summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--AUTHORS3
-rw-r--r--COPYING347
-rw-r--r--COPYING-DOCS397
-rw-r--r--ChangeLog17
-rw-r--r--INSTALL176
-rw-r--r--Mainpage.dox16
-rw-r--r--Makefile.am.in22
-rw-r--r--Makefile.cvs16
-rw-r--r--README97
-rw-r--r--configure.in.in17
-rw-r--r--doc/Makefile.am5
-rw-r--r--doc/kamera/Makefile.am4
-rw-r--r--doc/kamera/index.docbook78
-rw-r--r--doc/kcoloredit/Makefile.am4
-rw-r--r--doc/kcoloredit/index.docbook468
-rw-r--r--doc/kdvi/KDVI-features.dvibin0 -> 737562 bytes
-rw-r--r--doc/kdvi/KDVI-features.tex480
-rw-r--r--doc/kdvi/Makefile.am4
-rw-r--r--doc/kdvi/aboutkde.ps3351
-rw-r--r--doc/kdvi/index.docbook1072
-rw-r--r--doc/kdvi/kdvi-search.el102
-rw-r--r--doc/kdvi/optionrequester1.pngbin0 -> 14743 bytes
-rw-r--r--doc/kdvi/optionrequester2.pngbin0 -> 17905 bytes
-rw-r--r--doc/kdvi/srcltx.sty184
-rw-r--r--doc/kdvi/srctex.sty146
-rw-r--r--doc/kgamma/Makefile.am4
-rw-r--r--doc/kgamma/index.docbook234
-rw-r--r--doc/kghostview/Makefile.am4
-rw-r--r--doc/kghostview/index.docbook755
-rw-r--r--doc/kiconedit/Makefile.am4
-rw-r--r--doc/kiconedit/index.docbook1083
-rw-r--r--doc/kiconedit/kiconedit-configuration.pngbin0 -> 31231 bytes
-rw-r--r--doc/kolourpaint/Makefile.am2
-rw-r--r--doc/kolourpaint/brush_shapes.pngbin0 -> 475 bytes
-rw-r--r--doc/kolourpaint/color_box.pngbin0 -> 2417 bytes
-rw-r--r--doc/kolourpaint/eraser_shapes.pngbin0 -> 362 bytes
-rw-r--r--doc/kolourpaint/fcc_std_text.pngbin0 -> 10072 bytes
-rw-r--r--doc/kolourpaint/fcc_trans_text.pngbin0 -> 11702 bytes
-rw-r--r--doc/kolourpaint/fill_color_similarity.pngbin0 -> 17540 bytes
-rw-r--r--doc/kolourpaint/fill_style.pngbin0 -> 342 bytes
-rw-r--r--doc/kolourpaint/image_balance.pngbin0 -> 35978 bytes
-rw-r--r--doc/kolourpaint/image_emboss.pngbin0 -> 51537 bytes
-rw-r--r--doc/kolourpaint/image_flatten.pngbin0 -> 25398 bytes
-rw-r--r--doc/kolourpaint/image_flip.pngbin0 -> 10004 bytes
-rw-r--r--doc/kolourpaint/image_invert.pngbin0 -> 27542 bytes
-rw-r--r--doc/kolourpaint/image_reduce_colors.pngbin0 -> 25313 bytes
-rw-r--r--doc/kolourpaint/image_resize_scale.pngbin0 -> 36298 bytes
-rw-r--r--doc/kolourpaint/image_rotate.pngbin0 -> 32499 bytes
-rw-r--r--doc/kolourpaint/image_skew.pngbin0 -> 25028 bytes
-rw-r--r--doc/kolourpaint/image_soften_sharpen.pngbin0 -> 46238 bytes
-rw-r--r--doc/kolourpaint/index.docbook1501
-rw-r--r--doc/kolourpaint/kolourpaint-main.pngbin0 -> 35385 bytes
-rw-r--r--doc/kolourpaint/line_width.pngbin0 -> 307 bytes
-rw-r--r--doc/kolourpaint/lines_30_45_deg.pngbin0 -> 1382 bytes
-rw-r--r--doc/kolourpaint/lines_30_deg.pngbin0 -> 1062 bytes
-rw-r--r--doc/kolourpaint/lines_45_deg.pngbin0 -> 853 bytes
-rw-r--r--doc/kolourpaint/rotate_image_30.pngbin0 -> 2026 bytes
-rw-r--r--doc/kolourpaint/rotate_selection_30.pngbin0 -> 2898 bytes
-rw-r--r--doc/kolourpaint/selections_opaque_transparent.pngbin0 -> 1176 bytes
-rw-r--r--doc/kolourpaint/spraycan_patterns.pngbin0 -> 829 bytes
-rw-r--r--doc/kolourpaint/text_zoom_grid.pngbin0 -> 451 bytes
-rw-r--r--doc/kolourpaint/tool_brush.pngbin0 -> 675 bytes
-rw-r--r--doc/kolourpaint/tool_color_picker.pngbin0 -> 656 bytes
-rw-r--r--doc/kolourpaint/tool_color_washer.pngbin0 -> 1010 bytes
-rw-r--r--doc/kolourpaint/tool_curve.pngbin0 -> 483 bytes
-rw-r--r--doc/kolourpaint/tool_ellipse.pngbin0 -> 837 bytes
-rw-r--r--doc/kolourpaint/tool_elliptical_selection.pngbin0 -> 906 bytes
-rw-r--r--doc/kolourpaint/tool_eraser.pngbin0 -> 806 bytes
-rw-r--r--doc/kolourpaint/tool_flood_fill.pngbin0 -> 638 bytes
-rw-r--r--doc/kolourpaint/tool_free_form_selection.pngbin0 -> 855 bytes
-rw-r--r--doc/kolourpaint/tool_line.pngbin0 -> 439 bytes
-rw-r--r--doc/kolourpaint/tool_pen.pngbin0 -> 579 bytes
-rw-r--r--doc/kolourpaint/tool_polygon.pngbin0 -> 907 bytes
-rw-r--r--doc/kolourpaint/tool_polyline.pngbin0 -> 543 bytes
-rw-r--r--doc/kolourpaint/tool_polystar.pngbin0 -> 1365 bytes
-rw-r--r--doc/kolourpaint/tool_rect_selection.pngbin0 -> 921 bytes
-rw-r--r--doc/kolourpaint/tool_rectangle.pngbin0 -> 557 bytes
-rw-r--r--doc/kolourpaint/tool_rectangles.pngbin0 -> 824 bytes
-rw-r--r--doc/kolourpaint/tool_rounded_rectangle.pngbin0 -> 729 bytes
-rw-r--r--doc/kolourpaint/tool_selections.pngbin0 -> 1831 bytes
-rw-r--r--doc/kolourpaint/tool_spraycan.pngbin0 -> 784 bytes
-rw-r--r--doc/kolourpaint/tool_text.pngbin0 -> 401 bytes
-rw-r--r--doc/kolourpaint/view_thumbnails.pngbin0 -> 42197 bytes
-rw-r--r--doc/kooka/Makefile.am4
-rw-r--r--doc/kooka/index.docbook747
-rw-r--r--doc/kooka/kooka_gocr.pngbin0 -> 12366 bytes
-rw-r--r--doc/kooka/kooka_gocr_result.pngbin0 -> 12529 bytes
-rw-r--r--doc/kooka/kooka_mainctrl.pngbin0 -> 414827 bytes
-rw-r--r--doc/kooka/ocr-select.pngbin0 -> 899 bytes
-rw-r--r--doc/kooka/shortcut0.pngbin0 -> 32037 bytes
-rw-r--r--doc/kooka/shortcut1.pngbin0 -> 16028 bytes
-rw-r--r--doc/kooka/toolbar.pngbin0 -> 54602 bytes
-rw-r--r--doc/kooka/toolbar1.pngbin0 -> 6336 bytes
-rw-r--r--doc/kooka/toolbar2.pngbin0 -> 7244 bytes
-rw-r--r--doc/kpdf/Makefile.am4
-rw-r--r--doc/kpdf/configure.pngbin0 -> 11240 bytes
-rw-r--r--doc/kpdf/index.docbook932
-rw-r--r--doc/kpovmodeler/Makefile.am4
-rw-r--r--doc/kpovmodeler/cameraview.pngbin0 -> 7778 bytes
-rw-r--r--doc/kpovmodeler/controlpoints.pngbin0 -> 5658 bytes
-rw-r--r--doc/kpovmodeler/cr22-action-pmcamera.pngbin0 -> 525 bytes
-rw-r--r--doc/kpovmodeler/cr22-action-pmcolorlist.pngbin0 -> 218 bytes
-rw-r--r--doc/kpovmodeler/cr22-action-pmfinish.pngbin0 -> 299 bytes
-rw-r--r--doc/kpovmodeler/cr22-action-pminterior.pngbin0 -> 277 bytes
-rw-r--r--doc/kpovmodeler/cr22-action-pmlight.pngbin0 -> 438 bytes
-rw-r--r--doc/kpovmodeler/cr22-action-pmpigment.pngbin0 -> 305 bytes
-rw-r--r--doc/kpovmodeler/cr22-action-pmplane.pngbin0 -> 495 bytes
-rw-r--r--doc/kpovmodeler/cr22-action-pmrender.pngbin0 -> 637 bytes
-rw-r--r--doc/kpovmodeler/cr22-action-pmsolidcolor.pngbin0 -> 255 bytes
-rw-r--r--doc/kpovmodeler/cr22-action-pmsphere.pngbin0 -> 592 bytes
-rw-r--r--doc/kpovmodeler/defaultviewlayout.pngbin0 -> 20414 bytes
-rw-r--r--doc/kpovmodeler/dockwidget.pngbin0 -> 629 bytes
-rw-r--r--doc/kpovmodeler/dockwidgettab.pngbin0 -> 4534 bytes
-rw-r--r--doc/kpovmodeler/index.docbook2100
-rw-r--r--doc/kpovmodeler/insertaspopup.pngbin0 -> 709 bytes
-rw-r--r--doc/kpovmodeler/objectpropertiesview.pngbin0 -> 10272 bytes
-rw-r--r--doc/kpovmodeler/objecttree.pngbin0 -> 5962 bytes
-rw-r--r--doc/kpovmodeler/rendericon.pngbin0 -> 637 bytes
-rw-r--r--doc/kpovmodeler/rendermodeoutput.pngbin0 -> 41312 bytes
-rw-r--r--doc/kpovmodeler/rendermodequality.pngbin0 -> 40754 bytes
-rw-r--r--doc/kpovmodeler/rendermodesize.pngbin0 -> 41223 bytes
-rw-r--r--doc/kpovmodeler/rendermodesselection.pngbin0 -> 16508 bytes
-rw-r--r--doc/kpovmodeler/rendermodestoolbar.pngbin0 -> 2355 bytes
-rw-r--r--doc/kpovmodeler/rendersettingsicon.pngbin0 -> 693 bytes
-rw-r--r--doc/kpovmodeler/renderwindow.pngbin0 -> 45098 bytes
-rw-r--r--doc/kpovmodeler/texturepreview.pngbin0 -> 29483 bytes
-rw-r--r--doc/kpovmodeler/topview.pngbin0 -> 4616 bytes
-rw-r--r--doc/kpovmodeler/tutorial01-camera-dialog.pngbin0 -> 11691 bytes
-rw-r--r--doc/kpovmodeler/tutorial01-camera-graphic.pngbin0 -> 1009 bytes
-rw-r--r--doc/kpovmodeler/tutorial01-final-render.pngbin0 -> 40824 bytes
-rw-r--r--doc/kpovmodeler/tutorial01-ground-color-list.pngbin0 -> 14585 bytes
-rw-r--r--doc/kpovmodeler/tutorial01-ground-pigment.pngbin0 -> 24498 bytes
-rw-r--r--doc/kpovmodeler/tutorial01-ground-render.pngbin0 -> 54913 bytes
-rw-r--r--doc/kpovmodeler/tutorial01-ground-solid-color-1.pngbin0 -> 15590 bytes
-rw-r--r--doc/kpovmodeler/tutorial01-ground-solid-color-2.pngbin0 -> 15887 bytes
-rw-r--r--doc/kpovmodeler/tutorial01-ground-wrong-colors-render.pngbin0 -> 42474 bytes
-rw-r--r--doc/kpovmodeler/tutorial01-light-dialog.pngbin0 -> 11491 bytes
-rw-r--r--doc/kpovmodeler/tutorial01-light-graphic.pngbin0 -> 989 bytes
-rw-r--r--doc/kpovmodeler/tutorial01-plane-dialog.pngbin0 -> 5042 bytes
-rw-r--r--doc/kpovmodeler/tutorial01-plane-graphic.pngbin0 -> 1289 bytes
-rw-r--r--doc/kpovmodeler/tutorial01-plane-tree-expanded.pngbin0 -> 2358 bytes
-rw-r--r--doc/kpovmodeler/tutorial01-plane-tree-translate.pngbin0 -> 3068 bytes
-rw-r--r--doc/kpovmodeler/tutorial01-sphere-dialog.pngbin0 -> 5641 bytes
-rw-r--r--doc/kpovmodeler/tutorial01-sphere-finish-dialog.pngbin0 -> 9855 bytes
-rw-r--r--doc/kpovmodeler/tutorial01-sphere-render-finish.pngbin0 -> 37390 bytes
-rw-r--r--doc/kpovmodeler/tutorial01-sphere-render-nocolor.pngbin0 -> 37263 bytes
-rw-r--r--doc/kpovmodeler/tutorial01-sphere-render-solidcolor.pngbin0 -> 37375 bytes
-rw-r--r--doc/kpovmodeler/tutorial01-sphere-solid-color.pngbin0 -> 9346 bytes
-rw-r--r--doc/kruler/Makefile.am4
-rw-r--r--doc/kruler/index.docbook359
-rw-r--r--doc/ksnapshot/Makefile.am4
-rw-r--r--doc/ksnapshot/index.docbook535
-rw-r--r--doc/ksnapshot/preview.pngbin0 -> 32987 bytes
-rw-r--r--doc/ksnapshot/window.pngbin0 -> 43333 bytes
-rw-r--r--doc/kuickshow/Makefile.am4
-rw-r--r--doc/kuickshow/index.docbook1041
-rw-r--r--doc/kuickshow/screenshot.pngbin0 -> 235434 bytes
-rw-r--r--doc/kview/Makefile.am4
-rw-r--r--doc/kview/index.docbook835
-rw-r--r--doc/kview/kview-application-configuration.pngbin0 -> 31056 bytes
-rw-r--r--doc/kview/kview-viewer-configuration.pngbin0 -> 45321 bytes
-rw-r--r--kamera/AUTHORS4
-rw-r--r--kamera/Makefile.am1
-rw-r--r--kamera/README5
-rw-r--r--kamera/configure.in.in182
-rw-r--r--kamera/kcontrol/Makefile.am16
-rw-r--r--kamera/kcontrol/kamera.cpp423
-rw-r--r--kamera/kcontrol/kamera.desktop193
-rw-r--r--kamera/kcontrol/kamera.h115
-rw-r--r--kamera/kcontrol/kameraconfigdialog.cpp317
-rw-r--r--kamera/kcontrol/kameraconfigdialog.h53
-rw-r--r--kamera/kcontrol/kameradevice.cpp476
-rw-r--r--kamera/kcontrol/kameradevice.h117
-rw-r--r--kamera/kioslave/Makefile.am17
-rw-r--r--kamera/kioslave/camera.protocol16
-rw-r--r--kamera/kioslave/kamera.cpp1066
-rw-r--r--kamera/kioslave/kamera.h81
-rw-r--r--kamera/pics/Makefile.am1
-rw-r--r--kamera/pics/cr16-action-camera_test.pngbin0 -> 661 bytes
-rw-r--r--kamera/pics/cr16-app-camera.pngbin0 -> 747 bytes
-rw-r--r--kamera/pics/cr16-device-camera.pngbin0 -> 747 bytes
-rw-r--r--kamera/pics/cr22-device-camera.pngbin0 -> 953 bytes
-rw-r--r--kamera/pics/cr22-filesys-camera.pngbin0 -> 953 bytes
-rw-r--r--kamera/pics/cr32-device-camera.pngbin0 -> 1627 bytes
-rw-r--r--kamera/pics/cr32-filesys-camera.pngbin0 -> 1627 bytes
-rw-r--r--kcoloredit/Makefile.am35
-rw-r--r--kcoloredit/color.cpp78
-rw-r--r--kcoloredit/color.h81
-rw-r--r--kcoloredit/colorselector.cpp212
-rw-r--r--kcoloredit/colorselector.h96
-rw-r--r--kcoloredit/editablestreamhistory.cpp18
-rw-r--r--kcoloredit/editablestreamhistory.h107
-rw-r--r--kcoloredit/gradientselection.cpp252
-rw-r--r--kcoloredit/gradientselection.h106
-rw-r--r--kcoloredit/hi16-app-kcolorchooser.pngbin0 -> 372 bytes
-rw-r--r--kcoloredit/hi16-app-kcoloredit.pngbin0 -> 857 bytes
-rw-r--r--kcoloredit/hi22-app-kcolorchooser.pngbin0 -> 317 bytes
-rw-r--r--kcoloredit/hi32-app-kcoloredit.pngbin0 -> 2295 bytes
-rw-r--r--kcoloredit/imageselection.cpp28
-rw-r--r--kcoloredit/imageselection.h49
-rw-r--r--kcoloredit/kcolorchooser.cpp70
-rw-r--r--kcoloredit/kcolorchooser.desktop108
-rw-r--r--kcoloredit/kcoloredit.cpp363
-rw-r--r--kcoloredit/kcoloredit.desktop96
-rw-r--r--kcoloredit/kcoloredit.h192
-rw-r--r--kcoloredit/kcoloreditdoc.cpp293
-rw-r--r--kcoloredit/kcoloreditdoc.h156
-rw-r--r--kcoloredit/kcoloreditui.rc26
-rw-r--r--kcoloredit/kcoloreditview.cpp282
-rw-r--r--kcoloredit/kcoloreditview.h128
-rw-r--r--kcoloredit/kxycolorselector.cpp186
-rw-r--r--kcoloredit/kxycolorselector.h97
-rw-r--r--kcoloredit/kzcolorselector.cpp170
-rw-r--r--kcoloredit/kzcolorselector.h89
-rw-r--r--kcoloredit/loadpalettedlg.cpp111
-rw-r--r--kcoloredit/loadpalettedlg.h67
-rw-r--r--kcoloredit/main.cpp74
-rw-r--r--kcoloredit/main.h52
-rw-r--r--kcoloredit/palette.cpp226
-rw-r--r--kcoloredit/palette.h102
-rw-r--r--kcoloredit/palettehistory.h26
-rw-r--r--kcoloredit/paletteview.cpp75
-rw-r--r--kcoloredit/paletteview.h64
-rw-r--r--kcoloredit/paletteviewscrolledarea.cpp409
-rw-r--r--kcoloredit/paletteviewscrolledarea.h162
-rw-r--r--kcoloredit/resource.h35
-rw-r--r--kcoloredit/texteditselection.cpp187
-rw-r--r--kcoloredit/texteditselection.h89
-rw-r--r--kcoloredit/textselection.cpp24
-rw-r--r--kcoloredit/uninstall.desktop2
-rw-r--r--kdegraphics.lsm11
-rw-r--r--kdvi/AUTHORS39
-rw-r--r--kdvi/ChangeLog9
-rw-r--r--kdvi/Makefile.am66
-rw-r--r--kdvi/TODO30
-rw-r--r--kdvi/TeXFont.cpp9
-rw-r--r--kdvi/TeXFont.h48
-rw-r--r--kdvi/TeXFontDefinition.cpp250
-rw-r--r--kdvi/TeXFontDefinition.h126
-rw-r--r--kdvi/TeXFont_PFB.cpp294
-rw-r--r--kdvi/TeXFont_PFB.h41
-rw-r--r--kdvi/TeXFont_PK.cpp781
-rw-r--r--kdvi/TeXFont_PK.h38
-rw-r--r--kdvi/TeXFont_TFM.cpp163
-rw-r--r--kdvi/TeXFont_TFM.h38
-rw-r--r--kdvi/bigEndianByteReader.cpp111
-rw-r--r--kdvi/bigEndianByteReader.h62
-rw-r--r--kdvi/configure.in.in55
-rw-r--r--kdvi/dvi.h68
-rw-r--r--kdvi/dviFile.cpp406
-rw-r--r--kdvi/dviFile.h150
-rw-r--r--kdvi/dviPageCache.cpp42
-rw-r--r--kdvi/dviPageCache.h40
-rw-r--r--kdvi/dviRenderer.cpp839
-rw-r--r--kdvi/dviRenderer.h300
-rw-r--r--kdvi/dviRenderer_draw.cpp660
-rw-r--r--kdvi/dviRenderer_export.cpp391
-rw-r--r--kdvi/dviRenderer_prescan.cpp789
-rw-r--r--kdvi/dviWidget.cpp123
-rw-r--r--kdvi/dviWidget.h38
-rw-r--r--kdvi/dvisourcesplitter.cpp95
-rw-r--r--kdvi/dvisourcesplitter.h34
-rw-r--r--kdvi/examples/BrokenDVI1.dvibin0 -> 146 bytes
-rw-r--r--kdvi/examples/Font_not_found.dvibin0 -> 212 bytes
-rw-r--r--kdvi/examples/dvistd0.dvibin0 -> 141240 bytes
-rw-r--r--kdvi/fontEncoding.cpp87
-rw-r--r--kdvi/fontEncoding.h86
-rw-r--r--kdvi/fontEncodingPool.cpp37
-rw-r--r--kdvi/fontEncodingPool.h29
-rw-r--r--kdvi/fontMap.cpp159
-rw-r--r--kdvi/fontMap.h118
-rw-r--r--kdvi/fontpool.cpp597
-rw-r--r--kdvi/fontpool.h215
-rw-r--r--kdvi/fontprogress.cpp104
-rw-r--r--kdvi/fontprogress.h64
-rw-r--r--kdvi/glyph.cpp30
-rw-r--r--kdvi/glyph.h37
-rw-r--r--kdvi/infodialog.cpp134
-rw-r--r--kdvi/infodialog.h58
-rw-r--r--kdvi/kdvi.desktop90
-rw-r--r--kdvi/kdvi.h17
-rw-r--r--kdvi/kdvi.kcfg26
-rw-r--r--kdvi/kdvi.lsm14
-rw-r--r--kdvi/kdvi_multipage.cpp482
-rw-r--r--kdvi/kdvi_multipage.h96
-rw-r--r--kdvi/kdvi_multipage_texthandling.cpp70
-rw-r--r--kdvi/kdvi_part.rc26
-rw-r--r--kdvi/kdvimultipage.desktop18
-rw-r--r--kdvi/kprinterwrapper.h24
-rw-r--r--kdvi/main.cpp154
-rw-r--r--kdvi/make/ChangeLog370
-rw-r--r--kdvi/make/README3
-rw-r--r--kdvi/make/common.make42
-rw-r--r--kdvi/make/config.make39
-rw-r--r--kdvi/make/dist.make33
-rw-r--r--kdvi/make/library.make5
-rw-r--r--kdvi/make/makevars.make20
-rw-r--r--kdvi/make/misc.make31
-rw-r--r--kdvi/make/paths.make99
-rw-r--r--kdvi/make/programs.make13
-rw-r--r--kdvi/make/rdepend.make15
-rw-r--r--kdvi/make/texi.make13
-rw-r--r--kdvi/make/tkpathsea.make9
-rw-r--r--kdvi/optionDialogFontsWidget.cpp47
-rw-r--r--kdvi/optionDialogFontsWidget.h24
-rw-r--r--kdvi/optionDialogFontsWidget_base.ui64
-rw-r--r--kdvi/optionDialogSpecialWidget.cpp135
-rw-r--r--kdvi/optionDialogSpecialWidget.h36
-rw-r--r--kdvi/optionDialogSpecialWidget_base.ui208
-rw-r--r--kdvi/performanceMeasurement.h21
-rw-r--r--kdvi/pix/Makefile.am2
-rw-r--r--kdvi/pix/hi16-app-kdvi.pngbin0 -> 837 bytes
-rw-r--r--kdvi/pix/hi22-app-kdvi.pngbin0 -> 1440 bytes
-rw-r--r--kdvi/pix/hi32-app-kdvi.pngbin0 -> 2297 bytes
-rw-r--r--kdvi/pix/hi48-app-kdvi.pngbin0 -> 4397 bytes
-rw-r--r--kdvi/pix/hisc-app-kdvi.svgzbin0 -> 31209 bytes
-rw-r--r--kdvi/prebookmark.h50
-rw-r--r--kdvi/prefs.kcfgc5
-rw-r--r--kdvi/psgs.cpp340
-rw-r--r--kdvi/psgs.h107
-rw-r--r--kdvi/psheader.txt113
-rw-r--r--kdvi/renderedDviPagePixmap.cpp44
-rw-r--r--kdvi/renderedDviPagePixmap.h49
-rw-r--r--kdvi/special.cpp727
-rw-r--r--kdvi/squeeze.c190
-rw-r--r--kdvi/tips42
-rw-r--r--kdvi/util.cpp115
-rw-r--r--kdvi/vf.cpp184
-rw-r--r--kdvi/xdvi.h24
-rw-r--r--kfax/AUTHORS3
-rw-r--r--kfax/ChangeLog28
-rw-r--r--kfax/Makefile.am32
-rw-r--r--kfax/NOTES49
-rw-r--r--kfax/README34
-rw-r--r--kfax/TODO2
-rw-r--r--kfax/examples/README22
-rw-r--r--kfax/examples/README.kdeapps12
-rw-r--r--kfax/examples/kde.g3bin0 -> 55571 bytes
-rw-r--r--kfax/examples/nasty.tiffbin0 -> 92354 bytes
-rw-r--r--kfax/faxexpand.cpp732
-rw-r--r--kfax/faxexpand.h160
-rw-r--r--kfax/faxinit.cpp337
-rw-r--r--kfax/faxinput.cpp479
-rw-r--r--kfax/hi16-app-kfax.pngbin0 -> 787 bytes
-rw-r--r--kfax/hi22-app-kfax.pngbin0 -> 1241 bytes
-rw-r--r--kfax/hi32-app-kfax.pngbin0 -> 1928 bytes
-rw-r--r--kfax/hi48-app-kfax.pngbin0 -> 3352 bytes
-rw-r--r--kfax/hisc-app-kfax.svgzbin0 -> 11876 bytes
-rw-r--r--kfax/kfax.cpp1695
-rw-r--r--kfax/kfax.desktop86
-rw-r--r--kfax/kfax.h159
-rw-r--r--kfax/kfax.tifbin0 -> 74703 bytes
-rw-r--r--kfax/kfax_printsettings.cpp98
-rw-r--r--kfax/kfax_printsettings.h47
-rw-r--r--kfax/kfaxlogo.xpm134
-rw-r--r--kfax/kfaxui.rc28
-rw-r--r--kfax/options.cpp374
-rw-r--r--kfax/options.h112
-rw-r--r--kfax/version.h1
-rw-r--r--kfax/viewfax.cpp770
-rw-r--r--kfax/viewfax.h27
-rw-r--r--kfaxview/Makefile.am38
-rw-r--r--kfaxview/faxmultipage.cpp85
-rw-r--r--kfaxview/faxmultipage.h120
-rw-r--r--kfaxview/faxrenderer.cpp204
-rw-r--r--kfaxview/faxrenderer.h90
-rw-r--r--kfaxview/hi16-app-kfaxview.pngbin0 -> 787 bytes
-rw-r--r--kfaxview/hi22-app-kfaxview.pngbin0 -> 1241 bytes
-rw-r--r--kfaxview/hi32-app-kfaxview.pngbin0 -> 1928 bytes
-rw-r--r--kfaxview/hi48-app-kfaxview.pngbin0 -> 3352 bytes
-rw-r--r--kfaxview/hisc-app-kfaxview.svgzbin0 -> 11876 bytes
-rw-r--r--kfaxview/kfaxmultipage.desktop60
-rw-r--r--kfaxview/kfaxmultipage_tiff.desktop57
-rw-r--r--kfaxview/kfaxview.desktop82
-rw-r--r--kfaxview/libkfaximage/Makefile.am14
-rw-r--r--kfaxview/libkfaximage/faxexpand.cpp745
-rw-r--r--kfaxview/libkfaximage/faxexpand.h126
-rw-r--r--kfaxview/libkfaximage/faxinit.cpp345
-rw-r--r--kfaxview/libkfaximage/kfaximage.cpp667
-rw-r--r--kfaxview/libkfaximage/kfaximage.h162
-rw-r--r--kfaxview/main.cpp174
-rw-r--r--kfile-plugins/Makefile.am14
-rw-r--r--kfile-plugins/RETURNED_ITEMS245
-rw-r--r--kfile-plugins/bmp/Makefile.am22
-rw-r--r--kfile-plugins/bmp/kfile_bmp.cpp174
-rw-r--r--kfile-plugins/bmp/kfile_bmp.desktop66
-rw-r--r--kfile-plugins/bmp/kfile_bmp.h37
-rw-r--r--kfile-plugins/configure.in.bot32
-rw-r--r--kfile-plugins/dds/Makefile.am22
-rw-r--r--kfile-plugins/dds/kfile_dds.cpp317
-rw-r--r--kfile-plugins/dds/kfile_dds.desktop53
-rw-r--r--kfile-plugins/dds/kfile_dds.h37
-rw-r--r--kfile-plugins/dvi/Makefile.am22
-rw-r--r--kfile-plugins/dvi/kfile_dvi.cpp150
-rw-r--r--kfile-plugins/dvi/kfile_dvi.desktop60
-rw-r--r--kfile-plugins/dvi/kfile_dvi.h37
-rw-r--r--kfile-plugins/exr/Makefile.am25
-rw-r--r--kfile-plugins/exr/configure.in.in14
-rw-r--r--kfile-plugins/exr/kfile_exr.cpp393
-rw-r--r--kfile-plugins/exr/kfile_exr.desktop57
-rw-r--r--kfile-plugins/exr/kfile_exr.h39
-rw-r--r--kfile-plugins/gif/Makefile.am24
-rw-r--r--kfile-plugins/gif/README10
-rw-r--r--kfile-plugins/gif/gif-info.125
-rw-r--r--kfile-plugins/gif/gif-info.c561
-rw-r--r--kfile-plugins/gif/kfile_gif.cpp122
-rw-r--r--kfile-plugins/gif/kfile_gif.desktop65
-rw-r--r--kfile-plugins/gif/kfile_gif.h37
-rw-r--r--kfile-plugins/ico/Makefile.am22
-rw-r--r--kfile-plugins/ico/kfile_ico.cpp148
-rw-r--r--kfile-plugins/ico/kfile_ico.desktop65
-rw-r--r--kfile-plugins/ico/kfile_ico.h37
-rw-r--r--kfile-plugins/jpeg/Makefile.am24
-rw-r--r--kfile-plugins/jpeg/README35
-rw-r--r--kfile-plugins/jpeg/exif.cpp961
-rw-r--r--kfile-plugins/jpeg/exif.h127
-rw-r--r--kfile-plugins/jpeg/kfile_jpeg.cpp531
-rw-r--r--kfile-plugins/jpeg/kfile_jpeg.desktop64
-rw-r--r--kfile-plugins/jpeg/kfile_jpeg.h43
-rw-r--r--kfile-plugins/jpeg/kfile_setcomment.cpp536
-rw-r--r--kfile-plugins/pcx/Makefile.am21
-rw-r--r--kfile-plugins/pcx/kfile_pcx.cpp122
-rw-r--r--kfile-plugins/pcx/kfile_pcx.desktop62
-rw-r--r--kfile-plugins/pcx/kfile_pcx.h88
-rw-r--r--kfile-plugins/pdf/Makefile.am22
-rw-r--r--kfile-plugins/pdf/configure.in.in15
-rw-r--r--kfile-plugins/pdf/kfile_pdf.cpp104
-rw-r--r--kfile-plugins/pdf/kfile_pdf.desktop64
-rw-r--r--kfile-plugins/pdf/kfile_pdf.h38
-rw-r--r--kfile-plugins/png/Makefile.am22
-rw-r--r--kfile-plugins/png/kfile_png.cpp315
-rw-r--r--kfile-plugins/png/kfile_png.desktop65
-rw-r--r--kfile-plugins/png/kfile_png.h39
-rw-r--r--kfile-plugins/pnm/Makefile.am22
-rw-r--r--kfile-plugins/pnm/kfile_pnm.cpp137
-rw-r--r--kfile-plugins/pnm/kfile_pnm.desktop60
-rw-r--r--kfile-plugins/pnm/kfile_pnm.h39
-rw-r--r--kfile-plugins/ps/Makefile.am26
-rw-r--r--kfile-plugins/ps/gscreator.cpp619
-rw-r--r--kfile-plugins/ps/gscreator.h42
-rw-r--r--kfile-plugins/ps/gsthumbnail.desktop60
-rw-r--r--kfile-plugins/ps/kfile_ps.cpp124
-rw-r--r--kfile-plugins/ps/kfile_ps.desktop66
-rw-r--r--kfile-plugins/ps/kfile_ps.h50
-rw-r--r--kfile-plugins/raw/Makefile.am19
-rw-r--r--kfile-plugins/raw/kcamerarawplugin.cpp141
-rw-r--r--kfile-plugins/raw/kcamerarawplugin.h38
-rw-r--r--kfile-plugins/raw/kfile_raw.desktop53
-rw-r--r--kfile-plugins/raw/parse.c1080
-rw-r--r--kfile-plugins/rgb/Makefile.am22
-rw-r--r--kfile-plugins/rgb/kfile_rgb.cpp208
-rw-r--r--kfile-plugins/rgb/kfile_rgb.desktop61
-rw-r--r--kfile-plugins/rgb/kfile_rgb.h41
-rw-r--r--kfile-plugins/tga/Makefile.am22
-rw-r--r--kfile-plugins/tga/kfile_tga.cpp165
-rw-r--r--kfile-plugins/tga/kfile_tga.desktop64
-rw-r--r--kfile-plugins/tga/kfile_tga.h37
-rw-r--r--kfile-plugins/tiff/Makefile.am21
-rw-r--r--kfile-plugins/tiff/configure.in.in3
-rw-r--r--kfile-plugins/tiff/kfile_tiff.cpp299
-rw-r--r--kfile-plugins/tiff/kfile_tiff.desktop67
-rw-r--r--kfile-plugins/tiff/kfile_tiff.h42
-rw-r--r--kfile-plugins/xbm/Makefile.am22
-rw-r--r--kfile-plugins/xbm/kfile_xbm.cpp128
-rw-r--r--kfile-plugins/xbm/kfile_xbm.desktop65
-rw-r--r--kfile-plugins/xbm/kfile_xbm.h42
-rw-r--r--kfile-plugins/xpm/Makefile.am21
-rw-r--r--kfile-plugins/xpm/kfile_xpm.cpp71
-rw-r--r--kfile-plugins/xpm/kfile_xpm.desktop53
-rw-r--r--kfile-plugins/xpm/kfile_xpm.h45
-rw-r--r--kgamma/AUTHORS1
-rw-r--r--kgamma/ChangeLog54
-rw-r--r--kgamma/Makefile.am2
-rw-r--r--kgamma/TODO1
-rw-r--r--kgamma/configure.in.in65
-rw-r--r--kgamma/kcmkgamma/Makefile.am18
-rw-r--r--kgamma/kcmkgamma/displaynumber.cpp61
-rw-r--r--kgamma/kcmkgamma/displaynumber.h41
-rw-r--r--kgamma/kcmkgamma/gammactrl.cpp138
-rw-r--r--kgamma/kcmkgamma/gammactrl.h76
-rw-r--r--kgamma/kcmkgamma/kgamma.cpp625
-rw-r--r--kgamma/kcmkgamma/kgamma.desktop129
-rw-r--r--kgamma/kcmkgamma/kgamma.h78
-rw-r--r--kgamma/kcmkgamma/pics/Makefile.am7
-rw-r--r--kgamma/kcmkgamma/pics/background.pngbin0 -> 167 bytes
-rw-r--r--kgamma/kcmkgamma/pics/cmyscale.pngbin0 -> 1033 bytes
-rw-r--r--kgamma/kcmkgamma/pics/darkgrey.pngbin0 -> 502 bytes
-rw-r--r--kgamma/kcmkgamma/pics/greyscale.pngbin0 -> 428 bytes
-rw-r--r--kgamma/kcmkgamma/pics/hi16-app-kgamma.pngbin0 -> 427 bytes
-rw-r--r--kgamma/kcmkgamma/pics/hi32-app-kgamma.pngbin0 -> 1015 bytes
-rw-r--r--kgamma/kcmkgamma/pics/hi48-app-kgamma.pngbin0 -> 1314 bytes
-rw-r--r--kgamma/kcmkgamma/pics/lightgrey.pngbin0 -> 473 bytes
-rw-r--r--kgamma/kcmkgamma/pics/midgrey.pngbin0 -> 509 bytes
-rw-r--r--kgamma/kcmkgamma/pics/rgbscale.pngbin0 -> 752 bytes
-rw-r--r--kgamma/kcmkgamma/xf86configpath.cpp56
-rw-r--r--kgamma/kcmkgamma/xf86configpath.h42
-rw-r--r--kgamma/kcmkgamma/xvidextwrap.cpp170
-rw-r--r--kgamma/kcmkgamma/xvidextwrap.h59
-rw-r--r--kgamma/xf86gammacfg/Makefile.am11
-rw-r--r--kgamma/xf86gammacfg/xf86gammacfg.cpp138
-rw-r--r--kghostview/AUTHORS9
-rw-r--r--kghostview/ChangeLog40
-rw-r--r--kghostview/Makefile.am69
-rw-r--r--kghostview/README27
-rw-r--r--kghostview/TODO41
-rw-r--r--kghostview/configuration.kcfgc4
-rw-r--r--kghostview/data/Makefile.am3
-rw-r--r--kghostview/data/pdf_sec.ps386
-rw-r--r--kghostview/displayoptions.cpp150
-rw-r--r--kghostview/displayoptions.h112
-rw-r--r--kghostview/dscparse.cpp3432
-rw-r--r--kghostview/dscparse.h473
-rw-r--r--kghostview/dscparse_adapter.cpp420
-rw-r--r--kghostview/dscparse_adapter.h386
-rw-r--r--kghostview/fullscreenfilter.cpp54
-rw-r--r--kghostview/fullscreenfilter.h44
-rw-r--r--kghostview/generalsettingswidget.ui111
-rw-r--r--kghostview/generalsettingswidget.ui.h9
-rw-r--r--kghostview/gssettingswidget.ui158
-rw-r--r--kghostview/gssettingswidget.ui.h14
-rw-r--r--kghostview/hi128-app-kghostview.pngbin0 -> 15812 bytes
-rw-r--r--kghostview/hi16-app-kghostview.pngbin0 -> 991 bytes
-rw-r--r--kghostview/hi22-app-kghostview.pngbin0 -> 1247 bytes
-rw-r--r--kghostview/hi32-app-kghostview.pngbin0 -> 2218 bytes
-rw-r--r--kghostview/hi48-app-kghostview.pngbin0 -> 3910 bytes
-rw-r--r--kghostview/hi64-app-kghostview.pngbin0 -> 6493 bytes
-rw-r--r--kghostview/infodialog.cpp131
-rw-r--r--kghostview/infodialog.h44
-rw-r--r--kghostview/kdscerrordialog.cpp170
-rw-r--r--kghostview/kdscerrordialog.h74
-rw-r--r--kghostview/kghostview.desktop86
-rw-r--r--kghostview/kghostview.kcfg77
-rw-r--r--kghostview/kghostview.upd13
-rw-r--r--kghostview/kghostview_part.desktop19
-rw-r--r--kghostview/kghostviewui.rc43
-rw-r--r--kghostview/kgv.h15
-rw-r--r--kghostview/kgv_miniwidget.cpp573
-rw-r--r--kghostview/kgv_miniwidget.h173
-rw-r--r--kghostview/kgv_part.rc110
-rw-r--r--kghostview/kgv_view.cpp1037
-rw-r--r--kghostview/kgv_view.h268
-rw-r--r--kghostview/kgvconfigdialog.cpp154
-rw-r--r--kghostview/kgvconfigdialog.h32
-rw-r--r--kghostview/kgvdocument.cpp864
-rw-r--r--kghostview/kgvdocument.h195
-rw-r--r--kghostview/kgvfactory.cpp105
-rw-r--r--kghostview/kgvfactory.h50
-rw-r--r--kghostview/kgvmainwidget.cpp50
-rw-r--r--kghostview/kgvmainwidget.h45
-rw-r--r--kghostview/kgvpagedecorator.cpp106
-rw-r--r--kghostview/kgvpagedecorator.h81
-rw-r--r--kghostview/kgvpageview.cpp254
-rw-r--r--kghostview/kgvpageview.h105
-rw-r--r--kghostview/kgvshell.cpp370
-rw-r--r--kghostview/kgvshell.h92
-rw-r--r--kghostview/kpswidget.cpp530
-rw-r--r--kghostview/kpswidget.h387
-rw-r--r--kghostview/logwindow.cpp76
-rw-r--r--kghostview/logwindow.h55
-rw-r--r--kghostview/main.cpp71
-rw-r--r--kghostview/marklist.cpp242
-rw-r--r--kghostview/marklist.h88
-rw-r--r--kghostview/part_init.cpp22
-rw-r--r--kghostview/ps.c188
-rw-r--r--kghostview/ps.h44
-rw-r--r--kghostview/scrollbox.cpp129
-rw-r--r--kghostview/scrollbox.h60
-rw-r--r--kghostview/thumbnailservice.cpp161
-rw-r--r--kghostview/thumbnailservice.h92
-rw-r--r--kghostview/update-to-xt-names.pl36
-rw-r--r--kghostview/version.h4
-rw-r--r--kghostview/viewcontrol.cpp194
-rw-r--r--kghostview/viewcontrol.h44
-rw-r--r--kiconedit/AUTHORS10
-rw-r--r--kiconedit/Makefile.am26
-rw-r--r--kiconedit/NEWS68
-rw-r--r--kiconedit/kcolorgrid.cpp335
-rw-r--r--kiconedit/kcolorgrid.h104
-rw-r--r--kiconedit/kicon.cpp279
-rw-r--r--kiconedit/kicon.h78
-rw-r--r--kiconedit/kiconcolors.cpp170
-rw-r--r--kiconedit/kiconcolors.h83
-rw-r--r--kiconedit/kiconconfig.cpp589
-rw-r--r--kiconedit/kiconconfig.h153
-rw-r--r--kiconedit/kiconedit.cpp497
-rw-r--r--kiconedit/kiconedit.desktop95
-rw-r--r--kiconedit/kiconedit.h157
-rw-r--r--kiconedit/kiconeditslots.cpp543
-rw-r--r--kiconedit/kiconeditui.rc66
-rw-r--r--kiconedit/kicongrid.cpp2263
-rw-r--r--kiconedit/kicongrid.h263
-rw-r--r--kiconedit/knew.cpp326
-rw-r--r--kiconedit/knew.h164
-rw-r--r--kiconedit/kresize.cpp83
-rw-r--r--kiconedit/kresize.h62
-rw-r--r--kiconedit/main.cpp89
-rw-r--r--kiconedit/palettetoolbar.cpp178
-rw-r--r--kiconedit/palettetoolbar.h63
-rw-r--r--kiconedit/pics/Makefile.am5
-rw-r--r--kiconedit/pics/hi16-app-kiconedit.pngbin0 -> 406 bytes
-rw-r--r--kiconedit/pics/hi22-app-kiconedit.pngbin0 -> 1101 bytes
-rw-r--r--kiconedit/pics/hi32-app-kiconedit.pngbin0 -> 853 bytes
-rw-r--r--kiconedit/pics/hi48-app-kiconedit.pngbin0 -> 1187 bytes
-rw-r--r--kiconedit/pics/icons/Makefile.am5
-rw-r--r--kiconedit/pics/icons/compressed.pngbin0 -> 530 bytes
-rw-r--r--kiconedit/pics/icons/source.pngbin0 -> 473 bytes
-rw-r--r--kiconedit/pics/icons/standard.pngbin0 -> 611 bytes
-rw-r--r--kiconedit/pics/logo.xpm137
-rw-r--r--kiconedit/pics/toolbar/Makefile.am28
-rw-r--r--kiconedit/pics/toolbar/aim-cursor.xpm28
-rw-r--r--kiconedit/pics/toolbar/aim.pngbin0 -> 303 bytes
-rw-r--r--kiconedit/pics/toolbar/airbrush-cursor.xpm35
-rw-r--r--kiconedit/pics/toolbar/areaselect.pngbin0 -> 290 bytes
-rw-r--r--kiconedit/pics/toolbar/circle.pngbin0 -> 274 bytes
-rw-r--r--kiconedit/pics/toolbar/colorpicker-cursor.xpm36
-rw-r--r--kiconedit/pics/toolbar/ellipse.pngbin0 -> 257 bytes
-rw-r--r--kiconedit/pics/toolbar/eraser-cursor.xpm32
-rw-r--r--kiconedit/pics/toolbar/fileclose.pngbin0 -> 317 bytes
-rw-r--r--kiconedit/pics/toolbar/fill-cursor.xpm36
-rw-r--r--kiconedit/pics/toolbar/filledcircle.pngbin0 -> 279 bytes
-rw-r--r--kiconedit/pics/toolbar/filledellipse.pngbin0 -> 262 bytes
-rw-r--r--kiconedit/pics/toolbar/filledrectangle.pngbin0 -> 238 bytes
-rw-r--r--kiconedit/pics/toolbar/flood-cursor.xpm32
-rw-r--r--kiconedit/pics/toolbar/flood.pngbin0 -> 440 bytes
-rw-r--r--kiconedit/pics/toolbar/grayscale.pngbin0 -> 449 bytes
-rw-r--r--kiconedit/pics/toolbar/grid.pngbin0 -> 236 bytes
-rw-r--r--kiconedit/pics/toolbar/kdepalette.pngbin0 -> 416 bytes
-rw-r--r--kiconedit/pics/toolbar/line.pngbin0 -> 222 bytes
-rw-r--r--kiconedit/pics/toolbar/paintbrush-cursor.xpm36
-rw-r--r--kiconedit/pics/toolbar/paintbrush.pngbin0 -> 374 bytes
-rw-r--r--kiconedit/pics/toolbar/pointer.pngbin0 -> 298 bytes
-rw-r--r--kiconedit/pics/toolbar/rectangle.pngbin0 -> 246 bytes
-rw-r--r--kiconedit/pics/toolbar/selectcircle.pngbin0 -> 274 bytes
-rw-r--r--kiconedit/pics/toolbar/selectrect.pngbin0 -> 243 bytes
-rw-r--r--kiconedit/pics/toolbar/spraycan-cursor.xpm30
-rw-r--r--kiconedit/pics/toolbar/spraycan.pngbin0 -> 407 bytes
-rw-r--r--kiconedit/pics/toolbar/transform.pngbin0 -> 409 bytes
-rw-r--r--kiconedit/pics/toolbar/window_new.pngbin0 -> 799 bytes
-rw-r--r--kiconedit/properties.cpp147
-rw-r--r--kiconedit/properties.h82
-rw-r--r--kiconedit/utils.cpp134
-rw-r--r--kiconedit/utils.h73
-rw-r--r--kiconedit/version.h36
-rw-r--r--kmrml/AUTHORS1
-rw-r--r--kmrml/ChangeLog28
-rw-r--r--kmrml/Makefile.am1
-rw-r--r--kmrml/README95
-rw-r--r--kmrml/README.DEVELOPMENT41
-rw-r--r--kmrml/TODO15
-rw-r--r--kmrml/example-session.mrml142
-rw-r--r--kmrml/kmrml.lsm27
-rw-r--r--kmrml/kmrml.spec62
-rw-r--r--kmrml/kmrml/Makefile.am41
-rw-r--r--kmrml/kmrml/algorithmcombo.cpp66
-rw-r--r--kmrml/kmrml/algorithmcombo.h54
-rw-r--r--kmrml/kmrml/algorithmdialog.cpp132
-rw-r--r--kmrml/kmrml/algorithmdialog.h60
-rw-r--r--kmrml/kmrml/browser.cpp63
-rw-r--r--kmrml/kmrml/browser.h48
-rw-r--r--kmrml/kmrml/collectioncombo.cpp95
-rw-r--r--kmrml/kmrml/collectioncombo.h57
-rw-r--r--kmrml/kmrml/kcontrol/Makefile.am25
-rw-r--r--kmrml/kmrml/kcontrol/indexcleaner.cpp96
-rw-r--r--kmrml/kmrml/kcontrol/indexcleaner.h53
-rw-r--r--kmrml/kmrml/kcontrol/indexer.cpp190
-rw-r--r--kmrml/kmrml/kcontrol/indexer.h68
-rw-r--r--kmrml/kmrml/kcontrol/indextest.cpp43
-rw-r--r--kmrml/kmrml/kcontrol/indextest.h26
-rw-r--r--kmrml/kmrml/kcontrol/kcmkmrml.cpp146
-rw-r--r--kmrml/kmrml/kcontrol/kcmkmrml.desktop176
-rw-r--r--kmrml/kmrml/kcontrol/kcmkmrml.h52
-rw-r--r--kmrml/kmrml/kcontrol/mainpage.cpp501
-rw-r--r--kmrml/kmrml/kcontrol/mainpage.h109
-rw-r--r--kmrml/kmrml/kcontrol/serverconfigwidget.ui272
-rw-r--r--kmrml/kmrml/lib/Makefile.am11
-rw-r--r--kmrml/kmrml/lib/kmrml_config.cpp339
-rw-r--r--kmrml/kmrml/lib/kmrml_config.h123
-rw-r--r--kmrml/kmrml/lib/mrml_shared.cpp235
-rw-r--r--kmrml/kmrml/lib/mrml_shared.h166
-rw-r--r--kmrml/kmrml/lib/mrml_utils.cpp89
-rw-r--r--kmrml/kmrml/lib/mrml_utils.h50
-rw-r--r--kmrml/kmrml/lib/version.h6
-rw-r--r--kmrml/kmrml/lib/watcher_stub.cpp95
-rw-r--r--kmrml/kmrml/lib/watcher_stub.h36
-rw-r--r--kmrml/kmrml/loader.cpp121
-rw-r--r--kmrml/kmrml/loader.h72
-rw-r--r--kmrml/kmrml/mrml-servicemenu.desktop67
-rw-r--r--kmrml/kmrml/mrml.cpp267
-rw-r--r--kmrml/kmrml/mrml.desktop60
-rw-r--r--kmrml/kmrml/mrml.h84
-rw-r--r--kmrml/kmrml/mrml.protocol10
-rw-r--r--kmrml/kmrml/mrml_creator.cpp76
-rw-r--r--kmrml/kmrml/mrml_creator.h49
-rw-r--r--kmrml/kmrml/mrml_elements.cpp358
-rw-r--r--kmrml/kmrml/mrml_elements.h255
-rw-r--r--kmrml/kmrml/mrml_part.cpp857
-rw-r--r--kmrml/kmrml/mrml_part.desktop67
-rw-r--r--kmrml/kmrml/mrml_part.h175
-rw-r--r--kmrml/kmrml/mrml_view.cpp480
-rw-r--r--kmrml/kmrml/mrml_view.h180
-rw-r--r--kmrml/kmrml/mrmlsearch.cpp74
-rw-r--r--kmrml/kmrml/propertysheet.cpp206
-rw-r--r--kmrml/kmrml/propertysheet.h113
-rw-r--r--kmrml/kmrml/propertywidgets.cpp121
-rw-r--r--kmrml/kmrml/propertywidgets.h108
-rw-r--r--kmrml/kmrml/server/Makefile.am12
-rw-r--r--kmrml/kmrml/server/daemonwatcher.desktop103
-rw-r--r--kmrml/kmrml/server/watcher.cpp280
-rw-r--r--kmrml/kmrml/server/watcher.h107
-rw-r--r--kolourpaint/AUTHORS112
-rw-r--r--kolourpaint/BUGS154
-rw-r--r--kolourpaint/COPYING23
-rw-r--r--kolourpaint/ChangeLog15
-rw-r--r--kolourpaint/Makefile.am76
-rw-r--r--kolourpaint/NEWS349
-rw-r--r--kolourpaint/README102
-rw-r--r--kolourpaint/VERSION1
-rw-r--r--kolourpaint/cursors/Makefile.am11
-rw-r--r--kolourpaint/cursors/kpcursorlightcross.cpp128
-rw-r--r--kolourpaint/cursors/kpcursorlightcross.h38
-rw-r--r--kolourpaint/cursors/kpcursorprovider.cpp49
-rw-r--r--kolourpaint/cursors/kpcursorprovider.h43
-rw-r--r--kolourpaint/kolourpaint.cpp229
-rw-r--r--kolourpaint/kolourpaint.desktop92
-rw-r--r--kolourpaint/kolourpaintui.rc169
-rw-r--r--kolourpaint/kpcolor.cpp360
-rw-r--r--kolourpaint/kpcolor.h101
-rw-r--r--kolourpaint/kpcommandhistory.cpp939
-rw-r--r--kolourpaint/kpcommandhistory.h255
-rw-r--r--kolourpaint/kpdefs.h151
-rw-r--r--kolourpaint/kpdocument.cpp1539
-rw-r--r--kolourpaint/kpdocument.h260
-rw-r--r--kolourpaint/kpdocumentmetainfo.cpp186
-rw-r--r--kolourpaint/kpdocumentmetainfo.h90
-rw-r--r--kolourpaint/kpdocumentsaveoptions.cpp561
-rw-r--r--kolourpaint/kpdocumentsaveoptions.h150
-rw-r--r--kolourpaint/kpdocumentsaveoptionswidget.cpp951
-rw-r--r--kolourpaint/kpdocumentsaveoptionswidget.h200
-rw-r--r--kolourpaint/kpmainwindow.cpp1061
-rw-r--r--kolourpaint/kpmainwindow.h739
-rw-r--r--kolourpaint/kpmainwindow_edit.cpp1069
-rw-r--r--kolourpaint/kpmainwindow_file.cpp1409
-rw-r--r--kolourpaint/kpmainwindow_help.cpp219
-rw-r--r--kolourpaint/kpmainwindow_image.cpp474
-rw-r--r--kolourpaint/kpmainwindow_p.h49
-rw-r--r--kolourpaint/kpmainwindow_settings.cpp209
-rw-r--r--kolourpaint/kpmainwindow_statusbar.cpp417
-rw-r--r--kolourpaint/kpmainwindow_text.cpp395
-rw-r--r--kolourpaint/kpmainwindow_tools.cpp646
-rw-r--r--kolourpaint/kpmainwindow_view.cpp1151
-rw-r--r--kolourpaint/kpselection.cpp1446
-rw-r--r--kolourpaint/kpselection.h237
-rw-r--r--kolourpaint/kpselectiondrag.cpp294
-rw-r--r--kolourpaint/kpselectiondrag.h71
-rw-r--r--kolourpaint/kpselectiontransparency.cpp178
-rw-r--r--kolourpaint/kpselectiontransparency.h80
-rw-r--r--kolourpaint/kpsinglekeytriggersaction.cpp155
-rw-r--r--kolourpaint/kpsinglekeytriggersaction.h82
-rw-r--r--kolourpaint/kptemppixmap.cpp148
-rw-r--r--kolourpaint/kptemppixmap.h90
-rw-r--r--kolourpaint/kptextstyle.cpp279
-rw-r--r--kolourpaint/kptextstyle.h108
-rw-r--r--kolourpaint/kpthumbnail.cpp213
-rw-r--r--kolourpaint/kpthumbnail.h68
-rw-r--r--kolourpaint/kptool.cpp1666
-rw-r--r--kolourpaint/kptool.h422
-rw-r--r--kolourpaint/kpview.cpp1910
-rw-r--r--kolourpaint/kpview.h535
-rw-r--r--kolourpaint/kpviewmanager.cpp766
-rw-r--r--kolourpaint/kpviewmanager.h220
-rw-r--r--kolourpaint/kpviewscrollablecontainer.cpp1390
-rw-r--r--kolourpaint/kpviewscrollablecontainer.h255
-rw-r--r--kolourpaint/kpwidgetmapper.cpp76
-rw-r--r--kolourpaint/kpwidgetmapper.h47
-rw-r--r--kolourpaint/patches/checkerboard-faster-render.diff141
-rw-r--r--kolourpaint/patches/color_eraser_speedup.diff264
-rw-r--r--kolourpaint/patches/doc_resize_no_flicker.diff614
-rw-r--r--kolourpaint/pics/Makefile.am13
-rw-r--r--kolourpaint/pics/cr16-action-tool_brush.pngbin0 -> 675 bytes
-rw-r--r--kolourpaint/pics/cr16-action-tool_color_picker.pngbin0 -> 656 bytes
-rw-r--r--kolourpaint/pics/cr16-action-tool_color_washer.pngbin0 -> 1010 bytes
-rw-r--r--kolourpaint/pics/cr16-action-tool_curve.pngbin0 -> 483 bytes
-rw-r--r--kolourpaint/pics/cr16-action-tool_ellipse.pngbin0 -> 837 bytes
-rw-r--r--kolourpaint/pics/cr16-action-tool_elliptical_selection.pngbin0 -> 906 bytes
-rw-r--r--kolourpaint/pics/cr16-action-tool_eraser.pngbin0 -> 806 bytes
-rw-r--r--kolourpaint/pics/cr16-action-tool_flood_fill.pngbin0 -> 638 bytes
-rw-r--r--kolourpaint/pics/cr16-action-tool_free_form_selection.pngbin0 -> 855 bytes
-rw-r--r--kolourpaint/pics/cr16-action-tool_line.pngbin0 -> 439 bytes
-rw-r--r--kolourpaint/pics/cr16-action-tool_pen.pngbin0 -> 579 bytes
-rw-r--r--kolourpaint/pics/cr16-action-tool_polygon.pngbin0 -> 907 bytes
-rw-r--r--kolourpaint/pics/cr16-action-tool_polyline.pngbin0 -> 543 bytes
-rw-r--r--kolourpaint/pics/cr16-action-tool_rect_selection.pngbin0 -> 921 bytes
-rw-r--r--kolourpaint/pics/cr16-action-tool_rectangle.pngbin0 -> 557 bytes
-rw-r--r--kolourpaint/pics/cr16-action-tool_rounded_rectangle.pngbin0 -> 729 bytes
-rw-r--r--kolourpaint/pics/cr16-action-tool_spraycan.pngbin0 -> 784 bytes
-rw-r--r--kolourpaint/pics/cr16-action-tool_text.pngbin0 -> 401 bytes
-rw-r--r--kolourpaint/pics/cr22-action-tool_brush.pngbin0 -> 981 bytes
-rw-r--r--kolourpaint/pics/cr22-action-tool_color_picker.pngbin0 -> 981 bytes
-rw-r--r--kolourpaint/pics/cr22-action-tool_color_washer.pngbin0 -> 1555 bytes
-rw-r--r--kolourpaint/pics/cr22-action-tool_curve.pngbin0 -> 639 bytes
-rw-r--r--kolourpaint/pics/cr22-action-tool_ellipse.pngbin0 -> 1206 bytes
-rw-r--r--kolourpaint/pics/cr22-action-tool_elliptical_selection.pngbin0 -> 1317 bytes
-rw-r--r--kolourpaint/pics/cr22-action-tool_eraser.pngbin0 -> 1226 bytes
-rw-r--r--kolourpaint/pics/cr22-action-tool_flood_fill.pngbin0 -> 865 bytes
-rw-r--r--kolourpaint/pics/cr22-action-tool_free_form_selection.pngbin0 -> 1259 bytes
-rw-r--r--kolourpaint/pics/cr22-action-tool_line.pngbin0 -> 502 bytes
-rw-r--r--kolourpaint/pics/cr22-action-tool_pen.pngbin0 -> 857 bytes
-rw-r--r--kolourpaint/pics/cr22-action-tool_polygon.pngbin0 -> 1357 bytes
-rw-r--r--kolourpaint/pics/cr22-action-tool_polyline.pngbin0 -> 776 bytes
-rw-r--r--kolourpaint/pics/cr22-action-tool_rect_selection.pngbin0 -> 1337 bytes
-rw-r--r--kolourpaint/pics/cr22-action-tool_rectangle.pngbin0 -> 815 bytes
-rw-r--r--kolourpaint/pics/cr22-action-tool_rounded_rectangle.pngbin0 -> 1111 bytes
-rw-r--r--kolourpaint/pics/cr22-action-tool_spraycan.pngbin0 -> 1158 bytes
-rw-r--r--kolourpaint/pics/cr22-action-tool_text.pngbin0 -> 734 bytes
-rw-r--r--kolourpaint/pics/cr32-action-tool_brush.pngbin0 -> 1601 bytes
-rw-r--r--kolourpaint/pics/cr32-action-tool_color_picker.pngbin0 -> 1590 bytes
-rw-r--r--kolourpaint/pics/cr32-action-tool_color_washer.pngbin0 -> 2612 bytes
-rw-r--r--kolourpaint/pics/cr32-action-tool_curve.pngbin0 -> 947 bytes
-rw-r--r--kolourpaint/pics/cr32-action-tool_ellipse.pngbin0 -> 1872 bytes
-rw-r--r--kolourpaint/pics/cr32-action-tool_elliptical_selection.pngbin0 -> 2179 bytes
-rw-r--r--kolourpaint/pics/cr32-action-tool_eraser.pngbin0 -> 2047 bytes
-rw-r--r--kolourpaint/pics/cr32-action-tool_flood_fill.pngbin0 -> 1275 bytes
-rw-r--r--kolourpaint/pics/cr32-action-tool_free_form_selection.pngbin0 -> 2078 bytes
-rw-r--r--kolourpaint/pics/cr32-action-tool_line.pngbin0 -> 685 bytes
-rw-r--r--kolourpaint/pics/cr32-action-tool_pen.pngbin0 -> 1307 bytes
-rw-r--r--kolourpaint/pics/cr32-action-tool_polygon.pngbin0 -> 2036 bytes
-rw-r--r--kolourpaint/pics/cr32-action-tool_polyline.pngbin0 -> 1101 bytes
-rw-r--r--kolourpaint/pics/cr32-action-tool_rect_selection.pngbin0 -> 2128 bytes
-rw-r--r--kolourpaint/pics/cr32-action-tool_rectangle.pngbin0 -> 1002 bytes
-rw-r--r--kolourpaint/pics/cr32-action-tool_rounded_rectangle.pngbin0 -> 1683 bytes
-rw-r--r--kolourpaint/pics/cr32-action-tool_spraycan.pngbin0 -> 1928 bytes
-rw-r--r--kolourpaint/pics/cr32-action-tool_text.pngbin0 -> 1078 bytes
-rw-r--r--kolourpaint/pics/cr48-action-tool_brush.pngbin0 -> 2792 bytes
-rw-r--r--kolourpaint/pics/cr48-action-tool_color_picker.pngbin0 -> 2672 bytes
-rw-r--r--kolourpaint/pics/cr48-action-tool_color_washer.pngbin0 -> 4572 bytes
-rw-r--r--kolourpaint/pics/cr48-action-tool_curve.pngbin0 -> 1404 bytes
-rw-r--r--kolourpaint/pics/cr48-action-tool_ellipse.pngbin0 -> 2873 bytes
-rw-r--r--kolourpaint/pics/cr48-action-tool_elliptical_selection.pngbin0 -> 3442 bytes
-rw-r--r--kolourpaint/pics/cr48-action-tool_eraser.pngbin0 -> 3544 bytes
-rw-r--r--kolourpaint/pics/cr48-action-tool_flood_fill.pngbin0 -> 2052 bytes
-rw-r--r--kolourpaint/pics/cr48-action-tool_free_form_selection.pngbin0 -> 3607 bytes
-rw-r--r--kolourpaint/pics/cr48-action-tool_line.pngbin0 -> 981 bytes
-rw-r--r--kolourpaint/pics/cr48-action-tool_pen.pngbin0 -> 2163 bytes
-rw-r--r--kolourpaint/pics/cr48-action-tool_polygon.pngbin0 -> 3351 bytes
-rw-r--r--kolourpaint/pics/cr48-action-tool_polyline.pngbin0 -> 1647 bytes
-rw-r--r--kolourpaint/pics/cr48-action-tool_rect_selection.pngbin0 -> 3658 bytes
-rw-r--r--kolourpaint/pics/cr48-action-tool_rectangle.pngbin0 -> 1503 bytes
-rw-r--r--kolourpaint/pics/cr48-action-tool_rounded_rectangle.pngbin0 -> 2539 bytes
-rw-r--r--kolourpaint/pics/cr48-action-tool_spraycan.pngbin0 -> 3341 bytes
-rw-r--r--kolourpaint/pics/cr48-action-tool_text.pngbin0 -> 1539 bytes
-rw-r--r--kolourpaint/pics/crsc-action-tool_brush.svgzbin0 -> 9005 bytes
-rw-r--r--kolourpaint/pics/crsc-action-tool_color_picker.svgzbin0 -> 12495 bytes
-rw-r--r--kolourpaint/pics/crsc-action-tool_color_washer.svgzbin0 -> 8859 bytes
-rw-r--r--kolourpaint/pics/crsc-action-tool_curve.svgzbin0 -> 2442 bytes
-rw-r--r--kolourpaint/pics/crsc-action-tool_ellipse.svgzbin0 -> 2061 bytes
-rw-r--r--kolourpaint/pics/crsc-action-tool_elliptical_selection.svgzbin0 -> 3828 bytes
-rw-r--r--kolourpaint/pics/crsc-action-tool_eraser.svgzbin0 -> 7708 bytes
-rw-r--r--kolourpaint/pics/crsc-action-tool_flood_fill.svgzbin0 -> 2992 bytes
-rw-r--r--kolourpaint/pics/crsc-action-tool_free_form_selection.svgzbin0 -> 5071 bytes
-rw-r--r--kolourpaint/pics/crsc-action-tool_line.svgzbin0 -> 1359 bytes
-rw-r--r--kolourpaint/pics/crsc-action-tool_pen.svgzbin0 -> 5120 bytes
-rw-r--r--kolourpaint/pics/crsc-action-tool_polygon.svgzbin0 -> 2360 bytes
-rw-r--r--kolourpaint/pics/crsc-action-tool_polyline.svgzbin0 -> 2139 bytes
-rw-r--r--kolourpaint/pics/crsc-action-tool_rect_selection.svgzbin0 -> 4031 bytes
-rw-r--r--kolourpaint/pics/crsc-action-tool_rectangle.svgzbin0 -> 2021 bytes
-rw-r--r--kolourpaint/pics/crsc-action-tool_rounded_rectangle.svgzbin0 -> 2294 bytes
-rw-r--r--kolourpaint/pics/crsc-action-tool_spraycan.svgzbin0 -> 9431 bytes
-rw-r--r--kolourpaint/pics/crsc-action-tool_text.svgzbin0 -> 2732 bytes
-rw-r--r--kolourpaint/pics/custom/Makefile.am10
-rw-r--r--kolourpaint/pics/custom/color_transparent_26x26.pngbin0 -> 1055 bytes
-rw-r--r--kolourpaint/pics/custom/colorbutton_swap_16x16.pngbin0 -> 166 bytes
-rw-r--r--kolourpaint/pics/custom/image_rotate_anticlockwise.pngbin0 -> 371 bytes
-rw-r--r--kolourpaint/pics/custom/image_rotate_clockwise.pngbin0 -> 363 bytes
-rw-r--r--kolourpaint/pics/custom/image_skew_horizontal.pngbin0 -> 347 bytes
-rw-r--r--kolourpaint/pics/custom/image_skew_vertical.pngbin0 -> 424 bytes
-rw-r--r--kolourpaint/pics/custom/option_opaque.pngbin0 -> 787 bytes
-rw-r--r--kolourpaint/pics/custom/option_transparent.pngbin0 -> 888 bytes
-rw-r--r--kolourpaint/pics/custom/resize.pngbin0 -> 4465 bytes
-rw-r--r--kolourpaint/pics/custom/scale.pngbin0 -> 2222 bytes
-rw-r--r--kolourpaint/pics/custom/smooth_scale.pngbin0 -> 5556 bytes
-rw-r--r--kolourpaint/pics/custom/tool_spraycan_17x17.pngbin0 -> 188 bytes
-rw-r--r--kolourpaint/pics/custom/tool_spraycan_29x29.pngbin0 -> 364 bytes
-rw-r--r--kolourpaint/pics/custom/tool_spraycan_9x9.pngbin0 -> 121 bytes
-rw-r--r--kolourpaint/pics/hi16-app-kolourpaint.pngbin0 -> 814 bytes
-rw-r--r--kolourpaint/pics/hi22-app-kolourpaint.pngbin0 -> 1269 bytes
-rw-r--r--kolourpaint/pics/hi32-app-kolourpaint.pngbin0 -> 2231 bytes
-rw-r--r--kolourpaint/pics/hi48-app-kolourpaint.pngbin0 -> 4087 bytes
-rw-r--r--kolourpaint/pics/hisc-app-kolourpaint.svgzbin0 -> 14604 bytes
-rw-r--r--kolourpaint/pixmapfx/Makefile.am19
-rw-r--r--kolourpaint/pixmapfx/kpcoloreffect.cpp168
-rw-r--r--kolourpaint/pixmapfx/kpcoloreffect.h111
-rw-r--r--kolourpaint/pixmapfx/kpeffectbalance.cpp517
-rw-r--r--kolourpaint/pixmapfx/kpeffectbalance.h116
-rw-r--r--kolourpaint/pixmapfx/kpeffectblursharpen.cpp291
-rw-r--r--kolourpaint/pixmapfx/kpeffectblursharpen.h105
-rw-r--r--kolourpaint/pixmapfx/kpeffectemboss.cpp228
-rw-r--r--kolourpaint/pixmapfx/kpeffectemboss.h93
-rw-r--r--kolourpaint/pixmapfx/kpeffectflatten.cpp266
-rw-r--r--kolourpaint/pixmapfx/kpeffectflatten.h115
-rw-r--r--kolourpaint/pixmapfx/kpeffectinvert.cpp315
-rw-r--r--kolourpaint/pixmapfx/kpeffectinvert.h130
-rw-r--r--kolourpaint/pixmapfx/kpeffectreducecolors.cpp446
-rw-r--r--kolourpaint/pixmapfx/kpeffectreducecolors.h110
-rw-r--r--kolourpaint/pixmapfx/kpeffectsdialog.cpp369
-rw-r--r--kolourpaint/pixmapfx/kpeffectsdialog.h90
-rw-r--r--kolourpaint/pixmapfx/kpfloodfill.cpp362
-rw-r--r--kolourpaint/pixmapfx/kpfloodfill.h106
-rw-r--r--kolourpaint/pixmapfx/kppixmapfx.cpp1677
-rw-r--r--kolourpaint/pixmapfx/kppixmapfx.h450
-rw-r--r--kolourpaint/tests/45deg_line.pngbin0 -> 106 bytes
-rw-r--r--kolourpaint/tests/4x4-transparent.pngbin0 -> 98 bytes
-rw-r--r--kolourpaint/tests/5x5.pngbin0 -> 109 bytes
-rw-r--r--kolourpaint/tests/depth1.bmpbin0 -> 462 bytes
-rw-r--r--kolourpaint/tests/dither.pngbin0 -> 2894 bytes
-rw-r--r--kolourpaint/tests/rotate.pngbin0 -> 84 bytes
-rw-r--r--kolourpaint/tests/small16x16.pngbin0 -> 155 bytes
-rw-r--r--kolourpaint/tests/tool_fill_xlimit.pngbin0 -> 173 bytes
-rw-r--r--kolourpaint/tests/transparent.pngbin0 -> 212 bytes
-rw-r--r--kolourpaint/tests/transparent_selection.pngbin0 -> 694 bytes
-rw-r--r--kolourpaint/tools/Makefile.am53
-rw-r--r--kolourpaint/tools/kptoolaction.cpp107
-rw-r--r--kolourpaint/tools/kptoolaction.h78
-rw-r--r--kolourpaint/tools/kptoolairspray.cpp376
-rw-r--r--kolourpaint/tools/kptoolairspray.h110
-rw-r--r--kolourpaint/tools/kptoolautocrop.cpp780
-rw-r--r--kolourpaint/tools/kptoolautocrop.h127
-rw-r--r--kolourpaint/tools/kptoolbrush.cpp45
-rw-r--r--kolourpaint/tools/kptoolbrush.h43
-rw-r--r--kolourpaint/tools/kptoolclear.cpp135
-rw-r--r--kolourpaint/tools/kptoolclear.h68
-rw-r--r--kolourpaint/tools/kptoolcolorpicker.cpp197
-rw-r--r--kolourpaint/tools/kptoolcolorpicker.h95
-rw-r--r--kolourpaint/tools/kptoolcolorwasher.cpp45
-rw-r--r--kolourpaint/tools/kptoolcolorwasher.h43
-rw-r--r--kolourpaint/tools/kptoolconverttograyscale.cpp106
-rw-r--r--kolourpaint/tools/kptoolconverttograyscale.h57
-rw-r--r--kolourpaint/tools/kptoolcrop.cpp335
-rw-r--r--kolourpaint/tools/kptoolcrop.h39
-rw-r--r--kolourpaint/tools/kptoolcurve.cpp47
-rw-r--r--kolourpaint/tools/kptoolcurve.h45
-rw-r--r--kolourpaint/tools/kptoolellipse.cpp45
-rw-r--r--kolourpaint/tools/kptoolellipse.h45
-rw-r--r--kolourpaint/tools/kptoolellipticalselection.cpp46
-rw-r--r--kolourpaint/tools/kptoolellipticalselection.h43
-rw-r--r--kolourpaint/tools/kptooleraser.cpp44
-rw-r--r--kolourpaint/tools/kptooleraser.h43
-rw-r--r--kolourpaint/tools/kptoolflip.cpp213
-rw-r--r--kolourpaint/tools/kptoolflip.h88
-rw-r--r--kolourpaint/tools/kptoolfloodfill.cpp261
-rw-r--r--kolourpaint/tools/kptoolfloodfill.h94
-rw-r--r--kolourpaint/tools/kptoolfreeformselection.cpp46
-rw-r--r--kolourpaint/tools/kptoolfreeformselection.h43
-rw-r--r--kolourpaint/tools/kptoolline.cpp47
-rw-r--r--kolourpaint/tools/kptoolline.h45
-rw-r--r--kolourpaint/tools/kptoolpen.cpp1145
-rw-r--r--kolourpaint/tools/kptoolpen.h160
-rw-r--r--kolourpaint/tools/kptoolpolygon.cpp895
-rw-r--r--kolourpaint/tools/kptoolpolygon.h157
-rw-r--r--kolourpaint/tools/kptoolpolyline.cpp47
-rw-r--r--kolourpaint/tools/kptoolpolyline.h46
-rw-r--r--kolourpaint/tools/kptoolpreviewdialog.cpp431
-rw-r--r--kolourpaint/tools/kptoolpreviewdialog.h131
-rw-r--r--kolourpaint/tools/kptoolrectangle.cpp638
-rw-r--r--kolourpaint/tools/kptoolrectangle.h142
-rw-r--r--kolourpaint/tools/kptoolrectselection.cpp46
-rw-r--r--kolourpaint/tools/kptoolrectselection.h43
-rw-r--r--kolourpaint/tools/kptoolresizescale.cpp1222
-rw-r--r--kolourpaint/tools/kptoolresizescale.h196
-rw-r--r--kolourpaint/tools/kptoolrotate.cpp500
-rw-r--r--kolourpaint/tools/kptoolrotate.h129
-rw-r--r--kolourpaint/tools/kptoolroundedrectangle.cpp45
-rw-r--r--kolourpaint/tools/kptoolroundedrectangle.h45
-rw-r--r--kolourpaint/tools/kptoolselection.cpp2371
-rw-r--r--kolourpaint/tools/kptoolselection.h313
-rw-r--r--kolourpaint/tools/kptoolskew.cpp449
-rw-r--r--kolourpaint/tools/kptoolskew.h121
-rw-r--r--kolourpaint/tools/kptooltext.cpp1394
-rw-r--r--kolourpaint/tools/kptooltext.h203
-rw-r--r--kolourpaint/views/Makefile.am14
-rw-r--r--kolourpaint/views/kpthumbnailview.cpp98
-rw-r--r--kolourpaint/views/kpthumbnailview.h90
-rw-r--r--kolourpaint/views/kpunzoomedthumbnailview.cpp212
-rw-r--r--kolourpaint/views/kpunzoomedthumbnailview.h106
-rw-r--r--kolourpaint/views/kpzoomedthumbnailview.cpp140
-rw-r--r--kolourpaint/views/kpzoomedthumbnailview.h95
-rw-r--r--kolourpaint/views/kpzoomedview.cpp103
-rw-r--r--kolourpaint/views/kpzoomedview.h96
-rw-r--r--kolourpaint/widgets/Makefile.am21
-rw-r--r--kolourpaint/widgets/kpcolorsimilaritycube.cpp348
-rw-r--r--kolourpaint/widgets/kpcolorsimilaritycube.h72
-rw-r--r--kolourpaint/widgets/kpcolorsimilaritydialog.cpp123
-rw-r--r--kolourpaint/widgets/kpcolorsimilaritydialog.h62
-rw-r--r--kolourpaint/widgets/kpcolortoolbar.cpp1112
-rw-r--r--kolourpaint/widgets/kpcolortoolbar.h297
-rw-r--r--kolourpaint/widgets/kpresizesignallinglabel.cpp67
-rw-r--r--kolourpaint/widgets/kpresizesignallinglabel.h52
-rw-r--r--kolourpaint/widgets/kpsqueezedtextlabel.cpp215
-rw-r--r--kolourpaint/widgets/kpsqueezedtextlabel.h65
-rw-r--r--kolourpaint/widgets/kptooltoolbar.cpp640
-rw-r--r--kolourpaint/widgets/kptooltoolbar.h155
-rw-r--r--kolourpaint/widgets/kptoolwidgetbase.cpp608
-rw-r--r--kolourpaint/widgets/kptoolwidgetbase.h112
-rw-r--r--kolourpaint/widgets/kptoolwidgetbrush.cpp184
-rw-r--r--kolourpaint/widgets/kptoolwidgetbrush.h61
-rw-r--r--kolourpaint/widgets/kptoolwidgeterasersize.cpp161
-rw-r--r--kolourpaint/widgets/kptoolwidgeterasersize.h59
-rw-r--r--kolourpaint/widgets/kptoolwidgetfillstyle.cpp222
-rw-r--r--kolourpaint/widgets/kptoolwidgetfillstyle.h80
-rw-r--r--kolourpaint/widgets/kptoolwidgetlinewidth.cpp97
-rw-r--r--kolourpaint/widgets/kptoolwidgetlinewidth.h51
-rw-r--r--kolourpaint/widgets/kptoolwidgetopaqueortransparent.cpp100
-rw-r--r--kolourpaint/widgets/kptoolwidgetopaqueortransparent.h56
-rw-r--r--kolourpaint/widgets/kptoolwidgetspraycansize.cpp119
-rw-r--r--kolourpaint/widgets/kptoolwidgetspraycansize.h51
-rw-r--r--kooka/AUTHORS2
-rw-r--r--kooka/CHANGES158
-rw-r--r--kooka/COPYING339
-rw-r--r--kooka/CREDITS4
-rw-r--r--kooka/INSTALL181
-rw-r--r--kooka/Makefile.am46
-rw-r--r--kooka/README66
-rw-r--r--kooka/README.KADMOS73
-rw-r--r--kooka/TODO26
-rw-r--r--kooka/WARNING28
-rw-r--r--kooka/configure.in.in33
-rw-r--r--kooka/dwmenuaction.cpp72
-rw-r--r--kooka/dwmenuaction.h62
-rw-r--r--kooka/formathelp.h43
-rw-r--r--kooka/imageselectline.cpp105
-rw-r--r--kooka/imageselectline.h66
-rw-r--r--kooka/img_saver.cpp897
-rw-r--r--kooka/img_saver.h208
-rw-r--r--kooka/imgnamecombo.cpp93
-rw-r--r--kooka/imgnamecombo.h57
-rw-r--r--kooka/imgprintdialog.cpp302
-rw-r--r--kooka/imgprintdialog.h89
-rw-r--r--kooka/kadmosocr.cpp432
-rw-r--r--kooka/kadmosocr.h143
-rw-r--r--kooka/kocrbase.cpp368
-rw-r--r--kooka/kocrbase.h158
-rw-r--r--kooka/kocrgocr.cpp201
-rw-r--r--kooka/kocrgocr.h86
-rw-r--r--kooka/kocrkadmos.cpp521
-rw-r--r--kooka/kocrkadmos.h128
-rw-r--r--kooka/kocrocrad.cpp263
-rw-r--r--kooka/kocrocrad.h106
-rw-r--r--kooka/kooka.cpp465
-rw-r--r--kooka/kooka.desktop78
-rw-r--r--kooka/kooka.h141
-rw-r--r--kooka/kookaiface.h13
-rw-r--r--kooka/kookaimage.cpp413
-rw-r--r--kooka/kookaimage.h170
-rw-r--r--kooka/kookaimagemeta.cpp51
-rw-r--r--kooka/kookaimagemeta.h54
-rw-r--r--kooka/kookapref.cpp547
-rw-r--r--kooka/kookapref.h100
-rw-r--r--kooka/kookaprint.cpp410
-rw-r--r--kooka/kookaprint.h95
-rw-r--r--kooka/kookarc121
-rw-r--r--kooka/kookaui.rc62
-rw-r--r--kooka/kookaview.cpp1083
-rw-r--r--kooka/kookaview.h241
-rw-r--r--kooka/ksaneocr.cpp1493
-rw-r--r--kooka/ksaneocr.h285
-rw-r--r--kooka/main.cpp121
-rw-r--r--kooka/ocrresedit.cpp148
-rw-r--r--kooka/ocrresedit.h65
-rw-r--r--kooka/ocrword.cpp157
-rw-r--r--kooka/ocrword.h111
-rw-r--r--kooka/pics/Makefile.am8
-rw-r--r--kooka/pics/gocr.pngbin0 -> 5824 bytes
-rw-r--r--kooka/pics/lockzoom.pngbin0 -> 1185 bytes
-rw-r--r--kooka/pics/mirror-both.pngbin0 -> 471 bytes
-rw-r--r--kooka/pics/mirror-horiz.pngbin0 -> 452 bytes
-rw-r--r--kooka/pics/mirror-vert.pngbin0 -> 480 bytes
-rw-r--r--kooka/pics/newfromselect.pngbin0 -> 287 bytes
-rw-r--r--kooka/pics/ocr-select.pngbin0 -> 899 bytes
-rw-r--r--kooka/pics/ocr.pngbin0 -> 950 bytes
-rw-r--r--kooka/pics/ocrad.pngbin0 -> 244 bytes
-rw-r--r--kooka/pics/scaleorig.pngbin0 -> 656 bytes
-rw-r--r--kooka/pics/scaletoheight.pngbin0 -> 591 bytes
-rw-r--r--kooka/pics/scaletowidth.pngbin0 -> 590 bytes
-rw-r--r--kooka/pics/thumbviewtile.pngbin0 -> 16383 bytes
-rw-r--r--kooka/resource.h94
-rw-r--r--kooka/scanpackager.cpp1261
-rw-r--r--kooka/scanpackager.h167
-rw-r--r--kooka/thumbview.cpp494
-rw-r--r--kooka/thumbview.h153
-rw-r--r--kooka/thumbviewitem.cpp49
-rw-r--r--kooka/thumbviewitem.h60
-rw-r--r--kooka/version.h4
-rw-r--r--kpdf/AUTHORS6
-rw-r--r--kpdf/COPYING339
-rw-r--r--kpdf/Makefile.am30
-rw-r--r--kpdf/README.internals.pngbin0 -> 43015 bytes
-rw-r--r--kpdf/TODO173
-rw-r--r--kpdf/VERSION1
-rw-r--r--kpdf/conf/Makefile.am13
-rw-r--r--kpdf/conf/dlgaccessibility.ui576
-rw-r--r--kpdf/conf/dlggeneral.ui171
-rw-r--r--kpdf/conf/dlggeneral.ui.h26
-rw-r--r--kpdf/conf/dlgperformance.ui278
-rw-r--r--kpdf/conf/dlgperformance.ui.h38
-rw-r--r--kpdf/conf/dlgpresentation.ui282
-rw-r--r--kpdf/conf/kpdf.kcfg177
-rw-r--r--kpdf/conf/preferencesdialog.cpp34
-rw-r--r--kpdf/conf/preferencesdialog.h44
-rw-r--r--kpdf/conf/settings.kcfgc4
-rw-r--r--kpdf/configure.in.bot30
-rw-r--r--kpdf/configure.in.in124
-rw-r--r--kpdf/core/Makefile.am13
-rw-r--r--kpdf/core/document.cpp1634
-rw-r--r--kpdf/core/document.h225
-rw-r--r--kpdf/core/generator.h115
-rw-r--r--kpdf/core/generator_kimgio/Makefile.am6
-rw-r--r--kpdf/core/generator_kimgio/generator_kimgio.cpp72
-rw-r--r--kpdf/core/generator_kimgio/generator_kimgio.h43
-rw-r--r--kpdf/core/generator_pdf/Makefile.am10
-rw-r--r--kpdf/core/generator_pdf/generator_pdf.cpp1258
-rw-r--r--kpdf/core/generator_pdf/generator_pdf.h150
-rw-r--r--kpdf/core/generator_pdf/gp_outputdev.cpp397
-rw-r--r--kpdf/core/generator_pdf/gp_outputdev.h90
-rw-r--r--kpdf/core/link.cpp65
-rw-r--r--kpdf/core/link.h118
-rw-r--r--kpdf/core/observer.h58
-rw-r--r--kpdf/core/page.cpp327
-rw-r--r--kpdf/core/page.h149
-rw-r--r--kpdf/core/pagetransition.cpp28
-rw-r--r--kpdf/core/pagetransition.h86
-rw-r--r--kpdf/dcop.h35
-rw-r--r--kpdf/error.cpp44
-rw-r--r--kpdf/hi128-app-kpdf.pngbin0 -> 14500 bytes
-rw-r--r--kpdf/hi16-app-kpdf.pngbin0 -> 766 bytes
-rw-r--r--kpdf/hi22-app-kpdf.pngbin0 -> 1184 bytes
-rw-r--r--kpdf/hi32-app-kpdf.pngbin0 -> 2101 bytes
-rw-r--r--kpdf/hi48-app-kpdf.pngbin0 -> 3452 bytes
-rw-r--r--kpdf/hi64-app-kpdf.pngbin0 -> 5842 bytes
-rw-r--r--kpdf/hisc-app-kpdf.svgzbin0 -> 11018 bytes
-rw-r--r--kpdf/kpdf_part.desktop11
-rw-r--r--kpdf/part.cpp1100
-rw-r--r--kpdf/part.h212
-rw-r--r--kpdf/part.rc64
-rw-r--r--kpdf/shell/Makefile.am15
-rw-r--r--kpdf/shell/kpdf.desktop82
-rw-r--r--kpdf/shell/main.cpp82
-rw-r--r--kpdf/shell/shell.cpp262
-rw-r--r--kpdf/shell/shell.h112
-rw-r--r--kpdf/shell/shell.rc21
-rw-r--r--kpdf/ui/Makefile.am17
-rw-r--r--kpdf/ui/minibar.cpp436
-rw-r--r--kpdf/ui/minibar.h61
-rw-r--r--kpdf/ui/pagepainter.cpp252
-rw-r--r--kpdf/ui/pagepainter.h36
-rw-r--r--kpdf/ui/pageview.cpp2114
-rw-r--r--kpdf/ui/pageview.h148
-rw-r--r--kpdf/ui/pageviewutils.cpp207
-rw-r--r--kpdf/ui/pageviewutils.h72
-rw-r--r--kpdf/ui/presentationwidget.cpp1330
-rw-r--r--kpdf/ui/presentationwidget.h108
-rw-r--r--kpdf/ui/propertiesdialog.cpp94
-rw-r--r--kpdf/ui/propertiesdialog.h23
-rw-r--r--kpdf/ui/searchwidget.cpp135
-rw-r--r--kpdf/ui/searchwidget.h50
-rw-r--r--kpdf/ui/thumbnaillist.cpp575
-rw-r--r--kpdf/ui/thumbnaillist.h121
-rw-r--r--kpdf/ui/toc.cpp175
-rw-r--r--kpdf/ui/toc.h43
-rw-r--r--kpdf/xpdf/Makefile.am1
-rw-r--r--kpdf/xpdf/README.xpdf405
-rw-r--r--kpdf/xpdf/aconf.h17
-rw-r--r--kpdf/xpdf/fofi/FoFiBase.cc156
-rw-r--r--kpdf/xpdf/fofi/FoFiBase.h57
-rw-r--r--kpdf/xpdf/fofi/FoFiEncodings.cc994
-rw-r--r--kpdf/xpdf/fofi/FoFiEncodings.h36
-rw-r--r--kpdf/xpdf/fofi/FoFiTrueType.cc2040
-rw-r--r--kpdf/xpdf/fofi/FoFiTrueType.h175
-rw-r--r--kpdf/xpdf/fofi/FoFiType1.cc252
-rw-r--r--kpdf/xpdf/fofi/FoFiType1.h59
-rw-r--r--kpdf/xpdf/fofi/FoFiType1C.cc2603
-rw-r--r--kpdf/xpdf/fofi/FoFiType1C.h233
-rw-r--r--kpdf/xpdf/fofi/Makefile.am9
-rw-r--r--kpdf/xpdf/goo/GHash.cc380
-rw-r--r--kpdf/xpdf/goo/GHash.h78
-rw-r--r--kpdf/xpdf/goo/GList.cc97
-rw-r--r--kpdf/xpdf/goo/GList.h96
-rw-r--r--kpdf/xpdf/goo/GMutex.h49
-rw-r--r--kpdf/xpdf/goo/GString.cc718
-rw-r--r--kpdf/xpdf/goo/GString.h136
-rw-r--r--kpdf/xpdf/goo/Makefile.am5
-rw-r--r--kpdf/xpdf/goo/gfile.cc731
-rw-r--r--kpdf/xpdf/goo/gfile.h138
-rw-r--r--kpdf/xpdf/goo/gmem.cc315
-rw-r--r--kpdf/xpdf/goo/gmem.h80
-rw-r--r--kpdf/xpdf/goo/gmempp.cc32
-rw-r--r--kpdf/xpdf/goo/gtypes.h29
-rw-r--r--kpdf/xpdf/splash/Makefile.am8
-rw-r--r--kpdf/xpdf/splash/Splash.cc3335
-rw-r--r--kpdf/xpdf/splash/Splash.h293
-rw-r--r--kpdf/xpdf/splash/SplashBitmap.cc188
-rw-r--r--kpdf/xpdf/splash/SplashBitmap.h61
-rw-r--r--kpdf/xpdf/splash/SplashClip.cc382
-rw-r--r--kpdf/xpdf/splash/SplashClip.h107
-rw-r--r--kpdf/xpdf/splash/SplashErrorCodes.h34
-rw-r--r--kpdf/xpdf/splash/SplashFTFont.cc375
-rw-r--r--kpdf/xpdf/splash/SplashFTFont.h58
-rw-r--r--kpdf/xpdf/splash/SplashFTFontEngine.cc194
-rw-r--r--kpdf/xpdf/splash/SplashFTFontEngine.h60
-rw-r--r--kpdf/xpdf/splash/SplashFTFontFile.cc125
-rw-r--r--kpdf/xpdf/splash/SplashFTFontFile.h72
-rw-r--r--kpdf/xpdf/splash/SplashFont.cc201
-rw-r--r--kpdf/xpdf/splash/SplashFont.h105
-rw-r--r--kpdf/xpdf/splash/SplashFontEngine.cc295
-rw-r--r--kpdf/xpdf/splash/SplashFontEngine.h86
-rw-r--r--kpdf/xpdf/splash/SplashFontFile.cc108
-rw-r--r--kpdf/xpdf/splash/SplashFontFile.h77
-rw-r--r--kpdf/xpdf/splash/SplashFontFileID.cc23
-rw-r--r--kpdf/xpdf/splash/SplashFontFileID.h30
-rw-r--r--kpdf/xpdf/splash/SplashGlyphBitmap.h26
-rw-r--r--kpdf/xpdf/splash/SplashMath.h89
-rw-r--r--kpdf/xpdf/splash/SplashPath.cc184
-rw-r--r--kpdf/xpdf/splash/SplashPath.h121
-rw-r--r--kpdf/xpdf/splash/SplashPattern.cc40
-rw-r--r--kpdf/xpdf/splash/SplashPattern.h65
-rw-r--r--kpdf/xpdf/splash/SplashScreen.cc385
-rw-r--r--kpdf/xpdf/splash/SplashScreen.h56
-rw-r--r--kpdf/xpdf/splash/SplashState.cc165
-rw-r--r--kpdf/xpdf/splash/SplashState.h103
-rw-r--r--kpdf/xpdf/splash/SplashT1Font.cc292
-rw-r--r--kpdf/xpdf/splash/SplashT1Font.h57
-rw-r--r--kpdf/xpdf/splash/SplashT1FontEngine.cc122
-rw-r--r--kpdf/xpdf/splash/SplashT1FontEngine.h53
-rw-r--r--kpdf/xpdf/splash/SplashT1FontFile.cc117
-rw-r--r--kpdf/xpdf/splash/SplashT1FontFile.h58
-rw-r--r--kpdf/xpdf/splash/SplashTypes.h132
-rw-r--r--kpdf/xpdf/splash/SplashXPath.cc443
-rw-r--r--kpdf/xpdf/splash/SplashXPath.h100
-rw-r--r--kpdf/xpdf/splash/SplashXPathScanner.cc429
-rw-r--r--kpdf/xpdf/splash/SplashXPathScanner.h87
-rw-r--r--kpdf/xpdf/xpdf/Annot.cc1556
-rw-r--r--kpdf/xpdf/xpdf/Annot.h143
-rw-r--r--kpdf/xpdf/xpdf/Array.cc88
-rw-r--r--kpdf/xpdf/xpdf/Array.h59
-rw-r--r--kpdf/xpdf/xpdf/BuiltinFont.cc65
-rw-r--r--kpdf/xpdf/xpdf/BuiltinFont.h57
-rw-r--r--kpdf/xpdf/xpdf/BuiltinFontTables.cc4284
-rw-r--r--kpdf/xpdf/xpdf/BuiltinFontTables.h23
-rw-r--r--kpdf/xpdf/xpdf/CMap.cc408
-rw-r--r--kpdf/xpdf/xpdf/CMap.h102
-rw-r--r--kpdf/xpdf/xpdf/Catalog.cc443
-rw-r--r--kpdf/xpdf/xpdf/Catalog.h137
-rw-r--r--kpdf/xpdf/xpdf/CharCodeToUnicode.cc540
-rw-r--r--kpdf/xpdf/xpdf/CharCodeToUnicode.h117
-rw-r--r--kpdf/xpdf/xpdf/CharTypes.h24
-rw-r--r--kpdf/xpdf/xpdf/CompactFontTables.h464
-rw-r--r--kpdf/xpdf/xpdf/Decrypt.cc776
-rw-r--r--kpdf/xpdf/xpdf/Decrypt.h95
-rw-r--r--kpdf/xpdf/xpdf/Dict.cc95
-rw-r--r--kpdf/xpdf/xpdf/Dict.h77
-rw-r--r--kpdf/xpdf/xpdf/Error.h23
-rw-r--r--kpdf/xpdf/xpdf/ErrorCodes.h36
-rw-r--r--kpdf/xpdf/xpdf/FontEncodingTables.cc1824
-rw-r--r--kpdf/xpdf/xpdf/FontEncodingTables.h20
-rw-r--r--kpdf/xpdf/xpdf/Function.cc1575
-rw-r--r--kpdf/xpdf/xpdf/Function.h229
-rw-r--r--kpdf/xpdf/xpdf/Gfx.cc4187
-rw-r--r--kpdf/xpdf/xpdf/Gfx.h312
-rw-r--r--kpdf/xpdf/xpdf/GfxFont.cc1616
-rw-r--r--kpdf/xpdf/xpdf/GfxFont.h322
-rw-r--r--kpdf/xpdf/xpdf/GfxState.cc4137
-rw-r--r--kpdf/xpdf/xpdf/GfxState.h1244
-rw-r--r--kpdf/xpdf/xpdf/GlobalParams.cc2989
-rw-r--r--kpdf/xpdf/xpdf/GlobalParams.h464
-rw-r--r--kpdf/xpdf/xpdf/JArithmeticDecoder.cc322
-rw-r--r--kpdf/xpdf/xpdf/JArithmeticDecoder.h109
-rw-r--r--kpdf/xpdf/xpdf/JBIG2Stream.cc3648
-rw-r--r--kpdf/xpdf/xpdf/JBIG2Stream.h149
-rw-r--r--kpdf/xpdf/xpdf/JPXStream.cc3144
-rw-r--r--kpdf/xpdf/xpdf/JPXStream.h351
-rw-r--r--kpdf/xpdf/xpdf/Lexer.cc521
-rw-r--r--kpdf/xpdf/xpdf/Lexer.h82
-rw-r--r--kpdf/xpdf/xpdf/Link.cc784
-rw-r--r--kpdf/xpdf/xpdf/Link.h369
-rw-r--r--kpdf/xpdf/xpdf/Makefile.am19
-rw-r--r--kpdf/xpdf/xpdf/NameToCharCode.cc116
-rw-r--r--kpdf/xpdf/xpdf/NameToCharCode.h42
-rw-r--r--kpdf/xpdf/xpdf/NameToUnicodeTable.h1097
-rw-r--r--kpdf/xpdf/xpdf/Object.cc233
-rw-r--r--kpdf/xpdf/xpdf/Object.h303
-rw-r--r--kpdf/xpdf/xpdf/Outline.cc151
-rw-r--r--kpdf/xpdf/xpdf/Outline.h76
-rw-r--r--kpdf/xpdf/xpdf/OutputDev.cc131
-rw-r--r--kpdf/xpdf/xpdf/OutputDev.h250
-rw-r--r--kpdf/xpdf/xpdf/PDFDoc.cc433
-rw-r--r--kpdf/xpdf/xpdf/PDFDoc.h183
-rw-r--r--kpdf/xpdf/xpdf/PDFDocEncoding.cc44
-rw-r--r--kpdf/xpdf/xpdf/PDFDocEncoding.h16
-rw-r--r--kpdf/xpdf/xpdf/PSOutputDev.cc6307
-rw-r--r--kpdf/xpdf/xpdf/PSOutputDev.h391
-rw-r--r--kpdf/xpdf/xpdf/PSTokenizer.cc135
-rw-r--r--kpdf/xpdf/xpdf/PSTokenizer.h41
-rw-r--r--kpdf/xpdf/xpdf/Page.cc558
-rw-r--r--kpdf/xpdf/xpdf/Page.h259
-rw-r--r--kpdf/xpdf/xpdf/Parser.cc227
-rw-r--r--kpdf/xpdf/xpdf/Parser.h59
-rw-r--r--kpdf/xpdf/xpdf/PreScanOutputDev.cc257
-rw-r--r--kpdf/xpdf/xpdf/PreScanOutputDev.h130
-rw-r--r--kpdf/xpdf/xpdf/SecurityHandler.cc390
-rw-r--r--kpdf/xpdf/xpdf/SecurityHandler.h160
-rw-r--r--kpdf/xpdf/xpdf/SplashOutputDev.cc2851
-rw-r--r--kpdf/xpdf/xpdf/SplashOutputDev.h247
-rw-r--r--kpdf/xpdf/xpdf/Stream-CCITT.h462
-rw-r--r--kpdf/xpdf/xpdf/Stream.cc4697
-rw-r--r--kpdf/xpdf/xpdf/Stream.h860
-rw-r--r--kpdf/xpdf/xpdf/TextOutputDev.cc4090
-rw-r--r--kpdf/xpdf/xpdf/TextOutputDev.h661
-rw-r--r--kpdf/xpdf/xpdf/UTF8.h56
-rw-r--r--kpdf/xpdf/xpdf/UnicodeMap.cc293
-rw-r--r--kpdf/xpdf/xpdf/UnicodeMap.h123
-rw-r--r--kpdf/xpdf/xpdf/UnicodeMapTables.h361
-rw-r--r--kpdf/xpdf/xpdf/UnicodeTypeTable.cc949
-rw-r--r--kpdf/xpdf/xpdf/UnicodeTypeTable.h20
-rw-r--r--kpdf/xpdf/xpdf/XRef.cc917
-rw-r--r--kpdf/xpdf/xpdf/XRef.h136
-rw-r--r--kpdf/xpdf/xpdf/xpdf_config.h112
-rw-r--r--kpovmodeler/AUTHORS13
-rw-r--r--kpovmodeler/BUGS5
-rw-r--r--kpovmodeler/COPYING341
-rw-r--r--kpovmodeler/ChangeLog83
-rw-r--r--kpovmodeler/INSTALL167
-rw-r--r--kpovmodeler/Makefile.am251
-rw-r--r--kpovmodeler/README3
-rw-r--r--kpovmodeler/REQUIREMENTS19
-rw-r--r--kpovmodeler/StyleConvention225
-rw-r--r--kpovmodeler/TODO52
-rw-r--r--kpovmodeler/baseinsertrules.xml1039
-rw-r--r--kpovmodeler/configure.in.bot37
-rw-r--r--kpovmodeler/configure.in.in60
-rw-r--r--kpovmodeler/cr16-mime-kpovmodeler_doc.pngbin0 -> 684 bytes
-rw-r--r--kpovmodeler/cr32-mime-kpovmodeler_doc.pngbin0 -> 1464 bytes
-rw-r--r--kpovmodeler/cr48-mime-kpovmodeler_doc.pngbin0 -> 2258 bytes
-rw-r--r--kpovmodeler/examples/Makefile.am1
-rw-r--r--kpovmodeler/examples/includes/Makefile.am1
-rw-r--r--kpovmodeler/examples/includes/inlined/Makefile.am4
-rw-r--r--kpovmodeler/examples/includes/inlined/chars.kpmbin0 -> 3354 bytes
-rw-r--r--kpovmodeler/examples/includes/inlined/finish.kpmbin0 -> 937 bytes
-rw-r--r--kpovmodeler/examples/includes/inlined/glass.kpm141
-rw-r--r--kpovmodeler/examples/includes/inlined/golds.kpmbin0 -> 1140 bytes
-rw-r--r--kpovmodeler/examples/includes/inlined/metals.kpmbin0 -> 2748 bytes
-rw-r--r--kpovmodeler/examples/includes/inlined/shapes.kpmbin0 -> 1462 bytes
-rw-r--r--kpovmodeler/examples/includes/inlined/shapes2.kpmbin0 -> 1541 bytes
-rw-r--r--kpovmodeler/examples/includes/inlined/shapesq.kpmbin0 -> 3039 bytes
-rw-r--r--kpovmodeler/examples/includes/inlined/skies.kpmbin0 -> 2229 bytes
-rw-r--r--kpovmodeler/examples/includes/inlined/stars.kpmbin0 -> 1285 bytes
-rw-r--r--kpovmodeler/examples/includes/inlined/stones1.kpmbin0 -> 9383 bytes
-rw-r--r--kpovmodeler/examples/includes/inlined/stones2.kpmbin0 -> 3659 bytes
-rw-r--r--kpovmodeler/examples/includes/inlined/textures.kpmbin0 -> 7361 bytes
-rw-r--r--kpovmodeler/examples/includes/inlined/woods.kpmbin0 -> 7129 bytes
-rw-r--r--kpovmodeler/examples/includes/original/Makefile.am4
-rw-r--r--kpovmodeler/examples/includes/original/chars.kpmbin0 -> 3083 bytes
-rw-r--r--kpovmodeler/examples/includes/original/finish.kpmbin0 -> 937 bytes
-rw-r--r--kpovmodeler/examples/includes/original/glass.kpmbin0 -> 1237 bytes
-rw-r--r--kpovmodeler/examples/includes/original/golds.kpmbin0 -> 1166 bytes
-rw-r--r--kpovmodeler/examples/includes/original/metals.kpmbin0 -> 3359 bytes
-rw-r--r--kpovmodeler/examples/includes/original/shapes.kpmbin0 -> 1462 bytes
-rw-r--r--kpovmodeler/examples/includes/original/shapes2.kpmbin0 -> 1541 bytes
-rw-r--r--kpovmodeler/examples/includes/original/shapesq.kpmbin0 -> 3045 bytes
-rw-r--r--kpovmodeler/examples/includes/original/skies.kpmbin0 -> 1981 bytes
-rw-r--r--kpovmodeler/examples/includes/original/stars.kpmbin0 -> 1285 bytes
-rw-r--r--kpovmodeler/examples/includes/original/stones1.kpmbin0 -> 7777 bytes
-rw-r--r--kpovmodeler/examples/includes/original/stones2.kpmbin0 -> 3659 bytes
-rw-r--r--kpovmodeler/examples/includes/original/textures.kpmbin0 -> 7317 bytes
-rw-r--r--kpovmodeler/examples/includes/original/woods.kpmbin0 -> 5539 bytes
-rw-r--r--kpovmodeler/examples/scenes/Makefile.am1
-rw-r--r--kpovmodeler/examples/scenes/advanced/Makefile.am2
-rw-r--r--kpovmodeler/examples/scenes/advanced/ants.kpmbin0 -> 5229 bytes
-rw-r--r--kpovmodeler/examples/scenes/advanced/bee.kpmbin0 -> 3052 bytes
-rw-r--r--kpovmodeler/examples/scenes/advanced/ink.kpmbin0 -> 3251 bytes
-rw-r--r--kpovmodeler/examples/scenes/advanced/table.kpmbin0 -> 4961 bytes
-rw-r--r--kpovmodeler/examples/scenes/csg/Makefile.am2
-rw-r--r--kpovmodeler/examples/scenes/csg/cheese.kpmbin0 -> 2642 bytes
-rw-r--r--kpovmodeler/examples/scenes/csg/emptybox.kpmbin0 -> 1952 bytes
-rw-r--r--kpovmodeler/examples/scenes/csg/heightfield.kpmbin0 -> 1321 bytes
-rw-r--r--kpovmodeler/examples/scenes/interior/Makefile.am2
-rw-r--r--kpovmodeler/examples/scenes/interior/cubes.kpmbin0 -> 1273 bytes
-rw-r--r--kpovmodeler/examples/scenes/interior/media1.kpmbin0 -> 1151 bytes
-rw-r--r--kpovmodeler/examples/scenes/interior/media2.kpmbin0 -> 1467 bytes
-rw-r--r--kpovmodeler/examples/scenes/interior/media3.kpmbin0 -> 1737 bytes
-rw-r--r--kpovmodeler/examples/scenes/interior/spheres.kpmbin0 -> 1247 bytes
-rw-r--r--kpovmodeler/examples/scenes/lights/Makefile.am2
-rw-r--r--kpovmodeler/examples/scenes/lights/arealight.kpmbin0 -> 1142 bytes
-rw-r--r--kpovmodeler/examples/scenes/lights/arealight2.kpmbin0 -> 1148 bytes
-rw-r--r--kpovmodeler/examples/scenes/lights/spotlight.kpmbin0 -> 1117 bytes
-rw-r--r--kpovmodeler/examples/scenes/objects/Makefile.am3
-rw-r--r--kpovmodeler/examples/scenes/objects/allobjects.kpmbin0 -> 2413 bytes
-rw-r--r--kpovmodeler/examples/scenes/objects/fractals.kpmbin0 -> 1143 bytes
-rw-r--r--kpovmodeler/examples/scenes/objects/lathe.kpmbin0 -> 1122 bytes
-rw-r--r--kpovmodeler/examples/scenes/objects/prism.kpmbin0 -> 1359 bytes
-rw-r--r--kpovmodeler/examples/scenes/objects/sor.kpmbin0 -> 1764 bytes
-rw-r--r--kpovmodeler/examples/scenes/objects/superellipsoid.kpmbin0 -> 1242 bytes
-rw-r--r--kpovmodeler/examples/scenes/objects/text.kpmbin0 -> 1124 bytes
-rw-r--r--kpovmodeler/hi16-app-kpovmodeler.pngbin0 -> 815 bytes
-rw-r--r--kpovmodeler/hi22-app-kpovmodeler.pngbin0 -> 1149 bytes
-rw-r--r--kpovmodeler/hi32-app-kpovmodeler.pngbin0 -> 1891 bytes
-rw-r--r--kpovmodeler/hi48-app-kpovmodeler.pngbin0 -> 3163 bytes
-rw-r--r--kpovmodeler/kdoc.rules10
-rw-r--r--kpovmodeler/kpovmodeler.desktop59
-rw-r--r--kpovmodeler/kpovmodelerbrowser.rc21
-rw-r--r--kpovmodeler/kpovmodelershell.rc58
-rw-r--r--kpovmodeler/kpovmodelerui.rc303
-rw-r--r--kpovmodeler/main.cpp69
-rw-r--r--kpovmodeler/pics/Makefile.am1
-rw-r--r--kpovmodeler/pics/crystalsvg/Makefile.am2
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmaddpoint.pngbin0 -> 262 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmaddpointabove.pngbin0 -> 226 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmaddsubprism.pngbin0 -> 260 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmbicubicpatch.pngbin0 -> 398 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmblendmapmodifiers.pngbin0 -> 608 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmblob.pngbin0 -> 514 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmblobcylinder.pngbin0 -> 474 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmblobsphere.pngbin0 -> 443 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmboundedby.pngbin0 -> 398 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmbox.pngbin0 -> 270 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmbumpmap.pngbin0 -> 681 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmcamera.pngbin0 -> 244 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmclippedby.pngbin0 -> 387 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmcolorlist.pngbin0 -> 169 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmcolormap.pngbin0 -> 360 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmcolormapdeclare.pngbin0 -> 350 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmcomment.pngbin0 -> 209 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmcone.pngbin0 -> 374 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmcylinder.pngbin0 -> 337 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmdeclare.pngbin0 -> 451 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmdensity.pngbin0 -> 530 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmdensitydeclare.pngbin0 -> 485 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmdensitylist.pngbin0 -> 544 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmdensitymap.pngbin0 -> 586 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmdensitymapdeclare.pngbin0 -> 519 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmdialogview.pngbin0 -> 576 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmdifference.pngbin0 -> 271 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmdisc.pngbin0 -> 355 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmdrag.pngbin0 -> 276 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmfinish.pngbin0 -> 240 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmfinishdeclare.pngbin0 -> 265 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmfog.pngbin0 -> 524 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmfogdeclare.pngbin0 -> 477 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmglobalphotons.pngbin0 -> 589 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmglobalsettings.pngbin0 -> 736 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmglview.pngbin0 -> 549 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmheightfield.pngbin0 -> 385 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmimagemap.pngbin0 -> 758 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pminserterrors.pngbin0 -> 246 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pminsertfirstchild.pngbin0 -> 226 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pminsertlastchild.pngbin0 -> 229 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pminsertsibling.pngbin0 -> 233 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pminterior.pngbin0 -> 279 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pminteriordeclare.pngbin0 -> 253 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pminteriortexture.pngbin0 -> 449 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pminteriortexturedeclare.pngbin0 -> 376 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmintersection.pngbin0 -> 269 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmisosurface.pngbin0 -> 411 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmjuliafractal.pngbin0 -> 468 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmlathe.pngbin0 -> 445 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmlight.pngbin0 -> 419 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmlightgroup.pngbin0 -> 440 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmlistpattern.pngbin0 -> 405 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmlookslike.pngbin0 -> 385 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmmaterial.pngbin0 -> 461 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmmaterialdeclare.pngbin0 -> 407 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmmaterialmap.pngbin0 -> 699 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmmatrix.pngbin0 -> 565 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmmedia.pngbin0 -> 388 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmmediadeclare.pngbin0 -> 376 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmmerge.pngbin0 -> 281 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmmesh.pngbin0 -> 360 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmnormal.pngbin0 -> 539 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmnormaldeclare.pngbin0 -> 481 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmnormallist.pngbin0 -> 556 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmnormalmap.pngbin0 -> 516 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmnormalmapdeclare.pngbin0 -> 456 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmobjectdeclare.pngbin0 -> 420 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmobjectlink.pngbin0 -> 476 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmpattern.pngbin0 -> 710 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmphotons.pngbin0 -> 513 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmpigment.pngbin0 -> 334 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentdeclare.pngbin0 -> 361 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentlist.pngbin0 -> 442 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentmap.pngbin0 -> 487 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentmapdeclare.pngbin0 -> 454 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmplane.pngbin0 -> 483 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmpolynom.pngbin0 -> 371 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmprism.pngbin0 -> 322 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmprojectedthrough.pngbin0 -> 422 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmquickcolor.pngbin0 -> 220 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmradiosity.pngbin0 -> 534 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmrainbow.pngbin0 -> 318 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmrainbowdeclare.pngbin0 -> 307 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmraw.pngbin0 -> 193 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmremovepoint.pngbin0 -> 170 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmrender.pngbin0 -> 442 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmrenderpreview.pngbin0 -> 451 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmrendersettings.pngbin0 -> 595 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmrotate.pngbin0 -> 282 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmscale.pngbin0 -> 209 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmscene.pngbin0 -> 725 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmskysphere.pngbin0 -> 614 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmskyspheredeclare.pngbin0 -> 560 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmslope.pngbin0 -> 364 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmslopemap.pngbin0 -> 396 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmslopemapdeclare.pngbin0 -> 342 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmsolidcolor.pngbin0 -> 178 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmsor.pngbin0 -> 425 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmsphere.pngbin0 -> 467 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmspheresweep.pngbin0 -> 540 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmsqe.pngbin0 -> 495 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmtext.pngbin0 -> 248 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmtexture.pngbin0 -> 610 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmtexturedeclare.pngbin0 -> 544 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmtexturelist.pngbin0 -> 617 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmtexturemap.pngbin0 -> 603 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmtexturemapdeclare.pngbin0 -> 546 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmtorus.pngbin0 -> 498 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmtranslate.pngbin0 -> 231 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmtreeview.pngbin0 -> 539 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmtriangle.pngbin0 -> 252 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmunion.pngbin0 -> 312 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr16-action-pmwarp.pngbin0 -> 686 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmbicubicpatch.pngbin0 -> 521 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmblendmapmodifiers.pngbin0 -> 975 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmblob.pngbin0 -> 845 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmblobcylinder.pngbin0 -> 796 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmblobsphere.pngbin0 -> 617 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmboundedby.pngbin0 -> 432 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmbox.pngbin0 -> 302 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmbumpmap.pngbin0 -> 1206 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmcamera.pngbin0 -> 525 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmclippedby.pngbin0 -> 477 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmcolorlist.pngbin0 -> 218 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmcolormap.pngbin0 -> 573 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmcolormapdeclare.pngbin0 -> 518 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmcomment.pngbin0 -> 343 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmcone.pngbin0 -> 396 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmconfigurecolors.pngbin0 -> 883 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguredialogview.pngbin0 -> 392 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguregraphicalview.pngbin0 -> 652 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguregrid.pngbin0 -> 553 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureobjectlibrary.pngbin0 -> 500 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureobjects.pngbin0 -> 710 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureopengl.pngbin0 -> 519 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmconfigurepovray.pngbin0 -> 1080 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguretexturepreview.pngbin0 -> 765 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureviewlayout.pngbin0 -> 410 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmcylinder.pngbin0 -> 384 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmdeclare.pngbin0 -> 702 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmdensity.pngbin0 -> 1147 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmdensitydeclare.pngbin0 -> 683 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmdensitylist.pngbin0 -> 809 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmdensitymap.pngbin0 -> 900 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmdensitymapdeclare.pngbin0 -> 764 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmdifference.pngbin0 -> 430 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmdisc.pngbin0 -> 527 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmdrag.pngbin0 -> 369 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmfinish.pngbin0 -> 299 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmfinishdeclare.pngbin0 -> 338 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmfog.pngbin0 -> 827 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmfogdeclare.pngbin0 -> 725 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmglobalphotons.pngbin0 -> 962 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmglobalsettings.pngbin0 -> 904 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmheightfield.pngbin0 -> 487 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmimagemap.pngbin0 -> 1344 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pminserterrors.pngbin0 -> 483 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pminterior.pngbin0 -> 277 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pminteriordeclare.pngbin0 -> 255 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pminteriortexture.pngbin0 -> 656 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pminteriortexturedeclare.pngbin0 -> 535 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmintersection.pngbin0 -> 372 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmisosurface.pngbin0 -> 730 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmjuliafractal.pngbin0 -> 718 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmlathe.pngbin0 -> 654 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmlight.pngbin0 -> 438 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmlightgroup.pngbin0 -> 709 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmlistpattern.pngbin0 -> 367 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmlookslike.pngbin0 -> 347 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmmaterial.pngbin0 -> 675 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmmaterialdeclare.pngbin0 -> 563 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmmaterialmap.pngbin0 -> 1243 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmmatrix.pngbin0 -> 290 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmmedia.pngbin0 -> 416 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmmediadeclare.pngbin0 -> 405 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmmerge.pngbin0 -> 489 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmmesh.pngbin0 -> 576 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmnormal.pngbin0 -> 844 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmnormaldeclare.pngbin0 -> 741 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmnormallist.pngbin0 -> 845 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmnormalmap.pngbin0 -> 804 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmnormalmapdeclare.pngbin0 -> 700 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmobjectdeclare.pngbin0 -> 643 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmobjectlink.pngbin0 -> 806 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmpattern.pngbin0 -> 1246 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmphotons.pngbin0 -> 631 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmpigment.pngbin0 -> 305 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentdeclare.pngbin0 -> 377 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentlist.pngbin0 -> 492 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentmap.pngbin0 -> 737 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentmapdeclare.pngbin0 -> 660 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmplane.pngbin0 -> 495 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmpolynom.pngbin0 -> 498 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmprism.pngbin0 -> 423 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmprojectedthrough.pngbin0 -> 420 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmquickcolor.pngbin0 -> 225 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmradiosity.pngbin0 -> 428 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmrainbow.pngbin0 -> 576 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmrainbowdeclare.pngbin0 -> 558 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmraw.pngbin0 -> 271 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmrender.pngbin0 -> 637 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmrenderpreview.pngbin0 -> 648 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmrendersettings.pngbin0 -> 693 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmrotate.pngbin0 -> 272 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmscale.pngbin0 -> 383 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmscene.pngbin0 -> 791 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmskysphere.pngbin0 -> 914 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmskyspheredeclare.pngbin0 -> 768 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmslope.pngbin0 -> 312 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmslopemap.pngbin0 -> 555 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmslopemapdeclare.pngbin0 -> 493 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmsolidcolor.pngbin0 -> 255 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmsor.pngbin0 -> 629 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmsphere.pngbin0 -> 592 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmspheresweep.pngbin0 -> 618 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmsqe.pngbin0 -> 713 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmtext.pngbin0 -> 284 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmtexture.pngbin0 -> 977 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmtexturedeclare.pngbin0 -> 852 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmtexturelist.pngbin0 -> 960 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmtexturemap.pngbin0 -> 939 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmtexturemapdeclare.pngbin0 -> 800 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmtorus.pngbin0 -> 677 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmtranslate.pngbin0 -> 463 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmtriangle.pngbin0 -> 455 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmunion.pngbin0 -> 554 bytes
-rw-r--r--kpovmodeler/pics/crystalsvg/cr22-action-pmwarp.pngbin0 -> 1011 bytes
-rw-r--r--kpovmodeler/pics/locolor/Makefile.am2
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmaddpoint.pngbin0 -> 262 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmaddpointabove.pngbin0 -> 226 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmaddsubprism.pngbin0 -> 186 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmbicubicpatch.pngbin0 -> 373 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmblendmapmodifiers.pngbin0 -> 520 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmblob.pngbin0 -> 396 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmblobcylinder.pngbin0 -> 212 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmblobsphere.pngbin0 -> 436 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmboundedby.pngbin0 -> 296 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmbox.pngbin0 -> 251 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmbumpmap.pngbin0 -> 299 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmcamera.pngbin0 -> 244 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmclippedby.pngbin0 -> 277 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmcomment.pngbin0 -> 209 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmcone.pngbin0 -> 466 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmcylinder.pngbin0 -> 341 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmdeclare.pngbin0 -> 327 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmdensity.pngbin0 -> 398 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmdensitydeclare.pngbin0 -> 354 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmdensitylist.pngbin0 -> 376 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmdensitymap.pngbin0 -> 379 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmdensitymapdeclare.pngbin0 -> 373 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmdifference.pngbin0 -> 271 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmdisc.pngbin0 -> 394 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmdrag.pngbin0 -> 276 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmfog.pngbin0 -> 329 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmfogdeclare.pngbin0 -> 384 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmglobalsettings.pngbin0 -> 509 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmheightfield.pngbin0 -> 288 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmimagemap.pngbin0 -> 458 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pminserterrors.pngbin0 -> 246 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pminsertfirstchild.pngbin0 -> 226 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pminsertlastchild.pngbin0 -> 229 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pminsertsibling.pngbin0 -> 233 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmintersection.pngbin0 -> 269 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmjuliafractal.pngbin0 -> 313 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmlathe.pngbin0 -> 237 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmlight.pngbin0 -> 297 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmlistpattern.pngbin0 -> 359 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmlookslike.pngbin0 -> 203 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmmaterialmap.pngbin0 -> 341 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmmatrix.pngbin0 -> 200 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmmerge.pngbin0 -> 281 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmobjectdeclare.pngbin0 -> 420 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmobjectlink.pngbin0 -> 476 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmpigment.pngbin0 -> 344 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmpigmentdeclare.pngbin0 -> 364 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmplane.pngbin0 -> 427 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmpolynom.pngbin0 -> 233 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmprism.pngbin0 -> 217 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmquickcolor.pngbin0 -> 205 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmrainbow.pngbin0 -> 354 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmrainbowdeclare.pngbin0 -> 337 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmraw.pngbin0 -> 193 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmremovepoint.pngbin0 -> 170 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmrender.pngbin0 -> 363 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmrenderpreview.pngbin0 -> 382 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmrendersettings.pngbin0 -> 501 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmrotate.pngbin0 -> 282 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmscale.pngbin0 -> 209 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmscene.pngbin0 -> 559 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmskysphere.pngbin0 -> 384 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmskyspheredeclare.pngbin0 -> 368 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmsolidcolor.pngbin0 -> 382 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmsor.pngbin0 -> 311 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmsphere.pngbin0 -> 363 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmsqr.pngbin0 -> 289 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmtext.pngbin0 -> 208 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmtexture.pngbin0 -> 502 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmtexturedeclare.pngbin0 -> 464 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmtorus.pngbin0 -> 399 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmtranslate.pngbin0 -> 231 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmtriangle.pngbin0 -> 324 bytes
-rw-r--r--kpovmodeler/pics/locolor/lo16-action-pmunion.pngbin0 -> 312 bytes
-rw-r--r--kpovmodeler/pm2dcontrolpoint.cpp207
-rw-r--r--kpovmodeler/pm2dcontrolpoint.h135
-rw-r--r--kpovmodeler/pm3dcontrolpoint.cpp49
-rw-r--r--kpovmodeler/pm3dcontrolpoint.h68
-rw-r--r--kpovmodeler/pmactions.cpp254
-rw-r--r--kpovmodeler/pmactions.h106
-rw-r--r--kpovmodeler/pmaddcommand.cpp233
-rw-r--r--kpovmodeler/pmaddcommand.h87
-rw-r--r--kpovmodeler/pmallcommands.h27
-rw-r--r--kpovmodeler/pmalledits.h25
-rw-r--r--kpovmodeler/pmallobjects.h106
-rw-r--r--kpovmodeler/pmbicubicpatch.cpp544
-rw-r--r--kpovmodeler/pmbicubicpatch.h188
-rw-r--r--kpovmodeler/pmbicubicpatchedit.cpp218
-rw-r--r--kpovmodeler/pmbicubicpatchedit.h80
-rw-r--r--kpovmodeler/pmblendmapmodifiers.cpp284
-rw-r--r--kpovmodeler/pmblendmapmodifiers.h129
-rw-r--r--kpovmodeler/pmblendmapmodifiersedit.cpp261
-rw-r--r--kpovmodeler/pmblendmapmodifiersedit.h100
-rw-r--r--kpovmodeler/pmblob.cpp175
-rw-r--r--kpovmodeler/pmblob.h113
-rw-r--r--kpovmodeler/pmblobcylinder.cpp468
-rw-r--r--kpovmodeler/pmblobcylinder.h181
-rw-r--r--kpovmodeler/pmblobcylinderedit.cpp114
-rw-r--r--kpovmodeler/pmblobcylinderedit.h61
-rw-r--r--kpovmodeler/pmblobedit.cpp96
-rw-r--r--kpovmodeler/pmblobedit.h65
-rw-r--r--kpovmodeler/pmblobsphere.cpp391
-rw-r--r--kpovmodeler/pmblobsphere.h168
-rw-r--r--kpovmodeler/pmblobsphereedit.cpp102
-rw-r--r--kpovmodeler/pmblobsphereedit.h63
-rw-r--r--kpovmodeler/pmboundedby.cpp114
-rw-r--r--kpovmodeler/pmboundedby.h89
-rw-r--r--kpovmodeler/pmboundedbyedit.cpp65
-rw-r--r--kpovmodeler/pmboundedbyedit.h59
-rw-r--r--kpovmodeler/pmbox.cpp276
-rw-r--r--kpovmodeler/pmbox.h123
-rw-r--r--kpovmodeler/pmboxedit.cpp86
-rw-r--r--kpovmodeler/pmboxedit.h63
-rw-r--r--kpovmodeler/pmbumpmap.cpp384
-rw-r--r--kpovmodeler/pmbumpmap.h172
-rw-r--r--kpovmodeler/pmbumpmapedit.cpp319
-rw-r--r--kpovmodeler/pmbumpmapedit.h86
-rw-r--r--kpovmodeler/pmcamera.cpp769
-rw-r--r--kpovmodeler/pmcamera.h292
-rw-r--r--kpovmodeler/pmcameraedit.cpp439
-rw-r--r--kpovmodeler/pmcameraedit.h99
-rw-r--r--kpovmodeler/pmclippedby.cpp114
-rw-r--r--kpovmodeler/pmclippedby.h88
-rw-r--r--kpovmodeler/pmclippedbyedit.cpp65
-rw-r--r--kpovmodeler/pmclippedbyedit.h59
-rw-r--r--kpovmodeler/pmcolor.cpp196
-rw-r--r--kpovmodeler/pmcolor.h130
-rw-r--r--kpovmodeler/pmcoloredit.cpp201
-rw-r--r--kpovmodeler/pmcoloredit.h83
-rw-r--r--kpovmodeler/pmcolorsettings.cpp163
-rw-r--r--kpovmodeler/pmcolorsettings.h58
-rw-r--r--kpovmodeler/pmcommand.h146
-rw-r--r--kpovmodeler/pmcommandmanager.cpp99
-rw-r--r--kpovmodeler/pmcommandmanager.h118
-rw-r--r--kpovmodeler/pmcomment.cpp174
-rw-r--r--kpovmodeler/pmcomment.h92
-rw-r--r--kpovmodeler/pmcommentedit.cpp75
-rw-r--r--kpovmodeler/pmcommentedit.h62
-rw-r--r--kpovmodeler/pmcompositeobject.cpp396
-rw-r--r--kpovmodeler/pmcompositeobject.h198
-rw-r--r--kpovmodeler/pmcone.cpp451
-rw-r--r--kpovmodeler/pmcone.h188
-rw-r--r--kpovmodeler/pmconeedit.cpp119
-rw-r--r--kpovmodeler/pmconeedit.h64
-rw-r--r--kpovmodeler/pmcontrolpoint.cpp99
-rw-r--r--kpovmodeler/pmcontrolpoint.h190
-rw-r--r--kpovmodeler/pmcsg.cpp200
-rw-r--r--kpovmodeler/pmcsg.h105
-rw-r--r--kpovmodeler/pmcsgedit.cpp118
-rw-r--r--kpovmodeler/pmcsgedit.h63
-rw-r--r--kpovmodeler/pmcylinder.cpp407
-rw-r--r--kpovmodeler/pmcylinder.h176
-rw-r--r--kpovmodeler/pmcylinderedit.cpp113
-rw-r--r--kpovmodeler/pmcylinderedit.h63
-rw-r--r--kpovmodeler/pmdatachangecommand.cpp111
-rw-r--r--kpovmodeler/pmdatachangecommand.h68
-rw-r--r--kpovmodeler/pmdebug.h26
-rw-r--r--kpovmodeler/pmdeclare.cpp238
-rw-r--r--kpovmodeler/pmdeclare.h147
-rw-r--r--kpovmodeler/pmdeclareedit.cpp206
-rw-r--r--kpovmodeler/pmdeclareedit.h74
-rw-r--r--kpovmodeler/pmdefaults.h131
-rw-r--r--kpovmodeler/pmdeletecommand.cpp281
-rw-r--r--kpovmodeler/pmdeletecommand.h126
-rw-r--r--kpovmodeler/pmdensity.cpp76
-rw-r--r--kpovmodeler/pmdensity.h76
-rw-r--r--kpovmodeler/pmdensityedit.cpp44
-rw-r--r--kpovmodeler/pmdensityedit.h58
-rw-r--r--kpovmodeler/pmdetailobject.cpp151
-rw-r--r--kpovmodeler/pmdetailobject.h115
-rw-r--r--kpovmodeler/pmdetailobjectedit.cpp122
-rw-r--r--kpovmodeler/pmdetailobjectedit.h68
-rw-r--r--kpovmodeler/pmdialogeditbase.cpp558
-rw-r--r--kpovmodeler/pmdialogeditbase.h356
-rw-r--r--kpovmodeler/pmdialogview.cpp441
-rw-r--r--kpovmodeler/pmdialogview.h163
-rw-r--r--kpovmodeler/pmdisc.cpp440
-rw-r--r--kpovmodeler/pmdisc.h180
-rw-r--r--kpovmodeler/pmdiscedit.cpp147
-rw-r--r--kpovmodeler/pmdiscedit.h67
-rw-r--r--kpovmodeler/pmdistancecontrolpoint.cpp92
-rw-r--r--kpovmodeler/pmdistancecontrolpoint.h110
-rw-r--r--kpovmodeler/pmdockwidget.cpp2549
-rw-r--r--kpovmodeler/pmdockwidget.h1478
-rw-r--r--kpovmodeler/pmdockwidget_private.cpp372
-rw-r--r--kpovmodeler/pmdockwidget_private.h142
-rw-r--r--kpovmodeler/pmdocumentationmap.cpp193
-rw-r--r--kpovmodeler/pmdocumentationmap.h138
-rw-r--r--kpovmodeler/pmdocumentformat.h26
-rw-r--r--kpovmodeler/pmdragwidget.cpp49
-rw-r--r--kpovmodeler/pmdragwidget.h51
-rw-r--r--kpovmodeler/pmenumproperty.cpp57
-rw-r--r--kpovmodeler/pmenumproperty.h110
-rw-r--r--kpovmodeler/pmerrordialog.cpp136
-rw-r--r--kpovmodeler/pmerrordialog.h73
-rw-r--r--kpovmodeler/pmerrorflags.h31
-rw-r--r--kpovmodeler/pmface.cpp119
-rw-r--r--kpovmodeler/pmface.h130
-rw-r--r--kpovmodeler/pmfactory.cpp102
-rw-r--r--kpovmodeler/pmfactory.h48
-rw-r--r--kpovmodeler/pmfiledialog.cpp104
-rw-r--r--kpovmodeler/pmfiledialog.h60
-rw-r--r--kpovmodeler/pmfinish.cpp765
-rw-r--r--kpovmodeler/pmfinish.h208
-rw-r--r--kpovmodeler/pmfinishedit.cpp474
-rw-r--r--kpovmodeler/pmfinishedit.h122
-rw-r--r--kpovmodeler/pmfog.cpp347
-rw-r--r--kpovmodeler/pmfog.h129
-rw-r--r--kpovmodeler/pmfogedit.cpp240
-rw-r--r--kpovmodeler/pmfogedit.h95
-rw-r--r--kpovmodeler/pmformulalabel.cpp190
-rw-r--r--kpovmodeler/pmformulalabel.h69
-rw-r--r--kpovmodeler/pmglobalphotons.cpp521
-rw-r--r--kpovmodeler/pmglobalphotons.h284
-rw-r--r--kpovmodeler/pmglobalphotonsedit.cpp328
-rw-r--r--kpovmodeler/pmglobalphotonsedit.h98
-rw-r--r--kpovmodeler/pmglobals.h29
-rw-r--r--kpovmodeler/pmglobalsettings.cpp516
-rw-r--r--kpovmodeler/pmglobalsettings.h268
-rw-r--r--kpovmodeler/pmglobalsettingsedit.cpp317
-rw-r--r--kpovmodeler/pmglobalsettingsedit.h93
-rw-r--r--kpovmodeler/pmglview.cpp1853
-rw-r--r--kpovmodeler/pmglview.h589
-rw-r--r--kpovmodeler/pmgraphicalobject.cpp248
-rw-r--r--kpovmodeler/pmgraphicalobject.h141
-rw-r--r--kpovmodeler/pmgraphicalobjectedit.cpp168
-rw-r--r--kpovmodeler/pmgraphicalobjectedit.h78
-rw-r--r--kpovmodeler/pmgridsettings.cpp155
-rw-r--r--kpovmodeler/pmgridsettings.h60
-rw-r--r--kpovmodeler/pmheightfield.cpp469
-rw-r--r--kpovmodeler/pmheightfield.h180
-rw-r--r--kpovmodeler/pmheightfieldedit.cpp201
-rw-r--r--kpovmodeler/pmheightfieldedit.h87
-rw-r--r--kpovmodeler/pmheightfieldroam.cpp422
-rw-r--r--kpovmodeler/pmheightfieldroam.h283
-rw-r--r--kpovmodeler/pmimagemap.cpp522
-rw-r--r--kpovmodeler/pmimagemap.h209
-rw-r--r--kpovmodeler/pmimagemapedit.cpp625
-rw-r--r--kpovmodeler/pmimagemapedit.h121
-rw-r--r--kpovmodeler/pminserterrordialog.cpp51
-rw-r--r--kpovmodeler/pminserterrordialog.h54
-rw-r--r--kpovmodeler/pminsertpopup.cpp90
-rw-r--r--kpovmodeler/pminsertpopup.h81
-rw-r--r--kpovmodeler/pminsertrules.dtd97
-rw-r--r--kpovmodeler/pminsertrulesystem.cpp1061
-rw-r--r--kpovmodeler/pminsertrulesystem.h678
-rw-r--r--kpovmodeler/pminterior.cpp343
-rw-r--r--kpovmodeler/pminterior.h128
-rw-r--r--kpovmodeler/pminterioredit.cpp212
-rw-r--r--kpovmodeler/pminterioredit.h85
-rw-r--r--kpovmodeler/pminteriortexture.cpp75
-rw-r--r--kpovmodeler/pminteriortexture.h71
-rw-r--r--kpovmodeler/pminteriortextureedit.cpp44
-rw-r--r--kpovmodeler/pminteriortextureedit.h58
-rw-r--r--kpovmodeler/pmiomanager.cpp96
-rw-r--r--kpovmodeler/pmiomanager.h184
-rw-r--r--kpovmodeler/pmisosurface.cpp419
-rw-r--r--kpovmodeler/pmisosurface.h234
-rw-r--r--kpovmodeler/pmisosurfaceedit.cpp326
-rw-r--r--kpovmodeler/pmisosurfaceedit.h92
-rw-r--r--kpovmodeler/pmjuliafractal.cpp449
-rw-r--r--kpovmodeler/pmjuliafractal.h174
-rw-r--r--kpovmodeler/pmjuliafractaledit.cpp380
-rw-r--r--kpovmodeler/pmjuliafractaledit.h79
-rw-r--r--kpovmodeler/pmlathe.cpp948
-rw-r--r--kpovmodeler/pmlathe.h193
-rw-r--r--kpovmodeler/pmlatheedit.cpp333
-rw-r--r--kpovmodeler/pmlatheedit.h89
-rw-r--r--kpovmodeler/pmlayoutsettings.cpp774
-rw-r--r--kpovmodeler/pmlayoutsettings.h174
-rw-r--r--kpovmodeler/pmlibrarybrowser.cpp304
-rw-r--r--kpovmodeler/pmlibrarybrowser.h119
-rw-r--r--kpovmodeler/pmlibraryentrypreview.cpp344
-rw-r--r--kpovmodeler/pmlibraryentrypreview.h119
-rw-r--r--kpovmodeler/pmlibraryhandle.cpp395
-rw-r--r--kpovmodeler/pmlibraryhandle.h210
-rw-r--r--kpovmodeler/pmlibraryhandleedit.cpp131
-rw-r--r--kpovmodeler/pmlibraryhandleedit.h66
-rw-r--r--kpovmodeler/pmlibraryiconview.cpp328
-rw-r--r--kpovmodeler/pmlibraryiconview.h123
-rw-r--r--kpovmodeler/pmlibrarymanager.cpp121
-rw-r--r--kpovmodeler/pmlibrarymanager.h97
-rw-r--r--kpovmodeler/pmlibraryobject.cpp331
-rw-r--r--kpovmodeler/pmlibraryobject.h136
-rw-r--r--kpovmodeler/pmlibraryobjectsearch.cpp86
-rw-r--r--kpovmodeler/pmlibraryobjectsearch.h55
-rw-r--r--kpovmodeler/pmlight.cpp1064
-rw-r--r--kpovmodeler/pmlight.h372
-rw-r--r--kpovmodeler/pmlightedit.cpp450
-rw-r--r--kpovmodeler/pmlightedit.h115
-rw-r--r--kpovmodeler/pmlightgroup.cpp134
-rw-r--r--kpovmodeler/pmlightgroup.h98
-rw-r--r--kpovmodeler/pmlightgroupedit.cpp78
-rw-r--r--kpovmodeler/pmlightgroupedit.h64
-rw-r--r--kpovmodeler/pmline.cpp22
-rw-r--r--kpovmodeler/pmline.h102
-rw-r--r--kpovmodeler/pmlineedits.cpp229
-rw-r--r--kpovmodeler/pmlineedits.h133
-rw-r--r--kpovmodeler/pmlinkedit.cpp146
-rw-r--r--kpovmodeler/pmlinkedit.h105
-rw-r--r--kpovmodeler/pmlistpattern.cpp469
-rw-r--r--kpovmodeler/pmlistpattern.h351
-rw-r--r--kpovmodeler/pmlistpatternedit.cpp225
-rw-r--r--kpovmodeler/pmlistpatternedit.h78
-rw-r--r--kpovmodeler/pmlookslike.cpp92
-rw-r--r--kpovmodeler/pmlookslike.h82
-rw-r--r--kpovmodeler/pmmapmemento.cpp51
-rw-r--r--kpovmodeler/pmmapmemento.h81
-rw-r--r--kpovmodeler/pmmaterial.cpp75
-rw-r--r--kpovmodeler/pmmaterial.h75
-rw-r--r--kpovmodeler/pmmaterialedit.cpp44
-rw-r--r--kpovmodeler/pmmaterialedit.h58
-rw-r--r--kpovmodeler/pmmaterialmap.cpp338
-rw-r--r--kpovmodeler/pmmaterialmap.h153
-rw-r--r--kpovmodeler/pmmaterialmapedit.cpp299
-rw-r--r--kpovmodeler/pmmaterialmapedit.h81
-rw-r--r--kpovmodeler/pmmath.cpp67
-rw-r--r--kpovmodeler/pmmath.h48
-rw-r--r--kpovmodeler/pmmatrix.cpp442
-rw-r--r--kpovmodeler/pmmatrix.h188
-rw-r--r--kpovmodeler/pmmedia.cpp480
-rw-r--r--kpovmodeler/pmmedia.h149
-rw-r--r--kpovmodeler/pmmediaedit.cpp370
-rw-r--r--kpovmodeler/pmmediaedit.h102
-rw-r--r--kpovmodeler/pmmemento.cpp220
-rw-r--r--kpovmodeler/pmmemento.h318
-rw-r--r--kpovmodeler/pmmesh.cpp557
-rw-r--r--kpovmodeler/pmmesh.h142
-rw-r--r--kpovmodeler/pmmeshedit.cpp100
-rw-r--r--kpovmodeler/pmmeshedit.h67
-rw-r--r--kpovmodeler/pmmessage.cpp43
-rw-r--r--kpovmodeler/pmmessage.h79
-rw-r--r--kpovmodeler/pmmetaobject.cpp95
-rw-r--r--kpovmodeler/pmmetaobject.h416
-rw-r--r--kpovmodeler/pmmovecommand.cpp478
-rw-r--r--kpovmodeler/pmmovecommand.h88
-rw-r--r--kpovmodeler/pmnamedobject.cpp111
-rw-r--r--kpovmodeler/pmnamedobject.h89
-rw-r--r--kpovmodeler/pmnamedobjectedit.cpp81
-rw-r--r--kpovmodeler/pmnamedobjectedit.h64
-rw-r--r--kpovmodeler/pmnormal.cpp189
-rw-r--r--kpovmodeler/pmnormal.h122
-rw-r--r--kpovmodeler/pmnormaledit.cpp118
-rw-r--r--kpovmodeler/pmnormaledit.h70
-rw-r--r--kpovmodeler/pmobject.cpp283
-rw-r--r--kpovmodeler/pmobject.h511
-rw-r--r--kpovmodeler/pmobjectaction.h100
-rw-r--r--kpovmodeler/pmobjectdrag.cpp230
-rw-r--r--kpovmodeler/pmobjectdrag.h81
-rw-r--r--kpovmodeler/pmobjectlibrarysettings.cpp189
-rw-r--r--kpovmodeler/pmobjectlibrarysettings.h78
-rw-r--r--kpovmodeler/pmobjectlink.cpp197
-rw-r--r--kpovmodeler/pmobjectlink.h99
-rw-r--r--kpovmodeler/pmobjectlinkedit.cpp74
-rw-r--r--kpovmodeler/pmobjectlinkedit.h62
-rw-r--r--kpovmodeler/pmobjectselect.cpp361
-rw-r--r--kpovmodeler/pmobjectselect.h132
-rw-r--r--kpovmodeler/pmobjectsettings.cpp550
-rw-r--r--kpovmodeler/pmobjectsettings.h78
-rw-r--r--kpovmodeler/pmopenglsettings.cpp59
-rw-r--r--kpovmodeler/pmopenglsettings.h54
-rw-r--r--kpovmodeler/pmoutputdevice.cpp203
-rw-r--r--kpovmodeler/pmoutputdevice.h159
-rw-r--r--kpovmodeler/pmpalettevalue.cpp81
-rw-r--r--kpovmodeler/pmpalettevalue.h78
-rw-r--r--kpovmodeler/pmpalettevalueedit.cpp99
-rw-r--r--kpovmodeler/pmpalettevalueedit.h67
-rw-r--r--kpovmodeler/pmpalettevaluememento.cpp84
-rw-r--r--kpovmodeler/pmpalettevaluememento.h85
-rw-r--r--kpovmodeler/pmparser.cpp433
-rw-r--r--kpovmodeler/pmparser.h299
-rw-r--r--kpovmodeler/pmpart.cpp2884
-rw-r--r--kpovmodeler/pmpart.h1041
-rw-r--r--kpovmodeler/pmpartiface.h119
-rw-r--r--kpovmodeler/pmpattern.cpp1126
-rw-r--r--kpovmodeler/pmpattern.h449
-rw-r--r--kpovmodeler/pmpatternedit.cpp1073
-rw-r--r--kpovmodeler/pmpatternedit.h164
-rw-r--r--kpovmodeler/pmphotons.cpp240
-rw-r--r--kpovmodeler/pmphotons.h160
-rw-r--r--kpovmodeler/pmphotonsedit.cpp160
-rw-r--r--kpovmodeler/pmphotonsedit.h79
-rw-r--r--kpovmodeler/pmpigment.cpp124
-rw-r--r--kpovmodeler/pmpigment.h95
-rw-r--r--kpovmodeler/pmpigmentedit.cpp68
-rw-r--r--kpovmodeler/pmpigmentedit.h60
-rw-r--r--kpovmodeler/pmplane.cpp276
-rw-r--r--kpovmodeler/pmplane.h148
-rw-r--r--kpovmodeler/pmplaneedit.cpp124
-rw-r--r--kpovmodeler/pmplaneedit.h66
-rw-r--r--kpovmodeler/pmplanenormalcontrolpoint.cpp93
-rw-r--r--kpovmodeler/pmplanenormalcontrolpoint.h92
-rw-r--r--kpovmodeler/pmpluginmanager.cpp115
-rw-r--r--kpovmodeler/pmpluginmanager.h113
-rw-r--r--kpovmodeler/pmpluginsettings.cpp150
-rw-r--r--kpovmodeler/pmpluginsettings.h62
-rw-r--r--kpovmodeler/pmpoint.cpp98
-rw-r--r--kpovmodeler/pmpoint.h122
-rw-r--r--kpovmodeler/pmpolynom.cpp238
-rw-r--r--kpovmodeler/pmpolynom.h105
-rw-r--r--kpovmodeler/pmpolynomedit.cpp255
-rw-r--r--kpovmodeler/pmpolynomedit.h80
-rw-r--r--kpovmodeler/pmpolynomexponents.cpp71
-rw-r--r--kpovmodeler/pmpolynomexponents.h129
-rw-r--r--kpovmodeler/pmpovray31format.cpp153
-rw-r--r--kpovmodeler/pmpovray31format.h64
-rw-r--r--kpovmodeler/pmpovray31serialization.cpp2199
-rw-r--r--kpovmodeler/pmpovray31serialization.h103
-rw-r--r--kpovmodeler/pmpovray35format.cpp100
-rw-r--r--kpovmodeler/pmpovray35format.h64
-rw-r--r--kpovmodeler/pmpovray35serialization.cpp1471
-rw-r--r--kpovmodeler/pmpovray35serialization.h49
-rw-r--r--kpovmodeler/pmpovrayformat.cpp52
-rw-r--r--kpovmodeler/pmpovrayformat.h94
-rw-r--r--kpovmodeler/pmpovraymatrix.cpp152
-rw-r--r--kpovmodeler/pmpovraymatrix.h97
-rw-r--r--kpovmodeler/pmpovraymatrixedit.cpp102
-rw-r--r--kpovmodeler/pmpovraymatrixedit.h62
-rw-r--r--kpovmodeler/pmpovrayoutputwidget.cpp115
-rw-r--r--kpovmodeler/pmpovrayoutputwidget.h77
-rw-r--r--kpovmodeler/pmpovrayparser.cpp7213
-rw-r--r--kpovmodeler/pmpovrayparser.h534
-rw-r--r--kpovmodeler/pmpovrayrenderwidget.cpp437
-rw-r--r--kpovmodeler/pmpovrayrenderwidget.h177
-rw-r--r--kpovmodeler/pmpovraysettings.cpp308
-rw-r--r--kpovmodeler/pmpovraysettings.h98
-rw-r--r--kpovmodeler/pmpovraywidget.cpp411
-rw-r--r--kpovmodeler/pmpovraywidget.h103
-rw-r--r--kpovmodeler/pmpreviewsettings.cpp207
-rw-r--r--kpovmodeler/pmpreviewsettings.h69
-rw-r--r--kpovmodeler/pmprism.cpp1187
-rw-r--r--kpovmodeler/pmprism.h224
-rw-r--r--kpovmodeler/pmprismedit.cpp696
-rw-r--r--kpovmodeler/pmprismedit.h122
-rw-r--r--kpovmodeler/pmprismmemento.cpp55
-rw-r--r--kpovmodeler/pmprismmemento.h71
-rw-r--r--kpovmodeler/pmprojectedthrough.cpp92
-rw-r--r--kpovmodeler/pmprojectedthrough.h82
-rw-r--r--kpovmodeler/pmprototypemanager.cpp243
-rw-r--r--kpovmodeler/pmprototypemanager.h149
-rw-r--r--kpovmodeler/pmquickcolor.cpp132
-rw-r--r--kpovmodeler/pmquickcolor.h100
-rw-r--r--kpovmodeler/pmquickcoloredit.cpp77
-rw-r--r--kpovmodeler/pmquickcoloredit.h65
-rw-r--r--kpovmodeler/pmradiosity.cpp428
-rw-r--r--kpovmodeler/pmradiosity.h241
-rw-r--r--kpovmodeler/pmradiosityedit.cpp233
-rw-r--r--kpovmodeler/pmradiosityedit.h81
-rw-r--r--kpovmodeler/pmrainbow.cpp422
-rw-r--r--kpovmodeler/pmrainbow.h139
-rw-r--r--kpovmodeler/pmrainbowedit.cpp278
-rw-r--r--kpovmodeler/pmrainbowedit.h90
-rw-r--r--kpovmodeler/pmraw.cpp135
-rw-r--r--kpovmodeler/pmraw.h90
-rw-r--r--kpovmodeler/pmrawedit.cpp79
-rw-r--r--kpovmodeler/pmrawedit.h62
-rw-r--r--kpovmodeler/pmrecursiveobjectiterator.cpp62
-rw-r--r--kpovmodeler/pmrecursiveobjectiterator.h49
-rw-r--r--kpovmodeler/pmrendermanager.cpp1647
-rw-r--r--kpovmodeler/pmrendermanager.h435
-rw-r--r--kpovmodeler/pmrendermode.cpp220
-rw-r--r--kpovmodeler/pmrendermode.h128
-rw-r--r--kpovmodeler/pmrendermodesdialog.cpp611
-rw-r--r--kpovmodeler/pmrendermodesdialog.h179
-rw-r--r--kpovmodeler/pmresourcelocator.cpp103
-rw-r--r--kpovmodeler/pmresourcelocator.h65
-rw-r--r--kpovmodeler/pmrotate.cpp164
-rw-r--r--kpovmodeler/pmrotate.h102
-rw-r--r--kpovmodeler/pmrotatecontrolpoint.cpp78
-rw-r--r--kpovmodeler/pmrotatecontrolpoint.h73
-rw-r--r--kpovmodeler/pmrotateedit.cpp74
-rw-r--r--kpovmodeler/pmrotateedit.h62
-rw-r--r--kpovmodeler/pmscale.cpp163
-rw-r--r--kpovmodeler/pmscale.h103
-rw-r--r--kpovmodeler/pmscalecontrolpoint.cpp58
-rw-r--r--kpovmodeler/pmscalecontrolpoint.h71
-rw-r--r--kpovmodeler/pmscaleedit.cpp74
-rw-r--r--kpovmodeler/pmscaleedit.h62
-rw-r--r--kpovmodeler/pmscanner.cpp1353
-rw-r--r--kpovmodeler/pmscanner.h191
-rw-r--r--kpovmodeler/pmscene.cpp119
-rw-r--r--kpovmodeler/pmscene.h92
-rw-r--r--kpovmodeler/pmserializer.cpp93
-rw-r--r--kpovmodeler/pmserializer.h179
-rw-r--r--kpovmodeler/pmsettingsdialog.cpp263
-rw-r--r--kpovmodeler/pmsettingsdialog.h187
-rw-r--r--kpovmodeler/pmshell.cpp676
-rw-r--r--kpovmodeler/pmshell.h172
-rw-r--r--kpovmodeler/pmskysphere.cpp76
-rw-r--r--kpovmodeler/pmskysphere.h75
-rw-r--r--kpovmodeler/pmskysphereedit.cpp44
-rw-r--r--kpovmodeler/pmskysphereedit.h58
-rw-r--r--kpovmodeler/pmslope.cpp146
-rw-r--r--kpovmodeler/pmslope.h94
-rw-r--r--kpovmodeler/pmslopeedit.cpp95
-rw-r--r--kpovmodeler/pmslopeedit.h68
-rw-r--r--kpovmodeler/pmsolidcolor.cpp127
-rw-r--r--kpovmodeler/pmsolidcolor.h97
-rw-r--r--kpovmodeler/pmsolidcoloredit.cpp79
-rw-r--r--kpovmodeler/pmsolidcoloredit.h62
-rw-r--r--kpovmodeler/pmsolidobject.cpp140
-rw-r--r--kpovmodeler/pmsolidobject.h94
-rw-r--r--kpovmodeler/pmsolidobjectedit.cpp82
-rw-r--r--kpovmodeler/pmsolidobjectedit.h63
-rw-r--r--kpovmodeler/pmsor.cpp708
-rw-r--r--kpovmodeler/pmsor.h191
-rw-r--r--kpovmodeler/pmsorcontrolpoint.cpp228
-rw-r--r--kpovmodeler/pmsorcontrolpoint.h99
-rw-r--r--kpovmodeler/pmsoredit.cpp282
-rw-r--r--kpovmodeler/pmsoredit.h86
-rw-r--r--kpovmodeler/pmsorsegment.cpp97
-rw-r--r--kpovmodeler/pmsorsegment.h77
-rw-r--r--kpovmodeler/pmsphere.cpp411
-rw-r--r--kpovmodeler/pmsphere.h165
-rw-r--r--kpovmodeler/pmsphereedit.cpp95
-rw-r--r--kpovmodeler/pmsphereedit.h64
-rw-r--r--kpovmodeler/pmspheresweep.cpp894
-rw-r--r--kpovmodeler/pmspheresweep.h245
-rw-r--r--kpovmodeler/pmspheresweepedit.cpp354
-rw-r--r--kpovmodeler/pmspheresweepedit.h90
-rw-r--r--kpovmodeler/pmsplinememento.cpp58
-rw-r--r--kpovmodeler/pmsplinememento.h68
-rw-r--r--kpovmodeler/pmsplinesegment.cpp107
-rw-r--r--kpovmodeler/pmsplinesegment.h122
-rw-r--r--kpovmodeler/pmsqe.cpp413
-rw-r--r--kpovmodeler/pmsqe.h155
-rw-r--r--kpovmodeler/pmsqeedit.cpp93
-rw-r--r--kpovmodeler/pmsqeedit.h63
-rw-r--r--kpovmodeler/pmsymboltable.cpp121
-rw-r--r--kpovmodeler/pmsymboltable.h128
-rw-r--r--kpovmodeler/pmtext.cpp339
-rw-r--r--kpovmodeler/pmtext.h147
-rw-r--r--kpovmodeler/pmtextedit.cpp138
-rw-r--r--kpovmodeler/pmtextedit.h74
-rw-r--r--kpovmodeler/pmtexture.cpp124
-rw-r--r--kpovmodeler/pmtexture.h95
-rw-r--r--kpovmodeler/pmtexturebase.cpp180
-rw-r--r--kpovmodeler/pmtexturebase.h96
-rw-r--r--kpovmodeler/pmtexturebaseedit.cpp72
-rw-r--r--kpovmodeler/pmtexturebaseedit.h64
-rw-r--r--kpovmodeler/pmtextureedit.cpp67
-rw-r--r--kpovmodeler/pmtextureedit.h60
-rw-r--r--kpovmodeler/pmtexturemap.cpp601
-rw-r--r--kpovmodeler/pmtexturemap.h368
-rw-r--r--kpovmodeler/pmtexturemapedit.cpp152
-rw-r--r--kpovmodeler/pmtexturemapedit.h70
-rw-r--r--kpovmodeler/pmthreestate.h26
-rw-r--r--kpovmodeler/pmtokens.h463
-rw-r--r--kpovmodeler/pmtorus.cpp379
-rw-r--r--kpovmodeler/pmtorus.h172
-rw-r--r--kpovmodeler/pmtorusedit.cpp105
-rw-r--r--kpovmodeler/pmtorusedit.h65
-rw-r--r--kpovmodeler/pmtranslate.cpp162
-rw-r--r--kpovmodeler/pmtranslate.h102
-rw-r--r--kpovmodeler/pmtranslatecontrolpoint.cpp50
-rw-r--r--kpovmodeler/pmtranslatecontrolpoint.h71
-rw-r--r--kpovmodeler/pmtranslateedit.cpp74
-rw-r--r--kpovmodeler/pmtranslateedit.h62
-rw-r--r--kpovmodeler/pmtreeview.cpp820
-rw-r--r--kpovmodeler/pmtreeview.h182
-rw-r--r--kpovmodeler/pmtreeviewitem.cpp117
-rw-r--r--kpovmodeler/pmtreeviewitem.h88
-rw-r--r--kpovmodeler/pmtriangle.cpp621
-rw-r--r--kpovmodeler/pmtriangle.h158
-rw-r--r--kpovmodeler/pmtriangleedit.cpp273
-rw-r--r--kpovmodeler/pmtriangleedit.h77
-rw-r--r--kpovmodeler/pmtruetypecache.cpp395
-rw-r--r--kpovmodeler/pmtruetypecache.h194
-rw-r--r--kpovmodeler/pmunknownview.cpp37
-rw-r--r--kpovmodeler/pmunknownview.h47
-rw-r--r--kpovmodeler/pmvalue.h102
-rw-r--r--kpovmodeler/pmvariant.cpp920
-rw-r--r--kpovmodeler/pmvariant.h221
-rw-r--r--kpovmodeler/pmvector.cpp593
-rw-r--r--kpovmodeler/pmvector.h275
-rw-r--r--kpovmodeler/pmvectorcontrolpoint.cpp89
-rw-r--r--kpovmodeler/pmvectorcontrolpoint.h101
-rw-r--r--kpovmodeler/pmvectoredit.cpp235
-rw-r--r--kpovmodeler/pmvectoredit.h100
-rw-r--r--kpovmodeler/pmvectorlistedit.cpp357
-rw-r--r--kpovmodeler/pmvectorlistedit.h174
-rw-r--r--kpovmodeler/pmview.cpp108
-rw-r--r--kpovmodeler/pmview.h76
-rw-r--r--kpovmodeler/pmviewbase.cpp20
-rw-r--r--kpovmodeler/pmviewbase.h128
-rw-r--r--kpovmodeler/pmviewfactory.cpp94
-rw-r--r--kpovmodeler/pmviewfactory.h145
-rw-r--r--kpovmodeler/pmviewlayoutmanager.cpp935
-rw-r--r--kpovmodeler/pmviewlayoutmanager.h306
-rw-r--r--kpovmodeler/pmviewstructure.cpp127
-rw-r--r--kpovmodeler/pmviewstructure.h222
-rw-r--r--kpovmodeler/pmwarp.cpp548
-rw-r--r--kpovmodeler/pmwarp.h162
-rw-r--r--kpovmodeler/pmwarpedit.cpp407
-rw-r--r--kpovmodeler/pmwarpedit.h110
-rw-r--r--kpovmodeler/pmxmlhelper.cpp160
-rw-r--r--kpovmodeler/pmxmlhelper.h121
-rw-r--r--kpovmodeler/pmxmlparser.cpp177
-rw-r--r--kpovmodeler/pmxmlparser.h84
-rw-r--r--kpovmodeler/povraydocmap.xml174
-rw-r--r--kpovmodeler/questionmark.pngbin0 -> 12749 bytes
-rw-r--r--kpovmodeler/version.h18
-rw-r--r--kruler/Makefile.am25
-rw-r--r--kruler/eventsrc192
-rw-r--r--kruler/klineal.cpp746
-rw-r--r--kruler/klineal.h106
-rw-r--r--kruler/kruler.desktop90
-rw-r--r--kruler/main.cpp48
-rw-r--r--kruler/move.wavbin0 -> 2656 bytes
-rw-r--r--kruler/pics/Makefile.am5
-rw-r--r--kruler/pics/hi16-app-kruler.pngbin0 -> 391 bytes
-rw-r--r--kruler/pics/hi22-app-kruler.pngbin0 -> 310 bytes
-rw-r--r--kruler/pics/hi32-app-kruler.pngbin0 -> 730 bytes
-rw-r--r--kruler/pics/hi48-app-kruler.pngbin0 -> 932 bytes
-rw-r--r--kruler/pics/kruler-east.pngbin0 -> 446 bytes
-rw-r--r--kruler/pics/kruler-north.pngbin0 -> 310 bytes
-rw-r--r--kruler/pics/kruler-south.pngbin0 -> 300 bytes
-rw-r--r--kruler/pics/kruler-west.pngbin0 -> 439 bytes
-rw-r--r--kruler/uninstall.desktop2
-rw-r--r--ksnapshot/Makefile.am21
-rw-r--r--ksnapshot/README29
-rw-r--r--ksnapshot/configure.in.in6
-rw-r--r--ksnapshot/hi16-app-ksnapshot.pngbin0 -> 852 bytes
-rw-r--r--ksnapshot/hi22-app-ksnapshot.pngbin0 -> 1328 bytes
-rw-r--r--ksnapshot/hi32-app-ksnapshot.pngbin0 -> 2056 bytes
-rw-r--r--ksnapshot/hi48-app-ksnapshot.pngbin0 -> 3530 bytes
-rw-r--r--ksnapshot/hisc-app-ksnapshot.svgzbin0 -> 5445 bytes
-rw-r--r--ksnapshot/ksnapshot.cpp510
-rw-r--r--ksnapshot/ksnapshot.desktop92
-rw-r--r--ksnapshot/ksnapshot.h150
-rw-r--r--ksnapshot/ksnapshotiface.h65
-rw-r--r--ksnapshot/ksnapshotwidget.ui361
-rw-r--r--ksnapshot/ksnapshotwidget.ui.h138
-rw-r--r--ksnapshot/main.cpp77
-rw-r--r--ksnapshot/regiongrabber.cpp177
-rw-r--r--ksnapshot/regiongrabber.h70
-rw-r--r--ksnapshot/uninstall.desktop2
-rw-r--r--ksnapshot/windowgrabber.cpp353
-rw-r--r--ksnapshot/windowgrabber.h59
-rw-r--r--ksvg/AUTHORS2
-rw-r--r--ksvg/FAQ17
-rw-r--r--ksvg/Makefile.am115
-rw-r--r--ksvg/NEWS8
-rw-r--r--ksvg/README9
-rw-r--r--ksvg/RELEASE-TODO10
-rw-r--r--ksvg/TODO10
-rw-r--r--ksvg/VERSION1
-rw-r--r--ksvg/configure.in.bot25
-rw-r--r--ksvg/configure.in.in203
-rw-r--r--ksvg/core/CanvasFactory.cpp176
-rw-r--r--ksvg/core/CanvasFactory.h69
-rw-r--r--ksvg/core/CanvasItem.h154
-rw-r--r--ksvg/core/CanvasItems.cpp509
-rw-r--r--ksvg/core/CanvasItems.h133
-rw-r--r--ksvg/core/DocumentFactory.cpp110
-rw-r--r--ksvg/core/DocumentFactory.h63
-rw-r--r--ksvg/core/KSVGCanvas.cpp786
-rw-r--r--ksvg/core/KSVGCanvas.h190
-rw-r--r--ksvg/core/KSVGHelper.cpp92
-rw-r--r--ksvg/core/KSVGHelper.h144
-rw-r--r--ksvg/core/KSVGLoader.cpp449
-rw-r--r--ksvg/core/KSVGLoader.h92
-rw-r--r--ksvg/core/KSVGReader.cc500
-rw-r--r--ksvg/core/KSVGReader.h67
-rw-r--r--ksvg/core/KSVGTextChunk.cpp69
-rw-r--r--ksvg/core/KSVGTextChunk.h54
-rw-r--r--ksvg/core/Makefile.am16
-rw-r--r--ksvg/core/ksvgrenderer.desktop56
-rw-r--r--ksvg/data/SVGAElementImpl.lut.h20
-rw-r--r--ksvg/data/SVGAngleImpl.lut.h77
-rw-r--r--ksvg/data/SVGAnimatedAngleImpl.lut.h22
-rw-r--r--ksvg/data/SVGAnimatedBooleanImpl.lut.h22
-rw-r--r--ksvg/data/SVGAnimatedEnumerationImpl.lut.h22
-rw-r--r--ksvg/data/SVGAnimatedIntegerImpl.lut.h22
-rw-r--r--ksvg/data/SVGAnimatedLengthImpl.lut.h22
-rw-r--r--ksvg/data/SVGAnimatedLengthListImpl.lut.h22
-rw-r--r--ksvg/data/SVGAnimatedNumberImpl.lut.h22
-rw-r--r--ksvg/data/SVGAnimatedNumberListImpl.lut.h22
-rw-r--r--ksvg/data/SVGAnimatedPathDataImpl.lut.h28
-rw-r--r--ksvg/data/SVGAnimatedPointsImpl.lut.h22
-rw-r--r--ksvg/data/SVGAnimatedPreserveAspectRatioImpl.lut.h22
-rw-r--r--ksvg/data/SVGAnimatedRectImpl.lut.h22
-rw-r--r--ksvg/data/SVGAnimatedStringImpl.lut.h22
-rw-r--r--ksvg/data/SVGAnimatedTransformListImpl.lut.h22
-rw-r--r--ksvg/data/SVGAnimationElementImpl.lut.h94
-rw-r--r--ksvg/data/SVGCircleElementImpl.lut.h26
-rw-r--r--ksvg/data/SVGClipPathElementImpl.lut.h20
-rw-r--r--ksvg/data/SVGColorImpl.lut.h76
-rw-r--r--ksvg/data/SVGColorProfileElementImpl.lut.h26
-rw-r--r--ksvg/data/SVGCursorElementImpl.lut.h22
-rw-r--r--ksvg/data/SVGDocumentImpl.lut.h67
-rw-r--r--ksvg/data/SVGEcma.lut.h396
-rw-r--r--ksvg/data/SVGElementImpl.lut.h92
-rw-r--r--ksvg/data/SVGEllipseElementImpl.lut.h28
-rw-r--r--ksvg/data/SVGEventImpl.lut.h271
-rw-r--r--ksvg/data/SVGExternalResourcesRequiredImpl.lut.h20
-rw-r--r--ksvg/data/SVGFitToViewBoxImpl.lut.h22
-rw-r--r--ksvg/data/SVGForeignObjectElementImpl.lut.h26
-rw-r--r--ksvg/data/SVGGlyphElementImpl.lut.h39
-rw-r--r--ksvg/data/SVGGlyphRefElementImpl.lut.h28
-rw-r--r--ksvg/data/SVGGradientElementImpl.lut.h51
-rw-r--r--ksvg/data/SVGICCColorImpl.lut.h23
-rw-r--r--ksvg/data/SVGImageElementImpl.lut.h31
-rw-r--r--ksvg/data/SVGLangSpaceImpl.lut.h24
-rw-r--r--ksvg/data/SVGLengthImpl.lut.h87
-rw-r--r--ksvg/data/SVGLengthListImpl.lut.h55
-rw-r--r--ksvg/data/SVGLineElementImpl.lut.h27
-rw-r--r--ksvg/data/SVGLinearGradientElementImpl.lut.h27
-rw-r--r--ksvg/data/SVGLocatableImpl.lut.h49
-rw-r--r--ksvg/data/SVGMarkerElementImpl.lut.h90
-rw-r--r--ksvg/data/SVGMaskElementImpl.lut.h31
-rw-r--r--ksvg/data/SVGMatrixImpl.lut.h74
-rw-r--r--ksvg/data/SVGNumberImpl.lut.h20
-rw-r--r--ksvg/data/SVGNumberListImpl.lut.h55
-rw-r--r--ksvg/data/SVGPaintImpl.lut.h59
-rw-r--r--ksvg/data/SVGPathElementImpl.lut.h87
-rw-r--r--ksvg/data/SVGPathSegArcImpl.lut.h75
-rw-r--r--ksvg/data/SVGPathSegCurvetoCubicImpl.lut.h65
-rw-r--r--ksvg/data/SVGPathSegCurvetoCubicSmoothImpl.lut.h55
-rw-r--r--ksvg/data/SVGPathSegCurvetoQuadraticImpl.lut.h53
-rw-r--r--ksvg/data/SVGPathSegCurvetoQuadraticSmoothImpl.lut.h43
-rw-r--r--ksvg/data/SVGPathSegImpl.lut.h88
-rw-r--r--ksvg/data/SVGPathSegLinetoHorizontalImpl.lut.h39
-rw-r--r--ksvg/data/SVGPathSegLinetoImpl.lut.h43
-rw-r--r--ksvg/data/SVGPathSegLinetoVerticalImpl.lut.h39
-rw-r--r--ksvg/data/SVGPathSegListImpl.lut.h55
-rw-r--r--ksvg/data/SVGPathSegMovetoImpl.lut.h43
-rw-r--r--ksvg/data/SVGPatternElementImpl.lut.h37
-rw-r--r--ksvg/data/SVGPointImpl.lut.h22
-rw-r--r--ksvg/data/SVGPointListImpl.lut.h55
-rw-r--r--ksvg/data/SVGPreserveAspectRatioImpl.lut.h73
-rw-r--r--ksvg/data/SVGRadialGradientElementImpl.lut.h30
-rw-r--r--ksvg/data/SVGRectElementImpl.lut.h29
-rw-r--r--ksvg/data/SVGRectImpl.lut.h26
-rw-r--r--ksvg/data/SVGSVGElementImpl.lut.h136
-rw-r--r--ksvg/data/SVGScriptElementImpl.lut.h20
-rw-r--r--ksvg/data/SVGStopElementImpl.lut.h22
-rw-r--r--ksvg/data/SVGStringListImpl.lut.h74
-rw-r--r--ksvg/data/SVGStylableImpl.lut.h143
-rw-r--r--ksvg/data/SVGStyleElementImpl.lut.h27
-rw-r--r--ksvg/data/SVGSymbolElementImpl.lut.h22
-rw-r--r--ksvg/data/SVGTestsImpl.lut.h45
-rw-r--r--ksvg/data/SVGTextContentElementImpl.lut.h84
-rw-r--r--ksvg/data/SVGTextPathElementImpl.lut.h56
-rw-r--r--ksvg/data/SVGTextPositioningElementImpl.lut.h28
-rw-r--r--ksvg/data/SVGTransformImpl.lut.h89
-rw-r--r--ksvg/data/SVGTransformListImpl.lut.h55
-rw-r--r--ksvg/data/SVGTransformableImpl.lut.h20
-rw-r--r--ksvg/data/SVGURIReferenceImpl.lut.h20
-rw-r--r--ksvg/data/SVGUseElementImpl.lut.h36
-rw-r--r--ksvg/data/SVGViewElementImpl.lut.h20
-rw-r--r--ksvg/data/SVGZoomAndPanImpl.lut.h45
-rw-r--r--ksvg/data/SVGZoomEventImpl.lut.h29
-rw-r--r--ksvg/data/ksvg_window.lut.h98
-rw-r--r--ksvg/dom/Makefile.am58
-rw-r--r--ksvg/dom/SVGAElement.cc80
-rw-r--r--ksvg/dom/SVGAElement.h64
-rw-r--r--ksvg/dom/SVGAltGlyphDefElement.cc67
-rw-r--r--ksvg/dom/SVGAltGlyphDefElement.h50
-rw-r--r--ksvg/dom/SVGAltGlyphElement.cc80
-rw-r--r--ksvg/dom/SVGAltGlyphElement.h55
-rw-r--r--ksvg/dom/SVGAngle.cc120
-rw-r--r--ksvg/dom/SVGAngle.h74
-rw-r--r--ksvg/dom/SVGAnimateColorElement.cc67
-rw-r--r--ksvg/dom/SVGAnimateColorElement.h50
-rw-r--r--ksvg/dom/SVGAnimateElement.cc67
-rw-r--r--ksvg/dom/SVGAnimateElement.h50
-rw-r--r--ksvg/dom/SVGAnimateMotionElement.cc65
-rw-r--r--ksvg/dom/SVGAnimateMotionElement.h47
-rw-r--r--ksvg/dom/SVGAnimateTransformElement.cc67
-rw-r--r--ksvg/dom/SVGAnimateTransformElement.h50
-rw-r--r--ksvg/dom/SVGAnimatedAngle.cc79
-rw-r--r--ksvg/dom/SVGAnimatedAngle.h52
-rw-r--r--ksvg/dom/SVGAnimatedBoolean.cc84
-rw-r--r--ksvg/dom/SVGAnimatedBoolean.h53
-rw-r--r--ksvg/dom/SVGAnimatedEnumeration.cc84
-rw-r--r--ksvg/dom/SVGAnimatedEnumeration.h53
-rw-r--r--ksvg/dom/SVGAnimatedInteger.cc84
-rw-r--r--ksvg/dom/SVGAnimatedInteger.h53
-rw-r--r--ksvg/dom/SVGAnimatedLength.cc79
-rw-r--r--ksvg/dom/SVGAnimatedLength.h52
-rw-r--r--ksvg/dom/SVGAnimatedLengthList.cc78
-rw-r--r--ksvg/dom/SVGAnimatedLengthList.h51
-rw-r--r--ksvg/dom/SVGAnimatedNumber.cc84
-rw-r--r--ksvg/dom/SVGAnimatedNumber.h53
-rw-r--r--ksvg/dom/SVGAnimatedNumberList.cc78
-rw-r--r--ksvg/dom/SVGAnimatedNumberList.h51
-rw-r--r--ksvg/dom/SVGAnimatedPathData.cc91
-rw-r--r--ksvg/dom/SVGAnimatedPathData.h54
-rw-r--r--ksvg/dom/SVGAnimatedPoints.cc79
-rw-r--r--ksvg/dom/SVGAnimatedPoints.h52
-rw-r--r--ksvg/dom/SVGAnimatedPreserveAspectRatio.cc79
-rw-r--r--ksvg/dom/SVGAnimatedPreserveAspectRatio.h52
-rw-r--r--ksvg/dom/SVGAnimatedRect.cc79
-rw-r--r--ksvg/dom/SVGAnimatedRect.h51
-rw-r--r--ksvg/dom/SVGAnimatedString.cc84
-rw-r--r--ksvg/dom/SVGAnimatedString.h55
-rw-r--r--ksvg/dom/SVGAnimatedTransformList.cc79
-rw-r--r--ksvg/dom/SVGAnimatedTransformList.h52
-rw-r--r--ksvg/dom/SVGAnimationElement.cc93
-rw-r--r--ksvg/dom/SVGAnimationElement.h60
-rw-r--r--ksvg/dom/SVGCSSRule.cc66
-rw-r--r--ksvg/dom/SVGCSSRule.h51
-rw-r--r--ksvg/dom/SVGCircleElement.cc92
-rw-r--r--ksvg/dom/SVGCircleElement.h117
-rw-r--r--ksvg/dom/SVGClipPathElement.cc79
-rw-r--r--ksvg/dom/SVGClipPathElement.h65
-rw-r--r--ksvg/dom/SVGColor.cc105
-rw-r--r--ksvg/dom/SVGColor.h69
-rw-r--r--ksvg/dom/SVGColorProfileElement.cc105
-rw-r--r--ksvg/dom/SVGColorProfileElement.h62
-rw-r--r--ksvg/dom/SVGColorProfileRule.cc103
-rw-r--r--ksvg/dom/SVGColorProfileRule.h57
-rw-r--r--ksvg/dom/SVGComponentTransferFunctionElement.cc112
-rw-r--r--ksvg/dom/SVGComponentTransferFunctionElement.h71
-rw-r--r--ksvg/dom/SVGCursorElement.cc83
-rw-r--r--ksvg/dom/SVGCursorElement.h60
-rw-r--r--ksvg/dom/SVGDefinitionSrcElement.cc67
-rw-r--r--ksvg/dom/SVGDefinitionSrcElement.h50
-rw-r--r--ksvg/dom/SVGDefsElement.cc72
-rw-r--r--ksvg/dom/SVGDefsElement.h78
-rw-r--r--ksvg/dom/SVGDescElement.cc69
-rw-r--r--ksvg/dom/SVGDescElement.h54
-rw-r--r--ksvg/dom/SVGDocument.cc138
-rw-r--r--ksvg/dom/SVGDocument.h70
-rw-r--r--ksvg/dom/SVGElement.cc124
-rw-r--r--ksvg/dom/SVGElement.h83
-rw-r--r--ksvg/dom/SVGElementInstance.cc117
-rw-r--r--ksvg/dom/SVGElementInstance.h60
-rw-r--r--ksvg/dom/SVGElementInstanceList.cc79
-rw-r--r--ksvg/dom/SVGElementInstanceList.h52
-rw-r--r--ksvg/dom/SVGEllipseElement.cc98
-rw-r--r--ksvg/dom/SVGEllipseElement.h131
-rw-r--r--ksvg/dom/SVGEvent.cc187
-rw-r--r--ksvg/dom/SVGEvent.h95
-rw-r--r--ksvg/dom/SVGException.h51
-rw-r--r--ksvg/dom/SVGExternalResourcesRequired.cc65
-rw-r--r--ksvg/dom/SVGExternalResourcesRequired.h53
-rw-r--r--ksvg/dom/SVGFEBlendElement.cc88
-rw-r--r--ksvg/dom/SVGFEBlendElement.h68
-rw-r--r--ksvg/dom/SVGFEColorMatrixElement.cc89
-rw-r--r--ksvg/dom/SVGFEColorMatrixElement.h68
-rw-r--r--ksvg/dom/SVGFEComponentTransferElement.cc75
-rw-r--r--ksvg/dom/SVGFEComponentTransferElement.h55
-rw-r--r--ksvg/dom/SVGFECompositeElement.cc113
-rw-r--r--ksvg/dom/SVGFECompositeElement.h74
-rw-r--r--ksvg/dom/SVGFEConvolveMatrixElement.cc140
-rw-r--r--ksvg/dom/SVGFEConvolveMatrixElement.h78
-rw-r--r--ksvg/dom/SVGFEDiffuseLightingElement.cc88
-rw-r--r--ksvg/dom/SVGFEDiffuseLightingElement.h58
-rw-r--r--ksvg/dom/SVGFEDisplacementMapElement.cc101
-rw-r--r--ksvg/dom/SVGFEDisplacementMapElement.h69
-rw-r--r--ksvg/dom/SVGFEDistantLightElement.cc80
-rw-r--r--ksvg/dom/SVGFEDistantLightElement.h54
-rw-r--r--ksvg/dom/SVGFEFloodElement.cc76
-rw-r--r--ksvg/dom/SVGFEFloodElement.h57
-rw-r--r--ksvg/dom/SVGFEFuncAElement.cc67
-rw-r--r--ksvg/dom/SVGFEFuncAElement.h50
-rw-r--r--ksvg/dom/SVGFEFuncBElement.cc67
-rw-r--r--ksvg/dom/SVGFEFuncBElement.h50
-rw-r--r--ksvg/dom/SVGFEFuncGElement.cc67
-rw-r--r--ksvg/dom/SVGFEFuncGElement.h50
-rw-r--r--ksvg/dom/SVGFEFuncRElement.cc67
-rw-r--r--ksvg/dom/SVGFEFuncRElement.h50
-rw-r--r--ksvg/dom/SVGFEGaussianBlurElement.cc94
-rw-r--r--ksvg/dom/SVGFEGaussianBlurElement.h60
-rw-r--r--ksvg/dom/SVGFEImageElement.cc72
-rw-r--r--ksvg/dom/SVGFEImageElement.h60
-rw-r--r--ksvg/dom/SVGFEMergeElement.cc68
-rw-r--r--ksvg/dom/SVGFEMergeElement.h52
-rw-r--r--ksvg/dom/SVGFEMergeNodeElement.cc74
-rw-r--r--ksvg/dom/SVGFEMergeNodeElement.h53
-rw-r--r--ksvg/dom/SVGFEMorphologyElement.cc95
-rw-r--r--ksvg/dom/SVGFEMorphologyElement.h67
-rw-r--r--ksvg/dom/SVGFEOffsetElement.cc88
-rw-r--r--ksvg/dom/SVGFEOffsetElement.h58
-rw-r--r--ksvg/dom/SVGFEPointLightElement.cc86
-rw-r--r--ksvg/dom/SVGFEPointLightElement.h55
-rw-r--r--ksvg/dom/SVGFESpecularLightingElement.cc94
-rw-r--r--ksvg/dom/SVGFESpecularLightingElement.h59
-rw-r--r--ksvg/dom/SVGFESpotLightElement.cc116
-rw-r--r--ksvg/dom/SVGFESpotLightElement.h60
-rw-r--r--ksvg/dom/SVGFETileElement.cc75
-rw-r--r--ksvg/dom/SVGFETileElement.h55
-rw-r--r--ksvg/dom/SVGFETurbulenceElement.cc107
-rw-r--r--ksvg/dom/SVGFETurbulenceElement.h71
-rw-r--r--ksvg/dom/SVGFilterElement.cc128
-rw-r--r--ksvg/dom/SVGFilterElement.h74
-rw-r--r--ksvg/dom/SVGFilterPrimitiveStandardAttributes.cc88
-rw-r--r--ksvg/dom/SVGFilterPrimitiveStandardAttributes.h55
-rw-r--r--ksvg/dom/SVGFitToViewBox.cc72
-rw-r--r--ksvg/dom/SVGFitToViewBox.h55
-rw-r--r--ksvg/dom/SVGFontElement.cc69
-rw-r--r--ksvg/dom/SVGFontElement.h54
-rw-r--r--ksvg/dom/SVGFontFaceElement.cc67
-rw-r--r--ksvg/dom/SVGFontFaceElement.h50
-rw-r--r--ksvg/dom/SVGFontFaceFormatElement.cc67
-rw-r--r--ksvg/dom/SVGFontFaceFormatElement.h50
-rw-r--r--ksvg/dom/SVGFontFaceNameElement.cc67
-rw-r--r--ksvg/dom/SVGFontFaceNameElement.h50
-rw-r--r--ksvg/dom/SVGFontFaceSrcElement.cc67
-rw-r--r--ksvg/dom/SVGFontFaceSrcElement.h50
-rw-r--r--ksvg/dom/SVGFontFaceUriElement.cc67
-rw-r--r--ksvg/dom/SVGFontFaceUriElement.h50
-rw-r--r--ksvg/dom/SVGForeignObjectElement.cc97
-rw-r--r--ksvg/dom/SVGForeignObjectElement.h66
-rw-r--r--ksvg/dom/SVGGElement.cc72
-rw-r--r--ksvg/dom/SVGGElement.h83
-rw-r--r--ksvg/dom/SVGGlyphElement.cc68
-rw-r--r--ksvg/dom/SVGGlyphElement.h52
-rw-r--r--ksvg/dom/SVGGlyphRefElement.cc81
-rw-r--r--ksvg/dom/SVGGlyphRefElement.h57
-rw-r--r--ksvg/dom/SVGGradientElement.cc80
-rw-r--r--ksvg/dom/SVGGradientElement.h71
-rw-r--r--ksvg/dom/SVGHKernElement.cc67
-rw-r--r--ksvg/dom/SVGHKernElement.h50
-rw-r--r--ksvg/dom/SVGICCColor.cc85
-rw-r--r--ksvg/dom/SVGICCColor.h56
-rw-r--r--ksvg/dom/SVGImageElement.cc106
-rw-r--r--ksvg/dom/SVGImageElement.h70
-rw-r--r--ksvg/dom/SVGLangSpace.cc82
-rw-r--r--ksvg/dom/SVGLangSpace.h58
-rw-r--r--ksvg/dom/SVGLength.cc135
-rw-r--r--ksvg/dom/SVGLength.h81
-rw-r--r--ksvg/dom/SVGLengthList.cc115
-rw-r--r--ksvg/dom/SVGLengthList.h59
-rw-r--r--ksvg/dom/SVGLineElement.cc98
-rw-r--r--ksvg/dom/SVGLineElement.h126
-rw-r--r--ksvg/dom/SVGLinearGradientElement.cc92
-rw-r--r--ksvg/dom/SVGLinearGradientElement.h141
-rw-r--r--ksvg/dom/SVGLocatable.cc97
-rw-r--r--ksvg/dom/SVGLocatable.h122
-rw-r--r--ksvg/dom/SVGMPathElement.cc69
-rw-r--r--ksvg/dom/SVGMPathElement.h54
-rw-r--r--ksvg/dom/SVGMarkerElement.cc129
-rw-r--r--ksvg/dom/SVGMarkerElement.h87
-rw-r--r--ksvg/dom/SVGMaskElement.cc109
-rw-r--r--ksvg/dom/SVGMaskElement.h69
-rw-r--r--ksvg/dom/SVGMatrix.cc210
-rw-r--r--ksvg/dom/SVGMatrix.h79
-rw-r--r--ksvg/dom/SVGMetadataElement.cc67
-rw-r--r--ksvg/dom/SVGMetadataElement.h50
-rw-r--r--ksvg/dom/SVGMissingGlyphElement.cc68
-rw-r--r--ksvg/dom/SVGMissingGlyphElement.h52
-rw-r--r--ksvg/dom/SVGNumber.cc78
-rw-r--r--ksvg/dom/SVGNumber.h51
-rw-r--r--ksvg/dom/SVGNumberList.cc115
-rw-r--r--ksvg/dom/SVGNumberList.h58
-rw-r--r--ksvg/dom/SVGPaint.cc93
-rw-r--r--ksvg/dom/SVGPaint.h70
-rw-r--r--ksvg/dom/SVGPathElement.cc200
-rw-r--r--ksvg/dom/SVGPathElement.h107
-rw-r--r--ksvg/dom/SVGPathSeg.cc69
-rw-r--r--ksvg/dom/SVGPathSeg.h76
-rw-r--r--ksvg/dom/SVGPathSegArc.cc238
-rw-r--r--ksvg/dom/SVGPathSegArc.h109
-rw-r--r--ksvg/dom/SVGPathSegClosePath.cc46
-rw-r--r--ksvg/dom/SVGPathSegClosePath.h50
-rw-r--r--ksvg/dom/SVGPathSegCurvetoCubic.cc214
-rw-r--r--ksvg/dom/SVGPathSegCurvetoCubic.h103
-rw-r--r--ksvg/dom/SVGPathSegCurvetoCubicSmooth.cc166
-rw-r--r--ksvg/dom/SVGPathSegCurvetoCubicSmooth.h91
-rw-r--r--ksvg/dom/SVGPathSegCurvetoQuadratic.cc166
-rw-r--r--ksvg/dom/SVGPathSegCurvetoQuadratic.h91
-rw-r--r--ksvg/dom/SVGPathSegCurvetoQuadraticSmooth.cc118
-rw-r--r--ksvg/dom/SVGPathSegCurvetoQuadraticSmooth.h79
-rw-r--r--ksvg/dom/SVGPathSegLineto.cc118
-rw-r--r--ksvg/dom/SVGPathSegLineto.h79
-rw-r--r--ksvg/dom/SVGPathSegLinetoHorizontal.cc94
-rw-r--r--ksvg/dom/SVGPathSegLinetoHorizontal.h73
-rw-r--r--ksvg/dom/SVGPathSegLinetoVertical.cc94
-rw-r--r--ksvg/dom/SVGPathSegLinetoVertical.h73
-rw-r--r--ksvg/dom/SVGPathSegList.cc114
-rw-r--r--ksvg/dom/SVGPathSegList.h59
-rw-r--r--ksvg/dom/SVGPathSegMoveto.cc118
-rw-r--r--ksvg/dom/SVGPathSegMoveto.h79
-rw-r--r--ksvg/dom/SVGPatternElement.cc117
-rw-r--r--ksvg/dom/SVGPatternElement.h188
-rw-r--r--ksvg/dom/SVGPoint.cc97
-rw-r--r--ksvg/dom/SVGPoint.h57
-rw-r--r--ksvg/dom/SVGPointList.cc114
-rw-r--r--ksvg/dom/SVGPointList.h57
-rw-r--r--ksvg/dom/SVGPolygonElement.cc84
-rw-r--r--ksvg/dom/SVGPolygonElement.h106
-rw-r--r--ksvg/dom/SVGPolylineElement.cc85
-rw-r--r--ksvg/dom/SVGPolylineElement.h106
-rw-r--r--ksvg/dom/SVGPreserveAspectRatio.cc81
-rw-r--r--ksvg/dom/SVGPreserveAspectRatio.h76
-rw-r--r--ksvg/dom/SVGRadialGradientElement.cc98
-rw-r--r--ksvg/dom/SVGRadialGradientElement.h57
-rw-r--r--ksvg/dom/SVGRect.cc114
-rw-r--r--ksvg/dom/SVGRect.h87
-rw-r--r--ksvg/dom/SVGRectElement.cc109
-rw-r--r--ksvg/dom/SVGRectElement.h173
-rw-r--r--ksvg/dom/SVGRenderingIntent.h41
-rw-r--r--ksvg/dom/SVGSVGElement.cc337
-rw-r--r--ksvg/dom/SVGSVGElement.h581
-rw-r--r--ksvg/dom/SVGScriptElement.cc81
-rw-r--r--ksvg/dom/SVGScriptElement.h58
-rw-r--r--ksvg/dom/SVGSetElement.cc67
-rw-r--r--ksvg/dom/SVGSetElement.h50
-rw-r--r--ksvg/dom/SVGStopElement.cc75
-rw-r--r--ksvg/dom/SVGStopElement.h81
-rw-r--r--ksvg/dom/SVGStringList.cc115
-rw-r--r--ksvg/dom/SVGStringList.h60
-rw-r--r--ksvg/dom/SVGStylable.cc76
-rw-r--r--ksvg/dom/SVGStylable.h56
-rw-r--r--ksvg/dom/SVGStyleElement.cc115
-rw-r--r--ksvg/dom/SVGStyleElement.h63
-rw-r--r--ksvg/dom/SVGSwitchElement.cc72
-rw-r--r--ksvg/dom/SVGSwitchElement.h60
-rw-r--r--ksvg/dom/SVGSymbolElement.cc71
-rw-r--r--ksvg/dom/SVGSymbolElement.h58
-rw-r--r--ksvg/dom/SVGTRefElement.cc68
-rw-r--r--ksvg/dom/SVGTRefElement.h52
-rw-r--r--ksvg/dom/SVGTSpanElement.cc67
-rw-r--r--ksvg/dom/SVGTSpanElement.h70
-rw-r--r--ksvg/dom/SVGTests.cc83
-rw-r--r--ksvg/dom/SVGTests.h59
-rw-r--r--ksvg/dom/SVGTextContentElement.cc120
-rw-r--r--ksvg/dom/SVGTextContentElement.h79
-rw-r--r--ksvg/dom/SVGTextElement.cc68
-rw-r--r--ksvg/dom/SVGTextElement.h115
-rw-r--r--ksvg/dom/SVGTextPathElement.cc89
-rw-r--r--ksvg/dom/SVGTextPathElement.h70
-rw-r--r--ksvg/dom/SVGTextPositioningElement.cc85
-rw-r--r--ksvg/dom/SVGTextPositioningElement.h60
-rw-r--r--ksvg/dom/SVGTitleElement.cc69
-rw-r--r--ksvg/dom/SVGTitleElement.h54
-rw-r--r--ksvg/dom/SVGTransform.cc119
-rw-r--r--ksvg/dom/SVGTransform.h71
-rw-r--r--ksvg/dom/SVGTransformList.cc129
-rw-r--r--ksvg/dom/SVGTransformList.h63
-rw-r--r--ksvg/dom/SVGTransformable.cc67
-rw-r--r--ksvg/dom/SVGTransformable.h55
-rw-r--r--ksvg/dom/SVGURIReference.cc63
-rw-r--r--ksvg/dom/SVGURIReference.h53
-rw-r--r--ksvg/dom/SVGUnitTypes.h41
-rw-r--r--ksvg/dom/SVGUseElement.cc111
-rw-r--r--ksvg/dom/SVGUseElement.h71
-rw-r--r--ksvg/dom/SVGVKernElement.cc67
-rw-r--r--ksvg/dom/SVGVKernElement.h50
-rw-r--r--ksvg/dom/SVGViewElement.cc77
-rw-r--r--ksvg/dom/SVGViewElement.h59
-rw-r--r--ksvg/dom/SVGViewSpec.cc107
-rw-r--r--ksvg/dom/SVGViewSpec.h63
-rw-r--r--ksvg/dom/SVGWindow.cc175
-rw-r--r--ksvg/dom/SVGWindow.h127
-rw-r--r--ksvg/dom/SVGZoomAndPan.cc70
-rw-r--r--ksvg/dom/SVGZoomAndPan.h60
-rw-r--r--ksvg/dom/SVGZoomEvent.cc99
-rw-r--r--ksvg/dom/SVGZoomEvent.h58
-rw-r--r--ksvg/ecma/Makefile.am7
-rw-r--r--ksvg/ecma/ksvg_bridge.h103
-rw-r--r--ksvg/ecma/ksvg_cacheimpl.h65
-rw-r--r--ksvg/ecma/ksvg_ecma.cpp336
-rw-r--r--ksvg/ecma/ksvg_ecma.h114
-rw-r--r--ksvg/ecma/ksvg_ecmaeventlistener.cpp99
-rw-r--r--ksvg/ecma/ksvg_ecmaeventlistener.h54
-rw-r--r--ksvg/ecma/ksvg_helper.cpp68
-rw-r--r--ksvg/ecma/ksvg_lookup.h318
-rw-r--r--ksvg/ecma/ksvg_scriptinterpreter.cpp92
-rw-r--r--ksvg/ecma/ksvg_scriptinterpreter.h71
-rw-r--r--ksvg/ecma/ksvg_window.cpp578
-rw-r--r--ksvg/ecma/ksvg_window.h122
-rw-r--r--ksvg/impl/LRUCache.h169
-rw-r--r--ksvg/impl/Makefile.am116
-rw-r--r--ksvg/impl/SVGAElementImpl.cc117
-rw-r--r--ksvg/impl/SVGAElementImpl.h79
-rw-r--r--ksvg/impl/SVGAltGlyphDefElementImpl.cc33
-rw-r--r--ksvg/impl/SVGAltGlyphDefElementImpl.h49
-rw-r--r--ksvg/impl/SVGAltGlyphElementImpl.cc50
-rw-r--r--ksvg/impl/SVGAltGlyphElementImpl.h55
-rw-r--r--ksvg/impl/SVGAngleImpl.cc277
-rw-r--r--ksvg/impl/SVGAngleImpl.h102
-rw-r--r--ksvg/impl/SVGAnimateColorElementImpl.cc98
-rw-r--r--ksvg/impl/SVGAnimateColorElementImpl.h60
-rw-r--r--ksvg/impl/SVGAnimateElementImpl.cc191
-rw-r--r--ksvg/impl/SVGAnimateElementImpl.h59
-rw-r--r--ksvg/impl/SVGAnimateMotionElementImpl.cc102
-rw-r--r--ksvg/impl/SVGAnimateMotionElementImpl.h56
-rw-r--r--ksvg/impl/SVGAnimateTransformElementImpl.cc257
-rw-r--r--ksvg/impl/SVGAnimateTransformElementImpl.h74
-rw-r--r--ksvg/impl/SVGAnimatedAngleImpl.cc83
-rw-r--r--ksvg/impl/SVGAnimatedAngleImpl.h61
-rw-r--r--ksvg/impl/SVGAnimatedBooleanImpl.cc93
-rw-r--r--ksvg/impl/SVGAnimatedBooleanImpl.h64
-rw-r--r--ksvg/impl/SVGAnimatedEnumerationImpl.cc93
-rw-r--r--ksvg/impl/SVGAnimatedEnumerationImpl.h64
-rw-r--r--ksvg/impl/SVGAnimatedIntegerImpl.cc91
-rw-r--r--ksvg/impl/SVGAnimatedIntegerImpl.h64
-rw-r--r--ksvg/impl/SVGAnimatedLengthImpl.cc96
-rw-r--r--ksvg/impl/SVGAnimatedLengthImpl.h65
-rw-r--r--ksvg/impl/SVGAnimatedLengthListImpl.cc95
-rw-r--r--ksvg/impl/SVGAnimatedLengthListImpl.h61
-rw-r--r--ksvg/impl/SVGAnimatedNumberImpl.cc94
-rw-r--r--ksvg/impl/SVGAnimatedNumberImpl.h63
-rw-r--r--ksvg/impl/SVGAnimatedNumberListImpl.cc82
-rw-r--r--ksvg/impl/SVGAnimatedNumberListImpl.h58
-rw-r--r--ksvg/impl/SVGAnimatedPathDataImpl.cc108
-rw-r--r--ksvg/impl/SVGAnimatedPathDataImpl.h67
-rw-r--r--ksvg/impl/SVGAnimatedPointsImpl.cc139
-rw-r--r--ksvg/impl/SVGAnimatedPointsImpl.h67
-rw-r--r--ksvg/impl/SVGAnimatedPreserveAspectRatioImpl.cc83
-rw-r--r--ksvg/impl/SVGAnimatedPreserveAspectRatioImpl.h61
-rw-r--r--ksvg/impl/SVGAnimatedRectImpl.cc81
-rw-r--r--ksvg/impl/SVGAnimatedRectImpl.h61
-rw-r--r--ksvg/impl/SVGAnimatedStringImpl.cc90
-rw-r--r--ksvg/impl/SVGAnimatedStringImpl.h65
-rw-r--r--ksvg/impl/SVGAnimatedTransformListImpl.cc83
-rw-r--r--ksvg/impl/SVGAnimatedTransformListImpl.h61
-rw-r--r--ksvg/impl/SVGAnimationElementImpl.cc465
-rw-r--r--ksvg/impl/SVGAnimationElementImpl.h149
-rw-r--r--ksvg/impl/SVGBBoxTarget.cc55
-rw-r--r--ksvg/impl/SVGBBoxTarget.h45
-rw-r--r--ksvg/impl/SVGCSSRuleImpl.cc33
-rw-r--r--ksvg/impl/SVGCSSRuleImpl.h42
-rw-r--r--ksvg/impl/SVGCircleElementImpl.cc178
-rw-r--r--ksvg/impl/SVGCircleElementImpl.h84
-rw-r--r--ksvg/impl/SVGClipPathElementImpl.cc104
-rw-r--r--ksvg/impl/SVGClipPathElementImpl.h80
-rw-r--r--ksvg/impl/SVGColorImpl.cc540
-rw-r--r--ksvg/impl/SVGColorImpl.h94
-rw-r--r--ksvg/impl/SVGColorProfileElementImpl.cc271
-rw-r--r--ksvg/impl/SVGColorProfileElementImpl.h100
-rw-r--r--ksvg/impl/SVGColorProfileRuleImpl.cc63
-rw-r--r--ksvg/impl/SVGColorProfileRuleImpl.h58
-rw-r--r--ksvg/impl/SVGComponentTransferFunctionElementImpl.cc105
-rw-r--r--ksvg/impl/SVGComponentTransferFunctionElementImpl.h66
-rw-r--r--ksvg/impl/SVGContainerImpl.cc135
-rw-r--r--ksvg/impl/SVGContainerImpl.h58
-rw-r--r--ksvg/impl/SVGCursorElementImpl.cc104
-rw-r--r--ksvg/impl/SVGCursorElementImpl.h69
-rw-r--r--ksvg/impl/SVGDefinitionSrcElementImpl.cc33
-rw-r--r--ksvg/impl/SVGDefinitionSrcElementImpl.h46
-rw-r--r--ksvg/impl/SVGDefsElementImpl.cc34
-rw-r--r--ksvg/impl/SVGDefsElementImpl.h61
-rw-r--r--ksvg/impl/SVGDescElementImpl.cc39
-rw-r--r--ksvg/impl/SVGDescElementImpl.h55
-rw-r--r--ksvg/impl/SVGDocumentImpl.cc705
-rw-r--r--ksvg/impl/SVGDocumentImpl.h245
-rw-r--r--ksvg/impl/SVGEcma.cc844
-rw-r--r--ksvg/impl/SVGEcma.h250
-rw-r--r--ksvg/impl/SVGElementImpl.cc713
-rw-r--r--ksvg/impl/SVGElementImpl.h229
-rw-r--r--ksvg/impl/SVGElementInstanceImpl.cc108
-rw-r--r--ksvg/impl/SVGElementInstanceImpl.h70
-rw-r--r--ksvg/impl/SVGElementInstanceListImpl.cc44
-rw-r--r--ksvg/impl/SVGElementInstanceListImpl.h49
-rw-r--r--ksvg/impl/SVGEllipseElementImpl.cc200
-rw-r--r--ksvg/impl/SVGEllipseElementImpl.h86
-rw-r--r--ksvg/impl/SVGEventImpl.cc992
-rw-r--r--ksvg/impl/SVGEventImpl.h468
-rw-r--r--ksvg/impl/SVGExternalResourcesRequiredImpl.cc88
-rw-r--r--ksvg/impl/SVGExternalResourcesRequiredImpl.h59
-rw-r--r--ksvg/impl/SVGFEBlendElementImpl.cc64
-rw-r--r--ksvg/impl/SVGFEBlendElementImpl.h59
-rw-r--r--ksvg/impl/SVGFEColorMatrixElementImpl.cc65
-rw-r--r--ksvg/impl/SVGFEColorMatrixElementImpl.h60
-rw-r--r--ksvg/impl/SVGFEComponentTransferElementImpl.cc43
-rw-r--r--ksvg/impl/SVGFEComponentTransferElementImpl.h54
-rw-r--r--ksvg/impl/SVGFECompositeElementImpl.cc105
-rw-r--r--ksvg/impl/SVGFECompositeElementImpl.h68
-rw-r--r--ksvg/impl/SVGFEConvolveMatrixElementImpl.cc149
-rw-r--r--ksvg/impl/SVGFEConvolveMatrixElementImpl.h80
-rw-r--r--ksvg/impl/SVGFEDiffuseLightingElementImpl.cc64
-rw-r--r--ksvg/impl/SVGFEDiffuseLightingElementImpl.h59
-rw-r--r--ksvg/impl/SVGFEDisplacementMapElementImpl.cc85
-rw-r--r--ksvg/impl/SVGFEDisplacementMapElementImpl.h64
-rw-r--r--ksvg/impl/SVGFEDistantLightElementImpl.cc53
-rw-r--r--ksvg/impl/SVGFEDistantLightElementImpl.h54
-rw-r--r--ksvg/impl/SVGFEFloodElementImpl.cc43
-rw-r--r--ksvg/impl/SVGFEFloodElementImpl.h56
-rw-r--r--ksvg/impl/SVGFEFuncAElementImpl.cc33
-rw-r--r--ksvg/impl/SVGFEFuncAElementImpl.h46
-rw-r--r--ksvg/impl/SVGFEFuncBElementImpl.cc33
-rw-r--r--ksvg/impl/SVGFEFuncBElementImpl.h45
-rw-r--r--ksvg/impl/SVGFEFuncGElementImpl.cc33
-rw-r--r--ksvg/impl/SVGFEFuncGElementImpl.h46
-rw-r--r--ksvg/impl/SVGFEFuncRElementImpl.cc33
-rw-r--r--ksvg/impl/SVGFEFuncRElementImpl.h46
-rw-r--r--ksvg/impl/SVGFEGaussianBlurElementImpl.cc68
-rw-r--r--ksvg/impl/SVGFEGaussianBlurElementImpl.h60
-rw-r--r--ksvg/impl/SVGFEImageElementImpl.cc33
-rw-r--r--ksvg/impl/SVGFEImageElementImpl.h56
-rw-r--r--ksvg/impl/SVGFEMergeElementImpl.cc33
-rw-r--r--ksvg/impl/SVGFEMergeElementImpl.h48
-rw-r--r--ksvg/impl/SVGFEMergeNodeElementImpl.cc43
-rw-r--r--ksvg/impl/SVGFEMergeNodeElementImpl.h52
-rw-r--r--ksvg/impl/SVGFEMorphologyElementImpl.cc75
-rw-r--r--ksvg/impl/SVGFEMorphologyElementImpl.h62
-rw-r--r--ksvg/impl/SVGFEOffsetElementImpl.cc64
-rw-r--r--ksvg/impl/SVGFEOffsetElementImpl.h59
-rw-r--r--ksvg/impl/SVGFEPointLightElementImpl.cc63
-rw-r--r--ksvg/impl/SVGFEPointLightElementImpl.h56
-rw-r--r--ksvg/impl/SVGFESpecularLightingElementImpl.cc74
-rw-r--r--ksvg/impl/SVGFESpecularLightingElementImpl.h61
-rw-r--r--ksvg/impl/SVGFESpotLightElementImpl.cc113
-rw-r--r--ksvg/impl/SVGFESpotLightElementImpl.h65
-rw-r--r--ksvg/impl/SVGFETileElementImpl.cc43
-rw-r--r--ksvg/impl/SVGFETileElementImpl.h54
-rw-r--r--ksvg/impl/SVGFETurbulenceElementImpl.cc100
-rw-r--r--ksvg/impl/SVGFETurbulenceElementImpl.h65
-rw-r--r--ksvg/impl/SVGFilterElementImpl.cc119
-rw-r--r--ksvg/impl/SVGFilterElementImpl.h76
-rw-r--r--ksvg/impl/SVGFilterPrimitiveStandardAttributesImpl.cc84
-rw-r--r--ksvg/impl/SVGFilterPrimitiveStandardAttributesImpl.h55
-rw-r--r--ksvg/impl/SVGFitToViewBoxImpl.cc141
-rw-r--r--ksvg/impl/SVGFitToViewBoxImpl.h69
-rw-r--r--ksvg/impl/SVGFontElementImpl.cc33
-rw-r--r--ksvg/impl/SVGFontElementImpl.h49
-rw-r--r--ksvg/impl/SVGFontFaceElementImpl.cc33
-rw-r--r--ksvg/impl/SVGFontFaceElementImpl.h46
-rw-r--r--ksvg/impl/SVGFontFaceFormatElementImpl.cc33
-rw-r--r--ksvg/impl/SVGFontFaceFormatElementImpl.h46
-rw-r--r--ksvg/impl/SVGFontFaceNameElementImpl.cc33
-rw-r--r--ksvg/impl/SVGFontFaceNameElementImpl.h46
-rw-r--r--ksvg/impl/SVGFontFaceSrcElementImpl.cc33
-rw-r--r--ksvg/impl/SVGFontFaceSrcElementImpl.h45
-rw-r--r--ksvg/impl/SVGFontFaceUriElementImpl.cc33
-rw-r--r--ksvg/impl/SVGFontFaceUriElementImpl.h46
-rw-r--r--ksvg/impl/SVGForeignObjectElementImpl.cc121
-rw-r--r--ksvg/impl/SVGForeignObjectElementImpl.h78
-rw-r--r--ksvg/impl/SVGGElementImpl.cc36
-rw-r--r--ksvg/impl/SVGGElementImpl.h59
-rw-r--r--ksvg/impl/SVGGlyphElementImpl.cc98
-rw-r--r--ksvg/impl/SVGGlyphElementImpl.h66
-rw-r--r--ksvg/impl/SVGGlyphRefElementImpl.cc134
-rw-r--r--ksvg/impl/SVGGlyphRefElementImpl.h79
-rw-r--r--ksvg/impl/SVGGradientElementImpl.cc264
-rw-r--r--ksvg/impl/SVGGradientElementImpl.h110
-rw-r--r--ksvg/impl/SVGHKernElementImpl.cc33
-rw-r--r--ksvg/impl/SVGHKernElementImpl.h46
-rw-r--r--ksvg/impl/SVGHelperImpl.cc230
-rw-r--r--ksvg/impl/SVGHelperImpl.h88
-rw-r--r--ksvg/impl/SVGICCColorImpl.cc107
-rw-r--r--ksvg/impl/SVGICCColorImpl.h67
-rw-r--r--ksvg/impl/SVGImageElementImpl.cc522
-rw-r--r--ksvg/impl/SVGImageElementImpl.h140
-rw-r--r--ksvg/impl/SVGLangSpaceImpl.cc130
-rw-r--r--ksvg/impl/SVGLangSpaceImpl.h67
-rw-r--r--ksvg/impl/SVGLengthImpl.cc510
-rw-r--r--ksvg/impl/SVGLengthImpl.h136
-rw-r--r--ksvg/impl/SVGLengthListImpl.cc64
-rw-r--r--ksvg/impl/SVGLengthListImpl.h48
-rw-r--r--ksvg/impl/SVGLineElementImpl.cc213
-rw-r--r--ksvg/impl/SVGLineElementImpl.h86
-rw-r--r--ksvg/impl/SVGLinearGradientElementImpl.cc201
-rw-r--r--ksvg/impl/SVGLinearGradientElementImpl.h74
-rw-r--r--ksvg/impl/SVGList.h174
-rw-r--r--ksvg/impl/SVGLocatableImpl.cc208
-rw-r--r--ksvg/impl/SVGLocatableImpl.h94
-rw-r--r--ksvg/impl/SVGMPathElementImpl.cc33
-rw-r--r--ksvg/impl/SVGMPathElementImpl.h50
-rw-r--r--ksvg/impl/SVGMarkerElementImpl.cc424
-rw-r--r--ksvg/impl/SVGMarkerElementImpl.h121
-rw-r--r--ksvg/impl/SVGMaskElementImpl.cc542
-rw-r--r--ksvg/impl/SVGMaskElementImpl.h158
-rw-r--r--ksvg/impl/SVGMatrixImpl.cc460
-rw-r--r--ksvg/impl/SVGMatrixImpl.h130
-rw-r--r--ksvg/impl/SVGMetadataElementImpl.cc33
-rw-r--r--ksvg/impl/SVGMetadataElementImpl.h46
-rw-r--r--ksvg/impl/SVGMissingGlyphElementImpl.cc33
-rw-r--r--ksvg/impl/SVGMissingGlyphElementImpl.h47
-rw-r--r--ksvg/impl/SVGNumberImpl.cc83
-rw-r--r--ksvg/impl/SVGNumberImpl.h61
-rw-r--r--ksvg/impl/SVGNumberListImpl.cc64
-rw-r--r--ksvg/impl/SVGNumberListImpl.h48
-rw-r--r--ksvg/impl/SVGPaintImpl.cc175
-rw-r--r--ksvg/impl/SVGPaintImpl.h85
-rw-r--r--ksvg/impl/SVGPaintServerImpl.cc55
-rw-r--r--ksvg/impl/SVGPaintServerImpl.h52
-rw-r--r--ksvg/impl/SVGPathElementImpl.cc868
-rw-r--r--ksvg/impl/SVGPathElementImpl.h194
-rw-r--r--ksvg/impl/SVGPathSegArcImpl.cc495
-rw-r--r--ksvg/impl/SVGPathSegArcImpl.h150
-rw-r--r--ksvg/impl/SVGPathSegClosePathImpl.cc46
-rw-r--r--ksvg/impl/SVGPathSegClosePathImpl.h61
-rw-r--r--ksvg/impl/SVGPathSegCurvetoCubicImpl.cc325
-rw-r--r--ksvg/impl/SVGPathSegCurvetoCubicImpl.h139
-rw-r--r--ksvg/impl/SVGPathSegCurvetoCubicSmoothImpl.cc298
-rw-r--r--ksvg/impl/SVGPathSegCurvetoCubicSmoothImpl.h139
-rw-r--r--ksvg/impl/SVGPathSegCurvetoQuadraticImpl.cc260
-rw-r--r--ksvg/impl/SVGPathSegCurvetoQuadraticImpl.h123
-rw-r--r--ksvg/impl/SVGPathSegCurvetoQuadraticSmoothImpl.cc235
-rw-r--r--ksvg/impl/SVGPathSegCurvetoQuadraticSmoothImpl.h123
-rw-r--r--ksvg/impl/SVGPathSegImpl.cc107
-rw-r--r--ksvg/impl/SVGPathSegImpl.h75
-rw-r--r--ksvg/impl/SVGPathSegLinetoHorizontalImpl.cc167
-rw-r--r--ksvg/impl/SVGPathSegLinetoHorizontalImpl.h99
-rw-r--r--ksvg/impl/SVGPathSegLinetoImpl.cc196
-rw-r--r--ksvg/impl/SVGPathSegLinetoImpl.h107
-rw-r--r--ksvg/impl/SVGPathSegLinetoVerticalImpl.cc165
-rw-r--r--ksvg/impl/SVGPathSegLinetoVerticalImpl.h99
-rw-r--r--ksvg/impl/SVGPathSegListImpl.cc64
-rw-r--r--ksvg/impl/SVGPathSegListImpl.h48
-rw-r--r--ksvg/impl/SVGPathSegMovetoImpl.cc196
-rw-r--r--ksvg/impl/SVGPathSegMovetoImpl.h107
-rw-r--r--ksvg/impl/SVGPatternElementImpl.cc509
-rw-r--r--ksvg/impl/SVGPatternElementImpl.h136
-rw-r--r--ksvg/impl/SVGPointImpl.cc108
-rw-r--r--ksvg/impl/SVGPointImpl.h66
-rw-r--r--ksvg/impl/SVGPointListImpl.cc64
-rw-r--r--ksvg/impl/SVGPointListImpl.h48
-rw-r--r--ksvg/impl/SVGPolyElementImpl.cc141
-rw-r--r--ksvg/impl/SVGPolyElementImpl.h70
-rw-r--r--ksvg/impl/SVGPolygonElementImpl.cc88
-rw-r--r--ksvg/impl/SVGPolygonElementImpl.h54
-rw-r--r--ksvg/impl/SVGPolylineElementImpl.cc100
-rw-r--r--ksvg/impl/SVGPolylineElementImpl.h54
-rw-r--r--ksvg/impl/SVGPreserveAspectRatioImpl.cc217
-rw-r--r--ksvg/impl/SVGPreserveAspectRatioImpl.h84
-rw-r--r--ksvg/impl/SVGRadialGradientElementImpl.cc216
-rw-r--r--ksvg/impl/SVGRadialGradientElementImpl.h76
-rw-r--r--ksvg/impl/SVGRectElementImpl.cc244
-rw-r--r--ksvg/impl/SVGRectElementImpl.h90
-rw-r--r--ksvg/impl/SVGRectImpl.cc157
-rw-r--r--ksvg/impl/SVGRectImpl.h80
-rw-r--r--ksvg/impl/SVGSVGElementImpl.cc982
-rw-r--r--ksvg/impl/SVGSVGElementImpl.h198
-rw-r--r--ksvg/impl/SVGScriptElementImpl.cc185
-rw-r--r--ksvg/impl/SVGScriptElementImpl.h90
-rw-r--r--ksvg/impl/SVGSetElementImpl.cc48
-rw-r--r--ksvg/impl/SVGSetElementImpl.h54
-rw-r--r--ksvg/impl/SVGShapeImpl.cc162
-rw-r--r--ksvg/impl/SVGShapeImpl.h73
-rw-r--r--ksvg/impl/SVGStopElementImpl.cc125
-rw-r--r--ksvg/impl/SVGStopElementImpl.h70
-rw-r--r--ksvg/impl/SVGStringListImpl.cc93
-rw-r--r--ksvg/impl/SVGStringListImpl.h82
-rw-r--r--ksvg/impl/SVGStylableImpl.cc1309
-rw-r--r--ksvg/impl/SVGStylableImpl.h327
-rw-r--r--ksvg/impl/SVGStyleElementImpl.cc135
-rw-r--r--ksvg/impl/SVGStyleElementImpl.h72
-rw-r--r--ksvg/impl/SVGSwitchElementImpl.cc58
-rw-r--r--ksvg/impl/SVGSwitchElementImpl.h62
-rw-r--r--ksvg/impl/SVGSymbolElementImpl.cc106
-rw-r--r--ksvg/impl/SVGSymbolElementImpl.h76
-rw-r--r--ksvg/impl/SVGTRefElementImpl.cc76
-rw-r--r--ksvg/impl/SVGTRefElementImpl.h52
-rw-r--r--ksvg/impl/SVGTSpanElementImpl.cc64
-rw-r--r--ksvg/impl/SVGTSpanElementImpl.h55
-rw-r--r--ksvg/impl/SVGTestsImpl.cc178
-rw-r--r--ksvg/impl/SVGTestsImpl.h77
-rw-r--r--ksvg/impl/SVGTextContentElementImpl.cc285
-rw-r--r--ksvg/impl/SVGTextContentElementImpl.h115
-rw-r--r--ksvg/impl/SVGTextElementImpl.cc124
-rw-r--r--ksvg/impl/SVGTextElementImpl.h65
-rw-r--r--ksvg/impl/SVGTextPathElementImpl.cc240
-rw-r--r--ksvg/impl/SVGTextPathElementImpl.h84
-rw-r--r--ksvg/impl/SVGTextPositioningElementImpl.cc198
-rw-r--r--ksvg/impl/SVGTextPositioningElementImpl.h83
-rw-r--r--ksvg/impl/SVGTimeScheduler.cc234
-rw-r--r--ksvg/impl/SVGTimeScheduler.h104
-rw-r--r--ksvg/impl/SVGTitleElementImpl.cc39
-rw-r--r--ksvg/impl/SVGTitleElementImpl.h55
-rw-r--r--ksvg/impl/SVGTransformImpl.cc240
-rw-r--r--ksvg/impl/SVGTransformImpl.h99
-rw-r--r--ksvg/impl/SVGTransformListImpl.cc103
-rw-r--r--ksvg/impl/SVGTransformListImpl.h53
-rw-r--r--ksvg/impl/SVGTransformableImpl.cc169
-rw-r--r--ksvg/impl/SVGTransformableImpl.h77
-rw-r--r--ksvg/impl/SVGURIReferenceImpl.cc135
-rw-r--r--ksvg/impl/SVGURIReferenceImpl.h64
-rw-r--r--ksvg/impl/SVGUnitConverter.h100
-rw-r--r--ksvg/impl/SVGUseElementImpl.cc409
-rw-r--r--ksvg/impl/SVGUseElementImpl.h101
-rw-r--r--ksvg/impl/SVGVKernElementImpl.cc33
-rw-r--r--ksvg/impl/SVGVKernElementImpl.h46
-rw-r--r--ksvg/impl/SVGViewElementImpl.cc94
-rw-r--r--ksvg/impl/SVGViewElementImpl.h70
-rw-r--r--ksvg/impl/SVGViewSpecImpl.cc98
-rw-r--r--ksvg/impl/SVGViewSpecImpl.h69
-rw-r--r--ksvg/impl/SVGWindowImpl.cc187
-rw-r--r--ksvg/impl/SVGWindowImpl.h73
-rw-r--r--ksvg/impl/SVGZoomAndPanImpl.cc112
-rw-r--r--ksvg/impl/SVGZoomAndPanImpl.h76
-rw-r--r--ksvg/impl/SVGZoomEventImpl.cc111
-rw-r--r--ksvg/impl/SVGZoomEventImpl.h77
-rw-r--r--ksvg/impl/TODO5
-rw-r--r--ksvg/impl/generateddata.cpp8899
-rw-r--r--ksvg/impl/libs/Makefile.am1
-rw-r--r--ksvg/impl/libs/art_support/Makefile.am4
-rw-r--r--ksvg/impl/libs/art_support/art_misc.c1841
-rw-r--r--ksvg/impl/libs/art_support/art_misc.h79
-rw-r--r--ksvg/impl/libs/art_support/art_render_misc.c774
-rw-r--r--ksvg/impl/libs/art_support/art_render_misc.h90
-rw-r--r--ksvg/impl/libs/art_support/art_rgba_svp.c659
-rw-r--r--ksvg/impl/libs/art_support/art_rgba_svp.h57
-rw-r--r--ksvg/impl/libs/libtext2path/AUTHORS1
-rw-r--r--ksvg/impl/libs/libtext2path/COPYING339
-rw-r--r--ksvg/impl/libs/libtext2path/ChangeLog2
-rw-r--r--ksvg/impl/libs/libtext2path/INSTALL181
-rw-r--r--ksvg/impl/libs/libtext2path/Makefile.am7
-rw-r--r--ksvg/impl/libs/libtext2path/NEWS1
-rw-r--r--ksvg/impl/libs/libtext2path/README4
-rw-r--r--ksvg/impl/libs/libtext2path/VERSION1
-rw-r--r--ksvg/impl/libs/libtext2path/configure.in.in41
-rw-r--r--ksvg/impl/libs/libtext2path/libtext2path.lsm16
-rw-r--r--ksvg/impl/libs/libtext2path/libtext2path.pc.in11
-rw-r--r--ksvg/impl/libs/libtext2path/libtext2path.spec41
-rw-r--r--ksvg/impl/libs/libtext2path/src/Affine.cpp174
-rw-r--r--ksvg/impl/libs/libtext2path/src/Affine.h67
-rw-r--r--ksvg/impl/libs/libtext2path/src/BezierPath.h56
-rw-r--r--ksvg/impl/libs/libtext2path/src/Cache.h156
-rw-r--r--ksvg/impl/libs/libtext2path/src/Converter.cpp505
-rw-r--r--ksvg/impl/libs/libtext2path/src/Converter.h94
-rw-r--r--ksvg/impl/libs/libtext2path/src/Font.cpp252
-rw-r--r--ksvg/impl/libs/libtext2path/src/Font.h91
-rw-r--r--ksvg/impl/libs/libtext2path/src/Glyph.cpp353
-rw-r--r--ksvg/impl/libs/libtext2path/src/Glyph.h198
-rw-r--r--ksvg/impl/libs/libtext2path/src/GlyphTracer.cpp76
-rw-r--r--ksvg/impl/libs/libtext2path/src/GlyphTracer.h65
-rw-r--r--ksvg/impl/libs/libtext2path/src/Makefile.am10
-rw-r--r--ksvg/impl/libs/libtext2path/src/Point.h65
-rw-r--r--ksvg/impl/libs/libtext2path/src/QtUnicode.cpp164
-rw-r--r--ksvg/impl/libs/libtext2path/src/QtUnicode.h149
-rw-r--r--ksvg/impl/libs/libtext2path/src/Rectangle.cpp102
-rw-r--r--ksvg/impl/libs/libtext2path/src/Rectangle.h55
-rw-r--r--ksvg/impl/libs/libtext2path/src/Tools.h85
-rw-r--r--ksvg/impl/libs/libtext2path/src/myboost/assert.hpp24
-rw-r--r--ksvg/impl/libs/libtext2path/src/myboost/checked_delete.hpp61
-rw-r--r--ksvg/impl/libs/libtext2path/src/myboost/lightweight_mutex.hpp74
-rw-r--r--ksvg/impl/libs/libtext2path/src/myboost/shared_count.hpp367
-rw-r--r--ksvg/impl/libs/libtext2path/src/myboost/shared_ptr.hpp395
-rw-r--r--ksvg/impl/libs/libtext2path/src/myboost/throw_exception.hpp30
-rw-r--r--ksvg/impl/libs/xrgbrender/Makefile.am5
-rw-r--r--ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib-drawable.c1137
-rw-r--r--ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib-private.h30
-rw-r--r--ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib.c46
-rw-r--r--ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib.h78
-rw-r--r--ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlibrgb.c3425
-rw-r--r--ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlibrgb.h145
-rw-r--r--ksvg/impl/svgpathparser.cc564
-rw-r--r--ksvg/impl/svgpathparser.h63
-rw-r--r--ksvg/plugin/Makefile.am29
-rw-r--r--ksvg/plugin/backends/Makefile.am1
-rw-r--r--ksvg/plugin/backends/agg/AggCanvas.cpp130
-rw-r--r--ksvg/plugin/backends/agg/AggCanvas.h77
-rw-r--r--ksvg/plugin/backends/agg/AggCanvasFactory.cpp45
-rw-r--r--ksvg/plugin/backends/agg/AggCanvasFactory.h45
-rw-r--r--ksvg/plugin/backends/agg/AggCanvasItems.cpp1747
-rw-r--r--ksvg/plugin/backends/agg/AggCanvasItems.h500
-rw-r--r--ksvg/plugin/backends/agg/BezierPathAgg.cpp126
-rw-r--r--ksvg/plugin/backends/agg/BezierPathAgg.h83
-rw-r--r--ksvg/plugin/backends/agg/GlyphTracerAgg.cpp113
-rw-r--r--ksvg/plugin/backends/agg/GlyphTracerAgg.h49
-rw-r--r--ksvg/plugin/backends/agg/Makefile.am15
-rw-r--r--ksvg/plugin/backends/agg/ksvgaggcanvas.desktop101
-rw-r--r--ksvg/plugin/backends/libart/BezierPathLibart.cpp160
-rw-r--r--ksvg/plugin/backends/libart/BezierPathLibart.h52
-rw-r--r--ksvg/plugin/backends/libart/GlyphTracerLibart.cpp177
-rw-r--r--ksvg/plugin/backends/libart/GlyphTracerLibart.h50
-rw-r--r--ksvg/plugin/backends/libart/LibartCanvas.cpp425
-rw-r--r--ksvg/plugin/backends/libart/LibartCanvas.h84
-rw-r--r--ksvg/plugin/backends/libart/LibartCanvasFactory.cpp45
-rw-r--r--ksvg/plugin/backends/libart/LibartCanvasFactory.h45
-rw-r--r--ksvg/plugin/backends/libart/LibartCanvasItems.cpp2209
-rw-r--r--ksvg/plugin/backends/libart/LibartCanvasItems.h414
-rw-r--r--ksvg/plugin/backends/libart/Makefile.am11
-rw-r--r--ksvg/plugin/backends/libart/ksvglibartcanvas.desktop101
-rw-r--r--ksvg/plugin/ksvg_factory.cpp100
-rw-r--r--ksvg/plugin/ksvg_factory.h58
-rw-r--r--ksvg/plugin/ksvg_plugin.cpp417
-rw-r--r--ksvg/plugin/ksvg_plugin.h87
-rw-r--r--ksvg/plugin/ksvg_widget.cpp267
-rw-r--r--ksvg/plugin/ksvg_widget.h68
-rw-r--r--ksvg/plugin/ksvgplugin.desktop85
-rw-r--r--ksvg/plugin/ksvgplugin.rc35
-rw-r--r--ksvg/plugin/svgcreator.cpp92
-rw-r--r--ksvg/plugin/svgcreator.h45
-rw-r--r--ksvg/plugin/svgthumbnail.desktop52
-rw-r--r--ksvg/scripts/COPYRIGHTS19
-rwxr-xr-xksvg/scripts/ECMACHECK25
-rwxr-xr-xksvg/scripts/OPENREF9
-rw-r--r--ksvg/scripts/README16
-rw-r--r--ksvg/scripts/add_static.pl42
-rwxr-xr-xksvg/scripts/check_hashtablesize.pl224
-rwxr-xr-xksvg/scripts/gen.sh51
-rwxr-xr-xksvg/scripts/generate.pl69
-rwxr-xr-xksvg/scripts/genimpl.sh49
-rwxr-xr-xksvg/scripts/getjs.php390
-rw-r--r--ksvg/scripts/idl/svg.idl1756
-rw-r--r--ksvg/scripts/makecc211
-rw-r--r--ksvg/scripts/makeheader164
-rw-r--r--ksvg/scripts/makeimpl440
-rw-r--r--ksvg/test/Makefile.am1
-rw-r--r--ksvg/test/Units.svg43
-rw-r--r--ksvg/test/W3C_TESTSUITE_1.1227
-rw-r--r--ksvg/test/ZVON-TEST-PASSED168
-rw-r--r--ksvg/test/amflag.svg54
-rw-r--r--ksvg/test/animskew.svg44
-rw-r--r--ksvg/test/arabic.svg10
-rw-r--r--ksvg/test/butterfly.svg11
-rw-r--r--ksvg/test/chem1.svg189
-rw-r--r--ksvg/test/colortest.svg18
-rw-r--r--ksvg/test/dashes.svg32
-rw-r--r--ksvg/test/ecma/bbox/bbox-circle.svg13
-rw-r--r--ksvg/test/ecma/bbox/bbox-ellipse.svg14
-rw-r--r--ksvg/test/ecma/bbox/bbox-line.svg35
-rw-r--r--ksvg/test/ecma/bbox/bbox-path.svg15
-rw-r--r--ksvg/test/ecma/bbox/bbox-path2.svg14
-rw-r--r--ksvg/test/ecma/bbox/bbox-polygon.svg13
-rw-r--r--ksvg/test/ecma/bbox/bbox-polyline.svg13
-rw-r--r--ksvg/test/ecma/bbox/bbox-rect.svg15
-rw-r--r--ksvg/test/ecma/bbox/bbox.js103
-rw-r--r--ksvg/test/ecma/broken.svg30
-rw-r--r--ksvg/test/ecma/circle.svg38
-rw-r--r--ksvg/test/ecma/clock.svg66
-rw-r--r--ksvg/test/ecma/dom01.svg40
-rw-r--r--ksvg/test/external/Makefile.am13
-rw-r--r--ksvg/test/external/SVGTestWidget.cc206
-rw-r--r--ksvg/test/external/SVGTestWidget.h37
-rw-r--r--ksvg/test/external/printnodetest.cpp63
-rw-r--r--ksvg/test/external/printnodetest.h32
-rw-r--r--ksvg/test/external/svgdisplay.cc32
-rw-r--r--ksvg/test/fonttest.svg126
-rw-r--r--ksvg/test/keytest.svg25
-rw-r--r--ksvg/test/lion.svg160
-rw-r--r--ksvg/test/opacity.svg41
-rw-r--r--ksvg/test/physics-motor.svg43
-rw-r--r--ksvg/test/poly.svg12
-rw-r--r--ksvg/test/shapes-rect-trans.svg92
-rw-r--r--ksvg/test/tiger.svg722
-rw-r--r--ksvg/test/tiger2.svg725
-rw-r--r--ksvg/test/tigert.svg388
-rw-r--r--ksvg/test/tux.svg298
-rw-r--r--ksvg/test/tux2.svg287
-rw-r--r--ksvg/test/xlink.svg13
-rw-r--r--kuickshow/AUTHORS1
-rw-r--r--kuickshow/BUGS3
-rw-r--r--kuickshow/COPYING339
-rw-r--r--kuickshow/ChangeLog921
-rw-r--r--kuickshow/Makefile.am8
-rw-r--r--kuickshow/README8
-rw-r--r--kuickshow/TODO24
-rw-r--r--kuickshow/configure.in.bot9
-rw-r--r--kuickshow/configure.in.in69
-rw-r--r--kuickshow/kuickshow.lsm18
-rw-r--r--kuickshow/kuickshow.spec69
-rw-r--r--kuickshow/misc/Makefile.am2
-rw-r--r--kuickshow/misc/im_palette.pal64
-rw-r--r--kuickshow/pics/Makefile.am7
-rw-r--r--kuickshow/pics/about.pngbin0 -> 257 bytes
-rw-r--r--kuickshow/pics/arrows.pngbin0 -> 264 bytes
-rw-r--r--kuickshow/pics/calibrate.pngbin0 -> 9161 bytes
-rw-r--r--kuickshow/pics/handcursor.pngbin0 -> 359 bytes
-rw-r--r--kuickshow/pics/imageviewer-medium.pngbin0 -> 1696 bytes
-rw-r--r--kuickshow/pics/imageviewer-small.pngbin0 -> 618 bytes
-rw-r--r--kuickshow/pics/ksslide.pngbin0 -> 246 bytes
-rw-r--r--kuickshow/pics/kuickshow-day.jpgbin0 -> 48857 bytes
-rw-r--r--kuickshow/pics/kuickshow-night.jpgbin0 -> 36800 bytes
-rw-r--r--kuickshow/pics/logo.pngbin0 -> 2904 bytes
-rw-r--r--kuickshow/src/Makefile.am31
-rw-r--r--kuickshow/src/aboutwidget.cpp95
-rw-r--r--kuickshow/src/aboutwidget.h43
-rw-r--r--kuickshow/src/defaultswidget.cpp282
-rw-r--r--kuickshow/src/defaultswidget.h73
-rw-r--r--kuickshow/src/filecache.cpp83
-rw-r--r--kuickshow/src/filecache.h47
-rw-r--r--kuickshow/src/filefinder.cpp99
-rw-r--r--kuickshow/src/filefinder.h54
-rw-r--r--kuickshow/src/filewidget.cpp464
-rw-r--r--kuickshow/src/filewidget.h98
-rw-r--r--kuickshow/src/generalwidget.cpp163
-rw-r--r--kuickshow/src/generalwidget.h62
-rw-r--r--kuickshow/src/hi16-app-kuickshow.pngbin0 -> 396 bytes
-rw-r--r--kuickshow/src/hi22-app-kuickshow.pngbin0 -> 1423 bytes
-rw-r--r--kuickshow/src/hi32-app-kuickshow.pngbin0 -> 954 bytes
-rw-r--r--kuickshow/src/imagewindow.cpp1251
-rw-r--r--kuickshow/src/imagewindow.h176
-rw-r--r--kuickshow/src/imdata.cpp92
-rw-r--r--kuickshow/src/imdata.h57
-rw-r--r--kuickshow/src/imlibwidget.cpp715
-rw-r--r--kuickshow/src/imlibwidget.h187
-rw-r--r--kuickshow/src/kuick.cpp4
-rw-r--r--kuickshow/src/kuick.h70
-rw-r--r--kuickshow/src/kuickconfigdlg.cpp99
-rw-r--r--kuickshow/src/kuickconfigdlg.h58
-rw-r--r--kuickshow/src/kuickdata.cpp177
-rw-r--r--kuickshow/src/kuickdata.h86
-rw-r--r--kuickshow/src/kuickfile.cpp194
-rw-r--r--kuickshow/src/kuickfile.h99
-rw-r--r--kuickshow/src/kuickglobals.h33
-rw-r--r--kuickshow/src/kuickimage.cpp527
-rw-r--r--kuickshow/src/kuickimage.h92
-rw-r--r--kuickshow/src/kuickshow.cpp1443
-rw-r--r--kuickshow/src/kuickshow.desktop93
-rw-r--r--kuickshow/src/kuickshow.h178
-rw-r--r--kuickshow/src/kurlwidget.cpp42
-rw-r--r--kuickshow/src/kurlwidget.h36
-rw-r--r--kuickshow/src/main.cpp66
-rw-r--r--kuickshow/src/mainwidget.cpp43
-rw-r--r--kuickshow/src/mainwidget.h47
-rw-r--r--kuickshow/src/printing.cpp338
-rw-r--r--kuickshow/src/printing.h85
-rw-r--r--kuickshow/src/slideshowwidget.cpp80
-rw-r--r--kuickshow/src/slideshowwidget.h44
-rw-r--r--kuickshow/src/version.h3
-rw-r--r--kview/AUTHORS4
-rw-r--r--kview/ChangeLog98
-rw-r--r--kview/Makefile.am25
-rw-r--r--kview/TODO73
-rw-r--r--kview/config/Makefile.am21
-rw-r--r--kview/config/kview.setdlg219
-rw-r--r--kview/config/kviewconfmodules.cpp90
-rw-r--r--kview/config/kviewconfmodules.h47
-rw-r--r--kview/config/kviewgeneralconfig.desktop131
-rw-r--r--kview/config/plugins/Makefile.am17
-rw-r--r--kview/config/plugins/kviewpluginsconfig.cpp46
-rw-r--r--kview/config/plugins/kviewpluginsconfig.desktop118
-rw-r--r--kview/config/plugins/kviewpluginsconfig.h38
-rw-r--r--kview/hi16-app-kview.pngbin0 -> 943 bytes
-rw-r--r--kview/hi22-app-kview.pngbin0 -> 1506 bytes
-rw-r--r--kview/hi32-app-kview.pngbin0 -> 2592 bytes
-rw-r--r--kview/hi48-app-kview.pngbin0 -> 4918 bytes
-rw-r--r--kview/kimageviewer/Makefile.am18
-rw-r--r--kview/kimageviewer/canvas.cpp35
-rw-r--r--kview/kimageviewer/canvas.h348
-rw-r--r--kview/kimageviewer/kimageviewer.desktop63
-rw-r--r--kview/kimageviewer/kimageviewercanvas.desktop60
-rw-r--r--kview/kimageviewer/viewer.cpp36
-rw-r--r--kview/kimageviewer/viewer.h99
-rw-r--r--kview/kview.cpp698
-rw-r--r--kview/kview.desktop95
-rw-r--r--kview/kview.h124
-rw-r--r--kview/kviewcanvas/ChangeLog18
-rw-r--r--kview/kviewcanvas/Makefile.am18
-rw-r--r--kview/kviewcanvas/config/Makefile.am16
-rw-r--r--kview/kviewcanvas/config/confmodules.cpp145
-rw-r--r--kview/kviewcanvas/config/confmodules.h51
-rw-r--r--kview/kviewcanvas/config/defaults.h46
-rw-r--r--kview/kviewcanvas/config/generalconfigwidget.ui300
-rw-r--r--kview/kviewcanvas/config/kviewcanvasconfig.desktop118
-rw-r--r--kview/kviewcanvas/kimagecanvas.cpp953
-rw-r--r--kview/kviewcanvas/kimagecanvas.h366
-rw-r--r--kview/kviewcanvas/kimageholder.cpp371
-rw-r--r--kview/kviewcanvas/kimageholder.h105
-rw-r--r--kview/kviewcanvas/kviewcanvas.desktop63
-rw-r--r--kview/kviewcanvas/test/Makefile.am9
-rw-r--r--kview/kviewcanvas/test/main.cpp51
-rw-r--r--kview/kviewcanvas/test/test.cpp46
-rw-r--r--kview/kviewcanvas/test/test.h25
-rw-r--r--kview/kviewui.rc50
-rw-r--r--kview/kviewviewer/ChangeLog68
-rw-r--r--kview/kviewviewer/Makefile.am21
-rw-r--r--kview/kviewviewer/config/Makefile.am17
-rw-r--r--kview/kviewviewer/config/kviewviewerpluginsconfig.cpp48
-rw-r--r--kview/kviewviewer/config/kviewviewerpluginsconfig.desktop118
-rw-r--r--kview/kviewviewer/config/kviewviewerpluginsconfig.h38
-rw-r--r--kview/kviewviewer/imagesettings.cpp73
-rw-r--r--kview/kviewviewer/imagesettings.h45
-rw-r--r--kview/kviewviewer/kviewkonqextension.cpp105
-rw-r--r--kview/kviewviewer/kviewkonqextension.h52
-rw-r--r--kview/kviewviewer/kviewpopup.rc7
-rw-r--r--kview/kviewviewer/kviewviewer.cpp883
-rw-r--r--kview/kviewviewer/kviewviewer.desktop118
-rw-r--r--kview/kviewviewer/kviewviewer.h145
-rw-r--r--kview/kviewviewer/kviewviewer.rc36
-rw-r--r--kview/kviewviewer/kviewviewer_ro.rc34
-rw-r--r--kview/kviewviewer/kviewvieweriface.h30
-rw-r--r--kview/kviewviewer/printimagesettings.ui190
-rw-r--r--kview/kviewviewer/test/Makefile.am9
-rw-r--r--kview/kviewviewer/test/main.cpp51
-rw-r--r--kview/kviewviewer/test/test.cpp43
-rw-r--r--kview/kviewviewer/test/test.h25
-rw-r--r--kview/main.cpp70
-rw-r--r--kview/modules/Makefile.am1
-rw-r--r--kview/modules/NAMING4
-rw-r--r--kview/modules/README52
-rw-r--r--kview/modules/browser/Makefile.am15
-rw-r--r--kview/modules/browser/kmyfileitemlist.cpp41
-rw-r--r--kview/modules/browser/kmyfileitemlist.h39
-rw-r--r--kview/modules/browser/kviewbrowser.cpp179
-rw-r--r--kview/modules/browser/kviewbrowser.desktop130
-rw-r--r--kview/modules/browser/kviewbrowser.h62
-rw-r--r--kview/modules/browser/kviewbrowser.rc18
-rw-r--r--kview/modules/effects/Makefile.am15
-rw-r--r--kview/modules/effects/kvieweffects.cpp244
-rw-r--r--kview/modules/effects/kvieweffects.desktop119
-rw-r--r--kview/modules/effects/kvieweffects.h46
-rw-r--r--kview/modules/effects/kvieweffects.rc10
-rw-r--r--kview/modules/presenter/DESIGN42
-rw-r--r--kview/modules/presenter/Makefile.am17
-rw-r--r--kview/modules/presenter/config/Makefile.am17
-rw-r--r--kview/modules/presenter/config/kviewpresenterconfig.cpp72
-rw-r--r--kview/modules/presenter/config/kviewpresenterconfig.desktop120
-rw-r--r--kview/modules/presenter/config/kviewpresenterconfig.h46
-rw-r--r--kview/modules/presenter/imagelistdialog.ui289
-rw-r--r--kview/modules/presenter/imagelistdialog.ui.h23
-rw-r--r--kview/modules/presenter/imagelistitem.cpp82
-rw-r--r--kview/modules/presenter/imagelistitem.h49
-rw-r--r--kview/modules/presenter/kviewpresenter.cpp492
-rw-r--r--kview/modules/presenter/kviewpresenter.desktop118
-rw-r--r--kview/modules/presenter/kviewpresenter.h103
-rw-r--r--kview/modules/presenter/kviewpresenter.rc20
-rw-r--r--kview/modules/presenter/kviewpresenterconfmodule.cpp60
-rw-r--r--kview/modules/presenter/kviewpresenterconfmodule.h49
-rw-r--r--kview/modules/scale/Makefile.am15
-rw-r--r--kview/modules/scale/kfloatspinbox.cpp116
-rw-r--r--kview/modules/scale/kfloatspinbox.h64
-rw-r--r--kview/modules/scale/kview_scale.cpp180
-rw-r--r--kview/modules/scale/kview_scale.desktop127
-rw-r--r--kview/modules/scale/kview_scale.h48
-rw-r--r--kview/modules/scale/kview_scale.rc14
-rw-r--r--kview/modules/scale/scaledlg.cpp311
-rw-r--r--kview/modules/scale/scaledlg.h78
-rw-r--r--kview/modules/scanner/Makefile.am15
-rw-r--r--kview/modules/scanner/kviewscanner.cpp96
-rw-r--r--kview/modules/scanner/kviewscanner.desktop127
-rw-r--r--kview/modules/scanner/kviewscanner.h50
-rw-r--r--kview/modules/scanner/kviewscanner.rc12
-rw-r--r--kview/modules/template/Makefile.am15
-rw-r--r--kview/modules/template/kviewtemplate.cpp43
-rw-r--r--kview/modules/template/kviewtemplate.desktop129
-rw-r--r--kview/modules/template/kviewtemplate.h27
-rw-r--r--kview/modules/template/kviewtemplate.rc11
-rw-r--r--kview/photobook/Makefile.am19
-rw-r--r--kview/photobook/cr16-app-photobook.pngbin0 -> 720 bytes
-rw-r--r--kview/photobook/cr22-app-photobook.pngbin0 -> 922 bytes
-rw-r--r--kview/photobook/photobook.cpp292
-rw-r--r--kview/photobook/photobook.desktop131
-rw-r--r--kview/photobook/photobook.h140
-rw-r--r--kview/photobook/photobookui.rc14
-rw-r--r--kview/version.h3
-rw-r--r--kviewshell/DESIGN7
-rw-r--r--kviewshell/Mainpage.dox92
-rw-r--r--kviewshell/Makefile.am67
-rw-r--r--kviewshell/TODO94
-rw-r--r--kviewshell/anchor.h61
-rw-r--r--kviewshell/bookmark.h107
-rw-r--r--kviewshell/documentPageCache.cpp337
-rw-r--r--kviewshell/documentPageCache.h143
-rw-r--r--kviewshell/documentRenderer.cpp133
-rw-r--r--kviewshell/documentRenderer.h478
-rw-r--r--kviewshell/documentWidget.cpp764
-rw-r--r--kviewshell/documentWidget.h193
-rw-r--r--kviewshell/emptyRenderer.cpp29
-rw-r--r--kviewshell/emptyRenderer.h41
-rw-r--r--kviewshell/empty_multipage.cpp48
-rw-r--r--kviewshell/empty_multipage.h51
-rw-r--r--kviewshell/emptymultipage.desktop29
-rw-r--r--kviewshell/history.cpp91
-rw-r--r--kviewshell/history.h58
-rw-r--r--kviewshell/hyperlink.h78
-rw-r--r--kviewshell/kmultipage.cpp1976
-rw-r--r--kviewshell/kmultipage.desktop41
-rw-r--r--kviewshell/kmultipage.h650
-rw-r--r--kviewshell/kmultipageInterface.h18
-rw-r--r--kviewshell/kprintDialogPage_pageoptions.cpp166
-rw-r--r--kviewshell/kprintDialogPage_pageoptions.h43
-rw-r--r--kviewshell/kviewerpart.rc91
-rw-r--r--kviewshell/kviewpart.cpp1632
-rw-r--r--kviewshell/kviewpart.h252
-rw-r--r--kviewshell/kviewpart_iface.cpp4
-rw-r--r--kviewshell/kviewpart_iface.h35
-rw-r--r--kviewshell/kviewshell.cpp384
-rw-r--r--kviewshell/kviewshell.h89
-rw-r--r--kviewshell/kviewshell.kcfg115
-rw-r--r--kviewshell/kviewshell.rc37
-rw-r--r--kviewshell/kvsprefs.kcfgc5
-rw-r--r--kviewshell/length.h173
-rw-r--r--kviewshell/main.cpp184
-rw-r--r--kviewshell/marklist.cpp616
-rw-r--r--kviewshell/marklist.h186
-rw-r--r--kviewshell/optionDialogAccessibilityWidget.ui528
-rw-r--r--kviewshell/optionDialogGUIWidget_base.ui148
-rw-r--r--kviewshell/pageNumber.h65
-rw-r--r--kviewshell/pageSize.cpp343
-rw-r--r--kviewshell/pageSize.h280
-rw-r--r--kviewshell/pageSizeDialog.cpp63
-rw-r--r--kviewshell/pageSizeDialog.h52
-rw-r--r--kviewshell/pageSizeWidget.cpp148
-rw-r--r--kviewshell/pageSizeWidget.h52
-rw-r--r--kviewshell/pageSizeWidget_base.ui260
-rw-r--r--kviewshell/pageView.cpp593
-rw-r--r--kviewshell/pageView.h175
-rw-r--r--kviewshell/pics/Makefile.am3
-rw-r--r--kviewshell/pics/cr16-app-kviewshell.pngbin0 -> 945 bytes
-rw-r--r--kviewshell/pics/cr32-app-kviewshell.pngbin0 -> 2224 bytes
-rw-r--r--kviewshell/pics/cr48-app-kviewshell.pngbin0 -> 3949 bytes
-rw-r--r--kviewshell/pics/icons/Makefile.am3
-rw-r--r--kviewshell/pics/icons/hi16-action-movetool.pngbin0 -> 433 bytes
-rw-r--r--kviewshell/pics/icons/hi16-action-selectiontool.pngbin0 -> 483 bytes
-rw-r--r--kviewshell/pics/icons/hi22-action-movetool.pngbin0 -> 826 bytes
-rw-r--r--kviewshell/pics/icons/hi22-action-selectiontool.pngbin0 -> 404 bytes
-rw-r--r--kviewshell/pics/icons/hi32-action-movetool.pngbin0 -> 1554 bytes
-rw-r--r--kviewshell/pics/icons/hi48-action-movetool.pngbin0 -> 2874 bytes
-rw-r--r--kviewshell/plugins/Makefile.am1
-rw-r--r--kviewshell/plugins/djvu/Makefile.am33
-rw-r--r--kviewshell/plugins/djvu/djvumultipage.cpp357
-rw-r--r--kviewshell/plugins/djvu/djvumultipage.desktop57
-rw-r--r--kviewshell/plugins/djvu/djvumultipage.h149
-rw-r--r--kviewshell/plugins/djvu/djvumultipage.kcfg18
-rw-r--r--kviewshell/plugins/djvu/djvumultipage.rc15
-rw-r--r--kviewshell/plugins/djvu/djvurenderer.cpp719
-rw-r--r--kviewshell/plugins/djvu/djvurenderer.h146
-rw-r--r--kviewshell/plugins/djvu/kprintDialogPage_DJVUconversionoptions.cpp118
-rw-r--r--kviewshell/plugins/djvu/kprintDialogPage_DJVUconversionoptions.h50
-rw-r--r--kviewshell/plugins/djvu/kprintDialogPage_DJVUconversionoptions_basewidget.ui145
-rw-r--r--kviewshell/plugins/djvu/kprintDialogPage_DJVUpageoptions.cpp119
-rw-r--r--kviewshell/plugins/djvu/kprintDialogPage_DJVUpageoptions.h42
-rw-r--r--kviewshell/plugins/djvu/libdjvu/Arrays.cpp305
-rw-r--r--kviewshell/plugins/djvu/libdjvu/Arrays.h997
-rw-r--r--kviewshell/plugins/djvu/libdjvu/BSByteStream.cpp465
-rw-r--r--kviewshell/plugins/djvu/libdjvu/BSByteStream.h275
-rw-r--r--kviewshell/plugins/djvu/libdjvu/BSEncodeByteStream.cpp1010
-rw-r--r--kviewshell/plugins/djvu/libdjvu/ByteStream.cpp1445
-rw-r--r--kviewshell/plugins/djvu/libdjvu/ByteStream.h416
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DataPool.cpp1837
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DataPool.h627
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVmDir.cpp839
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVmDir.h451
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVmDir0.cpp169
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVmDir0.h217
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVmDoc.cpp663
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVmDoc.h274
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVmNav.cpp338
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVmNav.h146
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuAnno.cpp1514
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuAnno.h295
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuDocEditor.cpp2193
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuDocEditor.h460
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuDocument.cpp1845
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuDocument.h1071
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuDumpHelper.cpp353
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuDumpHelper.h126
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuErrorList.cpp174
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuErrorList.h194
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuFile.cpp2831
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuFile.h848
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuFileCache.cpp272
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuFileCache.h292
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuGlobal.cpp255
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuGlobal.h398
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuGlobalMemory.cpp306
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuImage.cpp1486
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuImage.h449
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuInfo.cpp205
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuInfo.h193
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuMessage.cpp647
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuMessage.h135
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuMessageLite.cpp478
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuMessageLite.h227
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuNavDir.cpp237
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuNavDir.h192
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuPalette.cpp590
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuPalette.h339
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuPort.cpp710
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuPort.h518
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuText.cpp971
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuText.h281
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuToPS.cpp2582
-rw-r--r--kviewshell/plugins/djvu/libdjvu/DjVuToPS.h425
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GBitmap.cpp1658
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GBitmap.h673
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GContainer.cpp802
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GContainer.h1366
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GException.cpp284
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GException.h356
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GIFFManager.cpp663
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GIFFManager.h394
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GMapAreas.cpp1066
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GMapAreas.h565
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GOS.cpp370
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GOS.h161
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GPixmap.cpp1676
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GPixmap.h531
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GRect.cpp458
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GRect.h407
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GScaler.cpp706
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GScaler.h321
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GSmartPointer.cpp256
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GSmartPointer.h489
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GString.cpp2811
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GString.h1676
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GThreads.cpp1887
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GThreads.h639
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GURL.cpp1965
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GURL.h446
-rw-r--r--kviewshell/plugins/djvu/libdjvu/GUnicode.cpp790
-rw-r--r--kviewshell/plugins/djvu/libdjvu/IFFByteStream.cpp558
-rw-r--r--kviewshell/plugins/djvu/libdjvu/IFFByteStream.h312
-rw-r--r--kviewshell/plugins/djvu/libdjvu/IW44EncodeCodec.cpp1797
-rw-r--r--kviewshell/plugins/djvu/libdjvu/IW44Image.cpp1935
-rw-r--r--kviewshell/plugins/djvu/libdjvu/IW44Image.h761
-rw-r--r--kviewshell/plugins/djvu/libdjvu/JB2EncodeCodec.cpp564
-rw-r--r--kviewshell/plugins/djvu/libdjvu/JB2Image.cpp1427
-rw-r--r--kviewshell/plugins/djvu/libdjvu/JB2Image.h805
-rw-r--r--kviewshell/plugins/djvu/libdjvu/JPEGDecoder.cpp413
-rw-r--r--kviewshell/plugins/djvu/libdjvu/JPEGDecoder.h133
-rw-r--r--kviewshell/plugins/djvu/libdjvu/MMRDecoder.cpp961
-rw-r--r--kviewshell/plugins/djvu/libdjvu/MMRDecoder.h238
-rw-r--r--kviewshell/plugins/djvu/libdjvu/MMX.cpp209
-rw-r--r--kviewshell/plugins/djvu/libdjvu/MMX.h194
-rw-r--r--kviewshell/plugins/djvu/libdjvu/Makefile.am18
-rw-r--r--kviewshell/plugins/djvu/libdjvu/README.djvulibre85
-rw-r--r--kviewshell/plugins/djvu/libdjvu/Template.h258
-rw-r--r--kviewshell/plugins/djvu/libdjvu/UnicodeByteStream.cpp368
-rw-r--r--kviewshell/plugins/djvu/libdjvu/UnicodeByteStream.h199
-rw-r--r--kviewshell/plugins/djvu/libdjvu/XMLParser.cpp1128
-rw-r--r--kviewshell/plugins/djvu/libdjvu/XMLParser.h123
-rw-r--r--kviewshell/plugins/djvu/libdjvu/XMLTags.cpp417
-rw-r--r--kviewshell/plugins/djvu/libdjvu/XMLTags.h242
-rw-r--r--kviewshell/plugins/djvu/libdjvu/ZPCodec.cpp1292
-rw-r--r--kviewshell/plugins/djvu/libdjvu/ZPCodec.h747
-rw-r--r--kviewshell/plugins/djvu/libdjvu/configure.in.in674
-rw-r--r--kviewshell/plugins/djvu/libdjvu/debug.cpp299
-rw-r--r--kviewshell/plugins/djvu/libdjvu/debug.h304
-rw-r--r--kviewshell/plugins/djvu/pageRangeWidget.cpp68
-rw-r--r--kviewshell/plugins/djvu/pageRangeWidget.h45
-rw-r--r--kviewshell/plugins/djvu/pageRangeWidget_base.ui75
-rw-r--r--kviewshell/plugins/djvu/prefs.kcfgc5
-rw-r--r--kviewshell/renderedDocumentPage.cpp375
-rw-r--r--kviewshell/renderedDocumentPage.h241
-rw-r--r--kviewshell/renderedDocumentPagePixmap.cpp122
-rw-r--r--kviewshell/renderedDocumentPagePixmap.h59
-rw-r--r--kviewshell/renderedDocumentPagePrinter.cpp53
-rw-r--r--kviewshell/renderedDocumentPagePrinter.h46
-rw-r--r--kviewshell/searchWidget.cpp141
-rw-r--r--kviewshell/searchWidget.h73
-rw-r--r--kviewshell/selection.cpp66
-rw-r--r--kviewshell/selection.h86
-rw-r--r--kviewshell/simplePageSize.cpp49
-rw-r--r--kviewshell/simplePageSize.h164
-rw-r--r--kviewshell/sizePreview.cpp134
-rw-r--r--kviewshell/sizePreview.h47
-rw-r--r--kviewshell/tableOfContents.cpp119
-rw-r--r--kviewshell/tableOfContents.h69
-rw-r--r--kviewshell/textBox.h65
-rw-r--r--kviewshell/units.cpp83
-rw-r--r--kviewshell/units.h34
-rw-r--r--kviewshell/zoom.cpp156
-rw-r--r--kviewshell/zoom.h55
-rw-r--r--kviewshell/zoomlimits.h19
-rw-r--r--libkscan/AUTHORS2
-rw-r--r--libkscan/COPYING.LIB486
-rw-r--r--libkscan/INSTALL167
-rw-r--r--libkscan/Makefile.am32
-rw-r--r--libkscan/README12
-rw-r--r--libkscan/TODO59
-rw-r--r--libkscan/configure.in.bot9
-rw-r--r--libkscan/configure.in.in22
-rw-r--r--libkscan/devselector.cpp183
-rw-r--r--libkscan/devselector.h104
-rw-r--r--libkscan/dispgamma.cpp85
-rw-r--r--libkscan/dispgamma.h62
-rw-r--r--libkscan/gammadialog.cpp114
-rw-r--r--libkscan/gammadialog.h75
-rw-r--r--libkscan/img_canvas.cpp1115
-rw-r--r--libkscan/img_canvas.h221
-rw-r--r--libkscan/imgscaledialog.cpp178
-rw-r--r--libkscan/imgscaledialog.h62
-rw-r--r--libkscan/imgscaninfo.cpp75
-rw-r--r--libkscan/imgscaninfo.h52
-rw-r--r--libkscan/kgammatable.cpp93
-rw-r--r--libkscan/kgammatable.h71
-rw-r--r--libkscan/kscandevice.cpp1541
-rw-r--r--libkscan/kscandevice.h459
-rw-r--r--libkscan/kscandoc.h116
-rw-r--r--libkscan/kscanoption.cpp1221
-rw-r--r--libkscan/kscanoption.h260
-rw-r--r--libkscan/kscanoptset.cpp221
-rw-r--r--libkscan/kscanoptset.h113
-rw-r--r--libkscan/kscanslider.cpp319
-rw-r--r--libkscan/kscanslider.h244
-rw-r--r--libkscan/massscandialog.cpp123
-rw-r--r--libkscan/massscandialog.h67
-rw-r--r--libkscan/pics/Makefile.am1
-rw-r--r--libkscan/pics/cr16-action-palette_color.pngbin0 -> 227 bytes
-rw-r--r--libkscan/pics/cr16-action-palette_gray.pngbin0 -> 176 bytes
-rw-r--r--libkscan/pics/cr16-action-palette_halftone.pngbin0 -> 131 bytes
-rw-r--r--libkscan/pics/cr16-action-palette_lineart.pngbin0 -> 131 bytes
-rw-r--r--libkscan/previewer.cpp871
-rw-r--r--libkscan/previewer.h120
-rw-r--r--libkscan/scandialog.cpp380
-rw-r--r--libkscan/scandialog.h83
-rw-r--r--libkscan/scanparams.cpp1140
-rw-r--r--libkscan/scanparams.h182
-rw-r--r--libkscan/scanservice.desktop70
-rw-r--r--libkscan/scansourcedialog.cpp211
-rw-r--r--libkscan/scansourcedialog.h69
-rw-r--r--libkscan/sizeindicator.cpp113
-rw-r--r--libkscan/sizeindicator.h98
3625 files changed, 622724 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 00000000..74eb758b
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,3 @@
+
+Look in the subdirs to get info about the authors.
+
diff --git a/COPYING b/COPYING
new file mode 100644
index 00000000..8900e10b
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,347 @@
+NOTE! The GPL below is copyrighted by the Free Software Foundation, but
+the instance of code that it refers to (the kde programs) are copyrighted
+by the authors who actually wrote it.
+
+---------------------------------------------------------------------------
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/COPYING-DOCS b/COPYING-DOCS
new file mode 100644
index 00000000..4a0fe1c8
--- /dev/null
+++ b/COPYING-DOCS
@@ -0,0 +1,397 @@
+ GNU Free Documentation License
+ Version 1.2, November 2002
+
+
+ Copyright (C) 2000,2001,2002 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+0. PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+functional and useful document "free" in the sense of freedom: to
+assure everyone the effective freedom to copy and redistribute it,
+with or without modifying it, either commercially or noncommercially.
+Secondarily, this License preserves for the author and publisher a way
+to get credit for their work, while not being considered responsible
+for modifications made by others.
+
+This License is a kind of "copyleft", which means that derivative
+works of the document must themselves be free in the same sense. It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does. But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book. We recommend this License
+principally for works whose purpose is instruction or reference.
+
+
+1. APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work, in any medium, that
+contains a notice placed by the copyright holder saying it can be
+distributed under the terms of this License. Such a notice grants a
+world-wide, royalty-free license, unlimited in duration, to use that
+work under the conditions stated herein. The "Document", below,
+refers to any such manual or work. Any member of the public is a
+licensee, and is addressed as "you". You accept the license if you
+copy, modify or distribute the work in a way requiring permission
+under copyright law.
+
+A "Modified Version" of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A "Secondary Section" is a named appendix or a front-matter section of
+the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall subject
+(or to related matters) and contains nothing that could fall directly
+within that overall subject. (Thus, if the Document is in part a
+textbook of mathematics, a Secondary Section may not explain any
+mathematics.) The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The "Invariant Sections" are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License. If a
+section does not fit the above definition of Secondary then it is not
+allowed to be designated as Invariant. The Document may contain zero
+Invariant Sections. If the Document does not identify any Invariant
+Sections then there are none.
+
+The "Cover Texts" are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License. A Front-Cover Text may
+be at most 5 words, and a Back-Cover Text may be at most 25 words.
+
+A "Transparent" copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, that is suitable for revising the document
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters. A copy made in an otherwise Transparent file
+format whose markup, or absence of markup, has been arranged to thwart
+or discourage subsequent modification by readers is not Transparent.
+An image format is not Transparent if used for any substantial amount
+of text. A copy that is not "Transparent" is called "Opaque".
+
+Examples of suitable formats for Transparent copies include plain
+ASCII without markup, Texinfo input format, LaTeX input format, SGML
+or XML using a publicly available DTD, and standard-conforming simple
+HTML, PostScript or PDF designed for human modification. Examples of
+transparent image formats include PNG, XCF and JPG. Opaque formats
+include proprietary formats that can be read and edited only by
+proprietary word processors, SGML or XML for which the DTD and/or
+processing tools are not generally available, and the
+machine-generated HTML, PostScript or PDF produced by some word
+processors for output purposes only.
+
+The "Title Page" means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page. For works in
+formats which do not have any title page as such, "Title Page" means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+A section "Entitled XYZ" means a named subunit of the Document whose
+title either is precisely XYZ or contains XYZ in parentheses following
+text that translates XYZ in another language. (Here XYZ stands for a
+specific section name mentioned below, such as "Acknowledgements",
+"Dedications", "Endorsements", or "History".) To "Preserve the Title"
+of such a section when you modify the Document means that it remains a
+section "Entitled XYZ" according to this definition.
+
+The Document may include Warranty Disclaimers next to the notice which
+states that this License applies to the Document. These Warranty
+Disclaimers are considered to be included by reference in this
+License, but only as regards disclaiming warranties: any other
+implication that these Warranty Disclaimers may have is void and has
+no effect on the meaning of this License.
+
+
+2. VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no other
+conditions whatsoever to those of this License. You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute. However, you may accept
+compensation in exchange for copies. If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+
+3. COPYING IN QUANTITY
+
+If you publish printed copies (or copies in media that commonly have
+printed covers) of the Document, numbering more than 100, and the
+Document's license notice requires Cover Texts, you must enclose the
+copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover. Both covers must also clearly and legibly identify
+you as the publisher of these copies. The front cover must present
+the full title with all words of the title equally prominent and
+visible. You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a computer-network location from which the general network-using
+public has access to download using public-standard network protocols
+a complete Transparent copy of the Document, free of added material.
+If you use the latter option, you must take reasonably prudent steps,
+when you begin distribution of Opaque copies in quantity, to ensure
+that this Transparent copy will remain thus accessible at the stated
+location until at least one year after the last time you distribute an
+Opaque copy (directly or through your agents or retailers) of that
+edition to the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to give
+them a chance to provide you with an updated version of the Document.
+
+
+4. MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it. In addition, you must do these things in the Modified Version:
+
+A. Use in the Title Page (and on the covers, if any) a title distinct
+ from that of the Document, and from those of previous versions
+ (which should, if there were any, be listed in the History section
+ of the Document). You may use the same title as a previous version
+ if the original publisher of that version gives permission.
+B. List on the Title Page, as authors, one or more persons or entities
+ responsible for authorship of the modifications in the Modified
+ Version, together with at least five of the principal authors of the
+ Document (all of its principal authors, if it has fewer than five),
+ unless they release you from this requirement.
+C. State on the Title page the name of the publisher of the
+ Modified Version, as the publisher.
+D. Preserve all the copyright notices of the Document.
+E. Add an appropriate copyright notice for your modifications
+ adjacent to the other copyright notices.
+F. Include, immediately after the copyright notices, a license notice
+ giving the public permission to use the Modified Version under the
+ terms of this License, in the form shown in the Addendum below.
+G. Preserve in that license notice the full lists of Invariant Sections
+ and required Cover Texts given in the Document's license notice.
+H. Include an unaltered copy of this License.
+I. Preserve the section Entitled "History", Preserve its Title, and add
+ to it an item stating at least the title, year, new authors, and
+ publisher of the Modified Version as given on the Title Page. If
+ there is no section Entitled "History" in the Document, create one
+ stating the title, year, authors, and publisher of the Document as
+ given on its Title Page, then add an item describing the Modified
+ Version as stated in the previous sentence.
+J. Preserve the network location, if any, given in the Document for
+ public access to a Transparent copy of the Document, and likewise
+ the network locations given in the Document for previous versions
+ it was based on. These may be placed in the "History" section.
+ You may omit a network location for a work that was published at
+ least four years before the Document itself, or if the original
+ publisher of the version it refers to gives permission.
+K. For any section Entitled "Acknowledgements" or "Dedications",
+ Preserve the Title of the section, and preserve in the section all
+ the substance and tone of each of the contributor acknowledgements
+ and/or dedications given therein.
+L. Preserve all the Invariant Sections of the Document,
+ unaltered in their text and in their titles. Section numbers
+ or the equivalent are not considered part of the section titles.
+M. Delete any section Entitled "Endorsements". Such a section
+ may not be included in the Modified Version.
+N. Do not retitle any existing section to be Entitled "Endorsements"
+ or to conflict in title with any Invariant Section.
+O. Preserve any Warranty Disclaimers.
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant. To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section Entitled "Endorsements", provided it contains
+nothing but endorsements of your Modified Version by various
+parties--for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version. Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity. If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+
+5. COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice, and that you preserve all their Warranty Disclaimers.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy. If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections Entitled "History"
+in the various original documents, forming one section Entitled
+"History"; likewise combine any sections Entitled "Acknowledgements",
+and any sections Entitled "Dedications". You must delete all sections
+Entitled "Endorsements".
+
+
+6. COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other documents
+released under this License, and replace the individual copies of this
+License in the various documents with a single copy that is included in
+the collection, provided that you follow the rules of this License for
+verbatim copying of each of the documents in all other respects.
+
+You may extract a single document from such a collection, and distribute
+it individually under this License, provided you insert a copy of this
+License into the extracted document, and follow this License in all
+other respects regarding verbatim copying of that document.
+
+
+7. AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, is called an "aggregate" if the copyright
+resulting from the compilation is not used to limit the legal rights
+of the compilation's users beyond what the individual works permit.
+When the Document is included in an aggregate, this License does not
+apply to the other works in the aggregate which are not themselves
+derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one half of
+the entire aggregate, the Document's Cover Texts may be placed on
+covers that bracket the Document within the aggregate, or the
+electronic equivalent of covers if the Document is in electronic form.
+Otherwise they must appear on printed covers that bracket the whole
+aggregate.
+
+
+8. TRANSLATION
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections. You may include a
+translation of this License, and all the license notices in the
+Document, and any Warranty Disclaimers, provided that you also include
+the original English version of this License and the original versions
+of those notices and disclaimers. In case of a disagreement between
+the translation and the original version of this License or a notice
+or disclaimer, the original version will prevail.
+
+If a section in the Document is Entitled "Acknowledgements",
+"Dedications", or "History", the requirement (section 4) to Preserve
+its Title (section 1) will typically require changing the actual
+title.
+
+
+9. TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document except
+as expressly provided for under this License. Any other attempt to
+copy, modify, sublicense or distribute the Document is void, and will
+automatically terminate your rights under this License. However,
+parties who have received copies, or rights, from you under this
+License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+
+10. FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions
+of the GNU Free Documentation License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns. See
+http://www.gnu.org/copyleft/.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License "or any later version" applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation. If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation.
+
+
+ADDENDUM: How to use this License for your documents
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+
+ Copyright (c) YEAR YOUR NAME.
+ Permission is granted to copy, distribute and/or modify this document
+ under the terms of the GNU Free Documentation License, Version 1.2
+ or any later version published by the Free Software Foundation;
+ with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+ A copy of the license is included in the section entitled "GNU
+ Free Documentation License".
+
+If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
+replace the "with...Texts." line with this:
+
+ with the Invariant Sections being LIST THEIR TITLES, with the
+ Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
+
+If you have Invariant Sections without Cover Texts, or some other
+combination of the three, merge those two alternatives to suit the
+situation.
+
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 00000000..5036ba5e
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,17 @@
+1998-12-05 Alex Zepeda <garbanzo@hooked.net>
+
+ * README: Use a "new" style README.
+
+1998-11-13 Alex Zepeda <garbanzo@hooked.net>
+
+ * Makefile.cvs (all): Use an updated Makefile.cvs from kdenetwork that
+ tests for the admin directory.
+
+ * configure.in.1: Remove comment about this being Alpha (quality)
+ software, and update version number (now it's at 1.1pre). Also, now
+ it uses the kde-common copy of the autoconf stuff.
+
+1998-11-08 Alex Zepeda <alex@zippy.dyn.ml.org>
+
+ * Makefile.cvs (all): Use the kde-common version of automoc.
+
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 00000000..f8bad0c1
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,176 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes a while. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/kde/bin', `/usr/local/kde/lib', etc. You can specify an
+installation prefix other than `/usr/local/kde' by giving `configure'
+the option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made.
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
+
diff --git a/Mainpage.dox b/Mainpage.dox
new file mode 100644
index 00000000..668e62f5
--- /dev/null
+++ b/Mainpage.dox
@@ -0,0 +1,16 @@
+/**
+ * @mainpage The KDE Graphics API Reference
+ *
+ * This section contains the KDE online class reference for the current
+ * development version of the KDE graphics package.
+ *
+ * - <a href="kviewshell/html/index.html"><b>kviewshell</b></a>
+ * (<a href="kviewshell/html/classes.html">classes</a>)\n
+ * <i>API for the implementation of kviewshell plugins.</i>
+ *
+ * More information about the KDE architecture in form of
+ * tutorials, HOWTOs,
+ * and FAQs can be found at
+ * the <a href="http://developer.kde.org">KDE Developer's corner</a>.
+ */
+
diff --git a/Makefile.am.in b/Makefile.am.in
new file mode 100644
index 00000000..f2467786
--- /dev/null
+++ b/Makefile.am.in
@@ -0,0 +1,22 @@
+## kdegraphics/Makefile.am $Id$
+## (C) 1997 Stephan Kulow
+
+AUTOMAKE_OPTIONS = foreign 1.6.1
+
+COMPILE_BEFORE_kooka = libkscan
+COMPILE_BEFORE_kfaxview = kfax
+COMPILE_BEFORE_kfile-plugins = kghostview
+COMPILE_AFTER_kviewshell = kdvi kfaxview
+
+DISTCLEANFILES = inst-apps
+
+EXTRA_DIST = admin debian kdebase.spec.in README.pam kde.pamd
+
+dist-hook:
+ cd $(top_distdir) && perl $(top_srcdir)/admin/am_edit -padmin
+
+MAINTAINERCLEANFILES = subdirs configure.in acinclude.m4 SUBDIRS
+
+include admin/Doxyfile.am
+include admin/deps.am
+
diff --git a/Makefile.cvs b/Makefile.cvs
new file mode 100644
index 00000000..b4752bd8
--- /dev/null
+++ b/Makefile.cvs
@@ -0,0 +1,16 @@
+
+all:
+ @echo "This Makefile is only for the CVS repository"
+ @echo "This will be deleted before making the distribution"
+ @echo ""
+ @if test ! -d admin; then \
+ echo "Please recheckout this module!" ;\
+ echo "for cvs: use checkout once and after that update again" ;\
+ echo "for cvsup: checkout kde-common from cvsup and" ;\
+ echo " link kde-common/admin to ./admin" ;\
+ exit 1 ;\
+ fi
+ $(MAKE) -f admin/Makefile.common cvs
+
+.SILENT:
+
diff --git a/README b/README
new file mode 100644
index 00000000..f0ea21a4
--- /dev/null
+++ b/README
@@ -0,0 +1,97 @@
+In this file:
+
+* About kdegraphics
+* Common Mistakes
+* Debugging
+* More Info
+
+
+About kdegraphics
+-----------------
+kdegraphics is a collection of graphic oriented applications:
+
+* debian
+ Files needed to create Debian packages.
+
+* doc
+ XML based documentation for the programs.
+
+* kamera
+ Digital camera io_slave for Konqueror. Together gPhoto this allows you
+ to access your camera's picture with the URL kamera:/
+
+* kcoloredit
+ Contains two programs: a color value editor and also a color picker.
+
+* kdvi
+ Program (and embeddable KPart) to display *.DVI files from TeX.
+
+* kfax
+ A program to display raw and tiffed fax images (g3, g3-2d, g4).
+
+* kfaxview
+ An embeddable KPart to display tiffed fax images.
+
+* kfile-plugins
+ Provide meta information for graphic files.
+
+* kghostview
+ Program (and embeddable KPart) to display *.pdf and *.ps
+
+* kiconedit
+ An icon editor.
+
+* kmrml
+ Connects to a MRML server and find similar images
+
+* kooka
+ A raster image scan program, based on SANE and libkscan.
+
+* kolourpaint
+ An easy-to-use paint program designed for everyday tasks like drawing
+ simple diagrams/logos/icons and editing screenshots.
+
+* kpovmodeler
+ Program to enter scenes for the 3D rendering engine PovRay.
+
+* kruler
+ A ruler in inch, centimeter and pixel to check distances on the screen.
+
+* ksnapshot
+ Make snapshots of the screen contents.
+
+* kuickshow
+ Fast and comfortable imageviewer.
+
+* kview
+ Picture viewer, provided as standalone program and embeddable KPart.
+
+* kviewshell
+ Generic framework for viewer applications.
+
+* libkscan
+ Library to access scanners used by kooka (and koffice), needs SANE to be
+ used
+
+
+Common Mistakes
+---------------
+If configure claims Qt cannot be found, have a look at http://www.trolltech.com
+to get a copy of latest Qt 3.3.x version.
+
+
+Debugging
+---------
+You can use --enable-debug with the configure script, if you want to have
+debug code in your KDE apps and libs. This will ensure useful and more
+verbose backtraces, but will require a lot more disk space.
+
+
+More Info
+---------
+Please direct any bug reports to our bug list by visiting
+http://bugs.kde.org.
+
+General KDE discussions should go to the KDE mailing list (kde@kde.org).
+
+
diff --git a/configure.in.in b/configure.in.in
new file mode 100644
index 00000000..c0c74795
--- /dev/null
+++ b/configure.in.in
@@ -0,0 +1,17 @@
+#MIN_CONFIG
+DO_NOT_COMPILE="$DO_NOT_COMPILE"
+
+dnl Checks for header files.
+AC_HEADER_DIRENT
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h sys/time.h unistd.h stdlib.h paths.h)
+AC_CHECK_SETENV
+AC_CHECK_UNSETENV
+AC_CHECK_USLEEP
+AC_CHECK_MKSTEMPS
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_HEADER_TIME
+
+CXXFLAGS="$CXXFLAGS $KDE_DEFAULT_CXXFLAGS"
+
+KDE_INIT_DOXYGEN([KDE Graphics API Reference], [Version $VERSION])
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644
index 00000000..6812bd2d
--- /dev/null
+++ b/doc/Makefile.am
@@ -0,0 +1,5 @@
+
+KDE_LANG = en
+KDE_DOCS = AUTO
+SUBDIRS = $(AUTODIRS)
+
diff --git a/doc/kamera/Makefile.am b/doc/kamera/Makefile.am
new file mode 100644
index 00000000..085981d9
--- /dev/null
+++ b/doc/kamera/Makefile.am
@@ -0,0 +1,4 @@
+
+KDE_LANG = en
+KDE_DOCS = AUTO
+
diff --git a/doc/kamera/index.docbook b/doc/kamera/index.docbook
new file mode 100644
index 00000000..2579fe41
--- /dev/null
+++ b/doc/kamera/index.docbook
@@ -0,0 +1,78 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+ <!ENTITY kappname "&kamera;">
+ <!ENTITY package "kdegraphics">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE">
+]>
+
+<book lang="&language;">
+
+<bookinfo>
+<title>The &kamera; Handbook</title>
+
+<authorgroup>
+<author>
+<firstname></firstname>
+<othername></othername>
+<surname></surname>
+<affiliation>
+<address><email></email></address>
+</affiliation>
+</author>
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+</authorgroup>
+
+<legalnotice>&FDLNotice;</legalnotice>
+
+<!-- Date and version information of the documentation
+Don't forget to include this last date and this last revision number, we
+need them for translation coordination !
+Please respect the format of the date (DD/MM/YYYY) and of the version
+(Major.minor.lesser), it could be used by automation scripts -->
+
+<date>2000-09-02</date>
+<releaseinfo>0.00.00</releaseinfo>
+
+<!-- Abstract about this handbook -->
+
+<abstract>
+<para>
+&kamera; allows you to view and download images on a digital camera.
+</para>
+</abstract>
+
+
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>Kapp</keyword>
+</keywordset>
+
+</bookinfo>
+
+<chapter id="introduction"> <title>Introduction</title> <para>Sorry, but
+the documentation for &kappname; was not finished when &kde; was installed on
+this computer.</para> <para>If you need help, please check <ulink
+url="http://www.kde.org">The &kde; Website</ulink> for updates, or by
+submitting your question to <ulink url="mailto:kde@kde.org">The
+&kde; User Mailing list</ulink>.</para> <para><emphasis>The &kde;
+Team</emphasis></para>
+
+&underFDL;
+
+</chapter>
+
+&documentation.index;
+</book>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-minimize-attributes:nil
+sgml-general-insert-case:lower
+sgml-indent-step:0
+sgml-indent-data:nil
+End:
+
+// vim:ts=2:sw=2:tw=78:noet
+-->
diff --git a/doc/kcoloredit/Makefile.am b/doc/kcoloredit/Makefile.am
new file mode 100644
index 00000000..085981d9
--- /dev/null
+++ b/doc/kcoloredit/Makefile.am
@@ -0,0 +1,4 @@
+
+KDE_LANG = en
+KDE_DOCS = AUTO
+
diff --git a/doc/kcoloredit/index.docbook b/doc/kcoloredit/index.docbook
new file mode 100644
index 00000000..8599cdf4
--- /dev/null
+++ b/doc/kcoloredit/index.docbook
@@ -0,0 +1,468 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+ <!ENTITY kcoloredit "<application>KColorEdit</application>">
+ <!ENTITY kappname "&kcoloredit;">
+ <!ENTITY package "kdegraphics">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE"> <!-- Change language only here -->
+]
+>
+
+<book lang="&language;">
+<bookinfo>
+<title> The &kcoloredit; Handbook</title>
+<authorgroup>
+<author>
+<firstname>Artur</firstname>
+<surname>Rataj</surname>
+<affiliation>
+<address>&Artur.Rataj.mail;</address>
+</affiliation>
+</author>
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+
+</authorgroup>
+
+<copyright>
+<year>2000</year>
+<holder>&Artur.Rataj;</holder>
+</copyright>
+
+<legalnotice>&FDLNotice;</legalnotice>
+
+<date>2005-12-10</date>
+<releaseinfo>3.5.0</releaseinfo>
+
+<abstract>
+<para>&kcoloredit; is a palette files editor. It can be used for editing
+color palettes and for color choosing and naming.</para>
+</abstract>
+
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>graphics</keyword>
+<keyword>palette</keyword>
+</keywordset>
+</bookinfo>
+
+<chapter id="introduction">
+<title>Introduction</title>
+
+<para>&kcoloredit; is a palette files editor. It can be used for
+editing color palettes and for color choosing and naming.</para>
+
+</chapter>
+
+<chapter id="file-operations">
+<title>File operations</title>
+
+<sect1 id="file">
+<title>About palette files</title>
+
+<para>
+The palette files installed by &kde; can be either system-wide or the
+user ones. The latter are in you private &kde; configuration
+folders, and they are named <guilabel>Custom Colors</guilabel> and
+<guilabel>Recent Colors</guilabel>.
+</para>
+
+<para>
+In &kcoloredit;, you may open all of these palettes, as well as
+palettes in arbitrary files.
+</para>
+
+</sect1>
+
+<sect1 id="file-open">
+<title>Opening a file</title>
+<para>
+In the <guilabel>Open File</guilabel> dialog, you may choose from a
+list of installed palettes, or browse folders for files.
+</para>
+</sect1>
+
+</chapter>
+
+<chapter id="Edition">
+<title>Editing</title>
+
+<sect1 id="cursor">
+<title>Cursor</title>
+
+<para>The cursor is visible as a line in the palette view. It can be
+moved by clicking on an area beside a color.</para>
+
+<para>The cursor has the following functions:</para>
+
+<itemizedlist>
+<listitem>
+<para>
+It points to the color after it. The color, if any, is described below
+the palette view. You may edit its name there.
+</para>
+</listitem>
+<listitem>
+<para>
+It can be used to make a selection. A selection can be made by
+clicking on an area beside a color, so to move the cursor there, and
+by moving the mouse then with the left mouse button pressed.
+</para>
+</listitem>
+<listitem>
+<para>If the <guilabel>At cursor</guilabel> check-box near the
+<guilabel>Add Color</guilabel> button is checked, a color from the
+color chooser is put at the cursor. The color is either inserted
+or it overwrites another one, depending on whether the
+<guilabel>Overwrite</guilabel> mode is chosen. The mode can be chosen
+by checking the <guilabel>Overwrite</guilabel> check-box, that is next
+to the <guilabel>At cursor</guilabel> one.</para>
+</listitem>
+</itemizedlist>
+
+</sect1>
+
+<sect1 id = "selection">
+<title>Selection</title>
+<para>
+A selection, that can be made as it was written in the previous
+section, can be used with the copy, cut and paste operations.
+</para>
+</sect1>
+
+<sect1 id = "clipboard-format">
+<title>Clipboard format</title>
+<para>
+&kcoloredit; uses the following format for clipboard data: for each
+color three numbers for red, green and blue components, respectively,
+and an optional color name, followed by a new line character if there
+is another color. Therefore, if for example three numbers are in the
+clipboard, they can be pasted by &kcoloredit; as a color.
+</para>
+</sect1>
+
+</chapter>
+
+<chapter id="color-selection">
+<title>Selecting a color from an RGB space</title>
+
+<para>
+A color can be selected from an RGB space in &kcoloredit; in the
+following ways:
+<itemizedlist>
+<listitem>
+<para>
+By editing the HSV or RGB components.
+</para>
+</listitem>
+<listitem>
+<para>
+By selecting a color from color gradient panels. In the left one, two
+from HSV components can be selected, and in the right one, the third
+one. The third component can be chosen by clicking on one of the
+buttons labeled <guilabel>H:</guilabel>, <guilabel>S:</guilabel> and
+<guilabel>V:</guilabel>. The one component panel display colors with
+the other two components equal to these selected in the two components
+panel. The two components panel may display colors with the third
+component fixed, or, if the <guilabel>Variable</guilabel> check-box is
+set, with a value equal to the one selected in the one component
+panel. In the <guilabel>Replace</guilabel> mode, the color selected in
+panels replaces the output one instantly, and in the
+<guilabel>Change:</guilabel> mode it modifies the output color after
+each click, or a mouse move while a mouse button is
+pressed. Therefore, in the latter mode the color selected in the
+gradient panels may be different from the output color. To synchronize
+the colors, the <guibutton>Synchronize</guibutton> button can be used.
+</para>
+</listitem>
+</itemizedlist>
+</para>
+</chapter>
+
+<!-- Someone energetic might want to write a small chapter here -->
+<!-- describing RGB vs HSV etc -->
+
+<chapter id="drag-and-drop">
+<title>Drag and drop</title>
+<para>
+The palette colors and the color selection output color can be dragged
+with a mouse.
+</para>
+</chapter>
+
+<chapter id="menu-reference">
+<title>Menu Reference</title>
+
+<sect1 id="file-menu">
+<title>The <guimenu>File</guimenu> Menu</title>
+
+<variablelist>
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo action="simul">&Ctrl;
+<keycap>N</keycap></keycombo></shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>New</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Start a new palette in the current window.</action></para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>New Window</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Open a new window</action></para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo action="simul">&Ctrl;
+<keycap>O</keycap></keycombo></shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Open</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Open a saved palette.</action></para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Open Recent</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Reopen a palette that you have recently been
+editing.</action></para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo action="simul">&Ctrl;
+<keycap>S</keycap></keycombo></shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Save</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Save the currently open palette.</action></para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Save As...</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Save the currently open palette with a new
+name.</action></para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo action="simul">&Ctrl;
+<keycap>W</keycap></keycombo></shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Close</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Close</action> the current &kcoloredit; window</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo action="simul">&Ctrl;
+<keycap>Q</keycap></keycombo></shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Quit</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Quit</action> &kcoloredit;.</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+</sect1>
+
+<sect1 id="edit-menu">
+<title>The <guimenu>Edit</guimenu> Menu</title>
+
+<variablelist>
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo action="simul">&Ctrl;
+<keycap>X</keycap></keycombo></shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Cut</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Cut the currently selected color to the
+clipboard.</action></para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo action="simul">&Ctrl;
+<keycap>C</keycap></keycombo></shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Copy</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Copy the currently selected color to the
+clipboard.</action></para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo action="simul">&Ctrl;
+<keycap>V</keycap></keycombo></shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Paste</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Paste a color from the clipboard.</action></para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+</sect1>
+
+<sect1 id="color-menu">
+<title>The <guimenu>Color</guimenu> Menu</title>
+
+<variablelist>
+<varlistentry>
+<term><menuchoice>
+<guimenu>Color</guimenu>
+<guimenuitem>From Palette</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Find the color currently selected in the palette, in the
+color selector on the left.</action></para><!-- eww... needs rewrite -->
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Color</guimenu>
+<guimenuitem>From Screen</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Pick a color from anywhere on the screen, and find it
+in the color selector on the left.</action></para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+</sect1>
+
+<sect1 id="settings-menu">
+<title>The <guimenu>Settings</guimenu> Menu</title>
+
+<variablelist>
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Hide/Show Toolbar</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Toggle on and off the toolbar icons.</action></para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Hide/Show Statusbar</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Toggle on and off the status bar.</action></para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Hide/Show Color Names</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para>If the currently open palette has color name, <action>display
+them alongside the colors</action>.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Configure Shortcuts...</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Configure</action> the keyboard keys you use to access the
+different actions.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Configure Toolbars...</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Configure</action> the items you want to put in the toolbar
+</para>
+</listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect1>
+
+<sect1 id="help-menu">
+<title>The <guimenu>Help</guimenu> Menu</title>
+
+&help.menu.documentation;
+
+</sect1>
+
+</chapter>
+
+<chapter id="credits-and-licenses">
+<title>Credits and Licenses</title>
+
+<para>&kcoloredit; copyright 2000 &Artur.Rataj;</para>
+
+<para>Documentation copyright 2000 &Artur.Rataj;</para>
+
+<!-- TRANS:CREDIT_FOR_TRANSLATORS -->
+
+&underFDL;
+&underGPL;
+</chapter>
+
+<appendix id="installation">
+<title>Installation</title>
+
+&install.intro.documentation;
+
+&install.compile.documentation;
+
+</appendix>
+
+</book>
+<!--
+Local Variables:
+mode: sgml
+sgml-omittag: nil
+sgml-shorttag: t
+End:
+-->
+
diff --git a/doc/kdvi/KDVI-features.dvi b/doc/kdvi/KDVI-features.dvi
new file mode 100644
index 00000000..2bf4d014
--- /dev/null
+++ b/doc/kdvi/KDVI-features.dvi
Binary files differ
diff --git a/doc/kdvi/KDVI-features.tex b/doc/kdvi/KDVI-features.tex
new file mode 100644
index 00000000..66c3f9f5
--- /dev/null
+++ b/doc/kdvi/KDVI-features.tex
@@ -0,0 +1,480 @@
+\documentclass{article}
+
+\usepackage{amstext}
+\usepackage{colordvi}
+\usepackage{graphicx}
+\usepackage{times}
+\usepackage[arrow,matrix,curve,ps]{xy}
+\xyoption{dvips}
+\usepackage[active]{srcltx}
+\usepackage[hypertex]{hyperref}
+\sloppy
+
+\newcommand{\KDVI}{{\sf KDVI 1.1}}
+
+\begin{document}
+
+\title{Support for \TeX\ extensions in \KDVI}
+
+\author{Stefan Kebekus}
+
+\maketitle
+\begin{abstract}
+ This document describes the extensions to the standard format of DVI
+ files which \KDVI\ implements in order to support PostScript
+ inclusion and hyperlinks.
+
+ \KDVI\ is a program that displays DVI-files generated by the \TeX\
+ typesetting system. If you don't know what \TeX\ is then you are
+ most likely not interested in this. If you would like to know how to
+ use special features of \KDVI, then you can find examples here.
+\end{abstract}
+
+\tableofcontents
+
+\section{What's all this}
+
+The DVI-previewing program \KDVI\ is able to display standard
+DVI-files as specified in \cite{Level0Std}. In order to support
+graphics inclusion, hyperlinks and non-standard fonts, \KDVI\
+implements a number of features which extend \cite{Level0Std}. In
+particular, \KDVI\ supports a number of \TeX 's $\backslash${\tt
+ special} commands. The aim of this document is to describe these
+extensions and give examples of their use.
+
+Unfortunately, in spite of several attempts to find a sound standard
+for the use of $\backslash${\tt special} commands, there is now a
+wealth of competing and mutually incompatible definitions.
+
+\KDVI\ does not attempt to support all possible features. Instead, we
+tried to implement those which are most useful and used most commonly.
+In this, we have tried to be consistent with the {\sf dvips} program.
+\KDVI\ does not support a number of outdated and unsane standards, nor
+does it support features which impair the system security.
+
+
+\section{Virtual fonts}
+
+\KDVI\ supports ``virtual fonts''. This enables \TeX\ to use
+PostScript fonts. For more information, and a complete specification,
+consult \cite{dvips}.
+
+\paragraph*{Example}
+
+This text uses the ``Times'' family of fonts instead of the ``Computer
+Modern'' fonts which are usually used by \TeX. This was realized in
+\LaTeX 2$\epsilon$ by including the line
+\begin{verbatim}
+\usepackage{times}
+\end{verbatim}
+in the header of this document.
+
+
+\section{PostScript support}
+
+\KDVI\ implements basic facilities to include PostScript graphics in a
+DVI file, which will enable the reader to conviently read most
+scientific papers which use such features.
+
+\subsection{Literal PostScript}
+
+\KDVI\ supports the inclusion of PostScript into DVI-files by means of
+the quote-special. The syntax follows the specification of
+\cite{dvips}:
+\begin{verbatim}
+\special{" PostScript-commands}
+\end{verbatim}
+The PostScript-commands are not directly included, in fact they are
+sandwiched between a {\tt save} and {\tt restore} pair. That way
+\KDVI\ ensures that the command cannot affect PostScript-commands
+which appear somewhere else in your file.
+
+\paragraph*{Example}
+
+Figure~\ref{quote-special} shows an example taken from \cite{dvips}.
+The generating \TeX -code is
+\begin{verbatim}
+\vbox to 100bp{\vss
+\special{" newpath 0 0 moveto 100 100 lineto
+ 300 0 lineto closepath gsave 0.8 setgray fill
+ grestore stroke}}
+\end{verbatim}
+
+\begin{figure}
+\vbox to 100bp{\vss
+\special{" newpath 0 0 moveto 100 100 lineto 300 0 lineto closepath gsave 0.8 setgray fill grestore stroke}}
+\caption{Graphic generated by literal PostScript inclusion\label{quote-special}}
+\end{figure}
+
+
+\subsection{Direct PostScript}
+
+\KDVI\ supports the inclusion of PostScript into DVI-files by means of
+the direct-special. The syntax follows the specification of
+\cite{dvips}:
+\begin{verbatim}
+\special{ps: Postscript-commands}
+\end{verbatim}
+The PostScript-commands are directly included, and there is no
+protective {\tt save} and {\tt restore} pair. The use of this command
+is not recommended, as it may have funny side effects on other
+PostScript commands which appear later in your file.
+
+\KDVI\ also supports the following syntactical variants which are
+explained in \cite{dvips}:
+\begin{verbatim}
+\special{ps: Postscript-commands}
+\special{ps::[begin] Postscript-commands}
+\special{ps:: Postscript-commands}
+\special{ps::[end] Postscript-commands}
+\end{verbatim}
+The variant
+\begin{verbatim}
+\special{ps: plotfile filename}
+\end{verbatim}
+is not currently supported.
+
+\paragraph*{Example}
+
+The command
+\begin{verbatim}
+\includegraphics[height=3cm, angle=20]{aboutkde.ps}
+\end{verbatim}
+which is used in section~\ref{chap:eps} uses the direct-special
+internally in order to set the rotation.
+
+\subsection{Literal headers}
+
+Literal headers work as described in \cite{dvips}.
+\begin{verbatim}
+\special{! PostScript-Header-commands}
+\end{verbatim}
+
+\paragraph*{Example}
+The following diagram, which was generated using the \Xy -pic macro
+packages uses literal postscript inclusion which relies on literal
+headers.
+$$
+\xymatrix{ {\tilde X}
+ \ar@{-->}[rrd]_{\exists \alpha} \ar[rrrr]^{\eta}_{\txt{\tiny
+ normalization}} \ar@/_/ [rrdd]_ {\tilde \pi} & & & & {X}
+ \ar@/^/[lldd]^{\pi} \\ & & {X'}
+ \ar@{-->}[rru]_{\exists \beta} \ar@{-->}[d]_{\exists \pi'} & & \\ & &
+ {Y}& &}
+$$
+Note that the actual headers are defined on the first page of the
+document. This was a major source of trouble in earlier versions of
+KDVI.
+
+
+
+\subsection{PostScript headers}
+
+PostScript headers work as described in \cite{dvips}. This command is
+very similar to the literal header command, but expects the name of a
+file which should be included.
+\begin{verbatim}
+\special{header=filename}
+\end{verbatim}
+
+
+
+
+\subsection{EPS inclusion}\label{chap:eps}
+
+A popular way to include PostScript-files into \TeX\ documents uses
+the PSFile $\backslash${\tt special} command. Again this is explained
+in detail in \cite{dvips}. Currently \KDVI\ supports the syntax
+\begin{verbatim}
+\special{psfile=File keyword=value keyword=value ...}
+\end{verbatim}
+Where keyword is one of the following
+\begin{description}
+\item[llx] lower left corner of the bounding box, $x$-coordinate
+\item[lly] lower left corner of the bounding box, $y$-coordinate
+\item[urx] upper right corner of the bounding box, $x$-coordinate
+\item[ury] upper right corner of the bounding box, $y$-coordinate
+\item[rwi] width of the bounding box. If $llx-urx \not = rwi$, then
+the boundig box is scaled accordingly.
+\item[rhi] height of the bounding box If $lly-ury \not = rhi$, then
+the boundig box is scaled accordingly.
+\item[angle] rotates the picture counterclockwise
+\end{description}
+Unknown keywords are silently ignored. The keywords {\tt llx}, {\tt
+ lly}, {\tt urx}, {\tt ury} and {\tt rwi} are usually generated by
+the {\tt epsf} macros. The keywords {\tt hoffset}, {\tt voffset},
+{\tt hsize}, {\tt vsize}, {\tt hscale}, {\tt vscale}, {\tt angle} and
+{\tt clip} are not currently implemented. The ``uncompression''
+feature of {\sf dvips} and {\sf xdvi} which allows to execute
+arbitrary commands in via the syntactical variant
+\begin{verbatim}
+\special{psfile="'shell-command" keyword=value ...}
+\end{verbatim}
+is deliberately not implemented for security reasons.
+
+\paragraph*{Example}
+Figure~\ref{epsf-special} shows an embedded postscript-file.
+\begin{figure}
+ \begin{center}
+ \includegraphics[height=3cm]{aboutkde.ps}
+ \includegraphics[height=4cm]{aboutkde.ps}
+ \includegraphics[height=3cm, angle=20]{aboutkde.ps}
+ \end{center}
+\caption{Embedded PostScript graphic\label{epsf-special}}
+\end{figure}
+This was easily realized by including the line
+\begin{verbatim}
+\usepackage{graphicx}
+\end{verbatim}
+into the header of this document, and the lines
+\begin{verbatim}
+\includegraphics[height=3cm]{aboutkde.ps}
+\includegraphics[height=4cm]{aboutkde.ps}
+\includegraphics[height=3cm, angle=20]{aboutkde.ps}
+\end{verbatim}
+at the place where the graphic should appear. It is strongly
+recommended to use the {\tt graphicx} macro package for this purpose.
+\begin{figure}
+ \begin{center}
+ \includegraphics[height=2cm, bb=0 0 150 50]{nonexistent.ps}
+ \end{center}
+\caption{Reference to a non-existent PS-file\label{nonex-special}}
+\end{figure}
+Figure~\ref{nonex-special} shows how \KDVI\ warns you about
+non-existent files.
+
+
+\section{Hypertext support}
+
+\KDVI\ supports commands for hyperlink support which commands
+establish links between sections of documents in a manner exactly
+analogous to the HTML of the WWW. For a detailed specification we
+refer to \cite{HFAQ99} or \cite{Rah98}. Note, however, that \KDVI\
+does currently not allow nested hyperlinks.
+
+\subsection{Hyper-Labels}
+
+The commands
+\begin{verbatim}
+\special{html:<a name="namestring">}
+\special{html:</a>}
+\end{verbatim}
+labels the current point of the text for later reference.
+
+\subsection{Hyper-References}
+
+The commands
+\begin{verbatim}
+\special{html:<a href="hrefstring">}
+Text
+\special{html:</a>}
+\end{verbatim}
+makes {\tt Text} a link to {\tt hrefstring}, where {\tt hrefstring} is
+an absolute or relative URL in the standard format used on the
+internel. If {\tt hrefstring} is of the form {\tt \#label} then it
+points to the section of the current document which is labeled using
+the labeling command described above:
+\begin{verbatim}
+\special{html:<a name="namestring">}
+\end{verbatim}
+
+
+
+\paragraph*{Example}
+This document features a clickable table of contents, and also the
+references can be clicked on. This has been achieved by using the {\tt
+ hyperref} macro package in \LaTeX\ by including the line
+\begin{verbatim}
+\usepackage[hypertex]{hyperref}
+\end{verbatim}
+into the document preamble. Everything else is automatic.
+
+Here is an external link which points to the \href{http://www.kde.org}{main
+ website of the KDE project}. For this, the command {\tt href} of the
+{\tt hyperref} macro package was used:
+\begin{verbatim}
+\href{http://www.kde.org}{main
+ website of the KDE project}
+\end{verbatim}
+
+
+\paragraph{Warning.} On some installations, the {\tt
+ hyperref} macro package is configured to generate PostScript
+hyperlinks for {\tt dvips} by default. On these systems, using the
+line
+\begin{verbatim}
+\usepackage{hyperref}
+\end{verbatim}
+will generate DVI file whose hyperlinks are not visible in KDVI.
+Worse, KDVI will call the {\tt ghostview} PostScript interpreter for
+every page, which makes the display very slow.
+
+
+
+\section{Colored \Red{text} \Green{and} \Blue{background}}
+
+The DVI specials for colored text are supported as they are described
+in \cite{dvips}.
+
+\paragraph*{Example} In this document, the following code was used to
+generate the text below.
+\begin{verbatim}
+\usepackage{colordvi}
+
+...
+
+\textGreen This text is green but here we are
+\Red{switching to red, \Blue{nesting blue},
+recovering the red} and back to original green.
+\textCyan The text from here on will be cyan
+unless \Yellow{locally changed to yellow}. Now
+we are back to cyan. \textBlack
+\end{verbatim}
+
+This gave the following output:
+\begin{verse}
+ \textGreen This text is green but here
+we are \Red{switching to red, \Blue{nesting blue}, recovering the red}
+and back to original green. \textCyan The text from here on will be
+cyan unless \Yellow{locally changed to yellow}. Now we are back to
+cyan. \textBlack
+\end{verse}
+
+To set the background color of the page, the command
+\background{Lavender}
+\begin{verbatim}
+\background{Lavender}
+\end{verbatim}
+was used. To switch back to normal, the command
+\begin{verbatim}
+\background{White}
+\end{verbatim}
+was placed somewhere on the following page. As you see, the background
+command does not fit well into \LaTeX's philosophy and should be
+avoided.
+
+\section{Rotated Text}
+
+Rotated text can sometimes be useful, e.g. to fit large table onto a
+single page. This is used, e.g.~in the style files of journals of the
+American Astronomical Society. Here is one example.
+
+\begin{table}[h]
+ \centering
+\begin{tabular}{l|ll}
+ & \rotatebox{90}{uses \TeX} & \rotatebox{90}{uses Linux} \\ \hline
+ Stefan & $\times$ & $\times$ \\
+ Anke & & $\times$ \\
+ Thomas & $\times$ &\\
+\end{tabular}
+\end{table}
+
+This was easily realized by including the line
+\begin{verbatim}
+\usepackage{graphicx}
+\end{verbatim}
+into the header of this document. The table itself was then typeset by
+{\footnotesize
+\begin{verbatim}
+\begin{tabular}{l|ll}
+ & \rotatebox{90}{uses \TeX} & \rotatebox{90}{uses Linux} \\ \hline
+ Stefan & $\times$ & $\times$ \\
+ Anke & & $\times$ \\
+ Thomas & $\times$ &\\
+\end{tabular}
+\end{verbatim}
+}
+
+\section{Source text specials}
+
+\KDVI\ is able to make use of source file information which is included
+in the DVI file. To include source file information, a {\tt special}
+command like to following should be included at the beginning of every
+paragraph or every line:
+\begin{verbatim}
+\special{src:123text.tex}
+\end{verbatim}
+This tells \KDVI\ that the next paragraph should be associated with
+line 123 in the source file text.tex.
+
+It is of course not practical to add these commands manually to the
+beginning of every line ---see the \href{help:/kdvi}{Handbook of
+\KDVI} to learn how to add the special commands automatically to your
+DVI files.
+
+The main use of source file specials is the interaction between \KDVI\
+and your editor. Starting from version~1.0, both \emph{forward search}
+and \emph{inverse search} are supported.
+
+\subsection{Forward search}
+
+Forward search is a feature that helps you find the place in the DVI
+file that corresponds to a certain line in the source text. If source
+file information is included, you can find the place in the DVI file
+{\tt test.dvi} which corresponds to line 1234 in the source file {\tt
+text.tex} by starting \KDVI\ like this:
+\begin{verbatim}
+kdvi file:test.dvi#1234text.tex
+\end{verbatim}
+In pracitse, this command line will be generated by a script that
+communicates with your editor. Currently, scripts for Emacs and XEmacs
+exist. As usual, the \href{help:/kdvi/forward-search.html}{Handbook of
+\KDVI} explains how to set up your editor with thest scripts.
+
+
+\subsection{Inverse search}
+
+\background{White}
+Inverse search means that you can click into the document in \KDVI,
+and your editor will open, load the source file and jump to the proper
+place. \KDVI\ currently supports the editors Emacs, Kate, NEdit, VI
+and XEmacs. Users who prefer a different editor can specify shell
+commands which are to be used. Again we refer to the
+\href{help:/kdvi/inverse-search.html}{Handbook of \KDVI} for a detailed explanation.
+
+\paragraph*{Example}
+If you are viewing this document in \KDVI, you can click anywhere with
+the middle mouse button (if your mouse has only two buttons, click
+left and right simultaneously). An editor will pop up, load the
+\LaTeX\ sourcefile and jump to the appropriate line in the
+text. Source specials has been added using the {\tt srcltx} macro
+package in \LaTeX\ by including the line
+\begin{verbatim}
+\usepackage[active]{srcltx}
+\end{verbatim}
+into the document preamble. Everything else is automatic.
+
+
+\begin{thebibliography}{CM97}
+
+\bibitem[Bha99]{HFAQ99}
+T.~Bhattacharya et al.
+\newblock {\em Hyper\TeX\ FAQ}
+\newblock available on the internet site of the preprint server of the
+ Los Alamos National Labatories at
+\href{http://arXiv.org/hypertex}{\small \tt http://arXiv.org/hypertex}
+
+\bibitem[Rah98]{Rah98}
+S.~Rahts
+\newblock {\em Hypertext marks in \LaTeX: the {\sf hyperref} package}
+\newblock included in the tetex distribution. A copy can be found on KDVI's
+home page at \hfill \linebreak
+\href{http://devel-home.kde.org/~kdvi/DVI/hyperref-manual.pdf}{\small \tt http://devel-home.kde.org/$\sim$kdvi/DVI/hyperref-manual.pdf}
+
+\bibitem[Rok00]{dvips}
+T.~Rokicki
+\newblock {\em DVIPS: A \TeX\ Driver}
+\newblock included in the tetex distribution. A copy can be found on KDVI's
+home page at \hfill \linebreak
+\href{http://devel-home.kde.org/~kdvi/DVI/dvips.dvi}{\small \tt http://devel-home.kde.org/$\sim$kdvi/DVI/dvips.dvi}
+
+\bibitem[TUG0]{Level0Std}
+The TUG DVI Driver Standards Committee
+\newblock {\em The DVI Driver Standard, Level 0}
+\newblock included in the tetex distribution. A copy can be found on KDVI's
+home page at \hfill \linebreak
+\href{http://devel-home.kde.org/~kdvi/DVI/dvistd0.dvi}{\small \tt http://devel-home.kde.org/$\sim$kdvi/DVI/dvistd0.dvi}
+
+
+\end{thebibliography}
+\end{document}
diff --git a/doc/kdvi/Makefile.am b/doc/kdvi/Makefile.am
new file mode 100644
index 00000000..085981d9
--- /dev/null
+++ b/doc/kdvi/Makefile.am
@@ -0,0 +1,4 @@
+
+KDE_LANG = en
+KDE_DOCS = AUTO
+
diff --git a/doc/kdvi/aboutkde.ps b/doc/kdvi/aboutkde.ps
new file mode 100644
index 00000000..63200859
--- /dev/null
+++ b/doc/kdvi/aboutkde.ps
@@ -0,0 +1,3351 @@
+%!PS-Adobe-2.0 EPSF-2.0
+%%Title: /home/devel/dvifiles/aboutkde.ps
+%%Creator: XV Version 3.10a Rev: 12/29/94 (PNG patch 1.2) - by John Bradley
+%%BoundingBox: 0 0 150 250
+%%Pages: 1
+%%DocumentFonts:
+%%EndComments
+%%EndProlog
+
+%%Page: 1 1
+
+% remember original state
+/origstate save def
+
+% build a temporary dictionary
+20 dict begin
+
+% define string to hold a scanline's worth of data
+/pix 450 string def
+
+% define space for color conversions
+/grays 150 string def % space for gray scale line
+/npixls 0 def
+/rgbindx 0 def
+
+% lower left corner
+0 0 translate
+
+% size of image (on paper, in 1/72inch coords)
+149.97600 249.98400 scale
+
+% define 'colorimage' if it isn't defined
+% ('colortogray' and 'mergeprocs' come from xwd2ps
+% via xgrab)
+/colorimage where % do we know about 'colorimage'?
+ { pop } % yes: pop off the 'dict' returned
+ { % no: define one
+ /colortogray { % define an RGB->I function
+ /rgbdata exch store % call input 'rgbdata'
+ rgbdata length 3 idiv
+ /npixls exch store
+ /rgbindx 0 store
+ 0 1 npixls 1 sub {
+ grays exch
+ rgbdata rgbindx get 20 mul % Red
+ rgbdata rgbindx 1 add get 32 mul % Green
+ rgbdata rgbindx 2 add get 12 mul % Blue
+ add add 64 idiv % I = .5G + .31R + .18B
+ put
+ /rgbindx rgbindx 3 add store
+ } for
+ grays 0 npixls getinterval
+ } bind def
+
+ % Utility procedure for colorimage operator.
+ % This procedure takes two procedures off the
+ % stack and merges them into a single procedure.
+
+ /mergeprocs { % def
+ dup length
+ 3 -1 roll
+ dup
+ length
+ dup
+ 5 1 roll
+ 3 -1 roll
+ add
+ array cvx
+ dup
+ 3 -1 roll
+ 0 exch
+ putinterval
+ dup
+ 4 2 roll
+ putinterval
+ } bind def
+
+ /colorimage { % def
+ pop pop % remove 'false 3' operands
+ {colortogray} mergeprocs
+ image
+ } bind def
+ } ifelse % end of 'false' case
+
+
+
+150 250 8 % dimensions of data
+[150 0 0 -250 0 250] % mapping matrix
+{currentfile pix readhexstring pop}
+false 3 colorimage
+
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fcfffffffdfffefdfbfefffffffffff8fffff8fffffffcfbfefffbfeffffffffffffffff
+fffefffefefffffffffefdfffdfdfde7e7e79797976767674444443a3a3a3333337f7f7f
+fffefdfffdfffdfcfffffffbfefffffefefffefdfffffffafffffffffffffefefefefefe
+fffffffefefefffffffefefeffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fcfefdfdfdfdfffffffffffffefcfdfefffffbfffffffdfffefcfffffff8fefff9ffffff
+fbfcf6fdfef9fffeffa3a2a74b4b4b1b1b1b1a1a1a2424243535352929292d2d2dc2c2c2
+fffefafffefffffffffffffd9799942c2e2d606165a0a1a5fffffffdfdfdfffffffafafa
+fffffffffffffbfbfbffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffbfdfffefeffffdadada979a93fffdf6fffefbfefffffffffbfffefffffffffefefc
+ffffffafb0a830322513121a1717172525252121211818181b1b1b676767f7f7f7ffffff
+fefefefdfdfbfffff8fffffdc9cbca1517141b1c1e2a2b2f3e3e3ea3a3a3fefefeffffff
+fcfcfcfffffffffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffafefffffffefffcfffd4a5c467e876cfbf5e5fffff6fffdfefffdfffbf9fffffeff
+82837e181914161618161614131313151515404040838383eaeaeafffffffcfcfcffffff
+fefffffefffffffff6fffefffefdff979a911618131315102727271e1e1e5f5f5fffffff
+fdfdfdfefefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffefbfdfcfffffdfffafff9759774567645838a60ddd9b6fffffbfbf9fefffdfffffffd
+999a9556555d5c5a6571726aa9a9a9e1e1e1fffffffefefefffffffafafaffffffffffff
+fbfffffefefffdfdfbfffdfffffffb979c7e888c7d55584f1616161515151717176b6b6b
+fffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffefdfffefffffbfffefffbb2d4b167995e7a9858999f63cad092ffffeffffefffaf8f9
+fffefffffefffffffbfdfef8fcfcfcfffffffffffffdfdfdfdfdfdffffffffffffffffff
+fbfff5fefefffcfafbfffffa7b7d589da367eaedd8fefefed2d2d27878783f3f3f696969
+fcfcfcfefefefffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fdfdfbfafefffffefffffafaf4ffee7db27c84be729ab669bac565d3dc8bfeffd9fffffa
+fdfcf8fffffdfcfcfefefff8fffffffefefefffffffffffffcfcfcfffffffffffffdfdfd
+fefff4fefdfffdfde386875bb1b46dd2d98cfffff1fffefffffffffefefefffffffdfdfd
+fefefefffffffffffffefefeffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fcfffdf9fffffbfffffffafffffef796c79a90da8da2d47dc3cc7be8f687f0fe8cfcffc2
+fffff7fffefffffffffefffffdfdfdfffffffffffffdfdfdfffffffffffffdfdfdffffff
+fefffbe9e8e68b8f54b2b763fdffa4dde195fffcf3fffefffffffffefefefffffffdfdfd
+fffffffbfbfbfdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffcfffbfffffcfdf8fffdfffff7ffd7f5d396ea95aef9a6bfeb9cd0ef78ffff9ffffd9a
+fcffb0f9fffdfbfefffffef4fafefffffffdfffef8fffefbfdfdfffcfffdfcfffdfefeff
+eeebe4828744bec55efdff9bfeffacdee48afffcfffffeffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffbfffdfffefefffbfbfbfdfffdfff7fff0aae6a6b2ffafc1ffa9d5fda5f2ff94ffffab
+ffffabffffb0feffddfafffff8fffdfbfffbfefefcfffdfffffefffffffafcfcf4fffcff
+93935dc3c95ffcfc98fffdaffffeb3e9ee94fffdfefefffdffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffcfffffdfcfcfffbfafefdfffffffffffbdbf7d1acfea9d2ffc2dfffb8eeffa3fffdad
+fffbbdb7c86a5176296f975bdbe4d1fcfffafcfcfff9fdfcfbfff1f9fefffefffd929a5f
+bcca5bfbff95fffbbcfffccdffffb2eaf096fffdfffcfffbffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffdfffffefdf7fcf8fffffffdfffefbfafffcfff4b8f5afd5ffcbe9fde2fafdc6ffffad
+99b0562b5620356e21366e173e641982ab6999ce748dd35974c13f6ab830589d1c508920
+6e8b3b849e3bb7c381fbfcd0fdffbdf6fea9fffff8fcfdffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fefefffffffdfefffdfffbfefefffff9fffffffffde1ffd2bcff9beefefbfcfffba3d16f
+29680f386721375d24335f2068945597b774d1e09df3f9cbfbffdcd9fba7699e322c6812
+295e102d5717264412596e2bdbeb93f9ffb5fefbf4fffbffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fdfcfffefffdfefffdfff9fcfffefff9fffffcfefdfefff1c3fa9fe4ffdcbff0c1388330
+31821c346826254d07749a67c7e6bae6ffbbfaffcbfffedfffffedfffffdfbfff4a1b474
+3063202e5e143d651e728e53bbcc98f6fecbfefee6fffbf2ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffdfcfefffffdfffcfefffffffbfffffefcfcfffbfffdfff9fff8bff89953ac3e3a951e
+3e902227701f6daa6ec5f8c0d9fdd1ebffdff3fedefeffeafffffdfefcfffffdfffdfdff
+bed79d39511f667c56aec39ae0f2c0f7ffdcffffefffffeaffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffefafffffffcfffdf7fffffffbfffffbfaf9fff6fff9fffbfff9bdf5aa389d1143a72d
+3c942463b455b9fec7befec1e5ffd2f0ffdcfeffebfffff3fefdfbfffffffbfdf8fefffd
+fffbff92917c777e5fbbc79fe4f6baf8ffdffbfcf7fffffaffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffdfffbfff84c923042af22
+439d228ddd98b3ffc3caffcbe6ffdffafde8fffff3fafff7fffffdfffdfffffefffffcff
+fefffdfcfcf489917ab0c59adef5c1fbffdcfffff3fdfdfffffffdfffffdfffffdfffefc
+fcfcfafffffdfcfcfafffffdffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffefffffcfdff9ec691378426
+4a9b3eabfcc1b6ffc9cefed4e5fdddffffedfefff1f9fff6fcfcfafffefffcfdfffffeff
+fcfefbfffffbd8e0cbb1c497e7fcc4f5ffdafefef2fefffffffefffffefffffdfeffffff
+fffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffdfffafefafff8fff4527e4b
+5aa564b4ffd3bcffced0fed9e8ffe0feffebfefff1f9fff8fffffdfffffffafffefeffff
+fcfefdfffefffefff3acbf91dbf0b8fbffe1fffff8fbfdfcfffffffffffffefefefdfdfd
+fffffffdfdfdfffffffefefeffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffff8fffefff3f9eb3a5f34
+a1f0b7afffd1bafac6d1ffd7e1ffe0faffeddaded0808a81ababa9fefefefcfffffeffff
+fefffffffdfffbfef3bccda0ddefbbfdffe9fdfcf8fefffdfefefefffffffffffffefefe
+fffffffffffffefefeffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffbf8f9fffa3f59363b6e35
+a8fccaabfed0c3fdd4cdffd8e6ffeca2af9d1820130d1810565654a5a1a2f4f6f5fffeff
+fdfffefffcfffffffad8e6c2aebd94717463696866b9bbb6fefffffdfffefbfbfbffffff
+fdfdfdfffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffb6b856a1a46113e813c
+adffd9b4ffe1c4fcdfcbffe1c6edd2111e0d0f160e161f1a444245bdb8bcb3b4b6fffdfe
+fdfffefffefffffffbd3ddc5222c13191911201e1f7e807bbbbdbcfdfffefefffffafafa
+fffffffffffffdfbfcfffeffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffaec6ac204816255c18438a3e
+b4ffe0b3fce1c4fee6cbffe55b7b66151b11171813141a182422277d7b80bbc1c1e2e6e7
+fefffffffefffefdf97f857b0e140a181715282327636564bcc0bfcdd1d0f9fbfafeffff
+fffffffdfdfdfffefffffeffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffff2f5e282e611c2f681958984a
+bafddebfffe5bffbdfc8fddf384f3f13120d1e1a191317181c1a1f3b3a4097a3a3b6c0bf
+fefffffffefbfffffb454a46161a1b171518201b1f3435379ea2a3acb0b1fefffffcfdff
+fefefffffffffffdfffffeffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffdfffffff7fcf8fbfffbfffdfffffbfff9fff6608657245b17397d283871204c8b3c
+b1ffdbc3fff4c5faf0aaffce3443461d1f1c1b201c12151c1f16272b282f77807fa4a7ac
+fcfffffefefcfffffa5e59531b16131b17181b191a2626247b84899aa0aefcfffffffffb
+fefcfffffefffffffaffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fdfdfdfffffdfefffdfcfcfcfffdfffcfcfaacc3a6205016387824387c25377a1b306b1b
+a2f9c2c8fff9c5fdf2aeffd6486b67202b271618131a1e1d1d181e2121234d5756848e8d
+fefffffefffffffffa6f706a13131118181819191b202221495154797e84e0e4e3fefffd
+fffefffefefefefff9feffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffefff7f9f6fffffffffcfffffcfff4fff02b582132702337841e3e892c39861c36701c
+8de49fccfffacafffbb3fcdf65988f2b3d3d1b1d1c181d16111610202423262f2c888f87
+fefdfffefffffcfffb7b8079141915181c1d14181b1d1e22373c3f545857e6e8e3feffff
+fffefffffffbfefff8fdfeffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fefcfffefffbfffffffff9fffefffa577d4e276b183784243c90203d922d3b89232b6a0f
+69b670cbfff4cbfeffc0fff27cb9a73e5656201f24171916171d1915191a171612bcbdab
+fffdfffffefffdfff96c736b161c1a171c1f14151a1d1c213031353b3c36fdfef6fdfdff
+fefefffffff2fefff2fffeffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffefffcfefbfcfcfafffffda6ba9f255e172f801a3c922742982939942b3b8226246a0a
+4f8b4fc6ffeaceffffc1fef7a8f1d331564e2828302218201412171a1a1c333327f8fedc
+fffef9fffff7fdfff551564f171b1a1b1c201c1b201c1a1d1515175e6053fffff4fffffb
+fffff4f9fce1fdfce8fffeffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fefefefffffffcfef9f0ffea29541e347d23398f2241972844972b328f243c7d29397f26
+2f5e27a5eabbcafff3c3fff8adffd95a967c091c1620171a1511121d241c9aa78df0ffd6
+faffe8feffecfcffef454b411f21201e1f211c1c1c12110d151b11b6bea6f6fee6fbffee
+fbffe1f4fad6fffff1fffeffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fefffdfffdfffcfffa5e825624651536892146992d3a8d2145942b388f263b7d252e6b1d
+376525387e3fbdfed6bffeebafffd8a6fccd669e793a503b495f4a8baa88d2edc4d8efc1
+eafdcff0ffd9d2dfc3333b2e1b1f1e171b1c10150f171d0f697c5ee9fed5ecffdaf1ffdb
+eafcc8e1edc5fefff8fbfaffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fefffdfffdffced6cb2151173686253c922543942b49982f4392293c8d26347c19346925
+2e601726692263ad70c1ffe6baffde9dffc695edb09dd7a79cd4a398d2989bc08cbbcda5
+bfdda1c6e1ae90a4811c2717282e2c383e3c3f493e6f7c68abc898bddba5cceab8d3f0ba
+d4eeafc5d7affafffefcfeffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffefffffdfdfffffefffffffd
+fdfdfbfffffffffdfffffcfffffdfcfffefffcfbfffffefffdfdfffdfdfbfffffdfffaff
+fffdfef9fffdf7fffdeefbf1d7ded6d0d3ccd5dad4d4ddd8e5e7e4f4f9f5fefbfffff9ff
+fffefff7fff8fbfffffffcfffffcfffffcfffefbfffcfefdfefffdfdfefffffefffffffb
+fffafff8fff845713e2a6f1c36882241972a439a294299263c8f233b8c253e8a28337920
+35762428641a28611d6ca36286dba08de0a88ad7a380c2947bad887a9d7f83998297a490
+9cb0978d9f873d4a391017101c2021313534555b4d6f79607e98689dae8eb2c196b2c5a5
+9bb88289a269fdfffefffcfdf8fdfffbfffffcfffffefffffefdfffdfcfffffeffffffff
+fffdfffefdfffbfcfffffffffffef9fffffaf9fdfcf7ffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffdfffefffdfdfffeffff
+fcfffffbfffcfbfdfafffffdf7fffffffffafffdfafffffffcfffdfbfffff8fdfff9ffff
+b2cda07da7684d8b383d82273a7d2038791f32771a2a7614366b1d306c1436631e4e6440
+717e6a9fac98b9c1aaadb397b4c5a5f6ffedfbfff7fffffbfdfbfefffefffffffffefffb
+ffffffb0c3ad27591c347d233e9427439b2a3e9625439a294194283b8c233f8d28378024
+367a253b7a2b2d691f265f18235a17366d2a477b3b4e82425484485780465d8048678851
+678a5053753938551f2f491c2a3e221f31212f41354456485d6f5f78887e899c7e849d80
+53754262834ef8fffffef8fffffff8fffffdfffdfefffffdfffffbfffffbfffffffefdff
+fffffbfefffdfbfffffdfefffefcfdfffefdfffffff9fdfcffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffefbfffffdfefffffbffff
+fafefffcfffffefffafdfff5fffefbfefdfffcfffffcfdf5fafbf6edffe590c279418c25
+2c8614287e0f2d7c13357c1e377b243881273b8c263b93234d94363b9c1b419b2043852d
+235a17133d0d254015304f14315a1840612ac5d6b6fffffafffcfffffcfffdfdfdfcffff
+f8fff65272492b65193f8d27439c28449f2a429c2a429a2a4295293b8e243a8b24408c2a
+3e8529377b243475212f6e1d3f681a3e681c3c681b416d20447325427121477423527f2c
+4b7d1e4e801d53831f517f1d4f7923497226406923436c284e723553743b5c8036557f37
+3966115d833af7fff9fffefffffdfefffcfffffbfffffdfffffefcfffff7fffff8fefdf8
+fcfdf5fefffafcfffbfcfffffffefffffbfffffefdfffffaffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffcfdfcfcfafcfffdfcffff
+fcfdfffffdfffffefffffffbfbfffafffff3fffdfdfbfffa91be7b3a881b2a78152e6c1f
+285921325d27355e262f5a242958242a552a2d4a2b303f2a254923337e2340982842952b
+3a9129357c2c335d2d284c1e345c1e2f5019374826fbfffafcf9fffffefffffffdfdfeff
+c4e2be27571b3e8328449b28409e22419f2544a12e409c2d409629449a2d3f92283e8f28
+428e2a3b85243c832541882a3f7d273b7622366f1e396e204070243f6d22416d20467122
+41712741722344732242721c4879204b7e22497c1f5083264d8023477a1e497d1b52842d
+44751c567935fbfffafffdfffdfefffefffffefffffefffffefefffcfbfffffefcfffff6
+fffefffffffdfefffbf8fcfbfefffffffdfffffcfdfffffaffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffdfffffffffcfffbfbfdf8
+fffdfffffbfffff9fffffcfffefffff8ffffa9d5a044902c1b631130602e306227357a29
+38742a3a7427397424397126376b2b2e5f282b55232f54213051243c7b2c448e2d439229
+429d283b89242b531e1c30152437192e3f1f16220cc0c6c2fefffffdfdfbfefefcfefdff
+5f8f552d6a1c3c8b2246a22642a22444a22843a02d429e2f429a2a3f97273f95283f9226
+3e90244192294291283d8c2337892739852a377b28336b223364223963243a6023395d1f
+3158232f561f3761224270284374254273224475244073243f6e1d3f701e3e6f1e3c6e27
+3d6e1f486f2cbdd2b3c7d4b8b5cba7a8be97a5bb94c7dabaf0ffecf9fffdfcfffffbfcff
+fffcfffdfbfffffefffcfcfafefffffcfffffeffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffdfafffefffffcfffafdfef9
+fffcfffffbfffefcfdfbfffbf2fff87bae6c26661a235a202e6c213889223c8a25407b29
+4277313e7d2c3a7f243776253669273360293466273c762a459e2a419e2943a22e429c2b
+3f97293d8e2530691c223b1421291c1d25162a3026fcfffffafefffcfffdfefffbfefffd
+2c6a1d3a8327429a2941a12444a42643a1273f9c273b9825429a293b93223e9625409827
+409627409627409627449a2b3d8e2738822135751f376b233561223259202e551c2c531a
+35581e3d6423406c1d4a7d1e568d25579027548c2b4b82274d79204b791f497827407326
+42771f386d1533621a33621436611a3664193665153c691445701e628543abc69df4fff1
+fcfffdfffffffffdfffffefffdfffafcfffbfcfffffeffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffefffcfefbf9fef8ffffff
+fffbfffcfcfaf5ffefddffd54f9a352555193760244286213e931a4193253c8929338729
+3a832941843440793535672a326723377b243e972b43a8303a91282f841c389a213d9e2a
+39852a3d892e3982282f561f2c3c2115200fb1b6b0fffffffffffff7fbfaf9fffaceddca
+246d1337892348a5323ea02545a52a46a42c45a22d409d28429d2846a12c429d28409a28
+459f2d459f2d3f99273e982648972c3c842135731d35691f315d1e2c55192c581b305c1f
+386021427028447823548e2768a93164a92c5b9f265b9e2d629d2f55942149861f50892b
+4c86204b842347832b4582234d86274c88244e9022579d23569b1e4b8c144a841d4b8227
+cee7bdf8ffeffbfbfbfffefffffffdfefffafefffdfefdffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffcfbfefffbfcfffffffeff
+fdfafff9fff6c7edbc407a2d245b1a327b1f42982941972a45932e3e892a428b3143852e
+398a213879273269263273233e9223479e2b3c7e272a521d2437232e4821468729408e20
+295d152d671d387c27365b2524451034492afcfff8fffcfbfffcfffefffff4fff59eb797
+28751542982d41a02c43a52c44a32d45a22d429f2a43a129429d28449f2a3f9a25419e29
+44a12c429f2c429f2c3d9a273790243d8f2b3e822d336b222859182c5a1c316123316221
+3b6d1641761e4b862a52942a589f2560ac2862b02961ae2a5bb12a61b52964b13160a52e
+65a3285e99255c972d5a98295fa02a61a72b62ad2c5dae2b58ab2961b23169b93261b023
+618c3de7ffd4fcfffdfffcfffffefffffff8fffffbfffdffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+f8fffcfcfffffffefffdfbfffffefffcfcfefefefffffefffefffdfbfffffffefffffefa
+fbfff5b2dead236b15275c16378c27449b2a459a213c8d27438e33428d28408c2a418d2b
+427a2f336b2a399027409b24347a24284e252f3e2b244319264a1c326b26429b2d2f601e
+213919315724317f1c2e56222a3c12475d39fcfffbfdfefffefffdfafdf4fffbff619d55
+35831e469c2f44a12c42a1294aa43348a032459f2d43a22a459e2a449d29409b243f9d23
+40a32542a42942a12b419b2a3e932b3b862b326c202d5e1d2f5b1e336120386c24376d21
+3c711f437a1c538d274b8926569a2b65b12b66b92b63b72d66b9296bbe2e66b92967ba2c
+6cbd3268b62f5ea92867af3162b32864b72b67ba2c6cbf3169be2d6abf2c70c5326dc531
+67bc2962a12cf2fff6fffdfffffefbfefdfbfefefffdfffcffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffafafcfffefffffefffffffffefffdfdfffcfefffdf8fbfffffcfffffffafbfffa
+a5cd98235d112c5f264199284a9d354099213b9227479a32489430468d2d408b22337f27
+33751d479b2c3c792b254c172546172954292a602c335926315f2144952f2c6820203a1d
+23431a3c60323883262a4c19293b15445737fcfff8fdfffefffffffcfffafffcfe3f802e
+39932142a42943aa2744aa2a43a52a419e2941a0283c9e2344972d41972a439d2b46a32e
+44a12c43a22c46a53141a02c3c8e28397f273166202e5c1c316220336b203871223a7326
+3b721f4881224a86224a88235ca02f63b12a63b6266abe326bbd2d68bb2b65b82869bc2c
+67ba2c66b72c63b12961af2865b82a6abd2f6ec13171c6356dc22f69be2b6dc63071ca34
+77cd34569f1988b16ffbfffafffefbfffefffcfdfffeffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffdfffffefffffffdfcfdf8fafcf7fefffbfefffbfbfffafffefffffbfffefdf99ac88a
+1b5e112f6b214ca12844a033449a2b419928439b2a41962e438f2b438b253b852639832a
+4a8e29276319234920325d2836622539622a2d65242b6229408c28326f2a1e39162f4b25
+285326345230408029234719223215415436fffff8fffffffbfafffcfffdfefdfb398226
+409f2745aa2a42ac2643ad2943a72942a02845a029429d263a99233f9e2642a22747a72c
+48a82d46a62b45a42c41a02a3885253473242d5d1f2e5f1e356f22367b203a7c243d7826
+3f79244a87284b89244f9028589e2a64b12d6abd2f68bd2e6ebf326cbf2f67bc296ec330
+6dc53172c7366fc43368bb2d69bc2c71c4346ec33267bc2964bd276ac32d72cb3374cd35
+74cc2c6ec72d5ea427d9f1cdfffffafffdfffefffbfcfdffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fff9fefffefdfdfffafefffbfefffdfefefefcfcfcfefefef9fdfefcfffb9dc68a246219
+30792047a52942a12d459e28409d2a439b2d499e2740912841912e3987223e842e468630
+2e5622264c23347028387527386f2b387027376b233c7d2b317f1c1f37272a491f3b6124
+2a552a2e552643812b1e3d1e1a291235482cfefff7fffefffffdfffafffefefffa418f29
+3e9b2649a92e46aa2c44a92944a729439e27449b2a45992a38a21e40a32547a52d4cac2e
+47ae2746ae2548a82a409724367f252e681e2d5b1d356823397e253c8a243d87243d7d26
+44832a4787294687234e91275197235fac2a65b82c65ba2965b62b6dc03266bb2a68c02c
+6bc52f6fc9336dc63065be2868bd2c6fc4336ec3306abf2c6dc63073cc3471cc336cc72e
+6bc32371d5345ab6137ca85bfdfff7fffafefffffdfefffdffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffefffefffbfafffafcfffdfefdfffffcfffffdfffffffff8fff8a7d8971b6010377c1f
+4ba62d3ea62b429d26479e2941a52b479e2b45912f428f253c8f2340913442842d2e611e
+2553243a682a3f7e2d3270253c7b2c3778283e77303d85211c4412274626336526355a27
+32592a2e6722378223263724152012293823fffffafffdfefffdfffafffefffffd499732
+42a2274eae334aae3045aa2a3fa424409f27469c2d42932c35802340812f3d7a2a438f2b
+49ae2e42b12641a124429128397a282e661d3366233d772a3a86243e912544932a418629
+4184274687294587254f94295ba22c62ae305eae276dc03261af276bbc316cbf316ac22e
+67c02a6bc52f6fca316bc42c70c3336abf2e68bd2c6cc12e6fc7336dc6306ac32d6ec930
+70c62f6dd0376bcd2a4c8b19eefde8fffefffffcfffbfef3ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fdfdfdfbfffaf9fffbf8fcfdfffdfffffcfffcfcfcf9fff8bbe7aa1a611536831d4aa929
+45a72c429a2a46a52d499e2941a22142982d45903544902c3c8e2044922f28651824511a
+3574253d7d27427530387b2b327d223579244687371e4f17293f1b3167292f6124375f2d
+2b62282e622437851f243c1c1419121f2a1cfffefffffffffefdfffbfffcfffeff4d933b
+41ab2345af2947ae2b42ac283da323419e2940912b2c721a2d4829223b1d12350b236116
+3e9a2b42aa2d3e9c2c378426306d202a6418337221397f2633811c37881f3f8e253d8724
+43862546892c478a294a8e215298245da6305da92b65b32b5fac2a62af2b6ebf3671c436
+61b62567bc2973c83571c63365b82c65b82c69bc2e6cc1326dc23169be2d66be2a6bc32f
+6dc23369c5366fcc36539c17b2d1a5fffffdfffcfffefff6ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffdfffefffdfbfffdfdfefffffcfffefcfff8fff3d6f2ca1f6b103d7e224aac3142a924
+46a0254ba835469c2f48a428469b243d922d43992c47982f4a91312f6d181b4e153d6e2d
+3f773036822036791839792330742b36802b306f1e20311e38622336712f32642737672b
+26622434602b438b281b370f171813151c14efeef4fefffffefffdfcfffafff5fd6aa660
+3aa91c47b12948ad2d46a52d469e30408b303269261b411212240c1d3d14356c29499638
+3e9b293c992744993235802531692230711f3a85263d8e273a88223e8825418c273f8c24
+438a2444872a46892a478a204d9120589e2e66ad3764af2e64ae3159a62668b53170c039
+60b12863b42969ba2f6cba3064b42d66b62f69ba3163b52c61b42868bd2e6cc1326dc233
+66bd3065b62b65b82a61b2297eae64fefffafff9fffbfffeffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffbfffffefffefffdfffefffef9fffefffae9ffdd416d303982284ba9314aa62747a72a
+43a52c4299264da62e3d9d22428c2d439b2b3ea0273a921a46862f1a461535652b41792e
+3a862b417c2c3b7e2e32762b3778244a7f2f1e3b0d2b522535782b356f25317522365e2a
+3d662e346e243a862c22361a161513101612dedce7fbfffffcfffbfdfff5fff9ffb6e9ae
+349f154db031459d2c358620367a252a5c1f1c3517191e17264f1547893147a72a40ac22
+46a9284397283c8824347e1d3166223478213e9127409629438f2b468b2e428a273d8c23
+3f862044872a44852752952b5ea2314c8f254f9523569e205fa92e4e981b58a52567b430
+63b12a62b0295da92362ae2863b02c5faf2a63b32c62b22b62b42b67b93065b82c62b529
+64bb2c6eb92b66b12352a320599234fafff6fffcfffcffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffcfffffdfffefefcfcfffafffff8fbfff55b8d522a92154dae2d4da92d48ab2a44a426
+459e2a47aa2c3ea025448e2f469d2a479e2d3b912642972f255718335427387e263b8926
+357f203f7b31387f233c752e338b23315d2221341e357b233d7b2e30791d36732e337023
+377125337b253a882522391d181818131313c8c8c8fffffffffffffdfdfdffffffffffff
+58a04e2c851b307d17305d222c4619202a1116231923531943a22a43a92942a62a479f31
+439d2c3e9d2534851c3a73242d6c1b3a802744952e3f97273b95233e94253e8c263f8626
+398a2442892d437d30437b2056961c68ac315197235ea6285aa72367b43261af2559a51f
+529c216eb93864b02c519a27589f2761a82e5ca42661a92964ad2a67af2f63ae2f5da72a
+69b32868b4305caf2166ba304d8c19def6c4fffdfffefcffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+f9fff4f4fff7fbfffcfffbfff8fffb79b96b30931249ac2e42af1e49ad2947a22b419f27
+4dac344298294193274099254aa12e419a263e98273d7e2c2350173b702c3b7f2a3c8229
+3a81253e7e2a357e243f833037872623491a2a4b203a802a3a782b347d21397631387629
+3a74283479263c8826213a1d121212171717b8b8b8fdfdfdfffffffdfdfdfffffffefefe
+e1fdd7446e3e2b56202a48241f331a112b082456174b9d3746a42a40a5253d9f24419929
+3f982a3d9a27358320356d223a8027438f2d43962c439d2b439d2b3e9425418e2841882a
+3d89253f8223417824467a27447c17619f304e91205b9d2f64ac2f5ba22a64ab3367af31
+61a9295ba22c5da6335aa429539925579d2959a02a5fa62e5da42a5ca329579e265ba22a
+62a82b59a02860b02d69ba3949871ab9d49ffefdfffffeffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fbfefffffcfffff8fffefffbb1dda23c922344ab2642a6223da11b44ac234ba92f48a230
+47a62e46982c48932e47a8274aa32f3e9c2441992b335b262f57223e872d3c7d2b3d7c2b
+3d812a3c812436822743912e3877281a3516376a253c812e3776273a81253976303b7c2a
+3b782a3477273f8928223d1c1717171313139f9f9ffffffffffffffffffffffffffdfdfd
+fffdfdf9f9fbf8fffbe8f6e99ba3a51b3a1a47942c3ba423449b28419c233c9a223e9628
+3e952a3f962b39862839752b41922b4b9e32409827429d2847a02c419428418d293f8427
+3d812c3a78233b6e1f3b68253a6b294c832f468123437d2853922957992b4e902657992b
+599f2550942551942b579e265395294c8e22519528589c2f569a2d5296274f93225fa430
+5c9f2e4e902465ae3858a32d417b149eb984fcfdfffffffdffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fbfff6fffefafffef9dcf8d275a164e1ffd8f0fff3dafed88ec87b449f2a3da41f49a72b
+469f29479e2b49a02d47a72a45a02943a1293f852c2b4c1f407233388525397a263e7b2b
+40852c3c86253b8d293f952a2d5a1f1f381a3e842c3a7e2b3576243d842835752b3b8129
+3b7b27357626418b2a24441b1515151313138f8f8fffffffffffffffffffffffffffffff
+fffbfffffbfffefefffafefde4deea213421397f1f399121408e283e8f26398c22388b23
+3d8f293e8e2b368124387c274098274aa5303e9c243c97204199284091283e88273b8025
+3b7f1c438023467b1f366514305f19447a24558f284078153f751d569029558f2b4f8a2c
+518e2753932549881f519329508d264c88244c8a274d8b2a4d8b284d8e264e902456982a
+45841957942d5b9e2d4d92273f78177a955efefffffefdfbffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffdfdfbfbfdf9fff8e3f0dffbfffdfbfbf9fffaf7fffafff5fff4bef2b047a72a44ac21
+449c21479f2748ab2c46a52d419f25469e2d306120305b25458936357b23377c2340822b
+428c2b3d88293d95253a91282241182d4e213c8d2e367a25377b243f892a3376273a8727
+3b8027377528408a29254d1b141414161616656565fafafafefefefefefeffffffffffff
+fdfffefffffaf8fcfdfefffdfff9ff1d23192d5b1b377124357b233e842e40862e3b842a
+3c852b357b22307a1b3f8b2740a02546a62b42a0283a95203e92233f8d273c83253a7f24
+3d7f1e3871224c802e50802c33651c487d2f558d2c5b922c43751e3567104c8125487d23
+487e28508827508922578e314c812550872c4d832b497f274880254d8627508c284a871f
+49871c59902b4e891f4987243f7619627e44fcfffdffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffbfffffefffffefffff8fffffcfffcfffbfbfef7fffcfffffcfff9fff8b7f1a43e9f1c
+49a6244fa92e42a72743a92c43a129408a29254a17407a303d8a2a397a283b85263f892a
+4395293b8b2a3f98243989281d3417376826368c293879253b8428418d29347c283c9227
+3c86273a792a3c8824285a1d1818181414142d2d2dfffffffbfbfbfffffffefefefefefe
+fffefffcfdf5fefffdfffffdfffef82a302216360f3262242364142e6a22366f2a336f25
+3572252d671a307719469d2c44a92943a62844a22a3f97273e8f283c88263980243b8027
+346e242f60282a5520436c30406c2f2a581a36651d3e6d1d57882f3e6c24376618477721
+3e6c213d6b2046762244732245712245712442712148772748792740751d4b80264d8226
+548c294f81224a7d1e457d263c701b5c793ff8fdf7fffeffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+f8fffff8fcfbfffefffffffffafaf2fffefdfffdfffffffbfffdfffffafff7ffef91cb7f
+429d2644ab2647ac2847aa2b479f2e346c21295719468a353683233d862c3e8a2840912a
+4098273e91293f9928387e262133193a7b29368b243a7b29408e2b42902a3781283c9926
+3d89253d7c2d3c89233168241616161313131b1b1bfcfcfcffffffffffffffffffffffff
+fffdfffdfffcfefffbfffefffefffa4a55440c240a345f2a2f6e1f285b1926531a28581c
+336327316123367a2347a62e47ab2d44a429439d2b42952b3c8a273982263a8027367a23
+3668212b57182f54202346103d64233e6721325b19375c193965164e79342a5412436c26
+37601e31571c395f22385f1e375d20315819375e1b3f6822406b233864193e6c2147752a
+3c701e4a7526436e1e44762f39691d47642afcfffbfffeffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffcf9fffffdf7fff4f8fff9fefefffffcfffffefffbfffffffffdfffffffffbfff4fff2
+55a74338b01b43ae2249a127489b2f2b571a377125428b313681263e902a3e8c27429529
+3a972243972740992f36752424371b38842a3b8e243a7b2b42932d4190273884293c9b25
+3a8b223e7d2e3b8a2139752b1d1d1d171717161616b0b0b0fffffffcfcfcfffffffcfcfc
+fffefdf9fffffbfff9fefdfff9ffff737e70111f0e2c512540802c2f601f294f1c264e1a
+274f1d264e1a31752245a83144a82a43a22a3f97273f9029378223377d243c822a2d711c
+335c202c53142d4a1c2e48232e5014375a163c5d28334e232f59194f7b30335b1c335727
+3457212f521c2c4c1d2c4c1b30501f3455204063293960213a611e3b6420396321345e1e
+386a25426928355d17325f242e5d17345119fafff8fefeffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffefcf9fffdfcfffbfff6ff
+b6e0b032a41949ad274aa12c42892d235d10458c303e8028408c2a3c97223f8d27449a2b
+41922941972a3d9527346e24244018429430398b253b842a429a2c3e912939872242932d
+3d9028398c223687213e892a202e171514191717155b615dfbfffbfffbf8fffdfffbfffa
+fffffafefefffffefffbf8fff8ffff8cae7c10320f28421d4992362e871b2a5f192d5928
+2142172644222a521e3dae2a47aa2c3f9b2c3f912f41882c3983242f7b20327525316220
+245715274916293a182534171f371329481c30501e334f1c304e1c3f6029416829264f0d
+3a62232b501a2d4c202f4b252c5012385c1e385c1f37581f33541d32501e3654222f4c1c
+395a2130511c224411355d1f446c2637561de8f6ddfefeffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffefff6fffafffffffffffd
+ebffe847b03047a82549a22c387623306e1b479130418d2b43912b3b9124409128449a2b
+3f90274197283f9729336d2128441c43952f398b253b8629439b2d41942a3a882342932d
+4093293f92283c8d2744902e2c481f161618140f131f2521fcfffdfffefdfffdfffcfffb
+fcfefdfefffffffbfffffefff9fdfcb9d1af22471c233819439229419c25327122376924
+26511c243f1624391a418a2e48b52847a22d3d8b263a8624357b223069223264252c611d
+2f4e242c4a24223f202d4628253d1b1a300c233b172e4825233f0f2d4b17446629406522
+466b2831531732501c2d49193c5c2a2e4e1c2d4b192b48182d4a1c2e491e2843182d481d
+37561a4464254b6e2a395e192b4f122b461de4efdeffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffefffbfffdfcfafdfbfff8
+ffffff81d16e40a12049a22c30661b40852a48963043992a45982c3f8d27429a2a439b2a
+3d90264199294199292f6c1f2a491f42972f388d253d8829429a2a41942a398a2340912a
+3f952a3f95283f902944922f2c611d1618171d111d131716c2c2c2fffdfefdfdfffefffd
+fcfffffdfefffffdfbfdfffafffeffe0ebdb25571a2a401c3c88243d912232732131631e
+2b621f27411a1d2a163055224aaf2b439f233a8e1f3f8b29326f22335e26325a26215019
+2e4920253e17253e1729461a3858293855271f330e29361823371c223a1a29431c2c491b
+3754242b47172841172b411b2d472226401b2b452028401c263e1a28401c223a1628401e
+304d212f4922304a23254216244415314925f9fff8fdfcffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffcfdfefffffbfdfcfbfff8
+fff7ffc9f9bd3e9f1c4299283466214896304298293fa224439b2a438d2c46a12c409b26
+3d9024429a29419b2a2d6a1c2d4c2043992e3a90233f8d2a419b293f95283b8c25409329
+3d93263f95283f92283e8c27368124182313190d1b141615646265fffdfffcfefbfeffff
+fcfffffefffffffcfbf9fff9fffcfff5fbf9387a232b4913388125448a34317021274e22
+2d691f1a39171930131a331636752644962a39901f327822306424346224274e19274624
+213c1b20341922341a1c30151732111f3a191d2f1528312022302324352321331b1d3115
+24391a22351720331729391f21351924381c23371b2134181f3216223517243719213416
+1c35151a31171f321e2940241e3612586b4ffafff9fffeffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfafffcfffbfefffa
+fffafff2ffea45a9253b88223c7526489c2d409b2640a523409b2647912e47a22d3e9924
+3d9324439d2b429c2a2d6c1b2d4e1f429a2c3a922242902a449f2a3e96263f922844972d
+3d95253f9727429529398a233b92271b39131c171d1515171d1b1cfffdfffefffdfcfdff
+fdfdfdfefffbfffbfcf9fffffffdfff6ffff41892537611733861e49953a2b6c1a244621
+3064221e3d1b2a45221e32191b331b3668293c822a2f74232b641f376827274c19294225
+283b1b21381c162e181c2d1b212a192229171d2c151b311a1d29131e2c15202e15202e14
+1c2a101f2d14202e17202c161c2b141e2d161f2f1520301620301622321727371c25351a
+243d162d421932441a32441e1e2e13849180f9fef7fffefcffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffbfdfcfffefffdfdfbfc
+fffefffdfcf853b33531731b418b28459e2a42a22743a627409b2446982c469e2d3d9622
+419728429f2a409d2831721e2a4f1c439b2b3b952343942b419e293e96253f9528449a2d
+3e96253e982642982b3b8c233b932530651f0d190d161417191816909092fffffdfcffff
+fffdfefdfff7fffefffbfffffffcfff7fffb6ca755385f1e3a9820419a26347a22325b21
+21461a29451c293d2219251114181913241229511f2f6f21276617305c2128441b213c19
+253c122439181f331a253220232a18222a13212f151f3317252e1d242d1c212a191e2919
+1f2a1c20281b1f271c21291e1e2c151f2d1626341d202e171d2b12243219233319223218
+1d3115233316263319212b13263120e9f3e8fefffafffffbffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffdfcfafbfffdfffcfffffffb
+fefffffffffd5bb2412e671a44a22846a12a45a82a48a62c429d2645a029489c2d3d9423
+439b2a42a028429f2a387a232a4f1b449e2c3d982345972b409e263f9927409627429829
+3f99273e98264298293e91273f902a3d8b28133210151014141510272928fffdfcfafffe
+fffdfffcfff6fcfdfffffffbfffafffefffb97b38a1c2f11398322378a1e3c802b386927
+162f0f2440171f2e19171d0f1d1f1a1517121d2f152c581b32671f2d561e24431a27411c
+23351d1d2c19152113192519182617202d1c21291e12171110170f141b14131915121615
+161a191218161016141319151824101c2814232f1b202d191c29151f2c1a1e2b19162512
+152616101b13151918222423c2c7c0fcfffafbfdfafffeffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffefdf5fff8fff8fffafff7
+fcfffffcfff85eab4335692147b12947a52d47aa2b4aa32f449f2a43a6274a9c303c9223
+449c2b43a12942a1293d7f282a4f1b45a02b3d982145992a3f9e26429c2a419728409828
+429d283f9a2541992943962c3f8a2b3f9c272a55271e191d13160f121615736d6ffbffff
+fffafffbfff5fbfffffffdf6fffbfffffdfa5e5f59131418325d253e7e3028641a2a5d24
+22391c1f3e1e1e301a1b23181a1e0f1e26172b3721394e25395c222c591e2b5122213615
+24221345523e5973582e492a27371a2d321c232719747973939b8e878f84888e84838881
+7e847a7c8278747c6d5c645525301f2732211e2919232e1e1c29181f2b1d4854465c6a5b
+6374617c8874919584e8eadffcfefdfefffffffffffffefcffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffefffbfffdfff8fff9fffcfd
+fbfffbfefff661904838822147b12b41a8253aa02036a01c34a017339f182f9518399a26
+469f2942a12947a2233d8e252b531e399d29469e23439821459c273b9a263c9b27358e1a
+358e1a33921e399725439a273d94293e982641882c19350f17151a151219121713d4dad0
+fffdfefbfffffffbfffcfefbfbfffdd8bfc52e1018251214181f0d263a212a4526273c1d
+1f32161c30171b2e1a14201215251b2030162f4c20355c27365422374e203a3e1b3e220d
+601d0c7e4e387fd79b5b74563c3a23443923525d4cfffdffffffffffffffffffffffffff
+ffffffffffffffffffffffff68905c3554422e32312e352535381d575b4cfffcfdf9ffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffefffffefffefffffefff9fffffafffdfffffaffffffff
+fffdfffffcfffefcfffffefffffefffefcfffefcfffcfefdfdfdfbfffffffffffffefefe
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffcfefbfffdfffefffffffeff
+fdfcfafefdf8508d3d3d9b1f44a5224fa72f8dd073d0f9bfe3fdd8e0ffd5ade19764ac46
+3c992637a11946a2254093292c541f3d952d41992b489f2c33a11a3998204d9b3689ca76
+90cf7e77bd654a9c3633901e409925328f1c4a9c3a2b5d2015240d191514181119403a44
+fefffffefffdfffbfcfbfffdfbfffa8f585d50181b3517152212121a1a12151b11181911
+191911171a13181a171614150e1e14312a1a492b13622a137923147b1b0f871a179c131b
+a31919a1352b86c78d557e563741263c3e26b5c2b0fffdffffffffffffffffffffffffff
+ffffffffffffffffffffffff9bbf93477052353f343b402c35351dc5cbbdfffcfffbffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffcfffbfbf9fbfffffcfffffefbfffffbfffffffbfcfff8
+f9fdfcfcfffafcfff4fbfff9fbfffffcfffafdfff5fefffffffffdfffffffdfdfdfefefe
+fffffffffffffefefefefeffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffefffffffdfefefcfffffdff
+fffbfffffffa398928399e1a79b764e7ffdcfbfffdfff9fffffafff9f8f6fcfffaf9fff8
+a4e798499b2d3a9f1f43a02d27481b3c8d2e429c38389e1e428c1da7d29cf5fffaf8fff8
+fffffffffefff1ffec9bc97e3a9520399322379024478d341b360d1e111a1e12200e1712
+818284fffffbfffefbfbfffffffdf18d2f3072121349161239161c2a16181f1315201418
+20131a1812161914181f141a231417400f126e16149e1a18b8181ab21619ad1416be151c
+d7121cc51d1d99bf825c95603b452a525540fbfff6fffdffffffffffffffffffffffffff
+ffffffffffffffffffffffffc5e3c1558a5e3e50383f432864614efbfffafffdfffbfbfb
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffcfdfffffafdfffcfefefffffefffffffbfefff7fefefe
+fffefffcfbf9faf8fbfffff8f7f8d9eeecd5fff9fafffbfffefefcffffffffffffffffff
+fefefefbfbfbfdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffefefffcfcfafffeffffffff
+fffafff0ffe831861f7ac465fffffffefffafefff3fdfff4fffbfcfffbfffffafffffffd
+f2fff4cde9c03c9e273ca31e324e263583203fa132319c1ac4e5b8f5fff1fafcfbfffdff
+fffafffff9fffefcfff9fff3cefac54c9738309012499d2e3b6b2d1b2d170f160f131a12
+19141aafaba8fbfbf9fefffff1dad49315168e14116016133f1312321613271815241518
+1f13171814151615111a15111910113d14186b15149e1713b50f0fb11113b51b19bf1112
+da0f13d31614a5af705c9c5f3b3b239b9587fffffafefdffffffffffffffffffffffffff
+ffffffffffffffffffffffffebfeea67a76a415b36373a1bc8c4b8f9fffdfffefffffeff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffcfffffdfdfbfffdfffdf8fefdfffcfcfff8fffffdfffcff
+f8fff9c5d1b9ebffb9daf58eb8ce7cadb989b8bda6fcfdf8fefefcfefefefdfdfdfefefe
+fffffffffffffefefefefeffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffdfafefdfefffdfefffa
+fff9ffd2fac83f882cf4ffeafffcfffffefffdfdfffffffdfffff8fffff8fafff9f5fefd
+fdfafffffcffa2de9630980d2b531f3e84243096179ad488f7fff9f8fff8f9fff8fdfff7
+fffffaf7fef7fbfffdfefffffefffdf4ffea6da858248b083ba12228641c182a14151611
+1c131815141297989afff8ffc48e8ea212129a16117218184c17133a17112b1613241415
+2115171b1a181819131a17101818163213186115159b1712ba1615ad1416a71313c11515
+d31715dc1a11af975b5a9f5c46412bede6dcfffefafcffffffffffffffffffffffffffff
+fffffffffffffffffffffffff9fffa72ba6e3c572e68684cfffaf6fbfffdfcfbfffffbff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffefffdfbfcfefbfbfbfffffbfffefffffefffbfffcf4fff0
+4e883e3e7e1eb9faa09fdd945c9a4d5994405c943b7db44efffffdfffffffffffffdfdfd
+fefefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffdfffafcfdfffefffbfffffa
+ffffffabe2a14e7c3efffafff9fffffffefffff9fffffcfffcfffffbfffffdfefffffdff
+f9fefafffcfff8fff368bc4c2461142e6c1956af3bfffefbfffcfffffcfffffcfffff7ff
+fffbfffffefffbfefffffefdfaf9f7fff9fffcfffa89ca7a2f95163b91243562291e311b
+191c1112171013141872676d822b31af191a9b17127b161a59181c4214163113152b1218
+27141a1d14191814151d1415101d16271416581617941713af1112a91c25a8272cae1517
+cd1714e0130ebf764963a661666b55fffff8fefffdf9feffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffd90da853c522ecdccb7fffdfffefffdfffffffefeff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffefdfcfffdf8fffafefffbfff9fffefbffcee9c8467f2e
+3e9a1d52af3a5aba3c3e9f1454b1245db427479617377a19e9e9e7f7f7f7ffffffffffff
+fffffffefefefdfdfdfefeffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffbfffcfffdfffffffdfcfcfa
+fbfdf87daf729dac99fff7fffffefbfdfff9f9fff8fbfffafefdfbfffdfffffcfefdfcfa
+f9fff8fffefffff7ffd1ffc92b7119205e13b4eda6fffafffffefffafafafffffdfffefd
+fdf9f6fffffbfcfffdfbfffffffdfffbfffdfdfcfffffdffdaf6ce4f9d3842952d326723
+19371114211015131617140f8b1c22b61a1b9814107d14185914194412153414152d1418
+2714181d141918131720151b2824215a40497f3e4492211d961414bd5e64e49c9dc16860
+cb1b1be61211d25537669859aab29dfbfdf8fefffffdfeffffffffffffffffffffffffff
+fffffffffffffffffffffffffffdff8fd87e6b7b61fdfbeffffefffffffafdfcfafeffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffefffefffdfbfdf8fcfcfafcfffdbcd7b63577203fa01d
+4eae264bab2549a6244aa3254794243c792b305c2751783ffefefcfffffffffffffdfdfd
+fefefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffbfffffff7fffffefffffeff
+fefff8557d4beee8f2fcfff8fcfffffefdfffffdfffffefffefdfbfefffdf9fffdfbffff
+fffffdfff9fffffdfff2fff85a9b47185c11d3f0d4f4fff4fefff1fffdfffffcfffafff9
+fcfffbfffcfffffcfffefff3fefffffcfdfffffefffff9fffffeffeaffe4448a31349b14
+346a2e24381f201a1a181a0d94191bb21212a11b1880161657171843161133181128150f
+2217131c1b17171715191516323c345b52559367687d20188a1d1ae4949dfbbec5ed9999
+c52321e91416d134234f7037e0e1d1fffefdfffefffffeffffffffffffffffffffffffff
+fffffffffffffffffffffffffffafd599e43c9d5c1fffffafafafffffff8fffefbf8fdff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffff8fffffffefffffafffffdffe4fddd41822e3ea12343b426
+49a633429d283b91223c872c37702b2e571f264013c2cfb1fefefcfffffffffffffefefe
+fffffffffffffefefeffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfbfffffdfbfbf9
+fffffd979795fdfdfbfffffdffffffffffffffffffffffffffffffffffffffffffffffff
+fcfffdfff9fffcfffaf8ffffbbd6ad115114aeb7a6fffbffffffffffffffffffffffffff
+fffffffffffffffffffffffffffcfffdfefffbfffafffffdfffafffffffde8fddc598645
+34922032712028441b15321c321f198b18259b0f188718115b151d491217371412281914
+1f1a162213162211171b161c3636364e4a4b82646275292b90333becaeb3f8bdc1d26c77
+c71815e31311c6251b4a4734ffffeffefdf9fffdfefffefffffefffcfdf7fffff8fffefc
+fffefffffffdfbfdfcfcffffebffdc829076fcfff6fefefefffefffffefffefefffdfffe
+fffffffffffffffffffffffffffffffffffffffffffffffffffdfffbfdf8fcfffbfefcff
+fffbfffffbfffffefffefefcfffcfdfcfcfefffefff5fff351953e389d1b44ab2843a628
+439b233a8c26357d27346c2131571e2235174c5244fffff6ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffefefcfffffdfffffdfffffd
+fdfdfbfdfdfbfffffdfcfcfaffffffffffffffffffffffffffffffffffffffffffffffff
+fbfffafffafff9fcf5fbfffdf4ffef1954128d928bfffdffffffffffffffffffffffffff
+fffffffffffffffffffffffffefefcfefff8fefff6fdfcf8fffcfffbfafff7fff8e8ffe2
+4386372f751c3f7925336528144817452d138517186a0e0f5319184f14163d17162d1513
+2910132115171919191d14172928264a46477b6162894447c67079f3b6bbeea8aaba414a
+c90e1fef1a14c0160967353efdf6fdfffefffefffaf8fffcfefffffefffffefffffeffff
+fcfcfefffefffffffffbfef7deebd7e7f2e2fefffafffffffffefffdfbfefffffdfefffb
+fffffffffffffffffffffffffffffffffffffffffffffffffffdfefffffdfbfdfaffffff
+fffffffdfdfbfefffdfdfffcfefdf8fffcffefffee5a98453a85204a98353d922b3d9024
+3f8626387d24336d2328531e233e1f0d1b0cc1c7c5fefeffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffdfffffdfcfcfafdfdfb
+fffffdfffffdfffffdfffffdffffffffffffffffffffffffffffffffffffffffffffffff
+fbfff9fffbfffdfef8fefffff9fff9508042747879fdfcfaffffffffffffffffffffffff
+fffffffffffffffffffffffffefff6fcfef3fffff8fdfcfafffefffffefff9fdfefbfffd
+fffdf357864f217216427d2b2e662521511f55321c851917581212461612391614341115
+2b10152216181c181718141323221e504a4a836a6e90575de79ea7efb3b5de8889b01d23
+d91521ee1617b7120c6c1921d3decdf9fffffffffffdfdfdfcfdfffefffffefffffdfeff
+fefffffdfefffbfbf9fffff8fbfffafefffdfefefcfffefffffffdfffffdfefffbfefffb
+fffffffffffffffffffffffffffffffffffffffffffffffffefffffdfdfffffffffdfffa
+fbfffafcfffbfafcf9fffffffcffffd1e6c746862f3c9a20409128397b23387824306e23
+2e65222d5f1a284d17253e21101d13525952fdfffefefeffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffefefeffffffffffffffffff
+fffffffdfdfdfdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fdfff9fffcfffffffbfefcfffffeffa0c4985c615dfffffbffffffffffffffffffffffff
+fffffffffffffffffffffffffafefdfffffffffdfffffdfffefefefffffdfdfbfcfffdff
+fff6fff8fffa5b8458265414323e181b27191926125f3016621616431610311410301315
+29161824141522141419151224241c4f46477d666cba8891eeafb8e6a8abb04e4db41114
+dc1512e21114ab1d1b73220f4580249bc289fdffedfff9fffffff4fffefffcf9ffffffff
+fefff8fafff6fffffffffdfffffffffbfbfdfffefffffdfcfffffdfefefcfefffdfeffff
+fffffffffffffffffffffffffffffffffffffffffffffffff9fffdfefcfffffdfffcfef9
+f6fdf5fefffffffefffefcffd0e8d22e761347a92041a0283b9229387f1f376d222d5d23
+295323214515253b15212d191b2117d9dcd3fffff8fffcf9ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffcfcfcfffffffefefe
+fefefefffffffefefeffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffdfcfcfcfffefdfffcfffffaf8ecfff074786afdfffeffffffffffffffffffffffff
+fffffffffffffffffffffffffdfefffffefffffafffffefffffffdfffffafffefdfffaff
+f8fffff8ffff9bae9b0f330d2635201e171e101c1a2230195028204b19183815132b1716
+2a141626131521161422141329261f4b41427e676dc3969dedb0b8e8aaafae4e4faf1316
+d81415e1191b941411783d1564c92f56a41a89b057f6fff4fffefffffdfcfffcfdfffdff
+fcfcfefcfff8fbfdf8fffdfffcfafdfffefffffefcfffffdfefdfbfefefefdfefffeffff
+fffffffffffffffffffffffffffffffffffffffffffffffff7fffbfffefffffcfffffffb
+fefffdfffcfffffafffefffa50963d43a62745ad24419f253e9a2b3884293870252d5f16
+28501e213f1922341a1b250d535a48fbfef7fffefdfffcfbffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfffffffdfdfd
+fffffff9f9f9fffffffefefeffffffffffffffffffffffffffffffffffffffffffffffff
+fffcfffcfffbfdfcfafffefffffcfbf8ffffe9eddefeffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffbfefefefdfdfffffffffdfdfdfffefcfffffffffeff
+fcfdff8591851a3b201c321b122311142b1b12140f1b171627291b3a1d194514183b1417
+2d15152617142416152113121b18135041448f7479ae7d81e3a0a9fcb9c2ea9598af3134
+c51518cc0d1596151a78531c62d02370d12c65b82072b951f2fff9fbfffafffbfafffdff
+fffefffcfffffbfdfafffefffffffdfffefcfdfcfafffffdfefefefffffffffefffefdff
+fffffffffffffffffffffffffffffffffffffffffffffffff8fffbfffdfffffdfffefffb
+fffefffdf2fffcfffaafcea233a21545a02747a52d41a5293f962d3d882d3b7d252d6617
+30591d2b492521331d1e2e1347573af6fff2fffefffff8ffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffdfdfdfdfdfdfffffffdfdfd
+fcfcfcfffffffefefefafafaffffffffffffffffffffffffffffffffffffffffffffffff
+fffcfffbfffdfffffbfdfefffff9fffbfffffffffbffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffbf8fefffbfcfffbfefffffffdfffffefffbfffff2fff8
+4d62591a261224371b1820111d1d131d2a18171b0d1a1112101d141d1c17391718411316
+3216132c17142a14161f13131e18185c4c4f947678b37d7db3686fefa9b3ffc4c9e18588
+ad1e1ac4151c9d17206355146dcd2e6ec33471d12963c9277dbb4ce6ffdcf7fffffefff9
+fefff3f9fdfcfffefffffefffafaf8fffffdfefffffafbfdfefffffdfdfffffffffefeff
+fffffffffffffffffffffffffffffffffffffffffffffffffcfffdfffdfffffdfcfbfffa
+fdfefffffdfff0ffe648922f3aa420469c2d499f32409f2b3f92283f8926367b20356e29
+2b511626421a24381f28421d2c4d1888a674f3ffedfeffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefeffffff
+fdfdfdfffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fff9fffbfffffefffafbfffdfffafffbfff7fffefffdfdfdffffffffffffffffffffffff
+fffffffffffffffffffffffffffdfffdfffcf9fffbfcfffffffdfffffcfdb9c5b92b452a
+14320e1b3a112435151c2b18171d19151419161f1e161616101a191419151f1a14331a15
+3f13143213112816162815171c1618635054a78886cc908f924046ca828efbc2c9ffbdc1
+d7625bb6180d9716115a602061b22f62a62d75c92971d03666c1265fa21eabcd81fbfff4
+fafdfffcfffffffffafffbfffefffff8faf9fefffffefffffcfdfffffffffcfcfafffffb
+fffffffffffffffffffffffffffffffffffffffffffffffffffefffffcfffffffbf8fff8
+fafefffbffff8bbb7d329d1146972e369328388e293f8d2040941b38862037732b285f1c
+2a4a1828411a29402327481b366517528328a8c78cf6fff2ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffcfdfefcfdfefffffeffff
+fffefffffffbfcfffbf8fffbfdfffefffffffffdfffffefff8faf771806d102b08204416
+284c1e203f161c34141f2e191d2518181d16151a13151a131217131b1a15161e11242f1e
+322618381c112f16112b171927140e6d5054b68c96d49ca5954a4e842b2ff9b1b5fbd4d5
+fd99a1ba2832851e0b5475264d912469b22f77c2345db7245ba63069c02364c41c80c260
+f1fff7fcfffffbfffffefdfffdfefffefffbfefffffefcfffffefffffffbfffefffdfeff
+fffefffffdfffffcfffffcfffffefffdfef9fdfff9fefffafffffdf9fffbf7fffbfffdff
+fffffab9dfb040912a3fa71c41942a3a8b243882213a7c243a7427376c262e611f245617
+2e41252c491b325c1c3d7126437e2a498b2958a42a69bd31b9e29cdffccef7fff4fcfdff
+fffbfffffffdfcfffdf9fffffcfcfffffefffffcfcfffefafffffbfdfffcfffffdfffffb
+fffefffbfffff8fffffffaf9fffffbf8fffd
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffdfffefefefafffcf9fffb
+fffffffffcfffffcfffffefffffafffffffdf4fff09ab3962c4b2912320d22401e243d1f
+24431a233d1a21351a1e2b191a2217191e17181d17161b15121b1818171222261722351f
+26321e321b13391213301317301712714a4dbd9097d5acaaad625f96141ed05a66ffd0cc
+ffb8b8bb3d496f33115c923c4a872a477d1d53861d5da71e70c53272cc2f73c9286bc11e
+75bd3de9ffd4fdf9f8fffff8fffff8fdfbfffffefffefef4fffffafffdfcfffef9fffffb
+fbfffafcfffbfefffdfdfffefefffdfefffdfefffdfefefcfffbfffffefffffefffafffb
+d7f5d13a7a2449a42d40a5253d9328388922337d1e32721c2e661b2e5f1e2d591e29541e
+2b531f2e5f1d38721e427f224282244286214a972557ac2d52a52356a42d64a7407eb759
+9ecb76b3d78fc7e2afdaf0caf4ffeafafff6fefffffefffffbfffefbfffafffffffffcff
+fffefff1fffbfffcfffffffdf6fffffffdff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffcfffefffffafff9fbfffb
+fefffffffbfffffbfffff9fffffeffbec6b9435e3d1d49142c5e2324511a24481c1e3916
+1e37191f33181e2d1a1b2318171c16191b16191e18181d17151d1f15140f222f1b193819
+1b2e18271e17381a1a3d13153c1a1174363bcd8c92dda6a1b0514da00a13ae1c26e27878
+d25654a616207c5d1a64a434498627417b2659913a66c33663b2326bc62d73d02a6ecf20
+69cd1d68b032f1ffd9fffbfffffcfdfffdfffdfbfefffff8fbfdfcfffefffdfdfbfffefa
+fbfffbfafffcfafffcfbfffffefffffdfcfffefcfffffdfffefbfffffafffffefdecffe4
+44883336941c3fa2233d9c2640952d3c8d2737802434742032671f326020335c22325924
+2a6219336e1e3d7c23437f273e7a243c7b22448b254f9d2d539d2e4e9d2a4da62855b628
+5bbe2355b41c4da4194e9d204e8e1e639c357bae5298c374c1e5a8e8fddcf8fefafefaff
+fffef8fefefcfffefffffcf9f8fdf6f9ffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffefffffcfefdfefffbfffffd
+fffefffefdfffefffbfcfff36b86652040191a3f13254f1d3e6b3438632b244b14254a14
+1d2f19182615141e13161b15191b18181a17171c16181f181a1e1f1919111e3d1d174018
+1c240f1c211a24271e41181258130e7722259d41469a3334931614a91a16ad1313ba151b
+c417139e0f09929e3074b6324f8c253f77203d64214f9429569a355faa2b6bc62d72d53c
+6dce3167c6246dab40fafff5fefffffffff6fefffafefefff9fefffbfffffcfffffffeff
+fffcfffffefffdfefffefdfffffdfffffdfffffdfffffdfff7fff3feffffbdccb7478230
+46a62841a52740992b3e91273b8b2a388525377d24357622356f22376c24376a25356624
+386e223770233a7025376a2732632135691e4181214e98294ea32151ac2955b93257c332
+59c62f5cc62e5dbe305ab62f4eb5254daf244fac2050aa144fa60a58a0168dc45edfffc1
+fbfffffffcfdfff7fffcf9fffbfff8fffdff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffcfffffdfdfffffcfffffcff
+fcfcfef7fff8b7d3ad3e632d215e1033682234612615390b24431a2f4d2726451c224318
+1d281a192018151a14181a17191b18161b15151c14151f14181d161c20121e441d265423
+222b101d281a1a311d3832186f18117a131491181d9d1519a61816ab130eb61210c8181a
+d81416a6311d89c23f7dbe3c5c9b33548b2e2f4312365021467f215b8c3067ad3369c830
+6bca2e67bd2868b62f7bbb4bfcfffafcfef1fffefdfbf8fffefffffcfffafdfef9fefbf6
+fffbfffffefffefffdfdfffcfefffffefffbf2fdece0f3d7a9d19f577b4f1e530f429926
+42aa213a97223b88283c83273a8329378027387e263b7d26397b243a7a24397b24377922
+3c7129366b253065212e611f2d601b326c183f86204f9e294eb0254db22851b52e55bb31
+57bc2e59bc2b5cbb2b5bb82954b83157bd2b5cc52a5ec92b61d0345ecb325cc12568c627
+a9ed80fdffeefdfff7fffdfffffffbf6faf9
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffbfffcfffefffffbfffefdfb
+f5fff08aab7e295d15306e183b7f1c37731b32641f2b4f1f1a3115142515101b1317221c
+191e171a1f191a1c19181a17171916151c14131f111422111c2b141e2c1520431b36682d
+244413202e152034192d4e21664927881b14a011159b1514a91717af1412b61914c51515
+da1310af472281cf4571b433569b305d9f314368231b2b0e263d133c651f4a8022539321
+56a61f69ba3171c23748aa07cfe2b5fcfff8fffafffffbfffdfbfffbfdfcfffffbfffcff
+fefff4e1ead9b6c5b08f9e8b6c7b684d644739602b31661e2a681d266b103e922347a72a
+42a527439a27317b1a357926317520327621377824397b24377921357a21347b1f30791d
+346d26306c223170213676203b7c203e851f4595264ba22d4ea7294da6264da8274eab27
+4eae284baf2949b02b46b02c4eab274ca62a50ab324cac3149ae2a56bd2e61c52f61c129
+60bb1e74c72de6ffc0fbfffffffafdfefff6
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffefffafdfbfcfffffdf5ffee
+6c915d2c62143b7c20458829407c243b702230591f2c4621192815161d1617181c1a191f
+161813181a17191917171916151a14131e101827141e301a28441b253c1f214118356e2a
+2a611d223d14293f1b2c57214670307c4325971c1499140fa61615ab1715ac1210c31717
+d01b10ae401d76bb3e67a22a54902c5a942457912d2c3f111d1a21203d0f3e6522476b2b
+5d943769b43563b6285fb92699c882f0fff3f8fffffeffffc7d2c19aae8972885a51623e
+36462b233819162d1016291316271417320f295c1942892d418f2c4aa32f48a72943a129
+4ca73249a22c40932730791f2f701c306f1e327120367323367323367524357624337422
+346f1f357521397d263e8527428826428825418c2740912a41912e44972f469a2b439a29
+439a2943992a41972a3e94293f99283f952647972848972a408f24408d234b94294d9228
+4d93304b9f168dd06fe8fae0fffbf2f4fffb
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffafffffdf9fff858774e
+2e64183a7e1b478b28448529376f282f5c231f3d1716230f1d2019191a151b1c16191a12
+171916151513141412181a15181d161621111d2f192e42272c511b2a44211841152f6f25
+3c762929541e3354293b5623326c224f6f2e7f351aac13159c1210a91b1ab91015b11614
+ca1317b728205e852c548122527c3057862a48972a44662912140f1d1d1330441f2b5817
+3d6e1d51901e66b52870c23263ba1d66a72f5276392f47272e4f1a2a55101c47121c411f
+1f32141e32161e32191e2c1d1d271e1f361a2a5a1c377e22499d2b409d283b9823419825
+469f293b9d2445a42e3f93243d7d29377723357020346d20346c21376f26376f28356d26
+3971183876203a7b273a7b293979253977223a78233a7a243f85253c842138851f378822
+3b8926388125387d243c7c25308021367e2a3575273879273e8122377d1b367821337128
+396727305e13448833b9e8c8f6ffeefcffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffdfef8fffcffa5c99d245617
+39662143781c4672272a53191e261b1d241c1d221b1a1f19161b17131512101211161817
+19181e333736394039151c15181f17182615233e1b244c1a2e492818380f2f5a242d601e
+3368203c71293c6e293c6a2940622f38712c5062267d311aa01413ae1613a9160fa61414
+b5161ba61e22384b1d405d2554722c5a8b32498b2748842037452c15150d2321221c2f13
+2a4f194c831d62ad2e6acd346bc12a55942b1c430c2b4623314e1e2c4815293a1821271b
+1e26171926141b2a171d251a1f211c1e2b1a224819377029388d253d9527419c27469d2a
+4296274194283c942444a12e489a2c37851f3079203272242f6d24316d25337022316f1c
+30701a33711e367121346c21346921346722336621336621346b27366e27357225367524
+387824387925357521306f1e2f691f2f6d243272282d6b1e2d651e3060242a5122254a1f
+25441b20391923362249564cbdc9bff4fff3
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb6f96612b5c1a
+3c64253c681d3f5e23223b111318111217101a1f191315121416133739386d6d6da6a6a6
+f6f5fafafcfba8afa80f160f1c24191f2e1b29442129511f27461c20451238662830641c
+356b1d42782a3d6f2641702a4b84254b761d3c71213f5c24752d1ea60f14ab1016a0171e
+a2130d9a3a106f9e346792295f82246895385b943347761681a064a8acad201c1b121816
+1a31153a5b224f82265196225ba22c43772525441b31482c28421d1f3a111b2e121d271c
+1e26191724121827141822171b201a1a251719371328551e3576223f8a2b42982b419928
+378d1e398a233b8924388621429124408d25387d2032721e336d20346d20346d1e366f1e
+336b22336b22326a213166203063202e611f2a5a1c28561827541928581a2b5d1e2e611f
+2d611f2c601e2c5f1d2d601e315f1f2b5c1a2b601a3166222f601e2a5617274e19204319
+182c110f1e093b453aa2a8a4fbfffcfbfffb
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffefefff8fff1406a2a2e6017
+385e213b5f2140522a29311a12141117191631333071716fcacacafcfcfcffffffffffff
+fbfbfdfeffff5c5e5b10150e1f271c1f2e1927431d264c1b284d173760243d6c263c7123
+3d74213d72203d6d213b69204b822e4f86324a752e3c68293f61256d411c911e178c131c
+941318995f16b8f653bff94f9ed44083ba3a68ad384f86214f842af4fff5e9e4ea4b454f
+12161719251b22370c36502041701f36581c283c172f3f22243a14243f16243a161d2d13
+1d251a1724131726131723151c211b1b20191625101934132d541f3b702c357e25368824
+388a263a85283a7e273b7c28317a213379232e6e20316d25356c292f63252d5f242f6126
+325f262f5f232c5e1f2b5d1e2c5e1f305d222c5721274f1b26421924401722411824421c
+24421e243f1c213c19213b18223d1c22401a1937111534121a3a151d3c131d36180d2213
+2a3129818680fffffdfffefffffefffcfafd
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffff8fbffc9e0c32b5a12316417
+345f18365d1c30471b2f3626848484ccccccfbfbfbfffffffffffffefefffffffffefcff
+fefffddfe1de1719161f221b1a22151a2912213b162d4e21325a1e3e6b2a38671f3b7020
+3c711f396c1d3f6f23406e25476f28587a30537e2f517e2b638d2b7baa388e98378f5317
+7b2914af9936ccff52c3fc3eb7f842a3e23c7ec93b529426397b1a92b478fffdfffffbfa
+9d97a33737411619101312171d360e30411f212b10232d1428381d293e1f2b402126391b
+1e231c192416162413142012191e181b1d1a171c151b23161a28112a46202b5b212a6721
+30702434742636752637762531752036772335752137722230661b295c192c5c1e29561d
+294d1f294f1e27521c28551a2c591e2f5a242d5320284c1e2d3e1e25381c1d2f17192a17
+1b291a1c281a1d281a1f271a1a2b182e3c2d606e616674674c5d4d4d5b4c404644868690
+fefefffffffffdfbfefffdfffffbfffffdff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffcffff7da173275b11386b1e
+3c701d3d6c1b2d511445553bfffdfffffefffffefffdfbfefefefefefefefffffffefefe
+f8fff561665f11130e1a1d161c2415223218263e1a28441c2f561d335c2037662235671e
+36691e4070263d6b23426f2a4f6d254d7628517329617b316c943375a92b90b935a8c449
+a19b3db3c245b5dc43afdf3ea3e637aee83b99db465c9a2b4589264d7f1ef3ffebfffefb
+fffcfffdfeffb6b8b74a44521116191516181212101618130f160f121f161e2e23142417
+151a13161e13162214131f13161b151717171513141614151a1b150d180a13270e203d1e
+2b50252d5c262d66212d6e1c306c262d661f2e681c376f2434672228591827541b244f1a
+24431a26471c274b1b29511c2b541c2b531e284f1a24491626431726451b25431d223d1c
+1f3a1b20371b21351c21331b1a320e2a39226f7a6cdde6d5f9ffedfcfff6fffefffffaff
+fffefffffffffffefffffffdfffffdfffdfe
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffff8fffa3f723034681d45752b
+4a7e294e832b39671e4d6740fffefffefcfffffefffcfcfcfffffffefefefcfcfafffffd
+c9dac7121d0f1a1f181a20161c27161d2f15223718223a18264b172e551e3a6327376423
+35641e3b6a243b68253663203c6e27466e2556762b5c7c335c7d2c718c2f839f3981a13c
+91ac37adbe4ba5ba45a2c841aeeb45bdfc4d93d3415a9930549628437d0f91b16efcffff
+fffefff9fdfcfbfffffbfcf7cac8d39390978f8d909999998587866a6e6d515a553d473f
+3f413c3e433d3e453e444b44565b57747474918f92a49fa3a6a4a5a2a2a2787d79394039
+192517142d10204718285c1c2c5529244f21214d1a25511c29541f234a1b1f441922441f
+28441e29451d2a491f2b4c1f2a4e1e2b501d2c531e2f561f2a5f192f6720336b24326925
+3165232e602129591f24511a284e1d1f3a171b2a1322301968785de8f6dcfcfff4fffaff
+fefffffcfefdfefffdfefffbfcfef9fefffd
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffdef1de2d6d1739701c3d6620
+3664194170223c6c204f6d3bfffdfffdfdfffffffffefefefffffdfcfefbfefffbfbfdf8
+465f4210210e1820151f251b23301e1e30161b2e1225381c254516315321335920355d1f
+38622233601d406d2a35621f355d21466f2152842557842763812b758a2f7f983389a23d
+8ba13c98a2428da43c98c03ca5dd3aa1e63e7ebd3b589035609a2c54922748791eeffdec
+fffffbfefffffbfffffffff4fffffbfefffafffffbfafbf6fefdf8fffffafcfdf8fefffb
+fdfffcfffffffefffffdfffefafefdfdfffefffffffffefffcfcfefffffffffffffffeff
+dad8d97577722f3d2c10290c1a3212203a1727431b203f152140142a491f29451d264019
+203e1a213c1b233c1c263f1f26421c26471a2b531e335e26357326377826397b24397b23
+387a223777233370222d691f2c5f272d561e27461a223c1f193c12395f22dffbcbf8fff8
+fffffffefefefefffffefffdfcfefbfafcf9
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffaec6ae29710e41781b476c27
+375f20345d1b3661194c6732fffffffffffffdfdfdfffffffbfdfafefffbfcfef9929790
+12310f1d301a1924161c241924311f1d2f1523351b28361f2946182d4a1a345721355b1e
+3d652635621d3d6a253867213e54303e5b214e702453792e5680346c933887a83797b539
+98b0408e9f377ba1309ac844a9d6477ebb3065952f4e722a52852657992d3d751c8ba66f
+fffefafffefffefefffffef9fffffbfbfdfcfefffffefdfffffdfffffcfefffdfffefbff
+fffffdfffffffffdfffefdfffefffffcfffdfefffdfcfefbfefffffcfffdfcfef9fffffd
+fffcfffffbfffffcffb4b4b65660572e3a2e212f1e1b2e1a152812172b12172911192b13
+112e0f132d10172e141c30171a331518380f1b46112353192a631e2f6c1f3676223a7b21
+38791f36741f347123356f25326f2a306610366217305a2a336624447e175d9034e1ffd9
+fffefffffefffdfdfffdfdfffefffffefefe
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffdfffbfffdfffffbfffcfffcfffffcfffffffdfefffeff76aa62397c1b408727478824
+4d8427417221345e14456131fffdfffefef6f8fff9dbe4df7f797dfffbffdbeed81e5b0d
+25481e1b35101a2b191d291f2434171d321321351c263b1c2b4b1c29481c325324345721
+385f1e3d66203d6725315a1e3f6721385d29375e27406728476e2b6187327ea53298c137
+98b73f84ab3885b53b87ba37709c2d577630435e274865234d8321588f31568f283f6e12
+bfdaa7fbfffffefafffffffafafffbfffffdfffdfffffcfffffefffbfffafcfffffdfeff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffefefef7f7f7e7e7e7d0d0d0b6b6b69d9d9d8d8d8d
+747e736771665965594f5b4f495549455346414f423b493c1c3c17163b0f2350192b5f1d
+316b1f397626377522357320326f21326d1d3d78283b76224380234a8b25498f1f62ab36
+fffff3fffbfffffdfffdfff9fdfff9fffdff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffdfffbfffdfffffdfffdfffbfffffefffffffefffeffff508e3b3d841e468c2a508e29
+4f87244e842c3f6b1c5b7649fffefffefffdb4beb31420141419153641334f75442a6b19
+24471d213b161a2b191a261a2434171c311023371e273b1f30502129481c2e4f2031541e
+396021365f1b37611f345e1f3c5f1b3f621e385b25385a283e602446652956742c7a9a35
+82a330769629708f32556e2c384a20374c21496a2378a5407fb3345e9339528e2c4b8521
+426d1ecee5bbfcfffffdfcfffffefbfdfafffffefffffffbfefffbfafbfffefdfffffffb
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffefefefffffffffffffdfdfd
+fcfffbfbfffafbfffafcfffbfbfffbfbfffbfbfffbfbfffbdee5dda4b1a05a6e532c4c23
+1d48131f531329651d34722737782632732131701f39792539772237731b407d20468324
+aedaa7fbfff6fffcfff8fffdf8fffdfffcff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffefffcfffdfffffdfffcfefcfffffffffffffefff5fff43c88263f8b1f428524518b27
+4f8a20508c2c3867177f9870fffefff8fcff535d521b2817223724254c1d3471212f751f
+2c5024213d171728151e2b1a2c3c1f1e331221351a2b3e222c4c1d2b4b1c30522031541e
+3d6326315a18355f1d3a6425344f243a542d3d5a2a3e5d243957253550272d461e2d4718
+2b4021263919374b18657a2d728a2c84a635aee448baff37b2eb4479b23f4a8b274f9228
+3e7718477024bfd9acf6fff7fffbfffffafefffffdfefffbfefffafffffbfffdfefffdff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffefefeffffffffffffffffffffffffffffffffffffffffff
+fefcfdfffdfefffefffffefffffffffefefefffffffefefefffcfffffcfffefefcf6fff5
+b5c8b45875562a50271944161e52102f6623346b283165252a5a1e29541c2b501d1e3e0d
+6da86eebfae7fffafef8fffff8fffffffafe
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffefffcfffdfffefffffdfefcfffdfffefffffeffdff3d832881d4090214a8a2c538b28
+4c8a1d478a2330641296ae8afffdfffcffff7d877f1523122345203474263c8826377b24
+2e5423203e181e321922311a2c3f1f223814213617273a1e2a4a1b3151203557242f521c
+3a60252c5415376121436d2d3a5729355226466623557b244e732344682046681e4f702b
+52702a5a79296a8c2d7fa133a0c63fbfee48bdf740c1ff49bbf93c8ccc384f8d284b8d23
+4782283f711c4d7f1091bc74f8fffbfefff8fffefbfffbfcfefdfbfffff8fffefcfffcff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefe
+fffdfffffdfffffdfffffdfffffefffffefffffefffffefffefffdfdfdfdfffefffffeff
+fafafcfcfffdecf6ed99a5994d614520371a173213153011182f15132110192018626461
+90a892ecf2eefffefffefefcfefefcfffeff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffefffefffbfffdfffffefffcfffbfffdffffffffbbdcb12f851a4292234a8b2f4b8423
+49881d4a8c283b70206f8966fffefffcfffbf2fcf42637252b5b213984273989282f711a
+2b531e23431a2c4424233618253b17274018253e172034182a4a1933532233562030531d
+3b61282c5418355f1f3e68264367273c611b456a24577e2f618a2e5f8a3065913076a62e
+88b13b84ac2f92b63c8dab39b1cf4bddff5ec3f642c3fd53abef3a7fbd384d832d508626
+467a28467b2b62a61f4b931563904beaffe0fffffdfffbfffffdfffbfffffbfcfefffffd
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffefefefdfdfdf8fff9fcfffbfdfdfdfffaff
+fffbfffffdfffffefffffffdfffefdf4f5f0aaafa87279717a817aa5a7a6dcd7ddfff9ff
+fffcfffffefffffffffffefbfffefbffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fefffffffffbfffdfffffffffcfff8fffcfffefffd90bb8333801a449222488e2b54932b
+58972c50922e4177232443196c7572f8fff3c5d3c4304d2e326a213c872837812833731d
+315f2123481c2f49222740182841192f4a1d2d481d1e36162e4e1d2e4e1c2a4d1732551f
+3a5f292d541b355f1f39641f3d6823436c2a51783550792d4b7425517a2b648f366f9e34
+76a12b91b83b9dba3cacbe46c2d150cde64cc1ed42b9f14894cf4356873845722d4d7920
+527d2b4478265196296cc132559f2251832ed7edc9fbfdfcfffefffbfcfffcfffbfafdf2
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffdfdfdfdfdfdfefefeffffffffffffffffffffffffffffff
+fdfffcfefffdfefffdfefffdfefffdfffffdfffffdfffffdfffffffffffffffefffffeff
+fffffdfffffbfffff8fcfff4fffbfdfffefffefefcfafcf9fcfffdfcfffdfcfefdffffff
+fffffffcfcfcfffffdfffffbfffffbfffffd
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fdfefffffffbfffbfffffffffafff5fffcfffbfffc6a9d5a3c7e1c499720489525549925
+5a9a2a52902b50872c2c52191127103f523c26412026561c3b7f2a418a30357b23387a23
+356825254d1b2a491d304c1c324d22304e1c32501e223c1930501f30511c294c1432551d
+3156222c531c3963233c67203c671f365e20487125567e25577c2e54792c5b832b5f872f
+72983386ae2a95b4329db047a2b542b8da3db2e24086be39558026385d273b651d4f7923
+4d792444782344862560b12869b82954a01958972fccf1bef5fff7fffefffffefcfefffd
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffffffffefefefefefefefefefefefeffffffffffff
+fcfefdfefffffdfffefcfefdfefefefefefefefefefffffffffcfffffdfffffefffffffd
+fefffbfafff9f9fef8fefffbfefefcfffffffffffffefffffcfefdfcfefbfcfffbfafff8
+fcfffdfefffafffffbfefffdfefffdfffffb
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fbfffffffffbfff9fffffffffafff5fffbfffbfffc538b4047801f559f2653a32a539d22
+5d9e2a55922b4b812137601c25451c2943282147182f6c1c357f262a701842842a357b23
+2c61192852202c4e1c34521e324f212b4c17355621233e1b2949183556213558203e6129
+2f54202d541d3a642536611a396226375f23385b233c5b1f4c6b284c6a2e4c6c2b587b27
+71913c83a93c7da5327aa0318fb8389ccc3a75a83143772f334e19486924618c33507e26
+497827487d254f8e2371ba376eb72872cb3360bc29569a2bd1e9b9fffcfefffbfffafeff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffefffffefffffdfffffefffffefffffffdfdfffafbfffa
+fbfffcfefffffffdfffffafffefffffcfdfffffefffffdfffffdfffffefffffdfefffffd
+fffdfffffffffefffdfefffffefffffefffd
+f9fffdfffffffffdfffffcfffffdfffffffffbfffefcfffffffefffefcfffffefffffeff
+fefcfffffefffffefffffefffbfffbfafff9fefffdfffffffffdfffffefffffdfffffeff
+fff9fffdfffef9fffafffbfafcfffafdfcfffefffb3b881e46932359a42e5ba92260ad2b
+59a1315191235083243b61242c56243056252b5e1c377d24357e223776273d7c2d337e1f
+32581f2f4e2232501c34581a30581c2f571b355621273c1d2f4c1c2d4d1c305521315821
+335a212f551c385b23385b233a5d273b5c273654202f4b1a354f2237512436511e46612a
+486e19557627566f2e5a712b5471213b57241836103d621f88ba358ec23285b53b5a822a
+466f204d82284b921c71c82c6ac2306bc5286ac32d65ba275ca424c7efbaf6fdfffffbff
+fefff8fefffffcfef9fffffdfffffbfffef9fffefffcfffdffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffdfdfdfefffdfdfffcfefffdfcfcfcfefefefffffffffffffcfcfc
+fffffffffffffffffffffffffffdfffffdfffffefffffdfffffefffefcfffffefffefcfd
+fffcfffefffffbfffcfffefcfbfdf8feffffcfe6c9368a184c9b2854a22b5cac2963b32e
+5da92f5ba029568d28345c1d2b541c29511d2f63212c751c2e791a3c7d29357423387e25
+3457212b4a202c4d1835591b375f23375f21375821203814324f2132522130521f2f541e
+33592030561d355820375a203a5d2533562033511f2b461d28401e2a4124233b1b1e3813
+1b301f2136231d341820371b1e341d415c2584aa33bbe845b3e5449ed03d81ac385f8629
+4f7925497c2f478b2672c7346ecc2e6ec72f77cb3870c63166b92958952ecde6befffeff
+fffefff8f9f3fffffdfffefffffefcfffdfefdfdfdfefffdffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffdfefdfdfbfefffbfcfffbfcfffbfcfefbfffffdfffffdfefffdfdfffcfefffdfefffd
+fcfefbfefffdfcfefbfefffdfffefffffefffffdfffffffffffffdfefffdfefffbfdfffa
+fffffff9fdfcfffefffffffffffeffc4c9c384b7753c981c4ea22952a32b5cad2d62b42c
+64b52c6ab32e58962934631b2a5617325e2339702c36812636841e3c83253574232a681d
+2848192140172a4a18365d1c3b63253c64254165272f4c1e284316294616264615315320
+365b2530561d2b511832551b3355232d4f1c395a23415f293f5c2645632751702c5d7d32
+65812c6a883071913074952a89ab30b2d344c9e948c4e43bb9e64190ba30759c3264882e
+4c741e477b28579c316ec72d6bcd2a73cb3777ca3470c72b6cca2e61b51f5a8e29efffe9
+fefafffffff6fffefffcfafffffffffffefffffffafefefcffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffefffffffdfefffdfdfdfffefcfffffdfffffefffcfdf8fdfffefefffffafcfbfeffff
+fafcfbfefffffefffffefffffdfffcfefffdf9fef8fcfffbfcfffbfbfffafafff9fefffb
+f3f7f6868887fff9fffcfcfec4bfc613200f3c882648a7274da32854a82f59ab2f5baf25
+6bc12c71c02f5598253e752241702831651d3c792b408c2a3f9122449129347324285e22
+29441b27431d3556214067263c642637601e3a621c2e5119314d1c3754242c4919264614
+2e501d3b5e28365c232c52172f521a2f531641642253742d5a7a2f5c7e285f83216a9126
+738e2f7c973696b042a4ba3bb5c642c3d04ccadc4cd0e646b7dc3f94ba337fa23c688b3b
+456c1d467c1c65ad306cc52b70ce3072ca3672c92d71cd2e69ca2f72cf2963ae1e79ad58
+fefffbfcfcfafcf9fffffefffefdfffefffffdfef6fffeffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fefffdfdfffcfefffffffcfffffafffff9fffffeff7c837bc9c9cbfefeffffffffffffff
+ffffffaeaeb0fcfcfefffffffdfffefdfffc969b97535852fdfffcfffffffffdfffff8ff
+747e761116108d888efcfffdb8b8ba27431d449d2949a5284ca72654aa2f55a92f57ae23
+6fc92c72c632519a24498726619a393f7c1d33751b3882213e9024408f26397b24336526
+2c442028421f31541e37601c355d1e365f1b406a203b64222b4c153758213d5e293c5c2a
+31511f2e511b3659213b612837562c385827436229486628506f2961832f6c9030769d32
+89ac2c8da837abbb3ebbbd42c0b355ccc157e4ed54e3f94ebee2449cbd38779a325f8232
+4a73274d832562aa2c68c02e73ca2e6ec9306bca326dce336dcc3276d23374cb2f4ea113
+bfd89ff9fffffefdfffffffdfefdfffdfffcfcfcfafffeffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fafffaeaf6eaf8fff6f9fff8fffefffffdff8c918d323e325c5c5cfefefeffffffffffff
+e0e0e02626269e9e9efdfdfdfffefffcfcfe3c3e3d0f110e767875dfdde0cfc8cfaea4ad
+3245321d2c191926142937281d2e1c31642147a5294fab2f52ad2c50a92b56aa305bb128
+6ec72d6ec334529d264e942466ad2d61a82e438b1f3a7f223a852637882240852834671c
+233616243e1b34571f3b641e3b64223a631d3f6b1e3b69213a61203b6223395c2230511c
+2d4d1b30501e375a2431541c2f4b23324f2345612e4b672d476424506f235f82286d912f
+84a532a5be48a9b23dc6b953d4ba59d7c348f4f462c9d849b2d24186a52d6a8d275d812a
+4e762d4e832761a9296bc12872c82967c2296dcc3e6bca3876d13477ce3274cf346ecf2a
+6a9f33ebffecfbfffffcfbf7fffefffcfefbfffefffffdfeffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+e9f0e9677b628dae8183a475748c6a76836f5e695b4b594a474c46747973858a84929791
+6b706a2d322c2f342e777c76797b78656c642632242536230f220c172a1417281512210e
+1f3d1b2a461d21461323411f284f223b892451b0304aa62a52ad2c51aa2a59ad315cb22b
+69c12d64ba35519e2a559f2460ae2665b62969b433529629428a2641942c40872b2e6218
+25361629411d365c1f3c661e3d66243b641e3f6b1c3d6d23416f243b661f355d1e2d5018
+3455202d4d1b34572132551f2c49132d490f3f5b1e506a2d516b2c506b2654732563852f
+819b3a91ac2ba7b23cb3a84fccb356d5be54c3bb4cbac447a3c24185a72f80a639638932
+406925477e2164ad276ec42d6ec82b6fca2f6fcb386fc93368c22475ce3472cc366dcd2d
+59a71d92c278f4fff1fffffdfffffafefefffffefffffffbffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fcfffb9ab59285b87381bc6a7ead69829d7273856d6f7d6c647064515d514753473f4b3f
+3e4a3e404c403d493d2a362a23342222391f2c4a282d54272753202d5c2625541e305f29
+335a2b2f581e30681d37612f2f6a263ea0254aab284bab2d4faa2954ad2b5aae325ab02b
+63ba2b5db2334e9d2a5ea92864b53461b62371bf2b72b532559e2b42952941893325571a
+2736172a421e355b1e3b671c416a28416a24406f1f3d70233e7220437327426c2a2e5419
+3859242f4f1d325220284b152f4725324b24374e203d54204c6428546f285b7c25749637
+88a032a6c045b0c248b8b74bc5b34dc8b64acac44ad3db51a2c24396bc318ab3314f7623
+335a254e852a66af2c67b73a6bc8326fc82e74ca2b71c9296cc72a69c62f6fc93468c129
+64c12b4e8d1adff2d6fffefffffff8fefcfffefefffcfdf5ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fcfefdfcfffbe3eee0acbea698b28f90b1848db47f82ab717f9f767292696a8a61608057
+5a7a5158794e51724550714243693a3d67353a6730396d2d37732b377828367c26378027
+387d24337022397629378923367821469f274aa62752aa2f4baa2c53ac2a5caf295fb129
+62b52f53aa2750a72457ae2b64b12767b73263b93265be3065ba275daa2652902d265b13
+1c281a2b3b213751243b5e1e446e263b661e416c24416d204474284172234271233a651d
+2f5718365921375725284515293c202e441d38501e39511d3f57234c66295d7a28749230
+97a939a2b935c3d54bc6c752cab758d0b854dbcc59c9c547a3be399cc541638c26344b1f
+455c30497f1d58a52362b7286abe326dc53170cb3070ce306fcd2f6dcb2d70cc2d74d02d
+79d03460bb205b8f3cfefffffffefffdfcfffffff6fffcffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffefffefefffcfffdf9fffaf3fff2c2d5c19cb49a95ae9192b68a8fb38786ac7d7aa472
+73a0696698595b904c59914a4e833f4a823b4480364180313e822d3a8329398425398724
+3984253b802740842d348c1e357e2249a72d4fae2e4aa5264cab2d53ac2a5caf295fb129
+5fb53054ab2852a9265bb12c66b52865b72f61b42e63ba2f66bb2c66b42c6ab13954962c
+3251182542122c4f174169204976253d6b2243732940721d417522427322477827447229
+365f1d2e541931521d2f4f1d2e4121334922395121425b2449662654722a64812d6c8b2e
+84a43595b435bad047bfc142c3b54ac4b250b4b148a5b23cadd13980a836284519374d26
+46651f52872f5ca2325ba52a60b22a64b92a68c1296ec92e6fcc336cc9306fca2f74d031
+78d7356ccb2f4e9120b9ceaffffffdfffffdfcfdf8feffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffdfffef9fdfffefffefefefcfefdfcfffff8fefcdfe5e3a4bb9e99b29290ae888bb084
+80ad7677ab6b70a96262a0535d9c4b5596424f933c4b9138448f303e8c293c8d2640912a
+368822418f2a408c283c962436892146a82f4aab2a4fac2a4cab2d53ac2a5ab02b5caf29
+5db32e54ab2854ab285db32e64b72b62b42b5eb22963b72e65b72e61b4286fc1316fbe2d
+5e98283e721d34641a4879204c7f224478234a812d4a86264c83264a8126487e28437627
+3c6a22396220385b2133541d31461d2d421b384e274058284d6a2763832e6c8f2b779c32
+92b7338ca736a3ab44b9b047bca547ac994aa0a144aabf469fc84439561e243b1f4b632f
+466a224b81294d8e2653922756a62364b62d6dc22f69c22c68c22c6dc73172cc3675d035
+6fd12e6acc2b62b7267aa85dfbfff9fffffafcfffffbfff9ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffffbfffffbfffffbfefdfbfffffdfffefffffefffefcfdfefffaecf2e8bbc6b898a996
+88a1847999727096676e96646397555f9450558f454c893b478834458b333f882c358021
+3a8c283d8b26418e263e96253f9c2a44aa2d49ae2c4baa284baa2c50ab2a59af2a59af2a
+59b02d50a92755ac295db32e5db32e5eb2295eb12564b62d66b8305eb2266cc22b73ce2b
+73c63067ae344d8b2a4c8526518a23518f24539529579d2d529025528f284c8828457d22
+4175223f6d223c6322375a20334b1b31461f2b3e20354926425a26506f216d90287fa62f
+85ac2d91af3d96a53ea1a1419b9138a19e41a9ba48a1c339415e261b2e0e4f622b4a6321
+39601d488122508f245d982a5aa4276bb93270c33369bf2a64be286bc52f70cb326fca2f
+6ccd2e6fce2a6fcf2d569925f6ffeefffefdfcfffffafff6ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fcfefbfffffdfffffdfefefcfffffdfefdfbfffdfcfffefdfffdfffffdfffffefffefefe
+e0e5dfbbc3b898a5947885735f785a526d4c49674143683c3c673237692c386f2c3c7530
+30752236772336781e3c88243ea0274cb23349ae2c47a6244baa2c50ab2a58af2c57ae2b
+55ae2c4faa2954ad2b5bb12c5cb0345cb22b5db22362b52965b72f5fb22c66bf2f70cb32
+6cc82775ca395ea73152932d5c9c2e65ac2a63af295ead2e5ea428599e29529627509427
+528f284a7f253f6b20385f20344b1d283e17283b1d26351e2b3e22394f214c672470903b
+97c942a8da45a5d23bb0d642bce040c0e64587ac3a34552017251850601f566426435c22
+426d1e4b81294e8821548f235ca12a62aa2a67b6296bbf296fc8306fca316dcb2f6dcb2d
+72cf3872cd2865c52353a215b9d0a6fdf8fefffefffffffdffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fefffffcfdfffefffffffefffefefffefefffffffffdfdfdfdfcfafffefffffffffefeff
+fffffffffffffbfdfafefffde4e6e5bdc2be959c9475817353665037503326442221411c
+224d182c572227571b2e661d45a52a4cb12f42a5244fad314cab2d50ab2a58af2c55ae2c
+53ae2d4faa2955ae2c5bb12c5cb0365bb02e5db1275db12561b42e5fb22e62b83168bf34
+65c22b6ec7315eae2b54992e5fa5336bb82a6cc02a63b72b69b72f65b5305fae2e5daa2a
+60a82b5a982b487a2536601e364f273248222438152230171a2715121f0e1e2d1a304228
+5d7e2d6f942b7fa72c80a82d72952f57722b263d1314251246572363702a47551a425c2d
+406724416c1d4372214b812b5594295a9f2862ae2769bb2970c62f71cc316fcd2f70ce2f
+71c93571c9296ac52a63b52368904afefffffffdfffffeffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fcfafffffefffefdfffaf9fefffffffefffffefffffdfefffefffbfdfffcfefffdfdfffe
+fbfcfefffffffffffffefefefffefffffefffffffffdfffefbfffaf0f7efced6cba3ada2
+7a89725c6b58425a402f532545a0274dae294aab2847a52d4cab2d4faa2955ae2c53ac2a
+50ac2d4eaa2b56af2d5ab02b59ae2d59ae2c5bb12c58ae295cb22d5fb22e62b52f66b830
+67bb2f68bb2b5aaa23509b245da92f62b3286bc12a69c12d69bf2a6ec6346ec63467bc29
+64b3245ea2274d84273b6823304b202d461f3a4b293c492b3843252e381f1722110d190d
+1d26111920191a201e121912121818191c21262b174c531f5f75234e5a284a5d25375523
+2140162d460f3d5a2247712f4c8729589a2e62aa2d64b52a68bd2a6cc6306dcb2f6dcb2d
+6fca2d75ce3675cb3464b7294a8622eafce6fffcfffffffdffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+fffefbfffbf8fffefbfffffdfdfdfbfcfefdfefffffefffffffdfefffdfefffefffffdff
+fffefffffffffdfdfffffffffefffdfdfdfbfffffffffffffffdfefffdfefffefffffcff
+fffdfafffffff9fffdd4ebcf49a22a4bab2549aa274da7354baa2c4da82753ac2a51ac2b
+4eaa2b4da92a56af2d59af2a5cb02758ae2958ae2f52a82955aa2958ab255eaf2663b127
+64b42d67b82f5fad2656a32363b2335fb12b69c12f72cd3471cc316fca316ecc3071cd2e
+70c52a64ad285089283c6e2534521e2b441c304023394422424e204d5a254752272f3a18
+1b2817212a172c311a363d1e4952275762285d69275f692a4d6029495a2441592533561c
+27411a2c352233441a395d1d417824498724579c2763b02c6abf3069c33069c62f6dcb2f
+71d02a6eca3777cc3165b72f3c8710a6c29afffcfffcfff8ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fcfffffdfffefffefff7fff349a42f4faf2954ad2d46a9284ba72a4da52a51a72c51aa2c
+4faa2b4ca72652a7285aab2b56ab2a55ac2a54ab2955a72b55a02a569f295aa6285daf29
+61b12c63b63057b02e4ea72965bb3671c53262b42169bc306ed1266dca336cc33475cb32
+6cc63161b9274d8d2d4774232f4f2038502c32421d2d3b18323f23394a1e44561a4a5922
+445d26485c1f586321636325615c25605c2c5d5c2c55592647591d4e6328375019395522
+3b5828243f122640132e481b39641d4e8027609e2f62aa2a60b32769c12f71cc3170cc2d
+6ece2c6ccb2f7acf3e68b7263d8306a0bf86fffffdfdfffcffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fefffffefefefffefff3ffef45a42c4eae2854ad2d49aa294ca62a4ca42950a62b50a82d
+4faa2b4ca72852a72858a82b55a72954a92a53a72b52a12a4f99284d9525519c2554a525
+5cac295bb12c54ad2b4ea92a5fb63171c6336dc12d61b4266fc52c76cb3a68bc306bc42a
+68c12960b32554932a49792339561e33481f33411d343d20303926303b1d3441153f4a20
+3e4a244d542b51522a544e2a554c2d504b2b4f512a4a52234e632b394c1e1d2c0d1a2713
+22311c2a3f1e3852223b5a1f396220437422508d255aa12760b02b6cc03470ca346fca2f
+6fcd2f73d23668bd2a62b4225da52793b579fdfcfafefffdffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffefffffefcfffffdecffe742a6284eb02958ae3150ad2b4da72c4da2294da3284fa52a
+4da72b4ca62a50a42a55a52c53a32a51a1284e9f274e9b294d942a4b8f284a9226499624
+56a2265aad2b52ad2a4eaa2b55af2967bf2d72c83367bc2d6cb83276c92f76cf296ac627
+71ca3269b6285d9d224a811c405f1c30461836421c303a182a311f2e3820313b18394021
+40451d41411b4b47244b44274944264545214048194b5a213647251f2b15141912141416
+181d19273420304a1d3153173b6126406e254d8426589c2b5fae2e66ba306ac2306ac42e
+6ec72f6ecb3260b82474c83555a12383a66cfffffdffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffefdfffefcfefffde5fee040a9284cb02958ae3354ad2d50a82e4ea32a4ca0274ca128
+4ba3294aa2284da12851a029529c294b98244996244b92284b8d2b46862845882748902c
+4e972455a72b4faa2b4ca82b52ad2a5db4256abf2c71c63766b72a6bbd2b78d3306ccd30
+6fca316eb82d5793224c8423334f1e293c2037442a353e1f2a331e29321f29331b2f3324
+34371c3c3c243a38213b39223c3a234245284953303c48201c231c151a16161817181818
+1a1d161924131b2e1028411a2c4f19335c1a3d711c488a1e539f215eb22868c02e6cc630
+6fc4336fca3170c63169be2f4d982174975dfffffbfffdffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffefbfffefffefffddffad73fab244aaf2b56a93351aa2a55ab3051a52b50a1294da128
+49a12749a1294c9f29509f2a5098284b9524499324498d26427e2439731f3b7924478730
+498d284b9a2748a02646a12851ac2d5ab2285db4256dc13570cf2b5daf2f66bc3571d13c
+70cf376ab32d4d843047812c2a491d1f361c35452144551f44552138491d32411a323c21
+2f39212a321a343a20373e1f4348284b523130391a161f041a151b181619141611151d12
+1823131522101a271326331f304e1a3d6124497a2954932b60aa2f68bb2f67bf2b62bb23
+6abe3268c32a6ec22f5cac2740881a6c8c5afffefafffeffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffafffefffeffffdbf5d040aa2248ab2a50a4324ba62756aa2e56a82c53a42b4fa329
+4aa22849a1294c9f2951a02b5199294b9524499123488a26417922356a1c32681d377023
+417f29448c26449b28429c2a49a22c56ad2a5db12865b93070d43460af20509a0f75d035
+68c63470c02d54932a4e92253a5e141d32131b28171e2a1227331b303f204151204b5a1f
+47591d4a5b24414f1e3d4a1f333c1d1e221314151713131f191313181713141913172118
+1927181b291823301c232f1b243e0f32531c416c2549852559a02868b92e6fc5306ec72f
+67b93061ba226dbc2d69b038317111617c4ffffefbffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffafffefffeffffd9f1cd42a92248ab2d4ca23349a52853a82955a72957a72c52a62c
+4ba32949a1274c9f2952a12c529c294e98254a92224a8b27477d293d6c2433621e2a5d18
+356d243d82273f92283f962b4199294ba1265aad2961b22f64c1347dbe3091c25772bf23
+68c43364bb1e70bd315caa22324b24131f1f1b2026181b1010160c121615171c181b1b19
+1f231421241b1c211b121710181b121b1e1715151518171d151610171813181a171a1f1b
+1822191b291822341c2135192137102c491b396123457d26559a2660b02969be2d6ec632
+67bb3268be2775bf365c9b3039701f647a54fffcf9fefffdffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fdfff9fefffffffeffd9efcb45ab2449ab304da33648a62a4ea32254a62857a72a55a72b
+4ea42949a1274c9f2951a02b549e2b539e284f97274d8b284a7e2b44722a3966252f5d1c
+295d1b3779223586203c932a43992e44972152a3235aab2b5ab126c5f190f4fff2a8e75a
+5fba1d6ec83273c43b62b62c475f230f1a0c1b1b1d1d1d13191a151a191e1715181b1716
+1f1b121c181718151c16151b1414161415101617111514101016141216151717151a1b16
+1e2118192614172e141e3b1c2b3e1e2b451e2f561f3f74245195285aaa2760b42865bc2d
+65b93064ba2363a924457f1b31631a7e9171fffefbfbfffaffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fefffafefffdfffbffceecc841b2264faa334ea53047a0284fa0274da52a4da72c51a62d
+53a12a569f2a4d9c254ba3284c9d2454a0245395344f9123487c29365d1e3a55281d3714
+20362130632034801e3e8c2740912a3d942c43962c549e255aa526feffebfffafff7ff87
+6bc8216bc3315aa4316bbd2d4f86291a1f191b151710160c14181b1517161317161b1714
+1616161616163e3e3ebfbfbf7f7f7f2b2b2b151515151515151316151515121411141912
+1820151a25171c27171f2a1a2734162c401d345121446f2759932d5fa92c60b42b63bb31
+6acb2672c734549724497828304c1ba0ac94fdfff5fffffbffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fefffafefffdfffaffcbebc242b12752ad3450a7324aa32b4ca0274ba3294aa4294ea229
+539e28569f2a4f9f264da52a53a72d54a02451942b5190253e72202b51181e440b335c24
+2c60201c420f335d2b377a2a388a1e3d88293f832c418e1e499622c1ef95fffff8fdfcaa
+6dc82d66c1286dc92668bc28508d252a381e1513141419131415171b1c1e151714181413
+1818186f6f6ffffffffdfdfdfffffffdfdfdadadad8080805b5b5d424242212121141613
+161b151a22171b26181b28171e2c1520321a213a1a274e193b711d51942163b12a6ec131
+6dbd364e951d457e1f3a631f1f3810cad5c4fefffbfffdffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffbfefffdfff9ffc3e9b843af2855ae3653a8334da42f4a9d2948a02848a0284e9f27
+559e295aa32d53a42b50aa2e52aa2f57a3255c9f2c4b88203c6d1e1c40143d6c2841822e
+439229274d1c122217274c213b7c223b7b243c782e3678203c7c2564ab31f2ffcddbd299
+6bb92f6fc5306dcc3067b231549f2045652610151116151a1a181915151720221f767573
+e1e1e1fcfcfcfffffffffffffffffffcfcfcfffffffefefefefffffefefffdfbfe7f7d80
+1414141419131d271c1824161825131c2e16243c1830511a426e1f538a2557962454951d
+548b2e3f7320305b162d4f1d32492cf7fff6fefffffffdffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffdfefffdfffbffb8e5ac46ad2a55ae3653a8334ea32e489a2b449826439a254d9e26
+58a12b5ca52f56a82c50ac2d51a92e57a3255fa328508d25406e237a977b467a3232851b
+398b1d3d74300e2014131716264013386e23326e283263223a681d457a1e778959817d5a
+66aa2f75c73e62b62c69ac2b6ec22f578b2749574668656e757170a2a0a3fdfef9fffdfe
+fffffffffffffcfcfcfffffffefefefefefefffffffffffffafcfbfffffffefcfffffdff
+2c2a2f101211111811172317191f1b1822191b29182135192b451e335226315223254919
+2846122f4c1c2d4a1e2c462351634df9fffafffefffff9ffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffefffdfffeffa9e19a49ac2d55af3454a7334fa2304b982e4094253f96234b9c26
+58a32c5ca62d55a72b50ab2c51aa2c5da8295ea5235598275b863fedfff35e8a4d257b0e
+39832241872f1a3c171f15201d181420441822551a2c531a2a4e1e32471e20391b3b5621
+72ba306cc43270c52c6db52f6fca2f4d9215bed8b1fcfbfffffefffffefffffffdfefefe
+fdfdfdfffffffffffffdfdfdfffffffefefefffffffdfdfdfefffffcfcfcfffeffefedf2
+1a181d141615151c151620171d2015181e14171c16141a18101916141f191b27191a2916
+1d2b1120301524341a1a29128a9786fbfffafdfdfdfffeffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fefefefefffdfffffd99d88752ae3258b03655a8344ea0314f9533429128419827499e27
+56a62b5ba72b58a82b54aa2b53a72b5ea92866af2c529c217ea765fbffffc0dab5236c12
+327b213e872b29561f1819141e1317202e1f294b262f551a153a182635144574264e8c2b
+62b7286ece3663bb2761b6275cb71e62b32a86ad6cfefffbfffefff8faf9fffffdfefefe
+fffffffffffffafafafffffffefefefffffffcfcfcfffffffefefefffffffbfdfa989a97
+111310131814171c18191e1a1a1d12191d0f1c20121c1f14171a111619101b1f111f2410
+262f1e232c1b263121262e1ff7fff4fcfffbfefefcfbfbfbffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fefefffefffdfefffa88cd7456af3759b13758a8354d9d2e498a2c408d27439b2b47a028
+53a72b59a82b5aa92a56a82a58a82d5da62365b23052a41e9bc384fef7fffcfff8417535
+30791f35802133672715220e1a17121c231b1b32183b57243a6629426a23659a3050932c
+5dae3665bb3262b82f65be266abf3067be3356892dfcfff3fdfefffcfffbfffffdfdfdff
+fffffffefefefffffffffffffafafafffffffffffffefefefffdfefffffdf8fdf6444e43
+0f190e10170f141915191b1a1a1f23181e1c181e14191f15181d171a1c191d1f1c1f211c
+1722121c2719151b118e918afefffbfefefcfffffffeffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffdfffcfcfdf87cc56957ae3958b03557a73449992a3f7b213b8522439b2b43a127
+4ea72956a6295ba72955a42559a52b66ad295ead2e52a61ab7dfa1fff9fffff9ff84ab7e
+296f163c8d27316d271d2f171416091726111e35192d3d19396122356d123a641a578f2c
+65b12a66ae2869ba2d61b13661b32b63bb33487f17dae4cbfbfffffbfffafefefefffeff
+fefefefffffffcfcfcfffffffffffffffffffdfdfdfffffffffefffbfcf7ebf3e6222f1e
+1b2918101a0f1517141a1a1a152211152210162111151f16171d1d171d1d161d16171d0f
+1523121b2618292e27fffffdfffdfffdfdfffffffffdfffeffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffdffffffe9ffe468be4f5eae3f58af3a59a2374e93263f701f3e712e43a22e489f2c
+48a72558a62c5ea52b53a32a5aaa3156a8226ab53457a920c8e9b0fefffbfffcfdd6e4d7
+26621a3484234090212a531b151a161c1a1b1a1e1d24301a2b451538611f4d882a519528
+498b274f8d285e9e2e5598275cb42c66b92b488715c7e7b8fbfffffff9fffffdfffeffff
+fffffffdfdfdfffffffffffffefefefffffffefefefffffffcfefdfffffb9ab990174b0d
+24441f202819181f17161a1d181d17192018141e15151f16181f18161b151518111f2219
+1d241c1217118c8e8bfffffffdfcfffefffffcfffffafefdffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffdfeffffffd3f1cd61b8475aad3b54ab36559e354d90264574262e5a1d48a231459c27
+47a62653a12957a12852a32a57a52d5bab2662ae2a5db125cdf0b6fcfefbfffbfff7fffa
+5385481f680e3a8721315f21182416171c161d271c2434193c58274064243c692635681d
+4376174b8121488025508e296ab63868af2f437917b3cca2fefffbfffefbfffffafdfeff
+fdfdfdfcfcfcfffffffffffffefefefffffffefefefffffffffbfffcfdf869945e2a741d
+2c63202b4a20182c111f29211c20121a20121c2216161c12171a131718121d1e16191c11
+13160b45463efffffafefaf7fffefdfffefbfefdf9fefff9ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffdfffeffffb4dfaa5bb44058ac3a54a934559934518f2a4a752d20421044972d47a02a
+47a62851a02958a22953a42c569f295aaa2760ad2960b826cdf1b4fffffffff9fff8fffb
+90bb862d6f183c8627376c261f38181220131f2e1915280c223c152d4a1c2b4c133b5e1e
+4164243c641e3d6e1d49802c3f76184b7e22345818c7d6bffdfdfbfffff8fbfcf6fcffff
+fffffffffffffffffffefefefefefefffffffefefefffffffffbfffcfff64a823b348b22
+337e23376f2626521723411f2837221724131920181719181b1c1e191a1c151918101511
+20221ff1f1f1fcfafbfffefffffdfffefcfdfffefffffffdffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffcfffcfffd94d08a58b33c5aad3953a634539533558e2d456e282036123a86244ba42e
+42a0244f9c2a55a0294f9e29589e2a58a7275dad2859b31ecbefb2fffefffffafff3fff4
+65955b33751d3b86293a7a262a501f15271725351b1928111e32192b422535511e3f5e22
+2b491732551f3c63242e561a2f50191e3a0a485a40fbfffffffefffffffbfffffffafcff
+fffffffffffffefefefefefefffffffffffffffffffffffffffefff3ffeb3b782a3b9229
+3e8b2b387d223678212155151b40151d3819162717141d18141a1a11171714191c13181b
+b9bdbefbfffffcfffffcfffffefffffefffff8faf9feffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffdfff7fef67bc56c58b13d59a93a51a132519131558c2e3f6625303c26498e354aa32b
+419f254e972c529b264b982655992856a5285aa92958b21ccef0b4fefdfffff9fdcce4ca
+2a681b337d1a3789273681223161231c321b222e18212c1c1b28172033171d3714254715
+39611b44682a233f17263e1e304023182312c4c8c7fefdfffffefffcfdf8fefffffdfdff
+fefefefefefefefefefffffffffffffefefefefefefefefefcfefdd7efcd337720348d1f
+3b8c2637811e387f21346826234e1621401622311a1b2115151b111e231c565654d3ced2
+fdfffefefffffefffdfafcf9fcfef9fefffafffffbfcfdf8ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffdecf8ea68c1575aae3e57a239519c33539031538c2b355d1f4d50476dab58439e25
+43a1294e952f51972552972a51972552a02859a82b60b522c8e7acfefdfffffffb88b07e
+2c7a173f90273e952c388a24336c252740221c28142633211520121d2c152e4624335523
+2a52163557242d4223202b1a1a231060635afffefffffefffffffbf9fcf3fefffafdfdfd
+fffffffffffffffffffffffffefefefdfdfdfffffffffffffcfffb83a475398a23399d23
+3d93283c8a2431731b2f552426412023321d1b1e171c1b1714150fc9cac4fffefffffaff
+fffcfffffdfffffefffffdfffffefffef9fffffcfffffcffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fefffadff0dd59bc4759a83d569a375299335390314f8b27285115736f6e87bf743a981e
+3f9c274d912e4e9223509226529828529f2b5aa52e5db020b9d69cfefffff7fff1538c45
+3189193e932b439b2d368d242e6d1e2342161426101a311422311e1f2c1b1f2e0f2b411a
+223b1d20391b3142221d26131a2217edeee9fdfcfafffffdfbfdf8fcfffbfdfef9fffefb
+fefefefefefefefefefffffffefefefffffffffffffbfbfbcfe6c9386b2637921d3da125
+3a8b253b872333731f23431c1e2b2114181714141615171216230f87997ff9fff3fffffa
+fefffdfcfefbfcfffbfbfffafcfffbfefffffefefffdfcffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fafff6d5e8d250b83d54a13b519234519532518e2f4b8a22214d12958f9390c87f3d9b21
+3c99244d8f2e4d8f214c8b22478f1f529f2d5aa52f57a81bb4d096fafeffccdec4367a23
+3c972042973243992a388f26397d2a355a242a41271c3c131f341528361f1e231c1c211a
+23311722321523301c131c099ca2a2fcfdfffffefffffffffbfffffcfffffdfcfffffdff
+fffffffffffffffffffffffffefefefffffffbfbfbe6e6e638682e3c81283c9c21369320
+40862e42892d30711d21481b1c2a1b151d121c221420311130531d38602156793f87a172
+97a886a7bb96aec49ea9c29bacc4a0cee3c2e1f1d6f4ffe9ffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fcffffc1e1b057a93b4b973350913748943a4f8c2f4a7525263b14b8b7bd90ce7b369724
+419a2c4c892c43882b538723438b2757912b4da827559c189dc086fff8ff9cb490287c1a
+419e293c8d2447932f3886203d8229325f24273f1f1729131b281628372221301918280e
+25331c2a35241d23194a4c47ffffffffffffffffffffffffffffffffffffffffffffffff
+fff9fffefffbf8fff8f5fcf5fffefbfffffdc7dac726561c24681337882140912b3f8731
+3d882d3f9226377c1f325e21293f192845192446142e531f32542134571f335b1c2d5811
+316513336d1935741b35721335710f336f0f3b7016406c17446a2d52733c68825b809f66
+91b875acd2a1d7f0d2fcfffffffbfffffdfffffdfefefffafcfef9fffcfffefffdf6fff9
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fbfff9b2d6a64fa13f46892844842e4595344e84304172172f3f22e2dfe69acb8a38931e
+429720488b223c84214884243f85234e8a284aa02359a1218bb273fefdff6a9357349023
+41a02a3e91293a85262671122c6d1b264e1a1e32191a2819182313182513293622212e1a
+25311d131b0c171c15d4d6d1fefefefefefeffffffffffffffffffffffffffffffffffff
+fefffbfefdfbfffefffffefffcfffb9eab9a2a4a232d651e3f84293c8d24378b1c38831a
+3a851c4592284285283c6b23374d262f4b1b2b4e182f521a33561c4064273e67233f6a22
+4574234a7f25477e234c802d4b7b2f3968203862202c52152d571538611532620c49831d
+5b9e1d4e990960a92685c348f1ffe3fefffbfffdfffffefffdfef6fffef8fef6ffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffdb2d5b5418d32abd08aa4cf7f438d2a4570283962203b4433fffdffb2d0ac3b8e22
+419023448b2b37782447853245882b4181214a9924519d1f82a966eaf5ed4083263a9b27
+369821449630479036397f272e67201e3e15162413192018131b0e192114152010151d0e
+161e0f13190f797b76fffffdfefefefffffffffffffffffffffffffffffffffffffefefe
+fbfff3fffcfffff9fff7fff86789681d441726571638752539792b357d273782233f8120
+38721b30651d2555191d4510293f182f4b1b3758213b5d21385a1e3d5f223a621c39671c
+3b68233b66163d6816335c1630581c395c224064273b5e2435671e52842d589e2a50a129
+6bb92f74cc2a6ccf3467c9287ebe44f1ffecfdfafffffefffefffffcfdf7fffefbfffcff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffcf7cfe8d567ab56fbfff6faffcf47823238621a324c1f646462fffffdd2e5d241922b
+4392273e872b2f60113364133e812442882847942249941e7da55fbbd3bb3b8f1d3d9c26
+3a99233886233778243a792a3163242a4323222a1f1719141c211a1c2218292f251e241a
+171a13646661f6f6f4ffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffafffcffe8f5e44c7e41246b1d2e712131711a31751e3070222f7223327023346621
+2b4d1a233b19283c202e43242b3f1c344d23314f1d35541b304f162d4f123d6421406e25
+46752d4470214f7927456f233b62213a5e204068223d691c4a852959923161b2315dba2e
+58a41e75c03070cf356bcf2e66c22194c363fefffdfffafff9fffff7fffffcfffffffffa
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fefffaf5fbf7aae79aecfff2f0fbc14f7d352b51182c3522c3bfc0fefffbe8f8ee519e38
+348d0d387f1556712a80965647822e368220418a1f4d922770995382a97c3d911f3d9628
+3d942334791e2e661b3063202048141a2c1220231a23241e1f211c1416111517121a1b16
+7b7b79fefefcfffffffefeffffffffffffffffffffffffffffffffffffffffffffffffff
+fffdfff8fffa4373372b7c13368f2145983044962a3d942c419327448c293a7525315a22
+2a421e2633172b36182b3a191f32162a401c2e491e355023334f1f2d4b153a6122427028
+4b8423538b284f86215488244a7c232d5e0d437724558b2d518d1c56902964b5326bcd28
+60af225d9f2472c52f6ccb3166c426bff07affffdefffcfffcfffff8fffff9fdfffefffa
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fbfffffffbffc9fbc0b2f6abaed5845474311b331b696b68fffefdfbfdfaf8ffff6eaa60
+318b10508b39f8fee4fefef4b6de9f31781c4386254b87275a8442538f4537861d42982d
+48922f366f22265217264c19203f16192614151811191c15141613191b18171715918f90
+fffefffffdfefafafcf8f8fafbfbfbfcfcfcfdfdfdffffffffffffffffffffffffffffff
+fcfffd8eb5893580233c951f3f9625459c2b41a0283fa72a419f25428a272e5f1d1c3f17
+1f391c28381b2e3d1c283c192131171b3011263e1c28401c2e4720324f1f33591c427028
+518f225aa330559e285f9e2974b33e5ba22a549b25579322568a25457c21559d2d6ece2c
+6fc9365396255fa51e63bf2e66b828bade84ffffbffffadafff9fdfffefffffffdfffdff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fefffafefcfdbbd9bd65a16573945f3c4a2915261ce0e0d8fdfdfbfffffffdfcff93b18b
+217112a8d3a5fffefafffff4f9ffe64a84373974204675244c7a3944952f357f20399322
+3d7a2a29541c203e181f3a191f361c1a241b161815161b151517141f211eb1b1b1fffeff
+fffefff8f6f9fffffffefffffafafafbfbfbfcfcfcfcfcfcfdfdfdfefefeffffffffffff
+fbfffa477e3a3b94263b932347992b49a42f43a52a42a527378e2332652320371a172a14
+1c33191d311828372025381c2f3f221c2f112034181b2f13283d1c35502332591a407122
+518f245fb4336bc23d5ba12770b73375d13268c02c62a12f4877264e85314a8b2358ad1c
+69c729b7f274afd86265a81b6bb8346d94399aa064f7f1d1ffffecfffff4fffdfffefcfd
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffafff9ffffd6e4d5526551383a245d5958b7c7c4fffbfffcfffffcfafbfffdfad8e1cc
+3f8636dbffd5f6fed7eeffadfffaee96c7852e62183f651c3d6e2d40a0254389313d9c26
+3064221d4115243b211f3520182919141a181516181218141116128a8c89fffffffdfbfe
+fbf9fcfcfcfefbfdfcf7fbfafcfcfcfbfbfbfafafaf9f9f9fafafafbfbfbfdfdfdffffff
+eff0ea3c762932931f338f22459b2c3e9e2345a22d469627347b1f26401b211c192a2b1b
+2b3a191c2c12202c18202e142738162437172b3f23213319213617264114325916477924
+5e9b265fbc2563c62e5198205fa8236fd52966c32c437b22457a22468723589327579e28
+60b526b4db6effffc5bfdc805ab122598d2b495733747959d1d6b6fefef6fffffafbfffa
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffafafaf555555e7e7e7fffffffefefefcfef9fbfffefffdfffffdf9
+b1ccabb5fbb5b8ffadb7e994e1f091f7ffcb6a79402e4d1435772f479b29489d2439962c
+2c59221f43171c2e16181a151914181a141819181617191410220ca0ac9efcfffffbf9ff
+fbfafffdfff5f6fef1f5fefbfafcf7fafbf6fbfaf6fdfcfafffafefdf8fefef9fffdf8fc
+fdfffc96ad912c601e1e6a0f33882142942e4b9838358021314d27192b13161e111c2218
+222d1d1825131b2616232b1e24311d1c2b1429391f2432192e3b212e481b396c1f4b922c
+5cb32e66c02aaceb5284b93746892870d0316bcb2b46702837602848672355882352ad22
+5dbd2580ba41d4e3a2ffffe6c6df8c61a52a34501f282f1f484f2ea8a8a0f4fffcfffdfd
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffefefefffffffffffffcfcfcfffffffdfdfdfffffffffffbf8fcfbfffefffffefb
+f0ffe99ed89e94d38c8dbb739aaf6ad3e09b717d4d1d440d3f912d48a731429829358820
+396e262a551d1e39181321121620181924161f2f14283e182d4d1b5e774de3f0dcfdfeff
+fffafffffbfffff8fefff9fffaf9fffdfcfffcfbfff9f9fbf8faf9f8fdf7fafff6f6fef1
+fcfbf7fffeffc1c6c25a715728551c24611328671629661920341b121d0d141510171715
+1b1e171820131820151c1f181c24171a251426361c1e36122c4f19316618408c2057b032
+50b72a7dd23feaff96e9fb8b638f2d62b92c68cc2e5b952e396d18385c1e406a2249912b
+5bb62b78bc459bbc85cce3affcffefa5c878528c261f32141b1515262f1ef6f4f7fffcff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffcfcfcfdfdfdfffffffffffffbfbfbfffffffafafafffcf9fbfffefbfcfffffcfd
+f8fff3aaceaa64905f658a56657b558a90545661362e652141a02c389d273c9227438629
+377124386b292a5122163412203b1a2d4c22365c233f6927325e0f4b74266e8c50bfcfb2
+e1e6dff7f7f5fffdfefef9fffffefffefdfffdfcfffffefffffefffffafffdf8fefffaff
+fbfbfdf9f8f6fffefbfffefddadadc99a39b586e5726461f151c141214111914181b161c
+18161717191611130e181a171719141e241a29382121461333711e3e90214bab265cc133
+5ec8347ac841d3da96ffffac9aaf5253932162c22d6fb8355da02c416d20375b1b3f7225
+529d1e72ba3c6c996087a26ddae3c8f8ffea41743195a88ae1d4deb1bab7fffdfffffff6
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffefefefffffffffffffcfcfcfffffffcfcfcfffffffffbfcfefffffbfffffffeff
+fefefce6f7e7536d523851333a483b56523775895640842d38962839972739872131651d
+255917346426355e24294e1832581f3c64263b6a24396b22305d2435631a34631239651a
+507937547b3a678e4d6e95567899628fac7caac49dc2d5b7dce8d4f2f8eefefcfffffbff
+fbfffdf6fffcf2f8f6fefcfffffafffffbfffffeffd7dcdf9f9f9f565457241f251a151b
+1210131919191517141a1f1b1722141f2c1a2b45222d601d45962d4baf2b4db42759bb30
+65c22c6cb24094a072faf9b6dce5a2527823529c2160a528538f2d4c7c263f60193e6121
+4e871e60a6295580395b6751768661d1e0cbb9c4b6fffffdfffafffbfdfcf7fff2fffeff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fbfbfbfffffffffffffafafafffffffffffffffffffefefefffcfefefffff8fcfdfffeff
+fffdfffdfffeb5c1b72634251a1b1f282921547b383885253d8e3146932d3b8025356625
+2f5c21346023365e2232581b355c1b345d1736641b39691d38682e437627427b1c468222
+3b78193f7d183d7e163d7e18397f0f377c12397b1a3d791f487f2b5f8f437ba56699be8a
+c5dccaeffbf1fffffbfffefffafafcf4f8f7fefffafefff5fdfbfeffffffd4d4d4727272
+2323231315141217112128201c3c15274c20356728367f2346a62b4db82c4fb52b55b230
+65bf2a5da341596e47c3ca9efaffdf798f4e477a1e437119284c1c3054143d5a20446328
+3b70204d95255a92312a38273d4039556d4dd6d2c9fefaf7fcfdfffffefff8fff0fffcff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffbfbfbfffffffffffffffffffbfbfbfffffffffffffffdfffffffffefffffcfcfe
+fffefffbf9fefeffffced3cd635e64374e342d6b18358025377b24347416336d21366a22
+33611936631e3c66263e6627426b29416c244874254878243c7318437d19518d29478329
+3f7b25437e243e761d457b2744801c4a8a294f932e48922349971d4f9c1c49951b47901d
+4b812367904aa3bc95e1ecdcfefffafefefcf6f4f7fcfbfffcfafdf8faf9fcfffbfcfffd
+d0d2d1696b6a191e180f19101b47122f63233e822f358c233ca0224fb63152b330449e22
+57ba2b579c434857387f836cfbfff5a1b37f345619334a20313d252c411a2d461f395b1f
+32671f3c8421599d263b622b1d140f101c10636a62fdfff2fbfff6fef9fdfffbfffeffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffefefefcfcfcfefefefefefefffffffdfdfdfffffffcfffffdfdfdfcfbf7fffffd
+fffffffffefffffffffcfdf8fdfff952834b307d1f347b1f42822b33711c3670233a7521
+407821447b274378263f72234475264475234b7d284d7d2744782342791e4680293b7626
+407b27467f214a7f23437221436d21416f24497e2c51922e62a93166b32f5aa72557a327
+5da32659a521559b1f649a3aa5c18eeff5e9fffdfff8f4fffcf7fdf9f9f9f7fcf6f3f8f2
+fefefefffeffc9c9c9646963182c131d4115336c27388229368822409329499d2e429626
+4fa72c58993d42513c53594beff5e7cdd5ae243912151f141f23121c25101f2c1a283c17
+2e4b1b406a283a6b122a4d177171654545474a534efbfffffefffffdfef9fffcffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffefefefffffffffffffcfcfcfffffffefefef9fffffffffffffefafffffb
+fcfffffefffffefcfdfffffbe4f2db3075252c821d478b2844842d3679293c7d2144832a
+45862845872643842045831e47831f3e77183f751d447825487727487c293b752034721c
+47892843851b458322477e2d4a7b22457924437e2442851e509a215ca92956a027549c2c
+549a285ca92966ba276bc22661af2579af51c6d9b9fcf9fff7f0f8f4f4f4f1f6f0f0f2ef
+f8f3f9f7f0f8fffdfffefefec9bbc8575f5413330a1c4e0f2f68213872263c7e273a8121
+4281195a9334354b3e334535aab499d1cdb02a341b1f2525141817131917101417161419
+1a17101f220d2b3421959d9ff0fffdfffcfffffefdfffffafffcfffefffffcfffbfffdfe
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffb6d4ae36722a388c1d4395263883243987243c872048892f
+4a8e2744842446822a39731e437f27417c2240762042721e426d1e44761d417825417a2b
+3f7b21418224448c294697214e952b54a02253a72d6caf3b529c235fa1256dbc2d5fa52b
+497a2154922765af346ec42b6ed12969c9295b9f24a7c39deff1fdecf0f1eaedf6ecefe8
+eff3e4edeee8eeecf9f4f1fafff9f9fbf7f6abada8434d421b2e1a1b361522461a335926
+305d26456d2f2d4d1e1a2c1e67706fb5b9ababada0e6e4e7e0e0e0dcdcdccdcdcdc7c7c7
+c4c4c4d5d5d5fafafaffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffbbd2b8306f1e419928418d293f86283d93263d952448932a
+428d24448a2835741b4180274686284684214d87234b811f4c86205492254b8c26428423
+4b9026519a2e53a63256b22b51b1295bb02f5ab92b71cf3d6dc93a4b9c1c65be2876ca36
+457b274078135fa52b5aa61f69c0316fcb2ab4f158b2ce60cad2abeef0efeff0f2eceaf7
+eeeeeceeeeeceff0eaecebf0eeeceff2f0f3fdfeffebeff0a1aaa54d5a501d2e1c10230d
+1831131d330c1b2b0e101914424649a2a59adce0d2fcfdfffefefefffffffefefeffffff
+fefefefcfcfcfffffffefefeffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffedf4ed458232348e1d3c872a48902d409e263ea4254ba72b
+499d2d3f8c2439811e478d2a42891f4b941f5aa12765a92e6bb63765b32b5cab2c56a12b
+56a52855a7295cb9345bc2294fbc2353b32b6dc12d67c22575cf3153a4245eab2775d52d
+5a9d364378204a8c2b4f8b275da82967bd28e7ffa9fafcd7d3de92e6e6dcf2f0f5f0f1eb
+eeedf3efeef3eeeeeef0f2e5efefefeeeef0efeef3f2f1f7faf9fff9f8fdcfcfd1959595
+63656452564855574c37363b1d1c21797c73dee1d8f1f5f6ecececeeeeeef4f4f4fefefe
+fffffffffffffffffffcfcfcffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffef9ff8ab57d2a7a173e932b459b2c40a32446b02c47ac28
+4ea930378e1b4c9e3053a63453ac2c5fba2f6bc53274ca356ec2366bc12a65b92d5bac2b
+5aaa2752a7255cbc345fc92b56b92a53c03168bd2e73ca2e71c92963ba2d5b9a2f71c62d
+6bbf33639d2d4e93264a7f274e90265fb12bc6dc8affffdaffffdfe9efafe2dedbf4f3f1
+edece8efeef4eaeaeceff2e9eaede4eef1eaeeeeecedebecf0eef1f3eef2f7f1f5fff9fb
+fbf5fff2eeeffdf9f8d0ced32a2a2c5f605af6f8f3e8eceff3f3f3f4f4f4f9f9f9fdfdfd
+fffffffffffffefefeffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffaffdeefdc49853b348e1d3ea02741a42649ac2b48ac2e
+48a7273e9a1d53af3353b43157be2e5fc92b6bd12f71d12f60b42a6ac02960b5245dae2b
+63b23249992049a12664c63560c1364ac02c5dc6355dc12175c3396ccc2c4d972663a331
+6cca2c70b4295ba8244a7f254c87295aa32d8ca34bc4c67dfcfed9fefde9dee0b9e6e4e5
+f3f2eef1f2ecefeef6edefeaf2f3ededeee9eeefeaf1f1efececeaeaeae8eeeeecf1f2ed
+ecebf1f7f7f5ebece7fbfbfbcccecdced0cbf9f9f7fefdfffcfcfcfefefeffffffffffff
+fffffffffffffdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffafffefdffa8c8a1307a1b3f9e2a4aa8304aa62946a52f
+44a32347a62654b83451ba2c57c42b66d03069c92a6fc52c58a7276cc02d67bc2b69bb35
+69b5394b952643912459ad315cc2324fb82756bd2eadf36eedffa9a6e15152a41c3b731c
+5db32a6eb63057a22b4e832b477c204c8a256578408b8b6fbdc491faf9f4fffefcccd1b3
+eff1e6eceaf5eeefe9ececececebf0ecebf0eeeef0eeeff1edeef0edf1f0ecf0efe7ebea
+f0f2efe9eee8ebf0eaeaefebf2f4f1f8faf7f7f7f7fefcfffffffffffffffffffffdfdfd
+fdfdfdfffffffefefeffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffbfdfafffdfffbfffa6f9564357c2040992545a329429f2c
+48a62c46a92b50b7344bb62a52bc265fbd2974be33649f1e519b2273c53370c63167bb31
+5dac2d589f354e94324993245db7315aba255ab12ee4ffb6ffffc9f3ffa07ab535366d1a
+468a236bb2325197234e8029406d1c3f6a2249612d515b39818867c3cba4fefffadbdecd
+e0e2d4f1f2eaefeef6f0f1ecebeaeff0eff4eeedf2ededefefeff1ecedefeaebedeff0f2
+eeefeaededebeef0efebf0ecf0f2f1ecececf9f7f8fffefdfefefeffffffffffffffffff
+fffffffffffffffffffefefeffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffff9fffafcfcfafff9ffe6f0e74a7c33388f1c40a22b459f2d
+3f9e2a46a82f4bb13149b42a51b62864b62ecbff8abbdf735ea52d76c83662bb215eb624
+58a9264d95293e8122458a1f579c2853bb1e66c14ae8fee7eafcc8ffffc8afcd69457d26
+4a802c5da225498c1b4d7f28496e293754243e57302c38244d5637717961c0cba3fbffe5
+c3c7b6fbfbfdf2f1f6efedeeefefedefefededeee9eeede9f0efedf0efedefedeeefedee
+f1ebebf3eef2efedf2ededefecedefefeff1f4f2f3fffef9fffffffffffffefefeffffff
+fefefefdfdfdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffafffefcfffffefffffeffffbdcebb41702c3e90223fa827
+46963544a92748b13044ac3148a92879cf62f4ffbdfdffac7ec13d66c13662b22d5ba72b
+54992c517e2939691f3a722b418923509e2e79c44dcbffd9daffe0ffffd8f8fac8518322
+3a672248741d4165284266263b622123461052722f1c34102a3024464d3d636b56babfa9
+c5c9b8f5f6eef8f8f8f3f0f9eeeeeef0f0f0efefefedededeeeeeef5f5f5fbfbfbfdfdfd
+fefefefefefefcfcfcfafafaf8f8f8f8f8f8fafafafcfcfcffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffdfffcfefdf9fef7fefffbfafff9aec6ac2e6720499f30
+3f9c2743a22a4dab314aa82c3fa1288de47ce0fec0fffcd691c6525eb02a599d2257942d
+4c8429426a21315e1b30621b32701b40841f68ac45b7f6bfceffebe6fcd5fdffe966843a
+2d4d1b254212162d1327411a32522319371146652a435e29191f13272d1f373e2e636758
+a6aa9ce6e7e1fffffff3f1f6f0f0f0efefefedededefefeff5f5f5fdfdfdffffffffffff
+fffffffffffffffffffffffffefefefdfdfdfefefefefefeffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffff7fffffefffcfff8fffff8fffafffffeffa4bea3407831
+439c2e499f3055ad354ea82d41a02c88d680cbfccdfffffa95b85a6ab131558d20436d25
+446c2d35561f274e193b5f21366521386f1b46832482c582b9fcd9c9fbd8f3fff9808d57
+2a3c14111e0a1f2a1934461c3c5420243e17253e16375019282d26151b111619102c2f26
+63645ed2d3cefdfdfbfdfdfdf5f5f5f2f2f2f0f0f0f3f3f3f9f9f9fefefefffffffefefe
+fefefeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffdfbfffefffafbfdfffffffffdfffffbfffbfffbb7cab6
+477b3b43842a52a53949a13048a23172b268befcd7effff488a35669ad34558329304921
+314927294121243f2033461934572134611e467f1e4b87417bbf84a7e2c2d0f0db899361
+2431131216171417101a220b233016232f231f272a38413066686360625d1b1d1a151716
+131313a1a19ffefefcfffffbfefefefcfcfcfbfbfbfcfcfcfefefefefefeffffffffffff
+fffffffffffffefefefefefeffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffcfffdfefffdfffffffefbfffefefefafbf3fffffbfffdff
+cddcc9557647407e3358a346499b3745813780bf90d3e6d07791525f9d384a722c243120
+233124202e211e2e242b301c263b1c2b4c1f37651a335f223b6b31659679a2c5af748656
+808d6fd1d5d4d7d7d5d0d0d2dadbdde9eaecfaf8fffffefbfefffdfeffffcacacc5e5e60
+464648cfcfcffcfcfafffffbffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffefefeffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffff9fffffbfdf8fffffbfffefffcfffffcfff8fffffafff9ff
+fffffaeff8f789a3884e7a3f38732f467f385f9058aab4a9677c514476313147211d2321
+27302d292e2a1d22251c1b1719221d22341e254021314c213043253b574066847a5d6e4c
+c0cbbafcfffffcfdf7fdfdfffffffdfefff5fffefffffdfafdfdfdfffffffffffffefeff
+fffffff9f9f9fffffdfffffdfffffffefefefdfdfdfffffffffffffffffffefefeffffff
+fffffffffffffffffffffffffffffffffffffffffffefefeffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffbfffffefffdfffffbfbfbf9fefffffcfefdfcfefdffffff
+fffef9fcfbfffcffffd2dec67a917561885c4c603d646a6a555e49536b51878882b9b7bc
+d1d7d3d4d3d1afb0b28381864c4d5223241e161f1c192414191d0f0d190d1e2e2e696f63
+e8edf3f6f5fffffcfffffefffbfdfcfefffdfffefffff9fffffffffcfcfefffffffcfcfc
+fffffffffffffffffffcfcfeffffffffffffffffffffffffffffffffffffffffffffffff
+fefefefefefefffffffffffffffffffffffffefefefefefeffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffbfffefffcfdfffffffdfffcf9fffdfffefffffbffff
+fffdfffbfffffefffffffbfefffbfdebf6eedcd3d4c3ced0e5e1def2f7fbfff9fffffbff
+fbfffafffefafffffdfcfdfff9f7f8dad0d1a9a7a87c8083797a6a84898399a29fd0c7ca
+f7fbecf2f1eff6f1f7fdfdfdfcfffdfbfffffafefdfefffafffefffffefffffffdfefefc
+fefefcfffffffffffffffefffffffffffffffffffffefefefefefefefefeffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+f3f3f3f2f2f2f3f3f3f7f7f7fcfcfcffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fdfdfdfcfcfcfbfbfbfcfcfcfefefefffffffffffffdfdfdffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffefefefefefefffffffffffffefefefefefeffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fefefefefefefefefefefefeffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fffffffffffffffffffffffffffffffefefefefefefefefeffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+fefefefefefefffffffffffffefefefefefeffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ffffffffffffffffffffffffffffffffffff
+
+showpage
+
+% stop using temporary dictionary
+end
+
+% restore original state
+origstate restore
+
+%%Trailer
diff --git a/doc/kdvi/index.docbook b/doc/kdvi/index.docbook
new file mode 100644
index 00000000..cd60e640
--- /dev/null
+++ b/doc/kdvi/index.docbook
@@ -0,0 +1,1072 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.1.2-Based Variant V1.1//EN"
+ "dtd/kdex.dtd" [
+ <!ENTITY kappname "&kdvi;">
+ <!ENTITY package "kdegraphics">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE"><!-- change language only here -->
+]>
+
+<book lang="&language;">
+ <bookinfo>
+ <title>The &kdvi; Handbook</title>
+ <authorgroup>
+ <author>
+ <firstname>Stefan</firstname>
+ <surname>Kebekus</surname>
+ <affiliation>
+ <address>
+ <email>kebekus@kde.org</email>
+ </address>
+ </affiliation>
+ </author>
+ <!-- TRANS:ROLES_OF_TRANSLATORS -->
+ </authorgroup>
+
+ <copyright>
+ <year>2001-2004</year>
+ <holder>Stefan Kebekus</holder>
+ </copyright>
+
+ <legalnotice>&FDLNotice;</legalnotice>
+
+ <date>2004-02-27</date>
+ <releaseinfo>1.11.00</releaseinfo>
+
+ <abstract>
+ <para>This document describes &kdvi; version 1.1</para>
+ </abstract>
+
+ <keywordset>
+ <keyword>KDE</keyword>
+ <keyword>linux</keyword>
+ <keyword>TeX</keyword>
+ <keyword>DVI</keyword>
+ </keywordset>
+
+ </bookinfo>
+
+ <chapter id="introduction">
+ <title>Introduction</title>
+
+ <para>&kdvi; is a plugin for the &kviewshell; program which allows
+ &kviewshell; to display &DVI;-files (<literal
+ role="extension">.dvi</literal>) which are produced by the TeX
+ typesetting system. &kdvi; supports many extensions of the &DVI;
+ standard, for instance the inclusion of &PostScript; graphics or
+ hyperlinks. More details, examples and all the technical
+ specifications can be found in the file
+ <filename>KDVI-features.dvi</filename> (or see
+ <filename>KDVI-features.tex</filename> for the TeX source of that
+ file).</para>
+
+ <para>For up-to-date information, consult <ulink
+ url="http://devel-home.kde.org/~kdvi">&kdvi;'s home page</ulink>.
+ </para>
+
+ <para>TeX is a high-end typesetting system geared towards
+ scientific, and in particular mathematical typesetting. More
+ information about TeX and &DVI; can be found on the <ulink
+ url="http://www.tug.org">homepage of the TeX user group</ulink> or
+ the German <ulink url="http://www.dante.de">German DANTE
+ e.V.</ulink>.
+ </para>
+ </chapter>
+
+
+ <chapter id="starting">
+ <title>Starting &kdvi;</title>
+
+ <para>Most of the time, &kdvi; will be started by just clicking
+ onto a <literal role="extension">.dvi</literal> file in the file
+ manager. For convenience there exists a command
+ <command>kdvi</command> which calls &kviewshell; with the &kdvi;
+ plugin preloaded. The viewer may thus be started using the command
+ <userinput><command>kdvi</command>
+ <parameter>somepath/paper.dvi</parameter></userinput>. The command
+ lines <userinput><command>kdvi</command>
+ <parameter>somepath/paper</parameter></userinput> or
+ <userinput><command>kdvi</command>
+ <parameter>somepath/paper.</parameter></userinput> will also
+ work. If you are connected to the internet, you can access files
+ which reside on other computers by giving a &URL; as a parameter,
+ like this: <userinput><command>kdvi</command>
+ <parameter>http://somepath/paper.dvi</parameter></userinput>
+ </para>
+
+ <para>If you give a &URL; as a parameter, you can tell &kdvi; to
+ jump directly to certain place of the &DVI; file.
+ For example, <userinput><command>kdvi</command>
+ <parameter>file:paper.dvi#43</parameter></userinput> will make
+ &kdvi; to open page 43. If you have included source file
+ information, a command like <userinput><command>kdvi</command>
+ <parameter>file:paper.dvi#src:43paper.tex</parameter></userinput>
+ will make &kdvi; search for the place in the &DVI; file which
+ corresponds to line 43 in the TeX file
+ <parameter>paper.tex</parameter>. You will hardly use this option
+ yourself &mdash; read the section on <link
+ linkend="forward-search">forward search</link> to learn how to
+ set up your editor to start &kdvi; automatically.
+ </para>
+
+ <warning><para>Don't forget the <userinput>file:</userinput>
+ prefix or it will give unexpected results. For example, the command
+ <userinput><command>kdvi</command>
+ <parameter>file:paper.dvi#43</parameter></userinput> will open
+ page 43 of the file <filename>paper.dvi</filename>. The command
+ <userinput><command>kdvi</command>
+ <parameter>paper.dvi#43</parameter></userinput> will try to open
+ the file <filename>paper.dvi#43</filename>.</para>
+ </warning>
+
+ <para>There is another option which you will most likely not need
+ to specify yourself. If you type
+ <userinput><command>kdvi</command> <parameter>--unique</parameter>
+ <parameter>somepath/paper.dvi</parameter></userinput>, &kdvi; will
+ load the file if there is no other instance running which has the
+ file already loaded. If there is, this instance of &kdvi; will pop
+ to the front. A command like <userinput><command>kdvi</command>
+ <parameter>--unique</parameter>
+ <parameter>file:paper.dvi#43</parameter></userinput> can be used
+ in shell scripts to make a running instance of &kdvi; to jump to
+ page 43.</para>
+
+ <para>The usual parameters handled by &Qt; and &kde; applications
+ also work: <userinput><command>kdvi</command>
+ <option>-style</option> <parameter>windows</parameter>
+ <option>-display</option> <parameter>:0</parameter>
+ <option>-geometry</option> <parameter>400x400+0+0</parameter>
+ <option>-caption</option> <parameter>&quot;DVI&quot;</parameter></userinput>
+ </para>
+ </chapter>
+
+
+ <chapter id="print">
+ <title>Printing &DVI; Files</title>
+
+ <para>&kdvi; can print your &DVI; files using the standard &kde;
+ printing interface. Internally, &kdvi; uses the program
+ <command>dvips</command> to generate &PostScript;, which is then
+ passed on to the printer. In particular, <command>dvips</command>
+ must be installed if you want to print with &kdvi;. The program
+ <command>dvips</command> uses its own configuration files and its
+ own settings, which are fine for most purposes. However, if you
+ care for optimal printing results, you should configure
+ <command>dvips</command> manually and make sure to set a default
+ MetaFont mode which fits your printer best &mdash; on many systems
+ you'll find a <ulink url="info:/dvips">GNU-texinfo documentation
+ of <command>dvips</command></ulink>, and you might also want to
+ look for a file called <filename>dvips.dvi</filename> or
+ similar.</para>
+ </chapter>
+
+ <chapter id="export">
+ <title>Exporting the &DVI; file to other formats</title>
+
+ <para>If you want to save your file as in &PostScript; or PDF
+ format, it is not recommended that you use the printing function
+ and redirect the printer output to a file. Instead, you can use
+ the export functions which produce better-quality output that
+ retains many of the special features of the dvi format and looks
+ better in many of the viewing applications, such as Adobe's
+ <application>Acrobat Reader</application>. You will find the
+ export functions in the <guimenu>File</guimenu> menu.</para>
+
+ <section id="export-ps">
+ <title>Exporting to &PostScript;</title>
+
+ <para>As in printing, the external program
+ <command>dvips</command> is used to generate the &PostScript;
+ file. If the &DVI; file contains hyperlinks, these will also be
+ included in the &PostScript; file. If you are an expert, and if
+ you would like to generate output which is optimized for a
+ specific printer, you should probably start
+ <command>dvips</command> manually and choose the proper MetaFont
+ mode yourself.</para>
+ </section>
+
+ <section id="export-pdf">
+ <title>Exporting to <acronym>PDF</acronym></title>
+
+ <para>In order to produce <acronym>PDF</acronym> files of high
+ quality, &kdvi; converts &DVI; to <acronym>PDF</acronym> using
+ the external program <command>dvipdfm</command>. If you are
+ working on a machine where an older distribution of the TeX
+ typesetting system is installed, it may be that the program
+ <command>dvipdfm</command> is not installed. In that case, you
+ need to use the printing function to generate
+ <acronym>PDF</acronym> output.</para>
+
+ <warning>
+ <itemizedlist>
+ <listitem>
+ <para>
+ If you use an older TeX installation, and if are viewing
+ the generated file in Adobe's <application>Acrobat
+ reader</application>, you may well find that some of the
+ fonts look extremely poor although a printout is fine,
+ and although the document looks ok in
+ <command>kghostview</command>. This is a known issue with
+ the <application>Acrobat Reader</application> and bitmap
+ fonts. At the time of writing, the only practicable
+ workaround seems to be to avoid bitmap fonts, or to
+ upgrade to a more recent TeX installation.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ While <command>dvipdfm</command> produces high-quality
+ <acronym>PDF</acronym> files, <command>dvipdfm</command>
+ currently currently ignores the &PostScript; that is
+ embedded into the &DVI; file. Embedded PostScript is
+ generated e.g. by the <application>xy</application> macro
+ package, or by the "Embed PostScript files" function
+ &kdvi; described <link linkend="embed">below</link>.
+ </para>
+ <para>
+ If you find that the generated <acronym>PDF</acronym>
+ file misses graphical data, use the print function of
+ &kdvi; instead.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </warning>
+ </section>
+
+
+ <section id="export-text">
+ <title>Exporting to text files</title>
+
+ <para>&kdvi; can also save your &DVI; files in text format.</para>
+
+ <warning>
+ <para>
+ The &DVI; file standard was not designed with this kind of
+ functionality in mind. This function therefore only works
+ well with standard ASCII characters. It will not work with
+ non-European languages. Depending on the fonts used in the
+ files, there may also be problems with accented characters or
+ umlauts, and sometimes with ligatures.
+ </para>
+ </warning>
+ </section>
+ </chapter>
+
+
+ <chapter id="embed">
+ <title>Embedding PostScript files into the &DVI;</title>
+
+ <para>The traditional way of using graphics with
+ <application>TeX</application> does not include the graphics data
+ directly in the &DVI; file. Instead, the &DVI; file contains only
+ a link to a graphics file which resides on the hard disk. The
+ advantage of this procedure is that the &DVI; file stays small,
+ and that the graphics file can be modified indepent of the
+ document's <application>TeX</application> source. The method,
+ however, becomes fairly inconvenient if you intend to archive the
+ &DVI; file, or if you wish to send it to someone else: rather than
+ handling a single file, you have to deal with a multitude of
+ files, which need to be kept in exactly the place specified in the
+ &DVI; file for everything to work.</para>
+
+ <para>For that reason, &kdvi; allows you to embed external
+ &PostScript; files into your &DVI; file. To embed all &PostScript;
+ files into a &DVI; file, use the menu entry <guimenu>Edit/Embed
+ external PostScript files</guimenu> </para>
+
+ <warning> <para>&DVI; files with embedded &PostScript; work fine
+ with most other &DVI; handling software,
+ e.g. <application>xdvi</application>,
+ <application>dvips</application> or
+ <application>dvipdf</application>. One notable exception is the
+ <application>dvipdfm</application> program, which currently
+ ignores the embedded &PostScript;. Since
+ <application>dvipdfm</application> is used internally by the
+ "Export to <acronym>PDF</acronym>" function of &kdvi;, expect
+ problems when you use that function. The same issue shows with
+ other software that uses embedded PostScript, e.g. the
+ <application>TeX</application> <application>xy</application> macro
+ package.</para> </warning>
+ </chapter>
+
+
+ <chapter id="inverse-search">
+ <title>Using inverse search</title>
+ <anchor id="inv-search"></anchor>
+
+ <para>Inverse search is a very useful feature when you are writing
+ a TeX document yourself. If everything is properly set up, you can
+ click into &kdvi;'s window with the
+ <mousebutton>middle</mousebutton> mouse button (on some systems,
+ when you don't have a three-button mouse, you can simultaneously
+ use the <mousebutton>left</mousebutton> and the
+ <mousebutton>right</mousebutton> button). After that, your
+ favorite editor will open, load the TeX source file and jump to
+ the proper paragraph. To use inverse search, do the
+ following:</para>
+
+
+ <procedure>
+ <step>
+ <para>Produce a &DVI; file that contains inverse search
+ information. This is explained in the section <link
+ linkend="inverse-search-tex">Producing TeX files for inverse
+ search</link> below. If you just want to test the inverse
+ search feature, you can also use the example file
+ <filename>KDVI-features.dvi</filename></para>
+ </step>
+ <step>
+ <para>Let &kdvi; know which editor you would like to
+ use. Choose an editor in the <guilabel>Preferences</guilabel>
+ dialog (this dialog can be reached by choosing
+ <guimenuitem>DVI Options</guimenuitem> in the
+ <guimenu>Settings</guimenu> menu). The next section of this
+ documentation, <link linkend="opt-rendering">Rendering
+ Options</link>, explains this dialog in more detail.</para>
+ </step>
+ <step>
+ <para>Some editors need to be started manually, or need
+ additional configuration. You will find a description of all
+ supported editors in the section <link
+ linkend="inverse-search-editor">Setting up your
+ editor for inverse search</link> below.</para>
+ </step>
+ <step>
+ <para>Test your setup. Open your &DVI; file in &kdvi; and use
+ the <mousebutton>middle</mousebutton> mouse button to click
+ into &kdvi;. The editor should pop up and display the TeX
+ file.</para>
+ </step>
+ </procedure>
+
+
+ <section id="inverse-search-tex">
+ <title>Producing TeX files for inverse search</title>
+ <para>There are essentially two ways to produce &DVI; files
+ which contain inverse search information: you can either use a
+ TeX/LaTeX binary which generates and includes the necessary
+ information automatically, or you can include an extra package
+ which is written in TeX/LaTeX.</para>
+ <itemizedlist>
+ <listitem>
+ <para>A TeX binary which generates and includes the
+ necessary information automatically is certainly the
+ preferred method of including inverse search information.
+ If you use version 2 or greater of the <ulink
+ url="http://www.tug.org/teTeX/">TeTeX TeX
+ distribution</ulink>, you can use the 'src-specials' command
+ line option of the tex or latex command, as follows.
+<programlisting>
+tex --src-specials myfile.tex
+</programlisting>
+or
+<programlisting>
+latex --src-specials myfile.tex
+</programlisting>
+ </para>
+ </listitem>
+ <listitem>
+ <para>If you do not have a TeX binary which includes inverse
+ search information natively, copy the files
+ <ulink url="srcltx.sty">
+ <filename>srcltx.sty</filename> </ulink> and
+ <ulink url="srctex.sty"> <filename>srctex.sty</filename>
+ </ulink> to the folder where your TeX file resides (you
+ can do that by pressing the &Shift; key and &LMB; while the
+ mouse pointer is on a hyperlink.) If you use LaTeX, add the
+ line
+<programlisting>
+\usepackage[active]{srcltx}
+</programlisting>
+ to the preamble of your LaTeX file. If you use plain TeX, the line
+<programlisting>
+\include{srctex}
+</programlisting>
+ will do the trick.</para>
+ </listitem>
+ </itemizedlist>
+
+ <tip>
+ <para>While inverse search is extremely useful when you are
+ typing a document yourself, it might be a good idea to remove
+ the inverse search information before sending the &DVI; file to
+ someone else.</para>
+ </tip>
+
+ </section>
+
+ <section id="inverse-search-editor">
+
+ <title>Setting up your editor for inverse search</title>
+
+ <para>While inverse search works generally very well with most
+ editors, some of them require a bit of extra care. This section
+ explains how to configure your editor.</para>
+
+ <section id="editor-setup-emacs">
+ <title><application>Emacs</application></title>
+
+ <para><application>Emacs</application> works well with
+ &kdvi;. The actual behavior of <application>Emacs</application>
+ depends largely on the configuration. As usual, you can
+ customize <application>Emacs</application> completely, if you
+ are willing to fight your way through Lisp code.</para>
+
+ <para>&kdvi; uses the program <command>emacsclient</command> to
+ remote control <application>Emacs</application>.</para>
+ <important>
+ <para>The program <command>emacsclient</command> requires that
+ <application>Emacs</application> is running, and that the
+ program <application>Emacs Server</application> is started inside
+ <application>Emacs</application>. Inverse search will not work
+ optimally unless you have started both
+ <application>Emacs</application> and the <application>Emacs
+ Server</application>.</para>
+ </important>
+
+ <para>To start the <application>Emacs Server</application>, you can do
+ one of the following:</para>
+ <itemizedlist>
+ <listitem>
+ <para>In <application>Emacs</application>, start the
+ <application>Emacs Server</application> by typing
+ <userinput><keycombo action="seq"><keycap>M</keycap><keycap>X</keycap></keycombo>
+ <command>server-start</command></userinput></para>
+ </listitem>
+ <listitem>
+ <para>Add the line
+<programlisting>
+(server-start)
+</programlisting>
+ to your <filename>.emacs</filename> file. Restart
+ <application>Emacs</application></para>
+ </listitem>
+ </itemizedlist>
+
+
+ <tip>
+ <itemizedlist>
+ <listitem>
+ <para>Make sure that <application>Emacs</application> is
+ installed. Try to start <command>emacs</command> from
+ the command line.</para>
+ </listitem>
+ <listitem>
+ <para>&kdvi; uses the command
+ <command>emacsclient</command> to remote control
+ <application>Emacs</application>. Make sure that
+ <command>emacsclient</command> is available on the
+ command line by trying the command
+ <userinput><command>emacsclient</command>
+ <parameter>Name of a text
+ file</parameter></userinput>. This should open a new
+ text in the <application>Emacs</application>
+ editor.</para>
+ </listitem>
+ <listitem>
+ <para>If <command>emacsclient</command> fails with an
+ error message like <computeroutput>unable to connect to
+ local</computeroutput>, make sure that
+ <application>Emacs</application> is
+ running. Furthermore, make sure that the
+ <application>Emacs Server</application> is started by typing
+ <userinput><keycombo action="seq"><keycap>M</keycap><keycap>x</keycap></keycombo>
+ <command>server-start</command></userinput>.</para>
+ </listitem>
+ <listitem>
+ <para>If you want the frame to be auto-raised, add the
+ <function>raise-frame</function> function to
+ <quote>server-switch-hook</quote> (do
+ <userinput><keycombo action="seq"><keycap>M</keycap><keycap>x</keycap></keycombo>
+ <command>customize-variable</command>
+ <keycap>RET</keycap>
+ <command>server-switch-hook</command></userinput> and
+ enter the function name into the text field.</para>
+ </listitem>
+ <listitem>
+ <para>If you have changed the buffer since your last
+ save, <application>Emacs</application> will ask you:
+ <computeroutput>Revert buffer from file ...? (yes or
+ no)</computeroutput>. You will probably always want to
+ say <emphasis>no</emphasis> here, since reverting means
+ that the file is reread from disk, <emphasis>causing all
+ your changes since the last save to be
+ lost!</emphasis></para>
+
+ <para><command>gnuclient</command>'s behavior
+ of silently reloading the changed buffer is probably
+ preferable &mdash; add the following lines to your
+ <filename>.emacs</filename> file to emulate
+ <command>gnuclient</command>'s behavior with
+ <command>emacsclient</command>:</para>
+
+<programlisting>
+(defadvice server-visit-files (around save-buffers last activate)
+ "Try to emulate gnuclient behavior with emacsclient.
+Works only for visiting one buffer at a time."
+ (let* ((filen (car (car (ad-get-arg 0))))
+ (buf (get-file-buffer filen))
+ (this-buf-modified-p nil))
+ ;;; the following is copied from server-visit-files, with
+ ;;; a modification for the `verify-visited-file-modtime' test
+ (if (and buf (set-buffer buf))
+ (if (file-exists-p filen)
+ ;;; if the file has changed on disk, reload it
+ ;;; using `find-file-noselect'
+ (if (not (verify-visited-file-modtime buf))
+ (progn
+ (find-file-noselect filen)
+ ;;; if user answered `no', reset modtime anyway
+ ;;; so that server-visit-files doesn't realize the
+ ;;; difference:
+ (set-visited-file-modtime)))
+ ;;; if file exists no longer, we let server-visit-files
+ ;;; deal with that
+ t)
+ (setq buf (find-file-noselect filen)))
+ (setq this-buf-modified-p (buffer-modified-p buf))
+ (set-buffer buf)
+ (set-buffer-modified-p nil)
+ ad-do-it
+ (set-buffer-modified-p this-buf-modified-p)))
+</programlisting>
+ </listitem>
+ </itemizedlist>
+ </tip>
+ </section>
+
+
+ <section id="editor-setup-kate">
+ <title>&kate;</title>
+
+ <para>&kde;'s editor &kate; supports inverse search very well.
+ No extra setup is required.</para> </section>
+
+
+ <section id="editor-setup-kile">
+ <title><application>Kile</application></title>
+
+ <para>The LaTeX-editor system <application>Kile</application>,
+ supports KDVI very well. No extra setup is
+ necessary. Further information about Kile can be found at
+ <ulink url="http://kile.sourceforge.net">Kile's
+ homepage</ulink>.
+ </para>
+ </section>
+
+
+ <section id="editor-setup-nedit">
+ <title><application>NEdit</application></title>
+
+ <para><application>NEdit</application> generally works very well
+ indeed. Clicking into the &DVI; file should open a new
+ window. If the TeX file is already used in another window of
+ <application>NEdit</application>, the newly opened window
+ displays another view of the buffer. Otherwise, the TeX file is
+ loaded. After opening the window,
+ <application>NEdit</application> highlights the first line of
+ the appropriate paragraph.</para>
+ <tip>
+ <para>&kdvi; uses the command <command>ncl</command> to
+ remote control <application>NEdit</application>. Make sure
+ that <command>ncl</command> is available on the command line
+ by trying the command <userinput><command>ncl</command>
+ <parameter>-noask</parameter></userinput>. This should
+ open an instance of the <application>NEdit</application>
+ editor. If <command>ncl</command> is not available, you
+ might be using an older version of
+ <application>NEdit</application>. In that case, you should
+ either upgrade to a more recent version, or you have to use
+ the option <guilabel>User defined editor</guilabel> from the
+ <guilabel>Options</guilabel> dialog.</para>
+ </tip>
+ </section>
+
+ <section id="editor-setup-xemacs">
+ <title><application>XEmacs</application></title>
+
+ <para><application>XEmacs</application> works well with
+ &kdvi;. The actual behavior of
+ <application>XEmacs</application> depends largely on the
+ configuration. As usual, you can customize
+ <application>XEmacs</application> completely, if you are willing
+ to fight your way through Lisp code.</para>
+
+ <para>&kdvi; uses the program <command>gnuclient</command> to
+ remote control <application>XEmacs</application>.</para>
+ <important>
+ <para>The program <command>gnuclient</command> requires that
+ <application>XEmacs</application> is running, and that the
+ program <application>gnuserv</application> is started inside
+ <application>XEmacs</application>. Inverse search will not
+ work unless you have started both
+ <application>XEmacs</application> and
+ <application>gnuserv</application>.</para>
+ </important>
+
+ <para>To start the <application>gnuserv</application> program, you can
+ do one of the following:</para>
+ <itemizedlist>
+ <listitem>
+ <para>In <application>XEmacs</application>, start
+ <application>gnuserv</application> by typing
+<userinput><keycombo action="seq"><keycap>M</keycap><keycap>X</keycap></keycombo>
+ <command>gnuserv-start</command></userinput></para>
+ </listitem>
+ <listitem>
+ <para>Add the line
+<programlisting>
+(gnuserv-start)
+</programlisting>
+ to your <filename>.xemacs</filename> file. If you use a
+ more recent version of <application>XEmacs</application>,
+ <filename class="directory">.xemacs</filename> will be a
+ folder. In that case, you should append the line to the
+ file <filename>.xemacs/init.el</filename>. Restart
+ <application>XEmacs</application></para>
+ </listitem>
+ </itemizedlist>
+
+ <para>If you don't want to open a new frame for each editor
+ call, and want the frame to be auto-raised, set <quote>Gnuserv
+ Frame</quote> to <quote>Use selected frame</quote>, and add the
+ <function>raise-frame</function> function to <quote>Visit
+ Hook</quote>. Do <userinput><keycombo action="seq"><keycap>M</keycap><keycap>x</keycap></keycombo>
+ <command>customize-group</command> <keycap>RET</keycap>
+ <command>gnuserv</command></userinput> to make these
+ settings.</para>
+
+ <tip>
+ <itemizedlist>
+ <listitem>
+ <para>Make sure that <application>XEmacs</application>
+ is installed. Try to start <command>xemacs</command>
+ from the command line.</para>
+ </listitem>
+ <listitem>
+ <para>&kdvi; uses the command <application>gnuserv</application>
+ to remote control
+ <application>XEmacs</application>. Make sure that
+ <command>gnuclient</command> is available on the command
+ line by trying the command
+ <userinput><command>gnuclient</command> <parameter>Name
+ of a text file</parameter></userinput>. This should open
+ a new frame in the <application>XEmacs</application>
+ editor.</para>
+ </listitem>
+ <listitem>
+ <para>If <application>gnuserv</application> fails with an error
+ message like <computeroutput>unable to connect to
+ local</computeroutput>, make sure that
+ <application>XEmacs</application> is
+ running. Furthermore, make sure that
+ <application>gnuserv</application> is started by typing
+ <userinput><keycombo action="seq"><keycap>M</keycap><keycap>X</keycap></keycombo>
+ <command>gnuserv-start</command></userinput>.</para>
+ </listitem>
+ <listitem>
+ <para>If you don't want to open a new frame for each
+ editor call, and want the frame to be auto-raised, set
+ <quote>Gnuserv Frame</quote> to <quote>Use selected
+ frame</quote>, and add the <quote>raise-frame</quote>
+ function to <quote>Visit Hook</quote>. Do
+ <userinput><keycombo action="simul"><keycap>M</keycap><keycap>X</keycap></keycombo>
+ <command>customize-group</command> <keycap>RET</keycap>
+ <command>gnuserv</command></userinput> to make these
+ settings.</para>
+ </listitem>
+ </itemizedlist>
+ </tip>
+ </section>
+
+ <section id="editor-setup-gvim">
+ <title><application>VI iMproved</application> / &GUI;</title>
+
+ <para>The <application>gvim</application> variant of the
+ <application>vi</application> editor supports inverse search very well.
+ No extra setup is required.</para>
+ </section>
+ </section>
+ </chapter>
+
+
+ <chapter id="forward-search">
+ <title>Forward search</title>
+
+ <para>The forward search functions allow you to jump from your
+ editor directly into the associated position of the &DVI;
+ file. Since forward search must be supported by your editor, only
+ <application>Emacs</application> and
+ <application>XEmacs</application> are currently supported. Other
+ editors will hopefully join in soon.</para>
+
+ <para>To use forward search, you have to do the following:</para>
+ <itemizedlist>
+ <listitem>
+ <para>Set up your editor &mdash; this is described below.</para>
+ </listitem>
+ <listitem>
+ <para>Add source file information to your &DVI; file, &eg; by
+ using the package <command>srcltx</command>. This has been
+ described in the section <link linkend="inverse-search-tex">Producing TeX files for inverse
+ search</link>.</para>
+ </listitem>
+ <listitem>
+ <para>If you use <application>Emacs</application> and
+ everything is properly set up, you just press
+ <userinput><keycombo action="simul">&Ctrl;<keycap>X</keycap></keycombo> <keycombo
+ action="simul">&Ctrl;<keycap>J</keycap>
+ </keycombo></userinput>, and &kdvi; pops up and jumps to the
+ place which corresponds to the place of the TeX file which you
+ are currently editing.</para>
+ </listitem>
+ </itemizedlist>
+
+ <section id="forward-search-editor">
+ <title>Setting up your editor for forward search</title>
+
+ <section id="forw-editor-setup-emacs">
+ <title><application>Emacs</application></title>
+
+ <para>In order to use forward search in
+ <application>Emacs</application>, follow these steps:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Download the following
+ <application>Emacs</application> script,
+ <ulink url="kdvi-search.el">
+ <filename>kdvi-search.el</filename> </ulink> (press
+ &Shift; and &LMB; the filename to download) and store
+ it in a place where <application>Emacs</application>
+ can access it &mdash; we recommend a folder
+ <filename class="directory">emacs-scripts</filename>.</para>
+ </listitem>
+ <listitem>
+ <para>Add the lines
+<programlisting>
+(add-to-list 'load-path (expand-file-name "~/emacs-scripts/"))
+(require 'kdvi-search)
+(add-hook 'LaTeX-mode-hook (lambda () (local-set-key "\C-x\C-j" 'kdvi-jump-to-line)))
+(add-hook 'tex-mode-hook (lambda () (local-set-key "\C-x\C-j" 'kdvi-jump-to-line)))
+</programlisting>
+ to your <filename>.emacs</filename> file. Restart
+ <application>Emacs</application>.</para>
+ </listitem>
+
+ <listitem>
+ <para>Open <application>Emacs</application>, load a
+ TeX file, produce the corresponding &DVI; file, and either
+ enter the command <userinput><keycombo action="simul"><keycap>M</keycap><keycap>x</keycap>
+ </keycombo><command>kdvi-jump-to-line</command></userinput>
+ or press <userinput><keycombo action="seq"><keycombo
+ action="simul">&Ctrl;<keycap>X</keycap></keycombo>
+ <keycombo action="simul">&Ctrl;<keycap>J</keycap></keycombo>
+ </keycombo></userinput>.
+ It may happen that <application>Emacs</application> asks
+ you for the name of a <quote>master file</quote>. This is
+ useful if you use a TeX file which includes other files:
+ the master file is the top-level file which includes the
+ others. <application>Emacs</application> will perhaps also
+ ask to save the name of the master file <quote>as a local
+ variable</quote>, &ie; as a comment at the very end of the
+ file. Type either <userinput>yes</userinput> or
+ <userinput>no</userinput> to continue.</para>
+ </listitem>
+ </itemizedlist>
+
+ <tip>
+ <itemizedlist>
+ <listitem>
+ <para>Make sure that <application>Emacs</application> is
+ installed. Try to start <command>emacs</command> from
+ the command line.</para>
+ </listitem>
+ <listitem>
+ <para>If <application>Emacs</application> fails to start
+ &kdvi;, you can find its output in the Buffer
+ <guilabel>kdvi-output</guilabel>.</para>
+ </listitem>
+ </itemizedlist>
+ </tip>
+ </section>
+
+ <section id="forw-editor-setup-kile">
+ <title><application>Kile</application></title>
+ <para>If you use Kile, no further setup is necessary.
+ </para>
+ </section>
+
+ <section id="forw-editor-setup-xemacs">
+ <title><application>XEmacs</application></title>
+
+ <para>To set up <application>XEmacs</application>, follow the
+ steps for <application>Emacs</application> <link
+ linkend="forw-editor-setup-emacs">above</link>, but modify
+ your <filename>.xemacs</filename> rather than your
+ <filename>.emacs</filename> file. If you use a very recent
+ version of <application>XEmacs</application>, <filename
+ class="directory">.xemacs</filename> may be a folder. In
+ that case, append the lines to
+ <filename>.xemacs/init.el</filename>.
+ </para>
+ </section>
+
+ </section>
+
+ </chapter>
+
+ <chapter id="preferences">
+ <title>The <guilabel>Preferences</guilabel> dialog</title>
+ <anchor id="opts"></anchor>
+
+ <para>The <guilabel>Preferences</guilabel> dialog can be reached
+ by choosing <guimenuitem>DVI Options</guimenuitem> in the
+ <guimenu>Settings</guimenu> menu.</para>
+
+ <para>The dialog consists of two tabs, <guilabel>Fonts</guilabel>
+ and <guilabel>Rendering</guilabel>.</para>
+
+ <sect1 id="opt-fonts">
+ <title><guilabel>Fonts</guilabel> Options</title>
+
+ <para>
+ Traditionally, the TeX typsetter uses fonts that are generated
+ by the <command>MetaFont</command> program. These fonts are
+ stored in the PK format. While a carefully configured
+ <command>MetaFont</command> system produces printouts of
+ highest quality, its configuration requires serious expertise,
+ <command>MetaFont</command> is not very good at producing fonts
+ suitable for computer displays, and there are only few
+ <command>MetaFont</command> fonts available for Asian
+ languages.
+ </para>
+
+ <para>
+ To overcome these problems, newer TeX installations therefore
+ include fonts that are stored in the "PostScript Type 1"
+ format, which is a widely used font format in electronic
+ publishing. &kdvi; is able to use both font formats.
+ </para>
+
+ <para>
+ The following picture shows the font options dialog of &kdvi;
+ that can be used to control &kdvi;'s use of the various font
+ formats.
+ </para>
+
+ <screenshot>
+ <screeninfo>The <guilabel>Fonts</guilabel> tab</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="optionrequester1.png" format="PNG"></imagedata>
+ </imageobject>
+ <textobject>
+ <phrase>The <guilabel>Fonts</guilabel> tab</phrase>
+ </textobject>
+ </mediaobject>
+ </screenshot>
+
+ <variablelist>
+ <varlistentry>
+ <term><guilabel>Use font hinting for Type 1 fonts, if available</guilabel> </term>
+ <listitem>
+ <para>
+ PostScript "Type 1" often contain "font hints",
+ i.e. additional information that is supposed to
+ help software produce better quality output on
+ computer screens. The quality of the font hints
+ varies from font to font, and you should experiment
+ to see if enabling this option gives better results.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect1>
+
+ <sect1 id="opt-rendering">
+ <title><guilabel>&DVI; specials</guilabel> Options</title>
+
+ <para>
+ &kdvi; supports a large number of extensions to the original
+ &DVI; format, e.g. hyperlinks, graphic file inclusion or
+ embedded source file information. These extensions are known as
+ "&DVI; specials". A full account of specials supported by
+ &kdvi; can be found in <ulink url="KDVI-features.dvi">this
+ document</ulink>.
+ </para>
+
+ <para>
+ The &DVI; specials dialog help you to configure support for
+ some specials. </para>
+
+ <screenshot>
+ <screeninfo>The <guilabel>Rendering</guilabel> tab</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="optionrequester2.png"
+ format="PNG"></imagedata>
+ </imageobject>
+ <textobject>
+ <phrase>The <guilabel>Rendering</guilabel> tab</phrase>
+ </textobject>
+ </mediaobject>
+ </screenshot>
+
+ <variablelist>
+ <varlistentry>
+ <term><guilabel>Show PostScript specials</guilabel></term>
+ <listitem>
+ <para>If this option is checked, &kdvi; will display
+ &PostScript; graphics which are embedded into the &DVI;
+ file. You probably want to set this option.</para>
+
+ <para>If an external &PostScript; file could not be found,
+ &kdvi; will draw a red warning box in its
+ place. Unfortunately, rendering &PostScript; graphics is
+ very slow in the current version of &kdvi;. We will
+ improve on the speed in later versions. If this option is
+ off, &kdvi; will either draw a gray box as a placeholder
+ for the graphics, or it will leave the space blank.</para>
+
+ <note>
+ <para>There is no standard way to embed &PostScript;
+ graphics into a &DVI; file. It may therefore happen that
+ &kdvi; cannot properly display a graphic which works
+ fine with other programs. Older versions of
+ <command>xdvi</command> and <command>dvips</command>
+ support the execution of external commands. This is a
+ bad security risk and therefore deliberately not
+ implemented in &kdvi;. Technical information about
+ supported ways to include &PostScript; can be found in
+ the document
+ <filename>KDVI-features.dvi</filename>.</para>
+ </note>
+
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><guilabel>Editor for inverse search</guilabel></term>
+ <listitem>
+ <para>If you intend to use <link linkend="inverse-search">inverse search</link>, a
+ very useful feature if you write TeX documents yourself,
+ you have to specify which editor you are going to use, and
+ how this editor can be started by &kdvi;. In the example
+ shown, the user has opted for the
+ <application>NEdit</application> editor. If you use one of
+ the pre-configured editors from the
+ <guilabel>Editor</guilabel> combobox, then you don't have
+ to do anything else. If you whish to use a different
+ editor, chose <guilabel>User-defined editor</guilabel>
+ from the <guilabel>Editor</guilabel> combobox and enter
+ the command line which will be used to start your
+ editor. Use the placeholders <token>%f</token> and
+ <token>%l</token> which will be replaced with the name of
+ the TeX file, and the line of the TeX file,
+ respectively.</para>
+
+ <para>If you use an editor which is not supported, please
+ send us an email at <email>kebekus@kde.org</email> and tell us
+ about the command line you use and how you have configured
+ your editor.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ </sect1>
+ </chapter>
+
+ <chapter id="faq">
+ <title>Frequently asked questions</title>
+
+ <qandaset>
+ <qandaentry>
+ <question id="fontgen">
+ <para>What happens when &kdvi; displays the message
+ <computeroutput>KDVI is currently generating bitmap
+ fonts</computeroutput>, and why does
+ the procedure take so long?</para>
+ </question>
+ <answer>
+ <para>Many of the fonts which are typically used in a TeX
+ document must be generated by the MetaFont system. Metafont
+ is a language similar to TeX (included in most TeX
+ distributions) which takes a description of the font
+ outline, and produces a rasterized version (<literal
+ role="extension">.pk</literal> file) of the font which can
+ then be send to a printer or be used in a previewing program
+ like &kdvi;. Metafont goes out of its way to produce the
+ best possible output for your printer. For instance, it
+ knows that a pixel of an inkjet printer is a roundish blot,
+ and that nearby pixels tend to smear into each other. In
+ contrast, a pixel on a laser printer is rectangular, but an
+ isolated pixel is very often not rendered at all.</para>
+
+ <para>Generating such highly optimized bitmap fonts is
+ naturally rather time-consuming, in particular since typical
+ TeX documents use a large number of different fonts. We can
+ only ask for your patience. To ease the matter somewhat,
+ most distributions of TeX store the <literal
+ role="extension">.pk</literal> files for a limited time,
+ &eg; 100 days. Therefore, if you access the same document
+ more than once, the <literal role="extension">.pk</literal>
+ files will be reused.</para>
+ </answer>
+ </qandaentry>
+
+ <qandaentry>
+ <question id="mfmodes">
+ <para>What is a MetaFont Mode?</para>
+ </question>
+ <answer>
+ <para>In order to produce bitmap fonts which are optimized
+ for your printer (see the answer to the first question),
+ Metafont comes with a database of printing engines &mdash; look
+ for a file called <filename>modes.mf</filename>. A Metafont
+ Mode is just the name of a database entry. For example, the
+ name <quote>ljfour</quote> refers to the entry in the
+ database that describes a &Hewlett-Packard; LaserJet 4
+ printer. A MetaFont Mode is usually followed by a number,
+ the resolution. The LaserJet, for instance, can print in both
+ 300 and 600 dots per inch. Thus, <quote>ljfour/600</quote>
+ would be a full description.</para>
+ </answer>
+ </qandaentry>
+
+ </qandaset>
+ </chapter>
+
+
+ <chapter id="credits-and-license">
+ <title>Credits and Licenses</title>
+
+ <para>&kdvi;</para>
+
+ <para>&kdvi; is based on based on the stand-alone-program &kdvi;
+ 0.4.3 by Markku Hihnala. That program is in turn based on
+ <application>xdvi</application> version 18f which has many
+ authors.</para>
+
+ <para>Documentation is copyright 2001-2004, Stefan Kebekus
+ <email>kebekus@kde.org</email></para>
+
+ <!-- TRANS:CREDIT_FOR_TRANSLATORS -->
+
+&underGPL;
+&underFDL;
+
+ </chapter>
+
+&documentation.index;
+
+</book>
+<!--
+Local Variables:
+mode: sgml
+sgml-omittag: nil
+sgml-shorttag: t
+End:
+-->
+
diff --git a/doc/kdvi/kdvi-search.el b/doc/kdvi/kdvi-search.el
new file mode 100644
index 00000000..d08dd07e
--- /dev/null
+++ b/doc/kdvi/kdvi-search.el
@@ -0,0 +1,102 @@
+;;; (X)Emacs frontend to forward search with kdvi. See the section on
+;;; FORWARD SEARCH in the kdvi manual for more information on forward
+;;; search, and for an explanation how to use this script. This script
+;;; is a modified version of the script "xdvi-search.el" by Stefan
+;;; Ulrich <ulrich@cis.uni-muenchen.de>, version 2000/03/13. The
+;;; modifications were performed by Stefan Kebekus
+;;; <kebekus@kde.org>. Tested with Emacs 20.7.1 and Xemacs 21.4.
+;;;
+;;; 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.
+;;;
+;;; Please report bugs or improvements, etc. via the "Report bug"-Menu
+;;; of kdvi.
+;;;
+
+(defvar kdvi-script "kdvi"
+ "*Name of start script for kdvi.")
+
+(defun kdvi-jump-to-line ()
+ "Call kdvi-script to perform a `forward search' for current file and line number.
+See contents of kdvi-script for details.
+If AucTeX is used, the value of TeX-master-file is used as filename
+for the master .dvi file; else, the return value of kdvi-master-file-name
+is used (which see)."
+ (interactive)
+ (save-excursion
+ (save-restriction
+ (widen)
+ (beginning-of-line 1)
+ (let* (;;; current line in file, as found in the documentation
+ ;;; of emacs. Slightly non-intuitive.
+ (current-line (format "%d" (+ 1 (count-lines (point-min) (point)))))
+ ;;; name of the `main' .tex file, which is also used as .dvi basename:
+ (master-file (expand-file-name (if (fboundp 'TeX-master-file)
+ (TeX-master-file t)
+ (kdvi-get-masterfile (kdvi-master-file-name)))))
+ ;;; .dvi file name:
+ (dvi-file (concat (file-name-sans-extension master-file) ".dvi"))
+ ;;; current source file name.
+ (filename (expand-file-name (buffer-file-name))))
+ (start-process "kdvi"
+ "kdvi-output" "kdvi" ;;; src-args
+ ;;; args for -sourceposition:
+ "--unique" (concat "file:" dvi-file "#src:" current-line filename)
+ )))))
+
+(defun kdvi-get-masterfile (file)
+ "Small helper function for AucTeX compatibility.
+Converts the special value t that TeX-master might be set to
+into a real file name."
+ (if (eq file t)
+ (buffer-file-name)
+ file))
+
+
+(defun kdvi-master-file-name ()
+ "Emulate AucTeX's TeX-master-file function.
+Partly copied from tex.el's TeX-master-file and TeX-add-local-master."
+ (if (boundp 'TeX-master)
+ TeX-master
+ (let ((master-file (read-file-name "Master file (default this file): ")))
+ (if (y-or-n-p "Save info as local variable? ")
+ (progn
+ (goto-char (point-max))
+ (if (re-search-backward "^\\([^\n]+\\)Local Variables:" nil t)
+ (let* ((prefix (if (match-beginning 1)
+ (buffer-substring (match-beginning 1) (match-end 1))
+ ""))
+ (start (point)))
+ (re-search-forward (regexp-quote (concat prefix "End:")) nil t)
+ (if (re-search-backward (regexp-quote (concat prefix "TeX-master")) start t)
+ ;;; if TeX-master line exists already, replace it
+ (progn
+ (beginning-of-line 1)
+ (kill-line 1))
+ (beginning-of-line 1))
+ (insert prefix "TeX-master: " (prin1-to-string master-file) "\n"))
+ (insert "\n%%% Local Variables: "
+;;; mode is of little use without AucTeX ...
+;;; "\n%%% mode: " (substring (symbol-name major-mode) 0 -5)
+ "\n%%% TeX-master: " (prin1-to-string master-file)
+ "\n%%% End: \n"))
+ (save-buffer)
+ (message "(local variables written.)"))
+ (message "(nothing written.)"))
+ (set (make-local-variable 'TeX-master) master-file))))
+
+
+(provide 'kdvi-search)
+
diff --git a/doc/kdvi/optionrequester1.png b/doc/kdvi/optionrequester1.png
new file mode 100644
index 00000000..c03159f1
--- /dev/null
+++ b/doc/kdvi/optionrequester1.png
Binary files differ
diff --git a/doc/kdvi/optionrequester2.png b/doc/kdvi/optionrequester2.png
new file mode 100644
index 00000000..13d252e3
--- /dev/null
+++ b/doc/kdvi/optionrequester2.png
Binary files differ
diff --git a/doc/kdvi/srcltx.sty b/doc/kdvi/srcltx.sty
new file mode 100644
index 00000000..3e2d61a3
--- /dev/null
+++ b/doc/kdvi/srcltx.sty
@@ -0,0 +1,184 @@
+
+% ------------------------------------------------------------------------
+% File: srcltx.sty
+% ==========
+%
+% Version 1.002 1999 Sep 3 (modified to change \everypar)
+% by David Carlisle
+%
+% Version 1.001 1998 Dec 23 (modified to change \output)
+% by Berthold Horn
+%
+% This package was originally written by Aleksander Simonic (the
+% author of WinEdt Shell) to implement a source file tracking and
+% DVI "SRC" specials for LaTeX.
+%
+% This package comes with no guarantees and no reserved rights.
+% You can use or modify this file at your own risk.
+% ************************************************************************
+% NOTE: TeX commands are case sensitive. You have to use uppercase
+% \Input to take advantage of this package
+%
+% This package supports nested \Input commands...
+% File extension should be specified in \Input!
+%
+% This file should be placed in a directory where your LaTeX is
+% looking for inputs (eg. ...\localtexmf\tex for MiKTeX).
+%
+% If you are writing a book with WinEdt and LaTeX simply
+% include this file and use \include{mychapter} command...
+% This way all the necessary specials for DVI Search and
+% Inverse Search are inserted in your DVI File.
+%
+% WinEdt will be able to track Errors from your LOG file.
+%
+% ************************************************************************
+%
+% Some TeX implementations (eg. MiKTeX 1.20 [or later]) can insert
+% the SRC specials much better than any macro package. Consult your
+% TeX documentation to see if it is better to leave the task to your
+% TeX. You can still use the [inactive] version of this package to
+% take advantage of the re-defined Input commands and thus allowing
+% WinEdt to keep track of errors in included source files.
+%
+% MiKTeX inserts the SRC specials in the DVI file if you start
+% [La]TeX with --src qualifier (see MiKTeX's Manual:
+% ...\texmf\Doc\MiKTeX\MiKTeX.pdf for more info).
+%
+% ************************************************************************
+%
+% * NOTE: Some TeX implementations add the file type to the "\jobname".
+% In that case the definition of the "\MainFile" should be modified to:
+%
+% \def\MainFile{\jobname} instead of \def\MainFile{\jobname.tex}.
+%
+% ************************************************************************
+%
+% *** Example - Your LaTeX thesis document may look like this:
+%
+%\documentclass[12pt]{report}
+%\usepackage[centertags]{amstex}
+%\usepackage{thesis,newlfont,amsthm}
+%\usepackage[active]{srcltx}
+%%No src specials are written when loading the package by
+%%\usepackage[inactive]{srcltx}
+%
+% .... Preamble ....
+%
+%\begin{document}
+%
+% .... Title, Author etc. ....
+%
+%\WinEdt{?0000} % Do not process any Errors (Overful/Underful Boxes)
+%\beforepreface
+%\WinEdt{?1111} % Process All Types of Errors from here on
+%\include{ABS}
+%\include{ACK}
+%\afterpreface
+%\include{chapter0}
+%\include{chapter1}
+%\include{chapter2}
+%\include{chapter3}
+%\bibliographystyle{amsplain}
+%\bibliography{xbib}
+%\end{document}
+%
+% ------------------------------------------------------------------------
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{srcltx}[1999/10/11 v1.002 DVI Search]
+\newif\ifSRCOK \SRCOKtrue
+\DeclareOption{active}{\SRCOKtrue}
+\DeclareOption{inactive}{\SRCOKfalse}
+\ExecuteOptions{inactive}
+\ProcessOptions
+% ------------------------------------------------------------------------
+\newcount\PAGETOP
+\newcount\LASTLINE
+\global\PAGETOP=1
+\global\LASTLINE=-1
+\gdef\MainFile{\jobname.tex}% ".tex" needed for MiKTeX
+\gdef\CurrentInput{\MainFile}
+\newcount\INPSP
+\global\INPSP=0
+\def\EJECT{\SRC\eject}
+\def\WinEdt#1{\typeout{:#1}}% WinEdt LOG MODE and INPUT
+% ------------------------------------------------------------------------
+%If your are using DVIWIN remove the \space from the definitions below...
+\def\SRC{\ifSRCOK%
+ \ifnum\inputlineno>\LASTLINE%
+ \ifnum\LASTLINE<0%
+ \global\PAGETOP=\inputlineno%
+ \fi%
+ \global\LASTLINE=\inputlineno%
+ \ifnum\INPSP=0%
+ \ifnum\inputlineno>\PAGETOP%
+ \special{src:\the\inputlineno\space\CurrentInput}%
+ \fi%
+ \else%
+ \special{src:\the\inputlineno\space\CurrentInput}%
+ \fi%
+ \fi%
+\fi}
+% ------------------------------------------------------------------------
+\def\PUSH#1{%
+\SRC%
+\ifnum\INPSP=0 \global\let\INPSTACKA=\CurrentInput \else%
+\ifnum\INPSP=1 \global\let\INPSTACKB=\CurrentInput \else%
+\ifnum\INPSP=2 \global\let\INPSTACKC=\CurrentInput \else%
+\ifnum\INPSP=3 \global\let\INPSTACKD=\CurrentInput \else%
+\ifnum\INPSP=4 \global\let\INPSTACKE=\CurrentInput \else%
+\ifnum\INPSP=5 \global\let\INPSTACKF=\CurrentInput \else%
+ \global\let\INPSTACKX=\CurrentInput \fi\fi\fi\fi\fi\fi%
+\gdef\CurrentInput{#1}%
+\WinEdt{<+ \CurrentInput}%
+\global\LASTLINE=0%
+\ifSRCOK\special{src:1\CurrentInput}\fi%
+\global\advance\INPSP by 1}
+%
+\def\POP{%
+\ifnum\INPSP>0 \global\advance\INPSP by -1 \fi%
+\ifnum\INPSP=0 \global\let\CurrentInput=\INPSTACKA \else%
+\ifnum\INPSP=1 \global\let\CurrentInput=\INPSTACKB \else%
+\ifnum\INPSP=2 \global\let\CurrentInput=\INPSTACKC \else%
+\ifnum\INPSP=3 \global\let\CurrentInput=\INPSTACKD \else%
+\ifnum\INPSP=4 \global\let\CurrentInput=\INPSTACKE \else%
+\ifnum\INPSP=5 \global\let\CurrentInput=\INPSTACKF \else%
+ \global\let\CurrentInput=\INPSTACKX \fi\fi\fi\fi\fi\fi%
+\WinEdt{<-}%
+\global\LASTLINE=\inputlineno%
+\global\advance\LASTLINE by -1%
+\SRC}
+% ------------------------------------------------------------------------
+% Dummy Input: can be used as \INPUT{<file>.bbl} to collect \bibitems
+\def\INPUT#1{\relax}
+% ------------------------------------------------------------------------
+% Redefine the original \include command
+\let\OldINCLUDE=\include
+\def\include#1{%Always ".tex" file type!
+\EJECT%
+\PUSH{#1.tex}%
+\OldINCLUDE{#1}%
+\POP}
+% ------------------------------------------------------------------------
+\def\Input#1{%Specify File Extension!
+\PUSH{#1}%
+\input #1%
+\POP}
+% ------------------------------------------------------------------------
+% Note that these have been defined to concatenate the \SRC with
+% whatever those token lists did before, just in case they were not
+% empty token lists. Of course, later definitions may undo all this...
+\let\originalxxxeverypar\everypar
+\newtoks\everypar
+\originalxxxeverypar{\the\everypar\expandafter\SRC}
+%\everypar\expandafter{\the\everypar\expandafter\SRC}
+% ??? Remove the following line if you encounter problems:
+\everymath\expandafter{\the\everymath\expandafter\SRC}
+% ------------------------------------------------------------------------
+% Redefine the \bibliography command:
+\let\zzzxxxbibliography=\bibliography
+\def\bibliography#1{\PUSH{\jobname.bbl}\zzzxxxbibliography{#1}\POP}
+%------------------------------------------------------------------------
+% Modification to output routine to turn off \SRC while \output is active
+\output\expandafter{\expandafter\SRCOKfalse\the\output}
+%------------------------------------------------------------------------
diff --git a/doc/kdvi/srctex.sty b/doc/kdvi/srctex.sty
new file mode 100644
index 00000000..26ecd74b
--- /dev/null
+++ b/doc/kdvi/srctex.sty
@@ -0,0 +1,146 @@
+% ------------------------------------------------------------------------
+% File: srctex.sty
+% ==========
+%
+% Version 1.002 1999 Sep 3 (modified to change \everypar)
+% by David Carlisle
+%
+% Version 1.001 1998 Dec 23 (modified to change \output)
+% by Berthold Horn
+%
+% This package was originally written by Aleksander Simonic (the
+% author of WinEdt Shell) to implement a source file tracking and
+% DVI "SRC" specials for TeX.
+%
+% This package comes with no guarantees and no reserved rights.
+% You can use or modify this file at your own risk.
+% ************************************************************************
+% NOTE: TeX commands are case sensitive. You have to use uppercase
+% \Input to take advantage of this package
+%
+% This package supports nested \Input commands...
+% File extension should be specified in \Input!
+%
+% This file should be placed in a directory where your TeX is
+% looking for inputs (eg. ...\localtexmf\tex for MiKTeX).
+%
+% ************************************************************************
+%
+% Some TeX implementations (eg. MiKTeX 1.20 [or later]) can insert
+% the SRC specials much better than any macro package. Consult your
+% TeX documentation to see if it is better to leave the task to your
+% TeX. You can still use the [inactive] version of this package to
+% take advantage of the re-defined Input commands and thus allowing
+% WinEdt to keep track of errors in included source files.
+%
+% MiKTeX inserts the SRC specials in the DVI file if you start
+% TeX with --src qualifier (see MiKTeX's Manual:
+% ...\texmf\Doc\MiKTeX\MiKTeX.pdf for more info).
+%
+% ************************************************************************
+%
+% If you are writing a book with WinEdt Shell and TeX simply
+% include this file and use "\Input{my_chapter}" instead of
+% "\input my_chapter". This way all the necessary specials for
+% DVI Search and Inverse Search are inserted in your DVI File.
+%
+% WinEdt will be able to track Errors from your LOG file.
+%
+% To remove SRC Specials from the dvi file compile the source
+% after inserting \SRCOKfalse immediately after
+% the \usepackage{srctex} directive...
+%
+% This package supports nested \Input commands...
+% File extension should be specified in \Input!
+%
+% ************************************************************************
+%
+% * NOTE: Some TeX implementations add the file type to the "\jobname".
+% In that case the definition of the "\MainFile" should be modified to:
+%
+% \def\MainFile{\jobname} instead of \def\MainFile{\jobname.tex}.
+%
+% ************************************************************************
+\def\typeout#1{\message{^^J}\message{#1}\message{^^J}}
+%
+\newif\ifSRCOK \SRCOKtrue
+\newcount\PAGETOP
+\newcount\LASTLINE
+\global\PAGETOP=1
+\global\LASTLINE=-1
+\def\EJECT{\SRC\eject}
+\def\WinEdt#1{\typeout{:#1}}% WinEdt LOG MODE and INPUT
+\gdef\MainFile{\jobname.tex}% ".tex" needed for MiKTeX
+\gdef\CurrentInput{\MainFile}
+\newcount\INPSP
+\global\INPSP=0
+% ------------------------------------------------------------------------
+%If your are using DVIWIN remove the \space from the definitions below...
+\def\SRC{\ifSRCOK%
+ \ifnum\inputlineno>\LASTLINE%
+ \ifnum\LASTLINE<0%
+ \global\PAGETOP=\inputlineno%
+ \fi%
+ \global\LASTLINE=\inputlineno%
+ \ifnum\INPSP=0%
+ \ifnum\inputlineno>\PAGETOP%
+ \special{src:\the\inputlineno\space\CurrentInput}
+ \fi%
+ \else%
+ \special{src:\the\inputlineno\space\CurrentInput}
+ \fi%
+ \fi%
+\fi}
+% ------------------------------------------------------------------------
+\def\PUSH#1{%
+\SRC%
+\ifnum\INPSP=0 \global\let\INPSTACKA=\CurrentInput \else%
+\ifnum\INPSP=1 \global\let\INPSTACKB=\CurrentInput \else%
+\ifnum\INPSP=2 \global\let\INPSTACKC=\CurrentInput \else%
+\ifnum\INPSP=3 \global\let\INPSTACKD=\CurrentInput \else%
+\ifnum\INPSP=4 \global\let\INPSTACKE=\CurrentInput \else%
+\ifnum\INPSP=5 \global\let\INPSTACKF=\CurrentInput \else%
+ \global\let\INPSTACKX=\CurrentInput \fi\fi\fi\fi\fi\fi%
+\gdef\CurrentInput{#1}%
+\WinEdt{<+ \CurrentInput}%
+\global\LASTLINE=0%
+\ifSRCOK\special{src:1\CurrentInput}\fi%
+\global\advance\INPSP by 1}
+%
+\def\POP{%
+\ifnum\INPSP>0 \global\advance\INPSP by -1 \fi%
+\ifnum\INPSP=0 \global\let\CurrentInput=\INPSTACKA \else%
+\ifnum\INPSP=1 \global\let\CurrentInput=\INPSTACKB \else%
+\ifnum\INPSP=2 \global\let\CurrentInput=\INPSTACKC \else%
+\ifnum\INPSP=3 \global\let\CurrentInput=\INPSTACKD \else%
+\ifnum\INPSP=4 \global\let\CurrentInput=\INPSTACKE \else%
+\ifnum\INPSP=5 \global\let\CurrentInput=\INPSTACKF \else%
+ \global\let\CurrentInput=\INPSTACKX \fi\fi\fi\fi\fi\fi%
+\WinEdt{<-}%
+\global\LASTLINE=\inputlineno%
+\global\advance\LASTLINE by -1%
+\SRC}
+% ------------------------------------------------------------------------
+% Dummy Input: can be used as \INPUT{<file>.bbl} to collect \bibitems
+\def\INPUT#1{\relax}
+% ------------------------------------------------------------------------
+\def\Input#1{%Specify File Extension!
+\SRC%
+\PUSH{#1}%
+\input #1%
+\POP%
+\SRC}
+% ------------------------------------------------------------------------
+% Note that these have been defined to concatenate the \SRC with
+% whatever those token lists did before, just in case they were not
+% empty token lists. Of course, later definitions may undo all this...
+\let\originalxxxeverypar\everypar
+\newtoks\everypar
+\originalxxxeverypar{\the\everypar\expandafter\SRC}
+%\everypar\expandafter{\the\everypar\expandafter\SRC}
+% ??? Remove the following line if you encounter problems:
+\everymath\expandafter{\the\everymath\expandafter\SRC}
+%------------------------------------------------------------------------
+% Modification to output routine to turn off \SRC while \output is active
+\output\expandafter{\expandafter\SRCOKfalse\the\output}
+%------------------------------------------------------------------------
diff --git a/doc/kgamma/Makefile.am b/doc/kgamma/Makefile.am
new file mode 100644
index 00000000..085981d9
--- /dev/null
+++ b/doc/kgamma/Makefile.am
@@ -0,0 +1,4 @@
+
+KDE_LANG = en
+KDE_DOCS = AUTO
+
diff --git a/doc/kgamma/index.docbook b/doc/kgamma/index.docbook
new file mode 100644
index 00000000..93be5949
--- /dev/null
+++ b/doc/kgamma/index.docbook
@@ -0,0 +1,234 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.1.2-Based Variant V1.1//EN"
+ "dtd/kdex.dtd" [
+ <!ENTITY kgamma '<application>KGamma</application>'>
+ <!ENTITY kappname "&kgamma;">
+ <!ENTITY package "kdegraphics">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE"><!-- change language only here -->
+]>
+
+<!-- ................................................................ -->
+
+<!-- The language must NOT be changed here. -->
+<book lang="&language;">
+<title>The KGamma Handbook</title>
+
+<bookinfo>
+<authorgroup>
+<author>
+<firstname>Michael</firstname>
+<surname>v.Ostheim</surname>
+<affiliation>
+<address><email>ostheimm@users.berlios.de</email></address>
+</affiliation>
+</author>
+</authorgroup>
+
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+<copyright>
+<year>2001, 2002, 2003</year>
+<holder>Michael v.Ostheim</holder>
+</copyright>
+<!-- Translators: put here the copyright notice of the translation -->
+
+<legalnotice>&FDLNotice;</legalnotice>
+<date>28/08/2003</date>
+<releaseinfo>1.00.20</releaseinfo>
+
+<!-- Abstract about this handbook -->
+<abstract>
+<para>&kgamma; is a simple tool for monitor gamma correction.</para>
+</abstract>
+
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>KGamma</keyword>
+<keyword>Monitor</keyword>
+<keyword>Calibration</keyword>
+<keyword>Gamma</keyword>
+</keywordset>
+
+</bookinfo>
+
+<chapter id="introduction">
+<title>Introduction</title>
+
+<para>This document describes &kgamma; version 1.0.2 (KDE 3.2)</para>
+<para>&kgamma; is a tool for monitor gamma correction. With proper gamma
+settings, your display (websites, images, etc.) will look the same on your
+monitor as on other monitors.</para>
+<para>&kgamma; allows you to alter the monitor's gamma correction of
+XFree86. But that's not all to do. For good results you have to set the
+correct brightness, contrast and color balance of your monitor. This
+may be difficult and you have to repeat every step several times.
+For perfect results you need really good (and expensive) hardware.</para>
+<para>This are system settings, please do not use &kgamma; to manipulate your
+image files.</para>
+</chapter>
+
+<chapter id="using-kgamma">
+<title>Using KGamma</title>
+<sect1 id="Setting-Gamma">
+<title>Setting Gamma Correction</title>
+<para>Use the four sliders to define the gamma correction either as a single
+value, or separately for the red, green and blue components. The XFree86
+default setting for gamma is 1.00 (Mac 1.80, WinXX 2.20). The test images help
+you to find proper settings.</para>
+<para>To store the gamma settings system wide, enable the option 'Store
+settings to XF86Config'. The system settings will be restored at next XFree86
+startup. You need root access to use this option. Use this if you want to
+correct the gamma settings for all users and graphical environments on this
+machine.</para>
+<para>To store the gamma settings to your personal KDE configuration, do not
+enable that option. The user settings will be restored at next KDE startup and
+replace temporary the system gamma settings. The system settings are not removed by
+that and will be restored at next XFree86 startup.</para>
+<para>On multi head systems, select the screen you want to alter with the combo
+box. This will also work with xinerama enabled. If you want to set all screens
+to the same gamma values, enable the 'Sync screens' option. On systems with only
+one screen this option will take no effect.</para>
+</sect1>
+
+<sect1 id="Gray-Scale">
+<title>Gray Scale Test Image</title>
+<para>You should be able to see the following:</para>
+
+<itemizedlist>
+<listitem>
+<para>A gray scale with 20 different sections</para>
+</listitem>
+<listitem>
+<para>The darkest section pure black</para>
+</listitem>
+<listitem>
+<para>The lightest section pure white</para>
+</listitem>
+<listitem>
+<para>No hint of any color in the gray tones</para>
+</listitem>
+</itemizedlist>
+
+<para>If you can't see all of the 20 sections, use your monitors contrast settings
+or the "Gamma" slider of &kgamma; to correct this. If black is not pure black,
+try to darken the monitor, if white is not pure white, try to lighten
+it. If you see any colors in the gray tones alter the color balance settings of
+your monitor or the "Red", "Green" and "Blue" slider of &kgamma;.</para>
+</sect1>
+
+<sect1 id="RGB-Scale">
+<title>RGB Scale Test Image</title>
+<para>
+You should be able to see three strips, each with 16 sections of red,
+green or blue tones. The darkest sections should be pure black, the brightest
+should be pure red, green or blue. If you don't see all sections of
+a color strip, try to lighten or darken this color.</para>
+</sect1>
+
+<sect1 id="CMY-Scale">
+<title>CMY Scale Test Image</title>
+<para>
+You should be able to see three strips, each with 11 sections of cyan,
+magenta or yellow tones. The brightest sections should be pure white, the darkest
+should be pure cyan, magenta or yellow.</para>
+
+<itemizedlist>
+<listitem>
+<para>If you can't see all cyan sections, try to lighten or darken red</para>
+</listitem>
+<listitem>
+<para>If you can't see all magenta sections, try to lighten or darken green</para>
+</listitem>
+<listitem>
+<para>If you can't see all yellow sections, try to lighten or darken blue</para>
+</listitem>
+</itemizedlist>
+</sect1>
+
+<sect1 id="advanced">
+<title>Advanced Test Images</title>
+<para>
+The following three pictures shows you the abilities of your monitor at
+three points of the gray spectrum. If you can't see all of the details,
+don't be worry, or buy better hardware.
+</para>
+<sect2 id="dark-gray">
+<title>Dark Gray Test Image</title>
+<para>
+You should be able to see 10 different rectangles of dark gray within a
+black box. The chart shows you 1% steps from black.
+</para>
+</sect2>
+<sect2 id="mid-gray">
+<title>Mid Gray Test Image</title>
+<para>
+This picture shows you 11 gray rectangles within a 50% gray box. You should be
+able to see all of the rectangles except the middle one. The rectangles represent
+the steps from 45% to 55% gray.
+</para>
+</sect2>
+<sect2 id="light-gray">
+<title>Light Gray Test Image</title>
+<para>
+You should be able to see 10 different rectangles of light gray within a white box.
+The chart shows you 1% steps from white.
+</para>
+</sect2>
+</sect1>
+
+</chapter>
+
+<chapter id="credits">
+<title>Credits and License</title>
+
+<para>
+&kgamma;
+</para>
+<para>
+Program copyright 2001, 2002, 3003 Michael v.Ostheim <email>ostheimm@users.berlios.de</email>
+</para>
+
+<para>
+Documentation copyright 2001, 2002, 2003 Michael v.Ostheim <email>ostheimm@users.berlios.de</email>
+</para>
+
+<!-- TRANS:CREDIT_FOR_TRANSLATORS -->
+
+&underFDL; <!-- FDL: do not remove. -->
+&underGPL; <!-- GPL License -->
+</chapter>
+
+<appendix id="installation">
+<title>Installation</title>
+
+<para>&kgamma;'s home site is
+<ulink url="http://kgamma.berlios.de/index2.php">http://kgamma.berlios.de/index2.php</ulink>
+</para>
+
+<sect1 id="compilation">
+<title>Compilation and Installation</title>
+
+<para>
+In order to compile and install &kgamma; on your system, type the following in the base
+folder of the &kgamma; distribution:
+<screen>
+<prompt>%</prompt> <userinput><command>./configure</command></userinput>
+<prompt>%</prompt> <userinput><command>make</command></userinput>
+<prompt>%</prompt> <userinput><command>make install</command></userinput>
+</screen>
+</para>
+
+</sect1>
+</appendix>
+
+&documentation.index;
+</book>
+<!--
+Local Variables:
+mode: sgml
+sgml-minimize-attributes:nil
+sgml-general-insert-case:lower
+sgml-indent-step:0
+sgml-indent-data:nil
+End:
+-->
diff --git a/doc/kghostview/Makefile.am b/doc/kghostview/Makefile.am
new file mode 100644
index 00000000..085981d9
--- /dev/null
+++ b/doc/kghostview/Makefile.am
@@ -0,0 +1,4 @@
+
+KDE_LANG = en
+KDE_DOCS = AUTO
+
diff --git a/doc/kghostview/index.docbook b/doc/kghostview/index.docbook
new file mode 100644
index 00000000..41258728
--- /dev/null
+++ b/doc/kghostview/index.docbook
@@ -0,0 +1,755 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN"
+ "dtd/kdex.dtd" [
+ <!ENTITY kappname "&kghostview;">
+ <!ENTITY package "kdegraphics">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE"><!-- change language only here -->
+]>
+<book lang="&language;">
+
+<bookinfo>
+<title>The &kghostview; Handbook</title>
+<authorgroup>
+<author>
+<firstname>Pamela</firstname>
+<surname>Roberts</surname>
+<affiliation>
+<address>&Pamela.Roberts.mail;</address>
+</affiliation>
+</author>
+
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+</authorgroup>
+
+<copyright>
+<year>2001</year> <year>2002</year>
+<holder>&Pamela.Roberts;</holder>
+</copyright>
+
+<legalnotice>&FDLNotice;</legalnotice>
+
+<date>2006-02-28</date>
+<releaseinfo>0.20</releaseinfo>
+
+<abstract>
+<para>&kghostview; displays and prints &PostScript; (<literal
+role="extension">.ps</literal>, <literal
+role="extension">.eps</literal>) and Portable Document Format
+(<literal role="extension">.pdf</literal>) files.</para>
+<para>This document describes &kghostview; version 0.20</para>
+</abstract>
+
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>linux</keyword>
+<keyword>postscript</keyword>
+<keyword>ghostview</keyword>
+</keywordset>
+
+</bookinfo>
+
+<chapter id="introduction">
+<title>Introduction</title>
+
+<para>
+&kghostview; displays and prints &PostScript; (<literal
+role="extension">.ps</literal>, <literal
+role="extension">.eps</literal>) and Portable Document Format (<literal
+role="extension">.pdf</literal>) files. It is a port to &kde; of Tim
+Theisen's <application>Ghostview</application> program which uses Alladin
+<application>Ghostscript</application> to view documents prepared in
+<trademark class="registered">Adobe</trademark>'s &PostScript; page
+description language. &PostScript; is the major page description language
+for printing on &UNIX; systems and this application can be used to preview
+material intended for printing or for reading documents online.
+</para>
+
+<para>
+You can use &kghostview; with all recent versions of
+<application>Ghostscript</application>. Newer versions offer much
+improved performance which you can take advantage of with &kghostview;.
+</para>
+
+<para>
+If a document does not conform to the <trademark
+class="registered">Adobe</trademark> document structuring convention the
+functionality of the viewer is limited. For example, if there is no
+table of contents, skipping around the document and marking pages is not
+possible.
+</para>
+
+</chapter>
+
+
+<chapter id="fundamentals">
+<title>Fundamentals</title>
+
+<para>
+This section describes what you see in the main &kghostview; window, the
+actions of the Toolbar buttons and how to use the Page List.
+</para>
+
+<para>
+You can open multiple instances of &kghostview; to view multiple
+documents. The titlebar at the top of a window shows you the name of
+the document in that window.
+</para>
+
+<para>
+The main area displays a page of the current document. If the page is
+too large to fit inside the window, scrollbars are automatically added
+to the sides of the display, although these can be disabled with the
+<guimenu>Settings</guimenu> menu.
+</para>
+<para>
+Note that the Toolbar and the Page List can be hidden with the <link
+linkend="settings">Settings</link> menu options to give more space on
+the screen for the content area.
+</para>
+
+<para>
+You can scroll up and down in a page with the <keysym>Up
+Arrow</keysym> and <keysym>Down Arrow</keysym> keys, or use the
+<menuchoice><guimenu>View</guimenu><guimenuitem>Read Up</guimenuitem></menuchoice>
+(<keycap>PageUp</keycap>) and <menuchoice><guimenu>View</guimenu>
+<guimenuitem>Read Down</guimenuitem></menuchoice>
+(<keycap>PageDown</keycap>) options to scroll through the entire document.
+</para>
+
+<para>The
+<guibutton>Read Up</guibutton> and <guibutton>Read Down</guibutton>
+-Toolbar buttons do what they say, or you can go
+immediately to any page with a &LMB; click on the appropriate entry in
+the Page List.
+</para>
+
+<para>
+If selected in the <guimenu>Settings</guimenu> menu a Page List will be
+displayed at the left side of the window. This list has two columns: the
+first may contain a flag indicating that the page has been marked, the
+second contains the page numbers. You can use this page list to navigate
+through the document or to mark pages for printing.
+</para>
+
+<para>
+You can toggle the <quote>page marked</quote> flag for the currently
+displayed page with <keycombo
+action="simul">&Ctrl;&Shift;<keycap>M</keycap></keycombo> or for
+any page by &LMB; clicking on it in the Page List. You can also clear or
+change your page marks using the context menu that is activated by
+&RMB; clicking anywhere in the Page List area or by selecting the <link
+linkend="menuedit">Edit</link> menu.
+</para>
+
+</chapter>
+
+<chapter id="primary-menu-items">
+<title>The Menubar</title>
+
+<sect1 id="menufile">
+<title>The <guimenu>File</guimenu> Menu</title>
+
+<variablelist>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo action="simul">&Ctrl;
+<keycap>O</keycap></keycombo></shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Open...</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Open</action> a file. If a file
+is currently being displayed it will be closed.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Open Recent</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Open</action> a file selected from a combo box of
+recently opened files. If a file is currently being displayed it will be
+closed.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Save As...</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Save</action> the currently open file.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo action="simul">&Ctrl;
+<keycap>P</keycap></keycombo></shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Print...</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Print</action> the currently displayed document.
+The Print dialog box will let you choose to print all or selected
+(marked) pages.</para> </listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Document Info</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Display</action> some basic information about
+the document.</para> </listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo action="simul">&Ctrl;
+<keycap>Q</keycap></keycombo></shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Quit</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Close</action> down &kghostview;.</para>
+</listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect1>
+
+<sect1 id="menuedit">
+<title>The <guimenu>Edit</guimenu> Menu</title>
+
+<note>
+<para>
+You can also get this menu by &RMB; clicking anywhere in the Page List
+area.
+</para>
+</note>
+
+<variablelist>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo action="simul">&Ctrl;&Shift;
+<keycap>M</keycap></keycombo></shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Mark Current Page</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Toggle the page marked
+flag</action> for the current page.</para> </listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Edit</guimenu>
+<guimenuitem>Mark All Pages</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Set the page marked
+flag</action> for all pages of the document.</para> </listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Edit</guimenu>
+<guimenuitem>Mark Even Pages</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Set the page marked
+flag</action> for all even numbered pages in the document. Used in
+conjunction with <guimenuitem>Mark Odd Pages</guimenuitem> or
+<guimenuitem>Toggle Page Marks</guimenuitem> this provides a convenient way of
+double-sided printing a document on a single sided printer</para> </listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Edit</guimenu>
+<guimenuitem>Mark Odd Pages</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Set the page marked
+flag</action> for all odd numbered pages in the document.</para> </listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Edit</guimenu>
+<guimenuitem>Toggle Page Marks</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Toggle the page marked
+flags</action> for all pages in the document.</para> </listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Edit</guimenu>
+<guimenuitem>Remove Page Marks</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Clear the page marked
+flags</action> for all pages in the document.</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect1>
+
+<sect1 id="view">
+<title>The <guimenu>View</guimenu> Menu</title>
+
+<variablelist>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycap>F5</keycap>
+</shortcut>
+<guimenu>View</guimenu>
+<guimenuitem>Reload</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Re-render</action> the current document page.</para>
+</listitem> </varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycap>M</keycap></shortcut>
+<guimenu>View</guimenu>
+<guimenuitem>Maximize</guimenuitem></menuchoice>
+</term>
+<listitem>
+<para>This option maximizes the &kghostview; window.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">&Ctrl;&Shift;
+<keycap>F</keycap></keycombo></shortcut>
+<guimenu>View</guimenu>
+<guimenuitem>Full Screen Mode</guimenuitem></menuchoice>
+</term>
+<listitem>
+<para>This option maximizes the &kghostview; window and the currently shown page.
+Even the window decorations (titlebar &etc;) are temporarily removed.
+To switch back to normal window mode, press the <keycap>ESC</keycap> key or
+the shortcut <keycombo action="simul">&Ctrl;&Shift;
+<keycap>F</keycap></keycombo> again, or open the context menu with a &RMB; click
+and select <guimenuitem>Exit Full Screen Mode</guimenuitem>.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>View</guimenu>
+<guimenuitem>Orientation</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Change the orientation</action> of the
+displayed page. You can choose between <guimenuitem>Auto</guimenuitem>,
+<guimenuitem>Portrait</guimenuitem>,
+<guimenuitem>Landscape</guimenuitem>, <guimenuitem>Upside
+Down</guimenuitem> and <guimenuitem>Seascape</guimenuitem> which is like
+<guimenuitem>Landscape</guimenuitem> but the other way up.</para> </listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>View</guimenu>
+<guimenuitem>Paper Size</guimenuitem>
+</menuchoice></term>
+<listitem><para>Lets you view the document as if it
+were printed on different <action>paper sizes</action> without changing the
+scale. You should normally choose <guimenuitem>Auto</guimenuitem>.</para>
+</listitem> </varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo action="simul">&Ctrl;<keycap>+</keycap></keycombo>
+</shortcut>
+<guimenu>View</guimenu>
+<guimenuitem>Zoom In</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Increase the magnification</action> of the
+document view.</para> </listitem> </varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>View</guimenu>
+<guimenuitem>Zoom</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+<action>Select a predefined zoom factor.</action>
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo action="simul">&Ctrl;
+<keycap>-</keycap></keycombo></shortcut>
+<guimenu>View</guimenu>
+<guimenuitem>Zoom Out</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Decrease the magnification</action> of the
+document view.</para> </listitem> </varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>View</guimenu>
+<guimenuitem>Fit to Page Width</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Scale</action> the display so a page width fits
+exactly across the main display area.</para> </listitem> </varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycap>S</keycap></shortcut>
+<guimenu>View</guimenu>
+<guimenuitem>Fit to Screen</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Scale</action> the display so the entire page fits
+exactly across the main display area.</para> </listitem> </varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo action="simul">&Ctrl;
+<keycap>PageUp</keycap></keycombo></shortcut>
+<guimenu>View</guimenu>
+<guimenuitem>Previous Page</guimenuitem>
+</menuchoice></term>
+<listitem><para>View the <action>previous page</action> of the
+document.</para> </listitem> </varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo action="simul">&Ctrl;
+<keycap>PageDown</keycap></keycombo></shortcut>
+<guimenu>View</guimenu>
+<guimenuitem>Next Page</guimenuitem>
+</menuchoice></term>
+<listitem><para>View the <action>next page</action> of the
+document.</para> </listitem> </varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo action="simul">&Ctrl;
+<keycap>Home</keycap></keycombo></shortcut>
+<guimenu>View</guimenu>
+<guimenuitem>First Page</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Go to the first page</action> of the
+document.</para> </listitem> </varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo action="simul">&Ctrl;
+<keycap>End</keycap></keycombo></shortcut>
+<guimenu>View</guimenu>
+<guimenuitem>Last Page</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Go to the last page</action> of the
+document.</para> </listitem> </varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>View</guimenu>
+<guimenuitem>Go to Page</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Go to a selected page</action> of the
+document.</para> </listitem> </varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycap>PageUp</keycap></shortcut>
+<guimenu>View</guimenu>
+<guimenuitem>Read Up</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Scroll backwards</action> through the
+document.</para> </listitem> </varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycap>PageDown</keycap></shortcut>
+<guimenu>View</guimenu>
+<guimenuitem>Read Down</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Scroll forwards</action> through the
+document.</para> </listitem> </varlistentry>
+
+</variablelist>
+
+</sect1>
+
+<sect1 id="settings">
+<title>The <guimenu>Settings</guimenu> Menu</title>
+
+<variablelist>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">
+&Ctrl;<keycap>M</keycap></keycombo></shortcut>
+<guimenu>Settings</guimenu>
+<guimenuitem>Show/Hide Menubar</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Toggles the menubar on/off.</action></para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Show/Hide Toolbar</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Toggle the Toolbar display</action> on
+and off.</para></listitem> </varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Show/Hide Statusbar</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Toggle the Status bar display</action> on
+and off.</para></listitem> </varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">&Ctrl;&Shift;
+<keycap>F</keycap></keycombo></shortcut>
+<guimenu>Settings</guimenu>
+<guimenuitem>Full Screen Mode</guimenuitem></menuchoice>
+</term>
+<listitem>
+<para>This option maximizes the &kghostview; window and the currently shown page.
+Even the window decorations (titlebar &etc;) are temporarily removed.
+To switch back to normal window mode, press the <keycap>ESC</keycap> key or
+the shortcut <keycombo action="simul">&Ctrl;&Shift;
+<keycap>F</keycap></keycombo> again, or open the context menu with a &RMB; click
+and select <guimenuitem>Exit Full Screen Mode</guimenuitem>.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Configure Shortcuts...</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Opens a dialog for changing the shortcuts.</action>
+Using this option you can change the standard key shortcut for &kghostview;'s commands
+or create new ones.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Configure Toolbars...</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Opens a dialog for configuring the toolbar.</action> You
+can add and remove toolbuttons for &kghostview;'s commands with this
+option.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Show/Hide Scrollbars</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Toggle the horizontal and vertical scrollbars</action>
+on and off.</para></listitem> </varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Show Page List</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Toggle the Page List</action>
+on and off.</para></listitem> </varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Show Page Labels</guimenuitem>
+</menuchoice></term>
+<listitem><para>If this is selected the <action>name (if any) of the
+current page is displayed in the Status Bar</action>.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Watch File</guimenuitem>
+</menuchoice></term>
+<listitem><para>If this is selected the display will
+<action>automatically update</action> if the document file
+changes.</para></listitem> </varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>No Flicker</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+If this is selected the display will start showing objects instantly as they are rendered,
+otherwise the whole page is rendered off-screen and then displayed.
+</para></listitem> </varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Configure &kghostview;...</guimenuitem>
+</menuchoice></term>
+<listitem><para>Brings up the &kghostview;
+<link linkend="config-dialog"><action>configuration dialog</action>
+box</link>.</para></listitem> </varlistentry>
+
+</variablelist>
+
+</sect1>
+
+<sect1 id="help">
+<title>The <guimenu>Help</guimenu> Menu</title>
+
+&help.menu.documentation;
+
+</sect1>
+</chapter>
+
+<chapter id="config-dialog">
+<title>Configuration</title>
+
+<para>
+The configuration dialog box is accessed with the
+<menuchoice><guimenu>Settings</guimenu><guimenuitem>Configure
+&kghostview;...</guimenuitem></menuchoice> option. It has two pages;
+<guilabel>General</guilabel> and <guilabel>Ghostscript
+Configuration</guilabel>
+</para>
+
+<sect1 id="general-settings">
+<title>General Settings</title>
+
+<para>
+You can select <guilabel>Enable anti-aliasing of fonts and
+images</guilabel> to get smoothly rendered text, but note that
+anti-aliasing is memory intensive and slower than straightforward
+rendering of fonts. Early versions of
+<application>Ghostscript</application> could not perform anti-aliasing.
+</para>
+
+<para>
+Select <guilabel>Use platform fonts</guilabel> if you wish to use your
+native system fonts rather than those that come with
+<application>Ghostscript</application>.
+</para>
+
+<para>
+Turn <guilabel>Show Ghostscript messages in a separate box</guilabel>
+on if you want to be informed of any output or error messages
+generated by the <application>Ghostscript</application> interpreter.
+</para>
+
+<para>
+You can choose whether &kghostview; uses a
+<guilabel>Monochrome</guilabel>, <guilabel>Grayscale</guilabel> or
+<guilabel>Color</guilabel> <guilabel>Palette</guilabel> for the display.
+</para>
+
+</sect1>
+
+<sect1 id="ghostscript-config">
+<title><application>Ghostscript</application> Configuration</title>
+
+<para>
+In this dialog box page you can set the name of the
+<application>Ghostscript</application> <guilabel>Interpreter:</guilabel>
+executable and the <guilabel>Non-antialiasing arguments:</guilabel> and
+the <guilabel>Antialiasing arguments:</guilabel> passed to it. The
+default settings should be suitable for most systems.
+</para>
+
+</sect1>
+
+</chapter>
+
+<chapter id="credits">
+
+<title>Credits and License</title>
+
+<para>
+&kghostview;
+</para>
+
+<itemizedlist>
+<title>Program Copyright:</title>
+<listitem><para>&Mark.Donohoe; &Mark.Donohoe.mail; (original author) 1998
+</para></listitem>
+<listitem><para>&David.Sweet; &David.Sweet.mail;
+Maintainer 1999-2000
+</para></listitem>
+<listitem><para>&Wilco.Greven; &Wilco.Greven.mail;
+Current maintainer
+</para></listitem>
+<listitem><para>&David.Faure; &David.Faure.mail; (basis for
+shell)</para>
+</listitem>
+<listitem><para>Daniel Duley <email>mosfet@kde.org</email> (port to
+Kparts)</para>
+</listitem>
+<listitem><para>&Espen.Sand; &Espen.Sand.mail; (dialog boxes)</para>
+</listitem>
+</itemizedlist>
+
+
+<para>
+Documentation copyright 2001, 2002 &Pamela.Roberts;
+&Pamela.Roberts.mail;
+</para>
+
+
+<!-- TRANS:CREDIT_FOR_TRANSLATORS -->
+
+&underFDL; <!-- FDL: do not remove -->
+
+&underGPL; <!-- GPL License -->
+
+
+</chapter>
+
+<appendix id="installation">
+<title>Installation</title>
+
+<para>
+&kghostview; is part of the &kde; 3 project, details of which can be found at
+<ulink url="http://www.kde.org">http://www.kde.org</ulink>.
+</para>
+
+<para>
+To use &kghostview;, you must have the <application>Ghostscript</application>
+program as well as &kde; 3 installed on your machine. The
+<application>Ghostscript</application> home page is at
+<ulink url="http://www.cs.wisc.edu/~ghost/">http://www.cs.wisc.edu/~ghost/</ulink>
+</para>
+
+<para>
+Most distributions will include &kghostview;, but if you want to roll your own
+the source code can be found in the &package; package on &kde-ftp;, the main
+ftp site of the &kde; project.</para>
+
+<!--
+<para>
+To see if a later version of &kghostview; has been released, you can
+take a look in <ulink
+url="http://apps.kde.com">http://apps.kde.com</ulink>. </para>
+-->
+
+&install.compile.documentation;
+
+</appendix>
+
+&documentation.index;
+
+</book>
+<!--
+Local Variables:
+mode: sgml
+sgml-omittag: nil
+sgml-shorttag: t
+End:
+-->
+
diff --git a/doc/kiconedit/Makefile.am b/doc/kiconedit/Makefile.am
new file mode 100644
index 00000000..085981d9
--- /dev/null
+++ b/doc/kiconedit/Makefile.am
@@ -0,0 +1,4 @@
+
+KDE_LANG = en
+KDE_DOCS = AUTO
+
diff --git a/doc/kiconedit/index.docbook b/doc/kiconedit/index.docbook
new file mode 100644
index 00000000..92bc8bc3
--- /dev/null
+++ b/doc/kiconedit/index.docbook
@@ -0,0 +1,1083 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+ <!ENTITY kappname "&kiconedit;">
+ <!ENTITY package "kdegraphics">
+ <!ENTITY % English "INCLUDE" > <!-- change language only here -->
+ <!ENTITY % addindex "IGNORE">
+]>
+
+<book lang="&language;">
+<bookinfo>
+<title>The &kiconedit; Manual</title>
+<authorgroup>
+<author>
+<firstname>Thomas</firstname>
+<surname>Tanghus</surname>
+<affiliation>
+<address>&Thomas.Tanghus.mail;</address>
+</affiliation>
+</author>
+
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+
+</authorgroup>
+
+<copyright>
+<year>1997</year>
+<holder>&Thomas.Tanghus;</holder>
+</copyright>
+<copyright>
+<year>2001</year><year>2003</year>
+<holder>&Lauri.Watts;</holder>
+</copyright>
+
+<legalnotice>
+&FDLNotice;
+</legalnotice>
+
+<date>2005-12-10</date>
+<releaseinfo>3.5.0</releaseinfo>
+
+<abstract>
+<para>
+&kiconedit; is designed to help create icons for &kde; using the
+standard icon palette.
+</para>
+</abstract>
+
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>kdegraphics</keyword>
+<keyword>KIconEdit</keyword>
+<keyword>icon</keyword>
+</keywordset>
+</bookinfo>
+
+<chapter id="Introduction">
+<title>Introduction</title>
+
+<blockquote>
+<attribution>&Thomas.Tanghus;
+&Thomas.Tanghus.mail;</attribution>
+
+<para>
+&kiconedit; is designed to help create icons for &kde; using the
+standard icon palette.
+</para>
+
+<para>
+I hope you will find this program somehow useful and I would
+appreciate any suggestions and comments.
+</para>
+
+</blockquote>
+
+</chapter>
+
+<chapter id="onscreen-fundamentals">
+<title>Onscreen Fundamentals</title>
+
+<para>
+In this section will be briefly described the Icon Editor user
+interface.
+</para>
+
+<para>
+The Icon Editor window is separated in five areas: main toolbar, tools
+toolbar, statusbar, color palette and the grid, where you paint the icon.
+</para>
+
+<sect1 id="main-toolbar">
+<title>Main Toolbar</title>
+
+<variablelist>
+
+<varlistentry>
+<term><guiicon>New</guiicon></term>
+<listitem>
+<para>
+<action>Create a new icon.</action> If the current file has been
+modified you will be asked if you want to save the changes. After that a
+dialog will open where you can choose to create the icon from scratch or
+from a template.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guiicon>Open</guiicon></term>
+<listitem>
+<para>
+<action>Open an existing icon file.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guiicon>Save</guiicon></term>
+<listitem>
+<para>
+<action>Save the currently open icon.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guiicon>Print</guiicon></term>
+<listitem>
+<para>
+<action>Print the icon.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guiicon>Undo</guiicon></term>
+<listitem><para>Undo the last action</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guiicon>Redo</guiicon></term>
+<listitem><para>Redo the last action undone. If no actions have been
+undone, this action is disabled.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guiicon>Cut</guiicon></term>
+<listitem>
+<para>
+<action>Cuts out the entire icon and put it onto the clipboard.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guiicon>Copy</guiicon></term>
+<listitem>
+<para>
+<action>Copies the entire icon to the clipboard.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guiicon>Paste</guiicon></term>
+<listitem>
+<para>
+<action>Paste the contents of the clipboard as a new image (if the
+clipboard contains a valid icon).</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guiicon>Zoom</guiicon></term>
+<term><guiicon>Zoom In</guiicon></term>
+<term><guiicon>Zoom Out</guiicon></term>
+<listitem>
+<para>
+<action>Zoom to predefined zoom factor, zoom in or zoom out.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guiicon>Resize</guiicon></term>
+<listitem>
+<para>
+<action>Resize icon to width X height.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><action>GrayScale</action></term>
+<listitem>
+<para>
+<action>Gray scale the icon image.</action> This may create colors not
+conformant to the &kde; icon palette.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guiicon>Show Grid</guiicon></term>
+<listitem>
+<para>
+<action>Toggle grid on/off.</action>
+</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+</sect1>
+
+<sect1 id="tools-toolbar">
+<title>Tools Toolbar</title>
+
+<para>
+This toolbar contains the tools you can use to manipulate the
+icon.
+</para>
+
+<variablelist>
+<varlistentry>
+<term><guiicon>Freehand</guiicon></term>
+<listitem>
+<para>
+<action>Draw free hand.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guiicon>Color Picker</guiicon></term>
+<listitem>
+<para>
+Doesn't change the icon but <action>changes the current drawcolor to the
+color clicked on.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guiicon>Rectangle</guiicon></term>
+<listitem>
+<para>
+<action>Draw a rectangle.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guiicon>Filled Rectangle</guiicon></term>
+<listitem>
+<para>
+<action>Draw a filled rectangle.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guiicon>Circle</guiicon></term>
+<listitem>
+<para>
+<action>Draw a circle.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guiicon>Filled Circle</guiicon></term>
+<listitem>
+<para>
+<action>Draw a filled circle.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guiicon>Ellipse</guiicon></term>
+<listitem>
+<para>
+<action>Draw an ellipse</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guiicon>Filled Ellipse</guiicon></term>
+<listitem>
+<para>
+<action>Draw a filled ellipse</action> (almost the same thing as drawing
+a circle.)
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guiicon>Spray</guiicon></term>
+<listitem>
+<para>
+<action>Draws a randow dotted pattern like a spraycan.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guiicon>Flood Fill</guiicon></term>
+<listitem>
+<para>
+<action>Fill an area with the current color.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guiicon>Line</guiicon></term>
+<listitem>
+<para>
+<action>Draw a line.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guiicon>Eraser (Transparent)</guiicon></term>
+<listitem>
+<para>
+<action>Draw transparent (invisible).</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guiicon>Rectangular Selection</guiicon></term>
+<term><guiicon>Circular Selection</guiicon></term>
+<listitem>
+<para>
+<action>Select (mark) a part of the icon.</action>
+</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+</sect1>
+
+<sect1 id="grid">
+<title>Grid</title>
+
+<para>
+The grid is where you manipulate the icon contents.
+</para>
+</sect1>
+
+<sect1 id="statusbar">
+<title>Statusbar</title>
+
+<para>
+The status bar keeps you informed of current operations. From left to
+right, it tells you the x,y coordinates of the pixel you are working on,
+the size of the current canvas, the zoom factor, and the current number
+of colors in the icon.
+</para>
+
+</sect1>
+</chapter>
+
+<chapter id="the-menu-entries">
+<title>The Menu Entries</title>
+
+<sect1 id="file">
+<title>The <guimenu>File</guimenu> Menu</title>
+
+<para>
+The following functions are available from the <guimenu>File</guimenu>
+menu:
+</para>
+
+<variablelist>
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>N</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>New</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Lets you create a new icon</action>, either from a template or
+by specifying the size.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>New Window</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Open a new Icon Editor window.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>O</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Open...</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Open an existing icon file.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>File</guimenu>
+<guisubmenu>Open Recent</guisubmenu>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Displays a list of recently opened icons to choose
+from.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>S</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Save</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Save the currently open icon.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Save As...</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Save the currently open icon under a new name.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>P</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Print...</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Print the icon</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>W</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Close</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Close</action> &kiconedit;.
+</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+</sect1>
+
+<sect1 id="edit">
+<title>The <guimenu>Edit</guimenu> Menu</title>
+
+<para>
+The <guimenu>Edit</guimenu> menu contains the following entries:
+</para>
+
+<variablelist>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo
+action="simul">&Ctrl;<keycap>Z</keycap></keycombo></shortcut>
+<guimenu>Edit</guimenu><guimenuitem>Undo</guimenuitem>
+</menuchoice></term>
+<listitem><para>Undo the last action</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">
+&Ctrl;&Shift;<keycap>Z</keycap></keycombo></shortcut>
+<guimenu>Edit</guimenu><guimenuitem>Redo</guimenuitem></menuchoice></term>
+<listitem><para>Redo the last action undone. If no actions have been
+undone, this action is disabled.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>X</keycap></keycombo>
+</shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Cut</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Cuts out the entire icon and put it onto the clipboard.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>C</keycap></keycombo>
+</shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Copy</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Copies the entire icon to the clipboard.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>V</keycap></keycombo>
+</shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Paste</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Paste the contents of the clipboard (if the clipboard contains a
+valid icon).</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Edit</guimenu>
+<guimenuitem>Paste as New</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Paste the contents of the clipboard as a new image into a new Icon Editor window (if the
+clipboard contains a valid icon).</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Edit</guimenu>
+<guimenuitem>Clear</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Clear the grid and fill it with transparent color.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>A</keycap></keycombo>
+</shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Select All</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Marks the entire icon as selected.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><guimenu>Edit</guimenu><guimenuitem>Resize...</guimenuitem>
+</menuchoice></term>
+<listitem><para>
+<action>Resize icon to width X height.</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><guimenu>Edit</guimenu><guimenuitem>GrayScale</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Gray scale the icon image.</action> This may
+create colors not conformant to the &kde; icon palette.</para>
+</listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect1>
+
+<sect1 id="view">
+<title>The <guimenu>View</guimenu> Menu</title>
+
+<variablelist>
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>+</keycap></keycombo></shortcut>
+<guimenu>View</guimenu>
+<guimenuitem>Zoom In</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Magnify the view of the icon</action>.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut><keycombo action="simul">
+&Ctrl;<keycap>-</keycap></keycombo></shortcut>
+<guimenu>View</guimenu>
+<guimenuitem>Zoom Out</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Shrink the view icon to a smaller screen size</action>
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>View</guimenu>
+<guisubmenu>Zoom</guisubmenu>
+</menuchoice>
+</term>
+<listitem>
+<para>Zoom to a predefined zoom factor</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+</sect1>
+
+<sect1 id="tools">
+<title>The <guimenu>Tools</guimenu> Menu</title>
+
+<variablelist>
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Tools</guimenu>
+<guimenuitem>Freehand</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+Draw free hand.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><guimenu>Tools</guimenu><guimenuitem>Color
+Picker</guimenuitem></menuchoice></term>
+<listitem><para>Select a color from the screen to use as the
+foreground color.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Tools</guimenu>
+<guimenuitem>Rectangle</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+Draw a rectangle.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Tools</guimenu>
+<guimenuitem>Filled Rectangle</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+Draw a filled rectangle.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Tools</guimenu>
+<guimenuitem>Circle</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+Draw a circle.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Tools</guimenu>
+<guimenuitem>Filled Circle</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+Draw a filled circle.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Tools</guimenu>
+<guimenuitem>Ellipse</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+Draw an ellipse
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Tools</guimenu>
+<guimenuitem>Filled Ellipse</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Draw a filled ellipse</action> (almost the same thing as drawing
+a circle.)
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Tools</guimenu>
+<guimenuitem>Spray</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+Draws a random dotted pattern like a spraycan.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Tools</guimenu>
+<guimenuitem>Flood Fill</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+Fill an area with the current color.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Tools</guimenu>
+<guimenuitem>Line</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+Draw a line.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Tools</guimenu>
+<guimenuitem>Eraser (Transparent)</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>Draw transparent (invisible).</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><guimenu>Tools</guimenu>
+<guimenuitem>Rectangular Selection</guimenuitem></menuchoice></term>
+<term><menuchoice><guimenu>Tools</guimenu>
+<guimenuitem>Circular Selection</guimenuitem></menuchoice></term>
+<listitem><para><action>Select (mark) a part of the icon.</action>
+</para>
+</listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect1>
+
+<sect1 id="settings">
+<title>The <guimenu>Settings</guimenu> Menu</title>
+
+<variablelist>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Toolbars</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Toggle on and off the display of the toolbars.</action>
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Show/Hide Statusbar</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Toggle on and off the display of the status bar.</action>
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Show/Hide Grid</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+<action>Toggle on and off the grid.</action>
+</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><menuchoice><guimenu>Settings</guimenu>
+<guimenuitem>Configure Shortcuts...</guimenuitem>
+</menuchoice></term>
+<listitem><para>Opens a dialog where you can customize &kiconedit;'s
+keyboard shortcuts.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Configure &kiconedit;...</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>
+Opens the &kiconedit; <link linkend="configuration">configuration
+dialog</link> configuration dialog, described separately.
+</para>
+</listitem>
+</varlistentry>
+
+
+</variablelist>
+
+</sect1>
+
+<sect1 id="help">
+<title>The <guimenu>Help</guimenu> Menu</title>
+
+&help.menu.documentation;
+
+</sect1>
+</chapter>
+
+<chapter id="configuration">
+<title>Configuration</title>
+
+<sect1>
+<title>Configuring &kiconedit;</title>
+<para>Selecting the <menuchoice><guimenu>Settings</guimenu>
+<guimenuitem>Configure &kiconedit;...</guimenuitem></menuchoice> menu item will
+open a configuration dialog with the tree tabs <guilabel>Icon Templates</guilabel>,
+<guilabel>Background</guilabel> and <guilabel>Icon Grid</guilabel>.</para>
+
+<screenshot>
+<screeninfo>&kiconedit; configuration dialog</screeninfo>
+<mediaobject>
+<imageobject><imagedata fileref="kiconedit-configuration.png" format="PNG"/></imageobject>
+<textobject><phrase>&kiconedit; configuration dialog</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<sect2 id="icon-templates-tab">
+<title>The <guilabel>Icon Templates</guilabel> Tab</title>
+<para><guilabel>Add...</guilabel>, <guilabel>Edit...</guilabel> and <guilabel>Remove</guilabel>
+the templates for <guilabel>Standard File</guilabel>, <guilabel>Source File</guilabel>,
+<guilabel>Compressed File</guilabel> &etc;.</para>
+</sect2>
+<sect2 id="background-tab">
+<title>The <guilabel>Background</guilabel> Tab</title>
+<para>Select to <guibutton>Use color</guibutton> or to <guibutton>Use pixmap</guibutton>
+as background. A <guilabel>Preview</guilabel> of your choice is displayed.</para>
+</sect2>
+<sect2 id="icon-grid-tab">
+<title>The <guilabel>Icon Grid</guilabel> Tab</title>
+<para>Select to <guilabel>Paste transparent pixels</guilabel> or <guilabel>Show rulers</guilabel>
+and set a <guilabel>Solid Color</guilabel> or a <guilabel>Checkerboard</guilabel> as
+<guilabel>Transparency Display</guilabel>.
+You can set the Checkerboard <guilabel>Size:</guilabel> to <guilabel>Small</guilabel>,
+<guilabel>Medium</guilabel> or <guilabel>Large</guilabel> and choose <guilabel>Color 1:</guilabel>
+and <guilabel>Color 2:</guilabel> of the checkerboard.</para>
+</sect2>
+</sect1>
+
+</chapter>
+
+<chapter id="credits-and-license">
+<title>Credits and Licenses</title>
+
+<para>
+&kiconedit;
+</para>
+
+<para>
+Program copyright &Thomas.Tanghus; <email>tanghus@kde.org</email>
+</para>
+
+<itemizedlist>
+<title>Contributors</title>
+<listitem>
+<para>
+John Califf <email>jcaliff@compuzone.net</email>
+</para>
+</listitem>
+<listitem>
+<para>
+Laurent Montel <email>lmontel@mandrakesoft.com</email>
+</para>
+</listitem>
+<listitem><para>Aaron Seigo &Aaron.J.Seigo.mail;</para></listitem>
+<listitem><para>Nadeem Hassan <email>nhasan@nadmm.com</email> - Rewrote UI to use
+XMLGUI, Lots of fixes and cleanup</para></listitem>
+<listitem><para>Adrian Page <email>Adrian.Page@tesco.net</email> - Bug Fixes and &GUI; tidy up.</para></listitem>
+
+
+</itemizedlist>
+
+<!-- TRANS:CREDIT_FOR_TRANSLATORS -->
+
+&underFDL;
+&underGPL;
+
+</chapter>
+
+<appendix id="installation">
+<title>Installation</title>
+
+<sect1 id="how-to-obtain-the-icon-editor">
+<title>How to obtain &kiconedit;</title>
+
+&install.intro.documentation;
+
+</sect1>
+
+<sect1 id="compilation-and-installation">
+<title>Compilation and Installation</title>
+
+&install.compile.documentation;
+
+</sect1>
+
+<!--
+<sect1 id="configuration">
+<title>Configuration</title>
+
+</sect1>
+
+-->
+</appendix>
+
+
+</book>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-indent-step:0
+sgml-indent-data:nil
+sgml-omittag:nil
+sgml-shorttag:t
+End:
+-->
+
diff --git a/doc/kiconedit/kiconedit-configuration.png b/doc/kiconedit/kiconedit-configuration.png
new file mode 100644
index 00000000..100a68cb
--- /dev/null
+++ b/doc/kiconedit/kiconedit-configuration.png
Binary files differ
diff --git a/doc/kolourpaint/Makefile.am b/doc/kolourpaint/Makefile.am
new file mode 100644
index 00000000..171f575c
--- /dev/null
+++ b/doc/kolourpaint/Makefile.am
@@ -0,0 +1,2 @@
+KDE_LANG = en
+KDE_DOCS = AUTO
diff --git a/doc/kolourpaint/brush_shapes.png b/doc/kolourpaint/brush_shapes.png
new file mode 100644
index 00000000..ee02cc21
--- /dev/null
+++ b/doc/kolourpaint/brush_shapes.png
Binary files differ
diff --git a/doc/kolourpaint/color_box.png b/doc/kolourpaint/color_box.png
new file mode 100644
index 00000000..97d7b458
--- /dev/null
+++ b/doc/kolourpaint/color_box.png
Binary files differ
diff --git a/doc/kolourpaint/eraser_shapes.png b/doc/kolourpaint/eraser_shapes.png
new file mode 100644
index 00000000..43c1f788
--- /dev/null
+++ b/doc/kolourpaint/eraser_shapes.png
Binary files differ
diff --git a/doc/kolourpaint/fcc_std_text.png b/doc/kolourpaint/fcc_std_text.png
new file mode 100644
index 00000000..6d74b00f
--- /dev/null
+++ b/doc/kolourpaint/fcc_std_text.png
Binary files differ
diff --git a/doc/kolourpaint/fcc_trans_text.png b/doc/kolourpaint/fcc_trans_text.png
new file mode 100644
index 00000000..c85f07d6
--- /dev/null
+++ b/doc/kolourpaint/fcc_trans_text.png
Binary files differ
diff --git a/doc/kolourpaint/fill_color_similarity.png b/doc/kolourpaint/fill_color_similarity.png
new file mode 100644
index 00000000..2fce4156
--- /dev/null
+++ b/doc/kolourpaint/fill_color_similarity.png
Binary files differ
diff --git a/doc/kolourpaint/fill_style.png b/doc/kolourpaint/fill_style.png
new file mode 100644
index 00000000..6ced3249
--- /dev/null
+++ b/doc/kolourpaint/fill_style.png
Binary files differ
diff --git a/doc/kolourpaint/image_balance.png b/doc/kolourpaint/image_balance.png
new file mode 100644
index 00000000..96eadb9c
--- /dev/null
+++ b/doc/kolourpaint/image_balance.png
Binary files differ
diff --git a/doc/kolourpaint/image_emboss.png b/doc/kolourpaint/image_emboss.png
new file mode 100644
index 00000000..093b25e3
--- /dev/null
+++ b/doc/kolourpaint/image_emboss.png
Binary files differ
diff --git a/doc/kolourpaint/image_flatten.png b/doc/kolourpaint/image_flatten.png
new file mode 100644
index 00000000..8095c62e
--- /dev/null
+++ b/doc/kolourpaint/image_flatten.png
Binary files differ
diff --git a/doc/kolourpaint/image_flip.png b/doc/kolourpaint/image_flip.png
new file mode 100644
index 00000000..0e87243d
--- /dev/null
+++ b/doc/kolourpaint/image_flip.png
Binary files differ
diff --git a/doc/kolourpaint/image_invert.png b/doc/kolourpaint/image_invert.png
new file mode 100644
index 00000000..64be7174
--- /dev/null
+++ b/doc/kolourpaint/image_invert.png
Binary files differ
diff --git a/doc/kolourpaint/image_reduce_colors.png b/doc/kolourpaint/image_reduce_colors.png
new file mode 100644
index 00000000..a8cd5884
--- /dev/null
+++ b/doc/kolourpaint/image_reduce_colors.png
Binary files differ
diff --git a/doc/kolourpaint/image_resize_scale.png b/doc/kolourpaint/image_resize_scale.png
new file mode 100644
index 00000000..43014039
--- /dev/null
+++ b/doc/kolourpaint/image_resize_scale.png
Binary files differ
diff --git a/doc/kolourpaint/image_rotate.png b/doc/kolourpaint/image_rotate.png
new file mode 100644
index 00000000..0db94613
--- /dev/null
+++ b/doc/kolourpaint/image_rotate.png
Binary files differ
diff --git a/doc/kolourpaint/image_skew.png b/doc/kolourpaint/image_skew.png
new file mode 100644
index 00000000..81f2afb4
--- /dev/null
+++ b/doc/kolourpaint/image_skew.png
Binary files differ
diff --git a/doc/kolourpaint/image_soften_sharpen.png b/doc/kolourpaint/image_soften_sharpen.png
new file mode 100644
index 00000000..ba7d94d7
--- /dev/null
+++ b/doc/kolourpaint/image_soften_sharpen.png
Binary files differ
diff --git a/doc/kolourpaint/index.docbook b/doc/kolourpaint/index.docbook
new file mode 100644
index 00000000..c80f7011
--- /dev/null
+++ b/doc/kolourpaint/index.docbook
@@ -0,0 +1,1501 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+ <!ENTITY kappname "&kolourpaint;">
+ <!ENTITY Clarence.Dang
+"<personname><firstname>Clarence</firstname><surname>Dang</surname></personname>">
+ <!ENTITY Clarence.Dang.mail "<email>dang@kde.org</email>">
+ <!ENTITY Thurston.Dang
+"<personname><firstname>Thurston</firstname><surname>Dang</surname></personname>">
+ <!ENTITY Thurston.Dang.mail "<email>thurston_dang@users.sourceforge.net</email>">
+ <!ENTITY package "kdegraphics">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE">
+]>
+
+<book lang="&language;">
+
+<bookinfo>
+<title>The &kolourpaint; Handbook</title>
+
+<authorgroup>
+<author>
+<personname>
+<firstname>Thurston</firstname>
+<surname>Dang</surname>
+</personname>
+<email>thurston_dang@users.sourceforge.net</email>
+</author>
+
+<othercredit role="reviewer">
+<personname>
+<firstname>Clarence</firstname>
+<surname>Dang</surname>
+</personname>
+</othercredit>
+
+<othercredit role="reviewer">
+&Lauri.Watts;
+</othercredit>
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+</authorgroup>
+
+<copyright>
+<year>2004</year>
+<year>2005</year>
+<holder>Thurston Dang</holder>
+</copyright>
+
+<legalnotice>
+&FDLNotice;
+</legalnotice>
+<date>2005-12-29</date>
+<releaseinfo>1.4_relight</releaseinfo>
+
+<abstract>
+<para>
+&kolourpaint; is a free, easy-to-use paint program for &kde;.
+</para>
+</abstract>
+
+<keywordset>
+<keyword>kolourpaint</keyword>
+<keyword>kdegraphics</keyword>
+</keywordset>
+
+</bookinfo>
+
+<chapter id="introduction">
+<title>Introduction</title>
+<para>&kolourpaint; is a free, easy-to-use paint program for &kde;. It's
+perfect for everyday tasks such as:</para>
+
+<itemizedlist>
+<listitem>
+<para>Painting - drawing diagrams and <quote>finger painting</quote></para>
+</listitem>
+<listitem>
+<para>Image Manipulation - editing screenshots and photos; applying
+effects</para>
+</listitem>
+<listitem>
+<para>Icon Editing - drawing clipart and logos with transparency</para>
+</listitem>
+</itemizedlist>
+</chapter>
+
+<chapter id="using-kolourpaint">
+<title>Using &kolourpaint;</title>
+
+<para>Click on the following links to explore &kolourpaint;'s
+capabilities:</para>
+
+<itemizedlist>
+<listitem>
+<para><link linkend="tools-chapter">Tools</link></para>
+</listitem>
+<listitem>
+<para><link linkend="working-with-color">Working with Color</link></para>
+</listitem>
+<listitem>
+<para><link linkend="view-options-chapter">View Options</link></para>
+</listitem>
+<listitem>
+<para><link linkend="image-effects-chapter">Image Effects</link></para>
+</listitem>
+</itemizedlist>
+</chapter>
+
+<chapter id="tools-chapter">
+<title>Tools</title>
+
+<sect1 id="tool-reference">
+<title>Tool Reference</title>
+
+<para>
+A quick way to select a tool in &kolourpaint; is to press the single key shortcut associated with it,
+documented below and in the <interface>Tool Box</interface> tooltips. You can also hold
+<keycombo action="simul">&Alt;&Shift;</keycombo> while pressing the key, which is necessary when you are
+writing text (as the single key shortcuts will be disabled). For example, to select the brush, press
+<keycombo action="simul">&Alt;&Shift;<keycap>B</keycap></keycombo> or just B (when not writing text).
+</para>
+
+<simplelist>
+<member><link linkend="tool-brush"><guiicon>
+<inlinemediaobject><imageobject><imagedata fileref="tool_brush.png" format="PNG"/>
+</imageobject></inlinemediaobject>
+</guiicon></link>
+<link linkend="tool-brush">Brush</link> (B)</member>
+
+<member><link linkend="tool-eraser-clr"><guiicon>
+<inlinemediaobject><imageobject>
+<imagedata fileref="tool_color_washer.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</guiicon>
+</link>
+<link linkend="tool-eraser-clr">Color Eraser</link> (O)</member>
+
+<member><link linkend="tool-color-picker"><guiicon>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_color_picker.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</guiicon>
+</link>
+<link linkend="tool-color-picker">Color Picker</link> (C)
+</member>
+
+<member>
+<link linkend="tool-polystar">
+<guiicon>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_polyline.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</guiicon>
+</link>
+<link linkend="tool-polystar">Connected Lines</link> (N)</member>
+
+<member>
+<link linkend="tool-curve">
+<guiicon>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_curve.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</guiicon>
+</link>
+<link linkend="tool-curve">Curve</link> (V)
+</member>
+
+<member>
+<link linkend="tool-ellipse">
+<guiicon>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_ellipse.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</guiicon>
+</link>
+<link linkend="tool-ellipse">Ellipse</link> (E)
+</member>
+
+<member>
+<link linkend="tool-eraser-std">
+<guiicon>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_eraser.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</guiicon>
+</link>
+<link linkend="tool-eraser-std">Eraser</link> (A)
+</member>
+
+<member>
+<link linkend="tool-flood-fill">
+<guiicon>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_flood_fill.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</guiicon>
+</link>
+<link linkend="tool-flood-fill">Flood Fill</link> (F)
+</member>
+
+<member>
+<link linkend="tool-line">
+<guiicon>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_line.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</guiicon>
+</link>
+<link linkend="tool-line">Line</link> (L)
+</member>
+
+<member>
+<link linkend="tool-pen">
+<guiicon>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_pen.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</guiicon>
+</link>
+<link linkend="tool-pen">Pen</link> (P)
+</member>
+
+<member>
+<link linkend="tool-polystar">
+<guiicon>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_polygon.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</guiicon>
+</link>
+<link linkend="tool-polystar">Polygon</link> (G)
+</member>
+
+<member>
+<link linkend="tool-rectangles">
+<guiicon>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_rectangle.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</guiicon>
+</link>
+<link linkend="tool-rectangles">Rectangle</link> (R)
+</member>
+
+<member>
+<link linkend="tool-rectangles">
+<guiicon>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_rounded_rectangle.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</guiicon>
+</link>
+<link linkend="tool-rectangles">Rounded Rectangle</link> (U)
+</member>
+
+<member>
+<link linkend="tool-selections">
+<guiicon>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_elliptical_selection.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</guiicon>
+</link>
+<link linkend="tool-selections">Selection (Elliptical)</link> (I)
+</member>
+
+<member>
+<link linkend="tool-selections">
+<guiicon>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_free_form_selection.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</guiicon>
+</link>
+<link linkend="tool-selections">Selection (Free-Form)</link> (M)
+</member>
+
+<member>
+<link linkend="tool-selections">
+<guiicon>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_rect_selection.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</guiicon>
+</link>
+<link linkend="tool-selections">Selection (Rectangular)</link> (S)
+</member>
+
+<member>
+<link linkend="tool-spraycan">
+<guiicon>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_spraycan.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</guiicon>
+</link>
+<link linkend="tool-spraycan">Spraycan</link> (Y)
+</member>
+
+<member>
+<link linkend="tool-text">
+<guiicon>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_text.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</guiicon>
+</link>
+<link linkend="tool-text">Text</link> (T)
+</member>
+</simplelist>
+
+</sect1>
+
+<sect1 id="tool-brush">
+<title>
+Brush
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_brush.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</title>
+<para>
+Click or click and drag with the brush to draw.
+</para>
+
+<informaltable>
+<tgroup cols="2">
+<tbody>
+<row>
+<entry>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="brush_shapes.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</entry>
+
+<entry>
+<para>
+Click on one of the shapes to select the brush shape. You can use a
+circular, square, slash or backslash brush shape.</para>
+</entry>
+</row>
+</tbody>
+</tgroup>
+</informaltable>
+
+<para>The &LMB; draws in the foreground color. The &RMB; draws in the
+background color.</para>
+</sect1>
+
+<sect1 id="tool-color-picker">
+<title>Color Picker <inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_color_picker.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</title>
+
+<para>To set the foreground color, <mousebutton>left</mousebutton> click on
+a pixel. To set the background color, <mousebutton>right</mousebutton> click on a pixel.
+&kolourpaint; will then return to the previously selected tool.</para>
+
+</sect1>
+
+<sect1 id="tool-polystar">
+<title>Connected Lines and Polygon
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_polystar.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</title>
+
+<para>Click and drag to draw connected lines. The polygon tool is used in
+the same way, however, the start and end points are automatically connected
+to form a polygon.</para>
+
+<para>The &LMB; draws in the foreground color. The &RMB; draws in the
+background color, and will also reverse the fill color for polygons.</para>
+
+<para>You can <link linkend="tool-options">set the line width</link>. For
+polygons, you can also <link linkend="tool-options">set the fill
+style</link>.</para>
+
+</sect1>
+
+<sect1 id="tool-curve">
+<title>Curve <inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_curve.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</title>
+
+<para>Click and drag to draw a line - this sets the start and end
+points. You can set up to two control points by dragging. To finish the
+curve without using both or any control points, click the other mouse
+button. The curve tool draws a Cubic Bezier.</para>
+
+<para>The &LMB; draws in the foreground color. The &RMB; draws in the
+background color.</para>
+
+<para>You can also <link linkend="tool-options">set the line
+width</link>.</para>
+
+</sect1>
+
+<sect1 id="tool-ellipse">
+<title>Ellipse <inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_ellipse.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</title>
+
+<para>Click and drag to draw an ellipse.</para>
+
+<para>The &LMB; draws in the foreground color. The &RMB; draws in the
+background color, and will reverse the fill color.</para>
+
+<para>You can also <link linkend="tool-options">set the line width and fill
+style</link>.</para>
+
+<para>For additional functionality, use the modifier keys:</para>
+
+<itemizedlist>
+<listitem>
+<para>Hold &Shift; and drag to draw a circle.</para>
+</listitem>
+<listitem>
+<para>To draw an ellipse with a center point of your choice, hold &Ctrl;,
+click on the center point, and drag until the ellipse is the correct size
+and shape.</para>
+</listitem>
+<listitem>
+<para>To draw a circle with a center point of your choice, hold &Ctrl; and
+&Shift;, click on the center point, and drag until the circle is the correct
+size.</para>
+</listitem>
+</itemizedlist>
+</sect1>
+
+<sect1 id="tool-erasers">
+<!-- This title does not contain the eraser icons because they are present in the
+sections; c.f. Connected Lines and Polygon, Rectangles and Selections. -->
+<title>Erasers</title>
+
+<sect2 id="tool-eraser-std">
+<title>Eraser
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_eraser.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</title>
+
+<para>Click and drag with the eraser to rub out mistakes.</para>
+
+<note>
+<para>Unlike other tools, the erasers draw in the background color. To draw
+in the foreground color, use the &RMB;.</para>
+</note>
+
+<para>The eraser only has <link linkend="tool-options">square
+shapes</link>. To draw with other shapes such as circles use the <link
+linkend="tool-brush">Brush</link> and the &RMB;.</para>
+
+<tip>
+<para>Double-click on the Eraser icon to clear the entire image. This is
+equivalent to using the <link linkend="image-clear">Clear</link> option on
+the Image menu.</para>
+</tip>
+
+</sect2>
+
+<sect2 id="tool-eraser-clr">
+<title>Color Eraser
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_color_washer.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</title>
+
+<para>Click and drag to replace pixels of the foreground color with the
+background color. To replace all pixels similar (but not necessarily exactly
+equal) to the foreground color, such as in dithered images and photos, use a
+<link linkend="color-box">Color Similarity</link> setting other than
+Exact.</para>
+
+<note>
+<para>Unlike other tools, the erasers draw in the background color. To
+replace pixels of the background color with the foreground color, use the
+&RMB;.</para>
+</note>
+
+<para>You can configure the <link linkend="tool-options">eraser
+size</link>.</para>
+
+<tip>
+<para>Double-click on the Color Eraser icon to apply it to the entire image.</para>
+</tip>
+</sect2>
+
+</sect1>
+
+<sect1 id="tool-flood-fill">
+<title>Flood Fill
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_flood_fill.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</title>
+
+<para>Click to fill a region. To fill a dithered region, use a <link
+linkend="color-box">Color Similarity</link> setting other than Exact.</para>
+
+<para>The &LMB; fills in the foreground color. The &RMB; fills in the
+background color.</para>
+</sect1>
+
+<sect1 id="tool-line">
+<title>
+Line
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_line.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</title>
+
+<para>Click and drag to draw a line.</para>
+
+<para>The &LMB; draws in the foreground color. The &RMB; draws in the
+background color.</para>
+
+<para>You can also <link linkend="tool-options">set the line
+width</link>.</para>
+
+<para>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="lines_30_deg.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="lines_30_45_deg.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="lines_45_deg.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</para>
+
+<itemizedlist>
+<listitem>
+<para>Hold &Ctrl; to draw lines angled at the nearest multiple of 30 degrees
+- these are the lines in the red diagram.</para>
+</listitem>
+<listitem>
+<para>Hold &Shift; to draw lines angled at the nearest multiple of 45
+degrees - these are the lines in the blue diagram.</para>
+</listitem>
+<listitem>
+<para>Hold &Ctrl; and &Shift; to draw lines angled at the nearest multiple
+of 30 or 45 degrees - these are the lines in the green diagram.</para>
+</listitem>
+</itemizedlist>
+
+</sect1>
+
+<sect1 id="tool-pen">
+<title>Pen
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_pen.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</title>
+
+<para>Click to draw a dot or click and drag to draw a freehand line.</para>
+
+<para>The &LMB; draws in the foreground color. The &RMB; draws in the
+background color. </para>
+
+</sect1>
+
+<sect1 id="tool-rectangles">
+<title>Rectangles
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_rectangles.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</title>
+
+<para>Click and drag to draw a rectangle. The Rounded Rectangle is a Rectangle with rounded
+corners.</para>
+
+<para>The &LMB; draws in the foreground color. The &RMB; draws in the background color,
+and will reverse the fill color.</para>
+
+<para>You can also <link linkend="tool-options">set the line width and fill
+style</link>.</para>
+
+<para> For additional functionality, use the modifier keys:</para>
+
+<itemizedlist>
+<listitem>
+<para>Hold &Shift; and drag to draw a square.</para>
+</listitem>
+<listitem>
+<para>To draw a rectangle with a center point of your choice, hold &Ctrl;,
+click on the center point, and drag until the rectangle is the correct size
+and shape.</para>
+</listitem>
+<listitem>
+<para>To draw a square with a center point of your choice, hold &Ctrl; and &Shift;,
+click on the center point, and drag until the square is the correct size.</para>
+</listitem>
+</itemizedlist>
+
+</sect1>
+
+<sect1 id="tool-selections">
+<title>Selections
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_selections.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</title>
+
+<para>Use the selection tools to draw out the boundary of a
+selection.</para>
+
+<para>To move the selection, click and drag on it. The main view will scroll as required to allow you to move the selection to part of the image that is not currently displayed.</para>
+
+<para>
+You can free-form <link linkend="image-resize-scale">Resize</link> the entire image or
+<link linkend="image-resize-scale">Smooth Scale</link> the selection using the corresponding handles.
+Hold &Shift; while free-form scaling the selection to maintain aspect ratio.
+The &RMB; invokes a context menu with common <guimenu>Edit</guimenu> commands and <link linkend="image-effects-section">Image Effects</link>.
+</para>
+
+<tip>
+<para>You can use the cursor keys while drawing out the boundary of the
+selection or while moving it.</para>
+</tip>
+
+<para>
+If you hold &Ctrl; before moving the selection, then you will move a
+copy of it. The selection will be smeared when moving it while &Shift; is held.
+</para>
+
+<informaltable>
+<tgroup cols="2">
+<tbody>
+<row>
+<entry>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="selections_opaque_transparent.png"
+format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</entry>
+<entry>
+<para>There are two selection modes: Opaque (default) and Transparent. If
+you use the Transparent selection mode, all pixels of the background color
+will be transparent (background subtraction). This allows you to paste a
+selection without the background. To perform background subtraction on a
+dithered image, use a <link linkend="color-box">Color Similarity</link>
+setting other than Exact.</para>
+</entry>
+</row>
+</tbody>
+</tgroup>
+</informaltable>
+
+<para>You can apply Image Effects to a selection - see the <link
+linkend="image-effects-section">Image Effects</link> section for more
+information.</para>
+</sect1>
+
+<sect1 id="tool-spraycan">
+<title>Spraycan
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_spraycan.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</title>
+
+<para>Click and drag to spray graffiti. Hold down the mouse button for a
+more concentrated spray.</para>
+
+<informaltable>
+<tgroup cols="2">
+<tbody>
+<row>
+<entry>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="spraycan_patterns.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</entry>
+<entry>
+<para>Click on one of the shapes to select the spray size. You can select
+from spray sizes of 9x9, 17x17 and 29x29.</para>
+</entry>
+</row>
+</tbody>
+</tgroup>
+</informaltable>
+
+<para>The &LMB; draws in the foreground color. The &RMB; draws in the
+background color.</para>
+
+</sect1>
+
+<sect1 id="tool-text">
+<title>Text
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_text.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</title>
+
+<para>
+Click and drag an area in which to write text. Click and drag
+on the border to move it. You can resize the text box by dragging on the
+handles or by using the <link linkend="image-resize-scale">Resize</link> dialog.
+</para>
+
+<tip>
+<para>If you have deselected a text box you can use <guimenuitem>Undo</guimenuitem> to edit the text
+again.</para>
+</tip>
+
+<sect2 id="tool-text-transparent">
+<title>Using the Transparent Color</title>
+
+<para>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="fcc_std_text.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</para>
+<para>The left picture shows the example image. The right picture shows the addition of text
+with opaque foreground and background colors.
+</para>
+
+<para>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="fcc_trans_text.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</para>
+
+<para>The left picture shows the addition of text with opaque foreground
+colors and a transparent background color. The right picture shows the
+addition of text with a transparent foreground color and opaque background
+color.</para>
+</sect2>
+</sect1>
+
+<sect1 id="tool-options">
+<title>Common Tool Options</title>
+
+<informaltable>
+<tgroup cols="2">
+<tbody>
+<row>
+<entry>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="eraser_shapes.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</entry>
+<entry>
+<para>Click on one of the squares to select the eraser size. You can select
+from squares of side length 2, 3, 5, 9, 17 and 29 pixels.</para>
+
+<para>The eraser size setting affects the <link
+linkend="tool-erasers">Erasers</link>.</para>
+</entry>
+</row>
+<row>
+<entry>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="line_width.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</entry>
+<entry>
+<para>Click on one of the lines to select the line width. You can select
+from line widths of 1, 2, 3, 5 and 8 pixel(s).</para>
+
+<para>The line width setting affects the <link
+linkend="tool-polystar">Connected Lines</link>, <link
+linkend="tool-curve">Curve</link>, <link
+linkend="tool-ellipse">Ellipse</link>, <link
+linkend="tool-line">Line</link>, <link
+linkend="tool-polystar">Polygon</link>, <link
+linkend="tool-rectangles">Rectangle</link> and <link
+linkend="tool-rectangles">Rounded Rectangle</link> tools. </para>
+</entry>
+</row>
+<row>
+<entry>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="fill_style.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</entry>
+<entry>
+<para>Click on one of the rectangles to select the fill style. You can
+select from No Fill, Fill with Background Color and Fill with Foreground
+Color.</para> <para>The fill style setting affects the <link
+linkend="tool-ellipse">Ellipse</link>, <link
+linkend="tool-polystar">Polygon</link>, <link
+linkend="tool-rectangles">Rectangle</link> and <link
+linkend="tool-rectangles">Rounded Rectangle</link> tools.
+</para>
+</entry>
+</row>
+</tbody>
+</tgroup>
+</informaltable>
+
+</sect1>
+</chapter>
+
+<chapter id="working-with-color">
+<title>Working with Color</title>
+
+<sect1 id="color-box">
+<title>The Color Box</title>
+
+<para>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="color_box.png" format="PNG"/>
+</imageobject>
+<textobject>
+<phrase>Color Box</phrase>
+</textobject>
+</inlinemediaobject>
+</para>
+
+<para>The Color Box has 3 main sections: the Color Tablet, the Color Palette
+and the Color Similarity Selector.</para>
+
+<para>The Color Tablet shows the current foreground color as a square on top
+of another square representing the current background color. When drawing
+with the &LMB;, the foreground color is used, and when drawing with the
+&RMB; the background color is used (except for the <link
+linkend="tool-erasers">Erasers</link>). You can click on the double-ended
+arrow to swap the foreground and background colors. </para>
+
+<para>The Color Palette shows a selection of colors for you to choose
+from. The translucent pyramid represents the transparent color. Left-click
+on a color to set the foreground color and right-click on a color to set the
+background color. You can also drag and drop any opaque color into the Color
+Tablet squares. To edit a color in the Color Tablet or Palette, double-click
+on it. The <link linkend="tool-color-picker">Color Picker</link> tool allows
+you to select a color from the image. </para>
+
+<para>Color Similarity allows you to work more effectively with dithered
+images and photos, in a comparable manner to the <quote>Magic Wand</quote> feature of other paint programs. It applies to transparent selections, as well as the
+<link linkend="tool-flood-fill">Flood Fill</link>, <link
+linkend="tool-eraser-clr">Color Eraser</link> and <link
+linkend="image-autocrop">Autocrop / Remove Internal Border</link> tools. Double-click on the Color
+Similarity Selector to choose how similar colors must be to be considered
+identical. When using selections in Transparent mode, any color in the
+selection that is similar to the background color will also be made
+transparent.</para>
+
+<para>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="fill_color_similarity.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</para>
+
+<para>
+The left picture shows the example image. The right pictures demonstrate the use of a flood fill, with Color Similarity settings of 5%, 15% and 30%. In this example, with a Color Similarity setting of <guilabel>Exact</guilabel>, a flood fill at (80, 100) would only fill one pixel, as the surrounding pixels are similar but not identical. As Color Similarity is increased, more pixels that are similar in color are considered identical, hence the fill extends further.
+</para>
+
+</sect1>
+</chapter>
+
+<chapter id="view-options-chapter">
+<title>View Options</title>
+
+<sect1 id="view-options-section">
+<title>View Options Reference</title>
+
+<para><link linkend="view-zoom">Zoom incorporating the Grid</link></para>
+<para><link linkend="view-thumbnail">Thumbnail</link></para>
+
+</sect1>
+
+<sect1 id="view-zoom">
+<title>Zoom incorporating the Grid</title>
+<para>Increase the zoom level to edit images with more precision, or reduce it to see more of the image.</para>
+
+<important>
+<para>
+At zoom levels that aren't multiples of 100%, parts of the image may appear to move when the user interacts with it. Other minor redraw glitches may also occur at such zoom levels.
+</para>
+</important>
+
+<para>At zoom levels of 600% or greater that are also multiples of 100%, you can <guimenuitem>Show Grid</guimenuitem> to more accurately edit individual pixels.</para>
+
+<para>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="tool_text.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="text_zoom_grid.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</para>
+
+<para>The first picture shows the <link linkend="tool-text">Text</link> tool icon, while the latter shows it at 600% zoom with the grid on.</para>
+
+<tip>
+<para>
+Another way of zooming when not drawing is to scroll the <mousebutton>wheel</mousebutton> while holding &Ctrl;.
+</para>
+</tip>
+
+</sect1>
+
+<sect1 id="view-thumbnail">
+<title>Thumbnail</title>
+<para>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="view_thumbnails.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</para>
+<para>
+If <guimenuitem>Zoomed Thumbnail Mode</guimenuitem> is selected, the entire image is displayed, scaled as required to fit the thumbnail window (top-right picture).
+</para>
+<para>
+Otherwise, the thumbnail displays as much of the image as possible, starting from the top-left of the main view (bottom-right picture).
+</para>
+</sect1>
+
+</chapter>
+
+<chapter id="image-effects-chapter">
+<title>Image Effects</title>
+
+<sect1 id="image-effects-section">
+<title>Image Effects Reference</title>
+<para><link linkend="image-autocrop">Autocrop / Remove Internal Border</link></para>
+<para><link linkend="image-balance">Balance</link></para>
+<para><link linkend="image-clear">Clear</link></para>
+<para><link linkend="image-emboss">Emboss</link></para>
+<para><link linkend="image-flatten">Flatten</link></para>
+<para><link linkend="image-flip">Flip</link></para>
+<para><link linkend="image-invert">Invert</link></para>
+<para><link linkend="image-reduce-colors">Reduce Colors</link></para>
+<para><link linkend="image-grayscale">Reduce to Grayscale</link></para>
+<para><link linkend="image-monochrome">Reduce to Monochrome (Dithered)</link></para>
+<para><link linkend="image-resize-scale">Resize / Scale</link></para>
+<para><link linkend="image-rotate">Rotate</link></para>
+<para><link linkend="image-set-as-image">Set as Image (Crop)</link></para>
+<para><link linkend="image-skew">Skew</link></para>
+<para><link linkend="image-soften-sharpen">Soften &amp; Sharpen</link></para>
+<para><link linkend="image-more-effects">More Effects</link></para>
+<para><link linkend="image-notes">Notes</link></para>
+</sect1>
+
+<sect1 id="image-autocrop">
+<title>Autocrop / Remove Internal Border</title>
+
+<para>This automatically removes the border of an image or selection. Use
+Autocrop if you have a figure that does not fill the entire image or selection and you
+wish to remove the excess whitespace. To use this feature with a dithered
+image border, you will also need to use <link linkend="color-box">Color
+Similarity</link>.</para>
+
+</sect1>
+
+<sect1 id="image-balance">
+<title>Balance</title>
+
+<para>
+This feature is accessible from the <link linkend="image-more-effects">More Effects</link> dialog.
+</para>
+<para>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="image_balance.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</para>
+
+<para>This allows you to set the brightness, contrast and gamma of the image or selection.
+</para>
+
+<note>
+<para>
+The more common measure of gamma (a decimal from 0.10 to 10.00) is located between the
+<guilabel>Gamma</guilabel> spinbox and the <guibutton>Reset</guibutton> button.
+</para>
+</note>
+</sect1>
+
+<sect1 id="image-clear">
+<title>Clear</title>
+
+<para>This fills the entire image or selection with the background
+color.</para>
+
+<tip>
+<para>Double-click on the <link linkend="tool-eraser-std">Eraser</link>
+icon to clear the entire image.</para>
+</tip>
+
+</sect1>
+
+<sect1 id="image-emboss">
+<title>Emboss</title>
+
+<para>
+This feature is accessible from the <link linkend="image-more-effects">More Effects</link> dialog.
+</para>
+<para>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="image_emboss.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</para>
+
+<para>
+Check <guilabel>Enable</guilabel> to apply the Emboss effect. This emphasises the edges and gives the
+image or selection an &quot;engraved look&quot;.
+</para>
+</sect1>
+
+<sect1 id="image-flatten">
+<title>Flatten</title>
+
+<para>
+This feature is accessible from the <link linkend="image-more-effects">More Effects</link> dialog.
+</para>
+<para>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="image_flatten.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</para>
+
+<para>
+This recolors the image with varying shades of the two selected colors.
+</para>
+</sect1>
+
+<sect1 id="image-flip">
+<title>Flip</title>
+
+<para>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="image_flip.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</para>
+
+<para>This flips the entire image or selection horizontally or
+vertically.</para>
+
+</sect1>
+
+<sect1 id="image-invert">
+<title>Invert</title>
+
+<para>
+This feature is accessible from the <link linkend="image-more-effects">More Effects</link> dialog.
+</para>
+<para>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="image_invert.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</para>
+
+<para>This allows you to invert one or more RGB channels in the image or selection. Select <guilabel>All</guilabel> to change a photo into a negative and vice versa. This generally looks quite funny.</para>
+
+<tip>
+<para>To quickly invert all channels, you do not need to use this dialog. You can instead
+access the <guimenuitem>Invert Colors</guimenuitem> item in the <guimenu>Image</guimenu> or
+<guimenu>Selection</guimenu> menu.
+</para>
+</tip>
+
+</sect1>
+
+<sect1 id="image-reduce-colors">
+<title>Reduce Colors</title>
+
+<para>
+This feature is accessible from the <link linkend="image-more-effects">More Effects</link> dialog.
+</para>
+<para>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="image_reduce_colors.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</para>
+
+<para>
+This reduces the number of colors used by the image or selection, with or without dithering.
+</para>
+
+<para>
+Dithering generally provides better quality results, however, you may wish to disable it for artistic effects;
+<abbrev>e.g.</abbrev> using <guilabel>Monochrome</guilabel> instead of
+<guilabel>Monochrome (Dithered)</guilabel> gives a silhouette effect.
+</para>
+
+<para>
+Another important distinction is that while <guilabel>Monochrome (Dithered)</guilabel> will always reduce the entire image or selection to black and white, <guilabel>Monochrome</guilabel> will do this only if the image or selection contains more than 2 colors.
+</para>
+
+<tip>
+<para>For a quick, dithered monochrome image or selection, use the <link linkend="image-monochrome">Reduce to Monochrome (Dithered)</link> item of the <guimenu>Image</guimenu> or <guimenu>Selection</guimenu> menu.
+</para>
+</tip>
+
+<note>
+<para>
+Changing the number of colors here has no effect on the color depth of the file format. If you want to
+change the color depth, you should select it in the file saving dialogs. Note that, confusingly, changing
+the color depth also changes the number of colors.
+</para>
+</note>
+</sect1>
+
+<sect1 id="image-grayscale">
+<title>Reduce to Grayscale</title>
+
+<para> This reduces the entire image or selection to grayscale.</para>
+
+</sect1>
+
+<sect1 id="image-monochrome">
+<title>Reduce to Monochrome (Dithered)</title>
+
+<para>This reduces the entire image or selection to black and white.</para>
+
+<tip>
+<para>
+If you do not want the image or selection to be dithered, use the <link linkend="image-reduce-colors">
+Reduce Colors</link> dialog.
+</para>
+</tip>
+</sect1>
+
+<sect1 id="image-resize-scale">
+<title>Resize / Scale</title>
+
+<para>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="image_resize_scale.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</para>
+
+<para>Resizing the image changes the dimensions of the image without
+applying a transformation to the existing contents. Scaling the image will
+stretch the existing contents to the new dimensions. <guibutton>Smooth Scale</guibutton>
+generally provides better quality results than Scaling, by blending neighbouring colors.</para>
+
+<para>You can express the new dimensions in pixels, or as a percentage of
+the original size. If you select <guilabel>Keep aspect ratio</guilabel>, the
+width and height will be scaled by the same percentage.</para>
+
+<tip>
+<para>
+You can free-form <guibutton>Resize</guibutton> the entire image or <guibutton>Smooth Scale</guibutton> the selection using the corresponding handles.
+</para>
+</tip>
+
+<note>
+<para>Only scaling is supported for selections, and only resizing is
+supported for text boxes. See <link linkend="image-notes">Notes</link> for
+additional details about applying these effects.</para>
+</note>
+</sect1>
+
+<sect1 id="image-rotate">
+<title>Rotate</title>
+
+<para>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="image_rotate.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</para>
+
+<para>This rotates the image. You can specify the angle and direction of
+rotation.</para>
+
+<tip>
+<para>You can reverse the direction of rotation by specifying a negative
+custom angle.</para>
+</tip>
+
+<note>
+<para>See <link linkend="image-notes">Notes</link> for details about
+applying this effect to a selection.
+</para>
+</note>
+</sect1>
+
+<sect1 id="image-set-as-image">
+<title>Set as Image (Crop)</title>
+
+<para>This will set the selection as the image.</para>
+
+<note>
+<para>This is only available when you have an active selection.</para>
+</note>
+</sect1>
+
+<sect1 id="image-skew">
+<title>Skew</title>
+
+<para>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="image_skew.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</para>
+
+<para>This skews the entire image or selection horizontally and/or
+vertically.</para>
+
+<note>
+<para>See <link linkend="image-notes">Notes</link> for details about
+applying this effect to a selection.</para>
+</note>
+</sect1>
+
+<sect1 id="image-soften-sharpen">
+<title>Soften &amp; Sharpen</title>
+
+<para>
+This feature is accessible from the <link linkend="image-more-effects">More Effects</link> dialog.
+</para>
+<para>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="image_soften_sharpen.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</para>
+
+<para>
+Use this effect to soften or sharpen the image.
+</para>
+</sect1>
+
+<sect1 id="image-more-effects">
+<!-- More Effects is left at the end because it is not part of the Image Effects Reference - if a
+user selects the next page, the next page should be Autocrop / Remove Internal Border. -->
+<title>More Effects</title>
+
+<para>
+This dialog contains the <link linkend="image-balance">Balance</link>,
+<link linkend="image-emboss">Emboss</link>, <link linkend="image-flatten">Flatten</link>,
+<link linkend="image-invert">Invert</link>, <link linkend="image-reduce-colors">Reduce Colors</link>
+and <link linkend="image-soften-sharpen">Soften &amp; Sharpen</link> features.
+</para>
+</sect1>
+
+<sect1 id="image-notes">
+<title>Notes</title>
+
+<para><link linkend="image-resize-scale">Resizing / Scaling</link>, <link
+linkend="image-rotate">Rotating</link> and <link
+linkend="image-skew">Skewing</link> may change the dimensions of the
+image. You can view the new dimensions in the dialog.</para>
+
+<para>If you apply these effects to an image, the image will be resized if
+necessary. However, if you apply these effects to a selection, the image
+will not be resized, even if the transformed selection does not fit.</para>
+
+<para>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="rotate_image_30.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</para>
+
+<para>
+The left image has been rotated 30 degrees clockwise to form the right image. &kolourpaint; has
+automatically enlarged the image to accommodate the larger contents.
+</para>
+
+<para>
+<inlinemediaobject>
+<imageobject>
+<imagedata fileref="rotate_selection_30.png" format="PNG"/>
+</imageobject>
+</inlinemediaobject>
+</para>
+
+<para>
+The left <emphasis>selection</emphasis> has been rotated 30 degrees clockwise to form the right
+selection. The image size has remained the same, hence parts of the selection will not be visible
+without <link linkend="image-resize-scale">Resizing</link> the <emphasis>image</emphasis>.
+</para>
+</sect1>
+
+</chapter>
+
+<chapter id="credits">
+<title>Credits and License</title>
+<epigraph>
+<attribution>Carl Tucker</attribution>
+<para>
+It might not be concise documentation; it might not be complete documentation; but it is
+honest documentation.
+</para>
+</epigraph>
+
+<para>
+&kolourpaint;
+</para>
+<para>Program Copyright &copy; 2003, 2004, 2005 &Clarence.Dang; &Clarence.Dang.mail;</para>
+
+<para>
+&kolourpaint;-specific icons Copyright &copy; 2004, 2005
+Kristof Borrey <email>borrey@kde.org</email>,
+Nuno Pinheiro <email>nf.pinheiro@gmail.com</email>,
+Danny Allen <email>dannya40uk@yahoo.co.uk</email>
+</para>
+
+<para>Documentation and additional documentation artwork Copyright &copy; 2004, 2005
+&Thurston.Dang; &Thurston.Dang.mail;</para>
+
+<para>Portions reproduced with permission from <ulink
+url="http://kolourpaint.sourceforge.net/"></ulink>.</para>
+
+&underFDL;
+
+<para>This program is licensed as follows:</para>
+
+<para>Copyright &copy; 2003, 2004, 2005 &Clarence.Dang; &Clarence.Dang.mail;</para>
+
+<literallayout>
+All rights reserved.
+
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS&apos;&apos; AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+</literallayout>
+</chapter>
+
+<appendix id="installation">
+<title>Installation</title>
+<sect1 id="getting-kapp">
+<title>How to obtain &kolourpaint;</title>
+
+&install.intro.documentation;
+
+<para>More frequent releases with support for previous versions of &kde; are
+available at <ulink
+url="http://kolourpaint.sourceforge.net/">http://kolourpaint.sourceforge.net/</ulink>.</para>
+
+</sect1>
+
+<sect1 id="requirements">
+<title>Requirements</title>
+
+<para> &kolourpaint; 1.4_relight requires &kde; 3.5.</para>
+</sect1>
+
+<sect1 id="compilation">
+<title>Compilation and Installation</title>
+
+<note>
+<para>
+If you are reading this help in the &khelpcenter;, then &kolourpaint; has already been
+installed on this system and you do not need to follow these generic instructions.
+</para>
+</note>
+
+&install.compile.documentation;
+
+</sect1>
+
+<sect1 id="configuration">
+<title>Configuration</title>
+
+<para>&kolourpaint; should run without any additional configuration.</para>
+</sect1>
+
+</appendix>
+
+&documentation.index;
+</book>
+
+<!--
+Local Variables:
+mode: xml
+sgml-minimize-attributes:nil
+sgml-general-insert-case:lower
+sgml-indent-step:0
+sgml-indent-data:nil
+End:
+
+vim:tabstop=2:shiftwidth=2:expandtab
+-->
diff --git a/doc/kolourpaint/kolourpaint-main.png b/doc/kolourpaint/kolourpaint-main.png
new file mode 100644
index 00000000..abab73d8
--- /dev/null
+++ b/doc/kolourpaint/kolourpaint-main.png
Binary files differ
diff --git a/doc/kolourpaint/line_width.png b/doc/kolourpaint/line_width.png
new file mode 100644
index 00000000..0477b6e1
--- /dev/null
+++ b/doc/kolourpaint/line_width.png
Binary files differ
diff --git a/doc/kolourpaint/lines_30_45_deg.png b/doc/kolourpaint/lines_30_45_deg.png
new file mode 100644
index 00000000..315499e5
--- /dev/null
+++ b/doc/kolourpaint/lines_30_45_deg.png
Binary files differ
diff --git a/doc/kolourpaint/lines_30_deg.png b/doc/kolourpaint/lines_30_deg.png
new file mode 100644
index 00000000..9519df52
--- /dev/null
+++ b/doc/kolourpaint/lines_30_deg.png
Binary files differ
diff --git a/doc/kolourpaint/lines_45_deg.png b/doc/kolourpaint/lines_45_deg.png
new file mode 100644
index 00000000..870cd464
--- /dev/null
+++ b/doc/kolourpaint/lines_45_deg.png
Binary files differ
diff --git a/doc/kolourpaint/rotate_image_30.png b/doc/kolourpaint/rotate_image_30.png
new file mode 100644
index 00000000..ebf00431
--- /dev/null
+++ b/doc/kolourpaint/rotate_image_30.png
Binary files differ
diff --git a/doc/kolourpaint/rotate_selection_30.png b/doc/kolourpaint/rotate_selection_30.png
new file mode 100644
index 00000000..23567ef8
--- /dev/null
+++ b/doc/kolourpaint/rotate_selection_30.png
Binary files differ
diff --git a/doc/kolourpaint/selections_opaque_transparent.png b/doc/kolourpaint/selections_opaque_transparent.png
new file mode 100644
index 00000000..627e5fee
--- /dev/null
+++ b/doc/kolourpaint/selections_opaque_transparent.png
Binary files differ
diff --git a/doc/kolourpaint/spraycan_patterns.png b/doc/kolourpaint/spraycan_patterns.png
new file mode 100644
index 00000000..6505311a
--- /dev/null
+++ b/doc/kolourpaint/spraycan_patterns.png
Binary files differ
diff --git a/doc/kolourpaint/text_zoom_grid.png b/doc/kolourpaint/text_zoom_grid.png
new file mode 100644
index 00000000..4fa85435
--- /dev/null
+++ b/doc/kolourpaint/text_zoom_grid.png
Binary files differ
diff --git a/doc/kolourpaint/tool_brush.png b/doc/kolourpaint/tool_brush.png
new file mode 100644
index 00000000..32a23881
--- /dev/null
+++ b/doc/kolourpaint/tool_brush.png
Binary files differ
diff --git a/doc/kolourpaint/tool_color_picker.png b/doc/kolourpaint/tool_color_picker.png
new file mode 100644
index 00000000..569171e6
--- /dev/null
+++ b/doc/kolourpaint/tool_color_picker.png
Binary files differ
diff --git a/doc/kolourpaint/tool_color_washer.png b/doc/kolourpaint/tool_color_washer.png
new file mode 100644
index 00000000..97193458
--- /dev/null
+++ b/doc/kolourpaint/tool_color_washer.png
Binary files differ
diff --git a/doc/kolourpaint/tool_curve.png b/doc/kolourpaint/tool_curve.png
new file mode 100644
index 00000000..b86c96fb
--- /dev/null
+++ b/doc/kolourpaint/tool_curve.png
Binary files differ
diff --git a/doc/kolourpaint/tool_ellipse.png b/doc/kolourpaint/tool_ellipse.png
new file mode 100644
index 00000000..608d40b7
--- /dev/null
+++ b/doc/kolourpaint/tool_ellipse.png
Binary files differ
diff --git a/doc/kolourpaint/tool_elliptical_selection.png b/doc/kolourpaint/tool_elliptical_selection.png
new file mode 100644
index 00000000..70edc438
--- /dev/null
+++ b/doc/kolourpaint/tool_elliptical_selection.png
Binary files differ
diff --git a/doc/kolourpaint/tool_eraser.png b/doc/kolourpaint/tool_eraser.png
new file mode 100644
index 00000000..459d28a2
--- /dev/null
+++ b/doc/kolourpaint/tool_eraser.png
Binary files differ
diff --git a/doc/kolourpaint/tool_flood_fill.png b/doc/kolourpaint/tool_flood_fill.png
new file mode 100644
index 00000000..746ede5b
--- /dev/null
+++ b/doc/kolourpaint/tool_flood_fill.png
Binary files differ
diff --git a/doc/kolourpaint/tool_free_form_selection.png b/doc/kolourpaint/tool_free_form_selection.png
new file mode 100644
index 00000000..ed03ba39
--- /dev/null
+++ b/doc/kolourpaint/tool_free_form_selection.png
Binary files differ
diff --git a/doc/kolourpaint/tool_line.png b/doc/kolourpaint/tool_line.png
new file mode 100644
index 00000000..ce282923
--- /dev/null
+++ b/doc/kolourpaint/tool_line.png
Binary files differ
diff --git a/doc/kolourpaint/tool_pen.png b/doc/kolourpaint/tool_pen.png
new file mode 100644
index 00000000..ae64f5aa
--- /dev/null
+++ b/doc/kolourpaint/tool_pen.png
Binary files differ
diff --git a/doc/kolourpaint/tool_polygon.png b/doc/kolourpaint/tool_polygon.png
new file mode 100644
index 00000000..a5500d94
--- /dev/null
+++ b/doc/kolourpaint/tool_polygon.png
Binary files differ
diff --git a/doc/kolourpaint/tool_polyline.png b/doc/kolourpaint/tool_polyline.png
new file mode 100644
index 00000000..1e23ccd9
--- /dev/null
+++ b/doc/kolourpaint/tool_polyline.png
Binary files differ
diff --git a/doc/kolourpaint/tool_polystar.png b/doc/kolourpaint/tool_polystar.png
new file mode 100644
index 00000000..8eadbcad
--- /dev/null
+++ b/doc/kolourpaint/tool_polystar.png
Binary files differ
diff --git a/doc/kolourpaint/tool_rect_selection.png b/doc/kolourpaint/tool_rect_selection.png
new file mode 100644
index 00000000..a85ef3f8
--- /dev/null
+++ b/doc/kolourpaint/tool_rect_selection.png
Binary files differ
diff --git a/doc/kolourpaint/tool_rectangle.png b/doc/kolourpaint/tool_rectangle.png
new file mode 100644
index 00000000..a8455de0
--- /dev/null
+++ b/doc/kolourpaint/tool_rectangle.png
Binary files differ
diff --git a/doc/kolourpaint/tool_rectangles.png b/doc/kolourpaint/tool_rectangles.png
new file mode 100644
index 00000000..851faf71
--- /dev/null
+++ b/doc/kolourpaint/tool_rectangles.png
Binary files differ
diff --git a/doc/kolourpaint/tool_rounded_rectangle.png b/doc/kolourpaint/tool_rounded_rectangle.png
new file mode 100644
index 00000000..4b5a0617
--- /dev/null
+++ b/doc/kolourpaint/tool_rounded_rectangle.png
Binary files differ
diff --git a/doc/kolourpaint/tool_selections.png b/doc/kolourpaint/tool_selections.png
new file mode 100644
index 00000000..1b0d09bf
--- /dev/null
+++ b/doc/kolourpaint/tool_selections.png
Binary files differ
diff --git a/doc/kolourpaint/tool_spraycan.png b/doc/kolourpaint/tool_spraycan.png
new file mode 100644
index 00000000..75b7f748
--- /dev/null
+++ b/doc/kolourpaint/tool_spraycan.png
Binary files differ
diff --git a/doc/kolourpaint/tool_text.png b/doc/kolourpaint/tool_text.png
new file mode 100644
index 00000000..ffaab637
--- /dev/null
+++ b/doc/kolourpaint/tool_text.png
Binary files differ
diff --git a/doc/kolourpaint/view_thumbnails.png b/doc/kolourpaint/view_thumbnails.png
new file mode 100644
index 00000000..069a0888
--- /dev/null
+++ b/doc/kolourpaint/view_thumbnails.png
Binary files differ
diff --git a/doc/kooka/Makefile.am b/doc/kooka/Makefile.am
new file mode 100644
index 00000000..085981d9
--- /dev/null
+++ b/doc/kooka/Makefile.am
@@ -0,0 +1,4 @@
+
+KDE_LANG = en
+KDE_DOCS = AUTO
+
diff --git a/doc/kooka/index.docbook b/doc/kooka/index.docbook
new file mode 100644
index 00000000..c0140d7e
--- /dev/null
+++ b/doc/kooka/index.docbook
@@ -0,0 +1,747 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+ <!ENTITY kappname "&kooka;">
+ <!ENTITY package "kdegraphics">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE"> <!-- change language only here -->
+]>
+
+<book lang="&language;">
+
+<bookinfo>
+<title>The &kooka; Manual</title>
+
+<authorgroup>
+<author> <firstname>Martin</firstname>
+<surname>Sommer</surname>
+<affiliation><address><email>msommer@suse.de</email></address></affiliation>
+</author>
+<othercredit role="developer">
+<firstname>Klaas</firstname>
+<surname>Freitag</surname>
+<affiliation>
+<address><email>freitag@suse.de</email></address>
+</affiliation>
+<contrib>Developer</contrib>
+</othercredit>
+
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+
+</authorgroup>
+
+<copyright>
+<year>2002</year>
+<holder>Klaas Freitag, Martin Sommer</holder>
+</copyright>
+
+<legalnotice
+>&FDLNotice;</legalnotice>
+
+<date>2002-02-04</date>
+<releaseinfo>0.33.00</releaseinfo>
+
+<abstract><para>&kooka; is a very useful &kde; scanning
+application.</para></abstract>
+
+
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>Scanner</keyword>
+</keywordset>
+
+</bookinfo>
+
+<chapter id="introduction">
+<title>Introduction</title>
+
+<para>&kooka; is a &kde; application that enables easy scanning using
+<acronym>SANE</acronym> libraries. Therefore,<acronym>SANE</acronym>
+the package must be installed to use &kooka;. Clear and concise use
+was the focus of its development.</para>
+
+<para>Character recognition is also provided by the built-in text
+recognition program gocr. Install <application>gocr</application> to
+use this functionality. After character recognition is complete, the
+recognized material can be opened in the text editor &kate; with just
+one click, where you can edit the contents.</para>
+
+</chapter>
+
+<chapter id="how-to-use">
+<title>Application Instructions</title>
+
+<para>The web site <ulink
+url="http://www.sane-project.org/">http://www.sane-project.org</ulink>
+has information about supported scanners. Refer to it before
+purchasing a scanner, if possible.</para>
+
+<sect1 id="screen">
+<title>The &kooka; Main Window</title>
+
+<screenshot>
+<screeninfo>The &kooka; Main Window </screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="kooka_mainctrl.png" format="PNG"/></imageobject>
+</mediaobject>
+
+</screenshot>
+
+<para>Start &kooka; from a console by simply entering
+<userinput><command>kooka</command></userinput>. Create a link on the
+&kde; desktop, which uses a scanner icon, if desired.</para>
+
+<para>The main window in &kooka; consists of three frames. At the top,
+see both icon and a menu panels. Use the mouse to enlarge or reduce
+the windows as needed.</para>
+
+<itemizedlist>
+<listitem>
+<para>The navigation window consists of two tabs, which allow you to
+switch between the <guilabel>Preview</guilabel> and the integrated
+file browser called the <guilabel>Gallery</guilabel>. The working
+folder is displayed in the lower part of the window along with the
+folder where the scan will be saved.</para>
+</listitem>
+
+<listitem>
+<para>Make your scanner-dependent settings, which are dependent on the
+scanner you have connected, in the lower left window. Usually, these
+are settings for resolution, brightness and contrast, scanning mode
+(&eg;, color, gray, or binary), and for gamma values.</para>
+
+<para>Configure your settings here first. Afterwards, initiate the
+preview scan with <guimenuitem>Preview</guimenuitem>. If the
+<guilabel>Preview</guilabel> tab in the upper window is selected, see
+the results there.</para>
+
+<para>Select the various formats in the preview image itself to define
+the final dimensions. The <guilabel>User</guilabel> setting is
+recommended for this, so you select the area to scan in the preview
+display with the mouse.</para>
+
+<para>After this is done, click <guimenu>Scan</guimenu> to scan the
+selection made in the preview. After scanning, you will be asked in
+which format to save the image whether to make this your standard
+format (without being prompted to confirm your selection in the
+future).</para>
+
+<note><para>If you checked that you do not want to be asked about the
+save format, the memory assistant will no longer appear. To change the
+format some time in the future, select <menuchoice>
+<guimenu>Settings</guimenu> <guimenuitem>Configure
+Kooka...</guimenuitem> <guimenuitem>Save Image</guimenuitem>
+<guimenuitem>Always show memory assistant</guimenuitem>
+</menuchoice></para></note>
+
+</listitem>
+<listitem>
+<para>The large window shows how the image appears after a final
+scan.</para>
+</listitem>
+</itemizedlist>
+
+</sect1>
+
+</chapter>
+
+<chapter id="commands">
+<title>Command References</title>
+
+<sect1 id="kooka-toolbar">
+<title>The main &kooka; Toolbar</title>
+
+
+<sect2>
+<title>The <guimenu>File</guimenu> Menu</title>
+
+<variablelist>
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>P</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Print</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para>Prints the displayed image.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Create Folder...</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para>Create a folder to hold your images.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Save Image</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para>Save the image selected underneath the
+<guilabel>Kooka Gallery</guilabel>.</para>
+<para>See the <link linkend="save"> Save</link>
+section for details.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Delete Image</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para>Delete the image selected underneath the
+<guilabel>Kooka Gallery</guilabel>.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Unload Image</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para>Remove the image displayed in the <guilabel>Image
+Viewer</guilabel>.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>Q</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Quit</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para>Quit &kooka;.</para>
+</listitem>
+</varlistentry>
+
+</variablelist>
+</sect2>
+
+<sect2>
+<title>The <guimenu>Image</guimenu> Menu</title>
+
+<variablelist>
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>G</keycap></keycombo>
+</shortcut>
+<guimenu>Image</guimenu>
+<guimenuitem>Open image in graphic application</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para>Enter a graphics application for opening your scanned image
+directly. Recommended applications include <application>The
+GIMP</application>.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice><shortcut>
+<keycombo action="simul">&Ctrl;<keycap>O</keycap></keycombo>
+</shortcut>
+<guimenu>Image</guimenu>
+<guimenuitem>OCR image...</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para>Start the window for optical character recognition
+(<acronym>OCR</acronym>). If you have <application>gocr</application>
+installed, then the path to it should be in the path line. This
+starts the character recognition for the preview image or for the
+highlighted area.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice><shortcut>
+<keycombo action="simul">&Ctrl;<keycap>C</keycap></keycombo>
+</shortcut>
+<guimenu>Image</guimenu>
+<guimenuitem>OCR on selection...</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para>A window will reappear for the character recognition. Here,
+however, the character recognition is only for the area highlighted in
+the final scan.</para>
+</listitem>
+</varlistentry>
+
+
+<varlistentry>
+<term>
+<menuchoice><shortcut>
+<keycombo action="simul">&Ctrl;<keycap>I</keycap></keycombo>
+</shortcut>
+<guimenu>Image</guimenu>
+<guimenuitem>Scale to Width</guimenuitem>
+</menuchoice></term>
+<listitem >
+<para>This proportionally scales the image in the large canvas to the
+width of the display.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice><shortcut>
+<keycombo action="simul">&Ctrl;<keycap>H</keycap></keycombo>
+</shortcut>
+<guimenu>Image</guimenu>
+<guimenuitem>Scale to Height</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para>Proportionately scales the image to the height of the
+display.</para>
+</listitem >
+</varlistentry>
+
+<varlistentry>
+<term >
+<menuchoice><shortcut>
+<keycombo action="simul">&Ctrl;<keycap>S</keycap></keycombo>
+</shortcut>
+<guimenu>Image</guimenu>
+<guimenuitem>Original Size</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para>Restores the original scan size by reducing or enlarging the
+image in the display.</para>
+
+<para>There are additional methods of scaling an image:
+<mousebutton>right</mousebutton> click the image display. Redefine the
+three named options and set the enlargement itself. This can also be
+done in the <guilabel>Preview</guilabel> window.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice><shortcut>
+<keycombo action="simul">&Ctrl;<keycap>N</keycap></keycombo>
+</shortcut>
+<guimenu>Image</guimenu>
+<guimenuitem>Create from selection</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para>If the scanned image includes more than you want to appear in the final
+image, use this tool to crop your image by marking your selection in
+the larger image display to the right then selecting this tool. The
+image is cropped according to your selection. You may already be
+familiar with this function from <application>The GIMP</application>
+crop tool.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice><shortcut>
+<keycombo action="simul">&Ctrl;<keycap>V</keycap></keycombo>
+</shortcut>
+<guimenu>Image</guimenu>
+<guimenuitem>Mirror image vertically</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para>Flip image vertically.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut>
+<keycombo action="simul">&Ctrl;<keycap>M</keycap></keycombo>
+</shortcut>
+<guimenu>Image</guimenu>
+<guimenuitem>Mirror image horizontally</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>Flip image horizontally.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut>
+<keycombo action="simul">&Ctrl;<keycap>B</keycap></keycombo>
+</shortcut>
+<guimenu>Image</guimenu>
+<guimenuitem>Mirror both directions</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para>Flip image both horizontally and vertically.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice><shortcut>
+<keycombo action="simul">&Ctrl;<keycap>R</keycap></keycombo>
+</shortcut>
+<guimenu>Image</guimenu>
+<guimenuitem>Rotate image clockwise</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para>Rotate the image ninety degrees clockwise.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice><shortcut>
+<keycombo action="simul">&Ctrl;<keycap>W</keycap></keycombo>
+</shortcut>
+<guimenu>Image</guimenu>
+<guimenuitem>Rotate image counter-clockwise</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>Rotate the image ninety degrees counterclockwise.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice><shortcut>
+<keycombo action="simul">&Ctrl;<keycap>D</keycap></keycombo>
+</shortcut>
+<guimenu>Image</guimenu>
+<guimenuitem>Rotate image 180 degrees</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>Rotates image 180 degrees.</para>
+</listitem>
+</varlistentry>
+</variablelist>
+</sect2>
+
+<sect2>
+<title>The <guimenu>Settings</guimenu> Menu</title>
+
+<variablelist>
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Show Toolbar</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>Removes the top toolbar to give additional viewing area. </para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Show Statusbar</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>Removes the bottom statusbar to give additional viewing area.</para>
+</listitem>
+</varlistentry>
+ </variablelist>
+</sect2>
+
+<sect2>
+<title>Configuring Shortcuts</title>
+
+<para>The <menuchoice>
+<guimenu>Settings</guimenu><guimenuitem>Configure Shortcuts...</guimenuitem></menuchoice>
+allows you to specify key bindings</para>
+
+
+<para>Below is an example of how to configure a short cut for deleting
+an image.</para>
+
+<screenshot>
+<screeninfo>Picture of shortcut dialog</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="shortcut0.png" format="PNG"/>
+ </imageobject>
+ </mediaobject>
+</screenshot>
+
+<itemizedlist>
+<listitem><para>
+Click on the custom button.
+</para></listitem>
+
+<listitem><para>
+Next click on the primary button.
+</para></listitem>
+
+<listitem><para>
+Do <userinput><keycombo
+action="seq"><keycap>CTRL</keycap><keycap>X</keycap></keycombo></userinput>
+and the dialog should disappear. The keybinding is now entered.
+</para></listitem>
+</itemizedlist>
+
+<screenshot>
+<screeninfo>Picture of keybinding dialog</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="shortcut1.png" format="PNG"/>
+ </imageobject>
+ </mediaobject>
+</screenshot>
+
+<para>Pressing the keys <userinput><keycombo
+action="seq"><keycap>CTRL</keycap><keycap>X</keycap></keycombo></userinput>
+now deletes the image selected underneath <guilabel>Kooka Gallery</guilabel>.
+</para>
+</sect2>
+
+<sect2>
+<title>Configuring Toolbars</title>
+<para>The <menuchoice>
+<guimenu>Settings</guimenu><guimenuitem>Configure Toolbars...</guimenuitem></menuchoice>
+Is used to add additional buttons to the toolbars.</para>
+
+<screenshot>
+<screeninfo>Picture of toolbars dialog</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="toolbar.png" format="PNG"/>
+ </imageobject>
+ </mediaobject>
+</screenshot>
+
+
+<itemizedlist>
+
+<listitem>
+<para>To add a button to the File toolbar,
+</para>
+
+<screenshot>
+<screeninfo>Picture of toolbars dialog</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="toolbar1.png" format="PNG"/>
+ </imageobject>
+ </mediaobject>
+</screenshot>
+
+<para> make sure <guilabel>Main Toolbar</guilabel> is displayed in
+the top combo box.
+</para></listitem>
+
+<listitem><para>
+Click on one of the items in the left hand pane. This item will now have a
+blue background showing that it has been selected.
+</para></listitem>
+
+<listitem><para>
+Next click on the <keysym>Right arrow</keysym> button to place it in
+the right pane.
+</para></listitem>
+
+<listitem><para>
+Click on <userinput><guilabel>Apply</guilabel></userinput> and then
+click on <userinput><guilabel>OK</guilabel></userinput>
+</para></listitem>
+</itemizedlist>
+
+
+<para>The new Item should be in the toolbar.
+<screenshot>
+<screeninfo>Picture of toolbars dialog</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="toolbar2.png" format="PNG"/>
+ </imageobject>
+ </mediaobject>
+</screenshot>
+</para>
+</sect2>
+
+<sect2>
+<title>Configuring Kooka</title>
+<para>The <menuchoice>
+<guimenu>Settings</guimenu><guimenuitem>Configure Kooka...</guimenuitem>
+</menuchoice>
+</para>
+
+
+<variablelist>
+<varlistentry>
+<term>
+<menuchoice>
+<guilabel>Kooka Startup Preferences</guilabel>
+</menuchoice>
+</term>
+<listitem>
+<para>You may want to uncheck <guilabel>Show the scanner selection box
+on next startup</guilabel>, if you have only one scanner. If you
+have only one computer you may also want to uncheck
+<guilabel>Query network for available scanners</guilabel>.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guilabel>Thumbnail View</guilabel>
+</menuchoice>
+</term>
+<listitem>
+<para>Here the size and the shading of the thumbnails can be adjusted;
+as well as the background. For example, you might want to reduce the
+size of the thumbnails if you are scanning many pages from a book.
+</para>
+</listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect2>
+
+
+</sect1>
+</chapter>
+
+<chapter id="save">
+<title>Save</title>
+<subtitle>More on Saving Images</subtitle>
+
+<para>The method for saving an image is somewhat different in &kooka;
+than in many other applications. Click the
+<guilabel>Gallery</guilabel> tab to open a small file browser. This is
+the folder <filename
+class="directory">~/.kde/share/apps/ScanImages/</filename> In the
+lower portion of the window, your current subfolder in the gallery
+is shown. This is where all scanned images are first saved as
+files. When starting &kooka; for the first time, you will only see the
+<filename class="directory">ScanImages</filename>. Create
+subfolders by <mousebutton>right</mousebutton> clicking this
+folder. The selected folder, highlighted in blue, is the first save
+location of the scanned images. The scans are labeled in ascending
+numerical order as in <filename>kscan_0001</filename> and
+<filename>kscan_0002</filename>.</para>
+
+<para>To save an image permanently, <mousebutton>left</mousebutton>
+click the name. Next, give a new name and the appropriate ending for
+the image format chosen when scanning. If you enter a different
+extension, you will get a message that it does not correspond to the
+scanned format. Although you can still save the image under this name,
+it will retain its original format. At present,
+<quote>On-the-fly</quote> conversion is not offered.</para
+
+><para>If you do not want to use this method of managing your images
+in <filename
+class="directory">~/.kde/share/apps/ScanImages/</filename>, you can,
+of course, save them to another location. To do this,
+<mousebutton>right</mousebutton> click the
+image name and select <guilabel>Save</guilabel>. Choose any path
+here. In addition, close or permanently delete images here.</para>
+
+<para>To incorporate other images in the gallery, add them in
+&konqueror; by dragging and dropping. Open &konqueror; to the
+folder containing the desired images. Then add them to the &kooka;
+gallery by dragging them and dropping them into the gallery.</para>
+
+</chapter>
+
+<chapter id="ocr">
+<title>Character Recognition</title>
+
+<para>As already mentioned, the <application>gocr</application> must
+be installed. Scan a preview of your document in grayscale or
+color. You can only scan in binary mode if you have a pure white sheet
+of paper with black print. Next, highlight the text to be recognized
+in the preview window. Then, do your final scan in binary mode with
+<guibutton>Scan</guibutton>.</para>
+
+<para>Now click the second icon from the left,
+<inlinemediaobject><imageobject>
+ <imagedata fileref="ocr-select.png" format="PNG"/>
+ </imageobject></inlinemediaobject>,
+ in the icon panel,
+<guilabel>OCR on Selection...</guilabel>, or select
+this item in the <guilabel>Image</guilabel> menu. For your
+first try, do not change the default settings shown in the emerging
+<acronym>OCR</acronym> window. These are usually appropriate and meet
+most needs. Now click <guimenuitem>Start character
+recognition</guimenuitem>. You will now see a window containing the
+<acronym>OCR</acronym> results. The quality depends heavily on that of
+the document itself. </para>
+
+<screenshot> <screeninfo>The gocr Window</screeninfo> <mediaobject>
+<imageobject><imagedata fileref="kooka_gocr.png"
+format="PNG"/></imageobject> </mediaobject> </screenshot>
+
+<para>The text can now be opened by clicking the button with the
+&kate; editor. After the final scan, mark a selection in the image
+display to the right to load just a part of the text or image to the
+<acronym>OCR</acronym>. Next, in the icon panel, click the third
+button from the right or click in the menu on
+<guimenuitem>OCR on selection</guimenuitem>. Now
+proceed as described in the previous section.</para >
+
+<screenshot>
+<screeninfo>The Results of the <acronym>OCR</acronym></screeninfo>
+<mediaobject>
+<imageobject>
+<imagedata fileref="kooka_gocr_result.png"
+format="PNG"/></imageobject>
+</mediaobject>
+</screenshot>
+
+</chapter>
+
+<chapter id="credits">
+<title>Credits and License</title>
+
+<para>&kooka;</para>
+
+<para> Copyright for the application 2001-2002 Klaas Freitag
+<email>freitag@suse.de</email></para>
+
+<para>Copyright for the documentation 2002 Martin Sommer
+<email>msommer@suse.de</email></para>
+
+<!-- TRANS:CREDIT_FOR_TRANSLATORS -->
+
+&underFDL;
+&underGPL;
+
+</chapter>
+
+<appendix id="installation">
+<title>Installation</title>
+
+&install.intro.documentation;
+
+&install.compile.documentation;
+
+</appendix>
+
+</book>
+
diff --git a/doc/kooka/kooka_gocr.png b/doc/kooka/kooka_gocr.png
new file mode 100644
index 00000000..ab94f75e
--- /dev/null
+++ b/doc/kooka/kooka_gocr.png
Binary files differ
diff --git a/doc/kooka/kooka_gocr_result.png b/doc/kooka/kooka_gocr_result.png
new file mode 100644
index 00000000..e96bbbed
--- /dev/null
+++ b/doc/kooka/kooka_gocr_result.png
Binary files differ
diff --git a/doc/kooka/kooka_mainctrl.png b/doc/kooka/kooka_mainctrl.png
new file mode 100644
index 00000000..1e727089
--- /dev/null
+++ b/doc/kooka/kooka_mainctrl.png
Binary files differ
diff --git a/doc/kooka/ocr-select.png b/doc/kooka/ocr-select.png
new file mode 100644
index 00000000..db076898
--- /dev/null
+++ b/doc/kooka/ocr-select.png
Binary files differ
diff --git a/doc/kooka/shortcut0.png b/doc/kooka/shortcut0.png
new file mode 100644
index 00000000..0e2eff1f
--- /dev/null
+++ b/doc/kooka/shortcut0.png
Binary files differ
diff --git a/doc/kooka/shortcut1.png b/doc/kooka/shortcut1.png
new file mode 100644
index 00000000..e93bc9b8
--- /dev/null
+++ b/doc/kooka/shortcut1.png
Binary files differ
diff --git a/doc/kooka/toolbar.png b/doc/kooka/toolbar.png
new file mode 100644
index 00000000..56675b0b
--- /dev/null
+++ b/doc/kooka/toolbar.png
Binary files differ
diff --git a/doc/kooka/toolbar1.png b/doc/kooka/toolbar1.png
new file mode 100644
index 00000000..a446a475
--- /dev/null
+++ b/doc/kooka/toolbar1.png
Binary files differ
diff --git a/doc/kooka/toolbar2.png b/doc/kooka/toolbar2.png
new file mode 100644
index 00000000..5ec2f725
--- /dev/null
+++ b/doc/kooka/toolbar2.png
Binary files differ
diff --git a/doc/kpdf/Makefile.am b/doc/kpdf/Makefile.am
new file mode 100644
index 00000000..085981d9
--- /dev/null
+++ b/doc/kpdf/Makefile.am
@@ -0,0 +1,4 @@
+
+KDE_LANG = en
+KDE_DOCS = AUTO
+
diff --git a/doc/kpdf/configure.png b/doc/kpdf/configure.png
new file mode 100644
index 00000000..bbe89d9f
--- /dev/null
+++ b/doc/kpdf/configure.png
Binary files differ
diff --git a/doc/kpdf/index.docbook b/doc/kpdf/index.docbook
new file mode 100644
index 00000000..7da3ab5f
--- /dev/null
+++ b/doc/kpdf/index.docbook
@@ -0,0 +1,932 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+ <!ENTITY kpdf "<application>KPDF</application>">
+ <!ENTITY kappname "&kpdf;">
+ <!ENTITY package "kdegraphics">
+ <!ENTITY % English "INCLUDE">
+ <!ENTITY % addindex "IGNORE">
+]>
+
+<book lang="&language;">
+ <bookinfo>
+ <title>The &kpdf; Handbook</title>
+ <authorgroup>
+ <author>
+ <firstname>Albert</firstname>
+ <surname>Astals Cid</surname>
+ <affiliation>
+ <address><email>tsdgeos@yahoo.es</email></address>
+ </affiliation>
+ </author>
+ <author>
+ <firstname>Titus</firstname>
+ <surname>Laska</surname>
+ <affiliation>
+ <address><email>titus.laska@gmx.de</email></address>
+ </affiliation>
+ </author>
+ <!-- TRANS:ROLES_OF_TRANSLATORS -->
+ </authorgroup>
+ <legalnotice>&FDLNotice;</legalnotice>
+ <date>2006-05-20</date>
+ <releaseinfo>0.5</releaseinfo>
+ <!-- Abstract about this handbook -->
+ <abstract>
+ <para>&kpdf; is a &kde; PDF viewer based on xpdf code.</para>
+ </abstract>
+ <keywordset>
+ <keyword>KDE</keyword>
+ <keyword>kpdf</keyword>
+ <keyword>pdf</keyword>
+ </keywordset>
+ </bookinfo>
+ <chapter id="introduction">
+ <title>Introduction</title>
+ <para>&kpdf; is a &kde; <firstterm>PDF</firstterm> (Portable Document Format) viewer
+ based on the code of the xpdf application. Although being based on xpdf code, &kpdf;
+ has some unique features such as continuous mode and presentation support.
+ </para>
+ <para>
+ The PDF format is widely used for publishing documents that are
+ mostly not meant to be edited again. &kpdf; is only a viewer
+ for these files and therefore it doesn't provide any functionality
+ to edit or create PDF documents.
+ </para>
+ </chapter>
+ <chapter id="use">
+ <title>Using &kpdf;</title>
+ <sect1 id="opening">
+ <title>Opening Files</title>
+ <para>
+ To view a PDF file in &kpdf;, select <menuchoice><guimenu>File</guimenu><guimenuitem>Open...
+ </guimenuitem></menuchoice>, choose a PDF or PS file in the dialogue and click <guibutton>Open</guibutton>.
+ Your file should now be displayed in the main window.
+ </para>
+ <para>
+ If you have already opened files in &kpdf; before, you can quickly access them by selecting them in
+ the <menuchoice><guimenu>File</guimenu><guisubmenu>Open Recent</guisubmenu></menuchoice> menu.
+ </para>
+ <para>
+ After having a file opened you probably want to read it and therefore navigate through it. Click
+ Next to learn more about this.
+ </para>
+ </sect1>
+ <sect1 id="navigating">
+ <title>Navigating</title>
+ <para>This section describes how you can navigate through a document in &kpdf;.</para>
+ <para>
+ There are multiple ways of scrolling the viewing area. One is to use the
+ <keycap>Up Arrow</keycap> and <keycap>Down Arrow</keycap> keys. You may also use
+ the scrollbar, your <!--TODO: insert entity, if any-->mousewheel or the <keycap>Page Up</keycap> and <keycap>Page Down</keycap>
+ keys.
+ </para>
+ <para>
+ Another way is to hold the &LMB; down at any place on the document while dragging the mouse in the
+ opposite direction of where you want to move. This procedure only works if the Browse Tool is
+ enabled, which you can select by choosing <menuchoice><guimenu>Tools</guimenu><guimenuitem>Browse Tool
+ </guimenuitem></menuchoice>.
+ </para>
+ <para>
+ The navigation panel on the left side of the screen enables two more ways of navigating
+ through a document:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ If you click on a page thumbnail the viewing area will be brought to
+ that page.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ If the document has a table of contents, clicking on a table
+ of contents item will bring the document to to the page linked to that
+ item.
+ </para>
+ </listitem>
+ </itemizedlist>
+ <para>
+ Some documents have links. In this case you can click on them and the view will
+ change to the page it links to. If the link is to a web page the default
+ browser will be invoked.
+ </para>
+ <para>
+ Additionally, you may use the following functionality to quickly move to specific places
+ in the document:
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ You can go to the first page of the document using
+ <keycombo action="simul">&Ctrl;<keycap>Home</keycap></keycombo> or
+ using
+ <menuchoice>
+ <guimenu>Go</guimenu>
+ <guimenuitem>First Page</guimenuitem>
+ </menuchoice>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ You can go to the last page of the document using
+ <keycombo action="simul">&Ctrl;<keycap>End</keycap></keycombo> or
+ using
+ <menuchoice>
+ <guimenu>Go</guimenu>
+ <guimenuitem>Last Page</guimenuitem>
+ </menuchoice>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ You can go to the next page of the document using
+ <keycap>Space</keycap>, the <guibutton>Next Page</guibutton> Toolbar
+ button or using
+ <menuchoice>
+ <guimenu>Go</guimenu>
+ <guimenuitem>Next Page</guimenuitem>
+ </menuchoice>.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ You can go to the previous page of the document using
+ <keycap>Backspace</keycap>, the <guibutton>Previous Page</guibutton> Toolbar
+ button or using
+ <menuchoice>
+ <guimenu>Go</guimenu>
+ <guimenuitem>Previous Page</guimenuitem>
+ </menuchoice>.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </sect1>
+ <sect1 id="presentationMode">
+ <title>Presentation Mode</title>
+ <para>
+ The Presentation mode represents another way to view PDF documents in &kpdf;. It can be
+ enabled in
+ <menuchoice><guimenu>View</guimenu><guimenuitem>Presentation</guimenuitem></menuchoice>.
+ It shows the document on a page per page basis. The pages are shown with
+ zoom to page, that means all the page is visible.
+ </para>
+ <note>
+ <para>
+ PDF documents can even specify that they are always opened in presentation mode.
+ </para>
+ </note>
+ <para>
+ To navigate between
+ pages you may use the &LMB; (next page) and the &RMB; (previous page), the mouse
+ wheel, the arrow icons that appear as soon as you move the mouse cursor to the top of the screen,
+ or the keys specified in the <link linkend="navigating">Navigating</link>
+ section.
+ </para>
+ <para>
+ You can exit presentation mode at any time by pressing the <keycap>ESC</keycap> key or clicking
+ the <guiicon>Quit</guiicon> icon appearing if you move the mouse cursor to the top of the
+ screen.
+ </para>
+ <para>
+ Presentation mode has some configuration options, you can find their
+ description at <link linkend="configpresentation">Configuring &kpdf;</link>.
+ </para>
+ </sect1>
+ </chapter>
+
+ <chapter id="primary-menu-items">
+ <title>The Menubar</title>
+
+ <sect1 id="menufile">
+ <title>The <guimenu>File</guimenu> Menu</title>
+ <variablelist>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut>
+ <keycombo action="simul">&Ctrl;<keycap>O</keycap></keycombo>
+ </shortcut>
+ <guimenu>File</guimenu>
+ <guimenuitem>Open...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>Open</action> a PDF or PS file. If there is already an opened file it will be closed.
+ For more information, see the section about <link linkend="opening">Opening Files</link>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>File</guimenu>
+ <guimenuitem>Open Recent</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>Open</action> a file which was used previously from a
+ submenu. If a file is currently being displayed it
+ will be closed. For more information, see the section about
+ <link linkend="opening">Opening Files</link>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>File</guimenu>
+ <guimenuitem>Save As...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para><action>Save</action> the currently open file under a different name.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut><keycombo action="simul">&Ctrl;<keycap>P</keycap></keycombo></shortcut>
+ <guimenu>File</guimenu>
+ <guimenuitem>Print...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>Print</action> the currently displayed document.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>File</guimenu>
+ <guimenuitem>Print Preview...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>
+ <action>Show a preview</action> of how the currently displayed
+ document would be printed with the default options.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>File</guimenu>
+ <guimenuitem>Properties</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para><action>Display some basic information</action> about the document, such as
+ title, author, creation date, and details about the fonts used.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut><keycombo action="simul">&Ctrl; <keycap>Q</keycap></keycombo></shortcut>
+ <guimenu>File</guimenu>
+ <guimenuitem>Quit</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para><action>Close</action> &kpdf;.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect1>
+
+ <sect1 id="menuedit">
+ <title>The <guimenu>Edit</guimenu> Menu</title>
+ <variablelist>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut><keycombo action="simul">&Ctrl; <keycap>F</keycap></keycombo></shortcut>
+ <guimenu>Edit</guimenu>
+ <guimenuitem>Find...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>Open a dialogue that allows you to <action>search for a string in
+ the document</action>.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut><keycap>F3</keycap></shortcut>
+ <guimenu>Edit</guimenu>
+ <guimenuitem>Find Next</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>Try to <action>find the previous searched string again</action> in the document.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect1>
+
+ <sect1 id="menuview">
+ <title>The <guimenu>View</guimenu> Menu</title>
+ <variablelist>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut><keycombo action="simul">&Ctrl;&Shift;<keycap>P</keycap></keycombo></shortcut>
+ <guimenu>View</guimenu>
+ <guimenuitem>Presentation</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para><action>Activates</action> the Presentation Mode. For more information, see the
+ section about <link linkend="presentationMode">Presentation Mode</link>.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut><keycombo action="simul">&Ctrl;<keycap>+</keycap></keycombo></shortcut>
+ <guimenu>View</guimenu>
+ <guimenuitem>Zoom In</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para><action>Increase the magnification</action> of the document view.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut><keycombo action="simul">&Ctrl;<keycap>-</keycap></keycombo></shortcut>
+ <guimenu>View</guimenu>
+ <guimenuitem>Zoom Out</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para><action>Decrease the magnification</action> of the document view.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>View</guimenu>
+ <guimenuitem>Fit to Page Width</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para><action>Change the magnification</action> of the document
+ view to a value that makes the pages' width equal to the document
+ view's width.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>View</guimenu>
+ <guimenuitem>Fit to Page</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para><action>Change the magnification</action> of the document view
+ to a value that makes at least one whole page visible.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>View</guimenu>
+ <guimenuitem>Continuous</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para><action>Enable the continuous page mode</action>. In continuous mode,
+ all pages of the document are shown, and you can scroll through
+ them without having to use the <menuchoice><guimenu>Go</guimenu>
+ <guimenuitem>Previous Page</guimenuitem></menuchoice> and
+ <menuchoice><guimenu>Go</guimenu><guimenuitem>Next Page</guimenuitem>
+ </menuchoice> options.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>View</guimenu>
+ <guimenuitem>Two Pages</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para><action>Enable the two page mode</action>, which shows two pages of
+ the document next to each other..</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect1>
+
+ <sect1 id="menugo">
+ <title>The <guimenu>Go</guimenu> Menu</title>
+ <variablelist>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut><keycap>Backspace</keycap></shortcut>
+ <guimenu>Go</guimenu>
+ <guimenuitem>Previous Page</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para><action>View the previous page</action> of the document.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut><keycap>Space</keycap></shortcut>
+ <guimenu>Go</guimenu>
+ <guimenuitem>Next Page</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para><action>View the next page</action> of the document.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut><keycombo action="simul">&Ctrl; <keycap>Home</keycap></keycombo></shortcut>
+ <guimenu>Go</guimenu>
+ <guimenuitem>First Page</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para><action>Go to the first page</action> of the document.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut><keycombo action="simul">&Ctrl; <keycap>End</keycap></keycombo></shortcut>
+ <guimenu>Go</guimenu>
+ <guimenuitem>Last Page</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para><action>Go to the last page</action> of the document.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut><keycombo action="simul">&Alt; <keycap>Left</keycap></keycombo></shortcut>
+ <guimenu>Go</guimenu>
+ <guimenuitem>Back</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para><action>Go back to the previous view</action> of the document.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut><keycombo action="simul">&Alt;<keycap>Right</keycap></keycombo></shortcut>
+ <guimenu>Go</guimenu>
+ <guimenuitem>Forward</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para><action>Move forward to the next view</action> of the document. This only works if you have already moved back before.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut><keycombo action="simul">&Ctrl;<keycap>G</keycap></keycombo></shortcut>
+ <guimenu>Go</guimenu>
+ <guimenuitem>Go to Page</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>Open a dialog which allows you to <action>go to any page</action> of the document.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect1>
+
+ <sect1 id="menutools">
+ <title>The <guimenu>Tools</guimenu> Menu</title>
+ <variablelist>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Tools</guimenu>
+ <guimenuitem>Browse Tool</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>The mouse will have its normal behaviour, &LMB; for dragging the document and following links and &RMB; for adding bookmarks and fit to width.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Tools</guimenu>
+ <guimenuitem>Zoom Tool</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>The mouse will work as a zoom tool. Clicking &LMB; and dragging will zoom the view to the selected area, clicking &RMB; will bring the document back to the previous zoom.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Tools</guimenu>
+ <guimenuitem>Select Tool</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>The mouse will work as a select tool. In that mode clicking &LMB; and dragging will give the option of copying the text/image of current the selected area to the clipboard, speak a text or to save an image to a file.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect1>
+
+ <sect1 id="settings-menu">
+ <title>The <guimenu>Settings</guimenu> Menu</title>
+ <variablelist>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut><keycombo action="simul">&Ctrl;<keycap>M</keycap></keycombo></shortcut>
+ <guimenu>Settings</guimenu>
+ <guimenuitem>Show/Hide Menubar</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para><action>Toggle the Menubar display</action> on and off. Once
+ hidden it can be made visible using the &RMB; menu.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Settings</guimenu>
+ <guimenuitem>Show/Hide Toolbar</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para><action>Toggle the Toolbar display</action> on and off.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut><keycombo action="simul">&Ctrl;<keycap>L</keycap></keycombo></shortcut>
+ <guimenu>Settings</guimenu>
+ <guimenuitem>Show/Hide Navigation Panel</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para><action>Toggle the navigation panel</action> on and off.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <shortcut><keycombo action="simul">&Ctrl;&Shift;<keycap>F</keycap></keycombo></shortcut>
+ <guimenu>Settings</guimenu>
+ <guimenuitem>Full Screen Mode</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para><action>Enables the full screen mode</action>. Note that
+ full screen mode is different from <link
+ linkend="presentationMode">presentation mode</link> insofar as the
+ only peculiarity of full screen mode is that it hides the window
+ decorations, the menubar and the toolbar.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Settings</guimenu>
+ <guimenuitem>Configure Shortcuts...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>Opens a window that lets you <action>configure the keyboard
+ shortcuts</action> for many menu commands.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Settings</guimenu>
+ <guimenuitem>Configure Toolbars...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>Opens a window that lets you choose which icons are visible
+ in the toolbar.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>
+ <menuchoice>
+ <guimenu>Settings</guimenu>
+ <guimenuitem>Configure &kpdf;...</guimenuitem>
+ </menuchoice>
+ </term>
+ <listitem>
+ <para>Opens the <link linkend="configure">Configure</link>
+ window.</para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </sect1>
+ <sect1 id="menuhelp">
+ <title>The <guimenu>Help</guimenu> Menu</title>
+ &help.menu.documentation;
+ </sect1>
+
+ </chapter>
+ <chapter id="configure">
+ <title>Configuring &kpdf;</title>
+ <sect1 id="configindex">
+ <title>Overview</title>
+ <para>
+ You can configure &kpdf; by choosing <menuchoice><guimenu>Settings</guimenu>
+ <guimenuitem>Configure &kpdf;...</guimenuitem></menuchoice>.
+ The configuration dialogue is split into four sections. This chapter describes the available
+ options in detail.
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para><link linkend="configgeneral">General</link></para>
+ </listitem>
+ <listitem>
+ <para><link linkend="configaccessibility">Accessibility</link></para>
+ </listitem>
+ <listitem>
+ <para><link linkend="configperformance">Performance</link></para>
+ </listitem>
+ <listitem>
+ <para><link linkend="configpresentation">Presentation</link></para>
+ </listitem>
+ </itemizedlist>
+ <screenshot>
+ <screeninfo>The configuration dialogue</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="configure.png" format="PNG" />
+ </imageobject>
+ <textobject>
+ <phrase>The configuration dialogue</phrase>
+ </textobject>
+ </mediaobject>
+ </screenshot>
+ </sect1>
+ <sect1 id="configgeneral">
+ <title>General</title>
+ <variablelist>
+ <varlistentry>
+ <term>Show search bar in thumbnails list</term>
+ <listitem>
+ <para>Whether to the show a search bar in the thumbnails view or not. That
+ search bar is useful for filtering pages that contain a given
+ string.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Link thumbnails list with the page</term>
+ <listitem>
+ <para>Whether the thumbnails view should always display the current
+ page or not.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Show scrollbars</term>
+ <listitem>
+ <para>Whether to show scrollbars for the document view.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Show hints and info messages</term>
+ <listitem>
+ <para>Whether to show some informative messages on startup, file
+ load, etc.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Obey DRM limitations</term>
+ <listitem>
+ <para>Whether &kpdf; should obey <firstterm>DRM</firstterm> (Digital Rights Management) restrictions. DRM limitations are used to make it impossible to perform certain actions with PDF documents, such as copying content to the clipboard. Note that in some configurations of &kpdf;, this option is not available.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Watch file</term>
+ <listitem>
+ <para>Whether opened files should be automatically checked for
+ changes and updated, if necessary.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect1>
+ <sect1 id="configaccessibility">
+ <title>Accessibility</title>
+ <variablelist>
+ <varlistentry>
+ <term>Draw border around images</term>
+ <listitem>
+ <para>Whether to draw a border around images.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Draw border around links</term>
+ <listitem>
+ <para>Whether to draw a border around links.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Change colors</term>
+ <listitem>
+ <para><action>Enables</action> the color changing options.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Invert colors</term>
+ <listitem>
+ <para><action>Inverts</action> colors on the view, &ie; black objects will be shown white.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Change paper color</term>
+ <listitem>
+ <para><action>Changes</action> the paper's color, &ie; the document's background.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Change dark and light colors</term>
+ <listitem>
+ <para><action>Changes</action> the dark and light color to your preference, that means
+ black will not be rendered as black but as the selected dark color and white
+ will not be rendered as white but as the selected light color.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Convert to black and white</term>
+ <listitem>
+ <para><action>Converts</action> the document to black and white. You can set the
+ threshold and the contrast. Setting the threshold to a higher value
+ will result in darker grays used.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect1>
+ <sect1 id="configperformance">
+ <title>Performance</title>
+ <variablelist>
+ <varlistentry>
+ <term>Enable transparency effects</term>
+ <listitem>
+ <para>Draw selections and other special graphics using
+ transparency effects. Disable the option to draw them using
+ outline or opaque fill styles and increase speed on selections.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Enable background generation</term>
+ <listitem>
+ <para>Use a background thread to generate the pages. By disabling
+ this option the user interface will become less reactive (will be blocked
+ if necessary), but pages will be displayed a bit faster.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Memory usage profiles</term>
+ <listitem>
+ <para>&kpdf; can achieve best performance by tuning the memory usage, based on your system and your tastes.
+ The more memory you let it to use, the faster the program will behave. The Default profile is good
+ for every system, but you can prevent &kpdf; from using more memory than necessary by selecting the Low
+ profile, or let it get the most out of your system using Aggressive.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect1>
+ <sect1 id="configpresentation">
+ <title>Presentation</title>
+ <variablelist>
+ <varlistentry>
+ <term>Advance every</term>
+ <listitem>
+ <para>Enables automatic advancing of pages given a time period.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Loop after last page</term>
+ <listitem>
+ <para>When navigating on presentation mode and going past the last page the first page will appear.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Background color</term>
+ <listitem>
+ <para>The color that will fill the part of the screen not covered by the page when on presentation mode.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Default transition</term>
+ <listitem>
+ <para>The transition effect between page and page if the document does not specify one. Set this to <guilabel>Random
+ Transition</guilabel> to make &kpdf; randomly choose one of the available effects.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Mouse cursor</term>
+ <listitem>
+ <para>Whether the mouse should be always hidden, always shown or hidden after a small time of inactivity.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Show progress indicator</term>
+ <listitem>
+ <para>Whether to show a progress circle that shows the current page and the total number of pages on the upper
+ right corner of the presentation screen everytime you change the page.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Show summary page</term>
+ <listitem>
+ <para>Whether to show a summary page at the beginning of the presentation with the title, author and number of pages of the document.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect1>
+ </chapter>
+ <chapter id="credits">
+ <title>Credits and License</title>
+
+ <itemizedlist>
+ <title>Program Copyright:</title>
+ <listitem><para>Albert Astals Cid<email>tsdgeos@yahoo.es</email> Current maintainer</para></listitem>
+ <listitem><para>Christophe Devriese<email>oelewapperke@ulyssis.org</email></para></listitem>
+ <listitem><para>&Wilco.Greven; &Wilco.Greven.mail; Original author</para></listitem>
+ <listitem><para>Enrico Ros<email>eros.kde@email.it</email> Refactoring for 3.4</para></listitem>
+ <listitem><para>Laurent Montel<email>montel@kde.org</email></para></listitem>
+ </itemizedlist>
+
+ <itemizedlist>
+ <title>Documentation Copyright:</title>
+ <listitem><para>Albert Astals Cid<email>tsdgeos@yahoo.es</email> Author</para></listitem>
+ <listitem><para>Titus Laska<email>titus.laska@gmx.de</email> Some updates and additions</para></listitem>
+ </itemizedlist>
+ <!-- TRANS:CREDIT_FOR_TRANSLATORS -->
+ &underFDL;
+ &underGPL;
+ </chapter>
+
+ <appendix id="installation">
+ <title>Installation</title>
+ <sect1 id="getting-kapp">
+ <title>How to obtain &kpdf;</title>
+ &install.intro.documentation;
+ </sect1>
+ <sect1 id="compilation">
+ <title>Compilation and Installation</title>
+ <note>
+ <para>
+ If you are reading this help in the &khelpcenter;, &kpdf; has already been
+ installed on this system and you do not need install it anymore.
+ </para>
+ </note>
+ &install.compile.documentation;
+ </sect1>
+ </appendix>
+ &documentation.index;
+</book>
+
+
+<!--
+Local Variables:
+mode: sgml
+sgml-minimize-attributes:nil
+sgml-general-insert-case:lower
+sgml-indent-step:0
+sgml-indent-data:nil
+End:
+
+// vim:ts=2:sw=2:tw=78:noet
+-->
diff --git a/doc/kpovmodeler/Makefile.am b/doc/kpovmodeler/Makefile.am
new file mode 100644
index 00000000..085981d9
--- /dev/null
+++ b/doc/kpovmodeler/Makefile.am
@@ -0,0 +1,4 @@
+
+KDE_LANG = en
+KDE_DOCS = AUTO
+
diff --git a/doc/kpovmodeler/cameraview.png b/doc/kpovmodeler/cameraview.png
new file mode 100644
index 00000000..0003ea84
--- /dev/null
+++ b/doc/kpovmodeler/cameraview.png
Binary files differ
diff --git a/doc/kpovmodeler/controlpoints.png b/doc/kpovmodeler/controlpoints.png
new file mode 100644
index 00000000..88cd490d
--- /dev/null
+++ b/doc/kpovmodeler/controlpoints.png
Binary files differ
diff --git a/doc/kpovmodeler/cr22-action-pmcamera.png b/doc/kpovmodeler/cr22-action-pmcamera.png
new file mode 100644
index 00000000..51e3079a
--- /dev/null
+++ b/doc/kpovmodeler/cr22-action-pmcamera.png
Binary files differ
diff --git a/doc/kpovmodeler/cr22-action-pmcolorlist.png b/doc/kpovmodeler/cr22-action-pmcolorlist.png
new file mode 100644
index 00000000..b94946d3
--- /dev/null
+++ b/doc/kpovmodeler/cr22-action-pmcolorlist.png
Binary files differ
diff --git a/doc/kpovmodeler/cr22-action-pmfinish.png b/doc/kpovmodeler/cr22-action-pmfinish.png
new file mode 100644
index 00000000..070f16d1
--- /dev/null
+++ b/doc/kpovmodeler/cr22-action-pmfinish.png
Binary files differ
diff --git a/doc/kpovmodeler/cr22-action-pminterior.png b/doc/kpovmodeler/cr22-action-pminterior.png
new file mode 100644
index 00000000..d3c3a66f
--- /dev/null
+++ b/doc/kpovmodeler/cr22-action-pminterior.png
Binary files differ
diff --git a/doc/kpovmodeler/cr22-action-pmlight.png b/doc/kpovmodeler/cr22-action-pmlight.png
new file mode 100644
index 00000000..ebb36242
--- /dev/null
+++ b/doc/kpovmodeler/cr22-action-pmlight.png
Binary files differ
diff --git a/doc/kpovmodeler/cr22-action-pmpigment.png b/doc/kpovmodeler/cr22-action-pmpigment.png
new file mode 100644
index 00000000..6a2103d0
--- /dev/null
+++ b/doc/kpovmodeler/cr22-action-pmpigment.png
Binary files differ
diff --git a/doc/kpovmodeler/cr22-action-pmplane.png b/doc/kpovmodeler/cr22-action-pmplane.png
new file mode 100644
index 00000000..f5430a72
--- /dev/null
+++ b/doc/kpovmodeler/cr22-action-pmplane.png
Binary files differ
diff --git a/doc/kpovmodeler/cr22-action-pmrender.png b/doc/kpovmodeler/cr22-action-pmrender.png
new file mode 100644
index 00000000..6aa2b69f
--- /dev/null
+++ b/doc/kpovmodeler/cr22-action-pmrender.png
Binary files differ
diff --git a/doc/kpovmodeler/cr22-action-pmsolidcolor.png b/doc/kpovmodeler/cr22-action-pmsolidcolor.png
new file mode 100644
index 00000000..e8cbfc51
--- /dev/null
+++ b/doc/kpovmodeler/cr22-action-pmsolidcolor.png
Binary files differ
diff --git a/doc/kpovmodeler/cr22-action-pmsphere.png b/doc/kpovmodeler/cr22-action-pmsphere.png
new file mode 100644
index 00000000..bb9b6f2d
--- /dev/null
+++ b/doc/kpovmodeler/cr22-action-pmsphere.png
Binary files differ
diff --git a/doc/kpovmodeler/defaultviewlayout.png b/doc/kpovmodeler/defaultviewlayout.png
new file mode 100644
index 00000000..cb7f3af5
--- /dev/null
+++ b/doc/kpovmodeler/defaultviewlayout.png
Binary files differ
diff --git a/doc/kpovmodeler/dockwidget.png b/doc/kpovmodeler/dockwidget.png
new file mode 100644
index 00000000..aac95037
--- /dev/null
+++ b/doc/kpovmodeler/dockwidget.png
Binary files differ
diff --git a/doc/kpovmodeler/dockwidgettab.png b/doc/kpovmodeler/dockwidgettab.png
new file mode 100644
index 00000000..f0e76f91
--- /dev/null
+++ b/doc/kpovmodeler/dockwidgettab.png
Binary files differ
diff --git a/doc/kpovmodeler/index.docbook b/doc/kpovmodeler/index.docbook
new file mode 100644
index 00000000..f6551595
--- /dev/null
+++ b/doc/kpovmodeler/index.docbook
@@ -0,0 +1,2100 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+ <!ENTITY kappname "&kpovmodeler;">
+ <!ENTITY package "kdegraphics">
+ <!ENTITY Povray "<application>POV-Ray</application>">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE">
+]>
+
+<book lang="&language;">
+
+<bookinfo>
+<title>The &kpovmodeler; Handbook</title>
+
+<authorgroup>
+<author>
+<firstname>Lauri</firstname>
+<surname>Watts</surname>
+<affiliation>
+<address><email>lauri@kde.org</email></address>
+</affiliation>
+</author>
+
+<author>
+<firstname>Andreas</firstname>
+<surname>Zehender</surname>
+<affiliation>
+<address><email>zehender@kde.org</email></address>
+</affiliation>
+</author>
+
+<author>
+<firstname>Olivier</firstname>
+<surname>Saraja</surname>
+<affiliation>
+<address><email>olivier@linuxgraphic.org</email></address>
+</affiliation>
+</author>
+
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+</authorgroup>
+
+<legalnotice>&FDLNotice;</legalnotice>
+
+<date>2002-09-07</date>
+<releaseinfo>1.00.00</releaseinfo>
+
+<abstract>
+<para>
+&kpovmodeler; is a graphical 3D modeler, which can generate scenes for
+&Povray;
+</para>
+</abstract>
+
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>KPovModeler</keyword>
+</keywordset>
+
+</bookinfo>
+
+<chapter id="introduction">
+<title>Introduction</title>
+
+<para>&kpovmodeler; is a 3D modeling application to generate &Povray;
+scenes.</para>
+
+<para>While it is not necessary to fully understand the &Povray;
+application in order to make good use of &kpovmodeler;, it is highly
+recommended that you read and try to understand the &Povray;
+documentation.</para>
+
+<para>To find out more about &Povray; go to
+<ulink url="http://www.povray.org">www.povray.org</ulink>.</para>
+
+</chapter>
+
+<chapter id="the-interface">
+<title>The &kpovmodeler; Interface</title>
+
+<para>When you start &kpovmodeler;, the default layout is as
+follows:</para>
+
+<screenshot>
+<screeninfo>The default view layout</screeninfo>
+<mediaobject>
+<imageobject><imagedata fileref="defaultviewlayout.png" format="PNG"/></imageobject>
+<textobject><phrase>The default view layout</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<itemizedlist>
+<listitem>
+<para><link linkend="menu-reference">Menubars (1)</link></para>
+</listitem>
+<listitem>
+<para>Toolbars (2)</para>
+</listitem>
+<listitem>
+<para><link linkend="the-object-tree">The object tree (3)</link></para>
+</listitem>
+<listitem>
+<para><link linkend="the-properties-view">The object properties
+view (4)</link></para>
+</listitem>
+<listitem>
+<para><link linkend="the-wireframe-views">The wireframe and camera views (5)</link></para>
+</listitem>
+</itemizedlist>
+
+<sect1 id="the-object-tree">
+<title>The Object Tree</title>
+
+<para>The object tree displays the objects inside the scene and their hierarchy.</para>
+<screenshot>
+<mediaobject>
+<imageobject><imagedata fileref="objecttree.png" format="PNG"/></imageobject>
+<textobject><phrase>The object tree</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<sect2 id="object-tree-selecting-object">
+<title>Selecting Objects</title>
+<para>In the object tree you can select objects. Once you select an object, its attributes
+are displayed in the
+<link linkend="the-properties-view">properties view</link> and rendered yellow in the
+<link linkend="the-wireframe-views">wireframe views</link>.</para>
+
+<para>You can select multiple objects. However, you cannot select a child of an already
+selected object, because all children are selected indirectly with the parent.</para>
+
+<para>If only one object is selected, it is referred to as <quote>the active object</quote> from now on.</para>
+</sect2>
+
+<sect2 id="object-tree-add-objects">
+<title>Adding new Objects</title>
+
+<para>To add a new object to the object tree, select the object where you want to
+insert the new object and either click the icon in the toolbar or choose a menu entry
+in the <guimenu>Insert</guimenu> menu.</para>
+
+<para>There are three possible positions for new objects:</para>
+<itemizedlist>
+<listitem><para>As the first child of the active object</para></listitem>
+<listitem><para>As the last child of the active object</para></listitem>
+<listitem><para>As a sibling of the active object</para></listitem>
+</itemizedlist>
+
+<para>If there is more than one position possible, the following popup menu prompts
+you to select the correct position:</para>
+
+<screenshot>
+<mediaobject>
+<imageobject><imagedata fileref="insertaspopup.png" format="PNG"/></imageobject>
+<textobject><phrase>The insert position popup</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+</sect2>
+
+<sect2 id="object-tree-remove-objects">
+<title>Removing Objects</title>
+<para>To remove objects, select them and select <guimenuitem>Delete</guimenuitem> from
+either the <guimenu>Edit</guimenu> menu or the &RMB; context menu.</para>
+</sect2>
+
+<sect2 id="object-tree-move-objects">
+<title>Moving Objects</title>
+<para>To move objects, drag and drop the selected objects on to the object tree.</para>
+<para>You can cut the object and insert it at the new position as well.</para>
+</sect2>
+
+</sect1>
+
+<sect1 id="the-properties-view">
+<title>The Properties View</title>
+
+<para>The properties view displays the attributes of the active object.</para>
+<screenshot>
+<mediaobject>
+<imageobject><imagedata fileref="objectpropertiesview.png" format="PNG"/></imageobject>
+<textobject><phrase>The properties view</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>If you changed some properties, click the <guibutton>Apply</guibutton> button to
+make the changes permanent. If you entered invalid data, a message box will show up with
+an error description. You can then adjust the properties and press
+<guibutton>Apply</guibutton> again, or revert your changes with the
+<guibutton>Cancel</guibutton> button.</para>
+<para>If you set the path to your &Povray; user documentation in the
+<link linkend="configure-povray-tab">settings dialog</link>, you can open the
+&Povray; reference page for the displayed object with the <guibutton>Help</guibutton>
+button.
+</para>
+
+<note><para>You need the &Povray; 3.1g or 3.5 HTML user documentation in order to use this feature.
+If your distribution does not contain this documentation you can download it
+<ulink url="ftp://ftp.povray.org/pub/povray/Old-Versions/Official-3.1g/Docs/povhtml.zip">here</ulink>.
+The &Povray; 3.5 package contains the html user documentation.</para>
+</note>
+
+<para>If you edit a texture or a part of a texture, you can preview it inside the properties view.</para>
+
+<screenshot>
+<mediaobject>
+<imageobject><imagedata fileref="texturepreview.png" format="PNG"/></imageobject>
+<textobject><phrase>The properties view, texture preview</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>Press the <guibutton>Preview</guibutton> button inside the properties view and a
+small sample scene with the selected texture will be rendered. By default the whole texture
+will be rendered, even if not the top item is selected. If you want to render only a part of
+the texture (for example a texture inside a texture map and not the whole texture map), check the
+<guilabel>local</guilabel> check box.</para>
+
+</sect1>
+
+<sect1 id="the-wireframe-views">
+<title>The Wireframe Views</title>
+
+<sect2 id="orthographic-views">
+<title>The Orthographic Views</title>
+
+<para>The orthographic wireframe views show the scene as an orthographic
+projection on one of the coordinate planes.</para>
+
+<screenshot>
+<mediaobject>
+<imageobject><imagedata fileref="topview.png" format="PNG"/></imageobject>
+<textobject><phrase>The top wireframe view</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>There are six types of orthographic wireframes views:</para>
+<itemizedlist>
+<listitem><para>Top</para></listitem>
+<listitem><para>Bottom</para></listitem>
+<listitem><para>Left</para></listitem>
+<listitem><para>Right</para></listitem>
+<listitem><para>Front</para></listitem>
+<listitem><para>Back</para></listitem>
+</itemizedlist>
+
+<para>Each type renders the scene from a different perspective.</para>
+
+<sect3 id="graphical-change">
+<title>Graphical Attribute Changes</title>
+<para>In the orthographic views you can change object attribute
+properties graphically with the mouse.</para>
+
+<screenshot>
+<mediaobject>
+<imageobject><imagedata fileref="controlpoints.png" format="PNG"/></imageobject>
+<textobject><phrase>The control points of the camera object</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>The above screenshot shows the control points of the camera.
+You can drag the control points around to change the camera's position and direction.</para>
+
+<para>If a transformation is selected, the control points are removed and a small cross is
+displayed in the wireframe view. The cross marks the center for scaling and rotation,
+as well as the position for translations. You can change the transformation with the mouse
+by dragging inside the whole view.</para>
+
+<para>Some objects like the bicubic patch support selection and modification of multiple
+control points.</para>
+
+<informaltable>
+<tgroup cols="2"><tbody>
+<row>
+ <entry>&LMB;</entry>
+ <entry>Selects one control point and deselects all others</entry>
+</row>
+<row>
+ <entry><keycombo
+ action="click">&Ctrl;<mousebutton>Left</mousebutton></keycombo>
+ Mouse Button</entry>
+ <entry>Selects or deselects one control point</entry>
+</row>
+<row>
+ <entry><keycombo
+ action="click">&Shift;<mousebutton>Left</mousebutton></keycombo>
+ Mouse Button</entry>
+ <entry>Drag a rectangle. All control points inside the rectangle are
+ selected, the others deselected</entry>
+</row>
+<row>
+ <entry><keycombo
+ action="click">&Shift;&Ctrl;<keycap>Left</keycap></keycombo> Mouse Button</entry>
+ <entry>Drag a rectangle. All control points inside the rectangle are selected</entry>
+</row>
+</tbody></tgroup>
+</informaltable>
+
+</sect3>
+
+<sect3 id="display-window-selection">
+<title>Display Window Selection</title>
+<para>You can zoom and translate the view to change the display window.</para>
+<informaltable>
+<tgroup cols="2"><tbody>
+<row>
+ <entry>&MMB;</entry>
+ <entry>Translates the view</entry>
+</row>
+<row>
+ <entry><mousebutton>wheel</mousebutton></entry>
+ <entry>Zooms the view around the mouse position</entry>
+</row>
+<row>
+ <entry><keycap>Left</keycap>, <keycap>Right</keycap>, <keycap>Up</keycap>, <keycap>Down</keycap> </entry>
+ <entry>Translates the view</entry>
+</row>
+<row>
+ <entry><keycombo action="simul"><keycap>Ctrl</keycap><keycap>Left</keycap></keycombo>,
+ <keycombo action="simul"><keycap>Ctrl</keycap><keycap>Right</keycap></keycombo></entry>
+ <entry>Zooms the view</entry>
+</row>
+</tbody></tgroup>
+</informaltable>
+
+</sect3>
+
+</sect2>
+
+<sect2 id="camera-view">
+<title>The Camera View</title>
+
+<para>The camera view displays the scene from the camera's point of view.</para>
+
+<screenshot>
+<mediaobject>
+<imageobject><imagedata fileref="cameraview.png" format="PNG"/></imageobject>
+<textobject><phrase>The camera view</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>The blue box displays the field of view when the scene is rendered.</para>
+
+<para>You cannot change control points in the camera view.</para>
+
+</sect2>
+
+<sect2 id="visibility-levels">
+<title>Visibility Levels</title>
+
+<para>By default all objects are displayed in the wireframe views.</para>
+<para>Each object with a wire frame has a visibility level.
+You can specify a visibility level relative to the parent's visibility level
+or an absolute value. Objects are only displayed if they are selected or their visibility
+level is smaller or equal the chosen scene visibility level in the
+toolbar.</para>
+
+</sect2>
+
+</sect1>
+
+
+<sect1 id="view-layouts">
+<title>View Layouts</title>
+
+<para>&kpovmodeler; comes with a default view layout: The object tree and
+the object properties view to the left and four graphical views to the right.</para>
+
+<para>If you don't like the default layout, or need another layout, you can freely
+configure it. You can even save multiple view layouts and switch between them
+on the fly.</para>
+
+<sect2 id="change-the-view-layout">
+<title>Modifying the View Layout</title>
+
+<para>You can move the existing views by dragging the handle on top of the
+views around.</para>
+
+<screenshot>
+<mediaobject>
+<imageobject><imagedata fileref="dockwidget.png" format="PNG"/></imageobject>
+<textobject><phrase>The dock widget handle</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>To dock a widget above or below an existing view, drag the handle to
+the top or bottom of a view. A rectangle will indicate the new position.</para>
+<para>To create a new column, drag the handle to the right or left side
+of another view. The view will then dock to the left or right side of the
+view and span the full height.</para>
+<para>If you want multiple views sharing the same space, drag the handle to
+the center of another view. You can then switch between the views by
+clicking the corresponding tab on top of the views.</para>
+
+<screenshot>
+<mediaobject>
+<imageobject><imagedata fileref="dockwidgettab.png" format="PNG"/></imageobject>
+<textobject><phrase>The tabbed view layout</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>The last layout possibility are floating views: views that
+are not docked into the main view. To undock a view, drag the handle to the
+desktop or press the little arrow in the view handle that points to the
+top left side.</para>
+
+<para>To close a view, click the little cross in the handle. To prevent closing,
+click the little box between the arrow and the cross.</para>
+
+<para>You can add additional views to the main window. The <guimenu>View</guimenu>
+menu contains entries for each type of view. New views will be created floating,
+which you can dock wherever you like.</para>
+
+</sect2>
+
+<sect2 id="save-a-view-layout">
+<title>Saving a View Layout</title>
+
+<para>You can save the current view layout with
+<menuchoice>
+<guimenu>View</guimenu>
+<guimenuitem>Save View Layout...</guimenuitem>
+</menuchoice> A dialog opens that lets you select an existing layout
+or create a new one.</para>
+
+<para>You can then fine-tune your view layout in the
+<link linkend="configure-view-layout-tab">settings dialog</link>.
+
+</para>
+</sect2>
+
+<sect2 id="switching-between-view-layout">
+<title>Switching between View Layouts</title>
+<para>You can switch to a saved view layout by selecting the entry in the
+<menuchoice><guimenu>View</guimenu><guimenuitem>View Layout</guimenuitem></menuchoice>
+menu.</para>
+
+</sect2>
+
+</sect1>
+
+</chapter>
+
+
+<chapter id="povray-interaction">
+<title>&Povray; Interaction</title>
+
+<sect1 id="rendering-the-scene">
+<title>Rendering the Scene</title>
+
+<para>Once you have created a scene, you will want to render it. &kpovmodeler;
+uses &Povray; 3.1g to render the scene, so you need a correct installation of &Povray;.
+At the time of writing &Povray; 3.5 was released. This version is not supported in
+the &kpovmodeler; 1.0 version.</para>
+<para>Go to <ulink url="http://www.povray.org">www.povray.org</ulink>
+to get a version of &Povray; and for installation instructions.</para>
+
+<para>To render the current scene, press the render icon
+<inlinemediaobject>
+<imageobject><imagedata fileref="rendericon.png" format="PNG"/></imageobject>
+<textobject><phrase>The render icon</phrase></textobject>
+</inlinemediaobject>
+in the toolbar, or select the
+<menuchoice><guimenu>View</guimenu><guimenuitem>Render</guimenuitem></menuchoice>
+menu entry.</para>
+
+<sect2 id="render-modes">
+<title>Render Modes</title>
+
+<para>A render mode is similar to &Povray;s ini file entries. It specifies the image size
+and quality levels for rendering. If you would like to render your scene with different
+qualities and sizes, you can add as many render modes as you need, from quick previews
+to fullscreen high quality images.</para>
+
+<sect3 id="render-modes-configuration">
+<title>Render Modes Configuration</title>
+
+<para>When you press the render settings icon
+<inlinemediaobject>
+<imageobject><imagedata fileref="rendersettingsicon.png" format="PNG"/></imageobject>
+<textobject><phrase>The render settings</phrase></textobject>
+</inlinemediaobject>
+in the toolbar or select the
+<menuchoice><guimenu>View</guimenu><guimenuitem>Render Modes...</guimenuitem></menuchoice>
+menu icon, the following dialog opens:</para>
+
+<screenshot>
+<mediaobject>
+<imageobject><imagedata fileref="rendermodesselection.png" format="PNG"/></imageobject>
+<textobject><phrase>The render modes selection dialog</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>This dialog shows the list of all available render modes.</para>
+
+<variablelist>
+
+<varlistentry><term><guibutton>Add</guibutton></term>
+<listitem><para><action>Adds a default render mode to the list</action>.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry><term><guibutton>Remove</guibutton></term>
+<listitem><para><action>Removes the selected render mode</action>.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry><term><guibutton>Edit</guibutton></term>
+<listitem><para><action>Opens a dialog to edit the selected render mode</action>.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry><term><guibutton>Up</guibutton></term>
+<listitem><para><action>Moves the selected render mode one position up</action>.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry><term><guibutton>Down</guibutton></term>
+<listitem><para><action>Moves the selected render mode one position down</action>.</para>
+</listitem>
+</varlistentry>
+
+</variablelist>
+
+<para>The <guibutton>Edit</guibutton> Button opens the following
+configuration dialog:</para>
+
+<screenshot>
+<mediaobject>
+<imageobject><imagedata fileref="rendermodesize.png" format="PNG"/></imageobject>
+<textobject><phrase>The render modes size tab</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>Each render mode has a description. You can enter any description, but it should reflect
+the render mode's properties.</para>
+
+<para>In the <guilabel>Size</guilabel> tab you can enter the width and height of the rendered image. If
+you want to render only a small part of the image, check the
+<guilabel>Subselection</guilabel> check box and enter the part of the image
+in the fields below.</para>
+
+<screenshot>
+<mediaobject>
+<imageobject><imagedata fileref="rendermodequality.png" format="PNG"/></imageobject>
+<textobject><phrase>The render modes quality tab</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>In the <guilabel>Quality</guilabel> tab you can select various quality levels
+for the rendered image.</para>
+
+<para>In the <guilabel>Quality</guilabel> combo box you can select the features
+&Povray; uses while rendering. The possibilities range from a very simple coloring
+and lighting model, to one which has complex diffuse inter-reflection lighting.
+See the &Povray; user documentation
+for a detailed description of the rendering features.</para>
+
+<para>If an image is rendered with only one sample per pixel, various errors can occur.
+These images often have moir&eacute; or stepped effects in curves and lines, and
+details can get lost if they are smaller in appearance then one pixel.
+This effect is called <quote>aliasing</quote>.</para>
+
+<para>&Povray; uses a technique called <quote>anti-aliasing</quote> to reduce the impact
+of these errors. In general images will look smoother with this feature.</para>
+
+<para>If you enable anti-aliasing, &Povray; will calculate and combine more then one
+sample per pixel. This is called <quote>super-sampling</quote>.</para>
+
+<para>&Povray; supports two methods of super-sampling. The default
+is an adaptive non-recursive method; <quote>adaptive</quote>
+because the super-sampling
+depends on the local neighborhood of the pixel. Not every
+pixel is super-sampled with this method. The second method is an adaptive
+recursive one; <quote>recursive</quote> because every pixel is divided and sub-divided
+recursively, and <quote>adaptive</quote> because the recursion depth depends on the
+computed color values.</para>
+
+<para>When you select the first method, povray traces one ray per pixel. If the
+difference between its color value and that of its neighbor exceeds the given threshold,
+both pixels are super-sampled by tracing a fixed number of additional rays. If you set
+the depth value to 4, a 4x4 grid of additional points will be calculated, a depth
+value of 5 will result in 5x5 (25) samples per pixel.</para>
+
+<para>The difference between two pixels is computed as follows: r<subscript>1</subscript>,
+g<subscript>1</subscript> and b<subscript>1</subscript> are the
+red, green and blue values of the first pixel; r<subscript>2</subscript>,
+g<subscript>2</subscript> and b<subscript>2</subscript> are the red,
+green and blue values of the second pixel. The difference is then:
+</para>
+<para>diff = abs(r<subscript>1</subscript>-r<subscript>2</subscript>)
++ abs(g<subscript>1</subscript>-g<subscript>2</subscript>)
++ abs(b<subscript>1</subscript>-b<subscript>2</subscript>)</para>
+
+<para>The recursive method starts with 4 samples per pixel. If the resulting color values
+differ more than the given threshold, the pixel is sub-divided into 4 sub pixels that are
+separately traced and tested for further subdivision. You can specify the maximum
+recursive depth with the depth value.</para>
+
+<para>An additional method to reduce aliasing effects is to add noise to the
+sampling process, called <quote>jittering</quote>. If you enable
+jittering, &Povray; jitters the samples a tiny amount to reduce
+regular patterns.</para>
+
+<para>The last quality setting is radiosity. Radiosity is an experimental
+&Povray; feature that computes inter-diffuse light reflection. Be patient
+when rendering a scene with this feature.</para>
+
+<screenshot>
+<mediaobject>
+<imageobject><imagedata fileref="rendermodeoutput.png" format="PNG"/></imageobject>
+<textobject><phrase>The render modes output tab</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>In the last tab, you can configure whether or not the
+alpha channel should be calculated by povray.
+A pixel will then be transparent
+if the corresponding ray did not hit a single object.</para>
+
+</sect3>
+
+<sect3 id="choosing-a-render-mode">
+<title>Choosing a render mode</title>
+
+<para>You can select the render mode in the combo box in the rendering toolbar.</para>
+
+<screenshot>
+<mediaobject>
+<imageobject><imagedata fileref="rendermodestoolbar.png" format="PNG"/></imageobject>
+<textobject><phrase>The render modes toolbar</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+</sect3>
+
+</sect2>
+
+<sect2 id="the-render-window">
+<title>The Render Window</title>
+
+<para>When you started to render a scene, this window will open:</para>
+
+<screenshot>
+<mediaobject>
+<imageobject><imagedata fileref="renderwindow.png" format="PNG"/></imageobject>
+<textobject><phrase>The render window</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<para>It shows the rendered image, the progress and the current rendering
+speed.</para>
+
+<variablelist>
+
+<varlistentry><term><guibutton>Stop</guibutton></term>
+<listitem><para><action>Terminates &Povray;</action>.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry><term><guibutton>Suspend</guibutton></term>
+<listitem><para><action>Suspends rendering</action>.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry><term><guibutton>Resume</guibutton></term>
+<listitem><para><action>Resumes rendering</action>.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry><term><guibutton>Povray Output...</guibutton></term>
+<listitem><para><action>Opens another window that displays the &Povray;
+console output</action>. If &Povray; exits abnormally, you can find the reason
+in that window.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry><term><guibutton>Save...</guibutton></term>
+<listitem><para><action>Lets you save the image when it is rendered.</action></para>
+</listitem>
+</varlistentry>
+
+<varlistentry><term><guibutton>Close</guibutton></term>
+<listitem><para><action>Closes the render window</action>.</para>
+</listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect2>
+
+</sect1>
+
+<sect1 id="exporting-and-importing-povray">
+<title>Exporting and Importing</title>
+
+<sect2 id="exporting-and-importing-a-whole-scene">
+<title>Exporting and Importing a Whole Scene</title>
+
+<para>You can export a scene to &Povray; with the
+<menuchoice><guimenu>File</guimenu><guimenuitem>Export Povray...</guimenuitem></menuchoice>
+menu entry.</para>
+<para>The file save dialog will allow you to choose a name and
+location to save the file.</para>
+<note><para>&kpovmodeler; will automatically add the
+<literal role="extension">.pov</literal> extension.</para></note>
+
+<para>To import a &Povray; scene select the
+<menuchoice><guimenu>File</guimenu><guimenuitem>Import Povray...</guimenuitem></menuchoice>
+menu item and choose a file in the file open dialog.</para>
+
+<note><para>Not the full &Povray; syntax is supported by &kpovmodeler; at the moment.
+If there are errors or warnings during importing, a dialog will show up that
+lists all messages.</para></note>
+
+<tip><para>If you want to import unsupported code to &kpovmodeler;, put
+the source between the two special comments <quote>//*PMRawBegin</quote>
+and <quote>//*PMRawEnd</quote>.</para></tip>
+
+</sect2>
+
+<sect2 id="exporting-and-importing-single-objects">
+<title>Exporting and Importing single Objects</title>
+
+<para>You can drag objects from the object tree to an editor
+to export &Povray; code. This will insert the objects code into the current
+text file in the editor. To import objects into the scene, simply select
+the code in your editor and drag it on to the object tree.</para>
+<para>You can use the copy and paste functionality of &kpovmodeler;
+and your editor to exchange &Povray; code as well.</para>
+
+</sect2>
+
+</sect1>
+
+</chapter>
+
+
+<chapter id="customizing">
+<title>Configuring &kpovmodeler;</title>
+
+<sect1 id="configure-povray-tab">
+<title>The <guilabel>Povray</guilabel> Tab</title>
+
+<sect2 id="configure-povray-command">
+<title><guilabel>Povray Command</guilabel></title>
+
+<para>The povray command is called when &kpovmodeler; renders a scene. Common commands
+are <quote>povray</quote> or <quote>x-povray</quote>.</para>
+
+</sect2>
+
+<sect2 id="configure-povray-documentation">
+<title><guilabel>Povray User Documentation</guilabel></title>
+
+<para>If you press the <guibutton>Help</guibutton> button in the properties view, &kpovmodeler;
+opens the &Povray; user documentation for the displayed object. Set here the path to your documentation
+and your documentation version. Supported versions are 3.1g and 3.5.</para>
+
+</sect2>
+
+<sect2 id="configure-povray-library-paths">
+<title><guilabel>Library Paths</guilabel></title>
+
+<para>&Povray; searches for external files (height field data as example) in the &Povray; library paths.
+If you refer to files not in the scene's folder, you have to add the folder to the list. If a file
+exists in multiple library paths, that one in the first path is used.</para>
+<para>You can change the order with the <guibutton>Up</guibutton> and
+<guibutton>Down</guibutton> buttons.</para>
+
+</sect2>
+
+</sect1>
+
+<sect1 id="configure-graphical-view-tab">
+<title>The <guilabel>Graphical view</guilabel> Tab</title>
+
+<sect2 id="configure-colors">
+<title><guilabel>Colors</guilabel></title>
+
+<para>The color tab lets you configure the used colors for the graphical views.</para>
+
+<variablelist>
+
+<varlistentry>
+<term><guilabel>Background:</guilabel></term>
+<listitem><para>The background color.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Wire frame:</guilabel></term>
+<listitem><para>The colors for wire frames. The second color is used if the object
+is selected.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Control points:</guilabel></term>
+<listitem><para>The color for control points. The second color is used if the control point
+is selected.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Axes:</guilabel></term>
+<listitem><para>The colors for the x-, y- and z-axis.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Field of view:</guilabel></term>
+<listitem><para>The color for the field of view rectangle in the camera view
+and the view type labels.</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect2>
+
+<sect2 id="configure-grid">
+<title>The Grid</title>
+
+<para>This page lets you configure the grid in the wire frame views.</para>
+
+<sect3 id="configure-displayed-grid">
+<title><guilabel>Displayed Grid</guilabel></title>
+
+<variablelist>
+
+<varlistentry>
+<term><guilabel>Color:</guilabel></term>
+<listitem><para>The grid color.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Distance:</guilabel></term>
+<listitem><para>The minimal distance of two grid lines.</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect3>
+
+<sect3 id="configure-control-point-grid">
+<title><guilabel>Control Point Grid</guilabel></title>
+
+<para>You can snap control points to the grid with the context menu in
+the wireframe views. You can configure the grid for translations, scales and rotations
+separately here.</para>
+
+</sect3>
+
+</sect2>
+
+<sect2 id="configure-detail-levels">
+<title><guilabel>Objects</guilabel></title>
+
+<sect3 id="configure-object-subdivisions">
+<title><guilabel>Subdivisions</guilabel></title>
+
+<para>You can configure the detail levels for various objects here.</para>
+
+<para>Higher values lead to a finer wireframe and therefore to a better approximation for
+the displayed objects, but slow down rendering. For some objects like the sphere you can
+configure the detail level for two directions separately.</para>
+
+</sect3>
+
+<sect3 id="configure-object-sizes">
+<title><guilabel>Sizes</guilabel></title>
+
+<para>Lets you configure the sizes in which infinite objects are displayed in
+the wireframe views.</para>
+
+</sect3>
+
+<sect3 id="configure-camera-views">
+<title><guilabel>Camera Views</guilabel></title>
+
+<para>If you check the <guilabel>High detail for enhanced projections</guilabel> check box,
+all wire frame lines are subdivided further if the camera uses an enhanced projection. Enhanced
+projections are all projections except the perspective and orthographic projections. This feature
+greatly improves the approximation of these projections but slows down rendering.</para>
+
+</sect3>
+
+</sect2>
+
+</sect1>
+
+<sect1 id="configure-dialog-view-tab">
+<title>The <guilabel>Properties view</guilabel> Tab</title>
+
+<sect2 id="configure-texture-preview">
+<title><guilabel>Texture Preview</guilabel></title>
+
+<para>This page lets you configure the texture preview in the properties view.</para>
+
+<variablelist>
+
+<varlistentry>
+<term><guilabel>Size:</guilabel></term>
+<listitem><para>The preview image size.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Gamma:</guilabel></term>
+<listitem><para>The gamma correction.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Rendered Objects</guilabel></term>
+<listitem><para>Defines the small sample scene. At least one
+object has to be selected.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Wall</guilabel></term>
+<listitem><para>If the <guilabel>Enable wall</guilabel> check box is checked, a
+wall will be rendered behind the objects. The wall is textured with a checker pattern with the
+two configurable colors.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Floor</guilabel></term>
+<listitem><para>If the <guilabel>Enable floor</guilabel> check box is checked, a
+floor will be rendered below the objects. The floor is textured with a checker pattern with the
+two configurable colors.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Anti-Aliasing</guilabel></term>
+<listitem><para>If the <guilabel>Enable antialiasing</guilabel> check box is checked,
+the non-recursive antialiasing method will be used for rendering the scene. You can configure the
+depth and threshold values. See <link linkend="render-modes-configuration">render modes section</link>
+for a detailed description of the parameters.</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect2>
+
+</sect1>
+
+<sect1 id="configure-view-layout-tab">
+<title>The <guilabel>View Layout</guilabel> Tab</title>
+
+<para>In this page you can fine-tune existing view layouts or manually
+create new ones. See section <link linkend="view-layouts">View Layouts</link>
+how to create and save view layouts.</para>
+
+<sect2 id="configure-default-layout">
+<title>The default View Layout</title>
+
+<para>The combo box <guilabel>Default view layout:</guilabel>
+lists all available view layouts. &kpovmodeler; uses the selected
+view layout at program start.</para>
+
+</sect2>
+
+<sect2 id="configure-list-of-view-layouts">
+<title>List of View Layouts</title>
+
+<para>The list <guilabel>Available View Layouts</guilabel>
+shows all available view layouts. You can add a new layout with the
+<guibutton>Add</guibutton> button and remove the selected layout
+with the <guibutton>Remove</guibutton> button.</para>
+<para>The selected view layout is displayed in the box
+<guilabel>View Layout</guilabel></para>
+</sect2>
+
+<sect2 id="configure-view-layout-details">
+<title>View Layout Details</title>
+
+<para>Each view layout is identified by its name. The name has to
+be unique and must not be empty.</para>
+
+<para>The list below the name displays all views for the selected
+view layout. You can add new views with the
+<guibutton>Add</guibutton> button and remove the selected view
+with the <guibutton>Remove</guibutton> button.</para>
+
+<para>The attributes of the views are:</para>
+
+<variablelist>
+<varlistentry>
+<term><guilabel>Type:</guilabel></term>
+<listitem>
+<para>The view type. See <link linkend="the-interface">The &kpovmodeler; Interface</link>
+for a description of each view type.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>3D view type:</guilabel></term>
+<listitem>
+<para>The projection for wire frame views. You can choose one of the six
+orthographic projections or the camera mode.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Dock position:</guilabel></term>
+<listitem>
+<para>The position of the view. <guilabel>New Column</guilabel> will
+create a new column to the right side of the previous views,
+<guilabel>Below</guilabel> will dock the view below the previous view,
+<guilabel>Tabbed</guilabel> will create a tabbed view together with the previous one
+and <guilabel>Floating</guilabel> will not dock the view into the main
+window but create a separate window.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Column width:</guilabel></term>
+<listitem>
+<para>The width of the column in percent of the main view width.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>View height:</guilabel></term>
+<listitem>
+<para>The view height in percent of the main view height.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Width:</guilabel> and <guilabel>Height:</guilabel></term>
+<listitem>
+<para>The size in pixels for floating views.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Position x:</guilabel> and <guilabel>y:</guilabel></term>
+<listitem>
+<para>The position on the desktop for floating views.</para>
+</listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect2>
+
+</sect1>
+
+</chapter>
+
+<chapter id="basic-tutorial">
+<title>Basic Tutorial: Creating your first Scene</title>
+
+<para>OK, that's it. You have just installed &Povray; and &kpovmodeler;,
+and now you already want to start without much knowledge of any of the two
+softwares. Here we go now: If you follow the steps of this tutorial,
+you'll be able to set the ultimate simple scene, very widespread among
+the newbies: A sphere over a plane.</para>
+
+<screenshot>
+<mediaobject>
+<imageobject><imagedata fileref="tutorial01-final-render.png" format="PNG"/>
+</imageobject>
+</mediaobject>
+</screenshot>
+
+<para>At any time you can render your scene using one of the following methods:</para>
+
+<para>Using the menu:
+<menuchoice><guimenu>Display</guimenu><guimenuitem>Render</guimenuitem></menuchoice></para>
+<para>Using the toolbar: Click on the
+<inlinemediaobject>
+<imageobject><imagedata fileref="cr22-action-pmrender.png" format="PNG"/></imageobject>
+</inlinemediaobject> icon</para>
+
+<para>But you should carefully consider the following warnings before complaining
+if all you get is a black screen. If this is the very first time you use a 3D software,
+you should be aware of these golden rules:</para>
+
+<itemizedlist>
+<listitem><para>If you set no camera, no rules apply to the render engine which can't
+render a proper picture, ending in a black picture.</para></listitem>
+<listitem><para>If you set no light system, all your scene is in the dark,
+ending in a black picture.</para></listitem>
+<listitem><para>The objects for which no material has been set won't show on the
+rendered picture, ever.</para></listitem>
+</itemizedlist>
+
+<sect1 id="basic-tutorial-step-1">
+<title>Step 1: Start &kpovmodeler;</title>
+
+<para>If you got everything installed fine, once &kpovmodeler;
+is loaded, you discover the following default windows setting:</para>
+
+<screenshot>
+<mediaobject>
+<imageobject><imagedata fileref="defaultviewlayout.png" format="PNG"/></imageobject>
+</mediaobject>
+</screenshot>
+
+<para>Take a few minutes to explore the menus and icons available.
+If you have time, please read the documentation in order to get a
+fair idea of what you can expect from this piece of software.</para>
+
+<itemizedlist>
+<listitem>
+<para><link linkend="menu-reference">Menubars (1)</link></para>
+</listitem>
+<listitem>
+<para>Toolbars (2)</para>
+</listitem>
+<listitem>
+<para><link linkend="the-object-tree">The object tree (3)</link></para>
+</listitem>
+<listitem>
+<para><link linkend="the-properties-view">The object properties
+view (4)</link></para>
+</listitem>
+<listitem>
+<para><link linkend="the-wireframe-views">The wireframe and camera views (5)</link></para>
+</listitem>
+</itemizedlist>
+
+<para>You will have to use each of them intensively from now on, so always keep them
+and their use in mind.</para>
+
+<para>&kpovmodeler; starts with a simple scene. In order to follow this tutorial
+you first have to remove all objects from the object tree. Select the scene
+and choose the <menuchoice><guimenu>Edit</guimenu><guimenuitem>Delete</guimenuitem></menuchoice> menu
+entry. You should now have an empty scene.</para>
+
+</sect1>
+
+<sect1 id="basic-tutorial-step-2">
+<title>Step 2: Setting the Camera</title>
+
+<para>First of all, we will set a camera. In order to do so, two convenient ways are available:</para>
+<para>Using the menu: <menuchoice><guimenu>Insert</guimenu><guimenuitem>Camera</guimenuitem></menuchoice></para>
+<para>Using the toolbar: Click on the
+<inlinemediaobject>
+<imageobject><imagedata fileref="cr22-action-pmcamera.png" format="PNG"/></imageobject>
+</inlinemediaobject> icon</para>
+
+<para>The wireframe view shows how the camera is set regarding the whole scene we are creating.
+In particular, we can now see something in the fourth wire frame view (right, bottom):
+This is the view of the scene from the camera point of view.
+This is what will be seen when you render the scene.</para>
+
+<screenshot>
+<mediaobject>
+<imageobject><imagedata fileref="tutorial01-camera-graphic.png" format="PNG"/></imageobject>
+</mediaobject>
+</screenshot>
+
+<para>The object tree now shows a new entry, reading <quote>camera</quote>. If you click on it,
+it affects the content of the object properties view, where various parameters
+pertaining to the camera can be found.
+Referring to the &Povray;'s documentation to learn more about these could be helpful.</para>
+
+<screenshot>
+<mediaobject>
+<imageobject><imagedata fileref="tutorial01-camera-dialog.png" format="PNG"/></imageobject>
+</mediaobject>
+</screenshot>
+
+<para>We will change nothing to the basic settings of the camera,
+this will be the scope of later tutorials, but please note that in the graphic view,
+the camera has control points that let you control the point to which the camera points.
+You just have to left-click on one handle and move it to an appropriate location.</para>
+
+</sect1>
+
+<sect1 id="basic-tutorial-step-3">
+<title>Step 3: Setting a Light</title>
+
+<para>The same way we have set a camera, we will now set a light system:</para>
+<para>Using the menu:
+<menuchoice><guimenu>Insert</guimenu><guimenuitem>Light</guimenuitem></menuchoice></para>
+<para>Using the toolbar: Click on the
+<inlinemediaobject>
+<imageobject><imagedata fileref="cr22-action-pmlight.png" format="PNG"/></imageobject>
+</inlinemediaobject> icon</para>
+
+<para>A new entry features now in the object tree. If you click on the light entry,
+you see that the properties view changes in order to show the parameters available
+to the lighting system. We will change some parameters in order to set the
+light higher above the horizon (<guilabel>y</guilabel>=3), slightly on the right
+(<guilabel>x</guilabel>=1) and in the foreground (<guilabel>z</guilabel>=1).
+We can also rename the light system (<guilabel>Name</guilabel>=<quote>Main Light</quote>).
+Change the values in the object properties view as follows:</para>
+
+<screenshot>
+<mediaobject><imageobject><imagedata fileref="tutorial01-light-dialog.png" format="PNG"/></imageobject>
+</mediaobject>
+</screenshot>
+
+<para>Once you press the <guilabel>Apply</guilabel> button (or hit Enter),
+the wire frame view and the object tree immediately
+change in order to comply to these settings, and here is what now should see the camera.</para>
+
+<screenshot>
+<mediaobject><imageobject><imagedata fileref="tutorial01-light-graphic.png" format="PNG"/></imageobject>
+</mediaobject>
+</screenshot>
+
+</sect1>
+
+<sect1 id="basic-tutorial-step-4">
+<title>Step 4: Creating the Ground</title>
+<para>There are many ways to create a ground for our scene.
+One method could have been to insert a box object
+(<menuchoice><guimenu>Insert</guimenu><guisubmenu>Finite Solid Primitives</guisubmenu>
+<guimenuitem>Box</guimenuitem></menuchoice>)
+and resize x to 100, y to 0 and z to 100, for example, but it's a cumbersome way to do this task.</para>
+
+<para>In fact, &kpovmodeler; offers you a convenient feature: You can create
+a infinite plane that will feature the ground:</para>
+
+<para>Using the menu:
+<menuchoice><guimenu>Insert</guimenu><guisubmenu>Infinite Solid Primitives</guisubmenu>
+<guimenuitem>Plane</guimenuitem></menuchoice></para>
+<para>Using the toolbar: Click on the
+<inlinemediaobject><imageobject><imagedata fileref="cr22-action-pmplane.png" format="PNG"/></imageobject>
+</inlinemediaobject> icon.</para>
+
+<para>Take a good custom: Having the plane selected in the object tree, please change its name
+in something that is convenient to you and then press the <guilabel>Apply</guilabel> button (or hit Enter).
+The object tree will update the name of the entry.</para>
+
+<screenshot>
+<mediaobject><imageobject><imagedata fileref="tutorial01-plane-dialog.png" format="PNG"/></imageobject>
+</mediaobject>
+</screenshot>
+
+<para>The wire frame view also shows the plane now, even if it looks finite by now.
+But don't worry, it will spread up to the horizon line when you'll render the scene!</para>
+
+<para>If you pay attention to the object tree, you will notice that the ground entry
+can be expanded if you click on the <quote>plus</quote> icon standing just before the object.
+Once done, you see various settings parented to the object. In this case,
+there isn't much yet, apart from the standard options to any newly created object:
+Scale, rotate, and translate. Selecting each of these will change the settings
+available in the object properties view.</para>
+
+<screenshot>
+<mediaobject> <imageobject><imagedata fileref="tutorial01-plane-tree-expanded.png" format="PNG"/></imageobject>
+</mediaobject>
+</screenshot>
+
+<para>In this scene, we will arbitrary translate the ground one unit lower than the horizon line,
+just for you to tweak some of these parameters. Select translate, and adjust the parameters as follow:</para>
+
+<screenshot>
+<mediaobject><imageobject><imagedata fileref="tutorial01-plane-tree-translate.png" format="PNG"/></imageobject>
+</mediaobject>
+</screenshot>
+
+<para>Your scene should now look like the following picture.</para>
+<screenshot><mediaobject><imageobject><imagedata fileref="tutorial01-plane-graphic.png" format="PNG"/></imageobject>
+</mediaobject>
+</screenshot>
+
+</sect1>
+
+<sect1 id="basic-tutorial-step-5">
+<title>Step 5: Setting a Material for the Ground</title>
+
+<para>Please select the ground prior to adding any material properties to it.
+Many possibilities await us, but we will stay close to something quite easy for now.</para>
+
+<para>Using the menu: <menuchoice><guimenu>Insert</guimenu><guisubmenu>Textures</guisubmenu>
+<guimenuitem>Pigment</guimenuitem></menuchoice></para>
+<para>Using the toolbar: Click on the
+<inlinemediaobject>
+<imageobject><imagedata fileref="cr22-action-pmpigment.png" format="PNG"/></imageobject>
+</inlinemediaobject> icon.</para>
+
+<screenshot>
+<mediaobject><imageobject><imagedata fileref="insertaspopup.png" format="PNG"/></imageobject>
+</mediaobject>
+</screenshot>
+
+<para>In both cases, a popup window will prompt you to choose the way the object should be inserted.
+Please choose <guilabel>First Child</guilabel>. The pigment now appears in the object tree.
+You can change its name
+in the properties view (<guilabel>Name</guilabel>=<quote>Ground Pigment</quote>), and click on the
+<guibutton>Preview</guibutton> button
+in order to see how the pigment looks like for now.</para>
+
+<screenshot>
+<mediaobject><imageobject><imagedata fileref="tutorial01-ground-pigment.png" format="PNG"/></imageobject>
+</mediaobject>
+</screenshot>
+
+<para>Of course, the preview of the pigment shows nothing but a black matte material,
+because we need to refine the pigment settings. Anyway, keep in mind you always
+can preview the look and feel of your materials using the <guibutton>Preview</guibutton> button.
+We will now define the pigment colors. Again, many possibilities await us,
+but we will choose one of the most straightforward for now.</para>
+
+<para>Using the menu: <menuchoice><guimenu>Insert</guimenu><guisubmenu>Textures</guisubmenu>
+<guimenuitem>Color List</guimenuitem></menuchoice></para>
+<para>Using the toolbar: Click on the
+<inlinemediaobject>
+<imageobject><imagedata fileref="cr22-action-pmcolorlist.png" format="PNG"/></imageobject>
+</inlinemediaobject> icon</para>
+
+<para>If no color shows on the box and the sphere of the preview,
+click on the <guibutton>Apply</guibutton> button before calling for a preview.</para>
+
+<screenshot>
+<mediaobject><imageobject><imagedata fileref="tutorial01-ground-color-list.png" format="PNG"/></imageobject>
+</mediaobject>
+</screenshot>
+
+<para>The ground material has been successfully set! If you render your picture now, using the
+<inlinemediaobject>
+<imageobject><imagedata fileref="cr22-action-pmrender.png" format="PNG"/></imageobject>
+</inlinemediaobject> render icon, you should get the following result:</para>
+
+<screenshot>
+<mediaobject><imageobject><imagedata fileref="tutorial01-ground-wrong-colors-render.png" format="PNG"/></imageobject>
+</mediaobject>
+</screenshot>
+
+<para>Of course, these colors are not the ones you could have expected.
+We still have to see how we can customize them. In the case of the color list,
+you have to define two new sets of attributes, called <guilabel>Solid Color</guilabel>.
+In the Object Tree, make sure the color list entry is selected.
+Then go through this two times (you can't do it more, anyway,
+as the checkers color list can only afford the use of two solid colors):</para>
+
+<para>Using the menu: <menuchoice><guimenu>Insert</guimenu><guisubmenu>Textures</guisubmenu>
+<guimenuitem>Solid Color</guimenuitem></menuchoice></para>
+
+<para>Using the toolbar: Click on the
+<inlinemediaobject>
+<imageobject><imagedata fileref="cr22-action-pmsolidcolor.png" format="PNG"/></imageobject>
+</inlinemediaobject> icon.</para>
+
+<para>One after another, in the object tree, select the two solid colors
+and change their color attributes in the object properties view:</para>
+
+<screenshot>
+<mediaobject><imageobject><imagedata fileref="tutorial01-ground-solid-color-1.png" format="PNG"/></imageobject>
+</mediaobject>
+</screenshot>
+
+<para>...these attributes are for the first solid color (press <guibutton>Apply</guibutton>!),</para>
+
+<screenshot>
+<mediaobject><imageobject><imagedata fileref="tutorial01-ground-solid-color-2.png" format="PNG"/></imageobject>
+</mediaobject>
+</screenshot>
+
+<para>... and these attributes are for the second (press <guibutton>Apply</guibutton> again!).</para>
+
+<para>Of course, a new rendering of our scene will prove that everything has been
+taken into account accordingly:</para>
+
+<screenshot>
+<mediaobject><imageobject><imagedata fileref="tutorial01-ground-render.png" format="PNG"/></imageobject>
+</mediaobject>
+</screenshot>
+
+</sect1>
+
+<sect1 id="basic-tutorial-step-6">
+<title>Step 6: Creating the Sphere</title>
+
+<para>For this step, we should already be at ease, because we begin to understand
+&kpovmodeler;'s general behavior. In the object tree, select the scene entry.
+Creating the sphere is as easy as creating the ground:</para>
+
+<para>Using the menu: <menuchoice><guimenu>Insert</guimenu><guisubmenu>Finite Solid Primitives</guisubmenu>
+<guimenuitem>Sphere</guimenuitem></menuchoice></para>
+
+<para>Using the toolbar: Click on the
+<inlinemediaobject>
+<imageobject><imagedata fileref="cr22-action-pmsphere.png" format="PNG"/></imageobject>
+</inlinemediaobject> icon.</para>
+
+<screenshot>
+<mediaobject><imageobject><imagedata fileref="insertaspopup.png" format="PNG"/></imageobject>
+</mediaobject>
+</screenshot>
+
+<para>As before, select <guilabel>First Child</guilabel> when asked for.</para>
+
+<para>The object properties view offers you immediately to change its settings,
+which we'll do right now. By setting the <guilabel>Radius</guilabel> value to 1
+(don't forget to hit Enter or press <guibutton>Apply</guibutton>),
+we make sure that the sphere will be in contact
+with the ground. Otherwise, since we moved the ground one unit bottom,
+the sphere will look like floating above the ground.</para>
+
+<screenshot>
+<mediaobject><imageobject><imagedata fileref="tutorial01-sphere-dialog.png" format="PNG"/></imageobject>
+</mediaobject>
+</screenshot>
+
+<para>Of course, a rendering now will give a strange result: As already seen before,
+the sphere appears with a black matte material. We will set a proper material in the following step.</para>
+
+<screenshot>
+<mediaobject><imageobject><imagedata fileref="tutorial01-sphere-render-nocolor.png" format="PNG"/></imageobject>
+</mediaobject>
+</screenshot>
+
+</sect1>
+
+<sect1 id="basic-tutorial-step-7">
+<title>Step 7: Setting a Material for the Sphere</title>
+
+<para>With the sphere selected, you can now set a material for it. As we already did for the ground,
+let's give to the sphere a pigment color:</para>
+
+<para>Using the menu: <menuchoice><guimenu>Insert</guimenu><guisubmenu>Textures</guisubmenu>
+<guimenuitem>Pigment</guimenuitem></menuchoice></para>
+
+<para>Using the toolbar: Click on the
+<inlinemediaobject><imageobject><imagedata fileref="cr22-action-pmpigment.png" format="PNG"/></imageobject>
+</inlinemediaobject> icon</para>
+
+<para>Select <guilabel>First Child</guilabel> and rename to <quote>Sphere pigment</quote>, for example.
+With the sphere pigment entry selected, insert a solid color and set the parameters as follow:</para>
+
+<para>Using the menu: <menuchoice><guimenu>Insert</guimenu><guisubmenu>Textures</guisubmenu>
+<guimenuitem>Solid Color</guimenuitem></menuchoice></para>
+
+<para>Using the toolbar: Click on the
+<inlinemediaobject><imageobject><imagedata fileref="cr22-action-pmsolidcolor.png" format="PNG"/></imageobject>
+</inlinemediaobject> icon</para>
+
+<screenshot>
+<mediaobject><imageobject><imagedata fileref="tutorial01-sphere-solid-color.png" format="PNG"/></imageobject>
+</mediaobject>
+</screenshot>
+
+<para>You already can render the scene and get a first poor result:</para>
+
+<screenshot>
+<mediaobject><imageobject><imagedata fileref="tutorial01-sphere-render-solidcolor.png" format="PNG"/></imageobject>
+</mediaobject>
+</screenshot>
+
+<para>But there are more interesting effects to achieve if we take time to set some finish attributes:</para>
+
+<para>Using the menu: <menuchoice><guimenu>Insert</guimenu><guisubmenu>Textures</guisubmenu>
+<guimenuitem>Finish</guimenuitem></menuchoice></para>
+<para>Using the toolbar: Click on the
+<inlinemediaobject>
+<imageobject><imagedata fileref="cr22-action-pmfinish.png" format="PNG"/></imageobject>
+</inlinemediaobject> icon.</para>
+
+<para>Then change the values according to the following snapshot and press
+<guibutton>Apply</guibutton> or hit Enter.</para>
+
+<screenshot>
+<mediaobject><imageobject><imagedata fileref="tutorial01-sphere-finish-dialog.png" format="PNG"/></imageobject>
+</mediaobject>
+</screenshot>
+
+<para>The <guilabel>Specular</guilabel> and <guilabel>Reflection</guilabel>
+parameters give particularly good visual effects,
+perfect for glass or chrome-like effects, even if <guilabel>Metallic</guilabel>
+hasn't been chosen at this step:</para>
+
+<screenshot>
+<mediaobject><imageobject><imagedata fileref="tutorial01-sphere-render-finish.png" format="PNG"/></imageobject>
+</mediaobject>
+</screenshot>
+
+</sect1>
+
+<sect1 id="basic-tutorial-conclusion">
+<title>Conclusion</title>
+
+<para>You should now have a fair glimpse of what is possible with kpovmodeler.
+Hopefully, you are already skilled enough to do simple but beautiful things.</para>
+
+</sect1>
+</chapter>
+
+<chapter id="concepts">
+<title>Basic Concepts</title>
+
+<sect1 id="what-is-raytracing">
+<title>What is Raytracing?</title>
+
+<para>Raytracing is a method of <link
+linkend="gloss-rendering">rendering</link>, that is, creating a 2D
+image out of a 3D scene or model.</para>
+
+<para>When raytracing a scene, the renderer shoots a hypothetical ray
+from the perspective of the viewer (that is, from the camera you are
+rendering the scene from) through each pixel in the scene. It
+calculates how this ray reflects and refracts from objects, the visual
+effects of the light sources in the scene and how atmospheric effects such
+as fog affect it. The scene is built up, pixel by pixel.</para>
+
+<para>As you may imagine, without a camera, you cannot see anything -
+the camera is your <quote>eye</quote> into the scene. Furthermore,
+without any light, you still won't see anything - it would just be
+dark. Obviously, any scene intended for raytracing must include
+some light, an object of some kind and at least one camera.</para>
+
+</sect1>
+
+</chapter>
+
+<chapter id="objects-reference">
+<title>Objects Reference</title>
+
+<para>For a complete reference to all objects and attributes
+see the &Povray; user documentation.</para>
+</chapter>
+
+
+<chapter id="menu-reference">
+<title>Menu Reference</title>
+
+<sect1 id="file-menu">
+<title>The <guimenu>File</guimenu> Menu</title>
+
+<variablelist>
+<varlistentry>
+<term><menuchoice><shortcut>
+<keycombo action="simul">&Ctrl;<keycap>N</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>New</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Create a new scene.</action></para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Import Povray...</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Import a &Povray; scene</action> created outside
+&kpovmodeler;.</para>
+<para>A normal file dialog will open, allowing you to choose your
+file. Povray files usually have the extensions <literal
+role="extension">*.pov</literal> or <literal
+role="extension">*.inc</literal>.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut>
+<keycombo action="simul">&Ctrl;<keycap>O</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Open...</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Open a file.</action> The standard file dialog will
+allow you to choose a file you have previously created with
+&kpovmodeler;</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu>
+<guisubmenu>Open Recent</guisubmenu>
+</menuchoice></term>
+<listitem>
+<para><action>Open a file from a list of the files you have been
+recently working on.</action></para>
+<para>Whenever you open or create a new model, it is added to this
+submenu, replacing the oldest entry in the list.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut>
+<keycombo action="simul">&Ctrl;<keycap>S</keycap></keycombo></shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Save</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Save the currently active scene.</action></para>
+<para>If you have already saved this model, it will be saved with the
+same name. If it is a new file, you will be asked to name it and
+choose a location to save it.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Save As...</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Save the currently active scene with a new
+name.</action></para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Export Povray...</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Export the scene as a &Povray; file.</action></para>
+<para>The file save dialog will allow you to choose a name and
+location to save the file.</para>
+<note><para>&kpovmodeler; will automatically add the
+<literal role="extension">.pov</literal> extension.</para></note>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Revert</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Revert the scene to the state it was in the last time
+you saved it.</action> Changes you have made since the last save will
+be lost.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut>
+<keycombo action="simul">&Ctrl;<keycap>P</keycap></keycombo></shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Print...</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para>Printing is not implemented yet.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut>
+<keycombo action="simul">&Ctrl;<keycap>W</keycap></keycombo></shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Close</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Close the current scene</action> without closing
+&kpovmodeler;</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut>
+<keycombo action="simul">&Ctrl;<keycap>Q</keycap></keycombo></shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Quit</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Quit</action> &kpovmodeler;. If you have any unsaved
+changes, you will be given a chance to save them.</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+</sect1>
+
+<sect1 id="edit-menu">
+<title>The <guimenu>Edit</guimenu> Menu</title>
+
+<variablelist>
+<varlistentry>
+<term><menuchoice><shortcut>
+<keycombo action="simul">&Ctrl;<keycap>Z</keycap></keycombo>
+</shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Undo</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Undo the last action you performed.</action></para>
+<para>This menu item is not available unless you have unsaved changes
+to the current scene.</para><!-- FIXME: is the number of items in the -->
+<!-- undo history configurable? -->
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">
+&Ctrl;&Shift;<keycap>Z</keycap></keycombo></shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Redo</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Redo the last action you undid.</action> This menu item
+is not available unless you have used
+<menuchoice><guimenu>Edit</guimenu>
+<guimenuitem>Undo</guimenuitem></menuchoice>.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">
+&Ctrl;<keycap>X</keycap></keycombo></shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Cut</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Cut</action> the currently selected object(s) from the scene,
+and store them on the clipboard.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">
+&Ctrl;<keycap>C</keycap></keycombo></shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Copy</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Copy</action> the currently selected object(s), and
+store them on the clipboard.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">
+&Ctrl;<keycap>V</keycap></keycombo></shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Paste</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Paste</action> the contents of the clipboard.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Edit</guimenu>
+<guimenuitem>Delete</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para><action>Delete</action> the currently selected object(s) from
+the scene.</para>
+<!-- FIXME: Shouldn't this be bound to the delete key? -->
+</listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect1>
+
+<sect1 id="view-menu">
+<title>The <guimenu>View</guimenu> Menu</title>
+
+<variablelist>
+
+<varlistentry>
+<term><guimenu>View</guimenu>
+<guimenuitem>New Object Tree</guimenuitem>
+</term>
+<listitem>
+<para><action>Create</action> a new <link linkend="the-object-tree">Object Tree</link>.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guimenu>View</guimenu>
+<guimenuitem>New Properties View</guimenuitem>
+</term>
+<listitem>
+<para><action>Create</action> a new <link linkend="the-properties-view">Object Properties View</link>.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guimenu>View</guimenu>
+<guimenuitem>New Top View</guimenuitem>
+</term>
+<listitem>
+<para><action>Create</action> a new
+<link linkend="orthographic-views">Orthographic Wireframe View</link>
+from the top perspective.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guimenu>View</guimenu>
+<guimenuitem>New Bottom View</guimenuitem>
+</term>
+<listitem>
+<para><action>Create</action> a new
+<link linkend="orthographic-views">Orthographic Wireframe View</link>
+from the bottom perspective.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guimenu>View</guimenu>
+<guimenuitem>New Left View</guimenuitem>
+</term>
+<listitem>
+<para><action>Create</action> a new
+<link linkend="orthographic-views">Orthographic Wireframe View</link>
+from the left perspective.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guimenu>View</guimenu>
+<guimenuitem>New Right View</guimenuitem>
+</term>
+<listitem>
+<para><action>Create</action> a new
+<link linkend="orthographic-views">Orthographic Wireframe View</link>
+from the right perspective.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guimenu>View</guimenu>
+<guimenuitem>New Front View</guimenuitem>
+</term>
+<listitem>
+<para><action>Create</action> a new
+<link linkend="orthographic-views">Orthographic Wireframe View</link>
+from the front perspective.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guimenu>View</guimenu>
+<guimenuitem>New Back View</guimenuitem>
+</term>
+<listitem>
+<para><action>Create</action> a new
+<link linkend="orthographic-views">Orthographic Wireframe View</link>
+from the back perspective.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guimenu>View</guimenu>
+<guimenuitem>New Camera View</guimenuitem>
+</term>
+<listitem>
+<para><action>Create</action> a new
+<link linkend="camera-view">Camera View</link>.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guimenu>View</guimenu>
+<guimenuitem>View Layouts</guimenuitem>
+</term>
+<listitem>
+<para>Contains a list of all available view layouts. Switch to the
+selected layout.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guimenu>View</guimenu>
+<guimenuitem>Save View Layout...</guimenuitem>
+</term>
+<listitem>
+<para>Save the current view layout. A dialog opens to choose a
+name for a new layout or to overwrite an existing one.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guimenu>View</guimenu>
+<guimenuitem>Render Modes...</guimenuitem>
+</term>
+<listitem>
+<para>Open the
+<link linkend="render-modes-configuration">render modes configuration</link>
+dialog.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guimenu>View</guimenu>
+<guimenuitem>Render</guimenuitem>
+</term>
+<listitem>
+<para>Render the scene.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guimenu>View</guimenu>
+<guimenuitem>Render Window</guimenuitem>
+</term>
+<listitem>
+<para>Show the &Povray; render window.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guimenu>View</guimenu>
+<guimenuitem>Redisplay</guimenuitem>
+</term>
+<listitem>
+<para>Redisplay the wire frame views.</para>
+</listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect1>
+
+<sect1 id="insert-menu">
+<title>The <guimenu>Insert</guimenu> Menu</title>
+
+<para>Creation actions for all supported &Povray; objects.</para>
+
+</sect1>
+
+<sect1 id="settings-menu">
+<title>The <guimenu>Settings</guimenu> Menu</title>
+<para>This menu provides options for configuring &kpovmodeler;, changing its
+appearance, shortcuts and standard behavior.</para>
+
+<variablelist>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Show Statusbar</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Toggles the statusbar on/off.</action></para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Show Path</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Show/hide the path in the caption.</action></para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Save settings</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Saves the current settings.</action></para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Configure Key Bindings...</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Opens a dialog for changing the key bindings.</action>
+Using this option you can change the standard key shortcut for &kpovmodeler;'s commands
+or create new ones.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Configure Toolbars...</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Opens a dialog for configuring the toolbar.</action> You
+can add and remove toolbuttons for &kpovmodeler;'s commands with this
+option.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Configure KPovModeler...</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Opens a dialog to configure &kpovmodeler;.</action></para>
+</listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect1>
+
+
+<sect1 id="help-menu">
+<title>The <guimenu>Help</guimenu> Menu</title>
+
+&help.menu.documentation;
+
+</sect1>
+
+</chapter>
+
+<chapter id="credits-and-licenses">
+<title>Credits and Licenses</title>
+
+<para>&kpovmodeler; copyright 2001,2002 the &kpovmodeler;
+authors.</para>
+
+<itemizedlist>
+<title>Authors</title>
+<listitem>
+<para>Andreas Zehender <email>zehender@kde.org</email></para>
+</listitem>
+<listitem>
+<para>Luis Passos Carvalho
+<email>lpassos@mail.telepac.pt</email></para>
+</listitem>
+<listitem>
+<para>Phillippe Van Hecke
+<email>lephiloux@tiscalinet.be</email></para>
+</listitem>
+<listitem>
+<para>Leonardo Skorianez <email>skorianez@bol.com.br</email></para>
+</listitem>
+</itemizedlist>
+
+<para>Documentation copyright 2002 Lauri Watts
+<email>lauri@kde.org</email></para>
+<para>Documentation copyright 2002 Andreas Zehender
+<email>zehender@kde.org</email></para>
+<para>Documentation copyright 2002 Olivier Saraja
+<email>olivier@linuxgraphic.org</email></para>
+
+<!-- TRANS:CREDIT_FOR_TRANSLATORS -->
+
+&underFDL;
+&underGPL;
+
+</chapter>
+
+<glossary id="glossary">
+<title>Glossary</title>
+
+<glossentry id="gloss-bump-map">
+<glossterm>Bump Map</glossterm>
+<glossdef>
+<para>A bump map is a way to simulate a rough surface, without having
+to model every single <quote>bump</quote> on the surface, and without
+changing the underlying geometric shape of the object itself.</para>
+<para>It is common to use the same file as both a bump map and a <link
+linkend="gloss-texture-map">texture map</link>.</para>
+</glossdef>
+</glossentry>
+
+<glossentry id="gloss-primitives">
+<glossterm>Primitives</glossterm>
+<glossdef>
+<para>Primitives are the basic geometric shapes that you can use as
+<quote>building blocks</quote>. Most complex 3d models are created
+from many dozens, or even hundreds, of these primitives, which are
+then edited and manipulated to give a more realistic
+appearance.</para>
+</glossdef>
+</glossentry>
+
+<glossentry id="gloss-rendering">
+<glossterm>Rendering</glossterm>
+<glossdef>
+<para>Not yet written</para>
+</glossdef>
+</glossentry>
+
+<glossentry id="gloss-texture-map">
+<glossterm>Texture Map</glossterm>
+<glossdef>
+<para>A texture map is a way of applying color to the surface of an
+object on a pixel by pixel basis, by applying an image file as a color
+map.</para>
+<para>It is common to use the same image file as a <link
+linkend="gloss-bump-map">bump map</link>.</para>
+</glossdef>
+</glossentry>
+
+
+
+</glossary>
+
+&documentation.index;
+
+<appendix id="installation">
+<title>Installation</title>
+
+&install.intro.documentation;
+&install.compile.documentation;
+
+</appendix>
+
+</book>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-minimize-attributes:nil
+sgml-general-insert-case:lower
+sgml-indent-step:0
+sgml-indent-data:nil
+End:
+
+// vim:ts=2:sw=2:tw=78:noet
+-->
diff --git a/doc/kpovmodeler/insertaspopup.png b/doc/kpovmodeler/insertaspopup.png
new file mode 100644
index 00000000..523bd0cc
--- /dev/null
+++ b/doc/kpovmodeler/insertaspopup.png
Binary files differ
diff --git a/doc/kpovmodeler/objectpropertiesview.png b/doc/kpovmodeler/objectpropertiesview.png
new file mode 100644
index 00000000..92d74a6f
--- /dev/null
+++ b/doc/kpovmodeler/objectpropertiesview.png
Binary files differ
diff --git a/doc/kpovmodeler/objecttree.png b/doc/kpovmodeler/objecttree.png
new file mode 100644
index 00000000..1be38e65
--- /dev/null
+++ b/doc/kpovmodeler/objecttree.png
Binary files differ
diff --git a/doc/kpovmodeler/rendericon.png b/doc/kpovmodeler/rendericon.png
new file mode 100644
index 00000000..6aa2b69f
--- /dev/null
+++ b/doc/kpovmodeler/rendericon.png
Binary files differ
diff --git a/doc/kpovmodeler/rendermodeoutput.png b/doc/kpovmodeler/rendermodeoutput.png
new file mode 100644
index 00000000..77146f2c
--- /dev/null
+++ b/doc/kpovmodeler/rendermodeoutput.png
Binary files differ
diff --git a/doc/kpovmodeler/rendermodequality.png b/doc/kpovmodeler/rendermodequality.png
new file mode 100644
index 00000000..0b0fba3d
--- /dev/null
+++ b/doc/kpovmodeler/rendermodequality.png
Binary files differ
diff --git a/doc/kpovmodeler/rendermodesize.png b/doc/kpovmodeler/rendermodesize.png
new file mode 100644
index 00000000..c593b1ed
--- /dev/null
+++ b/doc/kpovmodeler/rendermodesize.png
Binary files differ
diff --git a/doc/kpovmodeler/rendermodesselection.png b/doc/kpovmodeler/rendermodesselection.png
new file mode 100644
index 00000000..4ea97325
--- /dev/null
+++ b/doc/kpovmodeler/rendermodesselection.png
Binary files differ
diff --git a/doc/kpovmodeler/rendermodestoolbar.png b/doc/kpovmodeler/rendermodestoolbar.png
new file mode 100644
index 00000000..8aee4f53
--- /dev/null
+++ b/doc/kpovmodeler/rendermodestoolbar.png
Binary files differ
diff --git a/doc/kpovmodeler/rendersettingsicon.png b/doc/kpovmodeler/rendersettingsicon.png
new file mode 100644
index 00000000..cb6b2e9a
--- /dev/null
+++ b/doc/kpovmodeler/rendersettingsicon.png
Binary files differ
diff --git a/doc/kpovmodeler/renderwindow.png b/doc/kpovmodeler/renderwindow.png
new file mode 100644
index 00000000..25662a25
--- /dev/null
+++ b/doc/kpovmodeler/renderwindow.png
Binary files differ
diff --git a/doc/kpovmodeler/texturepreview.png b/doc/kpovmodeler/texturepreview.png
new file mode 100644
index 00000000..c9ca6060
--- /dev/null
+++ b/doc/kpovmodeler/texturepreview.png
Binary files differ
diff --git a/doc/kpovmodeler/topview.png b/doc/kpovmodeler/topview.png
new file mode 100644
index 00000000..faf76e20
--- /dev/null
+++ b/doc/kpovmodeler/topview.png
Binary files differ
diff --git a/doc/kpovmodeler/tutorial01-camera-dialog.png b/doc/kpovmodeler/tutorial01-camera-dialog.png
new file mode 100644
index 00000000..b3f9856f
--- /dev/null
+++ b/doc/kpovmodeler/tutorial01-camera-dialog.png
Binary files differ
diff --git a/doc/kpovmodeler/tutorial01-camera-graphic.png b/doc/kpovmodeler/tutorial01-camera-graphic.png
new file mode 100644
index 00000000..12ca95bc
--- /dev/null
+++ b/doc/kpovmodeler/tutorial01-camera-graphic.png
Binary files differ
diff --git a/doc/kpovmodeler/tutorial01-final-render.png b/doc/kpovmodeler/tutorial01-final-render.png
new file mode 100644
index 00000000..48a3a016
--- /dev/null
+++ b/doc/kpovmodeler/tutorial01-final-render.png
Binary files differ
diff --git a/doc/kpovmodeler/tutorial01-ground-color-list.png b/doc/kpovmodeler/tutorial01-ground-color-list.png
new file mode 100644
index 00000000..00166661
--- /dev/null
+++ b/doc/kpovmodeler/tutorial01-ground-color-list.png
Binary files differ
diff --git a/doc/kpovmodeler/tutorial01-ground-pigment.png b/doc/kpovmodeler/tutorial01-ground-pigment.png
new file mode 100644
index 00000000..33bc3206
--- /dev/null
+++ b/doc/kpovmodeler/tutorial01-ground-pigment.png
Binary files differ
diff --git a/doc/kpovmodeler/tutorial01-ground-render.png b/doc/kpovmodeler/tutorial01-ground-render.png
new file mode 100644
index 00000000..18a4816c
--- /dev/null
+++ b/doc/kpovmodeler/tutorial01-ground-render.png
Binary files differ
diff --git a/doc/kpovmodeler/tutorial01-ground-solid-color-1.png b/doc/kpovmodeler/tutorial01-ground-solid-color-1.png
new file mode 100644
index 00000000..a805904a
--- /dev/null
+++ b/doc/kpovmodeler/tutorial01-ground-solid-color-1.png
Binary files differ
diff --git a/doc/kpovmodeler/tutorial01-ground-solid-color-2.png b/doc/kpovmodeler/tutorial01-ground-solid-color-2.png
new file mode 100644
index 00000000..870fd8d4
--- /dev/null
+++ b/doc/kpovmodeler/tutorial01-ground-solid-color-2.png
Binary files differ
diff --git a/doc/kpovmodeler/tutorial01-ground-wrong-colors-render.png b/doc/kpovmodeler/tutorial01-ground-wrong-colors-render.png
new file mode 100644
index 00000000..36dfe296
--- /dev/null
+++ b/doc/kpovmodeler/tutorial01-ground-wrong-colors-render.png
Binary files differ
diff --git a/doc/kpovmodeler/tutorial01-light-dialog.png b/doc/kpovmodeler/tutorial01-light-dialog.png
new file mode 100644
index 00000000..cb9adeaf
--- /dev/null
+++ b/doc/kpovmodeler/tutorial01-light-dialog.png
Binary files differ
diff --git a/doc/kpovmodeler/tutorial01-light-graphic.png b/doc/kpovmodeler/tutorial01-light-graphic.png
new file mode 100644
index 00000000..ede4b9c7
--- /dev/null
+++ b/doc/kpovmodeler/tutorial01-light-graphic.png
Binary files differ
diff --git a/doc/kpovmodeler/tutorial01-plane-dialog.png b/doc/kpovmodeler/tutorial01-plane-dialog.png
new file mode 100644
index 00000000..9a63936d
--- /dev/null
+++ b/doc/kpovmodeler/tutorial01-plane-dialog.png
Binary files differ
diff --git a/doc/kpovmodeler/tutorial01-plane-graphic.png b/doc/kpovmodeler/tutorial01-plane-graphic.png
new file mode 100644
index 00000000..c2cf8163
--- /dev/null
+++ b/doc/kpovmodeler/tutorial01-plane-graphic.png
Binary files differ
diff --git a/doc/kpovmodeler/tutorial01-plane-tree-expanded.png b/doc/kpovmodeler/tutorial01-plane-tree-expanded.png
new file mode 100644
index 00000000..024c969c
--- /dev/null
+++ b/doc/kpovmodeler/tutorial01-plane-tree-expanded.png
Binary files differ
diff --git a/doc/kpovmodeler/tutorial01-plane-tree-translate.png b/doc/kpovmodeler/tutorial01-plane-tree-translate.png
new file mode 100644
index 00000000..84d377b1
--- /dev/null
+++ b/doc/kpovmodeler/tutorial01-plane-tree-translate.png
Binary files differ
diff --git a/doc/kpovmodeler/tutorial01-sphere-dialog.png b/doc/kpovmodeler/tutorial01-sphere-dialog.png
new file mode 100644
index 00000000..2d17f4b6
--- /dev/null
+++ b/doc/kpovmodeler/tutorial01-sphere-dialog.png
Binary files differ
diff --git a/doc/kpovmodeler/tutorial01-sphere-finish-dialog.png b/doc/kpovmodeler/tutorial01-sphere-finish-dialog.png
new file mode 100644
index 00000000..e72b9aa6
--- /dev/null
+++ b/doc/kpovmodeler/tutorial01-sphere-finish-dialog.png
Binary files differ
diff --git a/doc/kpovmodeler/tutorial01-sphere-render-finish.png b/doc/kpovmodeler/tutorial01-sphere-render-finish.png
new file mode 100644
index 00000000..7861b608
--- /dev/null
+++ b/doc/kpovmodeler/tutorial01-sphere-render-finish.png
Binary files differ
diff --git a/doc/kpovmodeler/tutorial01-sphere-render-nocolor.png b/doc/kpovmodeler/tutorial01-sphere-render-nocolor.png
new file mode 100644
index 00000000..72dffddb
--- /dev/null
+++ b/doc/kpovmodeler/tutorial01-sphere-render-nocolor.png
Binary files differ
diff --git a/doc/kpovmodeler/tutorial01-sphere-render-solidcolor.png b/doc/kpovmodeler/tutorial01-sphere-render-solidcolor.png
new file mode 100644
index 00000000..b96ab37f
--- /dev/null
+++ b/doc/kpovmodeler/tutorial01-sphere-render-solidcolor.png
Binary files differ
diff --git a/doc/kpovmodeler/tutorial01-sphere-solid-color.png b/doc/kpovmodeler/tutorial01-sphere-solid-color.png
new file mode 100644
index 00000000..52b03ff7
--- /dev/null
+++ b/doc/kpovmodeler/tutorial01-sphere-solid-color.png
Binary files differ
diff --git a/doc/kruler/Makefile.am b/doc/kruler/Makefile.am
new file mode 100644
index 00000000..085981d9
--- /dev/null
+++ b/doc/kruler/Makefile.am
@@ -0,0 +1,4 @@
+
+KDE_LANG = en
+KDE_DOCS = AUTO
+
diff --git a/doc/kruler/index.docbook b/doc/kruler/index.docbook
new file mode 100644
index 00000000..433b3cc9
--- /dev/null
+++ b/doc/kruler/index.docbook
@@ -0,0 +1,359 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+ <!ENTITY kappname "&kruler;">
+ <!ENTITY package "kdegraphics">
+ <!ENTITY % English "INCLUDE" > <!-- change language only here -->
+ <!ENTITY % addindex "IGNORE">
+]>
+
+<book lang="&language;">
+
+<bookinfo>
+<title>The &kruler; Handbook</title>
+
+<authorgroup>
+<author>
+<firstname>Lauri</firstname>
+<surname>Watts</surname>
+<affiliation>
+<address><email>&Lauri.Watts.mail;</email></address>
+</affiliation>
+</author>
+
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+</authorgroup>
+
+<legalnotice>&FDLNotice;</legalnotice>
+
+<copyright>
+<year>2001</year>
+<holder>&Lauri.Watts;</holder>
+</copyright>
+
+<date>2005-12-10</date>
+<releaseinfo>3.5</releaseinfo>
+
+<!-- Abstract about this handbook -->
+
+<abstract>
+<para>
+&kruler; can be used to measure objects on the screen.
+</para>
+</abstract>
+
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>KRuler</keyword>
+<keyword>kdegraphics</keyword>
+</keywordset>
+
+</bookinfo>
+
+<chapter id="introduction">
+<title>Introduction</title>
+
+<para>&kruler; is a very simple application, with only one aim in life. To
+measure distances on your screen.</para>
+
+<para>To start &kruler;, choose <menuchoice><guimenu>Graphics</guimenu>
+<guisubmenu>More Applications</guisubmenu>
+<guimenuitem>KDE Screen Ruler</guimenuitem></menuchoice> from your
+<guimenu>K</guimenu> menu.</para>
+
+<para>Clicking with the &LMB; on the &kruler; will turn the cursor to a cross
+with four arrows and enables you to drag &kruler; around the screen.</para>
+
+<para>When you move the mouse over &kruler;, your cursor will turn into an
+elongated arrow, with a circle at one end. As you move the cursor, &kruler; will
+display how far from the point marked <guilabel>0</guilabel> the circle on the
+end of the cursor currently is. &kruler; will also display the
+&HTML; color code of the color currently under the circle.
+This is very useful for picking out colors from an image. If you move the
+mouse far enough that the arrow cursor is no longer touching &kruler;, the
+cursor will revert to normal, allowing you to carry on working with your other
+applications.</para>
+
+<para>You can change the orientation using the context menu, described in the
+next chapter.</para>
+
+</chapter>
+
+<chapter id="menu-reference">
+<title>Menu Reference</title>
+
+<para>Clicking with the &RMB; on the ruler will pop up a context menu, with the
+following entries:</para>
+
+<variablelist>
+<varlistentry>
+<term>
+<menuchoice>
+<guisubmenu>Orientation</guisubmenu>
+</menuchoice>
+</term>
+<listitem>
+<para>This submenu contains entries that allow you to change the orientation of
+&kruler;</para>
+
+<variablelist>
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycap>N</keycap>
+</shortcut>
+<guisubmenu>Orientation</guisubmenu>
+<guimenuitem>North</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>Turns &kruler; so the ruler is horizontal, and the measurements are on the
+top (North) of the ruler</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycap>E</keycap>
+</shortcut>
+<guisubmenu>Orientation</guisubmenu>
+<guimenuitem>East</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>Turns &kruler; so the ruler is vertical, and the measurements are on the
+right (East) of the ruler</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycap>S</keycap>
+</shortcut>
+<guisubmenu>Orientation</guisubmenu>
+<guimenuitem>South</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>Turns &kruler; so the ruler is horizontal, and the measurements are on the
+bottom (South) of the ruler</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycap>W</keycap>
+</shortcut>
+<guisubmenu>Orientation</guisubmenu>
+<guimenuitem>West</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>Turns &kruler; so the ruler is vertical, and the measurements are on the
+left (West) of the ruler</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycap>R</keycap>
+</shortcut>
+<guisubmenu>Orientation</guisubmenu>
+<guimenuitem>Turn Right</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>Turns the ruler 90 Degrees to the right. For example, if it is oriented
+South, it will rotate to be oriented West.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycap>L</keycap>
+</shortcut>
+<guisubmenu>Orientation</guisubmenu>
+<guimenuitem>Turn Left</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>Turns the ruler 90 Degrees to the left. For example, if it is oriented
+West, it will rotate to be oriented South.</para>
+</listitem>
+</varlistentry>
+</variablelist>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>
+<menuchoice>
+<guisubmenu>Length</guisubmenu>
+</menuchoice>
+</term>
+<listitem>
+<para>This submenu contains entries that allow you to change the length of
+&kruler;</para>
+<variablelist>
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut><keycombo action="simul">&Ctrl;
+<keycap>S</keycap></keycombo>
+</shortcut>
+<guisubmenu>Length</guisubmenu>
+<guimenuitem>Short</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>Makes &kruler; short - about 385 pixels long.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>M</keycap></keycombo>
+</shortcut>
+<guisubmenu>Length</guisubmenu>
+<guimenuitem>Medium</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>Makes &kruler; a medium length - about 640 pixels long.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>T</keycap></keycombo>
+</shortcut>
+<guisubmenu>Length</guisubmenu>
+<guimenuitem>Tall</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>Makes &kruler; long - about 960 pixels in length.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>F</keycap></keycombo>
+</shortcut>
+<guisubmenu>Length</guisubmenu>
+<guimenuitem>Full Screen Width</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>Makes &kruler; the same size as your screen width.</para>
+</listitem>
+</varlistentry>
+</variablelist>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>C</keycap></keycombo>
+</shortcut>
+<guimenuitem>Choose Color...</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>Displays the standard &kde; color picker dialog, where you can choose the
+background color for &kruler;.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul"><keycap>F</keycap></keycombo>
+</shortcut>
+<guimenuitem>Choose Font...</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para>Displays the standard &kde; font dialog where you can choose the font for
+&kruler;.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term>
+<menuchoice>
+<guisubmenu>Help</guisubmenu>
+</menuchoice>
+</term>
+<listitem>
+&help.menu.documentation;
+</listitem>
+</varlistentry>
+</variablelist>
+
+<variablelist>
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>Q</keycap></keycombo>
+</shortcut>
+<guimenuitem>Quit</guimenuitem>
+</menuchoice>
+</term>
+<listitem>
+<para><action>Quits</action> &kruler;</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+</chapter>
+
+<chapter id="credits-and-license">
+<title>Credits and Licenses</title>
+
+<para>&kruler;</para>
+
+<para>Copyright 2000, 2001 Till Krech <email>till@snafu.de</email></para>
+
+<para>Thanks to Gunnstein Lye <email>gl@ez.no</email> for the initial port to
+&kde; 2</para>
+
+<para>Documentation Copyright &Lauri.Watts;
+&Lauri.Watts.mail;</para>
+
+<!-- TRANS:CREDIT_FOR_TRANSLATORS -->
+
+&underFDL;
+&underGPL;
+
+</chapter>
+
+<appendix id="installation">
+<title>Installation</title>
+
+&install.intro.documentation;
+
+&install.compile.documentation;
+
+</appendix>
+
+&documentation.index;
+</book>
+<!--
+Local Variables:
+mode: sgml
+sgml-minimize-attributes: nil
+sgml-general-insert-case: lower
+End:
+-->
+
diff --git a/doc/ksnapshot/Makefile.am b/doc/ksnapshot/Makefile.am
new file mode 100644
index 00000000..085981d9
--- /dev/null
+++ b/doc/ksnapshot/Makefile.am
@@ -0,0 +1,4 @@
+
+KDE_LANG = en
+KDE_DOCS = AUTO
+
diff --git a/doc/ksnapshot/index.docbook b/doc/ksnapshot/index.docbook
new file mode 100644
index 00000000..408ab80d
--- /dev/null
+++ b/doc/ksnapshot/index.docbook
@@ -0,0 +1,535 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+ <!ENTITY kappname "&ksnapshot;">
+ <!ENTITY package "kdegraphics">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE" > <!-- change language only here -->
+]>
+
+<book lang="&language;">
+
+<bookinfo>
+<title>The &ksnapshot; Handbook</title>
+
+<authorgroup>
+<author>
+<firstname>Richard</firstname>
+<othername>J.</othername>
+<surname>Moore</surname>
+<affiliation>
+<address>&Richard.J.Moore.mail;</address>
+</affiliation>
+</author>
+
+<author>
+<firstname>Robert</firstname>
+<othername>L.</othername>
+<surname>McCormick</surname>
+<affiliation>
+<address>&Robert.L.McCormick.mail;</address>
+</affiliation>
+</author>
+
+<author>
+<firstname>Brad</firstname>
+<surname>Hards</surname>
+<affiliation>
+<address>&Brad.Hards.mail;</address>
+</affiliation>
+</author>
+
+<othercredit role="reviewer">
+<firstname>Lauri</firstname>
+<surname>Watts</surname>
+<affiliation>
+<address>&Lauri.Watts.mail;</address>
+</affiliation>
+<contrib>Reviewer</contrib>
+</othercredit>
+
+<othercredit role="developer">
+<firstname>Richard</firstname>
+<othername>J</othername>
+<surname>Moore</surname>
+<affiliation>
+<address>&Richard.J.Moore.mail;</address>
+</affiliation>
+<contrib>Developer</contrib>
+</othercredit>
+
+<othercredit role="developer">
+<firstname>Matthias</firstname>
+<surname>Ettrich</surname>
+<affiliation>
+<address>&Matthias.Ettrich.mail;</address>
+</affiliation>
+<contrib>Developer</contrib>
+</othercredit>
+
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+</authorgroup>
+
+<copyright>
+<year>1997-2000</year>
+<holder>&Richard.J.Moore;</holder>
+</copyright>
+
+<copyright>
+<year>2000</year>
+<holder>&Matthias.Ettrich;</holder>
+</copyright>
+
+<legalnotice>&FDLNotice;</legalnotice>
+
+<date>2006-07-05</date>
+<releaseinfo>0.7</releaseinfo>
+
+<abstract>
+<para>&ksnapshot; is a simple applet for taking screenshots. It is capable
+of capturing images of the whole desktop, a single window, a section of a window or a selected
+region. The images can then be saved in a variety of formats.</para>
+</abstract>
+
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>KSnapshot</keyword>
+<keyword>kdegraphics</keyword>
+<keyword>screen capture</keyword>
+<keyword>screen grab</keyword>
+</keywordset>
+
+</bookinfo>
+
+<chapter id="introduction">
+<title>Introduction</title>
+
+<para>&ksnapshot; is a simple applet for taking screenshots. It is capable
+of capturing images of the whole desktop, a single window a section of a window or a selected
+region. The images can then be saved in a variety of formats.</para>
+
+<para>Please report any problems or feature requests to the <ulink
+url="http://bugs.kde.org/wizard.cgi">&kde; Bug Tracking System</ulink></para>
+
+</chapter>
+
+<chapter id="using-ksapshot">
+<title>Using &ksnapshot;</title>
+
+<para>This chapter describes the use of &ksnapshot; for capturing screen
+images.</para>
+
+<sect1 id="starting">
+<title>Starting &ksnapshot;</title>
+
+<para>&ksnapshot; may be started by one of several ways as described
+below.</para>
+
+<itemizedlist>
+<listitem>
+<para>You may start &ksnapshot; by selecting it from the <menuchoice>
+<guimenu>K-Menu</guimenu><guisubmenu>Graphics</guisubmenu>
+<guimenuitem>&ksnapshot; (Screen Capture Program)</guimenuitem></menuchoice>.
+</para></listitem>
+<listitem>
+<para>You may start &ksnapshot; by entering the following at the command
+prompt:</para>
+<screen width="40">
+<prompt>%</prompt> <command>ksnapshot &amp;</command>
+</screen>
+</listitem>
+<listitem><para>The mini command line (invoked with
+<keycombo action="simul">&Alt;<keycap>F2</keycap></keycombo>) may
+also be used to start &ksnapshot;</para></listitem>
+</itemizedlist>
+
+<para>Once &ksnapshot; starts, you will see a window like the following:
+<mediaobject>
+<imageobject>
+<imagedata fileref="window.png" format="PNG"/>
+</imageobject>
+<textobject><phrase>&ksnapshot; Preview Window</phrase>
+</textobject>
+</mediaobject>
+</para>
+
+</sect1>
+
+<sect1 id="taking-snapshot">
+<title>Taking A Snapshot</title>
+
+<para> &ksnapshot; grabs an image of your entire desktop immediately after it is
+started, but before it displays itself on screen. This allows you to quickly
+create full-desktop screenshot images.</para>
+
+<para>The snapshot taken by &ksnapshot; is displayed in the preview window,
+which is located in the upper left of the &ksnapshot; application window.
+Below is an example of the preview window from &ksnapshot;. Your preview
+will differ depending on what you have displayed on the desktop.</para>
+
+<mediaobject>
+<imageobject>
+<imagedata fileref="preview.png" format="PNG"/>
+</imageobject>
+<textobject><phrase>&ksnapshot; Preview Window</phrase>
+</textobject>
+</mediaobject>
+
+<para>The snapshot can be saved by clicking on
+the <guibutton>Save As...</guibutton> button. This opens the standard &kde; save dialog,
+where you can choose the filename, the folder location, and the format that your snapshot
+will be saved in. If multiple snapshots are taken, the
+filename is automatically incremented to prevent you from overwriting previous
+snapshots. You may however edit the filename to anything you wish, including the name
+of a previously saved snapshot. </para>
+
+<para>To take a snapshot of a single window, select the <guilabel>Window
+Under Cursor</guilabel> combo box entry (next to the <guilabel>Capture mode:</guilabel>
+label), and then click on the <guibutton>New Snapshot</guibutton> button.</para>
+
+<para>Depending on your <guilabel>Snapshot delay:</guilabel> settings you
+get either a cross as the mouse pointer (for <guilabel>No delay</guilabel>),
+or a standard mouse cursor which you can use to work with a program until
+the delay is over and a snapshot is taken.</para>
+
+<para>With <guilabel>No delay</guilabel>, the snapshot is taken immediately when you
+click into a window.</para>
+
+<para>&ksnapshot; will display the new snapshot in the preview
+area, at which time you can choose to save the new image (by pressing
+<guibutton>Save As...</guibutton>)
+or to grab a new one, by pressing the
+<guibutton>New Snapshot</guibutton> button.</para>
+
+<para>To take a new snapshot of the entire desktop, select the
+<guilabel>Full Screen</guilabel> combo box entry and then click on the
+<guibutton>New Snapshot</guibutton> button.
+&ksnapshot; will now capture the entire desktop if you press
+<guibutton>New Snapshot</guibutton>.</para>
+
+<para>Similarly, to take a snapshot of a region, select the
+<guilabel>Region</guilabel> combo box entry and set the
+<guilabel>Snapshot delay</guilabel> to <guilabel>No delay</guilabel>,
+and then click on the <guibutton>New Snapshot</guibutton> button. The
+mouse cursor will then change into a cross, and you can then use the
+mouse to select the region you want to capture. </para>
+
+<para>To take a new snapshot of a section of a window, select the
+<guilabel>Section of Window</guilabel> combo box entry and then click on the
+<guibutton>New Snapshot</guibutton> button. With <guilabel>No delay</guilabel>
+you get a cross as the mouse pointer and you have to click once with the &LMB; into
+the window. The section of the window under the mouse cursor is now highlighted
+with a red border. Move the mouse to the wanted section and click the &LMB;
+to capture the screenshot.
+</para>
+
+</sect1>
+
+<sect1 id="additional-features">
+<title>Additional Features</title>
+
+<sect2 id="delay">
+<title>Snapshot Delay</title>
+
+<para>The <guilabel>Snapshot Delay:</guilabel> box allows you to enter an
+arbitrary time delay, in seconds, between the time that you press the
+<guibutton>New Snapshot</guibutton> button and the time that the snapshot is
+taken.</para>
+
+<para>When a delay time has been set, you do not have to click the mouse
+button to capture a screenshot. This enables you to open a drop down menu,
+and take a picture of it.</para>
+
+</sect2>
+
+<sect2 id="window-decoration">
+<title>Exclude Window decorations</title>
+
+<para><guilabel>Include window decorations</guilabel> is enabled by default.</para>
+
+<para>When you only want to capture the application itself without the surrounding
+window decoration, disable this option and take a new snapshot.</para>
+
+</sect2>
+
+<sect2 id="print-snapshot">
+<title>Print</title>
+
+<para>When you want to print your snapshot from the preview, just click
+<guibutton>Print...</guibutton> and you get the standard &kde; Print dialog, from
+where you can directly print your snapshot.</para>
+</sect2>
+
+<sect2 id="copy-snapshot">
+<title>Copy to Clipboard</title>
+
+<para>When you want to edit your snapshot in a graphics application without saving
+the snapshot, just click <guibutton>Copy to Clipboard</guibutton> and insert the image
+into a viewer or graphics application.</para>
+</sect2>
+
+
+<sect2 id="bottom-buttons">
+<title>Buttons</title>
+
+<para>There are two further buttons located at the bottom of the
+&ksnapshot; window. There function is described below.</para>
+
+<variablelist>
+<varlistentry>
+<term><guibutton>Help</guibutton></term>
+<listitem><para>Gives you a menu where you can open the
+<guimenuitem>&ksnapshot; Handbook</guimenuitem>, report a bug or
+get some more information <guimenuitem>About &ksnapshot;</guimenuitem>
+and <guimenuitem>About &kde;</guimenuitem>.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guibutton>Quit</guibutton></term>
+<listitem><para>Quits the &ksnapshot; application.</para></listitem>
+</varlistentry>
+</variablelist>
+
+</sect2>
+</sect1>
+</chapter>
+
+<chapter id="dcop">
+
+<title>&DCOP; Interface</title>
+
+<para>&ksnapshot; can be scripted using its &DCOP; interface. This
+chapter explains the various &DCOP; calls that you can use, and
+provides some examples of how you can use them.</para>
+
+<para>As with all &DCOP; calls, you need to specify the application
+you want to interface with, and the particular interface. With &ksnapshot;
+you need to identify which particular application, which is
+<literal>ksnapshot-</literal> followed by the process number.</para>
+
+<para>To start &ksnapshot; and obtain the right argument, use
+<command>dcopstart ksnapshot</command>, which returns the
+argument (such as <computeroutput>ksnapshot-20594</computeroutput>) on
+standard output.</para>
+
+<para>You can get a list of the available &DCOP; interfaces, use
+the right arguments, as shown in this example:
+<screen width="60">
+<prompt>$</prompt> <command>dcop `dcopstart ksnapshot` interface</command><computeroutput>
+QCStringList interfaces()
+QCStringList functions()
+QString url()
+void slotGrab()
+void slotPrint()
+void slotSave()
+bool save(QString filename)
+void slotSaveAs()
+void slotCopy()
+void setTime(int newTime)
+int timeout()
+void setURL(QString newURL)
+void setGrabMode(int grab)
+int grabMode()
+void slotMovePointer(int x,int y)
+void exit()
+</computeroutput>
+</screen>
+</para>
+
+<para>
+In the examples following, the process is always
+<computeroutput>ksnapshot-23151</computeroutput>.
+</para>
+
+<sect1 id="dcop-settings">
+
+<title>&DCOP; Access to Settings</title>
+
+<para>For each of the settings that you can control with the
+&GUI;, you can both obtain the current status of that setting,
+and modify the setting, using &DCOP;.
+</para>
+
+<para>You can obtain the current capture mode using
+<literal>grabMode</literal>, as shown below:
+<screen width="60">
+<prompt>$</prompt> <command>dcop ksnapshot-23151 interface grabMode</command>
+</screen>
+This will return <computeroutput>0</computeroutput> for full-screen capture,
+<computeroutput>1</computeroutput> for window capture, and <computeroutput>2</computeroutput>
+for region capture.
+</para>
+
+<para>You can set the capture mode using <literal>setGrabMode</literal>,
+which requires an argument to identify the mode required (as for <literal>grabMode</literal>).
+So you can set window capture mode (<command>1</command>), using:
+<screen width="60">
+<prompt>$</prompt> <command>dcop ksnapshot-23151 interface setGrabMode 1</command>
+</screen>
+</para>
+
+<para>You can obtain the current timeout setting (the <guilabel>Snapshot delay:</guilabel>
+GUI item) using <literal>timeout</literal>, as shown below:
+<screen width="60">
+<prompt>$</prompt> <command>dcop ksnapshot-23151 interface timeout</command>
+</screen>
+This will return the timeout setting in seconds, or zero if there is no delay
+(capture on click).
+</para>
+
+<para>You can set the timeout using <literal>setTime</literal>,
+which requires an argument to identify the timeout duration. So you can
+set a delay of 4 seconds using:
+<screen width="60">
+<prompt>$</prompt> <command>dcop ksnapshot-23151 interface setTime 4</command>
+</screen>
+</para>
+
+<para>You can obtain the path that the snapshot will be saved to using
+<literal>url</literal>, as shown below:
+<screen width="60">
+<prompt>$</prompt><command>dcop ksnapshot-23151 interface url</command>
+</screen>
+This will return the filename, as a &URL; (eg as
+<computeroutput>file:///home/bradh/test2.png</computeroutput>).
+</para>
+
+<para>You can set the path using <literal>setURL</literal>,
+which requires a string argument to identify the new path. So you can
+set the path to <literal>file:///home/bradh/snapshot.jpg</literal>
+using:
+<screen width="60">
+<prompt>$</prompt> <command>dcop ksnapshot-23151 interface setURL file:///home/bradh/snapshot.jpg</command>
+</screen>
+</para>
+
+</sect1>
+
+<sect1 id="dcop-snapshot">
+<title>Taking Screenshots with &DCOP;</title>
+
+<para>
+The key to taking screenshots with &DCOP; is use of <literal>slotGrab</literal>,
+as shown below:
+<screen width="60">
+<prompt>$</prompt> <command>dcop ksnapshot-23151 interface slotGrab</command>
+</screen>
+</para>
+
+<para>
+This will take a snapshot using the current snapshot mode and timeout settings
+(as described above). If you want to save the snapshot image, there are a
+number of calls you can use. If you just want to save the image to the current
+path (as returned by <literal>url</literal> or changed by
+<literal>setURL</literal>), you can use <literal>slotSave</literal>, as shown
+below:
+<screen width="60">
+<prompt>$</prompt> <command>dcop ksnapshot-23151 interface slotSave</command>
+</screen>
+</para>
+
+<para>
+If you want the user to be able to specify a filename (and path), you can use
+<literal>slotSaveAs</literal>, which will bring up a standard &kde; file
+save dialog.</para>
+
+<para>
+If you want to save the image to a different name (or path) without
+changing the path with <literal>setURL</literal>, you can use
+<literal>save</literal>, providing the &URL; to save to as an argument. So if you
+want to save the snapshot to <filename>file:///tmp/tempshot.png</filename>, you
+can do the following:
+<screen width="60">
+<prompt>$</prompt> <command>dcop ksnapshot-23151 interface save file:///tmp/tempshot.png</command>
+</screen>
+Note that this will return true if the snapshot was successfully saved, and false
+otherwise. Also, you should be aware that if the file already exists, the user
+will get a standard &kde; dialog that requires the user to decide whether to overwrite
+or not.
+</para>
+
+<para>
+In addition to saving the snapshot, you can also copy it to the clipboard, using
+<literal>slotCopy</literal>, as shown below:
+<screen width="60">
+<prompt>$</prompt> <command>dcop ksnapshot-23151 interface slotCopy</command>
+</screen>
+</para>
+
+<para>
+If you need to select a window that may not be under the mouse cursor, you
+can use <literal>slotMovePointer</literal>, passing the x position
+(in screen pixels) and the y position (also in screen pixels) as arguments.
+So to move the mouse to the top left hand corner of the screen (0,0), you
+can do the following:
+<screen width="60">
+<prompt>$</prompt> <command>dcop ksnapshot-23151 interface slotMoveMouse 0 0</command>
+</screen>
+</para>
+</sect1>
+
+<sect1 id="dcop-print">
+<title>Printing Screenshots with &DCOP;</title>
+
+<para>
+You can print the current screenshot (which may or may not have been saved)
+using <literal>printSlot</literal>, as shown below:
+<screen width="60">
+<prompt>$</prompt> <command>dcop ksnapshot-23151 interface slotPrint</command>
+</screen>
+</para>
+
+<para>
+Note that this will bring up the normal &kde; print dialog, which may require
+user interaction.
+</para>
+
+</sect1>
+
+<sect1 id="dcop-exit">
+<title>&DCOP; Application control</title>
+
+<para>
+You can cause &ksnapshot; to exit by using <literal>exit</literal>,
+as shown below.
+<screen width="60">
+<prompt>$</prompt> <command>dcop ksnapshot-23151 interface exit</command>
+</screen>
+</para>
+
+</sect1>
+
+</chapter>
+
+<chapter id="credits">
+
+<title>Credits and License</title>
+
+<para>Program copyright</para>
+<itemizedlist>
+<listitem><para>1997-2000 &Richard.J.Moore; &Richard.J.Moore.mail;</para></listitem>
+<listitem><para>2000 &Matthias.Ettrich; &Matthias.Ettrich.mail;</para></listitem>
+</itemizedlist>
+
+<para>Documentation based on the original, copyright 1997-2000 &Richard.J.Moore;
+&Richard.J.Moore.mail;</para>
+<!-- TRANS:CREDIT_FOR_TRANSLATORS -->
+
+&underFDL;
+&underGPL;
+
+</chapter>
+
+&documentation.index;
+</book>
+
+<!--
+Local Variables:
+sgml-minimize-attributes: nil
+sgml-general-insert-case: lower
+End:
+-->
+
+
+
+
diff --git a/doc/ksnapshot/preview.png b/doc/ksnapshot/preview.png
new file mode 100644
index 00000000..0ee37a41
--- /dev/null
+++ b/doc/ksnapshot/preview.png
Binary files differ
diff --git a/doc/ksnapshot/window.png b/doc/ksnapshot/window.png
new file mode 100644
index 00000000..c4e99de7
--- /dev/null
+++ b/doc/ksnapshot/window.png
Binary files differ
diff --git a/doc/kuickshow/Makefile.am b/doc/kuickshow/Makefile.am
new file mode 100644
index 00000000..085981d9
--- /dev/null
+++ b/doc/kuickshow/Makefile.am
@@ -0,0 +1,4 @@
+
+KDE_LANG = en
+KDE_DOCS = AUTO
+
diff --git a/doc/kuickshow/index.docbook b/doc/kuickshow/index.docbook
new file mode 100644
index 00000000..e454e2bf
--- /dev/null
+++ b/doc/kuickshow/index.docbook
@@ -0,0 +1,1041 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+ <!ENTITY kappname "&kuickshow;">
+ <!ENTITY package "kdegraphics">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE"><!-- change language only here -->
+]>
+
+<!-- The language must NOT be changed here. -->
+<book lang="&language;">
+
+<bookinfo>
+<title>The &kuickshow; Handbook</title>
+
+<authorgroup>
+<author>
+<firstname>Carsten</firstname>
+<surname>Pfeiffer</surname>
+<affiliation>
+<address>&Carsten.Pfeiffer.mail;</address>
+</affiliation>
+</author>
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+</authorgroup>
+
+<copyright>
+<year>2001</year>
+<holder>&Carsten.Pfeiffer;</holder>
+</copyright>
+
+<legalnotice>&FDLNotice;</legalnotice>
+
+<date>2005-12-29</date>
+<releaseinfo>0.8.7</releaseinfo>
+
+<!-- Abstract about this handbook -->
+
+<abstract>
+<para>
+&kuickshow; is a comfortable image browser/viewer.
+</para>
+</abstract>
+
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>kdegraphics</keyword>
+<keyword>kuickshow</keyword>
+<keyword>image</keyword>
+<keyword>viewer</keyword>
+</keywordset>
+
+</bookinfo>
+
+<chapter id="introduction">
+<title>Introduction</title>
+
+<para>
+&kuickshow; is a comfortable image browser/viewer. It displays a
+filebrowser where you can select images which are then shown.
+</para>
+
+<!-- LW: put a nice screenshot here -->
+
+<para>The following image formats are supported:</para>
+<itemizedlist>
+<listitem><para>jpg</para>
+</listitem>
+<listitem><para>gif</para>
+</listitem>
+<listitem><para>tiff</para>
+</listitem>
+<listitem><para>png</para>
+</listitem>
+<listitem><para>bmp</para>
+</listitem>
+<listitem><para>psd</para>
+</listitem>
+<listitem><para>xpm</para>
+</listitem>
+<listitem><para>ppm</para>
+</listitem>
+<listitem><para>pgm</para>
+</listitem>
+<listitem><para>pbm</para>
+</listitem>
+<listitem><para>pnm</para>
+</listitem>
+<listitem><para>eim</para>
+</listitem>
+<listitem><para>xcf</para>
+</listitem>
+</itemizedlist>
+
+<para>Images can be displayed either in their own window, as large as
+the image, or fullscreen.</para>
+
+</chapter>
+
+<chapter id="using-kuickshow">
+<title>Using &kuickshow;</title>
+
+<para>Using &kuickshow; is very simple. The file browser lists files,
+which you can select with a &LMB; click or the <keycap>Return</keycap>
+key.</para>
+
+<screenshot>
+<screeninfo>Here's a screenshot of &kuickshow;</screeninfo>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="screenshot.png" format="PNG"/>
+ </imageobject>
+ <imageobject>
+ <imagedata fileref="screenshot.eps" format="EPS"/>
+ </imageobject>
+ <textobject>
+ <phrase>Screenshot</phrase>
+ </textobject>
+ </mediaobject>
+</screenshot>
+
+
+<sect1 id="kuickshow-features">
+<title>More &kuickshow; features</title>
+
+<para>The options dialog makes available more possibilities:</para>
+
+<itemizedlist>
+<listitem><para>Images can be automatically shrunk to fit onto the
+screen, if they are larger.</para>
+</listitem>
+<listitem><para>You can configure whether images should show up in
+their own window, or always use the same window.</para>
+</listitem>
+<listitem><para>You can set the delay time for a slide show.</para>
+</listitem>
+<listitem><para>You can tell the browser which file types to show.</para>
+</listitem>
+<listitem><para>You can tweak the speed/quality
+ratio</para></listitem>
+</itemizedlist>
+
+<para>If you are looking for a certain file, just enter the first few
+characters of it's filename in the browser. A small edit window will
+pop up in the bottom right corner. When a matching file is found, it
+is highlighted. You can leave the edit window by pressing
+<keycap>Return</keycap> or &Esc;.</para>
+
+</sect1>
+</chapter>
+
+<chapter id="configuration-dialog">
+<title>The <guilabel>&kuickshow; Configuration</guilabel>
+Dialog</title>
+
+<para>The <guilabel>&kuickshow; Configuration</guilabel> dialog
+contains 5 tabs. Three of them, <link
+linkend="general-options"><guilabel>General</guilabel></link>, <link
+linkend="modifications-options"><guilabel>Modifications</guilabel></link>
+and <link linkend="slideshow-options"><guilabel>Slideshow</guilabel></link>
+configure the operation of &kuickshow;, and the other two,
+<link linkend="shortcuts-options"><guilabel>Viewer Shortcuts</guilabel></link>
+and <link linkend="shortcuts-options"><guilabel>Browser Shortcuts</guilabel></link>
+allow you to personalize the shortcuts for the
+respective windows.</para>
+
+<sect1 id="general-options">
+<title><guilabel>General</guilabel> Options</title>
+
+<para>The <guilabel>General</guilabel> contains the options to
+configure and tune &kuickshow;.</para>
+
+<variablelist>
+<varlistentry>
+<term><guilabel>Fullscreen mode</guilabel></term>
+<listitem>
+<para>If this is selected, images open in full screen mode. If the
+image is not large enough to fill the screen, the rest of the screen
+is filled with the background color selected below. The default is
+off.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Preload next image</guilabel></term>
+<listitem>
+<para>If this is selected, &kuickshow; will load the next image in the
+folder, while you are looking at the current one. This reduces the
+delay when you select the next image, and is especially useful for
+slide shows.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Remember last folder</guilabel></term>
+<listitem>
+<para>If this is selected, &kuickshow; saves the name of the last folder on exit.
+On next start &kuickshow; will open this folder in the browser window.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Background color:</guilabel></term>
+<listitem>
+<para>Click on the colored bar to select a background color. This is
+used to fill the screen in fullscreen mode, or the window, if you have
+resized it larger than the image.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Show only files with extension:</guilabel></term>
+<listitem>
+<para>You can configure &kuickshow; to only show you some of the file
+types it is capable of.</para>
+</listitem>
+</varlistentry>
+
+</variablelist>
+
+<variablelist>
+<title><guilabel>Quality/Speed</guilabel></title>
+<varlistentry>
+<term><guilabel>Fast rendering</guilabel></term>
+<listitem><para><!-- LW: Uhm.. help? -->Render things fast.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Dither in HiColor (15/16bit) modes</guilabel></term>
+<listitem><para><!-- LW: Maybe these should be on an advanced tab -->
+<!-- Write an example what this does here -->
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Dither in LowColor (&lt;=8bit) modes</guilabel></term>
+<listitem><para><!-- And here -->
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Use own color palette</guilabel></term>
+<listitem><para><!-- and this one -->
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Fast palette remapping</guilabel></term>
+<listitem>
+<para><!-- and this one -->
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Maximum cache size (MB):</guilabel></term>
+<listitem>
+<para><!-- and another -->
+</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect1>
+
+<sect1 id="modifications-options">
+<title>The <guilabel>Modifications</guilabel> Tab</title>
+
+<para>Check <guilabel>Apply default image modifications</guilabel> to open an image
+with these modifications in &kuickshow;.</para>
+
+<variablelist>
+<title><guilabel>Scaling</guilabel></title>
+<varlistentry>
+<term><guilabel>Shrink image to screen size, if larger</guilabel></term>
+<listitem>
+<para>If this is selected, large images are displayed in maximized window. The default is
+on.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Shrink image to screen size, if smaler, up to factor:</guilabel></term>
+<listitem>
+<para>If this is selected, &kuickshow; increases the magnification of small images up to
+the selected factor.</para>
+</listitem>
+</varlistentry>
+
+</variablelist>
+
+<variablelist>
+<title><guilabel>Geometry</guilabel></title>
+<varlistentry>
+<term><guilabel>Flip vertically</guilabel></term>
+<listitem><para>Flips the image vertically.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Flip horizontally</guilabel></term>
+<listitem><para>Flips the image horizontally.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Rotate image</guilabel></term>
+<listitem><para>Rotates the image to 0, 90, 180 or 270 degrees.
+</para>
+</listitem>
+</varlistentry>
+
+</variablelist>
+
+<variablelist>
+<title><guilabel>Adjustments</guilabel></title>
+<varlistentry>
+<term><guilabel>Brightness:</guilabel></term>
+<listitem><para>Lightens/darkens the image.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Contrast:</guilabel></term>
+<listitem><para>Adds/Removes contrast.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Gamma:</guilabel></term>
+<listitem><para>More/less gamma.
+</para>
+</listitem>
+</varlistentry>
+
+</variablelist>
+
+<para>A <guilabel>Preview</guilabel> of the <guilabel>Original</guilabel>
+and <guilabel>Modified</guilabel> image is displayed below this options.</para>
+
+</sect1>
+
+<sect1 id="slideshow-options">
+<title>The <guilabel>Slideshow</guilabel> Tab</title>
+
+<variablelist>
+
+<varlistentry>
+<term><guilabel>Switch to full-screen</guilabel></term>
+<listitem>
+<para>Indicates if &kuickshow; should switch to full-screen mode
+when starting the slideshow.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Start with current image</guilabel></term>
+<listitem>
+<para>Indicates if the slideshow should start with the first
+image in the folder or with the image which is selected.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Delay between slides:</guilabel></term>
+<listitem>
+<para>The length of time between image changes during the slideshow.
+You can use the slider, type a new value into the field,
+or use the small arrows to increase or decrease the value. The
+default is 3 seconds.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Iterations (0 = infinite):</guilabel></term>
+<listitem>
+<para>The amount of iterations. If set to 0 it will loop untill you
+abort the slideshow. You can use the slider, type a new value into the
+field, or use the small arrows to increase or decrease the value. The
+default is 1.</para>
+</listitem>
+</varlistentry>
+
+</variablelist>
+</sect1>
+
+<sect1 id="shortcuts-options">
+<title>The <guimenu>Shortcuts</guimenu> Tabs</title>
+<para>Change the shortcuts for the different modes of &kuickshow;
+in the <guilabel>Viewer Shortcuts</guilabel> and the <guilabel>Browser Shortcuts</guilabel> tabs.</para>
+</sect1>
+
+</chapter>
+
+<chapter id="menus">
+<title>Menu Reference</title>
+
+<sect1 id="file-menu">
+<title>The <guimenu>File</guimenu> Menu</title>
+
+<variablelist>
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>O</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Open</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Opens a new image</action> in &kuickshow;.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Show Image</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Displays </action> the selected image in a new image
+window.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Show Image in Aktive Window</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Displays </action>the selected image in the active image
+window.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Show Image in Fullscreen Mode</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Displays</action> the selected image in fullscreen mode.
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycap>F2</keycap></shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Start Slideshow</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Starts</action> a slideshow of the images in the folder.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo action="simul">&Ctrl;
+<keycap>P</keycap></keycombo></shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Print Image...</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Prints the image</action>.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">
+&Ctrl;<keycap>Q</keycap></keycombo></shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Quit</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Quits</action> &kuickshow;. If you have several
+images windows open, all of them are closed.</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect1>
+
+<sect1 id="edit-menu">
+<title>The <guimenu>Edit</guimenu> Menu</title>
+
+<variablelist>
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycap>F10</keycap></shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>New Folder...</guimenuitem></menuchoice>
+</term>
+<listitem>
+<para><action>Create</action> a new folder.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">
+<keycap>&Shift;</keycap><keycap>Delete</keycap></keycombo></shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Delete</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Deletes</action> the current file. You will be asked to confirm the
+action.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo action="simul">
+<keycap>&Alt;</keycap><keycap>Return</keycap></keycombo></shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Properties</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Displays</action> the properties of the current image file.</para></listitem>
+</varlistentry>
+</variablelist>
+
+</sect1>
+
+<sect1 id="view-menu">
+<title>The <guimenu>View</guimenu> Menu</title>
+
+<variablelist>
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycap>F6</keycap></shortcut>
+<guimenu>View</guimenu>
+<guimenuitem>Short View</guimenuitem>
+</menuchoice></term>
+<listitem><para>If this option is selected, only the names of the files and folders will be shown.</para>
+<para>Compare this to detailed view.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycap>F7</keycap></shortcut>
+<guimenu>View</guimenu>
+<guimenuitem>Detailed View</guimenuitem>
+</menuchoice></term>
+<listitem><para>If this option is selected, the names, sizes, dates, permissions, file owners and group ownerships are shown.</para>
+<para>Compare this to short view.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycap>F8</keycap></shortcut>
+<guimenu>View</guimenu>
+<guimenuitem>Show Hidden Files</guimenuitem>
+</menuchoice></term>
+<listitem><para>This will toggle between revealing and hiding normally hidden files.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycap>F12</keycap></shortcut>
+<guimenu>View</guimenu>
+<guimenuitem>Separate Folders</guimenuitem>
+</menuchoice></term>
+<listitem><para>Use this option to toggle between a 2 pane view of the file system (one pane for the folders
+and one pane for the files) and a one pane view of the file system with folders and files.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>View</guimenu>
+<guimenuitem>Large Icons</guimenuitem>
+</menuchoice></term>
+<listitem><para>Display the image files in the folder with large icons.
+This item is only available in <guimenuitem>Short View</guimenuitem> mode.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>View</guimenu>
+<guimenuitem>Small Icons</guimenuitem>
+</menuchoice></term>
+<listitem><para>Display the image files in the folder with small icons.
+This item is only available in <guimenuitem>Short View</guimenuitem> mode.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>View</guimenu>
+<guimenuitem>Thumbnail Previews</guimenuitem>
+</menuchoice></term>
+<listitem><para>Display a preview of the images in the folder. This item is only available in <guimenuitem>Short View</guimenuitem> mode.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">
+&Ctrl;<keycap>-</keycap></keycombo></shortcut>
+<guimenu>View</guimenu>
+<guimenuitem>Zoom Out</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Reduces the image size by ten percent</action>. Again
+this refers to the <emphasis>current</emphasis> size of the
+image.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">
+&Ctrl;<keycap>+</keycap></keycombo></shortcut>
+<guimenu>View</guimenu>
+<guimenuitem>Zoom In</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Enlarges the image by ten percent</action>. Notice that
+this refers to the <emphasis>current</emphasis> size of the
+picture.</para></listitem>
+</varlistentry>
+</variablelist>
+
+</sect1>
+
+<sect1 id="settings-menu">
+<title>The <guimenu>Settings</guimenu> Menu</title>
+
+<variablelist>
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Configure &kuickshow;...</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Opens a dialog for changing some options</action> as
+described in the section <xref linkend="configuration-dialog"/></para>
+</listitem>
+</varlistentry>
+</variablelist>
+</sect1>
+
+
+<sect1 id="help-menu">
+<title>The <guimenu>Help</guimenu> Menu</title>
+
+<variablelist>
+<varlistentry>
+<term>
+<menuchoice>
+<shortcut>
+<keycombo action="simul"><keycap>F1</keycap></keycombo>
+</shortcut>
+<guimenu>Help</guimenu>
+<guimenuitem>&kappname; Handbook</guimenuitem>
+</menuchoice>
+</term>
+<listitem><para><action>Invokes the &kde; Help system</action> starting at the
+&kappname; help pages. (this document).</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Help</guimenu>
+<guimenuitem>Report Bug...</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Opens the Bug report dialog</action> where you can
+report a bug or request a <quote>wishlist</quote> feature.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Help</guimenu>
+<guimenuitem>About &kappname;</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>This will display version and author
+information.</action></para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Help</guimenu>
+<guimenuitem>About KDE</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>This displays the &kde; version and other basic
+information.</action></para></listitem>
+</varlistentry>
+</variablelist>
+
+</sect1>
+
+</chapter>
+
+<chapter id="commands">
+<title>Command Reference</title>
+
+<sect1 id="keybindings">
+<title>The Image Window</title>
+
+<para>All the shortcuts are configurable from the <link
+linkend="configuration-dialog">Configuration Dialog</link>.</para>
+
+<table>
+<title>Image Window Keyboard Shortcuts</title>
+<tgroup cols="2">
+<thead>
+<row>
+<entry>Key</entry>
+<entry>Action</entry>
+</row>
+</thead>
+<tbody>
+<row>
+<entry><keycap>Page Down</keycap></entry>
+<entry>Load the next image</entry>
+</row>
+<row>
+<entry><keycap>Page Up</keycap></entry>
+<entry>Load the previous image</entry>
+</row>
+<row>
+<entry><keycap>Home</keycap></entry>
+<entry>Loads the first image</entry>
+</row>
+<row>
+<entry><keycap>End</keycap></entry>
+<entry>Loads the last image</entry>
+</row>
+<row>
+<entry><keycap>+</keycap></entry>
+<entry>Zooms into the image</entry>
+</row>
+<row>
+<entry><keycap>-</keycap></entry>
+<entry>Zooms out of the image</entry>
+</row>
+<row>
+<entry><keycap>*</keycap></entry>
+<entry>Flips the image horizontally</entry>
+</row>
+<row>
+<entry><keycap>/</keycap></entry>
+<entry>Flips the image vertically</entry>
+</row>
+<row>
+<entry><keycap>7</keycap></entry>
+<entry>Rotates 270&deg; clockwise (which is also 90&deg;
+counter-clockwise)</entry>
+</row>
+<row>
+<entry><keycap>8</keycap></entry>
+<entry>Rotates 90&deg; clockwise</entry>
+</row>
+<row>
+<entry><keycap>9</keycap></entry>
+<entry>Rotates 180&deg; clockwise</entry>
+</row>
+<row>
+<entry><keycap>Arrow</keycap> keys</entry>
+<entry>Move the image (or rather, you, the viewer,) if it is larger
+than the screen</entry>
+</row>
+<row>
+<entry><keycap>Return</keycap></entry>
+<entry>Toggles between fullscreen and window mode</entry>
+</row>
+<row>
+<entry><keycap>Space</keycap></entry>
+<entry>Toggles the display of the browser</entry>
+</row>
+<row>
+<entry>&Esc;</entry>
+<entry>Closes the image window. This will close &kuickshow; entirely,
+if you don't have a browser window open.</entry>
+</row>
+<row>
+<entry><keycap>B</keycap>/<keycombo action="simul">&Shift;<keycap>B</keycap></keycombo></entry>
+<entry>Lightens/darkens the image</entry>
+</row>
+<row>
+<entry><keycap>C</keycap>/<keycombo action="simul">&Shift;<keycap>C</keycap></keycombo></entry>
+<entry>Adds/Removes contrast</entry>
+</row>
+<row>
+<entry><keycap>G</keycap>/<keycombo action="simul">&Shift;<keycap>G</keycap></keycombo></entry>
+<entry>More/less <firstterm>gamma</firstterm></entry>
+</row>
+<row>
+<entry><keycap>O</keycap></entry>
+<entry>Shows the image in original size. This is only useful when you
+have enabled automatic scaling.</entry>
+</row>
+<row>
+<entry><keycap>Enter</keycap></entry>
+<entry>Redisplays the image with the default settings and
+size.</entry>
+</row>
+<row>
+<entry><keycombo action="simul">&Ctrl;<keycap>S</keycap></keycombo></entry>
+<entry>Opens the <guilabel>Save As</guilabel> dialog</entry>
+</row>
+<row>
+<entry><keycap>Delete</keycap></entry>
+<entry>Deletes the current image. You will be asked to confirm the
+request.</entry>
+</row>
+<row>
+<entry><keycombo action="simul">&Shift;<keycap>Delete</keycap></keycombo></entry>
+<entry>Deletes the current image without asking for
+confirmation</entry>
+</row>
+<row>
+<entry><keycombo action="simul">&Alt;<keycap>Return</keycap></keycombo></entry>
+<entry>Displays the properties of the image</entry>
+</row>
+<row>
+<entry><keycap>F1</keycap></entry>
+<entry>Opens the online help (this file)</entry>
+</row>
+<row>
+<entry><keycombo action="simul">&Ctrl;<keycap>W</keycap></keycombo></entry>
+<entry>Quits &kuickshow;</entry>
+</row>
+</tbody>
+</tgroup>
+</table>
+
+<table>
+<title>Image Window Mouse Usage</title>
+<tgroup cols="2">
+<thead>
+<row>
+<entry>Mouse button</entry>
+<entry>Action</entry>
+</row>
+</thead>
+<tbody>
+<row>
+<entry><mousebutton>Right</mousebutton> click</entry>
+<entry>Opens the context menu, with several options</entry>
+</row>
+<row>
+<entry><mousebutton>Left</mousebutton> drag</entry>
+<entry>Moves the image, if it doesn't fit in the window.</entry>
+</row>
+<row>
+<entry><keycombo action="simul">&Shift;<mousebutton>Left</mousebutton>
+</keycombo> drag</entry>
+<entry>Marks a rectangle you can zoom into.</entry>
+</row>
+<row>
+<entry><mousebutton>Left</mousebutton> double click</entry>
+<entry>Closes the current image</entry>
+</row>
+</tbody>
+</tgroup>
+</table>
+
+</sect1>
+
+<sect1 id="browser-window">
+<title>The Browser Window</title>
+
+<table>
+<title>Browser Window Keybindings</title>
+<tgroup cols="2">
+<thead>
+<row>
+<entry>Keybinding</entry>
+<entry>Action</entry>
+</row>
+</thead>
+<tbody>
+<row>
+<entry><keycap>Return</keycap></entry>
+<entry>Enters a folder, or opens an image window, depending on the
+item selected.</entry>
+</row>
+<row>
+<entry><keycap>Page Down</keycap></entry>
+<entry>Advances one page in the list of files</entry>
+</row>
+<row>
+<entry><keycap>Page Up</keycap></entry>
+<entry>Moves back up a page in the list of files</entry>
+</row>
+<row>
+<entry><keycap>Home</keycap></entry>
+<entry>Selects the first file or folder</entry>
+</row>
+<row>
+<entry><keycap>End</keycap></entry>
+<entry>Selects the last file or folder</entry>
+</row>
+<row>
+<entry><keycap>Space</keycap></entry>
+<entry>Toggles showing the browser, if an image window is open</entry>
+</row>
+<row>
+<entry><keycap>any alpha-numeric character</keycap></entry>
+<entry>Opens the edit field used for <quote>completion</quote>. Enter
+the first characters of a filename to search for, and if found, the
+file will be selected.</entry>
+</row>
+<row>
+<entry><keycombo
+action="simul">&Ctrl;<keycap>G</keycap></keycombo></entry>
+<entry><quote>Go to</quote> &mdash; lets you enter a folder to go
+to.</entry>
+</row>
+<row>
+<entry><keycap>Delete</keycap></entry>
+<entry>Deletes the current file. You will be asked to confirm the
+action.</entry>
+</row>
+<row>
+<entry><keycombo
+action="simul">&Shift;<keycap>Delete</keycap></keycombo></entry>
+<entry>Deletes the current file without asking for
+confirmation.</entry>
+</row>
+<row>
+<entry><keycap>F1</keycap></entry>
+<entry>Opens the online help (this file)</entry>
+</row>
+<row>
+<entry><keycombo
+action="simul">&Ctrl;<keycap>Q</keycap></keycombo></entry>
+<entry>Quits &kuickshow;</entry>
+</row>
+</tbody>
+</tgroup>
+</table>
+
+<table>
+<title>Browser Window Mouse Usage</title>
+<tgroup cols="2">
+<thead>
+<row>
+<entry>Mouse Usage</entry>
+<entry>Action</entry>
+</row>
+</thead>
+<tbody>
+<row>
+<entry><mousebutton>Left</mousebutton> click</entry>
+<entry>Enter a folder, or select an image window.</entry>
+</row>
+<row>
+<entry><mousebutton>Right</mousebutton> click</entry>
+<entry>Opens a context menu, with several options.</entry>
+</row>
+<row>
+<entry>Double click</entry>
+<entry>Loads the selected image or enters the selected
+folder</entry>
+</row>
+</tbody>
+</tgroup>
+
+</table>
+
+</sect1>
+</chapter>
+
+<chapter id="credits">
+
+<!-- Include credits for the programmers, documentation writers, and
+contributors here. The license for your software should then be included below
+the credits with a reference to the appropriate license file included in the KDE
+distribution. -->
+
+<title>Credits and License</title>
+
+<para>
+&kuickshow;
+</para>
+<para>
+Program copyright 1998-2002 &Carsten.Pfeiffer; &Carsten.Pfeiffer.mail;
+</para>
+
+<para>
+Documentation copyright 2001 &Carsten.Pfeiffer; &Carsten.Pfeiffer.mail;
+</para>
+<para>Converted to DocBook &XML; and extended by &Lauri.Watts;
+&Lauri.Watts.mail;</para>
+
+<!-- TRANS:CREDIT_FOR_TRANSLATORS -->
+
+&underFDL; <!-- FDL: do not remove -->
+
+&underGPL; <!-- GPL License -->
+
+</chapter>
+
+<appendix id="installation">
+<title>Installation</title>
+
+<sect1 id="getting-kuickshow">
+<title>How to obtain &kuickshow;</title>
+
+&install.intro.documentation;
+
+</sect1>
+
+<sect1 id="requirements">
+<title>Requirements</title>
+
+<para>To be written</para>
+<!--
+List any special requirements for your application here. This should include:
+.Libraries or other software that is not included in kdesupport,
+kdelibs, or kdebase.
+.Hardware requirements like amount of RAM, disk space, graphics card
+capabilities, screen resolution, special expansion cards, etc.
+.Operating systems the app will run on. If your app is designed only for a
+specific OS, (you wrote a graphical LILO configurator for example) put this
+information here.
+
+
+<para>
+In order to successfully use &kuickshow;, you need &kde; 1.1. Foobar.lib is
+required in order to support the advanced &kuickshow; features. &kuickshow; uses
+about 5 megs of memory to run, but this may vary depending on your
+platform and configuration.
+</para>
+
+<para>
+All required libraries as well as &kuickshow; itself can be found
+on <ulink url="ftp://ftp.kapp.org">The &kuickshow; home page</ulink>.
+</para>
+-->
+
+<!-- For a list of updates, you may refer to the application web site
+or the ChangeLog file, or ...
+<para>
+You can find a list of changes at <ulink
+url="http://apps.kde.org/kapp">http://apps.kde.org/kapp</ulink>.
+</para>-->
+</sect1>
+
+<sect1 id="compilation">
+<title>Compilation and Installation</title>
+
+&install.compile.documentation;
+
+</sect1>
+
+</appendix>
+
+&documentation.index;
+</book>
+
+<!--
+Local Variables:
+mode: sgml
+sgml-minimize-attributes:nil
+sgml-general-insert-case:lower
+sgml-indent-step:0
+sgml-indent-data:nil
+End:
+-->
+
diff --git a/doc/kuickshow/screenshot.png b/doc/kuickshow/screenshot.png
new file mode 100644
index 00000000..a57bd4c7
--- /dev/null
+++ b/doc/kuickshow/screenshot.png
Binary files differ
diff --git a/doc/kview/Makefile.am b/doc/kview/Makefile.am
new file mode 100644
index 00000000..085981d9
--- /dev/null
+++ b/doc/kview/Makefile.am
@@ -0,0 +1,4 @@
+
+KDE_LANG = en
+KDE_DOCS = AUTO
+
diff --git a/doc/kview/index.docbook b/doc/kview/index.docbook
new file mode 100644
index 00000000..e1ddbbdf
--- /dev/null
+++ b/doc/kview/index.docbook
@@ -0,0 +1,835 @@
+<?xml version="1.0" ?>
+<!DOCTYPE book PUBLIC "-//KDE//DTD DocBook XML V4.2-Based Variant V1.1//EN" "dtd/kdex.dtd" [
+ <!ENTITY kappname "&kview;">
+ <!ENTITY package "kdegraphics">
+ <!ENTITY % addindex "IGNORE">
+ <!ENTITY % English "INCLUDE" > <!-- change language only here -->
+]>
+
+<book lang="&language;">
+
+<bookinfo>
+<title>The &kview; Handbook</title>
+
+<authorgroup>
+<author>
+<firstname>Hauke</firstname>
+<surname>Hildebrandt</surname>
+<affiliation>
+<address>&Hauke.Hildebrandt.mail;</address>
+</affiliation>
+</author>
+
+<othercredit role="developer">
+<firstname>Sirtaj</firstname>
+<othername>Singh</othername>
+<surname>Kang</surname>
+<contrib>Developer</contrib>
+</othercredit>
+
+<othercredit role="reviewer">
+<firstname>Lauri</firstname>
+<surname>Watts</surname>
+<affiliation><address>&Lauri.Watts.mail;</address></affiliation>
+<contrib>Reviewer</contrib>
+</othercredit>
+<!-- TRANS:ROLES_OF_TRANSLATORS -->
+</authorgroup>
+
+
+<copyright>
+<year>2001</year>
+<holder>&Hauke.Hildebrandt;</holder>
+</copyright>
+
+<legalnotice>&FDLNotice;</legalnotice>
+
+<date>2006-05-20</date>
+<releaseinfo>3.5.2</releaseinfo>
+
+<abstract><para>&kview; is an image viewing program. It is small and fast and
+has some simple image processing commands. You can work with many different
+graphic file formats and convert your images to them. &kview; is not a
+fully-fledged image processor but it is sufficient for many of your everyday
+tasks.</para></abstract>
+
+<keywordset>
+<keyword>KDE</keyword>
+<keyword>kview</keyword>
+<keyword>kdegraphics</keyword>
+<keyword>image</keyword>
+<keyword>graphic</keyword>
+<keyword>viewer</keyword>
+</keywordset>
+
+</bookinfo>
+
+<chapter id="introduction">
+<title>Introduction</title>
+
+<para>&kview; is an image viewer for the &kde; desktop. You can view
+graphics of many different formats such as &PostScript;,
+<acronym>TIFF</acronym> &etc; By saving your files in a different
+format than the original you can easily convert images to other
+graphics formats. In addition, &kview; provides some nice little
+features for doing simple image processing, like stretching/shrinking,
+rotation and applying effects. You can arrange your images in a little
+slideshow.</para>
+
+</chapter>
+
+<chapter id="menus">
+<title>Menu Reference</title>
+
+<para>When you start &kview; you see the typical application layout: a
+workspace containing your documents (images in this case), a menubar that
+provides access to the various commands, a toolbar with shortcut buttons for
+some of them and a status bar at the bottom to display status messages. When
+you have the loaded an image into &kview;, there is also an additional
+context menu available which is displayed by clicking your right mouse
+button over the image. Below, all menu entries are explained in the order
+that they appear in the menubar.</para>
+
+<sect1 id="file-menu">
+<title>The <guimenu>File</guimenu> Menu</title>
+
+<variablelist>
+<varlistentry>
+<term><menuchoice>
+<shortcut>
+<keycombo action="simul">&Ctrl;<keycap>O</keycap></keycombo>
+</shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Open...</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Opens a new image</action> in &kview;. The size of the
+&kview; main window and the image after loading are determined by your
+settings. If you open several images, only the last one is shown, but all of
+them can be accessed using the image list.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Open Recent</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Displays a list of recently opened images.</action>
+Selecting one from this list reopens the image.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">
+&Ctrl;<keycap>S</keycap></keycombo></shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Save</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Save the current image</action>.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>File</guimenu>
+<guimenuitem>Save As</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Saves the image under a different name</action>. By
+choosing a new file format you can convert the image to a different graphics
+type.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<shortcut><keycombo action="simul">&Ctrl;
+<keycap>P</keycap></keycombo></shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Print...</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Prints the image</action>. In the standard &kde; print dialog
+click the <guibutton>Options &gt;&gt;</guibutton> button, go to the tab <guilabel>Image
+Settings</guilabel>. Select <guilabel>Fit image to page size</guilabel> or
+<guilabel>Center image on page</guilabel>.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo>
+&Ctrl;<keycap>W</keycap></keycombo></shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Close</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Closes the currently displayed
+image.</action></para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">
+&Ctrl;<keycap>Q</keycap></keycombo></shortcut>
+<guimenu>File</guimenu>
+<guimenuitem>Quit</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Quits</action> &kview;. If you have several &kview;
+images open, all of them are closed.</para></listitem>
+</varlistentry>
+
+</variablelist>
+
+</sect1>
+
+<sect1 id="edit-menu">
+<title>The <guimenu>Edit</guimenu> Menu</title>
+
+<variablelist>
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">&Ctrl;
+<keycap>C</keycap></keycombo></shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Copy</guimenuitem></menuchoice>
+</term>
+<listitem>
+<para><action>Copies</action> the entire image or the selection to the clipboard.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">&Ctrl;
+<keycap>V</keycap></keycombo></shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Paste</guimenuitem></menuchoice>
+</term>
+<listitem>
+<para><action>Paste</action> the contents of the clipboard as a new image (only available, if the clipboard contains a valid image).</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycap>C</keycap></shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Crop</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para>If you have selected any part of the image (by drawing a box around it
+using your mouse) you can cut off all the rest around it by using this
+option. Your image is effectively reduced to your selection.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycap>F5</keycap></shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Reload</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Reloads</action> the image to its original state (right
+after opening it).</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">
+<keycap>&Shift;</keycap><keycap>Delete</keycap></keycombo></shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Delete</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Deletes</action> the image.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycap>V</keycap></shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Flip</guimenuitem>
+<guimenuitem>Vertical</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Flips the image along the
+vertical</action>. Mathematically, this does a reflection along the image's
+horizontal center line.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycap>H</keycap></shortcut>
+<guimenu>Edit</guimenu>
+<guimenuitem>Flip</guimenuitem>
+<guimenuitem>Horizontal</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Flips the image along the
+horizontal</action>. Mathematically, this does a reflection along the image's
+vertical center line.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Edit</guimenu>
+<guimenuitem>Rotate Counter-Clockwise</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Rotates the image by 90° in the counter-clockwise
+direction</action>.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Edit</guimenu>
+<guimenuitem>Rotate Clockwise</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Rotates the image by 90° in the clockwise
+direction</action>.</para></listitem>
+</varlistentry>
+</variablelist>
+
+</sect1>
+
+<sect1 id="effects-menu">
+<title>The <guimenu>Effects</guimenu> Menu</title>
+
+<para>&kview; provides some functions for simple image processing:</para>
+
+<para>This menu item is only displayed in the menubar, if you choose the
+application plugin effects in &kview;s configure dialog</para>
+
+<variablelist>
+<varlistentry>
+<term><menuchoice>
+<guimenu>Effects</guimenu>
+<guimenuitem>Gamma Correction...</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Adjusts the gamma factor.</action></para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Effects</guimenu>
+<guimenuitem>Blend Color...</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Blends the image to selected color and opacity</action></para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Effects</guimenu>
+<guimenuitem>Change Intensity (Brightness)...</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Changes the brightness of the image.</action> Enter the
+new brightness in percent (with respect to the <emphasis>initial</emphasis>
+value).</para></listitem>
+</varlistentry>
+</variablelist>
+
+</sect1>
+
+<sect1 id="view-menu">
+<title>The <guimenu>View</guimenu> Menu</title>
+
+<variablelist>
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">
+&Ctrl;<keycap>+</keycap></keycombo></shortcut>
+<guimenu>View</guimenu>
+<guimenuitem>Zoom In</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Enlarges the image by ten percent</action>. Notice that
+this refers to the <emphasis>current</emphasis> size of the
+picture.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>View</guimenu>
+<guimenuitem>Zoom...</guimenuitem>
+</menuchoice></term>
+<listitem><para>Opens a list to <action>choose the zoom
+factor</action>. This value is given in percent and always refers to the
+<emphasis>initial</emphasis> size of the picture.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">
+&Ctrl;<keycap>-</keycap></keycombo></shortcut>
+<guimenu>View</guimenu>
+<guimenuitem>Zoom Out</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Reduces the image size by ten percent</action>. Again
+this refers to the <emphasis>current</emphasis> size of the
+image.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>View</guimenu><guimenuitem>Fit Image
+to Window</guimenuitem></menuchoice></term>
+<listitem><para><action>Maximizes the image size</action>. The image is scaled
+to the window size, keeping the aspect
+ratio.</para></listitem>
+</varlistentry>
+</variablelist>
+
+</sect1>
+
+<sect1 id="go-menu">
+<title>The <guimenu>Go</guimenu> Menu</title>
+
+<para>This item is only displayed in the menubar, if you choose the
+application plugin presenter in &kview;s configure dialog</para>
+
+<variablelist>
+<varlistentry>
+<term><menuchoice>
+<guimenu>Go</guimenu>
+<guimenuitem>Image List...</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Displays a list of the currently loaded images.</action>
+You can flip through the images by either double-clicking on them or using the
+<guibutton>Previous</guibutton> and <guibutton>Next</guibutton>
+buttons. <guibutton>Shuffle</guibutton> rearranges the images in a random order.
+Pressing
+<guibutton>Start Slideshow</guibutton> will start the slideshow with the current
+settings for the interval. In addition, you can save and load your image
+list using the corresponding buttons.
+<guilabel>Slideshow interval:</guilabel> <!--is guilabel correct? -->
+Here you can change the interval between the different slides for the slideshow.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycap>S</keycap></shortcut>
+<guimenu>Go</guimenu>
+<guimenuitem>Start/Stop Slideshow</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Starts or stops the
+slideshow.</action></para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">
+&Alt;<keysym>Left Arrow</keysym></keycombo></shortcut>
+<guimenu>Go</guimenu>
+<guimenuitem>Previous Image in List</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Switches to the previous image in the
+list.</action></para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">
+&Alt;<keysym>Right Arrow</keysym></keycombo></shortcut>
+<guimenu>Go</guimenu>
+<guimenuitem>Next Image in List</guimenuitem></menuchoice></term>
+<listitem><para><action>Switches to the next item in the
+list.</action></para></listitem>
+</varlistentry>
+</variablelist>
+
+</sect1>
+
+<sect1 id="tools-menu">
+<title>The <guimenu>Tools</guimenu> Menu</title>
+
+<variablelist>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Tools</guimenu>
+<guimenuitem>Scan Image...</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Opens</action> images from your scanner into &kview;.
+This menu item is only displayed in the menubar, if you choose the
+application plugin scanner in &kview;s configure dialog
+</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">
+&Shift;<keysym>Left Arrow</keysym></keycombo></shortcut>
+<guimenu>Tools</guimenu>
+<guimenuitem>Back</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Switches to the previous image in the current
+folder.</action></para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">
+&Shift;<keysym>Right Arrow</keysym></keycombo></shortcut>
+<guimenu>Tools</guimenu>
+<guimenuitem>Forward</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Switches to the next image in the current
+folder.</action></para></listitem>
+</varlistentry>
+</variablelist>
+
+</sect1>
+
+<sect1 id="settings-menu">
+<title>The <guimenu>Settings</guimenu> Menu</title>
+<para>This menu provides options for configuring &kview;, changing its
+appearance, shortcuts and standard behavior.</para>
+
+<variablelist>
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">
+&Ctrl;<keycap>M</keycap></keycombo></shortcut>
+<guimenu>Settings</guimenu>
+<guimenuitem>Show/Hide Menubar</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Toggles the menubar on/off.</action></para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><guimenu>Settings</guimenu>
+<guisubmenu>Toolbars</guisubmenu>
+<guimenuitem>Main Toolbar (KView)</guimenuitem>
+</menuchoice></term>
+<term><menuchoice><guimenu>Settings</guimenu>
+<guisubmenu>Toolbars</guisubmenu>
+<guimenuitem>Extra Toolbar (KView)</guimenuitem>
+</menuchoice></term>
+<listitem>
+<para>Toggles the main toolbar and the extra toolbar on and off
+respectively</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Show/Hide Statusbar</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Toggles the status bar on/off.</action></para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Show/Hide Scrollbars</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Toggles the Scrollbars on/off.</action></para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice><shortcut><keycombo action="simul">&Ctrl;
+<keycap>&Shift;</keycap><keycap>F</keycap></keycombo></shortcut>
+<guimenu>Settings</guimenu>
+<guimenuitem>Fullscreen Mode</guimenuitem></menuchoice>
+</term>
+<listitem>
+<para>This option maximizes the &kview; window and the currently shown image so
+you can have a closer look at it. Even the window decorations (titlebar &etc;) are
+temporarily removed. Selecting this option once again switches back to normal
+mode.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Configure Shortcuts...</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Opens a dialog for changing the key bindings.</action>
+Using this option you can change the standard key shortcut for &kview;'s commands
+or create new ones.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Configure Toolbars...</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Opens a dialog for configuring the toolbar.</action> You
+can add and remove toolbuttons for &kview;'s commands with this
+option.</para></listitem>
+</varlistentry>
+
+<varlistentry>
+<term><menuchoice>
+<guimenu>Settings</guimenu>
+<guimenuitem>Configure &kview;...</guimenuitem>
+</menuchoice></term>
+<listitem><para><action>Opens a dialog for changing some options</action> as
+described in the section <xref linkend="kview-options"/></para>
+</listitem>
+</varlistentry>
+</variablelist>
+</sect1>
+
+<sect1 id="help-menu">
+<title>The <guimenu>Help</guimenu> Menu</title>
+
+&help.menu.documentation;
+
+</sect1>
+</chapter>
+
+<chapter id="command-line">
+<title>Command Line Options</title>
+
+<para>&kview; can be started directly from a terminal like &konsole; or
+<application>xterm</application>. Several command line options are
+available.</para>
+
+<variablelist>
+<varlistentry>
+<term><command>kview</command> <option>--help</option></term>
+<listitem><para>Lists the command line options (see below).</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><command>kview</command> <option>--help-qt</option></term>
+<listitem><para>Shows the options specific to &Qt; (the &GUI;
+library that &kde; is based on).</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><command>kview</command> <option>--help-kde</option></term>
+<listitem><para>Shows the &kde;-specific options.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><command>kview</command> <option>--help-all</option></term>
+<listitem><para>Displays all command line options.</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><command>kview</command> <option>--author</option></term>
+<listitem><para>You want to send your warm wishes and euphoric cheers to
+someone? Here they are!</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><command>kview</command> <option>-v</option>,
+<option>--version</option></term>
+<listitem><para>Displays the version number of &kview; (and that of
+&Qt;/&kde;).</para></listitem>
+</varlistentry>
+<varlistentry>
+<term><command>kview</command> <option>--license</option></term>
+<listitem><para>Shows under which licenses &kview; is being
+published.</para></listitem>
+</varlistentry>
+</variablelist>
+</chapter>
+
+<chapter id="kview-options">
+<title>&kview; Options</title>
+
+<sect1 id="kview-options-viewer">
+<title><guilabel>Viewer</guilabel></title>
+
+<para>This is the configuration for the part of &kview; that can be reused
+by other applications (meaning that the settings will also affect the &kview;
+part that gets embedded into &konqueror; or other applications).</para>
+
+<screenshot>
+<screeninfo>&kview; viewer configuration dialog</screeninfo>
+<mediaobject>
+<imageobject><imagedata fileref="kview-viewer-configuration.png" format="PNG"/></imageobject>
+<textobject><phrase>&kview; viewer configuration dialog</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<variablelist>
+<title>General configuration options for KViewCanvas</title>
+<varlistentry>
+<term><guilabel>Use smooth scaling (high quality but
+slower)</guilabel></term>
+<listitem>
+<para>As the option suggests, use a very high quality but relatively slow
+method of scaling images.</para>
+</listitem>
+</varlistentry>
+<varlistentry>
+<term><guilabel>Keep aspect ratio</guilabel></term>
+<listitem>
+<para>If this is checked &kview; will always try to keep the aspect
+ratio. That means if the width is scaled with a factor x, the height is
+scaled with the same factor.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Center image</guilabel></term>
+<listitem>
+<para>If checked, the opened image will be displayed centered to the &kview;
+window.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Background Color</guilabel></term>
+<listitem>
+<para>Opens a normal &kde; color picker dialog, where you can choose the
+background color for the image</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Minimum width:</guilabel></term>
+<listitem>
+<para>The width of the image shown will not get smaller than the size you
+enter here. A value of 10 would cause a 1x1 image to be stretched
+horizontally by a factor of 10.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Maximum width:</guilabel></term>
+<listitem>
+<para>The width of the image shown will not get bigger than the size you
+enter here. A value of 100 would cause a 1000x1000 image to be compressed
+horizontally by a factor of 0.1.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Minimum height:</guilabel></term>
+<listitem>
+<para>The height of the image shown will not get smaller than the size you
+enter here. A value of 10 would cause a 1x1 image to be stretched vertically
+by a factor of 10. </para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Maximum height:</guilabel></term>
+<listitem>
+<para>The height of the image shown will not get bigger than the size you
+enter here. A value of 100 would cause a 1000x1000 image to be compressed
+vertically by a factor of 0.1. </para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Choose which blend effects should be used:</guilabel></term>
+<listitem>
+<para>Every effect selected may be used to create a transition effect
+between the images. If you select multiple effects they will be chosen
+randomly.
+</para>
+</listitem>
+</varlistentry>
+</variablelist>
+
+<variablelist>
+<title><guilabel>Chooose and Configure Your Plugins</guilabel></title>
+<varlistentry>
+<term><guilabel>Browser</guilabel></term>
+<listitem>
+<para>Here you can enable/disable use of the browser &kview; plugin, which
+enables you to browse through all the images in the current folder.
+</para>
+</listitem>
+</varlistentry>
+</variablelist>
+</sect1>
+
+<sect1 id="kview-options-application">
+<title><guilabel>Application</guilabel></title>
+
+<para>Here you can set options that are special for the &kview; application
+when running stand-alone. What you change in here will not affect other
+applications.</para>
+
+<screenshot>
+<screeninfo>&kview; application configuration dialog</screeninfo>
+<mediaobject>
+<imageobject><imagedata fileref="kview-application-configuration.png" format="PNG"/></imageobject>
+<textobject><phrase>&kview; application configuration dialog</phrase></textobject>
+</mediaobject>
+</screenshot>
+
+<variablelist>
+<title><guilabel>Application</guilabel></title>
+<varlistentry>
+<term><guilabel>Resizing</guilabel></term>
+<listitem><para>This option determines if the window and/or the image will be
+resized after loading a new picture into &kview;. With <guilabel>Only resize
+window</guilabel> enabled, the &kview; window will be resized so that it snuggly
+fits around the loaded image. Notice that this can reduce the main window almost
+to a vertical arrangement of menu entries if you load a small button pixmap (you
+can resize the window afterwards in the usual way, of course). If your image is
+pretty large (in terms of pixels), sometimes the &kview; window is resized in
+such a way that the caption bar completely moves off your screen. Similarly,
+<guilabel>Resize image to fit window</guilabel> resizes the image to fit into the &kview;
+workspace (keeping its aspect ratio intact). And with <guilabel>Don't
+resize anything</guilabel> as your choice, both &kview; and your image keep their
+size. With <guilabel>Best fit</guilabel>
+&kview; will resize the window to fit the image. The image will never be
+scaled up but if it is too large for the screen the image will be scaled down.
+</para></listitem>
+</varlistentry>
+</variablelist>
+
+<variablelist>
+<title><guilabel>Plugins</guilabel></title>
+<varlistentry>
+<term><guilabel>Effects</guilabel></term>
+<listitem>
+<para>Provides some image effects (and adds an <guimenu>Effects</guimenu> to
+the menubar to give you access to them).</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Presenter</guilabel></term>
+<listitem>
+<para>Creates an image list and enables you to create a slideshow.</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><guilabel>Scanner</guilabel></term>
+<listitem>
+<para>Adds <guimenu>Scan Image...</guimenu> to the <guimenu>Tools</guimenu>
+menu to open images from your scanner into &kview;.</para>
+</listitem>
+</varlistentry>
+</variablelist>
+</sect1>
+
+</chapter>
+
+<chapter id="credits">
+<title>Credits and License</title>
+
+<para>&kview;</para>
+
+<para>Program copyright 1997-2001 Sirtaj S. Kang
+&Sirtaj.Singh.Kang.mail;</para>
+<para>KParts integration by &Simon.Hausmann;
+<email>shaus@neuro2.med.uni-magdeburg.de</email></para>
+<para>Maintainer: Matthias Kretz <email>kretz@kde.org</email></para>
+<para>Documentation copyright 2001 &Hauke.Hildebrandt;
+&Hauke.Hildebrandt.mail;
+</para>
+
+<para>Documentation substantially updated by Burkhard Lück
+<email>lueck@hube-lueck.de</email> in 2005 for &kde; 3.5</para>
+
+<!-- TRANS:CREDIT_FOR_TRANSLATORS -->
+&underFDL; <!-- FDL: do not remove -->
+&underGPL; <!-- GPL License -->
+
+</chapter>
+
+<appendix id="installation">
+<title>Installation</title>
+
+<sect1 id="getting-kview">
+<title>How to obtain &kview;</title>
+
+&install.intro.documentation;
+
+&install.compile.documentation;
+
+</sect1>
+
+<sect1 id="requirements">
+<title>Requirements</title>
+
+<para>Since &kview; is part of the &kde; desktop you need a working &kde;
+installation to use it. However, some additional libraries are needed by &kview;
+to use the various graphics file formats. For example, to handle the
+<acronym>PNG</acronym> format &kview; needs the corresponding library
+libpng. &kview; uses the libraries that are registered by
+kdelibs/kimgio.</para>
+
+</sect1>
+
+</appendix>
+
+&documentation.index;
+</book>
+<!--
+Local Variables:
+mode: sgml
+sgml-minimize-attributes: nil
+sgml-general-insert-case: lower
+End:
+-->
diff --git a/doc/kview/kview-application-configuration.png b/doc/kview/kview-application-configuration.png
new file mode 100644
index 00000000..0ba79356
--- /dev/null
+++ b/doc/kview/kview-application-configuration.png
Binary files differ
diff --git a/doc/kview/kview-viewer-configuration.png b/doc/kview/kview-viewer-configuration.png
new file mode 100644
index 00000000..f2e6d8c2
--- /dev/null
+++ b/doc/kview/kview-viewer-configuration.png
Binary files differ
diff --git a/kamera/AUTHORS b/kamera/AUTHORS
new file mode 100644
index 00000000..b278e9ce
--- /dev/null
+++ b/kamera/AUTHORS
@@ -0,0 +1,4 @@
+ Copyright (C) 2001 The Kompany
+ 2001-2003 Ilya Konstantinov <kde-devel@future.shiny.co.il>
+ 2001-2007 Marcus Meissner <marcus@jet.franken.de>
+ 2003 Nadeem Hasan <nhasan@nadmm.com>
diff --git a/kamera/Makefile.am b/kamera/Makefile.am
new file mode 100644
index 00000000..f012f4a1
--- /dev/null
+++ b/kamera/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = kcontrol kioslave pics
diff --git a/kamera/README b/kamera/README
new file mode 100644
index 00000000..592a84f4
--- /dev/null
+++ b/kamera/README
@@ -0,0 +1,5 @@
+Dependencies:
+
+You need libgphoto 2.0 final (or later).
+
+libgphoto2 2.3.1 or newer is recommended.
diff --git a/kamera/configure.in.in b/kamera/configure.in.in
new file mode 100644
index 00000000..3e2fd1c6
--- /dev/null
+++ b/kamera/configure.in.in
@@ -0,0 +1,182 @@
+dnl KDE_FIND_GPHOTO2 - Find gphoto2 libraries and include files
+dnl
+dnl Adapted from kdebase/nsplugins/configure.in.in
+
+AC_DEFUN([KDE_FIND_GPHOTO2],
+[
+
+
+
+# Clear working variables
+gphoto2_includes=
+gphoto2_libraries=
+
+
+
+# Process user input to configure
+AC_ARG_WITH(kamera,
+AC_HELP_STRING([--without-kamera],[do not build kamera (gphoto2 required)]),
+[if test "$withval" = "no" ; then
+ gphoto2_includes=none
+ gphoto2_libraries=none
+fi])dnl
+
+AC_ARG_WITH(gphoto2-includes,
+AC_HELP_STRING([--with-gphoto2-includes=DIR],[gphoto2 include files are in DIR]),
+gphoto2_includes="$withval")
+
+AC_ARG_WITH(gphoto2-libraries,
+AC_HELP_STRING([--with-gphoto2-libraries=DIR],[gphoto2 libraries are in DIR]),
+gphoto2_libraries="$withval")
+
+AC_MSG_CHECKING(for gPhoto2)
+# the pkg-config way first, if user did not use --with-
+AC_CHECK_PROG(gphoto2_config,gphoto2-config,gphoto2-config,no)
+AC_CHECK_PROG(gphoto2_port_config,gphoto2-port-config,gphoto2-port-config,no)
+if test "$gphoto2_includes" = "" -a "$gphoto2_libraries" = "" -a "$gphoto2_config" != "no" -a "$gphoto2_port_config" != "no"
+then
+ with_kamera="yes"
+ GPHOTO2_INCS="`$gphoto2_config --cflags` `$gphoto2_port_config --cflags`"
+ GPHOTO2_LIBS="`$gphoto2_config --libs` `$gphoto2_port_config --libs`"
+else
+#
+# Search for gphoto2 include files.
+#
+ if test "$gphoto2_includes" = ""; then
+ AC_CACHE_VAL(ac_cv_gphoto2_includes, [
+ ac_gphoto2_save_LIBS="$LIBS"
+ LIBS="-lgphoto2 $LIBS"
+ ac_cv_gphoto2_includes="none"
+ AC_TRY_COMPILE([#include <gphoto2.h>],[int a;],
+ [
+ # gphoto2.h is in the standard search path.
+ ac_cv_gphoto2_includes=
+ ],[
+ # gphoto2.h is not in the standard search path.
+ # Locate it and put its directory in `gphoto2_includes'
+ for dir in /usr/include /usr/local/include \
+ /usr/include/gphoto2 /usr/local/include/gphoto2; do
+ if test -f "$dir/gphoto2.h"; then
+ ac_cv_gphoto2_includes="$dir"
+ break
+ fi
+ done
+ ])
+ #
+ LIBS="$ac_gphoto2_save_LIBS"
+ ])
+ gphoto2_includes="$ac_cv_gphoto2_includes"
+ fi
+
+ #
+ # Search for libgphoto2
+ #
+ if test "$gphoto2_libraries" = ""; then
+ AC_CACHE_VAL(ac_cv_gphoto2_libraries,[
+ ac_gphoto2_save_LIBS="$LIBS"
+ LIBS="-lgphoto2_port -lgphoto2 $LIBS"
+ ac_cv_gphoto2_libraries="none"
+ AC_TRY_LINK([#include <gphoto2.h>],[gp_context_progress_start(0,0,0,0);], [
+ # libgphoto2 is in the standard search path.
+ ac_cv_gphoto2_libraries=
+ ],[
+ # libgphoto2 is not in the standard search path.
+ # Locate it and put its directory in `gphoto2_libraries'
+ for dir in /usr/lib /usr/local/lib; do
+ if test -d "$dir" && test "`ls $dir/libgphoto2.* 2> /dev/null`" != ""; then
+ ac_cv_gphoto2_libraries="$dir"
+ break
+ fi
+ done
+ ])
+ #
+ LIBS="$ac_gphoto2_save_LIBS"
+ ])
+ #
+ gphoto2_libraries="$ac_cv_gphoto2_libraries"
+ fi
+# Initialise compiler and linker flag variables for export
+ if test "$gphoto2_includes" = "none" -o "$gphoto2_libraries" = "none" ; then
+ with_kamera="no"
+ else
+ with_kamera="yes"
+
+ if test "$gphoto2_libraries" = "" -o "$gphoto2_libraries" = "none"; then
+ GPHOTO2_LIBS="-lgphoto2"
+ else
+ GPHOTO2_LIBS="-L$gphoto2_libraries -lgphoto2"
+ fi
+ if test "$gphoto2_includes" != "" -a "$gphoto2_includes" != "none"; then
+ GPHOTO2_INCS="-I$gphoto2_includes"
+ fi
+ fi
+fi
+
+if test "$with_kamera" = "yes" ; then
+ # Check if it works.
+ ac_gphoto2_save_LIBS="$LIBS"
+ ac_gphoto2_save_CFLAGS="$CFLAGS"
+ LIBS="$LIBS $GPHOTO2_LIBS"
+ CFLAGS="$CFLAGS $GPHOTO2_INCS"
+ AC_TRY_LINK([#include <gphoto2.h>],[gp_context_progress_start(0,0,0,0);], [
+ # It works.
+ AC_DEFINE(HAVE_GPHOTO2,1,[Define if you have gPhoto2 installed])
+ ],[
+ with_kamera="no"
+ ])
+ LIBS="$ac_gphoto2_save_LIBS"
+ CFLAGS="$ac_gphoto2_save_CFLAGS"
+fi
+dnl **** Check for va_copy ****
+AC_CACHE_CHECK([for va_copy], ac_cv_c_va_copy,
+ AC_TRY_LINK(
+ [#include <stdarg.h>],
+ [va_list ap1, ap2;
+ va_copy(ap1,ap2);
+ ],
+ [ac_cv_c_va_copy="yes"],
+ [ac_cv_c_va_copy="no"])
+ )
+if test "$ac_cv_c_va_copy" = "yes"
+then
+ AC_DEFINE(HAVE_VA_COPY, 1, [Define if we have va_copy])
+fi
+AC_CACHE_CHECK([for __va_copy], ac_cv_c___va_copy,
+ AC_TRY_LINK(
+ [#include <stdarg.h>],
+ [va_list ap1, ap2;
+ __va_copy(ap1,ap2);
+ ],
+ [ac_cv_c___va_copy="yes"],
+ [ac_cv_c___va_copy="no"])
+ )
+if test "$ac_cv_c___va_copy" = "yes"
+then
+ AC_DEFINE(HAVE___VA_COPY, 1, [Define if we have __va_copy])
+fi
+
+# Export compiler and linker flags for replacement in Makefile
+AC_SUBST(GPHOTO2_INCS)
+AC_SUBST(GPHOTO2_LIBS)
+
+
+# Display results of configuration
+gphoto2_libraries_result="$gphoto2_libraries"
+gphoto2_includes_result="$gphoto2_includes"
+
+test "$gphoto2_libraries" = "" && gphoto2_libraries_result="in default path"
+test "$gphoto2_includes" = "" && gphoto2_includes_result="in default path"
+
+test "$gphoto2_libraries" = "none" && gphoto2_libraries_result="(none)"
+test "$gphoto2_includes" = "none" && gphoto2_includes_result="(none)"
+
+AC_MSG_RESULT(
+ [gphoto2 libraries $gphoto2_libraries_result, gphoto2 headers $gphoto2_includes_result])
+
+]) dnl end of KDE_FIND_GPHOTO2 definition
+
+KDE_FIND_GPHOTO2
+if test "$with_kamera" = "no"; then
+dnl AC_MSG_WARN([You need to install gphoto 2.0 (or later), e.g. http://gphoto.net/dist/gphoto2-2.0.tar.gz if your distributor doesn't have a package])
+ DO_NOT_COMPILE="$DO_NOT_COMPILE kamera"
+fi
diff --git a/kamera/kcontrol/Makefile.am b/kamera/kcontrol/Makefile.am
new file mode 100644
index 00000000..9fd30f46
--- /dev/null
+++ b/kamera/kcontrol/Makefile.am
@@ -0,0 +1,16 @@
+kde_module_LTLIBRARIES = kcm_kamera.la
+
+kcm_kamera_la_SOURCES = kamera.cpp kameradevice.cpp kameraconfigdialog.cpp
+
+kcm_kamera_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kcm_kamera_la_LIBADD = $(LIB_KIO) $(GPHOTO2_LIBS)
+INCLUDES= $(all_includes) $(GPHOTO2_INCS)
+
+kcm_kamera_la_METASOURCES = AUTO
+
+noinst_HEADERS = kamera.h kameradevice.h kameraconfigdialog.h
+
+messages:
+ $(XGETTEXT) $(kcm_kamera_la_SOURCES) -o $(podir)/kcmkamera.pot
+
+xdg_apps_DATA = kamera.desktop
diff --git a/kamera/kcontrol/kamera.cpp b/kamera/kcontrol/kamera.cpp
new file mode 100644
index 00000000..0fdc416a
--- /dev/null
+++ b/kamera/kcontrol/kamera.cpp
@@ -0,0 +1,423 @@
+/*
+
+ Copyright (C) 2001 The Kompany
+ 2002-2003 Ilya Konstantinov <kde-devel@future.shiny.co.il>
+ 2002-2003 Marcus Meissner <marcus@jet.franken.de>
+ 2003 Nadeem Hasan <nhasan@nadmm.com>
+
+ 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 <qlabel.h>
+#include <qlayout.h>
+
+#include <kgenericfactory.h>
+#include <ksimpleconfig.h>
+#include <kaction.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <kiconview.h>
+#include <kdialog.h>
+#include <klocale.h>
+#include <ktoolbar.h>
+#include <kpopupmenu.h>
+#include <kprotocolinfo.h>
+#include <kdebug.h>
+
+#include "kameraconfigdialog.h"
+#include "kameradevice.h"
+#include "kamera.h"
+#include "kamera.moc"
+
+typedef KGenericFactory<KKameraConfig, QWidget> KKameraConfigFactory;
+K_EXPORT_COMPONENT_FACTORY( kcm_kamera, KKameraConfigFactory( "kcmkamera" ) )
+
+// --------------- Camera control center module widget ---
+
+KKameraConfig *KKameraConfig::m_instance = NULL;
+
+KKameraConfig::KKameraConfig(QWidget *parent, const char *name, const QStringList &)
+ : KCModule(KKameraConfigFactory::instance(), parent, name)
+{
+ m_devicePopup = new KPopupMenu(this);
+ m_actions = new KActionCollection(this);
+ m_config = new KSimpleConfig(KProtocolInfo::config("camera"));
+
+ m_context = gp_context_new();
+ if (m_context) {
+
+ // Register the callback functions
+ gp_context_set_cancel_func(m_context, cbGPCancel, this);
+ gp_context_set_idle_func(m_context, cbGPIdle, this);
+
+ displayGPSuccessDialogue();
+
+ // load existing configuration
+ load();
+
+ } else {
+
+ displayGPFailureDialogue();
+ }
+
+ // store instance for frontend_prompt
+ m_instance = this;
+}
+
+KKameraConfig::~KKameraConfig()
+{
+ delete m_config;
+}
+
+void KKameraConfig::defaults()
+{
+ load( true );
+}
+
+void KKameraConfig::displayGPFailureDialogue(void)
+{
+ new QLabel(i18n("Unable to initialize the gPhoto2 libraries."), this);
+}
+
+void KKameraConfig::displayGPSuccessDialogue(void)
+{
+ // set the kcontrol module buttons
+ setButtons(Help | Apply | Cancel | Ok);
+
+ // create a layout with two vertical boxes
+ QVBoxLayout *topLayout = new QVBoxLayout(this, 0, 0);
+ topLayout->setAutoAdd(true);
+
+ m_toolbar = new KToolBar(this, "ToolBar");
+ m_toolbar->setMovingEnabled(false);
+
+ // create list of devices
+ m_deviceSel = new KIconView(this);
+
+ connect(m_deviceSel, SIGNAL(rightButtonClicked(QIconViewItem *, const QPoint &)),
+ SLOT(slot_deviceMenu(QIconViewItem *, const QPoint &)));
+ connect(m_deviceSel, SIGNAL(doubleClicked(QIconViewItem *)),
+ SLOT(slot_configureCamera()));
+ connect(m_deviceSel, SIGNAL(selectionChanged(QIconViewItem *)),
+ SLOT(slot_deviceSelected(QIconViewItem *)));
+
+ m_deviceSel->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
+
+ // create actions
+ KAction *act;
+
+ act = new KAction(i18n("Add"), "camera", 0, this, SLOT(slot_addCamera()), m_actions, "camera_add");
+ act->setWhatsThis(i18n("Click this button to add a new camera."));
+ act->plug(m_toolbar);
+ m_toolbar->insertLineSeparator();
+ act = new KAction(i18n("Test"), "camera_test", 0, this, SLOT(slot_testCamera()), m_actions, "camera_test");
+ act->setWhatsThis(i18n("Click this button to remove the selected camera from the list."));
+ act->plug(m_toolbar);
+ act = new KAction(i18n("Remove"), "edittrash", 0, this, SLOT(slot_removeCamera()), m_actions, "camera_remove");
+ act->setWhatsThis(i18n("Click this button to remove the selected camera from the list."));
+ act->plug(m_toolbar);
+ act = new KAction(i18n("Configure..."), "configure", 0, this, SLOT(slot_configureCamera()), m_actions, "camera_configure");
+ act->setWhatsThis(i18n("Click this button to change the configuration of the selected camera.<br><br>The availability of this feature and the contents of the Configuration dialog depend on the camera model."));
+ act->plug(m_toolbar);
+ act = new KAction(i18n("Information"), "hwinfo", 0, this, SLOT(slot_cameraSummary()), m_actions, "camera_summary");
+ act->setWhatsThis(i18n("Click this button to view a summary of the current status of the selected camera.<br><br>The availability of this feature and the contents of the Configuration dialog depend on the camera model."));
+ act->plug(m_toolbar);
+ m_toolbar->insertLineSeparator();
+ act = new KAction(i18n("Cancel"), "stop", 0, this, SLOT(slot_cancelOperation()), m_actions, "camera_cancel");
+ act->setWhatsThis(i18n("Click this button to cancel the current camera operation."));
+ act->setEnabled(false);
+ act->plug(m_toolbar);
+}
+
+void KKameraConfig::populateDeviceListView(void)
+{
+ m_deviceSel->clear();
+ CameraDevicesMap::Iterator it;
+ for (it = m_devices.begin(); it != m_devices.end(); it++) {
+ if (it.data()) {
+ new QIconViewItem(m_deviceSel, it.key(), DesktopIcon("camera"));
+ }
+ }
+ slot_deviceSelected(m_deviceSel->currentItem());
+}
+
+void KKameraConfig::save(void)
+{
+ CameraDevicesMap::Iterator it;
+
+ for (it = m_devices.begin(); it != m_devices.end(); it++)
+ {
+ it.data()->save(m_config);
+ }
+ m_config->sync();
+}
+
+void KKameraConfig::load(void)
+{
+ load( false );
+}
+
+void KKameraConfig::load(bool useDefaults )
+{
+ m_config->setReadDefaults( useDefaults );
+ QStringList groupList = m_config->groupList();
+ QStringList::Iterator it;
+ int i, count;
+ CameraList *list;
+ CameraAbilitiesList *al;
+ GPPortInfoList *il;
+ const char *model, *value;
+ KCamera *kcamera;
+
+ for (it = groupList.begin(); it != groupList.end(); it++) {
+ if (*it != "<default>") {
+ m_config->setGroup(*it);
+ if (m_config->readEntry("Path").contains("usb:"))
+ continue;
+
+ kcamera = new KCamera(*it,m_config->readEntry("Path"));
+ connect(kcamera, SIGNAL(error(const QString &)), SLOT(slot_error(const QString &)));
+ connect(kcamera, SIGNAL(error(const QString &, const QString &)), SLOT(slot_error(const QString &, const QString &)));
+ kcamera->load(m_config);
+ m_devices[*it] = kcamera;
+ }
+ }
+ m_cancelPending = false;
+
+ gp_list_new (&list);
+
+ gp_abilities_list_new (&al);
+ gp_abilities_list_load (al, m_context);
+ gp_port_info_list_new (&il);
+ gp_port_info_list_load (il);
+ gp_abilities_list_detect (al, il, list, m_context);
+ gp_abilities_list_free (al);
+ gp_port_info_list_free (il);
+
+ count = gp_list_count (list);
+
+ QMap<QString,QString> ports, names;
+
+ for (i = 0 ; i<count ; i++) {
+ gp_list_get_name (list, i, &model);
+ gp_list_get_value (list, i, &value);
+
+ ports[value] = model;
+ if (!strcmp(value,"usb:"))
+ names[model] = value;
+ }
+ if (ports.contains("usb:") && names[ports["usb:"]]!="usb:")
+ ports.remove("usb:");
+
+ QMap<QString,QString>::iterator portit;
+
+ for (portit = ports.begin() ; portit != ports.end(); portit++) {
+ /* kdDebug() << "Adding USB camera: " << portit.data() << " at " << portit.key() << endl; */
+
+ kcamera = new KCamera(portit.data(),portit.key());
+ connect(kcamera, SIGNAL(error(const QString &)), SLOT(slot_error(const QString &)));
+ connect(kcamera, SIGNAL(error(const QString &, const QString &)), SLOT(slot_error(const QString &, const QString &)));
+ m_devices[portit.data()] = kcamera;
+ }
+ populateDeviceListView();
+
+ gp_list_free (list);
+
+ emit changed( useDefaults );
+}
+
+void KKameraConfig::beforeCameraOperation(void)
+{
+ m_cancelPending = false;
+
+ m_actions->action("camera_test")->setEnabled(false);
+ m_actions->action("camera_remove")->setEnabled(false);
+ m_actions->action("camera_configure")->setEnabled(false);
+ m_actions->action("camera_summary")->setEnabled(false);
+
+ m_actions->action("camera_cancel")->setEnabled(true);
+}
+
+void KKameraConfig::afterCameraOperation(void)
+{
+ m_actions->action("camera_cancel")->setEnabled(false);
+
+ // if we're regaining control after a Cancel...
+ if (m_cancelPending) {
+ qApp->restoreOverrideCursor();
+ m_cancelPending = false;
+ }
+
+ // if any item was selected before the operation was run
+ // it makes sense for the relevant toolbar buttons to be enabled
+ slot_deviceSelected(m_deviceSel->currentItem());
+}
+
+QString KKameraConfig::suggestName(const QString &name)
+{
+ QString new_name = name;
+ new_name.replace("/", ""); // we cannot have a slash in a URI's host
+
+ if (!m_devices.contains(new_name)) return new_name;
+
+ // try new names with a number appended until we find a free one
+ int i = 1;
+ while (i++ < 0xffff) {
+ new_name = name + " (" + QString::number(i) + ")";
+ if (!m_devices.contains(new_name)) return new_name;
+ }
+
+ return QString::null;
+}
+
+void KKameraConfig::slot_addCamera()
+{
+ KCamera *m_device = new KCamera(QString::null,QString::null);
+ connect(m_device, SIGNAL(error(const QString &)), SLOT(slot_error(const QString &)));
+ connect(m_device, SIGNAL(error(const QString &, const QString &)), SLOT(slot_error(const QString &, const QString &)));
+ KameraDeviceSelectDialog dialog(this, m_device);
+ if (dialog.exec() == QDialog::Accepted) {
+ dialog.save();
+ m_device->setName(suggestName(m_device->model()));
+ m_devices.insert(m_device->name(), m_device);
+ populateDeviceListView();
+ emit changed(true);
+ } else {
+ delete m_device;
+ }
+}
+
+void KKameraConfig::slot_removeCamera()
+{
+ QString name = m_deviceSel->currentItem()->text();
+ if (m_devices.contains(name)) {
+ KCamera *m_device = m_devices[name];
+ m_devices.remove(name);
+ delete m_device;
+ m_config->deleteGroup(name, true);
+ populateDeviceListView();
+ emit changed(true);
+ }
+}
+
+void KKameraConfig::slot_testCamera()
+{
+ beforeCameraOperation();
+
+ QString name = m_deviceSel->currentItem()->text();
+ if (m_devices.contains(name)) {
+ KCamera *m_device = m_devices[name];
+ if (m_device->test())
+ KMessageBox::information(this, i18n("Camera test was successful."));
+ }
+
+ afterCameraOperation();
+}
+
+void KKameraConfig::slot_configureCamera()
+{
+ QString name = m_deviceSel->currentItem()->text();
+ if (m_devices.contains(name)) {
+ KCamera *m_device = m_devices[name];
+ m_device->configure();
+ }
+}
+
+void KKameraConfig::slot_cameraSummary()
+{
+ QString summary;
+ QString name = m_deviceSel->currentItem()->text();
+ if (m_devices.contains(name)) {
+ KCamera *m_device = m_devices[name];
+ summary = m_device->summary();
+ if (!summary.isNull()) {
+ KMessageBox::information(this, summary);
+ }
+ }
+}
+
+void KKameraConfig::slot_cancelOperation()
+{
+ m_cancelPending = true;
+ // Prevent the user from keeping clicking Cancel
+ m_actions->action("camera_cancel")->setEnabled(false);
+ // and indicate that the click on Cancel did have some effect
+ qApp->setOverrideCursor(Qt::WaitCursor);
+}
+
+void KKameraConfig::slot_deviceMenu(QIconViewItem *item, const QPoint &point)
+{
+ if (item) {
+ m_devicePopup->clear();
+ m_actions->action("camera_test")->plug(m_devicePopup);
+ m_actions->action("camera_remove")->plug(m_devicePopup);
+ m_actions->action("camera_configure")->plug(m_devicePopup);
+ m_actions->action("camera_summary")->plug(m_devicePopup);
+ m_devicePopup->popup(point);
+ }
+}
+
+void KKameraConfig::slot_deviceSelected(QIconViewItem *item)
+{
+ m_actions->action("camera_test")->setEnabled(item);
+ m_actions->action("camera_remove")->setEnabled(item);
+ m_actions->action("camera_configure")->setEnabled(item);
+ m_actions->action("camera_summary")->setEnabled(item);
+}
+
+void KKameraConfig::cbGPIdle(GPContext * /*context*/, void * /*data*/)
+{
+ /*KKameraConfig *self( reinterpret_cast<KKameraConfig*>(data) );*/
+
+ qApp->processEvents();
+}
+
+GPContextFeedback KKameraConfig::cbGPCancel(GPContext * /*context*/, void *data)
+{
+ KKameraConfig *self( reinterpret_cast<KKameraConfig*>(data) );
+
+ // Since in practice no camera driver supports idle callbacks yet,
+ // we'll use the cancel callback as opportunity to process events
+ qApp->processEvents();
+
+ // If a cancel request is pending, ask gphoto to cancel
+ if (self->m_cancelPending)
+ return GP_CONTEXT_FEEDBACK_CANCEL;
+ else
+ return GP_CONTEXT_FEEDBACK_OK;
+}
+
+QString KKameraConfig::quickHelp() const
+{
+ return i18n("<h1>Digital Camera</h1>\n"
+ "This module allows you to configure support for your digital camera.\n"
+ "You would need to select the camera's model and the port it is connected\n"
+ "to on your computer (e.g. USB, Serial, Firewire). If your camera doesn't\n"
+ "appear in the list of <i>Supported Cameras</i>, go to the\n"
+ "<a href=\"http://www.gphoto.org\">GPhoto web site</a> for a possible update.<br><br>\n"
+ "To view and download images from the digital camera, go to address\n"
+ "<a href=\"camera:/\">camera:/</a> in Konqueror and other KDE applications.");
+}
+
+void KKameraConfig::slot_error(const QString &message)
+{
+ KMessageBox::error(this, message);
+}
+
+void KKameraConfig::slot_error(const QString &message, const QString &details)
+{
+ KMessageBox::detailedError(this, message, details);
+}
+
diff --git a/kamera/kcontrol/kamera.desktop b/kamera/kcontrol/kamera.desktop
new file mode 100644
index 00000000..0fda1401
--- /dev/null
+++ b/kamera/kcontrol/kamera.desktop
@@ -0,0 +1,193 @@
+[Desktop Entry]
+Comment=Configure Kamera
+Comment[af]=Konfigureer Kamera
+Comment[ar]=إعداد Kamera
+Comment[az]=Kameranı Quraşdır
+Comment[bg]=Настройване на цифров фотоапарат
+Comment[br]=Kefluniañ Kamera
+Comment[bs]=Podesi kameru
+Comment[ca]=Configura Kamera
+Comment[cs]=Nastavení Kamery
+Comment[cy]=Ffurfweddu Kamera
+Comment[da]=Indstil kamera
+Comment[de]=Kamera einrichten
+Comment[el]=Ρύθμιση Kamera
+Comment[eo]=Agordu fotilon
+Comment[es]=Configura Kamera
+Comment[et]=Kaamera seadistamine
+Comment[eu]=Konfiguratu Kamera
+Comment[fa]=پیکربندی Kamera
+Comment[fi]=Kameran asetukset
+Comment[fr]=Configuration de Kamera
+Comment[ga]=Cumraigh Kamera
+Comment[gl]=Configurar Kamera
+Comment[he]=שינוי הגדרות Kamera
+Comment[hi]=कॉन्फ़िगर केमरा
+Comment[hr]=Podesi Kameru
+Comment[hu]=A digitális fényképezőgépek beállításai
+Comment[id]=Konfigurasi kamera
+Comment[is]=Stilla samskiptaforrit stafrænna myndavéla (Kamera)
+Comment[it]=Configura Kamera
+Comment[ja]=カメラの設定
+Comment[kk]=Kamera баптаулары
+Comment[km]=កំណត់​រចនាសម្ព័ន្ធ Kamera
+Comment[ko]=카메라 설정
+Comment[lt]=Konfigūruoti Kamera
+Comment[mk]=Конфигурирајте ја Kamera
+Comment[ms]=Konfigurasi Kamera
+Comment[mt]=Ikkonfigura Kamera
+Comment[nb]=Tilpass Kamera
+Comment[nds]=Kamera instellen
+Comment[ne]=क्यामेरा कन्फिगर गर्नुहोस्
+Comment[nl]=Camera instellen
+Comment[nn]=Set opp Kamera
+Comment[nso]=Beakanya Kamera
+Comment[pa]=ਕੈਮਰਾ ਸੰਰਚਨਾ
+Comment[pl]=Konfiguracja Kamery
+Comment[pt]=Configuração do Kamera
+Comment[pt_BR]=Configurar Kamera
+Comment[ro]=Configurează aparatul foto digital
+Comment[ru]=Настройка камеры
+Comment[se]=Heivet govvenapperáhta
+Comment[sk]=Nastaviť program Kamera
+Comment[sl]=Nastavitve fotoaparata
+Comment[sr]=Подеси Kamera-у
+Comment[sr@Latn]=Podesi Kamera-u
+Comment[sv]=Anpassa kamera
+Comment[ta]=காமிராவை அமை
+Comment[tg]=Танзимоти камера
+Comment[th]=ปรับแต่ง Kamera
+Comment[tr]=Kamera'yı Yapılandır
+Comment[uk]=Налаштувати Kamera
+Comment[uz]=Fotoaparatni moslash
+Comment[uz@cyrillic]=Фотоапаратни мослаш
+Comment[ven]=Dzudzanya kamera
+Comment[xh]=Qwalasela Umfoti
+Comment[zh_CN]=配置 Kamera
+Comment[zh_HK]=設定 Kamera
+Comment[zh_TW]=設定照相機
+Comment[zu]=Hlanganisa ikhamera
+Keywords=gphoto,camera,digicam,webcam,kamera
+Keywords[ar]=gphoto,كاميرا,كاميرا رقمية,كاميرا ويب,kamera
+Keywords[az]=gphoto,kamera,digicam,veb kamera,Kamera,webcam
+Keywords[bg]=фото, апарат, фотоапарат, камера, цифров, цифрова, gphoto, camera, digicam, webcam, kamera
+Keywords[br]=gphoto,kamera,digicam,webcam,kamera
+Keywords[ca]=gphoto,càmera,digicam,webcam,kamera
+Keywords[cs]=gphoto,Kamera,Digitální kamera,Webová kamera,Foto
+Keywords[da]=gphoto,kamera,digicam,webcam
+Keywords[de]=gphoto,Kamera,Digicam,Webcam,Digitalkamera
+Keywords[el]=gphoto,κάμερα,digicam,webcam,kamera
+Keywords[eo]=gphoto,kamerao,fotilo,cifereca fotilo,TTT-fotilo
+Keywords[es]=gphoto,cámara,digicam,webcam,kamera
+Keywords[et]=gphoto,kaamera,digitaalkaamera,veebikaamera,kamera
+Keywords[eu]=gphoto,kamera,digicam,webcam,kamera
+Keywords[fa]=gphoto، دوربین، دوربین رقمی، دوربین وب، kamera
+Keywords[fi]=gphoto,kamera,digicam,webcam
+Keywords[fr]=gphoto,camera,digicam,webcam,kamera,caméscope,caméra,appareil photo
+Keywords[he]=gphoto,kamera,מצלמה,מצלמת רשת,מצלמה דיגיטלית, amera,digicam,webcam
+Keywords[hi]=जीफोटो,केमरा,डिजिकेम,वेबकेम,केमरा
+Keywords[hu]=gphoto,fényképezőgép,digitális fényképezőgép,webkamera,videókamera
+Keywords[is]=gphoto,myndavél,stafræn myndavél,webcam,kamera
+Keywords[it]=gphoto,fotocamera,macchina fotografica digitale,webcam,kamera
+Keywords[ja]=gphoto,カメラ,デジカム,ウェブカム,kamera
+Keywords[km]=gphoto,ម៉ាស៊ីន​ថត​រូប,digicam,ម៉ាស៊ីនថត​តាម​បណ្ដាញ,kamera
+Keywords[ko]=gphoto,camera,digicam,webcam,kamera,사진,카메라,사진기,웹캠
+Keywords[lv]=gfoto,camera,digicam,webcam,kamera
+Keywords[nb]=gphoto,kamera,digicam,webcam,webkamera
+Keywords[nds]=gphoto,Kamera,Webcam,Kamera,Nettkamera
+Keywords[ne]=जी फोटो, क्यामेरा, डिजिक्याम, वेबक्याम, कामेरा
+Keywords[nl]=gphoto,camera,digicam,webcam,kamera,foto
+Keywords[nn]=gphoto,fotoapparat,digitalt kamera,webkamera,vevkamera,kamera
+Keywords[pl]=gphoto,kamera,kamera cyfrowa,kamera sieciowa
+Keywords[pt]=gphoto,câmara,digicam,webcam,kamera
+Keywords[pt_BR]=gphoto,câmera,câmera digital,webcam,kamera
+Keywords[ro]=gphoto,aparat,foto,digicam,webcam,camera,kamera
+Keywords[ru]=gphoto,camera,digicam,webcam,kamera,камера,фото
+Keywords[sl]=gphoto,kamera,digicam,webcam,foto,fotoaparat,spletna kamera
+Keywords[sr]=gphoto,camera,digicam,webcam,kamera,камера
+Keywords[sr@Latn]=gphoto,camera,digicam,webcam,kamera,kamera
+Keywords[sv]=gphoto,kamera,digital kamera,webbkamera,kamera
+Keywords[ta]=ஜிபோட்டோ, காமிரா, டிஜிகேம்,வலைதள காமிரா, காமிரா
+Keywords[tg]=gphoto,camera,digicam,webcam,kamera,камера,фото
+Keywords[tr]=gphoto,kamera,digicam,web kamera,Kamera,webcam
+Keywords[uk]=gphoto,камера,цифрова камера,камера Тенет,kamera
+Keywords[ven]=Tshinepe tsha g,Tshaudzhia zwifanyiso,digicam,webcam,Tshaudzhiazwifanyiso
+Keywords[xh]=gphoto,umfoti,digicam,webcam,umfoti
+Keywords[zh_CN]=gphoto,camera,digicam,webcam,kamera,照相机,数码相机,摄像头
+Keywords[zh_TW]=gphoto,camera,digicam,webcam,kamera,照相機
+Keywords[zu]=gphoto,ikhamera,digicam,webcam,ikhamera
+Name=Digital Camera
+Name[af]=Digitaal Kamera
+Name[ar]=كاميرا رقمية
+Name[az]=Digital Kamera
+Name[bg]=Фотоапарат
+Name[br]=Kamera niverel
+Name[bs]=Digitalna kamera
+Name[ca]=Càmera digital
+Name[cs]=Digitální fotoaparát
+Name[cy]=Camera Digidol
+Name[da]=Digitalt kamera
+Name[de]=Digitalkamera
+Name[el]=Ψηφιακή κάμερα
+Name[eo]=Cifereca fotilo
+Name[es]=Cámara digital
+Name[et]=Digitaalkaamera
+Name[eu]=Kamera digitala
+Name[fa]=دوربین رقمی
+Name[fi]=Digitaalikamera
+Name[fr]=Appareil photo numérique
+Name[ga]=Ceamara Digiteach
+Name[gl]=Cámara dixital
+Name[he]=מצלמה דיגיטלית
+Name[hi]=डिजिटल कैमरा
+Name[hr]=Digitalna kamera
+Name[hu]=Digitális fényképezőgép
+Name[is]=Stafræn myndavél
+Name[it]=Macchina fotografica digitale
+Name[ja]=デジタルカメラ
+Name[kk]=Цифрлық камера
+Name[km]=ម៉ាស៊ីន​ថតរូប​ឌីជីថល
+Name[lt]=Skaitmeninė kamera
+Name[lv]=Digitālā Kamera
+Name[mk]=Дигитална камера
+Name[ms]=Kamera Digital
+Name[mt]=Kamera diġitali
+Name[nb]=Digitalkamera
+Name[nds]=Digitaalkamera
+Name[ne]= डिजिटल क्यामेरा
+Name[nl]=Digitale camera
+Name[nn]=Digitalkamera
+Name[nso]=Camera ya Digital
+Name[pa]=ਡਿਜ਼ੀਟਲ ਕੈਮਰਾ
+Name[pl]=Aparat cyfrowy
+Name[pt]=Máquina Fotográfica Digital
+Name[pt_BR]=Câmera Digital
+Name[ro]=Aparat foto digital
+Name[ru]=Цифровая камера
+Name[se]=Digitalalaš govvenapperáhtta
+Name[sk]=Digitálny fotoaparát
+Name[sl]=Digitalni fotoaparat
+Name[sr]=Дигитална камера
+Name[sr@Latn]=Digitalna kamera
+Name[sv]=Digitalkamera
+Name[ta]= Digital Camera
+Name[tg]=Камераи digital
+Name[th]=กล้องดิจิตอล
+Name[tr]=Sayısal Kamera
+Name[uk]=Цифровий фотоапарат
+Name[uz]=Fotoaparat
+Name[uz@cyrillic]=Фотоапарат
+Name[ven]=Tshau dzhia zwifanyiso tsha didzhithala
+Name[xh]=Ikhamera Yesuntswana
+Name[zh_CN]=数码相机
+Name[zh_HK]=數碼相機
+Name[zh_TW]=數位相機
+Name[zu]=Ikhamera ebonisa inani ngalinye
+Terminal=false
+Type=Application
+X-KDE-Library=kamera
+X-KDE-ModuleType=Library
+Icon=camera
+Exec=kcmshell kamera
+DocPath=kamera/index.html
+Categories=Qt;KDE;Settings;X-KDE-settings-hardware;
diff --git a/kamera/kcontrol/kamera.h b/kamera/kcontrol/kamera.h
new file mode 100644
index 00000000..35f93bc0
--- /dev/null
+++ b/kamera/kcontrol/kamera.h
@@ -0,0 +1,115 @@
+/*
+
+ Copyright (C) 2001 The Kompany
+ 2002-2003 Ilya Konstantinov <kde-devel@future.shiny.co.il>
+ 2002-2003 Marcus Meissner <marcus@jet.franken.de>
+ 2003 Nadeem Hasan <nhasan@nadmm.com>
+
+ 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 __kamera_h__
+#define __kamera_h__
+
+#include <kcmodule.h>
+#include <gphoto2.h>
+
+class QWidget;
+class QRadioButton;
+class QPushButton;
+class QComboBox;
+class QVButtonGroup;
+class QLineEdit;
+class QWidgetStack;
+class QCheckBox;
+class QIconViewItem;
+
+class KCamera;
+class KameraDeviceSelectDialog;
+class KSimpleConfig;
+class KIconView;
+class KActionCollection;
+class KToolBar;
+class KPopupMenu;
+
+class KKameraConfig : public KCModule
+{
+ Q_OBJECT
+ friend class KameraDeviceSelectDialog;
+
+public:
+ KKameraConfig(QWidget *parent, const char *name, const QStringList &);
+ virtual ~KKameraConfig();
+
+ // KCModule interface methods
+ void load();
+ void load(bool useDefaults);
+ void save();
+ void defaults();
+ int buttons();
+ QString quickHelp() const;
+
+protected:
+ QString suggestName(const QString &name);
+
+protected slots:
+ void slot_deviceMenu(QIconViewItem *item, const QPoint &point);
+ void slot_deviceSelected(QIconViewItem *item);
+ void slot_addCamera();
+ void slot_removeCamera();
+ void slot_configureCamera();
+ void slot_cameraSummary();
+ void slot_testCamera();
+ void slot_cancelOperation();
+ void slot_error(const QString &message);
+ void slot_error(const QString &message, const QString &details);
+
+private:
+ void displayGPFailureDialogue(void);
+ void displayGPSuccessDialogue(void);
+ void displayCameraAbilities(const CameraAbilities &abilities);
+ void populateDeviceListView(void);
+ void beforeCameraOperation(void);
+ void afterCameraOperation(void);
+
+ // gphoto callbacks
+ static void cbGPIdle(GPContext *context, void *data);
+ static GPContextFeedback cbGPCancel(GPContext *context, void *data);
+
+private:
+ typedef QMap<QString, KCamera *> CameraDevicesMap;
+
+ KSimpleConfig *m_config;
+ CameraDevicesMap m_devices;
+ bool m_cancelPending;
+
+ // gphoto members
+ GPContext *m_context;
+
+ // widgets for the cameras listview
+ KIconView *m_deviceSel;
+ KActionCollection *m_actions;
+ QPushButton *m_addCamera, *m_removeCamera, *m_testCamera, *m_configureCamera;
+ KToolBar *m_toolbar;
+ KPopupMenu *m_devicePopup;
+
+ // true if libgphoto2 was initialised successfully in
+ // the constructor
+ bool m_gpInitialised;
+
+ static KKameraConfig *m_instance;
+};
+
+#endif
diff --git a/kamera/kcontrol/kameraconfigdialog.cpp b/kamera/kcontrol/kameraconfigdialog.cpp
new file mode 100644
index 00000000..5af0b33d
--- /dev/null
+++ b/kamera/kcontrol/kameraconfigdialog.cpp
@@ -0,0 +1,317 @@
+/*
+
+ Copyright (C) 2001 The Kompany
+ 2002-2003 Ilya Konstantinov <kde-devel@future.shiny.co.il>
+ 2002-2003 Marcus Meissner <marcus@jet.franken.de>
+ 2003 Nadeem Hasan <nhasan@nadmm.com>
+
+ 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 <qlayout.h>
+#include <qgrid.h>
+#include <qlabel.h>
+#include <qvgroupbox.h>
+#include <qcheckbox.h>
+#include <qradiobutton.h>
+#include <qlineedit.h>
+#include <qcombobox.h>
+#include <qslider.h>
+#include <qvbuttongroup.h>
+#include <qhbuttongroup.h>
+#include <qvbox.h>
+#include <qtabwidget.h>
+#include <qwhatsthis.h>
+
+#include <klocale.h>
+
+#include "kameraconfigdialog.h"
+#include "kameraconfigdialog.moc"
+
+KameraConfigDialog::KameraConfigDialog(Camera */*camera*/,
+ CameraWidget *widget,
+ QWidget *parent,
+ const char *name) :
+KDialogBase(parent, name, true, QString::null, Ok|Cancel, Ok ),
+m_widgetRoot(widget)
+{
+ QFrame *main = makeMainWidget();
+ QVBoxLayout *topLayout = new QVBoxLayout(main, 0, spacingHint());
+ topLayout->setAutoAdd(true);
+
+ m_tabWidget = 0;
+
+ appendWidget(main, widget);
+}
+
+void KameraConfigDialog::appendWidget(QWidget *parent, CameraWidget *widget)
+{
+ QWidget *newParent = parent;
+
+ CameraWidgetType widget_type;
+ const char *widget_name;
+ const char *widget_info;
+ const char *widget_label;
+ float widget_value_float;
+ int widget_value_int;
+ const char *widget_value_string;
+ gp_widget_get_type(widget, &widget_type);
+ gp_widget_get_label(widget, &widget_label);
+ gp_widget_get_info(widget, &widget_info);
+ gp_widget_get_name(widget, &widget_name);
+
+ QString whats_this = QString::fromLocal8Bit(widget_info); // gphoto2 doesn't seem to have any standard for i18n
+
+ // Add this widget to parent
+ switch(widget_type) {
+ case GP_WIDGET_WINDOW:
+ {
+ setCaption(widget_label);
+
+ break;
+ }
+ case GP_WIDGET_SECTION:
+ {
+ if (!m_tabWidget)
+ m_tabWidget = new QTabWidget(parent);
+ QWidget *tab = new QWidget(m_tabWidget);
+ // widgets are to be aligned vertically in the tab
+ QVBoxLayout *tabLayout = new QVBoxLayout(tab, marginHint(),
+ spacingHint());
+ m_tabWidget->insertTab(tab, widget_label);
+ QVBox *tabContainer = new QVBox(tab);
+ tabContainer->setSpacing(spacingHint());
+ tabLayout->addWidget(tabContainer);
+ newParent = tabContainer;
+
+ tabLayout->addStretch();
+
+ break;
+ }
+ case GP_WIDGET_TEXT:
+ {
+ gp_widget_get_value(widget, &widget_value_string);
+
+ QGrid *grid = new QGrid(2, Horizontal, parent);
+ grid->setSpacing(spacingHint());
+ new QLabel(QString::fromLocal8Bit( widget_label )+":", grid);
+ QLineEdit *lineEdit = new QLineEdit(widget_value_string, grid);
+ m_wmap.insert(widget, lineEdit);
+
+ if (!whats_this.isEmpty())
+ QWhatsThis::add(grid, whats_this);
+
+ break;
+ }
+ case GP_WIDGET_RANGE:
+ {
+ float widget_low;
+ float widget_high;
+ float widget_increment;
+ gp_widget_get_range(widget, &widget_low, &widget_high, &widget_increment);
+ gp_widget_get_value(widget, &widget_value_float);
+
+ QGroupBox *groupBox = new QVGroupBox(widget_label, parent);
+ QSlider *slider = new QSlider(
+ ( int )widget_low,
+ ( int )widget_high,
+ ( int )widget_increment,
+ ( int )widget_value_float,
+ QSlider::Horizontal,
+ groupBox );
+ m_wmap.insert(widget, slider);
+
+ if (!whats_this.isEmpty())
+ QWhatsThis::add(groupBox, whats_this);
+
+ break;
+ }
+ case GP_WIDGET_TOGGLE:
+ {
+ gp_widget_get_value(widget, &widget_value_int);
+
+ QCheckBox *checkBox = new QCheckBox(widget_label, parent);
+ checkBox->setChecked(widget_value_int);
+ m_wmap.insert(widget, checkBox);
+
+ if (!whats_this.isEmpty())
+ QWhatsThis::add(checkBox, whats_this);
+
+ break;
+ }
+ case GP_WIDGET_RADIO:
+ {
+ gp_widget_get_value(widget, &widget_value_string);
+
+ int count = gp_widget_count_choices(widget);
+
+ // for less than 5 options, align them horizontally
+ QButtonGroup *buttonGroup;
+ if (count > 4)
+ buttonGroup = new QVButtonGroup(widget_label, parent);
+ else
+ buttonGroup = new QHButtonGroup(widget_label, parent);
+
+ for(int i = 0; i < count; ++i) {
+ const char *widget_choice;
+ gp_widget_get_choice(widget, i, &widget_choice);
+
+ new QRadioButton(widget_choice, buttonGroup);
+ if(!strcmp(widget_value_string, widget_choice))
+ buttonGroup->setButton(i);
+ }
+ m_wmap.insert(widget, buttonGroup);
+
+ if (!whats_this.isEmpty())
+ QWhatsThis::add(buttonGroup, whats_this);
+
+ break;
+ }
+ case GP_WIDGET_MENU:
+ {
+ gp_widget_get_value(widget, &widget_value_string);
+
+ QComboBox *comboBox = new QComboBox(FALSE, parent);
+ comboBox->clear();
+ for(int i = 0; i < gp_widget_count_choices(widget); ++i) {
+ const char *widget_choice;
+ gp_widget_get_choice(widget, i, &widget_choice);
+
+ comboBox->insertItem(widget_choice);
+ if(!strcmp(widget_value_string, widget_choice))
+ comboBox->setCurrentItem(i);
+ }
+ m_wmap.insert(widget, comboBox);
+
+ if (!whats_this.isEmpty())
+ QWhatsThis::add(comboBox, whats_this);
+
+ break;
+ }
+ case GP_WIDGET_BUTTON:
+ {
+ // TODO
+ // I can't see a way of implementing this. Since there is
+ // no way of telling which button sent you a signal, we
+ // can't map to the appropriate widget->callback
+ new QLabel(i18n("Button (not supported by KControl)"), parent);
+
+ break;
+ }
+ case GP_WIDGET_DATE:
+ {
+ // TODO
+ new QLabel(i18n("Date (not supported by KControl)"), parent);
+
+ break;
+ }
+ default:
+ return;
+ }
+
+ // Append all this widgets children
+ for(int i = 0; i < gp_widget_count_children(widget); ++i) {
+ CameraWidget *widget_child;
+ gp_widget_get_child(widget, i, &widget_child);
+ appendWidget(newParent, widget_child);
+ }
+
+ // Things that must be done after all children were added
+/*
+ switch (widget_type) {
+ case GP_WIDGET_SECTION:
+ {
+ tabLayout->addItem( new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding) );
+ break;
+ }
+ }
+*/
+}
+
+void KameraConfigDialog::updateWidgetValue(CameraWidget *widget)
+{
+ CameraWidgetType widget_type;
+ gp_widget_get_type(widget, &widget_type);
+
+ switch(widget_type) {
+ case GP_WIDGET_WINDOW:
+ // nothing to do
+ break;
+ case GP_WIDGET_SECTION:
+ // nothing to do
+ break;
+ case GP_WIDGET_TEXT:
+ {
+ QLineEdit *lineEdit = static_cast<QLineEdit *>(m_wmap[widget]);
+ gp_widget_set_value(widget, (void *)lineEdit->text().local8Bit().data());
+
+ break;
+ }
+ case GP_WIDGET_RANGE:
+ {
+ QSlider *slider = static_cast<QSlider *>(m_wmap[widget]);
+ float value_float = slider->value();
+ gp_widget_set_value(widget, (void *)&value_float);
+
+ break;
+ }
+ case GP_WIDGET_TOGGLE:
+ {
+ QCheckBox *checkBox = static_cast<QCheckBox *>(m_wmap[widget]);
+ int value_int = checkBox->isChecked() ? 1 : 0;
+ gp_widget_set_value(widget, (void *)&value_int);
+
+ break;
+ }
+ case GP_WIDGET_RADIO:
+ {
+ QButtonGroup *buttonGroup = static_cast<QVButtonGroup *>(m_wmap[widget]);
+ gp_widget_set_value(widget, (void *)buttonGroup->selected()->text().local8Bit().data());
+
+ break;
+ }
+ case GP_WIDGET_MENU:
+ {
+ QComboBox *comboBox = static_cast<QComboBox *>(m_wmap[widget]);
+ gp_widget_set_value(widget, (void *)comboBox->currentText().local8Bit().data());
+
+ break;
+ }
+ case GP_WIDGET_BUTTON:
+ // nothing to do
+ break;
+ case GP_WIDGET_DATE:
+ {
+ // not implemented
+ break;
+ }
+ }
+
+ // Copy child widget values
+ for(int i = 0; i < gp_widget_count_children(widget); ++i) {
+ CameraWidget *widget_child;
+ gp_widget_get_child(widget, i, &widget_child);
+ updateWidgetValue(widget_child);
+ }
+}
+
+void KameraConfigDialog::slotOk()
+{
+ // Copy Qt widget values into CameraWidget hierarchy
+ updateWidgetValue(m_widgetRoot);
+
+ // 'ok' dialog
+ accept();
+}
diff --git a/kamera/kcontrol/kameraconfigdialog.h b/kamera/kcontrol/kameraconfigdialog.h
new file mode 100644
index 00000000..73b2a012
--- /dev/null
+++ b/kamera/kcontrol/kameraconfigdialog.h
@@ -0,0 +1,53 @@
+/*
+
+ Copyright (C) 2001 The Kompany
+ 2002-2003 Ilya Konstantinov <kde-devel@future.shiny.co.il>
+ 2002-2003 Marcus Meissner <marcus@jet.franken.de>
+ 2003 Nadeem Hasan <nhasan@nadmm.com>
+
+ 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 __kameraconfigdialog_h__
+#define __kameraconfigdialog_h__
+
+#include <qmap.h>
+#include <kdialogbase.h>
+#include <qtabwidget.h>
+
+extern "C" {
+ #include <gphoto2.h>
+}
+
+class KameraConfigDialog : public KDialogBase
+{
+ Q_OBJECT
+public:
+ KameraConfigDialog(Camera *camera, CameraWidget *widget,
+ QWidget *parent = 0, const char *name = 0);
+
+private slots:
+ void slotOk();
+
+private:
+ void appendWidget(QWidget *parent, CameraWidget *widget);
+ void updateWidgetValue(CameraWidget *widget);
+
+ QMap<CameraWidget *, QWidget *> m_wmap;
+ CameraWidget *m_widgetRoot;
+ QTabWidget *m_tabWidget;
+};
+
+#endif
diff --git a/kamera/kcontrol/kameradevice.cpp b/kamera/kcontrol/kameradevice.cpp
new file mode 100644
index 00000000..010bf694
--- /dev/null
+++ b/kamera/kcontrol/kameradevice.cpp
@@ -0,0 +1,476 @@
+/*
+
+ Copyright (C) 2001 The Kompany
+ 2002-2003 Ilya Konstantinov <kde-devel@future.shiny.co.il>
+ 2002-2003 Marcus Meissner <marcus@jet.franken.de>
+ 2003 Nadeem Hasan <nhasan@nadmm.com>
+
+ 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 <qlayout.h>
+#include <qwidgetstack.h>
+#include <qvbuttongroup.h>
+#include <qvgroupbox.h>
+#include <qcombobox.h>
+#include <qlineedit.h>
+#include <qradiobutton.h>
+#include <qwhatsthis.h>
+#include <qlabel.h>
+#include <qgrid.h>
+
+#include <klocale.h>
+#include <kconfig.h>
+#include <klistview.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+
+extern "C" {
+ #include <gphoto2.h>
+}
+
+#include "kamera.h"
+#include "kameraconfigdialog.h"
+#include "kameradevice.moc"
+
+// Define some parts of the old API
+#define GP_PROMPT_OK 0
+#define GP_PROMPT_CANCEL -1
+
+static const int INDEX_NONE= 0;
+static const int INDEX_SERIAL = 1;
+static const int INDEX_USB= 3;
+static GPContext *glob_context = 0;
+
+KCamera::KCamera(const QString &name, const QString &path)
+{
+ m_name = name;
+ m_model = name;
+ m_path = path;
+ m_camera = NULL;
+}
+
+KCamera::~KCamera()
+{
+ if(m_camera)
+ gp_camera_free(m_camera);
+ if(m_abilitylist)
+ gp_abilities_list_free(m_abilitylist);
+}
+
+bool KCamera::initInformation()
+{
+ if (!m_model)
+ return false;
+
+ if(gp_abilities_list_new(&m_abilitylist) != GP_OK) {
+ emit error(i18n("Could not allocate memory for abilities list."));
+ return false;
+ }
+ if(gp_abilities_list_load(m_abilitylist, glob_context) != GP_OK) {
+ emit error(i18n("Could not load ability list."));
+ return false;
+ }
+ int index = gp_abilities_list_lookup_model(m_abilitylist, m_model.local8Bit().data());
+ if(index < 0) {
+ emit error(i18n("Description of abilities for camera %1 is not available."
+ " Configuration options may be incorrect.").arg(m_model));
+ return false;
+ }
+ gp_abilities_list_get_abilities(m_abilitylist, index, &m_abilities);
+ return true;
+}
+
+bool KCamera::initCamera()
+{
+ if (m_camera)
+ return m_camera;
+ else {
+ int result;
+
+ initInformation();
+
+ if (!m_model || !m_path)
+ return false;
+
+ result = gp_camera_new(&m_camera);
+ if (result != GP_OK) {
+ // m_camera is not initialized, so we cannot get result as string
+ emit error(i18n("Could not access driver. Check your gPhoto2 installation."));
+ return false;
+ }
+
+ // set the camera's model
+ GPPortInfo info;
+ GPPortInfoList *il;
+ gp_port_info_list_new(&il);
+ gp_port_info_list_load(il);
+ gp_port_info_list_get_info(il, gp_port_info_list_lookup_path(il, m_path.local8Bit().data()), &info);
+ gp_port_info_list_free(il);
+ gp_camera_set_abilities(m_camera, m_abilities);
+ gp_camera_set_port_info(m_camera, info);
+
+ // this might take some time (esp. for non-existant camera) - better be done asynchronously
+ result = gp_camera_init(m_camera, glob_context);
+ if (result != GP_OK) {
+ gp_camera_free(m_camera);
+ m_camera = NULL;
+ emit error(
+ i18n("Unable to initialize camera. Check your port settings and camera connectivity and try again."),
+ gp_result_as_string(result));
+ return false;
+ }
+
+ return m_camera;
+ }
+}
+
+Camera* KCamera::camera()
+{
+ initCamera();
+ return m_camera;
+}
+
+QString KCamera::summary()
+{
+ int result;
+ CameraText summary;
+
+ initCamera();
+
+ result = gp_camera_get_summary(m_camera, &summary, glob_context);
+ if (result != GP_OK)
+ return i18n("No camera summary information is available.\n");
+ return QString(summary.text);
+}
+
+bool KCamera::configure()
+{
+ CameraWidget *window;
+ int result;
+
+ initCamera();
+
+ result = gp_camera_get_config(m_camera, &window, glob_context);
+ if (result != GP_OK) {
+ emit error(i18n("Camera configuration failed."), gp_result_as_string(result));
+ return false;
+ }
+
+ KameraConfigDialog kcd(m_camera, window);
+ result = kcd.exec() ? GP_PROMPT_OK : GP_PROMPT_CANCEL;
+
+ if (result == GP_PROMPT_OK) {
+ result = gp_camera_set_config(m_camera, window, glob_context);
+ if (result != GP_OK) {
+ emit error(i18n("Camera configuration failed."), gp_result_as_string(result));
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool KCamera::test()
+{
+ // TODO: Make testing non-blocking (maybe via KIO?)
+ // Currently, a failed serial test times out at about 30 sec.
+ return camera() != 0;
+}
+
+void KCamera::load(KConfig *config)
+{
+ config->setGroup(m_name);
+ if (m_model.isNull())
+ m_model = config->readEntry("Model");
+ if (m_path.isNull())
+ m_path = config->readEntry("Path");
+ invalidateCamera();
+}
+
+void KCamera::save(KConfig *config)
+{
+ config->setGroup(m_name);
+ config->writeEntry("Model", m_model);
+ config->writeEntry("Path", m_path);
+}
+
+QString KCamera::portName()
+{
+ QString port = m_path.left(m_path.find(":")).lower();
+ if (port == "serial") return i18n("Serial");
+ if (port == "usb") return i18n("USB");
+ return i18n("Unknown port");
+}
+
+void KCamera::setName(const QString &name)
+{
+ m_name = name;
+}
+
+void KCamera::setModel(const QString &model)
+{
+ m_model = model;
+ invalidateCamera();
+ initInformation();
+}
+
+void KCamera::setPath(const QString &path)
+{
+ m_path = path;
+ invalidateCamera();
+}
+
+void KCamera::invalidateCamera()
+{
+ if (m_camera) {
+ gp_camera_free(m_camera);
+ m_camera = NULL;
+ }
+}
+
+bool KCamera::isTestable() const
+{
+ return true;
+}
+
+bool KCamera::isConfigurable()
+{
+ initInformation();
+ return m_abilities.operations & GP_OPERATION_CONFIG;
+}
+
+QStringList KCamera::supportedPorts()
+{
+ initInformation();
+ QStringList ports;
+ if (m_abilities.port & GP_PORT_SERIAL)
+ ports.append("serial");
+ if (m_abilities.port & GP_PORT_USB)
+ ports.append("usb");
+ return ports;
+}
+
+CameraAbilities KCamera::abilities()
+{
+ return m_abilities;
+}
+
+// ---------- KameraSelectCamera ------------
+
+KameraDeviceSelectDialog::KameraDeviceSelectDialog(QWidget *parent, KCamera *device)
+ : KDialogBase(parent, "kkameradeviceselect", true, i18n("Select Camera Device"), Ok | Cancel, Ok, true)
+{
+ m_device = device;
+ connect(m_device, SIGNAL(error(const QString &)),
+ SLOT(slot_error(const QString &)));
+ connect(m_device, SIGNAL(error(const QString &, const QString &)),
+ SLOT(slot_error(const QString &, const QString &)));
+
+ QWidget *page = new QWidget( this );
+ setMainWidget(page);
+
+ // a layout with vertical boxes
+ QHBoxLayout *topLayout = new QHBoxLayout(page, 0, KDialog::spacingHint());
+
+ // the models list
+ m_modelSel = new KListView(page);
+ topLayout->addWidget( m_modelSel );
+ m_modelSel->addColumn(i18n("Supported Cameras"));
+ m_modelSel->setColumnWidthMode(0, QListView::Maximum);
+ connect(m_modelSel, SIGNAL(selectionChanged(QListViewItem *)),
+ SLOT(slot_setModel(QListViewItem *)));
+ // make sure listview only as wide as it needs to be
+ m_modelSel->setSizePolicy(QSizePolicy(QSizePolicy::Maximum,
+ QSizePolicy::Preferred));
+
+ QVBoxLayout *rightLayout = new QVBoxLayout(0L, 0, KDialog::spacingHint());
+ topLayout->addLayout( rightLayout );
+
+ m_portSelectGroup = new QVButtonGroup(i18n("Port"), page);
+ rightLayout->addWidget(m_portSelectGroup);
+ m_portSettingsGroup = new QVGroupBox(i18n("Port Settings"), page);
+ rightLayout->addWidget(m_portSettingsGroup);
+
+ // Create port type selection radiobuttons.
+ m_serialRB = new QRadioButton(i18n("Serial"), m_portSelectGroup);
+ m_portSelectGroup->insert(m_serialRB, INDEX_SERIAL);
+ QWhatsThis::add(m_serialRB, i18n("If this option is checked, the camera would have to be connected one of the serial ports (known as COM in Microsoft Windows) in your computer."));
+ m_USBRB = new QRadioButton(i18n("USB"), m_portSelectGroup);
+ m_portSelectGroup->insert(m_USBRB, INDEX_USB);
+ QWhatsThis::add(m_USBRB, i18n("If this option is checked, the camera would have to be connected to one of the USB slots in your computer or USB hub."));
+ // Create port settings widget stack
+ m_settingsStack = new QWidgetStack(m_portSettingsGroup);
+ connect(m_portSelectGroup, SIGNAL(clicked(int)),
+ m_settingsStack, SLOT(raiseWidget(int)));
+
+ // none tab
+ m_settingsStack->addWidget(new QLabel(i18n("No port type selected."),
+ m_settingsStack), INDEX_NONE);
+
+ // serial tab
+ QGrid *grid = new QGrid(2, m_settingsStack);
+ grid->setSpacing(KDialog::spacingHint());
+ new QLabel(i18n("Port:"), grid);
+ m_serialPortCombo = new QComboBox(TRUE, grid);
+ QWhatsThis::add(m_serialPortCombo, i18n("Here you should choose the serial port you connect the camera to."));
+ m_settingsStack->addWidget(grid, INDEX_SERIAL);
+
+ grid = new QGrid(2, m_settingsStack);
+ grid->setSpacing(KDialog::spacingHint());
+ new QLabel(i18n("Port"), grid);
+
+ m_settingsStack->addWidget(new
+ QLabel(i18n("No further configuration is required for USB."),
+ m_settingsStack), INDEX_USB);
+
+ // query gphoto2 for existing serial ports
+ GPPortInfoList *list;
+ GPPortInfo info;
+ int gphoto_ports=0;
+ gp_port_info_list_new(&list);
+ if(gp_port_info_list_load(list) >= 0) {
+ gphoto_ports = gp_port_info_list_count(list);
+ }
+ for (int i = 0; i < gphoto_ports; i++) {
+ if (gp_port_info_list_get_info(list, i, &info) >= 0) {
+ if (strncmp(info.path, "serial:", 7) == 0)
+ m_serialPortCombo->insertItem(QString::fromLatin1(info.path).mid(7));
+ }
+ }
+ gp_port_info_list_free(list);
+
+ // add a spacer
+ rightLayout->addStretch();
+
+ populateCameraListView();
+ load();
+
+ enableButtonOK(false );
+ m_portSelectGroup->setEnabled( false );
+ m_portSettingsGroup->setEnabled( false );
+}
+
+bool KameraDeviceSelectDialog::populateCameraListView()
+{
+ gp_abilities_list_new (&m_device->m_abilitylist);
+ gp_abilities_list_load(m_device->m_abilitylist, glob_context);
+ int numCams = gp_abilities_list_count(m_device->m_abilitylist);
+ CameraAbilities a;
+
+ if(numCams < 0) {
+ // XXX libgphoto2 failed to get te camera list
+ return false;
+ } else {
+ for(int x = 0; x < numCams; ++x) {
+ if(gp_abilities_list_get_abilities(m_device->m_abilitylist, x, &a) == GP_OK) {
+ new QListViewItem(m_modelSel, a.model);
+ }
+ }
+ return true;
+ }
+}
+
+void KameraDeviceSelectDialog::save()
+{
+ m_device->setModel(m_modelSel->currentItem()->text(0));
+
+ if (m_portSelectGroup->selected()) {
+ QString type = m_portSelectGroup->selected()->text();
+
+ if(type == i18n("Serial"))
+ m_device->setPath("serial:" + m_serialPortCombo->currentText());
+ else if(type == i18n("USB"))
+ m_device->setPath("usb:");
+ } else {
+ // This camera has no port type (e.g. "Directory Browse" camera).
+ // Do nothing.
+ }
+}
+
+void KameraDeviceSelectDialog::load()
+{
+ QString path = m_device->path();
+ QString port = path.left(path.find(":")).lower();
+
+ if (port == "serial") setPortType(INDEX_SERIAL);
+ if (port == "usb") setPortType(INDEX_USB);
+
+ QListViewItem *modelItem = m_modelSel->firstChild();
+ if( modelItem)
+ {
+ do {
+ if (modelItem->text(0) == m_device->model()) {
+ m_modelSel->setSelected(modelItem, true);
+ m_modelSel->ensureItemVisible(modelItem);
+ }
+ } while ( ( modelItem = modelItem->nextSibling() ) );
+ }
+}
+
+void KameraDeviceSelectDialog::slot_setModel(QListViewItem *item)
+{
+ enableButtonOK(true);
+ m_portSelectGroup->setEnabled(true);
+ m_portSettingsGroup->setEnabled(true);
+
+ QString model = item->text(0);
+
+ CameraAbilities abilities;
+ int index = gp_abilities_list_lookup_model(m_device->m_abilitylist, model.local8Bit().data());
+ if(index < 0) {
+ slot_error(i18n("Description of abilities for camera %1 is not available."
+ " Configuration options may be incorrect.").arg(model));
+ }
+ int result = gp_abilities_list_get_abilities(m_device->m_abilitylist, index, &abilities);
+ if (result == GP_OK) {
+ // enable radiobuttons for supported port types
+ m_serialRB->setEnabled(abilities.port & GP_PORT_SERIAL);
+ m_USBRB->setEnabled(abilities.port & GP_PORT_USB);
+
+ // turn off any selected port
+ QButton *selected = m_portSelectGroup->selected();
+ if(selected != NULL)
+ selected->toggle();
+
+ // if there's only one available port type, make sure it's selected
+ if (abilities.port == GP_PORT_SERIAL)
+ setPortType(INDEX_SERIAL);
+ if (abilities.port == GP_PORT_USB)
+ setPortType(INDEX_USB);
+ } else {
+ slot_error(i18n("Description of abilities for camera %1 is not available."
+ " Configuration options may be incorrect.").arg(model));
+ }
+}
+
+void KameraDeviceSelectDialog::setPortType(int type)
+{
+ // Enable the correct button
+ m_portSelectGroup->setButton(type);
+
+ // Bring the right tab to the front
+ m_settingsStack->raiseWidget(type);
+}
+
+void KameraDeviceSelectDialog::slot_error(const QString &message)
+{
+ KMessageBox::error(this, message);
+}
+
+void KameraDeviceSelectDialog::slot_error(const QString &message, const QString &details)
+{
+ KMessageBox::detailedError(this, message, details);
+}
diff --git a/kamera/kcontrol/kameradevice.h b/kamera/kcontrol/kameradevice.h
new file mode 100644
index 00000000..aae24e02
--- /dev/null
+++ b/kamera/kcontrol/kameradevice.h
@@ -0,0 +1,117 @@
+/*
+
+ Copyright (C) 2001 The Kompany
+ 2002-2003 Ilya Konstantinov <kde-devel@future.shiny.co.il>
+ 2002-2003 Marcus Meissner <marcus@jet.franken.de>
+ 2003 Nadeem Hasan <nhasan@nadmm.com>
+
+ 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 __kameradevice_h__
+#define __kameradevice_h__
+
+#include <qmap.h>
+#include <kdialogbase.h>
+#include <config.h>
+
+class KConfig;
+class QString;
+class KListView;
+class QWidgetStack;
+class QVButtonGroup;
+class QVGroupBox;
+class QComboBox;
+class QLineEdit;
+class QRadioButton;
+
+class KCamera : public QObject {
+ friend class KameraDeviceSelectDialog;
+ Q_OBJECT
+public:
+ KCamera(const QString &name, const QString &path);
+ ~KCamera();
+ void invalidateCamera();
+ bool configure();
+ void load(KConfig *m_config);
+ void save(KConfig *m_config);
+ bool test();
+ QStringList supportedPorts();
+
+ Camera* camera();
+ QString name() const { return m_name ; }
+ QString model() const { return m_model; }
+ QString path() const { return m_path; }
+ QString portName();
+
+ QString summary();
+ CameraAbilities abilities();
+
+ void setName(const QString &name);
+ void setModel(const QString &model);
+ void setPath(const QString &path);
+
+ bool isTestable() const;
+ bool isConfigurable();
+
+signals:
+ void error(const QString &message);
+ void error(const QString &message, const QString &details);
+
+protected:
+ bool initInformation();
+ bool initCamera();
+// void doConfigureCamera(Camera *camera, CameraWidget *widgets);
+// int frontend_prompt(Camera *camera, CameraWidget *widgets);
+
+ Camera *m_camera;
+// KConfig *m_config;
+ QString m_name; // the camera's real name
+ QString m_model;
+ QString m_path;
+ CameraAbilities m_abilities;
+ CameraAbilitiesList *m_abilitylist;
+};
+
+class KameraDeviceSelectDialog : public KDialogBase
+{
+ Q_OBJECT
+public:
+ KameraDeviceSelectDialog(QWidget *parent, KCamera *device);
+ void save();
+ void load();
+protected slots:
+ void slot_setModel(QListViewItem *item);
+ void slot_error(const QString &message);
+ void slot_error(const QString &message, const QString &details);
+protected:
+ KCamera *m_device;
+
+ bool populateCameraListView(void);
+ void setPortType(int type);
+
+ // port settings widgets
+ KListView *m_modelSel;
+ QLineEdit *m_nameEdit;
+ QWidgetStack *m_settingsStack;
+ QVButtonGroup *m_portSelectGroup;
+ QVGroupBox *m_portSettingsGroup;
+ QComboBox *m_serialPortCombo;
+ // port selection radio buttons
+ QRadioButton *m_serialRB;
+ QRadioButton *m_USBRB;
+};
+
+#endif
diff --git a/kamera/kioslave/Makefile.am b/kamera/kioslave/Makefile.am
new file mode 100644
index 00000000..4c6c148e
--- /dev/null
+++ b/kamera/kioslave/Makefile.am
@@ -0,0 +1,17 @@
+# $Id$
+# Makefile for kdebase/kioslave/kamera
+
+INCLUDES= -I$(srcdir)/../.. -I$(srcdir)/.. $(all_includes) $(GPHOTO2_INCS)
+
+####### Files
+
+kde_module_LTLIBRARIES = kio_kamera.la
+
+kio_kamera_la_SOURCES = kamera.cpp
+kio_kamera_la_LIBADD = $(LIB_KIO) -lgphoto2
+kio_kamera_la_LDFLAGS = $(all_libraries) $(GPHOTO2_LIBS) -module $(KDE_PLUGIN)
+
+noinst_HEADERS = kamera.h
+
+kde_services_DATA = camera.protocol
+
diff --git a/kamera/kioslave/camera.protocol b/kamera/kioslave/camera.protocol
new file mode 100644
index 00000000..947d02b9
--- /dev/null
+++ b/kamera/kioslave/camera.protocol
@@ -0,0 +1,16 @@
+[Protocol]
+exec=kio_kamera
+protocol=camera
+input=none
+output=filesystem
+listing=Name,Type
+reading=true
+writing=false
+deleting=true
+source=true
+makedir=false
+linking=false
+moving=false
+Icon=camera
+maxInstances=1
+Class=:local
diff --git a/kamera/kioslave/kamera.cpp b/kamera/kioslave/kamera.cpp
new file mode 100644
index 00000000..ab4eb469
--- /dev/null
+++ b/kamera/kioslave/kamera.cpp
@@ -0,0 +1,1066 @@
+/*
+
+ Copyright (C) 2001 The Kompany
+ 2001-2003 Ilya Konstantinov <kde-devel@future.shiny.co.il>
+ 2001-2007 Marcus Meissner <marcus@jet.franken.de>
+
+ 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 <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <errno.h>
+
+#include <qfile.h>
+#include <qtextstream.h>
+
+#include <kdebug.h>
+#include <kinstance.h>
+#include <kstandarddirs.h>
+#include <kconfig.h>
+#include <ksimpleconfig.h>
+#include <klocale.h>
+#include <kprotocolinfo.h>
+#include <kio/slaveconfig.h>
+
+#include <config.h>
+
+#include "kamera.h"
+
+#define MAXIDLETIME 30 /* seconds */
+
+#define tocstr(x) ((x).local8Bit())
+
+using namespace KIO;
+
+extern "C"
+{
+ KDE_EXPORT int kdemain(int argc, char **argv);
+
+ static void frontendCameraStatus(GPContext *context, const char *format, va_list args, void *data);
+ static unsigned int frontendProgressStart(
+ GPContext *context, float totalsize, const char *format,
+ va_list args, void *data
+ );
+ static void frontendProgressUpdate(
+ GPContext *context, unsigned int id, float current, void *data
+ );
+}
+
+int kdemain(int argc, char **argv)
+{
+ KInstance instance("kio_kamera");
+
+ if(argc != 4) {
+ kdDebug(7123) << "Usage: kio_kamera protocol "
+ "domain-socket1 domain-socket2" << endl;
+ exit(-1);
+ }
+ KameraProtocol slave(argv[2], argv[3]);
+ slave.dispatchLoop();
+ return 0;
+}
+
+KameraProtocol::KameraProtocol(const QCString &pool, const QCString &app)
+: SlaveBase("camera", pool, app),
+m_camera(NULL)
+{
+ // attempt to initialize libgphoto2 and chosen camera (requires locking)
+ // (will init m_camera, since the m_camera's configuration is empty)
+ m_camera = 0;
+ m_file = NULL;
+ m_config = new KSimpleConfig(KProtocolInfo::config("camera"));
+ m_context = gp_context_new();
+ actiondone = true;
+ cameraopen = false;
+ m_lockfile = locateLocal("tmp", "kamera");
+ idletime = 0;
+}
+
+// This handler is getting called every second. We use it to do the
+// delayed close of the camera.
+// Logic is:
+// - No more requests in the queue (signaled by actiondone) AND
+// - We are MAXIDLETIME seconds idle OR
+// - Another slave wants to have access to the camera.
+//
+// The existance of a lockfile is used to signify "please give up camera".
+//
+void KameraProtocol::special(const QByteArray&) {
+ kdDebug(7123) << "KameraProtocol::special() at " << getpid() << endl;
+
+ if (!actiondone && cameraopen) {
+ struct stat stbuf;
+ if ((-1!=::stat(m_lockfile.utf8(),&stbuf)) || (idletime++ >= MAXIDLETIME)) {
+ kdDebug(7123) << "KameraProtocol::special() closing camera." << endl;
+ closeCamera();
+ setTimeoutSpecialCommand(-1);
+ } else {
+ // continue to wait
+ setTimeoutSpecialCommand(1);
+ }
+ } else {
+ // We let it run until the slave gets no actions anymore.
+ setTimeoutSpecialCommand(1);
+ }
+ actiondone = false;
+}
+
+KameraProtocol::~KameraProtocol()
+{
+ kdDebug(7123) << "KameraProtocol::~KameraProtocol()" << endl;
+ delete m_config;
+ if(m_camera) {
+ closeCamera();
+ gp_camera_free(m_camera);
+ m_camera = NULL;
+ }
+}
+
+// initializes the camera for usage - should be done before operations over the wire
+bool KameraProtocol::openCamera(QString &str) {
+ idletime = 0;
+ actiondone = true;
+ if (!m_camera) {
+ reparseConfiguration();
+ } else {
+ if (!cameraopen) {
+ int ret, tries = 15;
+ kdDebug(7123) << "KameraProtocol::openCamera at " << getpid() << endl;
+ while (tries--) {
+ ret = gp_camera_init(m_camera, m_context);
+ if ( (ret == GP_ERROR_IO_USB_CLAIM) ||
+ (ret == GP_ERROR_IO_LOCK)) {
+ // just create / touch if not there
+ int fd = ::open(m_lockfile.utf8(),O_CREAT|O_WRONLY,0600);
+ if (fd != -1) ::close(fd);
+ ::sleep(1);
+ kdDebug(7123) << "openCamera at " << getpid() << "- busy, ret " << ret << ", trying again." << endl;
+ continue;
+ }
+ if (ret == GP_OK) break;
+ str = gp_result_as_string(ret);
+ return false;
+ }
+ ::unlink(m_lockfile.utf8());
+ setTimeoutSpecialCommand(1);
+ kdDebug(7123) << "openCamera succeeded at " << getpid() << endl;
+ cameraopen = true;
+ }
+ }
+ return true;
+}
+
+// should be done after operations over the wire
+void KameraProtocol::closeCamera(void)
+{
+ int gpr;
+
+ if (!m_camera)
+ return;
+
+ kdDebug(7123) << "KameraProtocol::closeCamera at " << getpid() << endl;
+ if ((gpr=gp_camera_exit(m_camera,m_context))!=GP_OK) {
+ kdDebug(7123) << "closeCamera failed with " << gp_result_as_string(gpr) << endl;
+ }
+ // HACK: gp_camera_exit() in gp 2.0 does not close the port if there
+ // is no camera_exit function.
+ gp_port_close(m_camera->port);
+ cameraopen = false;
+ return;
+}
+
+static QString fix_foldername(QString ofolder) {
+ QString folder = ofolder;
+ if (folder.length() > 1) {
+ while ((folder.length()>1) && (folder.right(1) == "/"))
+ folder = folder.left(folder.length()-1);
+ }
+ if (folder.length() == 0)
+ folder = "/";
+ return folder;
+}
+
+// The KIO slave "get" function (starts a download from the camera)
+// The actual returning of the data is done in the frontend callback functions.
+void KameraProtocol::get(const KURL &url)
+{
+ kdDebug(7123) << "KameraProtocol::get(" << url.path() << ")" << endl;
+
+ CameraFileType fileType;
+ int gpr;
+ if (url.host().isEmpty()) {
+ error(KIO::ERR_DOES_NOT_EXIST, url.path());
+ return;
+ }
+
+ if(!openCamera()) {
+ error(KIO::ERR_DOES_NOT_EXIST, url.path());
+ return;
+ }
+
+ // fprintf(stderr,"get(%s)\n",url.path().latin1());
+
+#define GPHOTO_TEXT_FILE(xx) \
+ if (!url.path().compare("/" #xx ".txt")) { \
+ CameraText xx; \
+ gpr = gp_camera_get_##xx(m_camera, &xx, m_context); \
+ if (gpr != GP_OK) { \
+ error(KIO::ERR_DOES_NOT_EXIST, url.path()); \
+ return; \
+ } \
+ QByteArray chunkDataBuffer; \
+ chunkDataBuffer.setRawData(xx.text, strlen(xx.text)); \
+ data(chunkDataBuffer); \
+ processedSize(strlen(xx.text)); \
+ chunkDataBuffer.resetRawData(xx.text, strlen(xx.text)); \
+ finished(); \
+ return; \
+ }
+
+ GPHOTO_TEXT_FILE(about);
+ GPHOTO_TEXT_FILE(manual);
+ GPHOTO_TEXT_FILE(summary);
+
+#undef GPHOTO_TEXT_FILE
+ // emit info message
+ infoMessage( i18n("Retrieving data from camera <b>%1</b>").arg(url.user()) );
+
+ // Note: There's no need to re-read directory for each get() anymore
+ gp_file_new(&m_file);
+
+ // emit the total size (we must do it before sending data to allow preview)
+ CameraFileInfo info;
+
+ gpr = gp_camera_file_get_info(m_camera, tocstr(fix_foldername(url.directory(false))), tocstr(url.fileName()), &info, m_context);
+ if (gpr != GP_OK) {
+ // fprintf(stderr,"Folder %s / File %s not found, gpr is %d\n",folder.latin1(), url.fileName().latin1(), gpr);
+ gp_file_unref(m_file);
+ if ((gpr == GP_ERROR_FILE_NOT_FOUND) || (gpr == GP_ERROR_DIRECTORY_NOT_FOUND))
+ error(KIO::ERR_DOES_NOT_EXIST, url.path());
+ else
+ error(KIO::ERR_UNKNOWN, gp_result_as_string(gpr));
+ return;
+ }
+
+ // at last, a proper API to determine whether a thumbnail was requested.
+ if(cameraSupportsPreview() && metaData("thumbnail") == "1") {
+ kdDebug(7123) << "get() retrieving the thumbnail" << endl;
+ fileType = GP_FILE_TYPE_PREVIEW;
+ if (info.preview.fields & GP_FILE_INFO_SIZE)
+ totalSize(info.preview.size);
+ if (info.preview.fields & GP_FILE_INFO_TYPE)
+ mimeType(info.preview.type);
+ } else {
+ kdDebug(7123) << "get() retrieving the full-scale photo" << endl;
+ fileType = GP_FILE_TYPE_NORMAL;
+ if (info.file.fields & GP_FILE_INFO_SIZE)
+ totalSize(info.file.size);
+ if (info.preview.fields & GP_FILE_INFO_TYPE)
+ mimeType(info.file.type);
+ }
+
+ // fetch the data
+ m_fileSize = 0;
+ gpr = gp_camera_file_get(m_camera, tocstr(fix_foldername(url.directory(false))), tocstr(url.fileName()), fileType, m_file, m_context);
+ if ( (gpr == GP_ERROR_NOT_SUPPORTED) &&
+ (fileType == GP_FILE_TYPE_PREVIEW)
+ ) {
+ // If we get here, the file info command information
+ // will either not be used, or still valid.
+ fileType = GP_FILE_TYPE_NORMAL;
+ gpr = gp_camera_file_get(m_camera, tocstr(fix_foldername(url.directory(false))), tocstr(url.fileName()), fileType, m_file, m_context);
+ }
+ switch(gpr) {
+ case GP_OK:
+ break;
+ case GP_ERROR_FILE_NOT_FOUND:
+ case GP_ERROR_DIRECTORY_NOT_FOUND:
+ gp_file_unref(m_file);
+ m_file = NULL;
+ error(KIO::ERR_DOES_NOT_EXIST, url.fileName());
+ return ;
+ default:
+ gp_file_unref(m_file);
+ m_file = NULL;
+ error(KIO::ERR_UNKNOWN, gp_result_as_string(gpr));
+ return;
+ }
+ // emit the mimetype
+ // NOTE: we must first get the file, so that CameraFile->name would be set
+ const char *fileMimeType;
+ gp_file_get_mime_type(m_file, &fileMimeType);
+ mimeType(fileMimeType);
+
+ // We need to pass left over data here. Some camera drivers do not
+ // implement progress callbacks!
+ const char *fileData;
+ long unsigned int fileSize;
+ // This merely returns us a pointer to gphoto's internal data
+ // buffer -- there's no expensive memcpy
+ gpr = gp_file_get_data_and_size(m_file, &fileData, &fileSize);
+ if (gpr != GP_OK) {
+ kdDebug(7123) << "get():: get_data_and_size failed." << endl;
+ gp_file_free(m_file);
+ m_file = NULL;
+ error(KIO::ERR_UNKNOWN, gp_result_as_string(gpr));
+ return;
+ }
+ // make sure we're not sending zero-sized chunks (=EOF)
+ // also make sure we send only if the progress did not send the data
+ // already.
+ if ((fileSize > 0) && (fileSize - m_fileSize)>0) {
+ unsigned long written = 0;
+ QByteArray chunkDataBuffer;
+
+ // We need to split it up here. Someone considered it funny
+ // to discard any data() larger than 16MB.
+ //
+ // So nearly any Movie will just fail....
+ while (written < fileSize-m_fileSize) {
+ unsigned long towrite = 1024*1024; // 1MB
+
+ if (towrite > fileSize-m_fileSize-written)
+ towrite = fileSize-m_fileSize-written;
+ chunkDataBuffer.setRawData(fileData + m_fileSize + written, towrite);
+ processedSize(m_fileSize + written + towrite);
+ data(chunkDataBuffer);
+ chunkDataBuffer.resetRawData(fileData + m_fileSize + written, towrite);
+ written += towrite;
+ }
+ m_fileSize = fileSize;
+ setFileSize(fileSize);
+ }
+
+ finished();
+ gp_file_unref(m_file); /* just unref, might be stored in fs */
+ m_file = NULL;
+}
+
+// The KIO slave "stat" function.
+void KameraProtocol::stat(const KURL &url)
+{
+ kdDebug(7123) << "stat(\"" << url.path() << "\")" << endl;
+
+ if (url.path() == "") {
+ KURL rooturl(url);
+
+ kdDebug(7123) << "redirecting to /" << endl;
+ rooturl.setPath("/");
+ rooturl.setHost(url.host());
+ rooturl.setUser(url.user());
+ redirection(rooturl);
+ finished();
+ return;
+ }
+
+ if(url.path() == "/")
+ statRoot();
+ else
+ statRegular(url);
+}
+
+// Implements stat("/") -- which always returns the same value.
+void KameraProtocol::statRoot(void)
+{
+ UDSEntry entry;
+ UDSAtom atom;
+
+ atom.m_uds = UDS_NAME;
+ atom.m_str = "/";
+ entry.append(atom);
+
+ atom.m_uds = UDS_FILE_TYPE;
+ atom.m_long = S_IFDIR;
+ entry.append(atom);
+
+ atom.m_uds = UDS_ACCESS;
+ atom.m_long = S_IRUSR | S_IRGRP | S_IROTH |
+ S_IWUSR | S_IWGRP | S_IWOTH;
+ entry.append(atom);
+
+ statEntry(entry);
+
+ finished();
+
+ // This call happens on autodetect by kdemm. So close the camera, but
+ // only if no more requests are pending.
+ idletime = MAXIDLETIME;
+}
+
+// Implements a regular stat() of a file / directory, returning all we know about it
+void KameraProtocol::statRegular(const KURL &url)
+{
+ UDSEntry entry;
+ int gpr;
+
+ kdDebug(7123) << "statRegular(\"" << url.path() << "\")" << endl;
+ if (openCamera() == false) {
+ error(KIO::ERR_DOES_NOT_EXIST, url.path());
+ return;
+ }
+
+ // fprintf(stderr,"statRegular(%s)\n",url.path().latin1());
+
+ // Is "url" a directory?
+ CameraList *dirList;
+ gp_list_new(&dirList);
+ kdDebug(7123) << "statRegular() Requesting directories list for " << url.directory() << endl;
+
+ gpr = gp_camera_folder_list_folders(m_camera, tocstr(fix_foldername(url.directory(false))), dirList, m_context);
+ if (gpr != GP_OK) {
+ if ((gpr == GP_ERROR_FILE_NOT_FOUND) || (gpr == GP_ERROR_DIRECTORY_NOT_FOUND))
+ error(KIO::ERR_DOES_NOT_EXIST, url.path());
+ else
+ error(KIO::ERR_UNKNOWN, gp_result_as_string(gpr));
+ gp_list_free(dirList);
+ return;
+ }
+
+#define GPHOTO_TEXT_FILE(xx) \
+ if (!url.path().compare("/"#xx".txt")) { \
+ CameraText xx; \
+ gpr = gp_camera_get_about(m_camera, &xx, m_context); \
+ if (gpr != GP_OK) { \
+ error(KIO::ERR_DOES_NOT_EXIST, url.fileName()); \
+ return; \
+ } \
+ translateTextToUDS(entry,#xx".txt",xx.text); \
+ statEntry(entry); \
+ finished(); \
+ return; \
+ }
+ GPHOTO_TEXT_FILE(about);
+ GPHOTO_TEXT_FILE(manual);
+ GPHOTO_TEXT_FILE(summary);
+#undef GPHOTO_TEXT_FILE
+
+ const char *name;
+ for(int i = 0; i < gp_list_count(dirList); i++) {
+ gp_list_get_name(dirList, i, &name);
+ if (url.fileName().compare(name) == 0) {
+ gp_list_free(dirList);
+ UDSEntry entry;
+ translateDirectoryToUDS(entry, url.fileName());
+ statEntry(entry);
+ finished();
+ return;
+ }
+ }
+ gp_list_free(dirList);
+
+ // Is "url" a file?
+ CameraFileInfo info;
+ gpr = gp_camera_file_get_info(m_camera, tocstr(fix_foldername(url.directory(false))), tocstr(url.fileName()), &info, m_context);
+ if (gpr != GP_OK) {
+ if ((gpr == GP_ERROR_FILE_NOT_FOUND) || (gpr == GP_ERROR_DIRECTORY_NOT_FOUND))
+ error(KIO::ERR_DOES_NOT_EXIST, url.path());
+ else
+ error(KIO::ERR_UNKNOWN, gp_result_as_string(gpr));
+ return;
+ }
+ translateFileToUDS(entry, info, url.fileName());
+ statEntry(entry);
+ finished();
+}
+
+// The KIO slave "del" function.
+void KameraProtocol::del(const KURL &url, bool isFile)
+{
+ kdDebug(7123) << "KameraProtocol::del(" << url.path() << ")" << endl;
+
+ if(!openCamera()) {
+ error(KIO::ERR_CANNOT_DELETE, url.fileName());
+ return;
+ }
+ if (!cameraSupportsDel()) {
+ error(KIO::ERR_CANNOT_DELETE, url.fileName());
+ return;
+ }
+ if(isFile){
+ CameraList *list;
+ gp_list_new(&list);
+ int ret;
+
+ ret = gp_camera_file_delete(m_camera, tocstr(fix_foldername(url.directory(false))), tocstr(url.fileName()), m_context);
+
+ if(ret != GP_OK) {
+ error(KIO::ERR_CANNOT_DELETE, url.fileName());
+ } else {
+ finished();
+ }
+ }
+}
+
+// The KIO slave "listDir" function.
+void KameraProtocol::listDir(const KURL &url)
+{
+ kdDebug(7123) << "KameraProtocol::listDir(" << url.path() << ")" << endl;
+
+ if (url.host().isEmpty()) {
+ KURL xurl;
+ // List the available cameras
+ QStringList groupList = m_config->groupList();
+ kdDebug(7123) << "Found cameras: " << groupList.join(", ") << endl;
+ QStringList::Iterator it;
+ UDSEntry entry;
+ UDSAtom atom;
+
+
+ /*
+ * What we do:
+ * - Autodetect cameras and remember them with their ports.
+ * - List all saved and possible offline cameras.
+ * - List all autodetected and not yet printed cameras.
+ */
+ QMap<QString,QString> ports, names;
+ QMap<QString,int> modelcnt;
+
+ /* Autodetect USB cameras ... */
+ GPContext *glob_context = NULL;
+ int i, count;
+ CameraList *list;
+ CameraAbilitiesList *al;
+ GPPortInfoList *il;
+
+ gp_list_new (&list);
+ gp_abilities_list_new (&al);
+ gp_abilities_list_load (al, glob_context);
+ gp_port_info_list_new (&il);
+ gp_port_info_list_load (il);
+ gp_abilities_list_detect (al, il, list, glob_context);
+ gp_abilities_list_free (al);
+ gp_port_info_list_free (il);
+
+ count = gp_list_count (list);
+
+ for (i = 0 ; i<count ; i++) {
+ const char *model, *value;
+
+ gp_list_get_name (list, i, &model);
+ gp_list_get_value (list, i, &value);
+
+ ports[value] = model;
+ // NOTE: We might get different ports than usb: later!
+ if (strcmp(value, "usb:"))
+ names[model] = value;
+
+ /* Save them, even though we can autodetect them for
+ * offline listing.
+ */
+ m_config->setGroup(model);
+ m_config->writeEntry("Model",model);
+ m_config->writeEntry("Path",value);
+ modelcnt[model]++;
+ }
+ gp_list_free (list);
+
+ /* Avoid duplicated entry for usb: and usb:001,042 entries. */
+ if (ports.contains("usb:") && names[ports["usb:"]]!="usb:")
+ ports.remove("usb:");
+
+ for (it = groupList.begin(); it != groupList.end(); it++) {
+ QString m_cfgPath;
+ if (*it == "<default>")
+ continue;
+
+ m_config->setGroup(*it);
+ m_cfgPath = m_config->readEntry("Path");
+
+ /* If autodetect by USB autodetect ... skip it here.
+ * We leave unattached USB cameras in here, because the user
+ * might plug them in later and does not want to press reload.
+ * We add them with port "usb:".
+ */
+ if (modelcnt[*it] > 0)
+ continue;
+
+ entry.clear();
+ atom.m_uds = UDS_FILE_TYPE;atom.m_long = S_IFDIR;entry.append(atom);
+ atom.m_uds = UDS_NAME;atom.m_str = *it;entry.append(atom);
+ atom.m_uds = UDS_ACCESS;
+ atom.m_long = S_IRUSR | S_IRGRP | S_IROTH |
+ S_IWUSR | S_IWGRP | S_IWOTH;
+ entry.append(atom);
+
+ atom.m_uds = UDS_URL;
+
+ xurl.setProtocol("camera");
+ xurl.setUser(*it);
+ /* Avoid setting usb:xxx,yyy. */
+ if (m_cfgPath.contains("usb:")>0) {
+ names[*it] = "usb:";
+ xurl.setHost("usb:");
+ } else {
+ xurl.setHost(m_cfgPath);
+ }
+ xurl.setPath("/");
+ atom.m_str = xurl.url();
+ entry.append(atom);
+
+ listEntry(entry, false);
+ }
+
+ QMap<QString,QString>::iterator portsit;
+
+ for (portsit = ports.begin(); portsit != ports.end(); portsit++) {
+ entry.clear();
+ atom.m_uds = UDS_FILE_TYPE;atom.m_long = S_IFDIR; entry.append(atom);
+ atom.m_uds = UDS_NAME;atom.m_str = portsit.data();entry.append(atom);
+
+ atom.m_uds = UDS_ACCESS;
+ atom.m_long = S_IRUSR | S_IRGRP | S_IROTH |
+ S_IWUSR | S_IWGRP | S_IWOTH;
+ entry.append(atom);
+
+ atom.m_uds = UDS_URL;
+ xurl.setProtocol("camera");
+ xurl.setHost(portsit.key());
+ xurl.setUser(portsit.data());
+ xurl.setPath("/");
+ atom.m_str = xurl.url();
+ entry.append(atom);
+
+ listEntry(entry, false);
+ }
+ listEntry(entry, true);
+
+ finished();
+ return;
+ }
+
+ if (url.path() == "") {
+ KURL rooturl(url);
+
+ kdDebug(7123) << "redirecting to /" << endl;
+ rooturl.setPath("/");
+ rooturl.setHost(url.host());
+ rooturl.setUser(url.user());
+ redirection(rooturl);
+ finished();
+ return;
+ }
+
+ if (!openCamera()) {
+ error(KIO::ERR_COULD_NOT_READ,url.path());
+ return;
+ }
+
+ CameraList *dirList;
+ CameraList *fileList;
+ CameraList *specialList;
+ gp_list_new(&dirList);
+ gp_list_new(&fileList);
+ gp_list_new(&specialList);
+ int gpr;
+
+ if (!url.path().compare("/")) {
+ CameraText text;
+ if (GP_OK == gp_camera_get_manual(m_camera, &text, m_context))
+ gp_list_append(specialList,"manual.txt",NULL);
+ if (GP_OK == gp_camera_get_about(m_camera, &text, m_context))
+ gp_list_append(specialList,"about.txt",NULL);
+ if (GP_OK == gp_camera_get_summary(m_camera, &text, m_context))
+ gp_list_append(specialList,"summary.txt",NULL);
+ }
+
+ gpr = readCameraFolder(url.path(), dirList, fileList);
+ if(gpr != GP_OK) {
+ kdDebug(7123) << "read Camera Folder failed:" << gp_result_as_string(gpr) <<endl;
+ gp_list_free(dirList);
+ gp_list_free(fileList);
+ gp_list_free(specialList);
+ error(KIO::ERR_COULD_NOT_READ, gp_result_as_string(gpr));
+ return;
+ }
+
+ totalSize(gp_list_count(specialList) + gp_list_count(dirList) + gp_list_count(fileList));
+
+ UDSEntry entry;
+ const char *name;
+
+ for(int i = 0; i < gp_list_count(dirList); ++i) {
+ gp_list_get_name(dirList, i, &name);
+ translateDirectoryToUDS(entry, QString::fromLocal8Bit(name));
+ listEntry(entry, false);
+ }
+
+ CameraFileInfo info;
+
+ for(int i = 0; i < gp_list_count(fileList); ++i) {
+ gp_list_get_name(fileList, i, &name);
+ // we want to know more info about files (size, type...)
+ gp_camera_file_get_info(m_camera, tocstr(url.path()), name, &info, m_context);
+ translateFileToUDS(entry, info, QString::fromLocal8Bit(name));
+ listEntry(entry, false);
+ }
+ if (!url.path().compare("/")) {
+ CameraText text;
+ if (GP_OK == gp_camera_get_manual(m_camera, &text, m_context)) {
+ translateTextToUDS(entry, "manual.txt", text.text);
+ listEntry(entry, false);
+ }
+ if (GP_OK == gp_camera_get_about(m_camera, &text, m_context)) {
+ translateTextToUDS(entry, "about.txt", text.text);
+ listEntry(entry, false);
+ }
+ if (GP_OK == gp_camera_get_summary(m_camera, &text, m_context)) {
+ translateTextToUDS(entry, "summary.txt", text.text);
+ listEntry(entry, false);
+ }
+ }
+
+
+ gp_list_free(fileList);
+ gp_list_free(dirList);
+ gp_list_free(specialList);
+
+ listEntry(entry, true); // 'entry' is not used in this case - we only signal list completion
+ finished();
+}
+
+void KameraProtocol::setHost(const QString& host, int port, const QString& user, const QString& pass )
+{
+ kdDebug(7123) << "KameraProtocol::setHost(" << host << ", " << port << ", " << user << ", " << pass << ")" << endl;
+ int gpr, idx;
+
+ if (!host.isEmpty()) {
+ kdDebug(7123) << "model is " << user << ", port is " << host << endl;
+ if (m_camera) {
+ kdDebug(7123) << "Configuration change detected" << endl;
+ closeCamera();
+ gp_camera_unref(m_camera);
+ m_camera = NULL;
+ infoMessage( i18n("Reinitializing camera") );
+ } else {
+ kdDebug(7123) << "Initializing camera" << endl;
+ infoMessage( i18n("Initializing camera") );
+ }
+ // fetch abilities
+ CameraAbilitiesList *abilities_list;
+ gp_abilities_list_new(&abilities_list);
+ gp_abilities_list_load(abilities_list, m_context);
+ idx = gp_abilities_list_lookup_model(abilities_list, tocstr(user));
+ if (idx < 0) {
+ gp_abilities_list_free(abilities_list);
+ kdDebug(7123) << "Unable to get abilities for model: " << user << endl;
+ error(KIO::ERR_UNKNOWN, gp_result_as_string(idx));
+ return;
+ }
+ gp_abilities_list_get_abilities(abilities_list, idx, &m_abilities);
+ gp_abilities_list_free(abilities_list);
+
+ // fetch port
+ GPPortInfoList *port_info_list;
+ GPPortInfo port_info;
+ gp_port_info_list_new(&port_info_list);
+ gp_port_info_list_load(port_info_list);
+ idx = gp_port_info_list_lookup_path(port_info_list, tocstr(host));
+
+ /* Handle erronously passed usb:XXX,YYY */
+ if ((idx < 0) && host.startsWith("usb:"))
+ idx = gp_port_info_list_lookup_path(port_info_list, "usb:");
+ if (idx < 0) {
+ gp_port_info_list_free(port_info_list);
+ kdDebug(7123) << "Unable to get port info for path: " << host << endl;
+ error(KIO::ERR_UNKNOWN, gp_result_as_string(idx));
+ return;
+ }
+ gp_port_info_list_get_info(port_info_list, idx, &port_info);
+ gp_port_info_list_free(port_info_list);
+
+ // create a new camera object
+ gpr = gp_camera_new(&m_camera);
+ if(gpr != GP_OK) {
+ error(KIO::ERR_UNKNOWN, gp_result_as_string(gpr));
+ return;
+ }
+
+ // register gphoto2 callback functions
+ gp_context_set_status_func(m_context, frontendCameraStatus, this);
+ gp_context_set_progress_funcs(m_context, frontendProgressStart, frontendProgressUpdate, NULL, this);
+ // gp_camera_set_message_func(m_camera, ..., this)
+
+ // set model and port
+ gp_camera_set_abilities(m_camera, m_abilities);
+ gp_camera_set_port_info(m_camera, port_info);
+ gp_camera_set_port_speed(m_camera, 0); // TODO: the value needs to be configurable
+ kdDebug(7123) << "Opening camera model " << user << " at " << host << endl;
+
+ QString errstr;
+ if (!openCamera(errstr)) {
+ kdDebug(7123) << "Unable to init camera: " << gp_result_as_string(gpr) << endl;
+ error(KIO::ERR_SERVICE_NOT_AVAILABLE, errstr);
+ gp_camera_exit(m_camera, m_context);
+ return;
+ }
+ }
+}
+
+void KameraProtocol::reparseConfiguration(void)
+{
+ // we have no global config, do we?
+}
+
+// translate a simple text to a UDS entry
+void KameraProtocol::translateTextToUDS(UDSEntry &udsEntry, const QString &fn,
+ const char *text
+) {
+ UDSAtom atom;
+
+ udsEntry.clear();
+
+ atom.m_uds = UDS_FILE_TYPE; // UDS type
+ atom.m_long = S_IFREG; // file
+ udsEntry.append(atom);
+
+ atom.m_uds = UDS_NAME;
+ atom.m_str = fn;
+ udsEntry.append(atom);
+
+ atom.m_uds = UDS_SIZE;
+ atom.m_long = strlen(text);
+ udsEntry.append(atom);
+
+ atom.m_uds = UDS_ACCESS;
+ atom.m_long = S_IRUSR | S_IRGRP | S_IROTH;
+ udsEntry.append(atom);
+}
+
+// translate a CameraFileInfo to a UDSEntry which we can return as a directory listing entry
+void KameraProtocol::translateFileToUDS(UDSEntry &udsEntry, const CameraFileInfo &info, QString name)
+{
+ UDSAtom atom;
+
+ udsEntry.clear();
+
+ atom.m_uds = UDS_FILE_TYPE; // UDS type
+ atom.m_long = S_IFREG; // file
+ udsEntry.append(atom);
+
+ atom.m_uds = UDS_NAME;
+ if (info.file.fields & GP_FILE_INFO_NAME)
+ atom.m_str = QString::fromLocal8Bit(info.file.name);
+ else
+ atom.m_str = name;
+ udsEntry.append(atom);
+
+ if (info.file.fields & GP_FILE_INFO_SIZE) {
+ atom.m_uds = UDS_SIZE;
+ atom.m_long = info.file.size;
+ udsEntry.append(atom);
+ }
+
+ if (info.file.fields & GP_FILE_INFO_MTIME) {
+ atom.m_uds = UDS_MODIFICATION_TIME;
+ atom.m_long = info.file.mtime;
+ udsEntry.append(atom);
+ } else {
+ atom.m_uds = UDS_MODIFICATION_TIME;
+ atom.m_long = time(NULL); /* NOW */
+ udsEntry.append(atom);
+ }
+
+ if (info.file.fields & GP_FILE_INFO_TYPE) {
+ atom.m_uds = UDS_MIME_TYPE;
+ atom.m_str = QString::fromLatin1(info.file.type);
+ udsEntry.append(atom);
+ }
+
+ if (info.file.fields & GP_FILE_INFO_PERMISSIONS) {
+ atom.m_uds = UDS_ACCESS;
+ atom.m_long = 0;
+ atom.m_long |= (info.file.permissions & GP_FILE_PERM_READ) ? (S_IRUSR | S_IRGRP | S_IROTH) : 0;
+ // we cannot represent individual FP_FILE_PERM_DELETE permission in the Unix access scheme
+ // since the parent directory's write permission defines that
+ udsEntry.append(atom);
+ } else {
+ // basic permissions, in case the camera doesn't provide permissions info
+ atom.m_uds = UDS_ACCESS;
+ atom.m_long = S_IRUSR | S_IRGRP | S_IROTH;
+ udsEntry.append(atom);
+ }
+
+ // TODO: We do not handle info.preview in any way
+}
+
+// translate a directory name to a UDSEntry which we can return as a directory listing entry
+void KameraProtocol::translateDirectoryToUDS(UDSEntry &udsEntry, const QString &dirname)
+{
+ UDSAtom atom;
+
+ udsEntry.clear();
+
+ atom.m_uds = UDS_FILE_TYPE; // UDS type
+ atom.m_long = S_IFDIR; // directory
+ udsEntry.append(atom);
+
+ atom.m_uds = UDS_NAME;
+ atom.m_str = dirname;
+ udsEntry.append(atom);
+
+ atom.m_uds = UDS_ACCESS;
+ atom.m_long = S_IRUSR | S_IRGRP | S_IROTH |
+ S_IWUSR | S_IWGRP | S_IWOTH;
+ udsEntry.append(atom);
+
+ atom.m_uds = UDS_MIME_TYPE;
+ atom.m_str = "inode/directory";
+ udsEntry.append(atom);
+}
+
+bool KameraProtocol::cameraSupportsDel(void)
+{
+ return (m_abilities.file_operations & GP_FILE_OPERATION_DELETE);
+}
+
+bool KameraProtocol::cameraSupportsPut(void)
+{
+ return (m_abilities.folder_operations & GP_FOLDER_OPERATION_PUT_FILE);
+}
+
+bool KameraProtocol::cameraSupportsPreview(void)
+{
+ return (m_abilities.file_operations & GP_FILE_OPERATION_PREVIEW);
+}
+
+int KameraProtocol::readCameraFolder(const QString &folder, CameraList *dirList, CameraList *fileList)
+{
+ kdDebug(7123) << "KameraProtocol::readCameraFolder(" << folder << ")" << endl;
+
+ int gpr;
+ if((gpr = gp_camera_folder_list_folders(m_camera, tocstr(folder), dirList, m_context)) != GP_OK)
+ return gpr;
+ if((gpr = gp_camera_folder_list_files(m_camera, tocstr(folder), fileList, m_context)) != GP_OK)
+ return gpr;
+ return GP_OK;
+}
+
+void frontendProgressUpdate(
+ GPContext * /*context*/, unsigned int /*id*/, float /*current*/, void *data
+) {
+ KameraProtocol *object = (KameraProtocol*)data;
+
+ // This code will get the last chunk of data retrieved from the
+ // camera and pass it to KIO, to allow progressive display
+ // of the downloaded photo.
+
+ const char *fileData = NULL;
+ long unsigned int fileSize = 0;
+
+ // This merely returns us a pointer to gphoto's internal data
+ // buffer -- there's no expensive memcpy
+ if (!object->getFile())
+ return;
+ gp_file_get_data_and_size(object->getFile(), &fileData, &fileSize);
+ // make sure we're not sending zero-sized chunks (=EOF)
+ if (fileSize > 0) {
+ // XXX using assign() here causes segfault, prolly because
+ // gp_file_free is called before chunkData goes out of scope
+ QByteArray chunkDataBuffer;
+ chunkDataBuffer.setRawData(fileData + object->getFileSize(), fileSize - object->getFileSize());
+ // Note: this will fail with sizes > 16MB ...
+ object->data(chunkDataBuffer);
+ object->processedSize(fileSize);
+ chunkDataBuffer.resetRawData(fileData + object->getFileSize(), fileSize - object->getFileSize());
+ object->setFileSize(fileSize);
+ }
+}
+
+unsigned int frontendProgressStart(
+ GPContext * /*context*/, float totalsize, const char *format, va_list args,
+ void *data
+) {
+ KameraProtocol *object = (KameraProtocol*)data;
+ char *status;
+
+ /* We must copy the va_list to walk it twice, or all hell
+ * breaks loose on non-i386 platforms.
+ */
+#if defined(HAVE_VA_COPY) || defined(HAVE___VA_COPY)
+ va_list xvalist;
+# ifdef HAVE_VA_COPY
+ va_copy(xvalist, args);
+# elif HAVE___VA_COPY
+ __va_copy(xvalist, args);
+# endif
+ int size=vsnprintf(NULL, 0, format, xvalist);
+ if(size<=0)
+ return GP_OK; // vsnprintf is broken, better don't do anything.
+
+ status=new char[size+1];
+# ifdef HAVE_VA_COPY
+ va_copy(xvalist, args);
+# elif HAVE___VA_COPY
+ __va_copy(xvalist, args);
+# endif
+ vsnprintf(status, size+1, format, xvalist);
+#else
+ /* We cannot copy the va_list, so make sure we
+ * walk it just _once_.
+ */
+ status=new char[300];
+ vsnprintf(status, 300, format, args);
+#endif
+
+ object->infoMessage(QString::fromLocal8Bit(status));
+ delete [] status;
+ object->totalSize((int)totalsize); // hack: call slot directly
+ return GP_OK;
+}
+
+// this callback function is activated on every status message from gphoto2
+static void frontendCameraStatus(GPContext * /*context*/, const char *format, va_list args, void *data)
+{
+ KameraProtocol *object = (KameraProtocol*)data;
+ char *status;
+
+ /* We must copy the va_list to walk it twice, or all hell
+ * breaks loose on non-i386 platforms.
+ */
+#if defined(HAVE_VA_COPY) || defined(HAVE___VA_COPY)
+ va_list xvalist;
+# ifdef HAVE_VA_COPY
+ va_copy(xvalist, args);
+# elif HAVE___VA_COPY
+ __va_copy(xvalist, args);
+# endif
+ int size=vsnprintf(NULL, 0, format, xvalist);
+ if(size<=0)
+ return; // vsnprintf is broken, better don't do anything.
+
+ status=new char[size+1];
+# ifdef HAVE_VA_COPY
+ va_copy(xvalist, args);
+# elif HAVE___VA_COPY
+ __va_copy(xvalist, args);
+# endif
+ vsnprintf(status, size+1, format, xvalist);
+#else
+ /* We cannot copy the va_list, so make sure we
+ * walk it just _once_.
+ */
+ status=new char[300];
+ vsnprintf(status, 300, format, args);
+#endif
+ object->infoMessage(QString::fromLocal8Bit(status));
+ delete [] status;
+}
diff --git a/kamera/kioslave/kamera.h b/kamera/kioslave/kamera.h
new file mode 100644
index 00000000..765f6560
--- /dev/null
+++ b/kamera/kioslave/kamera.h
@@ -0,0 +1,81 @@
+/*
+
+ Copyright (C) 2001 The Kompany
+ 2001-2003 Ilya Konstantinov <kde-devel@future.shiny.co.il>
+ 2001-2007 Marcus Meissner <marcus@jet.franken.de>
+
+ 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 __kamera_h__
+#define __kamera_h__
+
+#include <config.h>
+#include <kio/slavebase.h>
+#include <gphoto2.h>
+
+class KSimpleConfig;
+
+class KameraProtocol : public KIO::SlaveBase
+{
+public:
+ KameraProtocol(const QCString &pool, const QCString &app);
+ virtual ~KameraProtocol();
+
+ virtual void get(const KURL &url);
+ virtual void stat(const KURL &url);
+ virtual void del(const KURL &url, bool isFile);
+ virtual void setHost(const QString& host, int port, const QString& user, const QString& pass );
+ virtual void listDir(const KURL &url);
+ virtual void special(const QByteArray &data);
+
+ CameraFile *getFile() { return m_file; }
+ int getFileSize() { return m_fileSize; }
+ void setFileSize(int newfs) { m_fileSize = newfs; }
+
+private:
+ Camera *m_camera;
+ CameraAbilities m_abilities;
+ KSimpleConfig *m_config;
+
+ GPContext *m_context;
+
+ void reparseConfiguration(void);
+ bool openCamera(QString& str);
+ bool openCamera(void ) {
+ QString errstr;
+ return openCamera(errstr);
+ }
+ void closeCamera(void);
+
+ void statRoot(void);
+ void statRegular(const KURL &url);
+ void translateTextToUDS(KIO::UDSEntry &udsEntry, const QString &info, const char *txt);
+ void translateFileToUDS(KIO::UDSEntry &udsEntry, const CameraFileInfo &info, QString name);
+ void translateDirectoryToUDS(KIO::UDSEntry &udsEntry, const QString &dirname);
+ bool cameraSupportsPreview(void);
+ bool cameraSupportsDel(void);
+ bool cameraSupportsPut(void);
+ int readCameraFolder(const QString &folder, CameraList *dirList, CameraList *fileList);
+
+ QString m_lockfile;
+ int idletime;
+
+ int m_fileSize;
+ CameraFile *m_file;
+ bool actiondone, cameraopen;
+};
+#endif
diff --git a/kamera/pics/Makefile.am b/kamera/pics/Makefile.am
new file mode 100644
index 00000000..b74ac1ca
--- /dev/null
+++ b/kamera/pics/Makefile.am
@@ -0,0 +1 @@
+KDE_ICON = camera camera_test
diff --git a/kamera/pics/cr16-action-camera_test.png b/kamera/pics/cr16-action-camera_test.png
new file mode 100644
index 00000000..543710fb
--- /dev/null
+++ b/kamera/pics/cr16-action-camera_test.png
Binary files differ
diff --git a/kamera/pics/cr16-app-camera.png b/kamera/pics/cr16-app-camera.png
new file mode 100644
index 00000000..364167f0
--- /dev/null
+++ b/kamera/pics/cr16-app-camera.png
Binary files differ
diff --git a/kamera/pics/cr16-device-camera.png b/kamera/pics/cr16-device-camera.png
new file mode 100644
index 00000000..364167f0
--- /dev/null
+++ b/kamera/pics/cr16-device-camera.png
Binary files differ
diff --git a/kamera/pics/cr22-device-camera.png b/kamera/pics/cr22-device-camera.png
new file mode 100644
index 00000000..745affe7
--- /dev/null
+++ b/kamera/pics/cr22-device-camera.png
Binary files differ
diff --git a/kamera/pics/cr22-filesys-camera.png b/kamera/pics/cr22-filesys-camera.png
new file mode 100644
index 00000000..745affe7
--- /dev/null
+++ b/kamera/pics/cr22-filesys-camera.png
Binary files differ
diff --git a/kamera/pics/cr32-device-camera.png b/kamera/pics/cr32-device-camera.png
new file mode 100644
index 00000000..6876fa90
--- /dev/null
+++ b/kamera/pics/cr32-device-camera.png
Binary files differ
diff --git a/kamera/pics/cr32-filesys-camera.png b/kamera/pics/cr32-filesys-camera.png
new file mode 100644
index 00000000..6876fa90
--- /dev/null
+++ b/kamera/pics/cr32-filesys-camera.png
Binary files differ
diff --git a/kcoloredit/Makefile.am b/kcoloredit/Makefile.am
new file mode 100644
index 00000000..1f377635
--- /dev/null
+++ b/kcoloredit/Makefile.am
@@ -0,0 +1,35 @@
+INCLUDES = $(all_includes)
+
+kcoloredit_SOURCES = kzcolorselector.cpp imageselection.cpp \
+ texteditselection.cpp gradientselection.cpp colorselector.cpp \
+ kxycolorselector.cpp paletteview.cpp paletteviewscrolledarea.cpp \
+ editablestreamhistory.cpp color.cpp palette.cpp loadpalettedlg.cpp \
+ kcoloreditview.cpp kcoloreditdoc.cpp kcoloredit.cpp main.cpp
+kcoloredit_METASOURCES = AUTO
+kcoloredit_LDADD = $(LIB_KDEUI) $(LIB_KFILE)
+kcoloredit_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+
+rcdir = $(kde_datadir)/kcoloredit
+rc_DATA = kcoloreditui.rc
+
+bin_PROGRAMS = kcoloredit kcolorchooser
+kcolorchooser_SOURCES = kcolorchooser.cpp
+kcolorchooser_LDADD = $(LIB_KDEUI)
+kcolorchooser_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+
+noinst_HEADERS = color.h colorselector.h editablestreamhistory.h \
+ gradientselection.h imageselection.h kcoloredit.h kcoloreditdoc.h \
+ kcoloreditview.h kxycolorselector.h kzcolorselector.h \
+ loadpalettedlg.h main.h palette.h palettehistory.h paletteview.h \
+ resource.h texteditselection.h
+
+xdg_apps_DATA = kcoloredit.desktop kcolorchooser.desktop
+
+KDE_ICON = kcoloredit kcolorchooser
+
+EXTRA_DIST = $(xdg_apps_DATA)
+
+messages: rc.cpp
+ $(EXTRACTRC) *.rc > rc.cpp
+ $(XGETTEXT) $(kcoloredit_SOURCES) rc.cpp resource.h -o $(podir)/kcoloredit.pot
+
diff --git a/kcoloredit/color.cpp b/kcoloredit/color.cpp
new file mode 100644
index 00000000..db18a5a5
--- /dev/null
+++ b/kcoloredit/color.cpp
@@ -0,0 +1,78 @@
+/***************************************************************************
+ color.cpp - description
+ -------------------
+ begin : Sun Jul 9 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include "color.h"
+
+Color::Color(){
+ setComponents(0, 0, 0);
+ setName("");
+}
+Color::Color(const int red, const int green, const int blue, const QString& name) {
+ setComponents(red, green, blue);
+ setName(name);
+}
+Color::~Color(){
+}
+
+void Color::setComponent(const int index, const int value) {
+ m_components[index] = value;
+}
+
+void Color::setComponents(const int red, const int green, const int blue) {
+ setComponent(RED_INDEX, red);
+ setComponent(GREEN_INDEX, green);
+ setComponent(BLUE_INDEX, blue);
+}
+
+void Color::setName(const QString& name) {
+ m_name = name;
+}
+
+int Color::component(const int index) const {
+ return m_components[index];
+}
+
+const int* Color::components() const{
+ return m_components;
+}
+
+const QString& Color::name() const {
+ return m_name;
+}
+
+bool Color::equals(const Color& color) {
+ return component(RED_INDEX) == color.component(RED_INDEX) &&
+ component(GREEN_INDEX) == color.component(GREEN_INDEX) &&
+ component(BLUE_INDEX) == color.component(BLUE_INDEX);
+}
+
+void Color::modifyComponent(const int index, const int value, const double amount) {
+ int comp = component(index);
+ comp += (int)(value*amount + 0.5);
+ if(comp > RGB_MAX_COMPONENT_VALUE)
+ comp = RGB_MAX_COMPONENT_VALUE;
+ else if(comp < 0)
+ comp = 0;
+ setComponent(index, comp);
+}
+
+void Color::modifyComponents(const int red, const int green, const int blue, const double amount) {
+ modifyComponent(RED_INDEX, red, amount);
+ modifyComponent(GREEN_INDEX, green, amount);
+ modifyComponent(BLUE_INDEX, blue, amount);
+}
+
diff --git a/kcoloredit/color.h b/kcoloredit/color.h
new file mode 100644
index 00000000..723ba2f0
--- /dev/null
+++ b/kcoloredit/color.h
@@ -0,0 +1,81 @@
+/***************************************************************************
+ color.h - description
+ -------------------
+ begin : Sun Jul 9 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef COLOR_H
+#define COLOR_H
+
+#include "main.h"
+
+/**A color class, holds its components and name
+ *@author Artur Rataj
+ */
+
+class Color {
+ public:
+ /** indices of components
+ */
+ enum { RED_INDEX = 0,
+ GREEN_INDEX = 1,
+ BLUE_INDEX = 2,
+ COMPONENTS_NUM = 3 };
+
+ public:
+ /** constructs a color
+ */
+ Color();
+ /** constructs a color with given components and a name
+ */
+ Color(const int red, const int green, const int blue, const QString& name);
+ ~Color();
+ /** sets a component
+ */
+ void setComponent(const int index, const int value);
+ /** sets components
+ */
+ void setComponents(const int red, const int green, const int blue);
+ /** sets a name
+ */
+ void setName(const QString& name);
+ /** @return a component
+ */
+ int component(const int index) const;
+ /** @return components
+ */
+ const int* components() const;
+ /** @return a color name
+ */
+ const QString& name() const;
+ /** @return if is equal to color
+ */
+ bool equals(const Color& color);
+ /** modifies a component, amount can be either positive or negative
+ */
+ void modifyComponent(const int index, const int value, const double amount);
+ /** modifies components, amount can be either positive or negative
+ */
+ void modifyComponents(const int red, const int green, const int blue, const double amount);
+
+ protected:
+ /** components table
+ */
+ int m_components[COMPONENTS_NUM];
+ /** a color name
+ */
+ QString m_name;
+};
+
+#endif
diff --git a/kcoloredit/colorselector.cpp b/kcoloredit/colorselector.cpp
new file mode 100644
index 00000000..2b0530d3
--- /dev/null
+++ b/kcoloredit/colorselector.cpp
@@ -0,0 +1,212 @@
+/***************************************************************************
+ colorselector.cpp - description
+ -------------------
+ begin : Sun Jul 9 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include <math.h>
+
+#include <qlayout.h>
+/* #include <qtabwidget.h> */
+#include <qradiobutton.h>
+#include <qlabel.h>
+#include <qslider.h>
+#include <kseparator.h>
+#include <klocale.h>
+
+#include "main.h"
+#include "imageselection.h"
+#include "texteditselection.h"
+#include "colorselector.h"
+
+ColorSelector::ColorSelector(QWidget *parent, const char *name ) : QWidget(parent, name) {
+ fComponentsMode = false;
+ QVBoxLayout* topLayout = new QVBoxLayout(this, 4);
+ /*
+ QTabWidget* pages = new QTabWidget(this);
+ */
+ gradientSelection = new GradientSelection(this);
+ connect(gradientSelection, SIGNAL( valueChanged(Color*) ),
+ SLOT( slotGradientSelectionChangeColor(Color*) ));
+ connect(gradientSelection, SIGNAL( synchronizeColor() ),
+ SLOT( slotGradientSelectionSynchronizeColor() ));
+ connect(this, SIGNAL( valueChanged(Color*) ), gradientSelection, SLOT( slotSetValue(Color*) ));
+ /*
+ pages->addTab(gradientSelection, i18n( "Gradient" ));
+ ImageSelection* imageSelection = new ImageSelection(this);
+ connect(imageSelection, SIGNAL( valueChanged(Color*) ), SLOT( slotSetColor(Color*) ));
+ connect(this, SIGNAL( valueChanged(Color*) ), imageSelection, SLOT( slotSetValue(Color*) ));
+ pages->addTab(imageSelection, i18n( "Image" ));
+ topLayout->addWidget(pages, 10);
+ */
+ topLayout->addWidget(gradientSelection, 10);
+ KSeparator* hLine = new KSeparator(KSeparator::HLine, this);
+ topLayout->addWidget(hLine);
+ QHBoxLayout* layout = new QHBoxLayout();
+ TextEditSelection* textEditSelection = new TextEditSelection(this);
+ connect(textEditSelection, SIGNAL( valueChanged(Color*) ), SLOT( slotSetColor(Color*) ));
+ connect(this, SIGNAL( valueChanged(Color*) ), textEditSelection, SLOT( slotSetValue(Color*) ));
+ QVBoxLayout* colorChangeLayout = new QVBoxLayout();
+ colorChangeLayout->setMargin(2);
+ QRadioButton* replaceButton = new QRadioButton(i18n( "Replace" ), this);
+ connect(replaceButton, SIGNAL( clicked() ), SLOT( slotColorReplace() ));
+ replaceButton->setChecked(true);
+ colorChangeButtons.insert(replaceButton);
+ colorChangeLayout->addWidget(replaceButton);
+ QRadioButton* changeButton = new QRadioButton(i18n( "Change" ) + ":", this);
+ connect(changeButton, SIGNAL( clicked() ), SLOT( slotColorChange() ));
+ colorChangeButtons.insert(changeButton);
+ colorChangeLayout->addWidget(changeButton);
+ colorChangeValue = 0;
+ colorChangeSliderWidget = new QWidget(this);
+ QVBoxLayout* colorChangeSliderLayout = new QVBoxLayout(colorChangeSliderWidget, 1);
+ colorChangeSliderLayout->setMargin(0);
+ QSlider* colorChangeSlider = new QSlider(0, MAX_COLOR_CHANGE_VALUE,
+ MAX_COLOR_CHANGE_VALUE/4, colorChangeValue, QSlider::Horizontal, colorChangeSliderWidget);
+ colorChangeSlider->setTickInterval(colorChangeSlider->pageStep());
+ colorChangeSlider->setTickmarks(QSlider::Above);
+ connect(colorChangeSlider, SIGNAL( valueChanged(int) ), SLOT( slotColorChangeValueChanged(int) ));
+ colorChangeSliderLayout->addWidget(colorChangeSlider);
+ QHBoxLayout* colorChangeSliderLabelsLayout = new QHBoxLayout(0);
+ QLabel* subtractLabel = new QLabel(i18n( "0" ), colorChangeSliderWidget);
+ colorChangeSliderLabelsLayout->addWidget(subtractLabel);
+ colorChangeSliderLabelsLayout->addStretch(10);
+ QLabel* addLabel = new QLabel(" " + i18n( "Replace" ), colorChangeSliderWidget);
+ colorChangeSliderLabelsLayout->addWidget(addLabel);
+ colorChangeSliderLayout->addLayout(colorChangeSliderLabelsLayout);
+ colorChangeLayout->addStretch(10);
+ colorChangeLayout->addWidget(colorChangeSliderWidget);
+ colorChangeLayout->addStretch(10);
+ layout->addLayout(colorChangeLayout, 10);
+ m_color.setComponents(RGB_MAX_COMPONENT_VALUE, RGB_MAX_COMPONENT_VALUE, RGB_MAX_COMPONENT_VALUE);
+ slotColorReplace();
+ KSeparator* vLine = new KSeparator(KSeparator::VLine, this);
+ layout->addWidget(vLine);
+ layout->addWidget(textEditSelection, 1);
+ colorPatch = new KColorPatch(this);
+ connect(colorPatch, SIGNAL( colorChanged(const QColor&) ), SLOT( slotSetColor(const QColor&) ));
+ colorPatch->setMinimumSize(80, 64);
+ layout->addWidget(colorPatch, 10);
+ topLayout->addLayout(layout);
+}
+ColorSelector::~ColorSelector() {
+}
+
+void ColorSelector::slotSetColor(Color color) {
+ m_color = color;
+ colorPatch->setColor(QColor( m_color.component(Color::RED_INDEX),
+ m_color.component(Color::GREEN_INDEX),
+ m_color.component(Color::BLUE_INDEX) ));
+ fComponentsMode = false;
+ emit valueChanged(&m_color);
+}
+
+void ColorSelector::slotSetColor(Color* color) {
+ slotSetColor(*color);
+}
+
+void ColorSelector::slotSetColor(const QColor& color) {
+ m_color.setComponent(Color::RED_INDEX, color.red());
+ m_color.setComponent(Color::GREEN_INDEX, color.green());
+ m_color.setComponent(Color::BLUE_INDEX, color.blue());
+ fComponentsMode = false;
+ emit valueChanged(&m_color);
+}
+
+void ColorSelector::scaledComponent(double* const component, const double componentDiff) {
+ double scaledComponentDiff = componentDiff*
+ pow(colorChangeValue*1.0/MAX_COLOR_CHANGE_VALUE, 2.0);
+ *component += scaledComponentDiff;
+ if(*component > RGB_MAX_COMPONENT_VALUE)
+ *component = RGB_MAX_COMPONENT_VALUE;
+ else if(*component < 0)
+ *component = 0;
+}
+
+void ColorSelector::slotGradientSelectionChangeColor(Color* gradientSelectionColor) {
+ switch(colorChangeMode) {
+ case MODE_REPLACE:
+ slotSetColor(gradientSelectionColor);
+ break;
+
+ case MODE_CHANGE:
+ gradientSelection->slotIgnoreSetValue(true);
+ double rComponent;
+ double gComponent;
+ double bComponent;
+ if(fComponentsMode) {
+ rComponent = fRComponent;
+ gComponent = fGComponent;
+ bComponent = fBComponent;
+ } else {
+ rComponent = m_color.component(Color::RED_INDEX);
+ gComponent = m_color.component(Color::GREEN_INDEX);
+ bComponent = m_color.component(Color::BLUE_INDEX);
+ }
+ double rDiff = gradientSelectionColor->component(Color::RED_INDEX) - rComponent;
+ double gDiff = gradientSelectionColor->component(Color::GREEN_INDEX) - gComponent;
+ double bDiff = gradientSelectionColor->component(Color::BLUE_INDEX) - bComponent;
+ /*
+ printf("base color = (%i %i %i) gradient color = (%i %i %i)\n",
+ rComponent, gComponent, bComponent,
+ gradientSelectionColor->getComponent(Color::RED_INDEX),
+ gradientSelectionColor->getComponent(Color::GREEN_INDEX),
+ gradientSelectionColor->getComponent(Color::BLUE_INDEX));
+ */
+ scaledComponent(&rComponent, rDiff);
+ scaledComponent(&gComponent, gDiff);
+ scaledComponent(&bComponent, bDiff);
+ Color newColor((int)( rComponent + 0.5 ),
+ (int)( gComponent + 0.5 ), (int)( bComponent + 0.5 ), "");
+ slotSetColor(newColor);
+ fRComponent = rComponent;
+ fGComponent = gComponent;
+ fBComponent = bComponent;
+ fComponentsMode = true;
+ /*
+ printf("output color = (%i %i %i)\n",
+ rComponent, gComponent, bComponent);
+ */
+ gradientSelection->slotIgnoreSetValue(false);
+ break;
+ }
+}
+
+void ColorSelector::slotGradientSelectionSynchronizeColor() {
+ /** Notify the gradient selector to update its color */
+ emit valueChanged(&m_color);
+}
+
+const Color& ColorSelector::color() {
+ return m_color;
+}
+
+void ColorSelector::slotColorReplace() {
+ colorChangeMode = MODE_REPLACE;
+ slotGradientSelectionSynchronizeColor();
+ gradientSelection->enableSynchronizeColorButton(false);
+ colorChangeSliderWidget->setEnabled(false);
+}
+
+void ColorSelector::slotColorChange() {
+ colorChangeMode = MODE_CHANGE;
+ gradientSelection->enableSynchronizeColorButton(true);
+ colorChangeSliderWidget->setEnabled(true);
+}
+
+void ColorSelector::slotColorChangeValueChanged(int value) {
+ colorChangeValue = value;
+}
+
+#include "colorselector.moc"
diff --git a/kcoloredit/colorselector.h b/kcoloredit/colorselector.h
new file mode 100644
index 00000000..21b5902b
--- /dev/null
+++ b/kcoloredit/colorselector.h
@@ -0,0 +1,96 @@
+/***************************************************************************
+ colorselector.h - description
+ -------------------
+ begin : Sun Jul 9 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef COLORSELECTOR_H
+#define COLORSELECTOR_H
+
+#include <qwidget.h>
+#include <qcolor.h>
+#include <qbuttongroup.h>
+#include <kcolordialog.h>
+
+#include "color.h"
+#include "gradientselection.h"
+
+/** Color selector widget
+ * @author Artur Rataj
+ */
+class ColorSelector : public QWidget {
+ Q_OBJECT
+
+public:
+ /** constructs a color selector widget */
+ ColorSelector(QWidget *parent=0, const char *name=0);
+ ~ColorSelector();
+ /** @return the selected color */
+ const Color& color();
+
+signals:
+ /** A signal that a color value has changed */
+ void valueChanged(Color*);
+
+public slots:
+ /** Called if a color changed */
+ void slotSetColor(Color color);
+ /** Called if a color changed */
+ void slotSetColor(Color* color);
+ /** called if a color changed in the color patch */
+ void slotSetColor(const QColor& color);
+ /** Called by the gradient selection, to replace or modify a color */
+ void slotGradientSelectionChangeColor(Color* gradientSelectionColor);
+ /** Called by the gradient selection, to synchronize its color */
+ void slotGradientSelectionSynchronizeColor();
+ /** Called if color replace mode is chosen */
+ void slotColorReplace();
+ /** called if color change mode is chosen */
+ void slotColorChange();
+ /** Called if a color change value changed */
+ void slotColorChangeValueChanged(int value);
+
+private:
+ /** Color change mode constants */
+ enum { MODE_REPLACE = 0,
+ MODE_CHANGE = 1,
+ /** Maximum color change value */
+ MAX_COLOR_CHANGE_VALUE = 16 };
+
+ /** A color change slider widget */
+ QWidget* colorChangeSliderWidget;
+ /** Color change buttons button group widget */
+ QButtonGroup colorChangeButtons;
+ /** A color patch widget */
+ KColorPatch* colorPatch;
+ /** A gradient selection widget */
+ GradientSelection* gradientSelection;
+ /** The current color */
+ Color m_color;
+ /** Color change mode */
+ int colorChangeMode;
+ /** Current color change value */
+ int colorChangeValue;
+ /** Floating--point precision RGB components, for color change mode */
+ double fRComponent;
+ double fGComponent;
+ double fBComponent;
+ /** Whether in the floating-point precision components mode */
+ bool fComponentsMode;
+
+ /** Scales a component according to componentDiff and colorChangeValue */
+ void scaledComponent(double* const component, const double componentDiff);
+};
+
+#endif
diff --git a/kcoloredit/editablestreamhistory.cpp b/kcoloredit/editablestreamhistory.cpp
new file mode 100644
index 00000000..c299ed7a
--- /dev/null
+++ b/kcoloredit/editablestreamhistory.cpp
@@ -0,0 +1,18 @@
+/***************************************************************************
+ editablestream.cpp - description
+ -------------------
+ begin : Sun Jul 9 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include "editablestreamhistory.h"
diff --git a/kcoloredit/editablestreamhistory.h b/kcoloredit/editablestreamhistory.h
new file mode 100644
index 00000000..9fe59d99
--- /dev/null
+++ b/kcoloredit/editablestreamhistory.h
@@ -0,0 +1,107 @@
+/***************************************************************************
+ editablestreamhistory.h - description
+ -------------------
+ begin : Sun Jul 9 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef EDITABLESTREAMHISTORY_H
+#define EDITABLESTREAMHISTORY_H
+
+/** A template class adding undo/redo history for EDITABLE_STREAM paste and cut
+ * methods
+ * @author Artur Rataj
+ */
+template <class EDITABLE_STREAM> class EditableStreamHistory {
+public:
+ /** Constructs the class with stream as an EDITABLE_STREAM and
+ * a given number of undo levels
+ */
+ EditableStreamHistory(EDITABLE_STREAM* stream, const int undoLevels);
+ ~EditableStreamHistory();
+ /** Cuts a stream at index, of length length.
+ * Uses undo/redo history.
+ * @return A stream that has been cut out
+ */
+ EDITABLE_STREAM cut(const int index, const int length);
+ /** Pastes a stream at index. Uses undo/redo history */
+ void paste(const int index, EDITABLE_STREAM& pasteStream);
+ /** Replaces a stream at index. Uses undo/redo history */
+ void replace(const int index, EDITABLE_STREAM& replaceStream);
+ /** @return Whether undo possible */
+ bool undoPossible();
+ /** @return Whether redo possible */
+ bool redoPossible();
+ /** Undoes if possible */
+ void undo();
+ /** Redoes if possible */
+ void redo();
+ /** @return A pointer to editableStream */
+ EDITABLE_STREAM* editableStream();
+
+protected:
+ /** An editable stream */
+ EDITABLE_STREAM* m_editableStream;
+ /** A number of undo levels */
+ int m_undoLevels;
+};
+
+template <class EDITABLE_STREAM> EditableStreamHistory<EDITABLE_STREAM>::
+ EditableStreamHistory(EDITABLE_STREAM* stream, const int undoLevels) {
+ m_editableStream = stream;
+ m_undoLevels = undoLevels;
+}
+template <class EDITABLE_STREAM> EditableStreamHistory<EDITABLE_STREAM>::~EditableStreamHistory() {
+}
+
+template <class EDITABLE_STREAM> EDITABLE_STREAM
+ EditableStreamHistory<EDITABLE_STREAM>::cut(const int index, const int length) {
+ EDITABLE_STREAM cut_stream = m_editableStream->cut(index, length);
+ return cut_stream;
+}
+
+template <class EDITABLE_STREAM> void
+ EditableStreamHistory<EDITABLE_STREAM>::paste(const int index, EDITABLE_STREAM& pasteStream) {
+ m_editableStream->paste(index, pasteStream);
+}
+
+template <class EDITABLE_STREAM> void
+ EditableStreamHistory<EDITABLE_STREAM>::replace(const int index, EDITABLE_STREAM& replaceStream) {
+ m_editableStream->cut(index, replaceStream.length());
+ m_editableStream->paste(index, replaceStream);
+}
+
+template <class EDITABLE_STREAM> bool
+ EditableStreamHistory<EDITABLE_STREAM>::undoPossible() {
+ return false;
+}
+
+template <class EDITABLE_STREAM> bool
+ EditableStreamHistory<EDITABLE_STREAM>::redoPossible() {
+ return false;
+}
+
+template <class EDITABLE_STREAM> void
+ EditableStreamHistory<EDITABLE_STREAM>::undo() {
+}
+
+template <class EDITABLE_STREAM> void
+ EditableStreamHistory<EDITABLE_STREAM>::redo() {
+}
+
+template <class EDITABLE_STREAM> EDITABLE_STREAM*
+ EditableStreamHistory<EDITABLE_STREAM>::editableStream() {
+ return m_editableStream;
+}
+
+#endif
diff --git a/kcoloredit/gradientselection.cpp b/kcoloredit/gradientselection.cpp
new file mode 100644
index 00000000..a8927c7d
--- /dev/null
+++ b/kcoloredit/gradientselection.cpp
@@ -0,0 +1,252 @@
+/***************************************************************************
+ gradientselection.cpp - description
+ -------------------
+ begin : Wed Jul 12 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include <qlayout.h>
+#include <qframe.h>
+#include <qradiobutton.h>
+#include <qcolor.h>
+#include <klocale.h>
+
+#include "main.h"
+#include "gradientselection.h"
+
+GradientSelection::GradientSelection(QWidget *parent, const char *name ) : QWidget(parent,name) {
+ QGridLayout* topLayout = new QGridLayout(this, 2, 2, 0);
+ QHBoxLayout* layout = new QHBoxLayout(0);
+ layout->setMargin(3);
+ xyColorSelector = new KXYColorSelector(this);
+ connect(xyColorSelector, SIGNAL( valueChanged(int, int) ),
+ SLOT( slotXyColorSelectorPosChanged(int, int) ));
+ layout->addWidget(xyColorSelector);
+ topLayout->addLayout(layout, 0, 0);
+ topLayout->setRowStretch(0, 10);
+ topLayout->setRowStretch(1, 0);
+ QVBoxLayout* xyColorSelectorLayout = new QVBoxLayout();
+ QHBoxLayout* checkBoxLayout = new QHBoxLayout();
+ checkBoxLayout->setMargin(0);
+ variableCheckBox = new QCheckBox(i18n( "Variable" ), this);
+ variableGlobalComponent = false;
+ connect(variableCheckBox, SIGNAL( toggled(bool) ), SLOT( slotSetVariableGlobalComponent(bool) ));
+ checkBoxLayout->addSpacing(2);
+ checkBoxLayout->addWidget(variableCheckBox);
+ xyColorSelectorLayout->addLayout(checkBoxLayout);
+ xyColorSelectorLayout->addStretch(10);
+ QHBoxLayout* buttonsLayout = new QHBoxLayout();
+ synchronizeColorButton = new QPushButton(i18n( "Synchronize" ), this);
+ connect(synchronizeColorButton, SIGNAL( clicked() ), SLOT( slotSynchronizeColor() ));
+ buttonsLayout->addSpacing(2);
+ buttonsLayout->addWidget(synchronizeColorButton);
+ buttonsLayout->addStretch(10);
+ xyColorSelectorLayout->addLayout(buttonsLayout);
+ xyColorSelectorLayout->addSpacing(2);
+ topLayout->addLayout(xyColorSelectorLayout, 1, 0);
+ zColorSelector = new KZColorSelector(KZColorSelector::Vertical, this);
+ connect(zColorSelector, SIGNAL( valueChanged(int) ),
+ SLOT( slotZColorSelectorPosChanged(int) ));
+ zColorSelector->setFixedWidth(36);
+ topLayout->addWidget(zColorSelector, 0, 1);
+ QVBoxLayout* zColorSelectorLayout = new QVBoxLayout(0);
+ connect(&hsvButtons, SIGNAL( clicked(int) ), SLOT( slotSetColorSelectionMode(int) ));
+ QRadioButton* hRadioButton = new QRadioButton("H", this);
+ hsvButtons.insert(hRadioButton, H_COMPONENT);
+ zColorSelectorLayout->addWidget(hRadioButton);
+ QRadioButton* sRadioButton = new QRadioButton("S", this);
+ hsvButtons.insert(sRadioButton, S_COMPONENT);
+ zColorSelectorLayout->addWidget(sRadioButton);
+ QRadioButton* vRadioButton = new QRadioButton("V", this);
+ hsvButtons.insert(vRadioButton, V_COMPONENT);
+ vRadioButton->toggle();
+ zColorSelectorLayout->addWidget(vRadioButton);
+ topLayout->addLayout(zColorSelectorLayout, 1, 1);
+ color.setComponents(RGB_MAX_COMPONENT_VALUE, RGB_MAX_COMPONENT_VALUE, RGB_MAX_COMPONENT_VALUE);
+ hComponent = -1;
+ sComponent = 0;
+ vComponent = HSV_MAX_V_VALUE;
+ slotIgnoreSetValue(false);
+ slotSetColorSelectionMode(V_COMPONENT);
+}
+GradientSelection::~GradientSelection(){
+}
+
+void GradientSelection::slotSetValue(Color* color) {
+ if(!ignoreSetValue && !color->equals( this->color )) {
+ this->color = *color;
+ int newHComponent;
+ int newSComponent;
+ int newVComponent;
+ QColor hsvColor(this->color.component(Color::RED_INDEX),
+ this->color.component(Color::GREEN_INDEX),
+ this->color.component(Color::BLUE_INDEX));
+ hsvColor.hsv(&newHComponent, &newSComponent, &newVComponent);
+ hComponent = newHComponent;
+ sComponent = newSComponent;
+ vComponent = newVComponent;
+ updateXyColorSelector(false);
+ updateZColorSelector();
+ }
+}
+
+void GradientSelection::slotIgnoreSetValue(bool ignore) {
+ ignoreSetValue = ignore;
+}
+
+void GradientSelection::updateXyColorSelector(const bool modeChanged) {
+ int xPos;
+ int yPos;
+ int component;
+ switch(zColorSelectorComponentIndex) {
+ case H_COMPONENT:
+ xPos = (int)(vComponent*( KXYColorSelector::COMPONENT_SELECTION_RESOLUTION - 1 )/
+ HSV_MAX_V_VALUE + 0.5);
+ yPos = (int)(sComponent*( KXYColorSelector::COMPONENT_SELECTION_RESOLUTION - 1 )/
+ HSV_MAX_S_VALUE + 0.5);
+ component = hComponent;
+ break;
+
+ case S_COMPONENT:
+ xPos = (int)(hComponent*( KXYColorSelector::COMPONENT_SELECTION_RESOLUTION - 1 )/
+ HSV_MAX_H_VALUE + 0.5);
+ yPos = (int)(vComponent*( KXYColorSelector::COMPONENT_SELECTION_RESOLUTION - 1 )/
+ HSV_MAX_V_VALUE + 0.5);
+ if(variableGlobalComponent)
+ component = sComponent;
+ else
+ component = 240;
+ break;
+
+ case V_COMPONENT:
+ xPos = (int)(hComponent*( KXYColorSelector::COMPONENT_SELECTION_RESOLUTION - 1 )/
+ HSV_MAX_H_VALUE + 0.5);
+ yPos = (int)(sComponent*( KXYColorSelector::COMPONENT_SELECTION_RESOLUTION - 1 )/
+ HSV_MAX_S_VALUE + 0.5);
+ if(variableGlobalComponent)
+ component = vComponent;
+ else
+ component = 192;
+ break;
+
+ default:
+ xPos = 0;
+ yPos = 0;
+ component = 0;
+ break;
+
+ }
+ if(xPos < 0)
+ xPos = 0;
+ if(yPos < 0)
+ yPos = 0;
+ if(modeChanged || xyColorSelector->globalComponent() != component) {
+ xyColorSelector->setGlobalComponent(component);
+ xyColorSelector->updateContents();
+ }
+ xyColorSelector->setValues(xPos, yPos);
+}
+
+void GradientSelection::updateZColorSelector() {
+ zColorSelector->setBaseColorHsv(hComponent, sComponent, vComponent);
+ zColorSelector->updatePointerPos();
+ zColorSelector->updateContents();
+}
+
+void GradientSelection::slotSetColorSelectionMode(int mode) {
+ zColorSelectorComponentIndex = mode;
+ xyColorSelector->setType(zColorSelectorComponentIndex);
+ updateXyColorSelector(true);
+ switch(zColorSelectorComponentIndex) {
+ case H_COMPONENT:
+ zColorSelector->setType(KZColorSelector::TYPE_H);
+ variableCheckBox->setEnabled(false);
+ break;
+
+ case S_COMPONENT:
+ zColorSelector->setType(KZColorSelector::TYPE_S);
+ variableCheckBox->setEnabled(true);
+ break;
+
+ case V_COMPONENT:
+ zColorSelector->setType(KZColorSelector::TYPE_V);
+ variableCheckBox->setEnabled(true);
+ break;
+
+ }
+ updateZColorSelector();
+}
+
+void GradientSelection::slotSetVariableGlobalComponent(bool variable) {
+ variableGlobalComponent = variable;
+ updateXyColorSelector(false);
+}
+
+void GradientSelection::slotXyColorSelectorPosChanged(int x, int y) {
+ switch(zColorSelectorComponentIndex) {
+ case H_COMPONENT:
+ vComponent = (int)(x*1.0*HSV_MAX_V_VALUE/( KXYColorSelector::COMPONENT_SELECTION_RESOLUTION - 1 ) + 0.5);
+ sComponent = (int)(y*1.0*HSV_MAX_S_VALUE/( KXYColorSelector::COMPONENT_SELECTION_RESOLUTION - 1 ) + 0.5);
+ break;
+
+ case S_COMPONENT:
+ hComponent = (int)(x*1.0*HSV_MAX_H_VALUE/( KXYColorSelector::COMPONENT_SELECTION_RESOLUTION - 1 ) + 0.5);
+ vComponent = (int)(y*1.0*HSV_MAX_V_VALUE/( KXYColorSelector::COMPONENT_SELECTION_RESOLUTION - 1 ) + 0.5);
+ break;
+
+ case V_COMPONENT:
+ hComponent = (int)(x*1.0*HSV_MAX_H_VALUE/( KXYColorSelector::COMPONENT_SELECTION_RESOLUTION - 1 ) + 0.5);
+ sComponent = (int)(y*1.0*HSV_MAX_S_VALUE/( KXYColorSelector::COMPONENT_SELECTION_RESOLUTION - 1 ) + 0.5);
+ break;
+
+ }
+ QColor rgbColor;
+ rgbColor.setHsv(hComponent, sComponent, vComponent);
+ color.setComponents(rgbColor.red(), rgbColor.green(), rgbColor.blue());
+ updateZColorSelector();
+ emit valueChanged(&color);
+}
+
+void GradientSelection::slotZColorSelectorPosChanged(int y) {
+ bool repaintZColorSelector = false;
+ switch(zColorSelectorComponentIndex) {
+ case H_COMPONENT:
+ hComponent = y;
+ break;
+
+ case S_COMPONENT:
+ sComponent = y;
+ break;
+
+ case V_COMPONENT:
+ vComponent = y;
+ break;
+
+ }
+ QColor rgbColor;
+ rgbColor.setHsv(hComponent, sComponent, vComponent);
+ color.setComponents(rgbColor.red(), rgbColor.green(), rgbColor.blue());
+ updateXyColorSelector(false);
+ if(repaintZColorSelector)
+ updateZColorSelector();
+ emit valueChanged(&color);
+}
+
+void GradientSelection::slotSynchronizeColor() {
+ emit synchronizeColor();
+}
+
+void GradientSelection::enableSynchronizeColorButton(bool enable) {
+ synchronizeColorButton->setEnabled(enable);
+}
+#include "gradientselection.moc"
diff --git a/kcoloredit/gradientselection.h b/kcoloredit/gradientselection.h
new file mode 100644
index 00000000..24a3c5e1
--- /dev/null
+++ b/kcoloredit/gradientselection.h
@@ -0,0 +1,106 @@
+/***************************************************************************
+ gradientselection.h - description
+ -------------------
+ begin : Wed Jul 12 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef GRADIENTSELECTION_H
+#define GRADIENTSELECTION_H
+
+#include <qwidget.h>
+#include <qcheckbox.h>
+#include <qpushbutton.h>
+#include <qbuttongroup.h>
+
+#include "kxycolorselector.h"
+#include "kzcolorselector.h"
+#include "color.h"
+
+/** A widget for selecting colors from gradients
+ * @author Artur Rataj
+ */
+class GradientSelection : public QWidget {
+ Q_OBJECT
+
+public:
+ /** Constructs the widget */
+ GradientSelection(QWidget *parent=0, const char *name=0);
+ ~GradientSelection();
+ /** Enables or disables the color synchronize button */
+ void enableSynchronizeColorButton(bool enable);
+
+signals:
+ /** A signal that a color value has changed by edition */
+ void valueChanged(Color*);
+ /** Synchronizes the widget color */
+ void synchronizeColor();
+
+public slots:
+ /** Sets a color */
+ void slotSetValue(Color* color);
+ /** Whether to ignore the set value slot. Default is false. */
+ void slotIgnoreSetValue(bool ignore);
+
+protected:
+ /** Components indices. If the gradient selector shows one of them,
+ * the two components selector should be in a mode indicated by a value
+ * of the appropriate index
+ */
+ enum { H_COMPONENT = KXYColorSelector::TYPE_VS,
+ S_COMPONENT = KXYColorSelector::TYPE_HV,
+ V_COMPONENT = KXYColorSelector::TYPE_HS };
+
+ /** Variable global component checkbox */
+ QCheckBox* variableCheckBox;
+ /** Synchronize color button */
+ QPushButton* synchronizeColorButton;
+ /** HSV buttons button group widget */
+ QButtonGroup hsvButtons;
+ /** The two components selector */
+ KXYColorSelector* xyColorSelector;
+ /** The gradient selector */
+ KZColorSelector* zColorSelector;
+ /** Whether the two component color selector global component is variable */
+ bool variableGlobalComponent;
+ /** Whether to ignore the set value slot */
+ bool ignoreSetValue;
+ /** The selected color */
+ Color color;
+ /** The selected color H component */
+ int hComponent;
+ /** The selected color S component */
+ int sComponent;
+ /** The selected color V component */
+ int vComponent;
+ /** The gradient selector component index */
+ int zColorSelectorComponentIndex;
+ /** Updates two component selector colors */
+ void updateXyColorSelector(const bool modeChanged);
+ /** Updates gradient selector colors */
+ void updateZColorSelector();
+
+protected slots:
+ /** Sets color selection mode */
+ void slotSetColorSelectionMode(int mode);
+ /** Sets if the two component selector has a variable global component */
+ void slotSetVariableGlobalComponent(bool variable);
+ /** Notifies that the two component color selector pointer position changed */
+ void slotXyColorSelectorPosChanged(int x, int y);
+ /** Notifies that the gradient color selector pointer position changed */
+ void slotZColorSelectorPosChanged(int y);
+ /** sends synchronizeColor signal */
+ void slotSynchronizeColor();
+};
+
+#endif
diff --git a/kcoloredit/hi16-app-kcolorchooser.png b/kcoloredit/hi16-app-kcolorchooser.png
new file mode 100644
index 00000000..eeb387b3
--- /dev/null
+++ b/kcoloredit/hi16-app-kcolorchooser.png
Binary files differ
diff --git a/kcoloredit/hi16-app-kcoloredit.png b/kcoloredit/hi16-app-kcoloredit.png
new file mode 100644
index 00000000..c0a67bb9
--- /dev/null
+++ b/kcoloredit/hi16-app-kcoloredit.png
Binary files differ
diff --git a/kcoloredit/hi22-app-kcolorchooser.png b/kcoloredit/hi22-app-kcolorchooser.png
new file mode 100644
index 00000000..faa5080f
--- /dev/null
+++ b/kcoloredit/hi22-app-kcolorchooser.png
Binary files differ
diff --git a/kcoloredit/hi32-app-kcoloredit.png b/kcoloredit/hi32-app-kcoloredit.png
new file mode 100644
index 00000000..e5aa87cb
--- /dev/null
+++ b/kcoloredit/hi32-app-kcoloredit.png
Binary files differ
diff --git a/kcoloredit/imageselection.cpp b/kcoloredit/imageselection.cpp
new file mode 100644
index 00000000..39a8f2f0
--- /dev/null
+++ b/kcoloredit/imageselection.cpp
@@ -0,0 +1,28 @@
+/***************************************************************************
+ imageselection.cpp - description
+ -------------------
+ begin : Wed Jul 12 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include "imageselection.h"
+
+ImageSelection::ImageSelection(QWidget *parent, const char *name ) : QWidget(parent,name) {
+}
+ImageSelection::~ImageSelection(){
+}
+
+void ImageSelection::slotSetValue(Color* color) {
+ this->color = *color;
+}
+#include "imageselection.moc"
diff --git a/kcoloredit/imageselection.h b/kcoloredit/imageselection.h
new file mode 100644
index 00000000..3137fec7
--- /dev/null
+++ b/kcoloredit/imageselection.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ imageselection.h - description
+ -------------------
+ begin : Wed Jul 12 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef IMAGESELECTION_H
+#define IMAGESELECTION_H
+
+#include <qwidget.h>
+
+#include "color.h"
+
+/** This is a widget for selecting colors from an image
+ * @author Artur Rataj
+ */
+class ImageSelection : public QWidget {
+ Q_OBJECT
+
+public:
+ /** constructs the widget */
+ ImageSelection(QWidget *parent=0, const char *name=0);
+ ~ImageSelection();
+
+signals:
+ /** A signal that a color value has changed by edition */
+ void valueChanged(Color*);
+
+public slots:
+ /** Sets a color */
+ void slotSetValue(Color* color);
+
+protected:
+ /** The selected color */
+ Color color;
+};
+
+#endif
diff --git a/kcoloredit/kcolorchooser.cpp b/kcoloredit/kcolorchooser.cpp
new file mode 100644
index 00000000..bf1204fb
--- /dev/null
+++ b/kcoloredit/kcolorchooser.cpp
@@ -0,0 +1,70 @@
+/*
+This file is part of KDE
+
+ Copyright (C) 1998-2000 Waldo Bastian (bastian@kde.org)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include <iostream>
+
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <klocale.h>
+
+#include "kcolordialog.h"
+
+static const char description[] =
+ I18N_NOOP("KDE Color Chooser");
+
+static const char version[] = "v1.0.1";
+
+static KCmdLineOptions options[] =
+{
+ { "print", I18N_NOOP("Print the selected color to stdout"), 0 },
+ KCmdLineLastOption
+};
+
+int main(int argc, char *argv[])
+{
+ KLocale::setMainCatalogue("kdelibs");
+ KAboutData aboutData( "kcolorchooser", I18N_NOOP("KColorChooser"),
+ version, description, KAboutData::License_BSD,
+ "(c) 2000, Waldo Bastian");
+ aboutData.addAuthor("Waldo Bastian",0, "bastian@kde.org");
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ KCmdLineArgs::addCmdLineOptions( options );
+
+ KApplication app;
+
+ KColorDialog dlg;
+
+ dlg.setColor(Qt::blue); // Just a color
+
+ app.connect(&dlg, SIGNAL(finished()), SLOT(quit()));
+
+ dlg.show();
+ app.exec();
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ const QColor c = dlg.color();
+ if ( args->isSet("print") && c.isValid() ) {
+ std::cout << c.name().utf8().data() << std::endl;
+ }
+}
diff --git a/kcoloredit/kcolorchooser.desktop b/kcoloredit/kcolorchooser.desktop
new file mode 100644
index 00000000..37d7b075
--- /dev/null
+++ b/kcoloredit/kcolorchooser.desktop
@@ -0,0 +1,108 @@
+[Desktop Entry]
+Type=Application
+Exec=kcolorchooser %i %m
+Icon=kcolorchooser
+Path=
+Terminal=false
+DocPath=kcoloredit/index.html
+GenericName=Color Chooser
+GenericName[af]=Kleur Kieser
+GenericName[ar]=برنامج اختيار الألوان
+GenericName[bg]=Избор на цвят
+GenericName[br]=Dibaber livioù
+GenericName[bs]=Izbornik boja
+GenericName[ca]=Elecció de colors
+GenericName[cs]=Výběr barev
+GenericName[cy]=Dewis Lliwiau
+GenericName[da]=Farvevælger
+GenericName[de]=Farbauswahl
+GenericName[el]=Επιλογέας χρωμάτων
+GenericName[en_GB]=Colour Chooser
+GenericName[eo]=Ilo por elekti koloron
+GenericName[es]=Selector de colores
+GenericName[et]=Värvivalija
+GenericName[eu]=Kolore hautatzailea
+GenericName[fa]=انتخاب‌‌کنندۀ رنگ
+GenericName[fi]=Värivalitsin
+GenericName[fr]=Sélecteur de couleur
+GenericName[gl]=Selecionador de cores
+GenericName[he]=בוחר צבעים
+GenericName[hi]=रंग चयनक
+GenericName[hr]=Izbornik boja
+GenericName[hu]=Színválasztó
+GenericName[is]=Litavalstól
+GenericName[it]=Selettore di colori
+GenericName[ja]=色の選択
+GenericName[kk]=Түсті таңдау
+GenericName[km]=កម្មវិធី​ជ្រើស​ពណ៌
+GenericName[lt]=Spalvų parinkiklis
+GenericName[lv]=Krāsu Izvēlētājs
+GenericName[mk]=Избирач на бои
+GenericName[ms]=Pemilih Warna
+GenericName[mt]=Agħżel Kulur
+GenericName[nb]=Fargevelger
+GenericName[nds]=Klöörutwahl
+GenericName[ne]=रङ चयनकर्ता
+GenericName[nl]=Kleurenkiezer
+GenericName[nn]=Fargeveljar
+GenericName[pa]=ਰੰਗ ਸੰਰਚਨਾ
+GenericName[pl]=Wybór koloru
+GenericName[pt]=Selector de Cores
+GenericName[pt_BR]=Seletor de Cores
+GenericName[ro]=Selector de culori
+GenericName[ru]=Выбор цвета
+GenericName[se]=Ivdneválljejeaddji
+GenericName[sk]=Výber farieb
+GenericName[sl]=Izbirnik barv
+GenericName[sr]=Бирач боја
+GenericName[sr@Latn]=Birač boja
+GenericName[sv]=Färgväljare
+GenericName[ta]=வண்ணத் தேர்வு
+GenericName[tg]=Интихоби ранг
+GenericName[th]=เครื่องมือเลือกสีของ KDE
+GenericName[tr]=Renk Seçici
+GenericName[uk]=Селектор кольорів
+GenericName[uz]=Rang tanlovchi
+GenericName[uz@cyrillic]=Ранг танловчи
+GenericName[ven]=Munangi wa Muvhala
+GenericName[wa]=Tchoezixheu di coleurs
+GenericName[xh]=Mkhethi Wombala
+GenericName[zh_CN]=颜色选择程序
+GenericName[zh_HK]=顏色選擇器
+GenericName[zh_TW]=顏色選擇程式
+GenericName[zu]=Umkhethi Wombala
+Name=KColorChooser
+Name[af]=K-kleur-kieser
+Name[ar]=برنامج KColorChooser
+Name[ca]=Elecció de colors
+Name[cs]=Výběr barev
+Name[cy]=KDewisLliw
+Name[eo]=Kolorelektilo
+Name[fi]=Värivalitsin
+Name[hi]=के-कलर-चूसर
+Name[hr]=Izbornik boja
+Name[is]=Litaval
+Name[lv]=KKrāsuIzvēlētājs
+Name[nb]=Fargevelger
+Name[ne]=केडीई रङ चयनकर्ता
+Name[nn]=KDE-fargeveljar
+Name[nso]=KMokgethi wa Mmala
+Name[pa]=ਕੇਰੰਗਚੋਣਕਾਰ
+Name[pl]=Wybór koloru
+Name[pt_BR]=KSeletor de Cores
+Name[ro]=Selector culori
+Name[se]=KDE-ivdneválljejeaddji
+Name[sv]=Kcolorchooser
+Name[ta]=கேவண்ணத் தேர்வு
+Name[th]=เครื่องมือเลือกสี - K
+Name[tr]=K Renk Seçici
+Name[uk]=Селектор кольорів
+Name[uz]=Rang tanlovchi
+Name[uz@cyrillic]=Ранг танловчи
+Name[ven]=Tshinangi tsha muvhala tsha K
+Name[xh]=Umkhethi Wombala i K
+Name[zh_TW]=KColorChooser 顏色選擇器
+Name[zu]=Umkhethi Wombala ka K
+
+X-DCOP-ServiceType=Multi
+Categories=Qt;KDE;Graphics;X-KDE-More;
diff --git a/kcoloredit/kcoloredit.cpp b/kcoloredit/kcoloredit.cpp
new file mode 100644
index 00000000..a5582436
--- /dev/null
+++ b/kcoloredit/kcoloredit.cpp
@@ -0,0 +1,363 @@
+/***************************************************************************
+ kcoloredit.cpp - description
+ -------------------
+ begin : Sat Jul 8 09:57:28 CEST 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+// include files for QT
+#include <qdir.h>
+#include <qprinter.h>
+#include <qpainter.h>
+
+// include files for KDE
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <kfiledialog.h>
+#include <kmenubar.h>
+#include <klocale.h>
+#include <kcolordialog.h>
+#include <kconfig.h>
+#include <kdebug.h>
+
+// application specific includes
+#include "kcoloredit.h"
+#include "kcoloreditview.h"
+#include "kcoloreditdoc.h"
+#include "loadpalettedlg.h"
+#include "resource.h"
+#include <kpopupmenu.h>
+#include <kstatusbar.h>
+
+
+KColorEditApp::KColorEditApp() : KMainWindow(0) {
+ config=kapp->config();
+
+ ///////////////////////////////////////////////////////////////////
+ // call inits to invoke all other construction parts
+ initActions();
+ initStatusBar();
+ initDocument();
+ initView();
+
+ resize(606,400);
+ setupGUI();
+
+ readOptions();
+
+ gettingColorFromScreen = false;
+}
+
+KColorEditApp::~KColorEditApp() {
+}
+
+void KColorEditApp::initActions()
+{
+ // File actiojns
+ KStdAction::openNew( this, SLOT( slotFileNew() ), actionCollection() );
+ KStdAction::open( this, SLOT( slotFileOpen() ), actionCollection() );
+ KStdAction::saveAs( this, SLOT( slotFileSaveAs() ), actionCollection() );
+ KStdAction::close( this, SLOT( slotClose() ), actionCollection() );
+ KStdAction::quit( this, SLOT( slotQuit() ), actionCollection() );
+ m_actSave = KStdAction::save( this, SLOT( slotFileSave() ),
+ actionCollection() );
+ m_actRecent = KStdAction::openRecent( this,
+ SLOT( slotFileOpenRecent( const KURL& ) ), actionCollection() );
+
+ ( void ) new KAction( i18n("New &Window"), kapp->miniIcon(), KShortcut(),
+ this, SLOT( slotFileNewWindow() ), actionCollection(),
+ "file_new_window" );
+
+ // Edit actions
+ m_actCut = KStdAction::cut( this, SLOT( slotEditCut() ),
+ actionCollection() );
+ m_actCopy = KStdAction::copy( this, SLOT( slotEditCopy() ),
+ actionCollection() );
+ m_actPaste = KStdAction::paste( this, SLOT( slotEditPaste() ),
+ actionCollection() );
+
+ m_actPaste->setEnabled( false );
+
+ // Color Menu
+ m_actNames = new KToggleAction( i18n("Show &Color Names"), KShortcut(), this,
+ SLOT( slotViewColorNames() ), actionCollection(),
+ "color_view_names" );
+ m_actNames->setCheckedState(i18n("Hide &Color Names"));
+ m_actPalette = new KAction( i18n("From &Palette"), KShortcut(), this,
+ SLOT( slotColorFromPalette() ), actionCollection(),
+ "color_from_palette" );
+ ( void ) new KAction( i18n("From &Screen"), KShortcut(), this,
+ SLOT( slotColorFromScreen() ), actionCollection(),
+ "color_from_screen" );
+}
+
+void KColorEditApp::initStatusBar()
+{
+ statusBar()->insertItem(i18n("Ready."), ID_STATUS_MSG, 1);
+ statusBar()->setItemAlignment( ID_STATUS_MSG, Qt::AlignLeft );
+}
+
+void KColorEditApp::initDocument()
+{
+ doc = new KColorEditDoc(this);
+ doc->newDocument();
+
+ connect( doc, SIGNAL( selectionChanged( int, int ) ),
+ SLOT( slotSelectionChanged( int, int ) ) );
+ connect( doc, SIGNAL( clipboardChanged() ),
+ SLOT( slotClipboardChanged() ) );
+ connect( doc, SIGNAL( modified( bool ) ),
+ SLOT( slotModified( bool ) ) );
+ connect( doc, SIGNAL( paletteAvailable( bool ) ),
+ SLOT( slotPaletteAvailable( bool ) ) );
+}
+
+void KColorEditApp::initView()
+{
+ ////////////////////////////////////////////////////////////////////
+ // create the main widget here that is managed by KMainWindow's view-region
+ // and connect the widget to your document to display document contents.
+
+ view = new KColorEditView(this);
+ doc->addView(view);
+ setCentralWidget(view);
+ setCaption(doc->title());
+}
+
+void KColorEditApp::openDocumentFile(const char* _cmdl)
+{
+ doc->openDocument(_cmdl);
+}
+
+
+KColorEditDoc *KColorEditApp::document() const
+{
+ return doc;
+}
+
+void KColorEditApp::saveOptions()
+{
+ saveMainWindowSettings( config, "MainWindowSettings" );
+ m_actRecent->saveEntries( config );
+
+ config->setGroup("KColorEdit Options");
+ config->writeEntry("ColorNames", viewColorNames);
+}
+
+void KColorEditApp::readOptions()
+{
+ applyMainWindowSettings( config, "MainWindowSettings" );
+ m_actRecent->loadEntries( config );
+
+ config->setGroup("KColorEdit Options");
+
+ viewColorNames = config->readBoolEntry("ColorNames", false);
+ m_actNames->setChecked(viewColorNames);
+ doc->slotChangeViewMode(viewColorNames);
+}
+
+bool KColorEditApp::queryClose()
+{
+ return doc->saveModified();
+}
+
+bool KColorEditApp::queryExit()
+{
+ saveOptions();
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////
+// SLOT IMPLEMENTATION
+/////////////////////////////////////////////////////////////////////
+
+void KColorEditApp::slotSelectionChanged( int begin, int end )
+{
+ m_actCut->setEnabled( begin != end );
+ m_actCopy->setEnabled( begin != end );
+}
+
+void KColorEditApp::slotClipboardChanged()
+{
+ m_actPaste->setEnabled( true );
+}
+
+void KColorEditApp::slotModified( bool b )
+{
+ m_actSave->setEnabled( b );
+}
+
+void KColorEditApp::slotPaletteAvailable( bool b )
+{
+ m_actPalette->setEnabled( b );
+}
+
+void KColorEditApp::slotFileNewWindow()
+{
+ KColorEditApp *new_window= new KColorEditApp();
+ new_window->show();
+}
+
+void KColorEditApp::slotFileNew()
+{
+ if(doc->saveModified()) {
+ doc->newDocument();
+
+ setCaption(doc->title());
+ }
+}
+
+void KColorEditApp::slotFileOpen() {
+ if(doc->saveModified()) {
+ LoadPaletteDlg dialog(this);
+ if(dialog.exec()) {
+ QString fileToOpen = dialog.getFileName();
+ if(!fileToOpen.isEmpty())
+ {
+ if(!doc->openDocument( fileToOpen )) {
+ KMessageBox::sorry(0, doc->errorString());
+ } else {
+ setCaption(doc->title());
+ m_actRecent->addURL( KURL::fromPathOrURL( fileToOpen ) );
+ }
+ }
+ }
+ }
+}
+
+void KColorEditApp::slotFileOpenRecent( const KURL & url )
+{
+ if(doc->saveModified()) {
+ doc->openDocument( url.path() );
+ setCaption(doc->title());
+ }
+}
+
+void KColorEditApp::slotFileSave()
+{
+ if(!doc->saveDocument( doc->absFilePath() ))
+ slotFileSaveAs();
+ //KMessageBox::sorry(0, doc->getErrorString());
+}
+
+bool KColorEditApp::slotFileSaveAs()
+{
+ bool result = true;
+
+ while(result) {
+ QString newName=KFileDialog::getSaveFileName(lastSavePaletteAsFileDir,
+ "*|" + i18n("All Files"), this, i18n("Save As"));
+ if(newName.isEmpty())
+ result = false;
+ else {
+ QFileInfo saveAsInfo(newName);
+ if(!saveAsInfo.exists() ||
+ KMessageBox::questionYesNo( this,
+ i18n("A Document with this name already exists.\n"
+ "Do you want to overwrite it?"),
+ i18n("Warning"), i18n("Overwrite"), KStdGuiItem::cancel() ) == KMessageBox::Yes) {
+ if(!doc->saveDocument( newName )) {
+ KMessageBox::sorry(0, doc->errorString());
+ result = false;
+ } else {
+ doc->setTitle(saveAsInfo.fileName());
+ doc->setAbsFilePath(saveAsInfo.absFilePath());
+ setCaption(doc->title());
+ lastSavePaletteAsFileDir = saveAsInfo.absFilePath();
+ m_actRecent->addURL( KURL( newName ) );
+ break;
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+void KColorEditApp::slotClose()
+{
+ close();
+}
+
+void KColorEditApp::slotFilePrint()
+{
+ QPrinter printer;
+ if (printer.setup(this))
+ {
+ view->print(&printer);
+ }
+}
+
+void KColorEditApp::slotQuit()
+{
+ saveOptions();
+ // close the first window, the list makes the next one the first again.
+ // This ensures that queryClose() is called on each window to ask for closing
+ KMainWindow* w;
+ if(memberList)
+ {
+ for(w=memberList->first(); w!=0; w=memberList->next())
+ {
+ // only close the window if the closeEvent is accepted. If the user presses Cancel on the saveModified() dialog,
+ // the window and the application stay open.
+ if(!w->close())
+ break;
+ }
+ }
+}
+
+void KColorEditApp::slotEditCut()
+{
+ doc->cut();
+}
+
+void KColorEditApp::slotEditCopy()
+{
+ doc->copy();
+}
+
+void KColorEditApp::slotEditPaste()
+{
+ doc->paste();
+}
+
+void KColorEditApp::slotColorFromPalette() {
+ view->chooseColor(doc->paletteHistory()->editableStream()->
+ color( doc->paletteCursorPos() ));
+}
+
+void KColorEditApp::slotColorFromScreen() {
+ gettingColorFromScreen = true;
+ grabMouse(crossCursor);
+ grabKeyboard();
+}
+
+void KColorEditApp::slotViewColorNames()
+{
+ viewColorNames = m_actNames->isChecked();
+ doc->slotChangeViewMode(viewColorNames);
+}
+
+void KColorEditApp::mouseReleaseEvent(QMouseEvent* event) {
+ if(gettingColorFromScreen) {
+ gettingColorFromScreen = false;
+ releaseMouse();
+ releaseKeyboard();
+ QColor rgbColor = KColorDialog::grabColor(event->globalPos());
+ color.setComponents(rgbColor.red(), rgbColor.green(), rgbColor.blue());
+ view->chooseColor(&color);
+ } else
+ KMainWindow::mouseReleaseEvent(event);
+}
+
+#include "kcoloredit.moc"
diff --git a/kcoloredit/kcoloredit.desktop b/kcoloredit/kcoloredit.desktop
new file mode 100644
index 00000000..8a27dce8
--- /dev/null
+++ b/kcoloredit/kcoloredit.desktop
@@ -0,0 +1,96 @@
+[Desktop Entry]
+Type=Application
+Exec=kcoloredit %i %m %U
+Icon=kcoloredit
+Path=
+Terminal=false
+DocPath=kcoloredit/index.html
+GenericName=Color Palette Editor
+GenericName[af]=Kleur Palet Redigeerder
+GenericName[ar]=محرر لوحة الألوان
+GenericName[bg]=Редактор на цветове
+GenericName[br]=Aozer livaoueg
+GenericName[bs]=Editor palete boja
+GenericName[ca]=Editor de la paleta de colors
+GenericName[cs]=Editor palety barev
+GenericName[cy]=Golygydd Palet Lliwiau
+GenericName[da]=Farvepaletredigering
+GenericName[de]=Editor für Farbpaletten
+GenericName[el]=Επεξεργαστής παλέτας χρωμάτων
+GenericName[en_GB]=Colour Palette Editor
+GenericName[eo]=Paletroredaktilo
+GenericName[es]=Editor de paleta de color
+GenericName[et]=Värvipaleti redaktor
+GenericName[eu]=Koloreko paleta editorea
+GenericName[fa]=ویرایشگر پالت رنگ
+GenericName[fi]=Väripalettien muokkain
+GenericName[fr]=Éditeur de palette de couleurs
+GenericName[gl]=Editor de paletas de cores
+GenericName[he]=עורך לוחות צבעים
+GenericName[hi]=रंग पट्टिका संपादक
+GenericName[hr]=Uređivač palete
+GenericName[hu]=Palettaszerkesztő
+GenericName[is]=Sýsla með litaspjöld
+GenericName[it]=Editor di tavolozza
+GenericName[ja]=カラーパレットエディタ
+GenericName[kk]=Түстер палитрасын өңдеу
+GenericName[km]=កម្មវិធី​និពន្ធ​ក្ដារ​លាយ​ពណ៌
+GenericName[lt]=Spalvų paletės redaktorius
+GenericName[lv]=Krāsu Paletes Redaktors
+GenericName[mk]=Уредувач на палета
+GenericName[ms]=Editor Palet Warna
+GenericName[mt]=Editur tal-palett ta' kului
+GenericName[nb]=Palett-redigerer
+GenericName[nds]=Klörensett-Editor
+GenericName[ne]=रङदानी सम्पादक
+GenericName[nl]=Kleurenpaletbewerker
+GenericName[nn]=Palettredigering
+GenericName[pa]=ਰੰਗ ਪੱਟੀ ਸੰਪਾਦਕ
+GenericName[pl]=Edytor palety (kolorów)
+GenericName[pt]=Editor de Paletas de Cores
+GenericName[pt_BR]=Editor de Paleta de Cores
+GenericName[ro]=Editor paletă de culori
+GenericName[ru]=Редактор палитры
+GenericName[se]=Ivdnepaleahta doaimmaheaddji
+GenericName[sk]=Editor palety farieb
+GenericName[sl]=Urejevalnik barvne palete
+GenericName[sr]=Уређивач палете боја
+GenericName[sr@Latn]=Uređivač palete boja
+GenericName[sv]=Färgpaletteditor
+GenericName[ta]=வண்ணகளஞ்சியம்
+GenericName[tg]=Муҳаррири палитра
+GenericName[th]=เครื่องมือแก้ไขจานสีของ KDE
+GenericName[tr]=Renk Paleti Düzenleyici
+GenericName[uk]=Редактор палітри кольорів
+GenericName[ven]=Musengulusi wa phalete ya muvhala
+GenericName[wa]=Aspougneu del palete di coleurs
+GenericName[zh_CN]=调色板编辑器
+GenericName[zh_HK]=調色板編輯器
+GenericName[zh_TW]=調色板編輯器
+GenericName[zu]=Umhleli Wombala we Palette
+Name=KColorEdit
+Name[af]=K-kleur-redigeer
+Name[ar]=برنامج KColorEdit
+Name[cs]=Editor barev
+Name[cy]=KGolyguLliw
+Name[eo]=Kolorredaktilo
+Name[hi]=के-कलर-एडिट
+Name[hr]=Uređivač boja
+Name[lv]=KKrāsuRedaktors
+Name[ne]=केडीई रङ सम्पादन
+Name[nso]=KPhetoso ya Mmala
+Name[pa]=ਕੇਰੰਗ ਸੰਪਾਦਕ
+Name[pl]=Edytor kolorów
+Name[pt_BR]=KEditor de Cores
+Name[ro]=Editor culori
+Name[sv]=Kcoloredit
+Name[ta]=கேவண்ணம் திருத்தம்
+Name[th]=แก้ไขค่าสี - K
+Name[tr]=K Renk Düzenleyici
+Name[ven]=U sengulusa muvhala ha K
+Name[xh]=Umhleli Wombala ye K
+Name[zh_TW]=KColorEdit 顏色編輯器
+Name[zu]=Umhleli Wombala ka K
+
+X-DCOP-ServiceType=Multi
+Categories=Qt;KDE;Graphics;X-KDE-More;
diff --git a/kcoloredit/kcoloredit.h b/kcoloredit/kcoloredit.h
new file mode 100644
index 00000000..cd69cdaf
--- /dev/null
+++ b/kcoloredit/kcoloredit.h
@@ -0,0 +1,192 @@
+/***************************************************************************
+ kcoloredit.h - description
+ -------------------
+ begin : Sat Jul 8 09:57:28 CEST 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KCOLOREDIT_H
+#define KCOLOREDIT_H
+
+
+#include <config.h>
+
+// include files for Qt
+#include <qevent.h>
+#include <qstringlist.h>
+
+// include files for KDE
+#include <kapplication.h>
+#include <kmainwindow.h>
+#include <kaction.h>
+
+// application specific includes
+#include "color.h"
+
+class KColorEditDoc;
+class KColorEditView;
+
+/**
+ * The base class for KColorEdit application windows. It sets up the main
+ * window and reads the config file as well as providing a menubar, toolbar
+ * and statusbar. An instance of KColorEditView creates your center view, which is connected
+ * to the window's Doc object.
+ * KColorEditApp reimplements the methods that KMainWindow provides for main window handling and supports
+ * full session management as well as keyboard accelerator configuration by using KAccel.
+ * @see KMainWindow
+ * @see KApplication
+ * @see KConfig
+ * @see KAccel
+ *
+ * @author Source Framework Automatically Generated by KDevelop, (c) The KDevelop Team.
+ * @version KDevelop version 0.4 code generation
+ */
+class KColorEditApp : public KMainWindow
+{
+ Q_OBJECT
+
+ friend class KColorEditView;
+
+ public:
+ /** construtor of KColorEditApp, calls all init functions to create the application.
+ * @see initMenuBar initToolBar
+ */
+ KColorEditApp();
+ ~KColorEditApp();
+
+ /** opens a file specified by commandline option
+ */
+ void openDocumentFile(const char *_cmdl=0);
+ /** returns a pointer to the current document connected to the KMainWindow instance and is used by
+ * the View class to access the document object's methods
+ */
+ KColorEditDoc *document() const;
+
+ protected:
+ /** save general Options like all bar positions and status as well as the geometry and the recent file list to the configuration
+ * file
+ */
+ void saveOptions();
+ /** read general Options again and initialize all variables like the recent file list
+ */
+ void readOptions();
+
+ void initActions();
+
+ /** initMenuBar creates the menubar and inserts the menupopups as well as creating the helpMenu.
+ * @see KApplication#getHelpMenu
+ */
+ void initStatusBar();
+ /** initializes the document object of the main window that is connected to the view in initView().
+ * @see initView();
+ */
+ void initDocument();
+ /** creates the centerwidget of the KMainWindow instance and sets it as the view
+ */
+ void initView();
+ /** queryClose is called by KMainWindow on each closeEvent of a window. Against the
+ * default implementation (only returns true), this calles saveModified() on the document object to ask if the document shall
+ * be saved if Modified; on cancel the closeEvent is rejected.
+ * @see KMainWindow#queryClose
+ * @see KMainWindow#closeEvent
+ */
+ virtual bool queryClose();
+ /** queryExit is called by KMainWindow when the last window of the application is going to be closed during the closeEvent().
+ * Against the default implementation that just returns true, this calls saveOptions() to save the settings of the last window's
+ * properties.
+ * @see KMainWindow#queryExit
+ * @see KMainWindow#closeEvent
+ */
+ virtual bool queryExit();
+
+ void mouseReleaseEvent(QMouseEvent* event);
+
+ public slots:
+
+ void slotFileNewWindow();
+ /** clears the document in the actual view to reuse it as the new document */
+ void slotFileNew();
+ /** open a file and load it into the document*/
+ void slotFileOpen();
+ /** opens a file from the recent files menu */
+ void slotFileOpenRecent( const KURL & );
+ /** save a document */
+ void slotFileSave();
+ /** save a document by a new filename
+ * @return whether the file has been saved
+ */
+ bool slotFileSaveAs();
+ /** asks for saving if the file is modified, then closes the actual file and window*/
+ void slotClose();
+ /** print the actual file */
+ void slotFilePrint();
+ /** closes all open windows by calling close() on each memberList item until the list is empty, then quits the application.
+ * If queryClose() returns false because the user canceled the saveModified() dialog, the closing breaks.
+ */
+ void slotQuit();
+ /** put the marked text/object into the clipboard and remove
+ * it from the document
+ */
+ void slotEditCut();
+ /** put the marked text/object into the clipboard
+ */
+ void slotEditCopy();
+ /** paste the clipboard into the document
+ */
+ void slotEditPaste();
+ /** get a color from palette
+ */
+ void slotColorFromPalette();
+ /** get a color from screen
+ */
+ void slotColorFromScreen();
+ /** copies a color to clipboard
+ */
+ void slotViewColorNames();
+ /** changes the statusbar contents for the standard label permanently, used to indicate current actions.
+ * @param text the text that is displayed in the statusbar
+ */
+
+ void slotSelectionChanged( int, int );
+ void slotClipboardChanged();
+ void slotModified( bool );
+ void slotPaletteAvailable( bool );
+
+ private:
+
+ /** the configuration object of the application */
+ KConfig *config;
+
+ KAction *m_actSave, *m_actCut, *m_actCopy, *m_actPaste, *m_actPalette;
+ KToggleAction *m_actNames;
+ KRecentFilesAction *m_actRecent;
+
+ /** view is the main widget which represents your working area. The View
+ * class should handle all events of the view widget. It is kept empty so
+ * you can create your view according to your application's needs by
+ * changing the view class.
+ */
+ KColorEditView *view;
+ /** doc represents your actual document and is created only once. It keeps
+ * information such as filename and does the serialization of your files.
+ */
+ KColorEditDoc *doc;
+ /** Whether in getting a color from screen */
+ bool gettingColorFromScreen;
+ /** A color taken from screen */
+ Color color;
+ /** Whether to view color names */
+ bool viewColorNames;
+};
+
+#endif // KCOLOREDIT_H
diff --git a/kcoloredit/kcoloreditdoc.cpp b/kcoloredit/kcoloreditdoc.cpp
new file mode 100644
index 00000000..536300a5
--- /dev/null
+++ b/kcoloredit/kcoloreditdoc.cpp
@@ -0,0 +1,293 @@
+/***************************************************************************
+ kcoloreditdoc.cpp - description
+ -------------------
+ begin : Sat Jul 8 09:57:28 CEST 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+// include files for Qt
+#include <qdir.h>
+#include <qfileinfo.h>
+#include <qwidget.h>
+#include <qclipboard.h>
+
+// include files for KDE
+#include <klocale.h>
+#include <kmessagebox.h>
+
+// application specific includes
+#include "kcoloreditdoc.h"
+#include "kcoloredit.h"
+#include "kcoloreditview.h"
+#include "resource.h"
+
+KColorEditDoc::KColorEditDoc(QWidget *parent, const char *name) : QObject(parent, name),
+ m_palette(), m_paletteHistory(&m_palette, 0) {
+ m_pViewList = new QPtrList<KColorEditView>();
+ m_pViewList->setAutoDelete(true);
+}
+
+KColorEditDoc::~KColorEditDoc()
+{
+}
+
+void KColorEditDoc::addView(KColorEditView *view)
+{
+ m_pViewList->append(view);
+}
+
+void KColorEditDoc::removeView(KColorEditView *view)
+{
+ m_pViewList->remove(view);
+}
+
+void KColorEditDoc::setModified(bool b) {
+ m_modified = b;
+
+ emit modified( b );
+}
+
+void KColorEditDoc::setAbsFilePath(const QString &filename)
+{
+ m_absFilePath=filename;
+}
+
+const QString &KColorEditDoc::absFilePath() const
+{
+ return m_absFilePath;
+}
+
+void KColorEditDoc::setTitle(const QString &_t)
+{
+ m_title=_t;
+}
+
+const QString &KColorEditDoc::title() const
+{
+ return m_title;
+}
+
+void KColorEditDoc::slotRedrawAllViews(KColorEditView *sender, bool newDocument) {
+ KColorEditView *w;
+ if(m_pViewList)
+ {
+ for(w=m_pViewList->first(); w!=0; w=m_pViewList->next())
+ {
+ if(w!=sender)
+ w->redraw(newDocument);
+ }
+ }
+}
+
+void KColorEditDoc::slotChangeViewMode(bool viewColorNames) {
+ KColorEditView *w;
+ if(m_pViewList)
+ {
+ for(w=m_pViewList->first(); w!=0; w=m_pViewList->next())
+ {
+ w->slotViewColorNames(viewColorNames);
+ }
+ }
+}
+
+bool KColorEditDoc::saveModified()
+{
+ bool completed=true;
+
+ if(m_modified)
+ {
+ KColorEditApp *window=(KColorEditApp *) parent();
+ int want_save = KMessageBox::warningYesNoCancel(window,
+ i18n("The current file has been modified.\n"
+ "Do you want to save it?"), QString::null, KStdGuiItem::save(), i18n("Do Not Save"));
+ switch(want_save)
+ {
+ case KMessageBox::Yes:
+ if (title() == i18n("Untitled"))
+ {
+ completed = window->slotFileSaveAs();
+ }
+ else
+ {
+ completed = saveDocument(absFilePath());
+ };
+ if(!completed)
+ KMessageBox::sorry(0, errorString());
+ break;
+
+ case KMessageBox::No:
+ completed=true;
+ break;
+
+ case KMessageBox::Cancel:
+ completed=false;
+ break;
+
+ default:
+ completed=false;
+ break;
+ }
+ }
+
+ return completed;
+}
+
+void KColorEditDoc::closeDocument()
+{
+ deleteContents();
+}
+
+bool KColorEditDoc::newDocument()
+{
+ deleteContents();
+ setModified(false);
+ setAbsFilePath( QDir::homeDirPath() );
+ setTitle( i18n("Untitled") );
+ setPaletteCursorPos(0);
+ setPaletteSelection(0, 0);
+ slotRedrawAllViews(0, true);
+ return true;
+}
+
+bool KColorEditDoc::openDocument(const QString& filename) {
+ if(filename.isEmpty())
+ return newDocument();
+ else {
+ deleteContents();
+ QFileInfo fileInfo(filename);
+ setAbsFilePath( fileInfo.absFilePath() );
+ if(!m_palette.load( absFilePath() )) {
+ setErrorString(m_palette.errorString());
+ return false;
+ }
+ setModified(false);
+ setTitle( fileInfo.fileName() );
+ setPaletteCursorPos(m_palette.length());
+ setPaletteSelection(0, 0);
+ slotRedrawAllViews(0, true);
+ KColorEditApp *window=(KColorEditApp*)parent();
+ window->setCaption(m_title);
+ }
+ return true;
+}
+
+bool KColorEditDoc::saveDocument(const QString& filename) {
+ if(!m_palette.save( filename )) {
+ setErrorString(m_palette.errorString());
+ return false;
+ }
+ setModified(false);
+ return true;
+}
+
+void KColorEditDoc::deleteContents() {
+ m_palette.deleteContents();
+}
+
+void KColorEditDoc::setErrorString(const QString& string) {
+ m_errorString = string;
+}
+
+const QString& KColorEditDoc::errorString() const {
+ return m_errorString;
+}
+
+PaletteHistory* KColorEditDoc::paletteHistory() {
+ return &m_paletteHistory;
+}
+
+void KColorEditDoc::setPaletteCursorPos(const int pos) {
+ m_paletteCursorPos = pos;
+
+ emit paletteAvailable( pos < m_palette.length() );
+}
+
+int KColorEditDoc::paletteCursorPos() {
+ return m_paletteCursorPos;
+}
+
+void KColorEditDoc::setPaletteSelection(const int begin, const int end) {
+ m_paletteSelectionBegin = begin;
+ m_paletteSelectionEnd = end;
+
+ emit selectionChanged( begin, end );
+}
+
+int KColorEditDoc::paletteSelectionBegin() const {
+ return m_paletteSelectionBegin;
+}
+
+int KColorEditDoc::paletteSelectionEnd() const {
+ return m_paletteSelectionEnd;
+}
+
+void KColorEditDoc::copyToClipboard(Palette& palette) {
+ QString text;
+ QTextOStream stream(&text);
+ palette.save(stream, 0, false);
+ KApplication::clipboard()->setText(text);
+
+ emit clipboardChanged();
+}
+
+void KColorEditDoc::copy() {
+ Palette paletteCopy = m_palette.copy(paletteSelectionBegin(),
+ paletteSelectionEnd() - paletteSelectionBegin());
+ copyToClipboard(paletteCopy);
+}
+
+void KColorEditDoc::cut() {
+ Palette paletteCut = m_paletteHistory.cut(paletteSelectionBegin(),
+ paletteSelectionEnd() - paletteSelectionBegin());
+ copyToClipboard(paletteCut);
+ setPaletteCursorPos(paletteSelectionBegin());
+ setPaletteSelection(0, 0);
+ setModified(true);
+ slotRedrawAllViews(0);
+}
+
+void KColorEditDoc::paste() {
+ Palette palettePaste;
+ QString text;
+ QTextIStream stream(&text);
+ text = KApplication::clipboard()->text();
+ if(palettePaste.load( stream, false )) {
+ m_paletteHistory.paste(paletteCursorPos(), palettePaste);
+ setPaletteSelection(paletteCursorPos(), paletteCursorPos() +
+ palettePaste.length());
+ setModified(true);
+ slotRedrawAllViews(0);
+ }
+}
+
+void KColorEditDoc::insert(int index, const Color& color) {
+ Palette paletteInsert;
+ Color* insertColor = new Color(color);
+ paletteInsert.append(insertColor);
+ m_paletteHistory.paste(index, paletteInsert);
+ setPaletteCursorPos( index );
+ setPaletteSelection(0, 0);
+ setModified(true);
+ slotRedrawAllViews(0);
+}
+
+void KColorEditDoc::replace(int index, const Color& color) {
+ Palette paletteReplace;
+ Color* replaceColor = new Color(color);
+ paletteReplace.append(replaceColor);
+ m_paletteHistory.replace(index, paletteReplace);
+ setPaletteSelection(0, 0);
+ setModified(true);
+ slotRedrawAllViews(0);
+}
+#include "kcoloreditdoc.moc"
diff --git a/kcoloredit/kcoloreditdoc.h b/kcoloredit/kcoloreditdoc.h
new file mode 100644
index 00000000..1d209f46
--- /dev/null
+++ b/kcoloredit/kcoloreditdoc.h
@@ -0,0 +1,156 @@
+/***************************************************************************
+ kcoloreditdoc.h - description
+ -------------------
+ begin : Sat Jul 8 09:57:28 CEST 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KCOLOREDITDOC_H
+#define KCOLOREDITDOC_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// include files for QT
+#include <qobject.h>
+#include <qstring.h>
+#include <qptrlist.h>
+
+// application specific includes
+#include "palette.h"
+#include "palettehistory.h"
+
+// forward declaration of the KColorEdit classes
+class KColorEditView;
+
+/** KColorEditDoc provides a document object for a document-view model.
+ *
+ * The KColorEditDoc class provides a document object that can be used in conjunction with the classes KColorEditApp and KColorEditView
+ * to create a document-view model for standard KDE applications based on KApplication and KMainWindow. Thereby, the document object
+ * is created by the KColorEditApp instance and contains the document structure with the according methods for manipulation of the document
+ * data by KColorEditView objects. Also, KColorEditDoc contains the methods for serialization of the document data from and to files.
+ *
+ * @author Source Framework Automatically Generated by KDevelop, (c) The KDevelop Team.
+ * @version KDevelop version 0.4 code generation
+ */
+class KColorEditDoc : public QObject
+{
+ Q_OBJECT
+
+ public:
+ /** Constructor for the fileclass of the application */
+ KColorEditDoc(QWidget *parent, const char *name=0);
+ /** Destructor for the fileclass of the application */
+ ~KColorEditDoc();
+
+ /** adds a view to the document which represents the document contents. Usually this is your main view. */
+ void addView(KColorEditView *view);
+ /** removes a view from the list of currently connected views */
+ void removeView(KColorEditView *view);
+ /** sets the modified flag for the document after a modifying action on the view connected to the document.*/
+ void setModified(bool modified);
+ /** returns if the document is modified or not. Use this to determine if your document needs saving by the user on closing.*/
+ bool isModified() const { return m_modified; };
+ /** "save modified" - asks the user for saving if the document is modified */
+ bool saveModified();
+ /** deletes the document's contents */
+ void deleteContents();
+ /** initializes the document generally */
+ bool newDocument();
+ /** closes the actual document */
+ void closeDocument();
+ /** loads the document */
+ bool openDocument(const QString& filename);
+ /** saves the document */
+ bool saveDocument(const QString& filename);
+ /** sets the path to the file connected with the document */
+ void setAbsFilePath(const QString &filename);
+ /** returns the pathname of the current document file*/
+ const QString& absFilePath() const;
+ /** sets the filename of the document */
+ void setTitle(const QString &_t);
+ /** returns the title of the document */
+ const QString& title() const;
+ /** @return a description of a possible unsuccessfull IO operation */
+ const QString& errorString() const;
+ /** returns a pointer to paletteHistory */
+ PaletteHistory* paletteHistory();
+ /** sets a palette cursor position */
+ void setPaletteCursorPos(const int pos);
+ /** @return a palette cursor position */
+ int paletteCursorPos();
+ /** Sets palette selection and enables or disables cut/paste
+ * depending on whether any colors are selected
+ */
+ void setPaletteSelection(const int begin, const int end);
+ /** Gets lesser selection position or equal selection position
+ * if no colors are selected
+ */
+ int paletteSelectionBegin() const;
+ /** Gets greater selection position or equal selection position
+ * if no colors are selected
+ */
+ int paletteSelectionEnd() const;
+ /** Copies a selection into a clipboard */
+ void copy();
+ /** Cuts a selection into a clipboard */
+ void cut();
+ /** Pastes a selection from a clipboard */
+ void paste();
+ /** Inserts a color at index */
+ void insert(int index, const Color& color);
+ /** Replaces a color at index */
+ void replace(int index, const Color& color);
+
+ protected:
+ /** Sets an error string if an IO operation was unsuccesfull */
+ void setErrorString(const QString& string);
+ /** Copies a palette to clipboard */
+ void copyToClipboard(Palette& palette);
+
+ public slots:
+ /** Calls redraw() on all views connected to the document object,
+ * except for sender if sender is not null
+ */
+ void slotRedrawAllViews(KColorEditView* sender, bool newDocument = false);
+ /** Sets a view mode */
+ void slotChangeViewMode(bool viewColorNames);
+
+ signals:
+
+ void selectionChanged( int, int );
+ void clipboardChanged();
+ void modified( bool );
+ void paletteAvailable( bool );
+
+ public:
+ /** the list of the views currently connected to the document */
+ QPtrList<KColorEditView> *m_pViewList;
+
+ private:
+ /** the modified flag of the current document */
+ bool m_modified;
+ QString m_title;
+ QString m_absFilePath;
+ QString m_errorString;
+
+ protected:
+ Palette m_palette;
+ PaletteHistory m_paletteHistory;
+ int m_paletteCursorPos;
+ int m_paletteSelectionBegin;
+ int m_paletteSelectionEnd;
+};
+
+#endif // KCOLOREDITDOC_H
diff --git a/kcoloredit/kcoloreditui.rc b/kcoloredit/kcoloreditui.rc
new file mode 100644
index 00000000..d2820c12
--- /dev/null
+++ b/kcoloredit/kcoloreditui.rc
@@ -0,0 +1,26 @@
+<!DOCTYPE kpartgui>
+<kpartgui version="2" name="kcoloredit">
+<ActionProperties>
+ <Action name="color_from_palette" icon="colorize"/>
+ <Action name="color_from_screen" icon="colorpicker"/>
+</ActionProperties>
+
+<MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="file_new_window" append="new_merge"/>
+ </Menu>
+ <Menu name="color"><text>&amp;Color</text>
+ <Action name="color_from_palette"/>
+ <Action name="color_from_screen"/>
+ </Menu>
+ <Menu name="settings">
+ <Action name="color_view_names" append="show_merge"/>
+ </Menu>
+</MenuBar>
+<ToolBar name="mainToolBar" noMerge="1"><text>Main Toolbar</text>
+ <Action name="file_new" />
+ <Action name="file_open" />
+ <Action name="file_save" />
+ <Action name="color_from_screen"/>
+</ToolBar>
+</kpartgui>
diff --git a/kcoloredit/kcoloreditview.cpp b/kcoloredit/kcoloreditview.cpp
new file mode 100644
index 00000000..fe22f136
--- /dev/null
+++ b/kcoloredit/kcoloreditview.cpp
@@ -0,0 +1,282 @@
+/***************************************************************************
+ kcoloreditview.cpp - description
+ -------------------
+ begin : Sat Jul 8 09:57:28 CEST 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+// include files for Qt
+#include <qpainter.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qvgroupbox.h>
+#include <qlineedit.h>
+#include <qcolor.h>
+#include <qprinter.h>
+
+// include files for KDE
+#include <kseparator.h>
+#include <klocale.h>
+
+// application specific includes
+#include "main.h"
+#include "kcoloreditview.h"
+#include "kcoloreditdoc.h"
+#include "kcoloredit.h"
+#include "palette.h"
+
+KColorEditView::KColorEditView(QWidget *parent, const char *name) : QSplitter(parent, name) {
+ colorSelector = new ColorSelector(this);
+ colorSelector->slotSetColor(
+ Color( RGB_MAX_COMPONENT_VALUE, RGB_MAX_COMPONENT_VALUE, RGB_MAX_COMPONENT_VALUE, "" ));
+ QWidget* paletteViewArea = new QWidget(this);
+ QVBoxLayout* paletteLayout = new QVBoxLayout(paletteViewArea);
+ paletteView = new PaletteView(16, 16, 2, this, paletteViewArea);
+ paletteLayout->addWidget(paletteView, 10);
+ QHBoxLayout* layout = new QHBoxLayout();
+ QVBoxLayout* addColorLayout = new QVBoxLayout(4);
+ addColorLayout->setMargin(8);
+ QHBoxLayout* buttonsLayout = new QHBoxLayout(4);
+ QPushButton* addColorButton = new QPushButton(i18n( "Add Color" ), paletteViewArea);
+ connect(addColorButton, SIGNAL( clicked() ), SLOT( slotAddColor() ));
+ buttonsLayout->addWidget(addColorButton);
+ buttonsLayout->addStretch(10);
+ addColorLayout->addLayout(buttonsLayout);
+ QCheckBox* atCursorCheckBox = new QCheckBox(i18n( "At cursor" ), paletteViewArea);
+ connect(atCursorCheckBox, SIGNAL( toggled(bool) ), SLOT( slotAddColorAtCursor(bool) ));
+ addColorLayout->addWidget(atCursorCheckBox);
+ overwriteCheckBox = new QCheckBox(i18n( "Overwrite" ), paletteViewArea);
+ connect(overwriteCheckBox, SIGNAL( toggled(bool) ), SLOT( slotAddColorOverwrite(bool) ));
+ slotAddColorAtCursor(false);
+ slotAddColorOverwrite(false);
+ addColorLayout->addWidget(overwriteCheckBox);
+ addColorLayout->addStretch(10);
+ //KSeparator* hLine = new KSeparator(KSeparator::HLine, paletteViewArea);
+ //addColorLayout->addWidget(hLine);
+ //addColorLayout->addStretch(10);
+ //QCheckBox* cursorFollowsChosenColor = new QCheckBox(i18n( "Cursor follows" ), paletteViewArea);
+ //addColorLayout->addWidget(cursorFollowsChosenColor);
+ //connect(cursorFollowsChosenColor, SIGNAL( toggled(bool) ),
+ // paletteView, SLOT( slotCursorFollowsChosenColor(bool) ));
+ //cursorFollowsChosenColor->toggle();
+ paletteView->slotCursorFollowsChosenColor(true);
+ layout->addLayout(addColorLayout, 0);
+ QVGroupBox* colorAtCursorFrame = new QVGroupBox(i18n("Color at Cursor"), paletteViewArea);
+ QWidget* colorAtCursorFrameArea = new QWidget(colorAtCursorFrame);
+ QVBoxLayout* colorAtCursorLayout = new QVBoxLayout(colorAtCursorFrameArea, 4);
+ QHBoxLayout* colorNameLayout = new QHBoxLayout(0);
+ QLabel* nameLabel = new QLabel(i18n( "Name" ) + ": ", colorAtCursorFrameArea);
+ colorNameLayout->addWidget(nameLabel, 0);
+ colorName = new QLineEdit(colorAtCursorFrameArea);
+ connect(colorName, SIGNAL( textChanged(const QString&) ), SLOT( slotSetColorName(const QString&) ));
+ colorNameLayout->addWidget(colorName, 10);
+ colorAtCursorLayout->addLayout(colorNameLayout);
+ QGridLayout* colorAtCursorComponentsLayout = new QGridLayout(3, 6, 4);
+ colorAtCursorLayout->addLayout(colorAtCursorComponentsLayout);
+ colorAtCursorComponentsLayout->setColStretch(1, 10);
+ colorAtCursorComponentsLayout->addColSpacing(2, 8);
+ colorAtCursorComponentsLayout->setColStretch(4, 10);
+ colorAtCursorComponentsLayout->setColStretch(5, 10);
+ QLabel* hLabel = new QLabel("H: ", colorAtCursorFrameArea);
+ colorAtCursorComponentsLayout->addWidget(hLabel, 0, 0);
+ colorAtCursorHValueLabel = new QLabel("", colorAtCursorFrameArea);
+ setColorAtCursorComponentValueLabelSizes(colorAtCursorHValueLabel);
+ colorAtCursorComponentsLayout->addWidget(colorAtCursorHValueLabel, 0, 1);
+ QLabel* sLabel = new QLabel("S: ", colorAtCursorFrameArea);
+ colorAtCursorComponentsLayout->addWidget(sLabel, 1, 0);
+ colorAtCursorSValueLabel = new QLabel("", colorAtCursorFrameArea);
+ setColorAtCursorComponentValueLabelSizes(colorAtCursorSValueLabel);
+ colorAtCursorComponentsLayout->addWidget(colorAtCursorSValueLabel, 1, 1);
+ QLabel* vLabel = new QLabel("V: ", colorAtCursorFrameArea);
+ colorAtCursorComponentsLayout->addWidget(vLabel, 2, 0);
+ colorAtCursorVValueLabel = new QLabel("", colorAtCursorFrameArea);
+ setColorAtCursorComponentValueLabelSizes(colorAtCursorVValueLabel);
+ colorAtCursorComponentsLayout->addWidget(colorAtCursorVValueLabel, 2, 1);
+ QLabel* rLabel = new QLabel("R: ", colorAtCursorFrameArea);
+ colorAtCursorComponentsLayout->addWidget(rLabel, 0, 3);
+ colorAtCursorRValueLabel = new QLabel("", colorAtCursorFrameArea);
+ setColorAtCursorComponentValueLabelSizes(colorAtCursorRValueLabel);
+ colorAtCursorComponentsLayout->addWidget(colorAtCursorRValueLabel, 0, 4);
+ QLabel* gLabel = new QLabel("G: ", colorAtCursorFrameArea);
+ colorAtCursorComponentsLayout->addWidget(gLabel, 1, 3);
+ colorAtCursorGValueLabel = new QLabel("", colorAtCursorFrameArea);
+ setColorAtCursorComponentValueLabelSizes(colorAtCursorGValueLabel);
+ colorAtCursorComponentsLayout->addWidget(colorAtCursorGValueLabel, 1, 4);
+ QLabel* bLabel = new QLabel("B: ", colorAtCursorFrameArea);
+ colorAtCursorComponentsLayout->addWidget(bLabel, 2, 3);
+ colorAtCursorBValueLabel = new QLabel("", colorAtCursorFrameArea);
+ setColorAtCursorComponentValueLabelSizes(colorAtCursorBValueLabel);
+ colorAtCursorComponentsLayout->addWidget(colorAtCursorBValueLabel, 2, 4);
+ QHBoxLayout* colorAtCursorRgbStringLayout = new QHBoxLayout();
+ QLabel* colorAtCursorRgbStringLabel =
+ new QLabel("RGB " + i18n( "hex." ) + ": ", colorAtCursorFrameArea);
+ colorAtCursorRgbStringLayout->addWidget(colorAtCursorRgbStringLabel);
+ colorAtCursorRgbStringValueLabel = new QLabel("", colorAtCursorFrameArea);
+ colorAtCursorRgbStringValueLabel->setFixedWidth(
+ colorAtCursorRgbStringValueLabel->fontMetrics().width( QString("8888888") ));
+ colorAtCursorRgbStringLayout->addWidget(colorAtCursorRgbStringValueLabel);
+ colorAtCursorRgbStringLayout->addStretch();
+ colorAtCursorLayout->addLayout(colorAtCursorRgbStringLayout);
+ layout->addWidget(colorAtCursorFrame, 10);
+ layout->addSpacing(8);
+ paletteLayout->addSpacing(4);
+ paletteLayout->addLayout(layout);
+ paletteLayout->addSpacing(4);
+ inColorNameChanging = false;
+ doNotUpdateColorLabels = false;
+}
+
+KColorEditView::~KColorEditView() {
+}
+
+void KColorEditView::setColorAtCursorComponentValueLabelSizes(QLabel* const label) {
+ label->setMinimumWidth(label->fontMetrics().width( QString("888") ));
+ label->setMaximumWidth(label->fontMetrics().width( QString("88888") ));
+}
+
+KColorEditDoc *KColorEditView::document() const {
+ KColorEditApp *theApp=(KColorEditApp *) parentWidget();
+
+ return theApp->document();
+}
+
+void KColorEditView::print(QPrinter *pPrinter) {
+ QPainter printpainter;
+ printpainter.begin(pPrinter);
+
+ // TODO: add your printing code here
+
+ printpainter.end();
+}
+
+void KColorEditView::chooseColor(Color* const color) {
+ colorSelector->slotSetColor(color);
+}
+
+void KColorEditView::slotCursorPosChanged(int position) {
+ Palette* palette = document()->paletteHistory()->editableStream();
+ if(position < palette->length()) {
+ Color* color = palette->color(position);
+ QString string;
+ inColorNameChanging = true;
+ colorName->setText(color->name());
+ colorName->setEnabled(true);
+ inColorNameChanging = false;
+ int rComponent = color->component(Color::RED_INDEX);
+ int gComponent = color->component(Color::GREEN_INDEX);
+ int bComponent = color->component(Color::BLUE_INDEX);
+ colorAtCursorRValueLabel->setText(string.setNum( rComponent ));
+ colorAtCursorGValueLabel->setText(string.setNum( gComponent ));
+ colorAtCursorBValueLabel->setText(string.setNum( bComponent ));
+ QColor hsvColor(rComponent, gComponent, bComponent);
+ int hComponent;
+ int sComponent;
+ int vComponent;
+ hsvColor.hsv(&hComponent, &sComponent, &vComponent);
+ colorAtCursorHValueLabel->setText(string.setNum( hComponent ));
+ colorAtCursorSValueLabel->setText(string.setNum( sComponent ));
+ colorAtCursorVValueLabel->setText(string.setNum( vComponent ));
+ colorAtCursorRgbStringValueLabel->setText(string.sprintf( "%02x%02x%02x",
+ rComponent, gComponent, bComponent ));
+ } else {
+ colorName->setText("");
+ colorName->setEnabled(false);
+ colorAtCursorHValueLabel->setText("");
+ colorAtCursorSValueLabel->setText("");
+ colorAtCursorVValueLabel->setText("");
+ colorAtCursorRValueLabel->setText("");
+ colorAtCursorGValueLabel->setText("");
+ colorAtCursorBValueLabel->setText("");
+ colorAtCursorRgbStringValueLabel->setText("");
+ }
+}
+
+void KColorEditView::slotViewColorNames(bool viewColorNames) {
+ paletteView->slotViewColorNames(viewColorNames);
+}
+
+void KColorEditView::updateColorValueLabels() {
+ if(!doNotUpdateColorLabels)
+ slotCursorPosChanged(document()->paletteCursorPos());
+}
+
+void KColorEditView::redraw(bool newDocument) {
+ if(newDocument)
+ paletteView->setScrollBarValue(0);
+ paletteView->redraw();
+ updateColorValueLabels();
+}
+
+void KColorEditView::slotAddColor() {
+ Color color = colorSelector->color();
+ Palette* palette = document()->paletteHistory()->editableStream();
+ color.setName("");
+ int index;
+ if(addColorAtCursor)
+ index = document()->paletteCursorPos();
+ else
+ index = palette->length();
+ switch(addColorMode)
+ {
+ case INSERT_COLOR:
+ document()->insert(index, color);
+ break;
+
+ case REPLACE_COLOR:
+ if(index < palette->length())
+ document()->replace(index, color);
+ else
+ document()->insert(index, color);
+ break;
+
+ }
+}
+
+void KColorEditView::slotAddColorAtCursor(bool atCursor) {
+ addColorAtCursor = atCursor;
+ overwriteCheckBox->setEnabled(addColorAtCursor);
+}
+
+void KColorEditView::slotAddColorOverwrite(bool overwrite) {
+ if(overwrite)
+ addColorMode = REPLACE_COLOR;
+ else
+ addColorMode = INSERT_COLOR;
+}
+
+void KColorEditView::slotSetColorName(const QString& name) {
+ if(!inColorNameChanging) {
+ /*
+ Palette* palette = getDocument()->getPaletteHistory()->getEditableStream();
+ int cursorPos = getDocument()->getPaletteCursorPos();
+ if(cursorPos < palette->length()) {
+ palette->getColor(cursorPos)->setName(name);
+ getDocument()->setModified(true);
+ getDocument()->slotRedrawAllViews(this);
+ }
+ */
+ Palette* palette = document()->paletteHistory()->editableStream();
+ int cursorPos = document()->paletteCursorPos();
+ if(cursorPos < palette->length()) {
+ Color newColor(
+ palette->color(cursorPos)->component(Color::RED_INDEX),
+ palette->color(cursorPos)->component(Color::GREEN_INDEX),
+ palette->color(cursorPos)->component(Color::BLUE_INDEX),
+ name);
+ doNotUpdateColorLabels = true;
+ document()->replace(cursorPos, newColor);
+ doNotUpdateColorLabels = false;
+ }
+ }
+}
+#include "kcoloreditview.moc"
diff --git a/kcoloredit/kcoloreditview.h b/kcoloredit/kcoloreditview.h
new file mode 100644
index 00000000..ec0ca17f
--- /dev/null
+++ b/kcoloredit/kcoloreditview.h
@@ -0,0 +1,128 @@
+/***************************************************************************
+ kcoloreditview.h - description
+ -------------------
+ begin : Sat Jul 8 09:57:28 CEST 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KCOLOREDITVIEW_H
+#define KCOLOREDITVIEW_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// include files for Qt
+#include <qsplitter.h>
+#include <qcheckbox.h>
+#include <qlabel.h>
+
+// application specific includes
+#include "colorselector.h"
+#include "paletteview.h"
+
+class KColorEditDoc;
+
+/** The KColorEditView class provides the view widget for the KColorEditApp instance.
+ * The View instance inherits QWidget as a base class and represents the view object of a KMainWindow. As KColorEditView is part of the
+ * docuement-view model, it needs a reference to the document object connected with it by the KColorEditApp class to manipulate and display
+ * the document structure provided by the KColorEditDoc class.
+ *
+ * @author Source Framework Automatically Generated by KDevelop, (c) The KDevelop Team.
+ * @version KDevelop version 0.4 code generation
+ */
+class KColorEditView : public QSplitter {
+ Q_OBJECT
+
+ public:
+ /** Constructor for the main view */
+ KColorEditView(QWidget *parent = 0, const char *name = 0);
+ /** Destructor for the main view */
+ ~KColorEditView();
+
+ /** returns a pointer to the document connected to the view instance. Mind that this method requires a KColorEditApp instance as a parent
+ * widget to get to the window document pointer by calling the KColorEditApp::getDocument() method.
+ *
+ * @see KColorEditApp#getDocument
+ */
+ KColorEditDoc *document() const;
+
+ /** Contains the implementation for printing functionality */
+ void print(QPrinter *pPrinter);
+ /** Chooses a color to the color selector */
+ void chooseColor(Color* const color);
+ /** Updates the view after the document has been changed */
+ void redraw(bool newDocument);
+
+ public slots:
+ /** Notifies that the cursor position changed */
+ void slotCursorPosChanged(int position);
+ /** Whether to view color names */
+ void slotViewColorNames(bool viewColorNames);
+
+ protected:
+ ColorSelector* colorSelector;
+ PaletteView* paletteView;
+
+ protected slots:
+ /** Adds a color from color selector at cursor position. It inserts or replaces a color,
+ * depending on addColorMode
+ */
+ void slotAddColor();
+ /** Sets if add a color at cursor */
+ void slotAddColorAtCursor(bool atCursor);
+ /** Sets whether insert or replace a color */
+ void slotAddColorOverwrite(bool overwrite);
+ /** Sets a color name */
+ void slotSetColorName(const QString& name);
+
+ protected:
+ /** Add color mode constants */
+ enum { INSERT_COLOR = 0,
+ REPLACE_COLOR = 1 };
+
+ /** Color mode widget */
+ QCheckBox* overwriteCheckBox;
+ /** Color name widget */
+ QLineEdit* colorName;
+ /** H component value label of the color at cursor */
+ QLabel* colorAtCursorHValueLabel;
+ /** S component value label of the color at cursor */
+ QLabel* colorAtCursorSValueLabel;
+ /** V component value label of the color at cursor */
+ QLabel* colorAtCursorVValueLabel;
+ /** R component value label of the color at cursor */
+ QLabel* colorAtCursorRValueLabel;
+ /** G component value label of the color at cursor */
+ QLabel* colorAtCursorGValueLabel;
+ /** B component value label of the color at cursor */
+ QLabel* colorAtCursorBValueLabel;
+ /** RGB Hex string value label of the color at cursor */
+ QLabel* colorAtCursorRgbStringValueLabel;
+ /** If add a color at cursor */
+ bool addColorAtCursor;
+ /** Add color mode */
+ int addColorMode;
+ /** If in color name changing */
+ bool inColorNameChanging;
+ /** Whether not to update color labels */
+ bool doNotUpdateColorLabels;
+
+ protected:
+ /** Sets component value label of the color at cursor sizes */
+ void setColorAtCursorComponentValueLabelSizes(QLabel* const label);
+ /** Updates color value labels */
+ void updateColorValueLabels();
+};
+
+#endif // KCOLOREDITVIEW_H
diff --git a/kcoloredit/kxycolorselector.cpp b/kcoloredit/kxycolorselector.cpp
new file mode 100644
index 00000000..e12f7987
--- /dev/null
+++ b/kcoloredit/kxycolorselector.cpp
@@ -0,0 +1,186 @@
+/***************************************************************************
+ kxycolorselector.cpp - description
+ -------------------
+ begin : Fri Jul 7 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qimage.h>
+#include <kimageeffect.h>
+#include <kpalette.h>
+
+#include "kxycolorselector.h"
+
+KXYColorSelector::KXYColorSelector(QWidget *parent, const char *name) : KXYSelector(parent,name) {
+ setBackgroundMode(NoBackground);
+ setRange(0, 0, COMPONENT_SELECTION_RESOLUTION - 1, COMPONENT_SELECTION_RESOLUTION - 1);
+ setType(TYPE_NONE);
+ setGlobalComponent(0);
+ setMinimumSize(RGB_MAX_COMPONENT_VALUE/2 + 4, RGB_MAX_COMPONENT_VALUE/2 + 4);
+ setMaximumSize(512, 512);
+ updateContents();
+}
+KXYColorSelector::~KXYColorSelector() {
+
+}
+
+void KXYColorSelector::setType(const int type) {
+ this->type = type;
+}
+
+void KXYColorSelector::updateContents() {
+ drawPalette(&pixmap);
+ repaint();
+}
+
+void KXYColorSelector::resizeEvent(QResizeEvent*) {
+ setValues(xValue(), yValue());
+ updateContents();
+}
+
+void KXYColorSelector::drawContents(QPainter* painter) {
+ painter->drawPixmap(contentsRect().x(), contentsRect().y(), pixmap);
+}
+
+void KXYColorSelector::drawCursor(QPainter* painter, int x, int y) {
+ QColor color;
+ int colorX = x - contentsRect().x();
+ int colorY = y - contentsRect().y();
+ if(colorX < 0)
+ colorX = 0;
+ if(colorY < 0)
+ colorY = 0;
+ if(colorX > contentsRect().width() - 1)
+ colorX = contentsRect().width() - 1;
+ if(colorY > contentsRect().height() - 1)
+ colorY = contentsRect().height() - 1;
+ setColor(&color, colorX, colorY);
+ QColor cursorColor;
+ if(( 2*color.red() + 4*color.green() + 1*color.blue() )*1.0/
+ ( 2*255 + 4*255 + 1*255 ) > 0.65)
+ cursorColor = Qt::black;
+ else
+ cursorColor = Qt::white;
+ painter->setPen(QPen( cursorColor ));
+ const int lineBegin = 2;
+ const int lineEnd = 6;
+ painter->drawLine(x + lineBegin, y - lineBegin, x + lineEnd, y - lineEnd);
+ painter->drawLine(x + lineBegin, y + lineBegin, x + lineEnd, y + lineEnd);
+ painter->drawLine(x - lineBegin, y + lineBegin, x - lineEnd, y + lineEnd);
+ painter->drawLine(x - lineBegin, y - lineBegin, x - lineEnd, y - lineEnd);
+}
+
+void KXYColorSelector::setGlobalComponent(const int component) {
+ m_globalComponent = component;
+}
+
+int KXYColorSelector::globalComponent() const{
+ return m_globalComponent;
+}
+
+void KXYColorSelector::setColor(QColor* const color, const int x, const int y) {
+ int xSize = contentsRect().width();
+ int ySize = contentsRect().height();
+ switch(type) {
+ case TYPE_HS:
+ color->setHsv(360*x/xSize, 256*( ySize - 1 - y )/ySize,
+ globalComponent());
+ break;
+
+ case TYPE_VS:
+ color->setHsv(globalComponent(), 256*( ySize - 1 - y )/ySize,
+ 256*x/xSize);
+ break;
+
+ case TYPE_HV:
+ color->setHsv(360*x/xSize, globalComponent(),
+ 256*( ySize - 1 - y )/ySize);
+ break;
+
+ case TYPE_RG:
+ color->setRgb(x/xSize, 256*( ySize - 1 - y )/ySize,
+ globalComponent());
+ break;
+
+ case TYPE_GB:
+ color->setRgb(globalComponent(), 256*x/xSize,
+ 256*( ySize - 1 - y )/ySize);
+ break;
+
+ case TYPE_BR:
+ color->setRgb(256*( ySize - 1 - y )/ySize, globalComponent(),
+ 256*x/xSize);
+ break;
+
+ case TYPE_NONE:
+ color->setRgb(192, 192, 192);
+ break;
+
+ }
+}
+
+QColor* KXYColorSelector::standardColorsPalette() {
+ QColor* palette = new QColor[STANDARD_PALETTE_SIZE];
+ int i = 0;
+ palette[i++] = Qt::red;
+ palette[i++] = Qt::green;
+ palette[i++] = Qt::blue;
+ palette[i++] = Qt::cyan;
+ palette[i++] = Qt::magenta;
+ palette[i++] = Qt::yellow;
+ palette[i++] = Qt::darkRed;
+ palette[i++] = Qt::darkGreen;
+ palette[i++] = Qt::darkBlue;
+ palette[i++] = Qt::darkCyan;
+ palette[i++] = Qt::darkMagenta;
+ palette[i++] = Qt::darkYellow;
+ palette[i++] = Qt::white;
+ palette[i++] = Qt::lightGray;
+ palette[i++] = Qt::gray;
+ palette[i++] = Qt::darkGray;
+ palette[i++] = Qt::black;
+ return palette;
+}
+
+void KXYColorSelector::drawPalette(QPixmap* pixmap) {
+ int xSize = contentsRect().width();
+ int ySize = contentsRect().height();
+ QImage image(xSize, ySize, 32);
+ QColor color;
+ int x;
+ int y;
+
+ if(type != TYPE_NONE) {
+ for (y = 0; y < ySize; ++y)
+ {
+ unsigned int* p = (unsigned int*)image.scanLine(y);
+ for(x = 0; x < xSize; ++x)
+ {
+ setColor(&color, x, y);
+ *p = color.rgb();
+ ++p;
+ }
+ }
+ if (QColor::numBitPlanes() <= 8)
+ {
+ QColor* standardPalette = standardColorsPalette();
+ KImageEffect::dither(image, standardPalette, STANDARD_PALETTE_SIZE);
+ delete[] standardPalette;
+ }
+ }
+ pixmap->convertFromImage(image);
+}
+
+#include "kxycolorselector.moc"
diff --git a/kcoloredit/kxycolorselector.h b/kcoloredit/kxycolorselector.h
new file mode 100644
index 00000000..3213c59c
--- /dev/null
+++ b/kcoloredit/kxycolorselector.h
@@ -0,0 +1,97 @@
+/***************************************************************************
+ kxycolorselector.h - description
+ -------------------
+ begin : Fri Jul 7 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KXYCOLORSELECTOR_H
+#define KXYCOLORSELECTOR_H
+
+#include <qwidget.h>
+#include <kselect.h>
+
+#include "main.h"
+
+/** A widget for selecting two of color components
+ * @author Artur Rataj
+ */
+class KXYColorSelector : public KXYSelector {
+ Q_OBJECT
+
+public:
+ /** The types of the selector. They specify a color component subset */
+ enum { TYPE_NONE = 0,
+ TYPE_HS = 1,
+ TYPE_VS = 2,
+ TYPE_HV = 3,
+ TYPE_RG = 4,
+ TYPE_GB = 5,
+ TYPE_BR = 6,
+ TYPE_ = 7,
+ /** Component selection resolution */
+ COMPONENT_SELECTION_RESOLUTION = 10000 };
+
+public:
+ /** Constructs a two-dimensional color component selector widget,
+ * with a type TYPE_NONE and ranges 0 .. MAX_COLOR_COMPONENT_VALUE
+ */
+ KXYColorSelector(QWidget *parent=0, const char *name=0);
+ ~KXYColorSelector();
+ /** Set the type of the selector */
+ void setType(const int type);
+ /** Update the pixmap */
+ void updateContents();
+ /** Set the global component */
+ void setGlobalComponent(const int component);
+ /** @return The global component */
+ int globalComponent() const;
+
+protected:
+ /** The number of colors that are used to dither the pixmap
+ * if number of color planes <= 8. The palette returned by
+ * getStandardColorsPalette() is of the size.
+ */
+ enum { STANDARD_PALETTE_SIZE = 17 };
+
+ /** A type of the selector */
+ int type;
+ /** The global component value */
+ int m_globalComponent;
+
+ /** Draws the contents of the widget on a pixmap,
+ * which is used for buffering.
+ */
+ virtual void drawPalette( QPixmap *pixmap );
+ /** @reimplemented */
+ virtual void resizeEvent( QResizeEvent * );
+ /** Reimplemented from KXYSelector. This drawing is
+ * buffered in a pixmap here. As real drawing
+ * routine, drawPalette() is used.
+ */
+ virtual void drawContents( QPainter *painter );
+ /** Draws the cursor */
+ virtual void drawCursor(QPainter* painter, int x, int y);
+ /** set a color at a given coordinate */
+ virtual void setColor(QColor* const color, const int x, const int y);
+ /** @return STANDARD_PALETTE_SIZE colors used to dither the
+ * pixmap if number of color planes <= 8
+ */
+ QColor* standardColorsPalette();
+
+private:
+ /* The buffering pixmap */
+ QPixmap pixmap;
+};
+
+#endif
diff --git a/kcoloredit/kzcolorselector.cpp b/kcoloredit/kzcolorselector.cpp
new file mode 100644
index 00000000..36953180
--- /dev/null
+++ b/kcoloredit/kzcolorselector.cpp
@@ -0,0 +1,170 @@
+/***************************************************************************
+ kzcolorselector.cpp - description
+ -------------------
+ begin : Fri Jul 14 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include <qpainter.h>
+#include <qimage.h>
+#include <kimageeffect.h>
+#include <kpalette.h>
+
+#include "main.h"
+#include "kzcolorselector.h"
+
+KZColorSelector::KZColorSelector(Orientation o, QWidget *parent, const char *name) :
+ KSelector(o, parent, name) {
+ baseColorH = -1;
+ baseColorS = 0;
+ baseColorV = 0;
+ pixmap.setOptimization( QPixmap::BestOptim );
+}
+KZColorSelector::~KZColorSelector() {
+}
+
+void KZColorSelector::setType(const int type) {
+ this->type = type;
+ switch(this->type) {
+ case TYPE_H:
+ setRange(0, HSV_MAX_H_VALUE);
+ break;
+
+ case TYPE_S:
+ setRange(0, HSV_MAX_S_VALUE);
+ break;
+
+ case TYPE_V:
+ setRange(0, HSV_MAX_V_VALUE);
+ break;
+
+ }
+}
+
+void KZColorSelector::updateContents() {
+ drawPalette(&pixmap);
+ repaint(false);
+}
+
+void KZColorSelector::resizeEvent(QResizeEvent*) {
+ updateContents();
+}
+
+void KZColorSelector::drawContents(QPainter* painter) {
+ painter->drawPixmap(contentsRect().x(), contentsRect().y(), pixmap);
+}
+
+void KZColorSelector::setBaseColor(const QColor& color) {
+ color.hsv(&baseColorH, &baseColorS, &baseColorV);
+}
+
+void KZColorSelector::setBaseColorHsv(const int colorH,
+ const int colorS, const int colorV) {
+ baseColorH = colorH;
+ baseColorS = colorS;
+ baseColorV = colorV;
+}
+
+void KZColorSelector::updatePointerPos() {
+ int pos;
+ switch(type) {
+ case TYPE_H:
+ pos = baseColorH;
+ if(pos < 0)
+ pos = 0;
+ break;
+
+ case TYPE_S:
+ pos = baseColorS;
+ break;
+
+ case TYPE_V:
+ pos = baseColorV;
+ break;
+
+ default:
+ pos = 0;
+ break;
+
+ }
+ setValue(pos);
+}
+
+void KZColorSelector::setColor(QColor* const color, const int y) {
+ int ySize = contentsRect().height();
+ switch(type) {
+ case TYPE_H:
+ color->setHsv(( ySize - 1 - y )*360/ySize, baseColorS, baseColorV);
+ break;
+
+ case TYPE_S:
+ color->setHsv(baseColorH, ( ySize - 1 - y )*256/ySize, baseColorV);
+ break;
+
+ case TYPE_V:
+ color->setHsv(baseColorH, baseColorS, ( ySize - 1 - y )*256/ySize);
+ break;
+
+ }
+}
+
+QColor* KZColorSelector::getStandardColorsPalette() {
+ QColor* palette = new QColor[( int )STANDARD_PALETTE_SIZE];
+ int i = 0;
+ palette[i++] = Qt::red;
+ palette[i++] = Qt::green;
+ palette[i++] = Qt::blue;
+ palette[i++] = Qt::cyan;
+ palette[i++] = Qt::magenta;
+ palette[i++] = Qt::yellow;
+ palette[i++] = Qt::darkRed;
+ palette[i++] = Qt::darkGreen;
+ palette[i++] = Qt::darkBlue;
+ palette[i++] = Qt::darkCyan;
+ palette[i++] = Qt::darkMagenta;
+ palette[i++] = Qt::darkYellow;
+ palette[i++] = Qt::white;
+ palette[i++] = Qt::lightGray;
+ palette[i++] = Qt::gray;
+ palette[i++] = Qt::darkGray;
+ palette[i++] = Qt::black;
+ return palette;
+}
+
+void KZColorSelector::drawPalette(QPixmap* pixmap) {
+ int xSize = contentsRect().width();
+ int ySize = contentsRect().height();
+ QImage image(xSize, ySize, 32);
+ QColor color;
+ int x;
+ int y;
+
+ for (y = 0; y < ySize; ++y)
+ {
+ unsigned int* p = (unsigned int*)image.scanLine(y);
+ for(x = 0; x < xSize; ++x)
+ {
+ setColor(&color, y);
+ *p = color.rgb();
+ ++p;
+ }
+ }
+ if (QColor::numBitPlanes() <= 8)
+ {
+ QColor* standardPalette = getStandardColorsPalette();
+ KImageEffect::dither(image, standardPalette, STANDARD_PALETTE_SIZE);
+ delete[] standardPalette;
+ }
+ pixmap->convertFromImage(image);
+}
+#include "kzcolorselector.moc"
diff --git a/kcoloredit/kzcolorselector.h b/kcoloredit/kzcolorselector.h
new file mode 100644
index 00000000..cafdb254
--- /dev/null
+++ b/kcoloredit/kzcolorselector.h
@@ -0,0 +1,89 @@
+/***************************************************************************
+ kzcolorselector.h - description
+ -------------------
+ begin : Fri Jul 14 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KZCOLORSELECTOR_H
+#define KZCOLORSELECTOR_H
+
+#include "qcolor.h"
+#include "qpixmap.h"
+#include "kselect.h"
+
+#include "color.h"
+
+/** A widget for selecting a color component
+ * @author Artur Rataj
+ */
+class KZColorSelector : public KSelector {
+ Q_OBJECT
+
+public:
+ /** Selector type constants */
+ enum { TYPE_H = 0,
+ TYPE_S = 1,
+ TYPE_V = 2 };
+
+ /** Constructs the widget */
+ KZColorSelector(Orientation o, QWidget *parent=0, const char *name=0);
+ ~KZColorSelector();
+ /** Sets the selector type */
+ void setType(const int type);
+ /** Update the pixmap */
+ void updateContents();
+ /** Set the global components */
+ void setBaseColor(const QColor& color);
+ /** Set the global components using HSV components */
+ void setBaseColorHsv(const int colorH, const int colorS, const int colorV);
+ /** Updates a pointer position due to the base color */
+ void updatePointerPos();
+
+protected:
+ /** The number of colors that are used to dither the pixmap
+ * if number of color planes <= 8. The palette returned by
+ * getStandardColorsPalette() is of the size.
+ */
+ enum { STANDARD_PALETTE_SIZE = 17 };
+
+ /** A type of the selector */
+ int type;
+ /** A base color H component */
+ int baseColorH;
+ /** A base color S component */
+ int baseColorS;
+ /** A base color V component */
+ int baseColorV;
+
+ /** Draws the contents of the widget on a pixmap,
+ * which is used for buffering.
+ */
+ virtual void drawPalette( QPixmap *pixmap );
+ /** @reimplemented */
+ virtual void resizeEvent( QResizeEvent * );
+ /** Draws a color gradient in the selector */
+ virtual void drawContents( QPainter *painter );
+ /** Sets a color at a given coordinate */
+ virtual void setColor(QColor* const color, const int y);
+ /** @return STANDARD_PALETTE_SIZE colors used to dither the
+ * pixmap if number of color planes <= 8
+ */
+ QColor* getStandardColorsPalette();
+
+private:
+ /* The buffering pixmap */
+ QPixmap pixmap;
+};
+
+#endif
diff --git a/kcoloredit/loadpalettedlg.cpp b/kcoloredit/loadpalettedlg.cpp
new file mode 100644
index 00000000..b426a874
--- /dev/null
+++ b/kcoloredit/loadpalettedlg.cpp
@@ -0,0 +1,111 @@
+/***************************************************************************
+ loadpalettedlg.cpp - description
+ -------------------
+ begin : Sat Jul 8 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include <string.h>
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qpushbutton.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <kpalette.h>
+#include <kfiledialog.h>
+
+#include "main.h"
+#include "palette.h"
+#include "loadpalettedlg.h"
+
+LoadPaletteDlg::LoadPaletteDlg(QWidget *parent, const char *name)
+ : KDialogBase(parent, name, true, i18n( "Load Palette" ),
+ Ok|Cancel, Ok, true) {
+ fileName = "";
+ QWidget *mainWidget = new QWidget( this );
+ setMainWidget( mainWidget );
+ QVBoxLayout* topLayout = new QVBoxLayout(mainWidget, 0, spacingHint());
+ QLabel* label = new QLabel(i18n( "Select a palette:" ), mainWidget);
+ topLayout->addWidget(label);
+ paletteBox = new QComboBox(false, mainWidget);
+ browseFileNameInserted = false;
+ QStringList palettesList = Palette::kdePalettes();
+ for(QStringList::Iterator palette = palettesList.begin();
+ palette != palettesList.end(); ++palette) {
+ bool prepend = (*palette).contains( "colors/Custom_Colors" );
+ QString fileName = locate("config", (*palette));
+ if(prepend) {
+ palettesFileNames.prepend(fileName);
+ setFileName(&fileName);
+ } else {
+ palettesFileNames.append(fileName);
+ if(palette == palettesList.begin())
+ setFileName(&fileName);
+ }
+ QString paletteName = (*palette).mid(palettesDir.length() + 1);
+ if(paletteName == "Custom_Colors")
+ paletteName = i18n("Custom Colors");
+ else if(paletteName == "Recent_Colors")
+ paletteName = i18n("Recent Colors");
+ if(prepend)
+ paletteBox->insertItem(paletteName, 0);
+ else
+ paletteBox->insertItem(paletteName);
+ }
+ connect(paletteBox, SIGNAL( activated(int) ), SLOT( setFileName(int) ));
+ topLayout->addWidget(paletteBox);
+ QHBoxLayout* browseLayout = new QHBoxLayout( mainWidget );
+ QPushButton* browseButton = new QPushButton(i18n( "Browse..." ),
+ mainWidget);
+ connect(browseButton, SIGNAL( clicked() ), SLOT( browseFileNames() ));
+ browseLayout->addWidget(browseButton);
+ browseLayout->addStretch(10);
+ topLayout->addLayout(browseLayout);
+ topLayout->addStretch(10);
+ resize(300, 155);
+}
+LoadPaletteDlg::~LoadPaletteDlg() {
+}
+
+void LoadPaletteDlg::setFileName(QString* fileName) {
+ this->fileName = *fileName;
+}
+
+void LoadPaletteDlg::setFileName(int index) {
+ setFileName(&palettesFileNames[index]);
+}
+
+void LoadPaletteDlg::browseFileNames() {
+ QString fileToOpen = KFileDialog::getOpenFileName(lastOpenPaletteFileDir,
+ i18n("*|All Files"), this, i18n("Open File"));
+ if(!fileToOpen.isEmpty()) {
+ fileName = fileToOpen;
+ if(browseFileNameInserted) {
+ paletteBox->removeItem(0);
+ palettesFileNames.remove(palettesFileNames.begin());
+ }
+ paletteBox->insertItem(fileName, 0);
+ paletteBox->setCurrentItem(0);
+ palettesFileNames.prepend(fileName);
+ browseFileNameInserted = true;
+ lastOpenPaletteFileDir = fileName;
+ }
+}
+
+QString LoadPaletteDlg::getFileName() {
+ return fileName;
+}
+#include "loadpalettedlg.moc"
diff --git a/kcoloredit/loadpalettedlg.h b/kcoloredit/loadpalettedlg.h
new file mode 100644
index 00000000..3168ed68
--- /dev/null
+++ b/kcoloredit/loadpalettedlg.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+ loadpalettedlg.h - description
+ -------------------
+ begin : Sat Jul 8 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef LOADPALETTEDLG_H
+#define LOADPALETTEDLG_H
+
+#include <qcombobox.h>
+#include <kdialog.h>
+
+/**A dialog showing a list of installed palettes, with a possibility
+ *of choosing a custom file
+ *@author Artur Rataj
+ */
+class LoadPaletteDlg : public KDialogBase {
+ Q_OBJECT
+
+public:
+ /** constructs the dialog
+ */
+ LoadPaletteDlg(QWidget *parent = 0, const char *name = 0);
+ ~LoadPaletteDlg();
+ /** @return the fetched file name
+ */
+ QString getFileName();
+
+protected slots:
+ /** sets fileName
+ */
+ void setFileName(QString* fileName);
+ /** sets fileName to that at position index in palettesFileNames
+ */
+ void setFileName(int index);
+ /** browses file names and if a file name fetched sets fileName
+ */
+ void browseFileNames();
+
+private:
+ /** A widget holding palettes names
+ */
+ QComboBox* paletteBox;
+ /** A list of KDE palettes file names
+ */
+ QStringList palettesFileNames;
+ /** A fetched palette file name
+ */
+ QString fileName;
+ /** whether a browse file name hab already been inserted into
+ * palettesFilenames
+ */
+ bool browseFileNameInserted;
+};
+
+#endif
diff --git a/kcoloredit/main.cpp b/kcoloredit/main.cpp
new file mode 100644
index 00000000..fcc2ac66
--- /dev/null
+++ b/kcoloredit/main.cpp
@@ -0,0 +1,74 @@
+/***************************************************************************
+ main.cpp - description
+ -------------------
+ begin : Sat Jul 8 09:57:28 CEST 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "kcoloredit.h"
+
+static const char description[] =
+ I18N_NOOP("KColorEdit");
+// INSERT A DESCRIPTION FOR YOUR APPLICATION HERE
+
+
+static KCmdLineOptions options[] =
+{
+ { "+[File]", I18N_NOOP("File to open"), 0 },
+ KCmdLineLastOption
+ // INSERT YOUR COMMANDLINE OPTIONS HERE
+};
+
+int main(int argc, char *argv[])
+{
+
+ KAboutData aboutData( "kcoloredit", I18N_NOOP("KColorEdit"),
+ VERSION, description, KAboutData::License_GPL,
+ "(c) 2000, Artur Rataj");
+ aboutData.addAuthor("Artur Rataj",0, "art@zeus.polsl.gliwice.pl");
+ aboutData.addCredit( "Nadeem Hasan", I18N_NOOP( "Rewrote UI code "
+ "to be KDE standards compliant" ), "nhasan@kde.org" );
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
+
+ KApplication app;
+
+ if (app.isRestored())
+ {
+ RESTORE(KColorEditApp);
+ }
+ else
+ {
+ KColorEditApp *kcoloredit = new KColorEditApp();
+ kcoloredit->show();
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ if (args->count())
+ {
+ kcoloredit->openDocumentFile(args->arg(0));
+ }
+ else
+ {
+ kcoloredit->openDocumentFile();
+ }
+ args->clear();
+ }
+
+ return app.exec();
+}
diff --git a/kcoloredit/main.h b/kcoloredit/main.h
new file mode 100644
index 00000000..5e0b086a
--- /dev/null
+++ b/kcoloredit/main.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+ main.h - description
+ -------------------
+ begin : Sat Jul 8 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef __MAIN_H__
+#define __MAIN_H__
+
+#include <qstring.h>
+#include <qdir.h>
+
+/** The maximum red, green or blue component value in RGB scheme
+ */
+const int RGB_MAX_COMPONENT_VALUE = 255;
+
+/** The maximum hue in HSV scheme
+ */
+const int HSV_MAX_H_VALUE = 359;
+
+/** The maximum saturation in HSV scheme
+ */
+const int HSV_MAX_S_VALUE = 255;
+
+/** The maximum value in HSV scheme
+ */
+const int HSV_MAX_V_VALUE = 255;
+
+/** name of KDE config directories containing palette files
+ */
+static const QString palettesDir("colors");
+
+/** last open file dialog path
+ */
+static QString lastOpenPaletteFileDir = QDir::homeDirPath();
+
+/** last save file as dialog path
+ */
+static QString lastSavePaletteAsFileDir = QDir::homeDirPath();
+
+#endif /* !defined( __MAIN_H__ ) */
diff --git a/kcoloredit/palette.cpp b/kcoloredit/palette.cpp
new file mode 100644
index 00000000..1e11aa27
--- /dev/null
+++ b/kcoloredit/palette.cpp
@@ -0,0 +1,226 @@
+/***************************************************************************
+ palette.cpp - description
+ -------------------
+ begin : Sat Jul 8 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qtextstream.h>
+#include <qregexp.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <klocale.h>
+
+#include "main.h"
+#include "color.h"
+#include "palette.h"
+
+Palette::Palette() {
+ init();
+}
+Palette::Palette(const Palette& palette) {
+ init();
+ for(int colorIndex = 0; colorIndex < palette.length(); ++colorIndex) {
+ Color* color = new Color(*( (Palette&)palette ).color( colorIndex ));
+ append(color);
+ }
+ setName(palette.name());
+}
+Palette::~Palette() {
+}
+
+void Palette::init() {
+ colors.setAutoDelete(true);
+}
+
+QStringList Palette::kdePalettes() {
+ QStringList paletteList;
+ KGlobal::dirs()->findAllResources("config", palettesDir + "/*", false, true, paletteList);
+ return paletteList;
+}
+
+void Palette::setName(const QString& name) {
+ m_name = name;
+}
+
+const QString& Palette::name() const {
+ return m_name;
+}
+
+void Palette::insert(const int index, Color* const color) {
+ colors.insert(index, color);
+}
+
+void Palette::append(Color* const color) {
+ colors.append(color);
+}
+
+void Palette::remove(const int index) {
+ colors.remove(index);
+}
+
+int Palette::length() const {
+ return (int)colors.count();
+}
+
+Color* Palette::color(const int index) {
+ return colors.at(index);
+}
+
+Palette Palette::copy(const int index, const int length) {
+ Palette newPalette;
+ for(int colorIndex = index; colorIndex < index + length; ++colorIndex)
+ newPalette.append(new Color( *color(colorIndex) ));
+ newPalette.setName(name());
+ return newPalette;
+}
+
+Palette Palette::cut(const int index, const int length) {
+ Palette newPalette;
+ for(int colorNum = 0; colorNum < length; ++colorNum) {
+ newPalette.append(new Color( *color(index) ));
+ remove(index);
+ }
+ newPalette.setName(name());
+ return newPalette;
+}
+
+void Palette::paste(const int index, Palette& palette) {
+ for(int colorIndex = 0; colorIndex < palette.length(); ++colorIndex)
+ insert(index + colorIndex, new Color( *palette.color(colorIndex) ));
+}
+
+bool Palette::load(QTextStream& stream, bool loadName /* = true */) {
+ bool result = true;
+ setName("KDE palette");
+ int lineNum = 0;
+ while (!stream.atEnd()) {
+ QString string = stream.readLine().append(' ');
+ if(string.find( QRegExp("[^\\s]") ) == -1 ||
+ string.stripWhiteSpace().at( 0 ) == '#' ||
+ ( loadName && lineNum == 0 )) {
+ if(loadName && lineNum == 0)
+ setName(string.stripWhiteSpace());
+ } else {
+ Color* newColor = new Color();
+ int position = string.find(QRegExp( "[^\\s]" ));
+ for(int componentIndex = 0; componentIndex < Color::COMPONENTS_NUM;
+ ++componentIndex) {
+ if(position == -1) {
+ m_errorString = i18n("Invalid format");
+ result = false;
+ break;
+ }
+ int endPosition = string.find(QRegExp( "\\s" ), position);
+ if(endPosition == -1) {
+ m_errorString = i18n("Invalid format");
+ result = false;
+ break;
+ }
+ QString componentString = string.mid(position, endPosition - position);
+ int componentValue = componentString.toInt(&result);
+ if(!result ||
+ componentValue < 0 ||
+ componentValue > RGB_MAX_COMPONENT_VALUE) {
+ m_errorString = i18n("Invalid format");
+ result = false;
+ break;
+ }
+ newColor->setComponent(componentIndex, componentValue);
+ position = string.find(QRegExp( "[^\\s]" ), endPosition);
+ }
+ if(!result) {
+ delete newColor;
+ break;
+ }
+ if(position != -1)
+ newColor->setName(string.mid( position ).stripWhiteSpace());
+ colors.append(newColor);
+ }
+ ++lineNum;
+ }
+ if(!result)
+ deleteContents();
+ return result;
+}
+
+bool Palette::load(const QString& fileName) {
+ bool result = true;
+ QFile file(fileName);
+ if(!file.open( IO_ReadOnly )) {
+ m_errorString = i18n("Could not open file");
+ result = false;
+ } else {
+ QTextStream stream(&file);
+ result = load(stream);
+ file.close();
+ }
+ return result;
+}
+
+bool Palette::save(QTextStream& stream, const QFile* file /* = 0 */,
+ bool saveName /* = true */) {
+ bool result = true;
+ if(saveName)
+ stream << name() + QString("\n");
+ if(file && file->status() != IO_Ok) {
+ m_errorString = i18n("Write error");
+ result = false;
+ } else
+ for(int colorIndex = 0; colorIndex < length(); ++colorIndex) {
+ Color* col = color(colorIndex);
+ QString redComponentString;
+ QString greenComponentString;
+ QString blueComponentString;
+ redComponentString.setNum(col->component( Color::RED_INDEX ));
+ greenComponentString.setNum(col->component( Color::GREEN_INDEX ));
+ blueComponentString.setNum(col->component( Color::BLUE_INDEX ));
+ QString nameString = col->name();
+ if(!nameString.isEmpty())
+ nameString.prepend(" ");
+ stream << redComponentString + QString(" ") +
+ greenComponentString + QString(" ") +
+ blueComponentString +
+ nameString + QString("\n");
+ if(file && file->status() != IO_Ok) {
+ m_errorString = i18n("Write error");
+ result = false;
+ break;
+ }
+ }
+ return result;
+}
+
+bool Palette::save(const QString& fileName) {
+ bool result = true;
+ QFile file(fileName);
+ if(!file.open( IO_WriteOnly|IO_Truncate )) {
+ m_errorString = i18n("Could not open file for writing");
+ result = false;
+ } else {
+ QTextStream stream(&file);
+ result = save(stream);
+ file.close();
+ }
+ return result;
+}
+
+void Palette::deleteContents() {
+ colors.clear();
+}
+
+const QString& Palette::errorString() const {
+ return m_errorString;
+}
diff --git a/kcoloredit/palette.h b/kcoloredit/palette.h
new file mode 100644
index 00000000..7b763296
--- /dev/null
+++ b/kcoloredit/palette.h
@@ -0,0 +1,102 @@
+/***************************************************************************
+ palette.h - description
+ -------------------
+ begin : Sat Jul 8 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef PALETTE_H
+#define PALETTE_H
+
+#include <qstring.h>
+#include <qtextstream.h>
+#include <qfile.h>
+
+#include "color.h"
+
+/**This class holds a palette.
+ *@author Artur Rataj
+ */
+class Palette {
+public:
+ /** Constructs an empty palette */
+ Palette();
+ /** The copy constructor */
+ Palette(const Palette& palette);
+ ~Palette();
+ /** @return A list of KDE palettes */
+ static QStringList kdePalettes();
+ /** sets palette name */
+ void setName(const QString& name);
+ /** @return palette name */
+ const QString& name() const;
+ /** inserts a color at a given position */
+ void insert(const int index, Color* const color);
+ /** appends a color */
+ void append(Color* const color);
+ /** removes a color at index */
+ void remove(const int index);
+ /** @return the number of colors */
+ int length() const;
+ /** @return color at index */
+ Color* color(const int index);
+ /** @return a copy of palette at index, of length length */
+ Palette copy(const int index, const int length);
+ /** cuts a palette at index, of length length
+ * @return a palette that has been cut out
+ */
+ Palette cut(const int index, const int length);
+ /** pastes a palette at index */
+ void paste(const int index, Palette& palette);
+ /** Loads a palette from a text stream
+ * @return whether the load was succesfull
+ */
+ bool load(QTextStream& stream, bool loadName = true);
+ /** Loads a palette from a file.
+ * If loadName is true, palette name is expected.
+ * @return whether the load was succesfull
+ */
+ bool load(const QString& fileName);
+ /** Saves a palette into a text stream.
+ * If file is given, it is checked for IO errors.
+ * If saveName is true, palette name is saved.
+ * @return whether save was succesfull
+ */
+ bool save(QTextStream& stream, const QFile* file = 0, bool saveName = true);
+ /** Saves a palette to a file
+ * @return whether save was succesfull
+ */
+ bool save(const QString& fileName);
+ /** Deletes contents of the palette */
+ void deleteContents();
+ /** @return A possible error description from the last unsuccessfull
+ * IO operation
+ */
+ const QString& errorString() const;
+
+private:
+ /** The palette name */
+ QString m_name;
+
+private:
+ /** Initialization method called by constructors */
+ void init();
+
+protected:
+ /** A list of palette colors */
+ QPtrList<Color> colors;
+ /** An IO error description */
+ QString m_errorString;
+};
+
+#endif
diff --git a/kcoloredit/palettehistory.h b/kcoloredit/palettehistory.h
new file mode 100644
index 00000000..8bb63643
--- /dev/null
+++ b/kcoloredit/palettehistory.h
@@ -0,0 +1,26 @@
+/***************************************************************************
+ palettehistory.h - description
+ -------------------
+ begin : Sun Jul 9 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef __PALETTE_HISTORY_H__
+#define __PALETTE_HISTORY_H__
+
+#include "editablestreamhistory.h"
+
+/** Definition of PaletteHistory type */
+typedef EditableStreamHistory<Palette> PaletteHistory;
+
+#endif /* !defined( __PALETTE_HISTORY_H__ ) */
diff --git a/kcoloredit/paletteview.cpp b/kcoloredit/paletteview.cpp
new file mode 100644
index 00000000..8e05a2d7
--- /dev/null
+++ b/kcoloredit/paletteview.cpp
@@ -0,0 +1,75 @@
+/***************************************************************************
+ paletteview.cpp - description
+ -------------------
+ begin : Sun Jul 9 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include <qlayout.h>
+
+#include "kcoloreditview.h"
+#include "paletteview.h"
+
+PaletteView::PaletteView(const int defaultCellWidth, const int defaultCellHeight, const int cellSpacing,
+ KColorEditView* view, QWidget *parent, const char *name) :
+ QFrame(parent, name, QWidget::WResizeNoErase*0) {
+ setFrameStyle(StyledPanel|Sunken);
+ setLineWidth(2);
+ QGridLayout* topLayout = new QGridLayout(this, 2, 2);
+ topLayout->setMargin(2);
+ topLayout->setRowStretch(0, 10);
+ topLayout->setRowStretch(1, 0);
+ topLayout->setColStretch(0, 10);
+ topLayout->setColStretch(1, 0);
+ scrollBar = new QScrollBar(this);
+ hScrollBar = new QScrollBar(0, 1, 1, 1, 0, QScrollBar::Horizontal, this);
+ scrolledArea = new PaletteViewScrolledArea(defaultCellWidth,
+ defaultCellHeight, cellSpacing, scrollBar, hScrollBar, view, this);
+ connect(scrollBar, SIGNAL( valueChanged(int) ),
+ SLOT( slotRepaintScrolledArea() ));
+ topLayout->addWidget(scrolledArea, 0, 0);
+ connect(hScrollBar, SIGNAL( valueChanged(int) ),
+ SLOT( slotRepaintScrolledArea() ));
+ QHBoxLayout* hScrollBarLayout = new QHBoxLayout();
+ hScrollBarLayout->addWidget(hScrollBar, 10);
+ hScrollBarLayout->addWidget(new QWidget(this), 0);
+ topLayout->addLayout(hScrollBarLayout, 1, 0);
+ topLayout->addWidget(scrollBar, 0, 1);
+}
+
+PaletteView::~PaletteView() {
+}
+
+void PaletteView::redraw() {
+ slotRepaintScrolledArea();
+}
+
+void PaletteView::setScrollBarValue(const int value) {
+ scrollBar->setValue(value);
+ hScrollBar->setValue(0);
+}
+
+void PaletteView::slotViewColorNames(bool viewColorNames) {
+ scrolledArea->slotViewColorNames(viewColorNames);
+ setScrollBarValue(0);
+ scrolledArea->redraw();
+}
+
+void PaletteView::slotCursorFollowsChosenColor(bool follows) {
+ scrolledArea->slotCursorFollowsChosenColor(follows);
+}
+
+void PaletteView::slotRepaintScrolledArea() {
+ scrolledArea->redraw();
+}
+#include "paletteview.moc"
diff --git a/kcoloredit/paletteview.h b/kcoloredit/paletteview.h
new file mode 100644
index 00000000..0032997f
--- /dev/null
+++ b/kcoloredit/paletteview.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+ paletteview.h - description
+ -------------------
+ begin : Sun Jul 9 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef PALETTEVIEW_H
+#define PALETTEVIEW_H
+
+#include <qframe.h>
+#include <qscrollbar.h>
+
+#include "paletteviewscrolledarea.h"
+
+class KColorEditView;
+
+/** This is a Palette class view widget.
+ * Its parent is KColorEditView
+ * @author Artur Rataj
+ */
+class PaletteView : public QFrame {
+ Q_OBJECT
+
+public:
+ /** Constructs a palette view widget, with a default cells sizes and spacing.
+ * The effective cell sizes may be adjusted to fit the widget sizes.
+ */
+ PaletteView(const int defaultCellWidth, const int defaultCellHeight, const int cellSpacing,
+ KColorEditView* view, QWidget *parent = 0, const char *name=0);
+ ~PaletteView();
+ /** Calls redraw() in scrolledArea */
+ void redraw();
+ /** Sets a scroll bar value */
+ void setScrollBarValue(const int value);
+ /** Sets whether to view color names */
+ void slotViewColorNames(bool viewColorNames);
+
+public slots:
+ /** Sets if the cursor follows a chosen color */
+ void slotCursorFollowsChosenColor(bool follows);
+ /** Repaints the scrolled area */
+ void slotRepaintScrolledArea();
+
+protected:
+ /** The scrolled area */
+ PaletteViewScrolledArea* scrolledArea;
+ /** The scroll bar widget */
+ QScrollBar* scrollBar;
+ /** The horizontal scroll bar widget */
+ QScrollBar* hScrollBar;
+};
+
+#endif
diff --git a/kcoloredit/paletteviewscrolledarea.cpp b/kcoloredit/paletteviewscrolledarea.cpp
new file mode 100644
index 00000000..dafb4d10
--- /dev/null
+++ b/kcoloredit/paletteviewscrolledarea.cpp
@@ -0,0 +1,409 @@
+/***************************************************************************
+ paletteviewscrolledarea.cpp
+ -------------------
+ begin : Sun Jul 17 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include <stdlib.h>
+#include <qptrlist.h>
+#include <qcolor.h>
+#include <qcursor.h>
+#include <qbrush.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qpen.h>
+#include <qfontmetrics.h>
+#include <qtimer.h>
+#include <kglobal.h>
+#include <kcolordrag.h>
+#include <qscrollbar.h>
+
+#include "palette.h"
+#include "palettehistory.h"
+#include "kcoloreditdoc.h"
+#include "kcoloreditview.h"
+#include "paletteviewscrolledarea.h"
+#include "paletteviewscrolledarea.moc"
+
+PaletteViewScrolledArea::PaletteViewScrolledArea(const int defaultCellWidth,
+ const int defaultCellHeight, const int cellSpacing, QScrollBar* scrollBar,
+ QScrollBar* hScrollBar, KColorEditView* view, QWidget* parent, const char* name)
+ : QFrame(parent, name) {
+ this->defaultCellWidth = defaultCellWidth;
+ this->defaultCellHeight = defaultCellHeight;
+ this->cellSpacing = cellSpacing;
+ this->scrollBar = scrollBar;
+ this->hScrollBar = hScrollBar;
+ this->view = view;
+ setBackgroundMode(NoBackground);
+ scrollTimeoutTimer = new QTimer(this);
+ connect(scrollTimeoutTimer, SIGNAL( timeout() ), SLOT( slotScrollTimeout() ));
+ scrollTimeout = true;
+ mousePressed = false;
+ cursorPositioning = false;
+ colorChosen = false;
+ setCellsSizes();
+ slotCursorFollowsChosenColor(false);
+ this->scrollBar->setValue(0);
+ slotViewColorNames(false);
+ setMinimumSize(1, 1);
+}
+
+PaletteViewScrolledArea::~PaletteViewScrolledArea() {
+}
+
+void PaletteViewScrolledArea::slotCursorFollowsChosenColor(bool follows) {
+ cursorFollowsChosenColor = follows;
+}
+
+void PaletteViewScrolledArea::slotViewColorNames(bool viewColorNames) {
+ this->viewColorNames = viewColorNames;
+}
+
+void PaletteViewScrolledArea::redraw() {
+ //setCellsSizes();
+ repaintPalette();
+}
+
+void PaletteViewScrolledArea::repaintPalette() {
+ repaint(false);
+}
+
+void PaletteViewScrolledArea::checkSelectionAutoScroll(const int mousePosY) {
+ if(mousePosY < 0)
+ scrollPalette(-8, 50);
+ else if(mousePosY > height() - 1)
+ scrollPalette(8, 50);
+}
+
+void PaletteViewScrolledArea::scrollPalette(const int amount, const int timeout) {
+ if(scrollTimeout) {
+ scrollBy(amount);
+ scrollTimeout = false;
+ scrollTimeoutTimer->start(timeout, true);
+ }
+}
+
+void PaletteViewScrolledArea::slotScrollTimeout() {
+ scrollTimeout = true;
+ if(mousePressed) {
+ QPoint cursorPoint = mapFromGlobal(QCursor::pos());
+ setCursorPos(cursorPoint.x(), cursorPoint.y());
+ selectionEnd = cursorPos();
+ if(selectionEnd >= selectionBegin)
+ setSelection(selectionBegin, selectionEnd);
+ else
+ setSelection(selectionEnd, selectionBegin);
+ checkSelectionAutoScroll(cursorPoint.y());
+ repaintPalette();
+ }
+}
+
+void PaletteViewScrolledArea::setCursorPos(const int pos) {
+ int oldCursorPos = document()->paletteCursorPos();
+ document()->setPaletteCursorPos(pos);
+ if(pos != oldCursorPos)
+ view->slotCursorPosChanged(pos);
+}
+
+bool PaletteViewScrolledArea::setCursorPos(const int x, const int y) {
+ int shiftedY = y + scrollBar->value();
+ int shiftedX = x + hScrollBar->value();
+ int cursorColumn = (shiftedX + rowWidth/cellsInRow/2)*cellsInRow/rowWidth;
+ int cursorRow;
+ if(shiftedY >= 0)
+ cursorRow = (shiftedY + cellSpacing)/rowHeight;
+ else
+ cursorRow = -1;
+ bool atCursorLocation = abs(cursorColumn*rowWidth/cellsInRow - shiftedX) < cellSpacing + 1;
+ if(!atCursorLocation) {
+ atCursorLocation = abs(cursorRow*rowHeight - shiftedY) < cellSpacing + 1;
+ if(atCursorLocation)
+ cursorColumn = 0;
+ }
+ if(atCursorLocation || cursorPositioning) {
+ if(cursorColumn > cellsInRow - 1) {
+ cursorColumn = 0;
+ ++cursorRow;
+ }
+ int tmpCursorPos = cursorRow*cellsInRow + cursorColumn;
+ if(tmpCursorPos < 0)
+ tmpCursorPos = 0;
+ else if(tmpCursorPos >= palette()->length()) {
+ if(tmpCursorPos == palette()->length() &&
+ cursorColumn == 0 &&
+ selectionMin() == selectionMax())
+ /* if cursor has been set after the last color and the color is
+ * also the last in a row, and there is no selection, scroll the
+ * palette to ensure the cursor is visible
+ */
+ scrollBy(rowHeight*2);
+ if(tmpCursorPos > palette()->length())
+ tmpCursorPos = palette()->length();
+ }
+ setCursorPos(tmpCursorPos);
+ }
+ return atCursorLocation;
+}
+
+void PaletteViewScrolledArea::setSelection(const int min, const int max) {
+ document()->setPaletteSelection(min, max);
+}
+
+void PaletteViewScrolledArea::setCellsSizes() {
+ rowWidth = width();
+ cellWidth = defaultCellWidth;
+ cellHeight = defaultCellHeight;
+ if(viewColorNames) {
+ QPainter painter;
+ painter.begin(this);
+ if(cellHeight < painter.fontMetrics().height()) {
+ int prevCellHeight = cellHeight;
+ cellHeight = painter.fontMetrics().height();
+ cellWidth = cellHeight*cellWidth/prevCellHeight;
+ }
+ painter.end();
+ }
+ if(viewColorNames)
+ cellsInRow = 1;
+ else
+ cellsInRow = rowWidth/(cellWidth + cellSpacing*2);
+ if(viewColorNames)
+ rowHeight = cellHeight + cellSpacing*2;
+ else
+ rowHeight = (int)(rowWidth*1.0/cellsInRow/
+ ( cellWidth + cellSpacing*2 )*( cellHeight + cellSpacing*2 ) + 0.5);
+ cellHeight = rowHeight - cellSpacing*2;
+ rowsNum = (palette()->length() + cellsInRow - 1)/cellsInRow;
+ cellTableHeight = rowsNum*rowHeight;
+ int contentsHeight;
+ if(palette()->length() != 0 &&
+ ( palette()->length()%cellsInRow ) == 0)
+ contentsHeight = cellTableHeight + rowHeight;
+ else
+ contentsHeight = cellTableHeight;
+ int scrollBarRange = contentsHeight - 1 - height();
+ if(scrollBarRange < 0)
+ scrollBarRange = 0;
+ scrollBar->setRange(0, scrollBarRange);
+ scrollBar->setSteps(rowHeight, height());
+}
+
+Palette* PaletteViewScrolledArea::palette() const {
+ return document()->paletteHistory()->editableStream();
+}
+
+int PaletteViewScrolledArea::cursorPos() const {
+ return document()->paletteCursorPos();
+}
+
+int PaletteViewScrolledArea::selectionMin() const{
+ return document()->paletteSelectionBegin();
+}
+
+int PaletteViewScrolledArea::selectionMax() const {
+ return document()->paletteSelectionEnd();
+}
+
+void PaletteViewScrolledArea::paintEvent(QPaintEvent* /*event*/) {
+ setCellsSizes();
+ QPixmap pixmap(size());
+ QPainter painter;
+ painter.begin(&pixmap, this);
+ QFontMetrics fontMetrics = painter.fontMetrics();
+ int maxLineWidth;
+ if(viewColorNames) {
+ int maxTextLength = 0;
+ for(int index = 0; index < palette()->length(); ++index) {
+ int currTextLength = fontMetrics.width(
+ palette()->color(index)->name());
+ if(currTextLength > maxTextLength)
+ maxTextLength = currTextLength;
+ }
+ maxLineWidth = cellWidth + cellSpacing*2 +
+ cellSpacing*3 + maxTextLength + 1;
+ } else
+ maxLineWidth = rowWidth;
+ int width = rowWidth;
+ if(maxLineWidth > width) {
+ hScrollBar->setRange(0, maxLineWidth - width);
+ hScrollBar->setSteps(8, width);
+ hScrollBar->show();
+ } else {
+ hScrollBar->setValue(0);
+ hScrollBar->hide();
+ }
+ int posY = scrollBar->value();
+ int firstRow = posY/rowHeight;
+ int lastRow = (posY + height() - 1 + rowHeight - 1)/rowHeight;
+ if(viewColorNames)
+ painter.fillRect(0, 0, rowWidth, height(),
+ QBrush( QFrame::palette().active().base() ));
+ QBrush normalBackgroundBrush(QFrame::palette().active().background());
+ QBrush selectedBackgroundBrush(QFrame::palette().active().highlight());
+ QBrush foregroundBrush;
+ QBrush cursorBrush(QFrame::palette().active().foreground());
+ QPen backgroundPen(QFrame::palette().active().foreground());
+ int min = selectionMin();
+ int max = selectionMax();
+ int fontAscent = fontMetrics.ascent();
+ int xBegin = -hScrollBar->value();
+ for(int x = 0; x < cellsInRow; ++x) {
+ int xEnd = -hScrollBar->value();
+ if(viewColorNames)
+ xEnd += cellWidth + cellSpacing*2;
+ else
+ xEnd += (x + 1)*(width - 1)/cellsInRow;
+ int cellWithSpacingWidth = xEnd - xBegin + 1;
+ int cellWidth = cellWithSpacingWidth - 2*cellSpacing;
+ for(int y = firstRow; y <= lastRow; ++y) {
+ int yBegin = y*rowHeight - posY;
+ int currCellNum = y*cellsInRow + x;
+ QBrush* backgroundBrush;
+ if(currCellNum >= min && currCellNum < max)
+ backgroundBrush = &selectedBackgroundBrush;
+ else
+ backgroundBrush = &normalBackgroundBrush;
+ if(currCellNum < palette()->length()) {
+ Color* color = palette()->color(currCellNum);
+ QBrush foregroundBrush(QColor(
+ color->component(Color::RED_INDEX),
+ color->component(Color::GREEN_INDEX),
+ color->component(Color::BLUE_INDEX) ));
+ painter.fillRect(xBegin, yBegin, cellWithSpacingWidth, cellSpacing,
+ *backgroundBrush);
+ painter.fillRect(xBegin, yBegin + rowHeight - cellSpacing, cellWithSpacingWidth, cellSpacing,
+ *backgroundBrush);
+ QBrush* backgroundOrCursorBrush;
+ if(cursorPos() == currCellNum)
+ backgroundOrCursorBrush = &cursorBrush;
+ else
+ backgroundOrCursorBrush = backgroundBrush;
+ painter.fillRect(xBegin, yBegin + cellSpacing, cellSpacing, cellHeight,
+ *backgroundOrCursorBrush);
+ painter.fillRect(xBegin + cellWithSpacingWidth - cellSpacing, yBegin + cellSpacing,
+ cellSpacing, cellHeight,
+ *backgroundBrush);
+ painter.fillRect(xBegin + cellSpacing, yBegin + cellSpacing, cellWidth, cellHeight,
+ foregroundBrush);
+ if(viewColorNames) {
+ painter.setPen(backgroundPen);
+ painter.drawText(xBegin + cellWithSpacingWidth + cellSpacing*3,
+ yBegin + rowHeight/2 + fontAscent/2, color->name());
+ }
+ } else {
+ if(cursorPos() == currCellNum) {
+ painter.fillRect(xBegin, yBegin + cellSpacing, cellSpacing, cellHeight,
+ cursorBrush);
+ painter.fillRect(xBegin, yBegin, cellSpacing, cellSpacing,
+ *backgroundBrush);
+ painter.fillRect(xBegin, yBegin + rowHeight - cellSpacing, cellSpacing, cellSpacing,
+ *backgroundBrush);
+ painter.fillRect(xBegin + cellSpacing, yBegin, cellWithSpacingWidth - cellSpacing, rowHeight,
+ *backgroundBrush);
+ } else
+ painter.fillRect(xBegin, yBegin, cellWithSpacingWidth, rowHeight,
+ *backgroundBrush);
+ }
+ }
+ xBegin = xEnd + 1;
+ }
+ painter.end();
+ painter.begin(this);
+ painter.drawPixmap(0, 0, pixmap);
+ painter.end();
+}
+
+int PaletteViewScrolledArea::colorIndex(const QPoint& point) const {
+ int colorColumn = point.x()*cellsInRow/rowWidth;
+ int colorRow = (point.y() + scrollBar->value())/rowHeight;
+ int colorIndex = colorRow*cellsInRow + colorColumn;
+ if(colorIndex > palette()->length() - 1 ||
+ colorIndex < 0)
+ colorIndex = -1;
+ return colorIndex;
+}
+
+QColor PaletteViewScrolledArea::color(const QPoint& point) const {
+ Color* color = palette()->color(colorIndex( point ));
+ return QColor(color->component( Color::RED_INDEX ),
+ color->component( Color::GREEN_INDEX ),
+ color->component( Color::BLUE_INDEX ));
+}
+
+void PaletteViewScrolledArea::mousePressEvent(QMouseEvent* event) {
+ cursorPositioning = false;
+ if(( cursorPositioning = setCursorPos(event->x(), event->y()) )) {
+ selectionBegin = cursorPos();
+ setSelection(selectionBegin, selectionBegin);
+ redraw();
+ colorChosen = false;
+ } else {
+ colorDragPoint = event->pos();
+ colorChosen = true;
+ }
+ mousePressed = true;
+}
+
+void PaletteViewScrolledArea::mouseMoveEvent(QMouseEvent* event) {
+ if(cursorPositioning) {
+ setCursorPos(event->x(), event->y());
+ selectionEnd = cursorPos();
+ if(selectionEnd >= selectionBegin)
+ setSelection(selectionBegin, selectionEnd);
+ else
+ setSelection(selectionEnd, selectionBegin);
+ checkSelectionAutoScroll(event->y());
+ redraw();
+ } else {
+ /* check if it is a color drag */
+ if(colorIndex( colorDragPoint ) != -1) {
+ if(abs( event->x() - colorDragPoint.x() ) > 2 ||
+ abs( event->y() - colorDragPoint.y() ) > 2) {
+ QColor draggedColor = color(colorDragPoint);
+ KColorDrag* colorDrag = KColorDrag::makeDrag(draggedColor, this);
+ colorDrag->dragCopy();
+ } else
+ colorChosen = true;
+ }
+ }
+}
+
+void PaletteViewScrolledArea::mouseReleaseEvent(QMouseEvent* /*event*/) {
+ if(colorChosen) {
+ if(colorIndex( colorDragPoint ) != -1) {
+ int index = colorIndex(colorDragPoint);
+ chooseColor(palette()->color( index ));
+ if(cursorFollowsChosenColor) {
+ setCursorPos(index);
+ setSelection(cursorPos(), cursorPos());
+ redraw();
+ }
+ }
+ colorChosen = false;
+ }
+ mousePressed = false;
+}
+
+void PaletteViewScrolledArea::chooseColor(Color* const color) {
+ view->chooseColor(color);
+}
+
+KColorEditDoc* PaletteViewScrolledArea::document() const {
+ return view->document();
+}
+
+void PaletteViewScrolledArea::scrollBy(const int y) {
+ scrollBar->setValue(scrollBar->value() + y);
+}
diff --git a/kcoloredit/paletteviewscrolledarea.h b/kcoloredit/paletteviewscrolledarea.h
new file mode 100644
index 00000000..18bbae2b
--- /dev/null
+++ b/kcoloredit/paletteviewscrolledarea.h
@@ -0,0 +1,162 @@
+/***************************************************************************
+ paletteviewscrolledarea.h
+ -------------------
+ begin : Sun Jul 17 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef PALETTEVIEWSCROLLEDAREA_H
+#define PALETTEVIEWSCROLLEDAREA_H
+
+#include <qframe.h>
+#include <qevent.h>
+
+#include "palette.h"
+
+class KColorEditDoc;
+class KColorEditView;
+class QScrollBar;
+
+/** This widget draws the palette view scrolled area.
+ * It has paste and cut features.
+ * @author Artur Rataj
+ */
+class PaletteViewScrolledArea : public QFrame {
+ Q_OBJECT
+
+public:
+ /** Constructs the widget */
+ PaletteViewScrolledArea(const int defaultCellWidth, const int defaultCellHeight,
+ const int cellSpacing, QScrollBar* scrollBar,
+ QScrollBar* hScrollBar, KColorEditView* view,
+ QWidget* parent = 0, const char* name = 0);
+ ~PaletteViewScrolledArea();
+ /** Sets cells sizes and then calls repaintPalette() */
+ void redraw();
+
+public slots:
+ /** Sets if the cursor follows a chosen color */
+ void slotCursorFollowsChosenColor(bool follows);
+ /** Sets whether to view color names */
+ void slotViewColorNames(bool viewColorNames);
+
+protected:
+ /** The scrollbar widget */
+ QScrollBar* scrollBar;
+ /** The horizontal scrollbar widget */
+ QScrollBar* hScrollBar;
+ /** Pointer to the document view */
+ KColorEditView* view;
+ /** Default cell width */
+ int defaultCellWidth;
+ /** Default cell height */
+ int defaultCellHeight;
+ /** Cell spacing */
+ int cellSpacing;
+ /** Cell width */
+ int cellWidth;
+ /** Cell height */
+ int cellHeight;
+ /** The number of cells in a row */
+ int cellsInRow;
+ /** The number of rows */
+ int rowsNum;
+ /** A row width */
+ int rowWidth;
+ /** A row height */
+ int rowHeight;
+ /** Total height of cells table */
+ int cellTableHeight;
+ /** A position at which selection started */
+ int selectionBegin;
+ /** A position at which selection ended */
+ int selectionEnd;
+ /** Auto scroll timeout timer */
+ QTimer* scrollTimeoutTimer;
+ /** Whether there is auto scroll timeout */
+ bool scrollTimeout;
+ /** Whether a mouse has been pressed over the palette and not yet released */
+ bool mousePressed;
+ /** Whether the cursor is being positioned */
+ bool cursorPositioning;
+ /** A color drag point */
+ QPoint colorDragPoint;
+ /** Whether a color has been chosen and it is not dragged */
+ bool colorChosen;
+ /** Whether the cursor follows a chosen color */
+ bool cursorFollowsChosenColor;
+ /** Whether to view color names */
+ bool viewColorNames;
+
+ /** @return The viewed palette */
+ Palette* palette() const;
+ /** Computes the size of cell, number of cells in a row and
+ * height of cells table, depending on colors number and
+ * visible area width
+ */
+ void setCellsSizes();
+ /** repaints the palette */
+ void repaintPalette();
+ /** @return A color index at a given position, -1 if none */
+ int colorIndex(const QPoint& point) const;
+ /** @return A color at a given position */
+ QColor color(const QPoint& point) const;
+ /** sets a palette cursor position */
+ void setCursorPos(const int pos);
+ /** Sets a cursor position due to a mouse position.
+ * If not in cursor positioning, the cursor is set
+ * only if mouse points to a possible cursor location
+ * @return If the mouse points to a cursor location
+ */
+ bool setCursorPos(const int x, const int y);
+ /** @return a palette cursor position */
+ int cursorPos() const;
+ /** sets a palette selection */
+ void setSelection(const int min, const int max);
+ /** @return a palette selection lesser position, or equal position
+ * if no colors are selected
+ */
+ int selectionMin() const;
+ /** @return a palette selection greater position, or equal position
+ * if no colors are selected
+ */
+ int selectionMax() const;
+ /** checks whether to scrolls the palette if a mouse position
+ * is outside it
+ */
+ void checkSelectionAutoScroll(const int mousePosY);
+ /** The widget painting */
+ void paintEvent(QPaintEvent* event);
+ /** Used to get mouse press events coordinates */
+ void mousePressEvent(QMouseEvent* event);
+ /** Used to get mouse move events coordinates */
+ void mouseMoveEvent(QMouseEvent* event);
+ /** Used to get mouse release events coordinates */
+ void mouseReleaseEvent(QMouseEvent* event);
+ /** If there is a scroll timeout, scrolls palette,
+ * sets scrollTimeout to false and resets scroll timeout timer
+ */
+ void scrollPalette(const int amount, const int timeout);
+ /** @return The viewed document */
+ KColorEditDoc* document() const;
+ /** Chooses a color to the color selector */
+ void chooseColor(Color* const color);
+ /** scrolls the scrolled area */
+ void scrollBy(const int y);
+
+protected slots:
+ /** called if there is a scroll timeout, sets scrollTimeout to true */
+ void slotScrollTimeout();
+};
+
+#endif /* !defined( PALETTEVIEWSCROLLEDAREA_H ) */
diff --git a/kcoloredit/resource.h b/kcoloredit/resource.h
new file mode 100644
index 00000000..c96576cc
--- /dev/null
+++ b/kcoloredit/resource.h
@@ -0,0 +1,35 @@
+/***************************************************************************
+ resource.h - description
+ -------------------
+ begin : Sat Jul 8 09:57:28 CEST 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef RESOURCE_H
+#define RESOURCE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+///////////////////////////////////////////////////////////////////
+// resource.h -- contains macros used for commands
+
+
+///////////////////////////////////////////////////////////////////
+// General application values
+#define ID_STATUS_MSG 1001
+
+#define IDS_STATUS_DEFAULT I18N_NOOP("Ready.")
+
+#endif // RESOURCE_H
diff --git a/kcoloredit/texteditselection.cpp b/kcoloredit/texteditselection.cpp
new file mode 100644
index 00000000..65d4ecad
--- /dev/null
+++ b/kcoloredit/texteditselection.cpp
@@ -0,0 +1,187 @@
+/***************************************************************************
+ texteditselection.cpp - description
+ -------------------
+ begin : Wed Jul 12 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include <qlabel.h>
+#include <qvalidator.h>
+#include <qcolor.h>
+
+#include <klocale.h>
+
+#include "main.h"
+#include "texteditselection.h"
+
+TextEditSelection::TextEditSelection(QWidget *parent, const char *name ) : QWidget(parent,name) {
+ inChangingComponents = false;
+ QVBoxLayout* topLayout = new QVBoxLayout(this, 4);
+ QGridLayout* componentsLayout = new QGridLayout(3, 5, 2);
+ topLayout->addLayout(componentsLayout);
+ componentsLayout->setColStretch(1, 10);
+ componentsLayout->addColSpacing(2, 8);
+ componentsLayout->setColStretch(4, 10);
+ QLineEdit* lineEdit;
+ addComponent(H_INDEX, ( lineEdit = new QLineEdit(this) ), HSV_MAX_H_VALUE, "H:", 0, 0, componentsLayout);
+ connect(lineEdit, SIGNAL( textChanged(const QString&) ), SLOT( slotHsvComponentChanged() ));
+ addComponent(S_INDEX, ( lineEdit = new QLineEdit(this) ), HSV_MAX_S_VALUE, "S:", 1, 0, componentsLayout);
+ connect(lineEdit, SIGNAL( textChanged(const QString&) ), SLOT( slotHsvComponentChanged() ));
+ addComponent(V_INDEX, ( lineEdit = new QLineEdit(this) ), HSV_MAX_V_VALUE, "V:", 2, 0, componentsLayout);
+ connect(lineEdit, SIGNAL( textChanged(const QString&) ), SLOT( slotHsvComponentChanged() ));
+ addComponent(R_INDEX, ( lineEdit = new QLineEdit(this) ), RGB_MAX_COMPONENT_VALUE, "R:", 0, 1, componentsLayout);
+ connect(lineEdit, SIGNAL( textChanged(const QString&) ), SLOT( slotRgbComponentChanged() ));
+ addComponent(G_INDEX, ( lineEdit = new QLineEdit(this) ), RGB_MAX_COMPONENT_VALUE, "G:", 1, 1, componentsLayout);
+ connect(lineEdit, SIGNAL( textChanged(const QString&) ), SLOT( slotRgbComponentChanged() ));
+ addComponent(B_INDEX, ( lineEdit = new QLineEdit(this) ), RGB_MAX_COMPONENT_VALUE, "B:", 2, 1, componentsLayout);
+ connect(lineEdit, SIGNAL( textChanged(const QString&) ), SLOT( slotRgbComponentChanged() ));
+ QHBoxLayout* rgbStringLayout = new QHBoxLayout(2);
+ QLabel* rgbStringLabel = new QLabel("RGB " + i18n( "hex." ) + ": ", this);
+ rgbStringLayout->addWidget(rgbStringLabel);
+ rgbStringLineEdit = new QLineEdit(this);
+ rgbStringLineEdit->setMinimumWidth(lineEdit->fontMetrics().width( QString("8888888") ));
+ rgbStringLineEdit->setMaximumWidth(lineEdit->fontMetrics().width( QString("888888888") ));
+ connect(rgbStringLineEdit, SIGNAL( textChanged(const QString&) ), SLOT( slotRgbStringChanged() ));
+ rgbStringLayout->addWidget(rgbStringLineEdit);
+ topLayout->addLayout(rgbStringLayout);
+}
+TextEditSelection::~TextEditSelection(){
+}
+
+void TextEditSelection::addComponent(const int index, QLineEdit* lineEdit, const int maxValue,
+ const QString& labelString, const int row, const int column, QGridLayout* layout) {
+ QLabel* label = new QLabel(labelString, this);
+ lineEdit->setValidator(new QIntValidator( 0, maxValue, lineEdit ));
+ lineEditTable[index] = lineEdit;
+ lineEdit->setMinimumWidth(lineEdit->fontMetrics().width( QString("8888") ));
+ lineEdit->setMaximumWidth(lineEdit->fontMetrics().width( QString("8888888") ));
+ layout->addWidget(label, row, column*3);
+ layout->addWidget(lineEdit, row, column*3 + 1);
+}
+
+void TextEditSelection::setRgbString(const int red, const int green, const int blue) {
+ QString string;
+ string.sprintf("%02x%02x%02x", red, green, blue);
+ rgbStringLineEdit->setText(string);
+}
+
+void TextEditSelection::slotHsvComponentChanged() {
+ if(!inChangingComponents) {
+ inChangingComponents = true;
+ int hComponent = lineEditTable[H_INDEX]->text().toInt();
+ int sComponent = lineEditTable[S_INDEX]->text().toInt();
+ int vComponent = lineEditTable[V_INDEX]->text().toInt();
+ QColor color;
+ color.setHsv(hComponent, sComponent, vComponent);
+ int rComponent = color.red();
+ int gComponent = color.green();
+ int bComponent = color.blue();
+ QString string;
+ lineEditTable[R_INDEX]->setText(string.setNum( rComponent ));
+ lineEditTable[G_INDEX]->setText(string.setNum( gComponent ));
+ lineEditTable[B_INDEX]->setText(string.setNum( bComponent ));
+ Color oldColor = this->color;
+ this->color.setComponent(Color::RED_INDEX, rComponent);
+ this->color.setComponent(Color::GREEN_INDEX, gComponent);
+ this->color.setComponent(Color::BLUE_INDEX, bComponent);
+ if(!this->color.equals( oldColor ))
+ emit valueChanged(&this->color);
+ setRgbString(rComponent, gComponent, bComponent);
+ inChangingComponents = false;
+ }
+}
+
+void TextEditSelection::slotRgbComponentChanged() {
+ if(!inChangingComponents) {
+ inChangingComponents = true;
+ int rComponent = lineEditTable[R_INDEX]->text().toInt();
+ int gComponent = lineEditTable[G_INDEX]->text().toInt();
+ int bComponent = lineEditTable[B_INDEX]->text().toInt();
+ QColor color;
+ color.setRgb(rComponent, gComponent, bComponent);
+ int hComponent;
+ int sComponent;
+ int vComponent;
+ color.hsv(&hComponent, &sComponent, &vComponent);
+ QString string;
+ lineEditTable[H_INDEX]->setText(string.setNum( hComponent ));
+ lineEditTable[S_INDEX]->setText(string.setNum( sComponent ));
+ lineEditTable[V_INDEX]->setText(string.setNum( vComponent ));
+ Color oldColor = this->color;
+ this->color.setComponent(Color::RED_INDEX, rComponent);
+ this->color.setComponent(Color::GREEN_INDEX, gComponent);
+ this->color.setComponent(Color::BLUE_INDEX, bComponent);
+ if(!this->color.equals( oldColor ))
+ emit valueChanged(&this->color);
+ setRgbString(rComponent, gComponent, bComponent);
+ inChangingComponents = false;
+ }
+}
+
+void TextEditSelection::slotRgbStringChanged() {
+ if(!inChangingComponents) {
+ inChangingComponents = true;
+ QString string = rgbStringLineEdit->text().stripWhiteSpace();
+ bool result;
+ int value = string.toInt(&result, 16);
+ if(result) {
+ int rComponent = (value >> 16)&0xff;
+ int gComponent = (value >> 8)&0xff;
+ int bComponent = (value >> 0)&0xff;
+ lineEditTable[R_INDEX]->setText(string.setNum( rComponent ));
+ lineEditTable[G_INDEX]->setText(string.setNum( gComponent ));
+ lineEditTable[B_INDEX]->setText(string.setNum( bComponent ));
+ int hComponent;
+ int sComponent;
+ int vComponent;
+ QColor hsvColor;
+ hsvColor.hsv(&hComponent, &sComponent, &vComponent);
+ lineEditTable[H_INDEX]->setText(string.setNum( hComponent ));
+ lineEditTable[S_INDEX]->setText(string.setNum( sComponent ));
+ lineEditTable[V_INDEX]->setText(string.setNum( vComponent ));
+ Color oldColor = this->color;
+ this->color.setComponent(Color::RED_INDEX, rComponent);
+ this->color.setComponent(Color::GREEN_INDEX, gComponent);
+ this->color.setComponent(Color::BLUE_INDEX, bComponent);
+ if(!this->color.equals( oldColor ))
+ emit valueChanged(&this->color);
+ }
+ inChangingComponents = false;
+ }
+}
+
+void TextEditSelection::slotSetValue(Color* color) {
+ if(!color->equals( this->color )) {
+ inChangingComponents = true;
+ this->color = *color;
+ QString string;
+ int rComponent = this->color.component(Color::RED_INDEX);
+ int gComponent = this->color.component(Color::GREEN_INDEX);
+ int bComponent = this->color.component(Color::BLUE_INDEX);
+ lineEditTable[R_INDEX]->setText(string.setNum( rComponent ));
+ lineEditTable[G_INDEX]->setText(string.setNum( gComponent ));
+ lineEditTable[B_INDEX]->setText(string.setNum( bComponent ));
+ QColor hsvColor(rComponent, gComponent, bComponent);
+ int hComponent;
+ int sComponent;
+ int vComponent;
+ hsvColor.hsv(&hComponent, &sComponent, &vComponent);
+ lineEditTable[H_INDEX]->setText(string.setNum( hComponent ));
+ lineEditTable[S_INDEX]->setText(string.setNum( sComponent ));
+ lineEditTable[V_INDEX]->setText(string.setNum( vComponent ));
+ setRgbString(rComponent, gComponent, bComponent);
+ inChangingComponents = false;
+ }
+}
+
+#include "texteditselection.moc"
diff --git a/kcoloredit/texteditselection.h b/kcoloredit/texteditselection.h
new file mode 100644
index 00000000..c2166098
--- /dev/null
+++ b/kcoloredit/texteditselection.h
@@ -0,0 +1,89 @@
+/***************************************************************************
+ texteditselection.h - description
+ -------------------
+ begin : Wed Jul 12 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef TEXTEDITSELECTION_H
+#define TEXTEDITSELECTION_H
+
+#include <qwidget.h>
+#include <qlineedit.h>
+#include <qlayout.h>
+
+#include "color.h"
+
+/** Color selection widget using line edit. Either HSV or RGB components
+ * can be set.
+ * @author Artur Rataj
+ */
+class TextEditSelection : public QWidget {
+ Q_OBJECT
+
+public:
+ /** Constructs the widget */
+ TextEditSelection(QWidget *parent=0, const char *name=0);
+ ~TextEditSelection();
+
+signals:
+ /** A signal that a color value has changed by edition */
+ void valueChanged(Color*);
+
+public slots:
+ /** sets a color */
+ void slotSetValue(Color* color);
+
+protected:
+ /** Adds a component line edit */
+ void addComponent(const int index, QLineEdit* lineEdit, const int maxValue, const QString& labelString,
+ const int row, const int column, QGridLayout* layout);
+ /** sets RGB string in rgbStringLineEdit */
+ void setRgbString(const int red, const int green, const int blue);
+
+protected slots:
+ /** Called if one of HSV components has changed. In that case, RGB components are
+ * also changed to match the HSV ones
+ */
+ void slotHsvComponentChanged();
+ /** Called if one of RGB components has changed. In that case, HSV components are
+ * also changed to match the RGB ones
+ */
+ void slotRgbComponentChanged();
+ /** Called if the RGB string has changed. In that case, RGB and HSV components are
+ * also changed to match the RGB string
+ */
+ void slotRgbStringChanged();
+
+protected:
+ /** Indexes of components */
+ enum { H_INDEX = 0,
+ S_INDEX = 1,
+ V_INDEX = 2,
+ R_INDEX = 3,
+ G_INDEX = 4,
+ B_INDEX = 5,
+ /** A total number of components */
+ COMPONENTS_NUM = 6 };
+
+ /** Line edit widgets table */
+ QLineEdit* lineEditTable[COMPONENTS_NUM];
+ /** RGB hex string line edit widgets table */
+ QLineEdit* rgbStringLineEdit;
+ /** The selected color */
+ Color color;
+ /** A flag that components are matched */
+ bool inChangingComponents;
+};
+
+#endif
diff --git a/kcoloredit/textselection.cpp b/kcoloredit/textselection.cpp
new file mode 100644
index 00000000..8a4225bc
--- /dev/null
+++ b/kcoloredit/textselection.cpp
@@ -0,0 +1,24 @@
+/***************************************************************************
+ textselection.cpp - description
+ -------------------
+ begin : Wed Jul 12 2000
+ copyright : (C) 2000 by Artur Rataj
+ email : art@zeus.polsl.gliwice.pl
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include "textselection.h"
+
+TextSelection::TextSelection(QWidget *parent, const char *name ) : QWidget(parent,name) {
+
+}
+TextSelection::~TextSelection(){
+}
diff --git a/kcoloredit/uninstall.desktop b/kcoloredit/uninstall.desktop
new file mode 100644
index 00000000..e1e3e173
--- /dev/null
+++ b/kcoloredit/uninstall.desktop
@@ -0,0 +1,2 @@
+[Desktop Entry]
+Hidden=true
diff --git a/kdegraphics.lsm b/kdegraphics.lsm
new file mode 100644
index 00000000..a3933ce8
--- /dev/null
+++ b/kdegraphics.lsm
@@ -0,0 +1,11 @@
+Begin4
+Title: kdegraphics
+Version: 3.5.10
+Entered-date: 2008-08-26
+Description: Graphical Applications written for the K Desktop Environment (KDE)
+Keywords: KDE X11 desktop Qt
+Author: http://bugs.kde.org/ (KDE Bugtracking System)
+Primary-site: http://www.kde.org/download/
+Platforms: Unix, Qt
+Copying-policy: GPL, Artistic
+End
diff --git a/kdvi/AUTHORS b/kdvi/AUTHORS
new file mode 100644
index 00000000..0d869c99
--- /dev/null
+++ b/kdvi/AUTHORS
@@ -0,0 +1,39 @@
+The programm KDVI is based on the dvi-previewer xdvik, See below. KDVI
+was written by Markku Hihnala with the help of many
+collaborators. Later KDVI became a plug-in to KViewShell and Stefan
+Kebekus re-implemented parts of the program. The current version of
+KDVI shares a substantial amount of code with xdvi, not not very much
+with the first versions of KDVI.
+
+------------------------------------------------------------------------------
+
+
+AUTHORS OF xdvik
+================
+
+This program, xdvik, was modified by kb@cs.umb.edu from Paul Vojta's
+xdvi distribution for common path searching, GNU-style configuration,
+etc. Send bug reports to tex-k@cs.umb.edu, not to Paul. See the
+README for more info.
+
+Here are the credits for the original xdvi program:
+
+This program is the combined work of many people, including but not restricted to:
+ Eric Cooper, CMU
+ Bob Scheifler, MIT LCS
+ Paal Kvamme, Norwegian Institute of Technology
+ H\aa vard Eidnes, Norwegian Institute of Technology
+ Mark Eichin, MIT SIPB
+ Paul Vojta, UC Berkeley
+ Jeffrey Lee, U of Toronto
+ Donald Richardson, Clarkson Univ.
+
+In addition to the various comp.sources.x archives, current versions
+of this program (the original xdvi, not xdvik) can also be obtained
+via anonymous ftp from the following location:
+
+ export.lcs.mit.edu [18.30.0.212] file contrib/xdvi.tar.Z
+To ease the load on expo, you may also check other X archives, for example:
+ gatekeeper.dec.com [16.1.0.2] file pub/X11/contrib/xdvi.shar.Z
+
+Paul Vojta is now the primary maintainer.
diff --git a/kdvi/ChangeLog b/kdvi/ChangeLog
new file mode 100644
index 00000000..8345a95e
--- /dev/null
+++ b/kdvi/ChangeLog
@@ -0,0 +1,9 @@
+Mon Jun 29 08:43:45 1998 Bernd Johannes Wuebben <wuebben@math.cornell.edu>
+
+ * KDVI uses KFileDialog now.
+
+Version 0.4.2
+ * [Robert Williams] Added version.h and ChangeLog
+ * [Robert Williams] Renamed Kdvi.kdelnk to kdvi.kdelnk
+ * [Robert Williams] Added -caption "%c" to kdvi.kdelnk
+ * [Robert Williams] Added getHelpMenu()
diff --git a/kdvi/Makefile.am b/kdvi/Makefile.am
new file mode 100644
index 00000000..dce4053a
--- /dev/null
+++ b/kdvi/Makefile.am
@@ -0,0 +1,66 @@
+# set the include path for X, qt and KDE
+INCLUDES= -I$(top_srcdir)/kviewshell \
+ -I$(top_builddir)/kviewshell \
+ $(all_includes) $(LIBFREETYPE_CFLAGS)
+# claim, which subdirectories you want to install
+SUBDIRS = . pix
+
+bin_PROGRAMS = kdvi
+
+# you can add here more. This one gets installed
+kde_module_LTLIBRARIES= kdvipart.la
+noinst_PROGRAMS = squeeze
+
+# just to make sure, automake makes them
+METASOURCES = AUTO
+
+kdvipart_la_SOURCES = renderedDviPagePixmap.cpp dviPageCache.cpp \
+ kdvi_multipage.cpp kdvi_multipage_texthandling.cpp \
+ dviRenderer.cpp bigEndianByteReader.cpp infodialog.cpp \
+ psheader.c dviRenderer_draw.cpp dviRenderer_prescan.cpp dviRenderer_export.cpp \
+ dviFile.cpp fontpool.cpp fontprogress.cpp psgs.cpp \
+ fontMap.cpp fontEncoding.cpp fontEncodingPool.cpp \
+ special.cpp util.cpp vf.cpp glyph.cpp \
+ optionDialogFontsWidget.cpp optionDialogFontsWidget_base.ui \
+ optionDialogSpecialWidget.cpp optionDialogSpecialWidget_base.ui \
+ TeXFont.cpp TeXFont_PK.cpp TeXFont_PFB.cpp TeXFont_TFM.cpp \
+ TeXFontDefinition.cpp dviWidget.cpp dvisourcesplitter.cpp \
+ prefs.kcfgc
+
+kde_kcfg_DATA = kdvi.kcfg
+
+kdvipart_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+kdvipart_la_LIBADD = $(LIBFREETYPE_LIBS) -lkparts \
+ $(top_builddir)/kviewshell/libkmultipage.la
+
+# Which sources should be compiled for squeeze.
+squeeze_SOURCES = squeeze.c
+
+KDE_OPTIONS = nofinal
+
+kdvi_SOURCES = main.cpp
+kdvi_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+kdvi_LDADD = ../kviewshell/libifaces.la ../kviewshell/libkviewshell.la -lkparts
+
+## this option you can leave out. Just, if you use "make dist", you need it
+noinst_HEADERS = dvi.h dviRenderer.h xdvi.h
+
+messages: rc.cpp
+ $(PREPARETIPS) > tips.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/kdvi.pot
+ rm -f tips.cpp
+
+xdg_apps_DATA = kdvi.desktop
+
+tip_DATA = tips
+tipdir = $(kde_datadir)/kdvi
+
+partdir = $(kde_datadir)/kdvi
+part_DATA = ../kviewshell/kviewshell.rc kdvi_part.rc
+
+kde_services_DATA = kdvimultipage.desktop
+
+psheader.c: psheader.txt squeeze
+ ./squeeze $(srcdir)/psheader.txt $@
+
+CLEANFILES = psheader.c
diff --git a/kdvi/TODO b/kdvi/TODO
new file mode 100644
index 00000000..44a4433c
--- /dev/null
+++ b/kdvi/TODO
@@ -0,0 +1,30 @@
+ToDo-List for kdvi
+
+URGENT / URGENT BUGFIXING
+
+o improve performance and perceived performance (see also under 'highly desirable')
+
+o do not render the same PS code more than once if all pages have the same PS code
+o add "papersize" which does not display the margin
+o get rid of useless README.kdvi
+o Proper handling of the base-url
+o add "tt.dvi.gz" to the list of recent files, not "/tmp/kviews....."
+o If one presses PgDn for a while, kdvi spends minutes browsing through pages...
+
+HIGHLY DESIRABLE
+
+o Speedup, in particular for ghostscript and glyph enlarging.
+
+o Support papersize information given by the dvi-file on a page-by-page
+ basis.
+
+o asynchronous rendering of pages, so that browsing with pg up/down looks faster
+
+
+NOT SO URGENT
+
+o Internal printing using QPrinter
+o Magnifier window
+o Two page view
+o Support for even more TeX specials
+o more robust Error handling with throw/catch; no need to abort just because a PK-file is bad. \ No newline at end of file
diff --git a/kdvi/TeXFont.cpp b/kdvi/TeXFont.cpp
new file mode 100644
index 00000000..829b00fb
--- /dev/null
+++ b/kdvi/TeXFont.cpp
@@ -0,0 +1,9 @@
+#include <config.h>
+
+#include "glyph.h"
+#include "TeXFont.h"
+
+TeXFont::~TeXFont()
+{
+ ;
+}
diff --git a/kdvi/TeXFont.h b/kdvi/TeXFont.h
new file mode 100644
index 00000000..8ff70499
--- /dev/null
+++ b/kdvi/TeXFont.h
@@ -0,0 +1,48 @@
+// -*- C++ -*-
+// TeXFont.h
+//
+// Part of KDVI - A DVI previewer for the KDE desktop environemt
+//
+// (C) 2003 Stefan Kebekus
+// Distributed under the GPL
+
+#ifndef _TEXFONT_H
+#define _TEXFONT_H
+
+#include "TeXFontDefinition.h"
+#include "glyph.h"
+
+
+class TeXFont {
+ public:
+ TeXFont(TeXFontDefinition *_parent)
+ {
+ parent = _parent;
+ errorMessage = QString::null;
+ };
+
+ virtual ~TeXFont();
+
+ void setDisplayResolution()
+ {
+ for(unsigned int i=0; i<TeXFontDefinition::max_num_of_chars_in_font; i++)
+ glyphtable[i].shrunkenCharacter.resize(0, 0);
+ };
+
+ virtual glyph* getGlyph(Q_UINT16 character, bool generateCharacterPixmap=false, const QColor& color=Qt::black) = 0;
+
+ // Checksum of the font. Used e.g. by PK fonts. This field is filled
+ // in by the constructor, or set to 0.0, if the font format does not
+ // contain checksums.
+ Q_UINT32 checksum;
+
+ // If the font or if some glyphs could not be loaded, error messages
+ // will be put here.
+ QString errorMessage;
+
+ protected:
+ glyph glyphtable[TeXFontDefinition::max_num_of_chars_in_font];
+ TeXFontDefinition *parent;
+};
+
+#endif
diff --git a/kdvi/TeXFontDefinition.cpp b/kdvi/TeXFontDefinition.cpp
new file mode 100644
index 00000000..9b745c83
--- /dev/null
+++ b/kdvi/TeXFontDefinition.cpp
@@ -0,0 +1,250 @@
+// $Id$
+#include <config.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <qfile.h>
+
+#include "dviRenderer.h"
+#include "fontpool.h"
+#include "kdvi.h"
+#ifdef HAVE_FREETYPE
+#include "TeXFont_PFB.h"
+#endif
+#include "TeXFont_PK.h"
+#include "TeXFont_TFM.h"
+#include "TeXFontDefinition.h"
+#include "xdvi.h"
+
+extern const int MFResolutions[];
+
+#define PK_PRE 247
+#define PK_ID 89
+#define PK_MAGIC (PK_PRE << 8) + PK_ID
+#define GF_PRE 247
+#define GF_ID 131
+#define GF_MAGIC (GF_PRE << 8) + GF_ID
+#define VF_PRE 247
+#define VF_ID_BYTE 202
+#define VF_MAGIC (VF_PRE << 8) + VF_ID_BYTE
+
+// #define DEBUG_FONT
+
+
+TeXFontDefinition::TeXFontDefinition(QString nfontname, double _displayResolution_in_dpi, Q_UINT32 chk, Q_INT32 _scaled_size_in_DVI_units,
+ class fontPool *pool, double _enlargement)
+{
+#ifdef DEBUG_FONT
+ kdDebug(4300) << "TeXFontDefinition::TeXFontDefinition(...); fontname=" << nfontname << ", enlargement=" << _enlargement << endl;
+#endif
+
+ enlargement = _enlargement;
+ font_pool = pool;
+ fontname = nfontname;
+ font = 0;
+ displayResolution_in_dpi = _displayResolution_in_dpi;
+ checksum = chk;
+ flags = TeXFontDefinition::FONT_IN_USE;
+ file = 0;
+ filename = QString::null;
+ scaled_size_in_DVI_units = _scaled_size_in_DVI_units;
+
+ macrotable = 0;
+
+ // By default, this font contains only empty characters. After the
+ // font has been loaded, this function pointer will be replaced by
+ // another one.
+ set_char_p = &dviRenderer::set_empty_char;
+}
+
+
+TeXFontDefinition::~TeXFontDefinition()
+{
+#ifdef DEBUG_FONT
+ kdDebug(4300) << "discarding font " << fontname << " at " << (int)(enlargement * MFResolutions[font_pool->getMetafontMode()] + 0.5) << " dpi" << endl;
+#endif
+
+ if (font != 0) {
+ delete font;
+ font = 0;
+ }
+ if (macrotable != 0) {
+ delete [] macrotable;
+ macrotable = 0;
+ }
+
+ if (flags & FONT_LOADED) {
+ if (file != 0) {
+ fclose(file);
+ file = 0;
+ }
+ if (flags & FONT_VIRTUAL)
+ vf_table.clear();
+ }
+}
+
+
+void TeXFontDefinition::fontNameReceiver(const QString& fname)
+{
+#ifdef DEBUG_FONT
+ kdDebug(4300) << "void TeXFontDefinition::fontNameReceiver( " << fname << " )" << endl;
+#endif
+
+ flags |= TeXFontDefinition::FONT_LOADED;
+ filename = fname;
+#ifdef HAVE_FREETYPE
+ fullFontName = QString::null;
+ fullEncodingName = QString::null;
+#endif
+
+ file = fopen(QFile::encodeName(filename), "r");
+ // Check if the file could be opened. If not, try to find the file
+ // in the DVI file's directory. If that works, modify the filename
+ // accordingly and go on.
+ if (file == 0) {
+ QString filename_test(font_pool->getExtraSearchPath() + "/" + filename);
+ file = fopen( QFile::encodeName(filename_test), "r");
+ if (file == 0) {
+ kdError(4300) << i18n("Cannot find font %1, file %2.").arg(fontname).arg(filename) << endl;
+ return;
+ } else
+ filename = filename_test;
+ }
+
+ set_char_p = &dviRenderer::set_char;
+ int magic = two(file);
+
+ if (fname.endsWith("pk"))
+ if (magic == PK_MAGIC) {
+ fclose(file);
+ file = 0;
+ font = new TeXFont_PK(this);
+ set_char_p = &dviRenderer::set_char;
+ if ((checksum != 0) && (checksum != font->checksum))
+ kdWarning(4300) << i18n("Checksum mismatch for font file %1").arg(filename) << endl;
+ fontTypeName = "TeX PK";
+ return;
+ }
+
+ if (fname.endsWith(".vf"))
+ if (magic == VF_MAGIC) {
+ read_VF_index();
+ set_char_p = &dviRenderer::set_vf_char;
+ fontTypeName = i18n("TeX virtual");
+ return;
+ }
+
+ if (fname.endsWith(".tfm")) {
+ fclose(file);
+ file = 0;
+ font = new TeXFont_TFM(this);
+ set_char_p = &dviRenderer::set_char;
+ fontTypeName = i18n("TeX Font Metric");
+ return;
+ }
+
+ // None of these known types? Then it should be one of the font
+ // formats that are handled by the FreeType library
+ fclose(file);
+ file = 0;
+#ifdef HAVE_FREETYPE
+ // Find the encoding for that font
+ const QString &enc = font_pool->fontsByTeXName.findEncoding(fontname);
+
+ if (enc.isEmpty() == false) {
+#ifdef DEBUG_FONT
+ kdDebug(4300) << "Font " << fontname << " uses encoding " << enc << endl;
+#endif
+ font = new TeXFont_PFB(this, font_pool->encodingPool.findByName(enc), font_pool->fontsByTeXName.findSlant(fontname) );
+ } else {
+#ifdef DEBUG_FONT
+ kdDebug(4300) << "Font " << fontname << " does not have an encoding." << endl;
+#endif
+ font = new TeXFont_PFB(this);
+ }
+
+ set_char_p = &dviRenderer::set_char;
+ fontTypeName = i18n("FreeType");
+ return;
+#else
+ // If we don't have the FreeType library, we should never have
+ // reached this point. Complain, and leave this font blank
+ kdError(4300) << i18n("Cannot recognize format for font file %1").arg(filename) << endl;
+#endif
+}
+
+
+void TeXFontDefinition::reset()
+{
+ if (font != 0) {
+ delete font;
+ font = 0;
+ }
+
+ if (macrotable != 0) {
+ delete [] macrotable;
+ macrotable = 0;
+ }
+
+ if (flags & FONT_LOADED) {
+ if (file != 0) {
+ fclose(file);
+ file = 0;
+ }
+ if (flags & FONT_VIRTUAL)
+ vf_table.clear();
+ }
+
+ filename = QString::null;
+ flags = TeXFontDefinition::FONT_IN_USE;
+ set_char_p = &dviRenderer::set_empty_char;
+}
+
+
+void TeXFontDefinition::setDisplayResolution(double _displayResolution_in_dpi)
+{
+ displayResolution_in_dpi = _displayResolution_in_dpi;
+ if (font != 0)
+ font->setDisplayResolution();
+}
+
+
+/** mark_as_used marks the font, and all the fonts it referrs to, as
+ used, i.e. their FONT_IN_USE-flag is set. */
+
+void TeXFontDefinition::mark_as_used()
+{
+#ifdef DEBUG_FONT
+ kdDebug(4300) << "TeXFontDefinition::mark_as_used()" << endl;
+#endif
+
+ if (flags & TeXFontDefinition::FONT_IN_USE)
+ return;
+
+ flags |= TeXFontDefinition::FONT_IN_USE;
+
+ // For virtual fonts, also go through the list of referred fonts
+ if (flags & TeXFontDefinition::FONT_VIRTUAL) {
+ QIntDictIterator<TeXFontDefinition> it(vf_table);
+ while( it.current() ) {
+ it.current()->mark_as_used();
+ ++it;
+ }
+ }
+}
+
+
+macro::macro()
+{
+ pos = 0; /* address of first byte of macro */
+ end = 0; /* address of last+1 byte */
+ dvi_advance_in_units_of_design_size_by_2e20 = 0; /* DVI units to move reference point */
+ free_me = false;
+}
+
+
+macro::~macro()
+{
+ if ((pos != 0L) && (free_me == true))
+ delete [] pos;
+}
diff --git a/kdvi/TeXFontDefinition.h b/kdvi/TeXFontDefinition.h
new file mode 100644
index 00000000..e3effc2a
--- /dev/null
+++ b/kdvi/TeXFontDefinition.h
@@ -0,0 +1,126 @@
+// -*- C++ -*-
+/*
+ * The layout of a font information block.
+ * There is one of these for every loaded font or magnification thereof.
+ * Duplicates are eliminated: this is necessary because of possible recursion
+ * in virtual fonts.
+ *
+ * Also note the strange units. The design size is in 1/2^20 point
+ * units (also called micro-points), and the individual character widths
+ * are in the TFM file in 1/2^20 ems units, i.e., relative to the design size.
+ *
+ * We then change the sizes to SPELL units (unshrunk pixel / 2^16).
+ */
+
+#ifndef _FONT_H
+#define _FONT_H
+
+#include <qintdict.h>
+#include <qstring.h>
+
+#include <stdio.h>
+
+class dviRenderer;
+class TeXFont;
+
+typedef void (dviRenderer::*set_char_proc)(unsigned int, unsigned int);
+
+
+// Per character information for virtual fonts
+
+class macro {
+ public:
+ macro();
+ ~macro();
+
+ unsigned char *pos; /* address of first byte of macro */
+ unsigned char *end; /* address of last+1 byte */
+ Q_INT32 dvi_advance_in_units_of_design_size_by_2e20; /* DVI units to move reference point */
+ bool free_me; // if memory at pos should be returned on destruction
+};
+
+
+class TeXFontDefinition {
+ public:
+ // Currently, kdvi supports fonts with at most 256 characters to
+ // comply with "The DVI Driver Standard, Level 0". If you change
+ // this value here, make sure to go through all the source and
+ // ensure that character numbers are stored in ints rather than
+ // unsigned chars.
+ static const unsigned int max_num_of_chars_in_font = 256;
+ enum font_flags {
+ FONT_IN_USE = 1, // used for housekeeping
+ FONT_LOADED = 2, // if font file has been read
+ FONT_VIRTUAL = 4, // if font is virtual
+ FONT_KPSE_NAME = 8 // if kpathsea has already tried to find the font name
+ };
+
+
+ TeXFontDefinition(QString nfontname, double _displayResolution_in_dpi, Q_UINT32 chk, Q_INT32 _scaled_size_in_DVI_units,
+ class fontPool *pool, double _enlargement);
+ ~TeXFontDefinition();
+
+ void reset();
+ void fontNameReceiver(const QString&);
+
+ // Members for character fonts
+ void setDisplayResolution(double _displayResolution_in_dpi);
+
+ bool isLocated() const {return ((flags & FONT_KPSE_NAME) != 0);}
+ void markAsLocated() {flags |= FONT_KPSE_NAME;}
+
+ void mark_as_used();
+ class fontPool *font_pool; // Pointer to the pool that contains this font.
+ QString fontname; // name of font, such as "cmr10"
+ unsigned char flags; // flags byte (see values below)
+ double enlargement;
+ Q_INT32 scaled_size_in_DVI_units; // Scaled size from the font definition command; in DVI units
+ set_char_proc set_char_p; // proc used to set char
+
+ // Resolution of the display device (resolution will usually be
+ // scaled, according to the zoom)
+ double displayResolution_in_dpi;
+
+ FILE *file; // open font file or NULL
+ QString filename; // name of font file
+
+ TeXFont *font;
+ macro *macrotable; // used by (loaded) virtual fonts
+ QIntDict<TeXFontDefinition> vf_table; // used by (loaded) virtual fonts, list of fonts used by this vf,
+ // acessible by number
+ TeXFontDefinition *first_font; // used by (loaded) virtual fonts, list of fonts used by this vf
+
+#ifdef HAVE_FREETYPE
+ const QString &getFullFontName() const {return fullFontName;}
+ const QString &getFullEncodingName() const {return fullEncodingName;}
+#endif
+ const QString &getFontTypeName() const {return fontTypeName;}
+
+#ifdef HAVE_FREETYPE
+ /** For FREETYPE fonts, which use a map file, this field will
+ contain the full name of the font (e.g. 'Computer Modern'). If
+ the name does not exist, or cannot be found, this field will be
+ QString::null. Only subclasses of TeXFont should write into this
+ field. */
+ QString fullFontName;
+
+ /** For FREETYPE fonts, which use a map file, this field will
+ contain the full name of the font encoding (e.g. 'TexBase1'). If
+ the encoding name does not exist, or cannot be found, this field
+ will be QString::null. Only subclasses of TeXFont should write
+ into this field. */
+ QString fullEncodingName;
+#endif
+
+ private:
+ Q_UINT32 checksum;
+
+ /** This will be set to a human-readable description of the font,
+ e.g. "virtual" or "TeX PK", or "Type 1" */
+ QString fontTypeName;
+
+ // Functions related to virtual fonts
+ void read_VF_index(void );
+};
+
+#endif
diff --git a/kdvi/TeXFont_PFB.cpp b/kdvi/TeXFont_PFB.cpp
new file mode 100644
index 00000000..927c84bc
--- /dev/null
+++ b/kdvi/TeXFont_PFB.cpp
@@ -0,0 +1,294 @@
+// TeXFont_PFB.cpp
+//
+// Part of KDVI - A DVI previewer for the KDE desktop environemt
+//
+// (C) 2003 Stefan Kebekus
+// Distributed under the GPL
+
+// This file is compiled only if the FreeType library is present on
+// the system
+
+// Add header files alphabetically
+
+#include <config.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <qimage.h>
+
+#include "fontpool.h"
+
+#ifdef HAVE_FREETYPE
+
+#include "glyph.h"
+#include "TeXFont_PFB.h"
+
+//#define DEBUG_PFB 1
+
+
+TeXFont_PFB::TeXFont_PFB(TeXFontDefinition *parent, fontEncoding *enc, double slant)
+ : TeXFont(parent)
+{
+#ifdef DEBUG_PFB
+ if (enc != 0)
+ kdDebug(4300) << "TeXFont_PFB::TeXFont_PFB( parent=" << parent << ", encoding=" << enc->encodingFullName << " )" << endl;
+ else
+ kdDebug(4300) << "TeXFont_PFB::TeXFont_PFB( parent=" << parent << ", encoding=0 )" << endl;
+#endif
+
+ fatalErrorInFontLoading = false;
+
+ int error = FT_New_Face( parent->font_pool->FreeType_library, parent->filename.local8Bit(), 0, &face );
+
+ if ( error == FT_Err_Unknown_File_Format ) {
+ errorMessage = i18n("The font file %1 could be opened and read, but its font format is unsupported.").arg(parent->filename);
+ kdError(4300) << errorMessage << endl;
+ fatalErrorInFontLoading = true;
+ return;
+ } else
+ if ( error ) {
+ errorMessage = i18n("The font file %1 is broken, or it could not be opened or read.").arg(parent->filename);
+ kdError(4300) << errorMessage << endl;
+ fatalErrorInFontLoading = true;
+ return;
+ }
+
+ // Take care of slanting, and transform all characters in the font, if necessary.
+ if (slant != 0.0) {
+ // Construct a transformation matrix for vertical shear which will
+ // be used to transform the characters.
+ transformationMatrix.xx = 0x10000;
+ transformationMatrix.xy = (FT_Fixed)(slant * 0x10000);
+ transformationMatrix.yx = 0;
+ transformationMatrix.yy = 0x10000;
+
+ FT_Set_Transform( face, &transformationMatrix, 0);
+ }
+
+ if (face->family_name != 0)
+ parent->fullFontName = face->family_name;
+
+ // Finally, we need to set up the charMap array, which maps TeX
+ // character codes to glyph indices in the font. (Remark: the
+ // charMap, and the font encoding procedure is necessary, because
+ // TeX is only able to address character codes 0-255 while
+ // e.g. Type1 fonts may contain several thousands of characters)
+ if (enc != 0) {
+ parent->fullEncodingName = enc->encodingFullName.remove(QString::fromLatin1( "Encoding" ));
+ parent->fullEncodingName = enc->encodingFullName.remove(QString::fromLatin1( "encoding" ));
+
+ // An encoding vector is given for this font, i.e. an array of
+ // character names (such as: 'parenleft' or 'dotlessj'). We use
+ // the FreeType library function 'FT_Get_Name_Index()' to
+ // associate glyph indices to those names.
+#ifdef DEBUG_PFB
+ kdDebug(4300) << "Trying to associate glyph indices to names from the encoding vector." << endl;
+#endif
+ for(int i=0; i<256; i++) {
+ charMap[i] = FT_Get_Name_Index( face, (FT_String *)(enc->glyphNameVector[i].ascii()) );
+#ifdef DEBUG_PFB
+ kdDebug(4300) << i << ": " << enc->glyphNameVector[i] << ", GlyphIndex=" << charMap[i] << endl;
+#endif
+ }
+ } else {
+ // If there is no encoding vector available, we check if the font
+ // itself contains a charmap that could be used. An admissible
+ // charMap will be stored under platform_id=7 and encoding_id=2.
+ FT_CharMap found = 0;
+ for (int n = 0; n<face->num_charmaps; n++ ) {
+ FT_CharMap charmap = face->charmaps[n];
+ if ( charmap->platform_id == 7 && charmap->encoding_id == 2 ) {
+ found = charmap;
+ break;
+ }
+ }
+
+ if ((found != 0) && (FT_Set_Charmap( face, found ) == 0)) {
+ // Feed the charMap array with the charmap data found in the
+ // previous step.
+#ifdef DEBUG_PFB
+ kdDebug(4300) << "No encoding given: using charmap platform=7, encoding=2 that is contained in the font." << endl;
+#endif
+ for(int i=0; i<256; i++)
+ charMap[i] = FT_Get_Char_Index( face, i );
+ } else {
+ if ((found == 0) && (face->charmap != 0)) {
+#ifdef DEBUG_PFB
+ kdDebug(4300) << "No encoding given: using charmap platform=" << face->charmap->platform_id <<
+ ", encoding=" << face->charmap->encoding_id << " that is contained in the font." << endl;
+#endif
+ for(int i=0; i<256; i++)
+ charMap[i] = FT_Get_Char_Index( face, i );
+ } else {
+ // As a last resort, we use the identity map.
+#ifdef DEBUG_PFB
+ kdDebug(4300) << "No encoding given, no suitable charmaps found in the font: using identity charmap." << endl;
+#endif
+ for(int i=0; i<256; i++)
+ charMap[i] = i;
+ }
+ }
+ }
+}
+
+
+TeXFont_PFB::~TeXFont_PFB()
+{
+ FT_Done_Face( face );
+}
+
+
+glyph *TeXFont_PFB::getGlyph(Q_UINT16 ch, bool generateCharacterPixmap, const QColor& color)
+{
+#ifdef DEBUG_PFB
+ kdDebug(4300) << "TeXFont_PFB::getGlyph( ch=" << ch << ", '" << (char)(ch) << "', generateCharacterPixmap=" << generateCharacterPixmap << " )" << endl;
+#endif
+
+ // Paranoia checks
+ if (ch >= TeXFontDefinition::max_num_of_chars_in_font) {
+ kdError(4300) << "TeXFont_PFB::getGlyph(): Argument is too big." << endl;
+ return glyphtable;
+ }
+
+ // This is the address of the glyph that will be returned.
+ struct glyph *g = glyphtable+ch;
+
+
+ if (fatalErrorInFontLoading == true)
+ return g;
+
+ if ((generateCharacterPixmap == true) && ((g->shrunkenCharacter.isNull()) || (color != g->color)) ) {
+ int error;
+ unsigned int res = (unsigned int)(parent->displayResolution_in_dpi/parent->enlargement +0.5);
+ g->color = color;
+
+ // Character height in 1/64th of points (reminder: 1 pt = 1/72 inch)
+ // Only approximate, may vary from file to file!!!! @@@@@
+
+ long int characterSize_in_printers_points_by_64 = (long int)((64.0*72.0*parent->scaled_size_in_DVI_units*parent->font_pool->getCMperDVIunit())/2.54 + 0.5 );
+ error = FT_Set_Char_Size(face, 0, characterSize_in_printers_points_by_64, res, res );
+ if (error) {
+ QString msg = i18n("FreeType reported an error when setting the character size for font file %1.").arg(parent->filename);
+ if (errorMessage.isEmpty())
+ errorMessage = msg;
+ kdError(4300) << msg << endl;
+ g->shrunkenCharacter.resize(1,1);
+ g->shrunkenCharacter.fill(QColor(255, 255, 255));
+ return g;
+ }
+
+ // load glyph image into the slot and erase the previous one
+ if (parent->font_pool->getUseFontHints() == true)
+ error = FT_Load_Glyph(face, charMap[ch], FT_LOAD_DEFAULT );
+ else
+ error = FT_Load_Glyph(face, charMap[ch], FT_LOAD_NO_HINTING );
+
+ if (error) {
+ QString msg = i18n("FreeType is unable to load glyph #%1 from font file %2.").arg(ch).arg(parent->filename);
+ if (errorMessage.isEmpty())
+ errorMessage = msg;
+ kdError(4300) << msg << endl;
+ g->shrunkenCharacter.resize(1,1);
+ g->shrunkenCharacter.fill(QColor(255, 255, 255));
+ return g;
+ }
+
+ // convert to an anti-aliased bitmap
+ error = FT_Render_Glyph( face->glyph, ft_render_mode_normal );
+ if (error) {
+ QString msg = i18n("FreeType is unable to render glyph #%1 from font file %2.").arg(ch).arg(parent->filename);
+ if (errorMessage.isEmpty())
+ errorMessage = msg;
+ kdError(4300) << msg << endl;
+ g->shrunkenCharacter.resize(1,1);
+ g->shrunkenCharacter.fill(QColor(255, 255, 255));
+ return g;
+ }
+
+ FT_GlyphSlot slot = face->glyph;
+
+ if ((slot->bitmap.width == 0) || (slot->bitmap.rows == 0)) {
+ if (errorMessage.isEmpty())
+ errorMessage = i18n("Glyph #%1 is empty.").arg(ch);
+ kdError(4300) << i18n("Glyph #%1 from font file %2 is empty.").arg(ch).arg(parent->filename) << endl;
+ g->shrunkenCharacter.resize( 15, 15 );
+ g->shrunkenCharacter.fill(QColor(255, 0, 0));
+ g->x2 = 0;
+ g->y2 = 15;
+ } else {
+ QImage imgi(slot->bitmap.width, slot->bitmap.rows, 32);
+ imgi.setAlphaBuffer(true);
+
+ // Do QPixmaps fully support the alpha channel? If yes, we use
+ // that. Otherwise, use other routines as a fallback
+ if (parent->font_pool->QPixmapSupportsAlpha) {
+ // If the alpha channel is properly supported, we set the
+ // character glyph to a colored rectangle, and define the
+ // character outline only using the alpha channel. That
+ // ensures good quality rendering for overlapping characters.
+ uchar *srcScanLine = slot->bitmap.buffer;
+ for(int row=0; row<slot->bitmap.rows; row++) {
+ uchar *destScanLine = imgi.scanLine(row);
+ for(int col=0; col<slot->bitmap.width; col++) {
+ destScanLine[4*col+0] = color.blue();
+ destScanLine[4*col+1] = color.green();
+ destScanLine[4*col+2] = color.red();
+ destScanLine[4*col+3] = srcScanLine[col];
+ }
+ srcScanLine += slot->bitmap.pitch;
+ }
+ } else {
+ // If the alpha channel is not supported... QT seems to turn
+ // the alpha channel into a crude bitmap which is used to mask
+ // the resulting QPixmap. In this case, we define the
+ // character outline using the image data, and use the alpha
+ // channel only to store "maximally opaque" or "completely
+ // transparent" values. When characters are rendered,
+ // overlapping characters are no longer correctly drawn, but
+ // quality is still sufficient for most purposes. One notable
+ // exception is output from the gftodvi program, which will be
+ // partially unreadable.
+ Q_UINT16 rInv = 0xFF - color.red();
+ Q_UINT16 gInv = 0xFF - color.green();
+ Q_UINT16 bInv = 0xFF - color.blue();
+
+ for(Q_UINT16 y=0; y<slot->bitmap.rows; y++) {
+ Q_UINT8 *srcScanLine = slot->bitmap.buffer + y*slot->bitmap.pitch;
+ unsigned int *destScanLine = (unsigned int *)imgi.scanLine(y);
+ for(Q_UINT16 col=0; col<slot->bitmap.width; col++) {
+ Q_UINT16 data = *srcScanLine;
+ // The value stored in "data" now has the following meaning:
+ // data = 0 -> white; data = 0xff -> use "color"
+ *destScanLine = qRgba(0xFF - (rInv*data + 0x7F) / 0xFF,
+ 0xFF - (gInv*data + 0x7F) / 0xFF,
+ 0xFF - (bInv*data + 0x7F) / 0xFF,
+ (data > 0x03) ? 0xff : 0x00);
+ destScanLine++;
+ srcScanLine++;
+ }
+ }
+ }
+
+ g->shrunkenCharacter.convertFromImage (imgi, 0);
+ g->x2 = -slot->bitmap_left;
+ g->y2 = slot->bitmap_top;
+ }
+ }
+
+ // Load glyph width, if that hasn't been done yet.
+ if (g->dvi_advance_in_units_of_design_size_by_2e20 == 0) {
+ int error = FT_Load_Glyph(face, charMap[ch], FT_LOAD_NO_SCALE);
+ if (error) {
+ QString msg = i18n("FreeType is unable to load metric for glyph #%1 from font file %2.").arg(ch).arg(parent->filename);
+ if (errorMessage.isEmpty())
+ errorMessage = msg;
+ kdError(4300) << msg << endl;
+ g->dvi_advance_in_units_of_design_size_by_2e20 = 1;
+ }
+ g->dvi_advance_in_units_of_design_size_by_2e20 = (Q_INT32)(((Q_INT64)(1<<20) * (Q_INT64)face->glyph->metrics.horiAdvance) / (Q_INT64)face->units_per_EM);
+ }
+
+ return g;
+}
+
+#endif // HAVE_FREETYPE
diff --git a/kdvi/TeXFont_PFB.h b/kdvi/TeXFont_PFB.h
new file mode 100644
index 00000000..68211cdb
--- /dev/null
+++ b/kdvi/TeXFont_PFB.h
@@ -0,0 +1,41 @@
+// -*- C++ -*-
+// TeXFont_PFB.cpp
+//
+// Part of KDVI - A DVI previewer for the KDE desktop environemt
+//
+// (C) 2003 Stefan Kebekus
+// Distributed under the GPL
+
+// This file is compiled only if the FreeType library is present on
+// the system
+
+#ifndef _TEXFONT_PFB_H
+#define _TEXFONT_PFB_H
+
+#include "TeXFont.h"
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+class fontEncoding;
+class glyph;
+
+
+class TeXFont_PFB : public TeXFont {
+ public:
+ TeXFont_PFB(TeXFontDefinition *parent, fontEncoding *enc=0, double slant=0.0 );
+ ~TeXFont_PFB();
+
+ glyph* getGlyph(Q_UINT16 character, bool generateCharacterPixmap=false, const QColor& color=Qt::black);
+
+ private:
+ FT_Face face;
+ bool fatalErrorInFontLoading;
+ Q_UINT16 charMap[256];
+
+ // This matrix is used internally to describes the slant, if
+ // nonzero. Otherwise, this is undefined.
+ FT_Matrix transformationMatrix;
+};
+
+#endif
diff --git a/kdvi/TeXFont_PK.cpp b/kdvi/TeXFont_PK.cpp
new file mode 100644
index 00000000..6a3c9b3a
--- /dev/null
+++ b/kdvi/TeXFont_PK.cpp
@@ -0,0 +1,781 @@
+/*
+ * Copyright (c) 1994 Paul Vojta. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * NOTE:
+ * xdvi is based on prior work as noted in the modification history, below.
+ */
+
+/*
+ * DVI previewer for X.
+ *
+ * Eric Cooper, CMU, September 1985.
+ *
+ * Code derived from dvi-imagen.c.
+ *
+ * Modification history:
+ * 1/1986 Modified for X.10 --Bob Scheifler, MIT LCS.
+ * 7/1988 Modified for X.11 --Mark Eichin, MIT
+ * 12/1988 Added 'R' option, toolkit, magnifying glass
+ * --Paul Vojta, UC Berkeley.
+ * 2/1989 Added tpic support --Jeffrey Lee, U of Toronto
+ * 4/1989 Modified for System V --Donald Richardson, Clarkson Univ.
+ * 3/1990 Added VMS support --Scott Allendorf, U of Iowa
+ * 7/1990 Added reflection mode --Michael Pak, Hebrew U of Jerusalem
+ * 1/1992 Added greyscale code --Till Brychcy, Techn. Univ. Muenchen
+ * and Lee Hetherington, MIT
+ * 4/1994 Added DPS support, bounding box
+ * --Ricardo Telichevesky
+ * and Luis Miguel Silveira, MIT RLE.
+ */
+
+#include <config.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <math.h>
+#include <qbitmap.h>
+#include <qfile.h>
+#include <qimage.h>
+#include <qpainter.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "fontpool.h"
+#include "glyph.h"
+#include "xdvi.h"
+#include "TeXFontDefinition.h"
+#include "TeXFont_PK.h"
+
+
+//#define DEBUG_PK
+
+#define PK_PRE 247
+#define PK_ID 89
+#define PK_MAGIC (PK_PRE << 8) + PK_ID
+
+
+extern void oops(QString message);
+
+
+
+TeXFont_PK::TeXFont_PK(TeXFontDefinition *parent)
+ : TeXFont(parent)
+{
+#ifdef DEBUG_PK
+ kdDebug(4300) << "TeXFont_PK::TeXFont_PK( parent=" << parent << ")" << endl;
+#endif
+
+ for(unsigned int i=0; i<TeXFontDefinition::max_num_of_chars_in_font; i++)
+ characterBitmaps[i] = 0;
+ file = fopen(QFile::encodeName(parent->filename), "r");
+ if (file == 0)
+ kdError(4300) << i18n("Cannot open font file %1.").arg(parent->filename) << endl;
+#ifdef DEBUG_PK
+ else
+ kdDebug(4300) << "TeXFont_PK::TeXFont_PK(): file opened successfully" << endl;
+#endif
+
+ read_PK_index();
+
+#ifdef DEBUG_PK
+ kdDebug(4300) << "TeXFont_PK::TeXFont_PK() ended" << endl;
+#endif
+}
+
+
+TeXFont_PK::~TeXFont_PK()
+{
+ //@@@ Release bitmaps
+
+ if (file != 0) {
+ fclose(file);
+ file = 0;
+ }
+}
+
+
+glyph* TeXFont_PK::getGlyph(Q_UINT16 ch, bool generateCharacterPixmap, const QColor& color)
+{
+#ifdef DEBUG_PK
+ kdDebug(4300) << "TeXFont_PK::getGlyph( ch=" << ch << ", generateCharacterPixmap=" << generateCharacterPixmap << " )" << endl;
+#endif
+
+ // Paranoia checks
+ if (ch >= TeXFontDefinition::max_num_of_chars_in_font) {
+ kdError(4300) << "TeXFont_PK::getGlyph(): Argument is too big." << endl;
+ return glyphtable;
+ }
+
+ // This is the address of the glyph that will be returned.
+ struct glyph *g = glyphtable+ch;
+
+ // Check if the glyph is loaded. If not, load it now.
+ if (characterBitmaps[ch] == 0) {
+ // If the character is not defined in the PK file, mark the
+ // character as missing, and print an error message
+ if (g->addr == 0) {
+ kdError(4300) << i18n("TexFont_PK::operator[]: Character %1 not defined in font %2").arg(ch).arg(parent->filename) << endl;
+ g->addr = -1;
+ return g;
+ }
+
+ // If the character has already been marked as missing, just
+ // return a pointer to the glyph (which will then be empty)
+ if (g->addr == -1)
+ return g;
+
+ // Otherwise, try to load the character
+ fseek(file, g->addr, 0);
+ read_PK_char(ch);
+ // Check if the character could be loaded. If not, mark the
+ // character as 'missing', and return a pointer.
+ if (characterBitmaps[ch]->bits == 0) {
+ g->addr = -1;
+ return g;
+ }
+ }
+
+ // At this point, g points to a properly loaded character. Generate
+ // a smoothly scaled QPixmap if the user asks for it.
+ if ((generateCharacterPixmap == true) &&
+ ((g->shrunkenCharacter.isNull()) || (color != g->color)) &&
+ (characterBitmaps[ch]->w != 0)) {
+ g->color = color;
+ double shrinkFactor = 1200 / parent->displayResolution_in_dpi;
+
+ // All is fine? Then we rescale the bitmap in order to produce the
+ // required pixmap. Rescaling a character, however, is an art
+ // that requires some explanation...
+ //
+ // If we would just divide the size of the character and the
+ // coordinates by the shrink factor, then the result would look
+ // quite ugly: due to the ineviatable rounding errors in the
+ // integer arithmetic, the characters would be displaced by up to
+ // a pixel. That doesn't sound much, but on low-resolution
+ // devices, such as a notebook screen, the effect would be a
+ // "dancing line" of characters, which looks really bad.
+
+ // Calculate the coordinates of the hot point in the shrunken
+ // bitmap. For simplicity, let us consider the x-coordinate
+ // first. In principle, the hot point should have an x-coordinate
+ // of (g->x/shrinkFactor). That, however, will generally NOT be an
+ // integral number. The cure is to translate the source image
+ // somewhat, so that the x-coordinate of the hot point falls onto
+ // the round-up of this number, i.e.
+ g->x2 = (int)ceil(g->x/shrinkFactor);
+
+ // Translating and scaling then means that the pixel in the scaled
+ // image which covers the range [x,x+1) corresponds to the range
+ // [x*shrinkFactor+srcXTrans, (x+1)*shrinkFactor+srcXTrans), where
+ // srcXTrans is the following NEGATIVE number
+ double srcXTrans = shrinkFactor * (g->x/shrinkFactor - ceil(g->x/shrinkFactor));
+
+ // How big will the shrunken bitmap then become? If shrunk_width
+ // denotes that width of the scaled image, and
+ // characterBitmaps[ch]->w the width of the orininal image, we
+ // need to make sure that the following inequality holds:
+ //
+ // shrunk_width*shrinkFactor+srcXTrans >= characterBitmaps[ch]->w
+ //
+ // in other words,
+ int shrunk_width = (int)ceil( (characterBitmaps[ch]->w - srcXTrans)/shrinkFactor );
+
+ // Now do the same for the y-coordinate
+ g->y2 = (int)ceil(g->y/shrinkFactor);
+ double srcYTrans = shrinkFactor * (g->y/shrinkFactor - ceil(g->y/shrinkFactor ));
+ int shrunk_height = (int)ceil( (characterBitmaps[ch]->h - srcYTrans)/shrinkFactor );
+
+ // Turn the image into 8 bit
+ QByteArray translated(characterBitmaps[ch]->w * characterBitmaps[ch]->h);
+ Q_UINT8 *data = (Q_UINT8 *)translated.data();
+ for(int x=0; x<characterBitmaps[ch]->w; x++)
+ for(int y=0; y<characterBitmaps[ch]->h; y++) {
+ Q_UINT8 bit = *(characterBitmaps[ch]->bits + characterBitmaps[ch]->bytes_wide*y + (x >> 3));
+ bit = bit >> (x & 7);
+ bit = bit & 1;
+ data[characterBitmaps[ch]->w*y + x] = bit;
+ }
+
+ // Now shrink the image. We shrink the X-direction first
+ QByteArray xshrunk(shrunk_width*characterBitmaps[ch]->h);
+ Q_UINT8 *xdata = (Q_UINT8 *)xshrunk.data();
+
+ // Do the shrinking. The pixel (x,y) that we want to calculate
+ // corresponds to the line segment from
+ //
+ // [shrinkFactor*x+srcXTrans, shrinkFactor*(x+1)+srcXTrans)
+ //
+ // The trouble is, these numbers are in general no integers.
+
+ for(int y=0; y<characterBitmaps[ch]->h; y++)
+ for(int x=0; x<shrunk_width; x++) {
+ Q_UINT32 value = 0;
+ double destStartX = shrinkFactor*x+srcXTrans;
+ double destEndX = shrinkFactor*(x+1)+srcXTrans;
+ for(int srcX=(int)ceil(destStartX); srcX<floor(destEndX); srcX++)
+ if ((srcX >= 0) && (srcX < characterBitmaps[ch]->w))
+ value += data[characterBitmaps[ch]->w*y + srcX] * 255;
+
+ if (destStartX >= 0.0)
+ value += (Q_UINT32) (255.0*(ceil(destStartX)-destStartX) * data[characterBitmaps[ch]->w*y + (int)floor(destStartX)]);
+ if (floor(destEndX) < characterBitmaps[ch]->w)
+ value += (Q_UINT32) (255.0*(destEndX-floor(destEndX)) * data[characterBitmaps[ch]->w*y + (int)floor(destEndX)]);
+
+ xdata[shrunk_width*y + x] = (int)(value/shrinkFactor + 0.5);
+ }
+
+ // Now shrink the Y-direction
+ QByteArray xyshrunk(shrunk_width*shrunk_height);
+ Q_UINT8 *xydata = (Q_UINT8 *)xyshrunk.data();
+ for(int x=0; x<shrunk_width; x++)
+ for(int y=0; y<shrunk_height; y++) {
+ Q_UINT32 value = 0;
+ double destStartY = shrinkFactor*y+srcYTrans;
+ double destEndY = shrinkFactor*(y+1)+srcYTrans;
+ for(int srcY=(int)ceil(destStartY); srcY<floor(destEndY); srcY++)
+ if ((srcY >= 0) && (srcY < characterBitmaps[ch]->h))
+ value += xdata[shrunk_width*srcY + x];
+
+ if (destStartY >= 0.0)
+ value += (Q_UINT32) ((ceil(destStartY)-destStartY) * xdata[shrunk_width*(int)floor(destStartY) + x]);
+ if (floor(destEndY) < characterBitmaps[ch]->h)
+ value += (Q_UINT32) ((destEndY-floor(destEndY)) * xdata[shrunk_width*(int)floor(destEndY) + x]);
+
+ xydata[shrunk_width*y + x] = (int)(value/shrinkFactor);
+ }
+
+ QImage im32(shrunk_width, shrunk_height, 32);
+ im32.setAlphaBuffer(true);
+ // Do QPixmaps fully support the alpha channel? If yes, we use
+ // that. Otherwise, use other routines as a fallback
+ if (parent->font_pool->QPixmapSupportsAlpha) {
+ // If the alpha channel is properly supported, we set the
+ // character glyph to a colored rectangle, and define the
+ // character outline only using the alpha channel. That ensures
+ // good quality rendering for overlapping characters.
+ im32.fill(qRgb(color.red(), color.green(), color.blue()));
+ for(Q_UINT16 y=0; y<shrunk_height; y++) {
+ Q_UINT8 *destScanLine = (Q_UINT8 *)im32.scanLine(y);
+ for(Q_UINT16 col=0; col<shrunk_width; col++)
+ destScanLine[4*col+3] = xydata[shrunk_width*y + col];
+ }
+ } else {
+ // If the alpha channel is not supported... QT seems to turn the
+ // alpha channel into a crude bitmap which is used to mask the
+ // resulting QPixmap. In this case, we define the character
+ // outline using the image data, and use the alpha channel only
+ // to store "maximally opaque" or "completely transparent"
+ // values. When characters are rendered, overlapping characters
+ // are no longer correctly drawn, but quality is still
+ // sufficient for most purposes. One notable exception is output
+ // from the gftodvi program, which will be partially unreadable.
+ Q_UINT16 rInv = 0xFF - color.red();
+ Q_UINT16 gInv = 0xFF - color.green();
+ Q_UINT16 bInv = 0xFF - color.blue();
+
+ Q_UINT8 *srcScanLine = xydata;
+ for(Q_UINT16 y=0; y<shrunk_height; y++) {
+ unsigned int *destScanLine = (unsigned int *)im32.scanLine(y);
+ for(Q_UINT16 col=0; col<shrunk_width; col++) {
+ Q_UINT16 data = *srcScanLine;
+ // The value stored in "data" now has the following meaning:
+ // data = 0 -> white; data = 0xff -> use "color"
+ *destScanLine = qRgba(0xFF - (rInv*data + 0x7F) / 0xFF,
+ 0xFF - (gInv*data + 0x7F) / 0xFF,
+ 0xFF - (bInv*data + 0x7F) / 0xFF,
+ (data > 0x03) ? 0xff : 0x00);
+ destScanLine++;
+ srcScanLine++;
+ }
+ }
+ }
+
+ g->shrunkenCharacter.convertFromImage(im32,0);
+ g->shrunkenCharacter.setOptimization(QPixmap::BestOptim);
+ }
+ return g;
+}
+
+
+
+#define ADD(a, b) ((Q_UINT32 *) (((char *) a) + b))
+#define SUB(a, b) ((Q_UINT32 *) (((char *) a) - b))
+
+
+
+// This table is used for changing the bit order in a byte. The
+// expression bitflp[byte] takes a byte in big endian and gives the
+// little endian equivalent of that.
+static const uchar bitflip[256] = {
+ 0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240,
+ 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248,
+ 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244,
+ 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252,
+ 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242,
+ 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250,
+ 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246,
+ 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254,
+ 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241,
+ 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249,
+ 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245,
+ 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253,
+ 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243,
+ 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251,
+ 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247,
+ 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255
+};
+
+static Q_UINT32 bit_masks[33] = {
+ 0x0, 0x1, 0x3, 0x7,
+ 0xf, 0x1f, 0x3f, 0x7f,
+ 0xff, 0x1ff, 0x3ff, 0x7ff,
+ 0xfff, 0x1fff, 0x3fff, 0x7fff,
+ 0xffff, 0x1ffff, 0x3ffff, 0x7ffff,
+ 0xfffff, 0x1fffff, 0x3fffff, 0x7fffff,
+ 0xffffff, 0x1ffffff, 0x3ffffff, 0x7ffffff,
+ 0xfffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
+ 0xffffffff
+};
+
+
+#define PK_ID 89
+#define PK_CMD_START 240
+#define PK_X1 240
+#define PK_X2 241
+#define PK_X3 242
+#define PK_X4 243
+#define PK_Y 244
+#define PK_POST 245
+#define PK_NOOP 246
+#define PK_PRE 247
+
+
+int TeXFont_PK::PK_get_nyb(FILE *fp)
+{
+#ifdef DEBUG_PK
+ kdDebug(4300) << "PK_get_nyb" << endl;
+#endif
+
+ unsigned temp;
+ if (PK_bitpos < 0) {
+ PK_input_byte = one(fp);
+ PK_bitpos = 4;
+ }
+ temp = PK_input_byte >> PK_bitpos;
+ PK_bitpos -= 4;
+ return (temp & 0xf);
+}
+
+
+int TeXFont_PK::PK_packed_num(FILE *fp)
+{
+#ifdef DEBUG_PK
+ kdDebug(4300) << "PK_packed_num" << endl;
+#endif
+
+ int i,j;
+
+ if ((i = PK_get_nyb(fp)) == 0) {
+ do {
+ j = PK_get_nyb(fp);
+ ++i;
+ }
+ while (j == 0);
+ while (i > 0) {
+ j = (j << 4) | PK_get_nyb(fp);
+ --i;
+ }
+ return (j - 15 + ((13 - PK_dyn_f) << 4) + PK_dyn_f);
+ }
+ else {
+ if (i <= PK_dyn_f) return i;
+ if (i < 14)
+ return (((i - PK_dyn_f - 1) << 4) + PK_get_nyb(fp)
+ + PK_dyn_f + 1);
+ if (i == 14) PK_repeat_count = PK_packed_num(fp);
+ else PK_repeat_count = 1;
+ return PK_packed_num(fp);
+ }
+}
+
+
+void TeXFont_PK::PK_skip_specials()
+{
+#ifdef DEBUG_PK
+ kdDebug(4300) << "TeXFont_PK::PK_skip_specials() called" << endl;
+#endif
+
+ int i,j;
+ register FILE *fp = file;
+
+#ifdef DEBUG_PK
+ if (fp == 0)
+ kdDebug(4300) << "TeXFont_PK::PK_skip_specials(): file == 0" << endl;
+#endif
+
+ do {
+ PK_flag_byte = one(fp);
+ if (PK_flag_byte >= PK_CMD_START) {
+ switch (PK_flag_byte) {
+ case PK_X1 :
+ case PK_X2 :
+ case PK_X3 :
+ case PK_X4 :
+ i = 0;
+ for (j = PK_CMD_START; j <= PK_flag_byte; ++j)
+ i = (i << 8) | one(fp);
+ while (i--) (void) one(fp);
+ break;
+ case PK_Y :
+ (void) four(fp);
+ case PK_POST :
+ case PK_NOOP :
+ break;
+ default :
+ oops(i18n("Unexpected %1 in PK file %2").arg(PK_flag_byte).arg(parent->filename) );
+ break;
+ }
+ }
+ }
+ while (PK_flag_byte != PK_POST && PK_flag_byte >= PK_CMD_START);
+
+#ifdef DEBUG_PK
+ kdDebug(4300) << "TeXFont_PK::PK_skip_specials() ended" << endl;
+#endif
+}
+
+
+void TeXFont_PK::read_PK_char(unsigned int ch)
+{
+#ifdef DEBUG_PK
+ kdDebug(4300) << "read_PK_char" << endl;
+#endif
+
+ int i, j;
+ int n;
+ int row_bit_pos;
+ bool paint_switch;
+ Q_UINT32 *cp;
+ register struct glyph *g;
+ register FILE *fp = file;
+ long fpwidth;
+ Q_UINT32 word = 0;
+ int word_weight, bytes_wide;
+ int rows_left, h_bit, count;
+
+ g = glyphtable + ch;
+ PK_flag_byte = g->x2;
+ PK_dyn_f = PK_flag_byte >> 4;
+ paint_switch = ((PK_flag_byte & 8) != 0);
+ PK_flag_byte &= 0x7;
+ if (PK_flag_byte == 7)
+ n = 4;
+ else
+ if (PK_flag_byte > 3)
+ n = 2;
+ else
+ n = 1;
+
+#ifdef DEBUG_PK
+ kdDebug(4300) << "loading pk char " << ch << ", char type " << n << endl;
+#endif
+
+ if (characterBitmaps[ch] == 0)
+ characterBitmaps[ch] = new bitmap();
+
+ /*
+ * now read rest of character preamble
+ */
+ if (n != 4)
+ fpwidth = num(fp, 3);
+ else {
+ fpwidth = sfour(fp);
+ (void) four(fp); /* horizontal escapement */
+ }
+ (void) num(fp, n); /* vertical escapement */
+ {
+ unsigned long w, h;
+
+ w = num(fp, n);
+ h = num(fp, n);
+ if (w > 0x7fff || h > 0x7fff)
+ oops(i18n("The character %1 is too large in file %2").arg(ch).arg(parent->filename));
+ characterBitmaps[ch]->w = w;
+ characterBitmaps[ch]->h = h;
+ }
+ g->x = snum(fp, n);
+ g->y = snum(fp, n);
+
+ g->dvi_advance_in_units_of_design_size_by_2e20 = fpwidth;
+
+ {
+ /* width must be multiple of 16 bits for raster_op */
+ characterBitmaps[ch]->bytes_wide = ROUNDUP((int) characterBitmaps[ch]->w, 32) * 4;
+ register unsigned int size = characterBitmaps[ch]->bytes_wide * characterBitmaps[ch]->h;
+ characterBitmaps[ch]->bits = new char[size != 0 ? size : 1];
+ }
+
+ cp = (Q_UINT32 *) characterBitmaps[ch]->bits;
+
+ /*
+ * read character data into *cp
+ */
+ bytes_wide = ROUNDUP((int) characterBitmaps[ch]->w, 32) * 4;
+ PK_bitpos = -1;
+
+ // The routines which read the character depend on the bit
+ // ordering. In principle, the bit order should be detected at
+ // compile time and the proper routing chosen. For the moment, as
+ // autoconf is somewhat complicated for the author, we prefer a
+ // simpler -even if somewhat slower approach and detect the ordering
+ // at runtime. That should of course be changed in the future.
+
+ int wordSize;
+ bool bigEndian;
+ qSysInfo (&wordSize, &bigEndian);
+
+ if (bigEndian) {
+ // Routine for big Endian machines. Applies e.g. to Motorola and
+ // (Ultra-)Sparc processors.
+
+#ifdef DEBUG_PK
+ kdDebug(4300) << "big Endian byte ordering" << endl;
+#endif
+
+ if (PK_dyn_f == 14) { /* get raster by bits */
+ memset(characterBitmaps[ch]->bits, 0, (int) characterBitmaps[ch]->h * bytes_wide);
+ for (i = 0; i < (int) characterBitmaps[ch]->h; i++) { /* get all rows */
+ cp = ADD(characterBitmaps[ch]->bits, i * bytes_wide);
+ row_bit_pos = 32;
+ for (j = 0; j < (int) characterBitmaps[ch]->w; j++) { /* get one row */
+ if (--PK_bitpos < 0) {
+ word = one(fp);
+ PK_bitpos = 7;
+ }
+ if (--row_bit_pos < 0) {
+ cp++;
+ row_bit_pos = 32 - 1;
+ }
+ if (word & (1 << PK_bitpos))
+ *cp |= 1 << row_bit_pos;
+ }
+ }
+ } else { /* get packed raster */
+ rows_left = characterBitmaps[ch]->h;
+ h_bit = characterBitmaps[ch]->w;
+ PK_repeat_count = 0;
+ word_weight = 32;
+ word = 0;
+ while (rows_left > 0) {
+ count = PK_packed_num(fp);
+ while (count > 0) {
+ if (count < word_weight && count < h_bit) {
+ h_bit -= count;
+ word_weight -= count;
+ if (paint_switch)
+ word |= bit_masks[count] << word_weight;
+ count = 0;
+ } else
+ if (count >= h_bit && h_bit <= word_weight) {
+ if (paint_switch)
+ word |= bit_masks[h_bit] << (word_weight - h_bit);
+ *cp++ = word;
+ /* "output" row(s) */
+ for (i = PK_repeat_count * bytes_wide / 4; i > 0; --i) {
+ *cp = *SUB(cp, bytes_wide);
+ ++cp;
+ }
+ rows_left -= PK_repeat_count + 1;
+ PK_repeat_count = 0;
+ word = 0;
+ word_weight = 32;
+ count -= h_bit;
+ h_bit = characterBitmaps[ch]->w;
+ } else {
+ if (paint_switch)
+ word |= bit_masks[word_weight];
+ *cp++ = word;
+ word = 0;
+ count -= word_weight;
+ h_bit -= word_weight;
+ word_weight = 32;
+ }
+ }
+ paint_switch = 1 - paint_switch;
+ }
+ if (cp != ((Q_UINT32 *) (characterBitmaps[ch]->bits + bytes_wide * characterBitmaps[ch]->h)))
+ oops(i18n("Wrong number of bits stored: char. %1, font %2").arg(ch).arg(parent->filename));
+ if (rows_left != 0 || h_bit != characterBitmaps[ch]->w)
+ oops(i18n("Bad pk file (%1), too many bits").arg(parent->filename));
+ }
+
+ // The data in the bitmap is now in the processor's bit order,
+ // that is, big endian. Since XWindows needs little endian, we
+ // need to change the bit order now.
+ register unsigned char* bitmapData = (unsigned char*) characterBitmaps[ch]->bits;
+ register unsigned char* endOfData = bitmapData + characterBitmaps[ch]->bytes_wide*characterBitmaps[ch]->h;
+ while(bitmapData < endOfData) {
+ *bitmapData = bitflip[*bitmapData];
+ bitmapData++;
+ }
+
+ } else {
+
+ // Routines for small Endian start here. This applies e.g. to
+ // Intel and Alpha processors.
+
+#ifdef DEBUG_PK
+ kdDebug(4300) << "small Endian byte ordering" << endl;
+#endif
+
+ if (PK_dyn_f == 14) { /* get raster by bits */
+ memset(characterBitmaps[ch]->bits, 0, (int) characterBitmaps[ch]->h * bytes_wide);
+ for (i = 0; i < (int) characterBitmaps[ch]->h; i++) { /* get all rows */
+ cp = ADD(characterBitmaps[ch]->bits, i * bytes_wide);
+ row_bit_pos = -1;
+ for (j = 0; j < (int) characterBitmaps[ch]->w; j++) { /* get one row */
+ if (--PK_bitpos < 0) {
+ word = one(fp);
+ PK_bitpos = 7;
+ }
+ if (++row_bit_pos >= 32) {
+ cp++;
+ row_bit_pos = 0;
+ }
+ if (word & (1 << PK_bitpos))
+ *cp |= 1 << row_bit_pos;
+ }
+ }
+ } else { /* get packed raster */
+ rows_left = characterBitmaps[ch]->h;
+ h_bit = characterBitmaps[ch]->w;
+ PK_repeat_count = 0;
+ word_weight = 32;
+ word = 0;
+ while (rows_left > 0) {
+ count = PK_packed_num(fp);
+ while (count > 0) {
+ if (count < word_weight && count < h_bit) {
+ if (paint_switch)
+ word |= bit_masks[count] << (32 - word_weight);
+ h_bit -= count;
+ word_weight -= count;
+ count = 0;
+ } else
+ if (count >= h_bit && h_bit <= word_weight) {
+ if (paint_switch)
+ word |= bit_masks[h_bit] << (32 - word_weight);
+ *cp++ = word;
+ /* "output" row(s) */
+ for (i = PK_repeat_count * bytes_wide / 4; i > 0; --i) {
+ *cp = *SUB(cp, bytes_wide);
+ ++cp;
+ }
+ rows_left -= PK_repeat_count + 1;
+ PK_repeat_count = 0;
+ word = 0;
+ word_weight = 32;
+ count -= h_bit;
+ h_bit = characterBitmaps[ch]->w;
+ } else {
+ if (paint_switch)
+ word |= bit_masks[word_weight] << (32 - word_weight);
+ *cp++ = word;
+ word = 0;
+ count -= word_weight;
+ h_bit -= word_weight;
+ word_weight = 32;
+ }
+ }
+ paint_switch = 1 - paint_switch;
+ }
+ if (cp != ((Q_UINT32 *) (characterBitmaps[ch]->bits + bytes_wide * characterBitmaps[ch]->h)))
+ oops(i18n("Wrong number of bits stored: char. %1, font %2").arg(ch).arg(parent->filename));
+ if (rows_left != 0 || h_bit != characterBitmaps[ch]->w)
+ oops(i18n("Bad pk file (%1), too many bits").arg(parent->filename));
+ }
+ } // endif: big or small Endian?
+}
+
+
+void TeXFont_PK::read_PK_index()
+{
+#ifdef DEBUG_PK
+ kdDebug(4300) << "TeXFont_PK::read_PK_index() called" << endl;
+#endif
+
+ if (file == 0) {
+ kdError(4300) << "TeXFont_PK::read_PK_index(): file == 0" << endl;
+ return;
+ }
+
+ int magic = two(file);
+ if (magic != PK_MAGIC) {
+ kdError(4300) << "TeXFont_PK::read_PK_index(): file is not a PK file" << endl;
+ return;
+ }
+
+ fseek(file, (long) one(file), SEEK_CUR); /* skip comment */
+ (void) four(file); /* skip design size */
+
+ checksum = four(file);
+
+ int hppp = sfour(file);
+ int vppp = sfour(file);
+ if (hppp != vppp)
+ kdWarning(4300) << i18n("Font has non-square aspect ratio ") << vppp << ":" << hppp << endl;
+
+ // Read glyph directory (really a whole pass over the file).
+ for (;;) {
+ int bytes_left, flag_low_bits;
+ unsigned int ch;
+
+ PK_skip_specials();
+ if (PK_flag_byte == PK_POST)
+ break;
+ flag_low_bits = PK_flag_byte & 0x7;
+ if (flag_low_bits == 7) {
+ bytes_left = four(file);
+ ch = four(file);
+ } else
+ if (flag_low_bits > 3) {
+ bytes_left = ((flag_low_bits - 4) << 16) + two(file);
+ ch = one(file);
+ } else {
+ bytes_left = (flag_low_bits << 8) + one(file);
+ ch = one(file);
+ }
+
+ glyphtable[ch].addr = ftell(file);
+ glyphtable[ch].x2 = PK_flag_byte;
+ fseek(file, (long) bytes_left, SEEK_CUR);
+#ifdef DEBUG_PK
+ kdDebug(4300) << "Scanning pk char " << ch << "at " << glyphtable[ch].addr << endl;
+#endif
+ }
+#ifdef DEBUG_PK
+ kdDebug(4300) << "TeXFont_PK::read_PK_index() called" << endl;
+#endif
+}
diff --git a/kdvi/TeXFont_PK.h b/kdvi/TeXFont_PK.h
new file mode 100644
index 00000000..b555934e
--- /dev/null
+++ b/kdvi/TeXFont_PK.h
@@ -0,0 +1,38 @@
+// -*- C++ -*-
+
+#ifndef _TEXFONT_PK_H
+#define _TEXFONT_PK_H
+
+#include "TeXFont.h"
+
+class glyph;
+
+class TeXFont_PK : public TeXFont {
+ public:
+ TeXFont_PK(TeXFontDefinition *parent);
+ ~TeXFont_PK();
+
+ glyph* getGlyph(Q_UINT16 character, bool generateCharacterPixmap=false, const QColor& color=Qt::black);
+
+ private:
+ FILE *file; // open font file or NULL
+ class bitmap *characterBitmaps[TeXFontDefinition::max_num_of_chars_in_font];
+
+ // For use by PK-decryption routines. I don't understand what these
+ // are good for -- Stefan Kebekus
+ int PK_flag_byte;
+ unsigned PK_input_byte;
+ int PK_bitpos;
+ int PK_dyn_f;
+ int PK_repeat_count;
+
+ // PK-internal routines which were taken from xdvi. Again, I do not
+ // really know what they are good for -- Stefan Kebekus
+ inline void read_PK_char(unsigned int ch);
+ inline int PK_get_nyb(FILE *fp);
+ inline int PK_packed_num(FILE *fp);
+ inline void read_PK_index();
+ inline void PK_skip_specials();
+};
+
+#endif
diff --git a/kdvi/TeXFont_TFM.cpp b/kdvi/TeXFont_TFM.cpp
new file mode 100644
index 00000000..54edd2fc
--- /dev/null
+++ b/kdvi/TeXFont_TFM.cpp
@@ -0,0 +1,163 @@
+// TeXFont_TFM.cpp
+//
+// Part of KDVI - A DVI previewer for the KDE desktop environemt
+//
+// (C) 2003 Stefan Kebekus
+// Distributed under the GPL
+
+// Add header files alphabetically
+
+#include <config.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <qdatastream.h>
+#include <qfile.h>
+
+#include "glyph.h"
+#include "TeXFont_TFM.h"
+#include "TeXFontDefinition.h"
+
+//#define DEBUG_TFM
+
+
+TeXFont_TFM::TeXFont_TFM(TeXFontDefinition *parent)
+ : TeXFont(parent)
+{
+#ifdef DEBUG_TFM
+ kdDebug(4300) << "TeXFont_TFM::TeXFont_TFM( parent=" << parent << " )" << endl;
+#endif
+
+ QFile file( parent->filename );
+ if ( !file.open( IO_ReadOnly ) ) {
+ kdError(4300) << "TeXFont_TFM::TeXFont_TFM(): Could not read TFM file" << endl;
+ return;
+ }
+ QDataStream stream( &file );
+
+ // Data from the very beginning of the TFM file, as specified in
+ // "The DVI Driver Standard, Level 0", section D.2.1
+ Q_UINT16 lf, lh, bc, ec, nw, nh, nd;
+ stream >> lf >> lh >> bc >> ec >> nw >> nh >> nd;
+#ifdef DEBUG_TFM
+ kdDebug(4300) << "lf= " << lf << endl
+ << "lh= " << lh << endl
+ << "bc= " << bc << endl
+ << "ec= " << ec << endl
+ << "nw= " << nw << endl
+ << "nh= " << nh << endl
+ << "nd= " << nd << endl;
+#endif
+ if ((bc > ec) || (ec >= TeXFontDefinition::max_num_of_chars_in_font)) {
+ kdError(4300) << "TeXFont_TFM::TeXFont_TFM( filename=" << parent->filename << " ): The font has an invalid bc and ec entries." << endl;
+ file.close();
+ return;
+ }
+
+ // Data from the HEADER section of the TFM data.
+ file.at(24);
+ stream >> checksum >> design_size_in_TeX_points.value;
+#ifdef DEBUG_TFM
+ kdDebug(4300) << "checksum = " << checksum << endl
+ << "design_size = " << design_size_in_TeX_points.toDouble() << " TeX Points" << endl
+ << " = " << design_size_in_TeX_points.toDouble()*254.0/7227.0 << " cm" << endl;
+#endif
+
+ // Width table
+ fix_word widthTable_in_units_of_design_size[TeXFontDefinition::max_num_of_chars_in_font];
+ for(unsigned int i=0; i<TeXFontDefinition::max_num_of_chars_in_font; i++)
+ widthTable_in_units_of_design_size[i].value = 0;
+
+ file.at( 24 + 4*lh + 4*(ec-bc) );
+ for(unsigned int i=0; i<nw; i++) {
+
+ stream >> widthTable_in_units_of_design_size[i].value;
+ // Some characters, which are used as parts of glyphs, have width
+ // 0 --the real width is caculated in a lig_kern program and
+ // depends on the preceding character. We cannot calculate the
+ // real width here and take 0.4 times the design size as an
+ // approximation.
+ if (widthTable_in_units_of_design_size[i].value == 0)
+ widthTable_in_units_of_design_size[i].fromDouble(0.4);
+ }
+
+ // Height table
+ fix_word heightTable_in_units_of_design_size[16];
+ for(unsigned int i=0; i<16; i++)
+ heightTable_in_units_of_design_size[i].value = 0;
+ for(unsigned int i=0; i<nh; i++) {
+ stream >> heightTable_in_units_of_design_size[i].value;
+ }
+
+ // Char-Info table
+ file.at( 24 + 4*lh );
+ for(unsigned int characterCode=bc; characterCode<ec; characterCode++) {
+ glyph *g = glyphtable+characterCode;
+
+ Q_UINT8 byte;
+ stream >> byte;
+ if (byte >= nw)
+ kdError(4300) << "TeXFont_TFM::TeXFont_TFM( filename=" << parent->filename << " ): The font has an invalid Char-Info table." << endl;
+ else {
+ characterWidth_in_units_of_design_size[characterCode] = widthTable_in_units_of_design_size[byte];
+ g->dvi_advance_in_units_of_design_size_by_2e20 = widthTable_in_units_of_design_size[byte].value;
+ }
+
+ stream >> byte;
+ byte = byte >> 4;
+ if (byte >= nh)
+ kdError(4300) << "TeXFont_TFM::TeXFont_TFM( filename=" << parent->filename << " ): The font has an invalid Char-Info table." << endl;
+ else
+ characterHeight_in_units_of_design_size[characterCode] = heightTable_in_units_of_design_size[byte];
+
+ stream >> byte;
+ stream >> byte;
+ }
+ file.close();
+}
+
+
+TeXFont_TFM::~TeXFont_TFM()
+{
+}
+
+
+glyph *TeXFont_TFM::getGlyph(Q_UINT16 characterCode, bool generateCharacterPixmap, const QColor& color)
+{
+#ifdef DEBUG_TFM
+ kdDebug(4300) << "TeXFont_TFM::getGlyph( ch=" << ch << ", generateCharacterPixmap=" << generateCharacterPixmap << " )" << endl;
+#endif
+
+ // Paranoia checks
+ if (characterCode >= TeXFontDefinition::max_num_of_chars_in_font) {
+ kdError(4300) << "TeXFont_TFM::getGlyph(): Argument is too big." << endl;
+ return glyphtable;
+ }
+
+ // This is the address of the glyph that will be returned.
+ struct glyph *g = glyphtable+characterCode;
+
+ if ((generateCharacterPixmap == true) && ((g->shrunkenCharacter.isNull()) || (color != g->color)) ) {
+ g->color = color;
+ Q_UINT16 pixelWidth = (Q_UINT16)(parent->displayResolution_in_dpi *
+ design_size_in_TeX_points.toDouble() *
+ characterWidth_in_units_of_design_size[characterCode].toDouble() * 100.0/7227.0 + 0.5);
+ Q_UINT16 pixelHeight = (Q_UINT16)(parent->displayResolution_in_dpi *
+ design_size_in_TeX_points.toDouble() *
+ characterHeight_in_units_of_design_size[characterCode].toDouble() * 100.0/7227.0 + 0.5);
+
+ // Just make sure that weired TFM files never lead to giant
+ // pixmaps that eat all system memory...
+ if (pixelWidth > 50)
+ pixelWidth = 50;
+ if (pixelHeight > 50)
+ pixelHeight = 50;
+
+ g->shrunkenCharacter.resize( pixelWidth, pixelHeight );
+ g->shrunkenCharacter.fill(color);
+ g->x2 = 0;
+ g->y2 = pixelHeight;
+ }
+
+ return g;
+}
diff --git a/kdvi/TeXFont_TFM.h b/kdvi/TeXFont_TFM.h
new file mode 100644
index 00000000..e68ba872
--- /dev/null
+++ b/kdvi/TeXFont_TFM.h
@@ -0,0 +1,38 @@
+// -*- C++ -*-
+// TeXFont_TFM.h
+//
+// Part of KDVI - A DVI previewer for the KDE desktop environemt
+//
+// (C) 2003 Stefan Kebekus
+// Distributed under the GPL
+
+#ifndef _TEXFONT_TFM_H
+#define _TEXFONT_TFM_H
+
+#include "TeXFont.h"
+
+
+class fix_word {
+ public:
+ void fromINT32(Q_INT32 val) {value = val;}
+ void fromDouble(double val) {value = (Q_INT32)(val * (1<<20) + 0.5);}
+ double toDouble() {return (double(value)) / (double(1<<20));}
+
+ Q_INT32 value;
+};
+
+class TeXFont_TFM : public TeXFont {
+ public:
+ TeXFont_TFM(TeXFontDefinition *parent);
+ ~TeXFont_TFM();
+
+ glyph* getGlyph(Q_UINT16 character, bool generateCharacterPixmap=false, const QColor& color=Qt::black);
+
+ private:
+ fix_word characterWidth_in_units_of_design_size[256];
+ fix_word characterHeight_in_units_of_design_size[256];
+
+ fix_word design_size_in_TeX_points;
+};
+
+#endif
diff --git a/kdvi/bigEndianByteReader.cpp b/kdvi/bigEndianByteReader.cpp
new file mode 100644
index 00000000..63d11f83
--- /dev/null
+++ b/kdvi/bigEndianByteReader.cpp
@@ -0,0 +1,111 @@
+// bigEndianByteReader.cpp
+//
+// Part of KDVI - A DVI previewer for the KDE desktop environemt
+//
+// (C) 2003 Stefan Kebekus
+// Distributed under the GPL
+
+#include <config.h>
+
+#include <kdebug.h>
+
+#include "bigEndianByteReader.h"
+#include "dvi.h"
+
+//#define DEBUG_ENDIANREADER
+
+Q_UINT8 bigEndianByteReader::readUINT8()
+{
+ // This check saveguards us against segmentation fault. It is also
+ // necessary for virtual fonts, which do not end whith EOP.
+ if (command_pointer >= end_pointer) {
+#ifdef DEBUG_ENDIANREADER
+ kdError(4300) << "bigEndianByteReader::readUINT8() tried to read past end of data chunk" << endl;
+ kdError(4300) << "end_pointer = " << end_pointer << endl;
+ kdError(4300) << "command_pointer = " << command_pointer << endl;
+#endif
+ return EOP;
+ }
+
+ return *(command_pointer++);
+}
+
+Q_UINT16 bigEndianByteReader::readUINT16()
+{
+ // This check saveguards us against segmentation fault. It is also
+ // necessary for virtual fonts, which do not end whith EOP.
+ if (command_pointer >= end_pointer)
+ return EOP;
+
+ Q_UINT16 a;
+ a = *(command_pointer++);
+ a = (a << 8) | *(command_pointer++);
+ return a;
+}
+
+Q_UINT32 bigEndianByteReader::readUINT32()
+{
+ // This check saveguards us against segmentation fault. It is also
+ // necessary for virtual fonts, which do not end whith EOP.
+ if (command_pointer >= end_pointer)
+ return EOP;
+
+ Q_UINT32 a;
+ a = *(command_pointer++);
+ a = (a << 8) | *(command_pointer++);
+ a = (a << 8) | *(command_pointer++);
+ a = (a << 8) | *(command_pointer++);
+ return a;
+}
+
+void bigEndianByteReader::writeUINT32(Q_UINT32 a)
+{
+ // This check saveguards us against segmentation fault. It is also
+ // necessary for virtual fonts, which do not end whith EOP.
+ if (command_pointer >= end_pointer)
+ return;
+
+ command_pointer[3] = (Q_UINT8)(a & 0xFF);
+ a = a >> 8;
+ command_pointer[2] = (Q_UINT8)(a & 0xFF);
+ a = a >> 8;
+ command_pointer[1] = (Q_UINT8)(a & 0xFF);
+ a = a >> 8;
+ command_pointer[0] = (Q_UINT8)(a & 0xFF);
+
+ command_pointer += 4;
+ return;
+}
+
+Q_UINT32 bigEndianByteReader::readUINT(Q_UINT8 size)
+{
+ // This check saveguards us against segmentation fault. It is also
+ // necessary for virtual fonts, which do not end whith EOP.
+ if (command_pointer >= end_pointer)
+ return EOP;
+
+ Q_UINT32 a = 0;
+ while (size > 0) {
+ a = (a << 8) + *(command_pointer++);
+ size--;
+ }
+ return a;
+}
+
+Q_INT32 bigEndianByteReader::readINT(Q_UINT8 length)
+{
+ // This check saveguards us against segmentation fault. It is also
+ // necessary for virtual fonts, which do not end whith EOP.
+ if (command_pointer >= end_pointer)
+ return EOP;
+
+ Q_INT32 a = *(command_pointer++);
+
+ if (a & 0x80)
+ a -= 0x100;
+
+ while ((--length) > 0)
+ a = (a << 8) | *(command_pointer++);
+
+ return a;
+}
diff --git a/kdvi/bigEndianByteReader.h b/kdvi/bigEndianByteReader.h
new file mode 100644
index 00000000..674ca1c1
--- /dev/null
+++ b/kdvi/bigEndianByteReader.h
@@ -0,0 +1,62 @@
+// -*- C++ -*-
+/* This file is part of KDVI (C) 2001 by Stefan Kebekus (kebekus@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License
+ as published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+*/
+
+/**
+ * Byte reading routines which read big endian numbers from memory and
+ * convert them to native integers.
+ *
+ * @author Stefan Kebekus (kebekus@kde.org)
+ *
+ **/
+
+#ifndef _bigEndianByteReader_H
+#define _bigEndianByteReader_H
+
+#include <qglobal.h>
+
+class bigEndianByteReader {
+ public:
+ /** Set this pointer to the location where the number resides which
+ you want to read. */
+ Q_UINT8 * command_pointer;
+
+ /** This pointer marks the end of the memory area where bytes can be
+ read. It should point to the first byte which CANNOT be
+ read. The idea is to have a safety net which protects us against
+ SEGFAULTs. This is also used in virtual fonts, where the macro
+ does not have an EOP command at the end of the macro. */
+ Q_UINT8 * end_pointer;
+
+ /** If command_pointer >= end_pointer, this method return EOP (=140)
+ and exists. Otherwise, the method returns the unsigned byte
+ and increases the command_pointer by one. */
+ Q_UINT8 readUINT8();
+
+ /** Similar to the method above, only that the method reads a big
+ endian 2-byte word and increases the pointer by two. */
+ Q_UINT16 readUINT16();
+
+ /** Similar to the method above, only that the method reads a big
+ endian 4-byte word and increases the pointer by four. */
+ Q_UINT32 readUINT32();
+
+ void writeUINT32(Q_UINT32 a);
+
+ /** Similar to the method above, only that the method reads a big
+ endian number of length size, where 1 <= size <= 4. Note that
+ the value 3 is allowed (and is acually used in DVI files)!!! */
+ Q_UINT32 readUINT(Q_UINT8 size);
+
+ /** Similar to the method above, only that the method reads a SIGNED
+ number */
+ Q_INT32 readINT(Q_UINT8);
+
+};
+
+#endif //ifndef _bigEndianByteReader_H
diff --git a/kdvi/configure.in.in b/kdvi/configure.in.in
new file mode 100644
index 00000000..ba3ee342
--- /dev/null
+++ b/kdvi/configure.in.in
@@ -0,0 +1,55 @@
+
+dnl the following is just to fool the toplevel configure.in
+LTLIBOBJS=
+AC_SUBST(LTLIBOBJS)
+
+compile_kdvi=yes
+for j in $DO_NOT_COMPILE; do
+ if test "kdvi" = $j; then
+ compile_kdvi=no
+ fi
+done
+
+dnl AC_CONFIG_SUBDIRS has to be done before KDE_CREATE_SUBDIRSLIST
+if test "$compile_kdvi" = "yes"; then
+
+ KDE_FIND_PATH(kpsewhich, KPSEWHICH, [/usr/bin /bin /usr/sbin /opt/teTeX/bin /opt/local/bin /opt/bin /usr/local/bin], [ ])
+
+ have_kpsewhich=no
+ test_kpsewhich="`${KPSEWHICH-kpsewhich} -show-path cnf 2>/dev/null`"
+ test -n "${test_kpsewhich}" && have_kpsewhich=yes
+
+fi
+
+AC_CHECK_HEADERS(sys/types.h sys/params.h limits.h)
+
+# Check for freetype2
+KDE_FIND_PATH(freetype-config, FREETYPE_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin],)
+
+if test -n "$FREETYPE_CONFIG"; then
+ vers=`$FREETYPE_CONFIG --version 2>/dev/null | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'`
+ if test -n "$vers" && test "$vers" -ge 8000002
+ then
+ LIBFREETYPE_LIBS="`$FREETYPE_CONFIG --libs`"
+ FREETYPE_RPATH=
+ for args in $LIBFREETYPE_LIBS; do
+ case $args in
+ -L*)
+ FREETYPE_RPATH="$FREETYPE_RPATH $args"
+ ;;
+ esac
+ done
+ FREETYPE_RPATH=`echo $FREETYPE_RPATH | sed -e "s/-L/-R/g"`
+ LIBFREETYPE_CFLAGS="`$FREETYPE_CONFIG --cflags`"
+
+ AC_DEFINE_UNQUOTED(HAVE_FREETYPE, 1, [Defines if your system has the freetype library])
+ fi
+fi
+
+AC_SUBST(LIBFREETYPE_LIBS)
+AC_SUBST(LIBFREETYPE_CFLAGS)
+AC_SUBST(FREETYPE_RPATH)
+
+if test -z "$LIBFREETYPE_LIBS"; then
+ DO_NOT_COMPILE="$DO_NOT_COMPILE kdvi"
+fi
diff --git a/kdvi/dvi.h b/kdvi/dvi.h
new file mode 100644
index 00000000..62178f49
--- /dev/null
+++ b/kdvi/dvi.h
@@ -0,0 +1,68 @@
+// -*- C++ -*-
+/*
+ * Mnemonics for bytes in dvi file.
+ */
+
+#ifndef DVI_H
+#define DVI_H
+
+#define SETCHAR0 0
+#define SET1 128
+#define SETRULE 132
+#define PUT1 133
+#define PUTRULE 137
+#define NOP 138
+#define BOP 139
+#define EOP 140
+#define PUSH 141
+#define POP 142
+#define RIGHT1 143
+#define RIGHT2 144
+#define RIGHT3 145
+#define RIGHT4 146
+#define W0 147
+#define W1 148
+#define W2 149
+#define W3 150
+#define W4 151
+#define X0 152
+#define X1 153
+#define X2 154
+#define X3 155
+#define X4 156
+#define DOWN1 157
+#define DOWN2 158
+#define DOWN3 159
+#define DOWN4 160
+#define Y0 161
+#define Y1 162
+#define Y2 163
+#define Y3 164
+#define Y4 165
+#define Z0 166
+#define Z1 167
+#define Z2 168
+#define Z3 169
+#define Z4 170
+#define FNTNUM0 171
+#define FNT1 235
+#define FNT2 236
+#define FNT3 237
+#define FNT4 238
+#define XXX1 239
+#define XXX2 240
+#define XXX3 241
+#define XXX4 242
+#define FNTDEF1 243
+#define FNTDEF2 244
+#define FNTDEF3 245
+#define FNTDEF4 246
+#define PRE 247
+#define POST 248
+#define POSTPOST 249
+#define SREFL 250
+#define EREFL 251
+
+#define TRAILER 223 /* Trailing bytes at end of file */
+
+#endif
diff --git a/kdvi/dviFile.cpp b/kdvi/dviFile.cpp
new file mode 100644
index 00000000..521fb39f
--- /dev/null
+++ b/kdvi/dviFile.cpp
@@ -0,0 +1,406 @@
+/*
+ * Copyright (c) 1994 Paul Vojta. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * NOTE:
+ * xdvi is based on prior work as noted in the modification history, below.
+ */
+
+/*
+ * DVI previewer for X.
+ *
+ * Eric Cooper, CMU, September 1985.
+ *
+ * Code derived from dvi-imagen.c.
+ *
+ * Modification history:
+ * 1/1986 Modified for X.10 --Bob Scheifler, MIT LCS.
+ * 7/1988 Modified for X.11 --Mark Eichin, MIT
+ * 12/1988 Added 'R' option, toolkit, magnifying glass
+ * --Paul Vojta, UC Berkeley.
+ * 2/1989 Added tpic support --Jeffrey Lee, U of Toronto
+ * 4/1989 Modified for System V --Donald Richardson, Clarkson Univ.
+ * 3/1990 Added VMS support --Scott Allendorf, U of Iowa
+ * 7/1990 Added reflection mode --Michael Pak, Hebrew U of Jerusalem
+ * 1/1992 Added greyscale code --Till Brychcy, Techn. Univ. Muenchen
+ * and Lee Hetherington, MIT
+ * 4/1994 Added DPS support, bounding box
+ * --Ricardo Telichevesky
+ * and Luis Miguel Silveira, MIT RLE.
+ */
+
+#include <config.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <ktempfile.h>
+#include <qdir.h>
+#include <qfileinfo.h>
+#include <stdlib.h>
+#include <kprocio.h>
+
+extern "C" {
+#include "dvi.h"
+}
+
+#include "../kviewshell/pageSize.h"
+#include "dviFile.h"
+#include "fontpool.h"
+#include "xdvi.h"
+
+
+dvifile::dvifile(const dvifile *old, fontPool *fp)
+{
+ errorMsg = QString::null;
+ errorCounter = 0;
+ page_offset = 0;
+ suggestedPageSize = 0;
+ numberOfExternalPSFiles = 0;
+ numberOfExternalNONPSFiles = 0;
+ sourceSpecialMarker = old->sourceSpecialMarker;
+
+ dviData = old->dviData.copy();
+
+ filename = old->filename;
+ size_of_file = old->size_of_file;
+ end_pointer = dvi_Data()+size_of_file;
+ if (dvi_Data() == 0) {
+ kdError(4300) << "Not enough memory to copy the DVI-file." << endl;
+ return;
+ }
+
+ font_pool = fp;
+ filename = old->filename;
+ generatorString = old->generatorString;
+ total_pages = old->total_pages;
+
+
+ tn_table.clear();
+ process_preamble();
+ find_postamble();
+ read_postamble();
+ prepare_pages();
+}
+
+
+void dvifile::process_preamble()
+{
+ command_pointer = dvi_Data();
+
+ Q_UINT8 magic_number = readUINT8();
+ if (magic_number != PRE) {
+ errorMsg = i18n("The DVI file does not start with the preamble.");
+ return;
+ }
+ magic_number = readUINT8();
+ if (magic_number != 2) {
+ errorMsg = i18n("The DVI file contains the wrong version of DVI output for this program. "
+ "Hint: If you use the typesetting system Omega, you have to use a special "
+ "program, such as oxdvi.");
+ return;
+ }
+
+ /** numerator, denominator and the magnification value that describe
+ how many centimeters there are in one TeX unit, as explained in
+ section A.3 of the DVI driver standard, Level 0, published by
+ the TUG DVI driver standards committee. */
+ Q_UINT32 numerator = readUINT32();
+ Q_UINT32 denominator = readUINT32();
+ _magnification = readUINT32();
+
+ cmPerDVIunit = (double(numerator) / double(denominator)) * (double(_magnification) / 1000.0) * (1.0 / 1e5);
+
+
+ // Read the generatorString (such as "TeX output ..." from the
+ // DVI-File). The variable "magic_number" holds the length of the
+ // string.
+ char job_id[300];
+ magic_number = readUINT8();
+ strncpy(job_id, (char *)command_pointer, magic_number);
+ job_id[magic_number] = '\0';
+ generatorString = job_id;
+}
+
+
+/** find_postamble locates the beginning of the postamble and leaves
+ the file ready to start reading at that location. */
+
+void dvifile::find_postamble()
+{
+ // Move backwards through the TRAILER bytes
+ command_pointer = dvi_Data() + size_of_file - 1;
+ while((*command_pointer == TRAILER) && (command_pointer > dvi_Data()))
+ command_pointer--;
+ if (command_pointer == dvi_Data()) {
+ errorMsg = i18n("The DVI file is badly corrupted. KDVI was not able to find the postamble.");
+ return;
+ }
+
+ // And this is finally the pointer to the beginning of the postamble
+ command_pointer -= 4;
+ beginning_of_postamble = readUINT32();
+ command_pointer = dvi_Data() + beginning_of_postamble;
+}
+
+
+void dvifile::read_postamble()
+{
+ Q_UINT8 magic_byte = readUINT8();
+ if (magic_byte != POST) {
+ errorMsg = i18n("The postamble does not begin with the POST command.");
+ return;
+ }
+ last_page_offset = readUINT32();
+
+ // Skip the numerator, denominator and magnification, the largest
+ // box height and width and the maximal depth of the stack. These
+ // are not used at the moment.
+ command_pointer += 4 + 4 + 4 + 4 + 4 + 2;
+
+ // The number of pages is more interesting for us.
+ total_pages = readUINT16();
+
+ // As a next step, read the font definitions.
+ Q_UINT8 cmnd = readUINT8();
+ while (cmnd >= FNTDEF1 && cmnd <= FNTDEF4) {
+ Q_UINT32 TeXnumber = readUINT(cmnd-FNTDEF1+1);
+ Q_UINT32 checksum = readUINT32(); // Checksum of the font, as found by TeX in the TFM file
+
+ // Read scale and design factor, and the name of the font. All
+ // these are explained in section A.4 of the DVI driver standard,
+ // Level 0, published by the TUG DVI driver standards committee
+ Q_UINT32 scale = readUINT32();
+ Q_UINT32 design = readUINT32();
+ Q_UINT16 len = readUINT8() + readUINT8(); // Length of the font name, including the directory name
+ char *fontname = new char[len + 1];
+ strncpy(fontname, (char *)command_pointer, len );
+ fontname[len] = '\0';
+ command_pointer += len;
+
+#ifdef DEBUG_FONTS
+ kdDebug(4300) << "Postamble: define font \"" << fontname << "\" scale=" << scale << " design=" << design << endl;
+#endif
+
+ // According to section A.4 of the DVI driver standard, this font
+ // shall be enlarged by the following factor before it is used.
+ double enlargement_factor = (double(scale) * double(_magnification))/(double(design) * 1000.0);
+
+ if (font_pool != 0) {
+ TeXFontDefinition *fontp = font_pool->appendx(fontname, checksum, scale, enlargement_factor);
+
+ // Insert font in dictionary and make sure the dictionary is big
+ // enough.
+ if (tn_table.size()-2 <= tn_table.count())
+ // Not quite optimal. The size of the dictionary should be a
+ // prime for optimal performance. I don't care.
+ tn_table.resize(tn_table.size()*2);
+ tn_table.insert(TeXnumber, fontp);
+ }
+
+ // Read the next command
+ cmnd = readUINT8();
+ }
+
+ if (cmnd != POSTPOST) {
+ errorMsg = i18n("The postamble contained a command other than FNTDEF.");
+ return;
+ }
+
+ // Now we remove all those fonts from the memory which are no longer
+ // in use.
+ if (font_pool != 0)
+ font_pool->release_fonts();
+}
+
+
+void dvifile::prepare_pages()
+{
+#ifdef DEBUG_DVIFILE
+ kdDebug(4300) << "prepare_pages" << endl;
+#endif
+
+ if (page_offset.resize(total_pages+1) == false) {
+ kdError(4300) << "No memory for page list!" << endl;
+ return;
+ }
+ for(int i=0; i<=total_pages; i++)
+ page_offset[i] = 0;
+
+
+ page_offset[total_pages] = beginning_of_postamble;
+ Q_UINT16 i = total_pages-1;
+ page_offset[i] = last_page_offset;
+
+ // Follow back pointers through pages in the DVI file, storing the
+ // offsets in the page_offset table.
+ while (i > 0) {
+ command_pointer = dvi_Data() + page_offset[i--];
+ if (readUINT8() != BOP) {
+ errorMsg = i18n("The page %1 does not start with the BOP command.").arg(i+1);
+ return;
+ }
+ command_pointer += 10 * 4;
+ page_offset[i] = readUINT32();
+ if ((dvi_Data()+page_offset[i] < dvi_Data())||(dvi_Data()+page_offset[i] > dvi_Data()+size_of_file))
+ break;
+ }
+}
+
+
+dvifile::dvifile(const QString& fname, fontPool* pool)
+{
+#ifdef DEBUG_DVIFILE
+ kdDebug(4300) << "init_dvi_file: " << fname << endl;
+#endif
+
+ errorMsg = QString::null;
+ errorCounter = 0;
+ page_offset = 0;
+ suggestedPageSize = 0;
+ numberOfExternalPSFiles = 0;
+ numberOfExternalNONPSFiles = 0;
+ font_pool = pool;
+ sourceSpecialMarker = true;
+
+ QFile file(fname);
+ filename = file.name();
+ file.open( IO_ReadOnly );
+ size_of_file = file.size();
+ dviData.resize(size_of_file);
+ // Sets the end pointer for the bigEndianByteReader so that the
+ // whole memory buffer is readable
+ end_pointer = dvi_Data()+size_of_file;
+ if (dvi_Data() == 0) {
+ kdError() << i18n("Not enough memory to load the DVI-file.");
+ return;
+ }
+ file.readBlock((char *)dvi_Data(), size_of_file);
+ file.close();
+ if (file.status() != IO_Ok) {
+ kdError() << i18n("Could not load the DVI-file.");
+ return;
+ }
+
+ tn_table.clear();
+
+ process_preamble();
+ find_postamble();
+ read_postamble();
+ prepare_pages();
+
+ return;
+}
+
+
+dvifile::~dvifile()
+{
+#ifdef DEBUG_DVIFILE
+ kdDebug(4300) << "destroy dvi-file" << endl;
+#endif
+
+ // Delete converted PDF files
+ QMap<QString, QString>::Iterator it;
+ for ( it = convertedFiles.begin(); it != convertedFiles.end(); ++it )
+ QFile::remove(it.data());
+
+ if (suggestedPageSize != 0)
+ delete suggestedPageSize;
+ if (font_pool != 0)
+ font_pool->mark_fonts_as_unused();
+}
+
+
+void dvifile::renumber()
+{
+ dviData.detach();
+
+ // Write the page number to the file, taking good care of byte
+ // orderings.
+ int wordSize;
+ bool bigEndian;
+ qSysInfo (&wordSize, &bigEndian);
+
+ for(Q_UINT32 i=1; i<=total_pages; i++) {
+ Q_UINT8 *ptr = dviData.data() + page_offset[i-1]+1;
+ Q_UINT8 *num = (Q_UINT8 *)&i;
+ for(Q_UINT8 j=0; j<4; j++)
+ if (bigEndian) {
+ *(ptr++) = num[0];
+ *(ptr++) = num[1];
+ *(ptr++) = num[2];
+ *(ptr++) = num[3];
+ } else {
+ *(ptr++) = num[3];
+ *(ptr++) = num[2];
+ *(ptr++) = num[1];
+ *(ptr++) = num[0];
+ }
+ }
+}
+
+
+QString dvifile::convertPDFtoPS(const QString &PDFFilename)
+{
+ // Check if the PDFFile is known
+ QMap<QString, QString>::Iterator it = convertedFiles.find(PDFFilename);
+ if (it != convertedFiles.end()) {
+ // PDF-File is known. Good.
+ return it.data();
+ }
+
+ // Get the name of a temporary file
+ KTempFile tmpfile(QString::null, ".ps");
+ QString convertedFileName = tmpfile.name();
+ tmpfile.close();
+ tmpfile.unlink();
+
+ // Use pdf2ps to do the conversion
+ KProcIO proc;
+ proc << "pdf2ps" << PDFFilename << convertedFileName;
+ if (proc.start(KProcess::Block) == false)
+ convertedFileName = QString::null; // Indicates that conversion failed, won't try again.
+ if (!QFile::exists(convertedFileName))
+ convertedFileName = QString::null; // Indicates that conversion failed, won't try again.
+
+ // Save name of converted file to buffer, so PDF file won't be
+ // converted again, and files can be deleted when *this is
+ // deconstructed.
+ convertedFiles[PDFFilename] = convertedFileName;
+
+ return convertedFileName;
+}
+
+
+bool dvifile::saveAs(const QString &filename)
+{
+ if (dvi_Data() == 0)
+ return false;
+
+ QFile out(filename);
+ if (out.open( IO_Raw|IO_WriteOnly ) == false)
+ return false;
+ if (out.writeBlock ( (char *)(dvi_Data()), size_of_file ) == -1)
+ return false;
+ out.close();
+ return true;
+}
diff --git a/kdvi/dviFile.h b/kdvi/dviFile.h
new file mode 100644
index 00000000..069ae6d9
--- /dev/null
+++ b/kdvi/dviFile.h
@@ -0,0 +1,150 @@
+// -*- C++ -*-
+//
+// Class: dviFile
+//
+// Class that represents a DVI file. Part of KDVI - A DVI previewing
+// plugin for kviewshell.
+//
+// (C) 2004--2005 Stefan Kebekus. Distributed under the GPL.
+//
+
+#ifndef _DVIFILE_H
+#define _DVIFILE_H
+
+#include "bigEndianByteReader.h"
+
+#include <qintdict.h>
+#include <qiodevice.h>
+#include <qmemarray.h>
+#include <qstring.h>
+
+class fontPool;
+class pageSize;
+class TeXFontDefinition;
+
+
+class dvifile : public bigEndianByteReader
+{
+ public:
+ /** Makes a deep copy of the old DVI file. */
+ dvifile(const dvifile *old, fontPool *fp );
+ dvifile(const QString& fname, class fontPool* pool);
+
+ ~dvifile();
+
+ fontPool * font_pool;
+ QString filename;
+ QString generatorString;
+ Q_UINT16 total_pages;
+ QMemArray<Q_UINT32> page_offset;
+
+ /** Saves the DVI file. Returns true on success. */
+ bool saveAs(const QString &filename);
+
+ // Returns a pointer to the DVI file's data, or 0 if no data has yet
+ // been allocated.
+ Q_UINT8 * dvi_Data() {return dviData.data();}
+
+ QIODevice::Offset size_of_file;
+ QString errorMsg;
+
+ /** This field is set to zero when the DVI file is constructed, and
+ will be modified during the prescan phase (at this time the
+ prescan code still resides in the dviRenderer class) */
+ Q_UINT16 numberOfExternalPSFiles;
+
+ /** This field is set to zero when the DVI file is constructed, and
+ will be modified during the prescan phase (at this time the
+ prescan code still resides in the dviRenderer class) */
+ Q_UINT16 numberOfExternalNONPSFiles;
+
+ Q_UINT32 beginning_of_postamble;
+
+ /** This flag is set to "true" during the construction of the
+ dvifile, and is never changed afterwards by the dvifile
+ class. It is used in kdvi in conjuction with source-specials:
+ the first time a page with source specials is rendered, KDVI
+ shows an info dialog, and the flag is set to false. That way
+ KDVI ensures that the user is only informed once. */
+ bool sourceSpecialMarker;
+
+ QIntDict<TeXFontDefinition> tn_table;
+
+ /** Returns the number of centimeters per DVI unit in this DVI
+ file. */
+ double getCmPerDVIunit() const {return cmPerDVIunit;}
+
+ /** Returns the magnification of the DVI file, as described in the
+ DVI Standard. */
+ Q_UINT32 getMagnification() const {return _magnification;}
+
+ /** This member is set to zero on construction and can be used by
+ other software to count error messages that were printed when
+ the DVI-file was processed. Suggested application: limit the
+ number of error messages to, say, 25. */
+ Q_UINT8 errorCounter;
+
+ /** Papersize information read from the dvi-File */
+ pageSize *suggestedPageSize;
+
+ /** Sets new DVI data; all old data is erased. EXPERIMENTAL, use
+ with care. */
+ void setNewData(const QMemArray<Q_UINT8>& newData) {dviData = newData;}
+
+ /** Page numbers that appear in a DVI document need not be
+ ordered. Worse, page numbers need not be unique. This method
+ renumbers the pages. */
+ void renumber();
+
+ /** PDF to PS file conversion
+
+ This utility method takes the name of a PDF-file, and attempts to
+ convert it to a PS file. The dvifile internally keeps a list of
+ converted files, to do two thigs:
+
+ - convert files only once.
+
+ - delete all converted files on destruction
+
+ @warning The internal buffer can lead to difficulties if filenames
+ of PDF-files are not unique: if the content of a PDF file is
+ changed and this method is called a second time with the same file
+ name, the method will then NOT convert the file, but simply return
+ the name from the buffer
+
+ @returns The name of the PS file, or QString::null on failure.
+ */
+ QString convertPDFtoPS(const QString &PDFFilename);
+
+ private:
+ /** process_preamble reads the information in the preamble and
+ stores it into global variables for later use. */
+ void process_preamble();
+ void find_postamble();
+ /** read_postamble reads the information in the postamble, storing
+ it into global variables. It also takes care of reading in all
+ of the pixel files for the fonts used in the job. */
+ void read_postamble();
+ void prepare_pages();
+
+
+ /** Offset in DVI file of last page, set in read_postamble(). */
+ Q_UINT32 last_page_offset;
+ Q_UINT32 _magnification;
+
+ double cmPerDVIunit;
+
+ QMemArray<Q_UINT8> dviData;
+
+
+ /** Map of filenames for converted PDF files
+
+ This map contains names of PDF files that were converted to
+ PostScript. The key is the name of the PDF file, the data the name
+ of the associated PS file, or QString::null, if the file could not
+ be converted. The PS files are deleted when the DVI-file is
+ destructed. */
+ QMap<QString, QString> convertedFiles;
+};
+
+#endif //ifndef _DVIFILE_H
diff --git a/kdvi/dviPageCache.cpp b/kdvi/dviPageCache.cpp
new file mode 100644
index 00000000..2a2b8a30
--- /dev/null
+++ b/kdvi/dviPageCache.cpp
@@ -0,0 +1,42 @@
+/***************************************************************************
+ * 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 <config.h>
+
+#include <kdebug.h>
+
+#include "dviPageCache.h"
+#include "renderedDviPagePixmap.h"
+
+DVIPageCache::DVIPageCache()
+ : DocumentPageCache()
+{
+}
+
+DVIPageCache::~DVIPageCache()
+{
+}
+
+RenderedDocumentPagePixmap* DVIPageCache::createDocumentPagePixmap() const
+{
+ return new RenderedDviPagePixmap();
+}
+
+#include "dviPageCache.moc"
diff --git a/kdvi/dviPageCache.h b/kdvi/dviPageCache.h
new file mode 100644
index 00000000..a28052c5
--- /dev/null
+++ b/kdvi/dviPageCache.h
@@ -0,0 +1,40 @@
+// -*- C++ -*-
+/***************************************************************************
+ * 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 _DVIPAGECACHE_H_
+#define _DVIPAGECACHE_H_
+
+#include "documentPageCache.h"
+
+class DVIPageCache : public DocumentPageCache
+{
+ Q_OBJECT
+
+ public:
+ DVIPageCache();
+
+ virtual ~DVIPageCache();
+
+ private:
+ virtual RenderedDocumentPagePixmap* createDocumentPagePixmap() const;
+};
+
+#endif
diff --git a/kdvi/dviRenderer.cpp b/kdvi/dviRenderer.cpp
new file mode 100644
index 00000000..b9bf6256
--- /dev/null
+++ b/kdvi/dviRenderer.cpp
@@ -0,0 +1,839 @@
+//
+// Class: dviRenderer
+//
+// Class for rendering TeX DVI files.
+// Part of KDVI- A previewer for TeX DVI files.
+//
+// (C) 2001-2005 Stefan Kebekus
+// Distributed under the GPL
+//
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <qcheckbox.h>
+#include <qclipboard.h>
+#include <qcursor.h>
+#include <qlabel.h>
+#include <qfileinfo.h>
+#include <qlayout.h>
+#include <qmessagebox.h>
+#include <qpaintdevice.h>
+#include <qpainter.h>
+#include <qptrstack.h>
+#include <qregexp.h>
+#include <qurl.h>
+#include <qvbox.h>
+
+#include <kapplication.h>
+#include <kmessagebox.h>
+#include <kmimemagic.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <keditcl.h>
+#include <kfiledialog.h>
+#include <kio/job.h>
+#include <kio/netaccess.h>
+#include <klocale.h>
+#include <kprinter.h>
+#include <kprocess.h>
+#include <kprogress.h>
+#include <kstandarddirs.h>
+#include <kstdguiitem.h>
+
+#include "documentWidget.h"
+#include "dviFile.h"
+#include "dviRenderer.h"
+#include "fontpool.h"
+#include "fontprogress.h"
+#include "hyperlink.h"
+#include "infodialog.h"
+#include "kdvi_multipage.h"
+#include "performanceMeasurement.h"
+#include "prebookmark.h"
+#include "psgs.h"
+#include "xdvi.h"
+#include "zoomlimits.h"
+#include "dvisourcesplitter.h"
+#include "renderedDviPagePixmap.h"
+
+//#define DEBUG_DVIRENDERER
+
+QPainter *foreGroundPainter; // QPainter used for text
+
+
+//------ now comes the dviRenderer class implementation ----------
+
+dviRenderer::dviRenderer(QWidget *par)
+ : DocumentRenderer(par), info(new infoDialog(par))
+{
+#ifdef DEBUG_DVIRENDERER
+ kdDebug(4300) << "dviRenderer( parent=" << par << " )" << endl;
+#endif
+
+ // initialize the dvi machinery
+ dviFile = 0;
+
+ connect(&font_pool, SIGNAL( setStatusBarText( const QString& ) ), this, SIGNAL( setStatusBarText( const QString& ) ) );
+
+ parentWidget = par;
+ shrinkfactor = 3;
+ current_page = 0;
+ resolutionInDPI = 0.0;
+
+ connect( &clearStatusBarTimer, SIGNAL(timeout()), this, SLOT(clearStatusBar()) );
+
+ currentlyDrawnPage = 0;
+ editorCommand = "";
+
+ PostScriptOutPutString = NULL;
+ HTML_href = NULL;
+ _postscript = 0;
+
+ // Storage used for dvips and friends, i.e. for the "export" functions.
+ proc = 0;
+ progress = 0;
+ export_printer = 0;
+ export_fileName = "";
+ export_tmpFileName = "";
+ export_errorString = "";
+
+ PS_interface = new ghostscript_interface();
+ // pass status bar messages through
+ connect(PS_interface, SIGNAL( setStatusBarText( const QString& ) ), this, SIGNAL( setStatusBarText( const QString& ) ) );
+}
+
+
+dviRenderer::~dviRenderer()
+{
+#ifdef DEBUG_DVIRENDERER
+ kdDebug(4300) << "~dviRenderer" << endl;
+#endif
+
+ mutex.lock();
+ mutex.unlock();
+
+ delete PS_interface;
+ delete proc;
+ delete dviFile;
+ // Don't delete the export printer. This is owned by the
+ // kdvi_multipage.
+ export_printer = 0;
+}
+
+
+void dviRenderer::setPrefs(bool flag_showPS, const QString &str_editorCommand, bool useFontHints )
+{
+ QMutexLocker locker(&mutex);
+ _postscript = flag_showPS;
+ editorCommand = str_editorCommand;
+ font_pool.setParameters( useFontHints );
+ emit(documentIsChanged());
+}
+
+
+void dviRenderer::showInfo()
+{
+ mutex.lock();
+ info->setDVIData(dviFile);
+ info->show();
+ mutex.unlock();
+}
+
+
+//------ this function calls the dvi interpreter ----------
+
+
+void dviRenderer::drawPage(double resolution, RenderedDocumentPage *page)
+{
+#ifdef DEBUG_DVIRENDERER
+ kdDebug(4300) << "dviRenderer::drawPage(documentPage *) called, page number " << page->getPageNumber() << endl;
+#endif
+
+ // Paranoid safety checks
+ if (page == 0) {
+ kdError(4300) << "dviRenderer::drawPage(documentPage *) called with argument == 0" << endl;
+ return;
+ }
+ if (page->getPageNumber() == 0) {
+ kdError(4300) << "dviRenderer::drawPage(documentPage *) called for a documentPage with page number 0" << endl;
+ return;
+ }
+
+ mutex.lock();
+ if ( dviFile == 0 ) {
+ kdError(4300) << "dviRenderer::drawPage(documentPage *) called, but no dviFile class allocated." << endl;
+ page->clear();
+ mutex.unlock();
+ return;
+ }
+ if (page->getPageNumber() > dviFile->total_pages) {
+ kdError(4300) << "dviRenderer::drawPage(documentPage *) called for a documentPage with page number " << page->getPageNumber()
+ << " but the current dviFile has only " << dviFile->total_pages << " pages." << endl;
+ mutex.unlock();
+ return;
+ }
+ if ( dviFile->dvi_Data() == 0 ) {
+ kdError(4300) << "dviRenderer::drawPage(documentPage *) called, but no dviFile is loaded yet." << endl;
+ page->clear();
+ mutex.unlock();
+ return;
+ }
+
+ if (resolution != resolutionInDPI)
+ setResolution(resolution);
+
+ currentlyDrawnPage = page;
+ shrinkfactor = 1200/resolutionInDPI;
+ current_page = page->getPageNumber()-1;
+
+
+ // Reset colors
+ colorStack.clear();
+ globalColor = Qt::black;
+
+ QApplication::setOverrideCursor( waitCursor );
+ foreGroundPainter = page->getPainter();
+ if (foreGroundPainter != 0) {
+ errorMsg = QString::null;
+ draw_page();
+ page->returnPainter(foreGroundPainter);
+ }
+ QApplication::restoreOverrideCursor();
+
+ page->isEmpty = false;
+ if (errorMsg.isEmpty() != true) {
+ KMessageBox::detailedError(parentWidget,
+ i18n("<qt><strong>File corruption!</strong> KDVI had trouble interpreting your DVI file. Most "
+ "likely this means that the DVI file is broken.</qt>"),
+ errorMsg, i18n("DVI File Error"));
+ errorMsg = QString::null;
+ currentlyDrawnPage = 0;
+ mutex.unlock();
+ return;
+ }
+
+ // Tell the user (once) if the DVI file contains source specials
+ // ... we don't want our great feature to go unnoticed.
+ RenderedDviPagePixmap* currentDVIPage = dynamic_cast<RenderedDviPagePixmap*>(currentlyDrawnPage);
+ if (currentDVIPage)
+ {
+ if ((dviFile->sourceSpecialMarker == true) && (currentDVIPage->sourceHyperLinkList.size() > 0)) {
+ dviFile->sourceSpecialMarker = false;
+ // Show the dialog as soon as event processing is finished, and
+ // the program is idle
+ QTimer::singleShot( 0, this, SLOT(showThatSourceInformationIsPresent()) );
+ }
+ }
+
+ currentlyDrawnPage = 0;
+ mutex.unlock();
+}
+
+
+void dviRenderer::getText(RenderedDocumentPage* page)
+{
+ bool postscriptBackup = _postscript;
+ // Disable postscript-specials temporarely to speed up text extraction.
+ _postscript = false;
+
+ drawPage(100.0, page);
+
+ _postscript = postscriptBackup;
+}
+
+
+void dviRenderer::showThatSourceInformationIsPresent()
+{
+ // In principle, we should use a KMessagebox here, but we want to
+ // add a button "Explain in more detail..." which opens the
+ // Helpcenter. Thus, we practically re-implement the KMessagebox
+ // here. Most of the code is stolen from there.
+
+ // Check if the 'Don't show again' feature was used
+ KConfig *config = kapp->config();
+ KConfigGroupSaver saver( config, "Notification Messages" );
+ bool showMsg = config->readBoolEntry( "KDVI-info_on_source_specials", true);
+
+ if (showMsg) {
+ KDialogBase *dialog= new KDialogBase(i18n("KDVI: Information"), KDialogBase::Yes, KDialogBase::Yes, KDialogBase::Yes,
+ parentWidget, "information", true, true,KStdGuiItem::ok() );
+
+ QVBox *topcontents = new QVBox (dialog);
+ topcontents->setSpacing(KDialog::spacingHint()*2);
+ topcontents->setMargin(KDialog::marginHint()*2);
+
+ QWidget *contents = new QWidget(topcontents);
+ QHBoxLayout * lay = new QHBoxLayout(contents);
+ lay->setSpacing(KDialog::spacingHint()*2);
+
+ lay->addStretch(1);
+ QLabel *label1 = new QLabel( contents);
+ label1->setPixmap(QMessageBox::standardIcon(QMessageBox::Information));
+ lay->add( label1 );
+ QLabel *label2 = new QLabel( i18n("<qt>This DVI file contains source file information. You may click into the text with the "
+ "middle mouse button, and an editor will open the TeX-source file immediately.</qt>"),
+ contents);
+ label2->setMinimumSize(label2->sizeHint());
+ lay->add( label2 );
+ lay->addStretch(1);
+ QSize extraSize = QSize(50,30);
+ QCheckBox *checkbox = new QCheckBox(i18n("Do not show this message again"), topcontents);
+ extraSize = QSize(50,0);
+ dialog->setHelpLinkText(i18n("Explain in more detail..."));
+ dialog->setHelp("inverse-search", "kdvi");
+ dialog->enableLinkedHelp(true);
+ dialog->setMainWidget(topcontents);
+ dialog->enableButtonSeparator(false);
+ dialog->incInitialSize( extraSize );
+ dialog->exec();
+ delete dialog;
+
+ showMsg = !checkbox->isChecked();
+ if (!showMsg) {
+ KConfigGroupSaver saver( config, "Notification Messages" );
+ config->writeEntry( "KDVI-info_on_source_specials", showMsg);
+ }
+ config->sync();
+ }
+}
+
+
+void dviRenderer::embedPostScript()
+{
+#ifdef DEBUG_DVIRENDERER
+ kdDebug(4300) << "dviRenderer::embedPostScript()" << endl;
+#endif
+
+ if (!dviFile)
+ return;
+
+ embedPS_progress = new KProgressDialog(parentWidget, "embedPSProgressDialog",
+ i18n("Embedding PostScript Files"), QString::null, true);
+ if (!embedPS_progress)
+ return;
+ embedPS_progress->setAllowCancel(false);
+ embedPS_progress->showCancelButton(false);
+ embedPS_progress->setMinimumDuration(400);
+ embedPS_progress->progressBar()->setTotalSteps(dviFile->numberOfExternalPSFiles);
+ embedPS_progress->progressBar()->setProgress(0);
+ embedPS_numOfProgressedFiles = 0;
+
+
+ Q_UINT16 currPageSav = current_page;
+ errorMsg = QString::null;
+ for(current_page=0; current_page < dviFile->total_pages; current_page++) {
+ if (current_page < dviFile->total_pages) {
+ command_pointer = dviFile->dvi_Data() + dviFile->page_offset[current_page];
+ end_pointer = dviFile->dvi_Data() + dviFile->page_offset[current_page+1];
+ } else
+ command_pointer = end_pointer = 0;
+
+ memset((char *) &currinf.data, 0, sizeof(currinf.data));
+ currinf.fonttable = &(dviFile->tn_table);
+ currinf._virtual = NULL;
+ prescan(&dviRenderer::prescan_embedPS);
+ }
+
+ delete embedPS_progress;
+
+ if (!errorMsg.isEmpty()) {
+ errorMsg = "<qt>" + errorMsg + "</qt>";
+ KMessageBox::detailedError(parentWidget, "<qt>" + i18n("Not all PostScript files could be embedded into your document.") + "</qt>", errorMsg);
+ errorMsg = QString::null;
+ } else
+ KMessageBox::information(parentWidget, "<qt>" + i18n("All external PostScript files were embedded into your document. You "
+ "will probably want to save the DVI file now.") + "</qt>",
+ QString::null, "embeddingDone");
+
+ // Prescan phase starts here
+#ifdef PERFORMANCE_MEASUREMENT
+ kdDebug(4300) << "Time elapsed till prescan phase starts " << performanceTimer.elapsed() << "ms" << endl;
+ QTime preScanTimer;
+ preScanTimer.start();
+#endif
+ dviFile->numberOfExternalPSFiles = 0;
+ prebookmarks.clear();
+ for(current_page=0; current_page < dviFile->total_pages; current_page++) {
+ PostScriptOutPutString = new QString();
+
+ if (current_page < dviFile->total_pages) {
+ command_pointer = dviFile->dvi_Data() + dviFile->page_offset[current_page];
+ end_pointer = dviFile->dvi_Data() + dviFile->page_offset[current_page+1];
+ } else
+ command_pointer = end_pointer = 0;
+
+ memset((char *) &currinf.data, 0, sizeof(currinf.data));
+ currinf.fonttable = &(dviFile->tn_table);
+ currinf._virtual = NULL;
+
+ prescan(&dviRenderer::prescan_parseSpecials);
+
+ if (!PostScriptOutPutString->isEmpty())
+ PS_interface->setPostScript(current_page, *PostScriptOutPutString);
+ delete PostScriptOutPutString;
+ }
+ PostScriptOutPutString = NULL;
+
+
+#ifdef PERFORMANCE_MEASUREMENT
+ kdDebug(4300) << "Time required for prescan phase: " << preScanTimer.restart() << "ms" << endl;
+#endif
+ current_page = currPageSav;
+ _isModified = true;
+}
+
+
+bool dviRenderer::isValidFile(const QString& filename) const
+{
+ QFile f(filename);
+ if (!f.open(IO_ReadOnly))
+ return false;
+
+ unsigned char test[4];
+ if ( f.readBlock( (char *)test,2)<2 || test[0] != 247 || test[1] != 2 )
+ return false;
+
+ int n = f.size();
+ if ( n < 134 ) // Too short for a dvi file
+ return false;
+ f.at( n-4 );
+
+ unsigned char trailer[4] = { 0xdf,0xdf,0xdf,0xdf };
+
+ if ( f.readBlock( (char *)test, 4 )<4 || strncmp( (char *)test, (char *) trailer, 4 ) )
+ return false;
+ // We suppose now that the dvi file is complete and OK
+ return true;
+}
+
+
+bool dviRenderer::setFile(const QString &fname, const KURL &base)
+{
+#ifdef DEBUG_DVIRENDERER
+ kdDebug(4300) << "dviRenderer::setFile( fname='" << fname << "', ref='" << ref << "', sourceMarker=" << sourceMarker << " )" << endl;
+#endif
+
+ QMutexLocker lock(&mutex);
+
+ QFileInfo fi(fname);
+ QString filename = fi.absFilePath();
+
+ // If fname is the empty string, then this means: "close". Delete
+ // the dvifile and the pixmap.
+ if (fname.isEmpty()) {
+ // Delete DVI file
+ info->setDVIData(0);
+ delete dviFile;
+ dviFile = 0;
+ return true;
+ }
+
+
+ // Make sure the file actually exists.
+ if (!fi.exists() || fi.isDir()) {
+ KMessageBox::error( parentWidget,
+ i18n("<qt><strong>File error.</strong> The specified file '%1' does not exist. "
+ "KDVI already tried to add the ending '.dvi'.</qt>").arg(filename),
+ i18n("File Error!"));
+ return false;
+ }
+
+ // Check if we are really loading a DVI file, and complain about the
+ // mime type, if the file is not DVI. Perhaps we should move the
+ // procedure later to the kviewpart, instead of the implementaton in
+ // the multipage.
+ QString mimetype( KMimeMagic::self()->findFileType( fname )->mimeType() );
+ if (mimetype != "application/x-dvi") {
+ KMessageBox::sorry( parentWidget,
+ i18n( "<qt>Could not open file <nobr><strong>%1</strong></nobr> which has "
+ "type <strong>%2</strong>. KDVI can only load DVI (.dvi) files.</qt>" )
+ .arg( fname )
+ .arg( mimetype ) );
+ return false;
+ }
+
+ // Check if the file is a valid DVI file.
+ if (!isValidFile(filename))
+ {
+ KMessageBox::sorry( parentWidget,
+ i18n("<qt>File corruption! KDVI had trouble interpreting your DVI file. Most "
+ "likely this means that the DVI file is broken.</qt>")
+ .arg( fname ) );
+ return false;
+ }
+
+ QApplication::setOverrideCursor( waitCursor );
+ dvifile *dviFile_new = new dvifile(filename, &font_pool);
+
+ if ((dviFile == 0) || (dviFile->filename != filename))
+ dviFile_new->sourceSpecialMarker = true;
+ else
+ dviFile_new->sourceSpecialMarker = false;
+
+ if ((dviFile_new->dvi_Data() == NULL)||(dviFile_new->errorMsg.isEmpty() != true)) {
+ QApplication::restoreOverrideCursor();
+ if (dviFile_new->errorMsg.isEmpty() != true)
+ KMessageBox::detailedError(parentWidget,
+ i18n("<qt>File corruption! KDVI had trouble interpreting your DVI file. Most "
+ "likely this means that the DVI file is broken.</qt>"),
+ dviFile_new->errorMsg, i18n("DVI File Error"));
+ delete dviFile_new;
+ return false;
+ }
+
+ delete dviFile;
+ dviFile = dviFile_new;
+ numPages = dviFile->total_pages;
+ info->setDVIData(dviFile);
+ _isModified = false;
+ baseURL = base;
+
+ font_pool.setExtraSearchPath( fi.dirPath(true) );
+ font_pool.setCMperDVIunit( dviFile->getCmPerDVIunit() );
+
+ // Extract PostScript from the DVI file, and store the PostScript
+ // specials in PostScriptDirectory, and the headers in the
+ // PostScriptHeaderString.
+ PS_interface->clear();
+
+ // If the DVI file comes from a remote URL (e.g. downloaded from a
+ // web server), we limit the PostScript files that can be accessed
+ // by this file to the download directory, in order to limit the
+ // possibilities of a denial of service attack.
+ QString includePath;
+ if (!baseURL.isLocalFile()) {
+ includePath = filename;
+ includePath.truncate(includePath.findRev('/'));
+ }
+ PS_interface->setIncludePath(includePath);
+
+ // We will also generate a list of hyperlink-anchors and source-file
+ // anchors in the document. So declare the existing lists empty.
+ anchorList.clear();
+ sourceHyperLinkAnchors.clear();
+ bookmarks.clear();
+ prebookmarks.clear();
+
+ if (dviFile->page_offset.isEmpty() == true)
+ return false;
+
+ // Locate fonts.
+ font_pool.locateFonts();
+
+ // Update the list of fonts in the info window
+ if (info != 0)
+ info->setFontInfo(&font_pool);
+
+ // We should pre-scan the document now (to extract embedded,
+ // PostScript, Hyperlinks, ets).
+
+ // PRESCAN STARTS HERE
+#ifdef PERFORMANCE_MEASUREMENT
+ kdDebug(4300) << "Time elapsed till prescan phase starts " << performanceTimer.elapsed() << "ms" << endl;
+ QTime preScanTimer;
+ preScanTimer.start();
+#endif
+ dviFile->numberOfExternalPSFiles = 0;
+ Q_UINT16 currPageSav = current_page;
+ prebookmarks.clear();
+
+ for(current_page=0; current_page < dviFile->total_pages; current_page++) {
+ PostScriptOutPutString = new QString();
+
+ if (current_page < dviFile->total_pages) {
+ command_pointer = dviFile->dvi_Data() + dviFile->page_offset[current_page];
+ end_pointer = dviFile->dvi_Data() + dviFile->page_offset[current_page+1];
+ } else
+ command_pointer = end_pointer = 0;
+
+ memset((char *) &currinf.data, 0, sizeof(currinf.data));
+ currinf.fonttable = &(dviFile->tn_table);
+ currinf._virtual = NULL;
+ prescan(&dviRenderer::prescan_parseSpecials);
+
+ if (!PostScriptOutPutString->isEmpty())
+ PS_interface->setPostScript(current_page, *PostScriptOutPutString);
+ delete PostScriptOutPutString;
+ }
+ PostScriptOutPutString = NULL;
+
+ // Generate the list of bookmarks
+ bookmarks.clear();
+ QPtrStack<Bookmark> stack;
+ stack.setAutoDelete (false);
+ QValueVector<PreBookmark>::iterator it;
+ for( it = prebookmarks.begin(); it != prebookmarks.end(); ++it ) {
+ Bookmark *bmk = new Bookmark((*it).title, findAnchor((*it).anchorName));
+ if (stack.isEmpty())
+ bookmarks.append(bmk);
+ else {
+ stack.top()->subordinateBookmarks.append(bmk);
+ stack.remove();
+ }
+ for(int i=0; i<(*it).noOfChildren; i++)
+ stack.push(bmk);
+ }
+ prebookmarks.clear();
+
+
+#ifdef PERFORMANCE_MEASUREMENT
+ kdDebug(4300) << "Time required for prescan phase: " << preScanTimer.restart() << "ms" << endl;
+#endif
+ current_page = currPageSav;
+ // PRESCAN ENDS HERE
+
+
+ pageSizes.resize(0);
+ if (dviFile->suggestedPageSize != 0) {
+ // Fill the vector pageSizes with total_pages identical entries
+ pageSizes.resize(dviFile->total_pages, *(dviFile->suggestedPageSize));
+ }
+
+ QApplication::restoreOverrideCursor();
+ return true;
+}
+
+
+Anchor dviRenderer::parseReference(const QString &reference)
+{
+ mutex.lock();
+
+#ifdef DEBUG_DVIRENDERER
+ kdError(4300) << "dviRenderer::parseReference( " << reference << " ) called" << endl;
+#endif
+
+ if (dviFile == 0) {
+ mutex.unlock();
+ return Anchor();
+ }
+
+ // case 1: The reference is a number, which we'll interpret as a
+ // page number.
+ bool ok;
+ int page = reference.toInt ( &ok );
+ if (ok == true) {
+ if (page < 0)
+ page = 0;
+ if (page > dviFile->total_pages)
+ page = dviFile->total_pages;
+
+ mutex.unlock();
+ return Anchor(page, Length() );
+ }
+
+ // case 2: The reference is of form "src:1111Filename", where "1111"
+ // points to line number 1111 in the file "Filename". KDVI then
+ // looks for source specials of the form "src:xxxxFilename", and
+ // tries to find the special with the biggest xxxx
+ if (reference.find("src:",0,false) == 0) {
+
+ // Extract the file name and the numeral part from the reference string
+ DVI_SourceFileSplitter splitter(reference, dviFile->filename);
+ Q_UINT32 refLineNumber = splitter.line();
+ QString refFileName = splitter.filePath();
+
+ if (sourceHyperLinkAnchors.isEmpty()) {
+ KMessageBox::sorry(parentWidget, i18n("<qt>You have asked KDVI to locate the place in the DVI file which corresponds to "
+ "line %1 in the TeX-file <strong>%2</strong>. It seems, however, that the DVI file "
+ "does not contain the necessary source file information. "
+ "We refer to the manual of KDVI for a detailed explanation on how to include this "
+ "information. Press the F1 key to open the manual.</qt>").arg(refLineNumber).arg(refFileName),
+ i18n("Could Not Find Reference"));
+ mutex.unlock();
+ return Anchor();
+ }
+
+ // Go through the list of source file anchors, and find the anchor
+ // whose line number is the biggest among those that are smaller
+ // than the refLineNumber. That way, the position in the DVI file
+ // which is highlighted is always a little further up than the
+ // position in the editor, e.g. if the DVI file contains
+ // positional information at the beginning of every paragraph,
+ // KDVI jumps to the beginning of the paragraph that the cursor is
+ // in, and never to the next paragraph. If source file anchors for
+ // the refFileName can be found, but none of their line numbers is
+ // smaller than the refLineNumber, the reason is most likely, that
+ // the cursor in the editor stands somewhere in the preamble of
+ // the LaTeX file. In that case, we jump to the beginning of the
+ // document.
+ bool anchorForRefFileFound = false; // Flag that is set if source file anchors for the refFileName could be found at all
+
+ QValueVector<DVI_SourceFileAnchor>::iterator bestMatch = sourceHyperLinkAnchors.end();
+ QValueVector<DVI_SourceFileAnchor>::iterator it;
+ for( it = sourceHyperLinkAnchors.begin(); it != sourceHyperLinkAnchors.end(); ++it )
+ if (refFileName.stripWhiteSpace() == it->fileName.stripWhiteSpace()
+ || refFileName.stripWhiteSpace() == it->fileName.stripWhiteSpace() + ".tex"
+ ) {
+ anchorForRefFileFound = true;
+
+ if ( (it->line <= refLineNumber) &&
+ ( (bestMatch == sourceHyperLinkAnchors.end()) || (it->line > bestMatch->line) ) )
+ bestMatch = it;
+ }
+
+ if (bestMatch != sourceHyperLinkAnchors.end()) {
+ mutex.unlock();
+ return Anchor(bestMatch->page, bestMatch->distance_from_top);
+ } else
+ if (anchorForRefFileFound == false)
+ KMessageBox::sorry(parentWidget, i18n("<qt>KDVI was not able to locate the place in the DVI file which corresponds to "
+ "line %1 in the TeX-file <strong>%2</strong>.</qt>").arg(refLineNumber).arg(refFileName),
+ i18n( "Could Not Find Reference" ));
+ else {
+ mutex.unlock();
+ return Anchor();
+ }
+ mutex.unlock();
+ return Anchor();
+ }
+ mutex.unlock();
+ return Anchor();
+}
+
+
+void dviRenderer::setResolution(double resolution_in_DPI)
+{
+ // Ignore minute changes. The difference to the current value would
+ // hardly be visible anyway. That saves a lot of re-painting,
+ // e.g. when the user resizes the window, and a flickery mouse
+ // changes the window size by 1 pixel all the time.
+ if (fabs(resolutionInDPI-resolution_in_DPI) < 1)
+ return;
+
+ resolutionInDPI = resolution_in_DPI;
+
+ // Pass the information on to the font pool.
+ font_pool.setDisplayResolution( resolutionInDPI );
+ shrinkfactor = 1200/resolutionInDPI;
+ return;
+}
+
+
+void dviRenderer::clearStatusBar()
+{
+ emit setStatusBarText( QString::null );
+}
+
+
+void dviRenderer::handleSRCLink(const QString &linkText, QMouseEvent *e, DocumentWidget *win)
+{
+#ifdef DEBUG_SPECIAL
+ RenderedDviPagePixmap* currentDVIPage = dynamic_cast<RenderedDviPagePixmap*> currentlyDrawnPage;
+ if (currentDVIPage)
+ {
+ kdDebug(4300) << "Source hyperlink to " << currentDVIPage->sourceHyperLinkList[i].linkText << endl;
+ }
+#endif
+
+ DVI_SourceFileSplitter splitter(linkText, dviFile->filename);
+ QString TeXfile = splitter.filePath();
+ if ( ! splitter.fileExists() )
+ {
+ KMessageBox::sorry(parentWidget, QString("<qt>") +
+ i18n("The DVI-file refers to the TeX-file "
+ "<strong>%1</strong> which could not be found.").arg(KShellProcess::quote(TeXfile)) +
+ QString("</qt>"),
+ i18n( "Could Not Find File" ));
+ return;
+ }
+
+ QString command = editorCommand;
+ if (command.isEmpty() == true) {
+ int r = KMessageBox::warningContinueCancel(parentWidget, QString("<qt>") +
+ i18n("You have not yet specified an editor for inverse search. "
+ "Please choose your favorite editor in the "
+ "<strong>DVI options dialog</strong> "
+ "which you will find in the <strong>Settings</strong>-menu.") +
+ QString("</qt>"),
+ i18n("Need to Specify Editor"),
+ i18n("Use KDE's Editor Kate for Now"));
+ if (r == KMessageBox::Continue)
+ command = "kate %f";
+ else
+ return;
+ }
+ command = command.replace( "%l", QString::number(splitter.line()) ).replace( "%f", KShellProcess::quote(TeXfile) );
+
+#ifdef DEBUG_SPECIAL
+ kdDebug(4300) << "Calling program: " << command << endl;
+#endif
+
+ // There may still be another program running. Since we don't
+ // want to mix the output of several programs, we will
+ // henceforth dimiss the output of the older programm. "If it
+ // hasn't failed until now, we don't care."
+ if (proc != 0) {
+ qApp->disconnect(proc, SIGNAL(receivedStderr(KProcess *, char *, int)), 0, 0);
+ qApp->disconnect(proc, SIGNAL(receivedStdout(KProcess *, char *, int)), 0, 0);
+ proc = 0;
+ }
+
+ // Set up a shell process with the editor command.
+ proc = new KShellProcess();
+ if (proc == 0) {
+ kdError(4300) << "Could not allocate ShellProcess for the editor command." << endl;
+ return;
+ }
+ qApp->connect(proc, SIGNAL(receivedStderr(KProcess *, char *, int)), this, SLOT(dvips_output_receiver(KProcess *, char *, int)));
+ qApp->connect(proc, SIGNAL(receivedStdout(KProcess *, char *, int)), this, SLOT(dvips_output_receiver(KProcess *, char *, int)));
+ qApp->connect(proc, SIGNAL(processExited(KProcess *)), this, SLOT(editorCommand_terminated(KProcess *)));
+ // Merge the editor-specific editor message here.
+ export_errorString = i18n("<qt>The external program<br><br><tt><strong>%1</strong></tt><br/><br/>which was used to call the editor "
+ "for inverse search, reported an error. You might wish to look at the <strong>document info "
+ "dialog</strong> which you will find in the File-Menu for a precise error report. The "
+ "manual for KDVI contains a detailed explanation how to set up your editor for use with KDVI, "
+ "and a list of common problems.</qt>").arg(command);
+
+ info->clear(i18n("Starting the editor..."));
+
+ int flashOffset = e->y(); // Heuristic correction. Looks better.
+ win->flash(flashOffset);
+
+
+ proc->clearArguments();
+ *proc << command;
+ proc->closeStdin();
+ if (proc->start(KProcess::NotifyOnExit, KProcess::AllOutput) == false) {
+ kdError(4300) << "Editor failed to start" << endl;
+ return;
+ }
+}
+
+
+QString dviRenderer::PDFencodingToQString(const QString& _pdfstring)
+{
+ // This method locates special PDF characters in a string and
+ // replaces them by UTF8. See Section 3.2.3 of the PDF reference
+ // guide for information.
+ QString pdfstring = _pdfstring;
+ pdfstring = pdfstring.replace("\\n", "\n");
+ pdfstring = pdfstring.replace("\\r", "\n");
+ pdfstring = pdfstring.replace("\\t", "\t");
+ pdfstring = pdfstring.replace("\\f", "\f");
+ pdfstring = pdfstring.replace("\\(", "(");
+ pdfstring = pdfstring.replace("\\)", ")");
+ pdfstring = pdfstring.replace("\\\\", "\\");
+
+ // Now replace octal character codes with the characters they encode
+ int pos;
+ QRegExp rx( "(\\\\)(\\d\\d\\d)" ); // matches "\xyz" where x,y,z are numbers
+ while((pos = rx.search( pdfstring )) != -1) {
+ pdfstring = pdfstring.replace(pos, 4, QChar(rx.cap(2).toInt(0,8)));
+ }
+ rx.setPattern( "(\\\\)(\\d\\d)" ); // matches "\xy" where x,y are numbers
+ while((pos = rx.search( pdfstring )) != -1) {
+ pdfstring = pdfstring.replace(pos, 3, QChar(rx.cap(2).toInt(0,8)));
+ }
+ rx.setPattern( "(\\\\)(\\d)" ); // matches "\x" where x is a number
+ while((pos = rx.search( pdfstring )) != -1) {
+ pdfstring = pdfstring.replace(pos, 4, QChar(rx.cap(2).toInt(0,8)));
+ }
+ return pdfstring;
+}
+
+
+#include "dviRenderer.moc"
diff --git a/kdvi/dviRenderer.h b/kdvi/dviRenderer.h
new file mode 100644
index 00000000..98f0f4bd
--- /dev/null
+++ b/kdvi/dviRenderer.h
@@ -0,0 +1,300 @@
+// -*- C++ -*-
+//
+// Class: dviRenderer
+//
+// Class for rendering TeX DVI files.
+// Part of KDVI- A previewer for TeX DVI files.
+//
+// (C) 2001-2005 Stefan Kebekus. Distributed under the GPL.
+
+#ifndef _dvirenderer_h_
+#define _dvirenderer_h_
+
+#include "bigEndianByteReader.h"
+#include "documentRenderer.h"
+#include "fontpool.h"
+
+#include <kurl.h>
+#include <qintdict.h>
+#include <qpointarray.h>
+#include <qtimer.h>
+#include <qvaluestack.h>
+#include <qvaluevector.h>
+
+class Anchor;
+class DocumentWidget;
+class dviRenderer;
+class fontProgressDialog;
+class ghostscript_interface;
+class infoDialog;
+class KAction;
+class KDVIMultiPage;
+class KPrinter;
+class KProcess;
+class KProgressDialog;
+class KShellProcess;
+class PreBookmark;
+class TeXFontDefinition;
+
+extern const int MFResolutions[];
+
+class DVI_SourceFileAnchor {
+ public:
+ DVI_SourceFileAnchor() {}
+ DVI_SourceFileAnchor(const QString& name, Q_UINT32 ln, Q_UINT32 pg, const Length& _distance_from_top)
+ : fileName(name), line(ln), page(pg),
+ distance_from_top(_distance_from_top) {}
+
+ QString fileName;
+ Q_UINT32 line;
+ Q_UINT32 page;
+ Length distance_from_top;
+};
+
+/** Compound of registers, as defined in section 2.6.2 of the DVI
+ driver standard, Level 0, published by the TUG DVI driver
+ standards committee. */
+
+struct framedata {
+ long dvi_h;
+ long dvi_v;
+ long w;
+ long x;
+ long y;
+ long z;
+ int pxl_v;
+};
+
+
+/* this information is saved when using virtual fonts */
+
+typedef void (dviRenderer::*set_char_proc)(unsigned int, unsigned int);
+typedef void (dviRenderer::*parseSpecials)(char *, Q_UINT8 *);
+
+struct drawinf {
+ struct framedata data;
+ TeXFontDefinition *fontp;
+ set_char_proc set_char_p;
+
+ QIntDict<TeXFontDefinition> *fonttable;
+ TeXFontDefinition *_virtual;
+};
+
+
+
+class dviRenderer : public DocumentRenderer, bigEndianByteReader
+{
+ Q_OBJECT
+
+public:
+ dviRenderer(QWidget *parent);
+ ~dviRenderer();
+
+ virtual bool setFile(const QString &fname, const KURL &base);
+
+ class dvifile *dviFile;
+
+ void setPrefs(bool flag_showPS, const QString &editorCommand, bool useFontHints );
+
+ virtual bool supportsTextSearch() const {return true;}
+
+ bool showPS() { return _postscript; }
+ int curr_page() { return current_page+1; }
+ virtual bool isValidFile(const QString& fileName) const;
+
+
+ /** This method will try to parse the reference part of the DVI
+ file's URL, (either a number, which is supposed to be a page
+ number, or src:<line><filename>) and see if a corresponding
+ section of the DVI file can be found. If so, it returns an
+ anchor to that section. If not, it returns an invalid anchor. */
+ virtual Anchor parseReference(const QString &reference);
+
+ // These should not be public... only for the moment
+ void read_postamble();
+ void draw_part(double current_dimconv, bool is_vfmacro);
+ void set_vf_char(unsigned int cmd, unsigned int ch);
+ void set_char(unsigned int cmd, unsigned int ch);
+ void set_empty_char(unsigned int cmd, unsigned int ch);
+ void set_no_char(unsigned int cmd, unsigned int ch);
+ void applicationDoSpecial(char * cp);
+
+ void special(long nbytes);
+ void printErrorMsgForSpecials(const QString& msg);
+ void color_special(const QString& cp);
+ void html_href_special(const QString& cp);
+ void html_anchor_end();
+ void draw_page();
+
+public slots:
+ void exportPS(const QString& fname = QString::null, const QString& options = QString::null, KPrinter* printer = 0);
+ void exportPDF();
+
+ void showInfo();
+ void handleSRCLink(const QString &linkText, QMouseEvent *e, DocumentWidget *widget);
+
+ void embedPostScript();
+ void abortExternalProgramm();
+
+ /** simply emits "setStatusBarText( QString::null )". This is used
+ in dviRenderer::mouseMoveEvent(), see the explanation there. */
+ void clearStatusBar();
+
+ virtual void drawPage(double res, RenderedDocumentPage *page);
+ virtual void getText(RenderedDocumentPage* page);
+
+ /** Slots used in conjunction with external programs */
+ void dvips_output_receiver(KProcess *, char *buffer, int buflen);
+ void dvips_terminated(KProcess *);
+ void editorCommand_terminated(KProcess *);
+
+signals:
+ /** Passed through to the top-level kpart. */
+ // void setStatusBarText( const QString& );
+
+private slots:
+ /** This method shows a dialog that tells the user that source
+ information is present, and gives the opportunity to open the
+ manual and learn more about forward and inverse search */
+ void showThatSourceInformationIsPresent();
+
+private:
+ /** URL to the DVI file
+
+ This field is initialized by the setFile() method. See the
+ explanation there. */
+ KURL baseURL;
+
+
+ /** This method parses a color specification of type "gray 0.5", "rgb
+ 0.5 0.7 1.0", "hsb ...", "cmyk .." or "PineGreen". See the source
+ code for details. */
+ QColor parseColorSpecification(const QString& colorSpec);
+
+ /** This map contains the colors which are known by name. This field
+ is initialized in the method parseColorSpecification() as soon as
+ it is needed. */
+ QMap<QString, QColor> namedColors;
+
+ /* This method locates special PDF characters in a string and
+ replaces them by UTF8. See Section 3.2.3 of the PDF reference
+ guide for information */
+ QString PDFencodingToQString(const QString& pdfstring);
+
+ void setResolution(double resolution_in_DPI);
+
+ fontPool font_pool;
+ infoDialog *info;
+
+ double resolutionInDPI;
+
+ // @@@ explanation
+ void prescan(parseSpecials specialParser);
+ void prescan_embedPS(char *cp, Q_UINT8 *);
+ void prescan_removePageSizeInfo(char *cp, Q_UINT8 *);
+ void prescan_parseSpecials(char *cp, Q_UINT8 *);
+ void prescan_ParsePapersizeSpecial(const QString& cp);
+ void prescan_ParseBackgroundSpecial(const QString& cp);
+ void prescan_ParseHTMLAnchorSpecial(const QString& cp);
+ void prescan_ParsePSHeaderSpecial(const QString& cp);
+ void prescan_ParsePSBangSpecial(const QString& cp);
+ void prescan_ParsePSQuoteSpecial(const QString& cp);
+ void prescan_ParsePSSpecial(const QString& cp);
+ void prescan_ParsePSFileSpecial(const QString& cp);
+ void prescan_ParseSourceSpecial(const QString& cp);
+ void prescan_setChar(unsigned int ch);
+
+ /* */
+ QValueVector<PreBookmark> prebookmarks;
+
+
+
+ /** Utility fields used by the embedPostScript method*/
+ KProgressDialog *embedPS_progress;
+ Q_UINT16 embedPS_numOfProgressedFiles;
+
+ /** Shrink factor. Units are not quite clear */
+ double shrinkfactor;
+
+ QString errorMsg;
+
+ /** Methods which handle certain special commands. */
+ void epsf_special(const QString& cp);
+ void source_special(const QString& cp);
+
+ /** TPIC specials */
+ void TPIC_setPen_special(const QString& cp);
+ void TPIC_addPath_special(const QString& cp);
+ void TPIC_flushPath_special();
+
+ /** This timer is used to delay clearing of the statusbar. Clearing
+ the statusbar is delayed to avoid awful flickering when the
+ mouse moves over a block of text that contains source
+ hyperlinks. The signal timeout() is connected to the method
+ clearStatusBar() of *this. */
+ QTimer clearStatusBarTimer;
+
+ // List of source-hyperlinks on all pages. This vector is generated
+ // when the DVI-file is first loaded, i.e. when draw_part is called
+ // with PostScriptOutPutString != NULL
+ QValueVector<DVI_SourceFileAnchor> sourceHyperLinkAnchors;
+
+ // If not NULL, the text currently drawn represents a source
+ // hyperlink to the (relative) URL given in the string;
+ QString *source_href;
+
+ // If not NULL, the text currently drawn represents a hyperlink to
+ // the (relative) URL given in the string;
+ QString *HTML_href;
+
+ QString editorCommand;
+
+ /** Stack for register compounds, used for the DVI-commands PUSH/POP
+ as explained in section 2.5 and 2.6.2 of the DVI driver standard,
+ Level 0, published by the TUG DVI driver standards committee. */
+ QValueStack<struct framedata> stack;
+
+ /** A stack where color are stored, according to the documentation of
+ DVIPS */
+ QValueStack<QColor> colorStack;
+
+ /** The global color is to be used when the color stack is empty */
+ QColor globalColor;
+
+ /** If PostScriptOutPutFile is non-zero, then no rendering takes
+ place. Instead, the PostScript code which is generated by the
+ \special-commands is written to the PostScriptString */
+ QString *PostScriptOutPutString;
+
+ ghostscript_interface *PS_interface;
+
+ /** true, if gs should be used, otherwise, only bounding boxes are
+ drawn. */
+ bool _postscript;
+
+ /** This flag is used when rendering a dvi-page. It is set to "true"
+ when any dvi-command other than "set" or "put" series of commands
+ is encountered. This is considered to mark the end of a word. */
+ bool line_boundary_encountered;
+ bool word_boundary_encountered;
+
+ unsigned int current_page;
+
+ /** Used to run and to show the progress of dvips and friends. */
+ fontProgressDialog *progress;
+ KShellProcess *proc;
+ KPrinter *export_printer;
+ QString export_fileName;
+ QString export_tmpFileName;
+ QString export_errorString;
+
+ /** Data required for handling TPIC specials */
+ float penWidth_in_mInch;
+ QPointArray TPIC_path;
+ Q_UINT16 number_of_elements_in_path;
+
+ struct drawinf currinf;
+ RenderedDocumentPage* currentlyDrawnPage;
+};
+
+#endif
diff --git a/kdvi/dviRenderer_draw.cpp b/kdvi/dviRenderer_draw.cpp
new file mode 100644
index 00000000..d09caf6d
--- /dev/null
+++ b/kdvi/dviRenderer_draw.cpp
@@ -0,0 +1,660 @@
+/*
+ * Copyright (c) 1994 Paul Vojta. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * NOTE:
+ * xdvi is based on prior work as noted in the modification history, below.
+ */
+
+/*
+ * DVI previewer for X.
+ *
+ * Eric Cooper, CMU, September 1985.
+ *
+ * Code derived from dvi-imagen.c.
+ *
+ * Modification history:
+ * 1/1986 Modified for X.10 --Bob Scheifler, MIT LCS.
+ * 7/1988 Modified for X.11 --Mark Eichin, MIT
+ * 12/1988 Added 'R' option, toolkit, magnifying glass
+ * --Paul Vojta, UC Berkeley.
+ * 2/1989 Added tpic support --Jeffrey Lee, U of Toronto
+ * 4/1989 Modified for System V --Donald Richardson, Clarkson Univ.
+ * 3/1990 Added VMS support --Scott Allendorf, U of Iowa
+ * 7/1990 Added reflection mode --Michael Pak, Hebrew U of Jerusalem
+ * 1/1992 Added greyscale code --Till Brychcy, Techn. Univ. Muenchen
+ * and Lee Hetherington, MIT
+ * 4/1994 Added DPS support, bounding box
+ * --Ricardo Telichevesky
+ * and Luis Miguel Silveira, MIT RLE.
+ */
+
+//#define DEBUG_RENDER 0
+
+#include <config.h>
+
+#include "dviRenderer.h"
+#include "dvi.h"
+#include "dviFile.h"
+#include "fontpool.h"
+#include "hyperlink.h"
+#include "kdvi_multipage.h"
+#include "performanceMeasurement.h"
+#include "psgs.h"
+#include "renderedDviPagePixmap.h"
+#include "TeXFont.h"
+#include "textBox.h"
+#include "xdvi.h"
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kprocess.h>
+#include <qpainter.h>
+#include <qbitmap.h>
+#include <qimage.h>
+#include <qpainter.h>
+#include <qfileinfo.h>
+
+extern QPainter *foreGroundPainter;
+
+
+/** Routine to print characters. */
+
+void dviRenderer::set_char(unsigned int cmd, unsigned int ch)
+{
+#ifdef DEBUG_RENDER
+ kdDebug(4300) << "set_char #" << ch << endl;
+#endif
+
+ glyph *g;
+ if (colorStack.isEmpty())
+ g = ((TeXFont *)(currinf.fontp->font))->getGlyph(ch, true, globalColor);
+ else
+ g = ((TeXFont *)(currinf.fontp->font))->getGlyph(ch, true, colorStack.top());
+ if (g == NULL)
+ return;
+
+ long dvi_h_sav = currinf.data.dvi_h;
+
+ QPixmap pix = g->shrunkenCharacter;
+ int x = ((int) ((currinf.data.dvi_h) / (shrinkfactor * 65536))) - g->x2;
+ int y = currinf.data.pxl_v - g->y2;
+
+ // Draw the character.
+ foreGroundPainter->drawPixmap(x, y, pix);
+
+ // Are we drawing text for a hyperlink? And are hyperlinks
+ // enabled?
+ if (HTML_href != NULL) {
+ // Now set up a rectangle which is checked against every mouse
+ // event.
+ if (line_boundary_encountered == true) {
+ // Set up hyperlink
+ Hyperlink dhl;
+ dhl.baseline = currinf.data.pxl_v;
+ dhl.box.setRect(x, y, pix.width(), pix.height());
+ dhl.linkText = *HTML_href;
+ currentlyDrawnPage->hyperLinkList.push_back(dhl);
+ } else {
+ QRect dshunion = currentlyDrawnPage->hyperLinkList[currentlyDrawnPage->hyperLinkList.size()-1].box.unite(QRect(x, y, pix.width(), pix.height())) ;
+ currentlyDrawnPage->hyperLinkList[currentlyDrawnPage->hyperLinkList.size()-1].box = dshunion;
+ }
+ }
+
+ // Are we drawing text for a source hyperlink? And are source
+ // hyperlinks enabled?
+ // If we are printing source hyperlinks are irrelevant, otherwise we
+ // actually got a pointer to a RenderedDviPagePixmap.
+ RenderedDviPagePixmap* currentDVIPage = dynamic_cast<RenderedDviPagePixmap*>(currentlyDrawnPage);
+ if (source_href != 0 && currentDVIPage) {
+ // Now set up a rectangle which is checked against every mouse
+ // event.
+ if (line_boundary_encountered == true) {
+ // Set up source hyperlinks
+ Hyperlink dhl;
+ dhl.baseline = currinf.data.pxl_v;
+ dhl.box.setRect(x, y, pix.width(), pix.height());
+ if (source_href != NULL)
+ dhl.linkText = *source_href;
+ else
+ dhl.linkText = "";
+ currentDVIPage->sourceHyperLinkList.push_back(dhl);
+ } else {
+ QRect dshunion = currentDVIPage->sourceHyperLinkList[currentDVIPage->sourceHyperLinkList.size()-1].box.unite(QRect(x, y, pix.width(), pix.height())) ;
+ currentDVIPage->sourceHyperLinkList[currentDVIPage->sourceHyperLinkList.size()-1].box = dshunion;
+ }
+ }
+
+ // Code for DVI -> text functions (e.g. marking of text, full text
+ // search, etc.). Set up the currentlyDrawnPage->textBoxList.
+ TextBox link;
+ link.box.setRect(x, y, pix.width(), pix.height());
+ link.text = "";
+ currentlyDrawnPage->textBoxList.push_back(link);
+
+ switch(ch) {
+ case 0x0b:
+ currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += "ff";
+ break;
+ case 0x0c:
+ currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += "fi";
+ break;
+ case 0x0d:
+ currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += "fl";
+ break;
+ case 0x0e:
+ currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += "ffi";
+ break;
+ case 0x0f:
+ currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += "ffl";
+ break;
+
+ case 0x7b:
+ currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += "-";
+ break;
+ case 0x7c:
+ currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += "---";
+ break;
+ case 0x7d:
+ currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += "\"";
+ break;
+ case 0x7e:
+ currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += "~";
+ break;
+ case 0x7f:
+ currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += "@@"; // @@@ check!
+ break;
+
+ default:
+ if ((ch >= 0x21) && (ch <= 0x7a))
+ currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += QChar(ch);
+ else
+ currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += "?";
+ break;
+ }
+
+
+ if (cmd == PUT1)
+ currinf.data.dvi_h = dvi_h_sav;
+ else
+ currinf.data.dvi_h += (int)(currinf.fontp->scaled_size_in_DVI_units * dviFile->getCmPerDVIunit() *
+ (1200.0 / 2.54)/16.0 * g->dvi_advance_in_units_of_design_size_by_2e20 + 0.5);
+
+ word_boundary_encountered = false;
+ line_boundary_encountered = false;
+}
+
+void dviRenderer::set_empty_char(unsigned int, unsigned int)
+{
+ return;
+}
+
+void dviRenderer::set_vf_char(unsigned int cmd, unsigned int ch)
+{
+#ifdef DEBUG_RENDER
+ kdDebug(4300) << "dviRenderer::set_vf_char( cmd=" << cmd << ", ch=" << ch << " )" << endl;
+#endif
+
+ static unsigned char c;
+ macro *m = &currinf.fontp->macrotable[ch];
+ if (m->pos == NULL) {
+ kdError(4300) << "Character " << ch << " not defined in font " << currinf.fontp->fontname << endl;
+ m->pos = m->end = &c;
+ return;
+ }
+
+ long dvi_h_sav = currinf.data.dvi_h;
+
+ struct drawinf oldinfo = currinf;
+ currinf.data.w = 0;
+ currinf.data.x = 0;
+ currinf.data.y = 0;
+ currinf.data.z = 0;
+
+ currinf.fonttable = &(currinf.fontp->vf_table);
+ currinf._virtual = currinf.fontp;
+ Q_UINT8 *command_ptr_sav = command_pointer;
+ Q_UINT8 *end_ptr_sav = end_pointer;
+ command_pointer = m->pos;
+ end_pointer = m->end;
+ draw_part(currinf.fontp->scaled_size_in_DVI_units*(dviFile->getCmPerDVIunit() * 1200.0 / 2.54)/16.0, true);
+ command_pointer = command_ptr_sav;
+ end_pointer = end_ptr_sav;
+ currinf = oldinfo;
+
+ if (cmd == PUT1)
+ currinf.data.dvi_h = dvi_h_sav;
+ else
+ currinf.data.dvi_h += (int)(currinf.fontp->scaled_size_in_DVI_units * dviFile->getCmPerDVIunit() *
+ (1200.0 / 2.54)/16.0 * m->dvi_advance_in_units_of_design_size_by_2e20 + 0.5);
+}
+
+
+void dviRenderer::set_no_char(unsigned int cmd, unsigned int ch)
+{
+#ifdef DEBUG_RENDER
+ kdDebug(4300) << "dviRenderer::set_no_char( cmd=" << cmd << ", ch =" << ch << " )" << endl;
+#endif
+
+ if (currinf._virtual) {
+ currinf.fontp = currinf._virtual->first_font;
+ if (currinf.fontp != NULL) {
+ currinf.set_char_p = currinf.fontp->set_char_p;
+ (this->*currinf.set_char_p)(cmd, ch);
+ return;
+ }
+ }
+
+ errorMsg = i18n("The DVI code set a character of an unknown font.");
+ return;
+}
+
+
+void dviRenderer::draw_part(double current_dimconv, bool is_vfmacro)
+{
+#ifdef DEBUG_RENDER
+ kdDebug(4300) << "draw_part" << endl;
+#endif
+
+ Q_INT32 RRtmp=0, WWtmp=0, XXtmp=0, YYtmp=0, ZZtmp=0;
+ Q_UINT8 ch;
+
+ currinf.fontp = NULL;
+ currinf.set_char_p = &dviRenderer::set_no_char;
+
+ for (;;) {
+ ch = readUINT8();
+ if (ch <= (unsigned char) (SETCHAR0 + 127)) {
+ (this->*currinf.set_char_p)(ch, ch);
+ } else
+ if (FNTNUM0 <= ch && ch <= (unsigned char) (FNTNUM0 + 63)) {
+ currinf.fontp = currinf.fonttable->find(ch - FNTNUM0);
+ if (currinf.fontp == NULL) {
+ errorMsg = i18n("The DVI code referred to font #%1, which was not previously defined.").arg(ch - FNTNUM0);
+ return;
+ }
+ currinf.set_char_p = currinf.fontp->set_char_p;
+ } else {
+ Q_INT32 a, b;
+
+ switch (ch) {
+ case SET1:
+ case PUT1:
+ (this->*currinf.set_char_p)(ch, readUINT8());
+ break;
+
+ case SETRULE:
+ if (is_vfmacro == false) {
+ word_boundary_encountered = true;
+ line_boundary_encountered = true;
+ }
+ /* Be careful, dvicopy outputs rules with height =
+ 0x80000000. We don't want any SIGFPE here. */
+ a = readUINT32();
+ b = readUINT32();
+ b = ((long) (b * current_dimconv));
+ if (a > 0 && b > 0) {
+ int h = ((int) ROUNDUP(((long) (a * current_dimconv)), shrinkfactor * 65536));
+ int w = ((int) ROUNDUP(b, shrinkfactor * 65536));
+
+ if (colorStack.isEmpty())
+ foreGroundPainter->fillRect( ((int) ((currinf.data.dvi_h) / (shrinkfactor * 65536))),
+ currinf.data.pxl_v - h + 1, w?w:1, h?h:1, globalColor );
+ else
+ foreGroundPainter->fillRect( ((int) ((currinf.data.dvi_h) / (shrinkfactor * 65536))),
+ currinf.data.pxl_v - h + 1, w?w:1, h?h:1, colorStack.top() );
+ }
+ currinf.data.dvi_h += b;
+ break;
+
+ case PUTRULE:
+ if (is_vfmacro == false) {
+ word_boundary_encountered = true;
+ line_boundary_encountered = true;
+ }
+ a = readUINT32();
+ b = readUINT32();
+ a = ((long) (a * current_dimconv));
+ b = ((long) (b * current_dimconv));
+ if (a > 0 && b > 0) {
+ int h = ((int) ROUNDUP(a, shrinkfactor * 65536));
+ int w = ((int) ROUNDUP(b, shrinkfactor * 65536));
+ if (colorStack.isEmpty())
+ foreGroundPainter->fillRect( ((int) ((currinf.data.dvi_h) / (shrinkfactor * 65536))),
+ currinf.data.pxl_v - h + 1, w?w:1, h?h:1, globalColor );
+ else
+ foreGroundPainter->fillRect( ((int) ((currinf.data.dvi_h) / (shrinkfactor * 65536))),
+ currinf.data.pxl_v - h + 1, w?w:1, h?h:1, colorStack.top() );
+ }
+ break;
+
+ case NOP:
+ break;
+
+ case BOP:
+ if (is_vfmacro == false) {
+ word_boundary_encountered = true;
+ line_boundary_encountered = true;
+ }
+ command_pointer += 11 * 4;
+ currinf.data.dvi_h = 1200 << 16; // Reminder: DVI-coordinates start at (1",1") from top of page
+ currinf.data.dvi_v = 1200;
+ currinf.data.pxl_v = int(currinf.data.dvi_v/shrinkfactor);
+ currinf.data.w = currinf.data.x = currinf.data.y = currinf.data.z = 0;
+ break;
+
+ case EOP:
+ // Check if we are just at the end of a virtual font macro.
+ if (is_vfmacro == false) {
+ // This is really the end of a page, and not just the end
+ // of a macro. Mark the end of the current word.
+ word_boundary_encountered = true;
+ line_boundary_encountered = true;
+ // Sanity check for the dvi-file: The DVI-standard asserts
+ // that at the end of a page, the stack should always be
+ // empty.
+ if (!stack.isEmpty()) {
+ kdDebug(4300) << "DRAW: The stack was not empty when the EOP command was encountered." << endl;
+ errorMsg = i18n("The stack was not empty when the EOP command was encountered.");
+ return;
+ }
+ }
+ return;
+
+ case PUSH:
+ stack.push(currinf.data);
+ break;
+
+ case POP:
+ if (stack.isEmpty()) {
+ errorMsg = i18n("The stack was empty when a POP command was encountered.");
+ return;
+ } else
+ currinf.data = stack.pop();
+ word_boundary_encountered = true;
+ line_boundary_encountered = true;
+ break;
+
+ case RIGHT1:
+ case RIGHT2:
+ case RIGHT3:
+ case RIGHT4:
+ RRtmp = readINT(ch - RIGHT1 + 1);
+
+ // A horizontal motion in the range 4 * font space [f] < h <
+ // font space [f] will be treated as a kern that is not
+ // indicated in the printouts that DVItype produces between
+ // brackets. We allow a larger space in the negative
+ // direction than in the positive one, because TEX makes
+ // comparatively large backspaces when it positions
+ // accents. (comments stolen from the source of dvitype)
+ if ((is_vfmacro == false) &&
+ (currinf.fontp != 0) &&
+ ((RRtmp >= currinf.fontp->scaled_size_in_DVI_units/6) || (RRtmp <= -4*(currinf.fontp->scaled_size_in_DVI_units/6))) &&
+ (currentlyDrawnPage->textBoxList.size() > 0))
+ currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += ' ';
+ currinf.data.dvi_h += ((long) (RRtmp * current_dimconv));
+ break;
+
+ case W1:
+ case W2:
+ case W3:
+ case W4:
+ WWtmp = readINT(ch - W0);
+ currinf.data.w = ((long) (WWtmp * current_dimconv));
+ case W0:
+ if ((is_vfmacro == false) &&
+ (currinf.fontp != 0) &&
+ ((WWtmp >= currinf.fontp->scaled_size_in_DVI_units/6) || (WWtmp <= -4*(currinf.fontp->scaled_size_in_DVI_units/6))) &&
+ (currentlyDrawnPage->textBoxList.size() > 0) )
+ currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += ' ';
+ currinf.data.dvi_h += currinf.data.w;
+ break;
+
+ case X1:
+ case X2:
+ case X3:
+ case X4:
+ XXtmp = readINT(ch - X0);
+ currinf.data.x = ((long) (XXtmp * current_dimconv));
+ case X0:
+ if ((is_vfmacro == false) &&
+ (currinf.fontp != 0) &&
+ ((XXtmp >= currinf.fontp->scaled_size_in_DVI_units/6) || (XXtmp <= -4*(currinf.fontp->scaled_size_in_DVI_units/6))) &&
+ (currentlyDrawnPage->textBoxList.size() > 0))
+ currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += ' ';
+ currinf.data.dvi_h += currinf.data.x;
+ break;
+
+ case DOWN1:
+ case DOWN2:
+ case DOWN3:
+ case DOWN4:
+ {
+ Q_INT32 DDtmp = readINT(ch - DOWN1 + 1);
+ if ((is_vfmacro == false) &&
+ (currinf.fontp != 0) &&
+ (abs(DDtmp) >= 5*(currinf.fontp->scaled_size_in_DVI_units/6)) &&
+ (currentlyDrawnPage->textBoxList.size() > 0)) {
+ word_boundary_encountered = true;
+ line_boundary_encountered = true;
+ if (abs(DDtmp) >= 10*(currinf.fontp->scaled_size_in_DVI_units/6))
+ currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += '\n';
+ }
+ currinf.data.dvi_v += ((long) (DDtmp * current_dimconv))/65536;
+ currinf.data.pxl_v = int(currinf.data.dvi_v/shrinkfactor);
+ }
+ break;
+
+ case Y1:
+ case Y2:
+ case Y3:
+ case Y4:
+ YYtmp = readINT(ch - Y0);
+ currinf.data.y = ((long) (YYtmp * current_dimconv));
+ case Y0:
+ if ((is_vfmacro == false) &&
+ (currinf.fontp != 0) &&
+ (abs(YYtmp) >= 5*(currinf.fontp->scaled_size_in_DVI_units/6)) &&
+ (currentlyDrawnPage->textBoxList.size() > 0)) {
+ word_boundary_encountered = true;
+ line_boundary_encountered = true;
+ if (abs(YYtmp) >= 10*(currinf.fontp->scaled_size_in_DVI_units/6))
+ currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += '\n';
+ }
+ currinf.data.dvi_v += currinf.data.y/65536;
+ currinf.data.pxl_v = int(currinf.data.dvi_v/shrinkfactor);
+ break;
+
+ case Z1:
+ case Z2:
+ case Z3:
+ case Z4:
+ ZZtmp = readINT(ch - Z0);
+ currinf.data.z = ((long) (ZZtmp * current_dimconv));
+ case Z0:
+ if ((is_vfmacro == false) &&
+ (currinf.fontp != 0) &&
+ (abs(ZZtmp) >= 5*(currinf.fontp->scaled_size_in_DVI_units/6)) &&
+ (currentlyDrawnPage->textBoxList.size() > 0)) {
+ word_boundary_encountered = true;
+ line_boundary_encountered = true;
+ if (abs(ZZtmp) >= 10*(currinf.fontp->scaled_size_in_DVI_units/6))
+ currentlyDrawnPage->textBoxList[currentlyDrawnPage->textBoxList.size()-1].text += '\n';
+ }
+ currinf.data.dvi_v += currinf.data.z/65536;
+ currinf.data.pxl_v = int(currinf.data.dvi_v/shrinkfactor);
+ break;
+
+ case FNT1:
+ case FNT2:
+ case FNT3:
+ currinf.fontp = currinf.fonttable->find(readUINT(ch - FNT1 + 1));
+ if (currinf.fontp == NULL) {
+ errorMsg = i18n("The DVI code referred to a font which was not previously defined.");
+ return;
+ }
+ currinf.set_char_p = currinf.fontp->set_char_p;
+ break;
+
+ case FNT4:
+ currinf.fontp = currinf.fonttable->find(readINT(ch - FNT1 + 1));
+ if (currinf.fontp == NULL) {
+ errorMsg = i18n("The DVI code referred to a font which was not previously defined.");
+ return;
+ }
+ currinf.set_char_p = currinf.fontp->set_char_p;
+ break;
+
+ case XXX1:
+ case XXX2:
+ case XXX3:
+ case XXX4:
+ if (is_vfmacro == false) {
+ word_boundary_encountered = true;
+ line_boundary_encountered = true;
+ }
+ a = readUINT(ch - XXX1 + 1);
+ if (a > 0) {
+ char *cmd = new char[a+1];
+ strncpy(cmd, (char *)command_pointer, a);
+ command_pointer += a;
+ cmd[a] = '\0';
+ applicationDoSpecial(cmd);
+ delete [] cmd;
+ }
+ break;
+
+ case FNTDEF1:
+ case FNTDEF2:
+ case FNTDEF3:
+ case FNTDEF4:
+ command_pointer += 12 + ch - FNTDEF1 + 1;
+ {
+ Q_UINT8 tempa = readUINT8();
+ Q_UINT8 tempb = readUINT8();
+ command_pointer += tempa + tempb;
+ }
+ break;
+
+ case PRE:
+ case POST:
+ case POSTPOST:
+ errorMsg = i18n("An illegal command was encountered.");
+ return;
+ break;
+
+ default:
+ errorMsg = i18n("The unknown op-code %1 was encountered.").arg(ch);
+ return;
+ } /* end switch*/
+ } /* end else (ch not a SETCHAR or FNTNUM) */
+ } /* end for */
+}
+
+
+void dviRenderer::draw_page()
+{
+ // Reset a couple of variables
+ HTML_href = 0;
+ source_href = 0;
+ penWidth_in_mInch = 0.0;
+
+ // Calling resize() here rather than clear() means that the memory
+ // taken up by the vector is not freed. This is faster than
+ // constantly allocating/freeing memory.
+ currentlyDrawnPage->textBoxList.resize(0);
+
+ RenderedDviPagePixmap* currentDVIPage = dynamic_cast<RenderedDviPagePixmap*>(currentlyDrawnPage);
+ if (currentDVIPage)
+ {
+ currentDVIPage->sourceHyperLinkList.resize(0);
+ }
+
+#ifdef PERFORMANCE_MEASUREMENT
+ // If this is the first time a page is drawn, take the time that is
+ // elapsed till the kdvi_multipage was constructed, and print
+ // it. Set the flag so that is message will not be printed again.
+ if (performanceFlag == 0) {
+ kdDebug(4300) << "Time elapsed till the first page is drawn: " << performanceTimer.restart() << "ms" << endl;
+ performanceFlag = 1;
+ }
+#endif
+
+
+#ifdef DEBUG_RENDER
+ kdDebug(4300) <<"draw_page" << endl;
+#endif
+
+ if (!accessibilityBackground)
+ {
+ foreGroundPainter->fillRect( foreGroundPainter->viewport(), PS_interface->getBackgroundColor(current_page) );
+ }
+ else
+ {
+ // In accessiblity mode use the custom background color
+ foreGroundPainter->fillRect( foreGroundPainter->viewport(), accessibilityBackgroundColor );
+ }
+
+ // Render the PostScript background, if there is one.
+ if (_postscript)
+ {
+ // In accessiblity mode use the custom background color
+ if (accessibilityBackground)
+ {
+ // Flag permanent is set to false because otherwise we would not be able to restore
+ // the original background color.
+ PS_interface->setBackgroundColor(current_page, accessibilityBackgroundColor, false);
+ }
+ else
+ PS_interface->restoreBackgroundColor(current_page);
+
+ PS_interface->graphics(current_page, resolutionInDPI, dviFile->getMagnification(), foreGroundPainter);
+ }
+
+ // Now really write the text
+ if (dviFile->page_offset.isEmpty() == true)
+ return;
+ if (current_page < dviFile->total_pages) {
+ command_pointer = dviFile->dvi_Data() + dviFile->page_offset[current_page];
+ end_pointer = dviFile->dvi_Data() + dviFile->page_offset[current_page+1];
+ } else
+ command_pointer = end_pointer = 0;
+
+ memset((char *) &currinf.data, 0, sizeof(currinf.data));
+ currinf.fonttable = &(dviFile->tn_table);
+ currinf._virtual = 0;
+
+ double fontPixelPerDVIunit = dviFile->getCmPerDVIunit() * 1200.0/2.54;
+
+ draw_part(65536.0*fontPixelPerDVIunit, false);
+ if (HTML_href != 0) {
+ delete HTML_href;
+ HTML_href = 0;
+ }
+ if (source_href != 0) {
+ delete source_href;
+ source_href = 0;
+ }
+}
diff --git a/kdvi/dviRenderer_export.cpp b/kdvi/dviRenderer_export.cpp
new file mode 100644
index 00000000..4745bf18
--- /dev/null
+++ b/kdvi/dviRenderer_export.cpp
@@ -0,0 +1,391 @@
+//
+// Class: dviRenderer
+// Author: Stefan Kebekus
+//
+// (C) 2001-2004, Stefan Kebekus.
+//
+// Previewer for TeX DVI files.
+//
+// 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.
+//
+// Please report bugs or improvements, etc. via the "Report bug"-Menu
+// of kdvi.
+
+#include <config.h>
+
+#include <kapplication.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <kfiledialog.h>
+#include <kio/job.h>
+#include <kio/netaccess.h>
+#include <klocale.h>
+#include <kprinter.h>
+#include <kprocess.h>
+#include <ktempfile.h>
+#include <qlabel.h>
+#include <qpainter.h>
+
+#include "dviRenderer.h"
+#include "dviFile.h"
+#include "fontprogress.h"
+#include "infodialog.h"
+#include "kdvi_multipage.h"
+
+extern QPainter foreGroundPaint; // QPainter used for text
+
+
+
+void dviRenderer::exportPDF()
+{
+ // It could perhaps happen that a kShellProcess, which runs an
+ // editor for inverse search, is still running. In that case, we
+ // ingore any further output of the editor by detaching the
+ // appropriate slots. The sigal "processExited", however, remains
+ // attached to the slow "exportCommand_terminated", which is smart
+ // enough to ignore the exit status of the editor if another command
+ // has been called meanwhile. See also the exportPS method.
+ if (proc != 0) {
+ // Make sure all further output of the programm is ignored
+ qApp->disconnect(proc, SIGNAL(receivedStderr(KProcess *, char *, int)), 0, 0);
+ qApp->disconnect(proc, SIGNAL(receivedStdout(KProcess *, char *, int)), 0, 0);
+ proc = 0;
+ }
+
+ // That sould also not happen.
+ if (dviFile == NULL)
+ return;
+
+ // Is the dvipdfm-Programm available ??
+ QStringList texList = QStringList::split(":", QString::fromLocal8Bit(getenv("PATH")));
+ bool found = false;
+ for (QStringList::Iterator it=texList.begin(); it!=texList.end(); ++it) {
+ QString temp = (*it) + "/" + "dvipdfm";
+ if (QFile::exists(temp)) {
+ found = true;
+ break;
+ }
+ }
+ if (found == false) {
+ KMessageBox::sorry(0, i18n("KDVI could not locate the program 'dvipdfm' on your computer. That program is "
+ "essential for the export function to work. You can, however, convert "
+ "the DVI-file to PDF using the print function of KDVI, but that will often "
+ "produce documents which print ok, but are of inferior quality if viewed in the "
+ "Acrobat Reader. It may be wise to upgrade to a more recent version of your "
+ "TeX distribution which includes the 'dvipdfm' program.\n"
+ "Hint to the perplexed system administrator: KDVI uses the shell's PATH variable "
+ "when looking for programs."));
+ return;
+ }
+
+ // Generate a suggestion for a reasonable file name
+ QString suggestedName = dviFile->filename;
+ suggestedName = suggestedName.left(suggestedName.find(".")) + ".pdf";
+
+ QString fileName = KFileDialog::getSaveFileName(suggestedName, i18n("*.pdf|Portable Document Format (*.pdf)"), parentWidget, i18n("Export File As"));
+ if (fileName.isEmpty())
+ return;
+ QFileInfo finfo(fileName);
+ if (finfo.exists()) {
+ int r = KMessageBox::warningContinueCancel (parentWidget, i18n("The file %1\nexists. Do you want to overwrite that file?").arg(fileName),
+ i18n("Overwrite File"), i18n("Overwrite"));
+ if (r == KMessageBox::Cancel)
+ return;
+ }
+
+ // Initialize the progress dialog
+ progress = new fontProgressDialog( QString::null,
+ i18n("Using dvipdfm to export the file to PDF"),
+ QString::null,
+ i18n("KDVI is currently using the external program 'dvipdfm' to "
+ "convert your DVI-file to PDF. Sometimes that can take "
+ "a while because dvipdfm needs to generate its own bitmap fonts "
+ "Please be patient."),
+ i18n("Waiting for dvipdfm to finish..."),
+ parentWidget, i18n("dvipdfm progress dialog"), false );
+ if (progress != 0) {
+ progress->TextLabel2->setText( i18n("Please be patient") );
+ progress->setTotalSteps( dviFile->total_pages );
+ qApp->connect(progress, SIGNAL(finished()), this, SLOT(abortExternalProgramm()));
+ }
+
+ proc = new KShellProcess();
+ if (proc == 0) {
+ kdError(4300) << "Could not allocate ShellProcess for the dvipdfm command." << endl;
+ return;
+ }
+ qApp->disconnect( this, SIGNAL(mySignal()), 0, 0 );
+
+ qApp->connect(proc, SIGNAL(receivedStderr(KProcess *, char *, int)), this, SLOT(dvips_output_receiver(KProcess *, char *, int)));
+ qApp->connect(proc, SIGNAL(receivedStdout(KProcess *, char *, int)), this, SLOT(dvips_output_receiver(KProcess *, char *, int)));
+ qApp->connect(proc, SIGNAL(processExited(KProcess *)), this, SLOT(dvips_terminated(KProcess *)));
+
+ export_errorString = i18n("<qt>The external program 'dvipdf', which was used to export the file, reported an error. "
+ "You might wish to look at the <strong>document info dialog</strong> which you will "
+ "find in the File-Menu for a precise error report.</qt>") ;
+ info->clear(i18n("Export: %1 to PDF").arg(KShellProcess::quote(dviFile->filename)));
+
+ proc->clearArguments();
+ finfo.setFile(dviFile->filename);
+ *proc << QString("cd %1; dvipdfm").arg(KShellProcess::quote(finfo.dirPath(true)));
+ *proc << QString("-o %1").arg(KShellProcess::quote(fileName));
+ *proc << KShellProcess::quote(dviFile->filename);
+ proc->closeStdin();
+ if (proc->start(KProcess::NotifyOnExit, KProcess::AllOutput) == false) {
+ kdError(4300) << "dvipdfm failed to start" << endl;
+ return;
+ }
+ return;
+}
+
+
+void dviRenderer::exportPS(const QString& fname, const QString& options, KPrinter* printer)
+{
+ // Safety check.
+ if (dviFile->page_offset.isEmpty() == true)
+ return;
+
+ // It could perhaps happen that a kShellProcess, which runs an
+ // editor for inverse search, is still running. In that case, we
+ // ingore any further output of the editor by detaching the
+ // appropriate slots. The sigal "processExited", however, remains
+ // attached to the slow "exportCommand_terminated", which is smart
+ // enough to ignore the exit status of the editor if another command
+ // has been called meanwhile. See also the exportPDF method.
+ if (proc != 0) {
+ qApp->disconnect(proc, SIGNAL(receivedStderr(KProcess *, char *, int)), 0, 0);
+ qApp->disconnect(proc, SIGNAL(receivedStdout(KProcess *, char *, int)), 0, 0);
+ proc = 0;
+ }
+
+ // That sould also not happen.
+ if (dviFile == NULL)
+ return;
+
+ if (dviFile->numberOfExternalNONPSFiles != 0) {
+ KMessageBox::sorry( parentWidget,
+ i18n("<qt><P>This DVI file refers to external graphic files which are not in PostScript format, and cannot be handled by the "
+ "<strong>dvips</strong> program that KDVI uses interally to print or to export to PostScript. The functionality that "
+ "you require is therefore unavailable in this version of KDVI.</p>"
+ "<p>As a workaround, you can use the <strong>File/Export As</strong>-Menu to save this file in PDF format, and then use "
+ "a PDF viewer.</p>"
+ "<p>The author of KDVI apologizes for the inconvenience. If enough users complain, the missing functionality might later "
+ "be added.</p></qt>") ,
+ i18n("Functionality Unavailable"));
+ return;
+ }
+
+ QString fileName;
+ if (fname.isEmpty()) {
+ // Generate a suggestion for a reasonable file name
+ QString suggestedName = dviFile->filename;
+ suggestedName = suggestedName.left(suggestedName.find(".")) + ".ps";
+
+ fileName = KFileDialog::getSaveFileName(suggestedName, i18n("*.ps|PostScript (*.ps)"), parentWidget, i18n("Export File As"));
+ if (fileName.isEmpty())
+ return;
+ QFileInfo finfo(fileName);
+ if (finfo.exists()) {
+ int r = KMessageBox::warningYesNo (parentWidget, i18n("The file %1\nexists. Do you want to overwrite that file?").arg(fileName),
+ i18n("Overwrite File"));
+ if (r == KMessageBox::No)
+ return;
+ }
+ } else
+ fileName = fname;
+ export_fileName = fileName;
+ export_printer = printer;
+
+ // Initialize the progress dialog
+ progress = new fontProgressDialog( QString::null,
+ i18n("Using dvips to export the file to PostScript"),
+ QString::null,
+ i18n("KDVI is currently using the external program 'dvips' to "
+ "convert your DVI-file to PostScript. Sometimes that can take "
+ "a while because dvips needs to generate its own bitmap fonts "
+ "Please be patient."),
+ i18n("Waiting for dvips to finish..."),
+ parentWidget, i18n("dvips progress dialog"), false );
+ if (progress != 0) {
+ progress->TextLabel2->setText( i18n("Please be patient") );
+ progress->setTotalSteps( dviFile->total_pages );
+ qApp->connect(progress, SIGNAL(finished()), this, SLOT(abortExternalProgramm()));
+ }
+
+ // There is a major problem with dvips, at least 5.86 and lower: the
+ // arguments of the option "-pp" refer to TeX-pages, not to
+ // sequentially numbered pages. For instance "-pp 7" may refer to 3
+ // or more pages: one page "VII" in the table of contents, a page
+ // "7" in the text body, and any number of pages "7" in various
+ // appendices, indices, bibliographies, and so forth. KDVI currently
+ // uses the following disgusting workaround: if the "options"
+ // variable is used, the DVI-file is copied to a temporary file, and
+ // all the page numbers are changed into a sequential ordering
+ // (using UNIX files, and taking manually care of CPU byte
+ // ordering). Finally, dvips is then called with the new file, and
+ // the file is afterwards deleted. Isn't that great?
+
+ // A similar problem occurs with DVI files that contain page size
+ // information. On these files, dvips pointblank refuses to change
+ // the page orientation or set another page size. Thus, if the
+ // DVI-file does contain page size information, we remove that
+ // information first.
+
+ // Sourcefile is the name of the DVI which is used by dvips, either
+ // the original file, or a temporary file with a new numbering.
+ QString sourceFileName = dviFile->filename;
+ if ((options.isEmpty() == false) || (dviFile->suggestedPageSize != 0) ) {
+ // Get a name for a temporary file.
+ KTempFile export_tmpFile;
+ export_tmpFileName = export_tmpFile.name();
+ export_tmpFile.unlink();
+
+ sourceFileName = export_tmpFileName;
+
+ fontPool fp;
+ dvifile newFile(dviFile, &fp);
+
+ // Renumber pages
+ newFile.renumber();
+
+ // Remove any page size information from the file
+ Q_UINT16 currPageSav = current_page;
+ dvifile *dvsav = dviFile;
+ dviFile = &newFile;
+ errorMsg = QString::null;
+
+
+ for(current_page=0; current_page < newFile.total_pages; current_page++) {
+ if (current_page < newFile.total_pages) {
+ command_pointer = dviFile->dvi_Data() + dviFile->page_offset[current_page];
+ end_pointer = dviFile->dvi_Data() + dviFile->page_offset[current_page+1];
+ } else
+ command_pointer = end_pointer = 0;
+
+ memset((char *) &currinf.data, 0, sizeof(currinf.data));
+ currinf.fonttable = &(dviFile->tn_table);
+ currinf._virtual = NULL;
+ prescan(&dviRenderer::prescan_removePageSizeInfo);
+ }
+
+ current_page = currPageSav;
+ dviFile = dvsav;
+ newFile.saveAs(sourceFileName);
+ }
+
+ // Allocate and initialize the shell process.
+ proc = new KShellProcess();
+ if (proc == 0) {
+ kdError(4300) << "Could not allocate ShellProcess for the dvips command." << endl;
+ return;
+ }
+
+ qApp->connect(proc, SIGNAL(receivedStderr(KProcess *, char *, int)), this, SLOT(dvips_output_receiver(KProcess *, char *, int)));
+ qApp->connect(proc, SIGNAL(receivedStdout(KProcess *, char *, int)), this, SLOT(dvips_output_receiver(KProcess *, char *, int)));
+ qApp->connect(proc, SIGNAL(processExited(KProcess *)), this, SLOT(dvips_terminated(KProcess *)));
+ export_errorString = i18n("<qt>The external program 'dvips', which was used to export the file, reported an error. "
+ "You might wish to look at the <strong>document info dialog</strong> which you will "
+ "find in the File-Menu for a precise error report.</qt>") ;
+ info->clear(i18n("Export: %1 to PostScript").arg(KShellProcess::quote(dviFile->filename)));
+
+ proc->clearArguments();
+ QFileInfo finfo(dviFile->filename);
+ *proc << QString("cd %1; dvips").arg(KShellProcess::quote(finfo.dirPath(true)));
+ if (printer == 0)
+ *proc << "-z"; // export Hyperlinks
+ if (options.isEmpty() == false)
+ *proc << options;
+ *proc << QString("%1").arg(KShellProcess::quote(sourceFileName));
+ *proc << QString("-o %1").arg(KShellProcess::quote(fileName));
+ proc->closeStdin();
+ if (proc->start(KProcess::NotifyOnExit, KProcess::Stderr) == false) {
+ kdError(4300) << "dvips failed to start" << endl;
+ return;
+ }
+ return;
+}
+
+
+void dviRenderer::dvips_output_receiver(KProcess *, char *buffer, int buflen)
+{
+ // Paranoia.
+ if (buflen < 0)
+ return;
+ QString op = QString::fromLocal8Bit(buffer, buflen);
+
+ info->outputReceiver(op);
+ if (progress != 0)
+ progress->show();
+}
+
+
+void dviRenderer::dvips_terminated(KProcess *sproc)
+{
+ // Give an error message from the message string. However, if the
+ // sproc is not the "current external process of interest", i.e. not
+ // the LAST external program that was started by the user, then the
+ // export_errorString, does not correspond to sproc. In that case,
+ // we ingore the return status silently.
+ if ((proc == sproc) && (sproc->normalExit() == true) && (sproc->exitStatus() != 0))
+ KMessageBox::error( parentWidget, export_errorString );
+
+ if (export_printer != 0)
+ export_printer->printFiles( QStringList(export_fileName), true );
+
+ // Kill and delete the remaining process, delete the printer, etc.
+ abortExternalProgramm();
+}
+
+
+void dviRenderer::editorCommand_terminated(KProcess *sproc)
+{
+ // Give an error message from the message string. However, if the
+ // sproc is not the "current external process of interest", i.e. not
+ // the LAST external program that was started by the user, then the
+ // export_errorString, does not correspond to sproc. In that case,
+ // we ingore the return status silently.
+ if ((proc == sproc) && (sproc->normalExit() == true) && (sproc->exitStatus() != 0))
+ KMessageBox::error( parentWidget, export_errorString );
+
+ // Let's hope that this is not all too nasty... killing a
+ // KShellProcess from a slot that was called from the KShellProcess
+ // itself. Until now, there weren't any problems.
+
+ // Perhaps it was a bad idea, after all.
+ //@@@@ delete sproc;
+}
+
+
+void dviRenderer::abortExternalProgramm()
+{
+ delete proc; // Deleting the KProcess kills the child.
+ proc = 0;
+
+ if (export_tmpFileName.isEmpty() != true) {
+ unlink(QFile::encodeName(export_tmpFileName)); // That should delete the file.
+ export_tmpFileName = "";
+ }
+
+ if (progress != 0) {
+ progress->hide();
+ delete progress;
+ progress = 0;
+ }
+
+ delete export_printer;
+ export_printer = 0;
+ export_fileName = "";
+}
diff --git a/kdvi/dviRenderer_prescan.cpp b/kdvi/dviRenderer_prescan.cpp
new file mode 100644
index 00000000..59bdeb25
--- /dev/null
+++ b/kdvi/dviRenderer_prescan.cpp
@@ -0,0 +1,789 @@
+// dviRenderer_prescan.cpp
+//
+// Part of KDVI - A DVI previewer for the KDE desktop environemt
+//
+// (C) 2003--2004 Stefan Kebekus
+// Distributed under the GPL
+
+#include <config.h>
+
+#include "dviRenderer.h"
+#include "dvi.h"
+#include "dviFile.h"
+#include "fontpool.h"
+#include "kdvi_multipage.h"
+#include "performanceMeasurement.h"
+#include "prebookmark.h"
+#include "psgs.h"
+#include "TeXFont.h"
+#include "xdvi.h"
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmimetype.h>
+#include <kprocess.h>
+#include <kprocio.h>
+#include <kprogress.h>
+#include <qapplication.h>
+#include <qbitmap.h>
+#include <qdir.h>
+#include <qfileinfo.h>
+#include <qimage.h>
+#include <qpainter.h>
+#include <qpaintdevice.h>
+
+
+extern QPainter foreGroundPaint;
+extern void parse_special_argument(const QString& strg, const char* argument_name, int* variable);
+
+
+//#define DEBUG_PRESCAN
+
+
+void dviRenderer::prescan_embedPS(char *cp, Q_UINT8 *beginningOfSpecialCommand)
+{
+#ifdef DEBUG_PRESCAN
+ kdDebug(4300) << "dviRenderer::prescan_embedPS( cp = " << cp << " ) " << endl;
+#endif
+
+ // Encapsulated Postscript File
+ if (strncasecmp(cp, "PSfile=", 7) != 0)
+ return;
+
+ QString command(cp+7);
+
+ QString include_command = command.simplifyWhiteSpace();
+
+ // The line is supposed to start with "..ile=", and then comes the
+ // filename. Figure out what the filename is and stow it away. Of
+ // course, this does not work if the filename contains spaces
+ // (already the simplifyWhiteSpace() above is wrong). If you have
+ // files like this, go away.
+ QString EPSfilename = include_command;
+ EPSfilename.truncate(EPSfilename.find(' '));
+
+ // Strip enclosing quotation marks which are included by some LaTeX
+ // macro packages (but not by others). This probably means that
+ // graphic files are no longer found if the filename really does
+ // contain quotes, but we don't really care that much.
+ if ((EPSfilename.at(0) == '\"') && (EPSfilename.at(EPSfilename.length()-1) == '\"'))
+ EPSfilename = EPSfilename.mid(1,EPSfilename.length()-2);
+
+ // If the file is neither a PostScript not a PDF file, we exit here.
+ // The graphic file is later read when the page is rendered.
+ KMimeType::Ptr const mime_type =
+ KMimeType::findByFileContent(EPSfilename);
+ QString const & mime_type_name = mime_type->name();
+
+ bool const is_ps_file = (mime_type_name == "application/postscript" ||
+ mime_type_name == "image/x-eps");
+ bool const is_pdf_file = (!is_ps_file &&
+ mime_type_name == "application/pdf");
+ if (!(is_ps_file || is_pdf_file))
+ return;
+
+ QString originalFName = EPSfilename;
+
+ embedPS_progress->setLabel(i18n("Embedding %1").arg(EPSfilename));
+ qApp->processEvents();
+
+
+ // Now locate the Gfx file on the hard disk...
+ EPSfilename = ghostscript_interface::locateEPSfile(EPSfilename, baseURL);
+
+ // If the EPSfilename really points to a PDF file, convert that file now.
+ if (is_pdf_file)
+ EPSfilename = dviFile->convertPDFtoPS(EPSfilename);
+
+ if (!QFile::exists(EPSfilename)) {
+ // Find the number of the page
+ Q_UINT32 currentOffset = beginningOfSpecialCommand - dviFile->dvi_Data();
+ Q_UINT16 page;
+ for(page=0; page < dviFile->total_pages; page++)
+ if ((dviFile->page_offset[page] <= currentOffset) && (currentOffset <= dviFile->page_offset[page+1]))
+ break;
+ errorMsg += i18n("Page %1: The PostScript file <strong>%2</strong> could not be found.<br>").arg(page+1).arg(originalFName);
+ embedPS_progress->progressBar()->advance(1);
+ qApp->processEvents();
+ return;
+ }
+
+ // Now parse the arguments.
+ int llx = 0;
+ int lly = 0;
+ int urx = 0;
+ int ury = 0;
+ int rwi = 0;
+ int rhi = 0;
+ int angle = 0;
+
+ // just to avoid ambiguities; the filename could contain keywords
+ include_command = include_command.mid(include_command.find(' '));
+
+ parse_special_argument(include_command, "llx=", &llx);
+ parse_special_argument(include_command, "lly=", &lly);
+ parse_special_argument(include_command, "urx=", &urx);
+ parse_special_argument(include_command, "ury=", &ury);
+ parse_special_argument(include_command, "rwi=", &rwi);
+ parse_special_argument(include_command, "rhi=", &rhi);
+ parse_special_argument(include_command, "angle=", &angle);
+
+ int clip=include_command.find(" clip"); // -1 if clip keyword is not present, >= 0 otherwise
+
+ // Generate the PostScript commands to be included
+ QString PS = QString("ps: @beginspecial %1 @llx %2 @lly %3 @urx %4 @ury").arg(llx).arg(lly).arg(urx).arg(ury);
+ if (rwi != 0)
+ PS.append( QString(" %1 @rwi").arg(rwi) );
+ if (rhi != 0)
+ PS.append( QString(" %1 @rhi").arg(rhi) );
+ if (angle != 0)
+ PS.append( QString(" %1 @angle").arg(angle) );
+ if (clip != -1)
+ PS.append(" @clip");
+ PS.append( " @setspecial\n" );
+
+ QFile file( EPSfilename );
+ if ( file.open( IO_ReadOnly ) ) {
+ QTextStream stream( &file );
+ while ( !stream.atEnd() ) {
+ PS += stream.readLine().section( '%', 0, 0);
+ PS += "\n";
+ }
+ file.close();
+ }
+ PS.append( "@endspecial" );
+ PS = PS.simplifyWhiteSpace();
+
+
+ _isModified = true;
+ Q_UINT32 lengthOfOldSpecial = command_pointer - beginningOfSpecialCommand;
+ Q_UINT32 lengthOfNewSpecial = PS.length()+5;
+
+ QMemArray<Q_UINT8> newDVI(dviFile->size_of_file + lengthOfNewSpecial-lengthOfOldSpecial);
+
+ Q_UINT8 *commandPtrSav = command_pointer;
+ Q_UINT8 *endPtrSav = end_pointer;
+ end_pointer = newDVI.data() + dviFile->size_of_file + lengthOfNewSpecial-lengthOfOldSpecial;
+ memcpy(newDVI.data(), dviFile->dvi_Data(), beginningOfSpecialCommand-dviFile->dvi_Data());
+ command_pointer = newDVI.data()+(beginningOfSpecialCommand-dviFile->dvi_Data());
+ command_pointer[0] = XXX4;
+ command_pointer++;
+ writeUINT32(PS.length());
+ memcpy(newDVI.data()+(beginningOfSpecialCommand-dviFile->dvi_Data())+5, PS.latin1(), PS.length() );
+ memcpy(newDVI.data()+(beginningOfSpecialCommand-dviFile->dvi_Data())+lengthOfNewSpecial, beginningOfSpecialCommand+lengthOfOldSpecial,
+ dviFile->size_of_file-(beginningOfSpecialCommand-dviFile->dvi_Data())-lengthOfOldSpecial );
+
+ // Adjust page pointers in the DVI file
+ dviFile->size_of_file = dviFile->size_of_file + lengthOfNewSpecial-lengthOfOldSpecial;
+ end_pointer = newDVI.data() + dviFile->size_of_file;
+ Q_UINT32 currentOffset = beginningOfSpecialCommand-dviFile->dvi_Data();
+ for(Q_UINT16 i=0; i < dviFile->total_pages; i++) {
+ if (dviFile->page_offset[i] > currentOffset) {
+ dviFile->page_offset[i] = dviFile->page_offset[i] + lengthOfNewSpecial-lengthOfOldSpecial;
+ command_pointer = dviFile->page_offset[i] + newDVI.data() + 4*10 + 1;
+ Q_UINT32 a = readUINT32();
+ if (a > currentOffset) {
+ a = a + lengthOfNewSpecial-lengthOfOldSpecial;
+ command_pointer = dviFile->page_offset[i] + newDVI.data() + 4*10 + 1;
+ writeUINT32(a);
+ }
+ }
+ }
+
+
+ dviFile->beginning_of_postamble = dviFile->beginning_of_postamble + lengthOfNewSpecial - lengthOfOldSpecial;
+ dviFile->page_offset[dviFile->total_pages] = dviFile->beginning_of_postamble;
+
+ command_pointer = newDVI.data() + dviFile->beginning_of_postamble + 1;
+ Q_UINT32 a = readUINT32();
+ if (a > currentOffset) {
+ a = a + lengthOfNewSpecial - lengthOfOldSpecial;
+ command_pointer = newDVI.data() + dviFile->beginning_of_postamble + 1;
+ writeUINT32(a);
+ }
+
+ command_pointer = newDVI.data() + dviFile->size_of_file - 1;
+ while((*command_pointer == TRAILER) && (command_pointer > newDVI.data()))
+ command_pointer--;
+ command_pointer -= 4;
+ writeUINT32(dviFile->beginning_of_postamble);
+ command_pointer -= 4;
+
+ command_pointer = commandPtrSav;
+ end_pointer = endPtrSav;
+
+ // Modify all pointers to point to the newly allocated memory
+ command_pointer = newDVI.data() + (command_pointer - dviFile->dvi_Data()) + lengthOfNewSpecial-lengthOfOldSpecial;
+ end_pointer = newDVI.data() + (end_pointer - dviFile->dvi_Data()) + lengthOfNewSpecial-lengthOfOldSpecial;
+
+ dviFile->setNewData(newDVI);
+
+ embedPS_progress->progressBar()->advance(1);
+ qApp->processEvents();
+ return;
+}
+
+
+void dviRenderer::prescan_removePageSizeInfo(char *cp, Q_UINT8 *beginningOfSpecialCommand)
+{
+#ifdef DEBUG_PRESCAN
+ kdDebug(4300) << "dviRenderer::prescan_embedPS( cp = " << cp << " ) " << endl;
+#endif
+
+ // Encapsulated Postscript File
+ if (strncasecmp(cp, "papersize=", 10) != 0)
+ return;
+
+ for (Q_UINT8 *ptr=beginningOfSpecialCommand; ptr<command_pointer; ptr++)
+ *ptr = NOP;
+}
+
+
+void dviRenderer::prescan_ParsePapersizeSpecial(const QString& _cp)
+{
+#ifdef DEBUG_PRESCAN
+ kdDebug(4300) << "Papersize-Special : papersize" << cp << endl;
+#endif
+
+ QString cp = _cp.simplifyWhiteSpace();
+
+ if (cp[0] == '=') {
+ cp = cp.mid(1);
+ dviFile->suggestedPageSize = new pageSize;
+ dviFile->suggestedPageSize->setPageSize(cp);
+ } else
+ printErrorMsgForSpecials(i18n("The papersize data '%1' could not be parsed.").arg(cp));
+
+ return;
+}
+
+
+void dviRenderer::prescan_ParseBackgroundSpecial(const QString& cp)
+{
+ QColor col = parseColorSpecification(cp.stripWhiteSpace());
+ if (col.isValid())
+ for(Q_UINT16 page=current_page; page < dviFile->total_pages; page++)
+ PS_interface->setBackgroundColor(page, col);
+ return;
+}
+
+
+void dviRenderer::prescan_ParseHTMLAnchorSpecial(const QString& _cp)
+{
+ QString cp = _cp;
+ cp.truncate(cp.find('"'));
+ Length l;
+ l.setLength_in_inch(currinf.data.dvi_v/(resolutionInDPI*shrinkfactor));
+ anchorList[cp] = Anchor(current_page+1, l);
+}
+
+
+void dviRenderer::prescan_ParsePSHeaderSpecial(const QString& cp)
+{
+#ifdef DEBUG_PRESCAN
+ kdDebug(4300) << "PostScript-special, header " << cp.latin1() << endl;
+#endif
+
+ QString _file = cp;
+
+ // If the file is not found in the current directory, use kpsewhich
+ // to find it.
+ if (!QFile::exists(_file)) {
+ // Otherwise, use kpsewhich to find the eps file.
+ KProcIO proc;
+ proc << "kpsewhich" << cp;
+ proc.start(KProcess::Block);
+ proc.readln(_file);
+ }
+
+ if (QFile::exists(_file))
+ PS_interface->PostScriptHeaderString->append( QString(" (%1) run\n").arg(_file) );
+}
+
+
+void dviRenderer::prescan_ParsePSBangSpecial(const QString& cp)
+{
+#ifdef DEBUG_PRESCAN
+ kdDebug(4300) << "PostScript-special, literal header " << cp.latin1() << endl;
+#endif
+
+ PS_interface->PostScriptHeaderString->append( " @defspecial \n" );
+ PS_interface->PostScriptHeaderString->append( cp );
+ PS_interface->PostScriptHeaderString->append( " @fedspecial \n" );
+}
+
+
+void dviRenderer::prescan_ParsePSQuoteSpecial(const QString& cp)
+{
+#ifdef DEBUG_PRESCAN
+ kdError(4300) << "PostScript-special, literal PostScript " << cp.latin1() << endl;
+#endif
+
+ double PS_H = (currinf.data.dvi_h*300.0)/(65536*1200)-300;
+ double PS_V = (currinf.data.dvi_v*300.0)/1200 - 300;
+ PostScriptOutPutString->append( QString(" %1 %2 moveto\n").arg(PS_H).arg(PS_V) );
+ PostScriptOutPutString->append( " @beginspecial @setspecial \n" );
+ PostScriptOutPutString->append( cp );
+ PostScriptOutPutString->append( " @endspecial \n" );
+}
+
+
+void dviRenderer::prescan_ParsePSSpecial(const QString& cp)
+{
+#ifdef DEBUG_PRESCAN
+ kdDebug(4300) << "PostScript-special, direct PostScript " << cp << endl;
+#endif
+
+ // Unfortunately, in some TeX distribution the hyperref package uses
+ // the dvips driver by default, rather than the hypertex driver. As
+ // a result, the DVI files produced are full of PostScript that
+ // specifies links and anchors, and KDVI would call the ghostscript
+ // interpreter for every page which makes it really slow. This is a
+ // major nuisance, so that we try to filter and interpret the
+ // hypertex generated PostScript here.
+ if (cp.startsWith("ps:SDict begin")) {
+ // We suspect this may be hyperref generated nonsense. Let's check
+ // for some known code that hyperref generates.
+ if (cp == "ps:SDict begin H.S end")
+ return; // start of hyperref rectangle
+ if (cp == "ps:SDict begin H.R end")
+ return; // end of hyperref rectangle
+ if (cp.endsWith("H.A end"))
+ return; // end of hyperref anchor
+ if (cp.endsWith("H.L end"))
+ return; // end of hyperref link
+ if (cp.startsWith("ps:SDict begin /product where{pop product(Distiller)"))
+ return; // hyperref tries to work around Distiller bug
+ if (cp.startsWith("ps:SDict begin [") && cp.endsWith(" pdfmark end")) { // hyperref definition of link/anchor/bookmark/etc
+ if (cp.contains("/DEST")) { // The PostScript code defines an anchor
+ QString anchorName = cp.section('(', 1, 1).section(')', 0, 0);
+ Length l;
+ l.setLength_in_inch(currinf.data.dvi_v/(resolutionInDPI*shrinkfactor));
+ anchorList[anchorName] = Anchor(current_page+1, l);
+ }
+ // The PostScript code defines a bookmark
+ if (cp.contains("/Dest") && cp.contains("/Title"))
+ prebookmarks.append(PreBookmark(PDFencodingToQString(cp.section('(', 2, 2).section(')', 0, 0)),
+ cp.section('(', 1, 1).section(')', 0, 0),
+ cp.section('-', 1, 1).section(' ', 0, 0).toUInt()
+ ));
+ return;
+ }
+ }
+
+ double PS_H = (currinf.data.dvi_h*300.0)/(65536*1200)-300;
+ double PS_V = (currinf.data.dvi_v*300.0)/1200 - 300;
+
+ if (cp.find("ps::[begin]", 0, false) == 0) {
+ PostScriptOutPutString->append( QString(" %1 %2 moveto\n").arg(PS_H).arg(PS_V) );
+ PostScriptOutPutString->append( QString(" %1\n").arg(cp.mid(11)) );
+ } else {
+ if (cp.find("ps::[end]", 0, false) == 0) {
+ PostScriptOutPutString->append( QString(" %1\n").arg(cp.mid(9)) );
+ } else {
+ if (cp.find("ps::", 0, false) == 0) {
+ PostScriptOutPutString->append( QString(" %1\n").arg(cp.mid(4)) );
+ } else {
+ PostScriptOutPutString->append( QString(" %1 %2 moveto\n").arg(PS_H).arg(PS_V) );
+ PostScriptOutPutString->append( QString(" %1\n").arg(cp.mid(3)) );
+ }
+ }
+ }
+}
+
+
+void dviRenderer::prescan_ParsePSFileSpecial(const QString& cp)
+{
+#ifdef DEBUG_PRESCAN
+ kdDebug(4300) << "epsf-special: psfile=" << cp <<endl;
+#endif
+
+ QString include_command = cp.simplifyWhiteSpace();
+
+ // The line is supposed to start with "..ile=", and then comes the
+ // filename. Figure out what the filename is and stow it away. Of
+ // course, this does not work if the filename contains spaces
+ // (already the simplifyWhiteSpace() above is wrong). If you have
+ // files like this, go away.
+ QString EPSfilename = include_command;
+ EPSfilename.truncate(EPSfilename.find(' '));
+
+ // Strip enclosing quotation marks which are included by some LaTeX
+ // macro packages (but not by others). This probably means that
+ // graphic files are no longer found if the filename really does
+ // contain quotes, but we don't really care that much.
+ if ((EPSfilename.at(0) == '\"') && (EPSfilename.at(EPSfilename.length()-1) == '\"')) {
+ EPSfilename = EPSfilename.mid(1,EPSfilename.length()-2);
+ }
+
+ // If the file name ends in 'png', 'gif', 'jpg' or 'jpeg', we assume
+ // that this is NOT a PostScript file, and we exit here.
+ QString ending = EPSfilename.section('.', -1).lower();
+ if ((ending == "png") || (ending == "gif") || (ending == "jpg") || (ending == "jpeg")) {
+ dviFile->numberOfExternalNONPSFiles++;
+ return;
+ }
+
+ // Now assume that the graphics file *is* a PostScript file
+ dviFile->numberOfExternalPSFiles++;
+
+ // Now locate the Gfx file on the hard disk...
+ EPSfilename = ghostscript_interface::locateEPSfile(EPSfilename, baseURL);
+
+ // If the EPSfilename really points to a PDF file, convert that file now.
+ if (ending == "pdf")
+ EPSfilename = dviFile->convertPDFtoPS(EPSfilename);
+
+ // Now parse the arguments.
+ int llx = 0;
+ int lly = 0;
+ int urx = 0;
+ int ury = 0;
+ int rwi = 0;
+ int rhi = 0;
+ int angle = 0;
+
+ // just to avoid ambiguities; the filename could contain keywords
+ include_command = include_command.mid(include_command.find(' '));
+
+ parse_special_argument(include_command, "llx=", &llx);
+ parse_special_argument(include_command, "lly=", &lly);
+ parse_special_argument(include_command, "urx=", &urx);
+ parse_special_argument(include_command, "ury=", &ury);
+ parse_special_argument(include_command, "rwi=", &rwi);
+ parse_special_argument(include_command, "rhi=", &rhi);
+ parse_special_argument(include_command, "angle=", &angle);
+
+ int clip=include_command.find(" clip"); // -1 if clip keyword is not present, >= 0 otherwise
+
+ if (QFile::exists(EPSfilename)) {
+ double PS_H = (currinf.data.dvi_h*300.0)/(65536*1200)-300;
+ double PS_V = (currinf.data.dvi_v*300.0)/1200 - 300;
+ PostScriptOutPutString->append( QString(" %1 %2 moveto\n").arg(PS_H).arg(PS_V) );
+ PostScriptOutPutString->append( "@beginspecial " );
+ PostScriptOutPutString->append( QString(" %1 @llx").arg(llx) );
+ PostScriptOutPutString->append( QString(" %1 @lly").arg(lly) );
+ PostScriptOutPutString->append( QString(" %1 @urx").arg(urx) );
+ PostScriptOutPutString->append( QString(" %1 @ury").arg(ury) );
+ if (rwi != 0)
+ PostScriptOutPutString->append( QString(" %1 @rwi").arg(rwi) );
+ if (rhi != 0)
+ PostScriptOutPutString->append( QString(" %1 @rhi").arg(rhi) );
+ if (angle != 0)
+ PostScriptOutPutString->append( QString(" %1 @angle").arg(angle) );
+ if (clip != -1)
+ PostScriptOutPutString->append(" @clip");
+ PostScriptOutPutString->append( " @setspecial \n" );
+ PostScriptOutPutString->append( QString(" (%1) run\n").arg(EPSfilename) );
+ PostScriptOutPutString->append( "@endspecial \n" );
+ }
+
+ return;
+}
+
+
+void dviRenderer::prescan_ParseSourceSpecial(const QString& cp)
+{
+ // if no rendering takes place, i.e. when the DVI file is first
+ // loaded, generate a DVI_SourceFileAnchor. These anchors are used
+ // in forward search, i.e. to relate references line
+ // "src:123file.tex" to positions in the DVI file
+
+ // extract the file name and the numeral part from the string
+ Q_UINT32 j;
+ for(j=0;j<cp.length();j++)
+ if (!cp.at(j).isNumber())
+ break;
+ Q_UINT32 sourceLineNumber = cp.left(j).toUInt();
+ QFileInfo fi1(dviFile->filename);
+ QString sourceFileName = QFileInfo(fi1.dir(), cp.mid(j).stripWhiteSpace()).absFilePath();
+ Length l;
+ l.setLength_in_inch(currinf.data.dvi_v/(resolutionInDPI*shrinkfactor));
+ DVI_SourceFileAnchor sfa(sourceFileName, sourceLineNumber, current_page+1, l);
+ sourceHyperLinkAnchors.push_back(sfa);
+}
+
+
+void dviRenderer::prescan_parseSpecials(char *cp, Q_UINT8 *)
+{
+ QString special_command(cp);
+
+ // Now to those specials which are only interpreted during the
+ // prescan phase, and NOT during rendering.
+
+ // PaperSize special
+ if (strncasecmp(cp, "papersize", 9) == 0) {
+ prescan_ParsePapersizeSpecial(special_command.mid(9));
+ return;
+ }
+
+ // color special for background color
+ if (strncasecmp(cp, "background", 10) == 0) {
+ prescan_ParseBackgroundSpecial(special_command.mid(10));
+ return;
+ }
+
+ // HTML anchor special
+ if (strncasecmp(cp, "html:<A name=", 13) == 0) {
+ prescan_ParseHTMLAnchorSpecial(special_command.mid(14));
+ return;
+ }
+
+ // Postscript Header File
+ if (strncasecmp(cp, "header=", 7) == 0) {
+ prescan_ParsePSHeaderSpecial(special_command.mid(7));
+ return;
+ }
+
+ // Literal Postscript Header
+ if (cp[0] == '!') {
+ prescan_ParsePSBangSpecial(special_command.mid(1));
+ return;
+ }
+
+ // Literal Postscript inclusion
+ if (cp[0] == '"') {
+ prescan_ParsePSQuoteSpecial(special_command.mid(1));
+ return;
+ }
+
+ // PS-Postscript inclusion
+ if (strncasecmp(cp, "ps:", 3) == 0) {
+ prescan_ParsePSSpecial(special_command);
+ return;
+ }
+
+ // Encapsulated Postscript File
+ if (strncasecmp(cp, "PSfile=", 7) == 0) {
+ prescan_ParsePSFileSpecial(special_command.mid(7));
+ return;
+ }
+
+ // source special
+ if (strncasecmp(cp, "src:", 4) == 0) {
+ prescan_ParseSourceSpecial(special_command.mid(4));
+ return;
+ }
+
+ // Finally there are those special commands which must be considered
+ // both during rendering and during the pre-scan phase
+
+ // HTML anchor end
+ if (strncasecmp(cp, "html:</A>", 9) == 0) {
+ html_anchor_end();
+ return;
+ }
+
+ return;
+}
+
+
+void dviRenderer::prescan_setChar(unsigned int ch)
+{
+ TeXFontDefinition *fontp = currinf.fontp;
+ if (fontp == NULL)
+ return;
+
+ if (currinf.set_char_p == &dviRenderer::set_char) {
+ glyph *g = ((TeXFont *)(currinf.fontp->font))->getGlyph(ch, true, globalColor);
+ if (g == NULL)
+ return;
+ currinf.data.dvi_h += (int)(currinf.fontp->scaled_size_in_DVI_units * dviFile->getCmPerDVIunit() *
+ (1200.0 / 2.54)/16.0 * g->dvi_advance_in_units_of_design_size_by_2e20 + 0.5);
+ return;
+ }
+
+ if (currinf.set_char_p == &dviRenderer::set_vf_char) {
+ macro *m = &currinf.fontp->macrotable[ch];
+ if (m->pos == NULL)
+ return;
+ currinf.data.dvi_h += (int)(currinf.fontp->scaled_size_in_DVI_units * dviFile->getCmPerDVIunit() *
+ (1200.0 / 2.54)/16.0 * m->dvi_advance_in_units_of_design_size_by_2e20 + 0.5);
+ return;
+ }
+}
+
+
+void dviRenderer::prescan(parseSpecials specialParser)
+{
+#ifdef DEBUG_PRESCAN
+ kdDebug(4300) << "dviRenderer::prescan( ... )" << endl;
+#endif
+
+ if (resolutionInDPI == 0.0)
+ setResolution(100);
+
+ Q_INT32 RRtmp=0, WWtmp=0, XXtmp=0, YYtmp=0, ZZtmp=0;
+ Q_UINT8 ch;
+ double fontPixelPerDVIunit = dviFile->getCmPerDVIunit() * 1200.0/2.54;
+
+ stack.clear();
+
+ currinf.fontp = NULL;
+ currinf.set_char_p = &dviRenderer::set_no_char;
+
+ for (;;) {
+ ch = readUINT8();
+
+ if (ch <= (unsigned char) (SETCHAR0 + 127)) {
+ prescan_setChar(ch);
+ continue;
+ }
+
+ if (FNTNUM0 <= ch && ch <= (unsigned char) (FNTNUM0 + 63)) {
+ currinf.fontp = currinf.fonttable->find(ch - FNTNUM0);
+ if (currinf.fontp == NULL) {
+ errorMsg = i18n("The DVI code referred to font #%1, which was not previously defined.").arg(ch - FNTNUM0);
+ return;
+ }
+ currinf.set_char_p = currinf.fontp->set_char_p;
+ continue;
+ }
+
+
+ Q_INT32 a, b;
+
+ switch (ch) {
+ case SET1:
+ prescan_setChar(readUINT8());
+ break;
+
+ case SETRULE:
+ /* Be careful, dvicopy outputs rules with height =
+ 0x80000000. We don't want any SIGFPE here. */
+ a = readUINT32();
+ b = readUINT32();
+ b = ((long) (b * 65536.0*fontPixelPerDVIunit));
+ currinf.data.dvi_h += b;
+ break;
+
+ case PUTRULE:
+ a = readUINT32();
+ b = readUINT32();
+ break;
+
+ case PUT1:
+ case NOP:
+ break;
+
+ case BOP:
+ command_pointer += 11 * 4;
+ currinf.data.dvi_h = 1200 << 16; // Reminder: DVI-coordinates start at (1",1") from top of page
+ currinf.data.dvi_v = 1200;
+ currinf.data.pxl_v = int(currinf.data.dvi_v/shrinkfactor);
+ currinf.data.w = currinf.data.x = currinf.data.y = currinf.data.z = 0;
+ break;
+
+ case PUSH:
+ stack.push(currinf.data);
+ break;
+
+ case POP:
+ if (stack.isEmpty())
+ return;
+ else
+ currinf.data = stack.pop();
+ break;
+
+ case RIGHT1:
+ case RIGHT2:
+ case RIGHT3:
+ case RIGHT4:
+ RRtmp = readINT(ch - RIGHT1 + 1);
+ currinf.data.dvi_h += ((long) (RRtmp * 65536.0*fontPixelPerDVIunit));
+ break;
+
+ case W1:
+ case W2:
+ case W3:
+ case W4:
+ WWtmp = readINT(ch - W0);
+ currinf.data.w = ((long) (WWtmp * 65536.0*fontPixelPerDVIunit));
+ case W0:
+ currinf.data.dvi_h += currinf.data.w;
+ break;
+
+ case X1:
+ case X2:
+ case X3:
+ case X4:
+ XXtmp = readINT(ch - X0);
+ currinf.data.x = ((long) (XXtmp * 65536.0*fontPixelPerDVIunit));
+ case X0:
+ currinf.data.dvi_h += currinf.data.x;
+ break;
+
+ case DOWN1:
+ case DOWN2:
+ case DOWN3:
+ case DOWN4:
+ {
+ Q_INT32 DDtmp = readINT(ch - DOWN1 + 1);
+ currinf.data.dvi_v += ((long) (DDtmp * 65536.0*fontPixelPerDVIunit))/65536;
+ currinf.data.pxl_v = int(currinf.data.dvi_v/shrinkfactor);
+ }
+ break;
+
+ case Y1:
+ case Y2:
+ case Y3:
+ case Y4:
+ YYtmp = readINT(ch - Y0);
+ currinf.data.y = ((long) (YYtmp * 65536.0*fontPixelPerDVIunit));
+ case Y0:
+ currinf.data.dvi_v += currinf.data.y/65536;
+ currinf.data.pxl_v = int(currinf.data.dvi_v/shrinkfactor);
+ break;
+
+ case Z1:
+ case Z2:
+ case Z3:
+ case Z4:
+ ZZtmp = readINT(ch - Z0);
+ currinf.data.z = ((long) (ZZtmp * 65536.0*fontPixelPerDVIunit));
+ case Z0:
+ currinf.data.dvi_v += currinf.data.z/65536;
+ currinf.data.pxl_v = int(currinf.data.dvi_v/shrinkfactor);
+ break;
+
+ case FNT1:
+ case FNT2:
+ case FNT3:
+ case FNT4:
+ currinf.fontp = currinf.fonttable->find(readUINT(ch - FNT1 + 1));
+ if (currinf.fontp == NULL)
+ return;
+ currinf.set_char_p = currinf.fontp->set_char_p;
+ break;
+
+ case XXX1:
+ case XXX2:
+ case XXX3:
+ case XXX4:
+ {
+ Q_UINT8 *beginningOfSpecialCommand = command_pointer-1;
+ a = readUINT(ch - XXX1 + 1);
+ if (a > 0) {
+ char *cmd = new char[a+1];
+ strncpy(cmd, (char *)command_pointer, a);
+ command_pointer += a;
+ cmd[a] = '\0';
+ (this->*specialParser)(cmd, beginningOfSpecialCommand);
+ delete [] cmd;
+ }
+ }
+ break;
+
+ case FNTDEF1:
+ case FNTDEF2:
+ case FNTDEF3:
+ case FNTDEF4:
+ command_pointer += 12 + ch - FNTDEF1 + 1;
+ command_pointer += readUINT8() + readUINT8();
+ break;
+
+ default:
+ return;
+ } /* end switch */
+ } /* end for */
+}
diff --git a/kdvi/dviWidget.cpp b/kdvi/dviWidget.cpp
new file mode 100644
index 00000000..8475af92
--- /dev/null
+++ b/kdvi/dviWidget.cpp
@@ -0,0 +1,123 @@
+//
+// Class: DVIWidget
+//
+// Widget for displaying TeX DVI files.
+// Part of KDVI- A previewer for TeX DVI files.
+//
+// (C) 2004 Wilfried Huss, Stefan Kebekus
+// Distributed under the GPL
+//
+
+#include <config.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "dviWidget.h"
+
+#include "documentPageCache.h"
+#include "documentWidget.h"
+#include "hyperlink.h"
+#include "pageView.h"
+#include "renderedDviPagePixmap.h"
+#include "selection.h"
+
+DVIWidget::DVIWidget(QWidget* parent, PageView* sv, DocumentPageCache* cache, const char* name)
+ : DocumentWidget(parent, sv, cache, name)
+{
+}
+
+
+void DVIWidget::mousePressEvent(QMouseEvent* e)
+{
+ // pageNr == 0 indicated an invalid page (e.g. page number not yet set)
+ if (pageNr == 0)
+ return;
+
+ // Get a pointer to the page contents
+ RenderedDviPagePixmap* pageData = dynamic_cast<RenderedDviPagePixmap*>(documentCache->getPage(pageNr));
+ if (pageData == 0)
+ {
+ kdDebug(4300) << "DVIWidget::mousePressEvent(...) pageData for page #" << pageNr << " is empty" << endl;
+ return;
+ }
+
+ // Check if the mouse is pressed on a source-hyperlink
+ // source hyperlinks can be invoked with the Middle Mousebutton or alternatively
+ // with Control+Left Mousebutton
+ if ((e->button() == MidButton || (e->button() == LeftButton && (e->state() & ControlButton)))
+ && (pageData->sourceHyperLinkList.size() > 0))
+ {
+ int minIndex = 0;
+ int minimum = 0;
+
+ for(unsigned int i=0; i<pageData->sourceHyperLinkList.size(); i++)
+ {
+ if (pageData->sourceHyperLinkList[i].box.contains(e->pos()))
+ {
+ emit(SRCLink(pageData->sourceHyperLinkList[i].linkText, e, this));
+ e->accept();
+ return;
+ }
+ // Remember the closest source link
+ QPoint center = pageData->sourceHyperLinkList[i].box.center();
+ int dx = center.x() - e->pos().x();
+ int dy = center.y() - e->pos().y();
+ if (dx*dx + dy*dy < minimum || i == 0)
+ {
+ minIndex = i;
+ minimum = dx*dx + dy*dy;
+ }
+ }
+ // If the mouse pointer is not exactly inside a source link, jump to the closest target.
+ emit(SRCLink(pageData->sourceHyperLinkList[minIndex].linkText, e, this));
+ e->accept();
+ }
+
+ // Call implementation from parent
+ DocumentWidget::mousePressEvent(e);
+}
+
+
+void DVIWidget::mouseMoveEvent(QMouseEvent* e)
+{
+ // pageNr == 0 indicated an invalid page (e.g. page number not yet set)
+ if (pageNr == 0)
+ return;
+
+ // Call the standard implementation
+ DocumentWidget::mouseMoveEvent(e);
+
+ // Analyze the mouse movement only if no mouse button was pressed
+ if ( e->state() == 0 ) {
+ // Get a pointer to the page contents
+ RenderedDviPagePixmap* pageData = dynamic_cast<RenderedDviPagePixmap*>(documentCache->getPage(pageNr));
+ if (pageData == 0) {
+ kdDebug(4300) << "DVIWidget::mouseMoveEvent(...) pageData for page #" << pageNr << " is empty" << endl;
+ return;
+ }
+
+ // Check if the cursor hovers over a sourceHyperlink.
+ for(unsigned int i=0; i<pageData->sourceHyperLinkList.size(); i++) {
+ if (pageData->sourceHyperLinkList[i].box.contains(e->pos())) {
+ clearStatusBarTimer.stop();
+
+ // The macro-package srcltx gives a special like "src:99 test.tex"
+ // while MikTeX gives "src:99test.tex". KDVI tries
+ // to understand both.
+ QString cp = pageData->sourceHyperLinkList[i].linkText;
+ int max = cp.length();
+ int i;
+ for(i=0; i<max; i++)
+ if (cp[i].isDigit() == false)
+ break;
+
+ emit setStatusBarText( i18n("line %1 of %2").arg(cp.left(i)).arg(cp.mid(i).simplifyWhiteSpace()) );
+ return;
+ }
+ }
+ }
+}
+
+
+#include "dviWidget.moc"
diff --git a/kdvi/dviWidget.h b/kdvi/dviWidget.h
new file mode 100644
index 00000000..7c008d5a
--- /dev/null
+++ b/kdvi/dviWidget.h
@@ -0,0 +1,38 @@
+// -*- C++ -*-
+//
+// Class: DVIWidget
+//
+// Widget for displaying TeX DVI files.
+// Part of KDVI- A previewer for TeX DVI files.
+//
+// (C) 2004 Wilfried Huss. Distributed under the GPL.
+
+#ifndef _DVIWIDGET_H_
+#define _DVIWIDGET_H_
+
+#include "documentWidget.h"
+
+class PageView;
+class DocumentPageCache;
+class QPaintEvent;
+class QMouseEvent;
+class QWidget;
+class textSelection;
+
+
+class DVIWidget : public DocumentWidget
+{
+ Q_OBJECT
+
+public:
+ DVIWidget(QWidget* parent, PageView* sv, DocumentPageCache* cache, const char* name);
+
+signals:
+ void SRCLink(const QString&, QMouseEvent* e, DocumentWidget*);
+
+private:
+ virtual void mousePressEvent(QMouseEvent* e);
+ virtual void mouseMoveEvent(QMouseEvent* e);
+};
+
+#endif
diff --git a/kdvi/dvisourcesplitter.cpp b/kdvi/dvisourcesplitter.cpp
new file mode 100644
index 00000000..a052a10a
--- /dev/null
+++ b/kdvi/dvisourcesplitter.cpp
@@ -0,0 +1,95 @@
+//
+// C++ Implementation: dvisourcesplitter
+//
+// Author: Jeroen Wijnhout <Jeroen.Wijnhout@kdemail.net>, (C) 2004
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+
+#include <config.h>
+
+#include <qdir.h>
+#include <kdebug.h>
+
+#include "dvisourcesplitter.h"
+
+//#define DEBUG_SOURCESPLITTER
+
+
+DVI_SourceFileSplitter::DVI_SourceFileSplitter(const QString &srclink, const QString &dviFile)
+{
+ QString filepart = srclink, linepart;
+ bool possibleNumberMixUp = false; //if sourcefilename starts with a number
+ //then there could be a mix up, i.e. src:123file.tex
+ //line 123 and file.tex or line 12 and 3file.tex?
+
+#ifdef DEBUG_SOURCESPLITTER
+ kdDebug(4300) << "DVI_SourceSplitter: srclink " << srclink << endl;
+#endif
+
+ //remove src: if necessary
+ if ( filepart.left(4) == "src:" ) filepart = srclink.mid(4);
+
+ //split first
+ Q_UINT32 max = filepart.length(), i = 0;
+ for(i=0; i<max; ++i) if ( !filepart[i].isDigit()) break;
+ linepart = filepart.left(i);
+ filepart = filepart.mid(i);
+
+ //check for number mix up
+ if ( filepart[0] != ' ' && (linepart.length() != 1) ) possibleNumberMixUp = true;
+
+ //remove a spaces
+ filepart = filepart.stripWhiteSpace();
+ linepart = linepart.stripWhiteSpace();
+
+#ifdef DEBUG_SOURCESPLITTER
+ kdDebug() << "DVI_SourceSplitter: filepart " << filepart << " linepart " << linepart << endl;
+#endif
+
+ //test if the file exists
+ m_fileInfo.setFile(QFileInfo(dviFile).dir(true), filepart);
+ bool fiExists = m_fileInfo.exists();
+
+ //if it doesn't exist, but adding ".tex"
+ if ( !fiExists && QFileInfo(m_fileInfo.absFilePath() + ".tex").exists() )
+ m_fileInfo.setFile(m_fileInfo.absFilePath() + ".tex");
+
+ //if that doesn't help either, perhaps the file started with a
+ //number: move the numbers from the sourceline to the filename
+ //one by one (also try to add .tex repeatedly)
+ if ( possibleNumberMixUp && !fiExists )
+ {
+ QFileInfo tempInfo(m_fileInfo);
+ QString tempFileName = tempInfo.fileName();
+ Q_UINT32 index, maxindex = linepart.length();
+ bool found = false;
+ for ( index = 1; index < maxindex; ++index)
+ {
+ tempInfo.setFile(linepart.right(index) + tempFileName);
+#ifdef DEBUG_SOURCESPLITTER
+ kdDebug() << "DVI_SourceSplitter: trying " << tempInfo.fileName() << endl;
+#endif
+ if ( tempInfo.exists() ) { found = true; break;}
+ tempInfo.setFile(linepart.right(index) + tempFileName + ".tex");
+#ifdef DEBUG_SOURCESPLITTER
+ kdDebug() << "DVI_SourceSplitter: trying " << tempInfo.fileName() << endl;
+#endif
+ if ( tempInfo.exists() ) { found = true; break;}
+ }
+
+ if (found)
+ {
+ m_fileInfo = tempInfo;
+ linepart = linepart.left(maxindex - index);
+ }
+ }
+
+ bool ok;
+ m_line = linepart.toInt(&ok);
+ if (!ok) m_line = 0;
+
+#ifdef DEBUG_SOURCESPLITTER
+ kdDebug() << "DVI_SourceSplitter: result: file " << m_fileInfo.absFilePath() << " line " << m_line << endl;
+#endif
+}
diff --git a/kdvi/dvisourcesplitter.h b/kdvi/dvisourcesplitter.h
new file mode 100644
index 00000000..f0028bf2
--- /dev/null
+++ b/kdvi/dvisourcesplitter.h
@@ -0,0 +1,34 @@
+// -*- C++ -*-
+//
+// C++ Interface: dvisourcesplitter
+//
+// Author: Jeroen Wijnhout <Jeroen.Wijnhout@kdemail.net>, (C) 2004
+//
+// Copyright: See COPYING file that comes with this distribution
+//
+
+#ifndef DVI_SOURCEFILESPLITTER_H
+#define DVI_SOURCEFILESPLITTER_H
+
+#include <qfileinfo.h>
+
+class QString;
+
+
+class DVI_SourceFileSplitter
+{
+public:
+ DVI_SourceFileSplitter(const QString & scrlink, const QString & dviFile);
+
+ QString fileName() { return m_fileInfo.fileName(); }
+ QString filePath() { return m_fileInfo.absFilePath(); }
+ bool fileExists() { return m_fileInfo.exists(); }
+
+ Q_UINT32 line() { return m_line; }
+
+private:
+ QFileInfo m_fileInfo;
+ Q_UINT32 m_line;
+ bool m_exists;
+};
+#endif
diff --git a/kdvi/examples/BrokenDVI1.dvi b/kdvi/examples/BrokenDVI1.dvi
new file mode 100644
index 00000000..4f189853
--- /dev/null
+++ b/kdvi/examples/BrokenDVI1.dvi
Binary files differ
diff --git a/kdvi/examples/Font_not_found.dvi b/kdvi/examples/Font_not_found.dvi
new file mode 100644
index 00000000..4ba6383f
--- /dev/null
+++ b/kdvi/examples/Font_not_found.dvi
Binary files differ
diff --git a/kdvi/examples/dvistd0.dvi b/kdvi/examples/dvistd0.dvi
new file mode 100644
index 00000000..ef73e604
--- /dev/null
+++ b/kdvi/examples/dvistd0.dvi
Binary files differ
diff --git a/kdvi/fontEncoding.cpp b/kdvi/fontEncoding.cpp
new file mode 100644
index 00000000..0ca83372
--- /dev/null
+++ b/kdvi/fontEncoding.cpp
@@ -0,0 +1,87 @@
+// fontEncoding.cpp
+//
+// Part of KDVI - A DVI previewer for the KDE desktop environemt
+//
+// (C) 2003 Stefan Kebekus
+// Distributed under the GPL
+
+#include <config.h>
+#ifdef HAVE_FREETYPE
+
+#include <kdebug.h>
+#include <kprocio.h>
+#include <qfile.h>
+#include <qstringlist.h>
+
+#include "fontEncoding.h"
+
+//#define DEBUG_FONTENC
+
+fontEncoding::fontEncoding(const QString &encName)
+{
+#ifdef DEBUG_FONTENC
+ kdDebug(4300) << "fontEncoding( " << encName << " )" << endl;
+#endif
+
+ _isValid = false;
+ // Use kpsewhich to find the encoding file.
+ KProcIO proc;
+ QString encFileName;
+ proc << "kpsewhich" << encName;
+ if (proc.start(KProcess::Block) == false) {
+ kdError(4300) << "fontEncoding::fontEncoding(...): kpsewhich could not be started." << endl;
+ return;
+ }
+ proc.readln(encFileName);
+ encFileName = encFileName.stripWhiteSpace();
+
+ if (encFileName.isEmpty()) {
+ kdError(4300) << QString("fontEncoding::fontEncoding(...): The file '%1' could not be found by kpsewhich.").arg(encName) << endl;
+ return;
+ }
+
+#ifdef DEBUG_FONTENC
+ kdDebug(4300) << "FileName of the encoding: " << encFileName << endl;
+#endif
+
+ QFile file( encFileName );
+ if ( file.open( IO_ReadOnly ) ) {
+ // Read the file (excluding comments) into the QString variable
+ // 'fileContent'
+ QTextStream stream( &file );
+ QString fileContent;
+ while ( !stream.atEnd() )
+ fileContent += stream.readLine().section('%', 0, 0); // line of text excluding '\n' until first '%'-sign
+ file.close();
+
+ fileContent = fileContent.stripWhiteSpace();
+
+ // Find the name of the encoding
+ encodingFullName = fileContent.section('[', 0, 0).simplifyWhiteSpace().mid(1);
+#ifdef DEBUG_FONTENC
+ kdDebug(4300) << "encodingFullName: " << encodingFullName << endl;
+#endif
+
+ fileContent = fileContent.section('[', 1, 1).section(']',0,0).simplifyWhiteSpace();
+ QStringList glyphNameList = QStringList::split( '/', fileContent );
+
+ int i = 0;
+ for ( QStringList::Iterator it = glyphNameList.begin(); (it != glyphNameList.end())&&(i<256); ++it ) {
+ glyphNameVector[i] = (*it).simplifyWhiteSpace();
+#ifdef DEBUG_FONTENC
+ kdDebug(4300) << i << ": " << glyphNameVector[i] << endl;
+#endif
+ i++;
+ }
+ for(; i<256; i++)
+ glyphNameVector[i] = ".notdef";
+ } else {
+ kdError(4300) << QString("fontEncoding::fontEncoding(...): The file '%1' could not be opened.").arg(encFileName) << endl;
+ return;
+ }
+
+ _isValid = true;
+}
+
+
+#endif // HAVE_FREETYPE
diff --git a/kdvi/fontEncoding.h b/kdvi/fontEncoding.h
new file mode 100644
index 00000000..b5ca1344
--- /dev/null
+++ b/kdvi/fontEncoding.h
@@ -0,0 +1,86 @@
+// -*- C++ -*-
+// fontEncoding.h
+//
+// Part of KDVI - A DVI previewer for the KDE desktop environemt
+//
+// (C) 2003 Stefan Kebekus
+// Distributed under the GPL
+
+#ifndef _FONTENCODING_H
+#define _FONTENCODING_H
+
+#include <qstring.h>
+
+
+/**
+ * This class represents the contents of a font encoding file,
+ * e.g. "8r.enc"
+ *
+ * Explanation of font encodings: TeX was designed to only use
+ * MetaFont fonts. A DVI file referres to a MetaFont font by giving an
+ * at-most-8-character name, such as 'cmr10'. The DVI previewer would
+ * then locate the associated PK font file (e.g. cmr10.600pk), load
+ * it, and retrieve the character shaped.
+ *
+ * Today TeX is also used to access Type1 and TrueType fonts, which it
+ * was never designed to do. As in the case of MetaFont font, the DVI
+ * file specifies the name of a font, e.g. 'rpbkd', and the DVI
+ * previewer finds the associated font file 'ubkd8a.pfb' by means of a
+ * map file (see fontMap.h). The font map file also specifies an
+ * encoding (e.g. '8r', to be found in a file '8r.enc'). Font
+ * encodings are necessary because TeX can only use the first 256
+ * characters of a font, while modern PostScript fonts often contain
+ * more.
+ *
+ * In a PostScript font, glyphs can often be accessed in two ways:
+ *
+ * (a) by an integer, the 'glyph index', which need not be
+ * positive. Glyph indices can be found in every font.
+ *
+ * (b) by the name of the glyph, such as 'A', 'plusminus' or
+ * 'ogonek'. Note: Not all fonts contain glyph names, and if a font
+ * contains glyph names, they are not always reliable.
+ *
+ * An encoding file is essentially a list of 256 names of glyphs that
+ * TeX wishes to use from a certain font. If the font contains more
+ * than 256 glyphs, TeX is still limited to use at most 256 glyphs. If
+ * more glyphs are required, TeX can probably use the same font under
+ * a different name and with a different encoding ---the map file
+ * (fontMap.h) can probably see to that.
+ *
+ * Summing up: this class contains 256 glyph names read from an
+ * encoding file during the construction of this class.
+ *
+ * @author Stefan Kebekus <kebekus@kde.org>
+ *
+ **/
+
+class fontEncoding {
+ public:
+ // The constructor takes the name of an encoding file, such as
+ // '8r.enc', locate the file on the hard disk using the 'kpsewhich'
+ // command, reads it in and parses it. If the file cannot be
+ // located, opened or parsed, errors are printed using the kdError()
+ // channel, and the array glyphNameVector will contain empty
+ // strings.
+ fontEncoding(const QString &encName);
+
+ // Full name of the encoding, as read from the encoding file
+ QString encodingFullName;
+
+ // List of 256 glyph names. The name can be '.notdef' to indicate
+ // that a certain position is left open, or empty, if the encoding
+ // file did not contain 256 characters or could not be properly read
+ QString glyphNameVector[256];
+
+ // Returns 'true' if the encoding file was found and could
+ // successfully be loaded.
+ bool isValid() {return _isValid;}
+
+ private:
+ // Set by the constructor to 'true', if the encoding file was found
+ // and could be loaded successfully.
+ bool _isValid;
+};
+
+#endif
diff --git a/kdvi/fontEncodingPool.cpp b/kdvi/fontEncodingPool.cpp
new file mode 100644
index 00000000..0100ee90
--- /dev/null
+++ b/kdvi/fontEncodingPool.cpp
@@ -0,0 +1,37 @@
+// fontEncodingPool.cpp
+//
+// Part of KDVI - A DVI previewer for the KDE desktop environemt
+//
+// (C) 2003 Stefan Kebekus
+// Distributed under the GPL
+
+#include <config.h>
+#ifdef HAVE_FREETYPE
+
+
+#include "fontEncodingPool.h"
+
+fontEncodingPool::fontEncodingPool()
+{
+}
+
+
+fontEncoding *fontEncodingPool::findByName(const QString &name)
+{
+ fontEncoding *ptr = dictionary.find( name );
+
+ if (ptr == 0) {
+ ptr = new fontEncoding(name);
+ if (ptr->isValid())
+ dictionary.insert(name, ptr );
+ else {
+ delete ptr;
+ ptr = 0;
+ }
+ }
+
+ return ptr;
+}
+
+
+#endif // HAVE_FREETYPE
diff --git a/kdvi/fontEncodingPool.h b/kdvi/fontEncodingPool.h
new file mode 100644
index 00000000..b875bf52
--- /dev/null
+++ b/kdvi/fontEncodingPool.h
@@ -0,0 +1,29 @@
+// -*- C++ -*-
+// fontEncodingPool.h
+//
+// Part of KDVI - A DVI previewer for the KDE desktop environemt
+//
+// (C) 2003 Stefan Kebekus
+// Distributed under the GPL
+
+#ifndef _FONTENCODINGPOOL_H
+#define _FONTENCODINGPOOL_H
+
+#include "fontEncoding.h"
+
+#include <qdict.h>
+
+class QString;
+
+
+class fontEncodingPool {
+ public:
+ fontEncodingPool();
+
+ fontEncoding *findByName(const QString &name);
+
+ private:
+ QDict<fontEncoding> dictionary;
+};
+
+#endif
diff --git a/kdvi/fontMap.cpp b/kdvi/fontMap.cpp
new file mode 100644
index 00000000..cf5fa841
--- /dev/null
+++ b/kdvi/fontMap.cpp
@@ -0,0 +1,159 @@
+// fontMap.cpp
+//
+// Part of KDVI - A DVI previewer for the KDE desktop environemt
+//
+// (C) 2003 Stefan Kebekus
+// Distributed under the GPL
+
+#include <config.h>
+#ifdef HAVE_FREETYPE
+
+#include <kdebug.h>
+#include <kprocio.h>
+#include <qfile.h>
+
+#include "fontMap.h"
+
+//#define DEBUG_FONTMAP
+
+fontMap::fontMap()
+{
+ // Read the map file of ps2pk which will provide us with a
+ // dictionary "TeX Font names" <-> "Name of font files, Font Names
+ // and Encodings" (example: the font "Times-Roman" is called
+ // "ptmr8y" in the DVI file, but the Type1 font file name is
+ // "utmr8a.pfb". We use the map file of "ps2pk" because that progam
+ // has, like kdvi (and unlike dvips), no built-in fonts.
+
+ // Finding ps2pk.map is not easy. In teTeX < 3.0, the kpsewhich
+ // program REQUIRES the option "--format=dvips config". In teTeX =
+ // 3.0, the option "--format=map" MUST be used. Since there is no
+ // way to give both options at the same time, there is seemingly no
+ // other way than to try both options one after another. We use the
+ // teTeX 3.0 format first.
+ KProcIO proc;
+ proc << "kpsewhich" << "--format=map" << "ps2pk.map";
+ if (proc.start(KProcess::Block) == false) {
+ kdError(4700) << "fontMap::fontMap(): kpsewhich could not be started." << endl;
+ return;
+ }
+
+ QString map_fileName;
+ proc.readln(map_fileName);
+ map_fileName = map_fileName.stripWhiteSpace();
+ if (map_fileName.isEmpty()) {
+ // Map file not found? Then we try the teTeX < 3.0 way of finding
+ // the file.
+ proc << "kpsewhich" << "--format=dvips config" << "ps2pk.map";
+ if (proc.start(KProcess::Block) == false) {
+ kdError(4700) << "fontMap::fontMap(): kpsewhich could not be started." << endl;
+ return;
+ }
+ proc.readln(map_fileName);
+ map_fileName = map_fileName.stripWhiteSpace();
+
+ // If both versions fail, then there is nothing left to do.
+ if (map_fileName.isEmpty()) {
+ kdError(4700) << "fontMap::fontMap(): The file 'ps2pk.map' could not be found by kpsewhich." << endl;
+ return;
+ }
+ }
+
+ QFile file( map_fileName );
+ if ( file.open( IO_ReadOnly ) ) {
+ QTextStream stream( &file );
+ QString line;
+ while ( !stream.atEnd() ) {
+ line = stream.readLine().simplifyWhiteSpace();
+ if (line.at(0) == '%')
+ continue;
+
+ QString TeXName = line.section(' ', 0, 0);
+ QString FullName = line.section(' ', 1, 1);
+ QString fontFileName = line.section('<', -1).stripWhiteSpace().section(' ', 0, 0);
+ QString encodingName = line.section('<', -2, -2).stripWhiteSpace().section(' ', 0, 0);
+ // It seems that sometimes the encoding is prepended by the
+ // letter '[', which we ignore
+ if ((!encodingName.isEmpty()) && (encodingName[0] == '['))
+ encodingName = encodingName.mid(1);
+
+ double slant = 0.0;
+ int i = line.find("SlantFont");
+ if (i >= 0) {
+ bool ok;
+ slant = line.left(i).section(' ', -1, -1 ,QString::SectionSkipEmpty).toDouble(&ok);
+ if (ok == false)
+ slant = 0.0;
+ }
+
+ fontMapEntry &entry = fontMapEntries[TeXName];
+
+ entry.slant = slant;
+ entry.fontFileName = fontFileName;
+ entry.fullFontName = FullName;
+ if (encodingName.endsWith(".enc"))
+ entry.fontEncoding = encodingName;
+ else
+ entry.fontEncoding = QString::null;
+ }
+ file.close();
+ } else
+ kdError(4300) << QString("fontMap::fontMap(): The file '%1' could not be opened.").arg(map_fileName) << endl;
+
+#ifdef DEBUG_FONTMAP
+ kdDebug(4300) << "FontMap file parsed. Results:" << endl;
+ QMap<QString, fontMapEntry>::Iterator it;
+ for ( it = fontMapEntries.begin(); it != fontMapEntries.end(); ++it )
+ kdDebug(4300) << "TeXName: " << it.key()
+ << ", FontFileName=" << it.data().fontFileName
+ << ", FullName=" << it.data().fullFontName
+ << ", Encoding=" << it.data().fontEncoding
+ << "." << endl;;
+#endif
+}
+
+
+const QString &fontMap::findFileName(const QString &TeXName)
+{
+ QMap<QString, fontMapEntry>::Iterator it = fontMapEntries.find(TeXName);
+
+ if (it != fontMapEntries.end())
+ return it.data().fontFileName;
+ else
+ return QString::null;
+}
+
+
+const QString &fontMap::findFontName(const QString &TeXName)
+{
+ QMap<QString, fontMapEntry>::Iterator it = fontMapEntries.find(TeXName);
+
+ if (it != fontMapEntries.end())
+ return it.data().fullFontName;
+ else
+ return QString::null;
+}
+
+
+const QString &fontMap::findEncoding(const QString &TeXName)
+{
+ QMap<QString, fontMapEntry>::Iterator it = fontMapEntries.find(TeXName);
+
+ if (it != fontMapEntries.end())
+ return it.data().fontEncoding;
+ else
+ return QString::null;
+}
+
+
+double fontMap::findSlant(const QString &TeXName)
+{
+ QMap<QString, fontMapEntry>::Iterator it = fontMapEntries.find(TeXName);
+
+ if (it != fontMapEntries.end())
+ return it.data().slant;
+ else
+ return 0.0;
+}
+
+#endif // HAVE_FREETYPE
diff --git a/kdvi/fontMap.h b/kdvi/fontMap.h
new file mode 100644
index 00000000..55e44082
--- /dev/null
+++ b/kdvi/fontMap.h
@@ -0,0 +1,118 @@
+// -*- C++ -*-
+// fontMap.h
+//
+// Part of KDVI - A DVI previewer for the KDE desktop environemt
+//
+// (C) 2003 Stefan Kebekus
+// Distributed under the GPL
+
+#ifndef _FONTMAP_H
+#define _FONTMAP_H
+
+#include <qmap.h>
+#include <qstring.h>
+
+/**
+ * This class represents one line of a font map file, and contains
+ * three pieces of information about a font: its file name, the full
+ * name of the font, and the encoding.
+ *
+ * @author Stefan Kebekus <kebekus@kde.org>
+ **/
+
+class fontMapEntry {
+ public:
+ // File name of the font WITHOUT the path. The full path name must
+ // be looked by using the kpathsea library, e.g. by means of the
+ // kpsewhich command. A valid entry would be 'ubkd8a.pfb'
+ QString fontFileName;
+
+ // This string contains the full name of the font,
+ // e.g. 'URWBookmanL-DemiBold'
+ QString fullFontName;
+
+ // If the font requires an encoding (see fontEncoding.h for an
+ // explanation), this string is not empty and contains the name of
+ // the encoding, e.g. '8r'. The path of the associated encoding file
+ // (on the author's machine: /usr/share/texmf/dvips/psnfss/8r.enc)
+ // must be looked up using the kpsewhich comman.
+ QString fontEncoding;
+
+ // Some fonts need to be slanted, and the font map file defines by
+ // how much. This field is set to 0.0 if no slanting is specified in
+ // the map file.
+ double slant;
+};
+
+
+/**
+ * This class represents the contents of the font map file "ps2pk.map"
+ *
+ * A font map file is part of the machinery that make it possible to
+ * access PostScript (and possibly also TrueType and OpenType) fonts
+ * from a DVI file.
+ *
+ * Long time ago, when TeX was only used with MetaFont fonts, the DVI
+ * file would specify a font by giving an 8-character name, such as
+ * 'cmr10'. The DVI previewer would then locate the associated PK font
+ * file, load it, and retrieve the character shaped. Happy times, they
+ * were.
+ *
+ * Today TeX is also used to access Type1 and TrueType fonts, which do
+ * not fit well into the TeX naming scheme. Like in earlier times, the
+ * DVI file specifies the name of a font, e.g. 'rpbkd', but nowadays
+ * the DVI previewer cannot just go and find a file 'rpbkd.pk'. No,
+ * no. Instead, the DVI previewr needs to look up the meaning of
+ * 'rpbkd' in a map-file. There it finds that 'rpbkd' refers to a font
+ * called 'URWBookmanL-DemiBold', to be found under the file name
+ * 'ubkd8a.pfb' whose glyphs are to be encoded using the '8a' encoding
+ * file (see the header file 'fontEncoding.h' for more information
+ * about encodings)
+ *
+ * Such map files exists for all dvi output drivers that are part of
+ * the TeX distribution that is installed on your
+ * computer. Unfortunately, KDVI is not part of a TeX distribution,
+ * and therefore does not have its own map file. As a workaround, KDVI
+ * uses the map file of the program ps2pk which is similar to KDVI in
+ * that the ps2pk driver does not have built-in fonts, unlike the
+ * PostScript printers for which dvips is used.
+ *
+ * @author Stefan Kebekus <kebekus@kde.org>
+ *
+ **/
+
+class fontMap {
+ public:
+ /** The default constructor will try to locate the file 'ps2pk.map',
+ and read its contents. If the file 'ps2pk.map' cannot be found
+ using the kpsewhich command, or if it cannot be read, or is
+ (partially) in an improper format, an error message is printed
+ to stderr using the kdDebug() stream. */
+ fontMap( void );
+
+ /** find the name of a font file (e.g. 'ubkd8a.pfb') from a TeX font
+ name (e.g. 'rpbkd'). This method return a reference to
+ QString::null if the font could not be found. */
+ const QString &findFileName(const QString &TeXName);
+
+ /** find the name of a font (e.g. 'URWBookmanL-DemiBold') from a TeX
+ font name (e.g. 'rpbkd'). This method return a reference to
+ QString::null if the font could not be found. */
+ const QString &findFontName(const QString &TeXName);
+
+ /** find the name of an encoding file for a font (e.g. '8r') from a
+ TeX font name (e.g. 'rpbkd'). This method return a reference to
+ QString::null if the font could not be found. */
+ const QString &findEncoding(const QString &TeXName);
+
+ /** This method finds the slant of a font. Returns 0.0 if no slant
+ was defined. */
+ double findSlant(const QString &TeXName);
+
+ private:
+ /** This member maps TeX font names mapEntry classes that contain
+ the font's filenames, full font names and encodings. */
+ QMap<QString, fontMapEntry> fontMapEntries;
+};
+
+#endif // ifndef _FONTMAP_H
diff --git a/kdvi/fontpool.cpp b/kdvi/fontpool.cpp
new file mode 100644
index 00000000..adec497b
--- /dev/null
+++ b/kdvi/fontpool.cpp
@@ -0,0 +1,597 @@
+//
+// fontpool.cpp
+//
+// (C) 2001-2004 Stefan Kebekus
+// Distributed under the GPL
+
+#include <config.h>
+
+#include <kdebug.h>
+#include <kinstance.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kprocess.h>
+#include <kprocio.h>
+#include <math.h>
+#include <qapplication.h>
+#include <qfile.h>
+#include <qimage.h>
+#include <qpainter.h>
+#include <stdlib.h>
+
+#include "fontpool.h"
+#include "performanceMeasurement.h"
+#include "prefs.h"
+#include "TeXFont.h"
+
+//#define DEBUG_FONTPOOL
+
+
+
+// List of permissible MetaFontModes which are supported by kdvi.
+
+//const char *MFModes[] = { "cx", "ljfour", "lexmarks" };
+//const char *MFModenames[] = { "Canon CX", "LaserJet 4", "Lexmark S" };
+//const int MFResolutions[] = { 300, 600, 1200 };
+
+#ifdef PERFORMANCE_MEASUREMENT
+QTime fontPoolTimer;
+bool fontPoolTimerFlag;
+#endif
+
+//#define DEBUG_FONTPOOL
+
+fontPool::fontPool()
+ : progress( "fontgen", // Chapter in the documentation for help.
+ i18n( "KDVI is currently generating bitmap fonts..." ),
+ i18n( "Aborts the font generation. Don't do this." ),
+ i18n( "KDVI is currently generating bitmap fonts which are needed to display your document. "
+ "For this, KDVI uses a number of external programs, such as MetaFont. You can find "
+ "the output of these programs later in the document info dialog." ),
+ i18n( "KDVI is generating fonts. Please wait." ),
+ 0 )
+{
+#ifdef DEBUG_FONTPOOL
+ kdDebug(4300) << "fontPool::fontPool() called" << endl;
+#endif
+
+ setName("Font Pool");
+
+ displayResolution_in_dpi = 100.0; // A not-too-bad-default
+ useFontHints = true;
+ CMperDVIunit = 0;
+ extraSearchPath = QString::null;
+ fontList.setAutoDelete(true);
+
+
+#ifdef HAVE_FREETYPE
+ // Initialize the Freetype Library
+ if ( FT_Init_FreeType( &FreeType_library ) != 0 ) {
+ kdError(4300) << "Cannot load the FreeType library. KDVI proceeds without FreeType support." << endl;
+ FreeType_could_be_loaded = false;
+ } else
+ FreeType_could_be_loaded = true;
+#endif
+
+ // Check if the QT library supports the alpha channel of
+ // pixmaps. Experiments show that --depending of the configuration
+ // of QT at compile and runtime or the availability of the XFt
+ // extension, alpha channels are either supported, or silently
+ // converted to 1-bit masks.
+ QImage start(1, 1, 32); // Generate a 1x1 image, black with alpha=0x10
+ start.setAlphaBuffer(true);
+ Q_UINT32 *destScanLine = (Q_UINT32 *)start.scanLine(0);
+ *destScanLine = 0x80000000;
+ QPixmap intermediate(start);
+ QPixmap dest(1,1);
+ dest.fill(Qt::white);
+ QPainter paint( &dest );
+ paint.drawPixmap(0, 0, intermediate);
+ paint.end();
+ start = dest.convertToImage().convertDepth(32);
+ Q_UINT8 result = *(start.scanLine(0)) & 0xff;
+
+ if ((result == 0xff) || (result == 0x00)) {
+#ifdef DEBUG_FONTPOOL
+ kdDebug(4300) << "fontPool::fontPool(): QPixmap does not support the alpha channel" << endl;
+#endif
+ QPixmapSupportsAlpha = false;
+ } else {
+#ifdef DEBUG_FONTPOOL
+ kdDebug(4300) << "fontPool::fontPool(): QPixmap supports the alpha channel" << endl;
+#endif
+ QPixmapSupportsAlpha = true;
+ }
+}
+
+
+fontPool::~fontPool()
+{
+#ifdef DEBUG_FONTPOOL
+ kdDebug(4300) << "fontPool::~fontPool() called" << endl;
+#endif
+
+ // need to manually clear the fonts _before_ freetype gets unloaded
+ fontList.clear();
+
+#ifdef HAVE_FREETYPE
+ if (FreeType_could_be_loaded == true)
+ FT_Done_FreeType( FreeType_library );
+#endif
+}
+
+
+void fontPool::setParameters( bool _useFontHints )
+{
+ // Check if glyphs need to be cleared
+ if (_useFontHints != useFontHints) {
+ double displayResolution = displayResolution_in_dpi;
+ TeXFontDefinition *fontp = fontList.first();
+ while(fontp != 0 ) {
+ fontp->setDisplayResolution(displayResolution * fontp->enlargement);
+ fontp=fontList.next();
+ }
+ }
+
+ useFontHints = _useFontHints;
+}
+
+
+TeXFontDefinition* fontPool::appendx(const QString& fontname, Q_UINT32 checksum, Q_UINT32 scale, double enlargement)
+{
+ // Reuse font if possible: check if a font with that name and
+ // natural resolution is already in the fontpool, and use that, if
+ // possible.
+ TeXFontDefinition *fontp = fontList.first();
+ while( fontp != 0 ) {
+ if ((fontname == fontp->fontname) && ( (int)(enlargement*1000.0+0.5)) == (int)(fontp->enlargement*1000.0+0.5)) {
+ // if font is already in the list
+ fontp->mark_as_used();
+ return fontp;
+ }
+ fontp=fontList.next();
+ }
+
+ // If font doesn't exist yet, we have to generate a new font.
+
+ double displayResolution = displayResolution_in_dpi;
+
+ fontp = new TeXFontDefinition(fontname, displayResolution*enlargement, checksum, scale, this, enlargement);
+ if (fontp == 0) {
+ kdError(4300) << i18n("Could not allocate memory for a font structure!") << endl;
+ exit(0);
+ }
+ fontList.append(fontp);
+
+#ifdef PERFORMANCE_MEASUREMENT
+ fontPoolTimer.start();
+ fontPoolTimerFlag = false;
+#endif
+
+ // Now start kpsewhich/MetaFont, etc. if necessary
+ return fontp;
+}
+
+
+QString fontPool::status()
+{
+#ifdef DEBUG_FONTPOOL
+ kdDebug(4300) << "fontPool::status() called" << endl;
+#endif
+
+ QString text;
+ QStringList tmp;
+
+ if (fontList.isEmpty())
+ return i18n("The fontlist is currently empty.");
+
+ text.append("<table WIDTH=\"100%\" NOSAVE >");
+ text.append( QString("<tr><td><b>%1</b></td> <td><b>%2</b></td> <td><b>%3</b></td> <td><b>%4</b> <td><b>%5</b></td> <td><b>%6</b></td></tr>")
+ .arg(i18n("TeX Name"))
+ .arg(i18n("Family"))
+ .arg(i18n("Zoom"))
+ .arg(i18n("Type"))
+ .arg(i18n("Encoding"))
+ .arg(i18n("Comment")) );
+
+ TeXFontDefinition *fontp = fontList.first();
+ while ( fontp != 0 ) {
+ QString errMsg, encoding;
+
+ if (!(fontp->flags & TeXFontDefinition::FONT_VIRTUAL)) {
+#ifdef HAVE_FREETYPE
+ encoding = fontp->getFullEncodingName();
+#endif
+ if (fontp->font != 0)
+ errMsg = fontp->font->errorMessage;
+ else
+ errMsg = i18n("Font file not found");
+ }
+
+#ifdef HAVE_FREETYPE
+ tmp << QString ("<tr><td>%1</td> <td>%2</td> <td>%3%</td> <td>%4</td> <td>%5</td> <td>%6</td></tr>")
+ .arg(fontp->fontname)
+ .arg(fontp->getFullFontName())
+ .arg((int)(fontp->enlargement*100 + 0.5))
+ .arg(fontp->getFontTypeName())
+ .arg(encoding)
+ .arg(errMsg);
+#endif
+
+ fontp=fontList.next();
+ }
+
+ tmp.sort();
+ text.append(tmp.join("\n"));
+ text.append("</table>");
+
+ return text;
+}
+
+
+bool fontPool::areFontsLocated()
+{
+#ifdef DEBUG_FONTPOOL
+ kdDebug(4300) << "fontPool::areFontsLocated() called" << endl;
+#endif
+
+ // Is there a font whose name we did not try to find out yet?
+ TeXFontDefinition *fontp = fontList.first();
+ while( fontp != 0 ) {
+ if ( !fontp->isLocated() )
+ return false;
+ fontp=fontList.next();
+ }
+
+#ifdef DEBUG_FONTPOOL
+ kdDebug(4300) << "... yes, all fonts are located (but not necessarily loaded)." << endl;
+#endif
+ return true; // That says that all fonts are located.
+}
+
+
+void fontPool::locateFonts()
+{
+ kpsewhichOutput = QString::null;
+
+ // First, we try and find those fonts which exist on disk
+ // already. If virtual fonts are found, they will add new fonts to
+ // the list of fonts whose font files need to be located, so that we
+ // repeat the lookup.
+ bool vffound;
+ do {
+ vffound = false;
+ locateFonts(false, false, &vffound);
+ } while(vffound);
+
+ // If still not all fonts are found, look again, this time with
+ // on-demand generation of PK fonts enabled.
+ if (!areFontsLocated())
+ locateFonts(true, false);
+
+ // If still not all fonts are found, we look for TFM files as a last
+ // resort, so that we can at least draw filled rectangles for
+ // characters.
+ if (!areFontsLocated())
+ locateFonts(false, true);
+
+ // If still not all fonts are found, we give up. We mark all fonts
+ // as 'located', so that wee won't look for them any more, and
+ // present an error message to the user.
+ if (!areFontsLocated()) {
+ markFontsAsLocated();
+ QString details = QString("<qt><p><b>PATH:</b> %1</p>%2</qt>").arg(getenv("PATH")).arg(kpsewhichOutput);
+ KMessageBox::detailedError( 0, i18n("<qt><p>KDVI was not able to locate all the font files "
+ "which are necessary to display the current DVI file. "
+ "Your document might be unreadable.</p></qt>"),
+ details,
+ i18n("Not All Font Files Found") );
+ }
+}
+
+
+void fontPool::locateFonts(bool makePK, bool locateTFMonly, bool *virtualFontsFound)
+{
+ // Set up the kpsewhich process. If pass == 0, look for vf-fonts and
+ // disable automatic font generation as vf-fonts can't be
+ // generated. If pass == 0, ennable font generation, if it was
+ // enabled globally.
+ emit setStatusBarText(i18n("Locating fonts..."));
+
+ QStringList shellProcessCmdLine;
+
+ KProcIO kpsewhichIO;
+ // If PK fonts are generated, the kpsewhich command will re-route
+ // the output of MetaFont into its stderr. Here we make sure this
+ // output is intercepted and parsed.
+ qApp->connect(&kpsewhichIO, SIGNAL(receivedStderr(KProcess *, char *, int)),
+ this, SLOT(mf_output_receiver(KProcess *, char *, int)));
+
+
+ kpsewhichIO.setUseShell(true);
+
+ // Now generate the command line for the kpsewhich
+ // program. Unfortunately, this can be rather long and involved...
+ shellProcessCmdLine += "kpsewhich";
+ shellProcessCmdLine += QString("--dpi 1200");
+ shellProcessCmdLine += QString("--mode lexmarks");
+
+ // Disable automatic pk-font generation.
+ if (makePK == true)
+ shellProcessCmdLine += "--mktex pk";
+ else
+ shellProcessCmdLine += "--no-mktex pk";
+
+ // Names of fonts that shall be located
+ Q_UINT16 numFontsInJob = 0;
+ TeXFontDefinition *fontp = fontList.first();
+ while ( fontp != 0 ) {
+ if (!fontp->isLocated()) {
+ numFontsInJob++;
+
+ if (locateTFMonly == true)
+ shellProcessCmdLine += KShellProcess::quote(QString("%1.tfm").arg(fontp->fontname));
+ else {
+#ifdef HAVE_FREETYPE
+ if (FreeType_could_be_loaded == true) {
+ const QString &filename = fontsByTeXName.findFileName(fontp->fontname);
+ if (!filename.isEmpty())
+ shellProcessCmdLine += KShellProcess::quote(QString("%1").arg(filename));
+ }
+#endif
+ shellProcessCmdLine += KShellProcess::quote(QString("%1.vf").arg(fontp->fontname));
+ shellProcessCmdLine += KShellProcess::quote(QString("%1.1200pk").arg(fontp->fontname));
+ }
+ }
+ fontp=fontList.next();
+ }
+
+ if (numFontsInJob == 0)
+ return;
+
+ progress.setTotalSteps(numFontsInJob, &kpsewhichIO);
+
+ // Now run... kpsewhich. In case of error, kick up a fuss.
+ MetafontOutput = QString::null;
+ kpsewhichOutput += "<p><b>"+shellProcessCmdLine.join(" ")+"</b></p>";
+ kpsewhichIO << shellProcessCmdLine;
+ QString importanceOfKPSEWHICH = i18n("<p>KDVI relies on the <b>kpsewhich</b> program to locate font files "
+ "on your hard disc and to generate PK fonts, if necessary.</p>");
+ if (kpsewhichIO.start(KProcess::NotifyOnExit, false) == false) {
+ QString msg = i18n( "<p>The shell process for the kpsewhich program could not "
+ "be started. Consequently, some font files could not be found, "
+ "and your document might by unreadable. If this error is reproducable "
+ "please report the issue to the KDVI developers using the 'Help' menu.<p>" );
+ QApplication::restoreOverrideCursor();
+ KMessageBox::error( 0, QString("<qt>%1%2</qt>").arg(importanceOfKPSEWHICH).arg(msg),
+ i18n("Problem locating fonts - KDVI") );
+ markFontsAsLocated();
+ return;
+ }
+
+ // We wait here while the kpsewhich program is concurrently
+ // running. Every second we call processEvents() to keep the GUI
+ // updated. This is important, e.g. for the progress dialog that is
+ // shown when PK fonts are generated by MetaFont.
+ while(kpsewhichIO.wait(1) == false)
+ qApp->processEvents();
+ progress.hide();
+
+ // Handle fatal errors.
+ if (!kpsewhichIO.normalExit()) {
+ KMessageBox::sorry( 0, "<qt><p>The font generation was aborted. As a result, "
+ "some font files could not be located, and your document might be unreadable.</p></qt>",
+ i18n("Font generation aborted - KDVI") );
+
+ // This makes sure the we don't try to run kpsewhich again
+ if (makePK == false)
+ markFontsAsLocated();
+ } else
+ if (kpsewhichIO.exitStatus() == 127) {
+ // An exit status of 127 means that the kpsewhich executable
+ // could not be found. We give extra explanation then.
+ QApplication::restoreOverrideCursor();
+ QString msg = i18n( "<p>There were problems running kpsewhich. As a result, "
+ "some font files could not be located, and your document might be unreadable.</p>"
+ "<p><b>Possible reason:</b> The kpsewhich program is perhaps not installed on your system, or it "
+ "cannot be found in the current search path.</p>"
+ "<p><b>What you can do:</b> The kpsewhich program is normally contained in distributions of the TeX "
+ "typesetting system. If TeX is not installed on your system, you could install the TeTeX distribution (www.tetex.org). "
+ "If you are sure that TeX is installed, please try to use the kpsewhich program from the command line to check if it "
+ "really works.</p>");
+ QString details = QString("<qt><p><b>PATH:</b> %1</p>%2</qt>").arg(getenv("PATH")).arg(kpsewhichOutput);
+
+ KMessageBox::detailedError( 0, QString("<qt>%1%2</qt>").arg(importanceOfKPSEWHICH).arg(msg), details,
+ i18n("Problem locating fonts - KDVI") );
+ // This makes sure the we don't try to run kpsewhich again
+ markFontsAsLocated();
+ return;
+ }
+
+ // Create a list with all filenames found by the kpsewhich program.
+ QStringList fileNameList;
+ QString line;
+ while(kpsewhichIO.readln(line) >= 0)
+ fileNameList += line;
+
+ // Now associate the file names found with the fonts
+ fontp=fontList.first();
+ while ( fontp != 0 ) {
+ if (fontp->filename.isEmpty() == true) {
+ QStringList matchingFiles;
+#ifdef HAVE_FREETYPE
+ const QString &fn = fontsByTeXName.findFileName(fontp->fontname);
+ if (!fn.isEmpty())
+ matchingFiles = fileNameList.grep(fn);
+#endif
+ if (matchingFiles.isEmpty() == true)
+ matchingFiles += fileNameList.grep(fontp->fontname+".");
+
+ if (matchingFiles.isEmpty() != true) {
+#ifdef DEBUG_FONTPOOL
+ kdDebug(4300) << "Associated " << fontp->fontname << " to " << matchingFiles.first() << endl;
+#endif
+ QString fname = matchingFiles.first();
+ fontp->fontNameReceiver(fname);
+ fontp->flags |= TeXFontDefinition::FONT_KPSE_NAME;
+ if (fname.endsWith(".vf")) {
+ if (virtualFontsFound != 0)
+ *virtualFontsFound = true;
+ // Constructing a virtual font will most likely insert other
+ // fonts into the fontList. After that, fontList.next() will
+ // no longer work. It is therefore safer to start over.
+ fontp=fontList.first();
+ continue;
+ }
+ }
+ } // of if (fontp->filename.isEmpty() == true)
+ fontp = fontList.next();
+ }
+}
+
+
+void fontPool::setCMperDVIunit( double _CMperDVI )
+{
+#ifdef DEBUG_FONTPOOL
+ kdDebug(4300) << "fontPool::setCMperDVIunit( " << _CMperDVI << " )" << endl;
+#endif
+
+ if (CMperDVIunit == _CMperDVI)
+ return;
+
+ CMperDVIunit = _CMperDVI;
+
+ TeXFontDefinition *fontp = fontList.first();
+ while(fontp != 0 ) {
+ fontp->setDisplayResolution(displayResolution_in_dpi * fontp->enlargement);
+ fontp=fontList.next();
+ }
+}
+
+
+void fontPool::setDisplayResolution( double _displayResolution_in_dpi )
+{
+#ifdef DEBUG_FONTPOOL
+ kdDebug(4300) << "fontPool::setDisplayResolution( displayResolution_in_dpi=" << _displayResolution_in_dpi << " ) called" << endl;
+#endif
+
+ // Ignore minute changes by less than 2 DPI. The difference would
+ // hardly be visible anyway. That saves a lot of re-painting,
+ // e.g. when the user resizes the window, and a flickery mouse
+ // changes the window size by 1 pixel all the time.
+ if ( fabs(displayResolution_in_dpi - _displayResolution_in_dpi) <= 2.0 ) {
+#ifdef DEBUG_FONTPOOL
+ kdDebug(4300) << "fontPool::setDisplayResolution(...): resolution wasn't changed. Aborting." << endl;
+#endif
+ return;
+ }
+
+ displayResolution_in_dpi = _displayResolution_in_dpi;
+ double displayResolution = displayResolution_in_dpi;
+
+ TeXFontDefinition *fontp = fontList.first();
+ while(fontp != 0 ) {
+ fontp->setDisplayResolution(displayResolution * fontp->enlargement);
+ fontp=fontList.next();
+ }
+
+ // Do something that causes re-rendering of the dvi-window
+ /*@@@@
+ emit fonts_have_been_loaded(this);
+ */
+}
+
+
+void fontPool::markFontsAsLocated()
+{
+ TeXFontDefinition *fontp=fontList.first();
+ while ( fontp != 0 ) {
+ fontp->markAsLocated();
+ fontp = fontList.next();
+ }
+}
+
+
+
+void fontPool::mark_fonts_as_unused()
+{
+#ifdef DEBUG_FONTPOOL
+ kdDebug(4300) << "fontPool::mark_fonts_as_unused() called" << endl;
+#endif
+
+ TeXFontDefinition *fontp = fontList.first();
+ while ( fontp != 0 ) {
+ fontp->flags &= ~TeXFontDefinition::FONT_IN_USE;
+ fontp=fontList.next();
+ }
+}
+
+
+void fontPool::release_fonts()
+{
+#ifdef DEBUG_FONTPOOL
+ kdDebug(4300) << "Release_fonts" << endl;
+#endif
+
+ TeXFontDefinition *fontp = fontList.first();
+ while(fontp != 0) {
+ if ((fontp->flags & TeXFontDefinition::FONT_IN_USE) != TeXFontDefinition::FONT_IN_USE) {
+ fontList.removeRef(fontp);
+ fontp = fontList.first();
+ } else
+ fontp = fontList.next();
+ }
+}
+
+
+void fontPool::mf_output_receiver(KProcess *, char *buffer, int buflen)
+{
+ // Paranoia.
+ if (buflen < 0)
+ return;
+
+ QString op = QString::fromLocal8Bit(buffer, buflen);
+
+ kpsewhichOutput.append(op);
+ MetafontOutput.append(op);
+
+ // We'd like to print only full lines of text.
+ int numleft;
+ bool show_prog = false;
+ while( (numleft = MetafontOutput.find('\n')) != -1) {
+ QString line = MetafontOutput.left(numleft+1);
+#ifdef DEBUG_FONTPOOL
+ kdDebug(4300) << "MF OUTPUT RECEIVED: " << line;
+#endif
+ // Search for a line which marks the beginning of a MetaFont run
+ // and show the progress dialog at the end of this method.
+ if (line.find("kpathsea:") == 0)
+ show_prog = true;
+
+ // If the Output of the kpsewhich program contains a line starting
+ // with "kpathsea:", this means that a new MetaFont-run has been
+ // started. We filter these lines out and update the display
+ // accordingly.
+ int startlineindex = line.find("kpathsea:");
+ if (startlineindex != -1) {
+ int endstartline = line.find("\n",startlineindex);
+ QString startLine = line.mid(startlineindex,endstartline-startlineindex);
+
+ // The last word in the startline is the name of the font which we
+ // are generating. The second-to-last word is the resolution in
+ // dots per inch. Display this info in the text label below the
+ // progress bar.
+ int lastblank = startLine.findRev(' ');
+ QString fontName = startLine.mid(lastblank+1);
+ int secondblank = startLine.findRev(' ',lastblank-1);
+ QString dpi = startLine.mid(secondblank+1,lastblank-secondblank-1);
+
+ progress.show();
+ progress.increaseNumSteps( i18n("Currently generating %1 at %2 dpi").arg(fontName).arg(dpi) );
+ }
+ MetafontOutput = MetafontOutput.remove(0,numleft+1);
+ }
+}
+
+
+#include "fontpool.moc"
diff --git a/kdvi/fontpool.h b/kdvi/fontpool.h
new file mode 100644
index 00000000..2e9d25da
--- /dev/null
+++ b/kdvi/fontpool.h
@@ -0,0 +1,215 @@
+// -*- C++ -*-
+// fontpool.h
+//
+// (C) 2001-2004 Stefan Kebekus
+// Distributed under the GPL
+
+#ifndef _FONTPOOL_H
+#define _FONTPOOL_H
+
+#include "fontEncodingPool.h"
+#include "fontMap.h"
+#include "fontprogress.h"
+#include "TeXFontDefinition.h"
+
+#include <qptrlist.h>
+#include <qobject.h>
+
+#ifdef HAVE_FREETYPE
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#endif
+
+class KProcess;
+class KShellProcess;
+
+
+/**
+ * A list of fonts and a compilation of utility functions
+ *
+ * This class holds a list of fonts and is able to perform a number of
+ * functions on each of the fonts. The main use of this class is that
+ * it is able to control a concurrently running "kpsewhich" programm
+ * which is used to locate and load the fonts.
+ *
+ * @author Stefan Kebekus <kebekus@kde.org>
+ *
+ **/
+
+class fontPool : public QObject {
+ Q_OBJECT
+
+public:
+ // Default constructor.
+ fontPool();
+
+ // Default destructor.
+ ~fontPool();
+
+ /** Method used to set the MetafontMode for the PK font files. This
+ data is used when loading fonts. Currently, a change here will be
+ applied only to those font which were not yet loaded ---expect
+ funny results when changing the data in the mid-work. */
+ void setParameters( bool useFontHints );
+
+ /** Sets the DVI file's path. This information is used to set the
+ current working directory for the kpsewhich command, so that
+ kpsewhich will find fonts that are stored in the DVI file's
+ directory. */
+ void setExtraSearchPath( const QString &path ) {extraSearchPath = path;}
+
+ /** Returns the path that is set as the current working directory
+ for the kpsewhich command, so that kpsewhich will find fonts
+ that are stored in the DVI file's directory. */
+ QString getExtraSearchPath( ) const {return extraSearchPath;}
+
+ /** Sets the resolution of the output device. */
+ void setDisplayResolution( double _displayResolution_in_dpi );
+
+ /** Sets the number of centimeters per DVI unit. */
+ void setCMperDVIunit( double CMperDVI );
+ double getCMperDVIunit() const {return CMperDVIunit;}
+
+ // If return value is true, font hinting should be used if possible
+ bool getUseFontHints() const {return useFontHints;}
+
+ // This method adds a font to the list. If the font is not currently
+ // loaded, it's file will be located and font::load_font will be
+ // called. Since this is done using a concurrently running process,
+ // there is no guarantee that the loading is already performed when
+ // the method returns.
+ TeXFontDefinition* appendx(const QString& fontname, Q_UINT32 checksum, Q_UINT32 scale, double enlargement);
+
+ // Returns a string in a very basic HTML format which describes the
+ // fonts in the pool.
+ QString status();
+
+ // This is the list which actually holds pointers to the fonts
+ QPtrList<TeXFontDefinition> fontList;
+
+ // This method marks all fonts in the fontpool as "not in use". The
+ // fonts are, however, not removed from memory until the method
+ // release_fonts is called. The method is called when the dvi-file
+ // is closed. Because the next dvi-file which will be loaded is
+ // likely to use most of the fonts again, this method implements a
+ // convenient way of re-using fonts without loading them repeatedly.
+ void mark_fonts_as_unused();
+
+ /** This methods removes all fonts from the fontpool (and thus from
+ memory) which are labeled "not in use". For explanation, see the
+ mark_fonts_as_unused method. */
+ void release_fonts();
+
+#ifdef HAVE_FREETYPE
+ /** A handle to the FreeType library, which is used by TeXFont_PFM
+ font objects, if KDVI is compiled with FreeType support. */
+ FT_Library FreeType_library;
+
+ /** Simple marker. Set to 'true', if the FreeType library was loaded
+ successfully */
+ bool FreeType_could_be_loaded;
+
+ /** This maps TeX font names to font file names, full font names and
+ encodings. See the file 'fontMap.h' for a detailed
+ description. */
+ fontMap fontsByTeXName;
+
+ /** This is a list of known font encodings which can be conveniently
+ acessed by name. */
+ fontEncodingPool encodingPool;
+#endif
+
+ /** This flag is set during the construction of the fontPool
+ object. It indicates if the QT library supports the alpha
+ channel of pixmaps. Experiments show that --depending of the
+ configuration of QT at compile and runtime or the availability
+ of the XFt extension, alpha channels are either supported, or
+ silently converted to 1-bit masks. The redering routines in the
+ TeXFont implementation use this flag to choose the apropriate
+ drawing routines for the different setups. */
+ bool QPixmapSupportsAlpha;
+
+signals:
+ /** Passed through to the top-level kpart. */
+ void setStatusBarText( const QString& );
+
+public slots:
+ // Locates font files on the disk using the kpsewhich program. If
+ // 'locateTFMonly' is true, the method does not look for PFB- or
+ // PK-fonts. Instead, only TFM-files are searched. This option can be
+ // used as a 'last resort': if a found cannot be found, one can at
+ // least use the TFM file to draw filled rectangles for the
+ // characters. If not null, the bool pointed at by virtualFontsFound
+ // is set to true if one of the fonts found is a virtual font. If no
+ // virtual font is found, the variable remains untouched.
+ void locateFonts();
+
+private:
+ // This method goes through the list of fonts, and marks each of them
+ // as 'located'. Used, e.g. after a fatal error in the font lookup
+ // process to ensure that the problematic kpsewhich is not used again
+ void markFontsAsLocated();
+
+ // Checks if all the fonts file names have been located, and returns
+ // true if that is so.
+ bool areFontsLocated();
+
+ // This flag is used by PFB fonts to determine if the FREETYPE engine
+ // should use hinted fonts or not
+ bool useFontHints;
+
+ // Resolution of the output device.
+ double displayResolution_in_dpi;
+
+ // Number of centimeters per DVI unit
+ double CMperDVIunit;
+
+
+ /** Members used for font location */
+
+ // Locates font files on the disk using the kpsewhich program. If
+ // 'locateTFMonly' is true, the method does not look for PFB- or
+ // PK-fonts. Instead, only TFM-files are searched. This option can be
+ // used as a 'last resort': if a found cannot be found, one can at
+ // least use the TFM file to draw filled rectangles for the
+ // characters. If not null, the bool pointed at by virtualFontsFound
+ // is set to true if one of the fonts found is a virtual font. If no
+ // virtual font is found, the variable remains untouched.
+ void locateFonts(bool makePK, bool locateTFMonly, bool *virtualFontsFound=0);
+
+ // This QString is used internally by the mf_output_receiver()
+ // method. This string is set to QString::null in locateFonts(bool,
+ // bool, bool *). Values are set and read by the
+ // mf_output_receiver(...) method
+ QString MetafontOutput;
+
+ // This QString is used to collect the output of kpsewhich and
+ // MetaFont. The string is set to QString::null in the
+ // locateFonts()-method, and content is gathered by the
+ // mf_output_receiver(). This string is used by locateFonts() and
+ // locateFonts(bool, bool, bool *) to display error messages.
+ QString kpsewhichOutput;
+
+ // This string is set to the DVI file's path. It is used to set the
+ // current working directory for the kpsewhich command, so that
+ // kpsewhich will find fonts that are stored in the DVI file's
+ // directory. Used by the locateFonts() and the locateFonts(bool,
+ // bool, bool *) method. Values are set by the
+ // setExtraSearchPath(...) method
+ QString extraSearchPath;
+
+ // FontProgress; the progress dialog used when generating fonts.
+ fontProgressDialog progress;
+
+private slots:
+ /** Members used for font location */
+
+ // For internal purposess only. This slot is called when MetaFont is
+ // run via the kpsewhich programm. The MetaFont output is
+ // transmitted to the fontpool via this slot. This method calles
+ // suitable methods in the fontProgres Dialog, and collects the
+ // output of MetaFontt int the "MetafontOutput" member
+ void mf_output_receiver(KProcess *, char *, int);
+};
+
+#endif //ifndef _FONTPOOL_H
diff --git a/kdvi/fontprogress.cpp b/kdvi/fontprogress.cpp
new file mode 100644
index 00000000..3935ceba
--- /dev/null
+++ b/kdvi/fontprogress.cpp
@@ -0,0 +1,104 @@
+// fontprogress.cpp
+//
+// (C) 2001--2004 Stefan Kebekus
+// Distributed under the GPL
+
+#include <config.h>
+
+#include "fontprogress.h"
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kprocio.h>
+#include <kprogress.h>
+#include <qapplication.h>
+#include <qframe.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qvariant.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+
+#include <qvbox.h>
+
+/*
+ * Constructs a fontProgressDialog which is a child of 'parent', with the
+ * name 'name' and widget flags set to 'f'
+ */
+fontProgressDialog::fontProgressDialog(const QString& helpIndex, const QString& label, const QString& abortTip, const QString& whatsThis, const QString& ttip, QWidget* parent, const QString& name, bool progressbar)
+ : KDialogBase( parent, "Font Generation Progress Dialog", true, name, Cancel, Cancel, true )
+{
+ setCursor( QCursor( 3 ) );
+
+ setButtonCancel(KGuiItem(i18n("Abort"), "stop", abortTip));
+
+ if (helpIndex.isEmpty() == false) {
+ setHelp(helpIndex, "kdvi");
+ setHelpLinkText( i18n( "What's going on here?") );
+ enableLinkedHelp(true);
+ } else
+ enableLinkedHelp(false);
+
+ QVBox *page = makeVBoxMainWidget();
+
+ TextLabel1 = new QLabel( label, page, "TextLabel2" );
+ TextLabel1->setAlignment( int( QLabel::AlignCenter ) );
+ QWhatsThis::add( TextLabel1, whatsThis );
+ QToolTip::add( TextLabel1, ttip );
+
+ if (progressbar) {
+ ProgressBar1 = new KProgress( page, "ProgressBar1" );
+ ProgressBar1->setFormat(i18n("%v of %m"));
+ QWhatsThis::add( ProgressBar1, whatsThis );
+ QToolTip::add( ProgressBar1, ttip );
+ } else
+ ProgressBar1 = NULL;
+
+ TextLabel2 = new QLabel( "", page, "TextLabel2" );
+ TextLabel2->setAlignment( int( QLabel::AlignCenter ) );
+ QWhatsThis::add( TextLabel2, whatsThis );
+ QToolTip::add( TextLabel2, ttip );
+
+ progress = 0;
+ procIO = 0;
+ qApp->connect(this, SIGNAL(finished()), this, SLOT(killProcIO()));
+}
+
+
+/*
+ * Destroys the object and frees any allocated resources
+ */
+
+fontProgressDialog::~fontProgressDialog()
+{
+ // no need to delete child widgets, Qt does it all for us
+}
+
+
+void fontProgressDialog::increaseNumSteps(const QString& explanation)
+{
+ if (ProgressBar1 != 0)
+ ProgressBar1->setProgress(progress++);
+ TextLabel2->setText( explanation );
+}
+
+
+void fontProgressDialog::setTotalSteps(int steps, KProcIO *proc)
+{
+ procIO = proc;
+ if (ProgressBar1 != 0) {
+ ProgressBar1->setTotalSteps(steps);
+ ProgressBar1->setProgress(0);
+ }
+ progress = 0;
+}
+
+
+void fontProgressDialog::killProcIO()
+{
+ if (!procIO.isNull())
+ procIO->kill();
+}
+
+
+#include "fontprogress.moc"
diff --git a/kdvi/fontprogress.h b/kdvi/fontprogress.h
new file mode 100644
index 00000000..f9c7232b
--- /dev/null
+++ b/kdvi/fontprogress.h
@@ -0,0 +1,64 @@
+// -*- C++ -*-
+//
+// fontprogress.h
+//
+// (C) 2001-2004 Stefan Kebekus
+// Distributed under the GPL
+
+#ifndef FONT_GENERATION_H
+#define FONT_GENERATION_H
+
+#include <kdialogbase.h>
+#include <qguardedptr.h>
+
+class KProcIO;
+class KProgress;
+class QLabel;
+
+
+/**
+ * A dialog to give feedback to the user when kpsewhich is generating fonts.
+ *
+ * This class implements a dialog which pops up, shows a progress bar
+ * and displays the MetaFont output. It contains three slots,
+ * outputReceiver, setTotalSteps and hideDialog which can be connected
+ * with the appropriate signals emitted by the fontpool class.
+ *
+ * @author Stefan Kebekus <kebekus@kde.org>
+ *
+ *
+ **/
+class fontProgressDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ fontProgressDialog( const QString& helpIndex, const QString& label, const QString& abortTip, const QString& whatsThis, const QString& ttip,
+ QWidget* parent = 0, const QString &name = 0, bool progressbar=true );
+ ~fontProgressDialog();
+
+ /** The number of steps already done is increased, the text received
+ here is analyzed and presented to the user. */
+ void increaseNumSteps(const QString& explanation);
+
+ /** Used to initialize the progress bar. If the argument proc is
+ non-zero, the associated process will be killed when the "abort"
+ button is pressed. The FontProgress uses a QGuarderPtr
+ internally, so it is save to delete the KProcIO anytime. */
+ void setTotalSteps(int, KProcIO *proc=0);
+
+ QLabel* TextLabel2;
+
+private slots:
+ /** Calling this slot does nothing than to kill the process that is
+ pointed to be procIO, if procIO is not zero.*/
+ void killProcIO();
+
+private:
+ QLabel* TextLabel1;
+ KProgress* ProgressBar1;
+ int progress;
+ QGuardedPtr<KProcIO> procIO;
+};
+
+#endif // FONT_GENERATION_H
diff --git a/kdvi/glyph.cpp b/kdvi/glyph.cpp
new file mode 100644
index 00000000..d495d096
--- /dev/null
+++ b/kdvi/glyph.cpp
@@ -0,0 +1,30 @@
+
+/* glyph.cpp
+ *
+ * part of kdvi, a dvi-previewer for the KDE desktop environement
+ *
+ * written by Stefan Kebekus, originally based on code by Paul Vojta
+ * and a large number of co-authors */
+
+#include <config.h>
+
+#include <kdebug.h>
+
+#include "glyph.h"
+
+glyph::glyph()
+{
+#ifdef DEBUG_GLYPH
+ kdDebug(4300) << "glyph::glyph()" << endl;
+#endif
+
+ addr = 0;
+ x = 0;
+ y = 0;
+ dvi_advance_in_units_of_design_size_by_2e20 = 0;
+}
+
+glyph::~glyph()
+{
+ ;
+}
diff --git a/kdvi/glyph.h b/kdvi/glyph.h
new file mode 100644
index 00000000..1cc41823
--- /dev/null
+++ b/kdvi/glyph.h
@@ -0,0 +1,37 @@
+// -*- C++ -*-
+
+#ifndef _GLYPH_H
+#define _GLYPH_H
+
+#include <qcolor.h>
+#include <qpixmap.h>
+
+
+struct bitmap {
+ Q_UINT16 w, h; /* width and height in pixels */
+ Q_UINT16 bytes_wide; /* scan-line width in bytes */
+ char *bits; /* pointer to the bits */
+};
+
+class glyph {
+ public:
+ glyph();
+ ~glyph();
+
+ // address of bitmap in font file
+ long addr;
+
+ QColor color;
+
+ // DVI units to move reference point
+ Q_INT32 dvi_advance_in_units_of_design_size_by_2e20;
+
+ // x and y offset in pixels
+ short x, y;
+
+ QPixmap shrunkenCharacter;
+
+ short x2, y2; /* x and y offset in pixels (shrunken bitmap) */
+};
+
+#endif //ifndef _GLYPH_H
diff --git a/kdvi/infodialog.cpp b/kdvi/infodialog.cpp
new file mode 100644
index 00000000..f645def8
--- /dev/null
+++ b/kdvi/infodialog.cpp
@@ -0,0 +1,134 @@
+// infodialog.cpp
+//
+// (C) 2001-2003 Stefan Kebekus
+// Distributed under the GPL
+
+#include <config.h>
+
+#include <kdebug.h>
+#include <kio/global.h>
+#include <klocale.h>
+#include <qfile.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qregexp.h>
+#include <qtextview.h>
+#include <qtooltip.h>
+#include <qvariant.h>
+#include <qwhatsthis.h>
+
+#include "dviFile.h"
+#include "fontpool.h"
+#include "infodialog.h"
+
+infoDialog::infoDialog( QWidget* parent )
+ : KDialogBase( Tabbed, i18n("Document Info"), Ok, Ok, parent, "Document Info", false, false)
+{
+ QFrame *page1 = addPage( i18n("DVI File") );
+ QVBoxLayout *topLayout1 = new QVBoxLayout( page1, 0, 6 );
+ TextLabel1 = new QTextView( page1, "TextLabel1" );
+ QToolTip::add( TextLabel1, i18n("Information on the currently loaded DVI-file.") );
+ topLayout1->addWidget( TextLabel1 );
+
+ QFrame *page2 = addPage( i18n("Fonts") );
+ QVBoxLayout *topLayout2 = new QVBoxLayout( page2, 0, 6 );
+ TextLabel2 = new QTextView( page2, "TextLabel1" );
+ TextLabel2->setMinimumWidth(fontMetrics().maxWidth()*40);
+ TextLabel2->setMinimumHeight(fontMetrics().height()*10);
+ QToolTip::add( TextLabel2, i18n("Information on currently loaded fonts.") );
+ QWhatsThis::add( TextLabel2, i18n("This text field shows detailed information about the currently loaded fonts. "
+ "This is useful for experts who want to locate problems in the setup of TeX or KDVI.") );
+ topLayout2->addWidget( TextLabel2 );
+
+ QFrame *page3 = addPage( i18n("External Programs") );
+ QVBoxLayout *topLayout3 = new QVBoxLayout( page3, 0, 6 );
+ TextLabel3 = new QTextView( page3, "TextLabel1" );
+ TextLabel3->setText( i18n("No output from any external program received.") );
+ QToolTip::add( TextLabel3, i18n("Output of external programs.") );
+ QWhatsThis::add( TextLabel3, i18n("KDVI uses external programs, such as MetaFont, dvipdfm or dvips. "
+ "This text field shows the output of these programs. "
+ "That is useful for experts who want to find problems in the setup of TeX or KDVI.") );
+ topLayout3->addWidget( TextLabel3 );
+
+ MFOutputReceived = false;
+ headline = QString::null;
+ pool = QString::null;
+}
+
+
+void infoDialog::setDVIData(dvifile *dviFile)
+{
+ QString text = "";
+
+ if (dviFile == NULL)
+ text = i18n("There is no DVI file loaded at the moment.");
+ else {
+ text.append("<table WIDTH=\"100%\" NOSAVE >");
+ text.append(QString("<tr><td><b>%1</b></td> <td>%2</td></tr>").arg(i18n("Filename")).arg(dviFile->filename));
+
+ QFile file(dviFile->filename);
+ if (file.exists())
+ text.append(QString("<tr><td><b>%1</b></td> <td>%2</td></tr>").arg(i18n("File Size")).arg(KIO::convertSize(file.size())));
+ else
+ text.append(QString("<tr><td><b> </b></td> <td>%1</td></tr>").arg(i18n("The file does no longer exist.")));
+
+ text.append(QString("<tr><td><b> </b></td> <td> </td></tr>"));
+ text.append(QString("<tr><td><b>%1</b></td> <td>%2</td></tr>").arg(i18n("#Pages")).arg(dviFile->total_pages));
+ text.append(QString("<tr><td><b>%1</b></td> <td>%2</td></tr>").arg(i18n("Generator/Date")).arg(dviFile->generatorString));
+ } // else (dviFile == NULL)
+
+ TextLabel1->setText( text );
+}
+
+
+void infoDialog::setFontInfo(fontPool *fp)
+{
+ TextLabel2->setText(fp->status());
+}
+
+void infoDialog::outputReceiver(const QString& _op)
+{
+ QString op = _op;
+ op = op.replace( QRegExp("<"), "&lt;" );
+
+ if (MFOutputReceived == false) {
+ TextLabel3->setText("<b>"+headline+"</b><br>");
+ headline = QString::null;
+ }
+
+ // It seems that the QTextView wants that we append only full lines.
+ // We see to that.
+ pool = pool+op;
+ int idx = pool.findRev("\n");
+
+ while(idx != -1) {
+ QString line = pool.left(idx);
+ pool = pool.mid(idx+1);
+
+ // If the Output of the kpsewhich program contains a line starting
+ // with "kpathsea:", this means that a new MetaFont-run has been
+ // started. We filter these lines out and print them in boldface.
+ int startlineindex = line.find("kpathsea:");
+ if (startlineindex != -1) {
+ int endstartline = line.find("\n",startlineindex);
+ QString startLine = line.mid(startlineindex,endstartline-startlineindex);
+ if (MFOutputReceived)
+ TextLabel3->append("<hr>\n<b>"+startLine+"</b>");
+ else
+ TextLabel3->append("<b>"+startLine+"</b>");
+ TextLabel3->append(line.mid(endstartline));
+ } else
+ TextLabel3->append(line);
+ idx = pool.findRev("\n");
+ }
+
+ MFOutputReceived = true;
+}
+
+void infoDialog::clear(const QString& op)
+{
+ headline = op;
+ pool = QString::null;
+ MFOutputReceived = false;
+}
+#include "infodialog.moc"
diff --git a/kdvi/infodialog.h b/kdvi/infodialog.h
new file mode 100644
index 00000000..916d0d13
--- /dev/null
+++ b/kdvi/infodialog.h
@@ -0,0 +1,58 @@
+// -*- C++ -*-
+// infodialog.h
+//
+// (C) 2001 Stefan Kebekus
+// Distributed under the GPL
+
+#ifndef INFO_KDVI_H
+#define INFO_KDVI_H
+
+#include <kdialogbase.h>
+
+#include <qstring.h>
+
+class dvifile;
+class fontPool;
+class QTextView;
+class QWidget;
+
+
+class infoDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ infoDialog( QWidget* parent = 0 );
+
+ /** This method is used to set the data coming from the DVI
+ file. Note that 0 is a permissible argument, that just means:
+ "no file loaded" */
+ void setDVIData(dvifile *dviFile);
+
+ QTextView* TextLabel1;
+ QTextView* TextLabel2;
+ QTextView* TextLabel3;
+
+public slots:
+ /** This slot is called when Output from the MetaFont programm
+ is received via the fontpool/kpsewhich */
+ void outputReceiver(const QString&);
+
+ /** This slot is called whenever anything in the fontpool has
+ changed. If the infoDialog is shown, the dialog could then
+ query the fontpool for more information. */
+ void setFontInfo(fontPool *fp);
+
+ /** Calling this slot clears the text view and stores the
+ headline. The next time output is received via the
+ outputReceiver, the headline is displayed in bold on top of
+ the text view. */
+ void clear(const QString&);
+
+protected:
+ bool MFOutputReceived;
+ QString headline;
+ QString pool;
+};
+
+#endif // INFO_KDVI_H
diff --git a/kdvi/kdvi.desktop b/kdvi/kdvi.desktop
new file mode 100644
index 00000000..183bef33
--- /dev/null
+++ b/kdvi/kdvi.desktop
@@ -0,0 +1,90 @@
+[Desktop Entry]
+GenericName=DVI Viewer
+GenericName[af]=Dvi Aansig
+GenericName[ar]=عارض ملفات DVI
+GenericName[az]=DVI Nümayişçisi
+GenericName[bg]=Преглед на документи DVI
+GenericName[br]=Gweler DVI
+GenericName[bs]=Preglednik DVI dokumenata
+GenericName[ca]=Visualitzador de DVI
+GenericName[cs]=Prohlížeč DVI souborů
+GenericName[cy]=Gwelydd DVI
+GenericName[da]=DVI-fremviser
+GenericName[de]=DVI-Betrachter
+GenericName[el]=Προβολέας DVI
+GenericName[eo]=DVI-rigardilo
+GenericName[es]=Visor de documentos DVI
+GenericName[et]=DVI failide vaataja
+GenericName[eu]=DVI ikustailea
+GenericName[fa]=مشاهده‌گر DVI
+GenericName[fi]=DVI-näytin
+GenericName[fr]=Afficheur DVI
+GenericName[ga]=Amharcán DVI
+GenericName[gl]=Visor de DVI
+GenericName[he]=מציג DVI
+GenericName[hi]=डीवीआई प्रदर्शक
+GenericName[hr]=Preglednik DVI dokumenata
+GenericName[hu]=DVI-nézegető
+GenericName[id]=Viewer DVI
+GenericName[is]=DVI sjá
+GenericName[it]=Visore DVI
+GenericName[ja]=DVI ビューア
+GenericName[kk]=DVI файлдарын қарау
+GenericName[km]=កម្មវិធី​មើល DVI
+GenericName[ko]=DVI 보기
+GenericName[lt]=DVI Žiūriklis
+GenericName[lv]=DVI Skatītājs
+GenericName[mk]=Прикажувач на DVI
+GenericName[ms]=Pemapar DVI
+GenericName[mt]=Werrej DVI
+GenericName[nb]=DVI-fremviser
+GenericName[nds]=DVI-Kieker
+GenericName[ne]=DVI दर्शक
+GenericName[nl]=DVI-weergaveprogramma
+GenericName[nn]=DVI-lesar
+GenericName[pa]=DVI ਦਰਸ਼ਕ
+GenericName[pl]=Przeglądarka plików DVI
+GenericName[pt]=Visualizador de DVIs
+GenericName[pt_BR]=Visualizador de DVI
+GenericName[ro]=Vizualizor DVI
+GenericName[ru]=Просмотр файлов DVI
+GenericName[rw]=Ikigaragaza DVI
+GenericName[se]=DVI čájeheaddji
+GenericName[sk]=Prehliadač DVI súborov
+GenericName[sl]=Pregledovalnik datotek DVI
+GenericName[sr]=DVI приказивач
+GenericName[sr@Latn]=DVI prikazivač
+GenericName[sv]=DVI-visare
+GenericName[ta]=DVI காட்சி
+GenericName[tg]=Намоиши файли DVI
+GenericName[th]=ตัวแสดงผล DVI
+GenericName[tr]=DVI Görüntüleyici
+GenericName[uk]=Переглядач DVI
+GenericName[uz]=DVI koʻruvchi
+GenericName[uz@cyrillic]=DVI кўрувчи
+GenericName[ven]=Muvhoni wa DVI
+GenericName[wa]=Håyneu di fitchîs DVI
+GenericName[xh]=Umboniseli we DVI
+GenericName[zh_CN]=DVI 查看器
+GenericName[zh_HK]=DVI 檢視器
+GenericName[zh_TW]=DVI 檢視器
+GenericName[zu]=Umboniseli we DVI
+Name=KDVI
+Name[af]=Kdvi
+Name[ar]=برنامج KDVI
+Name[eo]=DVI-rigardilo
+Name[hi]=के-डीवीआई
+Name[zh_TW]=KDVI 檢視器
+MimeType=application/x-dvi;application/x-gzdvi;application/x-bz2dvi;
+InitialPreference=6
+Exec=kdvi %f -caption "%c" %i %m
+Icon=kdvi
+Path=
+Type=Application
+Terminal=false
+ServiceTypes=Browser/View
+X-KDE-Library=kviewerpart
+X-KDE-BrowserView-Args=dvi
+DocPath=kdvi/index.html
+X-KDE-StartupNotify=true
+Categories=Qt;KDE;Graphics;
diff --git a/kdvi/kdvi.h b/kdvi/kdvi.h
new file mode 100644
index 00000000..c04fe189
--- /dev/null
+++ b/kdvi/kdvi.h
@@ -0,0 +1,17 @@
+// -*- C++ -*-
+// kdvi.h
+//
+// global variables and definitions for kdvi.
+//
+// (C) 2000, Stefan Kebekus. Distributed under the GPL.
+
+#ifndef KDVI_H
+#define KDVI_H
+
+// Define the following flags to generate debugging output
+
+// #define DEBUG_FONT 1
+// #define DEBUG_FONTPOOL 1
+// #define DEBUG_PK 1
+
+#endif
diff --git a/kdvi/kdvi.kcfg b/kdvi/kdvi.kcfg
new file mode 100644
index 00000000..aa416757
--- /dev/null
+++ b/kdvi/kdvi.kcfg
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <include>fontpool.h</include>
+ <kcfgfile name="kdvirc" />
+ <group name="kdvi" >
+ <entry key="MakePK" type="Bool" >
+ <label>Use MetaFont to generate missing fonts. If in doubt, enable this option.</label>
+ <whatsthis>Allows KDVI to use MetaFont to produce bitmap fonts. Unless you have a very specific reason, you probably want to enable this option.</whatsthis>
+ <default>true</default>
+ </entry>
+ <entry key="ShowPS" type="Bool" >
+ <label>Show PostScript specials. If in doubt, enable this option.</label>
+ <whatsthis>Some DVI files contain PostScript graphics. If enabled, KDVI will use the Ghostview PostScript interpreter to display these. You probably want to enable this option, unless you have a DVI-file whose PostScript part is broken, or too large for your machine.</whatsthis>
+ <default>true</default>
+ </entry>
+ <entry key="UseFontHints" type="Bool" >
+ <label>Use font hinting. You should enable this, if the use of font hinting improves readability on your machine.</label>
+ <whatsthis>Many modern fonts contain &quot;font hinting&quot; information which can be used to improve the appearance of a font on low-resolution displays, such as a computer monitor, or a notebook screen. However, many people find the &quot;improved&quot; fonts quite ugly and prefer to have this option disabled.</whatsthis>
+ <default>false</default>
+ </entry>
+ <entry key="EditorCommand" type="Path" />
+ </group>
+</kcfg>
diff --git a/kdvi/kdvi.lsm b/kdvi/kdvi.lsm
new file mode 100644
index 00000000..7c42cd2c
--- /dev/null
+++ b/kdvi/kdvi.lsm
@@ -0,0 +1,14 @@
+Begin3
+Title: kdvi
+Version: 0.4
+Entered-date: October 15, 1997
+Description: TeX DVI previewer for the K Desktop Environment
+Keywords: KDE, TeX, DVI, X11, Qt
+Author: Markku Hihnala <mah@ee.oulu.fi>
+Maintained-by: Markku Hihnala <mah@ee.oulu.fi>
+Primary-site: ftp://ftp.kde.org/pub/kde/
+Alternate-site:
+Original-site: ftp://ftp.kde.org/pub/kde/
+Platforms: Unix, Qt
+Copying-policy: GPL
+End
diff --git a/kdvi/kdvi_multipage.cpp b/kdvi/kdvi_multipage.cpp
new file mode 100644
index 00000000..973e4d5f
--- /dev/null
+++ b/kdvi/kdvi_multipage.cpp
@@ -0,0 +1,482 @@
+#include <config.h>
+#include <kaction.h>
+#include <kaboutdata.h>
+#include <kaboutdialog.h>
+#include <kapplication.h>
+#include <kbugreport.h>
+#include <kconfigdialog.h>
+#include <kdebug.h>
+#include <kfiledialog.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kstdaction.h>
+#include <ktempfile.h>
+#include <ktip.h>
+#include <qtimer.h>
+
+#include <kparts/part.h>
+#include <kparts/genericfactory.h>
+
+#include "kdvi_multipage.h"
+#include "documentWidget.h"
+#include "dviFile.h"
+#include "dviPageCache.h"
+#include "dviWidget.h"
+#include "fontpool.h"
+#include "kprinterwrapper.h"
+#include "kviewpart.h"
+#include "marklist.h"
+#include "optionDialogFontsWidget.h"
+#include "optionDialogSpecialWidget.h"
+#include "performanceMeasurement.h"
+#include "prefs.h"
+#include "renderedDocumentPagePixmap.h"
+
+
+#include <qlabel.h>
+
+//#define KDVI_MULTIPAGE_DEBUG
+
+#ifdef PERFORMANCE_MEASUREMENT
+// These objects are explained in the file "performanceMeasurement.h"
+QTime performanceTimer;
+int performanceFlag = 0;
+#endif
+
+typedef KParts::GenericFactory<KDVIMultiPage> KDVIMultiPageFactory;
+K_EXPORT_COMPONENT_FACTORY(kdvipart, KDVIMultiPageFactory)
+
+
+
+KDVIMultiPage::KDVIMultiPage(QWidget *parentWidget, const char *widgetName, QObject *parent,
+ const char *name, const QStringList& args)
+ : KMultiPage(parentWidget, widgetName, parent, name), DVIRenderer(parentWidget)
+{
+ Q_UNUSED(args);
+#ifdef PERFORMANCE_MEASUREMENT
+ performanceTimer.start();
+#endif
+
+ searchUsed = false;
+
+ setInstance(KDVIMultiPageFactory::instance());
+
+ // Points to the same object as renderer to avoid downcasting.
+ // FIXME: Remove when the API of the Renderer-class is finished.
+ DVIRenderer.setName("DVI renderer");
+ setRenderer(&DVIRenderer);
+
+ docInfoAction = new KAction(i18n("Document &Info"), "info", 0, &DVIRenderer, SLOT(showInfo()), actionCollection(), "info_dvi");
+ embedPSAction = new KAction(i18n("Embed External PostScript Files..."), 0, this, SLOT(slotEmbedPostScript()), actionCollection(), "embed_postscript");
+ new KAction(i18n("Enable All Warnings && Messages"), 0, this, SLOT(doEnableWarnings()), actionCollection(), "enable_msgs");
+ exportPSAction = new KAction(i18n("PostScript..."), 0, &DVIRenderer, SLOT(exportPS()), actionCollection(), "export_postscript");
+ exportPDFAction = new KAction(i18n("PDF..."), 0, &DVIRenderer, SLOT(exportPDF()), actionCollection(), "export_pdf");
+
+ KStdAction::tipOfDay(this, SLOT(showTip()), actionCollection(), "help_tipofday");
+
+ setXMLFile("kdvi_part.rc");
+
+ preferencesChanged();
+
+ enableActions(false);
+ // Show tip of the day, when the first main window is shown.
+ QTimer::singleShot(0,this,SLOT(showTipOnStart()));
+}
+
+
+KDVIMultiPage::~KDVIMultiPage()
+{
+ delete docInfoAction;
+ delete embedPSAction;
+ delete exportPSAction;
+ delete exportPDFAction;
+
+ Prefs::writeConfig();
+}
+
+
+KAboutData* KDVIMultiPage::createAboutData()
+{
+ KAboutData* about = new KAboutData("kdvi", I18N_NOOP("KDVI"), "1.3",
+ I18N_NOOP("A previewer for Device Independent files (DVI files) produced by the TeX typesetting system."),
+ KAboutData::License_GPL,
+ "Markku Hinhala, Stephan Kebekus",
+ I18N_NOOP("This program displays Device Independent (DVI) files which are produced by the TeX typesetting system.\n"
+ "KDVI 1.3 is based on original code from KDVI version 0.43 and xdvik."));
+
+ about->addAuthor ("Stefan Kebekus",
+ I18N_NOOP("Current Maintainer."),
+ "kebekus@kde.org",
+ "http://www.mi.uni-koeln.de/~kebekus");
+
+ about->addAuthor ("Markku Hinhala", I18N_NOOP("Author of kdvi 0.4.3"));
+ about->addAuthor ("Nicolai Langfeldt", I18N_NOOP("Maintainer of xdvik"));
+ about->addAuthor ("Paul Vojta", I18N_NOOP("Author of xdvi"));
+ about->addCredit ("Philipp Lehmann", I18N_NOOP("Testing and bug reporting."));
+ about->addCredit ("Wilfried Huss", I18N_NOOP("Re-organisation of source code."));
+
+ return about;
+}
+
+
+void KDVIMultiPage::slotEmbedPostScript()
+{
+ DVIRenderer.embedPostScript();
+ emit askingToCheckActions();
+}
+
+
+void KDVIMultiPage::setEmbedPostScriptAction()
+{
+ if ((DVIRenderer.dviFile == 0) || (DVIRenderer.dviFile->numberOfExternalPSFiles == 0))
+ embedPSAction->setEnabled(false);
+ else
+ embedPSAction->setEnabled(true);
+}
+
+
+void KDVIMultiPage::slotSave()
+{
+ // 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 (0, i18n("The file %1\nexists. Do you want to overwrite that file?").arg(fileName),
+ i18n("Overwrite File"), i18n("Overwrite"));
+ if (r == KMessageBox::Cancel)
+ return;
+ }
+
+ // TODO: error handling...
+ if ((DVIRenderer.dviFile != 0) && (DVIRenderer.dviFile->dvi_Data() != 0))
+ DVIRenderer.dviFile->saveAs(fileName);
+
+ return;
+}
+
+
+void KDVIMultiPage::slotSave_defaultFilename()
+{
+ // TODO: error handling...
+ if (DVIRenderer.dviFile != 0)
+ DVIRenderer.dviFile->saveAs(m_file);
+ return;
+}
+
+
+void KDVIMultiPage::setFile(bool r)
+{
+ enableActions(r);
+}
+
+
+QStringList KDVIMultiPage::fileFormats() const
+{
+ QStringList r;
+ r << i18n("*.dvi *.DVI|TeX Device Independent Files (*.dvi)");
+ return r;
+}
+
+
+void KDVIMultiPage::addConfigDialogs(KConfigDialog* configDialog)
+{
+ static optionDialogFontsWidget* fontConfigWidget = 0;
+
+ fontConfigWidget = new optionDialogFontsWidget(scrollView());
+ optionDialogSpecialWidget* specialConfigWidget = new optionDialogSpecialWidget(scrollView());
+
+ configDialog->addPage(fontConfigWidget, Prefs::self(), i18n("TeX Fonts"), "fonts");
+ configDialog->addPage(specialConfigWidget, Prefs::self(), i18n("DVI Specials"), "dvi");
+ configDialog->setHelp("preferences", "kdvi");
+}
+
+
+void KDVIMultiPage::preferencesChanged()
+{
+ // Call method from parent class
+ KMultiPage::preferencesChanged();
+#ifdef KDVI_MULTIPAGE_DEBUG
+ kdDebug(4300) << "preferencesChanged" << endl;
+#endif
+
+ bool showPS = Prefs::showPS();
+ bool useFontHints = Prefs::useFontHints();
+
+ DVIRenderer.setPrefs( showPS, Prefs::editorCommand(), useFontHints);
+}
+
+
+void KDVIMultiPage::print()
+{
+ // Obtain a fully initialized KPrinter structure, and disable all
+ // entries in the "Page Size & Placement" tab of the printer dialog.
+ KPrinter *printer = getPrinter(false);
+ // Abort with an error message if no KPrinter could be initialized
+ if (printer == 0) {
+ kdError(4300) << "KPrinter not available" << endl;
+ return;
+ }
+
+ // Show the printer options dialog. Return immediately if the user
+ // aborts.
+ if (!printer->setup(parentWdg, i18n("Print %1").arg(m_file.section('/', -1)) ))
+ return;
+
+ // This funny method call is necessary for the KPrinter to return
+ // proper results in printer->orientation() below. It seems that
+ // KPrinter does some options parsing in that method.
+ ((KDVIPrinterWrapper *)printer)->doPreparePrinting();
+ if (printer->pageList().isEmpty()) {
+ KMessageBox::error( scrollView(),
+ i18n("The list of pages you selected was empty.\n"
+ "Maybe you made an error in selecting the pages, "
+ "e.g. by giving an invalid range like '7-2'.") );
+ return;
+ }
+
+ // Turn the results of the options requestor into a list arguments
+ // which are used by dvips.
+ QString dvips_options = QString::null;
+ // Print in reverse order.
+ if ( printer->pageOrder() == KPrinter::LastPageFirst )
+ dvips_options += "-r ";
+ // Print only odd pages.
+ if ( printer->pageSet() == KPrinter::OddPages )
+ dvips_options += "-A ";
+ // Print only even pages.
+ if ( printer->pageSet() == KPrinter::EvenPages )
+ dvips_options += "-B ";
+ // We use the printer->pageSize() method to find the printer page
+ // size, and pass that information on to dvips. Unfortunately, dvips
+ // does not understand all of these; what exactly dvips understands,
+ // depends on its configuration files. Consequence: expect problems
+ // with unusual paper sizes.
+ switch( printer->pageSize() ) {
+ case KPrinter::A4:
+ dvips_options += "-t a4 ";
+ break;
+ case KPrinter::B5:
+ dvips_options += "-t b5 ";
+ break;
+ case KPrinter::Letter:
+ dvips_options += "-t letter ";
+ break;
+ case KPrinter::Legal:
+ dvips_options += "-t legal ";
+ break;
+ case KPrinter::Executive:
+ dvips_options += "-t executive ";
+ break;
+ case KPrinter::A0:
+ dvips_options += "-t a0 ";
+ break;
+ case KPrinter::A1:
+ dvips_options += "-t a1 ";
+ break;
+ case KPrinter::A2:
+ dvips_options += "-t a2 ";
+ break;
+ case KPrinter::A3:
+ dvips_options += "-t a3 ";
+ break;
+ case KPrinter::A5:
+ dvips_options += "-t a5 ";
+ break;
+ case KPrinter::A6:
+ dvips_options += "-t a6 ";
+ break;
+ case KPrinter::A7:
+ dvips_options += "-t a7 ";
+ break;
+ case KPrinter::A8:
+ dvips_options += "-t a8 ";
+ break;
+ case KPrinter::A9:
+ dvips_options += "-t a9 ";
+ break;
+ case KPrinter::B0:
+ dvips_options += "-t b0 ";
+ break;
+ case KPrinter::B1:
+ dvips_options += "-t b1 ";
+ break;
+ case KPrinter::B10:
+ dvips_options += "-t b10 ";
+ break;
+ case KPrinter::B2:
+ dvips_options += "-t b2 ";
+ break;
+ case KPrinter::B3:
+ dvips_options += "-t b3 ";
+ break;
+ case KPrinter::B4:
+ dvips_options += "-t b4 ";
+ break;
+ case KPrinter::B6:
+ dvips_options += "-t b6 ";
+ break;
+ case KPrinter::B7:
+ dvips_options += "-t b7 ";
+ break;
+ case KPrinter::B8:
+ dvips_options += "-t b8 ";
+ break;
+ case KPrinter::B9:
+ dvips_options += "-t b9 ";
+ break;
+ case KPrinter::C5E:
+ dvips_options += "-t c5e ";
+ break;
+ case KPrinter::Comm10E:
+ dvips_options += "-t comm10e ";
+ break;
+ case KPrinter::DLE:
+ dvips_options += "-t dle ";
+ break;
+ case KPrinter::Folio:
+ dvips_options += "-t folio ";
+ break;
+ case KPrinter::Ledger:
+ dvips_options += "-t ledger ";
+ break;
+ case KPrinter::Tabloid:
+ dvips_options += "-t tabloid ";
+ break;
+ default:
+ break;
+ }
+ // Orientation
+ if ( printer->orientation() == KPrinter::Landscape )
+ dvips_options += "-t landscape ";
+
+
+ // List of pages to print.
+ QValueList<int> pageList = printer->pageList();
+ dvips_options += "-pp ";
+ int commaflag = 0;
+ for( QValueList<int>::ConstIterator it = pageList.begin(); it != pageList.end(); ++it ) {
+ if (commaflag == 1)
+ dvips_options += QString(",");
+ else
+ commaflag = 1;
+ dvips_options += QString("%1").arg(*it);
+ }
+
+ // Now print. For that, export the DVI-File to PostScript. Note that
+ // dvips will run concurrently to keep the GUI responsive, keep log
+ // of dvips and allow abort. Giving a non-zero printer argument
+ // means that the dvi-widget will print the file when dvips
+ // terminates, and then delete the output file.
+ KTempFile tf;
+ DVIRenderer.exportPS(tf.name(), dvips_options, printer);
+
+ // "True" may be a bit euphemistic. However, since dvips runs
+ // concurrently, there is no way of telling the result of the
+ // printing command at this stage.
+ return;
+}
+
+
+void KDVIMultiPage::enableActions(bool b)
+{
+ KMultiPage::enableActions(b);
+
+ docInfoAction->setEnabled(b);
+ exportPSAction->setEnabled(b);
+ exportPDFAction->setEnabled(b);
+
+ setEmbedPostScriptAction();
+}
+
+
+void KDVIMultiPage::doEnableWarnings()
+{
+ KMessageBox::information (scrollView(), i18n("All messages and warnings will now be shown."));
+ KMessageBox::enableAllMessages();
+ KTipDialog::setShowOnStart(true);
+}
+
+
+void KDVIMultiPage::showTip()
+{
+ KTipDialog::showTip(scrollView(), "kdvi/tips", true);
+}
+
+
+void KDVIMultiPage::showTipOnStart()
+{
+ KTipDialog::showTip(scrollView(), "kdvi/tips");
+}
+
+
+DocumentWidget* KDVIMultiPage::createDocumentWidget()
+{
+ DVIWidget* documentWidget = new DVIWidget(scrollView()->viewport(), scrollView(), pageCache,
+ "singlePageWidget" );
+
+ // Lets not forget the connections we make in the KMultiPage
+ connect(documentWidget, SIGNAL(clearSelection()), this, SLOT(clearSelection()));
+ connect(this, SIGNAL(enableMoveTool(bool)), documentWidget, SLOT(slotEnableMoveTool(bool)));
+
+ // Handle source links
+ connect(documentWidget, SIGNAL(SRCLink(const QString&, QMouseEvent*, DocumentWidget*)), getRenderer(),
+ SLOT(handleSRCLink(const QString& ,QMouseEvent*, DocumentWidget*)));
+
+ return documentWidget;
+}
+
+
+void KDVIMultiPage::initializePageCache()
+{
+ pageCache = new DVIPageCache();
+}
+
+
+void KDVIMultiPage::showFindTextDialog()
+{
+ if ((getRenderer().isNull()) || (getRenderer()->supportsTextSearch() == false))
+ return;
+
+ if (!searchUsed)
+ {
+ // WARNING: This text appears several times in the code. Change
+ // everywhere, or nowhere!
+ if (KMessageBox::warningContinueCancel( scrollView(),
+ i18n("<qt>This function searches the DVI file for plain text. Unfortunately, this version of "
+ "KDVI treats only plain ASCII characters properly. Symbols, ligatures, mathematical "
+ "formulae, accented characters, and non-English text, such as Russian or Korean, will "
+ "most likely be messed up completely. Continue anyway?</qt>"),
+ i18n("Function May Not Work as Expected"),
+ KStdGuiItem::cont(),
+ "warning_search_text_may_not_work") == KMessageBox::Cancel)
+ return;
+
+ // Remember that we don't need to show the warning message again.
+ searchUsed = true;
+ }
+
+ // Now really show the search widget
+ KMultiPage::showFindTextDialog();
+}
+
+#include "kdvi_multipage.moc"
diff --git a/kdvi/kdvi_multipage.h b/kdvi/kdvi_multipage.h
new file mode 100644
index 00000000..713afab7
--- /dev/null
+++ b/kdvi/kdvi_multipage.h
@@ -0,0 +1,96 @@
+// -*- C++ -*-
+#ifndef KDVIMULTIPAGE_H
+#define KDVIMULTIPAGE_H
+
+#include "kmultipage.h"
+#include "dviRenderer.h"
+
+#include <qstringlist.h>
+
+class KPrinter;
+
+class KDVIMultiPage : public KMultiPage
+{
+ Q_OBJECT
+
+public:
+ KDVIMultiPage(QWidget *parentWidget, const char *widgetName, QObject *parent,
+ const char *name, const QStringList& args = QStringList());
+ virtual ~KDVIMultiPage();
+
+// Interface definition start ------------------------------------------------
+
+ /// returns the list of supported file formats
+ virtual QStringList fileFormats() const;
+
+ virtual void setFile(bool r);
+
+ virtual void print();
+
+ /// KDVI offers read- and write functionality must re-implement this
+ /// method and return true here.
+ virtual bool isReadWrite() {return true;}
+
+ virtual void addConfigDialogs(KConfigDialog* configDialog);
+
+ static KAboutData* createAboutData();
+
+private:
+ virtual DocumentWidget* createDocumentWidget();
+
+ virtual void initializePageCache();
+
+ /** Used to enable the export menu when a file is successfully
+ loaded. */
+ virtual void enableActions(bool);
+
+public slots:
+ /** Opens a file requestor and saves. This really saves the content
+ of the DVI-file, and does not just start a copy job */
+ virtual void slotSave();
+
+ /** Similar to slotSave, but does not ask for a filename. */
+ virtual void slotSave_defaultFilename();
+
+ void setEmbedPostScriptAction();
+
+ void slotEmbedPostScript();
+
+ virtual void preferencesChanged();
+
+ /** Shows the "text search" dialog, if text search is supported by
+ the renderer. Otherwise, the method returns immediately.
+ We reimplement this slot to show a warning message that informs the
+ user about the currently limited search capabilities of KDVI. */
+ virtual void showFindTextDialog();
+
+protected slots:
+ void doExportText();
+ void doEnableWarnings();
+
+ void showTip();
+ void showTipOnStart();
+
+private:
+ // Points to the same object as renderer to avoid downcasting.
+ // FIXME: Remove when the API of the Renderer-class is finished.
+ dviRenderer DVIRenderer;
+
+ // Set to true if we used the search function atleast once.
+ // It is used to remember if we already have show the warning message.
+ bool searchUsed;
+
+ /*************************************************************
+ * Methods and classes concerned with the find functionality *
+ *************************************************************/
+
+ /** Pointers to several actions which are disabled if no file is
+ loaded. */
+ KAction *docInfoAction;
+ KAction *embedPSAction;
+ KAction *exportPDFAction;
+ KAction *exportPSAction;
+};
+
+
+#endif
diff --git a/kdvi/kdvi_multipage_texthandling.cpp b/kdvi/kdvi_multipage_texthandling.cpp
new file mode 100644
index 00000000..c667584e
--- /dev/null
+++ b/kdvi/kdvi_multipage_texthandling.cpp
@@ -0,0 +1,70 @@
+//
+// Class: kdvi_multipage
+// Author: Stefan Kebekus
+//
+// (C) 2001-2005, Stefan Kebekus.
+//
+// Previewer for TeX DVI files.
+//
+// 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.
+//
+// Please report bugs or improvements, etc. via the "Report bug"-Menu
+// of kdvi.
+
+#include <config.h>
+
+#include <kaction.h>
+#include <kdebug.h>
+#include <keditcl.h>
+#include <kfiledialog.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <qapplication.h>
+#include <qprogressdialog.h>
+
+#include "kdvi_multipage.h"
+#include "dviFile.h"
+#include "documentWidget.h"
+#include "renderedDocumentPagePixmap.h"
+
+
+//#define KDVI_MULTIPAGE_DEBUG
+
+
+void KDVIMultiPage::doExportText()
+{
+#ifdef KDVI_MULTIPAGE_DEBUG
+ kdDebug(4300) << "KDVIMultiPage::doExportText() called" << endl;
+#endif
+
+ // Paranoid safety checks
+ if (DVIRenderer.dviFile == 0)
+ return;
+ if (DVIRenderer.dviFile->dvi_Data() == 0 )
+ return;
+
+ if (KMessageBox::warningContinueCancel( scrollView(),
+ i18n("<qt>This function exports the DVI file to a plain text. Unfortunately, this version of "
+ "KDVI treats only plain ASCII characters properly. Symbols, ligatures, mathematical "
+ "formulae, accented characters, and non-English text, such as Russian or Korean, will "
+ "most likely be messed up completely.</qt>"),
+ i18n("Function May Not Work as Expected"),
+ i18n("Continue Anyway"),
+ "warning_export_to_text_may_not_work") == KMessageBox::Cancel)
+ return;
+
+ KMultiPage::doExportText();
+}
diff --git a/kdvi/kdvi_part.rc b/kdvi/kdvi_part.rc
new file mode 100644
index 00000000..ded5f346
--- /dev/null
+++ b/kdvi/kdvi_part.rc
@@ -0,0 +1,26 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="kdvi_part" version="4">
+<MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="info_dvi" group="info_merge"/>
+ <Menu name="export" group="print_merge" ><text>Export As</text>
+ <Action name="export_postscript" group="export_merge"/>
+ <Action name="export_pdf" group="export_merge"/>
+ </Menu>
+ </Menu>
+
+ <Menu name="edit"><text>&amp;Edit</text>
+ <Separator/>
+ <Action name="embed_postscript"/>
+ </Menu>
+
+ <Menu name="settings"><text>&amp;Settings</text>
+ <Action name="enable_msgs" group="additional_settings_merge"/>
+ </Menu>
+
+ <Menu name="help"><text>&amp;Help</text>
+ <Action name="help_tipofday" group="help_top"/>
+ </Menu>
+</MenuBar>
+
+</kpartgui>
diff --git a/kdvi/kdvimultipage.desktop b/kdvi/kdvimultipage.desktop
new file mode 100644
index 00000000..48a5e1fb
--- /dev/null
+++ b/kdvi/kdvimultipage.desktop
@@ -0,0 +1,18 @@
+[Desktop Entry]
+Type=Service
+Comment=DVI
+Name=KDVIMultiPage
+Name[es]=KDVIMultiPágina
+Name[fr]=Multi-page KDVI
+Name[hu]=KDVITöbbOldalas
+Name[nb]=KDVI Flerside
+Name[ne]=केडीभीआई बहुपृष्ठ
+Name[nl]=KDVIMultiPagina
+Name[nn]=KDVI-fleirside
+Name[pt]=KDVIMultiPágina
+Name[ro]=KDVI Pagini Multiple
+Name[sv]=KDVI flera sidor
+ServiceTypes=KViewShell/MultiPage
+X-KDE-Library=kdvipart
+X-KDE-MimeTypes=application/x-dvi
+X-KDE-MultiPageVersion=2
diff --git a/kdvi/kprinterwrapper.h b/kdvi/kprinterwrapper.h
new file mode 100644
index 00000000..03959361
--- /dev/null
+++ b/kdvi/kprinterwrapper.h
@@ -0,0 +1,24 @@
+// -*- C++ -*-
+// kprinterwrapper.h
+//
+// Part of KDVI - A DVI previewer for the KDE desktop environemt
+//
+// (C) 2003 Stefan Kebekus
+// Distributed under the GPL
+
+
+#ifndef _PRINTERWRAPPER_H
+#define _PRINTERWRAPPER_H
+
+#include "kprinter.h"
+
+
+class KDVIPrinterWrapper : public KPrinter
+{
+public:
+ KDVIPrinterWrapper() : KPrinter(true, QPrinter::ScreenResolution) {; };
+
+ void doPreparePrinting() { preparePrinting(); };
+};
+
+#endif
diff --git a/kdvi/main.cpp b/kdvi/main.cpp
new file mode 100644
index 00000000..4340f0e8
--- /dev/null
+++ b/kdvi/main.cpp
@@ -0,0 +1,154 @@
+#include <config.h>
+
+#include <dcopclient.h>
+#include <dcopref.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kdebug.h>
+#include <kurl.h>
+#include <klocale.h>
+#include <kaboutdata.h>
+#include <qdir.h>
+
+#include <stdlib.h>
+
+#include "kviewshell.h"
+
+
+static KCmdLineOptions options[] =
+{
+ { "u", 0, 0 },
+ { "unique", I18N_NOOP("Check if the file is loaded in another KDVI.\nIf it is, bring up the other KDVI. Otherwise, load the file."), 0 },
+ { "g", 0, 0 },
+ { "goto <pagenumber>", I18N_NOOP("Navigate to this page"), 0 },
+ { "+file(s)", I18N_NOOP("Files to load"), 0 },
+ KCmdLineLastOption
+};
+
+
+static const char description[] = I18N_NOOP("A previewer for Device Independent files (DVI files) produced by the TeX typesetting system.");
+
+
+int main(int argc, char** argv)
+{
+ KAboutData about ("kdvi", I18N_NOOP("KDVI"), "1.4",
+ description, KAboutData::License_GPL,
+ "Markku Hinhala, Stephan Kebekus",
+ I18N_NOOP("This program displays Device Independent (DVI) files which are produced by the TeX typesetting system.\n"
+ "This KDVI version is based on original code from KDVI version 0.43 and xdvik."));
+
+ about.addAuthor ("Stefan Kebekus",
+ I18N_NOOP("Current Maintainer."),
+ "kebekus@kde.org",
+ "http://www.mi.uni-koeln.de/~kebekus");
+
+ about.addAuthor ("Markku Hinhala", I18N_NOOP("Author of kdvi 0.4.3"));
+ about.addAuthor ("Nicolai Langfeldt", I18N_NOOP("Maintainer of xdvik"));
+ about.addAuthor ("Paul Vojta", I18N_NOOP("Author of xdvi"));
+ about.addCredit ("Philipp Lehmann", I18N_NOOP("Testing and bug reporting."));
+ about.addCredit ("Wilfried Huss", I18N_NOOP("Re-organisation of source code."));
+
+ KCmdLineArgs::init(argc, argv, &about);
+ KCmdLineArgs::addCmdLineOptions(options);
+ KApplication app;
+
+ // see if we are starting with session management
+ if (app.isRestored())
+ {
+ RESTORE(KViewShell);
+ }
+ else
+ {
+ KCmdLineArgs* args = KCmdLineArgs::parsedArgs();
+
+ if (args->isSet("unique"))
+ {
+ // With --unique, we need 2 arguments.
+ if (args->count() < 1)
+ {
+ args->usage();
+ exit(-1);
+ }
+
+ // Find the fully qualified file name of the file we are
+ // loading. Complain, if we are given a URL which does not point
+ // to a local file.
+ KURL url(args->url(0));
+
+ if (!url.isValid())
+ {
+ kdError(4300) << QString(I18N_NOOP("The URL %1 is not well-formed.")).arg(args->arg(0)) << endl;
+ return -1;
+ }
+
+ if (!url.isLocalFile())
+ {
+ kdError(4300) << QString(I18N_NOOP("The URL %1 does not point to a local file. You can only specify local "
+ "files if you are using the '--unique' option.")).arg(args->arg(0)) << endl;
+ return -1;
+ }
+
+ QString qualPath = QFileInfo(url.path()).absFilePath();
+
+ app.dcopClient()->attach();
+ // We need to register as "kviewshell" to stay compatible with existing DCOP-skripts.
+ QCString id = app.dcopClient()->registerAs("unique-kviewshell");
+ if (id.isNull())
+ kdError(4300) << "There was an error using dcopClient()->registerAs()." << endl;
+ QCStringList apps = app.dcopClient()->registeredApplications();
+ for ( QCStringList::Iterator it = apps.begin(); it != apps.end(); ++it )
+ {
+ if ((*it).find("kviewshell") == 0)
+ {
+ QByteArray data, replyData;
+ QCString replyType;
+ QDataStream arg(data, IO_WriteOnly);
+ bool result;
+ arg << qualPath.stripWhiteSpace();
+ if (!app.dcopClient()->call( *it, "kmultipage", "is_file_loaded(QString)", data, replyType, replyData))
+ kdError(4300) << "There was an error using DCOP." << endl;
+ else
+ {
+ QDataStream reply(replyData, IO_ReadOnly);
+ if (replyType == "bool")
+ {
+ reply >> result;
+ if (result == true)
+ {
+ if (app.dcopClient()->send( *it, "kmultipage", "jumpToReference(QString)", url.ref()) == true)
+ {
+ app.dcopClient()->detach();
+ return 0;
+ }
+ }
+ }
+ else
+ kdError(4300) << "The DCOP function 'doIt' returned an unexpected type of reply!";
+ }
+ }
+ }
+ }
+
+ // We need to register as "kviewshell" to stay compatible with existing DCOP-skripts.
+ app.dcopClient()->registerAs("kviewshell");
+ KViewShell* shell = new KViewShell("application/x-dvi");
+ shell->show();
+ app.processEvents();
+
+ if (args->count() > 0)
+ {
+ KURL url = args->url(0);
+ if (!url.hasRef() && args->isSet("goto"))
+ {
+ // If the url doesn't already has a reference part, add the
+ // argument of --goto to the url as reference, to make the
+ // KViewShell jump to this page.
+ QString reference = args->getOption("goto");
+ url.setHTMLRef(reference);
+ }
+ shell->openURL(url);
+ }
+ }
+
+ return app.exec();
+}
diff --git a/kdvi/make/ChangeLog b/kdvi/make/ChangeLog
new file mode 100644
index 00000000..7f808ed6
--- /dev/null
+++ b/kdvi/make/ChangeLog
@@ -0,0 +1,370 @@
+Thu Apr 13 11:03:10 1995 Ulrik Vieth <vieth@thphy.uni-duesseldorf.de>
+
+ * paths.make: Add new variables for MetaPost directories:
+ mpinputdir, memdir, mppooldir.
+
+ * makevars.make: Make sure that new variables for MetaPost
+ directories are passed on to sub-makes.
+
+Sun Jan 8 12:16:36 1995 Karl Berry <karl@cs.umb.edu>
+
+ * kpathsea 2.6/dviljk 2.5/dvipsk 5.58f/xdvik 18f.
+
+Wed Jan 4 12:41:25 1995 Karl Berry <karl@cs.umb.edu>
+
+ * tkpathsea.make (kpathsea): Don't depend on texmf.cnf, since it
+ doesn't exist at the first make.
+
+Tue Jan 3 13:43:12 1995 Karl Berry <karl@cs.umb.edu>
+
+ * rdepend.make (depend): paths.h is not in the srcdir.
+
+ * config.make (autoconf): Add acsite.m4.
+
+ * dist.make (top_files): FTP belongs here, not in ln_files.
+
+Sun Jan 1 14:02:42 1995 Karl Berry <karl@cs.umb.edu>
+
+ * makevars.make (makevars): Include web2cdir.
+ * paths.make (web2cdir): New directory. Suggested by Joachim.
+
+Sat Dec 31 14:35:29 1994 Karl Berry <karl@cs.umb.edu>
+
+ * tmtpk.make: Just incorporate this in kpathsea/Makefile.in now.
+
+ * rdepend.make (depend): Depend on ourselves.
+
+Fri Dec 30 15:50:37 1994 Karl Berry <karl@cs.umb.edu>
+
+ * rdepend.make (depend): Use kpathsea_srcdir, not kpathsea_dir.
+ From Joachim.
+
+Wed Dec 28 14:16:50 1994 Karl Berry <karl@cs.umb.edu>
+
+ * dist.make (ln_files): Add FTP.
+
+Mon Dec 26 10:31:14 1994 Karl Berry <karl@cs.umb.edu>
+
+ * dist.make (dist): Copy aclocal.m4 from acsite.m4.
+ Suggested by interran@uluru.Stanford.EDU (John Interrante).
+
+Wed Dec 14 15:17:42 1994 Karl Berry <karl@cs.umb.edu>
+
+ * kpathsea 2.5/dviljk 2.4/dvipsk 5.58e/xdvik 18e.
+
+Sun Dec 11 13:23:12 1994 Karl Berry <karl@cs.umb.edu>
+
+ * rdepend.make (depend): Remove system include files that are
+ alone on a line.
+
+Fri Nov 25 09:21:02 1994 Karl Berry <karl@cs.umb.edu>
+
+ * tmtpk.make (MakeTeXPK): Depend on the new filename.
+
+Tue Nov 15 15:28:14 1994 Karl Berry <karl@cs.umb.edu>
+
+ * tkpathsea.make (makeargs): Change MAKEARGS to XMAKEARGS.
+
+ * targets.make (makeargs): Don't bother to pass $(SHELL).
+
+Tue Nov 8 19:12:45 1994 Karl Berry <karl@cs.umb.edu>
+
+ * common.make (CFLAGS): Don't include -g, since now it's automatic.
+
+Sun Nov 6 15:53:36 1994 Karl Berry <karl@cs.umb.edu>
+
+ * paths.make (prefix, exec_prefix): These value are now @prefix@
+ and @exec_prefix@.
+
+ * common.make: Call @SET_MAKE@.
+
+ * misc.make (distclean): Remove config.log and config.cache.
+
+ * programs.make (LDFLAGS): Add @LDFLAGS@.
+ * common.make (CPPFLAGS): Add @CPPFLAGS@.
+ (CFLAGS): Add @CFLAGS@.
+
+ * dist.make (top_files): Distribute install-sh, not install.sh,
+ for Autoconf 2.0.
+
+Sun Oct 30 16:15:34 1994 Karl Berry <karl@cs.umb.edu>
+
+ * config.make (ac_dir): This is now $(gnu)/share.
+
+Tue Oct 25 17:48:02 1994 Karl Berry <karl@cs.umb.edu>
+
+ * kpathsea 2.3/dviljk 2.3/dvipsk 5.58c/xdvik 18d.
+
+Sun Oct 23 17:33:56 1994 Karl Berry <karl@cs.umb.edu>
+
+ * targets.make (MakeTeXPK): Make sed substitutions global.
+ Reported by wfranzki@hlrserv.hlrz.kfa-juelich.de.
+
+Mon Oct 17 13:28:41 1994 Karl Berry <karl@cs.umb.edu>
+
+ * paths.make (mfpooldir): Doc fix.
+
+Fri Oct 14 10:31:35 1994 Karl Berry <karl@cs.umb.edu>
+
+ * kpathsea 2.2/dviljk 2.2/dvipsk 5.58b/xdvik 18c.
+
+Mon Oct 10 15:31:06 1994 Karl Berry <karl@cs.umb.edu>
+
+ * common.make (.SUFFIXES): Declare .c.o.
+
+ * programs.make (LOADLIBES): Omit LEXLIB here.
+
+Sun Sep 25 15:54:36 1994 Karl Berry <karl@cs.umb.edu>
+
+ * rdepend.make: Doc fix.
+
+ * library.make: New file.
+
+ * makevars.make (makevars): Remove MAKEARGS from here.
+
+ * programs.make (CCLD, link_command): New variables.
+ (LOADLIBES): Add proglib, LEXLIB.
+
+Mon Sep 12 11:06:14 1994 Karl Berry (karl@cs.umb.edu)
+
+ * kpathsea 2.1/dviljk 2.1/dvipsk 5.58a/xdvik 18b.
+
+Sun Sep 11 14:44:21 1994 Karl Berry (karl@cs.umb.edu)
+
+ * targets.make (install-MakeTeXPK): Install this if it didn't
+ exist, and mkdirchain $(scriptdir).
+
+ * dist.make (top_files): Include aclocal.m4.
+
+Sat Sep 10 13:40:10 1994 Karl Berry (karl@cs.umb.edu)
+
+ * texi.make (.texi.dvi): No -o option to texi2dvi.
+
+Thu Sep 8 14:31:59 1994 Karl Berry (karl@cs.umb.edu)
+
+ * kpathsea 2.0, dviljk 2.0, dvipsk 5.55b, xdvik 18a.
+
+Tue Sep 6 11:39:06 1994 Karl Berry (karl@cs.umb.edu)
+
+ * targets.make (MakeTeXPK): Use psheaderdir, not psconfigdir, and
+ depend on ourselves.
+
+Sat Sep 3 08:37:11 1994 Karl Berry (karl@cs.umb.edu)
+
+ * paths.make (psconfigdir): Toss this.
+
+ * misc.make (distclean): Add MakeTeXPK.
+
+ * rdepend.make: Rename from depend.make.
+
+Fri Sep 2 13:29:14 1994 Karl Berry (karl@cs.umb.edu)
+
+ * targets.make (makeargs, installargs): Declare these here.
+
+ * makevars.make (makevars): No need for ??_fontdir or psmacrodir.
+
+ * misc.make (TAGS): Omit -t, use -i, for Emacs 19.25's etags.
+
+Thu Sep 1 17:51:10 1994 Karl Berry (karl@cs.umb.edu)
+
+ * dist.make (top_files): Add install.sh.
+
+Tue Aug 30 14:46:18 1994 Karl Berry (karl@cs.umb.edu)
+
+ * dist.make (dist): Touch *.info* if they exist.
+
+Mon Aug 29 16:28:19 1994 Karl Berry (karl@cs.umb.edu)
+
+ * paths.make (dcfontdir, sauterdir): Move these here, since
+ everyone has MakeTeXPK now.
+
+Sun Aug 28 17:09:09 1994 Karl Berry (karl@cs.umb.edu)
+
+ * common.make (INSTALL_FONTS): New variable.
+
+Thu Aug 25 17:04:43 1994 Karl Berry (karl@cs.umb.edu)
+
+ * kpathsea.make (kpathsea): Also depend on texmf.cnf.in.
+
+ * paths.make (texmf_prefix): Rename to texmf; change uses.
+
+Sun Aug 21 11:03:48 1994 Karl Berry (karl@cs.umb.edu)
+
+ * programs.make: New file for driver-specific stuff.
+
+ * paths.make (fontnamedir): New definition.
+ (configdir, headerdir): Prepend with `ps'.
+
+Sat Aug 13 17:19:53 1994 Karl Berry (karl@cs.umb.edu)
+
+ * misc.make (mostlyclean): Don't remove $(lib), since we've tossed
+ that.
+
+Sun Jul 31 14:18:28 1994 Karl Berry (karl@cs.umb.edu)
+
+ * paths.make (DB_DIR, DB_NAME): Remove from here.
+
+Fri Jul 29 14:56:47 1994 Karl Berry (karl@cs.umb.edu)
+
+ * depend.make (depend): Add dvilj4l.o to the special cases.
+
+Sun Jul 17 11:37:57 1994 Karl Berry (karl@cs.umb.edu)
+
+ * paths.make (db_dir): Use $TEXMF.
+
+Mon Jun 27 17:32:47 1994 Karl Berry (karl@cs.umb.edu)
+
+ * paths.make (db_dir): Use $TEXMFROOT.
+
+Tue Jun 14 12:41:33 1994 Karl Berry (karl@cs.umb.edu)
+
+ * depend.make (depend): No need for depend_encies, I think.
+
+Mon May 30 13:50:34 1994 Karl Berry (karl@cs.umb.edu)
+
+ * common.make (LDFLAGS): Don't include $(CFLAGS), for Linux's sake.
+
+Tue May 24 13:26:05 1994 Karl Berry (karl@cs.umb.edu)
+
+ * config.make (stamp-auto, stamp-auto.in): New targets, to avoid
+ rerunning autoheader/autoconf even when they don't change the main
+ output files.
+
+Sun Apr 17 16:11:34 1994 Karl Berry (karl@ra.cs.umb.edu)
+
+ * config.make (configure): Change ; to && in case the cd fails.
+
+Thu Mar 24 11:12:56 1994 Karl Berry (karl@cs.umb.edu)
+
+ * dist.make (dist): Don't append kutil/ChangeLog to the source
+ ChangeLog.
+
+ * misc.make (extraclean): Don't delete patch*, since that kills
+ patchlevel.h.
+
+Sat Mar 5 13:48:15 1994 Karl Berry (karl@cs.umb.edu)
+
+ * common.make (LOADLIBES): Include XLOADLIBES.
+
+Fri Feb 25 14:21:17 1994 Karl Berry (karl@cs.umb.edu)
+
+ * dist.make (dist): Append kutil/ChangeLog to the top level, not
+ the main program.
+
+Thu Feb 24 16:11:37 1994 Karl Berry (karl@cs.umb.edu)
+
+ * misc.make (clean): Remove *.lj here.
+
+ * paths.make ({bh,cg,mt}_fontdir, install_fonts): Add these.
+
+Mon Feb 21 14:04:26 1994 Karl Berry (karl@cs.umb.edu)
+
+ * misc.make (distclean): remove pool files here.
+
+Wed Feb 16 15:18:13 1994 Karl Berry (karl@cs.umb.edu)
+
+ * paths.make: Doc fix.
+
+Sun Jan 23 17:17:37 1994 Karl Berry (karl@cs.umb.edu)
+
+ * dist.make (dist): Don't fake kpathsea/MACHINES any more, now we
+ have a real one.
+
+Fri Jan 14 14:53:12 1994 Karl Berry (karl@cs.umb.edu)
+
+ * paths.make ({tex,mf}pooldir, fmtdir, basedir): Use
+ $(texmf_prefix)/ini for all these.
+
+Tue Dec 21 19:23:29 1993 Karl Berry (karl@cs.umb.edu)
+
+ * common.make (LDFLAGS): Don't include $(x_lib_flags) here --
+ winds up getting included twice for virmf
+
+Tue Dec 14 17:40:23 1993 Karl Berry (karl@cs.umb.edu)
+
+ * dist.make (dist): Dist the top-level and kutil/ChangeLog.
+
+ * paths.make (formatdir): Rename to fmtdir.
+ (texprefix): Rename to texmf_prefix, change uses accordingly.
+
+Fri Dec 10 17:50:39 1993 Karl Berry (karl@cs.umb.edu)
+
+ * paths.make (dvipsprefix): Rename to dvips_prefix.
+
+Sun Nov 14 11:52:33 1993 Karl Berry (karl@cs.umb.edu)
+
+ * dist.make (dist): Do not depend on depend.make and TAGS, since
+ web2c doesn't have them.
+
+ * paths.make: Change defaults for new hierarchy.
+
+Thu Nov 11 11:07:22 1993 Karl Berry (karl@cs.umb.edu)
+
+ * common.make (CPPFLAGS, LDFLAGS): xincludedir, xlibdir, wlibs
+ names have changed.
+
+Sun Nov 7 15:22:32 1993 Karl Berry (karl@cs.umb.edu)
+
+ * paths.h: Give dire warning that editing Makefiles will not
+ rebuild paths.h.
+
+Fri Oct 29 14:01:57 1993 Karl Berry (karl@cs.umb.edu)
+
+ * dist.make (dist): chmod a+rw.
+
+Thu Oct 28 17:48:01 1993 Karl Berry (karl@cs.umb.edu)
+
+ * common.make (CPPFLAGS): Include -I. before -I$(srcdir).
+
+Fri Oct 22 13:08:19 1993 Karl Berry (karl@cs.umb.edu)
+
+ * paths.make: Remove the paths, and add the dvips directories.
+
+ * common.make (kpathsea_srcdir{,_parent}): Define. From
+ simon@lia.di.epfl.ch.
+
+Tue Oct 19 15:59:03 1993 Karl Berry (karl@cs.umb.edu)
+
+ * config.make (stamp-c-auto): New target.
+ (c-auto.h): Depend on it.
+
+Sat Oct 9 07:04:45 1993 Karl Berry (karl@cs.umb.edu)
+
+ * misc.make (mostlyclean): Remove programs.
+
+Sun Oct 3 12:44:04 1993 Karl Berry (karl@cs.umb.edu)
+
+ * misc.make (extraclean): Also remove .blg and .bbl, .vf and .vpl.
+ (clean): Remove *.pool.
+
+Tue Sep 28 13:11:01 1993 Karl Berry (karl@cs.umb.edu)
+
+ * common.make (CPPFLAGS): Add $(xincludedir) again; when did I
+ remove it?
+
+Fri Sep 24 07:53:45 1993 Karl Berry (karl@cs.umb.edu)
+
+ * common.make (warn_more) [kpathsea]: Move to kpathsea's Makefile.
+
+ * texi.make (.texi.dvi): New rule.
+
+ * common.make (warn_more): Had -pointer-arith twice.
+
+Thu Sep 23 17:42:42 1993 Karl Berry (karl@cs.umb.edu)
+
+ * common.make (autoconf): Toss aclocal.m4.
+ * dist.make (top_files): Ditto.
+
+ * common.make (autoheader): New variable, split off from autoconf.
+
+Sun Aug 29 11:30:39 1993 Karl Berry (karl@cs.umb.edu)
+
+ * dist.make (dist): Remove MACHINES in kpathsea.
+
+ * common.make (CPPFLAGS): Remove the -I. Why did I put it there?
+
+Sat Aug 28 07:01:52 1993 Karl Berry (karl@cs.umb.edu)
+
+ * unbackslsh.awk: New file.
+
+ * common.make (CPPFLAGS): Add -I before $(xincludedir).
diff --git a/kdvi/make/README b/kdvi/make/README
new file mode 100644
index 00000000..f91b3d16
--- /dev/null
+++ b/kdvi/make/README
@@ -0,0 +1,3 @@
+make -- this subdirectory contains Makefile fragments.
+configure substitutes them for ac_include lines in Makefile.in.
+(This is an enhancement to standard Autoconf; see aclocal.m4.)
diff --git a/kdvi/make/common.make b/kdvi/make/common.make
new file mode 100644
index 00000000..9d9f822d
--- /dev/null
+++ b/kdvi/make/common.make
@@ -0,0 +1,42 @@
+# common.make -- used by all Makefiles.
+SHELL = /bin/sh
+@SET_MAKE@
+top_srcdir = @top_srcdir@
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+CC = @CC@
+# CFLAGS is used for both compilation and linking.
+CFLAGS = @CFLAGS@ $(XCFLAGS)
+
+# Do not override CPPFLAGS; change XCPPFLAGS, CFLAGS, XCFLAGS, or DEFS instead.
+CPPFLAGS = $(XCPPFLAGS) -I. -I$(srcdir) \
+ -I$(kpathsea_parent) -I$(kpathsea_srcdir_parent) \
+ $(prog_cflags) @CPPFLAGS@ $(DEFS)
+.c.o:
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c $<
+.SUFFIXES: .c .o
+
+# Installation.
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+# This is used to recursively copy a fonts/ or tex/ directory to
+# $(fontdir) or $(texinputdir).
+# The first arg is `.', and the second is the target directory.
+CP_R = cp -r
+
+# This is so kpathsea will get remade automatically if you change
+# something in it and recompile from the package directory.
+kpathsea_parent = ..
+kpathsea_dir = $(kpathsea_parent)/kpathsea
+kpathsea_srcdir_parent = $(top_srcdir)/..
+kpathsea_srcdir = $(kpathsea_srcdir_parent)/kpathsea
+kpathsea = $(kpathsea_dir)/kpathsea.a
+
+##ifeq ($(CC), gcc)
+##XDEFS = -Wall -Wpointer-arith $(warn_more)
+##CFLAGS = -g $(XCFLAGS)
+##endif
+# End of common.make.
diff --git a/kdvi/make/config.make b/kdvi/make/config.make
new file mode 100644
index 00000000..c35cbebe
--- /dev/null
+++ b/kdvi/make/config.make
@@ -0,0 +1,39 @@
+# config.make -- autoconf rules to remake the Makefile, c-auto.h, etc.
+
+##ifdef HOSTNAME
+##ac_dir = $(gnu)/share/autoconf
+##autoconf = $(ac_dir)/acspecific.m4 $(ac_dir)/acgeneral.m4 $(ac_dir)/acsite.m4
+##autoheader = $(ac_dir)/acconfig.h
+##
+### I define $(autoconf) to acgeneral.m4 and the other Autoconf files, so
+### configure automatically gets remade in the sources with a new Autoconf
+### release. But it would be bad for installers with Autoconf to remake
+### configure (not to mention require Autoconf), so I take out the variable
+### $(autoconf) definition before release.
+##configure_in = $(srcdir)/configure.in $(kpathsea_srcdir)/common.ac
+##$(srcdir)/configure: $(configure_in) $(autoconf)
+## cd $(srcdir) && autoconf
+##endif
+
+config.status: $(srcdir)/configure
+ $(SHELL) $(srcdir)/configure --no-create --verbose
+
+Makefile: $(srcdir)/Makefile.in config.status
+ $(SHELL) config.status
+
+# This rule isn't used for web2c or the top-level Makefile, but it
+# doesn't hurt. We don't depend on config.status because configure
+# always rewrites config.status, even when it doesn't change. Thus it
+# might be newer than c-auto.h when we don't need to remake the latter.
+c-auto.h: $(srcdir)/stamp-auto
+$(srcdir)/stamp-auto: $(srcdir)/c-auto.h.in
+ $(SHELL) config.status
+ touch $(srcdir)/stamp-auto
+
+##ifdef HOSTNAME
+### autoheader reads acconfig.h (and c-auto.h.top) automatically.
+##$(srcdir)/c-auto.h.in: $(srcdir)/stamp-auto.in
+##$(srcdir)/stamp-auto.in: $(configure_in) $(autoheader) $(srcdir)/acconfig.h
+## cd $(srcdir) && autoheader
+## touch $(srcdir)/stamp-auto.in
+##endif
diff --git a/kdvi/make/dist.make b/kdvi/make/dist.make
new file mode 100644
index 00000000..39c619c7
--- /dev/null
+++ b/kdvi/make/dist.make
@@ -0,0 +1,33 @@
+# dist.make -- how to make the distribution tar file.
+
+top_distdir = $(distname)-$(version)
+top_files = ChangeLog FTP Makefile.in configure configure.in README \
+ $(HOME)/gnu/gnuorg/COPYING* $(HOME)/gnu/gnuorg/install-sh \
+ $(HOME)/bin/mkdirchain \
+ $(plain)/texinfo.tex
+distdir = $(top_distdir)/$(distname)
+kpathsea_distdir = ../$(distname)/$(top_distdir)/kpathsea
+ln_files = AUTHORS ChangeLog INSTALL NEWS README TAGS *.in *.h *.c \
+ configure *.make .gdbinit stamp-auto
+
+dist: depend.make TAGS pre-dist-$(distname)
+ rm -rf $(top_distdir)*
+ mkdir -p $(distdir)
+ cd ..; make Makefile ./configure
+ cd ..; cp -p $(top_files) $(distname)/$(top_distdir)
+ ln -s $(gnu)/share/autoconf/acsite.m4 $(top_distdir)/aclocal.m4
+ -ln $(ln_files) $(distdir)
+ ln $(program_files) $(distdir)
+ cd $(kpathsea_dir); $(MAKE) distdir=$(kpathsea_distdir) \
+ ln_files='$(ln_files)' distdir
+ cp -rp ../make $(top_distdir)
+ ungnumake $(distdir)/Makefile.in $(kpathsea_distdir)/Makefile.in \
+ $(top_distdir)/Makefile.in $(top_distdir)/make/*.make
+# Remove the extra files our patterns got us.
+ cd $(top_distdir); rm -f */depend.make */c-auto.h */Makefile
+ $(MAKE) post-dist-$(distname)
+ cd $(distdir); add-version $(version) $(version_files)
+ cd $(distdir); test ! -r *.info || touch *.info*
+ chmod -R a+rwX $(top_distdir)
+ GZIP=-9 tar chzf $(top_distdir).tar.gz $(top_distdir)
+ rm -rf $(top_distdir)
diff --git a/kdvi/make/library.make b/kdvi/make/library.make
new file mode 100644
index 00000000..c343bfd7
--- /dev/null
+++ b/kdvi/make/library.make
@@ -0,0 +1,5 @@
+# library.make -- stuff only useful for libraries.
+AR = ar
+ARFLAGS = cq
+RANLIB = @RANLIB@
+# End of library.make.
diff --git a/kdvi/make/makevars.make b/kdvi/make/makevars.make
new file mode 100644
index 00000000..4b14f1be
--- /dev/null
+++ b/kdvi/make/makevars.make
@@ -0,0 +1,20 @@
+# makevars.make -- the directory names we pass.
+# It's important that none of these values contain [ @%], for the sake
+# of kpathsea/texmf.sed.
+makevars = prefix=$(prefix) exec_prefix=$(exec_prefix) \
+ platform=$(platform) \
+ bindir=$(bindir) scriptdir=$(scriptdir) libdir=$(libdir) \
+ datadir=$(datadir) infodir=$(infodir) includedir=$(includedir) \
+ manext=$(manext) mandir=$(mandir) \
+ texmf=$(texmf) web2cdir=$(web2cdir) \
+ texinputdir=$(texinputdir) mfinputdir=$(mfinputdir) \
+ mpinputdir=$(mpinputdir) \
+ fontdir=$(fontdir) \
+ fmtdir=$(fmtdir) basedir=$(basedir) \
+ memdir=$(memdir) \
+ texpooldir=$(texpooldir) mfpooldir=$(mfpooldir) \
+ mppooldir=$(mppooldir) \
+ install_fonts=$(install_fonts) \
+ dvipsdir=$(dvipsdir) psheaderdir=$(psheaderdir) \
+ default_texsizes='$(default_texsizes)'
+# End of makevars.make.
diff --git a/kdvi/make/misc.make b/kdvi/make/misc.make
new file mode 100644
index 00000000..7ee38cca
--- /dev/null
+++ b/kdvi/make/misc.make
@@ -0,0 +1,31 @@
+# misc.make -- cleaning, etc.
+TAGS: *.c *.h
+ if pwd | grep kpathsea >/dev/null; then \
+ etags *.c *.h; else etags -i $(kpathsea_dir)/TAGS *.c *.h; fi
+
+mostlyclean::
+ rm -f *.o $(program) $(programs) squeeze $(library).a
+
+clean:: mostlyclean
+ rm -f *.dvi *.lj
+
+distclean:: clean
+ rm -f Makefile MakeTeXPK *.pool
+ rm -f config.status config.log config.cache c-auto.h
+
+# Although we can remake configure and c-auto.h.in, we don't remove
+# them, since many people may lack Autoconf. Use configclean for that.
+realclean:: distclean
+ rm -f TAGS *.info*
+
+extraclean::
+ rm -f *.aux *.bak *.bbl *.blg *.dvi *.log *.orig *.pl *.rej
+ rm -f *.i *.s *.tfm *.vf *.vpl *\#* *gf *pk *~
+ rm -f CONTENTS.tex a.out core mfput.* texput.*
+
+configclean:
+ rm -f configure c-auto.h.in c-auto.h
+
+# Prevent GNU make 3.[59,63) from overflowing arg limit on system V.
+.NOEXPORT:
+# End of misc.make.
diff --git a/kdvi/make/paths.make b/kdvi/make/paths.make
new file mode 100644
index 00000000..529612cc
--- /dev/null
+++ b/kdvi/make/paths.make
@@ -0,0 +1,99 @@
+# paths.make -- installation directories.
+#
+# The compile-time paths are defined in kpathsea/paths.h, which is built
+# from kpathsea/paths.h.in and these definitions. See kpathsea/INSTALL
+# for a description of how the various path-related files are used and
+# created.
+
+# Do not change prefix and exec_prefix in Makefile.in!
+# configure doesn't propagate the change to the other Makefiles.
+# Instead, give the -prefix/-exec-prefix options to configure.
+# (See kpathsea/INSTALL for more details.) This is arguably
+# a bug, but it's not likely to change soon.
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+platform = $(shell $(srcdir)/config.guess | sed 's/-.*-/-/')
+
+# Architecture-dependent executables.
+bindir = $(exec_prefix)/bin/$(platform)
+
+# Architecture-independent executables.
+scriptdir = $(bindir)
+
+# Architecture-dependent files, such as lib*.a files.
+libdir = $(exec_prefix)/lib
+
+# Architecture-independent files.
+datadir = $(prefix)/lib
+
+# Header files.
+includedir = $(prefix)/include
+
+# GNU .info* files.
+infodir = $(prefix)/info
+
+# Unix man pages.
+manext = 1
+mandir = $(prefix)/man/man$(manext)
+
+# TeX & MF-specific directories. Not all of the following are relevant
+# for all programs, but it seems cleaner to collect everything in one place.
+
+# The default paths are now in kpathsea/paths.h.in. Passing all the
+# paths to sub-makes can make the arg list too long on system V.
+
+# The root of the tree.
+texmf = $(prefix)/texmf
+
+# TeX, MF, and MP source files.
+texinputdir = $(texmf)/tex
+mfinputdir = $(texmf)/mf
+mpinputdir = $(texmf)/mp
+
+# MakeTeXPK.site, texmf.cnf, etc.
+web2cdir = $(texmf)/web2c
+
+# The top-level font directory.
+fontdir = $(texmf)/fonts
+
+# Memory dumps (.fmt, .base, and .mem).
+fmtdir = $(texmf)/web2c
+basedir = $(texmf)/web2c
+memdir = $(texmf)/web2c
+
+# Pool files.
+texpooldir = $(texmf)/web2c
+mfpooldir = $(texmf)/web2c
+mppooldir = $(texmf)/web2c
+
+# If install_fonts=true, the PostScript/LaserJet TFM and VF files for
+# the builtin fonts get installed in subdirectories of this directory,
+# named for the typeface families of these directories. If you don't
+# have the default directory setup, you will want to set
+# install_fonts=false. Ditto for install_macros.
+install_fonts = false
+install_macros = false
+
+# Where the .map files from fontname are installed.
+fontnamedir = $(texmf)/fontname
+
+# Where the dvips configuration files get installed, and where
+# psfonts.map is.
+dvipsdir = $(texmf)/dvips
+psheaderdir = $(dvipsdir)
+
+# MakeTeXPK will go here to create dc*.
+dcfontdir = $(fontdir)/public/dc
+
+# MakeTeXPK will go here if it exists to create nonstandard CM fonts,
+# e.g., cmr11. See ftp.cs.umb.edu:pub/tex/sauter.tar.gz. The Sauter
+# files must be in your regular MFINPUTS.
+sauterdir = $(fontdir)/public/sauter
+
+# If a font can't be found close enough to its stated size, we look for
+# each of these sizes in the order given. This colon-separated list is
+# overridden by the envvar TEXSIZES, and by a program-specific variable
+# (e.g., XDVISIZES), and perhaps by a config file (e.g., in dvips).
+default_texsizes = 300:600
+
+# End of paths.make.
diff --git a/kdvi/make/programs.make b/kdvi/make/programs.make
new file mode 100644
index 00000000..e54b73b5
--- /dev/null
+++ b/kdvi/make/programs.make
@@ -0,0 +1,13 @@
+# programs.make -- used by Makefiles for executables only.
+# Linking. Don't include $(CFLAGS), since ld -g under Linux forces
+# static libraries, including libc.a and libX*.a
+LDFLAGS = @LDFLAGS@ $(XLDFLAGS)
+LIBS = @LIBS@
+# proglib is for web2c;
+# XLOADLIBES is for the installer.
+LOADLIBES= $(proglib) $(kpathsea) $(LIBS) -lm $(XLOADLIBES)
+
+# Why separate CCLD from CC? No particular reason.
+CCLD = $(CXX)
+link_command = $(CCLD) -o $@ $(LDFLAGS)
+# End of programs.make.
diff --git a/kdvi/make/rdepend.make b/kdvi/make/rdepend.make
new file mode 100644
index 00000000..26ddeeb8
--- /dev/null
+++ b/kdvi/make/rdepend.make
@@ -0,0 +1,15 @@
+# rdepend.make -- rules for remaking the dependencies.
+# Have to use -M, not -MM, since we use <kpathsea/...> instead of
+# "kpathsea/..." in the sources. But that means we have to remove the
+# directory prefixes and all the system include files.
+# And <kpathsea/paths.h> is generated, not part of the distribution.
+depend depend.make:: c-auto.h $(top_srcdir)/../make/rdepend.make
+ $(CC) -M $(CPPFLAGS) *.c \
+ | sed -e 's,\.\./kpathsea/,$$(kpathsea_srcdir)/,g' \
+ -e 's,$$(kpathsea_srcdir)/paths.h,paths.h,g' \
+ -e 's,/usr[^ ]* ,,g' \
+ -e 's,/usr[^ ]*$$,,g' \
+ -e 's,dvi2xx.o,dvilj.o dvilj2p.o dvilj4.o dvilj4l.o,' \
+ | grep -v '^ *\\$$' \
+ >depend.make
+# End of rdepend.make.
diff --git a/kdvi/make/texi.make b/kdvi/make/texi.make
new file mode 100644
index 00000000..ff953cc7
--- /dev/null
+++ b/kdvi/make/texi.make
@@ -0,0 +1,13 @@
+# texi.make -- making .dvi and .info from .texi.
+
+MAKEINFO = makeinfo
+MAKEINFO_FLAGS = --paragraph-indent=2 -I$(HOME)/gnu/gnuorg
+# That -I is purely for my own benefit in doing `make dist'. It won't
+# hurt anything for you (I hope).
+TEXI2DVI = texi2dvi
+
+.SUFFIXES: .info .dvi .texi
+.texi.info:
+ -$(MAKEINFO) $(MAKEINFO_FLAGS) $< -o $@
+.texi.dvi:
+ -$(TEXI2DVI) $(TEXI2DVI_FLAGS) $<
diff --git a/kdvi/make/tkpathsea.make b/kdvi/make/tkpathsea.make
new file mode 100644
index 00000000..dd1b6d17
--- /dev/null
+++ b/kdvi/make/tkpathsea.make
@@ -0,0 +1,9 @@
+# tkpathsea.make -- remaking kpathsea.
+
+makeargs = $(MFLAGS) CC='$(CC)' CFLAGS='$(CFLAGS)' $(XMAKEARGS)
+
+$(kpathsea): $(kpathsea_srcdir)/*.c $(kpathsea_srcdir)/*.h \
+ $(kpathsea_srcdir)/texmf.cnf.in $(top_srcdir)/../make/paths.make
+ cd $(kpathsea_dir); $(MAKE) $(makeargs)
+
+# End of tkpathsea.make.
diff --git a/kdvi/optionDialogFontsWidget.cpp b/kdvi/optionDialogFontsWidget.cpp
new file mode 100644
index 00000000..a3a76425
--- /dev/null
+++ b/kdvi/optionDialogFontsWidget.cpp
@@ -0,0 +1,47 @@
+// optionDiologWidget.cpp
+//
+// Part of KDVI - A DVI previewer for the KDE desktop environemt
+//
+// (C) 2003 Stefan Kebekus
+// Distributed under the GPL
+
+// Add header files alphabetically
+
+#include <config.h>
+
+#include <kcombobox.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <qbuttongroup.h>
+#include <qcheckbox.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+
+#include "fontpool.h"
+#include "optionDialogFontsWidget.h"
+
+
+// Constructs a optionDialogWidget_base which is a child of 'parent', with
+// the name 'name' and widget flags set to 'f'.
+optionDialogFontsWidget::optionDialogFontsWidget( QWidget* parent, const char* name, WFlags fl )
+ : optionDialogFontsWidget_base( parent, name, fl )
+{
+#ifndef HAVE_FREETYPE
+ kcfg_UseType1Fonts->setChecked(false);
+ kcfg_UseType1Fonts->setEnabled(false);
+ kcfg_UseFontHints->setEnabled(false);
+ kcfg_UseFontHints->setChecked(false);
+ QToolTip::add(PFB_ButtonGroup, i18n("This version of KDVI does not support type 1 fonts."));
+ QWhatsThis::add(PFB_ButtonGroup, i18n("KDVI needs the FreeType library to access type 1 fonts. This library "
+ "was not present when KDVI was compiled. If you want to use type 1 "
+ "fonts, you must either install the FreeType library and recompile KDVI "
+ "yourself, or find a precompiled software package for your operating "
+ "system."));
+#endif
+}
+
+optionDialogFontsWidget::~optionDialogFontsWidget()
+{
+}
+
+#include "optionDialogFontsWidget.moc"
diff --git a/kdvi/optionDialogFontsWidget.h b/kdvi/optionDialogFontsWidget.h
new file mode 100644
index 00000000..63ce98cc
--- /dev/null
+++ b/kdvi/optionDialogFontsWidget.h
@@ -0,0 +1,24 @@
+// -*- C++ -*-
+// optionDialogFontsWidget.h
+//
+// Part of KDVI - A DVI previewer for the KDE desktop environemt
+//
+// (C) 2003 Stefan Kebekus
+// Distributed under the GPL
+
+#ifndef OPTIONDIALOGFONTSWIDGET_H
+#define OPTIONDIALOGFONTSWIDGET_H
+
+#include "optionDialogFontsWidget_base.h"
+
+
+class optionDialogFontsWidget : public optionDialogFontsWidget_base
+{
+ Q_OBJECT
+
+ public:
+ optionDialogFontsWidget( QWidget* parent = 0, const char* name = 0, WFlags fl = 0 );
+ ~optionDialogFontsWidget();
+};
+
+#endif // OPTIONDIALOGFONTSWIDGET_H
diff --git a/kdvi/optionDialogFontsWidget_base.ui b/kdvi/optionDialogFontsWidget_base.ui
new file mode 100644
index 00000000..da4ca601
--- /dev/null
+++ b/kdvi/optionDialogFontsWidget_base.ui
@@ -0,0 +1,64 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>optionDialogFontsWidget_base</class>
+<author>Stefan Kebekus</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>optionDialogFontsWidget_base</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>325</width>
+ <height>54</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_UseFontHints</cstring>
+ </property>
+ <property name="text">
+ <string>Use font hinting for Type 1 fonts, if available</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>You should enable this, if the use of font hinting improves readability on your machine.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Many modern fonts contain "font hinting" information which can be used to improve the appearance of a font on low-resolution displays, such as a computer monitor, or a notebook screen. However, many people find the "improved" fonts quite ugly and prefer to have this option disabled.</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer11</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>31</width>
+ <height>121</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<includes>
+ <include location="global" impldecl="in implementation">kdialog.h</include>
+</includes>
+<slots>
+ <slot>buttonGroup1_clicked(int)</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/>
+</UI>
diff --git a/kdvi/optionDialogSpecialWidget.cpp b/kdvi/optionDialogSpecialWidget.cpp
new file mode 100644
index 00000000..1e24f6cc
--- /dev/null
+++ b/kdvi/optionDialogSpecialWidget.cpp
@@ -0,0 +1,135 @@
+// optionDialogSpecialWidget.cpp
+//
+// Part of KDVI - A DVI previewer for the KDE desktop environemt
+//
+// (C) 2003 Stefan Kebekus
+// Distributed under the GPL
+
+// Add header files alphabetically
+
+#include <config.h>
+
+#include <kdebug.h>
+
+#include <kapplication.h>
+#include <kcombobox.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kurllabel.h>
+#include <qcheckbox.h>
+#include <qlabel.h>
+
+#include "optionDialogSpecialWidget.h"
+#include "prefs.h"
+
+
+// Constructs a optionDialogWidget_base which is a child of 'parent', with
+// the name 'name' and widget flags set to 'f'.
+optionDialogSpecialWidget::optionDialogSpecialWidget( QWidget* parent, const char* name, WFlags fl )
+ : optionDialogSpecialWidget_base( parent, name, fl )
+{
+ // Set up the list of known and supported editors
+ editorNameString += i18n("User-Defined Editor");
+ editorCommandString += "";
+ editorDescriptionString += i18n("Enter the command line below.");
+
+ editorNameString += "Emacs / emacsclient";
+ editorCommandString += "emacsclient --no-wait +%l %f || emacs +%l %f";
+ editorDescriptionString += i18n("Click 'Help' to learn how to set up Emacs.");
+
+ editorNameString += "Kate";
+ editorCommandString += "kate --use --line %l %f";
+ editorDescriptionString += i18n("Kate perfectly supports inverse search.");
+
+ editorNameString += "Kile";
+ editorCommandString += "kile %f --line %l";
+ editorDescriptionString += i18n("Kile works very well");
+
+ editorNameString += "NEdit";
+ editorCommandString += "ncl -noask -line %l %f || nc -noask -line %l %f";
+ editorDescriptionString += i18n("NEdit perfectly supports inverse search.");
+
+ editorNameString += "VIM - Vi IMproved / GUI";
+ editorCommandString += "gvim --servername KDVI --remote-silent +%l %f";
+ editorDescriptionString += i18n("VIM version 6.0 or greater works just fine.");
+
+ editorNameString += "XEmacs / gnuclient";
+ editorCommandString += "gnuclient -q +%l %f || xemacs +%l %f";
+ editorDescriptionString += i18n("Click 'Help' to learn how to set up XEmacs.");
+
+ for(unsigned int i=0; i<editorNameString.count(); i++)
+ editorChoice->insertItem(editorNameString[i]);
+ // Set the proper editor on the "Rendering-Page", try to recognize
+ // the editor command from the config-file. If the editor command is
+ // not recognized, switch to "User defined editor". That way, kdvi
+ // stays compatible even if the EditorCommands[] change between
+ // different versions of kdvi.
+ QString currentEditorCommand = Prefs::editorCommand();
+ int i;
+ for(i = editorCommandString.count()-1; i>0; i--)
+ if (editorCommandString[i] == currentEditorCommand)
+ break;
+ if (i == 0)
+ usersEditorCommand = currentEditorCommand;
+ slotComboBox(i);
+
+ connect(urll, SIGNAL(leftClickedURL(const QString&)), this, SLOT(slotExtraHelpButton(const QString&)));
+ connect(editorChoice, SIGNAL( activated( int ) ), this, SLOT( slotComboBox( int ) ) );
+
+ // Editor description strings (and their translations) vary in
+ // size. Find the longest description string available to make sure
+ // that the page is always large enough.
+ int maximumWidth = 0;
+ for ( QStringList::Iterator it = editorDescriptionString.begin(); it != editorDescriptionString.end(); ++it ) {
+ int width = editorDescription->fontMetrics().width(*it);
+ if (width > maximumWidth)
+ maximumWidth = width;
+ }
+ editorDescription->setMinimumWidth(maximumWidth+10);
+
+ connect(kcfg_EditorCommand, SIGNAL( textChanged (const QString &) ), this, SLOT( slotUserDefdEditorCommand( const QString & ) ) );
+}
+
+optionDialogSpecialWidget::~optionDialogSpecialWidget()
+{
+}
+
+void optionDialogSpecialWidget::slotUserDefdEditorCommand( const QString &text )
+{
+ if (isUserDefdEditor == true)
+ EditorCommand = usersEditorCommand = text;
+}
+
+
+void optionDialogSpecialWidget::slotComboBox(int item)
+{
+ if (item != editorChoice->currentItem())
+ editorChoice->setCurrentItem(item);
+
+ editorDescription->setText(editorDescriptionString[item]);
+
+ if (item != 0) {
+ isUserDefdEditor = false;
+ kcfg_EditorCommand->setText(editorCommandString[item]);
+ kcfg_EditorCommand->setReadOnly(true);
+ EditorCommand = editorCommandString[item];
+ } else {
+ kcfg_EditorCommand->setText(usersEditorCommand);
+ kcfg_EditorCommand->setReadOnly(false);
+ EditorCommand = usersEditorCommand;
+ isUserDefdEditor = true;
+ }
+}
+
+void optionDialogSpecialWidget::slotExtraHelpButton( const QString & )
+{
+ kapp->invokeHelp( "inv-search", "kdvi" );
+}
+
+void optionDialogSpecialWidget::apply()
+{
+ Prefs::setEditorCommand(EditorCommand);
+}
+
+
+#include "optionDialogSpecialWidget.moc"
diff --git a/kdvi/optionDialogSpecialWidget.h b/kdvi/optionDialogSpecialWidget.h
new file mode 100644
index 00000000..cdd81100
--- /dev/null
+++ b/kdvi/optionDialogSpecialWidget.h
@@ -0,0 +1,36 @@
+// -*- C++ -*-
+// optionDialogSpecialWidget.h
+//
+// Part of KDVI - A DVI previewer for the KDE desktop environemt
+//
+// (C) 2003 Stefan Kebekus
+// Distributed under the GPL
+
+#ifndef OPTIONDIALOGSPECIALWIDGET_H
+#define OPTIONDIALOGSPECIALWIDGET_H
+
+#include "optionDialogSpecialWidget_base.h"
+
+
+class optionDialogSpecialWidget : public optionDialogSpecialWidget_base
+{
+ Q_OBJECT
+
+ public:
+ optionDialogSpecialWidget( QWidget* parent = 0, const char* name = 0, WFlags fl = 0 );
+ ~optionDialogSpecialWidget();
+
+ public slots:
+ void apply();
+ void slotComboBox(int item);
+ void slotUserDefdEditorCommand( const QString &text );
+ void slotExtraHelpButton( const QString &anchor);
+
+ private:
+ QStringList editorNameString, editorCommandString, editorDescriptionString;
+ QString EditorCommand;
+ bool isUserDefdEditor;
+ QString usersEditorCommand;
+};
+
+#endif // OPTIONDIALOGSPECIALWIDGET_H
diff --git a/kdvi/optionDialogSpecialWidget_base.ui b/kdvi/optionDialogSpecialWidget_base.ui
new file mode 100644
index 00000000..7aa36a26
--- /dev/null
+++ b/kdvi/optionDialogSpecialWidget_base.ui
@@ -0,0 +1,208 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>optionDialogSpecialWidget_base</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>optionDialogSpecialWidget_base</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>519</width>
+ <height>201</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_ShowPS</cstring>
+ </property>
+ <property name="text">
+ <string>Show PostScript specials</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>If in doubt, enable this option.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Some DVI files contain PostScript graphics. If enabled, KDVI will use the Ghostview PostScript interpreter to display these. You probably want to enable this option, unless you have a DVI-file whose PostScript part is broken, or too large for your machine.</string>
+ </property>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup3</cstring>
+ </property>
+ <property name="title">
+ <string>Editor for Inverse Search</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KComboBox" row="1" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>editorChoice</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Choose an editor which is used in inverse search.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Some DVI files contain 'inverse search' information. If such a DVI file is loaded, you can right-click into KDVI and an editor will open, load the TeX file and jump to the correct position. You can select your favorite editor here. If in doubt, 'nedit' is usually a good choice.&lt;/p&gt;
+&lt;p&gt;Check the KDVI manual to see how to prepare DVI files which support the inverse search.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Description:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Shell command:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>editorDescription</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Explains about the editor's capabilities in conjunction with inverse search.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;Not all editors are well suited for inverse search. For instance, many editors have no command like 'If the file is not yet loaded, load it. Otherwise, bring the window with the file to the front'. If you are using an editor like this, clicking into the DVI file will always open a new editor, even if the TeX file is already open. Likewise, many editors have no command line argument that would allow KDVI to specify the exact line which you wish to edit.&lt;/p&gt;
+&lt;p&gt;If you feel that KDVI's support for a certain editor is inadequate, please write to kebekus@kde.org.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="3" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>kcfg_EditorCommand</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Shell-command line used to start the editor.</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>If you are using inverse search, KDVI uses this command line to start the editor. The field '%f' is replaced with the filename, and '%l' is replaced with the line number.</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Editor:</string>
+ </property>
+ </widget>
+ <widget class="KURLLabel" row="0" column="2">
+ <property name="name">
+ <cstring>urll</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>What is 'inverse search'? </string>
+ </property>
+ <property name="alignment">
+ <set>AlignVCenter|AlignRight</set>
+ </property>
+ <property name="url" stdset="0">
+ <string>inv-search</string>
+ </property>
+ </widget>
+ <spacer row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>390</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kcombobox.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kurllabel.h</includehint>
+</includehints>
+</UI>
diff --git a/kdvi/performanceMeasurement.h b/kdvi/performanceMeasurement.h
new file mode 100644
index 00000000..b6cb46c7
--- /dev/null
+++ b/kdvi/performanceMeasurement.h
@@ -0,0 +1,21 @@
+// -*- C++ -*-
+
+//#define PERFORMANCE_MEASUREMENT
+
+#ifdef PERFORMANCE_MEASUREMENT
+#include <qdatetime.h>
+
+// This is the central timer used for performance measurement. It is
+// set to zero and started when the kdvi_multipage is
+// constructed. This object is statically defined in
+// kdvi_multipage.cpp.
+extern QTime performanceTimer;
+
+// A flag that is set to true once the first page of the document was
+// successfully drawn. This object is statically defined in
+// kdvi_multipage.cpp.
+// 0 = initial value
+// 1 = first page was drawn
+// 2 = last page was drawn
+extern int performanceFlag;
+#endif
diff --git a/kdvi/pix/Makefile.am b/kdvi/pix/Makefile.am
new file mode 100644
index 00000000..c43e4d48
--- /dev/null
+++ b/kdvi/pix/Makefile.am
@@ -0,0 +1,2 @@
+KDE_ICON = kdvi
+
diff --git a/kdvi/pix/hi16-app-kdvi.png b/kdvi/pix/hi16-app-kdvi.png
new file mode 100644
index 00000000..dc4c71c6
--- /dev/null
+++ b/kdvi/pix/hi16-app-kdvi.png
Binary files differ
diff --git a/kdvi/pix/hi22-app-kdvi.png b/kdvi/pix/hi22-app-kdvi.png
new file mode 100644
index 00000000..0462047e
--- /dev/null
+++ b/kdvi/pix/hi22-app-kdvi.png
Binary files differ
diff --git a/kdvi/pix/hi32-app-kdvi.png b/kdvi/pix/hi32-app-kdvi.png
new file mode 100644
index 00000000..848eb1c3
--- /dev/null
+++ b/kdvi/pix/hi32-app-kdvi.png
Binary files differ
diff --git a/kdvi/pix/hi48-app-kdvi.png b/kdvi/pix/hi48-app-kdvi.png
new file mode 100644
index 00000000..404462dc
--- /dev/null
+++ b/kdvi/pix/hi48-app-kdvi.png
Binary files differ
diff --git a/kdvi/pix/hisc-app-kdvi.svgz b/kdvi/pix/hisc-app-kdvi.svgz
new file mode 100644
index 00000000..9e45007d
--- /dev/null
+++ b/kdvi/pix/hisc-app-kdvi.svgz
Binary files differ
diff --git a/kdvi/prebookmark.h b/kdvi/prebookmark.h
new file mode 100644
index 00000000..141c8d6c
--- /dev/null
+++ b/kdvi/prebookmark.h
@@ -0,0 +1,50 @@
+// -*- C++ -*-
+/***************************************************************************
+ * 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 _PREBOOKMARK_H_
+#define _PREBOOKMARK_H_
+
+#include <qstring.h>
+
+/*! \brief Bookmark representation
+
+This class presents a bookmark in a format that is used internally by
+the DVI prescan routines.
+*/
+
+class PreBookmark
+{
+ public:
+ PreBookmark(const QString& t, const QString& a, Q_UINT16 n) {title=t; anchorName=a; noOfChildren=n;}
+ PreBookmark() {title=QString::null; anchorName=QString::null; noOfChildren=0;}
+
+ // Title of the bookmark
+ QString title;
+
+ // Name of the anchor
+ QString anchorName;
+
+ // Number of subordinate bookmarks
+ Q_UINT16 noOfChildren;
+};
+
+#endif
diff --git a/kdvi/prefs.kcfgc b/kdvi/prefs.kcfgc
new file mode 100644
index 00000000..7b77dce6
--- /dev/null
+++ b/kdvi/prefs.kcfgc
@@ -0,0 +1,5 @@
+# Code generation options for kconfig_compiler
+File=kdvi.kcfg
+ClassName=Prefs
+Singleton=true
+Mutators=true \ No newline at end of file
diff --git a/kdvi/psgs.cpp b/kdvi/psgs.cpp
new file mode 100644
index 00000000..9e23fcad
--- /dev/null
+++ b/kdvi/psgs.cpp
@@ -0,0 +1,340 @@
+//
+// ghostscript_interface
+//
+// Part of KDVI - A framework for multipage text/gfx viewers
+//
+// (C) 2004 Stefan Kebekus
+// Distributed under the GPL
+
+#include <config.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kprocio.h>
+#include <ktempfile.h>
+#include <kurl.h>
+#include <qdir.h>
+#include <qpainter.h>
+
+#include "psgs.h"
+#include "dviFile.h"
+#include "pageNumber.h"
+
+extern const char psheader[];
+
+//#define DEBUG_PSGS
+
+
+pageInfo::pageInfo(const QString& _PostScriptString) {
+ PostScriptString = new QString(_PostScriptString);
+ background = Qt::white;
+ permanentBackground = Qt::white;
+}
+
+
+pageInfo::~pageInfo() {
+ if (PostScriptString != 0L)
+ delete PostScriptString;
+}
+
+
+// ======================================================
+
+ghostscript_interface::ghostscript_interface() {
+ pageList.setAutoDelete(true);
+
+ PostScriptHeaderString = new QString();
+
+ knownDevices.append("png256");
+ knownDevices.append("jpeg");
+ knownDevices.append("pnn");
+ knownDevices.append("pnnraw");
+ gsDevice = knownDevices.begin();
+}
+
+ghostscript_interface::~ghostscript_interface() {
+ if (PostScriptHeaderString != 0L)
+ delete PostScriptHeaderString;
+}
+
+
+void ghostscript_interface::setPostScript(const PageNumber& page, const QString& PostScript) {
+#ifdef DEBUG_PSGS
+ kdDebug(4300) << "ghostscript_interface::setPostScript( " << page << ", ... )" << endl;
+#endif
+
+ if (pageList.find(page) == 0) {
+ pageInfo *info = new pageInfo(PostScript);
+ // Check if dict is big enough
+ if (pageList.count() > pageList.size() -2)
+ pageList.resize(pageList.size()*2);
+ pageList.insert(page, info);
+ } else
+ *(pageList.find(page)->PostScriptString) = PostScript;
+}
+
+
+void ghostscript_interface::setIncludePath(const QString &_includePath) {
+ if (_includePath.isEmpty())
+ includePath = "*"; // Allow all files
+ else
+ includePath = _includePath+"/*";
+}
+
+
+void ghostscript_interface::setBackgroundColor(const PageNumber& page, const QColor& background_color, bool permanent) {
+#ifdef DEBUG_PSGS
+ kdDebug(4300) << "ghostscript_interface::setBackgroundColor( " << page << ", " << background_color << " )" << endl;
+#endif
+
+ if (pageList.find(page) == 0) {
+ pageInfo *info = new pageInfo(QString::null);
+ info->background = background_color;
+ if (permanent)
+ info->permanentBackground = background_color;
+ // Check if dict is big enough
+ if (pageList.count() > pageList.size() -2)
+ pageList.resize(pageList.size()*2);
+ pageList.insert(page, info);
+ } else {
+ pageList.find(page)->background = background_color;
+ if (permanent)
+ pageList.find(page)->permanentBackground = background_color;
+ }
+}
+
+void ghostscript_interface::restoreBackgroundColor(const PageNumber& page)
+{
+#ifdef DEBUG_PSGS
+ kdDebug(4300) << "ghostscript_interface::restoreBackgroundColor( " << page << " )" << endl;
+#endif
+ if (pageList.find(page) == 0)
+ return;
+
+ pageInfo *info = pageList.find(page);
+ info->background = info->permanentBackground;
+}
+
+// Returns the background color for a certain page. This color is
+// always guaranteed to be valid
+
+QColor ghostscript_interface::getBackgroundColor(const PageNumber& page) const {
+#ifdef DEBUG_PSGS
+ kdDebug(4300) << "ghostscript_interface::getBackgroundColor( " << page << " )" << endl;
+#endif
+
+ if (pageList.find(page) == 0)
+ return Qt::white;
+ else
+ return pageList.find(page)->background;
+}
+
+
+void ghostscript_interface::clear() {
+ PostScriptHeaderString->truncate(0);
+
+ // Deletes all items, removes temporary files, etc.
+ pageList.clear();
+}
+
+
+void ghostscript_interface::gs_generate_graphics_file(const PageNumber& page, const QString& filename, long magnification) {
+#ifdef DEBUG_PSGS
+ kdDebug(4300) << "ghostscript_interface::gs_generate_graphics_file( " << page << ", " << filename << " )" << endl;
+#endif
+
+ if (knownDevices.isEmpty()) {
+ kdError(4300) << "No known devices found" << endl;
+ return;
+ }
+
+ emit(setStatusBarText(i18n("Generating PostScript graphics...")));
+
+ pageInfo *info = pageList.find(page);
+
+ // Generate a PNG-file
+ // Step 1: Write the PostScriptString to a File
+ KTempFile PSfile(QString::null,".ps");
+
+ QTextStream& os = *PSfile.textStream();
+ os << "%!PS-Adobe-2.0\n"
+ << "%%Creator: kdvi\n"
+ << "%%Title: KDVI temporary PostScript\n"
+ << "%%Pages: 1\n"
+ << "%%PageOrder: Ascend\n"
+ // HSize and VSize in 1/72 inch
+ << "%%BoundingBox: 0 0 "
+ << (Q_INT32)(72*(pixel_page_w/resolution)) << ' '
+ << (Q_INT32)(72*(pixel_page_h/resolution)) << '\n'
+ << "%%EndComments\n"
+ << "%!\n"
+ << psheader
+ << "TeXDict begin "
+ // HSize in (1/(65781.76*72))inch
+ << (Q_INT32)(72*65781*(pixel_page_w/resolution)) << ' '
+ // VSize in (1/(65781.76*72))inch
+ << (Q_INT32)(72*65781*(pixel_page_h/resolution)) << ' '
+ // Magnification
+ << (Q_INT32)(magnification)
+ // dpi and vdpi
+ << " 300 300"
+ // Name
+ << " (test.dvi)"
+ << " @start end\n"
+ << "TeXDict begin\n"
+ // Start page
+ << "1 0 bop 0 0 a \n";
+
+ if (PostScriptHeaderString->latin1() != NULL)
+ os << PostScriptHeaderString->latin1();
+
+ if (info->background != Qt::white) {
+ QString colorCommand = QString("gsave %1 %2 %3 setrgbcolor clippath fill grestore\n").
+ arg(info->background.red()/255.0).
+ arg(info->background.green()/255.0).
+ arg(info->background.blue()/255.0);
+ os << colorCommand.latin1();
+ }
+
+ if (info->PostScriptString->latin1() != NULL)
+ os << info->PostScriptString->latin1();
+
+ os << "end\n"
+ << "showpage \n";
+
+ PSfile.close();
+
+ // Step 2: Call GS with the File
+ QFile::remove(filename.ascii());
+ KProcIO proc;
+ QStringList argus;
+ argus << "gs";
+ argus << "-dSAFER" << "-dPARANOIDSAFER" << "-dDELAYSAFER" << "-dNOPAUSE" << "-dBATCH";
+ argus << QString("-sDEVICE=%1").arg(*gsDevice);
+ argus << QString("-sOutputFile=%1").arg(filename);
+ argus << QString("-sExtraIncludePath=%1").arg(includePath);
+ argus << QString("-g%1x%2").arg(pixel_page_w).arg(pixel_page_h); // page size in pixels
+ argus << QString("-r%1").arg(resolution); // resolution in dpi
+ argus << "-c" << "<< /PermitFileReading [ ExtraIncludePath ] /PermitFileWriting [] /PermitFileControl [] >> setuserparams .locksafe";
+ argus << "-f" << PSfile.name();
+
+#ifdef DEBUG_PSGS
+ kdDebug(4300) << argus.join(" ") << endl;
+#endif
+
+ proc << argus;
+ if (proc.start(KProcess::Block) == false) {
+ // Starting ghostscript did not work.
+ // TODO: Issue error message, switch PS support off.
+ kdError(4300) << "ghostview could not be started" << endl;
+ }
+ PSfile.unlink();
+
+ // Check if gs has indeed produced a file.
+ if (QFile::exists(filename) == false) {
+ kdError(4300) << "GS did not produce output." << endl;
+
+ // No. Check is the reason is that the device is not compiled into
+ // ghostscript. If so, try again with another device.
+ QString GSoutput;
+ while(proc.readln(GSoutput) != -1) {
+ if (GSoutput.contains("Unknown device")) {
+ kdDebug(4300) << QString("The version of ghostview installed on this computer does not support "
+ "the '%1' ghostview device driver.").arg(*gsDevice) << endl;
+ knownDevices.remove(gsDevice);
+ gsDevice = knownDevices.begin();
+ if (knownDevices.isEmpty())
+ // TODO: show a requestor of some sort.
+ KMessageBox::detailedError(0,
+ i18n("<qt>The version of Ghostview that is installed on this computer does not contain "
+ "any of the Ghostview device drivers that are known to KDVI. PostScript "
+ "support has therefore been turned off in KDVI.</qt>"),
+ i18n("<qt><p>The Ghostview program, which KDVI uses internally to display the "
+ "PostScript graphics that is included in this DVI file, is generally able to "
+ "write its output in a variety of formats. The sub-programs that Ghostview uses "
+ "for these tasks are called 'device drivers'; there is one device driver for "
+ "each format that Ghostview is able to write. Different versions of Ghostview "
+ "often have different sets of device drivers available. It seems that the "
+ "version of Ghostview that is installed on this computer does not contain "
+ "<strong>any</strong> of the device drivers that are known to KDVI.</p>"
+ "<p>It seems unlikely that a regular installation of Ghostview would not contain "
+ "these drivers. This error may therefore point to a serious misconfiguration of "
+ "the Ghostview installation on your computer.</p>"
+ "<p>If you want to fix the problems with Ghostview, you can use the command "
+ "<strong>gs --help</strong> to display the list of device drivers contained in "
+ "Ghostview. Among others, KDVI can use the 'png256', 'jpeg' and 'pnm' "
+ "drivers. Note that KDVI needs to be restarted to re-enable PostScript support."
+ "</p></qt>"));
+ else {
+ kdDebug(4300) << QString("KDVI will now try to use the '%1' device driver.").arg(*gsDevice) << endl;
+ gs_generate_graphics_file(page, filename, magnification);
+ }
+ return;
+ }
+ }
+ }
+ emit(setStatusBarText(QString::null));
+}
+
+
+void ghostscript_interface::graphics(const PageNumber& page, double dpi, long magnification, QPainter* paint) {
+#ifdef DEBUG_PSGS
+ kdDebug(4300) << "ghostscript_interface::graphics( " << page << ", " << dpi << ", ... ) called." << endl;
+#endif
+
+ if (paint == 0) {
+ kdError(4300) << "ghostscript_interface::graphics(PageNumber page, double dpi, long magnification, QPainter *paint) called with paint == 0" << endl;
+ return;
+ }
+
+ resolution = dpi;
+
+ pixel_page_w = paint->viewport().width();
+ pixel_page_h = paint->viewport().height();
+
+ pageInfo *info = pageList.find(page);
+
+ // No PostScript? Then return immediately.
+ if ((info == 0) || (info->PostScriptString->isEmpty())) {
+#ifdef DEBUG_PSGS
+ kdDebug(4300) << "No PostScript found. Not drawing anything." << endl;
+#endif
+ return;
+ }
+
+ KTempFile gfxFile(QString::null, ".png");
+ gfxFile.setAutoDelete(1);
+ gfxFile.close(); // we are want the filename, not the file
+
+ gs_generate_graphics_file(page, gfxFile.name(), magnification);
+
+ QPixmap MemoryCopy(gfxFile.name());
+ paint->drawPixmap(0, 0, MemoryCopy);
+ return;
+}
+
+
+QString ghostscript_interface::locateEPSfile(const QString &filename, const KURL &base)
+{
+ // If the base URL indicates that the DVI file is local, try to find
+ // the graphics file in the directory where the DVI file resides
+ if (base.isLocalFile()) {
+ QString path = base.path(); // -> "/bar/foo.dvi"
+ QFileInfo fi1(path);
+ QFileInfo fi2(fi1.dir(),filename);
+ if (fi2.exists())
+ return fi2.absFilePath();
+ }
+
+ // Otherwise, use kpsewhich to find the eps file.
+ QString EPSfilename;
+ KProcIO proc;
+ proc << "kpsewhich" << filename;
+ proc.start(KProcess::Block);
+ proc.readln(EPSfilename);
+
+ return EPSfilename.stripWhiteSpace();
+}
+
+#include "psgs.moc"
diff --git a/kdvi/psgs.h b/kdvi/psgs.h
new file mode 100644
index 00000000..0b6e679d
--- /dev/null
+++ b/kdvi/psgs.h
@@ -0,0 +1,107 @@
+// -*- C++ -*-
+//
+// ghostscript_interface
+//
+// Part of KDVI - A framework for multipage text/gfx viewers
+//
+// (C) 2004 Stefan Kebekus
+// Distributed under the GPL
+
+#ifndef _PSGS_H_
+#define _PSGS_H_
+
+#include <qcolor.h>
+#include <qobject.h>
+#include <qstring.h>
+#include <qintdict.h>
+
+class PageNumber;
+class QPainter;
+
+
+class pageInfo
+{
+public:
+ pageInfo(const QString& _PostScriptString);
+ ~pageInfo();
+
+ QColor background;
+ QColor permanentBackground;
+ QString *PostScriptString;
+};
+
+
+class ghostscript_interface : public QObject
+{
+ Q_OBJECT
+
+public:
+ ghostscript_interface();
+ ~ghostscript_interface();
+
+ void clear();
+
+ // sets the PostScript which is used on a certain page
+ void setPostScript(const PageNumber& page, const QString& PostScript);
+
+ // sets path from additional postscript files may be read
+ void setIncludePath(const QString &_includePath);
+
+ // Sets the background color for a certain page. If permanent is false then the original
+ // background color can be restored by calling restoreBackground(page).
+ // The Option permanent = false is used when we want to display a different paper
+ // color as the one specified in the dvi file.
+ void setBackgroundColor(const PageNumber& page, const QColor& background_color, bool permanent = true);
+
+ // Restore the background to the color which was specified by the last call to setBackgroundColor()
+ // With option permanent = true.
+ void restoreBackgroundColor(const PageNumber& page);
+
+ // Draws the graphics of the page into the painter, if possible. If
+ // the page does not contain any graphics, nothing happens
+ void graphics(const PageNumber& page, double dpi, long magnification, QPainter* paint);
+
+ // Returns the background color for a certain page. If no color was
+ // set, Qt::white is returned.
+ QColor getBackgroundColor(const PageNumber& page) const;
+
+ QString *PostScriptHeaderString;
+
+ /** This method tries to find the PostScript file 'filename' in the
+ DVI file's directory (if the base-URL indicates that the DVI file
+ is local), and, if that fails, uses kpsewhich to find the file. If
+ the file is found, the full path (including file name) is
+ returned. Otherwise, the method returns the first argument. TODO:
+ use the DVI file's baseURL, once this is implemented.
+ */
+ static QString locateEPSfile(const QString &filename, const KURL &base);
+
+private:
+ void gs_generate_graphics_file(const PageNumber& page, const QString& filename, long magnification);
+ QIntDict<pageInfo> pageList;
+
+ double resolution; // in dots per inch
+ int pixel_page_w; // in pixels
+ int pixel_page_h; // in pixels
+
+ QString includePath;
+
+ // Output device that ghostscript is supposed tp use. Default is
+ // "png256". If that does not work, gs_generate_graphics_file will
+ // automatically try other known device drivers. If no known output
+ // device can be found, something is badly wrong. In that case,
+ // "gsDevice" is set to an empty string, and
+ // gs_generate_graphics_file will return immediately.
+ QValueListIterator<QString> gsDevice;
+
+ // A list of known devices, set by the constructor. This includes
+ // "png256", "pnm". If a device is found to not work, its name is
+ // removed from the list, and another device name is tried.
+ QStringList knownDevices;
+
+signals:
+ /** Passed through to the top-level kpart. */
+ void setStatusBarText( const QString& );
+};
+
+#endif
diff --git a/kdvi/psheader.txt b/kdvi/psheader.txt
new file mode 100644
index 00000000..f5e543d1
--- /dev/null
+++ b/kdvi/psheader.txt
@@ -0,0 +1,113 @@
+% texc.pro
+%!
+/TeXDict 300 dict def TeXDict begin/N{def}def/B{bind def}N/S{exch}N/X{S
+N}B/A{dup}B/TR{translate}N/isls false N/vsize 11 72 mul N/hsize 8.5 72
+mul N/landplus90{false}def/@rigin{isls{[0 landplus90{1 -1}{-1 1}ifelse 0
+0 0]concat}if 72 Resolution div 72 VResolution div neg scale isls{
+landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div hsize
+mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul TR[
+matrix currentmatrix{A A round sub abs 0.00001 lt{round}if}forall round
+exch round exch]setmatrix}N/@landscape{/isls true N}B/@manualfeed{
+statusdict/manualfeed true put}B/@copies{/#copies X}B/FMat[1 0 0 -1 0 0]
+N/FBB[0 0 0 0]N/nn 0 N/IEn 0 N/ctr 0 N/df-tail{/nn 8 dict N nn begin
+/FontType 3 N/FontMatrix fntrx N/FontBBox FBB N string/base X array
+/BitMaps X/BuildChar{CharBuilder}N/Encoding IEn N end A{/foo setfont}2
+array copy cvx N load 0 nn put/ctr 0 N[}B/sf 0 N/df{/sf 1 N/fntrx FMat N
+df-tail}B/dfs{div/sf X/fntrx[sf 0 0 sf neg 0 0]N df-tail}B/E{pop nn A
+definefont setfont}B/Cw{Cd A length 5 sub get}B/Ch{Cd A length 4 sub get
+}B/Cx{128 Cd A length 3 sub get sub}B/Cy{Cd A length 2 sub get 127 sub}
+B/Cdx{Cd A length 1 sub get}B/Ci{Cd A type/stringtype ne{ctr get/ctr ctr
+1 add N}if}B/id 0 N/rw 0 N/rc 0 N/gp 0 N/cp 0 N/G 0 N/CharBuilder{save 3
+1 roll S A/base get 2 index get S/BitMaps get S get/Cd X pop/ctr 0 N Cdx
+0 Cx Cy Ch sub Cx Cw add Cy setcachedevice Cw Ch true[1 0 0 -1 -.1 Cx
+sub Cy .1 sub]/id Ci N/rw Cw 7 add 8 idiv string N/rc 0 N/gp 0 N/cp 0 N{
+rc 0 ne{rc 1 sub/rc X rw}{G}ifelse}imagemask restore}B/G{{id gp get/gp
+gp 1 add N A 18 mod S 18 idiv pl S get exec}loop}B/adv{cp add/cp X}B
+/chg{rw cp id gp 4 index getinterval putinterval A gp add/gp X adv}B/nd{
+/cp 0 N rw exit}B/lsh{rw cp 2 copy get A 0 eq{pop 1}{A 255 eq{pop 254}{
+A A add 255 and S 1 and or}ifelse}ifelse put 1 adv}B/rsh{rw cp 2 copy
+get A 0 eq{pop 128}{A 255 eq{pop 127}{A 2 idiv S 128 and or}ifelse}
+ifelse put 1 adv}B/clr{rw cp 2 index string putinterval adv}B/set{rw cp
+fillstr 0 4 index getinterval putinterval adv}B/fillstr 18 string 0 1 17
+{2 copy 255 put pop}for N/pl[{adv 1 chg}{adv 1 chg nd}{1 add chg}{1 add
+chg nd}{adv lsh}{adv lsh nd}{adv rsh}{adv rsh nd}{1 add adv}{/rc X nd}{
+1 add set}{1 add clr}{adv 2 chg}{adv 2 chg nd}{pop nd}]A{bind pop}
+forall N/D{/cc X A type/stringtype ne{]}if nn/base get cc ctr put nn
+/BitMaps get S ctr S sf 1 ne{A A length 1 sub A 2 index S get sf div put
+}if put/ctr ctr 1 add N}B/I{cc 1 add D}B/bop{userdict/bop-hook known{
+bop-hook}if/SI save N @rigin 0 0 moveto/V matrix currentmatrix A 1 get A
+mul exch 0 get A mul add .99 lt{/QV}{/RV}ifelse load def pop pop}N/eop{
+SI restore userdict/eop-hook known{eop-hook}if showpage}N/@start{
+userdict/start-hook known{start-hook}if pop/VResolution X/Resolution X
+1000 div/DVImag X/IEn 256 array N 2 string 0 1 255{IEn S A 360 add 36 4
+index cvrs cvn put}for pop 65781.76 div/vsize X 65781.76 div/hsize X}N
+/p{show}N/RMat[1 0 0 -1 0 0]N/BDot 260 string N/Rx 0 N/Ry 0 N/V{}B/RV/v{
+/Ry X/Rx X V}B statusdict begin/product where{pop false[(Display)(NeXT)
+(LaserWriter 16/600)]{A length product length le{A length product exch 0
+exch getinterval eq{pop true exit}if}{pop}ifelse}forall}{false}ifelse
+end{{gsave TR -.1 .1 TR 1 1 scale Rx Ry false RMat{BDot}imagemask
+grestore}}{{gsave TR -.1 .1 TR Rx Ry scale 1 1 false RMat{BDot}
+imagemask grestore}}ifelse B/QV{gsave newpath transform round exch round
+exch itransform moveto Rx 0 rlineto 0 Ry neg rlineto Rx neg 0 rlineto
+fill grestore}B/a{moveto}B/delta 0 N/tail{A/delta X 0 rmoveto}B/M{S p
+delta add tail}B/b{S p tail}B/c{-4 M}B/d{-3 M}B/e{-2 M}B/f{-1 M}B/g{0 M}
+B/h{1 M}B/i{2 M}B/j{3 M}B/k{4 M}B/w{0 rmoveto}B/l{p -4 w}B/m{p -3 w}B/n{
+p -2 w}B/o{p -1 w}B/q{p 1 w}B/r{p 2 w}B/s{p 3 w}B/t{p 4 w}B/x{0 S
+rmoveto}B/y{3 2 roll p a}B/bos{/SS save N}B/eos{SS restore}B end
+
+% special.pro
+%!
+TeXDict begin/SDict 200 dict N SDict begin/@SpecialDefaults{/hs 612 N
+/vs 792 N/ho 0 N/vo 0 N/hsc 1 N/vsc 1 N/ang 0 N/CLIP 0 N/rwiSeen false N
+/rhiSeen false N/letter{}N/note{}N/a4{}N/legal{}N}B/@scaleunit 100 N
+/@hscale{@scaleunit div/hsc X}B/@vscale{@scaleunit div/vsc X}B/@hsize{
+/hs X/CLIP 1 N}B/@vsize{/vs X/CLIP 1 N}B/@clip{/CLIP 2 N}B/@hoffset{/ho
+X}B/@voffset{/vo X}B/@angle{/ang X}B/@rwi{10 div/rwi X/rwiSeen true N}B
+/@rhi{10 div/rhi X/rhiSeen true N}B/@llx{/llx X}B/@lly{/lly X}B/@urx{
+/urx X}B/@ury{/ury X}B/magscale true def end/@MacSetUp{userdict/md known
+{userdict/md get type/dicttype eq{userdict begin md length 10 add md
+maxlength ge{/md md dup length 20 add dict copy def}if end md begin
+/letter{}N/note{}N/legal{}N/od{txpose 1 0 mtx defaultmatrix dtransform S
+atan/pa X newpath clippath mark{transform{itransform moveto}}{transform{
+itransform lineto}}{6 -2 roll transform 6 -2 roll transform 6 -2 roll
+transform{itransform 6 2 roll itransform 6 2 roll itransform 6 2 roll
+curveto}}{{closepath}}pathforall newpath counttomark array astore/gc xdf
+pop ct 39 0 put 10 fz 0 fs 2 F/|______Courier fnt invertflag{PaintBlack}
+if}N/txpose{pxs pys scale ppr aload pop por{noflips{pop S neg S TR pop 1
+-1 scale}if xflip yflip and{pop S neg S TR 180 rotate 1 -1 scale ppr 3
+get ppr 1 get neg sub neg ppr 2 get ppr 0 get neg sub neg TR}if xflip
+yflip not and{pop S neg S TR pop 180 rotate ppr 3 get ppr 1 get neg sub
+neg 0 TR}if yflip xflip not and{ppr 1 get neg ppr 0 get neg TR}if}{
+noflips{TR pop pop 270 rotate 1 -1 scale}if xflip yflip and{TR pop pop
+90 rotate 1 -1 scale ppr 3 get ppr 1 get neg sub neg ppr 2 get ppr 0 get
+neg sub neg TR}if xflip yflip not and{TR pop pop 90 rotate ppr 3 get ppr
+1 get neg sub neg 0 TR}if yflip xflip not and{TR pop pop 270 rotate ppr
+2 get ppr 0 get neg sub neg 0 S TR}if}ifelse scaleby96{ppr aload pop 4
+-1 roll add 2 div 3 1 roll add 2 div 2 copy TR .96 dup scale neg S neg S
+TR}if}N/cp{pop pop showpage pm restore}N end}if}if}N/normalscale{
+Resolution 72 div VResolution 72 div neg scale magscale{DVImag dup scale
+}if 0 setgray}N/psfts{S 65781.76 div N}N/startTexFig{/psf$SavedState
+save N userdict maxlength dict begin/magscale true def normalscale
+currentpoint TR/psf$ury psfts/psf$urx psfts/psf$lly psfts/psf$llx psfts
+/psf$y psfts/psf$x psfts currentpoint/psf$cy X/psf$cx X/psf$sx psf$x
+psf$urx psf$llx sub div N/psf$sy psf$y psf$ury psf$lly sub div N psf$sx
+psf$sy scale psf$cx psf$sx div psf$llx sub psf$cy psf$sy div psf$ury sub
+TR/showpage{}N/erasepage{}N/copypage{}N/p 3 def @MacSetUp}N/doclip{
+psf$llx psf$lly psf$urx psf$ury currentpoint 6 2 roll newpath 4 copy 4 2
+roll moveto 6 -1 roll S lineto S lineto S lineto closepath clip newpath
+moveto}N/endTexFig{end psf$SavedState restore}N/@beginspecial{SDict
+begin/SpecialSave save N gsave normalscale currentpoint TR
+@SpecialDefaults count/ocount X/dcount countdictstack N}N/@setspecial{
+CLIP 1 eq{newpath 0 0 moveto hs 0 rlineto 0 vs rlineto hs neg 0 rlineto
+closepath clip}if ho vo TR hsc vsc scale ang rotate rwiSeen{rwi urx llx
+sub div rhiSeen{rhi ury lly sub div}{dup}ifelse scale llx neg lly neg TR
+}{rhiSeen{rhi ury lly sub div dup scale llx neg lly neg TR}if}ifelse
+CLIP 2 eq{newpath llx lly moveto urx lly lineto urx ury lineto llx ury
+lineto closepath clip}if/showpage{}N/erasepage{}N/copypage{}N newpath}N
+/@endspecial{count ocount sub{pop}repeat countdictstack dcount sub{end}
+repeat grestore SpecialSave restore end}N/@defspecial{SDict begin}N
+/@fedspecial{end}B/li{lineto}B/rl{rlineto}B/rc{rcurveto}B/np{/SaveX
+currentpoint/SaveY X N 1 setlinecap newpath}N/st{stroke SaveX SaveY
+moveto}N/fil{fill SaveX SaveY moveto}N/ellipse{/endangle X/startangle X
+/yrad X/xrad X/savematrix matrix currentmatrix N TR xrad yrad scale 0 0
+1 startangle endangle arc savematrix setmatrix}N end
diff --git a/kdvi/renderedDviPagePixmap.cpp b/kdvi/renderedDviPagePixmap.cpp
new file mode 100644
index 00000000..3d123a24
--- /dev/null
+++ b/kdvi/renderedDviPagePixmap.cpp
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * 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 <config.h>
+
+#include "renderedDviPagePixmap.h"
+#include "hyperlink.h"
+
+
+RenderedDviPagePixmap::RenderedDviPagePixmap()
+ : RenderedDocumentPagePixmap()
+{
+ sourceHyperLinkList.reserve(200);
+}
+
+RenderedDviPagePixmap::~RenderedDviPagePixmap()
+{
+}
+
+void RenderedDviPagePixmap::clear()
+{
+ RenderedDocumentPagePixmap::clear();
+
+ sourceHyperLinkList.clear();
+}
+
+#include "renderedDviPagePixmap.moc"
diff --git a/kdvi/renderedDviPagePixmap.h b/kdvi/renderedDviPagePixmap.h
new file mode 100644
index 00000000..3b0f7272
--- /dev/null
+++ b/kdvi/renderedDviPagePixmap.h
@@ -0,0 +1,49 @@
+// -*- C++ -*-
+/***************************************************************************
+ * 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 _RENDEREDDVIPAGEPIXMAP_H_
+#define _RENDEREDDVIPAGEPIXMAP_H_
+
+#include "renderedDocumentPagePixmap.h"
+
+#include <qobject.h>
+
+
+class RenderedDviPagePixmap : public RenderedDocumentPagePixmap
+{
+ Q_OBJECT
+
+ public:
+ RenderedDviPagePixmap();
+
+ virtual ~RenderedDviPagePixmap();
+
+ virtual void clear();
+
+ /** \brief List of source hyperlinks
+
+ List of source-hyperlinks in the current page. This vector is
+ generated when the current page is drawn.
+ */
+ QValueVector<Hyperlink> sourceHyperLinkList;
+};
+
+#endif
diff --git a/kdvi/special.cpp b/kdvi/special.cpp
new file mode 100644
index 00000000..23e58441
--- /dev/null
+++ b/kdvi/special.cpp
@@ -0,0 +1,727 @@
+
+// special.cpp
+
+// Methods for dviRenderer which deal with "\special" commands found in the
+// DVI file
+
+// Copyright 2000--2004, Stefan Kebekus (kebekus@kde.org).
+
+#include <config.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmimetype.h>
+#include <kprocio.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qimage.h>
+#include <qstringlist.h>
+
+#include "dviFile.h"
+#include "dviRenderer.h"
+#include "hyperlink.h"
+#include "kdvi.h"
+#include "kdvi_multipage.h"
+#include "psgs.h"
+#include "xdvi.h"
+
+//#define DEBUG_SPECIAL
+
+extern QPainter *foreGroundPainter;
+
+void dviRenderer::printErrorMsgForSpecials(const QString& msg)
+{
+ if (dviFile->errorCounter < 25) {
+ kdError(4300) << msg << endl;
+ dviFile->errorCounter++;
+ if (dviFile->errorCounter == 25)
+ kdError(4300) << i18n("That makes 25 errors. Further error messages will not be printed.") << endl;
+ }
+}
+
+// Parses a color specification, as explained in the manual to
+// dvips. If the spec could not be parsed, an invalid color will be
+// returned.
+
+QColor dviRenderer::parseColorSpecification(const QString& colorSpec)
+{
+ // Initialize the map of known colors, if that is not done yet.
+ if (namedColors.isEmpty()) {
+ namedColors["Red"] = QColor( (int)(255.0*1), (int)(255.0*0), (int)(255.0*0));
+ namedColors["Tan"] = QColor( (int)(255.0*0.86), (int)(255.0*0.58), (int)(255.0*0.44));
+ namedColors["Blue"] = QColor( (int)(255.0*0), (int)(255.0*0), (int)(255.0*1));
+ namedColors["Cyan"] = QColor( (int)(255.0*0), (int)(255.0*1), (int)(255.0*1));
+ namedColors["Gray"] = QColor( (int)(255.0*0.5), (int)(255.0*0.5), (int)(255.0*0.5));
+ namedColors["Plum"] = QColor( (int)(255.0*0.5), (int)(255.0*0), (int)(255.0*1));
+ namedColors["Black"] = QColor( (int)(255.0*0), (int)(255.0*0), (int)(255.0*0));
+ namedColors["Brown"] = QColor( (int)(255.0*0.4), (int)(255.0*0), (int)(255.0*0));
+ namedColors["Green"] = QColor( (int)(255.0*0), (int)(255.0*1), (int)(255.0*0));
+ namedColors["Melon"] = QColor( (int)(255.0*1), (int)(255.0*0.54), (int)(255.0*0.5));
+ namedColors["Peach"] = QColor( (int)(255.0*1), (int)(255.0*0.5), (int)(255.0*0.3));
+ namedColors["Sepia"] = QColor( (int)(255.0*0.3), (int)(255.0*0), (int)(255.0*0));
+ namedColors["White"] = QColor( (int)(255.0*1), (int)(255.0*1), (int)(255.0*1));
+ namedColors["Maroon"] = QColor( (int)(255.0*0.68), (int)(255.0*0), (int)(255.0*0));
+ namedColors["Orange"] = QColor( (int)(255.0*1), (int)(255.0*0.39), (int)(255.0*0.13));
+ namedColors["Orchid"] = QColor( (int)(255.0*0.68), (int)(255.0*0.36), (int)(255.0*1));
+ namedColors["Purple"] = QColor( (int)(255.0*0.55), (int)(255.0*0.14), (int)(255.0*1));
+ namedColors["Salmon"] = QColor( (int)(255.0*1), (int)(255.0*0.47), (int)(255.0*0.62));
+ namedColors["Violet"] = QColor( (int)(255.0*0.21), (int)(255.0*0.12), (int)(255.0*1));
+ namedColors["Yellow"] = QColor( (int)(255.0*1), (int)(255.0*1), (int)(255.0*0));
+ namedColors["Apricot"] = QColor( (int)(255.0*1), (int)(255.0*0.68), (int)(255.0*0.48));
+ namedColors["Emerald"] = QColor( (int)(255.0*0), (int)(255.0*1), (int)(255.0*0.5));
+ namedColors["Fuchsia"] = QColor( (int)(255.0*0.45), (int)(255.0*0.01), (int)(255.0*0.92));
+ namedColors["Magenta"] = QColor( (int)(255.0*1), (int)(255.0*0), (int)(255.0*1));
+ namedColors["SkyBlue"] = QColor( (int)(255.0*0.38), (int)(255.0*1), (int)(255.0*0.88));
+ namedColors["Thistle"] = QColor( (int)(255.0*0.88), (int)(255.0*0.41), (int)(255.0*1));
+ namedColors["BrickRed"] = QColor( (int)(255.0*0.72), (int)(255.0*0), (int)(255.0*0));
+ namedColors["Cerulean"] = QColor( (int)(255.0*0.06), (int)(255.0*0.89), (int)(255.0*1));
+ namedColors["Lavender"] = QColor( (int)(255.0*1), (int)(255.0*0.52), (int)(255.0*1));
+ namedColors["Mahogany"] = QColor( (int)(255.0*0.65), (int)(255.0*0), (int)(255.0*0));
+ namedColors["Mulberry"] = QColor( (int)(255.0*0.64), (int)(255.0*0.08), (int)(255.0*0.98));
+ namedColors["NavyBlue"] = QColor( (int)(255.0*0.06), (int)(255.0*0.46), (int)(255.0*1));
+ namedColors["SeaGreen"] = QColor( (int)(255.0*0.31), (int)(255.0*1), (int)(255.0*0.5));
+ namedColors["TealBlue"] = QColor( (int)(255.0*0.12), (int)(255.0*0.98), (int)(255.0*0.64));
+ namedColors["BlueGreen"] = QColor( (int)(255.0*0.15), (int)(255.0*1), (int)(255.0*0.67));
+ namedColors["CadetBlue"] = QColor( (int)(255.0*0.38), (int)(255.0*0.43), (int)(255.0*0.77));
+ namedColors["Dandelion"] = QColor( (int)(255.0*1), (int)(255.0*0.71), (int)(255.0*0.16));
+ namedColors["Goldenrod"] = QColor( (int)(255.0*1), (int)(255.0*0.9), (int)(255.0*0.16));
+ namedColors["LimeGreen"] = QColor( (int)(255.0*0.5), (int)(255.0*1), (int)(255.0*0));
+ namedColors["OrangeRed"] = QColor( (int)(255.0*1), (int)(255.0*0), (int)(255.0*0.5));
+ namedColors["PineGreen"] = QColor( (int)(255.0*0), (int)(255.0*0.75), (int)(255.0*0.16));
+ namedColors["RawSienna"] = QColor( (int)(255.0*0.55), (int)(255.0*0), (int)(255.0*0));
+ namedColors["RedOrange"] = QColor( (int)(255.0*1), (int)(255.0*0.23), (int)(255.0*0.13));
+ namedColors["RedViolet"] = QColor( (int)(255.0*0.59), (int)(255.0*0), (int)(255.0*0.66));
+ namedColors["Rhodamine"] = QColor( (int)(255.0*1), (int)(255.0*0.18), (int)(255.0*1));
+ namedColors["RoyalBlue"] = QColor( (int)(255.0*0), (int)(255.0*0.5), (int)(255.0*1));
+ namedColors["RubineRed"] = QColor( (int)(255.0*1), (int)(255.0*0), (int)(255.0*0.87));
+ namedColors["Turquoise"] = QColor( (int)(255.0*0.15), (int)(255.0*1), (int)(255.0*0.8));
+ namedColors["VioletRed"] = QColor( (int)(255.0*1), (int)(255.0*0.19), (int)(255.0*1));
+ namedColors["Aquamarine"] = QColor( (int)(255.0*0.18), (int)(255.0*1), (int)(255.0*0.7));
+ namedColors["BlueViolet"] = QColor( (int)(255.0*0.1), (int)(255.0*0.05), (int)(255.0*0.96));
+ namedColors["DarkOrchid"] = QColor( (int)(255.0*0.6), (int)(255.0*0.2), (int)(255.0*0.8));
+ namedColors["OliveGreen"] = QColor( (int)(255.0*0), (int)(255.0*0.6), (int)(255.0*0));
+ namedColors["Periwinkle"] = QColor( (int)(255.0*0.43), (int)(255.0*0.45), (int)(255.0*1));
+ namedColors["Bittersweet"] = QColor( (int)(255.0*0.76), (int)(255.0*0.01), (int)(255.0*0));
+ namedColors["BurntOrange"] = QColor( (int)(255.0*1), (int)(255.0*0.49), (int)(255.0*0));
+ namedColors["ForestGreen"] = QColor( (int)(255.0*0), (int)(255.0*0.88), (int)(255.0*0));
+ namedColors["GreenYellow"] = QColor( (int)(255.0*0.85), (int)(255.0*1), (int)(255.0*0.31));
+ namedColors["JungleGreen"] = QColor( (int)(255.0*0.01), (int)(255.0*1), (int)(255.0*0.48));
+ namedColors["ProcessBlue"] = QColor( (int)(255.0*0.04), (int)(255.0*1), (int)(255.0*1));
+ namedColors["RoyalPurple"] = QColor( (int)(255.0*0.25), (int)(255.0*0.1), (int)(255.0*1));
+ namedColors["SpringGreen"] = QColor( (int)(255.0*0.74), (int)(255.0*1), (int)(255.0*0.24));
+ namedColors["YellowGreen"] = QColor( (int)(255.0*0.56), (int)(255.0*1), (int)(255.0*0.26));
+ namedColors["MidnightBlue"] = QColor( (int)(255.0*0), (int)(255.0*0.44), (int)(255.0*0.57));
+ namedColors["YellowOrange"] = QColor( (int)(255.0*1), (int)(255.0*0.58), (int)(255.0*0));
+ namedColors["CarnationPink"] = QColor( (int)(255.0*1), (int)(255.0*0.37), (int)(255.0*1));
+ namedColors["CornflowerBlue"] = QColor( (int)(255.0*0.35), (int)(255.0*0.87), (int)(255.0*1));
+ namedColors["WildStrawberry"] = QColor( (int)(255.0*1), (int)(255.0*0.04), (int)(255.0*0.61));
+ }
+
+ QString specType = colorSpec.section(' ', 0, 0);
+
+ if (specType.find("rgb", false) == 0) {
+ bool ok;
+
+ double r = colorSpec.section(' ', 1, 1).toDouble(&ok);
+ if ((ok == false) || (r < 0.0) || (r > 1.0))
+ return QColor();
+
+ double g = colorSpec.section(' ', 2, 2).toDouble(&ok);
+ if ((ok == false) || (g < 0.0) || (g > 1.0))
+ return QColor();
+
+ double b = colorSpec.section(' ', 3, 3).toDouble(&ok);
+ if ((ok == false) || (b < 0.0) || (b > 1.0))
+ return QColor();
+
+ return QColor((int)(r*255.0+0.5), (int)(g*255.0+0.5), (int)(b*255.0+0.5));
+ }
+
+ if (specType.find("hsb", false) == 0) {
+ bool ok;
+
+ double h = colorSpec.section(' ', 1, 1).toDouble(&ok);
+ if ((ok == false) || (h < 0.0) || (h > 1.0))
+ return QColor();
+
+ double s = colorSpec.section(' ', 2, 2).toDouble(&ok);
+ if ((ok == false) || (s < 0.0) || (s > 1.0))
+ return QColor();
+
+ double b = colorSpec.section(' ', 3, 3).toDouble(&ok);
+ if ((ok == false) || (b < 0.0) || (b > 1.0))
+ return QColor();
+
+ return QColor((int)(h*359.0+0.5), (int)(s*255.0+0.5), (int)(b*255.0+0.5), QColor::Hsv);
+ }
+
+ if (specType.find("cmyk", false) == 0) {
+ bool ok;
+
+ double c = colorSpec.section(' ', 1, 1).toDouble(&ok);
+ if ((ok == false) || (c < 0.0) || (c > 1.0))
+ return QColor();
+
+ double m = colorSpec.section(' ', 2, 2).toDouble(&ok);
+ if ((ok == false) || (m < 0.0) || (m > 1.0))
+ return QColor();
+
+ double y = colorSpec.section(' ', 3, 3).toDouble(&ok);
+ if ((ok == false) || (y < 0.0) || (y > 1.0))
+ return QColor();
+
+ double k = colorSpec.section(' ', 3, 3).toDouble(&ok);
+ if ((ok == false) || (k < 0.0) || (k > 1.0))
+ return QColor();
+
+ // Convert cmyk coordinates to rgb.
+ double r = 1.0 - c - k;
+ if (r < 0.0)
+ r = 0.0;
+ double g = 1.0 - m - k;
+ if (g < 0.0)
+ g = 0.0;
+ double b = 1.0 - y - k;
+ if (b < 0.0)
+ b = 0.0;
+
+ return QColor((int)(r*255.0+0.5), (int)(g*255.0+0.5), (int)(b*255.0+0.5));
+ }
+
+ if (specType.find("gray", false) == 0) {
+ bool ok;
+
+ double g = colorSpec.section(' ', 1, 1).toDouble(&ok);
+ if ((ok == false) || (g < 0.0) || (g > 1.0))
+ return QColor();
+
+ return QColor((int)(g*255.0+0.5), (int)(g*255.0+0.5), (int)(g*255.0+0.5));
+ }
+
+ // Check if the color is one of the known named colors.
+ QMap<QString, QColor>::Iterator f = namedColors.find(specType);
+ if (f != namedColors.end())
+ return *f;
+
+ return QColor(specType);
+}
+
+
+
+
+
+
+void dviRenderer::color_special(const QString& _cp)
+{
+ QString const cp = _cp.stripWhiteSpace();
+
+ QString command = cp.section(' ', 0, 0);
+
+ if (command == "pop") {
+ // Take color off the stack
+ if (colorStack.isEmpty())
+ printErrorMsgForSpecials( i18n("Error in DVIfile '%1', page %2. Color pop command issued when the color stack is empty." ).
+ arg(dviFile->filename).arg(current_page));
+ else
+ colorStack.pop();
+ return;
+ }
+
+ if (command == "push") {
+ // Get color specification
+ QColor const col = parseColorSpecification(cp.section(' ', 1));
+ // Set color
+ if (col.isValid())
+ colorStack.push(col);
+ else
+ colorStack.push(Qt::black);
+ return;
+ }
+
+ // Get color specification and set the color for the rest of this
+ // page
+ QColor col = parseColorSpecification(cp);
+ // Set color
+ if (col.isValid())
+ globalColor = col;
+ else
+ globalColor = Qt::black;
+ return;
+}
+
+
+void dviRenderer::html_href_special(const QString& _cp)
+{
+ QString cp = _cp;
+ cp.truncate(cp.find('"'));
+
+#ifdef DEBUG_SPECIAL
+ kdDebug(4300) << "HTML-special, href " << cp.latin1() << endl;
+#endif
+ HTML_href = new QString(cp);
+}
+
+
+void dviRenderer::html_anchor_end()
+{
+#ifdef DEBUG_SPECIAL
+ kdDebug(4300) << "HTML-special, anchor-end" << endl;
+#endif
+
+ if (HTML_href != NULL) {
+ delete HTML_href;
+ HTML_href = NULL;
+ }
+}
+
+
+void dviRenderer::source_special(const QString& cp)
+{
+ // only when rendering really takes place: set source_href to the
+ // current special string. When characters are rendered, the
+ // rendering routine will then generate a DVI_HyperLink and add it
+ // to the proper list. This DVI_HyperLink is used to match mouse
+ // positions with the hyperlinks for inverse search.
+ if (source_href)
+ *source_href = cp;
+ else
+ source_href = new QString(cp);
+}
+
+
+void parse_special_argument(const QString& strg, const char* argument_name, int* variable)
+{
+ int index = strg.find(argument_name);
+ if (index >= 0) {
+ QString tmp = strg.mid(index + strlen(argument_name));
+ index = tmp.find(' ');
+ if (index >= 0)
+ tmp.truncate(index);
+
+ bool OK;
+ float const tmp_float = tmp.toFloat(&OK);
+
+ if (OK)
+ *variable = int(tmp_float+0.5);
+ else
+ // Maybe we should open a dialog here.
+ kdError(4300) << i18n("Malformed parameter in the epsf special command.\n"
+ "Expected a float to follow %1 in %2")
+ .arg(argument_name).arg(strg) << endl;
+ }
+}
+
+
+void dviRenderer::epsf_special(const QString& cp)
+{
+#ifdef DEBUG_SPECIAL
+ kdDebug(4300) << "epsf-special: psfile=" << cp <<endl;
+#endif
+
+ QString include_command = cp.simplifyWhiteSpace();
+
+ // The line is supposed to start with "..ile=", and then comes the
+ // filename. Figure out what the filename is and stow it away. Of
+ // course, this does not work if the filename contains spaces
+ // (already the simplifyWhiteSpace() above is wrong). If you have
+ // files like this, go away.
+ QString EPSfilename_orig = include_command;
+ EPSfilename_orig.truncate(EPSfilename_orig.find(' '));
+
+ // Strip enclosing quotation marks which are included by some LaTeX
+ // macro packages (but not by others). This probably means that
+ // graphic files are no longer found if the filename really does
+ // contain quotes, but we don't really care that much.
+ if ((EPSfilename_orig.at(0) == '\"') && (EPSfilename_orig.at(EPSfilename_orig.length()-1) == '\"')) {
+ EPSfilename_orig = EPSfilename_orig.mid(1,EPSfilename_orig.length()-2);
+ }
+ QString EPSfilename = ghostscript_interface::locateEPSfile(EPSfilename_orig, baseURL);
+
+ // Now parse the arguments.
+ int llx = 0;
+ int lly = 0;
+ int urx = 0;
+ int ury = 0;
+ int rwi = 0;
+ int rhi = 0;
+ int angle = 0;
+
+ // just to avoid ambiguities; the filename could contain keywords
+ include_command = include_command.mid(include_command.find(' '));
+
+ parse_special_argument(include_command, "llx=", &llx);
+ parse_special_argument(include_command, "lly=", &lly);
+ parse_special_argument(include_command, "urx=", &urx);
+ parse_special_argument(include_command, "ury=", &ury);
+ parse_special_argument(include_command, "rwi=", &rwi);
+ parse_special_argument(include_command, "rhi=", &rhi);
+ parse_special_argument(include_command, "angle=", &angle);
+
+ // If we have a png, gif, jpeg or mng file, we need to draw it here.
+ KMimeType::Ptr const mime_type = KMimeType::findByFileContent(EPSfilename);
+ QString const & mime_type_name = mime_type->name();
+ bool const isGFX = (mime_type_name == "image/png" ||
+ mime_type_name == "image/gif" ||
+ mime_type_name == "image/jpeg" ||
+ mime_type_name == "video/x-mng");
+
+ // So, if we do not have a PostScript file, but a graphics file, and
+ // if that file exists, we draw it here.
+ if (isGFX && QFile::exists(EPSfilename)) {
+ // Don't show PostScript, just draw the bounding box. For this,
+ // calculate the size of the bounding box in Pixels.
+ double bbox_width = urx - llx;
+ double bbox_height = ury - lly;
+
+ if ((rwi != 0)&&(bbox_width != 0)) {
+ bbox_height *= rwi/bbox_width;
+ bbox_width = rwi;
+ }
+ if ((rhi != 0)&&(bbox_height != 0)) {
+ bbox_width *= rhi/bbox_height;
+ bbox_height = rhi;
+ }
+
+ double fontPixelPerDVIunit = dviFile->getCmPerDVIunit() * 1200.0/2.54;
+
+ bbox_width *= 0.1 * 65536.0*fontPixelPerDVIunit / shrinkfactor;
+ bbox_height *= 0.1 * 65536.0*fontPixelPerDVIunit / shrinkfactor;
+
+ QImage image(EPSfilename);
+ image = image.smoothScale((int)(bbox_width), (int)(bbox_height));
+ foreGroundPainter->drawImage( ((int) ((currinf.data.dvi_h) / (shrinkfactor * 65536))), currinf.data.pxl_v - (int)bbox_height, image);
+ return;
+ }
+
+ if (!_postscript || !QFile::exists(EPSfilename)) {
+ // Don't show PostScript, just draw the bounding box. For this,
+ // calculate the size of the bounding box in Pixels.
+ double bbox_width = urx - llx;
+ double bbox_height = ury - lly;
+
+ if ((rwi != 0)&&(bbox_width != 0)) {
+ bbox_height *= rwi/bbox_width;
+ bbox_width = rwi;
+ }
+ if ((rhi != 0)&&(bbox_height != 0)) {
+ bbox_width *= rhi/bbox_height;
+ bbox_height = rhi;
+ }
+
+ double fontPixelPerDVIunit = dviFile->getCmPerDVIunit() * 1200.0/2.54;
+
+ bbox_width *= 0.1 * 65536.0*fontPixelPerDVIunit / shrinkfactor;
+ bbox_height *= 0.1 * 65536.0*fontPixelPerDVIunit / shrinkfactor;
+
+ QRect bbox(((int) ((currinf.data.dvi_h) / (shrinkfactor * 65536))), currinf.data.pxl_v - (int)bbox_height,
+ (int)bbox_width, (int)bbox_height);
+
+ foreGroundPainter->save();
+
+ if (QFile::exists(EPSfilename))
+ foreGroundPainter->setBrush(Qt::lightGray);
+ else
+ foreGroundPainter->setBrush(Qt::red);
+ foreGroundPainter->setPen(Qt::black);
+ foreGroundPainter->drawRoundRect(bbox, 2, 2);
+ QFont f = foreGroundPainter->font();
+ f.setPointSize(8);
+ foreGroundPainter->setFont(f);
+ if (QFile::exists(EPSfilename))
+ foreGroundPainter->drawText (bbox, (int)(Qt::AlignCenter), EPSfilename_orig, -1);
+ else
+ foreGroundPainter->drawText (bbox, (int)(Qt::AlignCenter),
+ i18n("File not found: \n %1").arg(EPSfilename_orig), -1);
+ foreGroundPainter->restore();
+ }
+
+ return;
+}
+
+
+void dviRenderer::TPIC_flushPath_special()
+{
+#ifdef DEBUG_SPECIAL
+ kdDebug(4300) << "TPIC special flushPath" << endl;
+#endif
+
+ if (number_of_elements_in_path == 0) {
+ printErrorMsgForSpecials("TPIC special flushPath called when path was empty.");
+ return;
+ }
+
+ QPen pen(Qt::black, (int)(penWidth_in_mInch*resolutionInDPI/1000.0 + 0.5)); // Sets the pen size in milli-inches
+ foreGroundPainter->setPen(pen);
+ foreGroundPainter->drawPolyline(TPIC_path, 0, number_of_elements_in_path);
+ number_of_elements_in_path = 0;
+}
+
+
+void dviRenderer::TPIC_addPath_special(const QString& cp)
+{
+#ifdef DEBUG_SPECIAL
+ kdDebug(4300) << "TPIC special addPath: " << cp << endl;
+#endif
+
+ // Adds a point to the path list
+ QString cp_noWhiteSpace = cp.stripWhiteSpace();
+ bool ok;
+ float xKoord = cp_noWhiteSpace.section(' ', 0, 0).toFloat(&ok);
+ if (ok == false) {
+ printErrorMsgForSpecials( QString("TPIC special; cannot parse first argument in 'pn %1'.").arg(cp) );
+ return;
+ }
+ float yKoord = cp_noWhiteSpace.section(' ', 1, 1).toFloat(&ok);
+ if (ok == false) {
+ printErrorMsgForSpecials( QString("TPIC special; cannot parse second argument in 'pn %1'.").arg(cp) );
+ return;
+ }
+
+ float mag = dviFile->getMagnification()/1000.0;
+
+ int x = (int)( currinf.data.dvi_h/(shrinkfactor*65536.0) + mag*xKoord*resolutionInDPI/1000.0 + 0.5 );
+ int y = (int)( currinf.data.pxl_v + mag*yKoord*resolutionInDPI/1000.0 + 0.5 );
+
+ // Initialize the point array used to store the path
+ if (TPIC_path.size() == 0)
+ number_of_elements_in_path = 0;
+ if (TPIC_path.size() == number_of_elements_in_path)
+ TPIC_path.resize(number_of_elements_in_path+100);
+ TPIC_path.setPoint(number_of_elements_in_path++, x, y);
+}
+
+
+void dviRenderer::TPIC_setPen_special(const QString& cp)
+{
+#ifdef DEBUG_SPECIAL
+ kdDebug(4300) << "TPIC special setPen: " << cp << endl;
+#endif
+
+ // Sets the pen size in milli-inches
+ bool ok;
+ penWidth_in_mInch = cp.stripWhiteSpace().toFloat(&ok);
+ if (ok == false) {
+ printErrorMsgForSpecials( QString("TPIC special; cannot parse argument in 'pn %1'.").arg(cp) );
+ penWidth_in_mInch = 0.0;
+ return;
+ }
+}
+
+
+void dviRenderer::applicationDoSpecial(char *cp)
+{
+ QString special_command(cp);
+
+ // First come specials which is only interpreted during rendering,
+ // and NOT during the prescan phase
+
+ // font color specials
+ if (strncasecmp(cp, "color", 5) == 0) {
+ color_special(special_command.mid(5));
+ return;
+ }
+
+ // HTML reference
+ if (strncasecmp(cp, "html:<A href=", 13) == 0) {
+ html_href_special(special_command.mid(14));
+ return;
+ }
+
+ // HTML anchor end
+ if (strncasecmp(cp, "html:</A>", 9) == 0) {
+ html_anchor_end();
+ return;
+ }
+
+ // TPIC specials
+ if (strncasecmp(cp, "pn", 2) == 0) {
+ TPIC_setPen_special(special_command.mid(2));
+ return;
+ }
+ if (strncasecmp(cp, "pa ", 3) == 0) {
+ TPIC_addPath_special(special_command.mid(3));
+ return;
+ }
+ if (strncasecmp(cp, "fp", 2) == 0) {
+ TPIC_flushPath_special();
+ return;
+ }
+
+ // Encapsulated Postscript File
+ if (strncasecmp(cp, "PSfile=", 7) == 0) {
+ epsf_special(special_command.mid(7));
+ return;
+ }
+
+ // source special
+ if (strncasecmp(cp, "src:", 4) == 0) {
+ source_special(special_command.mid(4));
+ return;
+ }
+
+ // Unfortunately, in some TeX distribution the hyperref package uses
+ // the dvips driver by default, rather than the hypertex driver. As
+ // a result, the DVI files produced are full of PostScript that
+ // specifies links and anchors, and KDVI would call the ghostscript
+ // interpreter for every page which makes it really slow. This is a
+ // major nuisance, so that we try to filter and interpret the
+ // hypertex generated PostScript here.
+ if (special_command.startsWith("ps:SDict begin")) {
+
+ // Hyperref: start of hyperref rectangle. At this stage it is not
+ // yet clear if the rectangle will conain a hyperlink, an anchor,
+ // or another type of object. We suspect that this rectangle will
+ // define a hyperlink, allocate a QString and set HTML_href to
+ // point to this string. The string contains the name of the
+ // destination which ---due to the nature of the PostScript
+ // language--- will be defined only after characters are drawn and
+ // the hyperref rectangle has been closed. We use "glopglyph" as a
+ // temporary name. Since the pointer HTML_href is not NULL, the
+ // chracter drawing routines will now underline all characters in
+ // blue to point out that they correspond to a hyperlink. Also, as
+ // soon as characters are drawn, the drawing routines will
+ // allocate a Hyperlink and add it to the top of the vector
+ // currentlyDrawnPage->hyperLinkList.
+ if (special_command == "ps:SDict begin H.S end") {
+ // At this stage, the vector 'hyperLinkList' should not contain
+ // links with unspecified destinations (i.e. destination set to
+ // 'glopglyph'). As a protection against bad DVI files, we make
+ // sure to remove all link rectangles which point to
+ // 'glopglyph'.
+ while (!currentlyDrawnPage->hyperLinkList.isEmpty())
+ if (currentlyDrawnPage->hyperLinkList.last().linkText == "glopglyph")
+ currentlyDrawnPage->hyperLinkList.pop_back();
+ else
+ break;
+
+ HTML_href = new QString("glopglyph");
+ return;
+ }
+
+ // Hyperref: end of hyperref rectangle of unknown type or hyperref
+ // link rectangle. In these cases we set HTML_href to NULL, which
+ // causes the character drawing routines to stop drawing
+ // characters underlined in blue. Note that the name of the
+ // destination is still set to "glopglyph". In a well-formed DVI
+ // file, this special command is immediately followed by another
+ // special, where the destination is specified. This special is
+ // treated below.
+ if ((special_command == "ps:SDict begin H.R end") || special_command.endsWith("H.L end")) {
+ if (HTML_href != NULL) {
+ delete HTML_href;
+ HTML_href = NULL;
+ }
+ return; // end of hyperref rectangle
+ }
+
+ // Hyperref: end of anchor rectangle. If this special is
+ // encountered, the rectangle, which was started with "ps:SDict
+ // begin H.S end" does not contain a link, but an anchor for a
+ // link. Anchors, however, have already been dealt with in the
+ // prescan phase and will not be considered here. Thus, we set
+ // HTML_href to NULL so that character drawing routines will no
+ // longer underline hyperlinks in blue, and remove the link from
+ // the hyperLinkList. NOTE: in a well-formed DVI file, the "H.A"
+ // special comes directly after the "H.S" special. A
+ // hyperlink-anchor rectangle therefore never contains characters,
+ // so no character will by accidentally underlined in blue.
+ if (special_command.endsWith("H.A end")) {
+ if (HTML_href != NULL) {
+ delete HTML_href;
+ HTML_href = NULL;
+ }
+ while (!currentlyDrawnPage->hyperLinkList.isEmpty())
+ if (currentlyDrawnPage->hyperLinkList.last().linkText == "glopglyph")
+ currentlyDrawnPage->hyperLinkList.pop_back();
+ else
+ break;
+ return; // end of hyperref anchor
+ }
+
+ // Hyperref: specification of a hyperref link rectangle's
+ // destination. As mentioned above, the destination of a hyperlink
+ // is specified only AFTER the rectangle has been specified. We
+ // will therefore go through the list of rectangles stored in
+ // currentlyDrawnPage->hyperLinkList, find those whose destination
+ // is open and fill in the value found here. NOTE: the character
+ // drawing routines sometimes split a single hyperlink rectangle
+ // into several rectangles (e.g. if the font changes, or when a
+ // line break is encountered)
+ if (special_command.startsWith("ps:SDict begin [") && special_command.endsWith(" pdfmark end")) {
+ if (!currentlyDrawnPage->hyperLinkList.isEmpty()) {
+ // Parse the PostScript literal text string inside parentheses
+ // and store it into 'targetName'. The scanner works
+ // according to "PostScript language reference, third edition"
+ // - Sec. 3.2.2. The specification is implemented completely:
+ // balanced parentheses and all escape sequences are
+ // considered.
+ QString tmpTargetName = special_command.section('(', 1);
+ QString targetName;
+ int parencount = 1;
+ for(int i=0; i<tmpTargetName.length(); i++) {
+ if (tmpTargetName[i] == '(')
+ if ((i == 0) || (tmpTargetName[i-1] != '\\'))
+ parencount++;
+ if (tmpTargetName[i] == ')')
+ if ((i == 0) || (tmpTargetName[i-1] != '\\'))
+ parencount--;
+ if (parencount == 0)
+ break;
+ targetName += tmpTargetName[i];
+ }
+ targetName = PDFencodingToQString(targetName);
+
+ QValueVector<Hyperlink>::iterator it;
+ for( it = currentlyDrawnPage->hyperLinkList.begin(); it != currentlyDrawnPage->hyperLinkList.end(); ++it )
+ if (it->linkText == "glopglyph")
+ it->linkText = targetName;
+ }
+ return; // hyperref definition of link/anchor/bookmark/etc
+ }
+ }
+
+ // Detect text rotation specials that are included by the graphicx
+ // package. If one of these specials is found, the state of the
+ // painter is saved, and the coordinate system is rotated
+ // accordingly
+ if (special_command.startsWith("ps: gsave currentpoint currentpoint translate ") &&
+ special_command.endsWith(" neg rotate neg exch neg exch translate") ) {
+ bool ok;
+ double angle = special_command.section(' ', 5, 5).toDouble(&ok);
+ if (ok == true) {
+ int x = ((int) ((currinf.data.dvi_h) / (shrinkfactor * 65536)));
+ int y = currinf.data.pxl_v;
+
+ foreGroundPainter->save();
+ // Rotate about the current point
+ foreGroundPainter->translate(x,y);
+ foreGroundPainter->rotate(-angle);
+ foreGroundPainter->translate(-x,-y);
+ } else
+ printErrorMsgForSpecials( i18n("Error in DVIfile '%1', page %2. Could not interpret angle in text rotation special." ).
+ arg(dviFile->filename).arg(current_page));
+ }
+
+ // The graphicx package marks the end of rotated text with this
+ // special. The state of the painter is restored.
+ if (special_command == "ps: currentpoint grestore moveto") {
+ foreGroundPainter->restore();
+ }
+
+ // The following special commands are not used here; they are of
+ // interest only during the prescan phase. We recognize them here
+ // anyway, to make sure that KDVI doesn't complain about
+ // unrecognized special commands.
+ if ((cp[0] == '!') ||
+ (cp[0] == '"') ||
+ (strncasecmp(cp, "html:<A name=", 13) == 0) ||
+ (strncasecmp(cp, "ps:", 3) == 0) ||
+ (strncasecmp(cp, "papersize", 9) == 0) ||
+ (strncasecmp(cp, "header", 6) == 0) ||
+ (strncasecmp(cp, "background", 10) == 0) )
+ return;
+
+ printErrorMsgForSpecials(i18n("The special command '%1' is not implemented.").arg(special_command));
+ return;
+}
diff --git a/kdvi/squeeze.c b/kdvi/squeeze.c
new file mode 100644
index 00000000..d0e2515f
--- /dev/null
+++ b/kdvi/squeeze.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 1994 Paul Vojta. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * NOTE:
+ * This routine is adapted from the squeeze.c that comes with dvips;
+ * it bears the message:
+ * This software is Copyright 1988 by Radical Eye Software.
+ * Used with permission.
+ */
+/*
+ * This routine squeezes a PostScript file down to its
+ * minimum. We parse and then output it.
+ * Adapted for xdvi 1/94. Writes a C program that contains the PS file
+ * as a constant string.
+ */
+#include <stdio.h>
+#include <string.h>
+#define LINELENGTH (72)
+#define BUFLENGTH (1000)
+#undef putchar
+#define putchar(a) (void)putc(a, out) ;
+FILE *in, *out ;
+static int linepos = 0 ;
+static int lastspecial = 1 ;
+static int stringlen = 0;
+
+void specialout(char);
+void strout(char *);
+void cmdout(char *);
+
+/*
+ * This next routine writes out a `special' character. In this case,
+ * we simply put it out, since any special character terminates the
+ * preceding token.
+ */
+void specialout(char c)
+{
+ if (linepos + 1 > LINELENGTH) {
+ (void)fputs("\\n\\\n", out);
+ stringlen += linepos + 1;
+ linepos = 0 ;
+ }
+ putchar(c) ;
+ linepos++ ;
+ lastspecial = 1 ;
+}
+void strout(s)
+char *s ;
+{
+ if (linepos + strlen(s) > LINELENGTH) {
+ (void)fputs("\\n\\\n", out);
+ stringlen += linepos + 1;
+ linepos = 0 ;
+ }
+ linepos += strlen(s) ;
+ while (*s != 0)
+ putchar(*s++) ;
+ lastspecial = 1 ;
+}
+void cmdout(s)
+char *s ;
+{
+ int l ;
+
+ l = strlen(s) ;
+ if (linepos + l + 1 > LINELENGTH) {
+ (void)fputs("\\n\\\n", out);
+ stringlen += linepos + 1;
+ linepos = 0 ;
+ lastspecial = 1 ;
+ }
+ if (! lastspecial) {
+ putchar(' ') ;
+ linepos++ ;
+ }
+ while (*s != 0) {
+ putchar(*s++) ;
+ }
+ linepos += l ;
+ lastspecial = 0 ;
+}
+char buf[BUFLENGTH] ;
+
+int main(int argc, char *argv[])
+{
+ int c ;
+ char *b ;
+ char seeking ;
+ extern void exit() ;
+
+ if (argc > 3 || (in=(argc < 2 ? stdin : fopen(argv[1], "r")))==NULL ||
+ (out=(argc < 3 ? stdout : fopen(argv[2], "w")))==NULL) {
+ (void)fprintf(stderr, "Usage: squeeze [infile [outfile]]\n") ;
+ exit(1) ;
+ }
+ (void)fputs("/*\n\
+ * DO NOT EDIT THIS FILE!\n\
+ * It was created by squeeze.c from another file (see the Makefile).\n\
+ */\n\n\
+#ifndef _Xconst\n\
+#if __STDC__\n\
+#define _Xconst const\n\
+#else\n\
+#define _Xconst\n\
+#endif\n\
+#endif\n\n\
+_Xconst char psheader[] = \"\\\n", out);
+ while (1) {
+ c = getc(in) ;
+ if (c==EOF)
+ break ;
+ if (c=='%') {
+ while ((c=getc(in))!='\n') ;
+ }
+ if (c <= ' ')
+ continue ;
+ switch (c) {
+case '{' :
+case '}' :
+case '[' :
+case ']' :
+ specialout(c) ;
+ break ;
+case '<' :
+case '(' :
+ if (c=='(')
+ seeking = ')' ;
+ else
+ seeking = '>' ;
+ b = buf ;
+ *b++ = c ;
+ do {
+ c = getc(in) ;
+ if (b > buf + BUFLENGTH-2) {
+ (void)fprintf(stderr, "Overran buffer seeking %c", seeking) ;
+ exit(1) ;
+ }
+ *b++ = c ;
+ if (c=='\\')
+ *b++ = getc(in) ;
+ } while (c != seeking) ;
+ *b++ = 0 ;
+ strout(buf) ;
+ break ;
+default:
+ b = buf ;
+ while ((c>='A'&&c<='Z')||(c>='a'&&c<='z')||
+ (c>='0'&&c<='9')||(c=='/')||(c=='@')||
+ (c=='!')||(c=='"')||(c=='&')||(c=='*')||(c==':')||
+ (c==',')||(c==';')||(c=='?')||(c=='^')||(c=='~')||
+ (c=='-')||(c=='.')||(c=='#')||(c=='|')||(c=='_')||
+ (c=='=')||(c=='$')||(c=='+')) {
+ *b++ = c ;
+ c = getc(in) ;
+ }
+ if (b == buf) {
+ (void)fprintf(stderr, "Oops! Missed a case: %c.\n", c) ;
+ exit(1) ;
+ }
+ *b++ = 0 ;
+ (void)ungetc(c, in) ;
+ cmdout(buf) ;
+ }
+ }
+ (void)fprintf(out, "\\n\";\n\n\
+int\tpsheaderlen\t= %d;\n", stringlen + linepos + 1);
+ return (0) ;
+ /*NOTREACHED*/
+}
diff --git a/kdvi/tips b/kdvi/tips
new file mode 100644
index 00000000..399d4427
--- /dev/null
+++ b/kdvi/tips
@@ -0,0 +1,42 @@
+<tip category="KDVI|General">
+<html>
+<p>...that KDVI can also load compressed DVI-files?
+</html>
+</tip>
+
+<tip category="KDVI|General">
+<html>
+<p>...that you can mark text with the right mouse button and paste it
+into any application?
+</html>
+</tip>
+
+<tip category="KDVI|General">
+<html>
+<p>...that KDVI now supports inverse search? You can click into your DVI file
+with the middle mouse button and your editor opens, loads the TeX file, and
+jumps to the proper line! <a href="help:/kdvi/inverse-search.html">The
+manual explains how to set up your editor for this.</a>
+</html>
+</tip>
+
+<tip category="KDVI|General">
+<html>
+<p>...that KDVI supports forward search? If you use Emacs or XEmacs, you can
+jump directly from the TeX file to the associated place in the DVI file.
+<a href="help:/kdvi/forward-search.html">The manual explains how to set up
+your editor for this.</a>
+</html>
+</tip>
+
+<tip category="KDVI|General">
+<html>
+<p>...that KDVI now offers full text search?
+</html>
+</tip>
+
+<tip category="KDVI|General">
+<html>
+<p>...that KDVI can save your DVI file as PostScript, PDF, and even plain text?
+</html>
+</tip>
diff --git a/kdvi/util.cpp b/kdvi/util.cpp
new file mode 100644
index 00000000..d25b7e03
--- /dev/null
+++ b/kdvi/util.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 1994 Paul Vojta. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * NOTE:
+ * xdvi is based on prior work as noted in the modification history, below.
+ */
+
+/*
+ * DVI previewer for X.
+ *
+ * Eric Cooper, CMU, September 1985.
+ *
+ * Code derived from dvi-imagen.c.
+ *
+ * Modification history:
+ * 1/1986 Modified for X.10 --Bob Scheifler, MIT LCS.
+ * 7/1988 Modified for X.11 --Mark Eichin, MIT
+ * 12/1988 Added 'R' option, toolkit, magnifying glass
+ * --Paul Vojta, UC Berkeley.
+ * 2/1989 Added tpic support --Jeffrey Lee, U of Toronto
+ * 4/1989 Modified for System V --Donald Richardson, Clarkson Univ.
+ * 3/1990 Added VMS support --Scott Allendorf, U of Iowa
+ * 7/1990 Added reflection mode --Michael Pak, Hebrew U of Jerusalem
+ * 1/1992 Added greyscale code --Till Brychcy, Techn. Univ. Muenchen
+ * and Lee Hetherington, MIT
+ * 4/1994 Added DPS support, bounding box
+ * --Ricardo Telichevesky
+ * and Luis Miguel Silveira, MIT RLE.
+ */
+
+#include <config.h>
+
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+
+#include "dviRenderer.h"
+#include "xdvi.h"
+
+
+
+/*
+ * General utility routines.
+ */
+
+/*
+ * Print error message and quit.
+ */
+
+void oops(QString message)
+{
+ kdError() << i18n("Fatal Error! ") << message << endl;
+
+ KMessageBox::error( NULL,
+ i18n("Fatal error.\n\n") +
+ message +
+ i18n("\n\n\
+This probably means that either you found a bug in KDVI,\n\
+or that the DVI file, or auxiliary files (such as font files, \n\
+or virtual font files) were really badly broken.\n\
+KDVI will abort after this message. If you believe that you \n\
+found a bug, or that KDVI should behave better in this situation\n\
+please report the problem."));
+ exit(1);
+}
+
+/*
+ *
+ * Read size bytes from the FILE fp, constructing them into a
+ * signed/unsigned integer.
+ *
+ */
+
+unsigned long num(FILE *fp, int size)
+{
+ register long x = 0;
+
+ while (size--) x = (x << 8) | one(fp);
+ return x;
+}
+
+long snum(FILE *fp, int size)
+{
+ register long x;
+
+#ifdef __STDC__
+ x = (signed char) getc(fp);
+#else
+ x = (unsigned char) getc(fp);
+ if (x & 0x80) x -= 0x100;
+#endif
+ while (--size) x = (x << 8) | one(fp);
+ return x;
+}
diff --git a/kdvi/vf.cpp b/kdvi/vf.cpp
new file mode 100644
index 00000000..36cad0ba
--- /dev/null
+++ b/kdvi/vf.cpp
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 1994 Paul Vojta. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <config.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "dvi.h"
+#include "dviRenderer.h"
+#include "fontpool.h"
+#include "xdvi.h"
+
+extern void oops(QString message);
+
+/***
+ *** VF font reading routines.
+ *** Public routine is read_index---because virtual characters are presumed
+ *** to be short, we read the whole virtual font in at once, instead of
+ *** faulting in characters as needed.
+ ***/
+
+#define LONG_CHAR 242
+
+/*
+ * These are parameters which determine whether macros are combined for
+ * storage allocation purposes. Small macros ( <= VF_PARM_1 bytes) are
+ * combined into chunks of size VF_PARM_2.
+ */
+
+#ifndef VF_PARM_1
+#define VF_PARM_1 20
+#endif
+#ifndef VF_PARM_2
+#define VF_PARM_2 256
+#endif
+
+/*
+ * The main routine
+ */
+
+void TeXFontDefinition::read_VF_index()
+{
+#ifdef DEBUG_FONTS
+ kdDebug(4300) << "font::read_VF_index()" << endl;
+#endif
+ FILE *VF_file = file;
+ unsigned char cmnd;
+ unsigned char *avail, *availend; /* available space for macros */
+
+ flags |= FONT_VIRTUAL;
+ set_char_p = &dviRenderer::set_vf_char;
+#ifdef DEBUG_FONTS
+ kdDebug(4300) << "TeXFontDefinition::read_VF_index: reading VF pixel file " << filename << endl;
+#endif
+ // Read preamble.
+ fseek(VF_file, (long) one(VF_file), 1); /* skip comment */
+ Q_UINT32 file_checksum = four(VF_file);
+
+ if (file_checksum && checksum && file_checksum != checksum)
+ kdError(4300) << i18n("Checksum mismatch") << "(dvi = " << checksum << "u, vf = " << file_checksum <<
+ "u)" << i18n(" in font file ") << filename << endl;
+ (void) four(VF_file); /* skip design size */
+
+ // Read the fonts.
+ first_font = NULL;
+ while ((cmnd = one(VF_file)) >= FNTDEF1 && cmnd <= FNTDEF4) {
+ int TeXnumber = num(VF_file, (int) cmnd - FNTDEF1 + 1);
+ Q_UINT32 checksum = four(VF_file);
+ Q_UINT32 scale = four(VF_file);
+ Q_UINT32 design = four(VF_file);
+ Q_UNUSED(design);
+ Q_UINT16 len = one(VF_file) + one(VF_file); /* sequence point in the middle */
+ char *fontname = new char[len + 1];
+ fread(fontname, sizeof(char), len, VF_file);
+ fontname[len] = '\0';
+
+#ifdef DEBUG_FONTS
+ kdDebug(4300) << "Virtual font defines subfont \"" << fontname << "\" scale=" << scale << " design=" << design << endl;
+#endif
+
+ // According to Knuth's documentation found in the web source code
+ // of the "vftovp" program (which seems to be the standard
+ // definition of virtual fonts), the "scale" is a fixed point
+ // number which describes extra enlargement that the virtual font
+ // imposes. One obtains the enlargement by dividing 2^20.
+ double enlargement_factor = double(scale)/(1<<20) * enlargement;
+
+ // TeXFontDefinition *newfontp = font_pool->appendx(fontname, checksum, (Q_UINT32)(scaled_size_in_DVI_units*enlargement_factor), enlargement_factor);
+ TeXFontDefinition *newfontp = font_pool->appendx(fontname, checksum, (Q_UINT32)((double(scale)/(1<<20))*scaled_size_in_DVI_units), enlargement_factor);
+
+ // Insert font in dictionary and make sure the dictionary is big
+ // enough.
+ if (vf_table.size()-2 <= vf_table.count())
+ // Not quite optimal. The size of the dictionary should be a
+ // prime. I don't care.
+ vf_table.resize(vf_table.size()*2);
+ vf_table.insert(TeXnumber, newfontp);
+
+ if (first_font == NULL)
+ first_font = newfontp;
+ }
+
+ // Prepare macro array.
+ macrotable = new macro[max_num_of_chars_in_font];
+ if (macrotable == 0) {
+ kdError() << i18n("Could not allocate memory for a macro table.") << endl;
+ exit(0);
+ }
+
+ // Read macros.
+ avail = availend = NULL;
+ for (; cmnd <= LONG_CHAR; cmnd = one(VF_file)) {
+ macro *m;
+ int len;
+ unsigned long cc;
+ long width;
+
+ if (cmnd == LONG_CHAR) { /* long form packet */
+ len = four(VF_file);
+ cc = four(VF_file);
+ width = four(VF_file);
+ if (cc >= 256) {
+ kdError() << i18n("Virtual character ") << cc << i18n(" in font ")
+ << fontname << i18n(" ignored.") << endl;
+ fseek(VF_file, (long) len, 1);
+ continue;
+ }
+ } else { /* short form packet */
+ len = cmnd;
+ cc = one(VF_file);
+ width = num(VF_file, 3);
+ }
+ m = &macrotable[cc];
+
+ m->dvi_advance_in_units_of_design_size_by_2e20 = width;
+ if (len > 0) {
+ if (len <= availend - avail) {
+ m->pos = avail;
+ avail += len;
+ } else {
+ m->free_me = true;
+ if (len <= VF_PARM_1) {
+ m->pos = avail = new unsigned char [VF_PARM_2];
+ availend = avail + VF_PARM_2;
+ avail += len;
+ } else
+ m->pos = new unsigned char[len];
+ }
+ fread((char *) m->pos, 1, len, VF_file);
+ m->end = m->pos + len;
+ }
+ }
+ if (cmnd != POST)
+ oops(i18n("Wrong command byte found in VF macro list: %1").arg(cmnd));
+
+ fclose (VF_file);
+ file = NULL;
+}
diff --git a/kdvi/xdvi.h b/kdvi/xdvi.h
new file mode 100644
index 00000000..0770cd8b
--- /dev/null
+++ b/kdvi/xdvi.h
@@ -0,0 +1,24 @@
+// -*- C++ -*-
+#ifndef _xdvi_h
+#define _xdvi_h
+
+#include <stdio.h>
+
+/*
+ * Written by Eric C. Cooper, CMU
+ */
+
+#define ROUNDUP(x,y) (((x)+(y)-1)/(y))
+
+extern unsigned long num (FILE *, int);
+extern long snum(FILE *, int);
+extern struct WindowRec mane, currwin;
+
+#define one(fp) ((unsigned char) getc(fp))
+#define sone(fp) ((long) one(fp))
+#define two(fp) num (fp, 2)
+#define stwo(fp) snum(fp, 2)
+#define four(fp) num (fp, 4)
+#define sfour(fp) snum(fp, 4)
+
+#endif /* _xdvi_h */
diff --git a/kfax/AUTHORS b/kfax/AUTHORS
new file mode 100644
index 00000000..88b4ef2b
--- /dev/null
+++ b/kfax/AUTHORS
@@ -0,0 +1,3 @@
+Bernd Johannes Wuebben
+wuebben@math.cornell.edu
+wuebben@kde.org
diff --git a/kfax/ChangeLog b/kfax/ChangeLog
new file mode 100644
index 00000000..39accef4
--- /dev/null
+++ b/kfax/ChangeLog
@@ -0,0 +1,28 @@
+1999-03-03 Harri Porten <porten@kde.org>
+
+ * viewfax.cpp: prefix getopt declarations with 'extern'. Bug reported
+ by Oliver Oster <olio@zait.uni-bremen.de>
+
+1999-02-08 Harri Porten <porten@kde.org>
+
+ * fixed segfault caused by infinite recursion in kfaxerror()
+
+Sun May 3 16:48:13 1998 Bernd Johannes Wuebben <wuebben@math.cornell.edu>
+
+ * fixed print dialog
+ adjusted layout for i18n
+
+Sun Oct 5 22:17:09 1997 Bernd Johannes Wuebben <wuebben@petit.cornell.edu>
+
+ * added support for printing all fax formats at all printer page
+ sizes.
+
+Sun Aug 3 09:55:52 1997 Bernd Johannes Wuebben <wuebben@petit.cornell.edu>
+
+ * Made kfax work with the new KToolBar etc.
+
+Thu Jul 24 20:44:33 1997 Bernd Johannes Wuebben <wuebben@petit.cornell.edu>
+
+ * made the necessary changes so that kfax will compile with
+ the new libs.
+
diff --git a/kfax/Makefile.am b/kfax/Makefile.am
new file mode 100644
index 00000000..fd3e478c
--- /dev/null
+++ b/kfax/Makefile.am
@@ -0,0 +1,32 @@
+AM_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+LDADD = $(LIB_KFILE) $(LIB_KDEPRINT) -lm
+INCLUDES = $(all_includes)
+
+####### Files
+noinst_HEADERS = kfax.h faxexpand.h options.h
+
+kfax_SOURCES = options.cpp kfax.cpp faxexpand.cpp faxinit.cpp faxinput.cpp \
+ viewfax.cpp kfax_printsettings.cpp
+
+METASOURCES = AUTO
+
+bin_PROGRAMS = kfax
+
+xdg_apps_DATA = kfax.desktop
+
+picsdir = $(kde_datadir)/kfax/pics
+pics_DATA = kfax.tif kfaxlogo.xpm
+
+rcdir = $(kde_datadir)/kfax
+rc_DATA = kfaxui.rc
+
+KDE_ICON = kfax
+
+EXTRA_DIST = $(xdg_apps_DATA) $(pics_DATA)
+
+messages: rc.cpp
+ $(XGETTEXT) $(kfax_SOURCES) -o $(podir)/kfax.pot
+
+####### Explicit dependencies
+
+
diff --git a/kfax/NOTES b/kfax/NOTES
new file mode 100644
index 00000000..9a3c70b6
--- /dev/null
+++ b/kfax/NOTES
@@ -0,0 +1,49 @@
+
+Drag and Drop
+Net Drag and Drop
+
+kfax can display all fax output modes of ghostscript:
+raw: fag3 faxg32d faxg4
+tiff: tiffg3 tiffg32d tiffg4
+
+By default raw fax files are interpreted as g3 files. If you want
+to display faxg3-2d and faxg4 files you have to specifiy this on
+the command line and in the case of raw g4 files also specify
+the height in scan lines of the fax if it differs from the
+default 2155.
+
+A raw file will have no pagignation information and will be displayed
+as a whole in the fax window.
+tiff files contain pagination information can be paged through in the
+fax window
+
+kfax can not display image file formats which are not related to
+faxing, such as an arbitrary tiff or gif file.
+
+
+How to create fax file that sendfax /mgetty can accept and send:
+gs -sDEVICE=faxg3 -sOutputFile=/tmp/fax.g3.%d yourdocument.ps
+
+Assume that you ps document yourdocumnet.ps contains three pages,
+this will produce fax.g3.1 fax.g3.2 fax.g3.3
+
+
+HylaFAX:
+http://info-sys.home.vix.com/flexfax/toc.html
+
+sendfax/mgetty:
+http://www.leo.org/~doering/mgetty/
+
+cat fax.g3 | g32pbm | pnmtops -noturn > output.ps
+
+
+
+How to print raw " no tiff " g3 fax data:
+
+
+
+fax2tiff -M viewfax.g3 -o viewfax.tiff
+(M for: Treat input data as having bits filled from most
+ significant bit (MSB) to most least bit (LSB))
+This is what I need on my intel machine, I would presume this
+might be different on a Sun station.
diff --git a/kfax/README b/kfax/README
new file mode 100644
index 00000000..23d3c6c2
--- /dev/null
+++ b/kfax/README
@@ -0,0 +1,34 @@
+KFax 0.3
+
+Added printing for g32 and g4, so that kfax can now print all fax formats.
+Added support for all pages sizes.
+
+Bernd
+wuebben@kde.org
+
+
+I am please to release KFax 0.2, the first public release of
+KFax - a fax file viewer for the KDE project.
+
+Please peruse the accompanying html documentation for more information
+about KFax
+
+Help wanted:
+============
+
+Much of my work was done "in vitro". Now it is time to go out into
+the wilderness and test KFax:
+
+I need people to send me faxes from all sorts of programs and machines
+in order to thoroughly test KFax and develop further ideas as to what needs
+to be implemented. If you own a fax modem or a fax machine and you would
+like to help, please write to me by email. I will then give you my phone
+number and we will agree on which fax program I will used for reception.
+You can then send me a fax from your favorite program or machine, stating
+what machine/program you used, from where you sent the fax, what
+the size of the fax is, the number of pages you transmitted etc.
+This would be very helpful. Thanks for your coorporation.
+
+thanks,
+Bernd Wuebben
+wuebben@kde.org
diff --git a/kfax/TODO b/kfax/TODO
new file mode 100644
index 00000000..2e9d8464
--- /dev/null
+++ b/kfax/TODO
@@ -0,0 +1,2 @@
+o Page Marking
+o Printing of only the Marked pages
diff --git a/kfax/examples/README b/kfax/examples/README
new file mode 100644
index 00000000..74631fe6
--- /dev/null
+++ b/kfax/examples/README
@@ -0,0 +1,22 @@
+If you have the kdeapps distributions, please also read README.kdeapps
+thanks,
+Bernd
+
+This directory contains a number of fax files which you can use to
+test and play with KFax:
+
+kde.g3 a group 3 raw fax file
+kde.g32d a group 3, 2-dim raw fax file
+kde.g4 a group 4 raw fax file
+
+Note: the g32d and g4 raw fax files will not display correctly
+ unless you change the default raw fax file format on the
+ Fax Options dialog.
+
+kdefaq.tiff.g3 a tiff group 3 encoded fax file
+kdefaq.tiff.g32d a tiff group 3, 2-dim, encoded fax file
+kdefaq.tiff.g4 a tiff group 4 encoded fax file
+
+Note that the tiff file format is the superiour format. Each
+of the above tiff fax files contains several pages.
+
diff --git a/kfax/examples/README.kdeapps b/kfax/examples/README.kdeapps
new file mode 100644
index 00000000..6664690a
--- /dev/null
+++ b/kfax/examples/README.kdeapps
@@ -0,0 +1,12 @@
+Note from the kdeapps maintainer:
+
+This directory used to contain several example fax files. Some of which are
+raw fax files others tiff fax files. Since I need to keep the kdeapps
+distributions small in size, I removed them with the permission of the author.
+You will still find all example files in the original kfax distribution
+at:
+
+ftp.kde.org//pub/kde/apps/graphics/
+
+Stephan Kulow <coolo@kde.org>
+
diff --git a/kfax/examples/kde.g3 b/kfax/examples/kde.g3
new file mode 100644
index 00000000..a419e9af
--- /dev/null
+++ b/kfax/examples/kde.g3
Binary files differ
diff --git a/kfax/examples/nasty.tiff b/kfax/examples/nasty.tiff
new file mode 100644
index 00000000..e9edd50c
--- /dev/null
+++ b/kfax/examples/nasty.tiff
Binary files differ
diff --git a/kfax/faxexpand.cpp b/kfax/faxexpand.cpp
new file mode 100644
index 00000000..93f1bc85
--- /dev/null
+++ b/kfax/faxexpand.cpp
@@ -0,0 +1,732 @@
+/* Expand one page of fax data
+ Copyright (C) 1990, 1995 Frank D. Cringle.
+
+This file is part of viewfax - g3/g4 fax processing software.
+
+viewfax 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 <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include "faxexpand.h"
+
+//Uncomment this for verbose debug output
+//#define DEBUG_FAX
+
+/* Note that NeedBits() only works for n <= 16 */
+#define NeedBits(n) do { \
+ if (BitsAvail < (n)) { \
+ BitAcc |= *sp++ << BitsAvail; \
+ BitsAvail += 16; \
+ } \
+} while (0)
+#define GetBits(n) (BitAcc & ((1<<(n))-1))
+#define ClrBits(n) do { \
+ BitAcc >>= (n); \
+ BitsAvail -= (n); \
+} while (0)
+
+#ifdef DEBUG_FAX
+#define DEBUG_SHOW putchar(BitAcc & (1 << t) ? '1' : '0')
+#define LOOKUP(wid,tab) do { \
+ int t; \
+ NeedBits(wid); \
+ TabEnt = tab + GetBits(wid); \
+ printf("%08lX/%d: %s%5d\t", BitAcc, BitsAvail, \
+ StateNames[TabEnt->State], TabEnt->Param); \
+ for (t = 0; t < TabEnt->Width; t++) \
+ DEBUG_SHOW; \
+ putchar('\n'); \
+ fflush(stdout); \
+ ClrBits(TabEnt->Width); \
+} while (0)
+
+#define SETVAL(x) do { \
+ *pa++ = RunLength + (x); \
+ printf("SETVAL: %d\t%d\n", RunLength + (x), a0); \
+ a0 += x; \
+ RunLength = 0; \
+} while (0)
+
+char *StateNames[] = {
+ "Null ",
+ "Pass ",
+ "Horiz ",
+ "V0 ",
+ "VR ",
+ "VL ",
+ "Ext ",
+ "TermW ",
+ "TermB ",
+ "MakeUpW",
+ "MakeUpB",
+ "MakeUp ",
+ "EOL ",
+};
+
+#else
+#define LOOKUP(wid,tab) do { \
+ NeedBits(wid); \
+ TabEnt = tab + GetBits(wid); \
+ ClrBits(TabEnt->Width); \
+} while (0)
+
+#define SETVAL(x) do { \
+ *pa++ = RunLength + (x); \
+ a0 += x; \
+ RunLength = 0; \
+} while (0)
+#endif
+
+#define dumpruns(runs) do { \
+ printf("-------------------- %d\n", LineNum); \
+ for (pa = runs, a0 = 0; a0 < lastx; a0 += *pa++) \
+ printf("%4d %d\n", a0, *pa); \
+} while (0)
+
+#define EndOfData(pn) (sp >= pn->data + pn->length/sizeof(*pn->data))
+
+/* This macro handles coding errors in G3 data.
+ We redefine it below for the G4 case */
+#define SKIP_EOL do { \
+ while (!EndOfData(pn)) { \
+ NeedBits(11); \
+ if (GetBits(11) == 0) \
+ break; \
+ ClrBits(1); \
+ } \
+ ClrBits(11); \
+ goto EOL; \
+} while (0)
+#define eol2lab EOL2:
+
+/* the line expanders are written as macros so that they can be reused
+ (twice each) but still have direct access to the local variables of
+ the "calling" function */
+#define expand1d() do { \
+ while (a0 < lastx) { \
+ int done = 0; \
+ while (!done) { /* white first */ \
+ LOOKUP(12, WhiteTable); \
+ switch (TabEnt->State) { \
+ case S_EOL: \
+ EOLcnt = 1; \
+ goto EOL; \
+ case S_TermW: \
+ SETVAL(TabEnt->Param); \
+ done = 1; \
+ break; \
+ case S_MakeUpW: \
+ case S_MakeUp: \
+ a0 += TabEnt->Param; \
+ RunLength += TabEnt->Param; \
+ break; \
+ case S_Ext: \
+ unexpected("Extension code", LineNum); \
+ SKIP_EOL; \
+ break; \
+ default: \
+ unexpected("WhiteTable", LineNum); \
+ SKIP_EOL; \
+ break; \
+ } \
+ } \
+ done = a0 >= lastx; \
+ while (!done) { /* then black */ \
+ LOOKUP(13, BlackTable); \
+ switch (TabEnt->State) { \
+ case S_EOL: \
+ EOLcnt = 1; \
+ goto EOL; \
+ case S_TermB: \
+ SETVAL(TabEnt->Param); \
+ done = 1; \
+ break; \
+ case S_MakeUpB: \
+ case S_MakeUp: \
+ a0 += TabEnt->Param; \
+ RunLength += TabEnt->Param; \
+ break; \
+ case S_Ext: \
+ unexpected("Extension code", LineNum); \
+ SKIP_EOL; \
+ break; \
+ default: \
+ unexpected("BlackTable", LineNum); \
+ SKIP_EOL; \
+ break; \
+ } \
+ } \
+ } \
+ EOL: ; \
+} while (0)
+
+#define CHECK_b1 do { \
+ if (pa != thisrun) while (b1 <= a0 && b1 < lastx) { \
+ b1 += pb[0] + pb[1]; \
+ pb += 2; \
+ } \
+} while (0)
+
+#define expand2d(eolab) do { \
+ while (a0 < lastx) { \
+ LOOKUP(7, MainTable); \
+ switch (TabEnt->State) { \
+ case S_Pass: \
+ CHECK_b1; \
+ b1 += *pb++; \
+ RunLength += b1 - a0; \
+ a0 = b1; \
+ b1 += *pb++; \
+ break; \
+ case S_Horiz: \
+ if ((pa-run0)&1) { \
+ int done = 0; \
+ while (!done) { /* black first */ \
+ LOOKUP(13, BlackTable); \
+ switch (TabEnt->State) { \
+ case S_TermB: \
+ SETVAL(TabEnt->Param); \
+ done = 1; \
+ break; \
+ case S_MakeUpB: \
+ case S_MakeUp: \
+ a0 += TabEnt->Param; \
+ RunLength += TabEnt->Param; \
+ break; \
+ default: \
+ unexpected("BlackTable", LineNum); \
+ SKIP_EOL; \
+ break; \
+ } \
+ } \
+ done = 0; \
+ while (!done) { /* then white */ \
+ LOOKUP(12, WhiteTable); \
+ switch (TabEnt->State) { \
+ case S_TermW: \
+ SETVAL(TabEnt->Param); \
+ done = 1; \
+ break; \
+ case S_MakeUpW: \
+ case S_MakeUp: \
+ a0 += TabEnt->Param; \
+ RunLength += TabEnt->Param; \
+ break; \
+ default: \
+ unexpected("WhiteTable", LineNum); \
+ SKIP_EOL; \
+ break; \
+ } \
+ } \
+ } \
+ else { \
+ int done = 0; \
+ while (!done) { /* white first */ \
+ LOOKUP(12, WhiteTable); \
+ switch (TabEnt->State) { \
+ case S_TermW: \
+ SETVAL(TabEnt->Param); \
+ done = 1; \
+ break; \
+ case S_MakeUpW: \
+ case S_MakeUp: \
+ a0 += TabEnt->Param; \
+ RunLength += TabEnt->Param; \
+ break; \
+ default: \
+ unexpected("WhiteTable", LineNum); \
+ SKIP_EOL; \
+ break; \
+ } \
+ } \
+ done = 0; \
+ while (!done) { /* then black */ \
+ LOOKUP(13, BlackTable); \
+ switch (TabEnt->State) { \
+ case S_TermB: \
+ SETVAL(TabEnt->Param); \
+ done = 1; \
+ break; \
+ case S_MakeUpB: \
+ case S_MakeUp: \
+ a0 += TabEnt->Param; \
+ RunLength += TabEnt->Param; \
+ break; \
+ default: \
+ unexpected("BlackTable", LineNum); \
+ SKIP_EOL; \
+ break; \
+ } \
+ } \
+ } \
+ CHECK_b1; \
+ break; \
+ case S_V0: \
+ CHECK_b1; \
+ SETVAL(b1 - a0); \
+ b1 += *pb++; \
+ break; \
+ case S_VR: \
+ CHECK_b1; \
+ SETVAL(b1 - a0 + TabEnt->Param); \
+ b1 += *pb++; \
+ break; \
+ case S_VL: \
+ CHECK_b1; \
+ SETVAL(b1 - a0 - TabEnt->Param); \
+ b1 -= *--pb; \
+ break; \
+ case S_Ext: \
+ *pa++ = lastx - a0; \
+ if (verbose) \
+ fprintf(stderr, "Line %d: extension code\n", LineNum); \
+ SKIP_EOL; \
+ break; \
+ case S_EOL: \
+ *pa++ = lastx - a0; \
+ NeedBits(4); \
+ if (GetBits(4) && verbose) /* already seen 7 zeros */ \
+ fprintf(stderr, "Line %d: Bad EOL\n", LineNum); \
+ ClrBits(4); \
+ EOLcnt = 1; \
+ goto eolab; \
+ break; \
+ default: \
+ unexpected("MainTable", LineNum); \
+ SKIP_EOL; \
+ break; \
+ } \
+ } \
+ if (RunLength) { \
+ if (RunLength + a0 < lastx) { \
+ /* expect a final V0 */ \
+ NeedBits(1); \
+ if (!GetBits(1)) { \
+ unexpected("MainTable", LineNum); \
+ SKIP_EOL; \
+ } \
+ ClrBits(1); \
+ } \
+ SETVAL(0); \
+ } \
+ eol2lab ; \
+} while (0)
+
+static void
+unexpected(const char *what, int LineNum)
+{
+ if (verbose)
+ fprintf(stderr, "Line %d: Unexpected state in %s\n",
+ LineNum, what);
+}
+
+/* Expand tiff modified huffman data (g3-1d without EOLs) */
+void
+MHexpand(struct pagenode *pn, drawfunc df)
+{
+ int a0; /* reference element */
+ int lastx = pn->width; /* copy line width to register */
+ t32bits BitAcc; /* bit accumulator */
+ int BitsAvail; /* # valid bits in BitAcc */
+ int RunLength; /* Length of current run */
+ t16bits *sp; /* pointer into compressed data */
+ pixnum *pa; /* pointer into new line */
+ int EOLcnt; /* number of consecutive EOLs */
+ int LineNum; /* line number */
+ pixnum *runs; /* list of run lengths */
+ struct tabent *TabEnt;
+
+ sp = pn->data;
+ BitAcc = 0;
+ BitsAvail = 0;
+ lastx = pn->width;
+ runs = (pixnum *) xmalloc(lastx * sizeof(pixnum));
+ for (LineNum = 0; LineNum < pn->rowsperstrip; ) {
+#ifdef DEBUG_FAX
+ printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail);
+ printf("-------------------- %d\n", LineNum);
+ fflush(stdout);
+#endif
+ RunLength = 0;
+ pa = runs;
+ a0 = 0;
+ EOLcnt = 0;
+ if (BitsAvail & 7) /* skip to byte boundary */
+ ClrBits(BitsAvail & 7);
+ expand1d();
+ if (RunLength)
+ SETVAL(0);
+ if (a0 != lastx) {
+ if (verbose)
+ fprintf(stderr, "Line %d: length is %d (expected %d)\n", LineNum, a0, lastx);
+ while (a0 > lastx)
+ a0 -= *--pa;
+ if (a0 < lastx) {
+ if ((pa - runs) & 1)
+ SETVAL(0);
+ SETVAL(lastx - a0);
+ }
+ }
+ (*df)(runs, LineNum++, pn);
+ }
+ free(runs);
+}
+
+/* Expand group-3 1-dimensional data */
+void
+g31expand(struct pagenode *pn, drawfunc df)
+{
+ int a0; /* reference element */
+ int lastx = pn->width; /* copy line width to register */
+ t32bits BitAcc; /* bit accumulator */
+ int BitsAvail; /* # valid bits in BitAcc */
+ int RunLength; /* Length of current run */
+ t16bits *sp; /* pointer into compressed data */
+ pixnum *pa; /* pointer into new line */
+ int EOLcnt; /* number of consecutive EOLs */
+ int LineNum; /* line number */
+ pixnum *runs; /* list of run lengths */
+ struct tabent *TabEnt;
+
+ sp = pn->data;
+ BitAcc = 0;
+ BitsAvail = 0;
+ lastx = pn->width;
+ runs = (pixnum *) xmalloc(lastx * sizeof(pixnum));
+ EOLcnt = 0;
+ for (LineNum = 0; LineNum < pn->rowsperstrip; ) {
+#ifdef DEBUG_FAX
+ printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail);
+ printf("-------------------- %d\n", LineNum);
+ fflush(stdout);
+#endif
+ if (EOLcnt == 0)
+ while (!EndOfData(pn)) {
+ /* skip over garbage after a coding error */
+ NeedBits(11);
+ if (GetBits(11) == 0)
+ break;
+ ClrBits(1);
+ }
+ for (EOLcnt = 1; !EndOfData(pn); EOLcnt++) {
+ /* we have seen 11 zeros, which implies EOL,
+ skip possible fill bits too */
+ while (1) {
+ NeedBits(8);
+ if (GetBits(8))
+ break;
+ ClrBits(8);
+ }
+ while (GetBits(1) == 0)
+ ClrBits(1);
+ ClrBits(1); /* the eol flag */
+ NeedBits(11);
+ if (GetBits(11))
+ break;
+ ClrBits(11);
+ }
+ if (EOLcnt > 1 && EOLcnt != 6 && verbose)
+ fprintf(stderr, "Line %d: bad RTC (%d EOLs)\n", LineNum, EOLcnt);
+ if (EOLcnt >= 6 || EndOfData(pn)) {
+ free(runs);
+ return;
+ }
+ RunLength = 0;
+ pa = runs;
+ a0 = 0;
+ EOLcnt = 0;
+ expand1d();
+ if (RunLength)
+ SETVAL(0);
+ if (a0 != lastx) {
+ if (verbose)
+ fprintf(stderr, "Line %d: length is %d (expected %d)\n", LineNum, a0, lastx);
+ while (a0 > lastx)
+ a0 -= *--pa;
+ if (a0 < lastx) {
+ if ((pa - runs) & 1)
+ SETVAL(0);
+ SETVAL(lastx - a0);
+ }
+ }
+ (*df)(runs, LineNum++, pn);
+ }
+ free(runs);
+}
+
+/* Expand group-3 2-dimensional data */
+void
+g32expand(struct pagenode *pn, drawfunc df)
+{
+ int RunLength; /* Length of current run */
+ int a0; /* reference element */
+ int b1; /* next change on previous line */
+ int lastx = pn->width; /* copy line width to register */
+ pixnum *run0, *run1; /* run length arrays */
+ pixnum *thisrun, *pa, *pb; /* pointers into runs */
+ t16bits *sp; /* pointer into compressed data */
+ t32bits BitAcc; /* bit accumulator */
+ int BitsAvail; /* # valid bits in BitAcc */
+ int EOLcnt; /* number of consecutive EOLs */
+ int refline = 0; /* 1D encoded reference line */
+ int LineNum; /* line number */
+ struct tabent *TabEnt;
+
+ sp = pn->data;
+ BitAcc = 0;
+ BitsAvail = 0;
+ /* allocate space for 2 runlength arrays */
+ run0 = (pixnum *) xmalloc(2 * ((lastx+5)&~1) * sizeof(pixnum));
+ run1 = run0 + ((lastx+5)&~1);
+ run1[0] = lastx;
+ run1[1] = 0;
+ EOLcnt = 0;
+ for (LineNum = 0; LineNum < pn->rowsperstrip; ) {
+#ifdef DEBUG_FAX
+ printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail);
+ printf("-------------------- %d\n", LineNum);
+ fflush(stdout);
+#endif
+ if (EOLcnt == 0)
+ while (!EndOfData(pn)) {
+ /* skip over garbage after a coding error */
+ NeedBits(11);
+ if (GetBits(11) == 0)
+ break;
+ ClrBits(1);
+ }
+ for (EOLcnt = 1; !EndOfData(pn); EOLcnt++) {
+ /* we have seen 11 zeros, which implies EOL,
+ skip possible fill bits too */
+ while (1) {
+ NeedBits(8);
+ if (GetBits(8))
+ break;
+ ClrBits(8);
+ }
+ while (GetBits(1) == 0)
+ ClrBits(1);
+ ClrBits(1); /* the eol flag */
+ NeedBits(12);
+ refline = GetBits(1); /* 1D / 2D flag */
+ ClrBits(1);
+ if (GetBits(11))
+ break;
+ ClrBits(11);
+ }
+ if (EOLcnt > 1 && EOLcnt != 6 && verbose)
+ fprintf(stderr, "Line %d: bad RTC (%d EOLs)\n", LineNum, EOLcnt);
+ if (EOLcnt >= 6 || EndOfData(pn)) {
+ free(run0);
+ return;
+ }
+ if (LineNum == 0 && refline == 0 && verbose)
+ fprintf(stderr, "First line is 2-D encoded\n");
+ RunLength = 0;
+ if (LineNum & 1) {
+ pa = run1;
+ pb = run0;
+ }
+ else {
+ pa = run0;
+ pb = run1;
+ }
+ thisrun = pa;
+ EOLcnt = 0;
+ a0 = 0;
+ b1 = *pb++;
+
+ if (refline) {
+ expand1d();
+ }
+ else {
+ expand2d(EOL2);
+ }
+ if (RunLength)
+ SETVAL(0);
+ if (a0 != lastx) {
+ if (verbose)
+ fprintf(stderr, "Line %d: length is %d (expected %d)\n", LineNum, a0, lastx);
+ while (a0 > lastx)
+ a0 -= *--pa;
+ if (a0 < lastx) {
+ if ((pa - run0) & 1)
+ SETVAL(0);
+ SETVAL(lastx - a0);
+ }
+ }
+ SETVAL(0); /* imaginary change at end of line for reference */
+ (*df)(thisrun, LineNum++, pn);
+ }
+ free(run0);
+}
+
+/* Redefine the "skip to eol" macro. We cannot recover from coding
+ errors in G4 data */
+#undef SKIP_EOL
+#undef eol2lab
+#define SKIP_EOL do { \
+ if (verbose) \
+ fprintf(stderr, "Line %d: G4 coding error\n", LineNum); \
+ free(run0); \
+ return; \
+} while (0)
+#define eol2lab
+
+/* Expand group-4 data */
+void
+g4expand(struct pagenode *pn, drawfunc df)
+{
+ int RunLength; /* Length of current run */
+ int a0; /* reference element */
+ int b1; /* next change on previous line */
+ int lastx = pn->width; /* copy line width to register */
+ pixnum *run0, *run1; /* run length arrays */
+ pixnum *thisrun, *pa, *pb; /* pointers into runs */
+ t16bits *sp; /* pointer into compressed data */
+ t32bits BitAcc; /* bit accumulator */
+ int BitsAvail; /* # valid bits in BitAcc */
+ int LineNum; /* line number */
+ int EOLcnt;
+ struct tabent *TabEnt;
+
+ sp = pn->data;
+ BitAcc = 0;
+ BitsAvail = 0;
+ /* allocate space for 2 runlength arrays */
+ run0 = (pixnum *) xmalloc(2 * ((lastx+5)&~1) * sizeof(pixnum));
+ run1 = run0 + ((lastx+5)&~1);
+ run1[0] = lastx; /* initial reference line */
+ run1[1] = 0;
+
+ for (LineNum = 0; LineNum < pn->rowsperstrip; ) {
+#ifdef DEBUG_FAX
+ printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail);
+ printf("-------------------- %d\n", LineNum);
+ fflush(stdout);
+#endif
+ RunLength = 0;
+ if (LineNum & 1) {
+ pa = run1;
+ pb = run0;
+ }
+ else {
+ pa = run0;
+ pb = run1;
+ }
+ thisrun = pa;
+ a0 = 0;
+ b1 = *pb++;
+ expand2d(EOFB);
+ if (a0 < lastx) {
+ if ((pa - run0) & 1)
+ SETVAL(0);
+ SETVAL(lastx - a0);
+ }
+ SETVAL(0); /* imaginary change at end of line for reference */
+ (*df)(thisrun, LineNum++, pn);
+ continue;
+ EOFB:
+ NeedBits(13);
+ if (GetBits(13) != 0x1001 && verbose)
+ fputs("Bad RTC\n", stderr);
+ break;
+ }
+ free(run0);
+}
+
+static unsigned char zerotab[256] = {
+ 0x88, 0x07, 0x16, 0x06, 0x25, 0x05, 0x15, 0x05,
+ 0x34, 0x04, 0x14, 0x04, 0x24, 0x04, 0x14, 0x04,
+ 0x43, 0x03, 0x13, 0x03, 0x23, 0x03, 0x13, 0x03,
+ 0x33, 0x03, 0x13, 0x03, 0x23, 0x03, 0x13, 0x03,
+ 0x52, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02,
+ 0x32, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02,
+ 0x42, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02,
+ 0x32, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02,
+ 0x61, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
+ 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
+ 0x41, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
+ 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
+ 0x51, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
+ 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
+ 0x41, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
+ 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
+ 0x70, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x50, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x60, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x50, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00
+};
+
+#define check(v) do { \
+ prezeros = zerotab[v]; \
+ postzeros = prezeros & 15; \
+ prezeros >>= 4; \
+ if (prezeros == 8) { \
+ zeros += 8; \
+ continue; \
+ } \
+ if (zeros + prezeros < 11) { \
+ empty = 0; \
+ zeros = postzeros; \
+ continue; \
+ } \
+ zeros = postzeros; \
+ if (empty) \
+ EOLcnt++; \
+ lines++; \
+ empty = 1; \
+} while (0)
+
+/* count fax lines */
+int
+G3count(struct pagenode *pn, int twoD)
+{
+ t16bits *p = pn->data;
+ t16bits *end = p + pn->length/sizeof(*p);
+ int lines = 0; /* lines seen so far */
+ int zeros = 0; /* number of consecutive zero bits seen */
+ int EOLcnt = 0; /* number of consecutive EOLs seen */
+ int empty = 1; /* empty line */
+ int prezeros, postzeros;
+
+ while (p < end && EOLcnt < 6) {
+ t16bits bits = *p++;
+ check(bits&255);
+ if (twoD && (prezeros + postzeros == 7)) {
+ if (postzeros || ((bits & 0x100) == 0))
+ zeros--;
+ }
+ check(bits>>8);
+ if (twoD && (prezeros + postzeros == 7)) {
+ if (postzeros || ((p < end) && ((*p & 1) == 0)))
+ zeros--;
+ }
+ }
+ return lines - EOLcnt; /* don't count trailing EOLs */
+}
diff --git a/kfax/faxexpand.h b/kfax/faxexpand.h
new file mode 100644
index 00000000..a1be736f
--- /dev/null
+++ b/kfax/faxexpand.h
@@ -0,0 +1,160 @@
+/* Include file for fax routines
+ Copyright (C) 1990, 1995 Frank D. Cringle.
+
+This file is part of viewfax - g3/g4 fax processing software.
+
+viewfax 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 _faxexpand_h_
+#define _faxexpand_h_
+
+#include <limits.h>
+
+#if ULONG_MAX == 4294967295UL
+typedef unsigned long t32bits;
+#elif UINT_MAX == 4294967295UL
+typedef unsigned int t32bits;
+#else
+#error need a 32-bit unsigned type
+/* if you expirence the above error, and live to tell about it,
+ add an #elif case for your architecture
+ and tell wuebben@math.cornell.edu , wuebben@kde.org about it */
+#endif
+
+#if USHRT_MAX == 65535
+typedef unsigned short t16bits;
+#elif UINT_MAX == 65535
+typedef unsigned int t16bits;
+#else
+#error need a 16-bit unsigned type
+/* if you experience the above error, and live to tell about it,
+ add an #elif case for your architecture
+ and tell fdc@cliwe.ping.de about it */
+#endif
+typedef t16bits pixnum;
+
+struct pagenode;
+
+/* drawfunc() points to a function which processes a line of the
+ expanded image described as a list of run lengths.
+ run is the base of an array of lengths, starting with a
+ (possibly empty) white run for line number linenum.
+ pn points to the page descriptor */
+typedef void (*drawfunc)(pixnum *run, int linenum, struct pagenode *pn);
+
+struct strip { /* tiff strip descriptor */
+ off_t offset; /* offset in file */
+ off_t size; /* size of this strip */
+};
+
+
+/* defines for the pagenode member: type */
+#define FAX_TIFF 1
+#define FAX_RAW 2
+
+struct pagenode { /* compressed page descriptor */
+ struct pagenode *prev, *next; /* list links */
+ char *name; /* basename of file */
+ char *pathname; /* full name of file */
+ int nstrips; /* number of strips */
+ int rowsperstrip; /* number of rows per strip */
+ int stripnum; /* current strip while expanding */
+ struct strip *strips; /* array of strips containing fax data in file */
+ t16bits *data; /* in-memory copy of strip */
+ size_t length; /* length of data */
+ pixnum width; /* width of page in pixels */
+ pixnum height; /* height of page in lines */
+ int inverse; /* black <=> white */
+ int lsbfirst; /* bit order is lsb first */
+ int type; /* Bernd: tiff vs no tiff*/
+ int orient; /* orientation - upsidedown, landscape, mirrored */
+ int vres; /* vertical resolution: 1 = fine */
+ int dpiX,dpiY; /* DPI horz/vert */
+ void (*expander)(struct pagenode *, drawfunc);
+ void *extra; /* used for Ximage */
+};
+extern struct pagenode *firstpage, *lastpage, *thispage,* auxpage;
+extern struct pagenode defaultpage;
+
+/* page orientation flags */
+#define TURN_U 1
+#define TURN_L 2
+#define TURN_M 4
+
+extern const char *ProgName;
+
+/* fsm state codes */
+#define S_Null 0
+#define S_Pass 1
+#define S_Horiz 2
+#define S_V0 3
+#define S_VR 4
+#define S_VL 5
+#define S_Ext 6
+#define S_TermW 7
+#define S_TermB 8
+#define S_MakeUpW 9
+#define S_MakeUpB 10
+#define S_MakeUp 11
+#define S_EOL 12
+
+/* state table entry */
+struct tabent {
+ unsigned char State;
+ unsigned char Width; /* width of code in bits */
+ pixnum Param; /* run length */
+};
+
+extern struct tabent MainTable[]; /* 2-D state table */
+extern struct tabent WhiteTable[]; /* White run lengths */
+extern struct tabent BlackTable[]; /* Black run lengths */
+
+extern int verbose;
+
+void MHexpand(struct pagenode *pn, drawfunc df);
+void g31expand(struct pagenode *pn, drawfunc df);
+void g32expand(struct pagenode *pn, drawfunc df);
+void g4expand(struct pagenode *pn, drawfunc df);
+
+unsigned char * getstrip(struct pagenode *pn, int strip);
+struct pagenode *notefile(const char *name);
+int notetiff(const char *name);
+
+/* initialise code tables */
+extern void faxinit(void);
+/* count lines in image */
+extern int G3count(struct pagenode *pn, int twoD);
+
+/* get memory or abort if none available */
+extern char *xmalloc(unsigned int size);
+
+#ifdef __linux__
+#define _HAVE_USLEEP
+#endif
+
+#if defined(BSD) || defined(__FreeBSD__) || defined(_BSD_SOURCE)
+#define _HAVE_USLEEP
+#ifndef rindex
+#define rindex strrchr
+#endif
+#ifndef bcmp
+#define memcmp bcmp
+#endif
+#define memclr(p,n) bzero(p,n)
+#else /* not BSD */
+#define memclr(p,n) memset(p,0,n)
+#endif
+
+#endif
diff --git a/kfax/faxinit.cpp b/kfax/faxinit.cpp
new file mode 100644
index 00000000..62ee0569
--- /dev/null
+++ b/kfax/faxinit.cpp
@@ -0,0 +1,337 @@
+/* Initialise fax decoder tables
+ Copyright (C) 1990, 1995 Frank D. Cringle.
+
+This file is part of viewfax - g3/g4 fax processing software.
+
+viewfax 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 <sys/types.h>
+#include "faxexpand.h"
+
+struct tabent MainTable[128];
+struct tabent WhiteTable[4096];
+struct tabent BlackTable[8192];
+
+struct proto {
+ t16bits code; /* right justified, lsb-first, zero filled */
+ t16bits val; /* (pixel count)<<4 + code width */
+};
+
+static struct proto Pass[] = {
+{ 0x0008, 4 },
+{ 0, 0 }
+};
+
+static struct proto Horiz[] = {
+{ 0x0004, 3 },
+{ 0, 0 }
+};
+
+static struct proto V0[] = {
+{ 0x0001, 1 },
+{ 0, 0 }
+};
+
+static struct proto VR[] = {
+{ 0x0006, (1<<4)+3 },
+{ 0x0030, (2<<4)+6 },
+{ 0x0060, (3<<4)+7 },
+{ 0, 0 }
+};
+
+static struct proto VL[] = {
+{ 0x0002, (1<<4)+3 },
+{ 0x0010, (2<<4)+6 },
+{ 0x0020, (3<<4)+7 },
+{ 0, 0 }
+};
+
+static struct proto ExtV[] = {
+{ 0x0040, 7 },
+{ 0, 0 }
+};
+
+static struct proto EOLV[] = {
+{ 0x0000, 7 },
+{ 0, 0 }
+};
+
+static struct proto MakeUpW[] = {
+{ 0x001b, 1029 },
+{ 0x0009, 2053 },
+{ 0x003a, 3078 },
+{ 0x0076, 4103 },
+{ 0x006c, 5128 },
+{ 0x00ec, 6152 },
+{ 0x0026, 7176 },
+{ 0x00a6, 8200 },
+{ 0x0016, 9224 },
+{ 0x00e6, 10248 },
+{ 0x0066, 11273 },
+{ 0x0166, 12297 },
+{ 0x0096, 13321 },
+{ 0x0196, 14345 },
+{ 0x0056, 15369 },
+{ 0x0156, 16393 },
+{ 0x00d6, 17417 },
+{ 0x01d6, 18441 },
+{ 0x0036, 19465 },
+{ 0x0136, 20489 },
+{ 0x00b6, 21513 },
+{ 0x01b6, 22537 },
+{ 0x0032, 23561 },
+{ 0x0132, 24585 },
+{ 0x00b2, 25609 },
+{ 0x0006, 26630 },
+{ 0x01b2, 27657 },
+{ 0, 0 }
+};
+
+static struct proto MakeUpB[] = {
+{ 0x03c0, 1034 },
+{ 0x0130, 2060 },
+{ 0x0930, 3084 },
+{ 0x0da0, 4108 },
+{ 0x0cc0, 5132 },
+{ 0x02c0, 6156 },
+{ 0x0ac0, 7180 },
+{ 0x06c0, 8205 },
+{ 0x16c0, 9229 },
+{ 0x0a40, 10253 },
+{ 0x1a40, 11277 },
+{ 0x0640, 12301 },
+{ 0x1640, 13325 },
+{ 0x09c0, 14349 },
+{ 0x19c0, 15373 },
+{ 0x05c0, 16397 },
+{ 0x15c0, 17421 },
+{ 0x0dc0, 18445 },
+{ 0x1dc0, 19469 },
+{ 0x0940, 20493 },
+{ 0x1940, 21517 },
+{ 0x0540, 22541 },
+{ 0x1540, 23565 },
+{ 0x0b40, 24589 },
+{ 0x1b40, 25613 },
+{ 0x04c0, 26637 },
+{ 0x14c0, 27661 },
+{ 0, 0 }
+};
+
+static struct proto MakeUp[] = {
+{ 0x0080, 28683 },
+{ 0x0180, 29707 },
+{ 0x0580, 30731 },
+{ 0x0480, 31756 },
+{ 0x0c80, 32780 },
+{ 0x0280, 33804 },
+{ 0x0a80, 34828 },
+{ 0x0680, 35852 },
+{ 0x0e80, 36876 },
+{ 0x0380, 37900 },
+{ 0x0b80, 38924 },
+{ 0x0780, 39948 },
+{ 0x0f80, 40972 },
+{ 0, 0 }
+};
+
+static struct proto TermW[] = {
+{ 0x00ac, 8 },
+{ 0x0038, 22 },
+{ 0x000e, 36 },
+{ 0x0001, 52 },
+{ 0x000d, 68 },
+{ 0x0003, 84 },
+{ 0x0007, 100 },
+{ 0x000f, 116 },
+{ 0x0019, 133 },
+{ 0x0005, 149 },
+{ 0x001c, 165 },
+{ 0x0002, 181 },
+{ 0x0004, 198 },
+{ 0x0030, 214 },
+{ 0x000b, 230 },
+{ 0x002b, 246 },
+{ 0x0015, 262 },
+{ 0x0035, 278 },
+{ 0x0072, 295 },
+{ 0x0018, 311 },
+{ 0x0008, 327 },
+{ 0x0074, 343 },
+{ 0x0060, 359 },
+{ 0x0010, 375 },
+{ 0x000a, 391 },
+{ 0x006a, 407 },
+{ 0x0064, 423 },
+{ 0x0012, 439 },
+{ 0x000c, 455 },
+{ 0x0040, 472 },
+{ 0x00c0, 488 },
+{ 0x0058, 504 },
+{ 0x00d8, 520 },
+{ 0x0048, 536 },
+{ 0x00c8, 552 },
+{ 0x0028, 568 },
+{ 0x00a8, 584 },
+{ 0x0068, 600 },
+{ 0x00e8, 616 },
+{ 0x0014, 632 },
+{ 0x0094, 648 },
+{ 0x0054, 664 },
+{ 0x00d4, 680 },
+{ 0x0034, 696 },
+{ 0x00b4, 712 },
+{ 0x0020, 728 },
+{ 0x00a0, 744 },
+{ 0x0050, 760 },
+{ 0x00d0, 776 },
+{ 0x004a, 792 },
+{ 0x00ca, 808 },
+{ 0x002a, 824 },
+{ 0x00aa, 840 },
+{ 0x0024, 856 },
+{ 0x00a4, 872 },
+{ 0x001a, 888 },
+{ 0x009a, 904 },
+{ 0x005a, 920 },
+{ 0x00da, 936 },
+{ 0x0052, 952 },
+{ 0x00d2, 968 },
+{ 0x004c, 984 },
+{ 0x00cc, 1000 },
+{ 0x002c, 1016 },
+{ 0, 0 }
+};
+
+static struct proto TermB[] = {
+{ 0x03b0, 10 },
+{ 0x0002, 19 },
+{ 0x0003, 34 },
+{ 0x0001, 50 },
+{ 0x0006, 67 },
+{ 0x000c, 84 },
+{ 0x0004, 100 },
+{ 0x0018, 117 },
+{ 0x0028, 134 },
+{ 0x0008, 150 },
+{ 0x0010, 167 },
+{ 0x0050, 183 },
+{ 0x0070, 199 },
+{ 0x0020, 216 },
+{ 0x00e0, 232 },
+{ 0x0030, 249 },
+{ 0x03a0, 266 },
+{ 0x0060, 282 },
+{ 0x0040, 298 },
+{ 0x0730, 315 },
+{ 0x00b0, 331 },
+{ 0x01b0, 347 },
+{ 0x0760, 363 },
+{ 0x00a0, 379 },
+{ 0x0740, 395 },
+{ 0x00c0, 411 },
+{ 0x0530, 428 },
+{ 0x0d30, 444 },
+{ 0x0330, 460 },
+{ 0x0b30, 476 },
+{ 0x0160, 492 },
+{ 0x0960, 508 },
+{ 0x0560, 524 },
+{ 0x0d60, 540 },
+{ 0x04b0, 556 },
+{ 0x0cb0, 572 },
+{ 0x02b0, 588 },
+{ 0x0ab0, 604 },
+{ 0x06b0, 620 },
+{ 0x0eb0, 636 },
+{ 0x0360, 652 },
+{ 0x0b60, 668 },
+{ 0x05b0, 684 },
+{ 0x0db0, 700 },
+{ 0x02a0, 716 },
+{ 0x0aa0, 732 },
+{ 0x06a0, 748 },
+{ 0x0ea0, 764 },
+{ 0x0260, 780 },
+{ 0x0a60, 796 },
+{ 0x04a0, 812 },
+{ 0x0ca0, 828 },
+{ 0x0240, 844 },
+{ 0x0ec0, 860 },
+{ 0x01c0, 876 },
+{ 0x0e40, 892 },
+{ 0x0140, 908 },
+{ 0x01a0, 924 },
+{ 0x09a0, 940 },
+{ 0x0d40, 956 },
+{ 0x0340, 972 },
+{ 0x05a0, 988 },
+{ 0x0660, 1004 },
+{ 0x0e60, 1020 },
+{ 0, 0 }
+};
+
+static struct proto ExtH[] = {
+{ 0x0100, 9 },
+{ 0, 0 }
+};
+
+static struct proto EOLH[] = {
+{ 0x0000, 11 },
+{ 0, 0 }
+};
+
+static void
+FillTable(struct tabent *T, int Size, struct proto *P, int State)
+{
+ int limit = 1 << Size;
+
+ while (P->val) {
+ int width = P->val & 15;
+ int param = P->val >> 4;
+ int incr = 1 << width;
+ int code;
+ for (code = P->code; code < limit; code += incr) {
+ struct tabent *E = T+code;
+ E->State = State;
+ E->Width = width;
+ E->Param = param;
+ }
+ P++;
+ }
+}
+
+/* initialise the huffman code tables */
+void
+faxinit(void)
+{
+ FillTable(MainTable, 7, Pass, S_Pass);
+ FillTable(MainTable, 7, Horiz, S_Horiz);
+ FillTable(MainTable, 7, V0, S_V0);
+ FillTable(MainTable, 7, VR, S_VR);
+ FillTable(MainTable, 7, VL, S_VL);
+ FillTable(MainTable, 7, ExtV, S_Ext);
+ FillTable(MainTable, 7, EOLV, S_EOL);
+ FillTable(WhiteTable, 12, MakeUpW, S_MakeUpW);
+ FillTable(WhiteTable, 12, MakeUp, S_MakeUp);
+ FillTable(WhiteTable, 12, TermW, S_TermW);
+ FillTable(WhiteTable, 12, ExtH, S_Ext);
+ FillTable(WhiteTable, 12, EOLH, S_EOL);
+ FillTable(BlackTable, 13, MakeUpB, S_MakeUpB);
+ FillTable(BlackTable, 13, MakeUp, S_MakeUp);
+ FillTable(BlackTable, 13, TermB, S_TermB);
+ FillTable(BlackTable, 13, ExtH, S_Ext);
+ FillTable(BlackTable, 13, EOLH, S_EOL);
+}
diff --git a/kfax/faxinput.cpp b/kfax/faxinput.cpp
new file mode 100644
index 00000000..8ca7fe85
--- /dev/null
+++ b/kfax/faxinput.cpp
@@ -0,0 +1,479 @@
+/* Fax file input processing
+ Copyright (C) 1990, 1995 Frank D. Cringle.
+
+This file is part of viewfax - g3/g4 fax processing software.
+
+viewfax 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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include "faxexpand.h"
+#include <qstring.h>
+#include <qfile.h>
+#include <kapplication.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+void statusbarupdate(char* name,int width,int height,char* res);
+extern void kfaxerror(const QString& title, const QString& error);
+
+#define FAXMAGIC "\000PC Research, Inc\000\000\000\000\000\000"
+
+/* Enter an argument in the linked list of pages */
+struct pagenode *
+notefile(const char *name, int type)
+{
+ struct pagenode *newnode = (struct pagenode *) xmalloc(sizeof *newnode);
+
+ *newnode = defaultpage;
+ if (firstpage == NULL){
+ firstpage = newnode;
+ auxpage = firstpage;
+ }
+ newnode->prev = lastpage;
+ newnode->next = NULL;
+ if (lastpage != NULL)
+ lastpage->next = newnode;
+ lastpage = newnode;
+
+ // kdDebug() << "Adding new node " << newnode << endl;
+
+ newnode->pathname = (char*) malloc (strlen(name) +1);
+ if(!newnode->pathname){
+ kfaxerror(i18n("Sorry"),i18n("Out of memory\n"));
+ exit(1);
+ }
+
+ strcpy(newnode->pathname,name);
+
+ newnode->type = type;
+
+
+ if ((newnode->name = strrchr(newnode->pathname, '/')) != NULL)
+ newnode->name++;
+ else
+ newnode->name = newnode->pathname;
+
+ if (newnode->width == 0)
+ newnode->width = 1728;
+ if (newnode->vres < 0)
+ newnode->vres = !(newnode->name[0] == 'f' && newnode->name[1] == 'n');
+ newnode->extra = NULL;
+
+ return newnode;
+}
+
+static t32bits
+get4(unsigned char *p, int endian)
+{
+ return endian ? (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3] :
+ p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
+}
+
+static int
+get2(unsigned char *p, int endian)
+{
+ return endian ? (p[0]<<8)|p[1] : p[0]|(p[1]<<8);
+}
+
+/* generate pagenodes for the images in a tiff file */
+int
+notetiff(const char *name)
+{
+
+ FILE *tf;
+ unsigned char header[8];
+ static const char littleTIFF[5] = "\x49\x49\x2a\x00";
+ static const char bigTIFF[5] = "\x4d\x4d\x00\x2a";
+ int endian;
+ t32bits IFDoff;
+ struct pagenode *pn = NULL;
+ QString str;
+
+
+ if ((tf = fopen(name, "r")) == NULL) {
+ QString mesg = i18n("Unable to open:\n%1\n").arg(QFile::decodeName(name));
+ kfaxerror(i18n("Sorry"), mesg);
+ return 0;
+ }
+
+ if (fread(header, 8, 1, tf) == 0) {
+ nottiff:
+ fclose(tf);
+ (void) notefile(name,FAX_RAW);
+ return 0;
+ }
+ if (memcmp(header, &littleTIFF, 4) == 0)
+ endian = 0;
+ else if (memcmp(header, &bigTIFF, 4) == 0)
+ endian = 1;
+ else
+ goto nottiff;
+ IFDoff = get4(header+4, endian);
+ if (IFDoff & 1)
+ goto nottiff;
+ do { /* for each page */
+ unsigned char buf[8];
+ unsigned char *dir = NULL , *dp = NULL;
+ int ndirent;
+ pixnum iwidth = defaultpage.width ? defaultpage.width : 1728;
+ pixnum iheight = defaultpage.height ? defaultpage.height : 2339;
+ int inverse = defaultpage.inverse;
+ int lsbfirst = 0;
+ int t4opt = 0, comp = 0;
+ int orient = defaultpage.orient;
+ double yres = defaultpage.vres ? 196.0 : 98.0;
+ struct strip *strips = NULL;
+ unsigned long rowsperstrip = 0;
+ t32bits nstrips = 1;
+
+ if (fseek(tf, IFDoff, SEEK_SET) < 0) {
+ realbad:
+ str = i18n("Invalid tiff file:\n%1\n").arg(QFile::decodeName(name));
+ kfaxerror(i18n("Sorry"),str);
+ bad:
+ if (strips)
+ free(strips);
+ if (dir)
+ free(dir);
+ fclose(tf);
+ return 1;
+ }
+ if (fread(buf, 2, 1, tf) == 0)
+ goto realbad;
+ ndirent = get2(buf, endian);
+ dir = (unsigned char *) xmalloc(12*ndirent+4);
+ if (fread(dir, 12*ndirent+4, 1, tf) == 0)
+ goto realbad;
+ for (dp = dir; ndirent; ndirent--, dp += 12) {
+ /* for each directory entry */
+ int tag, ftype;
+ t32bits count, value = 0;
+ tag = get2(dp, endian);
+ ftype = get2(dp+2, endian);
+ count = get4(dp+4, endian);
+ switch(ftype) { /* value is offset to list if count*size > 4 */
+ case 3: /* short */
+ value = get2(dp+8, endian);
+ break;
+ case 4: /* long */
+ value = get4(dp+8, endian);
+ break;
+ case 5: /* offset to rational */
+ value = get4(dp+8, endian);
+ break;
+ }
+ switch(tag) {
+ case 256: /* ImageWidth */
+ iwidth = value;
+ break;
+ case 257: /* ImageLength */
+ iheight = value;
+ break;
+ case 259: /* Compression */
+ comp = value;
+ break;
+ case 262: /* PhotometricInterpretation */
+ inverse ^= (value == 1);
+ break;
+ case 266: /* FillOrder */
+ lsbfirst = (value == 2);
+ break;
+ case 273: /* StripOffsets */
+ nstrips = count;
+ strips = (struct strip *) xmalloc(count * sizeof *strips);
+ if (count == 1 || (count == 2 && ftype == 3)) {
+ strips[0].offset = value;
+ if (count == 2)
+ strips[1].offset = get2(dp+10, endian);
+ break;
+ }
+ if (fseek(tf, value, SEEK_SET) < 0)
+ goto realbad;
+ for (count = 0; count < nstrips; count++) {
+ if (fread(buf, (ftype == 3) ? 2 : 4, 1, tf) == 0)
+ goto realbad;
+ strips[count].offset = (ftype == 3) ?
+ get2(buf, endian) : get4(buf, endian);
+ }
+ break;
+ case 274: /* Orientation */
+ switch(value) {
+ default: /* row0 at top, col0 at left */
+ orient = 0;
+ break;
+ case 2: /* row0 at top, col0 at right */
+ orient = TURN_M;
+ break;
+ case 3: /* row0 at bottom, col0 at right */
+ orient = TURN_U;
+ break;
+ case 4: /* row0 at bottom, col0 at left */
+ orient = TURN_U|TURN_M;
+ break;
+ case 5: /* row0 at left, col0 at top */
+ orient = TURN_M|TURN_L;
+ break;
+ case 6: /* row0 at right, col0 at top */
+ orient = TURN_U|TURN_L;
+ break;
+ case 7: /* row0 at right, col0 at bottom */
+ orient = TURN_U|TURN_M|TURN_L;
+ break;
+ case 8: /* row0 at left, col0 at bottom */
+ orient = TURN_L;
+ break;
+ }
+ break;
+ case 278: /* RowsPerStrip */
+ rowsperstrip = value;
+ break;
+ case 279: /* StripByteCounts */
+ if (count != nstrips) {
+ str = i18n("In file %1\nStripsPerImage tag 273=%2,tag279=%3\n")
+ .arg(QFile::decodeName(name)).arg(nstrips).arg(count);
+ kfaxerror(i18n("Message"),str);
+ goto realbad;
+ }
+ if (count == 1 || (count == 2 && ftype == 3)) {
+ strips[0].size = value;
+ if (count == 2)
+ strips[1].size = get2(dp+10, endian);
+ break;
+ }
+ if (fseek(tf, value, SEEK_SET) < 0)
+ goto realbad;
+ for (count = 0; count < nstrips; count++) {
+ if (fread(buf, (ftype == 3) ? 2 : 4, 1, tf) == 0)
+ goto realbad;
+ strips[count].size = (ftype == 3) ?
+ get2(buf, endian) : get4(buf, endian);
+ }
+ break;
+ case 283: /* YResolution */
+ if (fseek(tf, value, SEEK_SET) < 0 ||
+ fread(buf, 8, 1, tf) == 0)
+ goto realbad;
+ yres = get4(buf, endian) / get4(buf+4, endian);
+ break;
+ case 292: /* T4Options */
+ t4opt = value;
+ break;
+ case 293: /* T6Options */
+ /* later */
+ break;
+ case 296: /* ResolutionUnit */
+ if (value == 3)
+ yres *= 2.54;
+ break;
+ }
+ }
+ IFDoff = get4(dp, endian);
+ free(dir);
+ dir = NULL;
+ if (comp == 5) {
+ // compression type 5 is LZW compression
+ kfaxerror(i18n("Sorry"),i18n("Due to patent reasons KFax can not handle LZW (Lempel-Ziv & Welch) "
+ "compressed Fax files.\n"));
+ goto bad;
+ }
+ if (comp < 2 || comp > 4) {
+ kfaxerror(i18n("Sorry"),i18n("This version can only handle Fax files\n"));
+ goto bad;
+ }
+ pn = notefile(name,FAX_TIFF);
+ pn->nstrips = nstrips;
+ pn->rowsperstrip = nstrips > 1 ? rowsperstrip : iheight;
+ pn->strips = strips;
+ pn->width = iwidth;
+ pn->height = iheight;
+ pn->inverse = inverse;
+ pn->lsbfirst = lsbfirst;
+ pn->orient = orient;
+ pn->vres = (yres > 150); /* arbitrary threshold for fine resolution */
+ if (comp == 2)
+ pn->expander = MHexpand;
+ else if (comp == 3)
+ pn->expander = (t4opt & 1) ? g32expand : g31expand;
+ else
+ pn->expander = g4expand;
+ } while (IFDoff);
+ fclose(tf);
+ return 1;
+}
+
+/* report error and remove bad file from the list */
+static void
+badfile(struct pagenode *pn)
+{
+ struct pagenode *p;
+
+ if (errno)
+ perror(pn->pathname);
+ if (pn == firstpage) {
+ if (pn->next == NULL){
+ kfaxerror(i18n("Sorry"),i18n("Bad Fax File"));
+ return;
+ }
+ else{
+ firstpage = thispage = firstpage->next;
+ firstpage->prev = NULL;
+ }
+ }
+ else
+ for (p = firstpage; p; p = p->next)
+ if (p->next == pn) {
+ thispage = p;
+ p->next = pn->next;
+ if (pn->next)
+ pn->next->prev = p;
+ break;
+ }
+ if (pn) free(pn);
+ pn = NULL;
+}
+
+/* rearrange input bits into t16bits lsb-first chunks */
+static void
+normalize(struct pagenode *pn, int revbits, int swapbytes, size_t length)
+{
+ t32bits *p = (t32bits *) pn->data;
+
+ switch ((revbits<<1)|swapbytes) {
+ case 0:
+ break;
+ case 1:
+ for ( ; length; length -= 4) {
+ t32bits t = *p;
+ *p++ = ((t & 0xff00ff00) >> 8) | ((t & 0x00ff00ff) << 8);
+ }
+ break;
+ case 2:
+ for ( ; length; length -= 4) {
+ t32bits t = *p;
+ t = ((t & 0xf0f0f0f0) >> 4) | ((t & 0x0f0f0f0f) << 4);
+ t = ((t & 0xcccccccc) >> 2) | ((t & 0x33333333) << 2);
+ *p++ = ((t & 0xaaaaaaaa) >> 1) | ((t & 0x55555555) << 1);
+ }
+ break;
+ case 3:
+ for ( ; length; length -= 4) {
+ t32bits t = *p;
+ t = ((t & 0xff00ff00) >> 8) | ((t & 0x00ff00ff) << 8);
+ t = ((t & 0xf0f0f0f0) >> 4) | ((t & 0x0f0f0f0f) << 4);
+ t = ((t & 0xcccccccc) >> 2) | ((t & 0x33333333) << 2);
+ *p++ = ((t & 0xaaaaaaaa) >> 1) | ((t & 0x55555555) << 1);
+ }
+ }
+}
+
+
+/* get compressed data into memory */
+unsigned char *
+getstrip(struct pagenode *pn, int strip)
+{
+ int fd;
+ size_t offset, roundup;
+ struct stat sbuf;
+ unsigned char *Data;
+ union { t16bits s; unsigned char b[2]; } so;
+ QString str;
+
+#define ShortOrder so.b[1]
+
+ so.s = 1;
+ if ((fd = open(pn->pathname, O_RDONLY, 0)) < 0) {
+ badfile(pn);
+ return NULL;
+ }
+
+ if (pn->strips == NULL) {
+ if (fstat(fd, &sbuf) != 0) {
+ close(fd);
+ badfile(pn);
+ return NULL;
+ }
+ offset = 0;
+ pn->length = sbuf.st_size;
+ }
+ else if (strip < pn->nstrips) {
+ offset = pn->strips[strip].offset;
+ pn->length = pn->strips[strip].size;
+ }
+ else {
+ str = i18n("Trying to expand too many strips\n%1%n").arg(QFile::decodeName(pn->pathname));
+ kfaxerror(i18n("Warning"),str);
+ return NULL;
+ }
+
+ /* round size to full boundary plus t32bits */
+ roundup = (pn->length + 7) & ~3;
+
+ Data = (unsigned char *) xmalloc(roundup);
+ /* clear the last 2 t32bits, to force the expander to terminate
+ even if the file ends in the middle of a fax line */
+ *((t32bits *) Data + roundup/4 - 2) = 0;
+ *((t32bits *) Data + roundup/4 - 1) = 0;
+
+ /* we expect to get it in one gulp... */
+ if (lseek(fd, offset, SEEK_SET) < 0 ||
+ (uint) read(fd, Data, pn->length) != pn->length) {
+ badfile(pn);
+ free(Data);
+ close(fd);
+ return NULL;
+ }
+ close(fd);
+
+ pn->data = (t16bits *) Data;
+ if (pn->strips == NULL && memcmp(Data, FAXMAGIC, sizeof(FAXMAGIC)) == 0) {
+ /* handle ghostscript / PC Research fax file */
+ if (Data[24] != 1 || Data[25] != 0){
+ str = i18n("Only the first page of the PC Research multipage file\n%1\nwill be shown\n")
+ .arg(QFile::decodeName(pn->pathname));
+ kfaxerror(i18n("Message"),str);
+ }
+ pn->length -= 64;
+ pn->vres = Data[29];
+ pn->data += 32;
+ roundup -= 64;
+ }
+
+ normalize(pn, !pn->lsbfirst, ShortOrder, roundup);
+ if (pn->height == 0)
+ pn->height = G3count(pn, pn->expander == g32expand);
+ if (pn->height == 0) {
+
+ str = i18n("No fax found in file:\n%1\n").arg(QFile::decodeName(pn->pathname));
+ kfaxerror(i18n("Sorry"),str);
+ errno = 0;
+ badfile(pn);
+ free(Data);
+ return NULL;
+ }
+ if (pn->strips == NULL)
+ pn->rowsperstrip = pn->height;
+ if (verbose && strip == 0)
+ kdWarning() << pn->name << "\n\twidth = " << pn->width << "\n\theight = "
+ << pn->height << "\n\tresolution = " << (pn->vres ? "fine" : "normal") << endl;
+// statusbarupdate(pn->name,pn->width,pn->height,pn->vres ? "fine" : "normal");
+ return Data;
+}
diff --git a/kfax/hi16-app-kfax.png b/kfax/hi16-app-kfax.png
new file mode 100644
index 00000000..bb676f8b
--- /dev/null
+++ b/kfax/hi16-app-kfax.png
Binary files differ
diff --git a/kfax/hi22-app-kfax.png b/kfax/hi22-app-kfax.png
new file mode 100644
index 00000000..90fc64b0
--- /dev/null
+++ b/kfax/hi22-app-kfax.png
Binary files differ
diff --git a/kfax/hi32-app-kfax.png b/kfax/hi32-app-kfax.png
new file mode 100644
index 00000000..7330eb41
--- /dev/null
+++ b/kfax/hi32-app-kfax.png
Binary files differ
diff --git a/kfax/hi48-app-kfax.png b/kfax/hi48-app-kfax.png
new file mode 100644
index 00000000..3f58c369
--- /dev/null
+++ b/kfax/hi48-app-kfax.png
Binary files differ
diff --git a/kfax/hisc-app-kfax.svgz b/kfax/hisc-app-kfax.svgz
new file mode 100644
index 00000000..f46fd440
--- /dev/null
+++ b/kfax/hisc-app-kfax.svgz
Binary files differ
diff --git a/kfax/kfax.cpp b/kfax/kfax.cpp
new file mode 100644
index 00000000..02661325
--- /dev/null
+++ b/kfax/kfax.cpp
@@ -0,0 +1,1695 @@
+ /*
+
+ $Id$
+
+ Copyright (C) 1997 Bernd Johannes Wuebben
+ wuebben@math.cornell.edu
+
+ 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.
+
+ */
+
+#ifdef KDE_USE_FINAL
+/* NewImage() in viewfax.cpp needs to fiddle with the Display structure */
+#define XLIB_ILLEGAL_ACCESS
+#endif
+
+#include <stdlib.h>
+#include <signal.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <qfile.h>
+#include <qstrlist.h>
+#include <qtimer.h>
+#include <qpopupmenu.h>
+#include <qpainter.h>
+#include <qpaintdevicemetrics.h>
+#include <qbitmap.h>
+
+#include <klocale.h>
+#include <kaboutdata.h>
+#include <kstandarddirs.h>
+#include <kiconloader.h>
+#include <kfiledialog.h>
+#include <kfilemetainfo.h>
+#include <kstdaccel.h>
+#include <kconfig.h>
+#include <kmenubar.h>
+#include <kmessagebox.h>
+#include <kcmdlineargs.h>
+#include <kio/netaccess.h>
+#include <knotifyclient.h>
+#include <ktempfile.h>
+#include <kstdaction.h>
+#include <kdebug.h>
+#include <kurldrag.h>
+#include <kstatusbar.h>
+#include <kaction.h>
+#include <kprocess.h>
+#include <kprinter.h>
+#include <kio/job.h>
+#include <kdebug.h>
+
+#include "faxexpand.h"
+#include "kfax.h"
+#include "version.h"
+#include "viewfax.h"
+#include "options.h"
+#include "kfax_printsettings.h"
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/keysym.h>
+#include <X11/keysymdef.h>
+#include <X11/cursorfont.h>
+
+// StatusBar field IDs
+#define ID_LINE_COLUMN 1
+#define ID_INS_OVR 2
+#define ID_GENERAL 3
+#define ID_FNAME 4
+#define ID_TYPE 5
+#define ID_PAGE_NO 6
+
+
+TopLevel *toplevel;
+
+extern int GetImage(struct pagenode *pn);
+
+void TurnFollowing(int How, struct pagenode *pn);
+void handle_X_event(XEvent event);
+void ShowLoop(void);
+void SetupDisplay();
+void mysighandler(int sig);
+void setFaxDefaults();
+
+void parse(char* buf, char** args);
+
+extern void g31expand(struct pagenode *pn, drawfunc df);
+extern void g32expand(struct pagenode *pn, drawfunc df);
+extern void g4expand(struct pagenode *pn, drawfunc df);
+
+#define PATIENCE 100000
+
+static char KFAX_FILETYPES[] = "image/fax-g3 image/tiff";
+
+int ExpectConfNotify = 1;
+
+GC PaintGC;
+Cursor WorkCursor;
+Cursor ReadyCursor;
+Cursor MoveCursor;
+Cursor LRCursor;
+Cursor UDCursor;
+
+extern Time Lasttime;
+extern bool have_cmd_opt;
+extern struct pagenode *viewpage;
+
+extern XImage *FlipImage(XImage *xi);
+extern XImage *MirrorImage(XImage *xi);
+extern XImage *RotImage(XImage *Image);
+extern XImage *ZoomImage(XImage *Big);
+extern void FreeImage(XImage *Image);
+
+extern XImage *Image, *Images[MAXZOOM];
+
+int xpos, ox; /* x, old x, offset x, new xpos*/
+int ypos, oy; /* y, old y, offset y, new y */
+int offx, offy;
+int nx, ny;
+
+int oz, Resize, Refresh; /* old zoom, window size changed,
+ needs updating */
+int PaneWidth, PaneHeight; /* current size of our window */
+int AbsX, AbsY; /* absolute position of centre of window */
+
+Display* qtdisplay;
+
+int startingup;
+Window qtwin; // the qt window
+Window Win;
+int qwindow_height;
+int qwindow_width;
+bool have_no_fax = TRUE;
+bool display_is_setup = FALSE;
+struct optionsinfo fop; // contains the fax options
+
+extern struct pagenode *firstpage, *lastpage, *thispage;
+extern struct pagenode* auxpage;
+
+extern struct pagenode defaultpage;
+
+bool buttondown;
+
+bool MyApp::x11EventFilter( XEvent * ev)
+{
+ if (KApplication::x11EventFilter(ev))
+ return TRUE;
+
+ if (ev->type == ButtonRelease){
+ /* this is so that the cursor goes back to normal on leaving the fax window
+ and that the fax won't be moved when I reenter after I release the mouse*/
+
+ if (buttondown == true){
+ buttondown = false;
+ XDefineCursor(qtdisplay, Win, ReadyCursor);
+ XFlush(qtdisplay);
+ }
+ }
+ if ( ev->xany.window == qtwin ||
+ ev->xany.window == Win){
+
+ if(startingup || have_no_fax)
+ return FALSE;
+
+ toplevel->handle_X_event(*ev);
+ ev->xany.window = qtwin;
+
+ }
+
+ return FALSE;
+
+}
+
+TopLevel::TopLevel (QWidget *, const char *name)
+ : KMainWindow (0, name)
+{
+ setMinimumSize (100, 100);
+
+ buttondown = false;
+
+ setupMenuBar();
+ setupStatusBar();
+ updateActions();
+
+ resize(550,400);
+ setupGUI();
+
+ readSettings();
+
+ faxqtwin = new QFrame(this);
+
+ qtwin = faxqtwin->winId();
+ faxqtwin->setFrameStyle(QFrame::Panel | QFrame::Sunken);
+
+ // Create a Vertical scroll bar
+
+ vsb = new QScrollBar( QScrollBar::Vertical,faxqtwin,"scrollBar" );
+ vsb->hide();
+ connect( vsb, SIGNAL(valueChanged(int)), SLOT(scrollVert(int)) );
+
+ // Create a Horizontal scroll bar
+
+ hsb = new QScrollBar( QScrollBar::Horizontal,faxqtwin,"scrollBar" );
+ connect( hsb, SIGNAL(valueChanged(int)), SLOT(scrollHorz(int)) );
+ hsb->hide();
+
+ setCentralWidget(faxqtwin);
+
+ setAcceptDrops(true);
+
+ show();
+}
+
+
+TopLevel::~TopLevel()
+{
+}
+
+void TopLevel::setupMenuBar()
+{
+ // File menu
+ KStdAction::open( this, SLOT( faxOpen() ), actionCollection() );
+ actRecent = KStdAction::openRecent( this, SLOT( faxOpen( const KURL & ) ),
+ actionCollection() );
+ actSave = KStdAction::save( this, SLOT( faxSave() ), actionCollection() );
+ actSaveAs = KStdAction::saveAs( this, SLOT( faxSaveAs() ),
+ actionCollection() );
+ actPrint = KStdAction::print( this, SLOT( print() ), actionCollection() );
+ KStdAction::quit( this, SLOT( close() ), actionCollection() );
+ actAdd = new KAction( i18n( "A&dd..." ), "filenew", KShortcut(), this,
+ SLOT( faxAdd() ), actionCollection(), "file_add_fax" );
+
+ actRecent->setMaxItems( 5 );
+
+ // View Menu
+ actSize = KStdAction::actualSize( this, SLOT( actualSize() ),
+ actionCollection() );
+ actZoomIn = KStdAction::zoomIn( this, SLOT( zoomin() ), actionCollection() );
+ actZoomOut = KStdAction::zoomOut( this, SLOT( zoomout() ),
+ actionCollection() );
+
+ actRotate = new KAction( i18n( "&Rotate Page" ), "rotate", KShortcut(), this,
+ SLOT( rotatePage() ), actionCollection(), "view_rotate" );
+ actMirror = new KAction( i18n( "Mirror Page" ), KShortcut(), this,
+ SLOT( mirrorPage() ), actionCollection(), "view_mirror" );
+ actFlip = new KAction( i18n( "&Flip Page" ), KShortcut(), this,
+ SLOT( flipPage() ), actionCollection(), "view_flip" );
+
+ // Go menu
+ actNext = KStdAction::next( this, SLOT( nextPage() ), actionCollection() );
+ actPrev = KStdAction::prior( this, SLOT( prevPage() ), actionCollection() );
+ actFirst = KStdAction::firstPage( this, SLOT( firstPage() ),
+ actionCollection() );
+ actLast = KStdAction::lastPage( this, SLOT( lastPage() ),
+ actionCollection() );
+
+ // Settings menu
+ KStdAction::preferences( this, SLOT( faxoptions() ), actionCollection() );
+}
+
+void TopLevel::setupStatusBar()
+{
+ statusbar = statusBar();
+
+ statusbar->insertFixedItem(i18n("w: 00000 h: 00000"), ID_INS_OVR);
+ statusbar->insertFixedItem(i18n("Res: XXXXX"), ID_GENERAL);
+ statusbar->insertFixedItem(i18n("Type: XXXXXXX"), ID_TYPE);
+ statusbar->insertFixedItem(i18n("Page: XX of XX"), ID_PAGE_NO);
+ statusbar->insertItem(QString::null, ID_FNAME, 1);
+ statusbar->setItemAlignment( ID_FNAME, AlignLeft );
+
+ statusbar->changeItem(QString::null, ID_INS_OVR);
+ statusbar->changeItem(QString::null, ID_GENERAL);
+ statusbar->changeItem(QString::null, ID_TYPE);
+ statusbar->changeItem(QString::null, ID_PAGE_NO);
+ statusbar->changeItem(QString::null, ID_FNAME);
+}
+
+void TopLevel::readSettings()
+{
+ config = kapp->config();
+
+ applyMainWindowSettings( config, "MainWindowSettings" );
+
+ actRecent->loadEntries( config );
+
+ config->setGroup("General Options");
+
+ config->setGroup("Fax Options");
+
+ fop.width = config->readNumEntry("width", 1728);
+ fop.resauto = config->readNumEntry("resauto", 1);
+ fop.geomauto = config->readNumEntry("geomauto", 1);
+ fop.height = config->readNumEntry("height", 2339);
+ fop.fine = config->readNumEntry("resolution", 1);
+ fop.flip = config->readNumEntry("flip", 0);
+ fop.invert = config->readNumEntry("invert", 0);
+ fop.lsbfirst = config->readNumEntry("lsb", 0);
+ fop.raw = config->readNumEntry("raw", 3);
+
+ setFaxDefaults();
+}
+
+void TopLevel::updateActions()
+{
+ actAdd->setEnabled( thispage );
+ actSave->setEnabled( thispage );
+ actSaveAs->setEnabled( thispage );
+ actPrint->setEnabled( thispage );
+
+ actRotate->setEnabled( thispage );
+ actFlip->setEnabled( thispage );
+ actMirror->setEnabled( thispage );
+
+ updateGoActions();
+ updateZoomActions();
+}
+
+void TopLevel::updateGoActions()
+{
+ actNext->setEnabled( thispage && thispage->next );
+ actPrev->setEnabled( thispage && thispage->prev );
+ actFirst->setEnabled( thispage && thispage->prev );
+ actLast->setEnabled( thispage && thispage->next );
+}
+
+void TopLevel::updateZoomActions()
+{
+ actSize->setEnabled( Image && oz > 0 );
+ actZoomIn->setEnabled( Image && oz > 0 );
+ actZoomOut->setEnabled( Image && oz < MAXZOOM-1 && Image->width >= 256 );
+}
+
+bool TopLevel::queryClose()
+{
+ saveMainWindowSettings( config, "MainWindowSettings" );
+ actRecent->saveEntries( config );
+
+ return true;
+}
+
+void TopLevel::writeSettings()
+{
+ config = kapp->config();
+
+ config->setGroup("General Options");
+
+ config->setGroup("Fax Options");
+
+ config->writeEntry("resauto",fop.resauto);
+ config->writeEntry("geomauto",fop.geomauto);
+ config->writeEntry("width",fop.width);
+ config->writeEntry("height",fop.height);
+ config->writeEntry("resolution",fop.fine);
+ config->writeEntry("flip",fop.flip);
+ config->writeEntry("invert",fop.invert);
+ config->writeEntry("lsb",fop.lsbfirst);
+ config->writeEntry("raw",fop.raw);
+
+ config->sync();
+}
+
+void TopLevel::faxOpen()
+{
+ KURL url = KFileDialog::getOpenURL(QString::null, KFAX_FILETYPES);
+
+ faxOpen( url );
+
+ actRecent->addURL( fileURL );
+}
+
+void TopLevel::faxOpen( const KURL & url )
+{
+ if (!url.isValid())
+ return;
+
+ faxClose();
+ faxAdd( url );
+
+ fileURL = url;
+
+ updateActions();
+}
+
+void TopLevel::faxAdd()
+{
+ KURL url = KFileDialog::getOpenURL(QString::null, KFAX_FILETYPES);
+
+ faxAdd( url );
+
+ actRecent->addURL( fileURL );
+}
+
+void TopLevel::faxAdd( const KURL & url )
+{
+ if (!url.isValid())
+ return;
+
+ openNetFile(url);
+
+ updateGoActions();
+}
+
+void TopLevel::faxSave()
+{
+ saveNetFile(fileURL);
+}
+
+void TopLevel::faxSaveAs()
+{
+ fileURL = KFileDialog::getSaveURL(QString::null, KFAX_FILETYPES);
+
+ if (fileURL.isEmpty())
+ return;
+
+ faxSave();
+
+ actRecent->addURL( fileURL );
+}
+
+
+static void freeImages()
+{
+ int i;
+ for (i = 1; i < MAXZOOM; i++) {
+ if (Images[i])
+ FreeImage(Images[i]);
+ Images[i] = NULL;
+ }
+}
+
+static XImage *generateZoomImages(int maxzoom)
+{
+ int i;
+ for (i = 1; i < MAXZOOM; i++){
+ if (!Images[i-1])
+ continue;
+ Image = Images[i] = ZoomImage(Images[i-1]);
+ if(Image == NULL){// out of memory
+ Image = Images[i -1];
+ break;
+ }
+ }
+
+ i = maxzoom;
+ while (!Images[i])
+ i--;
+ return Images[i];
+}
+
+
+void TopLevel::zoom( int factor )
+{
+ if(!thispage || !Image || !faxqtwin || !display_is_setup)
+ return;
+
+ Resize = Refresh = 1;
+
+ Image = generateZoomImages(factor);
+
+ PaneWidth = Image->width;
+ PaneHeight = Image->height;
+
+ resizeView();
+ putImage();
+
+ uiUpdate();
+
+ updateZoomActions();
+}
+
+void TopLevel::zoomin()
+{
+ if ( oz > 0 )
+ {
+ oz--;
+ zoom( oz );
+ }
+}
+
+void TopLevel::zoomout()
+{
+ if (oz < MAXZOOM && Image->width >= 256)
+ {
+ ++oz;
+ zoom( oz );
+ }
+}
+
+void TopLevel::actualSize()
+{
+ oz = 0;
+ zoom( oz );
+}
+
+void loadfile(QString filename)
+{
+ // Typical FAX resolutions are:
+ // Standard: 203 dpi x 98 dpi
+ // Fine: 203 dpi x 196 lpi
+ // Super Fine: 203 dpi y 392 lpi, or
+ // 406 dpi x 392 lpi
+ QSize dpi(203,196);
+
+ KFileMetaInfo metaInfo(filename);
+ if (metaInfo.isValid() && metaInfo.item("Resolution").isValid())
+ {
+ QSize s = metaInfo.item("Resolution").value().toSize();
+ if (s.width() >= 100 && s.height() >= 100)
+ dpi = s;
+ }
+
+ (void) notetiff(QFile::encodeName(filename));
+
+ struct pagenode *pn;
+ for(pn = firstpage; pn; pn = pn->next)
+ if (!pn->dpiX) {
+ pn->dpiX = dpi.width();
+ pn->dpiY = dpi.height();
+ }
+}
+
+void TopLevel::openadd(QString filename)
+{
+ auxpage = lastpage;
+
+ loadfile(filename);
+
+ if( firstpage != lastpage )
+ {
+ if(auxpage->next)
+ auxpage = auxpage->next;
+ }
+
+ // auxpage should now point to the first pagenode which was created for
+ // the newly added fax file.
+ have_no_fax = false;
+ thispage = auxpage;
+ newPage();
+ resizeView();
+ putImage();
+}
+
+void TopLevel::resizeEvent(QResizeEvent *e)
+{
+ KMainWindow::resizeEvent(e);
+
+ resizeView();
+}
+
+void TopLevel::wheelEvent( QWheelEvent *e )
+{
+ e->accept();
+
+ if ( e->state() & ShiftButton )
+ {
+ if ( e->delta() < 0 )
+ zoomin();
+ else
+ zoomout();
+ }
+ else
+ {
+ int offset = QApplication::wheelScrollLines()*vsb->lineStep();
+ if ( e->state() & ControlButton )
+ offset = vsb->pageStep();
+ offset = -e->delta()*offset/120;
+ vsb->setValue( vsb->value() + offset );
+ }
+}
+
+void TopLevel::resizeView()
+{
+ if(!faxqtwin || !display_is_setup)
+ return;
+
+//printf("In resizeView() entered\n");
+
+ qwindow_width = faxqtwin->width();
+ qwindow_height = faxqtwin->height();
+
+ if( hsb->isVisible())
+ qwindow_height -= 16;
+
+ if( vsb->isVisible())
+ qwindow_width -= 16;
+
+ if(Image){
+ PaneWidth = Image->width;
+ PaneHeight = Image->height;
+ }
+
+ // printf("faxw %d qtw %d\n", PaneWidth , faxqtwin->width());
+
+ if( (PaneHeight > qwindow_height ) &&
+ (PaneWidth > qwindow_width)){
+
+ vsb->setGeometry(faxqtwin->width() - 16,0,16,faxqtwin->height()-16);
+ hsb->setGeometry(0,faxqtwin->height() - 16 ,faxqtwin->width()-16,16);
+
+ qwindow_width = faxqtwin->width() -16;
+ qwindow_height = faxqtwin->height()-16;
+
+
+ vsb->raise();
+ vsb->show();
+ hsb->show();
+ }
+ else{
+
+ if( PaneHeight > qwindow_height){
+ vsb->setGeometry(faxqtwin->width() - 16,0,16,faxqtwin->height());
+
+
+ qwindow_width = faxqtwin->width() -16 ;
+ qwindow_height = faxqtwin->height();
+
+
+ vsb->show();
+ hsb->hide();
+ hsb->raise();
+ }
+ else
+ vsb->hide();
+
+ if( PaneWidth > qwindow_width ){
+ hsb->setGeometry(0,faxqtwin->height() - 16 ,faxqtwin->width(),16);
+ hsb->show();
+ hsb->raise();
+ vsb->hide();
+ qwindow_width = faxqtwin->width() ;
+ qwindow_height = faxqtwin->height() -16;
+
+ }
+ else
+ hsb->hide();
+
+ }
+
+ if(Image){
+ hsb->setRange(0,QMAX(0,Image->width - qwindow_width));
+ hsb->setSteps(5,qwindow_width/2);
+ // printf("hsb range: %d\n",QMAX(0,Image->width - qwindow_width));
+ vsb->setRange(0,QMAX(0,Image->height - qwindow_height));
+ vsb->setSteps(5,qwindow_height/2);
+ // printf("vsb range: %d\n",QMAX(0,Image->height - qwindow_height));
+ // printf("vsb QMIN %d vdb QMAX %d\n",vsb->QMINValue(),vsb->QMAXValue());
+ }
+
+
+ Resize = 1;
+ uiUpdate();
+
+}
+
+bool TopLevel::loadAllPages( int &numpages, int &currentpage )
+{
+ struct pagenode *pn;
+
+ numpages = 0;
+ currentpage = 1;
+
+ for(pn = firstpage; pn; pn = pn->next) {
+ ++numpages;
+ if (pn == thispage)
+ currentpage = numpages;
+ if (!Pimage(pn)) {
+ int k = -1;
+ while((k != 0) && (k != 3) && (k != 1))
+ k = GetImage(pn); // fetch image if it is not available yet.
+ }
+ }
+ return (numpages != 0);
+}
+
+void TopLevel::print(){
+ if(!thispage || !firstpage) {
+ return KMessageBox::sorry(this, i18n("There is no document active."));
+ }
+
+ int pages, currentpage;
+ loadAllPages(pages, currentpage);
+
+ KPrinter printer(true, QPrinter::HighResolution);
+ printer.setFullPage( true );
+ printer.setUsePrinterResolution( true );
+ printer.setCreator( i18n("KFax") + " " KFAXVERSION );
+ printer.setDocName( QString("%1 - %2").arg(firstpage->name).arg(i18n("KFax")));
+ printer.setDocFileName( firstpage->name );
+ printer.setPageSelection( KPrinter::ApplicationSide );
+ printer.setMinMax( 1, pages );
+ printer.setCurrentPage( currentpage );
+ printer.addDialogPage(new KFAXPrintSettings());
+ if ( !printer.setup( this ) )
+ return;
+
+ QPainter painter;
+ painter.begin( &printer );
+ printIt(printer, painter);
+ painter.end();
+}
+
+
+void TopLevel::printIt( KPrinter &printer, QPainter &painter )
+{
+ QPaintDeviceMetrics dm(painter.device());
+
+ QApplication::setOverrideCursor( waitCursor );
+ kapp->processEvents();
+
+ const bool fullpage = printer.option(APP_KFAX_SCALE_FULLPAGE) == "true";
+ const bool center_h = printer.option(APP_KFAX_CENTER_HORZ) == "true";
+ const bool center_v = printer.option(APP_KFAX_CENTER_VERT) == "true";
+
+ int currentpage = 0;
+ bool first_page_printed = false;
+ struct pagenode *pn;
+ for(pn = firstpage; pn; pn = pn->next) {
+
+ ++currentpage;
+ // should this page be printed ?
+ if (printer.pageList().findIndex(currentpage) < 0)
+ continue;
+
+ XImage *Image = Pimage(pn);
+ if (!Image)
+ continue;
+
+ // byte-swapping the image
+ QByteArray bytes( Image->height*Image->bytes_per_line );
+ for (int y=Image->height-1; y>=0; --y) {
+ Q_UINT32 offset = y*Image->bytes_per_line;
+ Q_UINT32 *source = (Q_UINT32 *) (Image->data + offset);
+ Q_UINT32 *dest = (Q_UINT32 *) (bytes.data() + offset);
+ for (int x=(Image->bytes_per_line/4)-1; x>=0; --x) {
+ Q_UINT32 dv = 0, sv = *source;
+ for (int bit=32; bit>0; --bit) {
+ dv <<= 1;
+ dv |= sv&1;
+ sv >>= 1;
+ }
+ *dest = dv;
+ ++dest;
+ ++source;
+ }
+ }
+
+ QImage image( (uchar *)bytes.data(), Image->bytes_per_line*8, Image->height, 1, NULL, 2, QImage::LittleEndian);
+
+ if (first_page_printed)
+ printer.newPage();
+ first_page_printed = true;
+
+ const QSize printersize( dm.width(), dm.height() );
+ kdDebug() << "Printersize = " << printersize << endl;
+ // print Image in original size if possible, else scale it.
+
+ const QSize size( // logical size of the image
+ Image->width * dm.logicalDpiX() / pn->dpiX,
+ Image->height * dm.logicalDpiY() / pn->dpiY
+ );
+
+ kdDebug() << "Org image size = " << Image->width << "x" << Image->height
+ << " logical picture res = " << pn->dpiX << "x" << pn->dpiY << endl;
+ kdDebug() << "New image size = " << size
+ << " logical printer res = " << dm.logicalDpiX() << "x" << dm.logicalDpiY() << endl;
+
+ uint top, left, bottom, right;
+ if (fullpage)
+ top = left = bottom = right = 0;
+ else
+ printer.margins( &top, &left, &bottom, &right );
+ kdDebug() << "Margins = " << top << " " << left << " " << bottom << " " << right << endl;
+
+ const QSize maxSize( printersize.width()-left-right, printersize.height()-top-bottom );
+ QSize scaledImageSize = size;
+ if (size.width() > maxSize.width() || size.height() > maxSize.height() ) {
+ // Image does not fit - scale it and print centered
+ scaledImageSize.scale( maxSize, QSize::ScaleMin );
+ kdDebug() << "Image does not fit - scaling to " << maxSize << endl;
+ } else {
+ // Image does fit - print it in original size, but centered
+ scaledImageSize.scale( size, QSize::ScaleMin );
+ kdDebug() << "Image does fit - scaling to " << size << endl;
+ }
+ kdDebug() << "Final image size " << scaledImageSize << endl;
+ int x,y;
+ if (center_h)
+ x = (maxSize.width()-scaledImageSize.width())/2 + left;
+ else
+ x = left;
+ if (center_v)
+ y = (maxSize.height()-scaledImageSize.height())/2 + top;
+ else
+ y = top;
+ painter.drawImage( QRect(x,y,scaledImageSize.width(), scaledImageSize.height()), image );
+
+ }
+
+ QApplication::restoreOverrideCursor();
+}
+
+void TopLevel::saveNetFile( const KURL& dest)
+{
+ if ( !dest.isValid() )
+ {
+ KMessageBox::sorry(this, i18n("Malformed URL"));
+ return;
+ }
+
+ statusbar->message( i18n( "Saving..." ) );
+
+ KURL source = KURL::fromPathOrURL(thispage->pathname);
+ bool ok = KIO::NetAccess::file_copy( source, dest, -1, true, false, this);
+
+ statusbar->clear();
+
+ if (!ok)
+ KMessageBox::error(this, i18n("Failure in 'copy file()'\n"
+ "Could not save file!"));
+}
+
+void TopLevel::openNetFile( const KURL &u)
+{
+ if ( !u.isValid() )
+ {
+ KMessageBox::error(this, i18n("Malformed URL"));
+ return;
+ }
+
+ if ( u.isLocalFile() )
+ {
+ QString string = i18n("Loading '%1'").arg(u.path());
+ statusbar->message(string);
+ openadd( u.path());
+ statusbar->clear();
+ }
+ else
+ {
+ statusbar->message(i18n("Downloading..."));
+ QString tmpFile = QString::null;
+ if ( KIO::NetAccess::download( u, tmpFile, this ) )
+ {
+ openadd( tmpFile );
+ setCaption( u.prettyURL() );
+ }
+ statusbar->clear();
+ KIO::NetAccess::removeTempFile( tmpFile );
+ }
+}
+
+void TopLevel::dragEnterEvent( QDragEnterEvent * event)
+{
+ event->accept(KURLDrag::canDecode(event));
+}
+
+void TopLevel::dropEvent( QDropEvent * event)
+{
+
+ KURL::List list;
+
+ if (KURLDrag::decode(event, list) && !list.isEmpty())
+ {
+ // Load the first file in this window
+ const KURL &url = list.first();
+ openNetFile( url );
+ }
+}
+
+void SetupDisplay(){
+
+ if(display_is_setup){
+ return;
+ }
+
+ display_is_setup = TRUE;
+
+ xpos = ypos = ox = oy = 0;
+ ExpectConfNotify = 1;
+
+ /* XSizeHints size_hints;*/
+
+ Win = XCreateSimpleWindow(qtdisplay,qtwin,1,1,
+ 1,1,
+ 0,
+ BlackPixel(qtdisplay,XDefaultScreen(qtdisplay)),
+ WhitePixel(qtdisplay,XDefaultScreen(qtdisplay)));
+
+ PaintGC = XCreateGC(qtdisplay, Win, 0L, (XGCValues *) NULL);
+ XSetForeground(qtdisplay, PaintGC, BlackPixel(qtdisplay, XDefaultScreen(qtdisplay) ));
+ XSetBackground(qtdisplay, PaintGC, WhitePixel(qtdisplay, XDefaultScreen(qtdisplay) ));
+ XSetFunction(qtdisplay, PaintGC, GXcopy);
+ WorkCursor = XCreateFontCursor(qtdisplay, XC_watch);
+ //ReadyCursor = XCreateFontCursor(qtdisplay, XC_plus);
+ ReadyCursor = XCreateFontCursor(qtdisplay, XC_hand2);
+ MoveCursor = XCreateFontCursor(qtdisplay, XC_fleur);
+ LRCursor = XCreateFontCursor(qtdisplay, XC_sb_h_double_arrow);
+ UDCursor = XCreateFontCursor(qtdisplay, XC_sb_v_double_arrow);
+
+ XSelectInput(qtdisplay, Win, Button2MotionMask | ButtonPressMask |
+ ButtonReleaseMask | ExposureMask | KeyPressMask |
+ SubstructureNotifyMask | LeaveWindowMask | OwnerGrabButtonMask |
+ StructureNotifyMask);
+
+ XMapRaised(qtdisplay, Win);
+
+ XDefineCursor(qtdisplay, Win, ReadyCursor);
+ XFlush(qtdisplay);
+
+ memset(Images, 0, sizeof(Images));
+
+ // Start at half the Size
+ oz = 1;
+}
+
+void TopLevel::handle_X_event(XEvent Event)
+{
+ if(!thispage || !Image || !faxqtwin || !display_is_setup)
+ return;
+
+ bool putimage = false; // Do we actually have to write the image to the scree?
+
+ do {
+ switch(Event.type) {
+ case MappingNotify:
+ XRefreshKeyboardMapping((XMappingEvent *)(&Event));
+ break;
+
+ case LeaveNotify:
+ /* buttondown = false;
+ XDefineCursor(qtdisplay, Win, ReadyCursor);
+ XFlush(qtdisplay);*/
+ break;
+ case Expose:
+ {
+
+ if(Event.xexpose.count != 0)
+ break;
+
+ if(!Image)
+ break;
+
+ putimage = TRUE;
+ }
+ break;
+
+ case KeyPress:
+ if (ExpectConfNotify &&
+ (Event.xkey.time < (Lasttime + PATIENCE)))
+ break;
+ Lasttime = Event.xkey.time;
+ ExpectConfNotify = 0;
+ switch(XKeycodeToKeysym(qtdisplay, Event.xkey.keycode, 0)) {
+ case XK_m:
+ mirrorPage();
+ if (Event.xkey.state & ShiftMask)
+ TurnFollowing(TURN_M, thispage->next);
+ break;
+ case XK_o:
+ zoomout();
+ break;
+
+ case XK_i:
+ zoomin();
+ break;
+
+ case XK_Up:
+ ypos-= qwindow_height / 3;
+ putimage = TRUE;
+ break;
+ case XK_Down:
+ ypos+= qwindow_height / 3;
+ putimage = TRUE;
+ break;
+ case XK_Left:
+ xpos-= qwindow_width / 4;
+ putimage = TRUE;
+ break;
+ case XK_Right:
+ xpos+= qwindow_width / 4;
+ putimage = TRUE;
+ break;
+ case XK_Home:
+ case XK_R7:
+ if (Event.xkey.state & ShiftMask) {
+ thispage = firstpage;
+ newPage();
+ resizeView();
+ putImage();
+ break;
+ }
+ xpos= 0;
+ ypos= 0;
+ putImage();
+ break;
+ case XK_End:
+ case XK_R13:
+ if (Event.xkey.state & ShiftMask) {
+ thispage = lastpage;
+ newPage();
+ resizeView();
+ putImage();
+ break;
+ }
+ xpos= Image->width;
+ ypos= Image->height;
+ putImage();
+ break;
+ case XK_l:
+ case XK_r:
+ rotatePage();
+ if (Event.xkey.state & ShiftMask)
+ TurnFollowing(TURN_L, thispage->next);
+ break;
+ case XK_p:
+ case XK_minus:
+ case XK_Prior:
+ case XK_R9:
+ case XK_BackSpace:
+ prevPage();
+ break;
+ case XK_n:
+ case XK_plus:
+ case XK_space:
+ case XK_Next:
+ case XK_R15:
+ nextPage();
+ break;
+ case XK_u:
+ flipPage();
+ if (Event.xkey.state & ShiftMask)
+ TurnFollowing(TURN_U, thispage->next);
+ break;
+
+ case XK_q:
+ if (viewpage) {
+ thispage = viewpage;
+ viewpage = NULL;
+ newPage();
+ resizeView();
+ putImage();
+ }
+
+ }
+
+ break;
+
+ case ButtonPress:
+
+ if (ExpectConfNotify && (Event.xbutton.time < (Lasttime + PATIENCE)))
+ break;
+
+ Lasttime = Event.xbutton.time;
+ ExpectConfNotify = 0;
+
+
+ switch (Event.xbutton.button) {
+
+ case Button1:
+ buttondown = true;
+
+ switch (((Image->width > qwindow_width)<<1) |
+ (Image->height > qwindow_height)) {
+ case 0:
+ break;
+ case 1:
+ XDefineCursor(qtdisplay, Win, UDCursor);
+ break;
+ case 2:
+ XDefineCursor(qtdisplay, Win, LRCursor);
+ break;
+ case 3:
+ XDefineCursor(qtdisplay, Win, MoveCursor);
+ }
+
+ XFlush(qtdisplay);
+ offx = Event.xbutton.x;
+ offy = Event.xbutton.y;
+ break;
+
+ }
+
+ break;
+
+ case MotionNotify:
+ if(!buttondown)
+ break;
+ do {
+
+ nx = Event.xmotion.x;
+ ny = Event.xmotion.y;
+
+
+ } while (XCheckTypedEvent(qtdisplay, MotionNotify, &Event));
+
+
+ xpos+= offx - nx;
+ ypos+= offy - ny;
+
+ offx = nx;
+ offy = ny;
+
+ putimage = TRUE;
+
+ break;
+
+ case ButtonRelease:
+
+ if (Event.xbutton.button == Button1) {
+
+ buttondown = false;
+ XDefineCursor(qtdisplay, Win, ReadyCursor);
+ XFlush(qtdisplay);
+ }
+
+ }
+
+ } while (XCheckWindowEvent(qtdisplay, Win, KeyPressMask|ButtonPressMask, &Event));
+
+ if(putimage == TRUE) {
+ Refresh = Resize = 1;
+ putImage();
+ }
+}
+
+void TopLevel::rotatePage()
+{
+ if(!thispage || !Image || !faxqtwin || !display_is_setup)
+ return;
+
+ XDefineCursor(qtdisplay, Win, WorkCursor);
+ XFlush(qtdisplay);
+
+ XImage *newrotimage = RotImage(Images[0]);
+
+ XDefineCursor(qtdisplay, Win, ReadyCursor);
+
+ if(newrotimage == NULL){ // out of memory
+ return;
+ }
+
+ thispage->extra = Images[0] = newrotimage;
+ thispage->orient ^= TURN_L;
+
+ freeImages();
+ Image = generateZoomImages(oz);
+
+ { int t = xpos ; xpos= ypos; ypos= t; }
+
+ Refresh = Resize = 1;
+
+ putImage();
+}
+
+void TopLevel::flipPage()
+{
+ if(!thispage || !Image || !faxqtwin || !display_is_setup)
+ return;
+
+ XDefineCursor(qtdisplay, Win, WorkCursor);
+ XFlush(qtdisplay);
+
+ XImage *newflipimage = FlipImage(Images[0]);
+
+ XDefineCursor(qtdisplay, Win, ReadyCursor);
+
+ if(newflipimage == NULL){ // out of memory
+ return;
+ }
+
+ thispage->extra = Images[0] = newflipimage;
+ thispage->orient ^= TURN_U;
+
+ freeImages();
+ Image = generateZoomImages(oz);
+
+ Refresh = Resize = 1;
+ putImage();
+}
+
+void TopLevel::mirrorPage()
+{
+ if(!thispage || !Image || !faxqtwin || !display_is_setup)
+ return;
+
+ XDefineCursor(qtdisplay, Win, WorkCursor);
+ XFlush(qtdisplay);
+
+ XImage *newmirror = MirrorImage(Images[0]);
+
+ XDefineCursor(qtdisplay, Win, ReadyCursor);
+
+ if(newmirror == NULL){ // out of memory
+ return;
+ }
+ thispage->extra = Images[0] = newmirror;
+ thispage->orient ^= TURN_M;
+
+ freeImages();
+ Image = generateZoomImages(oz);
+
+ Refresh = Resize = 1;
+ putImage();
+}
+
+void TopLevel::scrollHorz(int){
+
+ if(!Image)
+ return;
+
+ // printf("hsb value: %d\n",hsb->value());
+ xpos= hsb->value() + qwindow_width/2;
+
+ Refresh = 1;
+ putImage();
+}
+
+void TopLevel::scrollVert(int ){
+
+ if(!Image)
+ return;
+
+ // printf("vsb value: %d\n",vsb->value());
+ ypos= vsb->value() + qwindow_height/2;
+
+ Refresh = 1;
+ putImage();
+}
+
+void TopLevel::lastPage()
+{
+ if(!thispage)
+ return;
+
+ if ( thispage->next )
+ {
+ while(thispage->next != NULL)
+ thispage = thispage->next;
+
+ newPage();
+ resizeView();
+ putImage();
+ }
+
+ updateGoActions();
+}
+
+void TopLevel::firstPage()
+{
+ if(!thispage)
+ return;
+
+ if ( thispage->prev )
+ {
+ while(thispage->prev != NULL)
+ thispage = thispage->prev;
+
+ newPage();
+ resizeView();
+ putImage();
+ }
+
+ updateGoActions();
+}
+
+void TopLevel::nextPage()
+{
+ if(!thispage)
+ return;
+
+ if (thispage->next)
+ {
+ thispage = thispage->next;
+
+ newPage();
+ resizeView();
+ putImage();
+ }
+
+ updateGoActions();
+}
+
+void TopLevel::prevPage()
+{
+ if(!thispage)
+ return;
+
+ if (thispage->prev)
+ {
+ thispage = thispage->prev;
+
+ newPage();
+ resizeView();
+ putImage();
+ }
+
+ updateGoActions();
+}
+
+void TopLevel::newPage(){
+
+ if(!display_is_setup)
+ SetupDisplay();
+
+ XDefineCursor(qtdisplay, Win, WorkCursor);
+ XFlush(qtdisplay);
+
+ freeImages();
+
+ int k = -1;
+
+ if(!thispage) {
+ XDefineCursor(qtdisplay, Win, ReadyCursor);
+ return;
+ }
+
+ if (Pimage(thispage) == NULL){
+
+ while((k != 0) && (k != 3) && (k !=1))
+ k = GetImage(thispage);
+
+ }
+
+ if (k == 3 ){
+
+ XDefineCursor(qtdisplay, Win, ReadyCursor);
+ FreeFax();
+ /* KMessageBox::sorry(i18n("Bad fax file k=3"));*/
+ return;
+ }
+
+ if (k == 0 ){
+
+ XDefineCursor(qtdisplay, Win, ReadyCursor);
+ FreeFax();
+ /* KMessageBox::sorry(i18n("Bad fax file k=0"));*/
+ return;
+ }
+
+ Image = Images[0] = Pimage(thispage);
+
+ setCaption(QFile::decodeName(thispage->name));
+
+ Image = generateZoomImages(oz);
+
+ PaneWidth = Image->width;
+ PaneHeight = Image->height;
+ Refresh = 1;
+
+ XDefineCursor(qtdisplay, Win, ReadyCursor);
+ uiUpdate();
+
+}
+
+
+void TopLevel::faxClose()
+{
+ FreeFax();
+
+ setCaption(i18n("KFax"));
+ // TODO replace this with unmapping the window.
+ if(display_is_setup)
+ XResizeWindow(qtdisplay,Win,1,1); // we want a clear gray background.
+
+ resizeView();
+ vsb->hide();
+ hsb->hide();
+
+ fileURL = QString::null;
+
+ updateActions();
+}
+
+void TopLevel::FreeFax()
+{
+ if(display_is_setup)
+ XClearWindow(qtdisplay, Win);
+
+ freeImages();
+
+ pagenode *pn;
+ for (pn = firstpage; pn; pn = pn->next){
+ if(Pimage(pn)){
+ FreeImage(Pimage(pn));
+ pn->extra = NULL;
+ }
+ }
+
+ Image = NULL;
+
+ for (pn = firstpage; pn; pn = pn->next){
+ if(pn->pathname){
+ free(pn->pathname);
+ }
+ }
+
+
+ if(firstpage){
+ for(pn = firstpage->next; pn; pn = pn->next){
+ if(pn->prev){
+ free(pn->prev);
+ }
+ }
+ }
+
+ if(lastpage)
+ free(lastpage);
+
+ firstpage = lastpage = viewpage = thispage = auxpage = NULL;
+
+ uiUpdate();
+}
+
+void TopLevel::uiUpdate(){
+
+ if(thispage){
+
+ struct pagenode *pn ;
+ int pages = 0;
+ int currentpage = 0;
+
+ for(pn = firstpage; pn ; pn = pn->next){
+ pages ++;
+ if (thispage == pn)
+ currentpage = pages;
+ }
+
+ QString pagestr = i18n("Page: %1 of %2").arg(currentpage).arg(pages);
+
+ statusbar->changeItem(pagestr, ID_PAGE_NO);
+
+ if(Image){
+ QString wh = i18n("W: %1 H: %2").arg(Image->width).arg(Image->height);
+ statusbar->changeItem(wh, ID_INS_OVR);
+ }
+
+ QString resolution = i18n("Res: %1").arg(thispage->vres?i18n("Fine"):i18n("Normal"));
+ // TODO: resolution += QString("%1x%2").arg(thispage->dpiX).arg(thispage->dpiY);
+ statusbar->changeItem(resolution, ID_GENERAL);
+
+ statusbar->changeItem(thispage->name, ID_FNAME);
+
+ QString typestring;
+
+ if(thispage->type == FAX_TIFF){
+ typestring = i18n("Type: Tiff ");
+ }
+ else if ( thispage->type == FAX_RAW){
+ typestring = i18n("Type: Raw ");
+ }
+
+ if ( thispage->expander == g31expand )
+ typestring += "G3";
+
+ if ( thispage->expander == g32expand )
+ typestring += "G3 2D";
+
+ if ( thispage->expander == g4expand )
+ typestring += "G4";
+
+ statusbar->changeItem(typestring,ID_TYPE);
+ updateActions();
+ }
+}
+
+void kfaxerror(const QString& title, const QString& error){
+ KMessageBox::error(toplevel, error, title);
+}
+
+void TopLevel::putImage()
+{
+
+ // TODO do I really need to set Refresh or Resize to 1 , is there
+ // really still someonce calling this with out haveing set Refresh or Resize to 1?
+
+ if ( !Image || !display_is_setup || !thispage )
+ return;
+
+ if ( qwindow_width > Image->width){
+ xpos= Image->width/2;
+ }
+ else{
+ if(xpos< qwindow_width/2){
+ xpos = qwindow_width/2;
+ }
+ else{
+ if(xpos> Image->width - qwindow_width/2){
+ xpos= Image->width - qwindow_width/2;
+ }
+
+ }
+ }
+
+ if ( qwindow_height > Image->height){
+ ypos= Image->height/2;
+ }
+ else{
+ if(ypos< qwindow_height/2){
+ ypos = qwindow_height/2;
+ }
+ else{
+ if(ypos> Image->height - qwindow_height/2){
+ ypos= Image->height - qwindow_height/2;
+ }
+
+ }
+ }
+
+ if (xpos!= ox || ypos!= oy || Refresh || Resize){
+
+ /* In the following we use qwindow_height -1 etc since the main view
+ has a sunken frame and I need to offset by 1 pixel to the right and
+ one pixel down so that I don't paint my fax into the border of the frame*/
+
+ XResizeWindow(qtdisplay,Win,QMIN(qwindow_width -1,Image->width ),
+ QMIN(qwindow_height -1,Image->height ));
+
+ XPutImage(qtdisplay, Win, PaintGC, Image,
+ QMAX(xpos - qwindow_width/2,0), QMAX(ypos - qwindow_height/2,0),
+ 0, 0, QMIN(qwindow_width -1,Image->width) ,
+ QMIN(qwindow_height -1,Image->height) );
+
+ vsb->setValue(QMAX(ypos - qwindow_height/2,0));
+ hsb->setValue(QMAX(xpos - qwindow_width/2,0));
+
+ XFlush(qtdisplay);
+ }
+
+ ox = xpos;
+ oy = ypos;
+
+ Resize = Refresh = 0;
+
+}
+
+void TopLevel::faxoptions(){
+
+ OptionsDialog * opd = new OptionsDialog(this, "options");
+ opd->setWidgets(&fop);
+
+ if(opd->exec()){
+
+ struct optionsinfo *newops;
+ newops = opd->getInfo();
+
+ fop.resauto = newops->resauto;
+ fop.geomauto = newops->geomauto;
+ fop.width = newops->width;
+ fop.height = newops->height;
+ fop.fine = newops->fine;
+ fop.landscape= newops->landscape;
+ fop.flip = newops->flip;
+ fop.invert = newops->invert;
+ fop.lsbfirst = newops->lsbfirst;
+ fop.raw = newops->raw;
+
+ setFaxDefaults();
+
+ writeSettings();
+ }
+
+ delete opd;
+}
+
+void setFaxDefaults(){
+
+ // fop is called in readSettings, so this can't be
+ // called after a TopLevel::readSettings()
+
+ if(have_cmd_opt ) // we have commad line options all kfaxrc defaults are
+ return; // overridden
+
+ if(fop.resauto == 1)
+ defaultpage.vres = -1;
+ else
+ defaultpage.vres = fop.fine;
+
+ if(fop.geomauto == 1){
+ defaultpage.width = defaultpage.height = 0;
+ }
+ else{
+ defaultpage.width = fop.width;
+ defaultpage.height = fop.height;
+ }
+
+ if(fop.landscape)
+ defaultpage.orient |= TURN_L;
+
+ if(fop.flip)
+ defaultpage.orient |= TURN_U;
+
+ defaultpage.inverse = fop.invert;
+ defaultpage.lsbfirst = fop.lsbfirst;
+
+ switch (fop.raw) {
+ case 2: defaultpage.expander = g32expand;
+ break;
+ case 4: defaultpage.expander = g4expand;
+ break;
+ default:defaultpage.expander = g31expand;
+ }
+
+}
+
+static const char description[] =
+ I18N_NOOP("KDE G3/G4 Fax Viewer");
+
+static KCmdLineOptions options[] =
+{
+ {"f", 0, 0 },
+ {"fine", I18N_NOOP( "Fine resolution" ), 0 },
+ {"n", 0, 0 },
+ {"normal", I18N_NOOP( "Normal resolution" ), 0 },
+ {"height", I18N_NOOP( "Height (number of fax lines)" ), 0 },
+ {"w", 0, 0 },
+ {"width", I18N_NOOP( "Width (dots per fax line)" ), 0 },
+ {"l", 0, 0 },
+ {"landscape", I18N_NOOP( "Turn image 90 degrees (landscape mode)" ), 0 },
+ {"u", 0, 0 },
+ {"upsidedown", I18N_NOOP( "Turn image upside down" ), 0 },
+ {"i", 0, 0 },
+ {"invert", I18N_NOOP( "Invert black and white" ), 0 },
+ {"m", 0, 0 },
+ {"mem <bytes>", I18N_NOOP( "Limit memory use to 'bytes'" ), "8M" },
+ {"r", 0, 0 },
+ {"reverse", I18N_NOOP( "Fax data is packed lsb first" ), 0 },
+ {"2" , I18N_NOOP( "Raw files are g3-2d" ), 0 },
+ {"4", I18N_NOOP( "Raw files are g4" ), 0 },
+ {"+file(s)", I18N_NOOP( "Fax file(s) to show" ), 0 },
+ KCmdLineLastOption
+};
+
+int main (int argc, char **argv)
+{
+ KAboutData aboutData( "kfax", I18N_NOOP("KFax"),
+ KFAXVERSION, description, KAboutData::License_GPL,
+ "(c) 1997-98 Bernd Johannes Wuebben");
+ aboutData.addAuthor( "Bernd Johannes Wuebben", 0, "wuebben@kde.org" );
+ aboutData.addCredit( "Nadeem Hasan", I18N_NOOP( "UI Rewrite, lots of code "
+ "cleanups and fixes" ), "nhasan@kde.org" );
+ aboutData.addCredit( "Helge Deller", I18N_NOOP( "Printing Rewrite, lots of code "
+ "cleanups and fixes"), "deller@kde.org" );
+
+ KCmdLineArgs::init(argc, argv, &aboutData);
+ KCmdLineArgs::addCmdLineOptions( options );
+
+ MyApp a;
+
+ qtdisplay = qt_xdisplay();
+
+ viewfaxmain();
+
+ toplevel = new TopLevel();
+ toplevel->show();
+
+ startingup = 1;
+ a.processEvents();
+ a.flushX();
+
+ startingup = 0;
+
+ faxinit();
+ if(!have_no_fax){
+
+ thispage = firstpage;
+
+ toplevel->newPage();
+ toplevel->resizeView();
+ //TODO : I don't think I need this putImage();
+ toplevel->putImage();
+ }
+
+ toplevel->uiUpdate();
+
+ return a.exec ();
+}
+
+
+#include "kfax.moc"
diff --git a/kfax/kfax.desktop b/kfax/kfax.desktop
new file mode 100644
index 00000000..eefd8b87
--- /dev/null
+++ b/kfax/kfax.desktop
@@ -0,0 +1,86 @@
+[Desktop Entry]
+MimeType=image/fax-g3;image/tiff;
+GenericName=Fax Viewer
+GenericName[af]=Faks Aansig
+GenericName[ar]=عارض الفاكس
+GenericName[bg]=Преглед на факсове
+GenericName[br]=Gweler faks
+GenericName[bs]=Preglednik faxova
+GenericName[ca]=Visualitzador de fax
+GenericName[cs]=Prohlížeč faxů
+GenericName[cy]=Gwelydd Ffacs
+GenericName[da]=Fax-fremviser
+GenericName[de]=Faxbetrachter
+GenericName[el]=Προβολέας φαξ
+GenericName[eo]=Faksrigardilo
+GenericName[es]=Visor de faxes
+GenericName[et]=Fakside vaataja
+GenericName[eu]=Fax ikustailua
+GenericName[fa]=مشاهده‌گر دورنگار
+GenericName[fi]=Faksinäytin
+GenericName[fr]=Afficheur de fax
+GenericName[gl]=Visor de fax
+GenericName[he]=מציג פקסים
+GenericName[hi]=फ़ैक्स प्रदर्शक
+GenericName[hr]=Preglednik faksova
+GenericName[hu]=Faxnézegető
+GenericName[is]=Fax sjá
+GenericName[it]=Visore di fax
+GenericName[ja]=ファクスビューア
+GenericName[kk]=Факсты қарау
+GenericName[km]=កម្មវិធី​មើល​ទូរសារ
+GenericName[lt]=Faksų žiūriklis
+GenericName[lv]=Faksu Skatītājs
+GenericName[ms]=Pemapar Faks
+GenericName[nb]=Faksfremviser
+GenericName[nds]=Faxkieker
+GenericName[ne]=फ्याक्स द्रष्टा
+GenericName[nl]=Faxweergaveprogramma
+GenericName[nn]=Faksvisar
+GenericName[pa]=ਫੈਕਸ ਦਰਸ਼ਕ
+GenericName[pl]=Przeglądarka faksów
+GenericName[pt]=Visualizador de Faxes
+GenericName[pt_BR]=Visualizador de Faxes
+GenericName[ro]=Vizualizor FAX
+GenericName[ru]=Просмотр факсов
+GenericName[se]=Fáksačájeheaddji
+GenericName[sk]=Prehliadač faxov
+GenericName[sl]=Pregledovalnik faksov
+GenericName[sr]=Приказивач факсова
+GenericName[sr@Latn]=Prikazivač faksova
+GenericName[sv]=Faxvisare
+GenericName[ta]=ஃபாக்ஸ் காட்சி
+GenericName[tg]=Хондани факс
+GenericName[th]=เครื่องมือแสดงโทรสารของ KDE
+GenericName[tr]=Faks Görüntüleyici
+GenericName[uk]=Переглядач факсів
+GenericName[uz]=Faks koʻruvchi
+GenericName[uz@cyrillic]=Факс кўрувчи
+GenericName[ven]=Muvhoni wa Fekisi
+GenericName[wa]=Håyneu di facs
+GenericName[xh]=Umboniseli Wefax
+GenericName[zh_CN]=传真查看器
+GenericName[zh_HK]=傳真檢視器
+GenericName[zh_TW]=傳真檢視器
+GenericName[zu]=Umbonisi wefax
+Name=KFax
+Name[af]=K-faks
+Name[ar]=برنامج KFax
+Name[cy]=KFfacs
+Name[eo]=Faksrigardilo
+Name[hi]=के-फ़ैक्स
+Name[lv]=KFakss
+Name[ne]=केडीई फ्याक्स
+Name[sv]=Kfax
+Name[ta]=கேஃபாக்ஸ்
+Name[ven]=Fekisi ya K
+Name[wa]=KFacs
+Name[zh_TW]=KFax 傳真檢視器
+Exec=kfax %f -caption "%c" %i %m
+Icon=kfax
+Path=
+Type=Application
+Terminal=false
+X-KDE-StartupNotify=true
+X-DCOP-ServiceType=Multi
+Categories=Qt;KDE;Graphics;X-KDE-More;
diff --git a/kfax/kfax.h b/kfax/kfax.h
new file mode 100644
index 00000000..506a1452
--- /dev/null
+++ b/kfax/kfax.h
@@ -0,0 +1,159 @@
+ /*
+
+ $Id$
+
+ Requires the Qt widget libraries, available at no cost at
+ http://www.troll.no
+
+ Copyright (C) 1997 Bernd Johannes Wuebben
+ wuebben@math.cornell.edu
+
+
+ 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 _KFAX_H_
+#define _KFAX_H_
+
+#include <kapplication.h>
+#include <kmainwindow.h>
+#include <qptrlist.h>
+#include <kurl.h>
+
+#define Pimage(p) ((XImage *)(p)->extra)
+
+class QPopupMenu;
+class KConfig;
+class KStatusBar;
+class KAction;
+class KRecentFilesAction;
+class KPrinter;
+class QPainter;
+class QScrollBar;
+
+typedef KToolBar::BarPosition BarPosition;
+
+class MyApp:public KApplication {
+public:
+ virtual bool x11EventFilter( XEvent * );
+};
+
+class TopLevel : public KMainWindow
+{
+ Q_OBJECT
+
+
+public:
+
+ TopLevel( QWidget *parent=0, const char *name=0 );
+ ~TopLevel();
+
+ void openNetFile( const KURL& _url);
+ void saveNetFile( const KURL& _url );
+
+ static QPtrList<TopLevel> windowList;
+ QPopupMenu *right_mouse_button, *colors;
+
+ void handle_X_event(XEvent Event);
+ void putImage();
+
+protected:
+
+ void resizeEvent( QResizeEvent * );
+ void wheelEvent( QWheelEvent * );
+ void dragEnterEvent( QDragEnterEvent * event );
+ void dropEvent( QDropEvent * event );
+
+ void updateActions();
+ void updateGoActions();
+ void updateZoomActions();
+
+ void zoom( int );
+
+ void readSettings();
+ void writeSettings();
+ void setupActions();
+ void setupMenuBar();
+ void setupToolBar();
+ void setupEditWidget();
+ void setupStatusBar();
+
+ bool queryClose();
+
+private:
+
+ QFrame *faxqtwin;
+
+ int indentID;
+ QColor forecolor;
+ QColor backcolor;
+
+ KURL fileURL;
+ KStatusBar *statusbar;
+
+ KRecentFilesAction *actRecent;
+ KAction *actAdd, *actSave, *actSaveAs, *actPrint;
+ KAction *actSize, *actZoomIn, *actZoomOut, *actRotate, *actMirror;
+ KAction *actFlip, *actNext, *actPrev, *actFirst, *actLast;
+
+ int open_mode;
+
+ KConfig *config;
+
+ QScrollBar *hsb;
+ QScrollBar *vsb;
+ QFrame* mainpane;
+
+ void printIt( KPrinter &printer, QPainter &painter );
+ bool loadAllPages( int &numpages, int &currentpage );
+
+public slots:
+
+ void faxOpen( const KURL & );
+ void faxOpen();
+ void faxAdd();
+ void faxAdd( const KURL & );
+ void faxClose();
+ void print();
+ void zoomin();
+ void zoomout();
+ void actualSize();
+ void resizeView();
+ void faxSave();
+ void faxSaveAs();
+
+ void faxoptions();
+ void rotatePage();
+ void mirrorPage();
+ void flipPage();
+ void nextPage();
+ void prevPage();
+ void newPage();
+ void firstPage();
+ void lastPage();
+ void uiUpdate();
+
+ void openadd(QString filename);
+ void FreeFax();
+ void scrollHorz(int);
+ void scrollVert(int);
+};
+
+void kfaxerror(const QString&, const QString&);
+void loadfile(QString filename);
+
+#endif // _KFAX_H_
+
diff --git a/kfax/kfax.tif b/kfax/kfax.tif
new file mode 100644
index 00000000..85eec6bb
--- /dev/null
+++ b/kfax/kfax.tif
Binary files differ
diff --git a/kfax/kfax_printsettings.cpp b/kfax/kfax_printsettings.cpp
new file mode 100644
index 00000000..02aa4050
--- /dev/null
+++ b/kfax/kfax_printsettings.cpp
@@ -0,0 +1,98 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (c) 2005 Helge Deller <deller@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#include "kfax_printsettings.h"
+
+#include <klocale.h>
+#include <qcheckbox.h>
+#include <qlayout.h>
+#include <qwhatsthis.h>
+
+KFAXPrintSettings::KFAXPrintSettings(QWidget *parent, const char *name)
+: KPrintDialogPage(parent, name)
+{
+ QString whatsThisScaleFullPage = i18n( "<qt>"
+ "<p><strong>'Ignore Paper Margins'</strong></p>"
+ "<p>"
+ "If this checkbox is enabled, the paper margins will be ignored "
+ "and the fax will be printed on the full paper size."
+ "</p>"
+ "<p>"
+ "If this checkbox is disabled, KFax will respect the standard paper "
+ "margins and print the fax inside this printable area."
+ "</p>"
+ " </qt>" );
+ QString whatsThisCenterHorz = i18n( "<qt>"
+ "<p><strong>'Horizontal centered'</strong></p>"
+ "<p>"
+ "If this checkbox is enabled, the fax will be centered horizontally "
+ "on the page."
+ "</p>"
+ "<p>"
+ "If this checkbox is disabled, the fax will be printed at the left "
+ "side of the page."
+ "</p>"
+ " </qt>" );
+ QString whatsThisCenterVert = i18n( "<qt>"
+ "<p><strong>'Vertical centered'</strong></p>"
+ "<p>"
+ "If this checkbox is enabled, the fax will be centered vertically "
+ "on the page."
+ "</p>"
+ "<p>"
+ "If this checkbox is disabled, the fax will be printed at the top "
+ "of the page."
+ "</p>"
+ " </qt>" );
+
+ setTitle(i18n("&Layout"));
+
+ m_scaleFullPage = new QCheckBox(i18n("Ignore paper margins"), this);
+ QWhatsThis::add(m_scaleFullPage, whatsThisScaleFullPage);
+ m_center_horz = new QCheckBox(i18n("Horizontal centered"), this);
+ QWhatsThis::add(m_center_horz, whatsThisCenterHorz);
+ m_center_vert = new QCheckBox(i18n("Vertical centered"), this);
+ QWhatsThis::add(m_center_vert, whatsThisCenterVert);
+
+ QVBoxLayout *l0 = new QVBoxLayout(this, 0, 10);
+ l0->addWidget(m_scaleFullPage);
+ l0->addWidget(m_center_horz);
+ l0->addWidget(m_center_vert);
+ l0->addStretch(1);
+}
+
+KFAXPrintSettings::~KFAXPrintSettings()
+{
+}
+
+void KFAXPrintSettings::getOptions(QMap<QString,QString>& opts, bool /*incldef*/)
+{
+ opts[APP_KFAX_SCALE_FULLPAGE] = (m_scaleFullPage->isChecked() ? "true" : "false");
+ opts[APP_KFAX_CENTER_HORZ] = (m_center_horz->isChecked() ? "true" : "false");
+ opts[APP_KFAX_CENTER_VERT] = (m_center_vert->isChecked() ? "true" : "false");
+}
+
+void KFAXPrintSettings::setOptions(const QMap<QString,QString>& opts)
+{
+ m_scaleFullPage->setChecked(opts[APP_KFAX_SCALE_FULLPAGE] == "true");
+ m_center_horz->setChecked(opts[APP_KFAX_CENTER_HORZ] != "false");
+ m_center_vert->setChecked(opts[APP_KFAX_CENTER_VERT] == "true");
+}
+
+#include "kfax_printsettings.moc"
diff --git a/kfax/kfax_printsettings.h b/kfax/kfax_printsettings.h
new file mode 100644
index 00000000..e43e3530
--- /dev/null
+++ b/kfax/kfax_printsettings.h
@@ -0,0 +1,47 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (c) 2005 Helge Deller <deller@kde.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License version 2 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ **/
+
+#ifndef KFAX_PRINTSETTINGS_H
+#define KFAX_PRINTSETTINGS_H
+
+#include <kdeprint/kprintdialogpage.h>
+
+class QCheckBox;
+
+#define APP_KFAX_SCALE_FULLPAGE "app-kfax-scalefullpage"
+#define APP_KFAX_CENTER_HORZ "app-kfax-center-horz"
+#define APP_KFAX_CENTER_VERT "app-kfax-center-vert"
+
+class KFAXPrintSettings : public KPrintDialogPage
+{
+ Q_OBJECT
+public:
+ KFAXPrintSettings(QWidget *parent = 0, const char *name = 0);
+ ~KFAXPrintSettings();
+
+ void getOptions(QMap<QString,QString>& opts, bool incldef = false);
+ void setOptions(const QMap<QString,QString>& opts);
+
+private:
+ QCheckBox *m_scaleFullPage;
+ QCheckBox *m_center_horz;
+ QCheckBox *m_center_vert;
+};
+
+#endif
diff --git a/kfax/kfaxlogo.xpm b/kfax/kfaxlogo.xpm
new file mode 100644
index 00000000..8adb7087
--- /dev/null
+++ b/kfax/kfaxlogo.xpm
@@ -0,0 +1,134 @@
+/* XPM */
+static char *magick[] = {
+/* columns rows colors chars-per-pixel */
+"90 120 8 1",
+" c #ffffff",
+". c #595959",
+"X c #808080",
+"o c #c0c0c0",
+"O c #000000",
+"+ c #dfdfdf",
+"@ c #303030",
+"# c #a0a0a4",
+/* pixels */
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" .....X ...... o....o ",
+" OOOOO. oOOOOOX +@OOOOOO@+ ",
+" OOOOO. .OOOO@ +@OOOOOOOO@+ ",
+" OOOOO. XOOOOO# @OOOOOOOOOO# ",
+" OOOOO. @OOOO@ #OOOOOOOOO@+ ",
+" OOOOO. XOOOOOo .OOOOO.@O. o...X+ o..... ..... ",
+" OOOOO.+@OOOO. OOOOO. o #.OOOOOO. #OOOOO OOOOO ",
+" OOOOO..OOOOO+ OOOOO. #OOOOOOOOO@+ #OOOOO OOOOO ",
+" OOOOO@OOOOO. OOOOO. +OOOOOOOOOOO. #OOOOO OOOOO ",
+" OOOOO@OOOOO# OOOOO@.o @OOOOOOOOOOOOo OOOOO++OOOOO ",
+" OOOOO.@OOOO. OOOOOOO# OOOOOO..OOOOO. .OOOO@@OOOO. ",
+" OOOOO.#OOOOOo OOOOOOO# #OOOOO# @OOOOO +.OOOOOOOO@+ ",
+" OOOOO. OOOOO@ OOOOOOO# #OOOO. #OOOOO .OOOOOOOO. ",
+" OOOOO. .OOOOOo OOOOOOO# oOOOO@ #OOOOO .OOOO@@OOOO. ",
+" OOOOO. +OOOOO@ OOOOO.#+ OOOOO@###OOOOO OOOOO++OOOO@ ",
+" OOOOO. @OOOOOo OOOOO. .OOOOOOO#OOOOO oOOOOO OOOOO ",
+" OOOOO. #OOOOO@ OOOOO. +@OOOOOO#OOOOO #OOOOO OOOOO ",
+" OOOOO. @OOOOOoOOOOO. o@OOOOO#OOOOO #OOOOO OOOOO ",
+" OOOOO. .OOOOO.OOOOO. +@OOOO#OOOOO #OOOOO OOOOO ",
+" #####o +####o######o o#.. ##### +##### ##### ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" "
+};
diff --git a/kfax/kfaxui.rc b/kfax/kfaxui.rc
new file mode 100644
index 00000000..35daf9f3
--- /dev/null
+++ b/kfax/kfaxui.rc
@@ -0,0 +1,28 @@
+<!DOCTYPE kpartgui>
+<kpartgui version="2" name="kfax">
+<MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="file_add_fax" append="open_merge"/>
+ </Menu>
+ <Menu name="view"><text>&amp;View</text>
+ <Action name="view_rotate"/>
+ <Action name="view_mirror"/>
+ <Action name="view_flip"/>
+ </Menu>
+</MenuBar>
+ <ToolBar noMerge="1" name="mainToolBar" >
+ <text>Main Toolbar</text>
+ <Action name="file_open" />
+ <Action name="file_save" />
+ <Action name="file_print" />
+ <Separator name="separator_2" />
+ <Action name="go_previous" />
+ <Action name="go_next" />
+ <Separator name="separator_1" />
+ <Action name="go_first" />
+ <Action name="go_last" />
+ <Separator name="separator_0" />
+ <Action name="view_zoom_in" />
+ <Action name="view_zoom_out" />
+ </ToolBar>
+</kpartgui>
diff --git a/kfax/options.cpp b/kfax/options.cpp
new file mode 100644
index 00000000..b8bf8067
--- /dev/null
+++ b/kfax/options.cpp
@@ -0,0 +1,374 @@
+/*
+ $Id$
+
+ Requires the Qt widget libraries, available at no cost at
+ http://www.troll.no
+
+ Copyright (C) 1996 Bernd Johannes Wuebben
+ wuebben@math.cornell.edu
+
+ 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 <stdio.h>
+
+#include <qlayout.h>
+#include <klocale.h>
+#include <knuminput.h>
+#include <qdir.h>
+#include <qprinter.h>
+#include <qframe.h>
+#include <qbuttongroup.h>
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qlistbox.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+#include <qscrollbar.h>
+#include <qtooltip.h>
+
+#include "kfax.h"
+#include "options.h"
+
+OptionsDialog::OptionsDialog( QWidget *parent, const char *name)
+ : KDialogBase( parent, name, true, i18n("Configure"), Ok|Cancel)
+{
+ QWidget *mainWidget = new QWidget(this);
+ setMainWidget(mainWidget);
+
+ QVBoxLayout *mainLayout = new QVBoxLayout(mainWidget, 0, spacingHint());
+
+ bg = new QGroupBox(mainWidget,"bg");
+ bg->setColumnLayout( 0, Qt::Horizontal );
+ mainLayout->addWidget( bg );
+
+ QVBoxLayout *vbl = new QVBoxLayout(bg->layout());
+
+ QHBoxLayout *hbl1 = new QHBoxLayout();
+
+ vbl->addLayout( hbl1 );
+
+ displaylabel = new QLabel(i18n("Display options:"), bg,"displaylabel");
+ displaylabel->setFixedSize( displaylabel->sizeHint() );
+ hbl1->addWidget( displaylabel );
+
+ landscape = new QCheckBox(i18n("Landscape"), bg,"Landscape");
+ landscape->setFixedSize( landscape->sizeHint() );
+ hbl1->addSpacing( 10 );
+ hbl1->addWidget( landscape );
+
+ flip = new QCheckBox(i18n("Upside down"), bg,"upsidedown");
+ flip->setFixedSize( flip->sizeHint() );
+ hbl1->addSpacing( 10 );
+ hbl1->addWidget( flip );
+
+ invert = new QCheckBox(i18n("Invert"), bg,"invert");
+ invert->setFixedSize( invert->sizeHint() );
+ hbl1->addSpacing( 10 );
+ hbl1->addWidget( invert );
+
+ vbl->addSpacing( 20 );
+
+ QHBoxLayout *hbl8 = new QHBoxLayout();
+ vbl->addLayout( hbl8 );
+ hbl8->addSpacing( 10 );
+
+ resgroup = new QButtonGroup(bg,"resgroup");
+ resgroup->setFrameStyle(QFrame::NoFrame);
+ hbl8->addWidget( resgroup );
+
+ QHBoxLayout *hbl2 = new QHBoxLayout(resgroup);
+
+ reslabel = new QLabel(i18n("Raw fax resolution:"),resgroup,"relabel");
+ hbl2->addWidget( reslabel );
+
+ resauto = new QRadioButton(i18n("Auto"),resgroup,"resauto");
+ hbl2->addSpacing( 20 );
+ hbl2->addWidget( resauto );
+
+ fine = new QRadioButton(i18n("Fine"),resgroup,"fine");
+ hbl2->addSpacing( 30 );
+ hbl2->addWidget( fine );
+
+ normal = new QRadioButton(i18n("Normal"),resgroup,"normal");
+ hbl2->addSpacing( 30 );
+ hbl2->addWidget( normal );
+
+ vbl->addSpacing( 20 );
+
+ QHBoxLayout *hbl3 = new QHBoxLayout();
+ vbl->addLayout( hbl3 );
+
+ lsblabel = new QLabel(i18n("Raw fax data are:"), bg,"lsblabel");
+ hbl3->addSpacing( 10 );
+ hbl3->addWidget( lsblabel );
+
+ lsb = new QCheckBox(i18n("LS-Bit first"), bg,"lsbitfirst");
+ hbl3->addSpacing( 10 );
+ hbl3->addWidget( lsb );
+
+ vbl->addSpacing( 15 );
+
+ QHBoxLayout *hbl9 = new QHBoxLayout();
+ vbl->addLayout( hbl9 );
+ hbl9->addSpacing( 10 );
+
+ rawgroup = new QButtonGroup(bg,"rawgroup");
+ hbl9->addWidget( rawgroup );
+
+ QHBoxLayout *hbl4 = new QHBoxLayout( rawgroup );
+
+ rawgroup->setFrameStyle(QFrame::NoFrame);
+
+ rawlabel = new QLabel(i18n("Raw fax format:"),rawgroup,"rawlabel");
+ rawlabel->setFixedSize( rawlabel->sizeHint() );
+ hbl4->addWidget( rawlabel );
+
+ g3 = new QRadioButton("G3",rawgroup,"g3");
+ connect(g3,SIGNAL(clicked()), this, SLOT(g3toggled()));
+ hbl4->addSpacing( 20 );
+ hbl4->addWidget( g3 );
+
+ g32d = new QRadioButton("G32d",rawgroup,"g32d");
+ connect(g32d,SIGNAL(clicked()), this,SLOT(g32toggled()));
+ hbl4->addSpacing( 30 );
+ hbl4->addWidget( g32d );
+
+ g4 = new QRadioButton("G4",rawgroup,"g4");
+ connect(g4,SIGNAL(clicked()), this, SLOT(g4toggled()));
+ hbl4->addSpacing( 30 );
+ hbl4->addWidget( g4 );
+
+ vbl->addSpacing( 20 );
+
+ QHBoxLayout *hbl5 = new QHBoxLayout();
+ vbl->addLayout( hbl5 );
+
+ widthlabel = new QLabel(i18n("Raw fax width:"),bg,"widthlabel");
+ hbl5->addSpacing( 10 );
+ hbl5->addWidget( widthlabel );
+
+ widthedit = new KIntNumInput(1, bg);
+ widthedit->setRange(1, 10000, 1, false);
+ hbl5->addWidget( widthedit );
+
+ heightlabel = new QLabel(i18n("Height:"),bg,"heightlabel");
+ hbl5->addSpacing( 10 );
+ hbl5->addWidget( heightlabel );
+
+ heightedit = new KIntNumInput(1, bg);
+ heightedit->setRange(0, 100000, 1, false);
+ hbl5->addWidget( heightedit );
+
+ geomauto = new QCheckBox(i18n("Auto"),bg,"geomauto");
+ connect(geomauto,SIGNAL(clicked()),this,SLOT(geomtoggled()));
+ hbl5->addSpacing( 10 );
+ hbl5->addWidget( geomauto );
+}
+
+
+struct optionsinfo * OptionsDialog::getInfo(){
+
+ if(resauto->isChecked())
+ oi.resauto = 1;
+
+ if(fine->isChecked())
+ oi.fine = 1;
+ else
+ oi.fine = 0;
+
+ if(landscape->isChecked())
+ oi.landscape = 1;
+ else
+ oi.landscape = 0;
+
+ if(flip->isChecked())
+ oi.flip = 1;
+ else
+ oi.flip = 0;
+
+ if(invert->isChecked())
+ oi.invert = 1;
+ else
+ oi.invert = 0;
+
+ if(lsb->isChecked())
+ oi.lsbfirst = 1;
+ else
+ oi.lsbfirst = 0;
+
+ if(geomauto->isChecked())
+ oi.geomauto = 1;
+
+
+ if(g3->isChecked()){
+ oi.raw = 3;
+ }
+
+ if(g32d->isChecked()){
+ oi.raw = 2;
+ oi.geomauto = 0;
+
+ }
+
+ if(g4->isChecked()){
+ oi.raw = 4;
+ oi.geomauto = 0;
+ }
+
+ oi.height = heightedit->value();
+ oi.width = widthedit->value();
+
+
+
+ return &oi;
+
+}
+
+void OptionsDialog::setWidgets(struct optionsinfo* newoi ){
+
+ if(!newoi)
+ return;
+
+ if(newoi->resauto == 1){
+ resauto->setChecked(newoi->resauto);
+ fine->setChecked(!newoi->resauto);
+ normal->setChecked(!newoi->resauto);
+ }
+ else{
+ if(newoi->fine == 1){
+ resauto->setChecked(FALSE);
+ fine->setChecked(TRUE);
+ normal->setChecked(FALSE);
+ }
+ else{
+ resauto->setChecked(FALSE);
+ fine->setChecked(FALSE);
+ normal->setChecked(TRUE);
+ }
+ }
+
+ if(newoi->landscape == 1)
+ landscape->setChecked(TRUE);
+ else
+ landscape->setChecked(FALSE);
+
+ if(newoi->flip == 1)
+ flip->setChecked(TRUE);
+ else
+ flip->setChecked(FALSE);
+
+ if(newoi->invert == 1)
+ invert->setChecked(TRUE);
+ else
+ invert->setChecked(FALSE);
+
+ if(newoi->lsbfirst == 1)
+ lsb->setChecked(TRUE);
+ else
+ lsb->setChecked(FALSE);
+
+ if(newoi->raw == 3){
+ geomauto->setEnabled(TRUE);
+ g3->setChecked(TRUE);
+ }
+
+ if(newoi->raw == 2){
+ geomauto->setEnabled(FALSE);
+ g32d->setChecked(TRUE);
+ }
+
+ if(newoi->raw == 4){
+ geomauto->setEnabled(FALSE);
+ g4->setChecked(TRUE);
+ }
+ widthedit->setValue(newoi->width);
+ heightedit->setValue(newoi->height);
+
+ // auto height and width can only work with g3 faxes
+ if(newoi->geomauto == 1 && newoi->raw != 4 && newoi->raw != 2){
+ geomauto->setChecked(TRUE);
+ widthedit->setEnabled(FALSE);
+ heightedit->setEnabled(FALSE);
+ }
+ else{
+ geomauto->setChecked(FALSE);
+ widthedit->setEnabled(TRUE);
+ heightedit->setEnabled(TRUE);
+
+ }
+
+}
+
+
+void OptionsDialog::g32toggled(){
+
+ geomauto->setChecked(FALSE);
+ geomauto->setEnabled(FALSE);
+ widthedit->setEnabled(TRUE);
+ heightedit->setEnabled(TRUE);
+
+}
+
+void OptionsDialog::g4toggled(){
+
+ geomauto->setChecked(FALSE);
+ geomauto->setEnabled(FALSE);
+ widthedit->setEnabled(TRUE);
+ heightedit->setEnabled(TRUE);
+
+
+}
+
+
+void OptionsDialog::g3toggled(){
+
+ geomauto->setEnabled(TRUE);
+ geomauto->setChecked(TRUE);
+ widthedit->setEnabled(FALSE);
+ heightedit->setEnabled(FALSE);
+
+
+}
+
+void OptionsDialog::geomtoggled(){
+
+ if(geomauto->isChecked()){
+
+ widthedit->setEnabled(FALSE);
+ heightedit->setEnabled(FALSE);
+
+ }
+ else{
+
+ widthedit->setEnabled(TRUE);
+ heightedit->setEnabled(TRUE);
+
+ }
+
+}
+
+void OptionsDialog::slotHelp(){
+ kapp->invokeHelp();
+}
+
+
+#include "options.moc"
diff --git a/kfax/options.h b/kfax/options.h
new file mode 100644
index 00000000..fa9c61c9
--- /dev/null
+++ b/kfax/options.h
@@ -0,0 +1,112 @@
+/*
+ $Id$
+
+
+ Copyright (C) 1996 Bernd Johannes Wuebben
+ wuebben@math.cornell.edu
+
+ 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 _OPTIONS_DIALOG_H_
+#define _OPTIONS_DIALOG_H_
+
+#include <qapplication.h>
+#include <qfiledialog.h>
+#include <kdialogbase.h>
+#include <qstring.h>
+
+class QGroupBox;
+class QLabel;
+class QButtonGroup;
+class QRadioButton;
+class QCheckBox;
+class QRadioButton;
+
+
+struct optionsinfo {
+ int geomauto;
+ int resauto;
+ int width ;
+ int height;
+ int fine;
+ int landscape;
+ int flip;
+ int invert;
+ int lsbfirst;
+ int raw;
+};
+
+class KIntNumInput;
+
+class OptionsDialog : public KDialogBase {
+
+ Q_OBJECT
+
+public:
+ OptionsDialog( QWidget *parent = 0, const char *name = 0);
+
+ struct optionsinfo* getInfo();
+ void setWidgets(struct optionsinfo *oi);
+
+signals:
+
+public slots:
+ void slotHelp();
+ void geomtoggled();
+ void g32toggled();
+ void g4toggled();
+ void g3toggled();
+
+private:
+
+ QGroupBox *bg;
+ QLabel *reslabel;
+ QButtonGroup *resgroup;
+ QRadioButton *fine;
+ QRadioButton *resauto;
+ QRadioButton *normal;
+ QLabel *displaylabel;
+ QButtonGroup *displaygroup;
+ QCheckBox *landscape;
+ QCheckBox *geomauto;
+ QCheckBox *flip;
+ QCheckBox *invert;
+
+ QButtonGroup *lsbgroup;
+ QLabel *lsblabel;
+ QCheckBox *lsb;
+ QButtonGroup *rawgroup;
+ QRadioButton *g3;
+ QRadioButton *g32d;
+ QRadioButton *g4;
+
+ QLabel *rawlabel;
+
+ QLabel *widthlabel;
+ QLabel *heightlabel;
+ KIntNumInput *widthedit;
+ KIntNumInput *heightedit;
+
+ struct optionsinfo oi;
+
+};
+
+
+#endif
diff --git a/kfax/version.h b/kfax/version.h
new file mode 100644
index 00000000..ca6653cf
--- /dev/null
+++ b/kfax/version.h
@@ -0,0 +1 @@
+#define KFAXVERSION "3.3.6"
diff --git a/kfax/viewfax.cpp b/kfax/viewfax.cpp
new file mode 100644
index 00000000..fe1e4246
--- /dev/null
+++ b/kfax/viewfax.cpp
@@ -0,0 +1,770 @@
+/*
+
+ KFax -- A G3/G4 Fax Viewer
+
+ Copyrigh (C) 1997 Bernd Johannes Wuebben
+ wuebben@math.cornell.edu
+ wuebben@kde.org
+
+ Based on:
+
+ viewfax - g3/g4 fax processing software.
+ Copyright (C) 1990, 1995 Frank D. Cringle.
+
+ This file is part of viewfax - g3/g4 fax processing software.
+
+ viewfax 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <qglobal.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qevent.h>
+#include <qprinter.h>
+#include <qstring.h>
+
+#include <kcmdlineargs.h>
+#include <klocale.h>
+
+#include "kfax.h"
+#include "faxexpand.h"
+#include "version.h"
+#include "viewfax.h"
+
+/* NewImage() needs to fiddle with the Display structure */
+#define XLIB_ILLEGAL_ACCESS
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xatom.h>
+#include <X11/keysym.h>
+#include <X11/keysymdef.h>
+#include <X11/cursorfont.h>
+
+
+#define VIEWFAXVERSION "2.3"
+
+
+/* If moving the image around with the middle mouse button is jerky or
+ slow, try defining USE_MOTIONHINT. It may help (it may also make
+ things worse - it depends on the server implementation) */
+#undef USE_MOTIONHINT
+
+
+
+/* access the 'extra' field in a pagenode */
+
+#define Pimage(p) ((XImage *)(p)->extra)
+
+
+/* forward declarations */
+
+XImage *FlipImage(XImage *xi);
+XImage *MirrorImage(XImage *xi);
+XImage *NewImage(int w, int h, char *data, int bit_order);
+XImage *RotImage(XImage *Image);
+XImage *ZoomImage(XImage *Big);
+
+void FreeImage(XImage *Image);
+
+static int release(int quit);
+
+
+/* X variables */
+
+extern Cursor WorkCursor;
+extern Cursor ReadyCursor;
+extern Cursor MoveCursor;
+extern Cursor LRCursor;
+extern Cursor UDCursor;
+
+extern bool have_no_fax;
+extern Display* qtdisplay ;
+extern Window qtwin;
+extern Window Win;
+extern int qwindow_width;
+extern int qwindow_height;
+
+struct pagenode *firstpage, *lastpage, *thispage, *helppage, *auxpage;
+struct pagenode defaultpage;
+
+Display *Disp;
+
+int Default_Screen;
+int verbose = 0;
+
+int abell = 1; /* audio bell */
+int vbell = 0; /* visual bell */
+bool have_cmd_opt = FALSE;
+
+size_t Memused = 0; /* image memory usage */
+static size_t Memlimit = 8*1024*1024; /* try not to exceed */
+
+#undef min
+#undef max
+#define min(a,b) ((a)<(b)?(a):(b))
+#define max(a,b) ((a)>(b)?(a):(b))
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE 1
+#endif
+
+/* OK, OK - this is a dreadful hack. But it adequately distinguishes
+ modern big- and little- endian hosts. We only need this to set the
+ byte order in XImage structures */
+
+static union { t32bits i; unsigned char b[4]; } bo;
+#define ByteOrder bo.b[3]
+
+static char Banner[] =
+"KFax version " KFAXVERSION "\tCopyright (C) 1997, Bernd Johannes Wuebben\n";
+
+/*"KFax is based on:\n"
+"viewfax " VERSION ":\t\tCopyright (c) 1990, 1995 Frank D. Cringle.\n"
+"libtiff v 3.4beta:\tCopyright (c) 1988 - 1955 Sam Leffler\n"
+" \tCopyright (c) 1991 - 1995 Silicon Graphics, Inc.\n\n"
+"KFax comes with ABSOLUTELY NO WARRANTY; for details see the\n"
+"file \"COPYING\" in the distribution directory.\n";*/
+
+XEvent Event;
+XImage *Image, *Images[MAXZOOM];
+XSizeHints size_hints;
+
+Time Lasttime = 0;
+
+struct pagenode *viewpage = 0;
+
+int viewfaxmain()
+{
+ int banner = 0;
+ int have_height = 0;
+
+ bo.i = 1;
+ defaultpage.vres = -1;
+ have_no_fax = TRUE;
+
+ /* TODO Do I need to know this: */
+ defaultpage.expander = g31expand;
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ if (args->isSet("height"))
+ {
+ have_height = 1;
+ defaultpage.height = args->getOption("height").toInt();
+ }
+
+ if (args->isSet("2"))
+ {
+ defaultpage.expander = g32expand;
+ if(!have_height)
+ defaultpage.height = 2339;
+ }
+
+ if (args->isSet("4"))
+ {
+ defaultpage.expander = g4expand;
+ if(!have_height)
+ defaultpage.height = 2155;
+ }
+
+ if (args->isSet("invert"))
+ {
+ defaultpage.inverse = 1;
+ }
+
+ if (args->isSet("landscape"))
+ {
+ defaultpage.orient |= TURN_L;
+ }
+
+ if (args->isSet("fine"))
+ {
+ defaultpage.vres = 1;
+ }
+
+ if (!args->isSet("rmal")) // "normal" is interpreted as "no"+"rmal" :-)
+ {
+ defaultpage.vres = 0;
+ }
+
+ if (args->isSet("reverse"))
+ {
+ defaultpage.lsbfirst = 1;
+ }
+
+ if (args->isSet("upsidedown"))
+ {
+ defaultpage.orient |= TURN_U;
+ }
+
+ if (args->isSet("width"))
+ {
+ defaultpage.width = args->getOption("width").toInt();
+ }
+
+ QCString mem = args->getOption("mem");
+ Memlimit = atoi(mem.data());
+ switch(mem[mem.length()-1]) {
+ case 'M':
+ case 'm':
+ Memlimit *= 1024;
+ case 'K':
+ case 'k':
+ Memlimit *= 1024;
+ }
+
+ if (defaultpage.expander == g4expand && defaultpage.height == 0) {
+ KCmdLineArgs::usage("--height value is required to interpret raw g4 faxes\n");
+ }
+
+ firstpage = lastpage = thispage = helppage = auxpage = 0;
+
+ for (int i = 0; i < args->count(); i++){
+ loadfile(QFile::decodeName(args->arg(i)));
+ }
+ args->clear();
+
+ if (banner ) {
+ fputs(Banner, stderr);
+ exit(1);
+ }
+
+ have_no_fax = (firstpage == 0);
+
+ Disp = qtdisplay;
+ Default_Screen = XDefaultScreen(qtdisplay);
+
+ return 1;
+}
+
+
+/* Change orientation of all following pages */
+void TurnFollowing(int How, struct pagenode *pn)
+{
+ while (pn) {
+ if (Pimage(pn)) {
+ FreeImage(Pimage(pn));
+ pn->extra = 0;
+ }
+ pn->orient ^= How;
+ pn = pn->next;
+ }
+}
+
+static void
+drawline(pixnum *run, int LineNum, struct pagenode *pn)
+{
+ t32bits *p, *p1; /* p - current line, p1 - low-res duplicate */
+ pixnum *r; /* pointer to run-lengths */
+ t32bits pix; /* current pixel value */
+ t32bits acc; /* pixel accumulator */
+ int nacc; /* number of valid bits in acc */
+ int tot; /* total pixels in line */
+ int n;
+
+ LineNum += pn->stripnum * pn->rowsperstrip;
+ if (LineNum >= pn->height) {
+ if (verbose && LineNum == pn->height)
+ fputs("Height exceeded\n", stderr);
+ return;
+ }
+
+ p = (t32bits *) (Pimage(pn)->data + LineNum*(2-pn->vres)*Pimage(pn)->bytes_per_line);
+ p1 =(t32bits *)( pn->vres ? 0 : p + Pimage(pn)->bytes_per_line/sizeof(*p));
+ r = run;
+ acc = 0;
+ nacc = 0;
+ pix = pn->inverse ? ~0 : 0;
+ tot = 0;
+ while (tot < pn->width) {
+ n = *r++;
+ tot += n;
+ /* Watch out for buffer overruns, e.g. when n == 65535. */
+ if (tot > pn->width)
+ break;
+ if (pix)
+ acc |= (~(t32bits)0 >> nacc);
+ else if (nacc)
+ acc &= (~(t32bits)0 << (32 - nacc));
+ else
+ acc = 0;
+ if (nacc + n < 32) {
+ nacc += n;
+ pix = ~pix;
+ continue;
+ }
+ *p++ = acc;
+ if (p1)
+ *p1++ = acc;
+ n -= 32 - nacc;
+ while (n >= 32) {
+ n -= 32;
+ *p++ = pix;
+ if (p1)
+ *p1++ = pix;
+ }
+ acc = pix;
+ nacc = n;
+ pix = ~pix;
+ }
+ if (nacc) {
+ *p++ = acc;
+ if (p1)
+ *p1++ = acc;
+ }
+}
+
+static int
+GetPartImage(struct pagenode *pn, int n)
+{
+ unsigned char *Data = getstrip(pn, n);
+
+ if (Data == 0)
+ return 3;
+ pn->stripnum = n;
+ (*pn->expander)(pn, drawline);
+ free(Data);
+ return 1;
+}
+
+int GetImage(struct pagenode *pn){
+ int i;
+
+ if (pn->strips == 0) {
+
+ /*printf("RAW fax file\n");*/
+
+ /* raw file; maybe we don't have the height yet */
+ unsigned char *Data = getstrip(pn, 0);
+ if (Data == 0){
+
+ return 0;
+ }
+ pn->extra = NewImage(pn->width, pn->vres ?
+ pn->height : 2*pn->height, 0, 1);
+
+//printf("height = %d\n",pn->height);
+//printf("setting height to %d\n", pn->vres ? pn->height : 2*pn->height);
+
+ if(pn->extra == 0)
+ return 0;
+
+ (*pn->expander)(pn, drawline);
+ }
+ else {
+ /* multi-strip tiff */
+ /*printf("MULTI STRIP TIFF fax file\n");*/
+
+ pn->extra = NewImage(pn->width, pn->vres ?
+ pn->height : 2*pn->height, 0, 1);
+
+ if(pn->extra == 0)
+ return 0;
+ pn->stripnum = 0;
+ for (i = 0; i < pn->nstrips; i++){
+
+ int k =GetPartImage(pn, i);
+
+ if ( k == 3 ){
+ FreeImage(Pimage(pn));
+ return k;
+ }
+
+ }
+ }
+ if (pn->orient & TURN_U)
+ pn->extra = FlipImage(Pimage(pn));
+ if (pn->orient & TURN_M)
+ pn->extra = MirrorImage(Pimage(pn));
+ if (pn->orient & TURN_L)
+ pn->extra = RotImage(Pimage(pn));
+ if (verbose) printf("\tmemused = %d\n", Memused);
+
+/*
+if(pn->extra)
+ printf("pn->extra !=0 %s\n",pn->name);
+else
+ printf("pn->extra ==0 %s\n",pn->name);
+ */
+
+ return 1;
+}
+
+
+
+/* run this region through perl to generate the zoom table:
+$lim = 1;
+@c = ("0", "1", "1", "2");
+print "static unsigned char Z[] = {\n";
+for ($i = 0; $i < 16; $i++) {
+ for ($j = 0; $j < 16; $j++) {
+ $b1 = ($c[$j&3]+$c[$i&3]) > $lim;
+ $b2 = ($c[($j>>2)&3]+$c[($i>>2)&3]) > $lim;
+ printf " %X,", ($b2 << 1) | $b1;
+ }
+ print "\n";
+}
+print "};\n";
+*/
+
+static unsigned char Z[] = {
+ 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 2, 2, 2, 3,
+ 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 2, 3, 3, 3,
+ 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 2, 3, 3, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3,
+ 0, 0, 0, 1, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3,
+ 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3,
+ 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3,
+ 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 0, 0, 0, 1, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3,
+ 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3,
+ 0, 1, 1, 1, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3,
+ 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3, 2, 2, 2, 3,
+ 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3,
+ 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+};
+
+#define nib(n,w) (((w)>>((n)<<2))&15)
+#define zak(a,b) Z[(a<<4)|b]
+
+/* 2 -> 1 zoom, 4 pixels -> 1 pixel
+ if #pixels <= $lim (see above), new pixel is white,
+ else black.
+*/
+
+XImage *ZoomImage(XImage *Big){
+
+ XImage *Small;
+ int w, h;
+ int i, j;
+
+ XDefineCursor(Disp, Win, WorkCursor);
+ XFlush(Disp);
+ w = (Big->width+1) / 2;
+ h = (Big->height+1) / 2;
+ Small = NewImage(w, h, 0, Big->bitmap_bit_order);
+ if(Small == 0)
+ return 0;
+
+ Small->xoffset = (Big->xoffset+1)/2;
+ for (i = 0; i < Big->height; i += 2) {
+ t32bits *pb0 = (t32bits *) (Big->data + i * Big->bytes_per_line);
+ t32bits *pb1 = pb0 + ((i == Big->height-1) ? 0 : Big->bytes_per_line/4);
+ t32bits *ps = (t32bits *) (Small->data + i * Small->bytes_per_line / 2);
+ for (j = 0; j < Big->bytes_per_line/8; j++) {
+ t32bits r1, r2;
+ t32bits t0 = *pb0++;
+ t32bits t1 = *pb1++;
+ r1 = (zak(nib(7,t0),nib(7,t1))<<14) |
+ (zak(nib(6,t0),nib(6,t1))<<12) |
+ (zak(nib(5,t0),nib(5,t1))<<10) |
+ (zak(nib(4,t0),nib(4,t1))<<8) |
+ (zak(nib(3,t0),nib(3,t1))<<6) |
+ (zak(nib(2,t0),nib(2,t1))<<4) |
+ (zak(nib(1,t0),nib(1,t1))<<2) |
+ (zak(nib(0,t0),nib(0,t1)));
+ t0 = *pb0++;
+ t1 = *pb1++;
+ r2 = (zak(nib(7,t0),nib(7,t1))<<14) |
+ (zak(nib(6,t0),nib(6,t1))<<12) |
+ (zak(nib(5,t0),nib(5,t1))<<10) |
+ (zak(nib(4,t0),nib(4,t1))<<8) |
+ (zak(nib(3,t0),nib(3,t1))<<6) |
+ (zak(nib(2,t0),nib(2,t1))<<4) |
+ (zak(nib(1,t0),nib(1,t1))<<2) |
+ (zak(nib(0,t0),nib(0,t1)));
+ *ps++ = (Big->bitmap_bit_order) ?
+ (r1<<16)|r2 : (r2<<16)|r1;
+ }
+ for ( ; j < Small->bytes_per_line/4; j++) {
+ t32bits r1;
+ t32bits t0 = *pb0++;
+ t32bits t1 = *pb1++;
+ r1 = (zak(nib(7,t0),nib(7,t1))<<14) |
+ (zak(nib(6,t0),nib(6,t1))<<12) |
+ (zak(nib(5,t0),nib(5,t1))<<10) |
+ (zak(nib(4,t0),nib(4,t1))<<8) |
+ (zak(nib(3,t0),nib(3,t1))<<6) |
+ (zak(nib(2,t0),nib(2,t1))<<4) |
+ (zak(nib(1,t0),nib(1,t1))<<2) |
+ (zak(nib(0,t0),nib(0,t1)));
+ *ps++ = (Big->bitmap_bit_order) ?
+ (r1<<16) : r1;
+ }
+ }
+ XDefineCursor(Disp, Win, ReadyCursor);
+ return Small;
+}
+
+XImage *FlipImage(XImage *Image){
+
+ XImage *New = NewImage(Image->width, Image->height,
+ Image->data, !Image->bitmap_bit_order);
+ if(New == 0)
+ return 0;
+
+ t32bits *p1 = (t32bits *) Image->data;
+ t32bits *p2 = (t32bits *) (Image->data + Image->height *
+ Image->bytes_per_line - 4);
+
+ /* the first shall be last ... */
+ while (p1 < p2) {
+ t32bits t = *p1;
+ *p1++ = *p2;
+ *p2-- = t;
+ }
+
+ /* let Xlib twiddle the bits */
+ New->xoffset = 32 - (Image->width & 31) - Image->xoffset;
+ New->xoffset &= 31;
+
+ Image->data = 0;
+ FreeImage(Image);
+ return New;
+}
+
+XImage *MirrorImage(XImage *Image){
+
+ int i;
+ XImage *New = NewImage(Image->width, Image->height,
+ Image->data, !Image->bitmap_bit_order);
+ if(New == 0)
+ return 0;
+
+ /* reverse order of 32-bit words in each line */
+ for (i = 0; i < Image->height; i++) {
+ t32bits *p1 = (t32bits *) (Image->data + Image->bytes_per_line * i);
+ t32bits *p2 = p1 + Image->bytes_per_line/4 - 1;
+ while (p1 < p2) {
+ t32bits t = *p1;
+ *p1++ = *p2;
+ *p2-- = t;
+ }
+ }
+
+ /* let Xlib twiddle the bits */
+ New->xoffset = 32 - (Image->width & 31) - Image->xoffset;
+ New->xoffset &= 31;
+
+ Image->data = 0;
+ FreeImage(Image);
+ return New;
+}
+
+XImage *RotImage(XImage *Image){
+
+ XImage *New;
+ int w = Image->height;
+ int h = Image->width;
+ int i, j, k, shift;
+ int order = Image->bitmap_bit_order;
+ int offs = h+Image->xoffset-1;
+
+ New = NewImage(w, h, 0, 1);
+ if (New == 0)
+ return 0;
+
+ k = (32 - Image->xoffset) & 3;
+ for (i = h - 1; i && k; i--, k--) {
+ t32bits *sp = (t32bits *) Image->data + (offs-i)/32;
+ t32bits *dp = (t32bits *) (New->data+i*New->bytes_per_line);
+ t32bits d0 =0;
+ shift = (offs-i)&31;
+ if (order) shift = 31-shift;
+ for (j = 0; j < w; j++) {
+ t32bits t = *sp;
+ sp += Image->bytes_per_line/4;
+ d0 |= ((t >> shift) & 1);
+ if ((j & 31) == 31)
+ *dp++ = d0;
+ d0 <<= 1;;
+ }
+ if (j & 31)
+ *dp++ = d0<<(31-j);
+ }
+ for ( ; i >= 3; i-=4) {
+ t32bits *sp = (t32bits *) Image->data + (offs-i)/32;
+ t32bits *dp0 = (t32bits *) (New->data+i*New->bytes_per_line);
+ t32bits *dp1 = dp0 - New->bytes_per_line/4;
+ t32bits *dp2 = dp1 - New->bytes_per_line/4;
+ t32bits *dp3 = dp2 - New->bytes_per_line/4;
+ t32bits d0=0 , d1=0, d2 =0, d3 =0;
+ shift = (offs-i)&31;
+ if (order) shift = 28-shift;
+ for (j = 0; j < w; j++) {
+ t32bits t = *sp >> shift;
+ sp += Image->bytes_per_line/4;
+ d0 |= t & 1; t >>= 1;
+ d1 |= t & 1; t >>= 1;
+ d2 |= t & 1; t >>= 1;
+ d3 |= t & 1; t >>= 1;
+ if ((j & 31) == 31) {
+ if (order) {
+ *dp0++ = d3;
+ *dp1++ = d2;
+ *dp2++ = d1;
+ *dp3++ = d0;
+ }
+ else {
+ *dp0++ = d0;
+ *dp1++ = d1;
+ *dp2++ = d2;
+ *dp3++ = d3;
+ }
+ }
+ d0 <<= 1; d1 <<= 1; d2 <<= 1; d3 <<= 1;
+ }
+ if (j & 31) {
+ if (order) {
+ *dp0++ = d3<<(31-j);
+ *dp1++ = d2<<(31-j);
+ *dp2++ = d1<<(31-j);
+ *dp3++ = d0<<(31-j);
+ }
+ else {
+ *dp0++ = d0<<(31-j);
+ *dp1++ = d1<<(31-j);
+ *dp2++ = d2<<(31-j);
+ *dp3++ = d3<<(31-j);
+ }
+ }
+ }
+ for (; i >= 0; i--) {
+ t32bits *sp = (t32bits *) Image->data + (offs-i)/32;
+ t32bits *dp = (t32bits *) (New->data+i*New->bytes_per_line);
+ t32bits d0=0;
+ shift = (offs-i)&31;
+ if (order) shift = 31-shift;
+ for (j = 0; j < w; j++) {
+ t32bits t = *sp;
+ sp += Image->bytes_per_line/4;
+ d0 |= ((t >> shift) & 1);
+ if ((j & 31) == 31)
+ *dp++ = d0;
+ d0 <<= 1;;
+ }
+ if (j & 31)
+ *dp++ = d0<<(31-j);
+ }
+ FreeImage(Image);
+ return New;
+}
+
+/* release some non-essential memory or abort */
+#define Try(n) \
+ if (n && n != thispage && n->extra) { \
+ FreeImage((XImage*)n->extra); \
+ n->extra = 0; \
+ return 1; \
+ }
+
+static int
+release(int quit)
+{
+ (void) quit;
+
+ struct pagenode *pn;
+
+ if (thispage) {
+ /* first consider "uninteresting" pages */
+ for (pn = firstpage->next; pn; pn = pn->next)
+ if (pn->extra && pn != thispage && pn != thispage->prev &&
+ pn != thispage->next && pn != lastpage) {
+ FreeImage(Pimage(pn));
+ pn->extra = 0;
+ return 1;
+ }
+ Try(lastpage);
+ Try(firstpage);
+ Try(thispage->prev);
+ Try(thispage->next);
+ }
+
+ return 0;
+
+}
+
+XImage *NewImage(int w, int h, char *data, int bit_order){
+
+ XImage *newimage;
+ /* This idea is taken from xwud/xpr. Use a fake display with the
+ desired bit/byte order to get the image routines initialised
+ correctly */
+ Display fake;
+
+ fake = *Disp;
+ if (data == 0)
+ data = xmalloc(((w + 31) & ~31) * h / 8);
+ fake.byte_order = ByteOrder;
+ fake.bitmap_unit = 32;
+ fake.bitmap_bit_order = bit_order;
+
+ int returncode = -1;
+ while ((newimage = XCreateImage(&fake, DefaultVisual(Disp, Default_Screen),
+ 1, XYBitmap, 0, data, w, h, 32, 0)) == 0 ){
+
+ returncode = release(1);
+ if (returncode == 0)
+ break;
+ }
+
+ if (returncode == 0){
+ kfaxerror("Sorry","Can not allocate Memory for a new Fax Image\n");
+ return 0;
+ }
+
+ Memused += newimage->bytes_per_line * newimage->height;
+ /*printf("allocating %d bytes for %ld\n",
+ newimage->bytes_per_line * newimage->height,
+ newimage);*/
+
+
+ return newimage;
+}
+
+void FreeImage(XImage *Image){
+
+ if (Image->data){
+ Memused -= Image->bytes_per_line * Image->height;
+/*printf("deallocating %d bytes for %ld\n",
+ Image->bytes_per_line * Image->height,
+ Image);*/
+ }
+ XDestroyImage(Image);
+}
+
+#ifndef xmalloc
+char *
+xmalloc(unsigned int size)
+{
+ char *p;
+
+ while (Memused + size > Memlimit && release(0))
+ ;
+ while ((p = (char*) malloc(size)) == 0)
+ (void) release(1);
+ return p;
+}
+#endif
diff --git a/kfax/viewfax.h b/kfax/viewfax.h
new file mode 100644
index 00000000..92ffbd70
--- /dev/null
+++ b/kfax/viewfax.h
@@ -0,0 +1,27 @@
+/*
+ This file is part of KFAX
+ Copyright (c) 1999 Waldo Bastian <bastian@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _VIEWFAX_H_
+#define _VIEWFAX_H_
+
+#define MAXZOOM 4
+
+int viewfaxmain();
+
+#endif
diff --git a/kfaxview/Makefile.am b/kfaxview/Makefile.am
new file mode 100644
index 00000000..669fcd9b
--- /dev/null
+++ b/kfaxview/Makefile.am
@@ -0,0 +1,38 @@
+INCLUDES = -I$(top_srcdir)/kviewshell \
+ -I$(top_builddir)/kviewshell \
+ -I$(kde_includes)/kviewshell \
+ -I$(srcdir)/libkfaximage \
+ -I$(top_srcdir) $(all_includes)
+
+SUBDIRS = libkfaximage .
+
+KDE_ICON = kfaxview
+
+METASOURCES = AUTO
+
+bin_PROGRAMS = kfaxview
+kfaxview_SOURCES = main.cpp
+kfaxview_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+kfaxview_LDADD = ../kviewshell/libifaces.la ../kviewshell/libkviewshell.la -lkparts
+
+# this is where the desktop file will go
+kde_services_DATA = kfaxmultipage.desktop kfaxmultipage_tiff.desktop
+
+# this is where the shell's XML-GUI resource file goes
+shellrcdir = $(kde_datadir)/kfaxview
+
+kde_module_LTLIBRARIES = kfaxviewpart.la
+kfaxviewpart_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+kfaxviewpart_la_LIBADD = -lkdeprint -lkparts $(top_builddir)/kviewshell/libkmultipage.la libkfaximage/libkfaximage.la
+kfaxviewpart_la_SOURCES = faxmultipage.cpp faxrenderer.cpp
+
+partdir = $(kde_datadir)/kfaxview
+part_DATA = ../kviewshell/kviewshell.rc
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/kfaxview.pot
+
+xdg_apps_DATA = kfaxview.desktop
+
+# The next line switches the API documentation on
+include ../admin/Doxyfile.am
diff --git a/kfaxview/faxmultipage.cpp b/kfaxview/faxmultipage.cpp
new file mode 100644
index 00000000..bbf4e566
--- /dev/null
+++ b/kfaxview/faxmultipage.cpp
@@ -0,0 +1,85 @@
+/***************************************************************************
+ * 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 <config.h>
+
+#include <kfiledialog.h>
+#include <kparts/genericfactory.h>
+
+#include "faxmultipage.h"
+
+
+
+typedef KParts::GenericFactory<FaxMultiPage> FaxMultiPageFactory;
+K_EXPORT_COMPONENT_FACTORY(kfaxviewpart, FaxMultiPageFactory)
+
+
+FaxMultiPage::FaxMultiPage(QWidget *parentWidget, const char *widgetName, QObject *parent,
+ const char *name, const QStringList&)
+ : KMultiPage(parentWidget, widgetName, parent, name), faxRenderer(parentWidget)
+{
+ /* This is kparts wizardry that cannot be understood by man. Simply
+ change the names to match your implementation. */
+ setInstance(FaxMultiPageFactory::instance());
+ faxRenderer.setName("Fax renderer");
+
+ setXMLFile("kfaxview.rc");
+
+ /* 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(&faxRenderer);
+}
+
+
+FaxMultiPage::~FaxMultiPage()
+{
+ ;
+}
+
+
+KAboutData* FaxMultiPage::createAboutData()
+{
+ /* You obviously want to change this to match your setup */
+ KAboutData* about = new KAboutData("kfaxview", I18N_NOOP("KFaxView"), "0.1",
+ I18N_NOOP("KViewshell Fax Plugin."),
+ KAboutData::License_GPL,
+ "Stefan Kebekus",
+ I18N_NOOP("This program previews fax (g3) files."));
+
+ about->addAuthor ("Stefan Kebekus",
+ I18N_NOOP("Current Maintainer."),
+ "kebekus@kde.org",
+ "http://www.mi.uni-koeln.de/~kebekus");
+ return about;
+}
+
+
+QStringList FaxMultiPage::fileFormats() const
+{
+ /* This list is used in the file selection dialog when the file is
+ saved */
+ QStringList r;
+ r << i18n("*.g3|Fax (g3) file (*.g3)");
+ return r;
+}
+
+
+#include "faxmultipage.moc"
diff --git a/kfaxview/faxmultipage.h b/kfaxview/faxmultipage.h
new file mode 100644
index 00000000..1ea8b6c5
--- /dev/null
+++ b/kfaxview/faxmultipage.h
@@ -0,0 +1,120 @@
+/***************************************************************************
+ * 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 FAXMULTIPAGE_H
+#define FAXMULTIPAGE_H
+
+#include <qstringlist.h>
+
+#include "kmultipage.h"
+#include "faxrenderer.h"
+
+
+
+/*! \mainpage FaxMultiPage
+
+\section intro_sec Introduction
+
+FaxMultiPage is a minimal, but well-documented reference
+implementation of a kviewshell plugin that can serve as a starting
+point for implementations.
+
+\section install_sec Usage
+
+When FaxMultiPage and the associated files are installed, the
+kviewshell program can open TIFF-Fax anf G3 fax files, i.e. files of
+mime types image/fax-g3 or image/tiff.
+
+\section content Content
+
+Only the two classes that are absolutely necessary for a working
+plugin are implemented. The only other file that is installed are
+desktop file, which tells kviewshell to use the plugin.
+
+- FaxMultiPage, an implementation of a KMultiPage. In a larger
+application, this class would contain the GUI elements that the plugin
+adds to the GUI of the kviewshell. For viewing FAXes, no special GUI
+elements are required, and this plugin does only the minimal
+initialization required.
+
+- FaxRenderer, an implementation of a DocumentRenderer. This class is
+responsible for document loading and rendering.
+
+- kfaxmultipage.desktop and kfaxmultipage_tiff.desktop are desktop
+entry files that associate the plugin wit image/fax-g3 or image/tiff
+mime-types. Without these files installed, the file dialog in
+kviewshell would not show FAX files, and the command line "kvieshell
+test.g3" would fail with an error dialog "No plugin for image/fax-g3
+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 larger application, this class would contain the
+GUI elements that the plugin adds to the GUI of the kviewshell. For
+viewing FAXes, no special GUI elements are required, and this plugin
+does only the minimal initialization required.
+*/
+
+class FaxMultiPage : 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.
+ */
+ FaxMultiPage(QWidget *parentWidget, const char *widgetName, QObject *parent,
+ const char *name, const QStringList& args = QStringList());
+
+ /** Destructor
+
+ This destructor does nothing.
+ */
+ virtual ~FaxMultiPage();
+
+ /** 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();
+
+ private:
+ /** This member holds the renderer which is used by the demo implementation */
+ FaxRenderer faxRenderer;
+};
+
+#endif
diff --git a/kfaxview/faxrenderer.cpp b/kfaxview/faxrenderer.cpp
new file mode 100644
index 00000000..ec18d431
--- /dev/null
+++ b/kfaxview/faxrenderer.cpp
@@ -0,0 +1,204 @@
+/***************************************************************************
+ * 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 <config.h>
+
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <qfileinfo.h>
+#include <qpainter.h>
+
+#include "documentWidget.h"
+#include "faxrenderer.h"
+#include "faxmultipage.h"
+
+//#define KF_DEBUG
+
+FaxRenderer::FaxRenderer(QWidget* par)
+ : DocumentRenderer(par)
+{
+#ifdef KF_DEBUG
+ kdError() << "FaxRenderer( parent=" << par << " )" << endl;
+#endif
+}
+
+
+
+FaxRenderer::~FaxRenderer()
+{
+#ifdef KF_DEBUG
+ kdDebug() << "~FaxRenderer" << endl;
+#endif
+
+ // Wait for all access to this documentRenderer to finish
+ mutex.lock();
+ mutex.unlock();
+}
+
+
+void FaxRenderer::drawPage(double resolution, RenderedDocumentPage* page)
+{
+#ifdef KF_DEBUG
+ kdDebug() << "FaxRenderer::drawPage(documentPage*) called, page number " << page->getPageNumber() << endl;
+#endif
+
+ // Paranoid safety checks
+ if (page == 0) {
+ kdError() << "FaxRenderer::drawPage(documentPage*) called with argument == 0" << endl;
+ return;
+ }
+ if (page->getPageNumber() == 0) {
+ kdError() << "FaxRenderer::drawPage(documentPage*) called for a documentPage with page number 0" << endl;
+ return;
+ }
+
+ // Wait for all access to this documentRenderer to finish
+ mutex.lock();
+
+ // more paranoid safety checks
+ if (page->getPageNumber() > numPages) {
+ kdError() << "FaxRenderer::drawPage(documentPage*) called for a documentPage with page number " << page->getPageNumber()
+ << " but the current fax file has only " << numPages << " pages." << endl;
+ mutex.unlock();
+ return;
+ }
+
+ QImage img = fax.page(page->getPageNumber() - 1);
+
+ SimplePageSize psize = pageSizes[page->getPageNumber() - 1];
+ if (psize.isValid()) {
+ QPainter *foreGroundPaint = page->getPainter();
+ if (foreGroundPaint != 0) {
+ // Compute an image for the page.
+
+ // WARNING: It may be tempting to compute the image size in
+ // pixel, using page->height() and page->width(). DON'T DO
+ // THAT. KViewShell uses transformations e.g. to rotate the
+ // page, and sets the argument 'resolution' accordingly. Similar
+ // problems occur if KViewShell required a shrunken version of
+ // the page, e.g. to print multiple pages on one sheet of paper.
+
+ int width_in_pixel = qRound(resolution * psize.width().getLength_in_inch());
+ int height_in_pixel = qRound(resolution * psize.height().getLength_in_inch());
+
+ img = img.smoothScale(width_in_pixel, height_in_pixel);
+ foreGroundPaint->drawImage(0, 0, img);
+ page->returnPainter(foreGroundPaint);
+ }
+ } else
+ kdError() << "FaxRenderer::drawPage() called, but page size for page " << page->getPageNumber() << " is invalid." << endl;
+
+ // To indicate that the page was drawn, we set the appropriate flas in the page structure
+ page->isEmpty = false;
+
+ mutex.unlock();
+}
+
+
+bool FaxRenderer::setFile(const QString &fname, const KURL &)
+{
+#ifdef KF_DEBUG
+ kdDebug() << "FaxRenderer::setFile(" << fname << ") called" << endl;
+#endif
+
+ // Wait for all access to this documentRenderer to finish
+ mutex.lock();
+
+ // If fname is the empty string, then this means: "close".
+ if (fname.isEmpty()) {
+ kdDebug() << "FaxRenderer::setFile( ... ) called with empty filename. Closing the file." << endl;
+ mutex.unlock();
+ 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("<qt><strong>File error.</strong> The specified file '%1' does not exist.</qt>").arg(filename),
+ i18n("File Error"));
+ // the return value 'false' indicates that this operation was not successful.
+ mutex.unlock();
+ return false;
+ }
+
+ // Now we assume that the file is fine and load the file into the
+ // fax member. We abort on error and give an error message.
+ bool ok = fax.loadImage(filename);
+
+ // It can happen that fax.loadImage() returns with 'ok == true', but
+ // still the file could NOT be loaded. This happens, e.g. for TIFF
+ // file that do NOT contain FAX, but other image formats. We handle
+ // that case here also.
+ if ( (!ok) || (fax.numPages() == 0)) {
+ // Unfortunately, it can happen that fax.loadImage() fails WITHOUT
+ // leaving an error message in fax.errorString(). We try to handle
+ // this case gracefully.
+ if (fax.errorString().isEmpty())
+ KMessageBox::error( parentWidget,
+ i18n("<qt><strong>File error.</strong> The specified file '%1' could not be loaded.</qt>").arg(filename),
+ i18n("File Error"));
+ else
+ KMessageBox::detailedError( parentWidget,
+ i18n("<qt><strong>File error.</strong> The specified file '%1' could not be loaded.</qt>").arg(filename),
+ fax.errorString(),
+ i18n("File Error"));
+ clear();
+ mutex.unlock();
+ return false;
+ }
+
+ // Set the number of pages page sizes
+ numPages = fax.numPages();
+
+ // Set the page size for the first page in the pageSizes array.
+ // The rest of the page sizes will be calculated on demand by the drawPage function.
+ pageSizes.resize(numPages);
+ Length w,h;
+
+ if (numPages != 0) {
+ for(Q_UINT16 pg=0; pg < numPages; pg++) {
+ QSize pageSize = fax.page_size(pg);
+ QPoint dpi = fax.page_dpi(pg);
+ double dpix = dpi.x();
+ double dpiy = dpi.y();
+
+ if (dpix*dpiy < 1.0) {
+ kdError() << "File invalid resolutions, dpi x = " << dpix << ", dpi y = " << dpiy << ". This information will be ignored and 75 DPI assumed." << endl;
+ dpix = dpiy = 75.0;
+ }
+
+ w.setLength_in_inch(pageSize.width() / dpix);
+ h.setLength_in_inch(pageSize.height() / dpiy);
+ pageSizes[pg].setPageSize(w, h);
+ }
+ }
+
+ // the return value 'true' indicates that this operation was not successful.
+ mutex.unlock();
+ return true;
+}
+
+
+#include "faxrenderer.moc"
diff --git a/kfaxview/faxrenderer.h b/kfaxview/faxrenderer.h
new file mode 100644
index 00000000..d2b37657
--- /dev/null
+++ b/kfaxview/faxrenderer.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+ * 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 _FAXRENDERER_H_
+#define _FAXRENDERER_H_
+
+
+#include "documentRenderer.h"
+#include "kfaximage.h"
+
+class documentPage;
+
+/*! \brief Well-documented minimal implementation of a documentRenderer for reading FAX files
+
+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().
+*/
+
+class FaxRenderer : public DocumentRenderer
+{
+ Q_OBJECT
+
+public:
+ /** Default constructor
+
+ This constructor simply prints a message (if debugging is
+ enabled) and calls the default constructor.
+ */
+ FaxRenderer(QWidget* parent);
+
+ /** Destructor
+
+ The destructor simpley prints a message if debugging is
+ enabled. It uses the mutex to ensure that this class is not
+ destructed while another thread is currently using it.
+ */
+ ~FaxRenderer();
+
+ /** Opening a file
+
+ This implementation does the necessary consistency checks and
+ complains, e.g. if the file does not exist. It then uses the
+ member 'fax' to load the fax file and initializes the
+ appropriate data structures. The code for loading and rendering
+ is contained in the class "KFaxImage", to keep this reference
+ implementation short.
+
+ @param fname the name of the file that should be opened.
+ */
+ virtual bool setFile(const QString& fname, const KURL &);
+
+ /** Rendering a page
+
+ This implementation first checks if the arguments are in a
+ reasonable range, and error messages are printed if this is not
+ so. Secondly, the page is rendered by the KFaxImage class and
+ the drawn.
+
+ @param res resolution at which drawing should take place
+
+ @param page pointer to a page structur on which we should draw
+ */
+ void drawPage(double res, RenderedDocumentPage* page);
+
+private:
+ /** This class holds the fax file */
+ KFaxImage fax;
+};
+
+#endif
diff --git a/kfaxview/hi16-app-kfaxview.png b/kfaxview/hi16-app-kfaxview.png
new file mode 100644
index 00000000..bb676f8b
--- /dev/null
+++ b/kfaxview/hi16-app-kfaxview.png
Binary files differ
diff --git a/kfaxview/hi22-app-kfaxview.png b/kfaxview/hi22-app-kfaxview.png
new file mode 100644
index 00000000..90fc64b0
--- /dev/null
+++ b/kfaxview/hi22-app-kfaxview.png
Binary files differ
diff --git a/kfaxview/hi32-app-kfaxview.png b/kfaxview/hi32-app-kfaxview.png
new file mode 100644
index 00000000..7330eb41
--- /dev/null
+++ b/kfaxview/hi32-app-kfaxview.png
Binary files differ
diff --git a/kfaxview/hi48-app-kfaxview.png b/kfaxview/hi48-app-kfaxview.png
new file mode 100644
index 00000000..3f58c369
--- /dev/null
+++ b/kfaxview/hi48-app-kfaxview.png
Binary files differ
diff --git a/kfaxview/hisc-app-kfaxview.svgz b/kfaxview/hisc-app-kfaxview.svgz
new file mode 100644
index 00000000..f46fd440
--- /dev/null
+++ b/kfaxview/hisc-app-kfaxview.svgz
Binary files differ
diff --git a/kfaxview/kfaxmultipage.desktop b/kfaxview/kfaxmultipage.desktop
new file mode 100644
index 00000000..1bfc9acc
--- /dev/null
+++ b/kfaxview/kfaxmultipage.desktop
@@ -0,0 +1,60 @@
+[Desktop Entry]
+Name=kfaxview
+Name[hu]=KFaxView
+Name[ja]=KfaxView
+Name[nb]=Kfaxview
+Name[ne]=केडीई फ्याक्स दृश्य
+Name[ro]=KFaxiView
+Name[sv]=Kfaxview
+Name[zh_CN]=KFaxView
+Icon=kfaxview
+Type=Service
+Comment=KViewShell plugin for fax files
+Comment[bg]=Приставка за факс файлове
+Comment[br]=Lugent KViewShell evit ar restroù faks
+Comment[bs]=KViewShell dodatak za fax datoteke
+Comment[ca]=Connector pel KViewShell per a fitxers de fax
+Comment[cs]=KViewShell modul pro faxové soubory
+Comment[da]=Kviewshell-plugin for telefaxfiler
+Comment[de]=Ein Modul für KViewShell zum Betrachten von Faxdateien
+Comment[el]=Πρόσθετο του KViewShell για αρχεία φαξ
+Comment[eo]=KViewShell-kromaĵo for faksdosieroj
+Comment[es]=Extensión KViewShell para archivos de fax
+Comment[et]=KView faksifailide plugin
+Comment[eu]=Fax fitxategientzatko KViewShell-en plugina
+Comment[fa]=وصلۀ KViewShell برای پرونده‌های دورنگار
+Comment[fi]=KViewShell sovelma faksitiedostoille
+Comment[fr]=Module KViewShell pour les fichiers de fax
+Comment[gl]=Extensión de KViewShell para ficheiros de fax
+Comment[hu]=KViewShell-modul faxfájlokhoz
+Comment[is]=KViewShell íforrit fyrir faxskrár
+Comment[it]=Plugin KViewShell per file di fax
+Comment[ja]=ファクスファイル用の KViewShell プラグイン
+Comment[kk]=Факс файлдарын қарау плагин модулі
+Comment[km]=កម្មវិធី​ជំនួយ KViewShell សម្រាប់​ឯកសារ​ទូរសារ
+Comment[lt]=KViewShell priedas fakso byloms
+Comment[ms]=Plugin KViewShell untuk fail faks
+Comment[nb]=KViewShell programtillegg for faksfiler
+Comment[nds]="KViewShell"-Moduul för Faxdateien
+Comment[ne]=फ्याक्स फाइलका लागि केडीई दृश्य शेल प्लगइन
+Comment[nl]=KViewShell-plugin voor faxbestanden
+Comment[nn]=KViewShell-programtillegg for faksfiler
+Comment[pl]=Wtyczka KViewShell do plików faksów
+Comment[pt]='Plugin' do KViewShell para ficheiros de Fax
+Comment[pt_BR]=Plugin KViewShell para arquivos de fax
+Comment[ru]=Компонент просмотра факсов
+Comment[sk]=KViewShell modul pre faxové súbory
+Comment[sl]=Vstavek za KViewShell za fakse
+Comment[sr]=KViewShell-ов прикључак за факс фајлове
+Comment[sr@Latn]=KViewShell-ov priključak za faks fajlove
+Comment[sv]=Kviewshell-insticksprogram för telefaxfiler
+Comment[th]=ปลั๊กอินสำหรับแสดงแฟ้มโทรสารของ KViewShell
+Comment[tr]=Faks dosyaları için KViewShell eklentisi
+Comment[uk]=Втулок перегляду файлів факсів для KViewShell
+Comment[zh_CN]=传真文件的 KViewShell 插件
+Comment[zh_HK]=傳真檔的 KViewShell 插件
+Comment[zh_TW]=KViewShell 傳真檔外掛程式
+ServiceTypes=KViewShell/MultiPage
+X-KDE-MimeTypes=image/fax-g3
+X-KDE-Library=kfaxviewpart
+X-KDE-MultiPageVersion=2
diff --git a/kfaxview/kfaxmultipage_tiff.desktop b/kfaxview/kfaxmultipage_tiff.desktop
new file mode 100644
index 00000000..a1b33913
--- /dev/null
+++ b/kfaxview/kfaxmultipage_tiff.desktop
@@ -0,0 +1,57 @@
+[Desktop Entry]
+Name=kfaxview_tiff
+Name[da]=Kfaxview TIFF
+Name[ne]=केडीई फ्याक्स दृश्य टिफ
+Name[sv]=Kfaxview TIFF
+Name[zh_CN]=KFaxView_tiff
+Icon=kfaxview
+Type=Service
+Comment=KViewShell plugin for fax files
+Comment[bg]=Приставка за факс файлове
+Comment[br]=Lugent KViewShell evit ar restroù faks
+Comment[bs]=KViewShell dodatak za fax datoteke
+Comment[ca]=Connector pel KViewShell per a fitxers de fax
+Comment[cs]=KViewShell modul pro faxové soubory
+Comment[da]=Kviewshell-plugin for telefaxfiler
+Comment[de]=Ein Modul für KViewShell zum Betrachten von Faxdateien
+Comment[el]=Πρόσθετο του KViewShell για αρχεία φαξ
+Comment[eo]=KViewShell-kromaĵo for faksdosieroj
+Comment[es]=Extensión KViewShell para archivos de fax
+Comment[et]=KView faksifailide plugin
+Comment[eu]=Fax fitxategientzatko KViewShell-en plugina
+Comment[fa]=وصلۀ KViewShell برای پرونده‌های دورنگار
+Comment[fi]=KViewShell sovelma faksitiedostoille
+Comment[fr]=Module KViewShell pour les fichiers de fax
+Comment[gl]=Extensión de KViewShell para ficheiros de fax
+Comment[hu]=KViewShell-modul faxfájlokhoz
+Comment[is]=KViewShell íforrit fyrir faxskrár
+Comment[it]=Plugin KViewShell per file di fax
+Comment[ja]=ファクスファイル用の KViewShell プラグイン
+Comment[kk]=Факс файлдарын қарау плагин модулі
+Comment[km]=កម្មវិធី​ជំនួយ KViewShell សម្រាប់​ឯកសារ​ទូរសារ
+Comment[lt]=KViewShell priedas fakso byloms
+Comment[ms]=Plugin KViewShell untuk fail faks
+Comment[nb]=KViewShell programtillegg for faksfiler
+Comment[nds]="KViewShell"-Moduul för Faxdateien
+Comment[ne]=फ्याक्स फाइलका लागि केडीई दृश्य शेल प्लगइन
+Comment[nl]=KViewShell-plugin voor faxbestanden
+Comment[nn]=KViewShell-programtillegg for faksfiler
+Comment[pl]=Wtyczka KViewShell do plików faksów
+Comment[pt]='Plugin' do KViewShell para ficheiros de Fax
+Comment[pt_BR]=Plugin KViewShell para arquivos de fax
+Comment[ru]=Компонент просмотра факсов
+Comment[sk]=KViewShell modul pre faxové súbory
+Comment[sl]=Vstavek za KViewShell za fakse
+Comment[sr]=KViewShell-ов прикључак за факс фајлове
+Comment[sr@Latn]=KViewShell-ov priključak za faks fajlove
+Comment[sv]=Kviewshell-insticksprogram för telefaxfiler
+Comment[th]=ปลั๊กอินสำหรับแสดงแฟ้มโทรสารของ KViewShell
+Comment[tr]=Faks dosyaları için KViewShell eklentisi
+Comment[uk]=Втулок перегляду файлів факсів для KViewShell
+Comment[zh_CN]=传真文件的 KViewShell 插件
+Comment[zh_HK]=傳真檔的 KViewShell 插件
+Comment[zh_TW]=KViewShell 傳真檔外掛程式
+ServiceTypes=KViewShell/MultiPage
+X-KDE-MimeTypes=image/tiff
+X-KDE-Library=kfaxviewpart
+X-KDE-MultiPageVersion=2
diff --git a/kfaxview/kfaxview.desktop b/kfaxview/kfaxview.desktop
new file mode 100644
index 00000000..4dc74ff1
--- /dev/null
+++ b/kfaxview/kfaxview.desktop
@@ -0,0 +1,82 @@
+[Desktop Entry]
+GenericName=Fax Viewer
+GenericName[af]=Faks Aansig
+GenericName[ar]=عارض الفاكس
+GenericName[bg]=Преглед на факсове
+GenericName[br]=Gweler faks
+GenericName[bs]=Preglednik faxova
+GenericName[ca]=Visualitzador de fax
+GenericName[cs]=Prohlížeč faxů
+GenericName[cy]=Gwelydd Ffacs
+GenericName[da]=Fax-fremviser
+GenericName[de]=Faxbetrachter
+GenericName[el]=Προβολέας φαξ
+GenericName[eo]=Faksrigardilo
+GenericName[es]=Visor de faxes
+GenericName[et]=Fakside vaataja
+GenericName[eu]=Fax ikustailua
+GenericName[fa]=مشاهده‌گر دورنگار
+GenericName[fi]=Faksinäytin
+GenericName[fr]=Afficheur de fax
+GenericName[gl]=Visor de fax
+GenericName[he]=מציג פקסים
+GenericName[hi]=फ़ैक्स प्रदर्शक
+GenericName[hr]=Preglednik faksova
+GenericName[hu]=Faxnézegető
+GenericName[is]=Fax sjá
+GenericName[it]=Visore di fax
+GenericName[ja]=ファクスビューア
+GenericName[kk]=Факсты қарау
+GenericName[km]=កម្មវិធី​មើល​ទូរសារ
+GenericName[lt]=Faksų žiūriklis
+GenericName[lv]=Faksu Skatītājs
+GenericName[ms]=Pemapar Faks
+GenericName[nb]=Faksfremviser
+GenericName[nds]=Faxkieker
+GenericName[ne]=फ्याक्स द्रष्टा
+GenericName[nl]=Faxweergaveprogramma
+GenericName[nn]=Faksvisar
+GenericName[pa]=ਫੈਕਸ ਦਰਸ਼ਕ
+GenericName[pl]=Przeglądarka faksów
+GenericName[pt]=Visualizador de Faxes
+GenericName[pt_BR]=Visualizador de Faxes
+GenericName[ro]=Vizualizor FAX
+GenericName[ru]=Просмотр факсов
+GenericName[se]=Fáksačájeheaddji
+GenericName[sk]=Prehliadač faxov
+GenericName[sl]=Pregledovalnik faksov
+GenericName[sr]=Приказивач факсова
+GenericName[sr@Latn]=Prikazivač faksova
+GenericName[sv]=Faxvisare
+GenericName[ta]=ஃபாக்ஸ் காட்சி
+GenericName[tg]=Хондани факс
+GenericName[th]=เครื่องมือแสดงโทรสารของ KDE
+GenericName[tr]=Faks Görüntüleyici
+GenericName[uk]=Переглядач факсів
+GenericName[uz]=Faks koʻruvchi
+GenericName[uz@cyrillic]=Факс кўрувчи
+GenericName[ven]=Muvhoni wa Fekisi
+GenericName[wa]=Håyneu di facs
+GenericName[xh]=Umboniseli Wefax
+GenericName[zh_CN]=传真查看器
+GenericName[zh_HK]=傳真檢視器
+GenericName[zh_TW]=傳真檢視器
+GenericName[zu]=Umbonisi wefax
+Name=KFaxView
+Name[nb]=Kfaxview
+Name[ne]=केडीई फ्याक्स दृश्य
+Name[sv]=Kfaxview
+Name[zh_TW]=KFaxView 傳真檢視
+MimeType=image/fax-g3;
+InitialPreference=6
+Exec=kfaxview %f
+Icon=kfaxview
+Path=
+Type=Application
+Terminal=false
+ServiceTypes=Browser/View
+X-KDE-Library=kviewerpart
+X-KDE-BrowserView-Args=fax
+DocPath=kfaxview/index.html
+X-KDE-StartupNotify=true
+Categories=Qt;KDE;Graphics;
diff --git a/kfaxview/libkfaximage/Makefile.am b/kfaxview/libkfaximage/Makefile.am
new file mode 100644
index 00000000..616afb3c
--- /dev/null
+++ b/kfaxview/libkfaximage/Makefile.am
@@ -0,0 +1,14 @@
+INCLUDES = -I$(top_srcdir) $(all_includes)
+
+lib_LTLIBRARIES = libkfaximage.la
+libkfaximage_la_LDFLAGS = $(all_libraries) -no-undefined -avoid-version
+libkfaximage_la_LIBADD = $(LIB_KDECORE)
+libkfaximage_la_SOURCES = kfaximage.cpp faxexpand.cpp faxinit.cpp
+
+include_HEADERS = kfaximage.h
+noinst_HEADERS = faxexpand.h
+
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) $(libkfaximage_la_SOURCES) -o $(podir)/libkfaximgage.pot
diff --git a/kfaxview/libkfaximage/faxexpand.cpp b/kfaxview/libkfaximage/faxexpand.cpp
new file mode 100644
index 00000000..9c4b4082
--- /dev/null
+++ b/kfaxview/libkfaximage/faxexpand.cpp
@@ -0,0 +1,745 @@
+/* Expand one page of fax data
+ Copyright (C) 1990, 1995 Frank D. Cringle.
+
+This file is part of viewfax - g3/g4 fax processing software.
+
+viewfax 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 <config.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#include <kdebug.h>
+
+#include "faxexpand.h"
+
+//Uncomment this for verbose debug output
+//#define DEBUG_FAX
+#define verbose false
+
+pagenode::pagenode()
+{
+}
+
+/* Note that NeedBits() only works for n <= 16 */
+#define NeedBits(n) do { \
+ if (BitsAvail < (n)) { \
+ BitAcc |= *sp++ << BitsAvail; \
+ BitsAvail += 16; \
+ } \
+} while (0)
+#define GetBits(n) (BitAcc & ((1<<(n))-1))
+#define ClrBits(n) do { \
+ BitAcc >>= (n); \
+ BitsAvail -= (n); \
+} while (0)
+
+#ifdef DEBUG_FAX
+#define DEBUG_SHOW putchar(BitAcc & (1 << t) ? '1' : '0')
+#define LOOKUP(wid,tab) do { \
+ int t; \
+ NeedBits(wid); \
+ TabEnt = tab + GetBits(wid); \
+ printf("%08lX/%d: %s%5d\t", BitAcc, BitsAvail, \
+ StateNames[TabEnt->State], TabEnt->Param); \
+ for (t = 0; t < TabEnt->Width; t++) \
+ DEBUG_SHOW; \
+ putchar('\n'); \
+ fflush(stdout); \
+ ClrBits(TabEnt->Width); \
+} while (0)
+
+#define SETVAL(x) do { \
+ *pa++ = RunLength + (x); \
+ printf("SETVAL: %d\t%d\n", RunLength + (x), a0); \
+ a0 += x; \
+ RunLength = 0; \
+} while (0)
+
+const char *StateNames[] = {
+ "Null ",
+ "Pass ",
+ "Horiz ",
+ "V0 ",
+ "VR ",
+ "VL ",
+ "Ext ",
+ "TermW ",
+ "TermB ",
+ "MakeUpW",
+ "MakeUpB",
+ "MakeUp ",
+ "EOL ",
+};
+
+#else
+#define LOOKUP(wid,tab) do { \
+ NeedBits(wid); \
+ TabEnt = tab + GetBits(wid); \
+ ClrBits(TabEnt->Width); \
+} while (0)
+
+#define SETVAL(x) do { \
+ *pa++ = RunLength + (x); \
+ a0 += x; \
+ RunLength = 0; \
+} while (0)
+#endif
+
+#define dumpruns(runs) do { \
+ printf("-------------------- %d\n", LineNum); \
+ for (pa = runs, a0 = 0; a0 < lastx; a0 += *pa++) \
+ printf("%4d %d\n", a0, *pa); \
+} while (0)
+
+#define EndOfData(pn) (sp >= pn->data + pn->length/sizeof(*pn->data))
+
+/* This macro handles coding errors in G3 data.
+ We redefine it below for the G4 case */
+#define SKIP_EOL do { \
+ while (!EndOfData(pn)) { \
+ NeedBits(11); \
+ if (GetBits(11) == 0) \
+ break; \
+ ClrBits(1); \
+ } \
+ ClrBits(11); \
+ goto EOL; \
+} while (0)
+#define eol2lab EOL2:
+
+/* the line expanders are written as macros so that they can be reused
+ (twice each) but still have direct access to the local variables of
+ the "calling" function */
+#define expand1d() do { \
+ while (a0 < lastx) { \
+ int done = 0; \
+ while (!done) { /* white first */ \
+ LOOKUP(12, WhiteTable); \
+ switch (TabEnt->State) { \
+ case S_EOL: \
+ EOLcnt = 1; \
+ goto EOL; \
+ case S_TermW: \
+ SETVAL(TabEnt->Param); \
+ done = 1; \
+ break; \
+ case S_MakeUpW: \
+ case S_MakeUp: \
+ a0 += TabEnt->Param; \
+ RunLength += TabEnt->Param; \
+ break; \
+ case S_Ext: \
+ unexpected("Extension code", LineNum); \
+ SKIP_EOL; \
+ break; \
+ default: \
+ unexpected("WhiteTable", LineNum); \
+ SKIP_EOL; \
+ break; \
+ } \
+ } \
+ done = a0 >= lastx; \
+ while (!done) { /* then black */ \
+ LOOKUP(13, BlackTable); \
+ switch (TabEnt->State) { \
+ case S_EOL: \
+ EOLcnt = 1; \
+ goto EOL; \
+ case S_TermB: \
+ SETVAL(TabEnt->Param); \
+ done = 1; \
+ break; \
+ case S_MakeUpB: \
+ case S_MakeUp: \
+ a0 += TabEnt->Param; \
+ RunLength += TabEnt->Param; \
+ break; \
+ case S_Ext: \
+ unexpected("Extension code", LineNum); \
+ SKIP_EOL; \
+ break; \
+ default: \
+ unexpected("BlackTable", LineNum); \
+ SKIP_EOL; \
+ break; \
+ } \
+ } \
+ } \
+ EOL: ; \
+} while (0)
+
+#define CHECK_b1 do { \
+ if (pa != thisrun) while (b1 <= a0 && b1 < lastx) { \
+ b1 += pb[0] + pb[1]; \
+ pb += 2; \
+ } \
+} while (0)
+
+#define expand2d(eolab) do { \
+ while (a0 < lastx) { \
+ LOOKUP(7, MainTable); \
+ switch (TabEnt->State) { \
+ case S_Pass: \
+ CHECK_b1; \
+ b1 += *pb++; \
+ RunLength += b1 - a0; \
+ a0 = b1; \
+ b1 += *pb++; \
+ break; \
+ case S_Horiz: \
+ if ((pa-run0)&1) { \
+ int done = 0; \
+ while (!done) { /* black first */ \
+ LOOKUP(13, BlackTable); \
+ switch (TabEnt->State) { \
+ case S_TermB: \
+ SETVAL(TabEnt->Param); \
+ done = 1; \
+ break; \
+ case S_MakeUpB: \
+ case S_MakeUp: \
+ a0 += TabEnt->Param; \
+ RunLength += TabEnt->Param; \
+ break; \
+ default: \
+ unexpected("BlackTable", LineNum); \
+ SKIP_EOL; \
+ break; \
+ } \
+ } \
+ done = 0; \
+ while (!done) { /* then white */ \
+ LOOKUP(12, WhiteTable); \
+ switch (TabEnt->State) { \
+ case S_TermW: \
+ SETVAL(TabEnt->Param); \
+ done = 1; \
+ break; \
+ case S_MakeUpW: \
+ case S_MakeUp: \
+ a0 += TabEnt->Param; \
+ RunLength += TabEnt->Param; \
+ break; \
+ default: \
+ unexpected("WhiteTable", LineNum); \
+ SKIP_EOL; \
+ break; \
+ } \
+ } \
+ } \
+ else { \
+ int done = 0; \
+ while (!done) { /* white first */ \
+ LOOKUP(12, WhiteTable); \
+ switch (TabEnt->State) { \
+ case S_TermW: \
+ SETVAL(TabEnt->Param); \
+ done = 1; \
+ break; \
+ case S_MakeUpW: \
+ case S_MakeUp: \
+ a0 += TabEnt->Param; \
+ RunLength += TabEnt->Param; \
+ break; \
+ default: \
+ unexpected("WhiteTable", LineNum); \
+ SKIP_EOL; \
+ break; \
+ } \
+ } \
+ done = 0; \
+ while (!done) { /* then black */ \
+ LOOKUP(13, BlackTable); \
+ switch (TabEnt->State) { \
+ case S_TermB: \
+ SETVAL(TabEnt->Param); \
+ done = 1; \
+ break; \
+ case S_MakeUpB: \
+ case S_MakeUp: \
+ a0 += TabEnt->Param; \
+ RunLength += TabEnt->Param; \
+ break; \
+ default: \
+ unexpected("BlackTable", LineNum); \
+ SKIP_EOL; \
+ break; \
+ } \
+ } \
+ } \
+ CHECK_b1; \
+ break; \
+ case S_V0: \
+ CHECK_b1; \
+ SETVAL(b1 - a0); \
+ b1 += *pb++; \
+ break; \
+ case S_VR: \
+ CHECK_b1; \
+ SETVAL(b1 - a0 + TabEnt->Param); \
+ b1 += *pb++; \
+ break; \
+ case S_VL: \
+ CHECK_b1; \
+ SETVAL(b1 - a0 - TabEnt->Param); \
+ b1 -= *--pb; \
+ break; \
+ case S_Ext: \
+ *pa++ = lastx - a0; \
+ if (verbose) \
+ kdDebug() << "Line " << LineNum << ": extension code\n";\
+ SKIP_EOL; \
+ break; \
+ case S_EOL: \
+ *pa++ = lastx - a0; \
+ NeedBits(4); \
+ if (GetBits(4) && verbose) /* already seen 7 zeros */ \
+ kdDebug() << "Line " << LineNum << ": Bad EOL\n"; \
+ ClrBits(4); \
+ EOLcnt = 1; \
+ goto eolab; \
+ break; \
+ default: \
+ unexpected("MainTable", LineNum); \
+ SKIP_EOL; \
+ break; \
+ } \
+ } \
+ if (RunLength) { \
+ if (RunLength + a0 < lastx) { \
+ /* expect a final V0 */ \
+ NeedBits(1); \
+ if (!GetBits(1)) { \
+ unexpected("MainTable", LineNum); \
+ SKIP_EOL; \
+ } \
+ ClrBits(1); \
+ } \
+ SETVAL(0); \
+ } \
+ eol2lab ; \
+} while (0)
+
+static void
+unexpected(const char *what, int LineNum)
+{
+ if (verbose)
+ kdError() << "Line " << LineNum << ": Unexpected state in "
+ << what << endl;
+}
+
+/* Expand tiff modified huffman data (g3-1d without EOLs) */
+void
+MHexpand(struct pagenode *pn, drawfunc df)
+{
+ int a0; /* reference element */
+ int lastx; /* copy line width to register */
+ t32bits BitAcc; /* bit accumulator */
+ int BitsAvail; /* # valid bits in BitAcc */
+ int RunLength; /* Length of current run */
+ t16bits *sp; /* pointer into compressed data */
+ pixnum *pa; /* pointer into new line */
+ int EOLcnt; /* number of consecutive EOLs */
+ int LineNum; /* line number */
+ pixnum *runs; /* list of run lengths */
+ struct tabent *TabEnt;
+
+ sp = pn->data;
+ BitAcc = 0;
+ BitsAvail = 0;
+ lastx = pn->size.width();
+ runs = (pixnum *) malloc(lastx * sizeof(pixnum));
+ for (LineNum = 0; LineNum < pn->rowsperstrip; ) {
+#ifdef DEBUG_FAX
+ printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail);
+ printf("-------------------- %d\n", LineNum);
+ fflush(stdout);
+#endif
+ RunLength = 0;
+ pa = runs;
+ a0 = 0;
+ EOLcnt = 0;
+ if (BitsAvail & 7) /* skip to byte boundary */
+ ClrBits(BitsAvail & 7);
+ expand1d();
+ if (RunLength)
+ SETVAL(0);
+ if (a0 != lastx) {
+ if (verbose)
+ kdWarning() << "Line " << LineNum << ": length is "
+ << a0 << " (expected "<< lastx << ")\n";
+ while (a0 > lastx)
+ a0 -= *--pa;
+ if (a0 < lastx) {
+ if ((pa - runs) & 1)
+ SETVAL(0);
+ SETVAL(lastx - a0);
+ }
+ }
+ (*df)(runs, LineNum++, pn);
+ }
+ free(runs);
+}
+
+/* Expand group-3 1-dimensional data */
+void
+g31expand(struct pagenode *pn, drawfunc df)
+{
+ int a0; /* reference element */
+ int lastx; /* copy line width to register */
+ t32bits BitAcc; /* bit accumulator */
+ int BitsAvail; /* # valid bits in BitAcc */
+ int RunLength; /* Length of current run */
+ t16bits *sp; /* pointer into compressed data */
+ pixnum *pa; /* pointer into new line */
+ int EOLcnt; /* number of consecutive EOLs */
+ int LineNum; /* line number */
+ pixnum *runs; /* list of run lengths */
+ struct tabent *TabEnt;
+
+ sp = pn->data;
+ BitAcc = 0;
+ BitsAvail = 0;
+ lastx = pn->size.width();
+ runs = (pixnum *) malloc(lastx * sizeof(pixnum));
+ EOLcnt = 0;
+ for (LineNum = 0; LineNum < pn->rowsperstrip; ) {
+#ifdef DEBUG_FAX
+ printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail);
+ printf("-------------------- %d\n", LineNum);
+ fflush(stdout);
+#endif
+ if (EOLcnt == 0)
+ while (!EndOfData(pn)) {
+ /* skip over garbage after a coding error */
+ NeedBits(11);
+ if (GetBits(11) == 0)
+ break;
+ ClrBits(1);
+ }
+ for (EOLcnt = 1; !EndOfData(pn); EOLcnt++) {
+ /* we have seen 11 zeros, which implies EOL,
+ skip possible fill bits too */
+ while (1) {
+ NeedBits(8);
+ if (GetBits(8))
+ break;
+ ClrBits(8);
+ }
+ while (GetBits(1) == 0)
+ ClrBits(1);
+ ClrBits(1); /* the eol flag */
+ NeedBits(11);
+ if (GetBits(11))
+ break;
+ ClrBits(11);
+ }
+ if (EOLcnt > 1 && EOLcnt != 6 && verbose)
+ kdError() << "Line " << LineNum << ": bad RTC (" << EOLcnt << " EOLs)\n";
+ if (EOLcnt >= 6 || EndOfData(pn)) {
+ free(runs);
+ return;
+ }
+ RunLength = 0;
+ pa = runs;
+ a0 = 0;
+ EOLcnt = 0;
+ expand1d();
+ if (RunLength)
+ SETVAL(0);
+ if (a0 != lastx) {
+ if (verbose)
+ kdWarning() << "Line " << LineNum << ": length is "
+ << a0 << " (expected "<< lastx << ")\n";
+ while (a0 > lastx)
+ a0 -= *--pa;
+ if (a0 < lastx) {
+ if ((pa - runs) & 1)
+ SETVAL(0);
+ SETVAL(lastx - a0);
+ }
+ }
+ (*df)(runs, LineNum++, pn);
+ }
+ free(runs);
+}
+
+/* Expand group-3 2-dimensional data */
+void
+g32expand(struct pagenode *pn, drawfunc df)
+{
+ int RunLength; /* Length of current run */
+ int a0; /* reference element */
+ int b1; /* next change on previous line */
+ int lastx = pn->size.width();/* copy line width to register */
+ pixnum *run0, *run1; /* run length arrays */
+ pixnum *thisrun, *pa, *pb; /* pointers into runs */
+ t16bits *sp; /* pointer into compressed data */
+ t32bits BitAcc; /* bit accumulator */
+ int BitsAvail; /* # valid bits in BitAcc */
+ int EOLcnt; /* number of consecutive EOLs */
+ int refline = 0; /* 1D encoded reference line */
+ int LineNum; /* line number */
+ struct tabent *TabEnt;
+
+ sp = pn->data;
+ BitAcc = 0;
+ BitsAvail = 0;
+ /* allocate space for 2 runlength arrays */
+ run0 = (pixnum *) malloc(2 * ((lastx+5)&~1) * sizeof(pixnum));
+ run1 = run0 + ((lastx+5)&~1);
+ run1[0] = lastx;
+ run1[1] = 0;
+ EOLcnt = 0;
+ for (LineNum = 0; LineNum < pn->rowsperstrip; ) {
+#ifdef DEBUG_FAX
+ printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail);
+ printf("-------------------- %d\n", LineNum);
+ fflush(stdout);
+#endif
+ if (EOLcnt == 0)
+ while (!EndOfData(pn)) {
+ /* skip over garbage after a coding error */
+ NeedBits(11);
+ if (GetBits(11) == 0)
+ break;
+ ClrBits(1);
+ }
+ for (EOLcnt = 1; !EndOfData(pn); EOLcnt++) {
+ /* we have seen 11 zeros, which implies EOL,
+ skip possible fill bits too */
+ while (1) {
+ NeedBits(8);
+ if (GetBits(8))
+ break;
+ ClrBits(8);
+ }
+ while (GetBits(1) == 0)
+ ClrBits(1);
+ ClrBits(1); /* the eol flag */
+ NeedBits(12);
+ refline = GetBits(1); /* 1D / 2D flag */
+ ClrBits(1);
+ if (GetBits(11))
+ break;
+ ClrBits(11);
+ }
+ if (EOLcnt > 1 && EOLcnt != 6 && verbose)
+ kdError() << "Line " << LineNum << ": bad RTC (" << EOLcnt << " EOLs)\n";
+ if (EOLcnt >= 6 || EndOfData(pn)) {
+ free(run0);
+ return;
+ }
+ if (LineNum == 0 && refline == 0 && verbose)
+ kdDebug() << "First line is 2-D encoded\n";
+ RunLength = 0;
+ if (LineNum & 1) {
+ pa = run1;
+ pb = run0;
+ }
+ else {
+ pa = run0;
+ pb = run1;
+ }
+ thisrun = pa;
+ EOLcnt = 0;
+ a0 = 0;
+ b1 = *pb++;
+
+ if (refline) {
+ expand1d();
+ }
+ else {
+ expand2d(EOL2);
+ }
+ if (RunLength)
+ SETVAL(0);
+ if (a0 != lastx) {
+ if (verbose)
+ kdWarning() << "Line " << LineNum << ": length is "
+ << a0 << " (expected "<< lastx << ")\n";
+ while (a0 > lastx)
+ a0 -= *--pa;
+ if (a0 < lastx) {
+ if ((pa - run0) & 1)
+ SETVAL(0);
+ SETVAL(lastx - a0);
+ }
+ }
+ SETVAL(0); /* imaginary change at end of line for reference */
+ (*df)(thisrun, LineNum++, pn);
+ }
+ free(run0);
+}
+
+/* Redefine the "skip to eol" macro. We cannot recover from coding
+ errors in G4 data */
+#undef SKIP_EOL
+#undef eol2lab
+#define SKIP_EOL do { \
+ if (verbose) \
+ kdError() << "Line " << LineNum << ": G4 coding error\n"; \
+ free(run0); \
+ return; \
+} while (0)
+#define eol2lab
+
+/* Expand group-4 data */
+void
+g4expand(struct pagenode *pn, drawfunc df)
+{
+ int RunLength; /* Length of current run */
+ int a0; /* reference element */
+ int b1; /* next change on previous line */
+ int lastx = pn->size.width();/* copy line width to register */
+ pixnum *run0, *run1; /* run length arrays */
+ pixnum *thisrun, *pa, *pb; /* pointers into runs */
+ t16bits *sp; /* pointer into compressed data */
+ t32bits BitAcc; /* bit accumulator */
+ int BitsAvail; /* # valid bits in BitAcc */
+ int LineNum; /* line number */
+ int EOLcnt;
+ struct tabent *TabEnt;
+
+ sp = pn->data;
+ BitAcc = 0;
+ BitsAvail = 0;
+ /* allocate space for 2 runlength arrays */
+ run0 = (pixnum *) malloc(2 * ((lastx+5)&~1) * sizeof(pixnum));
+ run1 = run0 + ((lastx+5)&~1);
+ run1[0] = lastx; /* initial reference line */
+ run1[1] = 0;
+
+ for (LineNum = 0; LineNum < pn->rowsperstrip; ) {
+#ifdef DEBUG_FAX
+ printf("\nBitAcc=%08lX, BitsAvail = %d\n", BitAcc, BitsAvail);
+ printf("-------------------- %d\n", LineNum);
+ fflush(stdout);
+#endif
+ RunLength = 0;
+ if (LineNum & 1) {
+ pa = run1;
+ pb = run0;
+ }
+ else {
+ pa = run0;
+ pb = run1;
+ }
+ thisrun = pa;
+ a0 = 0;
+ b1 = *pb++;
+ expand2d(EOFB);
+ if (a0 < lastx) {
+ if ((pa - run0) & 1)
+ SETVAL(0);
+ SETVAL(lastx - a0);
+ }
+ SETVAL(0); /* imaginary change at end of line for reference */
+ (*df)(thisrun, LineNum++, pn);
+ continue;
+ EOFB:
+ NeedBits(13);
+ if (GetBits(13) != 0x1001 && verbose)
+ kdError() << "Bad RTC\n";
+ break;
+ }
+ free(run0);
+}
+
+static const unsigned char zerotab[256] = {
+ 0x88, 0x07, 0x16, 0x06, 0x25, 0x05, 0x15, 0x05,
+ 0x34, 0x04, 0x14, 0x04, 0x24, 0x04, 0x14, 0x04,
+ 0x43, 0x03, 0x13, 0x03, 0x23, 0x03, 0x13, 0x03,
+ 0x33, 0x03, 0x13, 0x03, 0x23, 0x03, 0x13, 0x03,
+ 0x52, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02,
+ 0x32, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02,
+ 0x42, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02,
+ 0x32, 0x02, 0x12, 0x02, 0x22, 0x02, 0x12, 0x02,
+ 0x61, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
+ 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
+ 0x41, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
+ 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
+ 0x51, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
+ 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
+ 0x41, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
+ 0x31, 0x01, 0x11, 0x01, 0x21, 0x01, 0x11, 0x01,
+ 0x70, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x50, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x60, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x50, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x40, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00,
+ 0x30, 0x00, 0x10, 0x00, 0x20, 0x00, 0x10, 0x00
+};
+
+#define check(v) do { \
+ prezeros = zerotab[v]; \
+ postzeros = prezeros & 15; \
+ prezeros >>= 4; \
+ if (prezeros == 8) { \
+ zeros += 8; \
+ continue; \
+ } \
+ if (zeros + prezeros < 11) { \
+ empty = 0; \
+ zeros = postzeros; \
+ continue; \
+ } \
+ zeros = postzeros; \
+ if (empty) \
+ EOLcnt++; \
+ lines++; \
+ empty = 1; \
+} while (0)
+
+/* count fax lines */
+int
+G3count(struct pagenode *pn, int twoD)
+{
+ t16bits *p = pn->data;
+ t16bits *end = p + pn->length/sizeof(*p);
+ int lines = 0; /* lines seen so far */
+ int zeros = 0; /* number of consecutive zero bits seen */
+ int EOLcnt = 0; /* number of consecutive EOLs seen */
+ int empty = 1; /* empty line */
+ int prezeros, postzeros;
+
+ while (p < end && EOLcnt < 6) {
+ t16bits bits = *p++;
+ check(bits&255);
+ if (twoD && (prezeros + postzeros == 7)) {
+ if (postzeros || ((bits & 0x100) == 0))
+ zeros--;
+ }
+ check(bits>>8);
+ if (twoD && (prezeros + postzeros == 7)) {
+ if (postzeros || ((p < end) && ((*p & 1) == 0)))
+ zeros--;
+ }
+ }
+ return lines - EOLcnt; /* don't count trailing EOLs */
+}
diff --git a/kfaxview/libkfaximage/faxexpand.h b/kfaxview/libkfaximage/faxexpand.h
new file mode 100644
index 00000000..8da4e8bc
--- /dev/null
+++ b/kfaxview/libkfaximage/faxexpand.h
@@ -0,0 +1,126 @@
+/* Include file for fax routines
+ Copyright (C) 1990, 1995 Frank D. Cringle.
+ Copyright (C) 2005 Helge Deller <deller@kde.org>
+
+This file is part of viewfax - g3/g4 fax processing software.
+
+viewfax 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 _faxexpand_h_
+#define _faxexpand_h_
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <qglobal.h>
+#include <qimage.h>
+
+#define t32bits Q_UINT32
+#define t16bits Q_UINT16
+
+typedef t16bits pixnum;
+
+class pagenode;
+
+/* drawfunc() points to a function which processes a line of the
+ expanded image described as a list of run lengths.
+ run is the base of an array of lengths, starting with a
+ (possibly empty) white run for line number linenum.
+ pn points to the page descriptor */
+typedef void (*drawfunc)(pixnum *run, int linenum, class pagenode *pn);
+
+struct strip { /* tiff strip descriptor */
+ off_t offset; /* offset in file */
+ off_t size; /* size of this strip */
+};
+
+
+/* defines for the pagenode member: type */
+#define FAX_TIFF 1
+#define FAX_RAW 2
+
+class pagenode { /* compressed page descriptor */
+ public:
+ pagenode();
+ ~pagenode() { };
+ int nstrips; /* number of strips */
+ int rowsperstrip; /* number of rows per strip */
+ int stripnum; /* current strip while expanding */
+ struct strip *strips; /* array of strips containing fax data in file */
+ t16bits *data; /* in-memory copy of strip */
+ size_t length; /* length of data */
+ QSize size; /* width & height of page in pixels */
+ int inverse; /* black <=> white */
+ int lsbfirst; /* bit order is lsb first */
+ int type; /* Bernd: tiff vs no tiff*/
+ int orient; /* orientation - upsidedown, landscape, mirrored */
+ int vres; /* vertical resolution: 1 = fine */
+ QPoint dpi; /* DPI horz/vert */
+ void (*expander)(class pagenode *, drawfunc);
+ QImage image;
+ unsigned int bytes_per_line;
+};
+
+extern class pagenode *firstpage, *lastpage, *thispage;
+extern class pagenode defaultpage;
+
+/* page orientation flags */
+#define TURN_NONE 0
+#define TURN_U 1
+#define TURN_L 2
+#define TURN_M 4
+
+/* fsm state codes */
+#define S_Null 0
+#define S_Pass 1
+#define S_Horiz 2
+#define S_V0 3
+#define S_VR 4
+#define S_VL 5
+#define S_Ext 6
+#define S_TermW 7
+#define S_TermB 8
+#define S_MakeUpW 9
+#define S_MakeUpB 10
+#define S_MakeUp 11
+#define S_EOL 12
+
+/* state table entry */
+struct tabent {
+ unsigned char State;
+ unsigned char Width; /* width of code in bits */
+ pixnum Param; /* run length */
+};
+
+extern struct tabent MainTable[]; /* 2-D state table */
+extern struct tabent WhiteTable[]; /* White run lengths */
+extern struct tabent BlackTable[]; /* Black run lengths */
+
+void MHexpand(class pagenode *pn, drawfunc df);
+void g31expand(class pagenode *pn, drawfunc df);
+void g32expand(class pagenode *pn, drawfunc df);
+void g4expand(class pagenode *pn, drawfunc df);
+
+unsigned char *getstrip(class pagenode *pn, int strip);
+class pagenode *notefile(const char *name);
+int notetiff(const char *name);
+
+/* initialise code tables */
+extern void fax_init_tables(void);
+
+/* count lines in image */
+extern int G3count(class pagenode *pn, int twoD);
+
+#endif
diff --git a/kfaxview/libkfaximage/faxinit.cpp b/kfaxview/libkfaximage/faxinit.cpp
new file mode 100644
index 00000000..aa6166aa
--- /dev/null
+++ b/kfaxview/libkfaximage/faxinit.cpp
@@ -0,0 +1,345 @@
+/* Initialise fax decoder tables
+ Copyright (C) 1990, 1995 Frank D. Cringle.
+
+This file is part of viewfax - g3/g4 fax processing software.
+
+viewfax 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 <config.h>
+
+#include <sys/types.h>
+#include "faxexpand.h"
+
+struct tabent MainTable[128];
+struct tabent WhiteTable[4096];
+struct tabent BlackTable[8192];
+
+struct proto {
+ t16bits code; /* right justified, lsb-first, zero filled */
+ t16bits val; /* (pixel count)<<4 + code width */
+};
+
+static const struct proto Pass[] = {
+{ 0x0008, 4 },
+{ 0, 0 }
+};
+
+static const struct proto Horiz[] = {
+{ 0x0004, 3 },
+{ 0, 0 }
+};
+
+static const struct proto V0[] = {
+{ 0x0001, 1 },
+{ 0, 0 }
+};
+
+static const struct proto VR[] = {
+{ 0x0006, (1<<4)+3 },
+{ 0x0030, (2<<4)+6 },
+{ 0x0060, (3<<4)+7 },
+{ 0, 0 }
+};
+
+static const struct proto VL[] = {
+{ 0x0002, (1<<4)+3 },
+{ 0x0010, (2<<4)+6 },
+{ 0x0020, (3<<4)+7 },
+{ 0, 0 }
+};
+
+static const struct proto ExtV[] = {
+{ 0x0040, 7 },
+{ 0, 0 }
+};
+
+static const struct proto EOLV[] = {
+{ 0x0000, 7 },
+{ 0, 0 }
+};
+
+static const struct proto MakeUpW[] = {
+{ 0x001b, 1029 },
+{ 0x0009, 2053 },
+{ 0x003a, 3078 },
+{ 0x0076, 4103 },
+{ 0x006c, 5128 },
+{ 0x00ec, 6152 },
+{ 0x0026, 7176 },
+{ 0x00a6, 8200 },
+{ 0x0016, 9224 },
+{ 0x00e6, 10248 },
+{ 0x0066, 11273 },
+{ 0x0166, 12297 },
+{ 0x0096, 13321 },
+{ 0x0196, 14345 },
+{ 0x0056, 15369 },
+{ 0x0156, 16393 },
+{ 0x00d6, 17417 },
+{ 0x01d6, 18441 },
+{ 0x0036, 19465 },
+{ 0x0136, 20489 },
+{ 0x00b6, 21513 },
+{ 0x01b6, 22537 },
+{ 0x0032, 23561 },
+{ 0x0132, 24585 },
+{ 0x00b2, 25609 },
+{ 0x0006, 26630 },
+{ 0x01b2, 27657 },
+{ 0, 0 }
+};
+
+static const struct proto MakeUpB[] = {
+{ 0x03c0, 1034 },
+{ 0x0130, 2060 },
+{ 0x0930, 3084 },
+{ 0x0da0, 4108 },
+{ 0x0cc0, 5132 },
+{ 0x02c0, 6156 },
+{ 0x0ac0, 7180 },
+{ 0x06c0, 8205 },
+{ 0x16c0, 9229 },
+{ 0x0a40, 10253 },
+{ 0x1a40, 11277 },
+{ 0x0640, 12301 },
+{ 0x1640, 13325 },
+{ 0x09c0, 14349 },
+{ 0x19c0, 15373 },
+{ 0x05c0, 16397 },
+{ 0x15c0, 17421 },
+{ 0x0dc0, 18445 },
+{ 0x1dc0, 19469 },
+{ 0x0940, 20493 },
+{ 0x1940, 21517 },
+{ 0x0540, 22541 },
+{ 0x1540, 23565 },
+{ 0x0b40, 24589 },
+{ 0x1b40, 25613 },
+{ 0x04c0, 26637 },
+{ 0x14c0, 27661 },
+{ 0, 0 }
+};
+
+static const struct proto MakeUp[] = {
+{ 0x0080, 28683 },
+{ 0x0180, 29707 },
+{ 0x0580, 30731 },
+{ 0x0480, 31756 },
+{ 0x0c80, 32780 },
+{ 0x0280, 33804 },
+{ 0x0a80, 34828 },
+{ 0x0680, 35852 },
+{ 0x0e80, 36876 },
+{ 0x0380, 37900 },
+{ 0x0b80, 38924 },
+{ 0x0780, 39948 },
+{ 0x0f80, 40972 },
+{ 0, 0 }
+};
+
+static const struct proto TermW[] = {
+{ 0x00ac, 8 },
+{ 0x0038, 22 },
+{ 0x000e, 36 },
+{ 0x0001, 52 },
+{ 0x000d, 68 },
+{ 0x0003, 84 },
+{ 0x0007, 100 },
+{ 0x000f, 116 },
+{ 0x0019, 133 },
+{ 0x0005, 149 },
+{ 0x001c, 165 },
+{ 0x0002, 181 },
+{ 0x0004, 198 },
+{ 0x0030, 214 },
+{ 0x000b, 230 },
+{ 0x002b, 246 },
+{ 0x0015, 262 },
+{ 0x0035, 278 },
+{ 0x0072, 295 },
+{ 0x0018, 311 },
+{ 0x0008, 327 },
+{ 0x0074, 343 },
+{ 0x0060, 359 },
+{ 0x0010, 375 },
+{ 0x000a, 391 },
+{ 0x006a, 407 },
+{ 0x0064, 423 },
+{ 0x0012, 439 },
+{ 0x000c, 455 },
+{ 0x0040, 472 },
+{ 0x00c0, 488 },
+{ 0x0058, 504 },
+{ 0x00d8, 520 },
+{ 0x0048, 536 },
+{ 0x00c8, 552 },
+{ 0x0028, 568 },
+{ 0x00a8, 584 },
+{ 0x0068, 600 },
+{ 0x00e8, 616 },
+{ 0x0014, 632 },
+{ 0x0094, 648 },
+{ 0x0054, 664 },
+{ 0x00d4, 680 },
+{ 0x0034, 696 },
+{ 0x00b4, 712 },
+{ 0x0020, 728 },
+{ 0x00a0, 744 },
+{ 0x0050, 760 },
+{ 0x00d0, 776 },
+{ 0x004a, 792 },
+{ 0x00ca, 808 },
+{ 0x002a, 824 },
+{ 0x00aa, 840 },
+{ 0x0024, 856 },
+{ 0x00a4, 872 },
+{ 0x001a, 888 },
+{ 0x009a, 904 },
+{ 0x005a, 920 },
+{ 0x00da, 936 },
+{ 0x0052, 952 },
+{ 0x00d2, 968 },
+{ 0x004c, 984 },
+{ 0x00cc, 1000 },
+{ 0x002c, 1016 },
+{ 0, 0 }
+};
+
+static const struct proto TermB[] = {
+{ 0x03b0, 10 },
+{ 0x0002, 19 },
+{ 0x0003, 34 },
+{ 0x0001, 50 },
+{ 0x0006, 67 },
+{ 0x000c, 84 },
+{ 0x0004, 100 },
+{ 0x0018, 117 },
+{ 0x0028, 134 },
+{ 0x0008, 150 },
+{ 0x0010, 167 },
+{ 0x0050, 183 },
+{ 0x0070, 199 },
+{ 0x0020, 216 },
+{ 0x00e0, 232 },
+{ 0x0030, 249 },
+{ 0x03a0, 266 },
+{ 0x0060, 282 },
+{ 0x0040, 298 },
+{ 0x0730, 315 },
+{ 0x00b0, 331 },
+{ 0x01b0, 347 },
+{ 0x0760, 363 },
+{ 0x00a0, 379 },
+{ 0x0740, 395 },
+{ 0x00c0, 411 },
+{ 0x0530, 428 },
+{ 0x0d30, 444 },
+{ 0x0330, 460 },
+{ 0x0b30, 476 },
+{ 0x0160, 492 },
+{ 0x0960, 508 },
+{ 0x0560, 524 },
+{ 0x0d60, 540 },
+{ 0x04b0, 556 },
+{ 0x0cb0, 572 },
+{ 0x02b0, 588 },
+{ 0x0ab0, 604 },
+{ 0x06b0, 620 },
+{ 0x0eb0, 636 },
+{ 0x0360, 652 },
+{ 0x0b60, 668 },
+{ 0x05b0, 684 },
+{ 0x0db0, 700 },
+{ 0x02a0, 716 },
+{ 0x0aa0, 732 },
+{ 0x06a0, 748 },
+{ 0x0ea0, 764 },
+{ 0x0260, 780 },
+{ 0x0a60, 796 },
+{ 0x04a0, 812 },
+{ 0x0ca0, 828 },
+{ 0x0240, 844 },
+{ 0x0ec0, 860 },
+{ 0x01c0, 876 },
+{ 0x0e40, 892 },
+{ 0x0140, 908 },
+{ 0x01a0, 924 },
+{ 0x09a0, 940 },
+{ 0x0d40, 956 },
+{ 0x0340, 972 },
+{ 0x05a0, 988 },
+{ 0x0660, 1004 },
+{ 0x0e60, 1020 },
+{ 0, 0 }
+};
+
+static const struct proto ExtH[] = {
+{ 0x0100, 9 },
+{ 0, 0 }
+};
+
+static const struct proto EOLH[] = {
+{ 0x0000, 11 },
+{ 0, 0 }
+};
+
+static void
+FillTable(struct tabent *T, int Size, const struct proto *P, int State)
+{
+ int limit = 1 << Size;
+
+ while (P->val) {
+ int width = P->val & 15;
+ int param = P->val >> 4;
+ int incr = 1 << width;
+ int code;
+ for (code = P->code; code < limit; code += incr) {
+ struct tabent *E = T+code;
+ E->State = State;
+ E->Width = width;
+ E->Param = param;
+ }
+ P++;
+ }
+}
+
+/* initialise the huffman code tables */
+void
+fax_init_tables(void)
+{
+ static bool already_initialized = 0;
+ if (already_initialized)
+ return;
+
+ ++already_initialized;
+
+ FillTable(MainTable, 7, Pass, S_Pass);
+ FillTable(MainTable, 7, Horiz, S_Horiz);
+ FillTable(MainTable, 7, V0, S_V0);
+ FillTable(MainTable, 7, VR, S_VR);
+ FillTable(MainTable, 7, VL, S_VL);
+ FillTable(MainTable, 7, ExtV, S_Ext);
+ FillTable(MainTable, 7, EOLV, S_EOL);
+ FillTable(WhiteTable, 12, MakeUpW, S_MakeUpW);
+ FillTable(WhiteTable, 12, MakeUp, S_MakeUp);
+ FillTable(WhiteTable, 12, TermW, S_TermW);
+ FillTable(WhiteTable, 12, ExtH, S_Ext);
+ FillTable(WhiteTable, 12, EOLH, S_EOL);
+ FillTable(BlackTable, 13, MakeUpB, S_MakeUpB);
+ FillTable(BlackTable, 13, MakeUp, S_MakeUp);
+ FillTable(BlackTable, 13, TermB, S_TermB);
+ FillTable(BlackTable, 13, ExtH, S_Ext);
+ FillTable(BlackTable, 13, EOLH, S_EOL);
+}
diff --git a/kfaxview/libkfaximage/kfaximage.cpp b/kfaxview/libkfaximage/kfaximage.cpp
new file mode 100644
index 00000000..28744923
--- /dev/null
+++ b/kfaxview/libkfaximage/kfaximage.cpp
@@ -0,0 +1,667 @@
+/*
+ This file is part of KDE FAX image library
+ Copyright (c) 2005 Helge Deller <deller@kde.org>
+
+ based on Frank D. Cringle's viewfax package
+ Copyright (C) 1990, 1995 Frank D. Cringle.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <config.h>
+
+#include <stdlib.h>
+
+#include <qimage.h>
+#include <qfile.h>
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "faxexpand.h"
+#include "kfaximage.h"
+
+static const char FAXMAGIC[] = "\000PC Research, Inc\000\000\000\000\000\000";
+static const char littleTIFF[] = "\x49\x49\x2a\x00";
+static const char bigTIFF[] = "\x4d\x4d\x00\x2a";
+
+KFaxImage::KFaxImage( const QString &filename, QObject *parent, const char *name )
+ : QObject(parent,name)
+{
+ KGlobal::locale()->insertCatalogue( QString::fromLatin1("libkfaximage") );
+ loadImage(filename);
+}
+
+KFaxImage::~KFaxImage()
+{ }
+
+bool KFaxImage::loadImage( const QString &filename )
+{
+ reset();
+
+ m_filename = filename;
+ m_errorString = QString::null;
+
+ if (m_filename.isEmpty())
+ return false;
+
+ int ok = notetiff();
+ if (!ok) {
+ reset();
+ }
+ return ok == 1;
+}
+
+void KFaxImage::reset()
+{
+ fax_init_tables();
+ m_pagenodes.setAutoDelete(true);
+ m_pagenodes.clear();
+ // do not reset m_errorString and m_filename, since
+ // they may be needed by calling application
+}
+
+QImage KFaxImage::page( unsigned int pageNr )
+{
+ if (pageNr >= numPages()) {
+ kdDebug() << "KFaxImage::page() called with invalid page number\n";
+ return QImage();
+ }
+ pagenode *pn = m_pagenodes.at(pageNr);
+ GetImage(pn);
+ return pn->image;
+}
+
+QPoint KFaxImage::page_dpi( unsigned int pageNr )
+{
+ if (pageNr >= numPages()) {
+ kdDebug() << "KFaxImage::page_dpi() called with invalid page number\n";
+ return QPoint(0,0);
+ }
+ pagenode *pn = m_pagenodes.at(pageNr);
+ GetImage(pn);
+ return pn->dpi;
+}
+
+QSize KFaxImage::page_size( unsigned int pageNr )
+{
+ if (pageNr >= numPages()) {
+ kdDebug() << "KFaxImage::page_size() called with invalid page number\n";
+ return QSize(0,0);
+ }
+ pagenode *pn = m_pagenodes.at(pageNr);
+ GetImage(pn);
+ return pn->size;
+}
+
+
+pagenode *KFaxImage::AppendImageNode(int type)
+{
+ pagenode *pn = new pagenode();
+ if (pn) {
+ pn->type = type;
+ pn->expander = g31expand;
+ pn->strips = NULL;
+ pn->size = QSize(1728,2339);
+ pn->vres = -1;
+ pn->dpi = KFAX_DPI_FINE;
+ m_pagenodes.append(pn);
+ }
+ return pn;
+}
+
+bool KFaxImage::NewImage(pagenode *pn, int w, int h)
+{
+ pn->image = QImage( w, h, 1, 2, QImage::systemByteOrder() );
+ pn->image.setColor(0, qRgb(255,255,255));
+ pn->image.setColor(1, qRgb(0,0,0));
+ pn->data = (Q_UINT16*) pn->image.bits();
+ pn->bytes_per_line = pn->image.bytesPerLine();
+ pn->dpi = KFAX_DPI_FINE;
+
+ return !pn->image.isNull();
+}
+
+void KFaxImage::FreeImage(pagenode *pn)
+{
+ pn->image = QImage();
+ pn->data = NULL;
+ pn->bytes_per_line = 0;
+}
+
+void KFaxImage::kfaxerror(const QString& error)
+{
+ m_errorString = error;
+ kdError() << "kfaxerror: " << error << endl;
+}
+
+
+/* Enter an argument in the linked list of pages */
+pagenode *
+KFaxImage::notefile(int type)
+{
+ pagenode *newnode = new pagenode();
+ newnode->type = type;
+ newnode->size = QSize(1728,0);
+ return newnode;
+}
+
+static t32bits
+get4(unsigned char *p, QImage::Endian endian)
+{
+ return (endian == QImage::BigEndian)
+ ? (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3] :
+ p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
+}
+
+static int
+get2(unsigned char *p, QImage::Endian endian)
+{
+ return (endian == QImage::BigEndian) ? (p[0]<<8)|p[1] : p[0]|(p[1]<<8);
+}
+
+/* generate pagenodes for the images in a tiff file */
+int
+KFaxImage::notetiff()
+{
+#define SC(x) (char *)(x)
+ unsigned char header[8];
+ QImage::Endian endian;
+ t32bits IFDoff;
+ pagenode *pn = NULL;
+ QString str;
+
+ QFile file(filename());
+ if (!file.open(IO_ReadOnly)) {
+ kfaxerror(i18n("Unable to open file for reading."));
+ return 0;
+ }
+
+ if (file.readBlock(SC(header), 8) != 8) {
+ kfaxerror(i18n("Unable to read file header (file too short)."));
+ return 0;
+ }
+ if (memcmp(header, &littleTIFF, 4) == 0)
+ endian = QImage::LittleEndian;
+ else if (memcmp(header, &bigTIFF, 4) == 0)
+ endian = QImage::BigEndian;
+ else {
+ maybe_RAW_FAX:
+ kfaxerror(i18n("This is not a TIFF FAX file."));
+ // AppendImageNode(FAX_RAW);
+ return 0;
+ }
+ IFDoff = get4(header+4, endian);
+ if (IFDoff & 1) {
+ goto maybe_RAW_FAX;
+ }
+ do { /* for each page */
+ unsigned char buf[8];
+ unsigned char *dir = NULL , *dp = NULL;
+ int ndirent;
+ pixnum iwidth = 1728;
+ pixnum iheight = 2339;
+ int inverse = false;
+ int lsbfirst = 0;
+ int t4opt = 0, comp = 0;
+ int orient = TURN_NONE;
+ int yres = 196; /* 98.0 */
+ struct strip *strips = NULL;
+ unsigned int rowsperstrip = 0;
+ t32bits nstrips = 1;
+
+ if (!file.at(IFDoff)) {
+ realbad:
+ kfaxerror( i18n("Invalid or incomplete TIFF file.") );
+ bad:
+ if (strips)
+ free(strips);
+ if (dir)
+ free(dir);
+ file.close();
+ return 1;
+ }
+ if (file.readBlock(SC(buf), 2) != 2)
+ goto realbad;
+ ndirent = get2(buf, endian);
+ int len = 12*ndirent+4;
+ dir = (unsigned char *) malloc(len);
+ if (file.readBlock(SC(dir), len) != len)
+ goto realbad;
+ for (dp = dir; ndirent; ndirent--, dp += 12) {
+ /* for each directory entry */
+ int tag, ftype;
+ t32bits count, value = 0;
+ tag = get2(dp, endian);
+ ftype = get2(dp+2, endian);
+ count = get4(dp+4, endian);
+ switch(ftype) { /* value is offset to list if count*size > 4 */
+ case 3: /* short */
+ value = get2(dp+8, endian);
+ break;
+ case 4: /* long */
+ value = get4(dp+8, endian);
+ break;
+ case 5: /* offset to rational */
+ value = get4(dp+8, endian);
+ break;
+ }
+ switch(tag) {
+ case 256: /* ImageWidth */
+ iwidth = value;
+ break;
+ case 257: /* ImageLength */
+ iheight = value;
+ break;
+ case 259: /* Compression */
+ comp = value;
+ break;
+ case 262: /* PhotometricInterpretation */
+ inverse ^= (value == 1);
+ break;
+ case 266: /* FillOrder */
+ lsbfirst = (value == 2);
+ break;
+ case 273: /* StripOffsets */
+ nstrips = count;
+ strips = (struct strip *) malloc(count * sizeof *strips);
+ if (count == 1 || (count == 2 && ftype == 3)) {
+ strips[0].offset = value;
+ if (count == 2)
+ strips[1].offset = get2(dp+10, endian);
+ break;
+ }
+ if (!file.at(value))
+ goto realbad;
+ for (count = 0; count < nstrips; count++) {
+ if (file.readBlock(SC(buf), (ftype == 3) ? 2 : 4) <= 0)
+ goto realbad;
+ strips[count].offset = (ftype == 3) ?
+ get2(buf, endian) : get4(buf, endian);
+ }
+ break;
+ case 274: /* Orientation */
+ switch(value) {
+ default: /* row0 at top, col0 at left */
+ orient = 0;
+ break;
+ case 2: /* row0 at top, col0 at right */
+ orient = TURN_M;
+ break;
+ case 3: /* row0 at bottom, col0 at right */
+ orient = TURN_U;
+ break;
+ case 4: /* row0 at bottom, col0 at left */
+ orient = TURN_U|TURN_M;
+ break;
+ case 5: /* row0 at left, col0 at top */
+ orient = TURN_M|TURN_L;
+ break;
+ case 6: /* row0 at right, col0 at top */
+ orient = TURN_U|TURN_L;
+ break;
+ case 7: /* row0 at right, col0 at bottom */
+ orient = TURN_U|TURN_M|TURN_L;
+ break;
+ case 8: /* row0 at left, col0 at bottom */
+ orient = TURN_L;
+ break;
+ }
+ break;
+ case 278: /* RowsPerStrip */
+ rowsperstrip = value;
+ break;
+ case 279: /* StripByteCounts */
+ if (count != nstrips) {
+ str = i18n("In file %1\nStripsPerImage tag 273=%2,tag279=%3\n")
+ .arg(filename()).arg(nstrips).arg(count);
+ kfaxerror(str);
+ goto realbad;
+ }
+ if (count == 1 || (count == 2 && ftype == 3)) {
+ strips[0].size = value;
+ if (count == 2)
+ strips[1].size = get2(dp+10, endian);
+ break;
+ }
+ if (!file.at(value))
+ goto realbad;
+ for (count = 0; count < nstrips; count++) {
+ if (file.readBlock(SC(buf), (ftype == 3) ? 2 : 4) <= 0)
+ goto realbad;
+ strips[count].size = (ftype == 3) ?
+ get2(buf, endian) : get4(buf, endian);
+ }
+ break;
+ case 283: /* YResolution */
+ if (!file.at(value) ||
+ file.readBlock(SC(buf), 8) != 8)
+ goto realbad;
+ yres = get4(buf, endian) / get4(buf+4, endian);
+ break;
+ case 292: /* T4Options */
+ t4opt = value;
+ break;
+ case 293: /* T6Options */
+ /* later */
+ break;
+ case 296: /* ResolutionUnit */
+ if (value == 3)
+ yres = (yres * 254) / 100; /* *2.54 */
+ break;
+ }
+ }
+ IFDoff = get4(dp, endian);
+ free(dir);
+ dir = NULL;
+ if (comp == 5) {
+ // compression type 5 is LZW compression // XXX
+ kfaxerror(i18n("Due to patent reasons LZW (Lempel-Ziv & Welch) "
+ "compressed Fax files cannot be loaded yet.\n"));
+ goto bad;
+ }
+ if (comp < 2 || comp > 4) {
+ kfaxerror(i18n("This version can only handle Fax files\n"));
+ goto bad;
+ }
+ pn = AppendImageNode(FAX_TIFF);
+ pn->nstrips = nstrips;
+ pn->rowsperstrip = nstrips > 1 ? rowsperstrip : iheight;
+ pn->strips = strips;
+ pn->size = QSize(iwidth,iheight);
+ pn->inverse = inverse;
+ pn->lsbfirst = lsbfirst;
+ pn->orient = orient;
+ pn->dpi.setY(yres);
+ pn->vres = (yres > 150) ? 1:0; /* arbitrary threshold for fine resolution */
+ if (comp == 2)
+ pn->expander = MHexpand;
+ else if (comp == 3)
+ pn->expander = (t4opt & 1) ? g32expand : g31expand;
+ else
+ pn->expander = g4expand;
+ } while (IFDoff);
+ file.close();
+ return 1;
+#undef UC
+}
+
+/* report error and remove bad file from the list */
+void
+KFaxImage::badfile(pagenode *pn)
+{
+ kfaxerror(i18n("%1: Bad Fax File").arg(filename()));
+ FreeImage(pn);
+}
+
+/* rearrange input bits into t16bits lsb-first chunks */
+static void
+normalize(pagenode *pn, int revbits, int swapbytes, size_t length)
+{
+ t32bits *p = (t32bits *) pn->data;
+
+ kdDebug() << "normalize = " << ((revbits<<1)|swapbytes) << endl;
+ switch ((revbits<<1)|swapbytes) {
+ case 0:
+ break;
+ case 1:
+ for ( ; length; length -= 4) {
+ t32bits t = *p;
+ *p++ = ((t & 0xff00ff00) >> 8) | ((t & 0x00ff00ff) << 8);
+ }
+ break;
+ case 2:
+ for ( ; length; length -= 4) {
+ t32bits t = *p;
+ t = ((t & 0xf0f0f0f0) >> 4) | ((t & 0x0f0f0f0f) << 4);
+ t = ((t & 0xcccccccc) >> 2) | ((t & 0x33333333) << 2);
+ *p++ = ((t & 0xaaaaaaaa) >> 1) | ((t & 0x55555555) << 1);
+ }
+ break;
+ case 3:
+ for ( ; length; length -= 4) {
+ t32bits t = *p;
+ t = ((t & 0xff00ff00) >> 8) | ((t & 0x00ff00ff) << 8);
+ t = ((t & 0xf0f0f0f0) >> 4) | ((t & 0x0f0f0f0f) << 4);
+ t = ((t & 0xcccccccc) >> 2) | ((t & 0x33333333) << 2);
+ *p++ = ((t & 0xaaaaaaaa) >> 1) | ((t & 0x55555555) << 1);
+ }
+ }
+}
+
+
+/* get compressed data into memory */
+unsigned char *
+KFaxImage::getstrip(pagenode *pn, int strip)
+{
+ size_t offset, roundup;
+ unsigned char *Data;
+
+ union { t16bits s; unsigned char b[2]; } so;
+#define ShortOrder so.b[1]
+ so.s = 1; /* XXX */
+
+ QFile file(filename());
+ if (!file.open(IO_ReadOnly)) {
+ badfile(pn);
+ return NULL;
+ }
+
+ if (pn->strips == NULL) {
+ offset = 0;
+ pn->length = file.size();
+ }
+ else if (strip < pn->nstrips) {
+ offset = pn->strips[strip].offset;
+ pn->length = pn->strips[strip].size;
+ }
+ else {
+ kfaxerror( i18n("Trying to expand too many strips.") );
+ return NULL;
+ }
+
+ /* round size to full boundary plus t32bits */
+ roundup = (pn->length + 7) & ~3;
+
+ Data = (unsigned char *) malloc(roundup);
+ /* clear the last 2 t32bits, to force the expander to terminate
+ even if the file ends in the middle of a fax line */
+ *((t32bits *) Data + roundup/4 - 2) = 0;
+ *((t32bits *) Data + roundup/4 - 1) = 0;
+
+ /* we expect to get it in one gulp... */
+ if (!file.at(offset) ||
+ (size_t) file.readBlock((char *)Data, pn->length) != pn->length) {
+ badfile(pn);
+ free(Data);
+ return NULL;
+ }
+ file.close();
+
+ pn->data = (t16bits *) Data;
+ if (pn->strips == NULL && memcmp(Data, FAXMAGIC, sizeof(FAXMAGIC)-1) == 0) {
+ /* handle ghostscript / PC Research fax file */
+ if (Data[24] != 1 || Data[25] != 0){
+ kfaxerror( i18n("Only the first page of the PC Research multipage file will be shown.") );
+ }
+ pn->length -= 64;
+ pn->vres = Data[29];
+ pn->data += 32;
+ roundup -= 64;
+ }
+
+ normalize(pn, !pn->lsbfirst, ShortOrder, roundup);
+ if (pn->size.height() == 0)
+ pn->size.setHeight( G3count(pn, pn->expander == g32expand) );
+ if (pn->size.height() == 0) {
+
+ kfaxerror( i18n("No fax found in file.") );
+ badfile(pn);
+ free(Data);
+ return NULL;
+ }
+ if (pn->strips == NULL)
+ pn->rowsperstrip = pn->size.height();
+ return Data;
+}
+
+
+static void
+drawline(pixnum *run, int LineNum, pagenode *pn)
+{
+ t32bits *p, *p1; /* p - current line, p1 - low-res duplicate */
+ pixnum *r; /* pointer to run-lengths */
+ t32bits pix; /* current pixel value */
+ t32bits acc; /* pixel accumulator */
+ int nacc; /* number of valid bits in acc */
+ int tot; /* total pixels in line */
+ int n;
+
+ LineNum += pn->stripnum * pn->rowsperstrip;
+ if (LineNum >= pn->size.height()) {
+ if (LineNum == pn->size.height())
+ kdError() << "Height exceeded\n";
+ return;
+ }
+
+ p = (t32bits *) pn->image.scanLine(LineNum*(2-pn->vres));
+ p1 =(t32bits *)( pn->vres ? 0 : pn->image.scanLine(1+LineNum*(2-pn->vres)));
+ r = run;
+ acc = 0;
+ nacc = 0;
+ pix = pn->inverse ? ~0 : 0;
+ tot = 0;
+ while (tot < pn->size.width()) {
+ n = *r++;
+ tot += n;
+ /* Watch out for buffer overruns, e.g. when n == 65535. */
+ if (tot > pn->size.width())
+ break;
+ if (pix)
+ acc |= (~(t32bits)0 >> nacc);
+ else if (nacc)
+ acc &= (~(t32bits)0 << (32 - nacc));
+ else
+ acc = 0;
+ if (nacc + n < 32) {
+ nacc += n;
+ pix = ~pix;
+ continue;
+ }
+ *p++ = acc;
+ if (p1)
+ *p1++ = acc;
+ n -= 32 - nacc;
+ while (n >= 32) {
+ n -= 32;
+ *p++ = pix;
+ if (p1)
+ *p1++ = pix;
+ }
+ acc = pix;
+ nacc = n;
+ pix = ~pix;
+ }
+ if (nacc) {
+ *p++ = acc;
+ if (p1)
+ *p1++ = acc;
+ }
+}
+
+int
+KFaxImage::GetPartImage(pagenode *pn, int n)
+{
+ unsigned char *Data = getstrip(pn, n);
+ if (Data == 0)
+ return 3;
+ pn->stripnum = n;
+ (*pn->expander)(pn, drawline);
+ free(Data);
+ return 1;
+}
+
+int
+KFaxImage::GetImage(pagenode *pn)
+{
+ if (!pn->image.isNull())
+ return 1;
+
+ int i;
+ if (pn->strips == 0) {
+
+ kdDebug() << "Loading RAW fax file " << m_filename << " size=" << pn->size << endl;
+
+ /* raw file; maybe we don't have the height yet */
+ unsigned char *Data = getstrip(pn, 0);
+ if (Data == 0){
+ return 0;
+ }
+ if (!NewImage(pn, pn->size.width(), (pn->vres ? 1:2) * pn->size.height()))
+ return 0;
+
+ (*pn->expander)(pn, drawline);
+ }
+ else {
+ /* multi-strip tiff */
+ kdDebug() << "Loading MULTI STRIP TIFF fax file " << m_filename << endl;
+
+ if (!NewImage(pn, pn->size.width(), (pn->vres ? 1:2) * pn->size.height()))
+ return 0;
+ pn->stripnum = 0;
+ kdDebug() << "has " << pn->nstrips << " strips.\n";
+ for (i = 0; i < pn->nstrips; i++){
+
+ int k = GetPartImage(pn, i);
+ if ( k == 3 ){
+ FreeImage(pn);
+ kfaxerror( i18n("Fax G3 format not yet supported.") );
+ return k;
+ }
+
+ }
+ }
+
+ // byte-swapping the image on little endian machines
+#if defined(Q_BYTE_ORDER) && (Q_BYTE_ORDER == Q_LITTLE_ENDIAN)
+ for (int y=pn->image.height()-1; y>=0; --y) {
+ Q_UINT32 *source = (Q_UINT32 *) pn->image.scanLine(y);
+ Q_UINT32 *dest = source;
+ for (int x=(pn->bytes_per_line/4)-1; x>=0; --x) {
+ Q_UINT32 dv = 0, sv = *source;
+ for (int bit=32; bit>0; --bit) {
+ dv <<= 1;
+ dv |= sv&1;
+ sv >>= 1;
+ }
+ *dest = dv;
+ ++dest;
+ ++source;
+ }
+ }
+#endif
+
+ kdDebug() << filename()
+ << "\n\tsize = " << pn->size
+ << "\n\tDPI = " << pn->dpi
+ << "\n\tresolution = " << (pn->vres ? "fine" : "normal")
+ << endl;
+
+ return 1;
+}
+
+
+#include "kfaximage.moc"
diff --git a/kfaxview/libkfaximage/kfaximage.h b/kfaxview/libkfaximage/kfaximage.h
new file mode 100644
index 00000000..0ed2db90
--- /dev/null
+++ b/kfaxview/libkfaximage/kfaximage.h
@@ -0,0 +1,162 @@
+/*
+ This file is part of KDE FAX image loading library
+ Copyright (c) 2005 Helge Deller <deller@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _LIBKFAXIMAGE_H_
+#define _LIBKFAXIMAGE_H_
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qimage.h>
+#include <qptrlist.h>
+#include <kdelibs_export.h>
+
+class pagenode;
+
+
+/**
+ * This is KFaxImage, a class for loading FAX files under KDE
+ *
+ * @short KFaxImage
+ * @author Helge Deller
+ * @version 0.1
+ *
+ *
+ * Standard fax dpi values:
+ * ------------------------
+ * Standard: 203 dpi x 98 lpi
+ * Fine: 203 dpi x 196 lpi
+ * Super Fine: 203 dpi y 392 lpi, or
+ * 406 dpi x 392 lpi
+ */
+
+#define KFAX_DPI_STANDARD QPoint(203,98)
+#define KFAX_DPI_FINE QPoint(203,196)
+#define KFAX_DPI_SUPERFINE QPoint(406,392)
+
+
+class KDE_EXPORT KFaxImage : public QObject
+{
+ Q_OBJECT
+
+public:
+
+ /**
+ * KFaxImage - the KDE FAX loader class
+ * constructor.
+ * @param filename: an optional FAX file which should be loaded.
+ * @see: numPages
+ */
+
+ KFaxImage( const QString &filename = QString::null, QObject *parent = 0, const char *name = 0 );
+
+ /**
+ * Destructor
+ *
+ * releases internal allocated memory.
+ */
+
+ virtual ~KFaxImage();
+
+ /**
+ * loads the FAX image and returns true when sucessful.
+ * @param filename: the file which should be loaded.
+ * @return boolean value on success or failure
+ * @see: numPages
+ * @see: errorString
+ */
+
+ bool loadImage( const QString &filename );
+
+ /**
+ * returns currently loaded image file name.
+ * @return FAX filename
+ */
+
+ QString filename() { return m_filename; };
+
+ /**
+ * returns number of pages which are stored in the FAX file
+ * @return page count
+ */
+
+ unsigned int numPages() const { return m_pagenodes.count(); };
+
+ /**
+ * returns a QImage which holds the contents of page pageNr
+ * @param pageNr: page number (starting with 0)
+ * @return QImage of the page pageNr
+ */
+
+ QImage page( unsigned int pageNr );
+
+ /**
+ * returns the DPI (dots per inch) of page pageNr
+ * @param pageNr: page number (starting with 0)
+ * @return a QPoint value with the DPIs in X- and Y-direction
+ */
+
+ QPoint page_dpi( unsigned int pageNr );
+
+ /**
+ * returns the physical pixels of page pageNr
+ * @param pageNr: page number (starting with 0)
+ * @return a QSize value with the width and height of the image
+ */
+
+ QSize page_size( unsigned int pageNr );
+
+ /**
+ * @return a user-visible, translated error string
+ */
+
+ const QString errorString() const { return m_errorString; };
+
+
+
+ private:
+
+ /**
+ * private member variables
+ */
+
+ QString m_filename;
+ QString m_errorString;
+
+ typedef QPtrList<pagenode> t_PageNodeList;
+ t_PageNodeList m_pagenodes;
+
+ /**
+ * private member functions
+ */
+
+ void reset();
+ void kfaxerror(const QString& error);
+ pagenode *AppendImageNode(int type);
+ bool NewImage(pagenode *pn, int w, int h);
+ void FreeImage(pagenode *pn);
+ unsigned char *getstrip(pagenode *pn, int strip);
+ int GetPartImage(pagenode *pn, int n);
+ int GetImage(pagenode *pn);
+ pagenode *notefile(int type);
+ int notetiff();
+ void badfile(pagenode *pn);
+};
+
+#endif /* _LIBKFAXIMAGE_H_ */
+
diff --git a/kfaxview/main.cpp b/kfaxview/main.cpp
new file mode 100644
index 00000000..8e967a96
--- /dev/null
+++ b/kfaxview/main.cpp
@@ -0,0 +1,174 @@
+#include <config.h>
+
+#include <dcopclient.h>
+#include <dcopref.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kdebug.h>
+#include <kurl.h>
+#include <klocale.h>
+#include <kaboutdata.h>
+#include <qdir.h>
+
+#include <stdlib.h>
+
+#include "kviewshell.h"
+
+
+static KCmdLineOptions options[] =
+{
+ { "unique", I18N_NOOP("Check if the file is loaded in another KFaxView instance.\nIf it is, bring up the other KFaxView. Otherwise, load the file."), 0 },
+ { "g", 0, 0 },
+ { "goto <pagenumber>", I18N_NOOP("Navigate to this page"), 0 },
+ // The rest of the options are only for compability with the old KFax
+ { "f", 0, 0 },
+ { "fine", I18N_NOOP("(obsolete)"), 0 },
+ { "n", 0, 0 },
+ { "normal", I18N_NOOP("(obsolete)"), 0 },
+ { "height", I18N_NOOP("(obsolete)"), 0 },
+ { "w", 0, 0 },
+ { "width", I18N_NOOP("(obsolete)"), 0 },
+ { "l", 0, 0 },
+ { "landscape", I18N_NOOP("(obsolete)"), 0 },
+ { "u", 0, 0 },
+ { "upsidedown", I18N_NOOP("(obsolete)"), 0 },
+ { "i", 0, 0 },
+ { "invert", I18N_NOOP("(obsolete)"), 0 },
+ { "m", 0, 0 },
+ { "mem <bytes>", I18N_NOOP("(obsolete)"), 0 },
+ { "r", 0, 0 },
+ { "reverse", I18N_NOOP("(obsolete)"), 0 },
+ { "2" , I18N_NOOP("(obsolete)"), 0 },
+ { "4", I18N_NOOP("(obsolete)"), 0 },
+ { "+file(s)", I18N_NOOP("Files to load"), 0 },
+ KCmdLineLastOption
+};
+
+
+static const char description[] = I18N_NOOP("A previewer for Fax files.");
+
+
+int main(int argc, char** argv)
+{
+ KAboutData about ("kfaxview", I18N_NOOP("KFaxView"), "3.5",
+ description, KAboutData::License_GPL,
+ "Stephan Kebekus, Helge Deller",
+ I18N_NOOP("Fax-G3 plugin for the KViewShell document viewer framework."));
+
+ about.addAuthor ("Stefan Kebekus",
+ I18N_NOOP("KViewShell plugin"),
+ "kebekus@kde.org",
+ "http://www.mi.uni-koeln.de/~kebekus");
+
+ about.addAuthor ("Wilfried Huss",
+ I18N_NOOP("KViewShell maintainer"),
+ "Wilfried.Huss@gmx.at");
+
+ about.addAuthor ("Helge Deller",
+ I18N_NOOP("Fax file loading"),
+ "deller@gmx.de");
+
+ KCmdLineArgs::init(argc, argv, &about);
+ KCmdLineArgs::addCmdLineOptions(options);
+ KApplication app;
+
+ // see if we are starting with session management
+ if (app.isRestored())
+ {
+ RESTORE(KViewShell);
+ }
+ else
+ {
+ KCmdLineArgs* args = KCmdLineArgs::parsedArgs();
+
+ if (args->isSet("unique"))
+ {
+ // With --unique, we need 2 arguments.
+ if (args->count() < 1)
+ {
+ args->usage();
+ exit(-1);
+ }
+
+ // Find the fully qualified file name of the file we are
+ // loading. Complain, if we are given a URL which does not point
+ // to a local file.
+ KURL url(args->url(0));
+
+ if (!url.isValid())
+ {
+ kdError(4300) << QString(I18N_NOOP("The URL %1 is not well-formed.")).arg(args->arg(0)) << endl;
+ return -1;
+ }
+
+ if (!url.isLocalFile())
+ {
+ kdError(4300) << QString(I18N_NOOP("The URL %1 does not point to a local file. You can only specify local "
+ "files if you are using the '--unique' option.")).arg(args->arg(0)) << endl;
+ return -1;
+ }
+
+ QString qualPath = QFileInfo(url.path()).absFilePath();
+
+ app.dcopClient()->attach();
+ // We need to register as "kviewshell" to stay compatible with existing DCOP-skripts.
+ QCString id = app.dcopClient()->registerAs("unique-kviewshell");
+ if (id.isNull())
+ kdError(4300) << "There was an error using dcopClient()->registerAs()." << endl;
+ QCStringList apps = app.dcopClient()->registeredApplications();
+ for ( QCStringList::Iterator it = apps.begin(); it != apps.end(); ++it )
+ {
+ if ((*it).find("kviewshell") == 0)
+ {
+ QByteArray data, replyData;
+ QCString replyType;
+ QDataStream arg(data, IO_WriteOnly);
+ bool result;
+ arg << qualPath.stripWhiteSpace();
+ if (!app.dcopClient()->call( *it, "kmultipage", "is_file_loaded(QString)", data, replyType, replyData))
+ kdError(4300) << "There was an error using DCOP." << endl;
+ else
+ {
+ QDataStream reply(replyData, IO_ReadOnly);
+ if (replyType == "bool")
+ {
+ reply >> result;
+ if (result == true)
+ {
+ if (app.dcopClient()->send( *it, "kmultipage", "jumpToReference(QString)", url.ref()) == true)
+ {
+ app.dcopClient()->detach();
+ return 0;
+ }
+ }
+ }
+ else
+ kdError(4300) << "The DCOP function 'doIt' returned an unexpected type of reply!";
+ }
+ }
+ }
+ }
+
+ // We need to register as "kviewshell" to stay compatible with existing DCOP-skripts.
+ app.dcopClient()->registerAs("kviewshell");
+ KViewShell* shell = new KViewShell("image/fax-g3");
+ shell->show();
+ app.processEvents();
+
+ if (args->count() > 0)
+ {
+ KURL url = args->url(0);
+ if (!url.hasRef() && args->isSet("goto"))
+ {
+ // If the url doesn't already has a reference part, add the
+ // argument of --goto to the url as reference, to make the
+ // KViewShell jump to this page.
+ QString reference = args->getOption("goto");
+ url.setHTMLRef(reference);
+ }
+ shell->openURL(url);
+ }
+ }
+
+ return app.exec();
+}
diff --git a/kfile-plugins/Makefile.am b/kfile-plugins/Makefile.am
new file mode 100644
index 00000000..92a6e911
--- /dev/null
+++ b/kfile-plugins/Makefile.am
@@ -0,0 +1,14 @@
+if include_EXR_MODULES
+KFILE_EXR_SUBDIR=exr
+endif
+
+if include_TIFF
+KFILE_TIFF_SUBDIR=tiff
+endif
+
+if include_PDF
+KFILE_PDF_SUBDIR=pdf
+endif
+
+SUBDIRS=dvi png ps jpeg xbm xpm bmp tga rgb ico pcx $(KFILE_TIFF_SUBDIR) pnm \
+ $(KFILE_EXR_SUBDIR) $(KFILE_PDF_SUBDIR) dds gif raw
diff --git a/kfile-plugins/RETURNED_ITEMS b/kfile-plugins/RETURNED_ITEMS
new file mode 100644
index 00000000..593d466a
--- /dev/null
+++ b/kfile-plugins/RETURNED_ITEMS
@@ -0,0 +1,245 @@
+If you make a new plugin, please add the list of returned items to this list.
+
+
+pdf plugin:
+===========
+
+Date Created
+Date Modiified
+Int Pages
+Bool Encrypted
+and everything else pdfinfo returns as string
+
+
+png plugin:
+===========
+
+type key W/A details
+------------------------------------------------------------------------
+Size Dimensions -/-
+Int BitDepth -/-
+String ColorMode -/-
+String Compression -/- Compression type. Right now always "deflate"
+
+Other keys corresponding to the png comment keys are returned as non-editable
+String.
+
+Common keys that are recommended in the png spec:
+Title, Author, Description, Copyright, Creation Time, Software, Disclaimer,
+Warning, Source, Comment
+
+
+PostScript plugin:
+==================
+
+String Title
+String Creator
+String CreationDate
+String For
+Int Pages
+
+
+
+Jpeg plugin:
+============
+Note: number.number means precision of converted number
+
+type key Comment
+-----------------------------------------------------------------------------
+String Camera make
+String Camera model
+String Date/time
+Size Dimensions Width x Height in pixels
+int Orientation 1 - "The 0th row is at the visual top of the image,
+ and the 0th column is the visual left-hand side."
+ 2 - "The 0th row is at the visual top of the image,
+ and the 0th column is the visual right-hand side."
+ 3 - "The 0th row is at the visual bottom of the image,
+ and the 0th column is the visual right-hand side."
+ 4 - "The 0th row is at the visual bottom of the image,
+ and the 0th column is the visual left-hand side."
+ 5 - "The 0th row is the visual left-hand side of of the image,
+ and the 0th column is the visual top."
+ 6 - "The 0th row is the visual right-hand side of of the image,
+ and the 0th column is the visual top."
+ 7 - "The 0th row is the visual right-hand side of of the image,
+ and the 0th column is the visual bottom."
+ 8 - "The 0th row is the visual left-hand side of of the image,
+ and the 0th column is the visual bottom."
+String ColorMode "Grayscale" "Color"
+String Flash used "Yes" "No"
+String Focal length 4.1 mm, 35mm equivalent
+String Exposure time 6.3 (if < 0.5 also in 1/xx) sec
+String Aperture "f/3.1"
+String Focus dist. "Infinite" or 5.2 m
+String CCD width 4.2 Postfix mm
+String Exposure bias 4.2
+String Whitebalance 0 = unknown
+ 1 = Daylight
+ 2 = Fluorescent
+ 3 = Tungsten
+ 17 = Standard light A
+ 18 = Standard light B
+ 19 = Standard light C
+ 20 = D55
+ 21 = D65
+ 22 = D75
+ 23 to 254 = reserved
+ 255 = other
+String Metering mode 0 = unknown
+ 1 = Average
+ 2 = CenterWeightedAverage
+ 3 = Spot
+ 4 = MultiSpot
+ 5 = Pattern
+ 6 = Partial
+ 7 to 254 = reserved
+ 255 = other
+String Exposure 0 = Not defined
+ 1 = Manual
+ 2 = Normal program
+ 3 = Aperture priority
+ 4 = Shutter priority
+ 5 = Creative program (biased toward depth of field)
+ 6 = Action program
+ (biased toward fast shutter speed)
+ 7 = Portrait mode
+ (for closeup photos with the background out of focus)
+ 8 = Landscape mode
+ (for landscape photos with the background in focus)
+ 9 to 255 = reserved
+String ISO equiv. 2digits ???
+String JPG quality 1 - "basic"
+ 2 - "normal"
+ 4 - "fine"
+ default: unknown
+String User comment
+String Comment
+QImage Thumbnail
+
+
+gif plugin:
+===========
+
+type key Comment
+-----------------------------------------------------------------------------
+Size Dimensions Width x Height in pixels.
+String Comment gif comment blocks, which we permit to be utf-8 encoded
+ in clear violation/extension of the specification which
+ calls for 7 bit ASCII. See:
+ http://www.geocities.co.jp/SiliconValley/3453/gif_info/index_en.html
+
+
+TIFF plugin:
+===========
+
+:: Group: General ::
+
+type key Comment
+------ -------------- -----------------------------------------------------
+String ColorMode Color Mode (Monochrome, RGB, RGBA etc)
+Size Dimensions Width & height as a QSize object
+Size Resolution x & y resolution in dpi as a QSize object
+Int BitDepth No. of bits per pixel (e.g. 24 for 8-bit RGB)
+String Compression Compression used (None, Deflate, LZW, JPEG etc.)
+Int FaxPages No. of pages if this is fax
+String Software Software used to produce this image
+String Description Image description
+String Copyright Copyright information
+String DateTime Date and time of image creation
+String Artist Name of the person who created this image
+
+:: Group: Scanner ::
+
+type key Comment
+------ -------------- -----------------------------------------------------
+String Make Make of the scanner used
+String Model Model of the scanner used
+
+
+
+
+
+xbm plugin:
+===========
+
+type key W/A details
+------------------------------------------------------------------------
+QSize Dimensions -/- Dimensions in pixels
+
+xpm plugin:
+===========
+
+type key W/A details
+------------------------------------------------------------------------
+QSize Dimensions -/- Dimensions in pixels
+Int BitDepth -/- Bits per pixel
+
+
+bmp plugin:
+===========
+
+type key W/A details
+------------------------------------------------------------------------
+String Type -/- Bitmap type (Windows / OS/2)
+QSize Dimensions -/- Dimensions in pixels
+Int BitDepth -/- Bits per pixel
+String Compression -/- Compression type
+
+
+tga plugin:
+===========
+
+type key W/A details
+------------------------------------------------------------------------
+QSize Dimensions -/- Dimensions in pixels
+Int BitDepth -/- Bits per pixel
+String ColorMode -/- Color mode (e.g. RGB)
+String Compression -/- Compression type, if any
+
+
+ico plugin:
+===========
+
+type key W/A details
+------------------------------------------------------------------------
+Int Number -/- Number of icons in file
+QSize Dimensions -/- Dimensions
+QSize DimensionsM -/- Dimensions [of 1st icon]
+Int Colors -/- Number of colors [in 1st icon]
+
+pcx plugin:
+===========
+
+type key W/A details
+------------------------------------------------------------------------
+QSize Dimensions -/- Dimensions in pixels
+Int BitDepth -/- Bits per pixel
+QSize Resolution -/- Resolution in DPI
+String Compression -/- Compression type, if any
+
+
+rgb plugin:
+===========
+
+type key details
+------------------------------------------------------------------------
+String ImageName Image name (or comment)
+QSize Dimensions Dimensions in pixels
+Int BitDepth Bits per pixel
+String ColorMode Color Mode (Monochrome, RGB, RGBA etc)
+String Compression Compression type
+String SharedRows Percentage of shared rows
+ (amount of "aggression" -> see GIMP)
+dds plugin:
+===========
+
+type key details
+------------------------------------------------------------------------
+QSize Dimensions Dimensions in pixels
+Int Depth Depth in pixels
+Int BitDepth Bits per pixel
+String ColorMode Color Mode (RGB, RGBA)
+String Type 2D, volume or cube map
+String Compression Compression type
+
diff --git a/kfile-plugins/bmp/Makefile.am b/kfile-plugins/bmp/Makefile.am
new file mode 100644
index 00000000..dbaa8ff2
--- /dev/null
+++ b/kfile-plugins/bmp/Makefile.am
@@ -0,0 +1,22 @@
+## Makefile.am for bmp file meta info plugin
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = kfile_bmp.h
+
+kde_module_LTLIBRARIES = kfile_bmp.la
+
+kfile_bmp_la_SOURCES = kfile_bmp.cpp
+kfile_bmp_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_bmp_la_LIBADD = $(LIB_KSYCOCA)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) kfile_bmp.cpp -o $(podir)/kfile_bmp.pot
+
+services_DATA = kfile_bmp.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kfile-plugins/bmp/kfile_bmp.cpp b/kfile-plugins/bmp/kfile_bmp.cpp
new file mode 100644
index 00000000..b9d6a7ad
--- /dev/null
+++ b/kfile-plugins/bmp/kfile_bmp.cpp
@@ -0,0 +1,174 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Shane Wright <me@shanewright.co.uk>
+ *
+ * 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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <config.h>
+#include "kfile_bmp.h"
+
+#include <kprocess.h>
+#include <klocale.h>
+#include <kgenericfactory.h>
+#include <kstringvalidator.h>
+#include <kdebug.h>
+
+#include <qdict.h>
+#include <qvalidator.h>
+#include <qcstring.h>
+#include <qfile.h>
+#include <qdatetime.h>
+
+#if !defined(__osf__)
+#include <inttypes.h>
+#else
+typedef unsigned long uint32_t;
+typedef unsigned short uint16_t;
+#endif
+
+typedef KGenericFactory<KBmpPlugin> BmpFactory;
+
+K_EXPORT_COMPONENT_FACTORY(kfile_bmp, BmpFactory( "kfile_bmp" ))
+
+KBmpPlugin::KBmpPlugin(QObject *parent, const char *name,
+ const QStringList &args)
+
+ : KFilePlugin(parent, name, args)
+{
+ KFileMimeTypeInfo* info = addMimeTypeInfo( "image/x-bmp" );
+
+ KFileMimeTypeInfo::GroupInfo* group = 0L;
+
+ group = addGroupInfo(info, "Technical", i18n("Technical Details"));
+
+ KFileMimeTypeInfo::ItemInfo* item;
+
+ item = addItemInfo(group, "Type", i18n("Type"), QVariant::String);
+
+ item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size);
+ setHint( item, KFileMimeTypeInfo::Size );
+ setUnit(item, KFileMimeTypeInfo::Pixels);
+
+ item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int);
+ setUnit(item, KFileMimeTypeInfo::BitsPerPixel);
+
+ item = addItemInfo(group, "Compression", i18n("Compression"), QVariant::String);
+
+}
+
+
+bool KBmpPlugin::readInfo( KFileMetaInfo& info, uint what)
+{
+ const char * bmptype_bm = "BM";
+ const char * bmptype_ba = "BA";
+ const char * bmptype_ci = "CI";
+ const char * bmptype_cp = "CP";
+ const char * bmptype_ic = "IC";
+ const char * bmptype_pt = "PT";
+
+ QFile file(info.path());
+
+ if (!file.open(IO_ReadOnly))
+ {
+ kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl;
+ return false;
+ }
+
+ QDataStream dstream(&file);
+
+ // BMP files are little-endian
+ dstream.setByteOrder(QDataStream::LittleEndian);
+
+ // create this now because we output image type early on
+ KFileMetaInfoGroup group = appendGroup(info, "Technical");
+
+
+ // read the beginning of the file and make sure it looks ok
+ unsigned char * bmp_id = (unsigned char *) malloc(2);
+ file.readBlock((char *) bmp_id, 2);
+
+ if (memcmp(bmp_id, bmptype_bm, 2) == 0) {
+ appendItem(group, "Type", i18n("Windows Bitmap"));
+ } else if (memcmp(bmp_id, bmptype_ba, 2) == 0) {
+ appendItem(group, "Type", i18n("OS/2 Bitmap Array"));
+ } else if (memcmp(bmp_id, bmptype_ci, 2) == 0) {
+ appendItem(group, "Type", i18n("OS/2 Color Icon"));
+ } else if (memcmp(bmp_id, bmptype_cp, 2) == 0) {
+ appendItem(group, "Type", i18n("OS/2 Color Pointer"));
+ } else if (memcmp(bmp_id, bmptype_ic, 2) == 0) {
+ appendItem(group, "Type", i18n("OS/2 Icon"));
+ } else if (memcmp(bmp_id, bmptype_pt, 2) == 0) {
+ appendItem(group, "Type", i18n("OS/2 Pointer"));
+ } else {
+ return false;
+ }
+
+ free(bmp_id);
+
+
+ // read the next bits, we ignore them, but anyways...
+ uint32_t bmp_size;
+ uint16_t bmp_reserved1;
+ uint16_t bmp_reserved2;
+ uint32_t bmp_offbits;
+
+ dstream >> bmp_size;
+ dstream >> bmp_reserved1;
+ dstream >> bmp_reserved2;
+ dstream >> bmp_offbits;
+
+
+ // we should now be at the file info structure
+ uint32_t bmpi_size;
+ uint32_t bmpi_width;
+ uint32_t bmpi_height;
+ uint16_t bmpi_planes;
+ uint16_t bmpi_bitcount;
+ uint32_t bmpi_compression;
+
+ dstream >> bmpi_size;
+ dstream >> bmpi_width;
+ dstream >> bmpi_height;
+ dstream >> bmpi_planes;
+ dstream >> bmpi_bitcount;
+ dstream >> bmpi_compression;
+
+
+ // output the useful bits
+ appendItem(group, "Dimensions", QSize(bmpi_width, bmpi_height));
+ appendItem(group, "BitDepth", bmpi_bitcount);
+
+ switch (bmpi_compression) {
+ case 0 :
+ appendItem(group, "Compression", i18n("None"));
+ break;
+ case 1 :
+ appendItem(group, "Compression", i18n("RLE 8bit/pixel"));
+ break;
+ case 2 :
+ appendItem(group, "Compression", i18n("RLE 4bit/pixel"));
+ break;
+ case 3 :
+ appendItem(group, "Compression", i18n("Bitfields"));
+ break;
+ default :
+ appendItem(group, "Compression", i18n("Unknown"));
+ }
+
+ return true;
+}
+
+#include "kfile_bmp.moc"
diff --git a/kfile-plugins/bmp/kfile_bmp.desktop b/kfile-plugins/bmp/kfile_bmp.desktop
new file mode 100644
index 00000000..37b44b42
--- /dev/null
+++ b/kfile-plugins/bmp/kfile_bmp.desktop
@@ -0,0 +1,66 @@
+[Desktop Entry]
+Type=Service
+Name=BMP Info
+Name[af]=Bmp Inligting
+Name[ar]=معلومات BMP
+Name[br]=Titouroù BMP
+Name[ca]=Informació de BMP
+Name[cs]=BMP info
+Name[cy]=Gwybodaeth BMP
+Name[da]=BMP-info
+Name[de]=BMP-Info
+Name[el]=Πληροφορίες BMP
+Name[eo]=BMP-informo
+Name[es]=Info BMP
+Name[et]=BMP info
+Name[fa]=اطلاعات BMP
+Name[fi]=BMP-tiedot
+Name[fr]=Informations BMP
+Name[ga]=Eolas faoi BMP
+Name[gl]=Inf. BMP
+Name[he]=מידע BMP
+Name[hi]=BMP जानकारी
+Name[hr]=BMP informacije
+Name[hu]=BMP-jellemzők
+Name[is]=BMP upplýsingar
+Name[it]=Informazioni BMP
+Name[ja]=BMP 情報
+Name[kk]=BMP мәліметі
+Name[km]=ព័ត៌មាន BMP
+Name[lt]=BMP informacija
+Name[ms]=Maklumat BMP
+Name[nds]=BMP-Info
+Name[ne]=BMP सूचना
+Name[nl]=BMP-info
+Name[nn]=BMP-info
+Name[nso]=Tshedimoso ya BMP
+Name[pa]=BMP ਜਾਣਕਾਰੀ
+Name[pl]=Informacja o pliku BMP
+Name[pt]=Informação do BMP
+Name[pt_BR]=Informação sobre BMP
+Name[ro]=Informaţii BMP
+Name[ru]=Информация о BMP
+Name[se]=BMP-dieđut
+Name[sl]=Podatki o BMP
+Name[sr]=BMP информације
+Name[sr@Latn]=BMP informacije
+Name[sv]=BMP-information
+Name[ta]=BMP தகவல்
+Name[tg]=Иттилоот оиди BMP
+Name[th]=ข้อมูลแฟ้ม BMP
+Name[tr]=BMP Bilgisi
+Name[uk]=Інформація по BMP
+Name[uz]=BMP haqida maʼlumot
+Name[uz@cyrillic]=BMP ҳақида маълумот
+Name[ven]=Mafhungo BMP
+Name[wa]=Informåcion sol imådje BMP
+Name[xh]=Ulwazi lwe BMP
+Name[zh_CN]=BMP 信息
+Name[zh_HK]=BMP 資訊
+Name[zh_TW]=BMP 資訊
+Name[zu]=Ulwazi lwe-BMP
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_bmp
+MimeType=image/x-bmp
+PreferredGroups=Technical
+PreferredItems=Type,Resolution,Bitdepth,Compression
diff --git a/kfile-plugins/bmp/kfile_bmp.h b/kfile-plugins/bmp/kfile_bmp.h
new file mode 100644
index 00000000..b72ee16d
--- /dev/null
+++ b/kfile-plugins/bmp/kfile_bmp.h
@@ -0,0 +1,37 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Shane Wright <me@shanewright.co.uk>
+ *
+ * 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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __KFILE_BMP_H__
+#define __KFILE_BMP_H__
+
+#include <kfilemetainfo.h>
+
+class QStringList;
+
+class KBmpPlugin: public KFilePlugin
+{
+ Q_OBJECT
+
+public:
+ KBmpPlugin( QObject *parent, const char *name, const QStringList& args );
+
+ virtual bool readInfo( KFileMetaInfo& info, uint what);
+};
+
+#endif
diff --git a/kfile-plugins/configure.in.bot b/kfile-plugins/configure.in.bot
new file mode 100644
index 00000000..47308e8b
--- /dev/null
+++ b/kfile-plugins/configure.in.bot
@@ -0,0 +1,32 @@
+if test -z "$LIBTIFF"; then
+ echo ""
+ echo "You're missing libtiff. The additional info plugin for TIFF images"
+ echo "files won't be compiled without libtiff."
+ echo "You can download it from http://www.libtiff.org"
+ echo ""
+ all_tests=bad
+fi
+
+if test -z "$POPPLER_LIBS"; then
+ echo ""
+ echo "You're missing poppler. The additional info plugin for PDF files"
+ echo "files won't be compiled without poppler >= 0.3.1."
+ echo "You can download poppler from http://poppler.freedesktop.org/"
+ echo ""
+fi
+
+if test "$EXRSTATUS" = "no"; then
+ echo ""
+ echo "No OpenEXR Libraries were found"
+ echo "Install the OpenEXR package (from http://www.openexr.org)"
+ echo "if you want EXR image format support"
+ echo ""
+fi
+
+if test "$EXRSTATUS" = "old"; then
+ echo ""
+ echo "OpenEXR libraries were found, but at least version 1.1.0 is required"
+ echo "Install a newer OpenEXR package (from http://www.openexr.org)"
+ echo "if you want EXR image format support"
+ echo ""
+fi
diff --git a/kfile-plugins/dds/Makefile.am b/kfile-plugins/dds/Makefile.am
new file mode 100644
index 00000000..c3e0382a
--- /dev/null
+++ b/kfile-plugins/dds/Makefile.am
@@ -0,0 +1,22 @@
+## Makefile.am for dds file meta info plugin
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = kfile_dds.h
+
+kde_module_LTLIBRARIES = kfile_dds.la
+
+kfile_dds_la_SOURCES = kfile_dds.cpp
+kfile_dds_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_dds_la_LIBADD = $(LIB_KSYCOCA)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) kfile_dds.cpp -o $(podir)/kfile_dds.pot
+
+services_DATA = kfile_dds.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kfile-plugins/dds/kfile_dds.cpp b/kfile-plugins/dds/kfile_dds.cpp
new file mode 100644
index 00000000..dd7f8f1e
--- /dev/null
+++ b/kfile-plugins/dds/kfile_dds.cpp
@@ -0,0 +1,317 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Ignacio Castao <castano@ludicon.com>
+ *
+ * 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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <config.h>
+#include "kfile_dds.h"
+
+#include <kprocess.h>
+#include <klocale.h>
+#include <kgenericfactory.h>
+#include <kstringvalidator.h>
+#include <kdebug.h>
+
+#include <qdict.h>
+#include <qvalidator.h>
+#include <qcstring.h>
+#include <qfile.h>
+#include <qdatetime.h>
+
+
+typedef KGenericFactory<KDdsPlugin> DdsFactory;
+
+typedef Q_UINT32 uint;
+typedef Q_UINT16 ushort;
+typedef Q_UINT8 uchar;
+
+namespace { // Private.
+
+#if !defined(MAKEFOURCC)
+# define MAKEFOURCC(ch0, ch1, ch2, ch3) \
+ (uint(uchar(ch0)) | (uint(uchar(ch1)) << 8) | \
+ (uint(uchar(ch2)) << 16) | (uint(uchar(ch3)) << 24 ))
+#endif
+
+ static const uint FOURCC_DDS = MAKEFOURCC('D', 'D', 'S', ' ');
+ static const uint FOURCC_DXT1 = MAKEFOURCC('D', 'X', 'T', '1');
+ static const uint FOURCC_DXT2 = MAKEFOURCC('D', 'X', 'T', '2');
+ static const uint FOURCC_DXT3 = MAKEFOURCC('D', 'X', 'T', '3');
+ static const uint FOURCC_DXT4 = MAKEFOURCC('D', 'X', 'T', '4');
+ static const uint FOURCC_DXT5 = MAKEFOURCC('D', 'X', 'T', '5');
+ static const uint FOURCC_RXGB = MAKEFOURCC('R', 'X', 'G', 'B');
+
+ static const uint DDSD_CAPS = 0x00000001l;
+ static const uint DDSD_PIXELFORMAT = 0x00001000l;
+ static const uint DDSD_WIDTH = 0x00000004l;
+ static const uint DDSD_HEIGHT = 0x00000002l;
+ static const uint DDSD_PITCH = 0x00000008l;
+
+ static const uint DDSCAPS_TEXTURE = 0x00001000l;
+ static const uint DDSCAPS2_VOLUME = 0x00200000l;
+ static const uint DDSCAPS2_CUBEMAP = 0x00000200l;
+
+ static const uint DDPF_RGB = 0x00000040l;
+ static const uint DDPF_FOURCC = 0x00000004l;
+ static const uint DDPF_ALPHAPIXELS = 0x00000001l;
+
+ enum DDSType {
+ DDS_A8R8G8B8 = 0,
+ DDS_A1R5G5B5 = 1,
+ DDS_A4R4G4B4 = 2,
+ DDS_R8G8B8 = 3,
+ DDS_R5G6B5 = 4,
+ DDS_DXT1 = 5,
+ DDS_DXT2 = 6,
+ DDS_DXT3 = 7,
+ DDS_DXT4 = 8,
+ DDS_DXT5 = 9,
+ DDS_RXGB = 10,
+ DDS_UNKNOWN
+ };
+
+
+ struct DDSPixelFormat {
+ uint size;
+ uint flags;
+ uint fourcc;
+ uint bitcount;
+ uint rmask;
+ uint gmask;
+ uint bmask;
+ uint amask;
+ };
+
+ QDataStream & operator>> ( QDataStream & s, DDSPixelFormat & pf )
+ {
+ s >> pf.size;
+ s >> pf.flags;
+ s >> pf.fourcc;
+ s >> pf.bitcount;
+ s >> pf.rmask;
+ s >> pf.gmask;
+ s >> pf.bmask;
+ s >> pf.amask;
+ return s;
+ }
+
+ struct DDSCaps {
+ uint caps1;
+ uint caps2;
+ uint caps3;
+ uint caps4;
+ };
+
+ QDataStream & operator>> ( QDataStream & s, DDSCaps & caps )
+ {
+ s >> caps.caps1;
+ s >> caps.caps2;
+ s >> caps.caps3;
+ s >> caps.caps4;
+ return s;
+ }
+
+ struct DDSHeader {
+ uint size;
+ uint flags;
+ uint height;
+ uint width;
+ uint pitch;
+ uint depth;
+ uint mipmapcount;
+ uint reserved[11];
+ DDSPixelFormat pf;
+ DDSCaps caps;
+ uint notused;
+ };
+
+ QDataStream & operator>> ( QDataStream & s, DDSHeader & header )
+ {
+ s >> header.size;
+ s >> header.flags;
+ s >> header.height;
+ s >> header.width;
+ s >> header.pitch;
+ s >> header.depth;
+ s >> header.mipmapcount;
+ for( int i = 0; i < 11; i++ ) {
+ s >> header.reserved[i];
+ }
+ s >> header.pf;
+ s >> header.caps;
+ s >> header.notused;
+ return s;
+ }
+
+ static bool IsValid( const DDSHeader & header )
+ {
+ if( header.size != 124 ) {
+ return false;
+ }
+ const uint required = (DDSD_WIDTH|DDSD_HEIGHT|DDSD_CAPS|DDSD_PIXELFORMAT);
+ if( (header.flags & required) != required ) {
+ return false;
+ }
+ if( header.pf.size != 32 ) {
+ return false;
+ }
+ if( !(header.caps.caps1 & DDSCAPS_TEXTURE) ) {
+ return false;
+ }
+ return true;
+ }
+
+} // namespace
+
+
+
+K_EXPORT_COMPONENT_FACTORY(kfile_dds, DdsFactory( "kfile_dds" ))
+
+// Constructor, init mime type info.
+KDdsPlugin::KDdsPlugin(QObject *parent, const char *name, const QStringList &args) :
+ KFilePlugin(parent, name, args)
+{
+ KFileMimeTypeInfo * info = addMimeTypeInfo( "image/x-dds" );
+
+ KFileMimeTypeInfo::GroupInfo * group = 0L;
+
+ group = addGroupInfo(info, "Technical", i18n("Technical Details"));
+
+ KFileMimeTypeInfo::ItemInfo * item;
+
+ item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size);
+ setHint(item, KFileMimeTypeInfo::Size);
+ setUnit(item, KFileMimeTypeInfo::Pixels);
+
+ item = addItemInfo(group, "Depth", i18n("Depth"), QVariant::Int);
+ setUnit(item, KFileMimeTypeInfo::Pixels);
+
+ item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int);
+ setUnit(item, KFileMimeTypeInfo::BitsPerPixel);
+
+ addItemInfo(group, "MipmapCount", i18n("Mipmap Count"), QVariant::Int);
+
+ addItemInfo(group, "Type", i18n("Type"), QVariant::String);
+ addItemInfo(group, "ColorMode", i18n("Color Mode"), QVariant::String);
+ addItemInfo(group, "Compression", i18n("Compression"), QVariant::String);
+}
+
+// Read mime type info.
+bool KDdsPlugin::readInfo( KFileMetaInfo& info, uint /*what*/)
+{
+ QFile file(info.path());
+
+ if (!file.open(IO_ReadOnly)) {
+ kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl;
+ return false;
+ }
+
+ QDataStream s(&file);
+ s.setByteOrder(QDataStream::LittleEndian);
+
+ // Validate header.
+ uint fourcc;
+ s >> fourcc;
+ if( fourcc != FOURCC_DDS ) {
+ kdDebug(7034) << QFile::encodeName(info.path()) << " is not a DDS file." << endl;
+ return false;
+ }
+
+ // Read image header.
+ DDSHeader header;
+ s >> header;
+
+ // Check image file format.
+ if( s.atEnd() || !IsValid( header ) ) {
+ kdDebug(7034) << QFile::encodeName(info.path()) << " is not a valid DDS file." << endl;
+ return false;
+ }
+
+ // Set file info.
+ KFileMetaInfoGroup group = appendGroup(info, "Technical");
+ appendItem(group, "Dimensions", QSize(header.width, header.height));
+ appendItem(group, "MipmapCount", header.mipmapcount);
+
+ // Set file type.
+ if( header.caps.caps2 & DDSCAPS2_CUBEMAP ) {
+ appendItem(group, "Type", i18n("Cube Map Texture"));
+ }
+ else if( header.caps.caps2 & DDSCAPS2_VOLUME ) {
+ appendItem(group, "Type", i18n("Volume Texture"));
+ appendItem(group, "Depth", header.depth);
+ }
+ else {
+ appendItem(group, "Type", i18n("2D Texture"));
+ }
+
+ // Set file color depth and compression.
+ if( header.pf.flags & DDPF_RGB ) {
+ appendItem(group, "BitDepth", header.pf.bitcount);
+ appendItem(group, "Compression", i18n("Uncompressed"));
+ if( header.pf.flags & DDPF_ALPHAPIXELS ) {
+ appendItem(group, "ColorMode", "RGB/Alpha");
+ }
+ else {
+ appendItem(group, "ColorMode", "RGB");
+ }
+ }
+ else if( header.pf.flags & DDPF_FOURCC ) {
+ switch( header.pf.fourcc ) {
+ case FOURCC_DXT1:
+ appendItem(group, "BitDepth", 4);
+ appendItem(group, "Compression", "DXT1");
+ appendItem(group, "ColorMode", "RGB");
+ break;
+ case FOURCC_DXT2:
+ appendItem(group, "BitDepth", 16);
+ appendItem(group, "Compression", "DXT2");
+ appendItem(group, "ColorMode", "RGB/Alpha");
+ break;
+ case FOURCC_DXT3:
+ appendItem(group, "BitDepth", 16);
+ appendItem(group, "Compression", "DXT3");
+ appendItem(group, "ColorMode", "RGB/Alpha");
+ break;
+ case FOURCC_DXT4:
+ appendItem(group, "BitDepth", 16);
+ appendItem(group, "Compression", "DXT4");
+ appendItem(group, "ColorMode", "RGB/Alpha");
+ break;
+ case FOURCC_DXT5:
+ appendItem(group, "BitDepth", 16);
+ appendItem(group, "Compression", "DXT5");
+ appendItem(group, "ColorMode", "RGB/Alpha");
+ break;
+ case FOURCC_RXGB:
+ appendItem(group, "BitDepth", 16);
+ appendItem(group, "Compression", "RXGB");
+ appendItem(group, "ColorMode", "RGB");
+ break;
+ default:
+ appendItem(group, "Compression", "Unknown");
+ break;
+ }
+ }
+ else {
+ appendItem(group, "Compression", "Unknown");
+ }
+
+ return true;
+}
+
+#include "kfile_dds.moc"
+
diff --git a/kfile-plugins/dds/kfile_dds.desktop b/kfile-plugins/dds/kfile_dds.desktop
new file mode 100644
index 00000000..f6b4ae02
--- /dev/null
+++ b/kfile-plugins/dds/kfile_dds.desktop
@@ -0,0 +1,53 @@
+[Desktop Entry]
+Type=Service
+Name=DirectDraw Surface Info
+Name[ca]=Informació de superfície DirectDraw
+Name[cs]=DirectDraw Surface info
+Name[da]=DirectDraw overflade-info
+Name[de]=DirectDraw Oberflächeninfo
+Name[el]=Πληροφορίες επιφάνειας DirectDraw
+Name[eo]=DirectDraw surfac-informo
+Name[es]=Información de la primera vista de DirectDraw
+Name[et]=DirectDraw Surface'i info
+Name[eu]=DirectDraw Surface informazioa
+Name[fa]=اطلاعات سطح DirectDraw
+Name[fi]=DirectDraw pintatieto
+Name[fr]=Informations de surface DirectDraw
+Name[ga]=Eolas faoi DirectDraw Surface
+Name[gl]=Información de Superficie de DirectDraw
+Name[he]=מיגע אודות משטח DirectDraw
+Name[hu]=DirectDraw felületinformáció
+Name[is]=DirectDraw yfirborðs upplýsingar
+Name[it]=Informazioni superficie DirectDraw
+Name[ja]=DDS (DirectDraw Surface) 情報
+Name[kk]=DirectDraw бедерінің мәлметі
+Name[km]=ព័ត៌មាន​ផ្ទៃ​ខាង​ក្រៅ​អំពី DirectDraw
+Name[lt]=DirectDraw Surface informacija
+Name[ms]=Maklumat Permukaan LukisTerus
+Name[nb]=DirectDraw Overflate info
+Name[nds]="DirectDraw"-Böversietinfo
+Name[ne]=प्रत्यक्ष रेखाचित्र सतह सूचना
+Name[nl]=DirectDraw Surface-info
+Name[nn]=DirectDraw-overflateinfo
+Name[pl]=Informacja o powierzchni DirectDraw
+Name[pt]=Informação de Superfície DirectDraw
+Name[pt_BR]=Informações Sobre Superfícies Direct Draw
+Name[ro]=Informaţii Suprafaţă DirectDraw
+Name[ru]=Сведения о поверхности DirectDraw
+Name[sk]=DirectDraw informácie o povrchu
+Name[sl]=Podatki o površini DirectDraw
+Name[sr]=Информације о DirectDraw површини
+Name[sr@Latn]=Informacije o DirectDraw površini
+Name[sv]=Directdraw ytinformation
+Name[ta]=நேரடி மேற்பரப்பு தகவல்
+Name[th]=ข้อมูลแฟ้มพื้นผิว DirectDraw
+Name[tr]=DirectDraw Yüzey Bilgisi
+Name[uk]=Інформація про поверхню DirectDraw
+Name[zh_CN]=DirectDraw 表面信息
+Name[zh_HK]=DirectDraw 表面資訊
+Name[zh_TW]=DirectDraw Surface 資訊
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_dds
+MimeType=image/x-dds
+PreferredGroups=Technical
+PreferredItems=Dimensions,Depth,BitDepth,Type,ColorMode,Compression
diff --git a/kfile-plugins/dds/kfile_dds.h b/kfile-plugins/dds/kfile_dds.h
new file mode 100644
index 00000000..342581bb
--- /dev/null
+++ b/kfile-plugins/dds/kfile_dds.h
@@ -0,0 +1,37 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Ignacio Castao <castano@ludicon.com>
+ *
+ * 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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __KFILE_DDS_H__
+#define __KFILE_DDS_H__
+
+#include <kfilemetainfo.h>
+
+class QStringList;
+
+class KDdsPlugin: public KFilePlugin
+{
+ Q_OBJECT
+
+public:
+ KDdsPlugin( QObject *parent, const char *name, const QStringList& args );
+
+ virtual bool readInfo( KFileMetaInfo& info, uint what);
+};
+
+#endif
diff --git a/kfile-plugins/dvi/Makefile.am b/kfile-plugins/dvi/Makefile.am
new file mode 100644
index 00000000..61791bdc
--- /dev/null
+++ b/kfile-plugins/dvi/Makefile.am
@@ -0,0 +1,22 @@
+## Makefile.am for the dvi file meta info plugin
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = kfile_dvi.h
+
+kde_module_LTLIBRARIES = kfile_dvi.la
+
+kfile_dvi_la_SOURCES = kfile_dvi.cpp
+kfile_dvi_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_dvi_la_LIBADD = $(LIB_KIO)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages:
+ $(XGETTEXT) *.cpp -o $(podir)/kfile_dvi.pot
+
+services_DATA = kfile_dvi.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kfile-plugins/dvi/kfile_dvi.cpp b/kfile-plugins/dvi/kfile_dvi.cpp
new file mode 100644
index 00000000..4140b98b
--- /dev/null
+++ b/kfile-plugins/dvi/kfile_dvi.cpp
@@ -0,0 +1,150 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Matthias Witzgall <witzi@gmx.net>
+ *
+ * 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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+/* further informations about the dvi file format could be downloaded from: http://www.rpi.edu/~sofkam/DVI/archive/standards/dvistd0.dvi */
+
+#include "kfile_dvi.h"
+
+#include <kgenericfactory.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kfilemetainfo.h>
+
+#include <qstring.h>
+#include <qvariant.h>
+#include <qdatetime.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+
+
+// preprocessormacro K_EXPORT_COMPONENT_FACTORY loads shared library 'kfile_dvi.so' dynamic if necessary
+typedef KGenericFactory<KDviPlugin> DviFactory;
+K_EXPORT_COMPONENT_FACTORY(kfile_dvi, DviFactory("kfile_dvi"))
+
+KDviPlugin::KDviPlugin (QObject * parent, const char * name, const QStringList & preferredItems)
+ : KFilePlugin(parent, name, preferredItems)
+{
+ kdDebug(7034) << "dvi plugin" << endl;
+
+ // set up our mime type
+ KFileMimeTypeInfo * info = this->addMimeTypeInfo("application/x-dvi");
+
+
+ KFileMimeTypeInfo::GroupInfo * group = this->addGroupInfo(info, "General", "General");
+
+ this->addItemInfo(group, "3_Created", i18n("Created"), QVariant::String);
+ this->addItemInfo(group, "6_Comment", i18n("Comment"), QVariant::String);
+ this->addItemInfo(group, "7_Pages", i18n("Pages"), QVariant::UInt);
+}
+
+bool KDviPlugin::readInfo (KFileMetaInfo & info, uint /* what (unused in this plugin) */)
+{
+ if ( info.path().isEmpty() )
+ return false;
+ KFileMetaInfoGroup GeneralGroup = appendGroup(info, "General");
+ QFile f(info.path());
+ QFileInfo f_info;
+ Q_UINT16 bytes_to_read;
+ Q_UINT8 comment_length;
+ QString comment;
+ Q_UINT16 pages;
+ Q_UINT8 buffer[270]; // buffer for reading data; no data is read with more than 270 bytes
+ Q_UINT32 ptr;
+ int i; // running index
+
+ // open file and try to get the comment
+ f.open(IO_ReadOnly);
+
+ if ( f.isOpen() == false ){
+ kdDebug(7034) << "cannot open file" << endl;
+ return false;
+ }
+
+ f_info.setFile(f); // create fileinfoobject
+ bytes_to_read = QMIN(f_info.size(), 270); // check, if the file size is smaller than 270 bytes
+ // (if the comment is as large as possible, we don't have to
+ // read more than 270 bytes)
+
+ if ( f.readBlock((char *)buffer, bytes_to_read) != bytes_to_read ){ // cast to (char *) is necessary
+ kdDebug(7034) << "read error (1)" << endl;
+ return false;
+ }
+
+ if ( (buffer[0] != 247) || (buffer[1] != 2) ){
+ // magic numbers are not right
+ kdDebug(7034) << "wrong file format" << endl;;
+ return false;
+ }
+
+ comment_length = buffer[14]; // set up length of comment
+ comment.setLength(comment_length); // used to avoid permanent reallocation when extracting the comment from buffer
+
+ for ( i = 15; i <= 14+comment_length; ++i ) // extract comment from buffer
+ comment[i-15] = (char)buffer[i];
+
+ appendItem(GeneralGroup, "6_Comment", comment.simplifyWhiteSpace() );
+
+ // comment is ok, now get total number of pages
+ f.at( f.size() - 13);
+ if ( f.readBlock((char *)buffer, 13) != 13 ){
+ kdDebug(7034) << "read error (2)" << endl;
+ return false;
+ }
+
+ i = 12; // reset running index i
+ while ( buffer[i] == 223 ){ --i; } // skip all trailing bytes
+
+ if ( (buffer[i] != 2) || (i > 8) || (i < 5) ){
+ kdDebug(7034) << "wrong file formatx" << endl;
+ return false;
+ }
+
+ // now we know the position of the pointer to the beginning of the postamble and we can read it
+ ptr = buffer[i-4];
+ ptr = (ptr << 8) | buffer[i-3];
+ ptr = (ptr << 8) | buffer[i-2];
+ ptr = (ptr << 8) | buffer[i-1];
+
+ // bytes for total number of pages have a offset of 27 to the beginning of the postamble
+ f.at(ptr + 27);
+
+ // now read total number of pages from file
+ if ( f.readBlock((char *)buffer, 2) != 2 ){
+ kdDebug(7034) << "read error (3)" << endl;
+ return false;
+ }
+ pages = buffer[0];
+ pages = (pages << 8) | buffer[1];
+
+ appendItem(GeneralGroup, "7_Pages", QVariant(pages) );
+
+ f.close();
+
+ // now get and set up some basic informations about the file (same informations would be displayed, if there is no dvi-plugin)
+ appendItem(GeneralGroup, "1_Type", QVariant( i18n("TeX Device Independent file") ) ); // set up type of file
+
+ appendItem(GeneralGroup, "4_Modified", QVariant(f_info.lastModified().toString("yyyy-MM-dd hh:mm")) );
+ // ISO 8601 date format (without seconds)
+
+ return true;
+}
+
+#include "kfile_dvi.moc"
diff --git a/kfile-plugins/dvi/kfile_dvi.desktop b/kfile-plugins/dvi/kfile_dvi.desktop
new file mode 100644
index 00000000..ed640afb
--- /dev/null
+++ b/kfile-plugins/dvi/kfile_dvi.desktop
@@ -0,0 +1,60 @@
+[Desktop Entry]
+Icon=
+MimeType=application/x-dvi
+Name=DVI Info
+Name[ar]=معلومات DVI
+Name[br]=Titouroù DVI
+Name[ca]=Informació de DVI
+Name[cs]=DVI info
+Name[cy]=Gwybodaeth DVI
+Name[da]=DVI-info
+Name[de]=DVI-Info
+Name[el]=Πληροφορίες DVI
+Name[eo]=DVI-informo
+Name[es]=Info DVI
+Name[et]=DVI info
+Name[fa]=اطلاعات DVI
+Name[fi]=DVI-tiedot
+Name[fr]=Informations DVI
+Name[ga]=Eolas faoi DVI
+Name[gl]=Inf. DVI
+Name[he]=מידע DVI
+Name[hi]=DVI जानकारी
+Name[hu]=DVI-jellemzők
+Name[is]=DVI upplýsingar
+Name[it]=Informazioni DVI
+Name[ja]=DVI 情報
+Name[kk]=DVI мәліметі
+Name[km]=ព័ត៌មាន DVI
+Name[lt]=DVI informacija
+Name[ms]=Maklumat DVI
+Name[nds]=DVI-Info
+Name[ne]=DVI सूचना
+Name[nl]=DVI-info
+Name[nn]=DVI-info
+Name[pa]=DVI ਜਾਣਕਾਰੀ
+Name[pl]=Informacja o pliku DVI
+Name[pt]=Informação do DVI
+Name[pt_BR]=Informação sobre DVI
+Name[ro]=Informaţii DVI
+Name[ru]=Информация о DVI
+Name[se]=DVI-dieđut
+Name[sl]=Podatki o DVI
+Name[sr]=DVI информације
+Name[sr@Latn]=DVI informacije
+Name[sv]=DVI-information
+Name[ta]=DVI தகவல்
+Name[tg]=Иттилоот оиди DVI
+Name[th]=ข้อมูลแฟ้ม DVI
+Name[tr]=DVI Bilgisi
+Name[uk]=Інформація по DVI
+Name[uz]=DVI haqida maʼlumot
+Name[uz@cyrillic]=DVI ҳақида маълумот
+Name[wa]=Informåcion sol documint DVI
+Name[zh_CN]=DVI 信息
+Name[zh_HK]=DVI 資訊
+Name[zh_TW]=DVI 資訊
+ServiceTypes=KFilePlugin
+Type=Service
+X-KDE-Library=kfile_dvi
+PreferredItems=Title,Author,Subject,Creator,Producer,CreationDate,ModDate,Keywords
diff --git a/kfile-plugins/dvi/kfile_dvi.h b/kfile-plugins/dvi/kfile_dvi.h
new file mode 100644
index 00000000..66e7b218
--- /dev/null
+++ b/kfile-plugins/dvi/kfile_dvi.h
@@ -0,0 +1,37 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Matthias Witzgall <witzi@gmx.net>
+ *
+ * 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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef __KFILE_DVI_H__
+#define __KFILE_DVI_H__
+
+#include <kfilemetainfo.h>
+
+class QStringList;
+
+class KDviPlugin : public KFilePlugin
+{
+ Q_OBJECT
+public:
+ KDviPlugin ( QObject * parent, const char * name, const QStringList & preferredItems );
+
+ virtual bool readInfo (KFileMetaInfo & info, uint what);
+};
+
+#endif
diff --git a/kfile-plugins/exr/Makefile.am b/kfile-plugins/exr/Makefile.am
new file mode 100644
index 00000000..f337359c
--- /dev/null
+++ b/kfile-plugins/exr/Makefile.am
@@ -0,0 +1,25 @@
+## Makefile.am for EXR file meta info plugin
+
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+
+# set the include path for X, qt and KDE
+INCLUDES = -Drestrict= $(all_includes) $(EXR_FLAGS)
+# INCLUDES = $(all_includes) $(EXR_FLAGS)
+
+# these are the headers for your project
+noinst_HEADERS = kfile_exr.h
+
+kde_module_LTLIBRARIES = kfile_exr.la
+
+kfile_exr_la_SOURCES = kfile_exr.cpp
+kfile_exr_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_exr_la_LIBADD = $(LIB_KIO) $(LIB_EXR)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages:
+ $(XGETTEXT) *.cpp -o $(podir)/kfile_exr.pot
+
+services_DATA = kfile_exr.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kfile-plugins/exr/configure.in.in b/kfile-plugins/exr/configure.in.in
new file mode 100644
index 00000000..2a9ff5e5
--- /dev/null
+++ b/kfile-plugins/exr/configure.in.in
@@ -0,0 +1,14 @@
+AC_ARG_WITH([openexr],
+ [AC_HELP_STRING([--with-openexr],
+ [Enable support for OpenEXR @<:@default=check@:>@])],
+ [], with_openexr=check)
+
+if test "x$with_openexr" != xno; then
+ KDE_FIND_LIBEXR
+
+ if test "x$with_openexr" != xcheck && test -z "$LIB_EXR"; then
+ AC_MSG_ERROR([--with-openexr was given, but test for OpenEXR failed])
+ fi
+fi
+
+AM_CONDITIONAL(include_EXR_MODULES, test -n "$LIB_EXR")
diff --git a/kfile-plugins/exr/kfile_exr.cpp b/kfile-plugins/exr/kfile_exr.cpp
new file mode 100644
index 00000000..2e995fc6
--- /dev/null
+++ b/kfile-plugins/exr/kfile_exr.cpp
@@ -0,0 +1,393 @@
+// -*- C++;indent-tabs-mode: t; tab-width: 4; c-basic-offset: 4; -*-
+/* This file is part of the KDE project
+ * Copyright (C) 2003 <bradh@frogmouth.net>
+ *
+ * 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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#include <ImfStandardAttributes.h>
+#include <ImathBox.h>
+#include <ImfInputFile.h>
+#include <ImfBoxAttribute.h>
+#include <ImfChannelListAttribute.h>
+#include <ImfCompressionAttribute.h>
+#include <ImfFloatAttribute.h>
+#include <ImfIntAttribute.h>
+#include <ImfLineOrderAttribute.h>
+#include <ImfStringAttribute.h>
+#include <ImfVecAttribute.h>
+#include <ImfPreviewImage.h>
+#include <ImfVersion.h>
+#include <ImfCRgbaFile.h>
+
+#include <iostream>
+
+#include <stdlib.h>
+#include <string>
+
+#include <kurl.h>
+#include <kprocess.h>
+#include <klocale.h>
+#include <kgenericfactory.h>
+#include <kdebug.h>
+
+#include <qcstring.h>
+#include <qfile.h>
+#include <qdatetime.h>
+#include <qdict.h>
+#include <qvalidator.h>
+#include <qimage.h>
+
+
+#include "kfile_exr.h"
+using namespace Imf;
+
+typedef KGenericFactory<KExrPlugin> ExrFactory;
+
+K_EXPORT_COMPONENT_FACTORY(kfile_exr, ExrFactory("kfile_exr"))
+
+KExrPlugin::KExrPlugin(QObject *parent, const char *name,
+ const QStringList &args)
+ : KFilePlugin(parent, name, args)
+{
+ // set up our mime type
+ KFileMimeTypeInfo* info = addMimeTypeInfo( "image/x-exr" );
+
+ KFileMimeTypeInfo::GroupInfo* group = 0;
+ KFileMimeTypeInfo::ItemInfo* item;
+
+ // info group
+ group = addGroupInfo( info, "Info", i18n("Information") );
+ addItemInfo( group, "Version", i18n("Format Version"), QVariant::Int );
+ addItemInfo( group, "Tiled image", i18n("Tiled Image"), QVariant::String );
+ item = addItemInfo( group, "Dimensions", i18n("Dimensions"), QVariant::Size );
+ setHint( item, KFileMimeTypeInfo::Size );
+ setUnit( item, KFileMimeTypeInfo::Pixels );
+ item = addItemInfo( group, "ThumbnailDimensions",
+ i18n("Thumbnail Dimensions"), QVariant::Size );
+ setHint( item, KFileMimeTypeInfo::Size );
+ setUnit( item, KFileMimeTypeInfo::Pixels );
+ addItemInfo( group, "Comment", i18n("Comment"), QVariant::String );
+ item = addItemInfo( group, "Thumbnail", i18n("Thumbnail"), QVariant::Image );
+ setHint( item, KFileMimeTypeInfo::Thumbnail );
+
+ // standard attributes group
+ group = addGroupInfo( info, "Standard", i18n("Standard Attributes") );
+ addItemInfo( group, "Owner", i18n("Owner"), QVariant::String );
+ addItemInfo( group, "Comments", i18n("Comments"), QVariant::String );
+ addItemInfo( group, "Capture Date", i18n("Capture Date"), QVariant::String );
+ item = addItemInfo( group, "UTC Offset", i18n("UTC Offset"), QVariant::String );
+ item = addItemInfo( group, "Exposure time", i18n("Exposure Time"), QVariant::Double);
+ setUnit( item, KFileMimeTypeInfo::Seconds );
+ item = addItemInfo( group, "Focus", i18n("Focus"), QVariant::Double);
+ setSuffix( item, i18n("Metres", "m") );
+ item = addItemInfo( group, "X Density", i18n("X Density"), QVariant::Double);
+ setSuffix( item, i18n("Pixels Per Inch", " ppi") );
+ item = addItemInfo( group, "White luminance", i18n("White Luminance"), QVariant::Double);
+ setSuffix( item, i18n("Candelas per square metre", " Nits") );
+ addItemInfo( group, "Longitude", i18n("Longitude"), QVariant::String );
+ addItemInfo( group, "Latitude", i18n("Latitude"), QVariant::String );
+ item = addItemInfo( group, "Altitude", i18n("Altitude"), QVariant::String );
+ setSuffix( item, i18n("Metres", "m") );
+ addItemInfo( group, "ISO speed", i18n("ISO Speed"), QVariant::Double );
+ addItemInfo( group, "Aperture", i18n("Aperture"), QVariant::Double );
+
+ // channel group
+ group = addGroupInfo( info, "Channel", i18n("Channels") );
+ addItemInfo( group, "A", i18n("A"), QVariant::String );
+ addItemInfo( group, "R", i18n("R"), QVariant::String );
+ addItemInfo( group, "G", i18n("G"), QVariant::String );
+ addItemInfo( group, "B", i18n("B"), QVariant::String );
+ addItemInfo( group, "Z", i18n("Z"), QVariant::String );
+ addItemInfo( group, "NX", i18n("NX"), QVariant::String );
+ addItemInfo( group, "NY", i18n("NY"), QVariant::String );
+ addItemInfo( group, "NZ", i18n("NZ"), QVariant::String );
+ addItemInfo( group, "R", i18n("R"), QVariant::String );
+ addItemInfo( group, "U", i18n("U"), QVariant::String );
+ addItemInfo( group, "V", i18n("V"), QVariant::String );
+ addItemInfo( group, "materialID", i18n("materialID"), QVariant::String );
+ addItemInfo( group, "objectID", i18n("objectID"), QVariant::String );
+ addItemInfo( group, "renderID", i18n("renderID"), QVariant::String );
+ addItemInfo( group, "pixelCover", i18n("pixelCover"), QVariant::String );
+ addItemInfo( group, "velX", i18n("velX"), QVariant::String );
+ addItemInfo( group, "velY", i18n("velY"), QVariant::String );
+ addItemInfo( group, "packedRGBA", i18n("packedRGBA"), QVariant::String );
+
+
+ // technical group
+ group = addGroupInfo( info, "Technical", i18n("Technical Details") );
+ addItemInfo( group, "Compression", i18n("Compression"), QVariant::String );
+ addItemInfo( group, "Line Order", i18n("Line Order"), QVariant::String );
+
+ // 3dsMax group
+ // This supports a special plugin for 3D Studio Max
+ group = addGroupInfo( info, "3dsMax", i18n("3dsMax Details") );
+ addItemInfo( group, "Local time", i18n("Local Time"), QVariant::String );
+ addItemInfo( group, "System time", i18n("System Time"), QVariant::String );
+ addItemInfo( group, "Plugin version", i18n("Plugin Version"), QVariant::String );
+ addItemInfo( group, "EXR version", i18n("EXR Version"), QVariant::String );
+ addItemInfo( group, "Computer name", i18n("Computer Name"), QVariant::String );
+}
+
+QCString doType( PixelType pt )
+{
+ switch (pt)
+ {
+ case UINT:
+ return QCString("32-bit unsigned integer");
+ break;
+ case HALF:
+ return QCString("16-bit floating-point");
+ break;
+ case FLOAT:
+ return QCString("32-bit floating-point");
+ break;
+ default:
+ return QCString();
+ break;
+ }
+}
+
+bool KExrPlugin::readInfo( KFileMetaInfo& info, uint what)
+{
+ try
+ {
+ InputFile in ( info.path().ascii() );
+ const Header &h = in.header();
+
+ KFileMetaInfoGroup infogroup = appendGroup(info, "Info");
+ KFileMetaInfoGroup stdgroup = appendGroup(info, "Standard");
+ KFileMetaInfoGroup channelgroup = appendGroup(info, "Channel");
+ KFileMetaInfoGroup techgroup = appendGroup(info, "Technical");
+ KFileMetaInfoGroup threedsmaxgroup = appendGroup(info, "3dsMax");
+
+ appendItem( infogroup, "Version", getVersion(in.version()) );
+ if (isTiled(in.version())) {
+ appendItem( infogroup, "Tiled image", "yes" );
+ } else {
+ appendItem( infogroup, "Tiled image", "no" );
+ }
+
+ Imath::Box2i dw = h.dataWindow();
+ appendItem( infogroup, "Dimensions", QSize( (dw.max.x - dw.min.x + 1 ),
+ (dw.max.y - dw.min.y + 1 ) ) );
+
+ if ( h.hasPreviewImage() ) {
+ const PreviewImage &preview = in.header().previewImage();
+ appendItem( infogroup, "ThumbnailDimensions", QSize(preview.width(), preview.height()) );
+ QImage qpreview(preview.width(), preview.height(), 32, 0, QImage::BigEndian);
+ for ( unsigned int y=0; y < preview.height(); y++ ) {
+ for ( unsigned int x=0; x < preview.width(); x++ ) {
+ const PreviewRgba &q = preview.pixels()[x+(y*preview.width())];
+ qpreview.setPixel( x, y, qRgba(q.r, q.g, q.b, q.a) );
+ }
+ }
+ appendItem( infogroup, "Thumbnail", qpreview);
+ }
+
+ const StringAttribute *commentSA = h.findTypedAttribute <StringAttribute> ("comment");
+ if (commentSA) {
+ std::string commentString = commentSA->value();
+ QString qcommentString(commentString.data());
+ qcommentString.setLength(commentString.size());
+ appendItem( infogroup, "Comment", qcommentString );
+ }
+
+ // Standard Attributes we are interested in and can
+ // meaningfully represent.
+ if ( hasComments(h) ) {
+ std::string commentsString = comments(h);
+ QString qcommentsString(commentsString.data());
+ qcommentsString.setLength(commentsString.size());
+ appendItem( stdgroup, "Comments", qcommentsString );
+ }
+ if ( hasOwner(h) ) {
+ std::string ownerString = owner(h);
+ QString qownerString(ownerString.data());
+ qownerString.setLength(ownerString.size());
+ appendItem( stdgroup, "Owner", qownerString );
+ }
+ if ( hasCapDate(h) ) {
+ std::string capDateString = capDate(h);
+ QString qcapDateString(capDateString.data());
+ qcapDateString.setLength(capDateString.size());
+ appendItem( stdgroup, "Capture Date", qcapDateString );
+ }
+ // This define was introduced in EXR 1.6.0
+#ifndef IMF_B44_COMPRESSION
+ // This is the 1.4 and earlier version
+ if ( hasutcOffset(h) ) {
+#else
+ // This is the 1.6.0 and later version
+ if ( hasUtcOffset(h) ) {
+#endif
+ QString UTCOffset;
+ if (utcOffset(h)>0.0) {
+ UTCOffset.append(QString("%1").arg(utcOffset(h)/3600, 0, 'f', 1));
+ UTCOffset.append(" hours behind UTC");
+ } else {
+ UTCOffset.append(QString("%1").arg(-1.0*utcOffset(h)/3600, 0, 'f', 1));
+ UTCOffset.append(" hours ahead of UTC");
+ }
+ appendItem( stdgroup, "UTC Offset", UTCOffset);
+ }
+ if ( hasExpTime(h) ) {
+ double exposureTime = expTime(h);
+ appendItem( stdgroup, "Exposure time", exposureTime );
+ }
+ if ( hasFocus(h) ) {
+ double focusDistance = focus(h);
+ appendItem( stdgroup, "Focus", focusDistance );
+ }
+ if ( hasXDensity(h) ) {
+ double XDensity = xDensity(h);
+ appendItem( stdgroup, "X Density", XDensity );
+ }
+ if ( hasWhiteLuminance(h) ) {
+ double WhiteLuminance = whiteLuminance(h);
+ appendItem( stdgroup, "White luminance", WhiteLuminance );
+ }
+ if ( hasLongitude(h) ) {
+ QString Longitude;
+ if (longitude(h)<0.0) {
+ Longitude.append(QString("%1").arg(-1.0*longitude(h),0,'f',3));
+ Longitude.append(" deg West");
+ } else {
+ Longitude.append(QString("%1").arg(longitude(h),0,'f',3));
+ Longitude.append(" deg East");
+ }
+ appendItem( stdgroup, "Longitude", Longitude);
+ }
+ if ( hasLatitude(h) ) {
+ QString Latitude;
+ if (latitude(h)<0.0) {
+ Latitude.append(QString("%1").arg(-1.0*latitude(h),0,'f',3));
+ Latitude.append(" deg South");
+ } else {
+ Latitude.append(QString("%1").arg(latitude(h),0,'f',3));
+ Latitude.append(" deg North");
+ }
+ appendItem( stdgroup, "Latitude", Latitude );
+ }
+ if ( hasAltitude(h) ) {
+ double Altitude = altitude(h);
+ appendItem( stdgroup, "Altitude", QString("%1").arg(Altitude,0,'f',1) );
+ }
+ if ( hasIsoSpeed(h) ) {
+ double IsoSpeed = isoSpeed(h);
+ appendItem( stdgroup, "ISO speed", IsoSpeed );
+ }
+ if ( hasAperture(h) ) {
+ double Aperture = aperture(h);
+ appendItem( stdgroup, "Aperture", Aperture );
+ }
+
+ for (Header::ConstIterator i = h.begin(); i != h.end(); ++i) {
+ const Attribute *a = &i.attribute();
+
+ if (const CompressionAttribute *ta = dynamic_cast <const CompressionAttribute *> (a)) {
+ switch ( ta->value() )
+ {
+ case NO_COMPRESSION:
+ appendItem( techgroup, "Compression", i18n("No compression"));
+ break;
+ case RLE_COMPRESSION:
+ appendItem( techgroup, "Compression", i18n("Run Length Encoding"));
+ break;
+ case ZIPS_COMPRESSION:
+ appendItem( techgroup, "Compression", i18n("zip, individual scanlines"));
+ break;
+ case ZIP_COMPRESSION:
+ appendItem( techgroup, "Compression", i18n("zip, multi-scanline blocks"));
+ break;
+ case PIZ_COMPRESSION:
+ appendItem( techgroup, "Compression", i18n("piz compression"));
+ break;
+ default:
+ break;
+ }
+ } else if (const LineOrderAttribute *ta = dynamic_cast <const LineOrderAttribute *> (a)) {
+ switch (ta->value())
+ {
+ case INCREASING_Y:
+ appendItem( techgroup, "Line Order", i18n("increasing Y"));
+ break;
+ case DECREASING_Y:
+ appendItem( techgroup, "Line Order", i18n("decreasing Y"));
+ break;
+ default:
+ break;
+ };
+ } else if (const ChannelListAttribute *ta = dynamic_cast <const ChannelListAttribute *> (a)) {
+
+ for (ChannelList::ConstIterator i = ta->value().begin(); i != ta->value().end(); ++i)
+ {
+ appendItem( channelgroup, i.name(), doType(i.channel().type) );
+ }
+ }
+ }
+
+ // This section deals with some special case stuff for a 3D Studio Max
+ // plugin from Splutterfish. The weird construction is an
+ // attempt to to deal with class conversion. C++ string handling
+ // without Qt is a pain...
+ const StringAttribute *ver3DSM = h.findTypedAttribute <StringAttribute> ("version3dsMax");
+ if (ver3DSM) {
+ std::string ver3DSMstring = ver3DSM->value();
+ QString qver3DSMstring(ver3DSMstring.data());
+ qver3DSMstring.setLength(ver3DSMstring.size());
+ appendItem( threedsmaxgroup, "Plugin version", qver3DSMstring );
+ }
+ const StringAttribute *verEXR = h.findTypedAttribute <StringAttribute> ("versionEXR");
+ if (verEXR) {
+ std::string verEXRstring = verEXR->value();
+ QString qverEXRstring(verEXRstring.data());
+ qverEXRstring.setLength(verEXRstring.size());
+ appendItem( threedsmaxgroup, "EXR version", QString( verEXRstring.data() ) );
+ }
+ const StringAttribute *localTime = h.findTypedAttribute <StringAttribute> ("localTime");
+ if (localTime) {
+ std::string localTimeString = localTime->value();
+ QString qlocalTimeString(localTimeString.data());
+ qlocalTimeString.setLength(localTimeString.size());
+ appendItem( threedsmaxgroup, "Local time", qlocalTimeString );
+ }
+ const StringAttribute *systemTime = h.findTypedAttribute <StringAttribute> ("systemTime");
+ if (systemTime) {
+ std::string systemTimeString = systemTime->value();
+ QString qsystemTimeString(systemTimeString.data());
+ qsystemTimeString.setLength(systemTimeString.size());
+ appendItem( threedsmaxgroup, "System time", qsystemTimeString );
+ }
+ const StringAttribute *computerName = h.findTypedAttribute <StringAttribute> ("computerName");
+ if (computerName) {
+ std::string computerNameString = computerName->value();
+ QString qcomputerNameString(computerNameString.data());
+ qcomputerNameString.setLength(computerNameString.size());
+ appendItem( threedsmaxgroup, "Computer name", qcomputerNameString );
+ }
+
+ return true;
+ }
+ catch (const std::exception &e)
+ {
+ kdDebug(0) << e.what() << endl;
+ return false;
+ }
+}
+
+#include "kfile_exr.moc"
diff --git a/kfile-plugins/exr/kfile_exr.desktop b/kfile-plugins/exr/kfile_exr.desktop
new file mode 100644
index 00000000..b1b3a583
--- /dev/null
+++ b/kfile-plugins/exr/kfile_exr.desktop
@@ -0,0 +1,57 @@
+[Desktop Entry]
+Type=Service
+Name=EXR Info
+Name[br]=Titouroù EXR
+Name[ca]=Informació EXR
+Name[cs]=EXR info
+Name[cy]=Gwybodaeth EXR
+Name[da]=EXR-Info
+Name[de]=EXR-Info
+Name[el]=Πληροφορίες EXR
+Name[eo]=EXR-informo
+Name[es]=Info EXR
+Name[et]=EXR info
+Name[fa]=اطلاعات EXR
+Name[fi]=EXR-tiedot
+Name[fr]=Informations EXR
+Name[ga]=Eolas faoi EXR
+Name[gl]=Inf. EXR
+Name[he]=מידע EXR
+Name[hu]=EXR-jellemzők
+Name[is]=EXR upplýsingar
+Name[it]=Informazioni EXR
+Name[ja]=EXR 情報
+Name[kk]=EXR мәліметі
+Name[km]=ព័ត៌មាន EXR
+Name[lt]=EXR informacija
+Name[ms]=Maklumat EXR
+Name[nds]=EXR-Info
+Name[ne]=EXR सूचना
+Name[nl]=EXR-info
+Name[nn]=EXR-info
+Name[pa]=EXR ਜਾਣਕਾਰੀ
+Name[pl]=Informacja EXR
+Name[pt]=Informação do EXR
+Name[pt_BR]=Informação sobre EXR
+Name[ro]=Informaţii EXR
+Name[ru]=Информация о EXR
+Name[se]=EXR-dieđut
+Name[sl]=Podatki o EXR
+Name[sr]=EXR информације
+Name[sr@Latn]=EXR informacije
+Name[sv]=EXR-information
+Name[ta]=EXR தகவல்
+Name[tg]=Иттилоот оиди EXR
+Name[th]=ข้อมูลแฟ้ม EXR
+Name[tr]=EXR Bilgisi
+Name[uk]=Інформація по EXR
+Name[uz]=EXR haqida maʼlumot
+Name[uz@cyrillic]=EXR ҳақида маълумот
+Name[zh_CN]=EXR 信息
+Name[zh_HK]=EXR 資訊
+Name[zh_TW]=EXR 資訊
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_exr
+MimeType=image/x-exr
+PreferredGroups=Info,Standard,Channels,Technical,3dsMax
+PreferredItems=Dimensions,Thumbnail,ThumbnailDimensions,Version,Comments,Owner,Latitude,Longitude,Altitude,Capture Date,UTC Offset
diff --git a/kfile-plugins/exr/kfile_exr.h b/kfile-plugins/exr/kfile_exr.h
new file mode 100644
index 00000000..cb795ba5
--- /dev/null
+++ b/kfile-plugins/exr/kfile_exr.h
@@ -0,0 +1,39 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2003 <bradh@frogmouth.net>
+ *
+ * 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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#ifndef __KFILE_EXR_H__
+#define __KFILE_EXR_H__
+
+#include <kfilemetainfo.h>
+#include <kurl.h>
+
+class QStringList;
+
+class KExrPlugin: public KFilePlugin
+{
+ Q_OBJECT
+
+public:
+ KExrPlugin( QObject *parent, const char *name, const QStringList& preferredItems );
+
+ virtual bool readInfo( KFileMetaInfo& info, uint );
+};
+
+#endif
diff --git a/kfile-plugins/gif/Makefile.am b/kfile-plugins/gif/Makefile.am
new file mode 100644
index 00000000..b847d002
--- /dev/null
+++ b/kfile-plugins/gif/Makefile.am
@@ -0,0 +1,24 @@
+## Makefile.am for gif file meta info plugin
+
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = kfile_gif.h
+
+kde_module_LTLIBRARIES = kfile_gif.la
+
+kfile_gif_la_SOURCES = kfile_gif.cpp
+kfile_gif_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_gif_la_LIBADD = $(LIB_KIO)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages:
+ $(XGETTEXT) *.cpp -o $(podir)/kfile_gif.pot
+
+services_DATA = kfile_gif.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kfile-plugins/gif/README b/kfile-plugins/gif/README
new file mode 100644
index 00000000..e81cc913
--- /dev/null
+++ b/kfile-plugins/gif/README
@@ -0,0 +1,10 @@
+The original README for this file read:
+<quote>
+Note: Development of this module has been suspended.
+Please feel free to contact me, and pick it up. All I ask
+is that you preserve both command line and kfile abilities. Thanks.
+bryce@obviously.com
+</quote>
+
+I contacted Bryce, but received no response. The command line code
+is unchanged - I just fixed the kfile code to work, read only.
diff --git a/kfile-plugins/gif/gif-info.1 b/kfile-plugins/gif/gif-info.1
new file mode 100644
index 00000000..6c36b1c4
--- /dev/null
+++ b/kfile-plugins/gif/gif-info.1
@@ -0,0 +1,25 @@
+.TH gif-info 1 "April 2002"
+
+.SH NAME
+gif-info \- reads gif image info or sets comment.
+
+.SH SYNOPSIS
+.B gif-info
+.RB <filename>
+['Comment']
+
+.SH DESCRIPTION
+.LP
+.B gif-info
+displays information about the given gif (Graphic Interchange Format) image. If a comment is specified, the comment is set instead.
+.PP
+Write a empty comment ('') to delete the comment block.
+.PP
+The GIF standard allows any number of 256 byte comment blocks in an image file, but most implementations (including this one) restrict you to just one block. The GIF standard restricts comment blocks to "7 Bit ASCII", but this is widely ignored. You are welcome to store text in your own native language, and are especially encouraged to use comments in utf-8 unicode format.
+
+.SH "SEE ALSO"
+.BR wrjpgcom (1)
+.BR rdjpgcom (1)
+
+.SH AUTHOR
+Bryce Nesbitt
diff --git a/kfile-plugins/gif/gif-info.c b/kfile-plugins/gif/gif-info.c
new file mode 100644
index 00000000..2f64a2f2
--- /dev/null
+++ b/kfile-plugins/gif/gif-info.c
@@ -0,0 +1,561 @@
+/*
+** $Id$
+**
+** Minimal GIF parser, for use in extracting and setting metadata.
+** Modified for standalone & KDE calling by Bryce Nesbitt
+**
+** TODO:
+** Support gif comments that span more than one comment block.
+** Verify that Unicode utf-8 is fully unmolested by this code.
+** Implement gif structure verifier.
+**
+** Based on: GIFtrans v1.12.2
+** Copyright (C) 24.2.94 by Andreas Ley <ley@rz.uni-karlsruhe.de>
+**
+*******************************************************************************
+**
+** Original distribution site is
+** ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/giftrans.c
+** A man-page by knordlun@fltxa.helsinki.fi (Kai Nordlund) is at
+** ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/giftrans.1
+** An online version by taylor@intuitive.com (Dave Taylor) is at
+** http://www.intuitive.com/coolweb/Addons/giftrans-doc.html
+** To compile for MS-DOS or OS/2, you need getopt:
+** ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/getopt.c
+** MS-DOS executable can be found at
+** ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/giftrans.exe
+** OS/2 executable can be found at
+** ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/giftrans.os2.exe
+** A template rgb.txt for use with the MS-DOS version can be found at
+** ftp://ftp.rz.uni-karlsruhe.de/pub/net/www/tools/giftrans/rgb.txt
+** Additional info can be found on
+** http://melmac.corp.harris.com/transparent_images.html
+**
+** The GIF file format is documented in
+** ftp://ftp.uu.net/doc/literary/obi/Standards/Graphics/Formats/gif89a.doc.Z
+** A good quick reference is at:
+** http://www.goice.co.jp/member/mo/formats/gif.html
+**
+*******************************************************************************
+**
+** 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 <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#define STANDALONE_COMPILE
+
+extern int set_gif_comment( const char * original_filename, char * comment );
+extern void * get_gif_info( const char * original_filename );
+extern int validate_gif_structure( const char * original_filename );
+int giftrans( FILE * src, FILE * dest);
+
+#define WARNING_GARBAGE 1 /* Original file had some unspecified content */
+#define ERROR_NOT_A_JPEG 5 /* Original file not a proper jpeg (must be 1st) */
+#define ERROR_TEMP_FILE 6 /* Problem writing temporay file */
+#define ERROR_SCREWUP 7 /* Original file is now damaged. Ooops. */
+#define ERROR_PREMATURE_EOF 8 /* Unexpected end of file */
+#define ERROR_BAD_MARKER 9 /* Marker with illegal length */
+#define ERROR_MARKER_ORDER 10 /* File seems to be mixed up */
+
+/*****************************************************************************/
+#ifndef FALSE
+#define FALSE (0) /* This is the naked Truth */
+#define TRUE (1) /* and this is the Light */
+#endif
+
+#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */
+#define READ_BINARY "r"
+#define WRITE_BINARY "w"
+#else
+#ifdef VMS /* VMS is very nonstandard */
+#define READ_BINARY "rb", "ctx=stm"
+#define WRITE_BINARY "wb", "ctx=stm"
+#else /* standard ANSI-compliant case */
+#define READ_BINARY "rb"
+#define WRITE_BINARY "wb"
+#endif
+#endif
+
+#define SUCCESS (0)
+#define FAILURE (1)
+
+static char skipcomment,list,verbose,output,debug;
+char *global_comment;
+static long int pos;
+
+static char true[] = "True";
+static char false[] = "False";
+static char id[] = "$Id$";
+
+/*****************************************************************************/
+
+#define readword(buffer) ((buffer)[0]+256*(buffer)[1])
+#define readflag(buffer) ((buffer)?true:false)
+#define hex(c) ('a'<=(c)&&(c)<='z'?(c)-'a'+10:'A'<=(c)&&(c)<='Z'?(c)-'A'+10:(c)-'0')
+
+void dump(adr,data,len)
+long int adr;
+unsigned char *data;
+size_t len;
+{
+ int i;
+
+ while (len>0) {
+ (void)fprintf(stderr,"%08lx:%*s",adr,(int)((adr%16)*3+(adr%16>8?1:0)),"");
+ for (i=adr%16;i<16&&len>0;i++,adr++,data++,len--)
+ (void)fprintf(stderr,"%s%02x",i==8?" ":" ",*data);
+ (void)fprintf(stderr,"\n");
+ }
+}
+
+void writedata(dest,data,len)
+FILE *dest;
+unsigned char *data;
+size_t len;
+{
+ unsigned char size;
+
+ while (len) {
+ size=len<256?len:255;
+ (void)fwrite((void *)&size,1,1,dest);
+ (void)fwrite((void *)data,(size_t)size,1,dest);
+ data+=size;
+ len-=size;
+ }
+ size=0;
+ (void)fwrite((void *)&size,1,1,dest);
+}
+
+void skipdata(src)
+FILE *src;
+{
+ unsigned char size,buffer[256];
+
+ do {
+ pos=ftell(src);
+ (void)fread((void *)&size,1,1,src);
+ if (debug)
+ dump(pos,&size,1);
+ if (debug) {
+ pos=ftell(src);
+ (void)fread((void *)buffer,(size_t)size,1,src);
+ dump(pos,buffer,(size_t)size);
+ }
+ else
+ (void)fseek(src,(long int)size,SEEK_CUR);
+ } while (!feof(src)&&size>0);
+}
+
+void transblock(src,dest)
+FILE *src;
+FILE *dest;
+{
+ unsigned char size,buffer[256];
+
+ pos=ftell(src);
+ (void)fread((void *)&size,1,1,src);
+ if (debug)
+ dump(pos,&size,1);
+ if (output)
+ (void)fwrite((void *)&size,1,1,dest);
+ pos=ftell(src);
+ (void)fread((void *)buffer,(size_t)size,1,src);
+ if (debug)
+ dump(pos,buffer,(size_t)size);
+ if (output)
+ (void)fwrite((void *)buffer,(size_t)size,1,dest);
+}
+
+void dumpcomment(src)
+FILE *src;
+{
+ unsigned char size,buffer[256];
+ size_t i;
+
+ pos=ftell(src);
+ (void)fread((void *)&size,1,1,src);
+ if (debug)
+ dump(pos,&size,1);
+ (void)fread((void *)buffer,(size_t)size,1,src);
+ if (debug)
+ dump(pos+1,buffer,(size_t)size);
+ for (i=0; i<(size_t)size; i++)
+ {
+ if ( buffer[i] >= 0x20 || buffer[i] == '\t' ||
+ buffer[i] =='\r' || buffer[i] == '\n')
+ (void)putc(buffer[i],stderr);
+ else
+ (void)fprintf(stderr,"\\%03o",buffer[i]);
+ }
+ (void)fseek(src,(long int)pos,SEEK_SET);
+}
+
+void transdata(src,dest)
+FILE *src;
+FILE *dest;
+{
+ unsigned char size,buffer[256];
+
+ do {
+ pos=ftell(src);
+ (void)fread((void *)&size,1,1,src);
+ if (debug)
+ dump(pos,&size,1);
+ if (output)
+ (void)fwrite((void *)&size,1,1,dest);
+ pos=ftell(src);
+ (void)fread((void *)buffer,(size_t)size,1,src);
+ if (debug)
+ dump(pos,buffer,(size_t)size);
+ if (output)
+ (void)fwrite((void *)buffer,(size_t)size,1,dest);
+ } while (!feof(src)&&size>0);
+}
+
+
+/*****************************************************************************/
+
+int giftrans(src,dest)
+FILE *src;
+FILE *dest;
+{
+ unsigned char buffer[3*256],lsd[7],gct[3*256];
+ unsigned int cnt,cols,size,gct_size;
+
+ /* Header */
+ pos=ftell(src);
+ (void)fread((void *)buffer,6,1,src);
+ if (strncmp((char *)buffer,"GIF",3)) {
+ (void)fprintf(stderr,"Not GIF file!\n");
+ return(1);
+ }
+ if (verbose && debug) {
+ buffer[6]='\0';
+ (void)fprintf(stderr,"Header: \"%s\"\n",buffer);
+ }
+ if (debug)
+ dump(pos,buffer,6);
+ if (output) {
+ (void)fwrite((void *)buffer,6,1,dest);
+ }
+
+ /* Logical Screen Descriptor */
+ pos=ftell(src);
+ (void)fread((void *)lsd,7,1,src);
+ if (verbose) {
+ //(void)fprintf(stderr,"Logical Screen Descriptor:\n");
+ (void)fprintf(stderr,"Size : %dx%d pixels\n",readword(lsd), readword(lsd+2));
+ //(void)fprintf(stderr,"Global Color Table Flag: %s\n",readflag(lsd[4]&0x80));
+ (void)fprintf(stderr,"Depth : %d bits\n",(lsd[4]&0x70>>4)+1);
+ //if (lsd[4]&0x80) {
+ // (void)fprintf(stderr,"\tSort Flag: %s\n",readflag(lsd[4]&0x8));
+ // (void)fprintf(stderr,"\tSize of Global Color Table: %d colors\n",2<<(lsd[4]&0x7));
+ // (void)fprintf(stderr,"\tBackground Color Index: %d\n",lsd[5]);
+ //}
+ if (lsd[6])
+ (void)fprintf(stderr,"Pixel Aspect Ratio: %d (Aspect Ratio %f)\n",lsd[6],((double)lsd[6]+15)/64);
+ }
+ if (debug)
+ dump(pos,lsd,7);
+ if (output)
+ (void)fwrite((void *)lsd,7,1,dest);
+
+ /* Global Color Table */
+ if (lsd[4]&0x80) {
+ gct_size=2<<(lsd[4]&0x7);
+ pos=ftell(src);
+ (void)fread((void *)gct,gct_size,3,src);
+ if (output)
+ (void)fwrite((void *)gct,gct_size,3,dest);
+ }
+
+ do {
+ pos=ftell(src);
+ (void)fread((void *)buffer,1,1,src);
+ switch (buffer[0]) {
+ case 0x2c: /* Image Descriptor */
+ if (verbose && debug)
+ (void)fprintf(stderr,"Image Descriptor:\n");
+ (void)fread((void *)(buffer+1),9,1,src);
+ if (debug)
+ dump(pos,buffer,10);
+ if (output)
+ (void)fwrite((void *)buffer,10,1,dest);
+ /* Local Color Table */
+ if (buffer[8]&0x80) {
+ size=2<<(buffer[8]&0x7);
+ pos=ftell(src);
+ (void)fread((void *)buffer,size,3,src);
+ if (verbose && debug) {
+ (void)fprintf(stderr,"Local Color Table:\n");
+ for(cnt=0;cnt<size;cnt++)
+ (void)fprintf(stderr,"\tColor %d: Red %d, Green %d, Blue %d\n",cnt,buffer[3*cnt],buffer[3*cnt+1],buffer[3*cnt+2]);
+ }
+ if (debug)
+ dump(pos,buffer,size*3);
+ if (output)
+ (void)fwrite((void *)buffer,size,3,dest);
+ }
+ /* Table Based Image Data */
+ pos=ftell(src);
+ (void)fread((void *)buffer,1,1,src);
+ if (verbose && debug) {
+ (void)fprintf(stderr,"Table Based Image Data:\n");
+ (void)fprintf(stderr,"\tLZW Minimum Code Size: 0x%02x\n",buffer[0]);
+ }
+ if (debug)
+ dump(pos,buffer,1);
+ if (output)
+ (void)fwrite((void *)buffer,1,1,dest);
+ transdata(src,dest);
+ break;
+ case 0x21: /* Extension */
+ (void)fread((void *)(buffer+1),1,1,src);
+ switch (buffer[1]) {
+ case 0xfe: /* Comment Extension */
+ if (verbose)
+ {
+ (void)fprintf(stderr,"Comment: ");
+ dumpcomment(src);
+ (void)fprintf(stderr,"\n");
+ }
+ if (debug)
+ dump(pos,buffer,2);
+ if (skipcomment)
+ skipdata(src);
+ else {
+ if (output)
+ (void)fwrite((void *)buffer,2,1,dest);
+ transdata(src,dest);
+ }
+ break;
+ case 0x01: /* Plain Text Extension */
+ case 0xf9: /* Graphic Control Extension */
+ case 0xff: /* Application Extension */
+ default:
+ if (verbose && debug)
+ (void)fprintf(stderr,"Extension type: 0x%02x\n",buffer[1]);
+ if (debug)
+ dump(pos,buffer,2);
+ if (output)
+ (void)fwrite((void *)buffer,2,1,dest);
+ transblock(src,dest);
+ transdata(src,dest);
+ break;
+ }
+ break;
+ case 0x3b: /* Trailer (write comment just before here) */
+ if (verbose && debug)
+ (void)fprintf(stderr,"Trailer %o\n", pos);
+ if (debug)
+ dump(pos,buffer,1);
+ if (global_comment && *global_comment && output) {
+ (void)fputs("\041\376",dest);
+ writedata(dest,(unsigned char *)global_comment,strlen(global_comment));
+ }
+ if (output)
+ (void)fwrite((void *)buffer,1,1,dest);
+ break;
+ default:
+ (void)fprintf(stderr,"0x%08lx: Error, unknown block 0x%02x!\n",ftell(src)-1,buffer[0]);
+ if (debug)
+ dump(pos,buffer,1);
+ return(1);
+ }
+ } while (buffer[0]!=0x3b&&!feof(src));
+ return(buffer[0]==0x3b?SUCCESS:FAILURE);
+}
+
+
+/****************************************************************************/
+extern int validate_gif_structure( const char * original_filename )
+{
+FILE * infile;
+int rc;
+
+ if ((infile = fopen(original_filename, READ_BINARY)) == NULL) {
+ fprintf(stderr, "can't open gif image '%s'\n", original_filename);
+ return( 1 );
+ }
+ output = FALSE;
+ verbose = FALSE;
+ debug = FALSE;
+ skipcomment = FALSE;
+ rc = giftrans( infile, NULL );
+ fclose( infile );
+ return( rc );
+}
+
+
+/****************************************************************************/
+extern void * get_gif_info( const char * original_filename )
+{
+FILE * infile;
+
+ if ((infile = fopen(original_filename, READ_BINARY)) == NULL) {
+ fprintf(stderr, "can't open gif image '%s'\n", original_filename);
+ return( NULL );
+ }
+
+ output = FALSE;
+ verbose = TRUE;
+ debug = FALSE;
+ skipcomment = FALSE;
+ giftrans( infile, NULL );
+ return( NULL );
+}
+
+
+/*****************************************************************************
+ Modify the file in place, but be paranoid and safe about it.
+ It's worth a few extra CPU cycles to make sure we never
+ destory an original image:
+
+ 1) Validate the input file.
+ 2) Open a temporary file in same directory (filenameXX).
+ 3) Copy the data, writing a new comment block.
+ 4) Sync everything to disc.
+ 5) Validate the temporary file.
+ 6) Move the temporary file over the original.
+*/
+extern int set_gif_comment( const char * original_filename, char * comment )
+{
+int i;
+int rc;
+char * temp_filename;
+int temp_filename_length;
+struct stat statbuf;
+FILE * infile;
+FILE * outfile;
+
+
+ /*
+ * Make sure we're dealing with a proper input file. Safety first!
+ */
+ if( validate_gif_structure( original_filename ) ) {
+ fprintf(stderr, "error validating gif image '%s'\n", original_filename);
+ return(ERROR_NOT_A_JPEG);
+ }
+
+ /* Get a unique temporary file in the same directory. Hopefully
+ * if things go wrong, this file will still be left for recovery purposes.
+ *
+ * NB: I hate these stupid unsafe string functions in C...
+ */
+ outfile = NULL;
+ temp_filename_length = strlen( original_filename) + 4;
+ temp_filename = (char *)calloc( temp_filename_length, 1 );
+ for( i=0; i<10; i++ ) {
+ snprintf( temp_filename, temp_filename_length, "%s%d", original_filename, i );
+ if( (stat( temp_filename, &statbuf )) && (outfile = fopen(temp_filename, WRITE_BINARY)) ) {
+ //fprintf(stderr, "opened temporary file '%s'\n", temp_filename);
+ break;
+ }
+ }
+ if( !outfile ) {
+ fprintf(stderr, "failed opening temporary file '%s'\n", temp_filename);
+ return(ERROR_TEMP_FILE);
+ }
+
+ if ((infile = fopen(original_filename, READ_BINARY)) == NULL) {
+ fclose( outfile );
+ fprintf(stderr, "can't open gif image '%s'\n", original_filename);
+ return(ERROR_NOT_A_JPEG);
+ }
+ /* Let's do it */
+ output = TRUE;
+ verbose = FALSE;
+ debug = FALSE;
+ skipcomment = TRUE;
+ global_comment = comment;
+ rc = giftrans( infile, outfile );
+ fclose( infile );
+ fsync( fileno( outfile) ); /* Flush it to disk. IMPORTANT!! */
+ /* We really should also flush the directory */
+
+ /* If everything is OK, and if the new file validates, move
+ it over the top of the original */
+ if ( fclose( outfile ) || validate_gif_structure( temp_filename ) ) {
+ fprintf(stderr, "error in temporary file '%s'\n", temp_filename);
+ return(ERROR_TEMP_FILE);
+ }
+ if( rc ) {
+ unlink( temp_filename );
+ return( rc );
+ }
+ if( rename( temp_filename, original_filename ) ) {
+ fprintf(stderr, "error renaming '%s' to '%s'\n", temp_filename, original_filename);
+ return(ERROR_TEMP_FILE);
+ }
+
+ return(0);
+}
+
+
+/*****************************************************************************/
+#ifdef STANDALONE_COMPILE
+int
+main (int argc, char **argv)
+{
+ char * progname;
+ char * filename;
+ char * comment;
+ FILE * fp;
+ int error;
+
+ /* Process command line arguments... */
+ progname = argv[0];
+ if (progname == NULL || progname[0] == 0)
+ progname = "gif-info"; /* in case C library doesn't provide it */
+ if( argc < 2 || argc > 3) {
+ fprintf(stderr, "Usage: %s <filename> [\"<comment>\"]\nReads gif image info or sets comment.\n", progname);
+ return(5);
+ }
+ filename = argv[1];
+ comment = argv[2];
+
+
+ /* Check if file is readable... */
+ if ((fp = fopen(filename, READ_BINARY)) == NULL) {
+ fprintf(stderr, "Error: Can't open file '%s'\n", filename);
+ return(5);
+ }
+ fclose(fp);
+
+ /* Check if we really have a commentable image file here... */
+ if( validate_gif_structure( filename ) ) {
+ fprintf(stderr, "Error: error parsing file '%s' as a gif image\n", filename);
+ return(5);
+ }
+
+ if( argc == 2 ) {
+ get_gif_info( filename );
+ }
+ else {
+ set_gif_comment( filename, comment );
+ }
+
+ return( 0 );
+}
+#endif
+
diff --git a/kfile-plugins/gif/kfile_gif.cpp b/kfile-plugins/gif/kfile_gif.cpp
new file mode 100644
index 00000000..3c29f05f
--- /dev/null
+++ b/kfile-plugins/gif/kfile_gif.cpp
@@ -0,0 +1,122 @@
+/*
+ * This file is part of the KDE project, added by Bryce Nesbitt
+ *
+ * This is a plugin for Konqeror/KFile which processes 'extra' information
+ * contained in a .gif image file (In particular the comment, and resolution).
+ *
+ **************************************
+ *
+ * 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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <stdlib.h>
+#include "kfile_gif.h"
+
+#include <kurl.h>
+#include <kprocess.h>
+#include <klocale.h>
+#include <kgenericfactory.h>
+#include <kdebug.h>
+
+#include <qcstring.h>
+#include <qfile.h>
+#include <qdatetime.h>
+#include <qdict.h>
+#include <qvalidator.h>
+#include <qimage.h>
+
+typedef KGenericFactory<KGifPlugin> GifFactory;
+
+K_EXPORT_COMPONENT_FACTORY(kfile_gif, GifFactory("kfile_gif"))
+
+KGifPlugin::KGifPlugin(QObject *parent, const char *name,
+ const QStringList &args)
+ : KFilePlugin(parent, name, args)
+{
+ kdDebug(7034) << "gif KFileMetaInfo plugin\n";
+
+ KFileMimeTypeInfo* info = addMimeTypeInfo( "image/gif" );
+
+ KFileMimeTypeInfo::GroupInfo* group = 0L;
+
+ group = addGroupInfo(info, "General", i18n("General"));
+
+ KFileMimeTypeInfo::ItemInfo* item;
+
+ item = addItemInfo(group, "Version", i18n("Version"), QVariant::String);
+
+ item = addItemInfo( group, "Dimensions", i18n("Dimensions"), QVariant::Size );
+ setHint( item, KFileMimeTypeInfo::Size );
+ setUnit( item, KFileMimeTypeInfo::Pixels );
+
+ item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int);
+ setUnit(item, KFileMimeTypeInfo::BitsPerPixel);
+
+}
+
+bool KGifPlugin::readInfo( KFileMetaInfo& info, uint what )
+{
+ Q_UNUSED( what );
+
+ kdDebug(7034) << "gif KFileMetaInfo readInfo\n";
+
+ QFile file(info.path());
+
+ if (!file.open(IO_ReadOnly)) {
+ kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl;
+ return false;
+ }
+
+ QDataStream fstream(&file);
+
+ bool isGIF87a = false;
+ char magic[7];
+ Q_UINT16 width = 0;
+ Q_UINT16 height = 0;
+ Q_UINT8 miscInfo = 0;
+
+ fstream.readRawBytes( magic, 6 );
+ magic[6] = 0x00; // null terminate
+
+ // I have special requirements...
+ fstream.setByteOrder( QDataStream::LittleEndian );
+ fstream >> width;
+ fstream >> height;
+ fstream >> miscInfo;
+
+ KFileMetaInfoGroup group = appendGroup(info, "General");
+
+ if ( 0 == strncmp( magic, "GIF89a", 6 ) ) {
+ appendItem( group, "Version", i18n("GIF Version 89a") );
+ } else if ( 0 == strncmp( magic, "GIF87a", 6 ) ) {
+ appendItem( group, "Version", i18n("GIF Version 87a") );
+ isGIF87a = true;
+ } else {
+ appendItem( group, "Version", i18n("Unknown") );
+ }
+
+ appendItem( group, "Dimensions", QSize(width, height) );
+
+ if ( isGIF87a ) {
+ appendItem( group, "BitDepth", ( (miscInfo & 0x07) + 1) );
+ }
+
+ file.close();
+
+ return true;
+}
+
+#include "kfile_gif.moc"
diff --git a/kfile-plugins/gif/kfile_gif.desktop b/kfile-plugins/gif/kfile_gif.desktop
new file mode 100644
index 00000000..8188f60f
--- /dev/null
+++ b/kfile-plugins/gif/kfile_gif.desktop
@@ -0,0 +1,65 @@
+[Desktop Entry]
+Type=Service
+Name=GIF Info
+Name[af]=Gif Inligting
+Name[ar]=معلومات GIF
+Name[br]=Titouroù GIF
+Name[ca]=Informació de GIF
+Name[cs]=GIF info
+Name[cy]=Gwybodaeth GIF
+Name[da]=GIF-info
+Name[de]=GIF-Info
+Name[el]=Πληροφορίες GIF
+Name[eo]=GIF-informo
+Name[es]=Info GIF
+Name[et]=GIF info
+Name[fa]=اطلاعات GIF
+Name[fi]=GIF-tiedot
+Name[fr]=Informations GIF
+Name[ga]=Eolas faoi GIF
+Name[gl]=Inf. Gif
+Name[he]=מידע GIF
+Name[hi]=GIF जानकारी
+Name[hr]=GIF Informacije
+Name[hu]=GIF-jellemzők
+Name[is]=GIF upplýsingar
+Name[it]=Informazioni GIF
+Name[ja]=GIF 情報
+Name[kk]=GIF мәліметі
+Name[km]=ព័ត៌មាន GIF
+Name[lt]=GIF informacija
+Name[ms]=Maklumat GIF
+Name[nds]=GIF-Info
+Name[ne]=GIF सूचना
+Name[nl]=GIF-info
+Name[nn]=GIF-info
+Name[nso]=Tshedimoso ya GIF
+Name[pa]=GIF ਜਾਣਕਾਰੀ
+Name[pl]=Informacja o pliku GIF
+Name[pt]=Informação do GIF
+Name[pt_BR]=Informação sobre GIF
+Name[ro]=Informaţii GIF
+Name[ru]=Информация о GIF
+Name[se]=GIF-dieđut
+Name[sl]=Podatki o GIF
+Name[sr]=GIF информације
+Name[sr@Latn]=GIF informacije
+Name[sv]=Gif-information
+Name[ta]=GIF தகவல்
+Name[tg]=Иттилоот оиди GIF
+Name[th]=ข้อมูลแฟ้ม GIF
+Name[tr]=GIF Bilgisi
+Name[uk]=Інформація по GIF
+Name[uz]=GIF haqida maʼlumot
+Name[uz@cyrillic]=GIF ҳақида маълумот
+Name[ven]=Mafhungo a GIF
+Name[wa]=Informåcion sol imådje GIF
+Name[xh]=Ulwazi lwe GIF
+Name[zh_CN]=GIF 信息
+Name[zh_HK]=GIF 資訊
+Name[zh_TW]=GIF 資訊
+Name[zu]=Ulwazi lwe-GIF
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_gif
+MimeType=image/gif
+PreferredItems=Comment,Resolution
diff --git a/kfile-plugins/gif/kfile_gif.h b/kfile-plugins/gif/kfile_gif.h
new file mode 100644
index 00000000..6f932f37
--- /dev/null
+++ b/kfile-plugins/gif/kfile_gif.h
@@ -0,0 +1,37 @@
+/* This file is part of the KDE project
+ *
+ * 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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __KFILE_GIF_H__
+#define __KFILE_GIF_H__
+
+#include <kfilemetainfo.h>
+#include <kurl.h>
+
+class QStringList;
+
+class KGifPlugin: public KFilePlugin
+{
+ Q_OBJECT
+
+public:
+ KGifPlugin( QObject *parent, const char *name, const QStringList& args );
+
+ virtual bool readInfo ( KFileMetaInfo& info, uint what );
+};
+
+#endif
diff --git a/kfile-plugins/ico/Makefile.am b/kfile-plugins/ico/Makefile.am
new file mode 100644
index 00000000..df3d65ca
--- /dev/null
+++ b/kfile-plugins/ico/Makefile.am
@@ -0,0 +1,22 @@
+## Makefile.am for ico file meta info plugin
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = kfile_ico.h
+
+kde_module_LTLIBRARIES = kfile_ico.la
+
+kfile_ico_la_SOURCES = kfile_ico.cpp
+kfile_ico_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_ico_la_LIBADD = $(LIB_KSYCOCA)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) kfile_ico.cpp -o $(podir)/kfile_ico.pot
+
+services_DATA = kfile_ico.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kfile-plugins/ico/kfile_ico.cpp b/kfile-plugins/ico/kfile_ico.cpp
new file mode 100644
index 00000000..01c5b65e
--- /dev/null
+++ b/kfile-plugins/ico/kfile_ico.cpp
@@ -0,0 +1,148 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Shane Wright <me@shanewright.co.uk>
+ *
+ * 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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <config.h>
+#include "kfile_ico.h"
+
+#include <kprocess.h>
+#include <klocale.h>
+#include <kgenericfactory.h>
+#include <kstringvalidator.h>
+#include <kdebug.h>
+
+#include <qdict.h>
+#include <qvalidator.h>
+#include <qcstring.h>
+#include <qfile.h>
+#include <qdatetime.h>
+
+#if !defined(__osf__)
+#include <inttypes.h>
+#else
+typedef unsigned long uint32_t;
+typedef unsigned short uint16_t;
+typedef unsigned char uint8_t;
+#endif
+
+typedef KGenericFactory<KIcoPlugin> IcoFactory;
+
+K_EXPORT_COMPONENT_FACTORY(kfile_ico, IcoFactory( "kfile_ico" ))
+
+KIcoPlugin::KIcoPlugin(QObject *parent, const char *name,
+ const QStringList &args)
+
+ : KFilePlugin(parent, name, args)
+{
+ KFileMimeTypeInfo* info = addMimeTypeInfo( "image/x-ico" );
+
+ KFileMimeTypeInfo::GroupInfo* group = 0L;
+
+ group = addGroupInfo(info, "Technical", i18n("Technical Details"));
+
+ KFileMimeTypeInfo::ItemInfo* item;
+
+ item = addItemInfo(group, "Number", i18n("Number of Icons"), QVariant::Int);
+
+ item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size);
+ item = addItemInfo(group, "Colors", i18n("Colors"), QVariant::Int);
+
+ item = addItemInfo(group, "DimensionsM", i18n("Dimensions (1st icon)"), QVariant::Size);
+ item = addItemInfo(group, "ColorsM", i18n("Colors (1st icon)"), QVariant::Int);
+}
+
+
+bool KIcoPlugin::readInfo( KFileMetaInfo& info, uint what)
+{
+
+
+ QFile file(info.path());
+
+ if (!file.open(IO_ReadOnly))
+ {
+ kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl;
+ return false;
+ }
+
+ QDataStream dstream(&file);
+
+ // ICO files are little-endian
+ dstream.setByteOrder(QDataStream::LittleEndian);
+
+
+ // read the beginning of the file and make sure it looks ok
+ uint16_t ico_reserved;
+ uint16_t ico_type;
+ uint16_t ico_count;
+
+ dstream >> ico_reserved;
+ dstream >> ico_type;
+ dstream >> ico_count;
+
+ if ((ico_reserved != 0) || (ico_type != 1) || (ico_count < 1))
+ return false;
+
+
+ // now loop through each of the icon entries
+ uint8_t icoe_width;
+ uint8_t icoe_height;
+ uint8_t icoe_colorcount;
+ uint8_t icoe_reserved;
+ uint16_t icoe_planes;
+ uint16_t icoe_bitcount;
+ uint32_t icoe_bytesinres;
+ uint32_t icoe_imageoffset;
+
+ // read the data on the 1st icon
+ dstream >> icoe_width;
+ dstream >> icoe_height;
+ dstream >> icoe_colorcount;
+ dstream >> icoe_reserved;
+ dstream >> icoe_planes;
+ dstream >> icoe_bitcount;
+ dstream >> icoe_bytesinres;
+ dstream >> icoe_imageoffset;
+
+
+ // output the useful bits
+ KFileMetaInfoGroup group = appendGroup(info, "Technical");
+ appendItem(group, "Number", ico_count);
+
+ if (ico_count == 1) {
+ appendItem(group, "Dimensions", QSize(icoe_width, icoe_height));
+
+ if (icoe_colorcount > 0)
+ appendItem(group, "Colors", icoe_colorcount);
+ else if (icoe_bitcount > 0)
+ appendItem(group, "Colors", 2 ^ icoe_bitcount);
+
+ } else {
+
+ appendItem(group, "DimensionsM", QSize(icoe_width, icoe_height));
+
+ if (icoe_colorcount > 0)
+ appendItem(group, "ColorsM", icoe_colorcount);
+ else if (icoe_bitcount > 0)
+ appendItem(group, "ColorsM", 2 ^ icoe_bitcount);
+
+ }
+
+ return true;
+}
+
+#include "kfile_ico.moc"
diff --git a/kfile-plugins/ico/kfile_ico.desktop b/kfile-plugins/ico/kfile_ico.desktop
new file mode 100644
index 00000000..dcd98f50
--- /dev/null
+++ b/kfile-plugins/ico/kfile_ico.desktop
@@ -0,0 +1,65 @@
+[Desktop Entry]
+Type=Service
+Name=ICO Info
+Name[af]=Ico Inligting
+Name[ar]=معلومات ICO
+Name[br]=Titouroù ICO
+Name[ca]=Informació d'ICO
+Name[cs]=ICO info
+Name[cy]=Gwybodaeth ICO
+Name[da]=ICO-info
+Name[de]=ICO-Info
+Name[el]=Πληροφορίες ICO
+Name[eo]=ICO-informo
+Name[es]=Info ICO
+Name[et]=ICO info
+Name[fa]=اطلاعات ICO
+Name[fi]=ICO-tiedot
+Name[fr]=Informations ICO
+Name[gl]=Inf. ICO
+Name[he]=מידע ICO
+Name[hi]=ICO जानकारी
+Name[hr]=ICO informacije
+Name[hu]=ICO-jellemzők
+Name[is]=ICO upplýsingar
+Name[it]=Informazioni ICO
+Name[ja]=ICO 情報
+Name[kk]=ICO мәліметі
+Name[km]=ព័ត៌មាន ICO
+Name[lt]=ICO informacija
+Name[ms]= Maklumat ICO
+Name[nds]=ICO-Info
+Name[ne]=ICO सूचना
+Name[nl]=ICO-info
+Name[nn]=ICO-info
+Name[nso]=Tshedimoso ya ICO
+Name[pa]=ICO ਜਾਣਕਾਰੀ
+Name[pl]=Informacja o pliku ICO
+Name[pt]=Informação do ICO
+Name[pt_BR]=Informação sobre ICO
+Name[ro]=Informaţii ICO
+Name[ru]=Информация об ICO
+Name[se]=ICO-dieđut
+Name[sl]=Podatki o ICO
+Name[sr]=ICO информације
+Name[sr@Latn]=ICO informacije
+Name[sv]=Ico-information
+Name[ta]=ICO தகவல்
+Name[tg]=Иттилоот оиди ICO
+Name[th]=ข้อมูลแฟ้ม ICO
+Name[tr]=ICO Bilgisi
+Name[uk]=Інформація по ICO
+Name[uz]=ICO haqida maʼlumot
+Name[uz@cyrillic]=ICO ҳақида маълумот
+Name[ven]=Mafhungo a ICO
+Name[wa]=Informåcion sol imådjete ICO
+Name[xh]=Ulwazi lwe ICO
+Name[zh_CN]=ICO 信息
+Name[zh_HK]=ICO 資訊
+Name[zh_TW]=ICO 資訊
+Name[zu]=Ulwazi lwe-ICO
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_ico
+MimeType=image/x-ico
+PreferredGroups=Technical
+PreferredItems=Number,Resolution,Colors,ResolutionM,ColorsM
diff --git a/kfile-plugins/ico/kfile_ico.h b/kfile-plugins/ico/kfile_ico.h
new file mode 100644
index 00000000..e06e8094
--- /dev/null
+++ b/kfile-plugins/ico/kfile_ico.h
@@ -0,0 +1,37 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Shane Wright <me@shanewright.co.uk>
+ *
+ * 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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __KFILE_ICO_H__
+#define __KFILE_ICO_H__
+
+#include <kfilemetainfo.h>
+
+class QStringList;
+
+class KIcoPlugin: public KFilePlugin
+{
+ Q_OBJECT
+
+public:
+ KIcoPlugin( QObject *parent, const char *name, const QStringList& args );
+
+ virtual bool readInfo( KFileMetaInfo& info, uint what);
+};
+
+#endif
diff --git a/kfile-plugins/jpeg/Makefile.am b/kfile-plugins/jpeg/Makefile.am
new file mode 100644
index 00000000..fac3b392
--- /dev/null
+++ b/kfile-plugins/jpeg/Makefile.am
@@ -0,0 +1,24 @@
+## Makefile.am for jpeg file meta info plugin
+
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = kfile_jpeg.h exif.h
+
+kde_module_LTLIBRARIES = kfile_jpeg.la
+
+kfile_jpeg_la_SOURCES = kfile_jpeg.cpp exif.cpp kfile_setcomment.cpp
+kfile_jpeg_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_jpeg_la_LIBADD = $(LIB_KIO)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages:
+ $(XGETTEXT) *.cpp -o $(podir)/kfile_jpeg.pot
+
+services_DATA = kfile_jpeg.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kfile-plugins/jpeg/README b/kfile-plugins/jpeg/README
new file mode 100644
index 00000000..6b714426
--- /dev/null
+++ b/kfile-plugins/jpeg/README
@@ -0,0 +1,35 @@
+-------------------------------------------------------------------------------
+Thanks to:
+Matthias Wandel <matt@rim.net>
+jhead (http://www.sentex.net/~mwandel/jhead/)
+
+Groult Richard <rgroult@jalix.org>
+showimg (http://ric.jalix.org/)
+
+Bryce Nesbitt for setcomment
+based on wrjpgcom.c, Copyright (C) 1994-1997, Thomas G. Lane.
+
+Frank Pieczynski <pieczy@knuut.de>
+
+EXIF spec:
+http://www.pima.net/standards/it10/PIMA15740/exif.htm
+http://www.ba.wakwak.com/~tsuruzoh/Computer/Digicams/exif-e.html
+
+-------------------------------------------------------------------------------
+Bugs:
+ 0) Just showing the meta info can cause the file to be rewritten!!!
+ 1) utf-8 paths must be tested and supported.
+ 2) Display of EXIF comments need to be tested.
+ Both Unicode & ASCII need testing.
+
+New features needed:
+ 1) Should switch to a multi-line editor for comments. Support "\n".
+ 2) Should autodetect if the jpeg COM is in utf-8 format.
+ 3) Allow editing the EXIF "Orientation" flag (without rewriting the exif header).
+ 4) Extract and return the EXIF thumbnail, oriented properly, as an alternative
+ to the much slower process of generating a new thumbnail.
+
+Future features:
+ 1) Allow the user to erase or move comment in either the EXIF or jpeg COM.
+ 2) Play or return audio files associated with the exif.
+
diff --git a/kfile-plugins/jpeg/exif.cpp b/kfile-plugins/jpeg/exif.cpp
new file mode 100644
index 00000000..f25e8a78
--- /dev/null
+++ b/kfile-plugins/jpeg/exif.cpp
@@ -0,0 +1,961 @@
+//--------------------------------------------------------------------------
+// Program to pull the information out of various types of EFIF digital
+// camera files and show it in a reasonably consistent way
+//
+// This module parses the very complicated exif structures.
+//
+// Matthias Wandel, Dec 1999 - August 2000
+//--------------------------------------------------------------------------
+
+
+#include "exif.h"
+#include <qwmatrix.h>
+#include <kglobal.h>
+
+
+static unsigned char * LastExifRefd;
+static int ExifSettingsLength;
+static double FocalplaneXRes;
+static double FocalplaneUnits;
+static int MotorolaOrder = 0;
+static int SectionsRead;
+//static int HaveAll;
+
+//--------------------------------------------------------------------------
+// Table of Jpeg encoding process names
+
+#define M_SOF0 0xC0 // Start Of Frame N
+#define M_SOF1 0xC1 // N indicates which compression process
+#define M_SOF2 0xC2 // Only SOF0-SOF2 are now in common use
+#define M_SOF3 0xC3
+#define M_SOF5 0xC5 // NB: codes C4 and CC are NOT SOF markers
+#define M_SOF6 0xC6
+#define M_SOF7 0xC7
+#define M_SOF9 0xC9
+#define M_SOF10 0xCA
+#define M_SOF11 0xCB
+#define M_SOF13 0xCD
+#define M_SOF14 0xCE
+#define M_SOF15 0xCF
+#define M_SOI 0xD8 // Start Of Image (beginning of datastream)
+#define M_EOI 0xD9 // End Of Image (end of datastream)
+#define M_SOS 0xDA // Start Of Scan (begins compressed data)
+#define M_JFIF 0xE0 // Jfif marker
+#define M_EXIF 0xE1 // Exif marker
+#define M_COM 0xFE // COMment
+
+
+TagTable_t ProcessTable[] = {
+ { M_SOF0, "Baseline"},
+ { M_SOF1, "Extended sequential"},
+ { M_SOF2, "Progressive"},
+ { M_SOF3, "Lossless"},
+ { M_SOF5, "Differential sequential"},
+ { M_SOF6, "Differential progressive"},
+ { M_SOF7, "Differential lossless"},
+ { M_SOF9, "Extended sequential, arithmetic coding"},
+ { M_SOF10, "Progressive, arithmetic coding"},
+ { M_SOF11, "Lossless, arithmetic coding"},
+ { M_SOF13, "Differential sequential, arithmetic coding"},
+ { M_SOF14, "Differential progressive, arithmetic coding"},
+ { M_SOF15, "Differential lossless, arithmetic coding"},
+ { 0, "Unknown"}
+};
+
+
+
+//--------------------------------------------------------------------------
+// Describes format descriptor
+static int BytesPerFormat[] = {0,1,1,2,4,8,1,1,2,4,8,4,8};
+#define NUM_FORMATS 12
+
+#define FMT_BYTE 1
+#define FMT_STRING 2
+#define FMT_USHORT 3
+#define FMT_ULONG 4
+#define FMT_URATIONAL 5
+#define FMT_SBYTE 6
+#define FMT_UNDEFINED 7
+#define FMT_SSHORT 8
+#define FMT_SLONG 9
+#define FMT_SRATIONAL 10
+#define FMT_SINGLE 11
+#define FMT_DOUBLE 12
+
+//--------------------------------------------------------------------------
+// Describes tag values
+
+#define TAG_EXIF_OFFSET 0x8769
+#define TAG_INTEROP_OFFSET 0xa005
+
+#define TAG_MAKE 0x010F
+#define TAG_MODEL 0x0110
+#define TAG_ORIENTATION 0x0112
+
+#define TAG_EXPOSURETIME 0x829A
+#define TAG_FNUMBER 0x829D
+
+#define TAG_SHUTTERSPEED 0x9201
+#define TAG_APERTURE 0x9202
+#define TAG_MAXAPERTURE 0x9205
+#define TAG_FOCALLENGTH 0x920A
+
+#define TAG_DATETIME_ORIGINAL 0x9003
+#define TAG_USERCOMMENT 0x9286
+
+#define TAG_SUBJECT_DISTANCE 0x9206
+#define TAG_FLASH 0x9209
+
+#define TAG_FOCALPLANEXRES 0xa20E
+#define TAG_FOCALPLANEUNITS 0xa210
+#define TAG_EXIF_IMAGEWIDTH 0xA002
+#define TAG_EXIF_IMAGELENGTH 0xA003
+
+// the following is added 05-jan-2001 vcs
+#define TAG_EXPOSURE_BIAS 0x9204
+#define TAG_WHITEBALANCE 0x9208
+#define TAG_METERING_MODE 0x9207
+#define TAG_EXPOSURE_PROGRAM 0x8822
+#define TAG_ISO_EQUIVALENT 0x8827
+#define TAG_COMPRESSION_LEVEL 0x9102
+
+#define TAG_THUMBNAIL_OFFSET 0x0201
+#define TAG_THUMBNAIL_LENGTH 0x0202
+
+
+/*static TagTable_t TagTable[] = {
+ { 0x100, "ImageWidth"},
+ { 0x101, "ImageLength"},
+ { 0x102, "BitsPerSample"},
+ { 0x103, "Compression"},
+ { 0x106, "PhotometricInterpretation"},
+ { 0x10A, "FillOrder"},
+ { 0x10D, "DocumentName"},
+ { 0x10E, "ImageDescription"},
+ { 0x10F, "Make"},
+ { 0x110, "Model"},
+ { 0x111, "StripOffsets"},
+ { 0x112, "Orientation"},
+ { 0x115, "SamplesPerPixel"},
+ { 0x116, "RowsPerStrip"},
+ { 0x117, "StripByteCounts"},
+ { 0x11A, "XResolution"},
+ { 0x11B, "YResolution"},
+ { 0x11C, "PlanarConfiguration"},
+ { 0x128, "ResolutionUnit"},
+ { 0x12D, "TransferFunction"},
+ { 0x131, "Software"},
+ { 0x132, "DateTime"},
+ { 0x13B, "Artist"},
+ { 0x13E, "WhitePoint"},
+ { 0x13F, "PrimaryChromaticities"},
+ { 0x156, "TransferRange"},
+ { 0x200, "JPEGProc"},
+ { 0x201, "ThumbnailOffset"},
+ { 0x202, "ThumbnailLength"},
+ { 0x211, "YCbCrCoefficients"},
+ { 0x212, "YCbCrSubSampling"},
+ { 0x213, "YCbCrPositioning"},
+ { 0x214, "ReferenceBlackWhite"},
+ { 0x828D, "CFARepeatPatternDim"},
+ { 0x828E, "CFAPattern"},
+ { 0x828F, "BatteryLevel"},
+ { 0x8298, "Copyright"},
+ { 0x829A, "ExposureTime"},
+ { 0x829D, "FNumber"},
+ { 0x83BB, "IPTC/NAA"},
+ { 0x8769, "ExifOffset"},
+ { 0x8773, "InterColorProfile"},
+ { 0x8822, "ExposureProgram"},
+ { 0x8824, "SpectralSensitivity"},
+ { 0x8825, "GPSInfo"},
+ { 0x8827, "ISOSpeedRatings"},
+ { 0x8828, "OECF"},
+ { 0x9000, "ExifVersion"},
+ { 0x9003, "DateTimeOriginal"},
+ { 0x9004, "DateTimeDigitized"},
+ { 0x9101, "ComponentsConfiguration"},
+ { 0x9102, "CompressedBitsPerPixel"},
+ { 0x9201, "ShutterSpeedValue"},
+ { 0x9202, "ApertureValue"},
+ { 0x9203, "BrightnessValue"},
+ { 0x9204, "ExposureBiasValue"},
+ { 0x9205, "MaxApertureValue"},
+ { 0x9206, "SubjectDistance"},
+ { 0x9207, "MeteringMode"},
+ { 0x9208, "LightSource"},
+ { 0x9209, "Flash"},
+ { 0x920A, "FocalLength"},
+ { 0x927C, "MakerNote"},
+ { 0x9286, "UserComment"},
+ { 0x9290, "SubSecTime"},
+ { 0x9291, "SubSecTimeOriginal"},
+ { 0x9292, "SubSecTimeDigitized"},
+ { 0xA000, "FlashPixVersion"},
+ { 0xA001, "ColorSpace"},
+ { 0xA002, "ExifImageWidth"},
+ { 0xA003, "ExifImageLength"},
+ { 0xA005, "InteroperabilityOffset"},
+ { 0xA20B, "FlashEnergy"}, // 0x920B in TIFF/EP
+ { 0xA20C, "SpatialFrequencyResponse"}, // 0x920C - -
+ { 0xA20E, "FocalPlaneXResolution"}, // 0x920E - -
+ { 0xA20F, "FocalPlaneYResolution"}, // 0x920F - -
+ { 0xA210, "FocalPlaneResolutionUnit"}, // 0x9210 - -
+ { 0xA214, "SubjectLocation"}, // 0x9214 - -
+ { 0xA215, "ExposureIndex"}, // 0x9215 - -
+ { 0xA217, "SensingMethod"}, // 0x9217 - -
+ { 0xA300, "FileSource"},
+ { 0xA301, "SceneType"},
+ { 0, NULL}
+} ;
+*/
+
+
+//--------------------------------------------------------------------------
+// Parse the marker stream until SOS or EOI is seen;
+//--------------------------------------------------------------------------
+int ExifData::ReadJpegSections (QFile & infile, ReadMode_t ReadMode)
+{
+ int a;
+
+ a = infile.getch();
+
+ if (a != 0xff || infile.getch() != M_SOI) {
+ SectionsRead = 0;
+ return false;
+ }
+ for(SectionsRead = 0; SectionsRead < MAX_SECTIONS-1; ){
+ int marker = 0;
+ int got;
+ unsigned int ll,lh;
+ unsigned int itemlen;
+ uchar * Data;
+
+ for (a=0;a<7;a++){
+ marker = infile.getch();
+ if (marker != 0xff) break;
+
+ if (a >= 6){
+
+ kdDebug(7034) << "too many padding bytes\n";
+ return false;
+
+ }
+ }
+
+ if (marker == 0xff){
+ // 0xff is legal padding, but if we get that many, something's wrong.
+ throw FatalError("too many padding bytes!");
+ }
+
+ Sections[SectionsRead].Type = marker;
+
+ // Read the length of the section.
+ lh = (uchar) infile.getch();
+ ll = (uchar) infile.getch();
+
+ itemlen = (lh << 8) | ll;
+
+ if (itemlen < 2) {
+ throw FatalError("invalid marker");
+ }
+
+ Sections[SectionsRead].Size = itemlen;
+
+ Data = (uchar *)malloc(itemlen+1); // Add 1 to allow sticking a 0 at the end.
+ Sections[SectionsRead].Data = Data;
+
+ // Store first two pre-read bytes.
+ Data[0] = (uchar)lh;
+ Data[1] = (uchar)ll;
+
+ got = infile.readBlock((char*)Data+2, itemlen-2); // Read the whole section.
+ if (( unsigned ) got != itemlen-2){
+ throw FatalError("reading from file");
+ }
+ SectionsRead++;
+
+ switch(marker){
+
+ case M_SOS: // stop before hitting compressed data
+ // If reading entire image is requested, read the rest of the data.
+ if (ReadMode & READ_IMAGE){
+ unsigned long size;
+
+ size = kMax( 0ul, infile.size()-infile.at() );
+ Data = (uchar *)malloc(size);
+ if (Data == NULL){
+ throw FatalError("could not allocate data for entire image");
+ }
+
+ got = infile.readBlock((char*)Data, size);
+ if (( unsigned ) got != size){
+ throw FatalError("could not read the rest of the image");
+ }
+
+ Sections[SectionsRead].Data = Data;
+ Sections[SectionsRead].Size = size;
+ Sections[SectionsRead].Type = PSEUDO_IMAGE_MARKER;
+ SectionsRead ++;
+ //HaveAll = 1;
+ }
+ return true;
+
+ case M_EOI: // in case it's a tables-only JPEG stream
+ kdDebug(7034) << "No image in jpeg!\n";
+ return false;
+
+ case M_COM: // Comment section
+ // pieczy 2002-02-12
+ // now the User comment goes to UserComment
+ // so we can store a Comment section also in READ_EXIF mode
+ process_COM(Data, itemlen);
+ break;
+
+ case M_JFIF:
+ // Regular jpegs always have this tag, exif images have the exif
+ // marker instead, althogh ACDsee will write images with both markers.
+ // this program will re-create this marker on absence of exif marker.
+ // hence no need to keep the copy from the file.
+ free(Sections[--SectionsRead].Data);
+ break;
+
+ case M_EXIF:
+ // Seen files from some 'U-lead' software with Vivitar scanner
+ // that uses marker 31 for non exif stuff. Thus make sure
+ // it says 'Exif' in the section before treating it as exif.
+ if ((ReadMode & READ_EXIF) && memcmp(Data+2, "Exif", 4) == 0){
+ process_EXIF((uchar *)Data, itemlen); // FIXME: This call
+ // requires Data to be array of at least 8 bytes. Code
+ // above only checks for itemlen < 2.
+ }else{
+ // Discard this section.
+ free(Sections[--SectionsRead].Data);
+ }
+ break;
+
+ case M_SOF0:
+ case M_SOF1:
+ case M_SOF2:
+ case M_SOF3:
+ case M_SOF5:
+ case M_SOF6:
+ case M_SOF7:
+ case M_SOF9:
+ case M_SOF10:
+ case M_SOF11:
+ case M_SOF13:
+ case M_SOF14:
+ case M_SOF15:
+ process_SOFn(Data, marker); //FIXME: This call requires Data to
+ // be array of at least 8 bytes. Code above only checks for
+ // itemlen < 2.
+ break;
+ default:
+ break;
+ }
+ }
+ return true;
+}
+
+
+//--------------------------------------------------------------------------
+// Discard read data.
+//--------------------------------------------------------------------------
+void ExifData::DiscardData(void)
+{
+ for (int a=0; a < SectionsRead; a++)
+ free(Sections[a].Data);
+ SectionsRead = 0;
+}
+
+//--------------------------------------------------------------------------
+// Convert a 16 bit unsigned value from file's native byte order
+//--------------------------------------------------------------------------
+int ExifData::Get16u(void * Short)
+{
+ if (MotorolaOrder){
+ return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1];
+ }else{
+ return (((uchar *)Short)[1] << 8) | ((uchar *)Short)[0];
+ }
+}
+
+//--------------------------------------------------------------------------
+// Convert a 32 bit signed value from file's native byte order
+//--------------------------------------------------------------------------
+int ExifData::Get32s(void * Long)
+{
+ if (MotorolaOrder){
+ return ((( char *)Long)[0] << 24) | (((uchar *)Long)[1] << 16)
+ | (((uchar *)Long)[2] << 8 ) | (((uchar *)Long)[3] << 0 );
+ }else{
+ return ((( char *)Long)[3] << 24) | (((uchar *)Long)[2] << 16)
+ | (((uchar *)Long)[1] << 8 ) | (((uchar *)Long)[0] << 0 );
+ }
+}
+
+//--------------------------------------------------------------------------
+// Convert a 32 bit unsigned value from file's native byte order
+//--------------------------------------------------------------------------
+unsigned ExifData::Get32u(void * Long)
+{
+ return (unsigned)Get32s(Long) & 0xffffffff;
+}
+
+//--------------------------------------------------------------------------
+// Evaluate number, be it int, rational, or float from directory.
+//--------------------------------------------------------------------------
+double ExifData::ConvertAnyFormat(void * ValuePtr, int Format)
+{
+ double Value;
+ Value = 0;
+
+ switch(Format){
+ case FMT_SBYTE: Value = *(signed char *)ValuePtr; break;
+ case FMT_BYTE: Value = *(uchar *)ValuePtr; break;
+
+ case FMT_USHORT: Value = Get16u(ValuePtr); break;
+
+ case FMT_ULONG: Value = Get32u(ValuePtr); break;
+
+ case FMT_URATIONAL:
+ case FMT_SRATIONAL:
+ {
+ int Num,Den;
+ Num = Get32s(ValuePtr);
+ Den = Get32s(4+(char *)ValuePtr);
+ if (Den == 0){
+ Value = 0;
+ }else{
+ Value = (double)Num/Den;
+ }
+ break;
+ }
+
+ case FMT_SSHORT: Value = (signed short)Get16u(ValuePtr); break;
+ case FMT_SLONG: Value = Get32s(ValuePtr); break;
+
+ // Not sure if this is correct (never seen float used in Exif format)
+ case FMT_SINGLE: Value = (double)*(float *)ValuePtr; break;
+ case FMT_DOUBLE: Value = *(double *)ValuePtr; break;
+ }
+ return Value;
+}
+
+//--------------------------------------------------------------------------
+// Process one of the nested EXIF directories.
+//--------------------------------------------------------------------------
+void ExifData::ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength, unsigned NestingLevel)
+{
+ int de;
+ int a;
+ int NumDirEntries;
+ unsigned ThumbnailOffset = 0;
+ unsigned ThumbnailSize = 0;
+
+ if ( NestingLevel > 4)
+ throw FatalError("Maximum directory nesting exceeded (corrupt exif header)");
+
+ NumDirEntries = Get16u(DirStart);
+ #define DIR_ENTRY_ADDR(Start, Entry) (Start+2+12*(Entry))
+
+ {
+ unsigned char * DirEnd;
+ DirEnd = DIR_ENTRY_ADDR(DirStart, NumDirEntries);
+ if (DirEnd+4 > (OffsetBase+ExifLength)){
+ if (DirEnd+2 == OffsetBase+ExifLength || DirEnd == OffsetBase+ExifLength){
+ // Version 1.3 of jhead would truncate a bit too much.
+ // This also caught later on as well.
+ }else{
+ // Note: Files that had thumbnails trimmed with jhead 1.3 or earlier
+ // might trigger this.
+ throw FatalError("Illegally sized directory");
+ }
+ }
+ if (DirEnd < LastExifRefd) LastExifRefd = DirEnd;
+ }
+
+ for (de=0;de<NumDirEntries;de++){
+ int Tag, Format, Components;
+ unsigned char * ValuePtr;
+ unsigned ByteCount;
+ char * DirEntry;
+ DirEntry = (char *)DIR_ENTRY_ADDR(DirStart, de);
+
+ Tag = Get16u(DirEntry);
+ Format = Get16u(DirEntry+2);
+ Components = Get32u(DirEntry+4);
+
+ if ((Format-1) >= NUM_FORMATS) {
+ // (-1) catches illegal zero case as unsigned underflows to positive large.
+ throw FatalError("Illegal format code in EXIF dir");
+ }
+
+ if ((unsigned)Components > 0x10000) {
+ throw FatalError("Illegal number of components for tag");
+ continue;
+ }
+
+ ByteCount = Components * BytesPerFormat[Format];
+
+ if (ByteCount > 4){
+ unsigned OffsetVal;
+ OffsetVal = Get32u(DirEntry+8);
+ // If its bigger than 4 bytes, the dir entry contains an offset.
+ if (OffsetVal+ByteCount > ExifLength){
+ // Bogus pointer offset and / or bytecount value
+ //printf("Offset %d bytes %d ExifLen %d\n",OffsetVal, ByteCount, ExifLength);
+
+ throw FatalError("Illegal pointer offset value in EXIF");
+ }
+ ValuePtr = OffsetBase+OffsetVal;
+ }else{
+ // 4 bytes or less and value is in the dir entry itself
+ ValuePtr = (unsigned char *)DirEntry+8;
+ }
+
+ if (LastExifRefd < ValuePtr+ByteCount){
+ // Keep track of last byte in the exif header that was actually referenced.
+ // That way, we know where the discardable thumbnail data begins.
+ LastExifRefd = ValuePtr+ByteCount;
+ }
+
+ // Extract useful components of tag
+ switch(Tag){
+
+ case TAG_MAKE:
+ ExifData::CameraMake = QString::fromLatin1((const char*)ValuePtr, 31);
+ break;
+
+ case TAG_MODEL:
+ ExifData::CameraModel = QString::fromLatin1((const char*)ValuePtr, 39);
+ break;
+
+ case TAG_ORIENTATION:
+ Orientation = (int)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_DATETIME_ORIGINAL:
+ DateTime = QString::fromLatin1((const char*)ValuePtr, 19);
+ break;
+
+ case TAG_USERCOMMENT:
+ // Olympus has this padded with trailing spaces. Remove these first.
+ for (a=ByteCount;;){
+ a--;
+ if ((ValuePtr)[a] == ' '){
+ (ValuePtr)[a] = '\0';
+ }else{
+ break;
+ }
+ if (a == 0) break;
+ }
+
+ // Copy the comment
+ if (memcmp(ValuePtr, "ASCII",5) == 0){
+ for (a=5;a<10;a++){
+ int c;
+ c = (ValuePtr)[a];
+ if (c != '\0' && c != ' '){
+ UserComment = QString::fromLatin1((const char*)(a+ValuePtr), 199);
+ break;
+ }
+ }
+ }else{
+ UserComment = QString::fromLatin1((const char*)ValuePtr, 199);
+ }
+ break;
+
+ case TAG_FNUMBER:
+ // Simplest way of expressing aperture, so I trust it the most.
+ // (overwrite previously computd value if there is one)
+ ExifData::ApertureFNumber = (float)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_APERTURE:
+ case TAG_MAXAPERTURE:
+ // More relevant info always comes earlier, so only use this field if we don't
+ // have appropriate aperture information yet.
+ if (ExifData::ApertureFNumber == 0){
+ ExifData::ApertureFNumber
+ = (float)exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0)*0.5);
+ }
+ break;
+
+ case TAG_FOCALLENGTH:
+ // Nice digital cameras actually save the focal length as a function
+ // of how far they are zoomed in.
+ ExifData::FocalLength = (float)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_SUBJECT_DISTANCE:
+ // Inidcates the distacne the autofocus camera is focused to.
+ // Tends to be less accurate as distance increases.
+ ExifData::Distance = (float)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_EXPOSURETIME:
+ // Simplest way of expressing exposure time, so I trust it most.
+ // (overwrite previously computd value if there is one)
+ ExifData::ExposureTime = (float)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_SHUTTERSPEED:
+ // More complicated way of expressing exposure time, so only use
+ // this value if we don't already have it from somewhere else.
+ if (ExifData::ExposureTime == 0){
+ ExifData::ExposureTime
+ = (float)(1/exp(ConvertAnyFormat(ValuePtr, Format)*log(2.0)));
+ }
+ break;
+
+ case TAG_FLASH:
+ ExifData::FlashUsed = (int)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_EXIF_IMAGELENGTH:
+ ExifImageLength = (int)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_EXIF_IMAGEWIDTH:
+ ExifImageWidth = (int)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_FOCALPLANEXRES:
+ FocalplaneXRes = ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_FOCALPLANEUNITS:
+ switch((int)ConvertAnyFormat(ValuePtr, Format)){
+ case 1: FocalplaneUnits = 25.4; break; // inch
+ case 2:
+ // According to the information I was using, 2 means meters.
+ // But looking at the Cannon powershot's files, inches is the only
+ // sensible value.
+ FocalplaneUnits = 25.4;
+ break;
+
+ case 3: FocalplaneUnits = 10; break; // centimeter
+ case 4: FocalplaneUnits = 1; break; // milimeter
+ case 5: FocalplaneUnits = .001; break; // micrometer
+ }
+ break;
+
+ // Remaining cases contributed by: Volker C. Schoech (schoech@gmx.de)
+
+ case TAG_EXPOSURE_BIAS:
+ ExifData::ExposureBias = (float)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_WHITEBALANCE:
+ ExifData::Whitebalance = (int)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_METERING_MODE:
+ ExifData::MeteringMode = (int)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_EXPOSURE_PROGRAM:
+ ExifData::ExposureProgram = (int)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_ISO_EQUIVALENT:
+ ExifData::ISOequivalent = (int)ConvertAnyFormat(ValuePtr, Format);
+ if ( ExifData::ISOequivalent < 50 ) ExifData::ISOequivalent *= 200;
+ break;
+
+ case TAG_COMPRESSION_LEVEL:
+ ExifData::CompressionLevel = (int)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_THUMBNAIL_OFFSET:
+ ThumbnailOffset = (unsigned)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ case TAG_THUMBNAIL_LENGTH:
+ ThumbnailSize = (unsigned)ConvertAnyFormat(ValuePtr, Format);
+ break;
+
+ }
+
+ if (Tag == TAG_EXIF_OFFSET || Tag == TAG_INTEROP_OFFSET){
+ unsigned char * SubdirStart;
+ SubdirStart = OffsetBase + Get32u(ValuePtr);
+ if (SubdirStart <= OffsetBase || SubdirStart >= OffsetBase+ExifLength){
+ throw FatalError("Illegal subdirectory link");
+ }
+ ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1);
+ continue;
+ }
+ }
+
+ {
+ // In addition to linking to subdirectories via exif tags,
+ // there's also a potential link to another directory at the end of each
+ // directory. this has got to be the result of a comitee!
+ unsigned char * SubdirStart;
+ unsigned Offset;
+
+ if (DIR_ENTRY_ADDR(DirStart, NumDirEntries) + 4 <= OffsetBase+ExifLength){
+ Offset = Get32u(DIR_ENTRY_ADDR(DirStart, NumDirEntries));
+ // There is at least one jpeg from an HP camera having an Offset of almost MAXUINT.
+ // Adding OffsetBase to it produces an overflow, so compare with ExifLength here.
+ // See http://bugs.kde.org/show_bug.cgi?id=54542
+ if (Offset && Offset < ExifLength){
+ SubdirStart = OffsetBase + Offset;
+ if (SubdirStart > OffsetBase+ExifLength){
+ if (SubdirStart < OffsetBase+ExifLength+20){
+ // Jhead 1.3 or earlier would crop the whole directory!
+ // As Jhead produces this form of format incorrectness,
+ // I'll just let it pass silently
+ kdDebug(7034) << "Thumbnail removed with Jhead 1.3 or earlier\n";
+ }else{
+ throw FatalError("Illegal subdirectory link 2");
+ }
+ }else{
+ if (SubdirStart <= OffsetBase+ExifLength){
+ ProcessExifDir(SubdirStart, OffsetBase, ExifLength, NestingLevel+1);
+ }
+ }
+ }
+ }else{
+ // The exif header ends before the last next directory pointer.
+ }
+ }
+
+ if (ThumbnailSize && ThumbnailOffset){
+ if (ThumbnailSize + ThumbnailOffset < ExifLength){
+ // The thumbnail pointer appears to be valid. Store it.
+ Thumbnail.loadFromData(OffsetBase + ThumbnailOffset, ThumbnailSize, "JPEG");
+ }
+ }
+}
+
+//--------------------------------------------------------------------------
+// Process a COM marker. We want to leave the bytes unchanged. The
+// progam that displays this text may decide to remove blanks, convert
+// newlines, or otherwise modify the text. In particular we want to be
+// safe for passing utf-8 text.
+//--------------------------------------------------------------------------
+void ExifData::process_COM (const uchar * Data, int length)
+{
+ Comment = QString::fromUtf8((char *)Data+2, (length-2));
+}
+
+
+//--------------------------------------------------------------------------
+// Process a SOFn marker. This is useful for the image dimensions
+//--------------------------------------------------------------------------
+void ExifData::process_SOFn (const uchar * Data, int marker)
+{
+ int data_precision, num_components;
+
+ data_precision = Data[2];
+ ExifData::Height = Get16m(Data+3);
+ ExifData::Width = Get16m(Data+5);
+ num_components = Data[7];
+
+ if (num_components == 3){
+ ExifData::IsColor = 1;
+ }else{
+ ExifData::IsColor = 0;
+ }
+
+ ExifData::Process = marker;
+
+}
+
+//--------------------------------------------------------------------------
+// Get 16 bits motorola order (always) for jpeg header stuff.
+//--------------------------------------------------------------------------
+int ExifData::Get16m(const void * Short)
+{
+ return (((uchar *)Short)[0] << 8) | ((uchar *)Short)[1];
+}
+
+
+//--------------------------------------------------------------------------
+// Process a EXIF marker
+// Describes all the drivel that most digital cameras include...
+//--------------------------------------------------------------------------
+void ExifData::process_EXIF(unsigned char * CharBuf, unsigned int length)
+{
+ ExifData::FlashUsed = 0; // If it s from a digicam, and it used flash, it says so.
+
+ FocalplaneXRes = 0;
+ FocalplaneUnits = 0;
+ ExifImageWidth = 0;
+ ExifImageLength = 0;
+
+ { // Check the EXIF header component
+ static const uchar ExifHeader[] = "Exif\0\0";
+ if (memcmp(CharBuf+2, ExifHeader,6)){
+ throw FatalError("Incorrect Exif header");
+ }
+ }
+
+ if (memcmp(CharBuf+8,"II",2) == 0){
+ // printf("Exif section in Intel order\n");
+ MotorolaOrder = 0;
+ }else{
+ if (memcmp(CharBuf+8,"MM",2) == 0){
+ // printf("Exif section in Motorola order\n");
+ MotorolaOrder = 1;
+ }else{
+ throw FatalError("Invalid Exif alignment marker.");
+ }
+ }
+
+ // Check the next two values for correctness.
+ if (Get16u(CharBuf+10) != 0x2a){
+ throw FatalError("Invalid Exif start (1)");
+ }
+
+ long IFDoffset = Get32u(CharBuf+12);
+
+ LastExifRefd = CharBuf;
+
+ // First directory starts 16 bytes in. Offsets start at 8 bytes in.
+ ProcessExifDir(&CharBuf[8+IFDoffset], CharBuf+8, length-6, 0);
+
+ // This is how far the interesting (non thumbnail) part of the exif went.
+ ExifSettingsLength = LastExifRefd - CharBuf;
+
+ // Compute the CCD width, in milimeters.
+ if (FocalplaneXRes != 0){
+ kdDebug(7034) << "ExifImageWidth " << ExifImageWidth << " FocalplaneUnits " << FocalplaneUnits << " FocalplaneXRes " << FocalplaneXRes << endl;
+ ExifData::CCDWidth = (float)(ExifImageWidth * FocalplaneUnits / FocalplaneXRes);
+ }
+}
+
+//--------------------------------------------------------------------------
+// Convert exif time to Unix time structure
+//--------------------------------------------------------------------------
+int ExifData::Exif2tm(struct tm * timeptr, char * ExifTime)
+{
+ int a;
+
+ timeptr->tm_wday = -1;
+
+ // Check for format: YYYY:MM:DD HH:MM:SS format.
+ a = sscanf(ExifTime, "%d:%d:%d %d:%d:%d",
+ &timeptr->tm_year, &timeptr->tm_mon, &timeptr->tm_mday,
+ &timeptr->tm_hour, &timeptr->tm_min, &timeptr->tm_sec);
+
+ if (a == 6){
+ timeptr->tm_isdst = -1;
+ timeptr->tm_mon -= 1; // Adjust for unix zero-based months
+ timeptr->tm_year -= 1900; // Adjust for year starting at 1900
+ return true; // worked.
+ }
+
+ return false; // Wasn't in Exif date format.
+}
+
+//--------------------------------------------------------------------------
+// Contructor for initialising
+//--------------------------------------------------------------------------
+ExifData::ExifData()
+{
+ ExifData::Whitebalance = -1;
+ ExifData::MeteringMode = -1;
+ ExifData::FlashUsed = 0;
+ Orientation = 0;
+ Height = 0;
+ Width = 0;
+ IsColor = 0;
+ Process = 0;
+ FocalLength = 0;
+ ExposureTime = 0;
+ ApertureFNumber = 0;
+ Distance = 0;
+ CCDWidth = 0;
+ ExposureBias = 0;
+ ExposureProgram = 0;
+ ISOequivalent = 0;
+ CompressionLevel = 0;
+}
+
+//--------------------------------------------------------------------------
+// process a EXIF jpeg file
+//--------------------------------------------------------------------------
+bool ExifData::scan(const QString & path)
+{
+ int ret;
+
+ QFile f(path);
+ if ( !f.open(IO_ReadOnly) )
+ return false;
+
+ try {
+ // Scan the JPEG headers.
+ ret = ReadJpegSections(f, READ_EXIF);
+ }
+ catch (FatalError& e) {
+ e.debug_print();
+ f.close();
+ return false;
+ }
+
+ if (ret == false){
+ kdDebug(7034) << "Not JPEG file!\n";
+ DiscardData();
+ f.close();
+ return false;
+ }
+ f.close();
+ DiscardData();
+
+ //now make the strings clean,
+ // for exmaple my Casio is a "QV-4000 "
+ CameraMake = CameraMake.stripWhiteSpace();
+ CameraModel = CameraModel.stripWhiteSpace();
+ UserComment = UserComment.stripWhiteSpace();
+ Comment = Comment.stripWhiteSpace();
+ return true;
+}
+
+//--------------------------------------------------------------------------
+// Does the embedded thumbnail match the jpeg image?
+//--------------------------------------------------------------------------
+#ifndef JPEG_TOL
+#define JPEG_TOL 0.02
+#endif
+bool ExifData::isThumbnailSane() {
+ if (Thumbnail.isNull()) return false;
+
+ // check whether thumbnail dimensions match the image
+ // not foolproof, but catches some altered images (jpegtran -rotate)
+ if (ExifImageLength != 0 && ExifImageLength != Height) return false;
+ if (ExifImageWidth != 0 && ExifImageWidth != Width) return false;
+ if (Thumbnail.width() == 0 || Thumbnail.height() == 0) return false;
+ if (Height == 0 || Width == 0) return false;
+ double d = (double)Height/Width*Thumbnail.width()/Thumbnail.height();
+ return (1-JPEG_TOL < d) && (d < 1+JPEG_TOL);
+}
+
+
+//--------------------------------------------------------------------------
+// return a thumbnail that respects the orientation flag
+// only if it seems sane
+//--------------------------------------------------------------------------
+QImage ExifData::getThumbnail() {
+ if (!isThumbnailSane()) return NULL;
+ if (!Orientation || Orientation == 1) return Thumbnail;
+
+ // now fix orientation
+ QWMatrix M;
+ QWMatrix flip= QWMatrix(-1,0,0,1,0,0);
+ switch (Orientation) { // notice intentional fallthroughs
+ case 2: M = flip; break;
+ case 4: M = flip;
+ case 3: M.rotate(180); break;
+ case 5: M = flip;
+ case 6: M.rotate(90); break;
+ case 7: M = flip;
+ case 8: M.rotate(270); break;
+ default: break; // should never happen
+ }
+ return Thumbnail.xForm(M);
+}
diff --git a/kfile-plugins/jpeg/exif.h b/kfile-plugins/jpeg/exif.h
new file mode 100644
index 00000000..2b4e5606
--- /dev/null
+++ b/kfile-plugins/jpeg/exif.h
@@ -0,0 +1,127 @@
+#ifndef __EXIF_H__
+#define __EXIF_H__
+
+/**
+ exif.h
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+
+#include "qstring.h"
+#include "qfile.h"
+#include "qimage.h"
+#include <kdebug.h>
+
+typedef enum {
+ READ_EXIF = 1,
+ READ_IMAGE = 2,
+ READ_ALL = 3
+}ReadMode_t;
+
+//--------------------------------------------------------------------------
+// This structure is used to store jpeg file sections in memory.
+typedef struct {
+ uchar * Data;
+ int Type;
+ unsigned Size;
+}Section_t;
+
+typedef unsigned char uchar;
+
+typedef struct {
+ unsigned short Tag;
+ const char*const Desc;
+}TagTable_t;
+
+#define MAX_SECTIONS 20
+#define PSEUDO_IMAGE_MARKER 0x123; // Extra value.
+
+class ExifData {
+ Section_t Sections[MAX_SECTIONS];
+
+ QString CameraMake;
+ QString CameraModel;
+ QString DateTime;
+ int Orientation;
+ int Height, Width;
+ int ExifImageLength, ExifImageWidth;
+ int IsColor;
+ int Process;
+ int FlashUsed;
+ float FocalLength;
+ float ExposureTime;
+ float ApertureFNumber;
+ float Distance;
+ int Whitebalance;
+ int MeteringMode;
+ float CCDWidth;
+ float ExposureBias;
+ int ExposureProgram;
+ int ISOequivalent;
+ int CompressionLevel;
+ QString UserComment;
+ QString Comment;
+ QImage Thumbnail;
+
+ int ReadJpegSections (QFile & infile, ReadMode_t ReadMode);
+ void DiscardData(void);
+ int Get16u(void * Short);
+ int Get32s(void * Long);
+ unsigned Get32u(void * Long);
+ double ConvertAnyFormat(void * ValuePtr, int Format);
+ void ProcessExifDir(unsigned char * DirStart, unsigned char * OffsetBase, unsigned ExifLength,
+ unsigned NestingLevel);
+ void process_COM (const uchar * Data, int length);
+ void process_SOFn (const uchar * Data, int marker);
+ int Get16m(const void * Short);
+ void process_EXIF(unsigned char * CharBuf, unsigned int length);
+ int Exif2tm(struct tm * timeptr, char * ExifTime);
+
+public:
+ ExifData();
+ bool scan(const QString &);
+ QString getCameraMake() { return CameraMake; }
+ QString getCameraModel() { return CameraModel; }
+ QString getDateTime() { return DateTime; }
+ int getOrientation() { return Orientation; }
+ int getHeight() { return Height; }
+ int getWidth() { return Width; }
+ int getIsColor() { return IsColor; }
+ int getProcess() { return Process; }
+ int getFlashUsed() { return FlashUsed; }
+ float getFocalLength() { return FocalLength; }
+ float getExposureTime() { return ExposureTime; }
+ float getApertureFNumber() { return ApertureFNumber; }
+ float getDistance() { return Distance; }
+ int getWhitebalance() { return Whitebalance; }
+ int getMeteringMode() { return MeteringMode; }
+ float getCCDWidth() { return CCDWidth; }
+ float getExposureBias() { return ExposureBias; }
+ int getExposureProgram() { return ExposureProgram; }
+ int getISOequivalent() { return ISOequivalent; }
+ int getCompressionLevel() { return CompressionLevel; }
+ QString getUserComment() { return UserComment; }
+ QString getComment() { return Comment; }
+ QImage getThumbnail();
+ bool isThumbnailSane();
+ bool isNullThumbnail() { return !isThumbnailSane(); }
+};
+
+class FatalError {
+ const char* ex;
+public:
+ FatalError(const char* s) { ex = s; }
+ void debug_print() const { kdDebug(7034) << "exception: " << ex << endl; }
+};
+
+extern TagTable_t ProcessTable[];
+
+//--------------------------------------------------------------------------
+// Define comment writing code, impelemented in setcomment.c
+extern int safe_copy_and_modify( const char * original_filename, const char * comment );
+
+#endif
+
diff --git a/kfile-plugins/jpeg/kfile_jpeg.cpp b/kfile-plugins/jpeg/kfile_jpeg.cpp
new file mode 100644
index 00000000..d302cf65
--- /dev/null
+++ b/kfile-plugins/jpeg/kfile_jpeg.cpp
@@ -0,0 +1,531 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Frank Pieczynski <pieczy@knuut.de>,
+ * 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+ * based on the jhead tool of Matthias Wandel (see below)
+ *
+ * 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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#include <stdlib.h>
+#include "kfile_jpeg.h"
+
+#include <kurl.h>
+#include <kprocess.h>
+#include <klocale.h>
+#include <kgenericfactory.h>
+#include <kdebug.h>
+
+#include <qcstring.h>
+#include <qfile.h>
+#include <qdatetime.h>
+#include <qdict.h>
+#include <qvalidator.h>
+#include <qimage.h>
+
+#include "exif.h"
+
+#define EXIFGROUP "Jpeg EXIF Data"
+
+typedef KGenericFactory<KJpegPlugin> JpegFactory;
+
+K_EXPORT_COMPONENT_FACTORY(kfile_jpeg, JpegFactory("kfile_jpeg"))
+
+KJpegPlugin::KJpegPlugin(QObject *parent, const char *name,
+ const QStringList &args )
+ : KFilePlugin(parent, name, args)
+{
+ kdDebug(7034) << "jpeg plugin\n";
+
+ //
+ // define all possible meta info items
+ //
+ KFileMimeTypeInfo *info = addMimeTypeInfo("image/jpeg");
+ KFileMimeTypeInfo::GroupInfo *exifGroup = addGroupInfo( info, EXIFGROUP,
+ i18n("JPEG Exif") );
+ KFileMimeTypeInfo::ItemInfo* item;
+
+ item = addItemInfo( exifGroup, "Comment", i18n("Comment"), QVariant::String);
+ setAttributes( item,
+ KFileMimeTypeInfo::Modifiable |
+ KFileMimeTypeInfo::Addable |
+ KFileMimeTypeInfo::MultiLine );
+
+ item = addItemInfo( exifGroup, "Manufacturer", i18n("Camera Manufacturer"),
+ QVariant::String );
+
+ item = addItemInfo( exifGroup, "Model", i18n("Camera Model"),
+ QVariant::String );
+
+ item = addItemInfo( exifGroup, "Date/time", i18n("Date/Time"),
+ QVariant::DateTime );
+
+ item = addItemInfo( exifGroup, "CreationDate", i18n("Creation Date"),
+ QVariant::Date );
+
+ item = addItemInfo( exifGroup, "CreationTime", i18n("Creation Time"),
+ QVariant::Time );
+
+ item = addItemInfo( exifGroup, "Dimensions", i18n("Dimensions"),
+ QVariant::Size );
+ setHint( item, KFileMimeTypeInfo::Size );
+ setUnit( item, KFileMimeTypeInfo::Pixels );
+
+ item = addItemInfo( exifGroup, "Orientation", i18n("Orientation"),
+ QVariant::Int );
+
+ item = addItemInfo( exifGroup, "ColorMode", i18n("Color Mode"),
+ QVariant::String );
+
+ item = addItemInfo( exifGroup, "Flash used", i18n("Flash Used"),
+ QVariant::String );
+ item = addItemInfo( exifGroup, "Focal length", i18n("Focal Length"),
+ QVariant::String );
+ setUnit( item, KFileMimeTypeInfo::Millimeters );
+
+ item = addItemInfo( exifGroup, "35mm equivalent", i18n("35mm Equivalent"),
+ QVariant::Int );
+ setUnit( item, KFileMimeTypeInfo::Millimeters );
+
+ item = addItemInfo( exifGroup, "CCD width", i18n("CCD Width"),
+ QVariant::String );
+ setUnit( item, KFileMimeTypeInfo::Millimeters );
+
+ item = addItemInfo( exifGroup, "Exposure time", i18n("Exposure Time"),
+ QVariant::String );
+ setHint( item, KFileMimeTypeInfo::Seconds );
+
+ item = addItemInfo( exifGroup, "Aperture", i18n("Aperture"),
+ QVariant::String );
+
+ item = addItemInfo( exifGroup, "Focus dist.", i18n("Focus Dist."),
+ QVariant::String );
+
+ item = addItemInfo( exifGroup, "Exposure bias", i18n("Exposure Bias"),
+ QVariant::String );
+
+ item = addItemInfo( exifGroup, "Whitebalance", i18n("Whitebalance"),
+ QVariant::String );
+
+ item = addItemInfo( exifGroup, "Metering mode", i18n("Metering Mode"),
+ QVariant::String );
+
+ item = addItemInfo( exifGroup, "Exposure", i18n("Exposure"),
+ QVariant::String );
+
+ item = addItemInfo( exifGroup, "ISO equiv.", i18n("ISO Equiv."),
+ QVariant::String );
+
+ item = addItemInfo( exifGroup, "JPEG quality", i18n("JPEG Quality"),
+ QVariant::String );
+
+ item = addItemInfo( exifGroup, "User comment", i18n("User Comment"),
+ QVariant::String );
+ setHint(item, KFileMimeTypeInfo::Description);
+
+ item = addItemInfo( exifGroup, "JPEG process", i18n("JPEG Process"),
+ QVariant::String );
+
+ item = addItemInfo( exifGroup, "Thumbnail", i18n("Thumbnail"),
+ QVariant::Image );
+ setHint( item, KFileMimeTypeInfo::Thumbnail );
+
+// ###
+// exifGroup.setSupportsVariableKeys(true);
+}
+
+QValidator* KJpegPlugin::createValidator(const KFileMetaInfoItem& /*item*/,
+ QObject */*parent*/,
+ const char */*name*/ ) const
+{
+ // no need to return a validator that validates everything as OK :)
+// if (item.isEditable())
+// return new QRegExpValidator(QRegExp(".*"), parent, name);
+// else
+ return 0L;
+}
+
+bool KJpegPlugin::writeInfo( const KFileMetaInfo& info ) const
+{
+ QString comment = info[EXIFGROUP].value("Comment").toString();
+ QString path = info.path();
+
+ kdDebug(7034) << "exif writeInfo: " << info.path() << " \"" << comment << "\"\n";
+
+ /*
+ Do a strictly safe insertion of the comment:
+
+ Scan original to verify it's a proper jpeg
+ Open a unique temporary file in this directory
+ Write temporary, replacing all COM blocks with this one.
+ Scan temporary, to verify it's a proper jpeg
+ Rename original to another unique name
+ Rename temporary to original
+ Unlink original
+ */
+ /*
+ The jpeg standard does not regulate the contents of the COM block.
+ I'm assuming the best thing to do here is write as unicode utf-8,
+ which is fully backwards compatible with readers expecting ascii.
+ Readers expecting a national character set are out of luck...
+ */
+ if( safe_copy_and_modify( QFile::encodeName( path ), comment.utf8() ) ) {
+ return false;
+ }
+ return true;
+}
+
+bool KJpegPlugin::readInfo( KFileMetaInfo& info, uint what )
+{
+ const QString path( info.path() );
+ if ( path.isEmpty() ) // remote file
+ return false;
+
+ QString tag;
+ ExifData ImageInfo;
+
+ // parse the jpeg file now
+ try {
+ if ( !ImageInfo.scan(info.path()) ) {
+ kdDebug(7034) << "Not a JPEG file!\n";
+ return false;
+ }
+ }
+ catch (FatalError& e) { // malformed exif data?
+ kdDebug(7034) << "Exception caught while parsing Exif data of: " << info.path() << endl;
+ e.debug_print();
+ return false;
+ }
+
+ KFileMetaInfoGroup exifGroup = appendGroup( info, EXIFGROUP );
+
+ tag = ImageInfo.getComment();
+ if ( tag.length() ) {
+ kdDebug(7034) << "exif inserting Comment: " << tag << "\n";
+ appendItem( exifGroup, "Comment", tag );
+ } else {
+ appendItem( exifGroup, "Comment", tag ); // So user can add new comment
+ }
+
+ tag = ImageInfo.getCameraMake();
+ if (tag.length())
+ appendItem( exifGroup, "Manufacturer", tag );
+
+ tag = ImageInfo.getCameraModel();
+ if (tag.length())
+ appendItem( exifGroup, "Model", tag );
+
+ tag = ImageInfo.getDateTime();
+ if (tag.length()){
+ QDateTime dt = parseDateTime( tag.stripWhiteSpace() );
+ if ( dt.isValid() ) {
+ appendItem( exifGroup, "Date/time", dt );
+ appendItem( exifGroup, "CreationDate", dt.date() );
+ appendItem( exifGroup, "CreationTime", dt.time() );
+ }
+ }
+
+ appendItem( exifGroup,"Dimensions", QSize( ImageInfo.getWidth(),
+ ImageInfo.getHeight() ) );
+
+ if ( ImageInfo.getOrientation() )
+ appendItem( exifGroup, "Orientation", ImageInfo.getOrientation() );
+
+ appendItem( exifGroup, "ColorMode", ImageInfo.getIsColor() ?
+ i18n("Color") : i18n("Black and white") );
+
+ int flashUsed = ImageInfo.getFlashUsed(); // -1, <set>
+ if ( flashUsed >= 0 ) {
+ QString flash = i18n("Flash", "(unknown)");
+ switch ( flashUsed ) {
+ case 0: flash = i18n("Flash", "No");
+ break;
+ case 1:
+ case 5:
+ case 7:
+ flash = i18n("Flash", "Fired");
+ break;
+ case 9:
+ case 13:
+ case 15:
+ flash = i18n( "Flash", "Fill Fired" );
+ break;
+ case 16:
+ flash = i18n( "Flash", "Off" );
+ break;
+ case 24:
+ flash = i18n( "Flash", "Auto Off" );
+ break;
+ case 25:
+ case 29:
+ case 31:
+ flash = i18n( "Flash", "Auto Fired" );
+ break;
+ case 32:
+ flash = i18n( "Flash", "Not Available" );
+ break;
+ default:
+ break;
+ }
+ appendItem( exifGroup, "Flash used",
+ flash );
+ }
+
+ if (ImageInfo.getFocalLength()){
+ appendItem( exifGroup, "Focal length",
+ QString().sprintf("%4.1f", ImageInfo.getFocalLength()) );
+
+ if (ImageInfo.getCCDWidth()){
+ appendItem( exifGroup, "35mm equivalent",
+ (int)(ImageInfo.getFocalLength()/ImageInfo.getCCDWidth()*35 + 0.5) );
+ }
+ }
+
+ if (ImageInfo.getCCDWidth()){
+ appendItem( exifGroup, "CCD width",
+ QString().sprintf("%4.2f", ImageInfo.getCCDWidth()) );
+ }
+
+ if (ImageInfo.getExposureTime()){
+ tag=QString().sprintf("%6.3f", ImageInfo.getExposureTime());
+ float exposureTime = ImageInfo.getExposureTime();
+ if (exposureTime > 0 && exposureTime <= 0.5){
+ tag+=QString().sprintf(" (1/%d)", (int)(0.5 + 1/exposureTime) );
+ }
+ appendItem( exifGroup, "Exposure time", tag );
+ }
+
+ if (ImageInfo.getApertureFNumber()){
+ appendItem( exifGroup, "Aperture",
+ QString().sprintf("f/%3.1f",
+ (double)ImageInfo.getApertureFNumber()));
+ }
+
+ if (ImageInfo.getDistance()){
+ if (ImageInfo.getDistance() < 0){
+ tag=i18n("Infinite");
+ }else{
+ tag=QString().sprintf("%5.2fm",(double)ImageInfo.getDistance());
+ }
+ appendItem( exifGroup, "Focus dist.", tag );
+ }
+
+ if (ImageInfo.getExposureBias()){
+ appendItem( exifGroup, "Exposure bias",
+ QString().sprintf("%4.2f",
+ (double)ImageInfo.getExposureBias()) );
+ }
+
+ if (ImageInfo.getWhitebalance() != -1){
+ switch(ImageInfo.getWhitebalance()) {
+ case 0:
+ tag=i18n("Unknown");
+ break;
+ case 1:
+ tag=i18n("Daylight");
+ break;
+ case 2:
+ tag=i18n("Fluorescent");
+ break;
+ case 3:
+ //tag=i18n("incandescent");
+ tag=i18n("Tungsten");
+ break;
+ case 17:
+ tag=i18n("Standard light A");
+ break;
+ case 18:
+ tag=i18n("Standard light B");
+ break;
+ case 19:
+ tag=i18n("Standard light C");
+ break;
+ case 20:
+ tag=i18n("D55");
+ break;
+ case 21:
+ tag=i18n("D65");
+ break;
+ case 22:
+ tag=i18n("D75");
+ break;
+ case 255:
+ tag=i18n("Other");
+ break;
+ default:
+ //23 to 254 = reserved
+ tag=i18n("Unknown");
+ }
+ appendItem( exifGroup, "Whitebalance", tag );
+ }
+
+ if (ImageInfo.getMeteringMode() != -1){
+ switch(ImageInfo.getMeteringMode()) {
+ case 0:
+ tag=i18n("Unknown");
+ break;
+ case 1:
+ tag=i18n("Average");
+ break;
+ case 2:
+ tag=i18n("Center weighted average");
+ break;
+ case 3:
+ tag=i18n("Spot");
+ break;
+ case 4:
+ tag=i18n("MultiSpot");
+ break;
+ case 5:
+ tag=i18n("Pattern");
+ break;
+ case 6:
+ tag=i18n("Partial");
+ break;
+ case 255:
+ tag=i18n("Other");
+ break;
+ default:
+ // 7 to 254 = reserved
+ tag=i18n("Unknown");
+ }
+ appendItem( exifGroup, "Metering mode", tag );
+ }
+
+ if (ImageInfo.getExposureProgram()){
+ switch(ImageInfo.getExposureProgram()) {
+ case 0:
+ tag=i18n("Not defined");
+ break;
+ case 1:
+ tag=i18n("Manual");
+ break;
+ case 2:
+ tag=i18n("Normal program");
+ break;
+ case 3:
+ tag=i18n("Aperture priority");
+ break;
+ case 4:
+ tag=i18n("Shutter priority");
+ break;
+ case 5:
+ tag=i18n("Creative program\n(biased toward fast shutter speed)");
+ break;
+ case 6:
+ tag=i18n("Action program\n(biased toward fast shutter speed)");
+ break;
+ case 7:
+ tag=i18n("Portrait mode\n(for closeup photos with the background out of focus)");
+ break;
+ case 8:
+ tag=i18n("Landscape mode\n(for landscape photos with the background in focus)");
+ break;
+ default:
+ // 9 to 255 = reserved
+ tag=i18n("Unknown");
+ }
+ appendItem( exifGroup, "Exposure", tag );
+ }
+
+ if (ImageInfo.getISOequivalent()){
+ appendItem( exifGroup, "ISO equiv.",
+ QString().sprintf("%2d",
+ (int)ImageInfo.getISOequivalent()) );
+ }
+
+ if (ImageInfo.getCompressionLevel()){
+ switch(ImageInfo.getCompressionLevel()) {
+ case 1:
+ tag=i18n("Basic");
+ break;
+ case 2:
+ tag=i18n("Normal");
+ break;
+ case 4:
+ tag=i18n("Fine");
+ break;
+ default:
+ tag=i18n("Unknown");
+ }
+ appendItem( exifGroup, "JPEG quality", tag );
+ }
+
+ tag = ImageInfo.getUserComment();
+ if (tag.length()){
+ appendItem( exifGroup, "EXIF comment", tag );
+ }
+
+ int a;
+ for (a=0;;a++){
+ if (ProcessTable[a].Tag == ImageInfo.getProcess() || ProcessTable[a].Tag == 0){
+ appendItem( exifGroup, "JPEG process",
+ QString::fromUtf8( ProcessTable[a].Desc) );
+ break;
+ }
+ }
+
+ if ( what & KFileMetaInfo::Thumbnail && !ImageInfo.isNullThumbnail() ){
+ appendItem( exifGroup, "Thumbnail", ImageInfo.getThumbnail() );
+ }
+
+ return true;
+}
+
+// format of the string is:
+// YYYY:MM:DD HH:MM:SS
+QDateTime KJpegPlugin::parseDateTime( const QString& string )
+{
+ QDateTime dt;
+ if ( string.length() != 19 )
+ return dt;
+
+ QString year = string.left( 4 );
+ QString month = string.mid( 5, 2 );
+ QString day = string.mid( 8, 2 );
+ QString hour = string.mid( 11, 2 );
+ QString minute = string.mid( 14, 2 );
+ QString seconds = string.mid( 17, 2 );
+
+ bool ok;
+ bool allOk = true;
+ int y = year.toInt( &ok );
+ allOk &= ok;
+
+ int mo = month.toInt( &ok );
+ allOk &= ok;
+
+ int d = day.toInt( &ok );
+ allOk &= ok;
+
+ int h = hour.toInt( &ok );
+ allOk &= ok;
+
+ int mi = minute.toInt( &ok );
+ allOk &= ok;
+
+ int s = seconds.toInt( &ok );
+ allOk &= ok;
+
+ if ( allOk ) {
+ dt.setDate( QDate( y, mo, d ) );
+ dt.setTime( QTime( h, mi, s ) );
+ }
+
+ return dt;
+}
+
+#include "kfile_jpeg.moc"
diff --git a/kfile-plugins/jpeg/kfile_jpeg.desktop b/kfile-plugins/jpeg/kfile_jpeg.desktop
new file mode 100644
index 00000000..3ca5a011
--- /dev/null
+++ b/kfile-plugins/jpeg/kfile_jpeg.desktop
@@ -0,0 +1,64 @@
+[Desktop Entry]
+Type=Service
+Name=JPEG EXIF Info
+Name[ar]=معلومات JPEG EXIF
+Name[br]=Titouroù EXIF JPEG
+Name[ca]=Informació de JPEG EXIF
+Name[cs]=JPEG EXIF info
+Name[cy]=Gwybodaeth JPEG EXIF
+Name[da]=JPEG EXIF-info
+Name[de]=JPEG EXIF-Info
+Name[el]=Πληροφορίες JPEG EXIF
+Name[eo]=JPEG-EXIF-informo
+Name[es]=Info JPEG EXIF
+Name[et]=JPEG EXIF info
+Name[fa]=اطلاعات JPEG EXIF
+Name[fi]=JPEG EXIF -tiedot
+Name[fr]=Informations JPEG EXIF
+Name[gl]=Inf. JPEG EXIF
+Name[he]=מידע JPEG EXIF
+Name[hi]=JPEG EXIF जानकारी
+Name[hr]=JPEG EXIF Informacije
+Name[hu]=JPEG EXIF-jellemzők
+Name[is]=JPEG EXIF upplýsingar
+Name[it]=Informazioni JPEG EXIF
+Name[ja]=JPEG EXIF 情報
+Name[kk]=JPEG EXIF мәліметі
+Name[km]=ព័ត៌មាន JPEG EXIF
+Name[lt]=JPEG EXIF informacija
+Name[ms]=Maklumat JPEG EXIF
+Name[nds]=JPEG-EXIF-Info
+Name[ne]=JPEG EXIF सूचना
+Name[nl]=JPEG EXIF-info
+Name[nn]=JPEG EXIF-info
+Name[nso]=TshedimoJPEG EXIF Info
+Name[pa]=JPEG EXIF ਜਾਣਕਾਰੀ
+Name[pl]=Informacja o pliku JPEG EXIF
+Name[pt]=Informação do JPEG EXIF
+Name[pt_BR]=Informação sobre JPEG EXIF
+Name[ro]=Informaţii EXIF JPEG
+Name[ru]=Информация о JPEG EXIF
+Name[se]=JPEG EXIF-dieđut
+Name[sl]=Podatki o JPEG EXIF
+Name[sr]=JPEG EXIF информације
+Name[sr@Latn]=JPEG EXIF informacije
+Name[sv]=JPEG EXIF-information
+Name[ta]=JPEG EXIF தகவல்
+Name[tg]=Иттилоот оиди JPEG EXIF
+Name[th]=ข้อมูลแฟ้ม JPEG EXIF
+Name[tr]=JPEG EXIF Bilgisi
+Name[uk]=Інформація про JPEG EXIF
+Name[uz]=JPEG EXIF haqida maʼlumot
+Name[uz@cyrillic]=JPEG EXIF ҳақида маълумот
+Name[ven]=Mafhungo a JPEG EXIF
+Name[wa]=Informåcion sol imådje JPEG EXIF
+Name[xh]=Ulwazi lwe JPEG EXIF
+Name[zh_CN]=JPEG EXIF 信息
+Name[zh_HK]=JPEG EXIF 資訊
+Name[zh_TW]=JPEG EXIF 資訊
+Name[zu]=Ulwazi lwe-JPEG EXIF
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_jpeg
+MimeType=image/jpeg
+PreferredItems=User comment,CreationDate,CreationTime,Dimensions,Exposure time,JPEG quality,Comment
+SupportsThumbnail=true
diff --git a/kfile-plugins/jpeg/kfile_jpeg.h b/kfile-plugins/jpeg/kfile_jpeg.h
new file mode 100644
index 00000000..5c585fb0
--- /dev/null
+++ b/kfile-plugins/jpeg/kfile_jpeg.h
@@ -0,0 +1,43 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Frank Pieczynski
+ *
+ * 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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __KFILE_JPEG_H__
+#define __KFILE_JPEG_H__
+
+#include <qdatetime.h>
+#include <kfilemetainfo.h>
+
+class KJpegPlugin: public KFilePlugin
+{
+ Q_OBJECT
+
+public:
+ KJpegPlugin( QObject *parent, const char *name,
+ const QStringList& args );
+
+ virtual bool readInfo ( KFileMetaInfo& info, uint what );
+ virtual bool writeInfo( const KFileMetaInfo& info ) const;
+ virtual QValidator* createValidator( const KFileMetaInfoItem& item,
+ QObject* parent, const char* name) const;
+
+private:
+ QDateTime parseDateTime( const QString& string );
+};
+
+#endif
diff --git a/kfile-plugins/jpeg/kfile_setcomment.cpp b/kfile-plugins/jpeg/kfile_setcomment.cpp
new file mode 100644
index 00000000..07dca273
--- /dev/null
+++ b/kfile-plugins/jpeg/kfile_setcomment.cpp
@@ -0,0 +1,536 @@
+/*
+ * setcomment.cpp
+ *
+ * Copyright 2002 Bryce Nesbitt
+ *
+ * Based on wrjpgcom.c, Copyright (C) 1994-1997, Thomas G. Lane.
+ * Part of the Independent JPEG Group's software release 6b of 27-Mar-1998
+ *
+ * This file contains a very simple stand-alone application that inserts
+ * user-supplied text as a COM (comment) marker in a JPEG/JFIF file.
+ * This may be useful as an example of the minimum logic needed to parse
+ * JPEG markers.
+ *
+ * There can be an arbitrary number of COM blocks in each jpeg file, with
+ * up to 64K of data each. We, however, write just one COM and blow away
+ * the rest.
+ *
+ *****************
+ *
+ * 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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#undef STANDALONE_COMPILE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include "config.h"
+
+extern int safe_copy_and_modify( const char * original_filename, const char * comment );
+
+#ifdef DONT_USE_B_MODE /* define mode parameters for fopen() */
+#define READ_BINARY "r"
+#define WRITE_BINARY "w"
+#else
+#ifdef VMS /* VMS is very nonstandard */
+#define READ_BINARY "rb", "ctx=stm"
+#define WRITE_BINARY "wb", "ctx=stm"
+#else /* standard ANSI-compliant case */
+#define READ_BINARY "rb"
+#define WRITE_BINARY "wb"
+#endif
+#endif
+
+#define WARNING_GARBAGE 1 /* Original file had some unspecified content */
+#define ERROR_NOT_A_JPEG 5 /* Original file not a proper jpeg (must be 1st) */
+#define ERROR_TEMP_FILE 6 /* Problem writing temporay file */
+#define ERROR_SCREWUP 7 /* Original file is now damaged. Ooops. */
+#define ERROR_PREMATURE_EOF 8 /* Unexpected end of file */
+#define ERROR_BAD_MARKER 9 /* Marker with illegal length */
+#define ERROR_MARKER_ORDER 10 /* File seems to be mixed up */
+
+static int global_error; /* global error flag. Once set, we're dead. */
+
+/****************************************************************************/
+/*
+ * These macros are used to read the input file and write the output file.
+ * To reuse this code in another application, you might need to change these.
+ */
+static FILE * infile; /* input JPEG file */
+
+/* Return next input byte, or EOF if no more */
+#define NEXTBYTE() getc(infile)
+
+static FILE * outfile; /* output JPEG file */
+
+/* Emit an output byte */
+#define PUTBYTE(x) putc((x), outfile)
+
+
+/****************************************************************************/
+/* Read one byte, testing for EOF */
+static int
+read_1_byte (void)
+{
+ int c;
+
+ c = NEXTBYTE();
+ if (c == EOF) {
+ global_error = ERROR_PREMATURE_EOF;
+ }
+ return c;
+}
+
+/* Read 2 bytes, convert to unsigned int */
+/* All 2-byte quantities in JPEG markers are MSB first */
+static unsigned int
+read_2_bytes (void)
+{
+ int c1, c2;
+
+ c1 = NEXTBYTE();
+ if (c1 == EOF)
+ global_error = ERROR_PREMATURE_EOF;
+ c2 = NEXTBYTE();
+ if (c2 == EOF)
+ global_error = ERROR_PREMATURE_EOF;
+ return (((unsigned int) c1) << 8) + ((unsigned int) c2);
+}
+
+
+/****************************************************************************/
+/* Routines to write data to output file */
+static void
+write_1_byte (int c)
+{
+ PUTBYTE(c);
+}
+
+static void
+write_2_bytes (unsigned int val)
+{
+ PUTBYTE((val >> 8) & 0xFF);
+ PUTBYTE(val & 0xFF);
+}
+
+static void
+write_marker (int marker)
+{
+ PUTBYTE(0xFF);
+ PUTBYTE(marker);
+}
+
+static void
+copy_rest_of_file (void)
+{
+ int c;
+
+ while ((c = NEXTBYTE()) != EOF)
+ PUTBYTE(c);
+}
+
+
+/****************************************************************************/
+/*
+ * JPEG markers consist of one or more 0xFF bytes, followed by a marker
+ * code byte (which is not an FF). Here are the marker codes of interest
+ * in this program. (See jdmarker.c for a more complete list.)
+ */
+
+#define M_SOF0 0xC0 /* Start Of Frame N */
+#define M_SOF1 0xC1 /* N indicates which compression process */
+#define M_SOF2 0xC2 /* Only SOF0-SOF2 are now in common use */
+#define M_SOF3 0xC3
+#define M_SOF5 0xC5 /* NB: codes C4 and CC are NOT SOF markers */
+#define M_SOF6 0xC6
+#define M_SOF7 0xC7
+#define M_SOF9 0xC9
+#define M_SOF10 0xCA
+#define M_SOF11 0xCB
+#define M_SOF13 0xCD
+#define M_SOF14 0xCE
+#define M_SOF15 0xCF
+#define M_SOI 0xD8 /* Start Of Image (beginning of datastream) */
+#define M_EOI 0xD9 /* End Of Image (end of datastream) */
+#define M_SOS 0xDA /* Start Of Scan (begins compressed data) */
+#define M_COM 0xFE /* COMment */
+
+
+/*
+ * Find the next JPEG marker and return its marker code.
+ * We expect at least one FF byte, possibly more if the compressor used FFs
+ * to pad the file. (Padding FFs will NOT be replicated in the output file.)
+ * There could also be non-FF garbage between markers. The treatment of such
+ * garbage is unspecified; we choose to skip over it but emit a warning msg.
+ * NB: this routine must not be used after seeing SOS marker, since it will
+ * not deal correctly with FF/00 sequences in the compressed image data...
+ */
+static int
+next_marker (void)
+{
+ int c;
+ int discarded_bytes = 0;
+
+ /* Find 0xFF byte; count and skip any non-FFs. */
+ c = read_1_byte();
+ while (c != 0xFF) {
+ discarded_bytes++;
+ c = read_1_byte();
+ }
+ /* Get marker code byte, swallowing any duplicate FF bytes. Extra FFs
+ * are legal as pad bytes, so don't count them in discarded_bytes.
+ */
+ do {
+ c = read_1_byte();
+ } while (c == 0xFF);
+
+ if (discarded_bytes != 0) {
+ global_error = WARNING_GARBAGE;
+ }
+
+ return c;
+}
+
+
+/*
+ * Most types of marker are followed by a variable-length parameter segment.
+ * This routine skips over the parameters for any marker we don't otherwise
+ * want to process.
+ * Note that we MUST skip the parameter segment explicitly in order not to
+ * be fooled by 0xFF bytes that might appear within the parameter segment;
+ * such bytes do NOT introduce new markers.
+ */
+static void
+copy_variable (void)
+/* Copy an unknown or uninteresting variable-length marker */
+{
+ unsigned int length;
+
+ /* Get the marker parameter length count */
+ length = read_2_bytes();
+ write_2_bytes(length);
+ /* Length includes itself, so must be at least 2 */
+ if (length < 2) {
+ global_error = ERROR_BAD_MARKER;
+ length = 2;
+ }
+ length -= 2;
+ /* Skip over the remaining bytes */
+ while (length > 0) {
+ write_1_byte(read_1_byte());
+ length--;
+ }
+}
+
+static void
+skip_variable (void)
+/* Skip over an unknown or uninteresting variable-length marker */
+{
+ unsigned int length;
+
+ /* Get the marker parameter length count */
+ length = read_2_bytes();
+ /* Length includes itself, so must be at least 2 */
+ if (length < 2) {
+ global_error = ERROR_BAD_MARKER;
+ length = 2;
+ }
+ length -= 2;
+ /* Skip over the remaining bytes */
+ while (length > 0) {
+ (void) read_1_byte();
+ length--;
+ }
+}
+
+
+static int
+scan_JPEG_header (int keep_COM)
+/*
+ * Parse & copy the marker stream until SOFn or EOI is seen;
+ * copy data to output, but discard COM markers unless keep_COM is true.
+ */
+{
+ int c1, c2;
+ int marker;
+
+ /*
+ * Read the initial marker, which should be SOI.
+ * For a JFIF file, the first two bytes of the file should be literally
+ * 0xFF M_SOI. To be more general, we could use next_marker, but if the
+ * input file weren't actually JPEG at all, next_marker might read the whole
+ * file and then return a misleading error message...
+ */
+ c1 = NEXTBYTE();
+ c2 = NEXTBYTE();
+ if (c1 != 0xFF || c2 != M_SOI) {
+ global_error = ERROR_NOT_A_JPEG;
+ return EOF;
+ }
+
+ write_marker(M_SOI);
+
+ /* Scan miscellaneous markers until we reach SOFn. */
+ for (;;) {
+ marker = next_marker();
+ switch (marker) {
+ /* Note that marker codes 0xC4, 0xC8, 0xCC are not, and must not be,
+ * treated as SOFn. C4 in particular is actually DHT.
+ */
+ case M_SOF0: /* Baseline */
+ case M_SOF1: /* Extended sequential, Huffman */
+ case M_SOF2: /* Progressive, Huffman */
+ case M_SOF3: /* Lossless, Huffman */
+ case M_SOF5: /* Differential sequential, Huffman */
+ case M_SOF6: /* Differential progressive, Huffman */
+ case M_SOF7: /* Differential lossless, Huffman */
+ case M_SOF9: /* Extended sequential, arithmetic */
+ case M_SOF10: /* Progressive, arithmetic */
+ case M_SOF11: /* Lossless, arithmetic */
+ case M_SOF13: /* Differential sequential, arithmetic */
+ case M_SOF14: /* Differential progressive, arithmetic */
+ case M_SOF15: /* Differential lossless, arithmetic */
+ return marker;
+
+ case M_SOS: /* should not see compressed data before SOF */
+ global_error = ERROR_MARKER_ORDER;
+ break;
+
+ case M_EOI: /* in case it's a tables-only JPEG stream */
+ return marker;
+
+ case M_COM: /* Existing COM: conditionally discard */
+ if (keep_COM) {
+ write_marker(marker);
+ copy_variable();
+ } else {
+ skip_variable();
+ }
+ break;
+
+ default: /* Anything else just gets copied */
+ write_marker(marker);
+ copy_variable(); /* we assume it has a parameter count... */
+ break;
+ }
+ } /* end loop */
+}
+
+
+/****************************************************************************/
+/*
+ Verify we know how to set the comment on this type of file.
+
+ TODO: The actual check! This should verify
+ the image size promised in the headers matches the file,
+ and that all markers are properly formatted.
+*/
+static int validate_image_file( const char * filename )
+{
+int status = 1;
+int c1, c2;
+
+ if ( (infile = fopen(filename, READ_BINARY)) ) {
+ c1 = NEXTBYTE();
+ c2 = NEXTBYTE();
+ if (c1 != 0xFF || c2 != M_SOI)
+ status = ERROR_NOT_A_JPEG;
+ else
+ status = 0;
+ fclose( infile );
+ }
+ return( status );
+}
+
+
+/****************************************************************************/
+/*
+ Modify the file in place, but be paranoid and safe about it.
+ It's worth a few extra CPU cycles to make sure we never
+ destory an original image:
+ 1) Validate the input file.
+ 2) Open a temporary file.
+ 3) Copy the data, writing a new comment block.
+ 4) Validate the temporary file.
+ 5) Move the temporary file over the original.
+
+ To be even more paranoid & safe we could:
+ 5) Rename the original to a different temporary name.
+ 6) Rename the temporary to the original.
+ 7) Delete the original.
+*/
+extern int safe_copy_and_modify( const char * original_filename, const char * comment )
+{
+char * temp_filename;
+int temp_filename_length;
+int comment_length = 0;
+int marker;
+int i;
+struct stat statbuf;
+
+ global_error = 0;
+
+ /*
+ * Make sure we're dealing with a proper input file. Safety first!
+ */
+ if( validate_image_file( original_filename ) ) {
+ fprintf(stderr, "error validating original file %s\n", original_filename);
+ return(ERROR_NOT_A_JPEG);
+ }
+
+ /* Get a unique temporary file in the same directory. Hopefully
+ * if things go wrong, this file will still be left for recovery purposes.
+ *
+ * NB: I hate these stupid string functions in C... the buffer length is too
+ * hard to manage...
+ */
+ outfile = NULL;
+ temp_filename_length = strlen( original_filename) + 4;
+ temp_filename = (char *)calloc( temp_filename_length, 1 );
+ for( i=0; i<10; i++ ) {
+ snprintf( temp_filename, temp_filename_length, "%s%d", original_filename, i );
+ if( stat( temp_filename, &statbuf ) ) {
+ outfile = fopen(temp_filename, WRITE_BINARY);
+ break;
+ }
+ }
+ if( !outfile ) {
+ fprintf(stderr, "failed opening temporary file %s\n", temp_filename);
+ free(temp_filename);
+ return(ERROR_TEMP_FILE);
+ }
+
+
+ /*
+ * Let's rock and roll!
+ */
+ if ((infile = fopen(original_filename, READ_BINARY)) == NULL) {
+ fprintf(stderr, "can't open input file %s\n", original_filename);
+ free(temp_filename);
+ return(ERROR_NOT_A_JPEG);
+ }
+ /* Copy JPEG headers until SOFn marker;
+ * we will insert the new comment marker just before SOFn.
+ * This (a) causes the new comment to appear after, rather than before,
+ * existing comments; and (b) ensures that comments come after any JFIF
+ * or JFXX markers, as required by the JFIF specification.
+ */
+ marker = scan_JPEG_header(0);
+ /* Insert the new COM marker, but only if nonempty text has been supplied */
+ if (comment) {
+ comment_length = strlen( comment );
+ }
+ if (comment_length > 0) {
+ write_marker(M_COM);
+ write_2_bytes(comment_length + 2);
+ while (comment_length > 0) {
+ write_1_byte(*comment++);
+ comment_length--;
+ }
+ }
+ /* Duplicate the remainder of the source file.
+ * Note that any COM markers occurring after SOF will not be touched.
+ *
+ * :TODO: Discard COM markers occurring after SOF
+ */
+ write_marker(marker);
+ copy_rest_of_file();
+ fclose( infile );
+ fsync( fileno( outfile) ); /* Make sure its really on disk first. !!!VERY IMPORTANT!!! */
+ if ( fclose( outfile ) ) {
+ fprintf(stderr, "error in temporary file %s\n", temp_filename);
+ free(temp_filename);
+ return(ERROR_TEMP_FILE);
+ }
+
+
+ /*
+ * Make sure we did it right. We've already fsync()'ed the file. Safety first!
+ */
+ if( validate_image_file( temp_filename ) ) {
+ fprintf(stderr, "error in temporary file %s\n", temp_filename);
+ free(temp_filename);
+ return(ERROR_TEMP_FILE);
+ }
+
+ if( global_error >= ERROR_NOT_A_JPEG ) {
+ fprintf(stderr, "error %d processing %s\n", global_error, original_filename);
+ free(temp_filename);
+ return(ERROR_NOT_A_JPEG);
+ }
+
+ if( rename( temp_filename, original_filename ) ) {
+ fprintf(stderr, "error renaming %s to %s\n", temp_filename, original_filename);
+ free(temp_filename);
+ return(ERROR_TEMP_FILE);
+ }
+ free(temp_filename);
+
+ return(0);
+}
+
+
+#ifdef STANDALONE_COMPILE
+int
+main (int argc, char **argv)
+{
+ char * progname; /* program name for error messages */
+ char * filename;
+ char * comment;
+ FILE * fp;
+ int error;
+
+ /* Process command line arguments... */
+ progname = argv[0];
+ if (progname == NULL || progname[0] == 0)
+ progname = "writejpgcomment"; /* in case C library doesn't provide it */
+ if( argc != 3) {
+ fprintf(stderr, "Usage: %s <filename> \"<comment>\"\nOverwrites the comment in a image file with the given comment.\n", progname);
+ return(5);
+ }
+ filename = argv[1];
+ comment = argv[2];
+
+
+ /* Check if file is readable... */
+ if ((fp = fopen(filename, READ_BINARY)) == NULL) {
+ fprintf(stderr, "Error: Can't open file %s\n", filename);
+ fclose(fp);
+ return(5);
+ }
+ fclose(fp);
+
+ /* Check if we really have a commentable image file here... */
+ if( validate_image_file( filename ) ) {
+ fprintf(stderr, "Error: file %s is not of a supported type\n", filename);
+ return(5);
+ }
+
+ /* Lets do it... modify the comment in place */
+ if ((error = safe_copy_and_modify( filename, comment ) )) {
+ fprintf(stderr, "Error: %d setting jpg comment\n", error);
+ return(10);
+ }
+
+
+ /* TODO: Read comment back out of jpg and display it */
+ return( 0 );
+}
+#endif
diff --git a/kfile-plugins/pcx/Makefile.am b/kfile-plugins/pcx/Makefile.am
new file mode 100644
index 00000000..111b4c28
--- /dev/null
+++ b/kfile-plugins/pcx/Makefile.am
@@ -0,0 +1,21 @@
+## Makefile.am for PCX file meta info plugin
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+noinst_HEADERS = kfile_pcx.h
+
+kde_module_LTLIBRARIES = kfile_pcx.la
+
+kfile_pcx_la_SOURCES = kfile_pcx.cpp
+kfile_pcx_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_pcx_la_LIBADD = $(LIB_KIO) $(LIBTIFF)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages:
+ $(XGETTEXT) *.cpp -o $(podir)/kfile_pcx.pot
+
+services_DATA = kfile_pcx.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kfile-plugins/pcx/kfile_pcx.cpp b/kfile-plugins/pcx/kfile_pcx.cpp
new file mode 100644
index 00000000..a7468a57
--- /dev/null
+++ b/kfile-plugins/pcx/kfile_pcx.cpp
@@ -0,0 +1,122 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Nadeem Hasan <nhasan@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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kfile_pcx.h"
+
+#include <kgenericfactory.h>
+#include <kdebug.h>
+
+#include <qdatastream.h>
+#include <qfile.h>
+
+typedef KGenericFactory<KPcxPlugin> PcxFactory;
+
+K_EXPORT_COMPONENT_FACTORY(kfile_pcx, PcxFactory("kfile_pcx"))
+
+QDataStream &operator>>( QDataStream &s, PALETTE &pal )
+{
+ for ( int i=0; i<16; ++i )
+ s >> pal.p[ i ].r >> pal.p[ i ].g >> pal.p[ i ].b;
+
+ return s;
+}
+
+QDataStream &operator>>( QDataStream &s, PCXHEADER &ph )
+{
+ s >> ph.Manufacturer;
+ s >> ph.Version;
+ s >> ph.Encoding;
+ s >> ph.Bpp;
+ s >> ph.XMin >> ph.YMin >> ph.XMax >> ph.YMax;
+ s >> ph.HDpi >> ph.YDpi;
+ s >> ph.Palette;
+ s >> ph.Reserved;
+ s >> ph.NPlanes;
+ s >> ph.BytesPerLine;
+ s >> ph.PaletteInfo;
+ s >> ph.HScreenSize;
+ s >> ph.VScreenSize;
+
+ return s;
+}
+
+KPcxPlugin::KPcxPlugin( QObject *parent, const char *name,
+ const QStringList &args ) : KFilePlugin( parent, name, args )
+{
+ kdDebug(7034) << "PCX file meta info plugin" << endl;
+ KFileMimeTypeInfo* info = addMimeTypeInfo( "image/x-pcx" );
+
+ KFileMimeTypeInfo::GroupInfo* group =
+ addGroupInfo( info, "General", i18n( "General" ) );
+
+ KFileMimeTypeInfo::ItemInfo* item;
+ item = addItemInfo( group, "Dimensions", i18n( "Dimensions" ),
+ QVariant::Size );
+ setHint( item, KFileMimeTypeInfo::Size );
+ setUnit( item, KFileMimeTypeInfo::Pixels );
+ item = addItemInfo( group, "BitDepth", i18n( "Bit Depth" ),
+ QVariant::Int );
+ setUnit( item, KFileMimeTypeInfo::BitsPerPixel );
+ item = addItemInfo( group, "Resolution", i18n( "Resolution" ),
+ QVariant::Size );
+ setUnit( item, KFileMimeTypeInfo::DotsPerInch );
+ item = addItemInfo( group, "Compression", i18n( "Compression" ),
+ QVariant::String );
+}
+
+bool KPcxPlugin::readInfo( KFileMetaInfo& info, uint )
+{
+ if ( info.path().isEmpty() )
+ return false;
+
+ struct PCXHEADER header;
+
+ QFile f( info.path() );
+ if ( !f.open( IO_ReadOnly ) )
+ return false;
+
+ QDataStream s( &f );
+ s.setByteOrder( QDataStream::LittleEndian );
+
+ s >> header;
+
+ int w = ( header.XMax-header.XMin ) + 1;
+ int h = ( header.YMax-header.YMin ) + 1;
+ int bpp = header.Bpp*header.NPlanes;
+
+ KFileMetaInfoGroup group = appendGroup( info, "General" );
+
+ appendItem( group, "Dimensions", QSize( w, h ) );
+ appendItem( group, "BitDepth", bpp );
+ appendItem( group, "Resolution", QSize( header.HDpi, header.YDpi ) );
+ if ( header.Encoding == 1 )
+ appendItem( group, "Compression", i18n( "Yes (RLE)" ) );
+ else
+ appendItem( group, "Compression", i18n( "None" ) );
+
+ f.close();
+
+ return true;
+}
+
+#include "kfile_pcx.moc"
+
+/* vim: et sw=2 ts=2
+*/
+
diff --git a/kfile-plugins/pcx/kfile_pcx.desktop b/kfile-plugins/pcx/kfile_pcx.desktop
new file mode 100644
index 00000000..9a3f2090
--- /dev/null
+++ b/kfile-plugins/pcx/kfile_pcx.desktop
@@ -0,0 +1,62 @@
+[Desktop Entry]
+Type=Service
+Name=PCX File Meta Info
+Name[ar]=معلومات ملف PCX
+Name[br]=Meta-titouroù ar restr PCX
+Name[bs]=PCX meta-podaci
+Name[ca]=Metainformació de fitxer PCX
+Name[cs]=Metainformace obrázku typu PCX
+Name[cy]=Meta-wybodaeth Ffeil PCX
+Name[da]=PCX Fil-meta-info
+Name[de]=PCX Metainformation
+Name[el]=Μετα-πληροφορίες αρχείου PCX
+Name[eo]=PCX-dosiera metainformo
+Name[es]=Info meta de archivos PCX
+Name[et]=PCX faili metainfo
+Name[eu]=PCX fitxategi meta info
+Name[fa]=فرااطلاعات پروندۀ PCX
+Name[fi]=PCX-tiedoston metatiedot
+Name[fr]=Méta Informations sur les fichiers PCX
+Name[gl]=Inf. metaficheiro PCX
+Name[he]=מידע PCX
+Name[hi]=PCX फ़ाइल मेटा जानकारी
+Name[hu]=PCX-jellemzők
+Name[is]=PCX File Meta upplýsingar
+Name[it]=Informazioni PCX
+Name[ja]=PCX ファイルメタ情報
+Name[kk]=PCX файлдың мета деректері
+Name[km]=ព័ត៌មាន​មេតា​របស់​ឯកសារ PCX
+Name[lt]=PCX bylos meta informacija
+Name[ms]=Maklumat Meta Fail PCX
+Name[nb]=PCX-filmetainfo
+Name[nds]=PCX-Metainfo
+Name[ne]=PCX फाइल मेटा सूचना
+Name[nl]=PCX meta-info
+Name[nn]=PCX-filmetainfo
+Name[pl]=Informacja o pliku PCX
+Name[pt]=Meta-Informação do Ficheiro PCX
+Name[pt_BR]=Informação sobre Meta Arquivo PCX
+Name[ro]=Metainformaţii PCX
+Name[ru]=Информация о метафайле PCX
+Name[se]=PCX-filla metadieđut
+Name[sk]=Meta-info o súbore PCX
+Name[sl]=Meta podatki o PCX
+Name[sr]=Мета информације PCX фајла
+Name[sr@Latn]=Meta informacije PCX fajla
+Name[sv]=Metainformation om PCX-fil
+Name[ta]=PCX File Meta தகவல்
+Name[tg]=Иттилоот оиди метафайли PCX
+Name[th]=ข้อมูลเมตาแฟ้ม PCX
+Name[tr]=PCX Dosya Bilgisi
+Name[uk]=Метаінформація про файл PCX
+Name[uz]=PCX-faylining meta-maʼlumoti
+Name[uz@cyrillic]=PCX-файлининг мета-маълумоти
+Name[wa]=Informåcion sol imådje PCX
+Name[zh_CN]=PCX 文件元信息
+Name[zh_HK]=PCX 檔案 Meta 資訊
+Name[zh_TW]=PCX 檔案 Meta 資訊
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_pcx
+MimeType=image/x-pcx
+PreferredGroups=General
+PreferredItems=Dimensions,Resolution,BitDepth,Compression
diff --git a/kfile-plugins/pcx/kfile_pcx.h b/kfile-plugins/pcx/kfile_pcx.h
new file mode 100644
index 00000000..434f89a3
--- /dev/null
+++ b/kfile-plugins/pcx/kfile_pcx.h
@@ -0,0 +1,88 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Nadeem Hasan <nhasan@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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __KFILE_PCX_H_
+#define __KFILE_PCX_H_
+
+#include <kfilemetainfo.h>
+
+struct PALETTE
+{
+ struct
+ {
+ Q_UINT8 r;
+ Q_UINT8 g;
+ Q_UINT8 b;
+ } p[ 16 ];
+};
+
+struct PCXHEADER
+{
+ Q_UINT8 Manufacturer; // Constant Flag, 10 = ZSoft .pcx
+ Q_UINT8 Version; // Version information
+ // 0 = Version 2.5 of PC Paintbrush
+ // 2 = Version 2.8 w/palette information
+ // 3 = Version 2.8 w/o palette information
+ // 4 = PC Paintbrush for Windows(Plus for
+ // Windows uses Ver 5)
+ // 5 = Version 3.0 and > of PC Paintbrush
+ // and PC Paintbrush +, includes
+ // Publisher's Paintbrush . Includes
+ // 24-bit .PCX files
+ Q_UINT8 Encoding; // 1 = .PCX run length encoding
+ Q_UINT8 Bpp; // Number of bits to represent a pixel
+ // (per Plane) - 1, 2, 4, or 8
+ Q_UINT16 XMin;
+ Q_UINT16 YMin;
+ Q_UINT16 XMax;
+ Q_UINT16 YMax;
+ Q_UINT16 HDpi;
+ Q_UINT16 YDpi;
+ struct PALETTE Palette;
+ Q_UINT8 Reserved; // Should be set to 0.
+ Q_UINT8 NPlanes; // Number of color planes
+ Q_UINT16 BytesPerLine; // Number of bytes to allocate for a scanline
+ // plane. MUST be an EVEN number. Do NOT
+ // calculate from Xmax-Xmin.
+ Q_UINT16 PaletteInfo; // How to interpret palette- 1 = Color/BW,
+ // 2 = Grayscale ( ignored in PB IV/ IV + )
+ Q_UINT16 HScreenSize; // Horizontal screen size in pixels. New field
+ // found only in PB IV/IV Plus
+ Q_UINT16 VScreenSize; // Vertical screen size in pixels. New field
+ // found only in PB IV/IV Plus
+ Q_UINT8 Filler[ 54 ]; // Blank to fill out 128 byte header. Set all
+ // bytes to 0
+};
+
+class KPcxPlugin: public KFilePlugin
+{
+ Q_OBJECT
+
+public:
+ KPcxPlugin(QObject *parent, const char *name, const QStringList& args);
+ virtual bool readInfo(KFileMetaInfo& info, uint what);
+
+private:
+};
+
+#endif
+
+/* vim: et sw=2 ts=2
+*/
+
diff --git a/kfile-plugins/pdf/Makefile.am b/kfile-plugins/pdf/Makefile.am
new file mode 100644
index 00000000..841d9980
--- /dev/null
+++ b/kfile-plugins/pdf/Makefile.am
@@ -0,0 +1,22 @@
+## Makefile.am for the pdf file meta info plugin
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes) $(POPPLER_CFLAGS)
+
+# these are the headers for your project
+noinst_HEADERS = kfile_pdf.h
+
+kde_module_LTLIBRARIES = kfile_pdf.la
+
+kfile_pdf_la_SOURCES = kfile_pdf.cpp
+kfile_pdf_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_pdf_la_LIBADD = $(LIB_KIO) $(POPPLER_LIBS)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages:
+ $(XGETTEXT) *.cpp -o $(podir)/kfile_pdf.pot
+
+services_DATA = kfile_pdf.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kfile-plugins/pdf/configure.in.in b/kfile-plugins/pdf/configure.in.in
new file mode 100644
index 00000000..926497a5
--- /dev/null
+++ b/kfile-plugins/pdf/configure.in.in
@@ -0,0 +1,15 @@
+AC_ARG_WITH([poppler],
+ [AC_HELP_STRING([--with-poppler],
+ [Enable PDF support through poppler @<:@default=check@:>@])],
+ [], with_poppler=check)
+
+# Compile the pdf meta info plugin only if Poppler is available
+if test "x$with_poppler" != xno; then
+ PKG_CHECK_MODULES(POPPLER, poppler-qt >= 0.3.1, have_poppler=yes, have_poppler=no)
+
+ if test "x$with_poppler" != xcheck && test "x$have_poppler" != xyes; then
+ AC_MSG_ERROR([--with-poppler was given, but test for poppler failed])
+ fi
+fi
+
+AM_CONDITIONAL(include_PDF, test "x$have_poppler" = xyes)
diff --git a/kfile-plugins/pdf/kfile_pdf.cpp b/kfile-plugins/pdf/kfile_pdf.cpp
new file mode 100644
index 00000000..d5beeb60
--- /dev/null
+++ b/kfile-plugins/pdf/kfile_pdf.cpp
@@ -0,0 +1,104 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2001, 2002 Rolf Magnus <ramagnus@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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#include "kfile_pdf.h"
+
+#include <kgenericfactory.h>
+#include <kdebug.h>
+
+typedef KGenericFactory<KPdfPlugin> PdfFactory;
+
+K_EXPORT_COMPONENT_FACTORY(kfile_pdf, PdfFactory("kfile_pdf"))
+
+KPdfPlugin::KPdfPlugin(QObject *parent, const char *name, const QStringList &preferredItems)
+ : KFilePlugin(parent, name, preferredItems)
+{
+ kdDebug(7034) << "pdf plugin\n";
+
+ // set up our mime type
+ KFileMimeTypeInfo* info = addMimeTypeInfo( "application/pdf" );
+
+ // general group
+ KFileMimeTypeInfo::GroupInfo* group = addGroupInfo(info, "General", i18n("General"));
+
+ KFileMimeTypeInfo::ItemInfo* item;
+
+ item = addItemInfo(group, "Title", i18n("Title"), QVariant::String);
+ setHint(item, KFileMimeTypeInfo::Name);
+ item = addItemInfo(group, "Subject", i18n("Subject"), QVariant::String);
+ setHint(item, KFileMimeTypeInfo::Description);
+ item = addItemInfo(group, "Author", i18n("Author"), QVariant::String);
+ setHint(item, KFileMimeTypeInfo::Author);
+ addItemInfo(group, "Keywords", i18n("Key Words"), QVariant::String);
+ addItemInfo(group, "Creator", i18n("Creator"), QVariant::String);
+ addItemInfo(group, "Producer", i18n("Producer"), QVariant::String);
+ addItemInfo(group, "CreationDate", i18n("Creation Date"), QVariant::DateTime);
+ addItemInfo(group, "ModificationDate", i18n("Modified"), QVariant::DateTime);
+ addItemInfo(group, "Pages", i18n("Pages"), QVariant::Int);
+ addItemInfo(group, "Protected", i18n("Protected"), QVariant::String);
+ addItemInfo(group, "Linearized", i18n("Linearized"), QVariant::String);
+ addItemInfo(group, "Version", i18n("Version"), QVariant::String);
+}
+
+bool KPdfPlugin::readInfo( KFileMetaInfo& info, uint /* what */)
+{
+ Poppler::Document *doc = Poppler::Document::load(info.path());
+ if (!doc || doc->isLocked())
+ {
+ delete doc;
+ return false;
+ }
+
+ KFileMetaInfoGroup generalGroup = appendGroup(info, "General");
+
+ appendItem(generalGroup, "Title", doc->getInfo("Title") );
+ appendItem(generalGroup, "Subject", doc->getInfo("Subject") );
+ appendItem(generalGroup, "Author", doc->getInfo("Author") );
+ appendItem(generalGroup, "Keywords", doc->getInfo("Keywords") );
+ appendItem(generalGroup, "Creator", doc->getInfo("Creator") );
+ appendItem(generalGroup, "Producer", doc->getInfo("Producer") );
+
+ appendItem(generalGroup, "CreationDate", doc->getDate("CreationDate") );
+ appendItem(generalGroup, "ModificationDate", doc->getDate("ModDate") );
+ appendItem(generalGroup, "Pages", doc->getNumPages() );
+
+ QString enc;
+ if (doc->isEncrypted())
+ {
+ enc = i18n("Yes (Can Print:%1 Can Copy:%2 Can Change:%3 Can Add notes:%4)")
+ .arg(doc->okToPrint() ? i18n("Yes") : i18n("No"))
+ .arg(doc->okToCopy() ? i18n("Yes") : i18n("No"))
+ .arg(doc->okToChange() ? i18n("Yes") : i18n("No"))
+ .arg(doc->okToAddNotes() ? i18n("Yes") : i18n("No"));
+ }
+ else enc = i18n("No");
+
+ appendItem(generalGroup, "Protected", enc );
+ appendItem(generalGroup, "Linearized", doc->isLinearized() ? i18n("Yes") : i18n("No") );
+ QString versionString = QString("%1").arg( doc->getPDFVersion(), 0, 'f', 1 );
+ appendItem(generalGroup, "Version", versionString );
+
+ delete doc;
+
+ return true;
+}
+
+#include "kfile_pdf.moc"
+
diff --git a/kfile-plugins/pdf/kfile_pdf.desktop b/kfile-plugins/pdf/kfile_pdf.desktop
new file mode 100644
index 00000000..cdc6a8e8
--- /dev/null
+++ b/kfile-plugins/pdf/kfile_pdf.desktop
@@ -0,0 +1,64 @@
+[Desktop Entry]
+Type=Service
+Name=PDF Info
+Name[af]=Pdf Inligting
+Name[ar]=معلومات PDF
+Name[br]=Titouroù PDF
+Name[ca]=Informació de PDF
+Name[cs]=PDF info
+Name[cy]=Gybodaeth PDF
+Name[da]=PDF-info
+Name[de]=PDF-Info
+Name[el]=Πληροφορίες PDF
+Name[eo]=PDF-informo
+Name[es]=Info PDF
+Name[et]=PDF info
+Name[fa]=اطلاعات PDF
+Name[fi]=PDF-tiedot
+Name[fr]=Informations PDF
+Name[gl]=Inf. PDF
+Name[he]=מידע PDF
+Name[hi]=PDF जानकारी
+Name[hr]=PDF Informacije
+Name[hu]=PDF-jellemzők
+Name[is]=PDF upplýsingar
+Name[it]=Informazioni PDF
+Name[ja]=PDF 情報
+Name[kk]=PDF мәліметі
+Name[km]=ព័ត៌មាន PDF
+Name[lt]=PDF informacija
+Name[ms]=Maklumat PDF
+Name[nds]=PDF-Info
+Name[ne]=PDF सूचना
+Name[nl]=PDF-info
+Name[nn]=PDF-info
+Name[nso]=Tshedimoso ya PDF
+Name[pa]=PDF ਜਾਣਕਾਰੀ
+Name[pl]=Informacja o pliku PDF
+Name[pt]=Informação do PDF
+Name[pt_BR]=Informação sobre PDF
+Name[ro]=Informaţii PDF
+Name[ru]=Информация о PDF
+Name[se]=PDF-dieđut
+Name[sl]=Podatki o PDF
+Name[sr]=PDF информације
+Name[sr@Latn]=PDF informacije
+Name[sv]=PDF-information
+Name[ta]=PDF தகவல்
+Name[tg]=Иттилоот оиди PDF
+Name[th]=ข้อมูลแฟ้ม PDF
+Name[tr]=PDF Bilgisi
+Name[uk]=Інформація про PDF
+Name[uz]=PDF haqida maʼlumot
+Name[uz@cyrillic]=PDF ҳақида маълумот
+Name[ven]=Mafhungo a PDF
+Name[wa]=Informåcion sol documint PDF
+Name[xh]=PDF Ulwazi
+Name[zh_CN]=PDF 信息
+Name[zh_HK]=PDF 資訊
+Name[zh_TW]=PDF 資訊
+Name[zu]=Ulwazi lwe-PDF
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_pdf
+MimeType=application/pdf
+PreferredItems=Title,Subject,Author,Keywords,Creator,Producer,CreationDate,ModificationDate,Pages,Protected,Linearized,Version
diff --git a/kfile-plugins/pdf/kfile_pdf.h b/kfile-plugins/pdf/kfile_pdf.h
new file mode 100644
index 00000000..b0214f54
--- /dev/null
+++ b/kfile-plugins/pdf/kfile_pdf.h
@@ -0,0 +1,38 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2001, 2002 Rolf Magnus <ramagnus@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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#ifndef __KFILE_PDF_H__
+#define __KFILE_PDF_H__
+
+#include <kfilemetainfo.h>
+#include <poppler-qt.h>
+
+class QStringList;
+
+class KPdfPlugin: public KFilePlugin
+{
+Q_OBJECT
+public:
+ KPdfPlugin( QObject *parent, const char *name, const QStringList& preferredItems );
+
+ virtual bool readInfo(KFileMetaInfo& info, uint what);
+};
+
+#endif
diff --git a/kfile-plugins/png/Makefile.am b/kfile-plugins/png/Makefile.am
new file mode 100644
index 00000000..9aa820b6
--- /dev/null
+++ b/kfile-plugins/png/Makefile.am
@@ -0,0 +1,22 @@
+## Makefile.am for png file meta info plugin
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = kfile_png.h
+
+kde_module_LTLIBRARIES = kfile_png.la
+
+kfile_png_la_SOURCES = kfile_png.cpp
+kfile_png_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_png_la_LIBADD = $(LIB_KIO)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages:
+ $(XGETTEXT) *.cpp -o $(podir)/kfile_png.pot
+
+services_DATA = kfile_png.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kfile-plugins/png/kfile_png.cpp b/kfile-plugins/png/kfile_png.cpp
new file mode 100644
index 00000000..c3e54b66
--- /dev/null
+++ b/kfile-plugins/png/kfile_png.cpp
@@ -0,0 +1,315 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2001, 2002 Rolf Magnus <ramagnus@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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#include <stdlib.h>
+#include "kfile_png.h"
+
+#include <kurl.h>
+#include <kprocess.h>
+#include <klocale.h>
+#include <kgenericfactory.h>
+#include <kdebug.h>
+
+#include <qcstring.h>
+#include <qfile.h>
+#include <qdatetime.h>
+#include <qdict.h>
+#include <qvalidator.h>
+#include <zlib.h>
+
+// some defines to make it easier
+// don't tell me anything about preprocessor usage :)
+#define CHUNK_SIZE(data, index) ((data[index ]<<24) + (data[index+1]<<16) + \
+ (data[index+2]<< 8) + data[index+3])
+#define CHUNK_TYPE(data, index) &data[index+4]
+#define CHUNK_HEADER_SIZE 12
+#define CHUNK_DATA(data, index, offset) data[8+index+offset]
+
+// known translations for common png keys
+static const char* knownTranslations[]
+#ifdef __GNUC__
+__attribute__((unused))
+#endif
+ = {
+ I18N_NOOP("Title"),
+ I18N_NOOP("Author"),
+ I18N_NOOP("Description"),
+ I18N_NOOP("Copyright"),
+ I18N_NOOP("Creation Time"),
+ I18N_NOOP("Software"),
+ I18N_NOOP("Disclaimer"),
+ I18N_NOOP("Warning"),
+ I18N_NOOP("Source"),
+ I18N_NOOP("Comment")
+};
+
+// and for the colors
+static const char* colors[] = {
+ I18N_NOOP("Grayscale"),
+ I18N_NOOP("Unknown"),
+ I18N_NOOP("RGB"),
+ I18N_NOOP("Palette"),
+ I18N_NOOP("Grayscale/Alpha"),
+ I18N_NOOP("Unknown"),
+ I18N_NOOP("RGB/Alpha")
+};
+
+ // and compressions
+static const char* compressions[] =
+{
+ I18N_NOOP("Deflate")
+};
+
+ // interlaced modes
+static const char* interlaceModes[] = {
+ I18N_NOOP("None"),
+ I18N_NOOP("Adam7")
+};
+
+typedef KGenericFactory<KPngPlugin> PngFactory;
+
+K_EXPORT_COMPONENT_FACTORY(kfile_png, PngFactory("kfile_png"))
+
+KPngPlugin::KPngPlugin(QObject *parent, const char *name,
+ const QStringList &args)
+ : KFilePlugin(parent, name, args)
+{
+ kdDebug(7034) << "png plugin\n";
+
+ // set up our mime type
+ KFileMimeTypeInfo* info = addMimeTypeInfo( "image/png" );
+
+ KFileMimeTypeInfo::GroupInfo* group = 0;
+ KFileMimeTypeInfo::ItemInfo* item = 0;
+
+ // comment group
+ group = addGroupInfo(info, "Comment", i18n("Comment"));
+ addVariableInfo(group, QVariant::String, 0);
+
+ // technical group
+ group = addGroupInfo(info, "Technical", i18n("Technical Details"));
+
+ item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size);
+ setHint( item, KFileMimeTypeInfo::Size );
+ setUnit(item, KFileMimeTypeInfo::Pixels);
+
+ item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int);
+ setUnit(item, KFileMimeTypeInfo::BitsPerPixel);
+
+ addItemInfo(group, "ColorMode", i18n("Color Mode"), QVariant::String);
+ addItemInfo(group, "Compression", i18n("Compression"), QVariant::String);
+ addItemInfo(group, "InterlaceMode", i18n("Interlace Mode"),QVariant::String);
+}
+
+bool KPngPlugin::readInfo( KFileMetaInfo& info, uint what)
+{
+ if ( info.path().isEmpty() ) // remote file
+ return false;
+ QFile f(info.path());
+ if ( !f.open(IO_ReadOnly) )
+ return false;
+
+ QIODevice::Offset fileSize = f.size();
+
+ if (fileSize < 29) return false;
+ // the technical group will be read from the first 29 bytes. If the file
+ // is smaller, we can't even read this.
+
+ bool readComments = false;
+ if (what & (KFileMetaInfo::Fastest |
+ KFileMetaInfo::DontCare |
+ KFileMetaInfo::ContentInfo)) readComments = true;
+ else
+ fileSize = 29; // No need to read more
+
+ uchar *data = new uchar[fileSize+1];
+ f.readBlock(reinterpret_cast<char*>(data), fileSize);
+ data[fileSize]='\n';
+
+ // find the start
+ if (data[0] == 137 && data[1] == 80 && data[2] == 78 && data[3] == 71 &&
+ data[4] == 13 && data[5] == 10 && data[6] == 26 && data[7] == 10 )
+ {
+ // ok
+ // the IHDR chunk should be the first
+ if (!strncmp((char*)&data[12], "IHDR", 4))
+ {
+ // we found it, get the dimensions
+ ulong x,y;
+ x = (data[16]<<24) + (data[17]<<16) + (data[18]<<8) + data[19];
+ y = (data[20]<<24) + (data[21]<<16) + (data[22]<<8) + data[23];
+
+ uint type = data[25];
+ uint bpp = data[24];
+ kdDebug(7034) << "dimensions " << x << "*" << y << endl;
+
+ // the bpp are only per channel, so we need to multiply the with
+ // the channel count
+ switch (type)
+ {
+ case 0: break; // Grayscale
+ case 2: bpp *= 3; break; // RGB
+ case 3: break; // palette
+ case 4: bpp *= 2; break; // grayscale w. alpha
+ case 6: bpp *= 4; break; // RGBA
+
+ default: // we don't get any sensible value here
+ bpp = 0;
+ }
+
+ KFileMetaInfoGroup techgroup = appendGroup(info, "Technical");
+
+ appendItem(techgroup, "Dimensions", QSize(x, y));
+ appendItem(techgroup, "BitDepth", bpp);
+ appendItem(techgroup, "ColorMode",
+ (type < sizeof(colors)/sizeof(colors[0]))
+ ? i18n(colors[data[25]]) : i18n("Unknown"));
+
+ appendItem(techgroup, "Compression",
+ (data[26] < sizeof(compressions)/sizeof(compressions[0]))
+ ? i18n(compressions[data[26]]) : i18n("Unknown"));
+
+ appendItem(techgroup, "InterlaceMode",
+ (data[28] < sizeof(interlaceModes)/sizeof(interlaceModes[0]))
+ ? i18n(interlaceModes[data[28]]) : i18n("Unknown"));
+ }
+
+ // look for a tEXt chunk
+ if (readComments)
+ {
+ uint index = 8;
+ index += CHUNK_SIZE(data, index) + CHUNK_HEADER_SIZE;
+ KFileMetaInfoGroup commentGroup = appendGroup(info, "Comment");
+
+ while(index<fileSize-12)
+ {
+ while (index < fileSize - 12 &&
+ strncmp((char*)CHUNK_TYPE(data,index), "tEXt", 4) &&
+ strncmp((char*)CHUNK_TYPE(data,index), "zTXt", 4))
+
+ {
+ if (!strncmp((char*)CHUNK_TYPE(data,index), "IEND", 4))
+ goto end;
+
+ index += CHUNK_SIZE(data, index) + CHUNK_HEADER_SIZE;
+ }
+
+ if (index < fileSize - 12)
+ {
+ // we found a tEXt or zTXt field
+
+ // get the key, it's a null terminated string at the
+ // chunk start
+
+ uchar* key = &CHUNK_DATA(data,index,0);
+
+ int keysize=0;
+ for (;key[keysize]!=0; keysize++)
+ // look if we reached the end of the file
+ // (it might be corrupted)
+ if (8+index+keysize>=fileSize)
+ goto end;
+
+ QByteArray arr;
+ if(!strncmp((char*)CHUNK_TYPE(data,index), "zTXt", 4)) {
+ kdDebug(7034) << "We found a zTXt field\n";
+ // we get the compression method after the key
+ uchar* compressionMethod = &CHUNK_DATA(data,index,keysize+1);
+ if ( *compressionMethod != 0x00 ) {
+ // then it isn't zlib compressed and we are sunk
+ kdDebug(7034) << "Non-standard compression method." << endl;
+ goto end;
+ }
+ // compressed string after the compression technique spec
+ uchar* compressedText = &CHUNK_DATA(data, index, keysize+2);
+ uint compressedTextSize = CHUNK_SIZE(data, index)-keysize-2;
+
+ // security check, also considering overflow wraparound from the addition --
+ // we may endup with a /smaller/ index if we wrap all the way around
+ uint firstIndex = (uint)(compressedText - data);
+ uint onePastLastIndex = firstIndex + compressedTextSize;
+ if ( onePastLastIndex > fileSize || onePastLastIndex <= firstIndex)
+ goto end;
+
+ uLongf uncompressedLen = compressedTextSize * 2; // just a starting point
+ int zlibResult;
+ do {
+ arr.resize(uncompressedLen);
+ zlibResult = uncompress((Bytef*)arr.data(), &uncompressedLen,
+ compressedText, compressedTextSize);
+ if (Z_OK == zlibResult) {
+ // then it is all OK
+ arr.resize(uncompressedLen);
+ } else if (Z_BUF_ERROR == zlibResult) {
+ // the uncompressedArray needs to be larger
+ // kdDebug(7034) << "doubling size for decompression" << endl;
+ uncompressedLen *= 2;
+
+ // DoS protection. can't be bigger than 64k
+ if ( uncompressedLen > 131072 )
+ break;
+ } else {
+ // something bad happened
+ goto end;
+ }
+ } while (Z_BUF_ERROR == zlibResult);
+
+ if (Z_OK != zlibResult)
+ goto end;
+ } else if (!strncmp((char*)CHUNK_TYPE(data,index), "tEXt", 4)) {
+ kdDebug(7034) << "We found a tEXt field\n";
+ // the text comes after the key, but isn't null terminated
+ uchar* text = &CHUNK_DATA(data,index, keysize+1);
+ uint textsize = CHUNK_SIZE(data, index)-keysize-1;
+
+ // security check, also considering overflow wraparound from the addition --
+ // we may endup with a /smaller/ index if we wrap all the way around
+ uint firstIndex = (uint)(text - data);
+ uint onePastLastIndex = firstIndex + textsize;
+
+ if ( onePastLastIndex > fileSize || onePastLastIndex <= firstIndex)
+ goto end;
+
+ arr.resize(textsize);
+ arr = QByteArray(textsize).duplicate((const char*)text,
+ textsize);
+
+ } else {
+ kdDebug(7034) << "We found a field, not expected though\n";
+ goto end;
+ }
+ appendItem(commentGroup,
+ QString(reinterpret_cast<char*>(key)),
+ QString(arr));
+
+ kdDebug(7034) << "adding " << key << " / "
+ << QString(arr) << endl;
+
+ index += CHUNK_SIZE(data, index) + CHUNK_HEADER_SIZE;
+ }
+ }
+ }
+ }
+end:
+ delete[] data;
+ return true;
+}
+
+#include "kfile_png.moc"
diff --git a/kfile-plugins/png/kfile_png.desktop b/kfile-plugins/png/kfile_png.desktop
new file mode 100644
index 00000000..b4819b8d
--- /dev/null
+++ b/kfile-plugins/png/kfile_png.desktop
@@ -0,0 +1,65 @@
+[Desktop Entry]
+Type=Service
+Name=PNG Info
+Name[af]=Png Inligting
+Name[ar]=معلومات PNG
+Name[br]=Titouroù PNG
+Name[ca]=Informació de PNG
+Name[cs]=PNG info
+Name[cy]=Gybodaeth PNG
+Name[da]=PNG-info
+Name[de]=PNG-Info
+Name[el]=Πληροφορίες PNG
+Name[eo]=PNG-informo
+Name[es]=Info PNG
+Name[et]=PNG info
+Name[fa]=اطلاعات PNG
+Name[fi]=PNG-tiedot
+Name[fr]=Informations PNG
+Name[gl]=Inf. PNG
+Name[he]=מידע PNG
+Name[hi]=PNG जानकारी
+Name[hr]=PNG Informacije
+Name[hu]=PNG-jellemzők
+Name[is]=PNG upplýsingar
+Name[it]=Informazioni PNG
+Name[ja]=PNG 情報
+Name[kk]=PNG мәліметі
+Name[km]=ព័ត៌មាន PNG
+Name[lt]=PNG informacija
+Name[ms]=Maklumat PNG
+Name[nds]=PNG-Info
+Name[ne]=PNG सूचना
+Name[nl]=PNG-Info
+Name[nn]=PNG-info
+Name[nso]=Tshedimoso ya PNG
+Name[pa]=PNG ਜਾਣਕਾਰੀ
+Name[pl]=Informacja o pliku PNG
+Name[pt]=Informação do PNG
+Name[pt_BR]= Informação sobre PNG
+Name[ro]=Informaţii PNG
+Name[ru]=Информация о PNG
+Name[se]=PNG-dieđut
+Name[sl]=Podatki o PNG
+Name[sr]=PNG информације
+Name[sr@Latn]=PNG informacije
+Name[sv]=PNG-information
+Name[ta]=PNG தகவல்
+Name[tg]=Иттилоот оиди PNG
+Name[th]=ข้อมูลแฟ้ม PNG
+Name[tr]=PNG Bilgisi
+Name[uk]=Інформація про PNG
+Name[uz]=PNG haqida maʼlumot
+Name[uz@cyrillic]=PNG ҳақида маълумот
+Name[ven]=Mafhungo a PNG
+Name[wa]=Informåcion sol imådje PNG
+Name[xh]=PNG Ulwazi
+Name[zh_CN]=PNG 信息
+Name[zh_HK]=PNG 資訊
+Name[zh_TW]=PNG 資訊
+Name[zu]=Ulwazi lwe-PNG
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_png
+MimeType=image/png
+PreferredGroups=Comment,Technical
+PreferredItems=Title,Author,Dimensions,BitDepth,ColorMode,Compression
diff --git a/kfile-plugins/png/kfile_png.h b/kfile-plugins/png/kfile_png.h
new file mode 100644
index 00000000..0873d55d
--- /dev/null
+++ b/kfile-plugins/png/kfile_png.h
@@ -0,0 +1,39 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2001, 2002 Rolf Magnus <ramagnus@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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#ifndef __KFILE_PNG_H__
+#define __KFILE_PNG_H__
+
+#include <kfilemetainfo.h>
+#include <kurl.h>
+
+class QStringList;
+
+class KPngPlugin: public KFilePlugin
+{
+ Q_OBJECT
+
+public:
+ KPngPlugin( QObject *parent, const char *name, const QStringList& preferredItems );
+
+ virtual bool readInfo( KFileMetaInfo& info, uint );
+};
+
+#endif
diff --git a/kfile-plugins/pnm/Makefile.am b/kfile-plugins/pnm/Makefile.am
new file mode 100644
index 00000000..7148232a
--- /dev/null
+++ b/kfile-plugins/pnm/Makefile.am
@@ -0,0 +1,22 @@
+## Makefile.am for pnm file meta info plugin
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = kfile_pnm.h
+
+kde_module_LTLIBRARIES = kfile_pnm.la
+
+kfile_pnm_la_SOURCES = kfile_pnm.cpp
+kfile_pnm_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_pnm_la_LIBADD = $(LIB_KIO)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages:
+ $(XGETTEXT) *.cpp -o $(podir)/kfile_pnm.pot
+
+services_DATA = kfile_pnm.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kfile-plugins/pnm/kfile_pnm.cpp b/kfile-plugins/pnm/kfile_pnm.cpp
new file mode 100644
index 00000000..b0a1dcca
--- /dev/null
+++ b/kfile-plugins/pnm/kfile_pnm.cpp
@@ -0,0 +1,137 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2003 Volker Krause <volker.krause@rwth-aachen.de>
+ *
+ * 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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kfile_pnm.h"
+
+#include <math.h>
+#include <kgenericfactory.h>
+#include <qfile.h>
+#include <qtextstream.h>
+
+static const char* formats[] = {
+ I18N_NOOP("plain"),
+ I18N_NOOP("raw")
+};
+
+typedef KGenericFactory<KPnmPlugin> PnmFactory;
+
+K_EXPORT_COMPONENT_FACTORY(kfile_pnm, PnmFactory("kfile_pnm"))
+
+KPnmPlugin::KPnmPlugin(QObject *parent, const char *name, const QStringList &args) : KFilePlugin(parent, name, args)
+{
+ makeMimeTypeInfo( "image/x-portable-bitmap" );
+ makeMimeTypeInfo( "image/x-portable-greymap" );
+ makeMimeTypeInfo( "image/x-portable-pixmap" );
+}
+
+void KPnmPlugin::makeMimeTypeInfo(const QString& mimetype)
+{
+ KFileMimeTypeInfo* info = addMimeTypeInfo( mimetype );
+
+ KFileMimeTypeInfo::GroupInfo* group = 0;
+ KFileMimeTypeInfo::ItemInfo* item = 0;
+
+ group = addGroupInfo(info, "General", i18n("General"));
+
+ addItemInfo(group, "Format", i18n("Format"), QVariant::String);
+
+ item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size);
+ setUnit(item, KFileMimeTypeInfo::Pixels);
+
+ item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int);
+ setUnit(item, KFileMimeTypeInfo::BitsPerPixel);
+
+ addItemInfo(group, "Comment", i18n("Comment"), QVariant::String);
+}
+
+
+bool KPnmPlugin::readInfo( KFileMetaInfo& info, uint /*what*/)
+{
+ QFile f(info.path());
+ if(!f.open(IO_ReadOnly))
+ return false;
+ if(f.size() <= 2)
+ return false;
+ QTextStream stream(&f);
+
+ char c;
+ stream >> c;
+ if(c != 'P')
+ return false;
+
+ // image format and type
+ int n;
+ stream >> n;
+ int format = (n - 1) / 3;
+ if(format != 0 && format != 1)
+ return false;
+ int type = (n - 1) % 3;
+
+ QString comments, buffer;
+ while(!stream.atEnd()) {
+ stream >> c;
+ // comment
+ if( c == '#') {
+ buffer = stream.readLine();
+ comments += buffer.stripWhiteSpace();
+ comments += '\n';
+ }
+ // image size
+ // unfortunately Qt doesn't have some kind of push-back method for
+ // QTextStream, so we need to manually decode the first part of the
+ // image size.
+ if( c >= '0' && c <= '9' ) {
+ buffer = "";
+ QChar tmp(c);
+ while(!stream.atEnd() && tmp.isDigit()) {
+ buffer += tmp;
+ stream >> tmp;
+ }
+ break;
+ }
+ }
+
+ // image size
+ int x, y, max;
+ x = buffer.toInt();
+ stream >> y;
+ stream >> max;
+
+ // bit depth
+ // PNM doesn't provide a conventional bit depth value, only the highest value
+ // per pixel. To have comparable values with other formats, we convert it to
+ // a normal bit depth value.
+ int bpp = 1;
+ if(type != 0)
+ bpp = (int)ceil(log((double)max) / log(2.0));
+ if(type == 2)
+ bpp *= 3;
+
+ KFileMetaInfoGroup group = appendGroup(info, "General");
+ appendItem(group, "Format", formats[format]);
+ appendItem(group, "Dimensions", QSize(x, y));
+ if(!comments.isEmpty())
+ appendItem(group, "Comment", comments.stripWhiteSpace());
+ appendItem(group, "BitDepth", bpp);
+
+ f.close();
+ return true;
+}
+
+#include "kfile_pnm.moc"
diff --git a/kfile-plugins/pnm/kfile_pnm.desktop b/kfile-plugins/pnm/kfile_pnm.desktop
new file mode 100644
index 00000000..cfb475d2
--- /dev/null
+++ b/kfile-plugins/pnm/kfile_pnm.desktop
@@ -0,0 +1,60 @@
+[Desktop Entry]
+Type=Service
+Name=PNM Info
+Name[ar]=معلومات PNM
+Name[br]=Titouroù PNM
+Name[ca]=Informació de PNM
+Name[cs]=PNM info
+Name[cy]=Gybodaeth PNM
+Name[da]=PNG-info
+Name[de]=PNM-Info
+Name[el]=Πληροφορίες PNM
+Name[eo]=PNM-informo
+Name[es]=Info PNM
+Name[et]=PNM info
+Name[fa]=اطلاعات PNM
+Name[fi]=PNM-tiedot
+Name[fr]=Informations PNM
+Name[gl]=Inf. PNM
+Name[he]=מידע PNM
+Name[hi]=PNM जानकारी
+Name[hu]=PNM-jellemzők
+Name[is]=PNM upplýsingar
+Name[it]=Informazioni PNM
+Name[ja]=PNM 情報
+Name[kk]=PNM мәліметі
+Name[km]=ព័ត៌មាន PNM
+Name[lt]=PNM informacija
+Name[ms]=Maklumat PNM
+Name[nb]=PNM-info
+Name[nds]=PNM-Info
+Name[ne]=PNM सूचना
+Name[nl]=PNG-info
+Name[nn]=PNM-info
+Name[pa]=PNM ਜਾਣਕਾਰੀ
+Name[pl]=Informacja o pliku PNM
+Name[pt]=Informação do PNM
+Name[pt_BR]=Informação sobre PNG
+Name[ro]=Informaţii PNM
+Name[ru]=Информация о PNM
+Name[se]=PNM-dieđut
+Name[sl]=Podatki o PNM
+Name[sr]=PNM информације
+Name[sr@Latn]=PNM informacije
+Name[sv]=PNM-information
+Name[ta]=PNM தகவல்
+Name[tg]=Иттилоот оиди PNM
+Name[th]=ข้อมูลแฟ้ม PNM
+Name[tr]=PNM Bilgisi
+Name[uk]=Інформація про PNM
+Name[uz]=PNM haqida maʼlumot
+Name[uz@cyrillic]=PNM ҳақида маълумот
+Name[wa]=Informåcion sol imådje PNM
+Name[zh_CN]=PNM 信息
+Name[zh_HK]=PNM 資訊
+Name[zh_TW]=PNM 資訊
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_pnm
+MimeType=image/x-portable-bitmap;image/x-portable-greymap;image/x-portable-pixmap
+PreferredGroups=General
+PreferredItems=Format,Dimensions,BitDepth,Comment
diff --git a/kfile-plugins/pnm/kfile_pnm.h b/kfile-plugins/pnm/kfile_pnm.h
new file mode 100644
index 00000000..4f1043e5
--- /dev/null
+++ b/kfile-plugins/pnm/kfile_pnm.h
@@ -0,0 +1,39 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2003 Volker Krause <volker.krause@rwth-aachen.de>
+ *
+ * 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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __KFILE_PNM_H__
+#define __KFILE_PNM_H__
+
+#include <kfilemetainfo.h>
+
+class QStringList;
+
+class KPnmPlugin: public KFilePlugin
+{
+ Q_OBJECT
+
+public:
+ KPnmPlugin( QObject *parent, const char *name, const QStringList& preferredItems );
+ virtual bool readInfo( KFileMetaInfo& info, uint );
+
+private:
+ void makeMimeTypeInfo( const QString&);
+};
+
+#endif
diff --git a/kfile-plugins/ps/Makefile.am b/kfile-plugins/ps/Makefile.am
new file mode 100644
index 00000000..9c5b20a3
--- /dev/null
+++ b/kfile-plugins/ps/Makefile.am
@@ -0,0 +1,26 @@
+## Makefile.am for the ps file meta info plugin
+
+# set the include path for X, qt and KDE
+INCLUDES = -I$(top_srcdir)/kghostview $(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = kfile_ps.h gscreator.h
+
+kde_module_LTLIBRARIES = kfile_ps.la gsthumbnail.la
+
+kfile_ps_la_SOURCES = kfile_ps.cpp
+kfile_ps_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_ps_la_LIBADD = $(LIB_KIO) ../../kghostview/libdscparse.la
+
+gsthumbnail_la_SOURCES = gscreator.cpp
+gsthumbnail_la_LIBADD = $(LIB_KDECORE) ../../kghostview/libdscparse.la
+gsthumbnail_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages:
+ $(XGETTEXT) *.cpp -o $(podir)/kfile_ps.pot
+
+services_DATA = kfile_ps.desktop gsthumbnail.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kfile-plugins/ps/gscreator.cpp b/kfile-plugins/ps/gscreator.cpp
new file mode 100644
index 00000000..33cbc141
--- /dev/null
+++ b/kfile-plugins/ps/gscreator.cpp
@@ -0,0 +1,619 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2001 Malte Starostik <malte@kde.org>
+
+ Handling of EPS previews Copyright (C) 2003 Philipp Hullmann <phull@gmx.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/* This function gets a path of a DVI, EPS, PS or PDF file and
+ produces a PNG-Thumbnail which is stored as a QImage
+
+ The program works as follows
+
+ 1. Test if file is a DVI file
+
+ 2. Create a child process (1), in which the
+ file is to be changed into a PNG
+
+ 3. Child-process (1) :
+
+ 4. If file is DVI continue with 6
+
+ 5. If file is no DVI continue with 9
+
+ 6. Create another child process (2), in which the DVI is
+ turned into PS using dvips
+
+ 7. Parent process (2) :
+ Turn the recently created PS file into a PNG file using gs
+
+ 8. continue with 10
+
+ 9. Turn the PS,PDF or EPS file into a PNG file using gs
+
+ 10. Parent process (1)
+ store data in a QImage
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <kdemacros.h>
+
+#include <qcolor.h>
+#include <qfile.h>
+#include <qimage.h>
+#include <qregexp.h>
+
+
+#include "gscreator.h"
+#include "dscparse_adapter.h"
+#include "dscparse.h"
+
+extern "C"
+{
+ KDE_EXPORT ThumbCreator *new_creator()
+ {
+ return new GSCreator;
+ }
+}
+
+// This PS snippet will be prepended to the actual file so that only
+// the first page is output.
+static const char *psprolog =
+ "%!PS-Adobe-3.0\n"
+ "/.showpage.orig /showpage load def\n"
+ "/.showpage.firstonly {\n"
+ " .showpage.orig\n"
+ " quit\n"
+ "} def\n"
+ "/showpage { .showpage.firstonly } def\n";
+
+// This is the code recommended by Adobe tech note 5002 for including
+// EPS files.
+static const char *epsprolog =
+ "%!PS-Adobe-3.0\n"
+ "userdict begin /pagelevel save def /showpage { } def\n"
+ "0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin 10 setmiterlimit\n"
+ "[ ] 0 setdash newpath false setoverprint false setstrokeadjust\n";
+
+static const char * gsargs_ps[] = {
+ "gs",
+ "-sDEVICE=png16m",
+ "-sOutputFile=-",
+ "-dSAFER",
+ "-dPARANOIDSAFER",
+ "-dNOPAUSE",
+ "-dFirstPage=1",
+ "-dLastPage=1",
+ "-q",
+ "-",
+ 0, // file name
+ "-c",
+ "showpage",
+ "-c",
+ "quit",
+ 0
+};
+
+static const char * gsargs_eps[] = {
+ "gs",
+ "-sDEVICE=png16m",
+ "-sOutputFile=-",
+ "-dSAFER",
+ "-dPARANOIDSAFER",
+ "-dNOPAUSE",
+ 0, // page size
+ 0, // resolution
+ "-q",
+ "-",
+ 0, // file name
+ "-c",
+ "pagelevel",
+ "-c",
+ "restore",
+ "-c",
+ "end",
+ "-c",
+ "showpage",
+ "-c",
+ "quit",
+ 0
+};
+
+static const char *dvipsargs[] = {
+ "dvips",
+ "-n",
+ "1",
+ "-q",
+ "-o",
+ "-",
+ 0, // file name
+ 0
+};
+
+static bool correctDVI(const QString& filename);
+
+
+namespace {
+ bool got_sig_term = false;
+ void handle_sigterm( int ) {
+ got_sig_term = true;
+ }
+}
+
+
+bool GSCreator::create(const QString &path, int width, int height, QImage &img)
+{
+// The code in the loop (when testing whether got_sig_term got set)
+// should read some variation of:
+// parentJob()->wasKilled()
+//
+// Unfortunatelly, that's currently impossible without breaking BIC.
+// So we need to catch the signal ourselves.
+// Otherwise, on certain funny PS files (for example
+// http://www.tjhsst.edu/~Eedanaher/pslife/life.ps )
+// gs would run forever after we were dead.
+// #### Reconsider for KDE 4 ###
+// (24/12/03 - luis_pedro)
+//
+ typedef void ( *sighandler_t )( int );
+ // according to linux's "man signal" the above typedef is a gnu extension
+ sighandler_t oldhandler = signal( SIGTERM, handle_sigterm );
+
+ int input[2];
+ int output[2];
+ int dvipipe[2];
+
+ QByteArray data(1024);
+
+ bool ok = false;
+
+ // Test if file is DVI
+ bool no_dvi =!correctDVI(path);
+
+ if (pipe(input) == -1) {
+ return false;
+ }
+ if (pipe(output) == -1) {
+ close(input[0]);
+ close(input[1]);
+ return false;
+ }
+
+ KDSC dsc;
+ endComments = false;
+ dsc.setCommentHandler(this);
+
+ if (no_dvi)
+ {
+ FILE* fp = fopen(QFile::encodeName(path), "r");
+ if (fp == 0) return false;
+
+ char buf[4096];
+ int count;
+ while ((count = fread(buf, sizeof(char), 4096, fp)) != 0
+ && !endComments) {
+ dsc.scanData(buf, count);
+ }
+ fclose(fp);
+
+ if (dsc.pjl() || dsc.ctrld()) {
+ // this file is a mess.
+ return false;
+ }
+ }
+
+ const bool is_encapsulated = no_dvi &&
+ (path.find(QRegExp("\\.epsi?$", false, false)) > 0) &&
+ (dsc.bbox()->width() > 0) && (dsc.bbox()->height() > 0) &&
+ (dsc.page_count() <= 1);
+
+ char translation[64] = "";
+ char pagesize[32] = "";
+ char resopt[32] = "";
+ std::auto_ptr<KDSCBBOX> bbox = dsc.bbox();
+ if (is_encapsulated) {
+ // GhostScript's rendering at the extremely low resolutions
+ // required for thumbnails leaves something to be desired. To
+ // get nicer images, we render to four times the required
+ // resolution and let QImage scale the result.
+ const int hres = (width * 72) / bbox->width();
+ const int vres = (height * 72) / bbox->height();
+ const int resolution = (hres > vres ? vres : hres) * 4;
+ const int gswidth = ((bbox->urx() - bbox->llx()) * resolution) / 72;
+ const int gsheight = ((bbox->ury() - bbox->lly()) * resolution) / 72;
+
+ snprintf(pagesize, 31, "-g%ix%i", gswidth, gsheight);
+ snprintf(resopt, 31, "-r%i", resolution);
+ snprintf(translation, 63,
+ " 0 %i sub 0 %i sub translate\n", bbox->llx(),
+ bbox->lly());
+ }
+
+ const CDSC_PREVIEW_TYPE previewType =
+ static_cast<CDSC_PREVIEW_TYPE>(dsc.preview());
+
+ switch (previewType) {
+ case CDSC_TIFF:
+ case CDSC_WMF:
+ case CDSC_PICT:
+ // FIXME: these should take precedence, since they can hold
+ // color previews, which EPSI can't (or can it?).
+ break;
+ case CDSC_EPSI:
+ {
+ const int xscale = bbox->width() / width;
+ const int yscale = bbox->height() / height;
+ const int scale = xscale < yscale ? xscale : yscale;
+ if (getEPSIPreview(path,
+ dsc.beginpreview(),
+ dsc.endpreview(),
+ img,
+ bbox->width() / scale,
+ bbox->height() / scale))
+ return true;
+ // If the preview extraction routine fails, gs is used to
+ // create a thumbnail.
+ }
+ break;
+ case CDSC_NOPREVIEW:
+ default:
+ // need to run ghostscript in these cases
+ break;
+ }
+
+ pid_t pid = fork();
+ if (pid == 0) {
+ // Child process (1)
+
+ // close(STDERR_FILENO);
+
+ // find first zero entry in gsargs and put the filename
+ // or - (stdin) there, if DVI
+ const char **gsargs = gsargs_ps;
+ const char **arg = gsargs;
+
+ if (no_dvi && is_encapsulated) {
+ gsargs = gsargs_eps;
+ arg = gsargs;
+
+ // find first zero entry and put page size there
+ while (*arg) ++arg;
+ *arg = pagesize;
+
+ // find second zero entry and put resolution there
+ while (*arg) ++arg;
+ *arg = resopt;
+ }
+
+ // find next zero entry and put the filename there
+ QCString fname = QFile::encodeName( path );
+ while (*arg)
+ ++arg;
+ if( no_dvi )
+ *arg = fname.data();
+ else
+ *arg = "-";
+
+ // find first zero entry in dvipsargs and put the filename there
+ arg = dvipsargs;
+ while (*arg)
+ ++arg;
+ *arg = fname.data();
+
+ if( !no_dvi ){
+ pipe(dvipipe);
+ pid_t pid_two = fork();
+ if( pid_two == 0 ){
+ // Child process (2), reopen stdout on the pipe "dvipipe" and exec dvips
+
+ close(input[0]);
+ close(input[1]);
+ close(output[0]);
+ close(output[1]);
+ close(dvipipe[0]);
+
+ dup2( dvipipe[1], STDOUT_FILENO);
+
+ execvp(dvipsargs[0], const_cast<char *const *>(dvipsargs));
+ exit(1);
+ }
+ else if(pid_two != -1){
+ close(input[1]);
+ close(output[0]);
+ close(dvipipe[1]);
+
+ dup2( dvipipe[0], STDIN_FILENO);
+ dup2( output[1], STDOUT_FILENO);
+
+ execvp(gsargs[0], const_cast<char *const *>(gsargs));
+ exit(1);
+ }
+ else{
+ // fork() (2) failed, close these
+ close(dvipipe[0]);
+ close(dvipipe[1]);
+ }
+
+ }
+ else if( no_dvi ){
+ // Reopen stdin/stdout on the pipes and exec gs
+ close(input[1]);
+ close(output[0]);
+
+ dup2(input[0], STDIN_FILENO);
+ dup2(output[1], STDOUT_FILENO);
+
+ execvp(gsargs[0], const_cast<char *const *>(gsargs));
+ exit(1);
+ }
+ }
+ else if (pid != -1) {
+ // Parent process, write first-page-only-hack (the hack is not
+ // used if DVI) and read the png output
+ close(input[0]);
+ close(output[1]);
+ const char *prolog;
+ if (is_encapsulated)
+ prolog = epsprolog;
+ else
+ prolog = psprolog;
+ int count = write(input[1], prolog, strlen(prolog));
+ if (is_encapsulated)
+ write(input[1], translation, strlen(translation));
+
+ close(input[1]);
+ if (count == static_cast<int>(strlen(prolog))) {
+ int offset = 0;
+ while (!ok) {
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(output[0], &fds);
+ struct timeval tv;
+ tv.tv_sec = 20;
+ tv.tv_usec = 0;
+
+ got_sig_term = false;
+ if (select(output[0] + 1, &fds, 0, 0, &tv) <= 0) {
+ if ( ( errno == EINTR || errno == EAGAIN ) && !got_sig_term ) continue;
+ break; // error, timeout or master wants us to quit (SIGTERM)
+ }
+ if (FD_ISSET(output[0], &fds)) {
+ count = read(output[0], data.data() + offset, 1024);
+ if (count == -1)
+ break;
+ else
+ if (count) // prepare for next block
+ {
+ offset += count;
+ data.resize(offset + 1024);
+ }
+ else // got all data
+ {
+ data.resize(offset);
+ ok = true;
+ }
+ }
+ }
+ }
+ if (!ok) // error or timeout, gs probably didn't exit yet
+ {
+ kill(pid, SIGTERM);
+ }
+
+ int status = 0;
+ if (waitpid(pid, &status, 0) != pid || (status != 0 && status != 256) )
+ ok = false;
+ }
+ else {
+ // fork() (1) failed, close these
+ close(input[0]);
+ close(input[1]);
+ close(output[1]);
+ }
+ close(output[0]);
+
+ int l = img.loadFromData( data );
+
+ if ( got_sig_term &&
+ oldhandler != SIG_ERR &&
+ oldhandler != SIG_DFL &&
+ oldhandler != SIG_IGN ) {
+ oldhandler( SIGTERM ); // propagate the signal. Other things might rely on it
+ }
+ if ( oldhandler != SIG_ERR ) signal( SIGTERM, oldhandler );
+
+ return ok && l;
+}
+
+ThumbCreator::Flags GSCreator::flags() const
+{
+ return static_cast<Flags>(DrawFrame);
+}
+
+void GSCreator::comment(Name name)
+{
+ switch (name) {
+ case EndPreview:
+ case BeginProlog:
+ case Page:
+ endComments = true;
+ break;
+
+ default:
+ break;
+ }
+}
+
+// Quick function to check if the filename corresponds to a valid DVI
+// file. Returns true if <filename> is a DVI file, false otherwise.
+
+static bool correctDVI(const QString& filename)
+{
+ QFile f(filename);
+ if (!f.open(IO_ReadOnly))
+ return FALSE;
+
+ unsigned char test[4];
+ if ( f.readBlock( (char *)test,2)<2 || test[0] != 247 || test[1] != 2 )
+ return FALSE;
+
+ int n = f.size();
+ if ( n < 134 ) // Too short for a dvi file
+ return FALSE;
+ f.at( n-4 );
+
+ unsigned char trailer[4] = { 0xdf,0xdf,0xdf,0xdf };
+
+ if ( f.readBlock( (char *)test, 4 )<4 || strncmp( (char *)test, (char*) trailer, 4 ) )
+ return FALSE;
+ // We suppose now that the dvi file is complete and OK
+ return TRUE;
+}
+
+bool GSCreator::getEPSIPreview(const QString &path, long start, long
+ end, QImage &outimg, int imgwidth, int imgheight)
+{
+ FILE *fp;
+ fp = fopen(QFile::encodeName(path), "r");
+ if (fp == 0) return false;
+
+ const long previewsize = end - start + 1;
+
+ char *buf = (char *) malloc(previewsize);
+ fseek(fp, start, SEEK_SET);
+ int count = fread(buf, sizeof(char), previewsize - 1, fp);
+ fclose(fp);
+ buf[previewsize - 1] = 0;
+ if (count != previewsize - 1)
+ {
+ free(buf);
+ return false;
+ }
+
+ QString previewstr = QString::fromLatin1(buf);
+ free(buf);
+
+ int offset = 0;
+ while ((offset < previewsize) && !(previewstr[offset].isDigit())) offset++;
+ int digits = 0;
+ while ((offset + digits < previewsize) && previewstr[offset + digits].isDigit()) digits++;
+ int width = previewstr.mid(offset, digits).toInt();
+ offset += digits + 1;
+ while ((offset < previewsize) && !(previewstr[offset].isDigit())) offset++;
+ digits = 0;
+ while ((offset + digits < previewsize) && previewstr[offset + digits].isDigit()) digits++;
+ int height = previewstr.mid(offset, digits).toInt();
+ offset += digits + 1;
+ while ((offset < previewsize) && !(previewstr[offset].isDigit())) offset++;
+ digits = 0;
+ while ((offset + digits < previewsize) && previewstr[offset + digits].isDigit()) digits++;
+ int depth = previewstr.mid(offset, digits).toInt();
+
+ // skip over the rest of the BeginPreview comment
+ while ((offset < previewsize) &&
+ previewstr[offset] != '\n' &&
+ previewstr[offset] != '\r') offset++;
+ while ((offset < previewsize) && previewstr[offset] != '%') offset++;
+
+ unsigned int imagedepth;
+ switch (depth) {
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ imagedepth = 8;
+ break;
+ case 12: // valid, but not (yet) supported
+ default: // illegal value
+ return false;
+ }
+
+ unsigned int colors = (1U << depth);
+ QImage img(width, height, imagedepth, colors);
+ img.setAlphaBuffer(false);
+
+ if (imagedepth <= 8) {
+ for (unsigned int gray = 0; gray < colors; gray++) {
+ unsigned int grayvalue = (255U * (colors - 1 - gray)) /
+ (colors - 1);
+ img.setColor(gray, qRgb(grayvalue, grayvalue, grayvalue));
+ }
+ }
+
+ const unsigned int bits_per_scan_line = width * depth;
+ unsigned int bytes_per_scan_line = bits_per_scan_line / 8;
+ if (bits_per_scan_line % 8) bytes_per_scan_line++;
+ const unsigned int bindatabytes = height * bytes_per_scan_line;
+ QMemArray<unsigned char> bindata(bindatabytes);
+
+ for (unsigned int i = 0; i < bindatabytes; i++) {
+ if (offset >= previewsize)
+ return false;
+
+ while (!isxdigit(previewstr[offset].latin1()) &&
+ offset < previewsize)
+ offset++;
+
+ bool ok = false;
+ bindata[i] = static_cast<unsigned char>(previewstr.mid(offset, 2).toUInt(&ok, 16));
+ if (!ok)
+ return false;
+
+ offset += 2;
+ }
+
+ for (int scanline = 0; scanline < height; scanline++) {
+ unsigned char *scanlineptr = img.scanLine(scanline);
+
+ for (int pixelindex = 0; pixelindex < width; pixelindex++) {
+ unsigned char pixelvalue = 0;
+ const unsigned int bitoffset =
+ scanline * bytes_per_scan_line * 8U + pixelindex * depth;
+ for (int depthindex = 0; depthindex < depth;
+ depthindex++) {
+ const unsigned int byteindex = (bitoffset + depthindex) / 8U;
+ const unsigned int bitindex =
+ 7 - ((bitoffset + depthindex) % 8U);
+ const unsigned char bitvalue =
+ (bindata[byteindex] & static_cast<unsigned char>(1U << bitindex)) >> bitindex;
+ pixelvalue |= (bitvalue << depthindex);
+ }
+ scanlineptr[pixelindex] = pixelvalue;
+ }
+ }
+
+ outimg = img.convertDepth(32).smoothScale(imgwidth, imgheight);
+
+ return true;
+}
diff --git a/kfile-plugins/ps/gscreator.h b/kfile-plugins/ps/gscreator.h
new file mode 100644
index 00000000..b91fb0b0
--- /dev/null
+++ b/kfile-plugins/ps/gscreator.h
@@ -0,0 +1,42 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Malte Starostik <malte@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _GSCREATOR_H_
+#define _GSCREATOR_H_
+
+#include <kio/thumbcreator.h>
+#include "dscparse_adapter.h"
+
+class GSCreator : public ThumbCreator, public KDSCCommentHandler
+{
+public:
+ GSCreator() {};
+ virtual bool create(const QString &path, int, int, QImage &img);
+ virtual Flags flags() const;
+ void comment(Name name);
+
+private:
+ static bool getEPSIPreview(const QString &path,
+ long start, long end,
+ QImage &outimg,
+ int imgwidth, int imgheight);
+ bool endComments;
+};
+
+#endif
diff --git a/kfile-plugins/ps/gsthumbnail.desktop b/kfile-plugins/ps/gsthumbnail.desktop
new file mode 100644
index 00000000..0211020e
--- /dev/null
+++ b/kfile-plugins/ps/gsthumbnail.desktop
@@ -0,0 +1,60 @@
+[Desktop Entry]
+Type=Service
+Name=PostScript, PDF and DVI Files
+Name[ar]=ملفات الــ PostScript ، PDF و DVI
+Name[br]=Restroù PostScript, PDF ha DVI
+Name[bs]=Postscript, PDF i DVI datoteke
+Name[ca]=Fitxers PostScript, PDF i DVI
+Name[cs]=Postscriptové, PDF a DVI soubory
+Name[cy]=Ffeiliau PostScript, PDF a DVI
+Name[da]=PostScript, PDF- og DVI-filer
+Name[de]=PostScript-, PDF- und DVI-Dateien
+Name[el]=Αρχεία PostScript, PDF και DVI
+Name[eo]=Postskriptaj, PDF- kaj DVI-dosieroj
+Name[es]=Archivos PostScript, PDF y DVI
+Name[et]=PostScript-, PDF- ja DVI-failid
+Name[eu]=PostScript, PDF eta DVI fitxategiak
+Name[fa]=پرونده‌های PostScript، PDF و DVI
+Name[fi]=PostScript-, PDF- ja DVI-tiedostot
+Name[fr]=Fichiers PostScript, PDF et DVI
+Name[ga]=Comhaid PostScript, PDF agus DVI
+Name[gl]=Ficheiros PostScript, PDF e DVI
+Name[he]=קבצי PostScript, PDF ו־DVI
+Name[hu]=PostScript-, PDF- és DVI-fájlok
+Name[is]=PostScript PDF og DVI skrár
+Name[it]=File PostScript, PDF e DVI
+Name[ja]=Postscript,PDF,DVIファイル
+Name[kk]=PostScript, PDF және DVI файлдары
+Name[km]=ឯកសារ PostScript, PDF និង DVI
+Name[lt]=Postscript, PDF ir DVI bylos
+Name[ms]=PostScript, PDF dan Fail DVI
+Name[nb]=PostScript, PDF og DVI filer
+Name[nds]=PostScript-, PDF- un DVI-Dateien
+Name[ne]=पोष्टस्क्रिप्ट, PDF र DVI फाइल
+Name[nl]=PostScript-, DVI- en PDF-bestanden
+Name[nn]=PostScript-, PDF- og DVI-filer
+Name[pl]=Pliki PostScript, PDF i DVI
+Name[pt]=Ficheiros PostScript, PDF e DVI
+Name[pt_BR]=Arquivos PostScript, PDF e DVI
+Name[ro]=Fişiere PostScript, PDF şi DVI
+Name[ru]=Файлы PostScript, PDF и DVI
+Name[se]=PostScript-, PDF- ja DVI-fiillat
+Name[sk]=PostScript, PDF a DVI súbory
+Name[sl]=Datoteke PostScript, PDF in DVI
+Name[sr]=PostScript, PDF и DVI фајлови
+Name[sr@Latn]=PostScript, PDF i DVI fajlovi
+Name[sv]=Postscript, PDF och DVI-filer
+Name[ta]= போஸ்ட்கிரிப்ட், பிடிஃப் மற்றும் டிவிஐ கோப்புகள்
+Name[tg]=Файлҳои PostScript, PDF ва DVI
+Name[th]=แฟ้ม PDF, DVI และ โพสต์สคริปต์
+Name[tr]=PostScript, PDF ve DVI Dosyaları
+Name[uk]=Файли PostScript, PDF та DVI
+Name[uz]=PostScript, PDF va DVI fayllari
+Name[uz@cyrillic]=PostScript, PDF ва DVI файллари
+Name[zh_CN]=PostScript、PDF 和 DVI 文件
+Name[zh_HK]=PostScript 、PDF 及 DVI 檔案
+Name[zh_TW]=PostScript,PDF 與 DVI 檔
+ServiceTypes=ThumbCreator
+MimeTypes=application/x-dvi,application/postscript,application/pdf,image/x-eps
+X-KDE-Library=gsthumbnail
+CacheThumbnail=true
diff --git a/kfile-plugins/ps/kfile_ps.cpp b/kfile-plugins/ps/kfile_ps.cpp
new file mode 100644
index 00000000..6d3caa31
--- /dev/null
+++ b/kfile-plugins/ps/kfile_ps.cpp
@@ -0,0 +1,124 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Wilco Greven <greven@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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#include "kfile_ps.h"
+
+#include <qfile.h>
+
+#include <klocale.h>
+#include <kgenericfactory.h>
+#include <kdebug.h>
+
+typedef KGenericFactory<KPSPlugin> PSFactory;
+
+K_EXPORT_COMPONENT_FACTORY(kfile_ps, PSFactory("kfile_ps"))
+
+KPSPlugin::KPSPlugin(QObject *parent, const char *name,
+ const QStringList &preferredItems) :
+ KFilePlugin( parent, name, preferredItems )
+{
+ kdDebug(7034) << "ps plugin\n";
+
+ // set up our mimetypes
+ makeMimeTypeInfo( "application/postscript" );
+ makeMimeTypeInfo( "image/x-eps" );
+}
+
+void KPSPlugin::makeMimeTypeInfo( const char* mimeType )
+{
+ KFileMimeTypeInfo* info = addMimeTypeInfo( mimeType );
+
+ // general group
+ KFileMimeTypeInfo::GroupInfo* group = addGroupInfo(info, "General", i18n("General"));
+ addItemInfo(group, "Title", i18n("Title"), QVariant::String);
+ addItemInfo(group, "Creator", i18n("Creator"), QVariant::String);
+ addItemInfo(group, "CreationDate", i18n("Creation Date"), QVariant::String);
+ addItemInfo(group, "For", i18n("For"), QVariant::String);
+ addItemInfo(group, "Pages", i18n("Pages"), QVariant::UInt);
+}
+
+bool KPSPlugin::readInfo( KFileMetaInfo& info, uint /* what */)
+{
+ _info = info;
+ _group = appendGroup(info, "General");
+ _endComments = false;
+ _setData = 0;
+
+ _dsc = new KDSC;
+ _dsc->setCommentHandler( this );
+ FILE* fp = fopen( QFile::encodeName( info.path() ), "r" );
+ if( fp == 0 )
+ return false;
+
+ char buf[4096];
+ int count;
+ while( ( count = fread( buf, sizeof(char), sizeof( buf ), fp ) ) ) {
+ if ( !_dsc->scanData( buf, count ) ) break;
+ if ( _endComments || _setData == 5 ) break; // Change if new item scanned
+ }
+ fclose( fp );
+ delete _dsc;
+ _dsc = 0;
+
+ return _setData > 0;
+}
+
+void KPSPlugin::comment( Name name )
+{
+ switch( name )
+ {
+ case Title:
+ appendItem(_group, "Title", _dsc->dsc_title());
+ ++_setData;
+ break;
+ case Creator:
+ appendItem(_group, "Creator", _dsc->dsc_creator());
+ ++_setData;
+ break;
+ case CreationDate:
+ appendItem(_group, "CreationDate", _dsc->dsc_date());
+ ++_setData;
+ break;
+ case For:
+ appendItem(_group, "For", _dsc->dsc_for());
+ ++_setData;
+ break;
+ case Pages: {
+ int pages = _dsc->page_pages();
+ if (pages)
+ {
+ appendItem(_group, "Pages", pages);
+ ++_setData;
+ }
+ }
+ break;
+
+ // Right now we watch for 5 elements:
+ // Title, Creator, CreationDate, For, Pages
+ //
+ // If you add another one(s), please update the 5 in "_setData == 5" above
+ //
+ case EndComments: _endComments = true;
+ default: ; // Ignore
+ }
+}
+
+#include "kfile_ps.moc"
+
diff --git a/kfile-plugins/ps/kfile_ps.desktop b/kfile-plugins/ps/kfile_ps.desktop
new file mode 100644
index 00000000..75b3e055
--- /dev/null
+++ b/kfile-plugins/ps/kfile_ps.desktop
@@ -0,0 +1,66 @@
+[Desktop Entry]
+Type=Service
+Name=PostScript Info
+Name[af]=Postscript Inligting
+Name[ar]=معلومات PostScript
+Name[br]=Procinfo PostScript
+Name[ca]=Informació de PostScript
+Name[cs]=PostScript info
+Name[cy]=Gwybodaeth PostScript
+Name[da]=PostScript-info
+Name[de]=PostScript-Info
+Name[el]=Πληροφορίες PostScript
+Name[eo]=Postskriptinformo
+Name[es]=Info PostScript
+Name[et]=PostScript info
+Name[fa]=اطلاعات PostScript
+Name[fi]=PostScript-tiedot
+Name[fr]=Informations PostScript
+Name[gl]=Inf. PostScript
+Name[he]=מידע PostScript
+Name[hi]=पोस्टस्क्रिप्ट जानकारी
+Name[hr]=Postscript informacije
+Name[hu]=PostScript-jellemzők
+Name[is]=PostScript upplýsingar
+Name[it]=Informazioni PostScript
+Name[ja]=PostScript 情報
+Name[kk]=PostScript мәліметі
+Name[km]=ព័ត៌មាន PostScript
+Name[lt]=PostScript informacija
+Name[lv]=Postscript Info
+Name[ms]=Maklumat PostScript
+Name[nb]=PostScript-info
+Name[nds]=PostScript-Info
+Name[ne]=पोष्टस्क्रिप्ट सूचना
+Name[nl]=PostScript-info
+Name[nn]=PostScript-info
+Name[nso]=Tshedimoso ya PostScript
+Name[pa]=PostScript ਜਾਣਕਾਰੀ
+Name[pl]=Informacja o pliku PostScriptu
+Name[pt]=Informação do PostScript
+Name[pt_BR]=Informação sobre PostScript
+Name[ro]=Informaţii PostScript
+Name[ru]=Информация о PostScript
+Name[se]=PostScript-dieđut
+Name[sl]=Podatki o PostScriptu
+Name[sr]=PostScript информације
+Name[sr@Latn]=PostScript informacije
+Name[sv]=Postscript-information
+Name[ta]=முன் எழுத்தாக்க தகவல்
+Name[tg]=Иттилоот оиди PostScript
+Name[th]=ข้อมูลโพสต์สคริปต์
+Name[tr]=PostScript Bilgisi
+Name[uk]=Інформація про PostScript
+Name[uz]=PostScript haqida maʼlumot
+Name[uz@cyrillic]=PostScript ҳақида маълумот
+Name[ven]=Mafhungo a mabammbiri a poso
+Name[wa]=Informåcion sol documint PostScript
+Name[xh]=Ulwazi Lwe PostScript
+Name[zh_CN]=PostScript 信息
+Name[zh_HK]=PostScript 資訊
+Name[zh_TW]=PostScript 資訊
+Name[zu]=Ulwazi Lwesi-PostScript
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_ps
+MimeType=application/postscript;image/x-eps
+PreferredItems=Title,Creator,CreationDate,For,Pages
diff --git a/kfile-plugins/ps/kfile_ps.h b/kfile-plugins/ps/kfile_ps.h
new file mode 100644
index 00000000..339020d1
--- /dev/null
+++ b/kfile-plugins/ps/kfile_ps.h
@@ -0,0 +1,50 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Wilco Greven <greven@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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#ifndef __KFILE_PS_H__
+#define __KFILE_PS_H__
+
+#include <kfilemetainfo.h>
+
+#include "dscparse_adapter.h"
+
+class QStringList;
+
+class KPSPlugin: public KFilePlugin, public KDSCCommentHandler
+{
+ Q_OBJECT
+public:
+ KPSPlugin( QObject *parent, const char *name,
+ const QStringList& preferredItems );
+
+ virtual bool readInfo( KFileMetaInfo& info, uint what);
+
+ void comment( Name );
+ void makeMimeTypeInfo( const char* mimeType );
+
+private:
+ KFileMetaInfo _info;
+ KFileMetaInfoGroup _group;
+ KDSC* _dsc;
+ bool _endComments;
+ int _setData;
+};
+
+#endif
diff --git a/kfile-plugins/raw/Makefile.am b/kfile-plugins/raw/Makefile.am
new file mode 100644
index 00000000..c68309bc
--- /dev/null
+++ b/kfile-plugins/raw/Makefile.am
@@ -0,0 +1,19 @@
+## Makefile.am for the raw thumbnail extration plugin
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = kcamerarawplugin.h
+
+kde_module_LTLIBRARIES = kfile_raw.la
+
+kfile_raw_la_SOURCES = kcamerarawplugin.cpp parse.c
+kfile_raw_la_LIBADD = $(LIB_KIO)
+kfile_raw_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+services_DATA = kfile_raw.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kfile-plugins/raw/kcamerarawplugin.cpp b/kfile-plugins/raw/kcamerarawplugin.cpp
new file mode 100644
index 00000000..525e53ae
--- /dev/null
+++ b/kfile-plugins/raw/kcamerarawplugin.cpp
@@ -0,0 +1,141 @@
+/* This file is part of the KDE project
+ * Copyright (C) Steffen Hansen <hansen@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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kcamerarawplugin.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <klocale.h>
+#include <kgenericfactory.h>
+#include <kdebug.h>
+#include <ktempfile.h>
+#include <kimageio.h>
+#include <qfile.h>
+#include <qimage.h>
+#include <qwmatrix.h>
+#include <cstdio>
+
+
+typedef KGenericFactory<KCameraRawPlugin> RawFactory;
+
+K_EXPORT_COMPONENT_FACTORY(kfile_raw, RawFactory("kfile_raw"))
+
+#ifndef KDE_EXPORT
+# define KDE_EXPORT
+#endif
+
+/* Main entry point into raw parser */
+extern "C" {
+ int extract_thumbnail( FILE*, FILE*, int* );
+ extern char make[];
+ extern char model[];
+}
+
+bool KCameraRawPlugin::createPreview(const QString &path, QImage &img)
+{
+ /* Open file and extract thumbnail */
+ FILE* input = fopen( QFile::encodeName(path), "rb" );
+ if( !input ) return false;
+ KTempFile output;
+ output.setAutoDelete(true);
+ int orientation = 0;
+ if( extract_thumbnail( input, output.fstream(), &orientation ) ) {
+ fclose(input);
+ return false;
+ }
+ fclose(input);
+ output.close();
+ if( !img.load( output.name() ) ) return false;
+
+ if(orientation) {
+ QWMatrix M;
+ QWMatrix flip= QWMatrix(-1,0,0,1,0,0);
+ switch(orientation+1) { // notice intentional fallthroughs
+ case 2: M = flip; break;
+ case 4: M = flip;
+ case 3: M.rotate(180); break;
+ case 5: M = flip;
+ case 6: M.rotate(90); break;
+ case 7: M = flip;
+ case 8: M.rotate(270); break;
+ default: break; // should never happen
+ }
+ img = img.xForm(M);
+ }
+ return true;
+}
+
+KCameraRawPlugin::KCameraRawPlugin(QObject *parent, const char *name,
+ const QStringList &args )
+ : KFilePlugin(parent, name, args)
+{
+ kdDebug(7034) << "KCameraRawPlugin c'tor" << endl;
+
+ //
+ // define all possible meta info items
+ //
+ KFileMimeTypeInfo *info = addMimeTypeInfo("image/x-raw");
+ KFileMimeTypeInfo::GroupInfo *group = addGroupInfo( info, "Info",
+ i18n("Image Info") );
+ KFileMimeTypeInfo::ItemInfo* item;
+
+ item = addItemInfo( group, "Manufacturer", i18n("Camera Manufacturer"),
+ QVariant::String );
+ item = addItemInfo( group, "Model", i18n("Camera Model"),
+ QVariant::String );
+ item = addItemInfo( group, "Thumbnail", i18n("Thumbnail"),
+ QVariant::Image );
+ setHint( item, KFileMimeTypeInfo::Thumbnail );
+}
+
+bool KCameraRawPlugin::readInfo( KFileMetaInfo& info, uint what )
+{
+ kdDebug(7034) << "KCameraRawPlugin::readInfo()" << endl;
+
+ const QString path( info.path() );
+ if ( path.isEmpty() ) // remote file
+ return false;
+
+ KFileMetaInfoGroup group = appendGroup( info, "Info" );
+ if ( what & KFileMetaInfo::Thumbnail ){
+ QImage img;
+ if( createPreview( path,img ) ) {
+ appendItem( group, "Thumbnail", img );
+ kdDebug(7034) << "thumbnail " << path << " created" << endl;
+ }
+ } else {
+ // HACK: We have to extract thumbnail to get any info...
+ QImage img;
+ createPreview( path,img );
+ }
+ kdDebug(7034) << "make=" << make << endl;
+ kdDebug(7034) << "model=" << model << endl;
+ if( make[0] ) {
+ appendItem( group, "Manufacturer", &make[0] );
+ }
+ if( model[0] ) {
+ appendItem( group, "Model", &model[0] );
+ }
+
+ return true;
+}
+
+#include "kcamerarawplugin.moc"
diff --git a/kfile-plugins/raw/kcamerarawplugin.h b/kfile-plugins/raw/kcamerarawplugin.h
new file mode 100644
index 00000000..5a097784
--- /dev/null
+++ b/kfile-plugins/raw/kcamerarawplugin.h
@@ -0,0 +1,38 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2005 Steffen Hansen <hansen@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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef KCAMERARAWPLUGIN_H
+#define KCAMERARAWPLUGIN_H
+
+#include <kfilemetainfo.h>
+
+class QImage;
+
+class KCameraRawPlugin: public KFilePlugin {
+ Q_OBJECT
+
+public:
+ KCameraRawPlugin(QObject *parent, const char *name, const QStringList& args);
+ virtual bool readInfo(KFileMetaInfo& info, uint what);
+
+private:
+ bool createPreview(const QString &path, QImage &img);
+};
+
+#endif /* KCAMERARAWPLUGIN_H */
diff --git a/kfile-plugins/raw/kfile_raw.desktop b/kfile-plugins/raw/kfile_raw.desktop
new file mode 100644
index 00000000..696d286e
--- /dev/null
+++ b/kfile-plugins/raw/kfile_raw.desktop
@@ -0,0 +1,53 @@
+[Desktop Entry]
+Type=Service
+Name=RAW Camera Files
+Name[br]=Restroù kamera kriz
+Name[bs]=RAW kamera datoteke
+Name[ca]=Fitxers RAW de càmera
+Name[cs]=RAW soubory
+Name[da]=RAW kamera-filer
+Name[de]=RAW Kamera-Dateien
+Name[el]=RAW αρχείο κάμερας
+Name[es]=Archivos RAW de cámara
+Name[et]=Toored kaamerafailid
+Name[eu]=RAW kamera-fitxategiak
+Name[fa]=پرونده‌های خام دوربین
+Name[fi]=RAW-kuvatiedostot
+Name[fr]=Fichiers RAW d'appareil photo numérique
+Name[ga]=Comhaid Cheamara RAW
+Name[gl]=Ficheiros RAW de Cámara
+Name[he]=קבצי מצלמה דיגיטלית גולמיים
+Name[hu]=RAW-fájlok
+Name[is]=RAW myndavélaskrár
+Name[it]=File grezzi fotocamera digitale
+Name[ja]=RAW カメラファイル
+Name[kk]=Камераның RAW пішімдегі файлдары
+Name[km]=ឯកសារ​ចេញ​ពី​ម៉ាស៊ីន​ថត​រូប
+Name[lt]=RAW fotoaparato bylos
+Name[nb]=RAW-kamerafiler
+Name[nds]=RAW-Kameradateien
+Name[ne]=RAW क्यामेरा फाइल
+Name[nl]=Rauwe camerabestanden
+Name[nn]=RAW-kamerafiler
+Name[pa]=RAW ਕੈਮਰਾ ਫਾਇਲਾਂ
+Name[pl]=Pliki RAW z aparatów cyfrowych
+Name[pt]=Ficheiros de Máquina Fotográfica Digital RAW
+Name[pt_BR]=Arquivos de Câmeras
+Name[ro]=Fişiere foto brute
+Name[ru]=Необработанные Файлы с цифровой камеры (RAW)
+Name[sk]=RAW súbory digitálneho fotoaparátu
+Name[sl]=Surove datoteke s fotoaparata
+Name[sr]=RAW фајлови слика
+Name[sr@Latn]=RAW fajlovi slika
+Name[sv]=Obehandlade kamerafiler
+Name[th]=แฟ้มภาพ RAW จากกล้อง
+Name[tr]=RAW Kamera Dosyaları
+Name[uk]=Файли цифрової камери RAW
+Name[zh_CN]=RAW 相机文件
+Name[zh_HK]=RAW 相機檔案
+Name[zh_TW]=原始相機檔
+ServiceTypes=KFilePlugin
+MimeType=image/x-raw
+X-KDE-Library=kfile_raw
+CacheThumbnail=false
+SupportsThumbnail=true
diff --git a/kfile-plugins/raw/parse.c b/kfile-plugins/raw/parse.c
new file mode 100644
index 00000000..1abbbfce
--- /dev/null
+++ b/kfile-plugins/raw/parse.c
@@ -0,0 +1,1080 @@
+/*
+ Raw Photo Parser
+ Copyright 2004 by Dave Coffin, dcoffin a cybercom o net
+
+ This program extracts thumbnail images (preferably JPEGs)
+ from any raw digital camera formats that have them, and
+ shows table contents.
+
+ $Revision: 1.36 $
+ $Date: 2005/05/10 21:43:10 $
+ */
+
+/* Hacked for thumbnail extraction in KDE by
+ Steffen Hansen <hansen@kde.org>
+
+ Based on parse.c and parts of dcraw.c by Dave Coffin
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/types.h>
+
+#ifdef WIN32
+#include <winsock2.h>
+typedef __int64 INT64;
+#else
+#include <netinet/in.h>
+typedef long long INT64;
+#endif
+
+/*
+ TIFF and CIFF data blocks can be quite large.
+ Display only the first DLEN bytes.
+ */
+#ifndef DLEN
+#define DLEN 768
+#endif
+
+typedef unsigned char uchar;
+/*typedef unsigned short ushort;*/
+
+FILE *ifp;
+short order;
+char *fname;
+char make[128], model[128], model2[128], thumb_head[128];
+int width, height, offset, length, bps, is_dng;
+int thumb_offset, thumb_length, thumb_layers;
+float cam_mul[4], pre_mul[4], coeff[3][4];
+#define camera_red cam_mul[0]
+#define camera_blue cam_mul[2]
+/*float flash_used, canon_5814;*/
+time_t timestamp;
+/*int data_offset, meta_offset*/
+int raw_height, raw_width, top_margin, left_margin;
+static int flip = 0;
+
+struct decode {
+ struct decode *branch[2];
+ int leaf;
+} first_decode[640], *free_decode;
+
+#define CLASS
+
+#define FORC3 for (c=0; c < 3; c++)
+#define FORC4 for (c=0; c < 4; c++)
+#define FORCC for (c=0; c < colors; c++)
+
+/*
+ Get a 2-byte integer, making no assumptions about CPU byte order.
+ Nor should we assume that the compiler evaluates left-to-right.
+ */
+ushort get2()
+{
+ uchar a, b;
+
+ a = fgetc(ifp); b = fgetc(ifp);
+
+ if (order == 0x4949) /* "II" means little-endian */
+ return a | b << 8;
+ else /* "MM" means big-endian */
+ return a << 8 | b;
+}
+
+/*
+ Same for a 4-byte integer.
+ */
+int get4()
+{
+ uchar a, b, c, d;
+
+ a = fgetc(ifp); b = fgetc(ifp);
+ c = fgetc(ifp); d = fgetc(ifp);
+
+ if (order == 0x4949)
+ return a | b << 8 | c << 16 | d << 24;
+ else
+ return a << 24 | b << 16 | c << 8 | d;
+}
+
+void tiff_dump(int base, int tag, int type, int count, int level)
+{
+ int save, j, num, den;
+ uchar c;
+ int size[] = { 1,1,1,2,4,8,1,1,2,4,8,4,8 };
+
+ if (count * size[type < 13 ? type:0] > 4)
+ fseek (ifp, get4()+base, SEEK_SET);
+ save = ftell(ifp);
+ fseek (ifp, save, SEEK_SET);
+}
+
+void nikon_decrypt (uchar ci, uchar cj, int tag, int i, int size, uchar *buf)
+{
+}
+
+int parse_tiff_ifd (int base, int level);
+
+void nef_parse_makernote (base)
+{
+ int offset=0, entries, tag, type, count, val, save;
+ unsigned serial=0, key=0;
+ uchar buf91[630], buf97[608], buf98[31];
+ short sorder;
+ char buf[10];
+
+/*
+ The MakerNote might have its own TIFF header (possibly with
+ its own byte-order!), or it might just be a table.
+ */
+ sorder = order;
+ fread (buf, 1, 10, ifp);
+ if (!strcmp (buf,"Nikon")) { /* starts with "Nikon\0\2\0\0\0" ? */
+ base = ftell(ifp);
+ order = get2(); /* might differ from file-wide byteorder */
+ val = get2(); /* should be 42 decimal */
+ offset = get4();
+ fseek (ifp, offset-8, SEEK_CUR);
+ } else if (!strncmp (buf,"FUJIFILM",8) ||
+ !strcmp (buf,"Panasonic")) {
+ order = 0x4949;
+ fseek (ifp, 2, SEEK_CUR);
+ } else if (!strcmp (buf,"OLYMP") ||
+ !strcmp (buf,"LEICA") ||
+ !strcmp (buf,"EPSON"))
+ fseek (ifp, -2, SEEK_CUR);
+ else if (!strcmp (buf,"AOC"))
+ fseek (ifp, -4, SEEK_CUR);
+ else
+ fseek (ifp, -10, SEEK_CUR);
+
+ entries = get2();
+ if (entries > 100) return;
+ while (entries--) {
+ save = ftell(ifp);
+ tag = get2();
+ type = get2();
+ count= get4();
+ tiff_dump (base, tag, type, count, 2);
+ if (tag == 0x1d)
+ fscanf (ifp, "%d", &serial);
+ if (tag == 0x91)
+ fread (buf91, sizeof buf91, 1, ifp);
+ if (tag == 0x97)
+ fread (buf97, sizeof buf97, 1, ifp);
+ if (tag == 0x98)
+ fread (buf98, sizeof buf98, 1, ifp);
+ if (tag == 0xa7)
+ key = fgetc(ifp)^fgetc(ifp)^fgetc(ifp)^fgetc(ifp);
+
+ if (tag == 0x100 && type == 7 && !strncmp(make,"OLYMPUS",7)) {
+ thumb_offset = ftell(ifp);
+ thumb_length = count;
+ }
+ if (tag == 0x280 && type == 1) { /* EPSON */
+ strncpy (thumb_head, "\xff", sizeof(thumb_head) );
+ thumb_offset = ftell(ifp)+1;
+ thumb_length = count-1;
+ }
+ if (strstr(make,"Minolta") || strstr(make,"MINOLTA")) {
+ switch (tag) {
+ case 0x81:
+ thumb_offset = ftell(ifp);
+ thumb_length = count;
+ break;
+ case 0x88:
+ thumb_offset = get4() + base;
+ break;
+ case 0x89:
+ thumb_length = get4();
+ }
+ }
+ if (!strcmp (buf,"OLYMP") && tag >> 8 == 0x20)
+ parse_tiff_ifd (base, 3);
+ fseek (ifp, save+12, SEEK_SET);
+ }
+ nikon_decrypt (serial, key, 0x91, 4, sizeof buf91, buf91);
+ nikon_decrypt (serial, key, 0x97, 284, sizeof buf97, buf97);
+ nikon_decrypt (serial, key, 0x98, 4, sizeof buf98, buf98);
+ order = sorder;
+}
+
+void nef_parse_exif(int base)
+{
+ int entries, tag, type, count, save;
+
+ entries = get2();
+ while (entries--) {
+ save = ftell(ifp);
+ tag = get2();
+ type = get2();
+ count= get4();
+ tiff_dump (base, tag, type, count, 1);
+ if (tag == 0x927c)
+ nef_parse_makernote (base);
+ fseek (ifp, save+12, SEEK_SET);
+ }
+}
+
+int parse_tiff_ifd (int base, int level)
+{
+ int entries, tag, type, count, slen, save, save2, val, i;
+ int comp=0;
+ static const int flip_map[] = { 0,1,3,2,4,6,7,5 };
+
+ entries = get2();
+ if (entries > 255) return 1;
+ while (entries--) {
+ save = ftell(ifp);
+ tag = get2();
+ type = get2();
+ count= get4();
+ slen = count;
+ if (slen > 128) slen = 128;
+
+ tiff_dump (base, tag, type, count, level);
+
+ save2 = ftell(ifp);
+ if (type == 3) /* short int */
+ val = get2();
+ else
+ val = get4();
+ fseek (ifp, save2, SEEK_SET);
+
+ if (tag > 50700 && tag < 50800)
+ is_dng = 1;
+
+ if (level == 3) { /* Olympus E-1 and E-300 */
+ if (type == 4) {
+ if (tag == 0x101)
+ thumb_offset = val;
+ else if (tag == 0x102)
+ thumb_length = val;
+ }
+ goto cont;
+ }
+ switch (tag) {
+ case 0x100: /* ImageWidth */
+ if (!width) width = val;
+ break;
+ case 0x101: /* ImageHeight */
+ if (!height) height = val;
+ break;
+ case 0x102: /* Bits per sample */
+ if (bps) break;
+ bps = val;
+ if (count == 1)
+ thumb_layers = 1;
+ break;
+ case 0x103: /* Compression */
+ comp = val;
+ break;
+ case 0x10f: /* Make tag */
+ fgets (make, slen, ifp);
+ break;
+ case 0x110: /* Model tag */
+ fgets (model, slen, ifp);
+ break;
+ case 33405: /* Model2 tag */
+ fgets (model2, slen, ifp);
+ break;
+ case 0x111: /* StripOffset */
+ if (!offset || is_dng) offset = val;
+ break;
+ case 0x112: /* Orientation */
+ flip = flip_map[(val-1) & 7];
+ break;
+ case 0x117: /* StripByteCounts */
+ if (!length || is_dng) length = val;
+ if (offset > val && !strncmp(make,"KODAK",5) && !is_dng)
+ offset -= val;
+ break;
+ case 0x14a: /* SubIFD tag */
+ save2 = ftell(ifp);
+ for (i=0; i < count; i++) {
+ fseek (ifp, save2 + i*4, SEEK_SET);
+ fseek (ifp, get4()+base, SEEK_SET);
+ parse_tiff_ifd (base, level+1);
+ }
+ break;
+ case 0x201:
+ if (strncmp(make,"OLYMPUS",7) || !thumb_offset)
+ thumb_offset = val;
+ break;
+ case 0x202:
+ if (strncmp(make,"OLYMPUS",7) || !thumb_length)
+ thumb_length = val;
+ break;
+ case 34665:
+ fseek (ifp, get4()+base, SEEK_SET);
+ nef_parse_exif (base);
+ break;
+ case 50706:
+ is_dng = 1;
+ }
+cont:
+ fseek (ifp, save+12, SEEK_SET);
+ }
+ if ((comp == 6 && !strcmp(make,"Canon")) ||
+ (comp == 7 && is_dng)) {
+ thumb_offset = offset;
+ thumb_length = length;
+ }
+ return 0;
+}
+
+/*
+ Parse a TIFF file looking for camera model and decompress offsets.
+ */
+void parse_tiff (int base)
+{
+ int doff, spp=3, ifd=0;
+
+ width = height = offset = length = bps = is_dng = 0;
+ fseek (ifp, base, SEEK_SET);
+ order = get2();
+ if (order != 0x4949 && order != 0x4d4d) return;
+ get2();
+ while ((doff = get4())) {
+ fseek (ifp, doff+base, SEEK_SET);
+ printf ("IFD #%d:\n", ifd++);
+ if (parse_tiff_ifd (base, 0)) break;
+ }
+ if (is_dng) return;
+
+ if (strncmp(make,"KODAK",5))
+ thumb_layers = 0;
+ if (!strncmp(make,"Kodak",5)) {
+ fseek (ifp, 12+base, SEEK_SET);
+ puts ("\nSpecial Kodak image directory:");
+ parse_tiff_ifd (base, 0);
+ }
+ if (!strncmp(model,"DCS460A",7)) {
+ spp = 1;
+ thumb_layers = 0;
+ }
+ if (!thumb_length && offset) {
+ thumb_offset = offset;
+ sprintf (thumb_head, "P%d %d %d %d\n",
+ spp > 1 ? 6:5, width, height, (1 << bps) - 1);
+ thumb_length = width * height * spp * ((bps+7)/8);
+ }
+}
+
+void parse_minolta()
+{
+ int data_offset, save, tag, len;
+
+ fseek (ifp, 4, SEEK_SET);
+ data_offset = get4() + 8;
+ while ((save=ftell(ifp)) < data_offset) {
+ tag = get4();
+ len = get4();
+ printf ("Tag %c%c%c offset %06x length %06x\n",
+ tag>>16, tag>>8, tag, save, len);
+ switch (tag) {
+ case 0x545457: /* TTW */
+ parse_tiff (ftell(ifp));
+ }
+ fseek (ifp, save+len+8, SEEK_SET);
+ }
+ strncpy (thumb_head, "\xff", sizeof(thumb_head) );
+ thumb_offset++;
+ thumb_length--;
+}
+
+/*
+ Parse a CIFF file, better known as Canon CRW format.
+ */
+void parse_ciff (int offset, int length, int level /*unused*/)
+{
+ int tboff, nrecs, i, c, type, len, roff, aoff, save, wbi=-1;
+ static const int remap[] = { 1,2,3,4,5,1 };
+ static const int remap_10d[] = { 0,1,3,4,5,6,0,0,2,8 };
+ static const int remap_s70[] = { 0,1,2,9,4,3,6,7,8,9,10,0,0,0,7,0,0,8 };
+ ushort key[] = { 0x410, 0x45f3 };
+
+ if (strcmp(model,"Canon PowerShot G6") &&
+ strcmp(model,"Canon PowerShot S60") &&
+ strcmp(model,"Canon PowerShot S70") &&
+ strcmp(model,"Canon PowerShot Pro1"))
+ key[0] = key[1] = 0;
+ fseek (ifp, offset+length-4, SEEK_SET);
+ tboff = get4() + offset;
+ fseek (ifp, tboff, SEEK_SET);
+ nrecs = get2();
+ if (nrecs > 100) return;
+ for (i = 0; i < nrecs; i++) {
+ type = get2();
+ len = get4();
+ roff = get4();
+ aoff = offset + roff;
+ save = ftell(ifp);
+ if (type == 0x080a) { /* Get the camera make and model */
+ fseek (ifp, aoff, SEEK_SET);
+ fread (make, 64, 1, ifp);
+ fseek (ifp, aoff+strlen(make)+1, SEEK_SET);
+ fread (model, 64, 1, ifp);
+ }
+ if (type == 0x102a) { /* Find the White Balance index */
+ fseek (ifp, aoff+14, SEEK_SET); /* 0=auto, 1=daylight, 2=cloudy ... */
+ wbi = get2();
+ if (((!strcmp(model,"Canon EOS DIGITAL REBEL") ||
+ !strcmp(model,"Canon EOS 300D DIGITAL"))) && wbi == 6)
+ wbi++;
+ }
+ if (type == 0x102c) { /* Get white balance (G2) */
+ if (!strcmp(model,"Canon PowerShot G1") ||
+ !strcmp(model,"Canon PowerShot Pro90 IS")) {
+ fseek (ifp, aoff+120, SEEK_SET);
+ FORC4 cam_mul[c ^ 2] = get2();
+ } else {
+ fseek (ifp, aoff+100, SEEK_SET);
+ goto common;
+ }
+ }
+ if (type == 0x0032) { /* Get white balance (D30 & G3) */
+ if (!strcmp(model,"Canon EOS D30")) {
+ fseek (ifp, aoff+72, SEEK_SET);
+common:
+ camera_red = get2() ^ key[0];
+ camera_red =(get2() ^ key[1]) / camera_red;
+ camera_blue = get2() ^ key[0];
+ camera_blue /= get2() ^ key[1];
+ } else if (!strcmp(model,"Canon PowerShot G6") ||
+ !strcmp(model,"Canon PowerShot S60") ||
+ !strcmp(model,"Canon PowerShot S70")) {
+ fseek (ifp, aoff+96 + remap_s70[wbi]*8, SEEK_SET);
+ goto common;
+ } else if (!strcmp(model,"Canon PowerShot Pro1")) {
+ fseek (ifp, aoff+96 + wbi*8, SEEK_SET);
+ goto common;
+ } else {
+ fseek (ifp, aoff+80 + (wbi < 6 ? remap[wbi]*8 : 0), SEEK_SET);
+ if (!camera_red)
+ goto common;
+ }
+ }
+ if (type == 0x10a9) { /* Get white balance (D60) */
+ if (!strcmp(model,"Canon EOS 10D"))
+ wbi = remap_10d[wbi];
+ fseek (ifp, aoff+2 + wbi*8, SEEK_SET);
+ camera_red = get2();
+ camera_red /= get2();
+ camera_blue = get2();
+ camera_blue = get2() / camera_blue;
+ }
+ /* Skip this for now /steffen */
+#if 0
+ if (type == 0x1030 && (wbi == 6 || wbi == 15)) {
+ fseek (ifp, aoff, SEEK_SET); /* Get white sample */
+ ciff_block_1030();
+ }
+#endif
+ if (type == 0x1031) { /* Get the raw width and height */
+ fseek (ifp, aoff+2, SEEK_SET);
+ raw_width = get2();
+ raw_height = get2();
+ }
+ if (type == 0x180e) { /* Get the timestamp */
+ fseek (ifp, aoff, SEEK_SET);
+ timestamp = get4();
+ }
+ if (type == 0x580e)
+ timestamp = len;
+#if 0
+ if (type == 0x5813)
+ flash_used = *((float *) &len);
+ if (type == 0x5814)
+ canon_5814 = *((float *) &len);
+#endif
+ if (type == 0x1810) { /* Get the rotation */
+ fseek (ifp, aoff+12, SEEK_SET);
+ flip = get4();
+ }
+ /* Skip this for now /steffen */
+#if 0
+ if (type == 0x1835) { /* Get the decoder table */
+ fseek (ifp, aoff, SEEK_SET);
+ crw_init_tables (get4());
+ }
+#endif
+ if (type == 0x2007) { /* Found the JPEG thumbnail */
+ thumb_offset = aoff;
+ thumb_length = len;
+ }
+ if (type >> 8 == 0x28 || type >> 8 == 0x30) /* Get sub-tables */
+ parse_ciff(aoff, len, level+1);
+ fseek (ifp, save, SEEK_SET);
+ }
+ if (wbi == 0 && !strcmp(model,"Canon EOS D30"))
+ camera_red = -1; /* Use my auto WB for this photo */
+}
+
+
+void parse_mos(int level)
+{
+ uchar data[256];
+ int i, j, skip, save;
+ char *cp;
+
+ save = ftell(ifp);
+ while (1) {
+ fread (data, 1, 8, ifp);
+ if (strcmp(data,"PKTS")) break;
+ strcpy (model, "Valeo");
+ fread (data, 1, 40, ifp);
+ skip = get4();
+ if (!strcmp(data,"icc_camera_to_tone_matrix")) {
+ for (i=0; i < skip/4; i++) {
+ j = get4();
+ }
+ continue;
+ }
+ if (!strcmp(data,"JPEG_preview_data")) {
+ thumb_head[0] = 0;
+ thumb_offset = ftell(ifp);
+ thumb_length = skip;
+ }
+ fread (data, 1, sizeof data, ifp);
+ fseek (ifp, -sizeof data, SEEK_CUR);
+ data[sizeof data - 1] = 0;
+ while ((cp=index(data,'\n')))
+ *cp = ' ';
+ parse_mos(level+2);
+ fseek (ifp, skip, SEEK_CUR);
+ }
+ fseek (ifp, save, SEEK_SET);
+}
+
+void parse_rollei()
+{
+ char line[128], *val;
+
+ fseek (ifp, 0, SEEK_SET);
+ do {
+ fgets (line, 128, ifp);
+ fputs (line, stdout);
+ if ((val = strchr(line,'=')))
+ *val++ = 0;
+ else
+ val = line + strlen(line);
+ if (!strcmp(line,"HDR"))
+ thumb_offset = atoi(val);
+ if (!strcmp(line,"TX "))
+ width = atoi(val);
+ if (!strcmp(line,"TY "))
+ height = atoi(val);
+ } while (strncmp(line,"EOHD",4));
+ strcpy (make, "Rollei");
+ strcpy (model, "d530flex");
+ thumb_length = width*height*2;
+}
+
+void rollei_decode (FILE *tfp)
+{
+ ushort data;
+ int row, col;
+
+ fseek (ifp, thumb_offset, SEEK_SET);
+ fprintf (tfp, "P6\n%d %d\n255\n", width, height);
+ for (row=0; row < height; row++)
+ for (col=0; col < width; col++) {
+ fread (&data, 2, 1, ifp);
+ data = ntohs(data);
+ putc (data << 3, tfp);
+ putc (data >> 5 << 2, tfp);
+ putc (data >> 11 << 3, tfp);
+ }
+}
+
+void get_utf8 (int offset, char *buf, int len)
+{
+ ushort c;
+ char *cp;
+
+ fseek (ifp, offset, SEEK_SET);
+ for (cp=buf; (c = get2()) && cp+3 < buf+len; ) {
+ if (c < 0x80)
+ *cp++ = c;
+ else if (c < 0x800) {
+ *cp++ = 0xc0 + (c >> 6);
+ *cp++ = 0x80 + (c & 0x3f);
+ } else {
+ *cp++ = 0xe0 + (c >> 12);
+ *cp++ = 0x80 + (c >> 6 & 0x3f);
+ *cp++ = 0x80 + (c & 0x3f);
+ }
+ }
+ *cp = 0;
+}
+
+ushort sget2 (uchar *s)
+{
+ return s[0] + (s[1]<<8);
+}
+
+int sget4 (uchar *s)
+{
+ return s[0] + (s[1]<<8) + (s[2]<<16) + (s[3]<<24);
+}
+
+void parse_foveon()
+{
+ int entries, img=0, off, len, tag, save, i, j, k, pent, poff[256][2];
+ char name[128], value[128], camf[0x20000], *pos, *cp, *dp;
+ unsigned val, key, type, num, ndim, dim[3];
+
+ order = 0x4949; /* Little-endian */
+ fseek (ifp, -4, SEEK_END);
+ fseek (ifp, get4(), SEEK_SET);
+ if (get4() != 0x64434553) { /* SECd */
+ printf ("Bad Section identifier at %6x\n", (int)ftell(ifp)-4);
+ return;
+ }
+ get4();
+ entries = get4();
+ while (entries--) {
+ off = get4();
+ len = get4();
+ tag = get4();
+ save = ftell(ifp);
+ fseek (ifp, off, SEEK_SET);
+ if (get4() != (0x20434553 | (tag << 24))) {
+ printf ("Bad Section identifier at %6x\n", off);
+ goto next;
+ }
+ val = get4();
+ switch (tag) {
+ case 0x32414d49: /* IMA2 */
+ case 0x47414d49: /* IMAG */
+ if (++img == 2) { /* second image */
+ thumb_offset = off;
+ thumb_length = 1;
+ }
+ printf ("type %d, " , get4());
+ printf ("format %2d, " , get4());
+ printf ("columns %4d, " , get4());
+ printf ("rows %4d, " , get4());
+ printf ("rowsize %d\n" , get4());
+ break;
+ case 0x464d4143: /* CAMF */
+ printf ("type %d, ", get4());
+ get4();
+ for (i=0; i < 4; i++)
+ putchar(fgetc(ifp));
+ val = get4();
+ printf (" version %d.%d:\n",val >> 16, val & 0xffff);
+ key = get4();
+ if ((len -= 28) > 0x20000)
+ len = 0x20000;
+ fread (camf, 1, len, ifp);
+ for (i=0; i < len; i++) {
+ key = (key * 1597 + 51749) % 244944;
+ val = key * (INT64) 301593171 >> 24;
+ camf[i] ^= ((((key << 8) - val) >> 1) + val) >> 17;
+ }
+ for (pos=camf; (unsigned) (pos-camf) < len; pos += sget4(pos+8)) {
+ if (strncmp (pos, "CMb", 3)) {
+ printf("Bad CAMF tag \"%.4s\"\n", pos);
+ break;
+ }
+ val = sget4(pos+4);
+ printf (" %4.4s version %d.%d: ", pos, val >> 16, val & 0xffff);
+ switch (pos[3]) {
+ case 'M':
+ cp = pos + sget4(pos+16);
+ type = sget4(cp);
+ ndim = sget4(cp+4);
+ dim[0] = dim[1] = dim[2] = 1;
+ printf ("%d-dimensonal array %s of type %d:\n Key: (",
+ ndim, pos+sget4(pos+12), sget4(cp));
+ dp = pos + sget4(cp+8);
+ for (i=ndim; i--; ) {
+ cp += 12;
+ dim[i] = sget4(cp);
+ printf ("%s %d%s", pos+sget4(cp+4), dim[i], i ? ", ":")\n");
+ }
+ for (i=0; i < dim[2]; i++) {
+ for (j=0; j < dim[1]; j++) {
+ printf (" ");
+ for (k=0; k < dim[0]; k++)
+ switch (type) {
+ case 0:
+ case 6:
+ printf ("%7d", sget2(dp));
+ dp += 2;
+ break;
+ case 1:
+ case 2:
+ printf (" %d", sget4(dp));
+ dp += 4;
+ break;
+ case 3: {
+ union { int ival; float fval; } __t;
+ __t.ival = sget4(dp);
+ printf (" %9f", __t.fval);
+ dp += 4;
+ }
+ }
+ printf ("\n");
+ }
+ printf ("\n");
+ }
+ break;
+ case 'P':
+ val = sget4(pos+16);
+ num = sget4(pos+val);
+ printf ("%s, %d parameters:\n", pos+sget4(pos+12), num);
+ cp = pos+val+8 + num*8;
+ for (i=0; i < num; i++) {
+ val += 8;
+ printf (" %s = %s\n", cp+sget4(pos+val), cp+sget4(pos+val+4));
+ }
+ break;
+ case 'T':
+ cp = pos + sget4(pos+16);
+ printf ("%s = %.*s\n", pos+sget4(pos+12), sget4(cp), cp+4);
+ break;
+ default:
+ printf ("\n");
+ }
+ }
+ break;
+ case 0x504f5250: /* PROP */
+ printf ("entries %d, ", pent=get4());
+ printf ("charset %d, ", get4());
+ get4();
+ printf ("nchars %d\n", get4());
+ off += pent*8 + 24;
+ if (pent > 256) pent=256;
+ for (i=0; i < pent*2; i++)
+ poff[0][i] = off + get4()*2;
+ for (i=0; i < pent; i++) {
+ get_utf8 (poff[i][0], name, 128);
+ get_utf8 (poff[i][1], value, 128);
+ printf (" %s = %s\n", name, value);
+ if (!strcmp (name,"CAMMANUF"))
+ strncpy (make, value, sizeof(make));
+ if (!strcmp (name,"CAMMODEL"))
+ strncpy (model, value, sizeof(value));
+ }
+ }
+next:
+ fseek (ifp, save, SEEK_SET);
+ }
+}
+
+void foveon_tree (unsigned huff[1024], unsigned code)
+{
+ struct decode *cur;
+ int i, len;
+
+ cur = free_decode++;
+ if (code) {
+ for (i=0; i < 1024; i++)
+ if (huff[i] == code) {
+ cur->leaf = i;
+ return;
+ }
+ }
+ if ((len = code >> 27) > 26) return;
+ code = (len+1) << 27 | (code & 0x3ffffff) << 1;
+
+ cur->branch[0] = free_decode;
+ foveon_tree (huff, code);
+ cur->branch[1] = free_decode;
+ foveon_tree (huff, code+1);
+}
+
+void foveon_decode (FILE *tfp)
+{
+ int bwide, row, col, bit=-1, c, i;
+ char *buf;
+ struct decode *dindex;
+ short pred[3];
+ unsigned huff[1024], bitbuf=0;
+
+ fseek (ifp, thumb_offset+16, SEEK_SET);
+ width = get4();
+ height = get4();
+ bwide = get4();
+ fprintf (tfp, "P6\n%d %d\n255\n", width, height);
+ if (bwide > 0) {
+ buf = malloc(bwide);
+ for (row=0; row < height; row++) {
+ fread (buf, 1, bwide, ifp);
+ fwrite (buf, 3, width, tfp);
+ }
+ free (buf);
+ return;
+ }
+ for (i=0; i < 256; i++)
+ huff[i] = get4();
+ memset (first_decode, 0, sizeof first_decode);
+ free_decode = first_decode;
+ foveon_tree (huff, 0);
+
+ for (row=0; row < height; row++) {
+ memset (pred, 0, sizeof pred);
+ if (!bit) get4();
+ for (col=bit=0; col < width; col++) {
+ for (c=0; c < 3; c++) {
+ for (dindex=first_decode; dindex->branch[0]; ) {
+ if ((bit = (bit-1) & 31) == 31)
+ for (i=0; i < 4; i++)
+ bitbuf = (bitbuf << 8) + fgetc(ifp);
+ dindex = dindex->branch[bitbuf >> bit & 1];
+ }
+ pred[c] += dindex->leaf;
+ fputc (pred[c], tfp);
+ }
+ }
+ }
+}
+
+void kodak_yuv_decode (FILE *tfp)
+{
+ uchar c, blen[384];
+ unsigned row, col, len, bits=0;
+ INT64 bitbuf=0;
+ int i, li=0, si, diff, six[6], y[4], cb=0, cr=0, rgb[3];
+ ushort *out, *op;
+
+ fseek (ifp, thumb_offset, SEEK_SET);
+ width = (width+1) & -2;
+ height = (height+1) & -2;
+ fprintf (tfp, "P6\n%d %d\n65535\n", width, height);
+ out = malloc (width * 12);
+ if (!out) {
+ fprintf (stderr, "kodak_yuv_decode() malloc failed!\n");
+ exit(1);
+ }
+
+ for (row=0; row < height; row+=2) {
+ for (col=0; col < width; col+=2) {
+ if ((col & 127) == 0) {
+ len = (width - col + 1) * 3 & -4;
+ if (len > 384) len = 384;
+ for (i=0; i < len; ) {
+ c = fgetc(ifp);
+ blen[i++] = c & 15;
+ blen[i++] = c >> 4;
+ }
+ li = bitbuf = bits = y[1] = y[3] = cb = cr = 0;
+ if (len % 8 == 4) {
+ bitbuf = fgetc(ifp) << 8;
+ bitbuf += fgetc(ifp);
+ bits = 16;
+ }
+ }
+ for (si=0; si < 6; si++) {
+ len = blen[li++];
+ if (bits < len) {
+ for (i=0; i < 32; i+=8)
+ bitbuf += (INT64) fgetc(ifp) << (bits+(i^8));
+ bits += 32;
+ }
+ diff = bitbuf & (0xffff >> (16-len));
+ bitbuf >>= len;
+ bits -= len;
+ if ((diff & (1 << (len-1))) == 0)
+ diff -= (1 << len) - 1;
+ six[si] = diff;
+ }
+ y[0] = six[0] + y[1];
+ y[1] = six[1] + y[0];
+ y[2] = six[2] + y[3];
+ y[3] = six[3] + y[2];
+ cb += six[4];
+ cr += six[5];
+ for (i=0; i < 4; i++) {
+ op = out + ((i >> 1)*width + col+(i & 1)) * 3;
+ rgb[0] = y[i] + 1.40200/2 * cr;
+ rgb[1] = y[i] - 0.34414/2 * cb - 0.71414/2 * cr;
+ rgb[2] = y[i] + 1.77200/2 * cb;
+ for (c=0; c < 3; c++)
+ if (rgb[c] > 0) op[c] = htons(rgb[c]);
+ }
+ }
+ fwrite (out, sizeof *out, width*6, tfp);
+ }
+ free(out);
+}
+
+void parse_phase_one (int base)
+{
+ unsigned entries, tag, type, len, data, save;
+ char str[256];
+
+ fseek (ifp, base + 8, SEEK_SET);
+ fseek (ifp, base + get4(), SEEK_SET);
+ entries = get4();
+ get4();
+ while (entries--) {
+ tag = get4();
+ type = get4();
+ len = get4();
+ data = get4();
+ save = ftell(ifp);
+ printf ("Phase One tag=0x%x, type=%d, len=%2d, data = 0x%x\n",
+ tag, type, len, data);
+ if (type == 1 && len < 256) {
+ fseek (ifp, base + data, SEEK_SET);
+ fread (str, 256, 1, ifp);
+ puts (str);
+ }
+ if (tag == 0x110) {
+ thumb_offset = data + base;
+ thumb_length = len;
+ }
+ fseek (ifp, save, SEEK_SET);
+ }
+ strcpy (make, "Phase One");
+ strcpy (model, "unknown");
+}
+
+void parse_jpeg (int offset)
+{
+ int len, save, hlen;
+
+ fseek (ifp, offset, SEEK_SET);
+ if (fgetc(ifp) != 0xff || fgetc(ifp) != 0xd8) return;
+
+ while (fgetc(ifp) == 0xff && fgetc(ifp) >> 4 != 0xd) {
+ order = 0x4d4d;
+ len = get2() - 2;
+ save = ftell(ifp);
+ order = get2();
+ hlen = get4();
+ if (get4() == 0x48454150) /* "HEAP" */
+ parse_ciff (save+hlen, len-hlen, 0);
+ parse_tiff (save+6);
+ fseek (ifp, save+len, SEEK_SET);
+ }
+}
+
+char *raw_memmem (char *haystack, size_t haystacklen,
+ char *needle, size_t needlelen)
+{
+ char *c;
+ for (c = haystack; c <= haystack + haystacklen - needlelen; c++)
+ if (!memcmp (c, needle, needlelen))
+ return c;
+ return NULL;
+}
+
+/*
+ Identify which camera created this file, and set global variables
+ accordingly.
+ Return nonzero if the file cannot be decoded or no thumbnail is found
+ */
+int identify(FILE* tfp)
+{
+ char head[32], *thumb, *rgb, *cp;
+ unsigned hlen, fsize, toff, tlen, lsize, i;
+
+ make[0] = model[0] = model2[0] = is_dng = 0;
+ thumb_head[0] = thumb_offset = thumb_length = thumb_layers = 0;
+ order = get2();
+ hlen = get4();
+ fseek (ifp, 0, SEEK_SET);
+ fread (head, 1, 32, ifp);
+ fseek (ifp, 0, SEEK_END);
+ fsize = ftell(ifp);
+ if ((cp = raw_memmem (head, 32, "MMMMRawT", 8)) ||
+ (cp = raw_memmem (head, 32, "IIIITwaR", 8)))
+ parse_phase_one (cp - head);
+ else if (order == 0x4949 || order == 0x4d4d) {
+ if (!memcmp(head+6,"HEAPCCDR",8)) {
+ parse_ciff (hlen, fsize - hlen, 0);
+ fseek (ifp, hlen, SEEK_SET);
+ } else
+ parse_tiff (0);
+ } else if (!memcmp (head, "\0MRM", 4))
+ parse_minolta();
+ else if (!memcmp (head, "\xff\xd8\xff\xe1", 4) &&
+ !memcmp (head+6, "Exif", 4)) {
+ parse_tiff (12);
+ thumb_length = 0;
+ } else if (!memcmp (head, "FUJIFILM", 8)) {
+ fseek (ifp, 84, SEEK_SET);
+ toff = get4();
+ tlen = get4();
+ thumb_offset = toff;
+ thumb_length = tlen;
+ } else if (!memcmp (head, "DSC-Image", 9))
+ parse_rollei();
+ else if (!memcmp (head, "FOVb", 4))
+ parse_foveon();
+ fseek (ifp, 8, SEEK_SET);
+ parse_mos(0);
+ fseek (ifp, 3472, SEEK_SET);
+ parse_mos(0);
+ parse_jpeg(0);
+
+ if (!thumb_length) {
+ fprintf (stderr, "Thumbnail image not found\n");
+ return -1;
+ }
+
+ if (is_dng) goto dng_skip;
+ if (!strncmp(model,"DCS Pro",7)) {
+ kodak_yuv_decode (tfp);
+ goto done;
+ }
+ if (!strcmp(make,"Rollei")) {
+ rollei_decode (tfp);
+ goto done;
+ }
+ if (!strcmp(make,"SIGMA")) {
+ foveon_decode (tfp);
+ goto done;
+ }
+dng_skip:
+ thumb = (char *) malloc(thumb_length);
+ if (!thumb) {
+ fprintf (stderr, "Cannot allocate %d bytes!!\n", thumb_length);
+ exit(1);
+ }
+ fseek (ifp, thumb_offset, SEEK_SET);
+ fread (thumb, 1, thumb_length, ifp);
+ if (thumb_layers && !is_dng) {
+ rgb = (char *) malloc(thumb_length);
+ if (!rgb) {
+ fprintf (stderr, "Cannot allocate %d bytes!!\n", thumb_length);
+ return -1;
+ }
+ lsize = thumb_length/3;
+ for (i=0; i < thumb_length; i++)
+ rgb[(i%lsize)*3 + i/lsize] = thumb[i];
+ free(thumb);
+ thumb = rgb;
+ }
+ fputs (thumb_head, tfp);
+ fwrite(thumb, 1, thumb_length, tfp);
+ free (thumb);
+done:
+ fprintf (stderr, "Thumbnail image written, make=%s, model=%s\n",&(make[0]),&(model[0]));
+ return 0;
+}
+
+int extract_thumbnail( FILE* input, FILE* output, int* orientation )
+{
+ /* Coffin's code has different meaning for orientation
+ values than TIFF, so we map them to TIFF values */
+ static const int flip_map[] = { 0,1,3,2,4,7,5,6 };
+ int rc;
+ ifp = input;
+ rc = identify(output);
+ switch ((flip+3600) % 360) {
+ case 270: flip = 5; break;
+ case 180: flip = 3; break;
+ case 90: flip = 6;
+ }
+ if( orientation ) *orientation = flip_map[flip%7];
+ return rc;
+}
diff --git a/kfile-plugins/rgb/Makefile.am b/kfile-plugins/rgb/Makefile.am
new file mode 100644
index 00000000..8fc22e17
--- /dev/null
+++ b/kfile-plugins/rgb/Makefile.am
@@ -0,0 +1,22 @@
+## Makefile.am for rgb file meta info plugin
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = kfile_rgb.h
+
+kde_module_LTLIBRARIES = kfile_rgb.la
+
+kfile_rgb_la_SOURCES = kfile_rgb.cpp
+kfile_rgb_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_rgb_la_LIBADD = $(LIB_KSYCOCA)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) kfile_rgb.cpp -o $(podir)/kfile_rgb.pot
+
+services_DATA = kfile_rgb.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kfile-plugins/rgb/kfile_rgb.cpp b/kfile-plugins/rgb/kfile_rgb.cpp
new file mode 100644
index 00000000..b7b55035
--- /dev/null
+++ b/kfile-plugins/rgb/kfile_rgb.cpp
@@ -0,0 +1,208 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2004 Melchior FRANZ <mfranz@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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <config.h>
+#include "kfile_rgb.h"
+
+#include <qfile.h>
+#include <qvalidator.h>
+
+#include <kdebug.h>
+#include <kgenericfactory.h>
+
+
+typedef KGenericFactory<KRgbPlugin> RgbFactory;
+
+K_EXPORT_COMPONENT_FACTORY(kfile_rgb, RgbFactory("kfile_rgb"))
+
+
+KRgbPlugin::KRgbPlugin(QObject *parent, const char *name, const QStringList &args) :
+ KFilePlugin(parent, name, args)
+{
+ KFileMimeTypeInfo* info = addMimeTypeInfo("image/x-rgb");
+
+ KFileMimeTypeInfo::GroupInfo* group = 0;
+ KFileMimeTypeInfo::ItemInfo* item;
+
+
+ group = addGroupInfo(info, "Comment", i18n("Comment"));
+
+ item = addItemInfo(group, "ImageName", i18n("Name"), QVariant::String);
+ setAttributes(item, KFileMimeTypeInfo::Modifiable);
+ setHint(item, KFileMimeTypeInfo::Description);
+
+
+ group = addGroupInfo(info, "Technical", i18n("Technical Details"));
+
+ item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size);
+ setHint(item, KFileMimeTypeInfo::Size);
+ setUnit(item, KFileMimeTypeInfo::Pixels);
+
+ item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int);
+ setUnit(item, KFileMimeTypeInfo::BitsPerPixel);
+
+ item = addItemInfo(group, "ColorMode", i18n("Color Mode"), QVariant::String);
+ item = addItemInfo(group, "Compression", i18n("Compression"), QVariant::String);
+ item = addItemInfo(group, "SharedRows",
+ i18n("percentage of avoided vertical redundancy (the higher the better)",
+ "Shared Rows"), QVariant::String);
+
+}
+
+
+bool KRgbPlugin::readInfo(KFileMetaInfo& info, uint /*what*/)
+{
+ QFile file(info.path());
+
+ if (!file.open(IO_ReadOnly)) {
+ kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl;
+ return false;
+ }
+
+ QDataStream dstream(&file);
+
+ Q_UINT16 magic;
+ Q_UINT8 storage;
+ Q_UINT8 bpc;
+ Q_UINT16 dimension;
+ Q_UINT16 xsize;
+ Q_UINT16 ysize;
+ Q_UINT16 zsize;
+ Q_UINT32 pixmin;
+ Q_UINT32 pixmax;
+ Q_UINT32 dummy;
+ char imagename[80];
+ Q_UINT32 colormap;
+
+ dstream >> magic;
+ dstream >> storage;
+ dstream >> bpc;
+ dstream >> dimension;
+ dstream >> xsize;
+ dstream >> ysize;
+ dstream >> zsize;
+ dstream >> pixmin;
+ dstream >> pixmax;
+ dstream >> dummy;
+ dstream.readRawBytes(imagename, 80);
+ imagename[79] = '\0';
+ dstream >> colormap;
+ Q_UINT8 u8;
+ for (uint i = 0; i < 404; i++)
+ dstream >> u8;
+
+ if (magic != 474)
+ return false;
+
+ KFileMetaInfoGroup group;
+
+ group = appendGroup(info, "Technical");
+
+ if (dimension == 1)
+ ysize = 1;
+ appendItem(group, "Dimensions", QSize(xsize, ysize));
+ appendItem(group, "BitDepth", zsize * 8 * bpc);
+
+ if (zsize == 1)
+ appendItem(group, "ColorMode", i18n("Grayscale"));
+ else if (zsize == 2)
+ appendItem(group, "ColorMode", i18n("Grayscale/Alpha"));
+ else if (zsize == 3)
+ appendItem(group, "ColorMode", i18n("RGB"));
+ else if (zsize == 4)
+ appendItem(group, "ColorMode", i18n("RGB/Alpha"));
+
+ if (!storage)
+ appendItem(group, "Compression", i18n("Uncompressed"));
+ else if (storage == 1) {
+ long compressed = file.size() - 512;
+ long verbatim = xsize * ysize * zsize;
+ appendItem(group, "Compression", i18n("Runlength Encoded")
+ + QString(", %1%").arg(compressed * 100.0 / verbatim, 0, 'f', 1));
+
+ long k;
+ Q_UINT32 offs;
+ QMap<Q_UINT32, uint> map;
+ QMap<Q_UINT32, uint>::Iterator it;
+ QMap<Q_UINT32, uint>::Iterator end = map.end();
+ for (k = 0; k < (ysize * zsize); k++) {
+ dstream >> offs;
+ if ((it = map.find(offs)) != end)
+ map.replace(offs, it.data() + 1);
+ else
+ map[offs] = 0;
+ }
+ for (k = 0, it = map.begin(); it != end; ++it)
+ k += it.data();
+
+ if (k)
+ appendItem(group, "SharedRows", QString("%1%").arg(k * 100.0
+ / (ysize * zsize), 0, 'f', 1));
+ else
+ appendItem(group, "SharedRows", i18n("None"));
+ } else
+ appendItem(group, "Compression", i18n("Unknown"));
+
+
+ group = appendGroup(info, "Comment");
+ appendItem(group, "ImageName", imagename);
+
+ file.close();
+ return true;
+}
+
+
+bool KRgbPlugin::writeInfo(const KFileMetaInfo& info) const
+{
+ QFile file(info.path());
+
+ if (!file.open(IO_WriteOnly|IO_Raw)) {
+ kdDebug(7034) << "couldn't open " << QFile::encodeName(info.path()) << endl;
+ return false;
+ }
+
+ if (!file.at(24)) {
+ kdDebug(7034) << "couldn't set offset" << endl;
+ return false;
+ }
+
+ QDataStream dstream(&file);
+ QString s = info["Comment"]["ImageName"].value().toString();
+ s.truncate(79);
+
+ unsigned i;
+ for (i = 0; i < s.length(); i++)
+ dstream << Q_UINT8(s.latin1()[i]);
+ for (; i < 80; i++)
+ dstream << Q_UINT8(0);
+
+ file.close();
+ return true;
+}
+
+
+// restrict to 79 ASCII characters
+QValidator* KRgbPlugin::createValidator(const QString&, const QString &,
+ const QString &, QObject* parent, const char* name) const
+{
+ return new QRegExpValidator(QRegExp("[\x0020-\x007E]{79}"), parent, name);
+}
+
+
+#include "kfile_rgb.moc"
diff --git a/kfile-plugins/rgb/kfile_rgb.desktop b/kfile-plugins/rgb/kfile_rgb.desktop
new file mode 100644
index 00000000..3a02989d
--- /dev/null
+++ b/kfile-plugins/rgb/kfile_rgb.desktop
@@ -0,0 +1,61 @@
+[Desktop Entry]
+Type=Service
+Name=SGI Image (RGB)
+Name[br]=Skeudenn SGI (RGB)
+Name[bs]=SGI slika (RGB)
+Name[ca]=Imatge SGI (RGB)
+Name[cs]=SGI obrázek (RGB)
+Name[cy]=Delwedd SGI (RGB)
+Name[da]=SGI-billede (RGB)
+Name[de]=SGI-Bild (RGB)
+Name[el]=Εικόνα SGI (RGB)
+Name[es]=Imagen SGI (RGB)
+Name[et]=SGI pildifail (RGB)
+Name[eu]=SGI irudia RGB)
+Name[fa]=تصویر SGI (RGB)
+Name[fi]=SGI-kuva (RGB)
+Name[fr]=Image SGI (RVB)
+Name[ga]=Íomhá SGI (RGB)
+Name[gl]=Imaxe SGI (RGB)
+Name[he]=תמונת SGI (RGB)
+Name[hr]=SGI slika (RGB)
+Name[hu]=SGI-kép (RGB)
+Name[is]=SGI mynd (TGB)
+Name[it]=Immagine SGI (RGB)
+Name[ja]=SGI 画像 (RGB)
+Name[kk]=SGI кескіні (RGB)
+Name[km]=រូបភាព SGI (RGB)
+Name[lt]=SGI paveiksliukas (RGB)
+Name[ms]=Imej SGI (RGB)
+Name[nb]=Bildeindeks
+Name[nds]=SGI-Bild (RGB)
+Name[ne]=SGI छवि (RGB)
+Name[nl]=SGI-afbeelding (RGB)
+Name[nn]=SGI-bilete (RGB)
+Name[pl]=Obrazek SGI (RGB)
+Name[pt]=Imagem SGI (RGB)
+Name[pt_BR]=Imagem SGI (RGB)
+Name[ro]=Imagine SGI (RGB)
+Name[ru]=Изображение SGI (RGB)
+Name[rw]=SGI Ishusho (RGB)
+Name[se]=SGI-govva (RGB)
+Name[sk]=SGI obrázok (RGB)
+Name[sl]=Slika SGI (RGB)
+Name[sr]=SGI слика (RGB)
+Name[sr@Latn]=SGI slika (RGB)
+Name[sv]=SGI-bild (RGB)
+Name[ta]=எஸ்ஜிஐ படிமம் (RGB)
+Name[tg]=Тасвироти SGI (RGB)
+Name[th]=ภาพ SGI (RGB)
+Name[tr]=SGI Resmi(KYM)
+Name[uk]=Зображення SGI (RGB)
+Name[uz]=SGI-rasm (RGB)
+Name[uz@cyrillic]=SGI-расм (RGB)
+Name[zh_CN]=SGI 图像(RGB)
+Name[zh_HK]=SGI 圖像 (RGB)
+Name[zh_TW]=SGI 影像(RGB)
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_rgb
+MimeType=image/x-rgb
+PreferredGroups=Comment,Technical
+PreferredItems=Dimensions,BitDepth,ColorMode,Compression,SharedRows,ImageName
diff --git a/kfile-plugins/rgb/kfile_rgb.h b/kfile-plugins/rgb/kfile_rgb.h
new file mode 100644
index 00000000..dbbfef0e
--- /dev/null
+++ b/kfile-plugins/rgb/kfile_rgb.h
@@ -0,0 +1,41 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2004 Melcrhio FRANZ <mfranz@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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __KFILE_RGB_H__
+#define __KFILE_RGB_H__
+
+#include <kfilemetainfo.h>
+
+class QStringList;
+
+class KRgbPlugin : public KFilePlugin
+{
+ Q_OBJECT
+
+public:
+ KRgbPlugin(QObject *parent, const char *name, const QStringList& args);
+ virtual bool readInfo(KFileMetaInfo& info, uint what);
+ virtual bool writeInfo(const KFileMetaInfo& info) const;
+ virtual QValidator* createValidator(const QString& mimetype,
+ const QString &group, const QString &key,
+ QObject* parent, const char* name) const;
+
+};
+
+#endif
diff --git a/kfile-plugins/tga/Makefile.am b/kfile-plugins/tga/Makefile.am
new file mode 100644
index 00000000..3856c26f
--- /dev/null
+++ b/kfile-plugins/tga/Makefile.am
@@ -0,0 +1,22 @@
+## Makefile.am for tga file meta info plugin
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = kfile_tga.h
+
+kde_module_LTLIBRARIES = kfile_tga.la
+
+kfile_tga_la_SOURCES = kfile_tga.cpp
+kfile_tga_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_tga_la_LIBADD = $(LIB_KSYCOCA)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) kfile_tga.cpp -o $(podir)/kfile_tga.pot
+
+services_DATA = kfile_tga.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kfile-plugins/tga/kfile_tga.cpp b/kfile-plugins/tga/kfile_tga.cpp
new file mode 100644
index 00000000..9c2c24dc
--- /dev/null
+++ b/kfile-plugins/tga/kfile_tga.cpp
@@ -0,0 +1,165 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Shane Wright <me@shanewright.co.uk>
+ *
+ * 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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <config.h>
+#include "kfile_tga.h"
+
+#include <kprocess.h>
+#include <klocale.h>
+#include <kgenericfactory.h>
+#include <kstringvalidator.h>
+#include <kdebug.h>
+
+#include <qdict.h>
+#include <qvalidator.h>
+#include <qcstring.h>
+#include <qfile.h>
+#include <qdatetime.h>
+
+#if !defined(__osf__)
+#include <inttypes.h>
+#else
+typedef unsigned long uint32_t;
+typedef unsigned short uint16_t;
+typedef unsigned char uint8_t;
+#endif
+
+typedef KGenericFactory<KTgaPlugin> TgaFactory;
+
+K_EXPORT_COMPONENT_FACTORY(kfile_tga, TgaFactory( "kfile_tga" ))
+
+KTgaPlugin::KTgaPlugin(QObject *parent, const char *name,
+ const QStringList &args)
+
+ : KFilePlugin(parent, name, args)
+{
+ KFileMimeTypeInfo* info = addMimeTypeInfo( "image/x-targa" );
+
+ KFileMimeTypeInfo::GroupInfo* group = 0L;
+
+ group = addGroupInfo(info, "Technical", i18n("Technical Details"));
+
+ KFileMimeTypeInfo::ItemInfo* item;
+
+ item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size);
+ setHint( item, KFileMimeTypeInfo::Size );
+ setUnit(item, KFileMimeTypeInfo::Pixels);
+
+ item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int);
+ setUnit(item, KFileMimeTypeInfo::BitsPerPixel);
+
+ item = addItemInfo(group, "ColorMode", i18n("Color Mode"), QVariant::String);
+ item = addItemInfo(group, "Compression", i18n("Compression"), QVariant::String);
+
+}
+
+bool KTgaPlugin::readInfo( KFileMetaInfo& info, uint what)
+{
+
+
+ QFile file(info.path());
+
+ if (!file.open(IO_ReadOnly))
+ {
+ kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl;
+ return false;
+ }
+
+ QDataStream dstream(&file);
+
+ // TGA files are little-endian
+ dstream.setByteOrder(QDataStream::LittleEndian);
+
+ // the vars for the image data
+ uint8_t tga_idlength;
+ uint8_t tga_colormaptype;
+ uint8_t tga_imagetype;
+ uint16_t tga_colormap_fei;
+ uint16_t tga_colormap_length;
+ uint8_t tga_colormap_entrysize;
+ uint16_t tga_imagespec_origin_x;
+ uint16_t tga_imagespec_origin_y;
+ uint16_t tga_imagespec_width;
+ uint16_t tga_imagespec_height;
+ uint8_t tga_imagespec_depth;
+ uint8_t tga_imagespec_descriptor;
+
+ // read the image data
+ dstream >> tga_idlength;
+ dstream >> tga_colormaptype;
+ dstream >> tga_imagetype;
+ dstream >> tga_colormap_fei;
+ dstream >> tga_colormap_length;
+ dstream >> tga_colormap_entrysize;
+ dstream >> tga_imagespec_origin_x;
+ dstream >> tga_imagespec_origin_y;
+ dstream >> tga_imagespec_width;
+ dstream >> tga_imagespec_height;
+ dstream >> tga_imagespec_depth;
+ dstream >> tga_imagespec_descriptor;
+
+ // output the useful bits
+ KFileMetaInfoGroup group = appendGroup(info, "Technical");
+ appendItem(group, "Dimensions", QSize(tga_imagespec_width, tga_imagespec_height));
+ appendItem(group, "BitDepth", tga_imagespec_depth);
+
+ switch (tga_imagetype) {
+ case 1 :
+ case 9 :
+ case 32 :
+ appendItem(group, "ColorMode", i18n("Color-Mapped"));
+ break;
+ case 2 :
+ case 10 :
+ case 33 :
+ appendItem(group, "ColorMode", i18n("RGB"));
+ break;
+ case 3 :
+ case 11 :
+ appendItem(group, "ColorMode", i18n("Black and White"));
+ break;
+ default :
+ appendItem(group, "ColorMode", i18n("Unknown"));
+ }
+
+ switch (tga_imagetype) {
+ case 1 :
+ case 2 :
+ case 3 :
+ appendItem(group, "Compression", i18n("Uncompressed"));
+ break;
+ case 9 :
+ case 10 :
+ case 11 :
+ appendItem(group, "Compression", i18n("Runlength Encoded"));
+ break;
+ case 32 :
+ appendItem(group, "Compression", i18n("Huffman, Delta & RLE"));
+ break;
+ case 33 :
+ appendItem(group, "Compression", i18n("Huffman, Delta, RLE (4-pass quadtree)"));
+ break;
+ default :
+ appendItem(group, "Compression", i18n("Unknown"));
+ };
+
+ return true;
+}
+
+#include "kfile_tga.moc"
diff --git a/kfile-plugins/tga/kfile_tga.desktop b/kfile-plugins/tga/kfile_tga.desktop
new file mode 100644
index 00000000..a4578368
--- /dev/null
+++ b/kfile-plugins/tga/kfile_tga.desktop
@@ -0,0 +1,64 @@
+[Desktop Entry]
+Type=Service
+Name=Truevision Targa Info
+Name[ar]=معلومات Truevision Targa
+Name[br]=Gorretaol Truevision Targa
+Name[ca]=Informació de Targa Truevision
+Name[cs]=Truevision Targa info
+Name[cy]=Gwybodaeth Truevision Targa
+Name[da]=Truevision Targa-info
+Name[de]=Truevision Targa-Info
+Name[el]=Πληροφορίες Truevision Targa
+Name[eo]=TARGA-informo
+Name[es]=Info de Targa visión verdadera
+Name[et]=Truevision Targa info
+Name[fa]=اطلاعات Truevision Targa
+Name[fi]=Truevision Targa -tiedot
+Name[fr]=Informations Truevision
+Name[gl]=Inf. Truevision Targa
+Name[he]=מידע Truevision Targa
+Name[hi]=ट्रू-विज़न टाग्रा जानकारी
+Name[hr]=Truevision Targa Infomacije
+Name[hu]=Truevision/Targa-jellemzők
+Name[is]=Truevision Targa upplýsingar
+Name[it]=Informazioni Truevision Targa
+Name[ja]=TGA (Truevision Targa) 情報
+Name[kk]=Truevision Targa мәліметі
+Name[km]=ព័ត៌មាន Truevision Targa
+Name[lt]=Truevision Targa informacija
+Name[ms]=Maklumat Targa Truevision
+Name[nb]=Truevision Targa-info
+Name[nds]="Truevision Targa"-Info
+Name[ne]=ट्रुभिजन टार्गा सूचना
+Name[nl]=Truevision Targa-info
+Name[nn]=Truevision Targa-info
+Name[nso]=Tshedimoso ya Targa ya pono ya Nnete
+Name[pl]=Informacja o pliku Truevision Targa
+Name[pt]=Informação do Targa da Truevision
+Name[pt_BR]=Informação sobre Truevision Targa
+Name[ro]=Informaţii Targa Truevision
+Name[ru]=Информация о Truevision Targa
+Name[se]=Truevision Targa-dieđut
+Name[sl]=Podatki o Truevision Targa
+Name[sr]=Truevision Targa информације
+Name[sr@Latn]=Truevision Targa informacije
+Name[sv]=Information om Truevision Targa
+Name[ta]=சரியான பார்வை தார்கா தகவல்
+Name[tg]=Иттилоот оиди Truevision Targa
+Name[th]=ข้อมูลแฟ้ม Truevision Targa
+Name[tr]=Truevision Targa Bilgisi
+Name[uk]=Інформація по Truevision Targa
+Name[uz]=TGA haqida maʼlumot
+Name[uz@cyrillic]=TGA ҳақида маълумот
+Name[ven]=Mafhungo a Targa ya mbonalelo ya vhukuma
+Name[wa]=Informåcion sol imådje Truevision Targa
+Name[xh]=Ulwazi lwe Truevision Targa
+Name[zh_CN]=Truevision Targa 信息
+Name[zh_HK]=Truevision Targa 資訊
+Name[zh_TW]=Truevision Targa 資訊
+Name[zu]=Ulwazi lwe-Truevision Targa
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_tga
+MimeType=image/x-targa
+PreferredGroups=Technical
+PreferredItems=Dimensions,BitDepth,ColorMode,Compression
diff --git a/kfile-plugins/tga/kfile_tga.h b/kfile-plugins/tga/kfile_tga.h
new file mode 100644
index 00000000..cd224fdf
--- /dev/null
+++ b/kfile-plugins/tga/kfile_tga.h
@@ -0,0 +1,37 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Shane Wright <me@shanewright.co.uk>
+ *
+ * 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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __KFILE_TGA_H__
+#define __KFILE_TGA_H__
+
+#include <kfilemetainfo.h>
+
+class QStringList;
+
+class KTgaPlugin: public KFilePlugin
+{
+ Q_OBJECT
+
+public:
+ KTgaPlugin( QObject *parent, const char *name, const QStringList& args );
+
+ virtual bool readInfo( KFileMetaInfo& info, uint what);
+};
+
+#endif
diff --git a/kfile-plugins/tiff/Makefile.am b/kfile-plugins/tiff/Makefile.am
new file mode 100644
index 00000000..e1e74cde
--- /dev/null
+++ b/kfile-plugins/tiff/Makefile.am
@@ -0,0 +1,21 @@
+## Makefile.am for Tiff file meta info plugin
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+noinst_HEADERS = kfile_tiff.h
+
+kde_module_LTLIBRARIES = kfile_tiff.la
+
+kfile_tiff_la_SOURCES = kfile_tiff.cpp
+kfile_tiff_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_tiff_la_LIBADD = $(LIB_KIO) $(LIBTIFF)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages:
+ $(XGETTEXT) *.cpp -o $(podir)/kfile_tiff.pot
+
+services_DATA = kfile_tiff.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kfile-plugins/tiff/configure.in.in b/kfile-plugins/tiff/configure.in.in
new file mode 100644
index 00000000..e1a9730a
--- /dev/null
+++ b/kfile-plugins/tiff/configure.in.in
@@ -0,0 +1,3 @@
+# Compile the tiff meta info plugin only if libtiff was detected
+AC_FIND_TIFF
+AM_CONDITIONAL(include_TIFF, test -n "$LIBTIFF")
diff --git a/kfile-plugins/tiff/kfile_tiff.cpp b/kfile-plugins/tiff/kfile_tiff.cpp
new file mode 100644
index 00000000..1e844d0d
--- /dev/null
+++ b/kfile-plugins/tiff/kfile_tiff.cpp
@@ -0,0 +1,299 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Nadeem Hasan <nhasan@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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "kfile_tiff.h"
+
+#include <kgenericfactory.h>
+#include <kdebug.h>
+
+#include <qstringlist.h>
+#include <qfile.h>
+#include <qdatetime.h>
+#include <qregexp.h>
+
+#include <tiff.h>
+#include <tiffio.h>
+
+typedef KGenericFactory<KTiffPlugin> TiffFactory;
+
+K_EXPORT_COMPONENT_FACTORY(kfile_tiff, TiffFactory("kfile_tiff"))
+
+KTiffPlugin::KTiffPlugin(QObject *parent, const char *name,
+ const QStringList &args) : KFilePlugin(parent, name, args)
+{
+ kdDebug(7034) << "TIFF file meta info plugin" << endl;
+ KFileMimeTypeInfo* info = addMimeTypeInfo( "image/tiff" );
+
+ KFileMimeTypeInfo::GroupInfo* group =
+ addGroupInfo(info, "General", i18n("General"));
+
+ KFileMimeTypeInfo::ItemInfo* item;
+ item = addItemInfo(group, "Description", i18n("Description"),
+ QVariant::String);
+ setHint(item, KFileMimeTypeInfo::Description);
+ item = addItemInfo(group, "Copyright", i18n("Copyright"),
+ QVariant::String);
+ item = addItemInfo(group, "ColorMode", i18n("Color Mode"),
+ QVariant::String);
+ item = addItemInfo(group, "Dimensions", i18n("Dimensions"),
+ QVariant::Size);
+ setHint(item, KFileMimeTypeInfo::Size);
+ setUnit(item, KFileMimeTypeInfo::Pixels);
+ item = addItemInfo(group, "Resolution", i18n("Resolution"),
+ QVariant::Size);
+ setUnit(item, KFileMimeTypeInfo::DotsPerInch);
+ item = addItemInfo(group, "BitDepth", i18n("Bit Depth"),
+ QVariant::Int);
+ setUnit(item, KFileMimeTypeInfo::BitsPerPixel);
+ item = addItemInfo(group, "Compression", i18n("Compression"),
+ QVariant::String);
+ item = addItemInfo(group, "Software", i18n("Software"),
+ QVariant::String);
+ item = addItemInfo(group, "DateTime", i18n("Date/Time"),
+ QVariant::DateTime);
+ item = addItemInfo(group, "Artist", i18n("Artist"),
+ QVariant::String);
+ setHint(item, KFileMimeTypeInfo::Author);
+ item = addItemInfo(group, "FaxPages", i18n("Fax Pages"),
+ QVariant::Int);
+
+ group = addGroupInfo(info, "Scanner", i18n("Scanner"));
+
+ item = addItemInfo(group, "Make", i18n("Make"), QVariant::String);
+ item = addItemInfo(group, "Model", i18n("Model"), QVariant::String);
+
+ m_colorMode.setAutoDelete(true);
+ m_imageCompression.setAutoDelete(true);
+
+ m_colorMode.insert(PHOTOMETRIC_MINISWHITE,
+ new QString(I18N_NOOP("Monochrome")));
+ m_colorMode.insert(PHOTOMETRIC_MINISBLACK,
+ new QString(I18N_NOOP("Monochrome")));
+ m_colorMode.insert(PHOTOMETRIC_RGB,
+ new QString(I18N_NOOP("RGB")));
+ m_colorMode.insert(PHOTOMETRIC_PALETTE,
+ new QString(I18N_NOOP("Palette color")));
+ m_colorMode.insert(PHOTOMETRIC_MASK,
+ new QString(I18N_NOOP("Transparency mask")));
+ m_colorMode.insert(PHOTOMETRIC_SEPARATED,
+ new QString(I18N_NOOP("Color separations")));
+ m_colorMode.insert(PHOTOMETRIC_YCBCR,
+ new QString(I18N_NOOP("YCbCr")));
+ m_colorMode.insert(PHOTOMETRIC_CIELAB,
+ new QString(I18N_NOOP("CIE Lab")));
+#ifdef PHOTOMETRIC_ITULAB
+ m_colorMode.insert(PHOTOMETRIC_ITULAB,
+ new QString(I18N_NOOP("ITU Lab")));
+#endif
+ m_colorMode.insert(PHOTOMETRIC_LOGL,
+ new QString(I18N_NOOP("LOGL")));
+ m_colorMode.insert(PHOTOMETRIC_LOGLUV,
+ new QString(I18N_NOOP("LOGLUV")));
+
+ m_imageCompression.insert(COMPRESSION_NONE,
+ new QString(I18N_NOOP("None")));
+ m_imageCompression.insert(COMPRESSION_CCITTRLE,
+ new QString(I18N_NOOP("RLE")));
+ m_imageCompression.insert(COMPRESSION_CCITTFAX3,
+ new QString(I18N_NOOP("G3 Fax")));
+ m_imageCompression.insert(COMPRESSION_CCITTFAX4,
+ new QString(I18N_NOOP("G4 Fax")));
+ m_imageCompression.insert(COMPRESSION_LZW,
+ new QString(I18N_NOOP("LZW")));
+ m_imageCompression.insert(COMPRESSION_OJPEG,
+ new QString(I18N_NOOP("JPEG")));
+ m_imageCompression.insert(COMPRESSION_JPEG,
+ new QString(I18N_NOOP("JPEG DCT")));
+#ifdef COMPRESSION_ADOBE_DEFLATE
+ m_imageCompression.insert(COMPRESSION_ADOBE_DEFLATE,
+ new QString(I18N_NOOP("Adobe Deflate")));
+#endif
+ m_imageCompression.insert(COMPRESSION_NEXT,
+ new QString(I18N_NOOP("NeXT 2-bit RLE")));
+ m_imageCompression.insert(COMPRESSION_CCITTRLEW,
+ new QString(I18N_NOOP("RLE Word")));
+ m_imageCompression.insert(COMPRESSION_PACKBITS,
+ new QString(I18N_NOOP("Packbits")));
+ m_imageCompression.insert(COMPRESSION_THUNDERSCAN,
+ new QString(I18N_NOOP("Thunderscan RLE")));
+ m_imageCompression.insert(COMPRESSION_IT8CTPAD,
+ new QString(I18N_NOOP("IT8 CT w/padding")));
+ m_imageCompression.insert(COMPRESSION_IT8LW,
+ new QString(I18N_NOOP("IT8 linework RLE")));
+ m_imageCompression.insert(COMPRESSION_IT8MP,
+ new QString(I18N_NOOP("IT8 monochrome")));
+ m_imageCompression.insert(COMPRESSION_IT8BL,
+ new QString(I18N_NOOP("IT8 binary lineart")));
+ m_imageCompression.insert(COMPRESSION_PIXARFILM,
+ new QString(I18N_NOOP("Pixar 10-bit LZW")));
+ m_imageCompression.insert(COMPRESSION_PIXARLOG,
+ new QString(I18N_NOOP("Pixar 11-bit ZIP")));
+ m_imageCompression.insert(COMPRESSION_DEFLATE,
+ new QString(I18N_NOOP("Pixar deflate")));
+ m_imageCompression.insert(COMPRESSION_DCS,
+ new QString(I18N_NOOP("Kodak DCS")));
+ m_imageCompression.insert(COMPRESSION_JBIG,
+ new QString(I18N_NOOP("ISO JBIG")));
+ m_imageCompression.insert(COMPRESSION_SGILOG,
+ new QString(I18N_NOOP("SGI log luminance RLE")));
+ m_imageCompression.insert(COMPRESSION_SGILOG24,
+ new QString(I18N_NOOP("SGI log 24-bit packed")));
+}
+
+QDateTime KTiffPlugin::tiffDate(const QString& s) const
+{
+ QDateTime dt;
+ QRegExp rxDate("^([0-9]{4}):([0-9]{2}):([0-9]{2})\\s"
+ "([0-9]{2}):([0-9]{2}):([0-9]{2})$");
+
+ if (rxDate.search(s) != -1)
+ {
+ int year = rxDate.cap(1).toInt();
+ int month = rxDate.cap(2).toInt();
+ int day = rxDate.cap(3).toInt();
+ int hour = rxDate.cap(4).toInt();
+ int min = rxDate.cap(5).toInt();
+ int sec = rxDate.cap(6).toInt();
+
+ QDate d = QDate(year, month, day);
+ QTime t = QTime(hour, min, sec);
+
+ if (d.isValid() && t.isValid())
+ {
+ dt.setDate(d);
+ dt.setTime(t);
+ }
+ }
+
+ return dt;
+}
+
+bool KTiffPlugin::readInfo(KFileMetaInfo& info, uint)
+{
+ TIFF *tiff = TIFFOpen(QFile::encodeName(info.path()), "r");
+ if (!tiff)
+ return false;
+
+ uint32 imageLength=0, imageWidth=0;
+ uint16 bitsPerSample=0, imageCompression=0, colorMode=0, samplesPerPixel=0,
+ imageAlpha=0, imageResUnit=0, dummy=0, faxPages=0;
+ float imageXResolution=0, imageYResolution=0;
+ char *description=0, *copyright=0, *software=0, *datetime=0, *artist=0,
+ *scannerMake=0, *scannerModel=0;
+
+ TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &imageLength);
+ TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &imageWidth);
+ TIFFGetFieldDefaulted(tiff, TIFFTAG_BITSPERSAMPLE, &bitsPerSample);
+ TIFFGetFieldDefaulted(tiff, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel);
+ TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &colorMode);
+ TIFFGetFieldDefaulted(tiff, TIFFTAG_COMPRESSION, &imageCompression);
+ TIFFGetField(tiff, TIFFTAG_MATTEING, &imageAlpha);
+ TIFFGetField(tiff, TIFFTAG_XRESOLUTION, &imageXResolution);
+ TIFFGetField(tiff, TIFFTAG_YRESOLUTION, &imageYResolution);
+ TIFFGetFieldDefaulted(tiff, TIFFTAG_RESOLUTIONUNIT, &imageResUnit);
+ TIFFGetField(tiff, TIFFTAG_IMAGEDESCRIPTION, &description);
+ TIFFGetField(tiff, TIFFTAG_SOFTWARE, &software);
+ TIFFGetField(tiff, TIFFTAG_COPYRIGHT, &copyright);
+ TIFFGetField(tiff, TIFFTAG_DATETIME, &datetime);
+ TIFFGetField(tiff, TIFFTAG_ARTIST, &artist);
+ TIFFGetField(tiff, TIFFTAG_PAGENUMBER, &dummy, &faxPages);
+ TIFFGetField(tiff, TIFFTAG_MAKE, &scannerMake);
+ TIFFGetField(tiff, TIFFTAG_MODEL, &scannerModel);
+
+ kdDebug(7034) << "Description: " << description << endl;
+ kdDebug(7034) << "Width: " << imageWidth << endl;
+ kdDebug(7034) << "Height: " << imageLength << endl;
+ kdDebug(7034) << "BitDepth: " << bitsPerSample << endl;
+ kdDebug(7034) << "ColorMode: " << colorMode << endl;
+ kdDebug(7034) << "Compression: " << imageCompression << endl;
+ kdDebug(7034) << "SamplesPerPixel: " << samplesPerPixel << endl;
+ kdDebug(7034) << "ImageAlpha: " << imageAlpha << endl;
+ kdDebug(7034) << "XResolution: " << imageXResolution << endl;
+ kdDebug(7034) << "YResolution: " << imageYResolution << endl;
+ kdDebug(7034) << "ResolutionUnit: " << imageResUnit << endl;
+ kdDebug(7034) << "FaxPages: " << faxPages << endl;
+ kdDebug(7034) << "DateTime: " << datetime << endl;
+ kdDebug(7034) << "Copyright: " << copyright << endl;
+ kdDebug(7034) << "Software: " << software << endl;
+ kdDebug(7034) << "Artist: " << artist << endl;
+ kdDebug(7034) << "Make: " << scannerMake << endl;
+ kdDebug(7034) << "Model: " << scannerModel << endl;
+
+ if (imageResUnit == RESUNIT_CENTIMETER)
+ {
+ imageXResolution *= 2.54;
+ imageYResolution *= 2.54;
+ }
+ else if (imageResUnit == RESUNIT_NONE)
+ {
+ imageXResolution = 0;
+ imageYResolution = 0;
+ }
+
+ int imageBpp = bitsPerSample*samplesPerPixel;
+ if (imageAlpha && colorMode==PHOTOMETRIC_RGB)
+ m_colorMode.replace(PHOTOMETRIC_RGB, new QString(I18N_NOOP("RGBA")));
+
+ KFileMetaInfoGroup group = appendGroup(info, "General");
+ if (description)
+ appendItem(group, "Description", QString(description));
+ appendItem(group, "Dimensions", QSize(imageWidth, imageLength));
+ appendItem(group, "BitDepth", imageBpp);
+ if (imageXResolution>0 && imageYResolution>0)
+ appendItem(group, "Resolution", QSize(
+ static_cast<int>(imageXResolution),
+ static_cast<int>(imageYResolution)));
+ if (m_colorMode[colorMode])
+ appendItem(group, "ColorMode", *m_colorMode[colorMode]);
+ if (m_imageCompression[imageCompression])
+ appendItem(group, "Compression", *m_imageCompression[imageCompression]);
+ if (datetime)
+ {
+ QDateTime dt = tiffDate(QString(datetime));
+ if (dt.isValid())
+ appendItem(group, "DateTime", dt);
+ }
+ if (copyright)
+ appendItem(group, "Copyright", QString(copyright));
+ if (software)
+ appendItem(group, "Software", QString(software));
+ if (artist)
+ appendItem(group, "Artist", QString(artist));
+
+ if (faxPages>0 && (imageCompression==COMPRESSION_CCITTFAX3 ||
+ imageCompression==COMPRESSION_CCITTFAX4))
+ {
+ appendItem(group, "FaxPages", faxPages);
+ }
+
+ if (scannerMake || scannerModel)
+ {
+ group = appendGroup(info, "Scanner");
+ if (scannerMake)
+ appendItem(group, "Make", QString(scannerMake));
+ if (scannerModel)
+ appendItem(group, "Model", QString(scannerModel));
+ }
+
+ TIFFClose(tiff);
+
+ return true;
+}
+
+#include "kfile_tiff.moc"
diff --git a/kfile-plugins/tiff/kfile_tiff.desktop b/kfile-plugins/tiff/kfile_tiff.desktop
new file mode 100644
index 00000000..c7c7441e
--- /dev/null
+++ b/kfile-plugins/tiff/kfile_tiff.desktop
@@ -0,0 +1,67 @@
+[Desktop Entry]
+Type=Service
+Name=TIFF File Meta Info
+Name[af]=Tiff Lêer Meta Inligting
+Name[ar]=معلومات ملف TIFF
+Name[br]=Meta-titouroù ar restr TIFF
+Name[ca]=Metainformació de fitxer TIFF
+Name[cs]=Metainformace obrázku typu TIFF
+Name[cy]=Meta-wybodaeth Ffeil TIFF
+Name[da]=TIFF Fil-meta-info
+Name[de]=TIFF-Metainformation
+Name[el]=Μετα-πληροφορίες αρχείου TIFF
+Name[eo]=TIFF-informo
+Name[es]=Info meta de archivos TIFF
+Name[et]=TIFF faili metainfo
+Name[eu]=TIFF fitxategi meta info
+Name[fa]=فرااطلاعات پروندۀ TIFF
+Name[fi]=TIFF-metatiedot
+Name[fr]=Méta Informations sur les fichiers TIFF
+Name[gl]=Inf. metaficheiro TIFF
+Name[he]=מידע TIFF
+Name[hi]=TIFF फ़ाइल मेटा जानकारी
+Name[hr]=TIFF meta informacije
+Name[hu]=TIFF-metajellemzők
+Name[is]=TIFF File Meta upplýsingar
+Name[it]=Informazioni TIFF
+Name[ja]=TIFF ファイルメタ情報
+Name[kk]=TIFF файлдың мета деректері
+Name[km]=ព័ត៌មាន​មេតា​របស់​ឯកសារ TIFF
+Name[lt]=TIFF bylos meta informacija
+Name[ms]=TIFF Maklumat Meta Fail TIFF
+Name[nb]=TIFF-filmetainfo
+Name[nds]=TIFF-Metainfo
+Name[ne]=TIFF फाइल मेटा सूचना
+Name[nl]=TIFF File Meta-info
+Name[nn]=TIFF-filmetainfo
+Name[nso]=Tshedimoso ya Meta wa Faele ya TIFF
+Name[pl]=Informacja o pliku TIFF
+Name[pt]=Meta-Informação do Ficheiro TIFF
+Name[pt_BR]=Informação sobre Meta Arquivo TIFF
+Name[ro]=Metainformaţii TIFF
+Name[ru]=Информация о метафайле TIFF
+Name[se]=TIFF-filla metadieđut
+Name[sk]=Meta-info o súbore TIFF
+Name[sl]=Meta podatki o TIFF
+Name[sr]=Мета информације TIFF фајла
+Name[sr@Latn]=Meta informacije TIFF fajla
+Name[sv]=Metainformation om TIFF-fil
+Name[ta]=TIFF மீக்கோப்பு தகவல்
+Name[tg]=Иттилоот оиди метафайли TIFF
+Name[th]=ข้อมูลเมตาแฟ้ม TIFF
+Name[tr]=TIFF Dosya Bilgisi
+Name[uk]=Метаінформація про файл TIFF
+Name[uz]=TIFF-faylining meta-maʼlumoti
+Name[uz@cyrillic]=TIFF-файлининг мета-маълумоти
+Name[ven]=Mafhungo a Meta faela ya TIFF
+Name[wa]=Informåcion sol imådje TIFF
+Name[xh]=Ulwazi lwe TIFF Ifayile Esembindini
+Name[zh_CN]=TIFF 文件元信息
+Name[zh_HK]=TIFF 檔案 Meta 資訊
+Name[zh_TW]=TIFF 檔案 Meta 資訊
+Name[zu]=Ulwazi Lwefayela yemeta ye-TIFF
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_tiff
+MimeType=image/tiff
+PreferredGroups=General,Scanner
+PreferredItems=Description,Copyright,Type,Dimensions,Resolution,BitDepth,Compression,Software,DateTime,Artist,FaxPages,Make,Model
diff --git a/kfile-plugins/tiff/kfile_tiff.h b/kfile-plugins/tiff/kfile_tiff.h
new file mode 100644
index 00000000..8985288d
--- /dev/null
+++ b/kfile-plugins/tiff/kfile_tiff.h
@@ -0,0 +1,42 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Nadeem Hasan <nhasan@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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __KFILE_TIFF_H_
+#define __KFILE_TIFF_H_
+
+#include <kfilemetainfo.h>
+
+#include <qintdict.h>
+
+class KTiffPlugin: public KFilePlugin
+{
+ Q_OBJECT
+
+public:
+ KTiffPlugin(QObject *parent, const char *name, const QStringList& args);
+ virtual bool readInfo(KFileMetaInfo& info, uint what);
+
+private:
+ QDateTime tiffDate(const QString&) const;
+
+ QIntDict<QString> m_colorMode;
+ QIntDict<QString> m_imageCompression;
+};
+
+#endif
diff --git a/kfile-plugins/xbm/Makefile.am b/kfile-plugins/xbm/Makefile.am
new file mode 100644
index 00000000..1b9d7ff9
--- /dev/null
+++ b/kfile-plugins/xbm/Makefile.am
@@ -0,0 +1,22 @@
+## Makefile.am for xbm file meta info plugin
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = kfile_xbm.h
+
+kde_module_LTLIBRARIES = kfile_xbm.la
+
+kfile_xbm_la_SOURCES = kfile_xbm.cpp
+kfile_xbm_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_xbm_la_LIBADD = $(LIB_KSYCOCA)
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) kfile_xbm.cpp -o $(podir)/kfile_xbm.pot
+
+services_DATA = kfile_xbm.desktop
+servicesdir = $(kde_servicesdir)
diff --git a/kfile-plugins/xbm/kfile_xbm.cpp b/kfile-plugins/xbm/kfile_xbm.cpp
new file mode 100644
index 00000000..d62471f5
--- /dev/null
+++ b/kfile-plugins/xbm/kfile_xbm.cpp
@@ -0,0 +1,128 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Shane Wright <me@shanewright.co.uk>
+ *
+ * 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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include <config.h>
+#include "kfile_xbm.h"
+
+#include <kprocess.h>
+#include <klocale.h>
+#include <kgenericfactory.h>
+#include <kstringvalidator.h>
+#include <kdebug.h>
+
+#include <qdict.h>
+#include <qvalidator.h>
+#include <qcstring.h>
+#include <qfile.h>
+#include <qdatetime.h>
+
+#if !defined(__osf__)
+#include <inttypes.h>
+#else
+typedef unsigned short uint32_t;
+#endif
+
+typedef KGenericFactory<KXbmPlugin> XbmFactory;
+
+K_EXPORT_COMPONENT_FACTORY(kfile_xbm, XbmFactory( "kfile_xbm" ))
+
+KXbmPlugin::KXbmPlugin(QObject *parent, const char *name,
+ const QStringList &args)
+
+ : KFilePlugin(parent, name, args)
+{
+ KFileMimeTypeInfo* info = addMimeTypeInfo( "image/x-xbm" );
+
+ KFileMimeTypeInfo::GroupInfo* group = 0L;
+
+ group = addGroupInfo(info, "Technical", i18n("Technical Details"));
+
+ KFileMimeTypeInfo::ItemInfo* item;
+
+ item = addItemInfo(group, "Dimensions", i18n("Dimensions"), QVariant::Size);
+ setHint( item, KFileMimeTypeInfo::Size );
+ setUnit(item, KFileMimeTypeInfo::Pixels);
+}
+
+
+unsigned long KXbmPlugin::xbm_processLine(char * linebuf)
+{
+ const char * fsig = "#define ";
+
+ // check it starts with #define
+ if (memcmp(linebuf, fsig, 8))
+ return 0;
+
+ // scan for the 2nd space and set up a pointer
+ uint32_t slen = strlen(linebuf);
+ bool done = false;
+ uint32_t spos = 0;
+ unsigned char spacecount = 0;
+ do {
+
+ if (linebuf[spos] == 0x00)
+ return 0;
+
+ if (linebuf[spos] == ' ')
+ ++spacecount;
+
+ if (spacecount == 2)
+ done = true;
+ else
+ ++spos;
+
+ } while (!done);
+
+ return atoi(linebuf + spos);
+}
+
+
+bool KXbmPlugin::readInfo( KFileMetaInfo& info, uint what)
+{
+
+ QFile file(info.path());
+
+ if (!file.open(IO_ReadOnly))
+ {
+ kdDebug(7034) << "Couldn't open " << QFile::encodeName(info.path()) << endl;
+ return false;
+ }
+
+ // we need a buffer for lines
+ char linebuf[1000];
+
+ // read the first line
+ file.readLine(linebuf, sizeof( linebuf ));
+ uint32_t width = xbm_processLine(linebuf);
+
+ // read the 2nd line
+ file.readLine(linebuf, sizeof( linebuf ));
+ uint32_t height = xbm_processLine(linebuf);
+
+ if ((width > 0) && (height > 0)) {
+ // we have valid looking data
+ KFileMetaInfoGroup group = appendGroup(info, "Technical");
+ appendItem(group, "Dimensions", QSize(width, height));
+ return true;
+ }
+
+ return false;
+}
+
+#include "kfile_xbm.moc"
diff --git a/kfile-plugins/xbm/kfile_xbm.desktop b/kfile-plugins/xbm/kfile_xbm.desktop
new file mode 100644
index 00000000..c33407ac
--- /dev/null
+++ b/kfile-plugins/xbm/kfile_xbm.desktop
@@ -0,0 +1,65 @@
+[Desktop Entry]
+Type=Service
+Name=XBM Info
+Name[af]=Xbm Inligting
+Name[ar]=معلومات XBM
+Name[br]=Titouroù XBM
+Name[ca]=Informació d'XBM
+Name[cs]=XBM info
+Name[cy]=Gwybodaeth XBM
+Name[da]=XBM-info
+Name[de]=XBM-Info
+Name[el]=Πληροφορίες XBM
+Name[eo]=XBM-informo
+Name[es]=Info XBM
+Name[et]=XBM info
+Name[fa]=اطلاعات XBM
+Name[fi]=XBM-tiedot
+Name[fr]=Informations sur XBM
+Name[gl]=Inf. XBM
+Name[he]=מידע XBM
+Name[hi]=XBM जानकारी
+Name[hr]=XBM Infoformacije
+Name[hu]=XBM-jellemzők
+Name[is]=XBM upplýsingar
+Name[it]=Informazioni XBM
+Name[ja]=XBM 情報
+Name[kk]=XBM мәліметі
+Name[km]=ព័ត៌មាន XBM
+Name[lt]=XBM informacija
+Name[ms]=Maklumat XBM
+Name[nds]=XBM-Info
+Name[ne]=XBM सूचना
+Name[nl]=XBM-info
+Name[nn]=XBM-info
+Name[nso]=Tshedimoso ya XBM
+Name[pa]=XBM ਜਾਣਕਾਰੀ
+Name[pl]=Informacja o pliku XBM
+Name[pt]=Informação do XBM
+Name[pt_BR]=Informação sobre XBM
+Name[ro]=Informaţii XBM
+Name[ru]=Информация о XBM
+Name[se]=XBM-dieđut
+Name[sl]=Podatki o XBM
+Name[sr]=XBM информације
+Name[sr@Latn]=XBM informacije
+Name[sv]=XBM-information
+Name[ta]=XBM தகவல்
+Name[tg]=Иттилоот оиди XBM
+Name[th]=ข้อมูลแฟ้ม XBM
+Name[tr]=XBM Bilgisi
+Name[uk]=Інформація по XBM
+Name[uz]=XBM haqida maʼlumot
+Name[uz@cyrillic]=XBM ҳақида маълумот
+Name[ven]=Mafhungo a XBM
+Name[wa]=Informåcion sol imådje XBM
+Name[xh]=Ulwazi lwe XBM
+Name[zh_CN]=XBM 信息
+Name[zh_HK]=XBM 資訊
+Name[zh_TW]=XBM 資訊
+Name[zu]=Ulwazi lwe-XBM
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_xbm
+MimeType=image/x-xbm
+PreferredGroups=Technical
+PreferredItems=Resolution
diff --git a/kfile-plugins/xbm/kfile_xbm.h b/kfile-plugins/xbm/kfile_xbm.h
new file mode 100644
index 00000000..8cc571e1
--- /dev/null
+++ b/kfile-plugins/xbm/kfile_xbm.h
@@ -0,0 +1,42 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2002 Shane Wright <me@shanewright.co.uk>
+ *
+ * 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 version 2.
+ *
+ * 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __KFILE_XBM_H__
+#define __KFILE_XBM_H__
+
+#include <kfilemetainfo.h>
+
+class QStringList;
+
+class KXbmPlugin: public KFilePlugin
+{
+ Q_OBJECT
+
+public:
+ KXbmPlugin( QObject *parent, const char *name, const QStringList& args );
+
+ virtual bool readInfo( KFileMetaInfo& info, uint what);
+
+private:
+
+ unsigned long xbm_processLine(char * linebuf);
+
+};
+
+#endif
diff --git a/kfile-plugins/xpm/Makefile.am b/kfile-plugins/xpm/Makefile.am
new file mode 100644
index 00000000..5a1254b1
--- /dev/null
+++ b/kfile-plugins/xpm/Makefile.am
@@ -0,0 +1,21 @@
+## Makefile.am for xpm file meta info plugin
+
+INCLUDES = $(all_includes)
+
+# these are the headers for your project
+noinst_HEADERS = kfile_xpm.h
+
+kde_module_LTLIBRARIES = kfile_xpm.la
+
+kfile_xpm_la_SOURCES = kfile_xpm.cpp
+kfile_xpm_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kfile_xpm_la_LIBADD = $(LIB_KIO)
+kfile_xpm_la_METASOURCES = kfile_xpm.moc
+
+# let automoc handle all of the meta source files (moc)
+METASOURCES = AUTO
+
+kde_services_DATA = kfile_xpm.desktop
+
+messages:
+ $(XGETTEXT) *.cpp -o $(podir)/kfile_xpm.pot
diff --git a/kfile-plugins/xpm/kfile_xpm.cpp b/kfile-plugins/xpm/kfile_xpm.cpp
new file mode 100644
index 00000000..3fd188b7
--- /dev/null
+++ b/kfile-plugins/xpm/kfile_xpm.cpp
@@ -0,0 +1,71 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Martin Koller *
+ * m.koller@surfeu.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 <config.h>
+#include <qimage.h>
+#include "kfile_xpm.h"
+
+#include <kgenericfactory.h>
+
+//--------------------------------------------------------------------------------
+
+typedef KGenericFactory<xpmPlugin> xpmFactory;
+
+K_EXPORT_COMPONENT_FACTORY(kfile_xpm, xpmFactory( "kfile_xpm" ))
+
+//--------------------------------------------------------------------------------
+
+xpmPlugin::xpmPlugin(QObject *parent, const char *name, const QStringList &args)
+ : KFilePlugin(parent, name, args)
+{
+ KFileMimeTypeInfo* info = addMimeTypeInfo( "image/x-xpm" );
+
+ // our new group
+ KFileMimeTypeInfo::GroupInfo* group = 0;
+ group = addGroupInfo(info, "xpmInfo", i18n("X PixMap File Information"));
+
+ KFileMimeTypeInfo::ItemInfo* item;
+
+ // our new items in the group
+ item = addItemInfo(group, "Dimension", i18n("Dimension"), QVariant::Size);
+ setHint(item, KFileMimeTypeInfo::Size);
+ setUnit(item, KFileMimeTypeInfo::Pixels);
+
+ item = addItemInfo(group, "BitDepth", i18n("Bit Depth"), QVariant::Int);
+ setUnit(item, KFileMimeTypeInfo::BitsPerPixel);
+}
+
+//--------------------------------------------------------------------------------
+
+bool xpmPlugin::readInfo(KFileMetaInfo& info, uint /*what*/)
+{
+ QImage pix;
+
+ if ( ! pix.load(info.path(), "XPM") ) return false;
+
+ KFileMetaInfoGroup group = appendGroup(info, "xpmInfo");
+
+ appendItem(group, "Dimension", pix.size());
+ appendItem(group, "BitDepth", pix.depth());
+
+ return true;
+}
+
+#include "kfile_xpm.moc"
diff --git a/kfile-plugins/xpm/kfile_xpm.desktop b/kfile-plugins/xpm/kfile_xpm.desktop
new file mode 100644
index 00000000..612fb82e
--- /dev/null
+++ b/kfile-plugins/xpm/kfile_xpm.desktop
@@ -0,0 +1,53 @@
+[Desktop Entry]
+Type=Service
+Name=XPM Info
+Name[br]=Titouroù XPM
+Name[ca]=Informació de XPM
+Name[cs]=XPM info
+Name[de]=XPM-Info
+Name[el]=Πληροφορίες XPM
+Name[eo]=XPM-informo
+Name[es]=Información XPM
+Name[et]=XPM info
+Name[fa]=اطلاعات XPM
+Name[fi]=XPM-tiedot
+Name[fr]=Informations XPM
+Name[gl]=Información XPM
+Name[he]=מידע XPM
+Name[hu]=XPM-jellemzők
+Name[is]=XPM upplýsingar
+Name[it]=Informazioni XPM
+Name[ja]=XPM 情報
+Name[kk]=XPM мәліметі
+Name[km]=ព័ត៌មាន XPM
+Name[lt]=XPM informacija
+Name[ms]=Maklumat XPM
+Name[nb]=XPM-info
+Name[nds]=XPM-Info
+Name[ne]=XPM सूचना
+Name[nl]=XPM-info
+Name[nn]=XPM-info
+Name[pa]=XPM ਜਾਣਕਾਰੀ
+Name[pl]=Informacja o pliku XPM
+Name[pt]=Informação do XPM
+Name[pt_BR]=Informações Sobre XPM
+Name[ro]=Informaţii XPM
+Name[ru]=Информация о XPM
+Name[sl]=Podatki o XPM
+Name[sr]=XPM информације
+Name[sr@Latn]=XPM informacije
+Name[sv]=XPM-information
+Name[ta]=XPM தகவல்
+Name[th]=ข้อมูลแฟ้ม XPM
+Name[tr]=XPM Bilgisi
+Name[uk]=Інформація про XPM
+Name[uz]=XPM haqida maʼlumot
+Name[uz@cyrillic]=XPM ҳақида маълумот
+Name[zh_CN]=XPM 信息
+Name[zh_HK]=XPM 資訊
+Name[zh_TW]=XPM 資訊
+ServiceTypes=KFilePlugin
+X-KDE-Library=kfile_xpm
+MimeType=image/x-xpm
+PreferredGroups=xpmInfo
+PreferredItems=Dimension
diff --git a/kfile-plugins/xpm/kfile_xpm.h b/kfile-plugins/xpm/kfile_xpm.h
new file mode 100644
index 00000000..c68ad4eb
--- /dev/null
+++ b/kfile-plugins/xpm/kfile_xpm.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Martin Koller *
+ * m.koller@surfeu.at *
+ * *
+ * This plugin provides information about the content of a *
+ * XPM image file. *
+ * *
+ * 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 KFILE_XPM_H
+#define KFILE_XPM_H
+
+/**
+ * Note: For further information look into <$KDEDIR/include/kfilemetainfo.h>
+ */
+#include <kfilemetainfo.h>
+
+class QStringList;
+
+class xpmPlugin: public KFilePlugin
+{
+ Q_OBJECT
+
+ public:
+ xpmPlugin(QObject *parent, const char *name, const QStringList& args);
+
+ virtual bool readInfo(KFileMetaInfo& info, uint what);
+};
+
+#endif
+
diff --git a/kgamma/AUTHORS b/kgamma/AUTHORS
new file mode 100644
index 00000000..3d67f1cb
--- /dev/null
+++ b/kgamma/AUTHORS
@@ -0,0 +1 @@
+Michael v.Ostheim <MvOstheim@web.de>
diff --git a/kgamma/ChangeLog b/kgamma/ChangeLog
new file mode 100644
index 00000000..6ffc823e
--- /dev/null
+++ b/kgamma/ChangeLog
@@ -0,0 +1,54 @@
+KGamma 0.9.9:
+
+* Add multi-head support (fix bug #321)
+* Add screen selector
+* Add screen synchronisation
+* Change kgammarc format (old user settings are lost)
+* Fix a localisation bug in class GammaCtrl
+* Add class XF86ConfigPath
+* Add Dutch translation (by Rinse de Vries)
+* Add Czech translation (by Daniel Prynych)
+
+KGamma 0.9.2:
+
+* Fix compile errors with configure option --enable-final (again)
+* Cancel the split into two parts (admin and user mode), add a
+ checkbox to choose where to store the settings (user config file
+ or XF86Config)
+
+KGamma 0.9.1:
+
+* Fix compile errors with configure option --enable-final
+* French and spanish translation update
+* Install script update
+
+KGamma 0.9:
+
+* Add admin mode (in this mode, gamma settings are stored to XF86Config)
+* Add spec file for RPM based distributions (Dominik Seichter)
+* Remove class RGBCtrl, handle the widgets in main widget
+* Add check for XFree86-VidModeExtension to configure.in.in
+* Add wrapper class XVidExtWrap to access XFree86-VidModeExtension directly,
+ KGamma no longer needs xgamma as a backend
+
+KGamma 0.2.3:
+
+* Minor install script changes, should compile with KDE2 and KDE3 now
+
+KGamma 0.2.2:
+
+* Ported to KDE3
+
+KGamma 0.2.1:
+
+* Code clean up
+* Converted all strings to QString to avoid copying between QString and char*
+* Add french localisation (Pierre Jarillon)
+* Add italian localization (Daniele Medri)
+
+KGamma 0.2:
+
+* Add spanish translation (Miguel Novas)
+* Change behavior of "Use Defaults" button to be compliant with kcontrol standard
+* Partial rewrite to make it a KDE control center plugin
+* Create new logo
diff --git a/kgamma/Makefile.am b/kgamma/Makefile.am
new file mode 100644
index 00000000..1c0d4b6d
--- /dev/null
+++ b/kgamma/Makefile.am
@@ -0,0 +1,2 @@
+SUBDIRS = kcmkgamma xf86gammacfg
+
diff --git a/kgamma/TODO b/kgamma/TODO
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/kgamma/TODO
@@ -0,0 +1 @@
+
diff --git a/kgamma/configure.in.in b/kgamma/configure.in.in
new file mode 100644
index 00000000..d4e1a9f4
--- /dev/null
+++ b/kgamma/configure.in.in
@@ -0,0 +1,65 @@
+#MIN_CONFIG(3)
+
+AM_INIT_AUTOMAKE(kgamma,1.0.2)
+
+dnl CXXFLAGS="$NOOPT_CXXFLAGS" dnl __kdevelop[noopt]__
+dnl CFLAGS="$NOOPT_CFLAGS" dnl __kdevelop[noopt]__
+dnl CXXFLAGS="$CXXFLAGS $USE_EXCEPTIONS" dnl __kdevelop[exc]__
+
+dnl KDE_NEED_FLEX dnl __kdevelop__
+dnl AC_PROG_YACC dnl __kdevelop__
+
+dnl This test is taken from the aktion configure.in.in
+dnl Modified by Michael v.Ostheim
+dnl Checking for XFree86 VidMode Extensions
+AC_MSG_CHECKING([for XFree86-VidModeExtension])
+
+AC_CACHE_VAL(ac_cv_lib_vm,
+ [ac_save_LIBS="$LIBS"
+ kgamma_save_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS $all_includes"
+ LIBS="-L$x_libraries -lXxf86vm -lXext -lX11"
+ AC_TRY_LINK( [
+ #include <X11/Xlib.h>
+ #include <X11/Xatom.h>
+ #include <X11/extensions/xf86vmode.h>
+ ],
+ [],
+ eval "ac_cv_lib_vm='-lXxf86vm'",
+ [AC_MSG_RESULT(no)
+ eval "ac_cv_lib_vm=no"])
+ LIBS="$ac_save_LIBS"
+ CFLAGS=$kgamma_save_CFLAGS
+])
+
+if eval "test ! \"`echo $ac_cv_lib_vm`\" = no"; then
+ LIBVM="$ac_cv_lib_vm"
+ AC_SUBST(LIBVM)
+ AC_MSG_RESULT($ac_cv_lib_vm)
+
+ AC_MSG_CHECKING([for gamma functions in XFree86-VidModeExtension])
+
+ AC_CACHE_VAL(ac_cv_lib_vmgamma,
+ [ac_save_LIBS="$LIBS"
+ kgamma_save_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS $all_includes"
+ LIBS="-L$x_libraries -lXxf86vm -lXext -lX11"
+ AC_TRY_LINK( [],
+ [XF86VidModeGetGamma();],
+ [AC_MSG_RESULT(yes)
+ eval "ac_cv_lib_vm='-lXxf86vm'"],
+ [AC_MSG_RESULT(no)
+ eval "ac_cv_lib_vm=no"])
+ LIBS="$ac_save_LIBS"
+ CFLAGS=$kgamma_save_CFLAGS
+ ])
+fi
+
+if eval "test \"`echo $ac_cv_lib_vm`\" = no"; then
+ DO_NOT_COMPILE="$DO_NOT_COMPILE kgamma"
+fi
+
+AC_LANG_SAVE
+AC_LANG_CPLUSPLUS
+AC_CHECK_HEADERS(sstream)
+AC_LANG_RESTORE
diff --git a/kgamma/kcmkgamma/Makefile.am b/kgamma/kcmkgamma/Makefile.am
new file mode 100644
index 00000000..6420ee92
--- /dev/null
+++ b/kgamma/kcmkgamma/Makefile.am
@@ -0,0 +1,18 @@
+
+INCLUDES = $(all_includes)
+
+kde_module_LTLIBRARIES = kcm_kgamma.la
+kcm_kgamma_la_METASOURCES=AUTO
+kcm_kgamma_la_SOURCES = xf86configpath.cpp xvidextwrap.cpp displaynumber.cpp \
+ gammactrl.cpp kgamma.cpp
+kcm_kgamma_la_LIBADD = $(LIBVM) $(LIB_KDEUI) $(LIB_KDECORE) $(LIB_QT)
+kcm_kgamma_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+
+SUBDIRS = pics
+
+xdg_apps_DATA = kgamma.desktop
+
+messages:
+ $(XGETTEXT) *.cpp -o $(podir)/kgamma.pot
+
+KDE_OPTIONS = nofinal
diff --git a/kgamma/kcmkgamma/displaynumber.cpp b/kgamma/kcmkgamma/displaynumber.cpp
new file mode 100644
index 00000000..cb04f513
--- /dev/null
+++ b/kgamma/kcmkgamma/displaynumber.cpp
@@ -0,0 +1,61 @@
+/***************************************************************************
+ displaynumber.cpp - description
+ -------------------
+ begin : Sun Feb 23 2003
+ copyright : (C) 2003 by Michael v.Ostheim
+ email : ostheimm@users.berlios.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include <qstring.h>
+#include <qfontmetrics.h>
+
+#include "displaynumber.h"
+
+DisplayNumber::DisplayNumber(QWidget *parent, int digits, \
+ int prec, const char *name) : QLabel(parent,name) {
+
+ setPrecision(prec);
+ setWidth(digits);
+
+ setFrameStyle(QFrame::Panel | QFrame::Sunken);
+ setBackgroundMode(Qt::PaletteBase);
+ setAlignment(Qt::AlignCenter);
+ setFocusPolicy(NoFocus);
+}
+
+DisplayNumber::~DisplayNumber(){
+}
+
+void DisplayNumber::setFont( const QFont & f ) {
+ QLabel::setFont(f);
+ setWidth(dg);
+}
+
+void DisplayNumber::setWidth(int digits) {
+ QFontMetrics fm(font());
+ QString s("0123456789.+-");
+ int width = 0, charWidth=0;
+
+ for (int i = 0; i < 11; i++, width = fm.width(s[i]))
+ charWidth = (width > charWidth) ? width : charWidth;
+
+ dg = digits;
+ setMinimumWidth( dg * charWidth + charWidth/2 );
+}
+
+void DisplayNumber::setNum(double num) {
+ QString text;
+ setText(text.setNum(num, 'f', precision));
+}
+
+
+#include "displaynumber.moc"
diff --git a/kgamma/kcmkgamma/displaynumber.h b/kgamma/kcmkgamma/displaynumber.h
new file mode 100644
index 00000000..e86d6d3a
--- /dev/null
+++ b/kgamma/kcmkgamma/displaynumber.h
@@ -0,0 +1,41 @@
+/***************************************************************************
+ displaynumber.h - description
+ -------------------
+ begin : Sun Feb 23 2003
+ copyright : (C) 2003 by Michael v.Ostheim
+ email : ostheimm@users.berlios.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef DISPLAYNUMBER_H
+#define DISPLAYNUMBER_H
+
+#include <qlabel.h>
+
+/**
+ *@author Michael v.Ostheim
+ */
+
+class DisplayNumber : public QLabel {
+ Q_OBJECT
+public:
+ DisplayNumber(QWidget *parent=0, int digits=0, int prec=0, const char *name=0);
+ ~DisplayNumber();
+ void setFont( const QFont & f );
+ void setNum(double num);
+ void setWidth(int digits);
+ void setPrecision(int prec) { precision = prec; };
+
+private:
+ int dg, precision;
+};
+
+#endif
diff --git a/kgamma/kcmkgamma/gammactrl.cpp b/kgamma/kcmkgamma/gammactrl.cpp
new file mode 100644
index 00000000..2052fd34
--- /dev/null
+++ b/kgamma/kcmkgamma/gammactrl.cpp
@@ -0,0 +1,138 @@
+/***************************************************************************
+ gammactrl.cpp - description
+ -------------------
+ begin : Sun Oct 7 2001
+ copyright : (C) 2001 by Michael v.Ostheim
+ email : MvOstheim@web.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qstring.h>
+
+#include <kdialog.h>
+
+#include "gammactrl.h"
+#include "xvidextwrap.h"
+#include "displaynumber.h"
+#include "gammactrl.moc"
+
+GammaCtrl::GammaCtrl(QWidget *parent, XVidExtWrap *xvid, int channel, \
+ const QString& mingamma, const QString& maxgamma, const QString& setgamma, \
+ const char *name) : QHBox(parent, name)
+{
+ int maxslider = (int)( ( maxgamma.toDouble() - mingamma.toDouble() \
+ + 0.0005 ) * 20 );
+ int setslider = (int)( ( setgamma.toDouble() - mingamma.toDouble() \
+ + 0.0005 ) * 20 );
+ setslider = (setslider > maxslider) ? maxslider : setslider;
+ setslider = (setslider < 0) ? 0 : setslider;
+
+ suspended = false;
+ changed=false;
+ ming = mingamma.toFloat();
+ mgamma = mingamma;
+ oldpos = setslider;
+ gchannel = channel;
+ xv = xvid;
+
+ setSpacing(KDialog::spacingHint());
+
+ slider = new QSlider(Horizontal, this);
+ slider->setFixedHeight(24);
+ slider->setTickmarks(QSlider::Below);
+ slider->setRange(0, maxslider);
+ slider->setTickInterval(2);
+ slider->setValue(setslider);
+ connect(slider, SIGNAL(valueChanged(int)), SLOT(setGamma(int)));
+ connect(slider, SIGNAL(sliderPressed()), SLOT(pressed()));
+
+ textfield = new DisplayNumber(this, 4, 2);
+ textfield->setText(setgamma);
+
+}
+
+GammaCtrl::~GammaCtrl()
+{
+}
+
+/** set gamma, slider and textfield */
+void GammaCtrl::setGamma(const QString& gamma){
+ int sliderpos;
+
+ sliderpos = (int)( ( gamma.toDouble() - mgamma.toDouble() + 0.0005 ) * 20 );
+ changed=true;
+ slider->setValue(sliderpos);
+
+ setGamma(sliderpos);
+ if (suspended) {
+ suspended=false;
+ textfield->setDisabled(false);
+ }
+}
+
+/** set slider and textfield */
+void GammaCtrl::setControl(const QString& gamma){
+ int sliderpos;
+
+ sliderpos = (int)( ( gamma.toDouble() - mgamma.toDouble() + 0.0005 ) * 20 );
+ setCtrl(sliderpos);
+}
+
+/** Return the current gamma value with precision prec */
+QString GammaCtrl::gamma(int prec){
+ QString gammatext;
+ gammatext.setNum(xv->getGamma(gchannel) + 0.0005, 'f', prec);
+
+ return(gammatext);
+}
+
+/** Slot: set gamma and textfield */
+void GammaCtrl::setGamma(int sliderpos){
+ if (sliderpos != oldpos || changed) {
+ xv->setGamma(gchannel, ming+(float)(slider->value())*0.05);
+ textfield->setNum(xv->getGamma(gchannel));
+ oldpos = sliderpos;
+ changed=false;
+ emit gammaChanged(sliderpos);
+ }
+}
+
+/** Slot: set slider and textfield */
+void GammaCtrl::setCtrl(int sliderpos){
+ if (suspended) {
+ suspended=false;
+ textfield->setDisabled(false);
+ }
+ oldpos = sliderpos;
+ slider->setValue(sliderpos);
+ textfield->setNum(xv->getGamma(gchannel));
+}
+
+/** Slot: disable textfield */
+void GammaCtrl::suspend(){
+ if (!suspended) {
+ suspended = true;
+ textfield->setDisabled(true);
+ }
+}
+
+/** Slot: Change status of GammaCtrl when pressed */
+void GammaCtrl::pressed(){
+ if (suspended) {
+ suspended=false;
+ textfield->setDisabled(false);
+ changed=true;
+ setGamma(slider->value());
+ }
+}
+
diff --git a/kgamma/kcmkgamma/gammactrl.h b/kgamma/kcmkgamma/gammactrl.h
new file mode 100644
index 00000000..0d6ea890
--- /dev/null
+++ b/kgamma/kcmkgamma/gammactrl.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+ gammactrl.h - description
+ -------------------
+ begin : Sun Oct 7 2001
+ copyright : (C) 2001 by Michael v.Ostheim
+ email : MvOstheim@web.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+/**A horizontal slider and a text field for the gamma value.
+ *@author Michael v.Ostheim
+ */
+
+#ifndef GAMMACTRL_H
+#define GAMMACTRL_H
+
+#include <qhbox.h>
+#include <qslider.h>
+
+class QString;
+class DisplayNumber;
+class XVidExtWrap;
+
+class GammaCtrl : public QHBox {
+
+ Q_OBJECT
+ public:
+ /** construktor */
+ GammaCtrl(QWidget *parent=0, XVidExtWrap *xvid=0, int channel=0, \
+ const QString& mingamma="0.40", const QString& maxgamma="3.50", \
+ const QString& setgamma="1.00", const char *name=0 );
+ /** destruktor */
+ ~GammaCtrl();
+ /** Return the current gamma value with precision prec */
+ QString gamma(int);
+ /** Set gamma, slider and textfield */
+ void setGamma(const QString&);
+ /** Set slider and textfield */
+ void setControl(const QString&);
+ /** Disable the slider */
+ void disableSlider() { slider->setDisabled(true);};
+
+ private:
+ QString mgamma;
+ QSlider *slider;
+ DisplayNumber *textfield;
+ bool suspended, changed;
+ int gchannel, oldpos;
+ double ming;
+ XVidExtWrap *xv;
+
+ public slots:
+ /** Disable textfield */
+ void suspend();
+
+ protected slots:
+ /** Set slider and textfield */
+ void setCtrl(int);
+ /** Set gamma and textfield */
+ void setGamma(int);
+ /** Change status of GammaCtrl when pressed */
+ void pressed();
+
+ signals:
+ /** Gamma change signal */
+ void gammaChanged(int);
+};
+
+#endif
diff --git a/kgamma/kcmkgamma/kgamma.cpp b/kgamma/kcmkgamma/kgamma.cpp
new file mode 100644
index 00000000..427d01c4
--- /dev/null
+++ b/kgamma/kcmkgamma/kgamma.cpp
@@ -0,0 +1,625 @@
+/***************************************************************************
+ kgamma.cpp - description
+ -------------------
+ begin : Sun Dec 16 13:52:24 CET 2001
+ copyright : (C) 2001 by Michael v.Ostheim
+ email : MvOstheim@web.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include <unistd.h>
+
+#include <qlabel.h>
+#include <qpixmap.h>
+#include <qstring.h>
+#include <qlayout.h>
+#include <qstringlist.h>
+#include <qdir.h>
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qwidgetstack.h>
+
+#include <kstandarddirs.h>
+#include <kconfig.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kprocess.h>
+#include <kdialog.h>
+#include <kgenericfactory.h>
+
+#include "config.h"
+#include "xf86configpath.h"
+#include "gammactrl.h"
+#include "xvidextwrap.h"
+#include "kgamma.h"
+#include "kgamma.moc"
+
+typedef KGenericFactory<KGamma, QWidget> KGammaFactory;
+K_EXPORT_COMPONENT_FACTORY ( kcm_kgamma, KGammaFactory( "kgamma" ) )
+
+extern "C"
+{
+ bool test_kgamma()
+ {
+ bool retval;
+ (void) new XVidExtWrap(&retval, NULL);
+ return retval;
+ }
+}
+
+KGamma::KGamma(QWidget *parent, const char *name, const QStringList&)
+ :KCModule(parent,name)
+{
+ bool ok;
+ GammaCorrection = true;
+ xv = new XVidExtWrap(&ok, NULL);
+ if (ok) { /* KDE 4: Uneccessary test, when all KCM wrappers do conditional loading */
+ xv->getGamma(XVidExtWrap::Red, &ok);
+ if (ok) {
+ ScreenCount = xv->_ScreenCount();
+ currentScreen = xv->getScreen();
+ xv->setGammaLimits(0.4, 3.5);
+
+ for (int i = 0; i < ScreenCount; i++ ) {
+ assign << 0;
+ rgamma << "";
+ ggamma << "";
+ bgamma << "";
+
+ // Store the current gamma values
+ xv->setScreen(i);
+ rbak << xv->getGamma(XVidExtWrap::Red);
+ gbak << xv->getGamma(XVidExtWrap::Green);
+ bbak << xv->getGamma(XVidExtWrap::Blue);
+ }
+ xv->setScreen(currentScreen);
+
+ rootProcess = new KProcess;
+ setupUI();
+ saved = false;
+
+ if (!loadSettings()) { //try to load gamma values from config file
+ // if failed, take current gamma values
+ for (int i = 0; i < ScreenCount; i++ ) {
+ rgamma[i].setNum(rbak[i], 'f', 2);
+ ggamma[i].setNum(gbak[i], 'f', 2);
+ bgamma[i].setNum(bbak[i], 'f', 2);
+ }
+ }
+ load();
+ }
+ else { //something is wrong, show only error message
+ GammaCorrection = false;
+ setupUI();
+ }
+ }
+}
+
+KGamma::~KGamma() {
+ // Restore the old gamma settings, if the user has not saved
+ // and there is no valid kgammarc.
+ // Existing user settings overwrite system settings
+ if (GammaCorrection) {
+ if ( loadUserSettings() ) load();
+ else if ( !saved )
+ for (int i = 0; i < ScreenCount; i++ ) {
+ xv->setScreen(i);
+ xv->setGamma( XVidExtWrap::Red, rbak[i] );
+ xv->setGamma( XVidExtWrap::Green, gbak[i] );
+ xv->setGamma( XVidExtWrap::Blue, bbak[i] );
+ }
+ delete rootProcess;
+ }
+ delete xv;
+}
+
+/** User interface */
+void KGamma::setupUI() {
+ QBoxLayout *topLayout = new QVBoxLayout(this, 0, KDialog::spacingHint());
+
+ if (GammaCorrection) {
+ QHBoxLayout *hbox = new QHBoxLayout( topLayout );
+ QLabel *label = new QLabel( i18n( "&Select test picture:" ) , this);
+ QComboBox *combo = new QComboBox( this );
+ label->setBuddy( combo );
+
+ QStringList list;
+ list << i18n( "Gray Scale" )
+ << i18n( "RGB Scale" )
+ << i18n( "CMY Scale" )
+ << i18n( "Dark Gray" )
+ << i18n( "Mid Gray" )
+ << i18n( "Light Gray" );
+ combo->insertStringList( list );
+
+ hbox->addWidget( label );
+ hbox->addWidget( combo );
+ hbox->addStretch();
+
+ QWidgetStack *stack = new QWidgetStack( this );
+ stack->setFrameStyle( QFrame::Box | QFrame::Raised );
+
+ connect( combo, SIGNAL( activated( int ) ),
+ stack, SLOT( raiseWidget( int ) ) );
+
+ QPixmap background;
+ background.load(locate("data", "kgamma/pics/background.png"));
+
+ QLabel *pic1 = new QLabel(stack);
+ pic1->setMinimumSize(530, 171);
+ pic1->setBackgroundPixmap(background);
+ pic1->setPixmap(QPixmap(locate("data", "kgamma/pics/greyscale.png")));
+ pic1->setAlignment(AlignCenter);
+ stack->addWidget( pic1, 0 );
+
+ QLabel *pic2 = new QLabel(stack);
+ pic2->setBackgroundPixmap(background);
+ pic2->setPixmap(QPixmap(locate("data", "kgamma/pics/rgbscale.png")));
+ pic2->setAlignment(AlignCenter);
+ stack->addWidget( pic2, 1 );
+
+ QLabel *pic3 = new QLabel(stack);
+ pic3->setBackgroundPixmap(background);
+ pic3->setPixmap(QPixmap(locate("data", "kgamma/pics/cmyscale.png")));
+ pic3->setAlignment(AlignCenter);
+ stack->addWidget( pic3, 2 );
+
+ QLabel *pic4 = new QLabel(stack);
+ pic4->setBackgroundPixmap(background);
+ pic4->setPixmap(QPixmap(locate("data", "kgamma/pics/darkgrey.png")));
+ pic4->setAlignment(AlignCenter);
+ stack->addWidget( pic4, 3 );
+
+ QLabel *pic5 = new QLabel(stack);
+ pic5->setBackgroundPixmap(background);
+ pic5->setPixmap(QPixmap(locate("data", "kgamma/pics/midgrey.png")));
+ pic5->setAlignment(AlignCenter);
+ stack->addWidget( pic5, 4 );
+
+ QLabel *pic6 = new QLabel(stack);
+ pic6->setBackgroundPixmap(background);
+ pic6->setPixmap(QPixmap(locate("data", "kgamma/pics/lightgrey.png")));
+ pic6->setAlignment(AlignCenter);
+ stack->addWidget( pic6, 5 );
+
+ topLayout->addWidget(stack, 10);
+
+ //Sliders for gamma correction
+ QFrame *frame1 = new QFrame(this);
+ frame1->setFrameStyle( QFrame::GroupBoxPanel | QFrame::Plain );
+
+ QFrame *frame2 = new QFrame(this);
+ frame2->setFrameStyle( QFrame::GroupBoxPanel | QFrame::Plain );
+
+ QLabel *gammalabel = new QLabel(this);
+ gammalabel->setText(i18n("Gamma:"));
+
+ QLabel *redlabel = new QLabel(this);
+ redlabel->setText(i18n("Red:"));
+
+ QLabel *greenlabel = new QLabel(this);
+ greenlabel->setText(i18n("Green:"));
+
+ QLabel *bluelabel = new QLabel(this);
+ bluelabel->setText(i18n("Blue:"));
+
+ gctrl = new GammaCtrl(this, xv);
+ connect(gctrl, SIGNAL(gammaChanged(int)), SLOT(Changed()));
+ connect(gctrl, SIGNAL(gammaChanged(int)), SLOT(SyncScreens()));
+ gammalabel->setBuddy( gctrl );
+
+ rgctrl = new GammaCtrl(this, xv, XVidExtWrap::Red);
+ connect(rgctrl, SIGNAL(gammaChanged(int)), SLOT(Changed()));
+ connect(rgctrl, SIGNAL(gammaChanged(int)), SLOT(SyncScreens()));
+ connect(gctrl, SIGNAL(gammaChanged(int)), rgctrl, SLOT(setCtrl(int)));
+ connect(rgctrl, SIGNAL(gammaChanged(int)), gctrl, SLOT(suspend()));
+ redlabel->setBuddy( rgctrl );
+
+ ggctrl = new GammaCtrl(this, xv, XVidExtWrap::Green);
+ connect(ggctrl, SIGNAL(gammaChanged(int)), SLOT(Changed()));
+ connect(ggctrl, SIGNAL(gammaChanged(int)), SLOT(SyncScreens()));
+ connect(gctrl, SIGNAL(gammaChanged(int)), ggctrl, SLOT(setCtrl(int)));
+ connect(ggctrl, SIGNAL(gammaChanged(int)), gctrl, SLOT(suspend()));
+ greenlabel->setBuddy( ggctrl );
+
+ bgctrl = new GammaCtrl(this, xv, XVidExtWrap::Blue);
+ connect(bgctrl, SIGNAL(gammaChanged(int)), SLOT(Changed()));
+ connect(bgctrl, SIGNAL(gammaChanged(int)), SLOT(SyncScreens()));
+ connect(gctrl, SIGNAL(gammaChanged(int)), bgctrl, SLOT(setCtrl(int)));
+ connect(bgctrl, SIGNAL(gammaChanged(int)), gctrl, SLOT(suspend()));
+ bluelabel->setBuddy( bgctrl );
+
+ QGridLayout *grid = new QGridLayout(4, 9);
+ grid->setSpacing(8);
+ grid->addMultiCellWidget(frame1, 0, 2, 0, 3);
+ grid->addMultiCellWidget(frame2, 4, 8, 0, 3);
+ grid->addWidget(gammalabel, 1, 1, Qt::AlignRight);
+ grid->addWidget(redlabel, 5, 1, Qt::AlignRight);
+ grid->addWidget(greenlabel, 6, 1, Qt::AlignRight);
+ grid->addWidget(bluelabel, 7, 1, Qt::AlignRight);
+ grid->addWidget(gctrl, 1, 2);
+ grid->addWidget(rgctrl, 5, 2);
+ grid->addWidget(ggctrl, 6, 2);
+ grid->addWidget(bgctrl, 7, 2);
+
+ topLayout->addLayout(grid);
+
+ //Options
+ QHBox *options = new QHBox(this);
+
+ xf86cfgbox = new QCheckBox( i18n("Save settings to XF86Config"), options );
+ connect(xf86cfgbox, SIGNAL(clicked()), SLOT(changeConfig()));
+
+ syncbox = new QCheckBox( i18n("Sync screens"), options );
+ connect(syncbox, SIGNAL(clicked()), SLOT(SyncScreens()));
+ connect(syncbox, SIGNAL(clicked()), SLOT(Changed()));
+
+ screenselect = new QComboBox( options );
+ for ( int i = 0; i < ScreenCount; i++ )
+ screenselect->insertItem( i18n("Screen %1").arg(i+1) );
+ screenselect->setCurrentItem(currentScreen);
+ connect(screenselect, SIGNAL(activated(int)), SLOT(changeScreen(int)));
+
+ options->setSpacing( 10 );
+ options->setStretchFactor( xf86cfgbox, 10 );
+ options->setStretchFactor( syncbox, 1 );
+ options->setStretchFactor( screenselect, 1 );
+
+ topLayout->addWidget(options);
+ }
+ else {
+ QLabel *error = new QLabel(this);
+ error->setText(i18n("Gamma correction is not supported by your"
+ " graphics hardware or driver."));
+ error->setAlignment(AlignCenter);
+ topLayout->addWidget(error);
+ }
+}
+
+void KGamma::load() {
+ load( false );
+}
+
+/** Restore latest saved gamma values */
+void KGamma::load(bool useDefaults) {
+ if (GammaCorrection) {
+ KConfig *config = new KConfig("kgammarc");
+
+ config->setReadDefaults( useDefaults );
+
+ config->setGroup("ConfigFile");
+
+ // save checkbox status
+ if ( xf86cfgbox->isChecked() ) config->writeEntry("use", "XF86Config");
+ else config->writeEntry("use", "kgammarc");
+
+ // load syncbox status
+ config->setGroup("SyncBox");
+ if ( config->readEntry("sync") == "yes" ) syncbox->setChecked(true);
+ else syncbox->setChecked(false);
+
+ config->sync();
+ delete config;
+
+ for (int i = 0; i < ScreenCount; i++) {
+ xv->setScreen(i);
+ if (rgamma[i] == ggamma[i] && rgamma[i] == bgamma[i])
+ if (i == currentScreen) gctrl->setGamma(rgamma[i]);
+ else xv->setGamma(XVidExtWrap::Value, rgamma[i].toFloat());
+ else {
+ if (i == currentScreen) {
+ rgctrl->setGamma(rgamma[i]);
+ ggctrl->setGamma(ggamma[i]);
+ bgctrl->setGamma(bgamma[i]);
+ gctrl->suspend();
+ }
+ else {
+ xv->setGamma(XVidExtWrap::Red, rgamma[i].toFloat());
+ xv->setGamma(XVidExtWrap::Green, ggamma[i].toFloat());
+ xv->setGamma(XVidExtWrap::Blue, bgamma[i].toFloat());
+ }
+ }
+ }
+ xv->setScreen(currentScreen);
+
+ emit changed(useDefaults);
+ }
+}
+
+void KGamma::save() {
+ if (GammaCorrection) {
+ for (int i = 0; i < ScreenCount; i++) {
+ xv->setScreen(i);
+ rgamma[i] = rgctrl->gamma(2);
+ ggamma[i] = ggctrl->gamma(2);
+ bgamma[i] = bgctrl->gamma(2);
+ }
+ xv->setScreen(currentScreen);
+
+ KConfig *config = new KConfig("kgammarc");
+ config->setGroup("SyncBox");
+ if ( syncbox->isChecked() ) config->writeEntry("sync", "yes");
+ else config->writeEntry("sync", "no");
+
+ if ( !xf86cfgbox->isChecked() ) { //write gamma settings to the users config
+ for (int i = 0; i < ScreenCount; i++) {
+ config->setGroup( QString("Screen %1").arg(i) );
+ config->writeEntry("rgamma", rgamma[i]);
+ config->writeEntry("ggamma", ggamma[i]);
+ config->writeEntry("bgamma", bgamma[i]);
+ }
+ config->setGroup("ConfigFile");
+ config->writeEntry("use", "kgammarc");
+ }
+ else { // write gamma settings to section "Monitor" of XF86Config
+ config->setGroup("ConfigFile");
+ config->writeEntry("use", "XF86Config");
+
+ if ( !rootProcess->isRunning() ) {
+ QString Arguments = "xf86gammacfg ";
+ for (int i = 0; i < ScreenCount; i++)
+ Arguments += rgamma[assign[i]] + " " + ggamma[assign[i]] + " " + \
+ bgamma[assign[i]] + " ";
+ rootProcess->clearArguments();
+ *rootProcess << "kdesu" << Arguments;
+ rootProcess->start();
+ }
+ }
+ config->sync();
+ delete config;
+ saved = true;
+ emit changed(false);
+ }
+}
+
+void KGamma::defaults() {
+ load( true );
+}
+
+bool KGamma::loadSettings() {
+ KConfig *config = new KConfig("kgammarc");
+ config->setGroup("ConfigFile");
+ QString ConfigFile( config->readEntry("use") );
+ config->setGroup("SyncBox");
+ if ( config->readEntry("sync") == "yes" ) syncbox->setChecked(true);
+ delete config;
+
+ if ( ConfigFile == "XF86Config" ) { // parse XF86Config
+ xf86cfgbox->setChecked(true);
+ return( loadSystemSettings() );
+ }
+ else { //get gamma settings from user config
+ return( loadUserSettings() );
+ }
+}
+
+bool KGamma::loadUserSettings() {
+ KConfig *config = new KConfig("kgammarc");
+
+ for (int i = 0; i < ScreenCount; i++) {
+ config->setGroup(QString( "Screen %1" ).arg(i) );
+ rgamma[i] = config->readEntry("rgamma");
+ ggamma[i] = config->readEntry("ggamma");
+ bgamma[i] = config->readEntry("bgamma");
+ }
+ delete config;
+
+ return( validateGammaValues() );
+}
+
+bool KGamma::loadSystemSettings() {
+ QStringList Monitor, Screen, ScreenLayout, ScreenMonitor, Gamma;
+ QValueList<int> ScreenNr;
+ QString Section;
+ XF86ConfigPath Path;
+
+ QFile f( Path.get() );
+ if ( f.open(IO_ReadOnly) ) {
+ QTextStream t( &f );
+ QString s;
+ int sn = 0;
+ bool gm = false;
+
+ // Analyse Screen<->Monitor assignments of multi-head configurations
+ while ( !t.eof() ) {
+ s = (t.readLine()).simplifyWhiteSpace();
+ QStringList words = QStringList::split(' ', s);
+
+ if ( !words.empty() ) {
+ if ( words[0] == "Section" && words.size() > 1 ) {
+ if ( (Section = words[1]) == "\"Monitor\"" ) gm = false;
+ }
+ else if ( words[0] == "EndSection" ) {
+ if ( Section == "\"Monitor\"" && !gm ) {
+ Gamma << "";
+ gm = false;
+ }
+ Section = "";
+ }
+ else if ( words[0] == "Identifier" && words.size() > 1 ) {
+ if ( Section == "\"Monitor\"" ) Monitor << words[1];
+ else if ( Section == "\"Screen\"" ) Screen << words[1];
+ }
+ else if ( words[0] == "Screen" && words.size() > 1 ) {
+ if ( Section == "\"ServerLayout\"" ) {
+ bool ok;
+ int i = words[1].toInt(&ok);
+ if ( ok && words.size() > 2 ) {
+ ScreenNr << i;
+ ScreenLayout << words[2];
+ }
+ else {
+ ScreenNr << sn++;
+ ScreenLayout << words[1];
+ }
+ }
+ }
+ else if ( words[0] == "Monitor" && words.size() > 1 ) {
+ if ( Section == "\"Screen\"" )
+ ScreenMonitor << words[1];
+ }
+ else if ( words[0] == "Gamma" ) {
+ if ( Section == "\"Monitor\"" ) {
+ Gamma << s;
+ gm = true;
+ }
+ }
+ }
+ } // End while
+ f.close();
+
+ for ( int i = 0; i < ScreenCount; i++ ) {
+ for ( int j = 0; j < ScreenCount; j++ ) {
+ if ( ScreenLayout[i] == Screen[j] ) {
+ for ( int k = 0; k < ScreenCount; k++ ) {
+ if ( Monitor[k] == ScreenMonitor[j] )
+ assign[ScreenNr[i]] = k;
+ }
+ }
+ }
+ }
+
+ // Extract gamma values
+ for ( int i = 0; i < ScreenCount; i++) {
+ rgamma[i] = ggamma[i] = bgamma[i] = "";
+
+ QStringList words = QStringList::split(' ', Gamma[assign[i]]);
+ QStringList::ConstIterator it = words.begin();
+ if ( words.size() < 4 )
+ rgamma[i] = ggamma[i] = bgamma[i] = *(++it); // single gamma value
+ else {
+ rgamma[i] = *(++it); // eventually rgb gamma values
+ ggamma[i] = *(++it);
+ bgamma[i] = *(++it);
+ }
+ }
+
+ }
+ return( validateGammaValues() );
+}
+
+bool KGamma::validateGammaValues() {
+ bool rOk, gOk, bOk, result;
+
+ result = true;
+ for (int i = 0; i < ScreenCount; i++ ) {
+ rgamma[i].toFloat( &rOk );
+ ggamma[i].toFloat( &gOk );
+ bgamma[i].toFloat( &bOk );
+
+ if ( !(rOk && gOk && bOk) ) {
+ if ( rOk ) ggamma[i] = bgamma[i] = rgamma[i];
+ else result = false;
+ }
+ }
+ return(result);
+}
+
+void KGamma::changeConfig() {
+ bool Ok = false;
+
+ if ( xf86cfgbox->isChecked() ) Ok = loadSystemSettings();
+ else Ok = loadUserSettings();
+
+ if ( !Ok ) {
+ for (int i = 0; i < ScreenCount; i++ ) {
+ xv->setScreen(i);
+ rgamma[i].setNum(xv->getGamma(XVidExtWrap::Red), 'f', 2);
+ ggamma[i].setNum(xv->getGamma(XVidExtWrap::Green), 'f', 2);
+ bgamma[i].setNum(xv->getGamma(XVidExtWrap::Blue), 'f', 2);
+ }
+ xv->setScreen(currentScreen);
+ }
+ load();
+}
+
+void KGamma::SyncScreens() {
+ if ( syncbox->isChecked() ) {
+ float rg = xv->getGamma(XVidExtWrap::Red);
+ float gg = xv->getGamma(XVidExtWrap::Green);
+ float bg = xv->getGamma(XVidExtWrap::Blue);
+
+ for (int i = 0; i < ScreenCount; i++ ) {
+ if ( i != currentScreen ) {
+ xv->setScreen(i);
+ xv->setGamma(XVidExtWrap::Red, rg);
+ xv->setGamma(XVidExtWrap::Green, gg);
+ xv->setGamma(XVidExtWrap::Blue, bg);
+ }
+ }
+ xv->setScreen(currentScreen);
+ }
+}
+
+void KGamma::changeScreen(int sn) {
+ QString red, green, blue;
+
+ xv->setScreen(sn);
+ currentScreen = sn;
+
+ red.setNum(xv->getGamma(XVidExtWrap::Red), 'f', 2);
+ green.setNum(xv->getGamma(XVidExtWrap::Green), 'f', 2);
+ blue.setNum(xv->getGamma(XVidExtWrap::Blue), 'f', 2);
+
+ gctrl->setControl(red);
+ rgctrl->setControl(red);
+ ggctrl->setControl(green);
+ bgctrl->setControl(blue);
+ if (red != green || red != blue) gctrl->suspend();
+}
+
+int KGamma::buttons () {
+ return Default|Apply|Help;
+}
+
+QString KGamma::quickHelp() const
+{
+ return i18n("<h1>Monitor Gamma</h1> This is a tool for changing monitor gamma"
+ " correction. Use the four sliders to define the gamma correction either"
+ " as a single value, or separately for the red, green and blue components."
+ " You may need to correct the brightness and contrast settings of your"
+ " monitor for good results. The test images help you to find proper"
+ " settings.<br> You can save them system-wide to XF86Config (root access"
+ " is required for that) or to your own KDE settings. On multi head"
+ " systems you can correct the gamma values separately for all screens.");
+}
+
+
+// ------------------------------------------------------------------------
+
+extern "C"
+{
+ // Restore the user gamma settings
+ void init_kgamma()
+ {
+ bool ok;
+ XVidExtWrap xv(&ok);
+
+ if (ok) {
+ xv.setGammaLimits(0.4, 3.5);
+ float rgamma, ggamma, bgamma;
+ KConfig *config = new KConfig("kgammarc");
+
+ for (int i = 0; i < xv._ScreenCount(); i++) {
+ xv.setScreen(i);
+ config->setGroup( QString("Screen %1").arg(i) );
+
+ if ((rgamma = config->readEntry("rgamma").toFloat()))
+ xv.setGamma(XVidExtWrap::Red, rgamma);
+ if ((ggamma = config->readEntry("ggamma").toFloat()))
+ xv.setGamma(XVidExtWrap::Green, ggamma);
+ if ((bgamma = config->readEntry("bgamma").toFloat()))
+ xv.setGamma(XVidExtWrap::Blue, bgamma);
+ }
+ delete config;
+ }
+ }
+}
diff --git a/kgamma/kcmkgamma/kgamma.desktop b/kgamma/kcmkgamma/kgamma.desktop
new file mode 100644
index 00000000..5d4c3b05
--- /dev/null
+++ b/kgamma/kcmkgamma/kgamma.desktop
@@ -0,0 +1,129 @@
+[Desktop Entry]
+Comment=A monitor calibration tool
+Comment[ar]=أداة مراقبة وتعيير
+Comment[bg]=Калибриране на монитора
+Comment[bs]=Alat za kalibraciju monitora
+Comment[ca]=Una eina de calibració del monitor
+Comment[cs]=Nástroj pro kalibraci monitoru
+Comment[cy]=Erfyn graddnodi dangosydd
+Comment[da]=Et skærmkalibreringsværktøj
+Comment[de]=Ein Kalibrierungswerkzeug für Monitore
+Comment[el]=Ένα εργαλείο ρύθμισης της οθόνης
+Comment[eo]=Ekrankalibrilo
+Comment[es]=Una herramienta de calibración del monitor
+Comment[et]=Monitori kalibreerija
+Comment[eu]=Monitoreak kalibratzeko tresna
+Comment[fa]=ابزار درجه‌بندی نمایشگر
+Comment[fi]=Näytön asetustyökalu
+Comment[fr]=Outil de calibrage de moniteur
+Comment[gl]=Unha utilidade para calibrar o monitor
+Comment[hi]=मॉनीटर केलिब्रेशन औज़ार
+Comment[hu]=Monitorbeállító program
+Comment[is]=Tól til að stilla skjáinn
+Comment[it]=Calibrazione del monitor
+Comment[ja]=モニタ測定ツール
+Comment[kk]=Мониторды калибрлеу құралы
+Comment[km]=ឧបករណ៍​ក្រិត​របស់​ម៉ូនីទ័រ
+Comment[lt]=Monitoriaus kalibravimo įrankis
+Comment[ms]=Alat tentukur monitor
+Comment[nb]=Et verktøy for å kalibrere skjermen
+Comment[nds]=En Afstimmwarktüüch för Monitoren
+Comment[ne]=मोनिटर क्यालिब्रेसन उपकरण
+Comment[nl]=Gereedschap om de kleurweergave goed in te stellen
+Comment[nn]=Eit verktøy for å kalibrera skjermen
+Comment[pl]=Narzędzie do kalibracji monitora
+Comment[pt]=Ferramenta de calibração do monitor
+Comment[pt_BR]=Uma ferramenta de calibragem de monitor
+Comment[ro]=Un utilitar de calibrat monitorul
+Comment[ru]=Утилита для калибровки монитора
+Comment[sk]=Kalibračný nástroj pre monitor
+Comment[sl]=Kalibracijsko orodje za monitorje
+Comment[sr]=Алат за калибрацију монитора
+Comment[sr@Latn]=Alat za kalibraciju monitora
+Comment[sv]=Kalibreringsverktyg för skärmen
+Comment[ta]=திரை நிலைக்கருவி
+Comment[tg]=Утилита барои калибратсия кардани монитор
+Comment[th]=เครื่องมือปรับความเที่ยงตรงของจอภาพ
+Comment[tr]=Monitör kalibrasyon aracı
+Comment[uk]=Засіб для калібрування монітора
+Comment[zh_CN]=监视器校准工具
+Comment[zh_HK]=顯示器調校工具
+Comment[zh_TW]=監視器校準工具
+
+Name=Gamma
+Name[ar]=غاما
+Name[az]=Qamma
+Name[bg]=Гама
+Name[cs]=Gama
+Name[cy]=Gama
+Name[el]=Γάμμα
+Name[eo]=Gamo
+Name[fa]=گاما
+Name[ga]=Gáma
+Name[gl]=Gama
+Name[he]=גאמה
+Name[hr]=Gama
+Name[hu]=Gamma-korrekció
+Name[is]=Litatíðni (gamma)
+Name[kk]=Гамма
+Name[km]=ហ្គាម៉ា
+Name[ne]=गामा
+Name[pa]=ਗ਼ਾਮਾ
+Name[pt]=Gama
+Name[ru]=Гамма
+Name[sl]=Gama
+Name[sr]=Гама
+Name[sr@Latn]=Gama
+Name[ta]=காமா
+Name[tg]=Гамма
+Name[th]=แกมมา
+Name[uk]=Гама
+Name[uz@cyrillic]=Гамма
+Name[wa]=Gama
+Name[xh]=Unobumba wesithathu konoobumba besiGrike
+Name[zh_HK]=伽馬(Gamma)
+
+DocPath=kgamma
+Exec=kcmshell kgamma
+Icon=kgamma
+Keywords=KGamma, kgamma, Gamma, gamma
+Keywords[bg]=калибриране, гама, яркост, цвят, монитор, екран, KGamma, kgamma, Gamma, gamma
+Keywords[cs]=KGamma, kgamma, gama
+Keywords[de]=KGamma,kgamma,Gamma,gamma
+Keywords[el]=KGamma, kgamma, Γάμμα, γάμμα
+Keywords[ga]=KGamma, kgamma, Gamma, gamma, Gáma
+Keywords[gl]=KGamma, kgamma, Gamma, gamma, gama
+Keywords[he]=KGamma, kgamma, Gamma, gamma, גאמה
+Keywords[hi]=के-गामा,केगामा,गामा,गामा
+Keywords[hu]=KGamma,kgamma,gamma,gamma-korrekció
+Keywords[it]=KGamma,gamma
+Keywords[ja]=KGamma, kgamma, ガンマ, Gamma, gamma
+Keywords[km]=KGamma, kgamma,ហ្គ៉ាម៉ា
+Keywords[lt]=KGamma, kgamma, Gamma, gamma, gama
+Keywords[nds]=KGamma,kgamma,Gamma,gamma
+Keywords[ne]=के गामा, के गामा, गामा, गामा
+Keywords[nl]=KGamma,kgamma,Gamma,gamma,kleurweergave
+Keywords[nn]=KGamma,gamma
+Keywords[pl]=KGamma, kgamma, Gamma, gamma, jasność,ciemność,rozjaśnienie
+Keywords[pt]=kgamma, gama
+Keywords[pt_BR]=KGama, kgama, Gama, gama
+Keywords[ro]=KGamma,kgamma,gama,gamma
+Keywords[ru]=KGamma,kgamma,Gamma,gamma,гамма,монитор
+Keywords[sk]=KGamma, kgamma, gamma
+Keywords[sl]=KGamma,kgamma,Gama,gama
+Keywords[sr]=KGamma, kgamma, Gamma, gamma, гама
+Keywords[sr@Latn]=KGamma, kgamma, Gamma, gamma, gama
+Keywords[ta]=கேகாமா, கேகாமா, காமா, காமா
+Keywords[tg]=KGamma,kgamma,Gamma,gamma,гамма,монитор
+Keywords[uk]=KGamma, kgamma, Gamma, gamma, гама, яскравість
+Keywords[uz@cyrillic]=KGamma, kgamma, Гамма, гамма
+Keywords[wa]=KGamma, kgamma, Gama, gama
+Keywords[zh_CN]=KGamma, kgamma, Gamma, gamma,伽玛
+Type=Application
+X-KDE-Init=kgamma
+X-KDE-FactoryName=kgamma
+X-KDE-Library=kgamma
+X-KDE-ModuleType=Library
+X-KDE-Test-Module=true
+NoDisplay=true
+Categories=Qt;KDE;Settings;X-KDE-settings-peripherals;
diff --git a/kgamma/kcmkgamma/kgamma.h b/kgamma/kcmkgamma/kgamma.h
new file mode 100644
index 00000000..b347e2a1
--- /dev/null
+++ b/kgamma/kcmkgamma/kgamma.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+ kgamma.h - description
+ -------------------
+ begin : Sun Dec 16 13:52:24 CET 2001
+ copyright : (C) 2001 by Michael v.Ostheim
+ email : MvOstheim@web.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+#ifndef KGAMMA_H_
+#define KGAMMA_H_
+
+#include <kcmodule.h>
+
+class GammaCtrl;
+class QCheckBox;
+class QComboBox;
+class XVidExtWrap;
+class KProcess;
+
+class KGamma: public KCModule
+{
+ Q_OBJECT
+ public:
+ KGamma(QWidget *parent, const char *name, const QStringList&);
+ virtual ~KGamma();
+
+ void load();
+ void load(bool useDefaults);
+ void save();
+ void defaults();
+ int buttons();
+ QString quickHelp() const;
+
+ protected: // Protected methods
+ /** The user interface */
+ void setupUI();
+ /** Decides if to load settings from user or system config */
+ bool loadSettings();
+ /** Load settings from kgammarc */
+ bool loadUserSettings();
+ /** Load settings from XF86Config */
+ bool loadSystemSettings();
+ /** Validate the loaded gamma values */
+ bool validateGammaValues();
+
+ private slots:
+ /** Called if the user changesd something */
+ void Changed() { emit changed(true); }
+ /** Called if the user marked or unmarked the XF86Config checkbox */
+ void changeConfig();
+ /** Called if the user marked or unmarked the sync screen checkbox */
+ void SyncScreens();
+ /** Called if the user chooses a new screen */
+ void changeScreen(int sn);
+
+ private:
+ bool saved, GammaCorrection;
+ int ScreenCount, currentScreen;
+ QStringList rgamma, ggamma, bgamma;
+ QValueList<int> assign;
+ QValueList<float> rbak, gbak, bbak;
+ GammaCtrl *gctrl, *rgctrl, *ggctrl, *bgctrl;
+ QCheckBox *xf86cfgbox, *syncbox;
+ QComboBox *screenselect;
+ KProcess *rootProcess;
+ XVidExtWrap *xv;
+};
+
+#endif
+
diff --git a/kgamma/kcmkgamma/pics/Makefile.am b/kgamma/kcmkgamma/pics/Makefile.am
new file mode 100644
index 00000000..14dd5857
--- /dev/null
+++ b/kgamma/kcmkgamma/pics/Makefile.am
@@ -0,0 +1,7 @@
+
+img_DATA = background.png cmyscale.png darkgrey.png greyscale.png lightgrey.png midgrey.png \
+ rgbscale.png
+imgdir = $(kde_datadir)/kgamma/pics
+
+KDE_ICON = kgamma
+
diff --git a/kgamma/kcmkgamma/pics/background.png b/kgamma/kcmkgamma/pics/background.png
new file mode 100644
index 00000000..01797213
--- /dev/null
+++ b/kgamma/kcmkgamma/pics/background.png
Binary files differ
diff --git a/kgamma/kcmkgamma/pics/cmyscale.png b/kgamma/kcmkgamma/pics/cmyscale.png
new file mode 100644
index 00000000..e30700bc
--- /dev/null
+++ b/kgamma/kcmkgamma/pics/cmyscale.png
Binary files differ
diff --git a/kgamma/kcmkgamma/pics/darkgrey.png b/kgamma/kcmkgamma/pics/darkgrey.png
new file mode 100644
index 00000000..221d65e4
--- /dev/null
+++ b/kgamma/kcmkgamma/pics/darkgrey.png
Binary files differ
diff --git a/kgamma/kcmkgamma/pics/greyscale.png b/kgamma/kcmkgamma/pics/greyscale.png
new file mode 100644
index 00000000..8532c3ea
--- /dev/null
+++ b/kgamma/kcmkgamma/pics/greyscale.png
Binary files differ
diff --git a/kgamma/kcmkgamma/pics/hi16-app-kgamma.png b/kgamma/kcmkgamma/pics/hi16-app-kgamma.png
new file mode 100644
index 00000000..de14649c
--- /dev/null
+++ b/kgamma/kcmkgamma/pics/hi16-app-kgamma.png
Binary files differ
diff --git a/kgamma/kcmkgamma/pics/hi32-app-kgamma.png b/kgamma/kcmkgamma/pics/hi32-app-kgamma.png
new file mode 100644
index 00000000..c5f605df
--- /dev/null
+++ b/kgamma/kcmkgamma/pics/hi32-app-kgamma.png
Binary files differ
diff --git a/kgamma/kcmkgamma/pics/hi48-app-kgamma.png b/kgamma/kcmkgamma/pics/hi48-app-kgamma.png
new file mode 100644
index 00000000..19fd51e7
--- /dev/null
+++ b/kgamma/kcmkgamma/pics/hi48-app-kgamma.png
Binary files differ
diff --git a/kgamma/kcmkgamma/pics/lightgrey.png b/kgamma/kcmkgamma/pics/lightgrey.png
new file mode 100644
index 00000000..650603c8
--- /dev/null
+++ b/kgamma/kcmkgamma/pics/lightgrey.png
Binary files differ
diff --git a/kgamma/kcmkgamma/pics/midgrey.png b/kgamma/kcmkgamma/pics/midgrey.png
new file mode 100644
index 00000000..5b22f4c5
--- /dev/null
+++ b/kgamma/kcmkgamma/pics/midgrey.png
Binary files differ
diff --git a/kgamma/kcmkgamma/pics/rgbscale.png b/kgamma/kcmkgamma/pics/rgbscale.png
new file mode 100644
index 00000000..5e9be6d9
--- /dev/null
+++ b/kgamma/kcmkgamma/pics/rgbscale.png
Binary files differ
diff --git a/kgamma/kcmkgamma/xf86configpath.cpp b/kgamma/kcmkgamma/xf86configpath.cpp
new file mode 100644
index 00000000..e6f7163b
--- /dev/null
+++ b/kgamma/kcmkgamma/xf86configpath.cpp
@@ -0,0 +1,56 @@
+/***************************************************************************
+ xf86configpath.cpp - description
+ -------------------
+ begin : Mon Dec 30 2002
+ copyright : (C) 2002 by Michael v.Ostheim
+ email : ostheimm@users.berlios.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <vector>
+
+#include "xf86configpath.h"
+
+using namespace std;
+
+XF86ConfigPath::XF86ConfigPath(){
+ vector <string> searchPaths;
+ searchPaths.push_back("/etc/X11/XF86Config-4");
+ searchPaths.push_back("/etc/X11/XF86Config");
+ searchPaths.push_back("/etc/XF86Config");
+ searchPaths.push_back("/usr/X11R6/etc/X11/XF86Config-4");
+ searchPaths.push_back("/usr/X11R6/etc/X11/XF86Config");
+ searchPaths.push_back("/usr/X11R6/lib/X11/XF86Config-4");
+ searchPaths.push_back("/usr/X11R6/lib/X11/XF86Config");
+
+ searchPaths.push_back("/etc/X11/xorg.conf-4");
+ searchPaths.push_back("/etc/X11/xorg.conf");
+ searchPaths.push_back("/etc/xorg.conf");
+ searchPaths.push_back("/usr/X11R6/etc/X11/xorg.conf-4");
+ searchPaths.push_back("/usr/X11R6/etc/X11/xorg.conf");
+ searchPaths.push_back("/usr/X11R6/lib/X11/xorg.conf-4");
+ searchPaths.push_back("/usr/X11R6/lib/X11/xorg.conf");
+
+ vector<string>::iterator it = searchPaths.begin();
+ for (; it != searchPaths.end(); ++it )
+ if ( !access( (Path = *it).c_str(), F_OK ) ) break;
+}
+
+XF86ConfigPath::~XF86ConfigPath(){
+}
+
+/** Returns path */
+const char* XF86ConfigPath::get(){
+ return( Path.c_str() );
+}
diff --git a/kgamma/kcmkgamma/xf86configpath.h b/kgamma/kcmkgamma/xf86configpath.h
new file mode 100644
index 00000000..88f7afa4
--- /dev/null
+++ b/kgamma/kcmkgamma/xf86configpath.h
@@ -0,0 +1,42 @@
+/***************************************************************************
+ xf86configpath.h - description
+ -------------------
+ begin : Mon Dec 30 2002
+ copyright : (C) 2002 by Michael v.Ostheim
+ email : ostheimm@users.berlios.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef XF86CONFIGPATH_H
+#define XF86CONFIGPATH_H
+
+#include <string>
+
+/**Search for XF86Config or XF86Config-4 which can be located at different
+ places.
+ *@author Michael v.Ostheim
+ */
+
+class XF86ConfigPath {
+
+public:
+ XF86ConfigPath();
+ ~XF86ConfigPath();
+
+ /** Returns Path variable */
+ const char* get();
+
+private: // Private attributes
+ /** Contains the path of XF86Config file */
+ std::string Path;
+};
+
+#endif
diff --git a/kgamma/kcmkgamma/xvidextwrap.cpp b/kgamma/kcmkgamma/xvidextwrap.cpp
new file mode 100644
index 00000000..9d8136d9
--- /dev/null
+++ b/kgamma/kcmkgamma/xvidextwrap.cpp
@@ -0,0 +1,170 @@
+/***************************************************************************
+ xvidextwrap.cpp - description
+ -------------------
+ begin : Sat Jan 5 2002
+ copyright : (C) 2002 by Michael v.Ostheim
+ email : MvOstheim@web.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+#include <X11/Xos.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/xf86vmode.h>
+
+#include <stdlib.h>
+#include <iostream>
+#include <fstream>
+
+#include <vector>
+#include <string>
+
+#include <config.h>
+
+#ifdef HAVE_SSTREAM
+#include <sstream>
+#else
+#include <strstream.h>
+#define istringstream istrstream
+#endif
+
+#include <kdebug.h>
+
+#include "xf86configpath.h"
+#include "xvidextwrap.h"
+
+using namespace std;
+
+
+XVidExtWrap::XVidExtWrap(bool* OK, const char* displayname) {
+ if ((dpy = XOpenDisplay(displayname))) {
+ screen = DefaultScreen(dpy);
+ setGammaLimits(0.1, 10.0);
+ *OK = true;
+ }
+ else {
+ kdDebug() << "KGamma: unable to open display " << displayname << endl;
+ *OK = false;
+ }
+}
+
+XVidExtWrap::~XVidExtWrap() {
+ if (dpy) XCloseDisplay(dpy);
+}
+
+int XVidExtWrap::_DefaultScreen() {
+ return DefaultScreen(dpy);
+}
+
+/** We have to parse XF86Config to get the number of screens, because */
+/** ScreenCount() from X11/Xlib.h does not count correctly with xinerama */
+int XVidExtWrap::_ScreenCount() {
+ int count = 0;
+ bool section = false;
+ XF86ConfigPath Path;
+
+ std::ifstream in( Path.get() );
+
+ if ( in.is_open() ) {
+ std::string s, buf;
+ std::vector<string> words;
+
+ while (getline(in, s,'\n')) {
+ words.clear();
+ istringstream ss(s.c_str());
+ while (ss >> buf) words.push_back(buf); // Split "s" into words
+
+ if ( !words.empty() ) {
+ if ( words[0] == "Section" && words.size() > 1 ) {
+ if ( words[1] == "\"ServerLayout\"" ) section = true;
+ }
+ else if ( words[0] == "EndSection" )
+ section = false;
+ if ( section && words[0] == "Screen" ) ++count;
+ }
+ } //end while
+ in.close();
+
+ }
+
+ if ( !count ) count = 1; //If failed,fill count with a valid value;
+
+ return( count );
+}
+
+const char* XVidExtWrap::DisplayName() {
+ return DisplayString(dpy);
+}
+
+void XVidExtWrap::setGamma(int channel, float gam, bool* OK) {
+ XF86VidModeGamma gamma;
+
+ if ( gam >= mingamma && gam <= maxgamma ) {
+ if (!XF86VidModeGetGamma(dpy, screen, &gamma)) {
+ kdDebug() << "KGamma: Unable to query gamma correction" << endl;
+ if ( OK ) *OK = false;
+ }
+ else {
+ switch (channel) {
+ case Value:
+ gamma.red = gam;
+ gamma.green = gam;
+ gamma.blue = gam; break;
+ case Red:
+ gamma.red = gam; break;
+ case Green:
+ gamma.green = gam; break;
+ case Blue:
+ gamma.blue = gam;
+ };
+ if (!XF86VidModeSetGamma(dpy, screen, &gamma)) {
+ kdDebug() << "KGamma: Unable to set gamma correction" << endl;
+ if ( OK ) *OK = false;
+ }
+ else {
+ XFlush(dpy);
+ if ( OK ) *OK = true;
+ }
+ }
+ }
+}
+
+float XVidExtWrap::getGamma(int channel, bool* OK) {
+ XF86VidModeGamma gamma;
+ float gam = 0;
+
+ if (!XF86VidModeGetGamma(dpy, screen, &gamma)) {
+ kdDebug() << "KGamma: Unable to query gamma correction" << endl;
+ if ( OK ) *OK = false;
+ }
+ else {
+ switch (channel) {
+ case Value:
+ gam = gamma.red; break;
+ case Red:
+ gam = gamma.red; break;
+ case Green:
+ gam = gamma.green; break;
+ case Blue:
+ gam = gamma.blue;
+ };
+ if ( OK ) *OK = true;
+ }
+ return(gam);
+}
+
+void XVidExtWrap::setGammaLimits( float min, float max ) {
+ mingamma = (min < 0.1) ? 0.1 : min;
+ maxgamma = (max > 10.0) ? 10.0 : max;
+}
+
+#ifdef istringstream
+#undef istringstream
+#endif
diff --git a/kgamma/kcmkgamma/xvidextwrap.h b/kgamma/kcmkgamma/xvidextwrap.h
new file mode 100644
index 00000000..20ae4310
--- /dev/null
+++ b/kgamma/kcmkgamma/xvidextwrap.h
@@ -0,0 +1,59 @@
+/***************************************************************************
+ xvidextwrap.h - description
+ -------------------
+ begin : Sat Jan 5 2002
+ copyright : (C) 2002 by Michael v.Ostheim
+ email : MvOstheim@web.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef XVIDEXTWRAP_H
+#define XVIDEXTWRAP_H
+
+struct _XDisplay;
+
+/**A wrapper for XF86VidMode Extension
+ *@author Michael v.Ostheim
+ */
+
+class XVidExtWrap {
+
+ public:
+
+ enum GammaChannel { Value = 0, Red = 1, Green = 2, Blue = 3 };
+ XVidExtWrap(bool *OK, const char* displayname = NULL);
+ ~XVidExtWrap();
+
+ /** Returns the default screen */
+ int _DefaultScreen();
+ /** Returns the number of screens (extracted from XF86Config) */
+ int _ScreenCount();
+ /** Returns the displayname */
+ const char* DisplayName();
+ /** Sets the screen actions are take effect */
+ void setScreen( int scrn ) { screen = scrn; };
+ /** Returns the current screen */
+ int getScreen() { return screen; };
+ /** Sets the gamma value on the current screen */
+ void setGamma( int channel, float gam, bool *OK = NULL );
+ /** Gets the gamma value of the current screen */
+ float getGamma( int channel, bool *OK = NULL );
+ /** Limits the possible gamma values (default 0.1-10.0) */
+ void setGammaLimits( float min, float max );
+
+ private:
+ float mingamma, maxgamma;
+ int screen;
+ Display* dpy;
+};
+
+#endif
+
diff --git a/kgamma/xf86gammacfg/Makefile.am b/kgamma/xf86gammacfg/Makefile.am
new file mode 100644
index 00000000..3c7c0154
--- /dev/null
+++ b/kgamma/xf86gammacfg/Makefile.am
@@ -0,0 +1,11 @@
+
+INCLUDES= $(all_includes)
+
+bin_PROGRAMS = xf86gammacfg
+xf86gammacfg_SOURCES = xf86gammacfg.cpp
+xf86gammacfg_LDADD =
+xf86gammacfg_METASOURCES = AUTO
+noinst_HEADERS =
+
+EXTRA_DIST = xf86gammacfg.cpp
+
diff --git a/kgamma/xf86gammacfg/xf86gammacfg.cpp b/kgamma/xf86gammacfg/xf86gammacfg.cpp
new file mode 100644
index 00000000..db98a8fb
--- /dev/null
+++ b/kgamma/xf86gammacfg/xf86gammacfg.cpp
@@ -0,0 +1,138 @@
+/***************************************************************************
+ main.cpp - description
+ -------------------
+ begin : Wed Aug 7 18:11:19 CEST 2002
+ copyright : (C) 2002 by Michael v.Ostheim
+ email : MvOstheim@web.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include <stdio.h>
+
+#include <stdlib.h>
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+
+#include <config.h>
+
+#ifdef HAVE_SSTREAM
+#include <sstream>
+#else
+#include <strstream.h>
+#define istringstream istrstream
+#endif
+
+using namespace std;
+
+int main(int argc, char *argv[])
+{
+
+ bool cpyonly, secmon, success;
+
+ cpyonly = secmon = success = false;
+
+ if ( !((argc-1) % 3) ) {
+ int Screen = 0;
+ int ScreenCount = (argc-1) / 3;
+
+ // First, search for XF86Config or xorg.conf
+ vector <string> searchPaths;
+ searchPaths.push_back("/etc/X11/XF86Config-4");
+ searchPaths.push_back("/etc/X11/XF86Config");
+ searchPaths.push_back("/etc/XF86Config");
+ searchPaths.push_back("/usr/X11R6/etc/X11/XF86Config-4");
+ searchPaths.push_back("/usr/X11R6/etc/X11/XF86Config");
+ searchPaths.push_back("/usr/X11R6/lib/X11/XF86Config-4");
+ searchPaths.push_back("/usr/X11R6/lib/X11/XF86Config");
+
+ searchPaths.push_back("/etc/X11/xorg.conf-4");
+ searchPaths.push_back("/etc/X11/xorg.conf");
+ searchPaths.push_back("/etc/xorg.conf");
+ searchPaths.push_back("/usr/X11R6/etc/X11/xorg.conf-4");
+ searchPaths.push_back("/usr/X11R6/etc/X11/xorg.conf");
+ searchPaths.push_back("/usr/X11R6/lib/X11/xorg.conf-4");
+ searchPaths.push_back("/usr/X11R6/lib/X11/xorg.conf");
+
+ std::vector<string>::iterator it = searchPaths.begin();
+ for (; it != searchPaths.end(); ++it ) {
+ //Try to open file
+ std::ifstream in( (*it).c_str() );
+
+ if ( in.is_open() ) {
+ std::ofstream out( ( (*it) + ".tmp" ).c_str() );
+ if ( out.is_open() ) {
+ std::string s, buf;
+ std::vector<string> words;
+
+ while (getline(in, s,'\n')) {
+ if (!cpyonly) {
+ words.clear();
+ std::istringstream ss(s.c_str());
+ while (ss >> buf) words.push_back(buf);
+
+ if ( !words.empty() ) {
+ if ( words[0] == "Section" && words.size() > 1 ) {
+ if ( words[1] == "\"Monitor\"" ) {
+ secmon = true;
+ out << s << endl;
+ continue;
+ }
+ }
+ if ( secmon ) {
+ if ( words[0] == "Gamma" ) {
+ out << " Gamma " << argv[3*Screen+1] << " " << \
+ argv[3*Screen+2]<< " " << argv[3*Screen+3];
+ out << " # created by KGamma" << endl;
+ cpyonly = success = ( ++Screen == ScreenCount );
+ secmon = false;
+ continue;
+ }
+ if ( words[0] == "EndSection" ) {
+ out << " Gamma " << argv[3*Screen+1] << " " << \
+ argv[3*Screen+2]<< " " << argv[3*Screen+3];
+ out << " # created by KGamma" << endl;
+ out << s << endl;
+ cpyonly = success = ( ++Screen == ScreenCount );
+ secmon = false;
+ continue;
+ }
+ }
+ }
+ }
+ out << s << endl;
+ } //endwhile
+
+ in.close();
+ out.close();
+
+ if ( success ) {
+ rename( (*it).c_str(),(*it + ".kgammaorig").c_str() );
+ rename( (*it + ".tmp").c_str(),(*it).c_str() );
+ }
+ else remove( (*it + ".tmp").c_str() );
+ break;
+ }
+ }
+ }
+ }
+ if ( !success )
+ cerr << "Usage: xf86gammacfg RGAMMA GGAMMA " \
+ "BGAMMA [RGAMMA GGAMMA BGAMMA [...]]" << endl;
+
+ return success;
+}
+
+#ifdef istringstream
+#undef istringstream
+#endif
diff --git a/kghostview/AUTHORS b/kghostview/AUTHORS
new file mode 100644
index 00000000..001afaa8
--- /dev/null
+++ b/kghostview/AUTHORS
@@ -0,0 +1,9 @@
+Copyright (C) 1997-1998 Mark Donohoe <donohoe@kde.org>
+Copyright (C) 2000 Daniel Duley <mosfet@kde.org>
+Copyright (C) 2000-2002 Wilco Greven <greven@kde.org>
+Copyright (C) 1997 Markkhu Hihnala <mah@ee.oulu.fi>
+Copyright (C) 2000 Espen Sand <espen@kde.org>
+Copyright (C) 1999-2000 David Sweet <dsweet@kde.org>
+Copyright (C) 2002-2003 Luís-Pedro Coelho <luis@luispedro.org>
+
+KGhostView is based on original work by Tim Theisen.
diff --git a/kghostview/ChangeLog b/kghostview/ChangeLog
new file mode 100644
index 00000000..3695036c
--- /dev/null
+++ b/kghostview/ChangeLog
@@ -0,0 +1,40 @@
+Version 0.8:
+ * [Mario Weilguni]
+ Made it work with Qt 2.0
+ Fixed a lot of layout problems
+ Fixed segfault caused by wrong accelerator in ::changeAccelerators()
+ There are still a few problems with changed color handling,
+ currently outcommented (look for "TODO" if you wish to fix it)
+
+Version 0.7:
+ * [Mark Donohoe] Patch from Jake Hamy <jehamby@lightside.com> which
+ incorporates code from Johanes Plass' GV. This adds
+ (1) Compressed file support, (2) PDF support
+ ( Currently limited by ghostscript's poor handling of
+ this format )
+ * [Mark Donohoe] Fixed major performance bug which caused gs to be
+ repeatedly restarted
+ * [Mark Donohoe] Improved print dialog
+ - Print to file
+ - Print all, current, marked, or range of pages
+ - Setup spooler command, printer name
+ - Reverse order of printing
+ * [Mark Donohoe] Much better keyboard support
+ * [Mark Donohoe] Improved geometry management
+ * [Mark Donohoe] Improved warning and error dialogs
+
+Version 0.6.3:
+ * [Mark Donohoe] Session management
+ * [Mark Donohoe] Patch from Markus Duda <Duda@physik.rwth-aachen.de> for
+ pagelist.
+ ( Fixes a problem with documents that have named rather
+ than numbered pages I believe )
+ * [Mark Donohoe] Imporvements to page list interface
+ * [Mark Donohoe] Fixed mix up of Magnification and Orientation on
+ View Control dialog
+ * [Mark Donohoe] Few geometry management fixes
+ * [Mark Donohoe] New icon
+
+Version 0.6.1:
+ * [Robert Williams] Added version.h and ChangeLog
+ * [Robert Williams] Added -caption "%c" to kghostview.kdelnk
diff --git a/kghostview/Makefile.am b/kghostview/Makefile.am
new file mode 100644
index 00000000..93209382
--- /dev/null
+++ b/kghostview/Makefile.am
@@ -0,0 +1,69 @@
+SUBDIRS = data
+
+INCLUDES= $(all_includes)
+
+####### Files
+
+bin_PROGRAMS = kghostview
+lib_LTLIBRARIES = libkghostviewlib.la
+kde_module_LTLIBRARIES = libkghostviewpart.la
+noinst_LTLIBRARIES = libdscparse.la
+
+libkghostviewlib_la_LDFLAGS = $(all_libraries)
+libkghostviewlib_la_LIBADD = $(LIB_KFILE) $(LIB_KPARTS) -lkdeprint libdscparse.la
+
+libkghostviewpart_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+libkghostviewpart_la_LIBADD = libkghostviewlib.la
+
+# Check "make final" after making changes to the following line!!
+libkghostviewlib_la_SOURCES = kgvshell.cpp kgvdocument.cpp kgv_miniwidget.cpp \
+ marklist.cpp logwindow.cpp infodialog.cpp \
+ kgvpageview.cpp ps.c kgv_view.cpp scrollbox.cpp kgvpagedecorator.cpp \
+ kgvconfigdialog.cpp kgvmainwidget.cpp \
+ kdscerrordialog.cpp displayoptions.cpp kpswidget.cpp \
+ fullscreenfilter.cpp kgvfactory.cpp \
+ generalsettingswidget.ui gssettingswidget.ui thumbnailservice.cpp \
+ configuration.kcfgc
+
+libkghostviewpart_la_SOURCES = part_init.cpp
+
+kghostview_SOURCES = main.cpp
+kghostview_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+kghostview_LDADD = libkghostviewlib.la
+
+libdscparse_la_LDFLAGS = $(all_libraries) -no-undefined
+libdscparse_la_LIBADD = $(LIB_QT)
+libdscparse_la_SOURCES = dscparse.cpp dscparse_adapter.cpp
+
+noinst_HEADERS = marklist.h logwindow.h infodialog.h kgvshell.h \
+ kpswidget.h kgvpageview.h ps.h kgv_miniwidget.h kgv_view.h scrollbox.h \
+ kgvpagedecorator.h kgvconfigdialog.h kgvmainwidget.h dscparse.h \
+ dscparse_adapter.h kdscerrordialog.h kgvdocument.h displayoptions.h \
+ fullscreenfilter.h kgvfactory.h thumbnailservice.h
+
+METASOURCES = AUTO
+EXTRA_DIST = kghostview.desktop
+
+KDE_ICON = kghostview
+
+xdg_apps_DATA = kghostview.desktop
+kde_kcfg_DATA = kghostview.kcfg
+
+partdir = $(kde_datadir)/kghostview
+part_DATA = kgv_part.rc kghostviewui.rc
+
+partdesktopdir = $(kde_servicesdir)
+partdesktop_DATA = kghostview_part.desktop
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp *.h -o $(podir)/kghostview.pot
+
+
+updatedir = $(kde_datadir)/kconf_update
+update_DATA = kghostview.upd
+update_SCRIPTS = update-to-xt-names.pl
+
+# check_PROGRAMS = testdsc
+
+# testdsc_SOURCES = testdsc.cpp kdsc.cpp ps.c
+# testdsc_LDADD = -lqt
diff --git a/kghostview/README b/kghostview/README
new file mode 100644
index 00000000..eb92b02b
--- /dev/null
+++ b/kghostview/README
@@ -0,0 +1,27 @@
+KGHOSTVIEW for KDE 3.x
+
+This is Tim Theisen's Ghostview program ported to the K
+Desktop Environment. Ghostscript is used to view PostScript
+documents on Unix X11 systems.
+
+REQUIREMENTS
+
+1. GNU ghostscript
+2. KDE 3.x
+
+If ghostscript works for you then so should KGhostview. ghostscript can be obtained
+at http://www.cs.wisc.edu/~ghost/.
+
+Due to security reasons, kghostview works only with recent versions of ghostscript.
+Versions greater or equal to than GNU version 6.53 or GNU version 7.05 should work.
+
+Other versions or implementation of ghostscript may or may not work. In the
+configuration dialog, found under the Settings menu in the app, it
+is possible to configure the interpreter to use.
+
+Send bugs via http://bugs.kde.org
+
+CURRENT MAINTANER
+
+Luís-Pedro Coelho <luis_pedro@netcabo.pt>
+
diff --git a/kghostview/TODO b/kghostview/TODO
new file mode 100644
index 00000000..f747ff13
--- /dev/null
+++ b/kghostview/TODO
@@ -0,0 +1,41 @@
+- Port to KViewShell / KMultiPage
+
+- Progress bar(s) when loading/converting (the latter can be very slow).
+
+- Find dialog.
+
+- Different icons for Read Up and Read Down.
+
+- Use pdftops which comes with xpdf for pdf->ps conversion. It's output
+ is much better, and it allows the conversion of selected pages, which is
+ important when you want to print a small number of pages from a large
+ document.
+ I don't think I'll switch to pdftops. Ghostscript also has the possibility
+ to convert selected pages only. And for printing its output is fine.
+
+- Provide more information via statusbar messages. See gsview, for how it
+ should be.
+
+- Move the page navigation options from the View menu to the Go menu.
+ Currently Konqueror doesn't merge the Go menu, so that should be fixed first.
+
+- Fit page to view-width, auto-zoom on widget resize.
+
+- Better handling of Orientation and Paper Size choice.
+
+- Continuous and Continuous Facing viewing of pages, like Acroread.
+
+- Find a good solution which helps the user to keep his eyes focused when
+ scrolling (smooth scrolling or using helper lines like gv).
+
+- Fix all the bugs.
+
+
+Done:
+- Scrollbox should show a thumbnail (like kdvi).
+
+- New implementation for the marklist because QTableView won't be in Qt-3.0
+ anymore. (I'll keep using QTableView, simply because there's no suitable
+ alternative in Qt3.)
+
+- Switch to the DSC parser provided by Ghostscript.
diff --git a/kghostview/configuration.kcfgc b/kghostview/configuration.kcfgc
new file mode 100644
index 00000000..5617f368
--- /dev/null
+++ b/kghostview/configuration.kcfgc
@@ -0,0 +1,4 @@
+File=kghostview.kcfg
+ClassName=Configuration
+Mutators=true
+Singleton=true
diff --git a/kghostview/data/Makefile.am b/kghostview/data/Makefile.am
new file mode 100644
index 00000000..f6a27c16
--- /dev/null
+++ b/kghostview/data/Makefile.am
@@ -0,0 +1,3 @@
+ps_DATA = pdf_sec.ps
+psdir = ${kde_datadir}/kghostview
+
diff --git a/kghostview/data/pdf_sec.ps b/kghostview/data/pdf_sec.ps
new file mode 100644
index 00000000..5fe9598a
--- /dev/null
+++ b/kghostview/data/pdf_sec.ps
@@ -0,0 +1,386 @@
+% Copyright (C) 1996-1998 Geoffrey Keating.
+% This file may be freely distributed with or without modifications,
+% so long as modified versions are marked as such and copyright notices are
+% not removed.
+
+% pdf_sec.ps (version 1.0.4)
+% Implementation of security hooks for PDF reader.
+
+% This file contains the procedures that have to take encryption into
+% account when reading a PDF file. It replaces the stub version of this
+% file that is shipped with GhostScript. It requires GhostScript version 4.02
+% or later.
+
+% Documentation for using this file is available at
+% http://www.ozemail.com.au/%7Egeoffk/pdfencrypt/
+
+/.setlanguagelevel where { pop 2 .setlanguagelevel } if
+.currentglobal true .setglobal
+/pdfdict where { pop } { /pdfdict 100 dict def } ifelse
+pdfdict begin
+
+% Older ghostscript versions do not have .pdftoken, so we use 'token' instead.
+/.pdftoken where { pop } { /.pdftoken /token load def } ifelse
+
+% An implementation of an algorithm compatible with the RSA Data Security
+% Inc. RC4 stream encryption algorithm.
+
+% <string> rc4setkey <dict>
+/rc4setkey
+{
+ 6 dict begin
+ /k exch def
+ /a 256 string def
+ 0 1 255 { a exch dup put } for
+ /l k length def
+ /j 0 def
+ 0 1 255
+ {
+ /i exch def
+ /j a i get k i l mod get add j add 255 and def
+ a i a j get a j a i get put put
+ } for
+ 3 dict dup begin
+ /a a def
+ /x 0 def
+ /y 0 def
+ end
+ end
+} bind def
+
+% <rc4key> <string> rc4 <string> <rc4key>
+/rc4
+{
+ 1 index begin
+ dup dup length 1 sub 0 exch 1 exch
+ {
+ /x x 1 add 255 and def
+ /y a x get y add 255 and def
+ a x a y get a y a x get put put
+% stack: string string index
+ 2 copy get
+ a dup x get a y get add 255 and get
+ xor put dup
+ } for
+ pop
+ end
+} bind def
+
+% take a stream and rc4 decrypt it.
+% <stream> <key> rc4decodefilter <stream>
+/rc4decodefilter {
+ currentglobal exch true setglobal
+ dup length string copy rc4setkey
+ exch setglobal
+ exch 512 string
+ % stack: <key> <stream> <string>
+ { readstring pop rc4 exch pop } aload pop
+ 8 array astore cvx 0 () /SubFileDecode filter
+} bind def
+
+% MD5 derived from RFC 1321, "The MD5 Message-Digest Algorithm",
+% R. Rivest, MIT, RSADSI; implemented in PostScript by Geoffrey Keating.
+
+% We construct the MD5 transform by a sort of inline expansion.
+% this takes up quite a bit of memory (around 17k), but gives a
+% factor-of-two speed increase.
+% This also allows us to take advantage of interpreters with 64-bit
+% wide integers.
+% This will not run on interpreters with 16-bit wide integers, if such
+% things exist.
+20 dict begin
+
+/T [
+16#d76aa478 16#e8c7b756 16#242070db 16#c1bdceee
+16#f57c0faf 16#4787c62a 16#a8304613 16#fd469501
+16#698098d8 16#8b44f7af 16#ffff5bb1 16#895cd7be
+16#6b901122 16#fd987193 16#a679438e 16#49b40821
+16#f61e2562 16#c040b340 16#265e5a51 16#e9b6c7aa
+16#d62f105d 16#02441453 16#d8a1e681 16#e7d3fbc8
+16#21e1cde6 16#c33707d6 16#f4d50d87 16#455a14ed
+16#a9e3e905 16#fcefa3f8 16#676f02d9 16#8d2a4c8a
+16#fffa3942 16#8771f681 16#6d9d6122 16#fde5380c
+16#a4beea44 16#4bdecfa9 16#f6bb4b60 16#bebfbc70
+16#289b7ec6 16#eaa127fa 16#d4ef3085 16#04881d05
+16#d9d4d039 16#e6db99e5 16#1fa27cf8 16#c4ac5665
+16#f4292244 16#432aff97 16#ab9423a7 16#fc93a039
+16#655b59c3 16#8f0ccc92 16#ffeff47d 16#85845dd1
+16#6fa87e4f 16#fe2ce6e0 16#a3014314 16#4e0811a1
+16#f7537e82 16#bd3af235 16#2ad7d2bb 16#eb86d391
+] def
+/F [
+{ c d /xor b /and d /xor } { b c /xor d /and c /xor }
+{ b c /xor d /xor } { d /not b /or c /xor }
+] def
+/R [
+16#0007 16#010c 16#0211 16#0316 16#0407 16#050c 16#0611 16#0716
+16#0807 16#090c 16#0a11 16#0b16 16#0c07 16#0d0c 16#0e11 16#0f16
+16#0105 16#0609 16#0b0e 16#0014 16#0505 16#0a09 16#0f0e 16#0414
+16#0905 16#0e09 16#030e 16#0814 16#0d05 16#0209 16#070e 16#0c14
+16#0504 16#080b 16#0b10 16#0e17 16#0104 16#040b 16#0710 16#0a17
+16#0d04 16#000b 16#0310 16#0617 16#0904 16#0c0b 16#0f10 16#0217
+16#0006 16#070a 16#0e0f 16#0515 16#0c06 16#030a 16#0a0f 16#0115
+16#0806 16#0f0a 16#060f 16#0d15 16#0406 16#0b0a 16#020f 16#0915
+] def
+
+/W 1 31 bitshift 0 gt def
+/A W { /add } { /md5add } ifelse def
+/t W { 1744 } { 1616 } ifelse array def
+/C 0 def
+
+0 1 63 {
+ /i exch def
+ /r R i get def
+ /a/b/c/d 4 i 3 and roll [ /d/c/b/a ] { exch def } forall
+
+ t C [
+ a F i -4 bitshift get exec
+ a A /x r -8 bitshift /get A T i get A
+ W { 1 32 bitshift 1 sub /and } if
+ /dup r 31 and /bitshift /exch r 31 and 32 sub /bitshift /or
+ b A
+ /def
+ ] dup length C add /C exch def putinterval
+} for
+
+1 1 C 1 sub {
+ dup 1 sub t exch get /def cvx eq
+ {pop}
+ {t exch 2 copy get cvx put}
+ ifelse
+} for
+
+% If we could put t into a _packed_ array, its memory requirements
+% would go from about 13k to about 4k. Unfortunately, we'd need around
+% 1600 stack positions, around 3 times what we can expect to have
+% available---and if that kind of memory is available, we don't really
+% need to pack t. Sigh.
+
+% In fact, it's worse than that. You can't even determine what t will
+% be and write it in directly (something like
+% { /a c d xor b and d xor a md5add x 0 get md5add -680876936 md5add dup 7
+% bitshift exch -25 bitshift or b md5add def /d b c xor a ...
+% ) because the scanner uses the operand stack to accumulate procedures.
+% So the only way to have md5transform as a single procedure is the above
+% trick.
+
+W /md5transform t end cvx bind def
+
+% Unfortunately, PostScript & its imitators convert large
+% integers to floating-point. Worse, the fp representation probably
+% won't have 32 significant bits.
+% This procedure accounts for about 35% of the total time on 32-bit
+% machines.
+not {
+ /md5add {
+ 2 copy xor 0 lt
+ % if one is positive and one is negative, can't overflow
+ { add }
+ % if both are positive or negative
+ { 16#80000000 xor add 16#80000000 xor }
+ % same as subtracting (or adding) 2^31 and then subtracting (or
+ % adding) it back.
+ ifelse
+ } bind def
+} {
+ /md5add {
+ add 16#0FFFFFFFF and
+ } bind def
+} ifelse
+
+/md5 {
+ 20 dict begin
+
+ % initialise a,b,c,d,x
+ /a 16#67452301 def
+ /b 16#efcdab89 def
+ /c 16#98badcfe def
+ /d 16#10325476 def
+ /x 16 array def
+
+ % parameters
+ /origs exch def
+ /oslen origs length def
+
+ % pad string to multiple of 512 bits
+ /s oslen 72 add 64 idiv 64 mul dup /slen exch def string def
+ s 0 origs putinterval
+ s oslen 16#80 put
+ s slen 8 sub oslen 31 and 3 bitshift put
+ s slen 7 sub oslen -5 bitshift 255 and put
+ s slen 6 sub oslen -13 bitshift 255 and put
+
+ 0 64 slen 64 sub {
+ dup 1 exch 63 add { s exch get } for
+ 15 -1 0 { x exch 6 2 roll 3 { 8 bitshift or } repeat put } for
+ a b c d
+ md5transform
+ d md5add /d exch def
+ c md5add /c exch def
+ b md5add /b exch def
+ a md5add /a exch def
+ } for
+
+ 16 string
+ [ [ a b c d ] { 3 { dup -8 bitshift } repeat } forall ]
+ 0 1 15 {
+ 3 copy dup 3 1 roll get 255 and put pop
+ } for
+ pop
+
+ end
+} bind def
+
+% Pad a key out to 32 bytes.
+/pdf_pad_key % <key> pdf_pad_key <padded key>
+ { dup length 32 gt { 0 32 getinterval } if
+ <28bf4e5e4e758a41 64004e56fffa0108
+ 2e2e00b6d0683e80 2f0ca9fe6453697a>
+ 0 32 3 index length sub getinterval
+ concatstrings
+ } bind def
+
+% Try a user key for a PDF file.
+/pdf_try_key % <key> pdf_try_key <filekey> true
+ % <key> pdf_try_key false
+ { Trailer /Encrypt oget
+ dup /O oget exch
+ /P oget 4 string exch
+ 2 copy 255 and 0 exch put
+ 2 copy -8 bitshift 255 and 1 exch put
+ 2 copy -16 bitshift 255 and 2 exch put
+ 2 copy -24 bitshift 255 and 3 exch put pop
+ Trailer /ID oget 0 oget
+ 3 { concatstrings } repeat
+ md5 0 5 getinterval
+ dup
+ Trailer /Encrypt oget /U oget dup length string copy exch
+ rc4setkey exch rc4 exch pop
+ <28bf4e5e4e758a41 64004e56fffa0108
+ 2e2e00b6d0683e80 2f0ca9fe6453697a> eq
+ dup not { exch pop } if
+ } bind def
+
+% Process the encryption information in the Trailer.
+/pdf_process_Encrypt
+ { Trailer /Encrypt oget
+ /Filter oget /Standard eq not
+ { (****This file uses an unknown security handler.\n) print flush
+ /pdf_process_Encrypt cvx /undefined signalerror
+ }
+ if
+ () pdf_pad_key pdf_try_key
+ { /FileKey exch def }
+ { /PDFPassword where
+ { pop PDFPassword pdf_pad_key pdf_try_key
+ { true }
+ { PDFPassword pdf_pad_key md5 0 5 getinterval rc4setkey
+ Trailer /Encrypt oget /O oget dup length string copy
+ rc4 exch pop
+ pdf_try_key
+ }
+ ifelse
+ { /FileKey exch def }
+ { (****Password did not work.\n) print flush
+ /pdf_process_Encrypt cvx /invalidfileaccess signalerror
+ }
+ ifelse
+ }
+ { (****This file has a user password set.\n) print flush
+ /pdf_process_Encrypt cvx /invalidfileaccess signalerror
+ }
+ ifelse
+ }
+ ifelse
+ Trailer /Encrypt oget /P oget 4 and 0 eq #? and
+ { (****This owner of this file has requested you do not print it.\n)
+ print flush
+ /pdf_process_Encrypt cvx /invalidfileaccess signalerror
+ }
+ if
+ } bind def
+
+% Calculate the key used to decrypt an object (to pass to .decpdfrun or
+% put into a stream dictionary).
+/computeobjkey % <object#> <generation#> computeobjkey <keystring>
+{
+ exch
+ 10 string
+ dup 0 FileKey putinterval
+ exch
+ % stack: gen# string obj#
+ 2 copy 255 and 5 exch put
+ 2 copy -8 bitshift 255 and 6 exch put
+ 2 copy -16 bitshift 255 and 7 exch put
+ pop exch
+ 2 copy 255 and 8 exch put
+ 2 copy -8 bitshift 255 and 9 exch put
+ pop md5 0 10 getinterval
+} bind def
+
+% As .pdfrun, but decrypt strings with key <key>.
+/.decpdfrun % <file> <keystring> <opdict> .decpdfrun -
+ { % Construct a procedure with the file, opdict and key bound into it.
+ 2 index cvlit mark mark 5 2 roll
+ { .pdftoken not { (%%EOF) cvn cvx } if
+ dup xcheck
+ { DEBUG { dup == flush } if
+ 3 -1 roll pop
+ 2 copy .knownget
+ { exch pop exch pop exec }
+ { (%stderr) (w) file
+ dup (****************Unknown operator: ) writestring
+ dup 3 -1 roll .writecvs dup (\n) writestring flushfile
+ pop
+ }
+ ifelse
+ }
+ { exch pop DEBUG { dup ==only ( ) print flush } if
+ dup type /stringtype eq
+ { exch rc4setkey exch rc4 }
+ if
+ exch pop
+ }
+ ifelse
+ }
+ aload pop .packtomark cvx
+ /loop cvx 2 packedarray cvx
+ { stopped /PDFsource } aload pop
+ PDFsource
+ { store { stop } if } aload pop .packtomark cvx
+ /PDFsource 3 -1 roll store exec
+ } bind def
+
+% Run the code to resolve an object reference.
+/pdf_run_resolve
+ { /FileKey where
+ { pop
+ 2 copy computeobjkey dup 4 1 roll
+ PDFfile exch resolveopdict .decpdfrun
+ dup dup dup 5 2 roll
+ % stack: object object key object object
+ xcheck exch type /dicttype eq and
+ { /StreamKey exch put }
+ { pop pop }
+ ifelse
+ }
+ { PDFfile resolveopdict .pdfrun }
+ ifelse
+ } bind def
+
+% Prefix a decryption filter to a stream if needed.
+% Stack: readdata? dict parms file/string filternames
+% (both before and after).
+/pdf_decrypt_stream
+ { 3 index /StreamKey known
+ {
+ exch
+ % Stack: readdata? dict parms filternames file/string
+ 3 index /Length oget () /SubFileDecode filter
+ 3 index /StreamKey get rc4decodefilter
+ exch
+ } if
+ } bind def
+
+end % pdfdict
+.setglobal
diff --git a/kghostview/displayoptions.cpp b/kghostview/displayoptions.cpp
new file mode 100644
index 00000000..48d45e7e
--- /dev/null
+++ b/kghostview/displayoptions.cpp
@@ -0,0 +1,150 @@
+/**
+ * Copyright (C) 2003, Lus Pedro Coelho
+ *
+ * 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 "displayoptions.h"
+#include <kdebug.h>
+#include <qregexp.h>
+#include <kcmdlineargs.h>
+#include <kconfig.h>
+
+namespace {
+ const double allowedMagnifications[] = {
+ 0.125,
+ 0.25,
+ 0.3333,
+ 0.5,
+ 0.6667,
+ 0.75,
+ 1,
+ 1.25,
+ 1.50,
+ 2,
+ 3,
+ 4,
+ 6,
+ 8
+ };
+ const size_t numberOfMagnifications = ( sizeof( allowedMagnifications ) / sizeof( allowedMagnifications[ 0 ] ) );
+}
+
+DisplayOptions DisplayOptions::parse( KCmdLineArgs* args )
+{
+ DisplayOptions res;
+#define CHECK_ORIENTATION( tag, value ) \
+ if ( args->isSet( tag ) ) res._overrideOrientation = value; \
+ if ( args->getOption( "orientation" ) == tag ) res._overrideOrientation = value;
+
+ CHECK_ORIENTATION( "landscape", CDSC_LANDSCAPE );
+ CHECK_ORIENTATION( "seascape", CDSC_SEASCAPE );
+ CHECK_ORIENTATION( "portrait", CDSC_PORTRAIT);
+ CHECK_ORIENTATION( "upsidedown", CDSC_UPSIDEDOWN);
+
+ res.setMagnification( args->getOption( "scale" ).toFloat() );
+ res.setPage( args->getOption( "page" ).toInt() - 1 ); // transform from 1-based into 0-based
+ //res._overridePageMedia = args->getOption( "paper" );
+ kdDebug(4500 ) << "Parsed options: " << DisplayOptions::toString( res ) << endl;
+ return res;
+}
+
+namespace {
+ const char* const rformat = ".page: (\\d+); .magnification: ([\\d\\.]+); .orientation = (\\d+); .media = ([^;]*);";
+ const char* const qformat = ".page: %1; .magnification: %2; .orientation = %3; .media = %4;";
+}
+
+QString DisplayOptions::toString( const DisplayOptions& options )
+{
+ return QString( qformat )
+ .arg( options.page() )
+ .arg( options.magnification() )
+ .arg( options.overrideOrientation() )
+ .arg( options.overridePageMedia().utf8() );
+}
+
+bool DisplayOptions::fromString( DisplayOptions& out, const QString& in )
+{
+ QRegExp regex( QString::fromLatin1( rformat ) );
+ if ( regex.search( in ) < 0 ) return false;
+
+ out.reset();
+ out.setPage( regex.cap( 1 ).toInt() );
+ out.setMagnification( regex.cap( 2 ).toDouble() );
+ out.setOverrideOrientation( static_cast<CDSC_ORIENTATION_ENUM>( regex.cap( 3 ).toInt() ) );
+ if ( !regex.cap( 4 ).isEmpty() ) out.setOverridePageMedia( regex.cap( 4 ) );
+ return true;
+}
+
+
+bool DisplayOptions::canZoomIn() const
+{
+ return unsigned( closestIndex() ) < ( numberOfMagnifications - 1 );
+}
+
+bool DisplayOptions::zoomIn()
+{
+ if ( !canZoomIn() ) return false;
+ _magnification = allowedMagnifications[ closestIndex() + 1 ];
+ return true;
+}
+
+bool DisplayOptions::canZoomOut() const
+{
+ return closestIndex() > 0;
+}
+
+bool DisplayOptions::zoomOut()
+{
+ if ( !canZoomOut() ) return false;
+ _magnification = allowedMagnifications[ closestIndex() - 1 ];
+ return true;
+}
+
+double DisplayOptions::magnification() const
+{
+ return _magnification;
+}
+
+
+void DisplayOptions::setMagnification( double newZoom ) {
+ _magnification = newZoom;
+}
+
+unsigned DisplayOptions::closestIndex() const {
+ kdDebug(4500) << "DisplayOptions::closestIndex(" << _magnification << ")" << endl;
+ unsigned res = 0;
+ while ( res < numberOfMagnifications
+ && allowedMagnifications[ res ] < _magnification ) ++res;
+ if ( res >= ( numberOfMagnifications - 1 ) ) return numberOfMagnifications - 1;
+ if ( res == 0 ) return 0;
+
+ if ( ( allowedMagnifications[ res ] - _magnification ) > ( _magnification - allowedMagnifications[ res - 1 ] ) ) {
+ --res;
+ }
+ kdDebug(4500) << "DisplayOptions::closestIndex(" << res << "): nearest allowed magnification: "
+ << allowedMagnifications[ res ] << endl;
+ return res;
+}
+
+QValueList<double> DisplayOptions::normalMagnificationValues() {
+ QValueList<double> res;
+ for ( const double *first = allowedMagnifications, *last = allowedMagnifications + numberOfMagnifications;
+ first != last;
+ ++first ) {
+ res << *first;
+ }
+ return res;
+}
+
diff --git a/kghostview/displayoptions.h b/kghostview/displayoptions.h
new file mode 100644
index 00000000..e929d8b7
--- /dev/null
+++ b/kghostview/displayoptions.h
@@ -0,0 +1,112 @@
+/**
+ * Copyright (C) 2003, Lus Pedro Coelho
+ *
+ * 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 DISPLAYOPTIONS_H
+#define DISPLAYOPTIONS_H
+#include <qstring.h>
+#include <qvaluelist.h>
+#include "dscparse_adapter.h"
+#include <kdemacros.h>
+class KCmdLineArgs;
+class KConfig;
+
+class KDE_EXPORT DisplayOptions
+{
+ public:
+ DisplayOptions();
+
+ // default generated DisplayOptions(const DisplayOptions&);
+ // default generated ~DisplayOptions();
+ // default generated DisplayOptions& operator = (const DisplayOptions&);
+
+ void reset() { *this = DisplayOptions(); }
+
+ void restoreOverrideOrientation() { setOverrideOrientation( CDSC_ORIENT_UNKNOWN ); }
+ void setOverrideOrientation(CDSC_ORIENTATION_ENUM e) { _overrideOrientation = e; }
+ CDSC_ORIENTATION_ENUM overrideOrientation() const { return _overrideOrientation; }
+
+ void restoreOverridePageMedia() { _overridePageMedia = QString::null; }
+ void setOverridePageMedia(const QString& newMedia) { _overridePageMedia = newMedia; }
+ const QString& overridePageMedia() const { return _overridePageMedia; }
+
+ /**
+ * The current page.
+ * Note that the pages here are 0-based, although the user should see 1-based pages.
+ *
+ * In parsing cmdline-args, we transform --page=1 into setPage( 0 );
+ */
+ int page() const { return _page; }
+ void setPage( int newPage ) { _page = newPage; }
+
+ double magnification() const;
+ void setMagnification( double );
+ /**
+ * Goes to the next degree of magnification if possible. If we cannot zoom in any more, it returns false,
+ * leaving the magnification untouched.
+ */
+ bool zoomIn();
+ bool zoomOut();
+
+ bool canZoomIn() const;
+ bool canZoomOut() const;
+
+ /**
+ * Parses command line options.
+ */
+ static DisplayOptions parse ( KCmdLineArgs * );
+ /**
+ * Transforms the object in a string representation.
+ * Useful for storing in config files, for example.
+ *
+ * \return string representation or null on error.
+ *
+ * \sa fromString
+ */
+ static QString toString( const DisplayOptions& );
+ /**
+ * Reads the display options from a string formatted by toString.
+ *
+ * \return true if the convertion succeeded.
+ */
+ static bool fromString( DisplayOptions&, const QString& );
+
+ /**
+ * Returns a list of values that normally we can get through
+ * zoomIn() & zoomOut()
+ */
+ static QValueList<double> normalMagnificationValues();
+
+ private:
+
+ unsigned closestIndex() const;
+
+ CDSC_ORIENTATION_ENUM _overrideOrientation;
+ QString _overridePageMedia;
+ int _page;
+ double _magnification;
+};
+
+inline
+DisplayOptions::DisplayOptions()
+ :_overrideOrientation( CDSC_ORIENT_UNKNOWN ),
+ _overridePageMedia ( QString::null ),
+ _page( 0 )
+{
+ setMagnification( 1.0 );
+}
+
+#endif // DISPLAYOPTIONS_H
diff --git a/kghostview/dscparse.cpp b/kghostview/dscparse.cpp
new file mode 100644
index 00000000..b5d2c3a7
--- /dev/null
+++ b/kghostview/dscparse.cpp
@@ -0,0 +1,3432 @@
+/* Copyright (C) 2000-2001, Ghostgum Software Pty Ltd. All rights reserved.
+
+ This file is part of GSview.
+
+ This file is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public Licence for full details.
+
+ Everyone is granted permission to copy, modify and redistribute this
+ file, but only under the conditions described in the GNU General
+ Public Licence. A copy of this license is supposed to have been given
+ to you along with this file so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+*/
+
+/* $Id$ */
+
+/* dscparse.c - DSC parser */
+
+/*
+ * This is a DSC parser, based on the DSC 3.0 spec,
+ * with a few DSC 2.1 additions for page size.
+ *
+ * Current limitations:
+ * %%+ may be used after any comment in the comment or trailer,
+ * but is currently only supported by
+ * %%DocumentMedia
+ *
+ * DSC 2.1 additions (discontinued in DSC 3.0):
+ * %%DocumentPaperColors:
+ * %%DocumentPaperForms:
+ * %%DocumentPaperSizes:
+ * %%DocumentPaperWeights:
+ * %%PaperColor: (ignored)
+ * %%PaperForm: (ignored)
+ * %%PaperSize:
+ * %%PaperWeight: (ignored)
+ *
+ * Other additions for defaults or page section
+ % %%ViewingOrientation: xx xy yx yy
+*/
+
+#include <stdio.h> /* for sprintf(), not file I/O */
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#define MAXSTR 256
+
+#include "dscparse.h"
+
+/* Macros for comparing string literals
+ * For maximum speed, the length of the second macro argument is
+ * computed at compile time.
+ * THE SECOND MACRO ARGUMENT MUST BE A STRING LITERAL.
+ */
+#define COMPARE(p,str) (strncmp((const char *)(p), (str), sizeof(str)-1)==0)
+#define IS_DSC(line, str) (COMPARE((line), (str)))
+
+/* Macros for comparing the first one or two characters */
+#define IS_WHITE(ch) (((ch)==' ') || ((ch)=='\t'))
+#define IS_EOL(ch) (((ch)=='\r') || ((ch)=='\n'))
+#define IS_WHITE_OR_EOL(ch) (IS_WHITE(ch) || IS_EOL(ch))
+#define IS_BLANK(str) (IS_EOL(str[0]))
+#define NOT_DSC_LINE(str) (((str)[0]!='%') || ((str)[1]!='%'))
+
+/* Macros for document offset to start and end of line */
+#define DSC_START(dsc) ((dsc)->data_offset + (dsc)->data_index - (dsc)->line_length)
+#define DSC_END(dsc) ((dsc)->data_offset + (dsc)->data_index)
+
+/* dsc_scan_SECTION() functions return one of
+ * CDSC_ERROR, CDSC_OK, CDSC_NOTDSC
+ * or one of the following
+ */
+/* The line should be passed on to the next section parser. */
+#define CDSC_PROPAGATE 10
+
+/* If document is DOS EPS and we haven't read 30 bytes, ask for more. */
+#define CDSC_NEEDMORE 11
+
+template<class T>
+inline T min (T a, T b) { return a < b ? a : b; }
+
+/* local prototypes */
+dsc_private void * dsc_memalloc(P2(CDSC *dsc, size_t size));
+dsc_private void dsc_memfree(P2(CDSC*dsc, void *ptr));
+dsc_private CDSC * dsc_init2(P1(CDSC *dsc));
+dsc_private void dsc_reset(P1(CDSC *dsc));
+dsc_private void dsc_section_join(P3(unsigned long begin, unsigned long *pend, unsigned long **pplast));
+dsc_private int dsc_read_line(P1(CDSC *dsc));
+dsc_private int dsc_read_doseps(P1(CDSC *dsc));
+dsc_private char * dsc_alloc_string(P3(CDSC *dsc, const char *str, int len));
+dsc_private char * dsc_add_line(P3(CDSC *dsc, const char *line, unsigned int len));
+dsc_private char * dsc_copy_string(P5(char *str, unsigned int slen,
+ char *line, unsigned int len, unsigned int *offset));
+dsc_private GSDWORD dsc_get_dword(P1(const unsigned char *buf));
+dsc_private GSWORD dsc_get_word(P1(const unsigned char *buf));
+dsc_private int dsc_get_int(P3(const char *line, unsigned int len, unsigned int *offset));
+dsc_private float dsc_get_real(P3(const char *line, unsigned int len,
+ unsigned int *offset));
+dsc_private int dsc_stricmp(P2(const char *s, const char *t));
+dsc_private void dsc_unknown(P1(CDSC *dsc));
+dsc_private GSBOOL dsc_is_section(char *line);
+dsc_private int dsc_parse_pages(P1(CDSC *dsc));
+dsc_private int dsc_parse_bounding_box(P3(CDSC *dsc, CDSCBBOX** pbbox, int offset));
+dsc_private int dsc_parse_float_bounding_box(P3(CDSC *dsc, CDSCFBBOX** pfbbox, int offset));
+dsc_private int dsc_parse_orientation(P3(CDSC *dsc, unsigned int *porientation,
+ int offset));
+dsc_private int dsc_parse_order(P1(CDSC *dsc));
+dsc_private int dsc_parse_media(P2(CDSC *dsc, const CDSCMEDIA **page_media));
+dsc_private int dsc_parse_document_media(P1(CDSC *dsc));
+dsc_private int dsc_parse_viewing_orientation(P2(CDSC *dsc, CDSCCTM **pctm));
+dsc_private int dsc_parse_page(P1(CDSC *dsc));
+dsc_private void dsc_save_line(P1(CDSC *dsc));
+dsc_private int dsc_scan_type(P1(CDSC *dsc));
+dsc_private int dsc_scan_comments(P1(CDSC *dsc));
+dsc_private int dsc_scan_preview(P1(CDSC *dsc));
+dsc_private int dsc_scan_defaults(P1(CDSC *dsc));
+dsc_private int dsc_scan_prolog(P1(CDSC *dsc));
+dsc_private int dsc_scan_setup(P1(CDSC *dsc));
+dsc_private int dsc_scan_page(P1(CDSC *dsc));
+dsc_private int dsc_scan_trailer(P1(CDSC *dsc));
+dsc_private int dsc_error(P4(CDSC *dsc, unsigned int explanation,
+ char *line, unsigned int line_len));
+
+/* DSC error reporting */
+dsc_private const int dsc_severity[] = {
+ CDSC_ERROR_WARN, /* CDSC_MESSAGE_BBOX */
+ CDSC_ERROR_WARN, /* CDSC_MESSAGE_EARLY_TRAILER */
+ CDSC_ERROR_WARN, /* CDSC_MESSAGE_EARLY_EOF */
+ CDSC_ERROR_ERROR, /* CDSC_MESSAGE_PAGE_IN_TRAILER */
+ CDSC_ERROR_ERROR, /* CDSC_MESSAGE_PAGE_ORDINAL */
+ CDSC_ERROR_ERROR, /* CDSC_MESSAGE_PAGES_WRONG */
+ CDSC_ERROR_ERROR, /* CDSC_MESSAGE_EPS_NO_BBOX */
+ CDSC_ERROR_ERROR, /* CDSC_MESSAGE_EPS_PAGES */
+ CDSC_ERROR_WARN, /* CDSC_MESSAGE_NO_MEDIA */
+ CDSC_ERROR_WARN, /* CDSC_MESSAGE_ATEND */
+ CDSC_ERROR_INFORM, /* CDSC_MESSAGE_DUP_COMMENT */
+ CDSC_ERROR_INFORM, /* CDSC_MESSAGE_DUP_TRAILER */
+ CDSC_ERROR_WARN, /* CDSC_MESSAGE_BEGIN_END */
+ CDSC_ERROR_INFORM, /* CDSC_MESSAGE_BAD_SECTION */
+ CDSC_ERROR_INFORM, /* CDSC_MESSAGE_LONG_LINE */
+ CDSC_ERROR_WARN, /* CDSC_MESSAGE_INCORRECT_USAGE */
+ 0
+};
+
+#define DSC_MAX_ERROR ((sizeof(dsc_severity) / sizeof(int))-2)
+
+const CDSCMEDIA dsc_known_media[CDSC_KNOWN_MEDIA] = {
+ /* These sizes taken from Ghostscript gs_statd.ps */
+ {"11x17", 792, 1224, 0, NULL, NULL, NULL},
+ {"A0", 2380, 3368, 0, NULL, NULL, NULL},
+ {"A1", 1684, 2380, 0, NULL, NULL, NULL},
+ {"A2", 1190, 1684, 0, NULL, NULL, NULL},
+ {"A3", 842, 1190, 0, NULL, NULL, NULL},
+ {"A4", 595, 842, 0, NULL, NULL, NULL},
+ {"A5", 421, 595, 0, NULL, NULL, NULL},
+ {"A6", 297, 421, 0, NULL, NULL, NULL},
+ {"A7", 210, 297, 0, NULL, NULL, NULL},
+ {"A8", 148, 210, 0, NULL, NULL, NULL},
+ {"A9", 105, 148, 0, NULL, NULL, NULL},
+ {"A10", 74, 105, 0, NULL, NULL, NULL},
+ {"B0", 2836, 4008, 0, NULL, NULL, NULL},
+ {"B1", 2004, 2836, 0, NULL, NULL, NULL},
+ {"B2", 1418, 2004, 0, NULL, NULL, NULL},
+ {"B3", 1002, 1418, 0, NULL, NULL, NULL},
+ {"B4", 709, 1002, 0, NULL, NULL, NULL}, /* ISO, but not Adobe standard */
+ {"B5", 501, 709, 0, NULL, NULL, NULL}, /* ISO, but not Adobe standard */
+ {"B6", 354, 501, 0, NULL, NULL, NULL},
+ {"C0", 2600, 3677, 0, NULL, NULL, NULL},
+ {"C1", 1837, 2600, 0, NULL, NULL, NULL},
+ {"C2", 1298, 1837, 0, NULL, NULL, NULL},
+ {"C3", 918, 1298, 0, NULL, NULL, NULL},
+ {"C4", 649, 918, 0, NULL, NULL, NULL},
+ {"C5", 459, 649, 0, NULL, NULL, NULL},
+ {"C6", 323, 459, 0, NULL, NULL, NULL},
+ {"Ledger", 1224, 792, 0, NULL, NULL, NULL},
+ {"Legal", 612, 1008, 0, NULL, NULL, NULL},
+ {"Letter", 612, 792, 0, NULL, NULL, NULL},
+ {"Note", 612, 792, 0, NULL, NULL, NULL},
+// ISO and JIS B sizes are different....
+ {"jisb0", 2916, 4128, 0, NULL, NULL, NULL},
+ {"jisb1", 2064, 2916, 0, NULL, NULL, NULL},
+ {"jisb2", 1458, 2064, 0, NULL, NULL, NULL},
+ {"jisb3", 1032, 1458, 0, NULL, NULL, NULL},
+ {"jisb4", 729, 1032, 0, NULL, NULL, NULL},
+ {"jisb5", 516, 729, 0, NULL, NULL, NULL},
+ {"jisb6", 363, 516, 0, NULL, NULL, NULL},
+// U.S. CAD standard paper sizes
+ {"archE", 2592, 3456, 0, NULL, NULL, NULL},
+ {"archD", 1728, 2592, 0, NULL, NULL, NULL},
+ {"archC", 1296, 1728, 0, NULL, NULL, NULL},
+ {"archB", 864, 1296, 0, NULL, NULL, NULL},
+ {"archA", 648, 864, 0, NULL, NULL, NULL},
+// Other paper sizes
+ {"flsa", 612, 936, 0, NULL, NULL, NULL}, /* U.S. foolscap */
+ {"flse", 612, 936, 0, NULL, NULL, NULL}, /* European foolscap */
+ {"halfletter", 396, 612, 0, NULL, NULL, NULL},
+ {NULL, 0, 0, 0, NULL, NULL, NULL}
+};
+
+/* parser state */
+enum CDSC_SCAN_SECTION {
+ scan_none = 0,
+ scan_comments = 1,
+ scan_pre_preview = 2,
+ scan_preview = 3,
+ scan_pre_defaults = 4,
+ scan_defaults = 5,
+ scan_pre_prolog = 6,
+ scan_prolog = 7,
+ scan_pre_setup = 8,
+ scan_setup = 9,
+ scan_pre_pages = 10,
+ scan_pages = 11,
+ scan_pre_trailer = 12,
+ scan_trailer = 13,
+ scan_eof = 14
+};
+
+static const char * const dsc_scan_section_name[15] = {
+ "Type", "Comments",
+ "pre-Preview", "Preview",
+ "pre-Defaults", "Defaults",
+ "pre-Prolog", "Prolog",
+ "pre-Setup", "Setup",
+ "pre-Page", "Page",
+ "pre-Trailer", "Trailer",
+ "EOF"
+};
+
+/******************************************************************/
+/* Public functions */
+/******************************************************************/
+
+/* constructor */
+CDSC *
+dsc_init(void *caller_data)
+{
+ CDSC *dsc = (CDSC *)malloc(sizeof(CDSC));
+ if (dsc == NULL)
+ return NULL;
+ memset(dsc, 0, sizeof(CDSC));
+ dsc->caller_data = caller_data;
+
+ return dsc_init2(dsc);
+}
+
+/* constructor, with caller supplied memalloc */
+CDSC *
+dsc_init_with_alloc(
+ void *caller_data,
+ void *(*memalloc)(size_t size, void *closure_data),
+ void (*memfree)(void *ptr, void *closure_data),
+ void *closure_data)
+{
+ CDSC *dsc = (CDSC *)memalloc(sizeof(CDSC), closure_data);
+ if (dsc == NULL)
+ return NULL;
+ memset(dsc, 0, sizeof(CDSC));
+ dsc->caller_data = caller_data;
+
+ dsc->memalloc = memalloc;
+ dsc->memfree = memfree;
+ dsc->mem_closure_data = closure_data;
+
+ return dsc_init2(dsc);
+}
+
+
+
+/* destructor */
+void
+dsc_free(CDSC *dsc)
+{
+ if (dsc == NULL)
+ return;
+ dsc_reset(dsc);
+ dsc_memfree(dsc, dsc);
+}
+
+
+/* Tell DSC parser how long document will be, to allow ignoring
+ * of early %%Trailer and %%EOF. This is optional.
+ */
+void
+dsc_set_length(CDSC *dsc, unsigned long len)
+{
+ dsc->file_length = len;
+}
+
+/* Process a buffer containing DSC comments and PostScript */
+/* Return value is < 0 for error, >=0 for OK.
+ * CDSC_ERROR
+ * CDSC_OK
+ * CDSC_NOTDSC (DSC will be ignored)
+ * other values indicate the last DSC comment read
+ */
+int
+dsc_scan_data(CDSC *dsc, const char *data, int length)
+{
+ int bytes_read;
+ int code = 0;
+
+ if (dsc == NULL)
+ return CDSC_ERROR;
+
+ if (dsc->id == CDSC_NOTDSC)
+ return CDSC_NOTDSC;
+ dsc->id = CDSC_OK;
+ if (dsc->eof)
+ return CDSC_OK; /* ignore */
+
+ if (length == 0) {
+ /* EOF, so process what remains */
+ dsc->eof = TRUE;
+ }
+
+ do {
+ if (dsc->id == CDSC_NOTDSC)
+ break;
+
+ if (length != 0) {
+ /* move existing data if needed */
+ if (dsc->data_length > CDSC_DATA_LENGTH/2) {
+ memmove(dsc->data, dsc->data + dsc->data_index,
+ dsc->data_length - dsc->data_index);
+ dsc->data_offset += dsc->data_index;
+ dsc->data_length -= dsc->data_index;
+ dsc->data_index = 0;
+ }
+ /* append to buffer */
+ bytes_read = min(length, (int)(CDSC_DATA_LENGTH - dsc->data_length));
+ memcpy(dsc->data + dsc->data_length, data, bytes_read);
+ dsc->data_length += bytes_read;
+ data += bytes_read;
+ length -= bytes_read;
+ }
+ if (dsc->scan_section == scan_none) {
+ code = dsc_scan_type(dsc);
+ if (code == CDSC_NEEDMORE) {
+ /* need more characters before we can identify type */
+ code = CDSC_OK;
+ break;
+ }
+ dsc->id = code;
+ }
+
+ if (code == CDSC_NOTDSC) {
+ dsc->id = CDSC_NOTDSC;
+ break;
+ }
+
+ while ((code = dsc_read_line(dsc)) > 0) {
+ if (dsc->id == CDSC_NOTDSC)
+ break;
+ if (dsc->doseps_end &&
+ (dsc->data_offset + dsc->data_index > dsc->doseps_end)) {
+ /* have read past end of DOS EPS PostScript section */
+ return CDSC_OK; /* ignore */
+ }
+ if (dsc->eof)
+ return CDSC_OK;
+ if (dsc->skip_document)
+ continue; /* embedded document */
+ if (dsc->skip_lines)
+ continue; /* embedded lines */
+ if (IS_DSC(dsc->line, "%%BeginData:"))
+ continue;
+ if (IS_DSC(dsc->line, "%%BeginBinary:"))
+ continue;
+ if (IS_DSC(dsc->line, "%%EndDocument"))
+ continue;
+ if (IS_DSC(dsc->line, "%%EndData"))
+ continue;
+ if (IS_DSC(dsc->line, "%%EndBinary"))
+ continue;
+
+ do {
+ switch (dsc->scan_section) {
+ case scan_comments:
+ code = dsc_scan_comments(dsc);
+ break;
+ case scan_pre_preview:
+ case scan_preview:
+ code = dsc_scan_preview(dsc);
+ break;
+ case scan_pre_defaults:
+ case scan_defaults:
+ code = dsc_scan_defaults(dsc);
+ break;
+ case scan_pre_prolog:
+ case scan_prolog:
+ code = dsc_scan_prolog(dsc);
+ break;
+ case scan_pre_setup:
+ case scan_setup:
+ code = dsc_scan_setup(dsc);
+ break;
+ case scan_pre_pages:
+ case scan_pages:
+ code = dsc_scan_page(dsc);
+ break;
+ case scan_pre_trailer:
+ case scan_trailer:
+ code = dsc_scan_trailer(dsc);
+ break;
+ case scan_eof:
+ code = CDSC_OK;
+ break;
+ default:
+ /* invalid state */
+ code = CDSC_ERROR;
+ }
+ /* repeat if line is start of next section */
+ } while (code == CDSC_PROPAGATE);
+
+ /* if DOS EPS header not complete, ask for more */
+ if (code == CDSC_NEEDMORE) {
+ code = CDSC_OK;
+ break;
+ }
+ if (code == CDSC_NOTDSC) {
+ dsc->id = CDSC_NOTDSC;
+ break;
+ }
+ }
+ } while (length != 0);
+
+ return (code < 0) ? code : dsc->id;
+}
+
+/* Tidy up from incorrect DSC comments */
+int
+dsc_fixup(CDSC *dsc)
+{
+ unsigned int i;
+ char buf[32];
+ unsigned long *last;
+
+ if (dsc->id == CDSC_NOTDSC)
+ return 0;
+
+ /* flush last partial line */
+ dsc_scan_data(dsc, NULL, 0);
+
+ /* Fix DSC error: code between %%EndSetup and %%Page */
+ if (dsc->page_count && (dsc->page[0].begin != dsc->endsetup)
+ && (dsc->endsetup != dsc->beginsetup)) {
+ dsc->endsetup = dsc->page[0].begin;
+ dsc_debug_print(dsc, "Warning: code included between setup and first page\n");
+ }
+
+ /* Last page contained a false trailer, */
+ /* so extend last page to start of trailer */
+ if (dsc->page_count && (dsc->begintrailer != 0) &&
+ (dsc->page[dsc->page_count-1].end != dsc->begintrailer)) {
+ dsc_debug_print(dsc, "Ignoring earlier misplaced trailer\n");
+ dsc_debug_print(dsc, "and extending last page to start of trailer\n");
+ dsc->page[dsc->page_count-1].end = dsc->begintrailer;
+ }
+
+ /*
+ * Join up all sections.
+ * There might be extra code between them, or we might have
+ * missed including the \n which followed \r.
+ */
+ last = &dsc->endcomments;
+ dsc_section_join(dsc->beginpreview, &dsc->endpreview, &last);
+ dsc_section_join(dsc->begindefaults, &dsc->enddefaults, &last);
+ dsc_section_join(dsc->beginprolog, &dsc->endprolog, &last);
+ dsc_section_join(dsc->beginsetup, &dsc->endsetup, &last);
+ for (i=0; i<dsc->page_count; i++)
+ dsc_section_join(dsc->page[i].begin, &dsc->page[i].end, &last);
+ if (dsc->begintrailer)
+ *last = dsc->begintrailer;
+
+ if ((dsc->page_pages == 0) && (dsc->page_count == 1)) {
+ /* don't flag an error if %%Pages absent but one %%Page found */
+ /* adjust incorrect page count */
+ dsc->page_pages = dsc->page_count;
+ }
+
+ /* Warnings and Errors that we can now identify */
+ if ((dsc->page_count != dsc->page_pages)) {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_PAGES_WRONG, NULL, 0);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ /* adjust incorrect page count */
+ dsc->page_pages = dsc->page_count;
+ break;
+ case CDSC_RESPONSE_CANCEL:
+ break;;
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+
+ if (dsc->epsf && (dsc->bbox == (CDSCBBOX *)NULL)) {
+ /* EPS files MUST include a BoundingBox */
+ int rc = dsc_error(dsc, CDSC_MESSAGE_EPS_NO_BBOX, NULL, 0);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ /* Assume that it is EPS */
+ break;
+ case CDSC_RESPONSE_CANCEL:
+ /* Is NOT an EPS file */
+ dsc->epsf = FALSE;
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+
+ if (dsc->epsf && ((dsc->page_count > 1) || (dsc->page_pages > 1))) {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_EPS_PAGES, NULL, 0);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ /* Is an EPS file */
+ break;
+ case CDSC_RESPONSE_CANCEL:
+ /* Is NOT an EPS file */
+ dsc->epsf = FALSE;
+ break;
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+
+ if ((dsc->media_count == 1) && (dsc->page_media == NULL)) {
+ /* if one only media was specified, and default page media */
+ /* was not specified, assume that default is the only media. */
+ dsc->page_media = dsc->media[0];
+ }
+
+ if ((dsc->media_count != 0) && (dsc->page_media == NULL)) {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_NO_MEDIA, NULL, 0);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ /* default media is first listed */
+ dsc->page_media = dsc->media[0];
+ break;
+ case CDSC_RESPONSE_CANCEL:
+ /* No default media */
+ break;
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+
+ /* make sure all pages have a label */
+ for (i=0; i<dsc->page_count; i++) {
+ if (strlen(dsc->page[i].label) == 0) {
+ sprintf(buf, "%d", i+1);
+ if ((dsc->page[i].label = dsc_alloc_string(dsc, buf, strlen(buf)))
+ == (char *)NULL)
+ return CDSC_ERROR; /* no memory */
+ }
+ }
+ return CDSC_OK;
+}
+
+/* Install a function to be used for displaying messages about
+ * DSC errors and warnings, and to request advice from user.
+ * Installing an error function is optional.
+ */
+void
+dsc_set_error_function(CDSC *dsc,
+ int (*fn)(P5(void *caller_data, CDSC *dsc,
+ unsigned int explanation, const char *line, unsigned int line_len)))
+{
+ dsc->dsc_error_fn = fn;
+}
+
+
+/* Install a function for printing debug messages */
+/* This is optional */
+void
+dsc_set_debug_function(CDSC *dsc,
+ void (*debug_fn)(P2(void *caller_data, const char *str)))
+{
+ dsc->debug_print_fn = debug_fn;
+}
+
+/* Doesn't need to be public for PostScript documents */
+/* Made public so GSview can add pages when processing PDF files */
+int
+dsc_add_page(CDSC *dsc, int ordinal, char *label)
+{
+ dsc->page[dsc->page_count].ordinal = ordinal;
+ dsc->page[dsc->page_count].label =
+ dsc_alloc_string(dsc, label, strlen(label)+1);
+ dsc->page[dsc->page_count].begin = 0;
+ dsc->page[dsc->page_count].end = 0;
+ dsc->page[dsc->page_count].orientation = CDSC_ORIENT_UNKNOWN;
+ dsc->page[dsc->page_count].media = NULL;
+ dsc->page[dsc->page_count].bbox = NULL;
+ dsc->page[dsc->page_count].viewing_orientation = NULL;
+
+ dsc->page_count++;
+ if (dsc->page_count >= dsc->page_chunk_length) {
+ CDSCPAGE *new_page = (CDSCPAGE *)dsc_memalloc(dsc,
+ (CDSC_PAGE_CHUNK+dsc->page_count) * sizeof(CDSCPAGE));
+ if (new_page == NULL)
+ return CDSC_ERROR; /* out of memory */
+ memcpy(new_page, dsc->page,
+ dsc->page_count * sizeof(CDSCPAGE));
+ dsc_memfree(dsc, dsc->page);
+ dsc->page= new_page;
+ dsc->page_chunk_length = CDSC_PAGE_CHUNK+dsc->page_count;
+ }
+ return CDSC_OK;
+}
+
+/* Doesn't need to be public for PostScript documents */
+/* Made public so GSview can store PDF MediaBox */
+int
+dsc_add_media(CDSC *dsc, CDSCMEDIA *media)
+{
+ CDSCMEDIA **newmedia_array;
+ CDSCMEDIA *newmedia;
+
+ /* extend media array */
+ newmedia_array = (CDSCMEDIA **)dsc_memalloc(dsc,
+ (dsc->media_count + 1) * sizeof(CDSCMEDIA *));
+ if (newmedia_array == NULL)
+ return CDSC_ERROR; /* out of memory */
+ if (dsc->media != NULL) {
+ memcpy(newmedia_array, dsc->media,
+ dsc->media_count * sizeof(CDSCMEDIA *));
+ dsc_memfree(dsc, dsc->media);
+ }
+ dsc->media = newmedia_array;
+
+ /* allocate new media */
+ newmedia = dsc->media[dsc->media_count] =
+ (CDSCMEDIA *)dsc_memalloc(dsc, sizeof(CDSCMEDIA));
+ if (newmedia == NULL)
+ return CDSC_ERROR; /* out of memory */
+ newmedia->name = NULL;
+ newmedia->width = 595.0;
+ newmedia->height = 842.0;
+ newmedia->weight = 80.0;
+ newmedia->colour = NULL;
+ newmedia->type = NULL;
+ newmedia->mediabox = NULL;
+
+ dsc->media_count++;
+
+ if (media->name) {
+ newmedia->name = dsc_alloc_string(dsc, media->name,
+ strlen(media->name));
+ if (newmedia->name == NULL)
+ return CDSC_ERROR; /* no memory */
+ }
+ newmedia->width = media->width;
+ newmedia->height = media->height;
+ newmedia->weight = media->weight;
+ if (media->colour) {
+ newmedia->colour = dsc_alloc_string(dsc, media->colour,
+ strlen(media->colour));
+ if (newmedia->colour == NULL)
+ return CDSC_ERROR; /* no memory */
+ }
+ if (media->type) {
+ newmedia->type = dsc_alloc_string(dsc, media->type,
+ strlen(media->type));
+ if (newmedia->type == NULL)
+ return CDSC_ERROR; /* no memory */
+ }
+ newmedia->mediabox = NULL;
+
+ if (media->mediabox) {
+ newmedia->mediabox = (CDSCBBOX *)dsc_memalloc(dsc, sizeof(CDSCBBOX));
+ if (newmedia->mediabox == NULL)
+ return CDSC_ERROR; /* no memory */
+ *newmedia->mediabox = *media->mediabox;
+ }
+ return CDSC_OK;
+}
+
+/* Doesn't need to be public for PostScript documents */
+/* Made public so GSview can store PDF CropBox */
+int
+dsc_set_page_bbox(CDSC *dsc, unsigned int page_number,
+ int llx, int lly, int urx, int ury)
+{
+ CDSCBBOX *bbox;
+ if (page_number >= dsc->page_count)
+ return CDSC_ERROR;
+ bbox = dsc->page[page_number].bbox;
+ if (bbox == NULL)
+ dsc->page[page_number].bbox = bbox =
+ (CDSCBBOX *)dsc_memalloc(dsc, sizeof(CDSCBBOX));
+ if (bbox == NULL)
+ return CDSC_ERROR;
+ bbox->llx = llx;
+ bbox->lly = lly;
+ bbox->urx = urx;
+ bbox->ury = ury;
+ return CDSC_OK;
+}
+
+
+/******************************************************************/
+/* Private functions below here. */
+/******************************************************************/
+
+dsc_private void *
+dsc_memalloc(CDSC *dsc, size_t size)
+{
+ if (dsc->memalloc)
+ return dsc->memalloc(size, dsc->mem_closure_data);
+ return malloc(size);
+}
+
+dsc_private void
+dsc_memfree(CDSC*dsc, void *ptr)
+{
+ if (dsc->memfree)
+ dsc->memfree(ptr, dsc->mem_closure_data);
+ else
+ free(ptr);
+}
+
+/* private constructor */
+dsc_private CDSC *
+dsc_init2(CDSC *dsc)
+{
+ dsc_reset(dsc);
+
+ dsc->string_head = (CDSCSTRING *)dsc_memalloc(dsc, sizeof(CDSCSTRING));
+ if (dsc->string_head == NULL) {
+ dsc_free(dsc);
+ return NULL; /* no memory */
+ }
+ dsc->string = dsc->string_head;
+ dsc->string->next = NULL;
+ dsc->string->data = (char *)dsc_memalloc(dsc, CDSC_STRING_CHUNK);
+ if (dsc->string->data == NULL) {
+ dsc_free(dsc);
+ return NULL; /* no memory */
+ }
+ dsc->string->index = 0;
+ dsc->string->length = CDSC_STRING_CHUNK;
+
+ dsc->page = (CDSCPAGE *)dsc_memalloc(dsc, CDSC_PAGE_CHUNK * sizeof(CDSCPAGE));
+ if (dsc->page == NULL) {
+ dsc_free(dsc);
+ return NULL; /* no memory */
+ }
+ dsc->page_chunk_length = CDSC_PAGE_CHUNK;
+ dsc->page_count = 0;
+
+ dsc->line = NULL;
+ dsc->data_length = 0;
+ dsc->data_index = dsc->data_length;
+
+ return dsc;
+}
+
+
+dsc_private void
+dsc_reset(CDSC *dsc)
+{
+ unsigned int i;
+ /* Clear public members */
+ dsc->dsc = FALSE;
+ dsc->ctrld = FALSE;
+ dsc->pjl = FALSE;
+ dsc->epsf = FALSE;
+ dsc->pdf = FALSE;
+ dsc->epsf = FALSE;
+ dsc->preview = CDSC_NOPREVIEW;
+ dsc->dsc_version = NULL; /* stored in dsc->string */
+ dsc->language_level = 0;
+ dsc->document_data = CDSC_DATA_UNKNOWN;
+ dsc->begincomments = 0;
+ dsc->endcomments = 0;
+ dsc->beginpreview = 0;
+ dsc->endpreview = 0;
+ dsc->begindefaults = 0;
+ dsc->enddefaults = 0;
+ dsc->beginprolog = 0;
+ dsc->endprolog = 0;
+ dsc->beginsetup = 0;
+ dsc->endsetup = 0;
+ dsc->begintrailer = 0;
+ dsc->endtrailer = 0;
+
+ for (i=0; i<dsc->page_count; i++) {
+ /* page media is pointer to an element of media or dsc_known_media */
+ /* do not free it. */
+
+ if (dsc->page[i].bbox)
+ dsc_memfree(dsc, dsc->page[i].bbox);
+ if (dsc->page[i].viewing_orientation)
+ dsc_memfree(dsc, dsc->page[i].viewing_orientation);
+ }
+ if (dsc->page)
+ dsc_memfree(dsc, dsc->page);
+ dsc->page = NULL;
+
+ dsc->page_count = 0;
+ dsc->page_pages = 0;
+ dsc->page_order = CDSC_ORDER_UNKNOWN;
+ dsc->page_orientation = CDSC_ORIENT_UNKNOWN;
+ if (dsc->viewing_orientation)
+ dsc_memfree(dsc, dsc->viewing_orientation);
+ dsc->viewing_orientation = NULL;
+
+ if (dsc->media) {
+ for (i=0; i<dsc->media_count; i++) {
+ if (dsc->media[i]) {
+ if (dsc->media[i]->mediabox)
+ dsc_memfree(dsc, dsc->media[i]->mediabox);
+ dsc_memfree(dsc, dsc->media[i]);
+ }
+ }
+ dsc_memfree(dsc, dsc->media);
+ }
+ dsc->media_count = 0;
+ dsc->media = NULL;
+
+ /* page_media is pointer to an element of media or dsc_known_media */
+ /* do not free it. */
+ dsc->page_media = NULL;
+
+ if (dsc->bbox)
+ dsc_memfree(dsc, dsc->bbox);
+ dsc->bbox = NULL;
+ if (dsc->page_bbox)
+ dsc_memfree(dsc, dsc->page_bbox);
+ dsc->page_bbox = NULL;
+ if (dsc->doseps)
+ dsc_memfree(dsc, dsc->doseps);
+ dsc->doseps = NULL;
+
+ dsc->dsc_title = NULL;
+ dsc->dsc_creator = NULL;
+ dsc->dsc_date = NULL;
+ dsc->dsc_for = NULL;
+
+
+ dsc->max_error = DSC_MAX_ERROR;
+ dsc->severity = dsc_severity;
+
+ /* Clear private members */
+ /* Don't touch dsc->caller_data */
+ dsc->id = CDSC_OK;
+ dsc->scan_section = scan_none;
+ dsc->doseps_end = 0;
+ dsc->page_chunk_length = 0;
+ dsc->file_length = 0;
+ dsc->skip_document = 0;
+ dsc->skip_bytes = 0;
+ dsc->skip_lines = 0;
+ dsc->skip_pjl = 0;
+ dsc->begin_font_count = 0;
+ dsc->begin_feature_count = 0;
+ dsc->begin_resource_count = 0;
+ dsc->begin_procset_count = 0;
+
+ dsc->data_length = 0;
+ dsc->data_index = 0;
+ dsc->data_offset = 0;
+
+ dsc->eof = 0;
+
+ dsc->line = 0;
+ dsc->line_length = 0;
+ dsc->eol = 0;
+ dsc->last_cr = FALSE;
+ dsc->line_count = 1;
+ dsc->long_line = FALSE;
+ memset(dsc->last_line, 0, sizeof(dsc->last_line));
+
+ dsc->string = dsc->string_head;
+ while (dsc->string != (CDSCSTRING *)NULL) {
+ if (dsc->string->data)
+ dsc_memfree(dsc, dsc->string->data);
+ dsc->string_head = dsc->string;
+ dsc->string = dsc->string->next;
+ dsc_memfree(dsc, dsc->string_head);
+ }
+ dsc->string_head = NULL;
+ dsc->string = NULL;
+
+ /* don't touch caller functions */
+
+ /* public data */
+ if (dsc->hires_bbox)
+ dsc_memfree(dsc, dsc->hires_bbox);
+ dsc->hires_bbox = NULL;
+ if (dsc->crop_box)
+ dsc_memfree(dsc, dsc->crop_box);
+ dsc->crop_box = NULL;
+}
+
+/*
+* Join up all sections.
+* There might be extra code between them, or we might have
+* missed including the \n which followed \r.
+* begin is the start of this section
+* pend is a pointer to the end of this section
+* pplast is a pointer to a pointer of the end of the previous section
+*/
+dsc_private void
+dsc_section_join(unsigned long begin, unsigned long *pend, unsigned long **pplast)
+{
+ if (begin)
+ **pplast = begin;
+ if (*pend > begin)
+ *pplast = pend;
+}
+
+
+/* return value is 0 if no line available, or length of line */
+dsc_private int
+dsc_read_line(CDSC *dsc)
+{
+ char *p, *last;
+ dsc->line = NULL;
+
+ if (dsc->eof) {
+ /* return all that remains, even if line incomplete */
+ dsc->line = dsc->data + dsc->data_index;
+ dsc->line_length = dsc->data_length - dsc->data_index;
+ dsc->data_index = dsc->data_length;
+ return dsc->line_length;
+ }
+
+ /* ignore embedded bytes */
+ if (dsc->skip_bytes) {
+ int cnt = min(dsc->skip_bytes,
+ (int)(dsc->data_length - dsc->data_index));
+ dsc->skip_bytes -= cnt;
+ dsc->data_index += cnt;
+ if (dsc->skip_bytes != 0)
+ return 0;
+ }
+
+ do {
+ dsc->line = dsc->data + dsc->data_index;
+ last = dsc->data + dsc->data_length;
+ if (dsc->data_index == dsc->data_length) {
+ dsc->line_length = 0;
+ return 0;
+ }
+ if (dsc->eol) {
+ /* if previous line was complete, increment line count */
+ dsc->line_count++;
+ if (dsc->skip_lines)
+ dsc->skip_lines--;
+ }
+
+ /* skip over \n which followed \r */
+ if (dsc->last_cr && dsc->line[0] == '\n') {
+ dsc->data_index++;
+ dsc->line++;
+ }
+ dsc->last_cr = FALSE;
+
+ /* look for EOL */
+ dsc->eol = FALSE;
+ for (p = dsc->line; p < last; p++) {
+ if (*p == '\r') {
+ p++;
+ if ((p<last) && (*p == '\n'))
+ p++; /* include line feed also */
+ else
+ dsc->last_cr = TRUE; /* we might need to skip \n */
+ dsc->eol = TRUE; /* dsc->line is a complete line */
+ break;
+ }
+ if (*p == '\n') {
+ p++;
+ dsc->eol = TRUE; /* dsc->line is a complete line */
+ break;
+ }
+ if (*p == '\032') { /* MS-DOS Ctrl+Z */
+ dsc->eol = TRUE;
+ }
+ }
+ if (dsc->eol == FALSE) {
+ /* we haven't got a complete line yet */
+ if (dsc->data_length - dsc->data_index < sizeof(dsc->data)/2) {
+ /* buffer is less than half full, ask for some more */
+ dsc->line_length = 0;
+ return 0;
+ }
+ }
+ dsc->data_index += dsc->line_length = (p - dsc->line);
+ } while (dsc->skip_lines && dsc->line_length);
+
+ if (dsc->line_length == 0)
+ return 0;
+
+ if ((dsc->line[0]=='%') && (dsc->line[1]=='%')) {
+ /* handle recursive %%BeginDocument */
+ if ((dsc->skip_document) && dsc->line_length &&
+ COMPARE(dsc->line, "%%EndDocument")) {
+ dsc->skip_document--;
+ }
+
+ /* handle embedded lines or binary data */
+ if (COMPARE(dsc->line, "%%BeginData:")) {
+ /* %%BeginData: <numberof>[ <type> [ <bytesorlines> ] ]
+ * <numberof> ::= <uint> (Lines or physical bytes)
+ * <type> ::= Hex | Binary | ASCII (Type of data)
+ * <bytesorlines> ::= Bytes | Lines (Read in bytes or lines)
+ */
+ char begindata[MAXSTR+1];
+ int cnt;
+ unsigned int num;
+ const char *numberof, *bytesorlines;
+ if ((num = dsc->line_length) >= sizeof(begindata)-1)
+ num = sizeof(begindata)-1;
+
+ memcpy(begindata, dsc->line, num);
+ begindata[num] = '\0';
+ numberof = strtok(begindata+12, " \r\n");
+ strtok(NULL, " \r\n"); /* dump type */
+ bytesorlines = strtok(NULL, " \r\n");
+ if (bytesorlines == NULL)
+ bytesorlines = "Bytes";
+
+ if ( (numberof == NULL) || (bytesorlines == NULL) ) {
+ /* invalid usage of %%BeginData */
+ /* ignore that we ever saw it */
+ int rc = dsc_error(dsc, CDSC_MESSAGE_INCORRECT_USAGE,
+ dsc->line, dsc->line_length);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ case CDSC_RESPONSE_CANCEL:
+ break;
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return 0;
+ }
+ }
+ else {
+ cnt = atoi(numberof);
+ if (cnt) {
+ if (bytesorlines && (dsc_stricmp(bytesorlines, "Lines")==0)) {
+ /* skip cnt lines */
+ if (dsc->skip_lines == 0) {
+ /* we are not already skipping lines */
+ dsc->skip_lines = cnt+1;
+ }
+ }
+ else {
+ /* byte count doesn't includes \n or \r\n */
+ /* or \r of %%BeginData: */
+ /* skip cnt bytes */
+ if (dsc->skip_bytes == 0) {
+ /* we are not already skipping lines */
+ dsc->skip_bytes = cnt;
+ }
+
+ }
+ }
+ }
+ }
+ else if (COMPARE(dsc->line, "%%BeginBinary:")) {
+ /* byte count doesn't includes \n or \r\n or \r of %%BeginBinary:*/
+ unsigned long cnt = atoi(dsc->line + 14);
+ if (dsc->skip_bytes == 0) {
+ /* we are not already skipping lines */
+ dsc->skip_bytes = cnt;
+ }
+ }
+ }
+
+ if ((dsc->line[0]=='%') && (dsc->line[1]=='%') &&
+ COMPARE(dsc->line, "%%BeginDocument:") ) {
+ /* Skip over embedded document, recursively */
+ dsc->skip_document++;
+ }
+
+ if (!dsc->long_line && (dsc->line_length > DSC_LINE_LENGTH)) {
+ dsc_error(dsc, CDSC_MESSAGE_LONG_LINE, dsc->line, dsc->line_length);
+ dsc->long_line = TRUE;
+ }
+
+ return dsc->line_length;
+}
+
+
+/* Save last DSC line, for use with %%+ */
+dsc_private void
+dsc_save_line(CDSC *dsc)
+{
+ int len = min((size_t) sizeof(dsc->last_line), (size_t) dsc->line_length);
+ memcpy(dsc->last_line, dsc->line, len);
+}
+
+/* display unknown DSC line */
+dsc_private void
+dsc_unknown(CDSC *dsc)
+{
+ if (dsc->debug_print_fn) {
+ char line[DSC_LINE_LENGTH];
+ unsigned int length = min((unsigned)DSC_LINE_LENGTH-1, dsc->line_length);
+ sprintf(line, "Unknown in %s section at line %d:\n ",
+ dsc_scan_section_name[dsc->scan_section], dsc->line_count);
+ dsc_debug_print(dsc, line);
+ strncpy(line, dsc->line, length);
+ line[length] = '\0';
+ dsc_debug_print(dsc, line);
+ }
+}
+
+
+dsc_private GSBOOL
+dsc_is_section(char *line)
+{
+ if ( !((line[0]=='%') && (line[1]=='%')) )
+ return FALSE;
+ if (IS_DSC(line, "%%BeginPreview"))
+ return TRUE;
+ if (IS_DSC(line, "%%BeginDefaults"))
+ return TRUE;
+ if (IS_DSC(line, "%%BeginProlog"))
+ return TRUE;
+ if (IS_DSC(line, "%%BeginSetup"))
+ return TRUE;
+ if (IS_DSC(line, "%%Page:"))
+ return TRUE;
+ if (IS_DSC(line, "%%Trailer"))
+ return TRUE;
+ if (IS_DSC(line, "%%EOF"))
+ return TRUE;
+ return FALSE;
+}
+
+
+dsc_private GSDWORD
+dsc_get_dword(const unsigned char *buf)
+{
+ GSDWORD dw;
+ dw = (GSDWORD)buf[0];
+ dw += ((GSDWORD)buf[1])<<8;
+ dw += ((GSDWORD)buf[2])<<16;
+ dw += ((GSDWORD)buf[3])<<24;
+ return dw;
+}
+
+dsc_private GSWORD
+dsc_get_word(const unsigned char *buf)
+{
+ GSWORD w;
+ w = (GSWORD)buf[0];
+ w |= (GSWORD)(buf[1]<<8);
+ return w;
+}
+
+dsc_private int
+dsc_read_doseps(CDSC *dsc)
+{
+ unsigned char *line = (unsigned char *)dsc->line;
+ if ((dsc->doseps = (CDSCDOSEPS *)dsc_memalloc(dsc, sizeof(CDSCDOSEPS))) == NULL)
+ return CDSC_ERROR; /* no memory */
+
+ dsc->doseps->ps_begin = dsc_get_dword(line+4);
+ dsc->doseps->ps_length = dsc_get_dword(line+8);
+ dsc->doseps->wmf_begin = dsc_get_dword(line+12);
+ dsc->doseps->wmf_length = dsc_get_dword(line+16);
+ dsc->doseps->tiff_begin = dsc_get_dword(line+20);
+ dsc->doseps->tiff_length = dsc_get_dword(line+24);
+ dsc->doseps->checksum = dsc_get_word(line+28);
+
+ dsc->doseps_end = dsc->doseps->ps_begin + dsc->doseps->ps_length;
+
+ /* move data_index backwards to byte after doseps header */
+ dsc->data_index -= dsc->line_length - 30;
+ /* we haven't read a line of PostScript code yet */
+ dsc->line_count = 0;
+ /* skip from current position to start of PostScript section */
+ dsc->skip_bytes = dsc->doseps->ps_begin - 30;
+
+ if (dsc->doseps->tiff_begin)
+ dsc->preview = CDSC_TIFF;
+ if (dsc->doseps->wmf_begin)
+ dsc->preview = CDSC_WMF;
+
+ return CDSC_OK;
+}
+
+
+
+dsc_private int
+dsc_parse_pages(CDSC *dsc)
+{
+ int ip, io;
+ unsigned int i;
+ char *p;
+ int n;
+ if ((dsc->page_pages != 0) && (dsc->scan_section == scan_comments)) {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line,
+ dsc->line_length);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ case CDSC_RESPONSE_CANCEL:
+ return CDSC_OK; /* ignore duplicate comments in header */
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+ if ((dsc->page_pages != 0) && (dsc->scan_section == scan_trailer)) {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line,
+ dsc->line_length);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ case CDSC_RESPONSE_CANCEL:
+ break; /* use duplicate comments in header */
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+
+ n = IS_DSC(dsc->line, "%%+") ? 3 : 8;
+ while (IS_WHITE(dsc->line[n]))
+ n++;
+ p = dsc->line + n;
+ if (COMPARE(p, "atend")) {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line, dsc->line_length);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ /* assume (atend) */
+ /* we should mark it as deferred */
+ break;
+ case CDSC_RESPONSE_CANCEL:
+ /* ignore it */
+ break;
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+ else if (COMPARE(p, "(atend)")) {
+ /* do nothing */
+ /* we should mark it as deferred */
+ }
+ else {
+ ip = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
+ if (i) {
+ n+=i;
+ dsc->page_pages = ip;
+ io = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
+ if (i) {
+ /* DSC 2 uses extra integer to indicate page order */
+ /* DSC 3 uses %%PageOrder: */
+ if (dsc->page_order == CDSC_ORDER_UNKNOWN)
+ switch (io) {
+ case -1:
+ dsc->page_order = CDSC_DESCEND;
+ break;
+ case 0:
+ dsc->page_order = CDSC_SPECIAL;
+ break;
+ case 1:
+ dsc->page_order = CDSC_ASCEND;
+ break;
+ }
+ }
+ }
+ else {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_INCORRECT_USAGE, dsc->line,
+ dsc->line_length);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ case CDSC_RESPONSE_CANCEL:
+ /* ignore it */
+ break;
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+ }
+ return CDSC_OK;
+}
+
+dsc_private int
+dsc_parse_bounding_box(CDSC *dsc, CDSCBBOX** pbbox, int offset)
+{
+ unsigned int i, n;
+ int llx, lly, urx, ury;
+ float fllx, flly, furx, fury;
+ char *p;
+ /* Process first %%BoundingBox: in comments, and last in trailer */
+ if ((*pbbox != NULL) && (dsc->scan_section == scan_comments)) {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line,
+ dsc->line_length);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ case CDSC_RESPONSE_CANCEL:
+ return CDSC_OK; /* ignore duplicate comments in header */
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+ if ((*pbbox != NULL) && (dsc->scan_section == scan_pages)) {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line,
+ dsc->line_length);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ case CDSC_RESPONSE_CANCEL:
+ return CDSC_OK; /* ignore duplicate comments in header */
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+ if ((*pbbox != NULL) && (dsc->scan_section == scan_trailer)) {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line,
+ dsc->line_length);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ case CDSC_RESPONSE_CANCEL:
+ break; /* use duplicate comments in trailer */
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+ if (*pbbox != NULL) {
+ dsc_memfree(dsc, *pbbox);
+ *pbbox = NULL;
+ }
+
+ /* should only process first %%BoundingBox: */
+
+ while (IS_WHITE(dsc->line[offset]))
+ offset++;
+ p = dsc->line + offset;
+
+ if (COMPARE(p, "atend")) {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line,
+ dsc->line_length);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ /* assume (atend) */
+ /* we should mark it as deferred */
+ break;
+ case CDSC_RESPONSE_CANCEL:
+ /* ignore it */
+ break;
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+ else if (COMPARE(p, "(atend)")) {
+ /* do nothing */
+ /* we should mark it as deferred */
+ }
+ else {
+ /* llx = */ lly = urx = ury = 0;
+ n = offset;
+ llx = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
+ n += i;
+ if (i)
+ lly = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
+ n += i;
+ if (i)
+ urx = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
+ n += i;
+ if (i)
+ ury = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
+ if (i) {
+ *pbbox = (CDSCBBOX *)dsc_memalloc(dsc, sizeof(CDSCBBOX));
+ if (*pbbox == NULL)
+ return CDSC_ERROR; /* no memory */
+ (*pbbox)->llx = llx;
+ (*pbbox)->lly = lly;
+ (*pbbox)->urx = urx;
+ (*pbbox)->ury = ury;
+ }
+ else {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_BBOX, dsc->line,
+ dsc->line_length);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ /* fllx = */ flly = furx = fury = 0.0;
+ n = offset;
+ n += i;
+ fllx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+ n += i;
+ if (i)
+ flly = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+ n += i;
+ if (i)
+ furx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+ n += i;
+ if (i)
+ fury = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+ if (i) {
+ *pbbox = (CDSCBBOX *)dsc_memalloc(dsc, sizeof(CDSCBBOX));
+ if (*pbbox == NULL)
+ return CDSC_ERROR; /* no memory */
+ (*pbbox)->llx = (int)fllx;
+ (*pbbox)->lly = (int)flly;
+ (*pbbox)->urx = (int)(furx+0.999);
+ (*pbbox)->ury = (int)(fury+0.999);
+ }
+ return CDSC_OK;
+ case CDSC_RESPONSE_CANCEL:
+ return CDSC_OK;
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+ }
+ return CDSC_OK;
+}
+
+dsc_private int
+dsc_parse_float_bounding_box(CDSC *dsc, CDSCFBBOX** pbbox, int offset)
+{
+ unsigned int i, n;
+ float fllx, flly, furx, fury;
+ char *p;
+ /* Process first %%HiResBoundingBox: or %%CropBox: in comments,
+ * and last in trailer.
+ */
+ if ((*pbbox != NULL) && (dsc->scan_section == scan_comments)) {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line,
+ dsc->line_length);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ case CDSC_RESPONSE_CANCEL:
+ return CDSC_OK; /* ignore duplicate comments in header */
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+ if ((*pbbox != NULL) && (dsc->scan_section == scan_pages)) {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line,
+ dsc->line_length);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ case CDSC_RESPONSE_CANCEL:
+ return CDSC_OK; /* ignore duplicate comments in header */
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+ if ((*pbbox != NULL) && (dsc->scan_section == scan_trailer)) {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line,
+ dsc->line_length);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ case CDSC_RESPONSE_CANCEL:
+ break; /* use duplicate comments in trailer */
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+ if (*pbbox != NULL) {
+ dsc_memfree(dsc, *pbbox);
+ *pbbox = NULL;
+ }
+
+ /* should only process first %%BoundingBox: */
+
+ while (IS_WHITE(dsc->line[offset]))
+ offset++;
+ p = dsc->line + offset;
+
+ if (COMPARE(p, "atend")) {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line,
+ dsc->line_length);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ /* assume (atend) */
+ /* we should mark it as deferred */
+ break;
+ case CDSC_RESPONSE_CANCEL:
+ /* ignore it */
+ break;
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+ else if (COMPARE(p, "(atend)")) {
+ /* do nothing */
+ /* we should mark it as deferred */
+ }
+ else {
+ /* fllx = */ flly = furx = fury = 0.0;
+ n = offset;
+ fllx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+ n += i;
+ if (i)
+ flly = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+ n += i;
+ if (i)
+ furx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+ n += i;
+ if (i)
+ fury = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+ if (i) {
+ *pbbox = (CDSCFBBOX *)dsc_memalloc(dsc, sizeof(CDSCFBBOX));
+ if (*pbbox == NULL)
+ return CDSC_ERROR; /* no memory */
+ (*pbbox)->fllx = fllx;
+ (*pbbox)->flly = flly;
+ (*pbbox)->furx = furx;
+ (*pbbox)->fury = fury;
+ }
+ }
+ return CDSC_OK;
+}
+
+dsc_private int
+dsc_parse_orientation(CDSC *dsc, unsigned int *porientation, int offset)
+{
+ char *p;
+ if ((dsc->page_orientation != CDSC_ORIENT_UNKNOWN) &&
+ (dsc->scan_section == scan_comments)) {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line,
+ dsc->line_length);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ case CDSC_RESPONSE_CANCEL:
+ return CDSC_OK; /* ignore duplicate comments in header */
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+ if ((dsc->page_orientation != CDSC_ORIENT_UNKNOWN) &&
+ (dsc->scan_section == scan_trailer)) {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line,
+ dsc->line_length);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ case CDSC_RESPONSE_CANCEL:
+ break; /* use duplicate comments in header; */
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+ p = dsc->line + offset;
+ while (IS_WHITE(*p))
+ p++;
+ if (COMPARE(p, "atend")) {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line, dsc->line_length);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ /* assume (atend) */
+ /* we should mark it as deferred */
+ break;
+ case CDSC_RESPONSE_CANCEL:
+ /* ignore it */
+ break;
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+ else if (COMPARE(p, "(atend)")) {
+ /* do nothing */
+ /* we should mark it as deferred */
+ }
+ else if (COMPARE(p, "Portrait")) {
+ *porientation = CDSC_PORTRAIT;
+ }
+ else if (COMPARE(p, "Landscape")) {
+ *porientation = CDSC_LANDSCAPE;
+ }
+ else {
+ dsc_unknown(dsc);
+ }
+ return CDSC_OK;
+}
+
+dsc_private int
+dsc_parse_order(CDSC *dsc)
+{
+ char *p;
+ if ((dsc->page_order != CDSC_ORDER_UNKNOWN) &&
+ (dsc->scan_section == scan_comments)) {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line,
+ dsc->line_length);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ case CDSC_RESPONSE_CANCEL:
+ return CDSC_OK; /* ignore duplicate comments in header */
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+ if ((dsc->page_order != CDSC_ORDER_UNKNOWN) &&
+ (dsc->scan_section == scan_trailer)) {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line,
+ dsc->line_length);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ case CDSC_RESPONSE_CANCEL:
+ break; /* use duplicate comments in trailer */
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+
+ p = dsc->line + (IS_DSC(dsc->line, "%%+") ? 3 : 13);
+ while (IS_WHITE(*p))
+ p++;
+ if (COMPARE(p, "atend")) {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line,
+ dsc->line_length);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ /* assume (atend) */
+ /* we should mark it as deferred */
+ break;
+ case CDSC_RESPONSE_CANCEL:
+ /* ignore it */
+ break;
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+ else if (COMPARE(p, "(atend)")) {
+ /* do nothing */
+ /* we should mark it as deferred */
+ }
+ else if (COMPARE(p, "Ascend")) {
+ dsc->page_order = CDSC_ASCEND;
+ }
+ else if (COMPARE(p, "Descend")) {
+ dsc->page_order = CDSC_DESCEND;
+ }
+ else if (COMPARE(p, "Special")) {
+ dsc->page_order = CDSC_SPECIAL;
+ }
+ else {
+ dsc_unknown(dsc);
+ }
+ return CDSC_OK;
+}
+
+
+dsc_private int
+dsc_parse_media(CDSC *dsc, const CDSCMEDIA **page_media)
+{
+ char media_name[MAXSTR];
+ int n = IS_DSC(dsc->line, "%%+") ? 3 : 12; /* %%PageMedia: */
+ unsigned int i;
+
+ if (dsc_copy_string(media_name, sizeof(media_name)-1,
+ dsc->line+n, dsc->line_length-n, NULL)) {
+ for (i=0; i<dsc->media_count; i++) {
+ if (dsc->media[i]->name &&
+ (dsc_stricmp(media_name, dsc->media[i]->name) == 0)) {
+ *page_media = dsc->media[i];
+ return CDSC_OK;
+ }
+ }
+ }
+ dsc_unknown(dsc);
+
+ return CDSC_OK;
+}
+
+
+dsc_private int
+dsc_parse_document_media(CDSC *dsc)
+{
+ unsigned int i, n;
+ CDSCMEDIA lmedia;
+ GSBOOL blank_line;
+
+ if (IS_DSC(dsc->line, "%%DocumentMedia:"))
+ n = 16;
+ else if (IS_DSC(dsc->line, "%%+"))
+ n = 3;
+ else
+ return CDSC_ERROR; /* error */
+
+ /* check for blank remainder of line */
+ blank_line = TRUE;
+ for (i=n; i<dsc->line_length; i++) {
+ if (!IS_WHITE_OR_EOL(dsc->line[i])) {
+ blank_line = FALSE;
+ break;
+ }
+ }
+
+ if (!blank_line) {
+ char name[MAXSTR];
+ char colour[MAXSTR];
+ char type[MAXSTR];
+ lmedia.name = lmedia.colour = lmedia.type = (char *)NULL;
+ lmedia.width = lmedia.height = lmedia.weight = 0;
+ lmedia.mediabox = (CDSCBBOX *)NULL;
+ lmedia.name = dsc_copy_string(name, sizeof(name)-1,
+ dsc->line+n, dsc->line_length-n, &i);
+ n+=i;
+ if (i)
+ lmedia.width = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+ n+=i;
+ if (i)
+ lmedia.height = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+ n+=i;
+ if (i)
+ lmedia.weight = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+ n+=i;
+ if (i)
+ lmedia.colour = dsc_copy_string(colour, sizeof(colour)-1,
+ dsc->line+n, dsc->line_length-n, &i);
+ n+=i;
+ if (i)
+ lmedia.type = dsc_copy_string(type, sizeof(type)-1,
+ dsc->line+n, dsc->line_length-n, &i);
+
+ if (i==0)
+ dsc_unknown(dsc); /* we didn't get all fields */
+ else {
+ if (dsc_add_media(dsc, &lmedia))
+ return CDSC_ERROR; /* out of memory */
+ }
+ }
+ return CDSC_OK;
+}
+
+/* viewing orientation is believed to be the first four elements of
+ * a CTM matrix
+ */
+dsc_private int
+dsc_parse_viewing_orientation(CDSC *dsc, CDSCCTM **pctm)
+{
+ CDSCCTM ctm;
+ unsigned int i, n;
+
+ if (*pctm != NULL) {
+ dsc_memfree(dsc, *pctm);
+ *pctm = NULL;
+ }
+
+ n = IS_DSC(dsc->line, "%%+") ? 3 : 21; /* %%ViewingOrientation: */
+ while (IS_WHITE(dsc->line[n]))
+ n++;
+
+ /* ctm.xx = */ ctm.xy = ctm.yx = ctm.yy = 0.0;
+ ctm.xx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+ n += i;
+ if (i)
+ ctm.xy = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+ n += i;
+ if (i)
+ ctm.yx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+ n += i;
+ if (i)
+ ctm.yy = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+ if (i==0) {
+ dsc_unknown(dsc); /* we didn't get all fields */
+ }
+ else {
+ *pctm = (CDSCCTM *)dsc_memalloc(dsc, sizeof(CDSCCTM));
+ if (*pctm == NULL)
+ return CDSC_ERROR; /* no memory */
+ **pctm = ctm;
+ }
+ return CDSC_OK;
+}
+
+
+/* This is called before dsc_read_line(), since we may
+ * need to skip a binary header which contains a new line
+ * character
+ */
+dsc_private int
+dsc_scan_type(CDSC *dsc)
+{
+ unsigned char *p;
+ unsigned char *line = (unsigned char *)(dsc->data + dsc->data_index);
+ int length = dsc->data_length - dsc->data_index;
+
+ /* Types that should be known:
+ * DSC
+ * EPSF
+ * PJL + any of above
+ * ^D + any of above
+ * DOS EPS
+ * PDF
+ * non-DSC
+ */
+
+ /* First process any non PostScript headers */
+ /* At this stage we do not have a complete line */
+
+ if (length == 0)
+ return CDSC_NEEDMORE;
+
+ if (dsc->skip_pjl) {
+ /* skip until first PostScript comment */
+ while (length >= 2) {
+ while (length && !IS_EOL(line[0])) {
+ /* skip until EOL character */
+ line++;
+ dsc->data_index++;
+ length--;
+ }
+ while ((length >= 2) && IS_EOL(line[0]) && IS_EOL(line[1])) {
+ /* skip until EOL followed by non-EOL */
+ line++;
+ dsc->data_index++;
+ length--;
+ }
+ if (length < 2)
+ return CDSC_NEEDMORE;
+
+ if (IS_EOL(line[0]) && line[1]=='%') {
+ line++;
+ dsc->data_index++;
+ length--;
+ dsc->skip_pjl = FALSE;
+ break;
+ }
+ else {
+ /* line++; */
+ dsc->data_index++;
+ /* length--; */
+ return CDSC_NEEDMORE;
+ }
+ }
+ if (dsc->skip_pjl)
+ return CDSC_NEEDMORE;
+ }
+
+ if (length == 0)
+ return CDSC_NEEDMORE;
+
+ if (line[0] == '\004') {
+ line++;
+ dsc->data_index++;
+ length--;
+ dsc->ctrld = TRUE;
+ }
+
+ if (line[0] == '\033') {
+ /* possibly PJL */
+ if (length < 9)
+ return CDSC_NEEDMORE;
+ if (COMPARE(line, "\033%-12345X")) {
+ dsc->skip_pjl = TRUE; /* skip until first PostScript comment */
+ dsc->pjl = TRUE;
+ dsc->data_index += 9;
+ return dsc_scan_type(dsc);
+ }
+ }
+
+ if ((line[0]==0xc5) && (length < 4))
+ return CDSC_NEEDMORE;
+ if ((line[0]==0xc5) && (line[1]==0xd0) &&
+ (line[2]==0xd3) && (line[3]==0xc6) ) {
+ /* id is "EPSF" with bit 7 set */
+ /* read DOS EPS header, then ignore all bytes until the PS section */
+ if (length < 30)
+ return CDSC_NEEDMORE;
+ dsc->line = (char *)line;
+ if (dsc_read_doseps(dsc))
+ return CDSC_ERROR;
+ }
+ else {
+ if (length < 2)
+ return CDSC_NEEDMORE;
+ if ((line[0] == '%') && (line[1] == 'P')) {
+ if (length < 5)
+ return CDSC_NEEDMORE;
+ if (COMPARE(line, "%PDF-")) {
+ dsc->pdf = TRUE;
+ dsc->scan_section = scan_comments;
+ return CDSC_OK;
+ }
+ }
+ }
+
+ /* Finally process PostScript headers */
+
+ if (dsc_read_line(dsc) <= 0)
+ return CDSC_NEEDMORE;
+
+ dsc->dsc_version = dsc_add_line(dsc, dsc->line, dsc->line_length);
+ if (COMPARE(dsc->line, "%!PS-Adobe")) {
+ dsc->dsc = TRUE;
+ dsc->begincomments = DSC_START(dsc);
+ if (dsc->dsc_version == NULL)
+ return CDSC_ERROR; /* no memory */
+ p = (unsigned char *)dsc->line + 14;
+ while (IS_WHITE(*p))
+ p++;
+ if (COMPARE(p, "EPSF-"))
+ dsc->epsf = TRUE;
+ dsc->scan_section = scan_comments;
+ return CDSC_PSADOBE;
+ }
+ if (COMPARE(dsc->line, "%!")) {
+ dsc->scan_section = scan_comments;
+ return CDSC_NOTDSC;
+ }
+
+ dsc->scan_section = scan_comments;
+ return CDSC_NOTDSC; /* unrecognised */
+}
+
+
+
+dsc_private int
+dsc_scan_comments(CDSC *dsc)
+{
+ /* Comments section ends at */
+ /* %%EndComments */
+ /* another section */
+ /* line that does not start with %% */
+ /* Save a few important lines */
+
+ char *line = dsc->line;
+ GSBOOL continued = FALSE;
+ dsc->id = CDSC_OK;
+ if (IS_DSC(line, "%%EndComments")) {
+ dsc->id = CDSC_ENDCOMMENTS;
+ dsc->endcomments = DSC_END(dsc);
+ dsc->scan_section = scan_pre_preview;
+ return CDSC_OK;
+ }
+ else if (IS_DSC(line, "%%BeginComments")) {
+ /* ignore because we are in this section */
+ dsc->id = CDSC_BEGINCOMMENTS;
+ }
+ else if (dsc_is_section(line)) {
+ dsc->endcomments = DSC_START(dsc);
+ dsc->scan_section = scan_pre_preview;
+ return CDSC_PROPAGATE;
+ }
+ else if (line[0] == '%' && IS_WHITE_OR_EOL(line[1])) {
+ dsc->endcomments = DSC_START(dsc);
+ dsc->scan_section = scan_pre_preview;
+ return CDSC_PROPAGATE;
+ }
+ else if (line[0] != '%') {
+ dsc->id = CDSC_OK;
+ dsc->endcomments = DSC_START(dsc);
+ dsc->scan_section = scan_pre_preview;
+ return CDSC_PROPAGATE;
+ }
+ else if (IS_DSC(line, "%%Begin")) {
+ dsc->endcomments = DSC_START(dsc);
+ dsc->scan_section = scan_pre_preview;
+ return CDSC_PROPAGATE;
+ }
+
+ /* Handle continuation lines.
+ * To simply processing, we assume that contination lines
+ * will only occur if repeat parameters are allowed and that
+ * a complete set of these parameters appears on each line.
+ * This is more restrictive than the DSC specification, but
+ * is valid for the DSC comments understood by this parser
+ * for all documents that we have seen.
+ */
+ if (IS_DSC(line, "%%+")) {
+ line = dsc->last_line;
+ continued = TRUE;
+ }
+ else
+ dsc_save_line(dsc);
+
+ if (IS_DSC(line, "%%Pages:")) {
+ dsc->id = CDSC_PAGES;
+ if (dsc_parse_pages(dsc) != 0)
+ return CDSC_ERROR;
+ }
+ else if (IS_DSC(line, "%%Creator:")) {
+ dsc->id = CDSC_CREATOR;
+ dsc->dsc_creator = dsc_add_line(dsc, dsc->line+10, dsc->line_length-10);
+ if (dsc->dsc_creator==NULL)
+ return CDSC_ERROR;
+ }
+ else if (IS_DSC(line, "%%CreationDate:")) {
+ dsc->id = CDSC_CREATIONDATE;
+ dsc->dsc_date = dsc_add_line(dsc, dsc->line+15, dsc->line_length-15);
+ if (dsc->dsc_date==NULL)
+ return CDSC_ERROR;
+ }
+ else if (IS_DSC(line, "%%Title:")) {
+ dsc->id = CDSC_TITLE;
+ dsc->dsc_title = dsc_add_line(dsc, dsc->line+8, dsc->line_length-8);
+ if (dsc->dsc_title==NULL)
+ return CDSC_ERROR;
+ }
+ else if (IS_DSC(line, "%%For:")) {
+ dsc->id = CDSC_FOR;
+ dsc->dsc_for = dsc_add_line(dsc, dsc->line+6, dsc->line_length-6);
+ if (dsc->dsc_for==NULL)
+ return CDSC_ERROR;
+ }
+ else if (IS_DSC(line, "%%LanguageLevel:")) {
+ unsigned int n = continued ? 3 : 16;
+ unsigned int i;
+ int ll;
+ dsc->id = CDSC_LANGUAGELEVEL;
+ ll = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
+ if (i) {
+ if ( (ll==1) || (ll==2) || (ll==3) )
+ dsc->language_level = ll;
+ else {
+ dsc_unknown(dsc);
+ }
+ }
+ else
+ dsc_unknown(dsc);
+ }
+ else if (IS_DSC(line, "%%BoundingBox:")) {
+ dsc->id = CDSC_BOUNDINGBOX;
+ if (dsc_parse_bounding_box(dsc, &(dsc->bbox), continued ? 3 : 14))
+ return CDSC_ERROR;
+ }
+ else if (IS_DSC(line, "%%HiResBoundingBox:")) {
+ dsc->id = CDSC_HIRESBOUNDINGBOX;
+ if (dsc_parse_float_bounding_box(dsc, &(dsc->hires_bbox),
+ continued ? 3 : 19))
+ return CDSC_ERROR;
+ }
+ else if (IS_DSC(line, "%%CropBox:")) {
+ dsc->id = CDSC_CROPBOX;
+ if (dsc_parse_float_bounding_box(dsc, &(dsc->crop_box),
+ continued ? 3 : 10))
+ return CDSC_ERROR;
+ }
+ else if (IS_DSC(line, "%%Orientation:")) {
+ dsc->id = CDSC_ORIENTATION;
+ if (dsc_parse_orientation(dsc, &(dsc->page_orientation),
+ continued ? 3 : 14))
+ return CDSC_ERROR;
+ }
+ else if (IS_DSC(line, "%%PageOrder:")) {
+ dsc->id = CDSC_PAGEORDER;
+ if (dsc_parse_order(dsc))
+ return CDSC_ERROR;
+ }
+ else if (IS_DSC(line, "%%DocumentMedia:")) {
+ dsc->id = CDSC_DOCUMENTMEDIA;
+ if (dsc_parse_document_media(dsc))
+ return CDSC_ERROR;
+ }
+ else if (IS_DSC(line, "%%DocumentPaperSizes:")) {
+ /* DSC 2.1 */
+ unsigned int n = continued ? 3 : 21;
+ unsigned int count = 0;
+ unsigned int i = 1;
+ char name[MAXSTR];
+ char *p;
+ dsc->id = CDSC_DOCUMENTPAPERSIZES;
+ while (i && (dsc->line[n]!='\r') && (dsc->line[n]!='\n')) {
+ p = dsc_copy_string(name, sizeof(name)-1,
+ dsc->line+n, dsc->line_length-n, &i);
+ if (i && p) {
+ const CDSCMEDIA *m = dsc_known_media;
+ if (count >= dsc->media_count) {
+ /* set some default values */
+ CDSCMEDIA lmedia;
+ lmedia.name = p;
+ lmedia.width = 595.0;
+ lmedia.height = 842.0;
+ lmedia.weight = 80.0;
+ lmedia.colour = NULL;
+ lmedia.type = NULL;
+ lmedia.mediabox = NULL;
+ if (dsc_add_media(dsc, &lmedia))
+ return CDSC_ERROR;
+ }
+ else
+ dsc->media[count]->name =
+ dsc_alloc_string(dsc, p, strlen(p));
+ /* find in list of known media */
+ while (m && m->name) {
+ if (dsc_stricmp(p, m->name)==0) {
+ dsc->media[count]->width = m->width;
+ dsc->media[count]->height = m->height;
+ break;
+ }
+ m++;
+ }
+ }
+ n+=i;
+ count++;
+ }
+ }
+ else if (IS_DSC(line, "%%DocumentPaperForms:")) {
+ /* DSC 2.1 */
+ unsigned int n = continued ? 3 : 21;
+ unsigned int count = 0;
+ unsigned int i = 1;
+ char type[MAXSTR];
+ char *p;
+ dsc->id = CDSC_DOCUMENTPAPERFORMS;
+ while (i && (dsc->line[n]!='\r') && (dsc->line[n]!='\n')) {
+ p = dsc_copy_string(type, sizeof(type)-1,
+ dsc->line+n, dsc->line_length-n, &i);
+ if (i && p) {
+ if (count >= dsc->media_count) {
+ /* set some default values */
+ CDSCMEDIA lmedia;
+ lmedia.name = NULL;
+ lmedia.width = 595.0;
+ lmedia.height = 842.0;
+ lmedia.weight = 80.0;
+ lmedia.colour = NULL;
+ lmedia.type = p;
+ lmedia.mediabox = NULL;
+ if (dsc_add_media(dsc, &lmedia))
+ return CDSC_ERROR;
+ }
+ else
+ dsc->media[count]->type =
+ dsc_alloc_string(dsc, p, strlen(p));
+ }
+ n+=i;
+ count++;
+ }
+ }
+ else if (IS_DSC(line, "%%DocumentPaperColors:")) {
+ /* DSC 2.1 */
+ unsigned int n = continued ? 3 : 22;
+ unsigned int count = 0;
+ unsigned int i = 1;
+ char colour[MAXSTR];
+ char *p;
+ dsc->id = CDSC_DOCUMENTPAPERCOLORS;
+ while (i && (dsc->line[n]!='\r') && (dsc->line[n]!='\n')) {
+ p = dsc_copy_string(colour, sizeof(colour)-1,
+ dsc->line+n, dsc->line_length-n, &i);
+ if (i && p) {
+ if (count >= dsc->media_count) {
+ /* set some default values */
+ CDSCMEDIA lmedia;
+ lmedia.name = NULL;
+ lmedia.width = 595.0;
+ lmedia.height = 842.0;
+ lmedia.weight = 80.0;
+ lmedia.colour = p;
+ lmedia.type = NULL;
+ lmedia.mediabox = NULL;
+ if (dsc_add_media(dsc, &lmedia))
+ return CDSC_ERROR;
+ }
+ else
+ dsc->media[count]->colour =
+ dsc_alloc_string(dsc, p, strlen(p));
+ }
+ n+=i;
+ count++;
+ }
+ }
+ else if (IS_DSC(line, "%%DocumentPaperWeights:")) {
+ /* DSC 2.1 */
+ unsigned int n = continued ? 3 : 23;
+ unsigned int count = 0;
+ unsigned int i = 1;
+ float w;
+ dsc->id = CDSC_DOCUMENTPAPERWEIGHTS;
+ while (i && (dsc->line[n]!='\r') && (dsc->line[n]!='\n')) {
+ w = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
+ if (i) {
+ if (count >= dsc->media_count) {
+ /* set some default values */
+ CDSCMEDIA lmedia;
+ lmedia.name = NULL;
+ lmedia.width = 595.0;
+ lmedia.height = 842.0;
+ lmedia.weight = w;
+ lmedia.colour = NULL;
+ lmedia.type = NULL;
+ lmedia.mediabox = NULL;
+ if (dsc_add_media(dsc, &lmedia))
+ return CDSC_ERROR;
+ }
+ else
+ dsc->media[count]->weight = w;
+ }
+ n+=i;
+ count++;
+ }
+ }
+ else if (IS_DSC(line, "%%DocumentData:")) {
+ unsigned int n = continued ? 3 : 15;
+ char *p = dsc->line + n;
+ while (IS_WHITE(*p))
+ p++;
+ dsc->id = CDSC_DOCUMENTDATA;
+ if (COMPARE(p, "Clean7Bit"))
+ dsc->document_data = CDSC_CLEAN7BIT;
+ else if (COMPARE(p, "Clean8Bit"))
+ dsc->document_data = CDSC_CLEAN8BIT;
+ else if (COMPARE(p, "Binary"))
+ dsc->document_data = CDSC_BINARY;
+ else
+ dsc_unknown(dsc);
+ }
+ else if (IS_DSC(line, "%%Requirements:")) {
+ dsc->id = CDSC_REQUIREMENTS;
+ /* ignore */
+ }
+ else if (IS_DSC(line, "%%DocumentNeededFonts:")) {
+ dsc->id = CDSC_DOCUMENTNEEDEDFONTS;
+ /* ignore */
+ }
+ else if (IS_DSC(line, "%%DocumentSuppliedFonts:")) {
+ dsc->id = CDSC_DOCUMENTSUPPLIEDFONTS;
+ /* ignore */
+ }
+ else if (dsc->line[0] == '%' && IS_WHITE_OR_EOL(dsc->line[1])) {
+ dsc->id = CDSC_OK;
+ /* ignore */
+ }
+ else {
+ dsc->id = CDSC_UNKNOWNDSC;
+ dsc_unknown(dsc);
+ }
+
+ dsc->endcomments = DSC_END(dsc);
+ return CDSC_OK;
+}
+
+
+dsc_private int
+dsc_scan_preview(CDSC *dsc)
+{
+ /* Preview section ends at */
+ /* %%EndPreview */
+ /* another section */
+ /* Preview section must start with %%BeginPreview */
+ char *line = dsc->line;
+ dsc->id = CDSC_OK;
+
+ if (dsc->scan_section == scan_pre_preview) {
+ if (IS_BLANK(line))
+ return CDSC_OK; /* ignore blank lines before preview */
+ else if (IS_DSC(line, "%%BeginPreview")) {
+ dsc->id = CDSC_BEGINPREVIEW;
+ dsc->beginpreview = DSC_START(dsc);
+ dsc->endpreview = DSC_END(dsc);
+ dsc->scan_section = scan_preview;
+ /* Don't mark the preview as EPSI if a DOS EPS header is present */
+ if (dsc->preview == CDSC_NOPREVIEW)
+ dsc->preview = CDSC_EPSI;
+ return CDSC_OK;
+ }
+ else {
+ dsc->scan_section = scan_pre_defaults;
+ return CDSC_PROPAGATE;
+ }
+ }
+
+ if (IS_DSC(line, "%%BeginPreview")) {
+ /* ignore because we are in this section */
+ }
+ else if (dsc_is_section(line)) {
+ dsc->endpreview = DSC_START(dsc);
+ dsc->scan_section = scan_pre_defaults;
+ return CDSC_PROPAGATE;
+ }
+ else if (IS_DSC(line, "%%EndPreview")) {
+ dsc->id = CDSC_ENDPREVIEW;
+ dsc->endpreview = DSC_END(dsc);
+ dsc->scan_section = scan_pre_defaults;
+ return CDSC_OK;
+ }
+ else if (line[0] == '%' && line[1] != '%') {
+ /* Ordinary comments are OK */
+ }
+ else {
+ dsc->id = CDSC_UNKNOWNDSC;
+ /* DSC comments should not occur in preview */
+ dsc_unknown(dsc);
+ }
+
+ dsc->endpreview = DSC_END(dsc);
+ return CDSC_OK;
+}
+
+dsc_private int
+dsc_scan_defaults(CDSC *dsc)
+{
+ /* Defaults section ends at */
+ /* %%EndDefaults */
+ /* another section */
+ /* Defaults section must start with %%BeginDefaults */
+ char *line = dsc->line;
+ dsc->id = CDSC_OK;
+
+ if (dsc->scan_section == scan_pre_defaults) {
+ if (IS_BLANK(line))
+ return CDSC_OK; /* ignore blank lines before defaults */
+ else if (IS_DSC(line, "%%BeginDefaults")) {
+ dsc->id = CDSC_BEGINDEFAULTS;
+ dsc->begindefaults = DSC_START(dsc);
+ dsc->enddefaults = DSC_END(dsc);
+ dsc->scan_section = scan_defaults;
+ return CDSC_OK;
+ }
+ else {
+ dsc->scan_section = scan_pre_prolog;
+ return CDSC_PROPAGATE;
+ }
+ }
+
+ if (NOT_DSC_LINE(line)) {
+ /* ignore */
+ }
+ else if (IS_DSC(line, "%%BeginPreview")) {
+ /* ignore because we have already processed this section */
+ }
+ else if (IS_DSC(line, "%%BeginDefaults")) {
+ /* ignore because we are in this section */
+ }
+ else if (dsc_is_section(line)) {
+ dsc->enddefaults = DSC_START(dsc);
+ dsc->scan_section = scan_pre_prolog;
+ return CDSC_PROPAGATE;
+ }
+ else if (IS_DSC(line, "%%EndDefaults")) {
+ dsc->id = CDSC_ENDDEFAULTS;
+ dsc->enddefaults = DSC_END(dsc);
+ dsc->scan_section = scan_pre_prolog;
+ return CDSC_OK;
+ }
+ else if (IS_DSC(line, "%%PageMedia:")) {
+ dsc->id = CDSC_PAGEMEDIA;
+ dsc_parse_media(dsc, &dsc->page_media);
+ }
+ else if (IS_DSC(line, "%%PageOrientation:")) {
+ dsc->id = CDSC_PAGEORIENTATION;
+ /* This can override %%Orientation: */
+ if (dsc_parse_orientation(dsc, &(dsc->page_orientation), 18))
+ return CDSC_ERROR;
+ }
+ else if (IS_DSC(line, "%%PageBoundingBox:")) {
+ dsc->id = CDSC_PAGEBOUNDINGBOX;
+ if (dsc_parse_bounding_box(dsc, &(dsc->page_bbox), 18))
+ return CDSC_ERROR;
+ }
+ else if (IS_DSC(line, "%%ViewingOrientation:")) {
+ dsc->id = CDSC_VIEWINGORIENTATION;
+ if (dsc_parse_viewing_orientation(dsc, &dsc->viewing_orientation))
+ return CDSC_ERROR;
+ }
+ else {
+ dsc->id = CDSC_UNKNOWNDSC;
+ /* All other DSC comments are unknown, but not an error */
+ dsc_unknown(dsc);
+ }
+ dsc->enddefaults = DSC_END(dsc);
+ return CDSC_OK;
+}
+
+/* CDSC_RESPONSE_OK and CDSC_RESPONSE_CANCEL mean ignore the
+ * mismatch (default) */
+dsc_private int
+dsc_check_match_prompt(CDSC *dsc, const char *str, int count)
+{
+ if (count != 0) {
+ char buf[MAXSTR+MAXSTR] = "";
+ if (dsc->line_length < (unsigned int)(sizeof(buf)/2-1)) {
+ strncpy(buf, dsc->line, dsc->line_length);
+ buf[dsc->line_length] = '\0';
+ }
+ sprintf(buf+strlen(buf), "\n%%%%Begin%.40s: / %%%%End%.40s\n", str, str);
+ return dsc_error(dsc, CDSC_MESSAGE_BEGIN_END, buf, strlen(buf));
+ }
+ return CDSC_RESPONSE_CANCEL;
+}
+
+dsc_private int
+dsc_check_match_type(CDSC *dsc, const char *str, int count)
+{
+ if (dsc_check_match_prompt(dsc, str, count) == CDSC_RESPONSE_IGNORE_ALL)
+ return CDSC_NOTDSC;
+ return CDSC_OK;
+}
+
+/* complain if Begin/End blocks didn't match */
+/* return non-zero if we should ignore all DSC */
+dsc_private int
+dsc_check_match(CDSC *dsc)
+{
+ int rc = 0;
+ const char *font = "Font";
+ const char *feature = "Feature";
+ const char *resource = "Resource";
+ const char *procset = "ProcSet";
+
+ if (!rc)
+ rc = dsc_check_match_type(dsc, font, dsc->begin_font_count);
+ if (!rc)
+ rc = dsc_check_match_type(dsc, feature, dsc->begin_feature_count);
+ if (!rc)
+ rc = dsc_check_match_type(dsc, resource, dsc->begin_resource_count);
+ if (!rc)
+ rc = dsc_check_match_type(dsc, procset, dsc->begin_procset_count);
+
+ dsc->begin_font_count = 0;
+ dsc->begin_feature_count = 0;
+ dsc->begin_resource_count = 0;
+ dsc->begin_procset_count = 0;
+ return rc;
+}
+
+
+dsc_private int
+dsc_scan_prolog(CDSC *dsc)
+{
+ /* Prolog section ends at */
+ /* %%EndProlog */
+ /* another section */
+ /* Prolog section may start with %%BeginProlog or non-dsc line */
+ char *line = dsc->line;
+ dsc->id = CDSC_OK;
+
+ if (dsc->scan_section == scan_pre_prolog) {
+ if (dsc_is_section(line) && (!IS_DSC(line, "%%BeginProlog"))) {
+ dsc->scan_section = scan_pre_setup;
+ return CDSC_PROPAGATE;
+ }
+ dsc->id = CDSC_BEGINPROLOG;
+ dsc->beginprolog = DSC_START(dsc);
+ dsc->endprolog = DSC_END(dsc);
+ dsc->scan_section = scan_prolog;
+ if (IS_DSC(line, "%%BeginProlog"))
+ return CDSC_OK;
+ }
+
+ if (NOT_DSC_LINE(line)) {
+ /* ignore */
+ }
+ else if (IS_DSC(line, "%%BeginPreview")) {
+ /* ignore because we have already processed this section */
+ }
+ else if (IS_DSC(line, "%%BeginDefaults")) {
+ /* ignore because we have already processed this section */
+ }
+ else if (IS_DSC(line, "%%BeginProlog")) {
+ /* ignore because we are in this section */
+ }
+ else if (dsc_is_section(line)) {
+ dsc->endprolog = DSC_START(dsc);
+ dsc->scan_section = scan_pre_setup;
+ if (dsc_check_match(dsc))
+ return CDSC_NOTDSC;
+ return CDSC_PROPAGATE;
+ }
+ else if (IS_DSC(line, "%%EndProlog")) {
+ dsc->id = CDSC_ENDPROLOG;
+ dsc->endprolog = DSC_END(dsc);
+ dsc->scan_section = scan_pre_setup;
+ if (dsc_check_match(dsc))
+ return CDSC_NOTDSC;
+ return CDSC_OK;
+ }
+ else if (IS_DSC(line, "%%BeginFont:")) {
+ dsc->id = CDSC_BEGINFONT;
+ /* ignore Begin/EndFont, apart form making sure */
+ /* that they are matched. */
+ dsc->begin_font_count++;
+ }
+ else if (IS_DSC(line, "%%EndFont")) {
+ dsc->id = CDSC_ENDFONT;
+ dsc->begin_font_count--;
+ }
+ else if (IS_DSC(line, "%%BeginFeature:")) {
+ dsc->id = CDSC_BEGINFEATURE;
+ /* ignore Begin/EndFeature, apart form making sure */
+ /* that they are matched. */
+ dsc->begin_feature_count++;
+ }
+ else if (IS_DSC(line, "%%EndFeature")) {
+ dsc->id = CDSC_ENDFEATURE;
+ dsc->begin_feature_count--;
+ }
+ else if (IS_DSC(line, "%%BeginResource:")) {
+ dsc->id = CDSC_BEGINRESOURCE;
+ /* ignore Begin/EndResource, apart form making sure */
+ /* that they are matched. */
+ dsc->begin_resource_count++;
+ }
+ else if (IS_DSC(line, "%%EndResource")) {
+ dsc->id = CDSC_ENDRESOURCE;
+ dsc->begin_resource_count--;
+ }
+ else if (IS_DSC(line, "%%BeginProcSet:")) {
+ dsc->id = CDSC_BEGINPROCSET;
+ /* ignore Begin/EndProcSet, apart form making sure */
+ /* that they are matched. */
+ dsc->begin_procset_count++;
+ }
+ else if (IS_DSC(line, "%%EndProcSet")) {
+ dsc->id = CDSC_ENDPROCSET;
+ dsc->begin_procset_count--;
+ }
+ else {
+ /* All other DSC comments are unknown, but not an error */
+ dsc->id = CDSC_UNKNOWNDSC;
+ dsc_unknown(dsc);
+ }
+
+ dsc->endprolog = DSC_END(dsc);
+ return CDSC_OK;
+}
+
+dsc_private int
+dsc_scan_setup(CDSC *dsc)
+{
+ /* Setup section ends at */
+ /* %%EndSetup */
+ /* another section */
+ /* Setup section must start with %%BeginSetup */
+
+ char *line = dsc->line;
+ dsc->id = CDSC_OK;
+
+ if (dsc->scan_section == scan_pre_setup) {
+ if (IS_BLANK(line))
+ return CDSC_OK; /* ignore blank lines before setup */
+ else if (IS_DSC(line, "%%BeginSetup")) {
+ dsc->id = CDSC_BEGINSETUP;
+ dsc->beginsetup = DSC_START(dsc);
+ dsc->endsetup = DSC_END(dsc);
+ dsc->scan_section = scan_setup;
+ return CDSC_OK;
+ }
+ else {
+ dsc->scan_section = scan_pre_pages;
+ return CDSC_PROPAGATE;
+ }
+ }
+
+ if (NOT_DSC_LINE(line)) {
+ /* ignore */
+ }
+ else if (IS_DSC(line, "%%BeginPreview")) {
+ /* ignore because we have already processed this section */
+ }
+ else if (IS_DSC(line, "%%BeginDefaults")) {
+ /* ignore because we have already processed this section */
+ }
+ else if (IS_DSC(line, "%%BeginProlog")) {
+ /* ignore because we have already processed this section */
+ }
+ else if (IS_DSC(line, "%%BeginSetup")) {
+ /* ignore because we are in this section */
+ }
+ else if (dsc_is_section(line)) {
+ dsc->endsetup = DSC_START(dsc);
+ dsc->scan_section = scan_pre_pages;
+ if (dsc_check_match(dsc))
+ return CDSC_NOTDSC;
+ return CDSC_PROPAGATE;
+ }
+ else if (IS_DSC(line, "%%EndSetup")) {
+ dsc->id = CDSC_ENDSETUP;
+ dsc->endsetup = DSC_END(dsc);
+ dsc->scan_section = scan_pre_pages;
+ if (dsc_check_match(dsc))
+ return CDSC_NOTDSC;
+ return CDSC_OK;
+ }
+ else if (IS_DSC(line, "%%BeginFeature:")) {
+ dsc->id = CDSC_BEGINFEATURE;
+ /* ignore Begin/EndFeature, apart form making sure */
+ /* that they are matched. */
+ dsc->begin_feature_count++;
+ }
+ else if (IS_DSC(line, "%%EndFeature")) {
+ dsc->id = CDSC_ENDFEATURE;
+ dsc->begin_feature_count--;
+ }
+ else if (IS_DSC(line, "%%Feature:")) {
+ dsc->id = CDSC_FEATURE;
+ /* ignore */
+ }
+ else if (IS_DSC(line, "%%BeginResource:")) {
+ dsc->id = CDSC_BEGINRESOURCE;
+ /* ignore Begin/EndResource, apart form making sure */
+ /* that they are matched. */
+ dsc->begin_resource_count++;
+ }
+ else if (IS_DSC(line, "%%EndResource")) {
+ dsc->id = CDSC_ENDRESOURCE;
+ dsc->begin_resource_count--;
+ }
+ else if (IS_DSC(line, "%%PaperColor:")) {
+ dsc->id = CDSC_PAPERCOLOR;
+ /* ignore */
+ }
+ else if (IS_DSC(line, "%%PaperForm:")) {
+ dsc->id = CDSC_PAPERFORM;
+ /* ignore */
+ }
+ else if (IS_DSC(line, "%%PaperWeight:")) {
+ dsc->id = CDSC_PAPERWEIGHT;
+ /* ignore */
+ }
+ else if (IS_DSC(line, "%%PaperSize:")) {
+ /* DSC 2.1 */
+ GSBOOL found_media = FALSE;
+ int i;
+ int n = 12;
+ char buf[MAXSTR];
+ buf[0] = '\0';
+ dsc->id = CDSC_PAPERSIZE;
+ dsc_copy_string(buf, sizeof(buf)-1, dsc->line+n, dsc->line_length-n,
+ NULL);
+ for (i=0; i<(int)dsc->media_count; i++) {
+ if (dsc->media[i] && dsc->media[i]->name &&
+ (dsc_stricmp(buf, dsc->media[i]->name)==0)) {
+ dsc->page_media = dsc->media[i];
+ found_media = TRUE;
+ break;
+ }
+ }
+ if (!found_media) {
+ /* It didn't match %%DocumentPaperSizes: */
+ /* Try our known media */
+ const CDSCMEDIA *m = dsc_known_media;
+ while (m->name) {
+ if (dsc_stricmp(buf, m->name)==0) {
+ dsc->page_media = m;
+ break;
+ }
+ m++;
+ }
+ if (m->name == NULL)
+ dsc_unknown(dsc);
+ }
+ }
+ else {
+ /* All other DSC comments are unknown, but not an error */
+ dsc->id = CDSC_UNKNOWNDSC;
+ dsc_unknown(dsc);
+ }
+
+ dsc->endsetup = DSC_END(dsc);
+ return CDSC_OK;
+}
+
+dsc_private int
+dsc_scan_page(CDSC *dsc)
+{
+ /* Page section ends at */
+ /* %%Page */
+ /* %%Trailer */
+ /* %%EOF */
+ char *line = dsc->line;
+ dsc->id = CDSC_OK;
+
+ if (dsc->scan_section == scan_pre_pages) {
+ if (IS_DSC(line, "%%Page:")) {
+ dsc->scan_section = scan_pages;
+ /* fall through */
+ }
+ else {
+ /* %%Page: didn't follow %%EndSetup
+ * Keep reading until reach %%Page or %%Trailer
+ * and add it to previous section.
+ */
+ unsigned long *last;
+ if (dsc->endsetup != 0)
+ last = &dsc->endsetup;
+ else if (dsc->endprolog != 0)
+ last = &dsc->endprolog;
+ else if (dsc->enddefaults != 0)
+ last = &dsc->enddefaults;
+ else if (dsc->endpreview != 0)
+ last = &dsc->endpreview;
+ else if (dsc->endcomments != 0)
+ last = &dsc->endcomments;
+ else
+ last = &dsc->begincomments;
+ *last = DSC_START(dsc);
+ if (IS_DSC(line, "%%Trailer") || IS_DSC(line, "%%EOF")) {
+ dsc->scan_section = scan_pre_trailer;
+ return CDSC_PROPAGATE;
+ }
+ return CDSC_OK;
+ }
+ }
+
+ if (NOT_DSC_LINE(line)) {
+ /* ignore */
+ }
+ else if (IS_DSC(line, "%%Page:")) {
+ dsc->id = CDSC_PAGE;
+ if (dsc->page_count) {
+ dsc->page[dsc->page_count-1].end = DSC_START(dsc);
+ if (dsc_check_match(dsc))
+ return CDSC_NOTDSC;
+ }
+
+ if (dsc_parse_page(dsc) != 0)
+ return CDSC_ERROR;
+
+ return CDSC_OK;
+ }
+ else if (IS_DSC(line, "%%BeginPreview")) {
+ /* ignore because we have already processed this section */
+ }
+ else if (IS_DSC(line, "%%BeginDefaults")) {
+ /* ignore because we have already processed this section */
+ }
+ else if (IS_DSC(line, "%%BeginProlog")) {
+ /* ignore because we have already processed this section */
+ }
+ else if (IS_DSC(line, "%%BeginSetup")) {
+ /* ignore because we have already processed this section */
+ }
+ else if (dsc_is_section(line)) {
+ if (IS_DSC(line, "%%Trailer")) {
+ dsc->page[dsc->page_count-1].end = DSC_START(dsc);
+ if (dsc->file_length) {
+ if ((!dsc->doseps &&
+ ((DSC_END(dsc) + 32768) < dsc->file_length)) ||
+ ((dsc->doseps) &&
+ ((DSC_END(dsc) + 32768) < dsc->doseps_end))) {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_EARLY_TRAILER,
+ dsc->line, dsc->line_length);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ /* ignore early trailer */
+ break;
+ case CDSC_RESPONSE_CANCEL:
+ /* this is the trailer */
+ dsc->scan_section = scan_pre_trailer;
+ if (dsc_check_match(dsc))
+ return CDSC_NOTDSC;
+ return CDSC_PROPAGATE;
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+ else {
+ dsc->scan_section = scan_pre_trailer;
+ if (dsc_check_match(dsc))
+ return CDSC_NOTDSC;
+ return CDSC_PROPAGATE;
+ }
+ }
+ else {
+ dsc->scan_section = scan_pre_trailer;
+ if (dsc_check_match(dsc))
+ return CDSC_NOTDSC;
+ return CDSC_PROPAGATE;
+ }
+ }
+ else if (IS_DSC(line, "%%EOF")) {
+ dsc->page[dsc->page_count-1].end = DSC_START(dsc);
+ if (dsc->file_length) {
+ if ((DSC_END(dsc)+100 < dsc->file_length) ||
+ (dsc->doseps && (DSC_END(dsc) + 100 < dsc->doseps_end))) {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_EARLY_EOF,
+ dsc->line, dsc->line_length);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ /* %%EOF is wrong, ignore it */
+ break;
+ case CDSC_RESPONSE_CANCEL:
+ /* %%EOF is correct */
+ dsc->scan_section = scan_eof;
+ dsc->eof = TRUE;
+ if (dsc_check_match(dsc))
+ return CDSC_NOTDSC;
+ return CDSC_PROPAGATE;
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+ }
+ else {
+ /* ignore it */
+ if (dsc_check_match(dsc))
+ return CDSC_NOTDSC;
+ return CDSC_OK;
+ }
+ }
+ else {
+ /* Section comment, probably from a badly */
+ /* encapsulated EPS file. */
+ int rc = dsc_error(dsc, CDSC_MESSAGE_BAD_SECTION,
+ dsc->line, dsc->line_length);
+ if (rc == CDSC_RESPONSE_IGNORE_ALL)
+ return CDSC_NOTDSC;
+ }
+ }
+ else if (IS_DSC(line, "%%PageTrailer")) {
+ dsc->id = CDSC_PAGETRAILER;
+ /* ignore */
+ }
+ else if (IS_DSC(line, "%%BeginPageSetup")) {
+ dsc->id = CDSC_BEGINPAGESETUP;
+ /* ignore */
+ }
+ else if (IS_DSC(line, "%%EndPageSetup")) {
+ dsc->id = CDSC_ENDPAGESETUP;
+ /* ignore */
+ }
+ else if (IS_DSC(line, "%%PageMedia:")) {
+ dsc->id = CDSC_PAGEMEDIA;
+ dsc_parse_media(dsc, &(dsc->page[dsc->page_count-1].media));
+ }
+ else if (IS_DSC(line, "%%PaperColor:")) {
+ dsc->id = CDSC_PAPERCOLOR;
+ /* ignore */
+ }
+ else if (IS_DSC(line, "%%PaperForm:")) {
+ dsc->id = CDSC_PAPERFORM;
+ /* ignore */
+ }
+ else if (IS_DSC(line, "%%PaperWeight:")) {
+ dsc->id = CDSC_PAPERWEIGHT;
+ /* ignore */
+ }
+ else if (IS_DSC(line, "%%PaperSize:")) {
+ /* DSC 2.1 */
+ GSBOOL found_media = FALSE;
+ int i;
+ int n = 12;
+ char buf[MAXSTR];
+ buf[0] = '\0';
+ dsc_copy_string(buf, sizeof(buf)-1, dsc->line+n,
+ dsc->line_length-n, NULL);
+ for (i=0; i<(int)dsc->media_count; i++) {
+ if (dsc->media[i] && dsc->media[i]->name &&
+ (dsc_stricmp(buf, dsc->media[i]->name)==0)) {
+ dsc->page_media = dsc->media[i];
+ found_media = TRUE;
+ break;
+ }
+ }
+ if (!found_media) {
+ /* It didn't match %%DocumentPaperSizes: */
+ /* Try our known media */
+ const CDSCMEDIA *m = dsc_known_media;
+ while (m->name) {
+ if (dsc_stricmp(buf, m->name)==0) {
+ dsc->page[dsc->page_count-1].media = m;
+ break;
+ }
+ m++;
+ }
+ if (m->name == NULL)
+ dsc_unknown(dsc);
+ }
+ }
+ else if (IS_DSC(line, "%%PageOrientation:")) {
+ dsc->id = CDSC_PAGEORIENTATION;
+ if (dsc_parse_orientation(dsc,
+ &(dsc->page[dsc->page_count-1].orientation) ,18))
+ return CDSC_NOTDSC;
+ }
+ else if (IS_DSC(line, "%%PageBoundingBox:")) {
+ dsc->id = CDSC_PAGEBOUNDINGBOX;
+ if (dsc_parse_bounding_box(dsc, &dsc->page[dsc->page_count-1].bbox, 18))
+ return CDSC_NOTDSC;
+ }
+ else if (IS_DSC(line, "%%ViewingOrientation:")) {
+ dsc->id = CDSC_VIEWINGORIENTATION;
+ if (dsc_parse_viewing_orientation(dsc,
+ &dsc->page[dsc->page_count-1].viewing_orientation))
+ return CDSC_ERROR;
+ }
+ else if (IS_DSC(line, "%%BeginFont:")) {
+ dsc->id = CDSC_BEGINFONT;
+ /* ignore Begin/EndFont, apart form making sure */
+ /* that they are matched. */
+ dsc->begin_font_count++;
+ }
+ else if (IS_DSC(line, "%%EndFont")) {
+ dsc->id = CDSC_BEGINFONT;
+ dsc->begin_font_count--;
+ }
+ else if (IS_DSC(line, "%%BeginFeature:")) {
+ dsc->id = CDSC_BEGINFEATURE;
+ /* ignore Begin/EndFeature, apart form making sure */
+ /* that they are matched. */
+ dsc->begin_feature_count++;
+ }
+ else if (IS_DSC(line, "%%EndFeature")) {
+ dsc->id = CDSC_ENDFEATURE;
+ dsc->begin_feature_count--;
+ }
+ else if (IS_DSC(line, "%%BeginResource:")) {
+ dsc->id = CDSC_BEGINRESOURCE;
+ /* ignore Begin/EndResource, apart form making sure */
+ /* that they are matched. */
+ dsc->begin_resource_count++;
+ }
+ else if (IS_DSC(line, "%%EndResource")) {
+ dsc->id = CDSC_ENDRESOURCE;
+ dsc->begin_resource_count--;
+ }
+ else if (IS_DSC(line, "%%BeginProcSet:")) {
+ dsc->id = CDSC_BEGINPROCSET;
+ /* ignore Begin/EndProcSet, apart form making sure */
+ /* that they are matched. */
+ dsc->begin_procset_count++;
+ }
+ else if (IS_DSC(line, "%%EndProcSet")) {
+ dsc->id = CDSC_ENDPROCSET;
+ dsc->begin_procset_count--;
+ }
+ else if (IS_DSC(line, "%%IncludeFont:")) {
+ dsc->id = CDSC_INCLUDEFONT;
+ /* ignore */
+ }
+ else {
+ /* All other DSC comments are unknown, but not an error */
+ dsc->id = CDSC_UNKNOWNDSC;
+ dsc_unknown(dsc);
+ }
+
+ dsc->page[dsc->page_count-1].end = DSC_END(dsc);
+ return CDSC_OK;
+}
+
+/* Valid Trailer comments are
+ * %%Trailer
+ * %%EOF
+ * or the following deferred with (atend)
+ * %%BoundingBox:
+ * %%DocumentCustomColors:
+ * %%DocumentFiles:
+ * %%DocumentFonts:
+ * %%DocumentNeededFiles:
+ * %%DocumentNeededFonts:
+ * %%DocumentNeededProcSets:
+ * %%DocumentNeededResources:
+ * %%DocumentProcSets:
+ * %%DocumentProcessColors:
+ * %%DocumentSuppliedFiles:
+ * %%DocumentSuppliedFonts:
+ * %%DocumentSuppliedProcSets:
+ * %%DocumentSuppliedResources:
+ * %%Orientation:
+ * %%Pages:
+ * %%PageOrder:
+ *
+ * Our supported subset is
+ * %%Trailer
+ * %%EOF
+ * %%BoundingBox:
+ * %%Orientation:
+ * %%Pages:
+ * %%PageOrder:
+ * In addition to these, we support
+ * %%DocumentMedia:
+ *
+ * A %%PageTrailer can have the following:
+ * %%PageBoundingBox:
+ * %%PageCustomColors:
+ * %%PageFiles:
+ * %%PageFonts:
+ * %%PageOrientation:
+ * %%PageProcessColors:
+ * %%PageResources:
+ */
+
+dsc_private int
+dsc_scan_trailer(CDSC *dsc)
+{
+ /* Trailer section start at */
+ /* %%Trailer */
+ /* and ends at */
+ /* %%EOF */
+ char *line = dsc->line;
+ GSBOOL continued = FALSE;
+ dsc->id = CDSC_OK;
+
+ if (dsc->scan_section == scan_pre_trailer) {
+ if (IS_DSC(line, "%%Trailer")) {
+ dsc->id = CDSC_TRAILER;
+ dsc->begintrailer = DSC_START(dsc);
+ dsc->endtrailer = DSC_END(dsc);
+ dsc->scan_section = scan_trailer;
+ return CDSC_OK;
+ }
+ else if (IS_DSC(line, "%%EOF")) {
+ dsc->id = CDSC_EOF;
+ dsc->begintrailer = DSC_START(dsc);
+ dsc->endtrailer = DSC_END(dsc);
+ dsc->scan_section = scan_trailer;
+ /* Continue, in case we found %%EOF in an embedded document */
+ return CDSC_OK;
+ }
+ else {
+ /* %%Page: didn't follow %%EndSetup
+ * Keep reading until reach %%Page or %%Trailer
+ * and add it to setup section
+ */
+ /* append to previous section */
+ if (dsc->beginsetup)
+ dsc->endsetup = DSC_END(dsc);
+ else if (dsc->beginprolog)
+ dsc->endprolog = DSC_END(dsc);
+ else {
+ /* horribly confused */
+ }
+ return CDSC_OK;
+ }
+ }
+
+ /* Handle continuation lines.
+ * See comment above about our restrictive processing of
+ * continuation lines
+ */
+ if (IS_DSC(line, "%%+")) {
+ line = dsc->last_line;
+ continued = TRUE;
+ }
+ else
+ dsc_save_line(dsc);
+
+ if (NOT_DSC_LINE(line)) {
+ /* ignore */
+ }
+ else if (IS_DSC(dsc->line, "%%EOF")) {
+ /* Keep scanning, in case we have a false trailer */
+ dsc->id = CDSC_EOF;
+ }
+ else if (IS_DSC(dsc->line, "%%Trailer")) {
+ /* Cope with no pages with code after setup and before trailer. */
+ /* Last trailer is the correct one. */
+ dsc->id = CDSC_TRAILER;
+ dsc->begintrailer = DSC_START(dsc);
+ }
+ else if (IS_DSC(line, "%%Pages:")) {
+ dsc->id = CDSC_PAGES;
+ if (dsc_parse_pages(dsc) != 0)
+ return CDSC_ERROR;
+ }
+ else if (IS_DSC(line, "%%BoundingBox:")) {
+ dsc->id = CDSC_BOUNDINGBOX;
+ if (dsc_parse_bounding_box(dsc, &(dsc->bbox), continued ? 3 : 14))
+ return CDSC_ERROR;
+ }
+ else if (IS_DSC(line, "%%HiResBoundingBox:")) {
+ dsc->id = CDSC_HIRESBOUNDINGBOX;
+ if (dsc_parse_float_bounding_box(dsc, &(dsc->hires_bbox),
+ continued ? 3 : 19))
+ return CDSC_ERROR;
+ }
+ else if (IS_DSC(line, "%%CropBox:")) {
+ dsc->id = CDSC_CROPBOX;
+ if (dsc_parse_float_bounding_box(dsc, &(dsc->crop_box),
+ continued ? 3 : 10))
+ return CDSC_ERROR;
+ }
+ else if (IS_DSC(line, "%%Orientation:")) {
+ dsc->id = CDSC_ORIENTATION;
+ if (dsc_parse_orientation(dsc, &(dsc->page_orientation), continued ? 3 : 14))
+ return CDSC_ERROR;
+ }
+ else if (IS_DSC(line, "%%PageOrder:")) {
+ dsc->id = CDSC_PAGEORDER;
+ if (dsc_parse_order(dsc))
+ return CDSC_ERROR;
+ }
+ else if (IS_DSC(line, "%%DocumentMedia:")) {
+ dsc->id = CDSC_DOCUMENTMEDIA;
+ if (dsc_parse_document_media(dsc))
+ return CDSC_ERROR;
+ }
+ else if (IS_DSC(dsc->line, "%%Page:")) {
+ /* This should not occur in the trailer, but we might see
+ * this if a document has been incorrectly embedded.
+ */
+ int rc = dsc_error(dsc, CDSC_MESSAGE_PAGE_IN_TRAILER,
+ dsc->line, dsc->line_length);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ /* Assume that we are really in the previous */
+ /* page, not the trailer */
+ dsc->scan_section = scan_pre_pages;
+ if (dsc->page_count)
+ dsc->page[dsc->page_count-1].end = DSC_START(dsc);
+ return CDSC_PROPAGATE; /* try again */
+ case CDSC_RESPONSE_CANCEL:
+ /* ignore pages in trailer */
+ break;
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+ else if (IS_DSC(line, "%%DocumentNeededFonts:")) {
+ dsc->id = CDSC_DOCUMENTNEEDEDFONTS;
+ /* ignore */
+ }
+ else if (IS_DSC(line, "%%DocumentSuppliedFonts:")) {
+ dsc->id = CDSC_DOCUMENTSUPPLIEDFONTS;
+ /* ignore */
+ }
+ else {
+ /* All other DSC comments are unknown, but not an error */
+ dsc->id = CDSC_UNKNOWNDSC;
+ dsc_unknown(dsc);
+ }
+
+ dsc->endtrailer = DSC_END(dsc);
+ return CDSC_OK;
+}
+
+
+dsc_private char *
+dsc_alloc_string(CDSC *dsc, const char *str, int len)
+{
+ char *p;
+ if (dsc->string_head == NULL) {
+ dsc->string_head = (CDSCSTRING *)dsc_memalloc(dsc, sizeof(CDSCSTRING));
+ if (dsc->string_head == NULL)
+ return NULL; /* no memory */
+ dsc->string = dsc->string_head;
+ dsc->string->next = NULL;
+ dsc->string->data = (char *)dsc_memalloc(dsc, CDSC_STRING_CHUNK);
+ if (dsc->string->data == NULL) {
+ dsc_reset(dsc);
+ return NULL; /* no memory */
+ }
+ dsc->string->index = 0;
+ dsc->string->length = CDSC_STRING_CHUNK;
+ }
+ if ( dsc->string->index + len + 1 > dsc->string->length) {
+ /* allocate another string block */
+ CDSCSTRING *newstring = (CDSCSTRING *)dsc_memalloc(dsc, sizeof(CDSCSTRING));
+ if (newstring == NULL) {
+ dsc_debug_print(dsc, "Out of memory\n");
+ return NULL;
+ }
+ newstring->next = NULL;
+ newstring->length = 0;
+ newstring->index = 0;
+ newstring->data = (char *)dsc_memalloc(dsc, CDSC_STRING_CHUNK);
+ if (newstring->data == NULL) {
+ dsc_memfree(dsc, newstring);
+ dsc_debug_print(dsc, "Out of memory\n");
+ return NULL; /* no memory */
+ }
+ newstring->length = CDSC_STRING_CHUNK;
+ dsc->string->next = newstring;
+ dsc->string = newstring;
+ }
+ if ( dsc->string->index + len + 1 > dsc->string->length)
+ return NULL; /* failed */
+ p = dsc->string->data + dsc->string->index;
+ memcpy(p, str, len);
+ *(p+len) = '\0';
+ dsc->string->index += len + 1;
+ return p;
+}
+
+/* store line, ignoring leading spaces */
+dsc_private char *
+dsc_add_line(CDSC *dsc, const char *line, unsigned int len)
+{
+ char *newline;
+ unsigned int i;
+ while (len && (IS_WHITE(*line))) {
+ len--;
+ line++;
+ }
+ newline = dsc_alloc_string(dsc, line, len);
+ if (newline == NULL)
+ return NULL;
+
+ for (i=0; i<len; i++) {
+ if (newline[i] == '\r') {
+ newline[i]='\0';
+ break;
+ }
+ if (newline[i] == '\n') {
+ newline[i]='\0';
+ break;
+ }
+ }
+ return newline;
+}
+
+
+/* Copy string on line to new allocated string str */
+/* String is always null terminated */
+/* String is no longer than len */
+/* Return pointer to string */
+/* Store number of used characters from line */
+/* Don't copy enclosing () */
+dsc_private char *
+dsc_copy_string(char *str, unsigned int slen, char *line,
+ unsigned int len, unsigned int *offset)
+{
+ int quoted = FALSE;
+ int instring=0;
+ unsigned int newlength = 0;
+ unsigned int i = 0;
+ unsigned char ch;
+ if (len > slen)
+ len = slen-1;
+ while ( (i<len) && IS_WHITE(line[i]))
+ i++; /* skip leading spaces */
+ if (line[i]=='(') {
+ quoted = TRUE;
+ instring++;
+ i++; /* don't copy outside () */
+ }
+ while (i < len) {
+ str[newlength] = ch = line[i];
+ i++;
+ if (quoted) {
+ if (ch == '(')
+ instring++;
+ if (ch == ')')
+ instring--;
+ if (instring==0)
+ break;
+ }
+ else if (ch == ' ')
+ break;
+
+ if (ch == '\r')
+ break;
+ if (ch == '\n')
+ break;
+ else if ( (ch == '\\') && (i+1 < len) ) {
+ ch = line[i];
+ if ((ch >= '0') && (ch <= '9')) {
+ /* octal coded character */
+ int j = 3;
+ ch = 0;
+ while (j && (i < len) && line[i]>='0' && line[i]<='7') {
+ ch = (unsigned char)((ch<<3) + (line[i]-'0'));
+ i++;
+ j--;
+ }
+ str[newlength] = ch;
+ }
+ else if (ch == '(') {
+ str[newlength] = ch;
+ i++;
+ }
+ else if (ch == ')') {
+ str[newlength] = ch;
+ i++;
+ }
+ else if (ch == 'b') {
+ str[newlength] = '\b';
+ i++;
+ }
+ else if (ch == 'f') {
+ str[newlength] = '\b';
+ i++;
+ }
+ else if (ch == 'n') {
+ str[newlength] = '\n';
+ i++;
+ }
+ else if (ch == 'r') {
+ str[newlength] = '\r';
+ i++;
+ }
+ else if (ch == 't') {
+ str[newlength] = '\t';
+ i++;
+ }
+ else if (ch == '\\') {
+ str[newlength] = '\\';
+ i++;
+ }
+ }
+ newlength++;
+ }
+ str[newlength] = '\0';
+ if (offset != (unsigned int *)NULL)
+ *offset = i;
+ return str;
+}
+
+dsc_private int
+dsc_get_int(const char *line, unsigned int len, unsigned int *offset)
+{
+ char newline[MAXSTR];
+ int newlength = 0;
+ unsigned int i = 0;
+ unsigned char ch;
+
+ len = min((size_t) len, (size_t) sizeof(newline)-1);
+ while ((i<len) && IS_WHITE(line[i]))
+ i++; /* skip leading spaces */
+ while (i < len) {
+ newline[newlength] = ch = line[i];
+ if (!(isdigit(ch) || (ch=='-') || (ch=='+')))
+ break; /* not part of an integer number */
+ i++;
+ newlength++;
+ }
+ while ((i<len) && IS_WHITE(line[i]))
+ i++; /* skip trailing spaces */
+ newline[newlength] = '\0';
+ if (offset != (unsigned int *)NULL)
+ *offset = i;
+ return atoi(newline);
+}
+
+dsc_private float
+dsc_get_real(const char *line, unsigned int len, unsigned int *offset)
+{
+ char newline[MAXSTR];
+ int newlength = 0;
+ unsigned int i = 0;
+ unsigned char ch;
+
+ len = min((size_t) len, (size_t) sizeof(newline)-1);
+ while ((i<len) && IS_WHITE(line[i]))
+ i++; /* skip leading spaces */
+ while (i < len) {
+ newline[newlength] = ch = line[i];
+ if (!(isdigit(ch) || (ch=='.') || (ch=='-') || (ch=='+')
+ || (ch=='e') || (ch=='E')))
+ break; /* not part of a real number */
+ i++;
+ newlength++;
+ }
+ while ((i<len) && IS_WHITE(line[i]))
+ i++; /* skip trailing spaces */
+
+ newline[newlength] = '\0';
+
+ if (offset != (unsigned int *)NULL)
+ *offset = i;
+ return (float)atof(newline);
+}
+
+dsc_private int
+dsc_stricmp(const char *s, const char *t)
+{
+ while (toupper(*s) == toupper(*t)) {
+ if (*s == '\0')
+ return 0;
+ s++;
+ t++;
+ }
+ return (toupper(*s) - toupper(*t));
+}
+
+
+dsc_private int
+dsc_parse_page(CDSC *dsc)
+{
+ char *p;
+ unsigned int i;
+ char page_label[MAXSTR];
+ char *pl;
+ int page_ordinal;
+ int page_number;
+
+ p = dsc->line + 7;
+ pl = dsc_copy_string(page_label, sizeof(page_label)-1, p, dsc->line_length-7, &i);
+ if (pl == NULL)
+ return CDSC_ERROR;
+ p += i;
+ page_ordinal = atoi(p);
+
+ if ( (page_ordinal == 0) || (strlen(page_label) == 0) ||
+ (dsc->page_count &&
+ (page_ordinal != dsc->page[dsc->page_count-1].ordinal+1)) ) {
+ int rc = dsc_error(dsc, CDSC_MESSAGE_PAGE_ORDINAL, dsc->line,
+ dsc->line_length);
+ switch (rc) {
+ case CDSC_RESPONSE_OK:
+ /* ignore this page */
+ return CDSC_OK;
+ case CDSC_RESPONSE_CANCEL:
+ /* accept the page */
+ break;
+ case CDSC_RESPONSE_IGNORE_ALL:
+ return CDSC_NOTDSC;
+ }
+ }
+
+ page_number = dsc->page_count;
+ dsc_add_page(dsc, page_ordinal, page_label);
+ dsc->page[page_number].begin = DSC_START(dsc);
+ dsc->page[page_number].end = DSC_START(dsc);
+
+ if (dsc->page[page_number].label == NULL)
+ return CDSC_ERROR; /* no memory */
+
+ return CDSC_OK;
+}
+
+
+
+/* DSC error reporting */
+
+void
+dsc_debug_print(CDSC *dsc, const char *str)
+{
+ if (dsc->debug_print_fn)
+ dsc->debug_print_fn(dsc->caller_data, str);
+}
+
+
+/* Display a message about a problem with the DSC comments.
+ *
+ * explanation = an index to to a multiline explanation in dsc_message[]
+ * line = pointer to the offending DSC line (if any)
+ * return code =
+ * CDSC_RESPONSE_OK DSC was wrong, make a guess about what
+ * was really meant.
+ * CDSC_RESPONSE_CANCEL Assume DSC was correct, ignore if it
+ * is misplaced.
+ * CDSC_RESPONSE_IGNORE_ALL Ignore all DSC.
+ */
+/* Silent operation. Don't display errors. */
+dsc_private int
+dsc_error(CDSC *dsc, unsigned int explanation,
+ char *line, unsigned int line_len)
+{
+ /* if error function provided, use it */
+ if (dsc->dsc_error_fn)
+ return dsc->dsc_error_fn(dsc->caller_data, dsc,
+ explanation, line, line_len);
+
+ /* treat DSC as being correct */
+ return CDSC_RESPONSE_CANCEL;
+}
+
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/dscparse.h b/kghostview/dscparse.h
new file mode 100644
index 00000000..10d2746c
--- /dev/null
+++ b/kghostview/dscparse.h
@@ -0,0 +1,473 @@
+/* Copyright (C) 2000-2001, Ghostgum Software Pty Ltd. All rights reserved.
+
+ This file is part of GSview.
+
+ This file is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
+ to anyone for the consequences of using it or for whether it serves any
+ particular purpose or works at all, unless he says so in writing. Refer
+ to the GNU General Public Licence for full details.
+
+ Everyone is granted permission to copy, modify and redistribute this
+ file, but only under the conditions described in the GNU General
+ Public Licence. A copy of this license is supposed to have been given
+ to you along with this file so you can know your rights and
+ responsibilities. It should be in a file named COPYING. Among other
+ things, the copyright notice and this notice must be preserved on all
+ copies.
+*/
+
+/* $Id$ */
+
+/* dscparse.h */
+/* Interface for the DSC parser. */
+
+#ifndef _DSCPARSE_H_
+#define _DSCPARSE_H_
+
+/* Some local types that may need modification */
+typedef bool GSBOOL;
+typedef unsigned long GSDWORD; /* must be at least 32 bits */
+typedef unsigned int GSWORD; /* must be at least 16 bits */
+
+#ifndef FALSE
+# define FALSE ((GSBOOL)0)
+# define TRUE ((GSBOOL)(!FALSE))
+#endif
+
+#ifndef dsc_private
+# ifdef private
+# define dsc_private private
+# else
+# define dsc_private static
+# endif
+#endif
+
+/* macros to allow conversion of function declarations to K&R */
+#ifndef P0
+#define P0() void
+#define P1(t1) t1
+#define P2(t1,t2) t1,t2
+#define P3(t1,t2,t3) t1,t2,t3
+#define P4(t1,t2,t3,t4) t1,t2,t3,t4
+#define P5(t1,t2,t3,t4,t5) t1,t2,t3,t4,t5
+#define P6(t1,t2,t3,t4,t5,t6) t1,t2,t3,t4,t5,t6
+#endif
+
+/* maximum legal length of lines in a DSC compliant file */
+#define DSC_LINE_LENGTH 255
+
+/* memory for strings is allocated in chunks of this length */
+#define CDSC_STRING_CHUNK 4096
+
+/* page array is allocated in chunks of this many pages */
+#define CDSC_PAGE_CHUNK 128
+
+/* buffer length for storing lines passed to dsc_scan_data() */
+/* must be at least 2 * DSC_LINE_LENGTH */
+/* We choose 8192 as twice the length passed to us by GSview */
+#define CDSC_DATA_LENGTH 8192
+
+/* Return codes from dsc_scan_data()
+ * < 0 = error
+ * >=0 = OK
+ *
+ * -1 = error, usually insufficient memory.
+ * 0-9 = normal
+ * 10-99 = internal codes, should not be seen.
+ * 100-999 = identifier of last DSC comment processed.
+ */
+
+typedef enum {
+ CDSC_ERROR = -1, /* Fatal error, usually insufficient memory */
+
+ CDSC_OK = 0, /* OK, no DSC comment found */
+ CDSC_NOTDSC = 1, /* Not DSC, or DSC is being ignored */
+
+/* Any section */
+ CDSC_UNKNOWNDSC = 100, /* DSC comment not recognised */
+
+/* Header section */
+ CDSC_PSADOBE = 200, /* %!PS-Adobe- */
+ CDSC_BEGINCOMMENTS = 201, /* %%BeginComments */
+ CDSC_ENDCOMMENTS = 202, /* %%EndComments */
+ CDSC_PAGES = 203, /* %%Pages: */
+ CDSC_CREATOR = 204, /* %%Creator: */
+ CDSC_CREATIONDATE = 205, /* %%CreationDate: */
+ CDSC_TITLE = 206, /* %%Title: */
+ CDSC_FOR = 207, /* %%For: */
+ CDSC_LANGUAGELEVEL = 208, /* %%LanguageLevel: */
+ CDSC_BOUNDINGBOX = 209, /* %%BoundingBox: */
+ CDSC_ORIENTATION = 210, /* %%Orientation: */
+ CDSC_PAGEORDER = 211, /* %%PageOrder: */
+ CDSC_DOCUMENTMEDIA = 212, /* %%DocumentMedia: */
+ CDSC_DOCUMENTPAPERSIZES = 213, /* %%DocumentPaperSizes: */
+ CDSC_DOCUMENTPAPERFORMS = 214, /* %%DocumentPaperForms: */
+ CDSC_DOCUMENTPAPERCOLORS = 215, /* %%DocumentPaperColors: */
+ CDSC_DOCUMENTPAPERWEIGHTS = 216, /* %%DocumentPaperWeights: */
+ CDSC_DOCUMENTDATA = 217, /* %%DocumentData: */
+ CDSC_REQUIREMENTS = 218, /* IGNORED %%Requirements: */
+ CDSC_DOCUMENTNEEDEDFONTS = 219, /* IGNORED %%DocumentNeededFonts: */
+ CDSC_DOCUMENTSUPPLIEDFONTS = 220, /* IGNORED %%DocumentSuppliedFonts: */
+ CDSC_HIRESBOUNDINGBOX = 221, /* %%HiResBoundingBox: */
+ CDSC_CROPBOX = 222, /* %%CropBox: */
+
+/* Preview section */
+ CDSC_BEGINPREVIEW = 301, /* %%BeginPreview */
+ CDSC_ENDPREVIEW = 302, /* %%EndPreview */
+
+/* Defaults section */
+ CDSC_BEGINDEFAULTS = 401, /* %%BeginDefaults */
+ CDSC_ENDDEFAULTS = 402, /* %%EndDefaults */
+/* also %%PageMedia, %%PageOrientation, %%PageBoundingBox */
+
+/* Prolog section */
+ CDSC_BEGINPROLOG = 501, /* %%BeginProlog */
+ CDSC_ENDPROLOG = 502, /* %%EndProlog */
+ CDSC_BEGINFONT = 503, /* IGNORED %%BeginFont */
+ CDSC_ENDFONT = 504, /* IGNORED %%EndFont */
+ CDSC_BEGINFEATURE = 505, /* IGNORED %%BeginFeature */
+ CDSC_ENDFEATURE = 506, /* IGNORED %%EndFeature */
+ CDSC_BEGINRESOURCE = 507, /* IGNORED %%BeginResource */
+ CDSC_ENDRESOURCE = 508, /* IGNORED %%EndResource */
+ CDSC_BEGINPROCSET = 509, /* IGNORED %%BeginProcSet */
+ CDSC_ENDPROCSET = 510, /* IGNORED %%EndProcSet */
+
+/* Setup section */
+ CDSC_BEGINSETUP = 601, /* %%BeginSetup */
+ CDSC_ENDSETUP = 602, /* %%EndSetup */
+ CDSC_FEATURE = 603, /* IGNORED %%Feature: */
+ CDSC_PAPERCOLOR = 604, /* IGNORED %%PaperColor: */
+ CDSC_PAPERFORM = 605, /* IGNORED %%PaperForm: */
+ CDSC_PAPERWEIGHT = 606, /* IGNORED %%PaperWeight: */
+ CDSC_PAPERSIZE = 607, /* %%PaperSize: */
+/* also %%Begin/EndFeature, %%Begin/EndResource */
+
+/* Page section */
+ CDSC_PAGE = 700, /* %%Page: */
+ CDSC_PAGETRAILER = 701, /* IGNORED %%PageTrailer */
+ CDSC_BEGINPAGESETUP = 702, /* IGNORED %%BeginPageSetup */
+ CDSC_ENDPAGESETUP = 703, /* IGNORED %%EndPageSetup */
+ CDSC_PAGEMEDIA = 704, /* %%PageMedia: */
+/* also %%PaperColor, %%PaperForm, %%PaperWeight, %%PaperSize */
+ CDSC_PAGEORIENTATION = 705, /* %%PageOrientation: */
+ CDSC_PAGEBOUNDINGBOX = 706, /* %%PageBoundingBox: */
+/* also %%Begin/EndFont, %%Begin/EndFeature */
+/* also %%Begin/EndResource, %%Begin/EndProcSet */
+ CDSC_INCLUDEFONT = 707, /* IGNORED %%IncludeFont: */
+ CDSC_VIEWINGORIENTATION = 708, /* %%ViewingOrientation: */
+
+/* Trailer section */
+ CDSC_TRAILER = 800, /* %%Trailer */
+/* also %%Pages, %%BoundingBox, %%Orientation, %%PageOrder, %%DocumentMedia */
+/* %%Page is recognised as an error */
+/* also %%DocumentNeededFonts, %%DocumentSuppliedFonts */
+
+/* End of File */
+ CDSC_EOF = 900 /* %%EOF */
+} CDSC_RETURN_CODE;
+
+
+/* stored in dsc->preview */
+typedef enum {
+ CDSC_NOPREVIEW = 0,
+ CDSC_EPSI = 1,
+ CDSC_TIFF = 2,
+ CDSC_WMF = 3,
+ CDSC_PICT = 4
+} CDSC_PREVIEW_TYPE;
+
+/* stored in dsc->page_order */
+typedef enum {
+ CDSC_ORDER_UNKNOWN = 0,
+ CDSC_ASCEND = 1,
+ CDSC_DESCEND = 2,
+ CDSC_SPECIAL = 3
+} CDSC_PAGE_ORDER;
+
+/* stored in dsc->page_orientation and dsc->page[pagenum-1].orientation */
+typedef enum {
+ CDSC_ORIENT_UNKNOWN = 0,
+ CDSC_PORTRAIT = 1,
+ CDSC_LANDSCAPE = 2,
+ CDSC_UPSIDEDOWN = 3,
+ CDSC_SEASCAPE = 4
+} CDSC_ORIENTATION_ENUM;
+
+/* stored in dsc->document_data */
+typedef enum {
+ CDSC_DATA_UNKNOWN = 0,
+ CDSC_CLEAN7BIT = 1,
+ CDSC_CLEAN8BIT = 2,
+ CDSC_BINARY = 3
+} CDSC_DOCUMENT_DATA ;
+
+typedef struct CDSCBBOX_S {
+ int llx;
+ int lly;
+ int urx;
+ int ury;
+} CDSCBBOX;
+
+typedef struct CDSCFBBOX_S {
+ float fllx;
+ float flly;
+ float furx;
+ float fury;
+} CDSCFBBOX;
+
+typedef struct CDSCMEDIA_S {
+ const char *name;
+ float width; /* PostScript points */
+ float height;
+ float weight; /* GSM */
+ const char *colour;
+ const char *type;
+ CDSCBBOX *mediabox; /* Used by GSview for PDF MediaBox */
+} CDSCMEDIA;
+
+#define CDSC_KNOWN_MEDIA 46
+extern const CDSCMEDIA dsc_known_media[CDSC_KNOWN_MEDIA];
+
+typedef struct CDSCCTM_S { /* used for %%ViewingOrientation */
+ float xx;
+ float xy;
+ float yx;
+ float yy;
+ /* float ty; */
+ /* float ty; */
+} CDSCCTM;
+
+typedef struct CDSCPAGE_S {
+ int ordinal;
+ const char *label;
+ unsigned long begin;
+ unsigned long end;
+ unsigned int orientation;
+ const CDSCMEDIA *media;
+ CDSCBBOX *bbox; /* PageBoundingBox, also used by GSview for PDF CropBox */
+ CDSCCTM *viewing_orientation;
+} CDSCPAGE;
+
+/* binary DOS EPS header */
+typedef struct CDSCDOSEPS_S {
+ GSDWORD ps_begin;
+ GSDWORD ps_length;
+ GSDWORD wmf_begin;
+ GSDWORD wmf_length;
+ GSDWORD tiff_begin;
+ GSDWORD tiff_length;
+ GSWORD checksum;
+} CDSCDOSEPS;
+
+/* rather than allocated every string with malloc, we allocate
+ * chunks of 4k and place the (usually) short strings in these
+ * chunks.
+ */
+typedef struct CDSCSTRING_S CDSCSTRING;
+struct CDSCSTRING_S {
+ unsigned int index;
+ unsigned int length;
+ char *data;
+ CDSCSTRING *next;
+};
+
+
+/* DSC error reporting */
+
+typedef enum {
+ CDSC_MESSAGE_BBOX = 0,
+ CDSC_MESSAGE_EARLY_TRAILER = 1,
+ CDSC_MESSAGE_EARLY_EOF = 2,
+ CDSC_MESSAGE_PAGE_IN_TRAILER = 3,
+ CDSC_MESSAGE_PAGE_ORDINAL = 4,
+ CDSC_MESSAGE_PAGES_WRONG = 5,
+ CDSC_MESSAGE_EPS_NO_BBOX = 6,
+ CDSC_MESSAGE_EPS_PAGES = 7,
+ CDSC_MESSAGE_NO_MEDIA = 8,
+ CDSC_MESSAGE_ATEND = 9,
+ CDSC_MESSAGE_DUP_COMMENT = 10,
+ CDSC_MESSAGE_DUP_TRAILER = 11,
+ CDSC_MESSAGE_BEGIN_END = 12,
+ CDSC_MESSAGE_BAD_SECTION = 13,
+ CDSC_MESSAGE_LONG_LINE = 14,
+ CDSC_MESSAGE_INCORRECT_USAGE = 15
+} CDSC_MESSAGE_ERROR;
+
+/* severity */
+typedef enum {
+ CDSC_ERROR_INFORM = 0, /* Not an error */
+ CDSC_ERROR_WARN = 1, /* Not a DSC error itself, */
+ CDSC_ERROR_ERROR = 2 /* DSC error */
+} CDSC_MESSAGE_SEVERITY;
+
+/* response */
+typedef enum {
+ CDSC_RESPONSE_OK = 0,
+ CDSC_RESPONSE_CANCEL = 1,
+ CDSC_RESPONSE_IGNORE_ALL = 2
+} CDSC_RESPONSE;
+
+extern const char * const dsc_message[];
+
+typedef struct CDSC_S CDSC;
+struct CDSC_S {
+ /* public data */
+ GSBOOL dsc; /* TRUE if DSC comments found */
+ GSBOOL ctrld; /* TRUE if has CTRLD at start of stream */
+ GSBOOL pjl; /* TRUE if has HP PJL at start of stream */
+ GSBOOL epsf; /* TRUE if EPSF */
+ GSBOOL pdf; /* TRUE if Portable Document Format */
+ unsigned int preview; /* enum CDSC_PREVIEW_TYPE */
+ char *dsc_version; /* first line of file */
+ unsigned int language_level;
+ unsigned int document_data; /* Clean7Bit, Clean8Bit, Binary */
+ /* enum CDSC_DOCUMENT_DATA */
+ /* DSC sections */
+ unsigned long begincomments;
+ unsigned long endcomments;
+ unsigned long beginpreview;
+ unsigned long endpreview;
+ unsigned long begindefaults;
+ unsigned long enddefaults;
+ unsigned long beginprolog;
+ unsigned long endprolog;
+ unsigned long beginsetup;
+ unsigned long endsetup;
+ unsigned long begintrailer;
+ unsigned long endtrailer;
+ CDSCPAGE *page;
+ unsigned int page_count; /* number of %%Page: pages in document */
+ unsigned int page_pages; /* number of pages in document from %%Pages: */
+ unsigned int page_order; /* enum CDSC_PAGE_ORDER */
+ unsigned int page_orientation; /* the default page orientation */
+ /* enum CDSC_ORIENTATION */
+ CDSCCTM *viewing_orientation;
+ unsigned int media_count; /* number of media items */
+ CDSCMEDIA **media; /* the array of media */
+ const CDSCMEDIA *page_media;/* the default page media */
+ CDSCBBOX *bbox; /* the document bounding box */
+ CDSCBBOX *page_bbox; /* the default page bounding box */
+ CDSCDOSEPS *doseps; /* DOS binary header */
+ char *dsc_title;
+ char *dsc_creator;
+ char *dsc_date;
+ char *dsc_for;
+
+ unsigned int max_error; /* highest error number that will be reported */
+ const int *severity; /* array of severity values, one per error */
+
+
+ /* private data */
+ void *caller_data; /* pointer to be provided when calling */
+ /* error and debug callbacks */
+ int id; /* last DSC comment found */
+ int scan_section; /* section currently being scanned */
+ /* enum CDSC_SECTION */
+
+ unsigned long doseps_end; /* ps_begin+ps_length, otherwise 0 */
+ unsigned int page_chunk_length; /* number of pages allocated */
+ unsigned long file_length; /* length of document */
+ /* If provided we try to recognise %%Trailer and %%EOF */
+ /* incorrectly embedded inside document. */
+ /* Can be left set to default value of 0 */
+ int skip_document; /* recursion level of %%BeginDocument: */
+ int skip_bytes; /* #bytes to ignore from BeginData: */
+ /* or DOSEPS preview section */
+ int skip_lines; /* #lines to ignore from BeginData: */
+ GSBOOL skip_pjl; /* TRUE if skip PJL until first PS comment */
+ int begin_font_count; /* recursion level of %%BeginFont */
+ int begin_feature_count; /* recursion level of %%BeginFeature */
+ int begin_resource_count; /* recursion level of %%BeginResource */
+ int begin_procset_count; /* recursion level of %%BeginProcSet */
+
+ /* buffer for input */
+ char data[CDSC_DATA_LENGTH];/* start of buffer */
+ unsigned int data_length; /* length of data in buffer */
+ unsigned int data_index; /* offset to next char in buffer */
+ unsigned long data_offset; /* offset from start of document */
+ /* to byte in data[0] */
+ GSBOOL eof; /* TRUE if there is no more data */
+
+ /* information about DSC line */
+ char *line; /* pointer to last read DSC line */
+ /* not null terminated */
+ unsigned int line_length; /* number of characters in line */
+ GSBOOL eol; /* TRUE if dsc_line contains EOL */
+ GSBOOL last_cr; /* TRUE if last line ended in \r */
+ /* check next time for \n */
+ unsigned int line_count; /* line number */
+ GSBOOL long_line; /* TRUE if found a line longer than 255 characters */
+ char last_line[256]; /* previous DSC line, used for %%+ */
+
+ /* more efficient string storage (for short strings) than malloc */
+ CDSCSTRING *string_head; /* linked list head */
+ CDSCSTRING *string; /* current list item */
+
+ /* memory allocation routines */
+ void *(*memalloc)(P2(size_t size, void *closure_data));
+ void (*memfree)(P2(void *ptr, void *closure_data));
+ void *mem_closure_data;
+
+ /* function for printing debug messages */
+ void (*debug_print_fn)(P2(void *caller_data, const char *str));
+
+ /* function for reporting errors in DSC comments */
+ int (*dsc_error_fn)(P5(void *caller_data, CDSC *dsc,
+ unsigned int explanation, const char *line, unsigned int line_len));
+
+ /* public data */
+ /* Added 2001-10-01 */
+ CDSCFBBOX *hires_bbox; /* the hires document bounding box */
+ CDSCFBBOX *crop_box; /* the size of the trimmed page */
+};
+
+
+/* Public functions */
+
+/* Create and initialise DSC parser */
+CDSC *dsc_init(P1(void *caller_data));
+
+CDSC *dsc_init_with_alloc(P4(
+ void *caller_data,
+ void *(*memalloc)(size_t size, void *closure_data),
+ void (*memfree)(void *ptr, void *closure_data),
+ void *closure_data));
+
+/* Free the DSC parser */
+void dsc_free(P1(CDSC *dsc));
+
+/* Tell DSC parser how long document will be, to allow ignoring
+ * of early %%Trailer and %%EOF. This is optional.
+ */
+void dsc_set_length(P2(CDSC *dsc, unsigned long len));
+
+/* Process a buffer containing DSC comments and PostScript */
+int dsc_scan_data(P3(CDSC *dsc, const char *data, int len));
+
+/* All data has been processed, fixup any DSC errors */
+int dsc_fixup(P1(CDSC *dsc));
+
+/* Install error query function */
+void dsc_set_error_function(P2(CDSC *dsc,
+ int (*dsc_error_fn)(P5(void *caller_data, CDSC *dsc,
+ unsigned int explanation, const char *line, unsigned int line_len))));
+
+/* Install print function for debug messages */
+void dsc_set_debug_function(P2(CDSC *dsc,
+ void (*debug_fn)(P2(void *caller_data, const char *str))));
+
+/* Print a message to debug output, if provided */
+void dsc_debug_print(P2(CDSC *dsc, const char *str));
+
+/* should be internal only functions, but made available to
+ * GSview for handling PDF
+ */
+int dsc_add_page(P3(CDSC *dsc, int ordinal, char *label));
+int dsc_add_media(P2(CDSC *dsc, CDSCMEDIA *media));
+int dsc_set_page_bbox(P6(CDSC *dsc, unsigned int page_number,
+ int llx, int lly, int urx, int ury));
+
+#endif
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/dscparse_adapter.cpp b/kghostview/dscparse_adapter.cpp
new file mode 100644
index 00000000..4db450bb
--- /dev/null
+++ b/kghostview/dscparse_adapter.cpp
@@ -0,0 +1,420 @@
+/**
+ * Copyright (C) 2001 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 "dscparse_adapter.h"
+
+using namespace std;
+
+/*-- KDSCBBOX implementation -----------------------------------------------*/
+
+KDSCBBOX::KDSCBBOX() :
+ _llx( 0 ), _lly( 0 ),
+ _urx( 0 ), _ury( 0 )
+{}
+
+KDSCBBOX::KDSCBBOX( const KDSCBBOX& b ) :
+ _llx( b._llx ), _lly( b._lly ),
+ _urx( b._urx ), _ury( b._ury )
+{}
+
+KDSCBBOX::KDSCBBOX( int llx, int lly, int urx, int ury ) :
+ _llx( llx ), _lly( lly ),
+ _urx( urx ), _ury( ury )
+{}
+
+KDSCBBOX::KDSCBBOX( const CDSCBBOX& bbox ) :
+ _llx( bbox.llx ), _lly( bbox.lly ),
+ _urx( bbox.urx ), _ury( bbox.ury )
+{}
+
+KDSCBBOX& KDSCBBOX::operator = ( const KDSCBBOX& b )
+{
+ _llx = b._llx; _lly = b._lly; _urx = b._urx; _ury = b._ury;
+ return *this;
+}
+
+bool KDSCBBOX::operator == ( const KDSCBBOX& b )
+{
+ return ( _llx == b._llx && _lly == b._lly
+ && _urx == b._urx && _ury == b._ury );
+}
+
+bool KDSCBBOX::operator != ( const KDSCBBOX& b )
+{
+ return !( *this == b );
+}
+
+int KDSCBBOX::llx() const { return _llx; }
+int KDSCBBOX::lly() const { return _lly; }
+int KDSCBBOX::urx() const { return _urx; }
+int KDSCBBOX::ury() const { return _ury; }
+
+int KDSCBBOX::width() const { return _urx - _llx; }
+int KDSCBBOX::height() const { return _ury - _lly; }
+
+QSize KDSCBBOX::size() const { return QSize( width(), height() ); }
+
+ostream& operator << ( ostream& os, const KDSCBBOX& source )
+{
+ os << "{ llx: "<< source.llx() << ", lly: " << source.lly()
+ << " urx: "<< source.urx() << ", ury: " << source.ury() << " }";
+ return os;
+}
+
+/*-- KDSCError implementation ----------------------------------------------*/
+
+KDSCError::KDSCError( Type type, Severity severity, const QCString& line,
+ unsigned int lineNumber ) :
+ _type( type ),
+ _severity( severity ),
+ _line( line ),
+ _lineNumber( lineNumber )
+{}
+
+KDSCError::Type KDSCError::type() const
+{
+ return _type;
+}
+
+KDSCError::Severity KDSCError::severity() const
+{
+ return _severity;
+}
+
+QCString KDSCError::line() const
+{
+ return _line;
+}
+
+unsigned int KDSCError::lineNumber() const
+{
+ return _lineNumber;
+}
+
+/*-- KDSCOkErrorHandler implementation -------------------------------------*/
+
+KDSCErrorHandler::Response KDSCOkErrorHandler::error( const KDSCError& err )
+{
+ cout << "KDSC: error in line " << err.lineNumber() << endl;
+ cout << err.line() << endl;
+ return Ok;
+}
+
+/*-- KDSC implementation ---------------------------------------------------*/
+
+KDSC::KDSC() :
+ _errorHandler( 0 ),
+ _commentHandler( 0 )
+{
+ _cdsc = dsc_init( this );
+ Q_ASSERT( _cdsc != 0 );
+ _scanHandler = new KDSCScanHandler( _cdsc );
+}
+
+KDSC::~KDSC()
+{
+ dsc_free( _cdsc );
+ delete _scanHandler;
+}
+
+QString KDSC::dsc_version() const
+{
+ return QString( _cdsc->dsc_version );
+}
+
+bool KDSC::dsc() const
+{
+ return ( _cdsc->dsc == TRUE );
+}
+
+bool KDSC::ctrld() const
+{
+ return ( _cdsc->ctrld == TRUE );
+}
+
+bool KDSC::pjl() const
+{
+ return ( _cdsc->pjl == TRUE );
+}
+
+bool KDSC::epsf() const
+{
+ return ( _cdsc->epsf == TRUE );
+}
+
+bool KDSC::pdf() const
+{
+ return ( _cdsc->pdf == TRUE );
+}
+
+unsigned int KDSC::preview() const
+{
+ return _cdsc->preview;
+}
+
+unsigned int KDSC::language_level() const
+{
+ return _cdsc->language_level;
+}
+
+unsigned int KDSC::document_data() const
+{
+ return _cdsc->document_data;
+}
+
+unsigned long KDSC::begincomments() const
+{
+ return _cdsc->begincomments;
+}
+
+unsigned long KDSC::endcomments() const
+{
+ return _cdsc->endcomments;
+}
+
+unsigned long KDSC::beginpreview() const
+{
+ return _cdsc->beginpreview;
+}
+
+unsigned long KDSC::endpreview() const
+{
+ return _cdsc->endpreview;
+}
+
+unsigned long KDSC::begindefaults() const
+{
+ return _cdsc->begindefaults;
+}
+
+unsigned long KDSC::enddefaults() const
+{
+ return _cdsc->enddefaults;
+}
+
+unsigned long KDSC::beginprolog() const
+{
+ return _cdsc->beginprolog;
+}
+
+unsigned long KDSC::endprolog() const
+{
+ return _cdsc->endprolog;
+}
+
+unsigned long KDSC::beginsetup() const
+{
+ return _cdsc->beginsetup;
+}
+
+unsigned long KDSC::endsetup() const
+{
+ return _cdsc->endsetup;
+}
+
+unsigned long KDSC::begintrailer() const
+{
+ return _cdsc->begintrailer;
+}
+
+unsigned long KDSC::endtrailer() const
+{
+ return _cdsc->endtrailer;
+}
+
+CDSCPAGE* KDSC::page() const
+{
+ return _cdsc->page;
+}
+
+unsigned int KDSC::page_count() const
+{
+ return _cdsc->page_count;
+}
+
+unsigned int KDSC::page_pages() const
+{
+ return _cdsc->page_pages;
+}
+
+unsigned int KDSC::page_order() const
+{
+ return _cdsc->page_order;
+}
+
+unsigned int KDSC::page_orientation() const
+{
+ return _cdsc->page_orientation;
+}
+
+CDSCCTM* KDSC::viewing_orientation() const
+{
+ return _cdsc->viewing_orientation;
+}
+
+unsigned int KDSC::media_count() const
+{
+ return _cdsc->media_count;
+}
+
+CDSCMEDIA** KDSC::media() const
+{
+ return _cdsc->media;
+}
+
+const CDSCMEDIA* KDSC::page_media() const
+{
+ return _cdsc->page_media;
+}
+
+auto_ptr<KDSCBBOX> KDSC::bbox() const
+{
+ if( _cdsc->bbox == 0 )
+ return auto_ptr<KDSCBBOX>( 0 );
+ else
+ return auto_ptr<KDSCBBOX>( new KDSCBBOX( *_cdsc->bbox ) );
+}
+
+auto_ptr<KDSCBBOX> KDSC::page_bbox() const
+{
+ if( _cdsc->page_bbox == 0 )
+ return auto_ptr<KDSCBBOX>( 0 );
+ else
+ return auto_ptr<KDSCBBOX>( new KDSCBBOX( *_cdsc->page_bbox ) );
+}
+
+QString KDSC::dsc_title() const
+{
+ return QString( _cdsc->dsc_title );
+}
+
+QString KDSC::dsc_creator() const
+{
+ return QString( _cdsc->dsc_creator );
+}
+
+QString KDSC::dsc_date() const
+{
+ return QString( _cdsc->dsc_date );
+}
+
+QString KDSC::dsc_for() const
+{
+ return QString( _cdsc->dsc_for );
+}
+
+bool KDSC::scanData( char* buffer, unsigned int count )
+{
+ return _scanHandler->scanData( buffer, count );
+}
+
+int KDSC::fixup()
+{
+ return dsc_fixup( _cdsc );
+}
+
+KDSCErrorHandler* KDSC::errorHandler() const
+{
+ return _errorHandler;
+}
+
+void KDSC::setErrorHandler( KDSCErrorHandler* errorHandler )
+{
+ _errorHandler = errorHandler;
+ if( errorHandler == 0 )
+ dsc_set_error_function( _cdsc, 0 );
+ else
+ dsc_set_error_function( _cdsc, &errorFunction );
+}
+
+KDSCCommentHandler* KDSC::commentHandler() const
+{
+ return _commentHandler;
+}
+
+void KDSC::setCommentHandler( KDSCCommentHandler* commentHandler )
+{
+ if( _commentHandler != 0 && commentHandler == 0 )
+ {
+ delete _scanHandler;
+ _scanHandler = new KDSCScanHandler( _cdsc );
+ }
+ else if( _commentHandler == 0 && commentHandler != 0 )
+ {
+ delete _scanHandler;
+ _scanHandler = new KDSCScanHandlerByLine( _cdsc, commentHandler );
+ }
+ _commentHandler = commentHandler;
+}
+
+bool KDSC::isStructured() const
+{
+ return epsf() ? ( page_count() > 1 ) : ( page_count() > 0 );
+}
+
+CDSC* KDSC::cdsc() const
+{
+ return _cdsc;
+}
+
+int KDSC::errorFunction( void* caller_data, CDSC* dsc,
+ unsigned int explanation, const char* line, unsigned int line_len )
+{
+ KDSCError error(
+ static_cast< KDSCError::Type >( explanation ),
+ static_cast< KDSCError::Severity >( dsc->severity[explanation] ),
+ QCString( line, line_len + 1 ),
+ dsc->line_count
+ );
+
+ KDSC* kdsc = static_cast< KDSC* >( caller_data );
+ Q_ASSERT( kdsc );
+
+ return kdsc->errorHandler()->error( error );
+}
+
+bool KDSCScanHandlerByLine::scanData( char* buf, unsigned int count )
+{
+ char* lineStart = buf;
+ char* it = buf;
+ while( it < buf + count )
+ {
+ if( *it++ == '\n' )
+ {
+ int retval = dsc_scan_data( _cdsc, lineStart, it - lineStart );
+ if( retval < 0 )
+ return false;
+ else if( retval > 0 )
+ {
+ _commentHandler->comment(
+ static_cast<KDSCCommentHandler::Name>( retval ) );
+ }
+ lineStart = it;
+ }
+ }
+
+ if( it != lineStart )
+ {
+ // Scan the remaining part of the string.
+ return ( dsc_scan_data( _cdsc, lineStart, it - lineStart ) < 0 );
+ }
+ else
+ return true;
+}
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/dscparse_adapter.h b/kghostview/dscparse_adapter.h
new file mode 100644
index 00000000..9e41f3c2
--- /dev/null
+++ b/kghostview/dscparse_adapter.h
@@ -0,0 +1,386 @@
+/**
+ * Copyright (C) 2001 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 DSCPARSE_ADAPTER_H
+#define DSCPARSE_ADAPTER_H
+
+#include <iostream>
+#include <map>
+#include <memory>
+
+#include <qsize.h>
+#include <qstring.h>
+
+#include "dscparse.h"
+
+#if defined(__GNUC__)
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 93)
+/*
+ * We add a quick 'n' dirty inline implementation of auto_ptr for older
+ * releases of GCC, which don't include an auto_ptr implementation in
+ * <memory>.
+ */
+
+template <class T> class auto_ptr {
+private:
+ T* _ptr;
+
+public:
+ typedef T element_type;
+ explicit auto_ptr(T* p = 0) : _ptr(p) {}
+ auto_ptr(auto_ptr& a) : _ptr(a.release()) {}
+ template <class T1> auto_ptr(auto_ptr<T1>& a) : _ptr(a.release()) {}
+ auto_ptr& operator=(auto_ptr& a) {
+ if (&a != this) {
+ delete _ptr;
+ _ptr = a.release();
+ }
+ return *this;
+ }
+ template <class T1>
+ auto_ptr& operator=(auto_ptr<T1>& a) {
+ if (a.get() != this->get()) {
+ delete _ptr;
+ _ptr = a.release();
+ }
+ return *this;
+ }
+ ~auto_ptr() { delete _ptr; }
+
+ T& operator*() const { return *_ptr; }
+ T* operator->() const { return _ptr; }
+ T* get() const { return _ptr; }
+ T* release() { T* tmp = _ptr; _ptr = 0; return tmp; }
+ void reset(T* p = 0) { delete _ptr; _ptr = p; }
+};
+
+#endif
+#endif
+
+
+class KDSCBBOX
+{
+public:
+ KDSCBBOX();
+ KDSCBBOX( const KDSCBBOX& b );
+ KDSCBBOX( int llx, int lly, int urx, int ury );
+ KDSCBBOX( const CDSCBBOX& bbox );
+
+ KDSCBBOX& operator = ( const KDSCBBOX& b );
+
+ bool operator == ( const KDSCBBOX& b );
+ bool operator != ( const KDSCBBOX& b );
+
+ int llx() const;
+ int lly() const;
+ int urx() const;
+ int ury() const;
+
+ int width() const;
+ int height() const;
+
+ QSize size() const;
+
+private:
+ int _llx, _lly, _urx, _ury;
+};
+
+std::ostream& operator << ( std::ostream&, const KDSCBBOX& );
+
+
+class KDSCError
+{
+public:
+ enum Type
+ {
+ BBox = CDSC_MESSAGE_BBOX,
+ EarlyTrailer = CDSC_MESSAGE_EARLY_TRAILER,
+ EarlyEOF = CDSC_MESSAGE_EARLY_EOF,
+ PageInTrailer = CDSC_MESSAGE_PAGE_IN_TRAILER,
+ PageOrdinal = CDSC_MESSAGE_PAGE_ORDINAL,
+ PagesWrong = CDSC_MESSAGE_PAGES_WRONG,
+ EPSNoBBox = CDSC_MESSAGE_EPS_NO_BBOX,
+ EPSPages = CDSC_MESSAGE_EPS_PAGES,
+ NoMedia = CDSC_MESSAGE_NO_MEDIA,
+ AtEnd = CDSC_MESSAGE_ATEND,
+ DuplicateComment = CDSC_MESSAGE_DUP_COMMENT,
+ DuplicateTrailer = CDSC_MESSAGE_DUP_TRAILER,
+ BeginEnd = CDSC_MESSAGE_BEGIN_END,
+ BadSection = CDSC_MESSAGE_BAD_SECTION,
+ LongLine = CDSC_MESSAGE_LONG_LINE,
+ IncorrectUsage = CDSC_MESSAGE_INCORRECT_USAGE
+ };
+
+ enum Severity
+ {
+ Information = CDSC_ERROR_INFORM,
+ Warning = CDSC_ERROR_WARN,
+ Error = CDSC_ERROR_ERROR
+ };
+
+ KDSCError( Type, Severity, const QCString& line,
+ unsigned int lineNumber );
+
+ Type type() const;
+ Severity severity() const;
+ QCString line() const;
+ unsigned int lineNumber() const;
+
+private:
+ Type _type;
+ Severity _severity;
+ QCString _line;
+ unsigned int _lineNumber;
+};
+
+
+class KDSCErrorHandler
+{
+public:
+ virtual ~KDSCErrorHandler() {}
+ enum Response
+ {
+ Ok = CDSC_RESPONSE_OK,
+ Cancel = CDSC_RESPONSE_CANCEL,
+ IgnoreAll = CDSC_RESPONSE_IGNORE_ALL
+ };
+
+ virtual Response error( const KDSCError& ) = 0;
+};
+
+class KDSCOkErrorHandler : public KDSCErrorHandler
+{
+ Response error( const KDSCError& );
+};
+
+class KDSCCommentHandler
+{
+public:
+ virtual ~KDSCCommentHandler() {}
+ enum Name
+ {
+ // Header section
+ PSAdobe = CDSC_PSADOBE,
+ BeginComments = CDSC_BEGINCOMMENTS,
+ EndComments = CDSC_ENDCOMMENTS,
+ Pages = CDSC_PAGES,
+ Creator = CDSC_CREATOR,
+ CreationDate = CDSC_CREATIONDATE,
+ Title = CDSC_TITLE,
+ For = CDSC_FOR,
+ LanguageLevel = CDSC_LANGUAGELEVEL,
+ BoundingBox = CDSC_BOUNDINGBOX,
+ Orientation = CDSC_ORIENTATION,
+ PageOrder = CDSC_PAGEORDER,
+ DocumentMedia = CDSC_DOCUMENTMEDIA,
+ DocumentPaperSizes = CDSC_DOCUMENTPAPERSIZES,
+ DocumentPaperForms = CDSC_DOCUMENTPAPERFORMS,
+ DocumentPaperColors = CDSC_DOCUMENTPAPERCOLORS,
+ DocumentPaperWeights = CDSC_DOCUMENTPAPERWEIGHTS,
+ DocumentData = CDSC_DOCUMENTDATA,
+ Requirements = CDSC_REQUIREMENTS,
+ DocumentNeededFonts = CDSC_DOCUMENTNEEDEDFONTS,
+ DocumentSuppliedFonts = CDSC_DOCUMENTSUPPLIEDFONTS,
+ HiResBoundingBox = CDSC_HIRESBOUNDINGBOX,
+ CropBox = CDSC_CROPBOX,
+
+ // Preview section
+ BeginPreview = CDSC_BEGINPREVIEW,
+ EndPreview = CDSC_ENDPREVIEW,
+
+ // Defaults section
+ BeginDefaults = CDSC_BEGINDEFAULTS,
+ EndDefaults = CDSC_ENDDEFAULTS,
+ // also %%PageMedia, %%PageOrientation, %%PageBoundingBox
+
+ // Prolog section
+ BeginProlog = CDSC_BEGINPROLOG,
+ EndProlog = CDSC_ENDPROLOG,
+ BeginFont = CDSC_BEGINFONT,
+ EndFont = CDSC_ENDFONT,
+ BeginFeature = CDSC_BEGINFEATURE,
+ EndFeature = CDSC_ENDFEATURE,
+ BeginResource = CDSC_BEGINRESOURCE,
+ EndResource = CDSC_ENDRESOURCE,
+ BeginProcset = CDSC_BEGINPROCSET,
+ EndProcset = CDSC_ENDPROCSET,
+
+ // Setup section
+ BeginSetup = CDSC_BEGINSETUP,
+ EndSetup = CDSC_ENDSETUP,
+ Feature = CDSC_FEATURE,
+ PaperColor = CDSC_PAPERCOLOR,
+ PaperForm = CDSC_PAPERFORM,
+ PaperWeight = CDSC_PAPERWEIGHT,
+ PaperSize = CDSC_PAPERSIZE,
+ // also %%Begin/EndFeature, %%Begin/EndResource
+
+ // Page section
+ Page = CDSC_PAGE,
+ PageTrailer = CDSC_PAGETRAILER,
+ BeginPageSetup = CDSC_BEGINPAGESETUP,
+ EndPageSetup = CDSC_ENDPAGESETUP,
+ PageMedia = CDSC_PAGEMEDIA,
+ // also %%PaperColor, %%PaperForm, %%PaperWeight, %%PaperSize
+ PageOrientation = CDSC_PAGEORIENTATION,
+ PageBoundingBox = CDSC_PAGEBOUNDINGBOX,
+ // also %%Begin/EndFont, %%Begin/EndFeature
+ // also %%Begin/EndResource, %%Begin/EndProcSet
+ IncludeFont = CDSC_INCLUDEFONT,
+ ViewingOrientation = CDSC_VIEWINGORIENTATION,
+
+ // Trailer section
+ Trailer = CDSC_TRAILER,
+ // also %%Pages, %%BoundingBox, %%Orientation, %%PageOrder,
+ // %%DocumentMedia
+ // %%Page is recognised as an error
+ // also %%DocumentNeededFonts, %%DocumentSuppliedFonts
+
+ // End of File */
+ Eof = CDSC_EOF
+ };
+
+ virtual void comment( Name name ) { std::cout << name << std::endl; }
+};
+
+class KDSCScanHandler;
+class KDSC
+{
+public:
+ KDSC();
+ ~KDSC();
+
+ /*--- Adapter for CDSC ------------------------------------------------*/
+ QString dsc_version() const;
+
+ bool dsc() const;
+ bool ctrld() const;
+ bool pjl() const;
+ bool epsf() const;
+ bool pdf() const;
+
+ unsigned int preview() const;
+ unsigned int language_level() const;
+ unsigned int document_data() const;
+
+ unsigned long begincomments() const;
+ unsigned long endcomments() const;
+ unsigned long beginpreview() const;
+ unsigned long endpreview() const;
+ unsigned long begindefaults() const;
+ unsigned long enddefaults() const;
+ unsigned long beginprolog() const;
+ unsigned long endprolog() const;
+ unsigned long beginsetup() const;
+ unsigned long endsetup() const;
+ unsigned long begintrailer() const;
+ unsigned long endtrailer() const;
+
+ CDSCPAGE* page() const;
+
+ unsigned int page_count() const;
+ unsigned int page_pages() const;
+ unsigned int page_order() const;
+ unsigned int page_orientation() const;
+
+ CDSCCTM* viewing_orientation() const;
+
+ unsigned int media_count() const;
+ CDSCMEDIA** media() const;
+ const CDSCMEDIA* page_media() const;
+
+#if defined(__GNUC__) && (__GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 93))
+ auto_ptr<KDSCBBOX> bbox() const;
+ auto_ptr<KDSCBBOX> page_bbox() const;
+#else
+ std::auto_ptr<KDSCBBOX> bbox() const;
+ std::auto_ptr<KDSCBBOX> page_bbox() const;
+#endif
+
+ // CDSCDOSEPS *doseps;
+
+ QString dsc_title() const;
+ QString dsc_creator() const;
+ QString dsc_date() const;
+ QString dsc_for() const;
+
+ // unsigned int max_error
+
+ bool scanData( char*, unsigned int );
+
+ /**
+ * Tidy up from incorrect DSC comments.
+ */
+ int fixup();
+
+ KDSCErrorHandler* errorHandler() const;
+ void setErrorHandler( KDSCErrorHandler* );
+
+ KDSCCommentHandler* commentHandler() const;
+ void setCommentHandler( KDSCCommentHandler* );
+
+ /*--- Extra methods for convenience -----------------------------------*/
+ bool isStructured() const;
+
+ /*--- Temporary -------------------------------------------------------*/
+ CDSC* cdsc() const;
+
+protected:
+ static int errorFunction( void* caller_data, CDSC* dsc,
+ unsigned int explanation,
+ const char* line, unsigned int line_len );
+
+private:
+ CDSC* _cdsc;
+ KDSCErrorHandler* _errorHandler;
+ KDSCCommentHandler* _commentHandler;
+ KDSCScanHandler* _scanHandler;
+};
+
+class KDSCScanHandler
+{
+public:
+ virtual ~KDSCScanHandler() {}
+ KDSCScanHandler( CDSC* cdsc ) : _cdsc( cdsc ) {}
+
+ virtual bool scanData( char* buf, unsigned int count )
+ {
+ return ( dsc_scan_data( _cdsc, buf, count ) >= 0 );
+ }
+
+protected:
+ CDSC* _cdsc;
+};
+
+class KDSCScanHandlerByLine : public KDSCScanHandler
+{
+public:
+ KDSCScanHandlerByLine( CDSC* cdsc, KDSCCommentHandler* commentHandler ) :
+ KDSCScanHandler( cdsc ),
+ _commentHandler( commentHandler )
+ {}
+
+ virtual bool scanData( char* buf, unsigned int count );
+
+protected:
+ KDSCCommentHandler* _commentHandler;
+};
+
+#endif
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/fullscreenfilter.cpp b/kghostview/fullscreenfilter.cpp
new file mode 100644
index 00000000..ec208169
--- /dev/null
+++ b/kghostview/fullscreenfilter.cpp
@@ -0,0 +1,54 @@
+/**
+ * Copyright (C) 2003, Lus Pedro Coelho
+ *
+ * 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 "fullscreenfilter.h"
+
+#include "kgvshell.h"
+#include "kgv_view.h"
+#include "kgv_miniwidget.h"
+#include "kgvpageview.h"
+
+FullScreenFilter::FullScreenFilter( KGVShell& parent )
+ :QObject( &parent, "full-screen-filter" ),
+ parent( parent )
+{
+}
+
+bool FullScreenFilter::eventFilter( QObject* /*object*/, QEvent* ev) {
+ if ( QKeyEvent* keyevent = dynamic_cast<QKeyEvent*>( ev ) ) {
+ if ( keyevent->key() == Key_Escape ) {
+ parent.setFullScreen( false );
+ keyevent->accept();
+ return true;
+ }
+ }
+ if ( QMouseEvent* mouseevent = dynamic_cast<QMouseEvent*>( ev ) ) {
+ if ( mouseevent->stateAfter() & mouseevent->button() & LeftButton ) {
+ // if ( The whole image is visible at once )
+ if ( parent.m_gvpart->pageView()->contentsHeight() <= parent.m_gvpart->widget()->height() &&
+ parent.m_gvpart->pageView()->contentsWidth() <= parent.m_gvpart->widget()->width() ) {
+ parent.m_gvpart->miniWidget()->nextPage();
+ mouseevent->accept();
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+#include "fullscreenfilter.moc"
+
diff --git a/kghostview/fullscreenfilter.h b/kghostview/fullscreenfilter.h
new file mode 100644
index 00000000..e60090a1
--- /dev/null
+++ b/kghostview/fullscreenfilter.h
@@ -0,0 +1,44 @@
+/**
+ * Copyright (C) 2003, Lus Pedro Coelho
+ *
+ * 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 DB_FULLSCREENFILTER_H1055977622_INCLUDE_GUARD_
+#define DB_FULLSCREENFILTER_H1055977622_INCLUDE_GUARD_
+
+#include <qobject.h>
+class KGVShell;
+
+/* @class FullScreenFilter
+ *
+ * @short This class is to have in one place the special event all the special
+ * key/mouse handling related to full-screen mode without bloating further KGVPart
+ */
+class FullScreenFilter : public QObject {
+ Q_OBJECT
+ public:
+ FullScreenFilter( KGVShell& parent );
+
+ /**
+ * @reimplemented
+ */
+ virtual bool eventFilter( QObject*, QEvent* );
+ private:
+ KGVShell& parent;
+};
+
+
+
+#endif /* DB_FULLSCREENFILTER_H1055977622_INCLUDE_GUARD_ */
diff --git a/kghostview/generalsettingswidget.ui b/kghostview/generalsettingswidget.ui
new file mode 100644
index 00000000..60ffbdf3
--- /dev/null
+++ b/kghostview/generalsettingswidget.ui
@@ -0,0 +1,111 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>GeneralSettingsWidget</class>
+<author>Nadeem Hasan &lt;nhasan@kde.org&gt;</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>GeneralSettingsWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>397</width>
+ <height>143</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_Antialiasing</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Enable anti-aliasing of fonts and images</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Anti-aliasing makes the result look better, but it makes the display take longer</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_PlatformFonts</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Use platform fonts</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_Messages</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Show Ghostscript messages in a separate box</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Ghostscript is the basic renderer (the program which draws the picture)&lt;br&gt;
+In case of problems you might want to see its error messages</string>
+ </property>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>kcfg_Palette</cstring>
+ </property>
+ <property name="title">
+ <string>Palette</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>Mono</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Monochrome</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>2</number>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>Gray</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Grayscale</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>Color</cstring>
+ </property>
+ <property name="text">
+ <string>Co&amp;lor</string>
+ </property>
+ <property name="buttonGroupId">
+ <number>0</number>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<includes>
+ <include location="global" impldecl="in implementation">kdialog.h</include>
+ <include location="local" impldecl="in implementation">generalsettingswidget.ui.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/>
+</UI>
diff --git a/kghostview/generalsettingswidget.ui.h b/kghostview/generalsettingswidget.ui.h
new file mode 100644
index 00000000..8dd6920d
--- /dev/null
+++ b/kghostview/generalsettingswidget.ui.h
@@ -0,0 +1,9 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you wish to add, delete or rename functions or slots use
+** Qt Designer which will update this file, preserving your code. Create an
+** init() function in place of a constructor, and a destroy() function in
+** place of a destructor.
+*****************************************************************************/
+
diff --git a/kghostview/gssettingswidget.ui b/kghostview/gssettingswidget.ui
new file mode 100644
index 00000000..06779f3b
--- /dev/null
+++ b/kghostview/gssettingswidget.ui
@@ -0,0 +1,158 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>GSSettingsWidget</class>
+<author>Nadeem Hasan &lt;nhasan@kde.org&gt;</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>GSSettingsWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>395</width>
+ <height>243</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="KPushButton" row="0" column="0">
+ <property name="name">
+ <cstring>mConfigureButton</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Auto Con&amp;figure</string>
+ </property>
+ </widget>
+ <spacer row="0" column="1">
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>286</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QGroupBox" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Settings</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Interpreter:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_Interpreter</cstring>
+ </property>
+ </widget>
+ <widget class="KURLRequester">
+ <property name="name">
+ <cstring>kcfg_Interpreter</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Ghostscript is the basic renderer (i.e. the program which draws)</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>mDetectedVersion</cstring>
+ </property>
+ <property name="text">
+ <string>(detected gs version: %1)</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Non-antialiasing arguments:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_NonAntialiasingArguments</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>kcfg_NonAntialiasingArguments</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Anti-aliasing makes the result look better, but it makes the display take longer</string>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>An&amp;tialiasing arguments:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_AntialiasingArguments</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit">
+ <property name="name">
+ <cstring>kcfg_AntialiasingArguments</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Anti-aliasing makes the result look better, but it makes the display take longer</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<includes>
+ <include location="global" impldecl="in implementation">kdialog.h</include>
+ <include location="local" impldecl="in implementation">gssettingswidget.ui.h</include>
+</includes>
+<signals>
+ <signal>configClicked()</signal>
+</signals>
+<slots>
+ <slot specifier="non virtual">setDetectedVersion( QString v )</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/>
+<includehints>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kurlrequester.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>klineedit.h</includehint>
+ <includehint>klineedit.h</includehint>
+</includehints>
+</UI>
diff --git a/kghostview/gssettingswidget.ui.h b/kghostview/gssettingswidget.ui.h
new file mode 100644
index 00000000..87937c76
--- /dev/null
+++ b/kghostview/gssettingswidget.ui.h
@@ -0,0 +1,14 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you wish to add, delete or rename functions or slots use
+** Qt Designer which will update this file, preserving your code. Create an
+** init() function in place of a constructor, and a destroy() function in
+** place of a destructor.
+*****************************************************************************/
+
+void GSSettingsWidget::setDetectedVersion( QString v)
+{
+ mDetectedVersion->setText(mDetectedVersion->text().arg( v ));
+}
+
diff --git a/kghostview/hi128-app-kghostview.png b/kghostview/hi128-app-kghostview.png
new file mode 100644
index 00000000..82048b94
--- /dev/null
+++ b/kghostview/hi128-app-kghostview.png
Binary files differ
diff --git a/kghostview/hi16-app-kghostview.png b/kghostview/hi16-app-kghostview.png
new file mode 100644
index 00000000..9603332f
--- /dev/null
+++ b/kghostview/hi16-app-kghostview.png
Binary files differ
diff --git a/kghostview/hi22-app-kghostview.png b/kghostview/hi22-app-kghostview.png
new file mode 100644
index 00000000..2109ade8
--- /dev/null
+++ b/kghostview/hi22-app-kghostview.png
Binary files differ
diff --git a/kghostview/hi32-app-kghostview.png b/kghostview/hi32-app-kghostview.png
new file mode 100644
index 00000000..4726452e
--- /dev/null
+++ b/kghostview/hi32-app-kghostview.png
Binary files differ
diff --git a/kghostview/hi48-app-kghostview.png b/kghostview/hi48-app-kghostview.png
new file mode 100644
index 00000000..0289cea7
--- /dev/null
+++ b/kghostview/hi48-app-kghostview.png
Binary files differ
diff --git a/kghostview/hi64-app-kghostview.png b/kghostview/hi64-app-kghostview.png
new file mode 100644
index 00000000..e8bab3f4
--- /dev/null
+++ b/kghostview/hi64-app-kghostview.png
Binary files differ
diff --git a/kghostview/infodialog.cpp b/kghostview/infodialog.cpp
new file mode 100644
index 00000000..b9cc8a91
--- /dev/null
+++ b/kghostview/infodialog.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2000 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 <qframe.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qdatetime.h>
+#include <qregexp.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kstdguiitem.h>
+
+#include "infodialog.h"
+
+//
+// Using KDialogBase in message box mode (gives centered action button)
+//
+InfoDialog::InfoDialog( QWidget *parent, const char *name, bool modal )
+ :KDialogBase( i18n("Document Information"), Yes, Yes, Yes, parent,
+ name, modal, true, KStdGuiItem::ok() )
+{
+ QFrame *page = makeMainWidget();
+ QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
+ QGridLayout *glay = new QGridLayout( topLayout, 3, 2 );
+ glay->setColStretch(1,1);
+
+ QLabel *label = new QLabel( i18n("File name:" ), page );
+ glay->addWidget( label, 0, 0, AlignRight|AlignVCenter );
+ mFileLabel = new QLabel( page );
+ glay->addWidget( mFileLabel, 0, 1 );
+
+ label = new QLabel( i18n("Document title:" ), page );
+ glay->addWidget( label, 1, 0, AlignRight|AlignVCenter );
+ mTitleLabel = new QLabel( page );
+ glay->addWidget( mTitleLabel, 1, 1 );
+
+ label = new QLabel( i18n("Publication date:" ), page );
+ glay->addWidget( label, 2, 0, AlignRight|AlignVCenter );
+ mDateLabel = new QLabel( page );
+ glay->addWidget( mDateLabel, 2, 1 );
+
+ topLayout->addStretch(1);
+}
+
+namespace {
+ /* For PDF files, the dates are in a standard format.
+ *
+ * According to the spec at http://partners.adobe.com/asn/tech/pdf/specifications.jsp
+ * That format is "(D:YYYYMMDDHHmmSSOHH'mm')", where
+ * YYYY is year,
+ * MM month
+ * DD day
+ * HH hour
+ * mm minute
+ * SS second
+ * O is "+" or "-"
+ * HH is hour
+ * mm is minute
+ *
+ * OHH'mm' form together the desviation to UCT time ( the timezone ).
+ * Everything after the YYYY is optional.
+ * The D: is "highly recommended", but legally optional
+ *
+ * For PS files, there is no such standard and dates appear
+ * in any format they desire.
+ */
+ QString parseDate( const QString& dateStr ) {
+ kdDebug( 4500 ) << "parseDate( \"" << dateStr << "\" )" << endl;
+ QRegExp exp( "\\((?:D:)?"
+ "(\\d\\d\\d\\d)"
+ "(\\d\\d)?(\\d\\d)?(\\d\\d)?.*"
+ "(\\d\\d)?(\\d\\d)?.*"
+ "(?:(\\+|\\-)(\\d\\d)\'?(\\d\\d)\'?)?"
+ "\\)" );
+ if ( exp.exactMatch( dateStr ) ) {
+ QStringList list = exp.capturedTexts();
+ QStringList::iterator iter = list.begin();
+ ++iter; // whole string!
+#undef GET
+#define GET( variable, def ) \
+ unsigned variable = def; \
+ if ( iter != list.end() ) { \
+ variable = ( *iter ).toUInt();\
+ ++iter; \
+ }
+ GET( year, 1 )
+ GET( month, 1 )
+ GET( day, 1 )
+ GET( hour, 0 )
+ GET( min, 0 )
+ GET( sec, 0 )
+#undef GET
+ // FIXME: this ignores the timezone
+ QDate date( year, month, day );
+ QTime time( hour, min, sec );
+ KLocale locale( "kghostview" );
+ return locale.formatDateTime( QDateTime( date, time ) );
+ }
+ kdDebug( 4500 ) << "parseDate failed." << endl;
+ return dateStr;
+ }
+}
+
+void InfoDialog::setup( const QString &fileName, const QString &documentTitle,
+ const QString &publicationDate )
+{
+ mFileLabel->setText( fileName );
+ mTitleLabel->setText( documentTitle );
+ mDateLabel->setText( parseDate( publicationDate ) );
+}
+
+#include "infodialog.moc"
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/infodialog.h b/kghostview/infodialog.h
new file mode 100644
index 00000000..1c857fc1
--- /dev/null
+++ b/kghostview/infodialog.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2000 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 _INFO_DIALOG_H_
+#define _INFO_DIALOG_H_
+
+class QLabel;
+
+#include <kdialogbase.h>
+
+class InfoDialog : public KDialogBase
+{
+ Q_OBJECT
+
+ public:
+ InfoDialog( QWidget *parent=0, const char *name=0, bool modal=true );
+ void setup( const QString &fileName, const QString &documentTitle,
+ const QString &publicationDate );
+
+ private:
+ QLabel *mFileLabel;
+ QLabel *mTitleLabel;
+ QLabel *mDateLabel;
+};
+
+#endif
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/kdscerrordialog.cpp b/kghostview/kdscerrordialog.cpp
new file mode 100644
index 00000000..601f5fc5
--- /dev/null
+++ b/kghostview/kdscerrordialog.cpp
@@ -0,0 +1,170 @@
+/**
+ * Copyright (C) 2001 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 <qlabel.h>
+#include <qlayout.h>
+#include <qtextedit.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kseparator.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+#include "kdscerrordialog.h"
+#include "kdscerrordialog.moc"
+
+KDSCErrorThreshold::KDSCErrorThreshold( int threshold,
+ KDSCErrorHandler* errorHandler ) :
+ _threshold( threshold ),
+ _errorHandler( errorHandler )
+{}
+
+KDSCErrorHandler::Response KDSCErrorThreshold::error( const KDSCError& err )
+{
+ if( _errorHandler != 0 && err.severity() >= _threshold )
+ return _errorHandler->error( err );
+ else
+ // Cancel is the default handling strategy for dsc_error_fn, so
+ // we keep it. This cancels error handling and *not* document
+ // parsing!
+ return Cancel;
+}
+
+KDSCErrorDialog::KDSCErrorDialog( QWidget* parent ) :
+ KDialog( parent, "dscerrordialog", true ),
+ _response( Ok )
+{
+ QVBoxLayout* vbox = new QVBoxLayout( this, marginHint(), spacingHint() );
+
+ _lineNumberLabel = new QLabel( this );
+ vbox->addWidget( _lineNumberLabel );
+
+ _lineLabel = new QTextEdit( this );
+ _lineLabel->setReadOnly( true );
+ vbox->addWidget( _lineLabel );
+
+ _descriptionLabel = new QLabel( this );
+ vbox->addWidget( _descriptionLabel );
+
+ KSeparator* sep = new KSeparator( KSeparator::HLine, this );
+ vbox->addWidget( sep );
+
+ QHBoxLayout* hbox = new QHBoxLayout( vbox );
+
+ hbox->addStretch();
+
+ _okButton = new KPushButton( KStdGuiItem::ok(), this );
+ hbox->addWidget( _okButton );
+ _cancelButton = new KPushButton( KStdGuiItem::cancel(), this );
+ hbox->addWidget( _cancelButton );
+ _ignoreAllButton = new QPushButton( i18n("Ignore All"), this );
+ hbox->addWidget( _ignoreAllButton );
+
+ connect( _okButton, SIGNAL( clicked() ), this, SLOT( slotOk() ) );
+ connect( _cancelButton, SIGNAL( clicked() ), this, SLOT( slotCancel() ) );
+ connect( _ignoreAllButton, SIGNAL( clicked() ),
+ this, SLOT( slotIgnoreAll() ) );
+}
+
+KDSCErrorHandler::Response KDSCErrorDialog::error( const KDSCError& err )
+{
+ switch( err.severity() )
+ {
+ case KDSCError::Information:
+ setCaption( i18n( "DSC Information" ) );
+ break;
+ case KDSCError::Warning:
+ setCaption( i18n( "DSC Warning" ) );
+ break;
+ case KDSCError::Error:
+ setCaption( i18n( "DSC Error" ) );
+ break;
+ }
+
+ _lineNumberLabel->setText( i18n( "On line %1:" ).arg( err.lineNumber() ) );
+ _lineLabel->setText( err.line() );
+ _descriptionLabel->setText( description( err.type() ) );
+
+ exec();
+
+ kdDebug(4500) << "KDSCErrorDialog: returning " << _response << endl;
+
+ return _response;
+}
+
+QString KDSCErrorDialog::description( KDSCError::Type type ) const
+{
+ switch( type )
+ {
+ case KDSCError::BBox:
+ return "TODO";
+ case KDSCError::EarlyTrailer:
+ return "TODO";
+ case KDSCError::EarlyEOF:
+ return "TODO";
+ case KDSCError::PageInTrailer:
+ return "TODO";
+ case KDSCError::PageOrdinal:
+ return "TODO";
+ case KDSCError::PagesWrong:
+ return "TODO";
+ case KDSCError::EPSNoBBox:
+ return "TODO";
+ case KDSCError::EPSPages:
+ return "TODO";
+ case KDSCError::NoMedia:
+ return "TODO";
+ case KDSCError::AtEnd:
+ return "TODO";
+ case KDSCError::DuplicateComment:
+ return "TODO";
+ case KDSCError::DuplicateTrailer:
+ return "TODO";
+ case KDSCError::BeginEnd:
+ return "TODO";
+ case KDSCError::BadSection:
+ return "TODO";
+ case KDSCError::LongLine:
+ return i18n( "Lines in DSC documents must be shorter than 255 "
+ "characters." );
+ case KDSCError::IncorrectUsage:
+ return "TODO";
+ default: return "TODO";
+ }
+}
+
+void KDSCErrorDialog::slotOk()
+{
+ _response = Ok;
+ accept();
+}
+
+void KDSCErrorDialog::slotCancel()
+{
+ _response = Cancel;
+ accept();
+}
+
+void KDSCErrorDialog::slotIgnoreAll()
+{
+ _response = IgnoreAll;
+ accept();
+}
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/kdscerrordialog.h b/kghostview/kdscerrordialog.h
new file mode 100644
index 00000000..0aee24d2
--- /dev/null
+++ b/kghostview/kdscerrordialog.h
@@ -0,0 +1,74 @@
+/**
+ * Copyright (C) 2001 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 KDSCERRORDIALOG_H
+#define KDSCERRORDIALOG_H
+
+#include <kdialog.h>
+
+#include "dscparse_adapter.h"
+
+class QLabel;
+class QPushButton;
+class QTextEdit;
+
+class KDSCErrorThreshold : public KDSCErrorHandler
+{
+public:
+ KDSCErrorThreshold( int threshold, KDSCErrorHandler* );
+
+ Response error( const KDSCError& );
+
+private:
+ int _threshold;
+ KDSCErrorHandler* _errorHandler;
+};
+
+class KDSCErrorDialog : public KDialog, public KDSCErrorHandler
+{
+ Q_OBJECT
+
+public:
+ KDSCErrorDialog( QWidget* parent = 0 );
+
+ Response error( const KDSCError& );
+
+protected:
+ QString description( KDSCError::Type ) const;
+
+protected slots:
+ void slotOk();
+ void slotCancel();
+ void slotIgnoreAll();
+
+private:
+ QLabel* _lineNumberLabel;
+ QTextEdit* _lineLabel;
+ QLabel* _descriptionLabel;
+
+ QPushButton* _okButton;
+ QPushButton* _cancelButton;
+ QPushButton* _ignoreAllButton;
+
+ Response _response;
+};
+
+#endif
+
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/kghostview.desktop b/kghostview/kghostview.desktop
new file mode 100644
index 00000000..66d3ee3f
--- /dev/null
+++ b/kghostview/kghostview.desktop
@@ -0,0 +1,86 @@
+[Desktop Entry]
+Name=KGhostView
+Name[af]=Kghostview
+Name[ar]=برنامج KGhostView
+Name[eo]=Postskriptrigardilo
+Name[hi]=के-घोस्ट-व्यू
+Name[hu]=KGhostview
+Name[ne]=केडीई घोस्ट दृश्य
+Name[sv]=Kghostview
+Name[ta]=கேமற்றொரு காட்சி
+Name[tr]=GhostView
+Name[ven]=Mbonalelo ya tshipuku tsha K
+Name[xh]=Imboniselo yeKGhost
+MimeType=application/pdf;application/postscript;image/x-eps;application/x-gzpostscript;application/illustrator;
+InitialPreference=6
+Exec=kghostview %u -caption "%c" %i %m
+Icon=kghostview
+Type=Application
+DocPath=kghostview/index.html
+GenericName=PS/PDF Viewer
+GenericName[af]=Ps/Pdf Aansig
+GenericName[ar]=عارض PS/PDF
+GenericName[bg]=Преглед на документи PS/PDF
+GenericName[br]=Gweler PS/PDF
+GenericName[bs]=Preglednik PS/PDF dokumenata
+GenericName[ca]=Visualitzador de PS/PDF
+GenericName[cs]=Prohlížeč PS/PDF souborů
+GenericName[cy]=Gwelydd PS/PDF
+GenericName[da]=PS/PDF-fremviser
+GenericName[de]=PS/PDF-Betrachter
+GenericName[el]=Προβολέας PS/PDF
+GenericName[eo]=PS/PDF-rigardilo
+GenericName[es]=Visor de documentos PS/PDF
+GenericName[et]=PS/PDF-failide näitaja
+GenericName[eu]=PS/PDF ikustailua
+GenericName[fa]=مشاهده‌گر PS/PDF
+GenericName[fi]=PS/PDF-näytin
+GenericName[fr]=Afficheur PostScript et PDF
+GenericName[ga]=Amharcán PS/PDF
+GenericName[gl]=Visor PS/PDF
+GenericName[he]=מציג PS/PDF
+GenericName[hi]=PS/PDF प्रदर्शक
+GenericName[hr]=Preglednik PS/PDF dokumenata
+GenericName[hu]=PS/PDF-megjelenítő
+GenericName[is]=PS/PDF sjá
+GenericName[it]=Visore PS/PDF
+GenericName[ja]=PS/PDF ビューア
+GenericName[kk]=PS/PDF файлдарын қарау
+GenericName[km]=កម្មវិធី​មើល PS/PDF
+GenericName[lt]=PS/PDF žiūriklis
+GenericName[lv]=PS/PDF Skatītājs
+GenericName[ms]=Pemapar PS/PDF
+GenericName[nb]=PS-/PDF-fremviser
+GenericName[nds]=PostScript-/PDF-Kieker
+GenericName[ne]=PS/PDF दर्शक
+GenericName[nl]=PostScript/PDF-weergaveprogramma
+GenericName[nn]=PS/PDF-lesar
+GenericName[nso]=Molebeledi wa PS/PDF
+GenericName[pa]=PS/PDF ਦਰਸ਼ਕ
+GenericName[pl]=Przeglądarka plików PS/PDF
+GenericName[pt]=Visualizador de PS/PDF
+GenericName[pt_BR]=Visualizador PDF/PS
+GenericName[ro]=Vizualizor PS/PDF
+GenericName[ru]=Просмотр Postscript и PDF
+GenericName[se]=PS/PDF-čájeheaddji
+GenericName[sk]=Prehliadač PS/PDF
+GenericName[sl]=Pregledovalnik datotek PS/PDF
+GenericName[sr]=PS/PDF приказивач
+GenericName[sr@Latn]=PS/PDF prikazivač
+GenericName[sv]=PS/PDF-visare
+GenericName[ta]=PS/PDF காட்சி
+GenericName[tg]=Хондани PS/PDF
+GenericName[th]=เครื่องมือแสดงแฟ้มโพสต์สคริปต์ PS/PDF
+GenericName[tr]=PS/PDF Görüntüleyici
+GenericName[uk]=Переглядач PDF/PS
+GenericName[uz]=PS/PDF koʻruvchi
+GenericName[uz@cyrillic]=PS/PDF кўрувчи
+GenericName[ven]=Muvhoni wa PS/PDF
+GenericName[wa]=Håyneu di documints PS/PDF
+GenericName[xh]=Umboniseli we PS/PDF
+GenericName[zh_CN]=PS/PDF 查看器
+GenericName[zh_HK]=PS/PDF 檢視器
+GenericName[zh_TW]=PS/PDF 檢視器
+GenericName[zu]=Umboniseli we PS/PDF
+Terminal=false
+Categories=Qt;KDE;Graphics;
diff --git a/kghostview/kghostview.kcfg b/kghostview/kghostview.kcfg
new file mode 100644
index 00000000..362191f3
--- /dev/null
+++ b/kghostview/kghostview.kcfg
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="kghostviewrc"/>
+ <group name="General">
+ <entry name="Antialiasing" type="Bool">
+ <label>Whether to use anti-aliasing.</label>
+ <whatsthis>Anti-aliasing makes the result look better, specially regarding text, but it makes the display take longer</whatsthis>
+ </entry>
+ <entry name="Palette" type="Enum">
+ <choices>
+ <choice name="Color" />
+ <choice name="Grayscale" />
+ <choice name="Monochrome" />
+ </choices>
+ </entry>
+ <entry name="Messages" type="Bool">
+ <label>Whether to see a window with Ghostscript messages</label>
+ <whatsthis>Whether to see a window with Ghostscript messages. This can give you additional information on the files you see. In case of an error, a window will popup regardless of this option.</whatsthis>
+ <default>false</default>
+ </entry>
+ <entry name="PlatformFonts" type="Bool">
+ <label>Use Platform Fonts</label>
+ <whatsthis></whatsthis>
+ <default>true</default>
+ </entry>
+ <entry name="ShowPageList" type="Bool">
+ <label>Whether to show the page list</label>
+ <whatsthis></whatsthis>
+ <default>true</default>
+ </entry>
+ <entry name="ShowPageNames" type="Bool">
+ <label>Whether to show page names instead of numbers</label>
+ <whatsthis>Sometimes information is available on page names which can be used in the list panner instead of just the numbers. Most often, these names are, in fact, another numbering. Often, the first few pages use roman numbering (i, ii, iii, iv ...) followed by arabic numbers from one (1, 2, 3...) when the real content starts.</whatsthis>
+ <default>true</default>
+ </entry>
+ <entry name="ShowScrollBars" type="Bool">
+ <label>Whether to show scroll bars when pages are too big</label>
+ <whatsthis></whatsthis>
+ <default>true</default>
+ </entry>
+ <entry name="WatchFile" type="Bool">
+ <label>Watch File</label>
+ <whatsthis>If this is on, then the file will be reloaded whenever it changes on disk</whatsthis>
+ <default>false</default>
+ </entry>
+ </group>
+ <group name="Ghostscript">
+ <entry name="Interpreter" type="String">
+ <label>The ghostscript interpreter to use</label>
+ <whatsthis>Kghostview does not, itself, display the document: it relies on ghostscript, and therefore needs it to be available. Here you can define the ghostscript interpreter to use.</whatsthis>
+ <default>gs</default>
+ </entry>
+ <entry name="AntialiasingArguments" type="String">
+ <label>Arguments for ghostscript if running with antialiasing</label>
+ <whatsthis></whatsthis>
+ <default>-sDEVICE=x11 -dTextAlphaBits=4 -dGraphicsAlphaBits=2 -dMaxBitmap=10000000</default>
+ </entry>
+ <entry name="NonAntialiasingArguments" type="String">
+ <label></label>
+ <whatsthis></whatsthis>
+ <default>-sDEVICE=x11</default>
+ </entry>
+ <entry name="Version" type="String">
+ <label>This is the ghostscript version you are running</label>
+ <whatsthis>This is the version of ghostscript you are running. Normally you will not need to change this since it gets detected automatically.</whatsthis>
+ </entry>
+ <entry name="RedetectionCounter" type="UInt">
+ <label>This is an internal setting</label>
+ <whatsthis></whatsthis>
+ </entry>
+ </group>
+</kcfg>
+<!-- vim:set ts=4 -->
+
diff --git a/kghostview/kghostview.upd b/kghostview/kghostview.upd
new file mode 100644
index 00000000..a61fffaf
--- /dev/null
+++ b/kghostview/kghostview.upd
@@ -0,0 +1,13 @@
+Id=1changeToKConfigXT
+File=kghostviewrc
+Group=General
+Key=Platform Fonts,PlatformFonts
+Group=Ghostscript
+Key=Antialiasing arguments,AntialiasingArguments
+Key=Non-antialiasing arguments,NonAntialiasingArguments
+Key=Redetection Counter,RedetectionCounter
+#
+Id=2changeToKConfigXT
+File=kghostviewrc
+Group=General
+Script=update-to-xt-names.pl,perl
diff --git a/kghostview/kghostview_part.desktop b/kghostview/kghostview_part.desktop
new file mode 100644
index 00000000..a468fc02
--- /dev/null
+++ b/kghostview/kghostview_part.desktop
@@ -0,0 +1,19 @@
+[Desktop Entry]
+Name=KGhostView
+Name[af]=Kghostview
+Name[ar]=برنامج KGhostView
+Name[eo]=Postskriptrigardilo
+Name[hi]=के-घोस्ट-व्यू
+Name[hu]=KGhostview
+Name[ne]=केडीई घोस्ट दृश्य
+Name[sv]=Kghostview
+Name[ta]=கேமற்றொரு காட்சி
+Name[tr]=GhostView
+Name[ven]=Mbonalelo ya tshipuku tsha K
+Name[xh]=Imboniselo yeKGhost
+MimeType=application/pdf;application/postscript;image/x-eps;application/x-gzpostscript;application/illustrator
+InitialPreference=6
+Icon=kghostview
+ServiceTypes=KParts/ReadOnlyPart,Browser/View
+X-KDE-Library=libkghostviewpart
+Type=Service
diff --git a/kghostview/kghostviewui.rc b/kghostview/kghostviewui.rc
new file mode 100644
index 00000000..3903a725
--- /dev/null
+++ b/kghostview/kghostviewui.rc
@@ -0,0 +1,43 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="KGhostViewShell" version="11">
+<State name="initState">
+ <Disable>
+ <Action name="file_print" />
+ <Action name="reload" />
+ <Action name="maximize"/>
+ <Action name="fullscreen"/>
+ <Action name="showmenubar"/>
+ </Disable>
+</State>
+<State name="documentState">
+ <Enable>
+ <Action name="file_print" />
+ <Action name="reload" />
+ <Action name="fullscreen"/>
+ <Action name="showmenubar"/>
+ <Action name="maximize"/>
+ </Enable>
+</State>
+<MenuBar>
+ <Menu name="file">
+ <DefineGroup name="file_save" append="save_merge" />
+ <DefineGroup name="file_print" append="print_merge" />
+ </Menu>
+ <Menu name="edit">
+ <MergeLocal/>
+ </Menu>
+ <Menu name="view">
+ <Action name="reload" />
+ <Action name="maximize"/>
+ <Action name="fullscreen"/>
+ </Menu>
+ <Menu name="settings">
+ <Action name="option_show_toolbar" />
+ </Menu>
+ <Merge/>
+</MenuBar>
+<ToolBar name="mainToolBar">
+ <text>&amp;Main Toolbar</text>
+</ToolBar>
+</kpartgui>
+
diff --git a/kghostview/kgv.h b/kghostview/kgv.h
new file mode 100644
index 00000000..db7a1679
--- /dev/null
+++ b/kghostview/kgv.h
@@ -0,0 +1,15 @@
+#ifndef KGV_H
+#define KGV_H
+
+#include <qvaluelist.h>
+
+namespace KGV
+{
+
+typedef QValueList<int> PageList;
+
+}
+
+#endif
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/kgv_miniwidget.cpp b/kghostview/kgv_miniwidget.cpp
new file mode 100644
index 00000000..33045b17
--- /dev/null
+++ b/kghostview/kgv_miniwidget.cpp
@@ -0,0 +1,573 @@
+/**
+ * Copyright (C) 1997-2003 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 <math.h>
+
+#include <qlistbox.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kinstance.h>
+#include <kdeversion.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+// KLineEditDlg is depricated as of 3.2. use KInputDialog instead
+#if KDE_VERSION >= KDE_MAKE_VERSION(3,1,90)
+ #include <kinputdialog.h>
+#else
+ #include <qvalidator.h>
+ #include <qwidget.h>
+ #include <klineeditdlg.h>
+#endif
+
+#include <config.h>
+#include <stdlib.h>
+
+#include "infodialog.h"
+#include "marklist.h"
+#include "kgvdocument.h"
+#include "kgv_view.h"
+#include "version.h"
+#include "scrollbox.h"
+
+#include "kgv_miniwidget.h"
+
+#include "kpswidget.h"
+
+using namespace KGV;
+
+KGVMiniWidget::KGVMiniWidget( KGVPart* part, const char* name ) :
+ QObject( part, name ),
+ _document( 0 ),
+ _part( part ),
+ _psWidget( 0 ),
+ _usePageLabels( true ),
+ _visiblePage( -1 )
+{
+ KLocale locale( "kghostview" );
+ _fallBackPageMedia = pageSizeToString(
+ static_cast< QPrinter::PageSize >( locale.pageSize() ) );
+ _thumbnailService = new ThumbnailService( this );
+
+ connect( this, SIGNAL( newPageShown( int ) ),
+ SLOT( updateStatusBarText( int ) ) );
+}
+
+void KGVMiniWidget::setDocument( KGVDocument* document )
+{
+ _document = document;
+ if( _document )
+ connect( _document, SIGNAL( completed() ),
+ SLOT( slotDocumentOpened() ) );
+}
+
+QString KGVMiniWidget::pageSizeToString( QPrinter::PageSize pageSize )
+{
+ switch( pageSize )
+ {
+ case QPrinter::A3: return "A3";
+ case QPrinter::A4: return "A4";
+ case QPrinter::A5: return "A5";
+ case QPrinter::B4: return "B4";
+ case QPrinter::Ledger: return "Ledger";
+ case QPrinter::Legal: return "Legal";
+ case QPrinter::Letter: return "Letter";
+ default: return "Unknown";
+ }
+}
+
+void KGVMiniWidget::reset()
+{
+ /*
+ if( _psWidget )
+ _psWidget->disableInterpreter();
+ */
+
+ // return to document defaults
+ _options.reset();
+ emit setStatusBarText( "" );
+}
+
+void KGVMiniWidget::setPSWidget( KPSWidget* psWidget )
+{
+ _psWidget = psWidget;
+ // setMagnification( _magnification );
+ connect( _psWidget, SIGNAL( newPageImage( QPixmap ) ),
+ this, SLOT( sendPage() ) );
+}
+
+void KGVMiniWidget::goToPage()
+{
+#if KDE_VERSION >= KDE_MAKE_VERSION(3,1,90)
+ int num;
+ bool ok = false;
+ num = KInputDialog::getInteger(i18n("Go to Page"), i18n("Page:"), 1,
+ 1, dsc()->page_count(), 1, 10, &ok, _part->widget());
+ if (ok) goToPage( num-1 );
+#else
+ QString num;
+ bool b = false;
+ num = KLineEditDlg::getText(i18n("Go to Page"), i18n("Page:"), QString::null, &b, _part->widget(), new QIntValidator(1, dsc()->page_count(), this));
+ if (b) goToPage( num.toInt() - 1 );
+#endif
+}
+
+void KGVMiniWidget::info()
+{
+ if( !document()->isOpen() )
+ return;
+
+ InfoDialog* infoDialog = new InfoDialog( _part->widget(), "info", true );
+ infoDialog->setup( _part->url().prettyURL(),
+ dsc()->dsc_title(), dsc()->dsc_date() );
+ infoDialog->exec();
+ delete infoDialog;
+}
+
+void KGVMiniWidget::goToPage( int page )
+{
+ if( _options.page() != page ) {
+ _options.setPage( page );
+ showPage( _options.page() );
+ }
+}
+
+void KGVMiniWidget::zoomIn()
+{
+ if ( _options.zoomIn() ) showPage( _options.page() );
+}
+
+void KGVMiniWidget::zoomOut()
+{
+ if ( _options.zoomOut() ) showPage( _options.page() );
+}
+
+bool KGVMiniWidget::atMaxZoom() const
+{
+ return !_options.canZoomIn();
+}
+
+bool KGVMiniWidget::atMinZoom() const
+{
+ return !_options.canZoomOut();
+}
+
+void KGVMiniWidget::fitWidth( unsigned int width )
+{
+ if ( (orientation() == CDSC_LANDSCAPE) || (orientation() == CDSC_SEASCAPE) )
+ setMagnification( ( (double)width / QPaintDevice::x11AppDpiY()) /
+ ( (double)boundingBox().height() / 72) );
+ else // default
+ setMagnification( ( (double)width / QPaintDevice::x11AppDpiX() ) /
+ ( (double)boundingBox().width() / 72) );
+}
+
+void KGVMiniWidget::fitHeight( unsigned int height )
+{
+ if ( (orientation() == CDSC_LANDSCAPE) || (orientation() == CDSC_SEASCAPE) )
+ setMagnification( ( (double)height / QPaintDevice::x11AppDpiY()) /
+ ( (double)boundingBox().width() / 72) );
+ else //default
+ setMagnification( ( (double)height / QPaintDevice::x11AppDpiY()) /
+ ( (double)boundingBox().height() / 72) );
+}
+
+void KGVMiniWidget::fitWidthHeight( unsigned int w, unsigned int h )
+{
+ double magnification = std::min<double>(
+ ( ( double )h / QPaintDevice::x11AppDpiY() ) /
+ ( ( double )boundingBox().height() / 72.0 ),
+ ( ( double )w / QPaintDevice::x11AppDpiX() ) /
+ ( ( double )boundingBox().width() / 72.0 ) );
+ setMagnification( magnification );
+}
+
+void KGVMiniWidget::firstPage()
+{
+ goToPage( 0 );
+}
+
+void KGVMiniWidget::lastPage()
+{
+ if ( !dsc() ) return;
+
+ goToPage( dsc()->page_count() - 1 );
+}
+
+bool KGVMiniWidget::prevPage()
+{
+ if ( !dsc() ) return false;
+
+ int new_page = 0;
+
+ if( dsc()->isStructured() ) {
+ new_page = _options.page() - 1;
+ if( new_page < 0 )
+ return false;
+ }
+
+ goToPage( new_page );
+ return true;
+}
+
+bool KGVMiniWidget::nextPage()
+{
+ if ( !dsc() ) return false;
+
+ int new_page = 0;
+
+ if( dsc()->isStructured() ) {
+ new_page = _options.page() + 1;
+ if( (unsigned int)new_page >= dsc()->page_count() )
+ return false;
+ }
+
+ goToPage( new_page );
+ return true;
+}
+
+
+void KGVMiniWidget::redisplay ()
+{
+ if( !document()->psFile() )
+ return;
+
+ _psWidget->stopInterpreter();
+ showPage( _options.page() );
+}
+
+void KGVMiniWidget::restoreOverrideOrientation()
+{
+ _options.restoreOverrideOrientation();
+ showPage( _options.page() );
+}
+
+void KGVMiniWidget::setOverrideOrientation( CDSC_ORIENTATION_ENUM orientation )
+{
+ _options.setOverrideOrientation( orientation );
+ showPage( _options.page() );
+}
+
+CDSC_ORIENTATION_ENUM KGVMiniWidget::orientation() const
+{
+ if( _options.overrideOrientation() != CDSC_ORIENT_UNKNOWN )
+ return _options.overrideOrientation();
+ else if( dsc()->page_orientation() != CDSC_ORIENT_UNKNOWN )
+ return static_cast< CDSC_ORIENTATION_ENUM >( dsc()->page_orientation());
+ else if( dsc()->bbox().get() != 0
+ && dsc()->bbox()->width() > dsc()->bbox()->height() )
+ return CDSC_LANDSCAPE;
+ else
+ return CDSC_PORTRAIT;
+}
+
+CDSC_ORIENTATION_ENUM KGVMiniWidget::orientation( int pagenumber ) const
+{
+ if ( !dsc() || unsigned( pagenumber ) >= dsc()->page_count() ) {
+ return orientation();
+ }
+ if( _options.overrideOrientation() != CDSC_ORIENT_UNKNOWN ) {
+ return _options.overrideOrientation();
+ }
+
+ if( dsc()->page()[ pagenumber ].orientation != CDSC_ORIENT_UNKNOWN ) {
+ return static_cast< CDSC_ORIENTATION_ENUM >( dsc()->page()[ pagenumber ].orientation );
+ }
+ if( dsc()->page_orientation() != CDSC_ORIENT_UNKNOWN ) {
+ return static_cast< CDSC_ORIENTATION_ENUM >( dsc()->page_orientation());
+ }
+ if( !dsc()->epsf() ) {
+ return CDSC_PORTRAIT;
+ }
+ if( dsc()->bbox().get() != 0
+ && dsc()->bbox()->width() > dsc()->bbox()->height() ) {
+ return CDSC_LANDSCAPE;
+ }
+ return CDSC_PORTRAIT;
+}
+
+void KGVMiniWidget::restoreOverridePageMedia()
+{
+ _options.restoreOverridePageMedia();
+ redisplay();
+ showPage( _options.page() );
+}
+
+void KGVMiniWidget::setOverridePageMedia( const QString& mediaName )
+{
+ _options.setOverridePageMedia( mediaName );
+ showPage( _options.page() );
+}
+
+QString KGVMiniWidget::pageMedia() const
+{
+ if( !_options.overridePageMedia().isNull() )
+ return _options.overridePageMedia();
+ else if( dsc()->page_media() != 0 )
+ return QString( dsc()->page_media()->name );
+ else if( dsc()->bbox().get() != 0 )
+ return QString( "BoundingBox" );
+ else
+ return _fallBackPageMedia;
+}
+
+QString KGVMiniWidget::pageMedia( int pagenumber ) const
+{
+ kdDebug( 4500 ) << "KGVMiniWidget::pageMedia( " << pagenumber << " )" << endl;
+ if ( !dsc() ) return pageMedia();
+ if ( unsigned( pagenumber ) >= dsc()->page_count() ) return pageMedia();
+ if( !_options.overridePageMedia().isNull() )
+ return _options.overridePageMedia();
+ else if( dsc()->page()[ pagenumber ].media != 0 )
+ return QString( dsc()->page()[ pagenumber ].media->name );
+ else if( dsc()->page_media() != 0 )
+ return QString( dsc()->page_media()->name );
+ else if( dsc()->bbox().get() != 0 )
+ return QString( "BoundingBox" );
+ else
+ return _fallBackPageMedia;
+}
+
+KDSCBBOX KGVMiniWidget::boundingBox() const
+{
+ QString currentMedia = pageMedia();
+ if( currentMedia == "BoundingBox" )
+ return KDSCBBOX( *dsc()->bbox().get() );
+ else {
+ QSize size = document()->computePageSize( currentMedia );
+ return KDSCBBOX( 0, 0, size.width(), size.height() );
+ }
+}
+
+KDSCBBOX KGVMiniWidget::boundingBox( int pageNo ) const
+{
+ QString currentMedia = pageMedia( pageNo );
+ if( currentMedia == "BoundingBox" )
+ return KDSCBBOX( *dsc()->bbox().get() );
+ else {
+ QSize size = document()->computePageSize( currentMedia );
+ return KDSCBBOX( 0, 0, size.width(), size.height() );
+ }
+}
+
+bool KGVMiniWidget::atFirstPage() const
+{
+ return ( _options.page() == 0 );
+}
+
+bool KGVMiniWidget::atLastPage() const
+{
+ return ( _options.page() == static_cast<int>( dsc()->page_count() ) - 1 );
+}
+
+void KGVMiniWidget::showPage( int pagenumber )
+{
+ if( !document()->isOpen() )
+ return;
+
+ kdDebug(4500) << "KGVMiniWidget::showPage( " << pagenumber << " )" << endl;
+
+ static_cast< QWidget* >( _psWidget->parent() )->show();
+
+ _psWidget->setFileName(_document->fileName(), dsc()->isStructured() );
+ _psWidget->clear();
+
+ if( dsc()->isStructured() )
+ {
+ // Coerce page number to fall in range
+ if( ( unsigned int)pagenumber >= dsc()->page_count() )
+ pagenumber = dsc()->page_count() - 1;
+ if( pagenumber < 0 )
+ pagenumber = 0;
+
+ _options.setPage( pagenumber );
+
+
+ _psWidget->setOrientation( orientation( _options.page() ) );
+ _psWidget->setBoundingBox( boundingBox( _options.page() ) );
+ _psWidget->setMagnification( _options.magnification() );
+
+ if( !_psWidget->isInterpreterRunning() )
+ {
+ // Start interpreter, send preamble and send the current page.
+ if( _psWidget->startInterpreter() )
+ {
+ _psWidget->sendPS( psFile(), dsc()->beginprolog(),
+ dsc()->endprolog() );
+ _psWidget->sendPS( psFile(), dsc()->beginsetup(),
+ dsc()->endsetup() );
+ _psWidget->sendPS( psFile(), dsc()->page()[ _options.page() ].begin,
+ dsc()->page()[ _options.page() ].end );
+ _visiblePage = _options.page();
+ }
+ }
+ else
+ sendPage();
+ }
+ else
+ {
+ _psWidget->setOrientation( orientation() );
+ _psWidget->setBoundingBox( boundingBox() );
+ _psWidget->setMagnification( _options.magnification() );
+
+ if( !_psWidget->isInterpreterRunning() )
+ {
+ // This is not a structured document -- start interpreter
+ _psWidget->startInterpreter();
+ if( !dsc() )
+ _psWidget->stopInterpreter();
+ }
+ else if( _psWidget->isInterpreterReady() )
+ _psWidget->nextPage();
+ else
+ {
+ /*
+ KNotifyClient::userEvent
+ (i18n("KGhostview cannot load the document, \"%1\".\n"
+ "It appears to be broken.").arg( _fileName ),
+ KNotifyClient::Messagebox);
+ _psWidget->disableInterpreter();
+ _psFile=0;
+
+ //TODO: More to do to turn off display?
+ */
+ return;
+ }
+ }
+ // Do this after ajusting pagenumber above
+ _thumbnailService->cancelRequests( -1 , _part->scrollBox(), SLOT( setThumbnail( QPixmap ) ) );
+ _thumbnailService->delayedGetThumbnail( pagenumber, _part->scrollBox(), SLOT( setThumbnail( QPixmap ) ), true );
+
+ emit newPageShown( pagenumber );
+}
+
+void KGVMiniWidget::sendPage()
+{
+ // Send the page to the interpreter.
+ if( !_psWidget->isInterpreterBusy() && _visiblePage != _options.page() )
+ {
+ // Interpreter ready - Fire off next page
+ _psWidget->clear();
+ _psWidget->nextPage();
+ _psWidget->sendPS( psFile(), dsc()->page()[ _options.page() ].begin,
+ dsc()->page()[ _options.page() ].end );
+ _visiblePage = _options.page();
+ }
+}
+
+void KGVMiniWidget::updateStatusBarText( int pageNumber )
+{
+ if( !dsc() )
+ return;
+
+ if( dsc()->isStructured() )
+ {
+ QString text;
+
+ if( pageNumber == -1 )
+ text = i18n( "Page 1" );
+ else
+ if( !_usePageLabels || document()->format() == KGVDocument::PDF )
+ text = i18n( "Page %1 of %2" )
+ .arg( pageNumber + 1 )
+ .arg( dsc()->page_count() );
+ else
+ text = i18n( "Page %1 (%2 of %3)" )
+ .arg( dsc()->page()[ _options.page() ].label )
+ .arg( pageNumber + 1 )
+ .arg( dsc()->page_count() );
+
+ emit setStatusBarText( text );
+ }
+}
+
+void KGVMiniWidget::buildTOC()
+{
+ if( !dsc() )
+ return;
+
+ // Build table of contents
+ // Well, that's what it used to be called !!
+
+ int last_page = 0;
+
+ MarkList* marklist = _part->markList();
+
+ if( dsc()->isStructured() ) {
+ if( _usePageLabels )
+ for( unsigned i = 0; i < dsc()->page_count(); ++i ) {
+ unsigned j = i;
+ if( dsc()->page_order() == CDSC_DESCEND )
+ j = ( dsc()->page_count() - 1 ) - i;
+ last_page = atoi( dsc()->page()[j].label );
+ }
+
+ // finally set marked list
+ QString s;
+ for( unsigned i = 0; i < dsc()->page_count(); ++i ) {
+ const char * label = dsc()->page()[ i ].label;
+ QString tip = QString::fromLocal8Bit( label ? label : "" );
+
+ if( !_usePageLabels )
+ s.setNum( i + 1 );
+ else
+ s = tip;
+
+ marklist->insertItem( s, i, tip );
+ }
+ }
+ else {
+ marklist->insertItem( QString::fromLatin1( "1" ), 0 );
+ }
+}
+
+void KGVMiniWidget::setMagnification( double magnification )
+{
+ if ( magnification != _options.magnification() ) {
+ _options.setMagnification( magnification );
+ showPage( _options.page() );
+ }
+}
+
+void KGVMiniWidget::enablePageLabels( bool b )
+{
+ if( _usePageLabels != b )
+ {
+ _usePageLabels = b;
+ updateStatusBarText( _options.page() );
+ buildTOC();
+ }
+}
+
+void KGVMiniWidget::slotDocumentOpened()
+{
+ buildTOC();
+ showPage( _options.page() );
+}
+
+void KGVMiniWidget::setDisplayOptions( const DisplayOptions& newOptions )
+{
+ _options = newOptions;
+}
+
+#include "kgv_miniwidget.moc"
+
+
+// vim:sw=4:sts=4:ts=8:sta:tw=78:noet
diff --git a/kghostview/kgv_miniwidget.h b/kghostview/kgv_miniwidget.h
new file mode 100644
index 00000000..3c445d14
--- /dev/null
+++ b/kghostview/kgv_miniwidget.h
@@ -0,0 +1,173 @@
+/**
+ * Copyright (C) 1997-2003 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 __KGV_MINIWIDGET_H
+#define __KGV_MINIWIDGET_H
+
+#include <qprinter.h>
+
+#include "dscparse_adapter.h"
+#include "kgv.h"
+#include "kgvdocument.h"
+#include "displayoptions.h"
+
+#include "thumbnailservice.h"
+
+#include <qobject.h>
+
+class InfoDialog;
+class KGVPart;
+class KPSWidget;
+class MarkList;
+
+class KGVMiniWidget : public QObject
+{
+ Q_OBJECT
+
+public:
+ KGVMiniWidget( KGVPart* part, const char* name = 0 );
+
+ void setDocument( KGVDocument* document );
+
+ static QString pageSizeToString( QPrinter::PageSize );
+
+ void setPSWidget( KPSWidget* psWidget );
+
+ void setDisplayOptions( const DisplayOptions& newOptions );
+ const DisplayOptions& displayOptions() const { return _options; }
+
+ void restoreOverrideOrientation();
+ void setOverrideOrientation( CDSC_ORIENTATION_ENUM );
+
+ void restoreOverridePageMedia();
+ void setOverridePageMedia( const QString& mediaName );
+
+ ThumbnailService* getThumbnailService() { return _thumbnailService; }
+
+ /**
+ * Enable/disable fancy, document-supplied page labels.
+ **/
+ void enablePageLabels( bool e = true );
+ bool arePageLabelsEnabled () { return _usePageLabels; }
+
+ /**
+ * Return true if the current page is the first page, false otherwise.
+ */
+ bool atFirstPage() const;
+ /**
+ * Return true if the current page is the last page, false otherwise.
+ */
+ bool atLastPage() const;
+
+ /**
+ * Return true if we're zoomed in fully, false otherwise.
+ */
+ bool atMaxZoom() const;
+ /**
+ * Return true if we're zoomed out fully, false otherwise.
+ */
+ bool atMinZoom() const;
+
+ int currentPage() const { return _options.page(); }
+
+public slots:
+ bool prevPage();
+ bool nextPage();
+ void firstPage();
+ void lastPage();
+ void goToPage();
+ void goToPage( int page );
+
+ void zoomIn();
+ void zoomOut();
+
+ void fitWidth( unsigned int );
+ void fitHeight( unsigned int );
+ void fitWidthHeight( unsigned int, unsigned int );
+
+ void info();
+
+ /**
+ * Redisplay the page if the file has changed on disk.
+ **/
+ void redisplay();
+
+signals:
+ /**
+ * Page changed.
+ */
+ void newPageShown( int pageNumber ); // Should this one be under DOCUMENT?
+
+ void newPageImage( QPixmap image );
+
+ void setStatusBarText( const QString& );
+
+protected:
+ void showPage( int pageNumber );
+ void buildTOC();
+
+protected slots:
+ void sendPage();
+ void updateStatusBarText( int pageNumber );
+
+protected:
+ void reset();
+
+private:
+
+ CDSC_ORIENTATION_ENUM orientation() const;
+ CDSC_ORIENTATION_ENUM orientation( int pageNo ) const;
+
+ QString pageMedia() const;
+ QString pageMedia( int pageNo ) const;
+
+ KDSCBBOX boundingBox() const;
+ KDSCBBOX boundingBox( int pageNo ) const;
+
+ void setMagnification( double );
+
+ KDSC* const dsc() const
+ { return _document ? _document->dsc() : 0; }
+ FILE* psFile()
+ { return document()->psFile(); }
+ KGVDocument* const document() const
+ { return _document; }
+
+private slots:
+ void slotDocumentOpened();
+
+private:
+
+ friend class ThumbnailService;
+ KGVDocument* _document;
+
+ KGVPart* _part;
+ KPSWidget* _psWidget;
+ ThumbnailService* _thumbnailService;
+
+ bool _usePageLabels;
+
+ int _visiblePage;
+
+ DisplayOptions _options;
+ QString _fallBackPageMedia;
+};
+
+#endif
+
+// vim:sw=4:sts=4:ts=8:sta:tw=78:noet
diff --git a/kghostview/kgv_part.rc b/kghostview/kgv_part.rc
new file mode 100644
index 00000000..1ecc846a
--- /dev/null
+++ b/kghostview/kgv_part.rc
@@ -0,0 +1,110 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="KGhostView" version="22">
+<State name="initState">
+ <Disable>
+ <Action name="file_save_as" />
+ <Action name="info" />
+ <Action name="orientation_menu" />
+ <Action name="media_menu" />
+ <Action name="zoomOut" />
+ <Action name="zoomTo" />
+ <Action name="zoomIn" />
+ <Action name="fit_to_page" />
+ <Action name="fit_to_screen" />
+ <Action name="prevPage" />
+ <Action name="nextPage" />
+ <Action name="goToStart" />
+ <Action name="goToEnd" />
+ <Action name="goToPage" />
+ <Action name="readUp" />
+ <Action name="readDown" />
+ <Action name="mark_current" />
+ <Action name="mark_all" />
+ <Action name="mark_even" />
+ <Action name="mark_odd" />
+ <Action name="toggle" />
+ <Action name="remove" />
+ <Action name="no_flicker" />
+ </Disable>
+</State>
+<State name="documentState">
+ <Enable>
+ <Action name="file_save_as" />
+ <Action name="info" />
+ <Action name="orientation_menu" />
+ <Action name="media_menu" />
+ <Action name="zoomOut" />
+ <Action name="zoomTo" />
+ <Action name="zoomIn" />
+ <Action name="fit_to_page" />
+ <Action name="fit_to_screen" />
+ <Action name="prevPage" />
+ <Action name="nextPage" />
+ <Action name="goToStart" />
+ <Action name="goToEnd" />
+ <Action name="goToPage" />
+ <Action name="readUp" />
+ <Action name="readDown" />
+ <Action name="mark_current" />
+ <Action name="mark_all" />
+ <Action name="mark_even" />
+ <Action name="mark_odd" />
+ <Action name="toggle" />
+ <Action name="remove" />
+ <Action name="no_flicker" />
+ </Enable>
+</State>
+<MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="file_save_as" group="file_save" />
+ <Action name="info" group="file_print" />
+ </Menu>
+ <Menu name="edit"><text>&amp;Edit</text>
+ <Action name="mark_current"/>
+ <Action name="mark_all"/>
+ <Action name="mark_even"/>
+ <Action name="mark_odd"/>
+ <Action name="toggle"/>
+ <Action name="remove"/>
+ </Menu>
+ <Menu name="view"><text>&amp;View</text>
+ <Action name="orientation_menu"/>
+ <Action name="media_menu"/>
+ <Separator/>
+ <Action name="zoomIn"/>
+ <Action name="zoomTo" />
+ <Action name="zoomOut"/>
+ <Action name="fit_to_page"/>
+ <Action name="fit_to_screen" />
+ <Action name="prevPage"/>
+ <Action name="nextPage"/>
+ <Action name="goToStart"/>
+ <Action name="goToEnd"/>
+ <Action name="goToPage"/>
+ <Action name="readUp"/>
+ <Action name="readDown"/>
+ </Menu>
+ <Menu name="settings"><text>&amp;Settings</text>
+ <Action name="show_scrollbars"/>
+ <Action name="show_page_list"/>
+ <Action name="show_page_labels"/>
+ <Separator/>
+ <Action name="watch_file"/>
+ <Action name="no_flicker" />
+ <Separator/>
+ <Action name="options_configure_keybinding"/>
+ <Action name="options_configure" group="options_configure"/>
+ </Menu>
+</MenuBar>
+<ToolBar name="mainToolBar">
+ <text>&amp;Main Toolbar</text>
+ <Action name="zoomIn"/>
+ <Action name="zoomTo" />
+ <Action name="zoomOut"/>
+ <Action name="goToStart"/>
+ <Action name="readUp"/>
+ <Action name="readDown"/>
+ <Action name="goToEnd"/>
+</ToolBar>
+</kpartgui>
+
diff --git a/kghostview/kgv_view.cpp b/kghostview/kgv_view.cpp
new file mode 100644
index 00000000..3c25ef41
--- /dev/null
+++ b/kghostview/kgv_view.cpp
@@ -0,0 +1,1037 @@
+/**
+ * Copyright (C) 2000-2002 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 <qfile.h>
+#include <qfileinfo.h>
+#include <qframe.h>
+#include <qtable.h>
+#include <qlayout.h>
+#include <qregexp.h>
+
+#include <kaction.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kdirwatch.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <kinstance.h>
+#include <klocale.h>
+#include <kpopupmenu.h>
+#include <kstdaction.h>
+#include <kstdaccel.h>
+#include <ktempfile.h>
+#include <kio/scheduler.h>
+#include <kaboutdata.h>
+
+
+#include "kgv_view.h"
+#include "kgv_miniwidget.h"
+#include "kgvconfigdialog.h"
+#include "kgvdocument.h"
+#include "kgvpagedecorator.h"
+#include "kgvpageview.h"
+#include "kgvmainwidget.h"
+#include "kpswidget.h"
+#include "kgvfactory.h"
+#include "logwindow.h"
+#include "marklist.h"
+#include "scrollbox.h"
+#include "version.h"
+#include "configuration.h"
+
+#include <cmath>
+
+namespace KGV {
+ /*
+ * This is because Qt's iterators
+ * are not standard iterators bc of missing typedefs,
+ * so they are only *almost* STL compatible
+ */
+ template <typename T>
+ unsigned distance( T a, T b ) {
+ unsigned res = 0;
+ while ( a != b ) {
+ ++res;
+ ++a;
+ }
+ return res;
+ }
+}
+
+KGVPart::KGVPart( QWidget* parentWidget, const char*,
+ QObject* parent, const char* name,
+ const QStringList &args ) :
+ KParts::ReadOnlyPart( parent, name ),
+ _fitTimer( new QTimer( this ) ),
+ _job( 0 ),
+ _mimetypeScanner( 0 ),
+ _dirtyHandler( new QTimer( this ) ),
+ _isGuiInitialized( false ),
+ _isFileDirty( false ),
+ _stickyOptions( false ),
+ _embeddedInKGhostView( !args.contains( "KParts::ReadOnlyPart" ) ),
+ _customZoomIndex( -1 )
+{
+ setInstance( KGVFactory::instance() );
+
+ // Don't show the progress info dialog if we're embedded in Konqueror.
+ setProgressInfoEnabled( !args.contains( "Browser/View") );
+
+ _document = new KGVDocument( this );
+ connect( _document, SIGNAL( fileChangeFailed() ),
+ this, SLOT( slotCancelWatch() ) );
+ connect( _document, SIGNAL( completed() ),
+ this, SLOT( slotOpenFileCompleted() ) );
+ connect( _document, SIGNAL( canceled( const QString& ) ),
+ this, SIGNAL( canceled( const QString& ) ) );
+
+ _fileWatcher = new KDirWatch( this );
+ connect( _fileWatcher, SIGNAL( dirty( const QString& ) ),
+ this, SLOT( slotFileDirty( const QString& ) ) );
+ connect( _dirtyHandler, SIGNAL( timeout() ),
+ this, SLOT( slotDoFileDirty() ) );
+
+ // Setup main widget
+ _mainWidget = new KGVMainWidget( parentWidget );
+ _mainWidget->setFocusPolicy( QWidget::StrongFocus );
+ _mainWidget->installEventFilter( this );
+ _mainWidget->setAcceptDrops( true );
+ connect( _mainWidget, SIGNAL( spacePressed() ),
+ this, SLOT( slotReadDown() ) );
+ connect( _mainWidget, SIGNAL( urlDropped( const KURL& ) ),
+ this, SLOT( openURL( const KURL& ) ) );
+
+ QHBoxLayout* hlay = new QHBoxLayout( _mainWidget, 0, 0 );
+ QVBoxLayout* vlay = new QVBoxLayout( hlay );
+
+ const int PAGELIST_WIDTH = 75;
+
+ _scrollBox = new ScrollBox( _mainWidget , "scrollbox" );
+ _scrollBox->setFixedWidth( PAGELIST_WIDTH );
+ _scrollBox->setMinimumHeight( PAGELIST_WIDTH );
+ vlay->addWidget( _scrollBox );
+
+ _divider = new QFrame( _mainWidget, "divider" );
+ _divider->setFrameStyle( QFrame::Panel | QFrame::Raised );
+ _divider->setLineWidth( 1 );
+ _divider->setMinimumWidth( 3 );
+ hlay->addWidget( _divider );
+
+ _pageView = new KGVPageView( _mainWidget, "pageview" );
+ _pageView->viewport()->setBackgroundMode( QWidget::PaletteMid );
+ hlay->addWidget( _pageView, 1 );
+ _mainWidget->setFocusProxy( _pageView );
+ setWidget( _mainWidget );
+
+ _pageDecorator = new KGVPageDecorator( _pageView->viewport() );
+ _pageDecorator->hide();
+
+
+ _psWidget = new KPSWidget( _pageDecorator );
+ _psWidget->readSettings();
+ _pageView->setPage( _pageDecorator );
+ connect( _psWidget, SIGNAL( output( char*, int ) ),
+ this, SLOT( slotGhostscriptOutput( char*, int ) ) );
+
+ connect( _psWidget, SIGNAL( ghostscriptError( const QString& ) ),
+ this, SLOT( slotGhostscriptError( const QString& ) ) );
+
+
+ _logWindow = new LogWindow( i18n( "Ghostscript Messages" ), _mainWidget, "logwindow" );
+ _showLogWindow = false;
+
+ connect( _logWindow, SIGNAL( configureGS() ), SLOT( slotConfigure() ) );
+
+ _docManager = new KGVMiniWidget( this );
+ _docManager->setPSWidget( _psWidget );
+ _docManager->setDocument( document() );
+
+ _markList = new MarkList( _mainWidget, "marklist", _docManager );
+ _markList->setFixedWidth( PAGELIST_WIDTH );
+ vlay->addWidget( _markList, 1 );
+ connect( _markList, SIGNAL( contextMenuRequested ( int, int, const QPoint& ) ),
+ this, SLOT( showPopup( int, int, const QPoint& ) ) );
+
+
+ connect( _markList, SIGNAL( selected( int ) ),
+ _docManager, SLOT( goToPage( int ) ) );
+ connect( _docManager, SIGNAL( newPageShown( int ) ),
+ _markList, SLOT( select( int ) ) );
+ connect( _docManager, SIGNAL( setStatusBarText( const QString& ) ),
+ this, SIGNAL( setStatusBarText( const QString& ) ) );
+ connect( _scrollBox, SIGNAL( valueChangedRelative( int, int ) ),
+ _pageView, SLOT( scrollBy( int, int ) ) );
+ connect( _pageView, SIGNAL( pageSizeChanged( const QSize& ) ),
+ _scrollBox, SLOT( setPageSize( const QSize& ) ) );
+ connect( _pageView, SIGNAL( viewSizeChanged( const QSize& ) ),
+ _scrollBox, SLOT( setViewSize( const QSize& ) ) );
+ connect( _pageView, SIGNAL( contentsMoving( int, int ) ),
+ _scrollBox, SLOT( setViewPos( int, int ) ) );
+
+ //-- File Menu ----------------------------------------------------------
+ KStdAction::saveAs( document(), SLOT( saveAs() ),
+ actionCollection() );
+ new KAction( i18n( "Document &Info" ), 0,
+ miniWidget(), SLOT( info() ),
+ actionCollection(), "info" );
+
+ //-- Edit Menu -----------------------------------------------------
+ _popup = new KPopupMenu( _markList, "marklist_menu" );
+
+ KAction *act = new KAction( i18n( "Mark Current Page" ), "flag", CTRL+SHIFT+Key_M,
+ _markList, SLOT( markCurrent() ),
+ actionCollection(), "mark_current" );
+ act->plug( _popup );
+ act = new KAction( i18n( "Mark &All Pages" ), 0,
+ _markList, SLOT( markAll() ),
+ actionCollection(), "mark_all" );
+ act->plug( _popup );
+ act = new KAction( i18n( "Mark &Even Pages" ), 0,
+ _markList, SLOT( markEven() ),
+ actionCollection(), "mark_even" );
+ act->plug( _popup );
+ act = new KAction( i18n( "Mark &Odd Pages" ), 0,
+ _markList, SLOT( markOdd() ),
+ actionCollection(), "mark_odd" );
+ act->plug( _popup );
+ act = new KAction( i18n( "&Toggle Page Marks" ), 0,
+ _markList, SLOT( toggleMarks() ),
+ actionCollection(), "toggle" );
+ act->plug( _popup );
+ act = new KAction( i18n("&Remove Page Marks"), 0,
+ _markList, SLOT( removeMarks() ),
+ actionCollection(), "remove" );
+ act->plug( _popup );
+
+ // TODO -- disable entry if there aren't any page names
+
+ //-- View Menu ----------------------------------------------------------
+ _selectOrientation = new KSelectAction( i18n( "&Orientation" ), 0, 0, 0,
+ actionCollection(), "orientation_menu" );
+ _selectMedia = new KSelectAction( i18n( "Paper &Size" ), 0, 0, 0,
+ actionCollection(), "media_menu" );
+
+ _flick = new KToggleAction( i18n( "No &Flicker" ), 0,
+ this, SLOT( slotFlicker() ),
+ actionCollection(), "no_flicker" );
+
+ QStringList orientations;
+ orientations.append( i18n( "Auto" ) );
+ orientations.append( i18n( "Portrait" ) );
+ orientations.append( i18n( "Landscape" ) );
+ orientations.append( i18n( "Upside Down" ) );
+ orientations.append( i18n( "Seascape" ) );
+ _selectOrientation->setItems( orientations );
+
+ connect( _selectOrientation, SIGNAL( activated( int ) ),
+ this, SLOT( slotOrientation( int ) ) );
+ connect( _selectMedia, SIGNAL( activated( int ) ),
+ this, SLOT( slotMedia( int ) ) );
+
+ {
+ KShortcut zoomInShort = KStdAccel::zoomIn();
+ zoomInShort.append( KKey( CTRL+Key_Equal ) );
+ _zoomIn = KStdAction::zoomIn( this, SLOT( slotZoomIn() ),
+ actionCollection(), "zoomIn" );
+ _zoomIn->setShortcut( zoomInShort );
+ }
+ _zoomOut = KStdAction::zoomOut( this, SLOT( slotZoomOut() ),
+ actionCollection(), "zoomOut" );
+ _zoomTo = new KSelectAction( i18n( "Zoom" ), "viewmag", 0, actionCollection(), "zoomTo" );
+ connect( _zoomTo, SIGNAL( activated( const QString & ) ), this, SLOT( slotZoom( const QString& ) ) );
+ _zoomTo->setEditable( true );
+ _zoomTo->clear();
+ QValueList<double> mags = DisplayOptions::normalMagnificationValues();
+ QStringList zooms;
+ int idx = 0;
+ int cur = 0;
+ for ( QValueList<double>::iterator first = mags.begin(), last = mags.end();
+ first != last;
+ ++first ) {
+ QString str = QString( "%1%" ).arg( KGlobal::locale()->formatNumber( *first * 100.0, 2 ));
+ str.remove( KGlobal::locale()->decimalSymbol() + "00" );
+ zooms << str;
+ if ( *first == 1.0 ) idx = cur;
+ ++cur;
+ }
+ _zoomTo->setItems( zooms );
+ _zoomTo->setCurrentItem( idx );
+
+ _fitWidth = new KAction( i18n( "&Fit to Page Width" ), 0, this,
+ SLOT( slotFitToPage() ), actionCollection(),
+ "fit_to_page");
+ _fitScreen = new KAction( i18n( "&Fit to Screen" ), Key_S, this,
+ SLOT( slotFitToScreen() ), actionCollection(),
+ "fit_to_screen");
+
+ _prevPage = new KAction( i18n( "Previous Page" ), CTRL+Key_PageUp, this, SLOT( slotPrevPage() ),
+ actionCollection(), "prevPage" );
+ _prevPage->setWhatsThis( i18n( "Moves to the previous page of the document" ) );
+
+ _nextPage = new KAction( i18n( "Next Page" ), CTRL + Key_PageDown, this, SLOT( slotNextPage() ),
+ actionCollection(), "nextPage" );
+ _nextPage->setWhatsThis( i18n( "Moves to the next page of the document" ) );
+
+ _firstPage = KStdAction::firstPage( this, SLOT( slotGotoStart() ),
+ actionCollection(), "goToStart" );
+ _firstPage->setWhatsThis( i18n( "Moves to the first page of the document" ) );
+
+ _lastPage = KStdAction::lastPage( this, SLOT( slotGotoEnd() ),
+ actionCollection(), "goToEnd" );
+ _lastPage->setWhatsThis( i18n( "Moves to the last page of the document" ) );
+
+ KShortcut readUpShort = KStdAccel::shortcut( KStdAccel::Prior );
+ readUpShort.append( KKey( SHIFT+Key_Space ) );
+ _readUp = new KAction( i18n( "Read Up" ), "up",
+ readUpShort, this, SLOT( slotReadUp() ),
+ actionCollection(), "readUp" );
+
+ KShortcut readDownShort = KStdAccel::shortcut( KStdAccel::Next );
+ readDownShort.append( KKey( Key_Space ) );
+ _readDown = new KAction( i18n( "Read Down" ), "down",
+ readDownShort, this, SLOT( slotReadDown() ),
+ actionCollection(), "readDown" );
+
+ _gotoPage = KStdAction::gotoPage( _docManager, SLOT( goToPage() ),
+ actionCollection(), "goToPage" );
+
+ //-- Settings Menu ------------------------------------------------------
+ _showScrollBars = new KToggleAction( i18n( "Show &Scrollbars" ), 0,
+ actionCollection(), "show_scrollbars" );
+ _showScrollBars->setCheckedState(i18n("Hide &Scrollbars"));
+ _watchFile = new KToggleAction( i18n( "&Watch File" ), 0,
+ this, SLOT( slotWatchFile() ),
+ actionCollection(), "watch_file" );
+ _showPageList = new KToggleAction( i18n( "Show &Page List" ), 0,
+ actionCollection(), "show_page_list" );
+ _showPageList->setCheckedState(i18n("Hide &Page List"));
+ _showPageLabels = new KToggleAction( i18n("Show Page &Labels"), 0,
+ actionCollection(), "show_page_labels" );
+ _showPageLabels->setCheckedState(i18n("Hide Page &Labels"));
+ KStdAction::preferences( this, SLOT( slotConfigure() ), actionCollection() );
+ connect( _showScrollBars, SIGNAL( toggled( bool ) ),
+ SLOT( showScrollBars( bool ) ) );
+ connect( _showPageList, SIGNAL( toggled( bool ) ),
+ SLOT( showMarkList( bool ) ) );
+ connect( _showPageLabels, SIGNAL( toggled( bool ) ),
+ SLOT( showPageLabels( bool ) ) );
+
+ _extension = new KGVBrowserExtension( this );
+
+ setXMLFile( "kgv_part.rc" );
+
+ connect( miniWidget(), SIGNAL( newPageShown( int ) ),
+ this, SLOT( slotNewPage( int ) ) );
+ connect( _pageView, SIGNAL( contentsMoving( int, int ) ),
+ this, SLOT( slotPageMoved( int, int ) ) );
+
+ connect( _pageView, SIGNAL( nextPage() ), SLOT( slotNextPage() ));
+ connect( _pageView, SIGNAL( prevPage() ), SLOT( slotPrevPage() ));
+ connect( _pageView, SIGNAL( zoomIn() ), SLOT( slotZoomIn() ));
+ connect( _pageView, SIGNAL( zoomOut() ), SLOT( slotZoomOut() ));
+ connect( _pageView, SIGNAL( ReadUp() ), SLOT( slotReadUp() ));
+ connect( _pageView, SIGNAL( ReadDown() ), SLOT( slotReadDown() ));
+
+ QStringList items = document()->mediaNames();
+ items.prepend( i18n( "Auto ") );
+ _selectMedia->setItems( items );
+
+ readSettings();
+
+ updatePageDepActions();
+}
+
+KGVPart::~KGVPart()
+{
+ if ( _job ) _job -> kill();
+ delete _mimetypeScanner;
+ writeSettings();
+}
+
+KAboutData* KGVPart::createAboutData()
+{
+ KAboutData* about = new KAboutData( "kghostview", I18N_NOOP( "KGhostView"),
+ KGHOSTVIEW_VERSION,
+ I18N_NOOP( "Viewer for PostScript (.ps, .eps) and Portable Document Format (.pdf) files"),
+ KAboutData::License_GPL,
+ "(C) 1998 Mark Donohoe, (C) 1999-2000 David Sweet, "
+ "(C) 2000-2003 Wilco Greven",
+ I18N_NOOP( "KGhostView displays, prints, and saves "
+ "PostScript and PDF files.\n"
+ "Based on original work by Tim Theisen." ) );
+ about->addAuthor( "Luís Pedro Coelho",
+ I18N_NOOP( "Current maintainer" ),
+ "luis@luispedro.org",
+ "http://luispedro.org" );
+ about->addAuthor( "Wilco Greven",
+ I18N_NOOP( "Maintainer 2000-2003" ),
+ "greven@kde.org" );
+ about->addAuthor( "David Sweet",
+ I18N_NOOP( "Maintainer 1999-2000" ),
+ "dsweet@kde.org",
+ "http://www.andamooka.org/~dsweet" );
+ about->addAuthor( "Mark Donohoe",
+ I18N_NOOP( "Original author" ),
+ "donohoe@kde.org" );
+ about->addAuthor( "David Faure",
+ I18N_NOOP( "Basis for shell"),
+ "faure@kde.org" );
+ about->addAuthor( "Daniel Duley",
+ I18N_NOOP( "Port to KParts" ),
+ "mosfet@kde.org" );
+ about->addAuthor( "Espen Sand",
+ I18N_NOOP( "Dialog boxes" ),
+ "espen@kde.org" );
+ about->addCredit( "Russell Lang of Ghostgum Software Pty Ltd",
+ I18N_NOOP( "for contributing GSView's DSC parser." ),
+ 0,
+ "http://www.ghostgum.com.au/" );
+ about->addCredit( "The Ghostscript authors",
+ 0, 0,
+ "http://www.cs.wisc.edu/~ghost/" );
+ return about;
+}
+
+bool KGVPart::closeURL()
+{
+ document()->close();
+ _psWidget->stopInterpreter();
+ _docManager->getThumbnailService()->reset();
+ _markList->clear();
+ _pageDecorator->hide();
+ _scrollBox->clear();
+ _isFileDirty = false;
+ if ( _job )
+ {
+ _job -> kill();
+ _job = 0;
+ }
+ if( _mimetypeScanner != 0 )
+ _mimetypeScanner->abort();
+ if( !m_file.isEmpty() )
+ _fileWatcher->removeFile( m_file );
+ _mimetype = QString::null;
+ updatePageDepActions();
+ stateChanged( "initState" );
+ return KParts::ReadOnlyPart::closeURL();
+}
+
+void KGVPart::writeSettings()
+{
+ KConfigGroup general( KGVFactory::instance()->config(), "General" );
+ if ( !_embeddedInKGhostView )
+ general.writeEntry( "Display Options", DisplayOptions::toString( miniWidget()->displayOptions() ) );
+ general.sync();
+}
+
+void KGVPart::readSettings()
+{
+ KConfigGroup general( KGVFactory::instance()->config(), "General" );
+
+ _showScrollBars->setChecked( Configuration::showScrollBars() );
+ showScrollBars( _showScrollBars->isChecked() );
+
+ _watchFile->setChecked( Configuration::watchFile() );
+ slotWatchFile();
+
+ _showPageList->setChecked( Configuration::showPageList() );
+ showMarkList( _showPageList->isChecked() );
+
+ _showPageLabels->setChecked( Configuration::watchFile() );
+ showPageLabels( _showPageLabels->isChecked() );
+
+ _showLogWindow = Configuration::messages();
+ if ( !_embeddedInKGhostView ) {
+ DisplayOptions options;
+ if ( DisplayOptions::fromString( options, general.readEntry( "Display Options" ) ) )
+ setDisplayOptions( options );
+ }
+ _psWidget->readSettings();
+}
+
+void KGVPart::slotScrollLeft()
+{
+ _pageView->scrollLeft();
+}
+
+void KGVPart::slotFlicker()
+{
+ if ( _psWidget ) _psWidget->setDoubleBuffering( _flick->isChecked() );
+}
+
+void KGVPart::slotScrollRight()
+{
+ _pageView->scrollRight();
+}
+
+void KGVPart::slotScrollUp()
+{
+ _pageView->scrollUp();
+}
+
+void KGVPart::slotScrollDown()
+{
+ _pageView->scrollDown();
+}
+
+void KGVPart::slotReadUp()
+{
+ if( !( document() && document()->isOpen() ) )
+ return;
+
+ if( !_pageView->readUp() ) {
+ if (_docManager->prevPage())
+ _pageView->scrollBottom();
+ }
+}
+
+void KGVPart::slotReadDown()
+{
+ if( !( document() && document()->isOpen() ) )
+ return;
+
+ if( !_pageView->readDown() ) {
+ if( _docManager->nextPage() )
+ _pageView->scrollTop();
+ }
+}
+
+void KGVPart::slotPrevPage()
+{
+ if( !document() || !document()->isOpen() ) return;
+ _docManager->prevPage();
+}
+
+void KGVPart::slotNextPage()
+{
+ if( !document() || !document()->isOpen() ) return;
+ _docManager->nextPage();
+}
+
+void KGVPart::slotGotoStart()
+{
+ _docManager->firstPage();
+ _pageView->scrollTop();
+}
+
+void KGVPart::slotGotoEnd()
+{
+ _docManager->lastPage();
+ _pageView->scrollTop();
+}
+
+void KGVPart::slotWatchFile()
+{
+ if( _watchFile->isChecked() )
+ _fileWatcher->startScan();
+ else {
+ _dirtyHandler->stop();
+ _fileWatcher->stopScan();
+ }
+}
+
+void KGVPart::slotCancelWatch()
+{
+ _fileWatcher->stopScan();
+ _watchFile->setChecked( false );
+}
+
+/*
+void KGVPart::slotFitWidth()
+{
+ _docManager->fitWidth( pageView()->viewport()->width() -
+ 2*( pageDecorator()->margin() + pageDecorator()->borderWidth() ) );
+}
+*/
+
+void KGVPart::updateZoomActions()
+{
+ if( !( document() && document()->isOpen() ) )
+ return;
+
+ _zoomIn->setEnabled(!_docManager->atMaxZoom());
+ _zoomOut->setEnabled(!_docManager->atMinZoom());
+ _zoomTo->setEnabled( true );
+ QStringList items = _zoomTo->items();
+ bool updateItems = false;
+ if (_customZoomIndex != -1)
+ {
+ items.remove(items.at(_customZoomIndex));
+ _customZoomIndex = -1;
+ updateItems = true;
+ }
+ double zoom = floor(miniWidget()->displayOptions().magnification()*1000.0) / 10.0;
+ unsigned idx = 0;
+ for ( QStringList::iterator first = items.begin(), last = items.end();
+ first != last;
+ ++first ) {
+ QString cur = *first;
+ cur.remove( cur.find( '%' ), 1 );
+ cur = cur.simplifyWhiteSpace();
+ bool ok = false;
+ double z = cur.toDouble(&ok);
+ if ( ok ) {
+ if (std::abs( z - zoom ) < 0.1 ) {
+ if (updateItems)
+ _zoomTo->setItems( items );
+ _zoomTo->setCurrentItem( idx );
+ return;
+ }
+ if ( z > zoom )
+ break;
+ }
+ ++idx;
+ }
+
+ // Show percentage that isn't predefined
+ QString str = QString( "%1%" ).arg( KGlobal::locale()->formatNumber( zoom, 2 ));
+ str.remove( KGlobal::locale()->decimalSymbol() + "00" );
+ items.insert( items.at(idx), 1, str );
+ _zoomTo->setItems( items );
+ _zoomTo->setCurrentItem( idx );
+ _customZoomIndex = idx;
+}
+
+void KGVPart::updatePageDepActions()
+{
+ bool hasDoc = document() && document()->isOpen();
+
+ _fitWidth->setEnabled( hasDoc );
+ _fitScreen->setEnabled( hasDoc );
+
+ _prevPage->setEnabled( hasDoc && !_docManager->atFirstPage() );
+ _firstPage->setEnabled( hasDoc && !_docManager->atFirstPage() );
+ _nextPage->setEnabled( hasDoc && !_docManager->atLastPage() );
+ _lastPage->setEnabled( hasDoc && !_docManager->atLastPage() );
+ _gotoPage->setEnabled( hasDoc &&
+ !(_docManager->atFirstPage() && _docManager->atLastPage()) );
+
+ updateReadUpDownActions();
+}
+
+void KGVPart::updateReadUpDownActions()
+{
+ if( !( document() && document()->isOpen() ) )
+ {
+ _readUp->setEnabled( false );
+ _readDown->setEnabled( false );
+ return;
+ }
+
+ if( _docManager->atFirstPage() && _pageView->atTop() )
+ _readUp->setEnabled( false );
+ else
+ _readUp->setEnabled( true );
+
+ if( _docManager->atLastPage() && _pageView->atBottom() )
+ _readDown->setEnabled( false );
+ else
+ _readDown->setEnabled( true );
+}
+
+bool KGVPart::openURL( const KURL& url )
+{
+ if( !url.isValid() )
+ return false;
+ if( !closeURL() )
+ return false;
+
+ m_url = url;
+ if ( !_stickyOptions ) _options.reset();
+
+ emit setWindowCaption( m_url.prettyURL() );
+
+ _mimetypeScanner = new KGVRun( m_url, 0, m_url.isLocalFile(), false );
+ connect( _mimetypeScanner, SIGNAL( finished( const QString& ) ),
+ SLOT( slotMimetypeFinished( const QString& ) ) );
+ connect( _mimetypeScanner, SIGNAL( error() ),
+ SLOT( slotMimetypeError() ) );
+
+ return true;
+}
+
+void KGVPart::openURLContinue()
+{
+ kdDebug(4500) << "KGVPart::openURLContinue()" << endl;
+ if( m_url.isLocalFile() )
+ {
+ emit started( 0 );
+ m_file = m_url.path();
+ document()->openFile( m_file, _mimetype );
+ }
+ else
+ {
+ m_bTemp = true;
+ // Use same extension as remote file. This is important for
+ // mimetype-determination (e.g. koffice)
+ QString extension;
+ QString fileName = m_url.fileName();
+ int extensionPos = fileName.findRev( '.' );
+ if( extensionPos != -1 )
+ extension = fileName.mid( extensionPos ); // keep the '.'
+ KTempFile tempFile( QString::null, extension );
+ m_file = tempFile.name();
+ _tmpFile.setName( m_file );
+ _tmpFile.open( IO_ReadWrite );
+
+ /*
+ d->m_job = KIO::file_copy( m_url, m_file, 0600, true, false, d->m_showProgressInfo );
+ emit started( d->m_job );
+ connect( d->m_job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotJobFinished ( KIO::Job * ) ) );
+ */
+
+ _job = KIO::get( m_url, false, isProgressInfoEnabled() );
+
+ connect( _job, SIGNAL( data( KIO::Job*, const QByteArray& ) ),
+ SLOT( slotData( KIO::Job*, const QByteArray& ) ) );
+ connect( _job, SIGNAL( result( KIO::Job* ) ),
+ SLOT( slotJobFinished( KIO::Job* ) ) );
+
+ emit started( _job );
+ }
+}
+
+bool KGVPart::openFile()
+{
+ return false;
+}
+
+void KGVPart::slotOpenFileCompleted()
+{
+ _docManager->getThumbnailService()->setEnabled( true );
+ if( _isFileDirty )
+ {
+ _docManager->redisplay();
+ _isFileDirty = false;
+ }
+ else
+ {
+ if ( !_stickyOptions ) setDisplayOptions( DisplayOptions() );
+ _stickyOptions = false;
+
+ stateChanged( "documentState" );
+ if ( !_fileWatcher->contains( m_file ) )
+ _fileWatcher->addFile( m_file );
+ slotWatchFile();
+ updateZoomActions();
+ emit completed();
+ }
+}
+
+void KGVPart::slotGhostscriptOutput( char* data, int len )
+{
+ _logWindow->append( QString::fromLocal8Bit( data, len ) );
+ if( _showLogWindow )
+ _logWindow->show();
+}
+
+
+void KGVPart::slotGhostscriptError( const QString& error )
+{
+ _logWindow->setLabel( i18n( "<qt>An error occurred in rendering.<br>"
+ "<strong>%1</strong><br>"
+ "The display may contain errors.<br>"
+ "Below are any error messages which were received from Ghostscript "
+ "(<nobr><strong>%2</strong></nobr>) "
+ "which may help you.</qt>" )
+ .arg( error )
+ .arg( Configuration::interpreter() ),
+ true );
+ // The true above makes it show a "configure gs" option, but maybe we
+ // should trigger an auto-redetection?
+ // LPC (13 Apr 2003)
+ _logWindow->show();
+}
+
+
+void KGVPart::guiActivateEvent( KParts::GUIActivateEvent* event )
+{
+ if( event->activated() && !_isGuiInitialized )
+ {
+ stateChanged( "initState" );
+ _isGuiInitialized = true;
+ }
+ KParts::ReadOnlyPart::guiActivateEvent( event );
+}
+
+void KGVPart::slotData( KIO::Job* job, const QByteArray& data )
+{
+ Q_ASSERT( _job == job );
+
+ kdDebug(4500) << "KGVPart::slotData: received " << data.size() << " bytes." << endl;
+
+ _tmpFile.writeBlock( data );
+}
+
+void KGVPart::slotMimetypeFinished( const QString& type )
+{
+ kdDebug(4500) << "KGVPart::slotMimetypeFinished( " << type << " )" << endl;
+ _mimetype = type;
+ if( !_mimetypeScanner || _mimetypeScanner->hasError() )
+ emit canceled( QString::null );
+ else
+ openURLContinue();
+ _mimetypeScanner = 0;
+}
+
+void KGVPart::slotMimetypeError()
+{
+ kdDebug(4500) << "KGVPart::slotMimetypeError()" << endl;
+ _mimetypeScanner = 0;
+ emit started( 0 );
+ //kapp->processEvents();
+ emit canceled( QString::null );
+}
+
+void KGVPart::slotJobFinished( KIO::Job* job )
+{
+ Q_ASSERT( _job == job );
+
+ kdDebug(4500) << "KGVPart::slotJobFinished" << endl;
+
+ _job = 0;
+
+ _tmpFile.close();
+
+ if( job->error() )
+ emit canceled( job->errorString() );
+ else
+ document()->openFile( m_file, _mimetype );
+}
+
+void KGVPart::slotFileDirty( const QString& fileName )
+{
+ // The beauty of this is that each start cancels the previous one.
+ // This means that timeout() is only fired when there have
+ // no changes to the file for the last 750 milisecs.
+ // This is supposed to ensure that we don't update on every other byte
+ // that gets written to the file.
+ if ( fileName == m_file )
+ {
+ _dirtyHandler->start( 750, true );
+ }
+}
+
+void KGVPart::slotDoFileDirty()
+{
+ kdDebug(4500) << "KGVPart::File changed" << endl;
+ _isFileDirty = true;
+ reloadFile();
+}
+
+void KGVPart::slotNewPage( int )
+{
+ updatePageDepActions();
+ //media->setCurrentItem (miniWidget()->getSize()-1);
+ //orientation->setCurrentItem (miniWidget()->getOrientation()-1);
+ //TODO -- zoom
+}
+
+void KGVPart::slotPageMoved( int, int )
+{
+ updateReadUpDownActions();
+}
+
+void KGVPart::slotOrientation( int id )
+{
+ switch( id ) {
+ case 0: miniWidget()->restoreOverrideOrientation(); break;
+ case 1: miniWidget()->setOverrideOrientation( CDSC_PORTRAIT ); break;
+ case 2: miniWidget()->setOverrideOrientation( CDSC_LANDSCAPE ); break;
+ case 3: miniWidget()->setOverrideOrientation( CDSC_UPSIDEDOWN ); break;
+ case 4: miniWidget()->setOverrideOrientation( CDSC_SEASCAPE ); break;
+ default: ;
+ }
+}
+
+void KGVPart::slotMedia( int id )
+{
+ if( id == 0 )
+ miniWidget()->restoreOverridePageMedia();
+ else
+ miniWidget()->setOverridePageMedia( _document->mediaNames()[id-1] );
+}
+
+void KGVPart::showScrollBars( bool show )
+{
+ _pageView->enableScrollBars( show );
+}
+
+void KGVPart::showMarkList( bool show )
+{
+ _markList->setShown( show );
+ _scrollBox->setShown( show );
+ _divider->setShown( show );
+}
+
+void KGVPart::showPageLabels( bool show )
+{
+ _docManager->enablePageLabels( show );
+}
+
+void KGVPart::slotZoomIn()
+{
+ _docManager->zoomIn();
+ updateZoomActions();
+}
+
+void KGVPart::slotZoomOut()
+{
+ _docManager->zoomOut();
+ updateZoomActions();
+}
+
+void KGVPart::slotZoom( const QString& nz )
+{
+ QString z = nz;
+ double zoom;
+ z.remove( z.find( '%' ), 1 );
+ zoom = KGlobal::locale()->readNumber( z ) / 100;
+ kdDebug( 4500 ) << "ZOOM = " << nz << ", setting zoom = " << zoom << endl;
+
+ DisplayOptions options = miniWidget()->displayOptions();
+ options.setMagnification( zoom );
+ miniWidget()->setDisplayOptions( options );
+ miniWidget()->redisplay();
+ _mainWidget->setFocus();
+ updateZoomActions();
+}
+
+void KGVPart::slotFitToPage()
+{
+ kdDebug(4500) << "KGVPart::slotFitToPage()" << endl;
+ if( pageView()->page() )
+ miniWidget()->fitWidth( pageView()->viewport()->width() - 16 );
+ // We subtract 16 pixels because of the page decoration.
+ updateZoomActions();
+}
+
+void KGVPart::slotFitToScreen()
+{
+ kdDebug(4500) << "KGVPart::slotFitToScreen()" << endl;
+ if ( _fitTimer->isActive() ) {
+ disconnect( _fitTimer, SIGNAL( timeout() ), this, 0 );
+ connect( _fitTimer, SIGNAL( timeout() ), SLOT( slotDoFitToScreen() ) );
+ }
+ else slotDoFitToScreen();
+}
+
+void KGVPart::slotDoFitToScreen()
+{
+ kdDebug(4500) << "KGVPart::slotDoFitToScreen()" << endl;
+ if( pageView()->page() )
+ miniWidget()->fitWidthHeight( pageView()->viewport()->width() - 16,
+ pageView()->viewport()->height() - 16 );
+ updateZoomActions();
+}
+
+void KGVPart::reloadFile()
+{
+ _psWidget->stopInterpreter();
+ _docManager->getThumbnailService()->reset();
+ document()->openFile( m_file, _mimetype );
+}
+
+void KGVPart::slotConfigure()
+{
+ ConfigDialog::showSettings( this );
+}
+
+void KGVPart::slotConfigurationChanged()
+{
+ readSettings();
+ _psWidget->readSettings();
+ miniWidget()->redisplay();
+}
+
+void KGVPart::setDisplayOptions( const DisplayOptions& options )
+{
+ kdDebug(4500) << "KGVPart::setDisplayOptions()" << endl;
+ _stickyOptions = true;
+ _markList->select( options.page() );
+ _docManager->setDisplayOptions( options );
+ _selectOrientation->setCurrentItem( options.overrideOrientation() );
+ QStringList medias = document()->mediaNames();
+ QStringList::Iterator now = medias.find( options.overridePageMedia() );
+ if ( now != medias.end() ){
+ // The options are displayed in inverted order.
+ // Therefore, size() - index gets you the display index
+ _selectMedia->setCurrentItem( medias.size() - KGV::distance( medias.begin(), now ) );
+ } else {
+ _selectMedia->setCurrentItem( 0 );
+ }
+}
+
+
+KGVBrowserExtension::KGVBrowserExtension( KGVPart *parent ) :
+ KParts::BrowserExtension( parent, "KGVBrowserExtension" )
+{
+ emit enableAction( "print", true );
+ setURLDropHandlingEnabled( true );
+}
+
+void KGVBrowserExtension::print()
+{
+ ((KGVPart *)parent())->document()->print();
+}
+
+
+KGVRun::KGVRun( const KURL& url, mode_t mode, bool isLocalFile,
+ bool showProgressInfo ) :
+ KRun( url, mode, isLocalFile, showProgressInfo )
+{
+ connect( this, SIGNAL( finished() ), SLOT( emitFinishedWithMimetype() ) );
+}
+
+KGVRun::~KGVRun()
+{}
+
+void KGVRun::foundMimeType( const QString& mimetype )
+{
+ kdDebug(4500) << "KGVRun::foundMimeType( " << mimetype << " )" << endl;
+
+ if( m_job && m_job->inherits( "KIO::TransferJob" ) )
+ {
+ KIO::TransferJob *job = static_cast< KIO::TransferJob* >( m_job );
+ job->putOnHold();
+ m_job = 0;
+ }
+
+ _mimetype = mimetype;
+
+ m_bFinished = true;
+ m_timer.start( 0, true );
+}
+
+
+void KGVPart::updateFullScreen( bool fs )
+{
+ if ( fs ) showMarkList( false );
+ else showMarkList( _showPageList->isChecked() );
+}
+
+void KGVPart::showPopup( int, int, const QPoint& pos )
+{
+ _popup->exec( pos );
+}
+
+#include "kgv_view.moc"
+
+
+// vim:sw=4:sts=4:ts=8:sta:tw=78:noet
diff --git a/kghostview/kgv_view.h b/kghostview/kgv_view.h
new file mode 100644
index 00000000..3a426f58
--- /dev/null
+++ b/kghostview/kgv_view.h
@@ -0,0 +1,268 @@
+/**
+ * Copyright (C) 2000-2002 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 __KGV_VIEW_H
+#define __KGV_VIEW_H
+
+#include <qcstring.h> // QByteArray
+#include <qfile.h>
+
+#include <kio/job.h>
+#include <kparts/browserextension.h>
+#include <krun.h>
+
+#include "displayoptions.h"
+
+class QFrame;
+class QWidget;
+
+class KAboutData;
+class KAction;
+class KActionCollection;
+class KDirWatch;
+class KInstance;
+class KPopupMenu;
+class KSelectAction;
+class KToggleAction;
+
+class KGVBrowserExtension;
+class KGVConfigDialog;
+class KGVDocument;
+class KGVMiniWidget;
+class KGVPageView;
+class KGVPageDecorator;
+class KGVRun;
+class KPSWidget;
+class LogWindow;
+class MarkList;
+class ScrollBox;
+
+class KGVPart: public KParts::ReadOnlyPart
+{
+ Q_OBJECT
+public:
+ KGVPart( QWidget* parentWidget, const char* widgetName,
+ QObject* parent, const char* name,
+ const QStringList& args = QStringList() );
+
+ virtual ~KGVPart();
+
+ KGVMiniWidget* miniWidget() const { return _docManager; }
+ MarkList* markList() const { return _markList; }
+ ScrollBox* scrollBox() { return _scrollBox; }
+ KGVPageView* pageView() const { return _pageView; }
+ KGVPageDecorator* pageDecorator() const { return _pageDecorator; }
+ KGVDocument* document() const { return _document; }
+
+
+ /**
+ * Reimplemented from ReadOnlyPart in order to delete the file from
+ * KDirWatch's list.
+ */
+ virtual bool closeURL();
+
+ KDE_EXPORT static KAboutData* createAboutData();
+
+public slots:
+ /**
+ * Reimplemented from ReadOnlyPart so that incoming data can be sent
+ * through the DSC parser immediately on arrival.
+ */
+ virtual bool openURL( const KURL& );
+ virtual void openURLContinue();
+
+ /**
+ * Reloads the current file.
+ * No action if no file is loaded
+ */
+ void reloadFile();
+
+ void updateFullScreen( bool );
+
+ void showPopup( int, int, const QPoint &pos );
+
+ void slotScrollLeft();
+ void slotScrollRight();
+ void slotScrollUp();
+ void slotScrollDown();
+ void slotReadDown();
+ void slotFlicker();
+ void slotReadUp();
+ void slotPrevPage();
+ void slotNextPage();
+ void slotGotoStart();
+ void slotGotoEnd();
+
+ void slotFitToPage();
+ void slotFitToScreen();
+ void slotDoFitToScreen();
+
+ void showScrollBars( bool );
+ void slotCancelWatch();
+ void showMarkList( bool );
+ void showPageLabels( bool );
+
+ void slotZoomIn();
+ void slotZoomOut();
+
+ void slotZoom( const QString& );
+
+ void slotConfigure();
+ void slotConfigurationChanged();
+
+ /**
+ * Sets the display options in a sticky way.
+ * This means that the file being opened or the next one to be open will
+ * get these options. This is useful for session management or commandline
+ * arguments
+ */
+ void setDisplayOptions( const DisplayOptions& opts );
+
+protected slots:
+ void slotData( KIO::Job*, const QByteArray& );
+ void slotJobFinished( KIO::Job* );
+
+ void slotMimetypeFinished( const QString& );
+ void slotMimetypeError();
+
+ void slotFileDirty( const QString& );
+ void slotDoFileDirty();
+
+ void slotOrientation (int);
+ void slotMedia (int);
+ void slotNewPage( int );
+ void slotPageMoved( int, int );
+ void slotWatchFile();
+
+ void slotOpenFileCompleted();
+
+protected:
+ virtual void guiActivateEvent( KParts::GUIActivateEvent* );
+
+ // reimplemented from ReadOnlyPart
+ virtual bool openFile();
+
+ void updatePageDepActions();
+ void updateZoomActions();
+ void updateReadUpDownActions();
+
+ void readSettings();
+ void writeSettings();
+
+private slots:
+ void slotGhostscriptOutput( char* data, int len );
+ void slotGhostscriptError( const QString& );
+
+private:
+ KGVBrowserExtension* _extension;
+
+ KGVDocument* _document;
+
+ QWidget* _mainWidget;
+ KGVPageView* _pageView;
+ KGVPageDecorator* _pageDecorator;
+ KPSWidget* _psWidget;
+ ScrollBox* _scrollBox;
+ QFrame* _divider;
+ MarkList* _markList;
+ KGVMiniWidget* _docManager;
+
+ LogWindow* _logWindow;
+
+ QTimer* _fitTimer;
+
+ KSelectAction* _selectOrientation;
+ KSelectAction* _selectMedia;
+ KAction* _zoomIn;
+ KAction* _zoomOut;
+ KSelectAction* _zoomTo;
+ KAction * _fitWidth;
+ KAction * _fitScreen;
+ KAction* _prevPage;
+ KAction* _nextPage;
+ KAction* _firstPage;
+ KAction* _lastPage;
+ KAction* _readUp;
+ KAction* _readDown;
+ KAction* _gotoPage;
+ KToggleAction* _showScrollBars;
+ KToggleAction* _watchFile;
+ KToggleAction* _flick;
+ KToggleAction* _showPageList;
+ KToggleAction* _showPageLabels;
+ KPopupMenu* _popup;
+
+ QFile _tmpFile;
+ KIO::TransferJob* _job;
+ KDirWatch* _fileWatcher;
+ KGVRun* _mimetypeScanner;
+ QTimer* _dirtyHandler;
+
+ QString _mimetype;
+
+ bool _isGuiInitialized : 1;
+ bool _isFileDirty : 1;
+ bool _showLogWindow : 1;
+ bool _stickyOptions : 1;
+ bool _embeddedInKGhostView : 1;
+
+ int _customZoomIndex;
+
+ DisplayOptions _options;
+};
+
+
+class KGVBrowserExtension : public KParts::BrowserExtension
+{
+ Q_OBJECT
+ friend class KGVPart; // emits our signals
+public:
+ KGVBrowserExtension( KGVPart* parent );
+ virtual ~KGVBrowserExtension() {}
+
+public slots:
+ // Automatically detected by konqueror
+ void print();
+};
+
+class KGVRun : public KRun
+{
+ Q_OBJECT
+
+public:
+ KGVRun( const KURL& url, mode_t mode = 0,
+ bool isLocalFile = false, bool showProgressInfo = true );
+
+ virtual ~KGVRun();
+
+signals:
+ void finished( const QString& mimetype );
+
+protected:
+ void foundMimeType( const QString& mimetype );
+
+protected slots:
+ void emitFinishedWithMimetype() { emit finished( _mimetype ); }
+
+private:
+ QString _mimetype;
+};
+
+#endif
+
+// vim:sw=4:sts=4:ts=8:sta:tw=78:noet
diff --git a/kghostview/kgvconfigdialog.cpp b/kghostview/kgvconfigdialog.cpp
new file mode 100644
index 00000000..a9952008
--- /dev/null
+++ b/kghostview/kgvconfigdialog.cpp
@@ -0,0 +1,154 @@
+/**
+ * Copyright (C) 2000-2002 the KGhostView authors. See file AUTHORS.
+ *
+ * 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.
+ */
+
+
+// Add header files alphabetically
+
+#include <qlayout.h>
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <kinstance.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kprocess.h>
+#include <kstandarddirs.h>
+#include <kconfigdialog.h>
+
+#include "configuration.h"
+#include "kgv_view.h"
+#include "kgvfactory.h"
+
+#include "generalsettingswidget.h"
+#include "gssettingswidget.h"
+
+#include "kgvconfigdialog.h"
+
+
+namespace {
+ QString getGSVersion( QString fullPathToExec )
+ {
+ QString res;
+ QString chkVersion = KProcess::quote(fullPathToExec) + " --version";
+ FILE* p = popen( QFile::encodeName(chkVersion), "r" );
+ if( p ) {
+ // FIXME: a badly configured interpreter can hang us
+ QFile qp;
+ qp.open( IO_ReadOnly, p );
+ qp.readLine( res, 80 );
+ qp.close();
+ pclose( p );
+ res = res.stripWhiteSpace();
+ }
+ kdDebug(4500) << "kgvconfigdialog.cpp::{unamed}::getGSVersion() returning " << res << endl;
+ return res;
+ }
+
+
+ /* A mechanism for triggering redetection of gs versions:
+ *
+ * The idea is that whenever we find we need to workaround a certain version of gs,
+ * we cannot rely that there will solelly be a new kghostviewrc, but that users will
+ * upgrade kghostview. Therefore, whenever we want to trigger redection on a new version,
+ * we increment the counter below. It should have the old value from the previous version
+ * of kghostview and this function will get called.
+ *
+ */
+
+ /* On a related note:
+ * We don't detect upgrades (or downgrades, for that matter) of gs.
+ * I am seeing if I can get the version out of gs as a side effect to displaying a file.
+ * This way, using kconfig:/Ghostscript/GS Version we will see whether the version has changed
+ * and trigger a redetection without the trouble of running "gs --version" on each launch.
+ *
+ * LPC (9 April 2003)
+ */
+ /* currentRedetection value log:
+ *
+ * 1- remove -dMaxBitmap for gs 6.5x
+ * 2- see if it supports .setsafe ( see bug:57291 ).
+ */
+ const int currentRedetection = 2;
+
+
+ /* Here are the issues we found so far in version of gs:
+ *
+ * - gs before 6.50 uses device x11alpha instead of x11
+ * - gs 6.5x does not work well with -dMaxBitmap=...
+ * - gs 6.52 and earlier as well as 7.0x for x < 4 don't support the .setsafe operator
+ *
+ */
+
+ QString recommendSetSafe( QString version )
+ {
+ if ( version < QString::number( 6.53 ) ) return QString::number( 6.53 );
+ if ( version[ 0 ] == '7' && version < QString::number( 7.04 ) ) return QString::number( 7.05 );
+ return QString::null;
+ }
+ // This function should contain all the gs version specific workarounds.
+ void redoGSDetection()
+ {
+ kdDebug(4500) << "kgvconfigdialog.cpp::{unnamed}::redoGSDetection()" << endl;
+ QString version = getGSVersion( Configuration::interpreter() );
+ QString recommended = recommendSetSafe( version );
+ if ( !recommended.isNull() ) {
+ KMessageBox::sorry( 0,
+ i18n( "Your version of gs (version %1) is too old, since it has security issues "
+ "which are impossible to resolve. Please upgrade to a newer version.\n"
+ "KGhostView will try to work with it, but it may not display any files at all.\n"
+ "Version %2 seems to be appropriate on your system, although newer versions will work as well." )
+ .arg( version )
+ .arg( recommended ) );
+ }
+ if ( version < QString::number( 7.00 ) )
+ {
+ QStringList arguments = QStringList::split( ' ', Configuration::antialiasingArguments() );
+ arguments.remove( QString::fromLatin1( "-dMaxBitmap=10000000" ) );
+ QString antiAliasArgs = arguments.join( " " );
+
+ Configuration::setAntialiasingArguments( antiAliasArgs );
+ }
+
+ Configuration::setRedetectionCounter( currentRedetection );
+ Configuration::setVersion( version );
+ }
+} // namespace
+
+void ConfigDialog::showSettings( KGVPart* main ) {
+ const char* name = "kghostview-settings";
+ if ( KConfigDialog::showDialog( name ) ) return;
+
+ if ( Configuration::redetectionCounter() < currentRedetection ) redoGSDetection();
+
+ KConfigDialog* dialog = new KConfigDialog( 0, name,
+ Configuration::self(), KDialogBase::IconList );
+ dialog->addPage( new GeneralSettingsWidget( 0, "general-settings" ),
+ i18n( "General" ), QString::fromLatin1( "kghostview" ) );
+ GSSettingsWidget *gssw = new GSSettingsWidget( 0, "gs-settings" );
+ dialog->addPage( gssw, i18n( "Ghostscript\nConfiguration" ), QString::fromLatin1( "pdf" ) );
+
+ gssw->setDetectedVersion(Configuration::version());
+
+ QObject::connect( dialog, SIGNAL( settingsChanged() ), main, SLOT( slotConfigurationChanged() ) );
+ dialog->show();
+}
+
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/kgvconfigdialog.h b/kghostview/kgvconfigdialog.h
new file mode 100644
index 00000000..3f7ddead
--- /dev/null
+++ b/kghostview/kgvconfigdialog.h
@@ -0,0 +1,32 @@
+/**
+ * Copyright (C) 2000-2002 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 _INTERPRETER_DIALOG_H_
+#define _INTERPRETER_DIALOG_H_
+
+class KGVPart;
+
+namespace ConfigDialog {
+ void showSettings( KGVPart* );
+
+}
+
+#endif
+
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/kgvdocument.cpp b/kghostview/kgvdocument.cpp
new file mode 100644
index 00000000..d5b7df41
--- /dev/null
+++ b/kghostview/kgvdocument.cpp
@@ -0,0 +1,864 @@
+/**
+ * Copyright (C) 1997-2003 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 <algorithm>
+#include <memory>
+
+#include <qfileinfo.h>
+
+#include <kconfig.h>
+#include <kfiledialog.h>
+#include <kfilterdev.h>
+#include <kinstance.h>
+#include <kmessagebox.h>
+#include <kmimetype.h>
+#include <kprinter.h>
+#include <kprocess.h>
+#include <ktempfile.h>
+#include <kio/netaccess.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "configuration.h"
+#include "kdscerrordialog.h"
+#include "kgv_miniwidget.h"
+#include "marklist.h"
+#include "kgvfactory.h"
+
+extern "C" {
+#include "ps.h"
+}
+
+#include "kgvdocument.h"
+
+using namespace std;
+using namespace KGV;
+
+KGVDocument::KGVDocument( KGVPart* part, const char* name ) :
+ QObject( part, name ),
+ _psFile( 0 ),
+ _part( part ),
+ _tmpUnzipped( 0 ),
+ _tmpFromPDF( 0 ),
+ _tmpDSC( 0 ),
+ _isFileOpen( false ),
+ _dsc( 0 )
+
+{
+ readSettings();
+
+ _pdf2dsc = new Pdf2dsc( _interpreterPath, this );
+ connect( _pdf2dsc, SIGNAL( finished( bool ) ),
+ SLOT( openPDFFileContinue( bool ) ) );
+}
+
+KGVDocument::~KGVDocument()
+{
+ close();
+}
+
+void KGVDocument::readSettings()
+{
+ _interpreterPath = Configuration::interpreter();
+}
+
+/*- OPENING and READING ---------------------------------------------------*/
+
+void KGVDocument::openFile( const QString& name, const QString& mimetype )
+{
+ kdDebug(4500) << "KGVDocument::openFile" << endl;
+
+ close();
+ _fileName = name;
+ _mimetype = mimetype;
+
+ QTimer::singleShot( 0, this, SLOT( doOpenFile() ) );
+}
+
+void KGVDocument::doOpenFile()
+{
+ QFileInfo fileInfo( _fileName );
+ if( !fileInfo.exists() )
+ {
+ KMessageBox::sorry( _part->widget(),
+ i18n( "<qt>Could not open <nobr><strong>%1</strong></nobr>: "
+ "File does not exist.</qt>" )
+ .arg( _fileName ) );
+ emit canceled( QString() );
+ return;
+ }
+ if( !fileInfo.isReadable() )
+ {
+ KMessageBox::sorry( _part->widget(),
+ i18n( "<qt>Could not open <nobr><strong>%1</strong></nobr>: "
+ "Permission denied.</qt>" )
+ .arg( _fileName ) );
+ emit canceled( QString() );
+ return;
+ }
+
+ if( uncompressFile() )
+ {
+ kdDebug( 4500 ) << "FILENAME: " << _fileName << endl;
+ KMimeType::Ptr mimetype = KMimeType::findByPath( _fileName );
+ kdDebug(4500) << "KGVDocument::mimetype: " << mimetype->name()
+ << endl;
+ _mimetype = mimetype->name();
+ }
+
+ // If the file contains a PDF document, create a DSC description file
+ // of the PDF document. This can be passed to Ghostscript just like
+ // an ordinary PS file.
+ if( _mimetype == "application/pdf"
+ || _mimetype == "application/x-pdf" ) // see bug:67474
+ {
+ _tmpDSC = new KTempFile( QString::null, ".ps" );
+ Q_CHECK_PTR( _tmpDSC );
+ if( _tmpDSC->status() != 0 ) {
+ KMessageBox::error( _part->widget(),
+ i18n( "Could not create temporary file: %1" )
+ .arg( strerror( _tmpDSC->status() ) ) );
+ emit canceled( QString() );
+ return;
+ }
+
+ // When pdf2dsc has finished the program will continue with
+ // openPDFFileContinue.
+ _pdf2dsc->run( _fileName, _tmpDSC->name() );
+ return;
+ }
+ else if( _mimetype == "application/postscript"
+ || _mimetype == "application/x-postscript" // see bug:71546
+ || _mimetype == "application/illustrator"
+ || _mimetype == "image/x-eps"
+ || _mimetype == "text/plain" )
+ {
+ _format = PS;
+ openPSFile();
+ return;
+ }
+ else
+ {
+ KMessageBox::sorry( _part->widget(),
+ i18n( "<qt>Could not open <nobr><strong>%1</strong></nobr> "
+ "which has type <strong>%2</strong>. KGhostview can "
+ "only load PostScript (.ps, .eps) and Portable "
+ "Document Format (.pdf) files.</qt>" )
+ .arg( _fileName )
+ .arg( _mimetype ) );
+ emit canceled( QString() );
+ return;
+ }
+}
+
+bool KGVDocument::uncompressFile()
+{
+ // If the file is gzipped, gunzip it to the temporary file _tmpUnzipped.
+ kdDebug(4500) << "KGVDocument::uncompressFile()" << endl;
+
+ auto_ptr<QIODevice> filterDev( KFilterDev::deviceForFile( _fileName, _mimetype, true ) );
+ if ( !filterDev.get() ) {
+ KMimeType::Ptr mt = KMimeType::mimeType(_mimetype);
+ if ( (_fileName.right( 3 ) == ".gz") || mt->is("application/x-gzip") ) {
+ kdDebug(4500) << "KGVDocument::uncompressFile(): manually guessing gzip" << endl;
+ filterDev.reset( KFilterDev::deviceForFile( _fileName, "application/x-gzip", true ) );
+ } else if ( (_fileName.right( 4 ) == ".bz2") || mt->is("application/x-bzip2") ) {
+ kdDebug(4500) << "KGVDocument::uncompressFile(): manually guessing bzip2" << endl;
+ filterDev.reset( KFilterDev::deviceForFile( _fileName, "application/x-bzip2", true ) );
+ } else {
+ kdDebug( 4500 ) << "KGVDocument::uncompressFile(): Unable to guess " << _fileName << endl;
+ }
+ if ( !filterDev.get() )
+ return false;
+ }
+ if( !filterDev->open( IO_ReadOnly ) )
+ {
+ KMessageBox::error( _part->widget(),
+ i18n( "<qt>Could not uncompress <nobr><strong>%1</strong></nobr>.</qt>" )
+ .arg( _fileName ) );
+ emit canceled( QString() );
+ return false;
+ }
+
+ _tmpUnzipped = new KTempFile;
+ Q_CHECK_PTR( _tmpUnzipped );
+ if( _tmpUnzipped->status() != 0 )
+ {
+ KMessageBox::error( _part->widget(),
+ i18n( "Could not create temporary file: %2" )
+ .arg( strerror( _tmpUnzipped->status() ) ) );
+ emit canceled( QString() );
+ return false;
+ }
+
+
+ QByteArray buf( 8192 );
+ int read = 0, wrtn = 0;
+ while( ( read = filterDev->readBlock( buf.data(), buf.size() ) )
+ > 0 )
+ {
+ wrtn = _tmpUnzipped->file()->writeBlock( buf.data(), read );
+ if( read != wrtn )
+ break;
+ }
+
+ if( read != 0 )
+ {
+ KMessageBox::error( _part->widget(),
+ i18n( "<qt>Could not uncompress <nobr><strong>%1</strong></nobr>.</qt>" )
+ .arg( _fileName ) );
+ emit canceled( QString() );
+ return false;
+ }
+
+ _tmpUnzipped->close();
+ _fileName = _tmpUnzipped->name();
+ return true;
+}
+
+void KGVDocument::openPDFFileContinue( bool pdf2dscResult )
+{
+ kdDebug(4500) << "KGVDocument::openPDFFileContinue" << endl;
+
+ if( !pdf2dscResult )
+ {
+ KMessageBox::error( _part->widget(),
+ i18n( "<qt>Could not open file <nobr><strong>%1</strong></nobr>.</qt>" )
+ .arg( _part->url().url() ) );
+ emit canceled( QString() );
+ return;
+ }
+
+ _tmpDSC->close();
+ _format = PDF;
+
+ openPSFile(_tmpDSC->name());
+}
+
+void KGVDocument::openPSFile(const QString &file)
+{
+ QString fileName = file.isEmpty() ? _fileName : file;
+ kdDebug(4500) << "KGVDocument::openPSFile (" << fileName << ")" << endl;
+
+ FILE* fp = fopen( QFile::encodeName( fileName ), "r");
+ if( fp == 0 )
+ {
+ KMessageBox::error( _part->widget(),
+ i18n( "<qt>Error opening file <nobr><strong>%1</strong></nobr>: %2</qt>" )
+ .arg( _part->url().url() )
+ .arg( strerror( errno ) ) );
+ emit canceled( "" );
+ return;
+ }
+ else
+ {
+ _psFile = fp;
+ _isFileOpen = true;
+ scanDSC();
+ emit completed();
+ }
+}
+
+void KGVDocument::fileChanged( const QString& name )
+{
+ kdDebug(4500) << "KGVDocument: fileChanged " << name << endl;
+
+ if( !_psFile )
+ return;
+
+ // unsigned int savepage = _currentPage;
+
+ /*
+ if( openFile( name ) )
+ goToPage( savepage );
+ else
+ emit fileChangeFailed();
+ */
+}
+
+void KGVDocument::scanDSC()
+{
+ _dsc = new KDSC();
+
+ // Disable errorDialog for now while KDSCErrorDialog isn't fully
+ // implemented
+ // KDSCErrorDialog errorDialog;
+ // KDSCErrorThreshold errorHandler( 3, &errorDialog );
+ // _dsc->setErrorHandler( &errorHandler );
+
+ char buf[4096];
+ int count;
+ /*
+ QTime clock;
+ clock.start();
+ */
+ while( ( count = fread( buf, sizeof(char), sizeof( buf ), _psFile ) ) != 0 )
+ {
+ _dsc->scanData( buf, count );
+ /*
+ if( clock.elapsed() > 10 )
+ {
+ kapp->processEvents();
+ clock.start();
+ }
+ */
+ }
+ _dsc->fixup();
+ // _dsc->setErrorHandler( 0 );
+}
+
+void KGVDocument::close()
+{
+ _pdf2dsc->kill();
+ _isFileOpen = false;
+
+ delete _dsc;
+ _dsc = 0;
+
+ if( _psFile )
+ {
+ fclose( _psFile );
+ _psFile = 0;
+ }
+
+ clearTemporaryFiles();
+}
+
+bool KGVDocument::convertFromPDF( const QString& saveFileName,
+ unsigned int firstPage,
+ unsigned int lastPage )
+{
+ // TODO -- timeout/fail on this conversion (it can hang on a bad pdf)
+ // TODO -- use output from gs (leave out -q) to drive a progress bar
+ KProcess process;
+ process << _interpreterPath
+ << "-q"
+ << "-dNOPAUSE"
+ << "-dBATCH"
+ << "-dSAFER"
+ << "-dPARANOIDSAFER"
+ << "-sDEVICE=pswrite"
+ << ( QCString("-sOutputFile=")+QFile::encodeName(saveFileName) )
+ << ( QString("-dFirstPage=")+QString::number( firstPage ) )
+ << ( QString("-dLastPage=")+QString::number( lastPage ) )
+ << "-c"
+ << "save"
+ << "pop"
+ << "-f"
+ << QFile::encodeName(_fileName);
+
+ /*QValueList<QCString> args = process.args();
+ QValueList<QCString>::Iterator it = args.begin();
+ for ( ; it != args.end() ; ++it )
+ kdDebug(4500) << ( *it ) << endl;*/
+
+ if( !process.start( KProcess::Block ) )
+ {
+ kdError() << "convertFromPDF: Couldn't start gs process" << endl;
+ // TODO -- error message (gs not found?)
+ return false;
+ }
+ if ( !process.normalExit() || process.exitStatus() != 0 )
+ {
+ kdError() << "convertFromPDF: normalExit=" << process.normalExit() << " exitStatus=" << process.exitStatus() << endl;
+ // TODO -- error message (can't open, strerr())
+ return false;
+ }
+
+ return true;
+}
+
+void KGVDocument::clearTemporaryFiles()
+{
+ if( _tmpUnzipped ) {
+ _tmpUnzipped->setAutoDelete( true );
+ delete _tmpUnzipped;
+ _tmpUnzipped = 0;
+ }
+ if( _tmpFromPDF ) {
+ _tmpFromPDF->setAutoDelete( true );
+ delete _tmpFromPDF;
+ _tmpFromPDF = 0;
+ }
+ if( _tmpDSC ) {
+ _tmpDSC->setAutoDelete( true );
+ delete _tmpDSC;
+ _tmpDSC = 0;
+ }
+}
+
+
+/*- DOCUMENT --------------------------------------------------------------*/
+
+QStringList KGVDocument::mediaNames() const
+{
+ QStringList names;
+
+ const CDSCMEDIA* m = dsc_known_media;
+ while( m->name ) {
+ names << m->name;
+ m++;
+ }
+
+ if( isOpen() && dsc()->media() ) {
+ for( unsigned int i = 0; i < dsc()->media_count(); i++ ) {
+ if( dsc()->media()[i] && dsc()->media()[i]->name )
+ names << dsc()->media()[i]->name;
+ }
+ }
+
+ return names;
+}
+
+const CDSCMEDIA* KGVDocument::findMediaByName( const QString& mediaName ) const
+{
+ if( !isOpen() )
+ return 0;
+
+ if( dsc()->media() ) {
+ for( unsigned int i = 0; i < dsc()->media_count(); i++ ) {
+ if( dsc()->media()[i] && dsc()->media()[i]->name
+ && qstricmp( mediaName.local8Bit(),
+ dsc()->media()[i]->name ) == 0 ) {
+ return dsc()->media()[i];
+ }
+ }
+ }
+ /* It didn't match %%DocumentPaperSizes: */
+ /* Try our known media */
+ const CDSCMEDIA *m = dsc_known_media;
+ while( m->name ) {
+ if( qstricmp( mediaName.local8Bit(), m->name ) == 0 ) {
+ return m;
+ }
+ m++;
+ }
+
+ return 0;
+}
+
+QSize KGVDocument::computePageSize( const QString& mediaName ) const
+{
+ kdDebug(4500) << "KGVDocument::computePageSize( " << mediaName << " )" << endl;
+
+ if( mediaName == "BoundingBox" ) {
+ if( dsc()->bbox().get() != 0 )
+ return dsc()->bbox()->size();
+ else
+ return QSize( 0, 0 );
+ }
+
+ const CDSCMEDIA* m = findMediaByName( mediaName );
+ Q_ASSERT( m );
+ return QSize( static_cast<int>( m->width ), static_cast<int>( m->height ) );
+}
+
+
+/*- PRINTING and SAVING ---------------------------------------------------*/
+
+QString KGVDocument::pageListToRange( const PageList& pageList )
+{
+ QString range;
+
+ // Iterators marking the begin and end of a successive sequence
+ // of pages.
+ PageList::const_iterator bss( pageList.begin() );
+ PageList::const_iterator ess;
+
+ PageList::const_iterator it ( pageList.begin() );
+
+ while( it != pageList.end() )
+ {
+ ess = it++;
+
+ // If ess points to the end of a successive sequence of pages,
+ // add the stringrepresentation of the sequence to range and
+ // update bss.
+ if( it == pageList.end() || *it != (*ess) + 1 )
+ {
+ if( !range.isEmpty() )
+ range += ",";
+
+ if( bss == ess )
+ range += QString::number( *ess );
+ else
+ range += QString( "%1-%2" ).arg( *bss ).arg( *ess );
+
+ bss = it;
+ }
+ }
+
+ return range;
+}
+
+void KGVDocument::print()
+{
+ if( !dsc() ) return;
+
+ KPrinter printer;
+
+ if( dsc()->isStructured() )
+ {
+ printer.setPageSelection( KPrinter::ApplicationSide );
+
+ printer.setCurrentPage( _part->miniWidget()->displayOptions().page() + 1 );
+ printer.setMinMax( 1, dsc()->page_count() );
+ printer.setOption( "kde-range",
+ pageListToRange( _part->markList()->markList() ) );
+
+ if( printer.setup( _part->widget(), i18n("Print %1").arg(_part->url().fileName()) ) )
+ {
+ KTempFile tf( QString::null, ".ps" );
+ if( tf.status() == 0 )
+ {
+ if ( printer.pageList().empty() ) {
+ KMessageBox::sorry( 0,
+ i18n( "Printing failed because the list of "
+ "pages to be printed was empty." ),
+ i18n( "Error Printing" ) );
+ } else if ( savePages( tf.name(), printer.pageList() ) ) {
+ printer.printFiles( QStringList( tf.name() ), true );
+ } else {
+ KMessageBox::error( 0, i18n( "<qt><strong>Printing failure:</strong><br>Could not convert to PostScript</qt>" ) );
+ }
+ }
+ else
+ {
+ // TODO: Proper error handling
+ ;
+ }
+ }
+ }
+ else
+ {
+ printer.setPageSelection( KPrinter::SystemSide );
+
+ if( printer.setup( _part->widget(), i18n("Print %1").arg(_part->url().fileName()) ) )
+ printer.printFiles( _fileName );
+ }
+}
+
+void KGVDocument::saveAs()
+{
+ if( !isOpen() )
+ return;
+
+ KURL saveURL = KFileDialog::getSaveURL(
+ _part->url().isLocalFile()
+ ? _part->url().url()
+ : _part->url().fileName(),
+ QString::null,
+ _part->widget(),
+ QString::null );
+ if( !KIO::NetAccess::upload( _fileName,
+ saveURL,
+ static_cast<QWidget*>( 0 ) ) ) {
+ // TODO: Proper error dialog
+ }
+}
+
+bool KGVDocument::savePages( const QString& saveFileName,
+ const PageList& pageList )
+{
+ if( pageList.empty() )
+ return true;
+
+ if( _format == PDF )
+ {
+ KTempFile psSaveFile( QString::null, ".ps" );
+ psSaveFile.setAutoDelete( true );
+ if( psSaveFile.status() != 0 )
+ return false;
+
+ // Find the minimum and maximum pagenumber in pageList.
+ int minPage = pageList.first(), maxPage = pageList.first();
+ for( PageList::const_iterator ci = pageList.begin();
+ ci != pageList.end(); ++ci )
+ {
+ minPage = QMIN( *ci, minPage );
+ maxPage = QMAX( *ci, maxPage );
+ }
+
+
+ // TODO: Optimize "print whole document" case
+ //
+ // The convertion below from PDF to PS creates a temporary file which, in
+ // the case where we are printing the whole document will then be
+ // completelly copied to another temporary file.
+ //
+ // In very large files, the inefficiency is visible (measured in
+ // seconds).
+ //
+ // luis_pedro 4 Jun 2003
+
+
+
+ // Convert the pages in the range [minPage,maxPage] from PDF to
+ // PostScript.
+ if( !convertFromPDF( psSaveFile.name(),
+ minPage, maxPage ) )
+ return false;
+
+ // The page minPage in the original file becomes page 1 in the
+ // converted file. We still have to select the desired pages from
+ // this file, so we need to take into account that difference.
+ PageList normedPageList;
+ transform( pageList.begin(), pageList.end(),
+ back_inserter( normedPageList ),
+ bind2nd( minus<int>(), minPage - 1 ) );
+
+ // Finally select the desired pages from the converted file.
+ psCopyDoc( psSaveFile.name(), saveFileName, normedPageList );
+ }
+ else
+ {
+ psCopyDoc( _fileName, saveFileName, pageList );
+ }
+
+ return true;
+}
+
+// length calculates string length at compile time
+// can only be used with character constants
+#define length( a ) ( sizeof( a ) - 1 )
+
+// Copy the headers, marked pages, and trailer to fp
+
+bool KGVDocument::psCopyDoc( const QString& inputFile,
+ const QString& outputFile, const PageList& pageList )
+{
+ FILE* from;
+ FILE* to;
+ char text[ PSLINELENGTH ];
+ char* comment;
+ bool pages_written = false;
+ bool pages_atend = false;
+ unsigned int i = 0;
+ unsigned int pages = 0;
+ long here;
+
+ kdDebug(4500) << "KGVDocument: Copying pages from " << inputFile << " to "
+ << outputFile << endl;
+
+ pages = pageList.size();
+
+ if( pages == 0 ) {
+ KMessageBox::sorry( 0,
+ i18n( "Printing failed because the list of "
+ "pages to be printed was empty." ),
+ i18n( "Error Printing" ) );
+ return false;
+ }
+
+ from = fopen( QFile::encodeName( inputFile ), "r" );
+ to = fopen( QFile::encodeName( outputFile ), "w" );
+
+ // Hack in order to make printing of PDF files work. FIXME
+ CDSC* dsc;
+
+ if( _format == PS )
+ dsc = _dsc->cdsc();
+ else {
+ FILE* fp = fopen( QFile::encodeName( inputFile ), "r");
+ char buf[256];
+ int count;
+ dsc = dsc_init( 0 );
+ while( ( count = fread( buf, 1, sizeof( buf ), fp ) ) != 0 )
+ dsc_scan_data( dsc, buf, count );
+ fclose( fp );
+ if( !dsc )
+ return false;
+
+ dsc_fixup( dsc );
+ }
+
+ here = dsc->begincomments;
+ while( ( comment = pscopyuntil( from, to, here,
+ dsc->endcomments, "%%Pages:" ) ) ) {
+ here = ftell( from );
+ if( pages_written || pages_atend ) {
+ free( comment );
+ continue;
+ }
+ sscanf( comment + length("%%Pages:" ), "%256s", text );
+ text[256] = 0; // Just in case of an overflow
+ if( strcmp( text, "(atend)" ) == 0 ) {
+ fputs( comment, to );
+ pages_atend = true;
+ }
+ else {
+ switch ( sscanf( comment + length( "%%Pages:" ), "%*d %u", &i ) ) {
+ case 1:
+ fprintf( to, "%%%%Pages: %d %d\n", pages, i );
+ break;
+ default:
+ fprintf( to, "%%%%Pages: %d\n", pages );
+ break;
+ }
+ pages_written = true;
+ }
+ free(comment);
+ }
+ pscopy( from, to, dsc->beginpreview, dsc->endpreview );
+ pscopy( from, to, dsc->begindefaults, dsc->enddefaults );
+ pscopy( from, to, dsc->beginprolog, dsc->endprolog );
+ pscopy( from, to, dsc->beginsetup, dsc->endsetup );
+
+ //TODO -- Check that a all dsc attributes are copied
+
+ unsigned int count = 1;
+ PageList::const_iterator it;
+ for( it = pageList.begin(); it != pageList.end(); ++it ) {
+ i = (*it) - 1;
+ comment = pscopyuntil( from, to, dsc->page[i].begin,
+ dsc->page[i].end, "%%Page:" );
+ if ( comment ) free( comment );
+ fprintf( to, "%%%%Page: %s %d\n", dsc->page[i].label,
+ count++ );
+ pscopy( from, to, -1, dsc->page[i].end );
+ }
+
+ here = dsc->begintrailer;
+ while( ( comment = pscopyuntil( from, to, here,
+ dsc->endtrailer, "%%Pages:" ) ) ) {
+ here = ftell( from );
+ if ( pages_written ) {
+ free( comment );
+ continue;
+ }
+ switch ( sscanf( comment + length( "%%Pages:" ), "%*d %u", &i ) ) {
+ case 1:
+ fprintf( to, "%%%%Pages: %d %d\n", pages, i );
+ break;
+ default:
+ fprintf( to, "%%%%Pages: %d\n", pages );
+ break;
+ }
+ pages_written = true;
+ free( comment );
+ }
+
+ fclose( from );
+ fclose( to );
+
+ if( _format == PDF )
+ dsc_free( dsc );
+
+ return true;
+}
+
+#undef length
+
+
+/*- Conversion stuff ------------------------------------------------------*/
+
+/*
+void KGVDocument::runPdf2ps( const QString& pdfName,
+ const QString& dscName )
+{
+ KProcess process;
+ process << _interpreterPath
+ << "-dNODISPLAY"
+ << "-dQUIET"
+ << QString( "-sPDFname=%1" ).arg( pdfName )
+ << QString( "-sDSCnamale locale( "kghostview" );
+ _fallBackPageMedia = pageSizeToString(
+ static_cast< QPrinter::PageSize >( locale.pageSize() ) );
+
+ _usePageLabels = false;
+e=%1" ).arg( dscName )
+ << "pdf2dsc.ps"
+ << "-c"
+ << "quit";
+
+ connect( &process, SIGNAL( processExited( KProcess* ) ),
+ this, SLOT( pdf2psExited( KProcess* ) ) );
+
+ kdDebug(4500) << "KGVDocument: pdf2ps started" << endl;
+ process.start( KProcess::NotifyOnExit );
+}
+
+void KGVDocument::pdf2psExited( KProcess* process )
+{
+ kdDebug(4500) << "KGVDocument: pdf2ps exited" << endl;
+
+ emit pdf2psFinished( process.normalExit() && process.exitStatus() != 0 );
+}
+*/
+
+Pdf2dsc::Pdf2dsc( const QString& ghostscriptPath, QObject* parent, const char* name ) :
+ QObject( parent, name ),
+ _process( 0 ),
+ _ghostscriptPath( ghostscriptPath )
+{}
+
+Pdf2dsc::~Pdf2dsc()
+{
+ kill();
+}
+
+void Pdf2dsc::run( const QString& pdfName, const QString& dscName )
+{
+ kill();
+
+ _process = new KProcess;
+ *_process << _ghostscriptPath
+ << "-dSAFER"
+ << "-dPARANOIDSAFER"
+ << "-dDELAYSAFER"
+ << "-dNODISPLAY"
+ << "-dQUIET"
+ << QString( "-sPDFname=%1" ).arg( pdfName )
+ << QString( "-sDSCname=%1" ).arg( dscName )
+ << "-c"
+ << "<< /PermitFileReading [ PDFname ] /PermitFileWriting [ DSCname ] /PermitFileControl [] >> setuserparams .locksafe"
+ << "-f"
+ << "pdf2dsc.ps"
+ << "-c"
+ << "quit";
+
+ connect( _process, SIGNAL( processExited( KProcess* ) ),
+ this, SLOT( processExited() ) );
+
+ kdDebug(4500) << "Pdf2dsc: started" << endl;
+ _process->start( KProcess::NotifyOnExit );
+}
+
+void Pdf2dsc::kill()
+{
+ if( _process != 0 )
+ {
+ kdDebug(4500) << "Pdf2dsc: killing current process" << endl;
+ delete _process;
+ _process = 0;
+ }
+}
+
+void Pdf2dsc::processExited()
+{
+ kdDebug(4500) << "Pdf2dsc: process exited" << endl;
+
+ emit finished( _process->normalExit() && _process->exitStatus() == 0 );
+ delete _process;
+ _process = 0;
+}
+
+#include "kgvdocument.moc"
+
+
+// vim:sw=4:sts=4:ts=8:sta:tw=78:noet
diff --git a/kghostview/kgvdocument.h b/kghostview/kgvdocument.h
new file mode 100644
index 00000000..960843f8
--- /dev/null
+++ b/kghostview/kgvdocument.h
@@ -0,0 +1,195 @@
+/**
+ * Copyright (C) 1997-2003 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 __KGV_DOCUMENT_H__
+#define __KGV_DOCUMENT_H__
+
+#include <qprinter.h>
+#include <qsize.h>
+#include <qstring.h>
+
+#include "kgv.h"
+#include "dscparse_adapter.h"
+#include "kgv_view.h"
+
+class KPrinter;
+class KTempFile;
+class Pdf2dsc;
+
+class KGVDocument : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum Format { PS, PDF };
+
+ KGVDocument( KGVPart* part, const char* name = 0 );
+ ~KGVDocument();
+
+ void readSettings();
+
+ /**
+ * Is a file currently open?
+ */
+ bool isOpen() const;
+
+ /**
+ * Open the @em local file @p filename asynchronously.
+ */
+ void openFile( const QString& filename, const QString& mimetype );
+
+ /**
+ * Close the document.
+ */
+ void close();
+
+ const QString& fileName() const { return _fileName; }
+ FILE* psFile() { return _psFile; }
+
+ Format format() const { return _format; }
+
+ /**
+ * @return the document structure for the current document, or 0 if no
+ * file is loaded.
+ */
+ KDSC* const dsc() const;
+
+ /**
+ * A list of page media (sizes).
+ */
+ QStringList mediaNames() const;
+
+ const CDSCMEDIA* findMediaByName( const QString& mediaName ) const;
+
+ QSize computePageSize( const QString& pageMedia ) const;
+
+ static QString pageSizeToString( QPrinter::PageSize );
+
+ /**
+ * Returns a QString which contains a range representation of @p pageList.
+ * Examples: [1,3] -> "1,3"
+ * [1,2,3] -> "1-3"
+ * [1,3,4,5,8] -> "1,3-5,8"
+ */
+ static QString pageListToRange( const KGV::PageList& );
+
+public slots:
+ void fileChanged( const QString& );
+
+ void saveAs();
+ void print();
+
+signals:
+ /**
+ * Emitted if a fileChanged() call fails.
+ */
+ void fileChangeFailed();
+
+ void completed();
+ void canceled( const QString& );
+
+protected:
+ void scanDSC();
+ void clearTemporaryFiles();
+
+ /**
+ * Tries to uncompress the file. Returns true if it uncompressed the file
+ * ( it changes _fileName to point to the uncompressed version of the file ).
+ * Else, it does nothing and returns false.
+ *
+ * What type of files this is able to uncompress will depend on the
+ * kdelibs installed. Generally it will work for .gz and .bz2
+ */
+ bool uncompressFile();
+ void openPSFile(const QString &file=QString::null);
+
+protected:
+ bool savePages( const QString& saveFileName,
+ const KGV::PageList& pageList );
+
+ bool psCopyDoc( const QString& inputFile, const QString& outputFile,
+ const KGV::PageList& pageList );
+
+ bool convertFromPDF( const QString& saveFileName,
+ unsigned int firstPage, unsigned int lastPage );
+
+protected slots:
+ void doOpenFile();
+ void openPDFFileContinue( bool pdf2dscResult );
+
+private:
+ FILE* _psFile;
+
+ QString _fileName;
+ QString _mimetype;
+
+ KGVPart* _part;
+
+ Format _format;
+
+ KTempFile* _tmpUnzipped;
+ KTempFile* _tmpFromPDF;
+ KTempFile* _tmpDSC;
+
+ Pdf2dsc* _pdf2dsc;
+
+ QString _interpreterPath;
+
+ bool _isFileOpen;
+
+ KDSC* _dsc;
+};
+
+
+class Pdf2dsc : public QObject
+{
+ Q_OBJECT
+
+public:
+ Pdf2dsc( const QString& ghostscriptPath, QObject* parent = 0, const char* name = 0 );
+ ~Pdf2dsc();
+
+ void run( const QString& pdfName, const QString& dscName );
+ void kill();
+
+signals:
+ void finished( bool result );
+
+protected slots:
+ void processExited();
+
+private:
+ KProcess* _process;
+ QString _ghostscriptPath;
+};
+
+
+inline KDSC* const KGVDocument::dsc() const
+{
+ return _dsc;
+}
+
+inline bool KGVDocument::isOpen() const
+{
+ return _isFileOpen;
+}
+
+
+#endif
+
+// vim:sw=4:sts=4:ts=8:sta:tw=78:noet
diff --git a/kghostview/kgvfactory.cpp b/kghostview/kgvfactory.cpp
new file mode 100644
index 00000000..edf20144
--- /dev/null
+++ b/kghostview/kgvfactory.cpp
@@ -0,0 +1,105 @@
+/**
+ * Copyright (C) 2003, Lus Pedro Coelho,
+ * based on kdelibs/kparts/genericfactory.h
+ *
+ * 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 <kparts/factory.h>
+#include <kparts/part.h>
+#include <kgenericfactory.h>
+#include <kaboutdata.h>
+#include <kdebug.h>
+#include "kgv_view.h"
+
+#include "kgvfactory.h"
+
+KGVFactory::KGVFactory()
+{
+ if ( s_self )
+ kdWarning() << "KGVFactory instantiated more than once!" << endl;
+ s_self = this;
+}
+
+KGVFactory::~KGVFactory()
+{
+ delete s_aboutData;
+ delete s_instance;
+ s_aboutData = 0;
+ s_instance = 0;
+ s_self = 0;
+}
+
+KInstance *KGVFactory::createInstance()
+{
+ KInstance* res = new KInstance( aboutData() );
+ return res;
+}
+
+KGVFactory *KGVFactory::s_self;
+KInstance *KGVFactory::s_instance;
+KAboutData *KGVFactory::s_aboutData;
+
+KParts::Part *KGVFactory::createPartObject( QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name,
+ const char *className,
+ const QStringList &args_ )
+{
+ QStringList args = args_;
+ /* Below is the reason why we must
+ * have our own factory instead of
+ * typedef KParts::GenericFactory<KGVPart> KGVFactory
+ *
+ * as we did before.
+ */
+ args << QString::fromLatin1( className );
+ if ( !strcmp( className, "Browser/View" ) ) {
+ className = "KParts::ReadOnlyPart";
+ }
+ KGVPart *part = KDEPrivate::ConcreteFactory<KGVPart>::create( parentWidget,
+ widgetName,
+ parent,
+ name,
+ className,
+ args );
+
+ if ( part && !qstrcmp( className, "KParts::ReadOnlyPart" ) )
+ {
+ KParts::ReadWritePart *rwp = dynamic_cast<KParts::ReadWritePart *>( part );
+ if ( rwp )
+ rwp->setReadWrite( false );
+ }
+ return part;
+}
+
+KInstance *KGVFactory::instance()
+{
+ if ( !s_instance )
+ {
+ if ( s_self )
+ s_instance = s_self->createInstance();
+ else
+ s_instance = new KInstance( aboutData() );
+ }
+ return s_instance;
+}
+
+KAboutData *KGVFactory::aboutData()
+{
+ if ( !s_aboutData )
+ s_aboutData = KGVPart::createAboutData();
+ return s_aboutData;
+}
+
diff --git a/kghostview/kgvfactory.h b/kghostview/kgvfactory.h
new file mode 100644
index 00000000..238e3557
--- /dev/null
+++ b/kghostview/kgvfactory.h
@@ -0,0 +1,50 @@
+/**
+ * Copyright (C) 2003, Lus Pedro Coelho,
+ * based on kdelibs/kparts/genericfactory.h
+ *
+ * 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 KGVPart_H_INCLUDE_GUARD_
+#define KGVPart_H_INCLUDE_GUARD_
+
+#include <kparts/factory.h>
+#include <kparts/part.h>
+
+class KInstance;
+class KAboutData;
+
+class KDE_EXPORT KGVFactory : public KParts::Factory
+{
+ public:
+ KGVFactory();
+ virtual ~KGVFactory();
+ static KInstance *instance();
+ static KAboutData *aboutData();
+
+ virtual KParts::Part *createPartObject( QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name,
+ const char *className,
+ const QStringList &args );
+
+ protected:
+ virtual KInstance *createInstance();
+ private:
+ static KGVFactory*s_self;
+ static KInstance *s_instance;
+ static KAboutData *s_aboutData;
+};
+
+#endif
+
diff --git a/kghostview/kgvmainwidget.cpp b/kghostview/kgvmainwidget.cpp
new file mode 100644
index 00000000..2bad7f84
--- /dev/null
+++ b/kghostview/kgvmainwidget.cpp
@@ -0,0 +1,50 @@
+/**
+ * Copyright (C) 2001-2002 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 "kgvmainwidget.h"
+#include <kurl.h>
+#include <kurldrag.h>
+
+KGVMainWidget::KGVMainWidget( QWidget* parent, const char* name )
+ : QWidget( parent, name ) {}
+
+void KGVMainWidget::keyPressEvent( QKeyEvent* event )
+{
+ if( event->key() == Key_Space && event->state() != ShiftButton ) {
+ event->accept();
+ emit spacePressed();
+ }
+}
+
+void KGVMainWidget::dropEvent( QDropEvent* ev )
+{
+ KURL::List lst;
+ if ( KURLDrag::decode( ev, lst ) ) {
+ emit urlDropped( lst.first() );
+ }
+}
+
+
+void KGVMainWidget::dragEnterEvent( QDragEnterEvent * ev )
+{
+ ev->accept();
+}
+
+#include "kgvmainwidget.moc"
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/kgvmainwidget.h b/kghostview/kgvmainwidget.h
new file mode 100644
index 00000000..0e79fbd6
--- /dev/null
+++ b/kghostview/kgvmainwidget.h
@@ -0,0 +1,45 @@
+/**
+ * Copyright (C) 2001-2002 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 KGVMAINWIDGET_H
+#define KGVMAINWIDGET_H
+
+#include <qwidget.h>
+
+class KURL;
+
+class KGVMainWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ KGVMainWidget( QWidget* parent = 0, const char* name = 0 );
+
+signals:
+ void spacePressed();
+ void urlDropped( const KURL& );
+
+protected:
+ virtual void keyPressEvent( QKeyEvent* );
+ virtual void dragEnterEvent( QDragEnterEvent* );
+ virtual void dropEvent( QDropEvent* );
+};
+
+#endif
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/kgvpagedecorator.cpp b/kghostview/kgvpagedecorator.cpp
new file mode 100644
index 00000000..e1eccfc7
--- /dev/null
+++ b/kghostview/kgvpagedecorator.cpp
@@ -0,0 +1,106 @@
+/**
+ * Copyright (C) 2001-2002 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 <qbitmap.h>
+#include <qdrawutil.h>
+#include <qpainter.h>
+#include <qregion.h>
+
+#include "kgvpagedecorator.h"
+
+KGVPageDecorator::KGVPageDecorator( QWidget* parent, const char* name ) :
+ QHBox( parent, name ),
+ _margin( 5 ),
+ _borderWidth( 1 ),
+ _shadowOffset( 2, 2 )
+{
+ setFrameStyle( Box | Plain );
+ setLineWidth( _margin + _borderWidth );
+ setBackgroundMode( NoBackground );
+ setAutoMask( true );
+}
+
+bool KGVPageDecorator::eventFilter( QObject* o, QEvent* e )
+{
+ switch( e->type() ) {
+ case QEvent::MouseButtonPress:
+ case QEvent::MouseButtonRelease:
+ case QEvent::MouseButtonDblClick:
+ case QEvent::MouseMove:
+ return event( e );
+ default:
+ ;
+ }
+ return QHBox::eventFilter( o, e );
+}
+
+void KGVPageDecorator::childEvent( QChildEvent* e )
+{
+ if( e->child()->isWidgetType() && e->inserted() )
+ e->child()->installEventFilter( this );
+}
+
+void KGVPageDecorator::drawFrame( QPainter* p )
+{
+ QRect r( frameRect().topLeft() + QPoint(_margin,_margin),
+ frameRect().bottomRight() - QPoint(_margin,_margin) );
+
+ if( !r.isValid() )
+ return;
+
+ const QColorGroup& cg = colorGroup();
+
+ r.moveCenter( r.center() + _shadowOffset );
+ qDrawPlainRect( p, r, cg.shadow(), _shadowOffset.manhattanLength() );
+
+ r.moveCenter( r.center() - _shadowOffset );
+ qDrawPlainRect( p, r, cg.foreground(), _borderWidth );
+}
+
+void KGVPageDecorator::drawMask( QPainter* p )
+{
+ QRect r( frameRect().topLeft() + QPoint(_margin,_margin),
+ frameRect().bottomRight() - QPoint(_margin,_margin) );
+
+ if( !r.isValid() )
+ return;
+
+ QColorGroup cg( color1, color1, color1, color1, color1, color1, color1,
+ color1, color0 );
+ QBrush brush( cg.foreground() );
+
+ r.moveCenter( r.center() + _shadowOffset );
+ qDrawPlainRect( p, r, cg.foreground(), _shadowOffset.manhattanLength() );
+
+ r.moveCenter( r.center() - _shadowOffset );
+ qDrawPlainRect( p, r, cg.foreground(), _borderWidth, &brush );
+}
+
+void KGVPageDecorator::updateMask()
+{
+ QBitmap bm( size() );
+ bm.fill( color0 );
+ QPainter p( &bm, this );
+ p.setPen( color1 );
+ p.setBrush( color1 );
+ drawMask( &p );
+ p.end();
+ setMask( bm );
+}
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/kgvpagedecorator.h b/kghostview/kgvpagedecorator.h
new file mode 100644
index 00000000..72ceb956
--- /dev/null
+++ b/kghostview/kgvpagedecorator.h
@@ -0,0 +1,81 @@
+/**
+ * Copyright (C) 2001-2002 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 KGVPAGEDECORATOR_H
+#define KGVPAGEDECORATOR_H
+
+#include <qhbox.h>
+
+class KGVPageDecorator : public QHBox
+{
+public:
+ KGVPageDecorator( QWidget* parent = 0, const char* name = 0 );
+ ~KGVPageDecorator() { ; }
+
+ unsigned int margin() const;
+ unsigned int borderWidth() const;
+
+ /**
+ * Reimplemented from QObject to let mouse events from child widgets
+ * appear to come from this widget.
+ */
+ bool eventFilter( QObject*, QEvent* );
+
+protected:
+ /**
+ * Reimplemented from QObject to automatically insert an event filter
+ * on child widgets.
+ */
+ virtual void childEvent( QChildEvent* );
+
+ /**
+ * Reimplemented from QFrame to draw a pageshadow like frame.
+ */
+ virtual void drawFrame( QPainter* );
+
+ /**
+ * Draw the mask of both the frame and the contents in order to create a
+ * partially transparent frame.
+ */
+ virtual void drawMask( QPainter* );
+
+ /**
+ * Reimplemented from QWidget. It uses @ref drawMask() to draw the mask
+ * of the frame when transparency is required.
+ */
+ virtual void updateMask();
+
+private:
+ unsigned int _margin;
+ unsigned int _borderWidth;
+ QPoint _shadowOffset;
+};
+
+inline unsigned int KGVPageDecorator::margin() const
+{
+ return _margin;
+}
+
+inline unsigned int KGVPageDecorator::borderWidth() const
+{
+ return _borderWidth;
+}
+
+#endif
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/kgvpageview.cpp b/kghostview/kgvpageview.cpp
new file mode 100644
index 00000000..8a8af585
--- /dev/null
+++ b/kghostview/kgvpageview.cpp
@@ -0,0 +1,254 @@
+/**
+ * Copyright (C) 2001-2002 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 <qdatetime.h>
+
+#include <kdebug.h>
+
+#include "kgvpageview.h"
+
+KGVPageView::KGVPageView( QWidget* parent, const char* name )
+ : QScrollView( parent, name )
+{
+ _page = 0;
+
+ setFocusPolicy( QWidget::StrongFocus );
+ viewport()->setFocusPolicy( QWidget::WheelFocus );
+}
+
+void KGVPageView::setPage( QWidget* page )
+{
+ if( page != 0 ) {
+ addChild( page );
+ centerContents();
+ _page = page;
+ }
+}
+
+bool KGVPageView::atTop() const
+{
+ return verticalScrollBar()->value() == verticalScrollBar()->minValue();
+}
+
+bool KGVPageView::atBottom() const
+{
+ return verticalScrollBar()->value() == verticalScrollBar()->maxValue();
+}
+
+bool KGVPageView::eventFilter( QObject* o, QEvent* e )
+{
+ if ( o == _page && e->type() == QEvent::Resize ) {
+ // We need to call QScrollView::eventFilter before centerContents,
+ // otherwise a loop will be introduced.
+ bool result = QScrollView::eventFilter( o, e );
+ centerContents();
+ emit pageSizeChanged( _page->size() );
+ return result;
+ }
+ return QScrollView::eventFilter( o, e );
+}
+
+
+void KGVPageView::wheelEvent( QWheelEvent *e )
+{
+ int delta = e->delta();
+ e->accept();
+ if ((e->state() & ControlButton) == ControlButton) {
+ if ( e->delta() < 0 )
+ emit zoomOut();
+ else
+ emit zoomIn();
+ }
+ else if ( delta <= -120 && atBottom() )
+ {
+ emit ReadDown();
+ }
+ else if ( delta >= 120 && atTop())
+ {
+ emit ReadUp();
+ }
+
+ else
+ QScrollView::wheelEvent( e );
+}
+void KGVPageView::mousePressEvent( QMouseEvent * e )
+{
+ if ( e->button() & LeftButton )
+ {
+ _dragGrabPos = e -> globalPos();
+ setCursor( sizeAllCursor );
+ }
+ else if ( e->button() & MidButton )
+ {
+ emit ReadDown();
+ }
+ else if ( e -> button() & RightButton )
+ {
+ emit rightClick();
+ }
+}
+
+void KGVPageView::mouseReleaseEvent( QMouseEvent *e )
+{
+ if ( e -> button() & LeftButton )
+ {
+ setCursor( arrowCursor );
+ }
+}
+
+void KGVPageView::mouseMoveEvent( QMouseEvent * e )
+{
+ if ( e->state() & LeftButton )
+ {
+ QPoint delta = _dragGrabPos - e->globalPos();
+ scrollBy( delta.x(), delta.y() );
+ _dragGrabPos = e->globalPos();
+ }
+}
+
+bool KGVPageView::readUp()
+{
+ if( atTop() )
+ return false;
+ else {
+ int newValue = QMAX( verticalScrollBar()->value() - height() + 50,
+ verticalScrollBar()->minValue() );
+
+ /*
+ int step = 10;
+ int value = verticalScrollBar()->value();
+ while( value > newValue - step ) {
+ verticalScrollBar()->setValue( value );
+ value -= step;
+ }
+ */
+
+ verticalScrollBar()->setValue( newValue );
+ return true;
+ }
+}
+
+bool KGVPageView::readDown()
+{
+ if( atBottom() )
+ return false;
+ else {
+ int newValue = QMIN( verticalScrollBar()->value() + height() - 50,
+ verticalScrollBar()->maxValue() );
+
+ /*
+ int step = 10;
+ int value = verticalScrollBar()->value();
+ while( value < newValue + step ) {
+ verticalScrollBar()->setValue( value );
+ value += step;
+ }
+ */
+
+ verticalScrollBar()->setValue( newValue );
+ return true;
+ }
+}
+
+void KGVPageView::scrollRight()
+{
+ horizontalScrollBar()->addLine();
+}
+
+void KGVPageView::scrollLeft()
+{
+ horizontalScrollBar()->subtractLine();
+}
+
+void KGVPageView::scrollDown()
+{
+ verticalScrollBar()->addLine();
+}
+
+void KGVPageView::scrollUp()
+{
+ verticalScrollBar()->subtractLine();
+}
+
+void KGVPageView::scrollBottom()
+{
+ verticalScrollBar()->setValue( verticalScrollBar()->maxValue() );
+}
+
+void KGVPageView::scrollTop()
+{
+ verticalScrollBar()->setValue( verticalScrollBar()->minValue() );
+}
+
+void KGVPageView::enableScrollBars( bool b )
+{
+ setHScrollBarMode( b ? Auto : AlwaysOff );
+ setVScrollBarMode( b ? Auto : AlwaysOff );
+}
+
+void KGVPageView::keyPressEvent( QKeyEvent* e )
+{
+ switch ( e->key() ) {
+ case Key_Up:
+ scrollUp();
+ break;
+ case Key_Down:
+ scrollDown();
+ break;
+ case Key_Left:
+ scrollLeft();
+ break;
+ case Key_Right:
+ scrollRight();
+ break;
+ default:
+ e->ignore();
+ return;
+ }
+ e->accept();
+}
+
+void KGVPageView::viewportResizeEvent( QResizeEvent* e )
+{
+ QScrollView::viewportResizeEvent( e );
+ emit viewSizeChanged( viewport()->size() );
+ centerContents();
+}
+
+void KGVPageView::centerContents()
+{
+ if( !_page )
+ return;
+
+ int newX = 0;
+ int newY = 0;
+
+ QSize newViewportSize = viewportSize( _page->width(),
+ _page->height() );
+
+ if( newViewportSize.width() > _page->width() )
+ newX = ( newViewportSize.width() - _page->width() )/2;
+ if( newViewportSize.height() > _page->height() )
+ newY = ( newViewportSize.height() - _page->height() )/2;
+
+ moveChild( _page, newX, newY );
+}
+
+#include "kgvpageview.moc"
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/kgvpageview.h b/kghostview/kgvpageview.h
new file mode 100644
index 00000000..9a1abac3
--- /dev/null
+++ b/kghostview/kgvpageview.h
@@ -0,0 +1,105 @@
+/**
+ * Copyright (C) 2001-2002 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 KGVPAGEVIEW_H
+#define KGVPAGEVIEW_H
+
+#include <qscrollview.h>
+
+/**
+ * KGVPageView is a customized QScrollView, which can hold one page. This page
+ * will be centered on the viewport. Furthermore it adds the ability to scroll
+ * the page by dragging it using the mouse.
+ */
+class KGVPageView : public QScrollView
+{
+ Q_OBJECT
+
+public:
+ KGVPageView( QWidget* parent = 0, const char* name = 0 );
+ ~KGVPageView() { ; }
+
+ void setPage( QWidget* );
+ QWidget* page() const { return _page; }
+
+ /**
+ * Return true if the top resp. bottom of the page is visible.
+ */
+ bool atTop() const;
+ bool atBottom() const;
+
+ /**
+ * Turn the scrollbars on/off.
+ */
+ void enableScrollBars( bool);
+
+ /**
+ * @reimplemented
+ */
+ bool eventFilter( QObject*, QEvent* );
+
+public slots:
+ bool readUp();
+ bool readDown();
+ void scrollUp();
+ void scrollDown();
+ void scrollRight();
+ void scrollLeft();
+ void scrollBottom();
+ void scrollTop();
+
+signals:
+ void viewSizeChanged( const QSize& );
+ void pageSizeChanged( const QSize& );
+ void nextPage();
+ void zoomOut();
+ void zoomIn();
+ void prevPage();
+ void rightClick();
+ void ReadUp();
+ void ReadDown();
+
+protected:
+ virtual void keyPressEvent( QKeyEvent* );
+
+ /**
+ * Reimplemented to from QScrollView to make sure that the page is centered
+ * when it fits in the viewport.
+ */
+ virtual void viewportResizeEvent( QResizeEvent* );
+
+ virtual void mousePressEvent( QMouseEvent *e );
+ virtual void mouseReleaseEvent( QMouseEvent *e );
+ virtual void mouseMoveEvent( QMouseEvent *e );
+ virtual void wheelEvent( QWheelEvent * );
+
+ /**
+ * If the viewport is larger than the page, center the page on the
+ * viewport.
+ */
+ void centerContents();
+
+private:
+ QPoint _dragGrabPos;
+ QWidget* _page;
+};
+
+#endif
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/kgvshell.cpp b/kghostview/kgvshell.cpp
new file mode 100644
index 00000000..1dc546d5
--- /dev/null
+++ b/kghostview/kgvshell.cpp
@@ -0,0 +1,370 @@
+/**
+ * Copyright (C) 2000-2002 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 <assert.h>
+#include <stdlib.h>
+
+#include <kaction.h>
+#include <kapplication.h>
+#include <kfiledialog.h>
+#include <kiconloader.h>
+#include <klibloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <kstatusbar.h>
+#include <kstdaction.h>
+#include <kstdaccel.h>
+#include <ktempfile.h>
+#include <kmenubar.h>
+#include <kedittoolbar.h>
+#include <kdebug.h>
+
+#include <kicontheme.h>
+#include <kglobal.h>
+#include <kpopupmenu.h>
+#include <kparts/componentfactory.h>
+
+#include <kwin.h>
+
+#include <qcursor.h>
+
+#include "kgv_miniwidget.h"
+#include "kgv_view.h"
+#include "kgvpageview.h"
+#include "displayoptions.h"
+#include "fullscreenfilter.h"
+
+#undef Always // avoid X11/Qt namespace clash
+#include "kgvshell.moc"
+
+//TODO -- disable GUI when no file
+//TODO -- don't stay open when no file, go directly to KFileDialog
+
+KGVShell::KGVShell() :
+ _tmpFile( 0 )
+{
+ m_gvpart = KParts::ComponentFactory::createPartInstanceFromLibrary< KGVPart >( "libkghostviewpart", this, "kgvpart",
+ this, "kgvpart" );
+
+ /*---- File -----------------------------------------------------------*/
+ openact =
+ KStdAction::open( this, SLOT( slotFileOpen() ),
+ actionCollection() );
+ recent =
+ KStdAction::openRecent( this, SLOT( openURL( const KURL& ) ),
+ actionCollection() );
+ KStdAction::print( m_gvpart->document(), SLOT( print() ),
+ actionCollection() );
+ (void)
+ KStdAction::quit( this, SLOT( slotQuit() ), actionCollection() );
+
+ /*---- View -----------------------------------------------------------*/
+ new KAction( i18n( "&Reload" ), "reload",
+ KStdAccel::shortcut( KStdAccel::Reload ),
+ m_gvpart, SLOT( reloadFile() ),
+ actionCollection(), "reload" );
+ new KAction( i18n( "&Maximize" ), Key_M, this,
+ SLOT( slotMaximize() ), actionCollection(),
+ "maximize");
+ _showMenuBarAction = KStdAction::showMenubar( this, SLOT( slotShowMenubar() ), actionCollection() );
+
+ /*---- Settings -------------------------------------------------------*/
+#if KDE_VERSION >= KDE_MAKE_VERSION(3,1,90)
+ createStandardStatusBarAction();
+#endif
+ setAutoSaveSettings();
+ setStandardToolBarMenuEnabled(true);
+#if KDE_VERSION >= KDE_MAKE_VERSION(3,1,90)
+ m_fullScreenAction = KStdAction::fullScreen( this, SLOT( slotUpdateFullScreen() ), actionCollection(), this );
+#else
+ m_fullScreenAction = new KToggleAction( this, SLOT( slotUpdateFullScreen() ) );
+#endif
+ KStdAction::configureToolbars( this, SLOT( slotConfigureToolbars() ), actionCollection() );
+ KStdAction::keyBindings(guiFactory(), SLOT(configureShortcuts()),
+actionCollection());
+
+ //_popup = new KPopupMenu( i18n( "Full Screen Options" ), this, "rmb popup" );
+ _popup = new KPopupMenu( this, "rmb popup" );
+ _popup->insertTitle( i18n( "Full Screen Options" ) );
+ m_fullScreenAction->plug( _popup );
+ _showMenuBarAction->plug( _popup );
+
+ m_fsFilter = new FullScreenFilter( *this );
+
+ // Just save them automatically is destructor. (TODO: of kgv_view!)
+ //KStdAction::saveOptions ( this, SLOT (slotWriteSettings()), actionCollection());
+
+ setXMLFile( "kghostviewui.rc" );
+
+ // We could, at the user's option, make this connection and kghostview
+ // will always resize to fit the width of the page. But, for now,
+ // let's not.
+ // connect ( m_gvpart->widget(), SIGNAL (sizeHintChanged()), this, SLOT (slotResize ()) );
+
+ setCentralWidget( m_gvpart->widget() );
+ createGUI( m_gvpart );
+
+ connect( m_gvpart->pageView(), SIGNAL( rightClick() ),SLOT( slotRMBClick() ) );
+ connect( m_gvpart, SIGNAL( canceled(const QString&) ),SLOT( slotReset() ) );
+ connect( m_gvpart, SIGNAL( completed() ), SLOT( slotDocumentState() ) );
+
+ if (!initialGeometrySet())
+ resize(640,400);
+
+ readSettings();
+ stateChanged( "initState" );
+
+ // Make sure the view has the keyboard focus.
+ m_gvpart->widget()->setFocus();
+}
+
+KGVShell::~KGVShell()
+{
+ writeSettings();
+
+ if( _tmpFile )
+ {
+ _tmpFile->setAutoDelete( true );
+ delete _tmpFile;
+ _tmpFile = 0;
+ }
+
+ // delete m_gvpart;
+}
+
+void
+KGVShell::slotQuit()
+{
+ kapp->closeAllWindows();
+}
+
+void KGVShell::slotShowMenubar()
+{
+ if ( _showMenuBarAction->isChecked() ) menuBar()->show();
+ else menuBar()->hide();
+}
+
+void
+KGVShell::setDisplayOptions( const DisplayOptions& options )
+{
+ m_gvpart->setDisplayOptions( options );
+}
+
+void KGVShell::slotReset()
+{
+ kdDebug( 4500 ) << "KGVShell::slotReset()" << endl;
+ stateChanged( "initState" );
+}
+
+void
+KGVShell::readProperties( KConfig *config )
+{
+ KURL url = KURL::fromPathOrURL( config->readPathEntry( "URL" ) );
+ if ( url.isValid() ) {
+ openURL( url );
+ DisplayOptions options;
+ if ( DisplayOptions::fromString( options, config->readEntry( "Display Options" ) ) ) m_gvpart->setDisplayOptions( options );
+ }
+}
+
+void
+KGVShell::saveProperties( KConfig* config )
+{
+ config->writePathEntry( "URL", m_gvpart->url().prettyURL() );
+ config->writeEntry( "Display Options", DisplayOptions::toString( m_gvpart->miniWidget()->displayOptions() ) );
+}
+
+void
+KGVShell::readSettings()
+{
+ recent->loadEntries( KGlobal::config() );
+ QStringList items = recent->items();
+
+// Code copied from kviewshell.cpp:
+// Constant source of annoyance in KDVI < 1.0: the 'recent-files'
+// menu contains lots of files which don't exist (any longer). Thus,
+// we'll sort out the non-existent files here.
+
+ for ( QStringList::Iterator it = items.begin(); it != items.end(); ++it ) {
+ KURL url(*it);
+ if (url.isLocalFile()) {
+ QFileInfo info(url.path());
+ if (!info.exists())
+ recent->removeURL(url);
+ }
+ }
+
+ applyMainWindowSettings(KGlobal::config(), "MainWindow");
+
+ KGlobal::config()->setDesktopGroup();
+ bool fullScreen = KGlobal::config()->readBoolEntry( "FullScreen", false );
+ setFullScreen( fullScreen );
+ _showMenuBarAction->setChecked( menuBar()->isVisible() );
+}
+
+void
+KGVShell::writeSettings()
+{
+ saveMainWindowSettings(KGlobal::config(), "MainWindow");
+
+ recent->saveEntries( KGlobal::config() );
+
+ KGlobal::config()->setDesktopGroup();
+ KGlobal::config()->writeEntry( "FullScreen", m_fullScreenAction->isChecked());
+
+ KGlobal::config()->sync();
+}
+
+void
+KGVShell::openURL( const KURL & url )
+{
+ if( m_gvpart->openURL( url ) ) recent->addURL (url);
+}
+
+void
+KGVShell::openStdin()
+{
+ if( _tmpFile )
+ {
+ _tmpFile->setAutoDelete( true );
+ delete _tmpFile;
+ }
+
+ _tmpFile = new KTempFile;
+ _tmpFile->setAutoDelete( true );
+
+ if( _tmpFile->status() != 0 ) {
+ KMessageBox::error( this,
+ i18n( "Could not create temporary file: %1" )
+ .arg( strerror( _tmpFile->status() ) ) );
+ return;
+ }
+
+ QByteArray buf( BUFSIZ );
+ int read = 0, wrtn = 0;
+ while( ( read = fread( buf.data(), sizeof(char), buf.size(), stdin ) )
+ > 0 ) {
+ wrtn = _tmpFile->file()->writeBlock( buf.data(), read );
+ if( read != wrtn )
+ break;
+ kapp->processEvents();
+ }
+
+ if( read != 0 ) {
+ KMessageBox::error( this,
+ i18n( "Could not open standard input stream: %1" )
+ .arg( strerror( errno ) ) );
+ return;
+ }
+
+ _tmpFile->close();
+
+ if( m_gvpart->openURL( KURL::fromPathOrURL( _tmpFile->name() ) ) ) setCaption( "stdin" );
+}
+
+void KGVShell::slotFileOpen()
+{
+ KURL url = KFileDialog::getOpenURL( cwd, i18n(
+ "*.ps *.ps.bz2 *.ps.gz *.eps *.eps.gz *.pdf|All Document Files\n"
+ "*.ps *.ps.bz2 *.ps.gz|PostScript Files\n"
+ "*.pdf *.pdf.gz *.pdf.bz2|Portable Document Format (PDF) Files\n"
+ "*.eps *.eps.gz *.eps.bz2|Encapsulated PostScript Files\n"
+ "*|All Files" ) );
+
+ if( !url.isEmpty() ) {
+ openURL( url );
+ }
+}
+
+void KGVShell::slotDocumentState()
+{
+ stateChanged( "documentState" );
+}
+
+
+void KGVShell::slotMaximize()
+{
+ kdDebug(4500) << "KGVShell::slotMaximize()" << endl;
+ KWin::setState( winId(), NET::MaxHoriz | NET::MaxVert );
+ // If we do it now, it comes to nothing since it would work
+ // on the current (non-maximized) size
+ QTimer::singleShot( 800, m_gvpart, SLOT( slotFitToPage() ) );
+}
+
+void KGVShell::slotResize()
+{
+ resize( m_gvpart->pageView()->sizeHint().width(), height() );
+}
+
+void KGVShell::setFullScreen( bool useFullScreen )
+{
+ if( useFullScreen )
+ showFullScreen();
+ else if( isFullScreen())
+ showNormal();
+}
+
+void KGVShell::slotUpdateFullScreen()
+{
+ if( m_fullScreenAction->isChecked())
+ {
+ menuBar()->hide();
+ statusBar()->hide();
+ toolBar()->hide();
+ m_gvpart->updateFullScreen( true );
+ showFullScreen();
+ kapp->installEventFilter( m_fsFilter );
+ if ( m_gvpart->document()->isOpen() )
+ m_gvpart->slotFitToPage();
+ }
+ else
+ {
+ kapp->removeEventFilter( m_fsFilter );
+ m_gvpart->updateFullScreen( false );
+ menuBar()->show();
+#if KDE_VERSION >= KDE_MAKE_VERSION(3,1,90)
+ KToggleAction *statusbarAction = dynamic_cast<KToggleAction *>(actionCollection()->action(KStdAction::name(KStdAction::ShowStatusbar)));
+ assert( statusbarAction );
+ if (statusbarAction->isChecked()) statusBar()->show();
+#endif
+ toolBar()->show();
+ showNormal();
+ }
+}
+
+void KGVShell::slotConfigureToolbars()
+{
+ saveMainWindowSettings( KGlobal::config(), "MainWindow" );
+ KEditToolbar dlg( factory() );
+ connect(&dlg,SIGNAL(newToolbarConfig()),this,SLOT(slotNewToolbarConfig()));
+ dlg.exec();
+}
+
+void KGVShell::slotNewToolbarConfig()
+{
+ applyMainWindowSettings( KGlobal::config(), "MainWindow" );
+}
+
+void KGVShell::slotRMBClick()
+{
+ _popup->exec( QCursor::pos() );
+}
+
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/kgvshell.h b/kghostview/kgvshell.h
new file mode 100644
index 00000000..872430c1
--- /dev/null
+++ b/kghostview/kgvshell.h
@@ -0,0 +1,92 @@
+/**
+ * Copyright (C) 2000-2002 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 __KGVSHELL_H__
+#define __KGVSHELL_H__
+
+#include <qstring.h>
+
+#include <kparts/mainwindow.h>
+
+class QTimer;
+
+class KRecentFilesAction;
+class ScrollBox;
+class KGVPart;
+class KAction;
+class KConfig;
+class KTempFile;
+class KPopupMenu;
+class DisplayOptions;
+class FullScreenFilter;
+
+class KDE_EXPORT KGVShell : public KParts::MainWindow
+{
+ Q_OBJECT
+
+public:
+ KGVShell();
+ virtual ~KGVShell();
+
+public slots:
+ void openURL( const KURL& url );
+ void openStdin();
+ void setDisplayOptions( const DisplayOptions& );
+ void slotRMBClick();
+
+protected slots:
+ void slotFileOpen();
+ void slotShowMenubar();
+ void slotQuit();
+ void slotMaximize();
+ void slotResize();
+ void slotUpdateFullScreen();
+ void slotReset();
+ void slotDocumentState();
+ void slotConfigureToolbars();
+ void slotNewToolbarConfig();
+
+protected:
+ // session management
+ virtual void saveProperties( KConfig *config );
+ virtual void readProperties( KConfig *config );
+
+ void readSettings();
+ void writeSettings();
+ void enableStateDepActions( bool enable );
+ void setFullScreen( bool );
+
+private:
+
+ friend class FullScreenFilter;
+
+ KGVPart* m_gvpart;
+ QString cwd;
+
+ KAction* openact;
+ KToggleAction* _showMenuBarAction;
+ KToggleAction* m_fullScreenAction;
+ FullScreenFilter* m_fsFilter;
+ KPopupMenu* _popup;
+ KRecentFilesAction* recent;
+ KTempFile* _tmpFile; // Used for storing data received from stdin
+};
+
+#endif
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/kpswidget.cpp b/kghostview/kpswidget.cpp
new file mode 100644
index 00000000..b51cda5e
--- /dev/null
+++ b/kghostview/kpswidget.cpp
@@ -0,0 +1,530 @@
+/**
+ * Copyright (C) 2000-2003 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 "kpswidget.h"
+
+#include <stdlib.h>
+#include <math.h>
+
+#include <qstringlist.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kprocess.h>
+
+#include "configuration.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+int handler( Display* d, XErrorEvent* e )
+{
+ char msg[80], req[80], number[80];
+
+ XGetErrorText( d, e->error_code, msg, sizeof( msg ) );
+ sprintf( number, "%d", e->request_code );
+ XGetErrorDatabaseText( d, "XRequest", number, "<unknown>",
+ req, sizeof( req ) );
+ return 0;
+}
+
+int orientation2angle( CDSC_ORIENTATION_ENUM orientation )
+{
+ Q_ASSERT( orientation != CDSC_ORIENT_UNKNOWN );
+
+ int angle = 0;
+
+ switch( orientation )
+ {
+ case CDSC_ORIENT_UNKNOWN: break; // Catched by Q_ASSERT
+ case CDSC_PORTRAIT: angle = 0; break;
+ case CDSC_LANDSCAPE: angle = 90; break;
+ case CDSC_UPSIDEDOWN: angle = 180; break;
+ case CDSC_SEASCAPE: angle = 270; break;
+ }
+
+ return angle;
+}
+
+QCString palette2String( Configuration::EnumPalette::type palette )
+{
+ QCString str;
+
+ switch( palette )
+ {
+ case Configuration::EnumPalette::Color: str = "Color"; break;
+ case Configuration::EnumPalette::Grayscale: str = "Grayscale"; break;
+ case Configuration::EnumPalette::Monochrome: str = "Monochrome"; break;
+ default: kdWarning( 4500 ) << "palette2String(): unkown palette" << endl;
+ str = "Color";
+ }
+
+ return str;
+}
+
+
+KPSWidget::KPSWidget( QWidget* parent, const char* name ) :
+ QWidget ( parent, name ),
+ _gsWindow ( None ),
+ _usePipe ( false ),
+ _doubleBuffer ( false ),
+ _ghostscriptDirty ( false ),
+ _orientation ( CDSC_PORTRAIT ),
+ _magnification ( 1 ),
+ _palette ( Configuration::EnumPalette::Color ),
+ _widgetDirty ( true ),
+ _process ( 0 ),
+ _buffer ( 0 ),
+ _stdinReady ( false ),
+ _interpreterBusy ( false ),
+ _interpreterReady ( false )
+{
+ XSetErrorHandler( handler );
+
+ // Create the Atoms used to communicate with Ghostscript.
+ const char* const atomNames[] = { "GHOSTVIEW", "GHOSTVIEW_COLORS",
+ "NEXT", "PAGE", "DONE" };
+ XInternAtoms( x11Display(), const_cast<char**>( atomNames ),
+ 5, false, _atoms );
+
+ // readSettings() TODO
+}
+
+KPSWidget::~KPSWidget()
+{
+ if ( _buffer ) operator delete( _buffer );
+ stopInterpreter();
+}
+
+bool KPSWidget::isInterpreterReady() const
+{
+ return isInterpreterRunning() && _interpreterReady;
+}
+
+bool KPSWidget::isInterpreterBusy() const
+{
+ return _interpreterBusy;
+}
+
+bool KPSWidget::isInterpreterRunning() const
+{
+ return ( _process && _process->isRunning() );
+}
+
+bool KPSWidget::nextPage()
+{
+ if( !isInterpreterReady() )
+ return false;
+
+ if( _gsWindow == None ) {
+ kdDebug(4500) << "communication window unknown!" << endl;
+ return false;
+ }
+
+ _interpreterReady = false;
+ _interpreterBusy = true;
+ setCursor( waitCursor );
+
+ XEvent e;
+ e.xclient.type = ClientMessage;
+ e.xclient.display = x11Display();
+ e.xclient.window = _gsWindow;
+ e.xclient.message_type = _atoms[NEXT];
+ e.xclient.format = 32;
+
+ XSendEvent( x11Display(), _gsWindow, false, 0, &e );
+ XFlush( x11Display() );
+ return true;
+}
+
+
+void KPSWidget::clear()
+{
+ //_backgroundPixmap.fill();
+}
+
+
+bool KPSWidget::sendPS( FILE* fp, unsigned int begin, unsigned int end )
+{
+ kdDebug(4500) << "KPSWidget::sendPS" << endl;
+
+ if( !isInterpreterRunning() )
+ return false;
+
+ // Create a new record to add to the queue.
+ _inputQueue.push( Record( fp, begin, end - begin ) );
+
+ // Start processing the queue.
+ if( _stdinReady )
+ gs_input(_process);
+
+ return true;
+}
+
+void KPSWidget::setGhostscriptPath( const QString& path )
+{
+ kdDebug() << "KPSWidget::setGhostscriptPath( " << path << " )" << endl;
+ if( _ghostscriptPath != path )
+ {
+ _ghostscriptPath = path;
+ stopInterpreter();
+ _ghostscriptDirty = true;
+ }
+}
+
+void KPSWidget::setGhostscriptArguments( const QStringList& arguments )
+{
+ if( _ghostscriptArguments != arguments )
+ {
+ _ghostscriptArguments = arguments;
+ stopInterpreter();
+ _ghostscriptDirty = true;
+ }
+}
+
+void KPSWidget::setFileName( const QString& fileName, bool usePipe )
+{
+ if(( _fileName != fileName ) || (_usePipe != usePipe))
+ {
+ _usePipe = usePipe;
+ _fileName = fileName;
+ stopInterpreter();
+ _ghostscriptDirty = true;
+ }
+}
+
+void KPSWidget::setOrientation( CDSC_ORIENTATION_ENUM orientation )
+{
+ if( _orientation != orientation )
+ {
+ _orientation = orientation;
+ stopInterpreter();
+ _widgetDirty = true;
+ }
+}
+
+void KPSWidget::setBoundingBox( const KDSCBBOX& boundingBox )
+{
+ if( _boundingBox != boundingBox )
+ {
+ _boundingBox = boundingBox;
+ stopInterpreter();
+ _widgetDirty = true;
+ }
+}
+
+void KPSWidget::setMagnification( double magnification )
+{
+ if( kAbs( magnification - _magnification ) > 0.0001 )
+ {
+ _magnification = magnification;
+ stopInterpreter();
+ _widgetDirty = true;
+ }
+}
+
+void KPSWidget::setPalette( Configuration::EnumPalette::type palette )
+{
+ if( _palette != palette )
+ {
+ _palette = palette;
+ stopInterpreter();
+ _widgetDirty = true;
+ }
+}
+
+void KPSWidget::setDoubleBuffering( bool db )
+{
+ if( _doubleBuffer != db )
+ {
+ _doubleBuffer = db;
+ stopInterpreter();
+ _widgetDirty = true;
+ }
+}
+
+namespace {
+ /* Rounding up is better than normal rounding because it is better to have a pixel too many than one too little.
+ * If we have one too many, no one will notice. If we have one too little, gs complains.
+ *
+ * I have a file which isn't displayed (gs error) without this fix.
+ */
+ inline int round_up( double x )
+ {
+ return static_cast<int>( ceil( x ) );
+ }
+}
+
+void KPSWidget::setupWidget()
+{
+ if( !_widgetDirty )
+ return;
+
+ Q_ASSERT( orientation() != CDSC_ORIENT_UNKNOWN );
+
+ const float dpiX = _magnification * x11AppDpiX();
+ const float dpiY = _magnification * x11AppDpiY();
+
+ int newWidth = 0, newHeight = 0;
+ if( orientation() == CDSC_PORTRAIT || orientation() == CDSC_UPSIDEDOWN )
+ {
+ newWidth = round_up( boundingBox().width() * dpiX / 72.0 );
+ newHeight = round_up( boundingBox().height() * dpiY / 72.0 );
+ }
+ else
+ {
+ newWidth = round_up( boundingBox().height() * dpiX / 72.0 );
+ newHeight = round_up( boundingBox().width() * dpiY / 72.0 );
+ }
+
+ if( newWidth != width() || newHeight != height() )
+ {
+ setEraseColor( white );
+ setFixedSize( newWidth, newHeight );
+ kapp->processEvents();
+
+ _backgroundPixmap.resize( size() );
+ _backgroundPixmap.fill( white );
+ // The line below is needed to work around certain "features" of styles such as liquid
+ // see bug:61711 for more info (LPC, 20 Aug '03)
+ setBackgroundOrigin( QWidget::WidgetOrigin );
+ setErasePixmap( _backgroundPixmap );
+ }
+
+ char data[512];
+
+ sprintf( data, "%ld %d %d %d %d %d %g %g",
+ ( _doubleBuffer ? 0 : _backgroundPixmap.handle() ),
+ orientation2angle( orientation() ),
+ boundingBox().llx(), boundingBox().lly(),
+ boundingBox().urx(), boundingBox().ury(),
+ dpiX, dpiY );
+ XChangeProperty( x11Display(), winId(),
+ _atoms[GHOSTVIEW],
+ XA_STRING, 8, PropModeReplace,
+ (unsigned char*) data, strlen( data ) );
+
+ sprintf( data, "%s %d %d",
+ palette2String( _palette ).data(),
+ (int)BlackPixel( x11Display(), DefaultScreen( x11Display() ) ),
+ (int)WhitePixel( x11Display(), DefaultScreen( x11Display() ) ) );
+ XChangeProperty( x11Display(), winId(),
+ _atoms[GHOSTVIEW_COLORS],
+ XA_STRING, 8, PropModeReplace,
+ (unsigned char*) data, strlen( data ) );
+
+ // Make sure the properties are updated immediately.
+ XSync( x11Display(), false );
+
+ repaint();
+
+ _widgetDirty = false;
+}
+
+bool KPSWidget::startInterpreter()
+{
+ setupWidget();
+
+ _process = new KProcess;
+ if ( _doubleBuffer ) _process->setEnvironment( "GHOSTVIEW", QString( "%1 %2" ).arg( winId() ).arg( _backgroundPixmap.handle() ) );
+ else _process->setEnvironment( "GHOSTVIEW", QString::number( winId() ) );
+
+ *_process << _ghostscriptPath.local8Bit();
+ *_process << _ghostscriptArguments;
+
+ if( _usePipe )
+ *_process <<
+ // The following two lines are their to ensure that we are allowed to read _fileName
+ "-dDELAYSAFER" << "-sInputFile="+_fileName << "-c" <<
+ "<< /PermitFileReading [ InputFile ] /PermitFileWriting [] /PermitFileControl [] >> setuserparams .locksafe" <<
+ "-";
+ else
+ *_process << _fileName << "-c" << "quit";
+
+ connect( _process, SIGNAL( processExited( KProcess* ) ),
+ this, SLOT( slotProcessExited( KProcess* ) ) );
+ connect( _process, SIGNAL( receivedStdout( KProcess*, char*, int ) ),
+ this, SLOT( gs_output( KProcess*, char*, int ) ) );
+ connect( _process, SIGNAL( receivedStderr( KProcess*, char*, int ) ),
+ this, SLOT( gs_output( KProcess*, char*, int ) ) );
+ connect( _process, SIGNAL( wroteStdin( KProcess*) ),
+ this, SLOT( gs_input( KProcess* ) ) );
+
+ kapp->flushX();
+
+ // Finally fire up the interpreter.
+ kdDebug(4500) << "KPSWidget: starting interpreter" << endl;
+ if( _process->start( KProcess::NotifyOnExit,
+ _usePipe ? KProcess::All : KProcess::AllOutput ) )
+ {
+ _interpreterBusy = true;
+ setCursor( waitCursor );
+
+ _stdinReady = true;
+ _interpreterReady = false;
+ _ghostscriptDirty = false;
+
+ return true;
+ }
+ else
+ {
+ KMessageBox::error( this,
+ i18n( "Could not start Ghostscript. This is most likely "
+ "caused by an incorrectly specified interpreter." ) );
+ return false;
+ }
+}
+
+void KPSWidget::stopInterpreter()
+{
+ kdDebug(4500) << "KPSWidget::stopInterpreter()" << endl;
+ // if( !_interpreterBusy ) return;
+
+ if( isInterpreterRunning() )
+ _process->kill( SIGHUP );
+
+ _process = 0;
+ while ( !_inputQueue.empty() ) _inputQueue.pop();
+
+ _interpreterBusy = false;
+ unsetCursor();
+}
+
+void KPSWidget::interpreterFailed()
+{
+ stopInterpreter();
+}
+
+void KPSWidget::slotProcessExited( KProcess* process )
+{
+ kdDebug(4500) << "KPSWidget: process exited" << endl;
+
+ if ( process == _process )
+ {
+ kdDebug( 4500 ) << "KPSWidget::slotProcessExited(): looks like it was not a clean exit." << endl;
+ if ( process->normalExit() ) {
+ emit ghostscriptError( QString( i18n( "Exited with error code %1." ).arg( process->exitStatus() ) ) );
+ } else {
+ emit ghostscriptError( QString( i18n( "Process killed or crashed." ) ) );
+ }
+ _process = 0;
+ stopInterpreter();
+ unsetCursor();
+ }
+}
+
+void KPSWidget::gs_output( KProcess*, char* buffer, int len )
+{
+ emit output( buffer, len );
+}
+
+void KPSWidget::gs_input( KProcess* process )
+{
+ kdDebug(4500) << "KPSWidget::gs_input" << endl;
+
+ if (process != _process)
+ {
+ kdDebug(4500) << "KPSWidget::gs_input(): process != _process" << endl;
+ return;
+ }
+ _stdinReady = true;
+
+ while( ! _inputQueue.empty() && _inputQueue.front().len == 0 ) _inputQueue.pop();
+ if( _inputQueue.empty() ) {
+ _interpreterReady = true;
+ return;
+ }
+
+ Record& current = _inputQueue.front();
+
+ if ( fseek( current.fp, current.begin, SEEK_SET ) ) {
+ kdDebug(4500) << "KPSWidget::gs_input(): seek failed!" << endl;
+ interpreterFailed();
+ return;
+ }
+ Q_ASSERT( current.len > 0 );
+
+ const unsigned buffer_size = 4096;
+ if ( !_buffer ) _buffer = static_cast<char*>( operator new( buffer_size ) );
+ const int bytesRead = fread( _buffer, sizeof (char),
+ QMIN( buffer_size, current.len ),
+ current.fp );
+ if( bytesRead > 0 )
+ {
+ current.begin += bytesRead;
+ current.len -= bytesRead;
+ if( process && process->writeStdin( _buffer, bytesRead ) )
+ _stdinReady = false;
+ else
+ interpreterFailed();
+ }
+ else
+ interpreterFailed();
+}
+
+void KPSWidget::readSettings()
+{
+ setGhostscriptPath( Configuration::interpreter() );
+
+ QStringList arguments;
+
+ if( Configuration::antialiasing() )
+ arguments = QStringList::split( " ", Configuration::antialiasingArguments() );
+ else
+ arguments = QStringList::split( " ", Configuration::nonAntialiasingArguments() );
+
+ if( !Configuration::platformFonts() )
+ arguments << "-dNOPLATFONTS";
+
+ arguments << "-dNOPAUSE" << "-dQUIET" << "-dSAFER" << "-dPARANOIDSAFER";
+
+ setGhostscriptArguments( arguments );
+
+ setPalette( static_cast<Configuration::EnumPalette::type>( Configuration::palette() ) );
+}
+
+bool KPSWidget::x11Event( XEvent* e )
+{
+ if( e->type == ClientMessage )
+ {
+ _gsWindow = e->xclient.data.l[0];
+
+ if( e->xclient.message_type == _atoms[PAGE] )
+ {
+ kdDebug(4500) << "KPSWidget: received PAGE" << endl;
+ _interpreterBusy = false;
+ unsetCursor();
+ emit newPageImage( _backgroundPixmap );
+ if ( _doubleBuffer ) setErasePixmap( _backgroundPixmap );
+ return true;
+ }
+ else if( e->xclient.message_type == _atoms[DONE] )
+ {
+ kdDebug(4500) << "KPSWidget: received DONE" << endl;
+ stopInterpreter();
+ return true;
+ }
+ }
+ return QWidget::x11Event( e );
+}
+
+#include "kpswidget.moc"
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/kpswidget.h b/kghostview/kpswidget.h
new file mode 100644
index 00000000..66ef0b14
--- /dev/null
+++ b/kghostview/kpswidget.h
@@ -0,0 +1,387 @@
+/**
+ * Copyright (C) 2000-2003 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 __KPSWIDGET_H__
+#define __KPSWIDGET_H__
+
+#include <queue>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qwidget.h>
+#include <qpixmap.h>
+
+#include "dscparse_adapter.h"
+#include "configuration.h"
+
+#include <X11/X.h>
+
+class KProcess;
+
+class KGVConfigDialog;
+class MessagesDialog;
+
+/**
+ * @class KPSWidget
+ *
+ * @brief KPSWidget is a widget on which Ghostscript can render.
+ *
+ * @ref ghostscript_interface
+ */
+
+class KPSWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ KPSWidget( QWidget* parent = 0, const char* name = 0 );
+ ~KPSWidget();
+
+ /**
+ * Start up the Ghostscript interpreter. Returns true if Ghostscript
+ * could be started; otherwise false.
+ */
+ bool startInterpreter();
+
+ /**
+ * Stop the interpreter process.
+ */
+ void stopInterpreter();
+
+ /**
+ * Returns true if the interpreter is ready for new input.
+ */
+ bool isInterpreterReady() const;
+
+ bool isInterpreterBusy() const;
+
+ /**
+ * Returns true if the interpreter is running; otherwise returns false.
+ */
+ bool isInterpreterRunning() const;
+
+ /**
+ * Tell ghostscript to start the next page.
+ * Returns false if ghostscript is not running, or not ready to start
+ * another page. If another page is started, sets the _interpreterReady
+ * flag and cursor.
+ */
+ bool nextPage();
+
+ /**
+ * Queue a portion of a PostScript file for output to ghostscript and
+ * start processing the queue.
+ *
+ * fp: FILE* of the file in question. Should be seek()able.
+ * begin: position in file to start.
+ * len: number of bytes to write.
+ *
+ * If an interpreter is not running, nothing is queued and false is
+ * returned.
+ */
+ bool sendPS( FILE*, unsigned int begin, unsigned int end );
+
+ /**
+ * Sets the filename of the ghostscript input.
+ * @p usePipe indicates whether we use a pipe for
+ * communication or let ghoscript read the file itself.
+ */
+ void setFileName( const QString&, bool usePipe );
+
+ /**
+ * Set the bounding box of the drawable. See my comment in the source
+ * file.
+ */
+ void setBoundingBox( const KDSCBBOX& );
+
+ /**
+ * Set the orientation of the page.
+ */
+ void setOrientation( CDSC_ORIENTATION_ENUM );
+
+ /**
+ * Sets the resolution according to the physical resolution of the screen
+ * and the magnification value.
+ */
+ void setMagnification( double magnification );
+
+ /**
+ * @return the boundingbox of the drawable.
+ */
+ const KDSCBBOX& boundingBox() const;
+
+ /**
+ * @return the current orientation.
+ */
+ CDSC_ORIENTATION_ENUM orientation() const;
+
+ /**
+ * Double buffering means that all the drawing is done outside the
+ * screen and the finished picture is then flashed to the screen.
+ * This reduces flicker ( to almost none ) at the price of speed.
+ *
+ * By default, KPSWidget is *not* double buffered.
+ */
+ bool isDoubleBuffered() const { return _doubleBuffer; }
+ void setDoubleBuffering( bool n );
+
+
+ void clear();
+
+public slots:
+ /**
+ * Call this when the settings have changed.
+ */
+ void readSettings();
+signals:
+ /**
+ * This signal gets emited whenever a page is finished, but contains a reference to the pixmap
+ * used to hold the image.
+ *
+ * Don't change the pixmap or bad things will happen. This is the backing pixmap of the display.
+ */
+ void newPageImage( QPixmap image );
+
+ /**
+ * This signal is emitted whenever the ghostscript process has
+ * written data to stdout or stderr.
+ */
+ void output( char* data, int len );
+
+ /**
+ * This means that gs exited uncleanly
+ *
+ * @param msg a <strong>translated</strong> error message to display the user which may be null if we cannot tell anything important
+ */
+ void ghostscriptError( const QString& mgs );
+
+protected:
+ struct Record
+ {
+ Record( FILE* fp_, long begin_, unsigned len_ )
+ :fp( fp_ ), begin( begin_ ), len( len_ ) { }
+
+ FILE* fp;
+ long begin;
+ unsigned int len;
+ };
+
+ // void resizeEvent( QResizeEvent* );
+ bool x11Event( XEvent* );
+
+ /**
+ * Setup the widget according to the current settings for the
+ * boundingBox, the resolution and the orientation. This involves
+ * the following things:
+ * - Resize the widget
+ * - Resize and clear the background pixmap.
+ * - Setup the GHOSTVIEW and GHOSTVIEW_COLORS properties.
+ *
+ * Make sure ghostscript isn't running when calling this method.
+ */
+ void setupWidget();
+
+ void setGhostscriptPath( const QString& );
+ void setGhostscriptArguments( const QStringList& );
+ void setPalette( Configuration::EnumPalette::type );
+
+protected slots:
+ void gs_input( KProcess* );
+ void gs_output( KProcess*, char* buffer, int len );
+ void interpreterFailed();
+ void slotProcessExited( KProcess* );
+
+private:
+ Window _gsWindow; // Destination of ghostscript messages.
+
+ enum AtomName { GHOSTVIEW = 0, GHOSTVIEW_COLORS, NEXT, PAGE, DONE };
+ Atom _atoms[5];
+
+ QPixmap _backgroundPixmap;
+
+ /**
+ * The following properties determine how Ghostscript is started.
+ * If any of these is changed, Ghostscript needs to be restarted.
+ */
+ QString _ghostscriptPath;
+ QStringList _ghostscriptArguments;
+ QString _fileName;
+ bool _usePipe;
+ bool _doubleBuffer;
+
+ /**
+ * Flag set when one of the properties _ghostscriptPath,
+ * _ghostscriptArguments or _fileName has been changed.
+ */
+ bool _ghostscriptDirty;
+
+ /**
+ * The following properties determine how Ghostscript renders its
+ * pages. If any of these is changed, the widget needs to be setup,
+ * and Ghostscript needs to be restarted.
+ */
+ CDSC_ORIENTATION_ENUM _orientation;
+ KDSCBBOX _boundingBox;
+ float _magnification;
+ Configuration::EnumPalette::type _palette;
+
+ /**
+ * Flag set when one of the properties _orientation, _boundingBox,
+ * _dpi[X|Y] or _palette has been changed.
+ */
+ bool _widgetDirty;
+
+ KProcess* _process;
+ char* _buffer;
+
+ std::queue<Record> _inputQueue;
+
+ bool _stdinReady;
+ bool _interpreterBusy;
+ bool _interpreterReady;
+};
+
+inline const KDSCBBOX& KPSWidget::boundingBox() const
+{
+ return _boundingBox;
+}
+
+inline CDSC_ORIENTATION_ENUM KPSWidget::orientation() const
+{
+ return _orientation;
+}
+
+/**
+ * @page ghostview_interface Ghostview interface to Ghostscript
+ *
+ * When the GHOSTVIEW environment variable is set, Ghostscript draws on
+ * an existing drawable rather than creating its own window. Ghostscript
+ * can be directed to draw on either a window or a pixmap.
+ *
+ *
+ * @section window Drawing on a Window
+ *
+ * The GHOSTVIEW environment variable contains the window id of the target
+ * window. The window id is an integer. Ghostscript will use the attributes
+ * of the window to obtain the width, height, colormap, screen, and visual of
+ * the window. The remainder of the information is gotten from the GHOSTVIEW
+ * property on that window.
+ *
+ *
+ * @section pixmap Drawing on a Pixmap
+ *
+ * The GHOSTVIEW environment variable contains a window id and a pixmap id.
+ * They are integers separated by white space. Ghostscript will use the
+ * attributes of the window to obtain the colormap, screen, and visual to use.
+ * The width and height will be obtained from the pixmap. The remainder of the
+ * information, is gotten from the GHOSTVIEW property on the window. In this
+ * case, the property is deleted when read.
+ *
+ *
+ * @section gv_variable The GHOSTVIEW environment variable
+ *
+ * @par parameters:
+ * <tt> window-id [pixmap-id] </tt>
+ *
+ * @par scanf format:
+ * @code "%d %d" @endcode
+ *
+ * @par Explanation of the parameters
+ * @li @e window-id:
+ * tells Ghostscript where to:
+ * - read the GHOSTVIEW property
+ * - send events
+ * If pixmap-id is not present, Ghostscript will draw on this window.
+ *
+ * @li @e pixmap-id:
+ * If present, tells Ghostscript that a pixmap will be used as the
+ * final destination for drawing. The window will not be touched for
+ * drawing purposes.
+ *
+ *
+ * @section gv_property The GHOSTVIEW property
+ *
+ * @par type:
+ * STRING
+ *
+ * @par parameters:
+ * <tt> bpixmap orient llx lly urx ury xdpi ydpi [left bottom top right]
+ * </tt>
+ *
+ * @par scanf format:
+ * @code "%d %d %d %d %d %d %f %f %d %d %d %d" @endcode
+ *
+ * @par Explanation of the parameters
+ * @li @e bpixmap:
+ * pixmap id of the backing pixmap for the window. If no pixmap is to
+ * be used, this parameter should be zero. This parameter must be zero
+ * when drawing on a pixmap.
+ *
+ * @li <em>orient:</em>
+ * orientation of the page. The number represents clockwise rotation
+ * of the paper in degrees. Permitted values are 0, 90, 180, 270.
+ *
+ * @li <em>llx, lly, urx, ury:</em>
+ * Bounding box of the drawable. The bounding box is specified in
+ * PostScript points in default user coordinates. (Note the word
+ * @e drawable. This means that this bounding box is generally not
+ * the same as the BoundingBox specified in the DSC. In case
+ * DocumentMedia is specified, it is equal to the Media's bounding
+ * box.)
+ *
+ * @li <em>xdpi, ydpi:</em>
+ * Resolution of window. (This can be derived from the other
+ * parameters, but not without roundoff error. These values are
+ * included to avoid this error.)
+ *
+ * @li <em>left, bottom, top, right (optional):</em>
+ * Margins around the window. The margins extend the imageable area
+ * beyond the boundaries of the window. This is primarily used for
+ * popup zoom windows. I have encountered several instances of
+ * PostScript programs that position themselves with respect to the
+ * imageable area. The margins are specified in PostScript points.
+ * If omitted, the margins are assumed to be 0.
+ *
+ *
+ * @section events Events from Ghostscript
+ *
+ * If the final destination is a pixmap, the client will get a property
+ * notify event when Ghostscript reads the GHOSTVIEW property causing it to
+ * be deleted.
+ *
+ * Ghostscript sends events to the window where it read the GHOSTVIEW
+ * property. These events are of type ClientMessage. The message_type is set
+ * to either PAGE or DONE. The first long data value gives the window to be
+ * used to send replies to Ghostscript. The second long data value gives the
+ * primary drawable. If rendering to a pixmap, it is the primary drawable.
+ * If rendering to a window, the backing pixmap is the primary drawable. If
+ * no backing pixmap is employed, then the window is the primary drawable.
+ * This field is necessary to distinguish multiple Ghostscripts rendering to
+ * separate pixmaps where the GHOSTVIEW property was placed on the same
+ * window.
+ *
+ * The PAGE message indicates that a "page" has completed. Ghostscript will
+ * wait until it receives a ClientMessage whose message_type is NEXT before
+ * continuing.
+ *
+ * The DONE message indicates that Ghostscript has finished processing.
+ */
+
+#endif // __KPSWIDGET_H__
+
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/logwindow.cpp b/kghostview/logwindow.cpp
new file mode 100644
index 00000000..df2e5765
--- /dev/null
+++ b/kghostview/logwindow.cpp
@@ -0,0 +1,76 @@
+/**
+ * Copyright (C) 2003 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 <qtextedit.h>
+#include <qlabel.h>
+#include <qvbox.h>
+
+#include <kglobalsettings.h>
+#include <kurllabel.h>
+#include <klocale.h>
+
+#include "logwindow.h"
+
+LogWindow::LogWindow( const QString& caption,
+ QWidget* parent, const char* name) :
+ KDialogBase( parent, name, false, caption, User1|Close, Close, false,
+ KStdGuiItem::clear() )
+{
+ QVBox * display = makeVBoxMainWidget();
+
+ _errorIndication = new QLabel( "", display, "logview-label" );
+ _errorIndication->hide();
+
+ _configureGS = new KURLLabel( i18n( "Configure Ghostscript" ), QString::null, display );
+ _configureGS->hide();
+
+ _logView = new QTextEdit( display, "logview" );
+ _logView->setTextFormat( Qt::PlainText );
+ _logView->setReadOnly( true );
+ _logView->setWordWrap( QTextEdit::NoWrap );
+ _logView->setFont( KGlobalSettings::fixedFont() );
+ _logView->setMinimumWidth( 80 * fontMetrics().width( " " ) );
+
+ connect( this, SIGNAL( user1Clicked() ), SLOT( clear() ) );
+ connect( _configureGS, SIGNAL( leftClickedURL() ), SLOT( emitConfigureGS() ) );
+}
+
+void LogWindow::emitConfigureGS() {
+ emit configureGS();
+}
+
+void LogWindow::append( const QString& message )
+{
+ _logView->append( message );
+}
+
+void LogWindow::clear()
+{
+ _logView->clear();
+ _errorIndication->clear();
+}
+
+void LogWindow::setLabel( const QString& text, bool showConfigureGS )
+{
+ _errorIndication->setText( text );
+ _errorIndication->show();
+ if ( showConfigureGS ) _configureGS->show();
+ else _configureGS->hide();
+}
+
+#include "logwindow.moc"
diff --git a/kghostview/logwindow.h b/kghostview/logwindow.h
new file mode 100644
index 00000000..4eb099e0
--- /dev/null
+++ b/kghostview/logwindow.h
@@ -0,0 +1,55 @@
+/**
+ * Copyright (C) 2003 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 LOGWINDOW_H
+#define LOGWINDOW_H
+
+#include <kdialogbase.h>
+
+class QLabel;
+class QTextEdit;
+class KURLLabel;
+
+class LogWindow : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ LogWindow( const QString& caption,
+ QWidget* parent = 0, const char* name = 0 );
+
+public slots:
+ void append( const QString& message );
+ void clear();
+ void setLabel( const QString&, bool showConfigureGSLink );
+
+private slots:
+ void emitConfigureGS();
+
+signals:
+ void configureGS();
+
+private:
+ QLabel* _errorIndication;
+ QTextEdit* _logView;
+ KURLLabel* _configureGS;
+};
+
+#endif
+
+// vim:sw=4:sts=4:ts=8:sta:tw=78:noet
diff --git a/kghostview/main.cpp b/kghostview/main.cpp
new file mode 100644
index 00000000..26574ddf
--- /dev/null
+++ b/kghostview/main.cpp
@@ -0,0 +1,71 @@
+/**
+ * Copyright (C) 1997-2002 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 <qdir.h>
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+#include <kurl.h>
+
+#include "kgvshell.h"
+#include "kgv_view.h"
+#include "displayoptions.h"
+
+static KCmdLineOptions options[] =
+{
+ { "page <page-no>", I18N_NOOP( "Page to open. Use --page=3 to show the third page, for example. Note that if the page does not exist, any other page may be displayed" ), "1" },
+ { "scale <factor>", I18N_NOOP( "Magnification of the display" ), "1.0" },
+ { "orientation <orientation>", I18N_NOOP( "The orientation of the shown image. Use either \"auto\", \"portrait\", \"landscape\", \"upsidedown\" or \"seascape\"" ), "auto" },
+ { "portrait", I18N_NOOP( "Equivalent to orientation=portrait" ), 0 },
+ { "landscape", I18N_NOOP( "Equivalent to orientation=landscape" ), 0 },
+ { "upsidedown", I18N_NOOP( "Equivalent to orientation=upsidedown" ), 0 },
+ { "seascape", I18N_NOOP( "Equivalent to orientation=seascape" ), 0 },
+ // { "watch", I18N_NOOP( "Turns on watching of a file. This means that whenever the file changes while you are viewing it, kghostview automatically reloads it. This option (which can also be turned on in the menu) is especially useful if you are generating your files from latex or a similar tool." ), 0 },
+ // { "page-size", I18N_NOOP( "The page size.\nUse either something like \"A4\" or you can display exact pixel size width-height" ), "auto" }
+ { "+[URL]", I18N_NOOP( "Location to open" ), 0 },
+ KCmdLineLastOption
+};
+
+int main( int argc, char** argv )
+{
+ KCmdLineArgs::init( argc, argv, KGVPart::createAboutData() );
+ KCmdLineArgs::addCmdLineOptions( options );
+ KApplication app;
+ KCmdLineArgs* args = KCmdLineArgs::parsedArgs();
+
+ if( kapp->isRestored() )
+ RESTORE( KGVShell )
+ else {
+ KGVShell* shell = new KGVShell;
+ if( args->count() == 1 ) {
+ if( QString( args->arg(0) ) == "-" ) {
+ shell->openStdin();
+ } else {
+ shell->openURL( args->url(0) );
+ }
+ shell->setDisplayOptions( DisplayOptions::parse( args ) );
+ }
+ shell->show();
+ }
+ args->clear();
+ return app.exec();
+}
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/marklist.cpp b/kghostview/marklist.cpp
new file mode 100644
index 00000000..674630ed
--- /dev/null
+++ b/kghostview/marklist.cpp
@@ -0,0 +1,242 @@
+/**
+ * Copyright (C) 1997-2002 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 "marklist.moc"
+
+#include <cassert>
+
+#include <qimage.h>
+#include <qlayout.h>
+#include <qtooltip.h>
+#include <qlabel.h>
+#include <qwhatsthis.h>
+
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "kgv_miniwidget.h"
+
+MarkListItem::MarkListItem(QWidget *parent, const QString &text, const QString &tip, const QColor &color, KGVMiniWidget* miniW, int pageNum)
+ : QWidget( parent ),
+ _miniWidget( miniW ),
+ _pageNum( pageNum ),
+ _requested( false )
+{
+ //kdDebug( 4500 ) << "MarkListItem::MarkListItem( _ , " << text <<" , " << tip << " , " << color << ", _ ," << pageNum << " )" << endl;
+ QBoxLayout *l = new QVBoxLayout( this, 5, 0 );
+ _thumbnailW = new QWidget( this );
+ _checkBox = new QCheckBox( text, this );
+ l->addWidget( _thumbnailW, 1 );
+ l->addWidget( _checkBox, 0, Qt::AlignHCenter );
+ QWhatsThis::add( _checkBox, i18n( "Using this checkbox you can select pages for printing." ) );
+ setFixedHeight( 100 );
+ _backgroundColor = color;
+ setPaletteBackgroundColor( _backgroundColor );
+ QToolTip::add(this, tip);
+ // TODO: Put a little page number or other place-holder when there is no thumbnail to display.
+}
+
+bool MarkListItem::isChecked() const
+{
+ return _checkBox->isChecked();
+}
+
+void MarkListItem::toggle()
+{
+ _checkBox->toggle();
+}
+
+void MarkListItem::setChecked( bool checked )
+{
+ _checkBox->setChecked(checked);
+}
+
+void MarkListItem::setPixmap( QPixmap thumbnail )
+{
+ // The line below is needed to work around certain "features" of styles such as liquid
+ // see bug:61711 for more info (LPC, 20 Aug '03)
+ _thumbnailW->setBackgroundOrigin( QWidget::WidgetOrigin );
+ _thumbnailW->setPaletteBackgroundPixmap( thumbnail.convertToImage().smoothScale( _thumbnailW->size() ) );
+ _requested = false;
+}
+
+void MarkListItem::setSelected( bool selected )
+{
+ if (selected)
+ setPaletteBackgroundColor( QApplication::palette().active().highlight() );
+ else
+ setPaletteBackgroundColor( _backgroundColor );
+}
+
+void MarkListItem::resizeEvent( QResizeEvent * )
+{
+ if ( _thumbnailW->paletteBackgroundPixmap() )
+ _thumbnailW->setPaletteBackgroundPixmap( _thumbnailW->paletteBackgroundPixmap()->convertToImage().smoothScale( _thumbnailW->size() ) );
+}
+
+void MarkListItem::paintEvent( QPaintEvent* )
+{
+ /* TODO:
+ * We should cancel things which flipped into view and then flipped out.
+ *
+ * Now, if one scrolls through a 1000 page document to the end and then lingers on the
+ * last pages, these will take forever to appear in thumbnail form.
+ */
+ if ( _requested ) return;
+ if ( !_thumbnailW->paletteBackgroundPixmap() || _thumbnailW->paletteBackgroundPixmap()->isNull() ) {
+ _miniWidget->getThumbnailService()->delayedGetThumbnail( _pageNum, this, SLOT( setPixmap( QPixmap ) ) );
+ _requested = true;
+ }
+}
+
+
+/* MarkList */
+
+MarkList::MarkList( QWidget* parent, const char* name, KGVMiniWidget* mini)
+ : QTable( parent, name ),
+ _selected ( -1 ),
+_miniWidget( mini )
+{
+ setNumCols( 1 );
+ setLeftMargin( 0 ); // we don't want the vertical header
+ horizontalHeader()->setLabel( 0, i18n("Page") );
+
+ connect( this, SIGNAL( currentChanged( int, int ) ),
+ this, SIGNAL( selected( int ) ) );
+}
+
+QValueList<int> MarkList::markList() const
+{
+ QValueList<int> list;
+ MarkListItem *_item;
+ for(int i = 0; i < numRows(); i++)
+ {
+ _item = dynamic_cast<MarkListItem *>( cellWidget( i, 0 ) );
+ assert( _item );
+ if ( _item->isChecked() ) list << (i + 1);
+ }
+ return list;
+}
+
+void MarkList::insertItem( const QString& text, int index, const QString& tip)
+{
+ MarkListItem *_item;
+ _item = new MarkListItem( this, text, tip, viewport()->paletteBackgroundColor(), _miniWidget, index );
+ setNumRows( index + 1 );
+ setCellWidget( index, 0, _item );
+ setRowHeight( index, _item->height() );
+}
+
+void MarkList::select( int index )
+{
+ MarkListItem *_item;
+ setCurrentCell( index, 0 );
+ _item = dynamic_cast<MarkListItem *>( cellWidget( _selected, 0 ) );
+ if (_item) _item -> setSelected( false );
+ _selected = index;
+ _item = dynamic_cast<MarkListItem *>( cellWidget( _selected, 0 ) );
+ if (_item) _item -> setSelected( true );
+ clearFocus();
+}
+
+void MarkList::clear()
+{
+ for ( int i = 0; i != numRows() ; ++i ) {
+ clearCellWidget( i, 0 );
+ }
+ setNumRows( 0 );
+}
+
+void MarkList::markCurrent()
+{
+ MarkListItem *_item = dynamic_cast<MarkListItem *>( cellWidget( currentRow(), 0 ) );
+ assert( _item );
+ _item->toggle();
+}
+
+void MarkList::markAll()
+{
+ MarkListItem *_item;
+ for(int i = 0; i < numRows(); i++)
+ {
+ _item = dynamic_cast<MarkListItem *>( cellWidget( i, 0 ) );
+ assert( _item );
+ _item->setChecked( true );
+ }
+}
+
+void MarkList::markEven()
+{
+ MarkListItem *_item;
+ for(int i = 1; i < numRows(); i = i + 2)
+ {
+ _item = dynamic_cast<MarkListItem *>( cellWidget( i, 0 ) );
+ assert( _item );
+ _item->setChecked( true );
+ }
+}
+
+void MarkList::markOdd()
+{
+ MarkListItem *_item;
+ for(int i = 0; i < numRows(); i = i + 2)
+ {
+ _item = dynamic_cast<MarkListItem *>( cellWidget( i, 0 ) );
+ assert( _item );
+ _item->setChecked( true );
+ }
+}
+
+void MarkList::toggleMarks()
+{
+ MarkListItem *_item;
+ for(int i = 0; i < numRows(); i++)
+ {
+ _item = dynamic_cast<MarkListItem *>( cellWidget( i, 0 ) );
+ assert( _item );
+ _item->toggle();
+ }
+}
+
+void MarkList::removeMarks()
+{
+ MarkListItem *_item;
+ for( int i = 0; i < numRows(); i++ ) {
+ _item = dynamic_cast<MarkListItem *>( cellWidget( i, 0 ) );
+ assert( _item );
+ _item->setChecked( false );
+ }
+}
+
+void MarkList::viewportResizeEvent ( QResizeEvent * )
+{
+ MarkListItem *_item;
+ if( visibleWidth() != columnWidth( 0 ) )
+ {
+ setColumnWidth( 0, visibleWidth() );
+ for( int i = 0; i < numRows(); ++i )
+ {
+ _item = dynamic_cast<MarkListItem *>( cellWidget( i, 0 ) );
+ assert( _item );
+ _item->setFixedSize( visibleWidth(), _item->height() );
+ }
+ }
+}
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/marklist.h b/kghostview/marklist.h
new file mode 100644
index 00000000..18589af3
--- /dev/null
+++ b/kghostview/marklist.h
@@ -0,0 +1,88 @@
+/**
+ * Copyright (C) 1997-2002 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 MARKLIST_H
+#define MARKLIST_H
+
+#include <qcheckbox.h>
+#include <qtable.h>
+
+class KGVMiniWidget;
+
+class MarkListItem : public QWidget
+{
+ Q_OBJECT
+public:
+ MarkListItem( QWidget *parent, const QString &text, const QString &tip, const QColor &color, KGVMiniWidget*, int );
+
+ bool isChecked() const;
+
+public slots:
+ void toggle();
+ void setChecked( bool checked );
+ void setPixmap( QPixmap thumbnail );
+
+ void setSelected( bool selected );
+
+private:
+ void resizeEvent( QResizeEvent * );
+ void paintEvent( QPaintEvent* );
+private:
+ QWidget *_thumbnailW;
+ QCheckBox *_checkBox;
+ QColor _backgroundColor;
+ KGVMiniWidget* _miniWidget;
+ const int _pageNum;
+ bool _requested;
+};
+
+class MarkList: public QTable
+{
+ Q_OBJECT
+
+public:
+ MarkList( QWidget* parent = 0, const char* name = 0, KGVMiniWidget* = 0 );
+
+ QValueList<int> markList() const;
+ void insertItem( const QString& text, int index = -1,
+ const QString& tip = QString::null );
+
+public slots:
+ void select( int index );
+ void markCurrent();
+ void markAll();
+ void markEven();
+ void markOdd();
+ void toggleMarks();
+ void removeMarks();
+ void clear();
+
+protected:
+ virtual void viewportResizeEvent ( QResizeEvent * );
+
+signals:
+ void selected( int );
+
+private:
+ int _selected;
+ KGVMiniWidget* _miniWidget;
+};
+
+#endif
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/part_init.cpp b/kghostview/part_init.cpp
new file mode 100644
index 00000000..76036948
--- /dev/null
+++ b/kghostview/part_init.cpp
@@ -0,0 +1,22 @@
+// part_init.cpp
+// Copyright (C) 2004 Dominique Devriese <devriese@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 "kgvfactory.h"
+
+K_EXPORT_COMPONENT_FACTORY( libkghostviewpart, KGVFactory )
+
diff --git a/kghostview/ps.c b/kghostview/ps.c
new file mode 100644
index 00000000..1ff4effa
--- /dev/null
+++ b/kghostview/ps.c
@@ -0,0 +1,188 @@
+/*
+ * ps.c -- Postscript scanning and copying routines.
+ * Copyright (C) 1992 Timothy O. Theisen
+ *
+ * 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.
+ *
+ * Author: Tim Theisen Systems Programmer
+ * Internet: tim@cs.wisc.edu Department of Computer Sciences
+ * UUCP: uwvax!tim University of Wisconsin-Madison
+ * Phone: (608)262-0438 1210 West Dayton Street
+ * FAX: (608)262-9777 Madison, WI 53706
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ps.h"
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+#ifndef BUFSIZ
+#define BUFSIZ 1024
+#endif
+
+/* length calculates string length at compile time */
+/* can only be used with character constants */
+#define length(a) (sizeof(a)-1)
+#define iscomment(a, b) (strncmp(a, b, length(b)) == 0)
+#define DSCcomment(a) (a[0] == '%' && a[1] == '%')
+
+/*
+ * pscopy -- copy lines of Postscript from a section of one file
+ * to another file.
+ * Automatically switch to binary copying whenever
+ * %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
+ * comments are encountered.
+ */
+
+void
+pscopy(from, to, begin, end)
+ FILE *from;
+ FILE *to;
+ long begin; /* set negative to avoid initial seek */
+ long end;
+{
+ char line[PSLINELENGTH]; /* 255 characters + 1 newline + 1 NULL */
+ char text[PSLINELENGTH]; /* Temporary storage for text */
+ unsigned int num;
+ unsigned int i;
+ char buf[BUFSIZ];
+
+ if (begin >= 0) fseek(from, begin, SEEK_SET);
+ while (ftell(from) < end) {
+
+ fgets(line, sizeof line, from);
+ fputs(line, to);
+
+ if (!(DSCcomment(line) && iscomment(line+2, "Begin"))) {
+ /* Do nothing */
+ } else if (iscomment(line+7, "Data:")) {
+ int rc = 0;
+ text[0] = '\0';
+ rc = sscanf(line+length("%%BeginData:"), "%d %*s %256s", &num,text);
+ text[256] = '\0';
+ if (rc >= 1) {
+ if (strcmp(text, "Lines") == 0) {
+ for (i=0; i < num; i++) {
+ fgets(line, sizeof line, from);
+ fputs(line, to);
+ }
+ } else {
+ while (num > BUFSIZ) {
+ fread(buf, sizeof (char), BUFSIZ, from);
+ fwrite(buf, sizeof (char), BUFSIZ, to);
+ num -= BUFSIZ;
+ }
+ fread(buf, sizeof (char), num, from);
+ fwrite(buf, sizeof (char), num, to);
+ }
+ }
+ } else if (iscomment(line+7, "Binary:")) {
+ if(sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
+ while (num > BUFSIZ) {
+ fread(buf, sizeof (char), BUFSIZ, from);
+ fwrite(buf, sizeof (char), BUFSIZ, to);
+ num -= BUFSIZ;
+ }
+ fread(buf, sizeof (char), num, from);
+ fwrite(buf, sizeof (char), num, to);
+ }
+ }
+ }
+}
+
+/*
+ * pscopyuntil -- copy lines of Postscript from a section of one file
+ * to another file until a particular comment is reached.
+ * Automatically switch to binary copying whenever
+ * %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
+ * comments are encountered.
+ */
+
+char *
+pscopyuntil(from, to, begin, end, comment)
+ FILE *from;
+ FILE *to;
+ long begin; /* set negative to avoid initial seek */
+ long end;
+ const char *comment;
+{
+ char line[PSLINELENGTH]; /* 255 characters + 1 newline + 1 NULL */
+ char text[PSLINELENGTH]; /* Temporary storage for text */
+ unsigned int num;
+ unsigned int i;
+ int comment_length;
+ char buf[BUFSIZ];
+ char *cp;
+
+ comment_length = strlen(comment);
+ if (begin >= 0) fseek(from, begin, SEEK_SET);
+ while (ftell(from) < end) {
+
+ fgets(line, sizeof line, from);
+
+ /* iscomment cannot be used here,
+ * because comment_length is not known at compile time. */
+ if (strncmp(line, comment, comment_length) == 0) {
+ cp = (char *) malloc(strlen(line)+1);
+ if (cp == NULL) {
+ fprintf(stderr, "Fatal Error: Dynamic memory exhausted.\n");
+ exit(-1);
+ }
+ strcpy(cp, line);
+ return cp;
+ }
+ fputs(line, to);
+ if (!(DSCcomment(line) && iscomment(line+2, "Begin"))) {
+ /* Do nothing */
+ } else if (iscomment(line+7, "Data:")) {
+ int rc = 0;
+ text[0] = '\0';
+ rc = sscanf(line+length("%%BeginData:"), "%d %*s %256s", &num,text);
+ text[256] = '\0';
+ if (rc >= 1) {
+ if (strcmp(text, "Lines") == 0) {
+ for (i=0; i < num; i++) {
+ fgets(line, sizeof line, from);
+ fputs(line, to);
+ }
+ } else {
+ while (num > BUFSIZ) {
+ fread(buf, sizeof (char), BUFSIZ, from);
+ fwrite(buf, sizeof (char), BUFSIZ, to);
+ num -= BUFSIZ;
+ }
+ fread(buf, sizeof (char), num, from);
+ fwrite(buf, sizeof (char), num, to);
+ }
+ }
+ } else if (iscomment(line+7, "Binary:")) {
+ if(sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
+ while (num > BUFSIZ) {
+ fread(buf, sizeof (char), BUFSIZ, from);
+ fwrite(buf, sizeof (char), BUFSIZ, to);
+ num -= BUFSIZ;
+ }
+ fread(buf, sizeof (char), num, from);
+ fwrite(buf, sizeof (char), num, to);
+ }
+ }
+ }
+ return NULL;
+}
+
diff --git a/kghostview/ps.h b/kghostview/ps.h
new file mode 100644
index 00000000..3cb4ea9c
--- /dev/null
+++ b/kghostview/ps.h
@@ -0,0 +1,44 @@
+/*
+ * ps.h -- Include file for PostScript routines.
+ * Copyright (C) 1992 Timothy O. Theisen
+ *
+ * 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.
+ *
+ * Author: Tim Theisen Systems Programmer
+ * Internet: tim@cs.wisc.edu Department of Computer Sciences
+ * UUCP: uwvax!tim University of Wisconsin-Madison
+ * Phone: (608)262-0438 1210 West Dayton Street
+ * FAX: (608)262-9777 Madison, WI 53706
+ */
+
+#ifndef _PS_H
+#define _PS_H
+
+#define PSLINELENGTH 257 /* 255 characters + 1 newline + 1 NULL */
+
+ /* Copy a portion of the PostScript file */
+
+void pscopy(FILE *from, FILE *to, long begin, long end);
+
+ /* Copy a portion of the PostScript file upto a comment */
+
+char *pscopyuntil(FILE *from, FILE *to, long begin, long end,
+ const char *comment);
+
+#endif
+
+/*
+ * vim:sw=4:sts=4:ts=8:noet
+ */
diff --git a/kghostview/scrollbox.cpp b/kghostview/scrollbox.cpp
new file mode 100644
index 00000000..8be3ab61
--- /dev/null
+++ b/kghostview/scrollbox.cpp
@@ -0,0 +1,129 @@
+/**
+ * Copyright (C) 1997-2002 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 <qdrawutil.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+
+#include "scrollbox.h"
+
+ScrollBox::ScrollBox( QWidget* parent, const char* name )
+ : QFrame( parent, name )
+{
+ setFrameStyle( Panel | Sunken );
+}
+
+void ScrollBox::mousePressEvent( QMouseEvent* e )
+{
+ mouse = e->pos();
+ if( e->button() == RightButton )
+ emit button3Pressed();
+ if( e->button() == MidButton )
+ emit button2Pressed();
+}
+
+void ScrollBox::mouseMoveEvent( QMouseEvent* e )
+{
+ if( e->state() != LeftButton )
+ return;
+
+ int dx = ( e->pos().x() - mouse.x() ) * pagesize.width() / width();
+ int dy = ( e->pos().y() - mouse.y() ) * pagesize.height() / height();
+
+ // Notify the word what the view position has changed
+ // The word in turn will notify as that view position has changed
+ // Even if coordinates are out of range QScrollView handles
+ // this properly
+ emit valueChanged( QPoint( viewpos.x() + dx, viewpos.y() + dy ) );
+ emit valueChangedRelative( dx, dy );
+
+ mouse = e->pos();
+}
+
+void ScrollBox::resizeEvent( QResizeEvent * )
+{
+ if ( paletteBackgroundPixmap() )
+ setPaletteBackgroundPixmap( paletteBackgroundPixmap()->convertToImage().smoothScale( size() ) );
+}
+
+void ScrollBox::drawContents( QPainter* paint )
+{
+ if ( pagesize.isEmpty() )
+ return;
+
+
+ /* FIXME:
+ *
+ * The logic below is flawed because the page info given to us
+ * contains the borders used for page decoration, while we assume
+ * that it means only the actual displayed document.
+ *
+ */
+
+ QRect c( contentsRect() );
+
+ paint -> setPen( Qt::red );
+
+ int len = pagesize.width();
+ int x = c.x() + c.width() * viewpos.x() / len;
+ int w = c.width() * viewsize.width() / len ;
+ if ( w > c.width() ) w = c.width();
+
+ len = pagesize.height();
+ int y = c.y() + c.height() * viewpos.y() / len;
+ int h = c.height() * viewsize.height() / len;
+ if ( h > c.height() ) h = c.height();
+
+ paint->drawRect( x, y, w, h );
+}
+
+void ScrollBox::setPageSize( const QSize& s )
+{
+ pagesize = s;
+ setFixedHeight( s.height() * width() / s.width() );
+ repaint();
+}
+
+void ScrollBox::setViewSize( const QSize& s )
+{
+ viewsize = s;
+ repaint();
+}
+
+void ScrollBox::setViewPos( const QPoint& pos )
+{
+ viewpos = pos;
+ repaint();
+}
+
+void ScrollBox::setThumbnail( QPixmap img )
+{
+ // The line below is needed to work around certain "features" of styles such as liquid
+ // see bug:61711 for more info (LPC, 20 Aug '03)
+ setBackgroundOrigin( QWidget::WidgetOrigin );
+ setPaletteBackgroundPixmap( img.convertToImage().smoothScale( size() ) );
+}
+
+void ScrollBox::clear()
+{
+ unsetPalette();
+}
+
+#include "scrollbox.moc"
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/scrollbox.h b/kghostview/scrollbox.h
new file mode 100644
index 00000000..a815c655
--- /dev/null
+++ b/kghostview/scrollbox.h
@@ -0,0 +1,60 @@
+/**
+ * Copyright (C) 1997-2002 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 __SCROLLBOX_H__
+#define __SCROLLBOX_H__
+
+#include <qframe.h>
+#include <qimage.h>
+
+class ScrollBox: public QFrame
+{
+ Q_OBJECT
+
+public:
+ ScrollBox( QWidget* parent = 0, const char* name = 0 );
+
+public slots:
+ void setPageSize( const QSize& );
+ void setViewSize( const QSize& );
+ void setViewPos( const QPoint& );
+ void setViewPos( int x, int y ) { setViewPos( QPoint( x, y ) ); }
+ void setThumbnail( QPixmap img );
+ void clear();
+
+signals:
+ void valueChanged( const QPoint& );
+ void valueChangedRelative( int dx, int dy );
+ void button2Pressed();
+ void button3Pressed();
+
+protected:
+ void mousePressEvent( QMouseEvent *);
+ void mouseMoveEvent( QMouseEvent *);
+ void drawContents( QPainter *);
+ void resizeEvent( QResizeEvent * );
+
+private:
+ QPoint viewpos, mouse;
+ QSize pagesize;
+ QSize viewsize;
+};
+
+#endif
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/thumbnailservice.cpp b/kghostview/thumbnailservice.cpp
new file mode 100644
index 00000000..4d653cfa
--- /dev/null
+++ b/kghostview/thumbnailservice.cpp
@@ -0,0 +1,161 @@
+/**
+ * Copyright (C) 1997-2003 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 "thumbnailservice.h"
+
+#include "kgv_miniwidget.h"
+#include "kpswidget.h"
+#include "kgv_view.h"
+
+#include <kdebug.h>
+#include <qtimer.h>
+#include <algorithm>
+#include <cassert>
+#include <cstring>
+
+ThumbnailService::ThumbnailService( KGVMiniWidget* parent, const char* name ) :
+ QObject( parent, name ),
+ _mini( parent ),
+ timer_( new QTimer( this ) ),
+ _busy( false ),
+ _enabled( false )
+{
+ _thumbnailDrawer = new KPSWidget( parent->_part->widget(), "thumbnail-drawer" );
+ _thumbnailDrawer->readSettings();
+ connect( _thumbnailDrawer, SIGNAL( newPageImage( QPixmap ) ), SLOT( slotDone( QPixmap ) ) );
+ connect( timer_, SIGNAL( timeout() ), SLOT( processOne() ) );
+ _thumbnailDrawer->hide();
+}
+
+ThumbnailService::~ThumbnailService()
+{
+}
+
+bool ThumbnailService::Request::operator < ( ThumbnailService::Request b ) const
+{
+ if ( urgent != b.urgent ) return urgent;
+ if ( page != b.page ) return page < b.page;
+ // below is just so that == can be in terms of "<"
+ if ( receiver != b.receiver ) return std::less<QObject*>()( receiver, b.receiver );
+ if ( slot != b.slot ) return std::strcmp( slot, b.slot ) < 0;
+ return false;
+}
+
+void ThumbnailService::delayedGetThumbnail( const int page, QObject* rec, const char* slot, bool urgent )
+{
+ kdDebug( 4500 ) << "ThumbnailService::delayedGetThumbnail: request for page " << page << endl;
+ pending.insert( Request( page, rec, slot, urgent ) );
+ if ( !_busy ) {
+ _busy = true;
+ // The reason for the code below might not be obvious:
+ // It is much nicer to have the the thumbnails appear from top to bottom.
+ // However, when several are requested at once (or almost), then we cannot control the order
+ // unless we delay a bit the first one
+ if ( urgent ) processOne();
+ else timer_->start( 150, true );
+ }
+}
+
+void ThumbnailService::cancelRequests( const int page, QObject* rec, const char* slot )
+{
+ std::set<Request>::iterator first = pending.begin(), last = pending.end();
+ while ( first != last ) {
+ if ( ( page == -1 || page == first->page ) &&
+ ( !rec || rec == first->receiver ) &&
+ ( !slot || !strcmp( slot, first->slot ) ) ) {
+ std::set<Request>::iterator next = first;
+ ++next;
+ pending.erase( first );
+ first = next;
+ } else {
+ ++first;
+ }
+ }
+}
+
+void ThumbnailService::reset()
+{
+ kdDebug( 4500 ) << "ThumbnailService::reset()" << endl;
+ timer_->stop();
+ pending.clear();
+ assert( _thumbnailDrawer );
+ _thumbnailDrawer->stopInterpreter();
+ _busy = false;
+ _enabled = false;
+}
+
+void ThumbnailService::setEnabled( const bool e )
+{
+ kdDebug( 4500 ) << "ThumbnailService::setEnabled( " << ( e ? "true" : "false" ) << " )" << endl;
+ _enabled = e;
+ if ( _enabled && _busy ) processOne();
+}
+
+void ThumbnailService::slotDone( QPixmap pix )
+{
+ kdDebug( 4500 ) << "ThumbnailService::slotDone(): got page" << endl;
+ pix.detach();
+ emit relayPixmap( pix );
+ processOne();
+}
+
+
+void ThumbnailService::processOne()
+{
+ kdDebug( 4500 ) << "ThumbnailService::processOne()" << endl;
+ if ( !_enabled ) return;
+ if ( !_mini || !_mini->dsc() || !_mini->dsc()->isStructured() ) {
+ _busy = false;
+ pending.clear();
+ return;
+ }
+ assert( _thumbnailDrawer );
+ if ( pending.empty() ) {
+ _busy = false;
+ return;
+ }
+ _busy = true;
+ FILE* file = _mini->psFile();
+ Request req = *pending.begin();
+ kdDebug( 4500 ) << "ThumbnailService::processOne(): processing " << req.page << "(of " << pending.size() << " requests)" << endl;
+ disconnect( SIGNAL( relayPixmap( QPixmap ) ) );
+ while ( !pending.empty() && req.page == pending.begin()->page ) {
+ req = *pending.begin();
+ connect( this, SIGNAL( relayPixmap( QPixmap ) ), req.receiver, req.slot );
+ pending.erase( pending.begin() );
+ }
+ _thumbnailDrawer->setOrientation( _mini->orientation( req.page ) );
+ _thumbnailDrawer->setBoundingBox( _mini->boundingBox( req.page ) );
+ _thumbnailDrawer->setMagnification( 0.2 );
+ if ( !_thumbnailDrawer->isInterpreterRunning() ) {
+ _thumbnailDrawer->setFileName( _mini->_document->fileName(), true );
+ _thumbnailDrawer->startInterpreter();
+ _thumbnailDrawer->sendPS( file, _mini->dsc()->beginprolog(),
+ _mini->dsc()->endprolog() );
+ _thumbnailDrawer->sendPS( file, _mini->dsc()->beginsetup(),
+ _mini->dsc()->endsetup() );
+ }
+ else {
+ _thumbnailDrawer->nextPage();
+ }
+ _thumbnailDrawer->sendPS( file, _mini->dsc()->page()[ req.page ].begin,
+ _mini->dsc()->page()[ req.page ].end );
+}
+
+#include "thumbnailservice.moc"
+
diff --git a/kghostview/thumbnailservice.h b/kghostview/thumbnailservice.h
new file mode 100644
index 00000000..d1981242
--- /dev/null
+++ b/kghostview/thumbnailservice.h
@@ -0,0 +1,92 @@
+#ifndef THUMBNAILSERVICE_H
+#define THUMBNAILSERVICE_H
+/**
+ * Copyright (C) 1997-2003 the KGhostView authors. See file AUTHORS.
+ *
+ * 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 <set>
+#include <qobject.h>
+#include <qpixmap.h>
+#include <qguardedptr.h>
+#include <stdio.h>
+
+class KPSWidget;
+class KGVMiniWidget;
+class QTimer;
+
+class ThumbnailService : public QObject {
+ Q_OBJECT
+ public:
+ ThumbnailService( KGVMiniWidget* parent, const char* name = 0 );
+ ~ThumbnailService();
+
+ public slots:
+ void delayedGetThumbnail( int page, QObject* receiver, const char* slot, bool urgent = false );
+ /**
+ * Cancels the request matching the signature below.
+ *
+ * @param page the page of the request. Use "-1" for wildcard
+ * @param receiver the receiver. Use null for wildcard
+ * @param slot Use null for wildcard
+ */
+ void cancelRequests( int page, QObject* receiver, const char* slot);
+
+ void reset();
+ /**
+ * This "suspends" the service.
+ * Unlike @ref reset(), if you call setEnabled( false ),
+ * old requests will be kept and will be serviced when
+ * you call setEnabled( true ) later.
+ */
+ void setEnabled( bool );
+
+ signals:
+ /**
+ * Don't connect to this directly
+ */
+ void relayPixmap( QPixmap );
+
+ private slots:
+ void slotDone( QPixmap );
+ void processOne();
+
+ private:
+
+ struct Request {
+ Request( int p, QObject* r, const char* s ) :
+ page( p ), receiver( r ), slot( s ), urgent( false ) { }
+ Request( int p, QObject* r, const char* s, bool u ) :
+ page( p ), receiver( r ), slot( s ), urgent( u ) { }
+
+ int page;
+ QObject* receiver;
+ const char* slot;
+ bool urgent;
+ bool operator < ( Request ) const;
+ };
+ static bool pageCmp( Request, Request );
+ std::set<Request> pending;
+ QGuardedPtr<KPSWidget> _thumbnailDrawer;
+ KGVMiniWidget* _mini;
+ QTimer* timer_;
+ bool _busy;
+ bool _enabled;
+};
+
+// vim:sw=4:sts=4:ts=8:sta:tw=78:noet
+#endif // THUMBNAILSERVICE_H
+
diff --git a/kghostview/update-to-xt-names.pl b/kghostview/update-to-xt-names.pl
new file mode 100644
index 00000000..1aa07403
--- /dev/null
+++ b/kghostview/update-to-xt-names.pl
@@ -0,0 +1,36 @@
+#!/usr/bin/perl
+
+my $group = '';
+my $key = '';
+my $value = '';
+
+while (<>) {
+ if (/^\s.*$/) { next }
+ if (/^\s*#.*$/) { next }
+ if (/\[(.*)\]/) {
+ $group = $1;
+ } elsif (/^(.*)=(.*)$/) {
+ $key = $1;
+ $value = $2;
+ } else { next }
+
+ if (!$group || !$key) { next }
+
+ if ( $group eq 'General' ) {
+ if ( $key eq 'Palette' ) {
+ if ($value eq 'color') {
+ print "Palette=Color\n";
+ } elsif ($value eq 'monochrome') {
+ print "Palette=Monochrome\n";
+ } elsif ($value eq 'grayscale') {
+ print "Palette=Grayscale\n";
+ } else {
+ print "Palette=Color\n";
+ }
+ }
+ if ( $key eq 'Interpreter' ) {
+ print "# DELETE [General]Interpreter\n";
+ }
+ }
+}
+
diff --git a/kghostview/version.h b/kghostview/version.h
new file mode 100644
index 00000000..81cf5df2
--- /dev/null
+++ b/kghostview/version.h
@@ -0,0 +1,4 @@
+#define KGHOSTVIEW_VERSION "0.20"
+
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/viewcontrol.cpp b/kghostview/viewcontrol.cpp
new file mode 100644
index 00000000..cc66d598
--- /dev/null
+++ b/kghostview/viewcontrol.cpp
@@ -0,0 +1,194 @@
+/****************************************************************************
+**
+** A dialog for the selection of the view of a document.
+**
+** Copyright (C) 1997 by Mark Donohoe.
+** Based on original work by Tim Theisen.
+**
+** This code is freely distributable under the GNU Public License.
+**
+*****************************************************************************/
+
+#include <qcombobox.h>
+#include <qframe.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qlayout.h>
+
+
+#include "viewcontrol.h"
+#include "viewcontrol.moc"
+
+#include <klocale.h>
+#include <kapplication.h>
+#include <kbuttonbox.h>
+#include <kseparator.h>
+
+ViewControl::ViewControl( QWidget *parent, const char *name )
+ : QDialog( parent, name )
+{
+ setFocusPolicy(QWidget::StrongFocus);
+
+ QBoxLayout *topLayout = new QVBoxLayout( this, 10 );
+
+ QGroupBox* vcGroupBox;
+ vcGroupBox = new QGroupBox( this );
+ vcGroupBox->setFrameStyle( QFrame::NoFrame );
+ //vcGroupBox->setTitle( i18n("Force Changes To") );
+ //vcGroupBox->setAlignment( 1 );
+
+ topLayout->addWidget( vcGroupBox, 10 );
+
+ QGridLayout *grid = new QGridLayout( vcGroupBox, 3, 2, 10 );
+
+ grid->setRowStretch(0,0);
+ grid->setRowStretch(1,10);
+
+
+ grid->setColStretch(0,0);
+ grid->setColStretch(1,10);
+
+
+ magComboBox = new QComboBox( FALSE, vcGroupBox );
+ magComboBox->setFixedHeight( magComboBox->sizeHint().height() );
+
+
+ //magComboBox->hide();
+
+ connect ( magComboBox, SIGNAL (activated (int)),
+ this, SLOT (slotMagSelection (int)) );
+ grid->addWidget( magComboBox, 0, 1 );
+
+
+
+ mediaComboBox = new QComboBox( FALSE, vcGroupBox );
+ mediaComboBox->setFixedHeight( magComboBox->sizeHint().height() );
+
+ connect ( mediaComboBox, SIGNAL (activated (int)),
+ this, SLOT (slotMediaSelection (int)) );
+
+ grid->addWidget( mediaComboBox, 1, 1 );
+
+ orientComboBox = new QComboBox( FALSE, vcGroupBox );
+ orientComboBox->insertItem(i18n("Portrait"));
+ orientComboBox->insertItem(i18n("Landscape"));
+ orientComboBox->insertItem(i18n("Seascape"));
+ orientComboBox->insertItem(i18n("Upside Down"));
+ orientComboBox->setFixedHeight( magComboBox->sizeHint().height() );
+
+ connect ( orientComboBox, SIGNAL (activated (int)),
+ this, SLOT (slotOrientSelection (int)) );
+ grid->addWidget( orientComboBox, 2, 1 );
+
+ int labelWidth = 0;
+
+ QLabel* vcLabel;
+ vcLabel = new QLabel( magComboBox, i18n("&Magnification"), vcGroupBox );
+ vcLabel->setAlignment( AlignRight | AlignVCenter | ShowPrefix );
+ if ( vcLabel->sizeHint().width() > labelWidth )
+ labelWidth = vcLabel->sizeHint().width();
+ vcLabel->setMinimumWidth( labelWidth );
+
+ vcLabel->hide();
+
+ grid->addWidget( vcLabel, 0, 0 );
+
+
+ vcLabel = new QLabel( mediaComboBox, i18n("M&edia"), vcGroupBox );
+ vcLabel->setAlignment( AlignRight | AlignVCenter | ShowPrefix );
+ if ( vcLabel->sizeHint().width() > labelWidth )
+ labelWidth = vcLabel->sizeHint().width();
+ vcLabel->setMinimumWidth( labelWidth );
+
+ grid->addWidget( vcLabel, 1, 0 );
+
+ vcLabel = new QLabel( orientComboBox, i18n("&Orientation"), vcGroupBox );
+ vcLabel->setAlignment( AlignRight | AlignVCenter | ShowPrefix );
+ if ( vcLabel->sizeHint().width() > labelWidth )
+ labelWidth = vcLabel->sizeHint().width();
+ vcLabel->setMinimumWidth( labelWidth );
+
+ grid->addWidget( vcLabel, 2, 0 );
+
+ vcGroupBox->setMinimumHeight( 2*orientComboBox->sizeHint().height()+20 );
+ vcGroupBox->setMinimumWidth(
+ 40 + labelWidth + orientComboBox->sizeHint().width() );
+
+ KSeparator* sep = new KSeparator( KSeparator::HLine, this);
+ topLayout->addWidget( sep );
+
+ // CREATE BUTTONS
+
+ KButtonBox *bbox = new KButtonBox( this );
+ bbox->addStretch( 10 );
+
+ apply = bbox->addButton( KStdGuiItem::apply() );
+ connect( apply, SIGNAL(clicked()), SLOT(slotApplyClicked()) );
+
+ QPushButton *closebtn = bbox->addButton( KStdGuiItem::close() );
+ connect( closebtn, SIGNAL(clicked()), SLOT(reject()) );
+
+
+ bbox->layout();
+ topLayout->addWidget( bbox );
+
+ topLayout->activate();
+
+ prevmag = prevmedia = prevorient = 0;
+ applyEnable (false);
+}
+
+void
+ViewControl::updateMag (int mag)
+{
+ magComboBox->setCurrentItem (mag);
+ prevmag = mag;
+}
+
+
+void
+ViewControl::applyEnable (bool enable)
+{
+ apply->setEnabled (enable);
+}
+
+void
+ViewControl::slotApplyClicked()
+{
+ emit applyChanges();
+ applyEnable (false);
+}
+
+void
+ViewControl::slotMagSelection (int i)
+{
+ if (i != prevmag)
+ {
+ applyEnable (true);
+ prevmag = i;
+ }
+}
+
+void
+ViewControl::slotMediaSelection (int i)
+{
+ if (i != prevmedia)
+ {
+ applyEnable (true);
+ prevmedia = i;
+ }
+}
+
+void
+ViewControl::slotOrientSelection (int i)
+{
+ if (i != prevorient)
+ {
+ applyEnable (true);
+ prevorient = i;
+ }
+}
+
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kghostview/viewcontrol.h b/kghostview/viewcontrol.h
new file mode 100644
index 00000000..3e8bcd70
--- /dev/null
+++ b/kghostview/viewcontrol.h
@@ -0,0 +1,44 @@
+#ifndef VIEWCONTROL_H
+#define VIEWCONTROL_H
+
+#include <qdialog.h>
+class QComboBox;
+class QPushButton;
+
+
+class ViewControl : public QDialog
+{
+ Q_OBJECT
+public:
+ ViewControl( QWidget *parent, const char *name );
+ QComboBox* magComboBox;
+ QComboBox* mediaComboBox;
+ QComboBox* orientComboBox;
+ QPushButton *apply;
+
+ /**
+ * Update the mag combo box.
+ **/
+ void updateMag (int mag);
+
+ /**
+ * Enable/disable the apply button.
+ **/
+ void applyEnable (bool enable);
+
+protected:
+ int prevmag, prevmedia, prevorient;
+
+public slots:
+ void slotApplyClicked();
+ void slotMagSelection (int i);
+ void slotMediaSelection (int i);
+ void slotOrientSelection (int i);
+
+signals:
+ void applyChanges();
+};
+
+#endif
+
+// vim:sw=4:sts=4:ts=8:noet
diff --git a/kiconedit/AUTHORS b/kiconedit/AUTHORS
new file mode 100644
index 00000000..dd2047ae
--- /dev/null
+++ b/kiconedit/AUTHORS
@@ -0,0 +1,10 @@
+Copyright 1998 by Thomas Tanghus <tanghus@kde.org>
+Copyright 2000 by John Califf <jcaliff@compuzone.net>
+
+Original Author:
+ Thomas Tanghus
+
+Current Maintainers:
+ John Califf <jcaliff@compuzone.net>
+ Laurent Montel <lmontel@mandrakesoft.com>
+
diff --git a/kiconedit/Makefile.am b/kiconedit/Makefile.am
new file mode 100644
index 00000000..c2536935
--- /dev/null
+++ b/kiconedit/Makefile.am
@@ -0,0 +1,26 @@
+INCLUDES = $(all_includes)
+SUBDIRS = pics
+
+bin_PROGRAMS = kiconedit
+
+kiconedit_SOURCES = utils.cpp main.cpp kiconedit.cpp kicongrid.cpp \
+ kiconcolors.cpp kcolorgrid.cpp palettetoolbar.cpp\
+ kicon.cpp kresize.cpp knew.cpp properties.cpp \
+ kiconeditslots.cpp kiconconfig.cpp
+
+kiconedit_METASOURCES = AUTO
+
+# the library search path.
+kiconedit_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+kiconedit_LDADD = $(LIB_KFILE) -lkdeprint
+
+DISTCLEANFILES = *~ .deps/* .libs/*
+
+rcdir = $(kde_datadir)/kiconedit
+rc_DATA = kiconeditui.rc
+
+xdg_apps_DATA = kiconedit.desktop
+
+messages: rc.cpp
+ $(XGETTEXT) rc.cpp $(kiconedit_SOURCES) -o $(podir)/kiconedit.pot
+
diff --git a/kiconedit/NEWS b/kiconedit/NEWS
new file mode 100644
index 00000000..ba7ef218
--- /dev/null
+++ b/kiconedit/NEWS
@@ -0,0 +1,68 @@
+KDE Icon Editor
+_______________
+
+------------------------------------------------------------------------------
+ News and fixes in version 0.4.0:
+------------------------------------------------------------------------------
+ - Enabled loading other image types than XPM.
+ - Repainting large pictures is very much faster now.
+ - Added drop site indication when using XDND.
+ - Added QWhatsThis help (this is great!).
+ - Started playing with XDND. The toolbar now has a drag source and the grid
+ supports both XDND and KDND.
+ - Added rulers (can be toggled from the configuration dialog).
+ - Circular selection.
+ - Configuration dialog:
+ - Shortcut keys.
+ - Appearance.
+ - Templates.
+ - Miscellaneous (paste mode, show rulers etc.).
+
+------------------------------------------------------------------------------
+ News and fixes in version 0.3.2:
+------------------------------------------------------------------------------
+ - German translations. (thanks to Gregor Zumstein <zumste98@cui.unige.ch>)
+ - Solaris didn't like TRANSPARENT definition. (thanks to Alastair Burt <burt@dfki.de>)
+ - Crashed on empty string in strlen. (thanks to Alastair Burt <burt@dfki.de>)
+ - Russian translations (thanks to Andy Pershin <apa@penza.com.ru>)
+
+------------------------------------------------------------------------------
+ News and fixes in version 0.3.1:
+------------------------------------------------------------------------------
+ - Icon templates installed in the wrong directory.
+ - Templates didn't load.
+
+------------------------------------------------------------------------------
+ News and fixes in version 0.3:
+------------------------------------------------------------------------------
+ - Complete rewrite of the drawing grid. Should now be faster and more flexible.
+ - New class KIcon for file manipulation.
+ - The "Line" tool can now draw 45 dgr. angles.
+ - Smooth resizing of icons if linked with QT >= 1.40.
+ - Improved loading/saving images with transparent pixels.
+ - Loading and saving should now work on non-local files.
+
+------------------------------------------------------------------------------
+ News and fixes in version 0.2:
+------------------------------------------------------------------------------
+ - Saves restore file when closed by session management or by crash.
+ - Fixed multi instance handling.
+ - Added toolbar button for creating new instances.
+ - Added danish translation.
+ - Added statusbar field for messages.
+ - Saves window size.
+ - Couldn't toggle grid from the menu.
+ - Added "Toggle toolbar", "Toggle drawing tools" and "Toggle statusbar" to the
+ "View" menu. This as well as the *Bar positions is saved between sessions.
+ - Grid state and zoom factor saved between sessions.
+ - The clipboard is checked with short intervals to check if there's a pixmap.
+ - The cursor hotspots are now correct.
+ - Cursor position is shown in the statusbar.
+ - Removed a lot of memory leaks and made the general memory footprint some smaller.
+ - New tools: "Find pixel", "Flood Fill", "Filled Circle" and "Filled Ellipse".
+ - Clipboard now supports selection of regions and inserting into existing image.
+ - Speeded up loading of pixmaps by some thousand percents ;-)
+ - Preview has scrollbars if it doesn't fit.
+
+
+
diff --git a/kiconedit/kcolorgrid.cpp b/kiconedit/kcolorgrid.cpp
new file mode 100644
index 00000000..a3793cb2
--- /dev/null
+++ b/kiconedit/kcolorgrid.cpp
@@ -0,0 +1,335 @@
+/*
+ kiconedit - a small graphics drawing program for creating KDE icons
+ Copyright (C) 1998 Thomas Tanghus (tanghus@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 Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qpainter.h>
+
+#include <kdebug.h>
+
+#include "kcolorgrid.h"
+
+void KColorArray::remove(int idx)
+{
+ int oldsize = size();
+ if(idx >= (int)size())
+ {
+ kdWarning() << "KColorArray::remove: Index " << idx << " out of range" << endl;
+ return;
+ }
+ KColorArray tmp(*this);
+ tmp.detach();
+ resize(size()-1);
+ for(int i = idx; i < oldsize-1; i++)
+ at(i) = tmp[i+1];
+ //kdDebug(4640) << "KColorArray::remove() " << at(idx) << "\t-\tsize: " << size() << endl;
+}
+
+void KColorArray::append(uint c)
+{
+ resize(size()+1);
+ at(size()-1) = c;
+ //kdDebug(4640) << "KColorArray::append() " << c << "\t-\tsize: " << size() << endl;
+}
+
+uint KColorArray::closestMatch(uint color)
+{
+ //kdDebug(4640) << "KColorArray: " << c << endl;
+ uint c = color & ~OPAQUE_MASK, d = 0xffffff, t;
+ //kdDebug(4640) << "KColorArray: " << c << endl;
+ //kdDebug(4640) << "KColorArray: " << c|OPAQUE_MASK << endl;
+ uint cb = c;
+ for(uint i = 0; i < size(); i++)
+ {
+ if (at(i) > cb)
+ t = at(i) - cb;
+ else
+ t = cb - at(i);
+ if( t < d )
+ {
+ d = t;
+ c = at(i);
+ }
+ }
+ return c|OPAQUE_MASK;
+}
+
+KColorGrid::KColorGrid(QWidget *parent, const char *name, int space)
+ : QWidget(parent, name, Qt::WResizeNoErase|Qt::WRepaintNoErase)
+{
+ //kdDebug(4640) << "KColorGrid - constructor" << endl;
+ s = space;
+ rows = cols = totalwidth = totalheight = 0;
+ setCellSize(10);
+ setGridState(Plain);
+ setGrid(true);
+ numcolors.resize(0);
+ gridcolors.resize(0);
+
+ //kdDebug(4640) << "KColorGrid - constructor - done" << endl;
+}
+/*
+void KColorGrid::show()
+{
+ //updateScrollBars();
+ QWidget::show();
+}
+*/
+void KColorGrid::paintEvent(QPaintEvent *e)
+{
+ //kdDebug(4640) << "KColorGrid::paintEvent" << endl;
+
+ //updateScrollBars();
+ //QWidget::paintEvent(e);
+
+ const QRect urect = e->rect();
+
+ //kdDebug(4640) << "Update rect = ( " << //urect.left() << ", " << urect.top() << ", " << urect.width() << ", " << urect.height() << " )" << endl;
+
+
+ int firstcol = getX(urect.x())-1;
+ int firstrow = getY(urect.y())-1;
+ int lastcol = getX(urect.right())+1;
+ int lastrow = getY(urect.bottom())+1;
+
+ QWMatrix matrix;
+ QPixmap pm(urect.width(),urect.height());
+ pm.fill(paletteBackgroundColor());
+ QPainter p;
+ p.begin( &pm );
+
+ firstrow = (firstrow < 0) ? 0 : firstrow;
+ firstcol = (firstcol < 0) ? 0 : firstcol;
+ lastrow = (lastrow >= rows) ? rows : lastrow;
+ lastcol = (lastcol >= cols) ? cols : lastcol;
+ //kdDebug(4640) << urect.x() << " x " << urect.y() << " - row: " << urect.width() << " x " << urect.height() << endl;
+ //kdDebug(4640) << "col: " << firstcol << " -> " << lastcol << " - row: " << firstrow << " -> " << lastrow << endl;
+
+/*
+ if(this->isA("KDrawGrid"))
+ kdDebug(4640) << "KDrawGrid\n firstcol: " << firstcol << "\n lastcol: " << lastcol << "\n firstrow: " << firstrow << "\n lastrow: " << lastrow << endl;
+*/
+ for(int i = firstrow; i < lastrow; i++)
+ {
+ //if(this->isA("KDrawGrid"))
+ // kdDebug(4640) << "Updating row " << i << endl;
+ for(int j = firstcol; j < lastcol; j++)
+ {
+ matrix.translate( (j*cellsize)-urect.x(), (i*cellsize)-urect.y() );
+ p.setWorldMatrix( matrix );
+ //p.setClipRect(j*cellsize, i*cellsize, cellsize, cellsize);
+ paintCell(&p, i, j);
+ //p.setClipping(FALSE);
+ matrix.reset();
+ p.setWorldMatrix( matrix );
+ }
+ //kapp->processEvents();
+ }
+
+ matrix.translate(-urect.x(),-urect.y());
+ p.setWorldMatrix( matrix );
+ paintForeground(&p,e);
+
+ p.end();
+
+ bitBlt(this,urect.topLeft(),&pm,QRect(0,0,pm.width(),pm.height()));
+
+}
+
+void KColorGrid::paintForeground(QPainter* , QPaintEvent* )
+{
+}
+
+/*
+void KColorGrid::resizeEvent(QResizeEvent *)
+{
+ //kdDebug(4640) << "resize: width: " << width() << " - total: " << totalwidth << endl;
+ //kdDebug(4640) << "resize: height: " << height() << " - total: " << totalheight << endl;
+}
+*/
+
+QSize KColorGrid::sizeHint() const
+{
+ return QSize(totalwidth, totalheight);
+}
+
+int KColorGrid::getY( int y )
+{
+ if(y > (totalheight-1))
+ y = totalheight;
+ if(cellsize == 1)
+ return y;
+ return (y/cellsize);
+}
+
+int KColorGrid::getX( int x )
+{
+ if( x > totalwidth-1)
+ x = totalwidth;
+ if(cellsize == 1)
+ return x;
+ return (x/cellsize);
+}
+
+const QRect KColorGrid::viewRect()
+{
+ //kdDebug(4640) << "viewRect" << endl;
+ const QRect r(0, 0, width(), height());
+ //kdDebug(4640) << "viewRect - " << x << " x " << y << " - " << w << " x " << h << endl;
+ return r;
+}
+
+void KColorGrid::setNumRows(int n)
+{
+ //kdDebug(4640) << "setNumRows" << endl;
+ if(n < 0 || n == rows)
+ return;
+
+ rows = n;
+
+ gridcolors.resize(n*numCols());
+ //QTableView::setNumRows(n);
+ totalheight = (n * cellsize) + 1;
+ resize(totalwidth, totalheight);
+ //kdDebug(4640) << "setNumRows() - gridcolors: " << gridcolors.size() << " size: " << numCols()*numRows() << endl;
+}
+
+void KColorGrid::setNumCols(int n)
+{
+ //kdDebug(4640) << "setNumCols" << endl;
+ if(n < 0)
+ return;
+ int on = numCols();
+ KColorArray gc(gridcolors);
+ gc.detach();
+ //kdDebug(4640) << "gc size: " << gc.size() << " numrows: " << numRows() << endl;
+ gridcolors.resize(n*numRows());
+ cols = n;
+
+ totalwidth = (n * cellsize) + 1;
+ resize(totalwidth, totalheight);
+ //kdDebug(4640) << "numRows: " << numRows() << endl;
+ //kdDebug(4640) << "gridcolor: " << gridcolors.size() << " grid: " << numRows()*numCols() << endl;
+ if(numRows() == 0)
+ return;
+
+ for(int i = 0; i < numRows(); i++)
+ {
+ for(int j = 0; j < n; j++)
+ {
+ //kdDebug(4640) << "row " << i << " , col " << j << endl;
+ if(j < on ) //If there's something to read here -- i.e. we're within the original grid
+ {
+ //kdDebug(4640) << (i*numCols())+j << " " << (i*on)+j << endl;
+ gridcolors.at((i*numCols())+j) = gc.at((i*on)+j);
+ }
+ else //Initialize to something..
+ {
+ if (gc.size()) //Have some pixels originally..
+ gridcolors.at((i*numCols())+j) = gc.at(0);
+ else
+ gridcolors.at((i*numCols())+j) = 0; //Picks something #### Update numcolors?
+ }
+ }
+ }
+
+ //kdDebug(4640) << "setNumCols() - gridcolors: " << gridcolors.size() << " size: " << numCols()*numRows() << endl;
+}
+
+void KColorGrid::fill( uint color)
+{
+ gridcolors.fill(color);
+ numcolors.resize(1);
+ numcolors.at(0) = color;
+ emit colorschanged(numcolors.size(), numcolors.data());
+}
+
+void KColorGrid::setColor( int colNum, uint col, bool update )
+{
+ //kdDebug(4640) << "KColorGrid::setColor" << endl;
+ uint oldcolor = gridcolors[colNum];
+ gridcolors[colNum] = col;
+
+ if(!update)
+ return;
+
+ //kdDebug(4640) << "KColorGrid::setColor - before adding" << endl;
+ if(!numcolors.contains(col))
+ {
+ //kdDebug(4640) << "KColorGrid::setColor() - adding " << // col << " - " << qRed(col) << " " << qGreen(col) << " " << qBlue(col) << endl;
+ numcolors.append(col);
+ //kdDebug(4640) << "KColorGrid::setColor() - adding done " << numcolors.size()-1 << endl;
+ //numcolors++;
+ emit addingcolor(col);
+ }
+
+ //kdDebug(4640) << "KColorGrid::setColor - before removing" << endl;
+ if(!gridcolors.contains(oldcolor))
+ {
+ int idx = numcolors.find(oldcolor);
+ if(idx != -1)
+ {
+ //kdDebug(4640) << "KColorGrid::setColor() - removing " << // oldcolor << " - " << qRed(oldcolor) << " " << qGreen(oldcolor) << " " << qBlue(oldcolor) << endl;
+ numcolors.remove(idx);
+ //kdDebug(4640) << "KColorGrid::setColor() - removing done" << endl;
+ emit colorschanged(numcolors.size(), numcolors.data());
+ }
+ //numcolors--;
+ }
+
+ //kdDebug(4640) << "KColorGrid::setColor - before updateCell" << endl;
+ repaint((colNum%numCols())*cellsize,(colNum/numCols())*cellsize, cellsize, cellsize);
+ //updateCell( colNum/numCols(), colNum%numCols(), false );
+ //kdDebug(4640) << "KColorGrid::setColor - after updateCell" << endl;
+}
+
+void KColorGrid::updateCell( int row, int col, bool )
+{
+ //kdDebug(4640) << "updateCell - before repaint" << endl;
+ QWMatrix matrix;
+ QPainter p;
+ p.begin( this );
+ matrix.translate( (col*cellsize), (row*cellsize) );
+ p.setWorldMatrix( matrix );
+ paintCell(&p, row, col);
+ p.end();
+
+}
+
+void KColorGrid::updateColors()
+{
+ numcolors.resize(0);
+ for(int i = 0; i < (int)gridcolors.size(); i++)
+ {
+ uint col = gridcolors.at(i);
+ if(!numcolors.contains(col))
+ numcolors.append(col);
+ }
+ emit colorschanged(numcolors.size(), numcolors.data());
+}
+
+void KColorGrid::setCellSize( int s )
+{
+ cellsize = s;
+ totalwidth = (numCols() * s) + 1;
+ totalheight = (numRows() * s) + 1;
+ resize(totalwidth, totalheight);
+ if ( isVisible() )
+ repaint(viewRect(), false);
+}
+#include "kcolorgrid.moc"
diff --git a/kiconedit/kcolorgrid.h b/kiconedit/kcolorgrid.h
new file mode 100644
index 00000000..2bb7c856
--- /dev/null
+++ b/kiconedit/kcolorgrid.h
@@ -0,0 +1,104 @@
+/*
+ kiconedit - a small graphics drawing program for creating KDE icons
+ Copyright (C) 1998 Thomas Tanghus (tanghus@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 Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __KCOLORGRID_H__
+#define __KCOLORGRID_H__
+
+#include <qwidget.h>
+#include <qsize.h>
+#include <qrect.h>
+
+#include "utils.h"
+
+#define KArrayUint QMemArray<uint>
+
+class KColorArray : public KArrayUint
+{
+public:
+ void remove(int idx);
+ void append(uint);
+ uint closestMatch(uint);
+};
+
+class KColorGrid : public QWidget
+{
+private:
+ Q_OBJECT
+public:
+ KColorGrid( QWidget * parent = 0, const char *name = 0, int spacing = 0);
+ virtual ~KColorGrid() {};
+
+ enum GridState { Plain, Shaded };
+
+ void setSpacing(int space) { s = space; update(); }
+ void setGridState(GridState state) { gridstate = state;}
+ GridState gridState() { return gridstate; }
+ void setGrid(bool state) { hasgrid = state; }
+ int spacing() { return s; }
+ bool hasGrid() { return hasgrid; }
+ uint numColors() { return numcolors.size(); }
+ uint colors( uint *c ) { c = numcolors.data(); return numcolors.size(); }
+ bool contains(uint c) { return numcolors.contains(c); }
+ uint colorAt(int idx) { return gridcolors.at(idx); }
+ uint *data() {return numcolors.data(); }
+ void fill(uint color);
+ int numCols() { return cols; }
+ int numRows() { return rows; }
+
+ virtual void setCellSize( int s );
+ virtual int cellSize() { return cellsize; }
+ virtual QSize sizeHint() const;
+
+ void setSize(const QSize s) { setNumRows(s.height()); setNumCols(s.width()); }
+
+public slots:
+ //virtual void show();
+
+signals:
+ void addingcolor(uint);
+ void colorschanged(uint, uint*);
+
+protected:
+ void updateCell(int row, int col, bool f);
+ virtual void paintForeground( QPainter* p, QPaintEvent* e);
+ virtual void paintCell( QPainter *p, int row, int col) = 0;
+ virtual void paintEvent(QPaintEvent *);
+ //virtual void resizeEvent(QResizeEvent *);
+ void setColor(int colNum, uint, bool update = true );
+ void updateColors();
+ virtual void setNumRows(int);
+ virtual void setNumCols(int);
+ virtual int totalWidth() { return totalwidth; }
+ virtual int totalHeight() { return totalheight; }
+ int findRow(int y) { return getY(y); }
+ int getY(int y);
+ int findCol(int x) { return getX(x); }
+ int getX(int x);
+ const QRect viewRect();
+
+//private:
+ int s, cellsize, totalwidth, totalheight;
+ int rows, cols, ypos, xpos;
+ GridState gridstate;
+ bool hasgrid;
+ KColorArray gridcolors, numcolors;
+};
+
+#endif //__KCOLORGRID_H__
diff --git a/kiconedit/kicon.cpp b/kiconedit/kicon.cpp
new file mode 100644
index 00000000..92f1bc0b
--- /dev/null
+++ b/kiconedit/kicon.cpp
@@ -0,0 +1,279 @@
+/*
+ KDE Icon Editor - a small graphics drawing program for the KDE
+ Copyright (C) 1998 Thomas Tanghus (tanghus@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 Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <stdlib.h>
+
+#include <qimage.h>
+
+#include <kmessagebox.h>
+#include <kfiledialog.h>
+#include <kio/netaccess.h>
+#include <kimageio.h>
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "kicon.h"
+#include "utils.h"
+
+KIconEditIcon::KIconEditIcon(QObject *parent, const QImage *img, KURL url)
+ : QObject(parent)
+{
+ f = 0;
+ _lastdir = "/";
+ //checkUnNamedBackup(img);
+
+ if(!url.isEmpty())
+ {
+ open(img, url);
+ }
+}
+
+
+KIconEditIcon::~KIconEditIcon()
+{
+}
+
+
+bool KIconEditIcon::open(const QImage *image, KURL url)
+{
+ QImage *img = (QImage*)image;
+
+ if(url.isEmpty())
+ return false;
+
+ kdDebug(4640) << "KIconEditIcon::open " << url.prettyURL() << endl;
+
+ if(!url.isValid()) // try to see if it is a relative filename
+ {
+ kdDebug(4640) << "KIconEditIcon::open (malformed) " << url.prettyURL() << endl;
+
+ QFileInfo fi(url.url());
+ if(fi.isRelative())
+ url = "file:" + fi.absFilePath();
+
+ if(!url.isValid()) // Giving up
+ {
+ QString msg = i18n("The URL: %1 \nseems to be malformed.\n").arg(url.url());
+ KMessageBox::sorry((QWidget*)parent(), msg);
+ return false;
+ }
+ }
+
+ QString filename;
+
+ if(url.isLocalFile())
+ {
+ filename = url.path();
+ }
+ else
+ {
+ if(!KIO::NetAccess::download( url, filename, (QWidget*)parent() ))
+ {
+ QString msg = i18n("There was an error loading:\n%1\n").arg(url.prettyURL());
+ KMessageBox::error((QWidget*)parent(), msg);
+ return false;
+ }
+ }
+
+ bool loadedOk = img->load(filename);
+
+ if(!url.isLocalFile())
+ {
+ KIO::NetAccess::removeTempFile( filename );
+ }
+
+ if(!loadedOk)
+ {
+ QString msg = i18n("There was an error loading:\n%1\n").arg(url.prettyURL());
+ KMessageBox::error((QWidget*)parent(), msg);
+ }
+ else
+ {
+ kdDebug(4640) << "KIconEditIcon::open - Image loaded" << endl;
+
+ // _url is saved off for use in saving the image to the same
+ // file later - should include full path
+ if(url.isLocalFile())
+ {
+ _url = url.path();
+ }
+ else
+ {
+ _url = "";
+ }
+
+ kdDebug(4640) << "KIcon: _url: " << _url << endl;
+
+ // this causes updates of preview, color palettes, etc.
+ emit loaded(img);
+ kdDebug(4640) << "loaded(img)" << endl;
+
+ // this is the name that shows up in status bar -
+ // should be filename with path
+ emit newname(url.prettyURL());
+ kdDebug(4640) << "newname(_url) : " << url.prettyURL() << endl;
+
+ emit addrecent(url.prettyURL());
+
+ kdDebug(4640) << "KIconEditIcon::open - done" << endl;
+ }
+
+ return loadedOk;
+}
+
+
+
+bool KIconEditIcon::promptForFile(const QImage *img)
+{
+ kdDebug(4640) << "KIconEditIcon::promptForFile(const QImage *img)" << endl;
+ /*
+ QString filter = i18n("*|All Files (*)\n"
+ "*.xpm|XPM (*.xpm)\n"
+ "*.png|PNG (*.png)\n"
+ "*.gif|GIF files (*.gif)\n"
+ "*.jpg|JPEG files (*.jpg)\n"
+ "*.ico|Icon files (*.ico)\n");
+
+
+ KURL url = KFileDialog::getOpenURL( QString::null, filter );
+ */
+ bool loaded = false;
+ KURL url = KFileDialog::getImageOpenURL( QString::null, static_cast<QWidget *>(parent()) );
+
+ if( !url.isEmpty() )
+ {
+ loaded = open( img, url );
+ }
+
+ return loaded;
+}
+
+
+
+bool KIconEditIcon::saveAs(const QImage *image)
+{
+ kdDebug(4640) << "KIconEditIcon::saveAs" << endl;
+
+ QString file;
+
+ //Get list of file types..
+ KFileDialog *dialog=new KFileDialog(QString::null, QString::null, static_cast<QWidget *>(parent()), "file dialog", true);
+ dialog->setCaption( i18n("Save Icon As") );
+ dialog->setKeepLocation( true );
+ dialog->setMimeFilter( KImageIO::mimeTypes(KImageIO::Writing), "image/png" );
+ dialog->setOperationMode( KFileDialog::Saving );
+
+ if(dialog->exec()==QDialog::Accepted)
+ {
+ file = dialog->selectedFile();
+ if( file.isNull() )
+ {
+ delete dialog;
+ return false;
+ }
+ if ( !KImageIO::canWrite(KImageIO::type(file)) )
+ {
+ if ( KImageIO::canWrite(KImageIO::typeForMime(dialog->currentFilter())) )
+ file += "."+KImageIO::suffix(KImageIO::typeForMime(dialog->currentFilter()));
+ else
+ file += ".png";
+ }
+ }
+ else
+ {
+ delete dialog;
+ return false;
+ }
+
+ delete dialog;
+
+ if(QFile::exists(file))
+ {
+ int r=KMessageBox::warningContinueCancel(static_cast<QWidget *>(parent()),
+ i18n( "A file named \"%1\" already exists. "
+ "Overwrite it?" ).arg(file),
+ i18n( "Overwrite File?" ),
+ i18n( "&Overwrite" ) );
+
+ if(r==KMessageBox::Cancel)
+ {
+ return false;
+ }
+ }
+
+ return save( image, file );
+}
+
+
+
+bool KIconEditIcon::save(const QImage *image, const QString &_filename)
+{
+ kdDebug(4640) << "KIconEditIcon::save" << endl;
+ QString filename = _filename;
+
+ if(filename.isEmpty())
+ {
+ if(_url.isEmpty())
+ {
+ return saveAs(image);
+ }
+ else
+ {
+ KURL turl(_url);
+ filename = turl.path();
+ }
+ }
+
+ QImage *img = (QImage*)image;
+ img->setAlphaBuffer(true);
+
+ KURL turl(filename);
+ QString str = turl.path();
+ bool savedOk = false;
+
+ /* base image type on file extension - let kimageio
+ take care of this determination */
+
+ if(img->save(str, KImageIO::type(str).ascii()))
+ {
+ kdDebug(4640) << "img->save()) successful" << endl;
+ emit saved();
+ _url = filename;
+
+ // emit signal to change title bar to reflect new name
+ emit newname(filename);
+ kdDebug(4640) << "newname(filenamme) : " << _url << endl;
+ savedOk = true;
+ emit addrecent(filename);
+ }
+ else
+ {
+ QString msg = i18n("There was an error saving:\n%1\n").arg(str);
+ KMessageBox::error((QWidget*)parent(), msg);
+ kdDebug(4640) << "KIconEditIcon::save - " << msg << endl;
+ }
+
+ kdDebug(4640) << "KIconEditIcon::save - done" << endl;
+
+ return savedOk;
+}
+
+
+#include "kicon.moc"
diff --git a/kiconedit/kicon.h b/kiconedit/kicon.h
new file mode 100644
index 00000000..3af48c14
--- /dev/null
+++ b/kiconedit/kicon.h
@@ -0,0 +1,78 @@
+/*
+ KDE Icon Editor - a small icon drawing program for the KDE.
+ Copyright (C) 1998 Thomas Tanghus (tanghus@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 Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __KICON_H__
+#define __KICON_H__
+
+#include <stdio.h>
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if defined(HAVE_FCNTL_H) && !defined(HAVE_FLOCK)
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_STDC_HEADERS
+#include <stdlib.h>
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+
+class QImage;
+
+class KIconEditIcon : public QObject
+{
+ Q_OBJECT
+public:
+ KIconEditIcon(QObject*, const QImage*, KURL url = KURL() );
+ ~KIconEditIcon();
+
+ bool isLocal() { return local; }
+ QString url() { return _url; }
+ void setUrl( const QString & u ) { _url = u; };
+
+public slots:
+ bool open(const QImage*, KURL url = KURL());
+ bool promptForFile(const QImage*);
+ bool save(const QImage*, const QString &filename=QString::null);
+ bool saveAs(const QImage*);
+
+signals:
+ void newmessage( const QString &);
+ void newname(const QString &);
+ void addrecent(const QString &);
+ void opennewwin(const QString &);
+ void loaded(QImage *);
+ void saved();
+
+protected:
+ bool local;
+ QString _url;
+ QString _lastdir;
+ FILE *f;
+};
+
+#endif //__KICON_H__
diff --git a/kiconedit/kiconcolors.cpp b/kiconedit/kiconcolors.cpp
new file mode 100644
index 00000000..549f74d2
--- /dev/null
+++ b/kiconedit/kiconcolors.cpp
@@ -0,0 +1,170 @@
+/*
+ KDE Icon Editor - a small graphics drawing program for the KDE
+ Copyright (C) 1998 Thomas Tanghus (tanghus@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 Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qpainter.h>
+#include <qdrawutil.h>
+
+#include <kdebug.h>
+
+#include "kiconcolors.h"
+
+KDrawColors::KDrawColors(QWidget *parent) : KColorGrid(parent, 0, 3)
+{
+ kdDebug(4640) << "KDrawColors - constructor" << endl;
+ setCellSize(17);
+ setGrid(true);
+ setGridState(KColorGrid::Shaded);
+ selected = 0;
+ kdDebug(4640) << "KDrawColors - constructor - done" << endl;
+}
+
+void KDrawColors::paintCell( QPainter *painter, int row, int col )
+{
+ //KColorGrid::paintCell(painter, row, col);
+ uint c = colorAt( row * numCols() + col );
+ QBrush brush(c);
+ int d = spacing();
+
+ qDrawShadePanel( painter, d, d, cellSize()-d, cellSize()-d,
+ colorGroup(), true, 1, &brush);
+ if ( row * numCols() + col == selected)
+ painter->drawWinFocusRect( d+1, d+1, cellSize()-(2*d)+1, cellSize()-(2*d)+1 );
+}
+
+void KDrawColors::mouseReleaseEvent( QMouseEvent *e )
+{
+ int row = findRow( e->pos().y() );
+ int col = findCol( e->pos().x() );
+ int cell = row * numCols() + col;
+
+ if ( selected != cell )
+ {
+ int prevSel = selected;
+ selected = cell;
+ updateCell( prevSel/numCols(), prevSel%numCols(), FALSE );
+ updateCell( row, col, FALSE );
+ }
+
+ emit newColor(colorAt(cell)|OPAQUE_MASK);
+}
+
+KSysColors::KSysColors(QWidget *parent) : KDrawColors(parent)
+{
+ kdDebug(4640) << "KSysColors - constructor" << endl;
+
+ setNumRows(7);
+ setNumCols(6);
+ //fill(backgroundColor().rgb()|OPAQUE_MASK);
+ setFixedSize(numCols()*cellSize(), numRows()*cellSize());
+ fill(TRANSPARENT|OPAQUE_MASK);
+
+ int numcells = 42;
+
+ kdDebug(4640) << "KSysColors - constructor - before setColor" << endl;
+ for(int i = 0; i < numcells; i++)
+ {
+ setColor(i, iconpalette[i]|OPAQUE_MASK);
+ }
+ kdDebug(4640) << "KSysColors - constructor - done" << endl;
+}
+
+KCustomColors::KCustomColors(QWidget *parent) : KDrawColors(parent)
+{
+ kdDebug(4640) << "KCustomColors - constructor" << endl;
+ setNumRows(3);
+ setNumCols(6);
+ fill(TRANSPARENT|OPAQUE_MASK);
+ setFixedSize(numCols()*cellSize(), numRows()*cellSize());
+ freecells = new bool[numRows()*numCols()];
+ for(int i = 0; i < numRows()*numCols(); i++)
+ freecells[i] = true;
+ kdDebug(4640) << "KCustomColors - constructor - done" << endl;
+}
+
+KCustomColors::~KCustomColors()
+{
+ delete [] freecells;
+}
+
+void KCustomColors::mouseDoubleClickEvent(QMouseEvent *e)
+{
+ int row = findRow( e->pos().y() );
+ int col = findCol( e->pos().x() );
+ int cell = row * numCols() + col;
+ QColor color=colorAt(cell);
+ if(KColorDialog::getColor(color))
+ {
+ setColor(cell, color.rgb());
+ emit newColor(color.rgb()|OPAQUE_MASK);
+ freecells[cell] = false;
+ }
+}
+
+void KCustomColors::addColor(uint c)
+{
+ if(!contains(c))
+ {
+ int f = getFreeCell();
+ if(f != -1)
+ {
+ QColor color(c);
+ if(!color.isValid())
+ {
+ kdDebug(4640) << "KCustomColors::addColor: Not a valid color: " << c << endl;
+ return;
+ }
+ //kdDebug(4640) << "KCustomColors::addColor: Adding color: " << c << " - " << qRed(c) << " " << qGreen(c) << " " << qBlue(c) << endl;
+ setColor(f, c);
+ freecells[f] = false;
+ }
+ }
+}
+
+int KCustomColors::getFreeCell()
+{
+ for (int i = 0; i < numRows()*numCols(); i++)
+ {
+ if(freecells[i])
+ {
+ if(i+1 < numRows()*numCols())
+ freecells[i+1] = true;
+ else
+ freecells[0] = true;
+ return i;
+ break;
+ }
+ }
+ freeAllCells(); // start over again - not very elegant
+ return 0;
+}
+
+void KCustomColors::freeAllCells()
+{
+ for (int i = 0; i < numRows()*numCols(); i++)
+ freecells[i] = true;
+}
+
+void KCustomColors::clear()
+{
+ fill(TRANSPARENT);
+ freeAllCells();
+ update();
+}
+#include "kiconcolors.moc"
diff --git a/kiconedit/kiconcolors.h b/kiconedit/kiconcolors.h
new file mode 100644
index 00000000..a4293ff3
--- /dev/null
+++ b/kiconedit/kiconcolors.h
@@ -0,0 +1,83 @@
+/*
+ kiconedit - a small graphics drawing program for creating KDE icons
+ Copyright (C) 1998 Thomas Tanghus (tanghus@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 Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __KDRAWCOLORS_H__
+#define __KDRAWCOLORS_H__
+
+#include <qpopupmenu.h>
+
+#include <kcolordialog.h>
+
+#include "kcolorgrid.h"
+#include "utils.h"
+
+class KDrawColors : public KColorGrid
+{
+ Q_OBJECT
+public:
+ KDrawColors(QWidget *parent);
+
+ //bool hasColor(uint);
+
+signals:
+ void newColor(uint);
+
+protected:
+ virtual void paintCell( QPainter*, int, int );
+ virtual void mouseReleaseEvent(QMouseEvent*);
+
+ int selected;
+};
+
+class KCustomColors : public KDrawColors
+{
+ Q_OBJECT
+public:
+ KCustomColors(QWidget *parent);
+ ~KCustomColors();
+
+ void addColor(uint);
+ void clear();
+
+protected:
+ virtual void mouseDoubleClickEvent(QMouseEvent*);
+ int getFreeCell();
+ void freeAllCells();
+
+protected:
+ bool *freecells;
+ QPopupMenu *popup;
+};
+
+class KSysColors : public KDrawColors
+{
+ Q_OBJECT
+public:
+
+ KSysColors(QWidget *parent);
+
+};
+
+
+
+#endif //__KDRAWCOLORS_H__
+
+
+
diff --git a/kiconedit/kiconconfig.cpp b/kiconedit/kiconconfig.cpp
new file mode 100644
index 00000000..e7677e30
--- /dev/null
+++ b/kiconedit/kiconconfig.cpp
@@ -0,0 +1,589 @@
+/*
+ KDE Icon Editor - a small graphics drawing program for the KDE
+ Copyright (C) 1998 Thomas Tanghus (tanghus@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 Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <stdlib.h>
+
+#include <qcheckbox.h>
+#include <qlayout.h>
+#include <qlineedit.h>
+#include <qvbox.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+
+#include <kaccel.h>
+#include <kbuttonbox.h>
+#include <kapplication.h>
+#include <klocale.h>
+#include <kcolorbutton.h>
+#include <kfiledialog.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <kurlrequester.h>
+
+#include "kiconconfig.h"
+#include "kiconedit.h"
+
+#ifndef PICS_INCLUDED
+#define PICS_INCLUDED
+#include "pics/logo.xpm"
+#endif
+
+// little helper:
+static inline QPixmap loadIcon( const char * name )
+{
+ return KGlobal::instance()->iconLoader()
+ ->loadIcon( QString::fromLatin1(name), KIcon::NoGroup, KIcon::SizeMedium );
+}
+
+KTemplateEditDlg::KTemplateEditDlg(QWidget *parent)
+ : KDialogBase(parent, "KTemplateEditDlg", true, i18n( "Icon Template" ),
+ Ok|Cancel )
+{
+ QFrame *frame = makeMainWidget();
+ QVBoxLayout *ml = new QVBoxLayout(frame);
+ QGroupBox *grp = new QGroupBox(i18n("Template"), frame);
+ grp->setColumnLayout(0, Qt::Vertical);
+ grp->layout()->setSpacing(spacingHint());
+ grp->layout()->setMargin(marginHint());
+ QGridLayout *l = new QGridLayout(grp->layout());
+
+ ln_name = new QLineEdit( grp );
+ connect( ln_name, SIGNAL( textChanged( const QString & ) ),
+ SLOT( slotTextChanged() ) );
+ QLabel* lb_name = new QLabel( ln_name, i18n( "Description:" ), grp );
+
+ ln_path = new KURLRequester(grp);
+ connect( ln_path, SIGNAL( textChanged( const QString & ) ),
+ SLOT( slotTextChanged() ) );
+ QLabel* lb_path = new QLabel( ln_path, i18n( "Path:" ), grp );
+
+ l->addWidget(lb_name, 0, 0);
+ l->addWidget(ln_name, 0, 1);
+ l->addWidget(lb_path, 1, 0);
+ l->addWidget(ln_path, 1, 1);
+
+ ml->addWidget( grp, 1);
+
+ slotTextChanged();
+
+ setMinimumSize( 400, 150 );
+}
+
+void KTemplateEditDlg::slotTextChanged()
+{
+ QString name = ln_name->text(), path = ln_path->url();
+ enableButtonOK(name.length() && path.length());
+}
+
+void KTemplateEditDlg::setName(const QString & name)
+{
+ ln_name->setText(name);
+}
+
+QString KTemplateEditDlg::name()
+{
+ return ln_name->text();
+}
+
+void KTemplateEditDlg::setPath(const QString & path)
+{
+ ln_path->setURL(path);
+}
+
+QString KTemplateEditDlg::path()
+{
+ return ln_path->url();
+}
+
+KTemplateConfig::KTemplateConfig(QWidget *parent) : QWidget(parent)
+{
+ kdDebug(4640) << "KTemplateConfig constructor" << endl;
+
+ btadd = btremove = btedit = 0L;
+
+ QGroupBox* grp = new QGroupBox( i18n( "Templates" ), this );
+ grp->setColumnLayout( 0, Qt::Horizontal );
+
+ templates = new KIconListBox( grp );
+ connect( templates, SIGNAL( highlighted( int ) ),
+ SLOT( checkSelection( int ) ) );
+ connect( templates, SIGNAL(doubleClicked( QListBoxItem * ) ),
+ SLOT( edit() ) );
+
+ QVBoxLayout* ml = new QVBoxLayout( this );
+ ml->addWidget( grp );
+
+ QVBoxLayout* l = new QVBoxLayout( grp->layout(), KDialog::spacingHint() );
+ l->addWidget( templates );
+
+ for( unsigned int i = 0; i < KIconTemplateContainer::self()->count(); i++ )
+ templates->insertItem( new KIconListBoxItem( *KIconTemplateContainer::self()->at( i ) ) ) ;
+
+ KButtonBox *bbox = new KButtonBox( grp );
+
+ btadd = bbox->addButton( i18n( "&Add..." ) );
+ connect( btadd, SIGNAL( clicked() ), SLOT( add() ) );
+
+ btedit = bbox->addButton( i18n( "&Edit..." ) );
+ connect( btedit, SIGNAL( clicked() ), SLOT( edit() ) );
+ btedit->setEnabled( false );
+
+ btremove = bbox->addButton( i18n( "&Remove" ) );
+ connect( btremove, SIGNAL( clicked() ), SLOT( remove() ) );
+ btremove->setEnabled( false );
+
+ bbox->addStretch( 1 );
+
+ bbox->layout();
+ l->addWidget( bbox );
+}
+
+KTemplateConfig::~KTemplateConfig()
+{
+}
+
+void KTemplateConfig::saveSettings()
+{
+ kdDebug(4640) << "KTemplateConfig::saveSettings" << endl;
+
+ KIconTemplateContainer::self()->clear();
+
+ for(int i = 0; i < (int)templates->count(); i++)
+ {
+ KIconTemplateContainer::self()->append(templates->iconTemplate(i));
+ }
+ KIconTemplateContainer::self()->save();
+ kdDebug(4640) << "KTemplateConfig::saveSettings - done" << endl;
+
+}
+
+void KTemplateConfig::checkSelection(int)
+{
+ kdDebug(4640) << "KTemplateConfig::checkSelection" << endl;
+ if(templates->currentItem() != -1)
+ {
+ if(btremove) btremove->setEnabled(true);
+ if(btedit) btedit->setEnabled(true);
+ }
+ else
+ {
+ if(btremove) btremove->setEnabled(false);
+ if(btedit) btedit->setEnabled(false);
+ }
+ kdDebug(4640) << "KTemplateConfig::checkSelection - done" << endl;
+}
+
+void KTemplateConfig::remove()
+{
+ templates->removeItem(templates->currentItem());
+}
+
+void KTemplateConfig::add()
+{
+ KTemplateEditDlg dlg(this);
+ if(dlg.exec())
+ {
+ KIconTemplate it;
+ it.path = dlg.path();
+ it.title = dlg.name();
+ templates->insertItem(new KIconListBoxItem(it));
+ }
+}
+
+void KTemplateConfig::edit()
+{
+ KTemplateEditDlg dlg(this);
+ dlg.setPath(templates->path(templates->currentItem()));
+ dlg.setName(templates->text(templates->currentItem()));
+ templates->item(templates->currentItem());
+ if(dlg.exec())
+ {
+ //Edit the entry
+ KIconTemplate &it=templates->iconTemplate(templates->currentItem());
+ it.path = dlg.path();
+ it.title = dlg.name();
+ static_cast<KIconListBoxItem*>(templates->item(templates->currentItem()))->reloadIcon();
+ templates->update();
+ }
+}
+
+KBackgroundConfig::KBackgroundConfig( QWidget* parent )
+ : QWidget( parent )
+{
+ kdDebug(4640) << "KBackgroundConfig - constructor" << endl;
+
+ lb_ex = 0L;
+
+ KIconEditProperties *props = KIconEditProperties::self();
+
+ pixpath = props->bgPixmap();
+ pix.load(pixpath);
+ if(pix.isNull())
+ {
+ kdDebug(4640) << "BGPIX: " << pixpath << " not valid!" << endl;
+ QPixmap pmlogo((const char**)logo);
+ pix = pmlogo;
+ }
+
+ QVBoxLayout *mainLayout = new QVBoxLayout( this );
+
+ QGroupBox *grp1 = new QGroupBox( i18n( "Select Background" ), this );
+ grp1->setColumnLayout(0, Qt::Vertical );
+ grp1->layout()->setSpacing( KDialog::spacingHint() );
+ grp1->layout()->setMargin( KDialog::marginHint() );
+ mainLayout->addWidget( grp1 );
+
+ QGridLayout *grp1Layout = new QGridLayout( grp1->layout(), 3, 2 );
+
+ QButtonGroup* btngrp = new QButtonGroup( grp1 );
+ btngrp->setExclusive( true );
+ btngrp->setFrameStyle( QFrame::NoFrame );
+ connect( btngrp, SIGNAL( clicked( int ) ), SLOT( slotBackgroundMode( int ) ) );
+ grp1Layout->addWidget( btngrp, 0, 0 );
+
+ QVBoxLayout *bgl = new QVBoxLayout( btngrp, 5 );
+
+ QRadioButton *rbc = new QRadioButton( i18n( "Use co&lor" ), btngrp );
+ btngrp->insert( rbc, 0 );
+ bgl->addWidget( rbc );
+
+ QRadioButton *rbp = new QRadioButton( i18n( "Use pix&map" ), btngrp );
+ btngrp->insert( rbp, 1 );
+ bgl->addWidget( rbp );
+
+ bgl->addStretch( 1 );
+
+ QVBox *bbox = new QVBox( grp1 );
+ grp1Layout->addWidget( bbox, 0, 1 );
+
+ btcolor = new KColorButton(props->bgColor(), bbox) ;
+ connect(btcolor, SIGNAL(changed(const QColor &)),
+ SLOT( selectColor(const QColor &)));
+
+ btpix = new QPushButton(i18n( "Choose..." ), bbox);
+ connect( btpix, SIGNAL( clicked() ), SLOT( selectPixmap() ) );
+
+ QGroupBox *grp2 = new QGroupBox( i18n( "Preview" ), this );
+ mainLayout->addWidget( grp2, 1 );
+
+ QBoxLayout *l2 = new QVBoxLayout( grp2, 15 );
+
+ l2->addSpacing( 10 );
+
+ lb_ex = new QLabel( grp2 );
+ lb_ex->setFrameStyle( QFrame::Panel | QFrame::Sunken );
+ l2->addWidget( lb_ex );
+
+/*
+ l1->addWidget( btngrp, 0, AlignLeft );
+ l1->addLayout( l1r );
+*/
+ bgmode = props->bgMode();
+
+ if( bgmode == QWidget::FixedPixmap )
+ {
+ btngrp->setButton( 1 );
+ btcolor->setEnabled( false );
+ lb_ex->setBackgroundPixmap( pix );
+ }
+ else
+ {
+ btngrp->setButton( 0 );
+ btpix->setEnabled( false );
+ lb_ex->setBackgroundColor(btcolor->color());
+ }
+}
+
+KBackgroundConfig::~KBackgroundConfig()
+{
+}
+
+void KBackgroundConfig::slotBackgroundMode(int id)
+{
+ if(id == 0)
+ {
+ bgmode = QWidget::FixedColor;
+ btpix->setEnabled(false);
+ btcolor->setEnabled(true);
+ if(lb_ex)
+ lb_ex->setBackgroundColor(btcolor->color());
+ }
+ else
+ {
+ bgmode = QWidget::FixedPixmap;
+ btpix->setEnabled(true);
+ btcolor->setEnabled(false);
+ if(lb_ex)
+ lb_ex->setBackgroundPixmap(pix);
+ }
+}
+
+void KBackgroundConfig::saveSettings()
+{
+ kdDebug(4640) << "KBackgroundConfig::saveSettings" << endl;
+ KIconEditProperties *props = KIconEditProperties::self();
+ props->setBgMode( bgmode );
+ props->setBgPixmap( pixpath );
+ props->setBgColor( btcolor->color() );
+ kdDebug(4640) << "KBackgroundConfig::saveSettings - done" << endl;
+}
+
+void KBackgroundConfig::selectColor(const QColor & newColor)
+{
+ lb_ex->setBackgroundColor(newColor);
+}
+
+void KBackgroundConfig::selectPixmap()
+{
+ // KURL url = KFileDialog::getOpenURL("/", "*.xpm");
+ KURL url = KFileDialog::getImageOpenURL("/");
+
+ if( url.isEmpty() )
+ return;
+
+ if( !url.isLocalFile() )
+ {
+ KMessageBox::sorry( 0L, i18n( "Only local files are supported yet." ) );
+ return;
+ }
+
+ QPixmap p(url.path());
+
+ if( !p.isNull() )
+ {
+ lb_ex->setBackgroundPixmap( p );
+ pixpath = url.path();
+ }
+}
+
+KMiscConfig::KMiscConfig(QWidget *parent) : QWidget(parent)
+{
+ kdDebug(4640) << "KMiscConfig - constructor" << endl;
+
+ KIconEditProperties* props = KIconEditProperties::self();
+
+ QBoxLayout *ml = new QVBoxLayout( this, 0, 5 );
+
+ QCheckBox *cbp = new QCheckBox( i18n( "Paste &transparent pixels" ), this );
+ connect( cbp, SIGNAL( toggled( bool ) ), SLOT( pasteMode( bool ) ) );
+ ml->addWidget(cbp);
+
+ QCheckBox *cbr = new QCheckBox( i18n( "Show &rulers" ), this );
+ connect( cbr, SIGNAL( toggled( bool ) ), SLOT( showRulers( bool ) ) );
+ ml->addWidget(cbr);
+
+ QButtonGroup* btngrp = new QButtonGroup( i18n( "Transparency Display" ), this);
+ btngrp->setExclusive( true );
+ connect( btngrp, SIGNAL( clicked( int ) ), SLOT( slotTransparencyDisplayType( int ) ) );
+ ml->addWidget( btngrp );
+
+ QVBoxLayout *tgl = new QVBoxLayout( btngrp, KDialog::marginHint(), KDialog::spacingHint() );
+ tgl->insertSpacing(0, 10);
+
+ QHBoxLayout *hl = new QHBoxLayout(tgl);
+
+ QRadioButton *solidColorRButton = new QRadioButton( i18n( "&Solid color:" ), btngrp );
+ btngrp->insert( solidColorRButton, 0 );
+ hl->addWidget( solidColorRButton );
+
+ m_solidColorButton = new KColorButton(props->transparencySolidColor(), btngrp);
+ btngrp->insert( m_solidColorButton, 2 );
+ hl->addWidget(m_solidColorButton);
+ //connect(btcolor, SIGNAL(changed(const QColor &)),
+ // SLOT( selectColor(const QColor &)));
+
+ QRadioButton *checkerboardRButton = new QRadioButton( i18n( "Checker&board" ), btngrp );
+ btngrp->insert( checkerboardRButton, 1 );
+ tgl->addWidget( checkerboardRButton );
+
+ QGridLayout *grid = new QGridLayout(tgl, 3, 3);
+ grid->addColSpacing(0, 40);
+ grid->setColStretch(1, 1);
+ grid->setColStretch(2, 1);
+
+ m_checkerboardSizeCombo = new QComboBox(btngrp);
+ m_checkerboardSizeCombo->insertItem( i18n( "Small" ) );
+ m_checkerboardSizeCombo->insertItem( i18n( "Medium" ) );
+ m_checkerboardSizeCombo->insertItem( i18n( "Large" ) );
+ m_checkerboardSizeCombo->setCurrentItem(props->checkerboardSize());
+
+ QLabel *label = new QLabel(m_checkerboardSizeCombo, i18n("Si&ze:"), btngrp);
+
+ grid->addWidget(label, 0, 1);
+ grid->addWidget(m_checkerboardSizeCombo, 0, 2);
+
+ m_checkerboardColor1Button = new KColorButton(props->checkerboardColor1(), btngrp);
+ label = new QLabel(m_checkerboardColor1Button, i18n("Color &1:"), btngrp);
+
+ grid->addWidget(label, 1, 1);
+ grid->addWidget(m_checkerboardColor1Button, 1, 2);
+
+ m_checkerboardColor2Button = new KColorButton(props->checkerboardColor2(), btngrp);
+ label = new QLabel(m_checkerboardColor2Button, i18n("Color &2:"), btngrp);
+
+ grid->addWidget(label, 2, 1);
+ grid->addWidget(m_checkerboardColor2Button, 2, 2);
+
+ if(props->transparencyDisplayType() == KIconEditGrid::TRD_CHECKERBOARD)
+ {
+ checkerboardRButton->setChecked(true);
+ m_checkerboardColor1Button->setEnabled(true);
+ m_checkerboardColor2Button->setEnabled(true);
+ m_checkerboardSizeCombo->setEnabled(true);
+
+ solidColorRButton->setChecked(false);
+ m_solidColorButton->setEnabled(false);
+ }
+ else
+ {
+ checkerboardRButton->setChecked(false);
+ m_checkerboardColor1Button->setEnabled(false);
+ m_checkerboardColor2Button->setEnabled(false);
+ m_checkerboardSizeCombo->setEnabled(false);
+
+ solidColorRButton->setChecked(true);
+ m_solidColorButton->setEnabled(true);
+ }
+
+ ml->addStretch(1);
+
+ cbp->setChecked( props->pasteTransparent() );
+ cbr->setChecked( props->showRulers() );
+}
+
+KMiscConfig::~KMiscConfig()
+{
+
+}
+
+void KMiscConfig::saveSettings()
+{
+ kdDebug(4640) << "KMiscConfig::saveSettings" << endl;
+ KIconEditProperties* props = KIconEditProperties::self();
+ props->setPasteTransparent( pastemode );
+ props->setShowRulers( showrulers );
+ if(m_solidColorButton->isEnabled())
+ {
+ props->setTransparencyDisplayType(KIconEditGrid::TRD_SOLIDCOLOR);
+ props->setTransparencySolidColor(m_solidColorButton->color());
+ }
+ else
+ {
+ props->setTransparencyDisplayType(KIconEditGrid::TRD_CHECKERBOARD);
+ props->setCheckerboardColor1(m_checkerboardColor1Button->color());
+ props->setCheckerboardColor2(m_checkerboardColor2Button->color());
+ props->setCheckerboardSize((KIconEditGrid::CheckerboardSize)m_checkerboardSizeCombo->currentItem());
+ }
+}
+
+void KMiscConfig::pasteMode(bool mode)
+{
+ pastemode = mode;
+}
+
+void KMiscConfig::showRulers(bool mode)
+{
+ showrulers = mode;
+}
+
+void KMiscConfig::slotTransparencyDisplayType(int id)
+{
+ if(id == 0)
+ {
+ m_checkerboardColor1Button->setEnabled(false);
+ m_checkerboardColor2Button->setEnabled(false);
+ m_checkerboardSizeCombo->setEnabled(false);
+
+ m_solidColorButton->setEnabled(true);
+ }
+ else
+ if(id == 1)
+ {
+ m_checkerboardColor1Button->setEnabled(true);
+ m_checkerboardColor2Button->setEnabled(true);
+ m_checkerboardSizeCombo->setEnabled(true);
+
+ m_solidColorButton->setEnabled(false);
+ }
+}
+
+KIconConfig::KIconConfig(QWidget *parent)
+ : KDialogBase(KDialogBase::IconList, i18n("Configure"),
+ KDialogBase::Help |
+ KDialogBase::Ok |
+ KDialogBase::Apply |
+ KDialogBase::Cancel,
+ KDialogBase::Ok,
+ parent, "configDialog", true, true)
+{
+ setHelp(QString::null);
+ //KWin::setIcons(winId(), kapp->icon(), kapp->miniIcon());
+ connect(this, SIGNAL(finished()), this, SLOT(finis()));
+
+ QVBox* page = addVBoxPage(i18n("Icon Templates"), QString::null, loadIcon("icons"));
+ temps = new KTemplateConfig(page);
+
+ page = addVBoxPage(i18n("Background"), QString::null, loadIcon("background"));
+ backs = new KBackgroundConfig(page);
+
+ page = addVBoxPage(i18n("Icon Grid"), QString::null, loadIcon("kiconedit"));
+ misc = new KMiscConfig(page);
+
+ QSize min(300, 400);
+
+ if (300 < sizeHint().width()) { min.setWidth(sizeHint().width()); }
+ if (400 < sizeHint().height()) { min.setHeight(sizeHint().height()); }
+
+ resize(min);
+}
+
+KIconConfig::~KIconConfig()
+{
+ //delete dict;
+}
+
+void KIconConfig::slotApply()
+{
+ kdDebug(4640) << "KIconEditConfig::saveSettings" << endl;
+
+ temps->saveSettings();
+ backs->saveSettings();
+ misc->saveSettings();
+
+ for (KIconEdit* window = KIconEdit::windowList.first();
+ window;
+ window = KIconEdit::windowList.next())
+ {
+ window->updateProperties();
+ }
+}
+
+void KIconConfig::slotOk()
+{
+ slotApply();
+ KDialogBase::slotOk();
+}
+
+void KIconConfig::finis()
+{
+ delayedDestruct();
+}
+
+#include "kiconconfig.moc"
diff --git a/kiconedit/kiconconfig.h b/kiconedit/kiconconfig.h
new file mode 100644
index 00000000..04483732
--- /dev/null
+++ b/kiconedit/kiconconfig.h
@@ -0,0 +1,153 @@
+/*
+ KDE Icon Editor - a small icon drawing program for the KDE.
+ Copyright (C) 1998 Thomas Tanghus (tanghus@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 Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __KICONCONFIG_H__
+#define __KICONCONFIG_H__
+
+#include <qpixmap.h>
+#include <kdialogbase.h>
+
+#include "knew.h"
+#include "utils.h"
+#include "properties.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+class KAccel;
+class KKeyChooser;
+class KColorButton;
+class KURLRequester;
+class QComboBox;
+
+class KTemplateEditDlg : public KDialogBase
+{
+ Q_OBJECT
+public:
+ KTemplateEditDlg(QWidget *);
+ ~KTemplateEditDlg() {};
+
+ QString name();
+ QString path();
+ void setName(const QString &);
+ void setPath(const QString &);
+
+public slots:
+ void slotTextChanged();
+
+protected:
+ QLineEdit *ln_name;
+ KURLRequester *ln_path;
+};
+
+class KTemplateConfig : public QWidget
+{
+ Q_OBJECT
+public:
+ KTemplateConfig(QWidget*);
+ ~KTemplateConfig();
+
+ void saveSettings();
+
+protected slots:
+ void add();
+ void edit();
+ void remove();
+ void checkSelection(int);
+
+protected:
+ KIconListBox *templates;
+ QPushButton *btadd, *btedit, *btremove;
+};
+
+class KBackgroundConfig : public QWidget
+{
+ Q_OBJECT
+public:
+ KBackgroundConfig(QWidget *parent);
+ ~KBackgroundConfig();
+
+public slots:
+ void saveSettings();
+ void selectColor(const QColor & newColor);
+ void selectPixmap();
+
+signals:
+
+protected slots:
+ void slotBackgroundMode(int);
+
+protected:
+ KColorButton *btcolor;
+ QPushButton *btpix;
+ QPixmap pix;
+ QString pixpath;
+ QWidget::BackgroundMode bgmode;
+ QLabel *lb_ex;
+};
+
+class KMiscConfig : public QWidget
+{
+ Q_OBJECT
+public:
+ KMiscConfig(QWidget *parent);
+ ~KMiscConfig();
+
+public slots:
+ void saveSettings();
+ void pasteMode(bool);
+ void showRulers(bool);
+
+protected slots:
+ void slotTransparencyDisplayType(int);
+
+signals:
+
+protected:
+ bool pastemode, showrulers;
+ QRadioButton *rbp;
+ KColorButton *m_solidColorButton;
+ KColorButton *m_checkerboardColor1Button;
+ KColorButton *m_checkerboardColor2Button;
+ QComboBox *m_checkerboardSizeCombo;
+};
+
+class KIconConfig : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ KIconConfig(QWidget *parent);
+ ~KIconConfig();
+
+protected slots:
+ void slotApply();
+ void slotOk();
+ void finis();
+
+protected:
+ KTemplateConfig *temps;
+ KBackgroundConfig *backs;
+ KMiscConfig *misc;
+};
+
+#endif //__KICONCONFIG_H__
diff --git a/kiconedit/kiconedit.cpp b/kiconedit/kiconedit.cpp
new file mode 100644
index 00000000..13cd4b89
--- /dev/null
+++ b/kiconedit/kiconedit.cpp
@@ -0,0 +1,497 @@
+/*
+ kiconedit - a small graphics drawing program for the KDE
+ Copyright (C) 1998 Thomas Tanghus (tanghus@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 Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qwhatsthis.h>
+#include <qtooltip.h>
+
+#include <kpopupmenu.h>
+#include <kstdaction.h>
+#include <kconfig.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+
+#include "kiconedit.h"
+#include "palettetoolbar.h"
+
+WindowList KIconEdit::windowList;
+
+KIconEdit::KIconEdit(const QImage image, const char *name)
+ : KMainWindow(0, name)
+{
+ init();
+ img = image;
+ img.detach();
+ grid->load(&img);
+ grid->setModified(true);
+}
+
+KIconEdit::KIconEdit(KURL url, const char *name)
+ : KMainWindow(0, name)
+{
+ init();
+ icon->open(&img, url);
+}
+
+void KIconEdit::init()
+{
+ setMinimumSize( 600, 540 );
+
+ windowList.append(this);
+ setCaption(kapp->caption());
+
+ m_paletteToolBar = 0L;
+ statusbar = 0L;
+
+ history = new KCommandHistory( actionCollection(), true );
+
+ gridview = new KGridView(&img, history, this);
+ grid = gridview->grid();
+ icon = new KIconEditIcon(this, &grid->image());
+
+ setAcceptDrops(true);
+
+ setupActions();
+ setupStatusBar();
+ setStandardToolBarMenuEnabled( true );
+
+ createGUI();
+
+ connect(this, SIGNAL(newname(const QString &)),
+ SLOT( slotUpdateStatusName(const QString &)));
+
+ connect( icon, SIGNAL( saved()), SLOT(slotSaved()));
+ connect( icon, SIGNAL( loaded(QImage *)), grid, SLOT(load(QImage *)));
+ connect( icon, SIGNAL(opennewwin(const QString &)),
+ SLOT(slotNewWin(const QString &)));
+ connect(icon, SIGNAL(newname(const QString &)),
+ SLOT( slotUpdateStatusName(const QString &)));
+ connect(icon, SIGNAL(newmessage(const QString &)),
+ SLOT( slotUpdateStatusMessage(const QString &)));
+ connect(icon, SIGNAL(addrecent(const QString &)),
+ SLOT( addRecent(const QString &)));
+
+ connect( m_paletteToolBar, SIGNAL( newColor(uint)),
+ grid, SLOT(setColorSelection(uint)));
+
+ connect( grid, SIGNAL( changed(const QPixmap &) ),
+ m_paletteToolBar, SLOT( previewChanged(const QPixmap &) ) );
+ connect( grid, SIGNAL( addingcolor(uint) ),
+ m_paletteToolBar, SLOT(addColor(uint)));
+ connect( grid, SIGNAL( colorschanged(uint, uint*) ),
+ m_paletteToolBar, SLOT(addColors(uint, uint*)));
+
+ connect(grid, SIGNAL(sizechanged(int, int)),
+ SLOT( slotUpdateStatusSize(int, int)));
+ connect(grid, SIGNAL(poschanged(int, int)),
+ SLOT( slotUpdateStatusPos(int, int)));
+ connect(grid, SIGNAL(scalingchanged(int)),
+ SLOT( slotUpdateStatusScaling(int)));
+ connect(grid, SIGNAL(scalingchanged(int)),
+ SLOT( slotUpdateZoom(int)));
+ connect( grid, SIGNAL( addingcolor(uint) ),
+ SLOT(slotUpdateStatusColors(uint)));
+ connect(grid, SIGNAL(colorschanged(uint, uint*)),
+ SLOT( slotUpdateStatusColors(uint, uint*)));
+ connect(grid, SIGNAL(newmessage(const QString &)),
+ SLOT( slotUpdateStatusMessage(const QString &)));
+ connect(grid, SIGNAL(clipboarddata(bool)),
+ SLOT( slotUpdatePaste(bool)));
+ connect(grid, SIGNAL(colorSelected(uint)),
+ m_paletteToolBar, SLOT(currentColorChanged(uint)));
+ connect(grid, SIGNAL(modifiedchanged(bool)),
+ SLOT( slotUpdateStatusModified(bool)));
+ gridview->checkClipboard(); //Not very elegant, but fixes a buglet
+
+ connect(grid, SIGNAL(selecteddata(bool)), SLOT( slotUpdateCopy(bool)));
+
+ kdDebug(4640) << "Updating statusbar" << endl;
+ slotUpdateStatusSize(grid->cols(), grid->rows());
+ slotUpdateStatusScaling(grid->scaling());
+
+ slotUpdateZoom( grid->scaling() );
+
+ if(icon->url().length())
+ slotUpdateStatusName(icon->url());
+ else
+ slotUpdateStatusName(i18n("Untitled"));
+
+ slotUpdateCopy(false);
+
+ uint *c = 0, n = 0;
+ n = grid->getColors(c);
+ slotUpdateStatusColors(n, c);
+
+ setCentralWidget(gridview);
+
+ applyMainWindowSettings( kapp->config(), "MainWindowSettings" );
+ updateProperties();
+
+ updateAccels();
+ show();
+ moveDockWindow( m_paletteToolBar, Qt::DockRight, true, 0 );
+}
+
+KIconEdit::~KIconEdit()
+{
+ windowList.remove(this);
+
+ if (windowList.count() < 1)
+ {
+ kapp->quit();
+ }
+}
+
+bool KIconEdit::queryClose()
+{
+ bool cancel = false;
+ if (grid->isModified())
+ {
+ int r = KMessageBox::warningYesNoCancel(this,
+ i18n("The current file has been modified.\nDo you want to save it?"), QString::null, KStdGuiItem::save(), KStdGuiItem::discard());
+
+ switch(r)
+ {
+ case KMessageBox::Yes:
+ if (!icon->save(&grid->image()))
+ {
+ cancel = true;
+ }
+ break;
+ case KMessageBox::Cancel:
+ cancel = true;
+ break;
+ case KMessageBox::No:
+ default:
+ break;
+ }
+ }
+
+ if(!cancel)
+ {
+ writeConfig();
+ }
+ return (!cancel);
+}
+
+// this is for exit by request of the session manager
+void KIconEdit::saveProperties(KConfig *config )
+{
+ kdDebug(4640) << "KIconEdit::saveProperties" << endl;
+
+ config->writePathEntry("Name", icon->url());
+}
+
+// this is for instances opened by the session manager
+void KIconEdit::readProperties(KConfig *config)
+{
+ kdDebug(4640) << "KIconEdit::readProperties" << endl;
+
+ QString entry = config->readPathEntry("Name"); // no default
+ if (entry.isEmpty()) return;
+ icon->open(&grid->image(), KURL::fromPathOrURL( entry ));
+}
+
+/*
+ this is for normal exits or request from "Options->Save options".
+*/
+void KIconEdit::writeConfig()
+{
+ KConfig *config = kapp->config();
+ m_actRecent->saveEntries( kapp->config() );
+
+ KIconEditProperties::self()->save();
+
+ saveMainWindowSettings( config, "MainWindowSettings" );
+}
+
+QSize KIconEdit::sizeHint() const
+{
+ if(gridview)
+ return gridview->sizeHint();
+ else
+ return QSize(-1, -1);
+}
+
+void KIconEdit::setupActions()
+{
+ kdDebug(4640) << "setupActions" << endl;
+
+ KAction *action;
+ KRadioAction *toolAction;
+ KShortcut cut;
+
+ // File Menu
+ action = new KAction(i18n("New &Window"), "window_new", cut,
+ this, SLOT(slotNewWin()), actionCollection(), "file_new_window");
+ action->setWhatsThis(i18n("New window\n\nOpens a new icon editor window."));
+
+ action = KStdAction::openNew(this, SLOT(slotNew()), actionCollection());
+ action->setWhatsThis(i18n("New\n\nCreate a new icon, either from a"
+ " template or by specifying the size"));
+
+ action = KStdAction::open(this, SLOT(slotOpen()), actionCollection());
+ action->setWhatsThis(i18n("Open\n\nOpen an existing icon"));
+
+ m_actRecent = KStdAction::openRecent(this,
+ SLOT(slotOpenRecent(const KURL&)), actionCollection());
+ m_actRecent->setMaxItems(15); // FIXME should be configurable!
+ m_actRecent->loadEntries(kapp->config());
+
+ action = KStdAction::save(this, SLOT(slotSave()), actionCollection());
+ action->setWhatsThis(i18n("Save\n\nSave the current icon"));
+
+ KStdAction::saveAs(this, SLOT(slotSaveAs()), actionCollection());
+
+ action = KStdAction::print(this, SLOT(slotPrint()), actionCollection());
+ action->setWhatsThis(i18n("Print\n\nOpens a print dialog to let you print"
+ " the current icon."));
+
+ KStdAction::close(this, SLOT(slotClose()), actionCollection());
+
+ // Edit Menu
+
+ m_actCut = KStdAction::cut(this, SLOT(slotCut()), actionCollection());
+ m_actCut->setWhatsThis(i18n("Cut\n\nCut the current selection out of the"
+ " icon.\n\n(Tip: You can make both rectangular and circular selections)"));
+
+ m_actCopy = KStdAction::copy(this, SLOT(slotCopy()), actionCollection());
+ m_actCopy->setWhatsThis(i18n("Copy\n\nCopy the current selection out of the"
+ " icon.\n\n(Tip: You can make both rectangular and circular selections)"));
+
+ m_actPaste = KStdAction::paste(this, SLOT(slotPaste()), actionCollection());
+ m_actPaste->setWhatsThis(i18n("Paste\n\n"
+ "Paste the contents of the clipboard into the current icon.\n\n"
+ "If the contents are larger than the current icon you can paste them"
+ " in a new window.\n\n"
+ "(Tip: Select \"Paste transparent pixels\" in the configuration dialog"
+ " if you also want to paste transparency.)"));
+
+ m_actPasteNew = new KAction( i18n( "Paste as &New" ), cut, grid,
+ SLOT( editPasteAsNew() ), actionCollection(), "edit_paste_as_new" );
+
+ KStdAction::clear(this, SLOT(slotClear()), actionCollection());
+ KStdAction::selectAll(this, SLOT(slotSelectAll()), actionCollection());
+
+ action = new KAction(i18n("Resi&ze..."), "transform", cut,
+ grid, SLOT(editResize()), actionCollection(), "edit_resize");
+ action->setWhatsThis(i18n("Resize\n\nSmoothly resizes the icon while"
+ " trying to preserve the contents"));
+
+ action = new KAction(i18n("&GrayScale"), "grayscale", cut,
+ grid, SLOT(grayScale()), actionCollection(), "edit_grayscale");
+ action->setWhatsThis(i18n("Gray scale\n\nGray scale the current icon.\n"
+ "(Warning: The result is likely to contain colors not in the icon"
+ " palette"));
+
+ // View Menu
+ m_actZoomIn = KStdAction::zoomIn(this, SLOT(slotZoomIn()),
+ actionCollection());
+ m_actZoomIn->setWhatsThis(i18n("Zoom in\n\nZoom in by one."));
+
+ m_actZoomOut = KStdAction::zoomOut(this, SLOT(slotZoomOut()),
+ actionCollection());
+ m_actZoomOut->setWhatsThis(i18n("Zoom out\n\nZoom out by one."));
+
+ KActionMenu *actMenu = new KActionMenu( i18n( "&Zoom" ), "viewmag",
+ actionCollection(), "view_zoom" );
+
+ // xgettext:no-c-format
+ action = new KAction( i18n( "100%" ), cut, this, SLOT( slotZoom1() ),
+ actionCollection(), "view_zoom_1" );
+ actMenu->insert( action );
+ // xgettext:no-c-format
+ action = new KAction( i18n( "200%" ), cut, this, SLOT( slotZoom2() ),
+ actionCollection(), "view_zoom_2" );
+ actMenu->insert( action );
+ // xgettext:no-c-format
+ action = new KAction( i18n( "500%" ), cut, this, SLOT( slotZoom5() ),
+ actionCollection(), "view_zoom_5" );
+ actMenu->insert( action );
+ // xgettext:no-c-format
+ action = new KAction( i18n( "1000%" ), cut, this, SLOT( slotZoom10() ),
+ actionCollection(), "view_zoom_10" );
+ actMenu->insert( action );
+
+ // Settings Menu
+ KStdAction::keyBindings(this, SLOT(slotConfigureKeys()),
+ actionCollection());
+ KStdAction::preferences(this, SLOT(slotConfigureSettings()),
+ actionCollection());
+
+ createStandardStatusBarAction();
+
+ KToggleAction *toggle;
+
+ toggle = new KToggleAction( i18n( "Show &Grid" ), "grid",
+ cut, this, SLOT( slotShowGrid() ), actionCollection(),
+ "options_show_grid" );
+ toggle->setCheckedState(i18n("Hide &Grid"));
+ toggle->setWhatsThis( i18n( "Show grid\n\nToggles the grid in the icon"
+ " edit grid on/off" ) );
+ toggle->setChecked( KIconEditProperties::self()->showGrid() );
+
+ // Tools Menu
+ toolAction = new KRadioAction(i18n("Color Picker"), "colorpicker",
+ cut, this, SLOT(slotToolPointer()), actionCollection(),
+ "tool_find_pixel");
+ toolAction->setExclusiveGroup("toolActions");
+ toolAction->setWhatsThis(i18n("Color Picker\n\nThe color of the pixel clicked"
+ " on will be the current draw color"));
+
+ toolAction = new KRadioAction(i18n("Freehand"), "paintbrush",
+ cut, this, SLOT(slotToolFreehand()), actionCollection(),
+ "tool_freehand");
+ toolAction->setExclusiveGroup("toolActions");
+ toolAction->setWhatsThis(i18n("Free hand\n\nDraw non-linear lines"));
+
+ toolAction->setChecked( true );
+ grid->setTool(KIconEditGrid::Freehand);
+
+ toolAction = new KRadioAction(i18n("Rectangle"), "rectangle",
+ cut, this, SLOT(slotToolRectangle()), actionCollection(),
+ "tool_rectangle");
+ toolAction->setExclusiveGroup("toolActions");
+ toolAction->setWhatsThis(i18n("Rectangle\n\nDraw a rectangle"));
+
+ toolAction = new KRadioAction(i18n("Filled Rectangle"), "filledrectangle",
+ cut, this, SLOT(slotToolFilledRectangle()), actionCollection(),
+ "tool_filled_rectangle");
+ toolAction->setExclusiveGroup("toolActions");
+ toolAction->setWhatsThis(i18n("Filled rectangle\n\nDraw a filled rectangle"));
+
+ toolAction = new KRadioAction(i18n("Circle"), "circle",
+ cut, this, SLOT(slotToolCircle()), actionCollection(),
+ "tool_circle");
+ toolAction->setExclusiveGroup("toolActions");
+ toolAction->setWhatsThis(i18n("Circle\n\nDraw a circle"));
+
+ toolAction = new KRadioAction(i18n("Filled Circle"), "filledcircle",
+ cut, this, SLOT(slotToolFilledCircle()), actionCollection(),
+ "tool_filled_circle");
+ toolAction->setExclusiveGroup("toolActions");
+ toolAction->setWhatsThis(i18n("Filled circle\n\nDraw a filled circle"));
+
+ toolAction = new KRadioAction(i18n("Ellipse"), "ellipse",
+ cut, this, SLOT(slotToolEllipse()), actionCollection(),
+ "tool_ellipse");
+ toolAction->setExclusiveGroup("toolActions");
+ toolAction->setWhatsThis(i18n("Ellipse\n\nDraw an ellipse"));
+
+ toolAction = new KRadioAction(i18n("Filled Ellipse"), "filledellipse",
+ cut, this, SLOT(slotToolFilledEllipse()), actionCollection(),
+ "tool_filled_ellipse");
+ toolAction->setExclusiveGroup("toolActions");
+ toolAction->setWhatsThis(i18n("Filled ellipse\n\nDraw a filled ellipse"));
+
+ toolAction = new KRadioAction(i18n("Spray"), "airbrush",
+ cut, this, SLOT(slotToolSpray()), actionCollection(),
+ "tool_spray");
+ toolAction->setExclusiveGroup("toolActions");
+ toolAction->setWhatsThis(i18n("Spray\n\nDraw scattered pixels in the"
+ " current color"));
+
+ toolAction = new KRadioAction(i18n("Flood Fill"), "fill",
+ cut, this, SLOT(slotToolFlood()), actionCollection(),
+ "tool_flood_fill");
+ toolAction->setExclusiveGroup("toolActions");
+ toolAction->setWhatsThis(i18n("Flood fill\n\nFill adjoining pixels with"
+ " the same color with the current color"));
+
+ toolAction = new KRadioAction(i18n("Line"), "line",
+ cut, this, SLOT(slotToolLine()), actionCollection(),
+ "tool_line");
+ toolAction->setExclusiveGroup("toolActions");
+ toolAction->setWhatsThis(i18n("Line\n\nDraw a straight line vertically,"
+ " horizontally or at 45 deg. angles"));
+
+ toolAction = new KRadioAction(i18n("Eraser (Transparent)"), "eraser",
+ cut, this, SLOT(slotToolEraser()), actionCollection(),
+ "tool_eraser");
+ toolAction->setExclusiveGroup("toolActions");
+ toolAction->setWhatsThis(i18n("Erase\n\nErase pixels. Set the pixels to"
+ " be transparent\n\n(Tip: If you want to draw transparency with a"
+ " different tool, first click on \"Erase\" then on the tool you want"
+ " to use)"));
+
+ toolAction = new KRadioAction(i18n("Rectangular Selection"),
+ "selectrect", cut, this, SLOT(slotToolSelectRect()),
+ actionCollection(), "edit_select_rectangle");
+ toolAction->setExclusiveGroup( "toolActions" );
+ toolAction->setWhatsThis(i18n("Select\n\nSelect a rectangular section"
+ " of the icon using the mouse."));
+
+ toolAction = new KRadioAction(i18n("Circular Selection"),
+ "selectcircle", cut, this, SLOT(slotToolSelectCircle()),
+ actionCollection(), "edit_select_circle");
+ toolAction->setExclusiveGroup( "toolActions" );
+ toolAction->setWhatsThis(i18n("Select\n\nSelect a circular section of the"
+ " icon using the mouse."));
+}
+
+void KIconEdit::updateAccels()
+{
+ actionCollection()->readShortcutSettings();
+}
+
+QWidget *KIconEdit::createContainer( QWidget *parent, int index,
+ const QDomElement &element, int &id )
+{
+ if ( element.attribute( "name" ) == "paletteToolBar" )
+ {
+ m_paletteToolBar = new PaletteToolBar( this, "paletteToolBar" );
+ m_paletteToolBar->setText( i18n( "Palette Toolbar" ) );
+ return m_paletteToolBar;
+ }
+
+ return KXMLGUIBuilder::createContainer( parent, index, element, id );
+}
+
+bool KIconEdit::setupStatusBar()
+{
+ statusbar = statusBar();
+
+ QString str = i18n("Statusbar\n\nThe statusbar gives information on"
+ " the status of the current icon. The fields are:\n\n"
+ "\t- Application messages\n\t- Cursor position\n\t- Size\n\t- Zoom factor\n"
+ "\t- Number of colors");
+ QWhatsThis::add(statusBar(), str);
+
+ statusbar->insertFixedItem("99999,99999", 0, true);
+ statusbar->insertFixedItem("99999 x 99999", 1, true);
+ statusbar->insertFixedItem(" 1:999", 2, true);
+ str = i18n("Colors: %1").arg(9999999);
+ statusbar->insertFixedItem(str, 3, true);
+ statusbar->insertItem("", 4);
+
+ statusbar->changeItem( "", 0);
+ statusbar->changeItem( "", 1);
+ statusbar->changeItem( "", 2);
+ statusbar->changeItem( "", 3);
+
+ return true;
+}
+
+void KIconEdit::addRecent(const QString & path)
+{
+ m_actRecent->addURL(KURL( path ));
+}
+
+#include "kiconedit.moc"
diff --git a/kiconedit/kiconedit.desktop b/kiconedit/kiconedit.desktop
new file mode 100644
index 00000000..be70ac9f
--- /dev/null
+++ b/kiconedit/kiconedit.desktop
@@ -0,0 +1,95 @@
+[Desktop Entry]
+GenericName=Icon Editor
+GenericName[af]=Ikoon Redigeerder
+GenericName[ar]=محرر الإيقونات
+GenericName[bg]=Редактор на икони
+GenericName[br]=Aozer arlunioù
+GenericName[bs]=Editor ikona
+GenericName[ca]=Editor d'icones
+GenericName[cs]=Editor ikon
+GenericName[cy]=Golygydd Eiconau
+GenericName[da]=Ikoneditor
+GenericName[de]=Editor für Arbeitsflächensymbole
+GenericName[el]=Επεξεργαστής εικονιδίων
+GenericName[eo]=Ilo por pentri kaj redakti piktogramojn
+GenericName[es]=Editor de iconos
+GenericName[et]=Ikoonide redaktor
+GenericName[eu]=Ikono editorea
+GenericName[fa]=ویرایشگر شمایل
+GenericName[fi]=Kuvakemuokkain
+GenericName[fr]=Éditeur d'icônes
+GenericName[ga]=Eagarthóir Deilbhíní
+GenericName[gl]=Editor de iconas
+GenericName[he]=עורך סמלים
+GenericName[hi]=प्रतीक (आइकॉन) संपादक
+GenericName[hr]=Uređivač ikona
+GenericName[hu]=Ikonszerkesztő
+GenericName[is]=Táknmyndaritill
+GenericName[it]=Editor di icone
+GenericName[ja]=アイコンエディタ
+GenericName[kk]=Таңбаша өңдегіші
+GenericName[km]=កម្មវិធី​និពន្ធ​រូបតំណាង
+GenericName[lt]=Ženkliukų redaktorius
+GenericName[lv]=Ikonu Redaktors
+GenericName[ms]=Editor Ikon
+GenericName[nb]=Ikonredigerer
+GenericName[nds]=Lüttbildeditor
+GenericName[ne]=प्रतिमा सम्पादक
+GenericName[nl]=Pictogrambewerker
+GenericName[nn]=Ikonredigering
+GenericName[nso]=Mofetosi wa Seemedi
+GenericName[pa]=ਆਈਕਾਨ ਸੰਪਾਦਕ
+GenericName[pl]=Edytor ikon
+GenericName[pt]=Editor de Ícones
+GenericName[pt_BR]=Editor de Ícones
+GenericName[ro]=Editor de iconiţe
+GenericName[ru]=Редактор пиктограмм
+GenericName[se]=Govašdoaimmaheaddji
+GenericName[sk]=Editor ikon
+GenericName[sl]=Urejevalnik ikon
+GenericName[sr]=Уређивач икона
+GenericName[sr@Latn]=Uređivač ikona
+GenericName[sv]=Ikoneditor
+GenericName[ta]= கேசின்னம் திருத்தி
+GenericName[tg]=Муҳаррири ишорот
+GenericName[th]=เครื่องมือแก้ไขไอคอน
+GenericName[tr]=Simge Düzenleyici
+GenericName[uk]=Редактор піктограм
+GenericName[uz]=Nishoncha tahrirchi
+GenericName[uz@cyrillic]=Нишонча таҳрирчи
+GenericName[ven]=Musengulusi wa Aikhono
+GenericName[wa]=Aspougneu d' imådjetes
+GenericName[xh]=Umhleli we Icon
+GenericName[zh_CN]=图标编辑器
+GenericName[zh_HK]=圖示編輯器
+GenericName[zh_TW]=圖示編輯器
+GenericName[zu]=Umhleli we Icon
+Name=KIconEdit
+Name[af]=K-ikoon-redigeer
+Name[ar]=برنامج KIconEdit
+Name[cy]=KGolyguEicon
+Name[eo]=Piktogramredaktilo
+Name[hi]=के-आइकॉन-एडिट
+Name[hr]=Uređivač ikona
+Name[is]=Táknmyndaritill
+Name[lv]=KIkonuRedaktors
+Name[ms]=KIkonEdit
+Name[ne]=केडीई प्रतिमा सम्पादन
+Name[pl]=Edytor ikon
+Name[pt_BR]=KEditor de Ícones
+Name[ro]=Editor iconiţe
+Name[sv]=Kiconedit
+Name[ta]=கேசின்னம் திருத்து
+Name[tr]=K Icon Düzenleyici
+Name[ven]=U sengulusa ha aikhono ya K
+Name[zh_TW]=KIconEdit 圖示編輯器
+MimeType=image/x-xpm;image/x-ico;image/png;image/jpeg;
+Exec=kiconedit -caption "%c" %i %m %u
+Icon=kiconedit
+Path=
+DocPath=kiconedit/index.html
+Type=Application
+Terminal=false
+
+X-DCOP-ServiceType=Multi
+Categories=Qt;KDE;Graphics;X-KDE-More;
diff --git a/kiconedit/kiconedit.h b/kiconedit/kiconedit.h
new file mode 100644
index 00000000..54227206
--- /dev/null
+++ b/kiconedit/kiconedit.h
@@ -0,0 +1,157 @@
+/*
+ kiconedit - a small graphics drawing program for creating KDE icons
+ Copyright (C) 1998 Thomas Tanghus (tanghus@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 Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __KICONEDIT_H__
+#define __KICONEDIT_H__
+
+#include <qwidget.h>
+#include <qpixmap.h>
+#include <qptrlist.h>
+
+#include <kmainwindow.h>
+#include <kiconloader.h>
+#include <kmenubar.h>
+#include <kstatusbar.h>
+#include <ktoolbar.h>
+#include <kaccel.h>
+#include <kurl.h>
+#include <kaction.h>
+
+#include "knew.h"
+#include "kicon.h"
+#include "kiconconfig.h"
+#include "kicongrid.h"
+#include "kresize.h"
+#include "properties.h"
+
+class KIconEdit;
+class KCommandHistory;
+typedef QPtrList<KIconEdit> WindowList;
+
+class QWhatsThis;
+class QToolButton;
+class QLabel;
+class PaletteToolBar;
+
+/**
+* KIconEdit
+* @short KIconEdit
+* @author Thomas Tanghus <tanghus@kde.org>
+* @version 0.4
+*/
+class KIconEdit : public KMainWindow
+{
+ Q_OBJECT
+public:
+ KIconEdit( KURL url = KURL(), const char *name = "kiconedit");
+ KIconEdit( const QImage image, const char *name = "kiconedit");
+ ~KIconEdit();
+
+ virtual QSize sizeHint() const;
+ static WindowList windowList;
+
+signals:
+ void newname(const QString &);
+
+public slots:
+ virtual void saveProperties(KConfig*);
+ virtual void readProperties(KConfig*);
+ void updateProperties();
+
+protected slots:
+ void slotNewWin(const QString & url = 0);
+ void slotNew();
+ void slotOpen();
+ void slotClose();
+ void slotSave();
+ void slotSaveAs();
+ void slotPrint();
+ void slotZoomIn();
+ void slotZoomOut();
+ void slotZoom1();
+ void slotZoom2();
+ void slotZoom5();
+ void slotZoom10();
+ void slotCopy();
+ void slotCut();
+ void slotPaste();
+ void slotClear();
+ void slotSaved();
+ void slotSelectAll();
+ void slotOpenRecent(const KURL&);
+ void slotToolPointer();
+ void slotToolFreehand();
+ void slotToolRectangle();
+ void slotToolFilledRectangle();
+ void slotToolCircle();
+ void slotToolFilledCircle();
+ void slotToolEllipse();
+ void slotToolFilledEllipse();
+ void slotToolSpray();
+ void slotToolFlood();
+ void slotToolLine();
+ void slotToolEraser();
+ void slotToolSelectRect();
+ void slotToolSelectCircle();
+ void slotConfigureSettings();
+ void slotConfigureKeys();
+ void slotShowGrid();
+ void slotUpdateZoom( int );
+ void slotUpdateStatusColors(uint);
+ void slotUpdateStatusColors(uint, uint*);
+ void slotUpdateStatusPos(int, int);
+ void slotUpdateStatusSize(int, int);
+ void slotUpdateStatusMessage(const QString &);
+ void slotUpdateStatusName(const QString &);
+ void slotUpdateStatusModified(bool);
+ void slotUpdateStatusScaling(int);
+ void slotUpdatePaste(bool);
+ void slotUpdateCopy(bool);
+ void slotOpenBlank(const QSize);
+ void addRecent(const QString &);
+
+ virtual void dragEnterEvent(QDragEnterEvent* event);
+ virtual void dropEvent(QDropEvent *e);
+
+protected:
+ void init();
+ void setupActions();
+ bool setupStatusBar();
+ void writeConfig();
+ void updateAccels();
+
+ virtual bool queryClose();
+ virtual QWidget *createContainer( QWidget*, int, const QDomElement&, int& );
+
+ KCommandHistory* history;
+ PaletteToolBar *m_paletteToolBar;
+ KStatusBar *statusbar;
+ KIconEditGrid *grid;
+ KGridView *gridview;
+ KIconEditIcon *icon;
+ QImage img;
+ QString m_name;
+
+ KAction *m_actCopy, *m_actPaste, *m_actCut, *m_actPasteNew;
+ KAction *m_actZoomIn, *m_actZoomOut;
+ KRecentFilesAction *m_actRecent;
+};
+
+#endif //__KICONEDIT_H__
diff --git a/kiconedit/kiconeditslots.cpp b/kiconedit/kiconeditslots.cpp
new file mode 100644
index 00000000..0d57d28e
--- /dev/null
+++ b/kiconedit/kiconeditslots.cpp
@@ -0,0 +1,543 @@
+/*
+ KDE Icon Editor - a small graphics drawing program for the KDE
+ Copyright (C) 1998 Thomas Tanghus (tanghus@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 Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qpaintdevicemetrics.h>
+#include <qpainter.h>
+
+#include <kkeydialog.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <kprinter.h>
+#include <kurldrag.h>
+
+#include "kiconedit.h"
+#include "kiconcolors.h"
+#include "palettetoolbar.h"
+
+#ifndef PICS_INCLUDED
+#define PICS_INCLUDED
+#include "pics/logo.xpm"
+#endif
+
+void KIconEdit::updateProperties()
+{
+ KIconEditProperties *props = KIconEditProperties::self();
+ gridview->setShowRulers(props->showRulers());
+ if(props->bgMode() == QWidget::FixedPixmap)
+ {
+ QPixmap pix(props->bgPixmap());
+ if(pix.isNull())
+ {
+ QPixmap pmlogo((const char**)logo);
+ pix = pmlogo;
+ }
+ gridview->viewPortWidget()->viewport()->setBackgroundPixmap(pix);
+ m_paletteToolBar->setPreviewBackground(pix);
+ }
+ else
+ {
+ gridview->viewPortWidget()->viewport()
+ ->setBackgroundColor(props->bgColor());
+ m_paletteToolBar->setPreviewBackground(props->bgColor());
+ }
+ grid->setTransparencyDisplayType(props->transparencyDisplayType());
+ grid->setTransparencySolidColor(props->transparencySolidColor());
+ grid->setCheckerboardColor1(props->checkerboardColor1());
+ grid->setCheckerboardColor2(props->checkerboardColor2());
+ grid->setCheckerboardSize(props->checkerboardSize());
+ grid->update();
+}
+
+void KIconEdit::slotNewWin(const QString & url)
+{
+ //kdDebug(4640) << "KIconEdit::openNewWin() - " << url << endl;
+
+ KIconEdit *w = new KIconEdit(KURL(url), "kiconedit");
+ Q_CHECK_PTR(w);
+}
+
+
+void KIconEdit::slotNew()
+{
+ bool cancel = false;
+ if (grid->isModified())
+ {
+ int r = KMessageBox::warningYesNoCancel(this,
+ i18n("The current file has been modified.\nDo you want to save it?"), QString::null, KStdGuiItem::save(), KStdGuiItem::discard());
+
+ switch(r)
+ {
+ case KMessageBox::Yes:
+ if(!icon->save(&grid->image()))
+ {
+ cancel = true;
+ }
+ break;
+
+ case KMessageBox::No:
+ break;
+
+ case KMessageBox::Cancel:
+ cancel = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ if(!cancel)
+ {
+ KNewIcon newicon(this);
+ if(newicon.exec())
+ {
+ int r = newicon.openStyle();
+ if(r == KNewIcon::Blank)
+ {
+ grid->editClear();
+ const QSize s = newicon.templateSize();
+ //kdDebug(4640) << "Size: " << s.width() << " x " << s.height() << endl;
+ grid->setSize(s);
+ grid->setModified(false);
+ }
+ else if(r == KNewIcon::Template)
+ {
+ QString str = newicon.templatePath();
+ icon->open(&grid->image(), KURL( str ));
+ }
+ icon->setUrl("");
+ emit newname(i18n("Untitled"));
+ }
+ }
+}
+
+
+void KIconEdit::slotOpen()
+{
+ bool cancel = false;
+
+ if( grid->isModified() )
+ {
+ int r = KMessageBox::warningYesNoCancel(this,
+ i18n("The current file has been modified.\nDo you want to save it?"),QString::null, KStdGuiItem::save(), KStdGuiItem::discard());
+
+ switch( r )
+ {
+ case KMessageBox::Yes:
+ if(!icon->save( &grid->image() ))
+ {
+ cancel = true;
+ }
+ break;
+
+ case KMessageBox::No:
+ break;
+
+ case KMessageBox::Cancel:
+ cancel = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if( !cancel )
+ {
+ if (icon->promptForFile( &grid->image() ))
+ {
+ grid->setModified(false);
+ }
+ }
+}
+
+/*
+ close only the current window
+*/
+void KIconEdit::slotClose()
+{
+ //kdDebug(4640) << "KIconEdit: Closing " << endl;
+ close();
+}
+
+void KIconEdit::slotSave()
+{
+ //kdDebug(4640) << "KIconEdit: slotSave() " << endl;
+ icon->save(&grid->image());
+}
+
+
+void KIconEdit::slotSaveAs()
+{
+ //kdDebug(4640) << "KIconEdit: slotSaveAs() " << endl;
+ icon->saveAs(&grid->image());
+}
+
+
+void KIconEdit::slotPrint()
+{
+ KPrinter printer;
+
+ if ( printer.setup(this, i18n("Print %1").arg(icon->url().section('/', -1))) )
+ {
+ int margin = 10, yPos = 0;
+ printer.setCreator("KDE Icon Editor");
+
+ QPainter p;
+ p.begin( &printer );
+ QFontMetrics fm = p.fontMetrics();
+ // need width/height
+ QPaintDeviceMetrics metrics( &printer );
+
+ p.drawText( margin, margin + yPos, metrics.width(), fm.lineSpacing(),
+ ExpandTabs | DontClip, icon->url() );
+ yPos = yPos + fm.lineSpacing();
+ p.drawPixmap( margin, margin + yPos, grid->pixmap() );
+ p.end();
+ }
+}
+
+void KIconEdit::slotZoomIn()
+{
+ grid->zoom(DirIn);
+}
+
+void KIconEdit::slotZoomOut()
+{
+ grid->zoom(DirOut);
+}
+
+void KIconEdit::slotZoom1()
+{
+ grid->zoomTo(1);
+}
+
+void KIconEdit::slotZoom2()
+{
+ grid->zoomTo(2);
+}
+
+void KIconEdit::slotZoom5()
+{
+ grid->zoomTo(5);
+}
+
+void KIconEdit::slotZoom10()
+{
+ grid->zoomTo(10);
+}
+
+void KIconEdit::slotCopy()
+{
+ grid->editCopy();
+}
+
+void KIconEdit::slotCut()
+{
+ grid->editCopy(true);
+}
+
+void KIconEdit::slotPaste()
+{
+ static_cast<KRadioAction*>(actionCollection()
+ ->action("tool_find_pixel"))->setChecked(true);
+ grid->setTool(KIconEditGrid::Find);
+ grid->editPaste();
+}
+
+void KIconEdit::slotClear()
+{
+ grid->editClear();
+}
+
+void KIconEdit::slotSelectAll()
+{
+ grid->setTool(KIconEditGrid::SelectRect);
+ grid->editSelectAll();
+}
+
+void KIconEdit::slotOpenRecent(const KURL& iconFile)
+{
+ bool cancel = false;
+
+ if( grid->isModified() )
+ {
+ int r = KMessageBox::warningYesNoCancel(this,
+ i18n("The current file has been modified.\nDo you want to save it?"),QString::null, KStdGuiItem::save(), KStdGuiItem::discard());
+
+ switch( r )
+ {
+ case KMessageBox::Yes:
+ if (!icon->save( &grid->image() ))
+ {
+ cancel = true;
+ }
+ break;
+
+ case KMessageBox::No:
+ break;
+
+ case KMessageBox::Cancel:
+ cancel = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if( !cancel )
+ {
+ if(icon->open(&grid->image(), iconFile))
+ {
+ grid->setModified(false);
+ }
+ }
+}
+
+void KIconEdit::slotConfigureSettings()
+{
+ KIconConfig* c = new KIconConfig(this);
+ c->exec();
+ delete c;
+}
+
+void KIconEdit::slotConfigureKeys()
+{
+ KKeyDialog::configure(actionCollection());
+
+ KIconEdit *ki = 0L;
+ for (ki = windowList.first(); ki; ki = windowList.next())
+ {
+ if (ki != this)
+ {
+ ki->updateAccels();
+ }
+ }
+}
+
+void KIconEdit::slotShowGrid()
+{
+ bool b = KIconEditProperties::self()->showGrid();
+ grid->setGrid( !b );
+ KIconEditProperties::self()->setShowGrid( !b );
+}
+
+void KIconEdit::slotToolPointer()
+{
+ grid->setTool(KIconEditGrid::Find);
+}
+
+void KIconEdit::slotToolFreehand()
+{
+ grid->setTool(KIconEditGrid::Freehand);
+}
+
+void KIconEdit::slotToolRectangle()
+{
+ grid->setTool(KIconEditGrid::Rect);
+}
+
+void KIconEdit::slotToolFilledRectangle()
+{
+ grid->setTool(KIconEditGrid::FilledRect);
+}
+
+void KIconEdit::slotToolCircle()
+{
+ grid->setTool(KIconEditGrid::Circle);
+}
+
+void KIconEdit::slotToolFilledCircle()
+{
+ grid->setTool(KIconEditGrid::FilledCircle);
+}
+
+void KIconEdit::slotToolEllipse()
+{
+ grid->setTool(KIconEditGrid::Ellipse);
+}
+
+void KIconEdit::slotToolFilledEllipse()
+{
+ grid->setTool(KIconEditGrid::FilledEllipse);
+}
+
+void KIconEdit::slotToolSpray()
+{
+ grid->setTool(KIconEditGrid::Spray);
+}
+
+void KIconEdit::slotToolFlood()
+{
+ grid->setTool(KIconEditGrid::FloodFill);
+}
+
+void KIconEdit::slotToolLine()
+{
+ grid->setTool(KIconEditGrid::Line);
+}
+
+void KIconEdit::slotToolEraser()
+{
+ grid->setTool(KIconEditGrid::Eraser);
+}
+
+void KIconEdit::slotToolSelectRect()
+{
+ grid->setTool(KIconEditGrid::SelectRect);
+}
+
+void KIconEdit::slotToolSelectCircle()
+{
+ grid->setTool(KIconEditGrid::SelectCircle);
+}
+
+void KIconEdit::slotSaved()
+{
+ grid->setModified(false);
+}
+
+void KIconEdit::slotUpdateZoom( int s )
+{
+ m_actZoomOut->setEnabled( s>1 );
+}
+
+void KIconEdit::slotUpdateStatusPos(int x, int y)
+{
+ QString str = i18n("Status Position", "%1, %2").arg(x).arg(y);
+ statusbar->changeItem( str, 0);
+}
+
+void KIconEdit::slotUpdateStatusSize(int x, int y)
+{
+ QString str = i18n("Status Size", "%1 x %2").arg(x).arg(y);
+ statusbar->changeItem( str, 1);
+}
+
+void KIconEdit::slotUpdateStatusScaling(int s)
+{
+ KIconEditProperties::self()->setGridScale( s );
+ QString str;
+
+ str.sprintf("1:%d", s);
+ statusbar->changeItem( str, 2);
+}
+
+void KIconEdit::slotUpdateStatusColors(uint)
+{
+ QString str = i18n("Colors: %1").arg(grid->numColors());
+ statusbar->changeItem( str, 3);
+}
+
+void KIconEdit::slotUpdateStatusColors(uint n, uint *)
+{
+ QString str = i18n("Colors: %1").arg(n);
+ statusbar->changeItem( str, 3);
+}
+
+
+void KIconEdit::slotUpdateStatusMessage(const QString & msg)
+{
+ statusbar->changeItem( msg, 4);
+}
+
+
+void KIconEdit::slotUpdateStatusName(const QString & name)
+{
+ m_name = name;
+
+ QString text = m_name;
+
+ if(grid->isModified())
+ {
+ text += " ["+i18n("modified")+"]";
+ }
+
+ setCaption(text);
+}
+
+
+void KIconEdit::slotUpdateStatusModified(bool)
+{
+ slotUpdateStatusName(m_name);
+}
+
+void KIconEdit::slotUpdatePaste(bool state)
+{
+ m_actPaste->setEnabled(state);
+ m_actPasteNew->setEnabled(state);
+}
+
+
+void KIconEdit::slotUpdateCopy(bool state)
+{
+ m_actCopy->setEnabled(state);
+ m_actCut->setEnabled(state);
+}
+
+
+void KIconEdit::slotOpenBlank(const QSize s)
+{
+ grid->loadBlank( s.width(), s.height());
+}
+
+
+void KIconEdit::dragEnterEvent(QDragEnterEvent* e)
+{
+ e->accept(KURLDrag::canDecode(e));
+}
+
+
+/*
+ accept drop of a file - opens file in current window
+ old code to drop image, as image, should be removed
+*/
+void KIconEdit::dropEvent( QDropEvent *e )
+{
+ //kdDebug(4640) << "Got QDropEvent!" << endl;
+
+ KURL::List fileList;
+ bool loadedinthis = false;
+
+ if(KURLDrag::decode(e, fileList))
+ {
+ for(KURL::List::ConstIterator it = fileList.begin();
+ it != fileList.end(); ++it)
+ {
+ //kdDebug(4640) << "In dropEvent for " << (*it).prettyURL() << endl;
+ const KURL &url = *it;
+ if(url.isValid())
+ {
+ if (!grid->isModified() && !loadedinthis)
+ {
+ icon->open(&grid->image(), url);
+ loadedinthis = true;
+ }
+ else
+ {
+ slotNewWin(url.url());
+ }
+ }
+ }
+ }
+}
+
+
diff --git a/kiconedit/kiconeditui.rc b/kiconedit/kiconeditui.rc
new file mode 100644
index 00000000..cdef162c
--- /dev/null
+++ b/kiconedit/kiconeditui.rc
@@ -0,0 +1,66 @@
+<!DOCTYPE kpartgui>
+<kpartgui version="2" name="kiconedit">
+<MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="file_new_window" append="new_merge"/>
+ </Menu>
+ <Menu name="edit"><text>&amp;Edit</text>
+ <Action name="edit_paste_as_new" append="edit_paste_merge"/>
+ <Separator/>
+ <Action name="edit_resize"/>
+ <Action name="edit_grayscale"/>
+ </Menu>
+ <Menu name="tools"><text>&amp;Tools</text>
+ <Action name="tool_freehand"/>
+ <Action name="tool_find_pixel"/>
+ <Action name="tool_rectangle"/>
+ <Action name="tool_filled_rectangle"/>
+ <Action name="tool_circle"/>
+ <Action name="tool_filled_circle"/>
+ <Action name="tool_ellipse"/>
+ <Action name="tool_filled_ellipse"/>
+ <Action name="tool_spray"/>
+ <Action name="tool_flood_fill"/>
+ <Action name="tool_line"/>
+ <Action name="tool_eraser"/>
+ <Separator/>
+ <Action name="edit_select_rectangle"/>
+ <Action name="edit_select_circle"/>
+ </Menu>
+ <Menu name="settings"><text>&amp;Settings</text>
+ <Action name="options_show_grid" append="show_merge"/>
+ </Menu>
+</MenuBar>
+<ToolBar name="mainToolBar" newline="true" fullwidth="true">
+ <text>Main Toolbar</text>
+ <Action name="view_zoom_in"/>
+ <Action name="view_zoom_out"/>
+ <Separator/>
+ <Action name="edit_resize"/>
+ <Action name="edit_grayscale"/>
+ <Separator/>
+ <Action name="options_show_grid"/>
+</ToolBar>
+<ToolBar name="toolsToolBar" position="left" noEdit="true">
+ <text>Tools Toolbar</text>
+ <Action name="tool_freehand"/>
+ <Action name="tool_find_pixel"/>
+ <Action name="tool_rectangle"/>
+ <Action name="tool_filled_rectangle"/>
+ <Action name="tool_circle"/>
+ <Action name="tool_filled_circle"/>
+ <Action name="tool_ellipse"/>
+ <Action name="tool_filled_ellipse"/>
+ <Action name="tool_spray"/>
+ <Action name="tool_flood_fill"/>
+ <Action name="tool_line"/>
+ <Action name="tool_eraser"/>
+ <Separator/>
+ <Action name="edit_select_rectangle"/>
+ <Action name="edit_select_circle"/>
+</ToolBar>
+<ToolBar name="paletteToolBar" position="right" noEdit="true">
+ <text>Pallette Toolbar</text>
+</ToolBar>
+</kpartgui>
+
diff --git a/kiconedit/kicongrid.cpp b/kiconedit/kicongrid.cpp
new file mode 100644
index 00000000..abfb848e
--- /dev/null
+++ b/kiconedit/kicongrid.cpp
@@ -0,0 +1,2263 @@
+/*
+ KDE Icon Editor - a small graphics drawing program for the KDE.
+ Copyright (C) 1998 Thomas Tanghus (tanghus@kde.org)
+
+ Includes portions of code from Qt,
+ Copyright (C) 1992-2000 Trolltech AS.
+
+ 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 Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <stdlib.h>
+
+#include <qpainter.h>
+#include <qwhatsthis.h>
+#include <qscrollview.h>
+#include <qbitmap.h>
+#include <qclipboard.h>
+#include <qdatetime.h>
+
+#include <kiconloader.h>
+#include <kruler.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+
+#include "kresize.h"
+#include "properties.h"
+#include "kicongrid.h"
+#include "kiconedit.h"
+#ifndef PICS_INCLUDED
+#include "pics/logo.xpm"
+#define PICS_INCLUDED
+#endif
+
+#include <X11/Xos.h>
+
+void DrawCommand::execute()
+{
+ oldcolor = *((uint*)image->scanLine(y) + x);
+ *((uint*)image->scanLine(y) + x) = newcolor;
+ int cell = y * grid->numCols() + x;
+ grid->setUndoColor( cell, newcolor, false );
+}
+
+void DrawCommand::unexecute()
+{
+ *((uint*)image->scanLine(y) + x) = oldcolor;
+ int cell = y * grid->numCols() + x;
+ grid->setUndoColor( cell, oldcolor, false );
+}
+
+void RepaintCommand::execute()
+{
+ grid->update( area);
+}
+
+KGridView::KGridView(QImage *image, KCommandHistory* history, QWidget *parent, const char *name)
+: QFrame(parent, name)
+{
+ _corner = 0L;
+ _hruler = _vruler = 0L;
+ _grid = 0L;
+
+ acceptdrop = false;
+
+ KIconEditProperties *props = KIconEditProperties::self();
+
+ viewport = new QScrollView(this);
+ Q_CHECK_PTR(viewport);
+
+ _grid = new KIconEditGrid(image, history, viewport->viewport());
+ Q_CHECK_PTR(_grid);
+ viewport->addChild(_grid);
+ _grid->setGrid(props->showGrid());
+ _grid->setCellSize(props->gridScale());
+
+ QString str = i18n( "Icon draw grid\n\nThe icon grid is the area where"
+ " you draw the icons.\nYou can zoom in and out using the magnifying"
+ " glasses on the toolbar.\n(Tip: Hold the magnify button down for a"
+ " few seconds to zoom to a predefined scale)" );
+ QWhatsThis::add( _grid, str );
+
+ if(props->bgMode() == FixedPixmap)
+ {
+ QPixmap pix(props->bgPixmap());
+ if(pix.isNull())
+ {
+ QPixmap pmlogo((const char **)logo);
+ pix = pmlogo;
+ }
+ viewport->viewport()->setBackgroundPixmap(pix);
+ _grid->setBackgroundPixmap(pix);
+ }
+ else
+ {
+ viewport->viewport()->setBackgroundColor(props->bgColor());
+ }
+
+ _corner = new QFrame(this);
+ _corner->setFrameStyle(QFrame::WinPanel | QFrame::Raised);
+
+ _hruler = new KRuler(Qt::Horizontal, this);
+ _hruler->setEndLabel(i18n("width"));
+ _hruler->setOffset( -2 );
+ _hruler->setRange(0, 1000);
+
+ _vruler = new KRuler(Qt::Vertical, this);
+ _vruler->setEndLabel(i18n("height"));
+ _vruler->setOffset( -2 );
+ _vruler->setRange(0, 1000);
+
+ str = i18n( "Rulers\n\nThis is a visual representation of the current"
+ " cursor position" );
+ QWhatsThis::add( _hruler, str );
+ QWhatsThis::add( _vruler, str );
+
+ connect(_grid, SIGNAL(scalingchanged(int)), SLOT(scalingChange(int)));
+ connect(_grid, SIGNAL(sizechanged(int, int)), SLOT(sizeChange(int, int)));
+ connect(_grid, SIGNAL(needPainting()), SLOT(paintGrid()));
+ connect( _grid, SIGNAL(xposchanged(int)), _hruler, SLOT(slotNewValue(int)) );
+ connect( _grid, SIGNAL(yposchanged(int)), _vruler, SLOT(slotNewValue(int)) );
+ connect(viewport, SIGNAL(contentsMoving(int, int)), SLOT(moving(int, int)));
+
+ setSizes();
+ QResizeEvent e(size(), size());
+ resizeEvent(&e);
+}
+
+void KGridView::paintGrid()
+{
+ _grid->update(viewRect());
+}
+
+void KGridView::setSizes()
+{
+ if(KIconEditProperties::self()->showRulers())
+ {
+ _hruler->setLittleMarkDistance(_grid->scaling());
+ _vruler->setLittleMarkDistance(_grid->scaling());
+
+ _hruler->setMediumMarkDistance(5);
+ _vruler->setMediumMarkDistance(5);
+
+ _hruler->setBigMarkDistance(10);
+ _vruler->setBigMarkDistance(10);
+
+ _hruler->setShowTinyMarks(true);
+ _hruler->setShowLittleMarks(false);
+ _hruler->setShowMediumMarks(true);
+ _hruler->setShowBigMarks(true);
+ _hruler->setShowEndMarks(true);
+
+ _vruler->setShowTinyMarks(true);
+ _vruler->setShowLittleMarks(false);
+ _vruler->setShowMediumMarks(true);
+ _vruler->setShowBigMarks(true);
+ _vruler->setShowEndMarks(true);
+
+ _hruler->setPixelPerMark(_grid->scaling());
+ _vruler->setPixelPerMark(_grid->scaling());
+
+ _hruler->setMaxValue(_grid->width()+20);
+ _vruler->setMaxValue(_grid->height()+20);
+
+ _hruler->show();
+ _vruler->show();
+
+ _corner->show();
+ //resize(_grid->width()+_vruler->width(), _grid->height()+_hruler->height());
+ }
+ else
+ {
+ _hruler->hide();
+ _vruler->hide();
+ _corner->hide();
+ //resize(_grid->size());
+ }
+}
+
+void KGridView::sizeChange(int, int)
+{
+ setSizes();
+}
+
+void KGridView::moving(int x, int y)
+{
+ _hruler->setOffset(abs(x));
+ _vruler->setOffset(abs(y));
+}
+
+void KGridView::scalingChange(int)
+{
+ setSizes();
+}
+
+void KGridView::setShowRulers(bool mode)
+{
+ KIconEditProperties::self()->setShowRulers( mode );
+ setSizes();
+ QResizeEvent e(size(), size());
+ resizeEvent(&e);
+}
+
+void KGridView::setAcceptDrop(bool a)
+{
+ if(a == acceptdrop) return;
+ acceptdrop = a;
+ paintDropSite();
+}
+
+void KGridView::checkClipboard()
+{
+ _grid->checkClipboard();
+}
+
+const QRect KGridView::viewRect()
+{
+ int x, y, cx, cy;
+ if(viewport->horizontalScrollBar()->isVisible())
+ {
+ x = viewport->contentsX();
+ cx = viewport->viewport()->width();
+ }
+ else
+ {
+ x = 0;
+ cx = viewport->contentsWidth();
+ }
+
+ if(viewport->verticalScrollBar()->isVisible())
+ {
+ y = viewport->contentsY();
+ cy = viewport->viewport()->height();
+ }
+ else
+ {
+ y = 0;
+ cy = viewport->contentsHeight();
+ }
+
+ return QRect(x, y, cx, cy);
+}
+
+void KGridView::paintDropSite()
+{
+ QPainter p;
+ p.begin( _grid );
+ p.setRasterOp (NotROP);
+ p.drawRect(viewRect());
+ p.end();
+}
+
+void KGridView::paintEvent(QPaintEvent *)
+{
+ if(acceptdrop)
+ paintDropSite();
+}
+
+
+void KGridView::resizeEvent(QResizeEvent*)
+{
+ kdDebug(4640) << "KGridView::resizeEvent" << endl;
+
+ setSizes();
+
+ if(KIconEditProperties::self()->showRulers())
+ {
+ _hruler->setGeometry(_vruler->width(), 0, width(), _hruler->height());
+ _vruler->setGeometry(0, _hruler->height(), _vruler->width(), height());
+
+ _corner->setGeometry(0, 0, _vruler->width(), _hruler->height());
+ viewport->setGeometry(_corner->width(), _corner->height(),
+ width()-_corner->width(), height()-_corner->height());
+ }
+ else
+ viewport->setGeometry(0, 0, width(), height());
+}
+
+
+KIconEditGrid::KIconEditGrid(QImage *image, KCommandHistory* h, QWidget *parent, const char *name)
+ : KColorGrid(parent, name, 1)
+{
+ img = image;
+ history = h;
+ selected = 0;
+ m_command = 0;
+
+ // the 42 normal kde colors - there can be an additional
+ // 18 custom colors in the custom colors palette
+ for(uint i = 0; i < 42; i++)
+ iconcolors.append(iconpalette[i]);
+
+ setupImageHandlers();
+ btndown = isselecting = ispasting = modified = false;
+
+ img->create(32, 32, 32);
+ img->setAlphaBuffer(true);
+ clearImage(img);
+
+ currentcolor = qRgb(0,0,0)|OPAQUE_MASK;
+ emit colorSelected(currentcolor);
+
+ setMouseTracking(true);
+
+ setNumRows(32);
+ setNumCols(32);
+ fill(TRANSPARENT);
+
+ connect( kapp->clipboard(), SIGNAL(dataChanged()), SLOT(checkClipboard()));
+ connect( h, SIGNAL(commandExecuted()), this, SLOT(updatePreviewPixmap() ));
+ createCursors();
+
+ KIconEditProperties *props = KIconEditProperties::self();
+
+ setTransparencyDisplayType(props->transparencyDisplayType());
+ setTransparencySolidColor(props->transparencySolidColor());
+ setCheckerboardColor1(props->checkerboardColor1());
+ setCheckerboardColor2(props->checkerboardColor2());
+ setCheckerboardSize(props->checkerboardSize());
+}
+
+KIconEditGrid::~KIconEditGrid()
+{
+ kdDebug(4640) << "KIconEditGrid - destructor: done" << endl;
+}
+
+void KIconEditGrid::paintEvent(QPaintEvent *e)
+{
+ const QRect cellsRect(0, 0, numCols() * cellSize(), numRows() * cellSize());
+ const QRect paintCellsRect = cellsRect.intersect(e->rect());
+
+ if(!paintCellsRect.isEmpty())
+ {
+ //QTime time;
+
+ //time.start();
+
+ QRgb *imageBuffer = new QRgb[paintCellsRect.width() * paintCellsRect.height()];
+ const int cellsize = cellSize();
+ const int firstCellPixelsRemaining = cellsize - paintCellsRect.left() % cellsize;
+
+ if(transparencyDisplayType() == TRD_SOLIDCOLOR)
+ {
+ const QRgb backgroundColor = transparencySolidColor().rgb();
+ const int backgroundRed = transparencySolidColor().red();
+ const int backgroundGreen = transparencySolidColor().green();
+ const int backgroundBlue = transparencySolidColor().blue();
+ const int firstCellX = paintCellsRect.left() / cellsize;
+
+ for(int y = paintCellsRect.top(); y <= paintCellsRect.bottom(); y++)
+ {
+ QRgb *dest = imageBuffer + (y - paintCellsRect.top()) * paintCellsRect.width();
+
+ if(y % cellsize == 0 || dest == imageBuffer)
+ {
+ // Paint the first scanline in each block of cellSize() identical lines.
+ // The remaineder can just be copied from this one.
+ const int cellY = y / cellsize;
+ QRgb *src = gridcolors.data() + cellY * numCols() + firstCellX;
+
+ QRgb sourcePixel = *src++;
+ int sourceAlpha = qAlpha(sourcePixel);
+
+ QRgb c;
+
+ if(sourceAlpha == 255)
+ {
+ c = sourcePixel;
+ }
+ else
+ if(sourceAlpha == 0)
+ {
+ c = backgroundColor;
+ }
+ else
+ {
+ const int sourceRed = qRed(sourcePixel);
+ const int sourceGreen = qGreen(sourcePixel);
+ const int sourceBlue = qBlue(sourcePixel);
+
+ int r = (sourceAlpha * (sourceRed - backgroundRed)) + 0x80;
+ r = backgroundRed + ((r + (r >> 8)) >> 8);
+
+ int g = (sourceAlpha * (sourceGreen - backgroundGreen)) + 0x80;
+ g = backgroundGreen + ((g + (g >> 8)) >> 8);
+
+ int b = (sourceAlpha * (sourceBlue - backgroundBlue)) + 0x80;
+ b = backgroundBlue + ((b + (b >> 8)) >> 8);
+
+ c = qRgb(r, g, b);
+ }
+
+ int cellPixelsRemaining = firstCellPixelsRemaining;
+
+ for(int x = paintCellsRect.left(); x <= paintCellsRect.right(); x++)
+ {
+ if(cellPixelsRemaining == 0)
+ {
+ cellPixelsRemaining = cellsize;
+
+ // Fetch the next source pixel
+ sourcePixel = *src++;
+ sourceAlpha = qAlpha(sourcePixel);
+
+ if(sourceAlpha == 255)
+ {
+ c = sourcePixel;
+ }
+ else
+ if(sourceAlpha == 0)
+ {
+ c = backgroundColor;
+ }
+ else
+ {
+ const int sourceRed = qRed(sourcePixel);
+ const int sourceGreen = qGreen(sourcePixel);
+ const int sourceBlue = qBlue(sourcePixel);
+
+ //int r = backgroundRed + (sourceAlpha * (sourceRed - backgroundRed)) / 255;
+ //int g = backgroundGreen + (sourceAlpha * (sourceGreen - backgroundGreen)) / 255;
+ //int b = backgroundBlue + (sourceAlpha * (sourceBlue - backgroundBlue)) / 255;
+
+ int r = (sourceAlpha * (sourceRed - backgroundRed)) + 0x80;
+ r = backgroundRed + ((r + (r >> 8)) >> 8);
+
+ int g = (sourceAlpha * (sourceGreen - backgroundGreen)) + 0x80;
+ g = backgroundGreen + ((g + (g >> 8)) >> 8);
+
+ int b = (sourceAlpha * (sourceBlue - backgroundBlue)) + 0x80;
+ b = backgroundBlue + ((b + (b >> 8)) >> 8);
+
+ c = qRgb(r, g, b);
+ }
+ }
+
+ cellPixelsRemaining--;
+
+ *dest++ = c;
+ }
+ }
+ else
+ {
+ // Copy the scanline above.
+ memcpy(dest, dest - paintCellsRect.width(), paintCellsRect.width() * sizeof(QRgb));
+ }
+ }
+ }
+ else
+ {
+ int squareSize;
+ const int fixedPointMultiplier = 4;
+
+ if(checkerboardSize() == CHK_SMALL)
+ {
+ squareSize = (cellSize() * fixedPointMultiplier) / 4;
+ }
+ else
+ if(checkerboardSize() == CHK_MEDIUM)
+ {
+ squareSize = (cellSize() * fixedPointMultiplier) / 2;
+ }
+ else
+ {
+ squareSize = (2 * cellSize() * fixedPointMultiplier) / 2;
+ }
+
+ QRgb *color1ScanLine = new QRgb[paintCellsRect.width()];
+ QRgb *color2ScanLine = new QRgb[paintCellsRect.width()];
+ QRgb *color1Buffer = color1ScanLine;
+ QRgb *color2Buffer = color2ScanLine;
+
+ for(int x = paintCellsRect.left(); x <= paintCellsRect.right(); x++)
+ {
+ if((((x * fixedPointMultiplier) / squareSize) & 1) == 0)
+ {
+ *color1Buffer++ = checkerboardColor1().rgb();
+ *color2Buffer++ = checkerboardColor2().rgb();
+ }
+ else
+ {
+ *color1Buffer++ = checkerboardColor2().rgb();
+ *color2Buffer++ = checkerboardColor1().rgb();
+ }
+ }
+
+ const int firstCellX = paintCellsRect.left() / cellsize;
+ const int firstCellPixelsRemaining = cellsize - paintCellsRect.left() % cellsize;
+ int lastCellY = -1;
+ int lastLineFirstSquareColour = 0;
+
+ for(int y = paintCellsRect.top(); y <= paintCellsRect.bottom(); y++)
+ {
+ QRgb *dest = imageBuffer + (y - paintCellsRect.top()) * paintCellsRect.width();
+ const int cellY = y / cellsize;
+
+ int firstSquareColour;
+ const QRgb *checkerboardSrc;
+
+ if((((y * fixedPointMultiplier) / squareSize) & 1) == 0)
+ {
+ firstSquareColour = 1;
+ checkerboardSrc = color1ScanLine;
+ }
+ else
+ {
+ firstSquareColour = 2;
+ checkerboardSrc = color2ScanLine;
+ }
+
+ if(cellY == lastCellY && firstSquareColour == lastLineFirstSquareColour)
+ {
+ // Copy the scanline above.
+ memcpy(dest, dest - paintCellsRect.width(), paintCellsRect.width() * sizeof(QRgb));
+ }
+ else
+ {
+ QRgb *src = gridcolors.data() + cellY * numCols() + firstCellX;
+
+ QRgb sourcePixel = *src++;
+ int sourceRed = qRed(sourcePixel);
+ int sourceGreen = qGreen(sourcePixel);
+ int sourceBlue = qBlue(sourcePixel);
+ int sourceAlpha = qAlpha(sourcePixel);
+
+ int cellPixelsRemaining = firstCellPixelsRemaining;
+
+ for(int x = paintCellsRect.left(); x <= paintCellsRect.right(); x++)
+ {
+ if(cellPixelsRemaining == 0)
+ {
+ cellPixelsRemaining = cellsize;
+
+ // Fetch the next source pixel
+ sourcePixel = *src++;
+ sourceRed = qRed(sourcePixel);
+ sourceGreen = qGreen(sourcePixel);
+ sourceBlue = qBlue(sourcePixel);
+ sourceAlpha = qAlpha(sourcePixel);
+ }
+
+ cellPixelsRemaining--;
+
+ QRgb c;
+
+ if(sourceAlpha == 255)
+ {
+ c = sourcePixel;
+ }
+ else
+ if(sourceAlpha == 0)
+ {
+ c = *checkerboardSrc;
+ }
+ else
+ {
+ const int backgroundColor = *checkerboardSrc;
+ const int backgroundRed = qRed(backgroundColor);
+ const int backgroundGreen = qGreen(backgroundColor);
+ const int backgroundBlue = qBlue(backgroundColor);
+
+ //int r = backgroundRed + (sourceAlpha * (sourceRed - backgroundRed)) / 255;
+ //int g = backgroundGreen + (sourceAlpha * (sourceGreen - backgroundGreen)) / 255;
+ //int b = backgroundBlue + (sourceAlpha * (sourceBlue - backgroundBlue)) / 255;
+
+ int r = (sourceAlpha * (sourceRed - backgroundRed)) + 0x80;
+ r = backgroundRed + ((r + (r >> 8)) >> 8);
+
+ int g = (sourceAlpha * (sourceGreen - backgroundGreen)) + 0x80;
+ g = backgroundGreen + ((g + (g >> 8)) >> 8);
+
+ int b = (sourceAlpha * (sourceBlue - backgroundBlue)) + 0x80;
+ b = backgroundBlue + ((b + (b >> 8)) >> 8);
+
+ c = qRgb(r, g, b);
+ }
+
+ *dest++ = c;
+ checkerboardSrc++;
+ }
+ }
+
+ lastCellY = cellY;
+ lastLineFirstSquareColour = firstSquareColour;
+ }
+
+ delete [] color1ScanLine;
+ delete [] color2ScanLine;
+ }
+
+ QImage image((uchar *)(imageBuffer), paintCellsRect.width(), paintCellsRect.height(), 32, 0, 0,
+#if X_BYTE_ORDER == X_LITTLE_ENDIAN
+ QImage::LittleEndian);
+#else
+ QImage::BigEndian);
+#endif
+ Q_ASSERT(!image.isNull());
+
+ QPixmap _pixmap;
+ _pixmap.convertFromImage(image);
+
+ QPainter p;
+ p.begin(&_pixmap);
+ paintForeground(&p, e);
+ p.end();
+
+ bitBlt(this, paintCellsRect.left(), paintCellsRect.top(), &_pixmap);
+
+ //kdDebug(4640) << "Image render elapsed: " << time.elapsed() << endl;
+
+ delete [] imageBuffer;
+ }
+}
+
+void KIconEditGrid::paintForeground(QPainter* p, QPaintEvent* e)
+{
+ QWMatrix matrix;
+
+ matrix.translate(-e->rect().x(), -e->rect().y());
+ p->setWorldMatrix( matrix );
+
+ QRect cellsRect(0, 0, numCols() * cellSize(), numRows() * cellSize());
+ QRect paintCellsRect = cellsRect.intersect(e->rect());
+
+ if(!paintCellsRect.isEmpty())
+ {
+ int firstColumn = paintCellsRect.left() / cellSize();
+ int lastColumn = paintCellsRect.right() / cellSize();
+
+ int firstRow = paintCellsRect.top() / cellSize();
+ int lastRow = paintCellsRect.bottom() / cellSize();
+
+ p->setPen(QColor(0, 0, 0));
+ p->setBrush(QColor(0, 0, 0));
+
+ for(int column = firstColumn; column <= lastColumn; column++)
+ {
+ for(int row = firstRow; row <= lastRow; row++)
+ {
+ int x = column * cellSize();
+ int y = row * cellSize();
+
+ if((ispasting || isselecting) && isMarked(column, row))
+ {
+ p->drawWinFocusRect(x + 1, y + 1, cellSize() - 2, cellSize() - 2);
+ }
+ else
+ {
+ switch( tool )
+ {
+ case FilledRect:
+ case Rect:
+ case Ellipse:
+ case Circle:
+ case FilledEllipse:
+ case FilledCircle:
+ case Line:
+ if(btndown && isMarked(column, row))
+ {
+ if(cellSize() > 1)
+ {
+ p->drawWinFocusRect( x + 1, y + 1, cellSize() - 2, cellSize() - 2);
+ }
+ else
+ {
+ p->drawPoint(x, y);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if(hasGrid()&& !(cellSize()==1))
+ {
+ p->setPen(QColor(0, 0, 0));
+ int x = e->rect().x() - ((e->rect().x() % cellSize()) + cellSize());
+ if(x < 0) x = 0;
+ int y = e->rect().y() - ((e->rect().y() % cellSize()) + cellSize());
+ if(y < 0) y = 0;
+ int cx = e->rect().right() + cellSize();
+ int cy = e->rect().bottom() + cellSize();
+
+ // draw grid lines
+ for(int i = x; i < cx; i += cellSize())
+ p->drawLine(i, y, i, cy);
+
+ for(int i = y; i < cy; i += cellSize())
+ p->drawLine(x, i, cx, i);
+ }
+}
+
+void KIconEditGrid::mousePressEvent( QMouseEvent *e )
+{
+ if(!e || (e->button() != LeftButton))
+ return;
+
+ int row = findRow( e->pos().y() );
+ int col = findCol( e->pos().x() );
+ //int cell = row * numCols() + col;
+
+ if(!img->valid(col, row))
+ return;
+
+ btndown = true;
+ start.setX(col);
+ start.setY(row);
+
+ if(ispasting)
+ {
+ ispasting = false;
+ editPaste(true);
+ }
+
+ if(isselecting)
+ {
+ QPointArray a(pntarray.copy());
+ pntarray.resize(0);
+ drawPointArray(a, Mark);
+ emit selecteddata(false);
+ }
+
+ switch( tool )
+ {
+ case SelectRect:
+ case SelectCircle:
+ isselecting = true;
+ break;
+ default:
+ break;
+ }
+}
+
+void KIconEditGrid::mouseMoveEvent( QMouseEvent *e )
+{
+ if(!e) return;
+
+ int row = findRow( e->pos().y() );
+ int col = findCol( e->pos().x() );
+ int cell = row * numCols() + col;
+
+ if(img->valid(col, row))
+ {
+ //kdDebug(4640) << col << " X " << row << endl;
+ emit poschanged(col, row);
+ // for the rulers
+ emit xposchanged((col*scaling())+scaling()/2);
+ emit yposchanged((row*scaling())+scaling()/2);
+ }
+
+ QPoint tmpp(col, row);
+ if(tmpp == end) return;
+
+ // need to use intersection of rectangles to allow pasting
+ // only that part of clip image which intersects -jwc-
+ if(ispasting && !btndown && img->valid(col, row))
+ {
+ if( (col + cbsize.width()) > (numCols()-1) )
+ insrect.setX(numCols()-insrect.width());
+ else
+ insrect.setX(col);
+ if( (row + cbsize.height()) > (numRows()-1) )
+ insrect.setY(numRows()-insrect.height());
+ else
+ insrect.setY(row);
+
+ insrect.setSize(cbsize);
+ start = insrect.topLeft();
+ end = insrect.bottomRight();
+ drawRect(false);
+ return;
+ }
+
+ if(!img->valid(col, row) || !btndown)
+ return;
+
+ end.setX(col);
+ end.setY(row);
+
+ if(isselecting)
+ {
+ if(tool == SelectRect)
+ drawRect(false);
+ else
+ drawEllipse(false);
+ return;
+ }
+
+ bool erase=false;
+ switch( tool )
+ {
+ case Eraser:
+ erase=true;
+
+ case Freehand:
+ {
+ if( !m_command )
+ m_command = new KMacroCommand( i18n("Free Hand") );
+
+ if(erase)
+ setColor( cell, TRANSPARENT );
+ else
+ setColor( cell, currentcolor );
+
+ if ( selected != cell )
+ {
+ setModified( true );
+ int prevSel = selected;
+ selected = cell;
+ QRect area = QRect( col*cellsize,row*cellsize, cellsize, cellsize ).unite(
+ QRect ( (prevSel%numCols())*cellsize,(prevSel/numCols())*cellsize, cellsize, cellsize ) );
+
+ m_command->addCommand( new RepaintCommand( area, this ) );
+ DrawCommand* dc = new DrawCommand( col, row, colorAt(cell), img, this );
+ RepaintCommand* rp = new RepaintCommand( area, this );
+ dc->execute();
+ rp->execute();
+ m_command->addCommand( dc );
+ m_command->addCommand( rp );
+ }
+ break;
+ }
+ case Find:
+ {
+ iconcolors.closestMatch(colorAt(cell));
+ if ( selected != cell )
+ {
+ int prevSel = selected;
+ selected = cell;
+ update((prevSel%numCols())*cellsize,(prevSel/numCols())*cellsize, cellsize, cellsize);
+ update(col*cellsize,row*cellsize, cellsize, cellsize);
+ emit colorSelected(colorAt(selected));
+ }
+ break;
+ }
+ case Ellipse:
+ case Circle:
+ case FilledEllipse:
+ case FilledCircle:
+ {
+ drawEllipse(false);
+ break;
+ }
+ case FilledRect:
+ case Rect:
+ {
+ drawRect(false);
+ break;
+ }
+ case Line:
+ {
+ drawLine(false, false);
+ break;
+ }
+ case Spray:
+ {
+ drawSpray(QPoint(col, row));
+ setModified(true);
+ break;
+ }
+ default:
+ break;
+ }
+
+ p = *img;
+ emit changed(QPixmap(p));
+}
+
+void KIconEditGrid::mouseReleaseEvent( QMouseEvent *e )
+{
+ if(!e || (e->button() != LeftButton))
+ return;
+
+ int row = findRow( e->pos().y() );
+ int col = findCol( e->pos().x() );
+ btndown = false;
+ end.setX(col);
+ end.setY(row);
+ int cell = row * numCols() + col;
+ bool erase=false;
+ switch( tool )
+ {
+ case Eraser:
+ erase=true;
+ //currentcolor = TRANSPARENT;
+ case Freehand:
+ {
+ if(!img->valid(col, row))
+ return;
+ if(erase)
+ setColor( cell, TRANSPARENT );
+ else
+ setColor( cell, currentcolor );
+ //if ( selected != cell )
+ //{
+ setModified( true );
+ int prevSel = selected;
+ selected = cell;
+ update((prevSel%numCols())*cellsize,(prevSel/numCols())*cellsize, cellsize, cellsize);
+ update(col*cellsize,row*cellsize, cellsize, cellsize);
+ //updateCell( prevSel/numCols(), prevSel%numCols(), FALSE );
+ //updateCell( row, col, FALSE );
+ *((uint*)img->scanLine(row) + col) = colorAt(cell);
+ p = *img;
+ //}
+
+ if( m_command ) {
+ history->addCommand( m_command, false );
+ m_command = 0;
+ }
+
+ break;
+ }
+ case Ellipse:
+ case Circle:
+ case FilledEllipse:
+ case FilledCircle:
+ {
+ drawEllipse(true);
+ break;
+ }
+ case FilledRect:
+ case Rect:
+ {
+ drawRect(true);
+ break;
+ }
+ case Line:
+ {
+ drawLine(true, false);
+ break;
+ }
+ case Spray:
+ {
+ drawSpray(QPoint(col, row));
+ break;
+ }
+ case FloodFill:
+ {
+ QApplication::setOverrideCursor(waitCursor);
+ drawFlood(col, row, colorAt(cell));
+ QApplication::restoreOverrideCursor();
+ updateColors();
+ emit needPainting();
+ p = *img;
+ break;
+ }
+ case Find:
+ {
+ currentcolor = colorAt(cell);
+ if ( selected != cell )
+ {
+ int prevSel = selected;
+ selected = cell;
+ update((prevSel%numCols())*cellsize,(prevSel/numCols())*cellsize, cellsize, cellsize);
+ update(col*cellsize,row*cellsize, cellsize, cellsize);
+ emit colorSelected(currentcolor);
+ //updateCell( prevSel/numCols(), prevSel%numCols(), FALSE );
+ //updateCell( row, col, FALSE );
+ }
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ emit changed(QPixmap(p));
+ //emit colorschanged(numColors(), data());
+}
+
+//void KIconEditGrid::setColorSelection( const QColor &color )
+void KIconEditGrid::setColorSelection( uint c )
+{
+ currentcolor = c;
+ emit colorSelected(currentcolor);
+}
+
+void KIconEditGrid::loadBlank( int w, int h )
+{
+ img->create(w, h, 32);
+ img->setAlphaBuffer(true);
+ clearImage(img);
+ setNumRows(h);
+ setNumCols(w);
+ fill(TRANSPARENT);
+ emit sizechanged(numCols(), numRows());
+ emit colorschanged(numColors(), data());
+ history->clear();
+}
+
+
+
+void KIconEditGrid::load( QImage *image)
+{
+ kdDebug(4640) << "KIconEditGrid::load" << endl;
+
+ setUpdatesEnabled(false);
+
+ if(image == 0L)
+ {
+ QString msg = i18n("There was an error loading a blank image.\n");
+ KMessageBox::error(this, msg);
+ return;
+ }
+
+ *img = image->convertDepth(32);
+ img->setAlphaBuffer(true);
+ setNumRows(img->height());
+ setNumCols(img->width());
+
+ for(int y = 0; y < numRows(); y++)
+ {
+ uint *l = (uint*)img->scanLine(y);
+ for(int x = 0; x < numCols(); x++, l++)
+ {
+ setColor((y*numCols())+x, *l, false);
+ }
+ //kdDebug(4640) << "Row: " << y << endl;
+ kapp->processEvents(200);
+ }
+
+ updateColors();
+ emit sizechanged(numCols(), numRows());
+ emit colorschanged(numColors(), data());
+ emit changed(pixmap());
+ setUpdatesEnabled(true);
+ emit needPainting();
+ //repaint(viewRect(), false);
+ history->clear();
+}
+
+const QPixmap &KIconEditGrid::pixmap()
+{
+ if(!img->isNull())
+ p = *img;
+ //p.convertFromImage(*img, 0);
+ return(p);
+}
+
+void KIconEditGrid::getImage(QImage *image)
+{
+ kdDebug(4640) << "KIconEditGrid::getImage" << endl;
+ *image = *img;
+}
+
+bool KIconEditGrid::zoomTo(int scale)
+{
+ QApplication::setOverrideCursor(waitCursor);
+ setUpdatesEnabled(false);
+ setCellSize( scale );
+ setUpdatesEnabled(true);
+ emit needPainting();
+ QApplication::restoreOverrideCursor();
+ emit scalingchanged(cellSize());
+
+ if(scale == 1)
+ return false;
+ return true;
+}
+
+bool KIconEditGrid::zoom(Direction d)
+{
+ int f = (d == DirIn) ? (cellSize()+1) : (cellSize()-1);
+ QApplication::setOverrideCursor(waitCursor);
+ setUpdatesEnabled(false);
+ setCellSize( f );
+ setUpdatesEnabled(true);
+ //emit needPainting();
+ QApplication::restoreOverrideCursor();
+
+ emit scalingchanged(cellSize());
+ if(d == DirOut && cellSize() <= 1)
+ return false;
+ return true;
+}
+
+void KIconEditGrid::checkClipboard()
+{
+ bool ok = false;
+ QImage tmp = clipboardImage(ok);
+ if(ok)
+ emit clipboarddata(true);
+ else
+ {
+ emit clipboarddata(false);
+ }
+}
+
+QImage KIconEditGrid::clipboardImage(bool &ok)
+{
+ //###### Remove me later.
+ //Workaround Qt bug -- check whether format provided first.
+ //Code below is from QDragObject, to match the mimetype list....
+
+ QStrList fileFormats = QImageIO::inputFormats();
+ fileFormats.first();
+ bool oneIsSupported = false;
+ while ( fileFormats.current() )
+ {
+ QCString format = fileFormats.current();
+ QCString type = "image/" + format.lower();
+ if (kapp->clipboard()->data()->provides(type ) )
+ {
+ oneIsSupported = true;
+ }
+ fileFormats.next();
+ }
+ if (!oneIsSupported)
+ {
+ ok = false;
+ return QImage();
+ }
+
+ QImage image = kapp->clipboard()->image();
+ ok = !image.isNull();
+ if ( ok )
+ {
+ image = image.convertDepth(32);
+ image.setAlphaBuffer(true);
+ }
+ return image;
+}
+
+
+void KIconEditGrid::editSelectAll()
+{
+ start.setX(0);
+ start.setY(0);
+ end.setX(numCols()-1);
+ end.setY(numRows()-1);
+ isselecting = true;
+ drawRect(false);
+ emit newmessage(i18n("All selected"));
+}
+
+void KIconEditGrid::editClear()
+{
+ clearImage(img);
+ fill(TRANSPARENT);
+ update();
+ setModified(true);
+ p = *img;
+ emit changed(p);
+ emit newmessage(i18n("Cleared"));
+}
+
+QImage KIconEditGrid::getSelection(bool cut)
+{
+ const QRect rect = pntarray.boundingRect();
+ int nx = 0, ny = 0, nw = 0, nh = 0;
+ rect.rect(&nx, &ny, &nw, &nh);
+
+ QImage tmp(nw, nh, 32);
+ tmp.setAlphaBuffer(true);
+ clearImage(&tmp);
+
+ int s = pntarray.size();
+
+ for(int i = 0; i < s; i++)
+ {
+ int x = pntarray[i].x();
+ int y = pntarray[i].y();
+ if(img->valid(x, y) && rect.contains(QPoint(x, y)))
+ {
+ *((uint*)tmp.scanLine(y-ny) + (x-nx)) = *((uint*)img->scanLine(y) + x);
+ if(cut)
+ {
+ *((uint*)img->scanLine(y) + x) = TRANSPARENT;
+ setColor( (y*numCols()) + x, TRANSPARENT, false );
+ }
+ }
+ }
+
+ QPointArray a(pntarray.copy());
+ pntarray.resize(0);
+ drawPointArray(a, Mark);
+ emit selecteddata(false);
+ if(cut)
+ {
+ updateColors();
+ update(rect.x()*cellSize(), rect.y()*cellSize(),
+ rect.width()*cellSize(), rect.height()*cellSize());
+ p = *img;
+ emit changed(p);
+ emit colorschanged(numColors(), data());
+ emit newmessage(i18n("Selected area cut"));
+ setModified(true);
+ }
+ else
+ emit newmessage(i18n("Selected area copied"));
+
+ return tmp;
+}
+
+void KIconEditGrid::editCopy(bool cut)
+{
+ kapp->clipboard()->setImage(getSelection(cut));
+ isselecting = false;
+}
+
+
+void KIconEditGrid::editPaste(bool paste)
+{
+ bool ok = false;
+ QImage tmp = clipboardImage(ok);
+
+ KIconEditProperties *props = KIconEditProperties::self();
+
+ if(ok)
+ {
+ if( (tmp.size().width() > img->size().width())
+ || (tmp.size().height() > img->size().height()) )
+ {
+ if(KMessageBox::warningYesNo(this,
+ i18n("The clipboard image is larger than the current"
+ " image!\nPaste as new image?"),QString::null,i18n("Paste"), i18n("Do Not Paste")) == 0)
+ {
+ editPasteAsNew();
+ }
+ return;
+ }
+ else if(!paste)
+ {
+ ispasting = true;
+ cbsize = tmp.size();
+ return;
+ // emit newmessage(i18n("Pasting"));
+ }
+ else
+ {
+ //kdDebug(4640) << "KIconEditGrid: Pasting at: " << insrect.x() << " x " << insrect.y() << endl;
+ QApplication::setOverrideCursor(waitCursor);
+
+ for(int y = insrect.y(), ny = 0; y < numRows() && ny < insrect.height(); y++, ny++)
+ {
+ uint *l = ((uint*)img->scanLine(y)+insrect.x());
+ uint *cl = (uint*)tmp.scanLine(ny);
+ for(int x = insrect.x(), nx = 0; x < numCols() && nx < insrect.width(); x++, nx++, l++, cl++)
+ {
+ if(props->pasteTransparent())
+ {
+ *l = *cl;
+ }
+ else
+ {
+ // Porter-Duff Over composition
+ double alphaS = qAlpha(*cl) / 255.0;
+ double alphaD = qAlpha(*l) / 255.0;
+
+ double r = qRed(*cl) * alphaS + (1 - alphaS) * qRed(*l) * alphaD;
+ double g = qGreen(*cl) * alphaS + (1 - alphaS) * qGreen(*l) * alphaD;
+ double b = qBlue(*cl) * alphaS + (1 - alphaS) * qBlue(*l) * alphaD;
+ double a = alphaS + (1 - alphaS) * alphaD;
+
+ // Remove multiplication by alpha
+
+ if(a > 0)
+ {
+ r /= a;
+ g /= a;
+ b /= a;
+ }
+ else
+ {
+ r = 0;
+ g = 0;
+ b = 0;
+ }
+
+ int ir = (int)(r + 0.5);
+
+ if(ir < 0)
+ {
+ ir = 0;
+ }
+ else
+ if(ir > 255)
+ {
+ ir = 255;
+ }
+
+ int ig = (int)(g + 0.5);
+
+ if(ig < 0)
+ {
+ ig = 0;
+ }
+ else
+ if(ig > 255)
+ {
+ ig = 255;
+ }
+
+ int ib = (int)(b + 0.5);
+
+ if(ib < 0)
+ {
+ ib = 0;
+ }
+ else
+ if(ib > 255)
+ {
+ ib = 255;
+ }
+
+ int ia = (int)((a * 255) + 0.5);
+
+ if(ia < 0)
+ {
+ ia = 0;
+ }
+ else
+ if(ia > 255)
+ {
+ ia = 255;
+ }
+
+ *l = qRgba(ir, ig, ib, ia);
+ }
+
+ setColor((y*numCols())+x, (uint)*l, false);
+ }
+ }
+ updateColors();
+ update(insrect.x()*cellSize(), insrect.y()*cellSize(),
+ insrect.width()*cellSize(), insrect.height()*cellSize());
+
+ QApplication::restoreOverrideCursor();
+
+ setModified(true);
+ p = *img;
+ emit changed(QPixmap(p));
+ emit sizechanged(numCols(), numRows());
+ emit colorschanged(numColors(), data());
+ emit newmessage(i18n("Done pasting"));
+ }
+ }
+ else
+ {
+ QString msg = i18n("Invalid pixmap data in clipboard!\n");
+ KMessageBox::sorry(this, msg);
+ }
+}
+
+
+void KIconEditGrid::editPasteAsNew()
+{
+ bool ok = false;
+ QImage tmp = clipboardImage(ok);
+
+ if(ok)
+ {
+ if(isModified())
+ {
+ KIconEdit *w = new KIconEdit(tmp);
+ Q_CHECK_PTR(w);
+ }
+ else
+ {
+ *img = tmp;
+ load(img);
+ setModified(true);
+ //repaint(viewRect(), false);
+
+ p = *img;
+ emit changed(QPixmap(p));
+ emit sizechanged(numCols(), numRows());
+ emit colorschanged(numColors(), data());
+ emit newmessage(i18n("Done pasting"));
+ history->clear();
+ }
+ }
+ else
+ {
+ QString msg = i18n("Invalid pixmap data in clipboard!\n");
+ KMessageBox::error(this, msg);
+ }
+}
+
+
+void KIconEditGrid::editResize()
+{
+ kdDebug(4640) << "KIconGrid::editResize" << endl;
+ KResizeDialog *rs = new KResizeDialog(this, 0, QSize(numCols(), numRows()));
+ if(rs->exec())
+ {
+ const QSize s = rs->getSize();
+ *img = img->smoothScale(s.width(), s.height());
+ load(img);
+
+ setModified(true);
+ }
+ delete rs;
+}
+
+
+void KIconEditGrid::setSize(const QSize s)
+{
+ kdDebug(4640) << "::setSize: " << s.width() << " x " << s.height() << endl;
+
+ img->create(s.width(), s.height(), 32);
+ img->setAlphaBuffer(true);
+ clearImage(img);
+ load(img);
+}
+
+
+void KIconEditGrid::createCursors()
+{
+ QBitmap mask(22, 22);
+ QPixmap pix;
+
+ cursor_normal = QCursor(arrowCursor);
+
+ pix = BarIcon("colorpicker-cursor");
+ if(pix.isNull())
+ {
+ cursor_colorpicker = cursor_normal;
+ kdDebug(4640) << "KIconEditGrid: Error loading colorpicker-cursor.xpm" << endl;
+ }
+ else
+ {
+ mask = pix.createHeuristicMask();
+ pix.setMask(mask);
+ cursor_colorpicker = QCursor(pix, 1, 21);
+ }
+
+ pix = BarIcon("paintbrush-cursor");
+ if(pix.isNull())
+ {
+ cursor_paint = cursor_normal;
+ kdDebug(4640) << "KIconEditGrid: Error loading paintbrush.xpm" << endl;
+ }
+ else
+ {
+ mask = pix.createHeuristicMask();
+ pix.setMask(mask);
+ cursor_paint = QCursor(pix, 0, 19);
+ }
+
+ pix = BarIcon("fill-cursor");
+ if(pix.isNull())
+ {
+ cursor_flood = cursor_normal;
+ kdDebug(4640) << "KIconEditGrid: Error loading fill-cursor.xpm" << endl;
+ }
+ else
+ {
+ mask = pix.createHeuristicMask();
+ pix.setMask(mask);
+ cursor_flood = QCursor(pix, 3, 20);
+ }
+
+ pix = BarIcon("aim-cursor");
+ if(pix.isNull())
+ {
+ cursor_aim = cursor_normal;
+ kdDebug(4640) << "KIconEditGrid: Error loading aim-cursor.xpm" << endl;
+ }
+ else
+ {
+ mask = pix.createHeuristicMask();
+ pix.setMask(mask);
+ cursor_aim = QCursor(pix, 10, 10);
+ }
+
+ pix = BarIcon("airbrush-cursor");
+ if(pix.isNull())
+ {
+ cursor_spray = cursor_normal;
+ kdDebug(4640) << "KIconEditGrid: Error loading airbrush-cursor.xpm" << endl;
+ }
+ else
+ {
+ mask = pix.createHeuristicMask(true);
+ pix.setMask(mask);
+ cursor_spray = QCursor(pix, 0, 20);
+ }
+
+ pix = BarIcon("eraser-cursor");
+ if(pix.isNull())
+ {
+ cursor_erase = cursor_normal;
+ kdDebug(4640) << "KIconEditGrid: Error loading eraser-cursor.xpm" << endl;
+ }
+ else
+ {
+ mask = pix.createHeuristicMask(true);
+ pix.setMask(mask);
+ cursor_erase = QCursor(pix, 1, 16);
+ }
+}
+
+
+
+void KIconEditGrid::setTool(DrawTool t)
+{
+ btndown = false;
+ tool = t;
+
+ if(tool != SelectRect && tool != SelectCircle)
+ isselecting = false;
+
+ switch( tool )
+ {
+ case SelectRect:
+ isselecting = true;
+ setCursor(cursor_aim);
+ break;
+ case SelectCircle:
+ isselecting = true;
+ setCursor(cursor_aim);
+ break;
+ case Line:
+ case Ellipse:
+ case Circle:
+ case FilledEllipse:
+ case FilledCircle:
+ case FilledRect:
+ case Rect:
+ setCursor(cursor_aim);
+ break;
+ case Freehand:
+ setCursor(cursor_paint);
+ break;
+ case Spray:
+ setCursor(cursor_spray);
+ break;
+ case Eraser:
+ setCursor(cursor_erase);
+ break;
+ case FloodFill:
+ setCursor(cursor_flood);
+ break;
+ case Find:
+ setCursor(cursor_colorpicker);
+ break;
+ default:
+ break;
+ }
+}
+
+
+void KIconEditGrid::drawFlood(int x, int y, uint oldcolor)
+{
+ if((!img->valid(x, y))
+ || (colorAt((y * numCols())+x) != oldcolor)
+ || (colorAt((y * numCols())+x) == currentcolor))
+ return;
+
+ *((uint*)img->scanLine(y) + x) = currentcolor;
+ setColor((y*numCols())+x, currentcolor, false);
+
+ setModified(true);
+
+ drawFlood(x, y-1, oldcolor);
+ drawFlood(x, y+1, oldcolor);
+ drawFlood(x-1, y, oldcolor);
+ drawFlood(x+1, y, oldcolor);
+ //TODO: add undo
+}
+
+
+void KIconEditGrid::drawSpray(QPoint point)
+{
+ int x = (point.x()-5);
+ int y = (point.y()-5);
+
+ //kdDebug(4640) << "drawSpray() - " << x << " X " << y << endl;
+
+ pntarray.resize(0);
+ int points = 0;
+ for(int i = 1; i < 4; i++, points++)
+ {
+ int dx = (rand() % 10);
+ int dy = (rand() % 10);
+ pntarray.putPoints(points, 1, x+dx, y+dy);
+ }
+
+ drawPointArray(pntarray, Draw);
+}
+
+
+//This routine is from Qt sources -- it's the branch of QPointArray::makeEllipse( int x, int y, int w, int h ) that's not normally compiled
+//It seems like KIconEdit relied on the Qt1 semantics for makeEllipse, which broke
+//the tool with reasonably recent Qt versions.
+//Thankfully, Qt includes the old code #ifdef'd, which is hence included here
+static void QPA_makeEllipse(QPointArray& ar, int x, int y, int w, int h )
+{ // midpoint, 1/4 ellipse
+ if ( w <= 0 || h <= 0 ) {
+ if ( w == 0 || h == 0 ) {
+ ar.resize( 0 );
+ return;
+ }
+ if ( w < 0 ) { // negative width
+ w = -w;
+ x -= w;
+ }
+ if ( h < 0 ) { // negative height
+ h = -h;
+ y -= h;
+ }
+ }
+ int s = (w+h+2)/2; // max size of xx,yy array
+ int *px = new int[s]; // 1/4th of ellipse
+ int *py = new int[s];
+ int xx, yy, i=0;
+ double d1, d2;
+ double a2=(w/2)*(w/2), b2=(h/2)*(h/2);
+ xx = 0;
+ yy = int(h/2);
+ d1 = b2 - a2*(h/2) + 0.25*a2;
+ px[i] = xx;
+ py[i] = yy;
+ i++;
+ while ( a2*(yy-0.5) > b2*(xx+0.5) ) { // region 1
+ if ( d1 < 0 ) {
+ d1 = d1 + b2*(3.0+2*xx);
+ xx++;
+ } else {
+ d1 = d1 + b2*(3.0+2*xx) + 2.0*a2*(1-yy);
+ xx++;
+ yy--;
+ }
+ px[i] = xx;
+ py[i] = yy;
+ i++;
+ }
+ d2 = b2*(xx+0.5)*(xx+0.5) + a2*(yy-1)*(yy-1) - a2*b2;
+ while ( yy > 0 ) { // region 2
+ if ( d2 < 0 ) {
+ d2 = d2 + 2.0*b2*(xx+1) + a2*(3-2*yy);
+ xx++;
+ yy--;
+ } else {
+ d2 = d2 + a2*(3-2*yy);
+ yy--;
+ }
+ px[i] = xx;
+ py[i] = yy;
+ i++;
+ }
+ s = i;
+ ar.resize( 4*s ); // make full point array
+ x += w/2;
+ y += h/2;
+ for ( i=0; i<s; i++ ) { // mirror
+ xx = px[i];
+ yy = py[i];
+ ar.setPoint( s-i-1, x+xx, y-yy );
+ ar.setPoint( s+i, x-xx, y-yy );
+ ar.setPoint( 3*s-i-1, x-xx, y+yy );
+ ar.setPoint( 3*s+i, x+xx, y+yy );
+ }
+ delete[] px;
+ delete[] py;
+}
+
+
+
+void KIconEditGrid::drawEllipse(bool drawit)
+{
+ if(drawit)
+ {
+ drawPointArray(pntarray, Draw);
+ p = *img;
+ emit changed(p);
+ return;
+ }
+
+ QPointArray a(pntarray.copy());
+ int x = start.x(), y = start.y(), cx, cy;
+
+ if(x > end.x())
+ {
+ cx = x - end.x();
+ x = x - cx;
+ }
+ else
+ cx = end.x() - x;
+ if(y > end.y())
+ {
+ cy = y - end.y();
+ y = y - cy;
+ }
+ else
+ cy = end.y() - y;
+
+ int d = (cx > cy) ? cx : cy;
+
+ //kdDebug(4640) << x << ", " << y << " - " << d << " " << d << endl;
+ pntarray.resize(0);
+ drawPointArray(a, Mark);
+
+ if(tool == Circle || tool == FilledCircle || tool == SelectCircle)
+ QPA_makeEllipse(pntarray, x, y, d, d);
+ else if(tool == Ellipse || tool == FilledEllipse)
+ QPA_makeEllipse(pntarray, x, y, cx, cy);
+
+ if((tool == FilledEllipse) || (tool == FilledCircle)
+ || (tool == SelectCircle))
+ {
+ int s = pntarray.size();
+ int points = s;
+ for(int i = 0; i < s; i++)
+ {
+ int x = pntarray[i].x();
+ int y = pntarray[i].y();
+ for(int j = 0; j < s; j++)
+ {
+ if((pntarray[j].y() == y) && (pntarray[j].x() > x))
+ {
+ for(int k = x; k < pntarray[j].x(); k++, points++)
+ pntarray.putPoints(points, 1, k, y);
+ break;
+ }
+ }
+ }
+ }
+
+ drawPointArray(pntarray, Mark);
+
+ if(tool == SelectCircle && pntarray.size() > 0 && !ispasting)
+ emit selecteddata(true);
+}
+
+
+void KIconEditGrid::drawRect(bool drawit)
+{
+ if(drawit)
+ {
+ drawPointArray(pntarray, Draw);
+ p = *img;
+ emit changed(p);
+ return;
+ }
+
+ QPointArray a(pntarray.copy());
+ int x = start.x(), y = start.y(), cx, cy;
+
+ if(x > end.x())
+ {
+ cx = x - end.x();
+ x = x - cx;
+ }
+ else
+ cx = end.x() - x;
+ if(y > end.y())
+ {
+ cy = y - end.y();
+ y = y - cy;
+ }
+ else
+ cy = end.y() - y;
+
+ //kdDebug(4640) << x << ", " << y << " - " << cx << " " << cy << endl;
+ pntarray.resize(0);
+ drawPointArray(a, Mark); // remove previous marking
+
+ int points = 0;
+ bool pasting = ispasting;
+
+ if(tool == FilledRect || (tool == SelectRect))
+ {
+ for(int i = x; i <= x + (pasting ? cx + 1 : cx); i++)
+ {
+ for(int j = y; j <= y+cy; j++, points++)
+ pntarray.putPoints(points, 1, i, j);
+ }
+ }
+ else
+ {
+ for(int i = x; i <= x+cx; i++, points++)
+ pntarray.putPoints(points, 1, i, y);
+ for(int i = y; i <= y+cy; i++, points++)
+ pntarray.putPoints(points, 1, x, i);
+ for(int i = x; i <= x+cx; i++, points++)
+ pntarray.putPoints(points, 1, i, y+cy);
+ for(int i = y; i <= y+cy; i++, points++)
+ pntarray.putPoints(points, 1, x+cx, i);
+ }
+
+ drawPointArray(pntarray, Mark);
+
+ if(tool == SelectRect && pntarray.size() > 0 && !ispasting)
+ emit selecteddata(true);
+}
+
+
+void KIconEditGrid::drawLine(bool drawit, bool drawStraight)
+{
+ if(drawit)
+ {
+ drawPointArray(pntarray, Draw);
+ p = *img;
+ emit changed(p);
+ return;
+ }
+
+ QPointArray a(pntarray.copy());
+ pntarray.resize(0);
+
+ // remove previous marking
+ drawPointArray(a, Mark);
+
+ int x, y, dx, dy, delta;
+
+ dx = end.x() - start.x();
+ dy = end.y() - start.y();
+ x = start.x();
+ y = start.y();
+
+ delta = QMAX(abs(dx), abs(dy));
+ int deltaX = abs(dx);
+ int deltaY = abs(dy);
+
+ if ((drawStraight) && (delta > 0))
+ {
+ dx /= delta;
+ dy /= delta;
+
+ for(int i = 0; i <= delta; i++)
+ {
+ pntarray.putPoints(i, 1, x, y);
+ x += dx;
+ y += dy;
+ }
+ }
+
+ else if ((delta > 0) && (deltaX >= deltaY))
+ {
+ for(int i = 0; i <= deltaX; i++)
+ {
+ pntarray.putPoints(i, 1, x, y);
+
+ if(dx > 0)
+ x++;
+ else
+ x--;
+
+ if(dy >= 0)
+ y = start.y() + (abs(start.x() - x) * deltaY) / deltaX;
+ else
+ y = start.y() - (abs(start.x() - x) * deltaY) / deltaX;
+ }
+ }
+
+ else if ((delta > 0) && (deltaY > deltaX))
+ {
+ for(int i = 0; i <= deltaY; i++)
+ {
+ pntarray.putPoints(i, 1, x, y);
+
+ if(dy > 0)
+ y++;
+ else
+ y--;
+
+ if(dx >= 0)
+ x = start.x() + (abs(start.y() - y) * deltaX) / deltaY;
+ else
+ x = start.x() - (abs(start.y() - y) * deltaX) / deltaY;
+ }
+ }
+
+ drawPointArray(pntarray, Mark);
+}
+
+
+void KIconEditGrid::drawPointArray(QPointArray a, DrawAction action)
+{
+ QRect area( a.boundingRect().x()*cellSize()-1, a.boundingRect().y()*cellSize()-1,
+ a.boundingRect().width()*cellSize()+1, a.boundingRect().height()*cellSize()+1 );
+
+ KMacroCommand* macro = 0;
+ bool doupdate = false;
+
+ if( a.size() > 0 && action == Draw ) {
+ // might cause a memmory leak, if
+ // macro is never used and never
+ // added to the history! TODO: Fix this
+ macro = new KMacroCommand( i18n("Drawn Array") );
+ RepaintCommand* rc = new RepaintCommand( area, this );
+ macro->addCommand( rc );
+ }
+
+ int s = a.size(); //((rect.size().width()) * (rect.size().height()));
+ for(int i = 0; i < s; i++)
+ {
+ int x = a[i].x();
+ int y = a[i].y();
+
+ if(img->valid(x, y) && a.boundingRect().contains(a[ i ]))
+ {
+ //kdDebug(4640) << "x: " << x << " - y: " << y << endl;
+ switch( action )
+ {
+ case Draw:
+ {
+ DrawCommand* dc = new DrawCommand( x, y, currentcolor, img, this );
+ dc->execute();
+ //*((uint*)img->scanLine(y) + x) = currentcolor; //colors[cell]|OPAQUE;
+ //int cell = y * numCols() + x;
+ //setColor( cell, currentcolor, false );
+ doupdate = true;
+ //updateCell( y, x, FALSE );
+ macro->addCommand( dc );
+ break;
+ }
+
+ case Mark:
+ case UnMark:
+ update(x*cellsize,y*cellsize, cellsize, cellsize);
+ //updateCell( y, x, true );
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+
+ if(doupdate)
+ {
+ setModified( true );
+ updateColors();
+ RepaintCommand* rc = new RepaintCommand( area, this );
+ rc->execute();
+ macro->addCommand( rc );
+ pntarray.resize(0);
+ // add to undo/redo history
+ history->addCommand( macro, false ); }
+}
+
+void KIconEditGrid::updatePreviewPixmap()
+{
+ p = *img;
+ emit changed(QPixmap(p));
+}
+
+
+bool KIconEditGrid::isMarked(QPoint point)
+{
+ return isMarked(point.x(), point.y());
+}
+
+
+bool KIconEditGrid::isMarked(int x, int y)
+{
+ if(((y * numCols()) + x) == selected)
+ return true;
+
+ int s = pntarray.size();
+ for(int i = 0; i < s; i++)
+ {
+ if(y == pntarray[i].y() && x == pntarray[i].x())
+ return true;
+ }
+
+ return false;
+}
+
+
+// Fast diffuse dither to 3x3x3 color cube
+// Based on Qt's image conversion functions
+static bool kdither_32_to_8( const QImage *src, QImage *dst )
+{
+ register QRgb *p;
+ uchar *b;
+ int y;
+
+ //printf("kconvert_32_to_8\n");
+
+ if ( !dst->create(src->width(), src->height(), 8, 256) ) {
+ kdWarning() << "OImage: destination image not valid" << endl;
+ return FALSE;
+ }
+
+ int ncols = 256;
+
+ static uint bm[16][16];
+ static int init=0;
+ if (!init)
+ {
+ // Build a Bayer Matrix for dithering
+ init = 1;
+ int n, i, j;
+
+ bm[0][0]=0;
+
+ for (n=1; n<16; n*=2)
+ {
+ for (i=0; i<n; i++)
+ {
+ for (j=0; j<n; j++)
+ {
+ bm[i][j]*=4;
+ bm[i+n][j]=bm[i][j]+2;
+ bm[i][j+n]=bm[i][j]+3;
+ bm[i+n][j+n]=bm[i][j]+1;
+ }
+ }
+ }
+
+ for (i=0; i<16; i++)
+ for (j=0; j<16; j++)
+ bm[i][j]<<=8;
+ }
+
+ dst->setNumColors( ncols );
+
+#define MAX_R 2
+#define MAX_G 2
+#define MAX_B 2
+#define INDEXOF(r,g,b) (((r)*(MAX_G+1)+(g))*(MAX_B+1)+(b))
+
+ int rc, gc, bc;
+
+ for ( rc=0; rc<=MAX_R; rc++ ) // build 2x2x2 color cube
+ for ( gc=0; gc<=MAX_G; gc++ )
+ for ( bc=0; bc<=MAX_B; bc++ )
+ {
+ dst->setColor( INDEXOF(rc,gc,bc),
+ qRgb( rc*255/MAX_R, gc*255/MAX_G, bc*255/MAX_B ) );
+ }
+
+ int sw = src->width();
+ int* line1[3];
+ int* line2[3];
+ int* pv[3];
+
+ line1[0] = new int[src->width()];
+ line2[0] = new int[src->width()];
+ line1[1] = new int[src->width()];
+ line2[1] = new int[src->width()];
+ line1[2] = new int[src->width()];
+ line2[2] = new int[src->width()];
+ pv[0] = new int[sw];
+ pv[1] = new int[sw];
+ pv[2] = new int[sw];
+
+ for ( y=0; y < src->height(); y++ )
+ {
+ p = (QRgb *)src->scanLine(y);
+ b = dst->scanLine(y);
+ int endian = (QImage::systemByteOrder() == QImage::BigEndian);
+ int x;
+ uchar* q = src->scanLine(y);
+ uchar* q2 = src->scanLine(y+1 < src->height() ? y + 1 : 0);
+ for (int chan = 0; chan < 3; chan++)
+ {
+ b = dst->scanLine(y);
+ int *l1 = (y&1) ? line2[chan] : line1[chan];
+ int *l2 = (y&1) ? line1[chan] : line2[chan];
+ if ( y == 0 )
+ {
+ for (int i=0; i<sw; i++)
+ l1[i] = q[i*4+chan+endian];
+ }
+ if ( y+1 < src->height() )
+ {
+ for (int i=0; i<sw; i++)
+ l2[i] = q2[i*4+chan+endian];
+ }
+ // Bi-directional error diffusion
+ if ( y&1 )
+ {
+ for (x=0; x<sw; x++)
+ {
+ int pix = QMAX(QMIN(2, (l1[x] * 2 + 128)/ 255), 0);
+ int err = l1[x] - pix * 255 / 2;
+ pv[chan][x] = pix;
+
+ // Spread the error around...
+ if ( x+1<sw )
+ {
+ l1[x+1] += (err*7)>>4;
+ l2[x+1] += err>>4;
+ }
+ l2[x]+=(err*5)>>4;
+ if (x>1)
+ l2[x-1]+=(err*3)>>4;
+ }
+ }
+ else
+ {
+ for (x=sw; x-->0; )
+ {
+ int pix = QMAX(QMIN(2, (l1[x] * 2 + 128)/ 255), 0);
+ int err = l1[x] - pix * 255 / 2;
+ pv[chan][x] = pix;
+
+ // Spread the error around...
+ if ( x > 0 )
+ {
+ l1[x-1] += (err*7)>>4;
+ l2[x-1] += err>>4;
+ }
+ l2[x]+=(err*5)>>4;
+ if (x+1 < sw)
+ l2[x+1]+=(err*3)>>4;
+ }
+ }
+ }
+ if (endian)
+ {
+ for (x=0; x<sw; x++)
+ {
+ *b++ = INDEXOF(pv[2][x],pv[1][x],pv[0][x]);
+ }
+ }
+ else
+ {
+ for (x=0; x<sw; x++)
+ {
+ *b++ = INDEXOF(pv[0][x],pv[1][x],pv[2][x]);
+ }
+ }
+ }
+
+ delete [] line1[0];
+ delete [] line2[0];
+ delete [] line1[1];
+ delete [] line2[1];
+ delete [] line1[2];
+ delete [] line2[2];
+ delete [] pv[0];
+ delete [] pv[1];
+ delete [] pv[2];
+
+#undef MAX_R
+#undef MAX_G
+#undef MAX_B
+#undef INDEXOF
+
+ return TRUE;
+}
+
+// this doesn't work the way it should but the way KPixmap does.
+void KIconEditGrid::mapToKDEPalette()
+{
+ QImage dest;
+
+ kdither_32_to_8(img, &dest);
+ *img = dest.convertDepth(32);
+
+ for(int y = 0; y < img->height(); y++)
+ {
+ uint *l = (uint*)img->scanLine(y);
+ for(int x = 0; x < img->width(); x++, l++)
+ {
+ if(*l < 0xff000000)
+ {
+ *l = *l | 0xff000000;
+ }
+ }
+ }
+
+ load(img);
+ return;
+
+/*
+#if QT_VERSION > 140
+ *img = img->convertDepthWithPalette(32, iconpalette, 42);
+ load(img);
+ return;
+#endif
+*/
+
+ QApplication::setOverrideCursor(waitCursor);
+ for(int y = 0; y < numRows(); y++)
+ {
+ uint *l = (uint*)img->scanLine(y);
+ for(int x = 0; x < numCols(); x++, l++)
+ {
+ if(*l != TRANSPARENT)
+ {
+ if(!iconcolors.contains(*l))
+ *l = iconcolors.closestMatch(*l);
+ }
+ }
+ }
+
+ load(img);
+ setModified(true);
+ QApplication::restoreOverrideCursor();
+}
+
+
+void KIconEditGrid::grayScale()
+{
+ for(int y = 0; y < numRows(); y++)
+ {
+ uint *l = (uint*)img->scanLine(y);
+ for(int x = 0; x < numCols(); x++, l++)
+ {
+ if(*l != TRANSPARENT)
+ {
+ uint c = qGray(*l);
+ *l = qRgba(c, c, c, qAlpha(*l));
+ }
+ }
+ }
+
+ load(img);
+ setModified(true);
+}
+
+
+void KIconEditGrid::clearImage(QImage *image)
+{
+ if(image->depth() != 32)
+ {
+ image->fill(TRANSPARENT);
+ }
+ else
+ {
+ // QImage::fill() does not set the alpha channel so do it
+ // manually.
+ for(int y = 0; y < image->height(); y++)
+ {
+ uint *l = (uint*)image->scanLine(y);
+ for(int x = 0; x < image->width(); x++, l++)
+ {
+ *l = TRANSPARENT;
+ }
+ }
+ }
+}
+
+
+void KIconEditGrid::setModified(bool m)
+{
+ if(m != modified)
+ {
+ modified = m;
+ emit modifiedchanged(m);
+ }
+}
+
+
+#include "kicongrid.moc"
+// vim: set ts=4:
diff --git a/kiconedit/kicongrid.h b/kiconedit/kicongrid.h
new file mode 100644
index 00000000..24730735
--- /dev/null
+++ b/kiconedit/kicongrid.h
@@ -0,0 +1,263 @@
+/*
+ KDE Icon Editor - a small graphics drawing program for the KDE.
+ Copyright (C) 1998 Thomas Tanghus (tanghus@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 Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __KICONEDITGRID_H__
+#define __KICONEDITGRID_H__
+
+#include <qpixmap.h>
+#include <qimage.h>
+#include <qcursor.h>
+#include <qpointarray.h>
+#include <qframe.h>
+#include <kcommand.h>
+#include <klocale.h>
+
+#include "kcolorgrid.h"
+
+class KCommandHistory;
+class KRuler;
+class KIconEditGrid;
+class QScrollView;
+
+enum Direction {
+ DirIn = 0, DirOut = 1,
+ DirUp = DirIn, DirDown = DirOut,
+ DirLeft, DirRight
+};
+
+class DrawCommand : public KCommand {
+ public:
+ DrawCommand( int xx, int yy, uint newcol, QImage* img, KIconEditGrid* g ) {
+ x = xx;
+ y = yy;
+ newcolor = newcol;
+ image = img;
+ grid = g;
+ }
+
+ void execute();
+ void unexecute();
+ QString name() const {
+ return i18n("Drawed Something");
+ }
+
+ protected:
+ int x;
+ int y;
+ uint newcolor;
+ uint oldcolor;
+ QImage* image;
+ KIconEditGrid* grid;
+};
+
+class RepaintCommand : public KCommand {
+ public:
+ RepaintCommand( QRect a, KIconEditGrid* g ) {
+ area = a;
+ grid = g;
+ }
+
+ void execute();
+ void unexecute() {
+ execute();
+ }
+
+ QString name() const {
+ return "repainted";
+ }
+ protected:
+ KIconEditGrid* grid;
+ QRect area;
+};
+
+class KGridView : public QFrame
+{
+ Q_OBJECT
+public:
+ KGridView( QImage *image, KCommandHistory* history, QWidget * parent = 0, const char *name = 0);
+
+ KRuler *hruler() { return _hruler;}
+ KRuler *vruler() { return _vruler;}
+ QFrame *corner() { return _corner;}
+ KIconEditGrid *grid() { return _grid; }
+ void setShowRulers(bool mode);
+ void setAcceptDrop(bool a);
+ const QRect viewRect();
+ QScrollView *viewPortWidget() { return viewport;}
+
+public slots:
+ void sizeChange(int, int);
+ void moving(int, int);
+ void scalingChange(int);
+ void paintGrid();
+ void checkClipboard();
+
+protected:
+ virtual void paintEvent(QPaintEvent*);
+ virtual void resizeEvent(QResizeEvent*);
+ void paintDropSite();
+ void setSizes();
+
+ QFrame *_corner;
+ KIconEditGrid *_grid;
+ KRuler *_hruler, *_vruler;
+ QScrollView *viewport;
+ bool acceptdrop;
+};
+
+/**
+* KIconEditGrid
+* @short KIconEditGrid
+* @author Thomas Tanghus <tanghus@kde.org>
+* @version 0.3
+*/
+class KIconEditGrid : public KColorGrid
+{
+ Q_OBJECT
+public:
+ KIconEditGrid( QImage *image, KCommandHistory* h, QWidget * parent = 0, const char *name = 0);
+ virtual ~KIconEditGrid();
+
+ enum DrawTool { Line, Freehand, FloodFill, Spray, Rect, FilledRect, Circle,
+ FilledCircle, Ellipse, FilledEllipse, Eraser, SelectRect, SelectCircle, Find };
+ enum DrawAction { Mark, UnMark, Draw };
+
+ void setGrid(bool g) { KColorGrid::setGrid(g); emit needPainting(); }
+ bool isModified() { return modified; };
+ void setModified(bool m);
+ const QPixmap &pixmap();
+ const QImage &image() { return *img; }
+ QImage clipboardImage(bool &ok);
+ QImage getSelection(bool);
+ int rows() { return numRows(); };
+ int cols() { return numCols(); };
+ uint getColors( uint *_colors) { return colors(_colors); }
+ bool isMarked(QPoint p);
+ bool isMarked(int x, int y);
+ int scaling() { return cellSize(); }
+ void loadBlank( int w = 0, int h = 0);
+ void setUndoColor( int colNum, uint v, bool update = true ) {
+ setColor( colNum, v, update );
+ };
+
+ enum TransparencyDisplayType
+ {
+ TRD_SOLIDCOLOR,
+ TRD_CHECKERBOARD
+ };
+ enum CheckerboardSize
+ {
+ CHK_SMALL = 0,
+ CHK_MEDIUM = 1,
+ CHK_LARGE = 2
+ };
+
+ TransparencyDisplayType transparencyDisplayType() const { return m_transparencyDisplayType; }
+ QColor checkerboardColor1() const { return m_checkerboardColor1; }
+ QColor checkerboardColor2() const { return m_checkerboardColor2; }
+ CheckerboardSize checkerboardSize() const { return m_checkerboardSize; }
+ QColor transparencySolidColor() const { return m_transparencySolidColor; }
+
+ void setTransparencyDisplayType(TransparencyDisplayType t) { m_transparencyDisplayType = t; }
+ void setCheckerboardColor1(const QColor& c) { m_checkerboardColor1 = c; }
+ void setCheckerboardColor2(const QColor& c) { m_checkerboardColor2 = c; }
+ void setCheckerboardSize(CheckerboardSize size) { m_checkerboardSize = size; }
+ void setTransparencySolidColor(const QColor& c) { m_transparencySolidColor = c; }
+
+public slots:
+ void load( QImage *);
+ void editCopy(bool cut = false);
+ void editPaste(bool paste = false);
+ void editPasteAsNew();
+ void editSelectAll();
+ void editClear();
+ void getImage(QImage *image);
+//#if QT_VERSION <= 140
+ void editResize();
+//#endif
+ void setSize(const QSize s);
+ void grayScale();
+ void mapToKDEPalette();
+ void setTool(DrawTool tool);
+ bool zoom(Direction direct);
+ bool zoomTo(int);
+
+ void checkClipboard();
+
+signals:
+ void scalingchanged(int);
+ void changed( const QPixmap & );
+ void sizechanged( int, int );
+ void poschanged( int, int );
+ void xposchanged( int );
+ void yposchanged( int );
+ void newmessage(const QString &);
+ void clipboarddata(bool);
+ void selecteddata(bool);
+ void needPainting();
+ void modifiedchanged(bool);
+ void colorSelected(uint);
+
+protected slots:
+ void setColorSelection( uint );
+ void updatePreviewPixmap();
+
+protected:
+ virtual void paintEvent(QPaintEvent*);
+ virtual void paintCell( QPainter*, int, int ) {}
+ virtual void paintForeground(QPainter* p, QPaintEvent* e);
+ virtual void mousePressEvent(QMouseEvent*);
+ virtual void mouseReleaseEvent(QMouseEvent*);
+ virtual void mouseMoveEvent(QMouseEvent*);
+ void createCursors();
+ void drawPointArray(QPointArray, DrawAction);
+ void drawEllipse(bool);
+ void drawLine(bool drawIt, bool drawStraight);
+ void drawRect(bool);
+ void drawSpray(QPoint);
+ void drawFlood(int x, int y, uint oldcolor);
+ static void clearImage(QImage *image);
+
+ uint currentcolor;
+ QPoint start, end;
+ QRect insrect;
+ QSize cbsize;
+ QImage *img;
+ QPixmap p;
+ int selected, tool; //, numrows, numcols;
+ bool modified, btndown, ispasting, isselecting;
+ QPointArray pntarray;
+ KColorArray iconcolors;
+ KCommandHistory* history;
+ KMacroCommand* m_command;
+ QCursor cursor_normal, cursor_aim, cursor_flood, cursor_spray, cursor_erase, cursor_paint, cursor_colorpicker;
+ TransparencyDisplayType m_transparencyDisplayType;
+ QColor m_checkerboardColor1;
+ QColor m_checkerboardColor2;
+ CheckerboardSize m_checkerboardSize;
+ QColor m_transparencySolidColor;
+};
+
+
+
+#endif //__KICONEDITGRID_H__
+
+
+
diff --git a/kiconedit/knew.cpp b/kiconedit/knew.cpp
new file mode 100644
index 00000000..214952b0
--- /dev/null
+++ b/kiconedit/knew.cpp
@@ -0,0 +1,326 @@
+/*
+ KDE Draw - a small graphics drawing program for the KDE
+ Copyright (C) 1998 Thomas Tanghus (tanghus@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 Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qlayout.h>
+#include <qpainter.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+#include <qpushbutton.h>
+
+#include <kconfig.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+#include <kapplication.h>
+
+#include "knew.h"
+
+KIconTemplateContainer* KIconTemplateContainer::instance = 0;
+
+void createStandardTemplates(KIconTemplateContainer *list)
+{
+ KIconLoader *kil = KGlobal::iconLoader();
+
+ KIconTemplate it;
+ it.path = kil->iconPath("standard", KIcon::User);
+ it.title = i18n("Standard File");
+ list->append(it);
+
+ it.path = kil->iconPath("source", KIcon::User);
+ it.title = i18n("Source File");
+ list->append(it);
+
+ it.path = kil->iconPath("compressed", KIcon::User);
+ it.title = i18n("Compressed File");
+ list->append(it);
+
+ it.path = kil->iconPath("folder", KIcon::User);
+ it.title = i18n("Standard Folder");
+ list->append(it);
+
+ it.path = kil->iconPath("package", KIcon::User);
+ it.title = i18n("Standard Package");
+ list->append(it);
+
+ it.path = kil->iconPath("mini-folder", KIcon::User);
+ it.title = i18n("Mini Folder");
+ list->append(it);
+
+ it.path = kil->iconPath("mini-package", KIcon::User);
+ it.title = i18n("Mini Package");
+ list->append(it);
+}
+
+void KIconTemplateContainer::save()
+{
+ KConfig *k = kapp->config();
+ k->setGroup("Templates");
+
+ QStringList names;
+ for (QValueListIterator<KIconTemplate> iter = begin(); iter != end(); iter++)
+ {
+ names.append((*iter).title);
+ }
+
+ k->writeEntry("Names", names);
+
+ for(unsigned int i = 0; i < names.count(); i++)
+ {
+ k->writePathEntry(names[i], (*this)[i].path);
+ }
+}
+
+KIconTemplateContainer::KIconTemplateContainer() : QValueList<KIconTemplate>()
+{
+ QStrList names;
+ KConfig *k = kapp->config();
+ k->setGroup("Templates");
+ k->readListEntry("Names", names);
+ for(int i = 0; i < (int)names.count(); i++)
+ {
+ KIconTemplate it;
+ it.path = k->readPathEntry(names.at(i));
+ it.title = names.at(i);
+ //kdDebug(4640) << "Template: " << names.at(i) << "\n" << path.data() << endl;
+ append(it);
+ }
+
+ if(count() == 0)
+ {
+ createStandardTemplates(this);
+ }
+}
+
+KIconTemplateContainer::~KIconTemplateContainer()
+{
+ clear();
+}
+
+KIconListBoxItem::KIconListBoxItem( KIconTemplate t )
+ : QListBoxItem(), icontemplate(t)
+{
+ //kdDebug(4640) << "KIconListBoxItem - " << t->path.data() << ", " << t->title.data() << endl;
+
+ pm.load(t.path);
+ setText( t.title );
+}
+
+void KIconListBoxItem::reloadIcon()
+{
+ pm.load(icontemplate.path);
+ setText( icontemplate.title );
+}
+
+
+
+void KIconListBoxItem::paint( QPainter *p )
+{
+ p->drawPixmap( 3, 0, pm );
+ QFontMetrics fm = p->fontMetrics();
+ int yPos; // vertical text position
+ if ( pm.height() < fm.height() )
+ yPos = fm.ascent() + fm.leading()/2;
+ else
+ yPos = pm.height()/2 - fm.height()/2 + fm.ascent();
+ p->drawText( pm.width() + 5, yPos, text() );
+}
+
+int KIconListBoxItem::height(const QListBox *lb ) const
+{
+ return QMAX( pm.height(), lb->fontMetrics().lineSpacing() + 1 );
+}
+
+int KIconListBoxItem::width(const QListBox *lb ) const
+{
+ return pm.width() + lb->fontMetrics().width( text() ) + 6;
+}
+
+NewSelect::NewSelect(QWidget *parent) : QWidget( parent )
+{
+ wiz = (KWizard*) parent;
+ grp = new QButtonGroup( this );
+ connect( grp, SIGNAL( clicked( int ) ), SLOT( buttonClicked( int ) ) );
+ grp->setExclusive( true );
+
+ QVBoxLayout* ml = new QVBoxLayout( this );
+ ml->addWidget( grp, 1 );
+ //ml->addWidget(grp, 10, AlignLeft);
+ QVBoxLayout* l = new QVBoxLayout( grp, 10 );
+
+ rbscratch = new QRadioButton( i18n( "Create from scratch" ), grp );
+ l->addWidget( rbscratch, 1 );
+ //l->addWidget(rbscratch, 5, AlignLeft);
+
+ rbtempl = new QRadioButton( i18n( "Create from template" ), grp );
+ l->addWidget( rbtempl, 1 );
+ //l->addWidget(rbtempl, 5, AlignLeft);
+
+ //grp->setMinimumSize(grp->childrenRect().size());
+
+ grp->setButton( 0 );
+}
+
+NewSelect::~NewSelect()
+{
+}
+
+void NewSelect::buttonClicked(int id)
+{
+ //kdDebug(4640) << "Button: " << id << endl;
+
+ emit iconopenstyle(id);
+}
+
+NewFromTemplate::NewFromTemplate( QWidget* parent )
+ : QWidget( parent )
+{
+ wiz = (KWizard*) parent;
+
+ QVBoxLayout* ml = new QVBoxLayout(this);
+
+ grp = new QGroupBox( i18n( "Templates" ), this );
+ ml->addWidget( grp, 1 );
+ //ml->addWidget(grp, 10, AlignLeft);
+
+ QHBoxLayout* l = new QHBoxLayout( grp, 15 );
+
+ templates = new KIconListBox( grp );
+ connect( templates, SIGNAL( highlighted( int ) ), SLOT( checkSelection( int ) ) );
+ l->addWidget( templates );
+
+ for( int i = 0; i < (int) KIconTemplateContainer::self()->count(); i++ )
+ templates->insertItem( new KIconListBoxItem( *KIconTemplateContainer::self()->at( i ) ) );
+}
+
+NewFromTemplate::~NewFromTemplate()
+{
+}
+
+void NewFromTemplate::checkSelection( int )
+{
+ //kdDebug(4640) << "checkSelection(int) " << templates->currentItem() << endl;
+ if( templates->currentItem() != -1 )
+ wiz->finishButton()->setEnabled( true );
+ else
+ wiz->finishButton()->setEnabled( false );
+}
+
+KNewIcon::KNewIcon( QWidget* parent )
+ : KWizard( parent, 0, true )
+{
+ //kdDebug(4640) << "KNewIcon" << endl;
+ setCaption( i18n( "Create New Icon" ) );
+ resize( 400, 250 );
+
+ openstyle = 0;
+
+ finishButton()->setEnabled( true );
+ cancelButton()->setEnabled( true );
+ nextButton()->setEnabled( false );
+
+ select = new NewSelect( this );
+ connect( select, SIGNAL( iconopenstyle( int ) ), SLOT( iconOpenStyle( int ) ) );
+
+ scratch = new KResizeWidget( this, 0, QSize( 32, 32 ) );
+ // this doesn't accept default valid size, besides spin buttons won't allow
+ // an invalid size to be set by the user - forces user to change valid default
+ // size to create the new icon object -
+ connect( scratch, SIGNAL( validSize( bool ) ), SLOT( checkPage( bool ) ) );
+ connect(this, SIGNAL(selected(const QString &)), this, SLOT(checkPage(const QString &)));
+ templ = new NewFromTemplate(this);
+ templ->hide();
+
+ addPage(select, i18n("Select Icon Type"));
+ addPage(scratch, i18n("Create From Scratch"));
+ act = scratch;
+ //addPage(templ, i18n("Create From Template"));
+}
+
+KNewIcon::~KNewIcon()
+{
+ delete select;
+ delete scratch;
+ delete templ;
+}
+
+void KNewIcon::okClicked()
+{
+ if(openstyle == Blank)
+ emit newicon(scratch->getSize());
+ else
+ emit newicon(templ->path());
+ hide();
+ setResult(1);
+ accept();
+}
+
+void KNewIcon::cancelClicked()
+{
+ hide();
+ setResult(0);
+ reject();
+}
+
+void KNewIcon::iconOpenStyle(int style)
+{
+ openstyle = style;
+
+ if( act )
+ removePage( act );
+
+ if(openstyle == Blank)
+ {
+ act = scratch;
+ setNextEnabled( act, true );
+ addPage( scratch, i18n( "Create From Scratch" ) );
+ }
+ else if( openstyle == Template )
+ {
+ act = templ;
+ setNextEnabled( act, true );
+ addPage( templ, i18n( "Create From Template" ) );
+ }
+}
+
+void KNewIcon::checkPage( bool b)
+{
+ //kdDebug(4640) << "checkPage(int) " << openstyle << " " << p << endl;
+ if(openstyle == Blank)
+ finishButton()->setEnabled(true);
+ else if( !b )
+ finishButton()->setEnabled(false);
+ else
+ templ->checkSelection(0);
+}
+
+void KNewIcon::checkPage(const QString &)
+{
+ if(currentPage() == select || openstyle == Blank)
+ finishButton()->setEnabled(true);
+ else
+ finishButton()->setEnabled(false);
+}
+#include "knew.moc"
+
+
+
+
+
diff --git a/kiconedit/knew.h b/kiconedit/knew.h
new file mode 100644
index 00000000..8801faf7
--- /dev/null
+++ b/kiconedit/knew.h
@@ -0,0 +1,164 @@
+/*
+ KDE Draw - a small graphics drawing program for the KDE.
+ Copyright (C) 1998 Thomas Tanghus (tanghus@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 Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __KNEWICON_H__
+#define __KNEWICON_H__
+
+#include <qwidget.h>
+#include <qpixmap.h>
+#include <qimage.h>
+#include <qlistbox.h>
+
+#include <kwizard.h>
+
+#include "kresize.h"
+
+class KIconListBox;
+class KIconTemplateContainer;
+class QButtonGroup;
+class QRadioButton;
+class QGroupBox;
+
+struct KIconTemplate
+{
+ QString path;
+ QString title;
+};
+
+class KIconListBoxItem : public QListBoxItem
+{
+public:
+ KIconListBoxItem( KIconTemplate );
+
+
+ const QString path() { return icontemplate.path; }
+ KIconTemplate& iconTemplate() { return icontemplate; }
+ void reloadIcon();
+
+protected:
+ virtual void paint( QPainter * );
+ virtual int height( const QListBox * ) const;
+ virtual int width( const QListBox * ) const;
+private:
+ QPixmap pm;
+ KIconTemplate icontemplate;
+};
+
+class KIconListBox : public QListBox
+{
+ Q_OBJECT
+public:
+ KIconListBox( QWidget *parent ) : QListBox(parent) {} ;
+ const QString path(int idx) { return ((KIconListBoxItem*)item(idx))->path(); }
+ KIconTemplate& iconTemplate(int idx) { return ((KIconListBoxItem*)item(idx))->iconTemplate(); }
+
+};
+
+class KIconTemplateContainer : public QValueList<KIconTemplate>
+{
+public:
+ static KIconTemplateContainer* self()
+ {
+ if (!instance)
+ instance = new KIconTemplateContainer;
+ return instance;
+ }
+
+ void save();
+
+private:
+ static KIconTemplateContainer* instance;
+
+ const KIconTemplateContainer operator = (const KIconTemplateContainer&);
+ KIconTemplateContainer(const KIconTemplateContainer&);
+
+ KIconTemplateContainer();
+ ~KIconTemplateContainer();
+};
+
+class NewSelect : public QWidget
+{
+ Q_OBJECT
+public:
+ NewSelect(QWidget *parent);
+ ~NewSelect();
+
+signals:
+ void iconopenstyle(int);
+
+protected slots:
+ void buttonClicked(int);
+
+protected:
+ KWizard *wiz;
+ QButtonGroup *grp;
+ QRadioButton *rbscratch, *rbtempl;
+};
+
+class NewFromTemplate : public QWidget
+{
+ Q_OBJECT
+public:
+ NewFromTemplate(QWidget *parent);
+ ~NewFromTemplate();
+
+ const QString path() { return QString(templates->path(templates->currentItem())); }
+
+public slots:
+ void checkSelection(int);
+
+protected:
+ KIconListBox *templates;
+ KWizard *wiz;
+ QGroupBox *grp;
+};
+
+class KNewIcon : public KWizard
+{
+ Q_OBJECT
+public:
+ KNewIcon(QWidget *parent);
+ ~KNewIcon();
+
+ enum { Blank = 0, Template = 1};
+ int openStyle() { return openstyle; }
+ const QString templatePath() { return QString(templ->path()); }
+ const QSize templateSize() { return scratch->getSize(); }
+
+protected slots:
+ void okClicked();
+ void cancelClicked();
+ void iconOpenStyle(int);
+ void checkPage(bool);
+ void checkPage(const QString &);
+
+signals:
+ void newicon(const QSize);
+ void newicon(const QString);
+
+protected:
+ NewSelect *select;
+ KResizeWidget *scratch;
+ NewFromTemplate *templ;
+ QWidget *act;
+ int openstyle;
+};
+
+#endif // __KNEWICON_H__
diff --git a/kiconedit/kresize.cpp b/kiconedit/kresize.cpp
new file mode 100644
index 00000000..82a86ee3
--- /dev/null
+++ b/kiconedit/kresize.cpp
@@ -0,0 +1,83 @@
+/*
+ KDE Draw - a small graphics drawing program for the KDE
+ Copyright (C) 1998 Thomas Tanghus (tanghus@kde.org)
+ Copyright (C) 2002 Nadeem Hasan ( nhasan@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 Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qgroupbox.h>
+
+#include <klocale.h>
+#include <knuminput.h>
+
+#include "kresize.h"
+
+KResizeWidget::KResizeWidget( QWidget* parent, const char* name,
+ const QSize& size ) : QWidget( parent, name )
+{
+ QHBoxLayout* genLayout = new QHBoxLayout( this );
+
+ QGroupBox* group = new QGroupBox( i18n( "Size" ), this );
+ group->setColumnLayout( 0, Qt::Horizontal );
+ genLayout->addWidget( group );
+
+ QHBoxLayout* layout = new QHBoxLayout( group->layout(), 6 );
+
+ m_width = new KIntSpinBox( 1, 200, 1, 1, 10, group );
+ m_width->setValue( size.width() );
+ layout->addWidget( m_width, 1 );
+
+ QLabel* label = new QLabel( "X", group );
+ layout->addWidget( label );
+
+ m_height = new KIntSpinBox( 1, 200, 1, 1, 10, group);
+ m_height->setValue( size.height() );
+ layout->addWidget( m_height, 1 );
+
+ setMinimumSize( 200, 100 );
+}
+
+KResizeWidget::~KResizeWidget()
+{
+}
+
+const QSize KResizeWidget::getSize()
+{
+ return QSize( m_width->value(), m_height->value() );
+}
+
+KResizeDialog::KResizeDialog( QWidget* parent, const char* name,
+ const QSize size )
+ : KDialogBase( parent, name, true, i18n( "Select Size" ), Ok|Cancel )
+{
+ m_resize = new KResizeWidget( this, "resize widget", size );
+
+ setMainWidget( m_resize );
+}
+
+KResizeDialog::~KResizeDialog()
+{
+}
+
+const QSize KResizeDialog::getSize()
+{
+ return m_resize->getSize();
+}
+
+#include "kresize.moc"
diff --git a/kiconedit/kresize.h b/kiconedit/kresize.h
new file mode 100644
index 00000000..691a4bd9
--- /dev/null
+++ b/kiconedit/kresize.h
@@ -0,0 +1,62 @@
+/*
+ KDE Draw - a small graphics drawing program for the KDE.
+ Copyright (C) 1998 Thomas Tanghus (tanghus@kde.org)
+ Copyright ( C ) 2002 Nadeem Hasan ( nhasan@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 Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __KRESIZE_H__
+#define __KRESIZE_H__
+
+#include <kdialogbase.h>
+
+class KIntSpinBox;
+
+class KResizeWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ KResizeWidget( QWidget* parent, const char* name, const QSize& );
+ ~KResizeWidget();
+
+ const QSize getSize();
+
+private:
+
+ KIntSpinBox *m_width;
+ KIntSpinBox *m_height;
+};
+
+class KResizeDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+
+ KResizeDialog( QWidget* parent, const char* name, const QSize s );
+ ~KResizeDialog();
+
+ const QSize getSize();
+
+private:
+
+ KResizeWidget* m_resize;
+};
+
+#endif //__KRESIZE_H__
diff --git a/kiconedit/main.cpp b/kiconedit/main.cpp
new file mode 100644
index 00000000..52abdd09
--- /dev/null
+++ b/kiconedit/main.cpp
@@ -0,0 +1,89 @@
+/*
+ KDE Draw - a small graphics drawing program for the KDE.
+ Copyright (C) 1998 Thomas Tanghus (tanghus@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.
+*/
+
+// A lot of this code is lifted from KMail. Thanks, guys!
+
+#include <stdlib.h>
+
+#include <klocale.h>
+#include <kconfig.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <kdebug.h>
+
+#include "kiconedit.h"
+#include "config.h"
+#include "properties.h"
+
+static const char description[] =
+ I18N_NOOP("KDE Icon Editor");
+
+static KCmdLineOptions options[] =
+{
+ { "+[file(s)]" , I18N_NOOP("Icon file(s) to open"), 0 },
+ KCmdLineLastOption
+};
+
+int main(int argc, char **argv)
+{
+ KAboutData aboutData( "kiconedit", I18N_NOOP("KIconEdit"),
+ VERSION, description, KAboutData::License_GPL,
+ "(c) 1998, Thomas Tanghus");
+
+ aboutData.addAuthor("Thomas Tanghus",0, "tanghus@kde.org");
+ aboutData.addAuthor("John Califf",0, "jcaliff@compuzone.net");
+ aboutData.addAuthor("Laurent Montel",0, "lmontel@mandrakesoft.com");
+ aboutData.addAuthor("Aaron J. Seigo",0, "aseigo@olympusproject.org");
+ aboutData.addCredit( "Nadeem Hasan", "Rewrote UI to use XMLGUI\n"
+ "Lots of fixes and cleanup", "nhasan@nadmm.com" );
+ aboutData.addCredit( "Adrian Page", I18N_NOOP("Bug fixes and GUI tidy up"),
+ "Adrian.Page@tesco.net" );
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
+
+ KApplication a;
+
+// setSignalHandler(signalHandler);
+
+ if (a.isRestored())
+ {
+ RESTORE(KIconEdit);
+ }
+ else
+ {
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ for(int i = 0; i < args->count(); i++)
+ {
+ KIconEdit *ki = new KIconEdit(args->url(i), "kiconedit");
+ Q_CHECK_PTR(ki);
+ }
+
+ if (args->count() == 0)
+ {
+ KIconEdit *ki = new KIconEdit;
+ Q_CHECK_PTR(ki);
+ }
+ args->clear();
+ }
+
+ int rc = a.exec();
+ delete KIconEditProperties::self();
+ return rc;
+}
+
diff --git a/kiconedit/palettetoolbar.cpp b/kiconedit/palettetoolbar.cpp
new file mode 100644
index 00000000..207442e1
--- /dev/null
+++ b/kiconedit/palettetoolbar.cpp
@@ -0,0 +1,178 @@
+/*
+ kiconedit - a small graphics drawing program for the KDE
+ Copyright ( C ) 1998 Thomas Tanghus ( tanghus@kde.org )
+ Copyright ( C ) 2002 Nadeem Hasan ( nhasan@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 Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qwhatsthis.h>
+#include <qpainter.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "kiconcolors.h"
+#include "palettetoolbar.h"
+
+PaletteToolBar::PaletteToolBar( QWidget *parent, const char *name )
+ : KToolBar( parent, name )
+{
+ QWidget *base = new QWidget( this );
+
+ QBoxLayout::Direction d = orientation() == Qt::Horizontal?
+ QBoxLayout::LeftToRight : QBoxLayout::TopToBottom;
+ m_layout = new QBoxLayout( base, d, 2, 6 );
+
+ m_lblPreview = new QLabel( base );
+ m_lblPreview->setFrameStyle( QFrame::Panel|QFrame::Sunken );
+ m_lblPreview->setFixedHeight( 64 );
+ m_lblPreview->setAlignment( Qt::AlignHCenter|Qt::AlignVCenter );
+ QWhatsThis::add(m_lblPreview, i18n( "Preview\n\nThis is a 1:1 preview"
+ " of the current icon" ) );
+ m_layout->addWidget( m_lblPreview );
+
+ m_currentColorView = new QLabel( base );
+ m_currentColorView->setFrameStyle( QFrame::Panel|QFrame::Sunken );
+ m_currentColorView->setFixedHeight( 24 );
+ m_currentColorView->setAlignment( Qt::AlignHCenter|Qt::AlignVCenter );
+ QWhatsThis::add(m_currentColorView, i18n( "Current color\n\nThis is the currently selected color" ) );
+ m_layout->addWidget( m_currentColorView );
+
+ QVBoxLayout *vlayout = new QVBoxLayout( m_layout, 0 );
+ QLabel *l = new QLabel( i18n( "System colors:" ), base );
+ vlayout->addWidget( l );
+ m_sysColors = new KSysColors( base );
+ QWhatsThis::add(m_sysColors, i18n( "System colors\n\nHere you can select"
+ " colors from the KDE icon palette" ) );
+
+ vlayout->addWidget( m_sysColors );
+
+ connect( m_sysColors, SIGNAL( newColor(uint) ),
+ SIGNAL( newColor(uint) ) );
+
+ vlayout = new QVBoxLayout( m_layout, 0 );
+ l = new QLabel( i18n( "Custom colors:" ), base );
+ vlayout->addWidget( l );
+ m_customColors = new KCustomColors( base );
+ QWhatsThis::add(m_customColors, i18n( "Custom colors\n\nHere you can"
+ " build a palette of custom colors.\nDouble-click on a box to edit"
+ " the color" ) );
+
+ vlayout->addWidget( m_customColors );
+
+ connect( m_customColors, SIGNAL( newColor(uint) ),
+ SIGNAL( newColor(uint) ) );
+ connect( this, SIGNAL( newColor(uint)),
+ this, SLOT(currentColorChanged(uint)));
+ currentColorChanged(OPAQUE_MASK|0);
+
+ setEnableContextMenu( false );
+ setMovingEnabled( false );
+}
+
+void PaletteToolBar::setOrientation( Orientation o )
+{
+ if( barPos() == Floating )
+ o = o == Qt::Vertical ? Qt::Horizontal : Qt::Vertical;
+
+ QBoxLayout::Direction d = o == Qt::Horizontal? QBoxLayout::LeftToRight
+ : QBoxLayout::TopToBottom;
+ m_layout->setDirection( d );
+
+ QDockWindow::setOrientation( o );
+}
+
+void PaletteToolBar::previewChanged( const QPixmap &p )
+{
+ m_lblPreview->setPixmap( p );
+}
+
+void PaletteToolBar::addColors( uint n, uint *c )
+{
+ m_customColors->clear();
+ for( uint i = 0; i < n; i++ )
+ addColor( c[ i ] );
+}
+
+void PaletteToolBar::addColor( uint color )
+{
+ if( !m_sysColors->contains( color ) )
+ m_customColors->addColor( color );
+}
+
+void PaletteToolBar::setPreviewBackground( QPixmap pixmap )
+{
+ m_lblPreview->setBackgroundPixmap(pixmap);
+}
+
+void PaletteToolBar::setPreviewBackground( const QColor& colour )
+{
+ m_lblPreview->setBackgroundColor(colour);
+}
+
+void PaletteToolBar::currentColorChanged(uint color)
+{
+ if(qAlpha(color) == 255)
+ {
+ m_currentColorView->setBackgroundColor(color);
+ }
+ else
+ {
+ // Show the colour as if drawn over a checkerboard pattern
+ const int squareWidth = 8;
+ const uint lightColour = qRgb(255, 255, 255);
+ const uint darkColour = qRgb(127, 127, 127);
+
+ QPixmap pm(2 * squareWidth, 2 * squareWidth);
+ QPainter p(&pm);
+
+ double alpha = qAlpha(color) / 255.0;
+
+ int r = int(qRed(color) * alpha + (1 - alpha) * qRed(lightColour) + 0.5);
+ int g = int(qGreen(color) * alpha + (1 - alpha) * qGreen(lightColour) + 0.5);
+ int b = int(qBlue(color) * alpha + (1 - alpha) * qBlue(lightColour) + 0.5);
+
+ uint squareColour = qRgb(r, g, b);
+
+ p.setPen(Qt::NoPen);
+ p.setBrush(squareColour);
+ p.drawRect(0, 0, squareWidth, squareWidth);
+ p.drawRect(squareWidth, squareWidth, squareWidth, squareWidth);
+
+ r = int(qRed(color) * alpha + (1 - alpha) * qRed(darkColour) + 0.5);
+ g = int(qGreen(color) * alpha + (1 - alpha) * qGreen(darkColour) + 0.5);
+ b = int(qBlue(color) * alpha + (1 - alpha) * qBlue(darkColour) + 0.5);
+
+ squareColour = qRgb(r, g, b);
+
+ p.setBrush(squareColour);
+ p.drawRect(squareWidth, 0, squareWidth, squareWidth);
+ p.drawRect(0, squareWidth, squareWidth, squareWidth);
+
+ p.end();
+
+ m_currentColorView->setBackgroundPixmap(pm);
+ }
+}
+
+#include "palettetoolbar.moc"
+
+/* vim: et sw=2 ts=2
+*/
+
diff --git a/kiconedit/palettetoolbar.h b/kiconedit/palettetoolbar.h
new file mode 100644
index 00000000..83cb3960
--- /dev/null
+++ b/kiconedit/palettetoolbar.h
@@ -0,0 +1,63 @@
+/*
+ kiconedit - a small graphics drawing program for the KDE
+ Copyright ( C ) 1998 Thomas Tanghus ( tanghus@kde.org )
+ Copyright ( C ) 2002 Nadeem Hasan ( nhasan@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 Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef PALLETTETOOLBAR_H
+#define PALLETTETOOLBAR_H
+
+#include <ktoolbar.h>
+
+class QBoxLayout;
+class QLabel;
+class KSysColors;
+class KCustomColors;
+
+class PaletteToolBar : public KToolBar
+{
+ Q_OBJECT
+
+ public:
+ PaletteToolBar( QWidget *parent, const char *name = 0L );
+
+ signals:
+ void newColor( uint c );
+
+ public slots:
+ virtual void setOrientation( Orientation o );
+ void previewChanged( const QPixmap &p );
+ void addColors( uint n, uint *c );
+ void addColor( uint color );
+ void setPreviewBackground( QPixmap pixmap );
+ void setPreviewBackground( const QColor& colour );
+ void currentColorChanged(uint color);
+
+ private:
+ QBoxLayout *m_layout;
+ QLabel *m_lblPreview;
+ QLabel *m_currentColorView;
+ KSysColors *m_sysColors;
+ KCustomColors *m_customColors;
+};
+
+#endif // PALLETTETOOLBAR_H
+
+/* vim: et sw=2 ts=2
+*/
+
diff --git a/kiconedit/pics/Makefile.am b/kiconedit/pics/Makefile.am
new file mode 100644
index 00000000..1a0b167e
--- /dev/null
+++ b/kiconedit/pics/Makefile.am
@@ -0,0 +1,5 @@
+
+SUBDIRS = icons toolbar
+
+KDE_ICON = kiconedit
+
diff --git a/kiconedit/pics/hi16-app-kiconedit.png b/kiconedit/pics/hi16-app-kiconedit.png
new file mode 100644
index 00000000..ff16bcae
--- /dev/null
+++ b/kiconedit/pics/hi16-app-kiconedit.png
Binary files differ
diff --git a/kiconedit/pics/hi22-app-kiconedit.png b/kiconedit/pics/hi22-app-kiconedit.png
new file mode 100644
index 00000000..8bb080c7
--- /dev/null
+++ b/kiconedit/pics/hi22-app-kiconedit.png
Binary files differ
diff --git a/kiconedit/pics/hi32-app-kiconedit.png b/kiconedit/pics/hi32-app-kiconedit.png
new file mode 100644
index 00000000..604b17dd
--- /dev/null
+++ b/kiconedit/pics/hi32-app-kiconedit.png
Binary files differ
diff --git a/kiconedit/pics/hi48-app-kiconedit.png b/kiconedit/pics/hi48-app-kiconedit.png
new file mode 100644
index 00000000..b95bffae
--- /dev/null
+++ b/kiconedit/pics/hi48-app-kiconedit.png
Binary files differ
diff --git a/kiconedit/pics/icons/Makefile.am b/kiconedit/pics/icons/Makefile.am
new file mode 100644
index 00000000..4acb372f
--- /dev/null
+++ b/kiconedit/pics/icons/Makefile.am
@@ -0,0 +1,5 @@
+pics_DATA = source.png \
+ standard.png \
+ compressed.png
+
+picsdir = $(kde_datadir)/kiconedit/pics
diff --git a/kiconedit/pics/icons/compressed.png b/kiconedit/pics/icons/compressed.png
new file mode 100644
index 00000000..c919f3bf
--- /dev/null
+++ b/kiconedit/pics/icons/compressed.png
Binary files differ
diff --git a/kiconedit/pics/icons/source.png b/kiconedit/pics/icons/source.png
new file mode 100644
index 00000000..8351e380
--- /dev/null
+++ b/kiconedit/pics/icons/source.png
Binary files differ
diff --git a/kiconedit/pics/icons/standard.png b/kiconedit/pics/icons/standard.png
new file mode 100644
index 00000000..df1e8318
--- /dev/null
+++ b/kiconedit/pics/icons/standard.png
Binary files differ
diff --git a/kiconedit/pics/logo.xpm b/kiconedit/pics/logo.xpm
new file mode 100644
index 00000000..97dab29d
--- /dev/null
+++ b/kiconedit/pics/logo.xpm
@@ -0,0 +1,137 @@
+/* XPM */
+static const char *logo[]={
+"260 87 47 1",
+"J c #9e9e9e",
+"b c #9f9f9f",
+"f c #a0a0a0",
+"I c #a1a1a1",
+"c c #a2a2a2",
+"B c #a3a3a3",
+"G c #a4a4a4",
+"O c #a5a5a5",
+"a c #a6a6a6",
+"v c #a7a7a7",
+"N c #a8a8a8",
+"R c #a9a9a9",
+"z c #aaaaaa",
+"p c #ababab",
+"w c #acacac",
+"t c #adadad",
+"Q c #aeaeae",
+"P c #afafaf",
+"o c #b0b0b0",
+"S c #b1b1b1",
+"K c #b2b2b2",
+"C c #b3b3b3",
+"M c #b4b4b4",
+"s c #b5b5b5",
+"k c #b6b6b6",
+"n c #b7b7b7",
+"H c #b8b8b8",
+"A c #b9b9b9",
+"d c #bababa",
+"u c #bbbbbb",
+"x c #bcbcbc",
+"l c #bdbdbd",
+"q c #bebebe",
+"r c #bfbfbf",
+"e c #c0c0c0",
+"D c #c1c1c1",
+"E c #c2c2c2",
+"L c #c3c3c3",
+"F c #c4c4c4",
+"i c #c5c5c5",
+"h c #c6c6c6",
+"# c #c7c7c7",
+"j c #c8c8c8",
+"y c #c9c9c9",
+"g c #cacaca",
+"m c #cbcbcb",
+". c #cccccc",
+"....................#abcdebfg.hbijklm...................................#abcdebfg.hbijklm...................................#abcdebfg.hbijklm...................................#abcdebfg.hbijklm...................................#abcdebfg.hbijklm...............",
+"................gni.opqrcstbu..vd...................................gni.opqrcstbu..vd...................................gni.opqrcstbu..vd...................................gni.opqrcstbu..vd...................................gni.opqrcstbu..vd...................",
+"................qbu.wk..qbxbv..y....................................qbu.wk..qbxbv..y....................................qbu.wk..qbxbv..y....................................qbu.wk..qbxbv..y....................................qbu.wk..qbxbv..y....................",
+"........iszA....qB..svm..vsCbr.........Dd.sE................iszA....qB..svm..vsCbr.........Dd.sE................iszA....qB..svm..vsCbr.........Dd.sE................iszA....qB..svm..vsCbr.........Dd.sE................iszA....qB..svm..vsCbr.........Dd.sE........",
+"........sbbl.#..Ffg.jGog.zp.l#.........jh.Hp................sbbl.#..Ffg.jGog.zp.l#.........jh.Hp................sbbl.#..Ffg.jGog.zp.l#.........jh.Hp................sbbl.#..Ffg.jGog.zp.l#.........jh.Hp................sbbl.#..Ffg.jGog.zp.l#.........jh.Hp........",
+".....dm.obbFmfH.mBu..iaIvbq...............yIE............dm.obbFmfH.mBu..iaIvbq...............yIE............dm.obbFmfH.mBu..iaIvbq...............yIE............dm.obbFmfH.mBu..iaIvbq...............yIE............dm.obbFmfH.mBu..iaIvbq...............yIE.......",
+"...#pbu.pbJg.CbE.sGg.AKunL.................MNrKj.......#pbu.pbJg.CbE.sGg.AKunL.................MNrKj.......#pbu.pbJg.CbE.sGg.AKunL.................MNrKj.......#pbu.pbJg.CbE.sGg.AKunL.................MNrKj.......#pbu.pbJg.CbE.sGg.AKunL.................MNrKj....",
+"...EJbGmabB..ycp.#ONHBE....................#ffHg.......EJbGmabB..ycp.#ONHBE....................#ffHg.......EJbGmabB..ycp.#ONHBE....................#ffHg.......EJbGmabB..ycp.#ONHBE....................#ffHg.......EJbGmabB..ycp.#ONHBE....................#ffHg....",
+"....PbbHfbGh..xbHDOswq..............NF......acg.........PbbHfbGh..xbHDOswq..............NF......acg.........PbbHfbGh..xbHDOswq..............NF......acg.........PbbHfbGh..xbHDOswq..............NF......acg.........PbbHfbGh..xbHDOswq..............NF......acg.....",
+".hDixfbcbbbbwD.nbbz.................pp......jGC......hDixfbcbbbbwD.nbbz.................pp......jGC......hDixfbcbbbbwD.nbbz.................pp......jGC......hDixfbcbbbbwD.nbbz.................pp......jGC......hDixfbcbbbbwD.nbbz.................pp......jGC.....",
+".KbbpsbbfBbbbbNuLqg.................lbr..CF..rfE.....KbbpsbbfBbbbbNuLqg.................lbr..CF..rfE.....KbbpsbbfBbbbbNuLqg.................lbr..CF..rfE.....KbbpsbbfBbbbbNuLqg.................lbr..CF..rfE.....KbbpsbbfBbbbbNuLqg.................lbr..CF..rfE....",
+".QbbAgGbbuAObbbQm...................gBOm.PB#..KOg....QbbAgGbbuAObbbQm...................gBOm.PB#..KOg....QbbAgGbbuAObbbQm...................gBOm.PB#..KOg....QbbAgGbbuAObbbQm...................gBOm.PB#..KOg....QbbAgGbbuAObbbQm...................gBOm.PB#..KOg...",
+"..qIF.lbbOgmlNzg....................yvbn.hfP..#ONg....qIF.lbbOgmlNzg....................yvbn.hfP..#ONg....qIF.lbbOgmlNzg....................yvbn.hfP..#ONg....qIF.lbbOgmlNzg....................yvbn.hfP..#ONg....qIF.lbbOgmlNzg....................yvbn.hfP..#ONg..",
+"...vx..Rbbn.npwA....................MGGIj.MfFmvqbL.....vx..Rbbn.npwA....................MGGIj.MfFmvqbL.....vx..Rbbn.npwA....................MGGIj.MfFmvqbL.....vx..Rbbn.npwA....................MGGIj.MfFmvqbL.....vx..Rbbn.npwA....................MGGIj.MfFmvqbL..",
+"..HJo..LbbNmObbr................#y..anebS.gRcSbyrm....HJo..LbbNmObbr................#y..anebS.gRcSbyrm....HJo..LbbNmObbr................#y..anebS.gRcSbyrm....HJo..LbbNmObbr................#y..anebS.gRcSbyrm....HJo..LbbNmObbr................#y..anebS.gRcSbyrm..",
+".Lbbbl..SMyQQEqy...............sbBj.Od.nJA.gKvn......Lbbbl..SMyQQEqy...............sbBj.Od.nJA.gKvn......Lbbbl..SMyQQEqy...............sbBj.Od.nJA.gKvn......Lbbbl..SMyQQEqy...............sbBj.Od.nJA.gKvn......Lbbbl..SMyQQEqy...............sbBj.Od.nJA.gKvn.....",
+"..wpMGPrLdNbL.................yflad.to.ibbvRq.........wpMGPrLdNbL.................yflad.to.ibbvRq.........wpMGPrLdNbL.................yflad.to.ibbvRq.........wpMGPrLdNbL.................yflad.to.ibbvRq.........wpMGPrLdNbL.................yflad.to.ibbvRq.......",
+".....ubbNpbbM..............Dnhibmwn.lfEhbsul.............ubbNpbbM..............Dnhibmwn.lfEhbsul.............ubbNpbbM..............Dnhibmwn.lfEhbsul.............ubbNpbbM..............Dnhibmwn.lfEhbsul.............ubbNpbbM..............Dnhibmwn.lfEhbsul........",
+".....sbBg.KJC...........DFiIQBEbjOq..PINOm...............sbBg.KJC...........DFiIQBEbjOq..PINOm...............sbBg.KJC...........DFiIQBEbjOq..PINOm...............sbBg.KJC...........DFiIQBEbjOq..PINOm...............sbBg.KJC...........DFiIQBEbjOq..PINOm..........",
+".....Fkd..mxF...........qzAz.Cazvcg..QtKh................Fkd..mxF...........qzAz.Cazvcg..QtKh................Fkd..mxF...........qzAz.Cazvcg..QtKh................Fkd..mxF...........qzAz.Cazvcg..QtKh................Fkd..mxF...........qzAz.Cazvcg..QtKh...........",
+"...........rL...........gbvQ.gGHBOiiwOy........................rL...........gbvQ.gGHBOiiwOy........................rL...........gbvQ.gGHBOiiwOy........................rL...........gbvQ.gGHBOiiwOy........................rL...........gbvQ.gGHBOiiwOy.............",
+".....................LHL.wbO..dOiNbfoj...................................LHL.wbO..dOiNbfoj...................................LHL.wbO..dOiNbfoj...................................LHL.wbO..dOiNbfoj...................................LHL.wbO..dOiNbfoj..............",
+"....................EIbcPFfJ#.yfD.E#....................................EIbcPFfJ#.yfD.E#....................................EIbcPFfJ#.yfD.E#....................................EIbcPFfJ#.yfD.E#....................................EIbcPFfJ#.yfD.E#................",
+"................jwe.QKyjvwKbk..Pr...................................jwe.QKyjvwKbk..Pr...................................jwe.QKyjvwKbk..Pr...................................jwe.QKyjvwKbk..Pr...................................jwe.QKyjvwKbk..Pr...................",
+"..........mj....lbD.tM..FbxbBm................................mj....lbD.tM..FbxbBm................................mj....lbD.tM..FbxbBm................................mj....lbD.tM..FbxbBm................................mj....lbD.tM..FbxbBm......................",
+"........ezfH....rB..ABy..RKlfl.........qs.Pl................ezfH....rB..ABy..RKlfl.........qs.Pl................ezfH....rB..ABy..RKlfl.........qs.Pl................ezfH....rB..ABy..RKlfl.........qs.Pl................ezfH....rB..ABy..RKlfl.........qs.Pl........",
+"........Mbbrmxm.#bj.mpvEyvw.#m..........m.la................Mbbrmxm.#bj.mpvEyvw.#m..........m.la................Mbbrmxm.#bj.mpvEyvw.#m..........m.la................Mbbrmxm.#bj.mpvEyvw.#m..........m.la................Mbbrmxm.#bj.mpvEyvw.#m..........m.la........",
+"....jQy.Qbbi.BQ..as..htfbci...............mOx...........jQy.Qbbi.BQ..as..htfbci...............mOx...........jQy.Qbbi.BQ..as..htfbci...............mOx...........jQy.Qbbi.BQ..as..htfbci...............mOx...........jQy.Qbbi.BQ..as..htfbci...............mOx.......",
+"...LBbs.Rbfg.dbx.xfF.ssiEm.................AGMa#.......LBbs.Rbfg.dbx.xfF.ssiEm.................AGMa#.......LBbs.Rbfg.dbx.xfF.ssiEm.................AGMa#.......LBbs.Rbfg.dbx.xfF.ssiEm.................AGMa#.......LBbs.Rbfg.dbx.xfF.ssiEm.................AGMa#....",
+"...hIbIjGbO..mvOmhNIwBh.............#......gfIE........hIbIjGbO..mvOmhNIwBh.............#......gfIE........hIbIjGbO..mvOmhNIwBh.............#......gfIE........hIbIjGbO..mvOmhNIwBh.............#......gfIE........hIbIjGbO..mvOmhNIwBh.............#......gfIE.....",
+"....kbbKfbcum.LftABDnh..............Bq......wIh.........kbbKfbcum.LftABDnh..............Bq......wIh.........kbbKfbcum.LftABDnh..............Bq......wIh.........kbbKfbcum.LftABDnh..............Bq......wIh.........kbbKfbcum.LftABDnh..............Bq......wIh.....",
+".DkAkGbbbbbbBkjeGbC.................Qam.....gRw......DkAkGbbbbbbBkjeGbC.................Qam.....gRw......DkAkGbbbbbbBkjeGbC.................Qam.....gRw......DkAkGbbbbbbBkjeGbC.................Qam.....gRw......DkAkGbbbbbbBkjeGbC.................Qam.....gRw.....",
+".PbbQxbbfzJbbbfomy..................DbH..zx..iIu.....PbbQxbbfzJbbbfomy..................DbH..zx..iIu.....PbbQxbbfzJbbbfomy..................DbH..zx..iIu.....PbbQxbbfzJbbbfomy..................DbH..zx..iIu.....PbbQxbbfzJbbbfomy..................DbH..zx..iIu....",
+".kIbl.zbbkFofbbn.....................vIj.MbE..AIi....kIbl.zbbkFofbbn.....................vIj.MbE..AIi....kIbl.zbbkFofbbn.....................vIj.MbE..AIi....kIbl.zbbkFofbbn.....................vIj.MbE..AIi....kIbl.zbbkFofbbn.....................vIj.MbE..AIi...",
+"..#BF.LbbI#.FCCy....................hBbK.yBz..Epcy....#BF.LbbI#.FCCy....................hBbK.yBz..Epcy....#BF.LbbI#.FCCy....................hBbK.yBz..Epcy....#BF.LbbI#.FCCy....................hBbK.yBz..Epcy....#BF.LbbI#.FCCy....................hBbK.yBz..Epcy..",
+"..mOA..obbo.KIOH....................QRRbL.ubxgBLfF....mOA..obbo.KIOH....................QRRbL.ubxgBLfF....mOA..obbo.KIOH....................QRRbL.ubxgBLfF....mOA..obbo.KIOH....................QRRbL.ubxgBLfF....mOA..obbo.KIOH....................QRRbL.ubxgBLfF..",
+".gQbp..#IbojcfbD...............mlD..OAiBz..Kbvfyy....gQbp..#IbojcfbD...............mlD..OAiBz..Kbvfyy....gQbp..#IbojcfbD...............mlD..OAiBz..Kbvfyy....gQbp..#IbojcfbD...............mlD..OAiBz..Kbvfyy....gQbp..#IbojcfbD...............mlD..OAiBz..Kbvfyy...",
+".LbbbKm.dr#ak.ym...............pcbF.OA.ubQygxKD......LbbbKm.dr#ak.ym...............pcbF.OA.ubQygxKD......LbbbKm.dr#ak.ym...............pcbF.OA.ubQygxKD......LbbbKm.dr#ak.ym...............pcbF.OA.ubQygxKD......LbbbKm.dr#ak.ym...............pcbF.OA.ubQygxKD.....",
+"..nkrpGMnPIbD.................#bFRA.Sw.#bfbIe.........nkrpGMnPIbD.................#bFRA.Sw.#bfbIe.........nkrpGMnPIbD.................#bFRA.Sw.#bfbIe.........nkrpGMnPIbD.................#bFRA.Sw.#bfbIe.........nkrpGMnPIbD.................#bFRA.Sw.#bfbIe.......",
+".....dbbCkfbS..............kpqib.wH.EfdLbeh#.............dbbCkfbS..............kpqib.wH.EfdLbeh#.............dbbCkfbS..............kpqib.wH.EfdLbeh#.............dbbCkfbS..............kpqib.wH.EfdLbeh#.............dbbCkfbS..............kpqib.wH.EfdLbeh#........",
+".....Mbv..xBx...........xqEIdIlfLBD..kJfp................Mbv..xBx...........xqEIdIlfLBD..kJfp................Mbv..xBx...........xqEIdIlfLBD..kJfp................Mbv..xBx...........xqEIdIlfLBD..kJfp................Mbv..xBx...........xqEIdIlfLBD..kJfp...........",
+".....gDE...ur...........EOnw.uBofGm.yakqm................gDE...ur...........EOnw.uBofGm.yakqm................gDE...ur...........EOnw.uBofGm.yakqm................gDE...ur...........EOnw.uBofGm.yakqm................gDE...ur...........EOnw.uBofGm.yakqm...........",
+"...........hj...........mIcw..NsRcAABtm........................hj...........mIcw..NsRcAABtm........................hj...........mIcw..NsRcAABtm........................hj...........mIcw..NsRcAABtm........................hj...........mIcw..NsRcAABtm.............",
+".....................dtngCbB..rByMfvx....................................dtngCbB..rByMfvx....................................dtngCbB..rByMfvx....................................dtngCbB..rByMfvx....................................dtngCbB..rByMfvx...............",
+".................m..uINROFBbL.gIl....................................m..uINROFBbL.gIl....................................m..uINROFBbL.gIl....................................m..uINROFBbL.gIl....................................m..uINROFBbL.gIl...................",
+"................FId.ws.mPOkbK..AL...................................FId.ws.mPOkbK..AL...................................FId.ws.mPOkbK..AL...................................FId.ws.mPOkbK..AL...................................FId.ws.mPOkbK..AL...................",
+".........gDL....lI#.oS..jIdcIj.........gj.Fg.................gDL....lI#.oS..jIdcIj.........gj.Fg.................gDL....lI#.oS..jIdcIj.........gj.Fg.................gDL....lI#.oS..jIdcIj.........gj.Fg.................gDL....lI#.oS..jIdcIj.........gj.Fg........",
+"........dfbd....Dc..qfL..pPivr.........rH.ok................dfbd....Dc..qfL..pPivr.........rH.ok................dfbd....Dc..qfL..pPivr.........rH.ok................dfbd....Dc..qfL..pPivr.........rH.ok................dfbd....Dc..qfL..pPivr.........rH.ok........",
+".....m..Cbbemoj.ybi..sInlGP...............Dcg............m..Cbbemoj.ybi..sInlGP...............Dcg............m..Cbbemoj.ybi..sInlGP...............Dcg............m..Cbbemoj.ybi..sInlGP...............Dcg............m..Cbbemoj.ybi..sInlGP...............Dcg.......",
+"....eGh.Qbb#.vvg.zP..LoOfwy................Rs.j.........eGh.Qbb#.vvg.zP..LoOfwy................Rs.j.........eGh.Qbb#.vvg.zP..LoOfwy................Rs.j.........eGh.Qbb#.vvg.zP..LoOfwy................Rs.j.........eGh.Qbb#.vvg.zP..LoOfwy................Rs.j.....",
+"...rbbP.RbI..ebk.Ebx.QH....................qfNB#.......rbbP.RbI..ebk.Ebx.QH....................qfNB#.......rbbP.RbI..ebk.Ebx.QH....................qfNB#.......rbbP.RbI..ebk.Ebx.QH....................qfNB#.......rbbP.RbI..ebk.Ebx.QH....................qfNB#....",
+"...gGbbFBbv...tcjiRIcRg.............lm.....mIBy........gGbbFBbv...tcjiRIcRg.............lm.....mIBy........gGbbFBbv...tcjiRIcRg.............lm.....mIBy........gGbbFBbv...tcjiRIcRg.............lm.....mIBy........gGbbFBbv...tcjiRIcRg.............lm.....mIBy.....",
+"....ubbpbbbPL.jGGPByLm..............GH......kbD.........ubbpbbbPL.jGGPByLm..............GH......kbD.........ubbpbbbPL.jGGPByLm..............GH......kbD.........ubbpbbbPL.jGGPByLm..............GH......kbD.........ubbpbbbPL.jGGPByLm..............GH......kbD.....",
+".uzQQRbbbbbbbzq#PNx.................Ccj..#...oag.....uzQQRbbbbbbbzq#PNx.................Ccj..#...oag.....uzQQRbbbbbbbzq#PNx.................Ccj..#...oag.....uzQQRbbbbbbbzq#PNx.................Ccj..#...oag.....uzQQRbbbbbbbzq#PNx.................Ccj..#...oag....",
+".wbbSEJbfCBbbbbvm...................ibS..vK..yGC.....wbbSEJbfCBbbbbvm...................ibS..vK..yGC.....wbbSEJbfCBbbbbvm...................ibS..vK..yGC.....wbbSEJbfCBbbbbvm...................ibS..vK..yGC.....wbbSEJbfCBbbbbvm...................ibS..vK..yGC....",
+".rNbD.obbSmuabbe.....................pbF.dbx..ebl....rNbD.obbSmuabbe.....................pbF.dbx..ebl....rNbD.obbSmuabbe.....................pbF.dbx..ebl....rNbD.obbSmuabbe.....................pbF.dbx..ebl....rNbD.obbSmuabbe.....................pbF.dbx..ebl...",
+"...OD.#IbbL.LnnL....................ebbp.mvOmmdKb#.....OD.#IbbL.LnnL....................ebbp.mvOmmdKb#.....OD.#IbbL.LnnL....................ebbp.mvOmmdKb#.....OD.#IbbL.LnnL....................ebbp.mvOmmdKb#.....OD.#IbbL.LnnL....................ebbp.mvOmmdKb#..",
+"..jBk..nbbz.Qbbd....................pPobq.EbK#fhRh....jBk..nbbz.Qbbd....................pPobq.EbK#fhRh....jBk..nbbz.Qbbd....................pPobq.EbK#fhRh....jBk..nbbz.Qbbd....................pPobq.EbK#fhRh....jBk..nbbz.Qbbd....................pPobq.EbK#fhRh..",
+".#abay.gOIxEBpvF...............hSn..GdyROy.xIbGg.....#abay.gOIxEBpvF...............hSn..GdyROy.xIbGg.....#abay.gOIxEBpvF...............hSn..GdyROy.xIbGg.....#abay.gOIxEBpvF...............hSn..GdyROy.xIbGg.....#abay.gOIxEBpvF...............hSn..GdyROy.xIbGg....",
+".#IbbRF.EhqIq.................mOzfe.Nk.rbOqeDqy......#IbbRF.EhqIq.................mOzfe.Nk.rbOqeDqy......#IbbRF.EhqIq.................mOzfe.Nk.rbOqeDqy......#IbbRF.EhqIq.................mOzfe.Nk.rbOqeDqy......#IbbRF.EhqIq.................mOzfe.Nk.rbOqeDqy.....",
+"..eEgKbNpGbbl...............m.hbjpH.MvmjbOOaF.........eEgKbNpGbbl...............m.hbjpH.MvmjbOOaF.........eEgKbNpGbbl...............m.hbjpH.MvmjbOOaF.........eEgKbNpGbbl...............m.hbjpH.MvmjbOOaF.........eEgKbNpGbbl...............m.hbjpH.MvmjbOOaF.......",
+".....HbbqDBbt...........m.mpfMhbmpA.#cPdbi...............HbbqDBbt...........m.mpfMhbmpA.#cPdbi...............HbbqDBbt...........m.mpfMhbmpA.#cPdbi...............HbbqDBbt...........m.mpfMhbmpA.#cPdbi...............HbbqDBbt...........m.mpfMhbmpA.#cPdbi..........",
+".....Hfw..Lti...........dkqGiOsIAfF..AfbM................Hfw..Lti...........dkqGiOsIAfF..AfbM................Hfw..Lti...........dkqGiOsIAfF..AfbM................Hfw..Lti...........dkqGiOsIAfF..AfbM................Hfw..Lti...........dkqGiOsIAfF..AfbM...........",
+"......gj...nx...........hIKQ.Efkbv..Ecey..................gj...nx...........hIKQ.Efkbv..Ecey..................gj...nx...........hIKQ.Efkbv..Ecey..................gj...nx...........hIKQ.Efkbv..Ecey..................gj...nx...........hIKQ.Efkbv..Ecey............",
+"...........m............mBbz..QoCbQQfH.........................m............mBbz..QoCbQQfH.........................m............mBbz..QoCbQQfH.........................m............mBbz..QoCbQQfH.........................m............mBbz..QoCbQQfH..............",
+"....................mPIwFdbIm.EfjrpKh...................................mPIwFdbIm.EfjrpKh...................................mPIwFdbIm.EfjrpKh...................................mPIwFdbIm.EfjrpKh...................................mPIwFdbIm.EfjrpKh...............",
+".................Eg.saCMfqvbr.mBd....................................Eg.saCMfqvbr.mBd....................................Eg.saCMfqvbr.mBd....................................Eg.saCMfqvbr.mBd....................................Eg.saCMfqvbr.mBd...................",
+"................ebH.pn..ncdbw..Dy...................................ebH.pn..ncdbw..Dy...................................ebH.pn..ncdbw..Dy...................................ebH.pn..ncdbw..Dy...................................ebH.pn..ncdbw..Dy...................",
+"........gekq....lcm.Kw..mGHNbL.........hD.l#................gekq....lcm.Kw..mGHNbL.........hD.l#................gekq....lcm.Kw..mGHNbL.........hD.l#................gekq....lcm.Kw..mGHNbL.........hD.l#................gekq....lcm.Kw..mGHNbL.........hD.l#........",
+"........nbbx....Lfm.Ffd..ptmKL.........Lr.Co................nbbx....Lfm.Ffd..ptmKL.........Lr.Co................nbbx....Lfm.Ffd..ptmKL.........Lr.Co................nbbx....Lfm.Ffd..ptmKL.........Lr.Co................nbbx....Lfm.Ffd..ptmKL.........Lr.Co........",
+".....F..SbbEmOD.gfe..rIpKfk...............hf#............F..SbbEmOD.gfe..rIpKfk...............hf#............F..SbbEmOD.gfe..rIpKfk...............hf#............F..SbbEmOD.gfe..rIpKfk...............hf#............F..SbbEmOD.gfe..rIpKfk...............hf#.......",
+"...msbD.wbbj.tc#.PR..qoowHm................PPylg.......msbD.wbbj.tc#.PR..qoowHm................PPylg.......msbD.wbbj.tc#.PR..qoowHm................PPylg.......msbD.wbbj.tc#.PR..qoowHm................PPylg.......msbD.wbbj.tc#.PR..qoowHm................PPylg....",
+"...rbbR.vbc..hfo.hcSLNl....................Lbfwj.......rbbR.vbc..hfo.hcSLNl....................Lbfwj.......rbbR.vbc..hfo.hcSLNl....................Lbfwj.......rbbR.vbc..hfo.hcSLNl....................Lbfwj.......rbbR.vbc..hfo.hcSLNl....................Lbfwj....",
+"....Nbbqcbvm..MbELNzIM..............Kj......BBm.........Nbbqcbvm..MbELNzIM..............Kj......BBm.........Nbbqcbvm..MbELNzIM..............Kj......BBm.........Nbbqcbvm..MbELNzIM..............Kj......BBm.........Nbbqcbvm..MbELNzIM..............Kj......BBm.....",
+".g..qJbObbbOAymwbaO.................vS......rfd......g..qJbObbbOAymwbaO.................vS......rfd......g..qJbObbbOAymwbaO.................vS......rfd......g..qJbObbbOAymwbaO.................vS......rfd......g..qJbObbbOAymwbaO.................vS......rfd.....",
+".sbcpobbJbbbbICidCi.................HbF..ly..nI#.....sbcpobbJbbbbICidCi.................HbF..ly..nI#.....sbcpobbJbbbbICidCi.................HbF..ly..nI#.....sbcpobbJbbbbICidCi.................HbF..ly..nI#.....sbcpobbJbbbbICidCi.................HbF..ly..nI#....",
+".zbbkjIbbdQbbbbvm...................jfp..zRg.mzp.....zbbkjIbbdQbbbbvm...................jfp..zRg.mzp.....zbbkjIbbdQbbbbvm...................jfp..zRg.mzp.....zbbkjIbbdQbbbbvm...................jfp..zRg.mzp.....zbbkjIbbdQbbbbvm...................jfp..zRg.mzp....",
+".jCfL.kbbz.hSfGh....................mzbq.Dbs..hIK....jCfL.kbbz.hSfGh....................mzbq.Dbs..hIK....jCfL.kbbz.hSfGh....................mzbq.Dbs..hIK....jCfL.kbbz.hSfGh....................mzbq.Dbs..hIK....jCfL.kbbz.hSfGh....................mzbq.Dbs..hIK...",
+"...vq.gGbbq.qMCl....................dffOm.tIjmoAbi.....vq.gGbbq.qMCl....................dffOm.tIjmoAbi.....vq.gGbbq.qMCl....................dffOm.tIjmoAbi.....vq.gGbbq.qMCl....................dffOm.tIjmoAbi.....vq.gGbbq.qMCl....................dffOm.tIjmoAbi..",
+"..EIM..lbbv.Rbbl....................NMHbn.#cRxb#Mj....EIM..lbbv.Rbbl....................NMHbn.#cRxb#Mj....EIM..lbbv.Rbbl....................NMHbn.#cRxb#Mj....EIM..lbbv.Rbbl....................NMHbn.#cRxb#Mj....EIM..lbbv.Rbbl....................NMHbn.#cRxb#Mj..",
+".iIbIL..zNiAvnKj...............qapm.GumoIL.Fvbwm.....iIbIL..zNiAvnKj...............qapm.GumoIL.Fvbwm.....iIbIL..zNiAvnKj...............qapm.GumoIL.Fvbwm.....iIbIL..zNiAvnKj...............qapm.GumoIL.Fvbwm.....iIbIL..zNiAvnKj...............qapm.GumoIL.Fvbwm....",
+".gGIRBdgjiCbE.................gICBx.zM.EbfKsDy.......gGIRBdgjiCbE.................gICBx.zM.EbfKsDy.......gGIRBdgjiCbE.................gICBx.zM.EbfKsDy.......gGIRBdgjiCbE.................gICBx.zM.EbfKsDy.......gGIRBdgjiCbE.................gICBx.zM.EbfKsDy......",
+"..jm.HbbIIbbA..............jEmibgwn.HBjjbwoKy.........jm.HbbIIbbA..............jEmibgwn.HBjjbwoKy.........jm.HbbIIbbA..............jEmibgwn.HBjjbwoKy.........jm.HbbIIbbA..............jEmibgwn.HBjjbwoKy.........jm.HbbIIbbA..............jEmibgwn.HBjjbwoKy.......",
+".....kbIygRbt...........hyyBGRFbgRu.gvvoIy...............kbIygRbt...........hyyBGRFbgRu.gvvoIy...............kbIygRbt...........hyyBGRFbgRu.gvvoIy...............kbIygRbt...........hyyBGRFbgRu.gvvoIy...............kbIygRbt...........hyyBGRFbgRu.gvvoIy..........",
+".....qzK..ykj...........uouvmptOPf#..kvvl................qzK..ykj...........uouvmptOPf#..kvvl................qzK..ykj...........uouvmptOPf#..kvvl................qzK..ykj...........uouvmptOPf#..kvvl................qzK..ykj...........uouvmptOPf#..kvvl...........",
+"...........Aq...........ybtQ.#fHfvmmnIi........................Aq...........ybtQ.#fHfvmmnIi........................Aq...........ybtQ.#fHfvmmnIi........................Aq...........ybtQ.#fHfvmmnIi........................Aq...........ybtQ.#fHfvmmnIi.............",
+".....................yLmmvbN..MplIBBaE...................................yLmmvbN..MplIBBaE...................................yLmmvbN..MplIBBaE...................................yLmmvbN..MplIBBaE...................................yLmmvbN..MplIBBaE.............."};
diff --git a/kiconedit/pics/toolbar/Makefile.am b/kiconedit/pics/toolbar/Makefile.am
new file mode 100644
index 00000000..8e3cb6e2
--- /dev/null
+++ b/kiconedit/pics/toolbar/Makefile.am
@@ -0,0 +1,28 @@
+toolbar_DATA = fileclose.png \
+ circle.png \
+ filledcircle.png \
+ line.png \
+ paintbrush-cursor.xpm \
+ airbrush-cursor.xpm \
+ ellipse.png \
+ filledellipse.png \
+ rectangle.png \
+ filledrectangle.png \
+ areaselect.png \
+ selectrect.png \
+ selectcircle.png \
+ fill-cursor.xpm \
+ grid.png \
+ pointer.png \
+ aim.png \
+ aim-cursor.xpm \
+ window_new.png \
+ grayscale.png \
+ kdepalette.png \
+ transform.png \
+ eraser-cursor.xpm \
+ colorpicker-cursor.xpm
+
+
+
+toolbardir = $(kde_datadir)/kiconedit/pics
diff --git a/kiconedit/pics/toolbar/aim-cursor.xpm b/kiconedit/pics/toolbar/aim-cursor.xpm
new file mode 100644
index 00000000..ecef295f
--- /dev/null
+++ b/kiconedit/pics/toolbar/aim-cursor.xpm
@@ -0,0 +1,28 @@
+/* XPM */
+static char *aim[]={
+"22 22 3 1",
+". c None",
+"a c #000000",
+"# c #ffffff",
+"......................",
+"..........#...........",
+".........#a#..........",
+".........#a#..........",
+".........#a#..........",
+".........#a#..........",
+".........#a#..........",
+".........#a#..........",
+".........#a#..........",
+"..#######...#######...",
+".#aaaaaaa...aaaaaaa#..",
+"..#######...#######...",
+"..........a...........",
+".........#a#..........",
+".........#a#..........",
+".........#a#..........",
+".........#a#..........",
+".........#a#..........",
+".........#a#..........",
+"..........#...........",
+"......................",
+"......................"};
diff --git a/kiconedit/pics/toolbar/aim.png b/kiconedit/pics/toolbar/aim.png
new file mode 100644
index 00000000..ed0088a7
--- /dev/null
+++ b/kiconedit/pics/toolbar/aim.png
Binary files differ
diff --git a/kiconedit/pics/toolbar/airbrush-cursor.xpm b/kiconedit/pics/toolbar/airbrush-cursor.xpm
new file mode 100644
index 00000000..2fd8314d
--- /dev/null
+++ b/kiconedit/pics/toolbar/airbrush-cursor.xpm
@@ -0,0 +1,35 @@
+/* XPM */
+static char *airbrush[]={
+"22 22 10 1",
+". c None",
+"a c #000000",
+"d c #2a2a2a",
+"g c #303030",
+"c c #444444",
+"h c #555555",
+"f c #808080",
+"b c #aaaaaa",
+"e c #c8c8c8",
+"# c #ffffff",
+"..................#aa#",
+".................#abca",
+"................#abcca",
+"...####........#abccda",
+"..#aaaa#......#abccda#",
+".#a####a#....#abccda#.",
+".#a#eeba#...#abccda#..",
+".#a#eeba#..#abccda#...",
+".#a#eeba#.#abccda#....",
+".#a#eeba##abccda#.....",
+".#a#ebba#abccda#......",
+".#a#bbbfaeccda#.......",
+"..#a#bfgaebda#.#####..",
+"..#a#bfaebffa##ddddd#.",
+"...#afaebbfa##ddaaada#",
+"..#a#eebbfadddda###da#",
+".#a#eebbfa#aaaa#..#da#",
+"#a#eebbfa#.####..#da#.",
+"#aeebbfa#.......#da#..",
+".#ebbfa#.......#da#...",
+"dhfffa#.......#da#....",
+"hd.aa#........#da#...."};
diff --git a/kiconedit/pics/toolbar/areaselect.png b/kiconedit/pics/toolbar/areaselect.png
new file mode 100644
index 00000000..de3fe8fb
--- /dev/null
+++ b/kiconedit/pics/toolbar/areaselect.png
Binary files differ
diff --git a/kiconedit/pics/toolbar/circle.png b/kiconedit/pics/toolbar/circle.png
new file mode 100644
index 00000000..ccb5c9db
--- /dev/null
+++ b/kiconedit/pics/toolbar/circle.png
Binary files differ
diff --git a/kiconedit/pics/toolbar/colorpicker-cursor.xpm b/kiconedit/pics/toolbar/colorpicker-cursor.xpm
new file mode 100644
index 00000000..8edc155e
--- /dev/null
+++ b/kiconedit/pics/toolbar/colorpicker-cursor.xpm
@@ -0,0 +1,36 @@
+/* XPM */
+static char *colorpicker[]={
+"22 22 11 1",
+". c None",
+"# c #000000",
+"f c #151515",
+"e c #2a2a2a",
+"c c #333333",
+"d c #3a3a3a",
+"i c #808080",
+"g c #aaaaaa",
+"b c #d5d5d5",
+"h c #dcdcdc",
+"a c #ffffff",
+"..................##a.",
+".................#bc#a",
+"................#bdcc#",
+"...............#bddce#",
+"..............#bddcef#",
+"............##bddcef#a",
+"...........#bdddcef#a.",
+"............#becef#a..",
+"...........#agbee#a...",
+"..........#ahgibf#a...",
+".........#ahgi#.#a....",
+"........#ahgi#........",
+".......#ahgi#.........",
+"......#ahgi#..........",
+".....#ahgi#...........",
+"....#ahgi#............",
+"...#ahgi#.............",
+"..#ahgi#..............",
+".#ahgi#...............",
+".#hgi#................",
+"#ig##.................",
+"#i#..................."};
diff --git a/kiconedit/pics/toolbar/ellipse.png b/kiconedit/pics/toolbar/ellipse.png
new file mode 100644
index 00000000..658b944d
--- /dev/null
+++ b/kiconedit/pics/toolbar/ellipse.png
Binary files differ
diff --git a/kiconedit/pics/toolbar/eraser-cursor.xpm b/kiconedit/pics/toolbar/eraser-cursor.xpm
new file mode 100644
index 00000000..12c07f11
--- /dev/null
+++ b/kiconedit/pics/toolbar/eraser-cursor.xpm
@@ -0,0 +1,32 @@
+/* XPM */
+static char *eraser[]={
+"22 22 7 1",
+"b c #000080",
+"e c #800000",
+"a c #8080ff",
+"d c #c00000",
+"# c #c0c0ff",
+"c c #ffc0c0",
+". c #ffffff",
+"......................",
+"...............#aa....",
+"..............#aaaa...",
+".............#aaaaaa..",
+"............#aaaaaaaa.",
+"...........#aaaaaaaaa.",
+"..........#aaaaaaaaab.",
+".........#aaaaaaaaab..",
+"........#aaaaaaaaab...",
+".......c##aaaaaaab....",
+"......cdd##aaaaab.....",
+".....cdddd##aaab......",
+"....cdddddd##ab.......",
+"...cdddddddd#b........",
+"..cddddddddde.........",
+".cddddddddde..........",
+".ccddddddde...........",
+".cccddddde............",
+"..cccddde.............",
+"...cccde..............",
+"....cce...............",
+"......................"};
diff --git a/kiconedit/pics/toolbar/fileclose.png b/kiconedit/pics/toolbar/fileclose.png
new file mode 100644
index 00000000..906b2ec5
--- /dev/null
+++ b/kiconedit/pics/toolbar/fileclose.png
Binary files differ
diff --git a/kiconedit/pics/toolbar/fill-cursor.xpm b/kiconedit/pics/toolbar/fill-cursor.xpm
new file mode 100644
index 00000000..d5ca3034
--- /dev/null
+++ b/kiconedit/pics/toolbar/fill-cursor.xpm
@@ -0,0 +1,36 @@
+/* XPM */
+static char *fill[]={
+"22 22 11 1",
+". c None",
+"a c #000000",
+"i c #222222",
+"c c #2a2a2a",
+"e c #333333",
+"g c #3a3a3a",
+"d c #404040",
+"h c #555555",
+"f c #aaaaaa",
+"b c #d5d5d5",
+"# c #ffffff",
+"......................",
+"............#.........",
+"...........#a#........",
+"..........#aba#.......",
+".........#abcca#......",
+"........#adceca#......",
+".......#afdcecca#.....",
+"......#abcedcecca#....",
+".....#afcgeedeeca#....",
+"...##fddcggeeeecca#...",
+"..#fdccddcggeeeecca#..",
+".#ddcdcdddcggeeeeca#..",
+".#dccbdddddcggeeecca#.",
+".#ddcddbbdddgggeeccba#",
+".#ddhadddbddggggeebia#",
+".#fda#adddbdddggebca#.",
+".#fda##aaddbbddgbca#..",
+".#fda#.##adddbdbca#...",
+"..#da#...#aaddbca#....",
+"..#fa#....##abca#.....",
+"..#f#.......#aa#......",
+"...#.........##......."};
diff --git a/kiconedit/pics/toolbar/filledcircle.png b/kiconedit/pics/toolbar/filledcircle.png
new file mode 100644
index 00000000..1431fbe2
--- /dev/null
+++ b/kiconedit/pics/toolbar/filledcircle.png
Binary files differ
diff --git a/kiconedit/pics/toolbar/filledellipse.png b/kiconedit/pics/toolbar/filledellipse.png
new file mode 100644
index 00000000..3f1d6220
--- /dev/null
+++ b/kiconedit/pics/toolbar/filledellipse.png
Binary files differ
diff --git a/kiconedit/pics/toolbar/filledrectangle.png b/kiconedit/pics/toolbar/filledrectangle.png
new file mode 100644
index 00000000..1a011a63
--- /dev/null
+++ b/kiconedit/pics/toolbar/filledrectangle.png
Binary files differ
diff --git a/kiconedit/pics/toolbar/flood-cursor.xpm b/kiconedit/pics/toolbar/flood-cursor.xpm
new file mode 100644
index 00000000..8707443d
--- /dev/null
+++ b/kiconedit/pics/toolbar/flood-cursor.xpm
@@ -0,0 +1,32 @@
+/* XPM */
+static char *flood[]={
+"22 22 7 1",
+"b c #000000",
+"c c #303030",
+"# c #808080",
+"e c #a0a0a4",
+"a c #c0c0c0",
+"d c #dcdcdc",
+". c #ffffff",
+"......................",
+"......................",
+"...........##.........",
+"..........####........",
+".........##aa##.......",
+".........##ba##.......",
+".........##.b##.......",
+".......cc##..b#.......",
+".....cccd##d..b.......",
+"....cccdd#b.d..b......",
+"...ccceddbdb.d..b.....",
+"..eccceeddbdd.d..b....",
+"..ecccceeddddd.d..b...",
+"..ecccebeeddddd.d.b...",
+"..eccceebeeddddd.b....",
+"..eccc.eebeeddd.b.....",
+"..eecc..eebeeddb......",
+"...eec...eebeeb.......",
+"....e.....eebb........",
+"...........ee.........",
+"......................",
+"......................"};
diff --git a/kiconedit/pics/toolbar/flood.png b/kiconedit/pics/toolbar/flood.png
new file mode 100644
index 00000000..45e1130b
--- /dev/null
+++ b/kiconedit/pics/toolbar/flood.png
Binary files differ
diff --git a/kiconedit/pics/toolbar/grayscale.png b/kiconedit/pics/toolbar/grayscale.png
new file mode 100644
index 00000000..3b475550
--- /dev/null
+++ b/kiconedit/pics/toolbar/grayscale.png
Binary files differ
diff --git a/kiconedit/pics/toolbar/grid.png b/kiconedit/pics/toolbar/grid.png
new file mode 100644
index 00000000..acf1b687
--- /dev/null
+++ b/kiconedit/pics/toolbar/grid.png
Binary files differ
diff --git a/kiconedit/pics/toolbar/kdepalette.png b/kiconedit/pics/toolbar/kdepalette.png
new file mode 100644
index 00000000..705865a2
--- /dev/null
+++ b/kiconedit/pics/toolbar/kdepalette.png
Binary files differ
diff --git a/kiconedit/pics/toolbar/line.png b/kiconedit/pics/toolbar/line.png
new file mode 100644
index 00000000..25964286
--- /dev/null
+++ b/kiconedit/pics/toolbar/line.png
Binary files differ
diff --git a/kiconedit/pics/toolbar/paintbrush-cursor.xpm b/kiconedit/pics/toolbar/paintbrush-cursor.xpm
new file mode 100644
index 00000000..fa4a1e32
--- /dev/null
+++ b/kiconedit/pics/toolbar/paintbrush-cursor.xpm
@@ -0,0 +1,36 @@
+/* XPM */
+static char *paintbrush[]={
+"22 22 11 1",
+". c None",
+"a c #000000",
+"d c #272727",
+"i c #2c2c2c",
+"h c #303030",
+"c c #3b3b3b",
+"g c #aaaaaa",
+"e c #c8c8c8",
+"b c #d5d5d5",
+"f c #ececec",
+"# c #ffffff",
+".................#abcc",
+"................#abccc",
+"...............#abcccd",
+"..............#abcccdd",
+".............#abcccdda",
+"............#abcccdda#",
+"...........#abcccdda#.",
+"..........#abcccdda#..",
+"..........abcccdda#...",
+".........##cccdda#....",
+".........#eecdda#.....",
+"......##f#eegda#......",
+".....#aabeggga#.......",
+"....#abbchgaa#........",
+"...#abcccda##.........",
+"...abcccdda#..........",
+"..#abccddia#..........",
+".#abccdiaa#...........",
+"#abdddaa##............",
+"aaaaaa##..............",
+"######................",
+"......................"};
diff --git a/kiconedit/pics/toolbar/paintbrush.png b/kiconedit/pics/toolbar/paintbrush.png
new file mode 100644
index 00000000..53774e19
--- /dev/null
+++ b/kiconedit/pics/toolbar/paintbrush.png
Binary files differ
diff --git a/kiconedit/pics/toolbar/pointer.png b/kiconedit/pics/toolbar/pointer.png
new file mode 100644
index 00000000..62229be5
--- /dev/null
+++ b/kiconedit/pics/toolbar/pointer.png
Binary files differ
diff --git a/kiconedit/pics/toolbar/rectangle.png b/kiconedit/pics/toolbar/rectangle.png
new file mode 100644
index 00000000..7075cf10
--- /dev/null
+++ b/kiconedit/pics/toolbar/rectangle.png
Binary files differ
diff --git a/kiconedit/pics/toolbar/selectcircle.png b/kiconedit/pics/toolbar/selectcircle.png
new file mode 100644
index 00000000..91f528ec
--- /dev/null
+++ b/kiconedit/pics/toolbar/selectcircle.png
Binary files differ
diff --git a/kiconedit/pics/toolbar/selectrect.png b/kiconedit/pics/toolbar/selectrect.png
new file mode 100644
index 00000000..0ce3aa21
--- /dev/null
+++ b/kiconedit/pics/toolbar/selectrect.png
Binary files differ
diff --git a/kiconedit/pics/toolbar/spraycan-cursor.xpm b/kiconedit/pics/toolbar/spraycan-cursor.xpm
new file mode 100644
index 00000000..13d84b80
--- /dev/null
+++ b/kiconedit/pics/toolbar/spraycan-cursor.xpm
@@ -0,0 +1,30 @@
+/* XPM */
+static char *spraycan[]={
+"22 22 5 1",
+"# c #000000",
+"c c #808080",
+"b c #a0a0a4",
+"a c #c0c0c0",
+". c #ffffff",
+"......................",
+"......................",
+"......................",
+"......................",
+"........##............",
+"#.#..#..#a####........",
+".........#a.#.#.......",
+"......#..#b#a..#......",
+".#.......##aaa..#.....",
+"....#....#cbaaa..#....",
+".........b#cbaaa..#...",
+"..#...#..bc#cbaaa..#..",
+"..........bc#cbaaa..#.",
+".....#.....bc#cbaaa..#",
+"............bc#cbaaa#.",
+".............bc#cba#..",
+"..............bc#c#...",
+"...............bc#....",
+"................b.....",
+"......................",
+"......................",
+"......................"};
diff --git a/kiconedit/pics/toolbar/spraycan.png b/kiconedit/pics/toolbar/spraycan.png
new file mode 100644
index 00000000..c2ce7e8d
--- /dev/null
+++ b/kiconedit/pics/toolbar/spraycan.png
Binary files differ
diff --git a/kiconedit/pics/toolbar/transform.png b/kiconedit/pics/toolbar/transform.png
new file mode 100644
index 00000000..3a5ca2b3
--- /dev/null
+++ b/kiconedit/pics/toolbar/transform.png
Binary files differ
diff --git a/kiconedit/pics/toolbar/window_new.png b/kiconedit/pics/toolbar/window_new.png
new file mode 100644
index 00000000..4d0a40a0
--- /dev/null
+++ b/kiconedit/pics/toolbar/window_new.png
Binary files differ
diff --git a/kiconedit/properties.cpp b/kiconedit/properties.cpp
new file mode 100644
index 00000000..0f2c1f44
--- /dev/null
+++ b/kiconedit/properties.cpp
@@ -0,0 +1,147 @@
+/*
+ KDE Icon Editor - a small graphics drawing program for the KDE
+ Copyright (C) 1998 Thomas Tanghus (tanghus@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 Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kapplication.h>
+
+#include "properties.h"
+
+KIconEditProperties* KIconEditProperties::m_self = 0;
+
+KIconEditProperties* KIconEditProperties::self()
+{
+ if (!m_self)
+ m_self = new KIconEditProperties();
+ return m_self;
+}
+
+KIconEditProperties::KIconEditProperties() : QObject()
+{
+ KConfig *config = kapp->config();
+
+ config->setGroup( "Appearance" );
+
+ m_bgMode = (QWidget::BackgroundMode)config->readNumEntry( "BackgroundMode", QWidget::FixedPixmap);
+ m_bgColor = config->readColorEntry( "BackgroundColor", &gray);
+ m_bgPixmap = config->readPathEntry("BackgroundPixmap");
+
+ config->setGroup( "Grid" );
+ m_pasteTransparent = config->readBoolEntry( "PasteTransparent", false );
+ m_showGrid = config->readBoolEntry( "ShowGrid", true );
+ m_gridScale = config->readNumEntry( "GridScaling", 10 );
+ m_showRulers = config->readBoolEntry( "ShowRulers", true );
+
+ if(config->readEntry( "TransparencyDisplayType", "Checkerboard" ) == "Checkerboard")
+ {
+ m_transparencyDisplayType = KIconEditGrid::TRD_CHECKERBOARD;
+ }
+ else
+ {
+ m_transparencyDisplayType = KIconEditGrid::TRD_SOLIDCOLOR;
+ }
+
+ QColor checkColor1(255, 255, 255);
+ QColor checkColor2(127, 127, 127);
+
+ m_checkerboardColor1 = config->readColorEntry( "CheckerboardColor1", &checkColor1);
+ m_checkerboardColor2 = config->readColorEntry( "CheckerboardColor2", &checkColor2);
+
+ QString checkerboardSize = config->readEntry( "CheckerboardSize", "Medium" );
+
+ if(checkerboardSize == "Small")
+ {
+ m_checkerboardSize = KIconEditGrid::CHK_SMALL;
+ }
+ else
+ if(checkerboardSize == "Medium")
+ {
+ m_checkerboardSize = KIconEditGrid::CHK_MEDIUM;
+ }
+ else
+ {
+ m_checkerboardSize = KIconEditGrid::CHK_LARGE;
+ }
+
+ QColor solidColor(255, 255, 255);
+ m_transparencySolidColor = config->readColorEntry( "TransparencySolidColor", &solidColor);
+}
+
+KIconEditProperties::~KIconEditProperties()
+{
+ kdDebug(4640) << "KIconEditProperties: Deleting properties" << endl;
+ m_self = 0;
+}
+
+void KIconEditProperties::save()
+{
+ KConfig *config = kapp->config();
+
+ config->setGroup( "Appearance" );
+
+ config->writeEntry("BackgroundMode", m_bgMode );
+ config->writeEntry("BackgroundColor", m_bgColor );
+ config->writePathEntry("BackgroundPixmap", m_bgPixmap );
+
+ config->setGroup( "Grid" );
+ config->writeEntry("PasteTransparent", m_pasteTransparent );
+ config->writeEntry("ShowGrid", m_showGrid );
+ config->writeEntry("GridScaling", m_gridScale );
+ config->writeEntry("ShowRulers", m_showRulers );
+
+ QString transparencyDisplayType;
+
+ switch(m_transparencyDisplayType)
+ {
+ case KIconEditGrid::TRD_SOLIDCOLOR:
+ transparencyDisplayType = "SolidColor";
+ break;
+ case KIconEditGrid::TRD_CHECKERBOARD:
+ default:
+ transparencyDisplayType = "Checkerboard";
+ break;
+ }
+
+ config->writeEntry( "TransparencyDisplayType", transparencyDisplayType );
+ config->writeEntry( "CheckerboardColor1", m_checkerboardColor1 );
+ config->writeEntry( "CheckerboardColor2", m_checkerboardColor2 );
+
+ QString checkerboardSize;
+
+ switch(m_checkerboardSize)
+ {
+ case KIconEditGrid::CHK_SMALL:
+ checkerboardSize = "Small";
+ break;
+ case KIconEditGrid::CHK_MEDIUM:
+ checkerboardSize = "Medium";
+ break;
+ case KIconEditGrid::CHK_LARGE:
+ default:
+ checkerboardSize = "Large";
+ break;
+ }
+
+ config->writeEntry( "CheckerboardSize", checkerboardSize );
+ config->writeEntry( "TransparencySolidColor", m_transparencySolidColor );
+
+ config->sync();
+}
+
diff --git a/kiconedit/properties.h b/kiconedit/properties.h
new file mode 100644
index 00000000..e94f6d2c
--- /dev/null
+++ b/kiconedit/properties.h
@@ -0,0 +1,82 @@
+/*
+ kiconedit - a small graphics drawing program the KDE.
+
+ Copyright (C) 1998 Thomas Tanghus (tanghus@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 Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __PROPS_H__
+#define __PROPS_H__
+
+#include <qwidget.h>
+
+#include "kicongrid.h"
+
+class KIconEditProperties : public QObject
+{
+public:
+ static KIconEditProperties* self();
+ ~KIconEditProperties();
+
+ QString bgPixmap() { return m_bgPixmap; }
+ QColor bgColor() { return m_bgColor; }
+ QWidget::BackgroundMode bgMode() { return m_bgMode; }
+ bool showGrid() { return m_showGrid; }
+ bool pasteTransparent() { return m_pasteTransparent; }
+ bool showRulers() { return m_showRulers; }
+ int gridScale() { return m_gridScale; }
+
+ KIconEditGrid::TransparencyDisplayType transparencyDisplayType() const { return m_transparencyDisplayType; }
+ QColor checkerboardColor1() const { return m_checkerboardColor1; }
+ QColor checkerboardColor2() const { return m_checkerboardColor2; }
+ KIconEditGrid::CheckerboardSize checkerboardSize() const { return m_checkerboardSize; }
+ QColor transparencySolidColor() const { return m_transparencySolidColor; }
+
+ void setBgPixmap( const QString &p ) { m_bgPixmap = p; }
+ void setBgColor( const QColor &c ) { m_bgColor = c; }
+ void setBgMode( QWidget::BackgroundMode m ) { m_bgMode = m; }
+ void setShowGrid( bool b ) { m_showGrid = b; }
+ void setPasteTransparent( bool b ) { m_pasteTransparent = b; }
+ void setShowRulers( bool b ) { m_showRulers = b; }
+ void setGridScale( int s ) { m_gridScale = s; }
+ void setTransparencyDisplayType(KIconEditGrid::TransparencyDisplayType t) { m_transparencyDisplayType = t; }
+ void setCheckerboardColor1(const QColor& c) { m_checkerboardColor1 = c; }
+ void setCheckerboardColor2(const QColor& c) { m_checkerboardColor2 = c; }
+ void setCheckerboardSize(KIconEditGrid::CheckerboardSize size) { m_checkerboardSize = size; }
+ void setTransparencySolidColor(const QColor& c) { m_transparencySolidColor = c; }
+
+ void save();
+
+protected:
+ KIconEditProperties();
+ QString m_bgPixmap;
+ QColor m_bgColor;
+ QWidget::BackgroundMode m_bgMode;
+ bool m_showGrid;
+ bool m_pasteTransparent;
+ bool m_showRulers;
+ int m_gridScale;
+ KIconEditGrid::TransparencyDisplayType m_transparencyDisplayType;
+ QColor m_checkerboardColor1;
+ QColor m_checkerboardColor2;
+ KIconEditGrid::CheckerboardSize m_checkerboardSize;
+ QColor m_transparencySolidColor;
+
+ static KIconEditProperties* m_self;
+};
+
+#endif //__PROPS_H__
diff --git a/kiconedit/utils.cpp b/kiconedit/utils.cpp
new file mode 100644
index 00000000..1af52803
--- /dev/null
+++ b/kiconedit/utils.cpp
@@ -0,0 +1,134 @@
+/*
+ KDE Icon Editor - a small graphics drawing program for the KDE
+
+ Copyright (C) 1998 Thomas Tanghus (tanghus@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 Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kimageio.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "utils.h"
+#include "config.h"
+
+imageFormats *formats = 0L;
+
+void setupImageHandlers()
+{
+ if(formats != 0L)
+ return;
+
+ KImageIO::registerFormats();
+
+ kdDebug(4640) << "Initializing formats" << endl;
+ formats = new imageFormats;
+ Q_CHECK_PTR(formats);
+ formats->setAutoDelete(true);
+ formats->append(new imageFormat("GIF", "GIF", "gif"));
+#ifdef HAVE_LIBJPEG
+ formats->append(new imageFormat("JFIF", "JPEG", "jpg"));
+#endif
+ formats->append(new imageFormat("XPM", "XPM", "xpm"));
+ formats->append(new imageFormat("ICO", "Windows Icon File", "ico"));
+/*
+#ifdef HAVE_LIBJPEG
+ QImageIO::defineIOHandler("JFIF","^\377\330\377\340", 0, read_jpeg_jfif, NULL);
+#endif
+*/
+}
+
+// Simple copy operation on local files (isn't there something like this in the libs?)
+bool copyFile(const QString &src, const QString &dest)
+{
+ QFile f_src(src);
+ QFile f_dest(dest);
+ QFileInfo fi(f_src);
+ uint src_size = fi.size();
+ kdDebug(4640) << "Size: " << src_size << endl;
+
+ if ( f_src.open(IO_ReadOnly) )
+ { // file opened successfully
+ if ( !f_dest.open(IO_WriteOnly) )
+ {
+ kdDebug(4640) << "copyFile - There was an error opening destination file: " << dest << endl;
+ f_src.close();
+ return false;
+ }
+ char *data = new char[src_size];
+ if(f_src.readBlock(data, src_size) == -1)
+ {
+ kdDebug(4640) << "copyFile - There was an error reading source file: " << src << endl;
+ f_src.close();
+ f_dest.close();
+ delete [] data;
+ return false;
+ }
+ if(f_dest.writeBlock(data, src_size) == -1)
+ {
+ kdDebug(4640) << "copyFile - There was an error writing to destination file: " << dest << endl;
+ f_src.close();
+ f_dest.close();
+ delete [] data;
+ return false;
+ }
+
+ f_src.close();
+ f_dest.close();
+ delete [] data;
+ return true;
+ }
+ kdDebug(4640) << "copyFile - There was an error opening source file: " << src << endl;
+ return false;
+}
+
+bool removeFile(const QString &file)
+{
+ if(file.length() > 0 && QFile::exists(file))
+ {
+ QDir d;
+ kdDebug(4640) << "Removing " << file << endl;
+ if(!d.remove(file))
+ {
+ kdDebug(4640) << "removeFile - There was an error removing the file: " << file << endl;
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool moveFile(const QString &src, const QString &dest)
+{
+ if(copyFile(src, dest))
+ return removeFile(src);
+ return false;
+}
+
+uint kdeColor(uint color)
+{
+ uint c = iconpalette[0]|OPAQUE_MASK;
+
+ for(uint i = 0; i < 42; i++)
+ {
+ //kdDebug(4640) << "Color #" << i << " " << iconpalette[i] << endl;
+ if( (iconpalette[i]|OPAQUE_MASK) - c < (iconpalette[i]|OPAQUE_MASK) - color)
+ c = iconpalette[i]|OPAQUE_MASK;
+ }
+ //kdDebug(4640) << color << " -> " << c << endl;
+ return c;
+}
diff --git a/kiconedit/utils.h b/kiconedit/utils.h
new file mode 100644
index 00000000..c1e1a4c0
--- /dev/null
+++ b/kiconedit/utils.h
@@ -0,0 +1,73 @@
+/*
+ kiconedit - a small graphics drawing program for the KDE
+
+ Copyright (C) 1998 Thomas Tanghus (tanghus@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 Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __UTILS_H__
+#define __UTILS_H__
+
+#include <qimage.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif // HAVE_CONFIG_H
+
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <kapplication.h>
+
+#define OPAQUE_MASK 0xff000000
+
+#ifdef TRANSPARENT
+#undef TRANSPARENT
+#endif
+#define TRANSPARENT 0x00000000
+
+const uint iconpalette[42] = { // kde palette
+ 0x303030,0x585858,0x808080,0xa0a0a0,0xc3c3c3,0xdcdcdc,
+ 0x000040,0x004000,0x000000,0x004040,0x404000,0x000000,
+ 0x000080,0x008000,0x800000,0x008080,0x808000,0x800080,
+ 0x0000c0,0x00c000,0xc00000,0x00c0c0,0xc0c000,0xc000c0,
+ 0x0000ff,0x00ff00,0xff0000,0x00ffff,0xffff00,0xff00ff,
+ 0xc0c0ff,0xc0ffc0,0xffc0c0,0xc0ffff,0xffffc0,0xffc0ff,
+ 0x0080ff,0x0058c0,0x58a8ff,0xa8dcff,0xffffff,0x000000};
+
+struct imageFormat
+{
+ imageFormat(const char *f, const char *t, const char *e) { format = f; title = t, extension = e;}
+ const char *format;
+ const char *title;
+ const char *extension;
+};
+
+typedef QPtrList<struct imageFormat> imageFormats;
+extern imageFormats *formats;
+
+void setupImageHandlers();
+
+bool copyFile(const QString &src, const QString &dest);
+bool removeFile(const QString &file);
+bool moveFile(const QString &src, const QString &dest);
+uint kdeColor(uint c);
+
+#endif //__UTILS_H__
+
+
+
diff --git a/kiconedit/version.h b/kiconedit/version.h
new file mode 100644
index 00000000..8f04bb6e
--- /dev/null
+++ b/kiconedit/version.h
@@ -0,0 +1,36 @@
+/*
+ kiconedit - a small graphics drawing program for the KDE
+
+ Copyright (C) 1998 Thomas Tanghus (tanghus@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 Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __KIE_VERSION_H__
+#define __KIE_VERSION_H__
+
+#define KIE_VERSION_MAJOR 0
+#define KIE_VERSION_MINOR 4
+#define KIE_VERSION_RELEASE 0
+#define KIE_VERSION ((KIE_VERSION_MAJOR * 100) + (KIE_VERSION_MINOR *10) + KIE_VERSION_RELEASE)
+#define KIE_VERSION_STRING "0.4.0"
+
+
+
+#endif // __KIE_VERSION_H__
+
+
+
diff --git a/kmrml/AUTHORS b/kmrml/AUTHORS
new file mode 100644
index 00000000..9e0745fb
--- /dev/null
+++ b/kmrml/AUTHORS
@@ -0,0 +1 @@
+Carsten Pfeiffer <pfeiffer@kde.org>
diff --git a/kmrml/ChangeLog b/kmrml/ChangeLog
new file mode 100644
index 00000000..9dbd3ea3
--- /dev/null
+++ b/kmrml/ChangeLog
@@ -0,0 +1,28 @@
+Uh er, looks like I didn't add all the other changes lately :} Sorry...
+
+Sun May 6 04:40:52 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * UI is a bit nicer now (arrangement of thumbnail items)
+
+ * it's possible to search by example, i.e. by right-clicking
+ on one or more images and selecting "search for similar images"
+
+ * tiny bit of code cleanup
+
+Sat May 5 02:30:21 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * argh, fixed the bug that files couldn't get downloaded by
+ clicking on them and that the statusbar isn't updated.
+ casts suck :} That took me a lot of time to find out :(
+
+ * added middle-button -> create new window
+
+ * scroll to top when loading a new page
+
+ * show standard popupmenu on right-click on image
+
+ * schedule the slaves instead of creating all at once
+
+Sam Apr 28 00:09:17 CEST 2001 - Carsten Pfeiffer <pfeiffer@kde.org>
+ o Initial Creation
+ didn't do any entries until something is actually working :)
diff --git a/kmrml/Makefile.am b/kmrml/Makefile.am
new file mode 100644
index 00000000..c48d9eb6
--- /dev/null
+++ b/kmrml/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = kmrml
diff --git a/kmrml/README b/kmrml/README
new file mode 100644
index 00000000..59f2dd9b
--- /dev/null
+++ b/kmrml/README
@@ -0,0 +1,95 @@
+kio_mrml and mrml_part
+
+Carsten Pfeiffer <pfeiffer@kde.org> 2001/05/03
+----------------------------------------------------------------------
+These are the sources for an mrml kioslave and an accompanying KPart.
+
+
+How does it work in Konqueror?
+==============================
+For now, the MrmlPart is rather a proof of concept, than a full blown
+MRML client.
+
+You can start the MrmlPart by entering an appropriate URL into Konqueror,
+e.g. mrml://user:pass@host.domain:port
+user, pass and domain are optional, so if you're running a server locally
+yourself, you can enter mrml://localhost to make Konqueror show the
+MrmlPart. If you don't have a running GIFT-server, you can try out
+mrml://viper.unige.ch:12790 as an example. Then, Konqueror will try to
+connect the server at the given URL and show you a list of
+image-collections the server has available. You can specify the number
+of images a query should return and you can hit the Search-button
+to actually start the query. If you don't give an image as example for
+the query, it will return random images from the collection.
+
+Shortly after hitting the Search-button, you will see a list of images
+as thumbnails. Below every image is a small rectangle showing the
+similarity of the image with the example image(s). The longer the
+rectangle, the better the match.
+
+Even easier than entering the mrml URL is right-clicking on an image
+in Konqueror and selecting "Search for similar images..." in the context
+menu. This will open up a new Konqueror window where the query will start
+automatically. By default, this will try to contact a local server, i.e
+mrml://localhost. You can configure different servers in the KControl
+Module (System -> Advanced Search). The last chosen server will be used
+for those queries.
+
+Note that a remote server surely can't access an image from your home
+direcory though. I have to think a little bit about the usability of
+this :) The greatest use of this is when you've indexed your files
+and running an own GIFT server anyway. Ideally, the server could be
+started on demand, when a query comes up.
+
+
+MrmlPart:
+=========
+ This KPart makes use of the mrml ioslave to provide a full MRML
+client. MRML, Multimedia Retrieval Markup Language (see
+http://www.mrml.net) is a means to query CBIR (Content Based Image
+Retrieval) servers. An OpenSource server is the GIFT (GNU Image
+Finding Tool), see www.mrml.net for downloading the GIFT.
+
+You can query for images by choosing one or more "example" images.
+The server will search for images that have similarities to the
+example(s) you gave. Queries can be refined by specifying relevance,
+i.e. by including and excluding parts of the previous search result.
+
+
+mrml ioslave:
+=============
+ Basically this is not much more than a slave for asynchronous
+transport of "data". With the URL, you can specify the user, password
+and port, as well as the url of the server to connect to.
+
+The data exchange of client <-> slave is done via metaData, with an
+"mrml_data" key. The data that the slave sends to the client is sent
+in one big chunk, after all the data has arrived at the slave. This
+could be made configurable later.
+
+With a little tuning, one could turn this into a generic slave
+which can transport any kind of data.
+
+[mrmlsearch]
+This little baby is called from Konqueror's popupmenu, when you hit
+"Search for similar images...". This program simply gets the URLs
+from Konqueror and creates a query of the form
+mrml://host.com/?relevant=url1;url2;url3;url4....
+It will use the currently selected host in the KControl module
+System -> Advanced Search to perform the query.
+
+mrmlsearch will then invoke "kfmclient openURL query" to start open
+a new Konqueror window and perform the query.
+
+
+Thanks go to Wolfgang Mller <Wolfgang.Mueller@cui.unige.ch> for his
+work on the GIFT and for making me write this frontend :) I really
+had a WOW-effect about the GIFT, when MrmlPart returned the first
+query results.
+
+New versions of this package can be found at
+http://devel-home.kde.org/~pfeiffer/kmrml/
+See http://www.mrml.net for downloading the GIFT and more information.
+
+Have fun,
+ Carsten Pfeiffer
diff --git a/kmrml/README.DEVELOPMENT b/kmrml/README.DEVELOPMENT
new file mode 100644
index 00000000..6fbe600d
--- /dev/null
+++ b/kmrml/README.DEVELOPMENT
@@ -0,0 +1,41 @@
+This file gives an overview of the structure of the kmrml package.
+
+kmrml consists of the following:
+
+- kio_mrml: an ioslave that is able to contact an mrml daemon (i.e. the GIFT)
+ and transports the data from the daemon to its master (i.e. the
+ MrmlPart) as XML (MRML, Multimedia Retrieval Markup Language)
+
+- MrmlPart: the konqueror-embeddable controller and view
+
+- mrmlsearch: a small tool that is e.g. called from Konqueror's ContextMenu
+ "Search for similar images" to start an image query.
+
+- kcontrol/: a KDE Control Center module for configuring parts of the GIFT,
+ i.e. indexing directories, specifying GIFT hosts, etc.
+
+- server/: a kded module, i.e. a tiny little daemon, that can be told via
+ DCOP to start, restart upon failure and automatically/manually
+ stop services. It is completely independent of GIFT/kmrml.
+ It is used to have one centralized place where the gift server
+ is started (ensuring this happens only once, restarting it upon
+ failure and stopping the gift after all kio_mrml instances
+ have been killed.
+
+lib/: common stuff used by more than one module
+
+
+Useful URLs:
+
+The MRML DTD:
+http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/gift/gift/dtd/mrml.dtd?rev=HEAD&content-type=text/plain
+
+The GIFT Homepage:
+http://www.gnu.org/software/gift
+
+The fer-de-lance project homepage, under which the GIFT and kmrml are living
+http://www.fer-de-lance.org
+
+
+2002/08/08
+Carsten Pfeiffer <pfeiffer@kde.org>
diff --git a/kmrml/TODO b/kmrml/TODO
new file mode 100644
index 00000000..85a9aa7f
--- /dev/null
+++ b/kmrml/TODO
@@ -0,0 +1,15 @@
+- Konqueror Properties dialog for indexing directory? Or just a context menu entry?
+- make use of BrowserExtension, provide the actions
+- contextmenu
+- better layouting?
+- better keyboard support
+- progress report from slave
+- transfer mrml in chunks as data arrives?
+- finish algorithm configuration
+- integrate with KPaint so you can paint an example image
+- integrate with kamera, so that images from your digicam will be indexed automatically
+- create Konq ContextMenu plugin instead of the ServiceMenu thing (mrmlsearch binary)
+- proper browserextension (restorestate/savestate, history, implement actions)
+- a panel applet or tray app KDirWatching indexable dirs and re-indexing on demand
+
+lots more probably
diff --git a/kmrml/example-session.mrml b/kmrml/example-session.mrml
new file mode 100644
index 00000000..27b5c009
--- /dev/null
+++ b/kmrml/example-session.mrml
@@ -0,0 +1,142 @@
+ <algorithm-list>
+ <algorithm
+ algorithm-name="Classical IDF"
+ algorithm-id="a-cidf"
+ algorithm-type="a-cidf" >
+ cui-block-texture-histogram="no"
+ collection-id="c-0-40-20-27-3-101-5-116-0"
+ cui-pr-percentage-of-features="70"
+ cui-block-texture-blocks="no"
+ cui-weighting-function="ClassicalIDF"
+ cui-base-type="inverted_file"
+ cui-block-color-histogram="no"
+ cui-block-color-blocks="no"
+ <query-paradigm-list>
+ <query-paradigm/>
+ </query-paradigm-list>
+
+
+ <property-sheet
+ send-type="none"
+ maxsubsetsize="1"
+ property-sheet-id="cui-p-1"
+ minsubsetsize="0"
+ property-sheet-type="subset" >
+ <property-sheet
+ caption="Modify default configuration"
+ send-type="none"
+ property-sheet-id="cui-p0"
+ property-sheet-type="set-element" >
+
+ <property-sheet
+ send-name="cui-pr-percentage-of-features"
+ send-value="70"
+ caption="Prune at % of features"
+ send-type="attribute"
+ from="20"
+ to="100"
+ step="5"
+ property-sheet-id="cui-p15"
+ property-sheet-type="numeric" />
+
+ <property-sheet
+ send-type="none"
+ maxsubsetsize="4"
+ property-sheet-id="cui-p1"
+ minsubsetsize="1"
+ property-sheet-type="subset" >
+ <property-sheet
+ send-name="cui-block-color-blocks"
+ send-value="yes"
+ caption="Colour blocks"
+ send-type="attribute"
+ property-sheet-id="cui-p12"
+ send-boolean-inverted="yes"
+ property-sheet-type="set-element" />
+ <property-sheet
+ send-name="cui-block-texture-blocks"
+ send-value="yes"
+ caption="Gabor blocks"
+ send-type="attribute"
+ property-sheet-id="cui-p14"
+ send-boolean-inverted="yes"
+ property-sheet-type="set-element" />
+ <property-sheet
+ send-name="cui-block-texture-histogram"
+ send-value="yes"
+ caption="Gabor histogram"
+ send-type="attribute"
+ property-sheet-id="cui-p13"
+ send-boolean-inverted="yes"
+ property-sheet-type="set-element" />
+ <property-sheet
+ send-name="cui-block-color-histogram"
+ send-value="yes"
+ caption="Colour histogram"
+ send-type="attribute"
+ property-sheet-id="cui-p11"
+ send-boolean-inverted="yes"
+ property-sheet-type="set-element" />
+ </property-sheet>
+ </property-sheet>
+ </property-sheet>
+
+
+ </algorithm>
+
+
+ <!-- -->
+
+
+ <algorithm cui-perl-query-function="processGIFTQueryCall" algorithm-id="a-perl" cui-perl-script-file="/home/gis/gift-embed-perl-modules.pl" cui-perl-package="CGIFTLink" collection-id="c-0-40-20-27-3-101-5-116-0" cui-perl-random-function="processGIFTRandomQueryCall" cui-weighting-function="ClassicalIDF" algorithm-name="Perl link" cui-base-type="perl" algorithm-type="a-perl" >
+ <query-paradigm-list>
+ <query-paradigm type="inverted-file" />
+ <query-paradigm type="perl-demo" />
+ </query-paradigm-list>
+
+
+ <property-sheet send-type="none" maxsubsetsize="1" property-sheet-id="cui-p-1" minsubsetsize="0" property-sheet-type="subset" >
+ <property-sheet caption="Modify default configuration" send-type="none" property-sheet-id="cui-p0" property-sheet-type="set-element" />
+ </property-sheet>
+ </algorithm>
+ <algorithm cui-block-texture-histogram="no" algorithm-id="adefault" collection-id="c-0-40-20-27-3-101-5-116-0" cui-pr-percentage-of-features="70" cui-block-texture-blocks="no" cui-weighting-function="ClassicalIDF" algorithm-name="Separate Normalisation" cui-base-type="multiple" cui-block-color-histogram="no" cui-block-color-blocks="no" algorithm-type="adefault" >
+ <algorithm cui-block-texture-histogram="yes" algorithm-id="sub1" cui-pr-percentage-of-features="100" cui-block-texture-blocks="yes" algorithm-name="sub1" cui-base-type="inverted_file" cui-block-color-blocks="yes" algorithm-type="sub1" />
+ <algorithm cui-block-texture-histogram="yes" algorithm-id="sub2" cui-block-texture-blocks="yes" algorithm-name="sub2" cui-base-type="inverted_file" cui-block-color-histogram="yes" algorithm-type="sub2" />
+ <algorithm algorithm-id="sub3" cui-pr-percentage-of-features="100" cui-block-texture-blocks="yes" algorithm-name="sub3" cui-base-type="inverted_file" cui-block-color-histogram="yes" cui-block-color-blocks="yes" algorithm-type="sub3" />
+ <algorithm cui-block-texture-histogram="yes" algorithm-id="sub4" algorithm-name="sub4" cui-base-type="inverted_file" cui-block-color-histogram="yes" cui-block-color-blocks="yes" algorithm-type="sub4" />
+ <query-paradigm-list>
+ <query-paradigm/>
+ </query-paradigm-list>
+ <property-sheet send-type="none" maxsubsetsize="1" property-sheet-id="cui-p-1" minsubsetsize="0" property-sheet-type="subset" >
+ <property-sheet caption="Modify default configuration" send-type="none" property-sheet-id="cui-p0" property-sheet-type="set-element" >
+ <property-sheet send-name="cui-pr-percentage-of-features" send-value="70" caption="Prune at % of features" send-type="attribute" from="20" to="100" step="5" property-sheet-id="cui-p15" property-sheet-type="numeric" />
+ <property-sheet send-type="none" maxsubsetsize="4" property-sheet-id="cui-p1" minsubsetsize="1" property-sheet-type="subset" >
+ <property-sheet send-name="cui-block-color-blocks" send-value="yes" caption="Colour blocks" send-type="attribute" property-sheet-id="cui-p12" send-boolean-inverted="yes" property-sheet-type="set-element" />
+ <property-sheet send-name="cui-block-texture-blocks" send-value="yes" caption="Gabor blocks" send-type="attribute" property-sheet-id="cui-p14" send-boolean-inverted="yes" property-sheet-type="set-element" />
+ <property-sheet send-name="cui-block-texture-histogram" send-value="yes" caption="Gabor histogram" send-type="attribute" property-sheet-id="cui-p13" send-boolean-inverted="yes" property-sheet-type="set-element" />
+ <property-sheet send-name="cui-block-color-histogram" send-value="yes" caption="Colour histogram" send-type="attribute" property-sheet-id="cui-p11" send-boolean-inverted="yes" property-sheet-type="set-element" />
+ </property-sheet>
+ </property-sheet>
+ </property-sheet>
+ </algorithm>
+ </algorithm-list>
+
+
+
+ <collection-list>
+ <collection
+ collection-name="images"
+ collection-id="c-0-40-20-27-3-101-5-116-0"
+ cui-inverted-file-location="InvertedFile.db"
+ cui-offset-file-location="InvertedFileOffset.db"
+ cui-algorithm-id-list-id="ail-inverted-file"
+ cui-feature-file-location="url2fts.xml"
+ cui-feature-description-location="InvertedFileFeatureDescription.db"
+ cui-base-dir="/home/gis/gift-indexing-data/images//"
+ cui-number-of-images="372" >
+ <query-paradigm-list>
+ <query-paradigm type="inverted-file" />
+ <query-paradigm type="perl-demo" />
+ </query-paradigm-list>
+ </collection>
+ </collection-list>
diff --git a/kmrml/kmrml.lsm b/kmrml/kmrml.lsm
new file mode 100644
index 00000000..4b2dfeb6
--- /dev/null
+++ b/kmrml/kmrml.lsm
@@ -0,0 +1,27 @@
+Begin3
+Title: MRML for KDE -- Content based image retrieval
+Version: 0.3.2
+Entered-date: 2001/06/05
+Description: MRML is short for Multimedia Retrieval Markup Language,
+ which defines a protocol for querying a server for images
+ based on their content. See http://www.mrml.net about MRML
+ and the GNU Image Finding Tool (GIFT), an MRML server.
+
+ This package consists of an mrml kio-slave that handles
+ the communication with the MRML server and a KPart to
+ be embedded e.g. into Konqueror.
+
+ With those, you can search for images by giving an example
+ image and let the server look up similar images. The query
+ result can be refined by giving positive/negative feedback.
+Keywords: Image retrieval, GIFT, MRML, Konqueror, KDE, Qt
+Author: Carsten Pfeiffer <pfeiffer@kde.org>
+Maintained-by: Carsten Pfeiffer <pfeiffer@kde.org>
+Home-page: http://devel-home.kde.org/~pfeiffer/kmrml/
+Alternate-site: ftp://ftp.kde.org/pub/kde/unstable/apps/utils
+Primary-site: http://devel-home.kde.org/~pfeiffer/kmrml/
+ xxxxxx kmrml-0.3.2.tgz
+ xxx kmrml-0.3.2.lsm
+Platform: Unix. Needs KDE 3.x
+Copying-policy: GPL
+End
diff --git a/kmrml/kmrml.spec b/kmrml/kmrml.spec
new file mode 100644
index 00000000..79dbab29
--- /dev/null
+++ b/kmrml/kmrml.spec
@@ -0,0 +1,62 @@
+%define version 0.3
+%define release 1
+%define serial 1
+%define prefix /opt/kde3
+
+Name: kmrml
+Summary: MRML for KDE -- Content based image retrieval
+Version: %{version}
+Release: %{release}
+Serial: %{serial}
+Source: http://devel-home.kde.org/~pfeiffer/kmrml/kmrml-%{version}.tgz
+URL: http://devel-home.kde.org/~pfeiffer/kmrml/
+Copyright: GPL
+Packager: Carsten Pfeiffer <pfeiffer@kde.org>
+Group: X11/KDE/Utilities
+BuildRoot: /tmp/kmrml-%{version}-root
+Prefix: %{prefix}
+
+%description
+MRML is short for Multimedia Retrieval Markup Language,
+which defines a protocol for querying a server for images
+based on their content. See http://www.mrml.net about MRML
+and the GNU Image Finding Tool (GIFT), an MRML server.
+
+This package consists of an mrml kio-slave that handles
+the communication with the MRML server and a KPart to
+be embedded e.g. into Konqueror.
+
+With those, you can search for images by giving an example
+image and let the server look up similar images. The query
+result can be refined by giving positive/negative feedback.
+
+Install with '--prefix $KDEDIR' unless you have KDE in /opt/kde3
+
+%prep
+rm -rf $RPM_BUILD_ROOT
+
+%setup -n kmrml-%{version}
+
+%build
+export KDEDIR=%{prefix}
+CXXFLAGS="$RPM_OPT_FLAGS -fno-exceptions -malign-functions=2 -malign-jumps=2 -malign-loops=2 -pipe" LDFLAGS=-s ./configure --prefix=%{prefix} --enable-final --disable-debug
+mkdir -p $RPM_BUILD_ROOT
+make
+
+%install
+make install DESTDIR=$RPM_BUILD_ROOT
+
+cd $RPM_BUILD_ROOT
+
+find . -type d | sed '1,2d;s,^\.,\%attr(-\,root\,root) \%dir ,' > $RPM_BUILD_DIR/file.list.%{name}
+
+find . -type f | sed 's,^\.,\%attr(-\,root\,root) ,' >> $RPM_BUILD_DIR/file.list.%{name}
+
+find . -type l | sed 's,^\.,\%attr(-\,root\,root) ,' >> $RPM_BUILD_DIR/file.list.%{name}
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+rm -f $RPM_BUILD_DIR/file.list.%{name}
+
+%files -f ../file.list.%{name}
+
diff --git a/kmrml/kmrml/Makefile.am b/kmrml/kmrml/Makefile.am
new file mode 100644
index 00000000..440e1123
--- /dev/null
+++ b/kmrml/kmrml/Makefile.am
@@ -0,0 +1,41 @@
+SUBDIRS = server lib kcontrol
+INCLUDES= -I$(top_srcdir)/kmrml/kmrml/lib $(all_includes)
+METASOURCES = AUTO
+
+LIB_KMRMLSTUFF = $(top_builddir)/kmrml/kmrml/lib/libkmrmlstuff.la
+
+####### Files
+
+kde_module_LTLIBRARIES = kio_mrml.la libkmrmlpart.la
+
+kio_mrml_la_SOURCES = mrml.cpp
+kio_mrml_la_LIBADD = $(LIB_KMRMLSTUFF) $(LIB_KIO)
+kio_mrml_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+
+libkmrmlpart_la_SOURCES = mrml_part.cpp mrml_view.cpp loader.cpp \
+ mrml_elements.cpp mrml_creator.cpp browser.cpp algorithmdialog.cpp \
+ collectioncombo.cpp algorithmcombo.cpp propertysheet.cpp
+libkmrmlpart_la_LIBADD = $(LIB_KMRMLSTUFF) $(LIB_KPARTS)
+libkmrmlpart_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN)
+
+services_DATA = mrml.protocol mrml_part.desktop
+servicesdir = $(kde_servicesdir)
+
+mimetypes_DATA = mrml.desktop
+mimetypesdir = $(kde_mimedir)/text
+
+servicemenu_DATA = mrml-servicemenu.desktop
+servicemenudir = $(kde_datadir)/konqueror/servicemenus
+
+#############################################
+bin_PROGRAMS =
+lib_LTLIBRARIES =
+kdeinit_LTLIBRARIES = mrmlsearch.la
+
+mrmlsearch_la_LIBADD = $(LIB_KMRMLSTUFF) $(LIB_KDECORE)
+mrmlsearch_la_LDFLAGS = $(all_libraries) -module -avoid-version
+mrmlsearch_la_SOURCES = mrmlsearch.cpp
+
+messages:
+ $(EXTRACTRC) */*.ui > rc.cpp
+ $(XGETTEXT) *.h *.cpp */*.cpp */*.h -o $(podir)/kmrml.pot
diff --git a/kmrml/kmrml/algorithmcombo.cpp b/kmrml/kmrml/algorithmcombo.cpp
new file mode 100644
index 00000000..b22556df
--- /dev/null
+++ b/kmrml/kmrml/algorithmcombo.cpp
@@ -0,0 +1,66 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "algorithmcombo.h"
+
+#include <kdatastream.h>
+
+using namespace KMrml;
+
+// ### copycat of CollectionCombo... moc can't handle templates unfortunately..
+// could use base-class MrmlElement....
+
+AlgorithmCombo::AlgorithmCombo( QWidget *parent, const char *name )
+ : KComboBox( false, parent, name ),
+ m_algorithms( 0L )
+{
+ connect( this, SIGNAL( activated( const QString& ) ),
+ SLOT( slotActivated( const QString& ) ));
+}
+
+AlgorithmCombo::~AlgorithmCombo()
+{
+}
+
+void AlgorithmCombo::setAlgorithms( const AlgorithmList *algorithms )
+{
+ assert( algorithms != 0L );
+
+ clear();
+ m_algorithms = algorithms;
+ insertStringList( algorithms->itemNames() );
+ // #### block signals here?
+}
+
+void AlgorithmCombo::setCurrent( const Algorithm& coll )
+{
+ setCurrentItem( coll.name() );
+}
+
+Algorithm AlgorithmCombo::current() const
+{
+ return m_algorithms->findByName( currentText() );
+}
+
+void AlgorithmCombo::slotActivated( const QString& name )
+{
+ Algorithm coll = m_algorithms->findByName( name );
+ emit selected( coll );
+}
+
+#include "algorithmcombo.moc"
diff --git a/kmrml/kmrml/algorithmcombo.h b/kmrml/kmrml/algorithmcombo.h
new file mode 100644
index 00000000..3e151933
--- /dev/null
+++ b/kmrml/kmrml/algorithmcombo.h
@@ -0,0 +1,54 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef ALGORITHMCOMBO_H
+#define ALGORITHMCOMBO_H
+
+#include <kcombobox.h>
+
+#include "mrml_elements.h"
+
+namespace KMrml
+{
+
+ class AlgorithmCombo : public KComboBox
+ {
+ Q_OBJECT
+
+ public:
+ AlgorithmCombo( QWidget *parent, const char *name = 0 );
+ ~AlgorithmCombo();
+
+ void setAlgorithms( const AlgorithmList * algorithms );
+ void setCurrent( const Algorithm& coll );
+
+ Algorithm current() const;
+
+ signals:
+ void selected( const Algorithm& );
+
+ private slots:
+ void slotActivated( const QString& );
+
+ private:
+ const AlgorithmList *m_algorithms;
+ };
+
+}
+
+#endif // ALGORITHMCOMBO_H
diff --git a/kmrml/kmrml/algorithmdialog.cpp b/kmrml/kmrml/algorithmdialog.cpp
new file mode 100644
index 00000000..cb62fd84
--- /dev/null
+++ b/kmrml/kmrml/algorithmdialog.cpp
@@ -0,0 +1,132 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "algorithmdialog.h"
+#include "algorithmcombo.h"
+#include "collectioncombo.h"
+
+#include <qhbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qscrollview.h>
+#include <qvbox.h>
+#include <qvgroupbox.h>
+
+#include <klocale.h>
+
+using namespace KMrml;
+
+class ScrollView : public QScrollView
+{
+public:
+ ScrollView(QWidget* parent = 0, const char* name = 0)
+ : QScrollView(parent, name)
+ {
+ setFrameStyle(QFrame::NoFrame);
+ m_frame = new QFrame(viewport(), "ScrollView::m_frame");
+ m_frame->setFrameStyle(QFrame::NoFrame);
+ addChild(m_frame, 0, 0);
+ };
+
+ QFrame* frame() {return m_frame;};
+
+protected:
+ virtual void viewportResizeEvent(QResizeEvent* ev)
+ {
+ QScrollView::viewportResizeEvent(ev);
+ m_frame->resize( kMax(m_frame->sizeHint().width(), ev->size().width()),
+ kMax(m_frame->sizeHint().height(), ev->size().height()));
+ };
+
+private:
+ QFrame* m_frame;
+};
+
+AlgorithmDialog::AlgorithmDialog( const AlgorithmList& algorithms,
+ const CollectionList& collections,
+ const Collection& currentColl,
+ QWidget *parent, const char *name )
+ : KDialogBase( parent, name, false, i18n("Configure Query Algorithms"),
+ Ok | Cancel, Ok, false ),
+ m_allAlgorithms( algorithms ),
+ m_collections( collections )
+{
+ QWidget *box = makeMainWidget();
+
+ QVBoxLayout *mainLayout = new QVBoxLayout( box, 0, KDialog::spacingHint(),
+ "mainLayout");
+
+ QHBoxLayout *collectionLayout = new QHBoxLayout( 0L, 0, 0, "coll layout");
+ collectionLayout->addWidget( new QLabel( i18n("Collection: "), box ));
+
+ m_collectionCombo = new CollectionCombo( box, "collection combo" );
+ m_collectionCombo->setCollections( &m_collections );
+ collectionLayout->addWidget( m_collectionCombo );
+
+ mainLayout->addLayout( collectionLayout );
+ mainLayout->addSpacing( 14 );
+
+ QHBox *algoHLayout = new QHBox( box );
+ (void) new QLabel( i18n("Algorithm: "), algoHLayout);
+ m_algoCombo = new AlgorithmCombo( algoHLayout, "algo combo" );
+
+ QVGroupBox *groupBox = new QVGroupBox( box, "groupBox" );
+ mainLayout->addWidget( groupBox );
+ algoHLayout->raise();
+
+ ScrollView *scrollView = new ScrollView( groupBox, "scroll view" );
+ m_view = scrollView->frame();
+ QVBoxLayout *viewLayout = new QVBoxLayout( scrollView );
+ viewLayout->setSpacing( KDialog::spacingHint() );
+
+
+ collectionChanged( currentColl );
+
+ connect( m_algoCombo, SIGNAL( selected( const Algorithm& ) ),
+ SLOT( initGUI( const Algorithm& ) ));
+ connect( m_collectionCombo, SIGNAL( selected( const Collection& ) ),
+ SLOT( collectionChanged( const Collection& ) ));
+
+ algoHLayout->adjustSize();
+ mainLayout->activate();
+ algoHLayout->move( groupBox->x() + 10, groupBox->y() - 12 );
+
+ box->setMinimumWidth( algoHLayout->sizeHint().width() +
+ 4 * KDialog::spacingHint() );
+}
+
+AlgorithmDialog::~AlgorithmDialog()
+{
+}
+
+void AlgorithmDialog::collectionChanged( const Collection& coll )
+{
+ m_algosForCollection = m_allAlgorithms.algorithmsForCollection( coll );
+ m_algoCombo->setAlgorithms( &m_algosForCollection );
+
+ initGUI( m_algoCombo->current() );
+}
+
+void AlgorithmDialog::initGUI( const Algorithm& algo )
+{
+ m_algo = algo;
+
+
+}
+
+#include "algorithmdialog.moc"
diff --git a/kmrml/kmrml/algorithmdialog.h b/kmrml/kmrml/algorithmdialog.h
new file mode 100644
index 00000000..740a95bf
--- /dev/null
+++ b/kmrml/kmrml/algorithmdialog.h
@@ -0,0 +1,60 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef ALGORITHMDIALOG_H
+#define ALGORITHMDIALOG_H
+
+#include <kdialogbase.h>
+
+#include "mrml_elements.h"
+
+namespace KMrml
+{
+ class AlgorithmCombo;
+ class CollectionCombo;
+
+ class AlgorithmDialog : public KDialogBase
+ {
+ Q_OBJECT
+
+ public:
+ AlgorithmDialog( const AlgorithmList&, const CollectionList&,
+ const Collection& currentColl,
+ QWidget *parent = 0, const char *name = 0 );
+ ~AlgorithmDialog();
+
+ private slots:
+ void collectionChanged( const Collection& );
+ void initGUI( const Algorithm& algo );
+
+ private:
+ Algorithm m_algo;
+ AlgorithmList m_allAlgorithms;
+ AlgorithmList m_algosForCollection;
+ CollectionList m_collections;
+
+ CollectionCombo *m_collectionCombo;
+ AlgorithmCombo *m_algoCombo;
+
+ QFrame *m_view;
+ };
+
+}
+
+#endif // ALGORITHMDIALOG_H
diff --git a/kmrml/kmrml/browser.cpp b/kmrml/kmrml/browser.cpp
new file mode 100644
index 00000000..f2453243
--- /dev/null
+++ b/kmrml/kmrml/browser.cpp
@@ -0,0 +1,63 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "browser.h"
+#include "mrml_part.h"
+
+#include <qscrollview.h>
+
+using namespace KMrml;
+
+Browser::Browser( MrmlPart *parent, const char *name )
+ : KParts::BrowserExtension( parent, name ),
+ m_part( parent )
+{
+
+}
+
+Browser::~Browser()
+{
+
+}
+
+void Browser::saveState( QDataStream& stream )
+{
+// BrowserExtension::saveState( stream );
+
+ m_part->saveState( stream );
+}
+
+void Browser::restoreState( QDataStream& stream )
+{
+// BrowserExtension::restoreState( stream );
+ // ### BrowserExtension::restoreState() calls openURL() at the end (arghh).
+
+ m_part->restoreState( stream );
+}
+
+int Browser::xOffset()
+{
+ return static_cast<QScrollView*>( m_part->widget())->contentsX();
+}
+
+int Browser::yOffset()
+{
+ return static_cast<QScrollView*>( m_part->widget())->contentsY();
+}
+
+#include "browser.moc"
diff --git a/kmrml/kmrml/browser.h b/kmrml/kmrml/browser.h
new file mode 100644
index 00000000..11661ed5
--- /dev/null
+++ b/kmrml/kmrml/browser.h
@@ -0,0 +1,48 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef BROWSER_H
+#define BROWSER_H
+
+#include <kparts/browserextension.h>
+
+namespace KMrml
+{
+ class MrmlPart;
+
+ class Browser : public KParts::BrowserExtension
+ {
+ Q_OBJECT
+
+ public:
+ Browser( MrmlPart *parent, const char *name );
+ ~Browser();
+
+ virtual void saveState( QDataStream& stream );
+ virtual void restoreState( QDataStream& stream );
+
+ virtual int xOffset();
+ virtual int yOffset();
+
+ private:
+ MrmlPart *m_part;
+ };
+
+}
+
+#endif // BROWSER_H
diff --git a/kmrml/kmrml/collectioncombo.cpp b/kmrml/kmrml/collectioncombo.cpp
new file mode 100644
index 00000000..b45d7ebf
--- /dev/null
+++ b/kmrml/kmrml/collectioncombo.cpp
@@ -0,0 +1,95 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "collectioncombo.h"
+
+#include <kdatastream.h>
+
+using namespace KMrml;
+
+CollectionCombo::CollectionCombo( QWidget *parent, const char *name )
+ : KComboBox( false, parent, name ),
+ m_collections( 0L )
+{
+ connect( this, SIGNAL( activated( const QString& ) ),
+ SLOT( slotActivated( const QString& ) ));
+}
+
+CollectionCombo::~CollectionCombo()
+{
+}
+
+void CollectionCombo::setCollections( const CollectionList *collections )
+{
+ assert( collections != 0L );
+
+ clear();
+ m_collections = collections;
+ insertStringList( collections->itemNames() );
+ // #### block signals here?
+}
+
+void CollectionCombo::setCurrent( const Collection& coll )
+{
+ setCurrentItem( coll.name() );
+}
+
+Collection CollectionCombo::current() const
+{
+ return m_collections->findByName( currentText() );
+}
+
+void CollectionCombo::slotActivated( const QString& name )
+{
+ Collection coll = m_collections->findByName( name );
+ emit selected( coll );
+}
+
+QDataStream& KMrml::operator<<( QDataStream& stream,
+ const CollectionCombo& combo )
+{
+ int count = combo.count();
+ stream << count;
+ for ( int i = 0; i < count; i++ )
+ stream << combo.text( i );
+
+ stream << combo.currentItem();
+ return stream;
+}
+
+QDataStream& KMrml::operator>>( QDataStream& stream, CollectionCombo& combo )
+{
+ combo.clear();
+
+ int count;
+ stream >> count;
+ QString text;
+ for ( int i = 0; i < count; i++ )
+ {
+ stream >> text;
+ combo.insertItem( text );
+ }
+
+ int current;
+ stream >> current;
+ combo.setCurrentItem( current );
+
+ return stream;
+}
+
+#include "collectioncombo.moc"
diff --git a/kmrml/kmrml/collectioncombo.h b/kmrml/kmrml/collectioncombo.h
new file mode 100644
index 00000000..3ca67a64
--- /dev/null
+++ b/kmrml/kmrml/collectioncombo.h
@@ -0,0 +1,57 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef COLLECTIONCOMBO_H
+#define COLLECTIONCOMBO_H
+
+#include <kcombobox.h>
+
+#include "mrml_elements.h"
+
+namespace KMrml
+{
+
+ class CollectionCombo : public KComboBox
+ {
+ Q_OBJECT
+
+ public:
+ CollectionCombo( QWidget *parent, const char *name = 0 );
+ ~CollectionCombo();
+
+ void setCollections( const CollectionList * collections );
+ void setCurrent( const Collection& coll );
+
+ Collection current() const;
+
+ signals:
+ void selected( const Collection& );
+
+ private slots:
+ void slotActivated( const QString& );
+
+ private:
+ const CollectionList *m_collections;
+ };
+
+ QDataStream& operator<<( QDataStream& stream, const CollectionCombo& );
+ QDataStream& operator>>( QDataStream& stream, CollectionCombo& );
+
+}
+
+#endif // COLLECTIONCOMBO_H
diff --git a/kmrml/kmrml/kcontrol/Makefile.am b/kmrml/kmrml/kcontrol/Makefile.am
new file mode 100644
index 00000000..c1330cfd
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/Makefile.am
@@ -0,0 +1,25 @@
+LIB_KMRMLSTUFF = $(top_builddir)/kmrml/kmrml/lib/libkmrmlstuff.la
+
+kde_module_LTLIBRARIES = kcm_kmrml.la
+
+kcm_kmrml_la_SOURCES = kcmkmrml.cpp mainpage.cpp indexer.cpp serverconfigwidget.ui indexcleaner.cpp
+kcm_kmrml_la_LDFLAGS = $(all_libraries) -module -avoid-version -no-undefined
+kcm_kmrml_la_LIBADD = $(LIB_KMRMLSTUFF) $(LIB_KIO)
+INCLUDES= -I$(top_srcdir)/kmrml/kmrml/lib $(all_includes)
+
+kcm_kmrml_la_METASOURCES = AUTO
+
+noinst_HEADERS = kcmkmrml.h mainpage.h serverconfigwidget.h indexer.h indexcleaner.h
+
+xdg_apps_DATA = kcmkmrml.desktop
+
+#check_PROGRAMS = indextest
+#indextest_SOURCES = indextest.cpp indexer.cpp
+#indextest_LDADD = $(LIB_KMRMLSTUFF) $(LIB_KDECORE)
+#indextest_LDFLAGS = $(all_libraries)
+
+
+
+#pics_DATA = play.png
+#picsdir = $(kde_datadir)/kcontrol/pics
+
diff --git a/kmrml/kmrml/kcontrol/indexcleaner.cpp b/kmrml/kmrml/kcontrol/indexcleaner.cpp
new file mode 100644
index 00000000..5f5eea93
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/indexcleaner.cpp
@@ -0,0 +1,96 @@
+#include <kdebug.h>
+#include <kprocess.h>
+
+#include <kmrml_config.h>
+#include "indexcleaner.h"
+
+#include <kdeversion.h>
+#if KDE_VERSION < 306
+ #define QUOTE( x ) x
+#else
+ #define QUOTE( x ) KProcess::quote( x )
+#endif
+
+using namespace KMrmlConfig;
+
+IndexCleaner::IndexCleaner( const QStringList& dirs,
+ const KMrml::Config *config,
+ QObject *parent, const char *name )
+ : QObject( parent, name ),
+ m_dirs( dirs ),
+ m_config( config ),
+ m_process( 0L )
+{
+ m_stepSize = 100 / dirs.count();
+}
+
+IndexCleaner::~IndexCleaner()
+{
+ if ( m_process )
+ {
+ m_process->kill();
+ delete m_process;
+ m_process = 0L;
+ }
+}
+
+void IndexCleaner::start()
+{
+ startNext();
+}
+
+void IndexCleaner::slotExited( KProcess *proc )
+{
+ emit advance( m_stepSize );
+
+ if ( !proc->normalExit() )
+ kdWarning() << "Error removing old indexed directory" << endl;
+
+ m_process = 0L;
+
+ startNext();
+}
+
+void IndexCleaner::startNext()
+{
+ if ( m_dirs.isEmpty() )
+ {
+ emit advance( 100 );
+ emit finished();
+ return;
+ }
+
+#if KDE_VERSION < 306
+ m_process = new KShellProcess();
+#else
+ m_process = new KProcess();
+ m_process->setUseShell( true );
+#endif
+ connect( m_process, SIGNAL( processExited( KProcess * )),
+ SLOT( slotExited( KProcess * ) ));
+
+ QString cmd = m_config->removeCollectionCommandLine();
+
+ QString dir = m_dirs.first();
+ m_dirs.pop_front();
+
+ int index = cmd.find( "%d" );
+ if ( index != -1 )
+ cmd.replace( index, 2, QUOTE( dir ) );
+ else // no %d? What else can we do?
+ cmd.append( QString::fromLatin1(" ") + QUOTE( dir ) );
+
+ *m_process << cmd;
+
+ if ( !m_process->start() )
+ {
+ kdWarning() << "Error starting: " << cmd << endl;
+
+ delete m_process;
+ m_process = 0L;
+
+ startNext();
+ }
+}
+
+#include "indexcleaner.moc"
diff --git a/kmrml/kmrml/kcontrol/indexcleaner.h b/kmrml/kmrml/kcontrol/indexcleaner.h
new file mode 100644
index 00000000..0ddcaac4
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/indexcleaner.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+** $Id$
+**
+** Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+**
+****************************************************************************/
+
+#ifndef INDEXCLEANER_H
+#define INDEXCLEANER_H
+
+#include <qobject.h>
+#include <qstringlist.h>
+
+class KProcess;
+
+namespace KMrml
+{
+ class Config;
+}
+
+namespace KMrmlConfig
+{
+ class IndexCleaner : public QObject
+ {
+ Q_OBJECT
+
+ public:
+ IndexCleaner( const QStringList& dirs, const KMrml::Config *config,
+ QObject *parent = 0, const char *name = 0 );
+ ~IndexCleaner();
+
+ void start();
+
+ signals:
+ void advance( int value );
+ void finished();
+
+ private slots:
+ void slotExited( KProcess * );
+
+ private:
+ int m_stepSize;
+ void startNext();
+
+ QStringList m_dirs;
+ const KMrml::Config *m_config;
+ KProcess *m_process;
+ };
+
+}
+
+
+#endif // INDEXCLEANER_H
diff --git a/kmrml/kmrml/kcontrol/indexer.cpp b/kmrml/kmrml/kcontrol/indexer.cpp
new file mode 100644
index 00000000..a3bb6b7d
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/indexer.cpp
@@ -0,0 +1,190 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qfile.h>
+#include <qregexp.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kprocio.h>
+
+#include "indexer.h"
+
+#include <kdeversion.h>
+#if KDE_VERSION < 306
+ #define QUOTE( x ) x
+#else
+ #define QUOTE( x ) KProcess::quote( x )
+#endif
+
+using namespace KMrmlConfig;
+
+Indexer::Indexer( const KMrml::Config* config,
+ QObject *parent, const char *name )
+ : QObject( parent, name ),
+ m_config( config ),
+ m_dirCount( 0 )
+{
+ m_process = new KProcIO();
+#if KDE_VERSION >= 306
+ m_process->setUseShell( true );
+#endif
+ m_process->setEnvironment( "LC_ALL", "C" );
+ connect( m_process, SIGNAL( processExited( KProcess * )),
+ SLOT( processFinished( KProcess * )));
+ connect( m_process, SIGNAL( readReady( KProcIO * )),
+ SLOT( slotCanRead( KProcIO * )) );
+}
+
+Indexer::~Indexer()
+{
+ delete m_process;
+}
+
+void Indexer::startIndexing( const QStringList& dirs )
+{
+ if ( m_process->isRunning() )
+ return;
+
+ m_dirs = dirs;
+ m_dirCount = dirs.count();
+ processNext();
+}
+
+void Indexer::processFinished( KProcess *proc )
+{
+ // still more directories to index?
+ if ( !m_dirs.isEmpty() )
+ processNext();
+ else
+ {
+ if ( proc->normalExit() )
+ emit finished( proc->exitStatus() );
+ else
+ emit finished( -1000 );
+ }
+}
+
+
+void Indexer::processNext()
+{
+ m_currentDir = m_dirs.first();
+ m_dirs.pop_front();
+ while ( m_currentDir.endsWith( "/" ) )
+ m_currentDir.remove( m_currentDir.length() -1, 1 );
+
+ m_process->resetAll();
+
+ QString cmd = m_config->addCollectionCommandLine().simplifyWhiteSpace().stripWhiteSpace();
+
+ // in the commandline, replace %d with the directory to process and
+ // %t with the thumbnail dir
+ int index = cmd.find( "%d" ); // ### QFile::encodeName()?
+ if ( index != -1 )
+ cmd.replace( index, 2, QUOTE( m_currentDir ) );
+ index = cmd.find( "%t" );
+ if ( index != -1 )
+ cmd.replace( index, 2, QUOTE(m_currentDir + "_thumbnails") );
+
+// qDebug("****** command: %s", cmd.latin1());
+#if KDE_VERSION >= 306
+ *m_process << cmd;
+#else
+ QStringList params = QStringList::split( ' ', cmd );
+ QStringList::Iterator it = params.begin();
+ for ( ; it != params.end(); ++it )
+ *m_process << *it;
+#endif
+
+ emit progress( 0, i18n("<qt>Next Folder: <br><b>%1</b>").arg( m_currentDir ));
+ m_process->start();
+}
+
+void Indexer::slotCanRead( KProcIO *proc )
+{
+ static const QString& sprogress = KGlobal::staticQString("PROGRESS: ");
+ static const QString& r1 = /* PROGRESS: 1 of 6 done (15%) */
+ KGlobal::staticQString( "(\\d+) of (\\d+) done \\((\\d+)%\\)" );
+
+ QString line;
+ int bytes = -1;
+ while ( (bytes = proc->readln( line )) != -1 )
+ {
+ // examine the output.
+ // We're looking for lines like:
+ // PROGRESS: 1 of 6 done (15%)
+ // PROGRESS: 99%
+ // PROGRESS: 100%
+
+ if ( !line.startsWith( sprogress ) ) // uninteresting debug output
+ continue;
+ else // parse output
+ {
+ // cut off "PROGRESS: "
+ line = line.mid( sprogress.length() );
+ line = line.simplifyWhiteSpace().stripWhiteSpace();
+// qDebug("*** START LINE ***");
+// qDebug("%s", line.latin1());
+// qDebug("*** END LINE ***");
+
+ // case 1: image processing, below 99%
+ if ( line.at( line.length() -1 ) == ')' )
+ {
+ QRegExp regxp( r1 );
+ int pos = regxp.search( line );
+ if ( pos > -1 )
+ {
+ QString currentFile = regxp.cap( 1 );
+ QString numFiles = regxp.cap( 2 );
+ QString percent = regxp.cap( 3 );
+
+// qDebug( "current: %s, number: %s, percent: %s", currentFile.latin1(), numFiles.latin1(), percent.latin1());
+ bool ok = false;
+ int perc = percent.toInt( &ok );
+ if ( ok )
+ {
+ uint dirsLeft = m_dirs.count();
+ QString message = i18n( "<qt>Processing folder %1 of %2: <br><b>%3</b><br>File %4 of %5.</qt>").arg( m_dirCount - dirsLeft ).arg( m_dirCount).arg( m_currentDir ).arg( currentFile ).arg( numFiles );
+ emit progress( perc, message );
+ }
+ }
+ }
+
+
+ // case 2: file writing, 99% or done, 100%
+ else
+ {
+ QString percent = line.left( line.length() - 1 );
+
+ bool ok = false;
+ int number = percent.toInt( &ok );
+ if ( ok )
+ {
+ QString message = (number == 100) ?
+ i18n("Finished.") : i18n("Writing data...");
+ emit progress( number, message );
+ }
+ else
+ kdDebug() << "Error while parsing gift-add-collection.pl output" << endl;
+ }
+ }
+ }
+}
+
+#include "indexer.moc"
diff --git a/kmrml/kmrml/kcontrol/indexer.h b/kmrml/kmrml/kcontrol/indexer.h
new file mode 100644
index 00000000..97335a70
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/indexer.h
@@ -0,0 +1,68 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef INDEXER_H
+#define INDEXER_H
+
+#include <qobject.h>
+
+#include <kmrml_config.h>
+
+class KProcess;
+class KProcIO;
+
+namespace KMrmlConfig
+{
+ class Indexer : public QObject
+ {
+ Q_OBJECT
+
+ public:
+ Indexer( const KMrml::Config *config,
+ QObject *parent = 0L, const char *name = 0 );
+ ~Indexer();
+
+ void startIndexing( const QStringList& dirs );
+ void stop();
+
+ signals:
+ void progress( int percent, const QString& text );
+ void finished( int returnCode );
+
+
+ private slots:
+ void slotCanRead( KProcIO * );
+ void processFinished( KProcess * );
+
+ private:
+ void processNext();
+
+ KProcIO *m_process;
+ const KMrml::Config *m_config;
+
+ uint m_dirCount;
+ QStringList m_dirs;
+ QString m_currentDir;
+
+ };
+
+
+}
+
+
+#endif // INDEXER_H
diff --git a/kmrml/kmrml/kcontrol/indextest.cpp b/kmrml/kmrml/kcontrol/indextest.cpp
new file mode 100644
index 00000000..161ca798
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/indextest.cpp
@@ -0,0 +1,43 @@
+#include "indexer.h"
+#include <kmrml_config.h>
+#include "indextest.moc"
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kglobal.h>
+
+using namespace KMrmlConfig;
+
+IndexTest::IndexTest()
+{
+ KMrml::Config *config = new KMrml::Config( KGlobal::config() );
+ Indexer *indexer = new Indexer( *config, this );
+ connect( indexer, SIGNAL( finished( bool )), SLOT( slotFinished( bool )));
+ connect( indexer, SIGNAL( progress( int, const QString& )),
+ SLOT( slotProgress( int, const QString& )));
+
+ indexer->startIndexing( "/home/gis/testcoll" );
+}
+
+IndexTest::~IndexTest()
+{
+
+}
+
+void IndexTest::slotFinished( bool success )
+{
+ qDebug("##### FINISHED: %i", success );
+}
+
+void IndexTest::slotProgress( int percent, const QString& message )
+{
+ qDebug("--- progress: %i: %s", percent, message.latin1());
+}
+
+int main( int argc, char **argv )
+{
+ KApplication app( argc, argv, "indextest" );
+ IndexTest *test = new IndexTest();
+
+ return app.exec();
+}
diff --git a/kmrml/kmrml/kcontrol/indextest.h b/kmrml/kmrml/kcontrol/indextest.h
new file mode 100644
index 00000000..5f85f5f1
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/indextest.h
@@ -0,0 +1,26 @@
+/****************************************************************************
+** $Id$
+**
+** Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+**
+****************************************************************************/
+
+#ifndef INDEXTEST_H
+#define INDEXTEST_H
+
+class IndexTest : public QObject
+{
+ Q_OBJECT
+
+public:
+ IndexTest();
+ ~IndexTest();
+
+private slots:
+ void slotFinished( bool success );
+ void slotProgress( int percent, const QString& message );
+
+};
+
+
+#endif // INDEXTEST_H
diff --git a/kmrml/kmrml/kcontrol/kcmkmrml.cpp b/kmrml/kmrml/kcontrol/kcmkmrml.cpp
new file mode 100644
index 00000000..43e46b03
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/kcmkmrml.cpp
@@ -0,0 +1,146 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qlabel.h>
+#include <qlayout.h>
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kdialog.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kgenericfactory.h>
+#include <kstandarddirs.h>
+#include <kurllabel.h>
+
+#include "kcmkmrml.h"
+#include <dcopclient.h>
+
+#include "mainpage.h"
+#include <version.h>
+
+using namespace KMrmlConfig;
+
+static const int COL_FILENAME = 1;
+
+typedef KGenericFactory<KCMKMrml, QWidget> MrmlFactory;
+K_EXPORT_COMPONENT_FACTORY( kcm_kmrml, MrmlFactory("kmrml") )
+
+KCMKMrml::KCMKMrml(QWidget *parent, const char *name, const QStringList & ):
+ KCModule(MrmlFactory::instance(), parent, name)
+{
+ KAboutData* ab = new KAboutData(
+ "kcmkmrml",
+ I18N_NOOP("KCMKMrml"),
+ KMRML_VERSION,
+ I18N_NOOP("Advanced Search Control Module"),
+ KAboutData::License_GPL,
+ I18N_NOOP( "Copyright 2002, Carsten Pfeiffer" ),
+ 0,
+ "http://devel-home.kde.org/~pfeiffer/kmrml/" );
+ ab->addAuthor( "Carsten Pfeiffer", 0, "pfeiffer@kde.org" );
+ setAboutData( ab );
+
+ QVBoxLayout *layout = new QVBoxLayout( this );
+ layout->setSpacing( KDialog::spacingHint() );
+ m_mainPage = new MainPage( this, "main page" );
+
+ layout->addWidget( m_mainPage );
+
+ connect( m_mainPage, SIGNAL( changed( bool ) ), SIGNAL( changed( bool )));
+
+ checkGiftInstallation();
+}
+
+KCMKMrml::~KCMKMrml()
+{
+}
+
+void KCMKMrml::checkGiftInstallation()
+{
+ QString giftExe = KGlobal::dirs()->findExe( "gift" );
+ QString giftAddCollectionExe = KGlobal::dirs()->findExe( "gift-add-collection.pl" );
+
+ if ( giftExe.isEmpty() || giftAddCollectionExe.isEmpty() )
+ {
+ QString errorMessage =
+ i18n("Cannot find executables \"gift\" and/or \"gift-add-collection.pl\" in the PATH.\n"
+ "Please install the \"GNU Image Finding Tool\".");
+ KMessageBox::error( this, errorMessage );
+ m_mainPage->hide();
+ QLabel *errorLabel = new QLabel( errorMessage, this );
+ errorLabel->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );
+ KURLLabel *urlLabel = new KURLLabel( "http://www.gnu.org/software/gift", QString::null, this );
+ urlLabel->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) );
+ connect( urlLabel, SIGNAL( leftClickedURL( const QString& )), kapp, SLOT( invokeBrowser( const QString& )) );
+ QLayout *l = layout();
+ l->addItem( new QSpacerItem( 0, 10, QSizePolicy::Minimum, QSizePolicy::Expanding ) );
+ l->add( errorLabel );
+ l->add( urlLabel );
+ l->addItem( new QSpacerItem( 0, 10, QSizePolicy::Minimum, QSizePolicy::Expanding ) );
+ errorLabel->show();
+ }
+ else
+ load();
+}
+
+void KCMKMrml::defaults()
+{
+ if (KMessageBox::warningContinueCancel(this,
+ i18n("Do you really want the configuration to be reset "
+ "to the defaults?"), i18n("Reset Configuration"), KStdGuiItem::cont())
+ != KMessageBox::Continue)
+ return;
+
+ m_mainPage->resetDefaults();
+
+ emit changed( true );
+}
+
+void KCMKMrml::load()
+{
+ m_mainPage->load();
+
+ emit changed( true );
+}
+
+void KCMKMrml::save()
+{
+ m_mainPage->save();
+
+ emit changed( false );
+}
+
+QString KCMKMrml::quickHelp() const
+{
+ return i18n("<h1>Image Index</h1>"
+ "KDE can make use of the GNU Image Finding Tool (GIFT) to "
+ "perform queries based not just on filenames, but on "
+ "file content."
+ "<p>For example, you can search for an image by giving an example "
+ "image that looks similar to the one you are looking for.</p>"
+ "<p>For this to work, your image directories need to be "
+ "indexed by, for example, the GIFT server.</p>"
+ "<p>Here you can configure the servers (you can also query "
+ "remote servers) and the directories to index.</p>"
+ );
+}
+
+#include "kcmkmrml.moc"
diff --git a/kmrml/kmrml/kcontrol/kcmkmrml.desktop b/kmrml/kmrml/kcontrol/kcmkmrml.desktop
new file mode 100644
index 00000000..d9dd1f02
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/kcmkmrml.desktop
@@ -0,0 +1,176 @@
+[Desktop Entry]
+Exec=kcmshell kcmkmrml
+Icon=folder_image
+Type=Application
+
+X-KDE-ModuleType=Library
+X-KDE-Library=kmrml
+
+Name=Image Index
+Name[ar]=فهرس الصور
+Name[bg]=Графичен индекс
+Name[br]=Meneger ar skeudenn
+Name[bs]=Indeks slika
+Name[ca]=Índex d'imatge
+Name[cs]=Rejstřík obrázků
+Name[cy]=Mynegai Delweddau
+Name[da]=Billedindeks
+Name[de]=Bildindex
+Name[el]=Ευρετήριο εικόνων
+Name[eo]=Bildindekso
+Name[es]=Índice de imágenes
+Name[et]=Pildiindeks
+Name[eu]=Irudiaren indizea
+Name[fa]=نمایۀ تصویر
+Name[fi]=Kuvahakemisto
+Name[fr]=Indexation des images
+Name[gl]=Índice imaxe
+Name[he]=אינדקס תמונות
+Name[hi]=छवि सूची
+Name[hu]=Képkereső
+Name[is]=Myndayfirlit
+Name[it]=Indice di immagini
+Name[ja]=画像インデックス
+Name[kk]=Кескіндер индексі
+Name[km]=លិបិក្រម​រូបភាព
+Name[lt]=Paveikslėlių rodyklė
+Name[ms]=Indeks Imej
+Name[nb]=Bildeindeks
+Name[nds]=Bildindex
+Name[ne]=छवि अनुक्रमणिका
+Name[nl]=Afbeeldingenindex
+Name[nn]=Biletindeks
+Name[nso]=Palo ya Ponagalo
+Name[pl]=Spis obrazków
+Name[pt]=Índice de Imagens
+Name[pt_BR]=Índice de Imagens
+Name[ro]=Index imagini
+Name[ru]=Индексирование изображений
+Name[se]=Govvaindeaksa
+Name[sk]=Katalóg obrázkov
+Name[sl]=Seznam slik
+Name[sr]=Индекс слика
+Name[sr@Latn]=Indeks slika
+Name[sv]=Bildindex
+Name[ta]=பிம்ப அட்டவணை
+Name[tg]=Индексатсия кардани тасвирот
+Name[th]=ดัชนีรูปภาพ
+Name[tr]=Resim İndeksi
+Name[uk]=Індекс зображень
+Name[uz]=Rasm indeksi
+Name[uz@cyrillic]=Расм индекси
+Name[ven]=Index ya tshifanyiso
+Name[wa]=Indecse des imådjes
+Name[xh]=Isalathisi Somfanekiso
+Name[zh_CN]=图像索引
+Name[zh_HK]=圖像索引
+Name[zh_TW]=影像索引
+Name[zu]=Isiqalo Sesithombe
+
+Comment=Configuration for using the GNU Image Finding Tool
+Comment[ar]=اعدادات لاستخدام أداة GNU للبحث عن الصور
+Comment[bg]=Настройване на програмата за индексиране и търсене на изображения
+Comment[bs]=Podešavanje za upotrebu GNU Alata za pronalaženje slika
+Comment[ca]=Configuració per a l'ús de l'eina de cerca d'imatges GNU
+Comment[cs]=Konfigurace používání nástroje GNU Image Finding Tool
+Comment[cy]=Ffurfweddiad am ddefnyddio'r Erfyn Canfod Delweddau GNU
+Comment[da]=Indstilling for brug af GNU Image Finding Tool
+Comment[de]=Einrichtung für die Benutzung des GNU Bildersuchwerkzeugs (GNU Image Finding Tool)
+Comment[el]=Ρύθμιση για τη χρήση του εργαλείου αναζήτησης εικόνων GIFT
+Comment[es]=Configuración para utilizar la herramienta de búsqueda de imágenes de GNU
+Comment[et]=Seadistused GNU pildileidmisrakenduse kasutamiseks
+Comment[eu]=GNU irudi aurkitzailea erabiltzeko konfigurazioa
+Comment[fa]=پیکربندی برای استفاده از ابزار یافتن تصویر GNU
+Comment[fi]=Asetukset GNU Image Finding Tool -ohjelman käyttöä varten
+Comment[fr]=Configuration pour l'utilisation du GNU Image Finding Tool
+Comment[gl]=Configuración para empregar a «GNU Image Finding Tool»
+Comment[he]=שינוי הגדרות כלי חיפוש התמונות של GNU
+Comment[hi]=ग्नू छवि खोज औज़ार को उपयोग करने के लिए कॉन्फ़िगरेशन
+Comment[hu]=A GIFT képkereső szolgáltatás beállításai
+Comment[is]=Stillingar til þess að nota GNU myndleitartólið
+Comment[it]=Configurazione della ricerca delle immagini
+Comment[ja]=GIFT (GNU Image Finding Tool) を使用するための設定
+Comment[kk]=GNU Image Finding Tool кескінді табу құралын пайдалану баптаулары
+Comment[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ​ដើម្បី​ប្រើ​ឧបករណ៍​ស្វែងរក​រូបភាព​របស់ GNU
+Comment[lt]=GNU paveikslėlių paieškos įrankio konfigūracija
+Comment[ms]=Konfigurasi untuk mengguna Alat Carian Imej GNU
+Comment[nb]=Tilpass GNU bildesøkingsverktøy
+Comment[nds]=Inrichten för dat GNU-Bildsöökwarktüüch
+Comment[ne]=GNU छवि फेला पार्ने उपकरण प्रयोगका लागि कन्फिगरेसन
+Comment[nl]=Configuratie voor het gebruik van de GNU Image Finding Tool
+Comment[nn]=Oppsett av GNU Image Finding Tool
+Comment[pl]=Konfiguracja Gifta (narzędzia do szukania obrazków GNU)
+Comment[pt]=Configuração da Ferramenta de Procura de Imagens da GNU
+Comment[pt_BR]=Configuração para o uso da Ferramenta de Procura de Imagens GNU
+Comment[ro]=Configurare pentru GNU Image Finding Tool
+Comment[ru]=Настройка использования программы поиска изображений GNU Image Finding Tool
+Comment[se]=Heivet GNU Image Finding Tool
+Comment[sk]=Konfigurácia pre GNU Image Finding Tool
+Comment[sl]=Nastavitve za uporabo orodja GNU za iskanje slik
+Comment[sr]=Подешавање коришћења GNU-овог алата за тражење слика
+Comment[sr@Latn]=Podešavanje korišćenja GNU-ovog alata za traženje slika
+Comment[sv]=Inställning för att använda GNU:s bildsökverktyg
+Comment[ta]=GNU பிம்ப தேடுதல் கருவியை பயன்படுத்துவதற்கான அமைப்பு
+Comment[tg]=Танзимоти истифодабарии барномаиҷустуҷӯи тасвироти GNU Image Finding Tool
+Comment[tr]=GNU Resim Bulma Aracı yapılandırması
+Comment[uk]=Налаштування засобу пошуку зображень GNU
+Comment[ven]=Nzudzanyo yau shumisa tshishumiswa tshau toda tshifanyiso tsha GNU
+Comment[wa]=Apontiaedje po-z eployî l' usteye di cweraedje d' imådjes di GNU
+Comment[xh]=Uqwalaselo lokusebenzisa Isixhobo Sokufumana Umfanekiso we GNU
+Comment[zh_CN]=使用 GNU 图像查找工具的配置
+Comment[zh_HK]=GNU 圖像搜尋工具的設定
+Comment[zh_TW]= GNU 影像搜尋工具組態
+Comment[zu]=Inhlanganiselo yokusebenzisa Ithuluzi Lokuthola Isithombe se-GNU
+
+Keywords=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR
+Keywords[ar]=صور,بحث,استعلام,Find,Gift,kmrml,mrml,CBIR
+Keywords[bg]=изображения, търсене, заявка, картинка, картинки, снимки, Images, Search, Query, Find, Gift, kmrml, mrml, CBIR
+Keywords[bs]=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR,slike,pretraga,upit,nađi
+Keywords[ca]=Imatges,Cerca,Consulta,Busca,Gift,kmrml,mrml,CBIR
+Keywords[cs]=Obrázky,Hledat,Dotaz,Najít,Gift,kmrml,mrml,CBIR
+Keywords[cy]=Delweddau,Chwilio,Canfod,Gift,kmrml,mrml,CBIR
+Keywords[da]=Billeder,Søgning,Forespørgsel,Find,Gave,kmrml,mrml,CBIR
+Keywords[de]=Bilder,Suche,Anfrage,finden,Geschenk,kmrml,mrml,CBIR
+Keywords[el]=Εικόνες,Αναζήτηση,Ερώτηση,Αναζήτηση,Gift,kmrml,mrml,CBIR
+Keywords[es]=Imágenes,Búsqueda,Consulta,Buscar,Gift,kmrml,mrml,CBIR
+Keywords[et]=pildid,otsing,päring,leia,Gift,kmrml,mrml,CBIR
+Keywords[eu]=Irudiak,Bilaketa,Bilatu,Galdetu,Gift,kmrml,mrml,CBIR
+Keywords[fa]=تصاویر، جستجو، پرس‌و‌جو، یافتن، Gift،kmrml،mrml،CBIR
+Keywords[fi]=Kuvat,Haku,Etsi,Lahja,kmrml,mrml,CBIR
+Keywords[fr]=Images,Recherche,Requête,Chercher,Gift,kmrml,mrml,CBIR
+Keywords[gl]=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR, imaxes, procura
+Keywords[he]=תמונות,חיפוש,שאילתה,Gift,kmrml,mrml,CBIR, Images,Search,Query,Find
+Keywords[hi]=छवि, खोज,ढूंढ,तलाश,उपहार,केएमआरएमएल,एमआरएमएल,सीबीआईआर
+Keywords[hu]=képek,keresés,lekérdezés,találat,Gift,kmrml,mrml,CBIR
+Keywords[it]=immagini,ricerca,trovare,Gift,kmrml,mrml,CBIR
+Keywords[ja]=画像,検索,クエリ,検索,Gift,kmrml,mrml,CBIR
+Keywords[km]=រូបភាព,ស្វែងរក,សួរ,រក,Gift,kmrml,mrml,CBIR
+Keywords[lt]=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR, paveikslėliai,paieška,paklausimas
+Keywords[nb]=Bilder,Søk,Spørringer,Finn,Gift,kmrml,mrml,CBIR
+Keywords[nds]=Biller,Söök,Anfraag,söken,Gaav,kmrml,mrml,CBIR
+Keywords[nl]=illustraties,figuren,figuur,afbeeldingen,plaatjes,zoeken,find,gift,kmrml,mrml,CBIR,images
+Keywords[nn]=bilete,søk,spørjing,finn,gåve,kmrml,mrml,CBIR
+Keywords[nso]=Diponagalo,Nyaka,Kgokgonego,Hwetsa,Mpho,kmrml,mrml,CBIR
+Keywords[pl]=Obrazki,Szukanie,Zapytanie,Szukaj,Gift,kmrml,mrml,CBIR
+Keywords[pt]=Imagens,Procurar,Pesquisar,Encontrar,Prenda,kmrml,mrml,CBIR
+Keywords[pt_BR]=Imagens,Busca,Consulta,Procurar,Presente,kmrml,mrml,CBIR
+Keywords[ro]=imagini,căutare,caută,interogare,găseşte,dar,kmrml,mrml,CBIR
+Keywords[ru]=изображения,поиск,запрос,kmrml,mrml,CBIR
+Keywords[sk]=Obrázky,Hľadanie,Dotazy,Nájsť,kmrml,mrml,CBIR
+Keywords[sl]=slike,iskanje,povpraševanje,išči,najdi,gift,kmrml,mrml,CBIR
+Keywords[sr]=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR,слике,тражи,упит,нађи,поклон
+Keywords[sr@Latn]=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR,slike,traži,upit,nađi,poklon
+Keywords[sv]=Bilder,Sök,Förfrågan,Hitta,Gift,kmrml,mrml,CBIR
+Keywords[ta]=பிம்பங்கள், தேடு, கேள்வி, கண்டுபிடி,பரிசு,kmrml,mrml,CBIR
+Keywords[tg]=тасвирот,ҷустуҷӯӣ,дархост,kmrml,mrml,CBIR
+Keywords[tr]=Resimler,Ara,Arama,kmrml,mrml,CBIR
+Keywords[uk]=зображення,пошук,запит,знайти,подарунок,kmrml,mrml,CBIR
+Keywords[ven]=Zwifanyiso,Toda,Mbudziso,Wana,Mpho,kmrml,mrml,CBIR
+Keywords[wa]=Imådjes,Cweri,Cweraedje,Trover,Gift,kmrml,mrml,CBIR
+Keywords[xh]=Imifanekiso,Uphendlo,Ubuzo,fumana,Isiphiwo,kmrml,mrml,CBIR
+Keywords[zh_CN]=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR,图像,搜索,查询,查找,礼物
+Keywords[zh_HK]=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR,圖像,搜尋,查詢,尋找
+Keywords[zh_TW]=Images,Search,Query,Find,Gift,kmrml,mrml,CBIR,影像,搜尋,查詢,尋找
+Keywords[zu]=Izithombe,Funa,Buza,Thola,Isipho,kmrml,mrml,CBIR
+
+Categories=Qt;KDE;Settings;X-KDE-settings-system;
diff --git a/kmrml/kmrml/kcontrol/kcmkmrml.h b/kmrml/kmrml/kcontrol/kcmkmrml.h
new file mode 100644
index 00000000..b0bb2443
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/kcmkmrml.h
@@ -0,0 +1,52 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KCMKMRML_H
+#define KCMKMRML_H
+
+#include <kcmodule.h>
+
+class KAboutData;
+class KURLRequester;
+
+namespace KMrmlConfig
+{
+ class MainPage;
+
+ class KCMKMrml : public KCModule
+ {
+ Q_OBJECT
+
+ public:
+ KCMKMrml(QWidget *parent, const char *name, const QStringList &);
+ virtual ~KCMKMrml();
+
+ virtual void defaults();
+ virtual void load();
+ virtual void save();
+ virtual QString quickHelp() const;
+
+ private:
+ void checkGiftInstallation();
+
+ MainPage *m_mainPage;
+ };
+
+}
+
+#endif
diff --git a/kmrml/kmrml/kcontrol/mainpage.cpp b/kmrml/kmrml/kcontrol/mainpage.cpp
new file mode 100644
index 00000000..514b9cf6
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/mainpage.cpp
@@ -0,0 +1,501 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qsizepolicy.h>
+#include <qtooltip.h>
+#include <qwidget.h>
+#include <qvgroupbox.h>
+
+#include <kcombobox.h>
+#include <kdialog.h>
+#include <keditlistbox.h>
+#include <kglobalsettings.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <knuminput.h>
+#include <kprogress.h>
+#include <kurlrequester.h>
+
+#include <kdeversion.h>
+#include <kdebug.h>
+#include <kio/slaveconfig.h>
+#include <kio/ioslave_defaults.h> // MAX_PORT_VALUE
+
+#include "serverconfigwidget.h"
+#include "mainpage.h"
+#include "indexer.h"
+#include "indexcleaner.h"
+
+#include <limits.h>
+#include <string.h>
+
+using namespace KMrmlConfig;
+
+
+MainPage::MainPage( QWidget *parent, const char *name )
+ : QVBox( parent, name ),
+ m_indexer( 0L ),
+ m_indexCleaner( 0L ),
+ m_progressDialog( 0L ),
+ m_performIndexing( false ),
+ m_locked( false )
+{
+ m_config = new KMrml::Config();
+ setSpacing( KDialog::spacingHint() );
+
+ QVGroupBox *gBox = new QVGroupBox( i18n("Indexing Server Configuration"),
+ this );
+ m_serverWidget = new ServerConfigWidget( gBox, "server config widget" );
+ QString tip = i18n("Hostname of the Indexing Server");
+ QToolTip::add( m_serverWidget->m_hostLabel, tip );
+ QToolTip::add( m_serverWidget->m_hostCombo, tip );
+
+ m_serverWidget->m_portInput->setRange( 0, MAX_PORT_VALUE );
+
+#if KDE_VERSION >= 306
+ KURLRequester *requester = new KURLRequester( this, "dir requester" );
+ requester->setMode( KFile::Directory | KFile::ExistingOnly | KFile::LocalOnly );
+ requester->setURL( KGlobalSettings::documentPath() );
+ connect( requester, SIGNAL( openFileDialog( KURLRequester * )),
+ SLOT( slotRequesterClicked( KURLRequester * )));
+
+ m_listBox = new KEditListBox( i18n("Folders to Be Indexed" ),
+ requester->customEditor(), this, "listbox",
+ false,
+ KEditListBox::Add | KEditListBox::Remove );
+#else
+ m_listBox = new KEditListBox( i18n("Folders to Be Indexed" ),
+ this, "listbox", false,
+ KEditListBox::Add | KEditListBox::Remove );
+#endif
+
+ connect( m_listBox, SIGNAL( changed() ), SLOT( slotDirectoriesChanged() ));
+ connect( m_serverWidget->m_hostCombo, SIGNAL( textChanged(const QString&)),
+ SLOT( slotHostChanged() ));
+ connect( m_serverWidget->m_portInput, SIGNAL( valueChanged( int )),
+ SLOT( slotPortChanged( int ) ));
+ connect ( m_serverWidget->m_useAuth, SIGNAL( toggled(bool) ),
+ SLOT( slotUseAuthChanged( bool ) ));
+ connect( m_serverWidget->m_userEdit, SIGNAL( textChanged( const QString&)),
+ SLOT( slotUserChanged( const QString& ) ));
+ connect( m_serverWidget->m_passEdit, SIGNAL( textChanged( const QString&)),
+ SLOT( slotPassChanged( const QString& ) ));
+
+ connect( m_serverWidget->m_addButton, SIGNAL( clicked() ),
+ SLOT( slotAddClicked() ));
+ connect( m_serverWidget->m_removeButton, SIGNAL( clicked() ),
+ SLOT( slotRemoveClicked() ));
+
+ connect( m_serverWidget->m_hostCombo, SIGNAL( activated( const QString& )),
+ SLOT( slotHostActivated( const QString& )));
+ connect( m_serverWidget->m_hostCombo, SIGNAL( returnPressed() ),
+ SLOT( slotAddClicked() ));
+
+ connect( m_serverWidget->m_autoPort, SIGNAL( toggled( bool ) ),
+ SLOT( slotAutoPortChanged( bool ) ));
+
+ m_serverWidget->m_hostCombo->setTrapReturnKey( true );
+ m_serverWidget->m_hostCombo->setFocus();
+}
+
+MainPage::~MainPage()
+{
+ delete m_config;
+}
+
+void MainPage::resetDefaults()
+{
+ blockSignals( true );
+
+ initFromSettings( KMrml::ServerSettings::defaults() );
+
+ m_serverWidget->m_hostCombo->clear();
+ m_serverWidget->m_hostCombo->insertItem( m_settings.host );
+
+ m_listBox->clear();
+
+ // slotHostChanged(); not necessary, will be called by Qt signals
+ slotUseAuthChanged( m_serverWidget->m_useAuth->isChecked() );
+
+ blockSignals( false );
+}
+
+void MainPage::load()
+{
+ blockSignals( true );
+
+ initFromSettings( m_config->defaultSettings() );
+
+ m_serverWidget->m_hostCombo->clear();
+ m_serverWidget->m_hostCombo->insertStringList( m_config->hosts() );
+ m_serverWidget->m_hostCombo->setCurrentItem( m_settings.host );
+
+ m_listBox->clear();
+ m_listBox->insertStringList( m_config->indexableDirectories() );
+
+ // slotHostChanged(); not necessary, will be called by Qt signals
+ slotUseAuthChanged( m_serverWidget->m_useAuth->isChecked() );
+
+ blockSignals( false );
+}
+
+void MainPage::save()
+{
+ m_config->addSettings( m_settings );
+ m_config->setDefaultHost( m_settings.host );
+
+ QStringList indexDirs = m_listBox->items();
+ QStringList oldIndexDirs = m_config->indexableDirectories();
+ QStringList removedDirs = difference( oldIndexDirs, indexDirs );
+
+ m_config->setIndexableDirectories( indexDirs );
+ if ( indexDirs.isEmpty() )
+ KMessageBox::information( this,
+ i18n("You did not specify any folders to "
+ "be indexed. This means you will be "
+ "unable to perform queries on your "
+ "computer."),
+ "kcmkmrml_no_directories_specified" );
+
+ if ( m_config->sync() )
+ KIO::SlaveConfig::self()->reset();
+
+ processIndexDirs( removedDirs );
+}
+
+QStringList MainPage::difference( const QStringList& oldIndexDirs,
+ const QStringList& newIndexDirs ) const
+{
+ QStringList result;
+
+ QString slash = QString::fromLatin1("/");
+ QStringList::ConstIterator oldIt = oldIndexDirs.begin();
+ QString oldDir, newDir;
+
+ for ( ; oldIt != oldIndexDirs.end(); oldIt++ )
+ {
+ bool removed = true;
+ oldDir = *oldIt;
+
+ while ( oldDir.endsWith( slash ) ) // remove slashes
+ oldDir.remove( oldDir.length() - 1, 1 );
+
+ QStringList::ConstIterator newIt = newIndexDirs.begin();
+ for ( ; newIt != newIndexDirs.end(); newIt++ )
+ {
+ newDir = *newIt;
+ while ( newDir.endsWith( slash ) ) // remove slashes
+ newDir.remove( newDir.length() - 1, 1 );
+
+ if ( oldDir == newDir )
+ {
+ removed = false;
+ break;
+ }
+ }
+
+ if ( removed )
+ result.append( *oldIt ); // not oldDir -- maybe gift needs slashes
+ }
+
+ return result;
+}
+
+void MainPage::initFromSettings( const KMrml::ServerSettings& settings )
+{
+ m_settings = settings;
+
+ m_locked = true;
+
+ m_serverWidget->m_portInput->setValue( settings.configuredPort );
+ m_serverWidget->m_autoPort->setChecked( settings.autoPort );
+ m_serverWidget->m_useAuth->setChecked( settings.useAuth );
+ m_serverWidget->m_userEdit->setText( settings.user );
+ m_serverWidget->m_passEdit->setText( settings.pass );
+
+ m_locked = false;
+}
+
+void MainPage::slotHostActivated( const QString& host )
+{
+ // implicitly save the current settings when another host was chosen
+ m_config->addSettings( m_settings );
+
+ initFromSettings( m_config->settingsForHost( host ) );
+}
+
+void MainPage::slotHostChanged()
+{
+ QString host = m_serverWidget->m_hostCombo->currentText();
+ m_listBox->setEnabled( (host == "localhost") );
+
+ KMrml::ServerSettings settings = m_config->settingsForHost( host );
+ enableWidgetsFor( settings );
+}
+
+void MainPage::slotUseAuthChanged( bool enable )
+{
+ m_settings.useAuth = enable;
+ m_serverWidget->m_userEdit->setEnabled( enable );
+ m_serverWidget->m_passEdit->setEnabled( enable );
+
+ if ( enable )
+ m_serverWidget->m_userEdit->setFocus();
+
+ if ( !m_locked )
+ changed();
+}
+
+void MainPage::slotUserChanged( const QString& user )
+{
+ if ( m_locked )
+ return;
+
+ m_settings.user = user;
+ changed();
+}
+
+void MainPage::slotPassChanged( const QString& pass )
+{
+ if ( m_locked )
+ return;
+
+ m_settings.pass = pass;
+ changed();
+}
+
+void MainPage::slotPortChanged( int port )
+{
+ if ( m_locked )
+ return;
+
+ m_settings.configuredPort = (unsigned short int) port;
+ changed();
+}
+
+void MainPage::slotAutoPortChanged( bool on )
+{
+ if ( m_locked )
+ return;
+
+ m_settings.autoPort = on;
+ m_serverWidget->m_portInput->setEnabled( !on );
+ changed();
+}
+
+void MainPage::slotRequesterClicked( KURLRequester *requester )
+{
+ static bool init = true;
+ if ( !init )
+ return;
+
+ init = false;
+
+ requester->setCaption(i18n("Select Folder You Want to Index"));
+}
+
+void MainPage::slotAddClicked()
+{
+ QString host = m_serverWidget->m_hostCombo->currentText();
+ m_settings.host = host;
+
+ m_config->addSettings( m_settings );
+ m_serverWidget->m_hostCombo->insertItem( host );
+ m_serverWidget->m_hostCombo->setCurrentItem( host );
+
+ enableWidgetsFor( m_settings );
+}
+
+void MainPage::slotRemoveClicked()
+{
+ QString host = m_serverWidget->m_hostCombo->currentText();
+ if ( host.isEmpty() ) // should never happen
+ return;
+
+ m_config->removeSettings( host );
+ m_serverWidget->m_hostCombo->removeItem( m_serverWidget->m_hostCombo->currentItem() );
+ m_serverWidget->m_hostCombo->setCurrentItem( 0 );
+
+ host = m_serverWidget->m_hostCombo->currentText();
+ initFromSettings( m_config->settingsForHost( host ) );
+}
+
+void MainPage::enableWidgetsFor( const KMrml::ServerSettings& settings )
+{
+ QString host = settings.host;
+ bool enableWidgets = (m_config->hosts().findIndex( host ) > -1);
+ m_serverWidget->m_addButton->setEnabled(!enableWidgets && !host.isEmpty());
+ m_serverWidget->m_removeButton->setEnabled( enableWidgets &&
+ !host.isEmpty() &&
+ host != "localhost" );
+
+ m_serverWidget->m_autoPort->setEnabled( host == "localhost" );
+ bool portEnable = enableWidgets && (settings.autoPort ||
+ !m_serverWidget->m_autoPort->isEnabled());
+ m_serverWidget->m_portLabel->setEnabled( portEnable && !m_serverWidget->m_autoPort->isChecked());
+ m_serverWidget->m_portInput->setEnabled( portEnable && !m_serverWidget->m_autoPort->isChecked());
+
+ m_serverWidget->m_useAuth->setEnabled( enableWidgets );
+ m_serverWidget->m_userLabel->setEnabled( enableWidgets );
+ m_serverWidget->m_passLabel->setEnabled( enableWidgets );
+ m_serverWidget->m_userEdit->setEnabled( enableWidgets );
+ m_serverWidget->m_passEdit->setEnabled( enableWidgets );
+
+ bool useAuth = m_serverWidget->m_useAuth->isChecked();
+ m_serverWidget->m_userEdit->setEnabled( useAuth );
+ m_serverWidget->m_passEdit->setEnabled( useAuth );
+}
+
+void MainPage::slotDirectoriesChanged()
+{
+ m_performIndexing = true;
+ changed();
+}
+
+void MainPage::processIndexDirs( const QStringList& removeDirs )
+{
+ // ### how to remove indexed directories?
+ if ( !m_performIndexing ||
+ (removeDirs.isEmpty() && m_config->indexableDirectories().isEmpty()) )
+ return;
+
+ delete m_progressDialog;
+ delete m_indexCleaner;
+ m_indexCleaner = 0L;
+ delete m_indexer;
+ m_indexer = 0L;
+
+ m_progressDialog = new KProgressDialog( this, "indexing dialog",
+ i18n("Removing old Index Files"),
+ i18n("Processing..."),
+ true );
+ m_progressDialog->setAutoClose( false );
+ m_progressDialog->setMinimumWidth( 300 );
+ connect( m_progressDialog, SIGNAL( cancelClicked() ),
+ SLOT( slotCancelIndexing() ));
+
+ // argh -- don't automatically show the dialog
+ m_progressDialog->setMinimumDuration( INT_MAX );
+
+ if ( !removeDirs.isEmpty() )
+ {
+ m_indexCleaner = new IndexCleaner( removeDirs, m_config, this );
+ connect( m_indexCleaner, SIGNAL( advance( int ) ),
+ m_progressDialog->progressBar(), SLOT( advance( int ) ));
+ connect( m_indexCleaner, SIGNAL( finished() ),
+ SLOT( slotMaybeIndex() ) );
+ m_indexCleaner->start();
+ }
+ else
+ {
+ slotMaybeIndex();
+ }
+ if ( m_progressDialog )
+ m_progressDialog->exec();
+}
+
+void MainPage::slotMaybeIndex()
+{
+ delete m_indexCleaner; // Stop in the name of the law!
+ m_indexCleaner = 0L;
+
+ m_progressDialog->setLabel( i18n("Finished.") );
+
+ if ( m_config->indexableDirectories().isEmpty() )
+ return;
+
+ if ( KMessageBox::questionYesNo( this,
+ i18n("The settings have been saved. Now, "
+ "the configured directories need to "
+ "be indexed. This may take a while. "
+ "Do you want to do this now?"),
+ i18n("Start Indexing Now?"),
+ i18n("Index"), i18n("Do Not Index"),
+ "ask_startIndexing"
+ ) != KMessageBox::Yes )
+ return;
+ m_progressDialog->setCaption( i18n("Indexing Folders") );
+ m_progressDialog->setLabel( i18n("Processing...") );
+ m_progressDialog->progressBar()->setProgress( 0 );
+
+ // do the indexing
+ m_indexer = new Indexer( m_config, this, "Indexer" );
+ connect( m_indexer, SIGNAL( progress( int, const QString& )),
+ SLOT( slotIndexingProgress( int, const QString& ) ));
+ connect( m_indexer, SIGNAL( finished( int )),
+ SLOT( slotIndexingFinished( int ) ));
+ m_indexer->startIndexing( m_config->indexableDirectories() );
+}
+
+
+void MainPage::slotIndexingProgress( int percent, const QString& message )
+{
+ m_progressDialog->progressBar()->setValue( percent );
+ m_progressDialog->setLabel( message );
+}
+
+void MainPage::slotIndexingFinished( int returnCode )
+{
+ if ( returnCode != 0 )
+ {
+ QString syserr;
+ if ( returnCode == 127 )
+ syserr = i18n("Is the \"GNU Image Finding Tool\" properly installed?");
+ else
+ {
+ char *err = strerror( returnCode );
+ if ( err )
+ syserr = QString::fromLocal8Bit( err );
+ else
+ syserr = i18n("Unknown error: %1").arg( returnCode );
+ }
+
+ KMessageBox::detailedError( this, i18n("An error occurred during indexing. The index might be invalid."),
+ syserr, i18n("Indexing Aborted") );
+ }
+ else
+ m_performIndexing = false;
+
+ delete m_indexer;
+ m_indexer = 0L;
+ if ( m_progressDialog )
+ {
+ m_progressDialog->deleteLater();
+ m_progressDialog = 0L;
+ }
+}
+
+void MainPage::slotCancelIndexing()
+{
+ delete m_indexCleaner;
+ m_indexCleaner = 0L;
+
+ delete m_indexer;
+ m_indexer = 0L;
+ if ( m_progressDialog )
+ {
+ m_progressDialog->deleteLater();
+ m_progressDialog = 0L;
+ }
+}
+
+
+#include "mainpage.moc"
diff --git a/kmrml/kmrml/kcontrol/mainpage.h b/kmrml/kmrml/kcontrol/mainpage.h
new file mode 100644
index 00000000..e91b4168
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/mainpage.h
@@ -0,0 +1,109 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef MAINPAGE_H
+#define MAINPAGE_H
+
+#include <qvbox.h>
+
+#include <kmrml_config.h>
+
+class QCheckBox;
+class KComboBox;
+class KEditListBox;
+class KIntNumInput;
+class KLineEdit;
+class KProgressDialog;
+class KURLRequester;
+
+namespace KMrml
+{
+ class Config;
+}
+
+class ServerConfigWidget;
+
+namespace KMrmlConfig
+{
+ class Indexer;
+ class IndexCleaner;
+
+ class MainPage : public QVBox
+ {
+ Q_OBJECT
+
+ public:
+ MainPage( QWidget *parent, const char *name );
+ ~MainPage();
+
+ void resetDefaults();
+ void load();
+ void save();
+
+ signals:
+ void changed( bool );
+
+ private slots:
+ void changed() { emit changed( true ); }
+ void slotRequesterClicked( KURLRequester * );
+ void slotHostChanged();
+ void slotUseAuthChanged( bool );
+ void slotUserChanged( const QString& );
+ void slotPassChanged( const QString& );
+ void slotPortChanged( int );
+ void slotAutoPortChanged( bool );
+
+ void slotAddClicked();
+ void slotRemoveClicked();
+
+ void slotHostActivated( const QString& );
+
+ void slotDirectoriesChanged();
+
+ void slotMaybeIndex();
+ void slotIndexingProgress( int percent, const QString& message );
+ void slotIndexingFinished( int returnCode );
+ void slotCancelIndexing();
+
+
+ private:
+ void enableWidgetsFor( const KMrml::ServerSettings& settings );
+ void initFromSettings( const KMrml::ServerSettings& settings );
+
+ void processIndexDirs( const QStringList& removedDirs );
+
+ QStringList difference( const QStringList& oldIndexDirs,
+ const QStringList& newIndexDirs ) const;
+
+ ServerConfigWidget *m_serverWidget;
+ KEditListBox *m_listBox;
+ KMrml::Config *m_config;
+ KMrmlConfig::Indexer *m_indexer;
+ KMrmlConfig::IndexCleaner *m_indexCleaner;
+ KProgressDialog *m_progressDialog;
+
+ KMrml::ServerSettings m_settings;
+ bool m_performIndexing;
+ bool m_locked;
+ };
+
+}
+
+
+
+#endif // MAINPAGE_H
diff --git a/kmrml/kmrml/kcontrol/serverconfigwidget.ui b/kmrml/kmrml/kcontrol/serverconfigwidget.ui
new file mode 100644
index 00000000..e0a08007
--- /dev/null
+++ b/kmrml/kmrml/kcontrol/serverconfigwidget.ui
@@ -0,0 +1,272 @@
+<!DOCTYPE UI><UI version="3.0" stdsetdef="1">
+<class>ServerConfigWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>ServerConfigWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>455</width>
+ <height>321</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout7</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLayoutWidget" row="0" column="1">
+ <property name="name">
+ <cstring>Layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="KComboBox">
+ <property name="name">
+ <cstring>m_hostCombo</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="editable">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_addButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Add</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>m_removeButton</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Remove</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget" row="1" column="1">
+ <property name="name">
+ <cstring>Layout6</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="KIntSpinBox">
+ <property name="name">
+ <cstring>m_portInput</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>TCP/IP Port Number of the Indexing Server</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_autoPort</cstring>
+ </property>
+ <property name="text">
+ <string>Au&amp;to</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Tries to automatically determine the port. This works only for local servers.</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>200</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>m_hostLabel</cstring>
+ </property>
+ <property name="text">
+ <string>Ho&amp;stname:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>m_hostCombo</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>m_portLabel</cstring>
+ </property>
+ <property name="text">
+ <string>P&amp;ort:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>m_portInput</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_useAuth</cstring>
+ </property>
+ <property name="text">
+ <string>Per&amp;form authentication</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout12</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout6</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>m_userLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Username:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>m_userEdit</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>m_passEdit</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>m_passLabel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Password:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>m_passEdit</cstring>
+ </property>
+ </widget>
+ <widget class="KLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>m_userEdit</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<tabstops>
+ <tabstop>m_hostCombo</tabstop>
+ <tabstop>m_addButton</tabstop>
+ <tabstop>m_removeButton</tabstop>
+ <tabstop>m_portInput</tabstop>
+ <tabstop>m_useAuth</tabstop>
+ <tabstop>m_userEdit</tabstop>
+ <tabstop>m_passEdit</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kmrml/kmrml/lib/Makefile.am b/kmrml/kmrml/lib/Makefile.am
new file mode 100644
index 00000000..4201f04f
--- /dev/null
+++ b/kmrml/kmrml/lib/Makefile.am
@@ -0,0 +1,11 @@
+noinst_LTLIBRARIES = libkmrmlstuff.la
+libkmrmlstuff_la_SOURCES = kmrml_config.cpp mrml_shared.cpp mrml_utils.cpp\
+watcher_stub.cpp
+noinst_HEADERS = kmrml_config.h mrml_shared.h mrml_utils.h watcher_stub.h
+
+METASOURCES = AUTO
+
+libkmrmlstuff_la_LDFLAGS = $(all_libraries) -no-undefined
+libkmrmlstuff_la_LIBADD = $(LIB_KDECORE)
+
+INCLUDES = -I$(top_srcdir) $(all_includes)
diff --git a/kmrml/kmrml/lib/kmrml_config.cpp b/kmrml/kmrml/lib/kmrml_config.cpp
new file mode 100644
index 00000000..a88e8404
--- /dev/null
+++ b/kmrml/kmrml/lib/kmrml_config.cpp
@@ -0,0 +1,339 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qdir.h>
+#include <qfile.h>
+#include <qtextcodec.h>
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kprocess.h>
+#include <kstandarddirs.h>
+
+#include "kmrml_config.h"
+
+#include <kdeversion.h>
+#if KDE_VERSION < 307
+ #define QUOTE( x ) x
+#else
+ #define QUOTE( x ) KProcess::quote( x )
+#endif
+
+using namespace KMrml;
+
+// #define DEFAULT_ADDCOLLECTION_CMD "gift-add-collection.pl --thumbnail-dir=%t --local-encoding %d"
+#define DEFAULT_ADDCOLLECTION_CMD "gift-add-collection.pl --gift-home=%h --thumbnail-dir=%t --local-encoding=%e %d"
+#define DEFAULT_REMOVECOLLECTION_CMD "gift-add-collection.pl --gift-home=%h --local-encoding=%e --remove-collection %d"
+
+#define DEFAULT_MRMLD_CMD "gift --port %p --datadir %d"
+#define DEFAULT_MRMLD_CMD_AUTOPORT "gift --datadir %d"
+
+#define CONFIG_GROUP "MRML Settings"
+#define DEFAULT_HOST "localhost"
+#define DEFAULT_USER "kmrml"
+#define DEFAULT_PASS "none"
+#define DEFAULT_AUTH false
+#define DEFAULT_AUTOPORT true
+const int DEFAULT_PORT = 12789;
+
+Config::Config()
+{
+ m_ownConfig = new KConfig( "kio_mrmlrc", false, false );
+ m_config = m_ownConfig;
+
+ init();
+}
+
+Config::Config( KConfig *config )
+ : m_config( config ),
+ m_ownConfig( 0L )
+{
+ init();
+}
+
+Config::~Config()
+{
+ delete m_ownConfig;
+}
+
+void Config::init()
+{
+ m_config->setGroup( CONFIG_GROUP );
+ m_defaultHost = m_config->readEntry( "Default Host" );
+ if ( m_defaultHost.isEmpty() )
+ m_defaultHost = DEFAULT_HOST;
+
+ m_hostList = m_config->readListEntry( "Host List" );
+ if ( m_hostList.isEmpty() )
+ m_hostList.append( DEFAULT_HOST );
+
+ m_serverStartedIndividually =
+ m_config->readBoolEntry( "ServerStartedIndividually", false );
+}
+
+bool Config::sync()
+{
+ bool notifySlaves = m_config->isDirty();
+ m_config->sync();
+ return notifySlaves;
+
+ // This moved to kcontrol/MainPage::save() so we don't have to link against
+ // KIO and need a full KApplication instance to work (so that the tiny
+ // mrmlsearch binary can also use this class)
+ // tell the ioslaves about the new configuration
+// if ( notifySlaves )
+// KIO::SlaveConfig::self()->reset();
+}
+
+void Config::setDefaultHost( const QString& host )
+{
+ m_defaultHost = host.isEmpty() ?
+ QString::fromLatin1(DEFAULT_HOST) : host;
+
+ m_config->setGroup( CONFIG_GROUP );
+ m_config->writeEntry( "Default Host", m_defaultHost );
+}
+
+ServerSettings Config::settingsForLocalHost() const
+{
+ return settingsForHost( "localhost" );
+}
+
+ServerSettings Config::settingsForHost( const QString& host ) const
+{
+ KConfigGroup config( m_config, settingsGroup( host ) );
+ ServerSettings settings;
+
+ settings.host = host;
+ settings.configuredPort = config.readUnsignedNumEntry( "Port",
+ DEFAULT_PORT );
+ settings.autoPort = (host == "localhost") &&
+ config.readBoolEntry("Automatically determine Port",
+ DEFAULT_AUTOPORT );
+ settings.user = config.readEntry( "Username", DEFAULT_USER );
+ settings.pass = config.readEntry( "Password", DEFAULT_PASS );
+ settings.useAuth = config.readBoolEntry( "Perform Authentication",
+ DEFAULT_AUTH );
+
+ return settings;
+}
+
+void Config::addSettings( const ServerSettings& settings )
+{
+ QString host = settings.host;
+ if ( m_hostList.find( host ) == m_hostList.end() )
+ m_hostList.append( host );
+
+ m_config->setGroup( CONFIG_GROUP );
+ m_config->writeEntry( "Host List", m_hostList );
+
+ m_config->setGroup( settingsGroup( host ) );
+ m_config->writeEntry( "Host", host );
+ m_config->writeEntry( "Port", settings.configuredPort );
+ m_config->writeEntry( "Automatically determine Port", settings.autoPort );
+ m_config->writeEntry( "Username", settings.user );
+ m_config->writeEntry( "Password", settings.pass );
+ m_config->writeEntry( "Perform Authentication", settings.useAuth );
+}
+
+bool Config::removeSettings( const QString& host )
+{
+ bool success = m_config->deleteGroup( settingsGroup( host ) );
+ if ( success )
+ {
+ m_hostList.remove( host );
+ m_config->setGroup( CONFIG_GROUP );
+ }
+
+ return success;
+}
+
+QStringList Config::indexableDirectories() const
+{
+ m_config->setGroup( CONFIG_GROUP );
+ return m_config->readListEntry( "Indexable Directories" );
+}
+
+void Config::setIndexableDirectories( const QStringList& dirs )
+{
+ m_config->setGroup( CONFIG_GROUP );
+ m_config->writeEntry( "Indexable Directories", dirs );
+}
+
+QString Config::addCollectionCommandLine() const
+{
+ m_config->setGroup( CONFIG_GROUP );
+ QString cmd = m_config->readEntry( "AddCollection Commandline",
+ DEFAULT_ADDCOLLECTION_CMD );
+ int index = cmd.find( "%h" );
+ if ( index != -1 )
+ cmd.replace( index, 2, QUOTE( mrmldDataDir() ) );
+
+ index = cmd.find( "%e" );
+ if ( index != -1 )
+ cmd.replace( index, 2, QTextCodec::codecForLocale()->mimeName() );
+
+ return cmd;
+}
+
+void Config::setAddCollectionCommandLine( const QString& cmd )
+{
+ m_config->setGroup( CONFIG_GROUP );
+ m_config->writeEntry( "AddCollection Commandline", cmd );
+}
+
+QString Config::removeCollectionCommandLine() const
+{
+ m_config->setGroup( CONFIG_GROUP );
+ QString cmd = m_config->readEntry( "RemoveCollection Commandline",
+ DEFAULT_REMOVECOLLECTION_CMD );
+ int index = cmd.find( "%h" );
+ if ( index != -1 )
+ cmd.replace( index, 2, QUOTE( mrmldDataDir() ) );
+
+ index = cmd.find( "%e" );
+ if ( index != -1 )
+ cmd.replace( index, 2, QTextCodec::codecForLocale()->mimeName() );
+
+ return cmd;
+}
+
+void Config::setRemoveCollectionCommandLine( const QString& cmd )
+{
+ m_config->setGroup( CONFIG_GROUP );
+ m_config->writeEntry( "RemoveCollection Commandline", cmd );
+}
+
+QString Config::mrmldCommandline() const
+{
+ ServerSettings settings = settingsForLocalHost();
+
+ m_config->setGroup( CONFIG_GROUP );
+ QString cmd = m_config->readEntry( "MrmmlDaemon Commandline",
+ settings.autoPort ?
+ DEFAULT_MRMLD_CMD_AUTOPORT :
+ DEFAULT_MRMLD_CMD );
+
+ // add data directory and port to the commandline
+ int index = cmd.find( "%p" );
+ if ( index != -1 )
+ {
+ QString port = settings.autoPort ?
+ QString::null : QString::number( settings.configuredPort );
+ cmd.replace( index, 2, port );
+ }
+ index = cmd.find( "%d" );
+ if ( index != -1 )
+ {
+ cmd.replace( index, 2, QUOTE( mrmldDataDir() ) );
+ }
+
+ qDebug("***** commandline: %s", cmd.latin1());
+
+ return cmd;
+}
+
+QString Config::mrmldDataDir()
+{
+ QString dir = KGlobal::dirs()->saveLocation( "data",
+ "kmrml/mrmld-data/" );
+ if ( dir.isEmpty() ) // fallback
+ dir = QDir::homeDirPath() + "/";
+
+ return dir;
+}
+
+void Config::setMrmldCommandLine( const QString& cmd )
+{
+ m_config->setGroup( CONFIG_GROUP );
+ m_config->writeEntry( "MrmmlDaemon Commandline", cmd );
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+ServerSettings::ServerSettings()
+ : configuredPort( 0 ),
+ autoPort( true ),
+ useAuth( false )
+{
+}
+
+ServerSettings::ServerSettings( const QString& host, unsigned short int port,
+ bool autoPort, bool useAuth,
+ const QString& user, const QString& pass )
+{
+ this->host = host;
+ this->configuredPort = port;
+ this->autoPort = autoPort;
+ this->useAuth = useAuth;
+ this->user = user;
+ this->pass = pass;
+}
+
+// static
+ServerSettings ServerSettings::defaults()
+{
+ return ServerSettings( DEFAULT_HOST, DEFAULT_PORT,
+ (!strcmp(DEFAULT_HOST, "localhost") && DEFAULT_PORT),
+ DEFAULT_AUTH, DEFAULT_USER, DEFAULT_PASS );
+}
+
+KURL ServerSettings::getUrl() const
+{
+ KURL url;
+ url.setProtocol( "mrml" );
+ url.setHost( host );
+ if ( !autoPort )
+ url.setPort( configuredPort );
+
+ if ( useAuth && user.isEmpty() )
+ {
+ url.setUser( user );
+ url.setPass( pass );
+ }
+
+ return url;
+}
+
+unsigned short int ServerSettings::port() const
+{
+ if ( autoPort )
+ {
+ QString portsFile = Config::mrmldDataDir() + "gift-port.txt";
+ QFile file( portsFile );
+ if ( file.open( IO_ReadOnly ) )
+ {
+ QString line;
+ (void) file.readLine( line, 6 );
+// qDebug("**** read: %s", line.latin1());
+
+ file.close();
+
+ bool ok;
+ unsigned short int p = line.toUShort( &ok );
+ if ( ok )
+ return p;
+ }
+ else
+ kdWarning() << "Can't open \"" << portsFile << "\" to automatically determine the gift port" << endl;
+ }
+
+ return configuredPort;
+}
diff --git a/kmrml/kmrml/lib/kmrml_config.h b/kmrml/kmrml/lib/kmrml_config.h
new file mode 100644
index 00000000..3b6baa40
--- /dev/null
+++ b/kmrml/kmrml/lib/kmrml_config.h
@@ -0,0 +1,123 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KMRML_CONFIG_H
+#define KMRML_CONFIG_H
+
+class KConfig;
+
+#include <qstringlist.h>
+#include <kurl.h>
+
+namespace KMrml
+{
+ class ServerSettings
+ {
+ public:
+ ServerSettings();
+ ServerSettings(const QString& host, unsigned short int port,
+ bool autoPort, bool useAuth, const
+ QString& user, const QString& pass);
+
+ // does NOT set the port in the KURL object, if autoPort is selected
+ // kio_mrml is going to determine itself (via ServerSettings::port()).
+ // This deuglifies the mrml:/ url a bit (no port is shown)
+ KURL getUrl() const;
+
+ QString host;
+ QString user;
+ QString pass;
+ unsigned short int configuredPort;
+ bool autoPort :1; // only possible with host == localhost
+ bool useAuth :1;
+
+ static ServerSettings defaults();
+
+ // returns configuredPort or the automatically determined port,
+ // depending on the value of autoPort
+ unsigned short int port() const;
+ };
+
+ class Config
+ {
+ public:
+ Config();
+ Config( KConfig *config ); // does not take ownership of KConfig
+ ~Config();
+
+ bool sync();
+
+ ServerSettings defaultSettings() const
+ {
+ return settingsForHost( m_defaultHost );
+ }
+
+ ServerSettings settingsForLocalHost() const;
+ ServerSettings settingsForHost( const QString& host ) const;
+
+ void setDefaultHost( const QString& host );
+
+ /**
+ * Indexed by the hostname -- ensures there are no dupes
+ */
+ void addSettings( const ServerSettings& settings );
+
+ bool removeSettings( const QString& host );
+
+ QStringList hosts() const { return m_hostList; }
+
+ /**
+ * The list of indexable directories -- only applicable to "localhost"
+ */
+ QStringList indexableDirectories() const;
+ void setIndexableDirectories( const QStringList& dirs );
+
+ QString addCollectionCommandLine() const;
+ void setAddCollectionCommandLine( const QString& cmd );
+
+ QString removeCollectionCommandLine() const;
+ void setRemoveCollectionCommandLine( const QString& cmd );
+
+ void setMrmldCommandLine( const QString& cmd );
+ QString mrmldCommandline() const;
+
+ // e.g. Wolfgang needs this :)
+ bool serverStartedIndividually() const {
+ return m_serverStartedIndividually;
+ }
+
+ static QString mrmldDataDir();
+
+ private:
+ void init();
+
+ QString settingsGroup( const QString& host ) const
+ {
+ return QString::fromLatin1( "SettingsFor: " ).append( host );
+ }
+
+ bool m_serverStartedIndividually;
+ QString m_defaultHost;
+ QStringList m_hostList;
+
+ KConfig *m_config;
+ KConfig *m_ownConfig;
+ };
+}
+
+#endif // KMRML_CONFIG_H
diff --git a/kmrml/kmrml/lib/mrml_shared.cpp b/kmrml/kmrml/lib/mrml_shared.cpp
new file mode 100644
index 00000000..0c5b692b
--- /dev/null
+++ b/kmrml/kmrml/lib/mrml_shared.cpp
@@ -0,0 +1,235 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "mrml_shared.h"
+
+// mrml stuff
+const QString * MrmlShared::m_sessionId = 0L;
+const QString * MrmlShared::m_transactionId = 0L;
+const QString * MrmlShared::m_algorithm = 0L;
+const QString * MrmlShared::m_algorithmId = 0L;
+const QString * MrmlShared::m_algorithmName = 0L;
+const QString * MrmlShared::m_algorithmList = 0L;
+const QString * MrmlShared::m_algorithmType = 0L;
+const QString * MrmlShared::m_collectionId = 0L;
+const QString * MrmlShared::m_collectionList = 0L;
+const QString * MrmlShared::m_collection = 0L;
+const QString * MrmlShared::m_collectionName = 0L;
+const QString * MrmlShared::m_queryParadigm = 0L;
+const QString * MrmlShared::m_queryParadigmList = 0L;
+const QString * MrmlShared::m_configureSession = 0L;
+
+const QString * MrmlShared::m_propertySheet = 0L;
+const QString * MrmlShared::m_propertySheetId = 0L;
+const QString * MrmlShared::m_propertySheetType = 0L;
+const QString * MrmlShared::m_sendName = 0L;
+const QString * MrmlShared::m_sendType = 0L;
+const QString * MrmlShared::m_sendValue = 0L;
+const QString * MrmlShared::m_maxSubsetSize = 0L;
+const QString * MrmlShared::m_minSubsetSize = 0L;
+const QString * MrmlShared::m_caption = 0L;
+const QString * MrmlShared::m_from = 0L;
+const QString * MrmlShared::m_to = 0L;
+const QString * MrmlShared::m_step = 0L;
+const QString * MrmlShared::m_sendBooleanInverted = 0L;
+
+const QString * MrmlShared::m_element = 0L;
+const QString * MrmlShared::m_attribute = 0L;
+const QString * MrmlShared::m_attributeName = 0L;
+const QString * MrmlShared::m_attributeValue = 0L;
+const QString * MrmlShared::m_children = 0L;
+const QString * MrmlShared::m_none = 0L;
+
+const QString * MrmlShared::m_multiSet = 0L;
+const QString * MrmlShared::m_subset = 0L;
+const QString * MrmlShared::m_setElement = 0L;
+const QString * MrmlShared::m_boolean = 0L;
+const QString * MrmlShared::m_numeric = 0L;
+const QString * MrmlShared::m_textual = 0L;
+const QString * MrmlShared::m_panel = 0L;
+const QString * MrmlShared::m_clone = 0L;
+const QString * MrmlShared::m_reference = 0L;
+
+const QString * MrmlShared::m_visibility = 0L;
+const QString * MrmlShared::m_visible = 0L;
+const QString * MrmlShared::m_invisible = 0L;
+const QString * MrmlShared::m_popup = 0L;
+// const QString * MrmlShared::m_ = 0L;
+
+// meta-data
+const QString * MrmlShared::m_mrml_data = 0L;
+
+// kio_mrml tasks
+const QString * MrmlShared::m_kio_task = 0L;
+const QString * MrmlShared::m_kio_initialize = 0L;
+const QString * MrmlShared::m_kio_startQuery = 0L;
+
+
+int MrmlShared::s_references = 0;
+
+void MrmlShared::ref()
+{
+ if ( s_references == 0 )
+ init();
+
+ s_references++;
+}
+
+bool MrmlShared::deref()
+{
+ if ( s_references > 0 )
+ s_references--;
+
+ if ( s_references == 0 )
+ {
+ // ### delete all strings here...
+
+ return true;
+ }
+
+ return false;
+}
+
+void MrmlShared::init()
+{
+ m_sessionId = new QString ( "session-id" ) ;
+ m_transactionId = new QString ( "transaction-id" ) ;
+ m_algorithm = new QString ( "algorithm" ) ;
+ m_algorithmId = new QString ( "algorithm-id" ) ;
+ m_algorithmName = new QString ( "algorithm-name" ) ;
+ m_algorithmList = new QString ( "algorithm-list" ) ;
+ m_algorithmType = new QString ( "algorithm-type" ) ;
+ m_collectionId = new QString ( "collection-id" ) ;
+ m_collectionList = new QString ( "collection-list" ) ;
+ m_collection = new QString ( "collection" ) ;
+ m_collectionName = new QString ( "collection-name" ) ;
+ m_queryParadigm = new QString ( "query-paradigm" ) ;
+ m_queryParadigmList = new QString ( "query-paradigm-list" ) ;
+ m_configureSession = new QString ( "configure-session" ) ;
+
+ m_propertySheet = new QString ( "property-sheet" ) ;
+ m_propertySheetId = new QString ( "property-sheet-id" ) ;
+ m_propertySheetType = new QString ( "property-sheet-type" ) ;
+ m_sendName = new QString ( "send-name" ) ;
+ m_sendType = new QString ( "send-type" ) ;
+ m_sendValue = new QString ( "send-value" ) ;
+ m_maxSubsetSize = new QString ( "maxsubsetsize" ) ;
+ m_minSubsetSize = new QString ( "minsubsetsize" ) ;
+ m_caption = new QString ( "caption" ) ;
+ m_from = new QString ( "from" ) ;
+ m_to = new QString ( "to" ) ;
+ m_step = new QString ( "step" ) ;
+ m_sendBooleanInverted = new QString ( "send-boolean-inverted" ) ;
+
+ m_element = new QString ( "element" ) ;
+ m_attribute = new QString ( "attribute" ) ;
+ m_attributeName = new QString ( "attribute-name" ) ;
+ m_attributeValue = new QString ( "attribute-value" ) ;
+ m_children = new QString ( "children" ) ;
+ m_none = new QString ( "none" ) ;
+
+ m_multiSet = new QString ( "multi-set" ) ;
+ m_subset = new QString ( "subset" ) ;
+ m_setElement = new QString ( "set-element" ) ;
+ m_boolean = new QString ( "boolean" ) ;
+ m_numeric = new QString ( "numeric" ) ;
+ m_textual = new QString ( "textual" ) ;
+ m_panel = new QString ( "panel" ) ;
+ m_clone = new QString ( "clone" ) ;
+ m_reference = new QString ( "reference" ) ;
+
+ m_visibility = new QString ( "visibility" ) ;
+ m_visible = new QString ( "visible" ) ;
+ m_invisible = new QString ( "invisible" ) ;
+ m_popup = new QString ( "popup" ) ;
+// m_ = new QString ( "" ) ;
+
+// meta-data
+ m_mrml_data = new QString ( "mrml_data" ) ;
+
+// kio_mrml tasks
+ m_kio_task = new QString ( "kio_task" ) ;
+ m_kio_initialize = new QString ( "kio_initialize" ) ;
+ m_kio_startQuery = new QString ( "kio_startQuery" ) ;
+}
+
+void MrmlShared::cleanup()
+{
+ delete m_sessionId;
+ delete m_transactionId;
+ delete m_algorithm;
+ delete m_algorithmId;
+ delete m_algorithmName;
+ delete m_algorithmList;
+ delete m_algorithmType;
+ delete m_collectionId;
+ delete m_collectionList;
+ delete m_collection;
+ delete m_collectionName;
+ delete m_queryParadigm;
+ delete m_queryParadigmList;
+ delete m_configureSession;
+
+ // property sheet stuff
+ delete m_propertySheet;
+ delete m_propertySheetId;
+ delete m_propertySheetType;
+ delete m_sendName;
+ delete m_sendType;
+ delete m_sendValue;
+ delete m_maxSubsetSize;
+ delete m_minSubsetSize;
+ delete m_caption;
+ delete m_from;
+ delete m_to;
+ delete m_step;
+ delete m_sendBooleanInverted;
+
+ delete m_multiSet;
+ delete m_subset;
+ delete m_setElement;
+ delete m_boolean;
+ delete m_numeric;
+ delete m_textual;
+ delete m_panel;
+ delete m_clone;
+ delete m_reference;
+
+ delete m_element;
+ delete m_attribute;
+ delete m_attributeName;
+ delete m_attributeValue;
+ delete m_children;
+ delete m_none;
+
+ delete m_visibility;
+ delete m_visible;
+ delete m_invisible;
+ delete m_popup;
+// delete m_;
+
+ // meta-data
+ delete m_mrml_data;
+
+ // kio_mrml tasks
+ delete m_kio_task;
+ delete m_kio_initialize;
+ delete m_kio_startQuery;
+
+}
diff --git a/kmrml/kmrml/lib/mrml_shared.h b/kmrml/kmrml/lib/mrml_shared.h
new file mode 100644
index 00000000..aff2a98d
--- /dev/null
+++ b/kmrml/kmrml/lib/mrml_shared.h
@@ -0,0 +1,166 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001,2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SHARED_H
+#define SHARED_H
+
+// maybe use mrml_const.h from libMRML, unfortunately not installed
+// by gift 0.1.6pre2
+
+#include <qshared.h>
+#include <qstring.h>
+
+class MrmlShared
+{
+public:
+// attribute/element names for mrml
+ static void ref();
+ static bool deref();
+
+ static const QString& sessionId() { return *m_sessionId; }
+ static const QString& transactionId() { return *m_transactionId; }
+ static const QString& algorithm() { return *m_algorithm; }
+ static const QString& algorithmId() { return *m_algorithmId; }
+ static const QString& algorithmName() { return *m_algorithmName; }
+ static const QString& algorithmList() { return *m_algorithmList; }
+ static const QString& algorithmType() { return *m_algorithmType; }
+ static const QString& collectionId() { return *m_collectionId; }
+ static const QString& collectionList() { return *m_collectionList; }
+ static const QString& collection() { return *m_collection; }
+ static const QString& collectionName() { return *m_collectionName; }
+ static const QString& queryParadigm() { return *m_queryParadigm; }
+ static const QString& queryParadigmList() { return *m_queryParadigmList; }
+ static const QString& configureSession() { return *m_configureSession; }
+
+ // property sheet stuff
+ static const QString& propertySheet() { return *m_propertySheet; }
+ static const QString& propertySheetId() { return *m_propertySheetId; }
+ static const QString& propertySheetType() { return *m_propertySheetType; }
+ static const QString& sendName() { return *m_sendName; }
+ static const QString& sendType() { return *m_sendType; }
+ static const QString& sendValue() { return *m_sendValue; }
+ static const QString& maxSubsetSize() { return *m_maxSubsetSize; }
+ static const QString& minSubsetSize() { return *m_minSubsetSize; }
+ static const QString& caption() { return *m_caption; }
+ static const QString& from() { return *m_from; }
+ static const QString& to() { return *m_to; }
+ static const QString& step() { return *m_step; }
+ static const QString& sendBooleanInverted() { return *m_sendBooleanInverted; }
+
+ static const QString& multiSet() { return *m_multiSet; }
+ static const QString& subset() { return *m_subset; }
+ static const QString& setElement() { return *m_setElement; }
+ static const QString& boolean() { return *m_boolean; }
+ static const QString& numeric() { return *m_numeric; }
+ static const QString& textual() { return *m_textual; }
+ static const QString& panel() { return *m_panel; }
+ static const QString& clone() { return *m_clone; }
+ static const QString& reference() { return *m_reference; }
+
+ static const QString& element() { return *m_element; }
+ static const QString& attribute() { return *m_attribute; }
+ static const QString& attributeName() { return *m_attributeName; }
+ static const QString& attributeValue() { return *m_attributeValue; }
+ static const QString& children() { return *m_children; }
+ static const QString& none() { return *m_none; }
+
+ static const QString& visibility() { return *m_visibility; }
+ static const QString& visible() { return *m_visible; }
+ static const QString& invisible() { return *m_invisible; }
+ static const QString& popup() { return *m_popup; }
+// static const QString& () { return *m_; }
+
+ // meta-data
+ static const QString& mrml_data() { return *m_mrml_data; }
+
+ // kio_mrml tasks
+ static const QString& kio_task() { return *m_kio_task; }
+ static const QString& kio_initialize() { return *m_kio_initialize; }
+ static const QString& kio_startQuery() { return *m_kio_startQuery; }
+
+
+private:
+ static const QString * m_sessionId;
+ static const QString * m_transactionId;
+ static const QString * m_algorithm;
+ static const QString * m_algorithmId;
+ static const QString * m_algorithmName;
+ static const QString * m_algorithmList;
+ static const QString * m_algorithmType;
+ static const QString * m_collectionId;
+ static const QString * m_collectionList;
+ static const QString * m_collection;
+ static const QString * m_collectionName;
+ static const QString * m_queryParadigm;
+ static const QString * m_queryParadigmList;
+ static const QString * m_configureSession;
+
+ // property sheet stuff
+ static const QString * m_propertySheet;
+ static const QString * m_propertySheetId;
+ static const QString * m_propertySheetType;
+ static const QString * m_sendName;
+ static const QString * m_sendType;
+ static const QString * m_sendValue;
+ static const QString * m_maxSubsetSize;
+ static const QString * m_minSubsetSize;
+ static const QString * m_caption;
+ static const QString * m_from;
+ static const QString * m_to;
+ static const QString * m_step;
+ static const QString * m_sendBooleanInverted;
+
+ static const QString * m_multiSet;
+ static const QString * m_subset;
+ static const QString * m_setElement;
+ static const QString * m_boolean;
+ static const QString * m_numeric;
+ static const QString * m_textual;
+ static const QString * m_panel;
+ static const QString * m_clone;
+ static const QString * m_reference;
+
+ static const QString * m_element;
+ static const QString * m_attribute;
+ static const QString * m_attributeName;
+ static const QString * m_attributeValue;
+ static const QString * m_children;
+ static const QString * m_none;
+
+ static const QString * m_visibility;
+ static const QString * m_visible;
+ static const QString * m_invisible;
+ static const QString * m_popup;
+// static const QString * m_;
+
+ // meta-data
+ static const QString * m_mrml_data;
+
+ // kio_mrml tasks
+ static const QString * m_kio_task;
+ static const QString * m_kio_initialize;
+ static const QString * m_kio_startQuery;
+
+private:
+ static void cleanup();
+ static void init();
+
+ static int s_references;
+};
+
+#endif // SHARED_H
diff --git a/kmrml/kmrml/lib/mrml_utils.cpp b/kmrml/kmrml/lib/mrml_utils.cpp
new file mode 100644
index 00000000..f20dad6a
--- /dev/null
+++ b/kmrml/kmrml/lib/mrml_utils.cpp
@@ -0,0 +1,89 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <dcopclient.h>
+#include <kapplication.h>
+#include <kprocess.h>
+#include <kstaticdeleter.h>
+
+#include "watcher_stub.h"
+
+#include "mrml_utils.h"
+
+// after 100 of no use, terminate the mrmld
+#define TIMEOUT 100
+// how often to restart the mrmld in case of failure
+#define NUM_RESTARTS 5
+
+using namespace KMrml;
+
+KStaticDeleter<Util> utils_sd;
+
+Util *Util::s_self = 0L;
+
+Util::Util()
+{
+ // we need our own dcopclient, when used in kio_mrml
+ if ( !DCOPClient::mainClient() )
+ {
+ DCOPClient::setMainClient( new DCOPClient() );
+ if ( !DCOPClient::mainClient()->attach() )
+ qWarning( "kio_mrml: Can't attach to DCOP Server.");
+ }
+}
+
+Util::~Util()
+{
+ if ( this == s_self )
+ s_self = 0L;
+}
+
+Util *Util::self()
+{
+ if ( !s_self )
+ s_self = utils_sd.setObject( new Util() );
+ return s_self;
+}
+
+bool Util::requiresLocalServerFor( const KURL& url )
+{
+ return url.host().isEmpty() || url.host() == "localhost";
+}
+
+bool Util::startLocalServer( const Config& config )
+{
+ if ( config.serverStartedIndividually() )
+ return true;
+
+ DCOPClient *client = DCOPClient::mainClient();
+
+ // ### check if it's already running (add dcop method to Watcher)
+ Watcher_stub watcher( client, "kded", "daemonwatcher");
+ return ( watcher.requireDaemon( client->appId(),
+ "mrmld", config.mrmldCommandline(),
+ TIMEOUT, NUM_RESTARTS )
+ && watcher.ok() );
+}
+
+void Util::unrequireLocalServer()
+{
+ DCOPClient *client = DCOPClient::mainClient();
+
+ Watcher_stub watcher( client, "kded", "daemonwatcher");
+ watcher.unrequireDaemon( client->appId(), "mrmld" );
+}
diff --git a/kmrml/kmrml/lib/mrml_utils.h b/kmrml/kmrml/lib/mrml_utils.h
new file mode 100644
index 00000000..25f39d98
--- /dev/null
+++ b/kmrml/kmrml/lib/mrml_utils.h
@@ -0,0 +1,50 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#ifndef MRML_UTILS_H
+#define MRML_UTILS_H
+
+#include <qobject.h>
+
+#include <kurl.h>
+
+#include "kmrml_config.h"
+
+namespace KMrml
+{
+ class Util : public QObject
+ {
+ public:
+ static Util * self();
+ ~Util();
+
+ bool requiresLocalServerFor( const KURL& url );
+ bool startLocalServer( const Config& config );
+ void unrequireLocalServer();
+// bool isLocalServerRunning();
+
+ private:
+ static Util *s_self;
+ Util();
+ };
+
+
+}
+
+#endif // MRML_UTILS_H
diff --git a/kmrml/kmrml/lib/version.h b/kmrml/kmrml/lib/version.h
new file mode 100644
index 00000000..5cf8e270
--- /dev/null
+++ b/kmrml/kmrml/lib/version.h
@@ -0,0 +1,6 @@
+#ifndef VERSION_H
+#define VERSION_H
+
+#define KMRML_VERSION "0.3.2"
+
+#endif // VERSION_H
diff --git a/kmrml/kmrml/lib/watcher_stub.cpp b/kmrml/kmrml/lib/watcher_stub.cpp
new file mode 100644
index 00000000..cf84818b
--- /dev/null
+++ b/kmrml/kmrml/lib/watcher_stub.cpp
@@ -0,0 +1,95 @@
+//
+// Generated in ../server/ via dcopidl -- needs to be in the lib tho.
+// Regenerate when necessary by uncommenting the watcher.stub in
+// ../server/Makefile.am
+//
+
+#include "watcher_stub.h"
+#include <dcopclient.h>
+
+#include <kdatastream.h>
+
+namespace KMrml {
+
+Watcher_stub::Watcher_stub( const QCString& app, const QCString& obj )
+ : DCOPStub( app, obj )
+{
+}
+
+Watcher_stub::Watcher_stub( DCOPClient* client, const QCString& app, const QCString& obj )
+ : DCOPStub( client, app, obj )
+{
+}
+
+bool Watcher_stub::requireDaemon( const QCString& arg0, const QString& arg1, const QString& arg2, uint arg3, int arg4 )
+{
+ bool result;
+ if ( !dcopClient() ) {
+ setStatus( CallFailed );
+ return false;
+ }
+ QByteArray data, replyData;
+ QCString replyType;
+ QDataStream arg( data, IO_WriteOnly );
+ arg << arg0;
+ arg << arg1;
+ arg << arg2;
+ arg << arg3;
+ arg << arg4;
+ if ( dcopClient()->call( app(), obj(), "requireDaemon(QCString,QString,QString,uint,int)", data, replyType, replyData ) ) {
+ if ( replyType == "bool" ) {
+ QDataStream _reply_stream( replyData, IO_ReadOnly );
+ _reply_stream >> result;
+ setStatus( CallSucceeded );
+ } else {
+ callFailed();
+ }
+ } else {
+ callFailed();
+ }
+ return result;
+}
+
+void Watcher_stub::unrequireDaemon( const QCString& arg0, const QString& arg1 )
+{
+ if ( !dcopClient() ) {
+ setStatus( CallFailed );
+ return;
+ }
+ QByteArray data, replyData;
+ QCString replyType;
+ QDataStream arg( data, IO_WriteOnly );
+ arg << arg0;
+ arg << arg1;
+ if ( dcopClient()->call( app(), obj(), "unrequireDaemon(QCString,QString)", data, replyType, replyData ) ) {
+ setStatus( CallSucceeded );
+ } else {
+ callFailed();
+ }
+}
+
+QStringList Watcher_stub::runningDaemons()
+{
+ QStringList result;
+ if ( !dcopClient() ) {
+ setStatus( CallFailed );
+ return result;
+ }
+ QByteArray data, replyData;
+ QCString replyType;
+ if ( dcopClient()->call( app(), obj(), "runningDaemons()", data, replyType, replyData ) ) {
+ if ( replyType == "QStringList" ) {
+ QDataStream _reply_stream( replyData, IO_ReadOnly );
+ _reply_stream >> result;
+ setStatus( CallSucceeded );
+ } else {
+ callFailed();
+ }
+ } else {
+ callFailed();
+ }
+ return result;
+}
+
+} // namespace
+
diff --git a/kmrml/kmrml/lib/watcher_stub.h b/kmrml/kmrml/lib/watcher_stub.h
new file mode 100644
index 00000000..04b1292e
--- /dev/null
+++ b/kmrml/kmrml/lib/watcher_stub.h
@@ -0,0 +1,36 @@
+//
+// Generated in ../server/ via dcopidl -- needs to be in the lib tho.
+// Regenerate when necessary by uncommenting the watcher.stub in
+// ../server/Makefile.am
+//
+
+#ifndef __WATCHER_STUB__
+#define __WATCHER_STUB__
+
+#include <dcopstub.h>
+#include <qdict.h>
+#include <qptrlist.h>
+#include <qmap.h>
+#include <qstrlist.h>
+#include <qstringlist.h>
+#include <qtimer.h>
+#include <kdedmodule.h>
+#include <kprocess.h>
+
+namespace KMrml {
+
+class Watcher_stub : public DCOPStub
+{
+public:
+ Watcher_stub( const QCString& app, const QCString& id );
+ Watcher_stub( DCOPClient* client, const QCString& app, const QCString& id );
+ virtual bool requireDaemon( const QCString& clientAppId, const QString& daemonKey, const QString& commandline, uint timeout, int numRestarts );
+ virtual void unrequireDaemon( const QCString& clientAppId, const QString& daemonKey );
+ virtual QStringList runningDaemons();
+protected:
+ Watcher_stub() : DCOPStub( never_use ) {};
+};
+
+} // namespace
+
+#endif
diff --git a/kmrml/kmrml/loader.cpp b/kmrml/kmrml/loader.cpp
new file mode 100644
index 00000000..cc59c172
--- /dev/null
+++ b/kmrml/kmrml/loader.cpp
@@ -0,0 +1,121 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kstaticdeleter.h>
+#include <kio/scheduler.h>
+
+#include "loader.h"
+
+Loader *Loader::s_self = 0L;
+
+KStaticDeleter<Loader> sd;
+
+Loader * Loader::self()
+{
+ if ( !s_self )
+ s_self = sd.setObject( new Loader() );
+
+ return s_self;
+}
+
+Loader::Loader() : QObject()
+{
+}
+
+Loader::~Loader()
+{
+ disconnect( this, SIGNAL( finished( const KURL&, const QByteArray& )));
+
+ DownloadIterator it = m_downloads.begin();
+ for ( ; it != m_downloads.end(); ++it ) {
+ it.key()->kill();
+ delete it.data();
+ }
+
+ s_self = 0L;
+}
+
+void Loader::requestDownload( const KURL& url )
+{
+ DownloadIterator it = m_downloads.begin();
+ for ( ; it != m_downloads.end(); ++it ) {
+ if ( it.key()->url() == url )
+ return;
+ }
+
+ KIO::TransferJob *job = KIO::get( url, false, false );
+ KIO::Scheduler::scheduleJob(job);
+
+ connect( job , SIGNAL( data( KIO::Job *, const QByteArray& )),
+ SLOT( slotData( KIO::Job *, const QByteArray& )));
+ connect( job , SIGNAL( result( KIO::Job * )),
+ SLOT( slotResult( KIO::Job * )));
+
+ Download *d = new Download();
+ m_downloads.insert( job, d );
+}
+
+void Loader::slotData( KIO::Job *job, const QByteArray& data )
+{
+ DownloadIterator it = m_downloads.find( static_cast<KIO::TransferJob*>(job) );
+ if ( it != m_downloads.end() ) {
+ QBuffer& buffer = it.data()->m_buffer;
+ if ( !buffer.isOpen() )
+ buffer.open( IO_ReadWrite );
+ if ( !buffer.isOpen() ) {
+ qDebug("********* EEK, can't open buffer for thumbnail download!");
+ return;
+ }
+
+ buffer.writeBlock( data.data(), data.size() );
+ }
+}
+
+void Loader::slotResult( KIO::Job *job )
+{
+ KIO::TransferJob *tjob = static_cast<KIO::TransferJob*>( job );
+
+ DownloadIterator it = m_downloads.find( tjob );
+ if ( it != m_downloads.end() ) {
+ Download *d = it.data();
+
+ if ( job->error() != 0 )
+ emit finished( tjob->url(), QByteArray() );
+ else
+ emit finished( tjob->url(), d->m_buffer.buffer() );
+
+ delete d;
+ m_downloads.remove( it );
+ }
+}
+
+
+// ### simultaneous downloads with multiple views? reference count downloads!
+void Loader::removeDownload( const KURL& url )
+{
+ DownloadIterator it = m_downloads.begin();
+ for ( ; it != m_downloads.end(); ++it ) {
+ if ( it.key()->url() == url ) {
+ it.key()->kill();
+ delete it.data();
+ return;
+ }
+ }
+}
+
+#include "loader.moc"
diff --git a/kmrml/kmrml/loader.h b/kmrml/kmrml/loader.h
new file mode 100644
index 00000000..5e81a2e4
--- /dev/null
+++ b/kmrml/kmrml/loader.h
@@ -0,0 +1,72 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef LOADER_H
+#define LOADER_H
+
+#include <qbuffer.h>
+#include <qcstring.h>
+#include <qmap.h>
+#include <qobject.h>
+
+#include <kio/job.h>
+#include <kurl.h>
+
+class Download
+{
+public:
+ ~Download() {
+ if ( m_buffer.isOpen() )
+ m_buffer.close();
+ }
+ QBuffer m_buffer;
+ // add context of MrmlPart for progress?
+};
+
+
+class Loader : public QObject
+{
+ friend class gcc_sucks;
+ Q_OBJECT
+
+public:
+ static Loader *self();
+ ~Loader();
+
+ void requestDownload( const KURL& url );
+
+ void removeDownload( const KURL& url );
+
+signals:
+ void finished( const KURL& url, const QByteArray& );
+
+private slots:
+ void slotData( KIO::Job *, const QByteArray& );
+ void slotResult( KIO::Job * );
+
+private:
+ Loader();
+
+ QMap<KIO::TransferJob*,Download*> m_downloads;
+ typedef QMapIterator<KIO::TransferJob*,Download*> DownloadIterator;
+
+ static Loader *s_self;
+
+};
+
+#endif // LOADER_H
diff --git a/kmrml/kmrml/mrml-servicemenu.desktop b/kmrml/kmrml/mrml-servicemenu.desktop
new file mode 100644
index 00000000..2d9a938c
--- /dev/null
+++ b/kmrml/kmrml/mrml-servicemenu.desktop
@@ -0,0 +1,67 @@
+[Desktop Entry]
+ServiceTypes=image/png,image/jpeg,image/gif,image/tiff,image/bmp,image/x-xpm,image/x-xbm,image/x-png
+Actions=search;
+
+[Desktop Action search]
+Name=Search for Similar Images...
+Name[af]=Soektog vir Soortgelyk Beelde...
+Name[ar]=بحث عن الصور المتشابهه...
+Name[bg]=Търсене на подобни изображения...
+Name[bs]=Traženje sličnih slika...
+Name[ca]=Cerca imatges similars...
+Name[cs]=Hledat podobný obrázek...
+Name[cy]=Chwilio am Ddelweddau Tebyg...
+Name[da]=Søg efter lignende filer...
+Name[de]=Nach ähnlichen Bildern suchen ...
+Name[el]=Αναζήτηση για παρόμοιες εικόνες...
+Name[eo]=Serĉi Similajn Bildojn...
+Name[es]=Búsqueda de imágenes similares...
+Name[et]=Otsi sarnaseid pilte...
+Name[eu]=Bilatu antzeko irudiak...
+Name[fa]=جستجو برای تصاویر مشابه...
+Name[fi]=Etsi samankaltaisia kuvia...
+Name[fr]=Recherche d'images semblables...
+Name[gl]=Procurar imaxes semellantes...
+Name[he]=חיפוש תמונות דומות...
+Name[hi]=एक जैसे छवियों के लिए ढूंढें...
+Name[hu]=Ehhez hasonló képek keresése...
+Name[is]=Leita að svipuðum myndum...
+Name[it]=Cerca immagini simili...
+Name[ja]=同じような画像を検索...
+Name[kk]=Ұқсас кескіндерді іздеу...
+Name[km]=ស្វែងរក​រូបភាព​ស្រដៀង​គ្នា...
+Name[lt]=Panašių paveikslėlių paieška...
+Name[ms]=Cari Imej Serupa...
+Name[nb]=Søk etter liknende bilder …
+Name[nds]=Na lieke Biller söken...
+Name[ne]=उस्तै छविका लागि खोजी गर्नुहोस्...
+Name[nl]=Zoeken naar vergelijkbare afbeeldingen...
+Name[nn]=Søk etter liknande bilete …
+Name[nso]=Nyako ya Diponagalo tseo di Swanago...
+Name[pl]=Szukaj podobnych obrazków
+Name[pt]=Procurar por Imagens Semelhantes...
+Name[pt_BR]=Procurar por Imagens Parecidas...
+Name[ro]=Caută imagini similare...
+Name[ru]=Поиск похожих изображений...
+Name[se]=Oza seammalágana govaid …
+Name[sk]=Hľadať podobné obrázky...
+Name[sl]=Išči podobne slike ...
+Name[sr]=Потражи сличне слике...
+Name[sr@Latn]=Potraži slične slike...
+Name[sv]=Sök efter liknande bilder...
+Name[ta]=இதே போன்ற பிம்பங்களை தேடுக...
+Name[tg]=Ҷустуҷӯи тасвироти якхела...
+Name[th]=ค้นหาภาพที่เหมือนกัน...
+Name[tr]=Benzer Resimleri Ara...
+Name[uk]=Пошук схожих зображень...
+Name[uz]=Oʻxshash rasmlarni qidirish
+Name[uz@cyrillic]=Ўхшаш расмларни қидириш
+Name[ven]=Todani zwifanyiso zwielanaho...
+Name[wa]=Cweri après des rshonnantès imådjes...
+Name[xh]=Phendla Imifanekiso Efanayo...
+Name[zh_CN]=搜索类似图像...
+Name[zh_HK]=尋找類似的圖像...
+Name[zh_TW]=尋找類似的影像...
+Name[zu]=Sesha ukuthola Izithombe Ezifanayo....
+Icon=image
+Exec=mrmlsearch %U
diff --git a/kmrml/kmrml/mrml.cpp b/kmrml/kmrml/mrml.cpp
new file mode 100644
index 00000000..082d037b
--- /dev/null
+++ b/kmrml/kmrml/mrml.cpp
@@ -0,0 +1,267 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001,2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kinstance.h>
+#include <klocale.h>
+
+#include <mrml_utils.h>
+
+#include "mrml.h"
+
+extern "C" {
+ KDE_EXPORT int kdemain( int argc, char **argv )
+ {
+ KLocale::setMainCatalogue("kdelibs");
+ KInstance instance( "kio_mrml" );
+ KGlobal::locale()->insertCatalogue( "kmrml" );
+
+ kdDebug() << "Starting MRML " << getpid() << endl;
+
+ if (argc != 4)
+ {
+ fprintf(stderr, "Usage: kio_mrml protocol domain-socket1 domain-socket2\n");
+ exit(-1);
+ }
+
+ Mrml slave(argv[2], argv[3]);
+ slave.dispatchLoop();
+
+ kdDebug() << "Done" << endl;
+ return 0;
+ }
+}
+
+const int Mrml::bufsize = 8192;
+
+Mrml::Mrml( const QCString& pool_socket, const QCString& app_socket )
+ : TCPSlaveBase( 12789, "mrml", pool_socket, app_socket ),
+ m_config( KGlobal::config() )
+{
+ MrmlShared::ref();
+}
+
+Mrml::~Mrml()
+{
+ KMrml::Util::self()->unrequireLocalServer();
+
+ closeDescriptor();
+ MrmlShared::deref();
+}
+
+bool Mrml::checkLocalServer( const KURL& url )
+{
+ if ( KMrml::Util::self()->requiresLocalServerFor( url ) )
+ {
+ if ( !KMrml::Util::self()->startLocalServer( m_config ) )
+ return false;
+ }
+
+ return true;
+}
+
+void Mrml::get( const KURL& url )
+{
+// qDebug("******* getting: %s (user: %s)", url.url().latin1(), url.user().latin1());
+
+ if ( !checkLocalServer( url ) )
+ {
+ error( KIO::ERR_SLAVE_DEFINED, i18n("Unable to start the Indexing Server. "
+ "Aborting the query.") );
+ return;
+ }
+
+ int retriesLeft = 5;
+tryConnect:
+
+ QCString utf8;
+ bool sendError = (retriesLeft <= 0);
+
+ if ( connectToHost( url.host(), port(url), sendError ) )
+ {
+// qDebug(" connected!");
+
+ QString task = metaData( MrmlShared::kio_task() );
+
+ if ( task == MrmlShared::kio_initialize() ) {
+ startSession( url );
+ }
+
+ else if ( task == MrmlShared::kio_startQuery() ) {
+ QString meta = metaData( MrmlShared::mrml_data() );
+ if ( meta.isEmpty() ) {
+ closeDescriptor();
+ error( KIO::ERR_SLAVE_DEFINED, i18n("No MRML data is available.") );
+ return;
+ }
+
+ utf8 = meta.utf8();
+ write( utf8, utf8.length() );
+
+ emitData( readAll() );
+ }
+
+ // no task metadata available, we're called from KonqRun or something
+ // like that. Emitting the mimetype seems to suffice for now. After
+ // that, MrmlPart is going to start and start the get() again.
+ else
+ {
+ mimeType( "text/mrml" );
+ finished();
+ }
+
+ }
+ else
+ {
+ if ( retriesLeft-- >= 0 )
+ {
+#ifdef HAVE_USLEEP
+ usleep( 500 ); // wait a while for gift to start up
+#endif
+ goto tryConnect;
+ return;
+ }
+
+ error( KIO::ERR_COULD_NOT_CONNECT,
+ i18n("Could not connect to GIFT server.") );
+ return;
+ }
+
+ closeDescriptor();
+ //data( QByteArray() ); // send an empty QByteArray to signal end of data.
+ finished();
+}
+
+// make sure we're connected when you call this!
+QCString Mrml::readAll()
+{
+ QCString data;
+
+ char buf[bufsize];
+ ssize_t bytes = 0;
+
+ while ( (bytes = read( buf, bufsize-1 )) > 0 ) {
+ buf[bytes] = '\0';
+ data.append( buf );
+ }
+
+// qDebug("*** readAll()::: %i, %s", data.length(), data.data());
+ return data;
+}
+
+QCString Mrml::loginString()
+{
+ return "<mrml><get-server-properties/></mrml>";
+}
+
+QCString Mrml::getConfigurationString()
+{
+ return "<mrml><get-configuration/></mrml>";
+}
+
+// ### needed?
+QCString Mrml::getSessionsString( const QString& username,
+ const QString& password )
+{
+ QCString data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><mrml><get-sessions ";
+ if ( !username.isEmpty() ) { // ### pop up auth-dialog???
+ data.append( "user-name=\"");
+ data.append( username.utf8() );
+ data.append( "\"");
+
+ if ( !password.isEmpty() ) {
+ data.append( " password=\"");
+ data.append( password.utf8() );
+ data.append( "\"" );
+ }
+
+ }
+ data.append( "/></mrml>" );
+
+ return data;
+}
+
+
+bool Mrml::startSession( const KURL& url )
+{
+ // might first ask for collections, and then for algorithms for the
+ // desired collection-id
+
+ // Wolfgang says, we shouldn't create an own session-id here, as gcc 2.95
+ // apparently makes problems in exception handling somehow. So we simply
+ // accept the server's session-id.
+ QString msg = mrmlString( QString::null ).arg(
+ "<open-session user-name=\"%1\" session-name=\"kio_mrml session\" /> \
+ <get-algorithms /> \
+ <get-collections /> \
+ </mrml>" ).arg( user( url ));
+
+ QCString utf8 = msg.utf8();
+// qDebug(":::Writing: %s", utf8.data());
+ write( utf8, utf8.length() );
+
+ emitData( readAll() );
+
+ return true;
+}
+
+QString Mrml::mrmlString( const QString& sessionId, const QString& transactionId )
+{
+ QString msg =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?> \
+ <!DOCTYPE mrml SYSTEM \"http://isrpc85.epfl.ch/Charmer/code/mrml.dtd\"> \
+ %1 \
+ </mrml>";
+
+ if ( sessionId.isEmpty() ) // when we don't have one yet
+ return msg.arg( "<mrml>%1" );
+
+ if ( transactionId.isNull() )
+ return msg.arg( "<mrml session-id=\"%1\">%1" ).arg( sessionId );
+ else
+ return msg.arg( "<mrml session-id=\"%1\" transaction-id=\"%1\">%1")
+ .arg( sessionId ).arg( transactionId );
+}
+
+void Mrml::emitData( const QCString& msg )
+{
+ mimeType( "text/mrml" );
+ data( msg );
+ processedSize( msg.count() );
+}
+
+void Mrml::mimetype( const KURL& url )
+{
+ if ( url.protocol() == "mrml" ) {
+ mimeType( "text/mrml" );
+ finished();
+ }
+ else
+ KIO::TCPSlaveBase::mimetype( url );
+}
diff --git a/kmrml/kmrml/mrml.desktop b/kmrml/kmrml/mrml.desktop
new file mode 100644
index 00000000..73abf1e0
--- /dev/null
+++ b/kmrml/kmrml/mrml.desktop
@@ -0,0 +1,60 @@
+[Desktop Entry]
+Comment=Multimedia Retrieval Markup Language Document
+Comment[af]=Multimedia Onttrekking Opmerk Taal Dokument
+Comment[ar]=مستند لغة ترميز استرجاع الوسائط المتعددة
+Comment[bs]=Multimedia Retrieval Markup Language dokument
+Comment[ca]=Document de llenguatge de marcatge de recuperació multimèdia
+Comment[cs]=Multimedia Retrieval Markup Language dokument
+Comment[cy]=Dogfen Multimedia Retrieval Markup Language
+Comment[da]=Multimedia Retrieval Markup Language-dokument
+Comment[de]=Multimedia Suche- und Beschreibungssprache-Dokument (MRML-Dokument)
+Comment[el]=Έγγραφο Multimedia Retrieval Markup Language
+Comment[es]=Documento de lenguaje de descripción de descargas multimedia
+Comment[et]=Multimeedia otsingu märgistuskeele (MRML) dokument
+Comment[eu]=Multimedia Retrieval Markup Language dokumentua
+Comment[fa]=سند زبان نشان‌گذاری بازیابی چند رسانه‌ای
+Comment[fi]=Multimedianhakuasiakirja
+Comment[fr]=Document en langage Multimedia Retrieval Markup (MRML)
+Comment[he]=מסמך שפת סימון לאחזור מולטימדיה
+Comment[hi]=मल्टीमीडिया रिट्राइवल मार्कअप लैंग्वेज दस्तावेज़
+Comment[hu]=MRML-fájl
+Comment[is]=Multimedia Retrieval Markup Language skjal
+Comment[it]=Documento MRML
+Comment[ja]=Multimedia Retrieval Markup Language ドキュメント
+Comment[kk]=MRML (Multimedia Retrieval Markup Language) құжаты
+Comment[km]=ឯកសារ Multimedia Retrieval Markup Language
+Comment[lt]=Multimedia Retrieval Markup kalbos dokumentas
+Comment[ms]=Dokumen Bahasa Capaian Tandatas Multimedia
+Comment[nb]=«Multimedia Retrieval Markup Language»-dokument
+Comment[nds]=Dokment in de Affraag-Utteekspraak för Multimedia-Dokmenten
+Comment[ne]=मल्टिमिडिया पुन: प्राप्ति मार्कअप भाषा कागजात
+Comment[nl]=Multimedia Retrieval Markup Language-document
+Comment[nn]=«Multimedia Retrieval Markup Language»-dokument
+Comment[nso]=Tokomane ya Leleme la Peakanyo ya Kutullo ya Multimedia
+Comment[pl]=Dokument MRML (Język Znacznikowy Pozyskiwania Multimediów)
+Comment[pt]=Documento de Multimedia Retrieval Markup Language
+Comment[pt_BR]=Documento da Linguagem de Marcação de Recuperação Multimídia
+Comment[ro]=Document MRML (limbaj de marcare pentru căutări multimedia)
+Comment[ru]=Документ MRML (Multimedia Retrieval Markup Language)
+Comment[se]=«Multimedia Retrieval Markup Language»-dokumeanta
+Comment[sk]=Dokument Multimedia Retrieval Markup Language
+Comment[sl]=Dokument Multimedia Retrieval Markup Language
+Comment[sr]=Документ у обележивачком језику за добављање мултимедије (MRML)
+Comment[sr@Latn]=Dokument u obeleživačkom jeziku za dobavljanje multimedije (MRML)
+Comment[sv]=Multimedia Retrieval Markup Language-dokument
+Comment[ta]=பல் ஊடக திரும்பப்பெறு அடையாள மொழி ஆவணம்
+Comment[tg]=Санади MRML (Multimedia Retrieval Markup Language)
+Comment[th]=เอกสาร Multimedia Retrieval Markup Language
+Comment[tr]=Multimedia Retrieval Markup Language Belgesi
+Comment[uk]=Документ формату зберігання мультимедіа
+Comment[ven]=Manwalwa a luambo lwau humbula zwa khasho nnzhi
+Comment[xh]=Uxwebhu Lolwimi Lophawulo phezulu Lokufumana i Multimedia
+Comment[zh_CN]=多媒体检索标记语言文档
+Comment[zh_HK]=多媒體取得標記語言文件
+Comment[zh_TW]=多媒體補償標記語言文件
+Comment[zu]=Ushicilelo Lwe-Multimedia Retrieval Markup Language
+Icon=html
+Type=MimeType
+MimeType=text/mrml
+Patterns=*.mrml;*.MRML;
+X-KDE-AutoEmbed=true
diff --git a/kmrml/kmrml/mrml.h b/kmrml/kmrml/mrml.h
new file mode 100644
index 00000000..f8088ef6
--- /dev/null
+++ b/kmrml/kmrml/mrml.h
@@ -0,0 +1,84 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef MRML_H
+#define MRML_H
+
+
+#include <kio/tcpslavebase.h>
+#include <kurl.h>
+
+#include <kmrml_config.h>
+#include "mrml_shared.h"
+
+class Mrml : public KIO::TCPSlaveBase
+{
+public:
+ Mrml( const QCString&, const QCString& );
+ ~Mrml();
+
+ virtual void get( const KURL& url );
+
+ virtual void mimetype( const KURL& url );
+
+private:
+ QCString readAll();
+ void emitData( const QCString& );
+
+ bool startSession( const KURL& url );
+
+ // helpers
+ inline QString sessionId() {
+ return metaData( MrmlShared::sessionId() );
+ }
+
+ // misc
+ short int port( const KURL& url )
+ {
+ return (url.port() != 0) ?
+ url.port() :
+ m_config.settingsForHost( url.host() ).port();
+ }
+
+ static QString mrmlString( const QString& sessionId,
+ const QString& transactionId = QString::null );
+
+ static QCString loginString();
+ static QCString getConfigurationString();
+ static QCString getSessionsString( const QString& username,
+ const QString& password );
+ QString user( const KURL& url ) {
+ return url.hasUser() ?
+ url.user() : m_config.defaultSettings().user;
+ }
+ QString pass( const KURL& url ) {
+ return url.hasPass() ?
+ url.pass() : m_config.defaultSettings().pass;
+ }
+
+ bool checkLocalServer( const KURL& url );
+
+ static const int bufsize;
+ QString defaultUser;
+ QString defaultPass;
+
+ KMrml::Config m_config;
+
+};
+
+#endif // MRML_H
diff --git a/kmrml/kmrml/mrml.protocol b/kmrml/kmrml/mrml.protocol
new file mode 100644
index 00000000..c3a732eb
--- /dev/null
+++ b/kmrml/kmrml/mrml.protocol
@@ -0,0 +1,10 @@
+[Protocol]
+exec=kio_mrml
+protocol=mrml
+input=none
+output=filesystem
+reading=true
+defaultMimetype=text/mrml
+determineMimetypeFromExtension=false
+Icon=image
+DocPath=kioslave/mrml.html
diff --git a/kmrml/kmrml/mrml_creator.cpp b/kmrml/kmrml/mrml_creator.cpp
new file mode 100644
index 00000000..fce84e36
--- /dev/null
+++ b/kmrml/kmrml/mrml_creator.cpp
@@ -0,0 +1,76 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "mrml_creator.h"
+
+QDomElement MrmlCreator::createMrml( QDomDocument& doc,
+ const QString& sessionId,
+ const QString& transactionId )
+{
+ QDomElement mrml = doc.createElement( "mrml" );
+ doc.appendChild( mrml );
+ mrml.setAttribute( MrmlShared::sessionId(), sessionId );
+ if ( !transactionId.isNull() )
+ mrml.setAttribute( MrmlShared::transactionId(), transactionId );
+
+ return mrml;
+}
+
+QDomElement MrmlCreator::configureSession( QDomElement& mrml,
+ const KMrml::Algorithm& algo,
+ const QString& sessionId )
+{
+ QDomDocument doc = mrml.ownerDocument();
+ QDomElement config = doc.createElement( MrmlShared::configureSession() );
+ mrml.appendChild( config );
+ config.setAttribute( MrmlShared::sessionId(), sessionId );
+ algo.toElement( config );
+
+ return config;
+}
+
+QDomElement MrmlCreator::addQuery( QDomElement& mrml, int resultSize )
+{
+ QDomElement query = mrml.ownerDocument().createElement("query-step");
+ mrml.appendChild( query );
+ // query.setAttribute( "query-step-id", "5" ); // ###
+ query.setAttribute( "result-size", QString::number( resultSize ));
+ return query;
+}
+
+QDomElement MrmlCreator::addRelevanceList( QDomElement& query )
+{
+ QDomElement elem =
+ query.ownerDocument().createElement("user-relevance-element-list");
+ query.appendChild( elem );
+ return elem;
+}
+
+/**
+ * Creates a <user-relevance-element> with the given attributes set.
+ */
+void MrmlCreator::createRelevanceElement( QDomDocument& doc,
+ QDomElement& parent,
+ const QString& url,
+ Relevance relevance )
+{
+ QDomElement element = doc.createElement( "user-relevance-element" );
+ element.setAttribute( "image-location", url );
+ element.setAttribute( "user-relevance", QString::number( relevance ) );
+ parent.appendChild( element );
+}
diff --git a/kmrml/kmrml/mrml_creator.h b/kmrml/kmrml/mrml_creator.h
new file mode 100644
index 00000000..2cc59e7a
--- /dev/null
+++ b/kmrml/kmrml/mrml_creator.h
@@ -0,0 +1,49 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001,2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef MRML_CREATOR_H
+#define MRML_CREATOR_H
+
+#include <qdom.h>
+
+#include <kurl.h>
+
+#include "mrml_elements.h"
+#include "mrml_shared.h"
+
+namespace MrmlCreator
+{
+ enum Relevance { Relevant = 1, Irrelevant = -1 };
+
+ QDomElement createMrml( QDomDocument& doc,
+ const QString& sessionId,
+ const QString& transactionId = QString::null );
+ QDomElement configureSession( QDomElement& mrml,
+ const KMrml::Algorithm& algo,
+ const QString& sessionId );
+ QDomElement addQuery( QDomElement& mrml, int resultSize );
+ QDomElement addRelevanceList( QDomElement& query );
+ /**
+ * Creates a <user-relevance-element> with the given attributes set.
+ */
+ void createRelevanceElement( QDomDocument& doc, QDomElement& parent,
+ const QString& url, Relevance relevance );
+
+}
+
+#endif // MRML_CREATOR_H
diff --git a/kmrml/kmrml/mrml_elements.cpp b/kmrml/kmrml/mrml_elements.cpp
new file mode 100644
index 00000000..20f3d04e
--- /dev/null
+++ b/kmrml/kmrml/mrml_elements.cpp
@@ -0,0 +1,358 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "mrml_elements.h"
+#include "mrml_shared.h"
+
+#include <kdatastream.h>
+
+#include <qdom.h>
+
+using namespace KMrml;
+
+//
+// MrmlElement is currently the baseclass for Algorithm and Collection. Both
+// may have a single child-element <query-paradigm-list>, with a number of
+// <query-paradigm> elements as children.
+//
+
+MrmlElement::MrmlElement( const QDomElement& elem )
+{
+ QValueList<QDomElement> list =
+ KMrml::directChildElements( elem, MrmlShared::queryParadigmList() );
+
+ Q_ASSERT( list.count() < 2 ); // There can be only one.
+
+ if ( list.count() )
+ m_paradigms.initFromDOM( list.first() );
+}
+
+
+void MrmlElement::setOtherAttributes( QDomElement& elem ) const
+{
+ QMapConstIterator<QString,QString> it = m_attributes.begin();
+ for ( ; it != m_attributes.end(); ++it )
+ {
+ elem.setAttribute( it.key(), it.data() );
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+AlgorithmList AlgorithmList::algorithmsForCollection( const Collection& coll ) const
+{
+ AlgorithmList list;
+
+ AlgorithmList::ConstIterator it = begin();
+ for ( ; it != end(); ++it )
+ {
+ Algorithm algo = *it;
+ if ( algo.paradigms().matches( coll.paradigms() ) )
+ {
+ algo.setCollectionId( coll.id() );
+ list.append( algo );
+ }
+ }
+
+ return list;
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+Collection::Collection( const QDomElement& elem )
+ : MrmlElement( elem )
+{
+ QDomNamedNodeMap attrs = elem.attributes();
+ for ( uint i = 0; i < attrs.length(); i++ )
+ {
+ QDomAttr attribute = attrs.item( i ).toAttr();
+ QString name = attribute.name();
+
+ if ( name == MrmlShared::collectionName() )
+ m_name = attribute.value();
+ else if ( name == MrmlShared::collectionId() )
+ m_id = attribute.value();
+
+ else // custom attributes
+ m_attributes.insert( name, attribute.value() );
+ }
+}
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+Algorithm::Algorithm( const QDomElement& elem )
+ : MrmlElement( elem )
+{
+ QDomNamedNodeMap attrs = elem.attributes();
+
+ for ( uint i = 0; i < attrs.length(); i++ )
+ {
+ QDomAttr attribute = attrs.item( i ).toAttr();
+ QString name = attribute.name();
+
+ if ( name == MrmlShared::algorithmName() )
+ m_name = attribute.value();
+ else if ( name == MrmlShared::algorithmId() )
+ m_id = attribute.value();
+ else if ( name == MrmlShared::algorithmType() )
+ m_type = attribute.value();
+
+ // not really necessary
+ else if ( name == MrmlShared::collectionId() )
+ m_collectionId = attribute.value();
+
+ else // custom attributes
+ m_attributes.insert( name, attribute.value() );
+ }
+
+ QDomElement propsElem = firstChildElement(elem, MrmlShared::propertySheet());
+ m_propertySheet.initFromDOM( propsElem );
+
+ qDebug("############# new algorithm: name: %s, id: %s, type: %s", m_name.latin1(), m_id.latin1(), m_type.latin1());
+}
+
+Algorithm Algorithm::defaultAlgorithm()
+{
+ Algorithm algo;
+ algo.m_id = "adefault";
+ algo.m_type = "adefault"; // ### not in the DTD
+ algo.m_name = "dummy";
+
+ return algo;
+}
+
+QDomElement Algorithm::toElement( QDomElement& parent ) const
+{
+ QDomDocument doc = parent.ownerDocument();
+ QDomElement algorithm = doc.createElement( MrmlShared::algorithm() );
+ parent.appendChild( algorithm );
+ setOtherAttributes( algorithm );
+
+ if ( !m_name.isEmpty() )
+ algorithm.setAttribute( MrmlShared::algorithmName(), m_name );
+ if ( !m_id.isEmpty() )
+ algorithm.setAttribute( MrmlShared::algorithmId(), m_id );
+ if ( !m_type.isEmpty() )
+ algorithm.setAttribute( MrmlShared::algorithmType(), m_type );
+
+ if ( !m_collectionId.isEmpty() )
+ algorithm.setAttribute( MrmlShared::collectionId(), m_collectionId );
+ return algorithm;
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+QueryParadigm::QueryParadigm( const QDomElement& elem )
+{
+ QDomNamedNodeMap attrs = elem.attributes();
+ for ( uint i = 0; i < attrs.count(); i++ )
+ {
+ QDomAttr attr = attrs.item( i ).toAttr();
+ m_attributes.insert( attr.name(), attr.value() );
+ if ( attr.name() == "type" )
+ m_type = attr.value();
+ }
+}
+
+bool QueryParadigm::matches( const QueryParadigm& other ) const
+{
+ return m_attributes.isEmpty() || other.m_attributes.isEmpty() ||
+ equalMaps( m_attributes, other.m_attributes );
+}
+
+bool QueryParadigm::equalMaps( const QMap<QString,QString> m1,
+ const QMap<QString,QString> m2 )
+{
+ if ( m1.count() != m2.count() )
+ return false;
+
+ QMapConstIterator<QString,QString> it = m1.begin();
+ for ( ; it != m1.end(); ++it )
+ {
+ QMapConstIterator<QString,QString> it2 = m2.find( it.key() );
+ if ( it2 == m2.end() || it.data() != it2.data() )
+ return false;
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+void QueryParadigmList::initFromDOM( const QDomElement& elem )
+{
+ clear();
+
+ QValueList<QDomElement> list =
+ KMrml::directChildElements( elem, MrmlShared::queryParadigm() );
+
+ QValueListConstIterator<QDomElement> it = list.begin();
+ for ( ; it != list.end(); ++it )
+ {
+ append( QueryParadigm( *it ));
+ }
+}
+
+// two QueryParadigmLists match, when there is at least one pair of
+// QueryParadigms that match (all attribute-value pairs are equal, or there
+// are no attributes at all).
+bool QueryParadigmList::matches( const QueryParadigmList& other ) const
+{
+ ConstIterator it = begin();
+
+ for ( ; it != end(); ++it )
+ {
+ ConstIterator oit = other.begin();
+ for ( ; oit != other.end(); ++oit )
+ if ( (*it).matches( *oit ) )
+ return true;
+ }
+
+ return false;
+}
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+QValueList<QDomElement> KMrml::directChildElements( const QDomElement& parent,
+ const QString& tagName )
+{
+ QValueList<QDomElement> list;
+
+ QDomNode node = parent.firstChild();
+ while ( !node.isNull() )
+ {
+ if ( node.isElement() && node.nodeName() == tagName )
+ list.append( node.toElement() );
+
+ node = node.nextSibling();
+ }
+
+ return list;
+}
+
+QDomElement KMrml::firstChildElement( const QDomElement& parent,
+ const QString& tagName )
+{
+ QDomNode node = parent.firstChild();
+ while ( !node.isNull() )
+ {
+ if ( node.isElement() && node.nodeName() == tagName )
+ return node.toElement();
+
+ node = node.nextSibling();
+ }
+
+ return QDomElement();
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+QDataStream& KMrml::operator<<( QDataStream& stream, const QueryParadigm& )
+{
+
+ return stream;
+}
+QDataStream& KMrml::operator>>( QDataStream& stream, QueryParadigm& )
+{
+
+ return stream;
+}
+
+QDataStream& KMrml::operator<<( QDataStream& stream, const QueryParadigmList& )
+{
+
+ return stream;
+}
+QDataStream& KMrml::operator>>( QDataStream& stream, QueryParadigmList& )
+{
+
+ return stream;
+}
+
+QDataStream& KMrml::operator<<( QDataStream& stream, const MrmlElement& )
+{
+
+ return stream;
+}
+QDataStream& KMrml::operator>>( QDataStream& stream, MrmlElement& )
+{
+
+ return stream;
+}
+
+QDataStream& KMrml::operator<<( QDataStream& stream, const Algorithm& )
+{
+
+ return stream;
+}
+QDataStream& KMrml::operator>>( QDataStream& stream, Algorithm& )
+{
+
+ return stream;
+}
+
+QDataStream& KMrml::operator<<( QDataStream& stream, const Collection& )
+{
+
+ return stream;
+}
+QDataStream& KMrml::operator>>( QDataStream& stream, Collection& )
+{
+ return stream;
+}
+
+template <class t> QDataStream& KMrml::operator<<( QDataStream& stream,
+ const MrmlElementList<t>& )
+{
+
+ return stream;
+}
+template <class t> QDataStream& KMrml::operator>>( QDataStream& stream,
+ MrmlElementList<t>& )
+{
+
+ return stream;
+}
+
+QDataStream& KMrml::operator<<( QDataStream& stream, const AlgorithmList& )
+{
+
+ return stream;
+}
+QDataStream& KMrml::operator>>( QDataStream& stream, AlgorithmList& )
+{
+
+ return stream;
+}
+
diff --git a/kmrml/kmrml/mrml_elements.h b/kmrml/kmrml/mrml_elements.h
new file mode 100644
index 00000000..09d2a4a8
--- /dev/null
+++ b/kmrml/kmrml/mrml_elements.h
@@ -0,0 +1,255 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef MRML_ELEMENTS_H
+#define MRML_ELEMENTS_H
+
+#include <qdom.h>
+#include <qmap.h>
+#include <qstringlist.h>
+#include <qvaluelist.h>
+
+#include "mrml_shared.h"
+#include "propertysheet.h"
+
+#include <assert.h>
+
+namespace KMrml
+{
+ class PropertySheet;
+
+ class QueryParadigm
+ {
+ public:
+ QueryParadigm() {}
+ QueryParadigm( const QDomElement& elem );
+ bool matches( const QueryParadigm& other ) const;
+ QString type() const { return m_type; }
+
+// bool operator== ( const QueryParadigm& p1, const QueryParadigm& p2 )
+
+ private:
+ QString m_type;
+ QMap<QString,QString> m_attributes;
+
+ static bool equalMaps( const QMap<QString,QString>,
+ const QMap<QString,QString> );
+ };
+
+ class QueryParadigmList : protected QValueList<QueryParadigm>
+ {
+ public:
+ typedef QValueListIterator<QueryParadigm> Iterator;
+ typedef QValueListConstIterator<QueryParadigm> ConstIterator;
+
+ void initFromDOM( const QDomElement& elem );
+ bool matches( const QueryParadigmList& other ) const;
+ };
+
+ class MrmlElement
+ {
+ public:
+ MrmlElement() {}
+ MrmlElement( const QDomElement& elem );
+ virtual ~MrmlElement() {}
+
+ QString id() const { return m_id; }
+ QString name() const { return m_name; }
+ QString attribute( const QString& name ) const { return m_attributes[ name ]; }
+ QueryParadigmList paradigms() const { return m_paradigms; }
+
+
+ QMapConstIterator<QString,QString> attributeIterator() const {
+ return m_attributes.begin();
+ }
+ QMapConstIterator<QString,QString> end() const { return m_attributes.end(); }
+
+ bool isValid() const { return !m_name.isNull() && !m_id.isNull(); }
+
+ protected:
+ QString m_id;
+ QString m_name;
+ QueryParadigmList m_paradigms;
+ QMap<QString,QString> m_attributes;
+
+ void setOtherAttributes( QDomElement& elem ) const;
+ };
+
+ class Algorithm : public MrmlElement
+ {
+ public:
+ Algorithm() { m_collectionId = "adefault"; }
+ Algorithm( const QDomElement& elem );
+ QString type() const { return m_type; }
+
+ QString collectionId() const
+ {
+ return m_collectionId;
+ }
+ void setCollectionId( const QString& id )
+ {
+ m_collectionId = id;
+ }
+
+ QDomElement toElement( QDomElement& parent ) const;
+ const PropertySheet& propertySheet() const;
+
+ static Algorithm defaultAlgorithm();
+
+ private:
+ QString m_type;
+ PropertySheet m_propertySheet;
+
+ QString m_collectionId;
+ };
+
+ class Collection : public MrmlElement
+ {
+ public:
+ Collection() {}
+ Collection( const QDomElement& elem );
+ };
+
+ template <class t> class MrmlElementList : public QValueList<t>
+ {
+ public:
+ typedef QValueListIterator<t> Iterator;
+ typedef QValueListConstIterator<t> ConstIterator;
+
+ /**
+ * Creates an invalid element.
+ */
+ MrmlElementList( const QString& tagName ) :
+ QValueList<t>(),
+ m_tagName( tagName ) {}
+ MrmlElementList( const QDomElement& elem, const QString& tagName ) :
+ QValueList<t>(),
+ m_tagName( tagName )
+ {
+ initFromDOM( elem );
+ }
+ virtual ~MrmlElementList() {};
+
+ void initFromDOM( const QDomElement& elem )
+ {
+ assert( !m_tagName.isEmpty() );
+
+ QValueList<t>::clear();
+
+ QDomNodeList list = elem.elementsByTagName( m_tagName );
+ for ( uint i = 0; i < list.length(); i++ )
+ {
+ QDomElement elem = list.item( i ).toElement();
+ t item( elem );
+ if ( item.isValid() )
+ append( item );
+ }
+ }
+
+ t findByName( const QString& name ) const
+ {
+ QValueListConstIterator<t> it = QValueList<t>::begin();
+ for ( ; it != QValueList<t>::end(); ++it )
+ {
+ if ( (*it).name() == name )
+ return *it;
+ }
+
+ return t();
+ }
+
+ t findById( const QString& id ) const
+ {
+ QValueListConstIterator<t> it = QValueList<t>::begin();
+ for ( ; it != QValueList<t>::end(); ++it )
+ {
+ if ( (*it).id() == id )
+ return *it;
+ }
+
+ return MrmlElement();
+ }
+
+ QStringList itemNames() const {
+ QStringList list;
+ QValueListConstIterator<t> it = QValueList<t>::begin();
+ for ( ; it != QValueList<t>::end(); ++it )
+ list.append( (*it).name() );
+
+ return list;
+ }
+
+ void setItemName( const QString& tagName ) { m_tagName = tagName; }
+ QString tagName() const { return m_tagName; }
+
+ private:
+ QString m_tagName;
+ MrmlElementList();
+ };
+
+ class AlgorithmList : public MrmlElementList<Algorithm>
+ {
+ public:
+ AlgorithmList() :
+ MrmlElementList<Algorithm>( MrmlShared::algorithm() )
+ {}
+
+ AlgorithmList algorithmsForCollection( const Collection& coll ) const;
+ };
+
+ class CollectionList : public MrmlElementList<Collection>
+ {
+ public:
+ CollectionList() :
+ MrmlElementList<Collection>( MrmlShared::collection() )
+ {}
+ };
+
+
+ QValueList<QDomElement> directChildElements( const QDomElement& parent,
+ const QString& tagName);
+ QDomElement firstChildElement( const QDomElement& parent,
+ const QString& tagName );
+
+
+ QDataStream& operator<<( QDataStream& stream, const QueryParadigm& );
+ QDataStream& operator>>( QDataStream& stream, QueryParadigm& );
+
+ QDataStream& operator<<( QDataStream& stream, const QueryParadigmList& );
+ QDataStream& operator>>( QDataStream& stream, QueryParadigmList& );
+
+ QDataStream& operator<<( QDataStream& stream, const MrmlElement& );
+ QDataStream& operator>>( QDataStream& stream, MrmlElement& );
+
+ QDataStream& operator<<( QDataStream& stream, const Algorithm& );
+ QDataStream& operator>>( QDataStream& stream, Algorithm& );
+
+ QDataStream& operator<<( QDataStream& stream, const Collection& );
+ QDataStream& operator>>( QDataStream& stream, Collection& );
+
+ template <class t> QDataStream& operator<<( QDataStream&,
+ const MrmlElementList<t>& );
+ template <class t> QDataStream& operator>>( QDataStream&,
+ MrmlElementList<t>& );
+
+ QDataStream& operator<<( QDataStream&, const AlgorithmList& );
+ QDataStream& operator>>( QDataStream&, AlgorithmList& );
+
+}
+
+#endif // MRML_ELEMENTS_H
diff --git a/kmrml/kmrml/mrml_part.cpp b/kmrml/kmrml/mrml_part.cpp
new file mode 100644
index 00000000..4d3f65e6
--- /dev/null
+++ b/kmrml/kmrml/mrml_part.cpp
@@ -0,0 +1,857 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001,2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qcheckbox.h>
+#include <qcursor.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qgrid.h>
+#include <qhgroupbox.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qtooltip.h>
+#include <qvbox.h>
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kcombobox.h>
+#include <kconfig.h>
+#include <kdatastream.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kinstance.h>
+#include <kio/job.h>
+#include <kio/jobclasses.h>
+#include <kmessagebox.h>
+#include <knuminput.h>
+#include <kprotocolinfo.h>
+#include <kparts/genericfactory.h>
+#include <ktempfile.h>
+
+#include <mrml_utils.h>
+
+#include "algorithmdialog.h"
+#include "browser.h"
+#include "collectioncombo.h"
+#include "mrml_creator.h"
+#include "mrml_elements.h"
+#include "mrml_shared.h"
+#include "mrml_view.h"
+#include "mrml_part.h"
+#include "version.h"
+
+using namespace KMrml;
+
+extern "C"
+{
+ void * init_libkmrmlpart() {
+ return new KMrml::PartFactory();
+ }
+}
+
+KInstance * PartFactory::s_instance = 0L;
+
+PartFactory::PartFactory()
+ : KParts::Factory()
+{
+ MrmlShared::ref();
+}
+
+PartFactory::~PartFactory()
+{
+ MrmlShared::deref();
+ delete s_instance;
+ s_instance = 0L;
+}
+
+KInstance * PartFactory::instance()
+{
+ if ( !s_instance ) {
+ s_instance = new KInstance( "kmrml" );
+ KGlobal::locale()->insertCatalogue( "kmrml" );
+ }
+ return s_instance;
+}
+
+KParts::Part * PartFactory::createPartObject( QWidget *parentWidget,
+ const char *widgetName,
+ QObject *parent,
+ const char *name,
+ const char *,
+ const QStringList& args )
+{
+ return new MrmlPart( parentWidget, widgetName, parent, name, args );
+}
+
+
+// can't use this due to MrmlShared ref-counting
+// typedef KParts::GenericFactory<KMrml::MrmlPart> PartFactory;
+// K_EXPORT_COMPONENT_FACTORY( mrmlpart, PartFactory )
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+uint MrmlPart::s_sessionId = 0;
+
+MrmlPart::MrmlPart( QWidget *parentWidget, const char * /* widgetName */,
+ QObject *parent, const char *name,
+ const QStringList& /* args */ )
+ : KParts::ReadOnlyPart( parent, name ),
+ m_job( 0L ),
+ m_status( NeedCollection )
+{
+ m_sessionId = QString::number( s_sessionId++ ).prepend("kmrml_");
+
+ setName( "MRML Part" );
+ m_browser = new Browser( this, "mrml browserextension");
+ setInstance( PartFactory::instance(), true ); // do load plugins :)
+ KConfig *config = PartFactory::instance()->config();
+ config->setGroup("MRML Settings");
+
+ QVBox *box = new QVBox( parentWidget, "main mrml box" );
+ m_view = new MrmlView( box, "MrmlView" );
+ connect( m_view, SIGNAL( activated( const KURL&, ButtonState )),
+ this, SLOT( slotActivated( const KURL&, ButtonState )));
+ connect( m_view, SIGNAL( onItem( const KURL& )),
+ this, SLOT( slotSetStatusBar( const KURL& )));
+
+ m_panel = new QHGroupBox( box, "buttons box" );
+
+ QGrid *comboGrid = new QGrid( 2, m_panel, "combo grid" );
+ comboGrid->setSpacing( KDialog::spacingHint() );
+
+ (void) new QLabel( i18n("Server to query:"), comboGrid );
+
+ m_hostCombo = new KComboBox( false, comboGrid, "host combo" );
+ initHostCombo();
+ connect( m_hostCombo, SIGNAL( activated( const QString& ) ),
+ SLOT( slotHostComboActivated( const QString& )));
+
+ (void) new QLabel( i18n("Search in collection:"), comboGrid );
+ m_collectionCombo = new CollectionCombo( comboGrid, "collection-combo" );
+ // will be re-set in initCollections(), but we need to set it here to
+ // prevent crashes when the connection to the server fails
+ m_collectionCombo->setCollections( &m_collections );
+
+ m_algoButton = new QPushButton( QString::null, m_panel );
+ m_algoButton->setPixmap( SmallIcon("configure") );
+ m_algoButton->setFixedSize( m_algoButton->sizeHint() );
+ connect( m_algoButton, SIGNAL( clicked() ),
+ SLOT( slotConfigureAlgorithm() ));
+ QToolTip::add( m_algoButton, i18n("Configure algorithm") );
+
+ QWidget *spacer = new QWidget( m_panel );
+ spacer->setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding,
+ QSizePolicy::Minimum ) );
+
+ int resultSize = config->readNumEntry( "Result-size", 20 );
+ m_resultSizeInput = new KIntNumInput( resultSize, m_panel );
+ m_resultSizeInput->setRange( 1, 100 );
+ m_resultSizeInput->setLabel( i18n("Maximum result images:") );
+
+ QVBox *tmp = new QVBox( m_panel );
+ m_random = new QCheckBox( i18n("Random search"), tmp );
+
+ m_startButton = new QPushButton( QString::null, tmp );
+ connect( m_startButton, SIGNAL( clicked() ), SLOT( slotStartClicked() ));
+ setStatus( NeedCollection );
+
+ setWidget( box );
+
+ // setXMLFile( "mrml_part.rc" );
+
+ slotSetStatusBar( QString::null );
+
+ enableServerDependentWidgets( false );
+}
+
+MrmlPart::~MrmlPart()
+{
+ closeURL();
+}
+
+void MrmlPart::enableServerDependentWidgets( bool enable )
+{
+ m_collectionCombo->setEnabled( enable );
+ m_algoButton->setEnabled( enable && false ); // ### re-enable!!!
+}
+
+void MrmlPart::initCollections( const QDomElement& elem )
+{
+ m_collections.initFromDOM( elem );
+
+ m_collectionCombo->setCollections( &m_collections );
+ enableServerDependentWidgets( m_collectionCombo->count() > 0 );
+
+ if ( m_collectionCombo->count() == 0 )
+ {
+ KMessageBox::information( widget(),
+ i18n("There is no image collection available\n"
+ "at %1.\n"), i18n("No Image Collection"));
+ setStatus( NeedCollection );
+ }
+ else
+ m_collectionCombo->updateGeometry(); // adjust the entire grid
+}
+
+void MrmlPart::initAlgorithms( const QDomElement& elem )
+{
+ m_algorithms.initFromDOM( elem );
+}
+
+// this is where we start!
+bool MrmlPart::openURL( const KURL& url )
+{
+ closeURL();
+
+ if ( url.protocol() != "mrml" || !url.isValid() ) {
+ qWarning("MrmlPart::openURL: cannot handle url: %s", url.prettyURL().latin1());
+ return false; // what to do with that?
+ }
+
+ m_url = url;
+ QString host = url.host().isEmpty() ?
+ QString::fromLatin1("localhost") : url.host();
+
+ m_hostCombo->setCurrentItem( host );
+
+ // urls we need to download before starting the query
+ KURL::List downloadList;
+
+ m_queryList.clear();
+ QString param = url.queryItem( "relevant" );
+ QStringList list = QStringList::split( ';', param );
+
+ // we can only search by example on localhost
+ if ( host != "localhost" )
+ {
+ if ( !list.isEmpty() )
+ KMessageBox::sorry( m_view,
+ i18n("You can only search by example images "
+ "on a local indexing server."),
+ i18n("Only Local Servers Possible") );
+ }
+
+ else // localhost query
+ {
+ for( QStringList::Iterator it = list.begin(); it != list.end(); ++it )
+ {
+ KURL u;
+ if ( (*it).at(0) == '/' )
+ u.setPath( *it );
+ else
+ u = *it;
+
+ if ( u.isValid() )
+ {
+ if ( u.isLocalFile() )
+ m_queryList.append( u );
+ else
+ downloadList.append( u );
+ }
+ }
+
+
+ // ### we need a real solution for this!
+ // gift refuses to start when no config file is available.
+ if ( !QFile::exists( m_config.mrmldDataDir() + "/gift-config.mrml" ) )
+ {
+ if ( KMessageBox::questionYesNo(0L,
+ i18n("There are no indexable folders "
+ "specified. Do you want to configure them "
+ "now?"),
+ i18n("Configuration Missing"),
+ i18n("Configure"),
+ i18n("Do Not Configure"),
+ "kmrml_ask_configure_gift" )
+ == KMessageBox::Yes )
+ {
+ KApplication::kdeinitExec( "kcmshell",
+ QString::fromLatin1("kcmkmrml"));
+ setStatus( NeedCollection );
+ return false;
+ }
+ }
+ }
+
+
+ if ( !downloadList.isEmpty() )
+ downloadReferenceFiles( downloadList );
+ else
+ contactServer( m_url );
+
+ return true;
+}
+
+void MrmlPart::contactServer( const KURL& url )
+{
+ m_job = transferJob( url );
+
+ m_job->addMetaData( MrmlShared::kio_task(), MrmlShared::kio_initialize() );
+
+ QString host = url.host().isEmpty() ?
+ QString::fromLatin1("localhost") : url.host();
+
+ slotSetStatusBar( i18n("Connecting to indexing server at %1...").arg( host ));
+}
+
+//
+// schedules a download all urls of downloadList (all remote and wellformed)
+// No other downloads are running (closeURL() has been called before)
+//
+void MrmlPart::downloadReferenceFiles( const KURL::List& downloadList )
+{
+ assert( m_downloadJobs.isEmpty() );
+
+ KURL::List::ConstIterator it = downloadList.begin();
+ for ( ; it != downloadList.end(); it++ )
+ {
+ QString extension;
+ int index = (*it).fileName().findRev( '.' );
+ if ( index != -1 )
+ extension = (*it).fileName().mid( index );
+
+ KTempFile tmpFile( QString::null, extension );
+ if ( tmpFile.status() != 0 )
+ {
+ kdWarning() << "Can't create temporary file, skipping: " << *it << endl;
+
+ continue;
+ }
+
+ m_tempFiles.append( tmpFile.name() );
+ KURL destURL;
+ destURL.setPath( tmpFile.name() );
+
+ KIO::FileCopyJob *job = KIO::file_copy( *it, destURL, -1,
+ true /* overwrite tmpfile */ );
+ connect( job, SIGNAL( result( KIO::Job * ) ),
+ SLOT( slotDownloadResult( KIO::Job * ) ));
+ m_downloadJobs.append( job );
+ // ### should this be only called for one job?
+ emit started( job );
+ }
+
+ if ( !m_downloadJobs.isEmpty() )
+ slotSetStatusBar( i18n("Downloading reference files...") );
+ else // probably never happens
+ contactServer( m_url );
+}
+
+bool MrmlPart::closeURL()
+{
+ m_view->stopDownloads();
+ m_view->clear();
+
+ QPtrListIterator<KIO::FileCopyJob> it( m_downloadJobs );
+ for ( ; it.current(); ++it )
+ it.current()->kill();
+ m_downloadJobs.clear();
+
+ QStringList::Iterator tit = m_tempFiles.begin();
+ for ( ; tit != m_tempFiles.end(); ++tit )
+ QFile::remove( *tit );
+ m_tempFiles.clear();
+
+ if ( m_job ) {
+ m_job->kill();
+ m_job = 0L;
+ }
+
+ setStatus( NeedCollection );
+
+ return true;
+}
+
+KIO::TransferJob * MrmlPart::transferJob( const KURL& url )
+{
+ KIO::TransferJob *job = KIO::get( url, true, false ); // reload, no gui
+ job->setAutoErrorHandlingEnabled( true, m_view );
+ connect( job, SIGNAL( result( KIO::Job * )),
+ SLOT( slotResult( KIO::Job * )));
+ connect( job, SIGNAL( data( KIO::Job *, const QByteArray& )),
+ SLOT( slotData( KIO::Job *, const QByteArray& )));
+
+// ###
+// connect( job, SIGNAL( infoMessage( KIO::Job *, const QString& )),
+// SLOT( slotResult( KIO::Job *, const QString& )));
+
+ job->setWindow( widget() );
+ if ( !m_sessionId.isEmpty() )
+ job->addMetaData( MrmlShared::sessionId(), m_sessionId );
+
+ emit started( job );
+ emit setWindowCaption( url.prettyURL() );
+ setStatus( InProgress );
+
+ return job;
+}
+
+void MrmlPart::slotResult( KIO::Job *job )
+{
+ if ( job == m_job )
+ m_job = 0L;
+
+ slotSetStatusBar( QString::null );
+
+ if ( !job->error() )
+ emit completed();
+ else {
+ emit canceled( job->errorString() );
+// qDebug("*** canceled: error: %s", job->errorString().latin1());
+ }
+
+
+ bool auto_random = m_view->isEmpty() && m_queryList.isEmpty();
+ m_random->setChecked( auto_random );
+ m_random->setEnabled( !auto_random );
+ setStatus( job->error() ? NeedCollection : CanSearch );
+
+ if ( !job->error() && !m_queryList.isEmpty() ) {
+ // we have a connection and we got a list of relevant URLs to query for
+ // (via the URL)
+
+ createQuery( &m_queryList );
+ m_queryList.clear();
+ }
+}
+
+// ### when user cancels download, we crash :(
+void MrmlPart::slotDownloadResult( KIO::Job *job )
+{
+ assert( job->inherits( "KIO::FileCopyJob" ) );
+ KIO::FileCopyJob *copyJob = static_cast<KIO::FileCopyJob*>( job );
+
+ if ( !copyJob->error() )
+ m_queryList.append( copyJob->destURL() );
+
+ m_downloadJobs.removeRef( copyJob );
+
+ if ( m_downloadJobs.isEmpty() ) // finally, we can start the query!
+ {
+ if ( m_queryList.isEmpty() ) // rather unlikely, but could happen ;)
+ {
+ kdWarning() << "Couldn't download the reference files. Will start a random search now" << endl;
+ }
+
+ contactServer( m_url );
+ }
+}
+
+// mrml-document in the bytearray
+void MrmlPart::slotData( KIO::Job *, const QByteArray& data )
+{
+ if ( data.isEmpty() )
+ return;
+
+ QDomDocument doc;
+ doc.setContent( data );
+
+ if ( !doc.isNull() )
+ parseMrml( doc );
+}
+
+void MrmlPart::parseMrml( QDomDocument& doc )
+{
+ QDomNode mrml = doc.documentElement(); // root element
+ if ( !mrml.isNull() ) {
+ QDomNode child = mrml.firstChild();
+ for ( ; !child.isNull(); child = child.nextSibling() ) {
+// qDebug("**** HERE %s", child.nodeName().latin1());
+ if ( child.isElement() ) {
+ QDomElement elem = child.toElement();
+
+ QString tagName = elem.tagName();
+
+ if ( tagName == "acknowledge-session-op" )
+ m_sessionId = elem.attribute( MrmlShared::sessionId() );
+
+ else if ( tagName == MrmlShared::algorithmList() ) {
+ initAlgorithms( elem );
+ }
+
+ else if ( tagName == MrmlShared::collectionList() ) {
+ initCollections( elem );
+ }
+
+ else if ( tagName == "error" ) {
+ KMessageBox::information( widget(),
+ i18n("Server returned error:\n%1\n")
+ .arg( elem.attribute( "message" )),
+ i18n("Server Error") );
+ }
+
+ else if ( tagName == "query-result" ) {
+ m_view->clear();
+ parseQueryResult( elem );
+ }
+
+
+ } // child.isElement()
+ }
+ } // !mrml.isNull()
+}
+
+void MrmlPart::parseQueryResult( QDomElement& queryResult )
+{
+ QDomNode child = queryResult.firstChild();
+ for ( ; !child.isNull(); child = child.nextSibling() ) {
+ if ( child.isElement() ) {
+ QDomElement elem = child.toElement();
+ QString tagName = elem.tagName();
+
+ if ( tagName == "query-result-element-list" ) {
+ QValueList<QDomElement> list =
+ KMrml::directChildElements( elem, "query-result-element" );
+
+ QValueListConstIterator<QDomElement> it = list.begin();
+ for ( ; it != list.end(); ++it )
+ {
+ QDomNamedNodeMap a = (*it).attributes();
+ m_view->addItem( KURL( (*it).attribute("image-location" ) ),
+ KURL( (*it).attribute("thumbnail-location" ) ),
+ (*it).attribute("calculated-similarity"));
+
+ }
+ }
+
+ else if ( tagName == "query-result" )
+ parseQueryResult( elem );
+ }
+ }
+}
+
+// creates/stops the query when the Start/Stop button was pressed
+void MrmlPart::slotStartClicked()
+{
+ if ( m_status == InProgress )
+ {
+ closeURL();
+ m_startButton->setText( i18n("&Search" ) );
+ return;
+ }
+
+ // we need to reconnect, if the initial openURL() didn't work due to
+ // the gift not being available.
+ if ( m_status == NeedCollection )
+ {
+ openURL( m_url );
+ return;
+ }
+
+ // cut off an eventual query and reference from the url, when the user
+ // performs a real query (otherwise restoreState() would restore and
+ // re-do the query from the URL
+ m_url.setRef( QString::null );
+ m_url.setQuery( QString::null );
+
+ createQuery();
+ m_browser->openURLNotify();
+}
+
+//
+// relevantItems is 0L when called from slotStartClicked() and set to a
+// non-empty list when called initially, from the commandline.
+//
+void MrmlPart::createQuery( const KURL::List * relevantItems )
+{
+ if ( relevantItems && relevantItems->isEmpty() )
+ return;
+
+ QDomDocument doc( "mrml" );
+ QDomElement mrml = MrmlCreator::createMrml( doc,
+ sessionId(),
+ transactionId() );
+
+ Collection coll = currentCollection();
+// qDebug("** collection: name: %s, id: %s, valid: %i", coll.name().latin1(), coll.id().latin1(), coll.isValid());
+ Algorithm algo = firstAlgorithmForCollection( coll );
+// qDebug("** algorithm: name: %s, id: %s, valid: %i, collection-id: %s", algo.name().latin1(), algo.id().latin1(), algo.isValid(), algo.collectionId().latin1());
+
+ if ( algo.isValid() )
+ {
+ MrmlCreator::configureSession( mrml, algo, sessionId() );
+ }
+
+ QDomElement query = MrmlCreator::addQuery( mrml,
+ m_resultSizeInput->value() );
+ if ( algo.isValid() )
+ query.setAttribute( MrmlShared::algorithmId(), algo.id() );
+
+ // ### result-cutoff, query-type?
+
+ // start-up with/without urls on the commandline via mrmlsearch
+ if ( relevantItems )
+ {
+ QDomElement elem = MrmlCreator::addRelevanceList( query );
+ KURL::List::ConstIterator it = relevantItems->begin();
+ for ( ; it != relevantItems->end(); ++it )
+ MrmlCreator::createRelevanceElement( doc, elem, (*it).url(),
+ MrmlCreator::Relevant );
+ }
+
+ // get relevant items from the view? Only do this when relevantItems is 0L
+ else if ( !m_random->isChecked() )
+ {
+ QDomElement relevants = MrmlCreator::addRelevanceList( query );
+ m_view->addRelevanceToQuery( doc, relevants );
+ }
+
+ performQuery( doc );
+}
+
+Collection MrmlPart::currentCollection() const
+{
+ return m_collectionCombo->current();
+}
+
+Algorithm MrmlPart::firstAlgorithmForCollection( const Collection& coll ) const
+{
+ if ( !m_algorithms.isEmpty() )
+ {
+ AlgorithmList::ConstIterator it = m_algorithms.begin();
+ for ( ; it != m_algorithms.end(); ++it )
+ {
+ Algorithm algo = *it;
+ if ( algo.paradigms().matches( coll.paradigms() ) )
+ {
+ algo.setCollectionId( coll.id() );
+ return algo;
+ }
+ }
+ }
+
+ qDebug("#################### -> ADEFAULT!");
+ Algorithm algo = Algorithm::defaultAlgorithm();
+ algo.setCollectionId( coll.id() );
+ return algo;
+}
+
+// emits the given QDomDocument for eventual plugins, checks after that
+// if there are any relevance elements. If there are none, random search is
+// implied and performed.
+// finally, the search is actually started
+void MrmlPart::performQuery( QDomDocument& doc )
+{
+ QDomElement mrml = doc.documentElement();
+
+ emit aboutToStartQuery( doc ); // let plugins play with it :)
+
+ // no items available? All "neutral"? -> random search
+
+ QDomElement queryStep = KMrml::firstChildElement( mrml, "query-step" );
+ bool randomSearch = false;
+
+ if ( !queryStep.isNull() )
+ {
+ QDomElement relevanceList =
+ KMrml::firstChildElement(queryStep, "user-relevance-element-list");
+ QValueList<QDomElement> relevanceElements =
+ KMrml::directChildElements( relevanceList,
+ "user-relevance-element" );
+
+ randomSearch = relevanceElements.isEmpty();
+
+ if ( randomSearch )
+ {
+ m_random->setChecked( true );
+ m_random->setEnabled( false );
+ queryStep.setAttribute("query-type", "at-random");
+
+ // remove user-relevance-element-list element for random search
+ relevanceList.parentNode().removeChild( relevanceList );
+ }
+ }
+ else
+ {
+ KMessageBox::error( m_view, i18n("Error formulating the query. The "
+ "\"query-step\" element is missing."),
+ i18n("Query Error") );
+ }
+
+ m_job = transferJob( url() );
+ slotSetStatusBar( randomSearch ? i18n("Random search...") :
+ i18n("Searching...") );
+ m_job->addMetaData( MrmlShared::kio_task(), MrmlShared::kio_startQuery() );
+ qDebug("\n\nSending XML:\n%s", doc.toString().latin1());
+ m_job->addMetaData( MrmlShared::mrml_data(), doc.toString() );
+}
+
+void MrmlPart::slotSetStatusBar( const QString& text )
+{
+ if ( text.isEmpty() )
+ emit setStatusBarText( i18n("Ready.") );
+ else
+ emit setStatusBarText( text );
+}
+
+void MrmlPart::slotActivated( const KURL& url, ButtonState button )
+{
+ if ( button == LeftButton )
+ emit m_browser->openURLRequest( url );
+ else if ( button == MidButton )
+ emit m_browser->createNewWindow( url );
+ else if ( button == RightButton ) {
+ // enableExtensionActions( url, true ); // for now
+ emit m_browser->popupMenu( QCursor::pos(), url, QString::null );
+ // enableExtensionActions( url, false );
+ }
+}
+
+void MrmlPart::enableExtensionActions( const KURL& url, bool enable )
+{
+ bool del = KProtocolInfo::supportsDeleting( url );
+ emit m_browser->enableAction( "copy", enable );
+ emit m_browser->enableAction( "trash", del );
+ emit m_browser->enableAction( "del", del );
+ emit m_browser->enableAction( "shred", url.isLocalFile() );
+ emit m_browser->enableAction( "properties", enable );
+ // emit m_browser->enableAction( "print", enable ); // ### later
+}
+
+
+// only implemented because it's abstract in the baseclass
+bool MrmlPart::openFile()
+{
+ return false;
+}
+
+void MrmlPart::slotConfigureAlgorithm()
+{
+ m_algoButton->setEnabled( false );
+
+ m_algoConfig = new AlgorithmDialog( m_algorithms, m_collections,
+ currentCollection(),
+ m_view, "algorithm configuration" );
+ connect( m_algoConfig, SIGNAL( applyClicked() ),
+ SLOT( slotApplyAlgoConfig() ));
+ connect( m_algoConfig, SIGNAL( finished() ),
+ SLOT( slotAlgoConfigFinished() ));
+
+ m_algoConfig->show();
+}
+
+void MrmlPart::slotApplyAlgoConfig()
+{
+ // ###
+}
+
+void MrmlPart::slotAlgoConfigFinished()
+{
+ if ( m_algoConfig->result() == QDialog::Accepted )
+ slotApplyAlgoConfig();
+
+ m_algoButton->setEnabled( true );
+ m_algoConfig->deleteLater();
+ m_algoConfig = 0L;
+}
+
+void MrmlPart::initHostCombo()
+{
+ m_hostCombo->clear();
+ m_hostCombo->insertStringList( m_config.hosts() );
+}
+
+void MrmlPart::slotHostComboActivated( const QString& host )
+{
+ ServerSettings settings = m_config.settingsForHost( host );
+ openURL( settings.getUrl() );
+}
+
+void MrmlPart::setStatus( Status status )
+{
+ switch ( status )
+ {
+ case NeedCollection:
+ m_startButton->setText( i18n("&Connect") );
+ break;
+ case CanSearch:
+ m_startButton->setText( i18n("&Search") );
+ break;
+ case InProgress:
+ m_startButton->setText( i18n("Sto&p") );
+ break;
+ };
+
+ m_status = status;
+}
+
+
+void MrmlPart::saveState( QDataStream& stream )
+{
+ stream << url();
+ stream << m_sessionId;
+ stream << m_queryList;
+// stream << m_algorithms;
+// stream << m_collections;
+
+ stream << m_resultSizeInput->value();
+ stream << *m_collectionCombo;
+
+ m_view->saveState( stream );
+}
+
+void MrmlPart::restoreState( QDataStream& stream )
+{
+ KURL url;
+ stream >> url;
+
+ stream >> m_sessionId;
+ stream >> m_queryList;
+// stream >> m_algorithms;
+// stream >> m_collections;
+
+ int resultSize;
+ stream >> resultSize;
+ m_resultSizeInput->setValue( resultSize );
+ stream >> *m_collectionCombo;
+
+ m_view->restoreState( stream );
+
+// openURL( url );
+ m_url = url;
+}
+
+KAboutData * MrmlPart::createAboutData()
+{
+ KAboutData *data = new KAboutData(
+ "kmrml",
+ I18N_NOOP("MRML Client for KDE"),
+ KMRML_VERSION,
+ I18N_NOOP("A tool to search for images by their content"),
+ KAboutData::License_GPL,
+ I18N_NOOP("(c) 2001-2002, Carsten Pfeiffer"),
+ 0,
+ I18N_NOOP("http://devel-home.kde.org/~pfeiffer/kmrml/") );
+
+ data->addAuthor( "Carsten Pfeiffer",
+ I18N_NOOP("Developer, Maintainer"),
+ "pfeiffer@kde.org" );
+ data->addCredit( "Wolfgang Mller",
+ I18N_NOOP("Developer of the GIFT, Helping Hand") );
+
+ return data;
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+#include "mrml_part.moc"
diff --git a/kmrml/kmrml/mrml_part.desktop b/kmrml/kmrml/mrml_part.desktop
new file mode 100644
index 00000000..90017794
--- /dev/null
+++ b/kmrml/kmrml/mrml_part.desktop
@@ -0,0 +1,67 @@
+[Desktop Entry]
+Type=Service
+Exec=blahfoo
+Name=MRML View
+Name[ar]=برنامج MRML View
+Name[br]=Gwel MRML
+Name[ca]=Vista MRML
+Name[cs]=MRML pohled
+Name[cy]=Gwelydd MRML
+Name[da]=MRML-visning
+Name[de]=MRML-Ansicht
+Name[el]=Προβολή MRML
+Name[eo]=MRML-Rigardo
+Name[es]=Vista de MRML
+Name[et]=MRML vaade
+Name[eu]=MRML ikuspegia
+Name[fa]=نمای MRML
+Name[fi]=MRML-näkymä
+Name[fr]=Affichage MRML
+Name[ga]=Amharc MRML
+Name[gl]=Visor MRML
+Name[he]=תצוגת MRML
+Name[hi]=MRML दृश्य
+Name[hu]=MRML-nézet
+Name[is]=MRML sýn
+Name[it]=Visione MRML
+Name[ja]=MRML ビュー
+Name[kk]=MRML файлдарды қарау
+Name[km]=ទិដ្ឋភាព MRML
+Name[lt]=MRML peržiūra
+Name[ms]=Paparan MRML
+Name[nds]=MRML-Ansicht
+Name[ne]=MRML दृश्य
+Name[nl]=MRML-weergave
+Name[nso]=Pono ya MRML
+Name[pa]=MRML ਝਲਕ
+Name[pl]=Widok MRML
+Name[pt]=Janela de MRML
+Name[pt_BR]=Visualização de MRML
+Name[ro]=Vizualizare MRML
+Name[ru]=Просмотр MRML
+Name[se]=MRML-čájeheapmi
+Name[sk]=Prehliadač MRML
+Name[sl]=Pregledovalnik MRML
+Name[sr]=MRML приказивач
+Name[sr@Latn]=MRML prikazivač
+Name[ta]=MRML காட்சி
+Name[tg]=Намоиши MRML
+Name[th]=ดู MRML
+Name[tr]=MRML Görünümü
+Name[uk]=Перегляд MRML
+Name[ven]=Mbonalelo ya MRML
+Name[xh]=MRML Imbono
+Name[zh_CN]=MRML 查看器
+Name[zh_HK]=MRML 檢視
+Name[zh_TW]=MRML 檢視器
+Name[zu]=Umbukiso we-MRML
+MimeType=text/mrml
+ServiceTypes=KParts/ReadOnlyPart
+X-KDE-Library=libkmrmlpart
+#X-KDE-BrowserView-AllowAsDefault=true
+#X-KDE-BrowserView-HideFromMenus=true
+#X-KDE-BrowserView-Args=IconView
+#X-KDE-BrowserView-ModeProperty=viewMode
+#X-KDE-BrowserView-ModePropertyValue=IconView
+Icon=view_icon
+InitialPreference=10
diff --git a/kmrml/kmrml/mrml_part.h b/kmrml/kmrml/mrml_part.h
new file mode 100644
index 00000000..110d290a
--- /dev/null
+++ b/kmrml/kmrml/mrml_part.h
@@ -0,0 +1,175 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001,2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef MRMLPART_H
+#define MRMLPART_H
+
+#include <qcstring.h>
+#include <qstringlist.h>
+
+#include <kurl.h>
+#include <kparts/factory.h>
+#include <kparts/part.h>
+
+#include <kmrml_config.h>
+
+#include "mrml_elements.h"
+
+class QCheckBox;
+class QHGroupBox;
+class QPushButton;
+
+class KAboutData;
+class KComboBox;
+class KIntNumInput;
+
+namespace KIO {
+ class FileCopyJob;
+ class TransferJob;
+}
+
+namespace KMrml
+{
+
+class AlgorithmDialog;
+class Browser;
+class CollectionCombo;
+class MrmlView;
+
+class MrmlPart : public KParts::ReadOnlyPart
+{
+ Q_OBJECT
+
+public:
+ enum Status { NeedCollection, CanSearch, InProgress };
+
+ MrmlPart( QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name, const QStringList& args );
+ ~MrmlPart();
+
+ QString sessionId() const { return m_sessionId; }
+ QString transactionId() const { return QString::null; } // ###
+
+ void saveState( QDataStream& stream );
+ void restoreState( QDataStream& stream );
+
+ static KAboutData *createAboutData();
+
+public slots:
+ virtual bool openURL( const KURL& );
+ virtual bool closeURL();
+
+ void slotActivated( const KURL& url, ButtonState );
+
+protected:
+ virtual bool openFile();
+ Algorithm firstAlgorithmForCollection( const Collection& coll ) const;
+ Collection currentCollection() const;
+
+signals:
+ /**
+ * allow plugins to extend the query
+ */
+ void aboutToStartQuery( QDomDocument& );
+
+private slots:
+ void slotStartClicked();
+ void slotSetStatusBar( const QString& );
+ void slotSetStatusBar( const KURL& url ) { slotSetStatusBar( url.prettyURL() ); }
+ void slotHostComboActivated( const QString& );
+
+ void slotResult( KIO::Job * );
+ void slotData( KIO::Job *, const QByteArray& );
+
+ void slotDownloadResult( KIO::Job * );
+
+ void slotConfigureAlgorithm();
+ void slotApplyAlgoConfig();
+ void slotAlgoConfigFinished();
+
+private:
+ void createQuery( const KURL::List * relevantItems = 0L );
+ void initCollections( const QDomElement& );
+ void initAlgorithms( const QDomElement& );
+ void performQuery( QDomDocument& doc );
+ void parseMrml( QDomDocument& doc );
+ void parseQueryResult( QDomElement& );
+ void enableExtensionActions( const KURL& url, bool enable );
+ KIO::TransferJob * transferJob( const KURL& url );
+
+ void initHostCombo();
+ void enableServerDependentWidgets( bool enable );
+
+ void setStatus( Status status );
+
+ void contactServer( const KURL& url );
+ void downloadReferenceFiles( const KURL::List& downloadList );
+
+ KIO::TransferJob *m_job;
+ MrmlView *m_view;
+ Config m_config;
+ KIntNumInput * m_resultSizeInput;
+ CollectionCombo * m_collectionCombo;
+ QPushButton *m_algoButton;
+ QHGroupBox *m_panel;
+ QPushButton *m_startButton;
+ QCheckBox *m_random;
+ Browser *m_browser;
+ AlgorithmDialog *m_algoConfig;
+ KComboBox *m_hostCombo;
+
+ QPtrList<KIO::FileCopyJob> m_downloadJobs;
+ QStringList m_tempFiles;
+
+ QString m_sessionId;
+ KURL::List m_queryList; // a list of valid LOCAL (!) urls to query for
+
+ CollectionList m_collections;
+ AlgorithmList m_algorithms;
+
+ Status m_status;
+ static uint s_sessionId;
+
+};
+
+class PartFactory : public KParts::Factory
+{
+ Q_OBJECT
+
+public:
+ PartFactory();
+ ~PartFactory();
+
+ static KInstance * instance();
+
+protected:
+ virtual KParts::Part * createPartObject( QWidget *parentWidget = 0,
+ const char *widgetName = 0,
+ QObject *parent = 0,
+ const char *name = 0,
+ const char *classname = "KParts::Part",
+ const QStringList& args = QStringList() );
+
+private:
+ static KInstance * s_instance;
+
+};
+
+}
+
+#endif // MRMLPART_H
diff --git a/kmrml/kmrml/mrml_view.cpp b/kmrml/kmrml/mrml_view.cpp
new file mode 100644
index 00000000..71f3c741
--- /dev/null
+++ b/kmrml/kmrml/mrml_view.cpp
@@ -0,0 +1,480 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001,2002 Carsten Pfeiffer <pfeiffer@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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qdom.h>
+#include <qlabel.h>
+#include <qpainter.h>
+#include <qtimer.h>
+#include <qtooltip.h>
+
+#include <kcursor.h>
+#include <kdatastream.h>
+#include <klocale.h>
+#include <kcombobox.h>
+#include <kmimetype.h>
+#include <kurl.h>
+#include <kurldrag.h>
+
+#include "loader.h"
+#include "mrml_creator.h"
+#include "mrml_view.h"
+
+using namespace KMrml;
+
+MrmlView::MrmlView( QWidget *parent, const char *name )
+ : QScrollView( parent, name )
+{
+ setStaticBackground( true );
+ setResizePolicy( Manual );
+ setHScrollBarMode( AlwaysOff );
+ enableClipper( true ); // ### test this
+
+ m_items.setAutoDelete( true );
+
+ connect( Loader::self(), SIGNAL( finished(const KURL&, const QByteArray&)),
+ SLOT( slotDownloadFinished( const KURL&, const QByteArray& )));
+
+ m_timer = new QTimer( this );
+ connect( m_timer, SIGNAL( timeout() ), SLOT( slotLayout() ));
+
+ // we need a pixmap to be shown when no thumbnail is available for a
+ // query result image
+ QLabel l( i18n( "No thumbnail available" ), 0L );
+ l.setFixedSize( 80, 80 );
+ l.setAlignment( WordBreak | AlignCenter );
+// l.setFrameStyle( QLabel::Box | QLabel::Plain );
+// l.setLineWidth( 1 );
+ l.setPaletteBackgroundColor( Qt::white );
+ l.setPaletteForegroundColor( Qt::black );
+ m_unavailablePixmap = QPixmap::grabWidget( &l );
+}
+
+MrmlView::~MrmlView()
+{
+}
+
+MrmlViewItem * MrmlView::addItem( const KURL& url, const KURL& thumbURL,
+ const QString& similarity )
+{
+ bool ok;
+ double value = similarity.toDouble( &ok );
+ if ( !ok || value < 0.05 )
+ return 0L;
+
+ return addItem( url, thumbURL, value );
+}
+
+MrmlViewItem * MrmlView::addItem( const KURL& url, const KURL& thumbURL,
+ double similarity )
+{
+ if ( !url.isValid() ) {
+ qWarning( "MrmlPart: received malformed URL from query: %s",
+ url.prettyURL().isNull() ? "(null)" : url.prettyURL().latin1() );
+ return 0L;
+ }
+
+// qDebug("** url: %s", thumbURL.url().latin1());
+
+ MrmlViewItem *item = new MrmlViewItem( url, thumbURL, similarity, this );
+ QPixmap *pixmap = getPixmap( thumbURL );
+ if ( pixmap )
+ item->setPixmap( *pixmap );
+
+ m_items.append( item );
+
+ m_timer->start( 0, true );
+ return item;
+}
+
+void MrmlView::addRelevanceToQuery( QDomDocument& document,
+ QDomElement& parent )
+{
+ QPtrListIterator<MrmlViewItem> it( m_items );
+ for( ; it.current(); ++it ) {
+ it.current()->createRelevanceElement( document, parent );
+ }
+}
+
+void MrmlView::clear()
+{
+ m_items.clear(); // items are deleted and removed from scrollview
+ setContentsPos( 0, 0 );
+}
+
+QPixmap * MrmlView::getPixmap( const KURL& url )
+{
+ QString u = url.url();
+ QPixmap *pix = m_pixmapCache.find( u );
+ if ( pix )
+ return pix;
+
+ if ( url.isLocalFile() ) {
+ QPixmap p;
+ if ( !p.load( url.path() ) )
+ p = m_unavailablePixmap;
+
+ m_pixmapCache.insert( u, p );
+ return m_pixmapCache.find( u );
+ }
+ else { // remote url, download with KIO
+ Loader::self()->requestDownload( url );
+ }
+
+ return 0L;
+}
+
+void MrmlView::slotDownloadFinished( const KURL& url, const QByteArray& data )
+{
+ QPtrListIterator<MrmlViewItem> it( m_items );
+ for( ; it.current(); ++it ) {
+ MrmlViewItem *item = it.current();
+ if ( item->thumbURL() == url )
+ {
+ QPixmap p;
+ if ( data.isEmpty() || !p.loadFromData( data ) )
+ p = m_unavailablePixmap;
+
+ m_pixmapCache.insert( url.url(), p );
+ item->setPixmap( p );
+
+ slotLayout();
+ return;
+ }
+ }
+}
+
+void MrmlView::stopDownloads()
+{
+ Loader *loader = Loader::self();
+ QPtrListIterator<MrmlViewItem> it( m_items );
+ for( ; it.current(); ++it ) {
+ MrmlViewItem *item = it.current();
+ if ( !item->hasRemotePixmap() )
+ loader->removeDownload( item->url() );
+ }
+}
+
+void MrmlView::slotLayout()
+{
+ int itemWidth = 0;
+ QPtrListIterator<MrmlViewItem> it( m_items );
+
+ for ( ; it.current(); ++it ) {
+ itemWidth = QMAX( itemWidth, it.current()->sizeHint().width() );
+ }
+
+ if ( itemWidth == 0 )
+ return;
+
+
+ uint itemsPerRow = visibleWidth() / itemWidth;
+ int margin = (visibleWidth() - (itemsPerRow * itemWidth)) / 2;
+ int rowHeight = 0;
+ uint item = 0;
+ uint y = 5;
+
+ // pointing to the first item of a row
+ QPtrListIterator<MrmlViewItem> rowIt( m_items );
+
+ for ( it.toFirst(); it.current(); ++it ) {
+ if ( item >= itemsPerRow ) {
+ item = 0;
+ y += rowHeight;
+ rowHeight = 0;
+ }
+
+ if ( item == 0 )
+ rowIt = it;
+
+ rowHeight = QMAX( rowHeight, it.current()->sizeHint().height() );
+ addChild( it.current(), margin + item * itemWidth, y );
+ it.current()->show();
+
+ item++;
+
+ // resize all items of the current row so they all have the same size
+ if ( item >= itemsPerRow || it.atLast() )
+ {
+ for ( uint i = 0; (i < itemsPerRow && rowIt.current()); i++ )
+ {
+ rowIt.current()->resize( itemWidth, rowHeight );
+ ++rowIt;
+ }
+ }
+ }
+
+ resizeContents( visibleWidth(), y + rowHeight );
+}
+
+void MrmlView::resizeEvent( QResizeEvent *e )
+{
+ int oldW = visibleWidth();
+ QScrollView::resizeEvent( e );
+
+ if ( visibleWidth() != oldW )
+ slotLayout();
+}
+
+void MrmlView::saveState( QDataStream& stream )
+{
+ stream << m_items.count();
+ QPtrListIterator<MrmlViewItem> it( m_items );
+ for( ; it.current(); ++it ) {
+ stream << *it.current();
+ }
+
+}
+
+void MrmlView::restoreState( QDataStream& stream )
+{
+ stopDownloads();
+ clear();
+
+ int count;
+ stream >> count;
+
+ KURL url, thumbURL;
+ double similarity;
+ Q_UINT32 relevance;
+ MrmlViewItem *item;
+
+
+ for ( int i = 0; i < count; i++ )
+ {
+ stream >> url;
+ stream >> thumbURL;
+ stream >> similarity;
+ stream >> relevance;
+
+ item = addItem( url, thumbURL, similarity );
+ if ( item )
+ item->setRelevance( (MrmlViewItem::Relevance) relevance );
+ }
+}
+
+QDataStream& KMrml::operator<<( QDataStream& stream,
+ const KMrml::MrmlViewItem& item )
+{
+ return stream << item.url()
+ << item.thumbURL()
+ << item.similarity()
+ << static_cast<Q_UINT32>( item.relevance() );
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+MrmlViewItem::MrmlViewItem( const KURL& url, const KURL& thumbURL,
+ double similarity, MrmlView *view,
+ const char *name )
+ : QFrame( view->viewport() , name ),
+ m_view( view ),
+ m_url( url ),
+ m_thumbURL( thumbURL ),
+ similarityFullWidth( 120 ), // ###
+ m_hasRemotePixmap( false )
+{
+ if ( m_similarity != -1 )
+ m_similarity = QMAX( 0.0, QMIN( 1.0, similarity ));
+ setFrameStyle( Panel | Sunken );
+ setMouseTracking( true );
+
+ m_combo = new KComboBox( this );
+ QToolTip::add( m_combo, i18n("You can refine queries by giving feedback about the current result and pressing the Search button again.") );
+ m_combo->insertItem( i18n("Relevant"), Relevant );
+ m_combo->insertItem( i18n("Neutral"), Neutral );
+ m_combo->insertItem( i18n("Irrelevant"), Irrelevant );
+ m_combo->adjustSize();
+ m_combo->setCurrentItem( Neutral );
+
+ /*
+ if ( similarity > -1 )
+ QToolTip::add( this, QString::fromLatin1("<qt>%1<br>%1</qt>")
+ .arg( url )
+ .arg(i18n("Similarity: %1").arg( QString::number(similarity))));
+ else
+ QToolTip::add( this, QString::fromLatin1("<qt>%1</qt>").arg( url ) );
+ */
+
+ setMinimumSize( 130, 130 ); // ###
+}
+
+MrmlViewItem::~MrmlViewItem()
+{
+}
+
+void MrmlViewItem::setPixmap( const QPixmap& pix )
+{
+ if ( !m_url.isLocalFile() )
+ m_hasRemotePixmap = true;
+
+ m_pixmap = pix;
+ adjustSize();
+ update();
+}
+
+void MrmlViewItem::paintEvent( QPaintEvent *e )
+{
+ QFrame::paintEvent( e );
+
+ if ( !m_pixmap.isNull() ) {
+ bitBlt( this, pixmapX(), pixmapY(),
+ &m_pixmap, 0, 0, m_pixmap.width(), m_pixmap.height(),
+ CopyROP );
+ }
+
+ if ( m_similarity >= 0 ) {
+ QPainter p( this );
+ QPen pen( colorGroup().highlight(), 1, QPen::SolidLine );
+ p.setPen( pen );
+ int x = margin;
+ int y = m_combo->y() - similarityHeight - 2;
+ int w = (int) (similarityFullWidth * m_similarity);
+ int h = similarityHeight;
+ p.drawRect( x, y, similarityFullWidth, h );
+ p.fillRect( x, y, w, h, colorGroup().highlight() );
+ }
+}
+
+void MrmlViewItem::resizeEvent( QResizeEvent *e )
+{
+ QFrame::resizeEvent( e );
+
+ int y = height() - m_combo->height() - margin;
+ m_combo->move( width()/2 - m_combo->width()/2, y );
+}
+
+QSize MrmlViewItem::sizeHint() const
+{
+ int w = QMAX( QMAX(minimumHeight(), m_combo->width()), m_pixmap.width() );
+ w += 2 * margin;
+
+ int h = m_pixmap.isNull() ? margin : margin + spacing + m_pixmap.height();
+ h += (m_similarity > -1) ? similarityHeight + spacing : 0;
+ h += m_combo->height() + margin;
+
+ return QSize( w, h );
+}
+
+void MrmlViewItem::mousePressEvent( QMouseEvent *e )
+{
+ QFrame::mousePressEvent( e );
+ pressedPos.setX( 0 );
+ pressedPos.setY( 0 );
+
+
+ if ( e->button() == LeftButton || e->button() == MidButton ) {
+ if ( hitsPixmap( e->pos() ) )
+ pressedPos = e->pos();
+ }
+ else if ( e->button() == RightButton && hitsPixmap( e->pos() ) )
+ emit view()->activated( m_url, e->button() );
+}
+
+void MrmlViewItem::mouseMoveEvent( QMouseEvent *e )
+{
+ if ( hitsPixmap( e->pos() ) ) {
+ if ( !ownCursor() ) { // nice hacklet :)
+ setCursor( KCursor::handCursor() );
+ emit view()->onItem( m_url );
+ }
+ }
+ else {
+ if ( ownCursor() ) {
+ unsetCursor();
+ emit view()->onItem( KURL() );
+ }
+ }
+
+ if ( (e->state() & LeftButton) && !pressedPos.isNull() ) {
+ QPoint dist = e->pos() - pressedPos;
+ if ( dist.manhattanLength() > KGlobalSettings::dndEventDelay() ) {
+ // start drag here
+ KURL::List urls;
+ // ### support multiple files?
+ urls.append( m_url );
+ KURLDrag *drag = new KURLDrag( urls, this );
+ drag->setPixmap( KMimeType::pixmapForURL( m_url ) );
+ drag->drag();
+ }
+ }
+}
+
+void MrmlViewItem::mouseReleaseEvent( QMouseEvent *e )
+{
+ if ( hitsPixmap( e->pos() )) {
+ QPoint dist = e->pos() - pressedPos;
+ if ( dist.manhattanLength() < KGlobalSettings::dndEventDelay() ) {
+ emit view()->activated( m_url, e->button() );
+ }
+ }
+}
+
+bool MrmlViewItem::hitsPixmap( const QPoint& pos ) const
+{
+ if ( m_pixmap.isNull() )
+ return false;
+
+ if ( pos.x() > pixmapX() && pos.x() < pixmapX() + m_pixmap.width() &&
+ pos.y() > pixmapY() && pos.y() < pixmapY() + m_pixmap.height() )
+ return true;
+ return false;
+}
+
+void MrmlViewItem::createRelevanceElement( QDomDocument& document,
+ QDomElement& parent )
+{
+ int rel = m_combo->currentItem();
+ if ( rel == Neutral )
+ return;
+
+ MrmlCreator::createRelevanceElement( document, parent, m_url.url(),
+ (rel == Relevant) ? MrmlCreator::Relevant : MrmlCreator::Irrelevant );
+}
+
+MrmlViewItem::Relevance MrmlViewItem::relevance() const
+{
+ return (Relevance) m_combo->currentItem();
+}
+
+void MrmlViewItem::setRelevance( Relevance relevance )
+{
+ m_combo->setCurrentItem( relevance );
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+int MrmlViewItemList::compareItems( QPtrCollection::Item item1,
+ QPtrCollection::Item item2 )
+{
+ double s1 = (static_cast<MrmlViewItem*>( item1 ))->similarity();
+ double s2 = (static_cast<MrmlViewItem*>( item2 ))->similarity();
+
+ if ( s1 < s2 )
+ return 1;
+ else if ( s1 > s2 )
+ return -1;
+ else
+ return 0;
+}
+
+#include "mrml_view.moc"
diff --git a/kmrml/kmrml/mrml_view.h b/kmrml/kmrml/mrml_view.h
new file mode 100644
index 00000000..f6c9f58c
--- /dev/null
+++ b/kmrml/kmrml/mrml_view.h
@@ -0,0 +1,180 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef MRML_VIEW_H
+#define MRML_VIEW_H
+
+#include <qevent.h>
+#include <qframe.h>
+#include <qptrlist.h>
+#include <qpixmap.h>
+#include <qpixmapcache.h>
+#include <qscrollview.h>
+
+class QDomDocument;
+class QDomElement;
+class QTimer;
+
+class KComboBox;
+
+namespace KMrml
+{
+
+class MrmlViewItem;
+
+
+class MrmlViewItemList : public QPtrList<MrmlViewItem>
+{
+protected:
+ // sort by similarity
+ virtual int compareItems( QPtrCollection::Item, QPtrCollection::Item );
+
+};
+
+
+class MrmlView : public QScrollView
+{
+ friend class MrmlViewItem;
+
+ Q_OBJECT
+
+public:
+ MrmlView( QWidget *parent = 0L, const char *name = 0L );
+ ~MrmlView();
+
+ MrmlViewItem * addItem( const KURL& url, const KURL& thumbURL,
+ const QString& similarity );
+ MrmlViewItem * addItem( const KURL& url, const KURL& thumbURL,
+ double similarity );
+
+
+ void addRelevanceToQuery( QDomDocument&, QDomElement& parent );
+
+ void clear();
+
+ bool isEmpty() const { return m_items.isEmpty(); }
+
+ void stopDownloads();
+
+ void saveState( QDataStream& stream );
+ void restoreState( QDataStream& stream );
+
+signals:
+ void activated( const KURL& url, ButtonState button );
+ void onItem( const KURL& url );
+
+protected:
+ virtual void resizeEvent( QResizeEvent * );
+
+private slots:
+ void slotLayout();
+ void slotDownloadFinished( const KURL&, const QByteArray& );
+
+private:
+ /**
+ * @returns a _temporary_ pointer to a pixmap. Copy it!
+ */
+ QPixmap * getPixmap( const KURL& url );
+
+ MrmlViewItemList m_items;
+ QTimer *m_timer;
+ QPixmapCache m_pixmapCache;
+ QPixmap m_unavailablePixmap;
+
+
+};
+
+
+class MrmlViewItem : public QFrame
+{
+ Q_OBJECT
+
+public:
+ enum Relevance
+ {
+ Relevant = 0,
+ Neutral = 1,
+ Irrelevant = 2
+ };
+
+ MrmlViewItem( const KURL& url, const KURL& thumbURL, double similarity,
+ MrmlView *view, const char *name=0L );
+ virtual ~MrmlViewItem();
+
+ void setPixmap( const QPixmap& pixmap );
+
+ void createRelevanceElement( QDomDocument& document, QDomElement& parent );
+
+ double similarity() const { return m_similarity; }
+
+ void setSimilarity( double value );
+
+ virtual QSize sizeHint() const;
+
+ const KURL& url() const { return m_url; }
+ const KURL& thumbURL() const { return m_thumbURL; }
+
+ bool hasRemotePixmap() const { return !m_thumbURL.isLocalFile() && m_hasRemotePixmap; }
+
+ Relevance relevance() const;
+ void setRelevance( Relevance relevance );
+
+protected:
+ virtual void paintEvent( QPaintEvent * );
+ virtual void resizeEvent( QResizeEvent * );
+
+ virtual void mousePressEvent( QMouseEvent * );
+ virtual void mouseMoveEvent( QMouseEvent * );
+ virtual void mouseReleaseEvent( QMouseEvent * );
+
+private:
+ bool hitsPixmap( const QPoint& ) const;
+ MrmlView * view() const { return m_view; }
+
+ inline int pixmapX() const {
+ return QMAX( margin, (width() - m_pixmap.width()) / 2);
+ }
+ inline int pixmapY() const {
+ return m_combo->y() - similarityHeight - m_pixmap.height() - margin;
+ }
+
+ KComboBox *m_combo; // for relevance
+ MrmlView *m_view;
+
+ KURL m_url;
+ KURL m_thumbURL;
+
+ QPixmap m_pixmap;
+
+ double m_similarity;
+ const int similarityFullWidth;
+ bool m_hasRemotePixmap;
+
+ QPoint pressedPos;
+
+ static const int spacing = 3;
+ static const int margin = 5;
+ static const int similarityHeight = 4;
+
+};
+
+QDataStream& operator <<( QDataStream& stream, const KMrml::MrmlViewItem& );
+
+}
+
+#endif // MRML_VIEW_H
diff --git a/kmrml/kmrml/mrmlsearch.cpp b/kmrml/kmrml/mrmlsearch.cpp
new file mode 100644
index 00000000..6f411313
--- /dev/null
+++ b/kmrml/kmrml/mrmlsearch.cpp
@@ -0,0 +1,74 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// This little baby is called from Konqueror's popupmenu, when you hit
+// "Search for similar images...". This program simply gets the URLs
+// from Konqueror and creates a query of the form
+// mrml://host.com/?relevant=url1;url2;url3;url4....
+// By default, the mrml URL is mrml://localhost", but you can override that
+// by editing ~/.kde/share/config/kio_mrmlrc and adding
+// [MRML Settings]
+// Default URL=mrml://url.to.your.giftserver.com
+//
+// mrmlsearch will then invoke "kfmclient openURL query" to start open
+// a new Konqueror window and perform the query.
+
+#include <unistd.h>
+
+#include <qfile.h>
+#include <qstring.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <kinstance.h>
+#include <kurl.h>
+
+#include <kmrml_config.h>
+
+extern "C" KDE_EXPORT int kdemain( int argc, char **argv )
+{
+ QString query;
+
+ for ( int i = 1; i < argc; i++ ) {
+ if ( i > 1 )
+ query += ';';
+ QString path = QFile::decodeName( argv[i] );
+ if ( path.at( 0 ) == '/' ) {
+ KURL u;
+ u.setPath( path );
+ path = u.url();
+ }
+ query.append( path );
+ }
+
+ KInstance instance( "kio_mrml" );
+
+ KMrml::Config config( instance.config() );
+ KMrml::ServerSettings settings = config.defaultSettings();
+ KURL url;
+ url.setProtocol( "mrml" );
+ url.setHost( settings.host );
+
+ query = KURL::encode_string_no_slash( query );
+ query.prepend( "?relevant=" ); // this is not encoded!
+ url.setQuery( query );
+ qDebug("***** Query: %s ** URL: %s", query.latin1(), url.url().latin1());
+
+ return execlp( "kfmclient",
+ "kfmclient", "openURL", QFile::encodeName(url.url()).data(),
+ "text/mrml", (void *)0 );
+}
diff --git a/kmrml/kmrml/propertysheet.cpp b/kmrml/kmrml/propertysheet.cpp
new file mode 100644
index 00000000..ec46aac0
--- /dev/null
+++ b/kmrml/kmrml/propertysheet.cpp
@@ -0,0 +1,206 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "propertysheet.h"
+
+#include "mrml_elements.h"
+#include "mrml_shared.h"
+
+#include <knuminput.h>
+#include <qwidget.h>
+
+using namespace KMrml;
+
+template class QValueList<QDomElement>;
+
+PropertySheet::PropertySheet()
+{
+ init();
+}
+
+PropertySheet::PropertySheet( const QDomElement& elem )
+{
+ init();
+
+ initFromDOM( elem );
+}
+
+PropertySheet::PropertySheet( const PropertySheet& ps )
+{
+ *this = ps;
+}
+
+PropertySheet& PropertySheet::operator= ( const PropertySheet& ps )
+{
+ if ( &ps == this )
+ return *this;
+
+ m_visibility = ps.m_visibility;
+ m_type = ps.m_type;
+ m_caption = ps.m_caption;
+ m_id = ps.m_id;
+
+ m_sendType = ps.m_sendType;
+ m_sendName = ps.m_sendName;
+ m_sendValue = ps.m_sendValue;
+
+ m_minRange = ps.m_minRange;
+ m_maxRange = ps.m_maxRange;
+ m_stepSize = ps.m_stepSize;
+
+ m_minSubsetSize = ps.m_minSubsetSize;
+ m_maxSubsetSize = ps.m_maxSubsetSize;
+
+ // deep copy of m_subSheets
+ QPtrListIterator<PropertySheet> it( ps.m_subSheets );
+ for ( ; it.current(); ++it )
+ m_subSheets.append( new PropertySheet( *it.current() ) );
+
+ return *this;
+}
+
+void PropertySheet::init()
+{
+ m_subSheets.setAutoDelete( true );
+ m_visibility = Visible;
+}
+
+void PropertySheet::initFromDOM( const QDomElement& elem )
+{
+ m_subSheets.clear();
+
+ m_visibility = getVisibility( elem.attribute( MrmlShared::visibility() ));
+ m_type = getType( elem.attribute( MrmlShared::propertySheetType() ) );
+ m_caption = elem.attribute( MrmlShared::caption() );
+ m_id = elem.attribute( MrmlShared::propertySheetId() );
+ m_sendType = getSendType( elem.attribute( MrmlShared::sendType() ));
+ m_sendName = elem.attribute( MrmlShared::sendName() );
+ m_sendValue = elem.attribute( MrmlShared::sendValue() );
+ m_minRange = toInt( elem.attribute( MrmlShared::from() ));
+ m_maxRange = toInt( elem.attribute( MrmlShared::to() ));
+ m_stepSize = toInt( elem.attribute( MrmlShared::step() ));
+
+ m_minSubsetSize = toInt( elem.attribute( MrmlShared::minSubsetSize() ));
+ m_maxSubsetSize = toInt( elem.attribute( MrmlShared::maxSubsetSize() ));
+
+ QValueList<QDomElement> children =
+ KMrml::directChildElements( elem, MrmlShared::propertySheet() );
+ QValueListConstIterator<QDomElement> it = children.begin();
+ for ( ; it != children.end(); ++it )
+ m_subSheets.append( new PropertySheet( *it ) );
+}
+
+QWidget * PropertySheet::createWidget( QWidget */*parent*/, const char */*name*/ )
+{
+ QWidget *w = 0L;
+
+ switch ( m_type )
+ {
+ case Numeric:
+ {
+// KIntNumInput *input = new KIntNumInput();
+ break;
+ }
+
+ case Subset:
+ {
+ if ( m_minSubsetSize == 1 && m_maxSubsetSize == 1 )
+ {
+
+ }
+
+ break;
+ }
+
+ default:
+ qDebug("** can't create widget for type: %i", m_type);
+ }
+
+ return w;
+}
+
+
+//
+// static methods
+//
+PropertySheet::Visibility PropertySheet::getVisibility( const QString& value )
+{
+ Visibility vis;
+
+ if ( value == MrmlShared::invisible() )
+ vis = Invisible;
+ else if ( value == MrmlShared::popup() )
+ vis = Popup;
+ else
+ vis = Visible; // default value
+
+ return vis;
+}
+
+PropertySheet::Type PropertySheet::getType( const QString& value )
+{
+ Type type = (Type) 0;
+
+ if ( value == MrmlShared::multiSet() )
+ type = MultiSet;
+ else if ( value == MrmlShared::subset() )
+ type = Subset;
+ else if ( value == MrmlShared::setElement() )
+ type = SetElement;
+ else if ( value == MrmlShared::boolean() )
+ type = Boolean;
+ else if ( value == MrmlShared::numeric() )
+ type = Numeric;
+ else if ( value == MrmlShared::textual() )
+ type = Textual;
+ else if ( value == MrmlShared::panel() )
+ type = Panel;
+ else if ( value == MrmlShared::clone() )
+ type = Clone;
+ else if ( value == MrmlShared::reference() )
+ type = Reference;
+
+ return type;
+}
+
+PropertySheet::SendType PropertySheet::getSendType( const QString& value )
+{
+ SendType type = (SendType) 0;
+
+ if ( value == MrmlShared::element() )
+ type = Element;
+ else if ( value == MrmlShared::attribute() )
+ type = Attribute;
+ else if ( value == MrmlShared::attributeName() )
+ type = AttributeName;
+ else if ( value == MrmlShared::attributeValue() )
+ type = AttributeValue;
+ else if ( value == MrmlShared::children() )
+ type = Children;
+ else if ( value == MrmlShared::none() )
+ type = None;
+
+ return type;
+}
+
+int PropertySheet::toInt( const QString& value, int defaultValue )
+{
+ bool ok = false;
+ int res = value.toInt( &ok );
+ return ok ? res : defaultValue;
+}
diff --git a/kmrml/kmrml/propertysheet.h b/kmrml/kmrml/propertysheet.h
new file mode 100644
index 00000000..029d0242
--- /dev/null
+++ b/kmrml/kmrml/propertysheet.h
@@ -0,0 +1,113 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef PROPERTYSHEET_H
+#define PROPERTYSHEET_H
+
+#include <qdom.h>
+#include <qstring.h>
+#include <qptrlist.h>
+
+class QWidget;
+
+namespace KMrml
+{
+ class PropertySheet
+ {
+ public:
+ enum Type
+ {
+ MultiSet = 1, // ??
+ Subset, // radio-button/combobox or listbox
+ SetElement, // CheckBox -> disables/enables children?
+ Boolean, // CheckBox
+ Numeric, // Slider/Spinbox
+ Textual, // lineedit
+ Panel, // groupbox?
+ Clone,
+ Reference
+ };
+ enum Visibility
+ {
+ Visible,
+ Invisible,
+ Popup
+ };
+ enum SendType
+ {
+ Element = 1,
+ Attribute,
+ AttributeName,
+ AttributeValue,
+ Children,
+ None
+ };
+
+ PropertySheet();
+ PropertySheet( const QDomElement& elem );
+ PropertySheet( const PropertySheet& ps );
+ ~PropertySheet() {};
+
+ PropertySheet& operator=( const PropertySheet& ps );
+
+ bool isValid() const {
+ // required mrml attributes
+ return !m_id.isNull() && m_type != 0 && m_sendType != 0;
+ }
+ void initFromDOM( const QDomElement& elem );
+
+ void toElement( QDomElement& parent );
+
+ QWidget * createWidget( QWidget *parent, const char *name = 0 );
+
+ private:
+ static Visibility getVisibility( const QString& value );
+ static Type getType( const QString& value );
+ static SendType getSendType( const QString& value );
+ static int toInt( const QString& value, int defaultValue = 0 );
+
+ void init();
+
+
+ // update operator=() when adding data members!
+
+ QPtrList<PropertySheet> m_subSheets;
+ Visibility m_visibility;
+ Type m_type;
+ QString m_caption;
+ QString m_id;
+
+ SendType m_sendType;
+ QString m_sendName;
+ QString m_sendValue;
+
+ int m_minRange;
+ int m_maxRange;
+ int m_stepSize;
+
+ // Type = Subset && m_minSubsetSize == m_maxSubsetSize == 1 -> Combobox
+ // or radio buttons.
+ // > max > 1 -> Listbox with multiselection
+ int m_minSubsetSize;
+ int m_maxSubsetSize;
+
+ };
+
+}
+
+#endif // PROPERTYSHEET_H
diff --git a/kmrml/kmrml/propertywidgets.cpp b/kmrml/kmrml/propertywidgets.cpp
new file mode 100644
index 00000000..ef00b18f
--- /dev/null
+++ b/kmrml/kmrml/propertywidgets.cpp
@@ -0,0 +1,121 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "propertywidgets.h"
+
+IntegerWidget::IntegerWidget( const PropertySheet& sheet,
+ QWidget *parent, const char *name )
+ : QHBox( parent, name )
+{
+
+}
+
+IntegerWidget::~IntegerWidget()
+{
+
+}
+
+int IntegerWidget::value() const
+{
+
+}
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+ComboWidget::ComboWidget( const PropertySheet& sheet,
+ QWidget *parent, const char *name )
+ : QHBox( parent, name )
+{
+
+}
+
+ComboWidget::~ComboWidget()
+{
+
+}
+
+QString ComboWidget::value() const
+{
+
+}
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+CheckBoxWidget::CheckBoxWidget( const PropertySheet& sheet,
+ QWidget *parent, const char *name )
+ : QHBox( parent, name )
+{
+
+}
+
+CheckBoxWidget::~CheckBoxWidget()
+{
+
+}
+
+bool CheckBoxWidget::value() const
+{
+
+}
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+LineEditWidget::LineEditWidget( const PropertySheet& sheet,
+ QWidget *parent, const char *name )
+ : QHBox( parent, name )
+{
+
+}
+
+LineEditWidget::~LineEditWidget()
+{
+
+}
+
+QString LineEditWidget::value() const
+{
+
+}
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+ListBoxWidget::ListBoxWidget( const PropertySheet& sheet,
+ QWidget *parent, const char *name )
+ : QHBox( parent, name )
+{
+
+}
+
+ListBoxWidget::~ListBoxWidget()
+{
+
+}
+
+QStringList ListBoxWidget::value() const
+{
+
+}
+
+#include "propertywidgets.moc"
diff --git a/kmrml/kmrml/propertywidgets.h b/kmrml/kmrml/propertywidgets.h
new file mode 100644
index 00000000..c738d03d
--- /dev/null
+++ b/kmrml/kmrml/propertywidgets.h
@@ -0,0 +1,108 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef PROPERTYWIDGETS_H
+#define PROPERTYWIDGETS_H
+
+#include <qhbox.h>
+
+#include "propertysheet.h"
+
+namespace KMrml
+{
+ class IntegerWidget : public QHBox
+ {
+ Q_OBJECT
+
+ public:
+ IntegerWidget( const PropertySheet& sheet,
+ QWidget *parent = parent, const char *name = 0L );
+ ~IntegerWidget();
+
+ int value() const;
+
+ private:
+
+ };
+
+ class ComboWidget : public QHBox
+ {
+ Q_OBJECT
+
+ public:
+ ComboWidget( const PropertySheet& sheet,
+ QWidget *parent = parent, const char *name = 0L );
+ ~ComboWidget();
+
+ QString value() const;
+
+ private:
+
+ };
+
+ class CheckBoxWidget : public QHBox
+ {
+ Q_OBJECT
+
+ public:
+ CheckBoxWidget( const PropertySheet& sheet,
+ QWidget *parent = parent, const char *name = 0L );
+ ~CheckBoxWidget();
+
+ bool value();
+
+ private:
+
+
+ };
+
+
+ class LineEditWidget : public QHBox
+ {
+ Q_OBJECT
+
+ public:
+ LineEditWidget( const PropertySheet& sheet,
+ QWidget *parent = parent, const char *name = 0L );
+ ~LineEditWidget();
+
+ QString value();
+
+ private:
+
+ };
+
+ class ListBoxWidget : public QHBox
+ {
+ Q_OBJECT
+
+ public:
+ ListBoxWidget( const PropertySheet& sheet,
+ QWidget *parent = parent, const char *name = 0L );
+ ~ListBoxWidget();
+
+ QStringList values();
+
+ private:
+
+ };
+
+};
+
+
+#endif // PROPERTYWIDGETS_H
diff --git a/kmrml/kmrml/server/Makefile.am b/kmrml/kmrml/server/Makefile.am
new file mode 100644
index 00000000..875684b0
--- /dev/null
+++ b/kmrml/kmrml/server/Makefile.am
@@ -0,0 +1,12 @@
+kde_module_LTLIBRARIES = kded_daemonwatcher.la
+
+INCLUDES = $(all_includes)
+kded_daemonwatcher_la_SOURCES = watcher.cpp watcher.skel
+# watcher.stub
+kded_daemonwatcher_la_LDFLAGS = $(all_libraries) -module -avoid-version
+kded_daemonwatcher_la_LIBADD = $(LIB_KSYCOCA) $(LIB_KDEUI)
+
+METASOURCES = AUTO
+
+servicesdir = $(kde_servicesdir)/kded
+services_DATA = daemonwatcher.desktop
diff --git a/kmrml/kmrml/server/daemonwatcher.desktop b/kmrml/kmrml/server/daemonwatcher.desktop
new file mode 100644
index 00000000..c29495b4
--- /dev/null
+++ b/kmrml/kmrml/server/daemonwatcher.desktop
@@ -0,0 +1,103 @@
+[Desktop Entry]
+Type=Service
+Name=KDED KMRML Daemon Watcher
+Name[ar]=مراقب KDED KMRML Daemon
+Name[bs]=KDED KMRML nadzor demona
+Name[ca]=Dimoni vigilant KDED KMRL
+Name[cs]=Sledovač KMRML démonů
+Name[cy]=Gwyliwr Ellyll KMRML KDED
+Name[da]=KDED KMRML-dæmon-overvåger
+Name[de]=Überwachung der KDE-Bildersuche
+Name[el]=Επόπτης δαίμονα KMRML KDED
+Name[es]=Guardián del demonio KDED KMRML
+Name[et]=KDED KMRML deemoni jälgija
+Name[eu]=KDED KMRML deabru behatzailea
+Name[fa]=پایشگر شبح KDED KMRML
+Name[fi]=KDED KMRML-palvelimen tarkkailija
+Name[fr]=Observateur KDE du démon KMRML
+Name[gl]=Vixiante do daemon de KDED KMRML
+Name[he]=צופה תהליכי הרקע של KDED KMRML
+Name[hi]=KDED KMRML डेमन वाचर
+Name[hu]=KDED KMRML szolgáltatásfigyelő
+Name[is]=Eftirlit með KDED KMRML þjóninum
+Name[it]=Controllo del demone KDED KMRML
+Name[ja]=KDED KMRML デーモンウォッチャー
+Name[kk]=KDED KMRML қызметі
+Name[km]=កម្មវិធី​ឃ្លាំមើល​ដេមិន KDED KMRML
+Name[lt]=KDED KMRML tarnybos stebėtojas
+Name[ms]=Pemerhati Daemon KDED KMRML
+Name[nb]=KDED KMRML nisseovervåker
+Name[nds]=KMRML-Luerdämoon för KDED
+Name[ne]=KDED KMRML डेइमन दर्शक
+Name[nl]=KDED KMRML-daemonbeheer
+Name[nn]=KDED KMRML-nisseovervaking
+Name[pl]=Monitor usług KMRML
+Name[pt]=Monitor KMRML de Servidores KDED
+Name[pt_BR]=Sentinela de Serviços KDED
+Name[ro]=Demon KDED pentru MRML
+Name[ru]=Служба MRML
+Name[se]=KDED KMRML-duogášprográmmagoziheaddji
+Name[sk]=Sledovanie démona KDED KMRML
+Name[sl]=Opazovalnik demona KMRML za KDED
+Name[sr]=KDED KMRML демон за праћење
+Name[sr@Latn]=KDED KMRML demon za praćenje
+Name[sv]=KDED KMRML-demonbevakare
+Name[ta]=KDED டிமென் வாட்சர்
+Name[tg]=Мудири демони KDED KMRML
+Name[th]=ตัวเฝ้าดูแดมอน KDED KMRML
+Name[tr]=KDED KMRML Aracı İzleyici
+Name[uk]=Спостерігач демону KDED KMRML
+Name[zh_CN]=KDED KMRML 守护程序监视器
+Name[zh_HK]=KDED KMRML 系統程式監察器
+Name[zh_TW]=KDED KMRML 伺服程式監看器
+Comment=Starts daemons on demand and restarts them on failure
+Comment[bg]=Стартиране на демоните при заявка и рестартиране на демони при грешка
+Comment[bs]=Pokreće demone po potrebi i restartuje ih ako se sruše
+Comment[ca]=Engega els dimonis sota petició i els torna a engegar si fallen
+Comment[cs]=Spouští démony na požádání a restartuje je při selhání
+Comment[da]=Starter dæmoner ved forespørgsel og genstarter dem ved fejl
+Comment[de]=Startet KMRML-Dienste bei Bedarf und im Fehlerfall neu
+Comment[el]=Εκκινεί δαίμονες όταν ζητηθεί και τους επανεκκινεί κατά την αποτυχία
+Comment[es]=Inicia los demonios bajo demanda y los reinicia si fallan
+Comment[et]=Käivitab nõudmisel deemoneid ja taaskäivitab neid ebaõnnestumise korral
+Comment[eu]=Demonioak hasi eta bukau egiten ditu eskatzen zaionean
+Comment[fa]=شبحها را بر اساس نیاز آغاز می‌کند و هنگام خرابی آنها را بازآغازی می‌کند
+Comment[fi]=Käynnistää palvelimia tarpeen mukaan ja uudelleenkäynnistää ne virheen yhteydessä
+Comment[fr]=Lance les démons à la demande et les redémarre en cas d'échec
+Comment[gl]=Iniciar daemons cando sexa preciso e reinicialos se fallan.
+Comment[he]=מפעיל תהליכי רקע לפי דרישה ומפעיל אותם מחדש במקרה של כשל
+Comment[hu]=Szükség esetén elindítja, hiba esetén újraindítja a szolgáltatásokat
+Comment[is]=Ræsir þjóna þegar þarf og endurræsir þá ef þeir bregðast
+Comment[it]=Avvia i demoni su richiesta e li riavvia in caso di problemi
+Comment[ja]=デーモンをオンデマンドで起動し、失敗したときは再起動します。
+Comment[kk]=Талап бойынша қызметті жегу, жаңылса қайта жегу
+Comment[km]=ចាប់ផ្ដើម​ដេមិន​នៅ​ពេល​ត្រូវការ ហើយ​ចាប់ផ្ដើម​ពួក​វា​ឡើង​វិញ​នៅ​ពេល​បរាជ័យ
+Comment[lt]=Paleidžia tarnybas pagal pareikalavimą ir paleidžia iš naujo nesėkmės atveju
+Comment[ms]=Mulakan daemons atas permintaan dan mula semula atas kegagalan
+Comment[nb]=Starter nisser på forespørsler og starter dem igjen ved feil.
+Comment[nds]=Start Achtergrundperzessen op Nafraag un bi Fehlers nieg
+Comment[ne]=माग गरेको बेलामा डेइमन सुरु गर्दछ र अफफल भएमा फेरि सुरु गर्दछ
+Comment[nl]=Start achtergrondprogramma's op en herstart deze indien nodig
+Comment[nn]=Startar nissar når dei trengst og startar dei om att ved feil
+Comment[pl]=Uruchamia usługi na żądanie i wznawia je po awarii
+Comment[pt]=Inicia os servidores a pedido e reinicia-os em caso de falha
+Comment[pt_BR]=Inicia serviços sob demanda e reinicia-os em caso de falha
+Comment[ro]=Porneşte demonii la cerere şi îi reporneşte în caz de eroare
+Comment[ru]=Поддержка протокола MRML
+Comment[sk]=Spustí démonov podľa požiadaviek a pri zlyhaní ich reštartuje
+Comment[sl]=Na zahtevo zažene demone in jih ob napaki znova zažene
+Comment[sr]=На захтев покреће демоне и поново их покреће ако се сруше
+Comment[sr@Latn]=Na zahtev pokreće demone i ponovo ih pokreće ako se sruše
+Comment[sv]=Starta demoner vid behov och starta om dem vid fel
+Comment[ta]=அவசிய நேரத்தில் டிமென்னை துவக்குகிறது. இயலாதபோது திரும்ப துவக்குகிறது
+Comment[tg]=Оғози демон аз рӯи дархост ва ҳангоми нуқсони он аз сари нав оғоз намудан.
+Comment[tr]=İstek halinde programı başlatır ve hata durumunda yeniden başlatır.
+Comment[uk]=Запускає демони при потребі та перезапускає їх при аварії
+Comment[zh_CN]=按需启动守护程序并在失败时重新启动
+Comment[zh_HK]=依要求啟動系統程式並在失敗時重新啟動它們。
+Comment[zh_TW]=需要時啟動守護程式,失敗的話重新啟動
+ServiceTypes=KDEDModule
+X-KDE-ModuleType=Library
+X-KDE-Library=daemonwatcher
+X-KDE-FactoryName=daemonwatcher
+X-KDE-Kded-load-on-demand=true
diff --git a/kmrml/kmrml/server/watcher.cpp b/kmrml/kmrml/server/watcher.cpp
new file mode 100644
index 00000000..e6137cc5
--- /dev/null
+++ b/kmrml/kmrml/server/watcher.cpp
@@ -0,0 +1,280 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <dcopclient.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kdeversion.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include "watcher.h"
+
+using namespace KMrml;
+
+Watcher::Watcher( const QCString& name )
+ : KDEDModule( name )
+{
+ m_daemons.setAutoDelete( true );
+
+ // safety, for clients that die without unregistering
+ KApplication::dcopClient()->setNotifications( true );
+ connect( KApplication::dcopClient(),
+ SIGNAL( applicationRemoved( const QCString& )),
+ SLOT( slotAppUnregistered( const QCString& )));
+}
+
+Watcher::~Watcher()
+{
+ KApplication::dcopClient()->setNotifications( false );
+}
+
+bool Watcher::requireDaemon( const QCString& clientAppId,
+ const QString& daemonKey,
+ const QString& commandline,
+ uint timeout /* seconds */,
+ int restartOnFailure )
+{
+ if ( !KApplication::dcopClient()->isApplicationRegistered( clientAppId ) )
+ kdWarning() << "Watcher::requireDaemon: " << daemonKey
+ << ": Client AppID is not registered with DCOP: "
+ << clientAppId << endl;
+
+ DaemonData *daemon = m_daemons.find( daemonKey );
+
+ if ( daemon )
+ {
+ if ( !daemon->apps.find( clientAppId ) )
+ daemon->apps.append( clientAppId );
+
+ // timeout, commandline and restart values are: first come, first serve
+ return true; // process already running, all fine
+ }
+
+ else // start daemon
+ {
+ daemon = new DaemonData( daemonKey, commandline,
+ timeout, restartOnFailure );
+ m_daemons.insert( daemonKey, daemon );
+ daemon->apps.append( clientAppId );
+
+#if KDE_VERSION >= 306
+ daemon->process = new KProcess();
+ daemon->process->setUseShell( true );
+#else
+ daemon->process = new KShellProcess();
+#endif
+ daemon->process->setEnvironment( "LC_ALL", "C" );
+ daemon->process->setEnvironment( "LANG", "C" );
+ daemon->process->setEnvironment( "LANGUAGE", "C" );
+ *daemon->process << commandline;
+ connect( daemon->process, SIGNAL( processExited( KProcess * ) ),
+ SLOT( slotProcExited( KProcess * )));
+ return startDaemon( daemon );
+ }
+}
+
+void Watcher::unrequireDaemon( const QCString& clientAppId,
+ const QString& daemonKey )
+{
+ unrequireDaemon( m_daemons.find( daemonKey ), clientAppId );
+}
+
+void Watcher::unrequireDaemon( DaemonData *daemon,
+ const QCString& clientAppId )
+{
+ if ( daemon )
+ {
+ daemon->apps.remove( clientAppId );
+ if ( daemon->apps.isEmpty() )
+ {
+ if ( !daemon->timer )
+ {
+ daemon->timer = new QTimer();
+ connect( daemon->timer, SIGNAL( timeout() ),
+ SLOT( slotTimeout() ));
+ }
+ daemon->timer->start( daemon->timeout * 1000, true );
+ }
+ }
+ else
+ kdWarning() << "Watcher::unrequireDaemon: daemon unknown. client: "
+ << clientAppId << endl;
+}
+
+QStringList Watcher::runningDaemons() const
+{
+ QStringList result;
+ QDictIterator<DaemonData> it( m_daemons );
+ for ( ; it.current(); ++it )
+ result.append( it.current()->commandline );
+
+ return result;
+}
+
+void Watcher::slotProcExited( KProcess *proc )
+{
+ DaemonData *daemon = findDaemonFromProcess( proc );
+
+ if ( proc->normalExit() )
+ {
+ emitExited( daemon );
+ return;
+ }
+
+ if ( daemon )
+ {
+ if ( --daemon->restartOnFailure <= 0 )
+ {
+ if ( KMessageBox::questionYesNo( 0L,
+ i18n("<qt>The server with the command line"
+ "<br>%1<br>"
+ "is not available anymore. Do you want to "
+ "restart it?" ).arg( daemon->commandline ),
+ i18n("Service Failure"), i18n("Restart Server"), i18n("Do Not Restart") )
+ == KMessageBox::Yes )
+ {
+ daemon->restartOnFailure = 1;
+ }
+ }
+
+ if ( daemon->restartOnFailure > 0 )
+ {
+ startDaemon( daemon );
+ return;
+ }
+ }
+
+ emitFailure( daemon );
+}
+
+bool Watcher::startDaemon( DaemonData *daemon )
+{
+ if ( daemon->process->start( KProcess::NotifyOnExit ) )
+ return true;
+
+ else
+ {
+ if ( KMessageBox::questionYesNo( 0L,
+ i18n("Unable to start the server with the "
+ "command line"
+ "<br>%1<br>"
+ "Try again?").arg( daemon->commandline ),
+ i18n("Service Failure"), i18n("Try Again"), i18n("Do Not Try") )
+ == KMessageBox::Yes )
+ {
+ return startDaemon( daemon );
+ }
+ }
+
+ return false;
+}
+
+void Watcher::slotTimeout()
+{
+ QTimer *timer = static_cast<QTimer*>( const_cast<QObject *>( sender() ) );
+ DaemonData *daemon = findDaemonFromTimer( timer );
+ if ( daemon )
+ {
+ if ( daemon->apps.isEmpty() )
+ {
+ // the daemon and KProcess might get deleted by killing the
+ // KProcess (through slotProcExited()), so don't dereference
+ // daemon after proc->kill()
+ QString key = daemon->daemonKey;
+
+ // noone registered during the timeout, so kill the daemon
+ if ( !daemon->process->kill() )
+ daemon->process->kill( SIGKILL );
+
+ m_daemons.remove( key );
+ }
+ }
+}
+
+DaemonData * Watcher::findDaemonFromProcess( KProcess *proc )
+{
+ DaemonData *daemon;
+ QDictIterator<DaemonData> it( m_daemons );
+ for ( ; (daemon = it.current()); ++it )
+ {
+ if ( daemon->process == proc )
+ return daemon;
+ }
+
+ return 0L;
+}
+
+DaemonData * Watcher::findDaemonFromTimer( QTimer *timer )
+{
+ DaemonData *daemon;
+ QDictIterator<DaemonData> it( m_daemons );
+ for ( ; (daemon = it.current()); ++it )
+ {
+ if ( daemon->timer == timer )
+ return daemon;
+ }
+
+ return 0L;
+}
+
+void Watcher::slotAppUnregistered( const QCString& appId )
+{
+ if ( m_daemons.isEmpty() )
+ return;
+
+ DaemonData *daemon;
+ QDictIterator<DaemonData> it( m_daemons );
+ for ( ; (daemon = it.current()); ++it )
+ {
+ if ( daemon->apps.find( appId ) != -1 )
+ unrequireDaemon( daemon, appId );
+ }
+}
+
+void Watcher::emitExited( DaemonData *daemon )
+{
+ if ( daemon )
+ {
+ daemonExited( daemon->daemonKey,
+ daemon->process->pid(),
+ daemon->process->exitStatus() );
+
+ m_daemons.remove( daemon->daemonKey );
+ }
+}
+
+void Watcher::emitFailure( DaemonData *daemon )
+{
+ if ( daemon )
+ {
+ daemonDied( daemon->daemonKey, daemon->process->pid() );
+ m_daemons.remove( daemon->daemonKey ); // deletes daemon + KProcess
+ }
+}
+
+extern "C" {
+ KDE_EXPORT KDEDModule *create_daemonwatcher(const QCString & obj )
+ {
+ return new Watcher( obj );
+ }
+}
+
+
+#include "watcher.moc"
diff --git a/kmrml/kmrml/server/watcher.h b/kmrml/kmrml/server/watcher.h
new file mode 100644
index 00000000..67d9b5e1
--- /dev/null
+++ b/kmrml/kmrml/server/watcher.h
@@ -0,0 +1,107 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef LAUNCHER_H
+#define LAUNCHER_H
+
+#include <qdict.h>
+#include <qmap.h>
+#include <qstrlist.h>
+#include <qstringlist.h>
+#include <qtimer.h>
+
+#include <kdedmodule.h>
+#include <kprocess.h>
+
+namespace KMrml
+{
+ class DaemonData
+ {
+ public:
+ DaemonData( const QString& key, const QString& cmd,
+ uint time, int numRestarts )
+ : daemonKey( key ),
+ commandline( cmd ),
+ timeout( time ),
+ apps( true ), // deep copies
+ restartOnFailure( numRestarts ),
+ process( 0L ),
+ timer( 0L )
+ {
+ }
+ ~DaemonData()
+ {
+ delete process;
+ delete timer;
+ }
+ QString daemonKey;
+ QString commandline;
+ uint timeout;
+ QStrList apps;
+ int restartOnFailure;
+ KProcess *process;
+ QTimer *timer;
+ };
+
+ class Watcher : public KDEDModule
+ {
+ Q_OBJECT
+ K_DCOP
+
+ public:
+ Watcher( const QCString& name = "daemonwatcher" );
+ ~Watcher();
+
+ k_dcop:
+ virtual bool requireDaemon( const QCString& clientAppId,
+ const QString& daemonKey,
+ const QString& commandline,
+ uint timeout = 60 /* seconds */,
+ int numRestarts = 5 );
+ virtual void unrequireDaemon( const QCString& clientAppId,
+ const QString& daemonKey );
+ virtual QStringList runningDaemons() const;
+
+ k_dcop_signals:
+ void daemonExited(const QString& daemonKey, pid_t pid, int exitStatus);
+ void daemonDied( const QString& daemonKey, pid_t pid );
+
+ protected:
+ bool startDaemon( DaemonData *daemon );
+
+ protected slots:
+ virtual void slotTimeout();
+
+ private:
+ void unrequireDaemon( DaemonData *daemon, const QCString& clientAppId);
+ DaemonData *findDaemonFromProcess( KProcess *proc );
+ DaemonData *findDaemonFromTimer( QTimer *timer );
+
+ void emitExited( DaemonData *daemon );
+ void emitFailure( DaemonData *daemon );
+
+ private slots:
+ void slotProcExited( KProcess *proc );
+ void slotAppUnregistered( const QCString& appId );
+
+ QDict<DaemonData> m_daemons;
+ };
+
+}
+
+#endif // LAUNCHER_H
diff --git a/kolourpaint/AUTHORS b/kolourpaint/AUTHORS
new file mode 100644
index 00000000..c4befef2
--- /dev/null
+++ b/kolourpaint/AUTHORS
@@ -0,0 +1,112 @@
+
+Authors
+=======
+
+Clarence Dang <dang@kde.org>
+Maintainer
+
+Thurston Dang <thurston_dang@users.sourceforge.net>
+Chief Investigator
+
+Kristof Borrey <borrey@kde.org>
+Icons
+
+Kazuki Ohta <mover@hct.zaq.ne.jp>
+InputMethod Support
+
+Nuno Pinheiro <nf.pinheiro@gmail.com>
+Icons
+
+Danny Allen <dannya40uk@yahoo.co.uk>
+Icons
+
+Martin Koller <m.koller@surfeu.at>
+Scanning Support
+
+
+Thanks To
+=========
+
+Rashid N. Achilov
+Toyohiro Asukai
+Bela-Andreas Bargel
+Waldo Bastian
+Ismail Belhachmi
+Sashmit Bhaduri
+Antonio Bianco
+Stephan Binner
+Markus Brueffer
+Rob Buis
+Lucijan Busch
+Mikhail Capone
+Enrico Ceppi
+Tom Chance
+Albert Astals Cid
+Jennifer Dang
+Lawrence Dang
+Christoph Eckert
+David Faure
+P. Fisher
+Nicolas Goutte
+Herbert Graeber
+Brad Grant
+David Greenaway
+Wilco Greven
+Hubert Grininger
+Adriaan de Groot
+Esben Mose Hansen
+Nadeem Hasan
+Simon Hausmann
+Michael Hoehne
+Andrew J
+Werner Joss
+Derek Kite
+Tobias Koenig
+Dmitry Kolesnikov
+Stephan Kulow
+Eric Laffoon
+Michael Lake
+Sebastien Laout
+David Ling
+Volker Lochte
+Anders Lund
+Jacek Masiulaniec
+Benjamin Meyer
+Amir Michail
+Robert Moszczynski
+Dirk Mueller
+Ruivaldo Neto
+Ralf Nolden
+Steven Pasternak
+Cedric Pasteur
+Erik K. Pedersen
+Dennis Pennekamp
+Jos Poortvliet
+Boudewijn Rempt
+Marcos Rodriguez
+Matt Rogers
+Francisco Jose Canizares Santofimia
+Bram Schoenmakers
+Dirk Schonberger
+Lutz Schweizer
+Emmeran Seehuber
+Peter Simonsson
+Andrew Simpson
+A T Somers
+Igor Stepin
+Stephen Sweeney
+Bart Symons
+Stefan Taferner
+Hogne Titlestad
+Brandon Mark Turner
+Jonathan Turner
+Stephan Unknown
+Dries Verachtert
+Simon Vermeersch
+Lauri Watts
+Mark Wege
+Christoph Wiesen
+Andre Wobbeking
+Luke-Jr
+Maxim_86ualb2
+Michele
diff --git a/kolourpaint/BUGS b/kolourpaint/BUGS
new file mode 100644
index 00000000..84f3391f
--- /dev/null
+++ b/kolourpaint/BUGS
@@ -0,0 +1,154 @@
+
+Please send bug reports and feature requests to http://bugs.kde.org/.
+Don't hesitate to report bugs nor hesitate to send us your wishes - it
+provides valuable feedback that will help to improve future versions of
+KolourPaint and you will not receive flames for reporting duplicates.
+
+
+This file lists known bugs in this version that are not considered
+"release critical" and are difficult to fix:
+
+
+1. Flicker when zooming in/out.
+
+3. Tool Box & Colour Box RMB ToolBar Menus do not work.
+
+4. Image dialog spinboxes should accept Enter Key (instead of the dialog's
+ OK button) after the user has typed something.
+
+ OR
+
+ Spinboxes should signal that their values have changed every time the
+ user changes the text (rather than after pressing Enter or clicking on
+ another spinbox etc.).
+
+ The need for the "Update Preview" button and the difficulty of keeping
+ the percentages and dimensions in sync in the Resize / Scale dialog are
+ manifestations of the current QSpinBox behaviour.
+
+6. a) The undo history and document modified state are not updated during
+ the drawing of multi-segment shapes (Polygon, Connected Lines,
+ Curve). They are however updated after shapes' completion.
+
+ b) The text and brush-like tools set the document modified flag even if
+ user cancels the draw operation.
+
+ c) Select a region, manipulate it (e.g. move), undo - the document is
+ still marked as modified (because 2 commands - the create selection
+ and the move - were added but only one was undone).
+
+7. Certain shapes may have the wrong size (usually only a pixel off and
+ only in extreme cases) e.g. an ellipse of height 1 always has a width 1
+ pixel less than it should be. This is a Qt bug.
+
+8. At zoom levels that aren't multiples of 100%, parts of the image may
+ appear to move when the user interacts with it. Other minor redraw
+ glitches may also occur at such zoom levels.
+
+9. Keyboard shortcut changes do not propagate to other KolourPaint windows
+ (but will propagate to future windows).
+
+10. "File/Open Recent" entries are not updated interprocess.
+
+11. The blinking text cursor will "disappear" if you type more text than
+ you can fit in a text box.
+
+12. You cannot select only parts of the text you write.
+
+13. Due to a workaround for a Qt bug, writing text with the foreground
+ colour set to transparent is incredibly slow. Write your text in
+ another colour and then set the foreground colour to transparent after
+ you've finished typing to avoid this issue.
+
+14. The text cursor may be momentarily misrendered when scrolling the view.
+
+17. a) Using KolourPaint on a remote X display may result in redraw errors
+ and pixel data corruption.
+
+ b) KolourPaint is screen depth dependent. Opening an image with a
+ an alpha channel and/or a depth higher than the screen and then
+ saving it will likely result in loss of colour information. Also,
+ 8-bit screens are not supported at all. To reduce data loss, run
+ your screen at 24-bit. This bug will be addressed in a future
+ version of KolourPaint.
+
+19. Read support for EPS files is extremely slow. You should not enable
+ the "Save Preview" dialog when saving to EPS. This is an issue with
+ KDE.
+
+20. Pasting a large image (esp. one that doesn't compress well as PNG)
+ into an image editor (not necessarily KolourPaint) running as
+ different process from the KolourPaint which was the source of the
+ image, on a sufficiently slow computer, may fail with the following
+ output to STDERR:
+
+ "kolourpaint: ERROR: kpMainWindow::paste() with sel without pixmap
+ QClipboard: timed out while sending data"
+
+ This is a Qt bug.
+
+21. It is not always possible to copy and paste between 2 instances of
+ KolourPaint running different Qt versions. See
+ QDataStream::setVersion().
+
+22. The Emboss, Blur and Sharpen effects give different results depending
+ on _both_:
+
+ a) The KDE version KolourPaint was compiled with
+ (due to KImageEffect not supporting strength settings for these
+ effects in KDE 3.0, KolourPaint repeats these effects in order to
+ simulate strength)
+
+ b) The KDE version KolourPaint is running under
+ (e.g. for the same function calls, KDE 3.2's effects are slower but
+ give better results than those in KDE 3.0)
+
+23. Changing tool options while in the middle of a drawing option may
+ confuse KolourPaint. For instance:
+
+ a) With the brush tools, the cursor incorrectly appears.
+
+ b) With the rectangle-based tools, the temporary pixmap does not resize
+ when the line width increases.
+
+25. Sometimes when you take a screenshot of a window, and then paste in a
+ new window, it will be greyscale. When pasting again, it will still be
+ greyscale. Cannot consistently reproduce. [Thurston]
+
+26. Drawing with the keyboard is unreliable. Depending on the X server,
+ either holding down Enter may continually switch between drawing and
+ not drawing or KolourPaint may fail to detect the release of the Enter
+ key.
+
+27. InputMethod has not been tested at zoom levels other than 100%.
+
+28. KolourPaint has not been tested against invalid or malicious clipboard
+ data.
+
+
+Issue with XFree86 <= 3.3.6 with the "Emulate3Buttons" Option
+=============================================================
+
+When drawing, clicking the left or right mouse button that did not
+initiate the current operation will, in this order:
+
+1. finalise the current drawing operation
+2. attempt to paste the contents of the middle-mouse-button clipboard
+
+instead of canceling the current drawing operation.
+
+This is due to XFree86 sending a release notification for the button that
+initiated the drawing operation, followed by a press notification for the
+emulated 3rd button; instead of just a single press notification for the
+button that is intended to cancel the operation. This works correctly in
+XFree86 4.x with "Emulate3Buttons" on because it is harder to trigger the
+emulation for the 3rd button as it is only invoked if the left and right
+buttons are pressed at almost the same time.
+
+Possible solutions:
+
+a) Use XFree86 4.x or an X server from another vendor (e.g. X.org).
+b) Press Escape in KolourPaint to cancel the current drawing operation
+ instead of using the problematic click method described above.
+c) Disable "Emulate3Buttons".
+
diff --git a/kolourpaint/COPYING b/kolourpaint/COPYING
new file mode 100644
index 00000000..df47eb9b
--- /dev/null
+++ b/kolourpaint/COPYING
@@ -0,0 +1,23 @@
+Copyright (c) 2003,2004,2005,2006 Clarence Dang <dang@kde.org>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/kolourpaint/ChangeLog b/kolourpaint/ChangeLog
new file mode 100644
index 00000000..9acd0397
--- /dev/null
+++ b/kolourpaint/ChangeLog
@@ -0,0 +1,15 @@
+
+For logs of _every_ single change made to KolourPaint between any date or
+revision, visit:
+
+ http://websvn.kde.org/trunk/KDE/kdegraphics/kolourpaint
+
+ http://websvn.kde.org/branches/KDE/<version>/kdegraphics/kolourpaint
+ http://websvn.kde.org/tags/KDE/<version>/kdegraphics/kolourpaint
+
+ http://websvn.kde.org/branches/kolourpaint
+ http://websvn.kde.org/tags/kolourpaint
+
+
+For a summary of user-visible changes between each release, read NEWS.
+
diff --git a/kolourpaint/Makefile.am b/kolourpaint/Makefile.am
new file mode 100644
index 00000000..35da2859
--- /dev/null
+++ b/kolourpaint/Makefile.am
@@ -0,0 +1,76 @@
+SUBDIRS = cursors pics pixmapfx tools views widgets
+
+bin_PROGRAMS = kolourpaint
+
+
+kolourpaint.o: kolourpaintlicense.h kolourpaintversion.h
+
+kolourpaintlicense.h : $(srcdir)/COPYING
+ echo "static const char * const kpLicenseText =" > kolourpaintlicense.h
+ cat $(srcdir)/COPYING | sed -e 's/"/\\"/g' -e 's/$$/\\n"/g' -e 's/^/ "/g' >> kolourpaintlicense.h
+ echo ";" >> kolourpaintlicense.h
+
+kolourpaintversion.h : $(srcdir)/VERSION
+ echo "static const char * const kpVersionText =" > kolourpaintversion.h
+ cat $(srcdir)/VERSION | sed -e 's/"/\\"/g' -e 's/$$/"/g' -e 's/^/ "/g' >> kolourpaintversion.h
+ echo ";" >> kolourpaintversion.h
+
+CLEANFILES = kolourpaintlicense.h kolourpaintversion.h
+
+
+kolourpaint_SOURCES = kolourpaint.cpp \
+ kpdocument.cpp \
+ kpdocumentmetainfo.cpp \
+ kpdocumentsaveoptions.cpp \
+ kpdocumentsaveoptionswidget.cpp \
+ kpview.cpp \
+ kpcolor.cpp kpcommandhistory.cpp \
+ kpmainwindow.cpp \
+ kpmainwindow_edit.cpp kpmainwindow_help.cpp \
+ kpmainwindow_image.cpp kpmainwindow_tools.cpp \
+ kpmainwindow_file.cpp kpmainwindow_settings.cpp kpmainwindow_statusbar.cpp \
+ kpmainwindow_text.cpp \
+ kpmainwindow_view.cpp \
+ kpselection.cpp kpselectiondrag.cpp kpselectiontransparency.cpp \
+ kpsinglekeytriggersaction.cpp \
+ kptemppixmap.cpp kptextstyle.cpp \
+ kpthumbnail.cpp \
+ kptool.cpp \
+ kpviewmanager.cpp \
+ kpviewscrollablecontainer.cpp \
+ kpwidgetmapper.cpp
+kolourpaint_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+kolourpaint_LDADD = $(LIB_KDEPRINT) \
+ cursors/libkolourpaintcursors.la \
+ pixmapfx/libkolourpaintpixmapfx.la \
+ tools/libkolourpainttools.la \
+ views/libkolourpaintviews.la \
+ widgets/libkolourpaintwidgets.la
+
+AM_CPPFLAGS = -I$(srcdir)/cursors -I$(srcdir)/interfaces \
+ -I$(srcdir)/pixmapfx \
+ -I$(srcdir)/tools \
+ -I$(srcdir)/views \
+ -I$(srcdir)/widgets $(all_includes)
+
+METASOURCES = AUTO
+
+rcdir = $(kde_datadir)/kolourpaint
+rc_DATA = kolourpaintui.rc
+
+xdg_apps_DATA = kolourpaint.desktop
+
+messages: rc.cpp
+ $(EXTRACTRC) *.rc *.ui \
+ cursors/*.rc cursors/*.ui \
+ pixmapfx/*.rc pixmapfx/*.ui \
+ tools/*.rc tools/*.ui \
+ widgets/*.rc widgets/*.ui \
+ >> rc.cpp
+ $(XGETTEXT) *.cpp *.h \
+ cursors/*.cpp cursors/*.h \
+ pixmapfx/*.cpp pixmapfx/*.h \
+ tools/*.cpp tools/*.h \
+ widgets/*.cpp widgets/*.h \
+ -o $(podir)/kolourpaint.pot
+
diff --git a/kolourpaint/NEWS b/kolourpaint/NEWS
new file mode 100644
index 00000000..43828069
--- /dev/null
+++ b/kolourpaint/NEWS
@@ -0,0 +1,349 @@
+
+KolourPaint 1.4_relight Series (branches/KDE/3.5/)
+===============================
+
+KolourPaint 1.4.9_relight (Frozen ???)
+
+ * Ensure selection operations always repaint correctly
+ [the effects of this change are unlikely to be functionality visible]
+
+KolourPaint 1.4.8_relight (Frozen 2007-10-08)
+
+ * Always enable the paste actions to guarantee that pasting from
+ non-Qt applications is always allowed (non-Qt applications do not
+ notify KolourPaint when they place objects into the clipboard)
+
+ * Paste transparent pixels as white instead of uninitialized colors,
+ when the app does not support pasting transparent pixels (such as
+ OpenOffice.org)
+
+ * Make "Edit / Paste in New Window" always paste white pixels as white
+ (it used to paste them as transparent when the selection transparency
+ mode was set to Transparent)
+
+ * Saving, exporting and printing a document with an active text box,
+ that has opaque text and a transparent background, antialiases the
+ text with the document below
+
+ * "Edit / Paste From File..." respects the "Transparent" selection mode
+
+ * Focus an input field when the "Skew", "Rotate" and "Resize / Scale"
+ dialogs are displayed -- this allows the user to edit values without
+ an extra mouse click
+
+ * Add error dialogs for:
+ - if scanning support is unavailable
+ - running out of graphics memory during a scan
+
+ * Other minor changes -- some of these are:
+ - Finish the current shape in more cases of menu item accesses
+ - [internal] kpDocument::selectionCopyOntoDocument() marks the document
+ as modified
+ - More comments
+
+KolourPaint 1.4.7_relight (Frozen 2007-05-14)
+
+ * Save local files atomically - KolourPaint will no longer truncate
+ an existing file if the KImageIO library for the file format is
+ missing or if you run out of disk space.
+
+ * Add "File / Scan..." feature (Martin Koller)
+
+ * Add global session save/restore (Bug #94651)
+
+ * Make "File / Open Recent" consistently work when multiple windows are
+ open
+
+ * CTRL+C'ing a text box also places the text in the middle-mouse-button
+ clipboard, in lieu of being able to highlight the text to do this
+
+ * Change minimum allowed zoom level for the grid from 600% to 400%
+
+KolourPaint 1.4.6_relight (Frozen 2007-01-13)
+
+ * Fix crash triggered by rapidly deselecting the selection after
+ drag-scaling it (Bug #117866)
+ [also in branches/KDE/3.[34]/, branches/kolourpaint/1.2_kde3/]
+
+KolourPaint 1.4.5_relight (Frozen 2006-09-19)
+
+ * Translation updates
+
+KolourPaint 1.4.4_relight (Frozen 2006-07-12)
+
+ * Minor code cleanups and corrections
+
+KolourPaint 1.4.3_relight (Frozen 2006-05-02)
+
+ * Probably translation updates
+
+KolourPaint 1.4.2_relight (Frozen 2006-03-12)
+
+ * Printing improvements (Bug #108976)
+ - Respect image DPI
+ - Fit image to page if image is too big
+ - Centre image on page
+ [also in branches/KDE/3.[34]/, branches/kolourpaint/1.2_kde3/]
+
+KolourPaint 1.4.1_relight (Frozen 2006-01-15)
+
+ * Updated documentation (Thurston)
+
+KolourPaint 1.4_relight (Frozen 2005-11-08)
+
+ * New icons (Danny Allen, Nuno Pinheiro)
+
+ * Tool Box icon size is 22x22, not 16x16, at screen resolution >= 1024x768
+
+ * CTRL + Mouse Wheel = Zoom
+
+ * While freehand selection scaling, holding Shift maintains aspect ratio
+
+ * Prevent accidental drags in the Colour Palette from pasting text
+ containing the colour code
+ [also in branches/KDE/3.[34]/, branches/kolourpaint/1.2_kde3/]
+
+ * Cells in the bottom row and cells in the rightmost column of the Colour
+ Palette are now the same size as the other cells
+ [also in branches/KDE/3.[34]/, branches/kolourpaint/1.2_kde3/]
+
+ * Text drops to the empty part of the scrollview will not be placed
+ outside the document
+ [also in branches/KDE/3.[34]/, branches/kolourpaint/1.2_kde3/]
+
+ * Rename icons from "hi" to "cr" - back to the state of 1.0 (Danny Allen)
+ but leave application icons as "hi" (Jonathan Riddell)
+
+ * Enforce text box font height to prevent e.g. Chinese characters in
+ buggy fonts from enlarging the text box and putting the cursor out of
+ sync with the text
+ [also in branches/KDE/3.[34]/, branches/kolourpaint/1.2_kde3/]
+
+ * Clicking in a text box selects a character based on its midpoint -
+ not leftmost point - to be consistent with all text editors
+ (esp. noticeable with big fonts)
+ [also in branches/KDE/3.[34]/, branches/kolourpaint/1.2_kde3/]
+
+ * Return and Numpad 5 Key now draw
+ [also in branches/KDE/3.[34]/, branches/kolourpaint/1.2_kde3/]
+
+ * Tool Actions placed outside the Tool Box resize with their toolbars
+ [also in branches/KDE/3.[34]/, branches/kolourpaint/1.2_kde3/]
+
+ * Ensure Color Similarity maximum is 30, not 29 due to gcc4
+ [also in branches/KDE/3.[34]/, branches/kolourpaint/1.2_kde3/]
+
+ * Tool Box traps right clicks (for the RMB Menu) on top of tool options
+ widgets and the empty part of the Tool Box
+ [also in branches/KDE/3.[34]/, branches/kolourpaint/1.2_kde3/]
+
+ * Correct and update image format associations to all formats supported
+ by KDE 3.5 (kdelibs/kimgio/:r466654)
+
+ * String fixes (Stefan Winter)
+ [also in branches/KDE/3.4/]
+
+ * Other string fixes (Malcolm Hunter, Clarence Dang, Stephan Binner)
+
+
+KolourPaint 1.4_light Series (branches/KDE/3.4/)
+============================
+
+KolourPaint 1.4_light (Frozen 2005-02-22)
+ * Antialias text when the text box has a transparent background (Bug #24)
+ [later backported to branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/]
+ * Add Unzoomed Thumbnail Mode and Thumbnail Rectangle
+ * Add RMB context menu for when a selection tool is active (closing KDE
+ Bug #92882)
+ * More intuitive "Set as Image" behaviour (esp. with selection borders).
+ Thanks to Michael Lake for the feedback.
+ [later backported to branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/]
+ * InputMethod support
+ [later backported to branches/kolourpaint/1.2_kde3/]
+ * Save "More Effects" dialog's last effect to config file
+ * Save "Resize / Scale" dialog's last "Keep aspect ratio" setting to
+ config file
+ * Add "Help / Acquiring Screenshots"
+ * Fix selection regressions introduced in 1.2:
+ - Make selection dragging with CTRL work again (copies selection onto
+ document)
+ - When creating freeform selections, include the starting point; also
+ avoids a QRegion crash with constructing 1-point regions
+ [also in branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/]
+ * Fix other selection bugs:
+ - When the user drags very quickly on a resize handle, resize the
+ selection instead of moving it
+ - Draw resize handles above the grid lines - not below - so that the
+ handles are always visible if they are supposed to be there
+ [also in branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/]
+ * Smaller selection and text box resize handles (visually not
+ actually) - covers up fewer selected pixels, doesn't cover up text
+ [also in branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/]
+ * Restore mouse cursor after deselecting selection/text tools
+ [also in branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/]
+ * Empty text clipboard fixes:
+ - Don't get stuck on a wait cursor after attempting to paste empty
+ text into a text box
+ - Prevent pasting text from creating a new text box if text is empty
+ - Prevent copying of empty text box
+ [also in branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/]
+ * Speed up renderer (most noticeable with diagonal drag-scrolling at
+ high zoom)
+ - Don't paint anything outside of the view's visible region
+ (previously, clipped only on view _widget_ region)
+ - Region-aware: paint component rectangles of the update region,
+ rather than the bounding rectangle
+ [also in branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/]
+ * When changing between colour depth and quality widgets in the save
+ filedialog, make sure "Convert to:" and "Quality:" are correctly
+ rendered (hacking around a Qt redraw glitch)
+ [also in branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/]
+ * Fix crash after using the Colour Picker if it was the first used tool
+ [kolourpaint-1.2.2_kde3-color_picker_crash.diff]
+ [also in branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/]
+ * Fix crash due to text box when scaling image behind it
+ [also in branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/]
+ * Even when the thumbnail has focus (and not the main window), blink the
+ text cursor in all views
+ [kolourpaint-1.2.2_kde3-thumbnail_blink_text_cursor.diff]
+ [also in branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/]
+ * Correct "Soften" and "Sharpen" commands' command history names
+ * Correct invert commands' command history names
+ * Fix remaining untranslatable strings (closing KDE Bug #85785)
+ [also in branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/]
+ * Update image format associations to all formats supported by KDE 3.4
+ * Remove unused images in doc directory
+ [also in branches/KDE/3.3/, branches/kolourpaint/1.2_kde3/]
+ * Correct kolourpaint.desktop "Terminal=" and "Categories=" syntax
+ (Benjamin Meyer)
+
+
+KolourPaint 1.2 Series (branches/KDE/3.3/)
+======================
+
+Version 1.2 "ByFiat Everytime" (2004-08-18)
+ * Add up to 500 levels of Undo/Redo (minimum of 10 levels, maximum of
+ 500 as long as the total history size < 16MB)
+ * Add freehand resizing of image
+ * Add freehand smooth scaling of selections
+ * [also in 1.0 branch] New icons (Kristof Borrey)
+ * [also in 1.0 branch] Prefer Crystal SVG text icons over KolourPaint's
+ * [also in 1.0 branch] Add documentation in the KDE Help Centre
+ * Add drag scrolling
+ * Add "More Effects" dialog:
+ - Balance (Brightness, Contrast, Gamma)
+ - Emboss
+ - Flatten
+ - Invert (with choice of channels)
+ - Reduce Colours
+ - Soften & Sharpen
+ * File saving improvements:
+ - Support colour depths (optional dithering) and "colour monochrome"
+ - Support JPEG quality
+ - Realtime file dialog preview with estimated file size
+ - Retain PNG metadata
+ - Prompt when attempting lossy save
+ - Correctly save transparent selections (not as opaque)
+ * Dither more often when loading (and pasting) images for better quality
+ * Single key shortcuts for all tools and tool options (automatically
+ turned off when editing text but can then use Alt+Shift+<key>)
+ * Arrow keys now move one document pixel - not view pixel - at a time
+ (more usable when zoomed in)
+ * Fix selection bugs:
+ - Fix duplicate "Selection: Create" undo entries (Bug #5a)
+ - Allow redoing of selection operation if border deselected (Bug #5b)
+ - Don't print to STDERR when undoing a selection border create
+ operation and border has already been deselected
+ - [also in 1.0 branch] When pulling a selection from the document,
+ only set the bits of the document to the background colour where the
+ transparent selection is opaque in the same place (this is only
+ noticeable with colour similarity turned on). Now moving a
+ selection away and then back to its original place is always a NOP
+ as it should be.
+ * Selections can be deselected using Esc or clicking on icon in Tool Box
+ * Accidental drag detection when deselecting selections or text boxes
+ * Prevent selection from being moved completely offscreen (at least 1
+ pixel of the selection will stay within the view)
+ * Speed up copying selection when transparency is on
+ * Improve Text Tool usability:
+ - Allow single click creation of text box with a sane default size
+ - Allow freehand resizing of text boxes
+ - Add Opaque/Transparent selector for greater usability and
+ consistency with selections
+ - Minimum size is now 7x7 document pixels (1x1 - not 4x4 - border)
+ - Text cursor doesn't overlap border anymore
+ - When dropping text, paste at drop point
+ - When MMB pasting creates a new text box, do so at mouse position
+ * When MMB pasting text in an existing box, correctly paste multiline
+ clipboard contents
+ * Improve text quality:
+ - With a transparent background, don't antialias foreground opaque
+ text with arbitrarily chosen black
+ - Make sure transparent text shows up on opaque (usually, grey was
+ problematic) background
+ * Improve Resize/Scale dialog usability:
+ - Add Smooth Scale (useful for creating screenshot thumbnails)
+ - Allow manipulating image when selection is active
+ - Operation choices stand out as massive, easily clickable buttons
+ - Default focus on operation choices
+ * Warn if Resize/Scale, Rotate or Skew will take lots of memory
+ * Limit startup image size to 2048x2048
+ * Eliminate flicker when scrolling
+ * Thumbnail fixes:
+ - Reduce flicker when appearing (Bug #2)
+ - More reasonable minimum size (actually enforce it)
+ - [also in 1.0 branch] Use deleteLater()
+ - [also in 1.0 branch] Save geometry even if it's closed very quickly
+ after a geometry change
+ * Restore last used tool and tool options on startup
+ * Add Export, Copy To File, Paste From File, Paste in New Window,
+ Full Screen Mode
+ * Add Zoom In/Out buttons to main toolbar
+ * Rename Crop options in an attempt to reduce confusion:
+ - "Autocrop" --> "Remove Internal Border" when selection active
+ - "Crop Outside Selection" --> "Set as Image (Crop)"
+ * "Set as Image" changes:
+ - Enable for text boxes
+ - Underneath transparent bits of selection, fill image with
+ transparent rather than with background colour
+ * Permit "reloading" of an empty document
+ * Fixes when the current URL doesn't exist:
+ - Don't reload if underlying file disappeared
+ - Don't add non-existent file to Recent Files history
+ - Ask to save before mailing or setting as wallpaper
+ * Only enable Show Path when there is a URL
+ * Pop up dialog (instead of printing to STDERR) and disable Edit/Paste
+ on CTRL+V if the clipboard contents disappeared due to the source
+ application quitting (and Klipper didn't retain clipboard contents)
+ * Image/Clear now always sets _everything_ within the selection boundary
+ to the background colour - including transparent pixels
+ * Add Preview button to Colour Similarity Dialog to work around Bug #4
+ regarding spinboxes and enter key
+ * Colour Picker disallows trying to pick colour outside of image
+ * Make sure colour palette contains valid and visible colours at 8-bit
+ * [also in 1.0 branch] Fix (big) memory leak on kpSelection destruction
+ (Albert Astals Cid)
+ * Don't leak image dialogs' memory
+ * [also in 1.0 branch] Don't let C++ destruct the mask bitmap before its
+ painter when dbl-clicking the color eraser does NOP (avoids
+ QPaintDevice and X error)
+ * [also in 1.0 branch] Check for QImageDrag::canDecode() before calling
+ QImageDrag::decode() (prevents X and valgrind errors)
+ * [also in 1.0 branch] Fix compilation problem with QT_NO_ASCII_CAST
+ (Waldo Bastian)
+ * [also in 1.0 branch] Decrease application preference to below that of
+ a viewer (Stephan Kulow)
+ * Remember dialog dimensions
+ * Remove double dialog margins
+ * Fix missing i18n()'s
+ * Fix some untranslatable strings
+ * [also in 1.0 branch] Corrected several strings
+ * Remove unused icons
+
+
+KolourPaint 1.0 Series (branches/kolourpaint/1.0/)
+======================
+
+Version 1.0 "Seagull" (2004-02-29)
+ * First stable release
+
diff --git a/kolourpaint/README b/kolourpaint/README
new file mode 100644
index 00000000..b045e3b9
--- /dev/null
+++ b/kolourpaint/README
@@ -0,0 +1,102 @@
+
+KolourPaint Version 1.4.9_relight (KDE 3.5.9 Release Frozen ???)
+http://www.kolourpaint.org/
+
+Copyright (c) 2003,2004,2005,2006 Clarence Dang <dang@kde.org>
+
+
+For licensing and warranty information, read COPYING.
+For known problems with this release of KolourPaint, read BUGS.
+For what changes have been made, read NEWS.
+For developer information, checkout branches/kolourpaint/control/.
+For general information, read this file (README):
+
+
+1. What is KolourPaint?
+=======================
+
+KolourPaint is a free, easy-to-use paint program for KDE.
+
+It aims to be conceptually simple to understand; providing a level of
+functionality targeted towards the average user. It's designed for daily
+tasks like:
+
+* Painting - drawing diagrams and "finger painting"
+* Image Manipulation - editing screenshots and photos; applying effects
+* Icon Editing - drawing clipart and logos with transparency
+
+It's not an unusable and monolithic program where simple tasks like drawing
+lines become near impossible. Nor is it so simple that it lacks essential
+features like Undo/Redo.
+
+KolourPaint is opensource software written in C++ using the Qt and KDE
+libraries.
+
+
+2. Features
+===========
+
+* Undo/Redo Support (10-500 levels of history depending on memory usage)
+
+* Tools (single key shortcuts available for all tools)
+ - Brush, Color Eraser, Color Picker, Connected Lines a.k.a. Polyline
+ - Curve, Ellipse, Eraser, Flood Fill, Line, Pen, Polygon, Rectangle
+ - Rounded Rectangle, Spraycan, Text
+
+* Selections (fully undo- and redo-able)
+ - Rectangular, Elliptical, Free-Form shapes
+ - Choice between Opaque and Transparent selections
+ - Full Clipboard/Edit Menu support
+ - Freehand resizeable
+
+* Colour Similarity means that you can fill regions in dithered images and
+ photos
+
+* Transparency
+ - Draw transparent icons and logos on a checkerboard background
+ - All tools can draw in the "Transparent Colour"
+
+* Image Effects
+ - Autocrop / Remove Internal Border
+ - Balance (Brightness, Contrast, Gamma)
+ - Clear, Emboss, Flatten, Flip, Invert (with choice of channels)
+ - Reduce Colours, Reduce to Greyscale, Resize, Rotate
+ - Scale, Set as Image (Crop), Skew, Smooth Scale, Soften & Sharpen
+
+* Close-up Editing
+ - Zoom (from 0.01x to 16x)
+ - Grid
+ - Thumbnail
+
+* File Operations
+ - Open/Save in all file formats provided by KImageIO
+ (PNG, JPEG, BMP, ICO, PCX, TIFF,...) with preview
+ - Print, Print Preview
+ - Mail
+ - Set as Wallpaper
+
+
+3. Updates & More Information
+=============================
+
+Visit: http://www.kolourpaint.org/
+
+
+4. Support
+==========
+
+Visit: http://www.kolourpaint.org/
+
+If you have any questions about compiling, installing or using KolourPaint,
+don't be afraid to contact us. We try to support all versions of
+KolourPaint and even issues with 3rd party binary packages.
+
+
+5. Feedback
+===========
+
+Please send bug reports and feature requests to http://bugs.kde.org/.
+Don't hesitate to report bugs nor hesitate to send us your wishes - it
+provides valuable feedback that will help to improve future versions of
+KolourPaint and you will not receive flames for reporting duplicates.
+
diff --git a/kolourpaint/VERSION b/kolourpaint/VERSION
new file mode 100644
index 00000000..8b2f0f9b
--- /dev/null
+++ b/kolourpaint/VERSION
@@ -0,0 +1 @@
+1.4.8_relight-post
diff --git a/kolourpaint/cursors/Makefile.am b/kolourpaint/cursors/Makefile.am
new file mode 100644
index 00000000..5ae0504a
--- /dev/null
+++ b/kolourpaint/cursors/Makefile.am
@@ -0,0 +1,11 @@
+INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../cursors -I$(srcdir)/../interfaces \
+ -I$(srcdir)/../pixmapfx \
+ -I$(srcdir)/../tools \
+ -I$(srcdir)/../views \
+ -I$(srcdir)/../widgets $(all_includes)
+
+noinst_LTLIBRARIES = libkolourpaintcursors.la
+libkolourpaintcursors_la_SOURCES = kpcursorlightcross.cpp kpcursorprovider.cpp
+
+METASOURCES = AUTO
+
diff --git a/kolourpaint/cursors/kpcursorlightcross.cpp b/kolourpaint/cursors/kpcursorlightcross.cpp
new file mode 100644
index 00000000..0595d320
--- /dev/null
+++ b/kolourpaint/cursors/kpcursorlightcross.cpp
@@ -0,0 +1,128 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_CURSOR_LIGHT_CROSS 0
+
+
+#include <kpcursorlightcross.h>
+
+#include <qbitmap.h>
+#include <qcursor.h>
+
+#include <kdebug.h>
+
+
+enum PixelValue
+{
+ White, Black, Transparent
+};
+
+static void setPixel (unsigned char *colorBitmap,
+ unsigned char *maskBitmap,
+ int width,
+ int y, int x, enum PixelValue pv)
+{
+ const int ColorBlack = 1;
+ const int ColorWhite = 0;
+
+ const int MaskOpaque = 1;
+ const int MaskTransparent = 0;
+
+ int colorValue, maskValue;
+
+ switch (pv)
+ {
+ case White:
+ colorValue = ColorWhite;
+ maskValue = MaskOpaque;
+ break;
+
+ case Black:
+ colorValue = ColorBlack;
+ maskValue = MaskOpaque;
+ break;
+
+ case Transparent:
+ default:
+ colorValue = ColorWhite;
+ maskValue = MaskTransparent;
+ break;
+ }
+
+ if (colorValue)
+ colorBitmap [y * (width / 8) + (x / 8)] |= (1 << (x % 8));
+
+ if (maskValue)
+ maskBitmap [y * (width / 8) + (x / 8)] |= (1 << (x % 8));
+}
+
+
+const QCursor *kpMakeCursorLightCross ()
+{
+#if DEBUG_KP_CURSOR_LIGHT_CROSS
+ kdDebug () << "kpMakeCursorLightCross() " << endl;
+#endif
+
+ const int side = 24;
+ const int byteSize = (side * side) / 8;
+ unsigned char *colorBitmap = new unsigned char [byteSize];
+ unsigned char *maskBitmap = new unsigned char [byteSize];
+
+ memset (colorBitmap, 0, byteSize);
+ memset (maskBitmap, 0, byteSize);
+
+ const int oddSide = side - 1;
+ const int strokeLen = oddSide * 3 / 8;
+
+ for (int i = 0; i < strokeLen; i++)
+ {
+ const enum PixelValue pv = (i % 2) ? Black : White;
+
+ #define X_(val) (val)
+ #define Y_(val) (val)
+ #define DRAW(y,x) setPixel (colorBitmap, maskBitmap, side, (y), (x), pv)
+ // horizontal
+ DRAW (Y_(side / 2), X_(1 + i));
+ DRAW (Y_(side / 2), X_(side - 1 - i));
+
+ // vertical
+ DRAW (Y_(1 + i), X_(side / 2));
+ DRAW (Y_(side - 1 - i), X_(side / 2));
+ #undef DRAW
+ #undef Y_
+ #undef X_
+ }
+
+ QCursor *cursor = new QCursor (QBitmap (side, side, colorBitmap, true/*little endian bit order*/),
+ QBitmap (side, side, maskBitmap, true/*little endian bit order*/));
+
+ delete [] maskBitmap;
+ delete [] colorBitmap;
+
+ return cursor;
+}
+
diff --git a/kolourpaint/cursors/kpcursorlightcross.h b/kolourpaint/cursors/kpcursorlightcross.h
new file mode 100644
index 00000000..d2bf83e1
--- /dev/null
+++ b/kolourpaint/cursors/kpcursorlightcross.h
@@ -0,0 +1,38 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kp_cursor_light_cross_h__
+#define __kp_cursor_light_cross_h__
+
+
+class QCursor;
+
+const QCursor *kpMakeCursorLightCross ();
+
+
+#endif // __kp_cursor_light_cross_h__
diff --git a/kolourpaint/cursors/kpcursorprovider.cpp b/kolourpaint/cursors/kpcursorprovider.cpp
new file mode 100644
index 00000000..45d43801
--- /dev/null
+++ b/kolourpaint/cursors/kpcursorprovider.cpp
@@ -0,0 +1,49 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <kpcursorprovider.h>
+
+#include <qcursor.h>
+
+#include <kstaticdeleter.h>
+
+#include <kpcursorlightcross.h>
+
+
+static const QCursor *theLightCursor = 0;
+
+
+// public static
+QCursor kpCursorProvider::lightCross ()
+{
+ // TODO: don't leak (although it's cleaned up on exit by OS anyway)
+ if (!theLightCursor)
+ theLightCursor = kpMakeCursorLightCross ();
+
+ return *theLightCursor;
+}
diff --git a/kolourpaint/cursors/kpcursorprovider.h b/kolourpaint/cursors/kpcursorprovider.h
new file mode 100644
index 00000000..191b4f78
--- /dev/null
+++ b/kolourpaint/cursors/kpcursorprovider.h
@@ -0,0 +1,43 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kp_cursor_provider_h__
+#define __kp_cursor_provider_h__
+
+
+class QCursor;
+
+
+class kpCursorProvider
+{
+public:
+ static QCursor lightCross ();
+};
+
+
+#endif // __kp_cursor_provider_h__
diff --git a/kolourpaint/kolourpaint.cpp b/kolourpaint/kolourpaint.cpp
new file mode 100644
index 00000000..b9ba0f0c
--- /dev/null
+++ b/kolourpaint/kolourpaint.cpp
@@ -0,0 +1,229 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <qfile.h>
+
+#include <dcopclient.h>
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kdebug.h>
+#include <kimageio.h>
+#include <klocale.h>
+
+// for srand
+#include <stdlib.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <kpdefs.h>
+#include <kpmainwindow.h>
+
+#include <kolourpaintlicense.h>
+#include <kolourpaintversion.h>
+
+
+static const KCmdLineOptions cmdLineOptions [] =
+{
+ {"+[file]", I18N_NOOP ("Image file to open"), 0},
+ KCmdLineLastOption
+};
+
+
+int main (int argc, char *argv [])
+{
+ KAboutData aboutData
+ (
+ "kolourpaint",
+ I18N_NOOP ("KolourPaint"),
+ kpVersionText,
+ I18N_NOOP ("Paint Program for KDE"),
+ KAboutData::License_Custom,
+ 0/*copyright statement - see licence instead*/,
+ 0/*no free text*/,
+ "http://www.kolourpaint.org/"
+ );
+
+
+ // this is _not_ the same as KAboutData::License_BSD
+ aboutData.setLicenseText (kpLicenseText);
+
+
+ // SYNC: with AUTHORS
+
+ aboutData.addAuthor ("Clarence Dang", I18N_NOOP ("Maintainer"), "dang@kde.org");
+ aboutData.addAuthor ("Thurston Dang", I18N_NOOP ("Chief Investigator"),
+ "thurston_dang@users.sourceforge.net");
+ aboutData.addAuthor ("Kristof Borrey", I18N_NOOP ("Icons"), "borrey@kde.org");
+ aboutData.addAuthor ("Kazuki Ohta", I18N_NOOP ("InputMethod Support"), "mover@hct.zaq.ne.jp");
+ aboutData.addAuthor ("Nuno Pinheiro", I18N_NOOP ("Icons"), "nf.pinheiro@gmail.com");
+ aboutData.addAuthor ("Danny Allen", I18N_NOOP ("Icons"), "dannya40uk@yahoo.co.uk");
+ aboutData.addAuthor ("Martin Koller",
+ 0/*STRING: string freeze prevents us from writing: Scanning Support*/,
+ "m.koller@surfeu.at");
+
+
+ aboutData.addCredit ("Rashid N. Achilov");
+ aboutData.addCredit ("Toyohiro Asukai");
+ aboutData.addCredit ("Bela-Andreas Bargel");
+ aboutData.addCredit ("Waldo Bastian");
+ aboutData.addCredit ("Ismail Belhachmi");
+ aboutData.addCredit ("Sashmit Bhaduri");
+ aboutData.addCredit ("Antonio Bianco");
+ aboutData.addCredit ("Stephan Binner");
+ aboutData.addCredit ("Markus Brueffer");
+ aboutData.addCredit ("Rob Buis");
+ aboutData.addCredit ("Lucijan Busch");
+ aboutData.addCredit ("Mikhail Capone");
+ aboutData.addCredit ("Enrico Ceppi");
+ aboutData.addCredit ("Tom Chance");
+ aboutData.addCredit ("Albert Astals Cid");
+ aboutData.addCredit ("Jennifer Dang");
+ aboutData.addCredit ("Lawrence Dang");
+ aboutData.addCredit ("Christoph Eckert");
+ aboutData.addCredit ("David Faure");
+ aboutData.addCredit ("P. Fisher");
+ aboutData.addCredit ("Nicolas Goutte");
+ aboutData.addCredit ("Herbert Graeber");
+ aboutData.addCredit ("Brad Grant");
+ aboutData.addCredit ("David Greenaway");
+ aboutData.addCredit ("Wilco Greven");
+ aboutData.addCredit ("Hubert Grininger");
+ aboutData.addCredit ("Adriaan de Groot");
+ aboutData.addCredit ("Esben Mose Hansen");
+ aboutData.addCredit ("Nadeem Hasan");
+ aboutData.addCredit ("Simon Hausmann");
+ aboutData.addCredit ("Michael Hoehne");
+ aboutData.addCredit ("Andrew J");
+ aboutData.addCredit ("Werner Joss");
+ aboutData.addCredit ("Derek Kite");
+ aboutData.addCredit ("Tobias Koenig");
+ aboutData.addCredit ("Dmitry Kolesnikov");
+ aboutData.addCredit ("Stephan Kulow");
+ aboutData.addCredit ("Eric Laffoon");
+ aboutData.addCredit ("Michael Lake");
+ aboutData.addCredit ("Sebastien Laout");
+ aboutData.addCredit ("David Ling");
+ aboutData.addCredit ("Volker Lochte");
+ aboutData.addCredit ("Anders Lund");
+ aboutData.addCredit ("Jacek Masiulaniec");
+ aboutData.addCredit ("Benjamin Meyer");
+ aboutData.addCredit ("Amir Michail");
+ aboutData.addCredit ("Robert Moszczynski");
+ aboutData.addCredit ("Dirk Mueller");
+ aboutData.addCredit ("Ruivaldo Neto");
+ aboutData.addCredit ("Ralf Nolden");
+ aboutData.addCredit ("Steven Pasternak");
+ aboutData.addCredit ("Cédric Pasteur");
+ aboutData.addCredit ("Erik K. Pedersen");
+ aboutData.addCredit ("Dennis Pennekamp");
+ aboutData.addCredit ("Jos Poortvliet");
+ aboutData.addCredit ("Boudewijn Rempt");
+ aboutData.addCredit ("Marcos Rodriguez");
+ aboutData.addCredit ("Matt Rogers");
+ aboutData.addCredit ("Francisco Jose Canizares Santofimia");
+ aboutData.addCredit ("Bram Schoenmakers");
+ aboutData.addCredit ("Dirk Schönberger");
+ aboutData.addCredit ("Lutz Schweizer");
+ aboutData.addCredit ("Emmeran Seehuber");
+ aboutData.addCredit ("Peter Simonsson");
+ aboutData.addCredit ("Andrew Simpson");
+ aboutData.addCredit ("A T Somers");
+ aboutData.addCredit ("Igor Stepin");
+ aboutData.addCredit ("Stephen Sweeney");
+ aboutData.addCredit ("Bart Symons");
+ aboutData.addCredit ("Stefan Taferner");
+ aboutData.addCredit ("Hogne Titlestad");
+ aboutData.addCredit ("Brandon Mark Turner");
+ aboutData.addCredit ("Jonathan Turner");
+ aboutData.addCredit ("Stephan Unknown");
+ aboutData.addCredit ("Dries Verachtert");
+ aboutData.addCredit ("Simon Vermeersch");
+ aboutData.addCredit ("Lauri Watts");
+ aboutData.addCredit ("Mark Wege");
+ aboutData.addCredit ("Christoph Wiesen");
+ aboutData.addCredit ("Andre Wobbeking");
+ aboutData.addCredit ("Luke-Jr");
+ aboutData.addCredit ("Maxim_86ualb2");
+ aboutData.addCredit ("Michele");
+
+
+ KCmdLineArgs::init (argc, argv, &aboutData);
+ KCmdLineArgs::addCmdLineOptions (cmdLineOptions);
+
+ KApplication app;
+
+
+ // mainly for changing wallpaper :)
+ DCOPClient *client = app.dcopClient ();
+ if (!client->attach ())
+ kdError () << "Could not contact DCOP server" << endl;
+
+ // mainly for the Spraycan Tool
+ srand ((unsigned int) (getpid () + getppid ()));
+
+ // access more formats
+ KImageIO::registerFormats ();
+
+
+ // Qt says this is necessary but I don't think it is...
+ QObject::connect (&app, SIGNAL (lastWindowClosed ()),
+ &app, SLOT (quit ()));
+
+
+ if (app.isRestored ())
+ {
+ // Creates a kpMainWindow using the default constructor and then
+ // calls kpMainWindow::readProperties().
+ RESTORE (kpMainWindow)
+ }
+ else
+ {
+ kpMainWindow *mainWindow;
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs ();
+
+ if (args->count () >= 1)
+ {
+ for (int i = 0; i < args->count (); i++)
+ {
+ mainWindow = new kpMainWindow (args->url (i));
+ mainWindow->show ();
+ }
+ }
+ else
+ {
+ mainWindow = new kpMainWindow ();
+ mainWindow->show ();
+ }
+
+ args->clear ();
+ }
+
+
+ return app.exec ();
+}
diff --git a/kolourpaint/kolourpaint.desktop b/kolourpaint/kolourpaint.desktop
new file mode 100644
index 00000000..8a586219
--- /dev/null
+++ b/kolourpaint/kolourpaint.desktop
@@ -0,0 +1,92 @@
+[Desktop Entry]
+
+Name=KolourPaint
+Name[nb]=KPaint
+Name[ne]=रङ पेन्ट
+Name[pa]=ਕੇ-ਰੰਗ-ਪੇਂਟ
+Name[sv]=Kolourpaint
+Name[ta]=நிற பெயின்ட்
+Name[zh_TW]=KolourPaint 小畫家
+GenericName=Paint Program
+GenericName[af]=Verf Program
+GenericName[ar]=برنامج تلوين
+GenericName[bg]=Графичен редактор
+GenericName[br]=Goulev tresañ
+GenericName[bs]=Jednostavni program za crtanje
+GenericName[ca]=Programa de pintura
+GenericName[cs]=Kreslící program
+GenericName[cy]=Rhaglen Peintio
+GenericName[da]=Maleprogram
+GenericName[de]=Mal- und Zeichenprogramm
+GenericName[el]=Πρόγραμμα ζωγραφικής
+GenericName[eo]=Pentrilo
+GenericName[es]=Programa de pintura
+GenericName[et]=Joonistusprogramm
+GenericName[eu]=Marrazteko programa
+GenericName[fa]=برنامۀ رنگ
+GenericName[fi]=Piirto-ohjelma
+GenericName[fr]=Petit programme de dessin
+GenericName[ga]=Clár Péinteála
+GenericName[gl]=Programa de debuxo
+GenericName[he]=תוכנית ציור
+GenericName[hi]=छवि बनाने का प्रोग्राम
+GenericName[hr]=Program za slikanje
+GenericName[hu]=Rajzolóprogram
+GenericName[is]=Teikniforrit
+GenericName[it]=Programma di disegno
+GenericName[ja]=ペイントプログラム
+GenericName[kk]=Сурет салу бағдарламасы
+GenericName[km]=កម្មវិធី​គូរ
+GenericName[lt]=Piešimo programa
+GenericName[lv]=Krāsošanas Programma
+GenericName[ms]=Program Mewarna
+GenericName[mt]=Programm sempliċi tat-tpinġija
+GenericName[nb]=Maleprogram
+GenericName[nds]=Maalprogramm
+GenericName[ne]=पेन्ट कार्यक्रम
+GenericName[nl]=Tekenprogramma
+GenericName[nn]=Måleprogram
+GenericName[nso]=Lenaneo la Paint
+GenericName[pa]=ਰੰਗ ਕਾਰਜ
+GenericName[pl]=Program Paint
+GenericName[pt]=Programa de Pintura
+GenericName[pt_BR]=Programa de Pintura
+GenericName[ro]=Program de desenare
+GenericName[ru]=Графический редактор
+GenericName[rw]=Porogaramu Gusiga irangi
+GenericName[se]=Málenprográmma
+GenericName[sk]=Kreslenie
+GenericName[sl]=Slikarski program
+GenericName[sr]=Програм за сликање
+GenericName[sr@Latn]=Program za slikanje
+GenericName[sv]=Ritprogram
+GenericName[ta]=பெயிண்ட் நிரலி
+GenericName[tg]=Муҳаррири графикӣ
+GenericName[th]=โปรแกรมวาดภาพธรรมดาๆ
+GenericName[tr]=Boyama Programı
+GenericName[uk]=Програма для малювання
+GenericName[uz]=Chizish dasturi
+GenericName[uz@cyrillic]=Чизиш дастури
+GenericName[ven]=Mbekanyamushumo ya Pennde
+GenericName[wa]=Program di dessinaedje
+GenericName[xh]=Udweliso lwenkqubo lwepeyinti
+GenericName[zh_CN]=绘图程序
+GenericName[zh_HK]=繪圖程式
+GenericName[zh_TW]=繪圖程式
+GenericName[zu]=Elila Iprogremu Kapende
+Icon=kolourpaint
+
+Type=Application
+Exec=kolourpaint %u
+DocPath=kolourpaint/index.html
+
+# SYNC: Run branches/kolourpaint/control/scripts/gen_mimetype_line.sh in
+# the version of kdelibs/kimgio/ (e.g. KDE 3.5) KolourPaint is
+# shipped with.
+MimeType=image/fax-g3;image/gif;image/jp2;image/jpeg;image/png;image/tiff;image/x-bmp;image/x-dds;image/x-eps;image/x-exr;image/x-hdr;image/x-ico;image/x-pcx;image/x-portable-bitmap;image/x-portable-greymap;image/x-portable-pixmap;image/x-rgb;image/x-targa;image/x-vnd.adobe.photoshop;image/x-xbm;image/x-xcf-gimp;image/x-xpm;video/x-mng;
+
+Categories=Qt;KDE;Graphics;
+Terminal=false
+X-KDE-StartupNotify=true
+X-DCOP-ServiceType=Multi
+
diff --git a/kolourpaint/kolourpaintui.rc b/kolourpaint/kolourpaintui.rc
new file mode 100644
index 00000000..876c3e38
--- /dev/null
+++ b/kolourpaint/kolourpaintui.rc
@@ -0,0 +1,169 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<!--
+SYNC: Do not change the number of quotes before the version number
+ - it is parsed by the KolourPaint wrapper shell script (in standalone
+ backport releases of KolourPaint)
+-->
+<gui name="kolourpaint" version="25">
+
+<!--
+SYNC: Check for duplicate actions in menus caused by some of our actions
+ being added to ui_standards.rc. Makes me wonder why we are using
+ merging in the first place.
+-->
+
+<MenuBar>
+ <Menu name="file">
+ <!-- <Action name="file_new_window" append="new_merge" /> -->
+
+ <Action name="file_scan" append="open_merge" />
+
+ <Action name="file_export" append="save_merge" />
+ <Separator append="save_merge" />
+
+ <Action name="file_set_as_wallpaper_centered" />
+ <Action name="file_set_as_wallpaper_tiled" />
+ </Menu>
+
+ <Menu name="edit">
+ <Action name="edit_paste_in_new_window" append="edit_paste_merge" />
+
+ <Action name="edit_copy_to_file" />
+ <Action name="edit_paste_from_file" />
+ </Menu>
+
+ <!-- SRC: ui_standards.rc v10 (KDE 3.3) -->
+ <Menu name="view" noMerge="1"><text>&amp;View</text>
+ <Action name="view_actual_size"/>
+ <Action name="view_fit_to_page"/>
+ <Action name="view_fit_to_width"/>
+ <Action name="view_fit_to_height"/>
+
+ <Separator />
+
+ <!-- <MergeLocal name="view_zoom_merge"/> -->
+ <Action name="view_zoom_in"/>
+
+ <!-- Changed from "view_zoom" to allow custom ordering of zoom
+ actions in "mainToolBar" (which has a hardcoded position for
+ "view_zoom").
+ -->
+ <Action name="view_zoom_to"/>
+
+ <Action name="view_zoom_out"/>
+
+ <WeakSeparator/>
+
+ <Action name="view_redisplay"/>
+
+ <Separator/>
+
+ <!-- <MergeLocal/> -->
+ <Action name="view_show_grid" />
+ <Action name="view_show_thumbnail" />
+
+ <Separator/>
+
+ <Action name="view_zoomed_thumbnail" />
+ <Action name="view_show_thumbnail_rectangle" />
+ </Menu>
+
+ <Menu name="image"><text>&amp;Image</text>
+ <Action name="image_crop" />
+ <Action name="image_auto_crop" />
+ <Separator />
+ <Action name="image_resize_scale" />
+ <Action name="image_flip" />
+ <Action name="image_rotate" />
+ <Action name="image_skew" />
+ <Separator />
+ <Action name="image_convert_to_black_and_white" />
+ <Action name="image_convert_to_grayscale" />
+ <Action name="image_more_effects" />
+ <Separator />
+ <Action name="image_invert_colors" />
+ <Action name="image_clear" />
+ </Menu>
+
+ <Menu name="settings">
+ <Action name="settings_show_path" append="show_merge" />
+ </Menu>
+
+ <Menu name="help">
+ <Action name="help_taking_screenshots" />
+ </Menu>
+
+</MenuBar>
+
+<ToolBar name="mainToolBar">
+ <Action name="view_zoom_in" />
+ <Action name="view_zoom_out" />
+ <Action name="view_zoom_to" />
+</ToolBar>
+
+<ToolBar name="textToolBar" fullWidth="false" position="top" hidden="true"><text>Text Toolbar</text>
+ <Action name="text_font_family" />
+ <Action name="text_font_size" />
+ <Separator />
+ <Action name="text_bold" />
+ <Action name="text_italic" />
+ <Action name="text_underline" />
+ <Action name="text_strike_thru" />
+</ToolBar>
+
+<Menu name="selectionToolRMBMenu"><text>Selection Tool RMB Menu</text>
+ <!-- SRC: ui_standards.rc v10 (KDE 3.3) -->
+ <!-- <Menu name="edit"><text>&amp;Edit</text> -->
+
+ <!-- <Action name="edit_undo"/>
+ <Action name="edit_redo"/>
+ <MergeLocal name="edit_undo_merge"/>
+ <Separator/> -->
+ <Action name="edit_cut"/>
+ <Action name="edit_copy"/>
+ <Action name="edit_paste"/>
+ <!-- CUSTOM --> <!-- <Action name="edit_paste_in_new_window" /> -->
+ <MergeLocal name="edit_paste_merge"/>
+ <Action name="edit_clear"/>
+ <!-- <Separator/> -->
+ <Action name="edit_select_all"/>
+ <!-- <Action name="edit_deselect"/> -->
+ <MergeLocal name="edit_select_merge"/>
+ <Separator/>
+ <Action name="edit_find"/>
+ <Action name="edit_find_next"/>
+ <Action name="edit_find_last"/>
+ <Action name="edit_replace"/>
+ <MergeLocal name="edit_find_merge"/>
+ <Separator/>
+ <!-- CUSTOM --> <Action name="edit_copy_to_file" />
+ <!-- CUSTOM --> <Action name="edit_paste_from_file" />
+ <MergeLocal/>
+
+ <!-- </Menu> -->
+
+
+ <Separator/>
+
+
+ <!-- <Menu name="image"><text>&amp;Image</text> -->
+
+ <Action name="image_crop" />
+ <!-- <Action name="image_auto_crop" /> -->
+ <Separator />
+ <Action name="image_resize_scale" />
+ <Action name="image_flip" />
+ <Action name="image_rotate" />
+ <Action name="image_skew" />
+ <Separator />
+ <!-- <Action name="image_convert_to_black_and_white" /> -->
+ <!-- <Action name="image_convert_to_grayscale" /> -->
+ <!-- <Action name="image_more_effects" /> -->
+ <!-- <Separator /> -->
+ <Action name="image_invert_colors" />
+ <!-- <Action name="image_clear" /> -->
+
+ <!-- </Menu> -->
+</Menu>
+
+</gui>
diff --git a/kolourpaint/kpcolor.cpp b/kolourpaint/kpcolor.cpp
new file mode 100644
index 00000000..a9dc000b
--- /dev/null
+++ b/kolourpaint/kpcolor.cpp
@@ -0,0 +1,360 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_COLOR 0
+
+
+#include <kpcolor.h>
+
+#include <qdatastream.h>
+
+#include <kdebug.h>
+
+
+// public static
+const int kpColor::Exact = 0;
+
+// public static
+const kpColor kpColor::invalid; // TODO: what's wrong with explicitly specifying () constructor?
+const kpColor kpColor::transparent (0, 0, 0, true/*isTransparent*/);
+
+
+kpColor::kpColor ()
+ : m_rgbaIsValid (false),
+ m_colorCacheIsValid (false)
+{
+}
+
+kpColor::kpColor (int red, int green, int blue, bool isTransparent)
+ : m_colorCacheIsValid (false)
+{
+ if (red < 0 || red > 255 ||
+ green < 0 || green > 255 ||
+ blue < 0 || blue > 255)
+ {
+ kdError () << "kpColor::<ctor>(r=" << red
+ << ",g=" << green
+ << ",b=" << blue
+ << ",t=" << isTransparent
+ << ") passed out of range values" << endl;
+ m_rgbaIsValid = false;
+ return;
+ }
+
+ m_rgba = qRgba (red, green, blue, isTransparent ? 0 : 255/*opaque*/);
+ m_rgbaIsValid = true;
+}
+
+kpColor::kpColor (const QRgb &rgba)
+ : m_colorCacheIsValid (false)
+{
+ if (qAlpha (rgba) > 0 && qAlpha (rgba) < 255)
+ {
+ kdError () << "kpColor::<ctor>(QRgb) passed translucent alpha "
+ << qAlpha (rgba)
+ << " - trying to recover"
+ << endl;
+
+ // Forget the alpha channel - make it opaque
+ m_rgba = qRgb (qRed (m_rgba), qGreen (m_rgba), qBlue (m_rgba));
+ m_rgbaIsValid = true;
+ }
+ else
+ {
+ m_rgba = rgba;
+ m_rgbaIsValid = true;
+ }
+}
+
+kpColor::kpColor (const kpColor &rhs)
+ : m_rgbaIsValid (rhs.m_rgbaIsValid),
+ m_rgba (rhs.m_rgba),
+ m_colorCacheIsValid (rhs.m_colorCacheIsValid),
+ m_colorCache (rhs.m_colorCache)
+{
+}
+
+// friend
+QDataStream &operator<< (QDataStream &stream, const kpColor &color)
+{
+ stream << int (color.m_rgbaIsValid) << int (color.m_rgba);
+
+ return stream;
+}
+
+// friend
+QDataStream &operator>> (QDataStream &stream, kpColor &color)
+{
+ int a, b;
+ stream >> a >> b;
+ color.m_rgbaIsValid = a;
+ color.m_rgba = b;
+
+ color.m_colorCacheIsValid = false;
+
+ return stream;
+}
+
+kpColor &kpColor::operator= (const kpColor &rhs)
+{
+ // (as soon as you add a ptr, you won't be complaining to me that this
+ // method was unnecessary :))
+
+ if (this == &rhs)
+ return *this;
+
+ m_rgbaIsValid = rhs.m_rgbaIsValid;
+ m_rgba = rhs.m_rgba;
+ m_colorCacheIsValid = rhs.m_colorCacheIsValid;
+ m_colorCache = rhs.m_colorCache;
+
+ return *this;
+}
+
+bool kpColor::operator== (const kpColor &rhs) const
+{
+ return isSimilarTo (rhs, kpColor::Exact);
+}
+
+bool kpColor::operator!= (const kpColor &rhs) const
+{
+ return !(*this == rhs);
+}
+
+
+template <class dtype>
+inline dtype square (dtype val)
+{
+ return val * val;
+}
+
+// public static
+int kpColor::processSimilarity (double colorSimilarity)
+{
+ // sqrt (dr ^ 2 + dg ^ 2 + db ^ 2) <= colorSimilarity * sqrt (255 ^ 2 * 3)
+ // dr ^ 2 + dg ^ 2 + db ^ 2 <= (colorSimilarity ^ 2) * (255 ^ 2 * 3)
+
+ return int (square (colorSimilarity) * (square (255) * 3));
+}
+
+bool kpColor::isSimilarTo (const kpColor &rhs, int processedSimilarity) const
+{
+ // Are we the same?
+ if (this == &rhs)
+ return true;
+
+
+ // Do we dither in terms of validity?
+ if (isValid () != rhs.isValid ())
+ return false;
+
+ // Are both of us invalid?
+ if (!isValid ())
+ return true;
+
+ // --- both are now valid ---
+
+
+ if (isTransparent () != rhs.isTransparent ())
+ return false;
+
+ // Are both of us transparent?
+ if (isTransparent ())
+ return true;
+
+ // --- both are now valid and opaque ---
+
+
+ if (m_rgba == rhs.m_rgba)
+ return true;
+
+
+ if (processedSimilarity == kpColor::Exact)
+ return false;
+ else
+ {
+ return (square (qRed (m_rgba) - qRed (rhs.m_rgba)) +
+ square (qGreen (m_rgba) - qGreen (rhs.m_rgba)) +
+ square (qBlue (m_rgba) - qBlue (rhs.m_rgba))
+ <= processedSimilarity);
+ }
+}
+
+kpColor::~kpColor ()
+{
+}
+
+
+// public
+bool kpColor::isValid () const
+{
+ return m_rgbaIsValid;
+}
+
+
+// public
+int kpColor::red () const
+{
+ if (!m_rgbaIsValid)
+ {
+ kdError () << "kpColor::red() called with invalid kpColor" << endl;
+ return 0;
+ }
+
+ if (isTransparent ())
+ {
+ kdError () << "kpColor::red() called with transparent kpColor" << endl;
+ return 0;
+ }
+
+ return qRed (m_rgba);
+}
+
+// public
+int kpColor::green () const
+{
+ if (!m_rgbaIsValid)
+ {
+ kdError () << "kpColor::green() called with invalid kpColor" << endl;
+ return 0;
+ }
+
+ if (isTransparent ())
+ {
+ kdError () << "kpColor::green() called with transparent kpColor" << endl;
+ return 0;
+ }
+
+ return qGreen (m_rgba);
+}
+
+// public
+int kpColor::blue () const
+{
+ if (!m_rgbaIsValid)
+ {
+ kdError () << "kpColor::blue() called with invalid kpColor" << endl;
+ return 0;
+ }
+
+ if (isTransparent ())
+ {
+ kdError () << "kpColor::blue() called with transparent kpColor" << endl;
+ return 0;
+ }
+
+ return qBlue (m_rgba);
+}
+
+// public
+int kpColor::alpha () const
+{
+ if (!m_rgbaIsValid)
+ {
+ kdError () << "kpColor::alpha() called with invalid kpColor" << endl;
+ return 0;
+ }
+
+ const int alpha = qAlpha (m_rgba);
+
+ if (alpha > 0 && alpha < 255)
+ {
+ kdError () << "kpColor::alpha() called with translucent kpColor alpha=" << alpha << endl;
+
+ // no translucency
+ return alpha ? 255 : 0;
+ }
+ else
+ {
+ return alpha;
+ }
+}
+
+// public
+bool kpColor::isTransparent () const
+{
+ return (alpha () == 0);
+}
+
+// public
+bool kpColor::isOpaque () const
+{
+ return (alpha () == 255);
+}
+
+
+// public
+QRgb kpColor::toQRgb () const
+{
+ if (!m_rgbaIsValid)
+ {
+ kdError () << "kpColor::toQRgb() called with invalid kpColor" << endl;
+ return 0;
+ }
+
+ return m_rgba;
+}
+
+// public
+const QColor &kpColor::toQColor () const
+{
+ if (!m_rgbaIsValid)
+ {
+ kdError () << "kpColor::toQColor() called with invalid kpColor" << endl;
+ return Qt::black;
+ }
+
+ if (m_colorCacheIsValid)
+ return m_colorCache;
+
+ if (qAlpha (m_rgba) < 255)
+ {
+ kdError () << "kpColor::toQColor() called with not fully opaque kpColor alpha="
+ << qAlpha (m_rgba)
+ << endl;
+ return Qt::black;
+ }
+
+ m_colorCache = QColor (m_rgba);
+ if (!m_colorCache.isValid ())
+ {
+ kdError () << "kpColor::toQColor () internal error - could not return valid QColor"
+ << endl;
+ return Qt::black;
+ }
+
+ m_colorCacheIsValid = true;
+
+ return m_colorCache;
+}
+
+// public
+QColor kpColor::maskColor () const
+{
+ return isTransparent () ? Qt::color0 : Qt::color1;
+}
diff --git a/kolourpaint/kpcolor.h b/kolourpaint/kpcolor.h
new file mode 100644
index 00000000..131d4b61
--- /dev/null
+++ b/kolourpaint/kpcolor.h
@@ -0,0 +1,101 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kp_color_h__
+#define __kp_color_h__
+
+
+#include <qcolor.h>
+
+class QDataStream;
+
+
+//
+// kpColor is an object-oriented abstraction of QRgb, with the additional
+// restriction of following the KolourPaint convention of only supporting
+// totally transparent and totally opaque colors. It also provides better
+// error handling, reporting (noisy kdError()'s) and recovery.
+//
+// In general, you should pass around kpColor objects instead of QRgb
+// and QColor. Only convert an opaque kpColor to a QColor (using toQColor())
+// if you need to draw something onscreen. Constructing a kpColor object
+// from QColor is probably wrong since onscreen representations of color
+// are not guaranteed to be faithful (due to QColor color allocation).
+//
+class kpColor
+{
+public:
+ kpColor ();
+ kpColor (int red, int green, int blue, bool isTransparent = false);
+ kpColor (const QRgb &rgba);
+ kpColor (const kpColor &rhs);
+ friend QDataStream &operator<< (QDataStream &stream, const kpColor &color);
+ friend QDataStream &operator>> (QDataStream &stream, kpColor &color);
+ kpColor &operator= (const kpColor &rhs);
+ bool operator== (const kpColor &rhs) const;
+ bool operator!= (const kpColor &rhs) const;
+
+ static int processSimilarity (double colorSimilarity);
+ static const int Exact; // "isSimilarTo (rhs, kpColor::Exact)" == "== rhs"
+ // Usage: isSimilarTo (rhs, kpColor::processSimilarity (.1)) checks for
+ // Color Similarity within 10%
+ bool isSimilarTo (const kpColor &rhs, int processedSimilarity) const;
+ ~kpColor ();
+
+ static const kpColor invalid;
+ static const kpColor transparent;
+
+ bool isValid () const;
+
+ int red () const;
+ int green () const;
+ int blue () const;
+ int alpha () const;
+ bool isTransparent () const;
+ bool isOpaque () const;
+
+ // Cast operators will most likely result in careless conversions so
+ // use explicit functions instead:
+ QRgb toQRgb () const;
+
+ // (only valid if isOpaque())
+ // (const QColor & return results in fewer color reallocations)
+ const QColor &toQColor () const;
+
+ QColor maskColor () const;
+
+private:
+ bool m_rgbaIsValid;
+ QRgb m_rgba;
+
+ mutable bool m_colorCacheIsValid;
+ mutable QColor m_colorCache;
+};
+
+
+#endif // __kp_color_h__
diff --git a/kolourpaint/kpcommandhistory.cpp b/kolourpaint/kpcommandhistory.cpp
new file mode 100644
index 00000000..33010918
--- /dev/null
+++ b/kolourpaint/kpcommandhistory.cpp
@@ -0,0 +1,939 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_COMMAND_HISTORY 0
+
+
+#include <kpcommandhistory.h>
+
+#include <limits.h>
+
+#include <qdatetime.h>
+
+#include <kactionclasses.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kpopupmenu.h>
+#include <kstdaccel.h>
+#include <kstdaction.h>
+
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kptool.h>
+
+
+//template <typename T>
+static void clearPointerList (QValueList <kpCommand *> *listPtr)
+{
+ if (!listPtr)
+ return;
+
+ for (QValueList <kpCommand *>::iterator it = listPtr->begin ();
+ it != listPtr->end ();
+ it++)
+ {
+ delete (*it);
+ }
+
+ listPtr->clear ();
+}
+
+
+//
+// kpCommand
+//
+
+kpCommand::kpCommand (kpMainWindow *mainWindow)
+ : m_mainWindow (mainWindow)
+{
+ if (!mainWindow)
+ kdError () << "kpCommand::kpCommand() passed 0 mainWindow" << endl;
+}
+
+kpCommand::~kpCommand ()
+{
+}
+
+
+// protected
+kpMainWindow *kpCommand::mainWindow () const
+{
+ return m_mainWindow;
+}
+
+
+// protected
+kpDocument *kpCommand::document () const
+{
+ return m_mainWindow ? m_mainWindow->document () : 0;
+}
+
+// protected
+kpSelection *kpCommand::selection () const
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return 0;
+
+ return doc->selection ();
+}
+
+
+// protected
+kpViewManager *kpCommand::viewManager () const
+{
+ return m_mainWindow ? m_mainWindow->viewManager () : 0;
+}
+
+
+//
+// kpNamedCommand
+//
+
+kpNamedCommand::kpNamedCommand (const QString &name, kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ m_name (name)
+{
+}
+
+kpNamedCommand::~kpNamedCommand ()
+{
+}
+
+
+// public virtual [base kpCommand]
+QString kpNamedCommand::name () const
+{
+ return m_name;
+}
+
+
+//
+// kpMacroCommand
+//
+
+struct kpMacroCommandPrivate
+{
+};
+
+kpMacroCommand::kpMacroCommand (const QString &name, kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow),
+ d (new kpMacroCommandPrivate ())
+{
+}
+
+kpMacroCommand::~kpMacroCommand ()
+{
+ clearPointerList (&m_commandList);
+ delete d;
+}
+
+
+// public virtual [base kpCommand]
+int kpMacroCommand::size () const
+{
+#if DEBUG_KP_COMMAND_HISTORY && 0
+ kdDebug () << "kpMacroCommand::size()" << endl;
+#endif
+ int s = 0;
+
+#if DEBUG_KP_COMMAND_HISTORY && 0
+ kdDebug () << "\tcalculating:" << endl;
+#endif
+ for (QValueList <kpCommand *>::const_iterator it = m_commandList.begin ();
+ it != m_commandList.end ();
+ it++)
+ {
+ #if DEBUG_KP_COMMAND_HISTORY && 0
+ kdDebug () << "\t\tcurrentSize=" << s << " + "
+ << (*it)->name () << ".size=" << (*it)->size ()
+ << endl;
+ #endif
+ if (s > INT_MAX - (*it)->size ())
+ {
+ #if DEBUG_KP_COMMAND_HISTORY && 0
+ kdDebug () << "\t\t\toverflow" << endl;
+ #endif
+ s = INT_MAX;
+ break;
+ }
+ else
+ {
+ s += (*it)->size ();
+ }
+ }
+
+#if DEBUG_KP_COMMAND_HISTORY && 0
+ kdDebug () << "\treturning " << s << endl;
+#endif
+ return s;
+}
+
+
+// public virtual [base kpCommand]
+void kpMacroCommand::execute ()
+{
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "kpMacroCommand::execute()" << endl;
+#endif
+ for (QValueList <kpCommand *>::const_iterator it = m_commandList.begin ();
+ it != m_commandList.end ();
+ it++)
+ {
+ #if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "\texecuting " << (*it)->name () << endl;
+ #endif
+ (*it)->execute ();
+ }
+}
+
+// public virtual [base kpCommand]
+void kpMacroCommand::unexecute ()
+{
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "kpMacroCommand::unexecute()" << endl;
+#endif
+ QValueList <kpCommand *>::const_iterator it = m_commandList.end ();
+ it--;
+
+ while (it != m_commandList.end ())
+ {
+ #if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "\tunexecuting " << (*it)->name () << endl;
+ #endif
+ (*it)->unexecute ();
+
+ it--;
+ }
+}
+
+
+// public
+void kpMacroCommand::addCommand (kpCommand *command)
+{
+ m_commandList.push_back (command);
+}
+
+
+//
+// kpCommandHistoryBase
+//
+
+struct kpCommandHistoryBasePrivate
+{
+};
+
+
+kpCommandHistoryBase::kpCommandHistoryBase (bool doReadConfig,
+ KActionCollection *ac)
+ : d (new kpCommandHistoryBasePrivate ())
+{
+ m_actionUndo = new KToolBarPopupAction (undoActionText (),
+ QString::fromLatin1 ("undo"),
+ KStdAccel::shortcut (KStdAccel::Undo),
+ this, SLOT (undo ()),
+ ac, KStdAction::name (KStdAction::Undo));
+
+ m_actionRedo = new KToolBarPopupAction (redoActionText (),
+ QString::fromLatin1 ("redo"),
+ KStdAccel::shortcut (KStdAccel::Redo),
+ this, SLOT (redo ()),
+ ac, KStdAction::name (KStdAction::Redo));
+
+
+ m_actionUndo->setEnabled (false);
+ m_actionRedo->setEnabled (false);
+
+
+ connect (m_actionUndo->popupMenu (), SIGNAL (activated (int)),
+ this, SLOT (undoUpToNumber (int)));
+ connect (m_actionRedo->popupMenu (), SIGNAL (activated (int)),
+ this, SLOT (redoUpToNumber (int)));
+
+
+ m_undoMinLimit = 10;
+ m_undoMaxLimit = 500;
+ m_undoMaxLimitSizeLimit = 16 * 1048576;
+
+
+ m_documentRestoredPosition = 0;
+
+
+ if (doReadConfig)
+ readConfig ();
+}
+
+kpCommandHistoryBase::~kpCommandHistoryBase ()
+{
+ clearPointerList (&m_undoCommandList);
+ clearPointerList (&m_redoCommandList);
+
+ delete d;
+}
+
+
+// public
+int kpCommandHistoryBase::undoLimit () const
+{
+ return undoMinLimit ();
+}
+
+// public
+void kpCommandHistoryBase::setUndoLimit (int limit)
+{
+ setUndoMinLimit (limit);
+}
+
+
+// public
+int kpCommandHistoryBase::undoMinLimit () const
+{
+ return m_undoMinLimit;
+}
+
+// public
+void kpCommandHistoryBase::setUndoMinLimit (int limit)
+{
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "kpCommandHistoryBase::setUndoMinLimit("
+ << limit << ")"
+ << endl;
+#endif
+
+ if (limit < 1 || limit > 5000/*"ought to be enough for anybody"*/)
+ {
+ kdError () << "kpCommandHistoryBase::setUndoMinLimit("
+ << limit << ")"
+ << endl;
+ return;
+ }
+
+ if (limit == m_undoMinLimit)
+ return;
+
+ m_undoMinLimit = limit;
+ trimCommandListsUpdateActions ();
+}
+
+
+// public
+int kpCommandHistoryBase::undoMaxLimit () const
+{
+ return m_undoMaxLimit;
+}
+
+// public
+void kpCommandHistoryBase::setUndoMaxLimit (int limit)
+{
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "kpCommandHistoryBase::setUndoMaxLimit("
+ << limit << ")"
+ << endl;
+#endif
+
+ if (limit < 1 || limit > 5000/*"ought to be enough for anybody"*/)
+ {
+ kdError () << "kpCommandHistoryBase::setUndoMaxLimit("
+ << limit << ")"
+ << endl;
+ return;
+ }
+
+ if (limit == m_undoMaxLimit)
+ return;
+
+ m_undoMaxLimit = limit;
+ trimCommandListsUpdateActions ();
+}
+
+
+// public
+int kpCommandHistoryBase::undoMaxLimitSizeLimit () const
+{
+ return m_undoMaxLimitSizeLimit;
+}
+
+// public
+void kpCommandHistoryBase::setUndoMaxLimitSizeLimit (int sizeLimit)
+{
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "kpCommandHistoryBase::setUndoMaxLimitSizeLimit("
+ << sizeLimit << ")"
+ << endl;
+#endif
+
+ if (sizeLimit < 0 ||
+ sizeLimit > (500 * 1048576)/*"ought to be enough for anybody"*/)
+ {
+ kdError () << "kpCommandHistoryBase::setUndoMaxLimitSizeLimit("
+ << sizeLimit << ")"
+ << endl;
+ return;
+ }
+
+ if (sizeLimit == m_undoMaxLimitSizeLimit)
+ return;
+
+ m_undoMaxLimitSizeLimit = sizeLimit;
+ trimCommandListsUpdateActions ();
+}
+
+
+// public
+void kpCommandHistoryBase::readConfig ()
+{
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "kpCommandHistoryBase::readConfig()" << endl;
+#endif
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupUndoRedo);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ setUndoMinLimit (cfg->readNumEntry (kpSettingUndoMinLimit, undoMinLimit ()));
+ setUndoMaxLimit (cfg->readNumEntry (kpSettingUndoMaxLimit, undoMaxLimit ()));
+ setUndoMaxLimitSizeLimit (cfg->readNumEntry (kpSettingUndoMaxLimitSizeLimit,
+ undoMaxLimitSizeLimit ()));
+
+ trimCommandListsUpdateActions ();
+}
+
+// public
+void kpCommandHistoryBase::writeConfig ()
+{
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "kpCommandHistoryBase::writeConfig()" << endl;
+#endif
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupUndoRedo);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ cfg->writeEntry (kpSettingUndoMinLimit, undoMinLimit ());
+ cfg->writeEntry (kpSettingUndoMaxLimit, undoMaxLimit ());
+ cfg->writeEntry (kpSettingUndoMaxLimitSizeLimit, undoMaxLimitSizeLimit ());
+
+ cfg->sync ();
+}
+
+
+// public
+void kpCommandHistoryBase::addCommand (kpCommand *command, bool execute)
+{
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "kpCommandHistoryBase::addCommand("
+ << command
+ << ",execute=" << execute << ")"
+ << endl;
+#endif
+
+ if (execute)
+ command->execute ();
+
+ m_undoCommandList.push_front (command);
+ clearPointerList (&m_redoCommandList);
+
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "\tdocumentRestoredPosition=" << m_documentRestoredPosition
+ << endl;
+#endif
+ if (m_documentRestoredPosition != INT_MAX)
+ {
+ if (m_documentRestoredPosition > 0)
+ m_documentRestoredPosition = INT_MAX;
+ else
+ m_documentRestoredPosition--;
+ #if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "\t\tdocumentRestoredPosition=" << m_documentRestoredPosition
+ << endl;
+ #endif
+ }
+
+ trimCommandListsUpdateActions ();
+}
+
+// public
+void kpCommandHistoryBase::clear ()
+{
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "kpCommandHistoryBase::clear()" << endl;
+#endif
+
+ clearPointerList (&m_undoCommandList);
+ clearPointerList (&m_redoCommandList);
+
+ m_documentRestoredPosition = 0;
+
+ updateActions ();
+}
+
+
+// protected slot
+void kpCommandHistoryBase::undoInternal ()
+{
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "kpCommandHistoryBase::undoInternal()" << endl;
+#endif
+
+ kpCommand *undoCommand = nextUndoCommand ();
+ if (!undoCommand)
+ return;
+
+ undoCommand->unexecute ();
+
+
+ m_undoCommandList.erase (m_undoCommandList.begin ());
+ m_redoCommandList.push_front (undoCommand);
+
+
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "\tdocumentRestoredPosition=" << m_documentRestoredPosition
+ << endl;
+#endif
+ if (m_documentRestoredPosition != INT_MAX)
+ {
+ m_documentRestoredPosition++;
+ if (m_documentRestoredPosition == 0)
+ emit documentRestored ();
+ #if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "\t\tdocumentRestoredPosition=" << m_documentRestoredPosition
+ << endl;
+ #endif
+ }
+}
+
+// protected slot
+void kpCommandHistoryBase::redoInternal ()
+{
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "kpCommandHistoryBase::redoInternal()" << endl;
+#endif
+
+ kpCommand *redoCommand = nextRedoCommand ();
+ if (!redoCommand)
+ return;
+
+ redoCommand->execute ();
+
+
+ m_redoCommandList.erase (m_redoCommandList.begin ());
+ m_undoCommandList.push_front (redoCommand);
+
+
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "\tdocumentRestoredPosition=" << m_documentRestoredPosition
+ << endl;
+#endif
+ if (m_documentRestoredPosition != INT_MAX)
+ {
+ m_documentRestoredPosition--;
+ if (m_documentRestoredPosition == 0)
+ emit documentRestored ();
+ #if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "\t\tdocumentRestoredPosition=" << m_documentRestoredPosition
+ << endl;
+ #endif
+ }
+}
+
+
+// public slot virtual
+void kpCommandHistoryBase::undo ()
+{
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "kpCommandHistoryBase::undo()" << endl;
+#endif
+
+ undoInternal ();
+ trimCommandListsUpdateActions ();
+}
+
+// public slot virtual
+void kpCommandHistoryBase::redo ()
+{
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "kpCommandHistoryBase::redo()" << endl;
+#endif
+
+ redoInternal ();
+ trimCommandListsUpdateActions ();
+}
+
+
+// public slot virtual
+void kpCommandHistoryBase::undoUpToNumber (int which)
+{
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "kpCommandHistoryBase::undoUpToNumber(" << which << ")" << endl;
+#endif
+
+ for (int i = 0;
+ i <= which && !m_undoCommandList.isEmpty ();
+ i++)
+ {
+ undoInternal ();
+ }
+
+ trimCommandListsUpdateActions ();
+}
+
+// public slot virtual
+void kpCommandHistoryBase::redoUpToNumber (int which)
+{
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "kpCommandHistoryBase::redoUpToNumber(" << which << ")" << endl;
+#endif
+
+ for (int i = 0;
+ i <= which && !m_redoCommandList.isEmpty ();
+ i++)
+ {
+ redoInternal ();
+ }
+
+ trimCommandListsUpdateActions ();
+}
+
+
+// protected
+QString kpCommandHistoryBase::undoActionText () const
+{
+ kpCommand *undoCommand = nextUndoCommand ();
+
+ if (undoCommand)
+ return i18n ("&Undo: %1").arg (undoCommand->name ());
+ else
+ return i18n ("&Undo");
+}
+
+// protected
+QString kpCommandHistoryBase::redoActionText () const
+{
+ kpCommand *redoCommand = nextRedoCommand ();
+
+ if (redoCommand)
+ return i18n ("&Redo: %1").arg (redoCommand->name ());
+ else
+ return i18n ("&Redo");
+}
+
+
+// protected
+void kpCommandHistoryBase::trimCommandListsUpdateActions ()
+{
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "kpCommandHistoryBase::trimCommandListsUpdateActions()" << endl;
+#endif
+
+ trimCommandLists ();
+ updateActions ();
+}
+
+// protected
+void kpCommandHistoryBase::trimCommandList (QValueList <kpCommand *> *commandList)
+{
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "kpCommandHistoryBase::trimCommandList()" << endl;
+ QTime timer; timer.start ();
+#endif
+
+ if (!commandList)
+ {
+ kdError () << "kpCommandHistoryBase::trimCommandList() passed 0 commandList"
+ << endl;
+ return;
+ }
+
+
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "\tsize=" << commandList->size ()
+ << " undoMinLimit=" << m_undoMinLimit
+ << " undoMaxLimit=" << m_undoMaxLimit
+ << " undoMaxLimitSizeLimit=" << m_undoMaxLimitSizeLimit
+ << endl;
+#endif
+ if ((int) commandList->size () <= m_undoMinLimit)
+ {
+ #if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "\t\tsize under undoMinLimit - done" << endl;
+ #endif
+ return;
+ }
+
+
+#if DEBUG_KP_COMMAND_HISTORY && 0
+ kdDebug () << "\tsize over undoMinLimit - iterating thru cmds:" << endl;
+#endif
+
+ QValueList <kpCommand *>::iterator it = commandList->begin ();
+ int upto = 0;
+
+ int sizeSoFar = 0;
+
+ while (it != commandList->end ())
+ {
+ bool advanceIt = true;
+
+ if (sizeSoFar <= m_undoMaxLimitSizeLimit)
+ {
+ if (sizeSoFar > INT_MAX - (*it)->size ())
+ sizeSoFar = INT_MAX;
+ else
+ sizeSoFar += (*it)->size ();
+ }
+
+ #if DEBUG_KP_COMMAND_HISTORY && 0
+ kdDebug () << "\t\t" << upto << ":"
+ << " name='" << (*it)->name ()
+ << "' size=" << (*it)->size ()
+ << " sizeSoFar=" << sizeSoFar
+ << endl;
+ #endif
+
+ if (upto >= m_undoMinLimit)
+ {
+ if (upto >= m_undoMaxLimit ||
+ sizeSoFar > m_undoMaxLimitSizeLimit)
+ {
+ #if DEBUG_KP_COMMAND_HISTORY && 0
+ kdDebug () << "\t\t\tkill" << endl;
+ #endif
+ delete (*it);
+ it = m_undoCommandList.erase (it);
+ advanceIt = false;
+ }
+ }
+
+ if (advanceIt)
+ it++;
+ upto++;
+ }
+
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "\ttook " << timer.elapsed () << "ms" << endl;
+#endif
+}
+
+// protected
+void kpCommandHistoryBase::trimCommandLists ()
+{
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "kpCommandHistoryBase::trimCommandLists()" << endl;
+#endif
+
+ trimCommandList (&m_undoCommandList);
+ trimCommandList (&m_redoCommandList);
+
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "\tdocumentRestoredPosition=" << m_documentRestoredPosition
+ << endl;
+#endif
+ if (m_documentRestoredPosition != INT_MAX)
+ {
+ #if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "\t\tundoCmdList.size=" << m_undoCommandList.size ()
+ << " redoCmdList.size=" << m_redoCommandList.size ()
+ << endl;
+ #endif
+ if (m_documentRestoredPosition > (int) m_redoCommandList.size () ||
+ -m_documentRestoredPosition > (int) m_undoCommandList.size ())
+ {
+ #if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "\t\t\tinvalidate documentRestoredPosition" << endl;
+ #endif
+ m_documentRestoredPosition = INT_MAX;
+ }
+ }
+}
+
+
+static void populatePopupMenu (KPopupMenu *popupMenu,
+ const QString &undoOrRedo,
+ const QValueList <kpCommand *> &commandList)
+{
+ if (!popupMenu)
+ return;
+
+ popupMenu->clear ();
+
+ QValueList <kpCommand *>::const_iterator it = commandList.begin ();
+ int i = 0;
+ while (i < 10 && it != commandList.end ())
+ {
+ popupMenu->insertItem (i18n ("%1: %2").arg (undoOrRedo).arg ((*it)->name ()), i/*id*/);
+ i++, it++;
+ }
+
+ if (it != commandList.end ())
+ {
+ // TODO: maybe have a scrollview show all the items instead
+ KPopupTitle *title = new KPopupTitle (popupMenu);
+ title->setTitle (i18n ("%n more item", "%n more items",
+ commandList.size () - i));
+
+ popupMenu->insertItem (title);
+ }
+}
+
+
+// protected
+void kpCommandHistoryBase::updateActions ()
+{
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "kpCommandHistoryBase::updateActions()" << endl;
+#endif
+
+ m_actionUndo->setEnabled ((bool) nextUndoCommand ());
+ m_actionUndo->setText (undoActionText ());
+#if DEBUG_KP_COMMAND_HISTORY
+ QTime timer; timer.start ();
+#endif
+ populatePopupMenu (m_actionUndo->popupMenu (),
+ i18n ("Undo"),
+ m_undoCommandList);
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "\tpopuplatePopupMenu undo=" << timer.elapsed ()
+ << "ms" << endl;;
+#endif
+
+ m_actionRedo->setEnabled ((bool) nextRedoCommand ());
+ m_actionRedo->setText (redoActionText ());
+#if DEBUG_KP_COMMAND_HISTORY
+ timer.restart ();
+#endif
+ populatePopupMenu (m_actionRedo->popupMenu (),
+ i18n ("Redo"),
+ m_redoCommandList);
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "\tpopuplatePopupMenu redo=" << timer.elapsed ()
+ << "ms" << endl;
+#endif
+}
+
+
+// public
+kpCommand *kpCommandHistoryBase::nextUndoCommand () const
+{
+ if (m_undoCommandList.isEmpty ())
+ return 0;
+
+ return m_undoCommandList.first ();
+}
+
+// public
+kpCommand *kpCommandHistoryBase::nextRedoCommand () const
+{
+ if (m_redoCommandList.isEmpty ())
+ return 0;
+
+ return m_redoCommandList.first ();
+}
+
+
+// public
+void kpCommandHistoryBase::setNextUndoCommand (kpCommand *command)
+{
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "kpCommandHistoryBase::setNextUndoCommand("
+ << command
+ << ")"
+ << endl;
+#endif
+
+ if (m_undoCommandList.isEmpty ())
+ return;
+
+
+ delete m_undoCommandList [0];
+ m_undoCommandList [0] = command;
+
+
+ trimCommandListsUpdateActions ();
+}
+
+
+// public slot virtual
+void kpCommandHistoryBase::documentSaved ()
+{
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "kpCommandHistoryBase::documentSaved()" << endl;
+#endif
+
+ m_documentRestoredPosition = 0;
+}
+
+
+//
+// kpCommandHistory
+//
+
+kpCommandHistory::kpCommandHistory (bool doReadConfig, kpMainWindow *mainWindow)
+ : kpCommandHistoryBase (doReadConfig, mainWindow->actionCollection ()),
+ m_mainWindow (mainWindow)
+{
+}
+
+kpCommandHistory::~kpCommandHistory ()
+{
+}
+
+
+// public slot virtual [base KCommandHistory]
+void kpCommandHistory::undo ()
+{
+#if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "kpCommandHistory::undo() CALLED!" << endl;
+#endif
+ if (m_mainWindow && m_mainWindow->toolHasBegunShape ())
+ {
+ #if DEBUG_KP_COMMAND_HISTORY
+ kdDebug () << "\thas begun shape - cancel draw" << endl;
+ #endif
+ m_mainWindow->tool ()->cancelShapeInternal ();
+ }
+ else
+ kpCommandHistoryBase::undo ();
+}
+
+// public slot virtual [base KCommandHistory]
+void kpCommandHistory::redo ()
+{
+ if (m_mainWindow && m_mainWindow->toolHasBegunShape ())
+ {
+ // Not completely obvious but what else can we do?
+ //
+ // Ignoring the request would not be intuitive for tools like
+ // Polygon & Polyline (where it's not always apparent to the user
+ // that s/he's still drawing a shape even though the mouse isn't
+ // down).
+ m_mainWindow->tool ()->cancelShapeInternal ();
+ }
+ else
+ kpCommandHistoryBase::redo ();
+}
+
+#include <kpcommandhistory.moc>
diff --git a/kolourpaint/kpcommandhistory.h b/kolourpaint/kpcommandhistory.h
new file mode 100644
index 00000000..a1541512
--- /dev/null
+++ b/kolourpaint/kpcommandhistory.h
@@ -0,0 +1,255 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef KP_COMMAND_HISTORY_H
+#define KP_COMMAND_HISTORY_H
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qvaluelist.h>
+
+
+class KActionCollection;
+class KToolBarPopupAction;
+
+class kpDocument;
+class kpMainWindow;
+class kpSelection;
+class kpViewManager;
+
+
+class kpCommand
+{
+public:
+ kpCommand (kpMainWindow *mainWindow);
+ virtual ~kpCommand ();
+
+public:
+ virtual QString name () const = 0;
+
+ // Returns the estimated size in bytes.
+ //
+ // You only have to factor in the size of variables that change according
+ // to the amount of input e.g. pixmap size, text size. There is no need
+ // to include the size of O(1) variables unless they are huge.
+ //
+ // If in doubt, return the largest possible amount of memory that your
+ // command will take. This is better than making the user unexpectedly
+ // run out of memory.
+ virtual int size () const = 0;
+
+ virtual void execute () = 0;
+ virtual void unexecute () = 0;
+
+protected:
+ kpMainWindow *mainWindow () const;
+
+ kpDocument *document () const;
+ kpSelection *selection () const;
+
+ kpViewManager *viewManager () const;
+
+protected:
+ kpMainWindow *m_mainWindow;
+};
+
+
+class kpNamedCommand : public kpCommand
+{
+public:
+ kpNamedCommand (const QString &name, kpMainWindow *mainWindow);
+ virtual ~kpNamedCommand ();
+
+ virtual QString name () const;
+
+protected:
+ QString m_name;
+};
+
+
+class kpMacroCommand : public kpNamedCommand
+{
+public:
+ kpMacroCommand (const QString &name, kpMainWindow *mainWindow);
+ virtual ~kpMacroCommand ();
+
+
+ //
+ // kpCommand Interface
+ //
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+
+ //
+ // Interface
+ //
+
+ void addCommand (kpCommand *command);
+
+protected:
+ QValueList <kpCommand *> m_commandList;
+
+private:
+ class kpMacroCommandPrivate *d;
+};
+
+
+// Clone of KCommandHistory with features required by KolourPaint:
+// - nextUndoCommand()/nextRedoCommand()
+// - undo/redo history limited by both number and size
+//
+// Features not required by KolourPaint (e.g. commandExecuted()) are not
+// implemented and undo limit == redo limit. So compared to
+// KCommandHistory, this is only "almost source compatible".
+class kpCommandHistoryBase : public QObject
+{
+Q_OBJECT
+
+public:
+ kpCommandHistoryBase (bool doReadConfig, KActionCollection *ac);
+ virtual ~kpCommandHistoryBase ();
+
+public:
+ // (provided for compatibility with KCommandHistory)
+ int undoLimit () const;
+ void setUndoLimit (int limit);
+
+
+ int undoMinLimit () const;
+ void setUndoMinLimit (int limit);
+
+ int undoMaxLimit () const;
+ void setUndoMaxLimit (int limit);
+
+ int undoMaxLimitSizeLimit () const;
+ void setUndoMaxLimitSizeLimit (int sizeLimit);
+
+public:
+ // Read and write above config
+ void readConfig ();
+ void writeConfig ();
+
+public:
+ void addCommand (kpCommand *command, bool execute = true);
+ void clear ();
+
+protected slots:
+ // (same as undo() & redo() except they don't call
+ // trimCommandListsUpdateActions())
+ void undoInternal ();
+ void redoInternal ();
+
+public slots:
+ virtual void undo ();
+ virtual void redo ();
+
+ virtual void undoUpToNumber (int which);
+ virtual void redoUpToNumber (int which);
+
+protected:
+ QString undoActionText () const;
+ QString redoActionText () const;
+
+ void trimCommandListsUpdateActions ();
+ void trimCommandList (QValueList <kpCommand *> *commandList);
+ void trimCommandLists ();
+ void updateActions ();
+
+public:
+ kpCommand *nextUndoCommand () const;
+ kpCommand *nextRedoCommand () const;
+
+ void setNextUndoCommand (kpCommand *command);
+
+public slots:
+ virtual void documentSaved ();
+
+signals:
+ void documentRestored ();
+
+protected:
+ KToolBarPopupAction *m_actionUndo, *m_actionRedo;
+
+ // (Front element is the next one)
+ QValueList <kpCommand *> m_undoCommandList;
+ QValueList <kpCommand *> m_redoCommandList;
+
+ int m_undoMinLimit, m_undoMaxLimit, m_undoMaxLimitSizeLimit;
+
+ // What you have to do to get back to the document's unmodified state:
+ // * -x: must Undo x times
+ // * 0: unmodified
+ // * +x: must Redo x times
+ // * INT_MAX: can never become unmodified again
+ //
+ // ASSUMPTION: will never have INT_MAX commands in any list.
+ int m_documentRestoredPosition;
+
+private:
+ class kpCommandHistoryBasePrivate *d;
+};
+
+
+// Intercepts Undo/Redo requests:
+//
+// If the user is currently drawing a shape, it cancels it.
+// Else it passes on the Undo/Redo request to kpCommandHistoryBase.
+//
+// TODO: This is wrong. It won't work if the Undo action is disabled,
+// for instance.
+//
+// Maybe the real solution is to call kpCommandHistoryBase::addCommand()
+// as _soon_ as the shape starts - not after it ends. But the
+// trouble with this solution is that if the user Undoes/cancels
+// the shape s/he's currently drawing, it would replace a Redo
+// slot in the history. Arguably you shouldn't be able to Redo
+// something you never finished drawing.
+//
+// The solution is to add this functionality to kpCommandHistoryBase.
+class kpCommandHistory : public kpCommandHistoryBase
+{
+Q_OBJECT
+
+public:
+ kpCommandHistory (bool doReadConfig, kpMainWindow *mainWindow);
+ virtual ~kpCommandHistory ();
+
+public slots:
+ virtual void undo ();
+ virtual void redo ();
+
+protected:
+ kpMainWindow *m_mainWindow;
+};
+
+
+#endif // KP_COMMAND_HISTORY_H
diff --git a/kolourpaint/kpdefs.h b/kolourpaint/kpdefs.h
new file mode 100644
index 00000000..15faaee0
--- /dev/null
+++ b/kolourpaint/kpdefs.h
@@ -0,0 +1,151 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kp_defs_h__
+#define __kp_defs_h__
+
+
+#include <limits.h>
+
+#include <qglobal.h>
+#include <qpoint.h>
+#include <qsize.h>
+#include <qstring.h>
+
+#include <kdeversion.h>
+
+
+#define KP_IS_QT_3_3 (QT_VERSION >= 0x030300 && 1)
+#define KP_IS_KDE_3_3 ((KDE_VERSION_MAJOR >= 3 && KDE_VERSION_MINOR >= 3) && 1)
+
+
+// approx. 2896x2896x32bpp or 3344x3344x24bpp (TODO: 24==32?) or 4096*4096x16bpp
+#define KP_BIG_IMAGE_SIZE (32 * 1048576)
+
+
+#define KP_PI 3.141592653589793238462
+
+
+#define KP_DEGREES_TO_RADIANS(deg) ((deg) * KP_PI / 180.0)
+#define KP_RADIANS_TO_DEGREES(rad) ((rad) * 180.0 / KP_PI)
+
+
+#define KP_INVALID_POINT QPoint (INT_MIN / 8, INT_MIN / 8)
+#define KP_INVALID_WIDTH (INT_MIN / 8)
+#define KP_INVALID_HEIGHT (INT_MIN / 8)
+#define KP_INVALID_SIZE QSize (INT_MIN / 8, INT_MIN / 8)
+
+
+//
+// Settings
+//
+
+#define kpSettingsGroupGeneral QString::fromLatin1 ("General Settings")
+#define kpSettingFirstTime QString::fromLatin1 ("First Time")
+#define kpSettingShowGrid QString::fromLatin1 ("Show Grid")
+#define kpSettingShowPath QString::fromLatin1 ("Show Path")
+#define kpSettingColorSimilarity QString::fromLatin1 ("Color Similarity")
+#define kpSettingDitherOnOpen QString::fromLatin1 ("Dither on Open if Screen is 15/16bpp and Image Num Colors More Than")
+#define kpSettingPrintImageCenteredOnPage QString::fromLatin1 ("Print Image Centered On Page")
+
+#define kpSettingsGroupFileSaveAs QString::fromLatin1 ("File/Save As")
+#define kpSettingsGroupFileExport QString::fromLatin1 ("File/Export")
+#define kpSettingsGroupEditCopyTo QString::fromLatin1 ("Edit/Copy To")
+
+#define kpSettingForcedMimeType QString::fromLatin1 ("Forced MimeType")
+#define kpSettingForcedColorDepth QString::fromLatin1 ("Forced Color Depth")
+#define kpSettingForcedDither QString::fromLatin1 ("Forced Dither")
+#define kpSettingForcedQuality QString::fromLatin1 ("Forced Quality")
+
+#define kpSettingLastDocSize QString::fromLatin1 ("Last Document Size")
+
+#define kpSettingMoreEffectsLastEffect QString::fromLatin1 ("More Effects - Last Effect")
+
+#define kpSettingResizeScaleLastKeepAspect QString::fromLatin1 ("Resize Scale - Last Keep Aspect")
+
+
+#define kpSettingsGroupMimeTypeProperties QString::fromLatin1 ("MimeType Properties Version 1.2-2")
+#define kpSettingMimeTypeMaximumColorDepth QString::fromLatin1 ("Maximum Color Depth")
+#define kpSettingMimeTypeHasConfigurableColorDepth QString::fromLatin1 ("Configurable Color Depth")
+#define kpSettingMimeTypeHasConfigurableQuality QString::fromLatin1 ("Configurable Quality Setting")
+
+
+#define kpSettingsGroupUndoRedo QString::fromLatin1 ("Undo/Redo Settings")
+#define kpSettingUndoMinLimit QString::fromLatin1 ("Min Limit")
+#define kpSettingUndoMaxLimit QString::fromLatin1 ("Max Limit")
+#define kpSettingUndoMaxLimitSizeLimit QString::fromLatin1 ("Max Limit Size Limit")
+
+
+#define kpSettingsGroupThumbnail QString::fromLatin1 ("Thumbnail Settings")
+#define kpSettingThumbnailShown QString::fromLatin1 ("Shown")
+#define kpSettingThumbnailGeometry QString::fromLatin1 ("Geometry")
+#define kpSettingThumbnailZoomed QString::fromLatin1 ("Zoomed")
+#define kpSettingThumbnailShowRectangle QString::fromLatin1 ("ShowRectangle")
+
+
+#define kpSettingsGroupPreviewSave QString::fromLatin1 ("Save Preview Settings")
+#define kpSettingPreviewSaveGeometry QString::fromLatin1 ("Geometry")
+#define kpSettingPreviewSaveUpdateDelay QString::fromLatin1 ("Update Delay")
+
+
+#define kpSettingsGroupTools QString::fromLatin1 ("Tool Settings")
+#define kpSettingLastTool QString::fromLatin1 ("Last Used Tool")
+#define kpSettingToolBoxIconSize QString::fromLatin1 ("Tool Box Icon Size")
+
+
+#define kpSettingsGroupText QString::fromLatin1 ("Text Settings")
+#define kpSettingFontFamily QString::fromLatin1 ("Font Family")
+#define kpSettingFontSize QString::fromLatin1 ("Font Size")
+#define kpSettingBold QString::fromLatin1 ("Bold")
+#define kpSettingItalic QString::fromLatin1 ("Italic")
+#define kpSettingUnderline QString::fromLatin1 ("Underline")
+#define kpSettingStrikeThru QString::fromLatin1 ("Strike Thru")
+
+
+#define kpSettingsGroupFlattenEffect QString::fromLatin1 ("Flatten Effect Settings")
+#define kpSettingFlattenEffectColor1 QString::fromLatin1 ("Color1")
+#define kpSettingFlattenEffectColor2 QString::fromLatin1 ("Color2")
+
+
+//
+// Session Restore Setting
+//
+
+// URL of the document in the main window.
+//
+// This key only exists if the document does. If it exists, it can be empty.
+// The URL need not point to a file that exists e.g. "kolourpaint doesnotexist.png".
+#define kpSessionSettingDocumentUrl QString::fromLatin1 ("Session Document Url")
+
+// The size of a document which is not from a URL e.g. "kolourpaint doesnotexist.png".
+// This key does not exist for documents from URLs.
+#define kpSessionSettingNotFromUrlDocumentSize QString::fromLatin1 ("Session Not-From-Url Document Size")
+
+
+#endif // __kp_defs_h__
+
diff --git a/kolourpaint/kpdocument.cpp b/kolourpaint/kpdocument.cpp
new file mode 100644
index 00000000..801b922e
--- /dev/null
+++ b/kolourpaint/kpdocument.cpp
@@ -0,0 +1,1539 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_DOCUMENT 0
+
+
+#include <kpdocument.h>
+
+#include <math.h>
+
+#include <qcolor.h>
+#include <qbitmap.h>
+#include <qbrush.h>
+#include <qfile.h>
+#include <qimage.h>
+#include <qpixmap.h>
+#include <qpainter.h>
+#include <qrect.h>
+#include <qsize.h>
+#include <qvaluelist.h>
+#include <qwmatrix.h>
+
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kimageio.h>
+#include <kio/netaccess.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kmimetype.h>
+#include <ksavefile.h>
+#include <ktempfile.h>
+
+#include <kpcolor.h>
+#include <kpcolortoolbar.h>
+#include <kpdefs.h>
+#include <kpdocumentsaveoptions.h>
+#include <kpdocumentmetainfo.h>
+#include <kpeffectreducecolors.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kpselection.h>
+#include <kptool.h>
+#include <kptooltoolbar.h>
+#include <kpviewmanager.h>
+
+
+struct kpDocumentPrivate
+{
+ kpDocumentPrivate ()
+ {
+ }
+};
+
+
+kpDocument::kpDocument (int w, int h, kpMainWindow *mainWindow)
+ : m_constructorWidth (w), m_constructorHeight (h),
+ m_mainWindow (mainWindow),
+ m_isFromURL (false),
+ m_savedAtLeastOnceBefore (false),
+ m_saveOptions (new kpDocumentSaveOptions ()),
+ m_metaInfo (new kpDocumentMetaInfo ()),
+ m_modified (false),
+ m_selection (0),
+ m_oldWidth (-1), m_oldHeight (-1),
+ d (new kpDocumentPrivate ())
+{
+#if DEBUG_KP_DOCUMENT && 0
+ kdDebug () << "kpDocument::kpDocument (" << w << "," << h << ")" << endl;
+#endif
+
+ m_pixmap = new QPixmap (w, h);
+ m_pixmap->fill (Qt::white);
+}
+
+kpDocument::~kpDocument ()
+{
+ delete d;
+
+ delete m_pixmap;
+
+ delete m_saveOptions;
+ delete m_metaInfo;
+
+ delete m_selection;
+}
+
+
+kpMainWindow *kpDocument::mainWindow () const
+{
+ return m_mainWindow;
+}
+
+void kpDocument::setMainWindow (kpMainWindow *mainWindow)
+{
+ m_mainWindow = mainWindow;
+}
+
+
+/*
+ * File I/O
+ */
+
+// public static
+QPixmap kpDocument::convertToPixmapAsLosslessAsPossible (
+ const QImage &image,
+ const kpPixmapFX::WarnAboutLossInfo &wali,
+
+ kpDocumentSaveOptions *saveOptions,
+ kpDocumentMetaInfo *metaInfo)
+{
+ if (image.isNull ())
+ return QPixmap ();
+
+
+#if DEBUG_KP_DOCUMENT
+ kdDebug () << "\timage: depth=" << image.depth ()
+ << " (X display=" << QColor::numBitPlanes () << ")"
+ << " hasAlphaBuffer=" << image.hasAlphaBuffer ()
+ << endl;
+#endif
+
+ if (saveOptions)
+ {
+ saveOptions->setColorDepth (image.depth ());
+ saveOptions->setDither (false); // avoid double dithering when saving
+ }
+
+ if (metaInfo)
+ {
+ metaInfo->setDotsPerMeterX (image.dotsPerMeterX ());
+ metaInfo->setDotsPerMeterY (image.dotsPerMeterY ());
+ metaInfo->setOffset (image.offset ());
+
+ QValueList <QImageTextKeyLang> keyList = image.textList ();
+ for (QValueList <QImageTextKeyLang>::const_iterator it = keyList.begin ();
+ it != keyList.end ();
+ it++)
+ {
+ metaInfo->setText (*it, image.text (*it));
+ }
+
+ #if DEBUG_KP_DOCUMENT
+ metaInfo->printDebug ("\tmetaInfo");
+ #endif
+ }
+
+#if DEBUG_KP_DOCUMENT && 1
+{
+ if (image.width () <= 16 && image.height () <= 16)
+ {
+ kdDebug () << "Image dump:" << endl;
+
+ for (int y = 0; y < image.height (); y++)
+ {
+ for (int x = 0; x < image.width (); x++)
+ {
+ const QRgb rgb = image.pixel (x, y);
+ fprintf (stderr, " %08X", rgb);
+ }
+ fprintf (stderr, "\n");
+ }
+ }
+}
+#endif
+
+
+ QPixmap newPixmap = kpPixmapFX::convertToPixmapAsLosslessAsPossible (image, wali);
+
+
+#if DEBUG_KP_DOCUMENT && 1
+{
+ const QImage image2 = kpPixmapFX::convertToImage (newPixmap);
+ kdDebug () << "(Converted to pixmap) Image dump:" << endl;
+
+ bool differsFromOrgImage = false;
+ unsigned long hash = 0;
+ int numDiff = 0;
+ for (int y = 0; y < image2.height (); y++)
+ {
+ for (int x = 0; x < image2.width (); x++)
+ {
+ const QRgb rgb = image2.pixel (x, y);
+ hash += ((x % 2) + 1) * rgb;
+ if (rgb != image.pixel (x, y))
+ {
+ differsFromOrgImage = true;
+ numDiff++;
+ }
+ if (image2.width () <= 16 && image2.height () <= 16)
+ fprintf (stderr, " %08X", rgb);
+ }
+ if (image2.width () <= 16 && image2.height () <= 16)
+ fprintf (stderr, "\n");
+ }
+
+ kdDebug () << "\tdiffersFromOrgImage="
+ << differsFromOrgImage
+ << " numDiff="
+ << numDiff
+ << " hash=" << hash << endl;
+}
+#endif
+
+ return newPixmap;
+}
+
+// public static
+QPixmap kpDocument::getPixmapFromFile (const KURL &url, bool suppressDoesntExistDialog,
+ QWidget *parent,
+ kpDocumentSaveOptions *saveOptions,
+ kpDocumentMetaInfo *metaInfo)
+{
+#if DEBUG_KP_DOCUMENT
+ kdDebug () << "kpDocument::getPixmapFromFile(" << url << "," << parent << ")" << endl;
+#endif
+
+ if (saveOptions)
+ *saveOptions = kpDocumentSaveOptions ();
+
+ if (metaInfo)
+ *metaInfo = kpDocumentMetaInfo ();
+
+
+ QString tempFile;
+ if (url.isEmpty () || !KIO::NetAccess::download (url, tempFile, parent))
+ {
+ if (!suppressDoesntExistDialog)
+ {
+ KMessageBox::sorry (parent,
+ i18n ("Could not open \"%1\".")
+ .arg (kpDocument::prettyFilenameForURL (url)));
+ }
+
+ return QPixmap ();
+ }
+
+
+ QImage image;
+
+ // sync: remember to "KIO::NetAccess::removeTempFile (tempFile)" in all exit paths
+ {
+ QString detectedMimeType = KImageIO::mimeType (tempFile);
+ if (saveOptions)
+ saveOptions->setMimeType (detectedMimeType);
+
+ #if DEBUG_KP_DOCUMENT
+ kdDebug () << "\ttempFile=" << tempFile << endl;
+ kdDebug () << "\tmimetype=" << detectedMimeType << endl;
+ kdDebug () << "\tsrc=" << url.path () << endl;
+ kdDebug () << "\tmimetype of src=" << KImageIO::mimeType (url.path ()) << endl;
+ #endif
+
+ if (detectedMimeType.isEmpty ())
+ {
+ KMessageBox::sorry (parent,
+ i18n ("Could not open \"%1\" - unknown mimetype.")
+ .arg (kpDocument::prettyFilenameForURL (url)));
+ KIO::NetAccess::removeTempFile (tempFile);
+ return QPixmap ();
+ }
+
+
+ image = QImage (tempFile);
+ KIO::NetAccess::removeTempFile (tempFile);
+ }
+
+
+ if (image.isNull ())
+ {
+ KMessageBox::sorry (parent,
+ i18n ("Could not open \"%1\" - unsupported image format.\n"
+ "The file may be corrupt.")
+ .arg (kpDocument::prettyFilenameForURL (url)));
+ return QPixmap ();
+ }
+
+ const QPixmap newPixmap = kpDocument::convertToPixmapAsLosslessAsPossible (image,
+ kpPixmapFX::WarnAboutLossInfo (
+ i18n ("The image \"%1\""
+ " may have more colors than the current screen mode."
+ " In order to display it, some colors may be changed."
+ " Try increasing your screen depth to at least %2bpp."
+
+ "\nIt also"
+
+ " contains translucency which is not fully"
+ " supported. The translucency data will be"
+ " approximated with a 1-bit transparency mask.")
+ .arg (prettyFilenameForURL (url)),
+ i18n ("The image \"%1\""
+ " may have more colors than the current screen mode."
+ " In order to display it, some colors may be changed."
+ " Try increasing your screen depth to at least %2bpp.")
+ .arg (prettyFilenameForURL (url)),
+ i18n ("The image \"%1\""
+ " contains translucency which is not fully"
+ " supported. The translucency data will be"
+ " approximated with a 1-bit transparency mask.")
+ .arg (prettyFilenameForURL (url)),
+ "docOpen",
+ parent),
+ saveOptions,
+ metaInfo);
+
+ if (newPixmap.isNull ())
+ {
+ KMessageBox::sorry (parent,
+ i18n ("Could not open \"%1\" - out of graphics memory.")
+ .arg (kpDocument::prettyFilenameForURL (url)));
+ return QPixmap ();
+ }
+
+#if DEBUG_KP_DOCUMENT
+ kdDebug () << "\tpixmap: depth=" << newPixmap.depth ()
+ << " hasAlphaChannelOrMask=" << newPixmap.hasAlpha ()
+ << " hasAlphaChannel=" << newPixmap.hasAlphaChannel ()
+ << endl;
+#endif
+
+
+ return newPixmap;
+}
+
+void kpDocument::openNew (const KURL &url)
+{
+#if DEBUG_KP_DOCUMENT
+ kdDebug () << "KpDocument::openNew (" << url << ")" << endl;
+#endif
+
+ m_pixmap->fill (Qt::white);
+
+ setURL (url, false/*not from url*/);
+ *m_saveOptions = kpDocumentSaveOptions ();
+ *m_metaInfo = kpDocumentMetaInfo ();
+ m_modified = false;
+
+ emit documentOpened ();
+}
+
+bool kpDocument::open (const KURL &url, bool newDocSameNameIfNotExist)
+{
+#if DEBUG_KP_DOCUMENT
+ kdDebug () << "kpDocument::open (" << url << ")" << endl;
+#endif
+
+ kpDocumentSaveOptions newSaveOptions;
+ kpDocumentMetaInfo newMetaInfo;
+ QPixmap newPixmap = kpDocument::getPixmapFromFile (url,
+ newDocSameNameIfNotExist/*suppress "doesn't exist" dialog*/,
+ m_mainWindow,
+ &newSaveOptions,
+ &newMetaInfo);
+
+ if (!newPixmap.isNull ())
+ {
+ delete m_pixmap;
+ m_pixmap = new QPixmap (newPixmap);
+
+ setURL (url, true/*is from url*/);
+ *m_saveOptions = newSaveOptions;
+ *m_metaInfo = newMetaInfo;
+ m_modified = false;
+
+ emit documentOpened ();
+ return true;
+ }
+
+ if (newDocSameNameIfNotExist)
+ {
+ if (!url.isEmpty () &&
+ // not just a permission error?
+ !KIO::NetAccess::exists (url, true/*open*/, m_mainWindow))
+ {
+ openNew (url);
+ }
+ else
+ {
+ openNew (KURL ());
+ }
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool kpDocument::save (bool overwritePrompt, bool lossyPrompt)
+{
+#if DEBUG_KP_DOCUMENT
+ kdDebug () << "kpDocument::save("
+ << "overwritePrompt=" << overwritePrompt
+ << ",lossyPrompt=" << lossyPrompt
+ << ") url=" << m_url
+ << " savedAtLeastOnceBefore=" << savedAtLeastOnceBefore ()
+ << endl;
+#endif
+
+ // TODO: check feels weak
+ if (m_url.isEmpty () || m_saveOptions->mimeType ().isEmpty ())
+ {
+ KMessageBox::detailedError (m_mainWindow,
+ i18n ("Could not save image - insufficient information."),
+ i18n ("URL: %1\n"
+ "Mimetype: %2")
+ .arg (prettyURL ())
+ .arg (m_saveOptions->mimeType ().isEmpty () ?
+ i18n ("<empty>") :
+ m_saveOptions->mimeType ()),
+ i18n ("Internal Error"));
+ return false;
+ }
+
+ return saveAs (m_url, *m_saveOptions,
+ overwritePrompt,
+ lossyPrompt);
+}
+
+
+// public static
+bool kpDocument::lossyPromptContinue (const QPixmap &pixmap,
+ const kpDocumentSaveOptions &saveOptions,
+ QWidget *parent)
+{
+#if DEBUG_KP_DOCUMENT
+ kdDebug () << "kpDocument::lossyPromptContinue()" << endl;
+#endif
+
+#define QUIT_IF_CANCEL(messageBoxCommand) \
+{ \
+ if (messageBoxCommand != KMessageBox::Continue) \
+ { \
+ return false; \
+ } \
+}
+
+ const int lossyType = saveOptions.isLossyForSaving (pixmap);
+ if (lossyType & (kpDocumentSaveOptions::MimeTypeMaximumColorDepthLow |
+ kpDocumentSaveOptions::Quality))
+ {
+ QUIT_IF_CANCEL (
+ KMessageBox::warningContinueCancel (parent,
+ i18n ("<qt><p>The <b>%1</b> format may not be able"
+ " to preserve all of the image's color information.</p>"
+
+ "<p>Are you sure you want to save in this format?</p></qt>")
+ .arg (KMimeType::mimeType (saveOptions.mimeType ())->comment ()),
+ // TODO: caption misleading for lossless formats that have
+ // low maximum colour depth
+ i18n ("Lossy File Format"),
+ KStdGuiItem::save (),
+ QString::fromLatin1 ("SaveInLossyMimeTypeDontAskAgain")));
+ }
+ else if (lossyType & kpDocumentSaveOptions::ColorDepthLow)
+ {
+ QUIT_IF_CANCEL (
+ KMessageBox::warningContinueCancel (parent,
+ i18n ("<qt><p>Saving the image at the low color depth of %1-bit"
+ " may result in the loss of color information."
+
+ " Any transparency will also be removed.</p>"
+
+ "<p>Are you sure you want to save at this color depth?</p></qt>")
+ .arg (saveOptions.colorDepth ()),
+ i18n ("Low Color Depth"),
+ KStdGuiItem::save (),
+ QString::fromLatin1 ("SaveAtLowColorDepthDontAskAgain")));
+ }
+#undef QUIT_IF_CANCEL
+
+ return true;
+}
+
+// public static
+bool kpDocument::savePixmapToDevice (const QPixmap &pixmap,
+ QIODevice *device,
+ const kpDocumentSaveOptions &saveOptions,
+ const kpDocumentMetaInfo &metaInfo,
+ bool lossyPrompt,
+ QWidget *parent,
+ bool *userCancelled)
+{
+ if (userCancelled)
+ *userCancelled = false;
+
+ QString type = KImageIO::typeForMime (saveOptions.mimeType ());
+#if DEBUG_KP_DOCUMENT
+ kdDebug () << "\tmimeType=" << saveOptions.mimeType ()
+ << " type=" << type << endl;
+#endif
+
+ if (lossyPrompt && !lossyPromptContinue (pixmap, saveOptions, parent))
+ {
+ if (userCancelled)
+ *userCancelled = true;
+
+ #if DEBUG_KP_DOCUMENT
+ kdDebug () << "\treturning false because of lossyPrompt" << endl;
+ #endif
+ return false;
+ }
+
+
+ QPixmap pixmapToSave =
+ kpPixmapFX::pixmapWithDefinedTransparentPixels (pixmap,
+ Qt::white); // CONFIG
+ QImage imageToSave = kpPixmapFX::convertToImage (pixmapToSave);
+
+
+ // TODO: fix dup with kpDocumentSaveOptions::isLossyForSaving()
+ const bool useSaveOptionsColorDepth =
+ (saveOptions.mimeTypeHasConfigurableColorDepth () &&
+ !saveOptions.colorDepthIsInvalid ());
+ const bool useSaveOptionsQuality =
+ (saveOptions.mimeTypeHasConfigurableQuality () &&
+ !saveOptions.qualityIsInvalid ());
+
+
+ //
+ // Reduce colors if required
+ //
+
+ if (useSaveOptionsColorDepth &&
+ imageToSave.depth () != saveOptions.colorDepth ())
+ {
+ imageToSave = ::convertImageDepth (imageToSave,
+ saveOptions.colorDepth (),
+ saveOptions.dither ());
+ }
+
+
+ //
+ // Write Meta Info
+ //
+
+ imageToSave.setDotsPerMeterX (metaInfo.dotsPerMeterX ());
+ imageToSave.setDotsPerMeterY (metaInfo.dotsPerMeterY ());
+ imageToSave.setOffset (metaInfo.offset ());
+
+ QValueList <QImageTextKeyLang> keyList = metaInfo.textList ();
+ for (QValueList <QImageTextKeyLang>::const_iterator it = keyList.begin ();
+ it != keyList.end ();
+ it++)
+ {
+ imageToSave.setText ((*it).key, (*it).lang, metaInfo.text (*it));
+ }
+
+
+ //
+ // Save at required quality
+ //
+
+ int quality = -1; // default
+
+ if (useSaveOptionsQuality)
+ quality = saveOptions.quality ();
+
+ if (!imageToSave.save (device, type.latin1 (), quality))
+ {
+ #if DEBUG_KP_DOCUMENT
+ kdDebug () << "\tQImage::save() returned false" << endl;
+ #endif
+ return false;
+ }
+
+
+#if DEBUG_KP_DOCUMENT
+ kdDebug () << "\tsave OK" << endl;
+#endif
+ return true;
+}
+
+static void CouldNotCreateTemporaryFileDialog (QWidget *parent)
+{
+ KMessageBox::error (parent,
+ i18n ("Could not save image - unable to create temporary file."));
+}
+
+static void CouldNotSaveDialog (const KURL &url, QWidget *parent)
+{
+ // TODO: use file.errorString()
+ KMessageBox::error (parent,
+ i18n ("Could not save as \"%1\".")
+ .arg (kpDocument::prettyFilenameForURL (url)));
+}
+
+// public static
+bool kpDocument::savePixmapToFile (const QPixmap &pixmap,
+ const KURL &url,
+ const kpDocumentSaveOptions &saveOptions,
+ const kpDocumentMetaInfo &metaInfo,
+ bool overwritePrompt,
+ bool lossyPrompt,
+ QWidget *parent)
+{
+ // TODO: Use KIO::NetAccess:mostLocalURL() for accessing home:/ (and other
+ // such local URLs) for efficiency and because only local writes
+ // are atomic.
+#if DEBUG_KP_DOCUMENT
+ kdDebug () << "kpDocument::savePixmapToFile ("
+ << url
+ << ",overwritePrompt=" << overwritePrompt
+ << ",lossyPrompt=" << lossyPrompt
+ << ")" << endl;
+ saveOptions.printDebug (QString::fromLatin1 ("\tsaveOptions"));
+ metaInfo.printDebug (QString::fromLatin1 ("\tmetaInfo"));
+#endif
+
+ if (overwritePrompt && KIO::NetAccess::exists (url, false/*write*/, parent))
+ {
+ int result = KMessageBox::warningContinueCancel (parent,
+ i18n ("A document called \"%1\" already exists.\n"
+ "Do you want to overwrite it?")
+ .arg (prettyFilenameForURL (url)),
+ QString::null,
+ i18n ("Overwrite"));
+
+ if (result != KMessageBox::Continue)
+ {
+ #if DEBUG_KP_DOCUMENT
+ kdDebug () << "\tuser doesn't want to overwrite" << endl;
+ #endif
+
+ return false;
+ }
+ }
+
+
+ if (lossyPrompt && !lossyPromptContinue (pixmap, saveOptions, parent))
+ {
+ #if DEBUG_KP_DOCUMENT
+ kdDebug () << "\treturning false because of lossyPrompt" << endl;
+ #endif
+ return false;
+ }
+
+
+ // Local file?
+ if (url.isLocalFile ())
+ {
+ const QString filename = url.path ();
+
+ // sync: All failure exit paths _must_ call KSaveFile::abort() or
+ // else, the KSaveFile destructor will overwrite the file,
+ // <filename>, despite the failure.
+ KSaveFile atomicFileWriter (filename);
+ {
+ if (atomicFileWriter.status () != 0)
+ {
+ // We probably don't need this as <filename> has not been
+ // opened.
+ atomicFileWriter.abort ();
+
+ #if DEBUG_KP_DOCUMENT
+ kdDebug () << "\treturning false because could not open KSaveFile"
+ << " status=" << atomicFileWriter.status () << endl;
+ #endif
+ ::CouldNotCreateTemporaryFileDialog (parent);
+ return false;
+ }
+
+ // Write to local temporary file.
+ if (!savePixmapToDevice (pixmap, atomicFileWriter.file (),
+ saveOptions, metaInfo,
+ false/*no lossy prompt*/,
+ parent))
+ {
+ atomicFileWriter.abort ();
+
+ #if DEBUG_KP_DOCUMENT
+ kdDebug () << "\treturning false because could not save pixmap to device"
+ << endl;
+ #endif
+ ::CouldNotSaveDialog (url, parent);
+ return false;
+ }
+
+ // Atomically overwrite local file with the temporary file
+ // we saved to.
+ if (!atomicFileWriter.close ())
+ {
+ atomicFileWriter.abort ();
+
+ #if DEBUG_KP_DOCUMENT
+ kdDebug () << "\tcould not close KSaveFile" << endl;
+ #endif
+ ::CouldNotSaveDialog (url, parent);
+ return false;
+ }
+ } // sync KSaveFile.abort()
+ }
+ // Remote file?
+ else
+ {
+ // Create temporary file that is deleted when the variable goes
+ // out of scope.
+ KTempFile tempFile;
+ tempFile.setAutoDelete (true);
+
+ QString filename = tempFile.name ();
+ if (filename.isEmpty ())
+ {
+ #if DEBUG_KP_DOCUMENT
+ kdDebug () << "\treturning false because tempFile empty" << endl;
+ #endif
+ ::CouldNotCreateTemporaryFileDialog (parent);
+ return false;
+ }
+
+ // Write to local temporary file.
+ QFile file (filename);
+ {
+ if (!file.open (IO_WriteOnly))
+ {
+ #if DEBUG_KP_DOCUMENT
+ kdDebug () << "\treturning false because can't open file"
+ << " errorString=" << file.errorString () << endl;
+ #endif
+ ::CouldNotCreateTemporaryFileDialog (parent);
+ return false;
+ }
+
+ if (!savePixmapToDevice (pixmap, &file,
+ saveOptions, metaInfo,
+ false/*no lossy prompt*/,
+ parent))
+ {
+ #if DEBUG_KP_DOCUMENT
+ kdDebug () << "\treturning false because could not save pixmap to device"
+ << endl;
+ #endif
+ ::CouldNotSaveDialog (url, parent);
+ return false;
+ }
+ }
+ file.close ();
+ if (file.status () != IO_Ok)
+ {
+ #if DEBUG_KP_DOCUMENT
+ kdDebug () << "\treturning false because could not close" << endl;
+ #endif
+ ::CouldNotSaveDialog (url, parent);
+ return false;
+ }
+
+ // Copy local temporary file to overwrite remote.
+ // TODO: No one seems to know how to do this atomically
+ // [http://lists.kde.org/?l=kde-core-devel&m=117845162728484&w=2].
+ // At least, fish:// (ssh) is definitely not atomic.
+ if (!KIO::NetAccess::upload (filename, url, parent))
+ {
+ #if DEBUG_KP_DOCUMENT
+ kdDebug () << "\treturning false because could not upload" << endl;
+ #endif
+ KMessageBox::error (parent,
+ i18n ("Could not save image - failed to upload."));
+ return false;
+ }
+ }
+
+
+ return true;
+}
+
+bool kpDocument::saveAs (const KURL &url,
+ const kpDocumentSaveOptions &saveOptions,
+ bool overwritePrompt,
+ bool lossyPrompt)
+{
+#if DEBUG_KP_DOCUMENT
+ kdDebug () << "kpDocument::saveAs (" << url << ","
+ << saveOptions.mimeType () << ")" << endl;
+#endif
+
+ if (kpDocument::savePixmapToFile (pixmapWithSelection (),
+ url,
+ saveOptions, *metaInfo (),
+ overwritePrompt,
+ lossyPrompt,
+ m_mainWindow))
+ {
+ setURL (url, true/*is from url*/);
+ *m_saveOptions = saveOptions;
+ m_modified = false;
+
+ m_savedAtLeastOnceBefore = true;
+
+ emit documentSaved ();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+// public
+bool kpDocument::savedAtLeastOnceBefore () const
+{
+ return m_savedAtLeastOnceBefore;
+}
+
+// public
+KURL kpDocument::url () const
+{
+ return m_url;
+}
+
+// public
+void kpDocument::setURL (const KURL &url, bool isFromURL)
+{
+ m_url = url;
+ m_isFromURL = isFromURL;
+}
+
+// public
+bool kpDocument::isFromURL (bool checkURLStillExists) const
+{
+ if (!m_isFromURL)
+ return false;
+
+ if (!checkURLStillExists)
+ return true;
+
+ return (!m_url.isEmpty () &&
+ KIO::NetAccess::exists (m_url, true/*open*/, m_mainWindow));
+}
+
+
+// static
+QString kpDocument::prettyURLForURL (const KURL &url)
+{
+ if (url.isEmpty ())
+ return i18n ("Untitled");
+ else
+ return url.prettyURL (0, KURL::StripFileProtocol);
+}
+
+QString kpDocument::prettyURL () const
+{
+ return prettyURLForURL (m_url);
+}
+
+
+// static
+QString kpDocument::prettyFilenameForURL (const KURL &url)
+{
+ if (url.isEmpty ())
+ return i18n ("Untitled");
+ else if (url.fileName ().isEmpty ())
+ return prettyURLForURL (url); // better than the name ""
+ else
+ return url.fileName ();
+}
+
+QString kpDocument::prettyFilename () const
+{
+ return prettyFilenameForURL (m_url);
+}
+
+
+// public
+const kpDocumentSaveOptions *kpDocument::saveOptions () const
+{
+ return m_saveOptions;
+}
+
+// public
+void kpDocument::setSaveOptions (const kpDocumentSaveOptions &saveOptions)
+{
+ *m_saveOptions = saveOptions;
+}
+
+
+// public
+const kpDocumentMetaInfo *kpDocument::metaInfo () const
+{
+ return m_metaInfo;
+}
+
+// public
+void kpDocument::setMetaInfo (const kpDocumentMetaInfo &metaInfo)
+{
+ *m_metaInfo = metaInfo;
+}
+
+
+/*
+ * Properties
+ */
+
+void kpDocument::setModified (bool yes)
+{
+ if (yes == m_modified)
+ return;
+
+ m_modified = yes;
+
+ if (yes)
+ emit documentModified ();
+}
+
+bool kpDocument::isModified () const
+{
+ return m_modified;
+}
+
+bool kpDocument::isEmpty () const
+{
+ return url ().isEmpty () && !isModified ();
+}
+
+
+int kpDocument::constructorWidth () const
+{
+ return m_constructorWidth;
+}
+
+int kpDocument::width (bool ofSelection) const
+{
+ if (ofSelection && m_selection)
+ return m_selection->width ();
+ else
+ return m_pixmap->width ();
+}
+
+int kpDocument::oldWidth () const
+{
+ return m_oldWidth;
+}
+
+void kpDocument::setWidth (int w, const kpColor &backgroundColor)
+{
+ resize (w, height (), backgroundColor);
+}
+
+
+int kpDocument::constructorHeight () const
+{
+ return m_constructorHeight;
+}
+
+int kpDocument::height (bool ofSelection) const
+{
+ if (ofSelection && m_selection)
+ return m_selection->height ();
+ else
+ return m_pixmap->height ();
+}
+
+int kpDocument::oldHeight () const
+{
+ return m_oldHeight;
+}
+
+void kpDocument::setHeight (int h, const kpColor &backgroundColor)
+{
+ resize (width (), h, backgroundColor);
+}
+
+QRect kpDocument::rect (bool ofSelection) const
+{
+ if (ofSelection && m_selection)
+ return m_selection->boundingRect ();
+ else
+ return m_pixmap->rect ();
+}
+
+
+/*
+ * Pixmap access
+ */
+
+// public
+QPixmap kpDocument::getPixmapAt (const QRect &rect) const
+{
+ return kpPixmapFX::getPixmapAt (*m_pixmap, rect);
+}
+
+// public
+void kpDocument::setPixmapAt (const QPixmap &pixmap, const QPoint &at)
+{
+#if DEBUG_KP_DOCUMENT && 0
+ kdDebug () << "kpDocument::setPixmapAt (pixmap (w="
+ << pixmap.width ()
+ << ",h=" << pixmap.height ()
+ << "), x=" << at.x ()
+ << ",y=" << at.y ()
+ << endl;
+#endif
+
+ kpPixmapFX::setPixmapAt (m_pixmap, at, pixmap);
+ slotContentsChanged (QRect (at.x (), at.y (), pixmap.width (), pixmap.height ()));
+}
+
+// public
+void kpDocument::paintPixmapAt (const QPixmap &pixmap, const QPoint &at)
+{
+ kpPixmapFX::paintPixmapAt (m_pixmap, at, pixmap);
+ slotContentsChanged (QRect (at.x (), at.y (), pixmap.width (), pixmap.height ()));
+}
+
+
+// public
+QPixmap *kpDocument::pixmap (bool ofSelection) const
+{
+ if (ofSelection)
+ {
+ if (m_selection && m_selection->pixmap ())
+ return m_selection->pixmap ();
+ else
+ return 0;
+ }
+ else
+ return m_pixmap;
+}
+
+// public
+void kpDocument::setPixmap (const QPixmap &pixmap)
+{
+ m_oldWidth = width (), m_oldHeight = height ();
+
+ *m_pixmap = pixmap;
+
+ if (m_oldWidth == width () && m_oldHeight == height ())
+ slotContentsChanged (pixmap.rect ());
+ else
+ slotSizeChanged (width (), height ());
+}
+
+// public
+void kpDocument::setPixmap (bool ofSelection, const QPixmap &pixmap)
+{
+ if (ofSelection)
+ {
+ if (!m_selection)
+ {
+ kdError () << "kpDocument::setPixmap(ofSelection=true) without sel" << endl;
+ return;
+ }
+
+ m_selection->setPixmap (pixmap);
+ }
+ else
+ setPixmap (pixmap);
+}
+
+
+// private
+void kpDocument::updateToolsSingleKeyTriggersEnabled ()
+{
+ if (m_mainWindow)
+ {
+ // Disable single key shortcuts when the user is editing text
+ m_mainWindow->enableActionsSingleKeyTriggers (!m_selection || !m_selection->isText ());
+ }
+}
+
+
+// public
+kpSelection *kpDocument::selection () const
+{
+ return m_selection;
+}
+
+// public
+void kpDocument::setSelection (const kpSelection &selection)
+{
+#if DEBUG_KP_DOCUMENT && 0
+ kdDebug () << "kpDocument::setSelection() sel boundingRect="
+ << selection.boundingRect ()
+ << endl;
+#endif
+
+ kpViewManager *vm = m_mainWindow ? m_mainWindow->viewManager () : 0;
+ if (vm)
+ vm->setQueueUpdates ();
+
+ bool hadSelection = (bool) m_selection;
+
+
+ const bool isTextChanged = (m_mainWindow->toolIsTextTool () !=
+ (selection.type () == kpSelection::Text));
+
+ // We don't change the Selection Tool if the new selection's
+ // shape is merely different to the current tool's (e.g. rectangular
+ // vs elliptical) because:
+ //
+ // 1. All image selection tools support editing selections of all the
+ // different shapes anyway.
+ // 2. Suppose the user is trying out different drags of selection borders
+ // and then decides to paste a differently shaped selection before continuing
+ // to try out different borders. If the pasting were to switch to
+ // a differently shaped tool, the borders drawn after the paste would
+ // be using a new shape rather than the shape before the paste. This
+ // could get irritating so we don't do the switch.
+ //
+ if (m_mainWindow &&
+ (!m_mainWindow->toolIsASelectionTool () || isTextChanged))
+ {
+ // Switch to the appropriately shaped selection tool
+ // _before_ we change the selection
+ // (all selection tool's ::end() functions nuke the current selection)
+ switch (selection.type ())
+ {
+ case kpSelection::Rectangle:
+ m_mainWindow->slotToolRectSelection ();
+ break;
+ case kpSelection::Ellipse:
+ m_mainWindow->slotToolEllipticalSelection ();
+ break;
+ case kpSelection::Points:
+ m_mainWindow->slotToolFreeFormSelection ();
+ break;
+ case kpSelection::Text:
+ m_mainWindow->slotToolText ();
+ break;
+ default:
+ break;
+ }
+ }
+
+
+ if (m_selection)
+ {
+ // TODO: Emitting this, before setting the new selection, is bogus
+ // since it would redraw the old selection.
+ //
+ // Luckily, this doesn't matter thanks to the
+ // kpViewManager::setQueueUpdates() call above.
+ if (m_selection->pixmap ())
+ slotContentsChanged (m_selection->boundingRect ());
+ else
+ // TODO: Should emit contentsChanged() instead?
+ // I don't think it matters since contentsChanged() is
+ // connected to updateViews() anyway (see
+ // kpMainWindow::setDocument ()).
+ vm->updateViews (m_selection->boundingRect ());
+
+ delete m_selection;
+ }
+
+ m_selection = new kpSelection (selection);
+
+ // TODO: this coupling is bad, careless and lazy
+ if (m_mainWindow)
+ {
+ if (!m_selection->isText ())
+ {
+ if (m_selection->transparency () != m_mainWindow->selectionTransparency ())
+ {
+ kdDebug () << "kpDocument::setSelection() sel's transparency differs "
+ "from mainWindow's transparency - setting mainWindow's transparency "
+ "to sel"
+ << endl;
+ kdDebug () << "\tisOpaque: sel=" << m_selection->transparency ().isOpaque ()
+ << " mainWindow=" << m_mainWindow->selectionTransparency ().isOpaque ()
+ << endl;
+ m_mainWindow->setSelectionTransparency (m_selection->transparency ());
+ }
+ }
+ else
+ {
+ if (m_selection->textStyle () != m_mainWindow->textStyle ())
+ {
+ kdDebug () << "kpDocument::setSelection() sel's textStyle differs "
+ "from mainWindow's textStyle - setting mainWindow's textStyle "
+ "to sel"
+ << endl;
+ m_mainWindow->setTextStyle (m_selection->textStyle ());
+ }
+ }
+ }
+
+ updateToolsSingleKeyTriggersEnabled ();
+
+#if DEBUG_KP_DOCUMENT && 0
+ kdDebug () << "\tcheck sel " << (int *) m_selection
+ << " boundingRect=" << m_selection->boundingRect ()
+ << endl;
+#endif
+ if (m_selection->pixmap ())
+ slotContentsChanged (m_selection->boundingRect ());
+ else
+ // TODO: Should emit contentsChanged() instead?
+ // I don't think it matters since contentsChanged() is
+ // connected to updateViews() anyway (see
+ // kpMainWindow::setDocument ()).
+ vm->updateViews (m_selection->boundingRect ());
+
+ // There's no need to disconnect() the old selection since we:
+ //
+ // 1. Connect our _copy_ of the given selection.
+ // 2. We delete our copy when setSelection() is called again.
+ //
+ // See code above for both.
+ connect (m_selection, SIGNAL (changed (const QRect &)),
+ this, SLOT (slotContentsChanged (const QRect &)));
+
+
+ if (!hadSelection)
+ emit selectionEnabled (true);
+
+ if (isTextChanged)
+ emit selectionIsTextChanged (selection.type () == kpSelection::Text);
+
+ if (vm)
+ vm->restoreQueueUpdates ();
+}
+
+// public
+QPixmap kpDocument::getSelectedPixmap (const QBitmap &maskBitmap_) const
+{
+ kpSelection *sel = selection ();
+
+ // must have a selection region
+ if (!sel)
+ {
+ kdError () << "kpDocument::getSelectedPixmap() no sel region" << endl;
+ return QPixmap ();
+ }
+
+ // easy if we already have it :)
+ if (sel->pixmap ())
+ return *sel->pixmap ();
+
+
+ const QRect boundingRect = sel->boundingRect ();
+ if (!boundingRect.isValid ())
+ {
+ kdError () << "kpDocument::getSelectedPixmap() boundingRect invalid" << endl;
+ return QPixmap ();
+ }
+
+
+ QBitmap maskBitmap = maskBitmap_;
+ if (maskBitmap.isNull () &&
+ !sel->isRectangular ())
+ {
+ maskBitmap = sel->maskForOwnType ();
+
+ if (maskBitmap.isNull ())
+ {
+ kdError () << "kpDocument::getSelectedPixmap() could not get mask" << endl;
+ return QPixmap ();
+ }
+ }
+
+
+ QPixmap selPixmap = getPixmapAt (boundingRect);
+
+ if (!maskBitmap.isNull ())
+ {
+ // Src Dest = Result
+ // -----------------
+ // 0 0 0
+ // 0 1 0
+ // 1 0 0
+ // 1 1 1
+ QBitmap selMaskBitmap = kpPixmapFX::getNonNullMask (selPixmap);
+ bitBlt (&selMaskBitmap,
+ QPoint (0, 0),
+ &maskBitmap,
+ QRect (0, 0, maskBitmap.width (), maskBitmap.height ()),
+ Qt::AndROP);
+ selPixmap.setMask (selMaskBitmap);
+ }
+
+ return selPixmap;
+}
+
+// public
+bool kpDocument::selectionPullFromDocument (const kpColor &backgroundColor)
+{
+ kpViewManager *vm = m_mainWindow ? m_mainWindow->viewManager () : 0;
+
+ kpSelection *sel = selection ();
+
+ // must have a selection region
+ if (!sel)
+ {
+ kdError () << "kpDocument::selectionPullFromDocument() no sel region" << endl;
+ return false;
+ }
+
+ // should not already have a pixmap
+ if (sel->pixmap ())
+ {
+ kdError () << "kpDocument::selectionPullFromDocument() already has pixmap" << endl;
+ return false;
+ }
+
+ const QRect boundingRect = sel->boundingRect ();
+ if (!boundingRect.isValid ())
+ {
+ kdError () << "kpDocument::selectionPullFromDocument() boundingRect invalid" << endl;
+ return false;
+ }
+
+
+ //
+ // Figure out mask for non-rectangular selections
+ //
+
+ QBitmap maskBitmap = sel->maskForOwnType (true/*return null bitmap for rectangular*/);
+
+
+ //
+ // Get selection pixmap from document
+ //
+
+ QPixmap selPixmap = getSelectedPixmap (maskBitmap);
+
+ if (vm)
+ vm->setQueueUpdates ();
+
+ sel->setPixmap (selPixmap);
+
+
+ //
+ // Fill opaque bits of the hole in the document
+ //
+
+ // TODO: this assumes backgroundColor == sel->transparency ().transparentColor()
+ const QPixmap selTransparentPixmap = sel->transparentPixmap ();
+
+ if (backgroundColor.isOpaque ())
+ {
+ QPixmap erasePixmap (boundingRect.width (), boundingRect.height ());
+ erasePixmap.fill (backgroundColor.toQColor ());
+
+ if (selTransparentPixmap.mask ())
+ erasePixmap.setMask (*selTransparentPixmap.mask ());
+
+ paintPixmapAt (erasePixmap, boundingRect.topLeft ());
+ }
+ else
+ {
+ kpPixmapFX::paintMaskTransparentWithBrush (m_pixmap,
+ boundingRect.topLeft (),
+ kpPixmapFX::getNonNullMask (selTransparentPixmap));
+ slotContentsChanged (boundingRect);
+ }
+
+ if (vm)
+ vm->restoreQueueUpdates ();
+
+ return true;
+}
+
+// public
+bool kpDocument::selectionDelete ()
+{
+ kpSelection *sel = selection ();
+
+ if (!sel)
+ return false;
+
+ const QRect boundingRect = sel->boundingRect ();
+ if (!boundingRect.isValid ())
+ return false;
+
+ bool selectionHadPixmap = m_selection ? (bool) m_selection->pixmap () : false;
+
+ delete m_selection;
+ m_selection = 0;
+
+
+ // HACK to prevent document from being modified when
+ // user cancels dragging out a new selection
+ if (selectionHadPixmap)
+ slotContentsChanged (boundingRect);
+ else
+ emit contentsChanged (boundingRect);
+
+ emit selectionEnabled (false);
+
+
+ updateToolsSingleKeyTriggersEnabled ();
+
+ return true;
+}
+
+// public
+bool kpDocument::selectionCopyOntoDocument (bool useTransparentPixmap)
+{
+ kpSelection *sel = selection ();
+
+ // must have a pixmap already
+ if (!sel)
+ return false;
+
+ // hasn't actually been lifted yet
+ if (!sel->pixmap ())
+ return true;
+
+ const QRect boundingRect = sel->boundingRect ();
+ if (!boundingRect.isValid ())
+ return false;
+
+ if (!sel->isText ())
+ {
+ // We can't use kpSelection::paint() since that always uses the
+ // transparent pixmap.
+ paintPixmapAt (useTransparentPixmap ? sel->transparentPixmap () : sel->opaquePixmap (),
+ boundingRect.topLeft ());
+ }
+ else
+ {
+ // (for antialiasing with background)
+ sel->paint (m_pixmap, rect ());
+ }
+
+ slotContentsChanged (boundingRect);
+
+ return true;
+}
+
+// public
+bool kpDocument::selectionPushOntoDocument (bool useTransparentPixmap)
+{
+ return (selectionCopyOntoDocument (useTransparentPixmap) && selectionDelete ());
+}
+
+// public
+QPixmap kpDocument::pixmapWithSelection () const
+{
+#if DEBUG_KP_DOCUMENT && 1
+ kdDebug () << "kpDocument::pixmapWithSelection()" << endl;
+#endif
+
+ // Have floating selection?
+ if (m_selection && m_selection->pixmap ())
+ {
+ #if DEBUG_KP_DOCUMENT && 1
+ kdDebug () << "\tselection @ " << m_selection->boundingRect () << endl;
+ #endif
+ QPixmap output = *m_pixmap;
+
+ m_selection->paint (&output, rect ());
+
+ return output;
+ }
+ else
+ {
+ #if DEBUG_KP_DOCUMENT && 1
+ kdDebug () << "\tno selection" << endl;
+ #endif
+ return *m_pixmap;
+ }
+}
+
+
+/*
+ * Transformations
+ */
+
+void kpDocument::fill (const kpColor &color)
+{
+#if DEBUG_KP_DOCUMENT
+ kdDebug () << "kpDocument::fill ()" << endl;
+#endif
+
+ kpPixmapFX::fill (m_pixmap, color);
+ slotContentsChanged (m_pixmap->rect ());
+}
+
+void kpDocument::resize (int w, int h, const kpColor &backgroundColor, bool fillNewAreas)
+{
+#if DEBUG_KP_DOCUMENT
+ kdDebug () << "kpDocument::resize (" << w << "," << h << "," << fillNewAreas << ")" << endl;
+#endif
+
+ m_oldWidth = width (), m_oldHeight = height ();
+
+#if DEBUG_KP_DOCUMENT && 1
+ kdDebug () << "\toldWidth=" << m_oldWidth
+ << " oldHeight=" << m_oldHeight
+ << endl;
+#endif
+
+ if (w == m_oldWidth && h == m_oldHeight)
+ return;
+
+ kpPixmapFX::resize (m_pixmap, w, h, backgroundColor, fillNewAreas);
+
+ slotSizeChanged (width (), height ());
+}
+
+
+/*
+ * Slots
+ */
+
+void kpDocument::slotContentsChanged (const QRect &rect)
+{
+ setModified ();
+ emit contentsChanged (rect);
+}
+
+void kpDocument::slotSizeChanged (int newWidth, int newHeight)
+{
+ setModified ();
+ emit sizeChanged (newWidth, newHeight);
+ emit sizeChanged (QSize (newWidth, newHeight));
+}
+
+void kpDocument::slotSizeChanged (const QSize &newSize)
+{
+ slotSizeChanged (newSize.width (), newSize.height ());
+}
+
+#include <kpdocument.moc>
diff --git a/kolourpaint/kpdocument.h b/kolourpaint/kpdocument.h
new file mode 100644
index 00000000..d75e36ff
--- /dev/null
+++ b/kolourpaint/kpdocument.h
@@ -0,0 +1,260 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef KP_DOCUMENT_H
+#define KP_DOCUMENT_H
+
+#include <qbitmap.h>
+#include <qobject.h>
+#include <qstring.h>
+
+#include <kurl.h>
+
+#include <kppixmapfx.h>
+
+
+class QImage;
+class QIODevice;
+class QPixmap;
+class QPoint;
+class QRect;
+class QSize;
+
+class kpColor;
+class kpDocumentSaveOptions;
+class kpDocumentMetaInfo;
+class kpMainWindow;
+class kpSelection;
+
+
+class kpDocument : public QObject
+{
+Q_OBJECT
+
+public:
+ kpDocument (int w, int h, kpMainWindow *mainWindow);
+ ~kpDocument ();
+
+ kpMainWindow *mainWindow () const;
+ void setMainWindow (kpMainWindow *mainWindow);
+
+
+ /*
+ * File I/O
+ */
+
+ // Wraps kpPixmapFX::convertToPixmapAsLosslessAsPossible() but also
+ // returns document meta information.
+ static QPixmap convertToPixmapAsLosslessAsPossible (
+ const QImage &image,
+ const kpPixmapFX::WarnAboutLossInfo &wali = kpPixmapFX::WarnAboutLossInfo (),
+ kpDocumentSaveOptions *saveOptions = 0,
+ kpDocumentMetaInfo *metaInfo = 0);
+
+ static QPixmap getPixmapFromFile (const KURL &url, bool suppressDoesntExistDialog,
+ QWidget *parent,
+ kpDocumentSaveOptions *saveOptions = 0,
+ kpDocumentMetaInfo *metaInfo = 0);
+ // TODO: fix: open*() should only be called once.
+ // Create a new kpDocument() if you want to open again.
+ void openNew (const KURL &url);
+ bool open (const KURL &url, bool newDocSameNameIfNotExist = false);
+
+ static bool lossyPromptContinue (const QPixmap &pixmap,
+ const kpDocumentSaveOptions &saveOptions,
+ QWidget *parent);
+ static bool savePixmapToDevice (const QPixmap &pixmap,
+ QIODevice *device,
+ const kpDocumentSaveOptions &saveOptions,
+ const kpDocumentMetaInfo &metaInfo,
+ bool lossyPrompt,
+ QWidget *parent,
+ bool *userCancelled = 0);
+ static bool savePixmapToFile (const QPixmap &pixmap,
+ const KURL &url,
+ const kpDocumentSaveOptions &saveOptions,
+ const kpDocumentMetaInfo &metaInfo,
+ bool overwritePrompt,
+ bool lossyPrompt,
+ QWidget *parent);
+ bool save (bool overwritePrompt = false, bool lossyPrompt = false);
+ bool saveAs (const KURL &url,
+ const kpDocumentSaveOptions &saveOptions,
+ bool overwritePrompt = true,
+ bool lossyPrompt = true);
+
+ // Returns whether save() or saveAs() have ever been called and returned true
+ bool savedAtLeastOnceBefore () const;
+
+ KURL url () const;
+ void setURL (const KURL &url, bool isFromURL);
+
+ // Returns whether the document's pixmap was successfully opened from
+ // or saved to the URL returned by url(). This is not true for a
+ // new kpDocument and in the case of open() being passed
+ // "newDocSameNameIfNotExist = true" when the URL doesn't exist.
+ //
+ // If this returns true and the kpDocument hasn't been modified,
+ // this gives a pretty good indication that the pixmap stored at url()
+ // is equal to pixmap() (unless the something has happened to that url
+ // outside of KolourPaint).
+ bool isFromURL (bool checkURLStillExists = true) const;
+
+ // (will convert: empty URL --> "Untitled")
+ static QString prettyURLForURL (const KURL &url);
+ QString prettyURL () const;
+
+ // (will convert: empty URL --> "Untitled")
+ static QString prettyFilenameForURL (const KURL &url);
+ QString prettyFilename () const;
+
+ // (guaranteed to return valid pointer)
+
+ const kpDocumentSaveOptions *saveOptions () const;
+ void setSaveOptions (const kpDocumentSaveOptions &saveOptions);
+
+ const kpDocumentMetaInfo *metaInfo () const;
+ void setMetaInfo (const kpDocumentMetaInfo &metaInfo);
+
+
+ /*
+ * Properties (modified, width, height, color depth...)
+ */
+
+ void setModified (bool yes = true);
+ bool isModified () const;
+ bool isEmpty () const;
+
+ int constructorWidth () const; // as passed to the constructor
+ int width (bool ofSelection = false) const;
+ int oldWidth () const; // only valid in a slot connected to sizeChanged()
+ void setWidth (int w, const kpColor &backgroundColor);
+
+ int constructorHeight () const; // as passed to the constructor
+ int height (bool ofSelection = false) const;
+ int oldHeight () const; // only valid in a slot connected to sizeChanged()
+ void setHeight (int h, const kpColor &backgroundColor);
+
+ QRect rect (bool ofSelection = false) const;
+
+
+ /*
+ * Pixmap access
+ */
+
+ // get a copy of a bit of the doc's pixmap
+ // (not including the selection)
+ QPixmap getPixmapAt (const QRect &rect) const;
+
+ void setPixmapAt (const QPixmap &pixmap, const QPoint &at);
+
+ void paintPixmapAt (const QPixmap &pixmap, const QPoint &at);
+
+ // (not including the selection)
+ QPixmap *pixmap (bool ofSelection = false) const;
+ void setPixmap (const QPixmap &pixmap);
+ void setPixmap (bool ofSelection, const QPixmap &pixmap);
+
+private:
+ void updateToolsSingleKeyTriggersEnabled ();
+
+public:
+ kpSelection *selection () const;
+ void setSelection (const kpSelection &selection);
+
+ // TODO: this always returns opaque pixmap - need transparent ver
+ QPixmap getSelectedPixmap (const QBitmap &maskBitmap = QBitmap ()) const;
+
+ bool selectionPullFromDocument (const kpColor &backgroundColor);
+ bool selectionDelete ();
+ bool selectionCopyOntoDocument (bool useTransparentPixmap = true);
+ bool selectionPushOntoDocument (bool useTransparentPixmap = true);
+
+ // same as pixmap() but returns a _copy_ of the current pixmap
+ // + any selection pasted on top
+ QPixmap pixmapWithSelection () const;
+
+
+ /*
+ * Transformations
+ * (convenience only - you could achieve the same effect (and more) with
+ * kpPixmapFX: these functions do not affect the selection)
+ */
+
+ void fill (const kpColor &color);
+ void resize (int w, int h, const kpColor &backgroundColor, bool fillNewAreas = true);
+
+
+public slots:
+ // these will emit signals!
+ void slotContentsChanged (const QRect &rect);
+ void slotSizeChanged (int newWidth, int newHeight);
+ void slotSizeChanged (const QSize &newSize);
+
+signals:
+ void documentOpened ();
+ void documentSaved ();
+
+ // Emitted whenever the isModified() flag changes from false to true.
+ // This is the _only_ signal that may be emitted in addition to the others.
+ void documentModified ();
+
+ void contentsChanged (const QRect &rect);
+ void sizeChanged (int newWidth, int newHeight); // see oldWidth(), oldHeight()
+ void sizeChanged (const QSize &newSize);
+
+ void selectionEnabled (bool on);
+
+ // HACK: until we support Text Selection -> Rectangular Selection for Image ops
+ void selectionIsTextChanged (bool isText);
+
+private:
+ int m_constructorWidth, m_constructorHeight;
+ kpMainWindow *m_mainWindow;
+ QPixmap *m_pixmap;
+
+ KURL m_url;
+ bool m_isFromURL;
+ bool m_savedAtLeastOnceBefore;
+
+ kpDocumentSaveOptions *m_saveOptions;
+ kpDocumentMetaInfo *m_metaInfo;
+
+ bool m_modified;
+
+ kpSelection *m_selection;
+
+ int m_oldWidth, m_oldHeight;
+
+ // There is no need to maintain binary compatibility at this stage.
+ // The d-pointer is just so that you can experiment without recompiling
+ // the kitchen sink.
+ class kpDocumentPrivate *d;
+};
+
+#endif // KP_DOCUMENT_H
diff --git a/kolourpaint/kpdocumentmetainfo.cpp b/kolourpaint/kpdocumentmetainfo.cpp
new file mode 100644
index 00000000..5e5fc6ae
--- /dev/null
+++ b/kolourpaint/kpdocumentmetainfo.cpp
@@ -0,0 +1,186 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <kpdocumentmetainfo.h>
+
+#include <qpoint.h>
+
+#include <kdebug.h>
+
+
+struct kpDocumentMetaInfoPrivate
+{
+ int m_dotsPerMeterX, m_dotsPerMeterY;
+ QPoint m_offset;
+
+ QMap <QImageTextKeyLang, QString> m_textMap;
+};
+
+
+// public
+kpDocumentMetaInfo::kpDocumentMetaInfo ()
+ : d (new kpDocumentMetaInfoPrivate ())
+{
+ d->m_dotsPerMeterX = 0;
+ d->m_dotsPerMeterY = 0;
+ d->m_offset = QPoint (0, 0);
+}
+
+kpDocumentMetaInfo::kpDocumentMetaInfo (const kpDocumentMetaInfo &rhs)
+ : d (new kpDocumentMetaInfoPrivate ())
+{
+ d->m_dotsPerMeterX = rhs.dotsPerMeterX ();
+ d->m_dotsPerMeterY = rhs.dotsPerMeterY ();
+ d->m_offset = rhs.offset ();
+ d->m_textMap = rhs.textMap ();
+}
+
+// public
+kpDocumentMetaInfo::~kpDocumentMetaInfo ()
+{
+ delete d;
+}
+
+
+// public
+kpDocumentMetaInfo &kpDocumentMetaInfo::operator= (const kpDocumentMetaInfo &rhs)
+{
+ d->m_dotsPerMeterX = rhs.dotsPerMeterX ();
+ d->m_dotsPerMeterY = rhs.dotsPerMeterY ();
+ d->m_offset = rhs.offset ();
+ d->m_textMap = rhs.textMap ();
+
+ return *this;
+}
+
+
+// public
+void kpDocumentMetaInfo::printDebug (const QString &prefix) const
+{
+ const QString usedPrefix = !prefix.isEmpty () ?
+ prefix + QString::fromLatin1 (":") :
+ QString::null;
+
+ kdDebug () << usedPrefix << endl;
+
+ kdDebug () << "dotsPerMeter X=" << dotsPerMeterX ()
+ << " Y=" << dotsPerMeterY ()
+ << " offset=" << offset () << endl;
+
+ QValueList <QImageTextKeyLang> keyList = textList ();
+ for (QValueList <QImageTextKeyLang>::const_iterator it = keyList.begin ();
+ it != keyList.end ();
+ it++)
+ {
+ kdDebug () << "key=" << (*it).key
+ << " lang=" << (*it).lang
+ << " text=" << text (*it)
+ << endl;
+ }
+
+ kdDebug () << usedPrefix << "ENDS" << endl;
+}
+
+
+// public
+int kpDocumentMetaInfo::dotsPerMeterX () const
+{
+ return d->m_dotsPerMeterX;
+}
+
+// public
+void kpDocumentMetaInfo::setDotsPerMeterX (int val)
+{
+ d->m_dotsPerMeterX = val;
+}
+
+
+// public
+int kpDocumentMetaInfo::dotsPerMeterY () const
+{
+ return d->m_dotsPerMeterY;
+}
+
+// public
+void kpDocumentMetaInfo::setDotsPerMeterY (int val)
+{
+ d->m_dotsPerMeterY = val;
+}
+
+
+// public
+QPoint kpDocumentMetaInfo::offset () const
+{
+ return d->m_offset;
+}
+
+// public
+void kpDocumentMetaInfo::setOffset (const QPoint &point)
+{
+ d->m_offset = point;
+}
+
+
+// public
+QMap <QImageTextKeyLang, QString> kpDocumentMetaInfo::textMap () const
+{
+ return d->m_textMap;
+}
+
+// public
+QValueList <QImageTextKeyLang> kpDocumentMetaInfo::textList () const
+{
+ return d->m_textMap.keys ();
+}
+
+
+// public
+QString kpDocumentMetaInfo::text (const QImageTextKeyLang &itkl) const
+{
+ return d->m_textMap [itkl];
+}
+
+// public
+QString kpDocumentMetaInfo::text (const char *key, const char *lang) const
+{
+ return text (QImageTextKeyLang (key, lang));
+}
+
+
+// public
+void kpDocumentMetaInfo::setText (const QImageTextKeyLang &itkl,
+ const QString &string)
+{
+ d->m_textMap [itkl] = string;
+}
+
+// public
+void kpDocumentMetaInfo::setText (const char *key, const char *lang,
+ const QString &string)
+{
+ setText (QImageTextKeyLang (key, lang), string);
+}
diff --git a/kolourpaint/kpdocumentmetainfo.h b/kolourpaint/kpdocumentmetainfo.h
new file mode 100644
index 00000000..15e1408f
--- /dev/null
+++ b/kolourpaint/kpdocumentmetainfo.h
@@ -0,0 +1,90 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef KP_DOCUMENT_META_INFO
+#define KP_DOCUMENT_META_INFO
+
+
+#include <qimage.h>
+#include <qmap.h>
+#include <qstring.h>
+#include <qvaluelist.h>
+
+
+class QPoint;
+
+
+class kpDocumentMetaInfo
+{
+public:
+ kpDocumentMetaInfo ();
+ kpDocumentMetaInfo (const kpDocumentMetaInfo &rhs);
+ virtual ~kpDocumentMetaInfo ();
+
+private:
+ bool operator== (const kpDocumentMetaInfo &rhs) const;
+ bool operator!= (const kpDocumentMetaInfo &rhs) const;
+
+public:
+ kpDocumentMetaInfo &operator= (const kpDocumentMetaInfo &rhs);
+
+
+ void printDebug (const QString &prefix) const;
+
+
+ // See QImage documentation
+
+ int dotsPerMeterX () const;
+ void setDotsPerMeterX (int val);
+
+ int dotsPerMeterY () const;
+ void setDotsPerMeterY (int val);
+
+
+ QPoint offset () const;
+ void setOffset (const QPoint &point);
+
+
+ QMap <QImageTextKeyLang, QString> textMap () const;
+ QValueList <QImageTextKeyLang> textList () const;
+
+ QString text (const QImageTextKeyLang &itkl) const;
+ QString text (const char *key, const char *lang) const;
+ void setText (const QImageTextKeyLang &itkl, const QString &string);
+ void setText (const char *key, const char *lang, const QString &string);
+
+
+private:
+ // There is no need to maintain binary compatibility at this stage.
+ // The d-pointer is just so that you can experiment without recompiling
+ // the kitchen sink.
+ class kpDocumentMetaInfoPrivate *d;
+};
+
+
+#endif // KP_DOCUMENT_META_INFO
diff --git a/kolourpaint/kpdocumentsaveoptions.cpp b/kolourpaint/kpdocumentsaveoptions.cpp
new file mode 100644
index 00000000..701b6b51
--- /dev/null
+++ b/kolourpaint/kpdocumentsaveoptions.cpp
@@ -0,0 +1,561 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_DOCUMENT_SAVE_OPTIONS 0
+
+
+#include <kpdocumentsaveoptions.h>
+
+#include <qpixmap.h>
+#include <qstring.h>
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+
+#include <kpdefs.h>
+
+
+struct kpDocumentSaveOptionsPrivate
+{
+ QString m_mimeType;
+ int m_colorDepth;
+ bool m_dither;
+ int m_quality;
+};
+
+
+kpDocumentSaveOptions::kpDocumentSaveOptions ()
+ : d (new kpDocumentSaveOptionsPrivate ())
+{
+ d->m_mimeType = invalidMimeType ();
+ d->m_colorDepth = invalidColorDepth ();
+ d->m_dither = initialDither ();
+ d->m_quality = invalidQuality ();
+}
+
+kpDocumentSaveOptions::kpDocumentSaveOptions (const kpDocumentSaveOptions &rhs)
+ : d (new kpDocumentSaveOptionsPrivate ())
+{
+ d->m_mimeType = rhs.mimeType ();
+ d->m_colorDepth = rhs.colorDepth ();
+ d->m_dither = rhs.dither ();
+ d->m_quality = rhs.quality ();
+}
+
+kpDocumentSaveOptions::kpDocumentSaveOptions (QString mimeType, int colorDepth, bool dither, int quality)
+ : d (new kpDocumentSaveOptionsPrivate ())
+{
+ d->m_mimeType = mimeType;
+ d->m_colorDepth = colorDepth;
+ d->m_dither = dither;
+ d->m_quality = quality;
+}
+
+kpDocumentSaveOptions::~kpDocumentSaveOptions ()
+{
+ delete d;
+}
+
+
+// public
+bool kpDocumentSaveOptions::operator== (const kpDocumentSaveOptions &rhs) const
+{
+ return (mimeType () == rhs.mimeType () &&
+ colorDepth () == rhs.colorDepth () &&
+ dither () == rhs.dither () &&
+ quality () == rhs.quality ());
+}
+
+// public
+bool kpDocumentSaveOptions::operator!= (const kpDocumentSaveOptions &rhs) const
+{
+ return !(*this == rhs);
+}
+
+
+// public
+kpDocumentSaveOptions &kpDocumentSaveOptions::operator= (const kpDocumentSaveOptions &rhs)
+{
+ setMimeType (rhs.mimeType ());
+ setColorDepth (rhs.colorDepth ());
+ setDither (rhs.dither ());
+ setQuality (rhs.quality ());
+
+ return *this;
+}
+
+
+// public
+void kpDocumentSaveOptions::printDebug (const QString &prefix) const
+{
+ const QString usedPrefix = !prefix.isEmpty () ?
+ prefix + QString::fromLatin1 (": ") :
+ QString::null;
+
+ kdDebug () << usedPrefix
+ << "mimeType=" << mimeType ()
+ << " colorDepth=" << colorDepth ()
+ << " dither=" << dither ()
+ << " quality=" << quality ()
+ << endl;
+}
+
+
+// public
+QString kpDocumentSaveOptions::mimeType () const
+{
+ return d->m_mimeType;
+}
+
+// public
+void kpDocumentSaveOptions::setMimeType (const QString &mimeType)
+{
+ d->m_mimeType = mimeType;
+}
+
+
+// public static
+QString kpDocumentSaveOptions::invalidMimeType ()
+{
+ return QString::null;
+}
+
+// public static
+bool kpDocumentSaveOptions::mimeTypeIsInvalid (const QString &mimeType)
+{
+ return (mimeType == invalidMimeType ());
+}
+
+// public
+bool kpDocumentSaveOptions::mimeTypeIsInvalid () const
+{
+ return mimeTypeIsInvalid (mimeType ());
+}
+
+
+// public
+int kpDocumentSaveOptions::colorDepth () const
+{
+ return d->m_colorDepth;
+}
+
+// public
+void kpDocumentSaveOptions::setColorDepth (int depth)
+{
+ d->m_colorDepth = depth;
+}
+
+
+// public static
+int kpDocumentSaveOptions::invalidColorDepth ()
+{
+ return -1;
+}
+
+// public static
+bool kpDocumentSaveOptions::colorDepthIsInvalid (int colorDepth)
+{
+ return (colorDepth != 1 && colorDepth != 8 && colorDepth != 32);
+}
+
+// public
+bool kpDocumentSaveOptions::colorDepthIsInvalid () const
+{
+ return colorDepthIsInvalid (colorDepth ());
+}
+
+
+// public
+bool kpDocumentSaveOptions::dither () const
+{
+ return d->m_dither;
+}
+
+// public
+void kpDocumentSaveOptions::setDither (bool dither)
+{
+ d->m_dither = dither;
+}
+
+
+// public static
+int kpDocumentSaveOptions::initialDither ()
+{
+ return false; // to avoid accidental double dithering
+}
+
+
+// public
+int kpDocumentSaveOptions::quality () const
+{
+ return d->m_quality;
+}
+
+// public
+void kpDocumentSaveOptions::setQuality (int quality)
+{
+ d->m_quality = quality;
+}
+
+
+// public static
+int kpDocumentSaveOptions::invalidQuality ()
+{
+ return -2;
+}
+
+// public static
+bool kpDocumentSaveOptions::qualityIsInvalid (int quality)
+{
+ return (quality < -1 || quality > 100);
+}
+
+// public
+bool kpDocumentSaveOptions::qualityIsInvalid () const
+{
+ return qualityIsInvalid (quality ());
+}
+
+
+// public static
+QString kpDocumentSaveOptions::defaultMimeType (KConfigBase *config)
+{
+ return config->readEntry (kpSettingForcedMimeType,
+ QString::fromLatin1 ("image/png"));
+}
+
+// public static
+void kpDocumentSaveOptions::saveDefaultMimeType (KConfigBase *config,
+ const QString &mimeType)
+{
+ config->writeEntry (kpSettingForcedMimeType, mimeType);
+}
+
+
+// public static
+int kpDocumentSaveOptions::defaultColorDepth (KConfigBase *config)
+{
+ int colorDepth =
+ config->readNumEntry (kpSettingForcedColorDepth, -1);
+
+ if (colorDepthIsInvalid (colorDepth))
+ {
+ // (not screen depth, in case of transparency)
+ colorDepth = 32;
+ }
+
+ return colorDepth;
+}
+
+// public static
+void kpDocumentSaveOptions::saveDefaultColorDepth (KConfigBase *config, int colorDepth)
+{
+ config->writeEntry (kpSettingForcedColorDepth, colorDepth);
+}
+
+
+// public static
+int kpDocumentSaveOptions::defaultDither (KConfigBase *config)
+{
+ return config->readBoolEntry (kpSettingForcedDither, initialDither ());
+}
+
+// public static
+void kpDocumentSaveOptions::saveDefaultDither (KConfigBase *config, bool dither)
+{
+ config->writeEntry (kpSettingForcedDither, dither);
+}
+
+
+// public static
+int kpDocumentSaveOptions::defaultQuality (KConfigBase *config)
+{
+ int val = config->readNumEntry (kpSettingForcedQuality, -1);
+ if (qualityIsInvalid (val))
+ val = -1;
+
+ return val;
+}
+
+// public static
+void kpDocumentSaveOptions::saveDefaultQuality (KConfigBase *config, int quality)
+{
+ config->writeEntry (kpSettingForcedQuality, quality);
+}
+
+
+// public static
+kpDocumentSaveOptions kpDocumentSaveOptions::defaultDocumentSaveOptions (KConfigBase *config)
+{
+ kpDocumentSaveOptions saveOptions;
+ saveOptions.setMimeType (defaultMimeType (config));
+ saveOptions.setColorDepth (defaultColorDepth (config));
+ saveOptions.setDither (defaultDither (config));
+ saveOptions.setQuality (defaultQuality (config));
+
+#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS
+ saveOptions.printDebug ("kpDocumentSaveOptions::defaultDocumentSaveOptions()");
+#endif
+
+ return saveOptions;
+}
+
+// public static
+bool kpDocumentSaveOptions::saveDefaultDifferences (KConfigBase *config,
+ const kpDocumentSaveOptions &oldDocInfo,
+ const kpDocumentSaveOptions &newDocInfo)
+{
+ bool savedSomething = false;
+
+#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS
+ kdDebug () << "kpDocumentSaveOptions::saveDefaultDifferences()" << endl;
+ oldDocInfo.printDebug ("\told");
+ newDocInfo.printDebug ("\tnew");
+#endif
+
+ if (newDocInfo.mimeType () != oldDocInfo.mimeType ())
+ {
+ saveDefaultMimeType (config, newDocInfo.mimeType ());
+ savedSomething = true;
+ }
+
+ if (newDocInfo.colorDepth () != oldDocInfo.colorDepth ())
+ {
+ saveDefaultColorDepth (config, newDocInfo.colorDepth ());
+ savedSomething = true;
+ }
+
+ if (newDocInfo.dither () != oldDocInfo.dither ())
+ {
+ saveDefaultDither (config, newDocInfo.dither ());
+ savedSomething = true;
+ }
+
+ if (newDocInfo.quality () != oldDocInfo.quality ())
+ {
+ saveDefaultQuality (config, newDocInfo.quality ());
+ savedSomething = true;
+ }
+
+ return savedSomething;
+}
+
+
+static QStringList mimeTypesSupportingProperty (const QString &property,
+ const QStringList &defaultMimeTypesWithPropertyList)
+{
+ QStringList mimeTypeList;
+
+ KConfigGroupSaver cfgGroupSaver (KGlobal::config (),
+ kpSettingsGroupMimeTypeProperties);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ if (cfg->hasKey (property))
+ {
+ mimeTypeList = cfg->readListEntry (property);
+ }
+ else
+ {
+ mimeTypeList = defaultMimeTypesWithPropertyList;
+
+ cfg->writeEntry (property, mimeTypeList);
+ cfg->sync ();
+ }
+
+ return mimeTypeList;
+}
+
+static bool mimeTypeSupportsProperty (const QString &mimeType,
+ const QString &property, const QStringList &defaultMimeTypesWithPropertyList)
+{
+ const QStringList mimeTypeList = mimeTypesSupportingProperty (
+ property, defaultMimeTypesWithPropertyList);
+
+ return mimeTypeList.contains (mimeType);
+}
+
+
+// SYNC: update mime info
+//
+// Only care about writable mimetypes.
+//
+// Run "branches/kolourpaint/control/scripts/gen_mimetype_line.sh Write" in
+// the version of kdelibs/kimgio/ (e.g. KDE 3.5) KolourPaint is shipped with,
+// to check for any new mimetypes to add info for. In the methods below,
+// you can specify this info (maximum color depth, whether it's lossy etc.).
+//
+// Update the below list also and bump up "kpSettingsGroupMimeTypeProperties"
+// in kpdefs.h.
+//
+// Currently, Depth and Quality settings are mutually exclusive with
+// Depth overriding Quality. I've currently favoured Quality with the
+// below mimetypes (i.e. all lossy mimetypes are only given Quality settings,
+// no Depth settings).
+//
+// Mimetypes done:
+// image/jp2 [UNTESTED]
+// image/jpeg
+// image/png
+// image/x-bmp
+// image/x-eps
+// image/x-pcx
+// image/x-portable-bitmap
+// image/x-portable-greymap
+// image/x-portable-pixmap
+// image/x-rgb
+// image/x-targa
+// image/x-xbm
+// image/x-xpm
+//
+// To test whether depth is configurable, write an image in the new
+// mimetype with all depths and read each one back. See what
+// kpDocument thinks the depth is when it gets QImage to read it.
+
+
+// public static
+int kpDocumentSaveOptions::mimeTypeMaximumColorDepth (const QString &mimeType)
+{
+ QStringList defaultList;
+
+ // SYNC: update mime info here
+
+ // Greyscale actually (unenforced since depth not set to configurable)
+ defaultList << QString::fromLatin1 ("image/x-eps:32");
+
+ defaultList << QString::fromLatin1 ("image/x-portable-bitmap:1");
+
+ // Greyscale actually (unenforced since depth not set to configurable)
+ defaultList << QString::fromLatin1 ("image/x-portable-greymap:8");
+
+ defaultList << QString::fromLatin1 ("image/x-xbm:1");
+
+ const QStringList mimeTypeList = mimeTypesSupportingProperty (
+ kpSettingMimeTypeMaximumColorDepth, defaultList);
+
+ const QString mimeTypeColon = mimeType + QString::fromLatin1 (":");
+ for (QStringList::const_iterator it = mimeTypeList.begin ();
+ it != mimeTypeList.end ();
+ it++)
+ {
+ if ((*it).startsWith (mimeTypeColon))
+ {
+ int number = (*it).mid (mimeTypeColon.length ()).toInt ();
+ if (!colorDepthIsInvalid (number))
+ {
+ return number;
+ }
+ }
+ }
+
+ return 32;
+}
+
+// public
+int kpDocumentSaveOptions::mimeTypeMaximumColorDepth () const
+{
+ return mimeTypeMaximumColorDepth (mimeType ());
+}
+
+
+// public static
+bool kpDocumentSaveOptions::mimeTypeHasConfigurableColorDepth (const QString &mimeType)
+{
+ QStringList defaultMimeTypes;
+
+ // SYNC: update mime info here
+ defaultMimeTypes << QString::fromLatin1 ("image/png");
+ defaultMimeTypes << QString::fromLatin1 ("image/x-bmp");
+ defaultMimeTypes << QString::fromLatin1 ("image/x-pcx");
+
+ // TODO: Only 1, 24 not 8; Qt only sees 32 but "file" cmd realises
+ // it's either 1 or 24.
+ defaultMimeTypes << QString::fromLatin1 ("image/x-rgb");
+
+ // TODO: Only 8 and 24 - no 1.
+ defaultMimeTypes << QString::fromLatin1 ("image/x-xpm");
+
+ return mimeTypeSupportsProperty (mimeType,
+ kpSettingMimeTypeHasConfigurableColorDepth,
+ defaultMimeTypes);
+}
+
+// public
+bool kpDocumentSaveOptions::mimeTypeHasConfigurableColorDepth () const
+{
+ return mimeTypeHasConfigurableColorDepth (mimeType ());
+}
+
+
+// public static
+bool kpDocumentSaveOptions::mimeTypeHasConfigurableQuality (const QString &mimeType)
+{
+ QStringList defaultMimeTypes;
+
+ // SYNC: update mime info here
+ defaultMimeTypes << QString::fromLatin1 ("image/jp2");
+ defaultMimeTypes << QString::fromLatin1 ("image/jpeg");
+
+ return mimeTypeSupportsProperty (mimeType,
+ kpSettingMimeTypeHasConfigurableQuality,
+ defaultMimeTypes);
+}
+
+// public
+bool kpDocumentSaveOptions::mimeTypeHasConfigurableQuality () const
+{
+ return mimeTypeHasConfigurableQuality (mimeType ());
+}
+
+
+// public
+int kpDocumentSaveOptions::isLossyForSaving (const QPixmap &pixmap) const
+{
+ int ret = 0;
+
+ if (mimeTypeMaximumColorDepth () < pixmap.depth ())
+ {
+ ret |= MimeTypeMaximumColorDepthLow;
+ }
+
+ if (mimeTypeHasConfigurableColorDepth () &&
+ !colorDepthIsInvalid () /*TODO: prevent*/ &&
+ (colorDepth () < pixmap.depth () ||
+ colorDepth () < 32 && pixmap.mask ()))
+ {
+ ret |= ColorDepthLow;
+ }
+
+ if (mimeTypeHasConfigurableQuality () &&
+ !qualityIsInvalid ())
+ {
+ ret |= Quality;
+ }
+
+ return ret;
+}
+
diff --git a/kolourpaint/kpdocumentsaveoptions.h b/kolourpaint/kpdocumentsaveoptions.h
new file mode 100644
index 00000000..0d77ec2c
--- /dev/null
+++ b/kolourpaint/kpdocumentsaveoptions.h
@@ -0,0 +1,150 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef KP_DOCUMENT_SAVE_OPTIONS_H
+#define KP_DOCUMENT_SAVE_OPTIONS_H
+
+
+class QPixmap;
+class QString;
+
+class KConfigBase;
+
+
+class kpDocumentSaveOptions
+{
+public:
+ kpDocumentSaveOptions ();
+ kpDocumentSaveOptions (const kpDocumentSaveOptions &rhs);
+ kpDocumentSaveOptions (QString mimeType, int colorDepth, bool dither, int quality);
+ virtual ~kpDocumentSaveOptions ();
+
+ bool operator== (const kpDocumentSaveOptions &rhs) const;
+ bool operator!= (const kpDocumentSaveOptions &rhs) const;
+
+ kpDocumentSaveOptions &operator= (const kpDocumentSaveOptions &rhs);
+
+
+ void printDebug (const QString &prefix) const;
+
+
+ QString mimeType () const;
+ void setMimeType (const QString &mimeType);
+
+ static QString invalidMimeType ();
+ static bool mimeTypeIsInvalid (const QString &mimeType);
+ bool mimeTypeIsInvalid () const;
+
+
+ int colorDepth () const;
+ void setColorDepth (int depth);
+
+ static int invalidColorDepth ();
+ static bool colorDepthIsInvalid (int colorDepth);
+ bool colorDepthIsInvalid () const;
+
+
+ bool dither () const;
+ void setDither (bool dither);
+
+ static int initialDither ();
+
+
+ int quality () const;
+ void setQuality (int quality);
+
+ static int invalidQuality ();
+ static bool qualityIsInvalid (int quality);
+ bool qualityIsInvalid () const;
+
+
+ // (All assume that <config>'s group has been set)
+ // (None of them call KConfigBase::reparseConfig() nor KConfigBase::sync())
+
+ static QString defaultMimeType (KConfigBase *config);
+ static void saveDefaultMimeType (KConfigBase *config, const QString &mimeType);
+
+ static int defaultColorDepth (KConfigBase *config);
+ static void saveDefaultColorDepth (KConfigBase *config, int colorDepth);
+
+ static int defaultDither (KConfigBase *config);
+ static void saveDefaultDither (KConfigBase *config, bool dither);
+
+ static int defaultQuality (KConfigBase *config);
+ static void saveDefaultQuality (KConfigBase *config, int quality);
+
+
+ static kpDocumentSaveOptions defaultDocumentSaveOptions (KConfigBase *config);
+ // (returns true if it encountered a difference (and saved it to <config>))
+ static bool saveDefaultDifferences (KConfigBase *config,
+ const kpDocumentSaveOptions &oldDocInfo,
+ const kpDocumentSaveOptions &newDocInfo);
+
+
+public:
+ // (purely for informational purposes - not enforced by this class)
+ static int mimeTypeMaximumColorDepth (const QString &mimeType);
+ int mimeTypeMaximumColorDepth () const;
+
+
+ static bool mimeTypeHasConfigurableColorDepth (const QString &mimeType);
+ bool mimeTypeHasConfigurableColorDepth () const;
+
+ static bool mimeTypeHasConfigurableQuality (const QString &mimeType);
+ bool mimeTypeHasConfigurableQuality () const;
+
+
+ // TODO: checking for mask loss due to format e.g. BMP
+ enum LossyType
+ {
+ LossLess = 0,
+
+ // mimeTypeMaximumColorDepth() < <pixmap>.depth()
+ MimeTypeMaximumColorDepthLow = 1,
+ // i.e. colorDepth() < <pixmap>.depth() ||
+ // colorDepth() < 32 && <pixmap>.mask()
+ ColorDepthLow = 2,
+ // i.e. mimeTypeHasConfigurableQuality()
+ Quality = 4
+ };
+
+ // Returns whether saving <pixmap> with these options will result in
+ // loss of information. Returned value is the bitwise OR of
+ // LossType enum possiblities.
+ int isLossyForSaving (const QPixmap &pixmap) const;
+
+
+private:
+ // There is no need to maintain binary compatibility at this stage.
+ // The d-pointer is just so that you can experiment without recompiling
+ // the kitchen sink.
+ class kpDocumentSaveOptionsPrivate *d;
+};
+
+
+#endif // KP_DOCUMENT_SAVE_OPTIONS_H
diff --git a/kolourpaint/kpdocumentsaveoptionswidget.cpp b/kolourpaint/kpdocumentsaveoptionswidget.cpp
new file mode 100644
index 00000000..39edf5b8
--- /dev/null
+++ b/kolourpaint/kpdocumentsaveoptionswidget.cpp
@@ -0,0 +1,951 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET 0
+
+
+#include <kpdocumentsaveoptionswidget.h>
+
+#include <qapplication.h>
+#include <qbuffer.h>
+#include <qimage.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qtimer.h>
+
+#include <kcombobox.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kdialog.h>
+#include <kdialogbase.h>
+#include <kglobal.h>
+#include <kimageio.h>
+#include <klocale.h>
+#include <knuminput.h>
+#include <kpushbutton.h>
+
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kppixmapfx.h>
+#include <kpresizesignallinglabel.h>
+#include <kpselection.h>
+#include <kptoolpreviewdialog.h>
+#include <kpwidgetmapper.h>
+
+
+// protected static
+const QSize kpDocumentSaveOptionsPreviewDialog::s_pixmapLabelMinimumSize (25, 25);
+
+
+kpDocumentSaveOptionsPreviewDialog::kpDocumentSaveOptionsPreviewDialog (
+ QWidget *parent,
+ const char *name)
+ : QWidget (parent, name,
+ Qt::WType_TopLevel |
+ Qt::WStyle_Customize |
+ Qt::WStyle_DialogBorder |
+ Qt::WStyle_Title),
+#if 0
+KDialogBase (parent, name, false/*non-modal*/,
+ i18n ("Save Preview"),
+ 0/*no buttons*/),
+#endif
+ m_filePixmap (0),
+ m_fileSize (0)
+{
+ setCaption (i18n ("Save Preview"));
+
+ QWidget *baseWidget = this;//new QWidget (this);
+ //setMainWidget (baseWidget);
+
+
+ QGridLayout *lay = new QGridLayout (baseWidget, 2, 1,
+ KDialog::marginHint (), KDialog::spacingHint ());
+
+ m_filePixmapLabel = new kpResizeSignallingLabel (baseWidget);
+ m_fileSizeLabel = new QLabel (baseWidget);
+
+
+ m_filePixmapLabel->setMinimumSize (s_pixmapLabelMinimumSize);
+
+
+ lay->addWidget (m_filePixmapLabel, 0, 0);
+ lay->addWidget (m_fileSizeLabel, 1, 0, Qt::AlignHCenter);
+
+
+ lay->setRowStretch (0, 1);
+
+
+ connect (m_filePixmapLabel, SIGNAL (resized ()),
+ this, SLOT (updatePixmapPreview ()));
+}
+
+kpDocumentSaveOptionsPreviewDialog::~kpDocumentSaveOptionsPreviewDialog ()
+{
+ delete m_filePixmap;
+}
+
+
+// public
+QSize kpDocumentSaveOptionsPreviewDialog::preferredMinimumSize () const
+{
+ const int contentsWidth = 180;
+ const int totalMarginsWidth = 2 * KDialog::marginHint ();
+
+ return QSize (contentsWidth + totalMarginsWidth,
+ contentsWidth * 3 / 4 + totalMarginsWidth);
+}
+
+
+// public slot
+void kpDocumentSaveOptionsPreviewDialog::setFilePixmapAndSize (const QPixmap &pixmap,
+ int fileSize)
+{
+ delete m_filePixmap;
+ m_filePixmap = new QPixmap (pixmap);
+
+ updatePixmapPreview ();
+
+ m_fileSize = fileSize;
+
+ const int pixmapSize = kpPixmapFX::pixmapSize (pixmap);
+ const int percent = pixmapSize ?
+ QMAX (1, fileSize * 100 / pixmapSize) :
+ 0;
+#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "kpDocumentSaveOptionsPreviewDialog::setFilePixmapAndSize()"
+ << " pixmapSize=" << pixmapSize
+ << " fileSize=" << fileSize
+ << " raw fileSize/pixmapSize%="
+ << (pixmapSize ? fileSize * 100 / pixmapSize : 0)
+ << endl;
+#endif
+
+ // HACK: I don't know if the percentage thing will work well and we're
+ // really close to the message freeze so provide alt. texts to choose
+ // from during the message freeze :)
+ const QString alternateText0 = i18n ("%1 bytes");
+ const QString alternateText1 = i18n ("%1 bytes (%2%)");
+ const QString alternateText2 = i18n ("%1 B");
+ const QString alternateText3 = i18n ("%1 B (%2%)");
+ const QString alternateText4 = i18n ("%1 B (approx. %2%)");
+ const QString alternateText5 = i18n ("%1B");
+ const QString alternateText6 = i18n ("%1B (%2%)");
+ const QString alternateText7 = i18n ("%1B (approx. %2%)");
+ m_fileSizeLabel->setText (i18n ("%1 bytes (approx. %2%)")
+ .arg (KGlobal::locale ()->formatLong (m_fileSize))
+ .arg (percent));
+}
+
+// public slot
+void kpDocumentSaveOptionsPreviewDialog::updatePixmapPreview ()
+{
+#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "kpDocumentSaveOptionsPreviewDialog::updatePreviewPixmap()"
+ << " filePixmapLabel.size=" << m_filePixmapLabel->size ()
+ << " filePixmap.size=" << m_filePixmap->size ()
+ << endl;
+#endif
+
+ if (m_filePixmap)
+ {
+ int maxNewWidth = QMIN (m_filePixmap->width (),
+ m_filePixmapLabel->width ()),
+ maxNewHeight = QMIN (m_filePixmap->height (),
+ m_filePixmapLabel->height ());
+
+ double keepsAspect = kpToolPreviewDialog::aspectScale (
+ maxNewWidth, maxNewHeight,
+ m_filePixmap->width (), m_filePixmap->height ());
+ #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "\tmaxNewWidth=" << maxNewWidth
+ << " maxNewHeight=" << maxNewHeight
+ << " keepsAspect=" << keepsAspect
+ << endl;
+ #endif
+
+
+ const int newWidth = kpToolPreviewDialog::scaleDimension (
+ m_filePixmap->width (),
+ keepsAspect,
+ 1,
+ maxNewWidth);
+ const int newHeight = kpToolPreviewDialog::scaleDimension (
+ m_filePixmap->height (),
+ keepsAspect,
+ 1,
+ maxNewHeight);
+ #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "\tnewWidth=" << newWidth
+ << " newHeight=" << newHeight
+ << endl;
+ #endif
+
+
+ QPixmap transformedPixmap =
+ kpPixmapFX::scale (*m_filePixmap,
+ newWidth, newHeight);
+
+
+ QPixmap labelPixmap (m_filePixmapLabel->width (),
+ m_filePixmapLabel->height ());
+ kpPixmapFX::fill (&labelPixmap, kpColor::transparent);
+ kpPixmapFX::setPixmapAt (&labelPixmap,
+ (labelPixmap.width () - transformedPixmap.width ()) / 2,
+ (labelPixmap.height () - transformedPixmap.height ()) / 2,
+ transformedPixmap);
+
+
+ m_filePixmapLabel->setPixmap (labelPixmap);
+ }
+ else
+ {
+ m_filePixmapLabel->setPixmap (QPixmap ());
+ }
+}
+
+
+// protected virtual [base QWidget]
+void kpDocumentSaveOptionsPreviewDialog::closeEvent (QCloseEvent *e)
+{
+#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "kpDocumentSaveOptionsPreviewDialog::closeEvent()" << endl;
+#endif
+
+ QWidget::closeEvent (e);
+
+ emit finished ();
+}
+
+// protected virtual [base QWidget]
+void kpDocumentSaveOptionsPreviewDialog::moveEvent (QMoveEvent *e)
+{
+#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "kpDocumentSaveOptionsPreviewDialog::moveEvent()" << endl;
+#endif
+
+ QWidget::moveEvent (e);
+
+ emit moved ();
+}
+
+// protected virtual [base QWidget]
+void kpDocumentSaveOptionsPreviewDialog::resizeEvent (QResizeEvent *e)
+{
+#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "kpDocumentSaveOptionsPreviewDialog::resizeEvent()" << endl;
+#endif
+
+ QWidget::resizeEvent (e);
+
+ emit resized ();
+}
+
+
+kpDocumentSaveOptionsWidget::kpDocumentSaveOptionsWidget (
+ const QPixmap &docPixmap,
+ const kpDocumentSaveOptions &saveOptions,
+ const kpDocumentMetaInfo &metaInfo,
+ QWidget *parent, const char *name)
+ : QWidget (parent, name),
+ m_visualParent (parent)
+{
+ init ();
+ setDocumentSaveOptions (saveOptions);
+ setDocumentPixmap (docPixmap);
+ setDocumentMetaInfo (metaInfo);
+}
+
+kpDocumentSaveOptionsWidget::kpDocumentSaveOptionsWidget (
+ QWidget *parent, const char *name)
+ : QWidget (parent, name),
+ m_visualParent (parent)
+{
+ init ();
+}
+
+// private
+void kpDocumentSaveOptionsWidget::init ()
+{
+ m_documentPixmap = 0;
+ m_previewDialog = 0;
+ m_visualParent = 0;
+
+
+ m_colorDepthLabel = new QLabel (i18n ("Convert &to:"), this);
+ m_colorDepthCombo = new KComboBox (this);
+
+ m_colorDepthSpaceWidget = new QWidget (this);
+
+ m_qualityLabel = new QLabel (i18n ("Quali&ty:"), this);
+ m_qualityInput = new KIntNumInput (this);
+ // Note that we set min to 1 not 0 since "0 Quality" is a bit misleading
+ // and 101 quality settings would be weird. So we lose 1 quality setting
+ // according to QImage::save().
+ // TODO: 100 quality is also misleading since that implies perfect quality.
+ m_qualityInput->setRange (1, 100, 1/*step*/, true/*slider*/);
+
+ m_previewButton = new KPushButton (i18n ("&Preview"), this);
+ m_previewButton->setToggleButton (true);
+
+
+ m_colorDepthLabel->setBuddy (m_colorDepthCombo);
+
+ m_qualityLabel->setBuddy (m_qualityInput);
+
+
+ QHBoxLayout *lay = new QHBoxLayout (this, 0/*margin*/, KDialog::spacingHint ());
+
+ lay->addWidget (m_colorDepthLabel, 0/*stretch*/, Qt::AlignLeft);
+ lay->addWidget (m_colorDepthCombo, 0/*stretch*/);
+
+ lay->addWidget (m_colorDepthSpaceWidget, 1/*stretch*/);
+
+ lay->addWidget (m_qualityLabel, 0/*stretch*/, Qt::AlignLeft);
+ lay->addWidget (m_qualityInput, 2/*stretch*/);
+
+ lay->addWidget (m_previewButton, 0/*stretch*/, Qt::AlignRight);
+
+
+ connect (m_colorDepthCombo, SIGNAL (activated (int)),
+ this, SLOT (slotColorDepthSelected ()));
+ connect (m_colorDepthCombo, SIGNAL (activated (int)),
+ this, SLOT (updatePreview ()));
+
+ connect (m_qualityInput, SIGNAL (valueChanged (int)),
+ this, SLOT (updatePreviewDelayed ()));
+
+ connect (m_previewButton, SIGNAL (toggled (bool)),
+ this, SLOT (showPreview (bool)));
+
+
+ m_updatePreviewDelay = 200/*ms*/;
+
+ m_updatePreviewTimer = new QTimer (this);
+ connect (m_updatePreviewTimer, SIGNAL (timeout ()),
+ this, SLOT (updatePreview ()));
+
+ m_updatePreviewDialogLastRelativeGeometryTimer = new QTimer (this);
+ connect (m_updatePreviewDialogLastRelativeGeometryTimer, SIGNAL (timeout ()),
+ this, SLOT (updatePreviewDialogLastRelativeGeometry ()));
+
+
+ setMode (None);
+
+ slotColorDepthSelected ();
+}
+
+kpDocumentSaveOptionsWidget::~kpDocumentSaveOptionsWidget ()
+{
+#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "kpDocumentSaveOptionsWidget::<dtor>()" << endl;
+#endif
+ hidePreview ();
+
+ delete m_documentPixmap;
+}
+
+
+// public
+void kpDocumentSaveOptionsWidget::setVisualParent (QWidget *visualParent)
+{
+#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "kpDocumentSaveOptionsWidget::setVisualParent("
+ << visualParent << ")" << endl;
+#endif
+
+ m_visualParent = visualParent;
+}
+
+
+// protected
+bool kpDocumentSaveOptionsWidget::mimeTypeHasConfigurableColorDepth () const
+{
+ return kpDocumentSaveOptions::mimeTypeHasConfigurableColorDepth (mimeType ());
+}
+
+// protected
+bool kpDocumentSaveOptionsWidget::mimeTypeHasConfigurableQuality () const
+{
+ return kpDocumentSaveOptions::mimeTypeHasConfigurableQuality (mimeType ());
+}
+
+
+// public
+QString kpDocumentSaveOptionsWidget::mimeType () const
+{
+ return m_baseDocumentSaveOptions.mimeType ();
+}
+
+// public slots
+void kpDocumentSaveOptionsWidget::setMimeType (const QString &string)
+{
+#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "kpDocumentSaveOptionsWidget::setMimeType(" << string
+ << ") maxColorDepth="
+ << kpDocumentSaveOptions::mimeTypeMaximumColorDepth (string)
+ << endl;
+#endif
+
+ const int newMimeTypeMaxDepth =
+ kpDocumentSaveOptions::mimeTypeMaximumColorDepth (string);
+
+#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "\toldMimeType=" << mimeType ()
+ << " maxColorDepth="
+ << kpDocumentSaveOptions::mimeTypeMaximumColorDepth (
+ mimeType ())
+ << endl;
+#endif
+
+ if (mimeType ().isEmpty () ||
+ kpDocumentSaveOptions::mimeTypeMaximumColorDepth (mimeType ()) !=
+ newMimeTypeMaxDepth)
+ {
+ m_colorDepthCombo->clear ();
+
+ m_colorDepthCombo->insertItem (i18n ("Monochrome"), 0);
+ m_colorDepthCombo->insertItem (i18n ("Monochrome (Dithered)"), 1);
+
+ if (newMimeTypeMaxDepth >= 8)
+ {
+ m_colorDepthCombo->insertItem (i18n ("256 Color"), 2);
+ m_colorDepthCombo->insertItem (i18n ("256 Color (Dithered)"), 3);
+ }
+
+ if (newMimeTypeMaxDepth >= 24)
+ {
+ m_colorDepthCombo->insertItem (i18n ("24-bit Color"), 4);
+ }
+
+ if (m_colorDepthComboLastSelectedItem >= 0 &&
+ m_colorDepthComboLastSelectedItem < m_colorDepthCombo->count ())
+ {
+ #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "\tsetting colorDepthCombo to "
+ << m_colorDepthComboLastSelectedItem << endl;
+ #endif
+
+ m_colorDepthCombo->setCurrentItem (m_colorDepthComboLastSelectedItem);
+ }
+ else
+ {
+ #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "\tsetting colorDepthCombo to max item since"
+ << " m_colorDepthComboLastSelectedItem="
+ << m_colorDepthComboLastSelectedItem
+ << " out of range" << endl;
+ #endif
+
+ m_colorDepthCombo->setCurrentItem (m_colorDepthCombo->count () - 1);
+ }
+ }
+
+
+ m_baseDocumentSaveOptions.setMimeType (string);
+
+ if (mimeTypeHasConfigurableColorDepth ())
+ setMode (ColorDepth);
+ else if (mimeTypeHasConfigurableQuality ())
+ setMode (Quality);
+ else
+ setMode (None);
+
+ updatePreview ();
+}
+
+
+// public
+int kpDocumentSaveOptionsWidget::colorDepth () const
+{
+ if (mode () & ColorDepth)
+ {
+ switch (m_colorDepthCombo->currentItem ())
+ {
+ case 0:
+ case 1:
+ return 1;
+
+ case 2:
+ case 3:
+ return 8;
+
+ case 4:
+ return 32;
+
+ default:
+ return kpDocumentSaveOptions::invalidColorDepth ();
+ }
+ }
+ else
+ {
+ return m_baseDocumentSaveOptions.colorDepth ();
+ }
+}
+
+// public
+bool kpDocumentSaveOptionsWidget::dither () const
+{
+ if (mode () & ColorDepth)
+ {
+ return (m_colorDepthCombo->currentItem () == 1 ||
+ m_colorDepthCombo->currentItem () == 3);
+ }
+ else
+ {
+ return m_baseDocumentSaveOptions.dither ();
+ }
+}
+
+// protected static
+int kpDocumentSaveOptionsWidget::colorDepthComboItemFromColorDepthAndDither (
+ int depth, bool dither)
+{
+ if (depth == 1)
+ {
+ if (!dither)
+ {
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ else if (depth == 8)
+ {
+ if (!dither)
+ {
+ return 2;
+ }
+ else
+ {
+ return 3;
+ }
+ }
+ else if (depth == 32)
+ {
+ return 4;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+// public slots
+void kpDocumentSaveOptionsWidget::setColorDepthDither (int newDepth, bool newDither)
+{
+#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "kpDocumentSaveOptionsWidget::setColorDepthDither("
+ << "depth=" << newDepth
+ << ",dither=" << newDither
+ << ")" << endl;
+#endif
+
+ m_baseDocumentSaveOptions.setColorDepth (newDepth);
+ m_baseDocumentSaveOptions.setDither (newDither);
+
+
+ const int comboItem = colorDepthComboItemFromColorDepthAndDither (
+ newDepth, newDither);
+ // TODO: Ignoring when comboItem >= m_colorDepthCombo->count() is wrong.
+ // This happens if this mimeType has configurable colour depth
+ // and an incorrect maximum colour depth (less than a QImage of
+ // this mimeType, opened by kpDocument).
+ if (comboItem >= 0 && comboItem < m_colorDepthCombo->count ())
+ m_colorDepthCombo->setCurrentItem (comboItem);
+
+
+ slotColorDepthSelected ();
+}
+
+
+// protected slot
+void kpDocumentSaveOptionsWidget::slotColorDepthSelected ()
+{
+ if (mode () & ColorDepth)
+ {
+ m_colorDepthComboLastSelectedItem = m_colorDepthCombo->currentItem ();
+ }
+ else
+ {
+ m_colorDepthComboLastSelectedItem =
+ colorDepthComboItemFromColorDepthAndDither (
+ m_baseDocumentSaveOptions.colorDepth (),
+ m_baseDocumentSaveOptions.dither ());
+ }
+
+#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "kpDocumentSaveOptionsWidget::slotColorDepthSelected()"
+ << " mode&ColorDepth=" << (mode () & ColorDepth)
+ << " colorDepthComboLastSelectedItem="
+ << m_colorDepthComboLastSelectedItem
+ << endl;
+#endif
+}
+
+
+// public
+int kpDocumentSaveOptionsWidget::quality () const
+{
+ if (mode () & Quality)
+ {
+ return m_qualityInput->value ();
+ }
+ else
+ {
+ return m_baseDocumentSaveOptions.quality ();
+ }
+}
+
+// public
+void kpDocumentSaveOptionsWidget::setQuality (int newQuality)
+{
+#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "kpDocumentSaveOptionsWidget::setQuality("
+ << newQuality << ")" << endl;
+#endif
+
+ m_baseDocumentSaveOptions.setQuality (newQuality);
+ m_qualityInput->setValue (newQuality == -1/*QImage::save() default*/ ?
+ 75 :
+ newQuality);
+}
+
+
+// public
+kpDocumentSaveOptions kpDocumentSaveOptionsWidget::documentSaveOptions () const
+{
+ return kpDocumentSaveOptions (mimeType (), colorDepth (), dither (), quality ());
+}
+
+// public
+void kpDocumentSaveOptionsWidget::setDocumentSaveOptions (
+ const kpDocumentSaveOptions &saveOptions)
+{
+ setMimeType (saveOptions.mimeType ());
+ setColorDepthDither (saveOptions.colorDepth (), saveOptions.dither ());
+ setQuality (saveOptions.quality ());
+}
+
+
+// public
+void kpDocumentSaveOptionsWidget::setDocumentPixmap (const QPixmap &documentPixmap)
+{
+ delete m_documentPixmap;
+ m_documentPixmap = new QPixmap (documentPixmap);
+
+ updatePreview ();
+}
+
+// public
+void kpDocumentSaveOptionsWidget::setDocumentMetaInfo (
+ const kpDocumentMetaInfo &metaInfo)
+{
+ m_documentMetaInfo = metaInfo;
+
+ updatePreview ();
+}
+
+
+// public
+kpDocumentSaveOptionsWidget::Mode kpDocumentSaveOptionsWidget::mode () const
+{
+ return m_mode;
+}
+
+// public
+void kpDocumentSaveOptionsWidget::setMode (Mode mode)
+{
+ m_mode = mode;
+
+
+ // If mode == None, we show still show the Color Depth widgets but disabled
+ m_colorDepthLabel->setShown (mode != Quality);
+ m_colorDepthCombo->setShown (mode != Quality);
+ m_colorDepthSpaceWidget->setShown (mode != Quality);
+
+ m_qualityLabel->setShown (mode == Quality);
+ m_qualityInput->setShown (mode == Quality);
+
+
+ m_colorDepthLabel->setEnabled (mode == ColorDepth);
+ m_colorDepthCombo->setEnabled (mode == ColorDepth);
+
+ m_qualityLabel->setEnabled (mode == Quality);
+ m_qualityInput->setEnabled (mode == Quality);
+
+
+ // SYNC: HACK: When changing between color depth and quality widgets,
+ // we change the height of "this", causing the text on the labels
+ // to move but the first instance of the text doesn't get erased.
+ // Qt bug.
+ QTimer::singleShot (0, this, SLOT (repaintLabels ()));
+}
+
+// protected slot
+void kpDocumentSaveOptionsWidget::repaintLabels ()
+{
+ if (mode () != Quality)
+ m_colorDepthLabel->repaint ();
+ if (mode () == Quality)
+ m_qualityLabel->repaint ();
+}
+
+
+// protected slot
+void kpDocumentSaveOptionsWidget::showPreview (bool yes)
+{
+#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "kpDocumentSaveOptionsWidget::showPreview(" << yes << ")"
+ << " m_previewDialog=" << bool (m_previewDialog)
+ << endl;
+#endif
+
+ if (yes == bool (m_previewDialog))
+ return;
+
+ if (!m_visualParent)
+ return;
+
+ if (yes)
+ {
+ m_previewDialog = new kpDocumentSaveOptionsPreviewDialog (m_visualParent, "previewSaveDialog");
+ updatePreview ();
+
+ connect (m_previewDialog, SIGNAL (finished ()),
+ this, SLOT (hidePreview ()));
+
+
+ KConfigGroupSaver cfgGroupSaver (KGlobal::config (), kpSettingsGroupPreviewSave);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ if (cfg->hasKey (kpSettingPreviewSaveUpdateDelay))
+ {
+ m_updatePreviewDelay = cfg->readNumEntry (kpSettingPreviewSaveUpdateDelay);
+ }
+ else
+ {
+ cfg->writeEntry (kpSettingPreviewSaveUpdateDelay, m_updatePreviewDelay);
+ cfg->sync ();
+ }
+
+ if (m_updatePreviewDelay < 0)
+ m_updatePreviewDelay = 0;
+ #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "\tread cfg preview dialog update delay="
+ << m_updatePreviewDelay
+ << endl;
+ #endif
+
+
+ if (m_previewDialogLastRelativeGeometry.isEmpty ())
+ {
+ #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "\tread cfg preview dialog last rel geometry" << endl;
+ #endif
+ KConfigGroupSaver cfgGroupSaver (KGlobal::config (), kpSettingsGroupPreviewSave);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ m_previewDialogLastRelativeGeometry = cfg->readRectEntry (
+ kpSettingPreviewSaveGeometry);
+ }
+
+ #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "\tpreviewDialogLastRelativeGeometry="
+ << m_previewDialogLastRelativeGeometry
+ << " visualParent->rect()=" << m_visualParent->rect ()
+ << endl;
+ #endif
+
+ QRect relativeGeometry;
+ if (!m_previewDialogLastRelativeGeometry.isEmpty () &&
+ m_visualParent->rect ().intersects (m_previewDialogLastRelativeGeometry))
+ {
+ #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "\tok" << endl;
+ #endif
+ relativeGeometry = m_previewDialogLastRelativeGeometry;
+ }
+ else
+ {
+ #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "\t\tinvalid" << endl;
+ #endif
+ const int margin = 20;
+
+ relativeGeometry =
+ QRect (m_visualParent->width () -
+ m_previewDialog->preferredMinimumSize ().width () -
+ margin,
+ margin * 2, // Avoid folder combo
+ m_previewDialog->preferredMinimumSize ().width (),
+ m_previewDialog->preferredMinimumSize ().height ());
+ }
+
+
+ const QRect globalGeometry =
+ kpWidgetMapper::toGlobal (m_visualParent,
+ relativeGeometry);
+ #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "\trelativeGeometry=" << relativeGeometry
+ << " globalGeometry=" << globalGeometry
+ << endl;
+ #endif
+
+ m_previewDialog->resize (globalGeometry.size ());
+ m_previewDialog->move (globalGeometry.topLeft ());
+
+
+ m_previewDialog->show ();
+
+
+ #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "\tgeometry after show="
+ << QRect (m_previewDialog->x (), m_previewDialog->y (),
+ m_previewDialog->width (), m_previewDialog->height ())
+ << endl;
+ #endif
+
+ updatePreviewDialogLastRelativeGeometry ();
+
+ connect (m_previewDialog, SIGNAL (moved ()),
+ this, SLOT (updatePreviewDialogLastRelativeGeometry ()));
+ connect (m_previewDialog, SIGNAL (resized ()),
+ this, SLOT (updatePreviewDialogLastRelativeGeometry ()));
+
+ m_updatePreviewDialogLastRelativeGeometryTimer->start (200/*ms*/);
+ }
+ else
+ {
+ m_updatePreviewDialogLastRelativeGeometryTimer->stop ();
+
+ KConfigGroupSaver cfgGroupSaver (KGlobal::config (), kpSettingsGroupPreviewSave);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ cfg->writeEntry (kpSettingPreviewSaveGeometry, m_previewDialogLastRelativeGeometry);
+ cfg->sync ();
+
+ #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "\tsaving preview geometry "
+ << m_previewDialogLastRelativeGeometry
+ << " (Qt would have us believe "
+ << kpWidgetMapper::fromGlobal (m_visualParent,
+ QRect (m_previewDialog->x (), m_previewDialog->y (),
+ m_previewDialog->width (), m_previewDialog->height ()))
+ << ")"
+ << endl;
+ #endif
+
+ m_previewDialog->deleteLater ();
+ m_previewDialog = 0;
+ }
+}
+
+// protected slot
+void kpDocumentSaveOptionsWidget::hidePreview ()
+{
+ if (m_previewButton->isOn ())
+ m_previewButton->toggle ();
+}
+
+
+// protected slot
+void kpDocumentSaveOptionsWidget::updatePreviewDelayed ()
+{
+ m_updatePreviewTimer->start (m_updatePreviewDelay, true/*single shot*/);
+}
+
+// protected slot
+void kpDocumentSaveOptionsWidget::updatePreview ()
+{
+ if (!m_previewDialog || !m_documentPixmap)
+ return;
+
+
+ m_updatePreviewTimer->stop ();
+
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ QByteArray data;
+
+ QBuffer buffer (data);
+ buffer.open (IO_WriteOnly);
+ kpDocument::savePixmapToDevice (*m_documentPixmap,
+ &buffer,
+ documentSaveOptions (),
+ m_documentMetaInfo,
+ false/*no lossy prompt*/,
+ this);
+ buffer.close ();
+
+
+ QImage image;
+ image.loadFromData (data,
+ KImageIO::typeForMime (mimeType ()).latin1 ());
+
+ // TODO: merge with kpDocument::getPixmapFromFile()
+ m_previewDialog->setFilePixmapAndSize (
+ kpPixmapFX::convertToPixmapAsLosslessAsPossible (image),
+ data.size ());
+
+ QApplication::restoreOverrideCursor ();
+}
+
+// protected slot
+void kpDocumentSaveOptionsWidget::updatePreviewDialogLastRelativeGeometry ()
+{
+#if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "kpDocumentSaveOptionsWidget::"
+ << "updatePreviewDialogLastRelativeGeometry()"
+ << endl;
+#endif
+
+ if (m_previewDialog && m_previewDialog->isVisible ())
+ {
+ m_previewDialogLastRelativeGeometry =
+ kpWidgetMapper::fromGlobal (m_visualParent,
+ QRect (m_previewDialog->x (), m_previewDialog->y (),
+ m_previewDialog->width (), m_previewDialog->height ()));
+ #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "\tcaching pos = "
+ << m_previewDialogLastRelativeGeometry
+ << endl;
+ #endif
+ }
+ else
+ {
+ #if DEBUG_KP_DOCUMENT_SAVE_OPTIONS_WIDGET
+ kdDebug () << "\tnot visible - ignoring geometry" << endl;
+ #endif
+ }
+}
+
+
+#include <kpdocumentsaveoptionswidget.moc>
diff --git a/kolourpaint/kpdocumentsaveoptionswidget.h b/kolourpaint/kpdocumentsaveoptionswidget.h
new file mode 100644
index 00000000..50bd35aa
--- /dev/null
+++ b/kolourpaint/kpdocumentsaveoptionswidget.h
@@ -0,0 +1,200 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef KP_DOCUMENT_SAVE_OPTIONS_WIDGET_H
+#define KP_DOCUMENT_SAVE_OPTIONS_WIDGET_H
+
+
+#include <qsize.h>
+
+#include <qwidget.h>
+
+
+class QPixmap;
+class QLabel;
+
+class kpResizeSignallingLabel;
+
+
+class kpDocumentSaveOptionsPreviewDialog : public QWidget
+{
+Q_OBJECT
+
+public:
+ kpDocumentSaveOptionsPreviewDialog (QWidget *parent, const char *name = 0);
+ virtual ~kpDocumentSaveOptionsPreviewDialog ();
+
+ QSize preferredMinimumSize () const;
+
+protected:
+ static const QSize s_pixmapLabelMinimumSize;
+
+signals:
+ void moved ();
+ void resized ();
+ void finished ();
+
+public slots:
+ void setFilePixmapAndSize (const QPixmap &filePixmap, int fileSize);
+ void updatePixmapPreview ();
+
+protected:
+ virtual void closeEvent (QCloseEvent *e);
+ virtual void moveEvent (QMoveEvent *e);
+ virtual void resizeEvent (QResizeEvent *e);
+
+protected:
+ QPixmap *m_filePixmap;
+ int m_fileSize;
+
+ kpResizeSignallingLabel *m_filePixmapLabel;
+ QLabel *m_fileSizeLabel;
+};
+
+
+#include <qrect.h>
+#include <qwidget.h>
+
+#include <kpdocumentmetainfo.h>
+#include <kpdocumentsaveoptions.h>
+
+
+class QLabel;
+class QTimer;
+
+class KComboBox;
+class KIntNumInput;
+class KPushButton;
+
+
+class kpDocumentSaveOptionsWidget : public QWidget
+{
+Q_OBJECT
+
+public:
+ kpDocumentSaveOptionsWidget (const QPixmap &docPixmap,
+ const kpDocumentSaveOptions &saveOptions,
+ const kpDocumentMetaInfo &metaInfo,
+ QWidget *parent, const char *name = 0);
+ kpDocumentSaveOptionsWidget (QWidget *parent, const char *name = 0);
+private:
+ void init ();
+public:
+ virtual ~kpDocumentSaveOptionsWidget ();
+
+
+ // <visualParent> is usually the filedialog
+ void setVisualParent (QWidget *visualParent);
+
+
+protected:
+ bool mimeTypeHasConfigurableColorDepth () const;
+ bool mimeTypeHasConfigurableQuality () const;
+
+public:
+ QString mimeType () const;
+public slots:
+ void setMimeType (const QString &string);
+
+public:
+ int colorDepth () const;
+ bool dither () const;
+protected:
+ static int colorDepthComboItemFromColorDepthAndDither (int depth, bool dither);
+public slots:
+ void setColorDepthDither (int depth,
+ bool dither = kpDocumentSaveOptions::initialDither ());
+protected slots:
+ void slotColorDepthSelected ();
+
+public:
+ int quality () const;
+public slots:
+ void setQuality (int newQuality);
+
+public:
+ kpDocumentSaveOptions documentSaveOptions () const;
+public slots:
+ void setDocumentSaveOptions (const kpDocumentSaveOptions &saveOptions);
+
+
+public:
+ void setDocumentPixmap (const QPixmap &documentPixmap);
+ void setDocumentMetaInfo (const kpDocumentMetaInfo &metaInfo);
+
+
+protected:
+ enum Mode
+ {
+ // (mutually exclusive)
+ None, ColorDepth, Quality
+ };
+
+ Mode mode () const;
+ void setMode (Mode mode);
+
+protected slots:
+ void repaintLabels ();
+
+
+protected slots:
+ void showPreview (bool yes = true);
+ void hidePreview ();
+ void updatePreviewDelayed ();
+ void updatePreview ();
+ void updatePreviewDialogLastRelativeGeometry ();
+
+
+protected:
+ QWidget *m_visualParent;
+
+ Mode m_mode;
+
+ QPixmap *m_documentPixmap;
+
+ kpDocumentSaveOptions m_baseDocumentSaveOptions;
+ kpDocumentMetaInfo m_documentMetaInfo;
+
+ QLabel *m_colorDepthLabel;
+ KComboBox *m_colorDepthCombo;
+ int m_colorDepthComboLastSelectedItem;
+ QWidget *m_colorDepthSpaceWidget;
+
+ QLabel *m_qualityLabel;
+ KIntNumInput *m_qualityInput;
+
+ KPushButton *m_previewButton;
+ kpDocumentSaveOptionsPreviewDialog *m_previewDialog;
+ QRect m_previewDialogLastRelativeGeometry;
+ QTimer *m_updatePreviewTimer;
+ int m_updatePreviewDelay;
+ QTimer *m_updatePreviewDialogLastRelativeGeometryTimer;
+};
+
+
+#endif // KP_DOCUMENT_SAVE_OPTIONS_WIDGET_H
diff --git a/kolourpaint/kpmainwindow.cpp b/kolourpaint/kpmainwindow.cpp
new file mode 100644
index 00000000..9af3177b
--- /dev/null
+++ b/kolourpaint/kpmainwindow.cpp
@@ -0,0 +1,1061 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <kpmainwindow.h>
+#include <kpmainwindow_p.h>
+
+#include <qdragobject.h>
+#include <qpainter.h>
+#include <qtimer.h>
+
+#include <kactionclasses.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kurldrag.h>
+
+#include <kpcolortoolbar.h>
+#include <kpcommandhistory.h>
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kppixmapfx.h>
+#include <kpselection.h>
+#include <kpselectiondrag.h>
+#include <kpsinglekeytriggersaction.h>
+#include <kpthumbnail.h>
+#include <kptool.h>
+#include <kptooltoolbar.h>
+#include <kpviewmanager.h>
+#include <kpviewscrollablecontainer.h>
+#include <kpwidgetmapper.h>
+#include <kpzoomedthumbnailview.h>
+#include <kpzoomedview.h>
+
+#if DEBUG_KP_MAIN_WINDOW
+ #include <qdatetime.h>
+#endif
+
+
+kpMainWindow::kpMainWindow ()
+ : KMainWindow (0/*parent*/, "mainWindow"),
+ m_isFullyConstructed (false)
+{
+ init ();
+ open (KURL (), true/*create an empty doc*/);
+
+ m_isFullyConstructed = true;
+}
+
+kpMainWindow::kpMainWindow (const KURL &url)
+ : KMainWindow (0/*parent*/, "mainWindow"),
+ m_isFullyConstructed (false)
+{
+ init ();
+ open (url, true/*create an empty doc with the same url if url !exist*/);
+
+ m_isFullyConstructed = true;
+}
+
+kpMainWindow::kpMainWindow (kpDocument *newDoc)
+ : KMainWindow (0/*parent*/, "mainWindow"),
+ m_isFullyConstructed (false)
+{
+ init ();
+ setDocument (newDoc);
+
+ m_isFullyConstructed = true;
+}
+
+
+// public
+double kpMainWindow::configColorSimilarity () const
+{
+ return m_configColorSimilarity;
+}
+
+// public
+void kpMainWindow::configSetColorSimilarity (double val)
+{
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupGeneral);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ cfg->writeEntry (kpSettingColorSimilarity, m_configColorSimilarity = val);
+ cfg->sync ();
+}
+
+
+// private
+void kpMainWindow::readGeneralSettings ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tkpMainWindow(" << name () << ")::readGeneralSettings()" << endl;
+#endif
+
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupGeneral);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ m_configFirstTime = cfg->readBoolEntry (kpSettingFirstTime, true);
+ m_configShowGrid = cfg->readBoolEntry (kpSettingShowGrid, false);
+ m_configShowPath = cfg->readBoolEntry (kpSettingShowPath, false);
+ m_configColorSimilarity = cfg->readDoubleNumEntry (kpSettingColorSimilarity, 0);
+ d->m_moreEffectsDialogLastEffect = cfg->readNumEntry (kpSettingMoreEffectsLastEffect);
+ d->m_resizeScaleDialogLastKeepAspect = cfg->readBoolEntry (kpSettingResizeScaleLastKeepAspect, false);
+
+
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t\tGeneral Settings: firstTime=" << m_configFirstTime
+ << " showGrid=" << m_configShowGrid
+ << " showPath=" << m_configShowPath
+ << " colorSimilarity=" << m_configColorSimilarity
+ << " moreEffectsDialogLastEffect=" << d->m_moreEffectsDialogLastEffect
+ << " resizeScaleDialogLastKeepAspect=" << d->m_resizeScaleDialogLastKeepAspect
+ << endl;
+#endif
+}
+
+// private
+void kpMainWindow::readThumbnailSettings ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tkpMainWindow(" << name () << ")::readThumbnailSettings()" << endl;
+#endif
+
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupThumbnail);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ m_configThumbnailShown = cfg->readBoolEntry (kpSettingThumbnailShown, false);
+ m_configThumbnailGeometry = cfg->readRectEntry (kpSettingThumbnailGeometry);
+ m_configZoomedThumbnail = cfg->readBoolEntry (kpSettingThumbnailZoomed, true);
+ d->m_configThumbnailShowRectangle = cfg->readBoolEntry (kpSettingThumbnailShowRectangle, true);
+
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t\tThumbnail Settings: shown=" << m_configThumbnailShown
+ << " geometry=" << m_configThumbnailGeometry
+ << " zoomed=" << m_configZoomedThumbnail
+ << " showRectangle=" << d->m_configThumbnailShowRectangle
+ << endl;
+#endif
+}
+
+// private
+void kpMainWindow::init ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow(" << name () << ")::init()" << endl;
+ QTime totalTime; totalTime.start ();
+ QTime time; time.start ();
+#endif
+
+ d = new kpMainWindowPrivate;
+
+ m_scrollView = 0;
+ m_mainView = 0;
+ m_thumbnail = 0;
+ m_thumbnailView = 0;
+ m_document = 0;
+ m_viewManager = 0;
+ m_colorToolBar = 0;
+ m_toolToolBar = 0;
+ m_commandHistory = 0;
+ m_statusBarCreated = false;
+ m_settingSelectionTransparency = 0;
+ m_settingTextStyle = 0;
+
+ m_docResizeToBeCompleted = false;
+
+
+ //
+ // set mainwindow properties
+ //
+
+ setMinimumSize (320, 260);
+ setAcceptDrops (true);
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tTIME: little init = " << time.restart () << "msec" << endl;
+#endif
+
+
+ //
+ // read config
+ //
+
+ // KConfig::readEntry() does not actually reread from disk, hence doesn't
+ // realise what other processes have done e.g. Settings / Show Path
+ kapp->config ()->reparseConfiguration ();
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tTIME: reparseConfig = " << time.restart () << "msec" << endl;
+#endif
+
+ readGeneralSettings ();
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tTIME: readGeneralSettings = " << time.restart () << "msec" << endl;
+#endif
+
+ readThumbnailSettings ();
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tTIME: readThumbnailSettings = " << time.restart () << "msec" << endl;
+#endif
+
+
+ //
+ // create GUI
+ //
+
+ setupActions ();
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tTIME: setupActions = " << time.restart () << "msec" << endl;
+#endif
+
+ createStatusBar ();
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tTIME: createStatusBar = " << time.restart () << "msec" << endl;
+#endif
+
+ createGUI ();
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tTIME: createGUI = " << time.restart () << "msec" << endl;
+#endif
+
+
+ //
+ // create more GUI
+ //
+
+ m_colorToolBar = new kpColorToolBar (i18n ("Color Box"), this, "Color Box");
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tTIME: new kpColorToolBar = " << time.restart () << "msec" << endl;
+#endif
+
+ createToolBox ();
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tTIME: createToolBox = " << time.restart () << "msec" << endl;
+#endif
+
+ m_scrollView = new kpViewScrollableContainer (this, "scrollView");
+ connect (m_scrollView, SIGNAL (beganDocResize ()),
+ this, SLOT (slotBeganDocResize ()));
+ connect (m_scrollView, SIGNAL (continuedDocResize (const QSize &)),
+ this, SLOT (slotContinuedDocResize (const QSize &)));
+ connect (m_scrollView, SIGNAL (cancelledDocResize ()),
+ this, SLOT (slotCancelledDocResize ()));
+ connect (m_scrollView, SIGNAL (endedDocResize (const QSize &)),
+ this, SLOT (slotEndedDocResize (const QSize &)));
+
+ connect (m_scrollView, SIGNAL (statusMessageChanged (const QString &)),
+ this, SLOT (slotDocResizeMessageChanged (const QString &)));
+
+ connect (m_scrollView, SIGNAL (contentsMoving (int, int)),
+ this, SLOT (slotScrollViewAboutToScroll ()));
+ setCentralWidget (m_scrollView);
+ m_scrollView->show ();
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tTIME: m_scrollView = " << time.restart () << "msec" << endl;
+#endif
+
+
+ //
+ // set initial pos/size of GUI
+ //
+
+ setAutoSaveSettings ();
+
+ // Put our non-XMLGUI toolbars in a sane place, the first time around
+ // (have to do this _after_ setAutoSaveSettings as that applies default
+ // (i.e. random) settings to the toolbars)
+ if (m_configFirstTime)
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tfirstTime: positioning toolbars" << endl;
+ #endif
+
+ m_toolToolBar->setBarPos (KToolBar::Left);
+ m_colorToolBar->setBarPos (KToolBar::Bottom);
+
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupGeneral);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ cfg->writeEntry (kpSettingFirstTime, m_configFirstTime = false);
+ cfg->sync ();
+ }
+
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tall done in " << totalTime.elapsed () << "msec" << endl;
+#endif
+}
+
+
+// private virtual [base KMainWindow]
+void kpMainWindow::readProperties (KConfig *cfg)
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow<" << this << ">::readProperties()" << endl;
+#endif
+
+ // No document at all?
+ if (!cfg->hasKey (kpSessionSettingDocumentUrl))
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tno url - no document" << endl;
+ #endif
+ setDocument (0);
+ }
+ // Have a document.
+ else
+ {
+ const KURL url (cfg->readEntry (kpSessionSettingDocumentUrl));
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\turl=" << url << endl;
+ #endif
+
+ const QSize notFromURLDocSize =
+ cfg->readSizeEntry (kpSessionSettingNotFromUrlDocumentSize);
+
+ // Is from URL?
+ if (notFromURLDocSize.isEmpty ())
+ {
+ // If this fails, the empty document that kpMainWindow::kpMainWindow()
+ // created is left untouched.
+ openInternal (url, defaultDocSize (),
+ false/*show error message if url !exist*/);
+ }
+ // Not from URL?
+ else
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tnot from url; doc size=" << notFromURLDocSize << endl;
+ #endif
+ // Either we have an empty URL or we have a "kolourpaint doesnotexist.png"
+ // URL. Regarding the latter case, if a file now actually exists at that
+ // URL, we do open it - ignoring notFromURLDocSize - to avoid putting
+ // the user in a situation where he might accidentally overwrite an
+ // existing file.
+ openInternal (url, notFromURLDocSize,
+ true/*create an empty doc with the same url if url !exist*/);
+ }
+ }
+
+}
+
+// private virtual [base KMainWindow]
+// WARNING: KMainWindow API Doc says "No user interaction is allowed
+// in this function!"
+void kpMainWindow::saveProperties (KConfig *cfg)
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow<" << this << ">::saveProperties()" << endl;
+#endif
+
+ // No document at all?
+ if (!m_document)
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tno url - no document" << endl;
+ #endif
+ }
+ // Have a document.
+ else
+ {
+ // Save URL in all cases:
+ //
+ // a) m_document->isFromURL()
+ // b) !m_document->isFromURL() [save size in this case]
+ // i) No URL
+ // ii) URL (from "kolourpaint doesnotexist.png")
+
+ const KURL url = m_document->url ();
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\turl=" << url << endl;
+ #endif
+ cfg->writeEntry (kpSessionSettingDocumentUrl, url.url ());
+
+ // Not from URL e.g. "kolourpaint doesnotexist.png"?
+ //
+ // Note that "kolourpaint doesexist.png" is considered to be from
+ // a URL even if it was deleted in the background (hence the
+ // "false" arg to isFromURL()). This is because the user expects
+ // it to be from a URL, so when we session restore, we pop up a
+ // "cannot find file" dialog, instead of silently creating a new,
+ // blank document.
+ if (!m_document->isFromURL (false/*don't bother checking exists*/))
+ {
+ // If we don't have a URL either:
+ //
+ // a) it was not modified - so we can use either width() or
+ // constructorWidth() (they'll be equal).
+ // b) the changes were discarded so we use the initial width,
+ // constructorWidth().
+ //
+ // Similarly for height() and constructorHeight().
+ const QSize docSize (m_document->constructorWidth (),
+ m_document->constructorHeight ());
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tnot from url; doc size=" << docSize << endl;
+ #endif
+ cfg->writeEntry (kpSessionSettingNotFromUrlDocumentSize, docSize);
+ }
+
+
+ // Local session save i.e. queryClose() was not called beforehand
+ // (see QApplication::saveState())?
+ #if 0
+ if (m_document->isModified ())
+ {
+ // TODO: Implement by saving the current image to a persistent file.
+ // We do this instead of saving/mutating the backing image file
+ // as no one expects a file save on a session save without a
+ // "do you want to save" dialog first.
+ //
+ // I don't think any KDE application implements local session saving.
+ //
+ // --- The below code does not compile but shows you want to do ---
+
+ // Create unique name for the document in this main window.
+ const KURL tempURL = homeDir +
+ "kolourpaint session " + sessionID +
+ mainWindowPtrToString + ".png";
+ // TODO: Use lossless PNG saving options.
+ kpDocumentSaveOptions pngSaveOptions;
+
+ if (kpDocument::savePixmapToFile (m_document->pixmapWithSelection (),
+ tempURL,
+ pngSaveOptions, *m_document->metaInfo (),
+ false/*no overwrite prompt*/,
+ false/*no lossy prompt*/,
+ this))
+ {
+ // readProperties() will still open kpSessionSettingDocumentUrl
+ // (as that's the expected URL) and will then add commands to:
+ //
+ // 1. Resize the document to the size of image at
+ // kpSessionSettingDocumentUnsavedContentsUrl, if the sizes
+ // differ.
+ // 2. Paste the kpSessionSettingDocumentUnsavedContentsUrl image
+ // (setting the main window's selection mode to opaque beforehand).
+ //
+ // It will then delete the file at
+ // kpSessionSettingDocumentUnsavedContentsUrl.
+ cfg->writeEntry (kpSessionSettingDocumentUnsavedContentsUrl,
+ tempURL.url ());
+ }
+ else
+ {
+ // Not much we can do - we aren't allowed to throw up a dialog.
+ }
+ }
+ #endif
+ }
+}
+
+
+kpMainWindow::~kpMainWindow ()
+{
+ m_isFullyConstructed = false;
+
+ // delete document & views
+ setDocument (0);
+
+ delete m_commandHistory; m_commandHistory = 0;
+ delete m_scrollView; m_scrollView = 0;
+
+ delete d; d = 0;
+}
+
+
+// public
+kpDocument *kpMainWindow::document () const
+{
+ return m_document;
+}
+
+// public
+kpViewManager *kpMainWindow::viewManager () const
+{
+ return m_viewManager;
+}
+
+// public
+kpColorToolBar *kpMainWindow::colorToolBar () const
+{
+ return m_colorToolBar;
+}
+
+// public
+kpToolToolBar *kpMainWindow::toolToolBar () const
+{
+ return m_toolToolBar;
+}
+
+// public
+kpCommandHistory *kpMainWindow::commandHistory () const
+{
+ return m_commandHistory;
+}
+
+
+// private
+void kpMainWindow::setupActions ()
+{
+ setupFileMenuActions ();
+ setupEditMenuActions ();
+ setupViewMenuActions ();
+ setupImageMenuActions ();
+ setupSettingsMenuActions ();
+ setupHelpMenuActions ();
+
+ setupTextToolBarActions ();
+ setupToolActions ();
+}
+
+// private
+void kpMainWindow::enableDocumentActions (bool enable)
+{
+ enableFileMenuDocumentActions (enable);
+ enableEditMenuDocumentActions (enable);
+ enableViewMenuDocumentActions (enable);
+ enableImageMenuDocumentActions (enable);
+ enableSettingsMenuDocumentActions (enable);
+ enableHelpMenuDocumentActions (enable);
+}
+
+
+// public
+bool kpMainWindow::actionsSingleKeyTriggersEnabled () const
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::actionsSingleKeyTriggersEnabled()" << endl;
+ QTime timer; timer.start ();
+#endif
+
+ if (m_toolToolBar)
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\ttime=" << timer.restart () << endl;
+ #endif
+ return m_toolToolBar->toolsSingleKeyTriggersEnabled ();
+ }
+
+ return (m_actionPrevToolOptionGroup1->singleKeyTriggersEnabled () ||
+ m_actionNextToolOptionGroup1->singleKeyTriggersEnabled () ||
+ m_actionPrevToolOptionGroup2->singleKeyTriggersEnabled () ||
+ m_actionNextToolOptionGroup2->singleKeyTriggersEnabled ());
+}
+
+// public
+void kpMainWindow::enableActionsSingleKeyTriggers (bool enable)
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::enableActionsSingleKeyTriggers("
+ << enable << ")" << endl;
+ QTime timer; timer.start ();
+#endif
+
+ if (m_toolToolBar)
+ m_toolToolBar->enableToolsSingleKeyTriggers (enable);
+
+ m_actionPrevToolOptionGroup1->enableSingleKeyTriggers (enable);
+ m_actionNextToolOptionGroup1->enableSingleKeyTriggers (enable);
+ m_actionPrevToolOptionGroup2->enableSingleKeyTriggers (enable);
+ m_actionNextToolOptionGroup2->enableSingleKeyTriggers (enable);
+
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\ttime=" << timer.restart () << endl;
+#endif
+}
+
+
+// private
+void kpMainWindow::setDocument (kpDocument *newDoc)
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::setDocument (" << newDoc << ")" << endl;
+#endif
+
+ // is it a close operation?
+ if (!newDoc)
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tdisabling actions" << endl;
+ #endif
+
+ // sync with the bit marked "sync" below
+
+ if (m_colorToolBar)
+ m_colorToolBar->setEnabled (false);
+ else
+ {
+ kdError () << "kpMainWindow::setDocument() without colorToolBar"
+ << endl;
+ }
+
+ enableTextToolBarActions (false);
+ }
+
+ // Always disable the tools.
+ // If we decide to open a new document/mainView we want
+ // kpTool::begin() to be called again e.g. in case it sets the cursor.
+ // kpViewManager won't do this because we nuke it to avoid stale state.
+ enableToolsDocumentActions (false);
+
+ if (!newDoc)
+ {
+ enableDocumentActions (false);
+ }
+
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tdestroying views" << endl;
+#endif
+
+ delete m_mainView; m_mainView = 0;
+ slotDestroyThumbnail ();
+
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tdestroying viewManager" << endl;
+#endif
+
+ // viewManager will die and so will the selection
+ m_actionCopy->setEnabled (false);
+ m_actionCut->setEnabled (false);
+ m_actionDelete->setEnabled (false);
+ m_actionDeselect->setEnabled (false);
+ m_actionCopyToFile->setEnabled (false);
+
+ delete m_viewManager; m_viewManager = 0;
+
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tdestroying document" << endl;
+ kdDebug () << "\t\tm_document=" << m_document << endl;
+#endif
+ // destroy current document
+ delete m_document;
+ m_document = newDoc;
+
+
+ if (!m_lastCopyToURL.isEmpty ())
+ m_lastCopyToURL.setFileName (QString::null);
+ m_copyToFirstTime = true;
+
+ if (!m_lastExportURL.isEmpty ())
+ m_lastExportURL.setFileName (QString::null);
+ m_exportFirstTime = true;
+
+
+ // not a close operation?
+ if (m_document)
+ {
+ if (m_document->mainWindow () != this)
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tchanging doc's mainWindow from "
+ << m_document->mainWindow ()
+ << " to this="
+ << this
+ << endl;
+ #endif
+ m_document->setMainWindow (this);
+ }
+
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () <<"\tcreating viewManager" << endl;
+ #endif
+ m_viewManager = new kpViewManager (this);
+
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tcreating views" << endl;
+ #endif
+ m_mainView = new kpZoomedView (m_document, m_toolToolBar, m_viewManager,
+ 0/*buddyView*/,
+ m_scrollView,
+ m_scrollView->viewport (), "mainView");
+ if (m_scrollView)
+ {
+ m_scrollView->addChild (m_mainView);
+ }
+ else
+ kdError () << "kpMainWindow::setDocument() without scrollView" << endl;
+ m_viewManager->registerView (m_mainView);
+ m_mainView->show ();
+
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\thooking up document signals" << endl;
+ #endif
+
+ // Copy/Cut/Deselect/Delete
+ connect (m_document, SIGNAL (selectionEnabled (bool)),
+ m_actionCut, SLOT (setEnabled (bool)));
+ connect (m_document, SIGNAL (selectionEnabled (bool)),
+ m_actionCopy, SLOT (setEnabled (bool)));
+ connect (m_document, SIGNAL (selectionEnabled (bool)),
+ m_actionDelete, SLOT (setEnabled (bool)));
+ connect (m_document, SIGNAL (selectionEnabled (bool)),
+ m_actionDeselect, SLOT (setEnabled (bool)));
+ connect (m_document, SIGNAL (selectionEnabled (bool)),
+ m_actionCopyToFile, SLOT (setEnabled (bool)));
+
+ // this code won't actually enable any actions at this stage
+ // (fresh document) but better safe than sorry
+ m_actionCopy->setEnabled (m_document->selection ());
+ m_actionCut->setEnabled (m_document->selection ());
+ m_actionDeselect->setEnabled (m_document->selection ());
+ m_actionDelete->setEnabled (m_document->selection ());
+ m_actionCopyToFile->setEnabled (m_document->selection ());
+
+ connect (m_document, SIGNAL (selectionEnabled (bool)),
+ this, SLOT (slotImageMenuUpdateDueToSelection ()));
+ connect (m_document, SIGNAL (selectionIsTextChanged (bool)),
+ this, SLOT (slotImageMenuUpdateDueToSelection ()));
+
+ // Status bar
+ connect (m_document, SIGNAL (documentOpened ()),
+ this, SLOT (recalculateStatusBar ()));
+
+ connect (m_document, SIGNAL (sizeChanged (const QSize &)),
+ this, SLOT (setStatusBarDocSize (const QSize &)));
+
+ // Caption (url, modified)
+ connect (m_document, SIGNAL (documentModified ()),
+ this, SLOT (slotUpdateCaption ()));
+ connect (m_document, SIGNAL (documentOpened ()),
+ this, SLOT (slotUpdateCaption ()));
+ connect (m_document, SIGNAL (documentSaved ()),
+ this, SLOT (slotUpdateCaption ()));
+
+ // File/Reload action only available with non-empty URL
+ connect (m_document, SIGNAL (documentSaved ()),
+ this, SLOT (slotEnableReload ()));
+
+ connect (m_document, SIGNAL (documentSaved ()),
+ this, SLOT (slotEnableSettingsShowPath ()));
+
+ // Command history
+ if (m_commandHistory)
+ {
+ connect (m_commandHistory, SIGNAL (documentRestored ()),
+ this, SLOT (slotDocumentRestored ())); // caption "!modified"
+ connect (m_document, SIGNAL (documentSaved ()),
+ m_commandHistory, SLOT (documentSaved ()));
+ }
+ else
+ {
+ kdError () << "kpMainWindow::setDocument() without commandHistory"
+ << endl;
+ }
+
+ // Sync document -> views
+ connect (m_document, SIGNAL (contentsChanged (const QRect &)),
+ m_viewManager, SLOT (updateViews (const QRect &)));
+ connect (m_document, SIGNAL (sizeChanged (int, int)),
+ m_viewManager, SLOT (adjustViewsToEnvironment ()));
+
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tenabling actions" << endl;
+ #endif
+
+ // sync with the bit marked "sync" above
+
+ if (m_colorToolBar)
+ m_colorToolBar->setEnabled (true);
+ else
+ {
+ kdError () << "kpMainWindow::setDocument() without colorToolBar"
+ << endl;
+ }
+
+
+ // Hide the text toolbar - it will be shown by kpToolText::begin()
+ enableTextToolBarActions (false);
+
+ enableToolsDocumentActions (true);
+
+ enableDocumentActions (true);
+
+ // TODO: The thumbnail auto zoom doesn't work because it thinks its
+ // width == 1 when !this->isShown(). So for consistency,
+ // never create the thumbnail.
+ #if 0
+ if (m_configThumbnailShown)
+ {
+ if (isShown ())
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tcreating thumbnail immediately" << endl;
+ #endif
+ slotCreateThumbnail ();
+ }
+ // this' geometry is weird ATM
+ else
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tcreating thumbnail LATER" << endl;
+ #endif
+ QTimer::singleShot (0, this, SLOT (slotCreateThumbnail ()));
+ }
+ }
+ #endif
+ }
+
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tupdating mainWindow elements" << endl;
+#endif
+
+ slotImageMenuUpdateDueToSelection ();
+ recalculateStatusBar ();
+ slotUpdateCaption (); // Untitled to start with
+ slotEnableReload ();
+ slotEnableSettingsShowPath ();
+
+ if (m_commandHistory)
+ m_commandHistory->clear ();
+
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tdocument and views ready to go!" << endl;
+#endif
+}
+
+
+// private virtual [base KMainWindow]
+bool kpMainWindow::queryClose ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::queryClose()" << endl;
+#endif
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ if (!m_document || !m_document->isModified ())
+ return true; // ok to close current doc
+
+ int result = KMessageBox::warningYesNoCancel (this,
+ i18n ("The document \"%1\" has been modified.\n"
+ "Do you want to save it?")
+ .arg (m_document->prettyFilename ()),
+ QString::null/*caption*/,
+ KStdGuiItem::save (), KStdGuiItem::discard ());
+
+ switch (result)
+ {
+ case KMessageBox::Yes:
+ return slotSave (); // close only if save succeeds
+ case KMessageBox::No:
+ return true; // close without saving
+ default:
+ return false; // don't close current doc
+ }
+}
+
+
+// private virtual [base QWidget]
+void kpMainWindow::dragEnterEvent (QDragEnterEvent *e)
+{
+ e->accept (kpSelectionDrag::canDecode (e) ||
+ KURLDrag::canDecode (e) ||
+ QTextDrag::canDecode (e));
+}
+
+// private virtual [base QWidget]
+void kpMainWindow::dropEvent (QDropEvent *e)
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::dropEvent" << e->pos () << endl;
+#endif
+
+ kpSelection sel;
+ KURL::List urls;
+ QString text;
+
+ if (kpSelectionDrag::decode (e, sel/*ref*/, pasteWarnAboutLossInfo ()))
+ {
+ sel.setTransparency (selectionTransparency ());
+ // TODO: drop at point like with QTextDrag below?
+ paste (sel);
+ }
+ else if (KURLDrag::decode (e, urls/*ref*/))
+ {
+ for (KURL::List::ConstIterator it = urls.begin (); it != urls.end (); it++)
+ {
+ open (*it);
+ }
+ }
+ else if (QTextDrag::decode (e, text/*ref*/))
+ {
+ QPoint selTopLeft = KP_INVALID_POINT;
+ const QPoint globalPos = QWidget::mapToGlobal (e->pos ());
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tpos toGlobal=" << globalPos << endl;
+ #endif
+
+ kpView *view = 0;
+
+ if (m_viewManager)
+ {
+ view = m_viewManager->viewUnderCursor ();
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t\tviewUnderCursor=" << view << endl;
+ #endif
+ if (!view)
+ {
+ // HACK: see kpViewManager::setViewUnderCursor() to see why
+ // it's not reliable
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t\tattempting to discover view" << endl;
+
+ if (m_mainView && m_scrollView)
+ {
+ kdDebug () << "\t\t\tmainView->globalRect="
+ << kpWidgetMapper::toGlobal (m_mainView, m_mainView->rect ())
+ << " scrollView->globalRect="
+ << kpWidgetMapper::toGlobal (m_scrollView,
+ QRect (0, 0,
+ m_scrollView->visibleWidth (),
+ m_scrollView->visibleHeight ()))
+ << endl;
+ }
+ #endif
+ if (m_thumbnailView &&
+ kpWidgetMapper::toGlobal (m_thumbnailView, m_thumbnailView->rect ())
+ .contains (globalPos))
+ {
+ // TODO: Code will never get executed.
+ // Thumbnail doesn't accept drops.
+ view = m_thumbnailView;
+ }
+ else if (m_mainView &&
+ kpWidgetMapper::toGlobal (m_mainView, m_mainView->rect ())
+ .contains (globalPos) &&
+ m_scrollView &&
+ kpWidgetMapper::toGlobal (m_scrollView,
+ QRect (0, 0,
+ m_scrollView->visibleWidth (),
+ m_scrollView->visibleHeight ()))
+ .contains (globalPos))
+ {
+ view = m_mainView;
+ }
+ }
+ }
+
+ if (view)
+ {
+ const QPoint viewPos = view->mapFromGlobal (globalPos);
+ const QPoint docPoint = view->transformViewToDoc (viewPos);
+
+ // viewUnderCursor() is hacky and can return a view when we aren't
+ // over one thanks to drags.
+ if (m_document && m_document->rect ().contains (docPoint))
+ {
+ selTopLeft = docPoint;
+
+ // TODO: In terms of doc pixels, would be inconsistent behaviour
+ // based on zoomLevel of view.
+ // selTopLeft -= QPoint (-view->selectionResizeHandleAtomicSize (),
+ // -view->selectionResizeHandleAtomicSize ());
+ }
+ }
+
+ pasteText (text, true/*force new text selection*/, selTopLeft);
+ }
+}
+
+
+// private slot
+void kpMainWindow::slotScrollViewAboutToScroll ()
+{
+#if DEBUG_KP_MAIN_WINDOW && 0
+ kdDebug () << "kpMainWindow::slotScrollViewAboutToScroll() tool="
+ << tool () << " viewManager=" << viewManager () << endl;
+ if (viewManager ())
+ {
+ kdDebug () << "\tfastUpdates=" << viewManager ()->fastUpdates ()
+ << " queueUpdates=" << viewManager ()->queueUpdates ()
+ << endl;
+ }
+ else
+ {
+ // We're getting a late signal from the scrollview (thanks to
+ // a timer inside the QScrollView). By now, setDocument() has
+ // already killed the document(), tool() and viewManager().
+ }
+#endif
+
+ QTimer::singleShot (0, this, SLOT (slotScrollViewAfterScroll ()));
+}
+
+// private slot
+void kpMainWindow::slotScrollViewAfterScroll ()
+{
+#if DEBUG_KP_MAIN_WINDOW && 0
+ kdDebug () << "kpMainWindow::slotScrollViewAfterScroll() tool="
+ << tool () << endl;
+#endif
+
+ if (tool ())
+ {
+ tool ()->somethingBelowTheCursorChanged ();
+ }
+}
+
+
+// private virtual [base QWidget]
+void kpMainWindow::moveEvent (QMoveEvent * /*e*/)
+{
+ if (m_thumbnail)
+ {
+ // Disabled because it lags too far behind the mainWindow
+ // m_thumbnail->move (m_thumbnail->pos () + (e->pos () - e->oldPos ()));
+
+ notifyThumbnailGeometryChanged ();
+ }
+}
+
+
+// private slot
+void kpMainWindow::slotUpdateCaption ()
+{
+ if (m_document)
+ {
+ setCaption (m_configShowPath ? m_document->prettyURL ()
+ : m_document->prettyFilename (),
+ m_document->isModified ());
+ }
+ else
+ {
+ setCaption (QString::null, false);
+ }
+}
+
+// private slot
+void kpMainWindow::slotDocumentRestored ()
+{
+ if (m_document)
+ m_document->setModified (false);
+ slotUpdateCaption ();
+}
+
+
+#include <kpmainwindow.moc>
diff --git a/kolourpaint/kpmainwindow.h b/kolourpaint/kpmainwindow.h
new file mode 100644
index 00000000..f5514848
--- /dev/null
+++ b/kolourpaint/kpmainwindow.h
@@ -0,0 +1,739 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef KP_MAIN_WINDOW_H
+#define KP_MAIN_WINDOW_H
+
+
+#define DEBUG_KP_MAIN_WINDOW 0
+
+#include <qpoint.h>
+#include <qptrlist.h>
+#include <qsize.h>
+#include <qvaluevector.h>
+
+#include <kmainwindow.h>
+#include <kurl.h>
+
+#include <kpdefs.h>
+#include <kpdocumentsaveoptions.h>
+#include <kppixmapfx.h>
+
+
+class QPainter;
+class QPoint;
+class QPopupMenu;
+class QRect;
+class QSize;
+class QStringList;
+
+class KAction;
+class KFontAction;
+class KFontSizeAction;
+class KSelectAction;
+class KToggleAction;
+class KToolBar;
+class KPrinter;
+class KRecentFilesAction;
+class KScanDialog;
+class KToggleFullScreenAction;
+
+class kpColor;
+class kpColorToolBar;
+class kpCommand;
+class kpCommandHistory;
+class kpDocument;
+class kpDocumentMetaInfo;
+class kpDocumentSaveOptions;
+class kpViewManager;
+class kpViewScrollableContainer;
+class kpSelection;
+class kpSelectionTransparency;
+class kpSingleKeyTriggersAction;
+class kpSqueezedTextLabel;
+class kpTextStyle;
+class kpThumbnail;
+class kpThumbnailView;
+class kpTool;
+class kpToolText;
+class kpToolToolBar;
+class kpZoomedView;
+
+
+class kpMainWindow : public KMainWindow
+{
+Q_OBJECT
+
+public:
+ // Opens a new window with a blank document.
+ kpMainWindow ();
+
+ // Opens a new window with the document specified by <url>
+ // or creates a blank document if <url> could not be opened.
+ kpMainWindow (const KURL &url);
+
+ // Opens a new window with the document <newDoc>
+ // (<newDoc> can be 0 although this would result in a new
+ // window without a document at all).
+ kpMainWindow (kpDocument *newDoc);
+
+public:
+ double configColorSimilarity () const;
+ void configSetColorSimilarity (double val);
+
+private:
+ bool m_configFirstTime;
+ bool m_configShowGrid;
+ bool m_configShowPath;
+ double m_configColorSimilarity;
+
+ bool m_configThumbnailShown;
+ QRect m_configThumbnailGeometry;
+ bool m_configZoomedThumbnail;
+
+ void readGeneralSettings ();
+ void readThumbnailSettings ();
+ void init ();
+
+ // (only called for restoring a previous session e.g. starting KDE with
+ // a previously saved session; it's not called on normal KolourPaint
+ // startup)
+ virtual void readProperties (KConfig *cfg);
+ // (only called for saving the current session e.g. logging out of KDE
+ // with the KolourPaint window open; it's not called on normal KolourPaint
+ // exit)
+ virtual void saveProperties (KConfig *cfg);
+
+public:
+ ~kpMainWindow ();
+
+private:
+ bool m_isFullyConstructed;
+
+public:
+ kpDocument *document () const;
+ kpViewManager *viewManager () const;
+ kpColorToolBar *colorToolBar () const;
+ kpToolToolBar *toolToolBar () const;
+ kpCommandHistory *commandHistory () const;
+
+private:
+ kpViewScrollableContainer *m_scrollView;
+ kpZoomedView *m_mainView;
+ kpThumbnail *m_thumbnail;
+ kpThumbnailView *m_thumbnailView;
+ kpDocument *m_document;
+ kpViewManager *m_viewManager;
+ kpColorToolBar *m_colorToolBar;
+ kpToolToolBar *m_toolToolBar;
+ kpCommandHistory *m_commandHistory;
+
+private:
+ void setupActions ();
+ void enableDocumentActions (bool enable = true);
+
+public:
+ bool actionsSingleKeyTriggersEnabled () const;
+ void enableActionsSingleKeyTriggers (bool enable = true);
+
+private:
+ void setDocument (kpDocument *newDoc);
+
+ virtual bool queryClose ();
+
+ virtual void dragEnterEvent (QDragEnterEvent *e);
+ virtual void dropEvent (QDropEvent *e);
+
+private slots:
+ void slotScrollViewAboutToScroll ();
+ void slotScrollViewAfterScroll ();
+
+private:
+ virtual void moveEvent (QMoveEvent *e);
+
+private slots:
+ void slotUpdateCaption ();
+ void slotDocumentRestored ();
+
+
+ /*
+ * Tools
+ */
+
+private:
+ void setupToolActions ();
+ void createToolBox ();
+ void enableToolsDocumentActions (bool enable = true);
+
+private slots:
+ void updateToolOptionPrevNextActionsEnabled ();
+
+private:
+ kpTool *m_toolAirSpray, *m_toolBrush, *m_toolColorPicker,
+ *m_toolColorWasher, *m_toolCurve, *m_toolEllipse,
+ *m_toolEllipticalSelection, *m_toolEraser,
+ *m_toolFloodFill, *m_toolFreeFormSelection,
+ *m_toolLine, *m_toolPen, *m_toolPolygon,
+ *m_toolPolyline, *m_toolRectangle, *m_toolRectSelection,
+ *m_toolRoundedRectangle;
+ kpToolText *m_toolText;
+
+ QPtrList <kpTool> m_tools;
+ int m_lastToolNumber;
+
+ bool m_toolActionsEnabled;
+ kpSingleKeyTriggersAction *m_actionPrevToolOptionGroup1,
+ *m_actionNextToolOptionGroup1,
+ *m_actionPrevToolOptionGroup2,
+ *m_actionNextToolOptionGroup2;
+
+ int m_settingSelectionTransparency;
+
+ int m_docResizeWidth, m_docResizeHeight;
+ bool m_docResizeToBeCompleted;
+
+public:
+ kpTool *tool () const;
+ bool toolHasBegunShape () const;
+ bool toolIsASelectionTool (bool includingTextTool = true) const;
+ bool toolIsTextTool () const;
+
+ kpSelectionTransparency selectionTransparency () const;
+ // The drawing background color is set to <transparency>.transparentColor()
+ // if the <transparency> is in Transparent mode or if <forceColorChange>
+ // is true (not the default). [x]
+ //
+ // If <transparency> is in Opaque mode and <forceColorChange> is false,
+ // the background color is not changed because:
+ //
+ // 1. It is ignored by the selection in Opaque mode anyway.
+ // 2. This avoids irritating the user with an unnecessary background
+ // color change.
+ //
+ // The only case where you should set <forceColorChange> to true is in
+ // kpToolSelectionTransparencyCommand to ensure that the state
+ // is identical to when the command was constructed.
+ // Later: I don't think setting it to true is ever necessary since:
+ //
+ // 1. The background color only counts in Transparent mode.
+ //
+ // 2. Any kpToolSelectionTransparencyCommand that switches to
+ // Transparent mode will automatically set the background
+ // color due to the first part of [x] anyway.
+ //
+ // The other fields of <transparency> are copied into the main window
+ // as expected.
+ void setSelectionTransparency (const kpSelectionTransparency &transparency,
+ bool forceColorChange = false);
+ int settingSelectionTransparency () const;
+
+private slots:
+ void slotToolSelected (kpTool *tool);
+
+private:
+ void readLastTool ();
+ int toolNumber () const;
+ void saveLastTool ();
+
+private:
+ bool maybeDragScrollingMainView () const;
+private slots:
+ bool slotDragScroll (const QPoint &docPoint,
+ const QPoint &docLastPoint,
+ int zoomLevel,
+ bool *didSomething);
+ bool slotEndDragScroll ();
+
+private slots:
+ void slotBeganDocResize ();
+ void slotContinuedDocResize (const QSize &size);
+ void slotCancelledDocResize ();
+ void slotEndedDocResize (const QSize &size);
+
+ void slotDocResizeMessageChanged (const QString &string);
+
+private slots:
+ void slotActionPrevToolOptionGroup1 ();
+ void slotActionNextToolOptionGroup1 ();
+ void slotActionPrevToolOptionGroup2 ();
+ void slotActionNextToolOptionGroup2 ();
+
+public slots:
+ void slotToolAirSpray ();
+ void slotToolBrush ();
+ void slotToolColorPicker ();
+ void slotToolColorWasher ();
+ void slotToolCurve ();
+ void slotToolEllipse ();
+ void slotToolEllipticalSelection ();
+ void slotToolEraser ();
+ void slotToolFloodFill ();
+ void slotToolFreeFormSelection ();
+ void slotToolLine ();
+ void slotToolPen ();
+ void slotToolPolygon ();
+ void slotToolPolyline ();
+ void slotToolRectangle ();
+ void slotToolRectSelection ();
+ void slotToolRoundedRectangle ();
+ void slotToolText ();
+
+
+ /*
+ * File Menu
+ */
+
+private:
+ void setupFileMenuActions ();
+ void enableFileMenuDocumentActions (bool enable = true);
+
+ KAction *m_actionNew, *m_actionOpen;
+ KRecentFilesAction *m_actionOpenRecent;
+ KAction *m_actionScan, *m_actionSave, *m_actionSaveAs, *m_actionExport,
+ *m_actionReload,
+ *m_actionPrint, *m_actionPrintPreview,
+ *m_actionMail,
+ *m_actionSetAsWallpaperTiled, *m_actionSetAsWallpaperCentered,
+ *m_actionClose, *m_actionQuit;
+
+ KScanDialog *m_scanDialog;
+
+ KURL m_lastExportURL;
+ kpDocumentSaveOptions m_lastExportSaveOptions;
+ bool m_exportFirstTime;
+
+private:
+ void addRecentURL (const KURL &url);
+
+private slots:
+ void slotNew ();
+
+private:
+ QSize defaultDocSize () const;
+ void saveDefaultDocSize (const QSize &size);
+
+private:
+ bool shouldOpenInNewWindow () const;
+ void setDocumentChoosingWindow (kpDocument *doc);
+
+private:
+ kpDocument *openInternal (const KURL &url,
+ const QSize &fallbackDocSize,
+ bool newDocSameNameIfNotExist);
+ // Same as above except that it:
+ //
+ // 1. Assumes a default fallback document size.
+ // 2. If the URL is successfully opened (with the special exception of
+ // the "kolourpaint doesnotexist.png" case), it is bubbled up to the
+ // top in the Recent Files Action.
+ //
+ // As a result of this behavior, this should only be called in response
+ // to a user open request e.g. File / Open or "kolourpaint doesexist.png".
+ // It should not be used for session restore - in that case, it does not
+ // make sense to bubble the Recent Files list.
+ bool open (const KURL &url, bool newDocSameNameIfNotExist = false);
+
+ KURL::List askForOpenURLs (const QString &caption,
+ const QString &startURL,
+ bool allowMultipleURLs = true);
+
+private slots:
+ void slotOpen ();
+ void slotOpenRecent (const KURL &url);
+
+ void slotScan ();
+ void slotScanned (const QImage &image, int);
+
+ bool save (bool localOnly = false);
+ bool slotSave ();
+
+private:
+ KURL askForSaveURL (const QString &caption,
+ const QString &startURL,
+ const QPixmap &pixmapToBeSaved,
+ const kpDocumentSaveOptions &startSaveOptions,
+ const kpDocumentMetaInfo &docMetaInfo,
+ const QString &forcedSaveOptionsGroup,
+ bool localOnly,
+ kpDocumentSaveOptions *chosenSaveOptions,
+ bool isSavingForFirstTime,
+ bool *allowOverwritePrompt,
+ bool *allowLossyPrompt);
+
+private slots:
+ bool saveAs (bool localOnly = false);
+ bool slotSaveAs ();
+
+ bool slotExport ();
+
+ void slotEnableReload ();
+ bool slotReload ();
+
+private:
+ void sendFilenameToPrinter (KPrinter *printer);
+ void sendPixmapToPrinter (KPrinter *printer, bool showPrinterSetupDialog);
+
+private slots:
+ void slotPrint ();
+ void slotPrintPreview ();
+
+ void slotMail ();
+
+private:
+ void setAsWallpaper (bool centered);
+private slots:
+ void slotSetAsWallpaperCentered ();
+ void slotSetAsWallpaperTiled ();
+
+ void slotClose ();
+ void slotQuit ();
+
+
+ /*
+ * Edit Menu
+ */
+
+private:
+ kpPixmapFX::WarnAboutLossInfo pasteWarnAboutLossInfo ();
+ void setupEditMenuActions ();
+ void enableEditMenuDocumentActions (bool enable = true);
+
+ bool m_editMenuDocumentActionsEnabled;
+
+ KAction *m_actionUndo, *m_actionRedo,
+ *m_actionCut, *m_actionCopy,
+ *m_actionPaste, *m_actionPasteInNewWindow,
+ *m_actionDelete,
+ *m_actionSelectAll, *m_actionDeselect,
+ *m_actionCopyToFile, *m_actionPasteFromFile;
+
+ KURL m_lastPasteFromURL;
+
+ KURL m_lastCopyToURL;
+ kpDocumentSaveOptions m_lastCopyToSaveOptions;
+ bool m_copyToFirstTime;
+
+public:
+ QPopupMenu *selectionToolRMBMenu ();
+
+private slots:
+ void slotCut ();
+ void slotCopy ();
+ void slotEnablePaste ();
+private:
+ QRect calcUsefulPasteRect (int pixmapWidth, int pixmapHeight);
+ void paste (const kpSelection &sel,
+ bool forceTopLeft = false);
+public:
+ // (<forceNewTextSelection> is ignored if <text> is empty)
+ void pasteText (const QString &text,
+ bool forceNewTextSelection = false,
+ const QPoint &newTextSelectionTopLeft = KP_INVALID_POINT);
+ void pasteTextAt (const QString &text, const QPoint &point,
+ // Allow tiny adjustment of <point> so that mouse
+ // pointer is not exactly on top of the topLeft of
+ // any new text selection (so that it doesn't look
+ // weird by being on top of a resize handle just after
+ // a paste).
+ bool allowNewTextSelectionPointShift = false);
+public slots:
+ void slotPaste ();
+private slots:
+ void slotPasteInNewWindow ();
+public slots:
+ void slotDelete ();
+
+ void slotSelectAll ();
+private:
+ void addDeselectFirstCommand (kpCommand *cmd);
+public slots:
+ void slotDeselect ();
+private slots:
+ void slotCopyToFile ();
+ void slotPasteFromFile ();
+
+
+ /*
+ * View Menu
+ */
+
+private:
+ bool m_viewMenuDocumentActionsEnabled;
+
+ void setupViewMenuActions ();
+ bool viewMenuDocumentActionsEnabled () const;
+ void enableViewMenuDocumentActions (bool enable = true);
+ void actionShowGridUpdate ();
+
+ KAction *m_actionFullScreenBIC,
+ *m_actionActualSize,
+ *m_actionFitToPage, *m_actionFitToWidth, *m_actionFitToHeight,
+ *m_actionZoomIn, *m_actionZoomOut;
+ KSelectAction *m_actionZoom;
+ KToggleAction *m_actionShowGrid,
+ *m_actionShowThumbnail, *m_actionZoomedThumbnail;
+
+ QValueVector <int> m_zoomList;
+
+private:
+ void sendZoomListToActionZoom ();
+ int zoomLevelFromString (const QString &string);
+ QString zoomLevelToString (int zoomLevel);
+ void zoomTo (int zoomLevel, bool centerUnderCursor = false);
+
+private slots:
+ void finishZoomTo ();
+
+private slots:
+ void slotActualSize ();
+ void slotFitToPage ();
+ void slotFitToWidth ();
+ void slotFitToHeight ();
+
+public:
+ void zoomIn (bool centerUnderCursor = false);
+ void zoomOut (bool centerUnderCursor = false);
+
+public slots:
+ void slotZoomIn ();
+ void slotZoomOut ();
+
+private:
+ void zoomAccordingToZoomAction (bool centerUnderCursor = false);
+
+private slots:
+ void slotZoom ();
+
+ void slotShowGridToggled ();
+private:
+ void updateMainViewGrid ();
+
+private:
+ QRect mapToGlobal (const QRect &rect) const;
+ QRect mapFromGlobal (const QRect &rect) const;
+
+private slots:
+ void slotDestroyThumbnailIfNotVisible (bool tnIsVisible);
+ void slotDestroyThumbnail ();
+ void slotDestroyThumbnailInitatedByUser ();
+ void slotCreateThumbnail ();
+
+private:
+ QTimer *m_thumbnailSaveConfigTimer;
+
+public:
+ void notifyThumbnailGeometryChanged ();
+
+private slots:
+ void slotSaveThumbnailGeometry ();
+ void slotShowThumbnailToggled ();
+ void updateThumbnailZoomed ();
+ void slotZoomedThumbnailToggled ();
+ void slotThumbnailShowRectangleToggled ();
+
+private:
+ void enableViewZoomedThumbnail (bool enable = true);
+ void enableViewShowThumbnailRectangle (bool enable = true);
+ void enableThumbnailOptionActions (bool enable = true);
+ void createThumbnailView ();
+ void destroyThumbnailView ();
+ void updateThumbnail ();
+
+
+ /*
+ * Image Menu
+ */
+
+private:
+ bool isSelectionActive () const;
+ bool isTextSelection () const;
+
+ QString autoCropText () const;
+
+ void setupImageMenuActions ();
+ void enableImageMenuDocumentActions (bool enable = true);
+
+ bool m_imageMenuDocumentActionsEnabled;
+
+ KAction *m_actionResizeScale,
+ *m_actionCrop, *m_actionAutoCrop,
+ *m_actionFlip, *m_actionRotate, *m_actionSkew,
+ *m_actionConvertToBlackAndWhite, *m_actionConvertToGrayscale,
+ *m_actionMoreEffects,
+ *m_actionInvertColors, *m_actionClear;
+
+private slots:
+ void slotImageMenuUpdateDueToSelection ();
+
+public:
+ kpColor backgroundColor (bool ofSelection = false) const;
+ void addImageOrSelectionCommand (kpCommand *cmd,
+ bool addSelCreateCmdIfSelAvail = true,
+ bool addSelPullCmdIfSelAvail = true);
+
+private slots:
+ void slotResizeScale ();
+public slots:
+ void slotCrop ();
+private slots:
+ void slotAutoCrop ();
+ void slotFlip ();
+ void slotRotate ();
+ void slotSkew ();
+ void slotConvertToBlackAndWhite ();
+ void slotConvertToGrayscale ();
+ void slotInvertColors ();
+ void slotClear ();
+ void slotMoreEffects ();
+
+
+ /*
+ * Settings Menu
+ */
+
+private:
+ void setupSettingsMenuActions ();
+ void enableSettingsMenuDocumentActions (bool enable = true);
+
+ KToggleAction *m_actionShowPath;
+ KAction *m_actionKeyBindings, *m_actionConfigureToolbars, *m_actionConfigure;
+ KToggleFullScreenAction *m_actionFullScreen;
+
+private slots:
+ void slotFullScreen ();
+
+ void slotEnableSettingsShowPath ();
+ void slotShowPathToggled ();
+
+ void slotKeyBindings ();
+
+ void slotConfigureToolBars ();
+ void slotNewToolBarConfig ();
+
+ void slotConfigure ();
+
+
+ /*
+ * Status Bar
+ */
+
+private:
+ bool m_statusBarCreated;
+ kpSqueezedTextLabel *m_statusBarMessageLabel;
+
+ bool m_statusBarShapeLastPointsInitialised;
+ QPoint m_statusBarShapeLastStartPoint, m_statusBarShapeLastEndPoint;
+ bool m_statusBarShapeLastSizeInitialised;
+ QSize m_statusBarShapeLastSize;
+
+ enum
+ {
+ StatusBarItemMessage,
+ StatusBarItemShapePoints,
+ StatusBarItemShapeSize,
+ StatusBarItemDocSize,
+ StatusBarItemDocDepth,
+ StatusBarItemZoom
+ };
+
+ void addPermanentStatusBarItem (int id, int maxTextLen);
+ void createStatusBar ();
+
+private slots:
+ void setStatusBarMessage (const QString &message = QString::null);
+ void setStatusBarShapePoints (const QPoint &startPoint = KP_INVALID_POINT,
+ const QPoint &endPoint = KP_INVALID_POINT);
+ void setStatusBarShapeSize (const QSize &size = KP_INVALID_SIZE);
+ void setStatusBarDocSize (const QSize &size = KP_INVALID_SIZE);
+ void setStatusBarDocDepth (int depth = 0);
+ void setStatusBarZoom (int zoom = 0);
+
+ void recalculateStatusBarMessage ();
+ void recalculateStatusBarShape ();
+
+ void recalculateStatusBar ();
+
+
+ /*
+ * Text ToolBar
+ */
+
+private:
+ void setupTextToolBarActions ();
+ void readAndApplyTextSettings ();
+
+public:
+ void enableTextToolBarActions (bool enable = true);
+
+private slots:
+ void slotTextFontFamilyChanged ();
+ void slotTextFontSizeChanged ();
+ void slotTextBoldChanged ();
+ void slotTextItalicChanged ();
+ void slotTextUnderlineChanged ();
+ void slotTextStrikeThruChanged ();
+
+public:
+ KToolBar *textToolBar ();
+ bool isTextStyleBackgroundOpaque () const;
+ kpTextStyle textStyle () const;
+ void setTextStyle (const kpTextStyle &textStyle_);
+ int settingTextStyle () const;
+
+private:
+ KFontAction *m_actionTextFontFamily;
+ KFontSizeAction *m_actionTextFontSize;
+ KToggleAction *m_actionTextBold, *m_actionTextItalic,
+ *m_actionTextUnderline, *m_actionTextStrikeThru;
+
+ int m_settingTextStyle;
+ QString m_textOldFontFamily;
+ int m_textOldFontSize;
+
+
+ /*
+ * Help Menu
+ */
+private:
+ void setupHelpMenuActions ();
+ void enableHelpMenuDocumentActions (bool enable = true);
+
+private slots:
+ void slotHelpTakingScreenshots ();
+ void slotHelpTakingScreenshotsFollowLink (const QString &link);
+
+
+private:
+ // There is no need to maintain binary compatibility at this stage.
+ // The d-pointer is just so that you can experiment without recompiling
+ // the kitchen sink.
+ class kpMainWindowPrivate *d;
+};
+
+
+#endif // KP_MAIN_WINDOW_H
diff --git a/kolourpaint/kpmainwindow_edit.cpp b/kolourpaint/kpmainwindow_edit.cpp
new file mode 100644
index 00000000..3cf9b4f6
--- /dev/null
+++ b/kolourpaint/kpmainwindow_edit.cpp
@@ -0,0 +1,1069 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <kpmainwindow.h>
+
+#include <qapplication.h>
+#include <qclipboard.h>
+#include <qdatetime.h>
+#include <qfontmetrics.h>
+#include <qimage.h>
+#include <qpixmap.h>
+#include <qvaluevector.h>
+
+#include <kaction.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kstdaction.h>
+
+#include <kpcommandhistory.h>
+#include <kpdocument.h>
+#include <kpdocumentmetainfo.h>
+#include <kpdocumentsaveoptions.h>
+#include <kppixmapfx.h>
+#include <kpselection.h>
+#include <kpselectiondrag.h>
+#include <kpselectiontransparency.h>
+#include <kptool.h>
+#include <kptoolcrop.h>
+#include <kptoolresizescale.h>
+#include <kptoolselection.h>
+#include <kptooltext.h>
+#include <kpviewmanager.h>
+#include <kpviewscrollablecontainer.h>
+#include <kpzoomedview.h>
+
+
+// private
+kpPixmapFX::WarnAboutLossInfo kpMainWindow::pasteWarnAboutLossInfo ()
+{
+ return kpPixmapFX::WarnAboutLossInfo (
+ i18n ("The image to be pasted"
+ " may have more colors than the current screen mode."
+ " In order to display it, some colors may be changed."
+ " Try increasing your screen depth to at least %1bpp."
+
+ "\nIt also"
+
+ " contains translucency which is not fully"
+ " supported. The translucency data will be"
+ " approximated with a 1-bit transparency mask."),
+ i18n ("The image to be pasted"
+ " may have more colors than the current screen mode."
+ " In order to display it, some colors may be changed."
+ " Try increasing your screen depth to at least %1bpp."),
+ i18n ("The image to be pasted"
+ " contains translucency which is not fully"
+ " supported. The translucency data will be"
+ " approximated with a 1-bit transparency mask."),
+ "paste",
+ this);
+}
+
+
+// private
+void kpMainWindow::setupEditMenuActions ()
+{
+ KActionCollection *ac = actionCollection ();
+
+
+ // Undo/Redo
+ // CONFIG: need GUI
+ m_commandHistory = new kpCommandHistory (true/*read config*/, this);
+
+ if (m_configFirstTime)
+ {
+ // (so that cfg-file-editing user can modify in the meantime)
+ m_commandHistory->writeConfig ();
+ }
+
+
+ m_actionCut = KStdAction::cut (this, SLOT (slotCut ()), ac);
+ m_actionCopy = KStdAction::copy (this, SLOT (slotCopy ()), ac);
+ m_actionPaste = KStdAction::paste (this, SLOT (slotPaste ()), ac);
+ m_actionPasteInNewWindow = new KAction (i18n ("Paste in &New Window"),
+ Qt::CTRL + Qt::SHIFT + Qt::Key_V,
+ this, SLOT (slotPasteInNewWindow ()), ac, "edit_paste_in_new_window");
+
+ //m_actionDelete = KStdAction::clear (this, SLOT (slotDelete ()), ac);
+ m_actionDelete = new KAction (i18n ("&Delete Selection"), 0,
+ this, SLOT (slotDelete ()), ac, "edit_clear");
+
+ m_actionSelectAll = KStdAction::selectAll (this, SLOT (slotSelectAll ()), ac);
+ m_actionDeselect = KStdAction::deselect (this, SLOT (slotDeselect ()), ac);
+
+
+ m_actionCopyToFile = new KAction (i18n ("C&opy to File..."), 0,
+ this, SLOT (slotCopyToFile ()), ac, "edit_copy_to_file");
+ m_actionPasteFromFile = new KAction (i18n ("Paste &From File..."), 0,
+ this, SLOT (slotPasteFromFile ()), ac, "edit_paste_from_file");
+
+
+ m_editMenuDocumentActionsEnabled = false;
+ enableEditMenuDocumentActions (false);
+
+ // Paste should always be enabled, as long as there is something paste
+ // (independent of whether we have a document or not)
+ connect (QApplication::clipboard (), SIGNAL (dataChanged ()),
+ this, SLOT (slotEnablePaste ()));
+ slotEnablePaste ();
+}
+
+// private
+void kpMainWindow::enableEditMenuDocumentActions (bool enable)
+{
+ // m_actionCut
+ // m_actionCopy
+ // m_actionPaste
+ // m_actionPasteInNewWindow
+
+ // m_actionDelete
+
+ m_actionSelectAll->setEnabled (enable);
+ // m_actionDeselect
+
+ m_editMenuDocumentActionsEnabled = enable;
+
+ // m_actionCopyToFile
+ // Unlike m_actionPaste, we disable this if there is no document.
+ // This is because "File / Open" would do the same thing, if there is
+ // no document.
+ m_actionPasteFromFile->setEnabled (enable);
+}
+
+
+// public
+QPopupMenu *kpMainWindow::selectionToolRMBMenu ()
+{
+ return (QPopupMenu *) guiFactory ()->container ("selectionToolRMBMenu", this);
+}
+
+
+// private slot
+void kpMainWindow::slotCut ()
+{
+#if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "kpMainWindow::slotCut() CALLED" << endl;
+#endif
+
+ if (!m_document || !m_document->selection ())
+ {
+ kdError () << "kpMainWindow::slotCut () doc=" << m_document
+ << " sel=" << (m_document ? m_document->selection () : 0)
+ << endl;
+ return;
+ }
+
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ slotCopy ();
+ slotDelete ();
+
+ QApplication::restoreOverrideCursor ();
+
+}
+
+// private slot
+void kpMainWindow::slotCopy ()
+{
+#if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "kpMainWindow::slotCopy() CALLED" << endl;
+#endif
+
+ if (!m_document || !m_document->selection ())
+ {
+ kdError () << "kpMainWindow::slotCopy () doc=" << m_document
+ << " sel=" << (m_document ? m_document->selection () : 0)
+ << endl;
+ return;
+ }
+
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ kpSelection sel = *m_document->selection ();
+ // Transparency doesn't get sent across the aether so nuke it now
+ // so that transparency mask doesn't get needlessly recalculated
+ // if we ever call sel.setPixmap().
+ sel.setTransparency (kpSelectionTransparency ());
+
+ if (sel.isText ())
+ {
+ if (!sel.text ().isEmpty ())
+ {
+ QApplication::clipboard ()->setData (new QTextDrag (sel.text ()),
+ QClipboard::Clipboard);
+
+ // SYNC: Normally, users highlight text and press CTRL+C.
+ // Highlighting text copies it to the X11 "middle
+ // mouse button" clipboard. CTRL+C copies it to the
+ // separate, Windows-like "CTRL+V" clipboard.
+ //
+ // However, KolourPaint doesn't support highlighting.
+ // So when they press CTRL+C to copy all text, simulate
+ // the highlighting by copying the text to the "middle
+ // mouse button" clipboard. We don't do this for images
+ // as no one ever middle-mouse-pastes images.
+ //
+ // Note that we don't share the QTextDrag pointer with
+ // the above in case Qt doesn't expect it.
+ //
+ // Once we change KolourPaint to support highlighted text
+ // and CTRL+C to copy only the highlighted text, delete
+ // this code.
+ QApplication::clipboard ()->setData (new QTextDrag (sel.text ()),
+ QClipboard::Selection);
+ }
+ }
+ else
+ {
+ QPixmap rawPixmap;
+
+ if (sel.pixmap ())
+ rawPixmap = *sel.pixmap ();
+ else
+ rawPixmap = m_document->getSelectedPixmap ();
+
+ // Some apps, such as OpenOffice.org 2.0.4, ignore the image mask
+ // when pasting. For transparent pixels, the uninitialized RGB
+ // values are used. Fix this by initializing those values to a
+ // neutral color -- white.
+ //
+ // Strangely enough, OpenOffice.org respects the mask when inserting
+ // an image from a file, as opposed to pasting one from the clipboard.
+ sel.setPixmap (
+ kpPixmapFX::pixmapWithDefinedTransparentPixels (
+ rawPixmap,
+ Qt::white)); // CONFIG
+
+ QApplication::clipboard ()->setData (new kpSelectionDrag (sel),
+ QClipboard::Clipboard);
+ }
+
+ QApplication::restoreOverrideCursor ();
+}
+
+
+static bool HasSomethingToPaste (kpMainWindow *mw)
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow(" << mw->name () << "):HasSomethingToPaste()" << endl;
+ QTime timer;
+ timer.start ();
+#else
+ (void) mw;
+#endif
+
+ bool hasSomething = false;
+
+ QMimeSource *ms = QApplication::clipboard ()->data (QClipboard::Clipboard);
+ if (ms)
+ {
+ // It's faster to test for QTextDrag::canDecode() first due to the
+ // lazy evaluation of the '||' operator.
+ hasSomething = (QTextDrag::canDecode (ms) ||
+ kpSelectionDrag::canDecode (ms));
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t" << mw->name () << "***canDecode=" << timer.restart () << endl;
+ for (int i = 0; ; i++)
+ {
+ const char *fmt = ms->format (i);
+ if (!fmt)
+ break;
+
+ kdDebug () << "\t'" << fmt << "'" << endl;
+ }
+ #endif
+ }
+
+ return hasSomething;
+}
+
+// HACK: SYNC: Non-Qt apps do not cause QApplication::clipboard() to
+// emit dataChanged(). We don't want to have our paste
+// action disabled when we can actually paste something.
+//
+// So we make sure the paste action is always enabled and
+// before any paste, we check if there's actually something
+// to paste (HasSomethingToPasteWithDialogIfNot ()).
+
+#if 1 // Hack code path
+
+
+// Call before any paste only.
+static bool HasSomethingToPasteWithDialogIfNot (kpMainWindow *mw)
+{
+ if (::HasSomethingToPaste (mw))
+ return true;
+
+ // STRING: Unfortunately, we are in a string freeze.
+#if 1
+ (void) mw;
+#else
+ QApplication::setOverrideCursor (Qt::arrowCursor);
+
+ KMessageBox::sorry (mw,
+ STRING_FREEZE_i18n ("<qt><p>There is nothing in the clipboard to paste.</p></qt>"),
+ STRING_FREEZE_i18n ("Cannot Paste"));
+
+ QApplication::restoreOverrideCursor ();
+#endif
+
+ return false;
+}
+
+// private slot
+void kpMainWindow::slotEnablePaste ()
+{
+ const bool shouldEnable = true;
+ m_actionPasteInNewWindow->setEnabled (shouldEnable);
+ m_actionPaste->setEnabled (shouldEnable);
+}
+
+
+#else // No hack
+
+
+// Call before any paste only.
+static bool HasSomethingToPasteWithDialogIfNot (kpMainWindow *)
+{
+ // We will not be called if there's nothing to paste, as the paste
+ // action would have been disabled. But do _not_ assert that
+ // (see the slotPaste() "data unexpectedly disappeared" KMessageBox).
+ return true;
+}
+
+// private slot
+void kpMainWindow::slotEnablePaste ()
+{
+ const bool shouldEnable = ::HasSomethingToPaste (this);
+ m_actionPasteInNewWindow->setEnabled (shouldEnable);
+ m_actionPaste->setEnabled (shouldEnable);
+}
+
+
+#endif
+
+
+// private
+QRect kpMainWindow::calcUsefulPasteRect (int pixmapWidth, int pixmapHeight)
+{
+#if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "kpMainWindow::calcUsefulPasteRect("
+ << pixmapWidth << "," << pixmapHeight
+ << ")"
+ << endl;
+#endif
+ if (!m_document)
+ {
+ kdError () << "kpMainWindow::calcUsefulPasteRect() without doc" << endl;
+ return QRect ();
+ }
+
+ // TODO: 1st choice is to paste sel near but not overlapping last deselect point
+
+ if (m_mainView && m_scrollView)
+ {
+ const QPoint viewTopLeft (m_scrollView->contentsX (),
+ m_scrollView->contentsY ());
+
+ const QPoint docTopLeft = m_mainView->transformViewToDoc (viewTopLeft);
+
+ if ((docTopLeft.x () + pixmapWidth <= m_document->width () &&
+ docTopLeft.y () + pixmapHeight <= m_document->height ()) ||
+ pixmapWidth <= docTopLeft.x () ||
+ pixmapHeight <= docTopLeft.y ())
+ {
+ return QRect (docTopLeft.x (), docTopLeft.y (),
+ pixmapWidth, pixmapHeight);
+ }
+ }
+
+ return QRect (0, 0, pixmapWidth, pixmapHeight);
+}
+
+// private
+void kpMainWindow::paste (const kpSelection &sel, bool forceTopLeft)
+{
+#if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "kpMainWindow::paste(forceTopLeft=" << forceTopLeft << ")"
+ << endl;
+#endif
+
+ if (!sel.pixmap ())
+ {
+ kdError () << "kpMainWindow::paste() with sel without pixmap" << endl;
+ return;
+ }
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+
+ //
+ // Make sure we've got a document (esp. with File/Close)
+ //
+
+ if (!m_document)
+ {
+ kpDocument *newDoc = new kpDocument (
+ sel.width (), sel.height (), this);
+
+ // will also create viewManager
+ setDocument (newDoc);
+ }
+
+
+ //
+ // Paste as new selection
+ //
+
+ kpSelection selInUsefulPos = sel;
+ if (!forceTopLeft)
+ selInUsefulPos.moveTo (calcUsefulPasteRect (sel.width (), sel.height ()).topLeft ());
+ addDeselectFirstCommand (new kpToolSelectionCreateCommand (
+ selInUsefulPos.isText () ?
+ i18n ("Text: Create Box") :
+ i18n ("Selection: Create"),
+ selInUsefulPos,
+ this));
+
+
+#if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "sel.size=" << QSize (sel.width (), sel.height ())
+ << " document.size="
+ << QSize (m_document->width (), m_document->height ())
+ << endl;
+#endif
+
+ // If the selection is bigger than the document, automatically
+ // resize the document (with the option of Undo'ing) to fit
+ // the selection.
+ //
+ // No annoying dialog necessary.
+ //
+ if (sel.width () > m_document->width () ||
+ sel.height () > m_document->height ())
+ {
+ m_commandHistory->addCommand (
+ new kpToolResizeScaleCommand (
+ false/*act on doc, not sel*/,
+ QMAX (sel.width (), m_document->width ()),
+ QMAX (sel.height (), m_document->height ()),
+ kpToolResizeScaleCommand::Resize,
+ this));
+ }
+
+
+ QApplication::restoreOverrideCursor ();
+}
+
+// public
+void kpMainWindow::pasteText (const QString &text,
+ bool forceNewTextSelection,
+ const QPoint &newTextSelectionTopLeft)
+{
+#if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "kpMainWindow::pasteText(" << text
+ << ",forceNewTextSelection=" << forceNewTextSelection
+ << ",newTextSelectionTopLeft=" << newTextSelectionTopLeft
+ << ")" << endl;
+#endif
+
+ if (text.isEmpty ())
+ return;
+
+
+ // sync: restoreOverrideCursor() in all exit paths
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+
+ QValueVector <QString> textLines (1, QString::null);
+
+ for (int i = 0; i < (int) text.length (); i++)
+ {
+ if (text [i] == '\n')
+ textLines.push_back (QString::null);
+ else
+ textLines [textLines.size () - 1].append (text [i]);
+ }
+
+
+ if (!forceNewTextSelection &&
+ m_document && m_document->selection () &&
+ m_document->selection ()->isText () &&
+ m_commandHistory && m_viewManager)
+ {
+ #if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "\treusing existing Text Selection" << endl;
+ #endif
+
+ kpMacroCommand *macroCmd = new kpMacroCommand (i18n ("Text: Paste"),
+ this);
+
+ for (int i = 0; i < (int) textLines.size (); i++)
+ {
+ if (i > 0)
+ {
+ macroCmd->addCommand (
+ new kpToolTextEnterCommand (
+ QString::null/*uninteresting child of macroCmd*/,
+ m_viewManager->textCursorRow (),
+ m_viewManager->textCursorCol (),
+ this));
+ }
+
+ macroCmd->addCommand (
+ new kpToolTextInsertCommand (
+ QString::null/*uninteresting child of macroCmd*/,
+ m_viewManager->textCursorRow (),
+ m_viewManager->textCursorCol (),
+ textLines [i],
+ this));
+ }
+
+ m_commandHistory->addCommand (macroCmd, false/*no exec*/);
+ }
+ else
+ {
+ #if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "\tcreating Text Selection" << endl;
+ #endif
+
+ const kpTextStyle ts = textStyle ();
+ const QFontMetrics fontMetrics = ts.fontMetrics ();
+
+ int height = textLines.size () * fontMetrics.height ();
+ if (textLines.size () >= 1)
+ height += (textLines.size () - 1) * fontMetrics.leading ();
+
+ int width = 0;
+ for (QValueVector <QString>::const_iterator it = textLines.begin ();
+ it != textLines.end ();
+ it++)
+ {
+ const int w = fontMetrics.width (*it);
+ if (w > width)
+ width = w;
+ }
+
+
+ const int selWidth = QMAX (kpSelection::minimumWidthForTextStyle (ts),
+ width + kpSelection::textBorderSize () * 2);
+ const int selHeight = QMAX (kpSelection::minimumHeightForTextStyle (ts),
+ height + kpSelection::textBorderSize () * 2);
+ kpSelection sel (QRect (0, 0, selWidth, selHeight),
+ textLines,
+ ts);
+
+ if (newTextSelectionTopLeft != KP_INVALID_POINT)
+ {
+ sel.moveTo (newTextSelectionTopLeft);
+ paste (sel, true/*force topLeft*/);
+ }
+ else
+ {
+ paste (sel);
+ }
+ }
+
+
+ QApplication::restoreOverrideCursor ();
+}
+
+// public
+void kpMainWindow::pasteTextAt (const QString &text, const QPoint &point,
+ bool allowNewTextSelectionPointShift)
+{
+#if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "kpMainWindow::pasteTextAt(" << text
+ << ",point=" << point
+ << ",allowNewTextSelectionPointShift="
+ << allowNewTextSelectionPointShift
+ << ")" << endl;
+#endif
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+
+ if (m_document &&
+ m_document->selection () &&
+ m_document->selection ()->isText () &&
+ m_document->selection ()->pointIsInTextArea (point))
+ {
+ kpSelection *sel = m_document->selection ();
+
+ const int row = sel->textRowForPoint (point);
+ const int col = sel->textColForPoint (point);
+
+ m_viewManager->setTextCursorPosition (row, col);
+
+ pasteText (text);
+ }
+ else
+ {
+ QPoint pointToUse = point;
+
+ if (allowNewTextSelectionPointShift)
+ {
+ // TODO: In terms of doc pixels, would be inconsistent behaviour
+ // based on zoomLevel of view.
+ // pointToUse -= QPoint (-view->selectionResizeHandleAtomicSize (),
+ // -view->selectionResizeHandleAtomicSize ());
+ }
+
+ pasteText (text, true/*force new text selection*/, pointToUse);
+ }
+
+ QApplication::restoreOverrideCursor ();
+}
+
+// public slot
+void kpMainWindow::slotPaste ()
+{
+#if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "kpMainWindow::slotPaste() CALLED" << endl;
+#endif
+
+ // sync: restoreOverrideCursor() in all exit paths
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+
+ if (!::HasSomethingToPasteWithDialogIfNot (this))
+ {
+ QApplication::restoreOverrideCursor ();
+ return;
+ }
+
+
+ //
+ // Acquire the pixmap
+ //
+
+ QMimeSource *ms = QApplication::clipboard ()->data (QClipboard::Clipboard);
+ if (!ms)
+ {
+ kdError () << "kpMainWindow::slotPaste() without mimeSource" << endl;
+ QApplication::restoreOverrideCursor ();
+ return;
+ }
+
+ kpSelection sel;
+ QString text;
+ if (kpSelectionDrag::decode (ms, sel/*ref*/, pasteWarnAboutLossInfo ()))
+ {
+ sel.setTransparency (selectionTransparency ());
+ paste (sel);
+ }
+ else if (QTextDrag::decode (ms, text/*ref*/))
+ {
+ pasteText (text);
+ }
+ else
+ {
+ QApplication::restoreOverrideCursor ();
+
+ kdDebug () << "kpMainWindow::slotPaste() could not decode selection" << endl;
+ kdDebug () << "\tFormats supported:" << endl;
+ for (int i = 0; ms->format (i); i++)
+ {
+ kdDebug () << "\t\t" << i << ":" << ms->format (i) << endl;
+ }
+
+ // TODO: fix Klipper
+ KMessageBox::sorry (this,
+ i18n ("<qt><p>KolourPaint cannot paste the contents of"
+ " the clipboard as the data unexpectedly disappeared.</p>"
+
+ "<p>This usually occurs if the application which was"
+ " responsible"
+ " for the clipboard contents has been closed.</p></qt>"),
+ i18n ("Cannot Paste"));
+
+ // TODO: PROPAGATE: interprocess
+ if (KMainWindow::memberList)
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\thave memberList" << endl;
+ #endif
+
+ for (QPtrList <KMainWindow>::const_iterator it = KMainWindow::memberList->begin ();
+ it != KMainWindow::memberList->end ();
+ it++)
+ {
+ kpMainWindow *mw = dynamic_cast <kpMainWindow *> (*it);
+
+ if (!mw)
+ {
+ kdError () << "kpMainWindow::slotPaste() given fake kpMainWindow: " << (*it) << endl;
+ continue;
+ }
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t\tmw=" << mw << endl;
+ #endif
+
+ mw->slotEnablePaste ();
+ }
+ }
+
+ return;
+ }
+
+ QApplication::restoreOverrideCursor ();
+}
+
+// private slot
+void kpMainWindow::slotPasteInNewWindow ()
+{
+#if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "kpMainWindow::slotPasteInNewWindow() CALLED" << endl;
+#endif
+
+ // sync: restoreOverrideCursor() in all exit paths
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+
+ if (!::HasSomethingToPasteWithDialogIfNot (this))
+ {
+ QApplication::restoreOverrideCursor ();
+ return;
+ }
+
+
+ //
+ // Pasting must ensure that:
+ //
+ // Requirement 1. the document is the same size as the image to be pasted.
+ // Requirement 2. transparent pixels in the image must remain as transparent.
+ //
+
+ kpMainWindow *win = new kpMainWindow (0/*no document*/);
+ win->show ();
+
+ // Make "Edit / Paste in New Window" always paste white pixels as white.
+ // Don't let selection transparency get in the way and paste them as
+ // transparent.
+ kpSelectionTransparency transparency = win->selectionTransparency ();
+ if (transparency.isTransparent ())
+ {
+ #if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "\tchanging selection transparency to opaque" << endl;
+ #endif
+ transparency.setOpaque ();
+ // Since we are setting selection transparency programmatically
+ // -- as opposed to in response to user input -- this will not
+ // affect the selection transparency tool option widget's "last used"
+ // config setting.
+ win->setSelectionTransparency (transparency);
+ }
+
+ // (this handles Requirement 1. above)
+ win->slotPaste ();
+
+ // (this handles Requirement 2. above;
+ // slotDeselect() is not enough unless the document is filled with the
+ // transparent color in advance)
+ win->slotCrop ();
+
+
+ QApplication::restoreOverrideCursor ();
+}
+
+// public slot
+void kpMainWindow::slotDelete ()
+{
+#if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "kpMainWindow::slotDelete() CALLED" << endl;
+#endif
+ if (!m_actionDelete->isEnabled ())
+ {
+ #if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "\taction not enabled - was probably called from kpTool::keyPressEvent()" << endl;
+ #endif
+ return;
+ }
+
+ if (!m_document || !m_document->selection ())
+ {
+ kdError () << "kpMainWindow::slotDelete () doc=" << m_document
+ << " sel=" << (m_document ? m_document->selection () : 0)
+ << endl;
+ return;
+ }
+
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ addImageOrSelectionCommand (new kpToolSelectionDestroyCommand (
+ m_document->selection ()->isText () ?
+ i18n ("Text: Delete Box") : // not to be confused with i18n ("Text: Delete")
+ i18n ("Selection: Delete"),
+ false/*no push onto doc*/,
+ this));
+}
+
+
+// private slot
+void kpMainWindow::slotSelectAll ()
+{
+#if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "kpMainWindow::slotSelectAll() CALLED" << endl;
+#endif
+ if (!m_document)
+ {
+ kdError () << "kpMainWindow::slotSelectAll() without doc" << endl;
+ return;
+ }
+
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ if (m_document->selection ())
+ slotDeselect ();
+
+ // just the border - don't actually pull pixmap from doc yet
+ m_document->setSelection (kpSelection (kpSelection::Rectangle, m_document->rect (), selectionTransparency ()));
+
+ if (tool ())
+ tool ()->somethingBelowTheCursorChanged ();
+}
+
+
+// private
+void kpMainWindow::addDeselectFirstCommand (kpCommand *cmd)
+{
+#if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "kpMainWindow::addDeselectFirstCommand("
+ << cmd
+ << ")"
+ << endl;
+#endif
+
+
+ kpSelection *sel = m_document->selection ();
+
+#if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "\tsel=" << sel << endl;
+#endif
+
+ if (sel)
+ {
+ // if you just dragged out something with no action then
+ // forget the drag
+ if (!sel->pixmap ())
+ {
+ #if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "\tjust a fresh border - was nop - delete" << endl;
+ #endif
+ m_document->selectionDelete ();
+ if (tool ())
+ tool ()->somethingBelowTheCursorChanged ();
+
+ if (cmd)
+ m_commandHistory->addCommand (cmd);
+ }
+ else
+ {
+ #if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "\treal selection with pixmap - push onto doc cmd" << endl;
+ #endif
+ kpCommand *deselectCommand = new kpToolSelectionDestroyCommand (
+ sel->isText () ?
+ i18n ("Text: Finish") :
+ i18n ("Selection: Deselect"),
+ true/*push onto document*/,
+ this);
+
+ if (cmd)
+ {
+ kpMacroCommand *macroCmd = new kpMacroCommand (cmd->name (), this);
+ macroCmd->addCommand (deselectCommand);
+ macroCmd->addCommand (cmd);
+ m_commandHistory->addCommand (macroCmd);
+ }
+ else
+ m_commandHistory->addCommand (deselectCommand);
+ }
+ }
+ else
+ {
+ if (cmd)
+ m_commandHistory->addCommand (cmd);
+ }
+}
+
+
+// public slot
+void kpMainWindow::slotDeselect ()
+{
+#if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "kpMainWindow::slotDeselect() CALLED" << endl;
+#endif
+ if (!m_document || !m_document->selection ())
+ {
+ kdError () << "kpMainWindow::slotDeselect() doc=" << m_document
+ << " sel=" << (m_document ? m_document->selection () : 0)
+ << endl;
+ return;
+ }
+
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ addDeselectFirstCommand (0);
+}
+
+
+// private slot
+void kpMainWindow::slotCopyToFile ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotCopyToFile()" << endl;
+#endif
+
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+
+ if (!m_document->selection ())
+ return;
+
+ kpSelection sel = *m_document->selection ();
+
+ QPixmap pixmapToSave;
+
+ if (!sel.pixmap ())
+ {
+ // Not a floating selection - user has just selected a region;
+ // haven't pulled it off yet so probably don't expect and can't
+ // visualise selection transparency so give opaque, not transparent
+ // pixmap.
+ pixmapToSave = m_document->getSelectedPixmap ();
+ }
+ else
+ pixmapToSave = sel.transparentPixmap ();
+
+
+ kpDocumentSaveOptions chosenSaveOptions;
+ bool allowOverwritePrompt, allowLossyPrompt;
+ KURL chosenURL = askForSaveURL (i18n ("Copy to File"),
+ m_lastCopyToURL.url (),
+ pixmapToSave,
+ m_lastCopyToSaveOptions,
+ kpDocumentMetaInfo (),
+ kpSettingsGroupEditCopyTo,
+ false/*allow remote files*/,
+ &chosenSaveOptions,
+ m_copyToFirstTime,
+ &allowOverwritePrompt,
+ &allowLossyPrompt);
+
+ if (chosenURL.isEmpty ())
+ return;
+
+
+ if (!kpDocument::savePixmapToFile (pixmapToSave,
+ chosenURL,
+ chosenSaveOptions, kpDocumentMetaInfo (),
+ allowOverwritePrompt,
+ allowLossyPrompt,
+ this))
+ {
+ return;
+ }
+
+
+ addRecentURL (chosenURL);
+
+
+ m_lastCopyToURL = chosenURL;
+ m_lastCopyToSaveOptions = chosenSaveOptions;
+
+ m_copyToFirstTime = false;
+}
+
+// private slot
+void kpMainWindow::slotPasteFromFile ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotPasteFromFile()" << endl;
+#endif
+
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+
+ KURL::List urls = askForOpenURLs (i18n ("Paste From File"),
+ m_lastPasteFromURL.url (),
+ false/*only 1 URL*/);
+
+ if (urls.count () != 1)
+ return;
+
+ KURL url = urls.first ();
+ m_lastPasteFromURL = url;
+
+
+ QPixmap pixmap = kpDocument::getPixmapFromFile (url,
+ false/*show error message if doesn't exist*/,
+ this);
+
+
+ if (pixmap.isNull ())
+ return;
+
+
+ addRecentURL (url);
+
+ paste (kpSelection (kpSelection::Rectangle,
+ QRect (0, 0, pixmap.width (), pixmap.height ()),
+ pixmap,
+ selectionTransparency ()));
+}
+
diff --git a/kolourpaint/kpmainwindow_file.cpp b/kolourpaint/kpmainwindow_file.cpp
new file mode 100644
index 00000000..b30b323e
--- /dev/null
+++ b/kolourpaint/kpmainwindow_file.cpp
@@ -0,0 +1,1409 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <kpmainwindow.h>
+
+#include <qcstring.h>
+#include <qdatastream.h>
+#include <qpaintdevicemetrics.h>
+#include <qpainter.h>
+#include <qsize.h>
+
+#include <dcopclient.h>
+#include <kapplication.h>
+#include <kaction.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kfiledialog.h>
+#include <kiconloader.h>
+#include <kimagefilepreview.h>
+#include <kimageio.h>
+#include <kio/netaccess.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kprinter.h>
+#include <kstdaccel.h>
+#include <kstdaction.h>
+#include <kscan.h>
+
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpdocumentsaveoptionswidget.h>
+#include <kptool.h>
+#include <kpview.h>
+#include <kpviewmanager.h>
+
+
+// private
+void kpMainWindow::setupFileMenuActions ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::setupFileMenuActions()" << endl;
+#endif
+ KActionCollection *ac = actionCollection ();
+
+ m_actionNew = KStdAction::openNew (this, SLOT (slotNew ()), ac);
+ m_actionOpen = KStdAction::open (this, SLOT (slotOpen ()), ac);
+
+ m_actionOpenRecent = KStdAction::openRecent (this, SLOT (slotOpenRecent (const KURL &)), ac);
+ m_actionOpenRecent->loadEntries (kapp->config ());
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\trecent URLs=" << m_actionOpenRecent->items () << endl;
+#endif
+
+ m_actionSave = KStdAction::save (this, SLOT (slotSave ()), ac);
+ m_actionSaveAs = KStdAction::saveAs (this, SLOT (slotSaveAs ()), ac);
+
+ m_actionExport = new KAction (i18n ("E&xport..."), 0,
+ this, SLOT (slotExport ()), ac, "file_export");
+
+ m_actionScan = new KAction (i18n ("Scan..."), SmallIcon ("scanner"), 0,
+ this, SLOT (slotScan ()), ac, "file_scan");
+
+ //m_actionRevert = KStdAction::revert (this, SLOT (slotRevert ()), ac);
+ m_actionReload = new KAction (i18n ("Reloa&d"), KStdAccel::reload (),
+ this, SLOT (slotReload ()), ac, "file_revert");
+ slotEnableReload ();
+
+ m_actionPrint = KStdAction::print (this, SLOT (slotPrint ()), ac);
+ m_actionPrintPreview = KStdAction::printPreview (this, SLOT (slotPrintPreview ()), ac);
+
+ m_actionMail = KStdAction::mail (this, SLOT (slotMail ()), ac);
+
+ m_actionSetAsWallpaperCentered = new KAction (i18n ("Set as Wa&llpaper (Centered)"), 0,
+ this, SLOT (slotSetAsWallpaperCentered ()), ac, "file_set_as_wallpaper_centered");
+ m_actionSetAsWallpaperTiled = new KAction (i18n ("Set as Wallpaper (&Tiled)"), 0,
+ this, SLOT (slotSetAsWallpaperTiled ()), ac, "file_set_as_wallpaper_tiled");
+
+ m_actionClose = KStdAction::close (this, SLOT (slotClose ()), ac);
+ m_actionQuit = KStdAction::quit (this, SLOT (slotQuit ()), ac);
+
+ m_scanDialog = 0;
+
+ enableFileMenuDocumentActions (false);
+}
+
+// private
+void kpMainWindow::enableFileMenuDocumentActions (bool enable)
+{
+ // m_actionNew
+ // m_actionOpen
+
+ // m_actionOpenRecent
+
+ m_actionSave->setEnabled (enable);
+ m_actionSaveAs->setEnabled (enable);
+
+ m_actionExport->setEnabled (enable);
+
+ // m_actionReload
+
+ m_actionPrint->setEnabled (enable);
+ m_actionPrintPreview->setEnabled (enable);
+
+ m_actionMail->setEnabled (enable);
+
+ m_actionSetAsWallpaperCentered->setEnabled (enable);
+ m_actionSetAsWallpaperTiled->setEnabled (enable);
+
+ m_actionClose->setEnabled (enable);
+ // m_actionQuit->setEnabled (enable);
+}
+
+
+// private
+void kpMainWindow::addRecentURL (const KURL &url)
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::addRecentURL(" << url << ")" << endl;
+#endif
+ if (url.isEmpty ())
+ return;
+
+
+ KConfig *cfg = kapp->config ();
+
+ // KConfig::readEntry() does not actually reread from disk, hence doesn't
+ // realise what other processes have done e.g. Settings / Show Path
+ cfg->reparseConfiguration ();
+
+ // HACK: Something might have changed interprocess.
+ // If we could PROPAGATE: interprocess, then this wouldn't be required.
+ m_actionOpenRecent->loadEntries (cfg);
+
+ m_actionOpenRecent->addURL (url);
+
+ m_actionOpenRecent->saveEntries (cfg);
+ cfg->sync ();
+
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tnew recent URLs=" << m_actionOpenRecent->items () << endl;
+#endif
+
+
+ // TODO: PROPAGATE: interprocess
+ if (KMainWindow::memberList)
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\thave memberList" << endl;
+ #endif
+
+ for (QPtrList <KMainWindow>::const_iterator it = KMainWindow::memberList->begin ();
+ it != KMainWindow::memberList->end ();
+ it++)
+ {
+ kpMainWindow *mw = dynamic_cast <kpMainWindow *> (*it);
+
+ if (!mw)
+ {
+ kdError () << "kpMainWindow::addRecentURL() given fake kpMainWindow: " << (*it) << endl;
+ continue;
+ }
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t\tmw=" << mw << endl;
+ #endif
+
+ if (mw != this)
+ {
+ // WARNING: Do not use KRecentFilesAction::setItems()
+ // - it does not work since only its superclass,
+ // KSelectAction, implements setItems() and can't
+ // update KRecentFilesAction's URL list.
+
+ // Avoid URL memory leak in KRecentFilesAction::loadEntries().
+ mw->m_actionOpenRecent->clearURLList ();
+
+ mw->m_actionOpenRecent->loadEntries (cfg);
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t\t\tcheck recent URLs="
+ << mw->m_actionOpenRecent->items () << endl;
+ #endif
+ }
+ }
+ }
+}
+
+
+// private slot
+void kpMainWindow::slotNew ()
+{
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ if (m_document)
+ {
+ kpMainWindow *win = new kpMainWindow ();
+ win->show ();
+ }
+ else
+ {
+ open (KURL (), true/*create an empty doc*/);
+ }
+}
+
+
+// private
+QSize kpMainWindow::defaultDocSize () const
+{
+ // KConfig::readEntry() does not actually reread from disk, hence doesn't
+ // realise what other processes have done e.g. Settings / Show Path
+ kapp->config ()->reparseConfiguration ();
+
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupGeneral);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ QSize docSize = cfg->readSizeEntry (kpSettingLastDocSize);
+
+ if (docSize.isEmpty ())
+ {
+ docSize = QSize (400, 300);
+ }
+ else
+ {
+ // Don't get too big or you'll thrash (or even lock up) the computer
+ // just by opening a window
+ docSize = QSize (QMIN (2048, docSize.width ()),
+ QMIN (2048, docSize.height ()));
+ }
+
+ return docSize;
+}
+
+// private
+void kpMainWindow::saveDefaultDocSize (const QSize &size)
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tCONFIG: saving Last Doc Size = " << size << endl;
+#endif
+
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupGeneral);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ cfg->writeEntry (kpSettingLastDocSize, size);
+ cfg->sync ();
+}
+
+
+// private
+bool kpMainWindow::shouldOpenInNewWindow () const
+{
+ return (m_document && !m_document->isEmpty ());
+}
+
+// private
+void kpMainWindow::setDocumentChoosingWindow (kpDocument *doc)
+{
+ // need new window?
+ if (shouldOpenInNewWindow ())
+ {
+ // send doc to new window
+ kpMainWindow *win = new kpMainWindow (doc);
+ win->show ();
+ }
+ else
+ {
+ // set up views, doc signals
+ setDocument (doc);
+ }
+}
+
+
+// private
+kpDocument *kpMainWindow::openInternal (const KURL &url,
+ const QSize &fallbackDocSize,
+ bool newDocSameNameIfNotExist)
+{
+ // create doc
+ kpDocument *newDoc = new kpDocument (fallbackDocSize.width (),
+ fallbackDocSize.height (),
+ this);
+ if (!newDoc->open (url, newDocSameNameIfNotExist))
+ {
+ delete newDoc;
+ return 0;
+ }
+
+ // Send document to current or new window.
+ setDocumentChoosingWindow (newDoc);
+
+ return newDoc;
+}
+
+// private
+bool kpMainWindow::open (const KURL &url, bool newDocSameNameIfNotExist)
+{
+ kpDocument *newDoc = openInternal (url,
+ defaultDocSize (),
+ newDocSameNameIfNotExist);
+ if (newDoc)
+ {
+ if (newDoc->isFromURL (false/*don't bother checking exists*/))
+ addRecentURL (url);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+// private
+KURL::List kpMainWindow::askForOpenURLs (const QString &caption, const QString &startURL,
+ bool allowMultipleURLs)
+{
+ QStringList mimeTypes = KImageIO::mimeTypes (KImageIO::Reading);
+#if DEBUG_KP_MAIN_WINDOW
+ QStringList sortedMimeTypes = mimeTypes;
+ sortedMimeTypes.sort ();
+ kdDebug () << "kpMainWindow::askForURLs(allowMultiple="
+ << allowMultipleURLs
+ << ")" << endl
+ << "\tmimeTypes=" << mimeTypes << endl
+ << "\tsortedMimeTypes=" << sortedMimeTypes << endl;
+#endif
+ QString filter = mimeTypes.join (" ");
+
+ KFileDialog fd (startURL, filter, this, "fd", true/*modal*/);
+ fd.setCaption (caption);
+ fd.setOperationMode (KFileDialog::Opening);
+ if (allowMultipleURLs)
+ fd.setMode (KFile::Files);
+ fd.setPreviewWidget (new KImageFilePreview (&fd));
+
+ if (fd.exec ())
+ return fd.selectedURLs ();
+ else
+ return KURL::List ();
+}
+
+// private slot
+void kpMainWindow::slotOpen ()
+{
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+
+ const KURL::List urls = askForOpenURLs (i18n ("Open Image"),
+ m_document ? m_document->url ().url () : QString::null);
+
+ for (KURL::List::const_iterator it = urls.begin ();
+ it != urls.end ();
+ it++)
+ {
+ open (*it);
+ }
+}
+
+// private slot
+void kpMainWindow::slotOpenRecent (const KURL &url)
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotOpenRecent(" << url << ")" << endl;
+ kdDebug () << "\titems=" << m_actionOpenRecent->items () << endl;
+#endif
+
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ open (url);
+
+ // If the open is successful, addRecentURL() would have bubbled up the
+ // URL in the File / Open Recent action. As a side effect, the URL is
+ // deselected.
+ //
+ // If the open fails, we should deselect the URL:
+ //
+ // 1. for consistency
+ //
+ // 2. because it has not been opened.
+ //
+ m_actionOpenRecent->setCurrentItem (-1);
+}
+
+
+// private slot
+void kpMainWindow::slotScan ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotScan() scanDialog=" << m_scanDialog << endl;
+#endif
+
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+
+ if (!m_scanDialog)
+ {
+ // Create scan dialog by looking for plugin.
+ // [takes about 500ms on 350Mhz]
+ m_scanDialog = KScanDialog::getScanDialog (this, "scandialog", true/*modal*/);
+
+ // No scanning support (kdegraphics/libkscan) installed?
+ // [Remove $KDEDIR/share/servicetypes/kscan.desktop and
+ // $KDEDIR/share/services/scanservice.desktop to simulate this]
+ if (!m_scanDialog)
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tcould not create scan dialog" << endl;
+ #endif
+ // Instead, we could try to create the scan dialog in the ctor
+ // and just disable the action in the first place, removing
+ // the need for this dialog.
+ //
+ // But this increases startup time and is a bit risky e.g. if
+ // the scan support hangs, KolourPaint would not be able to be
+ // started at all.
+ //
+ // Also, disabling the action is bad because the scan support
+ // can be installed while KolourPaint is still running.
+ KMessageBox::sorry (this,
+ i18n ("Scanning support is not installed."),
+ i18n ("No Scanning Support"));
+ return;
+ }
+
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tcreated scanDialog=" << m_scanDialog << endl;
+ #endif
+ connect (m_scanDialog, SIGNAL (finalImage (const QImage &, int)),
+ SLOT (slotScanned (const QImage &, int)));
+ }
+
+
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tcalling setup" << endl;
+#endif
+ // Bring up dialog to select scan device.
+ if (m_scanDialog->setup ())
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t\tOK - showing dialog" << endl;
+ #endif
+ // Called only if scanner configured/available.
+ //
+ // In reality, this seems to be called even if you press "Cancel" in
+ // the KScanDialog::setup() dialog!
+ m_scanDialog->show ();
+ }
+ else
+ {
+ // Have never seen this code path execute even if "Cancel" is pressed.
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t\tFAIL" << endl;
+ #endif
+ }
+}
+
+// private slot
+void kpMainWindow::slotScanned (const QImage &image, int)
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotScanned() image.rect=" << image.rect () << endl;
+#endif
+
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\thiding dialog" << endl;
+#endif
+ // (KScanDialog does not close itself after a scan is made)
+ //
+ // Close the dialog, first thing:
+ //
+ // 1. This means that any dialogs we bring up won't be nested on top.
+ //
+ // 2. We don't want to return from this method but forget to close
+ // the dialog. So do it before anything else.
+ m_scanDialog->hide ();
+
+ // (just in case there's some drawing between slotScan() exiting and
+ // us being called)
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+
+ // TODO: Maybe this code should be moved into kpdocument.cpp -
+ // since it resembles the responsibilities of kpDocument::open().
+
+ // Convert QImage to kpDocument's image format, gathering meta info
+ // from QImage.
+ kpDocumentSaveOptions saveOptions;
+ kpDocumentMetaInfo metaInfo;
+ const QPixmap pixmap = kpDocument::convertToPixmapAsLosslessAsPossible (
+ image,
+ kpMainWindow::pasteWarnAboutLossInfo (),
+ &saveOptions,
+ &metaInfo);
+
+ if (pixmap.isNull ())
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tcould not convert to pixmap" << endl;
+ #endif
+ KMessageBox::sorry (this,
+ i18n ("Cannot scan - out of graphics memory."),
+ i18n ("Cannot Scan"));
+ return;
+ }
+
+
+ // Create document from image and meta info.
+ kpDocument *doc = new kpDocument (pixmap.width (), pixmap.height (), this);
+ doc->setPixmap (pixmap);
+ doc->setSaveOptions (saveOptions);
+ doc->setMetaInfo (metaInfo);
+
+
+ // Send document to current or new window.
+ setDocumentChoosingWindow (doc);
+}
+
+
+// private slot
+bool kpMainWindow::save (bool localOnly)
+{
+ if (m_document->url ().isEmpty () ||
+ KImageIO::mimeTypes (KImageIO::Writing)
+ .findIndex (m_document->saveOptions ()->mimeType ()) < 0 ||
+ // SYNC: kpDocument::getPixmapFromFile() can't determine quality
+ // from file so it has been set initially to an invalid value.
+ (m_document->saveOptions ()->mimeTypeHasConfigurableQuality () &&
+ m_document->saveOptions ()->qualityIsInvalid ()) ||
+ (localOnly && !m_document->url ().isLocalFile ()))
+ {
+ return saveAs (localOnly);
+ }
+ else
+ {
+ if (m_document->save (false/*no overwrite prompt*/,
+ !m_document->savedAtLeastOnceBefore ()/*lossy prompt*/))
+ {
+ addRecentURL (m_document->url ());
+ return true;
+ }
+ else
+ return false;
+ }
+}
+
+// private slot
+bool kpMainWindow::slotSave ()
+{
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ return save ();
+}
+
+// private
+KURL kpMainWindow::askForSaveURL (const QString &caption,
+ const QString &startURL,
+ const QPixmap &pixmapToBeSaved,
+ const kpDocumentSaveOptions &startSaveOptions,
+ const kpDocumentMetaInfo &docMetaInfo,
+ const QString &forcedSaveOptionsGroup,
+ bool localOnly,
+ kpDocumentSaveOptions *chosenSaveOptions,
+ bool isSavingForFirstTime,
+ bool *allowOverwritePrompt,
+ bool *allowLossyPrompt)
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::askForURL() startURL=" << startURL << endl;
+ startSaveOptions.printDebug ("\tstartSaveOptions");
+#endif
+
+ bool reparsedConfiguration = false;
+
+ // KConfig::readEntry() does not actually reread from disk, hence doesn't
+ // realise what other processes have done e.g. Settings / Show Path
+ // so reparseConfiguration() must be called
+#define SETUP_READ_CFG() \
+ if (!reparsedConfiguration) \
+ { \
+ kapp->config ()->reparseConfiguration (); \
+ reparsedConfiguration = true; \
+ } \
+ \
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), forcedSaveOptionsGroup); \
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+
+ if (chosenSaveOptions)
+ *chosenSaveOptions = kpDocumentSaveOptions ();
+
+ if (allowOverwritePrompt)
+ *allowOverwritePrompt = true; // play it safe for now
+
+ if (allowLossyPrompt)
+ *allowLossyPrompt = true; // play it safe for now
+
+
+ kpDocumentSaveOptions fdSaveOptions = startSaveOptions;
+
+ QStringList mimeTypes = KImageIO::mimeTypes (KImageIO::Writing);
+#if DEBUG_KP_MAIN_WINDOW
+ QStringList sortedMimeTypes = mimeTypes;
+ sortedMimeTypes.sort ();
+ kdDebug () << "\tmimeTypes=" << mimeTypes << endl
+ << "\tsortedMimeTypes=" << sortedMimeTypes << endl;
+#endif
+ if (mimeTypes.isEmpty ())
+ {
+ kdError () << "No KImageIO output mimetypes!" << endl;
+ return KURL ();
+ }
+
+#define MIME_TYPE_IS_VALID() (!fdSaveOptions.mimeTypeIsInvalid () && \
+ mimeTypes.findIndex (fdSaveOptions.mimeType ()) >= 0)
+ if (!MIME_TYPE_IS_VALID ())
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tmimeType=" << fdSaveOptions.mimeType ()
+ << " not valid, get default" << endl;
+ #endif
+
+ SETUP_READ_CFG ();
+
+ fdSaveOptions.setMimeType (kpDocumentSaveOptions::defaultMimeType (cfg));
+
+
+ if (!MIME_TYPE_IS_VALID ())
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tmimeType=" << fdSaveOptions.mimeType ()
+ << " not valid, get hardcoded" << endl;
+ #endif
+ if (mimeTypes.findIndex ("image/png") > -1)
+ fdSaveOptions.setMimeType ("image/png");
+ else if (mimeTypes.findIndex ("image/x-bmp") > -1)
+ fdSaveOptions.setMimeType ("image/x-bmp");
+ else
+ fdSaveOptions.setMimeType (mimeTypes.first ());
+ }
+ }
+#undef MIME_TYPE_IN_LIST
+
+ if (fdSaveOptions.colorDepthIsInvalid ())
+ {
+ SETUP_READ_CFG ();
+
+ fdSaveOptions.setColorDepth (kpDocumentSaveOptions::defaultColorDepth (cfg));
+ fdSaveOptions.setDither (kpDocumentSaveOptions::defaultDither (cfg));
+ }
+
+ if (fdSaveOptions.qualityIsInvalid ())
+ {
+ SETUP_READ_CFG ();
+
+ fdSaveOptions.setQuality (kpDocumentSaveOptions::defaultQuality (cfg));
+ }
+#if DEBUG_KP_MAIN_WINDOW
+ fdSaveOptions.printDebug ("\tcorrected saveOptions passed to fileDialog");
+#endif
+
+ kpDocumentSaveOptionsWidget *saveOptionsWidget =
+ new kpDocumentSaveOptionsWidget (pixmapToBeSaved,
+ fdSaveOptions,
+ docMetaInfo,
+ this);
+
+ KFileDialog fd (startURL, QString::null, this, "fd", true/*modal*/,
+ saveOptionsWidget);
+ saveOptionsWidget->setVisualParent (&fd);
+ fd.setCaption (caption);
+ fd.setOperationMode (KFileDialog::Saving);
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tmimeTypes=" << mimeTypes << endl;
+#endif
+ fd.setMimeFilter (mimeTypes, fdSaveOptions.mimeType ());
+ if (localOnly)
+ fd.setMode (KFile::File | KFile::LocalOnly);
+
+ connect (&fd, SIGNAL (filterChanged (const QString &)),
+ saveOptionsWidget, SLOT (setMimeType (const QString &)));
+
+
+ if (fd.exec ())
+ {
+ kpDocumentSaveOptions newSaveOptions = saveOptionsWidget->documentSaveOptions ();
+ #if DEBUG_KP_MAIN_WINDOW
+ newSaveOptions.printDebug ("\tnewSaveOptions");
+ #endif
+
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), forcedSaveOptionsGroup);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ // Save options user forced - probably want to use them in future
+ kpDocumentSaveOptions::saveDefaultDifferences (cfg,
+ fdSaveOptions, newSaveOptions);
+ cfg->sync ();
+
+
+ if (chosenSaveOptions)
+ *chosenSaveOptions = newSaveOptions;
+
+
+ bool shouldAllowOverwritePrompt =
+ (fd.selectedURL () != startURL ||
+ newSaveOptions.mimeType () != startSaveOptions.mimeType ());
+ if (allowOverwritePrompt)
+ {
+ *allowOverwritePrompt = shouldAllowOverwritePrompt;
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tallowOverwritePrompt=" << *allowOverwritePrompt << endl;
+ #endif
+ }
+
+ if (allowLossyPrompt)
+ {
+ // SYNC: kpDocumentSaveOptions elements - everything except quality
+ // (one quality setting is "just as lossy" as another so no
+ // need to continually warn due to quality change)
+ *allowLossyPrompt =
+ (isSavingForFirstTime ||
+ shouldAllowOverwritePrompt ||
+ newSaveOptions.mimeType () != startSaveOptions.mimeType () ||
+ newSaveOptions.colorDepth () != startSaveOptions.colorDepth () ||
+ newSaveOptions.dither () != startSaveOptions.dither ());
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tallowLossyPrompt=" << *allowLossyPrompt << endl;
+ #endif
+ }
+
+
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tselectedURL=" << fd.selectedURL () << endl;
+ #endif
+ return fd.selectedURL ();
+ }
+ else
+ return KURL ();
+#undef SETUP_READ_CFG
+}
+
+
+// private slot
+bool kpMainWindow::saveAs (bool localOnly)
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::saveAs URL=" << m_document->url () << endl;
+#endif
+
+ kpDocumentSaveOptions chosenSaveOptions;
+ bool allowOverwritePrompt, allowLossyPrompt;
+ KURL chosenURL = askForSaveURL (i18n ("Save Image As"),
+ m_document->url ().url (),
+ m_document->pixmapWithSelection (),
+ *m_document->saveOptions (),
+ *m_document->metaInfo (),
+ kpSettingsGroupFileSaveAs,
+ localOnly,
+ &chosenSaveOptions,
+ !m_document->savedAtLeastOnceBefore (),
+ &allowOverwritePrompt,
+ &allowLossyPrompt);
+
+
+ if (chosenURL.isEmpty ())
+ return false;
+
+
+ if (!m_document->saveAs (chosenURL, chosenSaveOptions,
+ allowOverwritePrompt,
+ allowLossyPrompt))
+ {
+ return false;
+ }
+
+
+ addRecentURL (chosenURL);
+
+ return true;
+}
+
+// private slot
+bool kpMainWindow::slotSaveAs ()
+{
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ return saveAs ();
+}
+
+// private slot
+bool kpMainWindow::slotExport ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotExport()" << endl;
+#endif
+
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+
+ kpDocumentSaveOptions chosenSaveOptions;
+ bool allowOverwritePrompt, allowLossyPrompt;
+ KURL chosenURL = askForSaveURL (i18n ("Export"),
+ m_lastExportURL.url (),
+ m_document->pixmapWithSelection (),
+ m_lastExportSaveOptions,
+ *m_document->metaInfo (),
+ kpSettingsGroupFileExport,
+ false/*allow remote files*/,
+ &chosenSaveOptions,
+ m_exportFirstTime,
+ &allowOverwritePrompt,
+ &allowLossyPrompt);
+
+
+ if (chosenURL.isEmpty ())
+ return false;
+
+
+ if (!kpDocument::savePixmapToFile (m_document->pixmapWithSelection (),
+ chosenURL,
+ chosenSaveOptions, *m_document->metaInfo (),
+ allowOverwritePrompt,
+ allowLossyPrompt,
+ this))
+ {
+ return false;
+ }
+
+
+ addRecentURL (chosenURL);
+
+
+ m_lastExportURL = chosenURL;
+ m_lastExportSaveOptions = chosenSaveOptions;
+
+ m_exportFirstTime = false;
+
+ return true;
+}
+
+
+// private slot
+void kpMainWindow::slotEnableReload ()
+{
+ m_actionReload->setEnabled (m_document);
+}
+
+// private slot
+bool kpMainWindow::slotReload ()
+{
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ if (!m_document)
+ return false;
+
+
+ KURL oldURL = m_document->url ();
+
+
+ if (m_document->isModified ())
+ {
+ int result = KMessageBox::Cancel;
+
+ if (m_document->isFromURL (false/*don't bother checking exists*/) && !oldURL.isEmpty ())
+ {
+ result = KMessageBox::warningContinueCancel (this,
+ i18n ("The document \"%1\" has been modified.\n"
+ "Reloading will lose all changes since you last saved it.\n"
+ "Are you sure?")
+ .arg (m_document->prettyFilename ()),
+ QString::null/*caption*/,
+ i18n ("&Reload"));
+ }
+ else
+ {
+ result = KMessageBox::warningContinueCancel (this,
+ i18n ("The document \"%1\" has been modified.\n"
+ "Reloading will lose all changes.\n"
+ "Are you sure?")
+ .arg (m_document->prettyFilename ()),
+ QString::null/*caption*/,
+ i18n ("&Reload"));
+ }
+
+ if (result != KMessageBox::Continue)
+ return false;
+ }
+
+
+ kpDocument *doc = 0;
+
+ // If it's _supposed to_ come from a URL or it exists
+ if (m_document->isFromURL (false/*don't bother checking exists*/) ||
+ (!oldURL.isEmpty () && KIO::NetAccess::exists (oldURL, true/*open*/, this)))
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotReload() reloading from disk!" << endl;
+ #endif
+
+ doc = new kpDocument (1, 1, this);
+ if (!doc->open (oldURL))
+ {
+ delete doc; doc = 0;
+ return false;
+ }
+
+ addRecentURL (oldURL);
+ }
+ else
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotReload() create doc" << endl;
+ #endif
+
+ doc = new kpDocument (m_document->constructorWidth (),
+ m_document->constructorHeight (),
+ this);
+ doc->setURL (oldURL, false/*not from URL*/);
+ }
+
+
+ setDocument (doc);
+
+ return true;
+}
+
+
+// private
+void kpMainWindow::sendFilenameToPrinter (KPrinter *printer)
+{
+ KURL url = m_document->url ();
+ if (!url.isEmpty ())
+ {
+ int dot;
+
+ QString fileName = url.fileName ();
+ dot = fileName.findRev ('.');
+
+ // file.ext but not .hidden-file?
+ if (dot > 0)
+ fileName.truncate (dot);
+
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::sendFilenameToPrinter() fileName="
+ << fileName
+ << " dir="
+ << url.directory ()
+ << endl;
+ #endif
+ printer->setDocName (fileName);
+ printer->setDocFileName (fileName);
+ printer->setDocDirectory (url.directory ());
+ }
+}
+
+
+static const double InchesPerMeter = 100 / 2.54;
+
+
+// TODO: GUI should allow viewing & changing of DPI.
+
+
+static bool shouldPrintImageCenteredOnPage ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpmainwindow_file.cpp:shouldPrintImageCenteredOnPage()" << endl;
+#endif
+ bool ret;
+
+ KConfigGroupSaver cfgGroupSaver (KGlobal::config (),
+ kpSettingsGroupGeneral);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ if (cfg->hasKey (kpSettingPrintImageCenteredOnPage))
+ {
+ ret = cfg->readBoolEntry (kpSettingPrintImageCenteredOnPage);
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tread: " << ret << endl;
+ #endif
+ }
+ else
+ {
+ ret = true;
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tfirst time - writing default: " << ret << endl;
+#endif
+ cfg->writeEntry (kpSettingPrintImageCenteredOnPage, ret);
+ cfg->sync ();
+ }
+
+ return ret;
+}
+
+
+// private
+void kpMainWindow::sendPixmapToPrinter (KPrinter *printer,
+ bool showPrinterSetupDialog)
+{
+ // Get image to be printed.
+ QPixmap pixmap = m_document->pixmapWithSelection ();
+
+
+ // Get image DPI.
+ double pixmapDotsPerMeterX =
+ double (m_document->metaInfo ()->dotsPerMeterX ());
+ double pixmapDotsPerMeterY =
+ double (m_document->metaInfo ()->dotsPerMeterY ());
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::sendPixmapToPrinter() pixmap:"
+ << " width=" << pixmap.width ()
+ << " height=" << pixmap.height ()
+ << " dotsPerMeterX=" << pixmapDotsPerMeterX
+ << " dotsPerMeterY=" << pixmapDotsPerMeterY
+ << endl;
+#endif
+
+ // Image DPI invalid (e.g. new image, could not read from file
+ // or Qt3 doesn't implement DPI for JPEG)?
+ if (pixmapDotsPerMeterX < 1 || pixmapDotsPerMeterY < 1)
+ {
+ // Even if just one DPI dimension is invalid, mutate both DPI
+ // dimensions as we have no information about the intended
+ // aspect ratio anyway (and other dimension likely to be invalid).
+
+ // When rendering text onto a document, the fonts are rasterised
+ // according to the screen's DPI.
+ // TODO: I think we should use the image's DPI. Technically
+ // possible?
+ //
+ // So no matter what computer you draw text on, you get
+ // the same pixels.
+ //
+ // So we must print at the screen's DPI to get the right text size.
+ //
+ // Unfortunately, this means that moving to a different screen DPI
+ // affects printing. If you edited the image at a different screen
+ // DPI than when you print, you get incorrect results. Furthermore,
+ // this is bogus if you don't have text in your image. Worse still,
+ // what if you have multiple screens connected to the same computer
+ // with different DPIs?
+ // TODO: mysteriously, someone else is setting this to 96dpi always.
+ QPaintDeviceMetrics screenMetrics (&pixmap/*screen element*/);
+ const int dpiX = screenMetrics.logicalDpiX (),
+ dpiY = screenMetrics.logicalDpiY ();
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tusing screen dpi: x=" << dpiX << " y=" << dpiY << endl;
+ #endif
+
+ pixmapDotsPerMeterX = dpiX * InchesPerMeter;
+ pixmapDotsPerMeterY = dpiY * InchesPerMeter;
+ }
+
+
+ // Get page size (excluding margins).
+ // Coordinate (0,0) is the X here:
+ // mmmmm
+ // mX m
+ // m m m = margin
+ // m m
+ // mmmmm
+ QPaintDeviceMetrics printerMetrics (printer);
+ const int printerWidthMM = printerMetrics.widthMM ();
+ const int printerHeightMM = printerMetrics.heightMM ();
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tprinter: widthMM=" << printerWidthMM
+ << " heightMM=" << printerHeightMM
+ << endl;
+#endif
+
+
+ double dpiX = pixmapDotsPerMeterX / InchesPerMeter;
+ double dpiY = pixmapDotsPerMeterY / InchesPerMeter;
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tpixmap: dpiX=" << dpiX << " dpiY=" << dpiY << endl;
+#endif
+
+
+ //
+ // If image doesn't fit on page at intended DPI, change the DPI.
+ //
+
+ const double scaleDpiX = (pixmap.width () / (printerWidthMM / 25.4))
+ / dpiX;
+ const double scaleDpiY = (pixmap.height () / (printerHeightMM / 25.4))
+ / dpiY;
+ const double scaleDpi = QMAX (scaleDpiX, scaleDpiY);
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t\tscaleDpi: x=" << scaleDpiX << " y=" << scaleDpiY
+ << " --> scale at " << scaleDpi << " to fit?"
+ << endl;
+#endif
+
+ // Need to increase resolution to fit page?
+ if (scaleDpi > 1.0)
+ {
+ dpiX *= scaleDpi;
+ dpiY *= scaleDpi;
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t\t\tto fit page, scaled to:"
+ << " dpiX=" << dpiX << " dpiY=" << dpiY << endl;
+ #endif
+ }
+
+
+ // Make sure DPIs are equal as that's all QPrinter::setResolution()
+ // supports. We do this in such a way that we only ever stretch an
+ // image, to avoid losing information. Don't antialias as the printer
+ // will do that to translate our DPI to its physical resolution and
+ // double-antialiasing looks bad.
+ if (dpiX > dpiY)
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tdpiX > dpiY; stretching pixmap height to equalise DPIs to dpiX="
+ << dpiX << endl;
+ #endif
+ kpPixmapFX::scale (&pixmap,
+ pixmap.width (),
+ QMAX (1, qRound (pixmap.height () * dpiX / dpiY)),
+ false/*don't antialias*/);
+
+ dpiY = dpiX;
+ }
+ else if (dpiY > dpiX)
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tdpiY > dpiX; stretching pixmap width to equalise DPIs to dpiY="
+ << dpiY << endl;
+ #endif
+ kpPixmapFX::scale (&pixmap,
+ QMAX (1, qRound (pixmap.width () * dpiY / dpiX)),
+ pixmap.height (),
+ false/*don't antialias*/);
+
+ dpiX = dpiY;
+ }
+
+
+ // ASSERT: dpiX == dpiY
+ // QPrinter::setResolution() has to be called before QPrinter::setup().
+ printer->setResolution (QMAX (1, qRound (dpiX)));
+
+
+ double originX = 0, originY = 0;
+
+ // Centre image on page?
+ if (shouldPrintImageCenteredOnPage ())
+ {
+ originX = (printerWidthMM * dpiX / 25.4 - pixmap.width ()) / 2;
+ originY = (printerHeightMM * dpiY / 25.4 - pixmap.height ()) / 2;
+ }
+
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\torigin: x=" << originX << " y=" << originY << endl;
+#endif
+
+
+ sendFilenameToPrinter (printer);
+
+ if (showPrinterSetupDialog)
+ {
+ // The user can mutate margins at their own risk in this dialog.
+ // It doesn't seem to affect the size of the page as reported
+ // by QPaintDeviceMetrics::{width,height}MM().
+ if (!printer->setup (this))
+ return;
+ }
+
+
+ // Send pixmap to printer.
+ QPainter painter;
+ painter.begin (printer);
+ painter.drawPixmap (qRound (originX), qRound (originY), pixmap);
+ painter.end ();
+}
+
+
+// private slot
+void kpMainWindow::slotPrint ()
+{
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ KPrinter printer;
+
+ sendPixmapToPrinter (&printer, true/*showPrinterSetupDialog*/);
+}
+
+// private slot
+void kpMainWindow::slotPrintPreview ()
+{
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ // TODO: get it to reflect default printer's settings
+ KPrinter printer (false/*separate settings from ordinary printer*/);
+
+ // TODO: pass "this" as parent
+ printer.setPreviewOnly (true);
+
+ sendPixmapToPrinter (&printer, false/*don't showPrinterSetupDialog*/);
+}
+
+
+// private slot
+void kpMainWindow::slotMail ()
+{
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ if (m_document->url ().isEmpty ()/*no name*/ ||
+ !m_document->isFromURL () ||
+ m_document->isModified ()/*needs to be saved*/)
+ {
+ int result = KMessageBox::questionYesNo (this,
+ i18n ("You must save this image before sending it.\n"
+ "Do you want to save it?"),
+ QString::null,
+ KStdGuiItem::save (), KStdGuiItem::cancel ());
+
+ if (result == KMessageBox::Yes)
+ {
+ if (!save ())
+ {
+ // save failed or aborted - don't email
+ return;
+ }
+ }
+ else
+ {
+ // don't want to save - don't email
+ return;
+ }
+ }
+
+ kapp->invokeMailer (
+ QString::null/*to*/,
+ QString::null/*cc*/,
+ QString::null/*bcc*/,
+ m_document->prettyFilename()/*subject*/,
+ QString::null/*body*/,
+ QString::null/*messageFile*/,
+ QStringList (m_document->url ().url ())/*attachments*/);
+}
+
+
+// private
+void kpMainWindow::setAsWallpaper (bool centered)
+{
+ if (m_document->url ().isEmpty ()/*no name*/ ||
+ !m_document->url ().isLocalFile ()/*remote file*/ ||
+ !m_document->isFromURL () ||
+ m_document->isModified ()/*needs to be saved*/)
+ {
+ QString question;
+
+ if (!m_document->url ().isLocalFile ())
+ {
+ question = i18n ("Before this image can be set as the wallpaper, "
+ "you must save it as a local file.\n"
+ "Do you want to save it?");
+ }
+ else
+ {
+ question = i18n ("Before this image can be set as the wallpaper, "
+ "you must save it.\n"
+ "Do you want to save it?");
+ }
+
+ int result = KMessageBox::questionYesNo (this,
+ question, QString::null,
+ KStdGuiItem::save (), KStdGuiItem::cancel ());
+
+ if (result == KMessageBox::Yes)
+ {
+ // save() is smart enough to pop up a filedialog if it's a
+ // remote file that should be saved locally
+ if (!save (true/*localOnly*/))
+ {
+ // save failed or aborted - don't set the wallpaper
+ return;
+ }
+ }
+ else
+ {
+ // don't want to save - don't set wallpaper
+ return;
+ }
+ }
+
+
+ QByteArray data;
+ QDataStream dataStream (data, IO_WriteOnly);
+
+ // write path
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::setAsWallpaper() path="
+ << m_document->url ().path () << endl;
+#endif
+ dataStream << QString (m_document->url ().path ());
+
+ // write position:
+ //
+ // SYNC: kdebase/kcontrol/background/bgsettings.h:
+ // 1 = Centered
+ // 2 = Tiled
+ // 6 = Scaled
+ // 9 = lastWallpaperMode
+ //
+ // Why restrict the user to Centered & Tiled?
+ // Why don't we let the user choose if it should be common to all desktops?
+ // Why don't we rewrite the Background control page?
+ //
+ // Answer: This is supposed to be a quick & convenient feature.
+ //
+ // If you want more options, go to kcontrol for that kind of
+ // flexiblity. We don't want to slow down average users, who see way too
+ // many dialogs already and probably haven't even heard of "Centered Maxpect"...
+ //
+ dataStream << int (centered ? 1 : 2);
+
+
+ // I'm going to all this trouble because the user might not have kdebase
+ // installed so kdebase/kdesktop/KBackgroundIface.h might not be around
+ // to be compiled in (where user == developer :))
+ if (!KApplication::dcopClient ()->send ("kdesktop", "KBackgroundIface",
+ "setWallpaper(QString,int)", data))
+ {
+ KMessageBox::sorry (this, i18n ("Could not change wallpaper."));
+ }
+}
+
+// private slot
+void kpMainWindow::slotSetAsWallpaperCentered ()
+{
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ setAsWallpaper (true/*centered*/);
+}
+
+// private slot
+void kpMainWindow::slotSetAsWallpaperTiled ()
+{
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ setAsWallpaper (false/*tiled*/);
+}
+
+
+// private slot
+void kpMainWindow::slotClose ()
+{
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotClose()" << endl;
+#endif
+
+ if (!queryClose ())
+ return;
+
+ setDocument (0);
+}
+
+// private slot
+void kpMainWindow::slotQuit ()
+{
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotQuit()" << endl;
+#endif
+
+ close (); // will call queryClose()
+}
+
diff --git a/kolourpaint/kpmainwindow_help.cpp b/kolourpaint/kpmainwindow_help.cpp
new file mode 100644
index 00000000..fb1fc790
--- /dev/null
+++ b/kolourpaint/kpmainwindow_help.cpp
@@ -0,0 +1,219 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <kpmainwindow.h>
+#include <kpmainwindow_p.h>
+
+#include <dcopclient.h>
+#include <kaction.h>
+#include <kactivelabel.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kdialogbase.h>
+#include <krun.h>
+#include <klocale.h>
+#include <kshortcut.h>
+
+#include <kptool.h>
+
+
+// private
+void kpMainWindow::setupHelpMenuActions ()
+{
+ KActionCollection *ac = actionCollection ();
+
+
+ // Explanation for action name:
+ // "Taking" is like a digital camera when you record the image and is
+ // analogous to pressing PrintScreen. However, "Acquiring" is when
+ // the image is brought into KolourPaint, just as you would acquire
+ // from a digital camera in future versions of KolourPaint. Hence
+ // "Acquiring" is more appropriate.
+ // -- Thurston
+ d->m_actionHelpTakingScreenshots = new KAction (
+ i18n ("Acquiring &Screenshots"), 0,
+ this, SLOT (slotHelpTakingScreenshots ()),
+ ac, "help_taking_screenshots");
+
+
+ enableHelpMenuDocumentActions (false);
+}
+
+// private
+void kpMainWindow::enableHelpMenuDocumentActions (bool /*enable*/)
+{
+}
+
+
+// SYNC: kdebase/kwin/kwinbindings.cpp
+static QString printScreenShortcutString ()
+{
+ KConfigGroupSaver cfgGroupSaver (KGlobal::config (), "Global Shortcuts");
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ // TODO: i18n() entry name? kwinbindings.cpp seems to but it doesn't
+ // make sense.
+ const QString cfgEntryString = cfg->readEntry ("Desktop Screenshot");
+
+
+ // (only use 1st key sequence, if it exists)
+ const QString humanReadableShortcut =
+ KShortcut (cfgEntryString).seq (0).toString ();
+
+ if (!humanReadableShortcut.isEmpty ())
+ {
+ return humanReadableShortcut;
+ }
+ else
+ {
+ // (localised)
+ return KKey (Qt::CTRL + Qt::Key_Print).toString ();
+ }
+}
+
+
+// private slot
+void kpMainWindow::slotHelpTakingScreenshots ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotHelpTakingScreenshots()" << endl;
+#endif
+
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+
+ // TODO: Totally bogus logic if kwin not running under same user as KolourPaint.
+ // SYNC: KWin contains PrintScreen key logic
+ QCStringList dcopApps = KApplication::dcopClient ()->registeredApplications ();
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tdcopApps=" << dcopApps << endl;
+#endif
+ bool isRunningKDE = (dcopApps.findIndex ("kwin") >= 0);
+
+#if 0
+{
+ int i = 0;
+ FILE *fp = fopen ("/home/kdevel/kolourpaint.tmp", "rt");
+ if (fp && fscanf (fp, "Hello: %d", &i) == 1)
+ isRunningKDE = i, fclose (fp);
+}
+#endif
+
+ QString message;
+ if (isRunningKDE)
+ {
+ message = i18n
+ (
+ "<p>"
+ "To acquire a screenshot, press <b>%1</b>."
+ " The screenshot will be placed into the clipboard"
+ " and you will be able to paste it in KolourPaint."
+ "</p>"
+
+ "<p>"
+ "You may configure the <b>Desktop Screenshot</b> shortcut"
+ " in the KDE Control Center"
+ " module <a href=\"configure kde shortcuts\">Keyboard Shortcuts</a>."
+ "</p>"
+
+ "<p>Alternatively, you may try the application"
+ " <a href=\"run ksnapshot\">KSnapshot</a>."
+ "</p>"
+ );
+ }
+ else
+ {
+ message = i18n
+ (
+ "<p>"
+ "You do not appear to be running KDE."
+ "</p>"
+
+ // We tell them this much even though they aren't running KDE
+ // to entice them to use KDE since it's so easy.
+ "<p>"
+ "Once you have loaded KDE:<br>"
+ "<blockquote>"
+ "To acquire a screenshot, press <b>%1</b>."
+ " The screenshot will be placed into the clipboard"
+ " and you will be able to paste it in KolourPaint."
+ "</blockquote>"
+ "</p>"
+
+ "<p>Alternatively, you may try the application"
+ " <a href=\"run ksnapshot\">KSnapshot</a>."
+ "</p>"
+ );
+ }
+
+ // TODO: Totally bogus logic if kwin not running under same user as KolourPaint.
+ message = message.arg (::printScreenShortcutString ());
+
+ // Add extra vertical space
+ message += "<p>&nbsp;</p>";
+
+
+ KDialogBase dlg (this, "helpTakingScreenshotsDialog", true/*modal*/,
+ i18n ("Acquiring Screenshots"),
+ KDialogBase::Close, KDialogBase::Close/*default btn*/,
+ true/*separator line*/);
+
+ KActiveLabel *messageLabel = new KActiveLabel (message, &dlg);
+ disconnect (messageLabel, SIGNAL (linkClicked (const QString &)),
+ messageLabel, SLOT (openLink (const QString &)));
+ connect (messageLabel, SIGNAL (linkClicked (const QString &)),
+ this, SLOT (slotHelpTakingScreenshotsFollowLink (const QString &)));
+
+ dlg.setMainWidget (messageLabel);
+
+ dlg.exec ();
+}
+
+// private
+void kpMainWindow::slotHelpTakingScreenshotsFollowLink (const QString &link)
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotHelpTakingScreenshotsFollowLink("
+ << link << ")" << endl;
+#endif
+
+ if (link == "configure kde shortcuts")
+ {
+ KRun::runCommand ("kcmshell keys");
+ }
+ else if (link == "run ksnapshot")
+ {
+ KRun::runCommand ("ksnapshot");
+ }
+ else
+ {
+ kdError () << "kpMainWindow::slotHelpTakingScreenshotsFollowLink("
+ << link << ")" << endl;
+ }
+}
diff --git a/kolourpaint/kpmainwindow_image.cpp b/kolourpaint/kpmainwindow_image.cpp
new file mode 100644
index 00000000..7f662af7
--- /dev/null
+++ b/kolourpaint/kpmainwindow_image.cpp
@@ -0,0 +1,474 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <kpmainwindow.h>
+#include <kpmainwindow_p.h>
+
+#include <qcolor.h>
+#include <qsize.h>
+
+#include <kaction.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmenubar.h>
+
+#include <kpcolor.h>
+#include <kpdefs.h>
+#include <kpcoloreffect.h>
+#include <kpcolortoolbar.h>
+#include <kpcommandhistory.h>
+#include <kpdocument.h>
+#include <kpeffectinvert.h>
+#include <kpeffectreducecolors.h>
+#include <kpeffectsdialog.h>
+#include <kpselection.h>
+#include <kptool.h>
+#include <kptoolautocrop.h>
+#include <kptoolclear.h>
+#include <kptoolconverttograyscale.h>
+#include <kptoolcrop.h>
+#include <kptoolflip.h>
+#include <kptoolresizescale.h>
+#include <kptoolrotate.h>
+#include <kptoolselection.h>
+#include <kptoolskew.h>
+#include <kpviewmanager.h>
+
+
+// private
+bool kpMainWindow::isSelectionActive () const
+{
+ return (m_document ? bool (m_document->selection ()) : false);
+}
+
+// private
+bool kpMainWindow::isTextSelection () const
+{
+ return (m_document && m_document->selection () &&
+ m_document->selection ()->isText ());
+}
+
+
+// private
+QString kpMainWindow::autoCropText () const
+{
+ return kpToolAutoCropCommand::name (isSelectionActive (),
+ kpToolAutoCropCommand::ShowAccel);
+}
+
+
+// private
+void kpMainWindow::setupImageMenuActions ()
+{
+ KActionCollection *ac = actionCollection ();
+
+ m_actionResizeScale = new KAction (i18n ("R&esize / Scale..."), Qt::CTRL + Qt::Key_E,
+ this, SLOT (slotResizeScale ()), ac, "image_resize_scale");
+
+ m_actionCrop = new KAction (i18n ("Se&t as Image (Crop)"), Qt::CTRL + Qt::Key_T,
+ this, SLOT (slotCrop ()), ac, "image_crop");
+
+ m_actionAutoCrop = new KAction (autoCropText (), Qt::CTRL + Qt::Key_U,
+ this, SLOT (slotAutoCrop ()), ac, "image_auto_crop");
+
+ m_actionFlip = new KAction (i18n ("&Flip..."), Qt::CTRL + Qt::Key_F,
+ this, SLOT (slotFlip ()), ac, "image_flip");
+
+ m_actionRotate = new KAction (i18n ("&Rotate..."), Qt::CTRL + Qt::Key_R,
+ this, SLOT (slotRotate ()), ac, "image_rotate");
+
+ m_actionSkew = new KAction (i18n ("S&kew..."), Qt::CTRL + Qt::Key_K,
+ this, SLOT (slotSkew ()), ac, "image_skew");
+
+ m_actionConvertToBlackAndWhite = new KAction (i18n ("Reduce to Mo&nochrome (Dithered)"), 0,
+ this, SLOT (slotConvertToBlackAndWhite ()), ac, "image_convert_to_black_and_white");
+
+ m_actionConvertToGrayscale = new KAction (i18n ("Reduce to &Grayscale"), 0,
+ this, SLOT (slotConvertToGrayscale ()), ac, "image_convert_to_grayscale");
+
+ m_actionInvertColors = new KAction (i18n ("&Invert Colors"), Qt::CTRL + Qt::Key_I,
+ this, SLOT (slotInvertColors ()), ac, "image_invert_colors");
+
+ m_actionClear = new KAction (i18n ("C&lear"), Qt::CTRL + Qt::SHIFT + Qt::Key_N,
+ this, SLOT (slotClear ()), ac, "image_clear");
+
+ m_actionMoreEffects = new KAction (i18n ("&More Effects..."), Qt::CTRL + Qt::Key_M,
+ this, SLOT (slotMoreEffects ()), ac, "image_more_effects");
+
+ enableImageMenuDocumentActions (false);
+}
+
+// private
+void kpMainWindow::enableImageMenuDocumentActions (bool enable)
+{
+ m_actionResizeScale->setEnabled (enable);
+ m_actionCrop->setEnabled (enable);
+ m_actionAutoCrop->setEnabled (enable);
+ m_actionFlip->setEnabled (enable);
+ m_actionRotate->setEnabled (enable);
+ m_actionSkew->setEnabled (enable);
+ m_actionConvertToBlackAndWhite->setEnabled (enable);
+ m_actionConvertToGrayscale->setEnabled (enable);
+ m_actionInvertColors->setEnabled (enable);
+ m_actionClear->setEnabled (enable);
+ m_actionMoreEffects->setEnabled (enable);
+
+ m_imageMenuDocumentActionsEnabled = enable;
+}
+
+
+// private slot
+void kpMainWindow::slotImageMenuUpdateDueToSelection ()
+{
+ KMenuBar *mBar = menuBar ();
+ if (!mBar) // just in case
+ return;
+
+ int mBarNumItems = (int) mBar->count ();
+ for (int index = 0; index < mBarNumItems; index++)
+ {
+ int id = mBar->idAt (index);
+
+ // SYNC: kolourpaintui.rc
+ QString menuBarItemTextImage = i18n ("&Image");
+ QString menuBarItemTextSelection = i18n ("Select&ion");
+
+ const QString menuBarItemText = mBar->text (id);
+ if (menuBarItemText == menuBarItemTextImage ||
+ menuBarItemText == menuBarItemTextSelection)
+ {
+ if (isSelectionActive ())
+ mBar->changeItem (id, menuBarItemTextSelection);
+ else
+ mBar->changeItem (id, menuBarItemTextImage);
+
+ break;
+ }
+ }
+
+
+ m_actionResizeScale->setEnabled (m_imageMenuDocumentActionsEnabled);
+ m_actionCrop->setEnabled (m_imageMenuDocumentActionsEnabled &&
+ isSelectionActive ());
+
+ const bool enable = (m_imageMenuDocumentActionsEnabled && !isTextSelection ());
+ m_actionAutoCrop->setText (autoCropText ());
+ m_actionAutoCrop->setEnabled (enable);
+ m_actionFlip->setEnabled (enable);
+ m_actionRotate->setEnabled (enable);
+ m_actionSkew->setEnabled (enable);
+ m_actionConvertToBlackAndWhite->setEnabled (enable);
+ m_actionConvertToGrayscale->setEnabled (enable);
+ m_actionInvertColors->setEnabled (enable);
+ m_actionClear->setEnabled (enable);
+ m_actionMoreEffects->setEnabled (enable);
+}
+
+
+// public
+kpColor kpMainWindow::backgroundColor (bool ofSelection) const
+{
+ if (ofSelection)
+ return kpColor::transparent;
+ else
+ {
+ if (m_colorToolBar)
+ return m_colorToolBar->backgroundColor ();
+ else
+ {
+ kdError () << "kpMainWindow::backgroundColor() without colorToolBar" << endl;
+ return kpColor::invalid;
+ }
+ }
+}
+
+
+// public
+void kpMainWindow::addImageOrSelectionCommand (kpCommand *cmd,
+ bool addSelCreateCmdIfSelAvail,
+ bool addSelPullCmdIfSelAvail)
+{
+#if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "kpMainWindow::addImageOrSelectionCommand()"
+ << " addSelCreateCmdIfSelAvail=" << addSelCreateCmdIfSelAvail
+ << " addSelPullCmdIfSelAvail=" << addSelPullCmdIfSelAvail
+ << endl;
+#endif
+
+ if (!m_document)
+ {
+ kdError () << "kpMainWindow::addImageOrSelectionCommand() without doc" << endl;
+ return;
+ }
+
+
+ if (m_viewManager)
+ m_viewManager->setQueueUpdates ();
+
+
+ kpSelection *sel = m_document->selection ();
+#if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "\tsel=" << sel
+ << " sel->pixmap=" << (sel ? sel->pixmap () : 0)
+ << endl;
+#endif
+ if (addSelCreateCmdIfSelAvail && sel && !sel->pixmap ())
+ {
+ // create selection region
+ kpCommand *createCommand = new kpToolSelectionCreateCommand (
+ i18n ("Selection: Create"),
+ *sel,
+ this);
+
+ if (kpToolSelectionCreateCommand::nextUndoCommandIsCreateBorder (commandHistory ()))
+ commandHistory ()->setNextUndoCommand (createCommand);
+ else
+ commandHistory ()->addCommand (createCommand,
+ false/*no exec - user already dragged out sel*/);
+ }
+
+
+ if (addSelPullCmdIfSelAvail && sel && !sel->pixmap ())
+ {
+ kpMacroCommand *macroCmd = new kpMacroCommand (cmd->name (), this);
+
+ macroCmd->addCommand (new kpToolSelectionPullFromDocumentCommand (
+ QString::null/*uninteresting child of macro cmd*/,
+ this));
+
+ macroCmd->addCommand (cmd);
+
+ m_commandHistory->addCommand (macroCmd);
+ }
+ else
+ {
+ m_commandHistory->addCommand (cmd);
+ }
+
+
+ if (m_viewManager)
+ m_viewManager->restoreQueueUpdates ();
+}
+
+// private slot
+void kpMainWindow::slotResizeScale ()
+{
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ kpToolResizeScaleDialog dialog (this);
+ dialog.setKeepAspectRatio (d->m_resizeScaleDialogLastKeepAspect);
+
+ if (dialog.exec () && !dialog.isNoOp ())
+ {
+ kpToolResizeScaleCommand *cmd = new kpToolResizeScaleCommand (
+ dialog.actOnSelection (),
+ dialog.imageWidth (), dialog.imageHeight (),
+ dialog.type (),
+ this);
+
+ bool addSelCreateCommand = (dialog.actOnSelection () ||
+ cmd->scaleSelectionWithImage ());
+ bool addSelPullCommand = dialog.actOnSelection ();
+
+ addImageOrSelectionCommand (
+ cmd,
+ addSelCreateCommand,
+ addSelPullCommand);
+
+ // Resized document?
+ if (!dialog.actOnSelection () &&
+ dialog.type () == kpToolResizeScaleCommand::Resize)
+ {
+ // TODO: this should be the responsibility of kpDocument
+ saveDefaultDocSize (QSize (dialog.imageWidth (), dialog.imageHeight ()));
+ }
+ }
+
+
+ if (d->m_resizeScaleDialogLastKeepAspect != dialog.keepAspectRatio ())
+ {
+ d->m_resizeScaleDialogLastKeepAspect = dialog.keepAspectRatio ();
+
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupGeneral);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ cfg->writeEntry (kpSettingResizeScaleLastKeepAspect,
+ d->m_resizeScaleDialogLastKeepAspect);
+ cfg->sync ();
+ }
+}
+
+// public slot
+void kpMainWindow::slotCrop ()
+{
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ if (!m_document || !m_document->selection ())
+ {
+ kdError () << "kpMainWindow::slotCrop() doc=" << m_document
+ << " sel=" << (m_document ? m_document->selection () : 0)
+ << endl;
+ return;
+ }
+
+
+ ::kpToolCrop (this);
+}
+
+// private slot
+void kpMainWindow::slotAutoCrop ()
+{
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ ::kpToolAutoCrop (this);
+}
+
+// private slot
+void kpMainWindow::slotFlip ()
+{
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ kpToolFlipDialog dialog ((bool) m_document->selection (), this);
+
+ if (dialog.exec () && !dialog.isNoOp ())
+ {
+ addImageOrSelectionCommand (
+ new kpToolFlipCommand (m_document->selection (),
+ dialog.getHorizontalFlip (), dialog.getVerticalFlip (),
+ this));
+ }
+}
+
+// private slot
+void kpMainWindow::slotRotate ()
+{
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ kpToolRotateDialog dialog ((bool) m_document->selection (), this);
+
+ if (dialog.exec () && !dialog.isNoOp ())
+ {
+ addImageOrSelectionCommand (
+ new kpToolRotateCommand (m_document->selection (),
+ dialog.angle (),
+ this));
+ }
+}
+
+// private slot
+void kpMainWindow::slotSkew ()
+{
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ kpToolSkewDialog dialog ((bool) m_document->selection (), this);
+
+ if (dialog.exec () && !dialog.isNoOp ())
+ {
+ addImageOrSelectionCommand (
+ new kpToolSkewCommand (m_document->selection (),
+ dialog.horizontalAngle (), dialog.verticalAngle (),
+ this));
+ }
+}
+
+// private slot
+void kpMainWindow::slotConvertToBlackAndWhite ()
+{
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ addImageOrSelectionCommand (
+ new kpEffectReduceColorsCommand (1/*depth*/, true/*dither*/,
+ m_document->selection (), this));
+}
+
+// private slot
+void kpMainWindow::slotConvertToGrayscale ()
+{
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ addImageOrSelectionCommand (
+ new kpToolConvertToGrayscaleCommand (m_document->selection (), this));
+}
+
+// private slot
+void kpMainWindow::slotInvertColors ()
+{
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ addImageOrSelectionCommand (
+ new kpEffectInvertCommand (m_document->selection (), this));
+}
+
+// private slot
+void kpMainWindow::slotClear ()
+{
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ addImageOrSelectionCommand (
+ new kpToolClearCommand (m_document->selection (), this));
+}
+
+// private slot
+void kpMainWindow::slotMoreEffects ()
+{
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ kpEffectsDialog dialog ((bool) m_document->selection (), this);
+ dialog.selectEffect (d->m_moreEffectsDialogLastEffect);
+
+ if (dialog.exec () && !dialog.isNoOp ())
+ {
+ addImageOrSelectionCommand (dialog.createCommand ());
+ }
+
+
+ if (d->m_moreEffectsDialogLastEffect != dialog.selectedEffect ())
+ {
+ d->m_moreEffectsDialogLastEffect = dialog.selectedEffect ();
+
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupGeneral);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ cfg->writeEntry (kpSettingMoreEffectsLastEffect,
+ d->m_moreEffectsDialogLastEffect);
+ cfg->sync ();
+ }
+}
diff --git a/kolourpaint/kpmainwindow_p.h b/kolourpaint/kpmainwindow_p.h
new file mode 100644
index 00000000..9ec94eaa
--- /dev/null
+++ b/kolourpaint/kpmainwindow_p.h
@@ -0,0 +1,49 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef KP_MAIN_WINDOW_P_H
+#define KP_MAIN_WINDOW_P_H
+
+
+class KAction;
+class KToggleAction;
+
+
+struct kpMainWindowPrivate
+{
+ bool m_configThumbnailShowRectangle;
+ KToggleAction *m_actionShowThumbnailRectangle;
+
+ KAction *m_actionHelpTakingScreenshots;
+
+ int m_moreEffectsDialogLastEffect;
+ bool m_resizeScaleDialogLastKeepAspect;
+};
+
+
+#endif // KP_MAIN_WINDOW_P_H
diff --git a/kolourpaint/kpmainwindow_settings.cpp b/kolourpaint/kpmainwindow_settings.cpp
new file mode 100644
index 00000000..609f7dfe
--- /dev/null
+++ b/kolourpaint/kpmainwindow_settings.cpp
@@ -0,0 +1,209 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <kpmainwindow.h>
+
+#include <kactionclasses.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kedittoolbar.h>
+#include <kkeydialog.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kstdaction.h>
+
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kptool.h>
+#include <kptooltoolbar.h>
+
+
+// private
+void kpMainWindow::setupSettingsMenuActions ()
+{
+ KActionCollection *ac = actionCollection ();
+
+
+ // Settings/Toolbars |> %s
+ setStandardToolBarMenuEnabled (true);
+
+ // Settings/Show Statusbar
+ createStandardStatusBarAction ();
+
+
+ m_actionFullScreen = KStdAction::fullScreen (this, SLOT (slotFullScreen ()), ac,
+ this/*window*/);
+
+
+ m_actionShowPath = new KToggleAction (i18n ("Show &Path"), 0,
+ this, SLOT (slotShowPathToggled ()), ac, "settings_show_path");
+ m_actionShowPath->setCheckedState (i18n ("Hide &Path"));
+ slotEnableSettingsShowPath ();
+
+
+ m_actionKeyBindings = KStdAction::keyBindings (this, SLOT (slotKeyBindings ()), ac);
+ m_actionConfigureToolbars = KStdAction::configureToolbars (this, SLOT (slotConfigureToolBars ()), ac);
+ // m_actionConfigure = KStdAction::preferences (this, SLOT (slotConfigure ()), ac);
+
+
+ enableSettingsMenuDocumentActions (false);
+}
+
+// private
+void kpMainWindow::enableSettingsMenuDocumentActions (bool /*enable*/)
+{
+}
+
+
+// private slot
+void kpMainWindow::slotFullScreen ()
+{
+ if (m_actionFullScreen->isChecked ())
+ showFullScreen ();
+ else
+ showNormal ();
+}
+
+
+// private slot
+void kpMainWindow::slotEnableSettingsShowPath ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotEnableSettingsShowPath()" << endl;
+#endif
+
+ const bool enable = (m_document && !m_document->url ().isEmpty ());
+
+ m_actionShowPath->setEnabled (enable);
+ m_actionShowPath->setChecked (enable && m_configShowPath);
+}
+
+// private slot
+void kpMainWindow::slotShowPathToggled ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotShowPathToggled()" << endl;
+#endif
+
+ m_configShowPath = m_actionShowPath->isChecked ();
+
+ slotUpdateCaption ();
+
+
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupGeneral);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ cfg->writeEntry (kpSettingShowPath, m_configShowPath);
+ cfg->sync ();
+}
+
+
+// private slot
+void kpMainWindow::slotKeyBindings ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotKeyBindings()" << endl;
+#endif
+
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+
+ bool singleKeyTriggersDisabled = !actionsSingleKeyTriggersEnabled ();
+
+ if (singleKeyTriggersDisabled)
+ enableActionsSingleKeyTriggers (true);
+
+
+ if (KKeyDialog::configure (actionCollection (), this))
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tdialog accepted" << endl;
+ #endif
+ // TODO: PROPAGATE: thru mainWindow's and interprocess
+
+ if (singleKeyTriggersDisabled)
+ enableActionsSingleKeyTriggers (false);
+ }
+}
+
+
+// private slot
+void kpMainWindow::slotConfigureToolBars ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotConfigureToolBars()" << endl;
+#endif
+
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+
+ //saveMainWindowSettings (kapp->config (), autoSaveGroup ());
+
+ KEditToolbar dialog (actionCollection (),
+ QString::null/*default ui.rc file*/,
+ true/*global resource*/,
+ this/*parent*/);
+ // Clicking on OK after Apply brings up the dialog (below) again.
+ // Bug with KEditToolBar.
+ dialog.showButtonApply (false);
+ connect (&dialog, SIGNAL (newToolbarConfig ()),
+ this, SLOT (slotNewToolBarConfig ()));
+
+ dialog.exec ();
+}
+
+// private slot
+void kpMainWindow::slotNewToolBarConfig ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotNewToolBarConfig()" << endl;
+#endif
+
+ // Wouldn't it be nice if createGUI () didn't nuke all the KToolBar's?
+ // (including my non-XMLGUI ones whose states take a _lot_ of effort to
+ // restore).
+ // TODO: this message is probably unacceptable - so restore the state of
+ // my toolbars instead.
+ KMessageBox::information (this,
+ i18n ("You have to restart KolourPaint for these changes to take effect."),
+ i18n ("Toolbar Settings Changed"),
+ QString::fromLatin1 ("ToolBarSettingsChanged"));
+
+ //createGUI();
+ //applyMainWindowSettings (kapp->config (), autoSaveGroup ());
+}
+
+
+// private slot
+void kpMainWindow::slotConfigure ()
+{
+ // TODO
+}
diff --git a/kolourpaint/kpmainwindow_statusbar.cpp b/kolourpaint/kpmainwindow_statusbar.cpp
new file mode 100644
index 00000000..ed854604
--- /dev/null
+++ b/kolourpaint/kpmainwindow_statusbar.cpp
@@ -0,0 +1,417 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_STATUS_BAR (DEBUG_KP_MAIN_WINDOW && 0)
+
+
+#include <kpmainwindow.h>
+
+#include <qlabel.h>
+#include <qstring.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kstatusbar.h>
+
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpsqueezedtextlabel.h>
+#include <kptool.h>
+#include <kpviewmanager.h>
+#include <kpviewscrollablecontainer.h>
+#include <kpzoomedview.h>
+
+
+// private
+void kpMainWindow::addPermanentStatusBarItem (int id, int maxTextLen)
+{
+ KStatusBar *sb = statusBar ();
+
+ QString textWithMaxLen;
+ textWithMaxLen.fill (QString::number (8/*big fat*/).at (0),
+ maxTextLen); //+ 2/*spaces on either side*/);
+
+ sb->insertFixedItem (textWithMaxLen, id, true/*permanent, place on the right*/);
+ sb->changeItem (QString::null, id);
+}
+
+// private
+void kpMainWindow::createStatusBar ()
+{
+ KStatusBar *sb = statusBar ();
+
+ // 9999 pixels "ought to be enough for anybody"
+ const int maxDimenLength = 4;
+
+ //sb->insertItem (QString::null, StatusBarItemMessage, 1/*stretch*/);
+ //sb->setItemAlignment (StatusBarItemMessage, Qt::AlignLeft | Qt::AlignVCenter);
+
+ m_statusBarMessageLabel = new kpSqueezedTextLabel (sb);
+ //m_statusBarMessageLabel->setShowEllipsis (false);
+ sb->addWidget (m_statusBarMessageLabel, 1/*stretch*/);
+
+ addPermanentStatusBarItem (StatusBarItemShapePoints,
+ (maxDimenLength + 1/*,*/ + maxDimenLength) * 2 + 3/* - */);
+ addPermanentStatusBarItem (StatusBarItemShapeSize,
+ (1/*+/-*/ + maxDimenLength) * 2 + 1/*x*/);
+
+ addPermanentStatusBarItem (StatusBarItemDocSize,
+ maxDimenLength + 1/*x*/ + maxDimenLength);
+ addPermanentStatusBarItem (StatusBarItemDocDepth,
+ 5/*XXbpp*/);
+
+ addPermanentStatusBarItem (StatusBarItemZoom,
+ 5/*1600%*/);
+
+ m_statusBarShapeLastPointsInitialised = false;
+ m_statusBarShapeLastSizeInitialised = false;
+ m_statusBarCreated = true;
+}
+
+
+
+// private slot
+void kpMainWindow::setStatusBarMessage (const QString &message)
+{
+#if DEBUG_STATUS_BAR && 1
+ kdDebug () << "kpMainWindow::setStatusBarMessage("
+ << message
+ << ") ok=" << m_statusBarCreated
+ << endl;
+#endif
+
+ if (!m_statusBarCreated)
+ return;
+
+ //statusBar ()->changeItem (message, StatusBarItemMessage);
+ m_statusBarMessageLabel->setText (message);
+}
+
+// private slot
+void kpMainWindow::setStatusBarShapePoints (const QPoint &startPoint,
+ const QPoint &endPoint)
+{
+#if DEBUG_STATUS_BAR && 0
+ kdDebug () << "kpMainWindow::setStatusBarShapePoints("
+ << startPoint << "," << endPoint
+ << ") ok=" << m_statusBarCreated
+ << endl;
+#endif
+
+ if (!m_statusBarCreated)
+ return;
+
+ if (m_statusBarShapeLastPointsInitialised &&
+ startPoint == m_statusBarShapeLastStartPoint &&
+ endPoint == m_statusBarShapeLastEndPoint)
+ {
+ #if DEBUG_STATUS_BAR && 0
+ kdDebug () << "\tNOP" << endl;
+ #endif
+ return;
+ }
+
+ if (startPoint == KP_INVALID_POINT)
+ {
+ statusBar ()->changeItem (QString::null, StatusBarItemShapePoints);
+ }
+ else if (endPoint == KP_INVALID_POINT)
+ {
+ statusBar ()->changeItem (i18n ("%1,%2")
+ .arg (startPoint.x ())
+ .arg (startPoint.y ()),
+ StatusBarItemShapePoints);
+ }
+ else
+ {
+ statusBar ()->changeItem (i18n ("%1,%2 - %3,%4")
+ .arg (startPoint.x ())
+ .arg (startPoint.y ())
+ .arg (endPoint.x ())
+ .arg (endPoint.y ()),
+ StatusBarItemShapePoints);
+ }
+
+ m_statusBarShapeLastStartPoint = startPoint;
+ m_statusBarShapeLastEndPoint = endPoint;
+ m_statusBarShapeLastPointsInitialised = true;
+}
+
+// private slot
+void kpMainWindow::setStatusBarShapeSize (const QSize &size)
+{
+#if DEBUG_STATUS_BAR && 0
+ kdDebug () << "kpMainWindow::setStatusBarShapeSize("
+ << size
+ << ") ok=" << m_statusBarCreated
+ << endl;
+#endif
+
+ if (!m_statusBarCreated)
+ return;
+
+ if (m_statusBarShapeLastSizeInitialised &&
+ size == m_statusBarShapeLastSize)
+ {
+ #if DEBUG_STATUS_BAR && 0
+ kdDebug () << "\tNOP" << endl;
+ #endif
+ return;
+ }
+
+ if (size == KP_INVALID_SIZE)
+ {
+ statusBar ()->changeItem (QString::null, StatusBarItemShapeSize);
+ }
+ else
+ {
+ statusBar ()->changeItem (i18n ("%1x%2")
+ .arg (size.width ())
+ .arg (size.height ()),
+ StatusBarItemShapeSize);
+ }
+
+ m_statusBarShapeLastSize = size;
+ m_statusBarShapeLastSizeInitialised = true;
+}
+
+// private slot
+void kpMainWindow::setStatusBarDocSize (const QSize &size)
+{
+#if DEBUG_STATUS_BAR && 0
+ kdDebug () << "kpMainWindow::setStatusBarDocSize("
+ << size
+ << ") ok=" << m_statusBarCreated
+ << endl;
+#endif
+
+ if (!m_statusBarCreated)
+ return;
+
+ if (size == KP_INVALID_SIZE)
+ {
+ statusBar ()->changeItem (QString::null, StatusBarItemDocSize);
+ }
+ else
+ {
+ statusBar ()->changeItem (i18n ("%1x%2")
+ .arg (size.width ())
+ .arg (size.height ()),
+ StatusBarItemDocSize);
+ }
+}
+
+// private slot
+void kpMainWindow::setStatusBarDocDepth (int depth)
+{
+#if DEBUG_STATUS_BAR && 0
+ kdDebug () << "kpMainWindow::setStatusBarDocDepth("
+ << depth
+ << ") ok=" << m_statusBarCreated
+ << endl;
+#endif
+
+ if (!m_statusBarCreated)
+ return;
+
+ if (depth <= 0)
+ {
+ statusBar ()->changeItem (QString::null, StatusBarItemDocDepth);
+ }
+ else
+ {
+ statusBar ()->changeItem (i18n ("%1bpp").arg (depth),
+ StatusBarItemDocDepth);
+ }
+}
+
+// private slot
+void kpMainWindow::setStatusBarZoom (int zoom)
+{
+#if DEBUG_STATUS_BAR && 0
+ kdDebug () << "kpMainWindow::setStatusBarZoom("
+ << zoom
+ << ") ok=" << m_statusBarCreated
+ << endl;
+#endif
+
+ if (!m_statusBarCreated)
+ return;
+
+ if (zoom <= 0)
+ {
+ statusBar ()->changeItem (QString::null, StatusBarItemZoom);
+ }
+ else
+ {
+ statusBar ()->changeItem (i18n ("%1%").arg (zoom),
+ StatusBarItemZoom);
+ }
+}
+
+void kpMainWindow::recalculateStatusBarMessage ()
+{
+#if DEBUG_STATUS_BAR && 1
+ kdDebug () << "kpMainWindow::recalculateStatusBarMessage()" << endl;
+#endif
+ QString scrollViewMessage = m_scrollView->statusMessage ();
+#if DEBUG_STATUS_BAR && 1
+ kdDebug () << "\tscrollViewMessage=" << scrollViewMessage << endl;
+ kdDebug () << "\tresizing doc? " << !m_scrollView->newDocSize ().isEmpty ()
+ << endl;
+ kdDebug () << "\tviewUnderCursor? "
+ << (m_viewManager && m_viewManager->viewUnderCursor ())
+ << endl;
+#endif
+
+ // HACK: To work around kpViewScrollableContainer's unreliable
+ // status messages (which in turn is due to Qt not updating
+ // QWidget::hasMouse() on drags and we needing to hack around it)
+ if (!scrollViewMessage.isEmpty () &&
+ m_scrollView->newDocSize ().isEmpty () &&
+ m_viewManager && m_viewManager->viewUnderCursor ())
+ {
+ #if DEBUG_STATUS_BAR && 1
+ kdDebug () << "\t\tnot resizing & viewUnderCursor - message is wrong - clearing"
+ << endl;
+ #endif
+ m_scrollView->blockSignals (true);
+ m_scrollView->clearStatusMessage ();
+ m_scrollView->blockSignals (false);
+
+ scrollViewMessage = QString::null;
+ #if DEBUG_STATUS_BAR && 1
+ kdDebug () << "\t\t\tdone" << endl;
+ #endif
+ }
+
+ if (!scrollViewMessage.isEmpty ())
+ {
+ setStatusBarMessage (scrollViewMessage);
+ }
+ else
+ {
+ const kpTool *t = tool ();
+ if (t)
+ {
+ setStatusBarMessage (t->userMessage ());
+ }
+ else
+ {
+ setStatusBarMessage ();
+ }
+ }
+}
+
+// private slot
+void kpMainWindow::recalculateStatusBarShape ()
+{
+#if DEBUG_STATUS_BAR && 0
+ kdDebug () << "kpMainWindow::recalculateStatusBarShape()" << endl;
+#endif
+
+ QSize docResizeTo = m_scrollView->newDocSize ();
+#if DEBUG_STATUS_BAR && 0
+ kdDebug () << "\tdocResizeTo=" << docResizeTo << endl;
+#endif
+ if (docResizeTo.isValid ())
+ {
+ const QPoint startPoint (m_document->width (), m_document->height ());
+ #if DEBUG_STATUS_BAR && 0
+ kdDebug () << "\thavedMovedFromOrgSize="
+ << m_scrollView->haveMovedFromOriginalDocSize () << endl;
+ #endif
+ if (!m_scrollView->haveMovedFromOriginalDocSize ())
+ {
+ setStatusBarShapePoints (startPoint);
+ setStatusBarShapeSize ();
+ }
+ else
+ {
+ const int newWidth = docResizeTo.width ();
+ const int newHeight = docResizeTo.height ();
+
+ setStatusBarShapePoints (startPoint, QPoint (newWidth, newHeight));
+ const QPoint sizeAsPoint (QPoint (newWidth, newHeight) - startPoint);
+ setStatusBarShapeSize (QSize (sizeAsPoint.x (), sizeAsPoint.y ()));
+ }
+ }
+ else
+ {
+ const kpTool *t = tool ();
+ #if DEBUG_STATUS_BAR && 0
+ kdDebug () << "\ttool=" << t << endl;
+ #endif
+ if (t)
+ {
+ setStatusBarShapePoints (t->userShapeStartPoint (),
+ t->userShapeEndPoint ());
+ setStatusBarShapeSize (t->userShapeSize ());
+ }
+ else
+ {
+ setStatusBarShapePoints ();
+ setStatusBarShapeSize ();
+ }
+ }
+}
+
+// private slot
+void kpMainWindow::recalculateStatusBar ()
+{
+#if DEBUG_STATUS_BAR && 1
+ kdDebug () << "kpMainWindow::recalculateStatusBar() ok="
+ << m_statusBarCreated
+ << endl;
+#endif
+
+ if (!m_statusBarCreated)
+ return;
+
+ recalculateStatusBarMessage ();
+ recalculateStatusBarShape ();
+
+ if (m_document)
+ {
+ setStatusBarDocSize (QSize (m_document->width (), m_document->height ()));
+ setStatusBarDocDepth (m_document->pixmap ()->depth ());
+ }
+ else
+ {
+ setStatusBarDocSize ();
+ setStatusBarDocDepth ();
+ }
+
+ if (m_mainView)
+ {
+ setStatusBarZoom (m_mainView->zoomLevelX ());
+ }
+ else
+ {
+ setStatusBarZoom ();
+ }
+}
diff --git a/kolourpaint/kpmainwindow_text.cpp b/kolourpaint/kpmainwindow_text.cpp
new file mode 100644
index 00000000..d5694dea
--- /dev/null
+++ b/kolourpaint/kpmainwindow_text.cpp
@@ -0,0 +1,395 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <kpmainwindow.h>
+
+#include <kactionclasses.h>
+#include <kapplication.h>
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcolortoolbar.h>
+#include <kpdefs.h>
+#include <kptextstyle.h>
+#include <kptooltext.h>
+#include <kptooltoolbar.h>
+#include <kptoolwidgetopaqueortransparent.h>
+#include <kpzoomedview.h>
+
+
+// private
+void kpMainWindow::setupTextToolBarActions ()
+{
+ KActionCollection *ac = actionCollection ();
+
+ m_actionTextFontFamily = new KFontAction (i18n ("Font Family"), 0/*shortcut*/,
+ this, SLOT (slotTextFontFamilyChanged ()), ac, "text_font_family");
+ m_actionTextFontSize = new KFontSizeAction (i18n ("Font Size"), 0/*shortcut*/,
+ this, SLOT (slotTextFontSizeChanged ()), ac, "text_font_size");
+
+ m_actionTextBold = new KToggleAction (i18n ("Bold"),
+ "text_bold"/*icon*/, 0/*shortcut*/,
+ this, SLOT (slotTextBoldChanged ()), ac, "text_bold");
+ m_actionTextItalic = new KToggleAction (i18n ("Italic"),
+ "text_italic"/*icon*/, 0/*shortcut*/,
+ this, SLOT (slotTextItalicChanged ()), ac, "text_italic");
+ m_actionTextUnderline = new KToggleAction (i18n ("Underline"),
+ "text_under"/*icon*/, 0/*shortcut*/,
+ this, SLOT (slotTextUnderlineChanged ()), ac, "text_underline");
+ m_actionTextStrikeThru = new KToggleAction (i18n ("Strike Through"),
+ "text_strike"/*icon*/, 0/*shortcut*/,
+ this, SLOT (slotTextStrikeThruChanged ()), ac, "text_strike_thru");
+
+
+ readAndApplyTextSettings ();
+
+
+ enableTextToolBarActions (false);
+}
+
+// private
+void kpMainWindow::readAndApplyTextSettings ()
+{
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupText);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ m_actionTextFontFamily->setFont (cfg->readEntry (kpSettingFontFamily, QString::fromLatin1 ("Times")));
+ m_actionTextFontSize->setFontSize (cfg->readNumEntry (kpSettingFontSize, 14));
+ m_actionTextBold->setChecked (cfg->readBoolEntry (kpSettingBold, false));
+ m_actionTextItalic->setChecked (cfg->readBoolEntry (kpSettingItalic, false));
+ m_actionTextUnderline->setChecked (cfg->readBoolEntry (kpSettingUnderline, false));
+ m_actionTextStrikeThru->setChecked (cfg->readBoolEntry (kpSettingStrikeThru, false));
+
+ m_textOldFontFamily = m_actionTextFontFamily->font ();
+ m_textOldFontSize = m_actionTextFontSize->fontSize ();
+}
+
+
+// public
+void kpMainWindow::enableTextToolBarActions (bool enable)
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::enableTextToolBarActions(" << enable << ")" << endl;
+#endif
+
+ m_actionTextFontFamily->setEnabled (enable);
+ m_actionTextFontSize->setEnabled (enable);
+ m_actionTextBold->setEnabled (enable);
+ m_actionTextItalic->setEnabled (enable);
+ m_actionTextUnderline->setEnabled (enable);
+ m_actionTextStrikeThru->setEnabled (enable);
+
+ if (textToolBar ())
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\thave toolbar - setShown" << endl;
+ #endif
+ textToolBar ()->setShown (enable);
+ }
+}
+
+
+// private slot
+void kpMainWindow::slotTextFontFamilyChanged ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotTextFontFamilyChanged() alive="
+ << m_isFullyConstructed
+ << " fontFamily="
+ << m_actionTextFontFamily->font ()
+ << endl;
+#endif
+
+ if (!m_isFullyConstructed)
+ return;
+
+ if (m_toolText && m_toolText->hasBegun ())
+ {
+ m_toolText->slotFontFamilyChanged (m_actionTextFontFamily->font (),
+ m_textOldFontFamily);
+ }
+
+ // Since editable KSelectAction's steal focus from view, switch back to mainView
+ // TODO: back to the last view
+ if (m_mainView)
+ m_mainView->setFocus ();
+
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupText);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+ cfg->writeEntry (kpSettingFontFamily, m_actionTextFontFamily->font ());
+ cfg->sync ();
+
+ m_textOldFontFamily = m_actionTextFontFamily->font ();
+}
+
+// private slot
+void kpMainWindow::slotTextFontSizeChanged ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotTextFontSizeChanged() alive="
+ << m_isFullyConstructed
+ << " fontSize="
+ << m_actionTextFontSize->fontSize ()
+ << endl;
+#endif
+
+ if (!m_isFullyConstructed)
+ return;
+
+ if (m_toolText && m_toolText->hasBegun ())
+ {
+ m_toolText->slotFontSizeChanged (m_actionTextFontSize->fontSize (),
+ m_textOldFontSize);
+ }
+
+ // Since editable KSelectAction's steal focus from view, switch back to mainView
+ // TODO: back to the last view
+ if (m_mainView)
+ m_mainView->setFocus ();
+
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupText);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+ cfg->writeEntry (kpSettingFontSize, m_actionTextFontSize->fontSize ());
+ cfg->sync ();
+
+ m_textOldFontSize = m_actionTextFontSize->fontSize ();
+}
+
+// private slot
+void kpMainWindow::slotTextBoldChanged ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotTextFontBoldChanged() alive="
+ << m_isFullyConstructed
+ << " bold="
+ << m_actionTextBold->isChecked ()
+ << endl;
+#endif
+
+ if (!m_isFullyConstructed)
+ return;
+
+ if (m_toolText && m_toolText->hasBegun ())
+ m_toolText->slotBoldChanged (m_actionTextBold->isChecked ());
+
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupText);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+ cfg->writeEntry (kpSettingBold, m_actionTextBold->isChecked ());
+ cfg->sync ();
+}
+
+// private slot
+void kpMainWindow::slotTextItalicChanged ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotTextFontItalicChanged() alive="
+ << m_isFullyConstructed
+ << " bold="
+ << m_actionTextItalic->isChecked ()
+ << endl;
+#endif
+
+ if (!m_isFullyConstructed)
+ return;
+
+ if (m_toolText && m_toolText->hasBegun ())
+ m_toolText->slotItalicChanged (m_actionTextItalic->isChecked ());
+
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupText);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+ cfg->writeEntry (kpSettingItalic, m_actionTextItalic->isChecked ());
+ cfg->sync ();
+}
+
+// private slot
+void kpMainWindow::slotTextUnderlineChanged ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotTextFontUnderlineChanged() alive="
+ << m_isFullyConstructed
+ << " underline="
+ << m_actionTextUnderline->isChecked ()
+ << endl;
+#endif
+
+ if (!m_isFullyConstructed)
+ return;
+
+ if (m_toolText && m_toolText->hasBegun ())
+ m_toolText->slotUnderlineChanged (m_actionTextUnderline->isChecked ());
+
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupText);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+ cfg->writeEntry (kpSettingUnderline, m_actionTextUnderline->isChecked ());
+ cfg->sync ();
+}
+
+// private slot
+void kpMainWindow::slotTextStrikeThruChanged ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotTextStrikeThruChanged() alive="
+ << m_isFullyConstructed
+ << " strikeThru="
+ << m_actionTextStrikeThru->isChecked ()
+ << endl;
+#endif
+
+ if (!m_isFullyConstructed)
+ return;
+
+ if (m_toolText && m_toolText->hasBegun ())
+ m_toolText->slotStrikeThruChanged (m_actionTextStrikeThru->isChecked ());
+
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupText);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+ cfg->writeEntry (kpSettingStrikeThru, m_actionTextStrikeThru->isChecked ());
+ cfg->sync ();
+}
+
+
+// public
+KToolBar *kpMainWindow::textToolBar ()
+{
+ return toolBar ("textToolBar");
+}
+
+bool kpMainWindow::isTextStyleBackgroundOpaque () const
+{
+ if (m_toolToolBar)
+ {
+ kpToolWidgetOpaqueOrTransparent *oot =
+ m_toolToolBar->toolWidgetOpaqueOrTransparent ();
+
+ if (oot)
+ {
+ return oot->isOpaque ();
+ }
+ }
+
+ return true;
+}
+
+// public
+kpTextStyle kpMainWindow::textStyle () const
+{
+ return kpTextStyle (m_actionTextFontFamily->font (),
+ m_actionTextFontSize->fontSize (),
+ m_actionTextBold->isChecked (),
+ m_actionTextItalic->isChecked (),
+ m_actionTextUnderline->isChecked (),
+ m_actionTextStrikeThru->isChecked (),
+ m_colorToolBar ? m_colorToolBar->foregroundColor () : kpColor::invalid,
+ m_colorToolBar ? m_colorToolBar->backgroundColor () : kpColor::invalid,
+ isTextStyleBackgroundOpaque ());
+}
+
+// public
+void kpMainWindow::setTextStyle (const kpTextStyle &textStyle_)
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::setTextStyle()" << endl;
+#endif
+
+ m_settingTextStyle++;
+
+
+ if (textStyle_.fontFamily () != m_actionTextFontFamily->font ())
+ {
+ m_actionTextFontFamily->setFont (textStyle_.fontFamily ());
+ slotTextFontFamilyChanged ();
+ }
+
+ if (textStyle_.fontSize () != m_actionTextFontSize->fontSize ())
+ {
+ m_actionTextFontSize->setFontSize (textStyle_.fontSize ());
+ slotTextFontSizeChanged ();
+ }
+
+ if (textStyle_.isBold () != m_actionTextBold->isChecked ())
+ {
+ m_actionTextBold->setChecked (textStyle_.isBold ());
+ slotTextBoldChanged ();
+ }
+
+ if (textStyle_.isItalic () != m_actionTextItalic->isChecked ())
+ {
+ m_actionTextItalic->setChecked (textStyle_.isItalic ());
+ slotTextItalicChanged ();
+ }
+
+ if (textStyle_.isUnderline () != m_actionTextUnderline->isChecked ())
+ {
+ m_actionTextUnderline->setChecked (textStyle_.isUnderline ());
+ slotTextUnderlineChanged ();
+ }
+
+ if (textStyle_.isStrikeThru () != m_actionTextStrikeThru->isChecked ())
+ {
+ m_actionTextStrikeThru->setChecked (textStyle_.isStrikeThru ());
+ slotTextStrikeThruChanged ();
+ }
+
+
+ if (textStyle_.foregroundColor () != m_colorToolBar->foregroundColor ())
+ {
+ m_colorToolBar->setForegroundColor (textStyle_.foregroundColor ());
+ }
+
+ if (textStyle_.backgroundColor () != m_colorToolBar->backgroundColor ())
+ {
+ m_colorToolBar->setBackgroundColor (textStyle_.backgroundColor ());
+ }
+
+
+ if (textStyle_.isBackgroundOpaque () != isTextStyleBackgroundOpaque ())
+ {
+ if (m_toolToolBar)
+ {
+ kpToolWidgetOpaqueOrTransparent *oot =
+ m_toolToolBar->toolWidgetOpaqueOrTransparent ();
+
+ if (oot)
+ {
+ oot->setOpaque (textStyle_.isBackgroundOpaque ());
+ }
+ }
+ }
+
+
+ m_settingTextStyle--;
+}
+
+// public
+int kpMainWindow::settingTextStyle () const
+{
+ return m_settingTextStyle;
+}
+
diff --git a/kolourpaint/kpmainwindow_tools.cpp b/kolourpaint/kpmainwindow_tools.cpp
new file mode 100644
index 00000000..fb86f91f
--- /dev/null
+++ b/kolourpaint/kpmainwindow_tools.cpp
@@ -0,0 +1,646 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <kpmainwindow.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcolortoolbar.h>
+#include <kpcommandhistory.h>
+#include <kpdocument.h>
+#include <kpselectiontransparency.h>
+#include <kpsinglekeytriggersaction.h>
+#include <kptool.h>
+#include <kptoolaction.h>
+#include <kptoolairspray.h>
+#include <kptoolbrush.h>
+#include <kptoolcolorpicker.h>
+#include <kptoolcolorwasher.h>
+#include <kptoolcurve.h>
+#include <kptoolellipticalselection.h>
+#include <kptoolellipse.h>
+#include <kptooleraser.h>
+#include <kptoolfloodfill.h>
+#include <kptoolfreeformselection.h>
+#include <kptoolline.h>
+#include <kptoolpen.h>
+#include <kptoolpolygon.h>
+#include <kptoolpolyline.h>
+#include <kptoolrectangle.h>
+#include <kptoolrectselection.h>
+#include <kptoolresizescale.h>
+#include <kptoolroundedrectangle.h>
+#include <kptooltext.h>
+#include <kptooltoolbar.h>
+#include <kptoolwidgetopaqueortransparent.h>
+#include <kpviewscrollablecontainer.h>
+#include <kpzoomedview.h>
+
+
+// private
+void kpMainWindow::setupToolActions ()
+{
+ m_tools.setAutoDelete (true);
+
+ m_tools.append (m_toolFreeFormSelection = new kpToolFreeFormSelection (this));
+ m_tools.append (m_toolRectSelection = new kpToolRectSelection (this));
+
+ m_tools.append (m_toolEllipticalSelection = new kpToolEllipticalSelection (this));
+ m_tools.append (m_toolText = new kpToolText (this));
+
+ m_tools.append (m_toolLine = new kpToolLine (this));
+ m_tools.append (m_toolPen = new kpToolPen (this));
+
+ m_tools.append (m_toolEraser = new kpToolEraser (this));
+ m_tools.append (m_toolBrush = new kpToolBrush (this));
+
+ m_tools.append (m_toolFloodFill = new kpToolFloodFill (this));
+ m_tools.append (m_toolColorPicker = new kpToolColorPicker (this));
+
+ m_tools.append (m_toolColorWasher = new kpToolColorWasher (this));
+ m_tools.append (m_toolAirSpray = new kpToolAirSpray (this));
+
+ m_tools.append (m_toolRoundedRectangle = new kpToolRoundedRectangle (this));
+ m_tools.append (m_toolRectangle = new kpToolRectangle (this));
+
+ m_tools.append (m_toolPolygon = new kpToolPolygon (this));
+ m_tools.append (m_toolEllipse = new kpToolEllipse (this));
+
+ m_tools.append (m_toolPolyline = new kpToolPolyline (this));
+ m_tools.append (m_toolCurve = new kpToolCurve (this));
+
+
+ KActionCollection *ac = actionCollection ();
+
+ m_actionPrevToolOptionGroup1 = new kpSingleKeyTriggersAction (
+ i18n ("Previous Tool Option (Group #1)"),
+ kpTool::shortcutForKey (Qt::Key_1),
+ this, SLOT (slotActionPrevToolOptionGroup1 ()),
+ ac, "prev_tool_option_group_1");
+ m_actionNextToolOptionGroup1 = new kpSingleKeyTriggersAction (
+ i18n ("Next Tool Option (Group #1)"),
+ kpTool::shortcutForKey (Qt::Key_2),
+ this, SLOT (slotActionNextToolOptionGroup1 ()),
+ ac, "next_tool_option_group_1");
+
+ m_actionPrevToolOptionGroup2 = new kpSingleKeyTriggersAction (
+ i18n ("Previous Tool Option (Group #2)"),
+ kpTool::shortcutForKey (Qt::Key_3),
+ this, SLOT (slotActionPrevToolOptionGroup2 ()),
+ ac, "prev_tool_option_group_2");
+ m_actionNextToolOptionGroup2 = new kpSingleKeyTriggersAction (
+ i18n ("Next Tool Option (Group #2)"),
+ kpTool::shortcutForKey (Qt::Key_4),
+ this, SLOT (slotActionNextToolOptionGroup2 ()),
+ ac, "next_tool_option_group_2");
+}
+
+// private
+void kpMainWindow::createToolBox ()
+{
+ m_toolToolBar = new kpToolToolBar (i18n ("Tool Box"), this, 2/*columns/rows*/, "Tool Box");
+ connect (m_toolToolBar, SIGNAL (sigToolSelected (kpTool *)),
+ this, SLOT (slotToolSelected (kpTool *)));
+ connect (m_toolToolBar, SIGNAL (toolWidgetOptionSelected ()),
+ this, SLOT (updateToolOptionPrevNextActionsEnabled ()));
+
+ for (QPtrList <kpTool>::const_iterator it = m_tools.begin ();
+ it != m_tools.end ();
+ it++)
+ {
+ m_toolToolBar->registerTool (*it);
+ }
+
+
+ // (from config file)
+ readLastTool ();
+
+
+ enableToolsDocumentActions (false);
+}
+
+// private
+void kpMainWindow::enableToolsDocumentActions (bool enable)
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::enableToolsDocumentsAction(" << enable << ")" << endl;
+#endif
+
+ m_toolActionsEnabled = enable;
+
+
+ if (enable && !m_toolToolBar->isEnabled ())
+ {
+ kpTool *previousTool = m_toolToolBar->previousTool ();
+
+ // select tool for enabled Tool Box
+
+ if (previousTool)
+ m_toolToolBar->selectPreviousTool ();
+ else
+ {
+ if (m_lastToolNumber >= 0 && m_lastToolNumber < (int) m_tools.count ())
+ m_toolToolBar->selectTool (m_tools.at (m_lastToolNumber));
+ else
+ m_toolToolBar->selectTool (m_toolPen);
+ }
+ }
+ else if (!enable && m_toolToolBar->isEnabled ())
+ {
+ // don't have a disabled Tool Box with an enabled Tool
+ m_toolToolBar->selectTool (0);
+ }
+
+
+ m_toolToolBar->setEnabled (enable);
+
+
+ for (QPtrList <kpTool>::const_iterator it = m_tools.begin ();
+ it != m_tools.end ();
+ it++)
+ {
+ kpToolAction *action = (*it)->action ();
+ if (action)
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tchanging enabled state of " << (*it)->name () << endl;
+ #endif
+
+ if (!enable && action->isChecked ())
+ action->setChecked (false);
+
+ action->setEnabled (enable);
+ }
+ else
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tno action for " << (*it)->name () << endl;
+ #endif
+ }
+ }
+
+
+ updateToolOptionPrevNextActionsEnabled ();
+}
+
+// private slot
+void kpMainWindow::updateToolOptionPrevNextActionsEnabled ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::updateToolOptionPrevNextActionsEnabled()"
+ << " numShownToolWidgets="
+ << m_toolToolBar->numShownToolWidgets ()
+ << endl;
+#endif
+
+ const bool enable = m_toolActionsEnabled;
+
+
+ m_actionPrevToolOptionGroup1->setEnabled (enable &&
+ m_toolToolBar->shownToolWidget (0) &&
+ m_toolToolBar->shownToolWidget (0)->hasPreviousOption ());
+ m_actionNextToolOptionGroup1->setEnabled (enable &&
+ m_toolToolBar->shownToolWidget (0) &&
+ m_toolToolBar->shownToolWidget (0)->hasNextOption ());
+
+ m_actionPrevToolOptionGroup2->setEnabled (enable &&
+ m_toolToolBar->shownToolWidget (1) &&
+ m_toolToolBar->shownToolWidget (1)->hasPreviousOption ());
+ m_actionNextToolOptionGroup2->setEnabled (enable &&
+ m_toolToolBar->shownToolWidget (1) &&
+ m_toolToolBar->shownToolWidget (1)->hasNextOption ());
+}
+
+
+// public
+kpTool *kpMainWindow::tool () const
+{
+ return m_toolToolBar ? m_toolToolBar->tool () : 0;
+}
+
+// public
+bool kpMainWindow::toolHasBegunShape () const
+{
+ kpTool *currentTool = tool ();
+ return (currentTool && currentTool->hasBegunShape ());
+}
+
+// public
+bool kpMainWindow::toolIsASelectionTool (bool includingTextTool) const
+{
+ kpTool *currentTool = tool ();
+
+ return ((currentTool == m_toolFreeFormSelection) ||
+ (currentTool == m_toolRectSelection) ||
+ (currentTool == m_toolEllipticalSelection) ||
+ (currentTool == m_toolText && includingTextTool));
+}
+
+// public
+bool kpMainWindow::toolIsTextTool () const
+{
+ return (tool () == m_toolText);
+}
+
+
+// public
+kpSelectionTransparency kpMainWindow::selectionTransparency () const
+{
+ kpToolWidgetOpaqueOrTransparent *oot = m_toolToolBar->toolWidgetOpaqueOrTransparent ();
+ if (!oot)
+ {
+ kdError () << "kpMainWindow::selectionTransparency() without opaqueOrTransparent widget" << endl;
+ return kpSelectionTransparency ();
+ }
+
+ return kpSelectionTransparency (oot->isOpaque (), backgroundColor (), m_colorToolBar->colorSimilarity ());
+}
+
+// public
+void kpMainWindow::setSelectionTransparency (const kpSelectionTransparency &transparency, bool forceColorChange)
+{
+#if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "kpMainWindow::setSelectionTransparency() isOpaque=" << transparency.isOpaque ()
+ << " color=" << (transparency.transparentColor ().isValid () ? (int *) transparency.transparentColor ().toQRgb () : 0)
+ << " forceColorChange=" << forceColorChange
+ << endl;
+#endif
+
+ kpToolWidgetOpaqueOrTransparent *oot = m_toolToolBar->toolWidgetOpaqueOrTransparent ();
+ if (!oot)
+ {
+ kdError () << "kpMainWindow::setSelectionTransparency() without opaqueOrTransparent widget" << endl;
+ return;
+ }
+
+ m_settingSelectionTransparency++;
+
+ oot->setOpaque (transparency.isOpaque ());
+ if (transparency.isTransparent () || forceColorChange)
+ {
+ m_colorToolBar->setColor (1, transparency.transparentColor ());
+ m_colorToolBar->setColorSimilarity (transparency.colorSimilarity ());
+ }
+
+ m_settingSelectionTransparency--;
+}
+
+// public
+int kpMainWindow::settingSelectionTransparency () const
+{
+ return m_settingSelectionTransparency;
+}
+
+
+// private slot
+void kpMainWindow::slotToolSelected (kpTool *tool)
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotToolSelected (" << tool << ")" << endl;
+#endif
+
+ kpTool *previousTool = m_toolToolBar ? m_toolToolBar->previousTool () : 0;
+
+ if (previousTool)
+ {
+ disconnect (previousTool, SIGNAL (movedAndAboutToDraw (const QPoint &, const QPoint &, int, bool *)),
+ this, SLOT (slotDragScroll (const QPoint &, const QPoint &, int, bool *)));
+ disconnect (previousTool, SIGNAL (endedDraw (const QPoint &)),
+ this, SLOT (slotEndDragScroll ()));
+ disconnect (previousTool, SIGNAL (cancelledShape (const QPoint &)),
+ this, SLOT (slotEndDragScroll ()));
+
+ disconnect (previousTool, SIGNAL (userMessageChanged (const QString &)),
+ this, SLOT (recalculateStatusBarMessage ()));
+ disconnect (previousTool, SIGNAL (userShapePointsChanged (const QPoint &, const QPoint &)),
+ this, SLOT (recalculateStatusBarShape ()));
+ disconnect (previousTool, SIGNAL (userShapeSizeChanged (const QSize &)),
+ this, SLOT (recalculateStatusBarShape ()));
+
+ disconnect (m_colorToolBar, SIGNAL (colorsSwapped (const kpColor &, const kpColor &)),
+ previousTool, SLOT (slotColorsSwappedInternal (const kpColor &, const kpColor &)));
+ disconnect (m_colorToolBar, SIGNAL (foregroundColorChanged (const kpColor &)),
+ previousTool, SLOT (slotForegroundColorChangedInternal (const kpColor &)));
+ disconnect (m_colorToolBar, SIGNAL (backgroundColorChanged (const kpColor &)),
+ previousTool, SLOT (slotBackgroundColorChangedInternal (const kpColor &)));
+ disconnect (m_colorToolBar, SIGNAL (colorSimilarityChanged (double, int)),
+ previousTool, SLOT (slotColorSimilarityChangedInternal (double, int)));
+ }
+
+ if (tool)
+ {
+ connect (tool, SIGNAL (movedAndAboutToDraw (const QPoint &, const QPoint &, int, bool *)),
+ this, SLOT (slotDragScroll (const QPoint &, const QPoint &, int, bool *)));
+ connect (tool, SIGNAL (endedDraw (const QPoint &)),
+ this, SLOT (slotEndDragScroll ()));
+ connect (tool, SIGNAL (cancelledShape (const QPoint &)),
+ this, SLOT (slotEndDragScroll ()));
+
+ connect (tool, SIGNAL (userMessageChanged (const QString &)),
+ this, SLOT (recalculateStatusBarMessage ()));
+ connect (tool, SIGNAL (userShapePointsChanged (const QPoint &, const QPoint &)),
+ this, SLOT (recalculateStatusBarShape ()));
+ connect (tool, SIGNAL (userShapeSizeChanged (const QSize &)),
+ this, SLOT (recalculateStatusBarShape ()));
+ recalculateStatusBar ();
+
+ connect (m_colorToolBar, SIGNAL (colorsSwapped (const kpColor &, const kpColor &)),
+ tool, SLOT (slotColorsSwappedInternal (const kpColor &, const kpColor &)));
+ connect (m_colorToolBar, SIGNAL (foregroundColorChanged (const kpColor &)),
+ tool, SLOT (slotForegroundColorChangedInternal (const kpColor &)));
+ connect (m_colorToolBar, SIGNAL (backgroundColorChanged (const kpColor &)),
+ tool, SLOT (slotBackgroundColorChangedInternal (const kpColor &)));
+ connect (m_colorToolBar, SIGNAL (colorSimilarityChanged (double, int)),
+ tool, SLOT (slotColorSimilarityChangedInternal (double, int)));
+
+
+ saveLastTool ();
+ }
+
+ updateToolOptionPrevNextActionsEnabled ();
+}
+
+
+// private
+void kpMainWindow::readLastTool ()
+{
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupTools);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ m_lastToolNumber = cfg->readNumEntry (kpSettingLastTool, -1);
+}
+
+
+// private
+int kpMainWindow::toolNumber () const
+{
+ int number = 0;
+ for (QPtrList <kpTool>::const_iterator it = m_tools.begin ();
+ it != m_tools.end ();
+ it++)
+ {
+ if (*it == tool ())
+ return number;
+
+ number++;
+ }
+
+ return -1;
+}
+
+// private
+void kpMainWindow::saveLastTool ()
+{
+ int number = toolNumber ();
+ if (number < 0 || number >= (int) m_tools.count ())
+ return;
+
+
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupTools);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ cfg->writeEntry (kpSettingLastTool, number);
+ cfg->sync ();
+}
+
+
+// private
+bool kpMainWindow::maybeDragScrollingMainView () const
+{
+ return (tool () && m_mainView &&
+ tool ()->viewUnderStartPoint () == m_mainView);
+}
+
+// private slot
+bool kpMainWindow::slotDragScroll (const QPoint &docPoint,
+ const QPoint &docLastPoint,
+ int zoomLevel,
+ bool *scrolled)
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotDragScroll() maybeDragScrolling="
+ << maybeDragScrollingMainView ()
+ << endl;
+#endif
+
+ if (maybeDragScrollingMainView ())
+ {
+ return m_scrollView->beginDragScroll (docPoint, docLastPoint, zoomLevel, scrolled);
+ }
+ else
+ {
+ return false;
+ }
+}
+
+// private slot
+bool kpMainWindow::slotEndDragScroll ()
+{
+ // (harmless if haven't started drag scroll)
+ return m_scrollView->endDragScroll ();
+}
+
+
+// private slot
+void kpMainWindow::slotBeganDocResize ()
+{
+ if (toolHasBegunShape ())
+ tool ()->endShapeInternal ();
+
+ recalculateStatusBarShape ();
+}
+
+// private slot
+void kpMainWindow::slotContinuedDocResize (const QSize &)
+{
+ recalculateStatusBarShape ();
+}
+
+// private slot
+void kpMainWindow::slotCancelledDocResize ()
+{
+ recalculateStatusBar ();
+}
+
+// private slot
+void kpMainWindow::slotEndedDocResize (const QSize &size)
+{
+#define DOC_RESIZE_COMPLETED() \
+{ \
+ m_docResizeToBeCompleted = false; \
+ recalculateStatusBar (); \
+}
+
+ // Prevent statusbar updates
+ m_docResizeToBeCompleted = true;
+
+ m_docResizeWidth = (size.width () > 0 ? size.width () : 1),
+ m_docResizeHeight = (size.height () > 0 ? size.height () : 1);
+
+ if (m_docResizeWidth == m_document->width () &&
+ m_docResizeHeight == m_document->height ())
+ {
+ DOC_RESIZE_COMPLETED ();
+ return;
+ }
+
+
+ // Blank status to avoid confusion if dialog comes up
+ setStatusBarMessage ();
+ setStatusBarShapePoints ();
+ setStatusBarShapeSize ();
+
+
+ if (kpTool::warnIfBigImageSize (m_document->width (),
+ m_document->height (),
+ m_docResizeWidth, m_docResizeHeight,
+ i18n ("<qt><p>Resizing the image to"
+ " %1x%2 may take a substantial amount of memory."
+ " This can reduce system"
+ " responsiveness and cause other application resource"
+ " problems.</p>"
+
+ "<p>Are you sure want to resize the"
+ " image?</p></qt>")
+ .arg (m_docResizeWidth)
+ .arg (m_docResizeHeight),
+ i18n ("Resize Image?"),
+ i18n ("R&esize Image"),
+ this))
+ {
+ m_commandHistory->addCommand (
+ new kpToolResizeScaleCommand (
+ false/*doc, not sel*/,
+ m_docResizeWidth, m_docResizeHeight,
+ kpToolResizeScaleCommand::Resize,
+ this));
+
+ saveDefaultDocSize (QSize (m_docResizeWidth, m_docResizeHeight));
+ }
+
+
+ DOC_RESIZE_COMPLETED ();
+
+#undef DOC_RESIZE_COMPLETED
+}
+
+// private slot
+void kpMainWindow::slotDocResizeMessageChanged (const QString &string)
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotDocResizeMessageChanged(" << string
+ << ") docResizeToBeCompleted=" << m_docResizeToBeCompleted
+ << endl;
+#else
+ (void) string;
+#endif
+
+ if (m_docResizeToBeCompleted)
+ return;
+
+ recalculateStatusBarMessage ();
+}
+
+
+// private slot
+void kpMainWindow::slotActionPrevToolOptionGroup1 ()
+{
+ if (!m_toolToolBar->shownToolWidget (0))
+ return;
+
+ m_toolToolBar->shownToolWidget (0)->selectPreviousOption ();
+ updateToolOptionPrevNextActionsEnabled ();
+}
+
+// private slot
+void kpMainWindow::slotActionNextToolOptionGroup1 ()
+{
+ if (!m_toolToolBar->shownToolWidget (0))
+ return;
+
+ m_toolToolBar->shownToolWidget (0)->selectNextOption ();
+ updateToolOptionPrevNextActionsEnabled ();
+}
+
+
+// private slot
+void kpMainWindow::slotActionPrevToolOptionGroup2 ()
+{
+ if (!m_toolToolBar->shownToolWidget (1))
+ return;
+
+ m_toolToolBar->shownToolWidget (1)->selectPreviousOption ();
+ updateToolOptionPrevNextActionsEnabled ();
+}
+
+// private slot
+void kpMainWindow::slotActionNextToolOptionGroup2 ()
+{
+ if (!m_toolToolBar->shownToolWidget (1))
+ return;
+
+ m_toolToolBar->shownToolWidget (1)->selectNextOption ();
+ updateToolOptionPrevNextActionsEnabled ();
+}
+
+
+// public slots
+
+#define SLOT_TOOL(toolName) \
+void kpMainWindow::slotTool##toolName () \
+{ \
+ if (!m_toolToolBar) \
+ return; \
+ \
+ if (tool () == m_tool##toolName) \
+ return; \
+ \
+ m_toolToolBar->selectTool (m_tool##toolName); \
+}
+
+SLOT_TOOL (AirSpray)
+SLOT_TOOL (Brush)
+SLOT_TOOL (ColorPicker)
+SLOT_TOOL (ColorWasher)
+SLOT_TOOL (Curve)
+SLOT_TOOL (Ellipse)
+SLOT_TOOL (EllipticalSelection)
+SLOT_TOOL (Eraser)
+SLOT_TOOL (FloodFill)
+SLOT_TOOL (FreeFormSelection)
+SLOT_TOOL (Line)
+SLOT_TOOL (Pen)
+SLOT_TOOL (Polygon)
+SLOT_TOOL (Polyline)
+SLOT_TOOL (Rectangle)
+SLOT_TOOL (RectSelection)
+SLOT_TOOL (RoundedRectangle)
+SLOT_TOOL (Text)
diff --git a/kolourpaint/kpmainwindow_view.cpp b/kolourpaint/kpmainwindow_view.cpp
new file mode 100644
index 00000000..1aa9b5dc
--- /dev/null
+++ b/kolourpaint/kpmainwindow_view.cpp
@@ -0,0 +1,1151 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_ZOOM_FLICKER 0
+
+#include <kpmainwindow.h>
+#include <kpmainwindow_p.h>
+
+#include <qdatetime.h>
+#include <qpainter.h>
+#include <qtimer.h>
+
+#include <kactionclasses.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kstdaction.h>
+
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpthumbnail.h>
+#include <kptool.h>
+#include <kptooltoolbar.h>
+#include <kpunzoomedthumbnailview.h>
+#include <kpviewmanager.h>
+#include <kpviewscrollablecontainer.h>
+#include <kpwidgetmapper.h>
+#include <kpzoomedview.h>
+#include <kpzoomedthumbnailview.h>
+
+
+// private
+void kpMainWindow::setupViewMenuActions ()
+{
+ m_viewMenuDocumentActionsEnabled = false;
+ m_thumbnailSaveConfigTimer = 0;
+
+
+ KActionCollection *ac = actionCollection ();
+
+ /*m_actionFullScreen = KStdAction::fullScreen (0, 0, ac);
+ m_actionFullScreen->setEnabled (false);*/
+
+
+ m_actionActualSize = KStdAction::actualSize (this, SLOT (slotActualSize ()), ac);
+ /*m_actionFitToPage = KStdAction::fitToPage (this, SLOT (slotFitToPage ()), ac);
+ m_actionFitToWidth = KStdAction::fitToWidth (this, SLOT (slotFitToWidth ()), ac);
+ m_actionFitToHeight = KStdAction::fitToHeight (this, SLOT (slotFitToHeight ()), ac);*/
+
+
+ m_actionZoomIn = KStdAction::zoomIn (this, SLOT (slotZoomIn ()), ac);
+ m_actionZoomOut = KStdAction::zoomOut (this, SLOT (slotZoomOut ()), ac);
+
+
+ m_actionZoom = new KSelectAction (i18n ("&Zoom"), 0,
+ this, SLOT (slotZoom ()), actionCollection (), "view_zoom_to");
+ m_actionZoom->setEditable (true);
+
+ // create the zoom list for the 1st call to zoomTo() below
+ m_zoomList.append (10); m_zoomList.append (25); m_zoomList.append (33);
+ m_zoomList.append (50); m_zoomList.append (67); m_zoomList.append (75);
+ m_zoomList.append (100);
+ m_zoomList.append (200); m_zoomList.append (300);
+ m_zoomList.append (400); m_zoomList.append (600); m_zoomList.append (800);
+ m_zoomList.append (1000); m_zoomList.append (1200); m_zoomList.append (1600);
+
+
+ m_actionShowGrid = new KToggleAction (i18n ("Show &Grid"), CTRL + Key_G,
+ this, SLOT (slotShowGridToggled ()), actionCollection (), "view_show_grid");
+ m_actionShowGrid->setCheckedState (i18n ("Hide &Grid"));
+
+
+ // TODO: This doesn't work when the thumbnail has focus.
+ // Testcase: Press CTRL+H twice on a fresh KolourPaint.
+ // The second CTRL+H doesn't close the thumbnail.
+ m_actionShowThumbnail = new KToggleAction (i18n ("Show T&humbnail"), CTRL + Key_H,
+ this, SLOT (slotShowThumbnailToggled ()), actionCollection (), "view_show_thumbnail");
+ m_actionShowThumbnail->setCheckedState (i18n ("Hide T&humbnail"));
+
+ // Please do not use setCheckedState() here - it wouldn't make sense
+ m_actionZoomedThumbnail = new KToggleAction (i18n ("Zoo&med Thumbnail Mode"), 0,
+ this, SLOT (slotZoomedThumbnailToggled ()), actionCollection (), "view_zoomed_thumbnail");
+
+ // For consistency with the above action, don't use setCheckedState()
+ //
+ // Also, don't use "Show Thumbnail Rectangle" because if entire doc
+ // can be seen in scrollView, checking option won't "Show" anything
+ // since rect _surrounds_ entire doc (hence, won't be rendered).
+ d->m_actionShowThumbnailRectangle = new KToggleAction (
+ i18n ("Enable Thumbnail &Rectangle"),
+ 0,
+ this, SLOT (slotThumbnailShowRectangleToggled ()),
+ actionCollection (), "view_show_thumbnail_rectangle");
+
+
+ enableViewMenuDocumentActions (false);
+}
+
+// private
+bool kpMainWindow::viewMenuDocumentActionsEnabled () const
+{
+ return m_viewMenuDocumentActionsEnabled;
+}
+
+// private
+void kpMainWindow::enableViewMenuDocumentActions (bool enable)
+{
+ m_viewMenuDocumentActionsEnabled = enable;
+
+
+ m_actionActualSize->setEnabled (enable);
+ /*m_actionFitToPage->setEnabled (enable);
+ m_actionFitToWidth->setEnabled (enable);
+ m_actionFitToHeight->setEnabled (enable);*/
+
+ m_actionZoomIn->setEnabled (enable);
+ m_actionZoomOut->setEnabled (enable);
+
+ m_actionZoom->setEnabled (enable);
+
+ actionShowGridUpdate ();
+
+ m_actionShowThumbnail->setEnabled (enable);
+ enableThumbnailOptionActions (enable);
+
+
+ // TODO: for the time being, assume that we start at zoom 100%
+ // with no grid
+
+ // This function is only called when a new document is created
+ // or an existing document is closed. So the following will
+ // always be correct:
+
+ zoomTo (100);
+}
+
+// private
+void kpMainWindow::actionShowGridUpdate ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::actionShowGridUpdate()" << endl;
+#endif
+ const bool enable = (viewMenuDocumentActionsEnabled () &&
+ m_mainView && m_mainView->canShowGrid ());
+
+ m_actionShowGrid->setEnabled (enable);
+ m_actionShowGrid->setChecked (enable && m_configShowGrid);
+}
+
+
+// private
+void kpMainWindow::sendZoomListToActionZoom ()
+{
+ QStringList items;
+
+ const QValueVector <int>::ConstIterator zoomListEnd (m_zoomList.end ());
+ for (QValueVector <int>::ConstIterator it = m_zoomList.begin ();
+ it != zoomListEnd;
+ it++)
+ {
+ items << zoomLevelToString (*it);
+ }
+
+ // Work around a KDE bug - KSelectAction::setItems() enables the action.
+ // David Faure said it won't be fixed because it's a feature used by
+ // KRecentFilesAction.
+ bool e = m_actionZoom->isEnabled ();
+ m_actionZoom->setItems (items);
+ if (e != m_actionZoom->isEnabled ())
+ m_actionZoom->setEnabled (e);
+}
+
+// private
+int kpMainWindow::zoomLevelFromString (const QString &string)
+{
+ // loop until not digit
+ int i;
+ for (i = 0; i < (int) string.length () && string.at (i).isDigit (); i++)
+ ;
+
+ // convert zoom level to number
+ bool ok = false;
+ int zoomLevel = string.left (i).toInt (&ok);
+
+ if (!ok || zoomLevel <= 0 || zoomLevel > 3200)
+ return 0; // error
+ else
+ return zoomLevel;
+}
+
+// private
+QString kpMainWindow::zoomLevelToString (int zoomLevel)
+{
+ return i18n ("%1%").arg (zoomLevel);
+}
+
+// private
+void kpMainWindow::zoomTo (int zoomLevel, bool centerUnderCursor)
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::zoomTo (" << zoomLevel << ")" << endl;
+#endif
+
+ if (zoomLevel <= 0)
+ zoomLevel = m_mainView ? m_mainView->zoomLevelX () : 100;
+
+// mute point since the thumbnail suffers from this too
+#if 0
+ else if (m_mainView && m_mainView->zoomLevelX () % 100 == 0 && zoomLevel % 100)
+ {
+ if (KMessageBox::warningContinueCancel (this,
+ i18n ("Setting the zoom level to a value that is not a multiple of 100% "
+ "results in imprecise editing and redraw glitches.\n"
+ "Do you really want to set to zoom level to %1%?")
+ .arg (zoomLevel),
+ QString::null/*caption*/,
+ i18n ("Set Zoom Level to %1%").arg (zoomLevel),
+ "DoNotAskAgain_ZoomLevelNotMultipleOf100") != KMessageBox::Continue)
+ {
+ zoomLevel = m_mainView->zoomLevelX ();
+ }
+ }
+#endif
+
+ int index = 0;
+ QValueVector <int>::Iterator it = m_zoomList.begin ();
+
+ while (index < (int) m_zoomList.count () && zoomLevel > *it)
+ it++, index++;
+
+ if (zoomLevel != *it)
+ m_zoomList.insert (it, zoomLevel);
+
+ sendZoomListToActionZoom ();
+ m_actionZoom->setCurrentItem (index);
+
+
+ if (viewMenuDocumentActionsEnabled ())
+ {
+ m_actionActualSize->setEnabled (zoomLevel != 100);
+
+ m_actionZoomIn->setEnabled (m_actionZoom->currentItem () < (int) m_zoomList.count () - 1);
+ m_actionZoomOut->setEnabled (m_actionZoom->currentItem () > 0);
+ }
+
+
+ if (m_viewManager)
+ m_viewManager->setQueueUpdates ();
+
+
+ if (m_scrollView)
+ {
+ m_scrollView->setUpdatesEnabled (false);
+ if (m_scrollView->viewport ())
+ m_scrollView->viewport ()->setUpdatesEnabled (false);
+ }
+
+ if (m_mainView)
+ {
+ m_mainView->setUpdatesEnabled (false);
+
+ if (m_scrollView && m_scrollView->viewport ())
+ {
+ // Ordinary flicker is better than the whole view moving
+ QPainter p (m_mainView);
+ p.fillRect (m_mainView->rect (),
+ m_scrollView->viewport ()->colorGroup ().background ());
+ }
+ }
+
+
+ if (m_scrollView && m_mainView)
+ {
+ #if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "\tscrollView contentsX=" << m_scrollView->contentsX ()
+ << " contentsY=" << m_scrollView->contentsY ()
+ << " contentsWidth=" << m_scrollView->contentsWidth ()
+ << " contentsHeight=" << m_scrollView->contentsHeight ()
+ << " visibleWidth=" << m_scrollView->visibleWidth ()
+ << " visibleHeight=" << m_scrollView->visibleHeight ()
+ << " oldZoomX=" << m_mainView->zoomLevelX ()
+ << " oldZoomY=" << m_mainView->zoomLevelY ()
+ << " newZoom=" << zoomLevel
+ << " mainViewX=" << m_scrollView->childX (m_mainView)
+ << " mainViewY=" << m_scrollView->childY (m_mainView)
+ << endl;
+ #endif
+
+ // TODO: when changing from no scrollbars to scrollbars, Qt lies about
+ // visibleWidth() & visibleHeight() (doesn't take into account the
+ // space taken by the would-be scrollbars) until it updates the
+ // scrollview; hence the centring is off by about 5-10 pixels.
+
+ // TODO: use visibleRect() for greater accuracy?
+
+ int viewX, viewY;
+
+ bool targetDocAvail = false;
+ double targetDocX, targetDocY;
+
+ if (centerUnderCursor &&
+ m_viewManager && m_viewManager->viewUnderCursor ())
+ {
+ kpView *const vuc = m_viewManager->viewUnderCursor ();
+ QPoint viewPoint = vuc->mouseViewPoint ();
+
+ // vuc->transformViewToDoc() returns QPoint which only has int
+ // accuracy so we do X and Y manually.
+ targetDocX = vuc->transformViewToDocX (viewPoint.x ());
+ targetDocY = vuc->transformViewToDocY (viewPoint.y ());
+ targetDocAvail = true;
+
+ if (vuc != m_mainView)
+ viewPoint = vuc->transformViewToOtherView (viewPoint, m_mainView);
+
+ viewX = viewPoint.x ();
+ viewY = viewPoint.y ();
+ }
+ else
+ {
+ viewX = m_scrollView->contentsX () +
+ QMIN (m_mainView->width (),
+ m_scrollView->visibleWidth ()) / 2;
+ viewY = m_scrollView->contentsY () +
+ QMIN (m_mainView->height (),
+ m_scrollView->visibleHeight ()) / 2;
+ }
+
+ int newCenterX = viewX * zoomLevel / m_mainView->zoomLevelX ();
+ int newCenterY = viewY * zoomLevel / m_mainView->zoomLevelY ();
+
+ m_mainView->setZoomLevel (zoomLevel, zoomLevel);
+ #if DEBUG_ZOOM_FLICKER
+ {
+ kdDebug () << "FLICKER: just setZoomLevel" << endl;
+ QTime timer; timer.start ();
+ while (timer.elapsed () < 1000)
+ ;
+ }
+ #endif
+
+ #if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "\tvisibleWidth=" << m_scrollView->visibleWidth ()
+ << " visibleHeight=" << m_scrollView->visibleHeight ()
+ << endl;
+ kdDebug () << "\tnewCenterX=" << newCenterX
+ << " newCenterY=" << newCenterY << endl;
+ #endif
+
+ m_scrollView->center (newCenterX, newCenterY);
+ #if DEBUG_ZOOM_FLICKER
+ {
+ kdDebug () << "FLICKER: just centred" << endl;
+ QTime timer; timer.start ();
+ while (timer.elapsed () < 2000)
+ ;
+ }
+ #endif
+
+ if (centerUnderCursor &&
+ targetDocAvail &&
+ m_viewManager && m_viewManager->viewUnderCursor ())
+ {
+ kpView *const vuc = m_viewManager->viewUnderCursor ();
+
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tcenterUnderCursor: reposition cursor; viewUnderCursor="
+ << vuc->name () << endl;
+ #endif
+
+ const double viewX = vuc->transformDocToViewX (targetDocX);
+ const double viewY = vuc->transformDocToViewY (targetDocY);
+ // Rounding error from zooming in and out :(
+ // TODO: do everything in terms of tool doc points in type "double".
+ const QPoint viewPoint ((int) viewX, (int) viewY);
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t\tdoc: (" << targetDocX << "," << targetDocY << ")"
+ << " viewUnderCursor: (" << viewX << "," << viewY << ")"
+ << endl;
+ #endif
+
+ if (vuc->clipRegion ().contains (viewPoint))
+ {
+ const QPoint globalPoint =
+ kpWidgetMapper::toGlobal (vuc, viewPoint);
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t\tglobalPoint=" << globalPoint << endl;
+ #endif
+
+ // TODO: Determine some sane cursor flashing indication -
+ // cursor movement is convenient but not conventional.
+ //
+ // Major problem: if using QApplication::setOverrideCursor()
+ // and in some stage of flash and window quits.
+ //
+ // Or if using kpView::setCursor() and change tool.
+ QCursor::setPos (globalPoint);
+ }
+ // e.g. Zoom to 200%, scroll mainView to bottom-right.
+ // Unzoomed Thumbnail shows top-left portion of bottom-right of
+ // mainView.
+ //
+ // Aim cursor at bottom-right of thumbnail and zoom out with
+ // CTRL+Wheel.
+ //
+ // If mainView is now small enough to largely not need scrollbars,
+ // Unzoomed Thumbnail scrolls to show _top-left_ portion
+ // _of top-left_ of mainView.
+ //
+ // Unzoomed Thumbnail no longer contains the point we zoomed out
+ // on top of.
+ else
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t\twon't move cursor - would get outside view"
+ << endl;
+ #endif
+
+ // TODO: Sane cursor flashing indication that indicates
+ // that the normal cursor movement didn't happen.
+ }
+ }
+
+ #if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "\t\tcheck (contentsX=" << m_scrollView->contentsX ()
+ << ",contentsY=" << m_scrollView->contentsY ()
+ << ")" << endl;
+ #endif
+ }
+
+ if (m_mainView)
+ {
+ actionShowGridUpdate ();
+ #if DEBUG_ZOOM_FLICKER
+ {
+ kdDebug () << "FLICKER: updated grid action" << endl;
+ QTime timer; timer.start ();
+ while (timer.elapsed () < 1000)
+ ;
+ }
+ #endif
+
+
+ updateMainViewGrid ();
+ #if DEBUG_ZOOM_FLICKER
+ {
+ kdDebug () << "FLICKER: just updated grid" << endl;
+ QTime timer; timer.start ();
+ while (timer.elapsed () < 1000)
+ ;
+ }
+ #endif
+
+
+ // Since Zoom Level KSelectAction on ToolBar grabs focus after changing
+ // Zoom, switch back to the Main View.
+ // TODO: back to the last view
+ m_mainView->setFocus ();
+ #if DEBUG_ZOOM_FLICKER
+ {
+ kdDebug () << "FLICKER: just set focus to mainview" << endl;
+ QTime timer; timer.start ();
+ while (timer.elapsed () < 1000)
+ ;
+ }
+ #endif
+
+ }
+#if 1
+ // The view magnified and moved beneath the cursor
+ if (tool ())
+ tool ()->somethingBelowTheCursorChanged ();
+ #if DEBUG_ZOOM_FLICKER
+ {
+ kdDebug () << "FLICKER: signalled something below cursor" << endl;
+ QTime timer; timer.start ();
+ while (timer.elapsed () < 1000)
+ ;
+ }
+ #endif
+#endif
+
+ // HACK: make sure all of Qt's update() calls trigger
+ // kpView::paintEvent() _now_ so that they can be queued by us
+ // (until kpViewManager::restoreQueueUpdates()) to reduce flicker
+ // caused mainly by m_scrollView->center()
+ //
+ // TODO: remove flicker completely
+ //QTimer::singleShot (0, this, SLOT (finishZoomTo ()));
+
+ // Later: I don't think there is an update() that needs to be queued
+ // - let's reduce latency instead.
+ finishZoomTo ();
+}
+
+// private slot
+void kpMainWindow::finishZoomTo ()
+{
+#if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "\tkpMainWindow::finishZoomTo enter" << endl;
+#endif
+
+#if DEBUG_ZOOM_FLICKER
+{
+ kdDebug () << "FLICKER: inside finishZoomTo" << endl;
+ QTime timer; timer.start ();
+ while (timer.elapsed () < 2000)
+ ;
+}
+#endif
+
+ // TODO: setUpdatesEnabled() should really return to old value
+ // - not neccessarily "true"
+
+ if (m_mainView)
+ {
+ m_mainView->setUpdatesEnabled (true);
+ m_mainView->update ();
+ }
+
+#if DEBUG_ZOOM_FLICKER
+{
+ kdDebug () << "FLICKER: just updated mainView" << endl;
+ QTime timer; timer.start ();
+ while (timer.elapsed () < 1000)
+ ;
+}
+#endif
+
+ if (m_scrollView)
+ {
+ if (m_scrollView->viewport ())
+ {
+ m_scrollView->viewport ()->setUpdatesEnabled (true);
+ m_scrollView->viewport ()->update ();
+ }
+ #if DEBUG_ZOOM_FLICKER
+ {
+ kdDebug () << "FLICKER: just updated scrollView::viewport()" << endl;
+ QTime timer; timer.start ();
+ while (timer.elapsed () < 1000)
+ ;
+ }
+ #endif
+
+ m_scrollView->setUpdatesEnabled (true);
+ m_scrollView->update ();
+ #if DEBUG_ZOOM_FLICKER
+ {
+ kdDebug () << "FLICKER: just updated scrollView" << endl;
+ QTime timer; timer.start ();
+ while (timer.elapsed () < 1000)
+ ;
+ }
+ #endif
+
+ }
+
+
+ if (m_viewManager && m_viewManager->queueUpdates ()/*just in case*/)
+ m_viewManager->restoreQueueUpdates ();
+#if DEBUG_ZOOM_FLICKER
+{
+ kdDebug () << "FLICKER: restored vm queued updates" << endl;
+ QTime timer; timer.start ();
+ while (timer.elapsed () < 1000)
+ ;
+}
+#endif
+
+ setStatusBarZoom (m_mainView ? m_mainView->zoomLevelX () : 0);
+
+#if DEBUG_KP_MAIN_WINDOW && 1
+ kdDebug () << "\tkpMainWindow::finishZoomTo done" << endl;
+#endif
+
+#if DEBUG_ZOOM_FLICKER
+{
+ kdDebug () << "FLICKER: finishZoomTo done" << endl;
+ QTime timer; timer.start ();
+ while (timer.elapsed () < 1000)
+ ;
+}
+#endif
+}
+
+
+// private slot
+void kpMainWindow::slotActualSize ()
+{
+ zoomTo (100);
+}
+
+// private slot
+void kpMainWindow::slotFitToPage ()
+{
+ if (!m_scrollView || !m_document)
+ return;
+
+ // doc_width * zoom / 100 <= view_width &&
+ // doc_height * zoom / 100 <= view_height &&
+ // 1 <= zoom <= 3200
+
+ zoomTo (QMIN (3200, QMAX (1, QMIN (m_scrollView->visibleWidth () * 100 / m_document->width (),
+ m_scrollView->visibleHeight () * 100 / m_document->height ()))));
+}
+
+// private slot
+void kpMainWindow::slotFitToWidth ()
+{
+ if (!m_scrollView || !m_document)
+ return;
+
+ // doc_width * zoom / 100 <= view_width &&
+ // 1 <= zoom <= 3200
+
+ zoomTo (QMIN (3200, QMAX (1, m_scrollView->visibleWidth () * 100 / m_document->width ())));
+}
+
+// private slot
+void kpMainWindow::slotFitToHeight ()
+{
+ if (!m_scrollView || !m_document)
+ return;
+
+ // doc_height * zoom / 100 <= view_height &&
+ // 1 <= zoom <= 3200
+
+ zoomTo (QMIN (3200, QMAX (1, m_scrollView->visibleHeight () * 100 / m_document->height ())));
+}
+
+
+// public
+void kpMainWindow::zoomIn (bool centerUnderCursor)
+{
+ const int targetItem = m_actionZoom->currentItem () + 1;
+
+ if (targetItem >= (int) m_zoomList.count ())
+ return;
+
+ m_actionZoom->setCurrentItem (targetItem);
+ zoomAccordingToZoomAction (centerUnderCursor);
+}
+
+// public
+void kpMainWindow::zoomOut (bool centerUnderCursor)
+{
+ const int targetItem = m_actionZoom->currentItem () - 1;
+
+ if (targetItem < 0)
+ return;
+
+ m_actionZoom->setCurrentItem (targetItem);
+ zoomAccordingToZoomAction (centerUnderCursor);
+}
+
+
+// public slot
+void kpMainWindow::slotZoomIn ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotZoomIn ()" << endl;
+#endif
+
+ zoomIn (false/*don't center under cursor*/);
+}
+
+// public slot
+void kpMainWindow::slotZoomOut ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotZoomOut ()" << endl;
+#endif
+
+ zoomOut (false/*don't center under cursor*/);
+}
+
+
+// public
+void kpMainWindow::zoomAccordingToZoomAction (bool centerUnderCursor)
+{
+ zoomTo (zoomLevelFromString (m_actionZoom->currentText ()),
+ centerUnderCursor);
+}
+
+// private slot
+void kpMainWindow::slotZoom ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotZoom () index=" << m_actionZoom->currentItem ()
+ << " text='" << m_actionZoom->currentText () << "'" << endl;
+#endif
+ zoomAccordingToZoomAction (false/*don't center under cursor*/);
+}
+
+
+// private slot
+void kpMainWindow::slotShowGridToggled ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotActionShowGridToggled()" << endl;
+#endif
+
+ updateMainViewGrid ();
+
+
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupGeneral);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ cfg->writeEntry (kpSettingShowGrid, m_configShowGrid = m_actionShowGrid->isChecked ());
+ cfg->sync ();
+}
+
+// private
+void kpMainWindow::updateMainViewGrid ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::updateMainViewGrid ()" << endl;
+#endif
+
+ if (m_mainView)
+ m_mainView->showGrid (m_actionShowGrid->isChecked ());
+}
+
+
+// private
+QRect kpMainWindow::mapToGlobal (const QRect &rect) const
+{
+ return kpWidgetMapper::toGlobal (this, rect);
+}
+
+// private
+QRect kpMainWindow::mapFromGlobal (const QRect &rect) const
+{
+ return kpWidgetMapper::fromGlobal (this, rect);
+}
+
+
+// public slot
+void kpMainWindow::slotDestroyThumbnailIfNotVisible (bool tnIsVisible)
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotDestroyThumbnailIfNotVisible(isVisible="
+ << tnIsVisible
+ << ")"
+ << endl;
+#endif
+
+ if (!tnIsVisible)
+ {
+ slotDestroyThumbnailInitatedByUser ();
+ }
+}
+
+// private slot
+void kpMainWindow::slotDestroyThumbnail ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotDestroyThumbnail()" << endl;
+#endif
+
+ m_actionShowThumbnail->setChecked (false);
+ enableThumbnailOptionActions (false);
+ updateThumbnail ();
+}
+
+// private slot
+void kpMainWindow::slotDestroyThumbnailInitatedByUser ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotDestroyThumbnailInitiatedByUser()" << endl;
+#endif
+
+ m_actionShowThumbnail->setChecked (false);
+ slotShowThumbnailToggled ();
+}
+
+// private slot
+void kpMainWindow::slotCreateThumbnail ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotCreateThumbnail()" << endl;
+#endif
+
+ m_actionShowThumbnail->setChecked (true);
+ enableThumbnailOptionActions (true);
+ updateThumbnail ();
+}
+
+// public
+void kpMainWindow::notifyThumbnailGeometryChanged ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::notifyThumbnailGeometryChanged()" << endl;
+#endif
+
+ if (!m_thumbnailSaveConfigTimer)
+ {
+ m_thumbnailSaveConfigTimer = new QTimer (this);
+ connect (m_thumbnailSaveConfigTimer, SIGNAL (timeout ()),
+ this, SLOT (slotSaveThumbnailGeometry ()));
+ }
+
+ m_thumbnailSaveConfigTimer->start (500/*msec*/, true/*single shot*/);
+}
+
+// private slot
+void kpMainWindow::slotSaveThumbnailGeometry ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::saveThumbnailGeometry()" << endl;
+#endif
+
+ if (!m_thumbnail)
+ return;
+
+ QRect rect (m_thumbnail->x (), m_thumbnail->y (),
+ m_thumbnail->width (), m_thumbnail->height ());
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tthumbnail relative geometry=" << rect << endl;
+#endif
+
+ m_configThumbnailGeometry = mapFromGlobal (rect);
+
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tCONFIG: saving thumbnail geometry "
+ << m_configThumbnailGeometry
+ << endl;
+#endif
+
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupThumbnail);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ cfg->writeEntry (kpSettingThumbnailGeometry, m_configThumbnailGeometry);
+ cfg->sync ();
+}
+
+// private slot
+void kpMainWindow::slotShowThumbnailToggled ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotShowThumbnailToggled()" << endl;
+#endif
+
+ m_configThumbnailShown = m_actionShowThumbnail->isChecked ();
+
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupThumbnail);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ cfg->writeEntry (kpSettingThumbnailShown, m_configThumbnailShown);
+ cfg->sync ();
+
+
+ enableThumbnailOptionActions (m_actionShowThumbnail->isChecked ());
+ updateThumbnail ();
+}
+
+// private slot
+void kpMainWindow::updateThumbnailZoomed ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::updateThumbnailZoomed() zoomed="
+ << m_actionZoomedThumbnail->isChecked () << endl;
+#endif
+
+ if (!m_thumbnailView)
+ return;
+
+ destroyThumbnailView ();
+ createThumbnailView ();
+}
+
+// private slot
+void kpMainWindow::slotZoomedThumbnailToggled ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotZoomedThumbnailToggled()" << endl;
+#endif
+
+ m_configZoomedThumbnail = m_actionZoomedThumbnail->isChecked ();
+
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupThumbnail);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ cfg->writeEntry (kpSettingThumbnailZoomed, m_configZoomedThumbnail);
+ cfg->sync ();
+
+
+ updateThumbnailZoomed ();
+}
+
+// private slot
+void kpMainWindow::slotThumbnailShowRectangleToggled ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::slotThumbnailShowRectangleToggled()" << endl;
+#endif
+
+ d->m_configThumbnailShowRectangle = d->m_actionShowThumbnailRectangle->isChecked ();
+
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupThumbnail);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ cfg->writeEntry (kpSettingThumbnailShowRectangle, d->m_configThumbnailShowRectangle);
+ cfg->sync ();
+
+
+ if (m_thumbnailView)
+ {
+ m_thumbnailView->showBuddyViewScrollableContainerRectangle (
+ d->m_actionShowThumbnailRectangle->isChecked ());
+ }
+}
+
+// private
+void kpMainWindow::enableViewZoomedThumbnail (bool enable)
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::enableSettingsViewZoomedThumbnail()" << endl;
+#endif
+
+ m_actionZoomedThumbnail->setEnabled (enable &&
+ m_actionShowThumbnail->isChecked ());
+
+ // Note: Don't uncheck if disabled - being able to see the zoomed state
+ // before turning on the thumbnail can be useful.
+ m_actionZoomedThumbnail->setChecked (m_configZoomedThumbnail);
+}
+
+// private
+void kpMainWindow::enableViewShowThumbnailRectangle (bool enable)
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::enableViewShowThumbnailRectangle()" << endl;
+#endif
+
+ d->m_actionShowThumbnailRectangle->setEnabled (enable &&
+ m_actionShowThumbnail->isChecked ());
+
+ // Note: Don't uncheck if disabled for consistency with
+ // enableViewZoomedThumbnail()
+ d->m_actionShowThumbnailRectangle->setChecked (
+ d->m_configThumbnailShowRectangle);
+}
+
+// private
+void kpMainWindow::enableThumbnailOptionActions (bool enable)
+{
+ enableViewZoomedThumbnail (enable);
+ enableViewShowThumbnailRectangle (enable);
+}
+
+
+// private
+void kpMainWindow::createThumbnailView ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t\tcreating new kpView:" << endl;
+#endif
+
+ if (m_thumbnailView)
+ {
+ kdDebug () << "kpMainWindow::createThumbnailView() had to destroy view" << endl;
+ destroyThumbnailView ();
+ }
+
+ if (m_actionZoomedThumbnail->isChecked ())
+ {
+ m_thumbnailView = new kpZoomedThumbnailView (
+ m_document, m_toolToolBar, m_viewManager,
+ m_mainView,
+ 0/*scrollableContainer*/,
+ m_thumbnail, "thumbnailView");
+ }
+ else
+ {
+ m_thumbnailView = new kpUnzoomedThumbnailView (
+ m_document, m_toolToolBar, m_viewManager,
+ m_mainView,
+ 0/*scrollableContainer*/,
+ m_thumbnail, "thumbnailView");
+
+ }
+
+ m_thumbnailView->showBuddyViewScrollableContainerRectangle (
+ d->m_actionShowThumbnailRectangle->isChecked ());
+
+
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t\tgive kpThumbnail the kpView:" << endl;
+#endif
+ if (m_thumbnail)
+ m_thumbnail->setView (m_thumbnailView);
+ else
+ kdError () << "kpMainWindow::createThumbnailView() no thumbnail" << endl;
+
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t\tregistering the kpView:" << endl;
+#endif
+ if (m_viewManager)
+ m_viewManager->registerView (m_thumbnailView);
+}
+
+// private
+void kpMainWindow::destroyThumbnailView ()
+{
+ if (!m_thumbnailView)
+ return;
+
+ if (m_viewManager)
+ m_viewManager->unregisterView (m_thumbnailView);
+
+ if (m_thumbnail)
+ m_thumbnail->setView (0);
+
+ m_thumbnailView->deleteLater (); m_thumbnailView = 0;
+}
+
+
+// private
+void kpMainWindow::updateThumbnail ()
+{
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "kpMainWindow::updateThumbnail()" << endl;
+#endif
+ bool enable = m_actionShowThumbnail->isChecked ();
+
+#if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tthumbnail="
+ << bool (m_thumbnail)
+ << " action_isChecked="
+ << enable
+ << endl;
+#endif
+
+ if (bool (m_thumbnail) == enable)
+ return;
+
+ if (!m_thumbnail)
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tcreating thumbnail" << endl;
+ #endif
+
+ // Read last saved geometry before creating thumbnail & friends
+ // in case they call notifyThumbnailGeometryChanged()
+ QRect thumbnailGeometry = m_configThumbnailGeometry;
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t\tlast used geometry=" << thumbnailGeometry << endl;
+ #endif
+
+ m_thumbnail = new kpThumbnail (this, "thumbnail");
+
+ createThumbnailView ();
+
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t\tmoving thumbnail to right place" << endl;
+ #endif
+ if (!thumbnailGeometry.isEmpty () &&
+ QRect (0, 0, width (), height ()).intersects (thumbnailGeometry))
+ {
+ const QRect geometry = mapToGlobal (thumbnailGeometry);
+ m_thumbnail->resize (geometry.size ());
+ m_thumbnail->move (geometry.topLeft ());
+ }
+ else
+ {
+ if (m_scrollView)
+ {
+ const int margin = 20;
+ const int initialWidth = 160, initialHeight = 120;
+
+ QRect geometryRect (width () - initialWidth - margin * 2,
+ m_scrollView->y () + margin,
+ initialWidth,
+ initialHeight);
+
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t\tcreating geometry=" << geometryRect << endl;
+ #endif
+
+ geometryRect = mapToGlobal (geometryRect);
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t\tmap to global=" << geometryRect << endl;
+ #endif
+ m_thumbnail->resize (geometryRect.size ());
+ m_thumbnail->move (geometryRect.topLeft ());
+ }
+ }
+
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t\tshowing thumbnail" << endl;
+ #endif
+ m_thumbnail->show ();
+
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t\tconnecting thumbnail::visibilityChange to destroy slot" << endl;
+ #endif
+ connect (m_thumbnail, SIGNAL (visibilityChanged (bool)),
+ this, SLOT (slotDestroyThumbnailIfNotVisible (bool)));
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\t\tDONE" << endl;
+ #endif
+ }
+ else
+ {
+ #if DEBUG_KP_MAIN_WINDOW
+ kdDebug () << "\tdestroying thumbnail" << endl;
+ #endif
+
+ if (m_thumbnailSaveConfigTimer && m_thumbnailSaveConfigTimer->isActive ())
+ {
+ m_thumbnailSaveConfigTimer->stop ();
+ slotSaveThumbnailGeometry ();
+ }
+
+
+ destroyThumbnailView ();
+
+
+ disconnect (m_thumbnail, SIGNAL (visibilityChanged (bool)),
+ this, SLOT (slotDestroyThumbnailIfNotVisible (bool)));
+
+ m_thumbnail->deleteLater (); m_thumbnail = 0;
+ }
+}
diff --git a/kolourpaint/kpselection.cpp b/kolourpaint/kpselection.cpp
new file mode 100644
index 00000000..eb5924cf
--- /dev/null
+++ b/kolourpaint/kpselection.cpp
@@ -0,0 +1,1446 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_SELECTION 0
+
+
+#include <kpselection.h>
+
+#include <qfont.h>
+#include <qimage.h>
+#include <qpainter.h>
+#include <qwmatrix.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcolorsimilaritydialog.h>
+#include <kpdefs.h>
+#include <kppixmapfx.h>
+#include <kptool.h>
+
+
+kpSelection::kpSelection (const kpSelectionTransparency &transparency)
+ : QObject (),
+ m_type (kpSelection::Rectangle),
+ m_pixmap (0)
+{
+ setTransparency (transparency);
+}
+
+kpSelection::kpSelection (Type type, const QRect &rect, const QPixmap &pixmap,
+ const kpSelectionTransparency &transparency)
+ : QObject (),
+ m_type (type),
+ m_rect (rect)
+{
+ calculatePoints ();
+ m_pixmap = pixmap.isNull () ? 0 : new QPixmap (pixmap);
+
+ setTransparency (transparency);
+}
+
+kpSelection::kpSelection (Type type, const QRect &rect, const kpSelectionTransparency &transparency)
+ : QObject (),
+ m_type (type),
+ m_rect (rect),
+ m_pixmap (0)
+{
+ calculatePoints ();
+
+ setTransparency (transparency);
+}
+
+kpSelection::kpSelection (const QRect &rect,
+ const QValueVector <QString> &textLines_,
+ const kpTextStyle &textStyle_)
+ : QObject (),
+ m_type (Text),
+ m_rect (rect),
+ m_pixmap (0),
+ m_textStyle (textStyle_)
+{
+ calculatePoints ();
+
+ setTextLines (textLines_);
+}
+
+kpSelection::kpSelection (const QPointArray &points, const QPixmap &pixmap,
+ const kpSelectionTransparency &transparency)
+ : QObject (),
+ m_type (Points),
+ m_rect (points.boundingRect ()),
+ m_points (points)
+{
+ m_pixmap = pixmap.isNull () ? 0 : new QPixmap (pixmap);
+ m_points.detach ();
+
+ setTransparency (transparency);
+}
+
+kpSelection::kpSelection (const QPointArray &points, const kpSelectionTransparency &transparency)
+ : QObject (),
+ m_type (Points),
+ m_rect (points.boundingRect ()),
+ m_points (points),
+ m_pixmap (0)
+{
+ m_points.detach ();
+
+ setTransparency (transparency);
+}
+
+kpSelection::kpSelection (const kpSelection &rhs)
+ : QObject (),
+ m_type (rhs.m_type),
+ m_rect (rhs.m_rect),
+ m_points (rhs.m_points),
+ m_pixmap (rhs.m_pixmap ? new QPixmap (*rhs.m_pixmap) : 0),
+ m_textLines (rhs.m_textLines),
+ m_textStyle (rhs.m_textStyle),
+ m_transparency (rhs.m_transparency),
+ m_transparencyMask (rhs.m_transparencyMask)
+{
+ m_points.detach ();
+}
+
+kpSelection &kpSelection::operator= (const kpSelection &rhs)
+{
+ if (this == &rhs)
+ return *this;
+
+ m_type = rhs.m_type;
+ m_rect = rhs.m_rect;
+ m_points = rhs.m_points;
+ m_points.detach ();
+
+ delete m_pixmap;
+ m_pixmap = rhs.m_pixmap ? new QPixmap (*rhs.m_pixmap) : 0;
+
+ m_textLines = rhs.m_textLines;
+ m_textStyle = rhs.m_textStyle;
+
+ m_transparency = rhs.m_transparency;
+ m_transparencyMask = rhs.m_transparencyMask;
+
+ return *this;
+}
+
+
+// friend
+QDataStream &operator<< (QDataStream &stream, const kpSelection &selection)
+{
+#if DEBUG_KP_SELECTION && 1
+ kdDebug () << "kpSelection::operator<<(sel: rect=" << selection.boundingRect ()
+ << " pixmap rect=" << (selection.pixmap () ? selection.pixmap ()->rect () : QRect ())
+ << endl;
+#endif
+ stream << int (selection.m_type);
+ stream << selection.m_rect;
+ stream << selection.m_points;
+#if DEBUG_KP_SELECTION && 1
+ kdDebug () << "\twrote type=" << int (selection.m_type) << " rect=" << selection.m_rect
+ << " and points" << endl;
+#endif
+
+ // TODO: need for text?
+ // For now we just use QTextDrag for Text Selections so this point is mute.
+ if (selection.m_pixmap)
+ {
+ const QImage image = kpPixmapFX::convertToImage (*selection.m_pixmap);
+ #if DEBUG_KP_SELECTION && 1
+ kdDebug () << "\twrote image rect=" << image.rect () << endl;
+ #endif
+ stream << image;
+ }
+ else
+ {
+ #if DEBUG_KP_SELECTION && 1
+ kdDebug () << "\twrote no image because no pixmap" << endl;
+ #endif
+ stream << QImage ();
+ }
+
+ //stream << selection.m_textLines;
+ //stream << selection.m_textStyle;
+
+ return stream;
+}
+
+// friend
+QDataStream &operator>> (QDataStream &stream, kpSelection &selection)
+{
+ selection.readFromStream (stream);
+ return stream;
+}
+
+// public
+// TODO: KolourPaint has not been tested against invalid or malicious
+// clipboard data [Bug #28].
+void kpSelection::readFromStream (QDataStream &stream,
+ const kpPixmapFX::WarnAboutLossInfo &wali)
+{
+#if DEBUG_KP_SELECTION && 1
+ kdDebug () << "kpSelection::readFromStream()" << endl;
+#endif
+ int typeAsInt;
+ stream >> typeAsInt;
+ m_type = kpSelection::Type (typeAsInt);
+#if DEBUG_KP_SELECTION && 1
+ kdDebug () << "\ttype=" << typeAsInt << endl;
+#endif
+
+ stream >> m_rect;
+ stream >> m_points;
+ m_points.detach ();
+#if DEBUG_KP_SELECTION && 1
+ kdDebug () << "\trect=" << m_rect << endl;
+ //kdDebug () << "\tpoints=" << m_points << endl;
+#endif
+
+ QImage image;
+ stream >> image;
+ delete m_pixmap;
+ if (!image.isNull ())
+ m_pixmap = new QPixmap (kpPixmapFX::convertToPixmap (image, false/*no dither*/, wali));
+ else
+ m_pixmap = 0;
+#if DEBUG_KP_SELECTION && 1
+ kdDebug () << "\timage: w=" << image.width () << " h=" << image.height ()
+ << " depth=" << image.depth () << endl;
+ if (m_pixmap)
+ {
+ kdDebug () << "\tpixmap: w=" << m_pixmap->width () << " h=" << m_pixmap->height ()
+ << endl;
+ }
+ else
+ {
+ kdDebug () << "\tpixmap: none" << endl;
+ }
+#endif
+
+ //stream >> m_textLines;
+ //stream >> m_textStyle;
+}
+
+kpSelection::~kpSelection ()
+{
+ delete m_pixmap; m_pixmap = 0;
+}
+
+
+// private
+void kpSelection::calculatePoints ()
+{
+ if (m_type == kpSelection::Points)
+ return;
+
+ if (m_type == kpSelection::Ellipse)
+ {
+ m_points.makeEllipse (m_rect.x (), m_rect.y (),
+ m_rect.width (), m_rect.height ());
+ return;
+ }
+
+ if (m_type == kpSelection::Rectangle || m_type == kpSelection::Text)
+ {
+ // OPT: not space optimal - redoes corners
+ m_points.resize (m_rect.width () * 2 + m_rect.height () * 2);
+
+ int pointsUpto = 0;
+
+ // top
+ for (int x = 0; x < m_rect.width (); x++)
+ m_points [pointsUpto++] = QPoint (m_rect.x () + x, m_rect.top ());
+
+ // right
+ for (int y = 0; y < m_rect.height (); y++)
+ m_points [pointsUpto++] = QPoint (m_rect.right (), m_rect.y () + y);
+
+ // bottom
+ for (int x = m_rect.width () - 1; x >= 0; x--)
+ m_points [pointsUpto++] = QPoint (m_rect.x () + x, m_rect.bottom ());
+
+ // left
+ for (int y = m_rect.height () - 1; y >= 0; y--)
+ m_points [pointsUpto++] = QPoint (m_rect.left (), m_rect.y () + y);
+
+ return;
+ }
+
+ kdError () << "kpSelection::calculatePoints() with unknown type" << endl;
+ return;
+}
+
+
+// public
+kpSelection::Type kpSelection::type () const
+{
+ return m_type;
+}
+
+// public
+bool kpSelection::isRectangular () const
+{
+ return (m_type == Rectangle || m_type == Text);
+}
+
+// public
+bool kpSelection::isText () const
+{
+ return (m_type == Text);
+}
+
+// public
+QString kpSelection::name () const
+{
+ if (m_type == Text)
+ return i18n ("Text");
+
+ return i18n ("Selection");
+}
+
+
+// public
+int kpSelection::size () const
+{
+ return kpPixmapFX::pointArraySize (m_points) +
+ kpPixmapFX::pixmapSize (m_pixmap) +
+ kpPixmapFX::stringSize (text ()) +
+ kpPixmapFX::pixmapSize (m_transparencyMask);
+}
+
+
+// public
+QBitmap kpSelection::maskForOwnType (bool nullForRectangular) const
+{
+ if (!m_rect.isValid ())
+ {
+ kdError () << "kpSelection::maskForOwnType() boundingRect invalid" << endl;
+ return QBitmap ();
+ }
+
+
+ if (isRectangular ())
+ {
+ if (nullForRectangular)
+ return QBitmap ();
+
+ QBitmap maskBitmap (m_rect.width (), m_rect.height ());
+ maskBitmap.fill (Qt::color1/*opaque*/);
+ return maskBitmap;
+ }
+
+
+ QBitmap maskBitmap (m_rect.width (), m_rect.height ());
+ maskBitmap.fill (Qt::color0/*transparent*/);
+
+ QPainter painter;
+ painter.begin (&maskBitmap);
+ painter.setPen (Qt::color1)/*opaque*/;
+ painter.setBrush (Qt::color1/*opaque*/);
+
+ if (m_type == kpSelection::Ellipse)
+ painter.drawEllipse (0, 0, m_rect.width (), m_rect.height ());
+ else if (m_type == kpSelection::Points)
+ {
+ QPointArray points = m_points;
+ points.detach ();
+ points.translate (-m_rect.x (), -m_rect.y ());
+
+ painter.drawPolygon (points, false/*even-odd algo*/);
+ }
+
+ painter.end ();
+
+
+ return maskBitmap;
+}
+
+
+// public
+QPoint kpSelection::topLeft () const
+{
+ return m_rect.topLeft ();
+}
+
+// public
+QPoint kpSelection::point () const
+{
+ return m_rect.topLeft ();
+}
+
+
+// public
+int kpSelection::x () const
+{
+ return m_rect.x ();
+}
+
+// public
+int kpSelection::y () const
+{
+ return m_rect.y ();
+}
+
+
+// public
+void kpSelection::moveBy (int dx, int dy)
+{
+#if DEBUG_KP_SELECTION && 1
+ kdDebug () << "kpSelection::moveBy(" << dx << "," << dy << ")" << endl;
+#endif
+
+ if (dx == 0 && dy == 0)
+ return;
+
+ QRect oldRect = boundingRect ();
+
+#if DEBUG_KP_SELECTION && 1
+ kdDebug () << "\toldRect=" << oldRect << endl;
+#endif
+
+ m_rect.moveBy (dx, dy);
+ m_points.translate (dx, dy);
+#if DEBUG_KP_SELECTION && 1
+ kdDebug () << "\tnewRect=" << m_rect << endl;
+#endif
+
+ emit changed (oldRect);
+ emit changed (boundingRect ());
+}
+
+// public
+void kpSelection::moveTo (int dx, int dy)
+{
+ moveTo (QPoint (dx, dy));
+}
+
+// public
+void kpSelection::moveTo (const QPoint &topLeftPoint)
+{
+#if DEBUG_KP_SELECTION && 1
+ kdDebug () << "kpSelection::moveTo(" << topLeftPoint << ")" << endl;
+#endif
+ QRect oldBoundingRect = boundingRect ();
+#if DEBUG_KP_SELECTION && 1
+ kdDebug () << "\toldBoundingRect=" << oldBoundingRect << endl;
+#endif
+ if (topLeftPoint == oldBoundingRect.topLeft ())
+ return;
+
+ QPoint delta (topLeftPoint - oldBoundingRect.topLeft ());
+ moveBy (delta.x (), delta.y ());
+}
+
+
+// public
+QPointArray kpSelection::points () const
+{
+ return m_points;
+}
+
+// public
+QPointArray kpSelection::pointArray () const
+{
+ return m_points;
+}
+
+// public
+QRect kpSelection::boundingRect () const
+{
+ return m_rect;
+}
+
+// public
+int kpSelection::width () const
+{
+ return boundingRect ().width ();
+}
+
+// public
+int kpSelection::height () const
+{
+ return boundingRect ().height ();
+}
+
+// public
+bool kpSelection::contains (const QPoint &point) const
+{
+ QRect rect = boundingRect ();
+
+#if DEBUG_KP_SELECTION && 1
+ kdDebug () << "kpSelection::contains(" << point
+ << ") rect==" << rect
+ << " #points=" << m_points.size ()
+ << endl;
+#endif
+
+ if (!rect.contains (point))
+ return false;
+
+ // OPT: QRegion is probably incredibly slow - cache
+ // We can't use the m_pixmap (if avail) and get the transparency of
+ // the pixel at that point as it may be transparent but still within the
+ // border
+ switch (m_type)
+ {
+ case kpSelection::Rectangle:
+ case kpSelection::Text:
+ return true;
+ case kpSelection::Ellipse:
+ return QRegion (m_rect, QRegion::Ellipse).contains (point);
+ case kpSelection::Points:
+ // TODO: make this always include the border
+ // (draw up a rect sel in this mode to see what I mean)
+ return QRegion (m_points, false/*even-odd algo*/).contains (point);
+ default:
+ return false;
+ }
+}
+
+// public
+bool kpSelection::contains (int x, int y)
+{
+ return contains (QPoint (x, y));
+}
+
+
+// public
+QPixmap *kpSelection::pixmap () const
+{
+ return m_pixmap;
+}
+
+// public
+void kpSelection::setPixmap (const QPixmap &pixmap)
+{
+ delete m_pixmap;
+ // TODO: If isText(), setting pixmap() to 0 is unexpected (implies
+ // it's a border, not a text box) but saves memory when using
+ // that kpSelection::setPixmap (QPixmap ()) hack.
+ m_pixmap = pixmap.isNull () ? 0 : new QPixmap (pixmap);
+ QRect changedRect = boundingRect ();
+
+ if (m_pixmap)
+ {
+ const bool changedSize = (m_pixmap->width () != m_rect.width () ||
+ m_pixmap->height () != m_rect.height ());
+ const bool changedFromText = (m_type == Text);
+ if (changedSize || changedFromText)
+ {
+ if (changedSize)
+ {
+ kdError () << "kpSelection::setPixmap() changes the size of the selection!"
+ << " old:"
+ << " w=" << m_rect.width ()
+ << " h=" << m_rect.height ()
+ << " new:"
+ << " w=" << m_pixmap->width ()
+ << " h=" << m_pixmap->height ()
+ << endl;
+ }
+
+ if (changedFromText)
+ {
+ kdError () << "kpSelection::setPixmap() changed from text" << endl;
+ }
+
+ m_type = kpSelection::Rectangle;
+ m_rect = QRect (m_rect.x (), m_rect.y (),
+ m_pixmap->width (), m_pixmap->height ());
+ calculatePoints ();
+
+ m_textLines = QValueVector <QString> ();
+
+ changedRect = changedRect.unite (boundingRect ());
+ }
+ }
+
+ calculateTransparencyMask ();
+
+ emit changed (changedRect);
+}
+
+
+// public
+bool kpSelection::usesBackgroundPixmapToPaint () const
+{
+ // Opaque text with transparent background needs to antialias with
+ // doc pixmap below it.
+ return (isText () &&
+ m_textStyle.foregroundColor ().isOpaque () &&
+ m_textStyle.effectiveBackgroundColor ().isTransparent ());
+}
+
+static int mostContrastingValue (int val)
+{
+ if (val <= 127)
+ return 255;
+ else
+ return 0;
+}
+
+static QRgb mostContrastingRGB (QRgb val)
+{
+ return qRgba (mostContrastingValue (qRed (val)),
+ mostContrastingValue (qGreen (val)),
+ mostContrastingValue (qBlue (val)),
+ mostContrastingValue (qAlpha (val)));
+}
+
+// private
+static void drawTextLines (QPainter *painter, QPainter *maskPainter,
+ const QRect &rect,
+ const QValueVector <QString> &textLines)
+{
+ if (!painter->clipRegion ().isEmpty () || !maskPainter->clipRegion ().isEmpty ())
+ {
+ // TODO: fix esp. before making method public
+ kdError () << "kpselection.cpp:drawTextLines() can't deal with existing painter clip regions" << endl;
+ return;
+ }
+
+
+#define PAINTER_CALL(cmd) \
+{ \
+ if (painter->isActive ()) \
+ painter->cmd; \
+ \
+ if (maskPainter->isActive ()) \
+ maskPainter->cmd; \
+}
+
+
+ // Can't do this because the line heights become
+ // >QFontMetrics::height() if you type Chinese characters (!) and then
+ // the cursor gets out of sync.
+ // PAINTER_CALL (drawText (rect, 0/*flags*/, text ()));
+
+
+#if 0
+ const QFontMetrics fontMetrics (painter->fontMetrics ());
+
+ kdDebug () << "height=" << fontMetrics.height ()
+ << " leading=" << fontMetrics.leading ()
+ << " ascent=" << fontMetrics.ascent ()
+ << " descent=" << fontMetrics.descent ()
+ << " lineSpacing=" << fontMetrics.lineSpacing ()
+ << endl;
+#endif
+
+
+ PAINTER_CALL (setClipRect (rect, QPainter::CoordPainter/*transform*/));
+
+ int baseLine = rect.y () + painter->fontMetrics ().ascent ();
+ for (QValueVector <QString>::const_iterator it = textLines.begin ();
+ it != textLines.end ();
+ it++)
+ {
+ PAINTER_CALL (drawText (rect.x (), baseLine, *it));
+ baseLine += painter->fontMetrics ().lineSpacing ();
+ }
+
+
+#undef PAINTER_CALL
+}
+
+// private
+void kpSelection::paintOpaqueText (QPixmap *destPixmap, const QRect &docRect) const
+{
+ if (!isText () || !m_textStyle.foregroundColor ().isOpaque ())
+ return;
+
+
+ const QRect modifyingRect = docRect.intersect (boundingRect ());
+ if (modifyingRect.isEmpty ())
+ return;
+
+
+ QBitmap destPixmapMask;
+ QPainter destPixmapPainter, destPixmapMaskPainter;
+
+ if (destPixmap->mask ())
+ {
+ if (m_textStyle.effectiveBackgroundColor ().isTransparent ())
+ {
+ QRect modifyingRectRelPixmap = modifyingRect;
+ modifyingRectRelPixmap.moveBy (-docRect.x (), -docRect.y ());
+
+ // Set the RGB of transparent pixels to foreground colour to avoid
+ // anti-aliasing the foreground coloured text with undefined RGBs.
+ kpPixmapFX::setPixmapAt (destPixmap,
+ modifyingRectRelPixmap,
+ kpPixmapFX::pixmapWithDefinedTransparentPixels (
+ kpPixmapFX::getPixmapAt (*destPixmap, modifyingRectRelPixmap),
+ m_textStyle.foregroundColor ().toQColor ()));
+ }
+
+ destPixmapMask = *destPixmap->mask ();
+ destPixmapMaskPainter.begin (&destPixmapMask);
+ destPixmapMaskPainter.translate (-docRect.x (), -docRect.y ());
+ destPixmapMaskPainter.setPen (Qt::color1/*opaque*/);
+ destPixmapMaskPainter.setFont (m_textStyle.font ());
+ }
+
+ destPixmapPainter.begin (destPixmap);
+ destPixmapPainter.translate (-docRect.x (), -docRect.y ());
+ destPixmapPainter.setPen (m_textStyle.foregroundColor ().toQColor ());
+ destPixmapPainter.setFont (m_textStyle.font ());
+
+
+ if (m_textStyle.effectiveBackgroundColor ().isOpaque ())
+ {
+ destPixmapPainter.fillRect (
+ boundingRect (),
+ m_textStyle.effectiveBackgroundColor ().toQColor ());
+
+ if (destPixmapMaskPainter.isActive ())
+ {
+ destPixmapMaskPainter.fillRect (
+ boundingRect (),
+ Qt::color1/*opaque*/);
+ }
+ }
+
+
+ ::drawTextLines (&destPixmapPainter, &destPixmapMaskPainter,
+ textAreaRect (),
+ textLines ());
+
+
+ if (destPixmapPainter.isActive ())
+ destPixmapPainter.end ();
+
+ if (destPixmapMaskPainter.isActive ())
+ destPixmapMaskPainter.end ();
+
+
+ if (!destPixmapMask.isNull ())
+ destPixmap->setMask (destPixmapMask);
+}
+
+// private
+QPixmap kpSelection::transparentForegroundTextPixmap () const
+{
+ if (!isText () || !m_textStyle.foregroundColor ().isTransparent ())
+ return QPixmap ();
+
+
+ QPixmap pixmap (m_rect.width (), m_rect.height ());
+ QBitmap pixmapMask (m_rect.width (), m_rect.height ());
+
+
+ // Iron out stupid case first
+ if (m_textStyle.effectiveBackgroundColor ().isTransparent ())
+ {
+ pixmapMask.fill (Qt::color0/*transparent*/);
+ pixmap.setMask (pixmapMask);
+ return pixmap;
+ }
+
+
+ // -- Foreground transparent, background opaque --
+
+
+ QFont font = m_textStyle.font ();
+ // TODO: why doesn't "font.setStyleStrategy (QFont::NoAntialias);"
+ // let us avoid the hack below?
+
+
+ QPainter pixmapPainter, pixmapMaskPainter;
+
+ pixmap.fill (m_textStyle.effectiveBackgroundColor ().toQColor ());
+ pixmapPainter.begin (&pixmap);
+ // HACK: Transparent foreground colour + antialiased fonts don't
+ // work - they don't seem to be able to draw in
+ // Qt::color0/*transparent*/ (but Qt::color1 seems Ok).
+ // So we draw in a contrasting color to the background so that
+ // we can identify the transparent pixels for manually creating
+ // the mask.
+ pixmapPainter.setPen (
+ QColor (mostContrastingRGB (m_textStyle.effectiveBackgroundColor ().toQRgb () & RGB_MASK)));
+ pixmapPainter.setFont (font);
+
+
+ pixmapMask.fill (Qt::color1/*opaque*/);
+ pixmapMaskPainter.begin (&pixmapMask);
+ pixmapMaskPainter.setPen (Qt::color0/*transparent*/);
+ pixmapMaskPainter.setFont (font);
+
+
+ QRect rect (textAreaRect ());
+ rect.moveBy (-m_rect.x (), -m_rect.y ());
+ ::drawTextLines (&pixmapPainter, &pixmapMaskPainter,
+ rect,
+ textLines ());
+
+
+ if (pixmapPainter.isActive ())
+ pixmapPainter.end ();
+
+ if (pixmapMaskPainter.isActive ())
+ pixmapMaskPainter.end ();
+
+
+#if DEBUG_KP_SELECTION
+ kdDebug () << "\tinvoking foreground transparency hack" << endl;
+#endif
+ QImage image = kpPixmapFX::convertToImage (pixmap);
+ QRgb backgroundRGB = image.pixel (0, 0); // on textBorderSize()
+
+ pixmapMaskPainter.begin (&pixmapMask);
+ for (int y = 0; y < image.height (); y++)
+ {
+ for (int x = 0; x < image.width (); x++)
+ {
+ if (image.pixel (x, y) == backgroundRGB)
+ pixmapMaskPainter.setPen (Qt::color1/*opaque*/);
+ else
+ pixmapMaskPainter.setPen (Qt::color0/*transparent*/);
+
+ pixmapMaskPainter.drawPoint (x, y);
+ }
+ }
+ pixmapMaskPainter.end ();
+
+
+ if (!pixmapMask.isNull ())
+ pixmap.setMask (pixmapMask);
+
+
+ return pixmap;
+}
+
+// public
+void kpSelection::paint (QPixmap *destPixmap, const QRect &docRect) const
+{
+ if (!isText ())
+ {
+ if (pixmap () && !pixmap ()->isNull ())
+ {
+ kpPixmapFX::paintPixmapAt (destPixmap,
+ topLeft () - docRect.topLeft (),
+ transparentPixmap ());
+ }
+ }
+ else
+ {
+ #if DEBUG_KP_SELECTION
+ kdDebug () << "kpSelection::paint() textStyle: fcol="
+ << (int *) m_textStyle.foregroundColor ().toQRgb ()
+ << " bcol="
+ << (int *) m_textStyle.effectiveBackgroundColor ().toQRgb ()
+ << endl;
+ #endif
+
+ if (m_textStyle.foregroundColor ().isOpaque ())
+ {
+ // (may have to antialias with background so don't use m_pixmap)
+ paintOpaqueText (destPixmap, docRect);
+ }
+ else
+ {
+ if (!m_pixmap)
+ {
+ kdError () << "kpSelection::paint() without m_pixmap?" << endl;
+ return;
+ }
+
+ // (transparent foreground slow to render, no antialiasing
+ // so use m_pixmap cache)
+ kpPixmapFX::paintPixmapAt (destPixmap,
+ topLeft () - docRect.topLeft (),
+ *m_pixmap);
+ }
+ }
+}
+
+// private
+void kpSelection::calculateTextPixmap ()
+{
+ if (!isText ())
+ {
+ kdError () << "kpSelection::calculateTextPixmap() not text sel"
+ << endl;
+ return;
+ }
+
+ delete m_pixmap;
+
+ if (m_textStyle.foregroundColor().isOpaque ())
+ {
+ m_pixmap = new QPixmap (m_rect.width (), m_rect.height ());
+
+ if (usesBackgroundPixmapToPaint ())
+ kpPixmapFX::fill (m_pixmap, kpColor::transparent);
+
+ paintOpaqueText (m_pixmap, m_rect);
+ }
+ else
+ {
+ m_pixmap = new QPixmap (transparentForegroundTextPixmap ());
+ }
+}
+
+
+// public static
+QString kpSelection::textForTextLines (const QValueVector <QString> &textLines_)
+{
+ if (textLines_.isEmpty ())
+ return QString::null;
+
+ QString bigString = textLines_ [0];
+
+ for (QValueVector <QString>::const_iterator it = textLines_.begin () + 1;
+ it != textLines_.end ();
+ it++)
+ {
+ bigString += QString::fromLatin1 ("\n");
+ bigString += (*it);
+ }
+
+ return bigString;
+}
+
+// public
+QString kpSelection::text () const
+{
+ if (!isText ())
+ {
+ return QString::null;
+ }
+
+ return textForTextLines (m_textLines);
+}
+
+// public
+QValueVector <QString> kpSelection::textLines () const
+{
+ if (!isText ())
+ {
+ kdError () << "kpSelection::textLines() not a text selection" << endl;
+ return QValueVector <QString> ();
+ }
+
+ return m_textLines;
+}
+
+// public
+void kpSelection::setTextLines (const QValueVector <QString> &textLines_)
+{
+ if (!isText ())
+ {
+ kdError () << "kpSelection::setTextLines() not a text selection" << endl;
+ return;
+ }
+
+ m_textLines = textLines_;
+ if (m_textLines.isEmpty ())
+ {
+ kdError () << "kpSelection::setTextLines() passed no lines" << endl;
+ m_textLines.push_back (QString::null);
+ }
+ calculateTextPixmap ();
+ emit changed (boundingRect ());
+}
+
+// public static
+int kpSelection::textBorderSize ()
+{
+ return 1;
+}
+
+// public
+QRect kpSelection::textAreaRect () const
+{
+ if (!isText ())
+ {
+ kdError () << "kpSelection::textAreaRect() not a text selection" << endl;
+ return QRect ();
+ }
+
+ return QRect (m_rect.x () + textBorderSize (),
+ m_rect.y () + textBorderSize (),
+ m_rect.width () - textBorderSize () * 2,
+ m_rect.height () - textBorderSize () * 2);
+}
+
+// public
+bool kpSelection::pointIsInTextBorderArea (const QPoint &globalPoint) const
+{
+ if (!isText ())
+ {
+ kdError () << "kpSelection::pointIsInTextBorderArea() not a text selection" << endl;
+ return false;
+ }
+
+ return (m_rect.contains (globalPoint) && !pointIsInTextArea (globalPoint));
+}
+
+// public
+bool kpSelection::pointIsInTextArea (const QPoint &globalPoint) const
+{
+ if (!isText ())
+ {
+ kdError () << "kpSelection::pointIsInTextArea() not a text selection" << endl;
+ return false;
+ }
+
+ return textAreaRect ().contains (globalPoint);
+}
+
+
+// public
+void kpSelection::textResize (int width, int height)
+{
+ if (!isText ())
+ {
+ kdError () << "kpSelection::textResize() not a text selection" << endl;
+ return;
+ }
+
+ QRect oldRect = m_rect;
+
+ m_rect = QRect (oldRect.x (), oldRect.y (), width, height);
+
+ calculatePoints ();
+ calculateTextPixmap ();
+
+ emit changed (m_rect.unite (oldRect));
+}
+
+
+// public static
+int kpSelection::minimumWidthForTextStyle (const kpTextStyle &)
+{
+ return (kpSelection::textBorderSize () * 2 + 5);
+}
+
+// public static
+int kpSelection::minimumHeightForTextStyle (const kpTextStyle &)
+{
+ return (kpSelection::textBorderSize () * 2 + 5);
+}
+
+// public static
+QSize kpSelection::minimumSizeForTextStyle (const kpTextStyle &textStyle)
+{
+ return QSize (minimumWidthForTextStyle (textStyle),
+ minimumHeightForTextStyle (textStyle));
+}
+
+
+// public static
+int kpSelection::preferredMinimumWidthForTextStyle (const kpTextStyle &textStyle)
+{
+ const int about15CharsWidth =
+ textStyle.fontMetrics ().width (
+ QString::fromLatin1 ("1234567890abcde"));
+
+ const int preferredMinWidth =
+ QMAX (150,
+ textBorderSize () * 2 + about15CharsWidth);
+
+ return QMAX (minimumWidthForTextStyle (textStyle),
+ QMIN (250, preferredMinWidth));
+}
+
+// public static
+int kpSelection::preferredMinimumHeightForTextStyle (const kpTextStyle &textStyle)
+{
+ const int preferredMinHeight =
+ textBorderSize () * 2 + textStyle.fontMetrics ().height ();
+
+ return QMAX (minimumHeightForTextStyle (textStyle),
+ QMIN (150, preferredMinHeight));
+}
+
+// public static
+QSize kpSelection::preferredMinimumSizeForTextStyle (const kpTextStyle &textStyle)
+{
+ return QSize (preferredMinimumWidthForTextStyle (textStyle),
+ preferredMinimumHeightForTextStyle (textStyle));
+}
+
+
+// public
+int kpSelection::minimumWidth () const
+{
+ if (isText ())
+ return minimumWidthForTextStyle (textStyle ());
+ else
+ return 1;
+}
+
+// public
+int kpSelection::minimumHeight () const
+{
+ if (isText ())
+ return minimumHeightForTextStyle (textStyle ());
+ else
+ return 1;
+}
+
+// public
+QSize kpSelection::minimumSize () const
+{
+ return QSize (minimumWidth (), minimumHeight ());
+}
+
+
+// public
+int kpSelection::textRowForPoint (const QPoint &globalPoint) const
+{
+ if (!isText ())
+ {
+ kdError () << "kpSelection::textRowForPoint() not a text selection" << endl;
+ return -1;
+ }
+
+ if (!pointIsInTextArea (globalPoint))
+ return -1;
+
+ const QFontMetrics fontMetrics (m_textStyle.fontMetrics ());
+
+ int row = (globalPoint.y () - textAreaRect ().y ()) /
+ fontMetrics.lineSpacing ();
+ if (row >= (int) m_textLines.size ())
+ row = m_textLines.size () - 1;
+
+ return row;
+}
+
+// public
+int kpSelection::textColForPoint (const QPoint &globalPoint) const
+{
+ if (!isText ())
+ {
+ kdError () << "kpSelection::textColForPoint() not a text selection" << endl;
+ return -1;
+ }
+
+ int row = textRowForPoint (globalPoint);
+ if (row < 0 || row >= (int) m_textLines.size ())
+ return -1;
+
+ const int localX = globalPoint.x () - textAreaRect ().x ();
+
+ const QFontMetrics fontMetrics (m_textStyle.fontMetrics ());
+
+ // (should be 0 but call just in case)
+ int charLocalLeft = fontMetrics.width (m_textLines [row], 0);
+
+ // OPT: binary search or guess location then move
+ for (int col = 0; col < (int) m_textLines [row].length (); col++)
+ {
+ // OPT: fontMetrics::charWidth() might be faster
+ const int nextCharLocalLeft = fontMetrics.width (m_textLines [row], col + 1);
+ if (localX <= (charLocalLeft + nextCharLocalLeft) / 2)
+ return col;
+
+ charLocalLeft = nextCharLocalLeft;
+ }
+
+ return m_textLines [row].length ()/*past end of line*/;
+}
+
+// public
+QPoint kpSelection::pointForTextRowCol (int row, int col)
+{
+ if (!isText ())
+ {
+ kdError () << "kpSelection::pointForTextRowCol() not a text selection" << endl;
+ return KP_INVALID_POINT;
+ }
+
+ if (row < 0 || row >= (int) m_textLines.size () ||
+ col < 0 || col > (int) m_textLines [row].length ())
+ {
+ #if DEBUG_KP_SELECTION && 1
+ kdDebug () << "kpSelection::pointForTextRowCol("
+ << row << ","
+ << col << ") out of range"
+ << " textLines='"
+ << text ()
+ << "'"
+ << endl;
+ #endif
+ return KP_INVALID_POINT;
+ }
+
+ const QFontMetrics fontMetrics (m_textStyle.fontMetrics ());
+
+ const int x = fontMetrics.width (m_textLines [row], col);
+ const int y = row * fontMetrics.height () +
+ (row >= 1 ? row * fontMetrics.leading () : 0);
+
+ return textAreaRect ().topLeft () + QPoint (x, y);
+}
+
+// public
+kpTextStyle kpSelection::textStyle () const
+{
+ if (!isText ())
+ {
+ kdError () << "kpSelection::textStyle() not a text selection" << endl;
+ }
+
+ return m_textStyle;
+}
+
+// public
+void kpSelection::setTextStyle (const kpTextStyle &textStyle_)
+{
+ if (!isText ())
+ {
+ kdError () << "kpSelection::setTextStyle() not a text selection" << endl;
+ return;
+ }
+
+ m_textStyle = textStyle_;
+ calculateTextPixmap ();
+ emit changed (boundingRect ());
+}
+
+// public
+QPixmap kpSelection::opaquePixmap () const
+{
+ QPixmap *p = pixmap ();
+ if (p)
+ {
+ return *p;
+ }
+ else
+ {
+ return QPixmap ();
+ }
+}
+
+// private
+void kpSelection::calculateTransparencyMask ()
+{
+#if DEBUG_KP_SELECTION
+ kdDebug () << "kpSelection::calculateTransparencyMask()" << endl;
+#endif
+
+ if (isText ())
+ {
+ #if DEBUG_KP_SELECTION
+ kdDebug () << "\ttext - no need for transparency mask" << endl;
+ #endif
+ m_transparencyMask.resize (0, 0);
+ return;
+ }
+
+ if (!m_pixmap)
+ {
+ #if DEBUG_KP_SELECTION
+ kdDebug () << "\tno pixmap - no need for transparency mask" << endl;
+ #endif
+ m_transparencyMask.resize (0, 0);
+ return;
+ }
+
+ if (m_transparency.isOpaque ())
+ {
+ #if DEBUG_KP_SELECTION
+ kdDebug () << "\topaque - no need for transparency mask" << endl;
+ #endif
+ m_transparencyMask.resize (0, 0);
+ return;
+ }
+
+ m_transparencyMask.resize (m_pixmap->width (), m_pixmap->height ());
+
+ QImage image = kpPixmapFX::convertToImage (*m_pixmap);
+ QPainter transparencyMaskPainter (&m_transparencyMask);
+
+ bool hasTransparent = false;
+ for (int y = 0; y < m_pixmap->height (); y++)
+ {
+ for (int x = 0; x < m_pixmap->width (); x++)
+ {
+ if (kpPixmapFX::getColorAtPixel (image, x, y).isSimilarTo (m_transparency.transparentColor (),
+ m_transparency.processedColorSimilarity ()))
+ {
+ transparencyMaskPainter.setPen (Qt::color1/*make it transparent*/);
+ hasTransparent = true;
+ }
+ else
+ {
+ transparencyMaskPainter.setPen (Qt::color0/*keep pixel as is*/);
+ }
+
+ transparencyMaskPainter.drawPoint (x, y);
+ }
+ }
+
+ transparencyMaskPainter.end ();
+
+ if (!hasTransparent)
+ {
+ #if DEBUG_KP_SELECTION
+ kdDebug () << "\tcolour useless - completely opaque" << endl;
+ #endif
+ m_transparencyMask.resize (0, 0);
+ return;
+ }
+}
+
+// public
+QPixmap kpSelection::transparentPixmap () const
+{
+ QPixmap pixmap = opaquePixmap ();
+
+ if (!m_transparencyMask.isNull ())
+ {
+ kpPixmapFX::paintMaskTransparentWithBrush (&pixmap, QPoint (0, 0),
+ m_transparencyMask);
+ }
+
+ return pixmap;
+}
+
+// public
+kpSelectionTransparency kpSelection::transparency () const
+{
+ return m_transparency;
+}
+
+// public
+bool kpSelection::setTransparency (const kpSelectionTransparency &transparency,
+ bool checkTransparentPixmapChanged)
+{
+ if (m_transparency == transparency)
+ return false;
+
+ m_transparency = transparency;
+
+ bool haveChanged = true;
+
+ QBitmap oldTransparencyMask = m_transparencyMask;
+ calculateTransparencyMask ();
+
+
+ if (oldTransparencyMask.width () == m_transparencyMask.width () &&
+ oldTransparencyMask.height () == m_transparencyMask.height ())
+ {
+ if (m_transparencyMask.isNull ())
+ {
+ #if DEBUG_KP_SELECTION
+ kdDebug () << "\tboth old and new pixmaps are null - nothing changed" << endl;
+ #endif
+ haveChanged = false;
+ }
+ else if (checkTransparentPixmapChanged)
+ {
+ QImage oldTransparencyMaskImage = kpPixmapFX::convertToImage (oldTransparencyMask);
+ QImage newTransparencyMaskImage = kpPixmapFX::convertToImage (m_transparencyMask);
+
+ bool changed = false;
+ for (int y = 0; y < oldTransparencyMaskImage.height () && !changed; y++)
+ {
+ for (int x = 0; x < oldTransparencyMaskImage.width () && !changed; x++)
+ {
+ if (kpPixmapFX::getColorAtPixel (oldTransparencyMaskImage, x, y) !=
+ kpPixmapFX::getColorAtPixel (newTransparencyMaskImage, x, y))
+ {
+ #if DEBUG_KP_SELECTION
+ kdDebug () << "\tdiffer at " << QPoint (x, y)
+ << " old=" << (int *) kpPixmapFX::getColorAtPixel (oldTransparencyMaskImage, x, y).toQRgb ()
+ << " new=" << (int *) kpPixmapFX::getColorAtPixel (newTransparencyMaskImage, x, y).toQRgb ()
+ << endl;
+ #endif
+ changed = true;
+ break;
+ }
+ }
+ }
+
+ if (!changed)
+ haveChanged = false;
+ }
+ }
+
+
+ if (haveChanged)
+ emit changed (boundingRect ());
+
+ return haveChanged;
+}
+
+
+// private
+void kpSelection::flipPoints (bool horiz, bool vert)
+{
+ QRect oldRect = boundingRect ();
+
+ m_points.translate (-oldRect.x (), -oldRect.y ());
+
+ const QWMatrix matrix = kpPixmapFX::flipMatrix (oldRect.width (), oldRect.height (),
+ horiz, vert);
+ m_points = matrix.map (m_points);
+
+ m_points.translate (oldRect.x (), oldRect.y ());
+}
+
+
+// public
+void kpSelection::flip (bool horiz, bool vert)
+{
+#if DEBUG_KP_SELECTION && 1
+ kdDebug () << "kpSelection::flip(horiz=" << horiz
+ << ",vert=" << vert << ")" << endl;
+#endif
+
+ flipPoints (horiz, vert);
+
+
+ if (m_pixmap)
+ {
+ #if DEBUG_KP_SELECTION && 1
+ kdDebug () << "\thave pixmap - flipping that" << endl;
+ #endif
+ kpPixmapFX::flip (m_pixmap, horiz, vert);
+ }
+
+ if (!m_transparencyMask.isNull ())
+ {
+ #if DEBUG_KP_SELECTION && 1
+ kdDebug () << "\thave transparency mask - flipping that" << endl;
+ #endif
+ kpPixmapFX::flip (&m_transparencyMask, horiz, vert);
+ }
+
+
+ emit changed (boundingRect ());
+}
+
+#include <kpselection.moc>
+
diff --git a/kolourpaint/kpselection.h b/kolourpaint/kpselection.h
new file mode 100644
index 00000000..69b836b9
--- /dev/null
+++ b/kolourpaint/kpselection.h
@@ -0,0 +1,237 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kpselection_h__
+#define __kpselection_h__
+
+#include <qbitmap.h>
+#include <qdatastream.h>
+#include <qobject.h>
+#include <qpixmap.h>
+#include <qpoint.h>
+#include <qpointarray.h>
+#include <qvaluevector.h>
+#include <qrect.h>
+#include <qstring.h>
+
+#include <kpcolor.h>
+#include <kppixmapfx.h>
+#include <kpselectiontransparency.h>
+#include <kptextstyle.h>
+
+
+class QSize;
+
+
+/*
+ * Holds a selection - will also be used for the clipboard
+ * so that we can retain the border.
+ */
+class kpSelection : public QObject
+{
+Q_OBJECT
+
+public:
+ enum Type
+ {
+ Rectangle,
+ Ellipse,
+ Points,
+ Text
+ };
+
+ // (for any)
+ kpSelection (const kpSelectionTransparency &transparency = kpSelectionTransparency ());
+
+ // (for Rectangle & Ellipse)
+ kpSelection (Type type, const QRect &rect, const QPixmap &pixmap = QPixmap (),
+ const kpSelectionTransparency &transparency = kpSelectionTransparency ());
+ kpSelection (Type type, const QRect &rect, const kpSelectionTransparency &transparency);
+
+ // (for Text)
+ kpSelection (const QRect &rect, const QValueVector <QString> &textLines_, const kpTextStyle &textStyle_);
+
+ // (for Points)
+ kpSelection (const QPointArray &points, const QPixmap &pixmap = QPixmap (),
+ const kpSelectionTransparency &transparency = kpSelectionTransparency ());
+ kpSelection (const QPointArray &points, const kpSelectionTransparency &transparency);
+
+ kpSelection (const kpSelection &rhs);
+ kpSelection &operator= (const kpSelection &rhs);
+ friend QDataStream &operator<< (QDataStream &stream, const kpSelection &selection);
+ friend QDataStream &operator>> (QDataStream &stream, kpSelection &selection);
+ void readFromStream (QDataStream &stream,
+ const kpPixmapFX::WarnAboutLossInfo &wali =
+ kpPixmapFX::WarnAboutLossInfo ());
+ ~kpSelection ();
+
+private:
+ void calculatePoints ();
+
+public:
+ Type type () const;
+ bool isRectangular () const;
+ bool isText () const;
+ // returns either i18n ("Selection") or i18n ("Text")
+ QString name () const;
+
+ int size () const;
+
+ QBitmap maskForOwnType (bool nullForRectangular = false) const;
+
+ // synonyms
+ QPoint topLeft () const;
+ QPoint point () const;
+
+ int x () const;
+ int y () const;
+
+ void moveBy (int dx, int dy);
+ void moveTo (int dx, int dy);
+ void moveTo (const QPoint &topLeftPoint);
+
+ // synonyms
+ QPointArray points () const;
+ QPointArray pointArray () const;
+
+ QRect boundingRect () const;
+ int width () const;
+ int height () const;
+
+
+ // (for non-rectangular selections, may return false even if
+ // kpView::onSelectionResizeHandle())
+ bool contains (const QPoint &point) const;
+ bool contains (int x, int y);
+
+
+ // (Avoid using for text selections since text selection may
+ // require a background for antialiasing purposes - use paint()
+ // instead, else no antialising)
+ QPixmap *pixmap () const;
+ void setPixmap (const QPixmap &pixmap);
+
+ bool usesBackgroundPixmapToPaint () const;
+
+private:
+ void paintOpaqueText (QPixmap *destPixmap, const QRect &docRect) const;
+ QPixmap transparentForegroundTextPixmap () const;
+
+public:
+ // (<docRect> is the document rectangle that <*destPixmap> represents)
+ void paint (QPixmap *destPixmap, const QRect &docRect) const;
+
+private:
+ void calculateTextPixmap ();
+
+public:
+ static QString textForTextLines (const QValueVector <QString> &textLines_);
+ QString text () const; // textLines() as one long string
+ QValueVector <QString> textLines () const;
+ void setTextLines (const QValueVector <QString> &textLines_);
+
+ static int textBorderSize ();
+ QRect textAreaRect () const;
+ bool pointIsInTextBorderArea (const QPoint &globalPoint) const;
+ bool pointIsInTextArea (const QPoint &globalPoint) const;
+
+
+ void textResize (int width, int height);
+
+ // TODO: Enforce in kpSelection, not just in kpToolSelection & when pasting
+ // (in kpMainWindow).
+ // Be more robust when external enforcement fails.
+ static int minimumWidthForTextStyle (const kpTextStyle &);
+ static int minimumHeightForTextStyle (const kpTextStyle &);
+ static QSize minimumSizeForTextStyle (const kpTextStyle &);
+
+ static int preferredMinimumWidthForTextStyle (const kpTextStyle &textStyle);
+ static int preferredMinimumHeightForTextStyle (const kpTextStyle &textStyle);
+ static QSize preferredMinimumSizeForTextStyle (const kpTextStyle &textStyle);
+
+ int minimumWidth () const;
+ int minimumHeight () const;
+ QSize minimumSize () const;
+
+ int textRowForPoint (const QPoint &globalPoint) const;
+ int textColForPoint (const QPoint &globalPoint) const;
+ QPoint pointForTextRowCol (int row, int col);
+
+ kpTextStyle textStyle () const;
+ void setTextStyle (const kpTextStyle &textStyle);
+
+ // TODO: ret val inconstent with pixmap()
+ // - fix when merge with kpTempPixmap
+ QPixmap opaquePixmap () const; // same as pixmap()
+
+private:
+ void calculateTransparencyMask ();
+
+public:
+ // Returns opaquePixmap() after applying kpSelectionTransparency
+ QPixmap transparentPixmap () const;
+
+ kpSelectionTransparency transparency () const;
+ // Returns whether or not the selection changed due to setting the
+ // transparency info. If <checkTransparentPixmapChanged> is set,
+ // it will try harder to return false (although the check is
+ // expensive).
+ bool setTransparency (const kpSelectionTransparency &transparency,
+ bool checkTransparentPixmapChanged = false);
+
+private:
+ void flipPoints (bool horiz, bool vert);
+
+public:
+ void flip (bool horiz, bool vert);
+
+signals:
+ void changed (const QRect &docRect);
+
+private:
+ // OPT: use implicit sharing
+
+ Type m_type;
+ QRect m_rect;
+ QPointArray m_points;
+ QPixmap *m_pixmap;
+
+ QValueVector <QString> m_textLines;
+ kpTextStyle m_textStyle;
+
+ kpSelectionTransparency m_transparency;
+ QBitmap m_transparencyMask;
+
+private:
+ // There is no need to maintain binary compatibility at this stage.
+ // The d-pointer is just so that you can experiment without recompiling
+ // the kitchen sink.
+ class kpSelectionPrivate *d;
+};
+
+#endif // __kpselection_h__
diff --git a/kolourpaint/kpselectiondrag.cpp b/kolourpaint/kpselectiondrag.cpp
new file mode 100644
index 00000000..23ab9a4e
--- /dev/null
+++ b/kolourpaint/kpselectiondrag.cpp
@@ -0,0 +1,294 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_SELECTION_DRAG 0
+
+
+#include <kpselectiondrag.h>
+
+#include <qdatastream.h>
+
+#include <kdebug.h>
+
+#include <kppixmapfx.h>
+#include <kpselection.h>
+
+
+// public static
+const char * const kpSelectionDrag::selectionMimeType = "application/x-kolourpaint-selection";
+
+
+kpSelectionDrag::kpSelectionDrag (QWidget *dragSource, const char *name)
+ : QImageDrag (dragSource, name)
+{
+}
+
+kpSelectionDrag::kpSelectionDrag (const QImage &image, QWidget *dragSource, const char *name)
+ : QImageDrag (image, dragSource, name)
+{
+}
+
+kpSelectionDrag::kpSelectionDrag (const kpSelection &sel, QWidget *dragSource, const char *name)
+ : QImageDrag (dragSource, name)
+{
+ setSelection (sel);
+}
+
+kpSelectionDrag::~kpSelectionDrag ()
+{
+}
+
+
+// public
+void kpSelectionDrag::setSelection (const kpSelection &sel)
+{
+ if (!sel.pixmap ())
+ {
+ kdError () << "kpSelectionDrag::setSelection() without pixmap" << endl;
+ return;
+ }
+
+ m_selection = sel;
+
+ // OPT: an awful waste of memory storing image in both selection and QImage
+
+ // HACK: need to set image else QImageDrag::format() lies
+ setImage (kpPixmapFX::convertToImage (*m_selection.pixmap ()));
+}
+
+// protected
+bool kpSelectionDrag::holdsSelection () const
+{
+ return bool (m_selection.pixmap ());
+}
+
+
+// public virtual [base QMimeSource]
+const char *kpSelectionDrag::format (int which) const
+{
+#if DEBUG_KP_SELECTION_DRAG && 0
+ kdDebug () << "kpSelectionDrag::format(" << which << ")" << endl;
+#endif
+ const char *ret = QImageDrag::format (which);
+ if (ret)
+ {
+ #if DEBUG_KP_SELECTION_DRAG && 0
+ kdDebug () << "\tQImageDrag reports " << ret << endl;
+ #endif
+ return ret;
+ }
+
+ int i;
+ for (i = 0; QImageDrag::format (i); i++)
+ ;
+
+#if DEBUG_KP_SELECTION_DRAG && 0
+ kdDebug () << "\tend of QImageDrag format list at " << i << endl;
+#endif
+
+ if (i == which)
+ {
+ #if DEBUG_KP_SELECTION_DRAG && 0
+ kdDebug () << "\treturning own mimetype" << endl;
+ #endif
+ return kpSelectionDrag::selectionMimeType;
+ }
+ else
+ {
+ #if DEBUG_KP_SELECTION_DRAG && 0
+ kdDebug () << "\treturning non-existent" << endl;
+ #endif
+ return 0;
+ }
+}
+
+// public virtual [base QMimeSource]
+// Don't need to override in Qt 3.2 (the QMimeSource base will work)
+// but we do so just in case QImageDrag later decides to override it.
+bool kpSelectionDrag::provides (const char *mimeType) const
+{
+#if DEBUG_KP_SELECTION_DRAG
+ kdDebug () << "kpSelectionDrag::provides(" << mimeType << ")" << endl;
+#endif
+
+ if (!mimeType)
+ return false;
+
+ return (!strcmp (mimeType, kpSelectionDrag::selectionMimeType) ||
+ QImageDrag::provides (mimeType));
+}
+
+// public virtual [base QMimeSource]
+QByteArray kpSelectionDrag::encodedData (const char *mimeType) const
+{
+#if DEBUG_KP_SELECTION_DRAG
+ kdDebug () << "kpSelectionDrag::encodedData(" << mimeType << ")" << endl;
+#endif
+
+ if (!mimeType)
+ return QByteArray ();
+
+ if (!strcmp (mimeType, kpSelectionDrag::selectionMimeType))
+ {
+ QByteArray ba;
+ QDataStream stream (ba, IO_WriteOnly);
+
+ #if DEBUG_KP_SELECTION_DRAG
+ kdDebug () << "\twant it as kpSelection in QByteArray" << endl;
+ #endif
+
+ if (holdsSelection ())
+ {
+ #if DEBUG_KP_SELECTION_DRAG
+ kdDebug () << "\t\thave selection - return it" << endl;
+ #endif
+ stream << m_selection;
+ }
+ else
+ {
+ #if DEBUG_KP_SELECTION_DRAG
+ kdDebug () << "\t\thave image - call kpSelectionDrag::decode(QImage)" << endl;
+ #endif
+ QImage image;
+ if (kpSelectionDrag::decode (this, image/*ref*/))
+ {
+ #if DEBUG_KP_SELECTION_DRAG
+ kdDebug () << "\t\t\tok - returning sel with image w="
+ << image.width ()
+ << " h="
+ << image.height ()
+ << endl;
+ #endif
+
+ QPixmap pixmap = kpPixmapFX::convertToPixmapAsLosslessAsPossible (image);
+
+ stream << kpSelection (kpSelection::Rectangle,
+ QRect (0, 0, pixmap.width (), pixmap.height ()),
+ pixmap);
+ }
+ else
+ {
+ kdError () << "kpSelectionDrag::encodedData(" << mimeType << ")"
+ << " kpSelectionDrag(QImage) could not decode data into QImage"
+ << endl;
+ stream << kpSelection ();
+ }
+ }
+
+ return ba;
+ }
+ else
+ {
+ #if DEBUG_KP_SELECTION_DRAG
+ kdDebug () << "\twant it as QImage in QByteArray" << endl;
+ #endif
+
+ return QImageDrag::encodedData (mimeType);
+ }
+}
+
+
+// public static
+bool kpSelectionDrag::canDecode (const QMimeSource *e)
+{
+#if DEBUG_KP_SELECTION_DRAG
+ kdDebug () << "kpSelectionDrag::canDecode()" << endl;
+#endif
+
+ if (!e)
+ return false;
+
+ return (e->provides (kpSelectionDrag::selectionMimeType) ||
+ QImageDrag::canDecode (e));
+}
+
+
+// public static
+bool kpSelectionDrag::decode (const QMimeSource *e, QImage &img)
+{
+#if DEBUG_KP_SELECTION_DRAG
+ kdDebug () << "kpSelectionDrag::decode(QImage)" << endl;
+#endif
+ if (!e)
+ return false;
+
+ return (QImageDrag::canDecode (e) && // prevents X errors, jumps based on unitialised values...
+ QImageDrag::decode (e, img/*ref*/));
+}
+
+// public static
+bool kpSelectionDrag::decode (const QMimeSource *e, kpSelection &sel,
+ const kpPixmapFX::WarnAboutLossInfo &wali)
+{
+#if DEBUG_KP_SELECTION_DRAG
+ kdDebug () << "kpSelectionDrag::decode(kpSelection)" << endl;
+#endif
+ if (!e)
+ return false;
+
+ if (e->provides (kpSelectionDrag::selectionMimeType))
+ {
+ #if DEBUG_KP_SELECTION_DRAG
+ kdDebug () << "\tmimeSource provides selection - just return it in QByteArray" << endl;
+ #endif
+ QByteArray data = e->encodedData (kpSelectionDrag::selectionMimeType);
+ QDataStream stream (data, IO_ReadOnly);
+
+ // (no need for wali as kpSelection's by definition only support QPixmap's)
+ stream >> sel;
+ }
+ else
+ {
+ #if DEBUG_KP_SELECTION_DRAG
+ kdDebug () << "\tmimeSource doesn't provide selection - try image" << endl;
+ #endif
+
+ QImage image;
+ if (kpSelectionDrag::decode (e, image/*ref*/))
+ {
+ #if DEBUG_KP_SELECTION_DRAG
+ kdDebug () << "\tok w=" << image.width () << " h=" << image.height () << endl;
+ #endif
+
+ sel = kpSelection (kpSelection::Rectangle,
+ QRect (0, 0, image.width (), image.height ()),
+ kpPixmapFX::convertToPixmapAsLosslessAsPossible (image, wali));
+ }
+ else
+ {
+ #if DEBUG_KP_SELECTION_DRAG
+ kdDebug () << "kpSelectionDrag::decode(kpSelection) mimeSource had no sel "
+ "and could not decode to image" << endl;
+ #endif
+ return false;
+ }
+ }
+
+ return true;
+}
+
+#include <kpselectiondrag.moc>
diff --git a/kolourpaint/kpselectiondrag.h b/kolourpaint/kpselectiondrag.h
new file mode 100644
index 00000000..5aae82d9
--- /dev/null
+++ b/kolourpaint/kpselectiondrag.h
@@ -0,0 +1,71 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kp_selection_drag_h__
+#define __kp_selection_drag_h__
+
+#include <qdragobject.h>
+
+#include <kppixmapfx.h>
+#include <kpselection.h>
+
+
+class kpSelectionDrag : public QImageDrag
+{
+Q_OBJECT
+
+public:
+ kpSelectionDrag (QWidget *dragSource = 0, const char *name = 0);
+ kpSelectionDrag (const QImage &image, QWidget *dragSource = 0, const char *name = 0);
+ kpSelectionDrag (const kpSelection &sel, QWidget *dragSource = 0, const char *name = 0);
+ virtual ~kpSelectionDrag ();
+
+ static const char * const selectionMimeType;
+
+ void setSelection (const kpSelection &sel);
+
+protected:
+ bool holdsSelection () const;
+
+public:
+ virtual const char *format (int which = 0) const;
+ virtual bool provides (const char *mimeType) const;
+ virtual QByteArray encodedData (const char *mimeType) const;
+
+ static bool canDecode (const QMimeSource *e);
+ static bool decode (const QMimeSource *e, QImage &img);
+ static bool decode (const QMimeSource *e, kpSelection &sel,
+ const kpPixmapFX::WarnAboutLossInfo &wali =
+ kpPixmapFX::WarnAboutLossInfo ());
+
+protected:
+ kpSelection m_selection;
+};
+
+
+#endif // __kp_selection_drag_h__
diff --git a/kolourpaint/kpselectiontransparency.cpp b/kolourpaint/kpselectiontransparency.cpp
new file mode 100644
index 00000000..62919be4
--- /dev/null
+++ b/kolourpaint/kpselectiontransparency.cpp
@@ -0,0 +1,178 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_SELECTION_TRANSPARENCY 0
+
+
+#include <kpselectiontransparency.h>
+
+#include <kdebug.h>
+
+#include <kpcolor.h>
+#include <kpcolorsimilaritydialog.h>
+
+
+kpSelectionTransparency::kpSelectionTransparency ()
+ : m_isOpaque (true)
+{
+ setColorSimilarity (0);
+}
+
+kpSelectionTransparency::kpSelectionTransparency (const kpColor &transparentColor, double colorSimilarity)
+ : m_isOpaque (false),
+ m_transparentColor (transparentColor)
+{
+ setColorSimilarity (colorSimilarity);
+}
+
+kpSelectionTransparency::kpSelectionTransparency (bool isOpaque, const kpColor &transparentColor,
+ double colorSimilarity)
+ : m_isOpaque (isOpaque),
+ m_transparentColor (transparentColor)
+{
+ setColorSimilarity (colorSimilarity);
+}
+
+bool kpSelectionTransparency::operator== (const kpSelectionTransparency &rhs) const
+{
+#if DEBUG_KP_SELECTION_TRANSPARENCY && 0
+ kdDebug () << "kpSelectionTransparency::operator==()" << endl;
+#endif
+
+ if (m_isOpaque != rhs.m_isOpaque)
+ {
+ #if DEBUG_KP_SELECTION_TRANSPARENCY && 0
+ kdDebug () << "\tdifferent opacity: lhs=" << m_isOpaque
+ << " rhs=" << rhs.m_isOpaque
+ << endl;
+ #endif
+ return false;
+ }
+
+ if (m_isOpaque)
+ {
+ #if DEBUG_KP_SELECTION_TRANSPARENCY && 0
+ kdDebug () << "\tboth opaque - eq" << endl;
+ #endif
+ return true;
+ }
+
+#if DEBUG_KP_SELECTION_TRANSPARENCY && 0
+ kdDebug () << "\tcolours: lhs=" << (int *) m_transparentColor.toQRgb ()
+ << " rhs=" << (int *) rhs.m_transparentColor.toQRgb ()
+ << endl;
+ kdDebug () << "\tcolour similarity: lhs=" << m_colorSimilarity
+ << " rhs=" << rhs.m_colorSimilarity
+ << endl;
+#endif
+
+ return (m_transparentColor == rhs.m_transparentColor &&
+ m_colorSimilarity == rhs.m_colorSimilarity);
+}
+
+bool kpSelectionTransparency::operator!= (const kpSelectionTransparency &rhs) const
+{
+ return !(*this == rhs);
+}
+
+kpSelectionTransparency::~kpSelectionTransparency ()
+{
+}
+
+
+// public
+bool kpSelectionTransparency::isOpaque () const
+{
+ return m_isOpaque;
+}
+
+// public
+bool kpSelectionTransparency::isTransparent () const
+{
+ return !isOpaque ();
+}
+
+// public
+void kpSelectionTransparency::setOpaque (bool yes)
+{
+ m_isOpaque = yes;
+}
+
+// public
+void kpSelectionTransparency::setTransparent (bool yes)
+{
+ setOpaque (!yes);
+}
+
+
+// public
+kpColor kpSelectionTransparency::transparentColor () const
+{
+ if (m_isOpaque)
+ {
+ // There are legitimate uses for this so no kdError()
+ kdDebug () << "kpSelectionTransparency::transparentColor() "
+ "getting transparent color even though opaque" << endl;
+ }
+
+ return m_transparentColor;
+}
+
+// public
+void kpSelectionTransparency::setTransparentColor (const kpColor &transparentColor)
+{
+ m_transparentColor = transparentColor;
+}
+
+
+// public
+double kpSelectionTransparency::colorSimilarity () const
+{
+ if (m_colorSimilarity < 0 ||
+ m_colorSimilarity > kpColorSimilarityDialog::maximumColorSimilarity)
+ {
+ kdError () << "kpSelectionTransparency::colorSimilarity() invalid colorSimilarity" << endl;
+ return 0;
+ }
+
+ return m_colorSimilarity;
+}
+
+// pubulic
+void kpSelectionTransparency::setColorSimilarity (double colorSimilarity)
+{
+ m_colorSimilarity = colorSimilarity;
+ m_processedColorSimilarity = kpColor::processSimilarity (colorSimilarity);
+}
+
+// public
+int kpSelectionTransparency::processedColorSimilarity () const
+{
+ return m_processedColorSimilarity;
+}
+
diff --git a/kolourpaint/kpselectiontransparency.h b/kolourpaint/kpselectiontransparency.h
new file mode 100644
index 00000000..690c4c1e
--- /dev/null
+++ b/kolourpaint/kpselectiontransparency.h
@@ -0,0 +1,80 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __kp_selection_transparency_h__
+#define __kp_selection_transparency_h__
+
+#include <kpcolor.h>
+
+
+// This does not apply to the Text Tool. Use kpTextStyle for that.
+class kpSelectionTransparency
+{
+public:
+ // Opaque selection
+ kpSelectionTransparency ();
+ // Selection that's transparent at pixels with <color>
+ kpSelectionTransparency (const kpColor &transparentColor, double colorSimilarity);
+ // If <isOpaque>, <transparentColor> is allowed to be anything
+ // (including invalid) as the color would have no effect.
+ // However, you are encouraged to set it as you would if !<isOpaque>,
+ // because setTransparent(true) might be called later, after which
+ // the <transparentColor> would suddenly become important.
+ //
+ // It is a similar case with <colorSimilarity>, although <colorSimilarity>
+ // must be in-range (see kpColorSimilarityDialog).
+ kpSelectionTransparency (bool isOpaque, const kpColor &transparentColor, double colorSimilarity);
+ // Returns whether they are visually equivalent.
+ // This is the same as a memcmp() except that if they are both opaque,
+ // this function will return true regardless of the transparentColor's.
+ bool operator== (const kpSelectionTransparency &rhs) const;
+ bool operator!= (const kpSelectionTransparency &rhs) const;
+ ~kpSelectionTransparency ();
+
+ bool isOpaque () const;
+ bool isTransparent () const;
+ void setOpaque (bool yes = true);
+ void setTransparent (bool yes = true);
+
+ // If isOpaque(), transparentColor() is generally not called because
+ // the transparent color would have no effect.
+ kpColor transparentColor () const;
+ void setTransparentColor (const kpColor &transparentColor);
+
+ double colorSimilarity () const;
+ void setColorSimilarity (double colorSimilarity);
+ int processedColorSimilarity () const;
+
+private:
+ bool m_isOpaque;
+ kpColor m_transparentColor;
+ double m_colorSimilarity;
+ int m_processedColorSimilarity;
+};
+
+
+#endif // __kp_selection_transparency_h__
diff --git a/kolourpaint/kpsinglekeytriggersaction.cpp b/kolourpaint/kpsinglekeytriggersaction.cpp
new file mode 100644
index 00000000..d3b64002
--- /dev/null
+++ b/kolourpaint/kpsinglekeytriggersaction.cpp
@@ -0,0 +1,155 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_SINGLE_KEY_TRIGGERS_ACTION 0
+
+
+//
+// kpSingleKeyTriggersActionInterface
+//
+
+
+#include <kpsinglekeytriggersaction.h>
+
+#include <kdebug.h>
+
+#include <kptool.h>
+
+
+kpSingleKeyTriggersActionInterface::kpSingleKeyTriggersActionInterface ()
+{
+ m_singleKeyTriggersEnabled = true;
+}
+
+kpSingleKeyTriggersActionInterface::~kpSingleKeyTriggersActionInterface ()
+{
+}
+
+
+// public
+bool kpSingleKeyTriggersActionInterface::singleKeyTriggersEnabled () const
+{
+ return m_singleKeyTriggersEnabled;
+}
+
+// public
+void kpSingleKeyTriggersActionInterface::enableSingleKeyTriggers (bool enable)
+{
+#if DEBUG_KP_SINGLE_KEY_TRIGGERS_ACTION
+ kdDebug () << "kpSingleKeyTriggersActionInterface(" << /*virtual*/actionName ()
+ << ")::enableSingleKeyTriggers(" << enable << ")"
+ << endl;
+#endif
+
+ if (enable == m_singleKeyTriggersEnabled)
+ {
+ #if DEBUG_KP_SINGLE_KEY_TRIGGERS_ACTION
+ kdDebug () << "\tnop" << endl;
+ #endif
+ return;
+ }
+
+ m_singleKeyTriggersEnabled = enable;
+
+
+ if (enable)
+ {
+ #if DEBUG_KP_SINGLE_KEY_TRIGGERS_ACTION
+ kdDebug () << "\tre-enabling to " << m_fullShortcut.toString () << endl;
+ #endif
+ /*pure virtual*/actionSetShortcut (m_fullShortcut);
+ }
+ else // disable single key triggers
+ {
+ m_fullShortcut = /*pure virtual*/actionShortcut ();
+
+ KShortcut newShortcut;
+ if (kpTool::containsSingleKeyTrigger (m_fullShortcut, &newShortcut))
+ {
+ #if DEBUG_KP_SINGLE_KEY_TRIGGERS_ACTION
+ kdDebug () << "\tchange shortcuts: old="
+ << m_fullShortcut.toString ()
+ << " new="
+ << newShortcut.toString ()
+ << endl;
+ #endif
+ /*pure virtual*/actionSetShortcut (newShortcut);
+ }
+ else
+ {
+ #if DEBUG_KP_SINGLE_KEY_TRIGGERS_ACTION
+ kdDebug () << "\tshortcut is untouched "
+ << m_fullShortcut.toString ()
+ << endl;
+ #endif
+ }
+ }
+}
+
+
+//
+// kpSingleKeyTriggersAction
+//
+
+
+kpSingleKeyTriggersAction::kpSingleKeyTriggersAction (const QString &text,
+ const KShortcut &shortcut,
+ const QObject *receiver, const char *slot,
+ KActionCollection *parent, const char *name)
+ : KAction (text, shortcut, receiver, slot, parent, name)
+{
+}
+
+kpSingleKeyTriggersAction::~kpSingleKeyTriggersAction ()
+{
+}
+
+
+//
+// kpSingleKeyTriggersAction implements kpSingleKeyTriggersActionInterface
+//
+
+// public virtual [base kpSingleKeyTriggersActionInterface]
+const char *kpSingleKeyTriggersAction::actionName () const
+{
+ return name ();
+}
+
+// public virtual [base kpSingleKeyTriggersActionInterface]
+KShortcut kpSingleKeyTriggersAction::actionShortcut () const
+{
+ return shortcut ();
+}
+
+// public virtual [base kpSingleKeyTriggersActionInterface]
+void kpSingleKeyTriggersAction::actionSetShortcut (const KShortcut &shortcut)
+{
+ setShortcut (shortcut);
+}
+
+
+#include <kpsinglekeytriggersaction.moc>
diff --git a/kolourpaint/kpsinglekeytriggersaction.h b/kolourpaint/kpsinglekeytriggersaction.h
new file mode 100644
index 00000000..fc404bd5
--- /dev/null
+++ b/kolourpaint/kpsinglekeytriggersaction.h
@@ -0,0 +1,82 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KP_SINGLE_KEY_TRIGGERS_ACTION_H
+#define KP_SINGLE_KEY_TRIGGERS_ACTION_H
+
+
+#include <kshortcut.h>
+
+
+class kpSingleKeyTriggersActionInterface
+{
+public:
+ kpSingleKeyTriggersActionInterface ();
+ virtual ~kpSingleKeyTriggersActionInterface ();
+
+ bool singleKeyTriggersEnabled () const;
+ void enableSingleKeyTriggers (bool enable = true);
+
+ // Avoid inheritance diamond by not deriving from KAction
+ // so you'll have to implement these by talking to your base KAction.
+ virtual const char *actionName () const { return 0; }
+ virtual KShortcut actionShortcut () const = 0;
+ virtual void actionSetShortcut (const KShortcut &shortcut) = 0;
+
+protected:
+ bool m_singleKeyTriggersEnabled;
+ KShortcut m_fullShortcut;
+};
+
+
+#include <kaction.h>
+
+
+class kpSingleKeyTriggersAction : public KAction,
+ public kpSingleKeyTriggersActionInterface
+{
+Q_OBJECT
+
+public:
+ kpSingleKeyTriggersAction (const QString &text,
+ const KShortcut &shortcut,
+ const QObject *receiver, const char *slot,
+ KActionCollection *parent, const char *name);
+ virtual ~kpSingleKeyTriggersAction ();
+
+
+ //
+ // kpSingleKeyTriggersActionInterface
+ //
+
+ virtual const char *actionName () const;
+ virtual KShortcut actionShortcut () const;
+ virtual void actionSetShortcut (const KShortcut &shortcut);
+};
+
+
+#endif // KP_SINGLE_KEY_TRIGGERS_ACTION_H
diff --git a/kolourpaint/kptemppixmap.cpp b/kolourpaint/kptemppixmap.cpp
new file mode 100644
index 00000000..55f669ee
--- /dev/null
+++ b/kolourpaint/kptemppixmap.cpp
@@ -0,0 +1,148 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_TEMP_PIXMAP 0
+
+
+#include <kptemppixmap.h>
+
+#include <kppixmapfx.h>
+#include <kpviewmanager.h>
+
+
+kpTempPixmap::kpTempPixmap (bool isBrush, RenderMode renderMode,
+ const QPoint &topLeft, const QPixmap &pixmap)
+ : m_isBrush (isBrush),
+ m_renderMode (renderMode),
+ m_topLeft (topLeft),
+ m_pixmap (pixmap)
+{
+}
+
+kpTempPixmap::kpTempPixmap (const kpTempPixmap &rhs)
+ : m_isBrush (rhs.m_isBrush),
+ m_renderMode (rhs.m_renderMode),
+ m_topLeft (rhs.m_topLeft),
+ m_pixmap (rhs.m_pixmap)
+{
+}
+
+kpTempPixmap &kpTempPixmap::operator= (const kpTempPixmap &rhs)
+{
+ if (this == &rhs)
+ return *this;
+
+ m_isBrush = rhs.m_isBrush;
+ m_renderMode = rhs.m_renderMode;
+ m_topLeft = rhs.m_topLeft;
+ m_pixmap = rhs.m_pixmap;
+
+ return *this;
+}
+
+kpTempPixmap::~kpTempPixmap ()
+{
+}
+
+
+// public
+bool kpTempPixmap::isBrush () const
+{
+ return m_isBrush;
+}
+
+// public
+kpTempPixmap::RenderMode kpTempPixmap::renderMode () const
+{
+ return m_renderMode;
+}
+
+// public
+QPoint kpTempPixmap::topLeft () const
+{
+ return m_topLeft;
+}
+
+// public
+QPixmap kpTempPixmap::pixmap () const
+{
+ return m_pixmap;
+}
+
+
+// public
+bool kpTempPixmap::isVisible (const kpViewManager *vm) const
+{
+ return m_isBrush ? (bool) vm->viewUnderCursor () : true;
+}
+
+// public
+QRect kpTempPixmap::rect () const
+{
+ return QRect (m_topLeft.x (), m_topLeft.y (),
+ m_pixmap.width (), m_pixmap.height ());
+}
+
+// public
+int kpTempPixmap::width () const
+{
+ return m_pixmap.width ();
+}
+
+// public
+int kpTempPixmap::height () const
+{
+ return m_pixmap.height ();
+}
+
+
+// public
+bool kpTempPixmap::mayChangeDocumentMask () const
+{
+ return (m_renderMode == SetPixmap ||
+ m_renderMode == PaintMaskTransparentWithBrush);
+}
+
+// public
+void kpTempPixmap::paint (QPixmap *destPixmap, const QRect &docRect) const
+{
+#define PARAMS destPixmap, m_topLeft - docRect.topLeft (), m_pixmap
+ switch (m_renderMode)
+ {
+ case SetPixmap:
+ kpPixmapFX::setPixmapAt (PARAMS);
+ break;
+ case PaintPixmap:
+ kpPixmapFX::paintPixmapAt (PARAMS);
+ break;
+ case PaintMaskTransparentWithBrush:
+ kpPixmapFX::paintMaskTransparentWithBrush (PARAMS);
+ break;
+ }
+#undef PARAMS
+}
diff --git a/kolourpaint/kptemppixmap.h b/kolourpaint/kptemppixmap.h
new file mode 100644
index 00000000..6ddb9413
--- /dev/null
+++ b/kolourpaint/kptemppixmap.h
@@ -0,0 +1,90 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// TODO: maybe merge with kpSelection?
+
+
+#ifndef __kp_temp_pixmap_h__
+#define __kp_temp_pixmap_h__
+
+
+#include <qpoint.h>
+#include <qpixmap.h>
+
+class kpViewManager;
+
+
+class kpTempPixmap
+{
+public:
+ enum RenderMode
+ {
+ SetPixmap,
+ PaintPixmap,
+ PaintMaskTransparentWithBrush
+ };
+
+ /*
+ * <isBrush> Specifies that its visibility is dependent on whether or
+ * not the mouse cursor is inside a view. If false, the
+ * pixmap is always displayed.
+ */
+ kpTempPixmap (bool isBrush, RenderMode renderMode, const QPoint &topLeft, const QPixmap &pixmap);
+ kpTempPixmap (const kpTempPixmap &rhs);
+ kpTempPixmap &operator= (const kpTempPixmap &rhs);
+ ~kpTempPixmap ();
+
+ bool isBrush () const;
+ RenderMode renderMode () const;
+ QPoint topLeft () const;
+ QPixmap pixmap () const;
+
+ bool isVisible (const kpViewManager *vm) const;
+ QRect rect () const;
+ int width () const;
+ int height () const;
+
+
+ // Returns whether a call to paint() may change <*destPixmap>'s mask
+ bool mayChangeDocumentMask () const;
+
+ /*
+ * Draws itself onto <*destPixmap>, given that <*destPixmap> represents
+ * the unzoomed <docRect> of the kpDocument. You should check for
+ * visibility before calling this function.
+ */
+ void paint (QPixmap *destPixmap, const QRect &docRect) const;
+
+private:
+ bool m_isBrush;
+ RenderMode m_renderMode;
+ QPoint m_topLeft;
+ QPixmap m_pixmap;
+};
+
+
+#endif // __kp_temp_pixmap_h__
diff --git a/kolourpaint/kptextstyle.cpp b/kolourpaint/kptextstyle.cpp
new file mode 100644
index 00000000..9f4d8fce
--- /dev/null
+++ b/kolourpaint/kptextstyle.cpp
@@ -0,0 +1,279 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <kptextstyle.h>
+
+#include <qdatastream.h>
+#include <qfont.h>
+#include <qfontmetrics.h>
+
+
+kpTextStyle::kpTextStyle ()
+ : m_fontSize (0),
+ m_isBold (false), m_isItalic (false),
+ m_isUnderline (false), m_isStrikeThru (false),
+ m_isBackgroundOpaque (true)
+{
+}
+
+kpTextStyle::kpTextStyle (const QString &fontFamily,
+ int fontSize,
+ bool isBold, bool isItalic,
+ bool isUnderline, bool isStrikeThru,
+ const kpColor &fcolor, const kpColor &bcolor,
+ bool isBackgroundOpaque)
+ : m_fontFamily (fontFamily),
+ m_fontSize (fontSize),
+ m_isBold (isBold), m_isItalic (isItalic),
+ m_isUnderline (isUnderline), m_isStrikeThru (isStrikeThru),
+ m_foregroundColor (fcolor), m_backgroundColor (bcolor),
+ m_isBackgroundOpaque (isBackgroundOpaque)
+{
+}
+
+kpTextStyle::~kpTextStyle ()
+{
+}
+
+
+// friend
+QDataStream &operator<< (QDataStream &stream, const kpTextStyle &textStyle)
+{
+ stream << textStyle.m_fontFamily;
+ stream << textStyle.m_fontSize;
+
+ stream << int (textStyle.m_isBold) << int (textStyle.m_isItalic)
+ << int (textStyle.m_isUnderline) << int (textStyle.m_isStrikeThru);
+
+ stream << textStyle.m_foregroundColor << textStyle.m_backgroundColor;
+
+ stream << int (textStyle.m_isBackgroundOpaque);
+
+ return stream;
+}
+
+// friend
+QDataStream &operator>> (QDataStream &stream, kpTextStyle &textStyle)
+{
+ stream >> textStyle.m_fontFamily;
+ stream >> textStyle.m_fontSize;
+
+ int a, b, c, d;
+ stream >> a >> b >> c >> d;
+ textStyle.m_isBold = a;
+ textStyle.m_isItalic = b;
+ textStyle.m_isUnderline = c;
+ textStyle.m_isStrikeThru = d;
+
+ stream >> textStyle.m_foregroundColor >> textStyle.m_backgroundColor;
+
+ int e;
+ stream >> e;
+ textStyle.m_isBackgroundOpaque = e;
+
+ return stream;
+}
+
+// public
+bool kpTextStyle::operator== (const kpTextStyle &rhs) const
+{
+ return (m_fontFamily == rhs.m_fontFamily &&
+ m_fontSize == rhs.m_fontSize &&
+ m_isBold == rhs.m_isBold &&
+ m_isItalic == rhs.m_isItalic &&
+ m_isUnderline == rhs.m_isUnderline &&
+ m_isStrikeThru == rhs.m_isStrikeThru &&
+ m_foregroundColor == rhs.m_foregroundColor &&
+ m_backgroundColor == rhs.m_backgroundColor &&
+ m_isBackgroundOpaque == rhs.m_isBackgroundOpaque);
+}
+
+// public
+bool kpTextStyle::operator!= (const kpTextStyle &rhs) const
+{
+ return !(*this == rhs);
+}
+
+
+// public
+QString kpTextStyle::fontFamily () const
+{
+ return m_fontFamily;
+}
+
+// public
+void kpTextStyle::setFontFamily (const QString &f)
+{
+ m_fontFamily = f;
+}
+
+
+// public
+int kpTextStyle::fontSize () const
+{
+ return m_fontSize;
+}
+
+// public
+void kpTextStyle::setFontSize (int s)
+{
+ m_fontSize = s;
+}
+
+
+// public
+bool kpTextStyle::isBold () const
+{
+ return m_isBold;
+}
+
+// public
+void kpTextStyle::setBold (bool yes)
+{
+ m_isBold = yes;
+}
+
+
+// public
+bool kpTextStyle::isItalic () const
+{
+ return m_isItalic;
+}
+
+// public
+void kpTextStyle::setItalic (bool yes)
+{
+ m_isItalic = yes;
+}
+
+
+// public
+bool kpTextStyle::isUnderline () const
+{
+ return m_isUnderline;
+}
+
+// public
+void kpTextStyle::setUnderline (bool yes)
+{
+ m_isUnderline = yes;
+}
+
+
+// public
+bool kpTextStyle::isStrikeThru () const
+{
+ return m_isStrikeThru;
+}
+
+// public
+void kpTextStyle::setStrikeThru (bool yes)
+{
+ m_isStrikeThru = yes;
+}
+
+
+// public
+kpColor kpTextStyle::foregroundColor () const
+{
+ return m_foregroundColor;
+}
+
+// public
+void kpTextStyle::setForegroundColor (const kpColor &fcolor)
+{
+ m_foregroundColor = fcolor;
+}
+
+
+// public
+kpColor kpTextStyle::backgroundColor () const
+{
+ return m_backgroundColor;
+}
+
+// public
+void kpTextStyle::setBackgroundColor (const kpColor &bcolor)
+{
+ m_backgroundColor = bcolor;
+}
+
+
+// public
+bool kpTextStyle::isBackgroundOpaque () const
+{
+ return m_isBackgroundOpaque;
+}
+
+// public
+void kpTextStyle::setBackgroundOpaque (bool yes)
+{
+ m_isBackgroundOpaque = yes;
+}
+
+
+// public
+bool kpTextStyle::isBackgroundTransparent () const
+{
+ return !m_isBackgroundOpaque;
+}
+
+// public
+void kpTextStyle::setBackgroundTransparent (bool yes)
+{
+ m_isBackgroundOpaque = !yes;
+}
+
+
+// public
+kpColor kpTextStyle::effectiveBackgroundColor () const
+{
+ if (isBackgroundOpaque ())
+ return backgroundColor ();
+ else
+ return kpColor::transparent;
+}
+
+
+// public
+QFont kpTextStyle::font () const
+{
+ QFont fnt (m_fontFamily, m_fontSize);
+ fnt.setBold (m_isBold);
+ fnt.setItalic (m_isItalic);
+ fnt.setUnderline (m_isUnderline);
+ fnt.setStrikeOut (m_isStrikeThru);
+
+ return fnt;
+}
+
+// public
+QFontMetrics kpTextStyle::fontMetrics () const
+{
+ return QFontMetrics (font ());
+}
diff --git a/kolourpaint/kptextstyle.h b/kolourpaint/kptextstyle.h
new file mode 100644
index 00000000..9356ce2c
--- /dev/null
+++ b/kolourpaint/kptextstyle.h
@@ -0,0 +1,108 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __kp_text_style_h__
+#define __kp_text_style_h__
+
+#include <qstring.h>
+
+#include <kpcolor.h>
+
+class QDataStream;
+class QFont;
+class QFontMetrics;
+
+class kpTextStyle
+{
+public:
+ kpTextStyle ();
+ kpTextStyle (const QString &fontFamily,
+ int fontSize,
+ bool isBold, bool isItalic,
+ bool isUnderline, bool isStrikeThru,
+ const kpColor &fcolor,
+ const kpColor &bcolor,
+ bool isBackgroundOpaque);
+ ~kpTextStyle ();
+
+
+ friend QDataStream &operator<< (QDataStream &stream, const kpTextStyle &textStyle);
+ friend QDataStream &operator>> (QDataStream &stream, kpTextStyle &textStyle);
+ bool operator== (const kpTextStyle &rhs) const;
+ bool operator!= (const kpTextStyle &rhs) const;
+
+
+ QString fontFamily () const;
+ void setFontFamily (const QString &f);
+
+ int fontSize () const;
+ void setFontSize (int s);
+
+ bool isBold () const;
+ void setBold (bool yes = true);
+
+ bool isItalic () const;
+ void setItalic (bool yes = true);
+
+ bool isUnderline () const;
+ void setUnderline (bool yes = true);
+
+ bool isStrikeThru () const;
+ void setStrikeThru (bool yes = true);
+
+ kpColor foregroundColor () const;
+ void setForegroundColor (const kpColor &fcolor);
+
+ // Note: This is the _input_ backgroundColor without applying any
+ // isBackground(Opaque|Transparent)() transformation.
+ // See effectiveBackgroundColor().
+ kpColor backgroundColor () const;
+ void setBackgroundColor (const kpColor &bcolor);
+
+ bool isBackgroundOpaque () const;
+ void setBackgroundOpaque (bool yes = true);
+
+ bool isBackgroundTransparent () const;
+ void setBackgroundTransparent (bool yes = true);
+
+
+ // If isBackgroundOpaque(), returns backgroundColor().
+ // Else, returns kpColor::transparent.
+ kpColor effectiveBackgroundColor () const;
+
+ QFont font () const;
+ QFontMetrics fontMetrics () const;
+
+private:
+ QString m_fontFamily;
+ int m_fontSize;
+ bool m_isBold, m_isItalic, m_isUnderline, m_isStrikeThru;
+ kpColor m_foregroundColor, m_backgroundColor;
+ bool m_isBackgroundOpaque;
+};
+
+#endif // __kp_text_style_h__
diff --git a/kolourpaint/kpthumbnail.cpp b/kolourpaint/kpthumbnail.cpp
new file mode 100644
index 00000000..a45164ac
--- /dev/null
+++ b/kolourpaint/kpthumbnail.cpp
@@ -0,0 +1,213 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_THUMBNAIL 0
+
+#include <kpthumbnail.h>
+
+#include <qdockarea.h>
+#include <qdockwindow.h>
+#include <qtimer.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kpthumbnailview.h>
+#include <kptool.h>
+
+
+// TODO: get out of the Alt+Tab list
+kpThumbnail::kpThumbnail (kpMainWindow *parent, const char *name)
+#if KP_IS_QT_3_3
+ : QDockWindow (QDockWindow::OutsideDock, parent, name),
+#else // With Qt <3.3, OutsideDock requires parent = 0,
+ // sync: make sure outside of dock
+ : QDockWindow (QDockWindow::InDock, parent, name),
+ #warning "Using Qt <3.3: the thumbnail will flicker more when appearing"
+#endif
+ m_mainWindow (parent),
+ m_view (0)
+{
+ if (!parent)
+ kdError () << "kpThumbnail::kpThumbnail() requires parent" << endl;
+
+
+#if !KP_IS_QT_3_3
+ if (parent)
+ {
+ hide ();
+
+ // sync: make sure outside of dock
+ parent->moveDockWindow (this, Qt::DockTornOff);
+ }
+#endif
+
+
+ if (parent)
+ {
+ // Prevent thumbnail from docking - it's _really_ irritating otherwise
+ parent->leftDock ()->setAcceptDockWindow (this, false);
+ parent->rightDock ()->setAcceptDockWindow (this, false);
+ parent->topDock ()->setAcceptDockWindow (this, false);
+ parent->bottomDock ()->setAcceptDockWindow (this, false);
+ }
+
+
+ QSize layoutMinimumSize = layout () ? layout ()->minimumSize () : QSize ();
+#if DEBUG_KP_THUMBNAIL
+ kdDebug () << "\tlayout=" << layout ()
+ << " minSize=" << (layout () ? layout ()->minimumSize () : QSize ()) << endl;
+ kdDebug () << "\tboxLayout=" << boxLayout ()
+ << " minSize=" << (boxLayout () ? boxLayout ()->minimumSize () : QSize ())
+ << endl;
+#endif
+ if (layout ())
+ layout ()->setResizeMode (QLayout::FreeResize);
+ setMinimumSize (QMAX (layoutMinimumSize.width (), 64),
+ QMAX (layoutMinimumSize.height (), 64));
+
+
+ // Enable "X" Close Button
+ setCloseMode (QDockWindow::Always);
+
+ setResizeEnabled (true);
+
+ updateCaption ();
+}
+
+kpThumbnail::~kpThumbnail ()
+{
+}
+
+
+// public
+kpThumbnailView *kpThumbnail::view () const
+{
+ return m_view;
+}
+
+// public
+void kpThumbnail::setView (kpThumbnailView *view)
+{
+#if DEBUG_KP_THUMBNAIL
+ kdDebug () << "kpThumbnail::setView(" << view << ")" << endl;
+#endif
+
+ if (m_view == view)
+ return;
+
+
+ if (m_view)
+ {
+ disconnect (m_view, SIGNAL (destroyed ()),
+ this, SLOT (slotViewDestroyed ()));
+ disconnect (m_view, SIGNAL (zoomLevelChanged (int, int)),
+ this, SLOT (updateCaption ()));
+
+ boxLayout ()->remove (m_view);
+ }
+
+ m_view = view;
+
+ if (m_view)
+ {
+ connect (m_view, SIGNAL (destroyed ()),
+ this, SLOT (slotViewDestroyed ()));
+ connect (m_view, SIGNAL (zoomLevelChanged (int, int)),
+ this, SLOT (updateCaption ()));
+ updateCaption ();
+
+ boxLayout ()->addWidget (m_view);
+ m_view->show ();
+ }
+}
+
+
+// public slot
+void kpThumbnail::updateCaption ()
+{
+ setCaption (view () ? view ()->caption () : i18n ("Thumbnail"));
+}
+
+
+// public slot virtual [base QDockWindow]
+void kpThumbnail::dock ()
+{
+#if DEBUG_KP_THUMBNAIL
+ kdDebug () << "kpThumbnail::dock() CALLED - ignoring request" << endl;
+#endif
+
+ // --- ignore all requests to dock ---
+}
+
+
+// protected slot
+void kpThumbnail::slotViewDestroyed ()
+{
+#if DEBUG_KP_THUMBNAIL
+ kdDebug () << "kpThumbnail::slotViewDestroyed()" << endl;
+#endif
+
+ m_view = 0;
+ updateCaption ();
+}
+
+
+// protected virtual [base QWidget]
+void kpThumbnail::resizeEvent (QResizeEvent *e)
+{
+#if DEBUG_KP_THUMBNAIL
+ kdDebug () << "kpThumbnail::resizeEvent(" << width ()
+ << "," << height () << ")" << endl;
+#endif
+
+ QDockWindow::resizeEvent (e);
+
+ // updateVariableZoom (); TODO: is below a good idea since this commented out
+
+ if (m_mainWindow)
+ {
+ m_mainWindow->notifyThumbnailGeometryChanged ();
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+}
+
+// protected virtual [base QWidget]
+void kpThumbnail::moveEvent (QMoveEvent * /*e*/)
+{
+ if (m_mainWindow)
+ m_mainWindow->notifyThumbnailGeometryChanged ();
+}
+
+
+#include <kpthumbnail.moc>
diff --git a/kolourpaint/kpthumbnail.h b/kolourpaint/kpthumbnail.h
new file mode 100644
index 00000000..183dc2f1
--- /dev/null
+++ b/kolourpaint/kpthumbnail.h
@@ -0,0 +1,68 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kp_thumbnail_h__
+#define __kp_thumbnail_h__
+
+#include <qdockwindow.h>
+
+class kpMainWindow;
+class kpThumbnailView;
+
+
+class kpThumbnail : public QDockWindow
+{
+Q_OBJECT
+
+public:
+ kpThumbnail (kpMainWindow *parent, const char *name = 0);
+ virtual ~kpThumbnail ();
+
+public:
+ kpThumbnailView *view () const;
+ void setView (kpThumbnailView *view);
+
+public slots:
+ void updateCaption ();
+
+ virtual void dock ();
+
+protected slots:
+ void slotViewDestroyed ();
+
+protected:
+ virtual void resizeEvent (QResizeEvent *e);
+ virtual void moveEvent (QMoveEvent *e);
+
+private:
+ kpMainWindow *m_mainWindow;
+ kpThumbnailView *m_view;
+};
+
+
+#endif // __kp_thumbnail_h__
diff --git a/kolourpaint/kptool.cpp b/kolourpaint/kptool.cpp
new file mode 100644
index 00000000..8d337c5b
--- /dev/null
+++ b/kolourpaint/kptool.cpp
@@ -0,0 +1,1666 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_TOOL 0
+
+
+#include <kptool.h>
+
+#include <limits.h>
+
+#include <qapplication.h>
+#include <qclipboard.h>
+#include <qcursor.h>
+#include <qevent.h>
+#include <qlayout.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include <kpcolor.h>
+#include <kpcolortoolbar.h>
+#include <kpdefs.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kpsinglekeytriggersaction.h>
+#include <kptoolaction.h>
+#include <kptooltoolbar.h>
+#include <kpview.h>
+#include <kpviewmanager.h>
+
+
+//
+// kpTool
+//
+
+struct kpToolPrivate
+{
+};
+
+
+kpTool::kpTool (const QString &text, const QString &description,
+ int key,
+ kpMainWindow *mainWindow, const char *name)
+{
+ init (text, description, key, mainWindow, name);
+}
+
+kpTool::~kpTool ()
+{
+ // before destructing, stop using the tool
+ if (m_began)
+ endInternal ();
+
+ if (m_action)
+ {
+ if (m_mainWindow && m_mainWindow->actionCollection ())
+ m_mainWindow->actionCollection ()->remove (m_action);
+ else
+ delete m_action;
+ }
+
+ delete d;
+}
+
+
+// private
+void kpTool::init (const QString &text, const QString &description,
+ int key,
+ kpMainWindow *mainWindow, const char *name)
+{
+ d = new kpToolPrivate ();
+
+ m_key = key;
+ m_action = 0;
+ m_ignoreColorSignals = 0;
+ m_shiftPressed = false, m_controlPressed = false, m_altPressed = false; // set in beginInternal()
+ m_beganDraw = false;
+ m_text = text, m_description = description, m_name = name;
+ m_mainWindow = mainWindow;
+ m_began = false;
+ m_viewUnderStartPoint = 0;
+ m_userShapeStartPoint = KP_INVALID_POINT;
+ m_userShapeEndPoint = KP_INVALID_POINT;
+ m_userShapeSize = KP_INVALID_SIZE;
+
+ createAction ();
+}
+
+
+// private
+void kpTool::createAction ()
+{
+#if DEBUG_KP_TOOL && 0
+ kdDebug () << "kpTool(" << name () << "::createAction()" << endl;
+#endif
+
+ if (!m_mainWindow)
+ {
+ kdError () << "kpTool::createAction() without mw" << endl;
+ return;
+ }
+
+ KActionCollection *ac = m_mainWindow->actionCollection ();
+ if (!ac)
+ {
+ kdError () << "kpTool::createAction() without ac" << endl;
+ return;
+ }
+
+
+ if (m_action)
+ {
+ // TODO: I don't think this will ever be executed as we are not called
+ // outside of the constructor.
+ #if DEBUG_KP_TOOL
+ kdDebug () << "\tdeleting existing" << endl;
+ #endif
+ ac->remove (m_action);
+ m_action = 0;
+ }
+
+
+ m_action = new kpToolAction (text (), iconName (), shortcutForKey (m_key),
+ this, SLOT (slotActionActivated ()),
+ m_mainWindow->actionCollection (), name ());
+ m_action->setExclusiveGroup (QString::fromLatin1 ("Tool Box Actions"));
+ m_action->setWhatsThis (description ());
+
+ connect (m_action, SIGNAL (toolTipChanged (const QString &)),
+ this, SLOT (slotActionToolTipChanged (const QString &)));
+}
+
+
+// protected slot
+void kpTool::slotActionToolTipChanged (const QString &string)
+{
+ emit actionToolTipChanged (string);
+}
+
+
+// public
+QString kpTool::text () const
+{
+ return m_text;
+}
+
+// public
+void kpTool::setText (const QString &text)
+{
+ m_text = text;
+
+ if (m_action)
+ m_action->setText (m_text);
+ else
+ createAction ();
+}
+
+
+// public static
+QString kpTool::toolTipForTextAndShortcut (const QString &text,
+ const KShortcut &shortcut)
+{
+ for (int i = 0; i < (int) shortcut.count (); i++)
+ {
+ const KKeySequence seq = shortcut.seq (i);
+ if (seq.count () == 1 && containsSingleKeyTrigger (seq))
+ {
+ return i18n ("<Tool Name> (<Single Accel Key>)",
+ "%1 (%2)")
+ .arg (text, seq.toString ());
+ }
+ }
+
+ return text;
+}
+
+// public static
+QString kpTool::toolTip () const
+{
+ return toolTipForTextAndShortcut (text (), shortcut ());
+}
+
+
+// public
+int kpTool::key () const
+{
+ return m_key;
+}
+
+// public
+void kpTool::setKey (int key)
+{
+ m_key = key;
+
+ if (m_action)
+ // TODO: this probably not wise since it nukes the user's settings
+ m_action->setShortcut (shortcutForKey (m_key));
+ else
+ createAction ();
+}
+
+// public static
+KShortcut kpTool::shortcutForKey (int key)
+{
+ KShortcut shortcut;
+
+ if (key)
+ {
+ shortcut.append (KKeySequence (KKey (key)));
+ // (CTRL+<key>, ALT+<key>, CTRL+ALT+<key>, CTRL+SHIFT+<key>
+ // all clash with global KDE shortcuts)
+ shortcut.append (KKeySequence (KKey (Qt::ALT + Qt::SHIFT + key)));
+ }
+
+ return shortcut;
+}
+
+// public
+KShortcut kpTool::shortcut () const
+{
+ return m_action ? m_action->shortcut () : KShortcut ();
+}
+
+
+// public static
+bool kpTool::keyIsText (int key)
+{
+ // TODO: should work like !QKeyEvent::text().isEmpty()
+ return !(key & (Qt::MODIFIER_MASK ^ Qt::SHIFT));
+}
+
+// public static
+bool kpTool::containsSingleKeyTrigger (const KKeySequence &seq)
+{
+ for (int i = 0; i < (int) seq.count (); i++)
+ {
+ const KKey key = seq.key (i);
+ if (keyIsText (key.keyCodeQt ()))
+ return true;
+ }
+
+ return false;
+}
+
+// public static
+bool kpTool::containsSingleKeyTrigger (const KShortcut &shortcut,
+ KShortcut *shortcutWithoutSingleKeyTriggers)
+{
+ if (shortcutWithoutSingleKeyTriggers)
+ *shortcutWithoutSingleKeyTriggers = shortcut;
+
+
+ KShortcut newShortcut;
+ bool needNewShortcut = false;
+
+ for (int i = 0; i < (int) shortcut.count (); i++)
+ {
+ const KKeySequence seq = shortcut.seq (i);
+
+ if (containsSingleKeyTrigger (seq))
+ {
+ needNewShortcut = true;
+ }
+ else
+ {
+ newShortcut.append (seq);
+ }
+ }
+
+
+ if (needNewShortcut && shortcutWithoutSingleKeyTriggers)
+ *shortcutWithoutSingleKeyTriggers = newShortcut;
+
+ return needNewShortcut;
+}
+
+
+// public
+bool kpTool::singleKeyTriggersEnabled () const
+{
+ return (m_action ? m_action->singleKeyTriggersEnabled () : true);
+}
+
+// public
+void kpTool::enableSingleKeyTriggers (bool enable)
+{
+#if DEBUG_KP_TOOL && 0
+ kdDebug () << "kpTool(" << name () << ")::enableSingleKeyTriggers("
+ << enable << ")" << endl;
+#endif
+
+ if (!m_action)
+ {
+ #if DEBUG_KP_TOOL && 0
+ kdDebug () << "\tno action" << endl;
+ #endif
+ return;
+ }
+
+ m_action->enableSingleKeyTriggers (enable);
+}
+
+
+// public
+QString kpTool::description () const
+{
+ return m_description;
+}
+
+// public
+void kpTool::setDescription (const QString &description)
+{
+ m_description = description;
+
+ if (m_action)
+ m_action->setWhatsThis (m_description);
+ else
+ createAction ();
+}
+
+
+// public
+const char *kpTool::name () const
+{
+ return m_name;
+}
+
+
+// static
+QRect kpTool::neededRect (const QRect &rect, int lineWidth)
+{
+ int x1, y1, x2, y2;
+ rect.coords (&x1, &y1, &x2, &y2);
+
+ if (lineWidth < 1)
+ lineWidth = 1;
+
+ return QRect (QPoint (x1 - lineWidth + 1, y1 - lineWidth + 1),
+ QPoint (x2 + lineWidth - 1, y2 + lineWidth - 1));
+}
+
+// static
+QPixmap kpTool::neededPixmap (const QPixmap &pixmap, const QRect &boundingRect)
+{
+ return kpPixmapFX::getPixmapAt (pixmap, boundingRect);
+}
+
+
+// public
+bool kpTool::hasCurrentPoint () const
+{
+ return (viewUnderStartPoint () || viewUnderCursor ());
+}
+
+// public
+QPoint kpTool::currentPoint (bool zoomToDoc) const
+{
+#if DEBUG_KP_TOOL && 0
+ kdDebug () << "kpTool::currentPoint(zoomToDoc=" << zoomToDoc << ")" << endl;
+ kdDebug () << "\tviewUnderStartPoint="
+ << (viewUnderStartPoint () ? viewUnderStartPoint ()->name () : "(none)")
+ << " viewUnderCursor="
+ << (viewUnderCursor () ? viewUnderCursor ()->name () : "(none)")
+ << endl;
+#endif
+
+ kpView *v = viewUnderStartPoint ();
+ if (!v)
+ {
+ v = viewUnderCursor ();
+ if (!v)
+ {
+ #if DEBUG_KP_TOOL && 0
+ kdDebug () << "\tno view - returning sentinel" << endl;
+ #endif
+ return KP_INVALID_POINT;
+ }
+ }
+
+
+ const QPoint globalPos = QCursor::pos ();
+ const QPoint viewPos = v->mapFromGlobal (globalPos);
+#if DEBUG_KP_TOOL && 0
+ kdDebug () << "\tglobalPos=" << globalPos
+ << " viewPos=" << viewPos
+ << endl;
+#endif
+ if (!zoomToDoc)
+ return viewPos;
+
+
+ const QPoint docPos = v->transformViewToDoc (viewPos);
+#if DEBUG_KP_TOOL && 0
+ kdDebug () << "\tdocPos=" << docPos << endl;
+#endif
+ return docPos;
+}
+
+
+// public slot
+void kpTool::somethingBelowTheCursorChanged ()
+{
+ somethingBelowTheCursorChanged (currentPoint (),
+ currentPoint (false/*view point*/));
+}
+
+// private
+// TODO: don't dup code from mouseMoveEvent()
+void kpTool::somethingBelowTheCursorChanged (const QPoint &currentPoint_,
+ const QPoint &currentViewPoint_)
+{
+#if DEBUG_KP_TOOL && 0
+ kdDebug () << "kpTool::somethingBelowTheCursorChanged(docPoint="
+ << currentPoint_
+ << " viewPoint="
+ << currentViewPoint_
+ << ")" << endl;
+ kdDebug () << "\tviewUnderStartPoint="
+ << (viewUnderStartPoint () ? viewUnderStartPoint ()->name () : "(none)")
+ << " viewUnderCursor="
+ << (viewUnderCursor () ? viewUnderCursor ()->name () : "(none)")
+ << endl;
+ kdDebug () << "\tbegan draw=" << m_beganDraw << endl;
+#endif
+
+ m_currentPoint = currentPoint_;
+ m_currentViewPoint = currentViewPoint_;
+
+ if (m_beganDraw)
+ {
+ if (m_currentPoint != KP_INVALID_POINT)
+ {
+ draw (m_currentPoint, m_lastPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+ m_lastPoint = m_currentPoint;
+ }
+ }
+ else
+ {
+ hover (m_currentPoint);
+ }
+}
+
+
+void kpTool::beginInternal ()
+{
+#if DEBUG_KP_TOOL
+ kdDebug () << "kpTool::beginInternal()" << endl;
+#endif
+
+ if (!m_began)
+ {
+ // clear leftover statusbar messages
+ setUserMessage ();
+ m_currentPoint = currentPoint ();
+ m_currentViewPoint = currentPoint (false/*view point*/);
+ setUserShapePoints (m_currentPoint);
+
+ // TODO: Audit all the code in this file - states like "m_began" &
+ // "m_beganDraw" should be set before calling user func.
+ // Also, m_currentPoint should be more frequently initialised.
+
+ // call user virtual func
+ begin ();
+
+ // we've starting using the tool...
+ m_began = true;
+
+ // but we haven't started drawing with it
+ m_beganDraw = false;
+
+
+ uint keyState = KApplication::keyboardModifiers ();
+
+ m_shiftPressed = (keyState & KApplication::ShiftModifier);
+ m_controlPressed = (keyState & KApplication::ControlModifier);
+
+ // TODO: Can't do much about ALT - unless it's always KApplication::Modifier1?
+ // Ditto for everywhere else where I set SHIFT & CTRL but not alt.
+ m_altPressed = false;
+ }
+}
+
+void kpTool::endInternal ()
+{
+ if (m_began)
+ {
+ // before we can stop using the tool, we must stop the current drawing operation (if any)
+ if (hasBegunShape ())
+ endShapeInternal (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ // call user virtual func
+ end ();
+
+ // clear leftover statusbar messages
+ setUserMessage ();
+ setUserShapePoints (currentPoint ());
+
+ // we've stopped using the tool...
+ m_began = false;
+
+ // and so we can't be drawing with it
+ m_beganDraw = false;
+
+ if (m_mainWindow)
+ {
+ kpToolToolBar *tb = m_mainWindow->toolToolBar ();
+ if (tb)
+ {
+ tb->hideAllToolWidgets ();
+ }
+ }
+
+ }
+}
+
+// virtual
+void kpTool::begin ()
+{
+#if DEBUG_KP_TOOL
+ kdDebug () << "kpTool::begin() base implementation" << endl;
+#endif
+}
+
+// virtual
+void kpTool::end ()
+{
+#if DEBUG_KP_TOOL
+ kdDebug () << "kpTool::end() base implementation" << endl;
+#endif
+}
+
+void kpTool::beginDrawInternal ()
+{
+ if (!m_beganDraw)
+ {
+ beginDraw ();
+
+ m_beganDraw = true;
+ emit beganDraw (m_currentPoint);
+ }
+}
+
+// virtual
+void kpTool::beginDraw ()
+{
+}
+
+// virtual
+void kpTool::hover (const QPoint &point)
+{
+#if DEBUG_KP_TOOL
+ kdDebug () << "kpTool::hover" << point
+ << " base implementation"
+ << endl;
+#endif
+
+ setUserShapePoints (point);
+}
+
+// virtual
+void kpTool::globalDraw ()
+{
+}
+
+// virtual
+void kpTool::reselect ()
+{
+#if DEBUG_KP_TOOL
+ kdDebug () << "kpTool::reselect() base implementation" << endl;
+#endif
+}
+
+
+// public
+QIconSet kpTool::iconSet (int forceSize) const
+{
+#if DEBUG_KP_TOOL && 0
+ kdDebug () << "kpTool(" << name () << ")::iconSet(forceSize=" << forceSize << ")" << endl;
+#endif
+ // (robust in case BarIcon() default arg changes)
+ if (forceSize > 0)
+ return BarIconSet (name (), forceSize);
+ else
+ return BarIconSet (name ());
+}
+
+// public
+QString kpTool::iconName () const
+{
+ return name ();
+}
+
+// public
+kpToolAction *kpTool::action ()
+{
+ if (!m_action)
+ createAction ();
+
+ return m_action;
+}
+
+
+// protected slots
+void kpTool::slotActionActivated ()
+{
+ emit actionActivated ();
+}
+
+
+// virtual
+void kpTool::draw (const QPoint &, const QPoint &, const QRect &)
+{
+}
+
+// also called by kpView
+void kpTool::cancelShapeInternal ()
+{
+ if (hasBegunShape ())
+ {
+ m_beganDraw = false;
+ cancelShape ();
+ m_viewUnderStartPoint = 0;
+
+ emit cancelledShape (viewUnderCursor () ? m_currentPoint : KP_INVALID_POINT);
+
+ if (viewUnderCursor ())
+ hover (m_currentPoint);
+ else
+ {
+ m_currentPoint = KP_INVALID_POINT;
+ m_currentViewPoint = KP_INVALID_POINT;
+ hover (m_currentPoint);
+ }
+
+ if (returnToPreviousToolAfterEndDraw ())
+ {
+ kpToolToolBar *tb = mainWindow ()->toolToolBar ();
+
+ // (don't end up with no tool selected)
+ if (tb->previousTool ())
+ {
+ // endInternal() will be called by kpMainWindow (thanks to this line)
+ // so we won't have the view anymore
+ tb->selectPreviousTool ();
+ }
+ }
+ }
+}
+
+// virtual
+void kpTool::cancelShape ()
+{
+ kdWarning () << "Tool cannot cancel operation!" << endl;
+}
+
+void kpTool::releasedAllButtons ()
+{
+}
+
+void kpTool::endDrawInternal (const QPoint &thisPoint, const QRect &normalizedRect,
+ bool wantEndShape)
+{
+#if DEBUG_KP_TOOL && 1
+ kdDebug () << "kpTool::endDrawInternal() wantEndShape=" << wantEndShape << endl;
+#endif
+
+ if (wantEndShape && !hasBegunShape ())
+ return;
+ else if (!wantEndShape && !hasBegunDraw ())
+ return;
+
+ m_beganDraw = false;
+
+ if (wantEndShape)
+ {
+ #if DEBUG_KP_TOOL && 0
+ kdDebug () << "\tcalling endShape()" << endl;
+ #endif
+ endShape (thisPoint, normalizedRect);
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL && 0
+ kdDebug () << "\tcalling endDraw()" << endl;
+ #endif
+ endDraw (thisPoint, normalizedRect);
+ }
+ m_viewUnderStartPoint = 0;
+
+ emit endedDraw (m_currentPoint);
+ if (viewUnderCursor ())
+ hover (m_currentPoint);
+ else
+ {
+ m_currentPoint = KP_INVALID_POINT;
+ m_currentViewPoint = KP_INVALID_POINT;
+ hover (m_currentPoint);
+ }
+
+ if (returnToPreviousToolAfterEndDraw ())
+ {
+ kpToolToolBar *tb = mainWindow ()->toolToolBar ();
+
+ // (don't end up with no tool selected)
+ if (tb->previousTool ())
+ {
+ // endInternal() will be called by kpMainWindow (thanks to this line)
+ // so we won't have the view anymore
+ tb->selectPreviousTool ();
+ }
+ }
+}
+
+// private
+void kpTool::endShapeInternal (const QPoint &thisPoint, const QRect &normalizedRect)
+{
+ endDrawInternal (thisPoint, normalizedRect, true/*end shape*/);
+}
+
+// virtual
+void kpTool::endDraw (const QPoint &, const QRect &)
+{
+}
+
+kpMainWindow *kpTool::mainWindow () const
+{
+ return m_mainWindow;
+}
+
+kpDocument *kpTool::document () const
+{
+ return m_mainWindow ? m_mainWindow->document () : 0;
+}
+
+kpView *kpTool::viewUnderCursor () const
+{
+ kpViewManager *vm = viewManager ();
+ return vm ? vm->viewUnderCursor () : 0;
+}
+
+kpViewManager *kpTool::viewManager () const
+{
+ return m_mainWindow ? m_mainWindow->viewManager () : 0;
+}
+
+kpToolToolBar *kpTool::toolToolBar () const
+{
+ return m_mainWindow ? m_mainWindow->toolToolBar () : 0;
+}
+
+kpColor kpTool::color (int which) const
+{
+ if (m_mainWindow)
+ return m_mainWindow->colorToolBar ()->color (which);
+ else
+ {
+ kdError () << "kpTool::color () without mainWindow" << endl;
+ return kpColor::invalid;
+ }
+}
+
+kpColor kpTool::foregroundColor () const
+{
+ return color (0);
+}
+
+kpColor kpTool::backgroundColor () const
+{
+ return color (1);
+}
+
+
+double kpTool::colorSimilarity () const
+{
+ if (m_mainWindow)
+ return m_mainWindow->colorToolBar ()->colorSimilarity ();
+ else
+ {
+ kdError () << "kpTool::colorSimilarity() without mainWindow" << endl;
+ return 0;
+ }
+}
+
+int kpTool::processedColorSimilarity () const
+{
+ if (m_mainWindow)
+ return m_mainWindow->colorToolBar ()->processedColorSimilarity ();
+ else
+ {
+ kdError () << "kpTool::processedColorSimilarity() without mainWindow" << endl;
+ return kpColor::Exact;
+ }
+}
+
+
+kpColor kpTool::oldForegroundColor () const
+{
+ if (m_mainWindow)
+ return m_mainWindow->colorToolBar ()->oldForegroundColor ();
+ else
+ {
+ kdError () << "kpTool::oldForegroundColor() without mainWindow" << endl;
+ return kpColor::invalid;
+ }
+}
+
+kpColor kpTool::oldBackgroundColor () const
+{
+ if (m_mainWindow)
+ return m_mainWindow->colorToolBar ()->oldBackgroundColor ();
+ else
+ {
+ kdError () << "kpTool::oldBackgroundColor() without mainWindow" << endl;
+ return kpColor::invalid;
+ }
+}
+
+double kpTool::oldColorSimilarity () const
+{
+ if (m_mainWindow)
+ return m_mainWindow->colorToolBar ()->oldColorSimilarity ();
+ else
+ {
+ kdError () << "kpTool::oldColorSimilarity() without mainWindow" << endl;
+ return 0;
+ }
+}
+
+
+void kpTool::slotColorsSwappedInternal (const kpColor &newForegroundColor,
+ const kpColor &newBackgroundColor)
+{
+ if (careAboutColorsSwapped ())
+ {
+ slotColorsSwapped (newForegroundColor, newBackgroundColor);
+ m_ignoreColorSignals = 2;
+ }
+ else
+ m_ignoreColorSignals = 0;
+}
+
+void kpTool::slotForegroundColorChangedInternal (const kpColor &color)
+{
+ if (m_ignoreColorSignals > 0)
+ {
+ #if DEBUG_KP_TOOL && 1
+ kdDebug () << "kpTool::slotForegroundColorChangedInternal() ignoreColorSignals=" << m_ignoreColorSignals << endl;
+ #endif
+ m_ignoreColorSignals--;
+ return;
+ }
+
+ slotForegroundColorChanged (color);
+}
+
+void kpTool::slotBackgroundColorChangedInternal (const kpColor &color)
+{
+ if (m_ignoreColorSignals > 0)
+ {
+ #if DEBUG_KP_TOOL && 1
+ kdDebug () << "kpTool::slotBackgroundColorChangedInternal() ignoreColorSignals=" << m_ignoreColorSignals << endl;
+ #endif
+ m_ignoreColorSignals--;
+ return;
+ }
+
+ slotBackgroundColorChanged (color);
+}
+
+void kpTool::slotColorSimilarityChangedInternal (double similarity, int processedSimilarity)
+{
+ slotColorSimilarityChanged (similarity, processedSimilarity);
+}
+
+bool kpTool::currentPointNextToLast () const
+{
+ if (m_lastPoint == QPoint (-1, -1))
+ return true;
+
+ int dx = kAbs (m_currentPoint.x () - m_lastPoint.x ());
+ int dy = kAbs (m_currentPoint.y () - m_lastPoint.y ());
+
+ return (dx <= 1 && dy <= 1);
+}
+
+bool kpTool::currentPointCardinallyNextToLast () const
+{
+ if (m_lastPoint == QPoint (-1, -1))
+ return true;
+
+ int dx = kAbs (m_currentPoint.x () - m_lastPoint.x ());
+ int dy = kAbs (m_currentPoint.y () - m_lastPoint.y ());
+
+ return (dx + dy <= 1);
+}
+
+kpCommandHistory *kpTool::commandHistory () const
+{
+ return m_mainWindow ? m_mainWindow->commandHistory () : 0;
+}
+
+void kpTool::mousePressEvent (QMouseEvent *e)
+{
+#if DEBUG_KP_TOOL && 1
+ kdDebug () << "kpTool::mousePressEvent pos=" << e->pos ()
+ << " btnStateBefore=" << (int) e->state ()
+ << " btnStateAfter=" << (int) e->stateAfter ()
+ << " button=" << (int) e->button ()
+ << " beganDraw=" << m_beganDraw << endl;
+#endif
+
+ // state of all the buttons - not just the one that triggered the event (button())
+ Qt::ButtonState buttonState = e->stateAfter ();
+
+ if (m_mainWindow && e->button () == Qt::MidButton)
+ {
+ const QString text = QApplication::clipboard ()->text (QClipboard::Selection);
+ #if DEBUG_KP_TOOL && 1
+ kdDebug () << "\tMMB pasteText='" << text << "'" << endl;
+ #endif
+ if (!text.isEmpty ())
+ {
+ if (hasBegunShape ())
+ {
+ #if DEBUG_KP_TOOL && 1
+ kdDebug () << "\t\thasBegunShape - end" << endl;
+ #endif
+ endShapeInternal (m_currentPoint,
+ QRect (m_startPoint, m_currentPoint).normalize ());
+ }
+
+ if (viewUnderCursor ())
+ {
+ m_mainWindow->pasteTextAt (text,
+ viewUnderCursor ()->transformViewToDoc (e->pos ()),
+ true/*adjust topLeft so that cursor isn't
+ on top of resize handle*/);
+ }
+
+ return;
+ }
+ }
+
+ int mb = mouseButton (buttonState);
+#if DEBUG_KP_TOOL && 1
+ kdDebug () << "\tmb=" << mb << " m_beganDraw=" << m_beganDraw << endl;
+#endif
+
+ if (mb == -1 && !m_beganDraw) return; // ignore
+
+ if (m_beganDraw)
+ {
+ if (mb == -1 || mb != m_mouseButton)
+ {
+ #if DEBUG_KP_TOOL && 1
+ kdDebug () << "\tCancelling operation as " << mb << " == -1 or != " << m_mouseButton << endl;
+ #endif
+
+ kpView *view = viewUnderStartPoint ();
+ if (!view)
+ {
+ kdError () << "kpTool::mousePressEvent() cancel without a view under the start point!" << endl;
+ }
+
+ // if we get a mousePressEvent when we're drawing, then the other
+ // mouse button must have been pressed
+ m_currentPoint = view ? view->transformViewToDoc (e->pos ()) : QPoint (-1, -1);
+ m_currentViewPoint = view ? e->pos () : QPoint (-1, -1);
+ cancelShapeInternal ();
+ }
+
+ return;
+ }
+
+ kpView *view = viewUnderCursor ();
+ if (!view)
+ {
+ kdError () << "kpTool::mousePressEvent() without a view under the cursor!" << endl;
+ }
+
+#if DEBUG_KP_TOOL && 1
+ if (view)
+ kdDebug () << "\tview=" << view->name () << endl;
+#endif
+
+
+ // let user know what mouse button is being used for entire draw
+ m_mouseButton = mouseButton (buttonState);
+ m_shiftPressed = (buttonState & Qt::ShiftButton);
+ m_controlPressed = (buttonState & Qt::ControlButton);
+ m_altPressed = (buttonState & Qt::AltButton);
+ m_startPoint = m_currentPoint = view ? view->transformViewToDoc (e->pos ()) : QPoint (-1, -1);
+ m_currentViewPoint = view ? e->pos () : QPoint (-1, -1);
+ m_viewUnderStartPoint = view;
+ m_lastPoint = QPoint (-1, -1);
+
+#if DEBUG_KP_TOOL && 1
+ kdDebug () << "\tBeginning draw @ " << m_currentPoint << endl;
+#endif
+
+ beginDrawInternal ();
+
+ draw (m_currentPoint, m_lastPoint, QRect (m_currentPoint, m_currentPoint));
+ m_lastPoint = m_currentPoint;
+}
+
+void kpTool::mouseMoveEvent (QMouseEvent *e)
+{
+#if DEBUG_KP_TOOL && 0
+ kdDebug () << "kpTool::mouseMoveEvent pos=" << e->pos ()
+ << " btnStateAfter=" << (int) e->stateAfter () << endl;
+ kpView *v0 = viewUnderCursor (),
+ *v1 = viewManager ()->viewUnderCursor (true/*use Qt*/),
+ *v2 = viewUnderStartPoint ();
+ kdDebug () << "\tviewUnderCursor=" << (v0 ? v0->name () : "(none)")
+ << " viewUnderCursorQt=" << (v1 ? v1->name () : "(none)")
+ << " viewUnderStartPoint=" << (v2 ? v2->name () : "(none)")
+ << endl;
+ kdDebug () << "\tfocusWidget=" << kapp->focusWidget () << endl;
+#endif
+
+ Qt::ButtonState buttonState = e->stateAfter ();
+ m_shiftPressed = (buttonState & Qt::ShiftButton);
+ m_controlPressed = (buttonState & Qt::ControlButton);
+ m_altPressed = (buttonState & Qt::AltButton);
+
+ if (m_beganDraw)
+ {
+ kpView *view = viewUnderStartPoint ();
+ if (!view)
+ {
+ kdError () << "kpTool::mouseMoveEvent() without a view under the start point!" << endl;
+ return;
+ }
+
+ m_currentPoint = view->transformViewToDoc (e->pos ());
+ m_currentViewPoint = e->pos ();
+
+ #if DEBUG_KP_TOOL && 0
+ kdDebug () << "\tDraw!" << endl;
+ #endif
+
+ bool dragScrolled = false;
+ movedAndAboutToDraw (m_currentPoint, m_lastPoint, view->zoomLevelX (), &dragScrolled);
+
+ if (dragScrolled)
+ {
+ m_currentPoint = currentPoint ();
+ m_currentViewPoint = currentPoint (false/*view point*/);
+
+ // Scrollview has scrolled contents and has scheduled an update
+ // for the newly exposed region. If draw() schedules an update
+ // as well (instead of immediately updating), the scrollview's
+ // update will be executed first and it'll only update part of
+ // the screen resulting in ugly tearing of the viewManager's
+ // tempPixmap.
+ viewManager ()->setFastUpdates ();
+ }
+
+ draw (m_currentPoint, m_lastPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ if (dragScrolled)
+ viewManager ()->restoreFastUpdates ();
+
+ m_lastPoint = m_currentPoint;
+ }
+ else
+ {
+ kpView *view = viewUnderCursor ();
+ if (!view) // possible if cancelShape()'ed but still holding down initial mousebtn
+ {
+ m_currentPoint = KP_INVALID_POINT;
+ m_currentViewPoint = KP_INVALID_POINT;
+ return;
+ }
+
+ m_currentPoint = view->transformViewToDoc (e->pos ());
+ m_currentViewPoint = e->pos ();
+ hover (m_currentPoint);
+ }
+}
+
+void kpTool::mouseReleaseEvent (QMouseEvent *e)
+{
+#if DEBUG_KP_TOOL && 1
+ kdDebug () << "kpTool::mouseReleaseEvent pos=" << e->pos ()
+ << " btnStateBefore=" << (int) e->state ()
+ << " btnStateAfter=" << (int) e->stateAfter ()
+ << " button=" << (int) e->button () << endl;
+#endif
+
+ if (m_beganDraw) // didn't cancelShape()
+ {
+ kpView *view = viewUnderStartPoint ();
+ if (!view)
+ {
+ kdError () << "kpTool::mouseReleaseEvent() without a view under the start point!" << endl;
+ return;
+ }
+
+ m_currentPoint = view ? view->transformViewToDoc (e->pos ()) : QPoint (-1, -1);
+ m_currentViewPoint = view ? e->pos () : QPoint (-1, -1);
+ endDrawInternal (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+ }
+
+ if ((e->stateAfter () & Qt::MouseButtonMask) == 0)
+ {
+ releasedAllButtons ();
+ }
+}
+
+void kpTool::wheelEvent (QWheelEvent *e)
+{
+#if DEBUG_KP_TOOL
+ kdDebug () << "kpTool::wheelEvent() state=" << e->state ()
+ << " hasBegunDraw=" << hasBegunDraw ()
+ << " delta=" << e->delta ()
+ << endl;
+#endif
+
+ e->ignore ();
+
+ // If CTRL not pressed, bye.
+ if ((e->state () & Qt::ControlButton) == 0)
+ return;
+
+ // If drawing, bye; don't care if a shape in progress though.
+ if (hasBegunDraw ())
+ return;
+
+
+ // Zoom in/out depending on wheel direction.
+
+ // Moved wheel away from user?
+ if (e->delta () > 0)
+ {
+ m_mainWindow->zoomIn (true/*center under cursor*/);
+ e->accept ();
+ }
+ // Moved wheel towards user?
+ else if (e->delta () < 0)
+ {
+ #if 1
+ m_mainWindow->zoomOut (true/*center under cursor - make zoom in/out
+ stay under same doc pos*/);
+ #else
+ m_mainWindow->zoomOut (false/*don't center under cursor - as is
+ confusing behaviour when zooming
+ out*/);
+ #endif
+ e->accept ();
+ }
+}
+
+
+void kpTool::keyPressEvent (QKeyEvent *e)
+{
+#if DEBUG_KP_TOOL && 0
+ kdDebug () << "kpTool::keyPressEvent() e->key=" << e->key () << endl;
+#endif
+
+ int dx = 0, dy = 0;
+
+ e->ignore ();
+
+ switch (e->key ())
+ {
+ case 0:
+ case Qt::Key_unknown:
+ #if DEBUG_KP_TOOL && 0
+ kdDebug () << "kpTool::keyPressEvent() picked up unknown key!" << endl;
+ #endif
+ // --- fall thru and update all modifiers ---
+ case Qt::Key_Alt:
+ case Qt::Key_Shift:
+ case Qt::Key_Control:
+ keyUpdateModifierState (e);
+
+ e->accept ();
+ break;
+
+ case Qt::Key_Delete:
+ m_mainWindow->slotDelete ();
+ break;
+
+ /*
+ * QCursor::setPos conveniently causes mouseMoveEvents :)
+ */
+
+ case Qt::Key_Home: dx = -1, dy = -1; break;
+ case Qt::Key_Up: dy = -1; break;
+ case Qt::Key_PageUp: dx = +1, dy = -1; break;
+
+ case Qt::Key_Left: dx = -1; break;
+ case Qt::Key_Right: dx = +1; break;
+
+ case Qt::Key_End: dx = -1, dy = +1; break;
+ case Qt::Key_Down: dy = +1; break;
+ case Qt::Key_PageDown: dx = +1, dy = +1; break;
+
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ case Qt::Key_Insert:
+ case Qt::Key_Clear/*Numpad 5 Key*/:
+ {
+ kpView *view = viewUnderCursor (); // TODO: wrong for dragging lines outside of view (for e.g.)
+ if (view)
+ {
+ // TODO: what about the modifiers
+ QMouseEvent me (QEvent::MouseButtonPress,
+ view->mapFromGlobal (QCursor::pos ()),
+ Qt::LeftButton,
+ 0);
+ mousePressEvent (&me);
+ e->accept ();
+ }
+
+ break;
+ }}
+
+ kpView *view = viewUnderCursor ();
+ if (view && (dx || dy))
+ {
+ QPoint oldPoint = view->mapFromGlobal (QCursor::pos ());
+ #if DEBUG_KP_TOOL && 0
+ kdDebug () << "\toldPoint=" << oldPoint
+ << " dx=" << dx << " dy=" << dy << endl;
+ #endif
+
+
+ const int viewIncX = (dx ? QMAX (1, view->zoomLevelX () / 100) * dx : 0);
+ const int viewIncY = (dy ? QMAX (1, view->zoomLevelY () / 100) * dy : 0);
+
+ int newViewX = oldPoint.x () + viewIncX;
+ int newViewY = oldPoint.y () + viewIncY;
+
+
+ #if DEBUG_KP_TOOL && 0
+ kdDebug () << "\tnewPoint=" << QPoint (newViewX, newViewY) << endl;
+ #endif
+
+ if (view->transformViewToDoc (QPoint (newViewX, newViewY)) ==
+ view->transformViewToDoc (oldPoint))
+ {
+ newViewX += viewIncX, newViewY += viewIncY;
+
+ #if DEBUG_KP_TOOL && 0
+ kdDebug () << "\tneed adjust for doc - newPoint="
+ << QPoint (newViewX, newViewY) << endl;
+ #endif
+ }
+
+
+ // TODO: visible width/height (e.g. with scrollbars)
+ int x = QMIN (QMAX (newViewX, 0), view->width () - 1);
+ int y = QMIN (QMAX (newViewY, 0), view->height () - 1);
+
+ QCursor::setPos (view->mapToGlobal (QPoint (x, y)));
+ e->accept ();
+ }
+}
+
+void kpTool::keyReleaseEvent (QKeyEvent *e)
+{
+#if DEBUG_KP_TOOL && 0
+ kdDebug () << "kpTool::keyReleaseEvent() e->key=" << e->key () << endl;
+#endif
+
+ e->ignore ();
+
+ switch (e->key ())
+ {
+ case 0:
+ case Qt::Key_unknown:
+ #if DEBUG_KP_TOOL
+ kdDebug () << "kpTool::keyReleaseEvent() picked up unknown key!" << endl;
+ #endif
+ // HACK: around Qt bug: if you hold a modifier before you start the
+ // program and then release it over the view,
+ // Qt reports it as the release of an unknown key
+ // --- fall thru and update all modifiers ---
+ case Qt::Key_Alt:
+ case Qt::Key_Shift:
+ case Qt::Key_Control:
+ keyUpdateModifierState (e);
+
+ e->accept ();
+ break;
+
+ case Qt::Key_Escape:
+ if (hasBegunDraw ())
+ {
+ cancelShapeInternal ();
+ e->accept ();
+ }
+
+ break;
+
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ case Qt::Key_Insert:
+ case Qt::Key_Clear/*Numpad 5 Key*/:
+ {
+ kpView *view = viewUnderCursor ();
+ if (view)
+ {
+ QMouseEvent me (QEvent::MouseButtonRelease,
+ view->mapFromGlobal (QCursor::pos ()),
+ Qt::LeftButton,
+ Qt::LeftButton);
+ mouseReleaseEvent (&me);
+ e->accept ();
+ }
+ break;
+ }}
+}
+
+// private
+void kpTool::keyUpdateModifierState (QKeyEvent *e)
+{
+#if DEBUG_KP_TOOL && 0
+ kdDebug () << "kpTool::updateModifierState() e->key=" << e->key () << endl;
+ kdDebug () << "\tshift="
+ << (e->stateAfter () & Qt::ShiftButton)
+ << " control="
+ << (e->stateAfter () & Qt::ControlButton)
+ << " alt="
+ << (e->stateAfter () & Qt::AltButton)
+ << endl;
+#endif
+ if (e->key () & (Qt::Key_Alt | Qt::Key_Shift | Qt::Key_Control))
+ {
+ #if DEBUG_KP_TOOL && 0
+ kdDebug () << "\t\tmodifier changed - use e's claims" << endl;
+ #endif
+ setShiftPressed (e->stateAfter () & Qt::ShiftButton);
+ setControlPressed (e->stateAfter () & Qt::ControlButton);
+ setAltPressed (e->stateAfter () & Qt::AltButton);
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL && 0
+ kdDebug () << "\t\tmodifiers not changed - figure out the truth" << endl;
+ #endif
+ uint keyState = KApplication::keyboardModifiers ();
+
+ setShiftPressed (keyState & KApplication::ShiftModifier);
+ setControlPressed (keyState & KApplication::ControlModifier);
+
+ // TODO: Can't do much about ALT - unless it's always KApplication::Modifier1?
+ // Ditto for everywhere else where I set SHIFT & CTRL but not alt.
+ setAltPressed (e->stateAfter () & Qt::AltButton);
+ }
+}
+
+
+void kpTool::notifyModifierStateChanged ()
+{
+ if (careAboutModifierState ())
+ {
+ if (m_beganDraw)
+ draw (m_currentPoint, m_lastPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+ else
+ {
+ m_currentPoint = currentPoint ();
+ m_currentViewPoint = currentPoint (false/*view point*/);
+ hover (m_currentPoint);
+ }
+ }
+}
+
+void kpTool::setShiftPressed (bool pressed)
+{
+ if (pressed == m_shiftPressed)
+ return;
+
+ m_shiftPressed = pressed;
+
+ notifyModifierStateChanged ();
+}
+
+void kpTool::setControlPressed (bool pressed)
+{
+ if (pressed == m_controlPressed)
+ return;
+
+ m_controlPressed = pressed;
+
+ notifyModifierStateChanged ();
+}
+
+void kpTool::setAltPressed (bool pressed)
+{
+ if (pressed = m_altPressed)
+ return;
+
+ m_altPressed = pressed;
+
+ notifyModifierStateChanged ();
+}
+
+void kpTool::focusInEvent (QFocusEvent *)
+{
+}
+
+void kpTool::focusOutEvent (QFocusEvent *)
+{
+#if DEBUG_KP_TOOL && 0
+ kdDebug () << "kpTool::focusOutEvent() beganDraw=" << m_beganDraw << endl;
+#endif
+
+ if (m_beganDraw)
+ endDrawInternal (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+}
+
+void kpTool::enterEvent (QEvent *)
+{
+#if DEBUG_KP_TOOL && 1
+ kdDebug () << "kpTool::enterEvent() beganDraw=" << m_beganDraw << endl;
+#endif
+}
+
+void kpTool::leaveEvent (QEvent *)
+{
+#if DEBUG_KP_TOOL && 1
+ kdDebug () << "kpTool::leaveEvent() beganDraw=" << m_beganDraw << endl;
+#endif
+
+ // if we haven't started drawing (e.g. dragging a rectangle)...
+ if (!m_beganDraw)
+ {
+ m_currentPoint = KP_INVALID_POINT;
+ m_currentViewPoint = KP_INVALID_POINT;
+ hover (m_currentPoint);
+ }
+}
+
+// static
+int kpTool::mouseButton (const Qt::ButtonState &buttonState)
+{
+ // we have nothing to do with mid-buttons
+ if (buttonState & Qt::MidButton)
+ return -1;
+
+ // both left & right together is quite meaningless...
+ Qt::ButtonState bothButtons = (Qt::ButtonState) (Qt::LeftButton | Qt::RightButton);
+ if ((buttonState & bothButtons) == bothButtons)
+ return -1;
+
+ if (buttonState & Qt::LeftButton)
+ return 0;
+ else if (buttonState & Qt::RightButton)
+ return 1;
+ else
+ return -1;
+}
+
+
+/*
+ * User Notifications
+ */
+
+
+// public static
+QString kpTool::cancelUserMessage (int mouseButton)
+{
+ if (mouseButton == 0)
+ return i18n ("Right click to cancel.");
+ else
+ return i18n ("Left click to cancel.");
+}
+
+// public
+QString kpTool::cancelUserMessage () const
+{
+ return cancelUserMessage (m_mouseButton);
+}
+
+
+// public
+QString kpTool::userMessage () const
+{
+ return m_userMessage;
+}
+
+// public
+void kpTool::setUserMessage (const QString &userMessage)
+{
+ m_userMessage = userMessage;
+
+ if (m_userMessage.isEmpty ())
+ m_userMessage = text ();
+ else
+ m_userMessage.prepend (i18n ("%1: ").arg (text ()));
+
+ emit userMessageChanged (m_userMessage);
+}
+
+
+// public
+QPoint kpTool::userShapeStartPoint () const
+{
+ return m_userShapeStartPoint;
+}
+
+// public
+QPoint kpTool::userShapeEndPoint () const
+{
+ return m_userShapeEndPoint;
+}
+
+// public static
+int kpTool::calculateLength (int start, int end)
+{
+ if (start <= end)
+ {
+ return end - start + 1;
+ }
+ else
+ {
+ return end - start - 1;
+ }
+}
+
+// public
+void kpTool::setUserShapePoints (const QPoint &startPoint,
+ const QPoint &endPoint,
+ bool setSize)
+{
+ m_userShapeStartPoint = startPoint;
+ m_userShapeEndPoint = endPoint;
+ emit userShapePointsChanged (m_userShapeStartPoint, m_userShapeEndPoint);
+
+ if (setSize)
+ {
+ if (startPoint != KP_INVALID_POINT &&
+ endPoint != KP_INVALID_POINT)
+ {
+ setUserShapeSize (calculateLength (startPoint.x (), endPoint.x ()),
+ calculateLength (startPoint.y (), endPoint.y ()));
+ }
+ else
+ {
+ setUserShapeSize ();
+ }
+ }
+}
+
+
+// public
+QSize kpTool::userShapeSize () const
+{
+ return m_userShapeSize;
+}
+
+// public
+int kpTool::userShapeWidth () const
+{
+ return m_userShapeSize.width ();
+}
+
+// public
+int kpTool::userShapeHeight () const
+{
+ return m_userShapeSize.height ();
+}
+
+// public
+void kpTool::setUserShapeSize (const QSize &size)
+{
+ m_userShapeSize = size;
+
+ emit userShapeSizeChanged (m_userShapeSize);
+ emit userShapeSizeChanged (m_userShapeSize.width (),
+ m_userShapeSize.height ());
+}
+
+// public
+void kpTool::setUserShapeSize (int width, int height)
+{
+ setUserShapeSize (QSize (width, height));
+}
+
+
+// public static
+bool kpTool::warnIfBigImageSize (int oldWidth, int oldHeight,
+ int newWidth, int newHeight,
+ const QString &text,
+ const QString &caption,
+ const QString &continueButtonText,
+ QWidget *parent)
+{
+#if DEBUG_KP_TOOL
+ kdDebug () << "kpTool::warnIfBigImageSize()"
+ << " old: w=" << oldWidth << " h=" << oldWidth
+ << " new: w=" << newWidth << " h=" << newHeight
+ << " pixmapSize="
+ << kpPixmapFX::pixmapSize (newWidth,
+ newHeight,
+ QPixmap::defaultDepth ())
+ << " vs BigImageSize=" << KP_BIG_IMAGE_SIZE
+ << endl;
+#endif
+
+ // Only got smaller or unchanged - don't complain
+ if (!(newWidth > oldWidth || newHeight > oldHeight))
+ {
+ return true;
+ }
+
+ // Was already large - user was warned before, don't annoy him/her again
+ if (kpPixmapFX::pixmapSize (oldWidth, oldHeight, QPixmap::defaultDepth ()) >=
+ KP_BIG_IMAGE_SIZE)
+ {
+ return true;
+ }
+
+ if (kpPixmapFX::pixmapSize (newWidth, newHeight, QPixmap::defaultDepth ()) >=
+ KP_BIG_IMAGE_SIZE)
+ {
+ int accept = KMessageBox::warningContinueCancel (parent,
+ text,
+ caption,
+ continueButtonText,
+ QString::fromLatin1 ("BigImageDontAskAgain"));
+
+ return (accept == KMessageBox::Continue);
+ }
+ else
+ {
+ return true;
+ }
+}
+
+
+#include <kptool.moc>
diff --git a/kolourpaint/kptool.h b/kolourpaint/kptool.h
new file mode 100644
index 00000000..ba7ee75e
--- /dev/null
+++ b/kolourpaint/kptool.h
@@ -0,0 +1,422 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __kp_tool_h__
+#define __kp_tool_h__
+
+#include <qobject.h>
+#include <qpoint.h>
+#include <qrect.h>
+#include <qsize.h>
+#include <qstring.h>
+
+#include <kpdefs.h>
+
+
+class QIconSet;
+class QPixmap;
+
+class KKeySequence;
+class KShortcut;
+
+class kpColor;
+class kpColorToolBar;
+class kpCommandHistory;
+class kpDocument;
+class kpView;
+class kpViewManager;
+class kpMainWindow;
+class kpToolAction;
+class kpToolToolBar;
+
+
+// Base class for all tools
+class kpTool : public QObject
+{
+Q_OBJECT
+
+public:
+ kpTool (const QString &text, const QString &description,
+ int key,
+ kpMainWindow *mainWindow, const char *name);
+ virtual ~kpTool ();
+
+private:
+ void init (const QString &text, const QString &description,
+ int key,
+ kpMainWindow *mainWindow, const char *name);
+
+
+protected:
+ void createAction ();
+
+ int m_key;
+ kpToolAction *m_action;
+
+signals:
+ void actionToolTipChanged (const QString &string);
+
+protected slots:
+ void slotActionToolTipChanged (const QString &string);
+
+public:
+ QString text () const;
+ void setText (const QString &text);
+
+ static QString toolTipForTextAndShortcut (const QString &text,
+ const KShortcut &shortcut);
+ QString toolTip () const;
+
+ QString description () const;
+ void setDescription (const QString &description);
+
+ int key () const;
+ void setKey (int key);
+
+ // Given a single <key>, returns a shortcut with <key>
+ // (disabled when the user is editing text) and as an alternate,
+ // <some modifiers>+<key>.
+ static KShortcut shortcutForKey (int key);
+ KShortcut shortcut () const;
+
+ static bool keyIsText (int key);
+ static bool containsSingleKeyTrigger (const KKeySequence &seq);
+ static bool containsSingleKeyTrigger (const KShortcut &shortcut,
+ KShortcut *shortcutWithoutSingleKeyTriggers);
+
+ bool singleKeyTriggersEnabled () const;
+ void enableSingleKeyTriggers (bool enable = true);
+
+ const char *name () const;
+
+
+ static QRect neededRect (const QRect &rect, int lineWidth);
+ static QPixmap neededPixmap (const QPixmap &pixmap, const QRect &boundingRect);
+
+ bool hasCurrentPoint () const;
+ // Returns the position of the cursor relative to the topleft point of
+ // the current view (viewUnderStartPoint() or viewUnderCursor() otherwise).
+ //
+ // If neither viewUnderStartPoint() nor viewUnderCursor()
+ // (i.e. !hasCurrentPoint()), then it returns KP_INVALID_POINT.
+ //
+ // If <zoomToDoc> is set (default), then it returns the position in the
+ // document. This theoretically == m_currentPoint (when m_currentPoint
+ // is defined) but I wouldn't bet on it. This function is useful when
+ // m_currentPoint isn't necessarily defined (outside of beginDraw(),draw()
+ // and hover()).
+ //
+ // If <zoomToDoc> is not set, then it returns an unzoomed view coordinate.
+ //
+ // Keep in mind that if viewUnderStartPoint(), this can return coordinates
+ // outside of the document/view.
+ QPoint currentPoint (bool zoomToDoc = true) const;
+
+public slots:
+ // Call this when something below the mouse cursor may have changed
+ // and/or if the view has moved relative to the cursor (as opposed to
+ // the cursor moving relative to the view, which would trigger a
+ // mouseMoveEvent and all would be well without such hacks)
+ // e.g. when zooming or scrolling the view or when deleting a selection.
+ //
+ // This calls hover() or draw() to let the tool know. The Brush Tool
+ // can then update the position of the Brush Cursor. The Selection
+ // Tool can update the real cursor. The Line Tool can update the current
+ // line. The statubar gets correct coordinates. etc. etc.
+ void somethingBelowTheCursorChanged ();
+
+private:
+ // Same as above except that you claim you know better than currentPoint()
+ void somethingBelowTheCursorChanged (const QPoint &currentPoint_,
+ const QPoint &currentViewPoint_);
+
+public:
+ // called when the tool is selected
+ virtual void begin ();
+
+ // called when the tool is deselected
+ virtual void end ();
+
+ // set after begin() has been called, unset after end() has been called
+ bool hasBegun () const { return m_began; }
+
+ bool hasBegunDraw () const { return m_beganDraw; }
+
+ virtual bool hasBegunShape () const { return hasBegunDraw (); }
+
+ // called when user double-left-clicks on Tool Icon (not view)
+ virtual void globalDraw ();
+
+ // called when the user clicks on the Tool Icon even though it's already
+ // the current tool (used by the selection tools to deselect)
+ virtual void reselect ();
+
+signals:
+ // emitted after beginDraw() has been called
+ void beganDraw (const QPoint &point);
+
+ // Emitted just before draw() is called in mouseMoveEvent(). Slots
+ // connected to this signal should return in <scrolled> whether the
+ // mouse pos may have changed. Used by drag scrolling.
+ void movedAndAboutToDraw (const QPoint &currentPoint, const QPoint &lastPoint,
+ int zoomLevel,
+ bool *scrolled);
+
+ // emitted after endDraw() has been called
+ void endedDraw (const QPoint &point);
+
+ // emitted after cancelShape() has been called
+ void cancelledShape (const QPoint &point);
+
+
+public:
+ QIconSet iconSet (int forceSize = 0) const;
+ QString iconName () const;
+ kpToolAction *action ();
+
+signals:
+ // User clicked on the tool's action - i.e. select this tool
+ void actionActivated ();
+
+protected slots:
+ void slotActionActivated ();
+
+
+protected:
+ virtual bool returnToPreviousToolAfterEndDraw () const { return false; }
+ virtual bool careAboutModifierState () const { return false; }
+ virtual bool careAboutColorsSwapped () const { return false; }
+
+ virtual void beginDraw ();
+
+ // mouse move without button pressed
+ // (only m_currentPoint & m_currentViewPoint is defined)
+ virtual void hover (const QPoint &point);
+
+ // this is useful for "instant" tools like the Pen & Eraser
+ virtual void draw (const QPoint &thisPoint, const QPoint &lastPoint,
+ const QRect &normalizedRect);
+
+ // (m_mouseButton will not change from beginDraw())
+ virtual void cancelShape ();
+ virtual void releasedAllButtons ();
+
+ virtual void endDraw (const QPoint &thisPoint, const QRect &normalizedRect);
+
+ virtual void endShape (const QPoint &thisPoint = QPoint (),
+ const QRect &normalizedRect = QRect ())
+ {
+ endDraw (thisPoint, normalizedRect);
+ }
+
+ kpMainWindow *mainWindow () const;
+ kpDocument *document () const;
+ kpViewManager *viewManager () const;
+ kpToolToolBar *toolToolBar () const;
+ kpView *viewUnderStartPoint () const { return m_viewUnderStartPoint; }
+ kpView *viewUnderCursor () const;
+ kpCommandHistory *commandHistory () const;
+
+ kpColor color (int which) const;
+
+ kpColor foregroundColor () const;
+ kpColor backgroundColor () const;
+
+ double colorSimilarity () const;
+ int processedColorSimilarity () const;
+
+protected:
+ int m_ignoreColorSignals;
+
+protected slots:
+ void slotColorsSwappedInternal (const kpColor &newForegroundColor,
+ const kpColor &newBackgroundColor);
+ void slotForegroundColorChangedInternal (const kpColor &color);
+ void slotBackgroundColorChangedInternal (const kpColor &color);
+ void slotColorSimilarityChangedInternal (double similarity, int processedSimilarity);
+
+protected slots: // TODO: there is no reason why these should be slots
+ virtual void slotColorsSwapped (const kpColor & /*newForegroundColor*/, const kpColor & /*newBackgroundColor*/) {}
+ virtual void slotForegroundColorChanged (const kpColor & /*color*/) {}
+ virtual void slotBackgroundColorChanged (const kpColor & /*color*/) {}
+ virtual void slotColorSimilarityChanged (double /*similarity*/, int /*processedSimilarity*/) {};
+
+protected:
+ // (only valid in slots connected to the respective signals above)
+ kpColor oldForegroundColor () const;
+ kpColor oldBackgroundColor () const;
+ double oldColorSimilarity () const;
+
+protected:
+ // returns true if m_currentPoint <= 1 pixel away from m_lastPoint
+ // or if there was no lastPoint
+ bool currentPointNextToLast () const; // (includes diagonal adjacency)
+ bool currentPointCardinallyNextToLast () const; // (only cardinally adjacent i.e. horiz & vert; no diag)
+
+ int m_mouseButton; /* 0 = left, 1 = right */
+ bool m_shiftPressed, m_controlPressed, m_altPressed; // m_altPressed is unreliable
+ bool m_beganDraw; // set after beginDraw() is called, unset before endDraw() is called
+ QPoint m_startPoint,
+ m_currentPoint, m_currentViewPoint,
+ m_lastPoint;
+
+protected:
+ friend class kpCommandHistory;
+ friend class kpMainWindow;
+ friend class kpToolToolBar;
+ void beginInternal ();
+ void endInternal ();
+
+ void beginDrawInternal ();
+ void endDrawInternal (const QPoint &thisPoint, const QRect &normalizedRect,
+ bool wantEndShape = false);
+ void cancelShapeInternal ();
+ void endShapeInternal (const QPoint &thisPoint = QPoint (),
+ const QRect &normalizedRect = QRect ());
+
+ friend class kpView;
+
+ // If you're reimplementing any of these, you probably don't know what
+ // you're doing - reimplement begin(),beginDraw(),draw(),cancelShape(),
+ // endDraw() etc. instead.
+ virtual void mousePressEvent (QMouseEvent *e);
+ virtual void mouseMoveEvent (QMouseEvent *e);
+ virtual void mouseReleaseEvent (QMouseEvent *e);
+ virtual void wheelEvent (QWheelEvent *e);
+
+ virtual void keyPressEvent (QKeyEvent *e);
+ virtual void keyReleaseEvent (QKeyEvent *e);
+
+ virtual void imStartEvent(QIMEvent *){}
+ virtual void imComposeEvent(QIMEvent *){}
+ virtual void imEndEvent(QIMEvent *){}
+
+private:
+ void keyUpdateModifierState (QKeyEvent *e);
+ void notifyModifierStateChanged ();
+protected:
+ virtual void setShiftPressed (bool pressed);
+ virtual void setControlPressed (bool pressed);
+ virtual void setAltPressed (bool pressed);
+ virtual void focusInEvent (QFocusEvent *e);
+ virtual void focusOutEvent (QFocusEvent *e);
+ virtual void enterEvent (QEvent *e);
+ virtual void leaveEvent (QEvent *e);
+
+ // 0 = left, 1 = right, -1 = other (none, left+right, mid)
+ static int mouseButton (const Qt::ButtonState &buttonState);
+
+ QString m_text, m_description;
+ const char *m_name;
+
+ kpMainWindow *m_mainWindow;
+ bool m_began;
+
+ kpView *m_viewUnderStartPoint;
+
+
+ /*
+ * User Notifications (Status Bar)
+ */
+
+public:
+ // Returns "(Left|Right) click to cancel." where Left or Right is chosen
+ // depending on which one is the _opposite_ of <mouseButton>
+ static QString cancelUserMessage (int mouseButton);
+ QString cancelUserMessage () const;
+
+ QString userMessage () const;
+ void setUserMessage (const QString &userMessage = QString::null);
+
+ QPoint userShapeStartPoint () const;
+ QPoint userShapeEndPoint () const;
+ static int calculateLength (int start, int end);
+ void setUserShapePoints (const QPoint &startPoint = KP_INVALID_POINT,
+ const QPoint &endPoint = KP_INVALID_POINT,
+ bool setSize = true);
+
+ QSize userShapeSize () const;
+ int userShapeWidth () const;
+ int userShapeHeight () const;
+ void setUserShapeSize (const QSize &size = KP_INVALID_SIZE);
+ void setUserShapeSize (int width, int height);
+
+signals:
+ void userMessageChanged (const QString &userMessage);
+ void userShapePointsChanged (const QPoint &startPoint = KP_INVALID_POINT,
+ const QPoint &endPoint = KP_INVALID_POINT);
+ void userShapeSizeChanged (const QSize &size);
+ void userShapeSizeChanged (int width, int height);
+
+protected:
+ QString m_userMessage;
+ QPoint m_userShapeStartPoint, m_userShapeEndPoint;
+ QSize m_userShapeSize;
+
+
+public:
+ // Call this before the user tries to cause the document or selection
+ // to resize from <oldWidth>x<oldHeight> to <newWidth>x<newHeight>.
+ // If at least one dimension increases, the new dimensions will take a
+ // large amount of memory (which causes thrashing, instability) and
+ // the old dimensions did not take a large amount of memory, ask the
+ // user if s/he really wants to perform the operation.
+ //
+ // Returns true if the operation should proceed, false otherwise.
+ //
+ // In order to make the translators' lives possible, this function cannot
+ // generate the <text>,<caption> nor <continueButtonText> (without
+ // concantenating sentences and words with tense). However, it is
+ // recommended that you give them the following values:
+ //
+ // e.g.:
+ // text = i18n ("<qt><p>(Rotating|Skewing) the (image|selection) to"
+ // " %1x%2 may take a substantial amount of memory."
+ // " This can reduce system"
+ // " responsiveness and cause other application resource"
+ // " problems.</p>").arg (newWidth, newHeight)
+ //
+ // "<p>Are you sure want to (rotate|skew) the"
+ // " (image|selection)?</p></qt>");
+ // caption = i18n ("Rotate (Image|Selection)?");
+ // continueButtonText = i18n ("Rotat&e (Image|Selection)");
+ static bool warnIfBigImageSize (int oldWidth, int oldHeight,
+ int newWidth, int newHeight,
+ const QString &text,
+ const QString &caption,
+ const QString &continueButtonText,
+ QWidget *parent);
+
+
+protected:
+ // There is no need to maintain binary compatibility at this stage.
+ // The d-pointer is just so that you can experiment without recompiling
+ // the kitchen sink.
+ class kpToolPrivate *d;
+};
+
+#endif // __kp_tool_h__
diff --git a/kolourpaint/kpview.cpp b/kolourpaint/kpview.cpp
new file mode 100644
index 00000000..1f18c659
--- /dev/null
+++ b/kolourpaint/kpview.cpp
@@ -0,0 +1,1910 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_VIEW 0
+#define DEBUG_KP_VIEW_RENDERER ((DEBUG_KP_VIEW && 0) || 0)
+
+
+#include <kpview.h>
+
+#include <math.h>
+#include <stdlib.h>
+
+#include <qbitmap.h>
+#include <qcursor.h>
+#include <qdragobject.h>
+#include <qguardedptr.h>
+#include <qimage.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qpoint.h>
+#include <qrect.h>
+#include <qregion.h>
+#include <qmemarray.h>
+
+#if DEBUG_KP_VIEW || DEBUG_KP_VIEW_RENDERER
+ #include <qdatetime.h>
+#endif
+
+#include <kdebug.h>
+
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kppixmapfx.h>
+#include <kpselection.h>
+#include <kptemppixmap.h>
+#include <kptool.h>
+#include <kptooltoolbar.h>
+#include <kpviewmanager.h>
+#include <kpviewscrollablecontainer.h>
+
+
+struct kpViewPrivate
+{
+ // sync: kpView::paintEvent()
+ //
+ // Normally, these pointers must be valid while the kpView is alive.
+ // Generally, the objects they point to are deleted only after kpView
+ // is deleted.
+ //
+ // However, sometimes we use deleteLater() for the kpView.
+ // Before the delayed deletion is executed, those objects are deleted
+ // and then our paintEvent() is called. paintEvent() must therefore
+ // have some way of realising that those objects have been deleted so
+ // we use guardded pointers.
+ //
+ // For more details, see SVN commit:
+ // "r385274 | dang | 2005-02-02 22:08:27 +1100 (Wed, 02 Feb 2005) | 21 lines".
+ QGuardedPtr <kpDocument> m_document;
+ QGuardedPtr <kpToolToolBar> m_toolToolBar;
+ QGuardedPtr <kpViewManager> m_viewManager;
+ QGuardedPtr <kpView> m_buddyView;
+ QGuardedPtr <kpViewScrollableContainer> m_scrollableContainer;
+
+ int m_hzoom, m_vzoom;
+ QPoint m_origin;
+ bool m_showGrid;
+ bool m_isBuddyViewScrollableContainerRectangleShown;
+ QRect m_buddyViewScrollableContainerRectangle;
+
+ QRegion m_queuedUpdateArea;
+ QPixmap *m_backBuffer;
+};
+
+
+kpView::kpView (kpDocument *document,
+ kpToolToolBar *toolToolBar,
+ kpViewManager *viewManager,
+ kpView *buddyView,
+ kpViewScrollableContainer *scrollableContainer,
+ QWidget *parent, const char *name)
+
+ : QWidget (parent, name, Qt::WNoAutoErase/*no flicker*/),
+ d (new kpViewPrivate ())
+{
+ d->m_document = document;
+ d->m_toolToolBar = toolToolBar;
+ d->m_viewManager = viewManager;
+ d->m_buddyView = buddyView;
+ d->m_scrollableContainer = scrollableContainer;
+
+ d->m_hzoom = 100, d->m_vzoom = 100;
+ d->m_origin = QPoint (0, 0);
+ d->m_showGrid = false;
+ d->m_isBuddyViewScrollableContainerRectangleShown = false;
+
+ d->m_backBuffer = 0;
+
+
+ setBackgroundMode (Qt::NoBackground); // no flicker
+ setFocusPolicy (QWidget::WheelFocus);
+ setMouseTracking (true); // mouseMoveEvent's even when no mousebtn down
+ setKeyCompression (true);
+ setInputMethodEnabled (true); // ensure using InputMethod
+}
+
+kpView::~kpView ()
+{
+ setHasMouse (false);
+
+ delete d->m_backBuffer;
+ delete d;
+}
+
+
+// public
+kpDocument *kpView::document () const
+{
+ return d->m_document;
+}
+
+// protected
+kpSelection *kpView::selection () const
+{
+ return document () ? document ()->selection () : 0;
+}
+
+// public
+kpToolToolBar *kpView::toolToolBar () const
+{
+ return d->m_toolToolBar;
+}
+
+// protected
+kpTool *kpView::tool () const
+{
+ return toolToolBar () ? toolToolBar ()->tool () : 0;
+}
+
+// public
+kpViewManager *kpView::viewManager () const
+{
+ return d->m_viewManager;
+}
+
+// public
+kpView *kpView::buddyView () const
+{
+ return d->m_buddyView;
+}
+
+// public
+kpViewScrollableContainer *kpView::buddyViewScrollableContainer () const
+{
+ return (buddyView () ? buddyView ()->scrollableContainer () : 0);
+}
+
+// public
+kpViewScrollableContainer *kpView::scrollableContainer () const
+{
+ return d->m_scrollableContainer;
+}
+
+
+// public
+int kpView::zoomLevelX (void) const
+{
+ return d->m_hzoom;
+}
+
+// public
+int kpView::zoomLevelY (void) const
+{
+ return d->m_vzoom;
+}
+
+// public virtual
+void kpView::setZoomLevel (int hzoom, int vzoom)
+{
+ if (hzoom == d->m_hzoom && vzoom == d->m_vzoom)
+ return;
+
+ if (hzoom <= 0 || vzoom <= 0)
+ return;
+
+ d->m_hzoom = hzoom;
+ d->m_vzoom = vzoom;
+
+ if (viewManager ())
+ viewManager ()->updateView (this);
+
+ emit zoomLevelChanged (hzoom, vzoom);
+}
+
+
+// public
+QPoint kpView::origin () const
+{
+ return d->m_origin;
+}
+
+// public virtual
+void kpView::setOrigin (const QPoint &origin)
+{
+#if DEBUG_KP_VIEW
+ kdDebug () << "kpView(" << name () << ")::setOrigin" << origin << endl;
+#endif
+
+ if (origin == d->m_origin)
+ {
+ #if DEBUG_KP_VIEW
+ kdDebug () << "\tNOP" << endl;
+ #endif
+ return;
+ }
+
+ d->m_origin = origin;
+
+ if (viewManager ())
+ viewManager ()->updateView (this);
+
+ emit originChanged (origin);
+}
+
+
+// public
+bool kpView::canShowGrid () const
+{
+ // (minimum zoom level < 400% would probably be reported as a bug by
+ // users who thought that the grid was a part of the image!)
+ return ((zoomLevelX () >= 400 && zoomLevelX () % 100 == 0) &&
+ (zoomLevelY () >= 400 && zoomLevelY () % 100 == 0));
+}
+
+// public
+bool kpView::isGridShown () const
+{
+ return d->m_showGrid;
+}
+
+// public
+void kpView::showGrid (bool yes)
+{
+ if (d->m_showGrid == yes)
+ return;
+
+ if (yes && !canShowGrid ())
+ return;
+
+ d->m_showGrid = yes;
+
+ if (viewManager ())
+ viewManager ()->updateView (this);
+}
+
+
+// public
+bool kpView::isBuddyViewScrollableContainerRectangleShown () const
+{
+ return d->m_isBuddyViewScrollableContainerRectangleShown;
+}
+
+// public
+void kpView::showBuddyViewScrollableContainerRectangle (bool yes)
+{
+ if (yes == d->m_isBuddyViewScrollableContainerRectangleShown)
+ return;
+
+ d->m_isBuddyViewScrollableContainerRectangleShown = yes;
+
+ if (d->m_isBuddyViewScrollableContainerRectangleShown)
+ {
+ // Got these connect statements by analysing deps of
+ // updateBuddyViewScrollableContainerRectangle() rect update code.
+
+ connect (this, SIGNAL (zoomLevelChanged (int, int)),
+ this, SLOT (updateBuddyViewScrollableContainerRectangle ()));
+ connect (this, SIGNAL (originChanged (const QPoint &)),
+ this, SLOT (updateBuddyViewScrollableContainerRectangle ()));
+
+ if (buddyViewScrollableContainer ())
+ {
+ connect (buddyViewScrollableContainer (), SIGNAL (contentsMovingSoon (int, int)),
+ this, SLOT (updateBuddyViewScrollableContainerRectangle ()));
+ connect (buddyViewScrollableContainer (), SIGNAL (resized ()),
+ this, SLOT (updateBuddyViewScrollableContainerRectangle ()));
+ }
+
+ if (buddyView ())
+ {
+ connect (buddyView (), SIGNAL (zoomLevelChanged (int, int)),
+ this, SLOT (updateBuddyViewScrollableContainerRectangle ()));
+ connect (buddyView (), SIGNAL (originChanged (const QPoint &)),
+ this, SLOT (updateBuddyViewScrollableContainerRectangle ()));
+
+ connect (buddyView (), SIGNAL (sizeChanged (int, int)),
+ this, SLOT (updateBuddyViewScrollableContainerRectangle ()));
+ }
+
+ }
+ else
+ {
+ disconnect (this, SIGNAL (zoomLevelChanged (int, int)),
+ this, SLOT (updateBuddyViewScrollableContainerRectangle ()));
+ disconnect (this, SIGNAL (originChanged (const QPoint &)),
+ this, SLOT (updateBuddyViewScrollableContainerRectangle ()));
+
+ if (buddyViewScrollableContainer ())
+ {
+ disconnect (buddyViewScrollableContainer (), SIGNAL (contentsMovingSoon (int, int)),
+ this, SLOT (updateBuddyViewScrollableContainerRectangle ()));
+ disconnect (buddyViewScrollableContainer (), SIGNAL (resized ()),
+ this, SLOT (updateBuddyViewScrollableContainerRectangle ()));
+ }
+
+ if (buddyView ())
+ {
+ disconnect (buddyView (), SIGNAL (zoomLevelChanged (int, int)),
+ this, SLOT (updateBuddyViewScrollableContainerRectangle ()));
+ disconnect (buddyView (), SIGNAL (originChanged (const QPoint &)),
+ this, SLOT (updateBuddyViewScrollableContainerRectangle ()));
+
+ disconnect (buddyView (), SIGNAL (sizeChanged (int, int)),
+ this, SLOT (updateBuddyViewScrollableContainerRectangle ()));
+ }
+
+ }
+
+ updateBuddyViewScrollableContainerRectangle ();
+}
+
+
+// protected
+QRect kpView::buddyViewScrollableContainerRectangle () const
+{
+ return d->m_buddyViewScrollableContainerRectangle;
+}
+
+// protected slot
+void kpView::updateBuddyViewScrollableContainerRectangle ()
+{
+ if (viewManager ())
+ viewManager ()->setQueueUpdates ();
+
+ {
+ if (d->m_buddyViewScrollableContainerRectangle.isValid ())
+ {
+ if (viewManager ())
+ {
+ // Erase last
+ viewManager ()->updateViewRectangleEdges (this,
+ d->m_buddyViewScrollableContainerRectangle);
+ }
+ }
+
+
+ QRect newRect;
+ if (isBuddyViewScrollableContainerRectangleShown () &&
+ buddyViewScrollableContainer () && buddyView ())
+ {
+ QRect docRect = buddyView ()->transformViewToDoc (
+ QRect (buddyViewScrollableContainer ()->contentsXSoon (),
+ buddyViewScrollableContainer ()->contentsYSoon (),
+ QMIN (buddyView ()->width (),
+ buddyViewScrollableContainer ()->visibleWidth ()),
+ QMIN (buddyView ()->height (),
+ buddyViewScrollableContainer ()->visibleHeight ())));
+
+
+ QRect viewRect = this->transformDocToView (docRect);
+
+
+ // (Surround the area of interest by moving outwards by 1 pixel in each
+ // direction - don't overlap area)
+ newRect = QRect (viewRect.x () - 1,
+ viewRect.y () - 1,
+ viewRect.width () + 2,
+ viewRect.height () + 2);
+ }
+ else
+ {
+ newRect = QRect ();
+ }
+
+ if (newRect != d->m_buddyViewScrollableContainerRectangle)
+ {
+ // (must set before updateView() for paintEvent() to see new
+ // rect)
+ d->m_buddyViewScrollableContainerRectangle = newRect;
+
+ if (newRect.isValid ())
+ {
+ if (viewManager ())
+ {
+ viewManager ()->updateViewRectangleEdges (this,
+ d->m_buddyViewScrollableContainerRectangle);
+ }
+ }
+ }
+ }
+
+ if (viewManager ())
+ viewManager ()->restoreQueueUpdates ();
+}
+
+
+// public
+double kpView::transformViewToDocX (double viewX) const
+{
+ return (viewX - origin ().x ()) * 100.0 / zoomLevelX ();
+}
+
+// public
+double kpView::transformViewToDocY (double viewY) const
+{
+ return (viewY - origin ().y ()) * 100.0 / zoomLevelY ();
+}
+
+// public
+QPoint kpView::transformViewToDoc (const QPoint &viewPoint) const
+{
+ return QPoint ((int) transformViewToDocX (viewPoint.x ()),
+ (int) transformViewToDocY (viewPoint.y ()));
+}
+
+// public
+QRect kpView::transformViewToDoc (const QRect &viewRect) const
+{
+ if (zoomLevelX () == 100 && zoomLevelY () == 100)
+ {
+ return QRect (viewRect.x () - origin ().x (),
+ viewRect.y () - origin ().y (),
+ viewRect.width (),
+ viewRect.height ());
+ }
+ else
+ {
+ const QPoint docTopLeft = transformViewToDoc (viewRect.topLeft ());
+
+ // (don't call transformViewToDoc[XY]() - need to round up dimensions)
+ const int docWidth = qRound (double (viewRect.width ()) * 100.0 / double (zoomLevelX ()));
+ const int docHeight = qRound (double (viewRect.height ()) * 100.0 / double (zoomLevelY ()));
+
+ // (like QWMatrix::Areas)
+ return QRect (docTopLeft.x (), docTopLeft.y (), docWidth, docHeight);
+ }
+}
+
+
+// public
+double kpView::transformDocToViewX (double docX) const
+{
+ return (docX * zoomLevelX () / 100.0) + origin ().x ();
+}
+
+// public
+double kpView::transformDocToViewY (double docY) const
+{
+ return (docY * zoomLevelY () / 100.0) + origin ().y ();
+}
+
+// public
+QPoint kpView::transformDocToView (const QPoint &docPoint) const
+{
+ return QPoint ((int) transformDocToViewX (docPoint.x ()),
+ (int) transformDocToViewY (docPoint.y ()));
+}
+
+// public
+QRect kpView::transformDocToView (const QRect &docRect) const
+{
+ if (zoomLevelX () == 100 && zoomLevelY () == 100)
+ {
+ return QRect (docRect.x () + origin ().x (),
+ docRect.y () + origin ().y (),
+ docRect.width (),
+ docRect.height ());
+ }
+ else
+ {
+ const QPoint viewTopLeft = transformDocToView (docRect.topLeft ());
+
+ // (don't call transformDocToView[XY]() - need to round up dimensions)
+ const int viewWidth = qRound (double (docRect.width ()) * double (zoomLevelX ()) / 100.0);
+ const int viewHeight = qRound (double (docRect.height ()) * double (zoomLevelY ()) / 100.0);
+
+ // (like QWMatrix::Areas)
+ return QRect (viewTopLeft.x (), viewTopLeft.y (), viewWidth, viewHeight);
+ }
+}
+
+
+// public
+QPoint kpView::transformViewToOtherView (const QPoint &viewPoint,
+ const kpView *otherView)
+{
+ if (this == otherView)
+ return viewPoint;
+
+ const double docX = transformViewToDocX (viewPoint.x ());
+ const double docY = transformViewToDocY (viewPoint.y ());
+
+ const double otherViewX = otherView->transformDocToViewX (docX);
+ const double otherViewY = otherView->transformDocToViewY (docY);
+
+ return QPoint ((int) otherViewX, (int) otherViewY);
+}
+
+
+// public
+int kpView::zoomedDocWidth () const
+{
+ return document () ? document ()->width () * zoomLevelX () / 100 : 0;
+}
+
+// public
+int kpView::zoomedDocHeight () const
+{
+ return document () ? document ()->height () * zoomLevelY () / 100 : 0;
+}
+
+
+// public
+void kpView::setHasMouse (bool yes)
+{
+ kpViewManager *vm = viewManager ();
+ if (!vm)
+ return;
+
+#if DEBUG_KP_VIEW && 0
+ kdDebug () << "kpView(" << name ()
+ << ")::setHasMouse(" << yes
+ << ") existing viewUnderCursor="
+ << (vm->viewUnderCursor () ? vm->viewUnderCursor ()->name () : "(none)")
+ << endl;
+#endif
+ if (yes && vm->viewUnderCursor () != this)
+ vm->setViewUnderCursor (this);
+ else if (!yes && vm->viewUnderCursor () == this)
+ vm->setViewUnderCursor (0);
+}
+
+
+// public
+void kpView::addToQueuedArea (const QRegion &region)
+{
+#if DEBUG_KP_VIEW && 0
+ kdDebug () << "kpView(" << name ()
+ << ")::addToQueuedArea() already=" << d->m_queuedUpdateArea
+ << " - plus - " << region
+ << endl;
+#endif
+ d->m_queuedUpdateArea += region;
+}
+
+// public
+void kpView::addToQueuedArea (const QRect &rect)
+{
+#if DEBUG_KP_VIEW && 0
+ kdDebug () << "kpView(" << name ()
+ << ")::addToQueuedArea() already=" << d->m_queuedUpdateArea
+ << " - plus - " << rect
+ << endl;
+#endif
+ d->m_queuedUpdateArea += rect;
+}
+
+// public
+void kpView::invalidateQueuedArea ()
+{
+#if DEBUG_KP_VIEW && 0
+ kdDebug () << "kpView::invalidateQueuedArea()" << endl;
+#endif
+
+ d->m_queuedUpdateArea = QRegion ();
+}
+
+// public
+void kpView::updateQueuedArea ()
+{
+ kpViewManager *vm = viewManager ();
+#if DEBUG_KP_VIEW && 0
+ kdDebug () << "kpView(" << name ()
+ << ")::updateQueuedArea() vm=" << (bool) vm
+ << " queueUpdates=" << (vm && vm->queueUpdates ())
+ << " fastUpdates=" << (vm && vm->fastUpdates ())
+ << " area=" << d->m_queuedUpdateArea
+ << endl;
+#endif
+
+ if (!vm)
+ return;
+
+ if (vm->queueUpdates ())
+ return;
+
+ if (!d->m_queuedUpdateArea.isNull ())
+ vm->updateView (this, d->m_queuedUpdateArea);
+
+ invalidateQueuedArea ();
+}
+
+// public
+void kpView::updateMicroFocusHint (const QRect &microFocusHint)
+{
+ int x = microFocusHint.topLeft().x();
+ int y = microFocusHint.topLeft().y();
+ int width = microFocusHint.width();
+ int height = microFocusHint.height();
+ setMicroFocusHint (x, y, width, height);
+}
+
+// public
+QRect kpView::selectionViewRect () const
+{
+ return selection () ?
+ transformDocToView (selection ()->boundingRect ()) :
+ QRect ();
+
+}
+
+// public
+QPoint kpView::mouseViewPoint (const QPoint &returnViewPoint) const
+{
+ if (returnViewPoint != KP_INVALID_POINT)
+ return returnViewPoint;
+ else
+ return mapFromGlobal (QCursor::pos ());
+}
+
+// public
+QPoint kpView::mouseViewPointRelativeToSelection (const QPoint &viewPoint) const
+{
+ if (!selection ())
+ return KP_INVALID_POINT;
+
+ return mouseViewPoint (viewPoint) - transformDocToView (selection ()->topLeft ());
+}
+
+// public
+bool kpView::mouseOnSelection (const QPoint &viewPoint) const
+{
+ const QRect selViewRect = selectionViewRect ();
+ if (!selViewRect.isValid ())
+ return false;
+
+ return selViewRect.contains (mouseViewPoint (viewPoint));
+}
+
+
+// public
+int kpView::textSelectionMoveBorderAtomicSize () const
+{
+ if (!selection () || !selection ()->isText ())
+ return 0;
+
+ return QMAX (4, zoomLevelX () / 100);
+}
+
+// public
+bool kpView::mouseOnSelectionToMove (const QPoint &viewPoint) const
+{
+ if (!mouseOnSelection (viewPoint))
+ return false;
+
+ if (!selection ()->isText ())
+ return true;
+
+ if (mouseOnSelectionResizeHandle (viewPoint))
+ return false;
+
+
+ const QPoint viewPointRelSel = mouseViewPointRelativeToSelection (viewPoint);
+
+ // Middle point should always be selectable
+ const QPoint selCenterDocPoint = selection ()->boundingRect ().center ();
+ if (tool () &&
+ tool ()->currentPoint () == selCenterDocPoint)
+ {
+ return false;
+ }
+
+
+ const int atomicSize = textSelectionMoveBorderAtomicSize ();
+ const QRect selViewRect = selectionViewRect ();
+
+ return (viewPointRelSel.x () < atomicSize ||
+ viewPointRelSel.x () >= selViewRect.width () - atomicSize ||
+ viewPointRelSel.y () < atomicSize ||
+ viewPointRelSel.y () >= selViewRect.height () - atomicSize);
+}
+
+
+// protected
+bool kpView::selectionLargeEnoughToHaveResizeHandlesIfAtomicSize (int atomicSize) const
+{
+ if (!selection ())
+ return false;
+
+ const QRect selViewRect = selectionViewRect ();
+
+ return (selViewRect.width () >= atomicSize * 5 ||
+ selViewRect.height () >= atomicSize * 5);
+}
+
+// public
+int kpView::selectionResizeHandleAtomicSize () const
+{
+ int atomicSize = QMIN (7, QMAX (4, zoomLevelX () / 100));
+ while (atomicSize > 0 &&
+ !selectionLargeEnoughToHaveResizeHandlesIfAtomicSize (atomicSize))
+ {
+ atomicSize--;
+ }
+
+ return atomicSize;
+}
+
+// public
+bool kpView::selectionLargeEnoughToHaveResizeHandles () const
+{
+ return (selectionResizeHandleAtomicSize () > 0);
+}
+
+// public
+QRegion kpView::selectionResizeHandlesViewRegion (bool forRenderer) const
+{
+ QRegion ret;
+
+ const int atomicLength = selectionResizeHandleAtomicSize ();
+ if (atomicLength <= 0)
+ return QRegion ();
+
+
+ // HACK: At low zoom (e.g. 100%), resize handles will probably be too
+ // big and overlap text / cursor / too much of selection.
+ //
+ // So limit the _visual_ size of handles at low zoom. The
+ // handles' grab area remains the same for usability; so yes,
+ // there are a few pixels that don't look grabable but they are.
+ //
+ // The real solution is to be able to partially render the
+ // handles outside of the selection view rect. If not possible,
+ // at least for text boxes, render text on top of handles.
+ int normalAtomicLength = atomicLength;
+ int vertEdgeAtomicLength = atomicLength;
+ if (forRenderer && selection ())
+ {
+ if (zoomLevelX () <= 150)
+ {
+ if (normalAtomicLength > 1)
+ normalAtomicLength--;
+
+ if (vertEdgeAtomicLength > 1)
+ vertEdgeAtomicLength--;
+ }
+
+ // 1 line of text?
+ if (selection ()->isText () && selection ()->textLines ().size () == 1)
+ {
+ if (zoomLevelX () <= 150)
+ vertEdgeAtomicLength = QMIN (vertEdgeAtomicLength, QMAX (2, zoomLevelX () / 100));
+ else if (zoomLevelX () <= 250)
+ vertEdgeAtomicLength = QMIN (vertEdgeAtomicLength, QMAX (3, zoomLevelX () / 100));
+ }
+ }
+
+
+ const QRect selViewRect = selectionViewRect ();
+
+#define ADD_BOX_RELATIVE_TO_SELECTION(type,x,y) \
+ ret += QRect ((x), (y), type##AtomicLength, type##AtomicLength)
+
+ ADD_BOX_RELATIVE_TO_SELECTION (normal,
+ selViewRect.width () - normalAtomicLength,
+ selViewRect.height () - normalAtomicLength);
+ ADD_BOX_RELATIVE_TO_SELECTION (normal,
+ selViewRect.width () - normalAtomicLength,
+ 0);
+ ADD_BOX_RELATIVE_TO_SELECTION (normal,
+ 0,
+ selViewRect.height () - normalAtomicLength);
+ ADD_BOX_RELATIVE_TO_SELECTION (normal,
+ 0,
+ 0);
+
+ ADD_BOX_RELATIVE_TO_SELECTION (vertEdge,
+ selViewRect.width () - vertEdgeAtomicLength,
+ (selViewRect.height () - vertEdgeAtomicLength) / 2);
+ ADD_BOX_RELATIVE_TO_SELECTION (normal,
+ (selViewRect.width () - normalAtomicLength) / 2,
+ selViewRect.height () - normalAtomicLength);
+ ADD_BOX_RELATIVE_TO_SELECTION (normal,
+ (selViewRect.width () - normalAtomicLength) / 2,
+ 0);
+ ADD_BOX_RELATIVE_TO_SELECTION (vertEdge,
+ 0,
+ (selViewRect.height () - vertEdgeAtomicLength) / 2);
+
+#undef ADD_BOX_RELATIVE_TO_SELECTION
+
+ ret.translate (selViewRect.x (), selViewRect.y ());
+ ret = ret.intersect (selViewRect);
+
+ return ret;
+}
+
+// public
+int kpView::mouseOnSelectionResizeHandle (const QPoint &viewPoint) const
+{
+#if DEBUG_KP_VIEW
+ kdDebug () << "kpView::mouseOnSelectionResizeHandle(viewPoint="
+ << viewPoint << ")" << endl;
+#endif
+
+ if (!mouseOnSelection (viewPoint))
+ {
+ #if DEBUG_KP_VIEW
+ kdDebug () << "\tmouse not on sel" << endl;
+ #endif
+ return 0;
+ }
+
+
+ const QRect selViewRect = selectionViewRect ();
+#if DEBUG_KP_VIEW
+ kdDebug () << "\tselViewRect=" << selViewRect << endl;
+#endif
+
+
+ const int atomicLength = selectionResizeHandleAtomicSize ();
+#if DEBUG_KP_VIEW
+ kdDebug () << "\tatomicLength=" << atomicLength << endl;
+#endif
+
+ if (atomicLength <= 0)
+ {
+ #if DEBUG_KP_VIEW
+ kdDebug () << "\tsel not large enough to have resize handles" << endl;
+ #endif
+ // Want to make it possible to move a small selection
+ return 0;
+ }
+
+
+ const QPoint viewPointRelSel = mouseViewPointRelativeToSelection (viewPoint);
+#if DEBUG_KP_VIEW
+ kdDebug () << "\tviewPointRelSel=" << viewPointRelSel << endl;
+#endif
+
+
+#define LOCAL_POINT_IN_BOX_AT(x,y) \
+ QRect ((x), (y), atomicLength, atomicLength).contains (viewPointRelSel)
+
+ // Favour the bottom & right and the corners.
+ if (LOCAL_POINT_IN_BOX_AT (selViewRect.width () - atomicLength,
+ selViewRect.height () - atomicLength))
+ {
+ return Bottom | Right;
+ }
+ else if (LOCAL_POINT_IN_BOX_AT (selViewRect.width () - atomicLength, 0))
+ {
+ return Top | Right;
+ }
+ else if (LOCAL_POINT_IN_BOX_AT (0, selViewRect.height () - atomicLength))
+ {
+ return Bottom | Left;
+ }
+ else if (LOCAL_POINT_IN_BOX_AT (0, 0))
+ {
+ return Top | Left;
+ }
+ else if (LOCAL_POINT_IN_BOX_AT (selViewRect.width () - atomicLength,
+ (selViewRect.height () - atomicLength) / 2))
+ {
+ return Right;
+ }
+ else if (LOCAL_POINT_IN_BOX_AT ((selViewRect.width () - atomicLength) / 2,
+ selViewRect.height () - atomicLength))
+ {
+ return Bottom;
+ }
+ else if (LOCAL_POINT_IN_BOX_AT ((selViewRect.width () - atomicLength) / 2, 0))
+ {
+ return Top;
+ }
+ else if (LOCAL_POINT_IN_BOX_AT (0, (selViewRect.height () - atomicLength) / 2))
+ {
+ return Left;
+ }
+ else
+ {
+ #if DEBUG_KP_VIEW
+ kdDebug () << "\tnot on sel resize handle" << endl;
+ #endif
+ return 0;
+ }
+#undef LOCAL_POINT_IN_BOX_AT
+}
+
+// public
+bool kpView::mouseOnSelectionToSelectText (const QPoint &viewPoint) const
+{
+#if DEBUG_KP_VIEW
+ kdDebug () << "kpView::mouseOnSelectionToSelectText(viewPoint="
+ << viewPoint << ")" << endl;
+#endif
+
+ if (!mouseOnSelection (viewPoint))
+ {
+ #if DEBUG_KP_VIEW
+ kdDebug () << "\tmouse non on sel" << endl;
+ #endif
+ return false;
+ }
+
+ if (!selection ()->isText ())
+ {
+ #if DEBUG_KP_VIEW
+ kdDebug () << "\tsel not text" << endl;
+ #endif
+ return false;
+ }
+
+#if DEBUG_KP_VIEW
+ kdDebug () << "\tmouse on sel: to move=" << mouseOnSelectionToMove ()
+ << " to resize=" << mouseOnSelectionResizeHandle ()
+ << endl;
+#endif
+
+ return (!mouseOnSelectionToMove (viewPoint) &&
+ !mouseOnSelectionResizeHandle (viewPoint));
+}
+
+
+// protected virtual [base QWidget]
+void kpView::mouseMoveEvent (QMouseEvent *e)
+{
+#if DEBUG_KP_VIEW && 0
+ kdDebug () << "kpView(" << name () << ")::mouseMoveEvent ("
+ << e->x () << "," << e->y () << ")"
+ << endl;
+#endif
+
+ // TODO: This is wrong if you leaveEvent the mainView by mouseMoving on the
+ // mainView, landing on top of the thumbnailView cleverly put on top
+ // of the mainView.
+ setHasMouse (rect ().contains (e->pos ()));
+
+ if (tool ())
+ tool ()->mouseMoveEvent (e);
+
+ e->accept ();
+}
+
+// protected virtual [base QWidget]
+void kpView::mousePressEvent (QMouseEvent *e)
+{
+#if DEBUG_KP_VIEW && 0
+ kdDebug () << "kpView(" << name () << ")::mousePressEvent ("
+ << e->x () << "," << e->y () << ")"
+ << endl;
+#endif
+
+ setHasMouse (true);
+
+ if (tool ())
+ tool ()->mousePressEvent (e);
+
+ e->accept ();
+}
+
+// protected virtual [base QWidget]
+void kpView::mouseReleaseEvent (QMouseEvent *e)
+{
+#if DEBUG_KP_VIEW && 0
+ kdDebug () << "kpView(" << name () << ")::mouseReleaseEvent ("
+ << e->x () << "," << e->y () << ")"
+ << endl;
+#endif
+
+ setHasMouse (rect ().contains (e->pos ()));
+
+ if (tool ())
+ tool ()->mouseReleaseEvent (e);
+
+ e->accept ();
+}
+
+// public virtual [base QWidget]
+void kpView::wheelEvent (QWheelEvent *e)
+{
+ if (tool ())
+ tool ()->wheelEvent (e);
+}
+
+
+// protected virtual [base QWidget]
+void kpView::keyPressEvent (QKeyEvent *e)
+{
+#if DEBUG_KP_VIEW && 0
+ kdDebug () << "kpView(" << name () << ")::keyPressEvent()" << endl;
+#endif
+
+ if (tool ())
+ tool ()->keyPressEvent (e);
+
+ e->accept ();
+}
+
+// protected virtual [base QWidget]
+void kpView::keyReleaseEvent (QKeyEvent *e)
+{
+#if DEBUG_KP_VIEW && 0
+ kdDebug () << "kpView(" << name () << ")::keyReleaseEvent()" << endl;
+#endif
+
+ if (tool ())
+ tool ()->keyReleaseEvent (e);
+
+ e->accept ();
+}
+
+
+// protected virtual [base QWidget]
+void kpView::focusInEvent (QFocusEvent *e)
+{
+#if DEBUG_KP_VIEW && 0
+ kdDebug () << "kpView(" << name () << ")::focusInEvent()" << endl;
+#endif
+ if (tool ())
+ tool ()->focusInEvent (e);
+}
+
+// protected virtual [base QWidget]
+void kpView::focusOutEvent (QFocusEvent *e)
+{
+#if DEBUG_KP_VIEW && 0
+ kdDebug () << "kpView(" << name () << ")::focusOutEvent()" << endl;
+#endif
+ if (tool ())
+ tool ()->focusOutEvent (e);
+}
+
+
+// protected virtual [base QWidget]
+void kpView::enterEvent (QEvent *e)
+{
+#if DEBUG_KP_VIEW && 0
+ kdDebug () << "kpView(" << name () << ")::enterEvent()" << endl;
+#endif
+
+ // Don't call setHasMouse(true) as it displays the brush cursor (if
+ // active) when dragging open a menu and then dragging
+ // past the extents of the menu due to Qt sending us an EnterEvent.
+ // We're already covered by MouseMoveEvent anyway.
+ //
+ // But disabling this causes a more serious problem: RMB on a text
+ // box and Esc. We have no other reliable way to determine if the
+ // mouse is still above the view (user could have moved mouse out
+ // while RMB menu was up) and hence the cursor is not updated.
+ setHasMouse (true);
+
+ if (tool ())
+ tool ()->enterEvent (e);
+}
+
+// protected virtual [base QWidget]
+void kpView::leaveEvent (QEvent *e)
+{
+#if DEBUG_KP_VIEW && 0
+ kdDebug () << "kpView(" << name () << ")::leaveEvent()" << endl;
+#endif
+
+ setHasMouse (false);
+ if (tool ())
+ tool ()->leaveEvent (e);
+}
+
+
+// protected virtual [base QWidget]
+void kpView::dragEnterEvent (QDragEnterEvent *)
+{
+#if DEBUG_KP_VIEW && 1
+ kdDebug () << "kpView(" << name () << ")::dragEnterEvent()" << endl;
+#endif
+
+ setHasMouse (true);
+}
+
+// protected virtual [base QWidget]
+void kpView::dragLeaveEvent (QDragLeaveEvent *)
+{
+#if DEBUG_KP_VIEW && 1
+ kdDebug () << "kpView(" << name () << ")::dragLeaveEvent" << endl;
+#endif
+
+ setHasMouse (false);
+}
+
+
+// public virtual [base QWidget]
+void kpView::resize (int w, int h)
+{
+#if DEBUG_KP_VIEW && 1
+ kdDebug () << "kpView(" << name ()
+ << ")::resize(" << w << "," << h << ")"
+ << endl;
+#endif
+
+ QWidget::resize (w, h);
+}
+
+// protected virtual [base QWidget]
+void kpView::resizeEvent (QResizeEvent *e)
+{
+#if DEBUG_KP_VIEW && 1
+ kdDebug () << "kpView(" << name () << ")::resizeEvent("
+ << e->size ()
+ << " vs actual=" << size ()
+ << ") old=" << e->oldSize () << endl;
+#endif
+
+ QWidget::resizeEvent (e);
+
+ emit sizeChanged (width (), height ());
+ emit sizeChanged (size ());
+}
+
+
+// private virtual
+void kpView::imStartEvent (QIMEvent *e)
+{
+#if DEBUG_KP_VIEW && 1
+ kdDebug () << "kpView(" << name () << ")::imStartEvent" << endl;
+#endif
+
+ if (tool ())
+ tool ()->imStartEvent (e);
+ e->accept();
+}
+
+// private virtual
+void kpView::imComposeEvent (QIMEvent *e)
+{
+#if DEBUG_KP_VIEW && 1
+ kdDebug () << "kpView(" << name () << ")::imComposeEvent" << endl;
+#endif
+
+ if (tool ())
+ tool ()->imComposeEvent (e);
+ e->accept();
+}
+
+// private virtual
+void kpView::imEndEvent (QIMEvent *e)
+{
+#if DEBUG_KP_VIEW && 1
+ kdDebug () << "kpView(" << name () << ")::imEndEvent" << endl;
+#endif
+
+ if (tool ())
+ tool ()->imEndEvent (e);
+ e->accept();
+}
+
+
+//
+// Renderer
+//
+
+// protected
+QRect kpView::paintEventGetDocRect (const QRect &viewRect) const
+{
+#if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "kpView::paintEventGetDocRect(" << viewRect << ")" << endl;
+#endif
+
+ QRect docRect;
+
+ // From the "we aren't sure whether to round up or round down" department:
+
+ if (zoomLevelX () < 100 || zoomLevelY () < 100)
+ docRect = transformViewToDoc (viewRect);
+ else
+ {
+ // think of a grid - you need to fully cover the zoomed-in pixels
+ // when docRect is zoomed back to the view later
+ docRect = QRect (transformViewToDoc (viewRect.topLeft ()), // round down
+ transformViewToDoc (viewRect.bottomRight ())); // round down
+ }
+
+ if (zoomLevelX () % 100 || zoomLevelY () % 100)
+ {
+ // at least round up the bottom-right point and deal with matrix weirdness:
+ // - helpful because it ensures we at least cover the required area
+ // at e.g. 67% or 573%
+ // - harmless since paintEventDrawRect() clips for us anyway
+ docRect.setBottomRight (docRect.bottomRight () + QPoint (2, 2));
+ }
+
+#if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "\tdocRect=" << docRect << endl;
+#endif
+ kpDocument *doc = document ();
+ if (doc)
+ {
+ docRect = docRect.intersect (doc->rect ());
+ #if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "\tintersect with doc=" << docRect << endl;
+ #endif
+ }
+
+ return docRect;
+}
+
+// public
+void kpView::drawTransparentBackground (QPainter *painter,
+ int /*viewWidth*/, int /*viewHeight*/,
+ const QRect &rect,
+ bool isPreview)
+{
+ const int cellSize = !isPreview ? 16 : 10;
+
+ int starty = rect.y ();
+ if (starty % cellSize)
+ starty -= (starty % cellSize);
+
+ int startx = rect.x ();
+ if (startx % cellSize)
+ startx -= (startx % cellSize);
+
+ painter->save ();
+ for (int y = starty; y <= rect.bottom (); y += cellSize)
+ {
+ for (int x = startx; x <= rect.right (); x += cellSize)
+ {
+ bool parity = (x / cellSize + y / cellSize) % 2;
+ QColor col;
+
+ if (parity)
+ {
+ if (!isPreview)
+ col = QColor (213, 213, 213);
+ else
+ col = QColor (224, 224, 224);
+ }
+ else
+ col = Qt::white;
+
+ painter->fillRect (x - rect.x (), y - rect.y (), cellSize, cellSize,
+ col);
+ }
+ }
+ painter->restore ();
+}
+
+// protected
+void kpView::paintEventDrawCheckerBoard (QPainter *painter, const QRect &viewRect)
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ drawTransparentBackground (painter,
+ doc->width () * zoomLevelX () / 100,
+ doc->height () * zoomLevelY () / 100,
+ viewRect);
+}
+
+// protected
+void kpView::paintEventDrawSelection (QPixmap *destPixmap, const QRect &docRect)
+{
+#if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "kpView::paintEventDrawSelection() docRect=" << docRect << endl;
+#endif
+
+ kpDocument *doc = document ();
+ if (!doc)
+ {
+ #if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "\tno doc - abort" << endl;
+ #endif
+ return;
+ }
+
+ kpSelection *sel = doc->selection ();
+ if (!sel)
+ {
+ #if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "\tno sel - abort" << endl;
+ #endif
+ return;
+ }
+
+
+ //
+ // Draw selection pixmap (if there is one)
+ //
+#if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "\tdraw sel pixmap @ " << sel->topLeft () << endl;
+#endif
+ sel->paint (destPixmap, docRect);
+
+
+ //
+ // Draw selection border
+ //
+
+ kpViewManager *vm = viewManager ();
+#if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "\tsel border visible="
+ << vm->selectionBorderVisible ()
+ << endl;
+#endif
+ if (vm->selectionBorderVisible ())
+ {
+ QPainter destPixmapPainter (destPixmap);
+ destPixmapPainter.setRasterOp (Qt::XorROP);
+ destPixmapPainter.setPen (QPen (Qt::white, 1, Qt::DotLine));
+
+ destPixmapPainter.setBackgroundMode (QPainter::OpaqueMode);
+ destPixmapPainter.setBackgroundColor (Qt::blue);
+
+ QBitmap maskBitmap;
+ QPainter maskBitmapPainter;
+ if (destPixmap->mask ())
+ {
+ maskBitmap = *destPixmap->mask ();
+ maskBitmapPainter.begin (&maskBitmap);
+ maskBitmapPainter.setPen (Qt::color1/*opaque*/);
+ }
+
+
+ #define PAINTER_CMD(cmd) \
+ { \
+ destPixmapPainter . cmd; \
+ if (maskBitmapPainter.isActive ()) \
+ maskBitmapPainter . cmd; \
+ }
+
+ QRect boundingRect = sel->boundingRect ();
+ #if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "\tsel boundingRect="
+ << boundingRect
+ << endl;
+ #endif
+
+ if (boundingRect.topLeft () != boundingRect.bottomRight ())
+ {
+ switch (sel->type ())
+ {
+ case kpSelection::Rectangle:
+ case kpSelection::Text:
+ #if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "\tselection border = rectangle" << endl;
+ kdDebug () << "\t\tx=" << boundingRect.x () - docRect.x ()
+ << " y=" << boundingRect.y () - docRect.y ()
+ << " w=" << boundingRect.width ()
+ << " h=" << boundingRect.height ()
+ << endl;
+ #endif
+ PAINTER_CMD (drawRect (boundingRect.x () - docRect.x (),
+ boundingRect.y () - docRect.y (),
+ boundingRect.width (),
+ boundingRect.height ()));
+ break;
+
+ case kpSelection::Ellipse:
+ #if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "\tselection border = ellipse" << endl;
+ #endif
+ PAINTER_CMD (drawEllipse (boundingRect.x () - docRect.x (),
+ boundingRect.y () - docRect.y (),
+ boundingRect.width (),
+ boundingRect.height ()));
+ break;
+
+ case kpSelection::Points:
+ {
+ #if DEBUG_KP_VIEW_RENDERER
+ kdDebug () << "\tselection border = freeForm" << endl;
+ #endif
+ QPointArray points = sel->points ();
+ points.detach ();
+ points.translate (-docRect.x (), -docRect.y ());
+ if (vm->selectionBorderFinished ())
+ {
+ PAINTER_CMD (drawPolygon (points));
+ }
+ else
+ {
+ PAINTER_CMD (drawPolyline (points));
+ }
+
+ break;
+ }
+
+ default:
+ kdError () << "kpView::paintEventDrawSelection() unknown sel border type" << endl;
+ break;
+ }
+
+
+ if (vm->selectionBorderFinished () &&
+ (sel->type () == kpSelection::Ellipse ||
+ sel->type () == kpSelection::Points))
+ {
+ destPixmapPainter.save ();
+
+ destPixmapPainter.setRasterOp (Qt::NotROP);
+ PAINTER_CMD (drawRect (boundingRect.x () - docRect.x (),
+ boundingRect.y () - docRect.y (),
+ boundingRect.width (),
+ boundingRect.height ()));
+
+ destPixmapPainter.restore ();
+ }
+ }
+ else
+ {
+ // SYNC: Work around Qt bug: can't draw 1x1 rectangle
+ PAINTER_CMD (drawPoint (boundingRect.topLeft () - docRect.topLeft ()));
+ }
+
+ #undef PAINTER_CMD
+
+ destPixmapPainter.end ();
+ if (maskBitmapPainter.isActive ())
+ maskBitmapPainter.end ();
+
+ destPixmap->setMask (maskBitmap);
+ }
+
+
+ //
+ // Draw text cursor
+ //
+
+ if (sel->isText () &&
+ vm->textCursorEnabled () &&
+ (vm->textCursorBlinkState () ||
+ // For the current main window:
+ // As long as _any_ view has focus, blink _all_ views not just the
+ // one with focus // !this->isActiveWindow ()
+ !vm->activeView ())) // sync: call will break when vm is not held by 1 mainWindow
+ {
+ // TODO: Fix code duplication: kpViewManager::{setTextCursorPosition,updateTextCursor}() & kpView::paintEventDrawSelection()
+ QPoint topLeft = sel->pointForTextRowCol (vm->textCursorRow (), vm->textCursorCol ());
+ if (topLeft != KP_INVALID_POINT)
+ {
+ QRect rect = QRect (topLeft.x (), topLeft.y (),
+ 1, sel->textStyle ().fontMetrics ().height ());
+ rect = rect.intersect (sel->textAreaRect ());
+ if (!rect.isEmpty ())
+ {
+ rect.moveBy (-docRect.x (), -docRect.y ());
+
+ QBitmap maskBitmap;
+ QPainter destPixmapPainter, maskBitmapPainter;
+
+ if (destPixmap->mask ())
+ {
+ maskBitmap = *destPixmap->mask ();
+ maskBitmapPainter.begin (&maskBitmap);
+ maskBitmapPainter.fillRect (rect, Qt::color1/*opaque*/);
+ maskBitmapPainter.end ();
+ }
+
+ destPixmapPainter.begin (destPixmap);
+ destPixmapPainter.setRasterOp (Qt::XorROP);
+ destPixmapPainter.fillRect (rect, Qt::white);
+ destPixmapPainter.end ();
+
+ if (!maskBitmap.isNull ())
+ destPixmap->setMask (maskBitmap);
+ }
+ }
+ }
+}
+
+// protected
+bool kpView::selectionResizeHandleAtomicSizeCloseToZoomLevel () const
+{
+ return (abs (selectionResizeHandleAtomicSize () - zoomLevelX () / 100) < 3);
+}
+
+// protected
+void kpView::paintEventDrawSelectionResizeHandles (QPainter *painter, const QRect &viewRect)
+{
+#if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "kpView::paintEventDrawSelectionResizeHandles("
+ << viewRect << ")" << endl;
+#endif
+
+ if (!selectionLargeEnoughToHaveResizeHandles ())
+ {
+ #if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "\tsel not large enough to have resize handles" << endl;
+ #endif
+ return;
+ }
+
+ kpViewManager *vm = viewManager ();
+ if (!vm || !vm->selectionBorderVisible () || !vm->selectionBorderFinished ())
+ {
+ #if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "\tsel border not visible or not finished" << endl;
+ #endif
+
+ return;
+ }
+
+ const QRect selViewRect = selectionViewRect ();
+#if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "\tselViewRect=" << selViewRect << endl;
+#endif
+ if (!selViewRect.intersects (viewRect))
+ {
+ #if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "\tdoesn't intersect viewRect" << endl;
+ #endif
+ return;
+ }
+
+ QRegion selResizeHandlesRegion = selectionResizeHandlesViewRegion (true/*for renderer*/);
+#if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "\tsel resize handles view region="
+ << selResizeHandlesRegion << endl;
+#endif
+ selResizeHandlesRegion.translate (-viewRect.x (), -viewRect.y ());
+
+ painter->save ();
+
+ QColor fillColor;
+ if (selectionResizeHandleAtomicSizeCloseToZoomLevel ())
+ {
+ fillColor = Qt::blue;
+ painter->setRasterOp (Qt::CopyROP);
+ }
+ else
+ {
+ fillColor = Qt::white;
+ painter->setRasterOp (Qt::XorROP);
+ }
+
+ QMemArray <QRect> rects = selResizeHandlesRegion.rects ();
+ for (QMemArray <QRect>::ConstIterator it = rects.begin ();
+ it != rects.end ();
+ it++)
+ {
+ painter->fillRect (*it, fillColor);
+ }
+
+ painter->restore ();
+}
+
+// protected
+void kpView::paintEventDrawTempPixmap (QPixmap *destPixmap, const QRect &docRect)
+{
+ kpViewManager *vm = viewManager ();
+ if (!vm)
+ return;
+
+ const kpTempPixmap *tpm = vm->tempPixmap ();
+#if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "kpView::paintEventDrawTempPixmap() tempPixmap="
+ << tpm
+ << " isVisible="
+ << (tpm ? tpm->isVisible (vm) : false)
+ << endl;
+#endif
+
+ if (!tpm || !tpm->isVisible (vm))
+ return;
+
+ tpm->paint (destPixmap, docRect);
+}
+
+// protected
+void kpView::paintEventDrawGridLines (QPainter *painter, const QRect &viewRect)
+{
+ int hzoomMultiple = zoomLevelX () / 100;
+ int vzoomMultiple = zoomLevelY () / 100;
+
+ QPen ordinaryPen (Qt::gray);
+ QPen tileBoundaryPen (Qt::lightGray);
+
+ painter->setPen (ordinaryPen);
+
+ // horizontal lines
+ int starty = viewRect.top ();
+ if (starty % vzoomMultiple)
+ starty = (starty + vzoomMultiple) / vzoomMultiple * vzoomMultiple;
+ int tileHeight = 16 * vzoomMultiple; // CONFIG
+ for (int y = starty - viewRect.y (); y <= viewRect.bottom () - viewRect.y (); y += vzoomMultiple)
+ {
+ if (0 && tileHeight > 0 && y % tileHeight == 0)
+ {
+ painter->setPen (tileBoundaryPen);
+ //painter.setRasterOp (Qt::XorROP);
+ }
+
+ painter->drawLine (0, y, viewRect.right () - viewRect.left (), y);
+
+ if (0 && tileHeight > 0 && y % tileHeight == 0)
+ {
+ painter->setPen (ordinaryPen);
+ //painter.setRasterOp (Qt::CopyROP);
+ }
+ }
+
+ // vertical lines
+ int startx = viewRect.left ();
+ if (startx % hzoomMultiple)
+ startx = (startx + hzoomMultiple) / hzoomMultiple * hzoomMultiple;
+ int tileWidth = 16 * hzoomMultiple; // CONFIG
+ for (int x = startx - viewRect.x (); x <= viewRect.right () - viewRect.x (); x += hzoomMultiple)
+ {
+ if (0 && tileWidth > 0 && x % tileWidth == 0)
+ {
+ painter->setPen (tileBoundaryPen);
+ //painter.setRasterOp (Qt::XorROP);
+ }
+
+ painter->drawLine (x, 0, x, viewRect.bottom () - viewRect.top ());
+
+ if (0 && tileWidth > 0 && x % tileWidth == 0)
+ {
+ painter->setPen (ordinaryPen);
+ //painter.setRasterOp (Qt::CopyROP);
+ }
+ }
+}
+
+
+void kpView::paintEventDrawRect (const QRect &viewRect)
+{
+#if DEBUG_KP_VIEW_RENDERER
+ kdDebug () << "\tkpView::paintEventDrawRect(viewRect=" << viewRect
+ << ")" << endl;
+#endif
+
+ kpViewManager *vm = viewManager ();
+ const kpDocument *doc = document ();
+
+ if (!vm || !doc)
+ return;
+
+
+ if (viewRect.isEmpty ())
+ return;
+
+
+ QRect docRect = paintEventGetDocRect (viewRect);
+
+#if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "\tdocRect=" << docRect << endl;
+#endif
+
+// uncomment to cause deliberate flicker (identifies needless updates)
+#if DEBUG_KP_VIEW_RENDERER && 0
+ QPainter flickerPainter (this);
+ flickerPainter.fillRect (viewRect, Qt::red);
+ flickerPainter.end ();
+#endif
+
+
+ //
+ // Prepare Back Buffer
+ //
+
+ if (!d->m_backBuffer ||
+ d->m_backBuffer->width () < viewRect.width () ||
+ d->m_backBuffer->height () < viewRect.height () ||
+ d->m_backBuffer->width () > width () ||
+ d->m_backBuffer->height () > height ())
+ {
+ // don't use QPixmap::resize() as that wastes time copying pixels
+ // that will be overwritten anyway
+ //
+ // OPT: Should use doubling trick or at least go up in multiples
+ // to reduce X server pressure.
+ delete d->m_backBuffer;
+ d->m_backBuffer = new QPixmap (viewRect.width (), viewRect.height ());
+ }
+
+// uncomment to catch bits of the view that the renderer forgot to update
+#if 0
+ d->m_backBuffer->fill (Qt::green);
+#endif
+
+ QPainter backBufferPainter;
+ backBufferPainter.begin (d->m_backBuffer);
+
+
+ //
+ // Draw checkboard for transparent images and/or views with borders
+ //
+
+ QPixmap docPixmap;
+
+ bool tempPixmapWillBeRendered = false;
+
+ if (!docRect.isEmpty ())
+ {
+ docPixmap = doc->getPixmapAt (docRect);
+
+ tempPixmapWillBeRendered =
+ (!doc->selection () &&
+ vm->tempPixmap () &&
+ vm->tempPixmap ()->isVisible (vm) &&
+ docRect.intersects (vm->tempPixmap ()->rect ()));
+
+ #if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "\ttempPixmapWillBeRendered=" << tempPixmapWillBeRendered
+ << " (sel=" << doc->selection ()
+ << " tempPixmap=" << vm->tempPixmap ()
+ << " tempPixmap.isVisible=" << (vm->tempPixmap () ? vm->tempPixmap ()->isVisible (vm) : false)
+ << " docRect.intersects(tempPixmap.rect)=" << (vm->tempPixmap () ? docRect.intersects (vm->tempPixmap ()->rect ()) : false)
+ << ")"
+ << endl;
+ #endif
+ }
+
+ if (docPixmap.mask () ||
+ (tempPixmapWillBeRendered && vm->tempPixmap ()->mayChangeDocumentMask ()))
+ {
+ #if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "\tmask=" << (bool) docPixmap.mask ()
+ << endl;
+ #endif
+ paintEventDrawCheckerBoard (&backBufferPainter, viewRect);
+ }
+ else
+ {
+ #if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "\tno mask" << endl;
+ #endif
+ }
+
+
+ if (!docRect.isEmpty ())
+ {
+ //
+ // Draw docPixmap + tempPixmap
+ //
+
+ if (doc->selection ())
+ {
+ paintEventDrawSelection (&docPixmap, docRect);
+ }
+ else if (tempPixmapWillBeRendered)
+ {
+ paintEventDrawTempPixmap (&docPixmap, docRect);
+ }
+
+ #if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "\torigin=" << origin () << endl;
+ #endif
+ // blit scaled version of docPixmap + tempPixmap onto Back Buffer
+ #if DEBUG_KP_VIEW_RENDERER && 1
+ QTime scaleTimer; scaleTimer.start ();
+ #endif
+ backBufferPainter.translate (origin ().x () - viewRect.x (),
+ origin ().y () - viewRect.y ());
+ backBufferPainter.scale (double (zoomLevelX ()) / 100.0,
+ double (zoomLevelY ()) / 100.0);
+ backBufferPainter.drawPixmap (docRect, docPixmap);
+ backBufferPainter.resetXForm (); // back to 1-1 scaling
+ #if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "\tscale time=" << scaleTimer.elapsed () << endl;
+ #endif
+
+ } // if (!docRect.isEmpty ()) {
+
+
+ //
+ // Draw Grid Lines
+ //
+
+ if (isGridShown ())
+ {
+ #if DEBUG_KP_VIEW_RENDERER && 1
+ QTime gridTimer; gridTimer.start ();
+ #endif
+ paintEventDrawGridLines (&backBufferPainter, viewRect);
+ #if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "\tgrid time=" << gridTimer.elapsed () << endl;
+ #endif
+ }
+
+
+ const QRect bvsvRect = buddyViewScrollableContainerRectangle ();
+ if (!bvsvRect.isEmpty ())
+ {
+ backBufferPainter.save ();
+
+ backBufferPainter.setRasterOp (Qt::XorROP);
+ backBufferPainter.setPen (Qt::white);
+ backBufferPainter.translate (-viewRect.x (), -viewRect.y ());
+ backBufferPainter.drawRect (bvsvRect);
+
+ backBufferPainter.restore ();
+ }
+
+
+ if (!docRect.isEmpty ())
+ {
+ if (doc->selection ())
+ {
+ // Draw resize handles on top of possible grid lines
+ paintEventDrawSelectionResizeHandles (&backBufferPainter, viewRect);
+ }
+ }
+
+
+ //
+ // Blit Back Buffer to View
+ //
+
+ backBufferPainter.end ();
+
+ bitBlt (this, viewRect.topLeft (),
+ d->m_backBuffer, QRect (0, 0, viewRect.width (), viewRect.height ()));
+}
+
+
+// protected virtual [base QWidget]
+void kpView::paintEvent (QPaintEvent *e)
+{
+ // sync: kpViewPrivate
+ // WARNING: document(), viewManager() and friends might be 0 in this method.
+ // TODO: I'm not 100% convinced that we always check if their friends are 0.
+
+#if DEBUG_KP_VIEW_RENDERER && 1
+ QTime timer;
+ timer.start ();
+#endif
+
+ kpViewManager *vm = viewManager ();
+
+#if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "kpView(" << name () << ")::paintEvent() vm=" << (bool) vm
+ << " queueUpdates=" << (vm && vm->queueUpdates ())
+ << " fastUpdates=" << (vm && vm->fastUpdates ())
+ << " viewRect=" << e->rect ()
+ << " erased=" << e->erased ()
+ << " topLeft=" << QPoint (x (), y ())
+ << endl;
+#endif
+
+ if (!vm)
+ return;
+
+ if (vm->queueUpdates ())
+ {
+ // OPT: if this update was due to the document,
+ // use document coordinates (in case of a zoom change in
+ // which view coordinates become out of date)
+ addToQueuedArea (e->region ());
+ return;
+ }
+
+
+ QRegion viewRegion = clipRegion ().intersect (e->region ());
+ QMemArray <QRect> rects = viewRegion.rects ();
+#if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "\t#rects = " << rects.count () << endl;
+#endif
+
+ for (QMemArray <QRect>::ConstIterator it = rects.begin ();
+ it != rects.end ();
+ it++)
+ {
+ paintEventDrawRect (*it);
+ }
+
+
+#if DEBUG_KP_VIEW_RENDERER && 1
+ kdDebug () << "\tall done in: " << timer.restart () << "ms" << endl;
+#endif
+}
+
+
+#include <kpview.moc>
diff --git a/kolourpaint/kpview.h b/kolourpaint/kpview.h
new file mode 100644
index 00000000..0bf8c495
--- /dev/null
+++ b/kolourpaint/kpview.h
@@ -0,0 +1,535 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef KP_VIEW_H
+#define KP_VIEW_H
+
+
+#include <qwidget.h>
+
+#include <kpdefs.h>
+
+
+class kpDocument;
+class kpSelection;
+class kpTool;
+class kpToolToolBar;
+class kpViewManager;
+class kpViewScrollableContainer;
+
+
+/**
+ * @short Abstract base class for all views.
+ *
+ * This is the abstract base class for all views. A view is a widget that
+ * renders a possibly zoomed onscreen representation of a document.
+ *
+ * 1 view corresponds to 1 document.
+ * 1 document corresponds to 0 or more views.
+ *
+ * @see kpViewManager
+ *
+ * @author Clarence Dang <dang@kde.org>
+ */
+class kpView : public QWidget
+{
+Q_OBJECT
+
+public:
+ /**
+ * Constructs a view.
+ *
+ * @param document The document this view is representing.
+ * @param toolToolBar The tool tool bar.
+ * @param viewManager The view manager.
+ * @param buddyView The view this view watches over (e.g. a thumbnail
+ * view would watch over the main view). May be 0.
+ * See for example, highlightBuddyViewRectangle().
+ * @param scrollableContainer This view's scrollable container.
+ * May be 0.
+ *
+ * You must call adjustEnvironment() at the end of your constructor.
+ */
+ kpView (kpDocument *document,
+ kpToolToolBar *toolToolBar,
+ kpViewManager *viewManager,
+ kpView *buddyView,
+ kpViewScrollableContainer *scrollableContainer,
+ QWidget *parent, const char *name);
+
+ /**
+ * Destructs this view. Informs the viewManager() that the mouse
+ * cursor is no longer above this view.
+ */
+ virtual ~kpView ();
+
+
+ /**
+ * @returns the document.
+ */
+ kpDocument *document () const;
+
+protected:
+ /**
+ * @returns the document's selection.
+ */
+ kpSelection *selection () const;
+
+public:
+ /**
+ * @returns the tool tool bar.
+ */
+ kpToolToolBar *toolToolBar () const;
+
+protected:
+ /**
+ * @returns the currently selected tool.
+ */
+ kpTool *tool () const;
+
+public:
+ /**
+ * @returns the view manager.
+ */
+ kpViewManager *viewManager () const;
+
+ /**
+ * @returns the buddy view.
+ */
+ kpView *buddyView () const;
+
+ /**
+ * @returns the buddyView()'s scrollable container.
+ */
+ kpViewScrollableContainer *buddyViewScrollableContainer () const;
+
+ /**
+ * @returns this view's scrollable container.
+ */
+ kpViewScrollableContainer *scrollableContainer () const;
+
+
+ /**
+ * @returns the horizontal zoom level (100 is unzoomed).
+ */
+ int zoomLevelX (void) const;
+
+ /**
+ * @returns the vertical zoom level (100 is unzoomed).
+ */
+ int zoomLevelY (void) const;
+
+ /**
+ * Sets the horizontal and vertical zoom levels.
+ *
+ * @param hzoom Horizontal zoom level.
+ * @param vzoom Vertical zoom level.
+ *
+ * If reimplementing, you must call this base implementation.
+ */
+ virtual void setZoomLevel (int hzoom, int vzoom);
+
+
+ /**
+ * @returns in views coordinates, where the top-left document() pixel
+ * will be rendered (default: (0,0)).
+ */
+ QPoint origin () const;
+
+ /**
+ * Sets the origin.
+ *
+ * @param origin New origin.
+ *
+ * If reimplementing, you must call this base implementation.
+ */
+ virtual void setOrigin (const QPoint &origin);
+
+
+ /**
+ * @returns whether at this zoom level, the grid can be enabled.
+ * This is based on whether the grid can be sensibly rendered.
+ */
+ bool canShowGrid () const;
+
+ /**
+ * @returns whether the grid is currently shown.
+ */
+ bool isGridShown () const;
+
+ /**
+ * Turns on/off the grid.
+ *
+ * @param yes Whether to enable the grid.
+ */
+ void showGrid (bool yes = true);
+
+
+ /**
+ * @returns whether to draw a rectangle highlighting the area of
+ * buddyView() visible through buddyViewScrollableContainer().
+ */
+ bool isBuddyViewScrollableContainerRectangleShown () const;
+
+ /**
+ * Turns on/off the rectangle highlighting the area of buddyView()
+ * visible through buddyViewScrollableContainer() and redraws.
+ *
+ * @param yes Whether to turn on the rectangle.
+ */
+ void showBuddyViewScrollableContainerRectangle (bool yes = true);
+
+protected:
+ /**
+ * @returns the current rectangle highlighting the area of buddyView()
+ * visible through buddyViewScrollableContainer(), that is being
+ * rendered by this view.
+ */
+ QRect buddyViewScrollableContainerRectangle () const;
+
+protected slots:
+ /**
+ * Updates the buddyViewScrollableContainerRectangle() and redraws
+ * appropriately.
+ *
+ * This is already connected to zoomLevelChanged() and originChanged();
+ * buddyView() and buddyViewScrollableContainer() signals. There is probably no
+ * need to call this function directly.
+ */
+ void updateBuddyViewScrollableContainerRectangle ();
+
+
+public:
+
+ /**
+ * @param viewX Horizontal position in view coordinates.
+ *
+ * @returns viewX transformed to document coordinates, based on the
+ * origin() and zoomLevelX().
+ */
+ double transformViewToDocX (double viewX) const;
+
+ /**
+ * @param viewY Vertical position in view coordinates.
+ *
+ * @returns viewY transformed to document coordinates, based on the
+ * origin() and zoomLevelY().
+ */
+ double transformViewToDocY (double viewY) const;
+
+ /**
+ * @param viewPoint Position in view coordinates.
+ *
+ * @returns viewPoint transformed to document coordinates, based on the
+ * origin(), zoomLevelX() and zoomLevelY().
+ */
+ QPoint transformViewToDoc (const QPoint &viewPoint) const;
+
+ /**
+ * @param viewRect Rectangle in view coordinates.
+ *
+ * @returns viewRect transformed to document coordinates based on the
+ * origin(), zoomLevelX() and zoomLevelY().
+ *
+ * For bounding rectangles, you should use this function instead of
+ * transformViewToDocX(), transformViewToDocY() or
+ * transformViewToDoc(const QPoint &) which act on coordinates only.
+ */
+ QRect transformViewToDoc (const QRect &viewRect) const;
+
+
+ /**
+ * @param docX Horizontal position in document coordinates.
+ *
+ * @returns docX transformed to view coordinates, based on the origin()
+ * and zoomLevelX().
+ */
+ double transformDocToViewX (double docX) const;
+
+ /**
+ * @param docY Vertical position in document coordinates.
+ *
+ * @returns docY transformed to view coordinates, based on the origin()
+ * and zoomLevelY().
+ */
+ double transformDocToViewY (double docY) const;
+
+ /**
+ * @param docPoint Position in document coordinates.
+ *
+ * @returns docPoint transformed to view coordinates, based on the
+ * origin(), zoomLevelX(), zoomLevelY().
+ */
+ QPoint transformDocToView (const QPoint &docPoint) const;
+
+ /**
+ * @param docRect Rectangle in document coordinates.
+ *
+ * @return docRect transformed to view coordinates, based on the
+ * origin(), zoomLevelX() and zoomLevelY().
+ *
+ * For bounding rectangles, you should use this function instead of
+ * transformDocToViewX(), transformDocToViewY() or
+ * transformDocToView(const QPoint &) which act on coordinates only.
+ */
+ QRect transformDocToView (const QRect &docRect) const;
+
+
+ /**
+ * @param viewPoint Position in view coordinates.
+ * @param otherView View whose coordinate system the return value will
+ * be in.
+ *
+ * @returns viewPoint transformed to the coordinate system of
+ * @param otherView based on this and otherView's origin(),
+ * zoomLevelX() and zoomLevelY(). This has less rounding
+ * error than otherView->transformDocToView (transformViewToDoc (viewPoint)).
+ */
+ QPoint transformViewToOtherView (const QPoint &viewPoint,
+ const kpView *otherView);
+
+
+ /**
+ * @returns the approximate view width required to display the entire
+ * document(), based on the zoom level only.
+ */
+ int zoomedDocWidth () const;
+
+ /**
+ * @returns the approximate view height required to display the entire
+ * document(), based on the zoom level only.
+ */
+ int zoomedDocHeight () const;
+
+
+protected:
+ /**
+ * Updates the viewManager() on whether or not the mouse is directly
+ * above this view. Among other things, this ensures the brush cursor
+ * is updated.
+ *
+ * This should be called in event handlers.
+ *
+ * @param yes Whether the mouse is directly above this view.
+ */
+ void setHasMouse (bool yes = true);
+
+
+public:
+ /**
+ * Adds a region (in view coordinates) to the dirty area that is
+ * repainted when the parent @ref kpViewManager is set not to queue
+ * updates.
+ *
+ * @param region Region (in view coordinates) that needs repainting.
+ */
+ void addToQueuedArea (const QRegion &region);
+
+ /**
+ * Convenience function. Same as above.
+ *
+ * Adds a rectangle (in view coordinates) to the dirty area that is
+ * repainted when the parent @ref kpViewManager is set not to queue
+ * updates.
+ *
+ * @param rect Rectangle (in view coordinates) that needs repainting.
+ */
+ void addToQueuedArea (const QRect &rect);
+
+ /**
+ * Removes the dirty region that has been queued for updating.
+ * Does not update the view.
+ */
+ void invalidateQueuedArea ();
+
+ /**
+ * Updates the part of the view described by dirty region and then
+ * calls invalidateQueuedArea(). Does nothing if @ref kpViewManager
+ * is set to queue updates.
+ */
+ void updateQueuedArea ();
+
+ void updateMicroFocusHint (const QRect &microFocusHint);
+
+
+public slots:
+ /**
+ * Call this when the "environment" (e.g. document size) changes. The
+ * environment is defined by the caller and should be based on the type
+ * of view. For instance, an unzoomed thumbnail view would also
+ * include in its environment the contents position of an associated
+ * scrollable container.
+ *
+ * This is never called by the kpView base class.
+ *
+ * Implementors should change whatever state is neccessary for their
+ * type of view. For instance, an unzoomed view would resize itself;
+ * a zoomed thumbnail would change the zoom level.
+ */
+ virtual void adjustToEnvironment () = 0;
+
+
+public:
+ QRect selectionViewRect () const;
+
+ // (if <viewPoint> is KP_INVALID_POINT, it uses QCursor::pos())
+
+ QPoint mouseViewPoint (const QPoint &returnViewPoint = KP_INVALID_POINT) const;
+ QPoint mouseViewPointRelativeToSelection (const QPoint &viewPoint = KP_INVALID_POINT) const;
+ bool mouseOnSelection (const QPoint &viewPoint = KP_INVALID_POINT) const;
+
+ int textSelectionMoveBorderAtomicSize () const;
+ bool mouseOnSelectionToMove (const QPoint &viewPoint = KP_INVALID_POINT) const;
+
+protected:
+ bool selectionLargeEnoughToHaveResizeHandlesIfAtomicSize (int atomicSize) const;
+public:
+ int selectionResizeHandleAtomicSize () const;
+ bool selectionLargeEnoughToHaveResizeHandles () const;
+
+ QRegion selectionResizeHandlesViewRegion (bool forRenderer = false) const;
+
+ enum SelectionResizeType
+ {
+ None = 0,
+ Left = 1,
+ Right = 2,
+ Top = 4,
+ Bottom = 8
+ };
+
+ // Returns a bitwise OR of the SelectionResizeType's
+ int mouseOnSelectionResizeHandle (const QPoint &viewPoint = KP_INVALID_POINT) const;
+
+ bool mouseOnSelectionToSelectText (const QPoint &viewPoint = KP_INVALID_POINT) const;
+
+
+signals:
+ /**
+ * Emitted after all zooming code has been executed.
+ *
+ * @param zoomLevelX New zoomLevelX()
+ * @param zoomLevelY New zoomLevelY()
+ */
+ void zoomLevelChanged (int zoomLevelX, int zoomLevelY);
+
+ /**
+ * Emitted after all resizing code has been executed.
+ *
+ * @param size New view size.
+ */
+ void sizeChanged (const QSize &size);
+
+ /**
+ * Convenience signal - same as above.
+ *
+ * Emitted after all resizing code has been executed.
+ *
+ * @param width New view width.
+ * @param height New view height.
+ */
+ void sizeChanged (int width, int height);
+
+ /**
+ * Emitted after all origin changing code has been executed.
+ *
+ * @param origin The new origin.
+ */
+ void originChanged (const QPoint &origin);
+
+protected:
+ virtual void mouseMoveEvent (QMouseEvent *e);
+ virtual void mousePressEvent (QMouseEvent *e);
+ virtual void mouseReleaseEvent (QMouseEvent *e);
+public:
+ // (needs to be public as it may also get event from
+ // QScrollView::contentsWheelEvent())
+ virtual void wheelEvent (QWheelEvent *e);
+
+protected:
+ virtual void keyPressEvent (QKeyEvent *e);
+ virtual void keyReleaseEvent (QKeyEvent *e);
+
+ virtual void focusInEvent (QFocusEvent *e);
+ virtual void focusOutEvent (QFocusEvent *e);
+
+ virtual void enterEvent (QEvent *e);
+ virtual void leaveEvent (QEvent *e);
+
+ virtual void dragEnterEvent (QDragEnterEvent *);
+ virtual void dragLeaveEvent (QDragLeaveEvent *);
+
+ virtual void imStartEvent (QIMEvent *e);
+ virtual void imComposeEvent (QIMEvent *e);
+ virtual void imEndEvent (QIMEvent *e);
+
+public:
+ virtual void resize (int w, int h);
+protected:
+ virtual void resizeEvent (QResizeEvent *e);
+
+
+protected:
+ QRect paintEventGetDocRect (const QRect &viewRect) const;
+public:
+ /**
+ * Draws an opaque background representing transparency. Currently,
+ * it draws a checkerboard.
+ *
+ * @param painter Painter.
+ * @param viewWidth Total width of the view visible to the user.
+ * @param viewHeight Total height of the view visible to the user.
+ * @param rect Rectangle to paint in relative to the painter. Note
+ * that this function does not clip and may draw slightly
+ * more than the requested rectangle. TODO: why not?
+ * @param isPreview Whether the view is for a preview as opposed to
+ * e.g. editing. If set, this function may render
+ * slightly differently.
+ */
+ static void drawTransparentBackground (QPainter *painter,
+ int viewWidth, int viewHeight,
+ const QRect &rect,
+ bool isPreview = false);
+protected:
+ void paintEventDrawCheckerBoard (QPainter *painter, const QRect &viewRect);
+ void paintEventDrawSelection (QPixmap *destPixmap, const QRect &docRect);
+ bool selectionResizeHandleAtomicSizeCloseToZoomLevel () const;
+ void paintEventDrawSelectionResizeHandles (QPainter *painter, const QRect &viewRect);
+ void paintEventDrawTempPixmap (QPixmap *destPixmap, const QRect &docRect);
+ void paintEventDrawGridLines (QPainter *painter, const QRect &viewRect);
+
+ void paintEventDrawRect (const QRect &viewRect);
+ virtual void paintEvent (QPaintEvent *e);
+
+
+private:
+ struct kpViewPrivate *d;
+};
+
+
+#endif // KP_VIEW_H
diff --git a/kolourpaint/kpviewmanager.cpp b/kolourpaint/kpviewmanager.cpp
new file mode 100644
index 00000000..d649f359
--- /dev/null
+++ b/kolourpaint/kpviewmanager.cpp
@@ -0,0 +1,766 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_VIEW_MANAGER 0
+
+
+#include <kpviewmanager.h>
+
+#include <qapplication.h>
+#include <qtimer.h>
+
+#include <kdebug.h>
+
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kpselection.h>
+#include <kptemppixmap.h>
+#include <kptool.h>
+#include <kpview.h>
+
+
+kpViewManager::kpViewManager (kpMainWindow *mainWindow)
+ : m_textCursorBlinkTimer (0),
+ m_textCursorRow (-1),
+ m_textCursorCol (-1),
+ m_textCursorBlinkState (true),
+ m_mainWindow (mainWindow),
+ m_tempPixmap (0),
+ m_viewUnderCursor (0),
+ m_selectionBorderVisible (false),
+ m_selectionBorderFinished (false)
+{
+ m_queueUpdatesCounter = m_fastUpdatesCounter = 0;
+}
+
+// private
+kpDocument *kpViewManager::document () const
+{
+ return m_mainWindow ? m_mainWindow->document () : 0;
+}
+
+kpViewManager::~kpViewManager ()
+{
+ unregisterAllViews ();
+
+ delete m_tempPixmap; m_tempPixmap = 0;
+}
+
+
+void kpViewManager::registerView (kpView *view)
+{
+#if DEBUG_KP_VIEW_MANAGER && 1
+ kdDebug () << "kpViewManager::registerView (" << view << ")" << endl;
+#endif
+ if (view && m_views.findRef (view) < 0)
+ {
+ #if DEBUG_KP_VIEW_MANAGER && 1
+ kdDebug () << "\tadded view" << endl;
+ #endif
+ view->setCursor (m_cursor);
+ m_views.append (view);
+ }
+ else
+ {
+ #if DEBUG_KP_VIEW_MANAGER && 1
+ kdDebug () << "\tignored register view attempt" << endl;
+ #endif
+ }
+}
+
+void kpViewManager::unregisterView (kpView *view)
+{
+ if (view)
+ {
+ if (view == m_viewUnderCursor)
+ m_viewUnderCursor = 0;
+
+ view->unsetCursor ();
+ m_views.removeRef (view);
+ }
+}
+
+void kpViewManager::unregisterAllViews ()
+{
+ // no autoDelete
+ m_views.clear ();
+}
+
+
+// public
+const kpTempPixmap *kpViewManager::tempPixmap () const
+{
+ return m_tempPixmap;
+}
+
+// public
+void kpViewManager::setTempPixmap (const kpTempPixmap &tempPixmap)
+{
+#if DEBUG_KP_VIEW_MANAGER
+ kdDebug () << "kpViewManager::setTempPixmap(isBrush="
+ << tempPixmap.isBrush ()
+ << ",topLeft=" << tempPixmap.topLeft ()
+ << ",pixmap.rect=" << tempPixmap.pixmap ().rect ()
+ << ")" << endl;
+#endif
+
+ QRect oldRect;
+
+ if (m_tempPixmap)
+ {
+ oldRect = m_tempPixmap->rect ();
+ delete m_tempPixmap;
+ m_tempPixmap = 0;
+ }
+
+ m_tempPixmap = new kpTempPixmap (tempPixmap);
+
+
+ setQueueUpdates ();
+
+ if (oldRect.isValid ())
+ updateViews (oldRect);
+ updateViews (m_tempPixmap->rect ());
+
+ restoreQueueUpdates ();
+}
+
+// public
+void kpViewManager::invalidateTempPixmap ()
+{
+ if (!m_tempPixmap)
+ return;
+
+ QRect oldRect = m_tempPixmap->rect ();
+
+ delete m_tempPixmap;
+ m_tempPixmap = 0;
+
+ updateViews (oldRect);
+}
+
+
+// public
+bool kpViewManager::selectionBorderVisible () const
+{
+ return m_selectionBorderVisible;
+}
+
+// public
+void kpViewManager::setSelectionBorderVisible (bool yes)
+{
+ if (m_selectionBorderVisible == yes)
+ return;
+
+ m_selectionBorderVisible = yes;
+
+ if (document () && document ()->selection ())
+ updateViews (document ()->selection ()->boundingRect ());
+}
+
+
+// public
+bool kpViewManager::selectionBorderFinished () const
+{
+ return m_selectionBorderFinished;
+}
+
+// public
+void kpViewManager::setSelectionBorderFinished (bool yes)
+{
+ if (m_selectionBorderFinished == yes)
+ return;
+
+ m_selectionBorderFinished = yes;
+
+ if (document () && document ()->selection ())
+ updateViews (document ()->selection ()->boundingRect ());
+}
+
+
+bool kpViewManager::textCursorEnabled () const
+{
+ return (bool) m_textCursorBlinkTimer;
+}
+
+void kpViewManager::setTextCursorEnabled (bool yes)
+{
+#if DEBUG_KP_VIEW_MANAGER && 1
+ kdDebug () << "kpViewManager::setTextCursorEnabled(" << yes << ")" << endl;
+#endif
+
+ if (yes == textCursorEnabled ())
+ return;
+
+ delete m_textCursorBlinkTimer;
+ m_textCursorBlinkTimer = 0;
+
+ setFastUpdates ();
+ setQueueUpdates ();
+
+ m_textCursorBlinkState = true;
+
+ if (yes)
+ {
+ m_textCursorBlinkTimer = new QTimer (this);
+ connect (m_textCursorBlinkTimer, SIGNAL (timeout ()),
+ this, SLOT (slotTextCursorBlink ()));
+ slotTextCursorBlink ();
+ }
+ // TODO: What if !yes - shouldn't it clear the cursor?
+
+ restoreQueueUpdates ();
+ restoreFastUpdates ();
+}
+
+
+int kpViewManager::textCursorRow () const
+{
+ bool handledErrors = false;
+ if (m_mainWindow)
+ {
+ kpDocument *doc = m_mainWindow->document ();
+ if (doc)
+ {
+ kpSelection *sel = doc->selection ();
+ if (sel && sel->isText ())
+ {
+ if (m_textCursorRow >= (int) sel->textLines ().size ())
+ {
+ #if DEBUG_KP_VIEW_MANAGER && 1
+ kdDebug () << "kpViewManager::textCursorRow() row="
+ << m_textCursorRow
+ << endl;
+ #endif
+ (const_cast <kpViewManager *> (this))->m_textCursorRow =
+ sel->textLines ().size () - 1;
+ }
+
+ handledErrors = true;
+ }
+ }
+ }
+
+ if (!handledErrors)
+ {
+ #if DEBUG_KP_VIEW_MANAGER && 1
+ kdDebug () << "kpViewManager::textCursorRow() no mw, doc or text sel" << endl;
+ #endif
+ (const_cast <kpViewManager *> (this))->m_textCursorRow = -1;
+ }
+
+ return m_textCursorRow;
+}
+
+int kpViewManager::textCursorCol () const
+{
+ int row = textCursorRow ();
+ if (row < 0)
+ return -1;
+
+ bool handledErrors = false;
+ if (m_mainWindow)
+ {
+ kpDocument *doc = m_mainWindow->document ();
+ if (doc)
+ {
+ kpSelection *sel = doc->selection ();
+ if (sel && sel->isText ())
+ {
+ if (m_textCursorCol > (int) sel->textLines () [row].length ())
+ {
+ #if DEBUG_KP_VIEW_MANAGER && 1
+ kdDebug () << "kpViewManager::textCursorRow() col="
+ << m_textCursorCol
+ << endl;
+ #endif
+ (const_cast <kpViewManager *> (this))->m_textCursorCol =
+ sel->textLines () [row].length ();
+ }
+
+ handledErrors = true;
+ }
+ }
+ }
+
+ if (!handledErrors)
+ {
+ #if DEBUG_KP_VIEW_MANAGER && 1
+ kdDebug () << "kpViewManager::textCursorCol() no mw, doc or text sel" << endl;
+ #endif
+ (const_cast <kpViewManager *> (this))->m_textCursorCol = -1;
+ }
+
+ return m_textCursorCol;
+}
+
+void kpViewManager::setTextCursorPosition (int row, int col, bool isUpdateMicroFocusHint)
+{
+ if (row == m_textCursorRow && col == m_textCursorCol)
+ return;
+
+ setFastUpdates ();
+ setQueueUpdates ();
+
+ m_textCursorBlinkState = false;
+ updateTextCursor ();
+
+ m_textCursorRow = row;
+ m_textCursorCol = col;
+
+ m_textCursorBlinkState = true;
+ updateTextCursor ();
+
+ restoreQueueUpdates ();
+ restoreFastUpdates ();
+
+ if (isUpdateMicroFocusHint)
+ {
+ kpDocument *doc = m_mainWindow->document ();
+ if (!doc)
+ return;
+
+ kpSelection *sel = doc->selection ();
+ if (!sel || !sel->isText ())
+ return;
+
+ if (m_viewUnderCursor)
+ {
+ // TODO: Fix code duplication: kpViewManager::{setTextCursorPosition,updateTextCursor}() & kpView::paintEventDrawSelection()
+ QPoint topLeft = sel->pointForTextRowCol (m_textCursorRow, m_textCursorCol);
+ if (topLeft != KP_INVALID_POINT)
+ {
+ // TODO: I think you need to consider zooming e.g. try editing
+ // text at 800% or with focus set to the thumbnail.
+ // kpSelection/kpDocument works fully in unzoomed
+ // coordinates unlike the view (which is zoomed and can
+ // change size).
+ //
+ // To fix it here, I think you should call
+ // m_viewUnderCursor->transformDocToView(QRect). However,
+ // the rest of the InputMethod support still needs to
+ // audited for this.
+ //
+ // [Bug #27]
+ m_viewUnderCursor->updateMicroFocusHint(QRect (topLeft.x (), topLeft.y (), 1, sel->textStyle ().fontMetrics ().height ()));
+ }
+ }
+ }
+}
+
+
+bool kpViewManager::textCursorBlinkState () const
+{
+ return m_textCursorBlinkState;
+}
+
+void kpViewManager::setTextCursorBlinkState (bool on)
+{
+ if (on == m_textCursorBlinkState)
+ return;
+
+ m_textCursorBlinkState = on;
+
+ updateTextCursor ();
+}
+
+
+// protected
+void kpViewManager::updateTextCursor ()
+{
+#if DEBUG_KP_VIEW_MANAGER && 0
+ kdDebug () << "kpViewManager::updateTextCursor()" << endl;
+#endif
+
+ if (!m_mainWindow)
+ return;
+
+ kpDocument *doc = m_mainWindow->document ();
+ if (!doc)
+ return;
+
+ kpSelection *sel = doc->selection ();
+ if (!sel || !sel->isText ())
+ return;
+
+ // TODO: Fix code duplication: kpViewManager::{setTextCursorPosition,updateTextCursor}() & kpView::paintEventDrawSelection()
+ QPoint topLeft = sel->pointForTextRowCol (m_textCursorRow, m_textCursorCol);
+ if (topLeft != KP_INVALID_POINT)
+ {
+ setFastUpdates ();
+ updateViews (QRect (topLeft.x (), topLeft.y (), 1, sel->textStyle ().fontMetrics ().height ()));
+ restoreFastUpdates ();
+ }
+}
+
+// protected slot
+void kpViewManager::slotTextCursorBlink ()
+{
+#if DEBUG_KP_VIEW_MANAGER && 0
+ kdDebug () << "kpViewManager::slotTextCursorBlink() cursorBlinkState="
+ << m_textCursorBlinkState << endl;
+#endif
+
+ if (m_textCursorBlinkTimer)
+ {
+ m_textCursorBlinkTimer->start (QApplication::cursorFlashTime () / 2,
+ true/*single shot*/);
+ }
+
+ updateTextCursor ();
+ m_textCursorBlinkState = !m_textCursorBlinkState;
+}
+
+
+void kpViewManager::setCursor (const QCursor &cursor)
+{
+ for (QPtrList <kpView>::const_iterator it = m_views.begin ();
+ it != m_views.end ();
+ it++)
+ {
+ (*it)->setCursor (cursor);
+ }
+
+ m_cursor = cursor;
+}
+
+void kpViewManager::unsetCursor ()
+{
+ for (QPtrList <kpView>::const_iterator it = m_views.begin ();
+ it != m_views.end ();
+ it++)
+ {
+ (*it)->unsetCursor ();
+ }
+
+ m_cursor = QCursor ();
+}
+
+
+kpView *kpViewManager::viewUnderCursor (bool usingQt) const
+{
+ if (!usingQt)
+ {
+ kpViewManager *nonConstThis = const_cast <kpViewManager *> (this);
+
+ if (m_viewUnderCursor && nonConstThis->m_views.findRef (m_viewUnderCursor) < 0)
+ {
+ kdError () << "kpViewManager::viewUnderCursor(): invalid view" << endl;
+ nonConstThis->m_viewUnderCursor = 0;
+ }
+
+
+ return m_viewUnderCursor;
+ }
+ else
+ {
+ for (QPtrList <kpView>::const_iterator it = m_views.begin ();
+ it != m_views.end ();
+ it++)
+ {
+ if ((*it)->hasMouse ())
+ return (*it);
+ }
+
+ return 0;
+ }
+}
+
+void kpViewManager::setViewUnderCursor (kpView *view)
+{
+#if DEBUG_KP_VIEW_MANAGER && 1
+ kdDebug () << "kpViewManager::setViewUnderCursor ("
+ << (view ? view->name () : "(none)") << ")"
+ << " old=" << (m_viewUnderCursor ? m_viewUnderCursor->name () : "(none)")
+ << endl;
+#endif
+ if (view == m_viewUnderCursor)
+ return;
+
+ m_viewUnderCursor = view;
+
+ if (!m_viewUnderCursor)
+ {
+ // Hide the brush if the mouse cursor just left the view
+ if (m_tempPixmap && m_tempPixmap->isBrush ())
+ {
+ #if DEBUG_KP_VIEW_MANAGER && 1
+ kdDebug () << "\thiding brush pixmap since cursor left view" << endl;
+ #endif
+ updateViews (m_tempPixmap->rect ());
+ }
+ }
+ else
+ {
+ if (m_mainWindow && m_mainWindow->tool ())
+ {
+ #if DEBUG_KP_VIEW_MANAGER && 1
+ kdDebug () << "\tnotify tool that something changed below cursor" << endl;
+ #endif
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+ }
+}
+
+
+// public
+kpView *kpViewManager::activeView () const
+{
+ for (QPtrList <kpView>::const_iterator it = m_views.begin ();
+ it != m_views.end ();
+ it++)
+ {
+ if ((*it)->isActiveWindow ())
+ return (*it);
+ }
+
+ return 0;
+}
+
+
+// public
+bool kpViewManager::queueUpdates () const
+{
+ return (m_queueUpdatesCounter > 0);
+}
+
+// public
+void kpViewManager::setQueueUpdates ()
+{
+ m_queueUpdatesCounter++;
+#if DEBUG_KP_VIEW_MANAGER && 1
+ kdDebug () << "kpViewManager::setQueueUpdates() counter="
+ << m_queueUpdatesCounter << endl;
+#endif
+}
+
+// public
+void kpViewManager::restoreQueueUpdates ()
+{
+ m_queueUpdatesCounter--;
+#if DEBUG_KP_VIEW_MANAGER && 1
+ kdDebug () << "kpViewManager::restoreQueueUpdates() counter="
+ << m_queueUpdatesCounter << endl;
+#endif
+ if (m_queueUpdatesCounter < 0)
+ {
+ kdError () << "kpViewManager::restoreQueueUpdates() counter="
+ << m_queueUpdatesCounter;
+ }
+
+ if (m_queueUpdatesCounter <= 0)
+ {
+ for (QPtrList <kpView>::const_iterator it = m_views.begin ();
+ it != m_views.end ();
+ it++)
+ {
+ (*it)->updateQueuedArea ();
+ }
+ }
+}
+
+
+// public
+bool kpViewManager::fastUpdates () const
+{
+ return (m_fastUpdatesCounter > 0);
+}
+
+// public
+void kpViewManager::setFastUpdates ()
+{
+ m_fastUpdatesCounter++;
+#if DEBUG_KP_VIEW_MANAGER && 0
+ kdDebug () << "kpViewManager::setFastUpdates() counter="
+ << m_fastUpdatesCounter << endl;
+#endif
+}
+
+// public
+void kpViewManager::restoreFastUpdates ()
+{
+ m_fastUpdatesCounter--;
+#if DEBUG_KP_VIEW_MANAGER && 0
+ kdDebug () << "kpViewManager::restoreFastUpdates() counter="
+ << m_fastUpdatesCounter << endl;
+#endif
+ if (m_fastUpdatesCounter < 0)
+ {
+ kdError () << "kpViewManager::restoreFastUpdates() counter="
+ << m_fastUpdatesCounter;
+ }
+}
+
+
+void kpViewManager::updateView (kpView *v)
+{
+ updateView (v, QRect (0, 0, v->width (), v->height ()));
+}
+
+void kpViewManager::updateView (kpView *v, const QRect &viewRect)
+{
+ if (!queueUpdates ())
+ {
+ if (fastUpdates ())
+ v->repaint (viewRect, false/*no erase*/);
+ else
+ v->update (viewRect);
+ }
+ else
+ v->addToQueuedArea (viewRect);
+}
+
+void kpViewManager::updateView (kpView *v, int x, int y, int w, int h)
+{
+ updateView (v, QRect (x, y, w, h));
+}
+
+void kpViewManager::updateView (kpView *v, const QRegion &viewRegion)
+{
+ if (!queueUpdates ())
+ {
+ if (fastUpdates ())
+ v->repaint (viewRegion, false/*no erase*/);
+ else
+ v->update (viewRegion.boundingRect ());
+ }
+ else
+ v->addToQueuedArea (viewRegion);
+}
+
+void kpViewManager::updateViewRectangleEdges (kpView *v, const QRect &viewRect)
+{
+ if (viewRect.height () <= 0 || viewRect.width () <= 0)
+ return;
+
+ // Top line
+ updateView (v, QRect (viewRect.x (), viewRect.y (),
+ viewRect.width (), 1));
+
+ if (viewRect.height () >= 2)
+ {
+ // Bottom line
+ updateView (v, QRect (viewRect.x (), viewRect.bottom (),
+ viewRect.width (), 1));
+
+ if (viewRect.height () > 2)
+ {
+ // Left line
+ updateView (v, QRect (viewRect.x (), viewRect.y () + 1,
+ 1, viewRect.height () - 2));
+
+ if (viewRect.width () >= 2)
+ {
+ // Right line
+ updateView (v, QRect (viewRect.right (), viewRect.y () + 1,
+ 1, viewRect.height () - 2));
+ }
+ }
+ }
+}
+
+
+void kpViewManager::updateViews ()
+{
+ kpDocument *doc = document ();
+ if (doc)
+ updateViews (QRect (0, 0, doc->width (), doc->height ()));
+}
+
+void kpViewManager::updateViews (const QRect &docRect)
+{
+#if DEBUG_KP_VIEW_MANAGER && 0
+ kdDebug () << "kpViewManager::updateViews (" << docRect << ")" << endl;
+#endif
+
+ for (QPtrList <kpView>::const_iterator it = m_views.begin ();
+ it != m_views.end ();
+ it++)
+ {
+ kpView *view = *it;
+
+ #if DEBUG_KP_VIEW_MANAGER && 0
+ kdDebug () << "\tupdating view " << view->name () << endl;
+ #endif
+ if (view->zoomLevelX () % 100 == 0 && view->zoomLevelY () % 100 == 0)
+ {
+ #if DEBUG_KP_VIEW_MANAGER && 0
+ kdDebug () << "\t\tviewRect=" << view->transformDocToView (docRect) << endl;
+ #endif
+ updateView (view, view->transformDocToView (docRect));
+ }
+ else
+ {
+ QRect viewRect = view->transformDocToView (docRect);
+
+ int diff = qRound (double (QMAX (view->zoomLevelX (), view->zoomLevelY ())) / 100.0) + 1;
+
+ QRect newRect = QRect (viewRect.x () - diff,
+ viewRect.y () - diff,
+ viewRect.width () + 2 * diff,
+ viewRect.height () + 2 * diff)
+ .intersect (QRect (0, 0, view->width (), view->height ()));
+
+ #if DEBUG_KP_VIEW_MANAGER && 0
+ kdDebug () << "\t\tviewRect (+compensate)=" << newRect << endl;
+ #endif
+ updateView (view, newRect);
+ }
+ }
+}
+
+void kpViewManager::updateViews (int x, int y, int w, int h)
+{
+ updateViews (QRect (x, y, w, h));
+}
+
+
+void kpViewManager::adjustViewsToEnvironment ()
+{
+#if DEBUG_KP_VIEW_MANAGER && 1
+ kdDebug () << "kpViewManager::adjustViewsToEnvironment()"
+ << " numViews=" << m_views.count ()
+ << endl;
+#endif
+ for (QPtrList <kpView>::const_iterator it = m_views.begin ();
+ it != m_views.end ();
+ it++)
+ {
+ kpView *view = *it;
+
+ #if DEBUG_KP_VIEW_MANAGER && 1
+ kdDebug () << "\tview: " << view->name ()
+ << endl;
+ #endif
+ view->adjustToEnvironment ();
+ }
+}
+
+#include <kpviewmanager.moc>
+
diff --git a/kolourpaint/kpviewmanager.h b/kolourpaint/kpviewmanager.h
new file mode 100644
index 00000000..c6ea1ef0
--- /dev/null
+++ b/kolourpaint/kpviewmanager.h
@@ -0,0 +1,220 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kpviewmanager_h__
+#define __kpviewmanager_h__
+
+#include <qcursor.h>
+#include <qobject.h>
+#include <qptrlist.h>
+#include <qrect.h>
+
+
+class QPixmap;
+class QRect;
+class QTimer;
+
+class kpDocument;
+class kpView;
+class kpMainWindow;
+class kpTempPixmap;
+
+class kpViewManager : public QObject
+{
+Q_OBJECT
+
+public:
+ kpViewManager (kpMainWindow *mainWindow);
+ ~kpViewManager ();
+
+
+ //
+ // Registering views
+ //
+
+ void registerView (kpView *view);
+ void unregisterView (kpView *view);
+ void unregisterAllViews ();
+
+
+ //
+ // Temp Pixmap
+ //
+
+ const kpTempPixmap *tempPixmap () const;
+ void setTempPixmap (const kpTempPixmap &tempPixmap);
+ void invalidateTempPixmap ();
+
+
+ //
+ // Selections
+ //
+
+ bool selectionBorderVisible () const;
+ void setSelectionBorderVisible (bool yes = true);
+
+ bool selectionBorderFinished () const;
+ void setSelectionBorderFinished (bool yes = true);
+
+
+ //
+ // Text Cursor
+ //
+
+ bool textCursorEnabled () const;
+ void setTextCursorEnabled (bool yes = true);
+
+ int textCursorRow () const;
+ int textCursorCol () const;
+ void setTextCursorPosition (int row, int col, bool isUpdateMicroFocusHint = false);
+
+ bool textCursorBlinkState () const;
+ void setTextCursorBlinkState (bool on = true);
+
+protected:
+ void updateTextCursor ();
+
+ QTimer *m_textCursorBlinkTimer;
+ int m_textCursorRow, m_textCursorCol;
+ bool m_textCursorBlinkState;
+
+protected slots:
+ void slotTextCursorBlink ();
+
+public:
+
+ //
+ // Cursors
+ //
+
+ void setCursor (const QCursor &cursor);
+ void unsetCursor ();
+
+
+ //
+ // View
+ //
+
+ kpView *viewUnderCursor (bool usingQt = false) const;
+
+ //
+ // QWidget::hasMouse() is unreliable:
+ //
+ // "bool QWidget::hasMouse () const
+ // ... See the "underMouse" property for details.
+ // .
+ // .
+ // .
+ // bool underMouse
+ // ... This value is not updated properly during drag and drop operations."
+ //
+ // i.e. it's possible that hasMouse() returns false in a mousePressEvent()!
+ //
+ // This hack needs to be called from kpView so that viewUnderCursor() works
+ // as a reasonable replacement (although there is at least one case where
+ // it still won't work - just after a fake drag onto the view).
+ //
+ void setViewUnderCursor (kpView *view);
+
+
+ // Returns a pointer to the view that has keyboard focus or else, 0
+ // TODO: rename to "anActiveView()" or "aViewIsActive()" as more than
+ // 1 view can be active at the same time?
+ kpView *activeView () const;
+
+
+ // Specifies whether KolourPaint will queue _all_ paint events
+ // (generated by you or the window system), until the
+ // corresponding call to restoreQueueUpdates(). Use this
+ // before multiple, big, non-interactive changes to the
+ // document to eliminate virtually all flicker.
+ //
+ // This is better than QWidget::setUpdatesEnabled() because
+ // restoreQueueUpdates() automatically restores only the regions
+ // of the views that need to be repainted, per view.
+ bool queueUpdates () const;
+ void setQueueUpdates ();
+ void restoreQueueUpdates ();
+
+ // Controls behaviour of updateViews():
+ //
+ // Slow: Let Qt buffer paint events via QWidget::update().
+ // Results in less flicker. Paint events are probably merged
+ // so long-term efficiency is increased at the expense of
+ // reduced responsiveness (default).
+ // Fast: Force Qt to redraw immediately. No paint events
+ // are merged so there is great potential for flicker,
+ // if used inappropriately. Use this when the redraw
+ // area is small and KolourPaint's responsiveness is
+ // critical. Continual use of this mode can result in
+ // unnecessary redraws and incredibly slugish performance.
+ bool fastUpdates () const;
+ void setFastUpdates ();
+ void restoreFastUpdates ();
+
+private:
+ int m_queueUpdatesCounter, m_fastUpdatesCounter;
+
+public slots:
+ // updating views
+ void updateView (kpView *v);
+ void updateView (kpView *v, const QRect &viewRect);
+ void updateView (kpView *v, int x, int y, int w, int h);
+ void updateView (kpView *v, const QRegion &viewRegion);
+ void updateViewRectangleEdges (kpView *v, const QRect &viewRect);
+
+ void updateViews ();
+ void updateViews (const QRect &docRect);
+ void updateViews (int x, int y, int w, int h);
+
+ void adjustViewsToEnvironment ();
+
+private:
+ // don't use
+ kpViewManager (const kpViewManager &);
+ bool operator= (const kpViewManager &);
+
+ kpDocument *document () const;
+
+ kpMainWindow *m_mainWindow;
+ QPtrList <kpView> m_views;
+ QCursor m_cursor;
+
+ kpTempPixmap *m_tempPixmap;
+ kpView *m_viewUnderCursor;
+
+ bool m_selectionBorderVisible;
+ bool m_selectionBorderFinished;
+
+ // There is no need to maintain binary compatibility at this stage.
+ // The d-pointer is just so that you can experiment without recompiling
+ // the kitchen sink.
+ class kpViewManagerPrivate *d;
+};
+
+#endif // __kpviewmanager_h__
diff --git a/kolourpaint/kpviewscrollablecontainer.cpp b/kolourpaint/kpviewscrollablecontainer.cpp
new file mode 100644
index 00000000..637f71b7
--- /dev/null
+++ b/kolourpaint/kpviewscrollablecontainer.cpp
@@ -0,0 +1,1390 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_VIEW_SCROLLABLE_CONTAINER 0
+
+#include <kpviewscrollablecontainer.h>
+
+#include <qcursor.h>
+#include <qpainter.h>
+#include <qpen.h>
+#include <qpixmap.h>
+#include <qtimer.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpdefs.h>
+#include <kppixmapfx.h>
+#include <kpview.h>
+#include <kpwidgetmapper.h>
+
+
+// (Pulled from out of Thurston's hat)
+static const int DragScrollLeftTopMargin = 0;
+static const int DragScrollRightBottomMargin = 16; // scrollbarish
+static const int DragScrollInterval = 1000 / 10;
+static const int DragScrollInitialInterval = DragScrollInterval * 2;
+static const int DragScrollNumPixels = 5;
+static const int DragDistanceFromRectMaxFor1stMultiplier = 50;
+static const int DragDistanceFromRectMaxFor2ndMultiplier = 100;
+
+static const int GripSize = 7;
+static const int GripHandleSize = 7;
+
+
+kpGrip::kpGrip (GripType type,
+ QWidget *parent, const char *name)
+ : QWidget (parent, name),
+ m_type (type),
+ m_startPoint (KP_INVALID_POINT),
+ m_currentPoint (KP_INVALID_POINT),
+ m_shouldReleaseMouseButtons (false)
+{
+ setCursor (cursorForType (m_type));
+
+ setMouseTracking (true); // mouseMoveEvent's even when no mousebtn down
+
+ updatePixmap ();
+}
+
+kpGrip::~kpGrip ()
+{
+}
+
+
+// public
+kpGrip::GripType kpGrip::type () const
+{
+ return m_type;
+}
+
+
+// public static
+const QCursor &kpGrip::cursorForType (GripType type)
+{
+ switch (type)
+ {
+ case Bottom:
+ return Qt::sizeVerCursor;
+ break; // one day you'll forget
+
+ case Right:
+ return Qt::sizeHorCursor;
+ break; // one day you'll forget
+
+ case BottomRight:
+ return Qt::sizeFDiagCursor;
+ break; // one day you'll forget
+ }
+
+ return Qt::arrowCursor;
+}
+
+
+// public
+QRect kpGrip::hotRect (bool toGlobal) const
+{
+ QRect ret;
+
+ switch (m_type)
+ {
+ case Bottom:
+ {
+ const int handleX = (width () - GripHandleSize) / 2;
+ ret = QRect (handleX, 0,
+ GripHandleSize, height ());
+ break;
+ }
+ case Right:
+ {
+ const int handleY = (height () - GripHandleSize) / 2;
+ ret = QRect (0, handleY,
+ width (), GripHandleSize);
+ break;
+ }
+ case BottomRight:
+ // pixmap all opaque
+ ret = rect ();
+ break;
+
+ default:
+ return QRect ();
+ }
+
+ return (toGlobal ? QRect (mapToGlobal (ret.topLeft ()),
+ mapToGlobal (ret.bottomRight ()))
+ : ret);
+}
+
+
+// public
+bool kpGrip::isDrawing () const
+{
+ return (m_startPoint != KP_INVALID_POINT);
+}
+
+
+// public
+QString kpGrip::haventBegunDrawUserMessage () const
+{
+ return i18n ("Left drag the handle to resize the image.");
+}
+
+
+// public
+QString kpGrip::userMessage () const
+{
+ return m_userMessage;
+}
+
+// public
+void kpGrip::setUserMessage (const QString &message)
+{
+ // Don't do NOP checking here since another grip might have changed
+ // the message so an apparent NOP for this grip is not a NOP in the
+ // global sense (kpViewScrollableContainer::slotGripStatusMessageChanged()).
+
+ m_userMessage = message;
+ emit statusMessageChanged (message);
+}
+
+
+// protected
+void kpGrip::updatePixmap ()
+{
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "kpGrip::updatePixmap() rect=" << rect () << endl;
+#endif
+ if (width () <= 0 || height () <= 0)
+ return;
+
+ QPixmap pixmap (width (), height ());
+ pixmap.fill (colorGroup ().highlight ());
+ kpPixmapFX::ensureTransparentAt (&pixmap, pixmap.rect ());
+ const QRect hr = hotRect ();
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "\thotRect=" << hr << endl;
+#endif
+ if (hr.isValid ())
+ kpPixmapFX::ensureOpaqueAt (&pixmap, hr);
+
+ setBackgroundPixmap (pixmap);
+ if (pixmap.mask ())
+ setMask (*pixmap.mask ());
+}
+
+
+// protected
+void kpGrip::cancel ()
+{
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "kpGrip::cancel()" << endl;
+#endif
+ if (m_currentPoint == KP_INVALID_POINT)
+ return;
+
+ m_startPoint = KP_INVALID_POINT;
+ m_currentPoint = KP_INVALID_POINT;
+
+ setUserMessage (i18n ("Resize Image: Let go of all the mouse buttons."));
+ setCursor (Qt::arrowCursor);
+ m_shouldReleaseMouseButtons = true;
+
+ releaseKeyboard ();
+ emit cancelledDraw ();
+}
+
+
+// protected virtual [base QWidget]
+void kpGrip::keyReleaseEvent (QKeyEvent *e)
+{
+ if (m_startPoint != KP_INVALID_POINT &&
+ e->key () == Qt::Key_Escape)
+ {
+ cancel ();
+ }
+}
+
+// protected virtual [base QWidget]
+void kpGrip::mousePressEvent (QMouseEvent *e)
+{
+ if (m_startPoint == KP_INVALID_POINT &&
+ (e->stateAfter () & Qt::MouseButtonMask) == Qt::LeftButton)
+ {
+ m_startPoint = e->pos ();
+ m_currentPoint = e->pos ();
+ emit beganDraw ();
+ grabKeyboard ();
+
+ setUserMessage (i18n ("Resize Image: Right click to cancel."));
+ setCursor (cursorForType (m_type));
+ }
+ else
+ {
+ if (m_startPoint != KP_INVALID_POINT)
+ cancel ();
+ }
+}
+
+// public
+QPoint kpGrip::viewDeltaPoint () const
+{
+ if (m_startPoint == KP_INVALID_POINT)
+ return KP_INVALID_POINT;
+
+ const QPoint point = mapFromGlobal (QCursor::pos ());
+
+ // TODO: this is getting out of sync with m_currentPoint
+
+ return QPoint (((m_type & Right) ? point.x () - m_startPoint.x () : 0),
+ ((m_type & Bottom) ? point.y () - m_startPoint.y () : 0));
+
+}
+
+// public
+void kpGrip::mouseMovedTo (const QPoint &point, bool dueToDragScroll)
+{
+ if (m_startPoint == KP_INVALID_POINT)
+ return;
+
+ m_currentPoint = point;
+
+ emit continuedDraw (((m_type & Right) ? point.x () - m_startPoint.x () : 0),
+ ((m_type & Bottom) ? point.y () - m_startPoint.y () : 0),
+ dueToDragScroll);
+}
+
+// protected virtual [base QWidget]
+void kpGrip::mouseMoveEvent (QMouseEvent *e)
+{
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "kpGrip::mouseMoveEvent() m_startPoint=" << m_startPoint
+ << " stateAfter=" << e->stateAfter ()
+ << endl;
+#endif
+
+ if (m_startPoint == KP_INVALID_POINT)
+ {
+ if ((e->stateAfter () & Qt::MouseButtonMask) == 0)
+ setUserMessage (haventBegunDrawUserMessage ());
+ return;
+ }
+
+ mouseMovedTo (e->pos (), false/*not due to drag scroll*/);
+}
+
+// protected virtual [base QWidget]
+void kpGrip::mouseReleaseEvent (QMouseEvent *e)
+{
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "kpGrip::mouseReleaseEvent() m_startPoint=" << m_startPoint
+ << " stateAfter=" << e->stateAfter ()
+ << endl;
+#endif
+
+ if (m_startPoint != KP_INVALID_POINT)
+ {
+ const int dx = m_currentPoint.x () - m_startPoint.x (),
+ dy = m_currentPoint.y () - m_startPoint.y ();
+
+ m_currentPoint = KP_INVALID_POINT;
+ m_startPoint = KP_INVALID_POINT;
+
+ releaseKeyboard ();
+ emit endedDraw ((m_type & Right) ? dx : 0,
+ (m_type & Bottom) ? dy : 0);
+ }
+
+ if ((e->stateAfter () & Qt::MouseButtonMask) == 0)
+ {
+ m_shouldReleaseMouseButtons = false;
+ setUserMessage (QString::null);
+ setCursor (cursorForType (m_type));
+
+ releaseKeyboard ();
+ emit releasedAllButtons ();
+ }
+}
+
+
+// protected virtual [base QWidget]
+void kpGrip::resizeEvent (QResizeEvent *)
+{
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "kpGrip::resizeEvent()" << endl;
+#endif
+ updatePixmap ();
+}
+
+
+// protected virtual [base QWidget]
+void kpGrip::enterEvent (QEvent * /*e*/)
+{
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "kpGrip::enterEvent()"
+ << " m_startPoint=" << m_startPoint
+ << " shouldReleaseMouseButtons="
+ << m_shouldReleaseMouseButtons << endl;
+#endif
+
+ if (m_startPoint == KP_INVALID_POINT &&
+ !m_shouldReleaseMouseButtons)
+ {
+ #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "\tsending message" << endl;
+ #endif
+ setUserMessage (haventBegunDrawUserMessage ());
+ }
+}
+
+// protected virtual [base QWidget]
+void kpGrip::leaveEvent (QEvent * /*e*/)
+{
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "kpGrip::leaveEvent()"
+ << " m_startPoint=" << m_startPoint
+ << " shouldReleaseMouseButtons="
+ << m_shouldReleaseMouseButtons << endl;
+#endif
+ if (m_startPoint == KP_INVALID_POINT &&
+ !m_shouldReleaseMouseButtons)
+ {
+ setUserMessage (QString::null);
+ }
+}
+
+
+// protected virtual [base QWidget]
+void kpGrip::paintEvent (QPaintEvent *e)
+{
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 0
+ kdDebug () << "kpGrip::paintEvent(" << e->rect () << ")" << endl;
+#endif
+ QWidget::paintEvent (e);
+}
+
+
+// TODO: Are we checking for m_view == 0 often enough?
+kpViewScrollableContainer::kpViewScrollableContainer (kpMainWindow *parent,
+ const char *name)
+ : QScrollView ((QWidget *) parent, name, Qt::WStaticContents | Qt::WNoAutoErase),
+ m_mainWindow (parent),
+ m_contentsXSoon (-1), m_contentsYSoon (-1),
+ m_view (0),
+ m_bottomGrip (new kpGrip (kpGrip::Bottom, viewport (), "Bottom Grip")),
+ m_rightGrip (new kpGrip (kpGrip::Right, viewport (), "Right Grip")),
+ m_bottomRightGrip (new kpGrip (kpGrip::BottomRight, viewport (), "BottomRight Grip")),
+ m_docResizingGrip (0),
+ m_dragScrollTimer (new QTimer (this)),
+ m_zoomLevel (100),
+ m_scrollTimerRunOnce (false),
+ m_resizeRoundedLastViewX (-1), m_resizeRoundedLastViewY (-1),
+ m_resizeRoundedLastViewDX (0), m_resizeRoundedLastViewDY (0),
+ m_haveMovedFromOriginalDocSize (false)
+
+{
+ m_bottomGrip->setFixedHeight (GripSize);
+ m_bottomGrip->hide ();
+ addChild (m_bottomGrip);
+ connectGripSignals (m_bottomGrip);
+
+ m_rightGrip->setFixedWidth (GripSize);
+ m_rightGrip->hide ();
+ addChild (m_rightGrip);
+ connectGripSignals (m_rightGrip);
+
+ m_bottomRightGrip->setFixedSize (GripSize, GripSize);
+ m_bottomRightGrip->hide ();
+ addChild (m_bottomRightGrip);
+ connectGripSignals (m_bottomRightGrip);
+
+
+ connect (this, SIGNAL (contentsMoving (int, int)),
+ this, SLOT (slotContentsMoving (int, int)));
+
+ connect (m_dragScrollTimer, SIGNAL (timeout ()),
+ this, SLOT (slotDragScroll ()));
+}
+
+kpViewScrollableContainer::~kpViewScrollableContainer ()
+{
+}
+
+
+// public
+int kpViewScrollableContainer::contentsXSoon ()
+{
+ if (m_contentsXSoon < 0)
+ return contentsX ();
+ else
+ return m_contentsXSoon;
+}
+
+// public
+int kpViewScrollableContainer::contentsYSoon ()
+{
+ if (m_contentsYSoon < 0)
+ return contentsY ();
+ else
+ return m_contentsYSoon;
+}
+
+
+// protected
+void kpViewScrollableContainer::connectGripSignals (kpGrip *grip)
+{
+ connect (grip, SIGNAL (beganDraw ()),
+ this, SLOT (slotGripBeganDraw ()));
+ connect (grip, SIGNAL (continuedDraw (int, int, bool)),
+ this, SLOT (slotGripContinuedDraw (int, int, bool)));
+ connect (grip, SIGNAL (cancelledDraw ()),
+ this, SLOT (slotGripCancelledDraw ()));
+ connect (grip, SIGNAL (endedDraw (int, int)),
+ this, SLOT (slotGripEndedDraw (int, int)));
+
+ connect (grip, SIGNAL (statusMessageChanged (const QString &)),
+ this, SLOT (slotGripStatusMessageChanged (const QString &)));
+
+ connect (grip, SIGNAL (releasedAllButtons ()),
+ this, SLOT (recalculateStatusMessage ()));
+}
+
+
+// public
+QSize kpViewScrollableContainer::newDocSize () const
+{
+ return newDocSize (m_resizeRoundedLastViewDX,
+ m_resizeRoundedLastViewDY);
+}
+
+// public
+bool kpViewScrollableContainer::haveMovedFromOriginalDocSize () const
+{
+ return m_haveMovedFromOriginalDocSize;
+}
+
+// public
+QString kpViewScrollableContainer::statusMessage () const
+{
+ return m_gripStatusMessage;
+}
+
+// public
+void kpViewScrollableContainer::clearStatusMessage ()
+{
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 1
+ kdDebug () << "kpViewScrollableContainer::clearStatusMessage()" << endl;
+#endif
+ m_bottomRightGrip->setUserMessage (QString::null);
+ m_bottomGrip->setUserMessage (QString::null);
+ m_rightGrip->setUserMessage (QString::null);
+}
+
+
+// protected
+QSize kpViewScrollableContainer::newDocSize (int viewDX, int viewDY) const
+{
+ if (!m_view)
+ return QSize ();
+
+ if (!docResizingGrip ())
+ return QSize ();
+
+ const int docX = (int) m_view->transformViewToDocX (m_view->width () + viewDX);
+ const int docY = (int) m_view->transformViewToDocY (m_view->height () + viewDY);
+
+ return QSize (QMAX (1, docX), QMAX (1, docY));
+}
+
+
+// protected
+void kpViewScrollableContainer::calculateDocResizingGrip ()
+{
+ if (m_bottomRightGrip->isDrawing ())
+ m_docResizingGrip = m_bottomRightGrip;
+ else if (m_bottomGrip->isDrawing ())
+ m_docResizingGrip = m_bottomGrip;
+ else if (m_rightGrip->isDrawing ())
+ m_docResizingGrip = m_rightGrip;
+ else
+ m_docResizingGrip = 0;
+}
+
+// protected
+kpGrip *kpViewScrollableContainer::docResizingGrip () const
+{
+ return m_docResizingGrip;
+}
+
+
+// protected
+int kpViewScrollableContainer::bottomResizeLineWidth () const
+{
+ if (!docResizingGrip ())
+ return -1;
+
+ if (!m_view)
+ return -1;
+
+ if (docResizingGrip ()->type () & kpGrip::Bottom)
+ return QMAX (m_view->zoomLevelY () / 100, 1);
+ else
+ return 1;
+}
+
+// protected
+int kpViewScrollableContainer::rightResizeLineWidth () const
+{
+ if (!docResizingGrip ())
+ return -1;
+
+ if (!m_view)
+ return -1;
+
+ if (docResizingGrip ()->type () & kpGrip::Right)
+ return QMAX (m_view->zoomLevelX () / 100, 1);
+ else
+ return 1;
+}
+
+
+// protected
+QRect kpViewScrollableContainer::bottomResizeLineRect () const
+{
+ if (m_resizeRoundedLastViewX < 0 || m_resizeRoundedLastViewY < 0)
+ return QRect ();
+
+ return QRect (QPoint (0,
+ m_resizeRoundedLastViewY),
+ QPoint (m_resizeRoundedLastViewX - 1,
+ m_resizeRoundedLastViewY + bottomResizeLineWidth () - 1));
+}
+
+// protected
+QRect kpViewScrollableContainer::rightResizeLineRect () const
+{
+ if (m_resizeRoundedLastViewX < 0 || m_resizeRoundedLastViewY < 0)
+ return QRect ();
+
+ return QRect (QPoint (m_resizeRoundedLastViewX,
+ 0),
+ QPoint (m_resizeRoundedLastViewX + rightResizeLineWidth () - 1,
+ m_resizeRoundedLastViewY - 1));
+}
+
+// protected
+QRect kpViewScrollableContainer::bottomRightResizeLineRect () const
+{
+ if (m_resizeRoundedLastViewX < 0 || m_resizeRoundedLastViewY < 0)
+ return QRect ();
+
+ return QRect (QPoint (m_resizeRoundedLastViewX,
+ m_resizeRoundedLastViewY),
+ QPoint (m_resizeRoundedLastViewX + rightResizeLineWidth () - 1,
+ m_resizeRoundedLastViewY + bottomResizeLineWidth () - 1));
+}
+
+
+// TODO: are these 2 correct? Remember that viewport()->x() == 1, viewport()->y() == 1
+
+// protected
+QPoint kpViewScrollableContainer::mapViewToViewport (const QPoint &viewPoint)
+{
+ return viewPoint - QPoint (contentsX (), contentsY ());
+}
+
+// protected
+QRect kpViewScrollableContainer::mapViewToViewport (const QRect &viewRect)
+{
+ if (!viewRect.isValid ())
+ return QRect ();
+
+ QRect ret = viewRect;
+ ret.moveBy (-contentsX (), -contentsY ());
+ return ret;
+}
+
+
+// protected
+QRect kpViewScrollableContainer::mapViewportToGlobal (const QRect &viewportRect)
+{
+ return kpWidgetMapper::toGlobal (viewport (), viewportRect);
+}
+
+// protected
+QRect kpViewScrollableContainer::mapViewToGlobal (const QRect &viewRect)
+{
+ return mapViewportToGlobal (mapViewToViewport (viewRect));
+}
+
+
+// protected
+void kpViewScrollableContainer::repaintWidgetAtResizeLineViewRect (
+ QWidget *widget, const QRect &resizeLineViewRect)
+{
+ const QRect resizeLineGlobalRect = mapViewToGlobal (resizeLineViewRect);
+ const QRect widgetGlobalRect = kpWidgetMapper::toGlobal (widget,
+ widget->rect ());
+
+ const QRect redrawGlobalRect =
+ resizeLineGlobalRect.intersect (widgetGlobalRect);
+
+ const QRect redrawWidgetRect =
+ kpWidgetMapper::fromGlobal (widget, redrawGlobalRect);
+
+
+ if (redrawWidgetRect.isValid ())
+ {
+ // TODO: should be "!widget->testWFlags (Qt::WRepaintNoErase)"
+ // but for some reason, doesn't work for viewport().
+ const bool erase = !dynamic_cast <kpView *> (widget);
+ widget->repaint (redrawWidgetRect, erase);
+ }
+}
+
+// protected
+void kpViewScrollableContainer::repaintWidgetAtResizeLines (QWidget *widget)
+{
+ repaintWidgetAtResizeLineViewRect (widget, rightResizeLineRect ());
+ repaintWidgetAtResizeLineViewRect (widget, bottomResizeLineRect ());
+ repaintWidgetAtResizeLineViewRect (widget, bottomRightResizeLineRect ());
+}
+
+// protected
+void kpViewScrollableContainer::eraseResizeLines ()
+{
+ if (m_resizeRoundedLastViewX >= 0 && m_resizeRoundedLastViewY >= 0)
+ {
+ repaintWidgetAtResizeLines (viewport ());
+ repaintWidgetAtResizeLines (m_view);
+
+ repaintWidgetAtResizeLines (m_bottomGrip);
+ repaintWidgetAtResizeLines (m_rightGrip);
+ repaintWidgetAtResizeLines (m_bottomRightGrip);
+ }
+}
+
+
+// protected
+void kpViewScrollableContainer::drawResizeLines ()
+{
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 0
+ kdDebug () << "kpViewScrollableContainer::drawResizeLines()"
+ << " lastViewX=" << m_resizeRoundedLastViewX
+ << " lastViewY=" << m_resizeRoundedLastViewY
+ << endl;
+#endif
+
+
+ QPainter p (viewport (), true/*unclipped*/);
+ p.setRasterOp (Qt::NotROP);
+
+ const QRect rightRect = rightResizeLineRect ();
+ if (rightRect.isValid ())
+ p.fillRect (mapViewToViewport (rightRect), Qt::white);
+
+ const QRect bottomRect = bottomResizeLineRect ();
+ if (bottomRect.isValid ())
+ p.fillRect (mapViewToViewport (bottomRect), Qt::white);
+
+ const QRect bottomRightRect = bottomRightResizeLineRect ();
+ if (bottomRightRect.isValid ())
+ p.fillRect (mapViewToViewport (bottomRightRect), Qt::white);
+
+ p.end ();
+}
+
+
+// protected
+void kpViewScrollableContainer::updateResizeLines (int viewX, int viewY,
+ int viewDX, int viewDY)
+{
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 0
+ kdDebug () << "kpViewScrollableContainer::updateResizeLines("
+ << viewX << "," << viewY << ")"
+ << " oldViewX=" << m_resizeRoundedLastViewX
+ << " oldViewY=" << m_resizeRoundedLastViewY
+ << " viewDX=" << viewDX
+ << " viewDY=" << viewDY
+ << endl;
+#endif
+
+ eraseResizeLines ();
+
+
+ if (viewX >= 0 && viewY >= 0)
+ {
+ m_resizeRoundedLastViewX = (int) m_view->transformDocToViewX ((int) m_view->transformViewToDocX (viewX));
+ m_resizeRoundedLastViewY = (int) m_view->transformDocToViewY ((int) m_view->transformViewToDocY (viewY));
+
+ m_resizeRoundedLastViewDX = viewDX;
+ m_resizeRoundedLastViewDY = viewDY;
+ }
+ else
+ {
+ m_resizeRoundedLastViewX = -1;
+ m_resizeRoundedLastViewY = -1;
+
+ m_resizeRoundedLastViewDX = 0;
+ m_resizeRoundedLastViewDY = 0;
+ }
+
+ // TODO: This is suboptimal since if another window pops up on top of
+ // KolourPaint then disappears, the lines are not redrawn
+ // (although this doesn't happen very frequently since we grab the
+ // keyboard and mouse when resizing):
+ //
+ // e.g. sleep 5 && gedit & sleep 10 && killall gedit
+ //
+ // Should be done in the paintEvent's of every child of the
+ // scrollview.
+ drawResizeLines ();
+}
+
+
+// protected slot
+void kpViewScrollableContainer::slotGripBeganDraw ()
+{
+ if (!m_view)
+ return;
+
+ calculateDocResizingGrip ();
+
+ m_haveMovedFromOriginalDocSize = false;
+
+ updateResizeLines (m_view->width (), m_view->height (),
+ 0/*viewDX*/, 0/*viewDY*/);
+
+ emit beganDocResize ();
+}
+
+// protected slot
+void kpViewScrollableContainer::slotGripContinuedDraw (int inViewDX, int inViewDY,
+ bool dueToDragScroll)
+{
+ int viewDX = inViewDX,
+ viewDY = inViewDY;
+
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "kpViewScrollableContainer::slotGripContinuedDraw("
+ << viewDX << "," << viewDY << ") size="
+ << newDocSize (viewDX, viewDY)
+ << " dueToDragScroll=" << dueToDragScroll
+ << endl;
+#endif
+
+ if (!m_view)
+ return;
+
+ if (!dueToDragScroll &&
+ beginDragScroll (QPoint (), QPoint (), m_view->zoomLevelX ()))
+ {
+ const QPoint newViewDeltaPoint = docResizingGrip ()->viewDeltaPoint ();
+ viewDX = newViewDeltaPoint.x ();
+ viewDY = newViewDeltaPoint.y ();
+ #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "\tdrag scrolled - new view delta point="
+ << newViewDeltaPoint
+ << endl;
+ #endif
+ }
+
+ m_haveMovedFromOriginalDocSize = true;
+
+ updateResizeLines (QMAX (1, QMAX (m_view->width () + viewDX, (int) m_view->transformDocToViewX (1))),
+ QMAX (1, QMAX (m_view->height () + viewDY, (int) m_view->transformDocToViewY (1))),
+ viewDX, viewDY);
+
+ emit continuedDocResize (newDocSize ());
+}
+
+// protected slot
+void kpViewScrollableContainer::slotGripCancelledDraw ()
+{
+ m_haveMovedFromOriginalDocSize = false;
+
+ updateResizeLines (-1, -1, 0, 0);
+
+ calculateDocResizingGrip ();
+
+ emit cancelledDocResize ();
+
+ endDragScroll ();
+}
+
+// protected slot
+void kpViewScrollableContainer::slotGripEndedDraw (int viewDX, int viewDY)
+{
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "kpViewScrollableContainer::slotGripEndedDraw("
+ << viewDX << "," << viewDY << ") size="
+ << newDocSize (viewDX, viewDY)
+ << endl;
+#endif
+
+ if (!m_view)
+ return;
+
+ const QSize newSize = newDocSize (viewDX, viewDY);
+
+ m_haveMovedFromOriginalDocSize = false;
+
+ // must erase lines before view size changes
+ updateResizeLines (-1, -1, 0, 0);
+
+ calculateDocResizingGrip ();
+
+ emit endedDocResize (newSize);
+
+ endDragScroll ();
+}
+
+
+// protected slot
+void kpViewScrollableContainer::slotGripStatusMessageChanged (const QString &string)
+{
+ if (string == m_gripStatusMessage)
+ return;
+
+ m_gripStatusMessage = string;
+ emit statusMessageChanged (string);
+}
+
+
+// public slot
+void kpViewScrollableContainer::recalculateStatusMessage ()
+{
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "kpViewScrollabelContainer::recalculateStatusMessage()" << endl;
+ kdDebug () << "\tQCursor::pos=" << QCursor::pos ()
+ << " global visibleRect="
+ << kpWidgetMapper::toGlobal (this,
+ QRect (0, 0, visibleWidth (), visibleHeight ()))
+ << " brGrip.hotRect=" << m_bottomRightGrip->hotRect (true)
+ << " bGrip.hotRect=" << m_bottomGrip->hotRect (true)
+ << " rGrip.hotRect=" << m_rightGrip->hotRect (true)
+ << endl;
+#endif
+
+ // HACK: After dragging to a new size, handles move so that they are now
+ // under the mouse pointer but no mouseMoveEvent() is generated for
+ // any grip. This also handles the case of cancelling over any
+ // grip.
+ //
+ if (kpWidgetMapper::toGlobal (this,
+ QRect (0, 0, visibleWidth (), visibleHeight ()))
+ .contains (QCursor::pos ()))
+ {
+ if (m_bottomRightGrip->isShown () &&
+ m_bottomRightGrip->hotRect (true/*to global*/)
+ .contains (QCursor::pos ()))
+ {
+ m_bottomRightGrip->setUserMessage (i18n ("Left drag the handle to resize the image."));
+ }
+ else if (m_bottomGrip->isShown () &&
+ m_bottomGrip->hotRect (true/*to global*/)
+ .contains (QCursor::pos ()))
+ {
+ m_bottomGrip->setUserMessage (i18n ("Left drag the handle to resize the image."));
+ }
+ else if (m_rightGrip->isShown () &&
+ m_rightGrip->hotRect (true/*to global*/)
+ .contains (QCursor::pos ()))
+ {
+ m_rightGrip->setUserMessage (i18n ("Left drag the handle to resize the image."));
+ }
+ else
+ {
+ clearStatusMessage ();
+ }
+ }
+ else
+ {
+ clearStatusMessage ();
+ }
+}
+
+
+// protected slot
+void kpViewScrollableContainer::slotContentsMoving (int x, int y)
+{
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "kpViewScrollableContainer::slotContentsMoving("
+ << x << "," << y << ")"
+ << " contentsX=" << contentsX ()
+ << " contentsY=" << contentsY () << endl;
+#endif
+
+ m_contentsXSoon = x, m_contentsYSoon = y;
+ emit contentsMovingSoon (m_contentsXSoon, m_contentsYSoon);
+
+ // Reduce flicker - don't let QScrollView scroll to-be-erased lines
+ eraseResizeLines ();
+
+ QTimer::singleShot (0, this, SLOT (slotContentsMoved ()));
+}
+
+// protected slot
+void kpViewScrollableContainer::slotContentsMoved ()
+{
+ m_contentsXSoon = m_contentsYSoon = -1;
+
+ kpGrip *grip = docResizingGrip ();
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "kpViewScrollableContainer::slotContentsMoved()"
+ << " grip=" << grip
+ << " contentsX=" << contentsX ()
+ << " contentsY=" << contentsY () << endl;
+#endif
+ if (!grip)
+ return;
+
+ grip->mouseMovedTo (grip->mapFromGlobal (QCursor::pos ()),
+ true/*moved due to drag scroll*/);
+}
+
+
+// protected
+void kpViewScrollableContainer::disconnectViewSignals ()
+{
+ disconnect (m_view, SIGNAL (sizeChanged (const QSize &)),
+ this, SLOT (updateGrips ()));
+ disconnect (m_view, SIGNAL (destroyed ()),
+ this, SLOT (slotViewDestroyed ()));
+}
+
+// protected
+void kpViewScrollableContainer::connectViewSignals ()
+{
+ connect (m_view, SIGNAL (sizeChanged (const QSize &)),
+ this, SLOT (updateGrips ()));
+ connect (m_view, SIGNAL (destroyed ()),
+ this, SLOT (slotViewDestroyed ()));
+}
+
+
+// public virtual [base QScrollView]
+void kpViewScrollableContainer::addChild (QWidget *widget, int x, int y)
+{
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "kpViewScrollableContainer::addChild(" << widget
+ << "," << x << "," << y << endl;
+#endif
+
+ QScrollView::addChild (widget, x, y);
+
+ kpView *view = dynamic_cast <kpView *> (widget);
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "\tcast to kpView: " << view << endl;
+#endif
+ if (view)
+ {
+ setView (view);
+ }
+}
+
+
+// public
+kpView *kpViewScrollableContainer::view () const
+{
+ return m_view;
+}
+
+// public
+void kpViewScrollableContainer::setView (kpView *view)
+{
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "kpViewScrollableContainer::setView(" << view << ")" << endl;
+#endif
+
+ if (m_view == view)
+ return;
+
+ if (m_view)
+ {
+ disconnectViewSignals ();
+ }
+
+ m_view = view;
+
+ updateGrips ();
+
+ if (m_view)
+ {
+ connectViewSignals ();
+ }
+}
+
+
+// public slot
+void kpViewScrollableContainer::updateGrips ()
+{
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "kpViewScrollableContainer::updateGrips() m_view="
+ << m_view << endl;
+#endif
+
+ if (m_view)
+ {
+ m_bottomGrip->setFixedWidth (m_view->width ());
+ moveChild (m_bottomGrip, 0, m_view->height ());
+
+ m_rightGrip->setFixedHeight (m_view->height ());
+ moveChild (m_rightGrip, m_view->width (), 0);
+
+ moveChild (m_bottomRightGrip, m_view->width (), m_view->height ());
+ }
+
+ m_bottomGrip->setShown (bool (m_view));
+ m_rightGrip->setShown (bool (m_view));
+ m_bottomRightGrip->setShown (bool (m_view));
+
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "\tcontentsRect=" << contentsRect ()
+ << " visibleRect=" << visibleRect ()
+ << " viewportRect=" << viewport ()->rect ()
+ << endl;
+#endif
+
+ if (m_view)
+ {
+ resizeContents (m_view->width () + m_rightGrip->width (),
+ m_view->height () + m_bottomGrip->height ());
+ }
+ else
+ {
+ resizeContents (0, 0);
+ }
+
+ recalculateStatusMessage ();
+}
+
+// protected slot
+void kpViewScrollableContainer::slotViewDestroyed ()
+{
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "kpViewScrollableContainer::slotViewDestroyed() m_view="
+ << m_view << endl;
+#endif
+
+ m_view = 0;
+ updateGrips ();
+}
+
+
+// public slot
+bool kpViewScrollableContainer::beginDragScroll (const QPoint &/*docPoint*/,
+ const QPoint &/*lastDocPoint*/,
+ int zoomLevel,
+ bool *didSomething)
+{
+ if (didSomething)
+ *didSomething = false;
+
+ m_zoomLevel = zoomLevel;
+
+ const QPoint p = mapFromGlobal (QCursor::pos ());
+
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "kpViewScrollableContainer::beginDragScroll() p=" << p
+ << " dragScrollTimerRunOnce=" << m_scrollTimerRunOnce
+ << endl;
+#endif
+
+ bool stopDragScroll = true;
+ bool scrolled = false;
+
+ if (!noDragScrollRect ().contains (p))
+ {
+ if (m_dragScrollTimer->isActive ())
+ {
+ if (m_scrollTimerRunOnce)
+ {
+ scrolled = slotDragScroll ();
+ }
+ }
+ else
+ {
+ m_scrollTimerRunOnce = false;
+ m_dragScrollTimer->start (DragScrollInitialInterval);
+ }
+
+ stopDragScroll = false;
+ }
+
+ if (stopDragScroll)
+ m_dragScrollTimer->stop ();
+
+ if (didSomething)
+ *didSomething = scrolled;
+
+ return scrolled;
+}
+
+// public slot
+bool kpViewScrollableContainer::beginDragScroll (const QPoint &docPoint,
+ const QPoint &lastDocPoint,
+ int zoomLevel)
+{
+ return beginDragScroll (docPoint, lastDocPoint, zoomLevel,
+ 0/*don't want scrolled notification*/);
+}
+
+
+// public slot
+bool kpViewScrollableContainer::endDragScroll ()
+{
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "kpViewScrollableContainer::endDragScroll()" << endl;
+#endif
+
+ if (m_dragScrollTimer->isActive ())
+ {
+ m_dragScrollTimer->stop ();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+static const int distanceFromRectToMultiplier (int dist)
+{
+ if (dist < 0)
+ return 0;
+ else if (dist < DragDistanceFromRectMaxFor1stMultiplier)
+ return 1;
+ else if (dist < DragDistanceFromRectMaxFor2ndMultiplier)
+ return 2;
+ else
+ return 4;
+}
+
+
+// protected slot
+bool kpViewScrollableContainer::slotDragScroll (bool *didSomething)
+{
+ bool scrolled = false;
+
+ if (didSomething)
+ *didSomething = false;
+
+
+ const QRect rect = noDragScrollRect ();
+ const QPoint pos = mapFromGlobal (QCursor::pos ());
+
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "kpViewScrollableContainer::slotDragScroll()"
+ << " noDragScrollRect=" << rect
+ << " pos=" << pos
+ << " contentsX=" << contentsX ()
+ << " contentsY=" << contentsY () << endl;
+#endif
+
+ int dx = 0, dy = 0;
+ int dxMultiplier = 0, dyMultiplier = 0;
+
+ if (pos.x () < rect.left ())
+ {
+ dx = -DragScrollNumPixels;
+ dxMultiplier = distanceFromRectToMultiplier (rect.left () - pos.x ());
+ }
+ else if (pos.x () > rect.right ())
+ {
+ dx = +DragScrollNumPixels;
+ dxMultiplier = distanceFromRectToMultiplier (pos.x () - rect.right ());
+ }
+
+ if (pos.y () < rect.top ())
+ {
+ dy = -DragScrollNumPixels;
+ dyMultiplier = distanceFromRectToMultiplier (rect.top () - pos.y ());
+ }
+ else if (pos.y () > rect.bottom ())
+ {
+ dy = +DragScrollNumPixels;
+ dyMultiplier = distanceFromRectToMultiplier (pos.y () - rect.bottom ());
+ }
+
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 0
+ kdDebug () << "kpViewScrollableContainer::slotDragScroll()"
+ << " dx=" << dx << " * " << dxMultiplier
+ << " dy=" << dy << " * " << dyMultiplier
+ << " zoomLevel=" << m_zoomLevel
+ << endl;
+#endif
+
+ dx *= dxMultiplier;// * QMAX (1, m_zoomLevel / 100);
+ dy *= dyMultiplier;// * QMAX (1, m_zoomLevel / 100);
+
+ if (dx || dy)
+ {
+ const int oldContentsX = contentsX (),
+ oldContentsY = contentsY ();
+
+ scrollBy (dx, dy);
+
+ #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 1
+ kdDebug () << "\tafter scrollBy():"
+ << " contentsX=" << contentsX ()
+ << " contentsY=" << contentsY () << endl;
+ #endif
+
+ scrolled = (oldContentsX != contentsX () ||
+ oldContentsY != contentsY ());
+
+ if (scrolled)
+ {
+ QRegion region = QRect (contentsX (), contentsY (),
+ visibleWidth (), visibleHeight ());
+ region -= QRect (oldContentsX, oldContentsY,
+ visibleWidth (), visibleHeight ());
+
+ // Repaint newly exposed region immediately to reduce tearing
+ // of scrollView.
+ m_view->repaint (region, false/*no erase*/);
+ }
+ }
+
+
+ m_dragScrollTimer->changeInterval (DragScrollInterval);
+ m_scrollTimerRunOnce = true;
+
+
+ if (didSomething)
+ *didSomething = scrolled;
+
+ return scrolled;
+}
+
+// protected virtual [base QScrollView]
+void kpViewScrollableContainer::contentsDragMoveEvent (QDragMoveEvent *e)
+{
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "kpViewScrollableContainer::contentsDragMoveEvent"
+ << e->pos ()
+ << endl;
+#endif
+
+ QScrollView::contentsDragMoveEvent (e);
+}
+
+// protected slot
+bool kpViewScrollableContainer::slotDragScroll ()
+{
+ return slotDragScroll (0/*don't want scrolled notification*/);
+}
+
+
+// protected virtual [base QScrollView]
+void kpViewScrollableContainer::contentsMouseMoveEvent (QMouseEvent *e)
+{
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "kpViewScrollableContainer::contentsMouseMoveEvent"
+ << e->pos ()
+ << endl;
+#endif
+
+ QScrollView::contentsMouseMoveEvent (e);
+}
+
+// protected virtual [base QScrollView]
+void kpViewScrollableContainer::mouseMoveEvent (QMouseEvent *e)
+{
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "kpViewScrollableContainer::mouseMoveEvent"
+ << e->pos ()
+ << endl;
+#endif
+
+ QScrollView::mouseMoveEvent (e);
+}
+
+
+// protected virtual [base QScrollView]
+void kpViewScrollableContainer::contentsWheelEvent (QWheelEvent *e)
+{
+ e->ignore ();
+
+ if (m_view)
+ m_view->wheelEvent (e);
+
+ if (!e->isAccepted ())
+ QScrollView::contentsWheelEvent (e);
+}
+
+
+QRect kpViewScrollableContainer::noDragScrollRect () const
+{
+ return QRect (DragScrollLeftTopMargin, DragScrollLeftTopMargin,
+ width () - DragScrollLeftTopMargin - DragScrollRightBottomMargin,
+ height () - DragScrollLeftTopMargin - DragScrollRightBottomMargin);
+}
+
+// protected virtual [base QScrollView]
+bool kpViewScrollableContainer::eventFilter (QObject *watchedObject, QEvent *event)
+{
+ return QScrollView::eventFilter (watchedObject, event);
+}
+
+// protected virtual [base QScrollView]
+void kpViewScrollableContainer::viewportPaintEvent (QPaintEvent *e)
+{
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+ kdDebug () << "kpViewScrollableContainer::viewportPaintEvent("
+ << e->rect ()
+ << ")" << endl;
+#endif
+
+ QScrollView::viewportPaintEvent (e);
+}
+
+// protected virtual [base QFrame]
+void kpViewScrollableContainer::paintEvent (QPaintEvent *e)
+{
+#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 0
+ kdDebug () << "kpViewScrollableContainer::paintEvent("
+ << e->rect ()
+ << ")" << endl;
+#endif
+
+ QScrollView::paintEvent (e);
+}
+
+// protected virtual [base QScrollView]
+void kpViewScrollableContainer::resizeEvent (QResizeEvent *e)
+{
+ QScrollView::resizeEvent (e);
+
+ emit resized ();
+}
+
+
+#include <kpviewscrollablecontainer.moc>
diff --git a/kolourpaint/kpviewscrollablecontainer.h b/kolourpaint/kpviewscrollablecontainer.h
new file mode 100644
index 00000000..203bbd1f
--- /dev/null
+++ b/kolourpaint/kpviewscrollablecontainer.h
@@ -0,0 +1,255 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef KP_VIEW_SCROLLABLE_CONTAINER_H
+#define KP_VIEW_SCROLLABLE_CONTAINER_H
+
+
+#include <qpoint.h>
+#include <qscrollview.h>
+#include <qsize.h>
+
+
+class QCursor;
+class QRect;
+class QTimer;
+
+class kpGrip;
+class kpView;
+class kpMainWindow;
+
+
+// TODO: refactor by sharing iface's with kpTool
+class kpGrip : public QWidget
+{
+Q_OBJECT
+
+public:
+ enum GripType
+ {
+ Right = 1, Bottom = 2,
+ BottomRight = Right | Bottom
+ };
+
+ kpGrip (GripType type,
+ QWidget *parent, const char *name = 0);
+ virtual ~kpGrip ();
+
+ GripType type () const;
+
+ static const QCursor &cursorForType (GripType type);
+
+ QRect hotRect (bool toGlobal = false) const;
+
+ bool isDrawing () const;
+
+signals:
+ void beganDraw ();
+ void continuedDraw (int viewDX, int viewDY, bool dueToDragScroll);
+ void cancelledDraw ();
+ void endedDraw (int viewDX, int viewDY);
+
+ void statusMessageChanged (const QString &string);
+
+ void releasedAllButtons ();
+
+public:
+ QString haventBegunDrawUserMessage () const;
+
+ QString userMessage () const;
+ void setUserMessage (const QString &message);
+
+protected:
+ void updatePixmap ();
+ void cancel ();
+
+protected:
+ virtual void keyReleaseEvent (QKeyEvent *e);
+ virtual void mousePressEvent (QMouseEvent *e);
+public:
+ QPoint viewDeltaPoint () const;
+ void mouseMovedTo (const QPoint &point, bool dueToDragScroll);
+protected:
+ virtual void mouseMoveEvent (QMouseEvent *e);
+ virtual void mouseReleaseEvent (QMouseEvent *e);
+ virtual void resizeEvent (QResizeEvent *e);
+
+ virtual void enterEvent (QEvent *e);
+ virtual void leaveEvent (QEvent *e);
+
+ virtual void paintEvent (QPaintEvent *e);
+
+protected:
+ GripType m_type;
+ QPoint m_startPoint, m_currentPoint;
+ QString m_userMessage;
+ bool m_shouldReleaseMouseButtons;
+};
+
+
+class kpViewScrollableContainer : public QScrollView
+{
+Q_OBJECT
+
+public:
+ kpViewScrollableContainer (kpMainWindow *parent, const char *name = 0);
+ virtual ~kpViewScrollableContainer ();
+
+ // Same as contentsX() and contentsY() except that after
+ // contentsMovingSoon() is emitted and before the scrollview actually
+ // scrolls, they return the would be values of contentsX() and
+ // contentsY() after scrolling.
+ int contentsXSoon ();
+ int contentsYSoon ();
+
+signals:
+ // connect to this instead of contentsMoving(int,int) so that
+ // contentsXSoon() and contentsYSoon() work
+ void contentsMovingSoon (int contentsX, int contentsY);
+
+ void beganDocResize ();
+ void continuedDocResize (const QSize &size);
+ void cancelledDocResize ();
+ void endedDocResize (const QSize &size);
+
+ // (string.isEmpty() if kpViewScrollableContainer has nothing to say)
+ void statusMessageChanged (const QString &string);
+
+ void resized ();
+
+public:
+ QSize newDocSize () const;
+ bool haveMovedFromOriginalDocSize () const;
+ QString statusMessage () const;
+ void clearStatusMessage ();
+
+protected:
+ void connectGripSignals (kpGrip *grip);
+
+ QSize newDocSize (int viewDX, int viewDY) const;
+
+ void calculateDocResizingGrip ();
+ kpGrip *docResizingGrip () const;
+
+ int bottomResizeLineWidth () const;
+ int rightResizeLineWidth () const;
+
+ QRect bottomResizeLineRect () const;
+ QRect rightResizeLineRect () const;
+ QRect bottomRightResizeLineRect () const;
+
+ QPoint mapViewToViewport (const QPoint &viewPoint);
+ QRect mapViewToViewport (const QRect &viewRect);
+
+ QRect mapViewportToGlobal (const QRect &viewportRect);
+ QRect mapViewToGlobal (const QRect &viewRect);
+
+ void repaintWidgetAtResizeLineViewRect (QWidget *widget,
+ const QRect &resizeLineViewRect);
+ void repaintWidgetAtResizeLines (QWidget *widget);
+ void eraseResizeLines ();
+
+ void drawResizeLines ();
+
+ void updateResizeLines (int viewX, int viewY,
+ int viewDX, int viewDY);
+
+protected slots:
+ void slotGripBeganDraw ();
+ void slotGripContinuedDraw (int viewDX, int viewDY, bool dueToScrollView);
+ void slotGripCancelledDraw ();
+ void slotGripEndedDraw (int viewDX, int viewDY);
+
+ void slotGripStatusMessageChanged (const QString &string);
+
+public slots:
+ void recalculateStatusMessage ();
+
+protected slots:
+ void slotContentsMoving (int x, int y);
+ void slotContentsMoved ();
+
+protected:
+ void disconnectViewSignals ();
+ void connectViewSignals ();
+
+public:
+ // Calls setView(<widget>) after adding <widget> if it's a kpView.
+ virtual void addChild (QWidget *widget, int x = 0, int y = 0);
+
+ kpView *view () const;
+ void setView (kpView *view);
+
+public slots:
+ void updateGrips ();
+protected slots:
+ void slotViewDestroyed ();
+
+public slots:
+ // TODO: Why the QPoint's?
+ // Why the need for view's zoomLevel? We have the view() anyway.
+ bool beginDragScroll (const QPoint &, const QPoint &,
+ int zoomLevel,
+ bool *didSomething);
+ bool beginDragScroll (const QPoint &, const QPoint &,
+ int zoomLevel);
+ bool endDragScroll ();
+
+protected slots:
+ bool slotDragScroll (bool *didSomething);
+ bool slotDragScroll ();
+
+protected:
+ QRect noDragScrollRect () const;
+
+ virtual void contentsDragMoveEvent (QDragMoveEvent *e);
+ virtual void contentsMouseMoveEvent (QMouseEvent *e);
+ virtual void contentsWheelEvent (QWheelEvent *e);
+ virtual void mouseMoveEvent (QMouseEvent *e);
+ virtual bool eventFilter (QObject *watchedObject, QEvent *e);
+ virtual void viewportPaintEvent (QPaintEvent *e);
+ virtual void paintEvent (QPaintEvent *e);
+ virtual void resizeEvent (QResizeEvent *e);
+
+protected:
+ kpMainWindow *m_mainWindow;
+ int m_contentsXSoon, m_contentsYSoon;
+ kpView *m_view;
+ kpGrip *m_bottomGrip, *m_rightGrip, *m_bottomRightGrip;
+ kpGrip *m_docResizingGrip;
+ QTimer *m_dragScrollTimer;
+ int m_zoomLevel;
+ bool m_scrollTimerRunOnce;
+ int m_resizeRoundedLastViewX, m_resizeRoundedLastViewY;
+ int m_resizeRoundedLastViewDX, m_resizeRoundedLastViewDY;
+ bool m_haveMovedFromOriginalDocSize;
+ QString m_gripStatusMessage;
+};
+
+
+#endif // KP_VIEW_SCROLLABLE_CONTAINER_H
diff --git a/kolourpaint/kpwidgetmapper.cpp b/kolourpaint/kpwidgetmapper.cpp
new file mode 100644
index 00000000..beb2624c
--- /dev/null
+++ b/kolourpaint/kpwidgetmapper.cpp
@@ -0,0 +1,76 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <kpwidgetmapper.h>
+
+#include <qpoint.h>
+#include <qrect.h>
+#include <qwidget.h>
+
+
+namespace kpWidgetMapper
+{
+
+
+QPoint fromGlobal (const QWidget *widget, const QPoint &point)
+{
+ if (!widget)
+ return point;
+
+ return widget->mapFromGlobal (point);
+}
+
+QRect fromGlobal (const QWidget *widget, const QRect &rect)
+{
+ if (!widget || !rect.isValid ())
+ return rect;
+
+ QPoint topLeft = fromGlobal (widget, rect.topLeft ());
+ return QRect (topLeft.x (), topLeft.y (), rect.width (), rect.height ());
+}
+
+
+QPoint toGlobal (const QWidget *widget, const QPoint &point)
+{
+ if (!widget)
+ return point;
+
+ return widget->mapToGlobal (point);
+}
+
+QRect toGlobal (const QWidget *widget, const QRect &rect)
+{
+ if (!widget || !rect.isValid ())
+ return rect;
+
+ QPoint topLeft = toGlobal (widget, rect.topLeft ());
+ return QRect (topLeft.x (), topLeft.y (), rect.width (), rect.height ());
+}
+
+
+} // namespace kpWidgetMapper {
diff --git a/kolourpaint/kpwidgetmapper.h b/kolourpaint/kpwidgetmapper.h
new file mode 100644
index 00000000..b5c4c412
--- /dev/null
+++ b/kolourpaint/kpwidgetmapper.h
@@ -0,0 +1,47 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KP_WIDGET_MAPPER
+#define KP_WIDGET_MAPPER
+
+
+class QWidget;
+class QPoint;
+class QRect;
+
+
+namespace kpWidgetMapper
+{
+ QPoint fromGlobal (const QWidget *widget, const QPoint &point);
+ QRect fromGlobal (const QWidget *widget, const QRect &rect);
+
+ QPoint toGlobal (const QWidget *widget, const QPoint &point);
+ QRect toGlobal (const QWidget *widget, const QRect &rect);
+}
+
+
+#endif // KP_WIDGET_MAPPER
diff --git a/kolourpaint/patches/checkerboard-faster-render.diff b/kolourpaint/patches/checkerboard-faster-render.diff
new file mode 100644
index 00000000..8c9c6402
--- /dev/null
+++ b/kolourpaint/patches/checkerboard-faster-render.diff
@@ -0,0 +1,141 @@
+At 100% zoom: kpMainWindow::drawTransparentBackground() accounts for
+about 75% of kpView::paintEvent()'s time. Bottleneck is
+QPainter::fillRect(). QPainter::drawPixmap() seems much faster. For
+800x600, renderer goes from 10ms to 1ms.
+
+--- kpmainwindow.cpp 2004-08-05 02:10:38.000000000 +1000
++++ kpmainwindow.cpp 2004-09-29 11:24:45.000000000 +1000
+@@ -838,12 +838,116 @@
+ }
+
+
++#if 1
++// (indexed by [isPreview][parity])
++static QPixmap *checkerBoardCache [2][2] = {{0, 0}, {0, 0}};
++
++
++static int checkerBoardCellSize (bool isPreview)
++{
++ return !isPreview ? 16 : 10;
++}
++
++
++// public
++static QPixmap *createCheckerBoardCache (bool isPreview, bool parity)
++{
++ int cellSize = checkerBoardCellSize (isPreview);
++ const int rep = 2; // must be multiple of 2
++
++ QPixmap *newPixmap = new QPixmap (cellSize * rep, cellSize * rep);
++ QPainter painter (newPixmap);
++
++ int parityAsInt = parity ? 1 : 0;
++ for (int y = 0; y < rep; y++)
++ {
++ for (int x = 0; x < rep; x++)
++ {
++ QColor col;
++
++ if ((parityAsInt + x + y) % 2)
++ {
++ if (!isPreview)
++ col = QColor (213, 213, 213);
++ else
++ col = QColor (224, 224, 224);
++ }
++ else
++ col = Qt::white;
++
++ painter.fillRect (x * cellSize, y * cellSize,
++ cellSize, cellSize,
++ col);
++ }
++ }
++
++ painter.end ();
++ return newPixmap;
++}
++
++void kpMainWindow::drawTransparentBackground (QPainter *painter,
++ int /*viewWidth*/, int /*viewHeight*/,
++ const QRect &rect,
++ bool isPreview)
++{
++#if DEBUG_KP_MAIN_WINDOW && 1 || 1
++ kdDebug () << "\tkpMainWindow::drawTransparentBackground(rect="
++ << rect << ")" << endl;
++ QTime totalTimer; totalTimer.start ();
++#endif
++
++ int cellSize = checkerBoardCellSize (isPreview);
++
++
++ int starty = rect.y ();
++ if (starty % cellSize)
++ starty -= (starty % cellSize);
++
++ int startx = rect.x ();
++ if (startx % cellSize)
++ startx -= (startx % cellSize);
++
++
++ int parity = ((startx / cellSize + starty / cellSize) % 2) ? 1 : 0;
++
++ if (!checkerBoardCache [isPreview][parity])
++ {
++ checkerBoardCache [isPreview][parity] = createCheckerBoardCache (isPreview, parity);
++ }
++
++ QPixmap *tilePixmap = checkerBoardCache [isPreview][parity];
++ for (int y = starty; y <= rect.bottom (); y += tilePixmap->height ())
++ {
++ for (int x = startx; x <= rect.right (); x += tilePixmap->width ())
++ {
++ painter->drawPixmap (x - rect.x (), y - rect.y (), *tilePixmap);
++ }
++ }
++
++#if DEBUG_KP_MAIN_WINDOW && 1 || 1
++{
++ const int totalTimerElapsed = totalTimer.elapsed ();
++ kdDebug () << "\t\ttotal=" << totalTimerElapsed << endl;
++}
++#endif
++}
++
++
++#else
++
+ // public
+ void kpMainWindow::drawTransparentBackground (QPainter *painter,
+ int /*viewWidth*/, int /*viewHeight*/,
+ const QRect &rect,
+ bool isPreview)
+ {
++#if DEBUG_KP_MAIN_WINDOW && 1
++ kdDebug () << "\tkpMainWindow::drawTransparentBackground(rect="
++ << rect << ")" << endl;
++ QTime totalTimer; totalTimer.start ();
++#endif
++
++
+ const int cellSize = !isPreview ? 16 : 10;
+
+ int starty = rect.y ();
+@@ -877,8 +982,15 @@
+ }
+ }
+ painter->restore ();
+-}
+
++#if DEBUG_KP_MAIN_WINDOW && 1 || 1
++{
++ const int totalTimerElapsed = totalTimer.elapsed ();
++ kdDebug () << "\t\ttotal=" << totalTimerElapsed << endl;
++}
++#endif
++}
++#endif
+
+ // private slot
+ void kpMainWindow::slotUpdateCaption ()
diff --git a/kolourpaint/patches/color_eraser_speedup.diff b/kolourpaint/patches/color_eraser_speedup.diff
new file mode 100644
index 00000000..5e1ff7b7
--- /dev/null
+++ b/kolourpaint/patches/color_eraser_speedup.diff
@@ -0,0 +1,264 @@
+[probably no longer applies without modification]
+
+Attempts to improve the performance of the Color Eraser & Eraser
+by drawing only _unique_ rectangles across interpolation lines
+and by not drawing pixmaps when the user has a solid rectangular
+brush.
+
+- appears to decrease the performance of the Eraser (QRegion
+ overhead?).
+- reduces code clarity
+- unsure of whether it increases performance of Color Eraser
+ (sometimes it seems faster, sometimes not)
+
+Index: tools/kptoolpen.cpp
+===================================================================
+RCS file: /home/kde/kdenonbeta/kolourpaint/tools/kptoolpen.cpp,v
+retrieving revision 1.9
+diff -u -p -r1.9 kptoolpen.cpp
+--- tools/kptoolpen.cpp 6 Dec 2003 06:53:36 -0000 1.9
++++ tools/kptoolpen.cpp 6 Dec 2003 06:55:46 -0000
+@@ -34,12 +34,13 @@
+ #include <qapplication.h>
+ #include <qbitmap.h>
+ #include <qcursor.h>
+-#include <qimage.h>
+-#include <qpainter.h>
+-#include <qpixmap.h>
+ #if DEBUG_KP_TOOL_PEN
+ #include <qdatetime.h>
+ #endif
++#include <qimage.h>
++#include <qpainter.h>
++#include <qpixmap.h>
++#include <qregion.h>
+
+ #include <kdebug.h>
+ #include <klocale.h>
+@@ -416,31 +417,28 @@ void kpToolPen::draw (const QPoint &this
+ rect = neededRect (rect, m_brushPixmap [m_mouseButton].width ());
+
+ #if DEBUG_KP_TOOL_PEN
+- if (m_mode & WashesPixmaps)
+- {
+- kdDebug () << "Washing pixmap (w=" << rect.width ()
+- << ",h=" << rect.height () << ")" << endl;
+- }
++ kdDebug () << "kpToolPen::draw() interpolate: area (w=" << rect.width ()
++ << ",h=" << rect.height () << ")" << endl;
+ QTime timer;
+ int convAndWashTime;
+ #endif
+
+- QPixmap pixmap = document ()->getPixmapAt (rect);
+- QPainter painter (&pixmap);
++ // optimsation - only render intersections of rectangles once
++ bool delayedDraw = ((m_mode & SquareBrushes) &&
++ ((m_mode & WashesPixmaps) ||
++ (m_mode == Eraser)/*solid rectangular brush*/));
++
++
++ QPixmap pixmap;
++ QPainter painter;
++ pixmap = document ()->getPixmapAt (rect);
++ painter.begin (&pixmap);
+ painter.setPen (color (m_mouseButton));
+
+- QImage image;
+- if (m_mode & WashesPixmaps)
+- {
+ #if DEBUG_KP_TOOL_PEN
++ if (m_mode & WashesPixmaps)
+ timer.start ();
+ #endif
+- image = pixmap.convertToImage ();
+- #if DEBUG_KP_TOOL_PEN
+- convAndWashTime = timer.restart ();
+- kdDebug () << "\tconvert to image: " << convAndWashTime << " ms" << endl;
+- #endif
+- }
+
+ bool didSomething = false;
+
+@@ -453,10 +451,21 @@ void kpToolPen::draw (const QPoint &this
+ else if (m_mode & (DrawsPixmaps | WashesPixmaps))
+ {
+ QRgb colorToReplace;
++ QImage image;
++ QRegion region;
+
+ if (m_mode & WashesPixmaps)
++ {
+ colorToReplace = color (1 - m_mouseButton).rgb ();
+
++ image = pixmap.convertToImage ();
++
++ #if DEBUG_KP_TOOL_PEN
++ convAndWashTime = timer.restart ();
++ kdDebug () << "\tconvert to image: " << convAndWashTime << " ms" << endl;
++ #endif
++ }
++
+ // Sweeps a pixmap along a line (modified Bresenham's line algorithm,
+ // see MODIFIED comment below).
+ //
+@@ -485,19 +494,27 @@ void kpToolPen::draw (const QPoint &this
+ int x = 0;
+ int y = 0;
+
+- if (m_mode & WashesPixmaps)
++ if (delayedDraw)
+ {
+- if (wash (&painter, image,
+- colorToReplace,
+- rect, plotx + rect.left (), ploty + rect.top ()))
+- {
+- didSomething = true;
+- }
++ region = region.unite (hotRect (plotx + rect.left (), ploty + rect.top ()));
+ }
+ else
+ {
+- painter.drawPixmap (hotPoint (plotx, ploty), m_brushPixmap [m_mouseButton]);
+- didSomething = true;
++ if (m_mode & WashesPixmaps)
++ {
++ if (wash (&painter, image,
++ colorToReplace,
++ rect, plotx + rect.left (), ploty + rect.top ()))
++ {
++ didSomething = true;
++ }
++ }
++ else
++ {
++ painter.drawPixmap (hotPoint (plotx, ploty),
++ m_brushPixmap [m_mouseButton]);
++ didSomething = true;
++ }
+ }
+
+ for (int i = 0; i <= inc; i++)
+@@ -541,39 +558,115 @@ void kpToolPen::draw (const QPoint &this
+ // is more than 1 point, of course). This is in contrast to the
+ // ordinary line algorithm which can create diagonal adjacencies.
+
++ if (delayedDraw)
++ {
++ region = region.unite (hotRect (plotx + rect.left (), oldploty + rect.top ()));
++ }
++ else
++ {
++ if (m_mode & WashesPixmaps)
++ {
++ if (wash (&painter, image,
++ colorToReplace,
++ rect, plotx + rect.left (), oldploty + rect.top ()))
++ {
++ didSomething = true;
++ }
++ }
++ else
++ {
++ painter.drawPixmap (hotPoint (plotx, oldploty),
++ m_brushPixmap [m_mouseButton]);
++ didSomething = true;
++ }
++ }
++ }
++
++ if (delayedDraw)
++ {
++ region = region.unite (hotRect (plotx + rect.left (), ploty + rect.top ()));
++ }
++ else
++ {
+ if (m_mode & WashesPixmaps)
+ {
+ if (wash (&painter, image,
+ colorToReplace,
+- rect, plotx + rect.left (), oldploty + rect.top ()))
++ rect, plotx + rect.left (), ploty + rect.top ()))
+ {
+ didSomething = true;
+ }
+ }
+ else
+ {
+- painter.drawPixmap (hotPoint (plotx, oldploty), m_brushPixmap [m_mouseButton]);
++ painter.drawPixmap (hotPoint (plotx, ploty),
++ m_brushPixmap [m_mouseButton]);
+ didSomething = true;
+ }
+ }
+-
++ }
++ }
++
++ if (delayedDraw)
++ {
++ QMemArray <QRect> rects = region.rects ();
++
++ int numRects = rects.count ();
++ #if DEBUG_KP_TOOL_PEN
++ kdDebug () << "\tdelayed draw now happening: numRects="
++ << numRects << endl;
++ int convImageMS = 0;
++ int washMS = 0;
++ int setDocMS = 0;
++ QTime timer;
++ #endif
++ for (int i = 0; i < numRects; i++)
++ {
++ QRect r = rects [i];
++ QPixmap pm = document ()->getPixmapAt (r);
++ #if DEBUG_KP_TOOL_PEN && 0
++ kdDebug () << "\tr=" << r << endl;
++ #endif
++
++ bool drew = false;
++
+ if (m_mode & WashesPixmaps)
+ {
++ timer.start ();
++
+ if (wash (&painter, image,
+ colorToReplace,
+- rect, plotx + rect.left (), ploty + rect.top ()))
++ rect, r))
+ {
+- didSomething = true;
++ drew = true;
+ }
++ washMS += timer.restart ();
+ }
+ else
+ {
+- painter.drawPixmap (hotPoint (plotx, ploty), m_brushPixmap [m_mouseButton]);
++ painter.setBrush (color (m_mouseButton));
++ painter.drawRect (r.x () - rect.x (),
++ r.y () - rect.y (),
++ r.width (),
++ r.height ());
++ drew = true;
++ }
++
++ if (drew)
++ {
++ m_currentCommand->updateBoundingRect (r);
+ didSomething = true;
++ setDocMS += timer.restart ();
+ }
+ }
++
++ #if DEBUG_KP_TOOL_PEN
++ kdDebug () << "convImageMS=" << convImageMS
++ << " washMS=" << washMS
++ << " setDocMS=" << setDocMS
++ << endl;
++ #endif
+ }
+-
+ }
+
+ painter.end ();
diff --git a/kolourpaint/patches/doc_resize_no_flicker.diff b/kolourpaint/patches/doc_resize_no_flicker.diff
new file mode 100644
index 00000000..ae5f9aba
--- /dev/null
+++ b/kolourpaint/patches/doc_resize_no_flicker.diff
@@ -0,0 +1,614 @@
+Eliminates flicker when moving document resize lines / dragging resize
+handles by:
+
+1. Not erasing areas that will be subsequently painted over with resize
+ lines.
+2. Erasing the old areas and painting the new ones atomicly by using
+ clever NOT'ing of pixels.
+
+Additionally, recover the resize lines after a window pops up momentarily
+over KolourPaint (kpViewScrollableContainer::windowActivationChange()).
+
+Critical bugs with this code and scrollbars:
+
+1. Drag scrolling leaves trails of resize lines.
+2. Moving the mouse cursor above the start of the document does not result
+ in a resize line at document y = 1.
+
+Because I'm still debugging, there are a few hacks in the code such as
+"m_resizeLinesDontPaintClever".
+
+Index: kpviewscrollablecontainer.cpp
+===================================================================
+RCS file: /home/kde/kdegraphics/kolourpaint/kpviewscrollablecontainer.cpp,v
+retrieving revision 1.7
+diff -u -p -r1.7 kpviewscrollablecontainer.cpp
+--- kpviewscrollablecontainer.cpp 29 Jul 2004 12:47:15 -0000 1.7
++++ kpviewscrollablecontainer.cpp 30 Jul 2004 11:37:20 -0000
+@@ -1,4 +1,4 @@
+-
++static bool inScroll = false;
+ /*
+ Copyright (c) 2003-2004 Clarence Dang <dang@kde.org>
+ All rights reserved.
+@@ -33,6 +33,7 @@
+ #include <qpainter.h>
+ #include <qpen.h>
+ #include <qpixmap.h>
++#include <qregion.h>
+ #include <qtimer.h>
+
+ #include <kdebug.h>
+@@ -240,7 +241,7 @@ void kpGrip::mousePressEvent (QMouseEven
+ m_startPoint = e->pos ();
+ m_currentPoint = e->pos ();
+ emit beganDraw ();
+- grabKeyboard ();
++ //grabKeyboard (); HACK
+
+ setUserMessage (i18n ("Resize Image: Right click to cancel."));
+ setCursor (cursorForType (m_type));
+@@ -387,6 +388,7 @@ kpViewScrollableContainer::kpViewScrolla
+ m_scrollTimerRunOnce (false),
+ m_resizeRoundedLastViewX (-1), m_resizeRoundedLastViewY (-1),
+ m_resizeRoundedLastViewDX (0), m_resizeRoundedLastViewDY (0),
++ m_resizeLinesDontPaintClever (0),
+ m_haveMovedFromOriginalDocSize (false)
+
+ {
+@@ -561,6 +563,18 @@ QRect kpViewScrollableContainer::bottomR
+ m_resizeRoundedLastViewY + bottomResizeLineWidth () - 1));
+ }
+
++// protected
++QRegion kpViewScrollableContainer::resizeLinesRegion () const
++{
++ QRegion ret;
++
++ ret += rightResizeLineRect ();
++ ret += bottomResizeLineRect ();
++ ret += bottomRightResizeLineRect ();
++
++ return ret;
++}
++
+
+ // TODO: are these 2 correct? Remember that viewport()->x() == 1, viewport()->y() == 1
+
+@@ -581,6 +595,17 @@ QRect kpViewScrollableContainer::mapView
+ return ret;
+ }
+
++// protected
++QRegion kpViewScrollableContainer::mapViewToViewport (const QRegion &viewRegion)
++{
++ if (viewRegion.isEmpty ())
++ return viewRegion;
++
++ QRegion ret = viewRegion;
++ ret.translate (-contentsX (), -contentsY ());
++ return ret;
++}
++
+
+ // protected
+ QRect kpViewScrollableContainer::mapViewportToGlobal (const QRect &viewportRect)
+@@ -589,89 +614,108 @@ QRect kpViewScrollableContainer::mapView
+ }
+
+ // protected
++QRegion kpViewScrollableContainer::mapViewportToGlobal (const QRegion &viewportRegion)
++{
++ return kpWidgetMapper::toGlobal (viewport (), viewportRegion);
++}
++
++
++// protected
+ QRect kpViewScrollableContainer::mapViewToGlobal (const QRect &viewRect)
+ {
+ return mapViewportToGlobal (mapViewToViewport (viewRect));
+ }
+
++// protected
++QRegion kpViewScrollableContainer::mapViewToGlobal (const QRegion &viewRegion)
++{
++ return mapViewportToGlobal (mapViewToViewport (viewRegion));
++}
++
+
+ // protected
+-void kpViewScrollableContainer::repaintWidgetAtResizeLineViewRect (
+- QWidget *widget, const QRect &resizeLineViewRect)
++void kpViewScrollableContainer::repaintWidgetRegion (
++ QWidget *widget,
++ const QRegion &viewRegion)
+ {
+- const QRect resizeLineGlobalRect = mapViewToGlobal (resizeLineViewRect);
++ const QRegion globalRegion = mapViewToGlobal (viewRegion);
++
+ const QRect widgetGlobalRect = kpWidgetMapper::toGlobal (widget,
+ widget->rect ());
+
+- const QRect redrawGlobalRect =
+- resizeLineGlobalRect.intersect (widgetGlobalRect);
+
+- const QRect redrawWidgetRect =
+- kpWidgetMapper::fromGlobal (widget, redrawGlobalRect);
++ const QRegion redrawGlobalRegion =
++ globalRegion.intersect (widgetGlobalRect);
+
++ const QRegion redrawWidgetRegion =
++ kpWidgetMapper::fromGlobal (widget, redrawGlobalRegion);
+
+- if (redrawWidgetRect.isValid ())
++
++ if (!redrawWidgetRegion.isEmpty ())
+ {
+ // TODO: should be "!widget->testWFlags (Qt::WRepaintNoErase)"
+ // but for some reason, doesn't work for viewport().
+ const bool erase = !dynamic_cast <kpView *> (widget);
+- widget->repaint (redrawWidgetRect, erase);
++ widget->repaint (redrawWidgetRegion, erase);
+ }
+ }
+
+ // protected
+-void kpViewScrollableContainer::repaintWidgetAtResizeLines (QWidget *widget)
++void kpViewScrollableContainer::eraseResizeLines (const QRegion &viewRegion)
+ {
+- repaintWidgetAtResizeLineViewRect (widget, rightResizeLineRect ());
+- repaintWidgetAtResizeLineViewRect (widget, bottomResizeLineRect ());
+- repaintWidgetAtResizeLineViewRect (widget, bottomRightResizeLineRect ());
+-}
++ if (viewRegion.isEmpty ())
++ return;
+
+-// protected
+-void kpViewScrollableContainer::eraseResizeLines ()
+-{
+- if (m_resizeRoundedLastViewX >= 0 && m_resizeRoundedLastViewY >= 0)
+- {
+- repaintWidgetAtResizeLines (viewport ());
+- repaintWidgetAtResizeLines (m_view);
+
+- repaintWidgetAtResizeLines (m_bottomGrip);
+- repaintWidgetAtResizeLines (m_rightGrip);
+- repaintWidgetAtResizeLines (m_bottomRightGrip);
+- }
++ repaintWidgetRegion (viewport (), viewRegion);
++ repaintWidgetRegion (m_view, viewRegion);
++
++ repaintWidgetRegion (m_bottomGrip, viewRegion);
++ repaintWidgetRegion (m_rightGrip, viewRegion);
++ repaintWidgetRegion (m_bottomRightGrip, viewRegion);
+ }
+
+
+ // protected
+-void kpViewScrollableContainer::drawResizeLines ()
++void kpViewScrollableContainer::drawResizeLines (const QRegion &viewRegion)
+ {
+ #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
+- kdDebug () << "kpViewScrollableContainer::drawResizeLines()"
++ kdDebug () << "kpViewScrollableContainer::drawResizeLines("
++ << viewRegion <<")"
+ << " lastViewX=" << m_resizeRoundedLastViewX
+ << " lastViewY=" << m_resizeRoundedLastViewY
+ << endl;
+ #endif
+
++ if (viewRegion.isEmpty ())
++ return;
++
+
+ QPainter p (viewport (), true/*unclipped*/);
+ p.setRasterOp (Qt::NotROP);
+
+- const QRect rightRect = rightResizeLineRect ();
+- if (rightRect.isValid ())
+- p.fillRect (mapViewToViewport (rightRect), Qt::white);
+-
+- const QRect bottomRect = bottomResizeLineRect ();
+- if (bottomRect.isValid ())
+- p.fillRect (mapViewToViewport (bottomRect), Qt::white);
+-
+- const QRect bottomRightRect = bottomRightResizeLineRect ();
+- if (bottomRightRect.isValid ())
+- p.fillRect (mapViewToViewport (bottomRightRect), Qt::white);
++ const QMemArray <QRect> rects = mapViewToViewport (viewRegion).rects ();
++ for (QMemArray <QRect>::ConstIterator it = rects.begin ();
++ it != rects.end ();
++ it++)
++ {
++ p.fillRect (*it, Qt::white);
++ }
+
+ p.end ();
+ }
+
+
++template <typename T>
++static inline void swap (T &a, T &b)
++{
++ T temp = a;
++
++ a = b;
++ b = temp;
++}
++
++
+ // protected
+ void kpViewScrollableContainer::updateResizeLines (int viewX, int viewY,
+ int viewDX, int viewDY)
+@@ -686,36 +730,71 @@ void kpViewScrollableContainer::updateRe
+ << endl;
+ #endif
+
+- eraseResizeLines ();
+-
++ int newResizeRoundedLastViewX = -1,
++ newResizeRoundedLastViewY = -1;
++ int newResizeRoundedLastViewDX = 0,
++ newResizeRoundedLastViewDY = 0;
+
+ if (viewX >= 0 && viewY >= 0)
+ {
+- m_resizeRoundedLastViewX = m_view->zoomDocToViewX (m_view->zoomViewToDocX (viewX));
+- m_resizeRoundedLastViewY = m_view->zoomDocToViewY (m_view->zoomViewToDocY (viewY));
++ newResizeRoundedLastViewX = m_view->zoomDocToViewX (m_view->zoomViewToDocX (viewX));
++ newResizeRoundedLastViewY = m_view->zoomDocToViewY (m_view->zoomViewToDocY (viewY));
+
+- m_resizeRoundedLastViewDX = viewDX;
+- m_resizeRoundedLastViewDY = viewDY;
++ newResizeRoundedLastViewDX = viewDX;
++ newResizeRoundedLastViewDY = viewDY;
+ }
+- else
+- {
+- m_resizeRoundedLastViewX = -1;
+- m_resizeRoundedLastViewY = -1;
+
+- m_resizeRoundedLastViewDX = 0;
+- m_resizeRoundedLastViewDY = 0;
+- }
+
+- // TODO: This is suboptimal since if another window pops up on top of
+- // KolourPaint then disappears, the lines are not redrawn
+- // (although this doesn't happen very frequently since we grab the
+- // keyboard and mouse when resizing):
+- //
+- // e.g. sleep 5 && gedit & sleep 10 && killall gedit
++ QRegion oldLinesRegion = resizeLinesRegion ();
++#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
++ kdDebug () << "\toldLinesRegion=" << oldLinesRegion << endl;
++#endif
++
++
++// (macro instead of writing out code to permit experimentation)
++#define SWAP_LAST_VIEW_STATS() \
++{ \
++ swap (m_resizeRoundedLastViewX, newResizeRoundedLastViewX); \
++ swap (m_resizeRoundedLastViewY, newResizeRoundedLastViewY); \
++ \
++ swap (m_resizeRoundedLastViewDX, newResizeRoundedLastViewDX); \
++ swap (m_resizeRoundedLastViewDY, newResizeRoundedLastViewDY); \
++}
++ SWAP_LAST_VIEW_STATS ();
++#undef SWAP_LAST_VIEW_STATS
++
++
++ QRegion newLinesRegion = resizeLinesRegion ();
++#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
++ kdDebug () << "\tnewLinesRegion=" << newLinesRegion << endl;
++#endif
++
++
++ // TODO: This is suboptimal - we will get redraw errors sooner or later.
++ // But I've tried hard to avoid them (e.g. windowActivationChange()).
+ //
+ // Should be done in the paintEvent's of every child of the
+ // scrollview.
+- drawResizeLines ();
++
++ if (m_resizeLinesDontPaintClever)
++ {
++ // (drawResizeLines() NOT's the pixels - so we can erase old and draw
++ // new at the same time)
++ drawResizeLines (newLinesRegion.eor (oldLinesRegion));
++ #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
++ kdDebug () << "\tNOTRregion="
++ << newLinesRegion.eor (oldLinesRegion) << endl;
++ #endif
++ }
++ else
++ {
++ eraseResizeLines (oldLinesRegion);
++ drawResizeLines (newLinesRegion);
++ #if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
++ kdDebug () << "\tnot erasing old lines; NOTRregion="
++ << newLinesRegion << endl;
++ #endif
++ }
+ }
+
+
+@@ -729,6 +808,8 @@ void kpViewScrollableContainer::slotGrip
+
+ m_haveMovedFromOriginalDocSize = false;
+
++ m_resizeLinesDontPaintClever = true;
++
+ updateResizeLines (m_view->width (), m_view->height (),
+ 0/*viewDX*/, 0/*viewDY*/);
+
+@@ -750,12 +831,28 @@ void kpViewScrollableContainer::slotGrip
+
+ m_haveMovedFromOriginalDocSize = true;
+
++#if 0
++ if (inScroll != !m_resizeLinesNeedErase)
++ {
++ kdError () << "slotGripContDraw EXCEPTION 0: inScroll=" << inScroll << endl;
++ memset (0, 42, 1048576);
++ }
++#endif
++
+ updateResizeLines (QMAX (1, QMAX (m_view->width () + viewDX, m_view->zoomDocToViewX (1))),
+ QMAX (1, QMAX (m_view->height () + viewDY, m_view->zoomDocToViewY (1))),
+ viewDX, viewDY);
+
+ emit continuedDocResize (newDocSize ());
+
++#if 0
++ if (!m_resizeLinesNeedErase)
++ {
++ kdError () << "slotGripContDraw EXCEPTION 1" << endl;
++ memset (0, 42, 1048576);
++ }
++#endif
++
+ beginDragScroll (QPoint (), QPoint (), m_view->zoomLevelX ());
+ }
+
+@@ -859,8 +956,19 @@ void kpViewScrollableContainer::slotCont
+ << x << "," << y << ")" << endl;
+ #endif
+
++ m_resizeLinesDontPaintClever++;
++
++ if (inScroll && 0)
++ {
++ kdError () << "slotContentsMovING EXCEPTION" << endl;
++ memset (0, 42, 1048576);
++ }
++
++ inScroll = true;
+ // Reduce flicker - don't let QScrollView scroll to-be-erased lines
+- eraseResizeLines ();
++ //eraseResizeLines (resizeLinesRegion ());
++ //m_resizeLinesNeedErase = false;
++
+
+ QTimer::singleShot (0, this, SLOT (slotContentsMoved ()));
+ }
+@@ -874,9 +982,27 @@ void kpViewScrollableContainer::slotCont
+ << " grip=" << grip << endl;
+ #endif
+ if (!grip)
++ {
++ inScroll = false;
+ return;
++ }
+
++ if (!inScroll && 0)
++ {
++ kdError () << "slotContentsMoved EXCEPTION" << endl;
++ memset (0, 42, 1048576);
++ }
+ grip->mouseMovedTo (grip->mapFromGlobal (QCursor::pos ()));
++#if 0
++ if (!m_resizeLinesNeedErase)
++ {
++ kdError () << "slotContentsMoved EXCEPTION 2" << endl;
++ memset (0, 42, 1048576);
++ }
++#endif
++ inScroll = false;
++
++ m_resizeLinesDontPaintClever--;
+ }
+
+
+@@ -1191,7 +1317,7 @@ bool kpViewScrollableContainer::eventFil
+ // protected virtual [base QScrollView]
+ void kpViewScrollableContainer::viewportPaintEvent (QPaintEvent *e)
+ {
+-#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER
++#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 0
+ kdDebug () << "kpViewScrollableContainer::viewportPaintEvent("
+ << e->rect ()
+ << ")" << endl;
+@@ -1213,4 +1339,42 @@ void kpViewScrollableContainer::paintEve
+ }
+
+
++// protected slot
++void kpViewScrollableContainer::windowActivationChanged ()
++{
++ if (isActiveWindow () &&
++ m_resizeRoundedLastViewX >= 0 && m_resizeRoundedLastViewY >= 0)
++ {
++ // We were obscured by a window that popped up monmentarily and
++ // this clobbered the resize lines (since the scrollView's child
++ // widgets don't draw them). This doesn't happen very frequently
++ // since we grab the keyboard and mouse when resizing but:
++ //
++ // e.g. sleep 5 && gedit & sleep 10 && killall gedit
++ //
++
++ // Repaint child widgets at the resize lines to make sure any
++ // remains of the resize lines are gone.
++ eraseResizeLines (resizeLinesRegion ());
++
++ // Draw the resize lines by NOT-ing the child widget pixels.
++ drawResizeLines (resizeLinesRegion ());
++ }
++}
++
++// protected virtual [base QWidget]
++void kpViewScrollableContainer::windowActivationChange (bool wasActive)
++{
++#if DEBUG_KP_VIEW_SCROLLABLE_CONTAINER && 1
++ kdDebug () << "kpViewScrollableContainer::windowActivationChange("
++ << wasActive << ")" << endl;
++#endif
++
++ QScrollView::windowActivationChange (wasActive);
++
++ // Wait for m_view to update
++ QTimer::singleShot (0, this, SLOT (windowActivationChanged ()));
++}
++
++
+ #include <kpviewscrollablecontainer.moc>
+Index: kpviewscrollablecontainer.h
+===================================================================
+RCS file: /home/kde/kdegraphics/kolourpaint/kpviewscrollablecontainer.h,v
+retrieving revision 1.3
+diff -u -p -r1.3 kpviewscrollablecontainer.h
+--- kpviewscrollablecontainer.h 19 Jul 2004 05:00:47 -0000 1.3
++++ kpviewscrollablecontainer.h 30 Jul 2004 11:37:21 -0000
+@@ -31,6 +31,7 @@
+
+
+ #include <qpoint.h>
++#include <qregion.h>
+ #include <qscrollview.h>
+ #include <qsize.h>
+
+@@ -147,19 +148,23 @@ protected:
+ QRect bottomResizeLineRect () const;
+ QRect rightResizeLineRect () const;
+ QRect bottomRightResizeLineRect () const;
++ QRegion resizeLinesRegion () const;
+
+ QPoint mapViewToViewport (const QPoint &viewPoint);
+ QRect mapViewToViewport (const QRect &viewRect);
++ QRegion mapViewToViewport (const QRegion &viewRegion);
+
+ QRect mapViewportToGlobal (const QRect &viewportRect);
++ QRegion mapViewportToGlobal (const QRegion &viewportRegion);
++
+ QRect mapViewToGlobal (const QRect &viewRect);
++ QRegion mapViewToGlobal (const QRegion &viewRegion);
+
+- void repaintWidgetAtResizeLineViewRect (QWidget *widget,
+- const QRect &resizeLineViewRect);
+- void repaintWidgetAtResizeLines (QWidget *widget);
+- void eraseResizeLines ();
++ void repaintWidgetRegion (QWidget *widget,
++ const QRegion &viewRegion);
++ void eraseResizeLines (const QRegion &viewRegion);
+
+- void drawResizeLines ();
++ void drawResizeLines (const QRegion &viewRegion);
+
+ void updateResizeLines (int viewX, int viewY,
+ int viewDX, int viewDY);
+@@ -213,6 +218,12 @@ protected:
+ virtual void viewportPaintEvent (QPaintEvent *e);
+ virtual void paintEvent (QPaintEvent *e);
+
++protected slots:
++ void windowActivationChanged ();
++protected:
++ virtual void windowActivationChange (bool wasActive);
++
++
+ protected:
+ kpMainWindow *m_mainWindow;
+ kpView *m_view;
+@@ -223,6 +234,7 @@ protected:
+ bool m_scrollTimerRunOnce;
+ int m_resizeRoundedLastViewX, m_resizeRoundedLastViewY;
+ int m_resizeRoundedLastViewDX, m_resizeRoundedLastViewDY;
++ int m_resizeLinesDontPaintClever;
+ bool m_haveMovedFromOriginalDocSize;
+ QString m_gripStatusMessage;
+ };
+Index: kpwidgetmapper.cpp
+===================================================================
+RCS file: /home/kde/kdegraphics/kolourpaint/kpwidgetmapper.cpp,v
+retrieving revision 1.1
+diff -u -p -r1.1 kpwidgetmapper.cpp
+--- kpwidgetmapper.cpp 10 Jul 2004 11:38:09 -0000 1.1
++++ kpwidgetmapper.cpp 30 Jul 2004 11:37:21 -0000
+@@ -30,6 +30,7 @@
+
+ #include <qpoint.h>
+ #include <qrect.h>
++#include <qregion.h>
+ #include <qwidget.h>
+
+
+@@ -54,6 +55,17 @@ QRect fromGlobal (const QWidget *widget,
+ return QRect (topLeft.x (), topLeft.y (), rect.width (), rect.height ());
+ }
+
++QRegion fromGlobal (const QWidget *widget, const QRegion &region)
++{
++ if (!widget || region.isEmpty ())
++ return region;
++
++ const QPoint widgetGlobalTopLeft = toGlobal (widget, QPoint (0, 0));
++ QRegion ret = region;
++ ret.translate (-widgetGlobalTopLeft.x (), -widgetGlobalTopLeft.y ());
++ return ret;
++}
++
+
+ QPoint toGlobal (const QWidget *widget, const QPoint &point)
+ {
+@@ -72,5 +84,16 @@ QRect toGlobal (const QWidget *widget, c
+ return QRect (topLeft.x (), topLeft.y (), rect.width (), rect.height ());
+ }
+
++QRegion toGlobal (const QWidget *widget, const QRegion &region)
++{
++ if (!widget || region.isEmpty ())
++ return region;
++
++ const QPoint widgetGlobalTopLeft = toGlobal (widget, QPoint (0, 0));
++ QRegion ret = region;
++ ret.translate (widgetGlobalTopLeft.x (), widgetGlobalTopLeft.y ());
++ return ret;
++}
++
+
+ } // namespace kpWidgetMapper {
+Index: kpwidgetmapper.h
+===================================================================
+RCS file: /home/kde/kdegraphics/kolourpaint/kpwidgetmapper.h,v
+retrieving revision 1.1
+diff -u -p -r1.1 kpwidgetmapper.h
+--- kpwidgetmapper.h 10 Jul 2004 11:38:09 -0000 1.1
++++ kpwidgetmapper.h 30 Jul 2004 11:37:21 -0000
+@@ -32,15 +32,18 @@
+ class QWidget;
+ class QPoint;
+ class QRect;
++class QRegion;
+
+
+ namespace kpWidgetMapper
+ {
+ QPoint fromGlobal (const QWidget *widget, const QPoint &point);
+ QRect fromGlobal (const QWidget *widget, const QRect &rect);
++ QRegion fromGlobal (const QWidget *widget, const QRegion &region);
+
+ QPoint toGlobal (const QWidget *widget, const QPoint &point);
+ QRect toGlobal (const QWidget *widget, const QRect &rect);
++ QRegion toGlobal (const QWidget *widget, const QRegion &region);
+ }
+
+
diff --git a/kolourpaint/pics/Makefile.am b/kolourpaint/pics/Makefile.am
new file mode 100644
index 00000000..2e4aed53
--- /dev/null
+++ b/kolourpaint/pics/Makefile.am
@@ -0,0 +1,13 @@
+SUBDIRS = custom
+
+KDE_ICON = kolourpaint
+
+actionicondir = $(kde_datadir)/kolourpaint/icons
+actionicon_ICON = AUTO
+
+# Change the following line every time you add an icon
+# to force Makefile regeneration:
+#
+# 4
+#
+
diff --git a/kolourpaint/pics/cr16-action-tool_brush.png b/kolourpaint/pics/cr16-action-tool_brush.png
new file mode 100644
index 00000000..32a23881
--- /dev/null
+++ b/kolourpaint/pics/cr16-action-tool_brush.png
Binary files differ
diff --git a/kolourpaint/pics/cr16-action-tool_color_picker.png b/kolourpaint/pics/cr16-action-tool_color_picker.png
new file mode 100644
index 00000000..569171e6
--- /dev/null
+++ b/kolourpaint/pics/cr16-action-tool_color_picker.png
Binary files differ
diff --git a/kolourpaint/pics/cr16-action-tool_color_washer.png b/kolourpaint/pics/cr16-action-tool_color_washer.png
new file mode 100644
index 00000000..97193458
--- /dev/null
+++ b/kolourpaint/pics/cr16-action-tool_color_washer.png
Binary files differ
diff --git a/kolourpaint/pics/cr16-action-tool_curve.png b/kolourpaint/pics/cr16-action-tool_curve.png
new file mode 100644
index 00000000..b86c96fb
--- /dev/null
+++ b/kolourpaint/pics/cr16-action-tool_curve.png
Binary files differ
diff --git a/kolourpaint/pics/cr16-action-tool_ellipse.png b/kolourpaint/pics/cr16-action-tool_ellipse.png
new file mode 100644
index 00000000..608d40b7
--- /dev/null
+++ b/kolourpaint/pics/cr16-action-tool_ellipse.png
Binary files differ
diff --git a/kolourpaint/pics/cr16-action-tool_elliptical_selection.png b/kolourpaint/pics/cr16-action-tool_elliptical_selection.png
new file mode 100644
index 00000000..70edc438
--- /dev/null
+++ b/kolourpaint/pics/cr16-action-tool_elliptical_selection.png
Binary files differ
diff --git a/kolourpaint/pics/cr16-action-tool_eraser.png b/kolourpaint/pics/cr16-action-tool_eraser.png
new file mode 100644
index 00000000..459d28a2
--- /dev/null
+++ b/kolourpaint/pics/cr16-action-tool_eraser.png
Binary files differ
diff --git a/kolourpaint/pics/cr16-action-tool_flood_fill.png b/kolourpaint/pics/cr16-action-tool_flood_fill.png
new file mode 100644
index 00000000..746ede5b
--- /dev/null
+++ b/kolourpaint/pics/cr16-action-tool_flood_fill.png
Binary files differ
diff --git a/kolourpaint/pics/cr16-action-tool_free_form_selection.png b/kolourpaint/pics/cr16-action-tool_free_form_selection.png
new file mode 100644
index 00000000..ed03ba39
--- /dev/null
+++ b/kolourpaint/pics/cr16-action-tool_free_form_selection.png
Binary files differ
diff --git a/kolourpaint/pics/cr16-action-tool_line.png b/kolourpaint/pics/cr16-action-tool_line.png
new file mode 100644
index 00000000..ce282923
--- /dev/null
+++ b/kolourpaint/pics/cr16-action-tool_line.png
Binary files differ
diff --git a/kolourpaint/pics/cr16-action-tool_pen.png b/kolourpaint/pics/cr16-action-tool_pen.png
new file mode 100644
index 00000000..ae64f5aa
--- /dev/null
+++ b/kolourpaint/pics/cr16-action-tool_pen.png
Binary files differ
diff --git a/kolourpaint/pics/cr16-action-tool_polygon.png b/kolourpaint/pics/cr16-action-tool_polygon.png
new file mode 100644
index 00000000..a5500d94
--- /dev/null
+++ b/kolourpaint/pics/cr16-action-tool_polygon.png
Binary files differ
diff --git a/kolourpaint/pics/cr16-action-tool_polyline.png b/kolourpaint/pics/cr16-action-tool_polyline.png
new file mode 100644
index 00000000..1e23ccd9
--- /dev/null
+++ b/kolourpaint/pics/cr16-action-tool_polyline.png
Binary files differ
diff --git a/kolourpaint/pics/cr16-action-tool_rect_selection.png b/kolourpaint/pics/cr16-action-tool_rect_selection.png
new file mode 100644
index 00000000..a85ef3f8
--- /dev/null
+++ b/kolourpaint/pics/cr16-action-tool_rect_selection.png
Binary files differ
diff --git a/kolourpaint/pics/cr16-action-tool_rectangle.png b/kolourpaint/pics/cr16-action-tool_rectangle.png
new file mode 100644
index 00000000..a8455de0
--- /dev/null
+++ b/kolourpaint/pics/cr16-action-tool_rectangle.png
Binary files differ
diff --git a/kolourpaint/pics/cr16-action-tool_rounded_rectangle.png b/kolourpaint/pics/cr16-action-tool_rounded_rectangle.png
new file mode 100644
index 00000000..4b5a0617
--- /dev/null
+++ b/kolourpaint/pics/cr16-action-tool_rounded_rectangle.png
Binary files differ
diff --git a/kolourpaint/pics/cr16-action-tool_spraycan.png b/kolourpaint/pics/cr16-action-tool_spraycan.png
new file mode 100644
index 00000000..75b7f748
--- /dev/null
+++ b/kolourpaint/pics/cr16-action-tool_spraycan.png
Binary files differ
diff --git a/kolourpaint/pics/cr16-action-tool_text.png b/kolourpaint/pics/cr16-action-tool_text.png
new file mode 100644
index 00000000..ffaab637
--- /dev/null
+++ b/kolourpaint/pics/cr16-action-tool_text.png
Binary files differ
diff --git a/kolourpaint/pics/cr22-action-tool_brush.png b/kolourpaint/pics/cr22-action-tool_brush.png
new file mode 100644
index 00000000..f2ad76cf
--- /dev/null
+++ b/kolourpaint/pics/cr22-action-tool_brush.png
Binary files differ
diff --git a/kolourpaint/pics/cr22-action-tool_color_picker.png b/kolourpaint/pics/cr22-action-tool_color_picker.png
new file mode 100644
index 00000000..3b7ed752
--- /dev/null
+++ b/kolourpaint/pics/cr22-action-tool_color_picker.png
Binary files differ
diff --git a/kolourpaint/pics/cr22-action-tool_color_washer.png b/kolourpaint/pics/cr22-action-tool_color_washer.png
new file mode 100644
index 00000000..35fcbac1
--- /dev/null
+++ b/kolourpaint/pics/cr22-action-tool_color_washer.png
Binary files differ
diff --git a/kolourpaint/pics/cr22-action-tool_curve.png b/kolourpaint/pics/cr22-action-tool_curve.png
new file mode 100644
index 00000000..9723e209
--- /dev/null
+++ b/kolourpaint/pics/cr22-action-tool_curve.png
Binary files differ
diff --git a/kolourpaint/pics/cr22-action-tool_ellipse.png b/kolourpaint/pics/cr22-action-tool_ellipse.png
new file mode 100644
index 00000000..cc57b2f8
--- /dev/null
+++ b/kolourpaint/pics/cr22-action-tool_ellipse.png
Binary files differ
diff --git a/kolourpaint/pics/cr22-action-tool_elliptical_selection.png b/kolourpaint/pics/cr22-action-tool_elliptical_selection.png
new file mode 100644
index 00000000..a6b23e11
--- /dev/null
+++ b/kolourpaint/pics/cr22-action-tool_elliptical_selection.png
Binary files differ
diff --git a/kolourpaint/pics/cr22-action-tool_eraser.png b/kolourpaint/pics/cr22-action-tool_eraser.png
new file mode 100644
index 00000000..78632a55
--- /dev/null
+++ b/kolourpaint/pics/cr22-action-tool_eraser.png
Binary files differ
diff --git a/kolourpaint/pics/cr22-action-tool_flood_fill.png b/kolourpaint/pics/cr22-action-tool_flood_fill.png
new file mode 100644
index 00000000..17cfefba
--- /dev/null
+++ b/kolourpaint/pics/cr22-action-tool_flood_fill.png
Binary files differ
diff --git a/kolourpaint/pics/cr22-action-tool_free_form_selection.png b/kolourpaint/pics/cr22-action-tool_free_form_selection.png
new file mode 100644
index 00000000..cc397f09
--- /dev/null
+++ b/kolourpaint/pics/cr22-action-tool_free_form_selection.png
Binary files differ
diff --git a/kolourpaint/pics/cr22-action-tool_line.png b/kolourpaint/pics/cr22-action-tool_line.png
new file mode 100644
index 00000000..7ab3c3d9
--- /dev/null
+++ b/kolourpaint/pics/cr22-action-tool_line.png
Binary files differ
diff --git a/kolourpaint/pics/cr22-action-tool_pen.png b/kolourpaint/pics/cr22-action-tool_pen.png
new file mode 100644
index 00000000..f80fa363
--- /dev/null
+++ b/kolourpaint/pics/cr22-action-tool_pen.png
Binary files differ
diff --git a/kolourpaint/pics/cr22-action-tool_polygon.png b/kolourpaint/pics/cr22-action-tool_polygon.png
new file mode 100644
index 00000000..1d05ec57
--- /dev/null
+++ b/kolourpaint/pics/cr22-action-tool_polygon.png
Binary files differ
diff --git a/kolourpaint/pics/cr22-action-tool_polyline.png b/kolourpaint/pics/cr22-action-tool_polyline.png
new file mode 100644
index 00000000..36c089c9
--- /dev/null
+++ b/kolourpaint/pics/cr22-action-tool_polyline.png
Binary files differ
diff --git a/kolourpaint/pics/cr22-action-tool_rect_selection.png b/kolourpaint/pics/cr22-action-tool_rect_selection.png
new file mode 100644
index 00000000..3dc8c75a
--- /dev/null
+++ b/kolourpaint/pics/cr22-action-tool_rect_selection.png
Binary files differ
diff --git a/kolourpaint/pics/cr22-action-tool_rectangle.png b/kolourpaint/pics/cr22-action-tool_rectangle.png
new file mode 100644
index 00000000..9954c17e
--- /dev/null
+++ b/kolourpaint/pics/cr22-action-tool_rectangle.png
Binary files differ
diff --git a/kolourpaint/pics/cr22-action-tool_rounded_rectangle.png b/kolourpaint/pics/cr22-action-tool_rounded_rectangle.png
new file mode 100644
index 00000000..b736a6cc
--- /dev/null
+++ b/kolourpaint/pics/cr22-action-tool_rounded_rectangle.png
Binary files differ
diff --git a/kolourpaint/pics/cr22-action-tool_spraycan.png b/kolourpaint/pics/cr22-action-tool_spraycan.png
new file mode 100644
index 00000000..bbd35078
--- /dev/null
+++ b/kolourpaint/pics/cr22-action-tool_spraycan.png
Binary files differ
diff --git a/kolourpaint/pics/cr22-action-tool_text.png b/kolourpaint/pics/cr22-action-tool_text.png
new file mode 100644
index 00000000..52b3ccf7
--- /dev/null
+++ b/kolourpaint/pics/cr22-action-tool_text.png
Binary files differ
diff --git a/kolourpaint/pics/cr32-action-tool_brush.png b/kolourpaint/pics/cr32-action-tool_brush.png
new file mode 100644
index 00000000..18bcab66
--- /dev/null
+++ b/kolourpaint/pics/cr32-action-tool_brush.png
Binary files differ
diff --git a/kolourpaint/pics/cr32-action-tool_color_picker.png b/kolourpaint/pics/cr32-action-tool_color_picker.png
new file mode 100644
index 00000000..38197e44
--- /dev/null
+++ b/kolourpaint/pics/cr32-action-tool_color_picker.png
Binary files differ
diff --git a/kolourpaint/pics/cr32-action-tool_color_washer.png b/kolourpaint/pics/cr32-action-tool_color_washer.png
new file mode 100644
index 00000000..b49c03ca
--- /dev/null
+++ b/kolourpaint/pics/cr32-action-tool_color_washer.png
Binary files differ
diff --git a/kolourpaint/pics/cr32-action-tool_curve.png b/kolourpaint/pics/cr32-action-tool_curve.png
new file mode 100644
index 00000000..db900434
--- /dev/null
+++ b/kolourpaint/pics/cr32-action-tool_curve.png
Binary files differ
diff --git a/kolourpaint/pics/cr32-action-tool_ellipse.png b/kolourpaint/pics/cr32-action-tool_ellipse.png
new file mode 100644
index 00000000..f6315fdc
--- /dev/null
+++ b/kolourpaint/pics/cr32-action-tool_ellipse.png
Binary files differ
diff --git a/kolourpaint/pics/cr32-action-tool_elliptical_selection.png b/kolourpaint/pics/cr32-action-tool_elliptical_selection.png
new file mode 100644
index 00000000..72c5fc7c
--- /dev/null
+++ b/kolourpaint/pics/cr32-action-tool_elliptical_selection.png
Binary files differ
diff --git a/kolourpaint/pics/cr32-action-tool_eraser.png b/kolourpaint/pics/cr32-action-tool_eraser.png
new file mode 100644
index 00000000..92efe970
--- /dev/null
+++ b/kolourpaint/pics/cr32-action-tool_eraser.png
Binary files differ
diff --git a/kolourpaint/pics/cr32-action-tool_flood_fill.png b/kolourpaint/pics/cr32-action-tool_flood_fill.png
new file mode 100644
index 00000000..6c116a71
--- /dev/null
+++ b/kolourpaint/pics/cr32-action-tool_flood_fill.png
Binary files differ
diff --git a/kolourpaint/pics/cr32-action-tool_free_form_selection.png b/kolourpaint/pics/cr32-action-tool_free_form_selection.png
new file mode 100644
index 00000000..b27f17d2
--- /dev/null
+++ b/kolourpaint/pics/cr32-action-tool_free_form_selection.png
Binary files differ
diff --git a/kolourpaint/pics/cr32-action-tool_line.png b/kolourpaint/pics/cr32-action-tool_line.png
new file mode 100644
index 00000000..b42db17f
--- /dev/null
+++ b/kolourpaint/pics/cr32-action-tool_line.png
Binary files differ
diff --git a/kolourpaint/pics/cr32-action-tool_pen.png b/kolourpaint/pics/cr32-action-tool_pen.png
new file mode 100644
index 00000000..a5881690
--- /dev/null
+++ b/kolourpaint/pics/cr32-action-tool_pen.png
Binary files differ
diff --git a/kolourpaint/pics/cr32-action-tool_polygon.png b/kolourpaint/pics/cr32-action-tool_polygon.png
new file mode 100644
index 00000000..5f643e3c
--- /dev/null
+++ b/kolourpaint/pics/cr32-action-tool_polygon.png
Binary files differ
diff --git a/kolourpaint/pics/cr32-action-tool_polyline.png b/kolourpaint/pics/cr32-action-tool_polyline.png
new file mode 100644
index 00000000..fabc5a48
--- /dev/null
+++ b/kolourpaint/pics/cr32-action-tool_polyline.png
Binary files differ
diff --git a/kolourpaint/pics/cr32-action-tool_rect_selection.png b/kolourpaint/pics/cr32-action-tool_rect_selection.png
new file mode 100644
index 00000000..c13c43b9
--- /dev/null
+++ b/kolourpaint/pics/cr32-action-tool_rect_selection.png
Binary files differ
diff --git a/kolourpaint/pics/cr32-action-tool_rectangle.png b/kolourpaint/pics/cr32-action-tool_rectangle.png
new file mode 100644
index 00000000..a271b7e5
--- /dev/null
+++ b/kolourpaint/pics/cr32-action-tool_rectangle.png
Binary files differ
diff --git a/kolourpaint/pics/cr32-action-tool_rounded_rectangle.png b/kolourpaint/pics/cr32-action-tool_rounded_rectangle.png
new file mode 100644
index 00000000..ed572dda
--- /dev/null
+++ b/kolourpaint/pics/cr32-action-tool_rounded_rectangle.png
Binary files differ
diff --git a/kolourpaint/pics/cr32-action-tool_spraycan.png b/kolourpaint/pics/cr32-action-tool_spraycan.png
new file mode 100644
index 00000000..b908810c
--- /dev/null
+++ b/kolourpaint/pics/cr32-action-tool_spraycan.png
Binary files differ
diff --git a/kolourpaint/pics/cr32-action-tool_text.png b/kolourpaint/pics/cr32-action-tool_text.png
new file mode 100644
index 00000000..a80b07a6
--- /dev/null
+++ b/kolourpaint/pics/cr32-action-tool_text.png
Binary files differ
diff --git a/kolourpaint/pics/cr48-action-tool_brush.png b/kolourpaint/pics/cr48-action-tool_brush.png
new file mode 100644
index 00000000..55758f0d
--- /dev/null
+++ b/kolourpaint/pics/cr48-action-tool_brush.png
Binary files differ
diff --git a/kolourpaint/pics/cr48-action-tool_color_picker.png b/kolourpaint/pics/cr48-action-tool_color_picker.png
new file mode 100644
index 00000000..e5414d6e
--- /dev/null
+++ b/kolourpaint/pics/cr48-action-tool_color_picker.png
Binary files differ
diff --git a/kolourpaint/pics/cr48-action-tool_color_washer.png b/kolourpaint/pics/cr48-action-tool_color_washer.png
new file mode 100644
index 00000000..2966d680
--- /dev/null
+++ b/kolourpaint/pics/cr48-action-tool_color_washer.png
Binary files differ
diff --git a/kolourpaint/pics/cr48-action-tool_curve.png b/kolourpaint/pics/cr48-action-tool_curve.png
new file mode 100644
index 00000000..c046a3ab
--- /dev/null
+++ b/kolourpaint/pics/cr48-action-tool_curve.png
Binary files differ
diff --git a/kolourpaint/pics/cr48-action-tool_ellipse.png b/kolourpaint/pics/cr48-action-tool_ellipse.png
new file mode 100644
index 00000000..a17095b1
--- /dev/null
+++ b/kolourpaint/pics/cr48-action-tool_ellipse.png
Binary files differ
diff --git a/kolourpaint/pics/cr48-action-tool_elliptical_selection.png b/kolourpaint/pics/cr48-action-tool_elliptical_selection.png
new file mode 100644
index 00000000..637b9603
--- /dev/null
+++ b/kolourpaint/pics/cr48-action-tool_elliptical_selection.png
Binary files differ
diff --git a/kolourpaint/pics/cr48-action-tool_eraser.png b/kolourpaint/pics/cr48-action-tool_eraser.png
new file mode 100644
index 00000000..69e5b77a
--- /dev/null
+++ b/kolourpaint/pics/cr48-action-tool_eraser.png
Binary files differ
diff --git a/kolourpaint/pics/cr48-action-tool_flood_fill.png b/kolourpaint/pics/cr48-action-tool_flood_fill.png
new file mode 100644
index 00000000..a2937a95
--- /dev/null
+++ b/kolourpaint/pics/cr48-action-tool_flood_fill.png
Binary files differ
diff --git a/kolourpaint/pics/cr48-action-tool_free_form_selection.png b/kolourpaint/pics/cr48-action-tool_free_form_selection.png
new file mode 100644
index 00000000..b0dd0ae9
--- /dev/null
+++ b/kolourpaint/pics/cr48-action-tool_free_form_selection.png
Binary files differ
diff --git a/kolourpaint/pics/cr48-action-tool_line.png b/kolourpaint/pics/cr48-action-tool_line.png
new file mode 100644
index 00000000..6d28915b
--- /dev/null
+++ b/kolourpaint/pics/cr48-action-tool_line.png
Binary files differ
diff --git a/kolourpaint/pics/cr48-action-tool_pen.png b/kolourpaint/pics/cr48-action-tool_pen.png
new file mode 100644
index 00000000..16d0f2f3
--- /dev/null
+++ b/kolourpaint/pics/cr48-action-tool_pen.png
Binary files differ
diff --git a/kolourpaint/pics/cr48-action-tool_polygon.png b/kolourpaint/pics/cr48-action-tool_polygon.png
new file mode 100644
index 00000000..d06b5b64
--- /dev/null
+++ b/kolourpaint/pics/cr48-action-tool_polygon.png
Binary files differ
diff --git a/kolourpaint/pics/cr48-action-tool_polyline.png b/kolourpaint/pics/cr48-action-tool_polyline.png
new file mode 100644
index 00000000..2d859d96
--- /dev/null
+++ b/kolourpaint/pics/cr48-action-tool_polyline.png
Binary files differ
diff --git a/kolourpaint/pics/cr48-action-tool_rect_selection.png b/kolourpaint/pics/cr48-action-tool_rect_selection.png
new file mode 100644
index 00000000..71b59563
--- /dev/null
+++ b/kolourpaint/pics/cr48-action-tool_rect_selection.png
Binary files differ
diff --git a/kolourpaint/pics/cr48-action-tool_rectangle.png b/kolourpaint/pics/cr48-action-tool_rectangle.png
new file mode 100644
index 00000000..9320c2d4
--- /dev/null
+++ b/kolourpaint/pics/cr48-action-tool_rectangle.png
Binary files differ
diff --git a/kolourpaint/pics/cr48-action-tool_rounded_rectangle.png b/kolourpaint/pics/cr48-action-tool_rounded_rectangle.png
new file mode 100644
index 00000000..91b8a185
--- /dev/null
+++ b/kolourpaint/pics/cr48-action-tool_rounded_rectangle.png
Binary files differ
diff --git a/kolourpaint/pics/cr48-action-tool_spraycan.png b/kolourpaint/pics/cr48-action-tool_spraycan.png
new file mode 100644
index 00000000..cb653e54
--- /dev/null
+++ b/kolourpaint/pics/cr48-action-tool_spraycan.png
Binary files differ
diff --git a/kolourpaint/pics/cr48-action-tool_text.png b/kolourpaint/pics/cr48-action-tool_text.png
new file mode 100644
index 00000000..1d007c02
--- /dev/null
+++ b/kolourpaint/pics/cr48-action-tool_text.png
Binary files differ
diff --git a/kolourpaint/pics/crsc-action-tool_brush.svgz b/kolourpaint/pics/crsc-action-tool_brush.svgz
new file mode 100644
index 00000000..5559a91b
--- /dev/null
+++ b/kolourpaint/pics/crsc-action-tool_brush.svgz
Binary files differ
diff --git a/kolourpaint/pics/crsc-action-tool_color_picker.svgz b/kolourpaint/pics/crsc-action-tool_color_picker.svgz
new file mode 100644
index 00000000..810cfe6b
--- /dev/null
+++ b/kolourpaint/pics/crsc-action-tool_color_picker.svgz
Binary files differ
diff --git a/kolourpaint/pics/crsc-action-tool_color_washer.svgz b/kolourpaint/pics/crsc-action-tool_color_washer.svgz
new file mode 100644
index 00000000..00f72a44
--- /dev/null
+++ b/kolourpaint/pics/crsc-action-tool_color_washer.svgz
Binary files differ
diff --git a/kolourpaint/pics/crsc-action-tool_curve.svgz b/kolourpaint/pics/crsc-action-tool_curve.svgz
new file mode 100644
index 00000000..fa995555
--- /dev/null
+++ b/kolourpaint/pics/crsc-action-tool_curve.svgz
Binary files differ
diff --git a/kolourpaint/pics/crsc-action-tool_ellipse.svgz b/kolourpaint/pics/crsc-action-tool_ellipse.svgz
new file mode 100644
index 00000000..42ca1349
--- /dev/null
+++ b/kolourpaint/pics/crsc-action-tool_ellipse.svgz
Binary files differ
diff --git a/kolourpaint/pics/crsc-action-tool_elliptical_selection.svgz b/kolourpaint/pics/crsc-action-tool_elliptical_selection.svgz
new file mode 100644
index 00000000..6b7c23b2
--- /dev/null
+++ b/kolourpaint/pics/crsc-action-tool_elliptical_selection.svgz
Binary files differ
diff --git a/kolourpaint/pics/crsc-action-tool_eraser.svgz b/kolourpaint/pics/crsc-action-tool_eraser.svgz
new file mode 100644
index 00000000..1a0278cc
--- /dev/null
+++ b/kolourpaint/pics/crsc-action-tool_eraser.svgz
Binary files differ
diff --git a/kolourpaint/pics/crsc-action-tool_flood_fill.svgz b/kolourpaint/pics/crsc-action-tool_flood_fill.svgz
new file mode 100644
index 00000000..24725599
--- /dev/null
+++ b/kolourpaint/pics/crsc-action-tool_flood_fill.svgz
Binary files differ
diff --git a/kolourpaint/pics/crsc-action-tool_free_form_selection.svgz b/kolourpaint/pics/crsc-action-tool_free_form_selection.svgz
new file mode 100644
index 00000000..2f304923
--- /dev/null
+++ b/kolourpaint/pics/crsc-action-tool_free_form_selection.svgz
Binary files differ
diff --git a/kolourpaint/pics/crsc-action-tool_line.svgz b/kolourpaint/pics/crsc-action-tool_line.svgz
new file mode 100644
index 00000000..f2cb1822
--- /dev/null
+++ b/kolourpaint/pics/crsc-action-tool_line.svgz
Binary files differ
diff --git a/kolourpaint/pics/crsc-action-tool_pen.svgz b/kolourpaint/pics/crsc-action-tool_pen.svgz
new file mode 100644
index 00000000..da783fda
--- /dev/null
+++ b/kolourpaint/pics/crsc-action-tool_pen.svgz
Binary files differ
diff --git a/kolourpaint/pics/crsc-action-tool_polygon.svgz b/kolourpaint/pics/crsc-action-tool_polygon.svgz
new file mode 100644
index 00000000..2e8e9066
--- /dev/null
+++ b/kolourpaint/pics/crsc-action-tool_polygon.svgz
Binary files differ
diff --git a/kolourpaint/pics/crsc-action-tool_polyline.svgz b/kolourpaint/pics/crsc-action-tool_polyline.svgz
new file mode 100644
index 00000000..f5f2e881
--- /dev/null
+++ b/kolourpaint/pics/crsc-action-tool_polyline.svgz
Binary files differ
diff --git a/kolourpaint/pics/crsc-action-tool_rect_selection.svgz b/kolourpaint/pics/crsc-action-tool_rect_selection.svgz
new file mode 100644
index 00000000..ac7ae6cf
--- /dev/null
+++ b/kolourpaint/pics/crsc-action-tool_rect_selection.svgz
Binary files differ
diff --git a/kolourpaint/pics/crsc-action-tool_rectangle.svgz b/kolourpaint/pics/crsc-action-tool_rectangle.svgz
new file mode 100644
index 00000000..c12ebf7c
--- /dev/null
+++ b/kolourpaint/pics/crsc-action-tool_rectangle.svgz
Binary files differ
diff --git a/kolourpaint/pics/crsc-action-tool_rounded_rectangle.svgz b/kolourpaint/pics/crsc-action-tool_rounded_rectangle.svgz
new file mode 100644
index 00000000..37625f3f
--- /dev/null
+++ b/kolourpaint/pics/crsc-action-tool_rounded_rectangle.svgz
Binary files differ
diff --git a/kolourpaint/pics/crsc-action-tool_spraycan.svgz b/kolourpaint/pics/crsc-action-tool_spraycan.svgz
new file mode 100644
index 00000000..6095c388
--- /dev/null
+++ b/kolourpaint/pics/crsc-action-tool_spraycan.svgz
Binary files differ
diff --git a/kolourpaint/pics/crsc-action-tool_text.svgz b/kolourpaint/pics/crsc-action-tool_text.svgz
new file mode 100644
index 00000000..c6be2b8f
--- /dev/null
+++ b/kolourpaint/pics/crsc-action-tool_text.svgz
Binary files differ
diff --git a/kolourpaint/pics/custom/Makefile.am b/kolourpaint/pics/custom/Makefile.am
new file mode 100644
index 00000000..e796e21a
--- /dev/null
+++ b/kolourpaint/pics/custom/Makefile.am
@@ -0,0 +1,10 @@
+customicondir = $(kde_datadir)/kolourpaint/pics
+customicon_DATA = tool_spraycan_9x9.png tool_spraycan_17x17.png tool_spraycan_29x29.png \
+ color_transparent_26x26.png colorbutton_swap_16x16.png \
+ option_opaque.png option_transparent.png \
+ resize.png scale.png smooth_scale.png \
+ image_skew_horizontal.png image_skew_vertical.png \
+ image_rotate_anticlockwise.png image_rotate_clockwise.png
+
+EXTRA_DIST = $(customicon_DATA)
+
diff --git a/kolourpaint/pics/custom/color_transparent_26x26.png b/kolourpaint/pics/custom/color_transparent_26x26.png
new file mode 100644
index 00000000..3ba3d39e
--- /dev/null
+++ b/kolourpaint/pics/custom/color_transparent_26x26.png
Binary files differ
diff --git a/kolourpaint/pics/custom/colorbutton_swap_16x16.png b/kolourpaint/pics/custom/colorbutton_swap_16x16.png
new file mode 100644
index 00000000..cebe9ed5
--- /dev/null
+++ b/kolourpaint/pics/custom/colorbutton_swap_16x16.png
Binary files differ
diff --git a/kolourpaint/pics/custom/image_rotate_anticlockwise.png b/kolourpaint/pics/custom/image_rotate_anticlockwise.png
new file mode 100644
index 00000000..8ef21bf2
--- /dev/null
+++ b/kolourpaint/pics/custom/image_rotate_anticlockwise.png
Binary files differ
diff --git a/kolourpaint/pics/custom/image_rotate_clockwise.png b/kolourpaint/pics/custom/image_rotate_clockwise.png
new file mode 100644
index 00000000..dee00f4a
--- /dev/null
+++ b/kolourpaint/pics/custom/image_rotate_clockwise.png
Binary files differ
diff --git a/kolourpaint/pics/custom/image_skew_horizontal.png b/kolourpaint/pics/custom/image_skew_horizontal.png
new file mode 100644
index 00000000..c27c8223
--- /dev/null
+++ b/kolourpaint/pics/custom/image_skew_horizontal.png
Binary files differ
diff --git a/kolourpaint/pics/custom/image_skew_vertical.png b/kolourpaint/pics/custom/image_skew_vertical.png
new file mode 100644
index 00000000..e84ac257
--- /dev/null
+++ b/kolourpaint/pics/custom/image_skew_vertical.png
Binary files differ
diff --git a/kolourpaint/pics/custom/option_opaque.png b/kolourpaint/pics/custom/option_opaque.png
new file mode 100644
index 00000000..ab442ecb
--- /dev/null
+++ b/kolourpaint/pics/custom/option_opaque.png
Binary files differ
diff --git a/kolourpaint/pics/custom/option_transparent.png b/kolourpaint/pics/custom/option_transparent.png
new file mode 100644
index 00000000..e751d7e9
--- /dev/null
+++ b/kolourpaint/pics/custom/option_transparent.png
Binary files differ
diff --git a/kolourpaint/pics/custom/resize.png b/kolourpaint/pics/custom/resize.png
new file mode 100644
index 00000000..0046cbcf
--- /dev/null
+++ b/kolourpaint/pics/custom/resize.png
Binary files differ
diff --git a/kolourpaint/pics/custom/scale.png b/kolourpaint/pics/custom/scale.png
new file mode 100644
index 00000000..9f0904dd
--- /dev/null
+++ b/kolourpaint/pics/custom/scale.png
Binary files differ
diff --git a/kolourpaint/pics/custom/smooth_scale.png b/kolourpaint/pics/custom/smooth_scale.png
new file mode 100644
index 00000000..5c48a6e2
--- /dev/null
+++ b/kolourpaint/pics/custom/smooth_scale.png
Binary files differ
diff --git a/kolourpaint/pics/custom/tool_spraycan_17x17.png b/kolourpaint/pics/custom/tool_spraycan_17x17.png
new file mode 100644
index 00000000..c5d228b0
--- /dev/null
+++ b/kolourpaint/pics/custom/tool_spraycan_17x17.png
Binary files differ
diff --git a/kolourpaint/pics/custom/tool_spraycan_29x29.png b/kolourpaint/pics/custom/tool_spraycan_29x29.png
new file mode 100644
index 00000000..47cfce16
--- /dev/null
+++ b/kolourpaint/pics/custom/tool_spraycan_29x29.png
Binary files differ
diff --git a/kolourpaint/pics/custom/tool_spraycan_9x9.png b/kolourpaint/pics/custom/tool_spraycan_9x9.png
new file mode 100644
index 00000000..85dde5a8
--- /dev/null
+++ b/kolourpaint/pics/custom/tool_spraycan_9x9.png
Binary files differ
diff --git a/kolourpaint/pics/hi16-app-kolourpaint.png b/kolourpaint/pics/hi16-app-kolourpaint.png
new file mode 100644
index 00000000..7802218f
--- /dev/null
+++ b/kolourpaint/pics/hi16-app-kolourpaint.png
Binary files differ
diff --git a/kolourpaint/pics/hi22-app-kolourpaint.png b/kolourpaint/pics/hi22-app-kolourpaint.png
new file mode 100644
index 00000000..9f411e5c
--- /dev/null
+++ b/kolourpaint/pics/hi22-app-kolourpaint.png
Binary files differ
diff --git a/kolourpaint/pics/hi32-app-kolourpaint.png b/kolourpaint/pics/hi32-app-kolourpaint.png
new file mode 100644
index 00000000..33e3e6f2
--- /dev/null
+++ b/kolourpaint/pics/hi32-app-kolourpaint.png
Binary files differ
diff --git a/kolourpaint/pics/hi48-app-kolourpaint.png b/kolourpaint/pics/hi48-app-kolourpaint.png
new file mode 100644
index 00000000..6878b110
--- /dev/null
+++ b/kolourpaint/pics/hi48-app-kolourpaint.png
Binary files differ
diff --git a/kolourpaint/pics/hisc-app-kolourpaint.svgz b/kolourpaint/pics/hisc-app-kolourpaint.svgz
new file mode 100644
index 00000000..9823cf97
--- /dev/null
+++ b/kolourpaint/pics/hisc-app-kolourpaint.svgz
Binary files differ
diff --git a/kolourpaint/pixmapfx/Makefile.am b/kolourpaint/pixmapfx/Makefile.am
new file mode 100644
index 00000000..dfa1d697
--- /dev/null
+++ b/kolourpaint/pixmapfx/Makefile.am
@@ -0,0 +1,19 @@
+INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../cursors -I$(srcdir)/../interfaces \
+ -I$(srcdir)/../pixmapfx \
+ -I$(srcdir)/../tools \
+ -I$(srcdir)/../views \
+ -I$(srcdir)/../widgets $(all_includes)
+
+noinst_LTLIBRARIES = libkolourpaintpixmapfx.la
+libkolourpaintpixmapfx_la_SOURCES = kpcoloreffect.cpp \
+ kpeffectbalance.cpp \
+ kpeffectblursharpen.cpp \
+ kpeffectemboss.cpp \
+ kpeffectflatten.cpp \
+ kpeffectinvert.cpp \
+ kpeffectreducecolors.cpp \
+ kpeffectsdialog.cpp \
+ kpfloodfill.cpp \
+ kppixmapfx.cpp
+
+METASOURCES = AUTO
diff --git a/kolourpaint/pixmapfx/kpcoloreffect.cpp b/kolourpaint/pixmapfx/kpcoloreffect.cpp
new file mode 100644
index 00000000..1660c1fa
--- /dev/null
+++ b/kolourpaint/pixmapfx/kpcoloreffect.cpp
@@ -0,0 +1,168 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <kpcoloreffect.h>
+
+#include <qapplication.h>
+#include <qpixmap.h>
+
+#include <kdialog.h>
+#include <klocale.h>
+
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kpselection.h>
+
+
+kpColorEffectCommand::kpColorEffectCommand (const QString &name,
+ bool actOnSelection,
+ kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ m_name (name),
+ m_actOnSelection (actOnSelection),
+ m_oldPixmapPtr (0)
+{
+}
+
+kpColorEffectCommand::~kpColorEffectCommand ()
+{
+ delete m_oldPixmapPtr; m_oldPixmapPtr = 0;
+}
+
+
+// public virtual [base kpCommand]
+QString kpColorEffectCommand::name () const
+{
+ if (m_actOnSelection)
+ return i18n ("Selection: %1").arg (m_name);
+ else
+ return m_name;
+}
+
+
+// public virtual [base kpCommand]
+int kpColorEffectCommand::size () const
+{
+ return kpPixmapFX::pixmapSize (m_oldPixmapPtr);
+}
+
+
+// public virtual [base kpCommand]
+void kpColorEffectCommand::execute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+
+ const QPixmap oldPixmap = *doc->pixmap (m_actOnSelection);
+
+ if (!isInvertible ())
+ {
+ m_oldPixmapPtr = new QPixmap ();
+ *m_oldPixmapPtr = oldPixmap;
+ }
+
+
+ QPixmap newPixmap = /*pure virtual*/applyColorEffect (oldPixmap);
+
+ doc->setPixmap (m_actOnSelection, newPixmap);
+
+
+ QApplication::restoreOverrideCursor ();
+}
+
+// public virtual [base kpCommand]
+void kpColorEffectCommand::unexecute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+
+ QPixmap newPixmap;
+
+ if (!isInvertible ())
+ {
+ newPixmap = *m_oldPixmapPtr;
+ }
+ else
+ {
+ newPixmap = /*pure virtual*/applyColorEffect (*doc->pixmap (m_actOnSelection));
+ }
+
+ doc->setPixmap (m_actOnSelection, newPixmap);
+
+
+ delete m_oldPixmapPtr; m_oldPixmapPtr = 0;
+
+
+ QApplication::restoreOverrideCursor ();
+}
+
+
+kpColorEffectWidget::kpColorEffectWidget (bool actOnSelection,
+ kpMainWindow *mainWindow,
+ QWidget *parent, const char *name)
+ : QWidget (parent, name),
+ m_actOnSelection (actOnSelection),
+ m_mainWindow (mainWindow)
+{
+}
+
+kpColorEffectWidget::~kpColorEffectWidget ()
+{
+}
+
+
+// public
+QString kpColorEffectWidget::caption () const
+{
+ return QString::null;
+}
+
+
+// protected
+int kpColorEffectWidget::marginHint () const
+{
+ return 0;
+}
+
+// protected
+int kpColorEffectWidget::spacingHint () const
+{
+ return KDialog::spacingHint ();
+}
+
+
+#include <kpcoloreffect.moc>
diff --git a/kolourpaint/pixmapfx/kpcoloreffect.h b/kolourpaint/pixmapfx/kpcoloreffect.h
new file mode 100644
index 00000000..8b3dfd09
--- /dev/null
+++ b/kolourpaint/pixmapfx/kpcoloreffect.h
@@ -0,0 +1,111 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef KP_COLOR_EFFECT_H
+#define KP_COLOR_EFFECT_H
+
+#include <qstring.h>
+#include <qwidget.h>
+
+#include <kpcommandhistory.h>
+
+class QPixmap;
+
+class kpDocument;
+class kpMainWindow;
+
+
+class kpColorEffectCommand : public kpCommand
+{
+public:
+ kpColorEffectCommand (const QString &name,
+ bool actOnSelection,
+ kpMainWindow *mainWindow);
+ virtual ~kpColorEffectCommand ();
+
+ virtual QString name () const;
+ virtual int size () const;
+
+public:
+ virtual void execute ();
+ virtual void unexecute ();
+
+public:
+ // Return true if applyColorEffect(applyColorEffect(pixmap)) == pixmap
+ // to avoid storing the old pixmap, saving memory.
+ virtual bool isInvertible () const { return false; }
+
+protected:
+ virtual QPixmap applyColorEffect (const QPixmap &pixmap) = 0;
+
+private:
+ QString m_name;
+ bool m_actOnSelection;
+
+ QPixmap *m_oldPixmapPtr;
+};
+
+
+class kpColorEffectWidget : public QWidget
+{
+Q_OBJECT
+
+public:
+ kpColorEffectWidget (bool actOnSelection,
+ kpMainWindow *mainWindow,
+ QWidget *parent, const char *name = 0);
+ virtual ~kpColorEffectWidget ();
+
+signals:
+ void settingsChangedNoWaitCursor ();
+
+ void settingsChanged ();
+
+ // (same as settingsChanged() but preview doesn't update until there
+ // has been no activity for a while - used for sliders in slow effects)
+ void settingsChangedDelayed ();
+
+public:
+ virtual QString caption () const;
+
+ virtual bool isNoOp () const = 0;
+ virtual QPixmap applyColorEffect (const QPixmap &pixmap) = 0;
+
+ virtual kpColorEffectCommand *createCommand () const = 0;
+
+protected:
+ int marginHint () const;
+ int spacingHint () const;
+
+protected:
+ bool m_actOnSelection;
+ kpMainWindow *m_mainWindow;
+};
+
+
+#endif // KP_COLOR_EFFECT_H
diff --git a/kolourpaint/pixmapfx/kpeffectbalance.cpp b/kolourpaint/pixmapfx/kpeffectbalance.cpp
new file mode 100644
index 00000000..f4494d29
--- /dev/null
+++ b/kolourpaint/pixmapfx/kpeffectbalance.cpp
@@ -0,0 +1,517 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_EFFECT_BALANCE 0
+
+
+#include <kpeffectbalance.h>
+
+#include <math.h>
+
+#include <qfontmetrics.h>
+#include <qimage.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpixmap.h>
+#include <qpushbutton.h>
+
+#include <kcombobox.h>
+#include <kdebug.h>
+#include <kimageeffect.h>
+#include <klocale.h>
+#include <knuminput.h>
+
+#include <kppixmapfx.h>
+
+
+#if DEBUG_KP_EFFECT_BALANCE
+ #include <qdatetime.h>
+#endif
+
+
+kpEffectBalanceCommand::kpEffectBalanceCommand (int channels,
+ int brightness, int contrast, int gamma,
+ bool actOnSelection,
+ kpMainWindow *mainWindow)
+ : kpColorEffectCommand (i18n ("Balance"), actOnSelection, mainWindow),
+ m_channels (channels),
+ m_brightness (brightness), m_contrast (contrast), m_gamma (gamma)
+{
+}
+
+kpEffectBalanceCommand::~kpEffectBalanceCommand ()
+{
+}
+
+
+static inline int between0And255 (int val)
+{
+ if (val < 0)
+ return 0;
+ else if (val > 255)
+ return 255;
+ else
+ return val;
+}
+
+
+static inline int brightness (int base, int strength)
+{
+ return between0And255 (base + strength * 255 / 50);
+}
+
+static inline int contrast (int base, int strength)
+{
+ return between0And255 ((base - 127) * (strength + 50) / 50 + 127);
+}
+
+static inline int gamma (int base, int strength)
+{
+ return between0And255 (qRound (255.0 * pow (base / 255.0, 1.0 / pow (10, strength / 50.0))));
+}
+
+
+static inline int brightnessContrastGamma (int base,
+ int newBrightness,
+ int newContrast,
+ int newGamma)
+{
+ return gamma (contrast (brightness (base, newBrightness),
+ newContrast),
+ newGamma);
+}
+
+static inline QRgb brightnessContrastGammaForRGB (QRgb rgb,
+ int channels,
+ int brightness, int contrast, int gamma)
+{
+ int red = qRed (rgb);
+ int green = qGreen (rgb);
+ int blue = qBlue (rgb);
+
+
+ if (channels & kpEffectBalanceCommand::Red)
+ red = brightnessContrastGamma (red, brightness, contrast, gamma);
+ if (channels & kpEffectBalanceCommand::Green)
+ green = brightnessContrastGamma (green, brightness, contrast, gamma);
+ if (channels & kpEffectBalanceCommand::Blue)
+ blue = brightnessContrastGamma (blue, brightness, contrast, gamma);
+
+
+ return qRgba (red, green, blue, qAlpha (rgb));
+}
+
+
+// public static
+QPixmap kpEffectBalanceCommand::applyColorEffect (const QPixmap &pixmap,
+ int channels,
+ int brightness, int contrast, int gamma)
+{
+#if DEBUG_KP_EFFECT_BALANCE
+ kdDebug () << "kpEffectBalanceCommand::applyColorEffect("
+ << "channels=" << channels
+ << ",brightness=" << brightness
+ << ",contrast=" << contrast
+ << ",gamma=" << gamma
+ << ")" << endl;
+ QTime timer; timer.start ();
+#endif
+
+ QImage image = kpPixmapFX::convertToImage (pixmap);
+#if DEBUG_KP_EFFECT_BALANCE
+ kdDebug () << "\tconvertToImage=" << timer.restart () << endl;
+#endif
+
+
+ Q_UINT8 transformRed [256],
+ transformGreen [256],
+ transformBlue [256];
+
+ for (int i = 0; i < 256; i++)
+ {
+ Q_UINT8 applied = (Q_UINT8) brightnessContrastGamma (i, brightness, contrast, gamma);
+
+ if (channels & kpEffectBalanceCommand::Red)
+ transformRed [i] = applied;
+ else
+ transformRed [i] = i;
+
+ if (channels & kpEffectBalanceCommand::Green)
+ transformGreen [i] = applied;
+ else
+ transformGreen [i] = i;
+
+ if (channels & kpEffectBalanceCommand::Blue)
+ transformBlue [i] = applied;
+ else
+ transformBlue [i] = i;
+ }
+
+#if DEBUG_KP_EFFECT_BALANCE
+ kdDebug () << "\tbuild lookup=" << timer.restart () << endl;
+#endif
+
+
+ if (image.depth () > 8)
+ {
+ for (int y = 0; y < image.height (); y++)
+ {
+ for (int x = 0; x < image.width (); x++)
+ {
+ const QRgb rgb = image.pixel (x, y);
+
+ const Q_UINT8 red = (Q_UINT8) qRed (rgb);
+ const Q_UINT8 green = (Q_UINT8) qGreen (rgb);
+ const Q_UINT8 blue = (Q_UINT8) qBlue (rgb);
+ const Q_UINT8 alpha = (Q_UINT8) qAlpha (rgb);
+
+ image.setPixel (x, y,
+ qRgba (transformRed [red],
+ transformGreen [green],
+ transformBlue [blue],
+ alpha));
+
+ #if 0
+ image.setPixel (x, y,
+ brightnessContrastGammaForRGB (image.pixel (x, y),
+ channels,
+ brightness, contrast, gamma));
+ #endif
+ }
+ }
+ }
+ else
+ {
+ for (int i = 0; i < image.numColors (); i++)
+ {
+ const QRgb rgb = image.color (i);
+
+ const Q_UINT8 red = (Q_UINT8) qRed (rgb);
+ const Q_UINT8 green = (Q_UINT8) qGreen (rgb);
+ const Q_UINT8 blue = (Q_UINT8) qBlue (rgb);
+ const Q_UINT8 alpha = (Q_UINT8) qAlpha (rgb);
+
+ image.setColor (i,
+ qRgba (transformRed [red],
+ transformGreen [green],
+ transformBlue [blue],
+ alpha));
+
+ #if 0
+ image.setColor (i,
+ brightnessContrastGammaForRGB (image.color (i),
+ channels,
+ brightness, contrast, gamma));
+ #endif
+ }
+
+ }
+#if DEBUG_KP_EFFECT_BALANCE
+ kdDebug () << "\teffect=" << timer.restart () << endl;
+#endif
+
+ const QPixmap retPixmap = kpPixmapFX::convertToPixmap (image);
+#if DEBUG_KP_EFFECT_BALANCE
+ kdDebug () << "\tconvertToPixmap=" << timer.restart () << endl;
+#endif
+
+ return retPixmap;
+}
+
+// protected virtual [base kpColorEffectCommand]
+QPixmap kpEffectBalanceCommand::applyColorEffect (const QPixmap &pixmap)
+{
+ return applyColorEffect (pixmap, m_channels,
+ m_brightness, m_contrast, m_gamma);
+}
+
+
+
+kpEffectBalanceWidget::kpEffectBalanceWidget (bool actOnSelection,
+ kpMainWindow *mainWindow,
+ QWidget *parent, const char *name)
+ : kpColorEffectWidget (actOnSelection, mainWindow, parent, name)
+{
+ QGridLayout *lay = new QGridLayout (this, 5, 5, marginHint (), spacingHint ());
+
+
+ QLabel *brightnessLabel = new QLabel (i18n ("&Brightness:"), this);
+ m_brightnessInput = new KIntNumInput (0/*value*/, this);
+ m_brightnessInput->setRange (-50, 50, 1/*step*/, true/*slider*/);
+ QPushButton *brightnessResetPushButton = new QPushButton (i18n ("Re&set"), this);
+
+ QLabel *contrastLabel = new QLabel (i18n ("Co&ntrast:"), this);
+ m_contrastInput = new KIntNumInput (0/*value*/, this);
+ m_contrastInput->setRange (-50, 50, 1/*step*/, true/*slider*/);
+ QPushButton *contrastResetPushButton = new QPushButton (i18n ("&Reset"), this);
+
+ QLabel *gammaLabel = new QLabel (i18n ("&Gamma:"), this);
+ m_gammaInput = new KIntNumInput (0/*value*/, this);
+ m_gammaInput->setRange (-50, 50, 1/*step*/, true/*slider*/);
+ // TODO: This is what should be shown in the m_gammaInput spinbox
+ m_gammaLabel = new QLabel (this);
+ // TODO: This doesn't seem to be wide enough with some fonts so the
+ // whole layout moves when we drag the gamma slider.
+ m_gammaLabel->setMinimumWidth (m_gammaLabel->fontMetrics ().width (" 10.00 "));
+ m_gammaLabel->setAlignment (m_gammaLabel->alignment () | Qt::AlignRight);
+ QPushButton *gammaResetPushButton = new QPushButton (i18n ("Rese&t"), this);
+
+
+ QWidget *spaceWidget = new QLabel (this);
+ spaceWidget->setFixedSize (1, spacingHint ());
+
+
+ QLabel *channelLabel = new QLabel (i18n ("C&hannels:"), this);
+ m_channelsComboBox = new KComboBox (this);
+ m_channelsComboBox->insertItem (i18n ("All"));
+ m_channelsComboBox->insertItem (i18n ("Red"));
+ m_channelsComboBox->insertItem (i18n ("Green"));
+ m_channelsComboBox->insertItem (i18n ("Blue"));
+
+
+ QPushButton *resetPushButton = new QPushButton (i18n ("Reset &All Values"), this);
+
+
+ brightnessLabel->setBuddy (m_brightnessInput);
+ contrastLabel->setBuddy (m_contrastInput);
+ gammaLabel->setBuddy (m_gammaInput);
+
+ channelLabel->setBuddy (m_channelsComboBox);
+
+
+ lay->addWidget (brightnessLabel, 0, 0);
+ lay->addMultiCellWidget (m_brightnessInput, 0, 0, 1, 2);
+ lay->addWidget (brightnessResetPushButton, 0, 4);
+
+ lay->addWidget (contrastLabel, 1, 0);
+ lay->addMultiCellWidget (m_contrastInput, 1, 1, 1, 2);
+ lay->addWidget (contrastResetPushButton, 1, 4);
+
+ lay->addWidget (gammaLabel, 2, 0);
+ lay->addMultiCellWidget (m_gammaInput, 2, 2, 1, 2);
+ lay->addWidget (m_gammaLabel, 2, 3);
+ lay->addWidget (gammaResetPushButton, 2, 4);
+
+ lay->addMultiCellWidget (spaceWidget, 3, 3, 0, 4);
+ lay->addMultiCellWidget (resetPushButton, 4, 4, 2, 4, Qt::AlignRight);
+
+ lay->addWidget (channelLabel, 4, 0);
+ lay->addWidget (m_channelsComboBox, 4, 1, Qt::AlignLeft);
+ //lay->addWidget (resetPushButton, 4, 2, Qt::AlignRight);
+
+ lay->setColStretch (1, 1);
+
+
+ // (no need for settingsChangedDelayed() since BCG effect is so fast :))
+ connect (m_brightnessInput, SIGNAL (valueChanged (int)),
+ this, SIGNAL (settingsChangedNoWaitCursor ()));
+ connect (m_contrastInput, SIGNAL (valueChanged (int)),
+ this, SIGNAL (settingsChangedNoWaitCursor ()));
+
+ connect (m_gammaInput, SIGNAL (valueChanged (int)),
+ this, SLOT (recalculateGammaLabel ()));
+ connect (m_gammaInput, SIGNAL (valueChanged (int)),
+ this, SIGNAL (settingsChangedNoWaitCursor ()));
+
+ connect (m_channelsComboBox, SIGNAL (activated (int)),
+ this, SIGNAL (settingsChanged ()));
+
+ connect (brightnessResetPushButton, SIGNAL (clicked ()),
+ this, SLOT (resetBrightness ()));
+ connect (contrastResetPushButton, SIGNAL (clicked ()),
+ this, SLOT (resetContrast ()));
+ connect (gammaResetPushButton, SIGNAL (clicked ()),
+ this, SLOT (resetGamma ()));
+
+ connect (resetPushButton, SIGNAL (clicked ()),
+ this, SLOT (resetAll ()));
+
+
+ recalculateGammaLabel ();
+}
+
+kpEffectBalanceWidget::~kpEffectBalanceWidget ()
+{
+}
+
+
+// public virtual [base kpColorEffectWidget]
+QString kpEffectBalanceWidget::caption () const
+{
+ return i18n ("Settings");
+}
+
+
+// public virtual [base kpColorEffectWidget]
+bool kpEffectBalanceWidget::isNoOp () const
+{
+ return (brightness () == 0 && contrast () == 0 && gamma () == 0);
+}
+
+// public virtual [base kpColorEffectWidget]
+QPixmap kpEffectBalanceWidget::applyColorEffect (const QPixmap &pixmap)
+{
+ return kpEffectBalanceCommand::applyColorEffect (pixmap,
+ channels (), brightness (), contrast (), gamma ());
+}
+
+// public virtual [base kpColorEffectWidget]
+kpColorEffectCommand *kpEffectBalanceWidget::createCommand () const
+{
+ return new kpEffectBalanceCommand (channels (),
+ brightness (), contrast (), gamma (),
+ m_actOnSelection,
+ m_mainWindow);
+}
+
+
+// protected
+int kpEffectBalanceWidget::channels () const
+{
+ switch (m_channelsComboBox->currentItem ())
+ {
+ default:
+ case 0:
+ return kpEffectBalanceCommand::RGB;
+
+ case 1:
+ return kpEffectBalanceCommand::Red;
+
+ case 2:
+ return kpEffectBalanceCommand::Green;
+
+ case 3:
+ return kpEffectBalanceCommand::Blue;
+ }
+}
+
+
+// protected
+int kpEffectBalanceWidget::brightness () const
+{
+ return m_brightnessInput->value ();
+}
+
+// protected
+int kpEffectBalanceWidget::contrast () const
+{
+ return m_contrastInput->value ();
+}
+
+// protected
+int kpEffectBalanceWidget::gamma () const
+{
+ return m_gammaInput->value ();
+}
+
+
+// protected slot
+void kpEffectBalanceWidget::recalculateGammaLabel ()
+{
+ m_gammaLabel->setText (
+ " " +
+ QString::number (pow (10, gamma () / 50.0),
+ 'f'/*[-]9.9*/,
+ 2/*precision*/) +
+ " ");
+ m_gammaLabel->repaint ();
+}
+
+
+// protected slot
+void kpEffectBalanceWidget::resetBrightness ()
+{
+ if (brightness () == 0)
+ return;
+
+ bool sb = signalsBlocked ();
+
+ if (!sb) blockSignals (true);
+ m_brightnessInput->setValue (0);
+ if (!sb) blockSignals (false);
+
+ // Immediate update (if signals aren't blocked)
+ emit settingsChanged ();
+}
+
+// protected slot
+void kpEffectBalanceWidget::resetContrast ()
+{
+ if (contrast () == 0)
+ return;
+
+ bool sb = signalsBlocked ();
+
+ if (!sb) blockSignals (true);
+ m_contrastInput->setValue (0);
+ if (!sb) blockSignals (false);
+
+ // Immediate update (if signals aren't blocked)
+ emit settingsChanged ();
+}
+
+// protected slot
+void kpEffectBalanceWidget::resetGamma ()
+{
+ if (gamma () == 0)
+ return;
+
+ bool sb = signalsBlocked ();
+
+ if (!sb) blockSignals (true);
+ m_gammaInput->setValue (0);
+ recalculateGammaLabel ();
+ if (!sb) blockSignals (false);
+
+ // Immediate update (if signals aren't blocked)
+ emit settingsChanged ();
+}
+
+
+// protected slot
+void kpEffectBalanceWidget::resetAll ()
+{
+ if (isNoOp ())
+ return;
+
+ // Prevent multiple settingsChanged() which would normally result in
+ // redundant, expensive preview repaints
+ blockSignals (true);
+
+ resetBrightness ();
+ resetContrast ();
+ resetGamma ();
+
+ recalculateGammaLabel ();
+
+ blockSignals (false);
+
+ emit settingsChanged ();
+}
+
+
+#include <kpeffectbalance.moc>
diff --git a/kolourpaint/pixmapfx/kpeffectbalance.h b/kolourpaint/pixmapfx/kpeffectbalance.h
new file mode 100644
index 00000000..b045159f
--- /dev/null
+++ b/kolourpaint/pixmapfx/kpeffectbalance.h
@@ -0,0 +1,116 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef KP_EFFECT_BALANCE_H
+#define KP_EFFECT_BALANCE_H
+
+#include <kpcoloreffect.h>
+
+
+class QLabel;
+
+class KComboBox;
+class KIntNumInput;
+
+class kpMainWindowe;
+
+
+class kpEffectBalanceCommand : public kpColorEffectCommand
+{
+public:
+ enum Channel
+ {
+ None = 0,
+ Red = 1, Green = 2, Blue = 4,
+ RGB = Red | Green | Blue
+ };
+
+ // <brightness>, <contrast> & <gamma> are from -50 to 50
+
+ kpEffectBalanceCommand (int channels,
+ int brightness, int contrast, int gamma,
+ bool actOnSelection,
+ kpMainWindow *mainWindow);
+ virtual ~kpEffectBalanceCommand ();
+
+ static QPixmap applyColorEffect (const QPixmap &pixmap,
+ int channels,
+ int brightness, int contrast, int gamma);
+
+protected:
+ virtual QPixmap applyColorEffect (const QPixmap &pixmap);
+
+protected:
+ int m_channels;
+ int m_brightness, m_contrast, m_gamma;
+};
+
+
+class kpEffectBalanceWidget : public kpColorEffectWidget
+{
+Q_OBJECT
+
+public:
+ kpEffectBalanceWidget (bool actOnSelection,
+ kpMainWindow *mainWindow,
+ QWidget *parent, const char *name = 0);
+ virtual ~kpEffectBalanceWidget ();
+
+ virtual QString caption () const;
+
+ virtual bool isNoOp () const;
+ virtual QPixmap applyColorEffect (const QPixmap &pixmap);
+
+ virtual kpColorEffectCommand *createCommand () const;
+
+protected:
+ int channels () const;
+
+ int brightness () const;
+ int contrast () const;
+ int gamma () const;
+
+protected slots:
+ void recalculateGammaLabel ();
+
+ void resetBrightness ();
+ void resetContrast ();
+ void resetGamma ();
+
+ void resetAll ();
+
+protected:
+ KIntNumInput *m_brightnessInput,
+ *m_contrastInput,
+ *m_gammaInput;
+ QLabel *m_gammaLabel;
+ KComboBox *m_channelsComboBox;
+};
+
+
+#endif // KP_EFFECT_BALANCE_H
diff --git a/kolourpaint/pixmapfx/kpeffectblursharpen.cpp b/kolourpaint/pixmapfx/kpeffectblursharpen.cpp
new file mode 100644
index 00000000..50c0b27d
--- /dev/null
+++ b/kolourpaint/pixmapfx/kpeffectblursharpen.cpp
@@ -0,0 +1,291 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_EFFECT_BLUR_SHARPEN 0
+
+
+#include <kpeffectblursharpen.h>
+
+#include <qimage.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpixmap.h>
+#include <qpushbutton.h>
+
+#include <kdebug.h>
+#include <kimageeffect.h>
+#include <klocale.h>
+#include <knuminput.h>
+
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+
+
+static QString nameForType (kpEffectBlurSharpenCommand::Type type)
+{
+ if (type == kpEffectBlurSharpenCommand::Blur)
+ return i18n ("Soften");
+ else if (type == kpEffectBlurSharpenCommand::Sharpen)
+ return i18n ("Sharpen");
+ else
+ return QString::null;
+}
+
+
+kpEffectBlurSharpenCommand::kpEffectBlurSharpenCommand (Type type,
+ double radius, double sigma,
+ int repeat,
+ bool actOnSelection,
+ kpMainWindow *mainWindow)
+ : kpColorEffectCommand (::nameForType (type), actOnSelection, mainWindow),
+ m_type (type),
+ m_radius (radius), m_sigma (sigma),
+ m_repeat (repeat)
+{
+}
+
+kpEffectBlurSharpenCommand::~kpEffectBlurSharpenCommand ()
+{
+}
+
+
+// public static
+QPixmap kpEffectBlurSharpenCommand::apply (const QPixmap &pixmap,
+ Type type, double radius, double sigma,
+ int repeat)
+{
+#if DEBUG_KP_EFFECT_BLUR_SHARPEN
+ kdDebug () << "kpEffectBlurSharpenCommand::apply(type="
+ << int (type)
+ << " radius=" << radius
+ << " sigma=" << sigma
+ << " repeat=" << repeat
+ << ")"
+ << endl;
+#endif
+
+ // (KImageEffect::(blur|sharpen)() ignores mask)
+ QPixmap usePixmap = kpPixmapFX::pixmapWithDefinedTransparentPixels (
+ pixmap,
+ Qt::white/*arbitrarily chosen*/);
+
+
+ QImage image = kpPixmapFX::convertToImage (usePixmap);
+
+ for (int i = 0; i < repeat; i++)
+ {
+ if (type == Blur)
+ image = KImageEffect::blur (image, radius, sigma);
+ else if (type == Sharpen)
+ image = KImageEffect::sharpen (image, radius, sigma);
+ }
+
+ QPixmap retPixmap = kpPixmapFX::convertToPixmap (image);
+
+
+ // KImageEffect::(blur|sharpen)() nukes mask - restore it
+ if (usePixmap.mask ())
+ retPixmap.setMask (*usePixmap.mask ());
+
+
+ return retPixmap;
+}
+
+// protected virtual [base kpColorEffectCommand]
+QPixmap kpEffectBlurSharpenCommand::applyColorEffect (const QPixmap &pixmap)
+{
+ return apply (pixmap, m_type, m_radius, m_sigma, m_repeat);
+}
+
+
+
+kpEffectBlurSharpenWidget::kpEffectBlurSharpenWidget (bool actOnSelection,
+ kpMainWindow *mainWindow,
+ QWidget *parent, const char *name)
+ : kpColorEffectWidget (actOnSelection, mainWindow, parent, name)
+{
+ QGridLayout *lay = new QGridLayout (this, 4, 2, marginHint (), spacingHint ());
+
+
+ QLabel *amountLabel = new QLabel (i18n ("&Amount:"), this);
+ m_amountInput = new KIntNumInput (this);
+ m_amountInput->setRange (-10, 10, 1/*step*/, true/*slider*/);
+
+ m_typeLabel = new QLabel (this);
+
+
+ amountLabel->setBuddy (m_amountInput);
+
+
+ lay->addWidget (amountLabel, 0, 0);
+ lay->addWidget (m_amountInput, 0, 1);
+
+ lay->addMultiCellWidget (m_typeLabel, 1, 1, 0, 1, Qt::AlignCenter);
+
+ lay->setColStretch (1, 1);
+
+
+ connect (m_amountInput, SIGNAL (valueChanged (int)),
+ this, SIGNAL (settingsChangedDelayed ()));
+
+ connect (m_amountInput, SIGNAL (valueChanged (int)),
+ this, SLOT (slotUpdateTypeLabel ()));
+}
+
+kpEffectBlurSharpenWidget::~kpEffectBlurSharpenWidget ()
+{
+}
+
+
+// public virtual [base kpColorEffectWidget]
+QString kpEffectBlurSharpenWidget::caption () const
+{
+ return QString::null;
+}
+
+
+// public virtual [base kpColorEffectWidget]
+bool kpEffectBlurSharpenWidget::isNoOp () const
+{
+ return (type () == kpEffectBlurSharpenCommand::None);
+}
+
+// public virtual [base kpColorEffectWidget]
+QPixmap kpEffectBlurSharpenWidget::applyColorEffect (const QPixmap &pixmap)
+{
+ return kpEffectBlurSharpenCommand::apply (pixmap,
+ type (), radius (), sigma (), repeat ());
+}
+
+// public virtual [base kpColorEffectWidget]
+kpColorEffectCommand *kpEffectBlurSharpenWidget::createCommand () const
+{
+ return new kpEffectBlurSharpenCommand (type (), radius (), sigma (), repeat (),
+ m_actOnSelection,
+ m_mainWindow);
+}
+
+
+// protected slot
+void kpEffectBlurSharpenWidget::slotUpdateTypeLabel ()
+{
+ QString text = ::nameForType (type ());
+
+#if DEBUG_KP_EFFECT_BLUR_SHARPEN
+ kdDebug () << "kpEffectBlurSharpenWidget::slotUpdateTypeLabel() text="
+ << text << endl;
+#endif
+ m_typeLabel->setText (text);
+}
+
+
+// protected
+kpEffectBlurSharpenCommand::Type kpEffectBlurSharpenWidget::type () const
+{
+ if (m_amountInput->value () == 0)
+ return kpEffectBlurSharpenCommand::None;
+ else if (m_amountInput->value () < 0)
+ return kpEffectBlurSharpenCommand::Blur;
+ else
+ return kpEffectBlurSharpenCommand::Sharpen;
+}
+
+// The numbers that follow were picked by experimentation.
+// I still have no idea what "radius" and "sigma" mean
+// (even after reading the API).
+
+// protected
+double kpEffectBlurSharpenWidget::radius () const
+{
+ if (m_amountInput->value () == 0)
+ return 0;
+
+ if (m_amountInput->value () < 0)
+ {
+ return 8;
+ }
+ else
+ {
+ const double SharpenMin = .1;
+ const double SharpenMax = 2.5;
+
+ return SharpenMin +
+ (m_amountInput->value () - 1) *
+ (SharpenMax - SharpenMin) /
+ (m_amountInput->maxValue () - 1);
+ }
+}
+
+// protected
+double kpEffectBlurSharpenWidget::sigma () const
+{
+ if (m_amountInput->value () == 0)
+ return 0;
+
+ if (m_amountInput->value () < 0)
+ {
+ const double BlurMin = .5;
+ const double BlurMax = 4;
+
+ return BlurMin +
+ (-m_amountInput->value () - 1) *
+ (BlurMax - BlurMin) /
+ (-m_amountInput->minValue () - 1);
+ }
+ else
+ {
+ const double SharpenMin = .5;
+ const double SharpenMax = 3.0;
+
+ return SharpenMin +
+ (m_amountInput->value () - 1) *
+ (SharpenMax - SharpenMin) /
+ (m_amountInput->maxValue () - 1);
+ }
+}
+
+// protected
+int kpEffectBlurSharpenWidget::repeat () const
+{
+ if (m_amountInput->value () == 0)
+ return 0;
+
+ if (m_amountInput->value () < 0)
+ return 1;
+ else
+ {
+ const double SharpenMin = 1;
+ const double SharpenMax = 2;
+
+ return qRound (SharpenMin +
+ (m_amountInput->value () - 1) *
+ (SharpenMax - SharpenMin) /
+ (m_amountInput->maxValue () - 1));
+ }
+}
+
+#include <kpeffectblursharpen.moc>
diff --git a/kolourpaint/pixmapfx/kpeffectblursharpen.h b/kolourpaint/pixmapfx/kpeffectblursharpen.h
new file mode 100644
index 00000000..3b12def1
--- /dev/null
+++ b/kolourpaint/pixmapfx/kpeffectblursharpen.h
@@ -0,0 +1,105 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef KP_EFFECT_BLUR_SHARPEN_H
+#define KP_EFFECT_BLUR_SHARPEN_H
+
+
+#include <kpcolor.h>
+
+#include <kpcoloreffect.h>
+
+
+class QLabel;
+
+class KIntNumInput;
+
+class kpMainWindow;
+
+
+class kpEffectBlurSharpenCommand : public kpColorEffectCommand
+{
+public:
+ enum Type
+ {
+ None = 0, Blur, Sharpen
+ };
+
+ kpEffectBlurSharpenCommand (Type type,
+ double radius, double sigma,
+ int repeat,
+ bool actOnSelection,
+ kpMainWindow *mainWindow);
+ virtual ~kpEffectBlurSharpenCommand ();
+
+ static QPixmap apply (const QPixmap &pixmap,
+ Type type, double radius, double sigma,
+ int repeat);
+
+protected:
+ virtual QPixmap applyColorEffect (const QPixmap &pixmap);
+
+protected:
+ Type m_type;
+ double m_radius, m_sigma;
+ int m_repeat;
+};
+
+
+class kpEffectBlurSharpenWidget : public kpColorEffectWidget
+{
+Q_OBJECT
+
+public:
+ kpEffectBlurSharpenWidget (bool actOnSelection,
+ kpMainWindow *mainWindow,
+ QWidget *parent, const char *name = 0);
+ virtual ~kpEffectBlurSharpenWidget ();
+
+ virtual QString caption () const;
+
+ virtual bool isNoOp () const;
+ virtual QPixmap applyColorEffect (const QPixmap &pixmap);
+
+ virtual kpColorEffectCommand *createCommand () const;
+
+protected slots:
+ void slotUpdateTypeLabel ();
+
+protected:
+ kpEffectBlurSharpenCommand::Type type () const;
+ double radius () const;
+ double sigma () const;
+ int repeat () const;
+
+ KIntNumInput *m_amountInput;
+ QLabel *m_typeLabel;
+};
+
+
+#endif // KP_EFFECT_BLUR_SHARPEN_H
diff --git a/kolourpaint/pixmapfx/kpeffectemboss.cpp b/kolourpaint/pixmapfx/kpeffectemboss.cpp
new file mode 100644
index 00000000..e33f3a42
--- /dev/null
+++ b/kolourpaint/pixmapfx/kpeffectemboss.cpp
@@ -0,0 +1,228 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_EFFECT_EMBOSS 0
+
+
+#include <kpeffectemboss.h>
+
+#include <qcheckbox.h>
+#include <qimage.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpixmap.h>
+#include <qpushbutton.h>
+
+#include <kdebug.h>
+#include <kimageeffect.h>
+#include <klocale.h>
+#include <knuminput.h>
+
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+
+
+kpEffectEmbossCommand::kpEffectEmbossCommand (double radius, double sigma,
+ int repeat,
+ bool actOnSelection,
+ kpMainWindow *mainWindow)
+ : kpColorEffectCommand (i18n ("Emboss"), actOnSelection, mainWindow),
+ m_radius (radius), m_sigma (sigma),
+ m_repeat (repeat)
+{
+}
+
+kpEffectEmbossCommand::~kpEffectEmbossCommand ()
+{
+}
+
+
+// public static
+QPixmap kpEffectEmbossCommand::apply (const QPixmap &pixmap,
+ double radius, double sigma,
+ int repeat)
+{
+#if DEBUG_KP_EFFECT_EMBOSS
+ kdDebug () << "kpEffectEmbossCommand::apply()"
+ << " radius=" << radius
+ << " sigma=" << sigma
+ << " repeat=" << repeat
+ << ")"
+ << endl;
+#endif
+
+ // (KImageEffect::emboss() ignores mask)
+ QPixmap usePixmap = kpPixmapFX::pixmapWithDefinedTransparentPixels (
+ pixmap,
+ Qt::white/*arbitrarily chosen*/);
+
+
+ QImage image = kpPixmapFX::convertToImage (usePixmap);
+
+ for (int i = 0; i < repeat; i++)
+ {
+ image = KImageEffect::emboss (image, radius, sigma);
+ }
+
+ QPixmap retPixmap = kpPixmapFX::convertToPixmap (image);
+
+
+ // KImageEffect::emboss() nukes mask - restore it
+ if (usePixmap.mask ())
+ retPixmap.setMask (*usePixmap.mask ());
+
+
+ return retPixmap;
+}
+
+// protected virtual [base kpColorEffectCommand]
+QPixmap kpEffectEmbossCommand::applyColorEffect (const QPixmap &pixmap)
+{
+ return apply (pixmap, m_radius, m_sigma, m_repeat);
+}
+
+
+
+kpEffectEmbossWidget::kpEffectEmbossWidget (bool actOnSelection,
+ kpMainWindow *mainWindow,
+ QWidget *parent, const char *name)
+ : kpColorEffectWidget (actOnSelection, mainWindow, parent, name)
+{
+ QGridLayout *lay = new QGridLayout (this, 4, 2, marginHint (), spacingHint ());
+
+
+#if 0
+ QLabel *amountLabel = new QLabel (i18n ("&Amount:"), this);
+ m_amountInput = new KIntNumInput (this);
+ m_amountInput->setRange (0, 10, 1/*step*/, true/*slider*/);
+ m_amountInput->setSpecialValueText (i18n ("None"));
+
+
+ amountLabel->setBuddy (m_amountInput);
+
+
+ lay->addWidget (amountLabel, 0, 0);
+ lay->addWidget (m_amountInput, 0, 1);
+
+ lay->setColStretch (1, 1);
+
+
+ connect (m_amountInput, SIGNAL (valueChanged (int)),
+ this, SIGNAL (settingsChanged ()));
+#endif
+
+ m_enableCheckBox = new QCheckBox (i18n ("E&nable"), this);
+
+
+ lay->addMultiCellWidget (m_enableCheckBox, 0, 0, 0, 1, Qt::AlignCenter);
+
+
+ // (settingsChangedDelayed() instead of settingsChanged() so that the
+ // user can quickly press OK to apply effect to document directly and
+ // not have to wait for the also slow preview)
+ connect (m_enableCheckBox, SIGNAL (toggled (bool)),
+ this, SIGNAL (settingsChangedDelayed ()));
+}
+
+kpEffectEmbossWidget::~kpEffectEmbossWidget ()
+{
+}
+
+
+// public virtual [base kpColorEffectWidget]
+QString kpEffectEmbossWidget::caption () const
+{
+ return QString::null;
+}
+
+
+// public virtual [base kpColorEffectWidget]
+bool kpEffectEmbossWidget::isNoOp () const
+{
+ //return (m_amountInput->value () == 0);
+ return !m_enableCheckBox->isChecked ();
+}
+
+// public virtual [base kpColorEffectWidget]
+QPixmap kpEffectEmbossWidget::applyColorEffect (const QPixmap &pixmap)
+{
+ if (isNoOp ())
+ return pixmap;
+
+ return kpEffectEmbossCommand::apply (pixmap, radius (), sigma (), repeat ());
+}
+
+// public virtual [base kpColorEffectWidget]
+kpColorEffectCommand *kpEffectEmbossWidget::createCommand () const
+{
+ return new kpEffectEmbossCommand (radius (), sigma (), repeat (),
+ m_actOnSelection,
+ m_mainWindow);
+}
+
+
+// The numbers that follow were picked by experimentation.
+// I still have no idea what "radius" and "sigma" mean
+// (even after reading the API).
+
+// protected
+double kpEffectEmbossWidget::radius () const
+{
+ //if (m_amountInput->value () == 0)
+ // return 0;
+
+ return 0;
+}
+
+
+// protected
+double kpEffectEmbossWidget::sigma () const
+{
+#if 0
+ if (m_amountInput->value () == 0)
+ return 0;
+
+ const double Min = 1;
+ const double Max = 1.2;
+
+ return Min +
+ (m_amountInput->maxValue () - m_amountInput->value ()) *
+ (Max - Min) /
+ (m_amountInput->maxValue () - 1);
+#endif
+
+ return 1;
+}
+
+// protected
+int kpEffectEmbossWidget::repeat () const
+{
+ return 1;
+}
+
+
+#include <kpeffectemboss.moc>
diff --git a/kolourpaint/pixmapfx/kpeffectemboss.h b/kolourpaint/pixmapfx/kpeffectemboss.h
new file mode 100644
index 00000000..0234627f
--- /dev/null
+++ b/kolourpaint/pixmapfx/kpeffectemboss.h
@@ -0,0 +1,93 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef KP_EFFECT_EMBOSS_H
+#define KP_EFFECT_EMBOSS_H
+
+
+#include <kpcolor.h>
+
+#include <kpcoloreffect.h>
+
+
+class QCheckBox;
+class KIntNumInput;
+
+class kpMainWindow;
+
+
+class kpEffectEmbossCommand : public kpColorEffectCommand
+{
+public:
+ kpEffectEmbossCommand (double radius, double sigma,
+ int repeat,
+ bool actOnSelection,
+ kpMainWindow *mainWindow);
+ virtual ~kpEffectEmbossCommand ();
+
+ static QPixmap apply (const QPixmap &pixmap,
+ double radius, double sigma,
+ int repeat);
+
+protected:
+ virtual QPixmap applyColorEffect (const QPixmap &pixmap);
+
+protected:
+ double m_radius, m_sigma;
+ int m_repeat;
+};
+
+
+class kpEffectEmbossWidget : public kpColorEffectWidget
+{
+Q_OBJECT
+
+public:
+ kpEffectEmbossWidget (bool actOnSelection,
+ kpMainWindow *mainWindow,
+ QWidget *parent, const char *name = 0);
+ virtual ~kpEffectEmbossWidget ();
+
+ virtual QString caption () const;
+
+ virtual bool isNoOp () const;
+ virtual QPixmap applyColorEffect (const QPixmap &pixmap);
+
+ virtual kpColorEffectCommand *createCommand () const;
+
+protected:
+ double radius () const;
+ double sigma () const;
+ int repeat () const;
+
+ //KIntNumInput *m_amountInput;
+ QCheckBox *m_enableCheckBox;
+};
+
+
+#endif // KP_EFFECT_EMBOSS_H
diff --git a/kolourpaint/pixmapfx/kpeffectflatten.cpp b/kolourpaint/pixmapfx/kpeffectflatten.cpp
new file mode 100644
index 00000000..6a81bca0
--- /dev/null
+++ b/kolourpaint/pixmapfx/kpeffectflatten.cpp
@@ -0,0 +1,266 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_EFFECT_FLATTEN 0
+
+
+#include <kpeffectflatten.h>
+
+#include <qcheckbox.h>
+#include <qimage.h>
+#include <qlayout.h>
+#include <qpixmap.h>
+#include <qvbox.h>
+
+#include <kcolorbutton.h>
+#include <kconfig.h>
+#include <kdialog.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kimageeffect.h>
+#include <klocale.h>
+
+#include <kpdefs.h>
+#include <kppixmapfx.h>
+
+
+//
+// kpEffectFlattenCommand
+//
+
+kpEffectFlattenCommand::kpEffectFlattenCommand (const QColor &color1,
+ const QColor &color2,
+ bool actOnSelection,
+ kpMainWindow *mainWindow)
+ : kpColorEffectCommand (i18n ("Flatten"), actOnSelection, mainWindow),
+ m_color1 (color1), m_color2 (color2)
+{
+}
+
+kpEffectFlattenCommand::~kpEffectFlattenCommand ()
+{
+}
+
+
+// public static
+void kpEffectFlattenCommand::apply (QPixmap *destPixmapPtr,
+ const QColor &color1, const QColor &color2)
+{
+ if (!destPixmapPtr)
+ return;
+
+ QImage image = kpPixmapFX::convertToImage (*destPixmapPtr);
+ apply (&image, color1, color2);
+ *destPixmapPtr = kpPixmapFX::convertToPixmap (image);
+}
+
+// public static
+QPixmap kpEffectFlattenCommand::apply (const QPixmap &pm,
+ const QColor &color1, const QColor &color2)
+{
+ QImage image = kpPixmapFX::convertToImage (pm);
+ apply (&image, color1, color2);
+ return kpPixmapFX::convertToPixmap (image);
+}
+
+// public static
+void kpEffectFlattenCommand::apply (QImage *destImagePtr,
+ const QColor &color1, const QColor &color2)
+{
+ if (!destImagePtr)
+ return;
+
+ KImageEffect::flatten (*destImagePtr/*ref*/, color1, color2);
+}
+
+// public static
+QImage kpEffectFlattenCommand::apply (const QImage &img,
+ const QColor &color1, const QColor &color2)
+{
+ QImage retImage = img;
+ apply (&retImage, color1, color2);
+ return retImage;
+}
+
+
+//
+// kpEffectFlattenCommand implements kpColorEffectCommand interface
+//
+
+// protected virtual [base kpColorEffectCommand]
+QPixmap kpEffectFlattenCommand::applyColorEffect (const QPixmap &pixmap)
+{
+ return apply (pixmap, m_color1, m_color2);
+}
+
+
+//
+// kpEffectFlattenWidget
+//
+
+// public static
+// Don't initialise globally when we probably don't have a colour
+// allocation context. This way, the colours aren't sometimes invalid
+// (e.g. at 8-bit).
+QColor kpEffectFlattenWidget::s_lastColor1;
+QColor kpEffectFlattenWidget::s_lastColor2;
+
+kpEffectFlattenWidget::kpEffectFlattenWidget (bool actOnSelection,
+ kpMainWindow *mainWindow,
+ QWidget *parent,
+ const char *name)
+ : kpColorEffectWidget (actOnSelection, mainWindow, parent, name)
+{
+ if (!s_lastColor1.isValid () || !s_lastColor2.isValid ())
+ {
+ KConfigGroupSaver cfgGroupSaver (KGlobal::config (), kpSettingsGroupFlattenEffect);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ s_lastColor1 = cfg->readColorEntry (kpSettingFlattenEffectColor1);
+ if (!s_lastColor1.isValid ())
+ s_lastColor1 = Qt::red;
+
+ s_lastColor2 = cfg->readColorEntry (kpSettingFlattenEffectColor2);
+ if (!s_lastColor2.isValid ())
+ s_lastColor2 = Qt::blue;
+ }
+
+
+ m_enableCheckBox = new QCheckBox (i18n ("E&nable"), this);
+
+ QVBox *colorButtonContainer = new QVBox (this);
+ colorButtonContainer->setMargin (KDialog::marginHint () / 2);
+ colorButtonContainer->setSpacing (spacingHint ());
+ m_color1Button = new KColorButton (s_lastColor1, colorButtonContainer);
+ m_color2Button = new KColorButton (s_lastColor2, colorButtonContainer);
+
+
+ m_color1Button->setEnabled (false);
+ m_color2Button->setEnabled (false);
+
+
+ QVBoxLayout *lay = new QVBoxLayout (this, marginHint (), spacingHint ());
+ lay->addWidget (m_enableCheckBox);
+ lay->addWidget (colorButtonContainer);
+
+
+ connect (m_enableCheckBox, SIGNAL (toggled (bool)),
+ this, SLOT (slotEnableChanged (bool)));
+
+ connect (m_color1Button, SIGNAL (changed (const QColor &)),
+ this, SIGNAL (settingsChanged ()));
+ connect (m_color2Button, SIGNAL (changed (const QColor &)),
+ this, SIGNAL (settingsChanged ()));
+}
+
+kpEffectFlattenWidget::~kpEffectFlattenWidget ()
+{
+ s_lastColor1 = color1 ();
+ s_lastColor2 = color2 ();
+
+
+ KConfigGroupSaver cfgGroupSaver (KGlobal::config (), kpSettingsGroupFlattenEffect);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ cfg->writeEntry (kpSettingFlattenEffectColor1, s_lastColor1);
+ cfg->writeEntry (kpSettingFlattenEffectColor2, s_lastColor2);
+ cfg->sync ();
+}
+
+
+// public
+QColor kpEffectFlattenWidget::color1 () const
+{
+ return m_color1Button->color ();
+}
+
+// public
+QColor kpEffectFlattenWidget::color2 () const
+{
+ return m_color2Button->color ();
+}
+
+
+//
+// kpEffectFlattenWidget implements kpColorEffectWidget interface
+//
+
+// public virtual [base kpColorEffectWidget]
+QString kpEffectFlattenWidget::caption () const
+{
+ return i18n ("Colors");
+}
+
+
+// public virtual [base kpColorEffectWidget]
+bool kpEffectFlattenWidget::isNoOp () const
+{
+ return !m_enableCheckBox->isChecked ();
+}
+
+// public virtual [base kpColorEffectWidget]
+QPixmap kpEffectFlattenWidget::applyColorEffect (const QPixmap &pixmap)
+{
+#if DEBUG_KP_EFFECT_FLATTEN
+ kdDebug () << "kpEffectFlattenWidget::applyColorEffect() nop="
+ << isNoOp () << endl;
+#endif
+
+ if (isNoOp ())
+ return pixmap;
+
+ return kpEffectFlattenCommand::apply (pixmap, color1 (), color2 ());
+}
+
+
+// public virtual [base kpColorEffectWidget]
+kpColorEffectCommand *kpEffectFlattenWidget::createCommand () const
+{
+ return new kpEffectFlattenCommand (color1 (), color2 (),
+ m_actOnSelection,
+ m_mainWindow);
+}
+
+
+// protected slot:
+void kpEffectFlattenWidget::slotEnableChanged (bool enable)
+{
+#if DEBUG_KP_EFFECT_FLATTEN
+ kdDebug () << "kpEffectFlattenWidget::slotEnableChanged(" << enable
+ << ") enableButton=" << m_enableCheckBox->isChecked ()
+ << endl;
+#endif
+
+ m_color1Button->setEnabled (enable);
+ m_color2Button->setEnabled (enable);
+
+ emit settingsChanged ();
+}
+
+
+#include <kpeffectflatten.moc>
+
diff --git a/kolourpaint/pixmapfx/kpeffectflatten.h b/kolourpaint/pixmapfx/kpeffectflatten.h
new file mode 100644
index 00000000..79c9bbaf
--- /dev/null
+++ b/kolourpaint/pixmapfx/kpeffectflatten.h
@@ -0,0 +1,115 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef KP_EFFECT_FLATTEN_H
+#define KP_EFFECT_FLATTEN_H
+
+
+#include <qcolor.h>
+
+#include <kpcoloreffect.h>
+
+
+class QCheckBox;
+class QImage;
+
+class KColorButton;
+
+class kpMainWindow;
+
+
+class kpEffectFlattenCommand : public kpColorEffectCommand
+{
+public:
+ kpEffectFlattenCommand (const QColor &color1, const QColor &color2,
+ bool actOnSelection,
+ kpMainWindow *mainWindow);
+ virtual ~kpEffectFlattenCommand ();
+
+
+ static void apply (QPixmap *destPixmapPtr,
+ const QColor &color1, const QColor &color2);
+ static QPixmap apply (const QPixmap &pm,
+ const QColor &color1, const QColor &color2);
+ static void apply (QImage *destImagePtr,
+ const QColor &color1, const QColor &color2);
+ static QImage apply (const QImage &img,
+ const QColor &color1, const QColor &color2);
+
+
+ //
+ // kpColorEffectCommand interface
+ //
+
+protected:
+ virtual QPixmap applyColorEffect (const QPixmap &pixmap);
+
+ QColor m_color1, m_color2;
+};
+
+
+class kpEffectFlattenWidget : public kpColorEffectWidget
+{
+Q_OBJECT
+
+public:
+ kpEffectFlattenWidget (bool actOnSelection,
+ kpMainWindow *mainWindow,
+ QWidget *parent, const char *name = 0);
+ virtual ~kpEffectFlattenWidget ();
+
+
+ static QColor s_lastColor1, s_lastColor2;
+
+
+ QColor color1 () const;
+ QColor color2 () const;
+
+
+ //
+ // kpColorEffectWidget interface
+ //
+
+ virtual QString caption () const;
+
+ virtual bool isNoOp () const;
+ virtual QPixmap applyColorEffect (const QPixmap &pixmap);
+
+ virtual kpColorEffectCommand *createCommand () const;
+
+protected slots:
+ void slotEnableChanged (bool enable);
+
+protected:
+ QCheckBox *m_enableCheckBox;
+ KColorButton *m_color1Button, *m_color2Button;
+};
+
+
+
+#endif // KP_EFFECT_FLATTEN_H
diff --git a/kolourpaint/pixmapfx/kpeffectinvert.cpp b/kolourpaint/pixmapfx/kpeffectinvert.cpp
new file mode 100644
index 00000000..b9bb00a8
--- /dev/null
+++ b/kolourpaint/pixmapfx/kpeffectinvert.cpp
@@ -0,0 +1,315 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_EFFECT_INVERT 0
+
+
+#include <kpeffectinvert.h>
+
+#include <qcheckbox.h>
+#include <qimage.h>
+#include <qlayout.h>
+#include <qpixmap.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kppixmapfx.h>
+
+
+//
+// kpEffectInvertCommand
+//
+
+kpEffectInvertCommand::kpEffectInvertCommand (int channels,
+ bool actOnSelection,
+ kpMainWindow *mainWindow)
+ : kpColorEffectCommand (channels == RGB ?
+ i18n ("Invert Colors") : i18n ("Invert"),
+ actOnSelection, mainWindow),
+ m_channels (channels)
+{
+}
+
+kpEffectInvertCommand::kpEffectInvertCommand (bool actOnSelection,
+ kpMainWindow *mainWindow)
+ : kpColorEffectCommand (i18n ("Invert Colors"), actOnSelection, mainWindow),
+ m_channels (RGB)
+{
+}
+
+kpEffectInvertCommand::~kpEffectInvertCommand ()
+{
+}
+
+
+// public static
+void kpEffectInvertCommand::apply (QPixmap *destPixmapPtr, int channels)
+{
+ QImage image = kpPixmapFX::convertToImage (*destPixmapPtr);
+ apply (&image, channels);
+ *destPixmapPtr = kpPixmapFX::convertToPixmap (image);
+}
+
+// public static
+QPixmap kpEffectInvertCommand::apply (const QPixmap &pm, int channels)
+{
+ QImage image = kpPixmapFX::convertToImage (pm);
+ apply (&image, channels);
+ return kpPixmapFX::convertToPixmap (image);
+}
+
+// public static
+void kpEffectInvertCommand::apply (QImage *destImagePtr, int channels)
+{
+ QRgb mask = qRgba ((channels & Red) ? 0xFF : 0,
+ (channels & Green) ? 0xFF : 0,
+ (channels & Blue) ? 0xFF : 0,
+ 0/*don't invert alpha*/);
+#if DEBUG_KP_EFFECT_INVERT
+ kdDebug () << "kpEffectInvertCommand::apply(channels=" << channels
+ << ") mask=" << (int *) mask
+ << endl;
+#endif
+
+ if (destImagePtr->depth () > 8)
+ {
+ #if 0
+ // SYNC: TODO: Qt BUG - invertAlpha argument is inverted!!!
+ destImagePtr->invertPixels (true/*no invert alpha (Qt 3.2)*/);
+ #else
+ // Above version works for Qt 3.2 at least.
+ // But this version will always work (slower, though) and supports
+ // inverting particular channels.
+ for (int y = 0; y < destImagePtr->height (); y++)
+ {
+ for (int x = 0; x < destImagePtr->width (); x++)
+ {
+ destImagePtr->setPixel (x, y, destImagePtr->pixel (x, y) ^ mask);
+ }
+ }
+ #endif
+ }
+ else
+ {
+ for (int i = 0; i < destImagePtr->numColors (); i++)
+ {
+ destImagePtr->setColor (i, destImagePtr->color (i) ^ mask);
+ }
+ }
+}
+
+// public static
+QImage kpEffectInvertCommand::apply (const QImage &img, int channels)
+{
+ QImage retImage = img;
+ apply (&retImage, channels);
+ return retImage;
+}
+
+
+//
+// kpEffectInvertCommand implements kpColorEffectCommand interface
+//
+
+// protected virtual [base kpColorEffectCommand]
+QPixmap kpEffectInvertCommand::applyColorEffect (const QPixmap &pixmap)
+{
+ return apply (pixmap, m_channels);
+}
+
+
+//
+// kpEffectInvertWidget
+//
+
+kpEffectInvertWidget::kpEffectInvertWidget (bool actOnSelection,
+ kpMainWindow *mainWindow,
+ QWidget *parent,
+ const char *name)
+ : kpColorEffectWidget (actOnSelection, mainWindow, parent, name)
+{
+ QVBoxLayout *topLevelLay = new QVBoxLayout (this, marginHint (), spacingHint ());
+
+
+ QWidget *centerWidget = new QWidget (this);
+ topLevelLay->addWidget (centerWidget, 0/*stretch*/, Qt::AlignCenter);
+
+
+ QVBoxLayout *centerWidgetLay = new QVBoxLayout (centerWidget,
+ 0/*margin*/,
+ spacingHint ());
+
+
+ m_redCheckBox = new QCheckBox (i18n ("&Red"), centerWidget);
+ m_greenCheckBox = new QCheckBox (i18n ("&Green"), centerWidget);
+ m_blueCheckBox = new QCheckBox (i18n ("&Blue"), centerWidget);
+
+ QWidget *spaceWidget = new QWidget (centerWidget);
+ spaceWidget->setFixedSize (1, spacingHint ());
+
+ m_allCheckBox = new QCheckBox (i18n ("&All"), centerWidget);
+
+
+ m_redCheckBox->setChecked (false);
+ m_greenCheckBox->setChecked (false);
+ m_blueCheckBox->setChecked (false);
+
+ m_allCheckBox->setChecked (false);
+
+
+ centerWidgetLay->addWidget (m_redCheckBox);
+ centerWidgetLay->addWidget (m_greenCheckBox);
+ centerWidgetLay->addWidget (m_blueCheckBox);
+
+ centerWidgetLay->addWidget (spaceWidget);
+
+ centerWidgetLay->addWidget (m_allCheckBox);
+
+
+ m_inSignalHandler = false;
+ connect (m_redCheckBox, SIGNAL (toggled (bool)),
+ this, SLOT (slotRGBCheckBoxToggled ()));
+ connect (m_greenCheckBox, SIGNAL (toggled (bool)),
+ this, SLOT (slotRGBCheckBoxToggled ()));
+ connect (m_blueCheckBox, SIGNAL (toggled (bool)),
+ this, SLOT (slotRGBCheckBoxToggled ()));
+
+ connect (m_allCheckBox, SIGNAL (toggled (bool)),
+ this, SLOT (slotAllCheckBoxToggled ()));
+}
+
+kpEffectInvertWidget::~kpEffectInvertWidget ()
+{
+}
+
+
+// public
+int kpEffectInvertWidget::channels () const
+{
+#if DEBUG_KP_EFFECT_INVERT
+ kdDebug () << "kpEffectInvertWidget::channels()"
+ << " isChecked: r=" << m_redCheckBox->isChecked ()
+ << " g=" << m_greenCheckBox->isChecked ()
+ << " b=" << m_blueCheckBox->isChecked ()
+ << endl;
+#endif
+
+ int channels = 0;
+
+
+ if (m_redCheckBox->isChecked ())
+ channels |= kpEffectInvertCommand::Red;
+
+ if (m_greenCheckBox->isChecked ())
+ channels |= kpEffectInvertCommand::Green;
+
+ if (m_blueCheckBox->isChecked ())
+ channels |= kpEffectInvertCommand::Blue;
+
+
+#if DEBUG_KP_EFFECT_INVERT
+ kdDebug () << "\treturning channels=" << (int *) channels << endl;
+#endif
+ return channels;
+}
+
+
+//
+// kpEffectInvertWidget implements kpColorEffectWidget interface
+//
+
+// public virtual [base kpColorEffectWidget]
+QString kpEffectInvertWidget::caption () const
+{
+ return i18n ("Channels");
+}
+
+
+// public virtual [base kpColorEffectWidget]
+bool kpEffectInvertWidget::isNoOp () const
+{
+ return (channels () == kpEffectInvertCommand::None);
+}
+
+// public virtual [base kpColorEffectWidget]
+QPixmap kpEffectInvertWidget::applyColorEffect (const QPixmap &pixmap)
+{
+ return kpEffectInvertCommand::apply (pixmap, channels ());
+}
+
+
+// public virtual [base kpColorEffectWidget]
+kpColorEffectCommand *kpEffectInvertWidget::createCommand () const
+{
+ return new kpEffectInvertCommand (channels (),
+ m_actOnSelection,
+ m_mainWindow);
+}
+
+
+// protected slots
+void kpEffectInvertWidget::slotRGBCheckBoxToggled ()
+{
+ if (m_inSignalHandler)
+ return;
+
+ m_inSignalHandler = true;
+
+ //blockSignals (true);
+ m_allCheckBox->setChecked (m_redCheckBox->isChecked () &&
+ m_blueCheckBox->isChecked () &&
+ m_greenCheckBox->isChecked ());
+ //blockSignals (false);
+
+ emit settingsChanged ();
+
+ m_inSignalHandler = false;
+}
+
+// protected slot
+void kpEffectInvertWidget::slotAllCheckBoxToggled ()
+{
+ if (m_inSignalHandler)
+ return;
+
+ m_inSignalHandler = true;
+
+ //blockSignals (true);
+ m_redCheckBox->setChecked (m_allCheckBox->isChecked ());
+ m_greenCheckBox->setChecked (m_allCheckBox->isChecked ());
+ m_blueCheckBox->setChecked (m_allCheckBox->isChecked ());
+ //blockSignals (false);
+
+ emit settingsChanged ();
+
+ m_inSignalHandler = false;
+}
+
+
+#include <kpeffectinvert.moc>
+
diff --git a/kolourpaint/pixmapfx/kpeffectinvert.h b/kolourpaint/pixmapfx/kpeffectinvert.h
new file mode 100644
index 00000000..61d6cfda
--- /dev/null
+++ b/kolourpaint/pixmapfx/kpeffectinvert.h
@@ -0,0 +1,130 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef KP_EFFECT_INVERT_H
+#define KP_EFFECT_INVERT_H
+
+
+#include <kpcoloreffect.h>
+
+
+class QCheckBox;
+class QImage;
+
+class kpMainWindow;
+
+
+class kpEffectInvertCommand : public kpColorEffectCommand
+{
+public:
+ enum Channel
+ {
+ None = 0,
+ Red = 1, Green = 2, Blue = 4,
+ RGB = Red | Green | Blue
+ };
+
+ kpEffectInvertCommand (int channels,
+ bool actOnSelection,
+ kpMainWindow *mainWindow);
+ kpEffectInvertCommand (bool actOnSelection,
+ kpMainWindow *mainWindow);
+ virtual ~kpEffectInvertCommand ();
+
+
+ //
+ // Inverts the colours of each pixel in the given image.
+ // These functions differ from QImage::invertPixels() in the following ways:
+ //
+ // 1. for 8-bit images, it inverts the colours of the Colour Table
+ // (this means that you would get visually similar results to inversion
+ // at higher bit depths - rather than a "random-looking" inversion
+ // depending on the contents of the Colour Table)
+ // 2. never inverts the Alpha Buffer
+ //
+
+ static void apply (QPixmap *destPixmapPtr, int channels = RGB);
+ static QPixmap apply (const QPixmap &pm, int channels = RGB);
+ static void apply (QImage *destImagePtr, int channels = RGB);
+ static QImage apply (const QImage &img, int channels = RGB);
+
+
+ //
+ // kpColorEffectCommand interface
+ //
+
+public:
+ virtual bool isInvertible () const { return true; }
+
+protected:
+ virtual QPixmap applyColorEffect (const QPixmap &pixmap);
+
+ int m_channels;
+};
+
+
+class kpEffectInvertWidget : public kpColorEffectWidget
+{
+Q_OBJECT
+
+public:
+ kpEffectInvertWidget (bool actOnSelection,
+ kpMainWindow *mainWindow,
+ QWidget *parent, const char *name = 0);
+ virtual ~kpEffectInvertWidget ();
+
+
+ int channels () const;
+
+
+ //
+ // kpColorEffectWidget interface
+ //
+
+ virtual QString caption () const;
+
+ virtual bool isNoOp () const;
+ virtual QPixmap applyColorEffect (const QPixmap &pixmap);
+
+ virtual kpColorEffectCommand *createCommand () const;
+
+protected slots:
+ void slotRGBCheckBoxToggled ();
+ void slotAllCheckBoxToggled ();
+
+protected:
+ QCheckBox *m_redCheckBox, *m_greenCheckBox, *m_blueCheckBox,
+ *m_allCheckBox;
+
+ // blockSignals() didn't seem to work
+ bool m_inSignalHandler;
+};
+
+
+
+#endif // KP_EFFECT_INVERT_H
diff --git a/kolourpaint/pixmapfx/kpeffectreducecolors.cpp b/kolourpaint/pixmapfx/kpeffectreducecolors.cpp
new file mode 100644
index 00000000..b6eb7a42
--- /dev/null
+++ b/kolourpaint/pixmapfx/kpeffectreducecolors.cpp
@@ -0,0 +1,446 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_EFFECT_REDUCE_COLORS 0
+
+
+#include <kpeffectreducecolors.h>
+
+#include <qbuttongroup.h>
+#include <qcheckbox.h>
+#include <qimage.h>
+#include <qlayout.h>
+#include <qpixmap.h>
+#include <qradiobutton.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kppixmapfx.h>
+
+
+QImage convertImageDepth (const QImage &image, int depth, bool dither)
+{
+#if DEBUG_KP_EFFECT_REDUCE_COLORS
+ kdDebug () << "::convertImageDepth() changing image (w=" << image.width ()
+ << ",h=" << image.height ()
+ << ") depth from " << image.depth ()
+ << " to " << depth
+ << " (dither=" << dither << ")"
+ << endl;
+#endif
+
+ if (image.isNull ())
+ return image;
+
+ if (depth == image.depth ())
+ return image;
+
+
+#if DEBUG_KP_EFFECT_REDUCE_COLORS && 0
+ for (int y = 0; y < image.height (); y++)
+ {
+ for (int x = 0; x < image.width (); x++)
+ {
+ fprintf (stderr, " %08X", image.pixel (x, y));
+ }
+ fprintf (stderr, "\n");
+ }
+#endif
+
+
+ // Hack around Qt's braindead QImage::convertDepth(1, ...) (with
+ // dithering off) which produces pathetic results with an image that
+ // only has 2 colours - sometimes it just gives a completely black
+ // result. Instead, we simply preserve the 2 colours. One use case
+ // is resaving a "colour monochrome" image (<= 2 colours but not
+ // necessarily black & white).
+ if (depth == 1 && !dither)
+ {
+ #if DEBUG_KP_EFFECT_REDUCE_COLORS
+ kdDebug () << "\tinvoking convert-to-depth 1 hack" << endl;
+ #endif
+ QRgb color0, color1;
+ bool color0Valid = false, color1Valid = false;
+
+ bool moreThan2Colors = false;
+
+ QImage monoImage (image.width (), image.height (),
+ 1/*depth*/, 2/*numColors*/, QImage::LittleEndian);
+ #if DEBUG_KP_EFFECT_REDUCE_COLORS
+ kdDebug () << "\t\tinitialising output image w=" << monoImage.width ()
+ << ",h=" << monoImage.height ()
+ << ",d=" << monoImage.depth ()
+ << endl;
+ #endif
+ for (int y = 0; y < image.height (); y++)
+ {
+ for (int x = 0; x < image.width (); x++)
+ {
+ QRgb imagePixel = image.pixel (x, y);
+
+ if (color0Valid && imagePixel == color0)
+ monoImage.setPixel (x, y, 0);
+ else if (color1Valid && imagePixel == color1)
+ monoImage.setPixel (x, y, 1);
+ else if (!color0Valid)
+ {
+ color0 = imagePixel;
+ color0Valid = true;
+ monoImage.setPixel (x, y, 0);
+ #if DEBUG_KP_EFFECT_REDUCE_COLORS
+ kdDebug () << "\t\t\tcolor0=" << (int *) color0
+ << " at x=" << x << ",y=" << y << endl;
+ #endif
+ }
+ else if (!color1Valid)
+ {
+ color1 = imagePixel;
+ color1Valid = true;
+ monoImage.setPixel (x, y, 1);
+ #if DEBUG_KP_EFFECT_REDUCE_COLORS
+ kdDebug () << "\t\t\tcolor1=" << (int *) color1
+ << " at x=" << x << ",y=" << y << endl;
+ #endif
+ }
+ else
+ {
+ #if DEBUG_KP_EFFECT_REDUCE_COLORS
+ kdDebug () << "\t\t\timagePixel=" << (int *) imagePixel
+ << " at x=" << x << ",y=" << y
+ << " moreThan2Colors - abort hack" << endl;
+ #endif
+ moreThan2Colors = true;
+
+ // Dijkstra, this is clearer than double break'ing or
+ // a check in both loops
+ goto exit_loop;
+ }
+ }
+ }
+ exit_loop:
+
+ if (!moreThan2Colors)
+ {
+ monoImage.setColor (0, color0Valid ? color0 : 0xFFFFFF);
+ monoImage.setColor (1, color1Valid ? color1 : 0x000000);
+ return monoImage;
+ }
+ }
+
+
+ QImage retImage = image.convertDepth (depth,
+ Qt::AutoColor |
+ (dither ? Qt::DiffuseDither : Qt::ThresholdDither) |
+ Qt::ThresholdAlphaDither |
+ (dither ? Qt::PreferDither : Qt::AvoidDither));
+
+#if DEBUG_KP_EFFECT_REDUCE_COLORS && 0
+ kdDebug () << "After colour reduction:" << endl;
+ for (int y = 0; y < image.height (); y++)
+ {
+ for (int x = 0; x < image.width (); x++)
+ {
+ fprintf (stderr, " %08X", image.pixel (x, y));
+ }
+ fprintf (stderr, "\n");
+ }
+#endif
+
+ return retImage;
+}
+
+
+//
+// kpEffectReduceColorsCommand
+//
+
+kpEffectReduceColorsCommand::kpEffectReduceColorsCommand (int depth, bool dither,
+ bool actOnSelection,
+ kpMainWindow *mainWindow)
+ : kpColorEffectCommand (commandName (depth, dither), actOnSelection, mainWindow),
+ m_depth (depth), m_dither (dither)
+{
+}
+
+kpEffectReduceColorsCommand::~kpEffectReduceColorsCommand ()
+{
+}
+
+
+// public
+QString kpEffectReduceColorsCommand::commandName (int depth, int dither) const
+{
+ if (depth == 1)
+ {
+ if (dither)
+ return i18n ("Reduce to Monochrome (Dithered)");
+ else
+ return i18n ("Reduce to Monochrome");
+ }
+ else if (depth == 8)
+ {
+ if (dither)
+ return i18n ("Reduce to 256 Color (Dithered)");
+ else
+ return i18n ("Reduce to 256 Color");
+ }
+ else
+ {
+ return QString::null;
+ }
+}
+
+
+// public static
+void kpEffectReduceColorsCommand::apply (QPixmap *destPixmapPtr, int depth, bool dither)
+{
+ if (!destPixmapPtr)
+ return;
+
+ if (depth != 1 && depth != 8)
+ return;
+
+
+ QImage image = kpPixmapFX::convertToImage (*destPixmapPtr);
+
+
+ image = ::convertImageDepth (image, depth, dither);
+
+ if (image.isNull ())
+ return;
+
+
+ QPixmap pixmap = kpPixmapFX::convertToPixmap (image, false/*no dither*/);
+
+
+ // HACK: The above "image.convertDepth()" erases the Alpha Channel
+ // (at least for monochrome).
+ // qpixmap.html says "alpha masks on monochrome images are ignored."
+ //
+ // Put the mask back.
+ //
+ if (destPixmapPtr->mask ())
+ pixmap.setMask (*destPixmapPtr->mask ());
+
+ *destPixmapPtr = pixmap;
+}
+
+// public static
+QPixmap kpEffectReduceColorsCommand::apply (const QPixmap &pm, int depth, bool dither)
+{
+ QPixmap ret = pm;
+ apply (&ret, depth, dither);
+ return ret;
+}
+
+
+//
+// kpEffectReduceColorsCommand implements kpColorEffectCommand interface
+//
+
+// protected virtual [base kpColorEffectCommand]
+QPixmap kpEffectReduceColorsCommand::applyColorEffect (const QPixmap &pixmap)
+{
+ return apply (pixmap, m_depth, m_dither);
+}
+
+
+//
+// kpEffectReduceColorsWidget
+//
+
+kpEffectReduceColorsWidget::kpEffectReduceColorsWidget (bool actOnSelection,
+ kpMainWindow *mainWindow,
+ QWidget *parent,
+ const char *name)
+ : kpColorEffectWidget (actOnSelection, mainWindow, parent, name)
+{
+ QVBoxLayout *lay = new QVBoxLayout (this, marginHint (), spacingHint ());
+
+
+ m_blackAndWhiteRadioButton =
+ new QRadioButton (i18n ("&Monochrome"), this);
+
+ m_blackAndWhiteDitheredRadioButton =
+ new QRadioButton (i18n ("Mo&nochrome (dithered)"), this);
+
+ m_8BitRadioButton = new QRadioButton (i18n ("256 co&lor"), this);
+
+ m_8BitDitheredRadioButton = new QRadioButton (i18n ("256 colo&r (dithered)"), this);
+
+ m_24BitRadioButton = new QRadioButton (i18n ("24-&bit color"), this);
+
+
+ QButtonGroup *buttonGroup = new QButtonGroup (this);
+ buttonGroup->hide ();
+
+ buttonGroup->insert (m_blackAndWhiteRadioButton);
+ buttonGroup->insert (m_blackAndWhiteDitheredRadioButton);
+ buttonGroup->insert (m_8BitRadioButton);
+ buttonGroup->insert (m_8BitDitheredRadioButton);
+ buttonGroup->insert (m_24BitRadioButton);
+
+
+ const int screenDepth = QPixmap::defaultDepth ();
+#if DEBUG_KP_EFFECT_REDUCE_COLORS
+ kdDebug () << "kpEffectReduceColorsWidget::<ctor> screenDepth="
+ << screenDepth
+ << endl;
+#endif
+
+ // Note that everything is disabled for a 1-bit screen since there
+ // would be no effect. I won't support 2-bit or 4-bit screens either :)
+ m_blackAndWhiteRadioButton->setEnabled (screenDepth >= 8);
+ m_blackAndWhiteDitheredRadioButton->setEnabled (screenDepth >= 8);
+ m_8BitRadioButton->setEnabled (screenDepth >= 8);
+ // (not enabled if screenDepth==8 as m_8BitRadioButton already serves
+ // as NOP default)
+ m_8BitDitheredRadioButton->setEnabled (screenDepth > 8);
+ // (not "screenDepth >= 24" as we need a NOP default for 15/16-bit
+ // screens)
+ m_24BitRadioButton->setEnabled (screenDepth > 8);
+
+
+ m_defaultRadioButton = 0;
+
+ if (m_24BitRadioButton->isEnabled ())
+ {
+ #if DEBUG_KP_EFFECT_REDUCE_COLORS
+ kdDebug () << "\tdefault is 24-bit button" << endl;
+ #endif
+ m_defaultRadioButton = m_24BitRadioButton;
+ }
+ else if (m_8BitRadioButton->isEnabled ())
+ {
+ #if DEBUG_KP_EFFECT_REDUCE_COLORS
+ kdDebug () << "\tdefault is 8-bit button" << endl;
+ #endif
+ m_defaultRadioButton = m_8BitRadioButton;
+ }
+ else
+ {
+ #if DEBUG_KP_EFFECT_REDUCE_COLORS
+ kdDebug () << "\tuser must have a 1-bit screen - no default" << endl;
+ #endif
+ }
+
+
+ if (m_defaultRadioButton)
+ m_defaultRadioButton->setChecked (true);
+
+
+ lay->addWidget (m_blackAndWhiteRadioButton);
+ lay->addWidget (m_blackAndWhiteDitheredRadioButton);
+ lay->addWidget (m_8BitRadioButton);
+ lay->addWidget (m_8BitDitheredRadioButton);
+ lay->addWidget (m_24BitRadioButton);
+
+
+ connect (m_blackAndWhiteRadioButton, SIGNAL (toggled (bool)),
+ this, SIGNAL (settingsChanged ()));
+ connect (m_blackAndWhiteDitheredRadioButton, SIGNAL (toggled (bool)),
+ this, SIGNAL (settingsChanged ()));
+ connect (m_8BitRadioButton, SIGNAL (toggled (bool)),
+ this, SIGNAL (settingsChanged ()));
+ connect (m_8BitDitheredRadioButton, SIGNAL (toggled (bool)),
+ this, SIGNAL (settingsChanged ()));
+ connect (m_24BitRadioButton, SIGNAL (toggled (bool)),
+ this, SIGNAL (settingsChanged ()));
+}
+
+kpEffectReduceColorsWidget::~kpEffectReduceColorsWidget ()
+{
+}
+
+
+// public
+int kpEffectReduceColorsWidget::depth () const
+{
+ if (m_blackAndWhiteRadioButton->isChecked () ||
+ m_blackAndWhiteDitheredRadioButton->isChecked ())
+ {
+ return 1;
+ }
+ else if (m_8BitRadioButton->isChecked () ||
+ m_8BitDitheredRadioButton->isChecked ())
+ {
+ return 8;
+ }
+ else if (m_24BitRadioButton->isChecked ())
+ {
+ return 24;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// public
+bool kpEffectReduceColorsWidget::dither () const
+{
+ return (m_blackAndWhiteDitheredRadioButton->isChecked () ||
+ m_8BitDitheredRadioButton->isChecked ());
+}
+
+
+//
+// kpEffectReduceColorsWidget implements kpColorEffectWidget interface
+//
+
+// public virtual [base kpColorEffectWidget]
+QString kpEffectReduceColorsWidget::caption () const
+{
+ return i18n ("Reduce To");
+}
+
+
+// public virtual [base kpColorEffectWidget]
+bool kpEffectReduceColorsWidget::isNoOp () const
+{
+ return (!m_defaultRadioButton || m_defaultRadioButton->isChecked ());
+}
+
+// public virtual [base kpColorEffectWidget]
+QPixmap kpEffectReduceColorsWidget::applyColorEffect (const QPixmap &pixmap)
+{
+ return kpEffectReduceColorsCommand::apply (pixmap, depth (), dither ());
+}
+
+
+// public virtual [base kpColorEffectWidget]
+kpColorEffectCommand *kpEffectReduceColorsWidget::createCommand () const
+{
+ return new kpEffectReduceColorsCommand (depth (), dither (),
+ m_actOnSelection,
+ m_mainWindow);
+}
+
+
+#include <kpeffectreducecolors.moc>
+
diff --git a/kolourpaint/pixmapfx/kpeffectreducecolors.h b/kolourpaint/pixmapfx/kpeffectreducecolors.h
new file mode 100644
index 00000000..a14cffc7
--- /dev/null
+++ b/kolourpaint/pixmapfx/kpeffectreducecolors.h
@@ -0,0 +1,110 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef KP_EFFECT_REDUCE_COLORS_H
+#define KP_EFFECT_REDUCE_COLORS_H
+
+
+#include <kpcoloreffect.h>
+
+
+class QRadioButton;
+class QImage;
+
+class kpMainWindow;
+
+
+QImage convertImageDepth (const QImage &image, int depth, bool dither);
+
+
+class kpEffectReduceColorsCommand : public kpColorEffectCommand
+{
+public:
+ // depth must be 1 or 8
+ kpEffectReduceColorsCommand (int depth, bool dither,
+ bool actOnSelection,
+ kpMainWindow *mainWindow);
+ virtual ~kpEffectReduceColorsCommand ();
+
+ QString commandName (int depth, int dither) const;
+
+ // (always preserves mask)
+ static void apply (QPixmap *destPixmapPtr, int depth, bool dither);
+ static QPixmap apply (const QPixmap &pm, int depth, bool dither);
+
+
+ //
+ // kpColorEffectCommand interface
+ //
+
+protected:
+ virtual QPixmap applyColorEffect (const QPixmap &pixmap);
+
+ int m_depth;
+ bool m_dither;
+};
+
+
+class kpEffectReduceColorsWidget : public kpColorEffectWidget
+{
+Q_OBJECT
+
+public:
+ kpEffectReduceColorsWidget (bool actOnSelection,
+ kpMainWindow *mainWindow,
+ QWidget *parent, const char *name = 0);
+ virtual ~kpEffectReduceColorsWidget ();
+
+
+ int depth () const;
+ bool dither () const;
+
+
+ //
+ // kpColorEffectWidget interface
+ //
+
+ virtual QString caption () const;
+
+ virtual bool isNoOp () const;
+ virtual QPixmap applyColorEffect (const QPixmap &pixmap);
+
+ virtual kpColorEffectCommand *createCommand () const;
+
+protected:
+ QRadioButton *m_blackAndWhiteRadioButton,
+ *m_blackAndWhiteDitheredRadioButton,
+ *m_8BitRadioButton,
+ *m_8BitDitheredRadioButton,
+ *m_24BitRadioButton;
+ QRadioButton *m_defaultRadioButton;
+};
+
+
+
+#endif // KP_EFFECT_REDUCE_COLORS_H
diff --git a/kolourpaint/pixmapfx/kpeffectsdialog.cpp b/kolourpaint/pixmapfx/kpeffectsdialog.cpp
new file mode 100644
index 00000000..666f81cf
--- /dev/null
+++ b/kolourpaint/pixmapfx/kpeffectsdialog.cpp
@@ -0,0 +1,369 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_EFFECTS_DIALOG 0
+
+
+#include <kpeffectsdialog.h>
+
+#include <qgroupbox.h>
+#include <qhbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qtimer.h>
+
+#include <kapplication.h>
+#include <kcombobox.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpeffectbalance.h>
+#include <kpeffectblursharpen.h>
+#include <kpeffectemboss.h>
+#include <kpeffectflatten.h>
+#include <kpeffectinvert.h>
+#include <kpeffectreducecolors.h>
+#include <kppixmapfx.h>
+
+
+// protected static
+int kpEffectsDialog::s_lastWidth = 640;
+int kpEffectsDialog::s_lastHeight = 620;
+
+
+kpEffectsDialog::kpEffectsDialog (bool actOnSelection,
+ kpMainWindow *parent,
+ const char *name)
+ : kpToolPreviewDialog (kpToolPreviewDialog::Preview,
+ true/*reserve top row*/,
+ QString::null/*caption*/,
+ QString::null/*afterActionText (no Dimensions Group Box)*/,
+ actOnSelection,
+ parent,
+ name),
+ m_delayedUpdateTimer (new QTimer (this)),
+ m_effectsComboBox (0),
+ m_settingsGroupBox (0),
+ m_settingsLayout (0),
+ m_colorEffectWidget (0)
+{
+#if DEBUG_KP_EFFECTS_DIALOG
+ kdDebug () << "kpEffectsDialog::kpEffectsDialog()" << endl;
+#endif
+
+ if (actOnSelection)
+ setCaption (i18n ("More Image Effects (Selection)"));
+ else
+ setCaption (i18n ("More Image Effects"));
+
+
+ connect (m_delayedUpdateTimer, SIGNAL (timeout ()),
+ this, SLOT (slotUpdateWithWaitCursor ()));
+
+
+ QHBox *effectContainer = new QHBox (mainWidget ());
+ effectContainer->setSpacing (spacingHint () * 4
+ /*need more space for QGroupBox titles*/);
+ effectContainer->setMargin (0);
+
+ QLabel *label = new QLabel (i18n ("&Effect:"), effectContainer);
+
+ m_effectsComboBox = new KComboBox (effectContainer);
+ m_effectsComboBox->insertItem (i18n ("Balance"));
+ m_effectsComboBox->insertItem (i18n ("Emboss"));
+ m_effectsComboBox->insertItem (i18n ("Flatten"));
+ m_effectsComboBox->insertItem (i18n ("Invert"));
+ m_effectsComboBox->insertItem (i18n ("Reduce Colors"));
+ m_effectsComboBox->insertItem (i18n ("Soften & Sharpen"));
+
+ label->setBuddy (m_effectsComboBox);
+ effectContainer->setStretchFactor (m_effectsComboBox, 1);
+
+ addCustomWidgetToFront (effectContainer);
+
+
+ m_settingsGroupBox = new QGroupBox (mainWidget ());
+ m_settingsLayout = new QVBoxLayout (m_settingsGroupBox,
+ marginHint () * 2,
+ spacingHint ());
+ addCustomWidgetToBack (m_settingsGroupBox);
+
+
+ connect (m_effectsComboBox, SIGNAL (activated (int)),
+ this, SLOT (selectEffect (int)));
+ selectEffect (0);
+
+
+ resize (s_lastWidth, s_lastHeight);
+
+
+#if DEBUG_KP_EFFECTS_DIALOG
+ kdDebug () << "\tabout to slotUpdate()" << endl;
+#endif
+ slotUpdate ();
+}
+
+kpEffectsDialog::~kpEffectsDialog ()
+{
+ s_lastWidth = width ();
+ s_lastHeight = height ();
+}
+
+
+// public virtual [base kpToolPreviewDialog]
+bool kpEffectsDialog::isNoOp () const
+{
+ if (!m_colorEffectWidget)
+ return true;
+
+ return m_colorEffectWidget->isNoOp ();
+}
+
+// public
+kpColorEffectCommand *kpEffectsDialog::createCommand () const
+{
+ if (!m_colorEffectWidget)
+ return 0;
+
+ return m_colorEffectWidget->createCommand ();
+}
+
+
+// protected virtual [base kpToolPreviewDialog]
+QSize kpEffectsDialog::newDimensions () const
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return QSize ();
+
+ return QSize (doc->width (m_actOnSelection),
+ doc->height (m_actOnSelection));
+}
+
+// protected virtual [base kpToolPreviewDialog]
+QPixmap kpEffectsDialog::transformPixmap (const QPixmap &pixmap,
+ int targetWidth, int targetHeight) const
+{
+ QPixmap pixmapWithEffect;
+
+ if (m_colorEffectWidget)
+ pixmapWithEffect = m_colorEffectWidget->applyColorEffect (pixmap);
+ else
+ pixmapWithEffect = pixmap;
+
+ return kpPixmapFX::scale (pixmapWithEffect, targetWidth, targetHeight);
+}
+
+
+// public
+int kpEffectsDialog::selectedEffect () const
+{
+ return m_effectsComboBox->currentItem ();
+}
+
+// public slot
+void kpEffectsDialog::selectEffect (int which)
+{
+#if DEBUG_KP_EFFECTS_DIALOG
+ kdDebug () << "kpEffectsDialog::selectEffect(" << which << ")" << endl;
+#endif
+
+ if (which < 0 ||
+ which >= m_effectsComboBox->count ())
+ {
+ return;
+ }
+
+ if (which != m_effectsComboBox->currentItem ())
+ m_effectsComboBox->setCurrentItem (which);
+
+
+ delete m_colorEffectWidget;
+ m_colorEffectWidget = 0;
+
+
+ m_settingsGroupBox->setCaption (QString::null);
+
+#define CREATE_EFFECT_WIDGET(name) \
+ m_colorEffectWidget = new name (m_actOnSelection, \
+ m_mainWindow, \
+ m_settingsGroupBox)
+ switch (which)
+ {
+ case 0:
+ CREATE_EFFECT_WIDGET (kpEffectBalanceWidget);
+ break;
+
+ case 1:
+ CREATE_EFFECT_WIDGET (kpEffectEmbossWidget);
+ break;
+
+ case 2:
+ CREATE_EFFECT_WIDGET (kpEffectFlattenWidget);
+ break;
+
+ case 3:
+ CREATE_EFFECT_WIDGET (kpEffectInvertWidget);
+ break;
+
+ case 4:
+ CREATE_EFFECT_WIDGET (kpEffectReduceColorsWidget);
+ break;
+
+ case 5:
+ CREATE_EFFECT_WIDGET (kpEffectBlurSharpenWidget);
+ break;
+ }
+#undef CREATE_EFFECT_WIDGET
+
+
+ if (m_colorEffectWidget)
+ {
+ #if DEBUG_KP_EFFECTS_DIALOG
+ kdDebug () << "\twidget exists for effect #" << endl;
+ #endif
+ m_settingsGroupBox->setTitle (m_colorEffectWidget->caption ());
+
+
+ // Don't resize the preview when showing the widget:
+ // TODO: actually work
+
+ QSize previewGroupBoxMinSize = m_previewGroupBox->minimumSize ();
+ QSize previewGroupBoxMaxSize = m_previewGroupBox->maximumSize ();
+ QLayout::ResizeMode previewGroupBoxResizeMode =
+ m_previewGroupBox->layout () ?
+ m_previewGroupBox->layout ()->resizeMode () :
+ QLayout::Auto;
+ #if DEBUG_KP_EFFECTS_DIALOG
+ kdDebug () << "\tpreviewGroupBox: minSize=" << previewGroupBoxMinSize
+ << " maxSize=" << previewGroupBoxMaxSize
+ << " size=" << m_previewGroupBox->size ()
+ << " layout=" << m_previewGroupBox->layout ()
+ << " resizeMode=" << previewGroupBoxResizeMode
+ << endl;
+ #endif
+
+ if (m_previewGroupBox->layout ())
+ m_previewGroupBox->layout ()->setResizeMode (QLayout::FreeResize);
+ #if DEBUG_KP_EFFECTS_DIALOG
+ kdDebug () << "\tafter set resizeMode, previewGroupBox.size="
+ << m_previewGroupBox->size () << endl;
+ #endif
+ m_previewGroupBox->setFixedSize (m_previewGroupBox->size ());
+ #if DEBUG_KP_EFFECTS_DIALOG
+ kdDebug () << "\tafter set fixedSize, previewGroupBox.size="
+ << m_previewGroupBox->size () << endl;
+ #endif
+
+ // Show widget
+ m_settingsLayout->addWidget (m_colorEffectWidget);
+ #if DEBUG_KP_EFFECTS_DIALOG
+ kdDebug () << "\tafter addWidget, previewGroupBox.size="
+ << m_previewGroupBox->size () << endl;
+ #endif
+ m_colorEffectWidget->show ();
+ #if DEBUG_KP_EFFECTS_DIALOG
+ kdDebug () << "\tafter addWidget show, previewGroupBox.size="
+ << m_previewGroupBox->size () << endl;
+ #endif
+
+ m_previewGroupBox->setMinimumSize (previewGroupBoxMinSize);
+ m_previewGroupBox->setMaximumSize (previewGroupBoxMaxSize);
+ #if DEBUG_KP_EFFECTS_DIALOG
+ kdDebug () << "\tafter set fixedSize, previewGroupBox.size="
+ << m_previewGroupBox->size () << endl;
+ #endif
+ if (m_previewGroupBox->layout ())
+ m_previewGroupBox->layout ()->setResizeMode (previewGroupBoxResizeMode);
+ #if DEBUG_KP_EFFECTS_DIALOG
+ kdDebug () << "\tafter restore resizeMode, previewGroupBox.size="
+ << m_previewGroupBox->size () << endl;
+ #endif
+
+
+ connect (m_colorEffectWidget, SIGNAL (settingsChangedNoWaitCursor ()),
+ this, SLOT (slotUpdate ()));
+ connect (m_colorEffectWidget, SIGNAL (settingsChanged ()),
+ this, SLOT (slotUpdateWithWaitCursor ()));
+ connect (m_colorEffectWidget, SIGNAL (settingsChangedDelayed ()),
+ this, SLOT (slotDelayedUpdate ()));
+ slotUpdateWithWaitCursor ();
+ #if DEBUG_KP_EFFECTS_DIALOG
+ kdDebug () << "\tafter slotUpdateWithWaitCursor, previewGroupBox.size="
+ << m_previewGroupBox->size () << endl;
+ #endif
+ }
+}
+
+
+// protected slot virtual [base kpToolPreviewDialog]
+void kpEffectsDialog::slotUpdate ()
+{
+#if DEBUG_KP_EFFECTS_DIALOG
+ kdDebug () << "kpEffectsDialog::slotUpdate()"
+ << " timerActive=" << m_delayedUpdateTimer->isActive ()
+ << endl;
+#endif
+
+ m_delayedUpdateTimer->stop ();
+
+ kpToolPreviewDialog::slotUpdate ();
+}
+
+// protected slot virtual [base kpToolPreviewDialog]
+void kpEffectsDialog::slotUpdateWithWaitCursor ()
+{
+#if DEBUG_KP_EFFECTS_DIALOG
+ kdDebug () << "kpEffectsDialog::slotUpdateWithWaitCursor()"
+ << " timerActive=" << m_delayedUpdateTimer->isActive ()
+ << endl;
+#endif
+
+ m_delayedUpdateTimer->stop ();
+
+ kpToolPreviewDialog::slotUpdateWithWaitCursor ();
+}
+
+
+// protected slot
+void kpEffectsDialog::slotDelayedUpdate ()
+{
+#if DEBUG_KP_EFFECTS_DIALOG
+ kdDebug () << "kpEffectsDialog::slotDelayedUpdate()"
+ << " timerActive=" << m_delayedUpdateTimer->isActive ()
+ << endl;
+#endif
+ m_delayedUpdateTimer->stop ();
+
+ m_delayedUpdateTimer->start (400/*ms*/, true/*single shot*/);
+}
+
+
+#include <kpeffectsdialog.moc>
diff --git a/kolourpaint/pixmapfx/kpeffectsdialog.h b/kolourpaint/pixmapfx/kpeffectsdialog.h
new file mode 100644
index 00000000..fe7265cc
--- /dev/null
+++ b/kolourpaint/pixmapfx/kpeffectsdialog.h
@@ -0,0 +1,90 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef KP_EFFECTS_DIALOG_H
+#define KP_EFFECTS_DIALOG_H
+
+
+#include <kptoolpreviewdialog.h>
+
+
+class QGroupBox;
+class QStringList;
+class QTimer;
+class QVBoxLayout;
+
+class KComboBox;
+
+class kpColorEffectCommand;
+class kpColorEffectWidget;
+class kpMainWindow;
+
+
+class kpEffectsDialog : public kpToolPreviewDialog
+{
+Q_OBJECT
+
+public:
+ kpEffectsDialog (bool actOnSelection,
+ kpMainWindow *parent,
+ const char *name = 0);
+ virtual ~kpEffectsDialog ();
+
+ virtual bool isNoOp () const;
+ kpColorEffectCommand *createCommand () const;
+
+protected:
+ virtual QSize newDimensions () const;
+ virtual QPixmap transformPixmap (const QPixmap &pixmap,
+ int targetWidth, int targetHeight) const;
+
+public:
+ int selectedEffect () const;
+public slots:
+ void selectEffect (int which);
+
+protected slots:
+ virtual void slotUpdate ();
+ virtual void slotUpdateWithWaitCursor ();
+
+ void slotDelayedUpdate ();
+
+protected:
+ static int s_lastWidth, s_lastHeight;
+
+ QTimer *m_delayedUpdateTimer;
+
+ KComboBox *m_effectsComboBox;
+ QGroupBox *m_settingsGroupBox;
+ QVBoxLayout *m_settingsLayout;
+
+ kpColorEffectWidget *m_colorEffectWidget;
+};
+
+
+#endif // KP_EFFECTS_DIALOG_H
diff --git a/kolourpaint/pixmapfx/kpfloodfill.cpp b/kolourpaint/pixmapfx/kpfloodfill.cpp
new file mode 100644
index 00000000..602e8acf
--- /dev/null
+++ b/kolourpaint/pixmapfx/kpfloodfill.cpp
@@ -0,0 +1,362 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_FLOOD_FILL 0
+
+
+#include <kpfloodfill.h>
+
+#include <qapplication.h>
+#include <qbitmap.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+
+#include <kdebug.h>
+#include <kpdefs.h>
+
+#include <kppixmapfx.h>
+#include <kptool.h>
+
+
+kpFloodFill::kpFloodFill (QPixmap *pixmap, int x, int y,
+ const kpColor &color, int processedColorSimilarity)
+ : m_pixmapPtr (pixmap), m_x (x), m_y (y),
+ m_color (color), m_processedColorSimilarity (processedColorSimilarity),
+ m_initState (0)
+{
+}
+
+kpFloodFill::~kpFloodFill ()
+{
+}
+
+
+// private
+int kpFloodFill::fillLinesListSize (const QValueList <kpFloodFill::FillLine> &fillLines) const
+{
+ return (fillLines.size () * kpFloodFill::FillLine::size ());
+}
+
+// public
+int kpFloodFill::size () const
+{
+ int fillLinesCacheSize = 0;
+ for (QValueVector < QValueList <kpFloodFill::FillLine > >::const_iterator it = m_fillLinesCache.begin ();
+ it != m_fillLinesCache.end ();
+ it++)
+ {
+ fillLinesCacheSize += fillLinesListSize (*it);
+ }
+
+ return fillLinesListSize (m_fillLines) +
+ kpPixmapFX::imageSize (m_image) +
+ fillLinesCacheSize;
+}
+
+
+QRect kpFloodFill::boundingRect () const
+{
+ return m_boundingRect;
+}
+
+bool kpFloodFill::fill ()
+{
+ if (m_initState < 2 && !prepare ())
+ {
+ kdError () << "kpFloodFill:fill() could not prepare()!" << endl;
+ return false;
+ }
+
+ // not trying to do a NOP fill
+ if (m_boundingRect.isValid ())
+ {
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ QPainter painter, maskPainter;
+ QBitmap maskBitmap;
+
+ if (m_pixmapPtr->mask () || m_color.isTransparent ())
+ {
+ maskBitmap = kpPixmapFX::getNonNullMask (*m_pixmapPtr);
+ maskPainter.begin (&maskBitmap);
+ maskPainter.setPen (m_color.maskColor ());
+ }
+
+ if (m_color.isOpaque ())
+ {
+ painter.begin (m_pixmapPtr);
+ painter.setPen (m_color.toQColor ());
+ }
+
+ const QValueList <FillLine>::ConstIterator fillLinesEnd = m_fillLines.end ();
+ for (QValueList <FillLine>::ConstIterator it = m_fillLines.begin ();
+ it != fillLinesEnd;
+ it++)
+ {
+ QPoint p1 = QPoint ((*it).m_x1, (*it).m_y);
+ QPoint p2 = QPoint ((*it).m_x2, (*it).m_y);
+
+ if (painter.isActive ())
+ painter.drawLine (p1, p2);
+
+ if (maskPainter.isActive ())
+ maskPainter.drawLine (p1, p2);
+ }
+
+ if (painter.isActive ())
+ painter.end ();
+
+ if (maskPainter.isActive ())
+ maskPainter.end ();
+
+ if (!maskBitmap.isNull ())
+ m_pixmapPtr->setMask (maskBitmap);
+
+ QApplication::restoreOverrideCursor ();
+ }
+ else
+ {
+ #if DEBUG_KP_FLOOD_FILL && 1
+ kdDebug () << "kpFloodFill::fill() performing NOP fill" << endl;
+ #endif
+ }
+
+ return true;
+}
+
+bool kpFloodFill::prepareColorToChange ()
+{
+#if DEBUG_KP_FLOOD_FILL && 1
+ kdDebug () << "kpFloodFill::prepareColorToChange" << endl;
+#endif
+
+ m_colorToChange = kpPixmapFX::getColorAtPixel (*m_pixmapPtr, QPoint (m_x, m_y));
+
+ if (m_colorToChange.isOpaque ())
+ {
+ #if DEBUG_KP_FLOOD_FILL && 1
+ kdDebug () << "\tcolorToChange: r=" << m_colorToChange.red ()
+ << ", b=" << m_colorToChange.blue ()
+ << ", g=" << m_colorToChange.green ()
+ << endl;
+ #endif
+ }
+ else
+ {
+ #if DEBUG_KP_FLOOD_FILL && 1
+ kdDebug () << "\tcolorToChange: transparent" << endl;
+ #endif
+ }
+
+ m_initState = 1;
+ return true;
+}
+
+// Derived from the zSprite2 Graphics Engine
+
+bool kpFloodFill::prepare ()
+{
+#if DEBUG_KP_FLOOD_FILL && 1
+ kdDebug () << "kpFloodFill::prepare()" << endl;
+#endif
+ m_boundingRect = QRect ();
+
+ if (m_initState < 1 && !prepareColorToChange ())
+ {
+ kdError () << "kpFloodFill:prepare() could not prepareColorToChange()!" << endl;
+ return false;
+ }
+
+#if DEBUG_KP_FLOOD_FILL && 1
+ kdDebug () << "\tperforming NOP check" << endl;
+#endif
+
+ // get the color we need to replace
+ if (m_processedColorSimilarity == 0 && m_color == m_colorToChange)
+ {
+ // need to do absolutely nothing (this is a significant optimisation
+ // for people who randomly click a lot over already-filled areas)
+ m_initState = 2; // sync with all "return true"'s
+ return true;
+ }
+
+#if DEBUG_KP_FLOOD_FILL && 1
+ kdDebug () << "\tconverting to image" << endl;
+#endif
+
+ // is this the only way to read pixels?
+ m_image = kpPixmapFX::convertToImage (*m_pixmapPtr);
+ if (m_image.isNull ())
+ {
+ kdError () << "kpFloodFill::prepare() could not convert to QImage" << endl;
+ return false;
+ }
+
+#if DEBUG_KP_FLOOD_FILL && 1
+ kdDebug () << "\tcreating fillLinesCache" << endl;
+#endif
+
+ // ready cache
+ m_fillLinesCache.resize (m_pixmapPtr->height ());
+
+#if DEBUG_KP_FLOOD_FILL && 1
+ kdDebug () << "\tcreating fill lines" << endl;
+#endif
+
+ // draw initial line
+ addLine (m_y, findMinX (m_y, m_x), findMaxX (m_y, m_x));
+
+ for (QValueList <FillLine>::ConstIterator it = m_fillLines.begin ();
+ it != m_fillLines.end ();
+ it++)
+ {
+ #if DEBUG_KP_FLOOD_FILL && 0
+ kdDebug () << "Expanding from y=" << (*it).m_y
+ << " x1=" << (*it).m_x1
+ << " x2=" << (*it).m_x2
+ << endl;
+ #endif
+
+ // make more lines above and below current line
+ findAndAddLines (*it, -1);
+ findAndAddLines (*it, +1);
+ }
+
+#if DEBUG_KP_FLOOD_FILL && 1
+ kdDebug () << "\tfinalising memory usage" << endl;
+#endif
+
+ // finalize memory usage
+ m_image.reset ();
+ m_fillLinesCache.clear ();
+
+ m_initState = 2; // sync with all "return true"'s
+ return true;
+}
+
+void kpFloodFill::addLine (int y, int x1, int x2)
+{
+#if DEBUG_KP_FLOOD_FILL && 0
+ kdDebug () << "kpFillCommand::fillAddLine (" << y << "," << x1 << "," << x2 << ")" << endl;
+#endif
+
+ m_fillLines.append (FillLine (y, x1, x2));
+ m_fillLinesCache [y].append (FillLine (y /* OPT */, x1, x2));
+ m_boundingRect = m_boundingRect.unite (QRect (QPoint (x1, y), QPoint (x2, y)));
+}
+
+kpColor kpFloodFill::pixelColor (int x, int y, bool *beenHere) const
+{
+ if (beenHere)
+ *beenHere = false;
+
+ if (y >= (int) m_fillLinesCache.count ())
+ {
+ kdError () << "kpFloodFill::pixelColor("
+ << x << ","
+ << y << ") y out of range=" << m_pixmapPtr->height () << endl;
+ return kpColor::invalid;
+ }
+
+ const QValueList <FillLine>::ConstIterator theEnd = m_fillLinesCache [y].end ();
+ for (QValueList <FillLine>::ConstIterator it = m_fillLinesCache [y].begin ();
+ it != theEnd;
+ it++)
+ {
+ if (x >= (*it).m_x1 && x <= (*it).m_x2)
+ {
+ if (beenHere)
+ *beenHere = true;
+ return m_color;
+ }
+ }
+
+ return kpPixmapFX::getColorAtPixel (m_image, QPoint (x, y));
+}
+
+bool kpFloodFill::shouldGoTo (int x, int y) const
+{
+ bool beenThere;
+ const kpColor col = pixelColor (x, y, &beenThere);
+
+ return (!beenThere && col.isSimilarTo (m_colorToChange, m_processedColorSimilarity));
+}
+
+void kpFloodFill::findAndAddLines (const FillLine &fillLine, int dy)
+{
+ // out of bounds?
+ if (fillLine.m_y + dy < 0 || fillLine.m_y + dy >= m_pixmapPtr->height ())
+ return;
+
+ for (int xnow = fillLine.m_x1; xnow <= fillLine.m_x2; xnow++)
+ {
+ // At current position, right colour?
+ if (shouldGoTo (xnow, fillLine.m_y + dy))
+ {
+ // Find minimum and maximum x values
+ int minxnow = findMinX (fillLine.m_y + dy, xnow);
+ int maxxnow = findMaxX (fillLine.m_y + dy, xnow);
+
+ // Draw line
+ addLine (fillLine.m_y + dy, minxnow, maxxnow);
+
+ // Move x pointer
+ xnow = maxxnow;
+ }
+ }
+}
+
+// finds the minimum x value at a certain line to be filled
+int kpFloodFill::findMinX (int y, int x) const
+{
+ for (;;)
+ {
+ if (x < 0)
+ return 0;
+
+ if (shouldGoTo (x, y))
+ x--;
+ else
+ return x + 1;
+ }
+}
+
+// finds the maximum x value at a certain line to be filled
+int kpFloodFill::findMaxX (int y, int x) const
+{
+ for (;;)
+ {
+ if (x > m_pixmapPtr->width () - 1)
+ return m_pixmapPtr->width () - 1;
+
+ if (shouldGoTo (x, y))
+ x++;
+ else
+ return x - 1;
+ }
+}
diff --git a/kolourpaint/pixmapfx/kpfloodfill.h b/kolourpaint/pixmapfx/kpfloodfill.h
new file mode 100644
index 00000000..5c0d8001
--- /dev/null
+++ b/kolourpaint/pixmapfx/kpfloodfill.h
@@ -0,0 +1,106 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kpfloodfill_h__
+#define __kpfloodfill_h__
+
+#include <qimage.h>
+#include <qvaluelist.h>
+#include <qvaluevector.h>
+
+#include <kpcolor.h>
+
+class QPixmap;
+
+class kpFloodFill
+{
+public:
+ kpFloodFill (QPixmap *pixmap, int x, int y,
+ const kpColor &color,
+ int processedColorSimilarity);
+ ~kpFloodFill ();
+
+ int size () const;
+
+ kpColor color () const { return m_color; }
+ int processedColorSimilarity () const { return m_processedColorSimilarity; }
+
+ // you should call [prepareColorToChange(),[prepare(),[fill()]]]
+ bool prepareColorToChange ();
+
+ // (only valid after prepareColorToChange())
+ kpColor colorToChange () const { return m_colorToChange; };
+
+ bool prepare ();
+ QRect boundingRect () const; // only valid after prepare()
+
+ bool fill ();
+
+private:
+ QPixmap *m_pixmapPtr;
+ int m_x, m_y;
+ kpColor m_color;
+ int m_processedColorSimilarity;
+
+ int m_initState;
+
+ QRect m_boundingRect;
+
+ struct FillLine
+ {
+ FillLine (int y = -1, int x1 = -1, int x2 = -1)
+ : m_y (y), m_x1 (x1), m_x2 (x2)
+ {
+ }
+
+ static int size ()
+ {
+ return sizeof (FillLine);
+ }
+
+ int m_y, m_x1, m_x2;
+ };
+
+ int fillLinesListSize (const QValueList <kpFloodFill::FillLine> &fillLines) const;
+
+ void addLine (int y, int x1, int x2);
+ kpColor pixelColor (int x, int y, bool *beenHere = 0) const;
+ bool shouldGoTo (int x, int y) const;
+ void findAndAddLines (const FillLine &fillLine, int dy);
+ int findMinX (int y, int x) const;
+ int findMaxX (int y, int x) const;
+
+ QValueList <FillLine> m_fillLines;
+
+ // Init info
+ QImage m_image;
+ QValueVector < QValueList <FillLine> > m_fillLinesCache;
+ kpColor m_colorToChange;
+};
+
+#endif // __kpfloodfill_h__
diff --git a/kolourpaint/pixmapfx/kppixmapfx.cpp b/kolourpaint/pixmapfx/kppixmapfx.cpp
new file mode 100644
index 00000000..1bd0b173
--- /dev/null
+++ b/kolourpaint/pixmapfx/kppixmapfx.cpp
@@ -0,0 +1,1677 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_PIXMAP_FX 0
+
+
+#include <kppixmapfx.h>
+
+#include <math.h>
+
+#include <qapplication.h>
+#include <qbitmap.h>
+#include <qdatetime.h>
+#include <qimage.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qpoint.h>
+#include <qpointarray.h>
+#include <qrect.h>
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include <kpcolor.h>
+#include <kpdefs.h>
+#include <kpselection.h>
+#include <kptool.h>
+
+
+//
+// Overflow Resistant Arithmetic:
+//
+
+// public static
+int kpPixmapFX::addDimensions (int lhs, int rhs)
+{
+ if (lhs < 0 || rhs < 0 ||
+ lhs > INT_MAX - rhs)
+ {
+ return INT_MAX;
+ }
+
+ return lhs + rhs;
+}
+
+// public static
+int kpPixmapFX::multiplyDimensions (int lhs, int rhs)
+{
+ if (rhs == 0)
+ return 0;
+
+ if (lhs < 0 || rhs < 0 ||
+ lhs > INT_MAX / rhs)
+ {
+ return INT_MAX;
+ }
+
+ return lhs * rhs;
+}
+
+
+//
+// QPixmap Statistics
+//
+
+// public static
+int kpPixmapFX::pixmapArea (const QPixmap &pixmap)
+{
+ return kpPixmapFX::pixmapArea (pixmap.width (), pixmap.height ());
+}
+
+// public static
+int kpPixmapFX::pixmapArea (const QPixmap *pixmap)
+{
+ return (pixmap ? kpPixmapFX::pixmapArea (*pixmap) : 0);
+}
+
+// public static
+int kpPixmapFX::pixmapArea (int width, int height)
+{
+ return multiplyDimensions (width, height);
+}
+
+
+// public static
+int kpPixmapFX::pixmapSize (const QPixmap &pixmap)
+{
+ return kpPixmapFX::pixmapSize (pixmap.width (), pixmap.height (),
+ pixmap.depth ());
+}
+
+// public static
+int kpPixmapFX::pixmapSize (const QPixmap *pixmap)
+{
+ return (pixmap ? kpPixmapFX::pixmapSize (*pixmap) : 0);
+}
+
+// public static
+int kpPixmapFX::pixmapSize (int width, int height, int depth)
+{
+ // handle 15bpp
+ int roundedDepth = (depth > 8 ? (depth + 7) / 8 * 8 : depth);
+
+#if DEBUG_KP_PIXMAP_FX && 0
+ kdDebug () << "kpPixmapFX::pixmapSize() w=" << width
+ << " h=" << height
+ << " d=" << depth
+ << " roundedDepth=" << roundedDepth
+ << " ret="
+ << multiplyDimensions (kpPixmapFX::pixmapArea (width, height), roundedDepth) / 8
+ << endl;
+#endif
+ return multiplyDimensions (kpPixmapFX::pixmapArea (width, height), roundedDepth) / 8;
+}
+
+
+// public static
+int kpPixmapFX::imageSize (const QImage &image)
+{
+ return kpPixmapFX::imageSize (image.width (), image.height (), image.depth ());
+}
+
+// public static
+int kpPixmapFX::imageSize (const QImage *image)
+{
+ return (image ? kpPixmapFX::imageSize (*image) : 0);
+}
+
+// public static
+int kpPixmapFX::imageSize (int width, int height, int depth)
+{
+ // handle 15bpp
+ int roundedDepth = (depth > 8 ? (depth + 7) / 8 * 8 : depth);
+
+#if DEBUG_KP_PIXMAP_FX && 0
+ kdDebug () << "kpPixmapFX::imageSize() w=" << width
+ << " h=" << height
+ << " d=" << depth
+ << " roundedDepth=" << roundedDepth
+ << " ret="
+ << multiplyDimensions (multiplyDimensions (width, height), roundedDepth) / 8
+ << endl;
+#endif
+
+ return multiplyDimensions (multiplyDimensions (width, height), roundedDepth) / 8;
+}
+
+
+// public static
+int kpPixmapFX::selectionSize (const kpSelection &sel)
+{
+ return sel.size ();
+}
+
+// public static
+int kpPixmapFX::selectionSize (const kpSelection *sel)
+{
+ return (sel ? sel->size () : 0);
+}
+
+
+// public static
+int kpPixmapFX::stringSize (const QString &string)
+{
+#if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "kpPixmapFX::stringSize(" << string << ")"
+ << " len=" << string.length ()
+ << " sizeof(QChar)=" << sizeof (QChar)
+ << endl;
+#endif
+ return string.length () * sizeof (QChar);
+}
+
+
+// public static
+int kpPixmapFX::pointArraySize (const QPointArray &points)
+{
+#if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "kpPixmapFX::pointArraySize() points.size="
+ << points.size ()
+ << " sizeof(QPoint)=" << sizeof (QPoint)
+ << endl;
+#endif
+
+ return (points.size () * sizeof (QPoint));
+}
+
+
+//
+// QPixmap/QImage Conversion Functions
+//
+
+// public static
+QImage kpPixmapFX::convertToImage (const QPixmap &pixmap)
+{
+ if (pixmap.isNull ())
+ return QImage ();
+
+ return pixmap.convertToImage ();
+}
+
+
+// Returns true if <image> contains translucency (rather than just transparency)
+// QPixmap::hasAlphaChannel() appears to give incorrect results
+static bool imageHasAlphaChannel (const QImage &image)
+{
+ if (image.depth () < 32)
+ return false;
+
+ for (int y = 0; y < image.height (); y++)
+ {
+ for (int x = 0; x < image.width (); x++)
+ {
+ const QRgb rgb = image.pixel (x, y);
+
+ if (qAlpha (rgb) > 0 && qAlpha (rgb) < 255)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static int imageNumColorsUpTo (const QImage &image, int max)
+{
+ QMap <QRgb, bool> rgbMap;
+
+ if (image.depth () <= 8)
+ {
+ for (int i = 0; i < image.numColors () && (int) rgbMap.size () < max; i++)
+ {
+ rgbMap.insert (image.color (i), true);
+ }
+ }
+ else
+ {
+ for (int y = 0; y < image.height () && (int) rgbMap.size () < max; y++)
+ {
+ for (int x = 0; x < image.width () && (int) rgbMap.size () < max; x++)
+ {
+ rgbMap.insert (image.pixel (x, y), true);
+ }
+ }
+ }
+
+ return rgbMap.size ();
+}
+
+static void convertToPixmapWarnAboutLoss (const QImage &image,
+ const kpPixmapFX::WarnAboutLossInfo &wali)
+{
+ if (!wali.isValid ())
+ return;
+
+
+ const QString colorDepthTranslucencyDontAskAgain =
+ wali.m_dontAskAgainPrefix + "_ColorDepthTranslucency";
+ const QString colorDepthDontAskAgain =
+ wali.m_dontAskAgainPrefix + "_ColorDepth";
+ const QString translucencyDontAskAgain =
+ wali.m_dontAskAgainPrefix + "_Translucency";
+
+#if DEBUG_KP_PIXMAP_FX && 1
+ QTime timer;
+ timer.start ();
+#endif
+
+ bool hasAlphaChannel =
+ (KMessageBox::shouldBeShownContinue (translucencyDontAskAgain) &&
+ imageHasAlphaChannel (image));
+
+#if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "\twarnAboutLoss - check hasAlphaChannel took "
+ << timer.restart () << "msec" << endl;
+#endif
+
+ bool moreColorsThanDisplay =
+ (KMessageBox::shouldBeShownContinue (colorDepthDontAskAgain) &&
+ image.depth () > QColor::numBitPlanes () &&
+ QColor::numBitPlanes () < 24); // 32 indicates alpha channel
+
+ int screenDepthNeeded = 0;
+
+ if (moreColorsThanDisplay)
+ screenDepthNeeded = QMIN (24, image.depth ());
+
+#if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "\ttranslucencyShouldBeShown="
+ << KMessageBox::shouldBeShownContinue (translucencyDontAskAgain)
+ << endl
+ << "\thasAlphaChannel=" << hasAlphaChannel
+ << endl
+ << "\tcolorDepthShownBeShown="
+ << KMessageBox::shouldBeShownContinue (colorDepthDontAskAgain)
+ << endl
+ << "\timage.depth()=" << image.depth ()
+ << endl
+ << "\tscreenDepth=" << QColor::numBitPlanes ()
+ << endl
+ << "\tmoreColorsThanDisplay=" << moreColorsThanDisplay
+ << endl
+ << "\tneedDepth=" << screenDepthNeeded
+ << endl;
+#endif
+
+
+ QApplication::setOverrideCursor (Qt::arrowCursor);
+
+ if (moreColorsThanDisplay && hasAlphaChannel)
+ {
+ KMessageBox::information (wali.m_parent,
+ wali.m_moreColorsThanDisplayAndHasAlphaChannelMessage
+ .arg (screenDepthNeeded),
+ QString::null, // or would you prefer "Low Screen Depth and Image Contains Transparency"? :)
+ colorDepthTranslucencyDontAskAgain);
+
+ if (!KMessageBox::shouldBeShownContinue (colorDepthTranslucencyDontAskAgain))
+ {
+ KMessageBox::saveDontShowAgainContinue (colorDepthDontAskAgain);
+ KMessageBox::saveDontShowAgainContinue (translucencyDontAskAgain);
+ }
+ }
+ else if (moreColorsThanDisplay)
+ {
+ KMessageBox::information (wali.m_parent,
+ wali.m_moreColorsThanDisplayMessage
+ .arg (screenDepthNeeded),
+ i18n ("Low Screen Depth"),
+ colorDepthDontAskAgain);
+ }
+ else if (hasAlphaChannel)
+ {
+ KMessageBox::information (wali.m_parent,
+ wali.m_hasAlphaChannelMessage,
+ i18n ("Image Contains Translucency"),
+ translucencyDontAskAgain);
+ }
+
+ QApplication::restoreOverrideCursor ();
+}
+
+// public static
+QPixmap kpPixmapFX::convertToPixmap (const QImage &image, bool pretty,
+ const WarnAboutLossInfo &wali)
+{
+#if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "kpPixmapFX::convertToPixmap(image,pretty=" << pretty
+ << ",warnAboutLossInfo.isValid=" << wali.isValid ()
+ << ")" << endl;
+ QTime timer;
+ timer.start ();
+#endif
+
+ if (image.isNull ())
+ return QPixmap ();
+
+
+ QPixmap destPixmap;
+
+ if (!pretty)
+ {
+ destPixmap.convertFromImage (image,
+ Qt::ColorOnly/*always display depth*/ |
+ Qt::ThresholdDither/*no dither*/ |
+ Qt::ThresholdAlphaDither/*no dither alpha*/|
+ Qt::AvoidDither);
+ }
+ else
+ {
+ destPixmap.convertFromImage (image,
+ Qt::ColorOnly/*always display depth*/ |
+ Qt::DiffuseDither/*hi quality dither*/ |
+ Qt::ThresholdAlphaDither/*no dither alpha*/ |
+ Qt::PreferDither/*(dither even if <256 colours)*/);
+ }
+
+#if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "\tconversion took " << timer.elapsed () << "msec" << endl;
+#endif
+
+ kpPixmapFX::ensureNoAlphaChannel (&destPixmap);
+
+
+ if (wali.isValid ())
+ convertToPixmapWarnAboutLoss (image, wali);
+
+
+ return destPixmap;
+}
+
+// TODO: don't dup convertToPixmap() code
+// public static
+QPixmap kpPixmapFX::convertToPixmapAsLosslessAsPossible (const QImage &image,
+ const WarnAboutLossInfo &wali)
+{
+#if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "kpPixmapFX::convertToPixmapAsLosslessAsPossible(image depth="
+ << image.depth ()
+ << ",warnAboutLossInfo.isValid=" << wali.isValid ()
+ << ") screenDepth=" << QPixmap::defaultDepth ()
+ << " imageNumColorsUpTo257=" << imageNumColorsUpTo (image, 257)
+ << endl;
+ QTime timer;
+ timer.start ();
+#endif
+
+ if (image.isNull ())
+ return QPixmap ();
+
+
+ const int screenDepth = (QPixmap::defaultDepth () >= 24 ?
+ 32 :
+ QPixmap::defaultDepth ());
+
+ QPixmap destPixmap;
+ int ditherFlags = 0;
+
+ if (image.depth () <= screenDepth)
+ {
+ #if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "\timage depth <= screen depth - don't dither"
+ << " (AvoidDither | ThresholdDither)" << endl;
+ #endif
+
+ ditherFlags = (Qt::AvoidDither | Qt::ThresholdDither);
+ }
+ // PRE: image.depth() > screenDepth
+ // ASSERT: screenDepth < 32
+ else if (screenDepth <= 8)
+ {
+ const int screenNumColors = (1 << screenDepth);
+
+ #if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "\tscreen depth <= 8; imageNumColorsUpTo"
+ << (screenNumColors + 1)
+ << "=" << imageNumColorsUpTo (image, screenNumColors + 1)
+ << endl;
+ #endif
+
+ if (imageNumColorsUpTo (image, screenNumColors + 1) <= screenNumColors)
+ {
+ #if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "\t\tcolors fit on screen - don't dither"
+ << " (AvoidDither | ThresholdDither)" << endl;
+ #endif
+ ditherFlags = (Qt::AvoidDither | Qt::ThresholdDither);
+ }
+ else
+ {
+ #if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "\t\tcolors don't fit on screen - dither"
+ << " (PreferDither | DiffuseDither)" << endl;
+ #endif
+ ditherFlags = (Qt::PreferDither | Qt::DiffuseDither);
+ }
+ }
+ // PRE: image.depth() > screenDepth &&
+ // screenDepth > 8
+ // ASSERT: screenDepth < 32
+ else
+ {
+ #if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "\tscreen depth > 8 - read config" << endl;
+ #endif
+
+ int configDitherIfNumColorsGreaterThan = 323;
+
+ KConfigGroupSaver cfgGroupSaver (KGlobal::config (),
+ kpSettingsGroupGeneral);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ if (cfg->hasKey (kpSettingDitherOnOpen))
+ {
+ configDitherIfNumColorsGreaterThan = cfg->readNumEntry (kpSettingDitherOnOpen);
+ }
+ else
+ {
+ cfg->writeEntry (kpSettingDitherOnOpen, configDitherIfNumColorsGreaterThan);
+ cfg->sync ();
+ }
+
+ #if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "\t\tcfg=" << configDitherIfNumColorsGreaterThan
+ << " image=" << imageNumColorsUpTo (image, configDitherIfNumColorsGreaterThan + 1)
+ << endl;
+ #endif
+
+ if (imageNumColorsUpTo (image, configDitherIfNumColorsGreaterThan + 1) >
+ configDitherIfNumColorsGreaterThan)
+ {
+ #if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "\t\t\talways dither (PreferDither | DiffuseDither)"
+ << endl;
+ #endif
+ ditherFlags = (Qt::PreferDither | Qt::DiffuseDither);
+ }
+ else
+ {
+ #if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "\t\t\tdon't dither (AvoidDither | ThresholdDither)"
+ << endl;
+ #endif
+ ditherFlags = (Qt::AvoidDither | Qt::ThresholdDither);
+ }
+ }
+
+
+ destPixmap.convertFromImage (image,
+ Qt::ColorOnly/*always display depth*/ |
+ Qt::ThresholdAlphaDither/*no dither alpha*/ |
+ ditherFlags);
+
+#if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "\tconversion took " << timer.elapsed () << "msec" << endl;
+#endif
+
+ kpPixmapFX::ensureNoAlphaChannel (&destPixmap);
+
+
+ if (wali.isValid ())
+ convertToPixmapWarnAboutLoss (image, wali);
+
+
+ return destPixmap;
+}
+
+
+// public static
+QPixmap kpPixmapFX::pixmapWithDefinedTransparentPixels (const QPixmap &pixmap,
+ const QColor &transparentColor)
+{
+ if (!pixmap.mask ())
+ return pixmap;
+
+ QPixmap retPixmap (pixmap.width (), pixmap.height ());
+ retPixmap.fill (transparentColor);
+
+ QPainter p (&retPixmap);
+ p.drawPixmap (QPoint (0, 0), pixmap);
+ p.end ();
+
+ retPixmap.setMask (*pixmap.mask ());
+ return retPixmap;
+}
+
+
+//
+// Get/Set Parts of Pixmap
+//
+
+
+// public static
+QPixmap kpPixmapFX::getPixmapAt (const QPixmap &pm, const QRect &rect)
+{
+ QPixmap retPixmap (rect.width (), rect.height ());
+
+#if DEBUG_KP_PIXMAP_FX && 0
+ kdDebug () << "kpPixmapFX::getPixmapAt(pm.hasMask="
+ << (pm.mask () ? 1 : 0)
+ << ",rect="
+ << rect
+ << ")"
+ << endl;
+#endif
+
+ const QRect validSrcRect = pm.rect ().intersect (rect);
+ const bool wouldHaveUndefinedPixels = (validSrcRect != rect);
+
+ if (wouldHaveUndefinedPixels)
+ {
+ #if DEBUG_KP_PIXMAP_FX && 0
+ kdDebug () << "\tret would contain undefined pixels - setting them to transparent" << endl;
+ #endif
+ QBitmap transparentMask (rect.width (), rect.height ());
+ transparentMask.fill (Qt::color0/*transparent*/);
+ retPixmap.setMask (transparentMask);
+ }
+
+ if (validSrcRect.isEmpty ())
+ {
+ #if DEBUG_KP_PIXMAP_FX && 0
+ kdDebug () << "\tsilly case - completely invalid rect - ret transparent pixmap" << endl;
+ #endif
+ return retPixmap;
+ }
+
+
+ const QPoint destTopLeft = validSrcRect.topLeft () - rect.topLeft ();
+
+ // copy data _and_ mask (if avail)
+ copyBlt (&retPixmap, /* dest */
+ destTopLeft.x (), destTopLeft.y (), /* dest pt */
+ &pm, /* src */
+ validSrcRect.x (), validSrcRect.y (), /* src pt */
+ validSrcRect.width (), validSrcRect.height ());
+
+ if (wouldHaveUndefinedPixels && retPixmap.mask () && !pm.mask ())
+ {
+ #if DEBUG_KP_PIXMAP_FX && 0
+ kdDebug () << "\tensure opaque in valid region" << endl;
+ #endif
+ kpPixmapFX::ensureOpaqueAt (&retPixmap,
+ QRect (destTopLeft.x (), destTopLeft.y (),
+ validSrcRect.width (), validSrcRect.height ()));
+ }
+
+#if DEBUG_KP_PIXMAP_FX && 0
+ kdDebug () << "\tretPixmap.hasMask="
+ << (retPixmap.mask () ? 1 : 0)
+ << endl;
+#endif
+
+ return retPixmap;
+}
+
+
+// public static
+void kpPixmapFX::setPixmapAt (QPixmap *destPixmapPtr, const QRect &destRect,
+ const QPixmap &srcPixmap)
+{
+ if (!destPixmapPtr)
+ return;
+
+#if DEBUG_KP_PIXMAP_FX && 0
+ kdDebug () << "kpPixmapFX::setPixmapAt(destPixmap->rect="
+ << destPixmapPtr->rect ()
+ << ",destPixmap->hasMask="
+ << (destPixmapPtr->mask () ? 1 : 0)
+ << ",destRect="
+ << destRect
+ << ",srcPixmap.rect="
+ << srcPixmap.rect ()
+ << ",srcPixmap.hasMask="
+ << (srcPixmap.mask () ? 1 : 0)
+ << ")"
+ << endl;
+#endif
+
+#if DEBUG_KP_PIXMAP_FX && 0
+ if (destPixmapPtr->mask ())
+ {
+ QImage image = kpPixmapFX::convertToImage (*destPixmapPtr);
+ int numTrans = 0;
+
+ for (int y = 0; y < image.height (); y++)
+ {
+ for (int x = 0; x < image.width (); x++)
+ {
+ if (qAlpha (image.pixel (x, y)) == 0)
+ numTrans++;
+ }
+ }
+
+ kdDebug () << "\tdestPixmapPtr numTrans=" << numTrans << endl;
+ }
+#endif
+
+#if 0
+ // TODO: why does undo'ing a single pen dot on a transparent pixel,
+ // result in a opaque image, except for that single transparent pixel???
+ // Qt bug on boundary case?
+
+ // copy data _and_ mask
+ copyBlt (destPixmapPtr,
+ destAt.x (), destAt.y (),
+ &srcPixmap,
+ 0, 0,
+ destRect.width (), destRect.height ());
+#else
+ bitBlt (destPixmapPtr,
+ destRect.x (), destRect.y (),
+ &srcPixmap,
+ 0, 0,
+ destRect.width (), destRect.height (),
+ Qt::CopyROP,
+ true/*ignore mask*/);
+
+ if (srcPixmap.mask ())
+ {
+ QBitmap mask = getNonNullMask (*destPixmapPtr);
+ bitBlt (&mask,
+ destRect.x (), destRect.y (),
+ srcPixmap.mask (),
+ 0, 0,
+ destRect.width (), destRect.height (),
+ Qt::CopyROP,
+ true/*ignore mask*/);
+ destPixmapPtr->setMask (mask);
+ }
+#endif
+
+ if (destPixmapPtr->mask () && !srcPixmap.mask ())
+ {
+ #if DEBUG_KP_PIXMAP_FX && 0
+ kdDebug () << "\t\topaque'ing dest rect" << endl;
+ #endif
+ kpPixmapFX::ensureOpaqueAt (destPixmapPtr, destRect);
+ }
+
+#if DEBUG_KP_PIXMAP_FX && 0
+ kdDebug () << "\tdestPixmap->hasMask="
+ << (destPixmapPtr->mask () ? 1 : 0)
+ << endl;
+ if (destPixmapPtr->mask ())
+ {
+ QImage image = kpPixmapFX::convertToImage (*destPixmapPtr);
+ int numTrans = 0;
+
+ for (int y = 0; y < image.height (); y++)
+ {
+ for (int x = 0; x < image.width (); x++)
+ {
+ if (qAlpha (image.pixel (x, y)) == 0)
+ numTrans++;
+ }
+ }
+
+ kdDebug () << "\tdestPixmapPtr numTrans=" << numTrans << endl;
+ }
+#endif
+}
+
+// public static
+void kpPixmapFX::setPixmapAt (QPixmap *destPixmapPtr, const QPoint &destAt,
+ const QPixmap &srcPixmap)
+{
+ kpPixmapFX::setPixmapAt (destPixmapPtr,
+ QRect (destAt.x (), destAt.y (),
+ srcPixmap.width (), srcPixmap.height ()),
+ srcPixmap);
+}
+
+// public static
+void kpPixmapFX::setPixmapAt (QPixmap *destPixmapPtr, int destX, int destY,
+ const QPixmap &srcPixmap)
+{
+ kpPixmapFX::setPixmapAt (destPixmapPtr, QPoint (destX, destY), srcPixmap);
+}
+
+
+// public static
+void kpPixmapFX::paintPixmapAt (QPixmap *destPixmapPtr, const QPoint &destAt,
+ const QPixmap &srcPixmap)
+{
+ if (!destPixmapPtr)
+ return;
+
+ // Copy src (masked by src's mask) on top of dest.
+ bitBlt (destPixmapPtr, /* dest */
+ destAt.x (), destAt.y (), /* dest pt */
+ &srcPixmap, /* src */
+ 0, 0 /* src pt */);
+
+ kpPixmapFX::ensureOpaqueAt (destPixmapPtr, destAt, srcPixmap);
+}
+
+// public static
+void kpPixmapFX::paintPixmapAt (QPixmap *destPixmapPtr, int destX, int destY,
+ const QPixmap &srcPixmap)
+{
+ kpPixmapFX::paintPixmapAt (destPixmapPtr, QPoint (destX, destY), srcPixmap);
+}
+
+
+// public static
+kpColor kpPixmapFX::getColorAtPixel (const QPixmap &pm, const QPoint &at)
+{
+#if DEBUG_KP_PIXMAP_FX && 0
+ kdDebug () << "kpToolColorPicker::colorAtPixel" << p << endl;
+#endif
+
+ if (at.x () < 0 || at.x () >= pm.width () ||
+ at.y () < 0 || at.y () >= pm.height ())
+ {
+ return kpColor::invalid;
+ }
+
+ QPixmap pixmap = getPixmapAt (pm, QRect (at, at));
+ QImage image = kpPixmapFX::convertToImage (pixmap);
+ if (image.isNull ())
+ {
+ kdError () << "kpPixmapFX::getColorAtPixel(QPixmap) could not convert to QImage" << endl;
+ return kpColor::invalid;
+ }
+
+ return getColorAtPixel (image, QPoint (0, 0));
+}
+
+// public static
+kpColor kpPixmapFX::getColorAtPixel (const QPixmap &pm, int x, int y)
+{
+ return kpPixmapFX::getColorAtPixel (pm, QPoint (x, y));
+}
+
+// public static
+kpColor kpPixmapFX::getColorAtPixel (const QImage &img, const QPoint &at)
+{
+ if (!img.valid (at.x (), at.y ()))
+ return kpColor::invalid;
+
+ QRgb rgba = img.pixel (at.x (), at.y ());
+ return kpColor (rgba);
+}
+
+// public static
+kpColor kpPixmapFX::getColorAtPixel (const QImage &img, int x, int y)
+{
+ return kpPixmapFX::getColorAtPixel (img, QPoint (x, y));
+}
+
+
+//
+// Mask Operations
+//
+
+
+// public static
+void kpPixmapFX::ensureNoAlphaChannel (QPixmap *destPixmapPtr)
+{
+ if (destPixmapPtr->hasAlphaChannel ())
+ destPixmapPtr->setMask (kpPixmapFX::getNonNullMask/*just in case*/ (*destPixmapPtr));
+}
+
+
+// public static
+QBitmap kpPixmapFX::getNonNullMask (const QPixmap &pm)
+{
+ if (pm.mask ())
+ return *pm.mask ();
+ else
+ {
+ QBitmap maskBitmap (pm.width (), pm.height ());
+ maskBitmap.fill (Qt::color1/*opaque*/);
+
+ return maskBitmap;
+ }
+}
+
+
+// public static
+void kpPixmapFX::ensureTransparentAt (QPixmap *destPixmapPtr, const QRect &destRect)
+{
+ if (!destPixmapPtr)
+ return;
+
+ QBitmap maskBitmap = getNonNullMask (*destPixmapPtr);
+
+ QPainter p (&maskBitmap);
+
+ p.setPen (Qt::color0/*transparent*/);
+ p.setBrush (Qt::color0/*transparent*/);
+
+ p.drawRect (destRect);
+
+ p.end ();
+
+ destPixmapPtr->setMask (maskBitmap);
+}
+
+
+// public static
+void kpPixmapFX::paintMaskTransparentWithBrush (QPixmap *destPixmapPtr, const QPoint &destAt,
+ const QPixmap &brushBitmap)
+{
+ if (!destPixmapPtr)
+ return;
+
+ if (brushBitmap.depth () > 1)
+ {
+ kdError () << "kpPixmapFX::paintMaskTransparentWidthBrush() passed brushPixmap with depth > 1" << endl;
+ return;
+ }
+
+ QBitmap destMaskBitmap = kpPixmapFX::getNonNullMask (*destPixmapPtr);
+
+ // Src
+ // Dest Mask Brush Bitmap = Result
+ // -------------------------------------
+ // 0 0 0
+ // 0 1 0
+ // 1 0 1
+ // 1 1 0
+ //
+ // Brush Bitmap value of 1 means "make transparent"
+ // 0 means "leave it as it is"
+
+ bitBlt (&destMaskBitmap,
+ destAt.x (), destAt.y (),
+ &brushBitmap,
+ 0, 0,
+ brushBitmap.width (), brushBitmap.height (),
+ Qt::NotAndROP);
+
+ destPixmapPtr->setMask (destMaskBitmap);
+}
+
+// public static
+void kpPixmapFX::paintMaskTransparentWithBrush (QPixmap *destPixmapPtr, int destX, int destY,
+ const QPixmap &brushBitmap)
+{
+ kpPixmapFX::paintMaskTransparentWithBrush (destPixmapPtr,
+ QPoint (destX, destY),
+ brushBitmap);
+}
+
+
+// public static
+void kpPixmapFX::ensureOpaqueAt (QPixmap *destPixmapPtr, const QRect &destRect)
+{
+ if (!destPixmapPtr || !destPixmapPtr->mask ()/*already opaque*/)
+ return;
+
+ QBitmap maskBitmap = *destPixmapPtr->mask ();
+
+ QPainter p (&maskBitmap);
+
+ p.setPen (Qt::color1/*opaque*/);
+ p.setBrush (Qt::color1/*opaque*/);
+
+ p.drawRect (destRect);
+
+ p.end ();
+
+ destPixmapPtr->setMask (maskBitmap);
+}
+
+// public static
+void kpPixmapFX::ensureOpaqueAt (QPixmap *destPixmapPtr, const QPoint &destAt,
+ const QPixmap &srcPixmap)
+{
+ if (!destPixmapPtr || !destPixmapPtr->mask ()/*already opaque*/)
+ return;
+
+ QBitmap destMask = *destPixmapPtr->mask ();
+
+ if (srcPixmap.mask ())
+ {
+ bitBlt (&destMask, /* dest */
+ destAt, /* dest pt */
+ srcPixmap.mask (), /* src */
+ QRect (0, 0, srcPixmap.width (), srcPixmap.height ()), /* src rect */
+ Qt::OrROP/*if either is opaque, it's opaque*/);
+ }
+ else
+ {
+ QPainter p (&destMask);
+
+ p.setPen (Qt::color1/*opaque*/);
+ p.setBrush (Qt::color1/*opaque*/);
+
+ p.drawRect (destAt.x (), destAt.y (),
+ srcPixmap.width (), srcPixmap.height ());
+
+ p.end ();
+ }
+
+ destPixmapPtr->setMask (destMask);
+}
+
+// public static
+void kpPixmapFX::ensureOpaqueAt (QPixmap *destPixmapPtr, int destX, int destY,
+ const QPixmap &srcPixmap)
+{
+ kpPixmapFX::ensureOpaqueAt (destPixmapPtr, QPoint (destX, destY), srcPixmap);
+}
+
+
+//
+// Effects
+//
+
+// public static
+void kpPixmapFX::convertToGrayscale (QPixmap *destPixmapPtr)
+{
+ QImage image = kpPixmapFX::convertToImage (*destPixmapPtr);
+ kpPixmapFX::convertToGrayscale (&image);
+ *destPixmapPtr = kpPixmapFX::convertToPixmap (image);
+}
+
+// public static
+QPixmap kpPixmapFX::convertToGrayscale (const QPixmap &pm)
+{
+ QImage image = kpPixmapFX::convertToImage (pm);
+ kpPixmapFX::convertToGrayscale (&image);
+ return kpPixmapFX::convertToPixmap (image);
+}
+
+static QRgb toGray (QRgb rgb)
+{
+ // naive way that doesn't preserve brightness
+ // int gray = (qRed (rgb) + qGreen (rgb) + qBlue (rgb)) / 3;
+
+ // over-exaggerates red & blue
+ // int gray = qGray (rgb);
+
+ int gray = (212671 * qRed (rgb) + 715160 * qGreen (rgb) + 72169 * qBlue (rgb)) / 1000000;
+ return qRgba (gray, gray, gray, qAlpha (rgb));
+}
+
+// public static
+void kpPixmapFX::convertToGrayscale (QImage *destImagePtr)
+{
+ if (destImagePtr->depth () > 8)
+ {
+ // hmm, why not just write to the pixmap directly???
+
+ for (int y = 0; y < destImagePtr->height (); y++)
+ {
+ for (int x = 0; x < destImagePtr->width (); x++)
+ {
+ destImagePtr->setPixel (x, y, toGray (destImagePtr->pixel (x, y)));
+ }
+ }
+ }
+ else
+ {
+ // 1- & 8- bit images use a color table
+ for (int i = 0; i < destImagePtr->numColors (); i++)
+ destImagePtr->setColor (i, toGray (destImagePtr->color (i)));
+ }
+}
+
+// public static
+QImage kpPixmapFX::convertToGrayscale (const QImage &img)
+{
+ QImage retImage = img;
+ kpPixmapFX::convertToGrayscale (&retImage);
+ return retImage;
+}
+
+
+// public static
+void kpPixmapFX::fill (QPixmap *destPixmapPtr, const kpColor &color)
+{
+ if (!destPixmapPtr)
+ return;
+
+ if (color.isOpaque ())
+ {
+ destPixmapPtr->setMask (QBitmap ()); // no mask = opaque
+ destPixmapPtr->fill (color.toQColor ());
+ }
+ else
+ {
+ kpPixmapFX::ensureTransparentAt (destPixmapPtr, destPixmapPtr->rect ());
+ }
+}
+
+// public static
+QPixmap kpPixmapFX::fill (const QPixmap &pm, const kpColor &color)
+{
+ QPixmap ret = pm;
+ kpPixmapFX::fill (&ret, color);
+ return ret;
+}
+
+
+// public static
+void kpPixmapFX::resize (QPixmap *destPixmapPtr, int w, int h,
+ const kpColor &backgroundColor, bool fillNewAreas)
+{
+#if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "kpPixmapFX::resize()" << endl;
+#endif
+
+ if (!destPixmapPtr)
+ return;
+
+ int oldWidth = destPixmapPtr->width ();
+ int oldHeight = destPixmapPtr->height ();
+
+ if (w == oldWidth && h == oldHeight)
+ return;
+
+
+ destPixmapPtr->resize (w, h);
+
+ if (fillNewAreas && (w > oldWidth || h > oldHeight))
+ {
+ #if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "\tfilling in new areas" << endl;
+ #endif
+ QBitmap maskBitmap;
+ QPainter painter, maskPainter;
+
+ if (backgroundColor.isOpaque ())
+ {
+ painter.begin (destPixmapPtr);
+ painter.setPen (backgroundColor.toQColor ());
+ painter.setBrush (backgroundColor.toQColor ());
+ }
+
+ if (backgroundColor.isTransparent () || destPixmapPtr->mask ())
+ {
+ maskBitmap = kpPixmapFX::getNonNullMask (*destPixmapPtr);
+ maskPainter.begin (&maskBitmap);
+ maskPainter.setPen (backgroundColor.maskColor ());
+ maskPainter.setBrush (backgroundColor.maskColor ());
+ }
+
+ #define PAINTER_CALL(cmd) \
+ { \
+ if (painter.isActive ()) \
+ painter . cmd ; \
+ \
+ if (maskPainter.isActive ()) \
+ maskPainter . cmd ; \
+ }
+ if (w > oldWidth)
+ PAINTER_CALL (drawRect (oldWidth, 0, w - oldWidth, oldHeight));
+
+ if (h > oldHeight)
+ PAINTER_CALL (drawRect (0, oldHeight, w, h - oldHeight));
+ #undef PAINTER_CALL
+
+ if (maskPainter.isActive ())
+ maskPainter.end ();
+
+ if (painter.isActive ())
+ painter.end ();
+
+ if (!maskBitmap.isNull ())
+ destPixmapPtr->setMask (maskBitmap);
+ }
+}
+
+// public static
+QPixmap kpPixmapFX::resize (const QPixmap &pm, int w, int h,
+ const kpColor &backgroundColor, bool fillNewAreas)
+{
+ QPixmap ret = pm;
+ kpPixmapFX::resize (&ret, w, h, backgroundColor, fillNewAreas);
+ return ret;
+}
+
+
+// public static
+void kpPixmapFX::scale (QPixmap *destPixmapPtr, int w, int h, bool pretty)
+{
+ if (!destPixmapPtr)
+ return;
+
+ *destPixmapPtr = kpPixmapFX::scale (*destPixmapPtr, w, h, pretty);
+}
+
+// public static
+QPixmap kpPixmapFX::scale (const QPixmap &pm, int w, int h, bool pretty)
+{
+#if DEBUG_KP_PIXMAP_FX && 0
+ kdDebug () << "kpPixmapFX::scale(oldRect=" << pm.rect ()
+ << ",w=" << w
+ << ",h=" << h
+ << ",pretty=" << pretty
+ << ")"
+ << endl;
+#endif
+
+ if (w == pm.width () && h == pm.height ())
+ return pm;
+
+ if (pretty)
+ {
+ QImage image = kpPixmapFX::convertToImage (pm);
+
+ #if DEBUG_KP_PIXMAP_FX && 0
+ kdDebug () << "\tBefore smooth scale:" << endl;
+ for (int y = 0; y < image.height (); y++)
+ {
+ for (int x = 0; x < image.width (); x++)
+ {
+ fprintf (stderr, " %08X", image.pixel (x, y));
+ }
+ fprintf (stderr, "\n");
+ }
+ #endif
+
+ image = image.smoothScale (w, h);
+
+ #if DEBUG_KP_PIXMAP_FX && 0
+ kdDebug () << "\tAfter smooth scale:" << endl;
+ for (int y = 0; y < image.height (); y++)
+ {
+ for (int x = 0; x < image.width (); x++)
+ {
+ fprintf (stderr, " %08X", image.pixel (x, y));
+ }
+ fprintf (stderr, "\n");
+ }
+ #endif
+
+ return kpPixmapFX::convertToPixmap (image, false/*let's not smooth it again*/);
+ }
+ else
+ {
+ QWMatrix matrix;
+
+ matrix.scale (double (w) / double (pm.width ()),
+ double (h) / double (pm.height ()));
+
+ return pm.xForm (matrix);
+ }
+}
+
+
+// public static
+double kpPixmapFX::AngleInDegreesEpsilon =
+ KP_RADIANS_TO_DEGREES (atan (1.0 / 10000.0))
+ / (2.0/*max error allowed*/ * 2.0/*for good measure*/);
+
+
+static QWMatrix matrixWithZeroOrigin (const QWMatrix &matrix, int width, int height)
+{
+#if DEBUG_KP_PIXMAP_FX
+ kdDebug () << "matrixWithZeroOrigin(w=" << width << ",h=" << height << ")" << endl;
+ kdDebug () << "\tmatrix: m11=" << matrix.m11 ()
+ << " m12=" << matrix.m12 ()
+ << " m21=" << matrix.m21 ()
+ << " m22=" << matrix.m22 ()
+ << " dx=" << matrix.dx ()
+ << " dy=" << matrix.dy ()
+ << endl;
+#endif
+ // TODO: Should we be using QWMatrix::Areas?
+ QRect newRect = matrix.mapRect (QRect (0, 0, width, height));
+#if DEBUG_KP_PIXMAP_FX
+ kdDebug () << "\tnewRect=" << newRect << endl;
+#endif
+
+ QWMatrix translatedMatrix (matrix.m11 (), matrix.m12 (), matrix.m21 (), matrix.m22 (),
+ matrix.dx () - newRect.left (), matrix.dy () - newRect.top ());
+
+ return translatedMatrix;
+}
+
+static QPixmap xForm (const QPixmap &pm, const QWMatrix &transformMatrix_,
+ const kpColor &backgroundColor,
+ int targetWidth, int targetHeight)
+{
+ QWMatrix transformMatrix = transformMatrix_;
+
+#if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "kppixmapfx.cpp: xForm(pm.size=" << pm.size ()
+ << ",targetWidth=" << targetWidth
+ << ",targetHeight=" << targetHeight
+ << ")"
+ << endl;
+#endif
+ // TODO: Should we be using QWMatrix::Areas?
+ QRect newRect = transformMatrix.map (pm.rect ());
+#if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "\tmappedRect=" << newRect << endl;
+
+#endif
+
+ QWMatrix scaleMatrix;
+ if (targetWidth > 0 && targetWidth != newRect.width ())
+ {
+ #if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "\tadjusting for targetWidth" << endl;
+ #endif
+ scaleMatrix.scale (double (targetWidth) / double (newRect.width ()), 1);
+ }
+
+ if (targetHeight > 0 && targetHeight != newRect.height ())
+ {
+ #if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "\tadjusting for targetHeight" << endl;
+ #endif
+ scaleMatrix.scale (1, double (targetHeight) / double (newRect.height ()));
+ }
+
+ if (!scaleMatrix.isIdentity ())
+ {
+ #if DEBUG_KP_PIXMAP_FX && 1
+ // TODO: What is going on here??? Why isn't matrix * working properly?
+ QWMatrix wrongMatrix = transformMatrix * scaleMatrix;
+ QWMatrix oldHat = transformMatrix;
+ if (targetWidth > 0 && targetWidth != newRect.width ())
+ oldHat.scale (double (targetWidth) / double (newRect.width ()), 1);
+ if (targetHeight > 0 && targetHeight != newRect.height ())
+ oldHat.scale (1, double (targetHeight) / double (newRect.height ()));
+ QWMatrix altHat = transformMatrix;
+ altHat.scale ((targetWidth > 0 && targetWidth != newRect.width ()) ? double (targetWidth) / double (newRect.width ()) : 1,
+ (targetHeight > 0 && targetHeight != newRect.height ()) ? double (targetHeight) / double (newRect.height ()) : 1);
+ QWMatrix correctMatrix = scaleMatrix * transformMatrix;
+
+ kdDebug () << "\tsupposedlyWrongMatrix: m11=" << wrongMatrix.m11 () // <<<---- this is the correct matrix???
+ << " m12=" << wrongMatrix.m12 ()
+ << " m21=" << wrongMatrix.m21 ()
+ << " m22=" << wrongMatrix.m22 ()
+ << " dx=" << wrongMatrix.dx ()
+ << " dy=" << wrongMatrix.dy ()
+ << " rect=" << wrongMatrix.map (pm.rect ())
+ << endl
+ << "\ti_used_to_use_thisMatrix: m11=" << oldHat.m11 ()
+ << " m12=" << oldHat.m12 ()
+ << " m21=" << oldHat.m21 ()
+ << " m22=" << oldHat.m22 ()
+ << " dx=" << oldHat.dx ()
+ << " dy=" << oldHat.dy ()
+ << " rect=" << oldHat.map (pm.rect ())
+ << endl
+ << "\tabove but scaled at the same time: m11=" << altHat.m11 ()
+ << " m12=" << altHat.m12 ()
+ << " m21=" << altHat.m21 ()
+ << " m22=" << altHat.m22 ()
+ << " dx=" << altHat.dx ()
+ << " dy=" << altHat.dy ()
+ << " rect=" << altHat.map (pm.rect ())
+ << endl
+ << "\tsupposedlyCorrectMatrix: m11=" << correctMatrix.m11 ()
+ << " m12=" << correctMatrix.m12 ()
+ << " m21=" << correctMatrix.m21 ()
+ << " m22=" << correctMatrix.m22 ()
+ << " dx=" << correctMatrix.dx ()
+ << " dy=" << correctMatrix.dy ()
+ << " rect=" << correctMatrix.map (pm.rect ())
+ << endl;
+ #endif
+
+ transformMatrix = transformMatrix * scaleMatrix;
+
+ // TODO: Should we be using QWMatrix::Areas?
+ newRect = transformMatrix.map (pm.rect ());
+ #if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "\tnewRect after targetWidth,targetHeight adjust=" << newRect << endl;
+ #endif
+ }
+
+
+ QPixmap newPixmap (targetWidth > 0 ? targetWidth : newRect.width (),
+ targetHeight > 0 ? targetHeight : newRect.height ());
+ if ((targetWidth > 0 && targetWidth != newRect.width ()) ||
+ (targetHeight > 0 && targetHeight != newRect.height ()))
+ {
+ #if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "kppixmapfx.cpp: xForm(pm.size=" << pm.size ()
+ << ",targetWidth=" << targetWidth
+ << ",targetHeight=" << targetHeight
+ << ") newRect=" << newRect
+ << " (you are a victim of rounding error)"
+ << endl;
+ #endif
+ }
+
+ QBitmap newBitmapMask;
+
+ if (backgroundColor.isOpaque ())
+ newPixmap.fill (backgroundColor.toQColor ());
+
+ if (backgroundColor.isTransparent () || pm.mask ())
+ {
+ newBitmapMask.resize (newPixmap.width (), newPixmap.height ());
+ newBitmapMask.fill (backgroundColor.maskColor ());
+ }
+
+ QPainter painter (&newPixmap);
+#if DEBUG_KP_PIXMAP_FX && 1
+ kdDebug () << "\tmatrix: m11=" << transformMatrix.m11 ()
+ << " m12=" << transformMatrix.m12 ()
+ << " m21=" << transformMatrix.m21 ()
+ << " m22=" << transformMatrix.m22 ()
+ << " dx=" << transformMatrix.dx ()
+ << " dy=" << transformMatrix.dy ()
+ << endl;
+ const QWMatrix trueMatrix = QPixmap::trueMatrix (transformMatrix,
+ pm.width (), pm.height ());
+ kdDebug () << "\ttrue matrix: m11=" << trueMatrix.m11 ()
+ << " m12=" << trueMatrix.m12 ()
+ << " m21=" << trueMatrix.m21 ()
+ << " m22=" << trueMatrix.m22 ()
+ << " dx=" << trueMatrix.dx ()
+ << " dy=" << trueMatrix.dy ()
+ << endl;
+#endif
+ painter.setWorldMatrix (transformMatrix);
+#if DEBUG_KP_PIXMAP_FX && 0
+ kdDebug () << "\ttranslate top=" << painter.xForm (QPoint (0, 0)) << endl;
+ kdDebug () << "\tmatrix: m11=" << painter.worldMatrix ().m11 ()
+ << " m12=" << painter.worldMatrix ().m12 ()
+ << " m21=" << painter.worldMatrix ().m21 ()
+ << " m22=" << painter.worldMatrix ().m22 ()
+ << " dx=" << painter.worldMatrix ().dx ()
+ << " dy=" << painter.worldMatrix ().dy ()
+ << endl;
+#endif
+ painter.drawPixmap (QPoint (0, 0), pm);
+ painter.end ();
+
+ if (!newBitmapMask.isNull ())
+ {
+ QPainter maskPainter (&newBitmapMask);
+ maskPainter.setWorldMatrix (transformMatrix);
+ maskPainter.drawPixmap (QPoint (0, 0), kpPixmapFX::getNonNullMask (pm));
+ maskPainter.end ();
+ newPixmap.setMask (newBitmapMask);
+ }
+
+ return newPixmap;
+}
+
+// public static
+QWMatrix kpPixmapFX::skewMatrix (int width, int height, double hangle, double vangle)
+{
+ if (fabs (hangle - 0) < kpPixmapFX::AngleInDegreesEpsilon &&
+ fabs (vangle - 0) < kpPixmapFX::AngleInDegreesEpsilon)
+ {
+ return QWMatrix ();
+ }
+
+
+ /* Diagram for completeness :)
+ *
+ * |---------- w ----------|
+ * (0,0)
+ * _ _______________________ (w,0)
+ * | |\~_ va |
+ * | | \ ~_ |
+ * | |ha\ ~__ |
+ * | \ ~__ | dy
+ * h | \ ~___ |
+ * | \ ~___ |
+ * | | \ ~___| (w,w*tan(va)=dy)
+ * | | \ * \
+ * _ |________\________|_____|\ vertical shear factor
+ * (0,h) dx ^~_ | \ |
+ * | ~_ \________\________ General Point (x,y) V
+ * | ~__ \ Skewed Point (x + y*tan(ha),y + x*tan(va))
+ * (h*tan(ha)=dx,h) ~__ \ ^
+ * ~___ \ |
+ * ~___ \ horizontal shear factor
+ * Key: ~___\
+ * ha = hangle (w + h*tan(ha)=w+dx,h + w*tan(va)=w+dy)
+ * va = vangle
+ *
+ * Skewing really just twists a rectangle into a parallelogram.
+ *
+ */
+
+ //QWMatrix matrix (1, tan (KP_DEGREES_TO_RADIANS (vangle)), tan (KP_DEGREES_TO_RADIANS (hangle)), 1, 0, 0);
+ // I think this is clearer than above :)
+ QWMatrix matrix;
+ matrix.shear (tan (KP_DEGREES_TO_RADIANS (hangle)),
+ tan (KP_DEGREES_TO_RADIANS (vangle)));
+
+ return matrixWithZeroOrigin (matrix, width, height);
+}
+
+// public static
+QWMatrix kpPixmapFX::skewMatrix (const QPixmap &pixmap, double hangle, double vangle)
+{
+ return kpPixmapFX::skewMatrix (pixmap.width (), pixmap.height (), hangle, vangle);
+}
+
+
+// public static
+void kpPixmapFX::skew (QPixmap *destPixmapPtr, double hangle, double vangle,
+ const kpColor &backgroundColor,
+ int targetWidth, int targetHeight)
+{
+ if (!destPixmapPtr)
+ return;
+
+ *destPixmapPtr = kpPixmapFX::skew (*destPixmapPtr, hangle, vangle,
+ backgroundColor,
+ targetWidth, targetHeight);
+}
+
+// public static
+QPixmap kpPixmapFX::skew (const QPixmap &pm, double hangle, double vangle,
+ const kpColor &backgroundColor,
+ int targetWidth, int targetHeight)
+{
+#if DEBUG_KP_PIXMAP_FX
+ kdDebug () << "kpPixmapFX::skew() pm.width=" << pm.width ()
+ << " pm.height=" << pm.height ()
+ << " hangle=" << hangle
+ << " vangle=" << vangle
+ << " targetWidth=" << targetWidth
+ << " targetHeight=" << targetHeight
+ << endl;
+#endif
+
+ if (fabs (hangle - 0) < kpPixmapFX::AngleInDegreesEpsilon &&
+ fabs (vangle - 0) < kpPixmapFX::AngleInDegreesEpsilon &&
+ (targetWidth <= 0 && targetHeight <= 0)/*don't want to scale?*/)
+ {
+ return pm;
+ }
+
+ if (fabs (hangle) > 90 - kpPixmapFX::AngleInDegreesEpsilon ||
+ fabs (vangle) > 90 - kpPixmapFX::AngleInDegreesEpsilon)
+ {
+ kdError () << "kpPixmapFX::skew() passed hangle and/or vangle out of range (-90 < x < 90)" << endl;
+ return pm;
+ }
+
+
+ QWMatrix matrix = skewMatrix (pm, hangle, vangle);
+
+ return ::xForm (pm, matrix, backgroundColor, targetWidth, targetHeight);
+}
+
+
+// public static
+QWMatrix kpPixmapFX::rotateMatrix (int width, int height, double angle)
+{
+ if (fabs (angle - 0) < kpPixmapFX::AngleInDegreesEpsilon)
+ {
+ return QWMatrix ();
+ }
+
+ QWMatrix matrix;
+ matrix.translate (width / 2, height / 2);
+ matrix.rotate (angle);
+
+ return matrixWithZeroOrigin (matrix, width, height);
+}
+
+// public static
+QWMatrix kpPixmapFX::rotateMatrix (const QPixmap &pixmap, double angle)
+{
+ return kpPixmapFX::rotateMatrix (pixmap.width (), pixmap.height (), angle);
+}
+
+
+// public static
+bool kpPixmapFX::isLosslessRotation (double angle)
+{
+ const double angleIn = angle;
+
+ // Reflect angle into positive if negative
+ if (angle < 0)
+ angle = -angle;
+
+ // Remove multiples of 90 to make sure 0 <= angle <= 90
+ angle -= ((int) angle) / 90 * 90;
+
+ // "Impossible" situation?
+ if (angle < 0 || angle > 90)
+ {
+ kdError () << "kpPixmapFX::isLosslessRotation(" << angleIn
+ << ") result=" << angle
+ << endl;
+ return false; // better safe than sorry
+ }
+
+ const bool ret = (angle < kpPixmapFX::AngleInDegreesEpsilon ||
+ 90 - angle < kpPixmapFX::AngleInDegreesEpsilon);
+#if DEBUG_KP_PIXMAP_FX
+ kdDebug () << "kpPixmapFX::isLosslessRotation(" << angleIn << ")"
+ << " residual angle=" << angle
+ << " returning " << ret
+ << endl;
+#endif
+ return ret;
+}
+
+
+// public static
+void kpPixmapFX::rotate (QPixmap *destPixmapPtr, double angle,
+ const kpColor &backgroundColor,
+ int targetWidth, int targetHeight)
+{
+ if (!destPixmapPtr)
+ return;
+
+ *destPixmapPtr = kpPixmapFX::rotate (*destPixmapPtr, angle,
+ backgroundColor,
+ targetWidth, targetHeight);
+}
+
+// public static
+QPixmap kpPixmapFX::rotate (const QPixmap &pm, double angle,
+ const kpColor &backgroundColor,
+ int targetWidth, int targetHeight)
+{
+ if (fabs (angle - 0) < kpPixmapFX::AngleInDegreesEpsilon &&
+ (targetWidth <= 0 && targetHeight <= 0)/*don't want to scale?*/)
+ {
+ return pm;
+ }
+
+
+ QWMatrix matrix = rotateMatrix (pm, angle);
+
+ return ::xForm (pm, matrix, backgroundColor, targetWidth, targetHeight);
+}
+
+
+// public static
+QWMatrix kpPixmapFX::flipMatrix (int width, int height, bool horz, bool vert)
+{
+ if (width <= 0 || height <= 0)
+ {
+ kdError () << "kpPixmapFX::flipMatrix() passed invalid dimensions" << endl;
+ return QWMatrix ();
+ }
+
+ return QWMatrix (horz ? -1 : +1, // m11
+ 0, // m12
+ 0, // m21
+ vert ? -1 : +1, // m22
+ horz ? (width - 1) : 0, // dx
+ vert ? (height - 1) : 0); // dy
+}
+
+// public static
+QWMatrix kpPixmapFX::flipMatrix (const QPixmap &pixmap, bool horz, bool vert)
+{
+ return kpPixmapFX::flipMatrix (pixmap.width (), pixmap.height (),
+ horz, vert);
+}
+
+
+// public static
+void kpPixmapFX::flip (QPixmap *destPixmapPtr, bool horz, bool vert)
+{
+ if (!horz && !vert)
+ return;
+
+ *destPixmapPtr = kpPixmapFX::flip (*destPixmapPtr, horz, vert);
+}
+
+// public static
+QPixmap kpPixmapFX::flip (const QPixmap &pm, bool horz, bool vert)
+{
+ if (!horz && !vert)
+ return pm;
+
+ return pm.xForm (flipMatrix (pm, horz, vert));
+}
+
+// public static
+void kpPixmapFX::flip (QImage *destImagePtr, bool horz, bool vert)
+{
+ if (!horz && !vert)
+ return;
+
+ *destImagePtr = kpPixmapFX::flip (*destImagePtr, horz, vert);
+}
+
+// public static
+QImage kpPixmapFX::flip (const QImage &img, bool horz, bool vert)
+{
+ if (!horz && !vert)
+ return img;
+
+ return img.mirror (horz, vert);
+}
diff --git a/kolourpaint/pixmapfx/kppixmapfx.h b/kolourpaint/pixmapfx/kppixmapfx.h
new file mode 100644
index 00000000..c083ee43
--- /dev/null
+++ b/kolourpaint/pixmapfx/kppixmapfx.h
@@ -0,0 +1,450 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef KP_PIXMAP_FX_H
+#define KP_PIXMAP_FX_H
+
+
+#include <qstring.h>
+
+
+class QBitmap;
+class QColor;
+class QImage;
+class QPointArray;
+class QPixmap;
+class QPoint;
+class QRect;
+class QString;
+class QWidget;
+class QWMatrix;
+
+class kpColor;
+class kpSelection;
+
+
+class kpPixmapFX
+{
+public:
+
+ //
+ // Overflow Resistant Arithmetic:
+ //
+ // Returns INT_MAX if <lhs> or <rhs> < 0 or if would overflow.
+ static int addDimensions (int lhs, int rhs);
+ static int multiplyDimensions (int lhs, int rhs);
+
+
+ //
+ // QPixmap Statistics
+ //
+
+ // Returns the width * height.
+ static int pixmapArea (const QPixmap &pixmap);
+ static int pixmapArea (const QPixmap *pixmap);
+ static int pixmapArea (int width, int height);
+
+ // Returns the estimated size of <pixmap> in pixmap memory.
+ static int pixmapSize (const QPixmap &pixmap);
+ static int pixmapSize (const QPixmap *pixmap);
+ static int pixmapSize (int width, int height, int depth);
+
+ static int imageSize (const QImage &image);
+ static int imageSize (const QImage *image);
+ static int imageSize (int width, int height, int depth);
+
+ static int selectionSize (const kpSelection &sel);
+ static int selectionSize (const kpSelection *sel);
+
+ static int stringSize (const QString &string);
+
+ static int pointArraySize (const QPointArray &points);
+
+
+ //
+ // QPixmap/QImage Conversion Functions
+ //
+
+ //
+ // Converts <pixmap> to a QImage and returns it.
+ //
+ // WARNING: On an 8-bit screen:
+ //
+ // QPixmap result = convertToPixmap (convertToImage (pixmap));
+ //
+ // <result> is slightly differently colored to <pixmap>.
+ //
+ // KolourPaint needs to convert to QImage occasionally as
+ // QImage allows KolourPaint to read pixels and because the QImage
+ // methods give reliable results and pixel-identical results on
+ // all platforms. The QPixmap paint engine has no such guarantee
+ // and even depends on the quality of the video driver.
+ //
+ // As a result, KolourPaint should not be used on an 8-bit screen.
+ // HITODO: Add warning on startup, like in KolourPaint/KDE4.
+ //
+ // This bug will be fixed when KolourPaint gets a proper image library,
+ // where QPixmap -> QImage -> QPixmap transitions will be not be needed.
+ static QImage convertToImage (const QPixmap &pixmap);
+
+ //
+ // Dialog info for warning about data loss with convertToPixmap().
+ //
+ struct WarnAboutLossInfo
+ {
+ // <moreColorsThanDisplayAndHasAlphaChannelMessage>:
+ //
+ // i18n ("The (image \"example.jpg\"|image from the clipboard)"
+ // " may have more colors than the current screen mode."
+ // " In order to display it, some colors may be changed."
+ // " Try increasing your screen depth to at least %1bpp."
+ //
+ // "\nIt also"
+ //
+ // " contains translucency which is not fully"
+ // " supported. The translucency data will be"
+ // " approximated with a 1-bit transparency mask.")
+ //
+ // <moreColorsThanDisplayMessage>:
+ // i18n ("The (image \"example.jpg\"|image from the clipboard)"
+ // " may have more colors than the current screen mode."
+ // " In order to display it, some colors may be changed."
+ // " Try increasing your screen depth to at least %1bpp.")
+ //
+ // <hasAlphaChannelMessage>:
+ // i18n ("The (image \"example.jpg\"|image from the clipboard)"
+ // " contains translucency which is not fully"
+ // " supported. The translucency data will be"
+ // " approximated with a 1-bit transparency mask.")
+ //
+ // <dontAskAgainPrefix>:
+ //
+ // Don'tAskAgain ID for dialog.
+ //
+ // <parent>:
+ //
+ // Dialog parent
+ //
+ WarnAboutLossInfo (const QString &moreColorsThanDisplayAndHasAlphaChannelMessage,
+ const QString &moreColorsThanDisplayMessage,
+ const QString &hasAlphaChannelMessage,
+ const QString &dontAskAgainPrefix,
+ QWidget *parent)
+ :
+ m_moreColorsThanDisplayAndHasAlphaChannelMessage (
+ moreColorsThanDisplayAndHasAlphaChannelMessage),
+ m_moreColorsThanDisplayMessage (
+ moreColorsThanDisplayMessage),
+ m_hasAlphaChannelMessage (
+ hasAlphaChannelMessage),
+ m_dontAskAgainPrefix (
+ dontAskAgainPrefix),
+ m_parent (parent),
+ m_isValid (true)
+ {
+ }
+
+ WarnAboutLossInfo ()
+ : m_parent (0),
+ m_isValid (false)
+ {
+ }
+
+ ~WarnAboutLossInfo ()
+ {
+ }
+
+
+ bool isValid () const { return m_isValid; }
+
+
+ QString m_moreColorsThanDisplayAndHasAlphaChannelMessage,
+ m_moreColorsThanDisplayMessage,
+ m_hasAlphaChannelMessage;
+ QString m_dontAskAgainPrefix;
+ QWidget *m_parent;
+ bool m_isValid;
+ };
+
+ //
+ // Converts <image> to a QPixmap of the current display's depth and
+ // returns it.
+ //
+ // If the flag <pretty> is set, it will dither the image making the
+ // returned pixmap look better but if the image has few colours
+ // (less than the screen can handle), this will be at the expense of
+ // exactness of conversion.
+ //
+ // This will automatically call ensureNoAlphaChannel().
+ //
+ // Never use a foreign QPixmap that is offered to you - always get the
+ // foreign QImage and use this function to convert it to a sane QPixmap.
+ //
+ // <wali>, if specified, describes parameters for the dialog that comes
+ // up warning the user of data loss if the <image> contains translucency
+ // and/or more colors than the current display.
+ //
+ static QPixmap convertToPixmap (const QImage &image, bool pretty = false,
+ const WarnAboutLossInfo &wali = WarnAboutLossInfo ());
+
+ // Same as convertToPixmap() but tries as hard as possible to make the
+ // pixmap look like the original <image> - when in doubt, reads the
+ // config to see whether or not to dither (default: on).
+ //
+ // If you know for sure that <image> can be displayed losslessly on
+ // the screen, you should call convertToPixmap() with <pretty> = false
+ // instead. If you know for sure that <image> cannot be displayed
+ // losslessly, then call convertToPixmap() with <pretty> = true.
+ //
+ static QPixmap convertToPixmapAsLosslessAsPossible (const QImage &image,
+ const WarnAboutLossInfo &wali = WarnAboutLossInfo ());
+
+
+ // Sets the RGB values of the pixels where <pixmap> is transparent to
+ // <transparentColor>. This has visually no effect on the <pixmap>
+ // unless the mask is lost.
+ static QPixmap pixmapWithDefinedTransparentPixels (const QPixmap &pixmap,
+ const QColor &transparentColor);
+
+
+ //
+ // Get/Set Parts of Pixmap
+ //
+
+
+ //
+ // Returns the pixel and mask data found at the <rect> in <pm>.
+ //
+ static QPixmap getPixmapAt (const QPixmap &pm, const QRect &rect);
+
+ //
+ // Sets the pixel and mask data at <destRect> in <*destPixmapPtr>
+ // to <srcPixmap>.
+ //
+ static void setPixmapAt (QPixmap *destPixmapPtr, const QRect &destRect,
+ const QPixmap &srcPixmap);
+
+ //
+ // Sets the pixel and mask data at the rectangle in <*destPixmapPtr>,
+ // with the top-left <destAt> and dimensions <srcPixmap.rect()>,
+ // to <srcPixmap>.
+ //
+ static void setPixmapAt (QPixmap *destPixmapPtr, const QPoint &destAt,
+ const QPixmap &srcPixmap);
+ static void setPixmapAt (QPixmap *destPixmapPtr, int destX, int destY,
+ const QPixmap &srcPixmap);
+
+ //
+ // Draws <srcPixmap> on top of <*destPixmapPtr> at <destAt>.
+ // The mask of <*destPixmapPtr> is adjusted so that all opaque
+ // pixels in <srcPixmap> will be opaque in <*destPixmapPtr>.
+ //
+ static void paintPixmapAt (QPixmap *destPixmapPtr, const QPoint &destAt,
+ const QPixmap &srcPixmap);
+ static void paintPixmapAt (QPixmap *destPixmapPtr, int destX, int destY,
+ const QPixmap &srcPixmap);
+
+ //
+ // Returns the colour of the pixel at <at> in <pm>.
+ // If the pixel is transparent, a value is returned such that
+ // kpTool::isColorTransparent(<return_value>) will return true.
+ //
+ static kpColor getColorAtPixel (const QPixmap &pm, const QPoint &at);
+ static kpColor getColorAtPixel (const QPixmap &pm, int x, int y);
+
+ //
+ // Returns the color of the pixel at <at> in <img>.
+ // If the pixel is transparent, a value is returned such that
+ // kpTool::isColorTransparent(<return_value>) will return true.
+ //
+ static kpColor getColorAtPixel (const QImage &img, const QPoint &at);
+ static kpColor getColorAtPixel (const QImage &img, int x, int y);
+
+
+ //
+ // Mask Operations
+ //
+
+
+ //
+ // Removes <*destPixmapPtr>'s Alpha Channel and attempts to convert it
+ // to a mask. KolourPaint - and QPixmap to a great extent - does not
+ // support Alpha Channels - only masks. Call this whenever you get
+ // a pixmap from a foreign source; else all KolourPaint code will
+ // exhibit "undefined behaviour".
+ //
+ static void ensureNoAlphaChannel (QPixmap *destPixmapPtr);
+
+ //
+ // Returns <pm>'s mask or a fully opaque mask (with <pm>'s dimensions)
+ // if <pm> does not have a mask.
+ //
+ static QBitmap getNonNullMask (const QPixmap &pm);
+
+ //
+ // Ensures that <*destPixmapPtr> is transparent at <rect>.
+ //
+ static void ensureTransparentAt (QPixmap *destPixmapPtr, const QRect &destRect);
+
+ //
+ // Sets the mask of <*destPixmapPtr> at the rectangle, with the
+ // top-left <destAt> and dimensions <srcMaskBitmap.rect()>,
+ // to transparent where <brushBitmap> is opaque.
+ //
+ // <brushPixmap> must be a QPixmap of depth 1 (or a QBitmap).
+ //
+ static void paintMaskTransparentWithBrush (QPixmap *destPixmapPtr, const QPoint &destAt,
+ const QPixmap &brushBitmap);
+ static void paintMaskTransparentWithBrush (QPixmap *destPixmapPtr, int destX, int destY,
+ const QPixmap &brushBitmap);
+
+ //
+ // Ensures that <*destPixmapPtr> is opaque at <rect>.
+ //
+ static void ensureOpaqueAt (QPixmap *destPixmapPtr, const QRect &destRect);
+
+ //
+ // Ensures that <srcPixmap>'s opaque pixels will be opaque if
+ // painted onto <*destPixmapPtr> at <destAt>.
+ //
+ static void ensureOpaqueAt (QPixmap *destPixmapPtr, const QPoint &destAt,
+ const QPixmap &srcPixmap);
+ static void ensureOpaqueAt (QPixmap *destPixmapPtr, int destX, int destY,
+ const QPixmap &srcPixmap);
+
+
+ //
+ // Effects
+ //
+
+
+ //
+ // Converts the image to grayscale.
+ //
+ static void convertToGrayscale (QPixmap *destPixmapPtr);
+ static QPixmap convertToGrayscale (const QPixmap &pm);
+ static void convertToGrayscale (QImage *destImagePtr);
+ static QImage convertToGrayscale (const QImage &img);
+
+ //
+ // Fills an image in the given color.
+ //
+ static void fill (QPixmap *destPixmapPtr, const kpColor &color);
+ static QPixmap fill (const QPixmap &pm, const kpColor &color);
+
+ //
+ // Resizes an image to the given width and height,
+ // filling any new areas with <backgroundColor> if <fillNewAreas> is set.
+ //
+ static void resize (QPixmap *destPixmapPtr, int w, int h,
+ const kpColor &backgroundColor, bool fillNewAreas = true);
+ static QPixmap resize (const QPixmap &pm, int w, int h,
+ const kpColor &backgroundColor, bool fillNewAreas = true);
+
+ //
+ // Scales an image to the given width and height.
+ // If <pretty> is true, a smooth scale will be used.
+ //
+ static void scale (QPixmap *destPixmapPtr, int w, int h, bool pretty = false);
+ static QPixmap scale (const QPixmap &pm, int w, int h, bool pretty = false);
+
+
+ // The minimum difference between 2 angles (in degrees) such that they are
+ // considered different. This gives you at least enough precision to
+ // rotate an image whose width <= 10000 such that its height increases
+ // by just 1 (and similarly with height <= 10000 and width).
+ //
+ // Currently used for skew & rotate operations.
+ static double AngleInDegreesEpsilon;
+
+
+ //
+ // Skews an image.
+ //
+ // <hangle> horizontal angle clockwise (-90 < x < 90)
+ // <vangle> vertical angle clockwise (-90 < x < 90)
+ // <backgroundColor> color to fill new areas with
+ // <targetWidth> if > 0, the desired width of the resultant pixmap
+ // <targetHeight> if > 0, the desired height of the resultant pixmap
+ //
+ // Using <targetWidth> & <targetHeight> to generate preview pixmaps is
+ // significantly more efficient than skewing and then scaling yourself.
+ //
+ static QWMatrix skewMatrix (int width, int height, double hangle, double vangle);
+ static QWMatrix skewMatrix (const QPixmap &pixmap, double hangle, double vangle);
+
+ static void skew (QPixmap *destPixmapPtr, double hangle, double vangle,
+ const kpColor &backgroundColor,
+ int targetWidth = -1, int targetHeight = -1);
+ static QPixmap skew (const QPixmap &pm, double hangle, double vangle,
+ const kpColor &backgroundColor,
+ int targetWidth = -1, int targetHeight = -1);
+
+ //
+ // Rotates an image.
+ //
+ // <angle> clockwise angle to rotate by
+ // <backgroundColor> color to fill new areas with
+ // <targetWidth> if > 0, the desired width of the resultant pixmap
+ // <targetHeight> if > 0, the desired height of the resultant pixmap
+ //
+ // Using <targetWidth> & <targetHeight> to generate preview pixmaps is
+ // significantly more efficient than rotating and then scaling yourself.
+ //
+ static QWMatrix rotateMatrix (int width, int height, double angle);
+ static QWMatrix rotateMatrix (const QPixmap &pixmap, double angle);
+
+ static bool isLosslessRotation (double angle);
+
+ static void rotate (QPixmap *destPixmapPtr, double angle,
+ const kpColor &backgroundColor,
+ int targetWidth = -1, int targetHeight = -1);
+ static QPixmap rotate (const QPixmap &pm, double angle,
+ const kpColor &backgroundColor,
+ int targetWidth = -1, int targetHeight = -1);
+
+
+ //
+ // Flips an image in the given directions.
+ //
+ static QWMatrix flipMatrix (int width, int height, bool horz, bool vert);
+ static QWMatrix flipMatrix (const QPixmap &pixmap, bool horz, bool vert);
+
+ // TODO: this kind of overloading is error prone
+ // e.g. QPixmap pixmap;
+ // kpPixmapFX::flip (pixmap, false, true);
+ // looks like it will flip vertically but does absolutely nothing!
+ // (should be &pixmap)
+ static void flip (QPixmap *destPixmapPtr, bool horz, bool vert);
+ static QPixmap flip (const QPixmap &pm, bool horz, bool vert);
+ static void flip (QImage *destImagePtr, bool horz, bool vert);
+ static QImage flip (const QImage &img, bool horz, bool vert);
+};
+
+
+#endif // KP_PIXMAP_FX_H
diff --git a/kolourpaint/tests/45deg_line.png b/kolourpaint/tests/45deg_line.png
new file mode 100644
index 00000000..5af95109
--- /dev/null
+++ b/kolourpaint/tests/45deg_line.png
Binary files differ
diff --git a/kolourpaint/tests/4x4-transparent.png b/kolourpaint/tests/4x4-transparent.png
new file mode 100644
index 00000000..58b0668e
--- /dev/null
+++ b/kolourpaint/tests/4x4-transparent.png
Binary files differ
diff --git a/kolourpaint/tests/5x5.png b/kolourpaint/tests/5x5.png
new file mode 100644
index 00000000..850766c7
--- /dev/null
+++ b/kolourpaint/tests/5x5.png
Binary files differ
diff --git a/kolourpaint/tests/depth1.bmp b/kolourpaint/tests/depth1.bmp
new file mode 100644
index 00000000..326c665a
--- /dev/null
+++ b/kolourpaint/tests/depth1.bmp
Binary files differ
diff --git a/kolourpaint/tests/dither.png b/kolourpaint/tests/dither.png
new file mode 100644
index 00000000..443ed07c
--- /dev/null
+++ b/kolourpaint/tests/dither.png
Binary files differ
diff --git a/kolourpaint/tests/rotate.png b/kolourpaint/tests/rotate.png
new file mode 100644
index 00000000..f6f028b4
--- /dev/null
+++ b/kolourpaint/tests/rotate.png
Binary files differ
diff --git a/kolourpaint/tests/small16x16.png b/kolourpaint/tests/small16x16.png
new file mode 100644
index 00000000..ed61d4d6
--- /dev/null
+++ b/kolourpaint/tests/small16x16.png
Binary files differ
diff --git a/kolourpaint/tests/tool_fill_xlimit.png b/kolourpaint/tests/tool_fill_xlimit.png
new file mode 100644
index 00000000..b499879a
--- /dev/null
+++ b/kolourpaint/tests/tool_fill_xlimit.png
Binary files differ
diff --git a/kolourpaint/tests/transparent.png b/kolourpaint/tests/transparent.png
new file mode 100644
index 00000000..c05a92ef
--- /dev/null
+++ b/kolourpaint/tests/transparent.png
Binary files differ
diff --git a/kolourpaint/tests/transparent_selection.png b/kolourpaint/tests/transparent_selection.png
new file mode 100644
index 00000000..8db8b7e5
--- /dev/null
+++ b/kolourpaint/tests/transparent_selection.png
Binary files differ
diff --git a/kolourpaint/tools/Makefile.am b/kolourpaint/tools/Makefile.am
new file mode 100644
index 00000000..9c665cb1
--- /dev/null
+++ b/kolourpaint/tools/Makefile.am
@@ -0,0 +1,53 @@
+INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../cursors -I$(srcdir)/../interfaces \
+ -I$(srcdir)/../pixmapfx \
+ -I$(srcdir)/../tools \
+ -I$(srcdir)/../views \
+ -I$(srcdir)/../widgets $(all_includes)
+
+noinst_LTLIBRARIES = libkolourpainttools.la
+libkolourpainttools_la_SOURCES = kptoolaction.cpp \
+ kptoolairspray.cpp \
+ kptoolautocrop.cpp \
+ kptoolbrush.cpp kptoolclear.cpp \
+ kptoolcolorpicker.cpp kptoolcolorwasher.cpp \
+ kptoolconverttograyscale.cpp \
+ kptoolcrop.cpp \
+ kptoolcurve.cpp \
+ kptoolellipse.cpp \
+ kptoolellipticalselection.cpp kptooleraser.cpp \
+ kptoolflip.cpp kptoolfloodfill.cpp \
+ kptoolfreeformselection.cpp \
+ kptoolline.cpp kptoolpen.cpp \
+ kptoolpolygon.cpp kptoolpolyline.cpp \
+ kptoolpreviewdialog.cpp \
+ kptoolrectangle.cpp kptoolrectselection.cpp \
+ kptoolresizescale.cpp kptoolrotate.cpp \
+ kptoolroundedrectangle.cpp kptoolselection.cpp \
+ kptoolskew.cpp kptooltext.cpp
+
+# TODO: Why is this needed? Isn't linking at the toplevel enough?
+libkolourpainttools_la_LIBADD = ../pixmapfx/libkolourpaintpixmapfx.la ../cursors/libkolourpaintcursors.la
+
+METASOURCES = kptoolaction.moc \
+ kptoolairspray.moc \
+ kptoolbrush.moc \
+ kptoolcolorpicker.moc \
+ kptoolcolorwasher.moc \
+ kptoolcurve.moc \
+ kptoolellipse.moc \
+ kptooleraser.moc \
+ kptoolflip.moc \
+ kptoolfloodfill.moc \
+ kptoolline.moc \
+ kptoolpen.moc \
+ kptoolpolygon.moc \
+ kptoolpolyline.moc \
+ kptoolpreviewdialog.moc \
+ kptoolrectangle.moc \
+ kptoolresizescale.moc \
+ kptoolrotate.moc \
+ kptoolroundedrectangle.moc \
+ kptoolselection.moc \
+ kptoolskew.moc \
+ kptooltext.moc
+
diff --git a/kolourpaint/tools/kptoolaction.cpp b/kolourpaint/tools/kptoolaction.cpp
new file mode 100644
index 00000000..ef5c8510
--- /dev/null
+++ b/kolourpaint/tools/kptoolaction.cpp
@@ -0,0 +1,107 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <kptoolaction.h>
+
+#include <kptool.h>
+
+
+kpToolAction::kpToolAction (const QString &text,
+ const QString &pic, const KShortcut &shortcut,
+ const QObject *receiver, const char *slot,
+ QObject *parent, const char *name)
+ : KToggleAction (text,
+ pic, shortcut,
+ receiver, slot,
+ parent, name)
+{
+ updateToolTip ();
+}
+
+kpToolAction::~kpToolAction ()
+{
+}
+
+
+// protected
+void kpToolAction::updateToolTip ()
+{
+ const QString newToolTip =
+ kpTool::toolTipForTextAndShortcut (text (), shortcut ());
+ if (newToolTip == toolTip ())
+ return;
+
+ setToolTip (newToolTip);
+ emit toolTipChanged (newToolTip);
+}
+
+
+//
+// KToggleAction interface
+//
+
+// public slot virtual [base KAction]
+void kpToolAction::setText (const QString &text)
+{
+ KToggleAction::setText (text);
+ updateToolTip ();
+}
+
+// public slot virtual [base KAction]
+bool kpToolAction::setShortcut (const KShortcut &shortcut)
+{
+ bool ret = KToggleAction::setShortcut (shortcut);
+ updateToolTip ();
+ return ret;
+}
+
+
+//
+// KToggleAction implements kpSingleKeyTriggersActionInterface
+//
+
+// public virtual [base kpSingleKeyTriggersActionInterface]
+const char *kpToolAction::actionName () const
+{
+ return name ();
+}
+
+// public virtual [base kpSingleKeyTriggersActionInterface]
+KShortcut kpToolAction::actionShortcut () const
+{
+ return shortcut ();
+}
+
+// public virtual [base kpSingleKeyTriggersActionInterface]
+void kpToolAction::actionSetShortcut (const KShortcut &shortcut)
+{
+ setShortcut (shortcut);
+}
+
+
+#include <kptoolaction.moc>
diff --git a/kolourpaint/tools/kptoolaction.h b/kolourpaint/tools/kptoolaction.h
new file mode 100644
index 00000000..df4e407e
--- /dev/null
+++ b/kolourpaint/tools/kptoolaction.h
@@ -0,0 +1,78 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KP_TOOL_ACTION_H
+#define KP_TOOL_ACTION_H
+
+#include <kactionclasses.h>
+
+#include <kpsinglekeytriggersaction.h>
+
+
+// Same as KToggleAction but shows the first single key trigger in the tooltip.
+class kpToolAction : public KToggleAction,
+ public kpSingleKeyTriggersActionInterface
+{
+Q_OBJECT
+
+public:
+ kpToolAction (const QString &text,
+ const QString &pic, const KShortcut &shortcut,
+ const QObject *receiver, const char *slot,
+ QObject *parent, const char *name);
+ virtual ~kpToolAction ();
+
+
+signals:
+ // Not emitted when toolTip is manually overriden by setToolTip()
+ void toolTipChanged (const QString &string);
+
+protected:
+ void updateToolTip ();
+
+
+ //
+ // KToggleAction interface
+ //
+
+public slots:
+ virtual void setText (const QString &text);
+ virtual bool setShortcut (const KShortcut &shortcut);
+
+
+ //
+ // kpSingleKeyTriggersActionInterface
+ //
+
+public:
+ virtual const char *actionName () const;
+ virtual KShortcut actionShortcut () const;
+ virtual void actionSetShortcut (const KShortcut &shortcut);
+};
+
+
+#endif // KP_TOOL_ACTION_H
diff --git a/kolourpaint/tools/kptoolairspray.cpp b/kolourpaint/tools/kptoolairspray.cpp
new file mode 100644
index 00000000..43f8bef3
--- /dev/null
+++ b/kolourpaint/tools/kptoolairspray.cpp
@@ -0,0 +1,376 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_TOOL_SPRAYCAN 0
+
+#include <stdlib.h>
+
+#include <qbitmap.h>
+#include <qpainter.h>
+#include <qpen.h>
+#include <qpixmap.h>
+#include <qpoint.h>
+#include <qpointarray.h>
+#include <qrect.h>
+#include <qtimer.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcommandhistory.h>
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kptoolairspray.h>
+#include <kptooltoolbar.h>
+#include <kptoolwidgetspraycansize.h>
+#include <kpview.h>
+#include <kpviewmanager.h>
+
+
+/*
+ * kpToolAirSpray
+ */
+
+kpToolAirSpray::kpToolAirSpray (kpMainWindow *mainWindow)
+ : kpTool (i18n ("Spraycan"), i18n ("Sprays graffiti"),
+ Qt::Key_Y,
+ mainWindow, "tool_spraycan"),
+ m_currentCommand (0)
+{
+ m_timer = new QTimer (this);
+ connect (m_timer, SIGNAL (timeout ()), this, SLOT (actuallyDraw ()));
+}
+
+kpToolAirSpray::~kpToolAirSpray ()
+{
+ delete m_currentCommand;
+}
+
+
+// private
+QString kpToolAirSpray::haventBegunDrawUserMessage () const
+{
+ return i18n ("Click or drag to spray graffiti.");
+}
+
+// public virtual
+void kpToolAirSpray::begin ()
+{
+ kpToolToolBar *tb = toolToolBar ();
+
+ m_toolWidgetSpraycanSize = 0;
+ m_size = 10;
+
+ if (tb)
+ {
+ m_toolWidgetSpraycanSize = tb->toolWidgetSpraycanSize ();
+
+ if (m_toolWidgetSpraycanSize)
+ {
+ m_size = m_toolWidgetSpraycanSize->spraycanSize ();
+ connect (m_toolWidgetSpraycanSize, SIGNAL (spraycanSizeChanged (int)),
+ this, SLOT (slotSpraycanSizeChanged (int)));
+
+ m_toolWidgetSpraycanSize->show ();
+ }
+ }
+
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+// public virtual
+void kpToolAirSpray::end ()
+{
+ if (m_toolWidgetSpraycanSize)
+ {
+ disconnect (m_toolWidgetSpraycanSize, SIGNAL (spraycanSizeChanged (int)),
+ this, SLOT (slotSpraycanSizeChanged (int)));
+ m_toolWidgetSpraycanSize = 0;
+ }
+
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+// private slot
+void kpToolAirSpray::slotSpraycanSizeChanged (int size)
+{
+ m_size = size;
+}
+
+
+void kpToolAirSpray::beginDraw ()
+{
+ m_currentCommand = new kpToolAirSprayCommand (
+ color (m_mouseButton),
+ m_size,
+ mainWindow ());
+
+ // without delay
+ actuallyDraw ();
+
+ // use a timer instead of reimplementing draw() (we don't draw all the time)
+ m_timer->start (25);
+
+ setUserMessage (cancelUserMessage ());
+}
+
+void kpToolAirSpray::draw (const QPoint &thisPoint, const QPoint &, const QRect &)
+{
+ // if the user is moving the spray, make the spray line continuous
+ if (thisPoint != m_lastPoint)
+ {
+ // without delay
+ actuallyDraw ();
+ }
+
+ setUserShapePoints (thisPoint);
+}
+
+void kpToolAirSpray::actuallyDraw ()
+{
+ QPointArray pArray (10);
+ int numPoints = 0;
+
+ QPoint p = m_currentPoint;
+
+#if DEBUG_KP_TOOL_SPRAYCAN
+ kdDebug () << "kpToolAirSpray::actuallyDraw() currentPoint=" << p
+ << " size=" << m_size
+ << endl;
+#endif
+
+ int radius = m_size / 2;
+
+ for (int i = 0; i < 10; i++)
+ {
+ int dx, dy;
+
+ dx = (rand () % m_size) - radius;
+ dy = (rand () % m_size) - radius;
+
+ // make it look circular
+ // OPT: can be done better
+ if (dx * dx + dy * dy <= radius * radius)
+ pArray [numPoints++] = QPoint (p.x () + dx, p.y () + dy);
+ }
+
+ pArray.resize (numPoints);
+
+ if (numPoints > 0)
+ {
+ // leave the command to draw
+ m_currentCommand->addPoints (pArray);
+ }
+}
+
+// virtual
+void kpToolAirSpray::cancelShape ()
+{
+#if 0
+ endDraw (QPoint (), QRect ());
+ mainWindow ()->commandHistory ()->undo ();
+#else
+ m_timer->stop ();
+
+ m_currentCommand->finalize ();
+ m_currentCommand->cancel ();
+
+ delete m_currentCommand;
+ m_currentCommand = 0;
+#endif
+
+ setUserMessage (i18n ("Let go of all the mouse buttons."));
+}
+
+void kpToolAirSpray::releasedAllButtons ()
+{
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+// virtual
+void kpToolAirSpray::endDraw (const QPoint &, const QRect &)
+{
+ m_timer->stop ();
+
+ m_currentCommand->finalize ();
+ mainWindow ()->commandHistory ()->addCommand (m_currentCommand, false /* don't exec */);
+
+ // don't delete - it's up to the commandHistory
+ m_currentCommand = 0;
+
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+
+/*
+ * kpToolAirSprayCommand
+ */
+
+kpToolAirSprayCommand::kpToolAirSprayCommand (const kpColor &color, int size,
+ kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ m_color (color),
+ m_size (size),
+ m_newPixmapPtr (0)
+{
+ m_oldPixmap = *document ()->pixmap ();
+}
+
+kpToolAirSprayCommand::~kpToolAirSprayCommand ()
+{
+ delete m_newPixmapPtr;
+}
+
+
+// public virtual [base kpCommand]
+QString kpToolAirSprayCommand::name () const
+{
+ return i18n ("Spraycan");
+}
+
+
+// public virtual [base kpCommand]
+int kpToolAirSprayCommand::size () const
+{
+ return kpPixmapFX::pixmapSize (m_newPixmapPtr) +
+ kpPixmapFX::pixmapSize (m_oldPixmap);
+}
+
+
+// Redo:
+//
+// must not call before unexecute() as m_newPixmapPtr is null
+// (one reason why we told addCommand() not to execute,
+// the other being that the dots have already been draw onto the doc)
+void kpToolAirSprayCommand::execute ()
+{
+ if (m_newPixmapPtr)
+ {
+ document ()->setPixmapAt (*m_newPixmapPtr, m_boundingRect.topLeft ());
+
+ // (will be regenerated in unexecute() if required)
+ delete m_newPixmapPtr;
+ m_newPixmapPtr = 0;
+ }
+ else
+ kdError () << "kpToolAirSprayCommand::execute() has null m_newPixmapPtr" << endl;
+}
+
+// Undo:
+void kpToolAirSprayCommand::unexecute ()
+{
+ if (!m_newPixmapPtr)
+ {
+ // the ultimate in laziness - figure out Redo info only if we Undo
+ m_newPixmapPtr = new QPixmap (m_boundingRect.width (), m_boundingRect.height ());
+ *m_newPixmapPtr = document ()->getPixmapAt (m_boundingRect);
+ }
+ else
+ kdError () << "kpToolAirSprayCommand::unexecute() has non-null newPixmapPtr" << endl;
+
+ document ()->setPixmapAt (m_oldPixmap, m_boundingRect.topLeft ());
+}
+
+
+// public
+void kpToolAirSprayCommand::addPoints (const QPointArray &points)
+{
+ QRect docRect = points.boundingRect ();
+
+#if DEBUG_KP_TOOL_SPRAYCAN
+ kdDebug () << "kpToolAirSprayCommand::addPoints() docRect=" << docRect
+ << " numPoints=" << points.count () << endl;
+ for (int i = 0; i < (int) points.count (); i++)
+ kdDebug () << "\t" << i << ": " << points [i] << endl;
+#endif
+
+ QPixmap pixmap = document ()->getPixmapAt (docRect);
+ QBitmap mask;
+
+ QPainter painter, maskPainter;
+
+ if (m_color.isOpaque ())
+ {
+ painter.begin (&pixmap);
+ painter.setPen (m_color.toQColor ());
+ }
+
+ if (pixmap.mask () || m_color.isTransparent ())
+ {
+ mask = kpPixmapFX::getNonNullMask (pixmap);
+ maskPainter.begin (&mask);
+ maskPainter.setPen (m_color.maskColor ());
+ }
+
+ for (int i = 0; i < (int) points.count (); i++)
+ {
+ QPoint pt (points [i].x () - docRect.x (),
+ points [i].y () - docRect.y ());
+
+ if (painter.isActive ())
+ painter.drawPoint (pt);
+
+ if (maskPainter.isActive ())
+ maskPainter.drawPoint (pt);
+ }
+
+ if (maskPainter.isActive ())
+ maskPainter.end ();
+
+ if (painter.isActive ())
+ painter.end ();
+
+ if (!mask.isNull ())
+ pixmap.setMask (mask);
+
+ viewManager ()->setFastUpdates ();
+ document ()->setPixmapAt (pixmap, docRect.topLeft ());
+ viewManager ()->restoreFastUpdates ();
+
+ m_boundingRect = m_boundingRect.unite (docRect);
+}
+
+void kpToolAirSprayCommand::finalize ()
+{
+ // store only needed part of doc pixmap
+ m_oldPixmap = kpTool::neededPixmap (m_oldPixmap, m_boundingRect);
+}
+
+void kpToolAirSprayCommand::cancel ()
+{
+ if (m_boundingRect.isValid ())
+ {
+ viewManager ()->setFastUpdates ();
+ document ()->setPixmapAt (m_oldPixmap, m_boundingRect.topLeft ());
+ viewManager ()->restoreFastUpdates ();
+ }
+}
+
+#include <kptoolairspray.moc>
diff --git a/kolourpaint/tools/kptoolairspray.h b/kolourpaint/tools/kptoolairspray.h
new file mode 100644
index 00000000..24f02787
--- /dev/null
+++ b/kolourpaint/tools/kptoolairspray.h
@@ -0,0 +1,110 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolairspray_h__
+#define __kptoolairspray_h__
+
+#include <kpcommandhistory.h>
+#include <kpcolor.h>
+#include <kptool.h>
+
+class QPixmap;
+class QPoint;
+class QRect;
+class QString;
+class QTimer;
+
+class kpMainWindow;
+class kpToolAirSprayCommand;
+class kpToolWidgetSpraycanSize;
+class kpViewManager;
+
+class kpToolAirSpray : public kpTool
+{
+Q_OBJECT
+
+public:
+ kpToolAirSpray (kpMainWindow *);
+ virtual ~kpToolAirSpray ();
+
+private:
+ QString haventBegunDrawUserMessage () const;
+
+public:
+ virtual void begin ();
+ virtual void end ();
+
+private slots:
+ void slotSpraycanSizeChanged (int size);
+
+public:
+ virtual void beginDraw ();
+ virtual void draw (const QPoint &thisPoint, const QPoint &, const QRect &);
+ virtual void cancelShape ();
+ virtual void releasedAllButtons ();
+ virtual void endDraw (const QPoint &, const QRect &);
+
+public slots:
+ void actuallyDraw ();
+
+private:
+ kpToolWidgetSpraycanSize *m_toolWidgetSpraycanSize;
+ kpToolAirSprayCommand *m_currentCommand;
+ QTimer *m_timer;
+ int m_size;
+};
+
+class kpToolAirSprayCommand : public kpCommand
+{
+public:
+ kpToolAirSprayCommand (const kpColor &color, int size,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolAirSprayCommand ();
+
+ virtual QString name () const;
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+ // interface for KToolAirSpray
+ void addPoints (const QPointArray &points);
+ void finalize ();
+ void cancel ();
+
+private:
+ kpColor m_color;
+ int m_size;
+
+ QPixmap *m_newPixmapPtr;
+ QPixmap m_oldPixmap;
+ QRect m_boundingRect;
+};
+
+#endif // __kptoolairspray_h__
diff --git a/kolourpaint/tools/kptoolautocrop.cpp b/kolourpaint/tools/kptoolautocrop.cpp
new file mode 100644
index 00000000..244c192d
--- /dev/null
+++ b/kolourpaint/tools/kptoolautocrop.cpp
@@ -0,0 +1,780 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// TODO: Color Similarity is obviously useful in Autocrop but it isn't
+// obvious as to how to implement it. The current heuristic,
+// for each side, chooses an arbitrary reference color for which
+// all other candidate pixels in that side are tested against
+// for similarity. But if the reference color happens to be at
+// one extreme of the range of colors in that side, then pixels
+// at the other extreme would not be deemed similar enough. The
+// key is to find the median color as the reference but how do
+// you do this if you don't know which pixels to sample in the first
+// place (that's what you're trying to find)? Chicken and egg situation.
+//
+// The other heuristic that is in doubt is the use of the average
+// color in determining the similarity of sides (it is possible
+// to get vastly differently colors in both sides yet they will be
+// considered similar).
+
+#define DEBUG_KP_TOOL_AUTO_CROP 0
+
+
+#include <kptoolautocrop.h>
+
+#include <qapplication.h>
+#include <qbitmap.h>
+#include <qimage.h>
+#include <qpainter.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include <kpcolortoolbar.h>
+#include <kpcommandhistory.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kpselection.h>
+#include <kptool.h>
+#include <kpviewmanager.h>
+
+
+kpToolAutoCropBorder::kpToolAutoCropBorder (const QPixmap *pixmapPtr,
+ int processedColorSimilarity)
+ : m_pixmapPtr (pixmapPtr),
+ m_processedColorSimilarity (processedColorSimilarity)
+{
+ invalidate ();
+}
+
+
+// public
+int kpToolAutoCropBorder::size () const
+{
+ return sizeof (kpToolAutoCropBorder);
+}
+
+
+// public
+const QPixmap *kpToolAutoCropBorder::pixmap () const
+{
+ return m_pixmapPtr;
+}
+
+// public
+int kpToolAutoCropBorder::processedColorSimilarity () const
+{
+ return m_processedColorSimilarity;
+}
+
+// public
+QRect kpToolAutoCropBorder::rect () const
+{
+ return m_rect;
+}
+
+// public
+int kpToolAutoCropBorder::left () const
+{
+ return m_rect.left ();
+}
+
+// public
+int kpToolAutoCropBorder::right () const
+{
+ return m_rect.right ();
+}
+
+// public
+int kpToolAutoCropBorder::top () const
+{
+ return m_rect.top ();
+}
+
+// public
+int kpToolAutoCropBorder::bottom () const
+{
+ return m_rect.bottom ();
+}
+
+// public
+kpColor kpToolAutoCropBorder::referenceColor () const
+{
+ return m_referenceColor;
+}
+
+// public
+kpColor kpToolAutoCropBorder::averageColor () const
+{
+ if (!m_rect.isValid ())
+ return kpColor::invalid;
+
+ if (m_referenceColor.isTransparent ())
+ return kpColor::transparent;
+ else if (m_processedColorSimilarity == 0)
+ return m_referenceColor;
+ else
+ {
+ int numPixels = (m_rect.width () * m_rect.height ());
+ if (numPixels <= 0)
+ {
+ kdError () << "kpToolAutoCropBorder::averageColor() rect=" << m_rect << endl;
+ return kpColor::invalid;
+ }
+
+ return kpColor (m_redSum / numPixels,
+ m_greenSum / numPixels,
+ m_blueSum / numPixels);
+ }
+}
+
+bool kpToolAutoCropBorder::isSingleColor () const
+{
+ return m_isSingleColor;
+}
+
+
+// public
+bool kpToolAutoCropBorder::calculate (int isX, int dir)
+{
+#if DEBUG_KP_TOOL_AUTO_CROP && 1
+ kdDebug () << "kpToolAutoCropBorder::calculate() CALLED!" << endl;
+#endif
+ int maxX = m_pixmapPtr->width () - 1;
+ int maxY = m_pixmapPtr->height () - 1;
+
+ QImage image = kpPixmapFX::convertToImage (*m_pixmapPtr);
+ if (image.isNull ())
+ {
+ kdError () << "Border::calculate() could not convert to QImage" << endl;
+ return false;
+ }
+
+ // (sync both branches)
+ if (isX)
+ {
+ int numCols = 0;
+ int startX = (dir > 0) ? 0 : maxX;
+
+ kpColor col = kpPixmapFX::getColorAtPixel (image, startX, 0);
+ for (int x = startX;
+ x >= 0 && x <= maxX;
+ x += dir)
+ {
+ int y;
+ for (y = 0; y <= maxY; y++)
+ {
+ if (!kpPixmapFX::getColorAtPixel (image, x, y).isSimilarTo (col, m_processedColorSimilarity))
+ break;
+ }
+
+ if (y <= maxY)
+ break;
+ else
+ numCols++;
+ }
+
+ if (numCols)
+ {
+ m_rect = QRect (QPoint (startX, 0),
+ QPoint (startX + (numCols - 1) * dir, maxY)).normalize ();
+ m_referenceColor = col;
+ }
+ }
+ else
+ {
+ int numRows = 0;
+ int startY = (dir > 0) ? 0 : maxY;
+
+ kpColor col = kpPixmapFX::getColorAtPixel (image, 0, startY);
+ for (int y = startY;
+ y >= 0 && y <= maxY;
+ y += dir)
+ {
+ int x;
+ for (x = 0; x <= maxX; x++)
+ {
+ if (!kpPixmapFX::getColorAtPixel (image, x, y).isSimilarTo (col, m_processedColorSimilarity))
+ break;
+ }
+
+ if (x <= maxX)
+ break;
+ else
+ numRows++;
+ }
+
+ if (numRows)
+ {
+ m_rect = QRect (QPoint (0, startY),
+ QPoint (maxX, startY + (numRows - 1) * dir)).normalize ();
+ m_referenceColor = col;
+ }
+ }
+
+
+ if (m_rect.isValid ())
+ {
+ m_isSingleColor = true;
+
+ if (m_referenceColor.isOpaque () && m_processedColorSimilarity != 0)
+ {
+ for (int y = m_rect.top (); y <= m_rect.bottom (); y++)
+ {
+ for (int x = m_rect.left (); x <= m_rect.right (); x++)
+ {
+ kpColor colAtPixel = kpPixmapFX::getColorAtPixel (image, x, y);
+
+ if (m_isSingleColor && colAtPixel != m_referenceColor)
+ m_isSingleColor = false;
+
+ m_redSum += colAtPixel.red ();
+ m_greenSum += colAtPixel.green ();
+ m_blueSum += colAtPixel.blue ();
+ }
+ }
+ }
+ }
+
+
+ return true;
+}
+
+// public
+bool kpToolAutoCropBorder::fillsEntirePixmap () const
+{
+ return (m_rect == m_pixmapPtr->rect ());
+}
+
+// public
+bool kpToolAutoCropBorder::exists () const
+{
+ // (will use in an addition so make sure returns 1 or 0)
+ return (m_rect.isValid () ? 1 : 0);
+}
+
+// public
+void kpToolAutoCropBorder::invalidate ()
+{
+ m_rect = QRect ();
+ m_referenceColor = kpColor::invalid;
+ m_redSum = m_greenSum = m_blueSum = 0;
+ m_isSingleColor = false;
+}
+
+
+class kpSetOverrideCursorSaver
+{
+public:
+ kpSetOverrideCursorSaver (const QCursor &cursor)
+ {
+ QApplication::setOverrideCursor (cursor);
+ }
+
+ ~kpSetOverrideCursorSaver ()
+ {
+ QApplication::restoreOverrideCursor ();
+ }
+};
+
+
+void showNothingToAutocropMessage (kpMainWindow *mainWindow, bool actOnSelection)
+{
+ kpSetOverrideCursorSaver cursorSaver (Qt::arrowCursor);
+
+ if (actOnSelection)
+ {
+ KMessageBox::information (mainWindow,
+ i18n ("KolourPaint cannot remove the selection's internal border as it"
+ " could not be located."),
+ i18n ("Cannot Remove Internal Border"),
+ "NothingToAutoCrop");
+ }
+ else
+ {
+ KMessageBox::information (mainWindow,
+ i18n ("KolourPaint cannot automatically crop the image as its"
+ " border could not be located."),
+ i18n ("Cannot Autocrop"),
+ "NothingToAutoCrop");
+ }
+}
+
+bool kpToolAutoCrop (kpMainWindow *mainWindow)
+{
+#if DEBUG_KP_TOOL_AUTO_CROP
+ kdDebug () << "kpToolAutoCrop() CALLED!" << endl;
+#endif
+
+ if (!mainWindow)
+ {
+ kdError () << "kpToolAutoCrop() passed NULL mainWindow" << endl;
+ return false;
+ }
+
+ kpDocument *doc = mainWindow->document ();
+ if (!doc)
+ {
+ kdError () << "kpToolAutoCrop() passed NULL document" << endl;
+ return false;
+ }
+
+ // OPT: if already pulled selection pixmap, no need to do it again here
+ QPixmap pixmap = doc->selection () ? doc->getSelectedPixmap () : *doc->pixmap ();
+ if (pixmap.isNull ())
+ {
+ kdError () << "kptoolAutoCrop() pased NULL pixmap" << endl;
+ return false;
+ }
+
+ kpViewManager *vm = mainWindow->viewManager ();
+ if (!vm)
+ {
+ kdError () << "kpToolAutoCrop() passed NULL vm" << endl;
+ return false;
+ }
+
+ int processedColorSimilarity = mainWindow->colorToolBar ()->processedColorSimilarity ();
+ kpToolAutoCropBorder leftBorder (&pixmap, processedColorSimilarity),
+ rightBorder (&pixmap, processedColorSimilarity),
+ topBorder (&pixmap, processedColorSimilarity),
+ botBorder (&pixmap, processedColorSimilarity);
+
+
+ kpSetOverrideCursorSaver cursorSaver (Qt::waitCursor);
+
+ // TODO: With Colour Similarity, a lot of weird (and wonderful) things can
+ // happen resulting in a huge number of code paths. Needs refactoring
+ // and regression testing.
+ //
+ // TODO: e.g. When the top fills entire rect but bot doesn't we could
+ // invalidate top and continue autocrop.
+ int numRegions = 0;
+ if (!leftBorder.calculate (true/*x*/, +1/*going right*/) ||
+ leftBorder.fillsEntirePixmap () ||
+ !rightBorder.calculate (true/*x*/, -1/*going left*/) ||
+ rightBorder.fillsEntirePixmap () ||
+ !topBorder.calculate (false/*y*/, +1/*going down*/) ||
+ topBorder.fillsEntirePixmap () ||
+ !botBorder.calculate (false/*y*/, -1/*going up*/) ||
+ botBorder.fillsEntirePixmap () ||
+ ((numRegions = leftBorder.exists () +
+ rightBorder.exists () +
+ topBorder.exists () +
+ botBorder.exists ()) == 0))
+ {
+ #if DEBUG_KP_TOOL_AUTO_CROP
+ kdDebug () << "\tcan't find border; leftBorder.rect=" << leftBorder.rect ()
+ << " rightBorder.rect=" << rightBorder.rect ()
+ << " topBorder.rect=" << topBorder.rect ()
+ << " botBorder.rect=" << botBorder.rect ()
+ << endl;
+ #endif
+ ::showNothingToAutocropMessage (mainWindow, (bool) doc->selection ());
+ return false;
+ }
+
+#if DEBUG_KP_TOOL_AUTO_CROP
+ kdDebug () << "\tnumRegions=" << numRegions << endl;
+ kdDebug () << "\t\tleft=" << leftBorder.rect ()
+ << " refCol=" << (leftBorder.exists () ? (int *) leftBorder.referenceColor ().toQRgb () : 0)
+ << " avgCol=" << (leftBorder.exists () ? (int *) leftBorder.averageColor ().toQRgb () : 0)
+ << endl;
+ kdDebug () << "\t\tright=" << rightBorder.rect ()
+ << " refCol=" << (rightBorder.exists () ? (int *) rightBorder.referenceColor ().toQRgb () : 0)
+ << " avgCol=" << (rightBorder.exists () ? (int *) rightBorder.averageColor ().toQRgb () : 0)
+ << endl;
+ kdDebug () << "\t\ttop=" << topBorder.rect ()
+ << " refCol=" << (topBorder.exists () ? (int *) topBorder.referenceColor ().toQRgb () : 0)
+ << " avgCol=" << (topBorder.exists () ? (int *) topBorder.averageColor ().toQRgb () : 0)
+ << endl;
+ kdDebug () << "\t\tbot=" << botBorder.rect ()
+ << " refCol=" << (botBorder.exists () ? (int *) botBorder.referenceColor ().toQRgb () : 0)
+ << " avgCol=" << (botBorder.exists () ? (int *) botBorder.averageColor ().toQRgb () : 0)
+ << endl;
+#endif
+
+
+ // In case e.g. the user pastes a solid, coloured-in rectangle,
+ // we favour killing the bottom and right regions
+ // (these regions probably contain the unwanted whitespace due
+ // to the doc being bigger than the pasted selection to start with).
+ //
+ // We also kill if they kiss or even overlap.
+
+ if (leftBorder.exists () && rightBorder.exists ())
+ {
+ const kpColor leftCol = leftBorder.averageColor ();
+ const kpColor rightCol = rightBorder.averageColor ();
+
+ if ((numRegions == 2 && !leftCol.isSimilarTo (rightCol, processedColorSimilarity)) ||
+ leftBorder.right () >= rightBorder.left () - 1) // kissing or overlapping
+ {
+ #if DEBUG_KP_TOOL_AUTO_CROP
+ kdDebug () << "\tignoring left border" << endl;
+ #endif
+ leftBorder.invalidate ();
+ }
+ }
+
+ if (topBorder.exists () && botBorder.exists ())
+ {
+ const kpColor topCol = topBorder.averageColor ();
+ const kpColor botCol = botBorder.averageColor ();
+
+ if ((numRegions == 2 && !topCol.isSimilarTo (botCol, processedColorSimilarity)) ||
+ topBorder.bottom () >= botBorder.top () - 1) // kissing or overlapping
+ {
+ #if DEBUG_KP_TOOL_AUTO_CROP
+ kdDebug () << "\tignoring top border" << endl;
+ #endif
+ topBorder.invalidate ();
+ }
+ }
+
+
+ mainWindow->addImageOrSelectionCommand (
+ new kpToolAutoCropCommand (
+ (bool) doc->selection (),
+ leftBorder, rightBorder,
+ topBorder, botBorder,
+ mainWindow));
+
+
+ return true;
+}
+
+
+kpToolAutoCropCommand::kpToolAutoCropCommand (bool actOnSelection,
+ const kpToolAutoCropBorder &leftBorder,
+ const kpToolAutoCropBorder &rightBorder,
+ const kpToolAutoCropBorder &topBorder,
+ const kpToolAutoCropBorder &botBorder,
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (name (actOnSelection, DontShowAccel), mainWindow),
+ m_actOnSelection (actOnSelection),
+ m_leftBorder (leftBorder),
+ m_rightBorder (rightBorder),
+ m_topBorder (topBorder),
+ m_botBorder (botBorder),
+ m_leftPixmap (0),
+ m_rightPixmap (0),
+ m_topPixmap (0),
+ m_botPixmap (0)
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ {
+ kdError () << "kpToolAutoCropCommand::<ctor>() without doc" << endl;
+ m_oldWidth = 0;
+ m_oldHeight = 0;
+ return;
+ }
+
+ m_oldWidth = doc->width (m_actOnSelection);
+ m_oldHeight = doc->height (m_actOnSelection);
+}
+
+kpToolAutoCropCommand::~kpToolAutoCropCommand ()
+{
+ deleteUndoPixmaps ();
+}
+
+
+// public static
+QString kpToolAutoCropCommand::name (bool actOnSelection, int options)
+{
+ if (actOnSelection)
+ {
+ if (options & ShowAccel)
+ return i18n ("Remove Internal B&order");
+ else
+ return i18n ("Remove Internal Border");
+ }
+ else
+ {
+ if (options & ShowAccel)
+ return i18n ("Autocr&op");
+ else
+ return i18n ("Autocrop");
+ }
+}
+
+
+// public virtual [base kpCommand]
+int kpToolAutoCropCommand::size () const
+{
+ return m_leftBorder.size () +
+ m_rightBorder.size () +
+ m_topBorder.size () +
+ m_botBorder.size () +
+ kpPixmapFX::pixmapSize (m_leftPixmap) +
+ kpPixmapFX::pixmapSize (m_rightPixmap) +
+ kpPixmapFX::pixmapSize (m_topPixmap) +
+ kpPixmapFX::pixmapSize (m_botPixmap) +
+ m_oldSelection.size ();
+}
+
+
+// private
+void kpToolAutoCropCommand::getUndoPixmap (const kpToolAutoCropBorder &border, QPixmap **pixmap)
+{
+ kpDocument *doc = document ();
+
+#if DEBUG_KP_TOOL_AUTO_CROP && 1
+ kdDebug () << "kpToolAutoCropCommand::getUndoPixmap()" << endl;
+ kdDebug () << "\tpixmap=" << pixmap
+ << " border: rect=" << border.rect ()
+ << " isSingleColor=" << border.isSingleColor ()
+ << endl;
+#endif
+
+ if (!doc)
+ return;
+
+ if (pixmap && border.exists () && !border.isSingleColor ())
+ {
+ if (*pixmap)
+ {
+ #if DEBUG_KP_TOOL_AUTO_CROP && 1
+ kdDebug () << "\talready have *pixmap - delete it" << endl;
+ #endif
+ delete *pixmap;
+ }
+
+ *pixmap = new QPixmap (
+ kpPixmapFX::getPixmapAt (*doc->pixmap (m_actOnSelection),
+ border.rect ()));
+ }
+}
+
+
+// private
+void kpToolAutoCropCommand::getUndoPixmaps ()
+{
+ getUndoPixmap (m_leftBorder, &m_leftPixmap);
+ getUndoPixmap (m_rightBorder, &m_rightPixmap);
+ getUndoPixmap (m_topBorder, &m_topPixmap);
+ getUndoPixmap (m_botBorder, &m_botPixmap);
+}
+
+// private
+void kpToolAutoCropCommand::deleteUndoPixmaps ()
+{
+#if DEBUG_KP_TOOL_AUTO_CROP && 1
+ kdDebug () << "kpToolAutoCropCommand::deleteUndoPixmaps()" << endl;
+#endif
+
+ delete m_leftPixmap; m_leftPixmap = 0;
+ delete m_rightPixmap; m_rightPixmap = 0;
+ delete m_topPixmap; m_topPixmap = 0;
+ delete m_botPixmap; m_botPixmap = 0;
+}
+
+
+// public virtual [base kpCommand]
+void kpToolAutoCropCommand::execute ()
+{
+ if (!m_contentsRect.isValid ())
+ m_contentsRect = contentsRect ();
+
+
+ getUndoPixmaps ();
+
+
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+
+ QPixmap pixmapWithoutBorder =
+ kpTool::neededPixmap (*doc->pixmap (m_actOnSelection),
+ m_contentsRect);
+
+
+ if (!m_actOnSelection)
+ doc->setPixmap (pixmapWithoutBorder);
+ else
+ {
+ m_oldSelection = *doc->selection ();
+ m_oldSelection.setPixmap (QPixmap ());
+
+ // m_contentsRect is relative to the top of the sel
+ // while sel is relative to the top of the doc
+ QRect rect = m_contentsRect;
+ rect.moveBy (m_oldSelection.x (), m_oldSelection.y ());
+
+ kpSelection sel (kpSelection::Rectangle,
+ rect,
+ pixmapWithoutBorder,
+ m_oldSelection.transparency ());
+
+ doc->setSelection (sel);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+}
+
+// public virtual [base kpCommand]
+void kpToolAutoCropCommand::unexecute ()
+{
+#if DEBUG_KP_TOOL_AUTO_CROP && 1
+ kdDebug () << "kpToolAutoCropCommand::unexecute()" << endl;
+#endif
+
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ QPixmap pixmap (m_oldWidth, m_oldHeight);
+ QBitmap maskBitmap;
+
+ // restore the position of the centre image
+ kpPixmapFX::setPixmapAt (&pixmap, m_contentsRect,
+ *doc->pixmap (m_actOnSelection));
+
+ // draw the borders
+
+ QPainter painter (&pixmap);
+ QPainter maskPainter;
+
+ const kpToolAutoCropBorder *borders [] =
+ {
+ &m_leftBorder, &m_rightBorder,
+ &m_topBorder, &m_botBorder,
+ 0
+ };
+
+ const QPixmap *pixmaps [] =
+ {
+ m_leftPixmap, m_rightPixmap,
+ m_topPixmap, m_botPixmap,
+ 0
+ };
+
+ const QPixmap **p = pixmaps;
+ for (const kpToolAutoCropBorder **b = borders; *b; b++, p++)
+ {
+ if (!(*b)->exists ())
+ continue;
+
+ if ((*b)->isSingleColor ())
+ {
+ kpColor col = (*b)->referenceColor ();
+ #if DEBUG_KP_TOOL_AUTO_CROP && 1
+ kdDebug () << "\tdrawing border " << (*b)->rect ()
+ << " rgb=" << (int *) col.toQRgb () /* %X hack */ << endl;
+ #endif
+
+ if (col.isOpaque ())
+ {
+ painter.fillRect ((*b)->rect (), col.toQColor ());
+ }
+ else
+ {
+ if (maskBitmap.isNull ())
+ {
+ // TODO: dangerous when a painter is active on pixmap?
+ maskBitmap = kpPixmapFX::getNonNullMask (pixmap);
+ maskPainter.begin (&maskBitmap);
+ }
+
+ maskPainter.fillRect ((*b)->rect (), Qt::color0/*transparent*/);
+ }
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_AUTO_CROP && 1
+ kdDebug () << "\trestoring border pixmap " << (*b)->rect () << endl;
+ #endif
+ // **p cannot contain a single transparent pixel because
+ // if it did, all other pixels must be transparent (only
+ // transparent pixels are similar to transparent pixels)
+ // and the other branch would execute.
+ if (*p)
+ {
+ // TODO: We should really edit the mask here. Due to good
+ // luck (if "maskBitmap" is initialized above, this region
+ // will be marked as opaque in the mask; if it's not
+ // initialized, we will be opaque by default), we
+ // don't actually have to edit the mask but this is
+ // highly error-prone.
+ painter.drawPixmap ((*b)->rect (), **p);
+ }
+ }
+ }
+
+ if (maskPainter.isActive ())
+ maskPainter.end ();
+
+ painter.end ();
+
+ if (!maskBitmap.isNull ())
+ pixmap.setMask (maskBitmap);
+
+
+ if (!m_actOnSelection)
+ doc->setPixmap (pixmap);
+ else
+ {
+ kpSelection sel = m_oldSelection;
+ sel.setPixmap (pixmap);
+
+ doc->setSelection (sel);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+
+
+ deleteUndoPixmaps ();
+}
+
+
+// private
+QRect kpToolAutoCropCommand::contentsRect () const
+{
+ const QPixmap *pixmap = document ()->pixmap (m_actOnSelection);
+
+ QPoint topLeft (m_leftBorder.exists () ?
+ m_leftBorder.rect ().right () + 1 :
+ 0,
+ m_topBorder.exists () ?
+ m_topBorder.rect ().bottom () + 1 :
+ 0);
+ QPoint botRight (m_rightBorder.exists () ?
+ m_rightBorder.rect ().left () - 1 :
+ pixmap->width () - 1,
+ m_botBorder.exists () ?
+ m_botBorder.rect ().top () - 1 :
+ pixmap->height () - 1);
+
+ return QRect (topLeft, botRight);
+}
diff --git a/kolourpaint/tools/kptoolautocrop.h b/kolourpaint/tools/kptoolautocrop.h
new file mode 100644
index 00000000..4d016a1d
--- /dev/null
+++ b/kolourpaint/tools/kptoolautocrop.h
@@ -0,0 +1,127 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolautocrop_h__
+#define __kptoolautocrop_h__
+
+#include <qrect.h>
+
+#include <kpcommandhistory.h>
+
+#include <kpcolor.h>
+#include <kpselection.h>
+
+class QPixmap;
+class kpDocument;
+class kpMainWindow;
+class kpViewManager;
+
+
+// (returns true on success (even if it did nothing) or false on error)
+bool kpToolAutoCrop (kpMainWindow *mainWindow);
+
+
+class kpToolAutoCropBorder
+{
+public:
+ kpToolAutoCropBorder (const QPixmap *pixmapPtr, int processedColorSimilarity);
+
+ int size () const;
+
+ const QPixmap *pixmap () const;
+ int processedColorSimilarity () const;
+ QRect rect () const;
+ int left () const;
+ int right () const;
+ int top () const;
+ int bottom () const;
+ kpColor referenceColor () const;
+ kpColor averageColor () const;
+ bool isSingleColor () const;
+
+ // (returns true on success (even if no rect) or false on error)
+ bool calculate (int isX, int dir);
+
+ bool fillsEntirePixmap () const;
+ bool exists () const;
+ void invalidate ();
+
+private:
+ const QPixmap *m_pixmapPtr;
+ int m_processedColorSimilarity;
+
+ QRect m_rect;
+ kpColor m_referenceColor;
+ int m_redSum, m_greenSum, m_blueSum;
+ bool m_isSingleColor;
+};
+
+
+class kpToolAutoCropCommand : public kpNamedCommand
+{
+public:
+ kpToolAutoCropCommand (bool actOnSelection,
+ const kpToolAutoCropBorder &leftBorder,
+ const kpToolAutoCropBorder &rightBorder,
+ const kpToolAutoCropBorder &topBorder,
+ const kpToolAutoCropBorder &botBorder,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolAutoCropCommand ();
+
+ enum NameOptions
+ {
+ DontShowAccel = 0,
+ ShowAccel = 1
+ };
+
+ static QString name (bool actOnSelection, int options);
+
+ virtual int size () const;
+
+private:
+ void getUndoPixmap (const kpToolAutoCropBorder &border, QPixmap **pixmap);
+ void getUndoPixmaps ();
+ void deleteUndoPixmaps ();
+
+public:
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ QRect contentsRect () const;
+
+ bool m_actOnSelection;
+ kpToolAutoCropBorder m_leftBorder, m_rightBorder, m_topBorder, m_botBorder;
+ QPixmap *m_leftPixmap, *m_rightPixmap, *m_topPixmap, *m_botPixmap;
+
+ QRect m_contentsRect;
+ int m_oldWidth, m_oldHeight;
+ kpSelection m_oldSelection;
+};
+
+#endif // __kptoolautocrop_h__
diff --git a/kolourpaint/tools/kptoolbrush.cpp b/kolourpaint/tools/kptoolbrush.cpp
new file mode 100644
index 00000000..6e684ed9
--- /dev/null
+++ b/kolourpaint/tools/kptoolbrush.cpp
@@ -0,0 +1,45 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <klocale.h>
+#include <kptoolbrush.h>
+
+kpToolBrush::kpToolBrush (kpMainWindow *mainWindow)
+ : kpToolPen (kpToolPen::Brush,
+ i18n ("Brush"),
+ i18n ("Draw using brushes of different shapes and sizes"),
+ Qt::Key_B,
+ mainWindow, "tool_brush")
+{
+}
+
+kpToolBrush::~kpToolBrush ()
+{
+}
+
+#include <kptoolbrush.moc>
diff --git a/kolourpaint/tools/kptoolbrush.h b/kolourpaint/tools/kptoolbrush.h
new file mode 100644
index 00000000..69498495
--- /dev/null
+++ b/kolourpaint/tools/kptoolbrush.h
@@ -0,0 +1,43 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolbrush_h__
+#define __kptoolbrush_h__
+
+#include <kptoolpen.h>
+
+class kpToolBrush : public kpToolPen
+{
+Q_OBJECT
+
+public:
+ kpToolBrush (kpMainWindow *mainWindow);
+ virtual ~kpToolBrush ();
+};
+
+#endif // __kptoolbrush_h__
diff --git a/kolourpaint/tools/kptoolclear.cpp b/kolourpaint/tools/kptoolclear.cpp
new file mode 100644
index 00000000..230e54a3
--- /dev/null
+++ b/kolourpaint/tools/kptoolclear.cpp
@@ -0,0 +1,135 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <kptoolclear.h>
+
+#include <qpixmap.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kpselection.h>
+
+
+kpToolClearCommand::kpToolClearCommand (bool actOnSelection,
+ const kpColor &newColor,
+ kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ m_actOnSelection (actOnSelection),
+ m_newColor (newColor),
+ m_oldPixmapPtr (0)
+{
+}
+
+kpToolClearCommand::kpToolClearCommand (bool actOnSelection,
+ kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ m_actOnSelection (actOnSelection),
+ m_newColor (mainWindow ? mainWindow->backgroundColor () : kpColor::invalid),
+ m_oldPixmapPtr (0)
+{
+}
+
+kpToolClearCommand::~kpToolClearCommand ()
+{
+ delete m_oldPixmapPtr;
+}
+
+
+// public virtual [base kpCommand]
+QString kpToolClearCommand::name () const
+{
+ QString opName = i18n ("Clear");
+
+ if (m_actOnSelection)
+ return i18n ("Selection: %1").arg (opName);
+ else
+ return opName;
+}
+
+
+// public virtual [base kpCommand]
+int kpToolClearCommand::size () const
+{
+ return kpPixmapFX::pixmapSize (m_oldPixmapPtr);
+}
+
+
+// public virtual [base kpCommand]
+void kpToolClearCommand::execute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ {
+ kdError () << "kpToolClearCommand::execute() without doc" << endl;
+ return;
+ }
+
+
+ m_oldPixmapPtr = new QPixmap ();
+ *m_oldPixmapPtr = *doc->pixmap (m_actOnSelection);
+
+
+ if (m_actOnSelection)
+ {
+ // OPT: could just edit pixmap directly and signal change
+ kpSelection *sel = doc->selection ();
+
+ QPixmap newPixmap (sel->width (), sel->height ());
+ kpPixmapFX::fill (&newPixmap, m_newColor);
+ // TODO: maybe disable Image/Clear if transparent colour
+ if (m_newColor.isOpaque ())
+ newPixmap.setMask (sel->maskForOwnType ());
+
+ sel->setPixmap (newPixmap);
+ }
+ else
+ doc->fill (m_newColor);
+}
+
+// public virtual [base kpCommand]
+void kpToolClearCommand::unexecute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ {
+ kdError () << "kpToolClearCommand::execute() without doc" << endl;
+ return;
+ }
+
+
+ doc->setPixmap (m_actOnSelection, *m_oldPixmapPtr);
+
+
+ delete m_oldPixmapPtr;
+ m_oldPixmapPtr = 0;
+}
diff --git a/kolourpaint/tools/kptoolclear.h b/kolourpaint/tools/kptoolclear.h
new file mode 100644
index 00000000..ccf3697f
--- /dev/null
+++ b/kolourpaint/tools/kptoolclear.h
@@ -0,0 +1,68 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolclear_h__
+#define __kptoolclear_h__
+
+#include <kpcommandhistory.h>
+
+#include <kpcolor.h>
+
+class QPixmap;
+class QString;
+
+class kpDocument;
+class kpMainWindow;
+
+
+class kpToolClearCommand : public kpCommand
+{
+public:
+ kpToolClearCommand (bool actOnSelection,
+ const kpColor &newColor,
+ kpMainWindow *mainWindow);
+ kpToolClearCommand (bool actOnSelection,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolClearCommand ();
+
+ virtual QString name () const;
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ bool m_actOnSelection;
+
+ kpColor m_newColor;
+ QPixmap *m_oldPixmapPtr;
+};
+
+
+#endif // __kptoolclear_h__
diff --git a/kolourpaint/tools/kptoolcolorpicker.cpp b/kolourpaint/tools/kptoolcolorpicker.cpp
new file mode 100644
index 00000000..1050b1cf
--- /dev/null
+++ b/kolourpaint/tools/kptoolcolorpicker.cpp
@@ -0,0 +1,197 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_TOOL_COLOR_PICKER 0
+
+
+#include <kptoolcolorpicker.h>
+
+#include <qimage.h>
+#include <qpixmap.h>
+#include <qpoint.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcolortoolbar.h>
+#include <kpcommandhistory.h>
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+
+
+/*
+ * kpToolColorPicker
+ */
+
+kpToolColorPicker::kpToolColorPicker (kpMainWindow *mainWindow)
+ : kpTool (i18n ("Color Picker"), i18n ("Lets you select a color from the image"),
+ Qt::Key_C,
+ mainWindow, "tool_color_picker")
+{
+}
+
+kpToolColorPicker::~kpToolColorPicker ()
+{
+}
+
+kpColor kpToolColorPicker::colorAtPixel (const QPoint &p)
+{
+#if DEBUG_KP_TOOL_COLOR_PICKER && 0
+ kdDebug () << "kpToolColorPicker::colorAtPixel" << p << endl;
+#endif
+
+ return kpPixmapFX::getColorAtPixel (*document ()->pixmap (), p);
+}
+
+
+QString kpToolColorPicker::haventBegunDrawUserMessage () const
+{
+ return i18n ("Click to select a color.");
+}
+
+void kpToolColorPicker::begin ()
+{
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+// virtual
+void kpToolColorPicker::beginDraw ()
+{
+ m_oldColor = color (m_mouseButton);
+
+ setUserMessage (cancelUserMessage ());
+}
+
+// virtual
+void kpToolColorPicker::draw (const QPoint &thisPoint, const QPoint &, const QRect &)
+{
+ const kpColor color = colorAtPixel (thisPoint);
+
+ if (color.isValid ())
+ {
+ mainWindow ()->colorToolBar ()->setColor (m_mouseButton, color);
+ setUserShapePoints (thisPoint);
+ }
+ else
+ {
+ mainWindow ()->colorToolBar ()->setColor (m_mouseButton, m_oldColor);
+ setUserShapePoints ();
+ }
+}
+
+// virtual
+void kpToolColorPicker::cancelShape ()
+{
+ mainWindow ()->colorToolBar ()->setColor (m_mouseButton, m_oldColor);
+
+ setUserMessage (i18n ("Let go of all the mouse buttons."));
+}
+
+void kpToolColorPicker::releasedAllButtons ()
+{
+ setUserMessage (haventBegunDrawUserMessage ());
+
+}
+
+// virtual
+void kpToolColorPicker::endDraw (const QPoint &thisPoint, const QRect &)
+{
+ const kpColor color = colorAtPixel (thisPoint);
+
+ if (color.isValid ())
+ {
+ kpToolColorPickerCommand *cmd = new kpToolColorPickerCommand (
+ m_mouseButton,
+ color, m_oldColor,
+ mainWindow ());
+
+ mainWindow ()->commandHistory ()->addCommand (cmd, false /* no exec */);
+ setUserMessage (haventBegunDrawUserMessage ());
+ }
+ else
+ {
+ cancelShape ();
+ }
+}
+
+/*
+ * kpToolColorPickerCommand
+ */
+
+kpToolColorPickerCommand::kpToolColorPickerCommand (int mouseButton,
+ const kpColor &newColor,
+ const kpColor &oldColor,
+ kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ m_mouseButton (mouseButton),
+ m_newColor (newColor),
+ m_oldColor (oldColor)
+{
+}
+
+kpToolColorPickerCommand::~kpToolColorPickerCommand ()
+{
+}
+
+
+// public virtual [base kpCommand]
+QString kpToolColorPickerCommand::name () const
+{
+ return i18n ("Color Picker");
+}
+
+
+// public virtual [base kpCommand]
+int kpToolColorPickerCommand::size () const
+{
+ return 0;
+}
+
+
+// public virtual [base kpCommand]
+void kpToolColorPickerCommand::execute ()
+{
+ colorToolBar ()->setColor (m_mouseButton, m_newColor);
+}
+
+// public virtual [base kpCommand]
+void kpToolColorPickerCommand::unexecute ()
+{
+ colorToolBar ()->setColor (m_mouseButton, m_oldColor);
+}
+
+
+// private
+kpColorToolBar *kpToolColorPickerCommand::colorToolBar () const
+{
+ return m_mainWindow ? m_mainWindow->colorToolBar () : 0;
+}
+
+#include <kptoolcolorpicker.moc>
diff --git a/kolourpaint/tools/kptoolcolorpicker.h b/kolourpaint/tools/kptoolcolorpicker.h
new file mode 100644
index 00000000..46fc94be
--- /dev/null
+++ b/kolourpaint/tools/kptoolcolorpicker.h
@@ -0,0 +1,95 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolcolorpicker_h__
+#define __kptoolcolorpicker_h__
+
+#include <kpcommandhistory.h>
+
+#include <kpcolor.h>
+#include <kptool.h>
+
+class QPoint;
+class QRect;
+
+class kpColorToolBar;
+
+class kpToolColorPicker : public kpTool
+{
+Q_OBJECT
+
+public:
+ kpToolColorPicker (kpMainWindow *);
+ virtual ~kpToolColorPicker ();
+
+ // generally the user goes to pick a color but wants to return to using
+ // his/her previous drawing tool
+ virtual bool returnToPreviousToolAfterEndDraw () const { return true; }
+
+private:
+ QString haventBegunDrawUserMessage () const;
+
+public:
+ virtual void begin ();
+ virtual void beginDraw ();
+ virtual void draw (const QPoint &thisPoint, const QPoint &, const QRect &);
+ virtual void cancelShape ();
+ virtual void releasedAllButtons ();
+ virtual void endDraw (const QPoint &thisPoint, const QRect &);
+
+private:
+ kpColor colorAtPixel (const QPoint &p);
+
+ kpColor m_oldColor;
+};
+
+class kpToolColorPickerCommand : public kpCommand
+{
+public:
+ kpToolColorPickerCommand (int mouseButton,
+ const kpColor &newColor, const kpColor &oldColor,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolColorPickerCommand ();
+
+ virtual QString name () const;
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ kpColorToolBar *colorToolBar () const;
+
+private:
+ int m_mouseButton;
+ kpColor m_newColor;
+ kpColor m_oldColor;
+};
+
+#endif // __kptoolcolorpicker_h__
diff --git a/kolourpaint/tools/kptoolcolorwasher.cpp b/kolourpaint/tools/kptoolcolorwasher.cpp
new file mode 100644
index 00000000..6c2d091f
--- /dev/null
+++ b/kolourpaint/tools/kptoolcolorwasher.cpp
@@ -0,0 +1,45 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <klocale.h>
+#include <kptoolcolorwasher.h>
+
+kpToolColorWasher::kpToolColorWasher (kpMainWindow *mainWindow)
+ : kpToolPen (kpToolPen::ColorWasher,
+ i18n ("Color Eraser"),
+ i18n ("Replaces pixels of the foreground color with the background color"),
+ Qt::Key_O,
+ mainWindow, "tool_color_washer")
+{
+}
+
+kpToolColorWasher::~kpToolColorWasher ()
+{
+}
+
+#include <kptoolcolorwasher.moc>
diff --git a/kolourpaint/tools/kptoolcolorwasher.h b/kolourpaint/tools/kptoolcolorwasher.h
new file mode 100644
index 00000000..1a707c3e
--- /dev/null
+++ b/kolourpaint/tools/kptoolcolorwasher.h
@@ -0,0 +1,43 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolcolorwasher_h__
+#define __kptoolcolorwasher_h__
+
+#include <kptoolpen.h>
+
+class kpToolColorWasher : public kpToolPen
+{
+Q_OBJECT
+
+public:
+ kpToolColorWasher (kpMainWindow *mainWindow);
+ virtual ~kpToolColorWasher ();
+};
+
+#endif // __kptoolcolorwasher_h__
diff --git a/kolourpaint/tools/kptoolconverttograyscale.cpp b/kolourpaint/tools/kptoolconverttograyscale.cpp
new file mode 100644
index 00000000..a80ef8fa
--- /dev/null
+++ b/kolourpaint/tools/kptoolconverttograyscale.cpp
@@ -0,0 +1,106 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <qapplication.h>
+#include <qpixmap.h>
+
+#include <klocale.h>
+
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kpselection.h>
+#include <kptoolconverttograyscale.h>
+
+
+kpToolConvertToGrayscaleCommand::kpToolConvertToGrayscaleCommand (bool actOnSelection,
+ kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ m_actOnSelection (actOnSelection),
+ m_oldPixmapPtr (0)
+{
+}
+
+kpToolConvertToGrayscaleCommand::~kpToolConvertToGrayscaleCommand ()
+{
+ delete m_oldPixmapPtr;
+}
+
+
+// public virtual [base kpCommand]
+QString kpToolConvertToGrayscaleCommand::name () const
+{
+ QString opName = i18n ("Reduce to Grayscale");
+
+ if (m_actOnSelection)
+ return i18n ("Selection: %1").arg (opName);
+ else
+ return opName;
+}
+
+
+// public virtual [base kpCommand]
+int kpToolConvertToGrayscaleCommand::size () const
+{
+ return kpPixmapFX::pixmapSize (m_oldPixmapPtr);
+}
+
+
+// public virtual [base kpCommand]
+void kpToolConvertToGrayscaleCommand::execute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ m_oldPixmapPtr = new QPixmap ();
+ *m_oldPixmapPtr = *doc->pixmap (m_actOnSelection);
+
+ QPixmap newPixmap = kpPixmapFX::convertToGrayscale (*doc->pixmap (m_actOnSelection));
+
+ doc->setPixmap (m_actOnSelection, newPixmap);
+
+ QApplication::restoreOverrideCursor ();
+}
+
+// public virtual [base kpCommand]
+void kpToolConvertToGrayscaleCommand::unexecute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ doc->setPixmap (m_actOnSelection, *m_oldPixmapPtr);
+
+ delete m_oldPixmapPtr;
+ m_oldPixmapPtr = 0;
+}
+
diff --git a/kolourpaint/tools/kptoolconverttograyscale.h b/kolourpaint/tools/kptoolconverttograyscale.h
new file mode 100644
index 00000000..6ea5e515
--- /dev/null
+++ b/kolourpaint/tools/kptoolconverttograyscale.h
@@ -0,0 +1,57 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolconverttograyscale_h__
+#define __kptoolconverttograyscale_h__
+
+#include <kpcommandhistory.h>
+
+class QPixmap;
+class QString;
+
+class kpMainWindow;
+
+class kpToolConvertToGrayscaleCommand : public kpCommand
+{
+public:
+ kpToolConvertToGrayscaleCommand (bool actOnSelection,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolConvertToGrayscaleCommand ();
+
+ virtual QString name () const;
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ bool m_actOnSelection;
+ QPixmap *m_oldPixmapPtr;
+};
+
+#endif // __kptoolconverttograyscale_h__
diff --git a/kolourpaint/tools/kptoolcrop.cpp b/kolourpaint/tools/kptoolcrop.cpp
new file mode 100644
index 00000000..8cc6e880
--- /dev/null
+++ b/kolourpaint/tools/kptoolcrop.cpp
@@ -0,0 +1,335 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_TOOL_CROP 0
+
+
+#include <kptoolcrop.h>
+
+#include <qpixmap.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcolor.h>
+#include <kpcommandhistory.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kpselection.h>
+#include <kptoolclear.h>
+#include <kptoolresizescale.h>
+#include <kptoolselection.h>
+#include <kpviewmanager.h>
+
+
+kpSelection selectionBorderAndMovedTo0_0 (const kpSelection &sel)
+{
+ kpSelection borderSel = sel;
+
+ borderSel.setPixmap (QPixmap ()); // only interested in border
+ borderSel.moveTo (QPoint (0, 0));
+
+ return borderSel;
+}
+
+
+//
+// kpToolCropSetImageCommand
+//
+
+class kpToolCropSetImageCommand : public kpCommand
+{
+public:
+ kpToolCropSetImageCommand (kpMainWindow *mainWindow);
+ virtual ~kpToolCropSetImageCommand ();
+
+ /* (uninteresting child of macro cmd) */
+ virtual QString name () const { return QString::null; }
+
+ virtual int size () const
+ {
+ return kpPixmapFX::pixmapSize (m_oldPixmap) +
+ kpPixmapFX::selectionSize (m_fromSelection) +
+ kpPixmapFX::pixmapSize (m_pixmapIfFromSelectionDoesntHaveOne);
+ }
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+protected:
+ kpColor m_backgroundColor;
+ QPixmap m_oldPixmap;
+ kpSelection m_fromSelection;
+ QPixmap m_pixmapIfFromSelectionDoesntHaveOne;
+};
+
+
+kpToolCropSetImageCommand::kpToolCropSetImageCommand (kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ m_backgroundColor (mainWindow ? mainWindow->backgroundColor () : kpColor::invalid),
+ m_fromSelection (*mainWindow->document ()->selection ()),
+ m_pixmapIfFromSelectionDoesntHaveOne (
+ m_fromSelection.pixmap () ?
+ QPixmap () :
+ mainWindow->document ()->getSelectedPixmap ())
+{
+}
+
+kpToolCropSetImageCommand::~kpToolCropSetImageCommand ()
+{
+}
+
+
+// public virtual [base kpCommand]
+void kpToolCropSetImageCommand::execute ()
+{
+#if DEBUG_KP_TOOL_CROP
+ kdDebug () << "kpToolCropSetImageCommand::execute()" << endl;
+#endif
+
+ viewManager ()->setQueueUpdates ();
+ {
+ m_oldPixmap = kpPixmapFX::getPixmapAt (*document ()->pixmap (),
+ QRect (0, 0, m_fromSelection.width (), m_fromSelection.height ()));
+
+
+ //
+ // e.g. original elliptical selection:
+ //
+ // t/---\ T = original transparent selection pixel
+ // | TT | t = outside the selection region
+ // t\__/t [every other character] = original opaque selection pixel
+ //
+ // Afterwards, the _document_ image becomes:
+ //
+ // b/---\ T = [unchanged]
+ // | TT | b = background color
+ // b\__/b [every other character] = [unchanged]
+ //
+ // The selection is deleted.
+ //
+ // TODO: Do not introduce a mask if the result will not contain
+ // any transparent pixels.
+ //
+
+ QPixmap newDocPixmap (m_fromSelection.width (), m_fromSelection.height ());
+ kpPixmapFX::fill (&newDocPixmap, m_backgroundColor);
+
+ #if DEBUG_KP_TOOL_CROP
+ kdDebug () << "\tsel: rect=" << m_fromSelection.boundingRect ()
+ << " pm=" << m_fromSelection.pixmap ()
+ << endl;
+ #endif
+ QPixmap selTransparentPixmap;
+
+ if (m_fromSelection.pixmap ())
+ {
+ selTransparentPixmap = m_fromSelection.transparentPixmap ();
+ #if DEBUG_KP_TOOL_CROP
+ kdDebug () << "\thave pixmap; rect="
+ << selTransparentPixmap.rect ()
+ << endl;
+ #endif
+ }
+ else
+ {
+ selTransparentPixmap = m_pixmapIfFromSelectionDoesntHaveOne;
+ #if DEBUG_KP_TOOL_CROP
+ kdDebug () << "\tno pixmap in sel - get it; rect="
+ << selTransparentPixmap.rect ()
+ << endl;
+ #endif
+ }
+
+ kpPixmapFX::paintMaskTransparentWithBrush (&newDocPixmap,
+ QPoint (0, 0),
+ m_fromSelection.maskForOwnType ());
+
+ kpPixmapFX::paintPixmapAt (&newDocPixmap,
+ QPoint (0, 0),
+ selTransparentPixmap);
+
+
+ document ()->setPixmapAt (newDocPixmap, QPoint (0, 0));
+ document ()->selectionDelete ();
+
+
+ if (mainWindow ()->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+ viewManager ()->restoreQueueUpdates ();
+}
+
+// public virtual [base kpCommand]
+void kpToolCropSetImageCommand::unexecute ()
+{
+#if DEBUG_KP_TOOL_CROP
+ kdDebug () << "kpToolCropSetImageCommand::unexecute()" << endl;
+#endif
+
+ viewManager ()->setQueueUpdates ();
+ {
+ document ()->setPixmapAt (m_oldPixmap, QPoint (0, 0));
+ m_oldPixmap.resize (0, 0);
+
+ #if DEBUG_KP_TOOL_CROP
+ kdDebug () << "\tsel: rect=" << m_fromSelection.boundingRect ()
+ << " pm=" << m_fromSelection.pixmap ()
+ << endl;
+ #endif
+ document ()->setSelection (m_fromSelection);
+
+ if (mainWindow ()->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+ viewManager ()->restoreQueueUpdates ();
+}
+
+
+//
+// kpToolCropCommand
+//
+
+
+class kpToolCropCommand : public kpMacroCommand
+{
+public:
+ kpToolCropCommand (kpMainWindow *mainWindow);
+ virtual ~kpToolCropCommand ();
+};
+
+
+kpToolCropCommand::kpToolCropCommand (kpMainWindow *mainWindow)
+ : kpMacroCommand (i18n ("Set as Image"), mainWindow)
+{
+#if DEBUG_KP_TOOL_CROP
+ kdDebug () << "kpToolCropCommand::<ctor>()" << endl;
+#endif
+
+ if (!mainWindow ||
+ !mainWindow->document () ||
+ !mainWindow->document ()->selection ())
+ {
+ kdError () << "kpToolCropCommand::kpToolCropCommand() without sel" << endl;
+ return;
+ }
+
+ kpSelection *sel = mainWindow->document ()->selection ();
+
+
+#if DEBUG_KP_TOOL_CROP
+ kdDebug () << "\tsel: w=" << sel->width ()
+ << " h=" << sel->height ()
+ << " <- resizing doc to these dimen" << endl;
+#endif
+
+ // (must resize doc _before_ kpToolCropSetImageCommand in case doc
+ // needs to gets bigger - else pasted down pixmap may not fit)
+ addCommand (
+ new kpToolResizeScaleCommand (
+ false/*act on doc, not sel*/,
+ sel->width (), sel->height (),
+ kpToolResizeScaleCommand::Resize,
+ mainWindow));
+
+
+ if (sel->isText ())
+ {
+ #if DEBUG_KP_TOOL_CROP
+ kdDebug () << "\tisText" << endl;
+ kdDebug () << "\tclearing doc with trans cmd" << endl;
+ #endif
+ addCommand (
+ new kpToolClearCommand (
+ false/*act on doc*/,
+ kpColor::transparent,
+ mainWindow));
+
+ #if DEBUG_KP_TOOL_CROP
+ kdDebug () << "\tmoving sel to (0,0) cmd" << endl;
+ #endif
+ kpToolSelectionMoveCommand *moveCmd =
+ new kpToolSelectionMoveCommand (
+ QString::null/*uninteresting child of macro cmd*/,
+ mainWindow);
+ moveCmd->moveTo (QPoint (0, 0), true/*move on exec, not now*/);
+ moveCmd->finalize ();
+ addCommand (moveCmd);
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_CROP
+ kdDebug () << "\tis pixmap sel" << endl;
+ kdDebug () << "\tcreating SetImage cmd" << endl;
+ #endif
+ addCommand (new kpToolCropSetImageCommand (mainWindow));
+
+ #if 0
+ addCommand (
+ new kpToolSelectionCreateCommand (
+ QString::null/*uninteresting child of macro cmd*/,
+ selectionBorderAndMovedTo0_0 (*sel),
+ mainWindow));
+ #endif
+ }
+}
+
+kpToolCropCommand::~kpToolCropCommand ()
+{
+}
+
+
+void kpToolCrop (kpMainWindow *mainWindow)
+{
+ kpDocument *doc = mainWindow->document ();
+ if (!doc)
+ return;
+
+ kpSelection *sel = doc ? doc->selection () : 0;
+ if (!sel)
+ return;
+
+
+ bool selWasText = sel->isText ();
+ kpSelection borderSel = selectionBorderAndMovedTo0_0 (*sel);
+
+
+ mainWindow->addImageOrSelectionCommand (
+ new kpToolCropCommand (mainWindow),
+ true/*add create cmd*/,
+ false/*don't add pull cmd*/);
+
+
+ if (!selWasText)
+ {
+ mainWindow->commandHistory ()->addCommand (
+ new kpToolSelectionCreateCommand (
+ i18n ("Selection: Create"),
+ borderSel,
+ mainWindow));
+ }
+}
diff --git a/kolourpaint/tools/kptoolcrop.h b/kolourpaint/tools/kptoolcrop.h
new file mode 100644
index 00000000..c710a041
--- /dev/null
+++ b/kolourpaint/tools/kptoolcrop.h
@@ -0,0 +1,39 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef KP_TOOL_CROP_H
+#define KP_TOOL_CROP_H
+
+
+class kpMainWindow;
+
+
+void kpToolCrop (kpMainWindow *mainWindow);
+
+
+#endif // KP_TOOL_CROP_H
diff --git a/kolourpaint/tools/kptoolcurve.cpp b/kolourpaint/tools/kptoolcurve.cpp
new file mode 100644
index 00000000..f889c1ba
--- /dev/null
+++ b/kolourpaint/tools/kptoolcurve.cpp
@@ -0,0 +1,47 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <kptoolcurve.h>
+
+#include <klocale.h>
+
+
+kpToolCurve::kpToolCurve (kpMainWindow *mainWindow)
+ : kpToolPolygon (Curve,
+ i18n ("Curve"),
+ i18n ("Draws curves"),
+ Qt::Key_V,
+ mainWindow, "tool_curve")
+{
+}
+
+kpToolCurve::~kpToolCurve ()
+{
+}
+
+#include <kptoolcurve.moc>
diff --git a/kolourpaint/tools/kptoolcurve.h b/kolourpaint/tools/kptoolcurve.h
new file mode 100644
index 00000000..489ce1fb
--- /dev/null
+++ b/kolourpaint/tools/kptoolcurve.h
@@ -0,0 +1,45 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolcurve_h__
+#define __kptoolcurve_h__
+
+#include <kptoolpolygon.h>
+
+class kpMainWindow;
+
+class kpToolCurve : public kpToolPolygon
+{
+Q_OBJECT
+
+public:
+ kpToolCurve (kpMainWindow *mainWindow);
+ virtual ~kpToolCurve ();
+};
+
+#endif // __kptoolcurve_h__
diff --git a/kolourpaint/tools/kptoolellipse.cpp b/kolourpaint/tools/kptoolellipse.cpp
new file mode 100644
index 00000000..f3b31dbb
--- /dev/null
+++ b/kolourpaint/tools/kptoolellipse.cpp
@@ -0,0 +1,45 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <klocale.h>
+#include <kptoolellipse.h>
+
+kpToolEllipse::kpToolEllipse (kpMainWindow *mainWindow)
+ : kpToolRectangle (Ellipse,
+ i18n ("Ellipse"),
+ i18n ("Draws ellipses and circles"),
+ Qt::Key_E,
+ mainWindow, "tool_ellipse")
+{
+}
+
+kpToolEllipse::~kpToolEllipse ()
+{
+}
+
+#include <kptoolellipse.moc>
diff --git a/kolourpaint/tools/kptoolellipse.h b/kolourpaint/tools/kptoolellipse.h
new file mode 100644
index 00000000..fc9bf798
--- /dev/null
+++ b/kolourpaint/tools/kptoolellipse.h
@@ -0,0 +1,45 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolellipse_h__
+#define __kptoolellipse_h__
+
+#include <kptoolrectangle.h>
+
+class kpMainWindow;
+
+class kpToolEllipse : public kpToolRectangle
+{
+Q_OBJECT
+
+public:
+ kpToolEllipse (kpMainWindow *);
+ virtual ~kpToolEllipse ();
+};
+
+#endif // __kptoolellipse_h__
diff --git a/kolourpaint/tools/kptoolellipticalselection.cpp b/kolourpaint/tools/kptoolellipticalselection.cpp
new file mode 100644
index 00000000..13daf799
--- /dev/null
+++ b/kolourpaint/tools/kptoolellipticalselection.cpp
@@ -0,0 +1,46 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <kptoolellipticalselection.h>
+
+#include <klocale.h>
+
+
+kpToolEllipticalSelection::kpToolEllipticalSelection (kpMainWindow *mainWindow)
+ : kpToolSelection (Ellipse,
+ i18n ("Selection (Elliptical)"),
+ i18n ("Makes an elliptical or circular selection"),
+ Qt::Key_I,
+ mainWindow, "tool_elliptical_selection")
+{
+}
+
+kpToolEllipticalSelection::~kpToolEllipticalSelection ()
+{
+}
+
diff --git a/kolourpaint/tools/kptoolellipticalselection.h b/kolourpaint/tools/kptoolellipticalselection.h
new file mode 100644
index 00000000..9dbd643e
--- /dev/null
+++ b/kolourpaint/tools/kptoolellipticalselection.h
@@ -0,0 +1,43 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolellipticalselection_h__
+#define __kptoolellipticalselection_h__
+
+#include <kptoolselection.h>
+
+class kpMainWindow;
+
+class kpToolEllipticalSelection : public kpToolSelection
+{
+public:
+ kpToolEllipticalSelection (kpMainWindow *);
+ virtual ~kpToolEllipticalSelection ();
+};
+
+#endif // __kptoolellipticalselection_h__
diff --git a/kolourpaint/tools/kptooleraser.cpp b/kolourpaint/tools/kptooleraser.cpp
new file mode 100644
index 00000000..1acbf66e
--- /dev/null
+++ b/kolourpaint/tools/kptooleraser.cpp
@@ -0,0 +1,44 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <klocale.h>
+#include <kptooleraser.h>
+
+kpToolEraser::kpToolEraser (kpMainWindow *mainWindow)
+ : kpToolPen (kpToolPen::Eraser,
+ i18n ("Eraser"), i18n ("Lets you rub out mistakes"),
+ Qt::Key_A,
+ mainWindow, "tool_eraser")
+{
+}
+
+kpToolEraser::~kpToolEraser ()
+{
+}
+
+#include <kptooleraser.moc>
diff --git a/kolourpaint/tools/kptooleraser.h b/kolourpaint/tools/kptooleraser.h
new file mode 100644
index 00000000..4dd7704a
--- /dev/null
+++ b/kolourpaint/tools/kptooleraser.h
@@ -0,0 +1,43 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptooleraser_h__
+#define __kptooleraser_h__
+
+#include <kptoolpen.h>
+
+class kpToolEraser : public kpToolPen
+{
+Q_OBJECT
+
+public:
+ kpToolEraser (kpMainWindow *mainWindow);
+ virtual ~kpToolEraser ();
+};
+
+#endif // __kptooleraser_h__
diff --git a/kolourpaint/tools/kptoolflip.cpp b/kolourpaint/tools/kptoolflip.cpp
new file mode 100644
index 00000000..58eeb66d
--- /dev/null
+++ b/kolourpaint/tools/kptoolflip.cpp
@@ -0,0 +1,213 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <kptoolflip.h>
+
+#include <qapplication.h>
+#include <qradiobutton.h>
+#include <qvbox.h>
+#include <qvbuttongroup.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kppixmapfx.h>
+#include <kpselection.h>
+#include <kptool.h>
+#include <kpmainwindow.h>
+
+
+/*
+ * kpToolFlipCommand
+ */
+
+kpToolFlipCommand::kpToolFlipCommand (bool actOnSelection,
+ bool horiz, bool vert,
+ kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ m_actOnSelection (actOnSelection),
+ m_horiz (horiz), m_vert (vert)
+{
+}
+
+kpToolFlipCommand::~kpToolFlipCommand ()
+{
+}
+
+
+// public virtual [base kpCommand]
+QString kpToolFlipCommand::name () const
+{
+ QString opName;
+
+
+#if 1
+ opName = i18n ("Flip");
+#else // re-enable when giving full descriptions for all actions
+ if (m_horiz && m_vert)
+ opName = i18n ("Flip horizontally and vertically");
+ else if (m_horiz)
+ opName = i18n ("Flip horizontally");
+ else if (m_vert)
+ opName = i18n ("Flip vertically");
+ else
+ {
+ kdError () << "kpToolFlipCommand::name() not asked to flip" << endl;
+ return QString::null;
+ }
+#endif
+
+
+ if (m_actOnSelection)
+ return i18n ("Selection: %1").arg (opName);
+ else
+ return opName;
+}
+
+
+// public virtual [base kpCommand]
+int kpToolFlipCommand::size () const
+{
+ return 0;
+}
+
+
+// public virtual [base kpCommand]
+void kpToolFlipCommand::execute ()
+{
+ flip ();
+}
+
+// public virtual [base kpCommand]
+void kpToolFlipCommand::unexecute ()
+{
+ flip ();
+}
+
+
+// private
+void kpToolFlipCommand::flip ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+
+ if (m_actOnSelection)
+ {
+ doc->selection ()->flip (m_horiz, m_vert);
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+ else
+ {
+ QPixmap newPixmap = kpPixmapFX::flip (*doc->pixmap (), m_horiz, m_vert);
+
+ doc->setPixmap (newPixmap);
+ }
+
+
+ QApplication::restoreOverrideCursor ();
+}
+
+
+/*
+ * kpToolFlipDialog
+ */
+
+// private static
+bool kpToolFlipDialog::s_lastIsVerticalFlip = true;
+
+
+kpToolFlipDialog::kpToolFlipDialog (bool actOnSelection, QWidget *parent)
+ : KDialogBase (parent, 0/*name*/, true/*modal*/,
+ actOnSelection ? i18n ("Flip Selection") : i18n ("Flip Image"),
+ KDialogBase::Ok | KDialogBase::Cancel)
+{
+ QVBox *vbox = makeVBoxMainWidget ();
+
+ if (!vbox)
+ {
+ kdError () << "kpToolFlipDialog::kpToolFlipDialog() received NULL vbox" << endl;
+ }
+ else
+ {
+ QVButtonGroup *buttonGroup = new QVButtonGroup (i18n ("Direction"), vbox);
+
+ // I'm sure vert flipping is much more common than horiz flipping so make it come first
+ m_verticalFlipRadioButton = new QRadioButton (i18n ("&Vertical (upside-down)"), buttonGroup);
+ m_horizontalFlipRadioButton = new QRadioButton (i18n ("&Horizontal"), buttonGroup);
+
+ m_verticalFlipRadioButton->setChecked (s_lastIsVerticalFlip);
+ m_horizontalFlipRadioButton->setChecked (!s_lastIsVerticalFlip);
+
+ connect (m_verticalFlipRadioButton, SIGNAL (toggled (bool)),
+ this, SLOT (slotIsVerticalFlipChanged ()));
+ connect (m_horizontalFlipRadioButton, SIGNAL (toggled (bool)),
+ this, SLOT (slotIsVerticalFlipChanged ()));
+ }
+}
+
+kpToolFlipDialog::~kpToolFlipDialog ()
+{
+}
+
+
+// public slot
+void kpToolFlipDialog::slotIsVerticalFlipChanged ()
+{
+ s_lastIsVerticalFlip = m_verticalFlipRadioButton->isChecked ();
+}
+
+
+// public
+bool kpToolFlipDialog::getHorizontalFlip () const
+{
+ return m_horizontalFlipRadioButton->isChecked ();
+}
+
+// public
+bool kpToolFlipDialog::getVerticalFlip () const
+{
+ return m_verticalFlipRadioButton->isChecked ();
+}
+
+// public
+bool kpToolFlipDialog::isNoOp () const
+{
+ return !getHorizontalFlip () && !getVerticalFlip ();
+}
+
+
+#include <kptoolflip.moc>
+
diff --git a/kolourpaint/tools/kptoolflip.h b/kolourpaint/tools/kptoolflip.h
new file mode 100644
index 00000000..c287c320
--- /dev/null
+++ b/kolourpaint/tools/kptoolflip.h
@@ -0,0 +1,88 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolflip_h__
+#define __kptoolflip_h__
+
+#include <kpcommandhistory.h>
+#include <kdialogbase.h>
+
+class QRadioButton;
+class QString;
+
+class kpDocument;
+class kpMainWindow;
+
+
+class kpToolFlipCommand : public kpCommand
+{
+public:
+ kpToolFlipCommand (bool actOnSelection,
+ bool horiz, bool vert,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolFlipCommand ();
+
+ virtual QString name () const;
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ void flip ();
+
+ bool m_actOnSelection;
+ bool m_horiz, m_vert;
+};
+
+
+class kpToolFlipDialog : public KDialogBase
+{
+Q_OBJECT
+
+public:
+ kpToolFlipDialog (bool actOnSelection, QWidget *parent);
+ ~kpToolFlipDialog ();
+
+private:
+ static bool s_lastIsVerticalFlip;
+
+public slots:
+ void slotIsVerticalFlipChanged ();
+
+public:
+ bool getHorizontalFlip () const;
+ bool getVerticalFlip () const;
+ bool isNoOp () const;
+
+private:
+ QRadioButton *m_horizontalFlipRadioButton, *m_verticalFlipRadioButton;
+};
+
+#endif // __kptoolflip_h__
diff --git a/kolourpaint/tools/kptoolfloodfill.cpp b/kolourpaint/tools/kptoolfloodfill.cpp
new file mode 100644
index 00000000..bb17d701
--- /dev/null
+++ b/kolourpaint/tools/kptoolfloodfill.cpp
@@ -0,0 +1,261 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_TOOL_FLOOD_FILL 0
+
+
+#include <kptoolfloodfill.h>
+
+#include <qapplication.h>
+#include <qcursor.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcommandhistory.h>
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kpview.h>
+#include <kpviewmanager.h>
+
+
+/*
+ * kpToolFloodFill
+ */
+
+kpToolFloodFill::kpToolFloodFill (kpMainWindow *mainWindow)
+ : kpTool (i18n ("Flood Fill"), i18n ("Fills regions in the image"),
+ Qt::Key_F,
+ mainWindow, "tool_flood_fill"),
+ m_currentCommand (0)
+{
+}
+
+kpToolFloodFill::~kpToolFloodFill ()
+{
+}
+
+QString kpToolFloodFill::haventBegunDrawUserMessage () const
+{
+ return i18n ("Click to fill a region.");
+}
+
+void kpToolFloodFill::begin ()
+{
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+// virtual
+void kpToolFloodFill::beginDraw ()
+{
+#if DEBUG_KP_TOOL_FLOOD_FILL && 1
+ kdDebug () << "kpToolFloodFill::beginDraw()" << endl;
+#endif
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ // Flood Fill is an expensive CPU operation so we only fill at a
+ // mouse click (beginDraw ()), not on mouse move (virtually draw())
+ m_currentCommand = new kpToolFloodFillCommand (m_currentPoint.x (), m_currentPoint.y (),
+ color (m_mouseButton), processedColorSimilarity (),
+ mainWindow ());
+
+ if (m_currentCommand->prepareColorToChange ())
+ {
+ #if DEBUG_KP_TOOL_FLOOD_FILL && 1
+ kdDebug () << "\tperforming new-doc-corner-case check" << endl;
+ #endif
+ if (document ()->url ().isEmpty () && !document ()->isModified ())
+ {
+ m_currentCommand->setFillEntirePixmap ();
+ m_currentCommand->execute ();
+ }
+ else if (m_currentCommand->prepare ())
+ {
+ m_currentCommand->execute ();
+ }
+ else
+ {
+ kdError () << "kpToolFloodFill::beginDraw() could not fill!" << endl;
+ }
+ }
+ else
+ {
+ kdError () << "kpToolFloodFill::beginDraw() could not prepareColorToChange!" << endl;
+ }
+
+ QApplication::restoreOverrideCursor ();
+
+ setUserMessage (cancelUserMessage ());
+}
+
+// virtual
+void kpToolFloodFill::draw (const QPoint &thisPoint, const QPoint &, const QRect &)
+{
+ setUserShapePoints (thisPoint);
+}
+
+// virtual
+void kpToolFloodFill::cancelShape ()
+{
+#if 0
+ endDraw (QPoint (), QRect ());
+ mainWindow ()->commandHistory ()->undo ();
+#else
+ m_currentCommand->unexecute ();
+
+ delete m_currentCommand;
+ m_currentCommand = 0;
+#endif
+
+ setUserMessage (i18n ("Let go of all the mouse buttons."));
+}
+
+void kpToolFloodFill::releasedAllButtons ()
+{
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+// virtual
+void kpToolFloodFill::endDraw (const QPoint &, const QRect &)
+{
+ mainWindow ()->commandHistory ()->addCommand (m_currentCommand,
+ false /* no exec - we already did it up there */);
+
+ // don't delete
+ m_currentCommand = 0;
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+
+/*
+ * kpToolFloodFillCommand
+ */
+
+kpToolFloodFillCommand::kpToolFloodFillCommand (int x, int y,
+ const kpColor &color, int processedColorSimilarity,
+ kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ kpFloodFill (document ()->pixmap (), x, y, color, processedColorSimilarity),
+ m_fillEntirePixmap (false)
+{
+}
+
+kpToolFloodFillCommand::~kpToolFloodFillCommand ()
+{
+}
+
+
+// public virtual [base kpCommand]
+QString kpToolFloodFillCommand::name () const
+{
+ return i18n ("Flood Fill");
+}
+
+// public virtual [base kpCommand]
+int kpToolFloodFillCommand::size () const
+{
+ return kpFloodFill::size () + kpPixmapFX::pixmapSize (m_oldPixmap);
+}
+
+
+void kpToolFloodFillCommand::setFillEntirePixmap (bool yes)
+{
+ m_fillEntirePixmap = yes;
+}
+
+
+// virtual
+void kpToolFloodFillCommand::execute ()
+{
+#if DEBUG_KP_TOOL_FLOOD_FILL && 1
+ kdDebug () << "kpToolFloodFillCommand::execute() m_fillEntirePixmap=" << m_fillEntirePixmap << endl;
+#endif
+
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+
+ if (m_fillEntirePixmap)
+ {
+ doc->fill (kpFloodFill::color ());
+ }
+ else
+ {
+ QRect rect = kpFloodFill::boundingRect ();
+ if (rect.isValid ())
+ {
+ QApplication::setOverrideCursor (QCursor::waitCursor);
+
+ m_oldPixmap = doc->getPixmapAt (rect);
+
+ kpFloodFill::fill ();
+ doc->slotContentsChanged (rect);
+
+ QApplication::restoreOverrideCursor ();
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_FLOOD_FILL && 1
+ kdDebug () << "\tinvalid boundingRect - must be NOP case" << endl;
+ #endif
+ }
+ }
+}
+
+// virtual
+void kpToolFloodFillCommand::unexecute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+
+ if (m_fillEntirePixmap)
+ {
+ doc->fill (kpFloodFill::colorToChange ());
+ }
+ else
+ {
+ QRect rect = kpFloodFill::boundingRect ();
+ if (rect.isValid ())
+ {
+ doc->setPixmapAt (m_oldPixmap, rect.topLeft ());
+
+ m_oldPixmap.resize (0, 0);
+
+ doc->slotContentsChanged (rect);
+ }
+ }
+}
+
+#include <kptoolfloodfill.moc>
diff --git a/kolourpaint/tools/kptoolfloodfill.h b/kolourpaint/tools/kptoolfloodfill.h
new file mode 100644
index 00000000..a2eeaa5a
--- /dev/null
+++ b/kolourpaint/tools/kptoolfloodfill.h
@@ -0,0 +1,94 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolfloodfill_h__
+#define __kptoolfloodfill_h__
+
+#include <qpixmap.h>
+
+#include <kpcommandhistory.h>
+
+#include <kpfloodfill.h>
+#include <kptool.h>
+
+
+class QString;
+
+class kpColor;
+
+class kpMainWindow;
+class kpToolFloodFillCommand;
+
+
+class kpToolFloodFill : public kpTool
+{
+Q_OBJECT
+
+public:
+ kpToolFloodFill (kpMainWindow *);
+ virtual ~kpToolFloodFill ();
+
+private:
+ QString haventBegunDrawUserMessage () const;
+
+public:
+ virtual void begin ();
+ virtual void beginDraw ();
+ virtual void draw (const QPoint &thisPoint, const QPoint &, const QRect &);
+ virtual void cancelShape ();
+ virtual void releasedAllButtons ();
+ virtual void endDraw (const QPoint &, const QRect &);
+
+private:
+ kpToolFloodFillCommand *m_currentCommand;
+};
+
+
+class kpToolFloodFillCommand : public kpCommand, public kpFloodFill
+{
+public:
+ kpToolFloodFillCommand (int x, int y,
+ const kpColor &color, int processedColorSimilarity,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolFloodFillCommand ();
+
+ virtual QString name () const;
+
+ virtual int size () const;
+
+ void setFillEntirePixmap (bool yes = true);
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ QPixmap m_oldPixmap;
+ bool m_fillEntirePixmap;
+};
+
+#endif // __kptoolfloodfill_h__
diff --git a/kolourpaint/tools/kptoolfreeformselection.cpp b/kolourpaint/tools/kptoolfreeformselection.cpp
new file mode 100644
index 00000000..7c736728
--- /dev/null
+++ b/kolourpaint/tools/kptoolfreeformselection.cpp
@@ -0,0 +1,46 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <kptoolfreeformselection.h>
+
+#include <klocale.h>
+
+
+kpToolFreeFormSelection::kpToolFreeFormSelection (kpMainWindow *mainWindow)
+ : kpToolSelection (kpToolSelection::FreeForm,
+ i18n ("Selection (Free-Form)"),
+ i18n ("Makes a free-form selection"),
+ Qt::Key_M,
+ mainWindow, "tool_free_form_selection")
+{
+}
+
+kpToolFreeFormSelection::~kpToolFreeFormSelection ()
+{
+}
+
diff --git a/kolourpaint/tools/kptoolfreeformselection.h b/kolourpaint/tools/kptoolfreeformselection.h
new file mode 100644
index 00000000..28f1e5ec
--- /dev/null
+++ b/kolourpaint/tools/kptoolfreeformselection.h
@@ -0,0 +1,43 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolfreeformselection_h__
+#define __kptoolfreeformselection_h__
+
+#include <kptoolselection.h>
+
+class kpMainWindow;
+
+class kpToolFreeFormSelection : public kpToolSelection
+{
+public:
+ kpToolFreeFormSelection (kpMainWindow *);
+ virtual ~kpToolFreeFormSelection ();
+};
+
+#endif // __kptoolfreeformselection_h__
diff --git a/kolourpaint/tools/kptoolline.cpp b/kolourpaint/tools/kptoolline.cpp
new file mode 100644
index 00000000..809824d9
--- /dev/null
+++ b/kolourpaint/tools/kptoolline.cpp
@@ -0,0 +1,47 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <kptoolline.h>
+
+#include <klocale.h>
+
+
+kpToolLine::kpToolLine (kpMainWindow *mainWindow)
+ : kpToolPolygon (Line,
+ i18n ("Line"),
+ i18n ("Draws lines"),
+ Qt::Key_L,
+ mainWindow, "tool_line")
+{
+}
+
+kpToolLine::~kpToolLine ()
+{
+}
+
+#include <kptoolline.moc>
diff --git a/kolourpaint/tools/kptoolline.h b/kolourpaint/tools/kptoolline.h
new file mode 100644
index 00000000..7a956245
--- /dev/null
+++ b/kolourpaint/tools/kptoolline.h
@@ -0,0 +1,45 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolline_h__
+#define __kptoolline_h__
+
+#include <kptoolpolygon.h>
+
+class kpMainWindow;
+
+class kpToolLine : public kpToolPolygon
+{
+Q_OBJECT
+
+public:
+ kpToolLine (kpMainWindow *);
+ virtual ~kpToolLine ();
+};
+
+#endif // __kptoolline_h__
diff --git a/kolourpaint/tools/kptoolpen.cpp b/kolourpaint/tools/kptoolpen.cpp
new file mode 100644
index 00000000..eb731ceb
--- /dev/null
+++ b/kolourpaint/tools/kptoolpen.cpp
@@ -0,0 +1,1145 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_TOOL_PEN 0
+
+#include <qapplication.h>
+#include <qbitmap.h>
+#include <qcursor.h>
+#include <qimage.h>
+#include <qpainter.h>
+#if DEBUG_KP_TOOL_PEN
+ #include <qdatetime.h>
+#endif
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcolor.h>
+#include <kpcommandhistory.h>
+#include <kpcursorprovider.h>
+#include <kptoolpen.h>
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kptemppixmap.h>
+#include <kptoolclear.h>
+#include <kptooltoolbar.h>
+#include <kptoolwidgetbrush.h>
+#include <kptoolwidgeterasersize.h>
+#include <kpviewmanager.h>
+
+/*
+ * kpToolPen
+ */
+
+kpToolPen::kpToolPen (Mode mode,
+ const QString &text, const QString &description,
+ int key,
+ kpMainWindow *mainWindow, const char *name)
+ : kpTool (text, description, key, mainWindow, name),
+ m_mode (mode),
+ m_toolWidgetBrush (0),
+ m_toolWidgetEraserSize (0),
+ m_currentCommand (0)
+{
+}
+
+kpToolPen::kpToolPen (kpMainWindow *mainWindow)
+ : kpTool (i18n ("Pen"), i18n ("Draws dots and freehand strokes"),
+ Qt::Key_P,
+ mainWindow, "tool_pen"),
+ m_mode (Pen),
+ m_toolWidgetBrush (0),
+ m_toolWidgetEraserSize (0),
+ m_currentCommand (0)
+{
+}
+
+void kpToolPen::setMode (Mode mode)
+{
+ int usesPixmaps = (mode & (DrawsPixmaps | WashesPixmaps));
+ int usesBrushes = (mode & (SquareBrushes | DiverseBrushes));
+
+ if ((usesPixmaps && !usesBrushes) ||
+ (usesBrushes && !usesPixmaps))
+ {
+ kdError () << "kpToolPen::setMode() passed invalid mode" << endl;
+ return;
+ }
+
+ m_mode = mode;
+}
+
+kpToolPen::~kpToolPen ()
+{
+}
+
+
+// private
+QString kpToolPen::haventBegunDrawUserMessage () const
+{
+ switch (m_mode)
+ {
+ case Pen:
+ case Brush:
+ return i18n ("Click to draw dots or drag to draw strokes.");
+ return i18n ("Click to draw dots or drag to draw strokes.");
+ case Eraser:
+ return i18n ("Click or drag to erase.");
+ case ColorWasher:
+ return i18n ("Click or drag to erase pixels of the foreground color.");
+ default:
+ return QString::null;
+ }
+}
+
+// virtual
+void kpToolPen::begin ()
+{
+ m_toolWidgetBrush = 0;
+ m_brushIsDiagonalLine = false;
+
+ kpToolToolBar *tb = toolToolBar ();
+ if (!tb)
+ return;
+
+ if (m_mode & SquareBrushes)
+ {
+ m_toolWidgetEraserSize = tb->toolWidgetEraserSize ();
+ connect (m_toolWidgetEraserSize, SIGNAL (eraserSizeChanged (int)),
+ this, SLOT (slotEraserSizeChanged (int)));
+ m_toolWidgetEraserSize->show ();
+
+ slotEraserSizeChanged (m_toolWidgetEraserSize->eraserSize ());
+
+ viewManager ()->setCursor (kpCursorProvider::lightCross ());
+ }
+
+ if (m_mode & DiverseBrushes)
+ {
+ m_toolWidgetBrush = tb->toolWidgetBrush ();
+ connect (m_toolWidgetBrush, SIGNAL (brushChanged (const QPixmap &, bool)),
+ this, SLOT (slotBrushChanged (const QPixmap &, bool)));
+ m_toolWidgetBrush->show ();
+
+ slotBrushChanged (m_toolWidgetBrush->brush (),
+ m_toolWidgetBrush->brushIsDiagonalLine ());
+
+ viewManager ()->setCursor (kpCursorProvider::lightCross ());
+ }
+
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+// virtual
+void kpToolPen::end ()
+{
+ if (m_toolWidgetEraserSize)
+ {
+ disconnect (m_toolWidgetEraserSize, SIGNAL (eraserSizeChanged (int)),
+ this, SLOT (slotEraserSizeChanged (int)));
+ m_toolWidgetEraserSize = 0;
+ }
+
+ if (m_toolWidgetBrush)
+ {
+ disconnect (m_toolWidgetBrush, SIGNAL (brushChanged (const QPixmap &, bool)),
+ this, SLOT (slotBrushChanged (const QPixmap &, bool)));
+ m_toolWidgetBrush = 0;
+ }
+
+ kpViewManager *vm = viewManager ();
+ if (vm)
+ {
+ if (vm->tempPixmap () && vm->tempPixmap ()->isBrush ())
+ vm->invalidateTempPixmap ();
+
+ if (m_mode & (SquareBrushes | DiverseBrushes))
+ vm->unsetCursor ();
+ }
+
+ // save memory
+ for (int i = 0; i < 2; i++)
+ m_brushPixmap [i].resize (0, 0);
+ m_cursorPixmap.resize (0, 0);
+}
+
+// virtual
+void kpToolPen::beginDraw ()
+{
+ switch (m_mode)
+ {
+ case Pen:
+ m_currentCommand = new kpToolPenCommand (i18n ("Pen"), mainWindow ());
+ break;
+ case Brush:
+ m_currentCommand = new kpToolPenCommand (i18n ("Brush"), mainWindow ());
+ break;
+ case Eraser:
+ m_currentCommand = new kpToolPenCommand (i18n ("Eraser"), mainWindow ());
+ break;
+ case ColorWasher:
+ m_currentCommand = new kpToolPenCommand (i18n ("Color Eraser"), mainWindow ());
+ break;
+
+ default:
+ m_currentCommand = new kpToolPenCommand (i18n ("Custom Pen or Brush"), mainWindow ());
+ break;
+ }
+
+ // we normally show the Brush pix in the foreground colour but if the
+ // user starts drawing in the background color, we don't want to leave
+ // the cursor in the foreground colour -- just hide it in all cases
+ // to avoid confusion
+ viewManager ()->invalidateTempPixmap ();
+
+ setUserMessage (cancelUserMessage ());
+}
+
+// virtual
+void kpToolPen::hover (const QPoint &point)
+{
+#if DEBUG_KP_TOOL_PEN && 0
+ kdDebug () << "kpToolPen::hover(" << point << ")"
+ << " hasBegun=" << hasBegun ()
+ << " hasBegunDraw=" << hasBegunDraw ()
+ << " cursorPixmap.isNull=" << m_cursorPixmap.isNull ()
+ << endl;
+#endif
+ if (point != KP_INVALID_POINT && !m_cursorPixmap.isNull ())
+ {
+ // (for hotPoint() as m_mouseButton is not normally defined in hover())
+ m_mouseButton = 0;
+
+ kpTempPixmap::RenderMode renderMode;
+ QPixmap cursorPixmapForTempPixmap = m_cursorPixmap;
+
+ if (m_mode & SquareBrushes)
+ renderMode = kpTempPixmap::SetPixmap;
+ else if (m_mode & DiverseBrushes)
+ {
+ if (color (0).isOpaque ())
+ renderMode = kpTempPixmap::PaintPixmap;
+ else
+ {
+ renderMode = kpTempPixmap::PaintMaskTransparentWithBrush;
+ cursorPixmapForTempPixmap = kpPixmapFX::getNonNullMask (m_cursorPixmap);
+ }
+ }
+
+ viewManager ()->setFastUpdates ();
+
+ viewManager ()->setTempPixmap (
+ kpTempPixmap (true/*brush*/,
+ renderMode,
+ hotPoint (),
+ cursorPixmapForTempPixmap));
+
+ viewManager ()->restoreFastUpdates ();
+ }
+
+#if DEBUG_KP_TOOL_PEN && 0
+ if (document ()->rect ().contains (point))
+ {
+ QImage image = kpPixmapFX::convertToImage (*document ()->pixmap ());
+
+ QRgb v = image.pixel (point.x (), point.y ());
+ kdDebug () << "(" << point << "): r=" << qRed (v)
+ << " g=" << qGreen (v)
+ << " b=" << qBlue (v)
+ << " a=" << qAlpha (v)
+ << endl;
+ }
+#endif
+
+ setUserShapePoints (point);
+}
+
+bool kpToolPen::wash (QPainter *painter, QPainter *maskPainter,
+ const QImage &image,
+ const kpColor &colorToReplace,
+ const QRect &imageRect, int plotx, int ploty)
+{
+ return wash (painter, maskPainter, image, colorToReplace, imageRect, hotRect (plotx, ploty));
+}
+
+bool kpToolPen::wash (QPainter *painter, QPainter *maskPainter,
+ const QImage &image,
+ const kpColor &colorToReplace,
+ const QRect &imageRect, const QRect &drawRect)
+{
+ bool didSomething = false;
+
+#if DEBUG_KP_TOOL_PEN && 0
+ kdDebug () << "kpToolPen::wash(imageRect=" << imageRect
+ << ",drawRect=" << drawRect
+ << ")" << endl;
+#endif
+
+// make use of scanline coherence
+#define FLUSH_LINE() \
+{ \
+ if (painter && painter->isActive ()) \
+ painter->drawLine (startDrawX, y, x - 1, y); \
+ if (maskPainter && maskPainter->isActive ()) \
+ maskPainter->drawLine (startDrawX, y, x - 1, y); \
+ didSomething = true; \
+ startDrawX = -1; \
+}
+
+ const int maxY = drawRect.bottom () - imageRect.top ();
+
+ const int minX = drawRect.left () - imageRect.left ();
+ const int maxX = drawRect.right () - imageRect.left ();
+
+ for (int y = drawRect.top () - imageRect.top ();
+ y <= maxY;
+ y++)
+ {
+ int startDrawX = -1;
+
+ int x; // for FLUSH_LINE()
+ for (x = minX; x <= maxX; x++)
+ {
+ #if DEBUG_KP_TOOL_PEN && 0
+ fprintf (stderr, "y=%i x=%i colorAtPixel=%08X colorToReplace=%08X ... ",
+ y, x,
+ kpPixmapFX::getColorAtPixel (image, QPoint (x, y)).toQRgb (),
+ colorToReplace.toQRgb ());
+ #endif
+ if (kpPixmapFX::getColorAtPixel (image, QPoint (x, y)).isSimilarTo (colorToReplace, processedColorSimilarity ()))
+ {
+ #if DEBUG_KP_TOOL_PEN && 0
+ fprintf (stderr, "similar\n");
+ #endif
+ if (startDrawX < 0)
+ startDrawX = x;
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_PEN && 0
+ fprintf (stderr, "different\n");
+ #endif
+ if (startDrawX >= 0)
+ FLUSH_LINE ();
+ }
+ }
+
+ if (startDrawX >= 0)
+ FLUSH_LINE ();
+ }
+
+#undef FLUSH_LINE
+
+ return didSomething;
+}
+
+// virtual
+void kpToolPen::globalDraw ()
+{
+ // it's easiest to reimplement globalDraw() here rather than in
+ // all the relevant subclasses
+
+ if (m_mode == Eraser)
+ {
+ #if DEBUG_KP_TOOL_PEN
+ kdDebug () << "kpToolPen::globalDraw() eraser" << endl;
+ #endif
+ mainWindow ()->commandHistory ()->addCommand (
+ new kpToolClearCommand (false/*act on doc, not sel*/, mainWindow ()));
+ }
+ else if (m_mode == ColorWasher)
+ {
+ #if DEBUG_KP_TOOL_PEN
+ kdDebug () << "kpToolPen::globalDraw() colour eraser" << endl;
+ #endif
+ if (foregroundColor () == backgroundColor () && processedColorSimilarity () == 0)
+ return;
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ kpToolPenCommand *cmd = new kpToolPenCommand (
+ i18n ("Color Eraser"), mainWindow ());
+
+ QPainter painter, maskPainter;
+ QBitmap maskBitmap;
+
+ if (backgroundColor ().isOpaque ())
+ {
+ painter.begin (document ()->pixmap ());
+ painter.setPen (backgroundColor ().toQColor ());
+ }
+
+ if (backgroundColor ().isTransparent () ||
+ document ()->pixmap ()->mask ())
+ {
+ maskBitmap = kpPixmapFX::getNonNullMask (*document ()->pixmap ());
+ maskPainter.begin (&maskBitmap);
+
+ maskPainter.setPen (backgroundColor ().maskColor ());
+ }
+
+ const QImage image = kpPixmapFX::convertToImage (*document ()->pixmap ());
+ QRect rect = document ()->rect ();
+
+ const bool didSomething = wash (&painter, &maskPainter, image,
+ foregroundColor ()/*replace foreground*/,
+ rect, rect);
+
+ // flush
+ if (painter.isActive ())
+ painter.end ();
+
+ if (maskPainter.isActive ())
+ maskPainter.end ();
+
+ if (didSomething)
+ {
+ if (!maskBitmap.isNull ())
+ document ()->pixmap ()->setMask (maskBitmap);
+
+
+ document ()->slotContentsChanged (rect);
+
+
+ cmd->updateBoundingRect (rect);
+ cmd->finalize ();
+
+ mainWindow ()->commandHistory ()->addCommand (cmd, false /* don't exec */);
+
+ // don't delete - it's up to the commandHistory
+ cmd = 0;
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_PEN
+ kdDebug () << "\tisNOP" << endl;
+ #endif
+ delete cmd;
+ cmd = 0;
+ }
+
+ QApplication::restoreOverrideCursor ();
+ }
+}
+
+// virtual
+// TODO: refactor!
+void kpToolPen::draw (const QPoint &thisPoint, const QPoint &lastPoint, const QRect &)
+{
+ if ((m_mode & WashesPixmaps) && (foregroundColor () == backgroundColor ()) && processedColorSimilarity () == 0)
+ return;
+
+ // sync: remember to restoreFastUpdates() in all exit paths
+ viewManager ()->setFastUpdates ();
+
+ if (m_brushIsDiagonalLine ? currentPointCardinallyNextToLast () : currentPointNextToLast ())
+ {
+ if (m_mode & DrawsPixels)
+ {
+ QPixmap pixmap (1, 1);
+
+ const kpColor c = color (m_mouseButton);
+
+ // OPT: this seems hopelessly inefficient
+ if (c.isOpaque ())
+ {
+ pixmap.fill (c.toQColor ());
+ }
+ else
+ {
+ QBitmap mask (1, 1);
+ mask.fill (Qt::color0/*transparent*/);
+
+ pixmap.setMask (mask);
+ }
+
+ // draw onto doc
+ document ()->setPixmapAt (pixmap, thisPoint);
+
+ m_currentCommand->updateBoundingRect (thisPoint);
+ }
+ // Brush & Eraser
+ else if (m_mode & DrawsPixmaps)
+ {
+ if (color (m_mouseButton).isOpaque ())
+ document ()->paintPixmapAt (m_brushPixmap [m_mouseButton], hotPoint ());
+ else
+ {
+ kpPixmapFX::paintMaskTransparentWithBrush (document ()->pixmap (),
+ hotPoint (),
+ kpPixmapFX::getNonNullMask (m_brushPixmap [m_mouseButton]));
+ document ()->slotContentsChanged (hotRect ());
+ }
+
+ m_currentCommand->updateBoundingRect (hotRect ());
+ }
+ else if (m_mode & WashesPixmaps)
+ {
+ #if DEBUG_KP_TOOL_PEN
+ kdDebug () << "Washing pixmap (immediate)" << endl;
+ QTime timer;
+ #endif
+ QRect rect = hotRect ();
+ #if DEBUG_KP_TOOL_PEN
+ timer.start ();
+ #endif
+ QPixmap pixmap = document ()->getPixmapAt (rect);
+ #if DEBUG_KP_TOOL_PEN
+ kdDebug () << "\tget from doc: " << timer.restart () << "ms" << endl;
+ #endif
+ const QImage image = kpPixmapFX::convertToImage (pixmap);
+ #if DEBUG_KP_TOOL_PEN
+ kdDebug () << "\tconvert to image: " << timer.restart () << "ms" << endl;
+ #endif
+ QPainter painter, maskPainter;
+ QBitmap maskBitmap;
+
+ if (color (m_mouseButton).isOpaque ())
+ {
+ painter.begin (&pixmap);
+ painter.setPen (color (m_mouseButton).toQColor ());
+ }
+
+ if (color (m_mouseButton).isTransparent () ||
+ pixmap.mask ())
+ {
+ maskBitmap = kpPixmapFX::getNonNullMask (pixmap);
+ maskPainter.begin (&maskBitmap);
+ maskPainter.setPen (color (m_mouseButton).maskColor ());
+ }
+
+ bool didSomething = wash (&painter, &maskPainter,
+ image,
+ color (1 - m_mouseButton)/*color to replace*/,
+ rect, rect);
+
+ if (painter.isActive ())
+ painter.end ();
+
+ if (maskPainter.isActive ())
+ maskPainter.end ();
+
+ if (didSomething)
+ {
+ if (!maskBitmap.isNull ())
+ pixmap.setMask (maskBitmap);
+
+ #if DEBUG_KP_TOOL_PEN
+ kdDebug () << "\twashed: " << timer.restart () << "ms" << endl;
+ #endif
+ document ()->setPixmapAt (pixmap, hotPoint ());
+ #if DEBUG_KP_TOOL_PEN
+ kdDebug () << "\tset doc: " << timer.restart () << "ms" << endl;
+ #endif
+ m_currentCommand->updateBoundingRect (hotRect ());
+ #if DEBUG_KP_TOOL_PEN
+ kdDebug () << "\tupdate boundingRect: " << timer.restart () << "ms" << endl;
+ kdDebug () << "\tdone" << endl;
+ #endif
+ }
+
+ #if DEBUG_KP_TOOL_PEN && 1
+ kdDebug () << endl;
+ #endif
+ }
+ }
+ // in reality, the system is too slow to give us all the MouseMove events
+ // so we "interpolate" the missing points :)
+ else
+ {
+ // find bounding rectangle
+ QRect rect = QRect (thisPoint, lastPoint).normalize ();
+ if (m_mode != DrawsPixels)
+ rect = neededRect (rect, m_brushPixmap [m_mouseButton].width ());
+
+ #if DEBUG_KP_TOOL_PEN
+ if (m_mode & WashesPixmaps)
+ {
+ kdDebug () << "Washing pixmap (w=" << rect.width ()
+ << ",h=" << rect.height () << ")" << endl;
+ }
+ QTime timer;
+ int convAndWashTime;
+ #endif
+
+ const kpColor c = color (m_mouseButton);
+ bool transparent = c.isTransparent ();
+
+ QPixmap pixmap = document ()->getPixmapAt (rect);
+ QBitmap maskBitmap;
+
+ QPainter painter, maskPainter;
+
+ if (m_mode & (DrawsPixels | WashesPixmaps))
+ {
+ if (!transparent)
+ {
+ painter.begin (&pixmap);
+ painter.setPen (c.toQColor ());
+ }
+
+ if (transparent || pixmap.mask ())
+ {
+ maskBitmap = kpPixmapFX::getNonNullMask (pixmap);
+ maskPainter.begin (&maskBitmap);
+ maskPainter.setPen (c.maskColor ());
+ }
+ }
+
+ QImage image;
+ if (m_mode & WashesPixmaps)
+ {
+ #if DEBUG_KP_TOOL_PEN
+ timer.start ();
+ #endif
+ image = kpPixmapFX::convertToImage (pixmap);
+ #if DEBUG_KP_TOOL_PEN
+ convAndWashTime = timer.restart ();
+ kdDebug () << "\tconvert to image: " << convAndWashTime << " ms" << endl;
+ #endif
+ }
+
+ bool didSomething = false;
+
+ if (m_mode & DrawsPixels)
+ {
+ QPoint sp = lastPoint - rect.topLeft (), ep = thisPoint - rect.topLeft ();
+ if (painter.isActive ())
+ painter.drawLine (sp, ep);
+
+ if (maskPainter.isActive ())
+ maskPainter.drawLine (sp, ep);
+
+ didSomething = true;
+ }
+ // Brush & Eraser
+ else if (m_mode & (DrawsPixmaps | WashesPixmaps))
+ {
+ kpColor colorToReplace;
+
+ if (m_mode & WashesPixmaps)
+ colorToReplace = color (1 - m_mouseButton);
+
+ // Sweeps a pixmap along a line (modified Bresenham's line algorithm,
+ // see MODIFIED comment below).
+ //
+ // Derived from the zSprite2 Graphics Engine
+
+ const int x1 = (thisPoint - rect.topLeft ()).x (),
+ y1 = (thisPoint - rect.topLeft ()).y (),
+ x2 = (lastPoint - rect.topLeft ()).x (),
+ y2 = (lastPoint - rect.topLeft ()).y ();
+
+ // Difference of x and y values
+ int dx = x2 - x1;
+ int dy = y2 - y1;
+
+ // Absolute values of differences
+ int ix = kAbs (dx);
+ int iy = kAbs (dy);
+
+ // Larger of the x and y differences
+ int inc = ix > iy ? ix : iy;
+
+ // Plot location
+ int plotx = x1;
+ int ploty = y1;
+
+ int x = 0;
+ int y = 0;
+
+ if (m_mode & WashesPixmaps)
+ {
+ if (wash (&painter, &maskPainter, image,
+ colorToReplace,
+ rect, plotx + rect.left (), ploty + rect.top ()))
+ {
+ didSomething = true;
+ }
+ }
+ else
+ {
+ if (!transparent)
+ {
+ kpPixmapFX::paintPixmapAt (&pixmap,
+ hotPoint (plotx, ploty),
+ m_brushPixmap [m_mouseButton]);
+ }
+ else
+ {
+ kpPixmapFX::paintMaskTransparentWithBrush (&pixmap,
+ hotPoint (plotx, ploty),
+ kpPixmapFX::getNonNullMask (m_brushPixmap [m_mouseButton]));
+ }
+
+ didSomething = true;
+ }
+
+ for (int i = 0; i <= inc; i++)
+ {
+ // oldplotx is equally as valid but would look different
+ // (but nobody will notice which one it is)
+ int oldploty = ploty;
+ int plot = 0;
+
+ x += ix;
+ y += iy;
+
+ if (x > inc)
+ {
+ plot++;
+ x -= inc;
+
+ if (dx < 0)
+ plotx--;
+ else
+ plotx++;
+ }
+
+ if (y > inc)
+ {
+ plot++;
+ y -= inc;
+
+ if (dy < 0)
+ ploty--;
+ else
+ ploty++;
+ }
+
+ if (plot)
+ {
+ if (m_brushIsDiagonalLine && plot == 2)
+ {
+ // MODIFIED: every point is
+ // horizontally or vertically adjacent to another point (if there
+ // is more than 1 point, of course). This is in contrast to the
+ // ordinary line algorithm which can create diagonal adjacencies.
+
+ if (m_mode & WashesPixmaps)
+ {
+ if (wash (&painter, &maskPainter, image,
+ colorToReplace,
+ rect, plotx + rect.left (), oldploty + rect.top ()))
+ {
+ didSomething = true;
+ }
+ }
+ else
+ {
+ if (!transparent)
+ {
+ kpPixmapFX::paintPixmapAt (&pixmap,
+ hotPoint (plotx, oldploty),
+ m_brushPixmap [m_mouseButton]);
+ }
+ else
+ {
+ kpPixmapFX::paintMaskTransparentWithBrush (&pixmap,
+ hotPoint (plotx, oldploty),
+ kpPixmapFX::getNonNullMask (m_brushPixmap [m_mouseButton]));
+ }
+
+ didSomething = true;
+ }
+ }
+
+ if (m_mode & WashesPixmaps)
+ {
+ if (wash (&painter, &maskPainter, image,
+ colorToReplace,
+ rect, plotx + rect.left (), ploty + rect.top ()))
+ {
+ didSomething = true;
+ }
+ }
+ else
+ {
+ if (!transparent)
+ {
+ kpPixmapFX::paintPixmapAt (&pixmap,
+ hotPoint (plotx, ploty),
+ m_brushPixmap [m_mouseButton]);
+ }
+ else
+ {
+ kpPixmapFX::paintMaskTransparentWithBrush (&pixmap,
+ hotPoint (plotx, ploty),
+ kpPixmapFX::getNonNullMask (m_brushPixmap [m_mouseButton]));
+ }
+
+ didSomething = true;
+ }
+ }
+ }
+
+ }
+
+ if (painter.isActive ())
+ painter.end ();
+
+ if (maskPainter.isActive ())
+ maskPainter.end ();
+
+ #if DEBUG_KP_TOOL_PEN
+ if (m_mode & WashesPixmaps)
+ {
+ int ms = timer.restart ();
+ kdDebug () << "\ttried to wash: " << ms << "ms"
+ << " (" << (ms ? (rect.width () * rect.height () / ms) : -1234)
+ << " pixels/ms)"
+ << endl;
+ convAndWashTime += ms;
+ }
+ #endif
+
+
+ if (didSomething)
+ {
+ if (!maskBitmap.isNull ())
+ pixmap.setMask (maskBitmap);
+
+ // draw onto doc
+ document ()->setPixmapAt (pixmap, rect.topLeft ());
+
+ #if DEBUG_KP_TOOL_PEN
+ if (m_mode & WashesPixmaps)
+ {
+ int ms = timer.restart ();
+ kdDebug () << "\tset doc: " << ms << "ms" << endl;
+ convAndWashTime += ms;
+ }
+ #endif
+
+ m_currentCommand->updateBoundingRect (rect);
+
+ #if DEBUG_KP_TOOL_PEN
+ if (m_mode & WashesPixmaps)
+ {
+ int ms = timer.restart ();
+ kdDebug () << "\tupdate boundingRect: " << ms << "ms" << endl;
+ convAndWashTime += ms;
+ kdDebug () << "\tdone (" << (convAndWashTime ? (rect.width () * rect.height () / convAndWashTime) : -1234)
+ << " pixels/ms)"
+ << endl;
+ }
+ #endif
+ }
+
+ #if DEBUG_KP_TOOL_PEN
+ if (m_mode & WashesPixmaps)
+ kdDebug () << endl;
+ #endif
+ }
+
+ viewManager ()->restoreFastUpdates ();
+ setUserShapePoints (thisPoint);
+}
+
+// virtual
+void kpToolPen::cancelShape ()
+{
+ m_currentCommand->finalize ();
+ m_currentCommand->cancel ();
+
+ delete m_currentCommand;
+ m_currentCommand = 0;
+
+ updateBrushCursor (false/*no recalc*/);
+
+ setUserMessage (i18n ("Let go of all the mouse buttons."));
+}
+
+void kpToolPen::releasedAllButtons ()
+{
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+// virtual
+void kpToolPen::endDraw (const QPoint &, const QRect &)
+{
+ m_currentCommand->finalize ();
+ mainWindow ()->commandHistory ()->addCommand (m_currentCommand, false /* don't exec */);
+
+ // don't delete - it's up to the commandHistory
+ m_currentCommand = 0;
+
+ updateBrushCursor (false/*no recalc*/);
+
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+
+// TODO: maybe the base should be virtual?
+kpColor kpToolPen::color (int which)
+{
+#if DEBUG_KP_TOOL_PEN && 0
+ kdDebug () << "kpToolPen::color (" << which << ")" << endl;
+#endif
+
+ // Pen & Brush
+ if ((m_mode & SwappedColors) == 0)
+ return kpTool::color (which);
+ // only the (Color) Eraser uses the opposite color
+ else
+ return kpTool::color (which ? 0 : 1); // don't trust !0 == 1
+}
+
+// virtual private slot
+void kpToolPen::slotForegroundColorChanged (const kpColor &col)
+{
+#if DEBUG_KP_TOOL_PEN
+ kdDebug () << "kpToolPen::slotForegroundColorChanged()" << endl;
+#endif
+ if (col.isOpaque ())
+ m_brushPixmap [(m_mode & SwappedColors) ? 1 : 0].fill (col.toQColor ());
+
+ updateBrushCursor ();
+}
+
+// virtual private slot
+void kpToolPen::slotBackgroundColorChanged (const kpColor &col)
+{
+#if DEBUG_KP_TOOL_PEN
+ kdDebug () << "kpToolPen::slotBackgroundColorChanged()" << endl;
+#endif
+
+ if (col.isOpaque ())
+ m_brushPixmap [(m_mode & SwappedColors) ? 0 : 1].fill (col.toQColor ());
+
+ updateBrushCursor ();
+}
+
+// private slot
+void kpToolPen::slotBrushChanged (const QPixmap &pixmap, bool isDiagonalLine)
+{
+#if DEBUG_KP_TOOL_PEN
+ kdDebug () << "kpToolPen::slotBrushChanged()" << endl;
+#endif
+ for (int i = 0; i < 2; i++)
+ {
+ m_brushPixmap [i] = pixmap;
+ if (color (i).isOpaque ())
+ m_brushPixmap [i].fill (color (i).toQColor ());
+ }
+
+ m_brushIsDiagonalLine = isDiagonalLine;
+
+ updateBrushCursor ();
+}
+
+// private slot
+void kpToolPen::slotEraserSizeChanged (int size)
+{
+#if DEBUG_KP_TOOL_PEN
+ kdDebug () << "KpToolPen::slotEraserSizeChanged(size=" << size << ")" << endl;
+#endif
+
+ for (int i = 0; i < 2; i++)
+ {
+ // Note: No matter what, the eraser's brush pixmap is never given
+ // a mask.
+ //
+ // With a transparent color, since we don't fill anything, the
+ // resize by itself will leave us with garbage pixels. This
+ // doesn't matter because:
+ //
+ // 1. The hover cursor will ask kpToolWidgetEraserSize for a proper
+ // cursor pixmap.
+ // 2. We will draw using kpPixmapFX::paintMaskTransparentWithBrush()
+ // which only cares about the opaqueness.
+ m_brushPixmap [i].resize (size, size);
+ if (color (i).isOpaque ())
+ m_brushPixmap [i].fill (color (i).toQColor ());
+ }
+
+ updateBrushCursor ();
+}
+
+QPoint kpToolPen::hotPoint () const
+{
+ return hotPoint (m_currentPoint);
+}
+
+QPoint kpToolPen::hotPoint (int x, int y) const
+{
+ return hotPoint (QPoint (x, y));
+}
+
+QPoint kpToolPen::hotPoint (const QPoint &point) const
+{
+ /*
+ * e.g.
+ * Width 5:
+ * 0 1 2 3 4
+ * ^
+ * |
+ * Center
+ */
+ return point -
+ QPoint (m_brushPixmap [m_mouseButton].width () / 2,
+ m_brushPixmap [m_mouseButton].height () / 2);
+}
+
+QRect kpToolPen::hotRect () const
+{
+ return hotRect (m_currentPoint);
+}
+
+QRect kpToolPen::hotRect (int x, int y) const
+{
+ return hotRect (QPoint (x, y));
+}
+
+QRect kpToolPen::hotRect (const QPoint &point) const
+{
+ QPoint topLeft = hotPoint (point);
+ return QRect (topLeft.x (),
+ topLeft.y (),
+ m_brushPixmap [m_mouseButton].width (),
+ m_brushPixmap [m_mouseButton].height ());
+}
+
+// private
+void kpToolPen::updateBrushCursor (bool recalc)
+{
+#if DEBUG_KP_TOOL_PEN && 1
+ kdDebug () << "kpToolPen::updateBrushCursor(recalc=" << recalc << ")" << endl;
+#endif
+
+ if (recalc)
+ {
+ if (m_mode & SquareBrushes)
+ m_cursorPixmap = m_toolWidgetEraserSize->cursorPixmap (color (0));
+ else if (m_mode & DiverseBrushes)
+ m_cursorPixmap = m_brushPixmap [0];
+ }
+
+ hover (hasBegun () ? m_currentPoint : currentPoint ());
+}
+
+
+/*
+ * kpToolPenCommand
+ */
+
+kpToolPenCommand::kpToolPenCommand (const QString &name, kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow),
+ m_pixmap (*document ()->pixmap ())
+{
+}
+
+kpToolPenCommand::~kpToolPenCommand ()
+{
+}
+
+
+// public virtual [base kpCommand]
+int kpToolPenCommand::size () const
+{
+ return kpPixmapFX::pixmapSize (m_pixmap);
+}
+
+
+// public virtual [base kpCommand]
+void kpToolPenCommand::execute ()
+{
+ swapOldAndNew ();
+}
+
+// public virtual [base kpCommand]
+void kpToolPenCommand::unexecute ()
+{
+ swapOldAndNew ();
+}
+
+
+// private
+void kpToolPenCommand::swapOldAndNew ()
+{
+ if (m_boundingRect.isValid ())
+ {
+ QPixmap oldPixmap = document ()->getPixmapAt (m_boundingRect);
+
+ document ()->setPixmapAt (m_pixmap, m_boundingRect.topLeft ());
+
+ m_pixmap = oldPixmap;
+ }
+}
+
+// public
+void kpToolPenCommand::updateBoundingRect (const QPoint &point)
+{
+ updateBoundingRect (QRect (point, point));
+}
+
+// public
+void kpToolPenCommand::updateBoundingRect (const QRect &rect)
+{
+#if DEBUG_KP_TOOL_PEN & 0
+ kdDebug () << "kpToolPenCommand::updateBoundingRect() existing="
+ << m_boundingRect
+ << " plus="
+ << rect
+ << endl;
+#endif
+ m_boundingRect = m_boundingRect.unite (rect);
+#if DEBUG_KP_TOOL_PEN & 0
+ kdDebug () << "\tresult=" << m_boundingRect << endl;
+#endif
+}
+
+// public
+void kpToolPenCommand::finalize ()
+{
+ if (m_boundingRect.isValid ())
+ {
+ // store only needed part of doc pixmap
+ m_pixmap = kpTool::neededPixmap (m_pixmap, m_boundingRect);
+ }
+ else
+ {
+ m_pixmap.resize (0, 0);
+ }
+}
+
+// public
+void kpToolPenCommand::cancel ()
+{
+ if (m_boundingRect.isValid ())
+ {
+ viewManager ()->setFastUpdates ();
+ document ()->setPixmapAt (m_pixmap, m_boundingRect.topLeft ());
+ viewManager ()->restoreFastUpdates ();
+ }
+}
+
+#include <kptoolpen.moc>
diff --git a/kolourpaint/tools/kptoolpen.h b/kolourpaint/tools/kptoolpen.h
new file mode 100644
index 00000000..f57eb367
--- /dev/null
+++ b/kolourpaint/tools/kptoolpen.h
@@ -0,0 +1,160 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolpen_h__
+#define __kptoolpen_h__
+
+#include <qpixmap.h>
+#include <qrect.h>
+
+#include <kpcommandhistory.h>
+#include <kptool.h>
+
+class QPoint;
+class QString;
+
+class kpColor;
+class kpMainWindow;
+class kpToolPenCommand;
+class kpToolWidgetBrush;
+class kpToolWidgetEraserSize;
+class kpViewManager;
+
+class kpToolPen : public kpTool
+{
+Q_OBJECT
+
+public:
+ enum Mode
+ {
+ // tool properties
+ DrawsPixels = (1 << 0), DrawsPixmaps = (1 << 1), WashesPixmaps = (1 << 2),
+ NoBrushes = 0, SquareBrushes = (1 << 3), DiverseBrushes = (1 << 4),
+ NormalColors = 0, SwappedColors = (1 << 5),
+
+ // tools:
+ //
+ // Pen = draws pixels, "interpolates" by "sweeping" pixels along a line (no brushes)
+ // Brush = draws pixmaps, "interpolates" by "sweeping" pixmaps along a line (interesting brushes)
+ // Eraser = Brush but with foreground & background colors swapped (a few square brushes)
+ // Color Washer = Brush that replaces/washes the foreground color with the background color
+ //
+ // (note the capitalization of "brush" here :))
+ Pen = DrawsPixels | NoBrushes | NormalColors,
+ Brush = DrawsPixmaps | DiverseBrushes | NormalColors,
+ Eraser = DrawsPixmaps | SquareBrushes | SwappedColors,
+ ColorWasher = WashesPixmaps | SquareBrushes | SwappedColors
+ };
+
+ kpToolPen (Mode mode, const QString &text, const QString &description,
+ int key,
+ kpMainWindow *mainWindow, const char *name);
+ kpToolPen (kpMainWindow *mainWindow);
+ virtual ~kpToolPen ();
+
+ void setMode (Mode mode);
+
+private:
+ QString haventBegunDrawUserMessage () const;
+
+public:
+ virtual void begin ();
+ virtual void end ();
+
+ virtual void beginDraw ();
+ virtual void hover (const QPoint &point);
+ virtual void globalDraw ();
+ virtual void draw (const QPoint &thisPoint, const QPoint &lastPoint, const QRect &);
+ virtual void cancelShape ();
+ virtual void releasedAllButtons ();
+ virtual void endDraw (const QPoint &, const QRect &);
+
+private slots:
+ virtual void slotForegroundColorChanged (const kpColor &col);
+ virtual void slotBackgroundColorChanged (const kpColor &col);
+
+ void slotBrushChanged (const QPixmap &pixmap, bool isDiagonalLine);
+ void slotEraserSizeChanged (int size);
+
+private:
+ bool wash (QPainter *painter, QPainter *maskPainter,
+ const QImage &image,
+ const kpColor &colorToReplace,
+ const QRect &imageRect, int plotx, int ploty);
+ bool wash (QPainter *painter, QPainter *maskPainter,
+ const QImage &image,
+ const kpColor &colorToReplace,
+ const QRect &imageRect, const QRect &drawRect);
+
+ kpColor color (int which);
+
+ QPoint hotPoint () const;
+ QPoint hotPoint (int x, int y) const;
+ QPoint hotPoint (const QPoint &point) const;
+ QRect hotRect () const;
+ QRect hotRect (int x, int y) const;
+ QRect hotRect (const QPoint &point) const;
+
+ Mode m_mode;
+
+ void updateBrushCursor (bool recalc = true);
+
+ kpToolWidgetBrush *m_toolWidgetBrush;
+ kpToolWidgetEraserSize *m_toolWidgetEraserSize;
+ QPixmap m_brushPixmap [2];
+ QPixmap m_cursorPixmap;
+ bool m_brushIsDiagonalLine;
+
+ kpToolPenCommand *m_currentCommand;
+};
+
+class kpToolPenCommand : public kpNamedCommand
+{
+public:
+ kpToolPenCommand (const QString &name, kpMainWindow *mainWindow);
+ virtual ~kpToolPenCommand ();
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+ // interface for KToolPen
+ void updateBoundingRect (const QPoint &point);
+ void updateBoundingRect (const QRect &rect);
+ void finalize ();
+ void cancel ();
+
+private:
+ void swapOldAndNew ();
+
+ QPixmap m_pixmap;
+ QRect m_boundingRect;
+};
+
+#endif // __kptoolpen_h__
diff --git a/kolourpaint/tools/kptoolpolygon.cpp b/kolourpaint/tools/kptoolpolygon.cpp
new file mode 100644
index 00000000..fb68745c
--- /dev/null
+++ b/kolourpaint/tools/kptoolpolygon.cpp
@@ -0,0 +1,895 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_TOOL_POLYGON 0
+
+#include <kptoolpolygon.h>
+
+#include <float.h>
+#include <math.h>
+
+#include <qbitmap.h>
+#include <qcursor.h>
+#include <qlayout.h>
+#include <qpainter.h>
+#include <qpoint.h>
+#include <qpushbutton.h>
+#include <qrect.h>
+#include <qtooltip.h>
+#include <qvbuttongroup.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcommandhistory.h>
+#include <kpdocument.h>
+#include <kpdefs.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kptemppixmap.h>
+#include <kptooltoolbar.h>
+#include <kptoolwidgetlinewidth.h>
+#include <kpviewmanager.h>
+
+
+#if DEBUG_KP_TOOL_POLYGON
+static const char *pointArrayToString (const QPointArray &pointArray)
+{
+ static char string [1000];
+ string [0] = '\0';
+
+ for (QPointArray::ConstIterator it = pointArray.begin ();
+ it != pointArray.end ();
+ it++)
+ {
+ QString ps = QString (" (%1, %2)").arg ((*it).x ()).arg ((*it).y ());
+ const char *pss = ps.latin1 ();
+ if (strlen (string) + strlen (pss) + 1 > sizeof (string) / sizeof (string [0]))
+ break;
+ strcat (string, pss);
+ }
+
+ return string;
+}
+#endif
+
+
+static QPen makeMaskPen (const kpColor &color, int lineWidth, Qt::PenStyle lineStyle)
+{
+ return QPen (color.maskColor (),
+ lineWidth == 1 ? 0/*closer to looking width 1*/ : lineWidth, lineStyle,
+ Qt::RoundCap, Qt::RoundJoin);
+}
+
+static QPen makePen (const kpColor &color, int lineWidth, Qt::PenStyle lineStyle)
+{
+ if (color.isOpaque ())
+ {
+ return QPen (color.toQColor (),
+ lineWidth == 1 ? 0/*closer to looking width 1*/ : lineWidth, lineStyle,
+ Qt::RoundCap, Qt::RoundJoin);
+ }
+ else
+ return Qt::NoPen;
+}
+
+static QBrush makeMaskBrush (const kpColor &foregroundColor,
+ const kpColor &backgroundColor,
+ kpToolWidgetFillStyle *toolWidgetFillStyle)
+{
+ if (toolWidgetFillStyle)
+ return toolWidgetFillStyle->maskBrush (foregroundColor, backgroundColor);
+ else
+ return Qt::NoBrush;
+}
+
+static QBrush makeBrush (const kpColor &foregroundColor,
+ const kpColor &backgroundColor,
+ kpToolWidgetFillStyle *toolWidgetFillStyle)
+{
+ if (toolWidgetFillStyle)
+ return toolWidgetFillStyle->brush (foregroundColor, backgroundColor);
+ else
+ return Qt::NoBrush;
+}
+
+static bool only1PixelInPointArray (const QPointArray &points)
+{
+ if (points.count () == 0)
+ return false;
+
+ for (int i = 1; i < (int) points.count (); i++)
+ {
+ if (points [i] != points [0])
+ return false;
+ }
+
+ return true;
+}
+
+static QPixmap pixmap (const QPixmap &oldPixmap,
+ const QPointArray &points, const QRect &rect,
+ const kpColor &foregroundColor, kpColor backgroundColor,
+ int lineWidth, Qt::PenStyle lineStyle,
+ kpToolWidgetFillStyle *toolWidgetFillStyle,
+ enum kpToolPolygon::Mode mode, bool final = true)
+{
+ //
+ // figure out points to draw relative to topLeft of oldPixmap
+
+ QPointArray pointsInRect = points;
+ pointsInRect.detach ();
+ pointsInRect.translate (-rect.x (), -rect.y ());
+
+#if DEBUG_KP_TOOL_POLYGON && 0
+ kdDebug () << "kptoolpolygon.cpp: pixmap(): points=" << pointArrayToString (points) << endl;
+#endif
+
+
+ //
+ // draw
+
+ QPen pen = makePen (foregroundColor, lineWidth, lineStyle),
+ maskPen = makeMaskPen (foregroundColor, lineWidth, lineStyle);
+ QBrush brush = makeBrush (foregroundColor, backgroundColor, toolWidgetFillStyle),
+ maskBrush = makeMaskBrush (foregroundColor, backgroundColor, toolWidgetFillStyle);
+
+ QPixmap pixmap = oldPixmap;
+ QBitmap maskBitmap;
+
+ QPainter painter, maskPainter;
+
+ if (pixmap.mask () ||
+ (maskPen.style () != Qt::NoPen &&
+ maskPen.color () == Qt::color0/*transparent*/) ||
+ (maskBrush.style () != Qt::NoBrush &&
+ maskBrush.color () == Qt::color0/*transparent*/))
+ {
+ maskBitmap = kpPixmapFX::getNonNullMask (pixmap);
+ maskPainter.begin (&maskBitmap);
+ maskPainter.setPen (maskPen);
+ maskPainter.setBrush (maskBrush);
+
+ #if DEBUG_KP_TOOL_POLYGON && 0
+ kdDebug () << "\tmaskPainter begin because:" << endl
+ << "\t\tpixmap.mask=" << pixmap.mask () << endl
+ << "\t\t(maskPenStyle!=NoPen)=" << (maskPen.style () != Qt::NoPen) << endl
+ << "\t\t(maskPenColor==trans)=" << (maskPen.color () == Qt::color0) << endl
+ << "\t\t(maskBrushStyle!=NoBrush)=" << (maskBrush.style () != Qt::NoBrush) << endl
+ << "\t\t(maskBrushColor==trans)=" << (maskBrush.color () == Qt::color0) << endl;
+ #endif
+ }
+
+ if (pen.style () != Qt::NoPen ||
+ brush.style () != Qt::NoBrush)
+ {
+ painter.begin (&pixmap);
+ painter.setPen (pen);
+ painter.setBrush (brush);
+
+ #if DEBUG_KP_TOOL_POLYGON && 0
+ kdDebug () << "\tpainter begin pen.rgb="
+ << (int *) painter.pen ().color ().rgb ()
+ << endl;
+ #endif
+ }
+
+#define PAINTER_CALL(cmd) \
+{ \
+ if (painter.isActive ()) \
+ painter . cmd ; \
+ \
+ if (maskPainter.isActive ()) \
+ maskPainter . cmd ; \
+}
+
+ // SYNC: Qt bug
+ if (only1PixelInPointArray (pointsInRect))
+ {
+ PAINTER_CALL (drawPoint (pointsInRect [0]));
+ }
+ else
+ {
+ switch (mode)
+ {
+ case kpToolPolygon::Line:
+ case kpToolPolygon::Polyline:
+ PAINTER_CALL (drawPolyline (pointsInRect));
+ break;
+ case kpToolPolygon::Polygon:
+ // TODO: why aren't the ends rounded?
+ PAINTER_CALL (drawPolygon (pointsInRect));
+
+ if (!final && 0/*HACK for TODO*/)
+ {
+ int count = pointsInRect.count ();
+
+ if (count > 2)
+ {
+ if (painter.isActive ())
+ {
+ QPen XORpen = painter.pen ();
+ XORpen.setColor (Qt::white);
+
+ painter.setPen (XORpen);
+ painter.setRasterOp (Qt::XorROP);
+ }
+
+ if (maskPainter.isActive ())
+ {
+ QPen XORpen = maskPainter.pen ();
+
+ // TODO???
+ #if 0
+ if (kpTool::isColorTransparent (foregroundColor))
+ XORpen.setColor (Qt::color1/*opaque*/);
+ else
+ XORpen.setColor (Qt::color0/*transparent*/);
+ #endif
+
+ maskPainter.setPen (XORpen);
+ }
+
+ PAINTER_CALL (drawLine (pointsInRect [0], pointsInRect [count - 1]));
+ }
+ }
+ break;
+ case kpToolPolygon::Curve:
+ int numPoints = pointsInRect.count ();
+ QPointArray pa (4);
+
+ pa [0] = pointsInRect [0];
+ pa [3] = pointsInRect [1];
+
+ switch (numPoints)
+ {
+ case 2:
+ pa [1] = pointsInRect [0];
+ pa [2] = pointsInRect [1];
+ break;
+ case 3:
+ pa [1] = pa [2] = pointsInRect [2];
+ break;
+ case 4:
+ pa [1] = pointsInRect [2];
+ pa [2] = pointsInRect [3];
+ }
+
+ PAINTER_CALL (drawCubicBezier (pa));
+ }
+ }
+#undef PAINTER_CALL
+
+ if (painter.isActive ())
+ painter.end ();
+
+ if (maskPainter.isActive ())
+ maskPainter.end ();
+
+ if (!maskBitmap.isNull ())
+ pixmap.setMask (maskBitmap);
+
+ return pixmap;
+}
+
+
+/*
+ * kpToolPolygon
+ */
+
+kpToolPolygon::kpToolPolygon (Mode mode,
+ const QString &text, const QString &description,
+ int key,
+ kpMainWindow *mainWindow, const char *name)
+ : kpTool (text, description, key, mainWindow, name),
+ m_mode (mode),
+ m_toolWidgetFillStyle (0),
+ m_toolWidgetLineWidth (0)
+{
+}
+
+kpToolPolygon::kpToolPolygon (kpMainWindow *mainWindow)
+ : kpTool (i18n ("Polygon"), i18n ("Draws polygons"),
+ Qt::Key_G,
+ mainWindow, "tool_polygon"),
+ m_mode (Polygon),
+ m_toolWidgetFillStyle (0),
+ m_toolWidgetLineWidth (0)
+{
+}
+
+kpToolPolygon::~kpToolPolygon ()
+{
+}
+
+void kpToolPolygon::setMode (Mode m)
+{
+ m_mode = m;
+}
+
+
+// private
+QString kpToolPolygon::haventBegunShapeUserMessage () const
+{
+ switch (m_mode)
+ {
+ case Line:
+ return i18n ("Drag to draw.");
+ case Polygon:
+ case Polyline:
+ return i18n ("Drag to draw the first line.");
+ case Curve:
+ return i18n ("Drag out the start and end points.");
+ default:
+ return QString::null;
+ }
+}
+
+// virtual
+void kpToolPolygon::begin ()
+{
+ kpToolToolBar *tb = toolToolBar ();
+
+#if DEBUG_KP_TOOL_POLYGON
+ kdDebug () << "kpToolPolygon::begin() tb=" << tb << endl;
+#endif
+
+ if (tb)
+ {
+ if (m_mode == Polygon)
+ m_toolWidgetFillStyle = tb->toolWidgetFillStyle ();
+ else
+ m_toolWidgetFillStyle = 0;
+
+ m_toolWidgetLineWidth = tb->toolWidgetLineWidth ();
+
+ if (m_toolWidgetFillStyle)
+ {
+ connect (m_toolWidgetFillStyle, SIGNAL (fillStyleChanged (kpToolWidgetFillStyle::FillStyle)),
+ this, SLOT (slotFillStyleChanged (kpToolWidgetFillStyle::FillStyle)));
+ }
+ connect (m_toolWidgetLineWidth, SIGNAL (lineWidthChanged (int)),
+ this, SLOT (slotLineWidthChanged (int)));
+
+ if (m_toolWidgetFillStyle)
+ m_toolWidgetFillStyle->show ();
+ m_toolWidgetLineWidth->show ();
+
+ m_lineWidth = m_toolWidgetLineWidth->lineWidth ();
+ }
+ else
+ {
+ m_toolWidgetFillStyle = 0;
+ m_toolWidgetLineWidth = 0;
+
+ m_lineWidth = 1;
+ }
+
+ viewManager ()->setCursor (QCursor (CrossCursor));
+
+ m_originatingMouseButton = -1;
+
+ setUserMessage (haventBegunShapeUserMessage ());
+}
+
+// virtual
+void kpToolPolygon::end ()
+{
+ endShape ();
+
+ if (m_toolWidgetFillStyle)
+ {
+ disconnect (m_toolWidgetFillStyle, SIGNAL (fillStyleChanged (kpToolWidgetFillStyle::FillStyle)),
+ this, SLOT (slotFillStyleChanged (kpToolWidgetFillStyle::FillStyle)));
+ m_toolWidgetFillStyle = 0;
+ }
+
+ if (m_toolWidgetLineWidth)
+ {
+ disconnect (m_toolWidgetLineWidth, SIGNAL (lineWidthChanged (int)),
+ this, SLOT (slotLineWidthChanged (int)));
+ m_toolWidgetLineWidth = 0;
+ }
+
+ viewManager ()->unsetCursor ();
+}
+
+
+void kpToolPolygon::beginDraw ()
+{
+#if DEBUG_KP_TOOL_POLYGON
+ kdDebug () << "kpToolPolygon::beginDraw() m_points=" << pointArrayToString (m_points)
+ << ", startPoint=" << m_startPoint << endl;
+#endif
+
+ bool endedShape = false;
+
+ // starting with a line...
+ if (m_points.count () == 0)
+ {
+ m_originatingMouseButton = m_mouseButton;
+ m_points.putPoints (m_points.count (), 2,
+ m_startPoint.x (), m_startPoint.y (),
+ m_startPoint.x (), m_startPoint.y ());
+ }
+ // continuing poly*
+ else
+ {
+ if (m_mouseButton != m_originatingMouseButton)
+ {
+ m_mouseButton = m_originatingMouseButton;
+ endShape ();
+ endedShape = true;
+ }
+ else
+ {
+ int count = m_points.count ();
+ m_points.putPoints (count, 1,
+ m_startPoint.x (), m_startPoint.y ());
+
+ // start point = last end point;
+ // _not_ the new/current start point
+ // (which is disregarded in a poly* as only the end points count
+ // after the initial line)
+ //
+ // Curve Tool ignores m_startPoint (doesn't call applyModifiers())
+ // after the initial has been defined.
+ m_startPoint = m_points [count - 1];
+ }
+ }
+
+#if DEBUG_KP_TOOL_POLYGON
+ kdDebug () << "\tafterwards, m_points=" << pointArrayToString (m_points) << endl;
+#endif
+
+ if (!endedShape)
+ {
+ switch (m_mode)
+ {
+ case Line:
+ case Curve:
+ case Polygon:
+ case Polyline:
+ setUserMessage (cancelUserMessage ());
+ break;
+
+ default:
+ kdError () << "kpToolPolygon::beginDraw() shape" << endl;
+ break;
+ }
+ }
+}
+
+// private
+void kpToolPolygon::applyModifiers ()
+{
+ int count = m_points.count ();
+
+ m_toolLineStartPoint = m_startPoint; /* also correct for poly* tool (see beginDraw()) */
+ m_toolLineEndPoint = m_currentPoint;
+
+#if DEBUG_KP_TOOL_POLYGON && 1
+ kdDebug () << "kpToolPolygon::applyModifiers() #pts=" << count
+ << " line: startPt=" << m_toolLineStartPoint
+ << " endPt=" << m_toolLineEndPoint
+ << " modifiers: shift=" << m_shiftPressed
+ << " alt=" << m_altPressed
+ << " ctrl=" << m_controlPressed
+ << endl;
+#endif
+
+ // angles
+ if (m_shiftPressed || m_controlPressed)
+ {
+ int diffx = m_toolLineEndPoint.x () - m_toolLineStartPoint.x ();
+ int diffy = m_toolLineEndPoint.y () - m_toolLineStartPoint.y ();
+
+ double ratio;
+ if (diffx == 0)
+ ratio = DBL_MAX;
+ else
+ ratio = fabs (double (diffy) / double (diffx));
+ #if DEBUG_KP_TOOL_POLYGON && 1
+ kdDebug () << "\tdiffx=" << diffx << " diffy=" << diffy
+ << " ratio=" << ratio
+ << endl;
+ #endif
+
+ // Shift = 0, 45, 90
+ // Alt = 0, 30, 60, 90
+ // Shift + Alt = 0, 30, 45, 60, 90
+ double angles [10]; // "ought to be enough for anybody"
+ int numAngles = 0;
+ angles [numAngles++] = 0;
+ if (m_controlPressed)
+ angles [numAngles++] = KP_PI / 6;
+ if (m_shiftPressed)
+ angles [numAngles++] = KP_PI / 4;
+ if (m_controlPressed)
+ angles [numAngles++] = KP_PI / 3;
+ angles [numAngles++] = KP_PI / 2;
+
+ double angle = angles [numAngles - 1];
+ for (int i = 0; i < numAngles - 1; i++)
+ {
+ double acceptingRatio = tan ((angles [i] + angles [i + 1]) / 2.0);
+ if (ratio < acceptingRatio)
+ {
+ angle = angles [i];
+ break;
+ }
+ }
+
+ // horizontal (dist from start !maintained)
+ if (fabs (KP_RADIANS_TO_DEGREES (angle) - 0)
+ < kpPixmapFX::AngleInDegreesEpsilon)
+ {
+ m_toolLineEndPoint = QPoint (m_toolLineEndPoint.x (), m_toolLineStartPoint.y ());
+ }
+ // vertical (dist from start !maintained)
+ else if (fabs (KP_RADIANS_TO_DEGREES (angle) - 90)
+ < kpPixmapFX::AngleInDegreesEpsilon)
+ {
+ m_toolLineEndPoint = QPoint (m_toolLineStartPoint.x (), m_toolLineEndPoint.y ());
+ }
+ // diagonal (dist from start maintained)
+ else
+ {
+ const double dist = sqrt (diffx * diffx + diffy * diffy);
+
+ #define sgn(a) ((a)<0?-1:1)
+ // Round distances _before_ adding to any coordinate
+ // (ensures consistent rounding behaviour in x & y directions)
+ const int newdx = qRound (dist * cos (angle) * sgn (diffx));
+ const int newdy = qRound (dist * sin (angle) * sgn (diffy));
+ #undef sgn
+
+ m_toolLineEndPoint = QPoint (m_toolLineStartPoint.x () + newdx,
+ m_toolLineStartPoint.y () + newdy);
+
+ #if DEBUG_KP_TOOL_POLYGON && 1
+ kdDebug () << "\t\tdiagonal line: dist=" << dist
+ << " angle=" << (angle * 180 / KP_PI)
+ << " endPoint=" << m_toolLineEndPoint
+ << endl;
+ #endif
+ }
+ } // if (m_shiftPressed || m_controlPressed) {
+
+ // centring
+ if (m_altPressed && 0/*ALT is unreliable*/)
+ {
+ // start = start - diff
+ // = start - (end - start)
+ // = start - end + start
+ // = 2 * start - end
+ if (count == 2)
+ m_toolLineStartPoint += (m_toolLineStartPoint - m_toolLineEndPoint);
+ else
+ m_toolLineEndPoint += (m_toolLineEndPoint - m_toolLineStartPoint);
+ } // if (m_altPressed) {
+
+ m_points [count - 2] = m_toolLineStartPoint;
+ m_points [count - 1] = m_toolLineEndPoint;
+
+ m_toolLineRect = kpTool::neededRect (QRect (m_toolLineStartPoint, m_toolLineEndPoint).normalize (),
+ m_lineWidth);
+}
+
+// virtual
+void kpToolPolygon::draw (const QPoint &, const QPoint &, const QRect &)
+{
+ if (m_points.count () == 0)
+ return;
+
+#if DEBUG_KP_TOOL_POLYGON
+ kdDebug () << "kpToolPolygon::draw() m_points=" << pointArrayToString (m_points)
+ << ", endPoint=" << m_currentPoint << endl;
+#endif
+
+ bool drawingALine = (m_mode != Curve) ||
+ (m_mode == Curve && m_points.count () == 2);
+
+ if (drawingALine)
+ applyModifiers ();
+ else
+ m_points [m_points.count () - 1] = m_currentPoint;
+
+#if DEBUG_KP_TOOL_POLYGON
+ kdDebug () << "\tafterwards, m_points=" << pointArrayToString (m_points) << endl;
+#endif
+
+ updateShape ();
+
+ if (drawingALine)
+ setUserShapePoints (m_toolLineStartPoint, m_toolLineEndPoint);
+ else
+ setUserShapePoints (m_currentPoint);
+}
+
+// private slot
+void kpToolPolygon::updateShape ()
+{
+ if (m_points.count () == 0)
+ return;
+
+ QRect boundingRect = kpTool::neededRect (m_points.boundingRect (), m_lineWidth);
+
+#if DEBUG_KP_TOOL_POLYGON
+ kdDebug () << "kpToolPolygon::updateShape() boundingRect="
+ << boundingRect
+ << " lineWidth="
+ << m_lineWidth
+ << endl;
+#endif
+
+ QPixmap oldPixmap = document ()->getPixmapAt (boundingRect);
+ QPixmap newPixmap = pixmap (oldPixmap,
+ m_points, boundingRect,
+ color (m_mouseButton), color (1 - m_mouseButton),
+ m_lineWidth, Qt::SolidLine,
+ m_toolWidgetFillStyle,
+ m_mode, false/*not final*/);
+
+ viewManager ()->setFastUpdates ();
+ viewManager ()->setTempPixmap (kpTempPixmap (false/*always display*/,
+ kpTempPixmap::SetPixmap/*render mode*/,
+ boundingRect.topLeft (),
+ newPixmap));
+ viewManager ()->restoreFastUpdates ();
+}
+
+// virtual
+void kpToolPolygon::cancelShape ()
+{
+#if 0
+ endDraw (QPoint (), QRect ());
+ commandHistory ()->undo ();
+#else
+ viewManager ()->invalidateTempPixmap ();
+#endif
+ m_points.resize (0);
+
+ setUserMessage (i18n ("Let go of all the mouse buttons."));
+}
+
+void kpToolPolygon::releasedAllButtons ()
+{
+ if (!hasBegunShape ())
+ setUserMessage (haventBegunShapeUserMessage ());
+
+ // --- else case already handled by endDraw() ---
+}
+
+// virtual
+void kpToolPolygon::endDraw (const QPoint &, const QRect &)
+{
+#if DEBUG_KP_TOOL_POLYGON
+ kdDebug () << "kpToolPolygon::endDraw() m_points=" << pointArrayToString (m_points) << endl;
+#endif
+
+ if (m_points.count () == 0)
+ return;
+
+ if (m_mode == Line ||
+ (m_mode == Curve && m_points.count () >= 4) ||
+ m_points.count () >= 50)
+ {
+ endShape ();
+ }
+ else
+ {
+ switch (m_mode)
+ {
+ case Line:
+ kdError () << "kpToolPolygon::endDraw() - line not ended" << endl;
+ setUserMessage ();
+ break;
+
+ case Polygon:
+ case Polyline:
+ if (m_points.isEmpty ())
+ {
+ kdError () << "kpToolPolygon::endDraw() exception - poly without points" << endl;
+ setUserMessage ();
+ }
+ else
+ {
+ if (m_mouseButton == 0)
+ {
+ setUserMessage (i18n ("Left drag another line or right click to finish."));
+ }
+ else
+ {
+ setUserMessage (i18n ("Right drag another line or left click to finish."));
+ }
+ }
+
+ break;
+
+ case Curve:
+ if (m_points.size () == 2)
+ {
+ if (m_mouseButton == 0)
+ {
+ setUserMessage (i18n ("Left drag to set the first control point or right click to finish."));
+ }
+ else
+ {
+ setUserMessage (i18n ("Right drag to set the first control point or left click to finish."));
+ }
+ }
+ else if (m_points.size () == 3)
+ {
+ if (m_mouseButton == 0)
+ {
+ setUserMessage (i18n ("Left drag to set the last control point or right click to finish."));
+ }
+ else
+ {
+ setUserMessage (i18n ("Right drag to set the last control point or left click to finish."));
+ }
+ }
+ else
+ {
+ kdError () << "kpToolPolygon::endDraw() exception - points" << endl;
+ setUserMessage ();
+ }
+
+ break;
+
+ default:
+ kdError () << "kpToolPolygon::endDraw() - clueless" << endl;
+ setUserMessage ();
+ break;
+ }
+ }
+}
+
+// public virtual
+void kpToolPolygon::endShape (const QPoint &, const QRect &)
+{
+#if DEBUG_KP_TOOL_POLYGON
+ kdDebug () << "kpToolPolygon::endShape() m_points=" << pointArrayToString (m_points) << endl;
+#endif
+
+ if (!hasBegunShape ())
+ return;
+
+ viewManager ()->invalidateTempPixmap ();
+
+ QRect boundingRect = kpTool::neededRect (m_points.boundingRect (), m_lineWidth);
+
+ kpToolPolygonCommand *lineCommand =
+ new kpToolPolygonCommand
+ (text (),
+ m_points, boundingRect,
+ color (m_mouseButton), color (1 - m_mouseButton),
+ m_lineWidth, Qt::SolidLine,
+ m_toolWidgetFillStyle,
+ document ()->getPixmapAt (boundingRect),
+ m_mode,
+ mainWindow ());
+
+ commandHistory ()->addCommand (lineCommand);
+
+ m_points.resize (0);
+ setUserMessage (haventBegunShapeUserMessage ());
+
+}
+
+// public virtual
+bool kpToolPolygon::hasBegunShape () const
+{
+ return (m_points.count () > 0);
+}
+
+
+// public slot
+void kpToolPolygon::slotLineWidthChanged (int width)
+{
+ m_lineWidth = width;
+ updateShape ();
+}
+
+// public slot
+void kpToolPolygon::slotFillStyleChanged (kpToolWidgetFillStyle::FillStyle /*fillStyle*/)
+{
+ updateShape ();
+}
+
+// virtual protected slot
+void kpToolPolygon::slotForegroundColorChanged (const kpColor &)
+{
+ updateShape ();
+}
+
+// virtual protected slot
+void kpToolPolygon::slotBackgroundColorChanged (const kpColor &)
+{
+ updateShape ();
+}
+
+
+/*
+ * kpToolPolygonCommand
+ */
+
+kpToolPolygonCommand::kpToolPolygonCommand (const QString &name,
+ const QPointArray &points,
+ const QRect &normalizedRect,
+ const kpColor &foregroundColor, const kpColor &backgroundColor,
+ int lineWidth, Qt::PenStyle lineStyle,
+ kpToolWidgetFillStyle *toolWidgetFillStyle,
+ const QPixmap &originalArea,
+ enum kpToolPolygon::Mode mode,
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow),
+ m_points (points),
+ m_normalizedRect (normalizedRect),
+ m_foregroundColor (foregroundColor), m_backgroundColor (backgroundColor),
+ m_lineWidth (lineWidth), m_lineStyle (lineStyle),
+ m_toolWidgetFillStyle (toolWidgetFillStyle),
+ m_originalArea (originalArea),
+ m_mode (mode)
+{
+ m_points.detach ();
+}
+
+kpToolPolygonCommand::~kpToolPolygonCommand ()
+{
+}
+
+
+// public virtual [base kpCommand]
+int kpToolPolygonCommand::size () const
+{
+ return kpPixmapFX::pointArraySize (m_points) +
+ kpPixmapFX::pixmapSize (m_originalArea);
+}
+
+
+// public virtual [base kpCommand]
+void kpToolPolygonCommand::execute ()
+{
+ QPixmap p = pixmap (m_originalArea,
+ m_points, m_normalizedRect,
+ m_foregroundColor, m_backgroundColor,
+ m_lineWidth, m_lineStyle,
+ m_toolWidgetFillStyle,
+ m_mode);
+ document ()->setPixmapAt (p, m_normalizedRect.topLeft ());
+}
+
+// public virtual [base kpCommand]
+void kpToolPolygonCommand::unexecute ()
+{
+ document ()->setPixmapAt (m_originalArea, m_normalizedRect.topLeft ());
+}
+
+#include <kptoolpolygon.moc>
diff --git a/kolourpaint/tools/kptoolpolygon.h b/kolourpaint/tools/kptoolpolygon.h
new file mode 100644
index 00000000..456dc4c0
--- /dev/null
+++ b/kolourpaint/tools/kptoolpolygon.h
@@ -0,0 +1,157 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolpolygon_h__
+#define __kptoolpolygon_h__
+
+#include <qbrush.h>
+#include <qpen.h>
+#include <qobject.h>
+#include <qpixmap.h>
+#include <qpoint.h>
+#include <qpointarray.h>
+#include <qrect.h>
+
+#include <kpcommandhistory.h>
+
+#include <kpcolor.h>
+#include <kptool.h>
+#include <kptoolwidgetfillstyle.h>
+
+class QMouseEvent;
+class QPen;
+class QPoint;
+class QRect;
+class QString;
+
+class kpView;
+class kpDocument;
+class kpMainWindow;
+
+class kpToolWidgetFillStyle;
+class kpToolWidgetLineWidth;
+class kpViewManager;
+
+class kpToolPolygon : public kpTool
+{
+Q_OBJECT
+
+public:
+ enum Mode
+ {
+ Polygon, Polyline, Line, Curve
+ };
+
+ kpToolPolygon (Mode mode, const QString &text, const QString &description,
+ int key,
+ kpMainWindow *mainWindow, const char *name);
+ kpToolPolygon (kpMainWindow *mainWindow);
+ virtual ~kpToolPolygon ();
+
+ void setMode (Mode mode);
+
+ virtual bool careAboutModifierState () const { return true; }
+
+private:
+ QString haventBegunShapeUserMessage () const;
+
+public:
+ virtual void begin ();
+ virtual void end ();
+
+ virtual void beginDraw ();
+ virtual void draw (const QPoint &, const QPoint &, const QRect &);
+ virtual void cancelShape ();
+ virtual void releasedAllButtons ();
+ virtual void endDraw (const QPoint &, const QRect &);
+ virtual void endShape (const QPoint & = QPoint (), const QRect & = QRect ());
+
+ virtual bool hasBegunShape () const;
+
+public slots:
+ void slotLineWidthChanged (int width);
+ void slotFillStyleChanged (kpToolWidgetFillStyle::FillStyle fillStyle);
+
+protected slots:
+ virtual void slotForegroundColorChanged (const kpColor &);
+ virtual void slotBackgroundColorChanged (const kpColor &);
+
+private slots:
+ void updateShape ();
+
+private:
+ Mode m_mode;
+
+ kpToolWidgetFillStyle *m_toolWidgetFillStyle;
+
+ int m_lineWidth;
+ kpToolWidgetLineWidth *m_toolWidgetLineWidth;
+
+ int m_originatingMouseButton;
+
+ void applyModifiers ();
+
+ QPoint m_toolLineStartPoint, m_toolLineEndPoint;
+ QRect m_toolLineRect;
+
+ QPointArray m_points;
+};
+
+class kpToolPolygonCommand : public kpNamedCommand
+{
+public:
+ kpToolPolygonCommand (const QString &name,
+ const QPointArray &points,
+ const QRect &normalizedRect,
+ const kpColor &foregroundColor, const kpColor &backgroundColor,
+ int lineWidth, Qt::PenStyle lineStyle,
+ kpToolWidgetFillStyle *toolWidgetFillStyle,
+ const QPixmap &originalArea,
+ kpToolPolygon::Mode mode,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolPolygonCommand ();
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ QPointArray m_points;
+ QRect m_normalizedRect;
+
+ kpColor m_foregroundColor, m_backgroundColor;
+ int m_lineWidth;
+ Qt::PenStyle m_lineStyle;
+ kpToolWidgetFillStyle *m_toolWidgetFillStyle;
+
+ QPixmap m_originalArea;
+ kpToolPolygon::Mode m_mode;
+};
+
+#endif // __kptoolpolygon_h__
diff --git a/kolourpaint/tools/kptoolpolyline.cpp b/kolourpaint/tools/kptoolpolyline.cpp
new file mode 100644
index 00000000..6299b5b7
--- /dev/null
+++ b/kolourpaint/tools/kptoolpolyline.cpp
@@ -0,0 +1,47 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <kptoolpolyline.h>
+
+#include <klocale.h>
+
+
+kpToolPolyline::kpToolPolyline (kpMainWindow *mainWindow)
+ : kpToolPolygon (Polyline,
+ i18n ("Connected Lines"),
+ i18n ("Draws connected lines"),
+ Qt::Key_N,
+ mainWindow, "tool_polyline")
+{
+}
+
+kpToolPolyline::~kpToolPolyline ()
+{
+}
+
+#include <kptoolpolyline.moc>
diff --git a/kolourpaint/tools/kptoolpolyline.h b/kolourpaint/tools/kptoolpolyline.h
new file mode 100644
index 00000000..f76a3959
--- /dev/null
+++ b/kolourpaint/tools/kptoolpolyline.h
@@ -0,0 +1,46 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolpolyline_h__
+#define __kptoolpolyline_h__
+
+#include <kptoolpolygon.h>
+
+class kpMainWindow;
+
+class kpToolPolyline : public kpToolPolygon
+{
+Q_OBJECT
+
+public:
+ kpToolPolyline (kpMainWindow *);
+ virtual ~kpToolPolyline ();
+};
+
+#endif // __kptoolpolyline_h__
+
diff --git a/kolourpaint/tools/kptoolpreviewdialog.cpp b/kolourpaint/tools/kptoolpreviewdialog.cpp
new file mode 100644
index 00000000..23149232
--- /dev/null
+++ b/kolourpaint/tools/kptoolpreviewdialog.cpp
@@ -0,0 +1,431 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_TOOL_PREVIEW_DIALOG 0
+
+#include <kptoolpreviewdialog.h>
+
+#include <qapplication.h>
+#include <qlayout.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcolor.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kpresizesignallinglabel.h>
+#include <kpselection.h>
+
+
+kpToolPreviewDialog::kpToolPreviewDialog (Features features,
+ bool reserveTopRow,
+ const QString &caption,
+ const QString &afterActionText,
+ bool actOnSelection,
+ kpMainWindow *parent,
+ const char *name)
+ : KDialogBase (parent, name, true/*modal*/,
+ caption,
+ KDialogBase::Ok | KDialogBase::Cancel),
+ m_afterActionText (afterActionText),
+ m_actOnSelection (actOnSelection),
+ m_mainWindow (parent),
+ m_dimensionsGroupBox (0),
+ m_afterTransformDimensionsLabel (0),
+ m_previewGroupBox (0),
+ m_previewPixmapLabel (0),
+ m_gridLayout (0)
+{
+ QWidget *baseWidget = new QWidget (this);
+ setMainWidget (baseWidget);
+
+
+ if (document ())
+ {
+ m_oldWidth = document ()->width (actOnSelection);
+ m_oldHeight = document ()->height (actOnSelection);
+ }
+ else
+ {
+ m_oldWidth = m_oldHeight = 1;
+ }
+
+
+ if (features & Dimensions)
+ createDimensionsGroupBox ();
+
+ if (features & Preview)
+ createPreviewGroupBox ();
+
+
+ m_gridLayout = new QGridLayout (baseWidget, 4, 2,
+ 0/*margin*/, spacingHint ());
+ m_gridNumRows = reserveTopRow ? 1 : 0;
+ if (m_dimensionsGroupBox || m_previewGroupBox)
+ {
+ if (m_dimensionsGroupBox && m_previewGroupBox)
+ {
+ m_gridLayout->addWidget (m_dimensionsGroupBox, m_gridNumRows, 0);
+ m_gridLayout->addWidget (m_previewGroupBox, m_gridNumRows, 1);
+
+ m_gridLayout->setColStretch (1, 1);
+ }
+ else if (m_dimensionsGroupBox)
+ {
+ m_gridLayout->addMultiCellWidget (m_dimensionsGroupBox,
+ m_gridNumRows, m_gridNumRows, 0, 1);
+ }
+ else if (m_previewGroupBox)
+ {
+ m_gridLayout->addMultiCellWidget (m_previewGroupBox,
+ m_gridNumRows, m_gridNumRows, 0, 1);
+ }
+
+ m_gridLayout->setRowStretch (m_gridNumRows, 1);
+ m_gridNumRows++;;
+ }
+}
+
+kpToolPreviewDialog::~kpToolPreviewDialog ()
+{
+}
+
+
+// private
+void kpToolPreviewDialog::createDimensionsGroupBox ()
+{
+ m_dimensionsGroupBox = new QGroupBox (i18n ("Dimensions"), mainWidget ());
+
+ QLabel *originalLabel = new QLabel (i18n ("Original:"), m_dimensionsGroupBox);
+ QString originalDimensions;
+ if (document ())
+ {
+ originalDimensions = i18n ("%1 x %2")
+ .arg (m_oldWidth)
+ .arg (m_oldHeight);
+
+ // Stop the Dimensions Group Box from resizing so often
+ const QString minimumLengthString ("100000 x 100000");
+ const int padLength = minimumLengthString.length ();
+ for (int i = originalDimensions.length (); i < padLength; i++)
+ originalDimensions += " ";
+ }
+ QLabel *originalDimensionsLabel = new QLabel (originalDimensions, m_dimensionsGroupBox);
+
+ QLabel *afterTransformLabel = new QLabel (m_afterActionText, m_dimensionsGroupBox);
+ m_afterTransformDimensionsLabel = new QLabel (m_dimensionsGroupBox);
+
+
+ QGridLayout *dimensionsLayout = new QGridLayout (m_dimensionsGroupBox,
+ 2, 2,
+ marginHint () * 2, spacingHint ());
+
+ dimensionsLayout->addWidget (originalLabel, 0, 0, Qt::AlignBottom);
+ dimensionsLayout->addWidget (originalDimensionsLabel, 0, 1, Qt::AlignBottom);
+ dimensionsLayout->addWidget (afterTransformLabel, 1, 0, Qt::AlignTop);
+ dimensionsLayout->addWidget (m_afterTransformDimensionsLabel, 1, 1, Qt::AlignTop);
+}
+
+// private
+void kpToolPreviewDialog::createPreviewGroupBox ()
+{
+ m_previewGroupBox = new QGroupBox (i18n ("Preview"), mainWidget ());
+
+ m_previewPixmapLabel = new kpResizeSignallingLabel (m_previewGroupBox);
+ m_previewPixmapLabel->setMinimumSize (150, 110);
+ connect (m_previewPixmapLabel, SIGNAL (resized ()),
+ this, SLOT (updatePreview ()));
+
+ QPushButton *updatePushButton = new QPushButton (i18n ("&Update"),
+ m_previewGroupBox);
+ connect (updatePushButton, SIGNAL (clicked ()),
+ this, SLOT (slotUpdateWithWaitCursor ()));
+
+
+ QVBoxLayout *previewLayout = new QVBoxLayout (m_previewGroupBox,
+ marginHint () * 2,
+ QMAX (1, spacingHint () / 2));
+
+ previewLayout->addWidget (m_previewPixmapLabel, 1/*stretch*/);
+ previewLayout->addWidget (updatePushButton, 0/*stretch*/, Qt::AlignHCenter);
+}
+
+
+// protected
+kpDocument *kpToolPreviewDialog::document () const
+{
+ return m_mainWindow ? m_mainWindow->document () : 0;
+}
+
+
+// protected
+void kpToolPreviewDialog::addCustomWidgetToFront (QWidget *w)
+{
+ m_gridLayout->addMultiCellWidget (w, 0, 0, 0, 1);
+}
+
+// protected
+void kpToolPreviewDialog::addCustomWidget (QWidget *w)
+{
+ m_gridLayout->addMultiCellWidget (w, m_gridNumRows, m_gridNumRows, 0, 1);
+ m_gridNumRows++;
+}
+
+
+// private
+void kpToolPreviewDialog::updateDimensions ()
+{
+ if (!m_dimensionsGroupBox)
+ return;
+
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ QSize newDim = newDimensions ();
+#if DEBUG_KP_TOOL_PREVIEW_DIALOG
+ kdDebug () << "kpToolPreviewDialog::updateDimensions(): newDim=" << newDim << endl;
+#endif
+
+ QString newDimString = i18n ("%1 x %2")
+ .arg (newDim.width ())
+ .arg (newDim.height ());
+ m_afterTransformDimensionsLabel->setText (newDimString);
+}
+
+
+// public static
+double kpToolPreviewDialog::aspectScale (int newWidth, int newHeight,
+ int oldWidth, int oldHeight)
+{
+ double widthScale = double (newWidth) / double (oldWidth);
+ double heightScale = double (newHeight) / double (oldHeight);
+
+ // Keeps aspect ratio
+ return QMIN (widthScale, heightScale);
+}
+
+// public static
+int kpToolPreviewDialog::scaleDimension (int dimension, double scale, int min, int max)
+{
+ return QMAX (min,
+ QMIN (max,
+ qRound (dimension * scale)));
+}
+
+
+// private
+void kpToolPreviewDialog::updateShrukenDocumentPixmap ()
+{
+#if DEBUG_KP_TOOL_PREVIEW_DIALOG
+ kdDebug () << "kpToolPreviewDialog::updateShrukenDocumentPixmap()"
+ << " shrunkenDocPixmap.size="
+ << m_shrunkenDocumentPixmap.size ()
+ << " previewPixmapLabelSizeWhenUpdatedPixmap="
+ << m_previewPixmapLabelSizeWhenUpdatedPixmap
+ << " previewPixmapLabel.size="
+ << m_previewPixmapLabel->size ()
+ << endl;
+#endif
+
+ if (!m_previewGroupBox)
+ return;
+
+
+ kpDocument *doc = document ();
+ if (!doc || !doc->pixmap ())
+ {
+ kdError () << "kpToolPreviewDialog::updateShrunkenDocumentPixmap() doc="
+ << doc << endl;
+ return;
+ }
+
+ if (m_shrunkenDocumentPixmap.isNull () ||
+ m_previewPixmapLabel->size () != m_previewPixmapLabelSizeWhenUpdatedPixmap)
+ {
+ #if DEBUG_KP_TOOL_PREVIEW_DIALOG
+ kdDebug () << "\tupdating shrunkenDocPixmap" << endl;
+ #endif
+
+ // TODO: Why the need to keep aspect ratio here?
+ // Isn't scaling the skewed result maintaining aspect enough?
+ double keepsAspectScale = aspectScale (m_previewPixmapLabel->width (),
+ m_previewPixmapLabel->height (),
+ m_oldWidth,
+ m_oldHeight);
+
+ QPixmap pixmap;
+
+ if (m_actOnSelection)
+ {
+ kpSelection sel = *doc->selection ();
+ if (!sel.pixmap ())
+ sel.setPixmap (doc->getSelectedPixmap ());
+
+ pixmap = sel.transparentPixmap ();
+ }
+ else
+ {
+ pixmap = *doc->pixmap ();
+ }
+
+ m_shrunkenDocumentPixmap = kpPixmapFX::scale (
+ pixmap,
+ scaleDimension (m_oldWidth,
+ keepsAspectScale,
+ 1, m_previewPixmapLabel->width ()),
+ scaleDimension (m_oldHeight,
+ keepsAspectScale,
+ 1, m_previewPixmapLabel->height ()));
+ #if 0
+ m_shrunkenDocumentPixmap = kpPixmapFX::scale (
+ m_actOnSelection ? doc->getSelectedPixmap () : *doc->pixmap (),
+ m_previewPixmapLabel->width (),
+ m_previewPixmapLabel->height ());
+ #endif
+
+ m_previewPixmapLabelSizeWhenUpdatedPixmap = m_previewPixmapLabel->size ();
+ }
+}
+
+
+// private
+void kpToolPreviewDialog::updatePreview ()
+{
+#if DEBUG_KP_TOOL_PREVIEW_DIALOG
+ kdDebug () << "kpToolPreviewDialog::updatePreview()" << endl;
+#endif
+
+ if (!m_previewGroupBox)
+ return;
+
+
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ updateShrukenDocumentPixmap ();
+
+ if (!m_shrunkenDocumentPixmap.isNull ())
+ {
+ QSize newDim = newDimensions ();
+ double keepsAspectScale = aspectScale (m_previewPixmapLabel->width (),
+ m_previewPixmapLabel->height (),
+ newDim.width (),
+ newDim.height ());
+
+ int targetWidth = scaleDimension (newDim.width (),
+ keepsAspectScale,
+ 1, // min
+ m_previewPixmapLabel->width ()); // max
+ int targetHeight = scaleDimension (newDim.height (),
+ keepsAspectScale,
+ 1, // min
+ m_previewPixmapLabel->height ()); // max
+
+ // TODO: Some effects work directly on QImage; so could cache the
+ // QImage so that transformPixmap() is faster
+ QPixmap transformedShrunkenDocumentPixmap =
+ transformPixmap (m_shrunkenDocumentPixmap, targetWidth, targetHeight);
+
+ QPixmap previewPixmap (m_previewPixmapLabel->width (),
+ m_previewPixmapLabel->height ());
+ kpPixmapFX::fill (&previewPixmap, kpColor::transparent);
+ kpPixmapFX::setPixmapAt (&previewPixmap,
+ (previewPixmap.width () - transformedShrunkenDocumentPixmap.width ()) / 2,
+ (previewPixmap.height () - transformedShrunkenDocumentPixmap.height ()) / 2,
+ transformedShrunkenDocumentPixmap);
+
+#if DEBUG_KP_TOOL_PREVIEW_DIALOG
+ kdDebug () << "kpToolPreviewDialog::updatePreview ():"
+ << " shrunkenDocumentPixmap: w="
+ << m_shrunkenDocumentPixmap.width ()
+ << " h="
+ << m_shrunkenDocumentPixmap.height ()
+ << " previewPixmapLabel: w="
+ << m_previewPixmapLabel->width ()
+ << " h="
+ << m_previewPixmapLabel->height ()
+ << " transformedShrunkenDocumentPixmap: w="
+ << transformedShrunkenDocumentPixmap.width ()
+ << " h="
+ << transformedShrunkenDocumentPixmap.height ()
+ << " previewPixmap: w="
+ << previewPixmap.width ()
+ << " h="
+ << previewPixmap.height ()
+ << endl;
+#endif
+
+ m_previewPixmapLabel->setPixmap (previewPixmap);
+
+ // immediate update esp. for expensive previews
+ m_previewPixmapLabel->repaint (false/*no erase*/);
+
+#if DEBUG_KP_TOOL_PREVIEW_DIALOG
+ kdDebug () << "\tafter QLabel::setPixmap() previewPixmapLabel: w="
+ << m_previewPixmapLabel->width ()
+ << " h="
+ << m_previewPixmapLabel->height ()
+ << endl;
+#endif
+ }
+}
+
+
+// protected slot virtual
+void kpToolPreviewDialog::slotUpdate ()
+{
+#if DEBUG_KP_TOOL_PREVIEW_DIALOG
+ kdDebug () << "kpToolPreviewDialog::slotUpdate()" << endl;
+#endif
+ updateDimensions ();
+ updatePreview ();
+}
+
+// protected slot virtual
+void kpToolPreviewDialog::slotUpdateWithWaitCursor ()
+{
+#if DEBUG_KP_TOOL_PREVIEW_DIALOG
+ kdDebug () << "kpToolPreviewDialog::slotUpdateWithWaitCursor()"
+ << endl;
+#endif
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ slotUpdate ();
+
+ QApplication::restoreOverrideCursor ();
+}
+
+
+#include <kptoolpreviewdialog.moc>
diff --git a/kolourpaint/tools/kptoolpreviewdialog.h b/kolourpaint/tools/kptoolpreviewdialog.h
new file mode 100644
index 00000000..35efdc38
--- /dev/null
+++ b/kolourpaint/tools/kptoolpreviewdialog.h
@@ -0,0 +1,131 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __kp_tool_preview_dialog_h__
+#define __kp_tool_preview_dialog_h__
+
+
+#include <qpixmap.h>
+
+#include <kdialogbase.h>
+
+
+class QLabel;
+class QGridLayout;
+class QGroupBox;
+
+class kpDocument;
+class kpMainWindow;
+class kpResizeSignallingLabel;
+
+
+class kpToolPreviewDialog : public KDialogBase
+{
+Q_OBJECT
+
+public:
+ enum Features
+ {
+ Dimensions = 1, Preview = 2,
+ AllFeatures = Dimensions | Preview
+ };
+
+ // You must call slotUpdate() in your constructor
+ kpToolPreviewDialog (Features features,
+ bool reserveTopRow,
+ // e.g. "Skew (Image|Selection)"
+ const QString &caption,
+ // (in the Dimensions Group Box) e.g. "After Skew:"
+ const QString &afterActionText,
+ bool actOnSelection,
+ kpMainWindow *parent,
+ const char *name = 0);
+ virtual ~kpToolPreviewDialog ();
+
+private:
+ void createDimensionsGroupBox ();
+ void createPreviewGroupBox ();
+
+public:
+ virtual bool isNoOp () const = 0;
+
+protected:
+ kpDocument *document () const;
+
+ // All widgets must have mainWidget() as their parent
+ void addCustomWidgetToFront (QWidget *w); // see <reserveTopRow> in ctor
+ void addCustomWidget (QWidget *w);
+ void addCustomWidgetToBack (QWidget *w)
+ {
+ addCustomWidget (w);
+ }
+
+ virtual QSize newDimensions () const = 0;
+ virtual QPixmap transformPixmap (const QPixmap &pixmap,
+ int targetWidth, int targetHeight) const = 0;
+
+private:
+ void updateDimensions ();
+
+public:
+ static double aspectScale (int newWidth, int newHeight,
+ int oldWidth, int oldHeight);
+ static int scaleDimension (int dimension, double scale, int min, int max);
+
+private:
+ void updateShrukenDocumentPixmap ();
+
+protected slots:
+ void updatePreview ();
+
+ // Call this whenever a value (e.g. an angle) changes
+ // and the Dimensions & Preview need to be updated
+ virtual void slotUpdate ();
+
+ virtual void slotUpdateWithWaitCursor ();
+
+protected:
+ QString m_afterActionText;
+ bool m_actOnSelection;
+ kpMainWindow *m_mainWindow;
+
+ int m_oldWidth, m_oldHeight;
+
+ QGroupBox *m_dimensionsGroupBox;
+ QLabel *m_afterTransformDimensionsLabel;
+
+ QGroupBox *m_previewGroupBox;
+ kpResizeSignallingLabel *m_previewPixmapLabel;
+ QSize m_previewPixmapLabelSizeWhenUpdatedPixmap;
+ QPixmap m_shrunkenDocumentPixmap;
+
+ QGridLayout *m_gridLayout;
+ int m_gridNumRows;
+};
+
+
+#endif // __kp_tool_preview_dialog_h__
diff --git a/kolourpaint/tools/kptoolrectangle.cpp b/kolourpaint/tools/kptoolrectangle.cpp
new file mode 100644
index 00000000..275db667
--- /dev/null
+++ b/kolourpaint/tools/kptoolrectangle.cpp
@@ -0,0 +1,638 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_TOOL_RECTANGLE 0
+
+#include <qbitmap.h>
+#include <qcursor.h>
+#include <qevent.h>
+#include <qpainter.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcolor.h>
+#include <kpcommandhistory.h>
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kptemppixmap.h>
+#include <kptoolrectangle.h>
+#include <kptooltoolbar.h>
+#include <kptoolwidgetfillstyle.h>
+#include <kptoolwidgetlinewidth.h>
+#include <kpview.h>
+#include <kpviewmanager.h>
+
+static QPixmap pixmap (const kpToolRectangle::Mode mode,
+ kpDocument *document, const QRect &rect,
+ const QPoint &startPoint, const QPoint &endPoint,
+ const QPen &pen, const QPen &maskPen,
+ const QBrush &brush, const QBrush &maskBrush)
+{
+ QPixmap pixmap = document->getPixmapAt (rect);
+ QBitmap maskBitmap;
+
+ QPainter painter, maskPainter;
+
+#if DEBUG_KP_TOOL_RECTANGLE && 1
+ kdDebug () << "pixmap: rect=" << rect
+ << " startPoint=" << startPoint
+ << " endPoint=" << endPoint
+ << endl;
+ kdDebug () << "\tm: p=" << (maskPen.style () != Qt::NoPen)
+ << " b=" << (maskBrush.style () != Qt::NoBrush)
+ << " o: p=" << (pen.style () != Qt::NoPen)
+ << " b=" << (brush.style () != Qt::NoBrush)
+ << endl;
+ kdDebug () << "\tmaskPen.color()=" << (int *) maskPen.color ().rgb ()
+ << " transparent=" << (int *) Qt::color0.rgb ()/*transparent*/
+ << endl;
+#endif
+
+ if (pixmap.mask () ||
+ (maskPen.style () != Qt::NoPen &&
+ maskPen.color () == Qt::color0/*transparent*/) ||
+ (maskBrush.style () != Qt::NoBrush &&
+ maskBrush.color () == Qt::color0/*transparent*/))
+ {
+ maskBitmap = kpPixmapFX::getNonNullMask (pixmap);
+ maskPainter.begin (&maskBitmap);
+ maskPainter.setPen (maskPen);
+ maskPainter.setBrush (maskBrush);
+ }
+
+ if (pen.style () != Qt::NoPen ||
+ brush.style () != Qt::NoBrush)
+ {
+ painter.begin (&pixmap);
+ painter.setPen (pen);
+ painter.setBrush (brush);
+ }
+
+#define PAINTER_CALL(cmd) \
+{ \
+ if (painter.isActive ()) \
+ painter . cmd ; \
+ \
+ if (maskPainter.isActive ()) \
+ maskPainter . cmd ; \
+}
+
+ if (startPoint != endPoint)
+ {
+ #if DEBUG_KP_TOOL_RECTANGLE && 1
+ kdDebug () << "\tdraw shape" << endl;
+ #endif
+
+ // TODO: Rectangle of pen width 1, height 1 and width X is rendered
+ // as width X - 1.
+ switch (mode)
+ {
+ case kpToolRectangle::Rectangle:
+ PAINTER_CALL (drawRect (QRect (startPoint - rect.topLeft (), endPoint - rect.topLeft ())));
+ break;
+ case kpToolRectangle::RoundedRectangle:
+ PAINTER_CALL (drawRoundRect (QRect (startPoint - rect.topLeft (), endPoint - rect.topLeft ())));
+ break;
+ case kpToolRectangle::Ellipse:
+ PAINTER_CALL (drawEllipse (QRect (startPoint - rect.topLeft (), endPoint - rect.topLeft ())));
+ break;
+ default:
+ kdError () << "kptoolrectangle.cpp::pixmap() passed unknown mode: " << int (mode) << endl;
+ break;
+ }
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_RECTANGLE && 1
+ kdDebug () << "\tstartPoint == endPoint" << endl;
+ #endif
+ // SYNC: Work around Qt bug: can't draw 1x1 rectangle
+ // Not strictly correct for border width > 1
+ // but better than not drawing at all
+ PAINTER_CALL (drawPoint (startPoint - rect.topLeft ()));
+ }
+#undef PAINTER_CALL
+
+ if (painter.isActive ())
+ painter.end ();
+
+ if (maskPainter.isActive ())
+ maskPainter.end ();
+
+ if (!maskBitmap.isNull ())
+ pixmap.setMask (maskBitmap);
+
+ return pixmap;
+}
+
+
+/*
+ * kpToolRectangle
+ */
+
+kpToolRectangle::kpToolRectangle (Mode mode,
+ const QString &text,
+ const QString &description,
+ int key,
+ kpMainWindow *mainWindow,
+ const char *name)
+ : kpTool (text, description, key, mainWindow, name),
+ m_mode (mode),
+ m_toolWidgetLineWidth (0),
+ m_toolWidgetFillStyle (0)
+{
+}
+
+kpToolRectangle::kpToolRectangle (kpMainWindow *mainWindow)
+ : kpTool (i18n ("Rectangle"), i18n ("Draws rectangles and squares"),
+ Qt::Key_R,
+ mainWindow, "tool_rectangle"),
+ m_mode (Rectangle),
+ m_toolWidgetLineWidth (0),
+ m_toolWidgetFillStyle (0)
+{
+}
+
+kpToolRectangle::~kpToolRectangle ()
+{
+}
+
+void kpToolRectangle::setMode (Mode mode)
+{
+ m_mode = mode;
+}
+
+
+// private
+void kpToolRectangle::updatePens ()
+{
+ for (int i = 0; i < 2; i++)
+ updatePen (i);
+}
+
+// private
+void kpToolRectangle::updateBrushes ()
+{
+ for (int i = 0; i < 2; i++)
+ updateBrush (i);
+}
+
+// virtual private slot
+void kpToolRectangle::slotForegroundColorChanged (const kpColor &)
+{
+#if DEBUG_KP_TOOL_RECTANGLE
+ kdDebug () << "kpToolRectangle::slotForegroundColorChanged()" << endl;
+#endif
+ updatePen (0);
+ updateBrush (0); // brush may be in foreground color
+ updateBrush (1);
+}
+
+// virtual private slot
+void kpToolRectangle::slotBackgroundColorChanged (const kpColor &)
+{
+#if DEBUG_KP_TOOL_RECTANGLE
+ kdDebug () << "kpToolRectangle::slotBackgroundColorChanged()" << endl;
+ kdDebug () << "\tm_toolWidgetFillStyle=" << m_toolWidgetFillStyle << endl;
+#endif
+ updatePen (1);
+ updateBrush (0);
+ updateBrush (1); // brush may be in background color
+}
+
+// private
+void kpToolRectangle::updatePen (int mouseButton)
+{
+ QColor maskPenColor = color (mouseButton).maskColor ();
+
+ if (!m_toolWidgetLineWidth)
+ {
+ if (color (mouseButton).isOpaque ())
+ m_pen [mouseButton] = QPen (color (mouseButton).toQColor ());
+ else
+ m_pen [mouseButton] = Qt::NoPen;
+ m_maskPen [mouseButton] = QPen (maskPenColor);
+ }
+ else
+ {
+ if (color (mouseButton).isOpaque ())
+ {
+ m_pen [mouseButton] = QPen (color (mouseButton).toQColor (),
+ m_toolWidgetLineWidth->lineWidth (),
+ Qt::SolidLine);
+ }
+ else
+ m_pen [mouseButton] = Qt::NoPen;
+ m_maskPen [mouseButton] = QPen (maskPenColor,
+ m_toolWidgetLineWidth->lineWidth (),
+ Qt::SolidLine);
+ }
+}
+
+void kpToolRectangle::updateBrush (int mouseButton)
+{
+#if DEBUG_KP_TOOL_RECTANGLE
+ kdDebug () << "kpToolRectangle::brush () mouseButton=" << mouseButton
+ << " m_toolWidgetFillStyle=" << m_toolWidgetFillStyle
+ << endl;
+#endif
+ if (m_toolWidgetFillStyle)
+ {
+ m_brush [mouseButton] = m_toolWidgetFillStyle->brush (
+ color (mouseButton)/*foreground colour*/,
+ color (1 - mouseButton)/*background colour*/);
+
+ m_maskBrush [mouseButton] = m_toolWidgetFillStyle->maskBrush (
+ color (mouseButton)/*foreground colour*/,
+ color (1 - mouseButton)/*background colour*/);
+ }
+ else
+ {
+ m_brush [mouseButton] = Qt::NoBrush;
+ m_maskBrush [mouseButton] = Qt::NoBrush;
+ }
+}
+
+
+// private slot virtual
+void kpToolRectangle::slotLineWidthChanged ()
+{
+ updatePens ();
+
+ if (hasBegunDraw ())
+ updateShape ();
+}
+
+// private slot virtual
+void kpToolRectangle::slotFillStyleChanged ()
+{
+ updateBrushes ();
+
+ if (hasBegunDraw ())
+ updateShape ();
+}
+
+
+// private
+QString kpToolRectangle::haventBegunDrawUserMessage () const
+{
+ return i18n ("Drag to draw.");
+}
+
+// virtual
+void kpToolRectangle::begin ()
+{
+#if DEBUG_KP_TOOL_RECTANGLE
+ kdDebug () << "kpToolRectangle::begin ()" << endl;
+#endif
+
+ kpToolToolBar *tb = toolToolBar ();
+
+#if DEBUG_KP_TOOL_RECTANGLE
+ kdDebug () << "\ttoolToolBar=" << tb << endl;
+#endif
+
+ if (tb)
+ {
+ m_toolWidgetLineWidth = tb->toolWidgetLineWidth ();
+ connect (m_toolWidgetLineWidth, SIGNAL (lineWidthChanged (int)),
+ this, SLOT (slotLineWidthChanged ()));
+ m_toolWidgetLineWidth->show ();
+
+ updatePens ();
+
+
+ m_toolWidgetFillStyle = tb->toolWidgetFillStyle ();
+ connect (m_toolWidgetFillStyle, SIGNAL (fillStyleChanged (kpToolWidgetFillStyle::FillStyle)),
+ this, SLOT (slotFillStyleChanged ()));
+ m_toolWidgetFillStyle->show ();
+
+ updateBrushes ();
+ }
+
+#if DEBUG_KP_TOOL_RECTANGLE
+ kdDebug () << "\t\tm_toolWidgetFillStyle=" << m_toolWidgetFillStyle << endl;
+#endif
+
+ viewManager ()->setCursor (QCursor (CrossCursor));
+
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+// virtual
+void kpToolRectangle::end ()
+{
+#if DEBUG_KP_TOOL_RECTANGLE
+ kdDebug () << "kpToolRectangle::end ()" << endl;
+#endif
+
+ if (m_toolWidgetLineWidth)
+ {
+ disconnect (m_toolWidgetLineWidth, SIGNAL (lineWidthChanged (int)),
+ this, SLOT (slotLineWidthChanged ()));
+ m_toolWidgetLineWidth = 0;
+ }
+
+ if (m_toolWidgetFillStyle)
+ {
+ disconnect (m_toolWidgetFillStyle, SIGNAL (fillStyleChanged (kpToolWidgetFillStyle::FillStyle)),
+ this, SLOT (slotFillStyleChanged ()));
+ m_toolWidgetFillStyle = 0;
+ }
+
+ viewManager ()->unsetCursor ();
+}
+
+void kpToolRectangle::applyModifiers ()
+{
+ QRect rect = QRect (m_startPoint, m_currentPoint).normalize ();
+
+#if DEBUG_KP_TOOL_RECTANGLE
+ kdDebug () << "kpToolRectangle::applyModifiers(" << rect
+ << ") shift=" << m_shiftPressed
+ << " ctrl=" << m_controlPressed
+ << endl;
+#endif
+
+ // user wants to m_startPoint == centre
+ if (m_controlPressed)
+ {
+ int xdiff = kAbs (m_startPoint.x () - m_currentPoint.x ());
+ int ydiff = kAbs (m_startPoint.y () - m_currentPoint.y ());
+ rect = QRect (m_startPoint.x () - xdiff, m_startPoint.y () - ydiff,
+ xdiff * 2 + 1, ydiff * 2 + 1);
+ }
+
+ // user wants major axis == minor axis:
+ // rectangle --> square
+ // rounded rectangle --> rounded square
+ // ellipse --> circle
+ if (m_shiftPressed)
+ {
+ if (!m_controlPressed)
+ {
+ if (rect.width () < rect.height ())
+ {
+ if (m_startPoint.y () == rect.y ())
+ rect.setHeight (rect.width ());
+ else
+ rect.setY (rect.bottom () - rect.width () + 1);
+ }
+ else
+ {
+ if (m_startPoint.x () == rect.x ())
+ rect.setWidth (rect.height ());
+ else
+ rect.setX (rect.right () - rect.height () + 1);
+ }
+ }
+ // have to maintain the centre
+ else
+ {
+ if (rect.width () < rect.height ())
+ {
+ QPoint center = rect.center ();
+ rect.setHeight (rect.width ());
+ rect.moveCenter (center);
+ }
+ else
+ {
+ QPoint center = rect.center ();
+ rect.setWidth (rect.height ());
+ rect.moveCenter (center);
+ }
+ }
+ }
+
+ m_toolRectangleStartPoint = rect.topLeft ();
+ m_toolRectangleEndPoint = rect.bottomRight ();
+
+ m_toolRectangleRectWithoutLineWidth = rect;
+ m_toolRectangleRect = kpTool::neededRect (rect, QMAX (m_pen [m_mouseButton].width (),
+ m_maskPen [m_mouseButton].width ()));
+}
+
+void kpToolRectangle::beginDraw ()
+{
+ setUserMessage (cancelUserMessage ());
+}
+
+void kpToolRectangle::updateShape ()
+{
+ viewManager ()->setFastUpdates ();
+
+ QPixmap newPixmap = pixmap (m_mode, document (), m_toolRectangleRect,
+ m_toolRectangleStartPoint, m_toolRectangleEndPoint,
+ m_pen [m_mouseButton], m_maskPen [m_mouseButton],
+ m_brush [m_mouseButton], m_maskBrush [m_mouseButton]);
+ kpTempPixmap newTempPixmap (false/*always display*/,
+ kpTempPixmap::SetPixmap/*render mode*/,
+ m_toolRectangleRect.topLeft (),
+ newPixmap);
+ viewManager ()->setTempPixmap (newTempPixmap);
+
+ viewManager ()->restoreFastUpdates ();
+}
+
+void kpToolRectangle::draw (const QPoint &, const QPoint &, const QRect &)
+{
+ applyModifiers ();
+
+
+ updateShape ();
+
+
+ // Recover the start and end points from the transformed & normalized m_toolRectangleRect
+
+ // S. or S or SC or S == C
+ // .C C
+ if (m_currentPoint.x () >= m_startPoint.x () &&
+ m_currentPoint.y () >= m_startPoint.y ())
+ {
+ setUserShapePoints (m_toolRectangleRectWithoutLineWidth.topLeft (),
+ m_toolRectangleRectWithoutLineWidth.bottomRight ());
+ }
+ // .C or C
+ // S. S
+ else if (m_currentPoint.x () >= m_startPoint.x () &&
+ m_currentPoint.y () < m_startPoint.y ())
+ {
+ setUserShapePoints (m_toolRectangleRectWithoutLineWidth.bottomLeft (),
+ m_toolRectangleRectWithoutLineWidth.topRight ());
+ }
+ // .S or CS
+ // C.
+ else if (m_currentPoint.x () < m_startPoint.x () &&
+ m_currentPoint.y () >= m_startPoint.y ())
+ {
+ setUserShapePoints (m_toolRectangleRectWithoutLineWidth.topRight (),
+ m_toolRectangleRectWithoutLineWidth.bottomLeft ());
+ }
+ // C.
+ // .S
+ else
+ {
+ setUserShapePoints (m_toolRectangleRectWithoutLineWidth.bottomRight (),
+ m_toolRectangleRectWithoutLineWidth.topLeft ());
+ }
+}
+
+void kpToolRectangle::cancelShape ()
+{
+#if 0
+ endDraw (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+ mainWindow ()->commandHistory ()->undo ();
+#else
+ viewManager ()->invalidateTempPixmap ();
+#endif
+
+ setUserMessage (i18n ("Let go of all the mouse buttons."));
+}
+
+void kpToolRectangle::releasedAllButtons ()
+{
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+void kpToolRectangle::endDraw (const QPoint &, const QRect &)
+{
+ applyModifiers ();
+
+ // TODO: flicker
+ viewManager ()->invalidateTempPixmap ();
+
+ mainWindow ()->commandHistory ()->addCommand (
+ new kpToolRectangleCommand
+ (m_mode,
+ m_pen [m_mouseButton], m_maskPen [m_mouseButton],
+ m_brush [m_mouseButton], m_maskBrush [m_mouseButton],
+ m_toolRectangleRect, m_toolRectangleStartPoint, m_toolRectangleEndPoint,
+ mainWindow ()));
+
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+
+/*
+ * kpToolRectangleCommand
+ */
+
+kpToolRectangleCommand::kpToolRectangleCommand (kpToolRectangle::Mode mode,
+ const QPen &pen, const QPen &maskPen,
+ const QBrush &brush, const QBrush &maskBrush,
+ const QRect &rect,
+ const QPoint &startPoint, const QPoint &endPoint,
+ kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ m_mode (mode),
+ m_pen (pen), m_maskPen (maskPen),
+ m_brush (brush), m_maskBrush (maskBrush),
+ m_rect (rect),
+ m_startPoint (startPoint),
+ m_endPoint (endPoint),
+ m_oldPixmapPtr (0)
+{
+}
+
+kpToolRectangleCommand::~kpToolRectangleCommand ()
+{
+ delete m_oldPixmapPtr;
+}
+
+
+// public virtual [base kpCommand]
+QString kpToolRectangleCommand::name () const
+{
+ switch (m_mode)
+ {
+ case kpToolRectangle::Rectangle:
+ return i18n ("Rectangle");
+ case kpToolRectangle::RoundedRectangle:
+ return i18n ("Rounded Rectangle");
+ case kpToolRectangle::Ellipse:
+ return i18n ("Ellipse");
+ default:
+ kdError () << "kpToolRectangleCommand::name() passed unknown mode: " << int (m_mode) << endl;
+ return QString::null;
+ }
+}
+
+
+// public virtual [base kpCommand]
+int kpToolRectangleCommand::size () const
+{
+ return kpPixmapFX::pixmapSize (m_oldPixmapPtr);
+}
+
+
+// public virtual [base kpCommand]
+void kpToolRectangleCommand::execute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ // store Undo info
+ if (!m_oldPixmapPtr)
+ {
+ // OPT: I can do better with no brush
+ m_oldPixmapPtr = new QPixmap ();
+ *m_oldPixmapPtr = doc->getPixmapAt (m_rect);
+ }
+ else
+ kdError () << "kpToolRectangleCommand::execute() m_oldPixmapPtr not null" << endl;
+
+ doc->setPixmapAt (pixmap (m_mode, doc,
+ m_rect, m_startPoint, m_endPoint,
+ m_pen, m_maskPen,
+ m_brush, m_maskBrush),
+ m_rect.topLeft ());
+}
+
+// public virtual [base kpCommand]
+void kpToolRectangleCommand::unexecute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ if (m_oldPixmapPtr)
+ {
+ doc->setPixmapAt (*m_oldPixmapPtr, m_rect.topLeft ());
+
+ delete m_oldPixmapPtr;
+ m_oldPixmapPtr = 0;
+ }
+ else
+ kdError () << "kpToolRectangleCommand::unexecute() m_oldPixmapPtr null" << endl;
+}
+
+#include <kptoolrectangle.moc>
diff --git a/kolourpaint/tools/kptoolrectangle.h b/kolourpaint/tools/kptoolrectangle.h
new file mode 100644
index 00000000..0fcf5ff4
--- /dev/null
+++ b/kolourpaint/tools/kptoolrectangle.h
@@ -0,0 +1,142 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolrectangle_h__
+#define __kptoolrectangle_h__
+
+#include <qbrush.h>
+#include <qpen.h>
+#include <qpixmap.h>
+#include <qpoint.h>
+#include <qrect.h>
+
+#include <kpcommandhistory.h>
+
+#include <kptool.h>
+
+class QString;
+
+class kpColor;
+class kpMainWindow;
+class kpToolWidgetFillStyle;
+class kpToolWidgetLineWidth;
+class kpViewManager;
+
+class kpToolRectangle : public kpTool
+{
+Q_OBJECT
+
+public:
+ // it turns out that these shapes are all really the same thing
+ // (same options, same feel) - the only real difference is the
+ // drawing functions (a one line change)
+ enum Mode {Rectangle, RoundedRectangle, Ellipse};
+
+ kpToolRectangle (Mode mode,
+ const QString &text, const QString &description,
+ int key,
+ kpMainWindow *mainWindow,
+ const char *name);
+ kpToolRectangle (kpMainWindow *);
+ virtual ~kpToolRectangle ();
+
+ void setMode (Mode mode);
+
+ virtual bool careAboutModifierState () const { return true; }
+
+private:
+ QString haventBegunDrawUserMessage () const;
+
+public:
+ virtual void begin ();
+ virtual void end ();
+
+ virtual void beginDraw ();
+private:
+ void updateShape ();
+public:
+ virtual void draw (const QPoint &, const QPoint &, const QRect &);
+ virtual void cancelShape ();
+ virtual void releasedAllButtons ();
+ virtual void endDraw (const QPoint &, const QRect &);
+
+private slots:
+ void updatePens ();
+ void updateBrushes ();
+
+ virtual void slotForegroundColorChanged (const kpColor &);
+ virtual void slotBackgroundColorChanged (const kpColor &);
+
+ virtual void slotLineWidthChanged ();
+ virtual void slotFillStyleChanged ();
+
+private:
+ Mode m_mode;
+
+ kpToolWidgetLineWidth *m_toolWidgetLineWidth;
+ kpToolWidgetFillStyle *m_toolWidgetFillStyle;
+
+ void updatePen (int mouseButton);
+ QPen m_pen [2], m_maskPen [2];
+
+ void updateBrush (int mouseButton);
+ QBrush m_brush [2], m_maskBrush [2];
+
+ void applyModifiers ();
+ QPoint m_toolRectangleStartPoint, m_toolRectangleEndPoint;
+ QRect m_toolRectangleRectWithoutLineWidth, m_toolRectangleRect;
+};
+
+class kpToolRectangleCommand : public kpCommand
+{
+public:
+ kpToolRectangleCommand (kpToolRectangle::Mode mode,
+ const QPen &pen, const QPen &maskPen,
+ const QBrush &brush, const QBrush &maskBrush,
+ const QRect &rect,
+ const QPoint &startPoint, const QPoint &endPoint,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolRectangleCommand ();
+
+ virtual QString name () const;
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ kpToolRectangle::Mode m_mode;
+ QPen m_pen, m_maskPen;
+ QBrush m_brush, m_maskBrush;
+ QRect m_rect;
+ QPoint m_startPoint, m_endPoint;
+ QPixmap *m_oldPixmapPtr;
+};
+
+#endif // __kptoolrectangle_h__
diff --git a/kolourpaint/tools/kptoolrectselection.cpp b/kolourpaint/tools/kptoolrectselection.cpp
new file mode 100644
index 00000000..3726cbfe
--- /dev/null
+++ b/kolourpaint/tools/kptoolrectselection.cpp
@@ -0,0 +1,46 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <kptoolrectselection.h>
+
+#include <klocale.h>
+
+
+kpToolRectSelection::kpToolRectSelection (kpMainWindow *mainWindow)
+ : kpToolSelection (Rectangle,
+ i18n ("Selection (Rectangular)"),
+ i18n ("Makes a rectangular selection"),
+ Qt::Key_S,
+ mainWindow, "tool_rect_selection")
+{
+}
+
+kpToolRectSelection::~kpToolRectSelection ()
+{
+}
+
diff --git a/kolourpaint/tools/kptoolrectselection.h b/kolourpaint/tools/kptoolrectselection.h
new file mode 100644
index 00000000..0d66b7a5
--- /dev/null
+++ b/kolourpaint/tools/kptoolrectselection.h
@@ -0,0 +1,43 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolrectselection_h__
+#define __kptoolrectselection_h__
+
+#include <kptoolselection.h>
+
+class kpMainWindow;
+
+class kpToolRectSelection : public kpToolSelection
+{
+public:
+ kpToolRectSelection (kpMainWindow *);
+ virtual ~kpToolRectSelection ();
+};
+
+#endif // __kptoolrectselection_h__
diff --git a/kolourpaint/tools/kptoolresizescale.cpp b/kolourpaint/tools/kptoolresizescale.cpp
new file mode 100644
index 00000000..ce9c9059
--- /dev/null
+++ b/kolourpaint/tools/kptoolresizescale.cpp
@@ -0,0 +1,1222 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_TOOL_RESIZE_SCALE_COMMAND 0
+#define DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG 0
+
+
+#include <kptoolresizescale.h>
+
+#include <math.h>
+
+#include <qaccel.h>
+#include <qapplication.h>
+#include <qbuttongroup.h>
+#include <qcheckbox.h>
+#include <qgroupbox.h>
+#include <qhbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpoint.h>
+#include <qpointarray.h>
+#include <qpushbutton.h>
+#include <qrect.h>
+#include <qsize.h>
+#include <qtoolbutton.h>
+#include <qwhatsthis.h>
+#include <qwmatrix.h>
+
+#include <kapplication.h>
+#include <kcombobox.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kiconeffect.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <knuminput.h>
+
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kpselection.h>
+#include <kptool.h>
+
+
+/*
+ * kpToolResizeScaleCommand
+ */
+
+kpToolResizeScaleCommand::kpToolResizeScaleCommand (bool actOnSelection,
+ int newWidth, int newHeight,
+ Type type,
+ kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ m_actOnSelection (actOnSelection),
+ m_type (type),
+ m_backgroundColor (mainWindow ? mainWindow->backgroundColor () : kpColor::invalid),
+ m_oldSelection (0)
+{
+ kpDocument *doc = document ();
+
+ m_oldWidth = doc->width (m_actOnSelection);
+ m_oldHeight = doc->height (m_actOnSelection);
+
+ m_actOnTextSelection = (m_actOnSelection &&
+ doc && doc->selection () &&
+ doc->selection ()->isText ());
+
+ resize (newWidth, newHeight);
+
+ // If we have a selection _border_ (but not a floating selection),
+ // then scale the selection with the document
+ m_scaleSelectionWithImage = (!m_actOnSelection &&
+ (m_type == Scale || m_type == SmoothScale) &&
+ document ()->selection () &&
+ !document ()->selection ()->pixmap ());
+}
+
+kpToolResizeScaleCommand::~kpToolResizeScaleCommand ()
+{
+ delete m_oldSelection;
+}
+
+
+// public virtual [base kpCommand]
+QString kpToolResizeScaleCommand::name () const
+{
+ if (m_actOnSelection)
+ {
+ if (m_actOnTextSelection)
+ {
+ if (m_type == Resize)
+ return i18n ("Text: Resize Box");
+ }
+ else
+ {
+ if (m_type == Scale)
+ return i18n ("Selection: Scale");
+ else if (m_type == SmoothScale)
+ return i18n ("Selection: Smooth Scale");
+ }
+ }
+ else
+ {
+ switch (m_type)
+ {
+ case Resize:
+ return i18n ("Resize");
+ case Scale:
+ return i18n ("Scale");
+ case SmoothScale:
+ return i18n ("Smooth Scale");
+ }
+ }
+
+ return QString::null;
+}
+
+// public virtual [base kpCommand]
+int kpToolResizeScaleCommand::size () const
+{
+ return kpPixmapFX::pixmapSize (m_oldPixmap) +
+ kpPixmapFX::pixmapSize (m_oldRightPixmap) +
+ kpPixmapFX::pixmapSize (m_oldBottomPixmap) +
+ (m_oldSelection ? m_oldSelection->size () : 0);
+}
+
+
+// public
+int kpToolResizeScaleCommand::newWidth () const
+{
+ return m_newWidth;
+}
+
+// public
+void kpToolResizeScaleCommand::setNewWidth (int width)
+{
+ resize (width, newHeight ());
+}
+
+
+// public
+int kpToolResizeScaleCommand::newHeight () const
+{
+ return m_newHeight;
+}
+
+// public
+void kpToolResizeScaleCommand::setNewHeight (int height)
+{
+ resize (newWidth (), height);
+}
+
+
+// public
+QSize kpToolResizeScaleCommand::newSize () const
+{
+ return QSize (newWidth (), newHeight ());
+}
+
+// public virtual
+void kpToolResizeScaleCommand::resize (int width, int height)
+{
+ m_newWidth = width;
+ m_newHeight = height;
+
+ m_isLosslessScale = ((m_type == Scale) &&
+ (m_newWidth / m_oldWidth * m_oldWidth == m_newWidth) &&
+ (m_newHeight / m_oldHeight * m_oldHeight == m_newHeight));
+}
+
+
+// public
+bool kpToolResizeScaleCommand::scaleSelectionWithImage () const
+{
+ return m_scaleSelectionWithImage;
+}
+
+
+// private
+void kpToolResizeScaleCommand::scaleSelectionRegionWithDocument ()
+{
+#if DEBUG_KP_TOOL_RESIZE_SCALE_COMMAND
+ kdDebug () << "kpToolResizeScaleCommand::scaleSelectionRegionWithDocument"
+ << endl;
+#endif
+
+ if (!m_oldSelection)
+ {
+ kdError () << "kpToolResizeScaleCommand::scaleSelectionRegionWithDocument()"
+ << " without old sel" << endl;
+ return;
+ }
+
+ if (m_oldSelection->pixmap ())
+ {
+ kdError () << "kpToolResizeScaleCommand::scaleSelectionRegionWithDocument()"
+ << " old sel has pixmap" << endl;
+ return;
+ }
+
+
+ const double horizScale = double (m_newWidth) / double (m_oldWidth);
+ const double vertScale = double (m_newHeight) / double (m_oldHeight);
+
+ const int newX = (int) (m_oldSelection->x () * horizScale);
+ const int newY = (int) (m_oldSelection->y () * vertScale);
+
+
+ QPointArray currentPoints = m_oldSelection->points ();
+ currentPoints.detach ();
+
+ currentPoints.translate (-currentPoints.boundingRect ().x (),
+ -currentPoints.boundingRect ().y ());
+
+ // TODO: refactor into kpPixmapFX
+ QWMatrix scaleMatrix;
+ scaleMatrix.scale (horizScale, vertScale);
+ currentPoints = scaleMatrix.map (currentPoints);
+
+ currentPoints.translate (
+ -currentPoints.boundingRect ().x () + newX,
+ -currentPoints.boundingRect ().y () + newY);
+
+ document ()->setSelection (kpSelection (currentPoints, QPixmap (),
+ m_oldSelection->transparency ()));
+
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+}
+
+
+// public virtual [base kpCommand]
+void kpToolResizeScaleCommand::execute ()
+{
+#if DEBUG_KP_TOOL_RESIZE_SCALE_COMMAND
+ kdDebug () << "kpToolResizeScaleCommand::execute() type="
+ << (int) m_type
+ << " oldWidth=" << m_oldWidth
+ << " oldHeight=" << m_oldHeight
+ << " newWidth=" << m_newWidth
+ << " newHeight=" << m_newHeight
+ << endl;
+#endif
+
+ if (m_oldWidth == m_newWidth && m_oldHeight == m_newHeight)
+ return;
+
+ if (m_type == Resize)
+ {
+ if (m_actOnSelection)
+ {
+ if (!m_actOnTextSelection)
+ {
+ kdError () << "kpToolResizeScaleCommand::execute() resizing sel doesn't make sense" << endl;
+ return;
+ }
+ else
+ {
+ QApplication::setOverrideCursor (Qt::waitCursor);
+ document ()->selection ()->textResize (m_newWidth, m_newHeight);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+
+ QApplication::restoreOverrideCursor ();
+ }
+ }
+ else
+ {
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+
+ if (m_newWidth < m_oldWidth)
+ {
+ m_oldRightPixmap = kpPixmapFX::getPixmapAt (
+ *document ()->pixmap (),
+ QRect (m_newWidth, 0,
+ m_oldWidth - m_newWidth, m_oldHeight));
+ }
+
+ if (m_newHeight < m_oldHeight)
+ {
+ m_oldBottomPixmap = kpPixmapFX::getPixmapAt (
+ *document ()->pixmap (),
+ QRect (0, m_newHeight,
+ m_newWidth, m_oldHeight - m_newHeight));
+ }
+
+ document ()->resize (m_newWidth, m_newHeight, m_backgroundColor);
+
+
+ QApplication::restoreOverrideCursor ();
+ }
+ }
+ else
+ {
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+
+ QPixmap oldPixmap = *document ()->pixmap (m_actOnSelection);
+
+ if (!m_isLosslessScale)
+ m_oldPixmap = oldPixmap;
+
+ QPixmap newPixmap = kpPixmapFX::scale (oldPixmap, m_newWidth, m_newHeight,
+ m_type == SmoothScale);
+
+
+ if (!m_oldSelection && document ()->selection ())
+ {
+ // Save sel border
+ m_oldSelection = new kpSelection (*document ()->selection ());
+ m_oldSelection->setPixmap (QPixmap ());
+ }
+
+ if (m_actOnSelection)
+ {
+ QRect newRect = QRect (m_oldSelection->x (), m_oldSelection->y (),
+ newPixmap.width (), newPixmap.height ());
+
+ // Not possible to retain non-rectangular selection borders on scale
+ // (think about e.g. a 45 deg line as part of the border & 2x scale)
+ document ()->setSelection (
+ kpSelection (kpSelection::Rectangle, newRect, newPixmap,
+ m_oldSelection->transparency ()));
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+ else
+ {
+ document ()->setPixmap (newPixmap);
+
+ if (m_scaleSelectionWithImage)
+ {
+ scaleSelectionRegionWithDocument ();
+ }
+ }
+
+
+ QApplication::restoreOverrideCursor ();
+ }
+}
+
+// public virtual [base kpCommand]
+void kpToolResizeScaleCommand::unexecute ()
+{
+#if DEBUG_KP_TOOL_RESIZE_SCALE_COMMAND
+ kdDebug () << "kpToolResizeScaleCommand::unexecute() type="
+ << m_type << endl;
+#endif
+
+ if (m_oldWidth == m_newWidth && m_oldHeight == m_newHeight)
+ return;
+
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ if (m_type == Resize)
+ {
+ if (m_actOnSelection)
+ {
+ if (!m_actOnTextSelection)
+ {
+ kdError () << "kpToolResizeScaleCommand::unexecute() resizing sel doesn't make sense" << endl;
+ return;
+ }
+ else
+ {
+ QApplication::setOverrideCursor (Qt::waitCursor);
+ document ()->selection ()->textResize (m_oldWidth, m_oldHeight);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+
+ QApplication::restoreOverrideCursor ();
+ }
+ }
+ else
+ {
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+
+ QPixmap newPixmap (m_oldWidth, m_oldHeight);
+
+ kpPixmapFX::setPixmapAt (&newPixmap, QPoint (0, 0),
+ *doc->pixmap ());
+
+ if (m_newWidth < m_oldWidth)
+ {
+ kpPixmapFX::setPixmapAt (&newPixmap,
+ QPoint (m_newWidth, 0),
+ m_oldRightPixmap);
+ }
+
+ if (m_newHeight < m_oldHeight)
+ {
+ kpPixmapFX::setPixmapAt (&newPixmap,
+ QPoint (0, m_newHeight),
+ m_oldBottomPixmap);
+ }
+
+ doc->setPixmap (newPixmap);
+
+
+ QApplication::restoreOverrideCursor ();
+ }
+ }
+ else
+ {
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+
+ QPixmap oldPixmap;
+
+ if (!m_isLosslessScale)
+ oldPixmap = m_oldPixmap;
+ else
+ oldPixmap = kpPixmapFX::scale (*doc->pixmap (m_actOnSelection),
+ m_oldWidth, m_oldHeight);
+
+
+ if (m_actOnSelection)
+ {
+ kpSelection oldSelection = *m_oldSelection;
+ oldSelection.setPixmap (oldPixmap);
+ doc->setSelection (oldSelection);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+ else
+ {
+ doc->setPixmap (oldPixmap);
+
+ if (m_scaleSelectionWithImage)
+ {
+ doc->setSelection (*m_oldSelection);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+ }
+
+
+ QApplication::restoreOverrideCursor ();
+ }
+}
+
+
+/*
+ * kpToolResizeScaleDialog
+ */
+
+#define SET_VALUE_WITHOUT_SIGNAL_EMISSION(knuminput_instance,value) \
+{ \
+ knuminput_instance->blockSignals (true); \
+ knuminput_instance->setValue (value); \
+ knuminput_instance->blockSignals (false); \
+}
+
+#define IGNORE_KEEP_ASPECT_RATIO(cmd) \
+{ \
+ m_ignoreKeepAspectRatio++; \
+ cmd; \
+ m_ignoreKeepAspectRatio--; \
+}
+
+
+// private static
+kpToolResizeScaleCommand::Type kpToolResizeScaleDialog::s_lastType =
+ kpToolResizeScaleCommand::Resize;
+
+// private static
+double kpToolResizeScaleDialog::s_lastPercentWidth = 100,
+ kpToolResizeScaleDialog::s_lastPercentHeight = 100;
+
+
+kpToolResizeScaleDialog::kpToolResizeScaleDialog (kpMainWindow *mainWindow)
+ : KDialogBase ((QWidget *) mainWindow,
+ 0/*name*/,
+ true/*modal*/,
+ i18n ("Resize / Scale")/*caption*/,
+ KDialogBase::Ok | KDialogBase::Cancel),
+ m_mainWindow (mainWindow),
+ m_ignoreKeepAspectRatio (0)
+{
+ // Using the percentage from last time become too confusing so disable for now
+ s_lastPercentWidth = 100, s_lastPercentHeight = 100;
+
+
+ QWidget *baseWidget = new QWidget (this);
+ setMainWidget (baseWidget);
+
+
+ createActOnBox (baseWidget);
+ createOperationGroupBox (baseWidget);
+ createDimensionsGroupBox (baseWidget);
+
+
+ QVBoxLayout *baseLayout = new QVBoxLayout (baseWidget, 0/*margin*/, spacingHint ());
+ baseLayout->addWidget (m_actOnBox);
+ baseLayout->addWidget (m_operationGroupBox);
+ baseLayout->addWidget (m_dimensionsGroupBox);
+
+
+ slotActOnChanged ();
+
+ m_newWidthInput->setEditFocus ();
+
+ //enableButtonOK (!isNoOp ());
+}
+
+kpToolResizeScaleDialog::~kpToolResizeScaleDialog ()
+{
+}
+
+
+// private
+kpDocument *kpToolResizeScaleDialog::document () const
+{
+ return m_mainWindow ? m_mainWindow->document () : 0;
+}
+
+// private
+kpSelection *kpToolResizeScaleDialog::selection () const
+{
+ return document () ? document ()->selection () : 0;
+}
+
+
+// private
+void kpToolResizeScaleDialog::createActOnBox (QWidget *baseWidget)
+{
+ m_actOnBox = new QHBox (baseWidget);
+ m_actOnBox->setSpacing (spacingHint () * 2);
+
+
+ m_actOnLabel = new QLabel (i18n ("Ac&t on:"), m_actOnBox);
+ m_actOnCombo = new KComboBox (m_actOnBox);
+
+
+ m_actOnLabel->setBuddy (m_actOnCombo);
+
+ m_actOnCombo->insertItem (i18n ("Entire Image"), Image);
+ if (selection ())
+ {
+ QString selName = i18n ("Selection");
+
+ if (selection ()->isText ())
+ selName = i18n ("Text Box");
+
+ m_actOnCombo->insertItem (selName, Selection);
+ m_actOnCombo->setCurrentItem (Selection);
+ }
+ else
+ {
+ m_actOnLabel->setEnabled (false);
+ m_actOnCombo->setEnabled (false);
+ }
+
+
+ m_actOnBox->setStretchFactor (m_actOnCombo, 1);
+
+
+ connect (m_actOnCombo, SIGNAL (activated (int)),
+ this, SLOT (slotActOnChanged ()));
+}
+
+
+static QIconSet toolButtonIconSet (const QString &iconName)
+{
+ QIconSet iconSet = UserIconSet (iconName);
+
+
+ // No "disabled" pixmap is generated by UserIconSet() so generate it
+ // ourselves:
+
+ QPixmap disabledIcon = KGlobal::iconLoader ()->iconEffect ()->apply (
+ UserIcon (iconName),
+ KIcon::Toolbar, KIcon::DisabledState);
+
+ const QPixmap iconSetNormalIcon = iconSet.pixmap (QIconSet::Small,
+ QIconSet::Normal);
+
+ // I bet past or future versions of KIconEffect::apply() resize the
+ // disabled icon if we claim it's in group KIcon::Toolbar. So resize
+ // it to match the QIconSet::Normal icon, just in case.
+ disabledIcon = kpPixmapFX::scale (disabledIcon,
+ iconSetNormalIcon.width (),
+ iconSetNormalIcon.height (),
+ true/*smooth scale*/);
+
+
+ iconSet.setPixmap (disabledIcon,
+ QIconSet::Small, QIconSet::Disabled);
+
+ return iconSet;
+}
+
+static void toolButtonSetLook (QToolButton *button,
+ const QString &iconName,
+ const QString &name)
+{
+ button->setIconSet (toolButtonIconSet (iconName));
+ button->setUsesTextLabel (true);
+ button->setTextLabel (name, false/*no tooltip*/);
+ button->setAccel (QAccel::shortcutKey (name));
+ button->setFocusPolicy (QWidget::StrongFocus);
+ button->setToggleButton (true);
+}
+
+
+// private
+void kpToolResizeScaleDialog::createOperationGroupBox (QWidget *baseWidget)
+{
+ m_operationGroupBox = new QGroupBox (i18n ("Operation"), baseWidget);
+ QWhatsThis::add (m_operationGroupBox,
+ i18n ("<qt>"
+ "<ul>"
+ "<li><b>Resize</b>: The size of the picture will be"
+ " increased"
+ " by creating new areas to the right and/or bottom"
+ " (filled in with the background color) or"
+ " decreased by cutting"
+ " it at the right and/or bottom.</li>"
+
+ "<li><b>Scale</b>: The picture will be expanded"
+ " by duplicating pixels or squashed by dropping pixels.</li>"
+
+ "<li><b>Smooth Scale</b>: This is the same as"
+ " <i>Scale</i> except that it blends neighboring"
+ " pixels to produce a smoother looking picture.</li>"
+ "</ul>"
+ "</qt>"));
+
+ // TODO: ALT+R doesn't select the button.
+ m_resizeButton = new QToolButton (m_operationGroupBox);
+ toolButtonSetLook (m_resizeButton,
+ QString::fromLatin1 ("resize"),
+ i18n ("&Resize"));
+
+ m_scaleButton = new QToolButton (m_operationGroupBox);
+ toolButtonSetLook (m_scaleButton,
+ QString::fromLatin1 ("scale"),
+ i18n ("&Scale"));
+
+ m_smoothScaleButton = new QToolButton (m_operationGroupBox);
+ toolButtonSetLook (m_smoothScaleButton,
+ QString::fromLatin1 ("smooth_scale"),
+ i18n ("S&mooth Scale"));
+
+
+ //m_resizeLabel = new QLabel (i18n ("&Resize"), m_operationGroupBox);
+ //m_scaleLabel = new QLabel (i18n ("&Scale"), m_operationGroupBox);
+ //m_smoothScaleLabel = new QLabel (i18n ("S&mooth scale"), m_operationGroupBox);
+
+
+ //m_resizeLabel->setAlignment (m_resizeLabel->alignment () | Qt::ShowPrefix);
+ //m_scaleLabel->setAlignment (m_scaleLabel->alignment () | Qt::ShowPrefix);
+ //m_smoothScaleLabel->setAlignment (m_smoothScaleLabel->alignment () | Qt::ShowPrefix);
+
+
+ QButtonGroup *resizeScaleButtonGroup = new QButtonGroup (baseWidget);
+ resizeScaleButtonGroup->setExclusive (true);
+ resizeScaleButtonGroup->hide ();
+
+ resizeScaleButtonGroup->insert (m_resizeButton);
+ resizeScaleButtonGroup->insert (m_scaleButton);
+ resizeScaleButtonGroup->insert (m_smoothScaleButton);
+
+
+ QGridLayout *operationLayout = new QGridLayout (m_operationGroupBox,
+ 1, 2,
+ marginHint () * 2/*don't overlap groupbox title*/,
+ spacingHint ());
+
+ operationLayout->addWidget (m_resizeButton, 0, 0, Qt::AlignCenter);
+ //operationLayout->addWidget (m_resizeLabel, 1, 0, Qt::AlignCenter);
+
+ operationLayout->addWidget (m_scaleButton, 0, 1, Qt::AlignCenter);
+ //operationLayout->addWidget (m_scaleLabel, 1, 1, Qt::AlignCenter);
+
+ operationLayout->addWidget (m_smoothScaleButton, 0, 2, Qt::AlignCenter);
+ //operationLayout->addWidget (m_smoothScaleLabel, 1, 2, Qt::AlignCenter);
+
+
+ connect (m_resizeButton, SIGNAL (toggled (bool)),
+ this, SLOT (slotTypeChanged ()));
+ connect (m_scaleButton, SIGNAL (toggled (bool)),
+ this, SLOT (slotTypeChanged ()));
+ connect (m_smoothScaleButton, SIGNAL (toggled (bool)),
+ this, SLOT (slotTypeChanged ()));
+}
+
+// private
+void kpToolResizeScaleDialog::createDimensionsGroupBox (QWidget *baseWidget)
+{
+ m_dimensionsGroupBox = new QGroupBox (i18n ("Dimensions"), baseWidget);
+
+ QLabel *widthLabel = new QLabel (i18n ("Width:"), m_dimensionsGroupBox);
+ widthLabel->setAlignment (widthLabel->alignment () | Qt::AlignHCenter);
+ QLabel *heightLabel = new QLabel (i18n ("Height:"), m_dimensionsGroupBox);
+ heightLabel->setAlignment (heightLabel->alignment () | Qt::AlignHCenter);
+
+ QLabel *originalLabel = new QLabel (i18n ("Original:"), m_dimensionsGroupBox);
+ m_originalWidthInput = new KIntNumInput (
+ document ()->width ((bool) selection ()),
+ m_dimensionsGroupBox);
+ QLabel *xLabel0 = new QLabel (i18n ("x"), m_dimensionsGroupBox);
+ m_originalHeightInput = new KIntNumInput (
+ document ()->height ((bool) selection ()),
+ m_dimensionsGroupBox);
+
+ QLabel *newLabel = new QLabel (i18n ("&New:"), m_dimensionsGroupBox);
+ m_newWidthInput = new KIntNumInput (m_dimensionsGroupBox);
+ QLabel *xLabel1 = new QLabel (i18n ("x"), m_dimensionsGroupBox);
+ m_newHeightInput = new KIntNumInput (m_dimensionsGroupBox);
+
+ QLabel *percentLabel = new QLabel (i18n ("&Percent:"), m_dimensionsGroupBox);
+ m_percentWidthInput = new KDoubleNumInput (0.01/*lower*/, 1000000/*upper*/,
+ 100/*value*/, 1/*step*/,
+ 2/*precision*/,
+ m_dimensionsGroupBox);
+ m_percentWidthInput->setSuffix (i18n ("%"));
+ QLabel *xLabel2 = new QLabel (i18n ("x"), m_dimensionsGroupBox);
+ m_percentHeightInput = new KDoubleNumInput (0.01/*lower*/, 1000000/*upper*/,
+ 100/*value*/, 1/*step*/,
+ 2/*precision*/,
+ m_dimensionsGroupBox);
+ m_percentHeightInput->setSuffix (i18n ("%"));
+
+ m_keepAspectRatioCheckBox = new QCheckBox (i18n ("Keep &aspect ratio"),
+ m_dimensionsGroupBox);
+
+
+ m_originalWidthInput->setEnabled (false);
+ m_originalHeightInput->setEnabled (false);
+ originalLabel->setBuddy (m_originalWidthInput);
+ newLabel->setBuddy (m_newWidthInput);
+ m_percentWidthInput->setValue (s_lastPercentWidth);
+ m_percentHeightInput->setValue (s_lastPercentHeight);
+ percentLabel->setBuddy (m_percentWidthInput);
+
+
+ QGridLayout *dimensionsLayout = new QGridLayout (m_dimensionsGroupBox,
+ 5, 4, marginHint () * 2, spacingHint ());
+ dimensionsLayout->setColStretch (1/*column*/, 1);
+ dimensionsLayout->setColStretch (3/*column*/, 1);
+
+
+ dimensionsLayout->addWidget (widthLabel, 0, 1);
+ dimensionsLayout->addWidget (heightLabel, 0, 3);
+
+ dimensionsLayout->addWidget (originalLabel, 1, 0);
+ dimensionsLayout->addWidget (m_originalWidthInput, 1, 1);
+ dimensionsLayout->addWidget (xLabel0, 1, 2);
+ dimensionsLayout->addWidget (m_originalHeightInput, 1, 3);
+
+ dimensionsLayout->addWidget (newLabel, 2, 0);
+ dimensionsLayout->addWidget (m_newWidthInput, 2, 1);
+ dimensionsLayout->addWidget (xLabel1, 2, 2);
+ dimensionsLayout->addWidget (m_newHeightInput, 2, 3);
+
+ dimensionsLayout->addWidget (percentLabel, 3, 0);
+ dimensionsLayout->addWidget (m_percentWidthInput, 3, 1);
+ dimensionsLayout->addWidget (xLabel2, 3, 2);
+ dimensionsLayout->addWidget (m_percentHeightInput, 3, 3);
+
+ dimensionsLayout->addMultiCellWidget (m_keepAspectRatioCheckBox, 4, 4, 0, 3);
+ dimensionsLayout->setRowStretch (4/*row*/, 1);
+ dimensionsLayout->setRowSpacing (4/*row*/, dimensionsLayout->rowSpacing (4) * 2);
+
+
+ connect (m_newWidthInput, SIGNAL (valueChanged (int)),
+ this, SLOT (slotWidthChanged (int)));
+ connect (m_newHeightInput, SIGNAL (valueChanged (int)),
+ this, SLOT (slotHeightChanged (int)));
+
+ connect (m_percentWidthInput, SIGNAL (valueChanged (double)),
+ this, SLOT (slotPercentWidthChanged (double)));
+ connect (m_percentHeightInput, SIGNAL (valueChanged (double)),
+ this, SLOT (slotPercentHeightChanged (double)));
+
+ connect (m_keepAspectRatioCheckBox, SIGNAL (toggled (bool)),
+ this, SLOT (setKeepAspectRatio (bool)));
+}
+
+
+// private
+void kpToolResizeScaleDialog::widthFitHeightToAspectRatio ()
+{
+ if (m_keepAspectRatioCheckBox->isChecked () && !m_ignoreKeepAspectRatio)
+ {
+ // width / height = oldWidth / oldHeight
+ // height = width * oldHeight / oldWidth
+ const int newHeight = qRound (double (imageWidth ()) * double (originalHeight ())
+ / double (originalWidth ()));
+ IGNORE_KEEP_ASPECT_RATIO (m_newHeightInput->setValue (newHeight));
+ }
+}
+
+// private
+void kpToolResizeScaleDialog::heightFitWidthToAspectRatio ()
+{
+ if (m_keepAspectRatioCheckBox->isChecked () && !m_ignoreKeepAspectRatio)
+ {
+ // width / height = oldWidth / oldHeight
+ // width = height * oldWidth / oldHeight
+ const int newWidth = qRound (double (imageHeight ()) * double (originalWidth ())
+ / double (originalHeight ()));
+ IGNORE_KEEP_ASPECT_RATIO (m_newWidthInput->setValue (newWidth));
+ }
+}
+
+
+// private
+bool kpToolResizeScaleDialog::resizeEnabled () const
+{
+ return (!actOnSelection () ||
+ (actOnSelection () && selection ()->isText ()));
+}
+
+// private
+bool kpToolResizeScaleDialog::scaleEnabled () const
+{
+ return (!(actOnSelection () && selection ()->isText ()));
+}
+
+// private
+bool kpToolResizeScaleDialog::smoothScaleEnabled () const
+{
+ return scaleEnabled ();
+}
+
+
+// public slot
+void kpToolResizeScaleDialog::slotActOnChanged ()
+{
+#if DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG && 1
+ kdDebug () << "kpToolResizeScaleDialog::slotActOnChanged()" << endl;
+#endif
+
+ m_resizeButton->setEnabled (resizeEnabled ());
+ //m_resizeLabel->setEnabled (resizeEnabled ());
+
+ m_scaleButton->setEnabled (scaleEnabled ());
+ //m_scaleLabel->setEnabled (scaleEnabled ());
+
+ m_smoothScaleButton->setEnabled (smoothScaleEnabled ());
+ //m_smoothScaleLabel->setEnabled (smoothScaleEnabled ());
+
+
+ // TODO: somehow share logic with (resize|*scale)Enabled()
+ if (actOnSelection ())
+ {
+ if (selection ()->isText ())
+ {
+ m_resizeButton->setOn (true);
+ }
+ else
+ {
+ if (s_lastType == kpToolResizeScaleCommand::Scale)
+ m_scaleButton->setOn (true);
+ else
+ m_smoothScaleButton->setOn (true);
+ }
+ }
+ else
+ {
+ if (s_lastType == kpToolResizeScaleCommand::Resize)
+ m_resizeButton->setOn (true);
+ else if (s_lastType == kpToolResizeScaleCommand::Scale)
+ m_scaleButton->setOn (true);
+ else
+ m_smoothScaleButton->setOn (true);
+ }
+
+
+ m_originalWidthInput->setValue (originalWidth ());
+ m_originalHeightInput->setValue (originalHeight ());
+
+
+ m_newWidthInput->blockSignals (true);
+ m_newHeightInput->blockSignals (true);
+
+ m_newWidthInput->setMinValue (actOnSelection () ?
+ selection ()->minimumWidth () :
+ 1);
+ m_newHeightInput->setMinValue (actOnSelection () ?
+ selection ()->minimumHeight () :
+ 1);
+
+ m_newWidthInput->blockSignals (false);
+ m_newHeightInput->blockSignals (false);
+
+
+ IGNORE_KEEP_ASPECT_RATIO (slotPercentWidthChanged (m_percentWidthInput->value ()));
+ IGNORE_KEEP_ASPECT_RATIO (slotPercentHeightChanged (m_percentHeightInput->value ()));
+
+ setKeepAspectRatio (m_keepAspectRatioCheckBox->isChecked ());
+}
+
+
+// public slot
+void kpToolResizeScaleDialog::slotTypeChanged ()
+{
+ s_lastType = type ();
+}
+
+// public slot
+void kpToolResizeScaleDialog::slotWidthChanged (int width)
+{
+#if DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG && 1
+ kdDebug () << "kpToolResizeScaleDialog::slotWidthChanged("
+ << width << ")" << endl;
+#endif
+ const double newPercentWidth = double (width) * 100 / double (originalWidth ());
+
+ SET_VALUE_WITHOUT_SIGNAL_EMISSION (m_percentWidthInput, newPercentWidth);
+
+ widthFitHeightToAspectRatio ();
+
+ //enableButtonOK (!isNoOp ());
+ s_lastPercentWidth = newPercentWidth;
+}
+
+// public slot
+void kpToolResizeScaleDialog::slotHeightChanged (int height)
+{
+#if DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG && 1
+ kdDebug () << "kpToolResizeScaleDialog::slotHeightChanged("
+ << height << ")" << endl;
+#endif
+ const double newPercentHeight = double (height) * 100 / double (originalHeight ());
+
+ SET_VALUE_WITHOUT_SIGNAL_EMISSION (m_percentHeightInput, newPercentHeight);
+
+ heightFitWidthToAspectRatio ();
+
+ //enableButtonOK (!isNoOp ());
+ s_lastPercentHeight = newPercentHeight;
+}
+
+// public slot
+void kpToolResizeScaleDialog::slotPercentWidthChanged (double percentWidth)
+{
+#if DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG && 1
+ kdDebug () << "kpToolResizeScaleDialog::slotPercentWidthChanged("
+ << percentWidth << ")" << endl;
+#endif
+
+ SET_VALUE_WITHOUT_SIGNAL_EMISSION (m_newWidthInput,
+ qRound (percentWidth * originalWidth () / 100.0));
+
+ widthFitHeightToAspectRatio ();
+
+ //enableButtonOK (!isNoOp ());
+ s_lastPercentWidth = percentWidth;
+}
+
+// public slot
+void kpToolResizeScaleDialog::slotPercentHeightChanged (double percentHeight)
+{
+#if DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG && 1
+ kdDebug () << "kpToolResizeScaleDialog::slotPercentHeightChanged("
+ << percentHeight << ")" << endl;
+#endif
+
+ SET_VALUE_WITHOUT_SIGNAL_EMISSION (m_newHeightInput,
+ qRound (percentHeight * originalHeight () / 100.0));
+
+ heightFitWidthToAspectRatio ();
+
+ //enableButtonOK (!isNoOp ());
+ s_lastPercentHeight = percentHeight;
+}
+
+// public
+bool kpToolResizeScaleDialog::keepAspectRatio () const
+{
+ return m_keepAspectRatioCheckBox->isChecked ();
+}
+
+// public slot
+void kpToolResizeScaleDialog::setKeepAspectRatio (bool on)
+{
+#if DEBUG_KP_TOOL_RESIZE_SCALE_DIALOG && 1
+ kdDebug () << "kpToolResizeScaleDialog::setKeepAspectRatio("
+ << on << ")" << endl;
+#endif
+ if (on != m_keepAspectRatioCheckBox->isChecked ())
+ m_keepAspectRatioCheckBox->setChecked (on);
+
+ if (on)
+ widthFitHeightToAspectRatio ();
+}
+
+#undef IGNORE_KEEP_ASPECT_RATIO
+#undef SET_VALUE_WITHOUT_SIGNAL_EMISSION
+
+
+// private
+int kpToolResizeScaleDialog::originalWidth () const
+{
+ return document ()->width (actOnSelection ());
+}
+
+// private
+int kpToolResizeScaleDialog::originalHeight () const
+{
+ return document ()->height (actOnSelection ());
+}
+
+
+// public
+int kpToolResizeScaleDialog::imageWidth () const
+{
+ return m_newWidthInput->value ();
+}
+
+// public
+int kpToolResizeScaleDialog::imageHeight () const
+{
+ return m_newHeightInput->value ();
+}
+
+// public
+bool kpToolResizeScaleDialog::actOnSelection () const
+{
+ return (m_actOnCombo->currentItem () == Selection);
+}
+
+// public
+kpToolResizeScaleCommand::Type kpToolResizeScaleDialog::type () const
+{
+ if (m_resizeButton->isOn ())
+ return kpToolResizeScaleCommand::Resize;
+ else if (m_scaleButton->isOn ())
+ return kpToolResizeScaleCommand::Scale;
+ else
+ return kpToolResizeScaleCommand::SmoothScale;
+}
+
+// public
+bool kpToolResizeScaleDialog::isNoOp () const
+{
+ return (imageWidth () == originalWidth () &&
+ imageHeight () == originalHeight ());
+}
+
+
+// private slot virtual [base KDialogBase]
+void kpToolResizeScaleDialog::slotOk ()
+{
+ enum { eText, eSelection, eImage } actionTarget = eText;
+
+ if (actOnSelection ())
+ {
+ if (selection ()->isText ())
+ {
+ actionTarget = eText;
+ }
+ else
+ {
+ actionTarget = eSelection;
+ }
+ }
+ else
+ {
+ actionTarget = eImage;
+ }
+
+
+ QString message, caption, continueButtonText;
+
+ // Note: If eText, can't Scale nor SmoothScale.
+ // If eSelection, can't Resize.
+
+ switch (type ())
+ {
+ default:
+ case kpToolResizeScaleCommand::Resize:
+ if (actionTarget == eText)
+ {
+ message =
+ i18n ("<qt><p>Resizing the text box to %1x%2"
+ " may take a substantial amount of memory."
+ " This can reduce system"
+ " responsiveness and cause other application resource"
+ " problems.</p>"
+
+ "<p>Are you sure you want to resize the text box?</p></qt>");
+
+ caption = i18n ("Resize Text Box?");
+ continueButtonText = i18n ("R&esize Text Box");
+ }
+ else if (actionTarget == eImage)
+ {
+ message =
+ i18n ("<qt><p>Resizing the image to %1x%2"
+ " may take a substantial amount of memory."
+ " This can reduce system"
+ " responsiveness and cause other application resource"
+ " problems.</p>"
+
+ "<p>Are you sure you want to resize the image?</p></qt>");
+
+ caption = i18n ("Resize Image?");
+ continueButtonText = i18n ("R&esize Image");
+ }
+
+ break;
+
+ case kpToolResizeScaleCommand::Scale:
+ if (actionTarget == eImage)
+ {
+ message =
+ i18n ("<qt><p>Scaling the image to %1x%2"
+ " may take a substantial amount of memory."
+ " This can reduce system"
+ " responsiveness and cause other application resource"
+ " problems.</p>"
+
+ "<p>Are you sure you want to scale the image?</p></qt>");
+
+ caption = i18n ("Scale Image?");
+ continueButtonText = i18n ("Scal&e Image");
+ }
+ else if (actionTarget == eSelection)
+ {
+ message =
+ i18n ("<qt><p>Scaling the selection to %1x%2"
+ " may take a substantial amount of memory."
+ " This can reduce system"
+ " responsiveness and cause other application resource"
+ " problems.</p>"
+
+ "<p>Are you sure you want to scale the selection?</p></qt>");
+
+ caption = i18n ("Scale Selection?");
+ continueButtonText = i18n ("Scal&e Selection");
+ }
+
+ break;
+
+ case kpToolResizeScaleCommand::SmoothScale:
+ if (actionTarget == eImage)
+ {
+ message =
+ i18n ("<qt><p>Smooth Scaling the image to %1x%2"
+ " may take a substantial amount of memory."
+ " This can reduce system"
+ " responsiveness and cause other application resource"
+ " problems.</p>"
+
+ "<p>Are you sure you want to smooth scale the image?</p></qt>");
+
+ caption = i18n ("Smooth Scale Image?");
+ continueButtonText = i18n ("Smooth Scal&e Image");
+ }
+ else if (actionTarget == eSelection)
+ {
+ message =
+ i18n ("<qt><p>Smooth Scaling the selection to %1x%2"
+ " may take a substantial amount of memory."
+ " This can reduce system"
+ " responsiveness and cause other application resource"
+ " problems.</p>"
+
+ "<p>Are you sure you want to smooth scale the selection?</p></qt>");
+
+ caption = i18n ("Smooth Scale Selection?");
+ continueButtonText = i18n ("Smooth Scal&e Selection");
+ }
+
+ break;
+ }
+
+
+ if (kpTool::warnIfBigImageSize (originalWidth (),
+ originalHeight (),
+ imageWidth (), imageHeight (),
+ message.arg (imageWidth ()).arg (imageHeight ()),
+ caption,
+ continueButtonText,
+ this))
+ {
+ KDialogBase::slotOk ();
+ }
+}
+
+
+#include <kptoolresizescale.moc>
diff --git a/kolourpaint/tools/kptoolresizescale.h b/kolourpaint/tools/kptoolresizescale.h
new file mode 100644
index 00000000..e23b040e
--- /dev/null
+++ b/kolourpaint/tools/kptoolresizescale.h
@@ -0,0 +1,196 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolresizescale_h__
+#define __kptoolresizescale_h__
+
+#include <qpixmap.h>
+
+#include <kpcommandhistory.h>
+#include <kdialogbase.h>
+
+#include <kpcolor.h>
+#include <kpselection.h>
+
+class QCheckBox;
+class QGroupBox;
+class QHBox;
+class QRadioButton;
+class QSize;
+class QString;
+class QToolButton;
+
+class KComboBox;
+class KDoubleNumInput;
+class KIntNumInput;
+
+class kpDocument;
+class kpMainWindow;
+class kpViewManager;
+
+class kpToolResizeScaleCommand : public kpCommand
+{
+public:
+ enum Type
+ {
+ Resize, Scale, SmoothScale
+ };
+
+ kpToolResizeScaleCommand (bool actOnSelection,
+ int newWidth, int newHeight,
+ Type type,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolResizeScaleCommand ();
+
+ virtual QString name () const;
+ virtual int size () const;
+
+public:
+ int newWidth () const;
+ void setNewWidth (int width);
+
+ int newHeight () const;
+ void setNewHeight (int height);
+
+ QSize newSize () const;
+ virtual void resize (int width, int height);
+
+public:
+ bool scaleSelectionWithImage () const;
+
+private:
+ void scaleSelectionRegionWithDocument ();
+
+public:
+ virtual void execute ();
+ virtual void unexecute ();
+
+protected:
+ bool m_actOnSelection;
+ int m_newWidth, m_newHeight;
+ Type m_type;
+ bool m_isLosslessScale;
+ bool m_scaleSelectionWithImage;
+ kpColor m_backgroundColor;
+
+ int m_oldWidth, m_oldHeight;
+ bool m_actOnTextSelection;
+ QPixmap m_oldPixmap, m_oldRightPixmap, m_oldBottomPixmap;
+ kpSelection *m_oldSelection;
+};
+
+class kpToolResizeScaleDialog : public KDialogBase
+{
+Q_OBJECT
+
+public:
+ kpToolResizeScaleDialog (kpMainWindow *mainWindow);
+ virtual ~kpToolResizeScaleDialog ();
+
+ enum ActOn
+ {
+ Image, Selection
+ };
+
+private:
+ static kpToolResizeScaleCommand::Type s_lastType;
+ static double s_lastPercentWidth, s_lastPercentHeight;
+
+private:
+ kpDocument *document () const;
+ kpSelection *selection () const;
+
+ void createActOnBox (QWidget *baseWidget);
+ void createOperationGroupBox (QWidget *baseWidget);
+ void createDimensionsGroupBox (QWidget *baseWidget);
+
+ void widthFitHeightToAspectRatio ();
+ void heightFitWidthToAspectRatio ();
+
+private:
+ bool resizeEnabled () const;
+ bool scaleEnabled () const;
+ bool smoothScaleEnabled () const;
+
+public slots:
+ void slotActOnChanged ();
+ void slotTypeChanged ();
+
+ void slotWidthChanged (int width);
+ void slotHeightChanged (int height);
+
+ void slotPercentWidthChanged (double percentWidth);
+ void slotPercentHeightChanged (double percentHeight);
+
+public:
+ // (refers only to the state of the checkbox - user of dialog does
+ // not have to do extra calculations)
+ bool keepAspectRatio () const;
+public slots:
+ void setKeepAspectRatio (bool on);
+
+private:
+ int originalWidth () const;
+ int originalHeight () const;
+
+public:
+ int imageWidth () const;
+ int imageHeight () const;
+ bool actOnSelection () const;
+ kpToolResizeScaleCommand::Type type () const;
+
+ bool isNoOp () const;
+
+private slots:
+ virtual void slotOk ();
+
+private:
+ kpMainWindow *m_mainWindow;
+
+ QHBox *m_actOnBox;
+ QLabel *m_actOnLabel;
+ KComboBox *m_actOnCombo;
+
+ QGroupBox *m_operationGroupBox;
+ QToolButton *m_resizeButton,
+ *m_scaleButton,
+ *m_smoothScaleButton;
+ QLabel *m_resizeLabel,
+ *m_scaleLabel,
+ *m_smoothScaleLabel;
+
+ QGroupBox *m_dimensionsGroupBox;
+ KIntNumInput *m_originalWidthInput, *m_originalHeightInput,
+ *m_newWidthInput, *m_newHeightInput;
+ KDoubleNumInput *m_percentWidthInput, *m_percentHeightInput;
+ QCheckBox *m_keepAspectRatioCheckBox;
+
+ int m_ignoreKeepAspectRatio;
+};
+
+#endif // __kptoolresizescale_h__
diff --git a/kolourpaint/tools/kptoolrotate.cpp b/kolourpaint/tools/kptoolrotate.cpp
new file mode 100644
index 00000000..8a37b673
--- /dev/null
+++ b/kolourpaint/tools/kptoolrotate.cpp
@@ -0,0 +1,500 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_TOOL_ROTATE 0
+
+
+#include <kptoolrotate.h>
+
+#include <qapplication.h>
+#include <qbuttongroup.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+#include <qwmatrix.h>
+
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <knuminput.h>
+#include <klocale.h>
+
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kpselection.h>
+#include <kptool.h>
+#include <kpviewmanager.h>
+
+
+kpToolRotateCommand::kpToolRotateCommand (bool actOnSelection,
+ double angle,
+ kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ m_actOnSelection (actOnSelection),
+ m_angle (angle),
+ m_backgroundColor (mainWindow ? mainWindow->backgroundColor (actOnSelection) : kpColor::invalid),
+ m_losslessRotation (kpPixmapFX::isLosslessRotation (angle))
+{
+}
+
+kpToolRotateCommand::~kpToolRotateCommand ()
+{
+}
+
+
+// public virtual [base kpCommand]
+QString kpToolRotateCommand::name () const
+{
+ QString opName = i18n ("Rotate");
+
+ if (m_actOnSelection)
+ return i18n ("Selection: %1").arg (opName);
+ else
+ return opName;
+}
+
+
+// public virtual [base kpCommand]
+int kpToolRotateCommand::size () const
+{
+ return kpPixmapFX::pixmapSize (m_oldPixmap) +
+ m_oldSelection.size ();
+}
+
+
+// public virtual [base kpCommand]
+void kpToolRotateCommand::execute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+
+ if (!m_losslessRotation)
+ m_oldPixmap = *doc->pixmap (m_actOnSelection);
+
+
+ QPixmap newPixmap = kpPixmapFX::rotate (*doc->pixmap (m_actOnSelection),
+ m_angle,
+ m_backgroundColor);
+
+
+ if (m_actOnSelection)
+ {
+ kpSelection *sel = doc->selection ();
+
+ // Save old selection
+ m_oldSelection = *sel;
+ m_oldSelection.setPixmap (QPixmap ());
+
+
+ // Calculate new top left (so selection rotates about centre)
+ // (the Times2 trickery is used to reduce integer division error without
+ // resorting to the troublesome world of floating point)
+ QPoint oldCenterTimes2 (sel->x () * 2 + sel->width (),
+ sel->y () * 2 + sel->height ());
+ QPoint newTopLeftTimes2 (oldCenterTimes2 - QPoint (newPixmap.width (), newPixmap.height ()));
+ QPoint newTopLeft (newTopLeftTimes2.x () / 2, newTopLeftTimes2.y () / 2);
+
+
+ // Calculate rotated points
+ QPointArray currentPoints = sel->points ();
+ currentPoints.translate (-currentPoints.boundingRect ().x (),
+ -currentPoints.boundingRect ().y ());
+ QWMatrix rotateMatrix = kpPixmapFX::rotateMatrix (*doc->pixmap (m_actOnSelection), m_angle);
+ currentPoints = rotateMatrix.map (currentPoints);
+ currentPoints.translate (-currentPoints.boundingRect ().x () + newTopLeft.x (),
+ -currentPoints.boundingRect ().y () + newTopLeft.y ());
+
+
+ if (currentPoints.boundingRect ().width () == newPixmap.width () &&
+ currentPoints.boundingRect ().height () == newPixmap.height ())
+ {
+ doc->setSelection (kpSelection (currentPoints, newPixmap,
+ m_oldSelection.transparency ()));
+ }
+ else
+ {
+ // TODO: fix the latter "victim of" problem in kpSelection by
+ // allowing the border width & height != pixmap width & height
+ // Or maybe autocrop?
+ #if DEBUG_KP_TOOL_ROTATE
+ kdDebug () << "kpToolRotateCommand::execute() currentPoints.boundingRect="
+ << currentPoints.boundingRect ()
+ << " newPixmap: w=" << newPixmap.width ()
+ << " h=" << newPixmap.height ()
+ << " (victim of rounding error and/or rotated-a-(rectangular)-pixmap-that-was-transparent-in-the-corners-making-sel-uselessly-bigger-than-needs-be)"
+ << endl;
+ #endif
+ doc->setSelection (kpSelection (kpSelection::Rectangle,
+ QRect (newTopLeft.x (), newTopLeft.y (),
+ newPixmap.width (), newPixmap.height ()),
+ newPixmap,
+ m_oldSelection.transparency ()));
+ }
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+ else
+ doc->setPixmap (newPixmap);
+
+
+ QApplication::restoreOverrideCursor ();
+}
+
+// public virtual [base kpCommand]
+void kpToolRotateCommand::unexecute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+
+ QPixmap oldPixmap;
+
+ if (!m_losslessRotation)
+ {
+ oldPixmap = m_oldPixmap;
+ m_oldPixmap.resize (0, 0);
+ }
+ else
+ {
+ oldPixmap = kpPixmapFX::rotate (*doc->pixmap (m_actOnSelection),
+ 360 - m_angle,
+ m_backgroundColor);
+ }
+
+
+ if (!m_actOnSelection)
+ doc->setPixmap (oldPixmap);
+ else
+ {
+ kpSelection oldSelection = m_oldSelection;
+ oldSelection.setPixmap (oldPixmap);
+ doc->setSelection (oldSelection);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+
+
+ QApplication::restoreOverrideCursor ();
+}
+
+
+/*
+ * kpToolRotateDialog
+ */
+
+
+// private static
+int kpToolRotateDialog::s_lastWidth = -1,
+ kpToolRotateDialog::s_lastHeight = -1;
+
+// private static
+bool kpToolRotateDialog::s_lastIsClockwise = true;
+int kpToolRotateDialog::s_lastAngleRadioButtonID = 3;
+int kpToolRotateDialog::s_lastAngleCustom = 0;
+
+
+kpToolRotateDialog::kpToolRotateDialog (bool actOnSelection,
+ kpMainWindow *mainWindow,
+ const char *name)
+ : kpToolPreviewDialog (kpToolPreviewDialog::AllFeatures,
+ false/*don't reserve top row*/,
+ actOnSelection ? i18n ("Rotate Selection") : i18n ("Rotate Image"),
+ i18n ("After Rotate:"),
+ actOnSelection, mainWindow, name)
+{
+ // Too confusing - disable for now
+ s_lastAngleRadioButtonID = 3;
+ s_lastAngleCustom = 0;
+
+
+ createDirectionGroupBox ();
+ createAngleGroupBox ();
+
+
+ if (s_lastWidth > 0 && s_lastHeight > 0)
+ resize (s_lastWidth, s_lastHeight);
+
+
+ slotAngleCustomRadioButtonToggled (m_angleCustomRadioButton->isChecked ());
+ slotUpdate ();
+}
+
+kpToolRotateDialog::~kpToolRotateDialog ()
+{
+ s_lastWidth = width (), s_lastHeight = height ();
+}
+
+
+// private
+void kpToolRotateDialog::createDirectionGroupBox ()
+{
+ QGroupBox *directionGroupBox = new QGroupBox (i18n ("Direction"), mainWidget ());
+ addCustomWidget (directionGroupBox);
+
+
+ QLabel *antiClockwisePixmapLabel = new QLabel (directionGroupBox);
+ antiClockwisePixmapLabel->setPixmap (UserIcon ("image_rotate_anticlockwise"));
+
+ QLabel *clockwisePixmapLabel = new QLabel (directionGroupBox);
+ clockwisePixmapLabel->setPixmap (UserIcon ("image_rotate_clockwise"));
+
+
+ m_antiClockwiseRadioButton = new QRadioButton (i18n ("Cou&nterclockwise"), directionGroupBox);
+ m_clockwiseRadioButton = new QRadioButton (i18n ("C&lockwise"), directionGroupBox);
+
+
+ m_antiClockwiseRadioButton->setChecked (!s_lastIsClockwise);
+ m_clockwiseRadioButton->setChecked (s_lastIsClockwise);
+
+
+ QButtonGroup *buttonGroup = new QButtonGroup (directionGroupBox);
+ buttonGroup->hide ();
+
+ buttonGroup->insert (m_antiClockwiseRadioButton);
+ buttonGroup->insert (m_clockwiseRadioButton);
+
+
+ QGridLayout *directionLayout = new QGridLayout (directionGroupBox,
+ 2, 2, marginHint () * 2, spacingHint ());
+ directionLayout->addWidget (antiClockwisePixmapLabel, 0, 0, Qt::AlignCenter);
+ directionLayout->addWidget (clockwisePixmapLabel, 0, 1, Qt::AlignCenter);
+ directionLayout->addWidget (m_antiClockwiseRadioButton, 1, 0, Qt::AlignCenter);
+ directionLayout->addWidget (m_clockwiseRadioButton, 1, 1, Qt::AlignCenter);
+
+
+ connect (m_antiClockwiseRadioButton, SIGNAL (toggled (bool)),
+ this, SLOT (slotUpdate ()));
+ connect (m_clockwiseRadioButton, SIGNAL (toggled (bool)),
+ this, SLOT (slotUpdate ()));
+}
+
+// private
+void kpToolRotateDialog::createAngleGroupBox ()
+{
+ QGroupBox *angleGroupBox = new QGroupBox (i18n ("Angle"), mainWidget ());
+ addCustomWidget (angleGroupBox);
+
+
+ m_angle90RadioButton = new QRadioButton (i18n ("90 &degrees"), angleGroupBox);
+ m_angle180RadioButton = new QRadioButton (i18n ("180 d&egrees"), angleGroupBox);
+ m_angle270RadioButton = new QRadioButton (i18n ("270 de&grees"), angleGroupBox);
+
+ m_angleCustomRadioButton = new QRadioButton (i18n ("C&ustom:"), angleGroupBox);
+ m_angleCustomInput = new KIntNumInput (s_lastAngleCustom, angleGroupBox);
+ m_angleCustomInput->setMinValue (-359);
+ m_angleCustomInput->setMaxValue (+359);
+ QLabel *degreesLabel = new QLabel (i18n ("degrees"), angleGroupBox);
+
+
+ m_angleButtonGroup = new QButtonGroup (angleGroupBox);
+ m_angleButtonGroup->hide ();
+
+ m_angleButtonGroup->insert (m_angle90RadioButton);
+ m_angleButtonGroup->insert (m_angle180RadioButton);
+ m_angleButtonGroup->insert (m_angle270RadioButton);
+
+ m_angleButtonGroup->insert (m_angleCustomRadioButton);
+
+ m_angleButtonGroup->setButton (s_lastAngleRadioButtonID);
+
+
+ QGridLayout *angleLayout = new QGridLayout (angleGroupBox,
+ 6, 3,
+ marginHint () * 2, spacingHint ());
+
+ angleLayout->addMultiCellWidget (m_angle90RadioButton, 0, 0, 0, 2);
+ angleLayout->addMultiCellWidget (m_angle180RadioButton, 1, 1, 0, 2);
+ angleLayout->addMultiCellWidget (m_angle270RadioButton, 2, 2, 0, 2);
+
+ angleLayout->addWidget (m_angleCustomRadioButton, 3, 0);
+ angleLayout->addWidget (m_angleCustomInput, 3, 1);
+ angleLayout->addWidget (degreesLabel, 3, 2);
+
+ angleLayout->setColStretch (1, 2); // Stretch Custom Angle Input
+
+
+ connect (m_angle90RadioButton, SIGNAL (toggled (bool)),
+ this, SLOT (slotUpdate ()));
+ connect (m_angle180RadioButton, SIGNAL (toggled (bool)),
+ this, SLOT (slotUpdate ()));
+ connect (m_angle270RadioButton, SIGNAL (toggled (bool)),
+ this, SLOT (slotUpdate ()));
+
+ connect (m_angleCustomRadioButton, SIGNAL (toggled (bool)),
+ this, SLOT (slotAngleCustomRadioButtonToggled (bool)));
+ connect (m_angleCustomRadioButton, SIGNAL (toggled (bool)),
+ this, SLOT (slotUpdate ()));
+
+ connect (m_angleCustomInput, SIGNAL (valueChanged (int)),
+ this, SLOT (slotUpdate ()));
+}
+
+
+// public virtual [base kpToolPreviewDialog]
+bool kpToolRotateDialog::isNoOp () const
+{
+ return (angle () == 0);
+}
+
+// public
+int kpToolRotateDialog::angle () const
+{
+ int retAngle;
+
+
+ if (m_angle90RadioButton->isChecked ())
+ retAngle = 90;
+ else if (m_angle180RadioButton->isChecked ())
+ retAngle = 180;
+ else if (m_angle270RadioButton->isChecked ())
+ retAngle = 270;
+ else // if (m_angleCustomRadioButton->isChecked ())
+ retAngle = m_angleCustomInput->value ();
+
+
+ if (m_antiClockwiseRadioButton->isChecked ())
+ retAngle *= -1;
+
+
+ if (retAngle < 0)
+ retAngle += ((0 - retAngle) / 360 + 1) * 360;
+
+ if (retAngle >= 360)
+ retAngle -= ((retAngle - 360) / 360 + 1) * 360;
+
+
+ return retAngle;
+}
+
+
+// private virtual [base kpToolPreviewDialog]
+QSize kpToolRotateDialog::newDimensions () const
+{
+ QWMatrix matrix = kpPixmapFX::rotateMatrix (m_oldWidth, m_oldHeight, angle ());
+ // TODO: Should we be using QWMatrix::Areas?
+ QRect rect = matrix.map (QRect (0, 0, m_oldWidth, m_oldHeight));
+ return rect.size ();
+}
+
+// private virtual [base kpToolPreviewDialog]
+QPixmap kpToolRotateDialog::transformPixmap (const QPixmap &pixmap,
+ int targetWidth, int targetHeight) const
+{
+ return kpPixmapFX::rotate (pixmap, angle (),
+ m_mainWindow ? m_mainWindow->backgroundColor (m_actOnSelection) : kpColor::invalid,
+ targetWidth, targetHeight);
+}
+
+
+// private slot
+void kpToolRotateDialog::slotAngleCustomRadioButtonToggled (bool isChecked)
+{
+ m_angleCustomInput->setEnabled (isChecked);
+
+ if (isChecked)
+ m_angleCustomInput->setEditFocus ();
+}
+
+// private slot virtual [base kpToolPreviewDialog]
+void kpToolRotateDialog::slotUpdate ()
+{
+ s_lastIsClockwise = m_clockwiseRadioButton->isChecked ();
+ s_lastAngleRadioButtonID = m_angleButtonGroup->selectedId ();
+ s_lastAngleCustom = m_angleCustomInput->value ();
+
+ kpToolPreviewDialog::slotUpdate ();
+}
+
+
+// private slot virtual [base KDialogBase]
+void kpToolRotateDialog::slotOk ()
+{
+ QString message, caption, continueButtonText;
+
+ if (document ()->selection ())
+ {
+ if (!document ()->selection ()->isText ())
+ {
+ message =
+ i18n ("<qt><p>Rotating the selection to %1x%2"
+ " may take a substantial amount of memory."
+ " This can reduce system"
+ " responsiveness and cause other application resource"
+ " problems.</p>"
+
+ "<p>Are you sure want to rotate the selection?</p></qt>");
+
+ caption = i18n ("Rotate Selection?");
+ continueButtonText = i18n ("Rotat&e Selection");
+ }
+ }
+ else
+ {
+ message =
+ i18n ("<qt><p>Rotating the image to %1x%2"
+ " may take a substantial amount of memory."
+ " This can reduce system"
+ " responsiveness and cause other application resource"
+ " problems.</p>"
+
+ "<p>Are you sure want to rotate the image?</p></qt>");
+
+ caption = i18n ("Rotate Image?");
+ continueButtonText = i18n ("Rotat&e Image");
+ }
+
+
+ const int newWidth = newDimensions ().width ();
+ const int newHeight = newDimensions ().height ();
+
+ if (kpTool::warnIfBigImageSize (m_oldWidth,
+ m_oldHeight,
+ newWidth, newHeight,
+ message.arg (newWidth).arg (newHeight),
+ caption,
+ continueButtonText,
+ this))
+ {
+ KDialogBase::slotOk ();
+ }
+}
+
+#include <kptoolrotate.moc>
diff --git a/kolourpaint/tools/kptoolrotate.h b/kolourpaint/tools/kptoolrotate.h
new file mode 100644
index 00000000..887473dc
--- /dev/null
+++ b/kolourpaint/tools/kptoolrotate.h
@@ -0,0 +1,129 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolrotate_h__
+#define __kptoolrotate_h__
+
+#include <qpixmap.h>
+#include <qpoint.h>
+
+#include <kdialogbase.h>
+
+#include <kpcolor.h>
+#include <kpcommandhistory.h>
+#include <kpselection.h>
+#include <kptoolpreviewdialog.h>
+
+
+class QButtonGroup;
+class QRadioButton;
+class QString;
+
+class KIntNumInput;
+
+class kpDocument;
+class kpViewManager;
+class kpMainWindow;
+
+
+class kpToolRotateCommand : public kpCommand
+{
+public:
+ kpToolRotateCommand (bool actOnSelection,
+ double angle, // 0 <= angle < 360 (clockwise)
+ kpMainWindow *mainWindow);
+ virtual ~kpToolRotateCommand ();
+
+ virtual QString name () const;
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ bool m_actOnSelection;
+ double m_angle;
+
+ kpColor m_backgroundColor;
+
+ bool m_losslessRotation;
+ QPixmap m_oldPixmap;
+ kpSelection m_oldSelection;
+};
+
+
+class kpToolRotateDialog : public kpToolPreviewDialog
+{
+Q_OBJECT
+
+public:
+ kpToolRotateDialog (bool actOnSelection,
+ kpMainWindow *parent,
+ const char *name = 0);
+ virtual ~kpToolRotateDialog ();
+
+private:
+ static int s_lastWidth, s_lastHeight;
+ static bool s_lastIsClockwise;
+ static int s_lastAngleRadioButtonID;
+ static int s_lastAngleCustom;
+
+ void createDirectionGroupBox ();
+ void createAngleGroupBox ();
+
+public:
+ virtual bool isNoOp () const;
+ int angle () const; // 0 <= angle < 360 (clockwise);
+
+private:
+ virtual QSize newDimensions () const;
+ virtual QPixmap transformPixmap (const QPixmap &pixmap,
+ int targetWidth, int targetHeight) const;
+
+private slots:
+ void slotAngleCustomRadioButtonToggled (bool isChecked);
+ virtual void slotUpdate ();
+
+private slots:
+ virtual void slotOk ();
+
+private:
+ QRadioButton *m_antiClockwiseRadioButton,
+ *m_clockwiseRadioButton;
+
+ QButtonGroup *m_angleButtonGroup;
+ QRadioButton *m_angle90RadioButton,
+ *m_angle180RadioButton,
+ *m_angle270RadioButton,
+ *m_angleCustomRadioButton;
+ KIntNumInput *m_angleCustomInput;
+};
+
+
+#endif // __kptoolrotate_h__
diff --git a/kolourpaint/tools/kptoolroundedrectangle.cpp b/kolourpaint/tools/kptoolroundedrectangle.cpp
new file mode 100644
index 00000000..b0f4ba05
--- /dev/null
+++ b/kolourpaint/tools/kptoolroundedrectangle.cpp
@@ -0,0 +1,45 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <klocale.h>
+#include <kptoolroundedrectangle.h>
+
+kpToolRoundedRectangle::kpToolRoundedRectangle (kpMainWindow *mainWindow)
+ : kpToolRectangle (RoundedRectangle,
+ i18n ("Rounded Rectangle"),
+ i18n ("Draws rectangles and squares with rounded corners"),
+ Qt::Key_U,
+ mainWindow, "tool_rounded_rectangle")
+{
+}
+
+kpToolRoundedRectangle::~kpToolRoundedRectangle ()
+{
+}
+
+#include <kptoolroundedrectangle.moc>
diff --git a/kolourpaint/tools/kptoolroundedrectangle.h b/kolourpaint/tools/kptoolroundedrectangle.h
new file mode 100644
index 00000000..924c1b34
--- /dev/null
+++ b/kolourpaint/tools/kptoolroundedrectangle.h
@@ -0,0 +1,45 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolroundedrectangle_h__
+#define __kptoolroundedrectangle_h__
+
+#include <kptoolrectangle.h>
+
+class kpMainWindow;
+
+class kpToolRoundedRectangle : public kpToolRectangle
+{
+Q_OBJECT
+
+public:
+ kpToolRoundedRectangle (kpMainWindow *);
+ virtual ~kpToolRoundedRectangle ();
+};
+
+#endif // __kptoolroundedrectangle_h__
diff --git a/kolourpaint/tools/kptoolselection.cpp b/kolourpaint/tools/kptoolselection.cpp
new file mode 100644
index 00000000..f664f01b
--- /dev/null
+++ b/kolourpaint/tools/kptoolselection.cpp
@@ -0,0 +1,2371 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_TOOL_SELECTION 0
+
+
+#include <kptoolselection.h>
+
+#include <qapplication.h>
+#include <qbitmap.h>
+#include <qcursor.h>
+#include <qpainter.h>
+#include <qpopupmenu.h>
+#include <qtimer.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcommandhistory.h>
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kpselection.h>
+#include <kptooltoolbar.h>
+#include <kptoolwidgetopaqueortransparent.h>
+#include <kpview.h>
+#include <kpviewmanager.h>
+
+
+kpToolSelection::kpToolSelection (Mode mode,
+ const QString &text,
+ const QString &description,
+ int key,
+ kpMainWindow *mainWindow,
+ const char *name)
+ : kpTool (text, description, key, mainWindow, name),
+ m_mode (mode),
+ m_currentPullFromDocumentCommand (0),
+ m_currentMoveCommand (0),
+ m_currentResizeScaleCommand (0),
+ m_toolWidgetOpaqueOrTransparent (0),
+ m_currentCreateTextCommand (0),
+ m_createNOPTimer (new QTimer (this)),
+ m_RMBMoveUpdateGUITimer (new QTimer (this))
+{
+ connect (m_createNOPTimer, SIGNAL (timeout ()),
+ this, SLOT (delayedDraw ()));
+ connect (m_RMBMoveUpdateGUITimer, SIGNAL (timeout ()),
+ this, SLOT (slotRMBMoveUpdateGUI ()));
+}
+
+kpToolSelection::~kpToolSelection ()
+{
+}
+
+
+// private
+void kpToolSelection::pushOntoDocument ()
+{
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "kpToolSelection::pushOntoDocument() CALLED" << endl;
+#endif
+ mainWindow ()->slotDeselect ();
+}
+
+
+// protected
+bool kpToolSelection::onSelectionToMove () const
+{
+ kpView *v = viewManager ()->viewUnderCursor ();
+ if (!v)
+ return 0;
+
+ return v->mouseOnSelectionToMove (m_currentViewPoint);
+}
+
+// protected
+int kpToolSelection::onSelectionResizeHandle () const
+{
+ kpView *v = viewManager ()->viewUnderCursor ();
+ if (!v)
+ return 0;
+
+ return v->mouseOnSelectionResizeHandle (m_currentViewPoint);
+}
+
+// protected
+bool kpToolSelection::onSelectionToSelectText () const
+{
+ kpView *v = viewManager ()->viewUnderCursor ();
+ if (!v)
+ return 0;
+
+ return v->mouseOnSelectionToSelectText (m_currentViewPoint);
+}
+
+
+// public
+QString kpToolSelection::haventBegunDrawUserMessage () const
+{
+#if DEBUG_KP_TOOL_SELECTION && 0
+ kdDebug () << "kpToolSelection::haventBegunDrawUserMessage()"
+ " cancelledShapeButStillHoldingButtons="
+ << m_cancelledShapeButStillHoldingButtons
+ << endl;
+#endif
+
+ if (m_cancelledShapeButStillHoldingButtons)
+ return i18n ("Let go of all the mouse buttons.");
+
+ kpSelection *sel = document ()->selection ();
+ if (sel && onSelectionResizeHandle () && !controlOrShiftPressed ())
+ {
+ if (m_mode == Text)
+ return i18n ("Left drag to resize text box.");
+ else
+ return i18n ("Left drag to scale selection.");
+ }
+ else if (sel && sel->contains (m_currentPoint))
+ {
+ if (m_mode == Text)
+ {
+ if (onSelectionToSelectText () && !controlOrShiftPressed ())
+ return i18n ("Left click to change cursor position.");
+ else
+ return i18n ("Left drag to move text box.");
+ }
+ else
+ {
+ return i18n ("Left drag to move selection.");
+ }
+ }
+ else
+ {
+ if (m_mode == Text)
+ return i18n ("Left drag to create text box.");
+ else
+ return i18n ("Left drag to create selection.");
+ }
+}
+
+
+// virtual
+void kpToolSelection::begin ()
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelection::begin()" << endl;
+#endif
+
+ kpToolToolBar *tb = toolToolBar ();
+
+ if (tb)
+ {
+ m_toolWidgetOpaqueOrTransparent = tb->toolWidgetOpaqueOrTransparent ();
+
+ if (m_toolWidgetOpaqueOrTransparent)
+ {
+ connect (m_toolWidgetOpaqueOrTransparent, SIGNAL (isOpaqueChanged (bool)),
+ this, SLOT (slotIsOpaqueChanged ()));
+ m_toolWidgetOpaqueOrTransparent->show ();
+ }
+ }
+ else
+ {
+ m_toolWidgetOpaqueOrTransparent = 0;
+ }
+
+ viewManager ()->setQueueUpdates ();
+ {
+ viewManager ()->setSelectionBorderVisible (true);
+ viewManager ()->setSelectionBorderFinished (true);
+ }
+ viewManager ()->restoreQueueUpdates ();
+
+ m_startDragFromSelectionTopLeft = QPoint ();
+ m_dragType = Unknown;
+ m_dragHasBegun = false;
+ m_hadSelectionBeforeDrag = false; // arbitrary
+ m_resizeScaleType = 0;
+
+ m_currentPullFromDocumentCommand = 0;
+ m_currentMoveCommand = 0;
+ m_currentResizeScaleCommand = 0;
+ m_currentCreateTextCommand = 0;
+
+ m_cancelledShapeButStillHoldingButtons = false;
+
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+// virtual
+void kpToolSelection::end ()
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelection::end()" << endl;
+#endif
+
+ if (document ()->selection ())
+ pushOntoDocument ();
+
+ if (m_toolWidgetOpaqueOrTransparent)
+ {
+ disconnect (m_toolWidgetOpaqueOrTransparent, SIGNAL (isOpaqueChanged (bool)),
+ this, SLOT (slotIsOpaqueChanged ()));
+ m_toolWidgetOpaqueOrTransparent = 0;
+ }
+
+ viewManager ()->unsetCursor ();
+}
+
+// virtual
+void kpToolSelection::reselect ()
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelection::reselect()" << endl;
+#endif
+
+ if (document ()->selection ())
+ pushOntoDocument ();
+}
+
+
+// virtual
+void kpToolSelection::beginDraw ()
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelection::beginDraw() m_startPoint="
+ << m_startPoint
+ << " QCursor::pos() view startPoint="
+ << m_viewUnderStartPoint->mapFromGlobal (QCursor::pos ())
+ << endl;
+#endif
+
+ m_createNOPTimer->stop ();
+ m_RMBMoveUpdateGUITimer->stop ();
+
+
+ // In case the cursor was wrong to start with
+ // (forgot to call kpTool::somethingBelowTheCursorChanged()),
+ // make sure it is correct during this operation.
+ hover (m_currentPoint);
+
+ // Currently used only to end the current text
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint/* TODO: wrong */, m_currentPoint).normalize ());
+
+ m_dragType = Create;
+ m_dragHasBegun = false;
+
+ kpSelection *sel = document ()->selection ();
+ m_hadSelectionBeforeDrag = bool (sel);
+
+ if (sel)
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\thas sel region rect=" << sel->boundingRect () << endl;
+ #endif
+ QRect selectionRect = sel->boundingRect ();
+
+ if (onSelectionResizeHandle () && !controlOrShiftPressed ())
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\t\tis resize/scale" << endl;
+ #endif
+
+ m_startDragFromSelectionTopLeft = m_currentPoint - selectionRect.topLeft ();
+ m_dragType = ResizeScale;
+ m_resizeScaleType = onSelectionResizeHandle ();
+
+ viewManager ()->setQueueUpdates ();
+ {
+ viewManager ()->setSelectionBorderVisible (true);
+ viewManager ()->setSelectionBorderFinished (true);
+ viewManager ()->setTextCursorEnabled (false);
+ }
+ viewManager ()->restoreQueueUpdates ();
+ }
+ else if (sel->contains (m_currentPoint))
+ {
+ if (m_mode == Text && onSelectionToSelectText () && !controlOrShiftPressed ())
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\t\tis select cursor pos" << endl;
+ #endif
+
+ m_dragType = SelectText;
+
+ viewManager ()->setTextCursorPosition (sel->textRowForPoint (m_currentPoint),
+ sel->textColForPoint (m_currentPoint));
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\t\tis move" << endl;
+ #endif
+
+ m_startDragFromSelectionTopLeft = m_currentPoint - selectionRect.topLeft ();
+ m_dragType = Move;
+
+ if (m_mouseButton == 0)
+ {
+ setSelectionBorderForMove ();
+ }
+ else
+ {
+ // Don't hide sel border momentarily if user is just
+ // right _clicking_ selection
+ m_RMBMoveUpdateGUITimer->start (100, true/*single shot*/);
+ }
+ }
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\t\tis new sel" << endl;
+ #endif
+
+ pushOntoDocument ();
+ }
+ }
+
+ // creating new selection?
+ if (m_dragType == Create)
+ {
+ viewManager ()->setQueueUpdates ();
+ {
+ viewManager ()->setSelectionBorderVisible (true);
+ viewManager ()->setSelectionBorderFinished (false);
+ viewManager ()->setTextCursorEnabled (false);
+ }
+ viewManager ()->restoreQueueUpdates ();
+
+ m_createNOPTimer->start (200, true/*single shot*/);
+ }
+
+ if (m_dragType != SelectText)
+ {
+ setUserMessage (cancelUserMessage ());
+ }
+}
+
+
+// protected
+const QCursor &kpToolSelection::cursor () const
+{
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "kpToolSelection::cursor()"
+ << " m_currentPoint=" << m_currentPoint
+ << " QCursor::pos() view under cursor="
+ << (viewUnderCursor () ?
+ viewUnderCursor ()->mapFromGlobal (QCursor::pos ()) :
+ KP_INVALID_POINT)
+ << " controlOrShiftPressed=" << controlOrShiftPressed ()
+ << endl;
+#endif
+
+ kpSelection *sel = document () ? document ()->selection () : 0;
+
+ if (sel && onSelectionResizeHandle () && !controlOrShiftPressed ())
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\tonSelectionResizeHandle="
+ << onSelectionResizeHandle () << endl;
+ #endif
+ switch (onSelectionResizeHandle ())
+ {
+ case (kpView::Top | kpView::Left):
+ case (kpView::Bottom | kpView::Right):
+ return Qt::sizeFDiagCursor;
+
+ case (kpView::Bottom | kpView::Left):
+ case (kpView::Top | kpView::Right):
+ return Qt::sizeBDiagCursor;
+
+ case kpView::Top:
+ case kpView::Bottom:
+ return Qt::sizeVerCursor;
+
+ case kpView::Left:
+ case kpView::Right:
+ return Qt::sizeHorCursor;
+ }
+
+ return Qt::arrowCursor;
+ }
+ else if (sel && sel->contains (m_currentPoint))
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\tsel contains currentPoint; selecting text? "
+ << onSelectionToSelectText () << endl;
+ #endif
+
+ if (m_mode == Text && onSelectionToSelectText () && !controlOrShiftPressed ())
+ return Qt::ibeamCursor;
+ else
+ return Qt::sizeAllCursor;
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\tnot on sel" << endl;
+ #endif
+ return Qt::crossCursor;
+ }
+}
+
+// virtual
+void kpToolSelection::hover (const QPoint &point)
+{
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "kpToolSelection::hover" << point << endl;
+#endif
+
+ viewManager ()->setCursor (cursor ());
+
+ setUserShapePoints (point, KP_INVALID_POINT, false/*don't set size*/);
+ if (document () && document ()->selection ())
+ {
+ setUserShapeSize (document ()->selection ()->width (),
+ document ()->selection ()->height ());
+ }
+ else
+ {
+ setUserShapeSize (KP_INVALID_SIZE);
+ }
+
+ QString mess = haventBegunDrawUserMessage ();
+ if (mess != userMessage ())
+ setUserMessage (mess);
+}
+
+// protected
+void kpToolSelection::popupRMBMenu ()
+{
+ QPopupMenu *pop = mainWindow () ? mainWindow ()->selectionToolRMBMenu () : 0;
+ if (!pop)
+ return;
+
+ // WARNING: enters event loop - may re-enter view/tool event handlers
+ pop->exec (QCursor::pos ());
+
+ // Cursor may have moved while menu up, triggering mouseMoveEvents
+ // for the menu - not the view. Update cursor position now.
+ somethingBelowTheCursorChanged ();
+}
+
+// protected
+void kpToolSelection::setSelectionBorderForMove ()
+{
+ // don't show border while moving
+ viewManager ()->setQueueUpdates ();
+ {
+ viewManager ()->setSelectionBorderVisible (false);
+ viewManager ()->setSelectionBorderFinished (true);
+ viewManager ()->setTextCursorEnabled (false);
+ }
+ viewManager ()->restoreQueueUpdates ();
+}
+
+// protected slot
+void kpToolSelection::slotRMBMoveUpdateGUI ()
+{
+ // (just in case not called from single shot)
+ m_RMBMoveUpdateGUITimer->stop ();
+
+ setSelectionBorderForMove ();
+
+ kpSelection * const sel = document () ? document ()->selection () : 0;
+ if (sel)
+ setUserShapePoints (sel->topLeft ());
+}
+
+// protected slot
+void kpToolSelection::delayedDraw ()
+{
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "kpToolSelection::delayedDraw() hasBegunDraw="
+ << hasBegunDraw ()
+ << " currentPoint=" << m_currentPoint
+ << " lastPoint=" << m_lastPoint
+ << " startPoint=" << m_startPoint
+ << endl;
+#endif
+
+ // (just in case not called from single shot)
+ m_createNOPTimer->stop ();
+
+ if (hasBegunDraw ())
+ {
+ draw (m_currentPoint, m_lastPoint,
+ QRect (m_startPoint, m_currentPoint).normalize ());
+ }
+}
+
+// virtual
+void kpToolSelection::draw (const QPoint &inThisPoint, const QPoint & /*lastPoint*/,
+ const QRect &inNormalizedRect)
+{
+ QPoint thisPoint = inThisPoint;
+ QRect normalizedRect = inNormalizedRect;
+
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "kpToolSelection::draw" << thisPoint
+ << " startPoint=" << m_startPoint
+ << " normalizedRect=" << normalizedRect << endl;
+#endif
+
+
+ // OPT: return when thisPoint == m_lastPoint so that e.g. when creating
+ // Points sel, press modifiers doesn't add multiple points in same
+ // place
+
+
+ bool nextDragHasBegun = true;
+
+
+ if (m_dragType == Create)
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\tnot moving - resizing rect to" << normalizedRect
+ << endl;
+ kdDebug () << "\t\tcreateNOPTimer->isActive()="
+ << m_createNOPTimer->isActive ()
+ << " viewManhattanLength from startPoint="
+ << m_viewUnderStartPoint->transformDocToViewX ((thisPoint - m_startPoint).manhattanLength ())
+ << endl;
+ #endif
+
+ if (m_createNOPTimer->isActive ())
+ {
+ if (m_viewUnderStartPoint->transformDocToViewX ((thisPoint - m_startPoint).manhattanLength ()) <= 6)
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\t\tsuppress accidental movement" << endl;
+ #endif
+ thisPoint = m_startPoint;
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\t\tit's a \"big\" intended move - stop timer" << endl;
+ #endif
+ m_createNOPTimer->stop ();
+ }
+ }
+
+
+ // Prevent unintentional 1-pixel selections
+ if (!m_dragHasBegun && thisPoint == m_startPoint)
+ {
+ if (m_mode != kpToolSelection::Text)
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\tnon-text NOP - return" << endl;
+ #endif
+ setUserShapePoints (thisPoint);
+ return;
+ }
+ else // m_mode == kpToolSelection::Text
+ {
+ // Attempt to deselect text box by clicking?
+ if (m_hadSelectionBeforeDrag)
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\ttext box deselect - NOP - return" << endl;
+ #endif
+ setUserShapePoints (thisPoint);
+ return;
+ }
+
+ // Drag-wise, this is a NOP so we'd normally return (hence
+ // m_dragHasBegun would not change). However, as a special
+ // case, allow user to create a text box using a single
+ // click. But don't set m_dragHasBegun for next iteration
+ // since it would be untrue.
+ //
+ // This makes sure that a single click creation of text box
+ // works even if draw() is invoked more than once at the
+ // same position (esp. with accidental drag suppression
+ // (above)).
+ nextDragHasBegun = false;
+ }
+ }
+
+
+ switch (m_mode)
+ {
+ case kpToolSelection::Rectangle:
+ {
+ const QRect usefulRect = normalizedRect.intersect (document ()->rect ());
+ document ()->setSelection (kpSelection (kpSelection::Rectangle, usefulRect,
+ mainWindow ()->selectionTransparency ()));
+
+ setUserShapePoints (m_startPoint,
+ QPoint (QMAX (0, QMIN (m_currentPoint.x (), document ()->width () - 1)),
+ QMAX (0, QMIN (m_currentPoint.y (), document ()->height () - 1))));
+ break;
+ }
+ case kpToolSelection::Text:
+ {
+ const kpTextStyle textStyle = mainWindow ()->textStyle ();
+
+ int minimumWidth, minimumHeight;
+
+ // Just a click?
+ if (!m_dragHasBegun && thisPoint == m_startPoint)
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\tclick creating text box" << endl;
+ #endif
+
+ // (Click creating text box with RMB would not be obvious
+ // since RMB menu most likely hides text box immediately
+ // afterwards)
+ if (m_mouseButton == 1)
+ break;
+
+
+ minimumWidth = kpSelection::preferredMinimumWidthForTextStyle (textStyle);
+ if (thisPoint.x () >= m_startPoint.x ())
+ {
+ if (m_startPoint.x () + minimumWidth - 1 >= document ()->width ())
+ {
+ minimumWidth = QMAX (kpSelection::minimumWidthForTextStyle (textStyle),
+ document ()->width () - m_startPoint.x ());
+ }
+ }
+ else
+ {
+ if (m_startPoint.x () - minimumWidth + 1 < 0)
+ {
+ minimumWidth = QMAX (kpSelection::minimumWidthForTextStyle (textStyle),
+ m_startPoint.x () + 1);
+ }
+ }
+
+ minimumHeight = kpSelection::preferredMinimumHeightForTextStyle (textStyle);
+ if (thisPoint.y () >= m_startPoint.y ())
+ {
+ if (m_startPoint.y () + minimumHeight - 1 >= document ()->height ())
+ {
+ minimumHeight = QMAX (kpSelection::minimumHeightForTextStyle (textStyle),
+ document ()->height () - m_startPoint.y ());
+ }
+ }
+ else
+ {
+ if (m_startPoint.y () - minimumHeight + 1 < 0)
+ {
+ minimumHeight = QMAX (kpSelection::minimumHeightForTextStyle (textStyle),
+ m_startPoint.y () + 1);
+ }
+ }
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\tdrag creating text box" << endl;
+ #endif
+ minimumWidth = kpSelection::minimumWidthForTextStyle (textStyle);
+ minimumHeight = kpSelection::minimumHeightForTextStyle (textStyle);
+ }
+
+
+ if (normalizedRect.width () < minimumWidth)
+ {
+ if (thisPoint.x () >= m_startPoint.x ())
+ normalizedRect.setWidth (minimumWidth);
+ else
+ normalizedRect.setX (normalizedRect.right () - minimumWidth + 1);
+ }
+
+ if (normalizedRect.height () < minimumHeight)
+ {
+ if (thisPoint.y () >= m_startPoint.y ())
+ normalizedRect.setHeight (minimumHeight);
+ else
+ normalizedRect.setY (normalizedRect.bottom () - minimumHeight + 1);
+ }
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\t\tnormalizedRect=" << normalizedRect
+ << " kpSelection::preferredMinimumSize="
+ << QSize (minimumWidth, minimumHeight)
+ << endl;
+ #endif
+
+ QValueVector <QString> textLines (1, QString ());
+ kpSelection sel (normalizedRect, textLines, textStyle);
+
+ if (!m_currentCreateTextCommand)
+ {
+ m_currentCreateTextCommand = new kpToolSelectionCreateCommand (
+ i18n ("Text: Create Box"),
+ sel,
+ mainWindow ());
+ }
+ else
+ m_currentCreateTextCommand->setFromSelection (sel);
+
+ viewManager ()->setTextCursorPosition (0, 0);
+ document ()->setSelection (sel);
+
+ QPoint actualEndPoint = KP_INVALID_POINT;
+ if (m_startPoint == normalizedRect.topLeft ())
+ actualEndPoint = normalizedRect.bottomRight ();
+ else if (m_startPoint == normalizedRect.bottomRight ())
+ actualEndPoint = normalizedRect.topLeft ();
+ else if (m_startPoint == normalizedRect.topRight ())
+ actualEndPoint = normalizedRect.bottomLeft ();
+ else if (m_startPoint == normalizedRect.bottomLeft ())
+ actualEndPoint = normalizedRect.topRight ();
+
+ setUserShapePoints (m_startPoint, actualEndPoint);
+ break;
+ }
+ case kpToolSelection::Ellipse:
+ document ()->setSelection (kpSelection (kpSelection::Ellipse, normalizedRect,
+ mainWindow ()->selectionTransparency ()));
+ setUserShapePoints (m_startPoint, m_currentPoint);
+ break;
+ case kpToolSelection::FreeForm:
+ QPointArray points;
+
+ if (document ()->selection ())
+ points = document ()->selection ()->points ();
+
+
+ // (not detached so will modify "points" directly but
+ // still need to call kpDocument::setSelection() to
+ // update screen)
+
+ if (!m_dragHasBegun)
+ {
+ // We thought the drag at startPoint was a NOP
+ // but it turns out that it wasn't...
+ points.putPoints (points.count (), 1, m_startPoint.x (), m_startPoint.y ());
+ }
+
+ // TODO: there should be an upper limit on this before drawing the
+ // polygon becomes too slow
+ points.putPoints (points.count (), 1, thisPoint.x (), thisPoint.y ());
+
+
+ document ()->setSelection (kpSelection (points, mainWindow ()->selectionTransparency ()));
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\t\tfreeform; #points=" << document ()->selection ()->points ().count () << endl;
+ #endif
+
+ setUserShapePoints (m_currentPoint);
+ break;
+ }
+
+ viewManager ()->setSelectionBorderVisible (true);
+ }
+ else if (m_dragType == Move)
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\tmoving selection" << endl;
+ #endif
+
+ kpSelection *sel = document ()->selection ();
+
+ QRect targetSelRect = QRect (thisPoint.x () - m_startDragFromSelectionTopLeft.x (),
+ thisPoint.y () - m_startDragFromSelectionTopLeft.y (),
+ sel->width (),
+ sel->height ());
+
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\t\tstartPoint=" << m_startPoint
+ << " thisPoint=" << thisPoint
+ << " startDragFromSel=" << m_startDragFromSelectionTopLeft
+ << " targetSelRect=" << targetSelRect
+ << endl;
+ #endif
+
+ // Try to make sure selection still intersects document so that it's
+ // reachable.
+
+ if (targetSelRect.right () < 0)
+ targetSelRect.moveBy (-targetSelRect.right (), 0);
+ else if (targetSelRect.left () >= document ()->width ())
+ targetSelRect.moveBy (document ()->width () - targetSelRect.left () - 1, 0);
+
+ if (targetSelRect.bottom () < 0)
+ targetSelRect.moveBy (0, -targetSelRect.bottom ());
+ else if (targetSelRect.top () >= document ()->height ())
+ targetSelRect.moveBy (0, document ()->height () - targetSelRect.top () - 1);
+
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\t\t\tafter ensure sel rect clickable=" << targetSelRect << endl;
+ #endif
+
+
+ if (!m_dragHasBegun &&
+ targetSelRect.topLeft () + m_startDragFromSelectionTopLeft == m_startPoint)
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\t\t\t\tnop" << endl;
+ #endif
+
+
+ if (!m_RMBMoveUpdateGUITimer->isActive ())
+ {
+ // (slotRMBMoveUpdateGUI() calls similar line)
+ setUserShapePoints (sel->topLeft ());
+ }
+
+ // Prevent both NOP drag-moves
+ return;
+ }
+
+
+ if (m_RMBMoveUpdateGUITimer->isActive ())
+ {
+ m_RMBMoveUpdateGUITimer->stop ();
+ slotRMBMoveUpdateGUI ();
+ }
+
+
+ if (!sel->pixmap () && !m_currentPullFromDocumentCommand)
+ {
+ m_currentPullFromDocumentCommand = new kpToolSelectionPullFromDocumentCommand (
+ QString::null/*uninteresting child of macro cmd*/,
+ mainWindow ());
+ m_currentPullFromDocumentCommand->execute ();
+ }
+
+ if (!m_currentMoveCommand)
+ {
+ m_currentMoveCommand = new kpToolSelectionMoveCommand (
+ QString::null/*uninteresting child of macro cmd*/,
+ mainWindow ());
+ m_currentMoveCommandIsSmear = false;
+ }
+
+
+ //viewManager ()->setQueueUpdates ();
+ //viewManager ()->setFastUpdates ();
+
+ if (m_shiftPressed)
+ m_currentMoveCommandIsSmear = true;
+
+ if (!m_dragHasBegun && (m_controlPressed || m_shiftPressed))
+ m_currentMoveCommand->copyOntoDocument ();
+
+ m_currentMoveCommand->moveTo (targetSelRect.topLeft ());
+
+ if (m_shiftPressed)
+ m_currentMoveCommand->copyOntoDocument ();
+
+ //viewManager ()->restoreFastUpdates ();
+ //viewManager ()->restoreQueueUpdates ();
+
+ QPoint start = m_currentMoveCommand->originalSelection ().topLeft ();
+ QPoint end = targetSelRect.topLeft ();
+ setUserShapePoints (start, end, false/*don't set size*/);
+ setUserShapeSize (end.x () - start.x (), end.y () - start.y ());
+ }
+ else if (m_dragType == ResizeScale)
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\tresize/scale" << endl;
+ #endif
+
+ kpSelection *sel = document ()->selection ();
+
+ if (!m_dragHasBegun && thisPoint == m_startPoint)
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\t\tnop" << endl;
+ #endif
+
+ setUserShapePoints (QPoint (sel->width (), sel->height ()));
+ return;
+ }
+
+
+ if (!sel->pixmap () && !m_currentPullFromDocumentCommand)
+ {
+ m_currentPullFromDocumentCommand = new kpToolSelectionPullFromDocumentCommand (
+ QString::null/*uninteresting child of macro cmd*/,
+ mainWindow ());
+ m_currentPullFromDocumentCommand->execute ();
+ }
+
+ if (!m_currentResizeScaleCommand)
+ {
+ m_currentResizeScaleCommand = new kpToolSelectionResizeScaleCommand (mainWindow ());
+ }
+
+
+ kpSelection originalSelection = m_currentResizeScaleCommand->originalSelection ();
+ const int oldWidth = originalSelection.width ();
+ const int oldHeight = originalSelection.height ();
+
+
+ // Determine new width.
+
+ int userXSign = 0;
+ if (m_resizeScaleType & kpView::Left)
+ userXSign = -1;
+ else if (m_resizeScaleType & kpView::Right)
+ userXSign = +1;
+
+ int newWidth = oldWidth + userXSign * (thisPoint.x () - m_startPoint.x ());
+
+ newWidth = QMAX (originalSelection.minimumWidth (), newWidth);
+
+
+ // Determine new height.
+
+ int userYSign = 0;
+ if (m_resizeScaleType & kpView::Top)
+ userYSign = -1;
+ else if (m_resizeScaleType & kpView::Bottom)
+ userYSign = +1;
+
+ int newHeight = oldHeight + userYSign * (thisPoint.y () - m_startPoint.y ());
+
+ newHeight = QMAX (originalSelection.minimumHeight (), newHeight);
+
+
+ // Keep aspect ratio?
+ if (m_shiftPressed && !sel->isText ())
+ {
+ // Width changed more than height? At equality, favour width.
+ // Fix width, change height.
+ if ((userXSign ? double (newWidth) / oldWidth : 0) >=
+ (userYSign ? double (newHeight) / oldHeight : 0))
+ {
+ newHeight = newWidth * oldHeight / oldWidth;
+ newHeight = QMAX (originalSelection.minimumHeight (),
+ newHeight);
+ }
+ // Height changed more than width?
+ // Fix height, change width.
+ else
+ {
+ newWidth = newHeight * oldWidth / oldHeight;
+ newWidth = QMAX (originalSelection.minimumWidth (), newWidth);
+ }
+ }
+
+
+ // Adjust x/y to new width/height for left/top resizes.
+
+ int newX = originalSelection.x ();
+ int newY = originalSelection.y ();
+
+ if (m_resizeScaleType & kpView::Left)
+ {
+ newX -= (newWidth - originalSelection.width ());
+ }
+
+ if (m_resizeScaleType & kpView::Top)
+ {
+ newY -= (newHeight - originalSelection.height ());
+ }
+
+ #if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\t\tnewX=" << newX
+ << " newY=" << newY
+ << " newWidth=" << newWidth
+ << " newHeight=" << newHeight
+ << endl;
+ #endif
+
+
+ viewManager ()->setFastUpdates ();
+ m_currentResizeScaleCommand->resizeAndMoveTo (newWidth, newHeight,
+ QPoint (newX, newY),
+ true/*smooth scale delayed*/);
+ viewManager ()->restoreFastUpdates ();
+
+ setUserShapePoints (QPoint (originalSelection.width (),
+ originalSelection.height ()),
+ QPoint (newWidth,
+ newHeight),
+ false/*don't set size*/);
+ setUserShapeSize (newWidth - originalSelection.width (),
+ newHeight - originalSelection.height ());
+ }
+
+
+ m_dragHasBegun = nextDragHasBegun;
+}
+
+// virtual
+void kpToolSelection::cancelShape ()
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelection::cancelShape() mouseButton=" << m_mouseButton << endl;
+#endif
+
+ m_createNOPTimer->stop ();
+ m_RMBMoveUpdateGUITimer->stop ();
+
+
+ viewManager ()->setQueueUpdates ();
+ {
+ if (m_dragType == Move)
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\twas drag moving - undo drag and undo acquire" << endl;
+ #endif
+
+ if (m_currentMoveCommand)
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\t\tundo currentMoveCommand" << endl;
+ #endif
+ m_currentMoveCommand->finalize ();
+ m_currentMoveCommand->unexecute ();
+ delete m_currentMoveCommand;
+ m_currentMoveCommand = 0;
+
+ if (document ()->selection ()->isText ())
+ viewManager ()->setTextCursorBlinkState (true);
+ }
+ }
+ else if (m_dragType == Create)
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\twas creating sel - kill" << endl;
+ #endif
+
+ // TODO: should we give the user back the selection s/he had before (if any)?
+ document ()->selectionDelete ();
+
+ if (m_currentCreateTextCommand)
+ {
+ delete m_currentCreateTextCommand;
+ m_currentCreateTextCommand = 0;
+ }
+ }
+ else if (m_dragType == ResizeScale)
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\twas resize/scale sel - kill" << endl;
+ #endif
+
+ if (m_currentResizeScaleCommand)
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\t\tundo currentResizeScaleCommand" << endl;
+ #endif
+ m_currentResizeScaleCommand->finalize (); // (unneeded but let's be safe)
+ m_currentResizeScaleCommand->unexecute ();
+ delete m_currentResizeScaleCommand;
+ m_currentResizeScaleCommand = 0;
+
+ if (document ()->selection ()->isText ())
+ viewManager ()->setTextCursorBlinkState (true);
+ }
+ }
+
+
+ if (m_currentPullFromDocumentCommand)
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\t\tundo pullFromDocumentCommand" << endl;
+ #endif
+ m_currentPullFromDocumentCommand->unexecute ();
+ delete m_currentPullFromDocumentCommand;
+ m_currentPullFromDocumentCommand = 0;
+ }
+
+
+ viewManager ()->setSelectionBorderVisible (true);
+ viewManager ()->setSelectionBorderFinished (true);
+ viewManager ()->setTextCursorEnabled (m_mode == Text && true);
+ }
+ viewManager ()->restoreQueueUpdates ();
+
+
+ m_dragType = Unknown;
+ m_cancelledShapeButStillHoldingButtons = true;
+ setUserMessage (i18n ("Let go of all the mouse buttons."));
+}
+
+// virtual
+void kpToolSelection::releasedAllButtons ()
+{
+ m_cancelledShapeButStillHoldingButtons = false;
+ setUserMessage (haventBegunDrawUserMessage ());
+}
+
+// virtual
+void kpToolSelection::endDraw (const QPoint & /*thisPoint*/, const QRect & /*normalizedRect*/)
+{
+ m_createNOPTimer->stop ();
+ m_RMBMoveUpdateGUITimer->stop ();
+
+
+ viewManager ()->setQueueUpdates ();
+ {
+ if (m_currentCreateTextCommand)
+ {
+ commandHistory ()->addCommand (m_currentCreateTextCommand, false/*no exec*/);
+ m_currentCreateTextCommand = 0;
+ }
+
+ kpMacroCommand *cmd = 0;
+ if (m_currentMoveCommand)
+ {
+ if (m_currentMoveCommandIsSmear)
+ {
+ cmd = new kpMacroCommand (i18n ("%1: Smear")
+ .arg (document ()->selection ()->name ()),
+ mainWindow ());
+ }
+ else
+ {
+ cmd = new kpMacroCommand ((document ()->selection ()->isText () ?
+ i18n ("Text: Move Box") :
+ i18n ("Selection: Move")),
+ mainWindow ());
+ }
+
+ if (document ()->selection ()->isText ())
+ viewManager ()->setTextCursorBlinkState (true);
+ }
+ else if (m_currentResizeScaleCommand)
+ {
+ cmd = new kpMacroCommand (m_currentResizeScaleCommand->kpNamedCommand::name (),
+ mainWindow ());
+
+ if (document ()->selection ()->isText ())
+ viewManager ()->setTextCursorBlinkState (true);
+ }
+
+ if (m_currentPullFromDocumentCommand)
+ {
+ if (!m_currentMoveCommand && !m_currentResizeScaleCommand)
+ {
+ kdError () << "kpToolSelection::endDraw() pull without move nor resize/scale" << endl;
+ delete m_currentPullFromDocumentCommand;
+ m_currentPullFromDocumentCommand = 0;
+ }
+ else
+ {
+ kpSelection selection;
+
+ if (m_currentMoveCommand)
+ selection = m_currentMoveCommand->originalSelection ();
+ else if (m_currentResizeScaleCommand)
+ selection = m_currentResizeScaleCommand->originalSelection ();
+
+ // just the border
+ selection.setPixmap (QPixmap ());
+
+ kpCommand *createCommand = new kpToolSelectionCreateCommand (
+ i18n ("Selection: Create"),
+ selection,
+ mainWindow ());
+
+ if (kpToolSelectionCreateCommand::nextUndoCommandIsCreateBorder (commandHistory ()))
+ commandHistory ()->setNextUndoCommand (createCommand);
+ else
+ commandHistory ()->addCommand (createCommand,
+ false/*no exec - user already dragged out sel*/);
+
+
+ cmd->addCommand (m_currentPullFromDocumentCommand);
+ m_currentPullFromDocumentCommand = 0;
+ }
+ }
+
+ if (m_currentMoveCommand)
+ {
+ m_currentMoveCommand->finalize ();
+ cmd->addCommand (m_currentMoveCommand);
+ m_currentMoveCommand = 0;
+
+ if (document ()->selection ()->isText ())
+ viewManager ()->setTextCursorBlinkState (true);
+ }
+
+ if (m_currentResizeScaleCommand)
+ {
+ m_currentResizeScaleCommand->finalize ();
+ cmd->addCommand (m_currentResizeScaleCommand);
+ m_currentResizeScaleCommand = 0;
+
+ if (document ()->selection ()->isText ())
+ viewManager ()->setTextCursorBlinkState (true);
+ }
+
+ if (cmd)
+ commandHistory ()->addCommand (cmd, false/*no exec*/);
+
+ viewManager ()->setSelectionBorderVisible (true);
+ viewManager ()->setSelectionBorderFinished (true);
+ viewManager ()->setTextCursorEnabled (m_mode == Text && true);
+ }
+ viewManager ()->restoreQueueUpdates ();
+
+
+ m_dragType = Unknown;
+ setUserMessage (haventBegunDrawUserMessage ());
+
+
+ if (m_mouseButton == 1/*right*/)
+ popupRMBMenu ();
+}
+
+
+// protected virtual [base kpTool]
+void kpToolSelection::keyPressEvent (QKeyEvent *e)
+{
+#if DEBUG_KP_TOOL_SELECTION && 0
+ kdDebug () << "kpToolSelection::keyPressEvent(e->text='" << e->text () << "')" << endl;
+#endif
+
+
+ e->ignore ();
+
+
+ if (document ()->selection () &&
+ !hasBegunDraw () &&
+ e->key () == Qt::Key_Escape)
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 0
+ kdDebug () << "\tescape pressed with sel when not begun draw - deselecting" << endl;
+ #endif
+
+ pushOntoDocument ();
+ e->accept ();
+ }
+
+
+ if (!e->isAccepted ())
+ {
+ #if DEBUG_KP_TOOL_SELECTION && 0
+ kdDebug () << "\tkey processing did not accept (text was '"
+ << e->text ()
+ << "') - passing on event to kpTool"
+ << endl;
+ #endif
+
+ kpTool::keyPressEvent (e);
+ return;
+ }
+}
+
+
+// private slot
+void kpToolSelection::selectionTransparencyChanged (const QString & /*name*/)
+{
+#if 0
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelection::selectionTransparencyChanged(" << name << ")" << endl;
+#endif
+
+ if (mainWindow ()->settingSelectionTransparency ())
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\trecursion - abort setting selection transparency: "
+ << mainWindow ()->settingSelectionTransparency () << endl;
+ #endif
+ return;
+ }
+
+ if (document ()->selection ())
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\thave sel - set transparency" << endl;
+ #endif
+
+ kpSelectionTransparency oldST = document ()->selection ()->transparency ();
+ kpSelectionTransparency st = mainWindow ()->selectionTransparency ();
+
+ // TODO: This "NOP" check causes us a great deal of trouble e.g.:
+ //
+ // Select a solid red rectangle.
+ // Switch to transparent and set red as the background colour.
+ // (the selection is now invisible)
+ // Invert Colours.
+ // (the selection is now cyan)
+ // Change the background colour to green.
+ // (no command is added to undo this as the selection does not change)
+ // Undo.
+ // The rectangle is no longer invisible.
+ //
+ //if (document ()->selection ()->setTransparency (st, true/*check harder for no change in mask*/))
+
+ document ()->selection ()->setTransparency (st);
+ if (true)
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\t\twhich changed the pixmap" << endl;
+ #endif
+
+ commandHistory ()->addCommand (new kpToolSelectionTransparencyCommand (
+ i18n ("Selection: Transparency"), // name,
+ st, oldST,
+ mainWindow ()),
+ false/* no exec*/);
+ }
+ }
+#endif
+
+ // TODO: I've duplicated the code (see below 3x) to make sure
+ // kpSelectionTransparency(oldST)::transparentColor() is defined
+ // and not taken from kpDocument (where it may not be defined because
+ // the transparency may be opaque).
+ //
+ // That way kpToolSelectionTransparencyCommand can force set colours.
+}
+
+
+// protected slot virtual
+void kpToolSelection::slotIsOpaqueChanged ()
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelection::slotIsOpaqueChanged()" << endl;
+#endif
+
+ if (mainWindow ()->settingSelectionTransparency ())
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\trecursion - abort setting selection transparency: "
+ << mainWindow ()->settingSelectionTransparency () << endl;
+ #endif
+ return;
+ }
+
+ if (document ()->selection ())
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\thave sel - set transparency" << endl;
+ #endif
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ if (hasBegunShape ())
+ endShapeInternal ();
+
+ kpSelectionTransparency st = mainWindow ()->selectionTransparency ();
+ kpSelectionTransparency oldST = st;
+ oldST.setOpaque (!oldST.isOpaque ());
+
+ document ()->selection ()->setTransparency (st);
+ commandHistory ()->addCommand (new kpToolSelectionTransparencyCommand (
+ st.isOpaque () ?
+ i18n ("Selection: Opaque") :
+ i18n ("Selection: Transparent"),
+ st, oldST,
+ mainWindow ()),
+ false/* no exec*/);
+
+ QApplication::restoreOverrideCursor ();
+ }
+}
+
+// protected slot virtual [base kpTool]
+void kpToolSelection::slotBackgroundColorChanged (const kpColor &)
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelection::slotBackgroundColorChanged()" << endl;
+#endif
+
+ if (mainWindow ()->settingSelectionTransparency ())
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\trecursion - abort setting selection transparency: "
+ << mainWindow ()->settingSelectionTransparency () << endl;
+ #endif
+ return;
+ }
+
+ if (document ()->selection ())
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\thave sel - set transparency" << endl;
+ #endif
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ kpSelectionTransparency st = mainWindow ()->selectionTransparency ();
+ kpSelectionTransparency oldST = st;
+ oldST.setTransparentColor (oldBackgroundColor ());
+
+ document ()->selection ()->setTransparency (st);
+ commandHistory ()->addCommand (new kpToolSelectionTransparencyCommand (
+ i18n ("Selection: Transparency Color"),
+ st, oldST,
+ mainWindow ()),
+ false/* no exec*/);
+
+ QApplication::restoreOverrideCursor ();
+ }
+}
+
+// protected slot virtual [base kpTool]
+void kpToolSelection::slotColorSimilarityChanged (double, int)
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelection::slotColorSimilarityChanged()" << endl;
+#endif
+
+ if (mainWindow ()->settingSelectionTransparency ())
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\trecursion - abort setting selection transparency: "
+ << mainWindow ()->settingSelectionTransparency () << endl;
+ #endif
+ return;
+ }
+
+ if (document ()->selection ())
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\thave sel - set transparency" << endl;
+ #endif
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ kpSelectionTransparency st = mainWindow ()->selectionTransparency ();
+ kpSelectionTransparency oldST = st;
+ oldST.setColorSimilarity (oldColorSimilarity ());
+
+ document ()->selection ()->setTransparency (st);
+ commandHistory ()->addCommand (new kpToolSelectionTransparencyCommand (
+ i18n ("Selection: Transparency Color Similarity"),
+ st, oldST,
+ mainWindow ()),
+ false/* no exec*/);
+
+ QApplication::restoreOverrideCursor ();
+ }
+}
+
+
+/*
+ * kpToolSelectionCreateCommand
+ */
+
+kpToolSelectionCreateCommand::kpToolSelectionCreateCommand (const QString &name,
+ const kpSelection &fromSelection,
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow),
+ m_fromSelection (0),
+ m_textRow (0), m_textCol (0)
+{
+ setFromSelection (fromSelection);
+}
+
+kpToolSelectionCreateCommand::~kpToolSelectionCreateCommand ()
+{
+ delete m_fromSelection;
+}
+
+
+// public virtual [base kpCommand]
+int kpToolSelectionCreateCommand::size () const
+{
+ return kpPixmapFX::selectionSize (m_fromSelection);
+}
+
+
+// public static
+bool kpToolSelectionCreateCommand::nextUndoCommandIsCreateBorder (
+ kpCommandHistory *commandHistory)
+{
+ if (!commandHistory)
+ return false;
+
+ kpCommand *cmd = commandHistory->nextUndoCommand ();
+ if (!cmd)
+ return false;
+
+ kpToolSelectionCreateCommand *c = dynamic_cast <kpToolSelectionCreateCommand *> (cmd);
+ if (!c)
+ return false;
+
+ const kpSelection *sel = c->fromSelection ();
+ if (!sel)
+ return false;
+
+ return (!sel->pixmap ());
+}
+
+
+// public
+const kpSelection *kpToolSelectionCreateCommand::fromSelection () const
+{
+ return m_fromSelection;
+}
+
+// public
+void kpToolSelectionCreateCommand::setFromSelection (const kpSelection &fromSelection)
+{
+ delete m_fromSelection;
+ m_fromSelection = new kpSelection (fromSelection);
+}
+
+// public virtual [base kpCommand]
+void kpToolSelectionCreateCommand::execute ()
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelectionCreateCommand::execute()" << endl;
+#endif
+
+ kpDocument *doc = document ();
+ if (!doc)
+ {
+ kdError () << "kpToolSelectionCreateCommand::execute() without doc" << endl;
+ return;
+ }
+
+ if (m_fromSelection)
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\tusing fromSelection" << endl;
+ kdDebug () << "\t\thave sel=" << doc->selection ()
+ << " pixmap=" << (doc->selection () ? doc->selection ()->pixmap () : 0)
+ << endl;
+ #endif
+ if (!m_fromSelection->isText ())
+ {
+ if (m_fromSelection->transparency () != m_mainWindow->selectionTransparency ())
+ m_mainWindow->setSelectionTransparency (m_fromSelection->transparency ());
+ }
+ else
+ {
+ if (m_fromSelection->textStyle () != m_mainWindow->textStyle ())
+ m_mainWindow->setTextStyle (m_fromSelection->textStyle ());
+ }
+
+ m_mainWindow->viewManager ()->setTextCursorPosition (m_textRow, m_textCol);
+ doc->setSelection (*m_fromSelection);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+}
+
+// public virtual [base kpCommand]
+void kpToolSelectionCreateCommand::unexecute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ {
+ kdError () << "kpToolSelectionCreateCommand::unexecute() without doc" << endl;
+ return;
+ }
+
+ if (!doc->selection ())
+ {
+ // Was just a border that got deselected?
+ if (m_fromSelection && !m_fromSelection->pixmap ())
+ return;
+
+ kdError () << "kpToolSelectionCreateCommand::unexecute() without sel region" << endl;
+ return;
+ }
+
+ m_textRow = m_mainWindow->viewManager ()->textCursorRow ();
+ m_textCol = m_mainWindow->viewManager ()->textCursorCol ();
+
+ doc->selectionDelete ();
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+}
+
+
+/*
+ * kpToolSelectionPullFromDocumentCommand
+ */
+
+kpToolSelectionPullFromDocumentCommand::kpToolSelectionPullFromDocumentCommand (const QString &name,
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow),
+ m_backgroundColor (mainWindow ? mainWindow->backgroundColor () : kpColor::invalid),
+ m_originalSelectionRegion (0)
+{
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "kpToolSelectionPullFromDocumentCommand::<ctor>() mainWindow="
+ << m_mainWindow
+ << endl;
+#endif
+}
+
+kpToolSelectionPullFromDocumentCommand::~kpToolSelectionPullFromDocumentCommand ()
+{
+ delete m_originalSelectionRegion;
+}
+
+
+// public virtual [base kpCommand]
+int kpToolSelectionPullFromDocumentCommand::size () const
+{
+ return kpPixmapFX::selectionSize (m_originalSelectionRegion);
+}
+
+
+// public virtual [base kpCommand]
+void kpToolSelectionPullFromDocumentCommand::execute ()
+{
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "kpToolSelectionPullFromDocumentCommand::execute()" << endl;
+#endif
+
+ kpDocument *doc = document ();
+
+ if (!doc)
+ {
+ kdError () << "kpToolSelectionPullFromDocumentCommand::execute() without doc" << endl;
+ return;
+ }
+
+ kpViewManager *vm = m_mainWindow ? m_mainWindow->viewManager () : 0;
+ if (vm)
+ vm->setQueueUpdates ();
+
+ // In case the user CTRL+Z'ed, selected a random region to throw us off
+ // and then CTRL+Shift+Z'ed putting us here. Make sure we pull from the
+ // originally requested region - not the random one.
+ if (m_originalSelectionRegion)
+ {
+ if (m_originalSelectionRegion->transparency () != m_mainWindow->selectionTransparency ())
+ m_mainWindow->setSelectionTransparency (m_originalSelectionRegion->transparency ());
+
+ doc->setSelection (*m_originalSelectionRegion);
+ }
+ else
+ {
+ // must have selection region but not pixmap
+ if (!doc->selection () || doc->selection ()->pixmap ())
+ {
+ kdError () << "kpToolSelectionPullFromDocumentCommand::execute() sel="
+ << doc->selection ()
+ << " pixmap="
+ << (doc->selection () ? doc->selection ()->pixmap () : 0)
+ << endl;
+ if (vm)
+ vm->restoreQueueUpdates ();
+ return;
+ }
+ }
+
+ doc->selectionPullFromDocument (m_backgroundColor);
+
+ if (vm)
+ vm->restoreQueueUpdates ();
+}
+
+// public virtual [base kpCommand]
+void kpToolSelectionPullFromDocumentCommand::unexecute ()
+{
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "kpToolSelectionPullFromDocumentCommand::unexecute()" << endl;
+#endif
+
+ kpDocument *doc = document ();
+
+ if (!doc)
+ {
+ kdError () << "kpToolSelectionPullFromDocumentCommand::unexecute() without doc" << endl;
+ return;
+ }
+
+ // must have selection pixmap
+ if (!doc->selection () || !doc->selection ()->pixmap ())
+ {
+ kdError () << "kpToolSelectionPullFromDocumentCommand::unexecute() sel="
+ << doc->selection ()
+ << " pixmap="
+ << (doc->selection () ? doc->selection ()->pixmap () : 0)
+ << endl;
+ return;
+ }
+
+
+ // We can have faith that this is the state of the selection after
+ // execute(), rather than after the user tried to throw us off by
+ // simply selecting another region as to do that, a destroy command
+ // must have been used.
+ doc->selectionCopyOntoDocument (false/*use opaque pixmap*/);
+ doc->selection ()->setPixmap (QPixmap ());
+
+ delete m_originalSelectionRegion;
+ m_originalSelectionRegion = new kpSelection (*doc->selection ());
+}
+
+
+/*
+ * kpToolSelectionTransparencyCommand
+ */
+
+kpToolSelectionTransparencyCommand::kpToolSelectionTransparencyCommand (const QString &name,
+ const kpSelectionTransparency &st,
+ const kpSelectionTransparency &oldST,
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow),
+ m_st (st),
+ m_oldST (oldST)
+{
+}
+
+kpToolSelectionTransparencyCommand::~kpToolSelectionTransparencyCommand ()
+{
+}
+
+
+// public virtual [base kpCommand]
+int kpToolSelectionTransparencyCommand::size () const
+{
+ return 0;
+}
+
+
+// public virtual [base kpCommand]
+void kpToolSelectionTransparencyCommand::execute ()
+{
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "kpToolSelectionTransparencyCommand::execute()" << endl;
+#endif
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ m_mainWindow->setSelectionTransparency (m_st, true/*force colour change*/);
+
+ if (doc->selection ())
+ doc->selection ()->setTransparency (m_st);
+
+ QApplication::restoreOverrideCursor ();
+}
+
+// public virtual [base kpCommand]
+void kpToolSelectionTransparencyCommand::unexecute ()
+{
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "kpToolSelectionTransparencyCommand::unexecute()" << endl;
+#endif
+
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ m_mainWindow->setSelectionTransparency (m_oldST, true/*force colour change*/);
+
+ if (doc->selection ())
+ doc->selection ()->setTransparency (m_oldST);
+
+ QApplication::restoreOverrideCursor ();
+}
+
+
+/*
+ * kpToolSelectionMoveCommand
+ */
+
+kpToolSelectionMoveCommand::kpToolSelectionMoveCommand (const QString &name,
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow)
+{
+ kpDocument *doc = document ();
+ if (doc && doc->selection ())
+ {
+ m_startPoint = m_endPoint = doc->selection ()->topLeft ();
+ }
+}
+
+kpToolSelectionMoveCommand::~kpToolSelectionMoveCommand ()
+{
+}
+
+
+// public
+kpSelection kpToolSelectionMoveCommand::originalSelection () const
+{
+ kpDocument *doc = document ();
+ if (!doc || !doc->selection ())
+ {
+ kdError () << "kpToolSelectionMoveCommand::originalSelection() doc="
+ << doc
+ << " sel="
+ << (doc ? doc->selection () : 0)
+ << endl;
+ return kpSelection (kpSelection::Rectangle, QRect ());
+ }
+
+ kpSelection selection = *doc->selection();
+ selection.moveTo (m_startPoint);
+
+ return selection;
+}
+
+
+// public virtual [base kpComand]
+int kpToolSelectionMoveCommand::size () const
+{
+ return kpPixmapFX::pixmapSize (m_oldDocumentPixmap) +
+ kpPixmapFX::pointArraySize (m_copyOntoDocumentPoints);
+}
+
+
+// public virtual [base kpCommand]
+void kpToolSelectionMoveCommand::execute ()
+{
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "kpToolSelectionMoveCommand::execute()" << endl;
+#endif
+
+ kpDocument *doc = document ();
+ if (!doc)
+ {
+ kdError () << "kpToolSelectionMoveCommand::execute() no doc" << endl;
+ return;
+ }
+
+ kpSelection *sel = doc->selection ();
+
+ // have to have pulled pixmap by now
+ if (!sel || !sel->pixmap ())
+ {
+ kdError () << "kpToolSelectionMoveCommand::execute() but haven't pulled pixmap yet: "
+ << "sel=" << sel << " sel->pixmap=" << (sel ? sel->pixmap () : 0)
+ << endl;
+ return;
+ }
+
+ kpViewManager *vm = m_mainWindow ? m_mainWindow->viewManager () : 0;
+
+ if (vm)
+ vm->setQueueUpdates ();
+
+ QPointArray::ConstIterator copyOntoDocumentPointsEnd = m_copyOntoDocumentPoints.end ();
+ for (QPointArray::ConstIterator it = m_copyOntoDocumentPoints.begin ();
+ it != copyOntoDocumentPointsEnd;
+ it++)
+ {
+ sel->moveTo (*it);
+ doc->selectionCopyOntoDocument ();
+ }
+
+ sel->moveTo (m_endPoint);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+
+ if (vm)
+ vm->restoreQueueUpdates ();
+}
+
+// public virtual [base kpCommand]
+void kpToolSelectionMoveCommand::unexecute ()
+{
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "kpToolSelectionMoveCommand::unexecute()" << endl;
+#endif
+
+ kpDocument *doc = document ();
+ if (!doc)
+ {
+ kdError () << "kpToolSelectionMoveCommand::unexecute() no doc" << endl;
+ return;
+ }
+
+ kpSelection *sel = doc->selection ();
+
+ // have to have pulled pixmap by now
+ if (!sel || !sel->pixmap ())
+ {
+ kdError () << "kpToolSelectionMoveCommand::unexecute() but haven't pulled pixmap yet: "
+ << "sel=" << sel << " sel->pixmap=" << (sel ? sel->pixmap () : 0)
+ << endl;
+ return;
+ }
+
+ kpViewManager *vm = m_mainWindow ? m_mainWindow->viewManager () : 0;
+
+ if (vm)
+ vm->setQueueUpdates ();
+
+ if (!m_oldDocumentPixmap.isNull ())
+ doc->setPixmapAt (m_oldDocumentPixmap, m_documentBoundingRect.topLeft ());
+#if DEBUG_KP_TOOL_SELECTION && 1
+ kdDebug () << "\tmove to startPoint=" << m_startPoint << endl;
+#endif
+ sel->moveTo (m_startPoint);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+
+ if (vm)
+ vm->restoreQueueUpdates ();
+}
+
+// public
+void kpToolSelectionMoveCommand::moveTo (const QPoint &point, bool moveLater)
+{
+#if DEBUG_KP_TOOL_SELECTION && 0
+ kdDebug () << "kpToolSelectionMoveCommand::moveTo" << point
+ << " moveLater=" << moveLater
+ <<endl;
+#endif
+
+ if (!moveLater)
+ {
+ kpDocument *doc = document ();
+ if (!doc)
+ {
+ kdError () << "kpToolSelectionMoveCommand::moveTo() without doc" << endl;
+ return;
+ }
+
+ kpSelection *sel = doc->selection ();
+
+ // have to have pulled pixmap by now
+ if (!sel)
+ {
+ kdError () << "kpToolSelectionMoveCommand::moveTo() no sel region" << endl;
+ return;
+ }
+
+ if (!sel->pixmap ())
+ {
+ kdError () << "kpToolSelectionMoveCommand::moveTo() no sel pixmap" << endl;
+ return;
+ }
+
+ if (point == sel->topLeft ())
+ return;
+
+ sel->moveTo (point);
+ }
+
+ m_endPoint = point;
+}
+
+// public
+void kpToolSelectionMoveCommand::moveTo (int x, int y, bool moveLater)
+{
+ moveTo (QPoint (x, y), moveLater);
+}
+
+// public
+void kpToolSelectionMoveCommand::copyOntoDocument ()
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelectionMoveCommand::copyOntoDocument()" << endl;
+#endif
+
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+ kpSelection *sel = doc->selection ();
+
+ // have to have pulled pixmap by now
+ if (!sel)
+ {
+ kdError () << "\tkpToolSelectionMoveCommand::copyOntoDocument() without sel region" << endl;
+ return;
+ }
+
+ if (!sel->pixmap ())
+ {
+ kdError () << "kpToolSelectionMoveCommand::moveTo() no sel pixmap" << endl;
+ return;
+ }
+
+ if (m_oldDocumentPixmap.isNull ())
+ m_oldDocumentPixmap = *doc->pixmap ();
+
+ QRect selBoundingRect = sel->boundingRect ();
+ m_documentBoundingRect.unite (selBoundingRect);
+
+ doc->selectionCopyOntoDocument ();
+
+ m_copyOntoDocumentPoints.putPoints (m_copyOntoDocumentPoints.count (),
+ 1,
+ selBoundingRect.x (),
+ selBoundingRect.y ());
+}
+
+// public
+void kpToolSelectionMoveCommand::finalize ()
+{
+ if (!m_oldDocumentPixmap.isNull () && !m_documentBoundingRect.isNull ())
+ {
+ m_oldDocumentPixmap = kpTool::neededPixmap (m_oldDocumentPixmap,
+ m_documentBoundingRect);
+ }
+}
+
+
+/*
+ * kpToolSelectionResizeScaleCommand
+ */
+
+kpToolSelectionResizeScaleCommand::kpToolSelectionResizeScaleCommand (
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (mainWindow->document ()->selection ()->isText () ?
+ i18n ("Text: Resize Box") :
+ i18n ("Selection: Smooth Scale"),
+ mainWindow),
+ m_smoothScaleTimer (new QTimer (this))
+{
+ m_originalSelection = *selection ();
+
+ m_newTopLeft = selection ()->topLeft ();
+ m_newWidth = selection ()->width ();
+ m_newHeight = selection ()->height ();
+
+ connect (m_smoothScaleTimer, SIGNAL (timeout ()),
+ this, SLOT (resizeScaleAndMove ()));
+}
+
+kpToolSelectionResizeScaleCommand::~kpToolSelectionResizeScaleCommand ()
+{
+}
+
+
+// public virtual
+int kpToolSelectionResizeScaleCommand::size () const
+{
+ return m_originalSelection.size ();
+}
+
+
+// public
+kpSelection kpToolSelectionResizeScaleCommand::originalSelection () const
+{
+ return m_originalSelection;
+}
+
+
+// public
+QPoint kpToolSelectionResizeScaleCommand::topLeft () const
+{
+ return m_newTopLeft;
+}
+
+// public
+void kpToolSelectionResizeScaleCommand::moveTo (const QPoint &point)
+{
+ if (point == m_newTopLeft)
+ return;
+
+ m_newTopLeft = point;
+ selection ()->moveTo (m_newTopLeft);
+}
+
+
+// public
+int kpToolSelectionResizeScaleCommand::width () const
+{
+ return m_newWidth;
+}
+
+// public
+int kpToolSelectionResizeScaleCommand::height () const
+{
+ return m_newHeight;
+}
+
+// public
+void kpToolSelectionResizeScaleCommand::resize (int width, int height,
+ bool delayed)
+{
+ if (width == m_newWidth && height == m_newHeight)
+ return;
+
+ m_newWidth = width;
+ m_newHeight = height;
+
+ resizeScaleAndMove (delayed);
+}
+
+
+// public
+void kpToolSelectionResizeScaleCommand::resizeAndMoveTo (int width, int height,
+ const QPoint &point,
+ bool delayed)
+{
+ if (width == m_newWidth && height == m_newHeight &&
+ point == m_newTopLeft)
+ {
+ return;
+ }
+
+ m_newWidth = width;
+ m_newHeight = height;
+ m_newTopLeft = point;
+
+ resizeScaleAndMove (delayed);
+}
+
+
+// protected
+void kpToolSelectionResizeScaleCommand::killSmoothScaleTimer ()
+{
+ m_smoothScaleTimer->stop ();
+}
+
+
+// protected
+void kpToolSelectionResizeScaleCommand::resizeScaleAndMove (bool delayed)
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelectionResizeScaleCommand::resizeScaleAndMove(delayed="
+ << delayed << ")" << endl;
+#endif
+
+ killSmoothScaleTimer ();
+
+ kpSelection newSel;
+
+ if (selection ()->isText ())
+ {
+ newSel = m_originalSelection;
+ newSel.textResize (m_newWidth, m_newHeight);
+ }
+ else
+ {
+ newSel = kpSelection (kpSelection::Rectangle,
+ QRect (m_originalSelection.x (),
+ m_originalSelection.y (),
+ m_newWidth,
+ m_newHeight),
+ kpPixmapFX::scale (*m_originalSelection.pixmap (),
+ m_newWidth, m_newHeight,
+ !delayed/*if not delayed, smooth*/),
+ m_originalSelection.transparency ());
+
+ if (delayed)
+ {
+ // Call self with delayed==false in 200ms
+ m_smoothScaleTimer->start (200/*ms*/, true/*single shot*/);
+ }
+ }
+
+ newSel.moveTo (m_newTopLeft);
+
+ m_mainWindow->document ()->setSelection (newSel);
+}
+
+// protected slots
+void kpToolSelectionResizeScaleCommand::resizeScaleAndMove ()
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelectionResizeScaleCommand::resizeScaleAndMove()" << endl;
+#endif
+ resizeScaleAndMove (false/*no delay*/);
+}
+
+
+// public
+void kpToolSelectionResizeScaleCommand::finalize ()
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelectionResizeScaleCommand::finalize()"
+ << " smoothScaleTimer->isActive="
+ << m_smoothScaleTimer->isActive ()
+ << endl;
+#endif
+
+ // Make sure the selection contains the final image and the timer won't
+ // fire afterwards.
+ if (m_smoothScaleTimer->isActive ())
+ {
+ resizeScaleAndMove ();
+ Q_ASSERT (!m_smoothScaleTimer->isActive ());
+ }
+}
+
+
+// public virtual [base kpToolResizeScaleCommand]
+void kpToolSelectionResizeScaleCommand::execute ()
+{
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ killSmoothScaleTimer ();
+
+ resizeScaleAndMove ();
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+
+ QApplication::restoreOverrideCursor ();
+}
+
+// public virtual [base kpToolResizeScaleCommand]
+void kpToolSelectionResizeScaleCommand::unexecute ()
+{
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+ killSmoothScaleTimer ();
+
+ m_mainWindow->document ()->setSelection (m_originalSelection);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+
+ QApplication::restoreOverrideCursor ();
+}
+
+
+/*
+ * kpToolSelectionDestroyCommand
+ */
+
+kpToolSelectionDestroyCommand::kpToolSelectionDestroyCommand (const QString &name,
+ bool pushOntoDocument,
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow),
+ m_pushOntoDocument (pushOntoDocument),
+ m_oldSelection (0)
+{
+}
+
+kpToolSelectionDestroyCommand::~kpToolSelectionDestroyCommand ()
+{
+ delete m_oldSelection;
+}
+
+
+// public virtual [base kpCommand]
+int kpToolSelectionDestroyCommand::size () const
+{
+ return kpPixmapFX::pixmapSize (m_oldDocPixmap) +
+ kpPixmapFX::selectionSize (m_oldSelection);
+}
+
+
+// public virtual [base kpCommand]
+void kpToolSelectionDestroyCommand::execute ()
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelectionDestroyCommand::execute () CALLED" << endl;
+#endif
+
+ kpDocument *doc = document ();
+ if (!doc)
+ {
+ kdError () << "kpToolSelectionDestroyCommand::execute() without doc" << endl;
+ return;
+ }
+
+ if (!doc->selection ())
+ {
+ kdError () << "kpToolSelectionDestroyCommand::execute() without sel region" << endl;
+ return;
+ }
+
+ m_textRow = m_mainWindow->viewManager ()->textCursorRow ();
+ m_textCol = m_mainWindow->viewManager ()->textCursorCol ();
+
+ m_oldSelection = new kpSelection (*doc->selection ());
+ if (m_pushOntoDocument)
+ {
+ m_oldDocPixmap = doc->getPixmapAt (doc->selection ()->boundingRect ());
+ doc->selectionPushOntoDocument ();
+ }
+ else
+ doc->selectionDelete ();
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+}
+
+// public virtual [base kpCommand]
+void kpToolSelectionDestroyCommand::unexecute ()
+{
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelectionDestroyCommand::unexecute () CALLED" << endl;
+#endif
+
+ kpDocument *doc = document ();
+ if (!doc)
+ {
+ kdError () << "kpToolSelectionDestroyCommand::unexecute() without doc" << endl;
+ return;
+ }
+
+ if (doc->selection ())
+ {
+ // not error because it's possible that the user dragged out a new
+ // region (without pulling pixmap), and then CTRL+Z
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "kpToolSelectionDestroyCommand::unexecute() already has sel region" << endl;
+ #endif
+
+ if (doc->selection ()->pixmap ())
+ {
+ kdError () << "kpToolSelectionDestroyCommand::unexecute() already has sel pixmap" << endl;
+ return;
+ }
+ }
+
+ if (!m_oldSelection)
+ {
+ kdError () << "kpToolSelectionDestroyCommand::unexecute() without old sel" << endl;
+ return;
+ }
+
+ if (m_pushOntoDocument)
+ {
+ #if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\tunpush oldDocPixmap onto doc first" << endl;
+ #endif
+ doc->setPixmapAt (m_oldDocPixmap, m_oldSelection->topLeft ());
+ }
+
+#if DEBUG_KP_TOOL_SELECTION
+ kdDebug () << "\tsetting selection to: rect=" << m_oldSelection->boundingRect ()
+ << " pixmap=" << m_oldSelection->pixmap ()
+ << " pixmap.isNull()=" << (m_oldSelection->pixmap ()
+ ?
+ m_oldSelection->pixmap ()->isNull ()
+ :
+ true)
+ << endl;
+#endif
+ if (!m_oldSelection->isText ())
+ {
+ if (m_oldSelection->transparency () != m_mainWindow->selectionTransparency ())
+ m_mainWindow->setSelectionTransparency (m_oldSelection->transparency ());
+ }
+ else
+ {
+ if (m_oldSelection->textStyle () != m_mainWindow->textStyle ())
+ m_mainWindow->setTextStyle (m_oldSelection->textStyle ());
+ }
+
+ m_mainWindow->viewManager ()->setTextCursorPosition (m_textRow, m_textCol);
+ doc->setSelection (*m_oldSelection);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+
+ delete m_oldSelection;
+ m_oldSelection = 0;
+}
+
+#include <kptoolselection.moc>
diff --git a/kolourpaint/tools/kptoolselection.h b/kolourpaint/tools/kptoolselection.h
new file mode 100644
index 00000000..ee978a15
--- /dev/null
+++ b/kolourpaint/tools/kptoolselection.h
@@ -0,0 +1,313 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kp_tool_selection_h__
+#define __kp_tool_selection_h__
+
+
+#include <qpixmap.h>
+#include <qpoint.h>
+#include <qpointarray.h>
+#include <qrect.h>
+
+#include <kpcolor.h>
+#include <kpcommandhistory.h>
+#include <kpselection.h>
+#include <kpselectiontransparency.h>
+#include <kptool.h>
+
+
+class QPoint;
+class QRect;
+class QTimer;
+
+class kpMainWindow;
+class kpSelection;
+
+class kpToolSelectionCreateCommand;
+class kpToolSelectionMoveCommand;
+class kpToolSelectionPullFromDocumentCommand;
+class kpToolSelectionResizeScaleCommand;
+class kpToolWidgetOpaqueOrTransparent;
+
+
+class kpToolSelection : public kpTool
+{
+Q_OBJECT
+
+public:
+ enum Mode {Rectangle, Ellipse, FreeForm, Text};
+
+ kpToolSelection (Mode mode,
+ const QString &text, const QString &description,
+ int key,
+ kpMainWindow *mainWindow, const char *name);
+ virtual ~kpToolSelection ();
+
+ void setMode (Mode mode) { m_mode = mode; }
+
+private:
+ void pushOntoDocument ();
+
+protected:
+ bool onSelectionToMove () const;
+ int onSelectionResizeHandle () const;
+ bool onSelectionToSelectText () const;
+
+public:
+ QString haventBegunDrawUserMessage () const;
+
+ virtual void begin ();
+ virtual void end ();
+ virtual void reselect ();
+
+ virtual bool careAboutModifierState () const { return true; }
+ bool controlOrShiftPressed () const { return (m_controlPressed || m_shiftPressed); }
+
+ virtual void beginDraw ();
+protected:
+ const QCursor &cursor () const;
+public:
+ virtual void hover (const QPoint &point);
+protected:
+ void popupRMBMenu ();
+ void setSelectionBorderForMove ();
+protected slots:
+ void slotRMBMoveUpdateGUI ();
+ void delayedDraw ();
+public:
+ virtual void draw (const QPoint &thisPoint, const QPoint &lastPoint,
+ const QRect &normalizedRect);
+ virtual void cancelShape ();
+ virtual void releasedAllButtons ();
+ virtual void endDraw (const QPoint &thisPoint, const QRect &normalizedRect);
+
+protected:
+ virtual void keyPressEvent (QKeyEvent *e);
+
+protected:
+ void selectionTransparencyChanged (const QString &name);
+
+protected slots:
+ virtual void slotIsOpaqueChanged ();
+ virtual void slotBackgroundColorChanged (const kpColor &color);
+ virtual void slotColorSimilarityChanged (double similarity, int);
+
+protected:
+ Mode m_mode;
+
+ QPoint m_startDragFromSelectionTopLeft;
+ enum DragType
+ {
+ Unknown, Create, Move, SelectText, ResizeScale
+ };
+ DragType m_dragType;
+ bool m_dragHasBegun;
+ bool m_hadSelectionBeforeDrag;
+ int m_resizeScaleType;
+
+ kpToolSelectionPullFromDocumentCommand *m_currentPullFromDocumentCommand;
+ kpToolSelectionMoveCommand *m_currentMoveCommand;
+ bool m_currentMoveCommandIsSmear;
+ kpToolSelectionResizeScaleCommand *m_currentResizeScaleCommand;
+ kpToolWidgetOpaqueOrTransparent *m_toolWidgetOpaqueOrTransparent;
+
+ kpToolSelectionCreateCommand *m_currentCreateTextCommand;
+ bool m_cancelledShapeButStillHoldingButtons;
+
+ QTimer *m_createNOPTimer, *m_RMBMoveUpdateGUITimer;
+};
+
+class kpToolSelectionCreateCommand : public kpNamedCommand
+{
+public:
+ // (if fromSelection doesn't have a pixmap, it will only recreate the region)
+ kpToolSelectionCreateCommand (const QString &name, const kpSelection &fromSelection,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolSelectionCreateCommand ();
+
+ virtual int size () const;
+
+ static bool nextUndoCommandIsCreateBorder (kpCommandHistory *commandHistory);
+
+ const kpSelection *fromSelection () const;
+ void setFromSelection (const kpSelection &fromSelection);
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ kpSelection *m_fromSelection;
+
+ int m_textRow, m_textCol;
+};
+
+class kpToolSelectionPullFromDocumentCommand : public kpNamedCommand
+{
+public:
+ kpToolSelectionPullFromDocumentCommand (const QString &name, kpMainWindow *mainWindow);
+ virtual ~kpToolSelectionPullFromDocumentCommand ();
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ kpColor m_backgroundColor;
+ kpSelection *m_originalSelectionRegion;
+};
+
+class kpToolSelectionTransparencyCommand : public kpNamedCommand
+{
+public:
+ kpToolSelectionTransparencyCommand (const QString &name,
+ const kpSelectionTransparency &st,
+ const kpSelectionTransparency &oldST,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolSelectionTransparencyCommand ();
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ kpSelectionTransparency m_st, m_oldST;
+};
+
+class kpToolSelectionMoveCommand : public kpNamedCommand
+{
+public:
+ kpToolSelectionMoveCommand (const QString &name, kpMainWindow *mainWindow);
+ virtual ~kpToolSelectionMoveCommand ();
+
+ kpSelection originalSelection () const;
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+ void moveTo (const QPoint &point, bool moveLater = false);
+ void moveTo (int x, int y, bool moveLater = false);
+ void copyOntoDocument ();
+ void finalize ();
+
+private:
+ QPoint m_startPoint, m_endPoint;
+
+ QPixmap m_oldDocumentPixmap;
+
+ // area of document affected (not the bounding rect of the sel)
+ QRect m_documentBoundingRect;
+
+ QPointArray m_copyOntoDocumentPoints;
+};
+
+// You could subclass kpToolResizeScaleCommand and/or
+// kpToolSelectionMoveCommand instead if want a disaster.
+// This is different to kpToolResizeScaleCommand in that:
+//
+// 1. This only works for selections.
+// 2. This is designed for the size and position to change several times
+// before execute().
+//
+class kpToolSelectionResizeScaleCommand : public QObject,
+ public kpNamedCommand
+{
+Q_OBJECT
+
+public:
+ kpToolSelectionResizeScaleCommand (kpMainWindow *mainWindow);
+ virtual ~kpToolSelectionResizeScaleCommand ();
+
+ virtual int size () const;
+
+public:
+ kpSelection originalSelection () const;
+
+ QPoint topLeft () const;
+ void moveTo (const QPoint &point);
+
+ int width () const;
+ int height () const;
+ void resize (int width, int height, bool delayed = false);
+
+ // (equivalent to resize() followed by moveTo() but faster)
+ void resizeAndMoveTo (int width, int height, const QPoint &point,
+ bool delayed = false);
+
+protected:
+ void killSmoothScaleTimer ();
+
+ // If <delayed>, does a fast, low-quality scale and then calls itself
+ // with <delayed> unset for a smooth scale, a short time later.
+ // If acting on a text box, <delayed> is ignored.
+ void resizeScaleAndMove (bool delayed);
+
+protected slots:
+ void resizeScaleAndMove (/*delayed = false*/);
+
+public:
+ void finalize ();
+
+public:
+ virtual void execute ();
+ virtual void unexecute ();
+
+protected:
+ kpSelection m_originalSelection;
+
+ QPoint m_newTopLeft;
+ int m_newWidth, m_newHeight;
+
+ QTimer *m_smoothScaleTimer;
+};
+
+class kpToolSelectionDestroyCommand : public kpNamedCommand
+{
+public:
+ kpToolSelectionDestroyCommand (const QString &name, bool pushOntoDocument,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolSelectionDestroyCommand ();
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ bool m_pushOntoDocument;
+ QPixmap m_oldDocPixmap;
+ kpSelection *m_oldSelection;
+
+ int m_textRow, m_textCol;
+};
+
+#endif // __kp_tool_selection_h__
diff --git a/kolourpaint/tools/kptoolskew.cpp b/kolourpaint/tools/kptoolskew.cpp
new file mode 100644
index 00000000..f1e446be
--- /dev/null
+++ b/kolourpaint/tools/kptoolskew.cpp
@@ -0,0 +1,449 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_TOOL_SKEW 0
+#define DEBUG_KP_TOOL_SKEW_DIALOG 0
+
+
+#include <kptoolskew.h>
+
+#include <qapplication.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qwmatrix.h>
+
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <knuminput.h>
+
+#include <kpdefs.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kpselection.h>
+#include <kptool.h>
+
+
+/*
+ * kpToolSkewCommand
+ */
+
+kpToolSkewCommand::kpToolSkewCommand (bool actOnSelection,
+ int hangle, int vangle,
+ kpMainWindow *mainWindow)
+ : kpCommand (mainWindow),
+ m_actOnSelection (actOnSelection),
+ m_hangle (hangle), m_vangle (vangle),
+ m_backgroundColor (mainWindow ? mainWindow->backgroundColor (actOnSelection) : kpColor::invalid),
+ m_oldPixmapPtr (0)
+{
+}
+
+kpToolSkewCommand::~kpToolSkewCommand ()
+{
+ delete m_oldPixmapPtr;
+}
+
+
+// public virtual [base kpCommand]
+QString kpToolSkewCommand::name () const
+{
+ QString opName = i18n ("Skew");
+
+ if (m_actOnSelection)
+ return i18n ("Selection: %1").arg (opName);
+ else
+ return opName;
+}
+
+
+// public virtual [base kpCommand]
+int kpToolSkewCommand::size () const
+{
+ return kpPixmapFX::pixmapSize (m_oldPixmapPtr) +
+ m_oldSelection.size ();
+}
+
+
+// public virtual [base kpCommand]
+void kpToolSkewCommand::execute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+
+ m_oldPixmapPtr = new QPixmap ();
+ *m_oldPixmapPtr = *doc->pixmap (m_actOnSelection);
+
+
+ QPixmap newPixmap = kpPixmapFX::skew (*doc->pixmap (m_actOnSelection),
+ kpToolSkewDialog::horizontalAngleForPixmapFX (m_hangle),
+ kpToolSkewDialog::verticalAngleForPixmapFX (m_vangle),
+ m_backgroundColor);
+
+ if (m_actOnSelection)
+ {
+ kpSelection *sel = doc->selection ();
+
+ // Save old selection
+ m_oldSelection = *sel;
+
+
+ // Calculate skewed points
+ QPointArray currentPoints = sel->points ();
+ currentPoints.translate (-currentPoints.boundingRect ().x (),
+ -currentPoints.boundingRect ().y ());
+ QWMatrix skewMatrix = kpPixmapFX::skewMatrix (
+ *doc->pixmap (m_actOnSelection),
+ kpToolSkewDialog::horizontalAngleForPixmapFX (m_hangle),
+ kpToolSkewDialog::verticalAngleForPixmapFX (m_vangle));
+ currentPoints = skewMatrix.map (currentPoints);
+ currentPoints.translate (-currentPoints.boundingRect ().x () + m_oldSelection.x (),
+ -currentPoints.boundingRect ().y () + m_oldSelection.y ());
+
+
+ if (currentPoints.boundingRect ().width () == newPixmap.width () &&
+ currentPoints.boundingRect ().height () == newPixmap.height ())
+ {
+ doc->setSelection (kpSelection (currentPoints, newPixmap,
+ m_oldSelection.transparency ()));
+ }
+ else
+ {
+ // TODO: fix the latter "victim of" problem in kpSelection by
+ // allowing the border width & height != pixmap width & height
+ // Or maybe autocrop?
+ #if DEBUG_KP_TOOL_SKEW
+ kdDebug () << "kpToolSkewCommand::execute() currentPoints.boundingRect="
+ << currentPoints.boundingRect ()
+ << " newPixmap: w=" << newPixmap.width ()
+ << " h=" << newPixmap.height ()
+ << " (victim of rounding error and/or skewed-a-(rectangular)-pixmap-that-was-transparent-in-the-corners-making-sel-uselessly-bigger-than-needs-be))"
+ << endl;
+ #endif
+ doc->setSelection (kpSelection (kpSelection::Rectangle,
+ QRect (currentPoints.boundingRect ().x (),
+ currentPoints.boundingRect ().y (),
+ newPixmap.width (),
+ newPixmap.height ()),
+ newPixmap,
+ m_oldSelection.transparency ()));
+ }
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+ else
+ {
+ doc->setPixmap (newPixmap);
+ }
+
+
+ QApplication::restoreOverrideCursor ();
+}
+
+// public virtual [base kpCommand]
+void kpToolSkewCommand::unexecute ()
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return;
+
+
+ QApplication::setOverrideCursor (Qt::waitCursor);
+
+
+ QPixmap oldPixmap = *m_oldPixmapPtr;
+ delete m_oldPixmapPtr; m_oldPixmapPtr = 0;
+
+
+ if (!m_actOnSelection)
+ doc->setPixmap (oldPixmap);
+ else
+ {
+ kpSelection oldSelection = m_oldSelection;
+ doc->setSelection (oldSelection);
+
+ if (m_mainWindow->tool ())
+ m_mainWindow->tool ()->somethingBelowTheCursorChanged ();
+ }
+
+
+ QApplication::restoreOverrideCursor ();
+}
+
+
+/*
+ * kpToolSkewDialog
+ */
+
+
+// private static
+int kpToolSkewDialog::s_lastWidth = -1,
+ kpToolSkewDialog::s_lastHeight = -1;
+
+// private static
+int kpToolSkewDialog::s_lastHorizontalAngle = 0,
+ kpToolSkewDialog::s_lastVerticalAngle = 0;
+
+
+kpToolSkewDialog::kpToolSkewDialog (bool actOnSelection, kpMainWindow *parent,
+ const char *name)
+ : kpToolPreviewDialog (kpToolPreviewDialog::AllFeatures,
+ false/*don't reserve top row*/,
+ actOnSelection ? i18n ("Skew Selection") : i18n ("Skew Image"),
+ i18n ("After Skew:"),
+ actOnSelection, parent, name)
+{
+ // Too confusing - disable for now
+ s_lastHorizontalAngle = s_lastVerticalAngle = 0;
+
+
+ createAngleGroupBox ();
+
+
+ if (s_lastWidth > 0 && s_lastHeight > 0)
+ resize (s_lastWidth, s_lastHeight);
+
+
+ slotUpdate ();
+
+
+ m_horizontalSkewInput->setEditFocus ();
+}
+
+kpToolSkewDialog::~kpToolSkewDialog ()
+{
+ s_lastWidth = width (), s_lastHeight = height ();
+}
+
+
+// private
+void kpToolSkewDialog::createAngleGroupBox ()
+{
+ QGroupBox *angleGroupBox = new QGroupBox (i18n ("Angle"), mainWidget ());
+ addCustomWidget (angleGroupBox);
+
+
+ QLabel *horizontalSkewPixmapLabel = new QLabel (angleGroupBox);
+ horizontalSkewPixmapLabel->setPixmap (UserIcon ("image_skew_horizontal"));
+
+ QLabel *horizontalSkewLabel = new QLabel (i18n ("&Horizontal:"), angleGroupBox);
+ m_horizontalSkewInput = new KIntNumInput (s_lastHorizontalAngle, angleGroupBox);
+ m_horizontalSkewInput->setMinValue (-89);
+ m_horizontalSkewInput->setMaxValue (+89);
+
+ QLabel *horizontalSkewDegreesLabel = new QLabel (i18n ("degrees"), angleGroupBox);
+
+
+ QLabel *verticalSkewPixmapLabel = new QLabel (angleGroupBox);
+ verticalSkewPixmapLabel->setPixmap (UserIcon ("image_skew_vertical"));
+
+ QLabel *verticalSkewLabel = new QLabel (i18n ("&Vertical:"), angleGroupBox);
+ m_verticalSkewInput = new KIntNumInput (s_lastVerticalAngle, angleGroupBox);
+ m_verticalSkewInput->setMinValue (-89);
+ m_verticalSkewInput->setMaxValue (+89);
+
+ QLabel *verticalSkewDegreesLabel = new QLabel (i18n ("degrees"), angleGroupBox);
+
+
+ horizontalSkewLabel->setBuddy (m_horizontalSkewInput);
+ verticalSkewLabel->setBuddy (m_verticalSkewInput);
+
+
+ QGridLayout *angleLayout = new QGridLayout (angleGroupBox, 4, 4,
+ marginHint () * 2, spacingHint ());
+
+ angleLayout->addWidget (horizontalSkewPixmapLabel, 0, 0);
+ angleLayout->addWidget (horizontalSkewLabel, 0, 1);
+ angleLayout->addWidget (m_horizontalSkewInput, 0, 2);
+ angleLayout->addWidget (horizontalSkewDegreesLabel, 0, 3);
+
+ angleLayout->addWidget (verticalSkewPixmapLabel, 1, 0);
+ angleLayout->addWidget (verticalSkewLabel, 1, 1);
+ angleLayout->addWidget (m_verticalSkewInput, 1, 2);
+ angleLayout->addWidget (verticalSkewDegreesLabel, 1, 3);
+
+
+ connect (m_horizontalSkewInput, SIGNAL (valueChanged (int)),
+ this, SLOT (slotUpdate ()));
+ connect (m_verticalSkewInput, SIGNAL (valueChanged (int)),
+ this, SLOT (slotUpdate ()));
+}
+
+
+// private virtual [base kpToolPreviewDialog]
+QSize kpToolSkewDialog::newDimensions () const
+{
+ kpDocument *doc = document ();
+ if (!doc)
+ return QSize ();
+
+ QWMatrix skewMatrix = kpPixmapFX::skewMatrix (*doc->pixmap (),
+ horizontalAngleForPixmapFX (),
+ verticalAngleForPixmapFX ());
+ // TODO: Should we be using QWMatrix::Areas?
+ QRect skewRect = skewMatrix.mapRect (doc->rect (m_actOnSelection));
+
+ return QSize (skewRect.width (), skewRect.height ());
+}
+
+// private virtual [base kpToolPreviewDialog]
+QPixmap kpToolSkewDialog::transformPixmap (const QPixmap &pixmap,
+ int targetWidth, int targetHeight) const
+{
+ return kpPixmapFX::skew (pixmap,
+ horizontalAngleForPixmapFX (),
+ verticalAngleForPixmapFX (),
+ m_mainWindow ? m_mainWindow->backgroundColor (m_actOnSelection) : kpColor::invalid,
+ targetWidth,
+ targetHeight);
+}
+
+
+// private
+void kpToolSkewDialog::updateLastAngles ()
+{
+ s_lastHorizontalAngle = horizontalAngle ();
+ s_lastVerticalAngle = verticalAngle ();
+}
+
+// private slot virtual [base kpToolPreviewDialog]
+void kpToolSkewDialog::slotUpdate ()
+{
+ updateLastAngles ();
+ kpToolPreviewDialog::slotUpdate ();
+}
+
+
+// public
+int kpToolSkewDialog::horizontalAngle () const
+{
+ return m_horizontalSkewInput->value ();
+}
+
+// public
+int kpToolSkewDialog::verticalAngle () const
+{
+ return m_verticalSkewInput->value ();
+}
+
+
+// public static
+int kpToolSkewDialog::horizontalAngleForPixmapFX (int hangle)
+{
+ return -hangle;
+}
+
+// public static
+int kpToolSkewDialog::verticalAngleForPixmapFX (int vangle)
+{
+ return -vangle;
+}
+
+
+// public
+int kpToolSkewDialog::horizontalAngleForPixmapFX () const
+{
+ return kpToolSkewDialog::horizontalAngleForPixmapFX (horizontalAngle ());
+}
+
+// public
+int kpToolSkewDialog::verticalAngleForPixmapFX () const
+{
+ return kpToolSkewDialog::verticalAngleForPixmapFX (verticalAngle ());
+}
+
+
+// public virtual [base kpToolPreviewDialog]
+bool kpToolSkewDialog::isNoOp () const
+{
+ return (horizontalAngle () == 0) && (verticalAngle () == 0);
+}
+
+
+// private slot virtual [base KDialogBase]
+void kpToolSkewDialog::slotOk ()
+{
+ QString message, caption, continueButtonText;
+
+ if (document ()->selection ())
+ {
+ if (!document ()->selection ()->isText ())
+ {
+ message =
+ i18n ("<qt><p>Skewing the selection to %1x%2"
+ " may take a substantial amount of memory."
+ " This can reduce system"
+ " responsiveness and cause other application resource"
+ " problems.</p>"
+
+ "<p>Are you sure want to skew the selection?</p></qt>");
+
+ caption = i18n ("Skew Selection?");
+ continueButtonText = i18n ("Sk&ew Selection");
+ }
+ }
+ else
+ {
+ message =
+ i18n ("<qt><p>Skewing the image to %1x%2"
+ " may take a substantial amount of memory."
+ " This can reduce system"
+ " responsiveness and cause other application resource"
+ " problems.</p>"
+
+ "<p>Are you sure want to skew the image?</p></qt>");
+
+ caption = i18n ("Skew Image?");
+ continueButtonText = i18n ("Sk&ew Image");
+ }
+
+
+ const int newWidth = newDimensions ().width ();
+ const int newHeight = newDimensions ().height ();
+
+ if (kpTool::warnIfBigImageSize (m_oldWidth,
+ m_oldHeight,
+ newWidth, newHeight,
+ message.arg (newWidth).arg (newHeight),
+ caption,
+ continueButtonText,
+ this))
+ {
+ KDialogBase::slotOk ();
+ }
+}
+
+#include <kptoolskew.moc>
diff --git a/kolourpaint/tools/kptoolskew.h b/kolourpaint/tools/kptoolskew.h
new file mode 100644
index 00000000..570909c2
--- /dev/null
+++ b/kolourpaint/tools/kptoolskew.h
@@ -0,0 +1,121 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptool_skew_h__
+#define __kptool_skew_h__
+
+#include <qpixmap.h>
+
+#include <kpcommandhistory.h>
+#include <kdialogbase.h>
+
+#include <kpcolor.h>
+#include <kpselection.h>
+#include <kptoolpreviewdialog.h>
+
+class QGroupBox;
+class QLabel;
+class QPixmap;
+
+class KIntNumInput;
+
+class kpDocument;
+class kpMainWindow;
+
+
+class kpToolSkewCommand : public kpCommand
+{
+public:
+ kpToolSkewCommand (bool actOnSelection,
+ int hangle, int vangle,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolSkewCommand ();
+
+ virtual QString name () const;
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+private:
+ bool m_actOnSelection;
+ int m_hangle, m_vangle;
+
+ kpColor m_backgroundColor;
+ QPixmap *m_oldPixmapPtr;
+ kpSelection m_oldSelection;
+};
+
+
+class kpToolSkewDialog : public kpToolPreviewDialog
+{
+Q_OBJECT
+
+public:
+ kpToolSkewDialog (bool actOnSelection, kpMainWindow *parent,
+ const char *name = 0);
+ virtual ~kpToolSkewDialog ();
+
+private:
+ static int s_lastWidth, s_lastHeight;
+ static int s_lastHorizontalAngle, s_lastVerticalAngle;
+
+ void createAngleGroupBox ();
+
+ virtual QSize newDimensions () const;
+ virtual QPixmap transformPixmap (const QPixmap &pixmap,
+ int targetWidth, int targetHeight) const;
+
+ void updateLastAngles ();
+
+private slots:
+ virtual void slotUpdate ();
+
+public:
+ // These are the angles the users sees in the dialog and...
+ int horizontalAngle () const;
+ int verticalAngle () const;
+
+ // ...these functions translate them for use in kpPixmapFX::skew().
+ static int horizontalAngleForPixmapFX (int hangle);
+ static int verticalAngleForPixmapFX (int vangle);
+
+ int horizontalAngleForPixmapFX () const;
+ int verticalAngleForPixmapFX () const;
+
+ virtual bool isNoOp () const;
+
+private slots:
+ virtual void slotOk ();
+
+private:
+ KIntNumInput *m_horizontalSkewInput, *m_verticalSkewInput;
+};
+
+#endif // __kptool_skew_h__
diff --git a/kolourpaint/tools/kptooltext.cpp b/kolourpaint/tools/kptooltext.cpp
new file mode 100644
index 00000000..73a60e66
--- /dev/null
+++ b/kolourpaint/tools/kptooltext.cpp
@@ -0,0 +1,1394 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_TOOL_TEXT 0
+
+
+#include <kptooltext.h>
+
+#include <qvaluevector.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcommandhistory.h>
+#include <kpdocument.h>
+#include <kpmainwindow.h>
+#include <kpselection.h>
+#include <kptoolwidgetopaqueortransparent.h>
+#include <kpviewmanager.h>
+
+
+kpToolText::kpToolText (kpMainWindow *mainWindow)
+ : kpToolSelection (Text,
+ i18n ("Text"), i18n ("Writes text"),
+ Qt::Key_T,
+ mainWindow, "tool_text"),
+ m_isIMStarted (false),
+ m_IMStartCursorRow (0),
+ m_IMStartCursorCol (0),
+ m_IMPreeditStr (0)
+{
+}
+
+kpToolText::~kpToolText ()
+{
+}
+
+
+// public virtual [base kpToolSelection]
+void kpToolText::begin ()
+{
+#if DEBUG_KP_TOOL_TEXT && 1
+ kdDebug () << "kpToolText::begin()" << endl;
+#endif
+
+ mainWindow ()->enableTextToolBarActions (true);
+ viewManager ()->setTextCursorEnabled (true);
+
+ m_insertCommand = 0;
+ m_enterCommand = 0;
+ m_backspaceCommand = 0;
+ m_deleteCommand = 0;
+
+ kpToolSelection::begin ();
+}
+
+// public virtual [base kpToolSelection]
+void kpToolText::end ()
+{
+#if DEBUG_KP_TOOL_TEXT && 1
+ kdDebug () << "kpToolText::end()" << endl;
+#endif
+
+ kpToolSelection::end ();
+
+ viewManager ()->setTextCursorEnabled (false);
+ mainWindow ()->enableTextToolBarActions (false);
+}
+
+
+// public
+bool kpToolText::hasBegunText () const
+{
+ return (m_insertCommand ||
+ m_enterCommand ||
+ m_backspaceCommand ||
+ m_deleteCommand);
+}
+
+// public virtual [base kpTool]
+bool kpToolText::hasBegunShape () const
+{
+ return (hasBegunDraw () || hasBegunText ());
+}
+
+
+// public virtual [base kpToolSelection]
+void kpToolText::cancelShape ()
+{
+#if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "kpToolText::cancelShape()" << endl;
+#endif
+
+ if (m_dragType != Unknown)
+ kpToolSelection::cancelShape ();
+ else if (hasBegunText ())
+ {
+ m_insertCommand = 0;
+ m_enterCommand = 0;
+ m_backspaceCommand = 0;
+ m_deleteCommand = 0;
+
+ commandHistory ()->undo ();
+ }
+ else
+ kpToolSelection::cancelShape ();
+}
+
+// public virtual [base kpTool]
+void kpToolText::endShape (const QPoint &thisPoint, const QRect &normalizedRect)
+{
+#if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "kpToolText::endShape()" << endl;
+#endif
+
+ if (m_dragType != Unknown)
+ kpToolSelection::endDraw (thisPoint, normalizedRect);
+ else if (hasBegunText ())
+ {
+ m_insertCommand = 0;
+ m_enterCommand = 0;
+ m_backspaceCommand = 0;
+ m_deleteCommand = 0;
+ }
+ else
+ kpToolSelection::endDraw (thisPoint, normalizedRect);
+}
+
+
+// protected virtual [base kpTool]
+void kpToolText::keyPressEvent (QKeyEvent *e)
+{
+#if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "kpToolText::keyPressEvent(e->text='" << e->text () << "')" << endl;
+#endif
+
+
+ e->ignore ();
+
+
+ if (hasBegunDraw ())
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\talready began draw with mouse - passing on event to kpTool" << endl;
+ #endif
+ kpToolSelection::keyPressEvent (e);
+ return;
+ }
+
+
+ kpSelection *sel = document ()->selection ();
+
+ if (!sel || !sel->isText ())
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tno text sel - passing on event to kpTool" << endl;
+ #endif
+ //if (hasBegunShape ())
+ // endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ kpToolSelection::keyPressEvent (e);
+ return;
+ }
+
+
+ const QValueVector <QString> textLines = sel->textLines ();
+ int cursorRow = viewManager ()->textCursorRow ();
+ int cursorCol = viewManager ()->textCursorCol ();
+
+
+#define IS_SPACE(c) ((c).isSpace () || (c).isNull ())
+ if (e->key () == Qt::Key_Enter || e->key () == Qt::Key_Return)
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tenter pressed" << endl;
+ #endif
+ if (!m_enterCommand)
+ {
+ // TODO: why not endShapeInternal(); ditto for everywhere else in this file?
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ m_enterCommand = new kpToolTextEnterCommand (i18n ("Text: New Line"),
+ viewManager ()->textCursorRow (), viewManager ()->textCursorCol (),
+ mainWindow ());
+ commandHistory ()->addCommand (m_enterCommand, false/*no exec*/);
+ }
+ else
+ m_enterCommand->addEnter ();
+
+ e->accept ();
+ }
+ else if (e->key () == Qt::Key_Backspace)
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tbackspace pressed" << endl;
+ #endif
+
+ if (!m_backspaceCommand)
+ {
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ m_backspaceCommand = new kpToolTextBackspaceCommand (i18n ("Text: Backspace"),
+ viewManager ()->textCursorRow (), viewManager ()->textCursorCol (),
+ mainWindow ());
+ commandHistory ()->addCommand (m_backspaceCommand, false/*no exec*/);
+ }
+ else
+ m_backspaceCommand->addBackspace ();
+
+ e->accept ();
+ }
+ else if (e->key () == Qt::Key_Delete)
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tdelete pressed" << endl;
+ #endif
+
+ if (!m_deleteCommand)
+ {
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ m_deleteCommand = new kpToolTextDeleteCommand (i18n ("Text: Delete"),
+ viewManager ()->textCursorRow (), viewManager ()->textCursorCol (),
+ mainWindow ());
+ commandHistory ()->addCommand (m_deleteCommand, false/*no exec*/);
+ }
+ else
+ m_deleteCommand->addDelete ();
+
+ e->accept ();
+ }
+ else if (e->key () == Qt::Key_Up)
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tup pressed" << endl;
+ #endif
+
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ if (cursorRow > 0)
+ {
+ cursorRow--;
+ cursorCol = QMIN (cursorCol, (int) textLines [cursorRow].length ());
+ viewManager ()->setTextCursorPosition (cursorRow, cursorCol);
+ }
+
+ e->accept ();
+ }
+ else if (e->key () == Qt::Key_Down)
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tdown pressed" << endl;
+ #endif
+
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ if (cursorRow < (int) textLines.size () - 1)
+ {
+ cursorRow++;
+ cursorCol = QMIN (cursorCol, (int) textLines [cursorRow].length ());
+ viewManager ()->setTextCursorPosition (cursorRow, cursorCol);
+ }
+
+ e->accept ();
+ }
+ else if (e->key () == Qt::Key_Left)
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tleft pressed" << endl;
+ #endif
+
+ #define MOVE_CURSOR_LEFT() \
+ { \
+ cursorCol--; \
+ \
+ if (cursorCol < 0) \
+ { \
+ cursorRow--; \
+ if (cursorRow < 0) \
+ { \
+ cursorRow = 0; \
+ cursorCol = 0; \
+ } \
+ else \
+ cursorCol = textLines [cursorRow].length (); \
+ } \
+ }
+
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ if ((e->state () & Qt::ControlButton) == 0)
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tmove single char" << endl;
+ #endif
+
+ MOVE_CURSOR_LEFT ();
+ viewManager ()->setTextCursorPosition (cursorRow, cursorCol);
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tmove to start of word" << endl;
+ #endif
+
+ // (these comments will exclude the row=0,col=0 boundary case)
+
+ #define IS_ON_ANCHOR() (!IS_SPACE (textLines [cursorRow][cursorCol]) && \
+ (cursorCol == 0 || IS_SPACE (textLines [cursorRow][cursorCol - 1])))
+ if (IS_ON_ANCHOR ())
+ MOVE_CURSOR_LEFT ();
+
+ // --- now we're not on an anchor point (start of word) ---
+
+ // End up on a letter...
+ while (!(cursorRow == 0 && cursorCol == 0) &&
+ (IS_SPACE (textLines [cursorRow][cursorCol])))
+ {
+ MOVE_CURSOR_LEFT ();
+ }
+
+ // --- now we're on a letter ---
+
+ // Find anchor point
+ while (!(cursorRow == 0 && cursorCol == 0) && !IS_ON_ANCHOR ())
+ {
+ MOVE_CURSOR_LEFT ();
+ }
+
+ #undef IS_ON_ANCHOR
+
+ viewManager ()->setTextCursorPosition (cursorRow, cursorCol);
+ }
+
+ #undef MOVE_CURSOR_LEFT
+
+ e->accept ();
+
+ }
+ else if (e->key () == Qt::Key_Right)
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tright pressed" << endl;
+ #endif
+
+ #define MOVE_CURSOR_RIGHT() \
+ { \
+ cursorCol++; \
+ \
+ if (cursorCol > (int) textLines [cursorRow].length ()) \
+ { \
+ cursorRow++; \
+ if (cursorRow > (int) textLines.size () - 1) \
+ { \
+ cursorRow = textLines.size () - 1; \
+ cursorCol = textLines [cursorRow].length (); \
+ } \
+ else \
+ cursorCol = 0; \
+ } \
+ }
+
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ if ((e->state () & Qt::ControlButton) == 0)
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tmove single char" << endl;
+ #endif
+
+ MOVE_CURSOR_RIGHT ();
+ viewManager ()->setTextCursorPosition (cursorRow, cursorCol);
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tmove to start of word" << endl;
+ #endif
+
+ // (these comments will exclude the last row,end col boundary case)
+
+ #define IS_AT_END() (cursorRow == (int) textLines.size () - 1 && \
+ cursorCol == (int) textLines [cursorRow].length ())
+
+ // Find space
+ while (!IS_AT_END () && !IS_SPACE (textLines [cursorRow][cursorCol]))
+ {
+ MOVE_CURSOR_RIGHT ();
+ }
+
+ // --- now we're on a space ---
+
+ // Find letter
+ while (!IS_AT_END () && IS_SPACE (textLines [cursorRow][cursorCol]))
+ {
+ MOVE_CURSOR_RIGHT ();
+ }
+
+ // --- now we're on a letter ---
+
+ viewManager ()->setTextCursorPosition (cursorRow, cursorCol);
+
+ #undef IS_AT_END
+ }
+
+ #undef MOVE_CURSOR_RIGHT
+
+ e->accept ();
+ }
+ else if (e->key () == Qt::Key_Home)
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\thome pressed" << endl;
+ #endif
+
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ if (e->state () & Qt::ControlButton)
+ cursorRow = 0;
+
+ cursorCol = 0;
+
+ viewManager ()->setTextCursorPosition (cursorRow, cursorCol);
+
+ e->accept ();
+ }
+ else if (e->key () == Qt::Key_End)
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tend pressed" << endl;
+ #endif
+
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ if (e->state () & Qt::ControlButton)
+ cursorRow = textLines.size () - 1;
+
+ cursorCol = textLines [cursorRow].length ();
+
+ viewManager ()->setTextCursorPosition (cursorRow, cursorCol);
+
+ e->accept ();
+ }
+ else
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\ttext='" << e->text () << "'" << endl;
+ #endif
+ QString usableText;
+ for (int i = 0; i < (int) e->text ().length (); i++)
+ {
+ if (e->text ().at (i).isPrint ())
+ usableText += e->text ().at (i);
+ }
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tusableText='" << usableText << "'" << endl;
+ #endif
+
+ if (usableText.length () > 0)
+ {
+ if (!m_insertCommand)
+ {
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ m_insertCommand = new kpToolTextInsertCommand (i18n ("Text: Write"),
+ viewManager ()->textCursorRow (), viewManager ()->textCursorCol (),
+ usableText,
+ mainWindow ());
+ commandHistory ()->addCommand (m_insertCommand, false/*no exec*/);
+ }
+ else
+ m_insertCommand->addText (usableText);
+
+ e->accept ();
+ }
+ }
+#undef IS_SPACE
+
+
+ if (!e->isAccepted ())
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tkey processing did not accept (text was '"
+ << e->text ()
+ << "') - passing on event to kpToolSelection"
+ << endl;
+ #endif
+ //if (hasBegunShape ())
+ // endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ kpToolSelection::keyPressEvent (e);
+ return;
+ }
+}
+
+void kpToolText::imStartEvent (QIMEvent *e)
+{
+#if DEBUG_KP_TOOL_TEXT && 1
+ kdDebug () << "kpToolText::imStartEvent() text='" << e->text ()
+ << " cursorPos=" << e->cursorPos ()
+ << " selectionLength=" << e->selectionLength ()
+ << endl;
+#endif
+
+ kpSelection *sel = document ()->selection ();
+ if (hasBegunDraw() || !sel || !sel->isText ())
+ {
+ e->ignore();
+ return;
+ }
+
+ m_IMStartCursorRow = viewManager ()->textCursorRow ();
+ m_IMStartCursorCol = viewManager ()->textCursorCol ();
+ m_IMPreeditStr = QString::null;
+}
+
+void kpToolText::imComposeEvent (QIMEvent *e)
+{
+#if DEBUG_KP_TOOL_TEXT && 1
+ kdDebug () << "kpToolText::imComposeEvent() text='" << e->text ()
+ << " cursorPos=" << e->cursorPos ()
+ << " selectionLength=" << e->selectionLength ()
+ << endl;
+#endif
+
+ kpSelection *sel = document ()->selection ();
+ if (hasBegunDraw() || !sel || !sel->isText ())
+ {
+ e->ignore();
+ return;
+ }
+
+ // remove old preedit
+ if (m_IMPreeditStr.length() > 0 )
+ {
+ // set cursor at the start input point
+ viewManager ()->setTextCursorPosition (m_IMStartCursorRow, m_IMStartCursorCol);
+ for (unsigned int i = 0; i < m_IMPreeditStr.length(); i++)
+ {
+ if (!m_deleteCommand)
+ {
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ m_deleteCommand = new kpToolTextDeleteCommand (i18n ("Text: Delete"),
+ viewManager ()->textCursorRow (), viewManager ()->textCursorCol (),
+ mainWindow ());
+ commandHistory ()->addCommand (m_deleteCommand, false/*no exec*/);
+ }
+ else
+ m_deleteCommand->addDelete ();
+ }
+ }
+
+ // insert new preedit
+ m_IMPreeditStr = e->text();
+ if (m_IMPreeditStr.length() > 0)
+ {
+ if (!m_insertCommand)
+ {
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ m_insertCommand = new kpToolTextInsertCommand (i18n ("Text: Write"),
+ viewManager ()->textCursorRow (), viewManager ()->textCursorCol (),
+ m_IMPreeditStr,
+ mainWindow ());
+ commandHistory ()->addCommand (m_insertCommand, false/*no exec*/);
+ }
+ else
+ m_insertCommand->addText (m_IMPreeditStr);
+ }
+
+ // set cursor pos
+ if (m_IMStartCursorRow >= 0)
+ {
+ int row = m_IMStartCursorRow;
+ int col = m_IMStartCursorCol + e->cursorPos () /* + e->selectionLength()*/;
+ viewManager ()->setTextCursorPosition (row, col, true /* update MicroFocusHint */);
+ }
+}
+
+void kpToolText::imEndEvent (QIMEvent *e)
+{
+#if DEBUG_KP_TOOL_TEXT && 1
+ kdDebug () << "kpToolText::imEndEvent() text='" << e->text ()
+ << " cursorPos=" << e->cursorPos ()
+ << " selectionLength=" << e->selectionLength ()
+ << endl;
+#endif
+
+ kpSelection *sel = document ()->selection ();
+ if (hasBegunDraw() || !sel || !sel->isText ())
+ {
+ e->ignore();
+ return;
+ }
+
+ // remove old preedit
+ if (m_IMPreeditStr.length() > 0 )
+ {
+ // set cursor at the start input point
+ viewManager ()->setTextCursorPosition (m_IMStartCursorRow, m_IMStartCursorCol);
+ for (unsigned int i = 0; i < m_IMPreeditStr.length(); i++)
+ {
+ if (!m_deleteCommand)
+ {
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ m_deleteCommand = new kpToolTextDeleteCommand (i18n ("Text: Delete"),
+ viewManager ()->textCursorRow (), viewManager ()->textCursorCol (),
+ mainWindow ());
+ commandHistory ()->addCommand (m_deleteCommand, false/*no exec*/);
+ }
+ else
+ m_deleteCommand->addDelete ();
+ }
+ }
+ m_IMPreeditStr = QString::null;
+
+ // commit string
+ QString inputStr = e->text();
+ if (inputStr.length() > 0)
+ {
+ if (!m_insertCommand)
+ {
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ m_insertCommand = new kpToolTextInsertCommand (i18n ("Text: Write"),
+ viewManager ()->textCursorRow (), viewManager ()->textCursorCol (),
+ inputStr,
+ mainWindow ());
+ commandHistory ()->addCommand (m_insertCommand, false/*no exec*/);
+ }
+ else
+ m_insertCommand->addText (inputStr);
+ }
+}
+
+
+// protected
+bool kpToolText::shouldChangeTextStyle () const
+{
+ if (mainWindow ()->settingTextStyle ())
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\trecursion - abort setting text style: "
+ << mainWindow ()->settingTextStyle ()
+ << endl;
+ #endif
+ return false;
+ }
+
+ if (!document ()->selection () ||
+ !document ()->selection ()->isText ())
+ {
+ #if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "\tno text selection - abort setting text style" << endl;
+ #endif
+ return false;
+ }
+
+ return true;
+}
+
+// protected
+void kpToolText::changeTextStyle (const QString &name,
+ const kpTextStyle &newTextStyle,
+ const kpTextStyle &oldTextStyle)
+{
+#if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "kpToolText::changeTextStyle(" << name << ")" << endl;
+#endif
+
+ if (hasBegunShape ())
+ endShape (m_currentPoint, QRect (m_startPoint, m_currentPoint).normalize ());
+
+ commandHistory ()->addCommand (
+ new kpToolTextChangeStyleCommand (
+ name,
+ newTextStyle,
+ oldTextStyle,
+ mainWindow ()));
+}
+
+
+// protected slot virtual [base kpToolSelection]
+void kpToolText::slotIsOpaqueChanged ()
+{
+#if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "kpToolText::slotIsOpaqueChanged()" << endl;
+#endif
+
+ if (!shouldChangeTextStyle ())
+ return;
+
+ kpTextStyle newTextStyle = mainWindow ()->textStyle ();
+ kpTextStyle oldTextStyle = newTextStyle;
+ oldTextStyle.setBackgroundOpaque (!m_toolWidgetOpaqueOrTransparent->isOpaque ());
+
+ changeTextStyle (newTextStyle.isBackgroundOpaque () ?
+ i18n ("Text: Opaque Background") :
+ i18n ("Text: Transparent Background"),
+ newTextStyle,
+ oldTextStyle);
+}
+
+// protected slot virtual [base kpTool]
+void kpToolText::slotColorsSwapped (const kpColor &newForegroundColor,
+ const kpColor &newBackgroundColor)
+{
+#if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "kpToolText::slotColorsSwapped()" << endl;
+#endif
+
+ if (!shouldChangeTextStyle ())
+ return;
+
+ kpTextStyle newTextStyle = mainWindow ()->textStyle ();
+ kpTextStyle oldTextStyle = newTextStyle;
+ oldTextStyle.setForegroundColor (newBackgroundColor);
+ oldTextStyle.setBackgroundColor (newForegroundColor);
+
+ changeTextStyle (i18n ("Text: Swap Colors"),
+ newTextStyle,
+ oldTextStyle);
+}
+
+// protected slot virtual [base kpTool]
+void kpToolText::slotForegroundColorChanged (const kpColor & /*color*/)
+{
+#if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "kpToolText::slotForegroundColorChanged()" << endl;
+#endif
+
+ if (!shouldChangeTextStyle ())
+ return;
+
+ kpTextStyle newTextStyle = mainWindow ()->textStyle ();
+ kpTextStyle oldTextStyle = newTextStyle;
+ oldTextStyle.setForegroundColor (oldForegroundColor ());
+
+ changeTextStyle (i18n ("Text: Foreground Color"),
+ newTextStyle,
+ oldTextStyle);
+}
+
+// protected slot virtual [base kpToolSelection]
+void kpToolText::slotBackgroundColorChanged (const kpColor & /*color*/)
+{
+#if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "kpToolText::slotBackgroundColorChanged()" << endl;
+#endif
+
+ if (!shouldChangeTextStyle ())
+ return;
+
+ kpTextStyle newTextStyle = mainWindow ()->textStyle ();
+ kpTextStyle oldTextStyle = newTextStyle;
+ oldTextStyle.setBackgroundColor (oldBackgroundColor ());
+
+ changeTextStyle (i18n ("Text: Background Color"),
+ newTextStyle,
+ oldTextStyle);
+}
+
+// protected slot virtual [base kpToolSelection]
+void kpToolText::slotColorSimilarityChanged (double, int)
+{
+ // --- don't pass on event to kpToolSelection which would have set the
+ // SelectionTransparency - not relevant to the Text Tool ---
+}
+
+
+// public slot
+void kpToolText::slotFontFamilyChanged (const QString &fontFamily,
+ const QString &oldFontFamily)
+{
+#if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "kpToolText::slotFontFamilyChanged() new="
+ << fontFamily
+ << " old="
+ << oldFontFamily
+ << endl;
+#else
+ (void) fontFamily;
+#endif
+
+ if (!shouldChangeTextStyle ())
+ return;
+
+ kpTextStyle newTextStyle = mainWindow ()->textStyle ();
+ kpTextStyle oldTextStyle = newTextStyle;
+ oldTextStyle.setFontFamily (oldFontFamily);
+
+ changeTextStyle (i18n ("Text: Font"),
+ newTextStyle,
+ oldTextStyle);
+}
+
+// public slot
+void kpToolText::slotFontSizeChanged (int fontSize, int oldFontSize)
+{
+#if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "kpToolText::slotFontSizeChanged() new="
+ << fontSize
+ << " old="
+ << oldFontSize
+ << endl;
+#else
+ (void) fontSize;
+#endif
+
+ if (!shouldChangeTextStyle ())
+ return;
+
+ kpTextStyle newTextStyle = mainWindow ()->textStyle ();
+ kpTextStyle oldTextStyle = newTextStyle;
+ oldTextStyle.setFontSize (oldFontSize);
+
+ changeTextStyle (i18n ("Text: Font Size"),
+ newTextStyle,
+ oldTextStyle);
+}
+
+
+// public slot
+void kpToolText::slotBoldChanged (bool isBold)
+{
+#if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "kpToolText::slotBoldChanged(" << isBold << ")" << endl;
+#endif
+
+ if (!shouldChangeTextStyle ())
+ return;
+
+ kpTextStyle newTextStyle = mainWindow ()->textStyle ();
+ kpTextStyle oldTextStyle = newTextStyle;
+ oldTextStyle.setBold (!isBold);
+
+ changeTextStyle (i18n ("Text: Bold"),
+ newTextStyle,
+ oldTextStyle);
+}
+
+// public slot
+void kpToolText::slotItalicChanged (bool isItalic)
+{
+#if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "kpToolText::slotItalicChanged(" << isItalic << ")" << endl;
+#endif
+
+ if (!shouldChangeTextStyle ())
+ return;
+
+ kpTextStyle newTextStyle = mainWindow ()->textStyle ();
+ kpTextStyle oldTextStyle = newTextStyle;
+ oldTextStyle.setItalic (!isItalic);
+
+ changeTextStyle (i18n ("Text: Italic"),
+ newTextStyle,
+ oldTextStyle);
+}
+
+// public slot
+void kpToolText::slotUnderlineChanged (bool isUnderline)
+{
+#if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "kpToolText::slotUnderlineChanged(" << isUnderline << ")" << endl;
+#endif
+
+ if (!shouldChangeTextStyle ())
+ return;
+
+ kpTextStyle newTextStyle = mainWindow ()->textStyle ();
+ kpTextStyle oldTextStyle = newTextStyle;
+ oldTextStyle.setUnderline (!isUnderline);
+
+ changeTextStyle (i18n ("Text: Underline"),
+ newTextStyle,
+ oldTextStyle);
+}
+
+// public slot
+void kpToolText::slotStrikeThruChanged (bool isStrikeThru)
+{
+#if DEBUG_KP_TOOL_TEXT
+ kdDebug () << "kpToolText::slotStrikeThruChanged(" << isStrikeThru << ")" << endl;
+#endif
+
+ if (!shouldChangeTextStyle ())
+ return;
+
+ kpTextStyle newTextStyle = mainWindow ()->textStyle ();
+ kpTextStyle oldTextStyle = newTextStyle;
+ oldTextStyle.setStrikeThru (!isStrikeThru);
+
+ changeTextStyle (i18n ("Text: Strike Through"),
+ newTextStyle,
+ oldTextStyle);
+}
+
+
+/*
+ * kpToolTextChangeStyleCommand
+ */
+
+kpToolTextChangeStyleCommand::kpToolTextChangeStyleCommand (const QString &name,
+ const kpTextStyle &newTextStyle, const kpTextStyle &oldTextStyle,
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow),
+ m_newTextStyle (newTextStyle),
+ m_oldTextStyle (oldTextStyle)
+{
+}
+
+kpToolTextChangeStyleCommand::~kpToolTextChangeStyleCommand ()
+{
+}
+
+
+// public virtual [base kpCommand]
+int kpToolTextChangeStyleCommand::size () const
+{
+ return 0;
+}
+
+
+// public virtual [base kpCommand]
+void kpToolTextChangeStyleCommand::execute ()
+{
+#if DEBUG_KP_TOOL_TEXT && 1
+ kdDebug () << "kpToolTextChangeStyleCommand::execute()"
+ << " font=" << m_newTextStyle.fontFamily ()
+ << " fontSize=" << m_newTextStyle.fontSize ()
+ << " isBold=" << m_newTextStyle.isBold ()
+ << " isItalic=" << m_newTextStyle.isItalic ()
+ << " isUnderline=" << m_newTextStyle.isUnderline ()
+ << " isStrikeThru=" << m_newTextStyle.isStrikeThru ()
+ << endl;
+#endif
+
+ m_mainWindow->setTextStyle (m_newTextStyle);
+ if (selection ())
+ selection ()->setTextStyle (m_newTextStyle);
+ else
+ kdError () << "kpToolTextChangeStyleCommand::execute() without sel" << endl;
+}
+
+// public virtual [base kpCommand]
+void kpToolTextChangeStyleCommand::unexecute ()
+{
+#if DEBUG_KP_TOOL_TEXT && 1
+ kdDebug () << "kpToolTextChangeStyleCommand::unexecute()"
+ << " font=" << m_newTextStyle.fontFamily ()
+ << " fontSize=" << m_newTextStyle.fontSize ()
+ << " isBold=" << m_newTextStyle.isBold ()
+ << " isItalic=" << m_newTextStyle.isItalic ()
+ << " isUnderline=" << m_newTextStyle.isUnderline ()
+ << " isStrikeThru=" << m_newTextStyle.isStrikeThru ()
+ << endl;
+#endif
+
+ m_mainWindow->setTextStyle (m_oldTextStyle);
+ if (selection ())
+ selection ()->setTextStyle (m_oldTextStyle);
+ else
+ kdError () << "kpToolTextChangeStyleCommand::unexecute() without sel" << endl;
+}
+
+
+/*
+ * kpToolTextInsertCommand
+ */
+
+kpToolTextInsertCommand::kpToolTextInsertCommand (const QString &name,
+ int row, int col, QString newText,
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow),
+ m_row (row), m_col (col)
+{
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+ addText (newText);
+}
+
+kpToolTextInsertCommand::~kpToolTextInsertCommand ()
+{
+}
+
+
+// public
+void kpToolTextInsertCommand::addText (const QString &moreText)
+{
+ if (moreText.isEmpty ())
+ return;
+
+ QValueVector <QString> textLines = selection ()->textLines ();
+ const QString leftHalf = textLines [m_row].left (m_col);
+ const QString rightHalf = textLines [m_row].mid (m_col);
+ textLines [m_row] = leftHalf + moreText + rightHalf;
+ selection ()->setTextLines (textLines);
+
+ m_newText += moreText;
+ m_col += moreText.length ();
+
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+}
+
+
+// public virtual [base kpCommand]
+int kpToolTextInsertCommand::size () const
+{
+ return m_newText.length () * sizeof (QChar);
+}
+
+
+// public virtual [base kpCommand]
+void kpToolTextInsertCommand::execute ()
+{
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+
+ QString text = m_newText;
+ m_newText = QString::null;
+ addText (text);
+}
+
+// public virtual [base kpCommand]
+void kpToolTextInsertCommand::unexecute ()
+{
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+
+ QValueVector <QString> textLines = selection ()->textLines ();
+ const QString leftHalf = textLines [m_row].left (m_col - m_newText.length ());
+ const QString rightHalf = textLines [m_row].mid (m_col);
+ textLines [m_row] = leftHalf + rightHalf;
+ selection ()->setTextLines (textLines);
+
+ m_col -= m_newText.length ();
+
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+}
+
+
+/*
+ * kpToolTextEnterCommand
+ */
+
+kpToolTextEnterCommand::kpToolTextEnterCommand (const QString &name,
+ int row, int col,
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow),
+ m_row (row), m_col (col),
+ m_numEnters (0)
+{
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+ addEnter ();
+}
+
+kpToolTextEnterCommand::~kpToolTextEnterCommand ()
+{
+}
+
+
+// public
+void kpToolTextEnterCommand::addEnter ()
+{
+ QValueVector <QString> textLines = selection ()->textLines ();
+
+ const QString rightHalf = textLines [m_row].mid (m_col);
+
+ textLines [m_row].truncate (m_col);
+ textLines.insert (textLines.begin () + m_row + 1, rightHalf);
+
+ selection ()->setTextLines (textLines);
+
+ m_row++;
+ m_col = 0;
+
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+
+ m_numEnters++;
+}
+
+
+// public virtual [base kpCommand]
+int kpToolTextEnterCommand::size () const
+{
+ return 0;
+}
+
+
+// public virtual [base kpCommand]
+void kpToolTextEnterCommand::execute ()
+{
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+ int oldNumEnters = m_numEnters;
+ m_numEnters = 0;
+
+ for (int i = 0; i < oldNumEnters; i++)
+ addEnter ();
+}
+
+// public virtual [base kpCommand]
+void kpToolTextEnterCommand::unexecute ()
+{
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+
+ QValueVector <QString> textLines = selection ()->textLines ();
+
+ for (int i = 0; i < m_numEnters; i++)
+ {
+ if (m_col != 0)
+ {
+ kdError () << "kpToolTextEnterCommand::unexecute() col=" << m_col << endl;
+ break;
+ }
+
+ if (m_row <= 0)
+ break;
+
+ int newRow = m_row - 1;
+ int newCol = textLines [newRow].length ();
+
+ textLines [newRow] += textLines [m_row];
+
+ textLines.erase (textLines.begin () + m_row);
+
+ m_row = newRow;
+ m_col = newCol;
+ }
+
+ selection ()->setTextLines (textLines);
+
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+}
+
+
+/*
+ * kpToolTextBackspaceCommand
+ */
+
+kpToolTextBackspaceCommand::kpToolTextBackspaceCommand (const QString &name,
+ int row, int col,
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow),
+ m_row (row), m_col (col),
+ m_numBackspaces (0)
+{
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+ addBackspace ();
+}
+
+kpToolTextBackspaceCommand::~kpToolTextBackspaceCommand ()
+{
+}
+
+
+// public
+void kpToolTextBackspaceCommand::addBackspace ()
+{
+ QValueVector <QString> textLines = selection ()->textLines ();
+
+ if (m_col > 0)
+ {
+ m_deletedText.prepend (textLines [m_row][m_col - 1]);
+
+ textLines [m_row] = textLines [m_row].left (m_col - 1) +
+ textLines [m_row].mid (m_col);
+ m_col--;
+ }
+ else
+ {
+ if (m_row > 0)
+ {
+ int newCursorRow = m_row - 1;
+ int newCursorCol = textLines [newCursorRow].length ();
+
+ m_deletedText.prepend ('\n');
+
+ textLines [newCursorRow] += textLines [m_row];
+
+ textLines.erase (textLines.begin () + m_row);
+
+ m_row = newCursorRow;
+ m_col = newCursorCol;
+ }
+ }
+
+ selection ()->setTextLines (textLines);
+
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+
+ m_numBackspaces++;
+}
+
+
+// public virtual [base kpCommand]
+int kpToolTextBackspaceCommand::size () const
+{
+ return m_deletedText.length () * sizeof (QChar);
+}
+
+
+// public virtual [base kpCommand]
+void kpToolTextBackspaceCommand::execute ()
+{
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+
+ m_deletedText = QString::null;
+ int oldNumBackspaces = m_numBackspaces;
+ m_numBackspaces = 0;
+
+ for (int i = 0; i < oldNumBackspaces; i++)
+ addBackspace ();
+}
+
+// public virtual [base kpCommand]
+void kpToolTextBackspaceCommand::unexecute ()
+{
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+
+ QValueVector <QString> textLines = selection ()->textLines ();
+
+ for (int i = 0; i < (int) m_deletedText.length (); i++)
+ {
+ if (m_deletedText [i] == '\n')
+ {
+ const QString rightHalf = textLines [m_row].mid (m_col);
+
+ textLines [m_row].truncate (m_col);
+ textLines.insert (textLines.begin () + m_row + 1, rightHalf);
+
+ m_row++;
+ m_col = 0;
+ }
+ else
+ {
+ const QString leftHalf = textLines [m_row].left (m_col);
+ const QString rightHalf = textLines [m_row].mid (m_col);
+
+ textLines [m_row] = leftHalf + m_deletedText [i] + rightHalf;
+ m_col++;
+ }
+ }
+
+ m_deletedText = QString::null;
+
+ selection ()->setTextLines (textLines);
+
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+}
+
+
+/*
+ * kpToolTextDeleteCommand
+ */
+
+kpToolTextDeleteCommand::kpToolTextDeleteCommand (const QString &name,
+ int row, int col,
+ kpMainWindow *mainWindow)
+ : kpNamedCommand (name, mainWindow),
+ m_row (row), m_col (col),
+ m_numDeletes (0)
+{
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+ addDelete ();
+}
+
+kpToolTextDeleteCommand::~kpToolTextDeleteCommand ()
+{
+}
+
+
+// public
+void kpToolTextDeleteCommand::addDelete ()
+{
+ QValueVector <QString> textLines = selection ()->textLines ();
+
+ if (m_col < (int) textLines [m_row].length ())
+ {
+ m_deletedText.prepend (textLines [m_row][m_col]);
+
+ textLines [m_row] = textLines [m_row].left (m_col) +
+ textLines [m_row].mid (m_col + 1);
+ }
+ else
+ {
+ if (m_row < (int) textLines.size () - 1)
+ {
+ m_deletedText.prepend ('\n');
+
+ textLines [m_row] += textLines [m_row + 1];
+ textLines.erase (textLines.begin () + m_row + 1);
+ }
+ }
+
+ selection ()->setTextLines (textLines);
+
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+
+ m_numDeletes++;
+}
+
+
+// public virtual [base kpCommand]
+int kpToolTextDeleteCommand::size () const
+{
+ return m_deletedText.length () * sizeof (QChar);
+}
+
+
+// public virtual [base kpCommand]
+void kpToolTextDeleteCommand::execute ()
+{
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+
+ m_deletedText = QString::null;
+ int oldNumDeletes = m_numDeletes;
+ m_numDeletes = 0;
+
+ for (int i = 0; i < oldNumDeletes; i++)
+ addDelete ();
+}
+
+// public virtual [base kpCommand]
+void kpToolTextDeleteCommand::unexecute ()
+{
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+
+ QValueVector <QString> textLines = selection ()->textLines ();
+
+ for (int i = 0; i < (int) m_deletedText.length (); i++)
+ {
+ if (m_deletedText [i] == '\n')
+ {
+ const QString rightHalf = textLines [m_row].mid (m_col);
+
+ textLines [m_row].truncate (m_col);
+ textLines.insert (textLines.begin () + m_row + 1, rightHalf);
+ }
+ else
+ {
+ const QString leftHalf = textLines [m_row].left (m_col);
+ const QString rightHalf = textLines [m_row].mid (m_col);
+
+ textLines [m_row] = leftHalf + m_deletedText [i] + rightHalf;
+ }
+ }
+
+ m_deletedText = QString::null;
+
+ selection ()->setTextLines (textLines);
+
+ viewManager ()->setTextCursorPosition (m_row, m_col);
+}
+
+
+#include <kptooltext.moc>
diff --git a/kolourpaint/tools/kptooltext.h b/kolourpaint/tools/kptooltext.h
new file mode 100644
index 00000000..a99654b7
--- /dev/null
+++ b/kolourpaint/tools/kptooltext.h
@@ -0,0 +1,203 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kp_tool_text_h__
+#define __kp_tool_text_h__
+
+#include <qstring.h>
+
+#include <kpcommandhistory.h>
+
+#include <kptextstyle.h>
+#include <kptoolselection.h>
+
+class kpColor;
+class kpMainWindow;
+class kpSelection;
+class kpViewManager;
+
+class kpToolText : public kpToolSelection
+{
+Q_OBJECT
+
+public:
+ kpToolText (kpMainWindow *mainWindow);
+ virtual ~kpToolText ();
+
+ virtual bool careAboutColorsSwapped () const { return true; }
+
+ virtual void begin ();
+ virtual void end ();
+
+ bool hasBegunText () const;
+ virtual bool hasBegunShape () const;
+ virtual void cancelShape ();
+ virtual void endShape (const QPoint &thisPoint, const QRect &normalizedRect);
+
+protected:
+ virtual void keyPressEvent (QKeyEvent *e);
+ virtual void imStartEvent (QIMEvent *e);
+ virtual void imComposeEvent (QIMEvent *e);
+ virtual void imEndEvent (QIMEvent *e);
+
+protected:
+ bool shouldChangeTextStyle () const;
+ void changeTextStyle (const QString &name,
+ const kpTextStyle &newTextStyle,
+ const kpTextStyle &oldTextStyle);
+
+protected slots:
+ virtual void slotIsOpaqueChanged ();
+ virtual void slotColorsSwapped (const kpColor &newForegroundColor,
+ const kpColor &newBackgroundColor);
+ virtual void slotForegroundColorChanged (const kpColor &color);
+ virtual void slotBackgroundColorChanged (const kpColor &color);
+ virtual void slotColorSimilarityChanged (double, int);
+
+public slots:
+ void slotFontFamilyChanged (const QString &fontFamily, const QString &oldFontFamily);
+ void slotFontSizeChanged (int fontSize, int oldFontSize);
+ void slotBoldChanged (bool isBold);
+ void slotItalicChanged (bool isItalic);
+ void slotUnderlineChanged (bool isUnderline);
+ void slotStrikeThruChanged (bool isStrikeThru);
+
+protected:
+ class kpToolTextInsertCommand *m_insertCommand;
+ class kpToolTextEnterCommand *m_enterCommand;
+ class kpToolTextBackspaceCommand *m_backspaceCommand;
+ class kpToolTextDeleteCommand *m_deleteCommand;
+
+ bool m_isIMStarted;
+ int m_IMStartCursorRow;
+ int m_IMStartCursorCol;
+ QString m_IMPreeditStr;
+};
+
+
+class kpToolTextChangeStyleCommand : public kpNamedCommand
+{
+public:
+ kpToolTextChangeStyleCommand (const QString &name,
+ const kpTextStyle &newTextStyle, const kpTextStyle &oldTextStyle,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolTextChangeStyleCommand ();
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+protected:
+ kpTextStyle m_newTextStyle, m_oldTextStyle;
+};
+
+class kpToolTextInsertCommand : public kpNamedCommand
+{
+public:
+ kpToolTextInsertCommand (const QString &name,
+ int row, int col, QString newText,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolTextInsertCommand ();
+
+ void addText (const QString &moreText);
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+protected:
+ int m_row, m_col;
+ QString m_newText;
+};
+
+class kpToolTextEnterCommand : public kpNamedCommand
+{
+public:
+ kpToolTextEnterCommand (const QString &name,
+ int row, int col,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolTextEnterCommand ();
+
+ void addEnter ();
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+protected:
+ int m_row, m_col;
+ int m_numEnters;
+};
+
+class kpToolTextBackspaceCommand : public kpNamedCommand
+{
+public:
+ kpToolTextBackspaceCommand (const QString &name,
+ int row, int col,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolTextBackspaceCommand ();
+
+ void addBackspace ();
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+protected:
+ int m_row, m_col;
+ int m_numBackspaces;
+ QString m_deletedText;
+};
+
+class kpToolTextDeleteCommand : public kpNamedCommand
+{
+public:
+ kpToolTextDeleteCommand (const QString &name,
+ int row, int col,
+ kpMainWindow *mainWindow);
+ virtual ~kpToolTextDeleteCommand ();
+
+ void addDelete ();
+
+ virtual int size () const;
+
+ virtual void execute ();
+ virtual void unexecute ();
+
+protected:
+ int m_row, m_col;
+ int m_numDeletes;
+ QString m_deletedText;
+};
+
+#endif // __kp_tool_text_h__
+
diff --git a/kolourpaint/views/Makefile.am b/kolourpaint/views/Makefile.am
new file mode 100644
index 00000000..2d771cfc
--- /dev/null
+++ b/kolourpaint/views/Makefile.am
@@ -0,0 +1,14 @@
+INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../cursors -I$(srcdir)/../interfaces \
+ -I$(srcdir)/../pixmapfx \
+ -I$(srcdir)/../tools \
+ -I$(srcdir)/../views \
+ -I$(srcdir)/../widgets $(all_includes)
+
+noinst_LTLIBRARIES = libkolourpaintviews.la
+libkolourpaintviews_la_SOURCES = kpthumbnailview.cpp \
+ kpunzoomedthumbnailview.cpp \
+ kpzoomedthumbnailview.cpp \
+ kpzoomedview.cpp
+
+METASOURCES = AUTO
+
diff --git a/kolourpaint/views/kpthumbnailview.cpp b/kolourpaint/views/kpthumbnailview.cpp
new file mode 100644
index 00000000..32c54376
--- /dev/null
+++ b/kolourpaint/views/kpthumbnailview.cpp
@@ -0,0 +1,98 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_THUMBNAIL_VIEW 0
+
+
+#include <kpthumbnailview.h>
+
+#include <kdebug.h>
+
+
+kpThumbnailView::kpThumbnailView (kpDocument *document,
+ kpToolToolBar *toolToolBar,
+ kpViewManager *viewManager,
+ kpView *buddyView,
+ kpViewScrollableContainer *scrollableContainer,
+ QWidget *parent, const char *name)
+
+ : kpView (document, toolToolBar, viewManager,
+ buddyView,
+ scrollableContainer,
+ parent, name)
+{
+}
+
+kpThumbnailView::~kpThumbnailView ()
+{
+}
+
+
+// protected
+void kpThumbnailView::setMaskToCoverDocument ()
+{
+#if DEBUG_KP_THUMBNAIL_VIEW
+ kdDebug () << "kpThumbnailView::setMaskToCoverDocument()"
+ << " origin=" << origin ()
+ << " zoomedDoc: width=" << zoomedDocWidth ()
+ << " height=" << zoomedDocHeight ()
+ << endl;
+#endif
+
+ setMask (QRegion (QRect (origin ().x (), origin ().y (),
+ zoomedDocWidth (), zoomedDocHeight ())));
+}
+
+
+// protected virtual [base kpView]
+void kpThumbnailView::resizeEvent (QResizeEvent *e)
+{
+#if DEBUG_KP_THUMBNAIL_VIEW
+ kdDebug () << "kpThumbnailView(" << name () << ")::resizeEvent()"
+ << endl;
+#endif
+
+ // For QResizeEvent's, Qt already throws an entire widget repaint into
+ // the event loop. So eat useless update() calls that can only slow
+ // things down.
+ // TODO: this doesn't seem to work.
+ const bool oldIsUpdatesEnabled = isUpdatesEnabled ();
+ setUpdatesEnabled (false);
+
+ {
+ kpView::resizeEvent (e);
+
+ adjustToEnvironment ();
+ }
+
+ setUpdatesEnabled (oldIsUpdatesEnabled);
+}
+
+
+#include <kpthumbnailview.moc>
+
diff --git a/kolourpaint/views/kpthumbnailview.h b/kolourpaint/views/kpthumbnailview.h
new file mode 100644
index 00000000..c3420833
--- /dev/null
+++ b/kolourpaint/views/kpthumbnailview.h
@@ -0,0 +1,90 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef KP_THUMBNAIL_VIEW
+#define KP_THUMBNAIL_VIEW
+
+
+#include <kpview.h>
+
+
+/**
+ * @short Abstract base class for all thumbnail views.
+ *
+ * @author Clarence Dang <dang@kde.org>
+ */
+class kpThumbnailView : public kpView
+{
+Q_OBJECT
+
+public:
+ /**
+ * Constructs a thumbnail view.
+ *
+ * You must call adjustEnvironment() at the end of your constructor.
+ */
+ kpThumbnailView (kpDocument *document,
+ kpToolToolBar *toolToolBar,
+ kpViewManager *viewManager,
+ kpView *buddyView,
+ kpViewScrollableContainer *scrollableContainer,
+ QWidget *parent, const char *name);
+
+ /**
+ * Destructs this thumbnail view.
+ */
+ virtual ~kpThumbnailView ();
+
+
+ /**
+ * @returns the caption to display in an enclosing thumbnail window.
+ */
+ virtual QString caption () const = 0;
+
+
+protected:
+ /**
+ * Sets the mask to cover the rectangle with top-left, origin() and
+ * dimensions equal to or slightly less than (in case of rounding
+ * error) the size of the document in view coordinates. This ensures
+ * that all pixels are initialised with either document pixels or the
+ * standard widget background.
+ */
+ void setMaskToCoverDocument ();
+
+
+ /**
+ * Calls adjustToEnvironment() in response to a resize event.
+ *
+ * Extends @ref kpView.
+ */
+ virtual void resizeEvent (QResizeEvent *e);
+};
+
+
+#endif // KP_THUMBNAIL_VIEW
diff --git a/kolourpaint/views/kpunzoomedthumbnailview.cpp b/kolourpaint/views/kpunzoomedthumbnailview.cpp
new file mode 100644
index 00000000..09d5aed1
--- /dev/null
+++ b/kolourpaint/views/kpunzoomedthumbnailview.cpp
@@ -0,0 +1,212 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_UNZOOMED_THUMBNAIL_VIEW 0
+
+
+#include <kpunzoomedthumbnailview.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpdocument.h>
+#include <kpviewmanager.h>
+#include <kpviewscrollablecontainer.h>
+
+
+struct kpUnzoomedThumbnailViewPrivate
+{
+};
+
+
+kpUnzoomedThumbnailView::kpUnzoomedThumbnailView (
+ kpDocument *document,
+ kpToolToolBar *toolToolBar,
+ kpViewManager *viewManager,
+ kpView *buddyView,
+ kpViewScrollableContainer *scrollableContainer,
+ QWidget *parent, const char *name)
+
+ : kpThumbnailView (document, toolToolBar, viewManager,
+ buddyView,
+ scrollableContainer,
+ parent, name),
+ d (new kpUnzoomedThumbnailViewPrivate ())
+{
+ if (buddyViewScrollableContainer ())
+ {
+ connect (buddyViewScrollableContainer (),
+ SIGNAL (contentsMovingSoon (int, int)),
+ this,
+ SLOT (adjustToEnvironment ()));
+ }
+
+ // Call to virtual function - this is why the class is sealed
+ adjustToEnvironment ();
+}
+
+
+kpUnzoomedThumbnailView::~kpUnzoomedThumbnailView ()
+{
+ delete d;
+}
+
+
+// public virtual [base kpThumbnailView]
+QString kpUnzoomedThumbnailView::caption () const
+{
+ return i18n ("Unzoomed Mode - Thumbnail");
+}
+
+
+// public slot virtual [base kpView]
+void kpUnzoomedThumbnailView::adjustToEnvironment ()
+{
+ if (!buddyView () || !buddyViewScrollableContainer () || !document ())
+ return;
+
+ const int scrollViewContentsX =
+ buddyViewScrollableContainer ()->contentsXSoon ();
+ const int scrollViewContentsY =
+ buddyViewScrollableContainer ()->contentsYSoon ();
+
+#if DEBUG_KP_UNZOOMED_THUMBNAIL_VIEW
+ kdDebug () << "kpUnzoomedThumbnailView(" << name ()
+ << ")::adjustToEnvironment("
+ << scrollViewContentsX
+ << ","
+ << scrollViewContentsY
+ << ") width=" << width ()
+ << " height=" << height ()
+ << endl;
+#endif
+
+
+#if 1
+ int x;
+ if (document ()->width () > width ())
+ {
+ x = (int) buddyView ()->transformViewToDocX (scrollViewContentsX);
+ const int rightMostAllowedX = QMAX (0, document ()->width () - width ());
+ #if DEBUG_KP_UNZOOMED_THUMBNAIL_VIEW
+ kdDebug () << "\tdocX=" << x
+ << " docWidth=" << document ()->width ()
+ << " rightMostAllowedX=" << rightMostAllowedX
+ << endl;
+ #endif
+ if (x > rightMostAllowedX)
+ x = rightMostAllowedX;
+ }
+ // Thumbnail width <= doc width
+ else
+ {
+ // Centre X (rather than flush left to be consistent with
+ // kpZoomedThumbnailView)
+ x = -(width () - document ()->width ()) / 2;
+ }
+
+
+ int y;
+ if (document ()->height () > height ())
+ {
+ y = (int) buddyView ()->transformViewToDocY (scrollViewContentsY);
+ const int bottomMostAllowedY = QMAX (0, document ()->height () - height ());
+ #if DEBUG_KP_UNZOOMED_THUMBNAIL_VIEW
+ kdDebug () << "\tdocY=" << y
+ << " docHeight=" << document ()->height ()
+ << " bottomMostAllowedY=" << bottomMostAllowedY
+ << endl;
+ #endif
+ if (y > bottomMostAllowedY)
+ y = bottomMostAllowedY;
+ }
+ // Thumbnail height <= doc height
+ else
+ {
+ // Centre Y (rather than flush top to be consistent with
+ // kpZoomedThumbnailView)
+ y = -(height () - document ()->height ()) / 2;
+ }
+// Prefer to keep visible area centred in thumbnail instead of flushed left.
+// Gives more editing context to the left and top.
+// But feels awkward for left-to-right users. So disabled for now.
+// Not totally tested.
+#else
+ if (!buddyViewScrollableContainer ())
+ return;
+
+ QRect docRect = buddyView ()->transformViewToDoc (
+ QRect (buddyViewScrollableContainer ()->contentsXSoon (),
+ buddyViewScrollableContainer ()->contentsYSoon (),
+ QMIN (buddyView ()->width (), buddyViewScrollableContainer ()->visibleWidth ()),
+ QMIN (buddyView ()->height (), buddyViewScrollableContainer ()->visibleHeight ())));
+
+ x = docRect.x () - (width () - docRect.width ()) / 2;
+ kdDebug () << "\tnew suggest x=" << x << endl;
+ const int rightMostAllowedX = QMAX (0, document ()->width () - width ());
+ if (x < 0)
+ x = 0;
+ if (x > rightMostAllowedX)
+ x = rightMostAllowedX;
+
+ y = docRect.y () - (height () - docRect.height ()) / 2;
+ kdDebug () << "\tnew suggest y=" << y << endl;
+ const int bottomMostAllowedY = QMAX (0, document ()->height () - height ());
+ if (y < 0)
+ y = 0;
+ if (y > bottomMostAllowedY)
+ y = bottomMostAllowedY;
+#endif
+
+
+ if (viewManager ())
+ {
+ viewManager ()->setFastUpdates ();
+ viewManager ()->setQueueUpdates ();
+ }
+
+ {
+ // OPT: scrollView impl would be much, much faster
+ setOrigin (QPoint (-x, -y));
+ setMaskToCoverDocument ();
+
+ // Above might be a NOP even if e.g. doc size changed so force
+ // update
+ if (viewManager ())
+ viewManager ()->updateView (this);
+ }
+
+ if (viewManager ())
+ {
+ viewManager ()->restoreQueueUpdates ();
+ viewManager ()->restoreFastUpdates ();
+ }
+}
+
+
+#include <kpunzoomedthumbnailview.moc>
diff --git a/kolourpaint/views/kpunzoomedthumbnailview.h b/kolourpaint/views/kpunzoomedthumbnailview.h
new file mode 100644
index 00000000..0f7ccf53
--- /dev/null
+++ b/kolourpaint/views/kpunzoomedthumbnailview.h
@@ -0,0 +1,106 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef KP_UNZOOMED_THUMBNAIL_VIEW_H
+#define KP_UNZOOMED_THUMBNAIL_VIEW_H
+
+
+#include <kpthumbnailview.h>
+
+
+class kpViewScrollableContainer;
+
+
+/**
+ * @short Unzoomed thumbnail view of a document.
+ *
+ * This is an unzoomed thumbnail view of a document. Unlike
+ * @ref kpZoomedThumbnailView, it never changes the zoom level. And unlike
+ * @ref kpZoomedView, it never resizes itself. Instead, it changes its
+ * origin according to the main view's scrollable container so that the
+ * top-left most document pixel displayed in the scrollable container will
+ * be visible.
+ *
+ * Do not call setZoomLevel() nor setOrigin().
+ *
+ * This class is sealed. Do not derive from it.
+ *
+ * @author Clarence Dang <dang@kde.org>
+ */
+/*sealed*/ class kpUnzoomedThumbnailView : public kpThumbnailView
+{
+Q_OBJECT
+
+public:
+ /**
+ * Constructs an unzoomed thumbnail view.
+ */
+ kpUnzoomedThumbnailView (kpDocument *document,
+ kpToolToolBar *toolToolBar,
+ kpViewManager *viewManager,
+ kpView *buddyView,
+ kpViewScrollableContainer *scrollableContainer,
+ QWidget *parent, const char *name);
+
+ /**
+ * Destructs an unzoomed thumbnail view.
+ */
+ virtual ~kpUnzoomedThumbnailView ();
+
+
+ /**
+ * Implements @ref kpThumbnailView.
+ */
+ QString caption () const;
+
+
+public slots:
+ /**
+ * Changes its origin according to the main view's scrollable container
+ * so that the top-left most document pixel displayed in the scrollable
+ * container will be visible.
+ *
+ * It tries to maximise the used area of this view. Unused areas will
+ * be set to the widget background thanks to the mask.
+ *
+ * Call this if the size of the document changes.
+ * Already connected to buddyViewScrollableContainer()'s
+ * contentsMovingSoon(int,int) signal.
+ * Already called by @ref kpThumbnailView resizeEvent().
+ *
+ * Implements @ref kpView.
+ */
+ virtual void adjustToEnvironment ();
+
+
+private:
+ struct kpUnzoomedThumbnailViewPrivate *d;
+};
+
+
+#endif // KP_UNZOOMED_THUMBNAIL_VIEW_H
diff --git a/kolourpaint/views/kpzoomedthumbnailview.cpp b/kolourpaint/views/kpzoomedthumbnailview.cpp
new file mode 100644
index 00000000..ecbfd317
--- /dev/null
+++ b/kolourpaint/views/kpzoomedthumbnailview.cpp
@@ -0,0 +1,140 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_ZOOMED_THUMBNAIL_VIEW 0
+
+
+#include <kpzoomedthumbnailview.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpdocument.h>
+#include <kpviewmanager.h>
+
+
+kpZoomedThumbnailView::kpZoomedThumbnailView (kpDocument *document,
+ kpToolToolBar *toolToolBar,
+ kpViewManager *viewManager,
+ kpView *buddyView,
+ kpViewScrollableContainer *scrollableContainer,
+ QWidget *parent, const char *name)
+
+ : kpThumbnailView (document, toolToolBar, viewManager,
+ buddyView,
+ scrollableContainer,
+ parent, name)
+{
+ // Call to virtual function - this is why the class is sealed
+ adjustToEnvironment ();
+}
+
+
+kpZoomedThumbnailView::~kpZoomedThumbnailView ()
+{
+}
+
+
+// public virtual [base kpThumbnailView]
+QString kpZoomedThumbnailView::caption () const
+{
+ return i18n ("%1% - Thumbnail").arg (zoomLevelX ());
+}
+
+
+// public slot virtual [base kpView]
+void kpZoomedThumbnailView::adjustToEnvironment ()
+{
+#if DEBUG_KP_ZOOMED_THUMBNAIL_VIEW
+ kdDebug () << "kpZoomedThumbnailView(" << name ()
+ << ")::adjustToEnvironment()"
+ << " width=" << width ()
+ << " height=" << height ()
+ << endl;
+#endif
+
+ if (!document ())
+ return;
+
+#if DEBUG_KP_ZOOMED_THUMBNAIL_VIEW
+ kdDebug () << "\tdoc: width=" << document ()->width ()
+ << " height=" << document ()->height ()
+ << endl;
+#endif
+
+ if (document ()->width () <= 0 || document ()->height () <= 0)
+ {
+ kdError () << "kpZoomedThumbnailView::adjustToEnvironment() doc:"
+ << " width=" << document ()->width ()
+ << " height=" << document ()->height ()
+ << endl;
+ return;
+ }
+
+
+ int hzoom = QMAX (1, width () * 100 / document ()->width ());
+ int vzoom = QMAX (1, height () * 100 / document ()->height ());
+
+ // keep aspect ratio
+ if (hzoom < vzoom)
+ vzoom = hzoom;
+ else
+ hzoom = vzoom;
+
+#if DEBUG_KP_ZOOMED_THUMBNAIL_VIEW && 1
+ kdDebug () << "\tproposed zoom=" << hzoom << endl;
+#endif
+ if (hzoom > 100 || vzoom > 100)
+ {
+ #if DEBUG_KP_ZOOMED_THUMBNAIL_VIEW && 1
+ kdDebug () << "\twon't magnify - setting zoom to 100%" << endl;
+ #endif
+ hzoom = 100, vzoom = 100;
+ }
+
+
+ if (viewManager ())
+ viewManager ()->setQueueUpdates ();
+
+ {
+ setZoomLevel (hzoom, vzoom);
+
+ setOrigin (QPoint ((width () - zoomedDocWidth ()) / 2,
+ (height () - zoomedDocHeight ()) / 2));
+ setMaskToCoverDocument ();
+
+ if (viewManager ())
+ viewManager ()->updateView (this);
+ }
+
+ if (viewManager ())
+ viewManager ()->restoreQueueUpdates ();
+}
+
+
+#include <kpzoomedthumbnailview.moc>
diff --git a/kolourpaint/views/kpzoomedthumbnailview.h b/kolourpaint/views/kpzoomedthumbnailview.h
new file mode 100644
index 00000000..0bcb367c
--- /dev/null
+++ b/kolourpaint/views/kpzoomedthumbnailview.h
@@ -0,0 +1,95 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef KP_ZOOMED_THUMBNAIL_VIEW_H
+#define KP_ZOOMED_THUMBNAIL_VIEW_H
+
+
+#include <kpthumbnailview.h>
+
+
+/**
+ * @short Zoomed thumbnail view of a document.
+ *
+ * This is a zoomed thumbnail view of a document. Unlike @ref kpZoomedView,
+ * it never resizes itself. Instead, it changes its zoom level to
+ * accommodate the display of entire document in the view, while
+ * maintaining aspect.
+ *
+ * Do not call setZoomLevel() nor setOrigin().
+ *
+ * This class is sealed. Do not derive from it.
+ *
+ * @author Clarence Dang <dang@kde.org>
+ */
+/*sealed*/ class kpZoomedThumbnailView : public kpThumbnailView
+{
+Q_OBJECT
+
+public:
+ /**
+ * Constructs a zoomed thumbnail view.
+ */
+ kpZoomedThumbnailView (kpDocument *document,
+ kpToolToolBar *toolToolBar,
+ kpViewManager *viewManager,
+ kpView *buddyView,
+ kpViewScrollableContainer *scrollableContainer,
+ QWidget *parent, const char *name);
+
+ /**
+ * Destructs a zoomed thumbnail view.
+ */
+ virtual ~kpZoomedThumbnailView ();
+
+
+ /**
+ * Implements @ref kpThumbnailView.
+ */
+ QString caption () const;
+
+
+public slots:
+ /**
+ * Changes its zoom level to accommodate the display of entire document
+ * in the view. It maintains aspect by changing the origin and mask.
+ *
+ * Call this if the size of the document changes.
+ * Already called by @ref kpThumbnailView resizeEvent().
+ *
+ * Implements @ref kpView.
+ */
+ virtual void adjustToEnvironment ();
+
+
+private:
+ struct kpZoomedThumbnailViewPrivate *d;
+};
+
+
+#endif // KP_ZOOMED_THUMBNAIL_VIEW_H
diff --git a/kolourpaint/views/kpzoomedview.cpp b/kolourpaint/views/kpzoomedview.cpp
new file mode 100644
index 00000000..ef1d6981
--- /dev/null
+++ b/kolourpaint/views/kpzoomedview.cpp
@@ -0,0 +1,103 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_ZOOMED_VIEW 0
+
+
+#include <kpzoomedview.h>
+
+#include <kdebug.h>
+
+#include <kpdocument.h>
+#include <kpview.h>
+#include <kpviewmanager.h>
+
+
+kpZoomedView::kpZoomedView (kpDocument *document,
+ kpToolToolBar *toolToolBar,
+ kpViewManager *viewManager,
+ kpView *buddyView,
+ kpViewScrollableContainer *scrollableContainer,
+ QWidget *parent, const char *name)
+
+ : kpView (document, toolToolBar, viewManager,
+ buddyView,
+ scrollableContainer,
+ parent, name)
+{
+ // Call to virtual function - this is why the class is sealed
+ adjustToEnvironment ();
+}
+
+kpZoomedView::~kpZoomedView ()
+{
+}
+
+
+// public virtual [base kpView]
+void kpZoomedView::setZoomLevel (int hzoom, int vzoom)
+{
+#if DEBUG_KP_ZOOMED_VIEW
+ kdDebug () << "kpZoomedView(" << name () << ")::setZoomLevel("
+ << hzoom << "," << vzoom << ")" << endl;
+#endif
+
+ if (viewManager ())
+ viewManager ()->setQueueUpdates ();
+
+ {
+ kpView::setZoomLevel (hzoom, vzoom);
+
+ adjustToEnvironment ();
+ }
+
+ if (viewManager ())
+ viewManager ()->restoreQueueUpdates ();
+}
+
+
+// public slot virtual [base kpView]
+void kpZoomedView::adjustToEnvironment ()
+{
+#if DEBUG_KP_ZOOMED_VIEW
+ kdDebug () << "kpZoomedView(" << name () << ")::adjustToEnvironment()"
+ << " doc: width=" << document ()->width ()
+ << " height=" << document ()->height ()
+ << endl;
+#endif
+
+ if (document ())
+ {
+ // TODO: use zoomedDocWidth() & zoomedDocHeight()?
+ resize ((int) transformDocToViewX (document ()->width ()),
+ (int) transformDocToViewY (document ()->height ()));
+ }
+}
+
+
+#include <kpzoomedview.moc>
diff --git a/kolourpaint/views/kpzoomedview.h b/kolourpaint/views/kpzoomedview.h
new file mode 100644
index 00000000..c3729282
--- /dev/null
+++ b/kolourpaint/views/kpzoomedview.h
@@ -0,0 +1,96 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef KP_ZOOMED_VIEW_H
+#define KP_ZOOMED_VIEW_H
+
+
+#include <kpview.h>
+
+
+/**
+ * @short Zoomed view of a document. Suitable as an ordinary editing view.
+ *
+ * This is a zoomed view of a document. It resizes according to the size
+ * of the document and the zoom level. Do not manually call resize() for
+ * this reason.
+ *
+ * It is suitable as an ordinary editing view.
+ *
+ * Do not call setOrigin().
+ *
+ * This class is sealed. Do not derive from it.
+ *
+ * @author Clarence Dang <dang@kde.org>
+ */
+/*sealed*/ class kpZoomedView : public kpView
+{
+Q_OBJECT
+
+public:
+ /**
+ * Constructs a zoomed view.
+ */
+ kpZoomedView (kpDocument *document,
+ kpToolToolBar *toolToolBar,
+ kpViewManager *viewManager,
+ kpView *buddyView,
+ kpViewScrollableContainer *scrollableContainer,
+ QWidget *parent, const char *name);
+
+ /**
+ * Destructs an unzoomed view.
+ */
+ virtual ~kpZoomedView ();
+
+
+ /**
+ * Extends @kpView. Calls adjustToEnvironment().
+ */
+ virtual void setZoomLevel (int hzoom, int vzoom);
+
+
+public slots:
+ /**
+ * Resizes itself so that the entire document in the zoom level fits
+ * almost perfectly.
+ *
+ * Call this if the size of the document changes.
+ * Already called by setZoomLevel().
+ *
+ * Implements @ref kpView.
+ */
+ virtual void adjustToEnvironment ();
+
+
+private:
+ struct kpZoomedViewPrivate *d;
+};
+
+
+#endif // KP_ZOOMED_VIEW_H
diff --git a/kolourpaint/widgets/Makefile.am b/kolourpaint/widgets/Makefile.am
new file mode 100644
index 00000000..f6501fac
--- /dev/null
+++ b/kolourpaint/widgets/Makefile.am
@@ -0,0 +1,21 @@
+INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../cursors -I$(srcdir)/../interfaces \
+ -I$(srcdir)/../pixmapfx \
+ -I$(srcdir)/../tools \
+ -I$(srcdir)/../views \
+ -I$(srcdir)/../widgets $(all_includes)
+
+noinst_LTLIBRARIES = libkolourpaintwidgets.la
+libkolourpaintwidgets_la_SOURCES = kpcolorsimilaritycube.cpp \
+ kpcolorsimilaritydialog.cpp \
+ kpcolortoolbar.cpp \
+ kpresizesignallinglabel.cpp \
+ kpsqueezedtextlabel.cpp \
+ kptooltoolbar.cpp \
+ kptoolwidgetbase.cpp kptoolwidgetbrush.cpp \
+ kptoolwidgeterasersize.cpp kptoolwidgetfillstyle.cpp \
+ kptoolwidgetlinewidth.cpp \
+ kptoolwidgetopaqueortransparent.cpp \
+ kptoolwidgetspraycansize.cpp
+
+METASOURCES = AUTO
+
diff --git a/kolourpaint/widgets/kpcolorsimilaritycube.cpp b/kolourpaint/widgets/kpcolorsimilaritycube.cpp
new file mode 100644
index 00000000..9fe3f29b
--- /dev/null
+++ b/kolourpaint/widgets/kpcolorsimilaritycube.cpp
@@ -0,0 +1,348 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_COLOR_SIMILARITY_CUBE 0
+
+
+#include <kpcolorsimilaritycube.h>
+
+#include <math.h>
+
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qwhatsthis.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcolor.h>
+#include <kpcolorsimilaritydialog.h>
+#include <kpdefs.h>
+
+
+const double kpColorSimilarityCube::colorCubeDiagonalDistance =
+ sqrt (255 * 255 * 3);
+
+kpColorSimilarityCube::kpColorSimilarityCube (int look,
+ kpMainWindow *mainWindow,
+ QWidget *parent,
+ const char *name)
+ : QFrame (parent, name, Qt::WNoAutoErase/*no flicker*/),
+ m_mainWindow (mainWindow),
+ m_colorSimilarity (-1)
+{
+ if (look & Depressed)
+ setFrameStyle (QFrame::Panel | QFrame::Sunken);
+
+ setColorSimilarity (0);
+
+
+ // Don't cause the translators grief by appending strings
+ // - duplicate text with 2 cases
+
+ if (look & DoubleClickInstructions)
+ {
+ QWhatsThis::add (this,
+ i18n ("<qt><p><b>Color Similarity</b> is how close "
+ "colors must be in the RGB Color Cube "
+ "to be considered the same.</p>"
+
+ "<p>If you set it to something "
+ "other than <b>Exact</b>, "
+ "you can work more effectively with dithered "
+ "images and photos.</p>"
+
+ "<p>This feature applies to transparent selections, as well as "
+ "the Flood Fill, Color Eraser and Autocrop "
+ "tools.</p>"
+
+ // sync: different to else case
+ "<p>To configure it, double click on the cube.</p>"
+
+ "</qt>"));
+ }
+ else
+ {
+ QWhatsThis::add (this,
+ i18n ("<qt><p><b>Color Similarity</b> is how close "
+ "colors must be in the RGB Color Cube "
+ "to be considered the same.</p>"
+
+ "<p>If you set it to something "
+ "other than <b>Exact</b>, "
+ "you can work more effectively with dithered "
+ "images and photos.</p>"
+
+ "<p>This feature applies to transparent selections, as well as "
+ "the Flood Fill, Color Eraser and Autocrop "
+ "tools.</p>"
+
+ "</qt>"));
+ }
+}
+
+kpColorSimilarityCube::~kpColorSimilarityCube ()
+{
+}
+
+
+// public
+double kpColorSimilarityCube::colorSimilarity () const
+{
+ return m_colorSimilarity;
+}
+
+// public
+void kpColorSimilarityCube::setColorSimilarity (double similarity)
+{
+#if DEBUG_KP_COLOR_SIMILARITY_CUBE
+ kdDebug () << "kpColorSimilarityCube::setColorSimilarity(" << similarity << ")" << endl;
+#endif
+
+ if (m_colorSimilarity == similarity)
+ return;
+
+ if (similarity < 0)
+ similarity = 0;
+ else if (similarity > kpColorSimilarityDialog::maximumColorSimilarity)
+ similarity = kpColorSimilarityDialog::maximumColorSimilarity;
+
+ m_colorSimilarity = similarity;
+
+ repaint (false/*no erase*/);
+}
+
+
+// protected virtual [base QWidget]
+QSize kpColorSimilarityCube::sizeHint () const
+{
+ return QSize (52, 52);
+}
+
+
+// protected
+QColor kpColorSimilarityCube::color (int redOrGreenOrBlue,
+ int baseBrightness,
+ int similarityDirection) const
+{
+ int brightness = int (baseBrightness +
+ similarityDirection *
+ .5 * m_colorSimilarity * kpColorSimilarityCube::colorCubeDiagonalDistance);
+
+ if (brightness < 0)
+ brightness = 0;
+ else if (brightness > 255)
+ brightness = 255;
+
+ switch (redOrGreenOrBlue)
+ {
+ default:
+ case 0: return QColor (brightness, 0, 0);
+ case 1: return QColor (0, brightness, 0);
+ case 2: return QColor (0, 0, brightness);
+ }
+}
+
+static QPoint pointBetween (const QPoint &p, const QPoint &q)
+{
+ return QPoint ((p.x () + q.x ()) / 2, (p.y () + q.y ()) / 2);
+}
+
+static void drawQuadrant (QPainter *p,
+ const QColor &col,
+ const QPoint &p1, const QPoint &p2, const QPoint &p3,
+ const QPoint pointNotOnOutline)
+{
+ p->save ();
+
+
+ QPointArray points (4);
+ points [0] = p1;
+ points [1] = p2;
+ points [2] = p3;
+ points [3] = pointNotOnOutline;
+
+ p->setPen (col);
+ p->setBrush (col);
+ p->drawPolygon (points);
+
+
+ points.resize (3);
+
+ p->setPen (Qt::black);
+ p->setBrush (Qt::NoBrush);
+ p->drawPolyline (points);
+
+
+ p->restore ();
+}
+
+// protected
+void kpColorSimilarityCube::drawFace (QPainter *p,
+ int redOrGreenOrBlue,
+ const QPoint &tl, const QPoint &tr,
+ const QPoint &bl, const QPoint &br)
+{
+#if DEBUG_KP_COLOR_SIMILARITY_CUBE
+ kdDebug () << "kpColorSimilarityCube(RorGorB=" << redOrGreenOrBlue
+ << ",tl=" << tl
+ << ",tr=" << tr
+ << ",bl=" << bl
+ << ",br=" << br
+ << ")"
+ << endl;
+#endif
+
+ // tl --- tm --- tr
+ // | | |
+ // | | |
+ // ml --- mm --- mr
+ // | | |
+ // | | |
+ // bl --- bm --- br
+
+ const QPoint tm (::pointBetween (tl, tr));
+ const QPoint bm (::pointBetween (bl, br));
+
+ const QPoint ml (::pointBetween (tl, bl));
+ const QPoint mr (::pointBetween (tr, br));
+ const QPoint mm (::pointBetween (ml, mr));
+
+
+ const int baseBrightness = QMAX (127,
+ 255 - int (kpColorSimilarityDialog::maximumColorSimilarity *
+ kpColorSimilarityCube::colorCubeDiagonalDistance / 2));
+ QColor colors [2] =
+ {
+ color (redOrGreenOrBlue, baseBrightness, -1),
+ color (redOrGreenOrBlue, baseBrightness, +1)
+ };
+
+ if (!isEnabled ())
+ {
+ #if DEBUG_KP_COLOR_SIMILARITY_CUBE
+ kdDebug () << "\tnot enabled - making us grey" << endl;
+ #endif
+ colors [0] = colorGroup ().background ();
+ colors [1] = colorGroup ().background ();
+ }
+
+#if DEBUG_KP_COLOR_SIMILARITY_CUBE
+ kdDebug () << "\tmaxColorSimilarity=" << kpColorSimilarityDialog::maximumColorSimilarity
+ << " colorCubeDiagDist=" << kpColorSimilarityCube::colorCubeDiagonalDistance
+ << endl
+ << "\tbaseBrightness=" << baseBrightness
+ << " color[0]=" << ((colors [0].rgb () & RGB_MASK) >> ((2 - redOrGreenOrBlue) * 8))
+ << " color[1]=" << ((colors [1].rgb () & RGB_MASK) >> ((2 - redOrGreenOrBlue) * 8))
+ << endl;
+#endif
+
+
+ ::drawQuadrant (p, colors [0], tm, tl, ml, mm);
+ ::drawQuadrant (p, colors [1], tm, tr, mr, mm);
+ ::drawQuadrant (p, colors [1], ml, bl, bm, mm);
+ ::drawQuadrant (p, colors [0], bm, br, mr, mm);
+}
+
+// protected virtual [base QFrame]
+void kpColorSimilarityCube::drawContents (QPainter *p)
+{
+ QRect cr (contentsRect ());
+
+ QPixmap backBuffer (cr.width (), cr.height ());
+ backBuffer.fill (colorGroup ().background ());
+
+ QPainter backBufferPainter (&backBuffer);
+
+ int cubeRectSize = QMIN (cr.width () * 6 / 8, cr.height () * 6 / 8);
+ int dx = (cr.width () - cubeRectSize) / 2,
+ dy = (cr.height () - cubeRectSize) / 2;
+ backBufferPainter.translate (dx, dy);
+
+ //
+ // P------- Q --- ---
+ // / / | | |
+ // /A / | side |
+ // R-------S T --- cubeRectSize
+ // | | / / |
+ // S | | / side |
+ // U-------V --- ---
+ // |-------|
+ // side
+ // |-----------|
+ // cubeRectSize
+ //
+ //
+
+ const double angle = KP_DEGREES_TO_RADIANS (45);
+ // S + S sin A = cubeRectSize
+ // (1 + sin A) x S = cubeRectSize
+ const double side = double (cubeRectSize) / (1 + sin (angle));
+
+
+ const QPoint pointP ((int) (side * cos (angle)), 0);
+ const QPoint pointQ ((int) (side * cos (angle) + side), 0);
+ const QPoint pointR (0, (int) (side * sin (angle)));
+ const QPoint pointS ((int) (side), (int) (side * sin (angle)));
+ const QPoint pointU (0, (int) (side * sin (angle) + side));
+ const QPoint pointT ((int) (side + side * cos (angle)), (int) (side));
+ const QPoint pointV ((int) (side), (int) (side * sin (angle) + side));
+
+
+ // Top Face
+ drawFace (&backBufferPainter,
+ 0/*red*/,
+ pointP, pointQ,
+ pointR, pointS);
+
+
+ // Bottom Face
+ drawFace (&backBufferPainter,
+ 1/*green*/,
+ pointR, pointS,
+ pointU, pointV);
+
+
+ // Right Face
+ drawFace (&backBufferPainter,
+ 2/*blue*/,
+ pointS, pointQ,
+ pointV, pointT);
+
+
+#if 0
+ backBufferPainter.save ();
+ backBufferPainter.setPen (Qt::cyan);
+ backBufferPainter.drawRect (0, 0, cubeRectSize, cubeRectSize);
+ backBufferPainter.restore ();
+#endif
+
+
+ backBufferPainter.end ();
+
+ p->drawPixmap (cr, backBuffer);
+}
diff --git a/kolourpaint/widgets/kpcolorsimilaritycube.h b/kolourpaint/widgets/kpcolorsimilaritycube.h
new file mode 100644
index 00000000..358d4b3a
--- /dev/null
+++ b/kolourpaint/widgets/kpcolorsimilaritycube.h
@@ -0,0 +1,72 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kp_color_similarity_cube_h__
+#define __kp_color_similarity_cube_h__
+
+#include <qframe.h>
+
+class kpColor;
+class kpMainWindow;
+
+class kpColorSimilarityCube : public QFrame
+{
+public:
+ enum Look
+ {
+ Plain = 0,
+ Depressed = 1,
+ DoubleClickInstructions = 2
+ };
+
+ kpColorSimilarityCube (int look,
+ kpMainWindow *mainWindow,
+ QWidget *parent,
+ const char *name = 0);
+ virtual ~kpColorSimilarityCube ();
+
+ static const double colorCubeDiagonalDistance;
+
+ double colorSimilarity () const;
+ void setColorSimilarity (double similarity);
+
+ virtual QSize sizeHint () const;
+
+protected:
+ QColor color (int redOrGreenOrBlue, int baseBrightness, int similarityDirection) const;
+ void drawFace (QPainter *p,
+ int redOrGreenOrBlue,
+ const QPoint &tl, const QPoint &tr,
+ const QPoint &bl, const QPoint &br);
+ virtual void drawContents (QPainter *p);
+
+ kpMainWindow *m_mainWindow;
+ double m_colorSimilarity;
+};
+
+#endif // __kp_color_similarity_cube_h__
diff --git a/kolourpaint/widgets/kpcolorsimilaritydialog.cpp b/kolourpaint/widgets/kpcolorsimilaritydialog.cpp
new file mode 100644
index 00000000..d2766568
--- /dev/null
+++ b/kolourpaint/widgets/kpcolorsimilaritydialog.cpp
@@ -0,0 +1,123 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <kpcolorsimilaritydialog.h>
+
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+
+#include <klocale.h>
+#include <knuminput.h>
+
+#include <kpcolorsimilaritycube.h>
+
+
+// public static
+const double kpColorSimilarityDialog::maximumColorSimilarity = .30;
+
+
+kpColorSimilarityDialog::kpColorSimilarityDialog (kpMainWindow *mainWindow,
+ QWidget *parent,
+ const char *name)
+ : KDialogBase (parent, name, true/*modal*/,
+ i18n ("Color Similarity"),
+ KDialogBase::Ok | KDialogBase::Cancel),
+ m_mainWindow (mainWindow)
+{
+ QWidget *baseWidget = new QWidget (this);
+ setMainWidget (baseWidget);
+
+
+ QGroupBox *cubeGroupBox = new QGroupBox (i18n ("Preview"), baseWidget);
+
+ m_colorSimilarityCube = new kpColorSimilarityCube (kpColorSimilarityCube::Plain,
+ mainWindow, cubeGroupBox);
+ m_colorSimilarityCube->setMinimumSize (240, 180);
+
+ QPushButton *updatePushButton = new QPushButton (i18n ("&Update"), cubeGroupBox);
+
+
+ QVBoxLayout *cubeLayout = new QVBoxLayout (cubeGroupBox, marginHint () * 2, spacingHint ());
+ cubeLayout->addWidget (m_colorSimilarityCube, 1/*stretch*/);
+ cubeLayout->addWidget (updatePushButton, 0/*stretch*/, Qt::AlignHCenter);
+
+
+ connect (updatePushButton, SIGNAL (clicked ()),
+ this, SLOT (slotColorSimilarityValueChanged ()));
+
+
+ QGroupBox *inputGroupBox = new QGroupBox (i18n ("RGB Color Cube Distance"), baseWidget);
+
+ m_colorSimilarityInput = new KIntNumInput (inputGroupBox);
+ m_colorSimilarityInput->setRange (0, int (kpColorSimilarityDialog::maximumColorSimilarity * 100 + .1/*don't floor below target int*/),
+ 5/*step*/, true/*slider*/);
+ m_colorSimilarityInput->setSuffix (i18n ("%"));
+ m_colorSimilarityInput->setSpecialValueText (i18n ("Exact Match"));
+
+
+ QVBoxLayout *inputLayout = new QVBoxLayout (inputGroupBox, marginHint () * 2, spacingHint ());
+ inputLayout->addWidget (m_colorSimilarityInput);
+
+
+ connect (m_colorSimilarityInput, SIGNAL (valueChanged (int)),
+ this, SLOT (slotColorSimilarityValueChanged ()));
+
+
+ QVBoxLayout *baseLayout = new QVBoxLayout (baseWidget, 0/*margin*/, spacingHint () * 2);
+ baseLayout->addWidget (cubeGroupBox, 1/*stretch*/);
+ baseLayout->addWidget (inputGroupBox);
+}
+
+kpColorSimilarityDialog::~kpColorSimilarityDialog ()
+{
+}
+
+
+// public
+double kpColorSimilarityDialog::colorSimilarity () const
+{
+ return m_colorSimilarityCube->colorSimilarity ();
+}
+
+// public
+void kpColorSimilarityDialog::setColorSimilarity (double similarity)
+{
+ m_colorSimilarityInput->setValue (qRound (similarity * 100));
+}
+
+
+// private slot
+void kpColorSimilarityDialog::slotColorSimilarityValueChanged ()
+{
+ m_colorSimilarityCube->setColorSimilarity (double (m_colorSimilarityInput->value ()) / 100);
+}
+
+
+#include <kpcolorsimilaritydialog.moc>
diff --git a/kolourpaint/widgets/kpcolorsimilaritydialog.h b/kolourpaint/widgets/kpcolorsimilaritydialog.h
new file mode 100644
index 00000000..fd70ecd0
--- /dev/null
+++ b/kolourpaint/widgets/kpcolorsimilaritydialog.h
@@ -0,0 +1,62 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __kp_color_similarity_dialog_h__
+#define __kp_color_similarity_dialog_h__
+
+#include <kdialogbase.h>
+
+class KIntNumInput;
+
+class kpColorSimilarityCube;
+class kpMainWindow;
+
+class kpColorSimilarityDialog : public KDialogBase
+{
+Q_OBJECT
+
+public:
+ kpColorSimilarityDialog (kpMainWindow *mainWindow,
+ QWidget *parent,
+ const char *name = 0);
+ virtual ~kpColorSimilarityDialog ();
+
+ double colorSimilarity () const;
+ void setColorSimilarity (double similarity);
+
+ static const double maximumColorSimilarity;
+
+private slots:
+ void slotColorSimilarityValueChanged ();
+
+private:
+ kpMainWindow *m_mainWindow;
+ kpColorSimilarityCube *m_colorSimilarityCube;
+ KIntNumInput *m_colorSimilarityInput;
+};
+
+#endif // __kp_color_similarity_dialog_h__
diff --git a/kolourpaint/widgets/kpcolortoolbar.cpp b/kolourpaint/widgets/kpcolortoolbar.cpp
new file mode 100644
index 00000000..cba73b4f
--- /dev/null
+++ b/kolourpaint/widgets/kpcolortoolbar.cpp
@@ -0,0 +1,1112 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_COLOR_TOOL_BAR 0
+
+
+#include <kpcolortoolbar.h>
+
+#include <qbitmap.h>
+#include <qdrawutil.h>
+#include <qframe.h>
+#include <qlayout.h>
+#include <qpainter.h>
+#include <qsize.h>
+#include <qtooltip.h>
+#include <qwidget.h>
+
+#include <kapplication.h>
+#include <kcolordialog.h>
+#include <kcolordrag.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <klocale.h>
+
+#include <kpcolorsimilaritydialog.h>
+#include <kpdefs.h>
+#include <kpmainwindow.h>
+#include <kppixmapfx.h>
+#include <kptool.h>
+#include <kpview.h>
+
+
+/*
+ * kpDualColorButton
+ */
+
+kpDualColorButton::kpDualColorButton (kpMainWindow *mainWindow,
+ QWidget *parent, const char *name)
+ : QFrame (parent, name, Qt::WNoAutoErase/*no flicker*/),
+ m_mainWindow (mainWindow),
+ m_backBuffer (0)
+{
+ setFrameStyle (QFrame::Panel | QFrame::Sunken);
+
+ m_color [0] = kpColor (0, 0, 0); // black
+ m_color [1] = kpColor (255, 255, 255); // white
+
+ setAcceptDrops (true);
+}
+
+kpDualColorButton::~kpDualColorButton ()
+{
+ delete m_backBuffer; m_backBuffer = 0;
+}
+
+
+kpColor kpDualColorButton::color (int which) const
+{
+ if (which < 0 || which > 1)
+ {
+ kdWarning () << "kpDualColorButton::color (" << which
+ << ") - out of range" << endl;
+ which = 0;
+ }
+
+ return m_color [which];
+}
+
+kpColor kpDualColorButton::foregroundColor () const
+{
+ return color (0);
+}
+
+kpColor kpDualColorButton::backgroundColor () const
+{
+ return color (1);
+}
+
+
+void kpDualColorButton::setColor (int which, const kpColor &color)
+{
+ if (which < 0 || which > 1)
+ {
+ kdWarning () << "kpDualColorButton::setColor (" << which
+ << ") - out of range" << endl;
+ which = 0;
+ }
+
+ if (m_color [which] == color)
+ return;
+
+ m_oldColor [which] = m_color [which];
+ m_color [which] = color;
+ update ();
+
+ if (which == 0)
+ emit foregroundColorChanged (color);
+ else
+ emit backgroundColorChanged (color);
+}
+
+void kpDualColorButton::setForegroundColor (const kpColor &color)
+{
+ setColor (0, color);
+}
+
+void kpDualColorButton::setBackgroundColor (const kpColor &color)
+{
+ setColor (1, color);
+}
+
+
+// public
+kpColor kpDualColorButton::oldForegroundColor () const
+{
+ return m_oldColor [0];
+}
+
+// public
+kpColor kpDualColorButton::oldBackgroundColor () const
+{
+ return m_oldColor [1];
+}
+
+
+// public virtual [base QWidget]
+QSize kpDualColorButton::sizeHint () const
+{
+ return QSize (52, 52);
+}
+
+
+// protected
+QRect kpDualColorButton::swapPixmapRect () const
+{
+ QPixmap swapPixmap = UserIcon ("colorbutton_swap_16x16");
+
+ return QRect (contentsRect ().width () - swapPixmap.width (),
+ 0,
+ swapPixmap.width (),
+ swapPixmap.height ());
+}
+
+// protected
+QRect kpDualColorButton::foregroundBackgroundRect () const
+{
+ QRect cr (contentsRect ());
+ return QRect (cr.width () / 8,
+ cr.height () / 8,
+ cr.width () * 6 / 8,
+ cr.height () * 6 / 8);
+}
+
+// protected
+QRect kpDualColorButton::foregroundRect () const
+{
+ QRect fbr (foregroundBackgroundRect ());
+ return QRect (fbr.x (),
+ fbr.y (),
+ fbr.width () * 3 / 4,
+ fbr.height () * 3 / 4);
+}
+
+// protected
+QRect kpDualColorButton::backgroundRect () const
+{
+ QRect fbr (foregroundBackgroundRect ());
+ return QRect (fbr.x () + fbr.width () / 4,
+ fbr.y () + fbr.height () / 4,
+ fbr.width () * 3 / 4,
+ fbr.height () * 3 / 4);
+}
+
+
+// TODO: drag a colour from this widget
+
+// protected virtual [base QWidget]
+void kpDualColorButton::dragMoveEvent (QDragMoveEvent *e)
+{
+ e->accept ((foregroundRect ().contains (e->pos ()) ||
+ backgroundRect ().contains (e->pos ())) &&
+ KColorDrag::canDecode (e));
+}
+
+// protected virtual [base QWidget]
+void kpDualColorButton::dropEvent (QDropEvent *e)
+{
+ QColor col;
+ KColorDrag::decode (e, col/*ref*/);
+
+ if (col.isValid ())
+ {
+ if (foregroundRect ().contains (e->pos ()))
+ setForegroundColor (kpColor (col.rgb ()));
+ else if (backgroundRect ().contains (e->pos ()))
+ setBackgroundColor (kpColor (col.rgb ()));
+ }
+}
+
+
+// protected virtual [base QWidget]
+void kpDualColorButton::mousePressEvent (QMouseEvent * /*e*/)
+{
+ // eat right-mouse click to prevent it from getting to the toolbar
+}
+
+// protected virtual [base QWidget]
+void kpDualColorButton::mouseDoubleClickEvent (QMouseEvent *e)
+{
+ int whichColor = -1;
+
+ if (foregroundRect ().contains (e->pos ()))
+ whichColor = 0;
+ else if (backgroundRect ().contains (e->pos ()))
+ whichColor = 1;
+
+ if (whichColor == 0 || whichColor == 1)
+ {
+ QColor col = Qt::black;
+ if (color (whichColor).isOpaque ())
+ col = color (whichColor).toQColor ();
+ else
+ {
+ // TODO: If you double-click on a transparent color and press OK, you get
+ // black, instead of the color staying as transparent.
+ //
+ // We should modify or fork KColorDialog to allow us to fix this.
+ //
+ // It would be wrong to stop the user from double-clicking on a
+ // transparent color as that would make the UI inconsistent, compared
+ // to opaque colors.
+ }
+
+ // TODO: parent
+ if (KColorDialog::getColor (col/*ref*/))
+ setColor (whichColor, kpColor (col.rgb ()));
+ }
+}
+
+// protected virtual [base QWidget]
+void kpDualColorButton::mouseReleaseEvent (QMouseEvent *e)
+{
+ if (swapPixmapRect ().contains (e->pos ()) &&
+ m_color [0] != m_color [1])
+ {
+ #if DEBUG_KP_COLOR_TOOL_BAR && 1
+ kdDebug () << "kpDualColorButton::mouseReleaseEvent() swap colors:" << endl;
+ #endif
+ m_oldColor [0] = m_color [0];
+ m_oldColor [1] = m_color [1];
+
+ kpColor temp = m_color [0];
+ m_color [0] = m_color [1];
+ m_color [1] = temp;
+
+ update ();
+
+ emit colorsSwapped (m_color [0], m_color [1]);
+ emit foregroundColorChanged (m_color [0]);
+ emit backgroundColorChanged (m_color [1]);
+ }
+}
+
+
+// protected virtual [base QFrame]
+void kpDualColorButton::drawContents (QPainter *p)
+{
+#if DEBUG_KP_COLOR_TOOL_BAR && 1
+ kdDebug () << "kpDualColorButton::draw() rect=" << rect ()
+ << " contentsRect=" << contentsRect ()
+ << endl;
+#endif
+
+ if (!m_backBuffer ||
+ m_backBuffer->width () != contentsRect ().width () ||
+ m_backBuffer->height () != contentsRect ().height ())
+ {
+ delete m_backBuffer;
+ m_backBuffer = new QPixmap (contentsRect ().width (), contentsRect ().height ());
+ }
+
+
+ QPainter backBufferPainter (m_backBuffer);
+
+ if (isEnabled () && m_mainWindow)
+ {
+ kpView::drawTransparentBackground (&backBufferPainter,
+ m_backBuffer->width (), m_backBuffer->height (),
+ m_backBuffer->rect (),
+ true/*preview*/);
+ }
+ else
+ {
+ backBufferPainter.fillRect (m_backBuffer->rect (),
+ colorGroup ().color (QColorGroup::Background));
+ }
+
+ QPixmap swapPixmap = UserIcon ("colorbutton_swap_16x16");
+ if (!isEnabled ())
+ {
+ // swapPixmap has a mask after all
+ swapPixmap.fill (colorGroup ().color (QColorGroup::Dark));
+ }
+ backBufferPainter.drawPixmap (swapPixmapRect ().topLeft (), swapPixmap);
+
+ // foreground patch must be drawn after background patch
+ // as it overlaps on top of background patch
+ QRect bgRect = backgroundRect ();
+ QRect bgRectInside = QRect (bgRect.x () + 2, bgRect.y () + 2,
+ bgRect.width () - 4, bgRect.height () - 4);
+ if (isEnabled ())
+ {
+ #if DEBUG_KP_COLOR_TOOL_BAR && 1
+ kdDebug () << "\tbackgroundColor=" << (int *) m_color [1].toQRgb ()
+ << endl;
+ #endif
+ if (m_color [1].isOpaque ())
+ backBufferPainter.fillRect (bgRectInside, m_color [1].toQColor ());
+ else
+ backBufferPainter.drawPixmap (bgRectInside, UserIcon ("color_transparent_26x26"));
+ }
+ else
+ backBufferPainter.fillRect (bgRectInside, colorGroup ().color (QColorGroup::Button));
+ qDrawShadePanel (&backBufferPainter, bgRect, colorGroup (),
+ false/*not sunken*/, 2/*lineWidth*/,
+ 0/*never fill*/);
+
+ QRect fgRect = foregroundRect ();
+ QRect fgRectInside = QRect (fgRect.x () + 2, fgRect.y () + 2,
+ fgRect.width () - 4, fgRect.height () - 4);
+ if (isEnabled ())
+ {
+ #if DEBUG_KP_COLOR_TOOL_BAR && 1
+ kdDebug () << "\tforegroundColor=" << (int *) m_color [0].toQRgb ()
+ << endl;
+ #endif
+ if (m_color [0].isOpaque ())
+ backBufferPainter.fillRect (fgRectInside, m_color [0].toQColor ());
+ else
+ backBufferPainter.drawPixmap (fgRectInside, UserIcon ("color_transparent_26x26"));
+ }
+ else
+ backBufferPainter.fillRect (fgRectInside, colorGroup ().color (QColorGroup::Button));
+ qDrawShadePanel (&backBufferPainter, fgRect, colorGroup (),
+ false/*not sunken*/, 2/*lineWidth*/,
+ 0/*never fill*/);
+
+ backBufferPainter.end ();
+
+ p->drawPixmap (contentsRect (), *m_backBuffer);
+}
+
+
+/*
+ * kpColorCells
+ */
+
+static inline int roundUp2 (int val)
+{
+ return val % 2 ? val + 1 : val;
+}
+
+static inline int btwn0_255 (int val)
+{
+ if (val < 0)
+ return 0;
+ else if (val > 255)
+ return 255;
+ else
+ return val;
+}
+
+enum
+{
+ blendDark = 25,
+ blendNormal = 50,
+ blendLight = 75,
+ blendAdd = 100
+};
+
+static QColor blend (const QColor &a, const QColor &b, int percent = blendNormal)
+{
+ return QColor (btwn0_255 (roundUp2 (a.red () + b.red ()) * percent / 100),
+ btwn0_255 (roundUp2 (a.green () + b.green ()) * percent / 100),
+ btwn0_255 (roundUp2 (a.blue () + b.blue ()) * percent / 100));
+}
+
+static QColor add (const QColor &a, const QColor &b)
+{
+ return blend (a, b, blendAdd);
+}
+
+
+
+
+
+//
+// make our own colors in case weird ones like "Qt::cyan"
+// (turquoise) get changed by Qt
+//
+
+// primary colors + B&W
+static QColor kpRed;
+static QColor kpGreen;
+static QColor kpBlue;
+static QColor kpBlack;
+static QColor kpWhite;
+
+// intentionally _not_ an HSV darkener
+static QColor dark (const QColor &color)
+{
+ return blend (color, kpBlack);
+}
+
+// full-brightness colors
+static QColor kpYellow;
+static QColor kpPurple;
+static QColor kpAqua;
+
+// mixed colors
+static QColor kpGrey;
+static QColor kpLightGrey;
+static QColor kpOrange;
+
+// pastel colors
+static QColor kpPink;
+static QColor kpLightGreen;
+static QColor kpLightBlue;
+static QColor kpTan;
+
+static bool ownColorsInitialised = false;
+
+/* TODO: clean up this code!!!
+ * (probably when adding palette load/save)
+ */
+#define rows 2
+#define cols 11
+kpColorCells::kpColorCells (QWidget *parent,
+ Qt::Orientation o,
+ const char *name)
+ : KColorCells (parent, rows, cols),
+ m_mouseButton (-1)
+{
+ setName (name);
+
+ setShading (false); // no 3D look
+
+ // Trap KColorDrag so that kpMainWindow does not trap it.
+ // See our impl of dropEvent().
+ setAcceptDrops (true);
+ setAcceptDrags (true);
+
+ connect (this, SIGNAL (colorDoubleClicked (int)),
+ SLOT (slotColorDoubleClicked (int)));
+
+ if (!ownColorsInitialised)
+ {
+ // Don't initialise globally when we probably don't have a colour
+ // allocation context. This way, the colours aren't sometimes
+ // invalid (e.g. at 8-bit).
+
+ kpRed = QColor (255, 0, 0);
+ kpGreen = QColor (0, 255, 0);
+ kpBlue = QColor (0, 0, 255);
+ kpBlack = QColor (0, 0, 0);
+ kpWhite = QColor (255, 255, 255);
+
+ kpYellow = add (kpRed, kpGreen);
+ kpPurple = add (kpRed, kpBlue);
+ kpAqua = add (kpGreen, kpBlue);
+
+ kpGrey = blend (kpBlack, kpWhite);
+ kpLightGrey = blend (kpGrey, kpWhite);
+ kpOrange = blend (kpRed, kpYellow);
+
+ kpPink = blend (kpRed, kpWhite);
+ kpLightGreen = blend (kpGreen, kpWhite);
+ kpLightBlue = blend (kpBlue, kpWhite);
+ kpTan = blend (kpYellow, kpWhite);
+
+ ownColorsInitialised = true;
+ }
+
+ setOrientation (o);
+}
+
+kpColorCells::~kpColorCells ()
+{
+}
+
+Qt::Orientation kpColorCells::orientation () const
+{
+ return m_orientation;
+}
+
+void kpColorCells::setOrientation (Qt::Orientation o)
+{
+ int c, r;
+
+ if (o == Qt::Horizontal)
+ {
+ c = cols;
+ r = rows;
+ }
+ else
+ {
+ c = rows;
+ r = cols;
+ }
+
+#if DEBUG_KP_COLOR_TOOL_BAR
+ kdDebug () << "kpColorCells::setOrientation(): r=" << r << " c=" << c << endl;
+#endif
+
+ setNumRows (r);
+ setNumCols (c);
+
+ setCellWidth (26);
+ setCellHeight (26);
+
+ setFixedSize (numCols () * cellWidth () + frameWidth () * 2,
+ numRows () * cellHeight () + frameWidth () * 2);
+
+/*
+ kdDebug () << "\tlimits: array=" << sizeof (colors) / sizeof (colors [0])
+ << " r*c=" << r * c << endl;
+ kdDebug () << "\tsizeof (colors)=" << sizeof (colors)
+ << " sizeof (colors [0])=" << sizeof (colors [0])
+ << endl;*/
+ QColor colors [] =
+ {
+ kpBlack,
+ kpGrey,
+ kpRed,
+ kpOrange,
+ kpYellow,
+ kpGreen,
+ kpAqua,
+ kpBlue,
+ kpPurple,
+ kpPink,
+ kpLightGreen,
+
+ kpWhite,
+ kpLightGrey,
+ dark (kpRed),
+ dark (kpOrange)/*brown*/,
+ dark (kpYellow),
+ dark (kpGreen),
+ dark (kpAqua),
+ dark (kpBlue),
+ dark (kpPurple),
+ kpLightBlue,
+ kpTan
+ };
+
+ for (int i = 0;
+ /*i < int (sizeof (colors) / sizeof (colors [0])) &&*/
+ i < r * c;
+ i++)
+ {
+ int y, x;
+ int pos;
+
+ if (o == Qt::Horizontal)
+ {
+ y = i / cols;
+ x = i % cols;
+ pos = i;
+ }
+ else
+ {
+ y = i % cols;
+ x = i / cols;
+ // int x = rows - 1 - i / cols;
+ pos = y * rows + x;
+ }
+
+ KColorCells::setColor (pos, colors [i]);
+ //QToolTip::add (this, cellGeometry (y, x), colors [i].name ());
+ }
+
+ m_orientation = o;
+}
+
+// virtual protected [base KColorCells]
+void kpColorCells::dropEvent (QDropEvent *e)
+{
+ // Eat event so that:
+ //
+ // 1. User doesn't clobber the palette (until we support reconfigurable
+ // palettes)
+ // 2. kpMainWindow::dropEvent() doesn't try to paste colour code as text
+ // (when the user slips and drags colour cell a little instead of clicking)
+ e->accept ();
+}
+
+// virtual protected
+void kpColorCells::paintCell (QPainter *painter, int row, int col)
+{
+ QColor oldColor;
+ int cellNo;
+
+ if (!isEnabled ())
+ {
+ cellNo = row * numCols () + col;
+
+ // make all cells 3D (so that disabled palette doesn't look flat)
+ setShading (true);
+
+ oldColor = KColorCells::color (cellNo);
+ KColorCells::colors [cellNo] = backgroundColor ();
+ }
+
+
+ // no focus rect as it doesn't make sense
+ // since 2 colors (foreground & background) can be selected
+ KColorCells::selected = -1;
+ KColorCells::paintCell (painter, row, col);
+
+
+ if (!isEnabled ())
+ {
+ KColorCells::colors [cellNo] = oldColor;
+ setShading (false);
+ }
+}
+
+// virtual protected
+void kpColorCells::mouseReleaseEvent (QMouseEvent *e)
+{
+ m_mouseButton = -1;
+
+ Qt::ButtonState button = e->button ();
+#if DEBUG_KP_COLOR_TOOL_BAR
+ kdDebug () << "kpColorCells::mouseReleaseEvent(left="
+ << (button & Qt::LeftButton)
+ << ",right="
+ << (button & Qt::RightButton)
+ << ")"
+ << endl;
+#endif
+ if (!((button & Qt::LeftButton) && (button & Qt::RightButton)))
+ {
+ if (button & Qt::LeftButton)
+ m_mouseButton = 0;
+ else if (button & Qt::RightButton)
+ m_mouseButton = 1;
+ }
+
+ connect (this, SIGNAL (colorSelected (int)), this, SLOT (slotColorSelected (int)));
+ KColorCells::mouseReleaseEvent (e);
+ disconnect (this, SIGNAL (colorSelected (int)), this, SLOT (slotColorSelected (int)));
+
+#if DEBUG_KP_COLOR_TOOL_BAR
+ kdDebug () << "kpColorCells::mouseReleaseEvent() setting m_mouseButton back to -1" << endl;
+#endif
+ m_mouseButton = -1;
+}
+
+// protected virtual [base KColorCells]
+void kpColorCells::resizeEvent (QResizeEvent *e)
+{
+ // KColorCells::resizeEvent() tries to adjust the cellWidth and cellHeight
+ // to the current dimensions but doesn't take into account
+ // frame{Width,Height}().
+ //
+ // In any case, we already set the cell{Width,Height} and a fixed
+ // widget size and don't want any of it changed. Eat the resize event.
+ (void) e;
+}
+
+// protected slot
+void kpColorCells::slotColorSelected (int cell)
+{
+#if DEBUG_KP_COLOR_TOOL_BAR
+ kdDebug () << "kpColorCells::slotColorSelected(cell=" << cell
+ << ") mouseButton = " << m_mouseButton << endl;
+#endif
+ QColor c = KColorCells::color (cell);
+
+ if (m_mouseButton == 0)
+ {
+ emit foregroundColorChanged (c);
+ emit foregroundColorChanged (kpColor (c.rgb ()));
+ }
+ else if (m_mouseButton == 1)
+ {
+ emit backgroundColorChanged (c);
+ emit backgroundColorChanged (kpColor (c.rgb ()));
+ }
+
+ m_mouseButton = -1; // just in case
+}
+
+// protected slot
+void kpColorCells::slotColorDoubleClicked (int cell)
+{
+#if DEBUG_KP_COLOR_TOOL_BAR
+ kdDebug () << "kpColorCells::slotColorDoubleClicked(cell="
+ << cell << ")" << endl;
+#endif
+
+ QColor color = KColorCells::color (cell);
+
+ // TODO: parent
+ if (KColorDialog::getColor (color/*ref*/))
+ KColorCells::setColor (cell, color);
+}
+
+
+/*
+ * kpTransparentColorCell
+ */
+
+kpTransparentColorCell::kpTransparentColorCell (QWidget *parent, const char *name)
+ : QFrame (parent, name)
+{
+#if DEBUG_KP_COLOR_TOOL_BAR
+ kdDebug () << "kpTransparentColorCell::kpTransparentColorCell()" << endl;
+#endif
+
+ setFrameStyle (QFrame::Panel | QFrame::Sunken);
+#if DEBUG_KP_COLOR_TOOL_BAR && 0
+ kdDebug () << "\tdefault line width=" << lineWidth ()
+ << " frame width=" << frameWidth () << endl;
+#endif
+ //setLineWidth (2);
+#if DEBUG_KP_COLOR_TOOL_BAR && 0
+ kdDebug () << "\tline width=" << lineWidth ()
+ << " frame width=" << frameWidth () << endl;
+#endif
+
+ m_pixmap = UserIcon ("color_transparent_26x26");
+
+ QToolTip::add (this, i18n ("Transparent"));
+}
+
+kpTransparentColorCell::~kpTransparentColorCell ()
+{
+}
+
+
+// public virtual [base QWidget]
+QSize kpTransparentColorCell::sizeHint () const
+{
+ return QSize (m_pixmap.width () + frameWidth () * 2,
+ m_pixmap.height () + frameWidth () * 2);
+}
+
+// protected virtual [base QWidget]
+void kpTransparentColorCell::mousePressEvent (QMouseEvent * /*e*/)
+{
+ // eat right-mouse click to prevent it from getting to the toolbar
+}
+
+// protected virtual [base QWidget]
+void kpTransparentColorCell::mouseReleaseEvent (QMouseEvent *e)
+{
+ if (rect ().contains (e->pos ()))
+ {
+ if (e->button () == Qt::LeftButton)
+ {
+ emit transparentColorSelected (0);
+ emit foregroundColorChanged (kpColor::transparent);
+ }
+ else if (e->button () == Qt::RightButton)
+ {
+ emit transparentColorSelected (1);
+ emit backgroundColorChanged (kpColor::transparent);
+ }
+ }
+}
+
+// protected virtual [base QFrame]
+void kpTransparentColorCell::drawContents (QPainter *p)
+{
+ QFrame::drawContents (p);
+ if (isEnabled ())
+ {
+ #if DEBUG_KP_COLOR_TOOL_BAR
+ kdDebug () << "kpTransparentColorCell::drawContents() contentsRect="
+ << contentsRect ()
+ << endl;
+ #endif
+ p->drawPixmap (contentsRect (), m_pixmap);
+ }
+}
+
+
+/*
+ * kpColorPalette
+ */
+
+kpColorPalette::kpColorPalette (QWidget *parent,
+ Qt::Orientation o,
+ const char *name)
+ : QWidget (parent, name),
+ m_boxLayout (0)
+{
+#if DEBUG_KP_COLOR_TOOL_BAR
+ kdDebug () << "kpColorPalette::kpColorPalette()" << endl;
+#endif
+
+ m_transparentColorCell = new kpTransparentColorCell (this);
+ m_transparentColorCell->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed);
+ connect (m_transparentColorCell, SIGNAL (foregroundColorChanged (const kpColor &)),
+ this, SIGNAL (foregroundColorChanged (const kpColor &)));
+ connect (m_transparentColorCell, SIGNAL (backgroundColorChanged (const kpColor &)),
+ this, SIGNAL (backgroundColorChanged (const kpColor &)));
+
+ m_colorCells = new kpColorCells (this);
+ connect (m_colorCells, SIGNAL (foregroundColorChanged (const kpColor &)),
+ this, SIGNAL (foregroundColorChanged (const kpColor &)));
+ connect (m_colorCells, SIGNAL (backgroundColorChanged (const kpColor &)),
+ this, SIGNAL (backgroundColorChanged (const kpColor &)));
+
+ setOrientation (o);
+}
+
+kpColorPalette::~kpColorPalette ()
+{
+}
+
+// public
+Qt::Orientation kpColorPalette::orientation () const
+{
+ return m_orientation;
+}
+
+void kpColorPalette::setOrientation (Qt::Orientation o)
+{
+ m_colorCells->setOrientation (o);
+
+ delete m_boxLayout;
+
+ if (o == Qt::Horizontal)
+ {
+ m_boxLayout = new QBoxLayout (this, QBoxLayout::LeftToRight, 0/*margin*/, 5/*spacing*/);
+ m_boxLayout->addWidget (m_transparentColorCell, 0/*stretch*/, Qt::AlignVCenter);
+ m_boxLayout->addWidget (m_colorCells);
+ }
+ else
+ {
+ m_boxLayout = new QBoxLayout (this, QBoxLayout::TopToBottom, 0/*margin*/, 5/*spacing*/);
+ m_boxLayout->addWidget (m_transparentColorCell, 0/*stretch*/, Qt::AlignHCenter);
+ m_boxLayout->addWidget (m_colorCells);
+ }
+
+ m_orientation = o;
+}
+
+
+/*
+ * kpColorSimilarityToolBarItem
+ */
+
+kpColorSimilarityToolBarItem::kpColorSimilarityToolBarItem (kpMainWindow *mainWindow,
+ QWidget *parent,
+ const char *name)
+ : kpColorSimilarityCube (kpColorSimilarityCube::Depressed |
+ kpColorSimilarityCube::DoubleClickInstructions,
+ mainWindow, parent, name),
+ m_mainWindow (mainWindow),
+ m_processedColorSimilarity (kpColor::Exact)
+{
+ setColorSimilarity (mainWindow->configColorSimilarity ());
+}
+
+kpColorSimilarityToolBarItem::~kpColorSimilarityToolBarItem ()
+{
+}
+
+
+// public
+int kpColorSimilarityToolBarItem::processedColorSimilarity () const
+{
+ return m_processedColorSimilarity;
+}
+
+
+// public slot
+void kpColorSimilarityToolBarItem::setColorSimilarity (double similarity)
+{
+ m_oldColorSimilarity = colorSimilarity ();
+
+ kpColorSimilarityCube::setColorSimilarity (similarity);
+ if (similarity > 0)
+ QToolTip::add (this, i18n ("Color similarity: %1%").arg (qRound (similarity * 100)));
+ else
+ QToolTip::add (this, i18n ("Color similarity: Exact"));
+
+ m_processedColorSimilarity = kpColor::processSimilarity (colorSimilarity ());
+
+ m_mainWindow->configSetColorSimilarity (colorSimilarity ());
+
+ emit colorSimilarityChanged (colorSimilarity (), m_processedColorSimilarity);
+}
+
+// public
+double kpColorSimilarityToolBarItem::oldColorSimilarity () const
+{
+ return m_oldColorSimilarity;
+}
+
+
+// private virtual [base QWidget]
+void kpColorSimilarityToolBarItem::mousePressEvent (QMouseEvent * /*e*/)
+{
+ // eat right-mouse click to prevent it from getting to the toolbar
+}
+
+// private virtual [base QWidget]
+void kpColorSimilarityToolBarItem::mouseDoubleClickEvent (QMouseEvent * /*e*/)
+{
+ kpColorSimilarityDialog dialog (m_mainWindow, this);
+ dialog.setColorSimilarity (colorSimilarity ());
+ if (dialog.exec ())
+ {
+ setColorSimilarity (dialog.colorSimilarity ());
+ }
+}
+
+
+/*
+ * kpColorToolBar
+ */
+
+kpColorToolBar::kpColorToolBar (const QString &label, kpMainWindow *mainWindow, const char *name)
+ : KToolBar (mainWindow, name),
+ m_mainWindow (mainWindow)
+{
+ setText (label);
+
+
+ QWidget *base = new QWidget (this);
+ m_boxLayout = new QBoxLayout (base, QBoxLayout::LeftToRight,
+ 5/*margin*/, (10 * 4)/*spacing*/);
+
+ m_dualColorButton = new kpDualColorButton (mainWindow, base);
+ m_dualColorButton->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed);
+ connect (m_dualColorButton, SIGNAL (colorsSwapped (const kpColor &, const kpColor &)),
+ this, SIGNAL (colorsSwapped (const kpColor &, const kpColor &)));
+ connect (m_dualColorButton, SIGNAL (foregroundColorChanged (const kpColor &)),
+ this, SIGNAL (foregroundColorChanged (const kpColor &)));
+ connect (m_dualColorButton, SIGNAL (backgroundColorChanged (const kpColor &)),
+ this, SIGNAL (backgroundColorChanged (const kpColor &)));
+ m_boxLayout->addWidget (m_dualColorButton, 0/*stretch*/);
+
+ m_colorPalette = new kpColorPalette (base);
+ connect (m_colorPalette, SIGNAL (foregroundColorChanged (const kpColor &)),
+ m_dualColorButton, SLOT (setForegroundColor (const kpColor &)));
+ connect (m_colorPalette, SIGNAL (backgroundColorChanged (const kpColor &)),
+ m_dualColorButton, SLOT (setBackgroundColor (const kpColor &)));
+ m_boxLayout->addWidget (m_colorPalette, 0/*stretch*/);
+
+ m_colorSimilarityToolBarItem = new kpColorSimilarityToolBarItem (mainWindow, base);
+ m_colorSimilarityToolBarItem->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed);
+ connect (m_colorSimilarityToolBarItem, SIGNAL (colorSimilarityChanged (double, int)),
+ this, SIGNAL (colorSimilarityChanged (double, int)));
+ m_boxLayout->addWidget (m_colorSimilarityToolBarItem, 0/*stretch*/);
+
+ // HACK: couldn't get QSpacerItem to work
+ QWidget *fakeSpacer = new QWidget (base);
+ m_boxLayout->addWidget (fakeSpacer, 1/*stretch*/);
+
+ m_lastDockedOrientationSet = false;
+ setOrientation (orientation ());
+
+ KToolBar::insertWidget (0, base->width (), base);
+}
+
+// virtual
+void kpColorToolBar::setOrientation (Qt::Orientation o)
+{
+ // (QDockWindow::undock() calls us)
+ bool isOutsideDock = (place () == QDockWindow::OutsideDock);
+
+ if (!m_lastDockedOrientationSet || !isOutsideDock)
+ {
+ m_lastDockedOrientation = o;
+ m_lastDockedOrientationSet = true;
+ }
+
+ if (isOutsideDock)
+ {
+ //kdDebug () << "\toutside dock, forcing orientation to last" << endl;
+ o = m_lastDockedOrientation;
+ }
+
+ if (o == Qt::Horizontal)
+ {
+ m_boxLayout->setDirection (QBoxLayout::LeftToRight);
+ }
+ else
+ {
+ m_boxLayout->setDirection (QBoxLayout::TopToBottom);
+ }
+
+ m_colorPalette->setOrientation (o);
+
+ KToolBar::setOrientation (o);
+}
+
+kpColorToolBar::~kpColorToolBar ()
+{
+}
+
+kpColor kpColorToolBar::color (int which) const
+{
+ if (which < 0 || which > 1)
+ {
+ kdWarning () << "kpColorToolBar::color (" << which
+ << ") - out of range" << endl;
+ which = 0;
+ }
+
+ return m_dualColorButton->color (which);
+}
+
+void kpColorToolBar::setColor (int which, const kpColor &color)
+{
+ if (which < 0 || which > 1)
+ {
+ kdWarning () << "kpColorToolBar::setColor (" << which
+ << ") - out of range" << endl;
+ which = 0;
+ }
+
+ m_dualColorButton->setColor (which, color);
+}
+
+kpColor kpColorToolBar::foregroundColor () const
+{
+ return m_dualColorButton->foregroundColor ();
+}
+
+void kpColorToolBar::setForegroundColor (const kpColor &color)
+{
+ m_dualColorButton->setForegroundColor (color);
+}
+
+kpColor kpColorToolBar::backgroundColor () const
+{
+ return m_dualColorButton->backgroundColor ();
+}
+
+void kpColorToolBar::setBackgroundColor (const kpColor &color)
+{
+ m_dualColorButton->setBackgroundColor (color);
+}
+
+
+kpColor kpColorToolBar::oldForegroundColor () const
+{
+ return m_dualColorButton->oldForegroundColor ();
+}
+
+kpColor kpColorToolBar::oldBackgroundColor () const
+{
+ return m_dualColorButton->oldBackgroundColor ();
+}
+
+double kpColorToolBar::oldColorSimilarity () const
+{
+ return m_colorSimilarityToolBarItem->oldColorSimilarity ();
+}
+
+
+double kpColorToolBar::colorSimilarity () const
+{
+ return m_colorSimilarityToolBarItem->colorSimilarity ();
+}
+
+void kpColorToolBar::setColorSimilarity (double similarity)
+{
+ m_colorSimilarityToolBarItem->setColorSimilarity (similarity);
+}
+
+int kpColorToolBar::processedColorSimilarity () const
+{
+ return m_colorSimilarityToolBarItem->processedColorSimilarity ();
+}
+
+
+#include <kpcolortoolbar.moc>
diff --git a/kolourpaint/widgets/kpcolortoolbar.h b/kolourpaint/widgets/kpcolortoolbar.h
new file mode 100644
index 00000000..b4a77bfb
--- /dev/null
+++ b/kolourpaint/widgets/kpcolortoolbar.h
@@ -0,0 +1,297 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kp_color_toolbar_h__
+#define __kp_color_toolbar_h__
+
+
+#include <qframe.h>
+#include <qwidget.h>
+
+#include <kcolordialog.h>
+#include <ktoolbar.h>
+
+#include <kpcolor.h>
+#include <kpcolorsimilaritycube.h>
+
+
+class QGridLayout;
+class KColorButton;
+
+class kpColorSimilarityCube;
+class kpMainWindow;
+
+
+//
+// Widget similar to KDualColorButton.
+// Main differences:
+// - more consistent feel with other KolourPaint widgets
+// (esp. kpColorPalette)
+// - displays the transparent colour using the special pixmap
+// used by kpTransparentColorCell
+// - no obscure "current" colour
+//
+class kpDualColorButton : public QFrame
+{
+Q_OBJECT
+
+public:
+ kpDualColorButton (kpMainWindow *mainWindow,
+ QWidget *parent, const char *name = 0);
+ virtual ~kpDualColorButton ();
+
+ kpColor color (int which) const;
+ kpColor foregroundColor () const;
+ kpColor backgroundColor () const;
+
+public slots:
+ void setColor (int which, const kpColor &color);
+ void setForegroundColor (const kpColor &color);
+ void setBackgroundColor (const kpColor &color);
+
+signals:
+ // If you connect to this signal, ignore the following
+ // foregroundColorChanged() and backgroundColorChanged() signals
+ void colorsSwapped (const kpColor &newForegroundColor,
+ const kpColor &newBackgroundColor);
+
+ void foregroundColorChanged (const kpColor &color);
+ void backgroundColorChanged (const kpColor &color);
+
+public:
+ // (only valid in slots connected to foregroundColorChanged())
+ kpColor oldForegroundColor () const;
+ // (only valid in slots connected to backgroundColorChanged())
+ kpColor oldBackgroundColor () const;
+
+public:
+ virtual QSize sizeHint () const;
+
+protected:
+ QRect swapPixmapRect () const;
+ QRect foregroundBackgroundRect () const;
+ QRect foregroundRect () const;
+ QRect backgroundRect () const;
+
+ //virtual void dragEnterEvent (QDragEnterEvent *e);
+ virtual void dragMoveEvent (QDragMoveEvent *e);
+ virtual void dropEvent (QDropEvent *e);
+
+ virtual void mousePressEvent (QMouseEvent *e);
+ virtual void mouseDoubleClickEvent (QMouseEvent *e);
+ virtual void mouseReleaseEvent (QMouseEvent *e);
+
+ virtual void drawContents (QPainter *p);
+
+ kpMainWindow *m_mainWindow;
+ kpColor m_color [2];
+ kpColor m_oldColor [2];
+ QPixmap *m_backBuffer;
+};
+
+
+class kpColorCells : public KColorCells
+{
+Q_OBJECT
+
+public:
+ kpColorCells (QWidget *parent,
+ Qt::Orientation o = Qt::Horizontal,
+ const char *name = 0);
+ virtual ~kpColorCells ();
+
+ Qt::Orientation orientation () const;
+ void setOrientation (Qt::Orientation o);
+
+signals:
+ void foregroundColorChanged (const QColor &color);
+ void backgroundColorChanged (const QColor &color);
+
+ // lazy
+ void foregroundColorChanged (const kpColor &color);
+ void backgroundColorChanged (const kpColor &color);
+
+protected:
+ Qt::Orientation m_orientation;
+
+ virtual void dropEvent (QDropEvent *e);
+ virtual void paintCell (QPainter *painter, int row, int col);
+ virtual void mouseReleaseEvent (QMouseEvent *e);
+ virtual void resizeEvent (QResizeEvent *e);
+
+ int m_mouseButton;
+
+protected slots:
+ void slotColorSelected (int cell);
+ void slotColorDoubleClicked (int cell);
+};
+
+
+class kpTransparentColorCell : public QFrame
+{
+Q_OBJECT
+
+public:
+ kpTransparentColorCell (QWidget *parent, const char *name = 0);
+ virtual ~kpTransparentColorCell ();
+
+ virtual QSize sizeHint () const;
+
+signals:
+ void transparentColorSelected (int mouseButton);
+
+ // lazy
+ void foregroundColorChanged (const kpColor &color);
+ void backgroundColorChanged (const kpColor &color);
+
+protected:
+ virtual void mousePressEvent (QMouseEvent *e);
+ virtual void mouseReleaseEvent (QMouseEvent *e);
+
+ virtual void drawContents (QPainter *p);
+
+ QPixmap m_pixmap;
+};
+
+
+class kpColorPalette : public QWidget
+{
+Q_OBJECT
+
+public:
+ kpColorPalette (QWidget *parent,
+ Qt::Orientation o = Qt::Horizontal,
+ const char *name = 0);
+ virtual ~kpColorPalette ();
+
+ Qt::Orientation orientation () const;
+ void setOrientation (Qt::Orientation o);
+
+signals:
+ void foregroundColorChanged (const kpColor &color);
+ void backgroundColorChanged (const kpColor &color);
+
+protected:
+ Qt::Orientation m_orientation;
+
+ QBoxLayout *m_boxLayout;
+ kpTransparentColorCell *m_transparentColorCell;
+ kpColorCells *m_colorCells;
+};
+
+
+class kpColorSimilarityToolBarItem : public kpColorSimilarityCube
+{
+Q_OBJECT
+
+public:
+ kpColorSimilarityToolBarItem (kpMainWindow *mainWindow,
+ QWidget *parent,
+ const char *name = 0);
+ virtual ~kpColorSimilarityToolBarItem ();
+
+public:
+ int processedColorSimilarity () const;
+
+public slots:
+ void setColorSimilarity (double similarity);
+
+signals:
+ void colorSimilarityChanged (double similarity, int processedSimilarity);
+
+public:
+ // (only valid in slots connected to colorSimilarityChanged());
+ double oldColorSimilarity () const;
+
+private:
+ virtual void mousePressEvent (QMouseEvent *e);
+ virtual void mouseDoubleClickEvent (QMouseEvent *e);
+
+private:
+ kpMainWindow *m_mainWindow;
+
+ double m_oldColorSimilarity;
+ int m_processedColorSimilarity;
+};
+
+
+class kpColorToolBar : public KToolBar
+{
+Q_OBJECT
+
+public:
+ kpColorToolBar (const QString &label, kpMainWindow *mainWindow, const char *name = 0);
+ virtual ~kpColorToolBar ();
+
+ kpColor color (int which) const;
+ void setColor (int which, const kpColor &color);
+
+ kpColor foregroundColor () const;
+ kpColor backgroundColor () const;
+
+ double colorSimilarity () const;
+ void setColorSimilarity (double similarity);
+ int processedColorSimilarity () const;
+
+signals:
+ // If you connect to this signal, ignore the following
+ // foregroundColorChanged() and backgroundColorChanged() signals
+ void colorsSwapped (const kpColor &newForegroundColor,
+ const kpColor &newBackgroundColor);
+
+ void foregroundColorChanged (const kpColor &color);
+ void backgroundColorChanged (const kpColor &color);
+ void colorSimilarityChanged (double similarity, int processedSimilarity);
+
+public:
+ // (only valid in slots connected to foregroundColorChanged())
+ kpColor oldForegroundColor () const;
+ // (only valid in slots connected to backgroundColorChanged())
+ kpColor oldBackgroundColor () const;
+
+ // (only valid in slots connected to colorSimilarityChanged())
+ double oldColorSimilarity () const;
+
+public slots:
+ void setForegroundColor (const kpColor &color);
+ void setBackgroundColor (const kpColor &color);
+
+private:
+ kpMainWindow *m_mainWindow;
+
+ Qt::Orientation m_lastDockedOrientation;
+ bool m_lastDockedOrientationSet;
+ virtual void setOrientation (Qt::Orientation o);
+
+ QBoxLayout *m_boxLayout;
+ kpDualColorButton *m_dualColorButton;
+ kpColorPalette *m_colorPalette;
+ kpColorSimilarityToolBarItem *m_colorSimilarityToolBarItem;
+};
+
+#endif // __kp_color_toolbar_h__
diff --git a/kolourpaint/widgets/kpresizesignallinglabel.cpp b/kolourpaint/widgets/kpresizesignallinglabel.cpp
new file mode 100644
index 00000000..77d0ad2b
--- /dev/null
+++ b/kolourpaint/widgets/kpresizesignallinglabel.cpp
@@ -0,0 +1,67 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_RESIZE_SIGNALLING_LABEL 0
+
+
+#include <kpresizesignallinglabel.h>
+
+#include <kdebug.h>
+
+
+kpResizeSignallingLabel::kpResizeSignallingLabel (const QString &string,
+ QWidget *parent,
+ const char *name)
+ : QLabel (string, parent, name)
+{
+}
+
+kpResizeSignallingLabel::kpResizeSignallingLabel (QWidget *parent,
+ const char *name)
+ : QLabel (parent, name)
+{
+}
+
+kpResizeSignallingLabel::~kpResizeSignallingLabel ()
+{
+}
+
+
+// protected virtual [base QLabel]
+void kpResizeSignallingLabel::resizeEvent (QResizeEvent *e)
+{
+#if DEBUG_KP_RESIZE_SIGNALLING_LABEL
+ kdDebug () << "kpResizeSignallingLabel::resizeEvent() newSize=" << e->size ()
+ << " oldSize=" << e->oldSize () << endl;
+#endif
+ QLabel::resizeEvent (e);
+
+ emit resized ();
+}
+
+
+#include <kpresizesignallinglabel.moc>
diff --git a/kolourpaint/widgets/kpresizesignallinglabel.h b/kolourpaint/widgets/kpresizesignallinglabel.h
new file mode 100644
index 00000000..6cd3beba
--- /dev/null
+++ b/kolourpaint/widgets/kpresizesignallinglabel.h
@@ -0,0 +1,52 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KP_RESIZE_SIGNALLING_LABEL
+#define KP_RESIZE_SIGNALLING_LABEL
+
+
+#include <qlabel.h>
+
+
+class kpResizeSignallingLabel : public QLabel
+{
+Q_OBJECT
+
+public:
+ kpResizeSignallingLabel (const QString &string, QWidget *parent, const char *name = 0);
+ kpResizeSignallingLabel (QWidget *parent, const char *name = 0);
+ virtual ~kpResizeSignallingLabel ();
+
+signals:
+ void resized ();
+
+protected:
+ virtual void resizeEvent (QResizeEvent *e);
+};
+
+
+#endif // KP_RESIZE_SIGNALLING_LABEL
diff --git a/kolourpaint/widgets/kpsqueezedtextlabel.cpp b/kolourpaint/widgets/kpsqueezedtextlabel.cpp
new file mode 100644
index 00000000..53fd85c9
--- /dev/null
+++ b/kolourpaint/widgets/kpsqueezedtextlabel.cpp
@@ -0,0 +1,215 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_SQUEEZED_TEXT_LABEL 0
+
+
+#include <kpsqueezedtextlabel.h>
+
+#include <qfont.h>
+#include <qfontmetrics.h>
+#include <qstring.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+
+kpSqueezedTextLabel::kpSqueezedTextLabel (QWidget *parent, const char *name)
+ : QLabel (parent, name),
+ m_showEllipsis (true)
+{
+}
+
+kpSqueezedTextLabel::kpSqueezedTextLabel (const QString &text, QWidget *parent, const char *name)
+ : QLabel (parent, name),
+ m_showEllipsis (true)
+{
+ setText (text);
+}
+
+
+// public virtual
+QSize kpSqueezedTextLabel::minimumSizeHint () const
+{
+#if DEBUG_KP_SQUEEZED_TEXT_LABEL && 1
+ kdDebug () << "kpSqueezedTextLabel::minimumSizeHint() qLabel prefers"
+ << QLabel::minimumSizeHint () << endl;
+#endif
+ return QSize (-1/*no minimum width*/, QLabel::minimumHeight ());
+}
+
+
+// public
+QString kpSqueezedTextLabel::fullText () const
+{
+ return m_fullText;
+}
+
+
+// public
+bool kpSqueezedTextLabel::showEllipsis () const
+{
+ return m_showEllipsis;
+}
+
+// public
+void kpSqueezedTextLabel::setShowEllipsis (bool yes)
+{
+ if (m_showEllipsis == yes)
+ return;
+
+ m_showEllipsis = yes;
+
+ squeezeText ();
+}
+
+
+// public slots virtual [base QLabel]
+void kpSqueezedTextLabel::setText (const QString &text)
+{
+ m_fullText = text;
+ squeezeText ();
+}
+
+
+// protected virtual [base QWidget]
+void kpSqueezedTextLabel::resizeEvent (QResizeEvent *e)
+{
+#if DEBUG_KP_SQUEEZED_TEXT_LABEL && 1
+ kdDebug () << "kpSqueezedTextLabeL::resizeEvent() size=" << e->size ()
+ << " oldSize=" << e->oldSize ()
+ << endl;
+#endif
+ squeezeText ();
+}
+
+
+// protected
+QString kpSqueezedTextLabel::ellipsisText () const
+{
+ return m_showEllipsis ? i18n ("...") : QString::null;
+}
+
+// protected
+void kpSqueezedTextLabel::squeezeText ()
+{
+#if DEBUG_KP_SQUEEZED_TEXT_LABEL && 1
+ kdDebug () << "kpSqueezedTextLabeL::squeezeText" << endl;
+#endif
+
+ QFontMetrics fontMetrics (font ());
+ int fullTextWidth = fontMetrics.width (m_fullText);
+#if DEBUG_KP_SQUEEZED_TEXT_LABEL && 1
+ kdDebug () << "\tfullText=" << m_fullText
+ << " fullTextWidth=" << fullTextWidth
+ << " labelWidth=" << width ()
+ << endl;
+#endif
+
+ if (fullTextWidth <= width ())
+ {
+ #if DEBUG_KP_SQUEEZED_TEXT_LABEL && 1
+ kdDebug () << "\tfullText will fit - display" << endl;
+ #endif
+ QLabel::setText (m_fullText);
+ }
+ else
+ {
+ #if DEBUG_KP_SQUEEZED_TEXT_LABEL && 1
+ kdDebug () << "\tfullText won't fit :( - squeeze" << endl;
+ kdDebug () << "\t\twidth of \"...\"="
+ << fontMetrics.width (ellipsisText ())
+ << endl;
+
+ #endif
+ if (fontMetrics.width (ellipsisText ()) > width ())
+ {
+ #if DEBUG_KP_SQUEEZED_TEXT_LABEL && 1
+ kdDebug () << "\t\t\tcan't even fit \"...\" - forget it" << endl;
+ #endif
+ QLabel::setText (QString::null);
+ return;
+ }
+
+ // Binary search our way to fit squeezed text
+ int numLettersToUseLo = 0;
+ int numLettersToUseHi = m_fullText.length ();
+ int numLettersToUse = 0;
+
+ while (numLettersToUseLo <= numLettersToUseHi)
+ {
+ int numLettersToUseMid = (numLettersToUseLo + numLettersToUseHi) / 2;
+ int squeezedWidth = fontMetrics.width (m_fullText.left (numLettersToUseMid) + ellipsisText ());
+ #if DEBUG_KP_SQUEEZED_TEXT_LABEL && 1
+ kdDebug () << "\tbsearch: lo=" << numLettersToUseLo
+ << " hi=" << numLettersToUseHi
+ << " mid=" << numLettersToUseMid
+ << " acceptable=" << numLettersToUse
+ << " squeezedWidth=" << squeezedWidth
+ << endl;
+ #endif
+
+ if (squeezedWidth == width ())
+ {
+ #if DEBUG_KP_SQUEEZED_TEXT_LABEL && 1
+ kdDebug () << "\t\tperfect match!" << endl;
+ #endif
+ numLettersToUse = numLettersToUseMid;
+ break;
+ }
+ else if (squeezedWidth < width ())
+ {
+ #if DEBUG_KP_SQUEEZED_TEXT_LABEL && 1
+ kdDebug () << "\t\tsmall enough - numLettersToUse="
+ << numLettersToUse << endl;
+ #endif
+ if (numLettersToUseMid > numLettersToUse)
+ {
+ numLettersToUse = numLettersToUseMid;
+ #if DEBUG_KP_SQUEEZED_TEXT_LABEL && 1
+ kdDebug () << "\t\t\tset numLettersToUse="
+ << numLettersToUse
+ << endl;
+ #endif
+ }
+
+ numLettersToUseLo = numLettersToUseMid + 1;
+ }
+ else
+ {
+ #if DEBUG_KP_SQUEEZED_TEXT_LABEL && 1
+ kdDebug () << "\t\ttoo big" << endl;
+ #endif
+ numLettersToUseHi = numLettersToUseMid - 1;
+ }
+ }
+
+ QLabel::setText (m_fullText.left (numLettersToUse) + ellipsisText ());
+ }
+}
+
+#include <kpsqueezedtextlabel.moc>
diff --git a/kolourpaint/widgets/kpsqueezedtextlabel.h b/kolourpaint/widgets/kpsqueezedtextlabel.h
new file mode 100644
index 00000000..57aa7b2f
--- /dev/null
+++ b/kolourpaint/widgets/kpsqueezedtextlabel.h
@@ -0,0 +1,65 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __kp_squeezed_text_label_h__
+#define __kp_squeezed_text_label_h__
+
+#include <qlabel.h>
+#include <qstring.h>
+
+
+// KSqueezedTextLabel done properly - squeeze at the end of the string,
+// not the middle.
+class kpSqueezedTextLabel : public QLabel
+{
+Q_OBJECT
+
+public:
+ kpSqueezedTextLabel (QWidget *parent, const char *name = 0);
+ kpSqueezedTextLabel (const QString &text, QWidget *parent, const char *name = 0);
+
+ virtual QSize minimumSizeHint () const;
+
+ // TODO: maybe text() should return the full text?
+ QString fullText () const;
+
+ bool showEllipsis () const;
+ void setShowEllipsis (bool yes = true);
+
+public slots:
+ virtual void setText (const QString &text);
+
+protected:
+ virtual void resizeEvent (QResizeEvent *);
+ QString ellipsisText () const;
+ void squeezeText ();
+
+ QString m_fullText;
+ bool m_showEllipsis;
+};
+
+#endif // __kp_squeezed_text_label_h__
diff --git a/kolourpaint/widgets/kptooltoolbar.cpp b/kolourpaint/widgets/kptooltoolbar.cpp
new file mode 100644
index 00000000..b8d1985c
--- /dev/null
+++ b/kolourpaint/widgets/kptooltoolbar.cpp
@@ -0,0 +1,640 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_TOOL_TOOL_BAR 0
+
+
+#include <kptooltoolbar.h>
+
+#include <qbuttongroup.h>
+#include <qlayout.h>
+#include <qdatetime.h>
+#include <qtoolbutton.h>
+#include <qtooltip.h>
+#include <qwidget.h>
+#include <qwhatsthis.h>
+
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobalsettings.h>
+#include <kicontheme.h>
+
+#include <kpdefs.h>
+#include <kptool.h>
+#include <kptoolaction.h>
+#include <kptoolwidgetbrush.h>
+#include <kptoolwidgeterasersize.h>
+#include <kptoolwidgetfillstyle.h>
+#include <kptoolwidgetlinewidth.h>
+#include <kptoolwidgetopaqueortransparent.h>
+#include <kptoolwidgetspraycansize.h>
+
+
+class kpToolButton : public QToolButton
+{
+public:
+ kpToolButton (kpTool *tool, QWidget *parent)
+ : QToolButton (parent),
+ m_tool (tool)
+ {
+ }
+
+ virtual ~kpToolButton ()
+ {
+ }
+
+protected:
+ // virtual [base QWidget]
+ void mouseDoubleClickEvent (QMouseEvent *e)
+ {
+ if (e->button () == Qt::LeftButton && m_tool)
+ m_tool->globalDraw ();
+ }
+
+ kpTool *m_tool;
+};
+
+
+kpToolToolBar::kpToolToolBar (const QString &label, kpMainWindow *mainWindow, int colsOrRows, const char *name)
+ : KToolBar ((QWidget *) mainWindow, name, false/*don't use global toolBar settings*/, true/*readConfig*/),
+ m_vertCols (colsOrRows),
+ m_buttonGroup (0),
+ m_baseWidget (0),
+ m_baseLayout (0),
+ m_toolLayout (0),
+ m_previousTool (0), m_currentTool (0),
+ m_defaultIconSize (0)
+{
+ setText (label);
+
+
+ // With these lines enabled, mousePressEvent's weren't being generated
+ // when right clicking in empty part of the toolbar (each call affects
+ // the toolbar in its respective orientation). They don't seem to be
+ // needed anyway since !isResizeEnabled().
+
+ //setHorizontallyStretchable (false);
+ //setVerticallyStretchable (false);
+
+
+ m_baseWidget = new QWidget (this);
+
+#if DEBUG_KP_TOOL_TOOL_BAR
+ QTime timer;
+ timer.start ();
+#endif
+
+ m_toolWidgets.append (m_toolWidgetBrush =
+ new kpToolWidgetBrush (m_baseWidget, "Tool Widget Brush"));
+ m_toolWidgets.append (m_toolWidgetEraserSize =
+ new kpToolWidgetEraserSize (m_baseWidget, "Tool Widget Eraser Size"));
+ m_toolWidgets.append (m_toolWidgetFillStyle =
+ new kpToolWidgetFillStyle (m_baseWidget, "Tool Widget Fill Style"));
+ m_toolWidgets.append (m_toolWidgetLineWidth =
+ new kpToolWidgetLineWidth (m_baseWidget, "Tool Widget Line Width"));
+ m_toolWidgets.append (m_toolWidgetOpaqueOrTransparent =
+ new kpToolWidgetOpaqueOrTransparent (m_baseWidget, "Tool Widget Opaque/Transparent"));
+ m_toolWidgets.append (m_toolWidgetSpraycanSize =
+ new kpToolWidgetSpraycanSize (m_baseWidget, "Tool Widget Spraycan Size"));
+
+#if DEBUG_KP_TOOL_TOOL_BAR
+ kdDebug () << "kpToolToolBar::<ctor> create tool widgets msec="
+ << timer.restart () << endl;
+#endif
+
+ for (QValueVector <kpToolWidgetBase *>::const_iterator it = m_toolWidgets.begin ();
+ it != m_toolWidgets.end ();
+ it++)
+ {
+ connect (*it, SIGNAL (optionSelected (int, int)),
+ this, SIGNAL (toolWidgetOptionSelected ()));
+ }
+
+#if DEBUG_KP_TOOL_TOOL_BAR
+ kdDebug () << "kpToolToolBar::<ctor> connect widgets msec="
+ << timer.restart () << endl;
+#endif
+
+ m_lastDockedOrientationSet = false;
+ setOrientation (orientation ());
+
+#if DEBUG_KP_TOOL_TOOL_BAR
+ kdDebug () << "kpToolToolBar::<ctor> layout tool widgets msec="
+ << timer.elapsed () << endl;
+#endif
+
+ m_buttonGroup = new QButtonGroup (); // invisible
+ m_buttonGroup->setExclusive (true);
+
+ connect (m_buttonGroup, SIGNAL (clicked (int)), SLOT (slotToolButtonClicked ()));
+
+ hideAllToolWidgets ();
+}
+
+kpToolToolBar::~kpToolToolBar ()
+{
+ unregisterAllTools ();
+ delete m_buttonGroup;
+}
+
+
+// private
+int kpToolToolBar::defaultIconSize ()
+{
+ // Cached?
+ if (m_defaultIconSize > 0)
+ return m_defaultIconSize;
+
+#if DEBUG_KP_TOOL_TOOL_BAR
+ kdDebug () << "kpToolToolBar::defaultIconSize()" << endl;
+#endif
+
+
+ KConfigGroupSaver cfgGroupSaver (KGlobal::config (),
+ kpSettingsGroupTools);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ if (cfg->hasKey (kpSettingToolBoxIconSize))
+ {
+ m_defaultIconSize = cfg->readNumEntry (kpSettingToolBoxIconSize);
+ #if DEBUG_KP_TOOL_TOOL_BAR
+ kdDebug () << "\tread: " << m_defaultIconSize << endl;
+ #endif
+ }
+ else
+ {
+ m_defaultIconSize = -1;
+#if DEBUG_KP_TOOL_TOOL_BAR
+ kdDebug () << "\tfirst time - writing default: " << m_defaultIconSize << endl;
+#endif
+ cfg->writeEntry (kpSettingToolBoxIconSize, m_defaultIconSize);
+ cfg->sync ();
+ }
+
+
+ if (m_defaultIconSize <= 0)
+ {
+ // Adapt according to screen geometry
+ const QRect desktopSize = KGlobalSettings::desktopGeometry (this);
+ #if DEBUG_KP_TOOL_TOOL_BAR
+ kdDebug () << "\tadapting to screen size=" << desktopSize << endl;
+ #endif
+
+ if (desktopSize.width () >= 1024 && desktopSize.height () >= 768)
+ m_defaultIconSize = KIcon::SizeSmallMedium/*22x22*/;
+ else
+ m_defaultIconSize = KIcon::SizeSmall/*16x16*/;
+ }
+
+
+#if DEBUG_KP_TOOL_TOOL_BAR
+ kdDebug () << "\treturning " << m_defaultIconSize << endl;
+#endif
+ return m_defaultIconSize;
+}
+
+// public
+void kpToolToolBar::registerTool (kpTool *tool)
+{
+ for (QValueVector <kpButtonToolPair>::const_iterator it = m_buttonToolPairs.begin ();
+ it != m_buttonToolPairs.end ();
+ it++)
+ {
+ if ((*it).m_tool == tool)
+ return;
+ }
+ int num = m_buttonToolPairs.count ();
+
+ QToolButton *b = new kpToolButton (tool, m_baseWidget);
+ b->setAutoRaise (true);
+ b->setUsesBigPixmap (false);
+ b->setUsesTextLabel (false);
+ b->setToggleButton (true);
+
+ b->setText (tool->text ());
+ b->setIconSet (tool->iconSet (defaultIconSize ()));
+ QToolTip::add (b, tool->toolTip ());
+ QWhatsThis::add (b, tool->description ());
+
+ m_buttonGroup->insert (b);
+ addButton (b, orientation (), num);
+
+ m_buttonToolPairs.append (kpButtonToolPair (b, tool));
+
+
+ connect (tool, SIGNAL (actionActivated ()),
+ this, SLOT (slotToolActionActivated ()));
+ connect (tool, SIGNAL (actionToolTipChanged (const QString &)),
+ this, SLOT (slotToolActionToolTipChanged ()));
+}
+
+// public
+void kpToolToolBar::unregisterTool (kpTool *tool)
+{
+ for (QValueVector <kpButtonToolPair>::iterator it = m_buttonToolPairs.begin ();
+ it != m_buttonToolPairs.end ();
+ it++)
+ {
+ if ((*it).m_tool == tool)
+ {
+ delete ((*it).m_button);
+ m_buttonToolPairs.erase (it);
+
+ disconnect (tool, SIGNAL (actionActivated ()),
+ this, SLOT (slotToolActionActivated ()));
+ disconnect (tool, SIGNAL (actionToolTipChanged (const QString &)),
+ this, SLOT (slotToolActionToolTipChanged ()));
+ break;
+ }
+ }
+}
+
+// public
+void kpToolToolBar::unregisterAllTools ()
+{
+ for (QValueVector <kpButtonToolPair>::iterator it = m_buttonToolPairs.begin ();
+ it != m_buttonToolPairs.end ();
+ it++)
+ {
+ delete ((*it).m_button);
+ }
+
+ m_buttonToolPairs.clear ();
+}
+
+
+// public
+kpTool *kpToolToolBar::tool () const
+{
+ return m_currentTool;
+}
+
+// public
+void kpToolToolBar::selectTool (const kpTool *tool, bool reselectIfSameTool)
+{
+#if DEBUG_KP_TOOL_TOOL_BAR
+ kdDebug () << "kpToolToolBar::selectTool (tool=" << tool
+ << ") currentTool=" << m_currentTool
+ << endl;
+#endif
+
+ if (!reselectIfSameTool && tool == m_currentTool)
+ return;
+
+ if (tool)
+ {
+ for (QValueVector <kpButtonToolPair>::iterator it = m_buttonToolPairs.begin ();
+ it != m_buttonToolPairs.end ();
+ it++)
+ {
+ if ((*it).m_tool == tool)
+ {
+ m_buttonGroup->setButton (m_buttonGroup->id ((*it).m_button));
+ slotToolButtonClicked ();
+ break;
+ }
+ }
+ }
+ else
+ {
+ QButton *b = m_buttonGroup->selected ();
+ #if DEBUG_KP_TOOL_TOOL_BAR
+ kdDebug () << "\twant to select no tool - button selected=" << b << endl;
+ #endif
+ if (b)
+ {
+ b->toggle ();
+ slotToolButtonClicked ();
+ }
+ }
+}
+
+
+// public
+kpTool *kpToolToolBar::previousTool () const
+{
+ return m_previousTool;
+}
+
+// public
+void kpToolToolBar::selectPreviousTool ()
+{
+ selectTool (m_previousTool);
+}
+
+
+// public
+void kpToolToolBar::hideAllToolWidgets ()
+{
+ for (QValueVector <kpToolWidgetBase *>::const_iterator it = m_toolWidgets.begin ();
+ it != m_toolWidgets.end ();
+ it++)
+ {
+ (*it)->hide ();
+ }
+}
+
+// public
+int kpToolToolBar::numShownToolWidgets () const
+{
+#if DEBUG_KP_TOOL_TOOL_BAR
+ kdDebug () << "kpToolToolBar::numShownToolWidgets()" << endl;
+#endif
+
+ int ret = 0;
+
+ for (QValueVector <kpToolWidgetBase *>::const_iterator it = m_toolWidgets.begin ();
+ it != m_toolWidgets.end ();
+ it++)
+ {
+ #if DEBUG_KP_TOOL_TOOL_BAR
+ kdDebug () << "\t" << (*it)->name ()
+ << " isShown=" << (*it)->isShown ()
+ << endl;
+ #endif
+ if ((*it)->isShown ())
+ ret++;
+ }
+
+ return ret;
+}
+
+// public
+kpToolWidgetBase *kpToolToolBar::shownToolWidget (int which) const
+{
+ int uptoVisibleWidget = 0;
+
+ for (QValueVector <kpToolWidgetBase *>::const_iterator it = m_toolWidgets.begin ();
+ it != m_toolWidgets.end ();
+ it++)
+ {
+ if ((*it)->isShown ())
+ {
+ if (which == uptoVisibleWidget)
+ return *it;
+
+ uptoVisibleWidget++;
+ }
+ }
+
+ return 0;
+}
+
+
+// public
+bool kpToolToolBar::toolsSingleKeyTriggersEnabled () const
+{
+ for (QValueVector <kpButtonToolPair>::const_iterator it = m_buttonToolPairs.begin ();
+ it != m_buttonToolPairs.end ();
+ it++)
+ {
+ if (!(*it).m_tool->singleKeyTriggersEnabled ())
+ return false;
+ }
+
+ return true;
+}
+
+// public
+void kpToolToolBar::enableToolsSingleKeyTriggers (bool enable)
+{
+#if DEBUG_KP_TOOL_TOOL_BAR
+ kdDebug () << "kpToolToolBar::enableToolsSingleKeyTriggers(" << enable << ")" << endl;
+#endif
+
+ for (QValueVector <kpButtonToolPair>::const_iterator it = m_buttonToolPairs.begin ();
+ it != m_buttonToolPairs.end ();
+ it++)
+ {
+ (*it).m_tool->enableSingleKeyTriggers (enable);
+ }
+}
+
+
+// private slot
+void kpToolToolBar::slotToolButtonClicked ()
+{
+ QButton *b = m_buttonGroup->selected ();
+
+#if DEBUG_KP_TOOL_TOOL_BAR
+ kdDebug () << "kpToolToolBar::slotToolButtonClicked() button=" << b << endl;
+#endif
+
+ kpTool *tool = 0;
+ for (QValueVector <kpButtonToolPair>::iterator it = m_buttonToolPairs.begin ();
+ it != m_buttonToolPairs.end ();
+ it++)
+ {
+ if ((*it).m_button == b)
+ {
+ tool = (*it).m_tool;
+ break;
+ }
+ }
+
+#if DEBUG_KP_TOOL_TOOL_BAR
+ kdDebug () << "\ttool=" << tool
+ << " currentTool=" << m_currentTool
+ << endl;
+#endif
+
+ if (tool == m_currentTool)
+ {
+ if (m_currentTool)
+ m_currentTool->reselect ();
+
+ return;
+ }
+
+ if (m_currentTool)
+ m_currentTool->endInternal ();
+
+ m_previousTool = m_currentTool;
+ m_currentTool = tool;
+
+ if (m_currentTool)
+ {
+ kpToolAction *action = m_currentTool->action ();
+ if (action)
+ {
+ action->setChecked (true);
+ }
+
+ m_currentTool->beginInternal ();
+ }
+
+ emit sigToolSelected (m_currentTool);
+}
+
+
+#define CONST_KP_TOOL_SENDER() (dynamic_cast <const kpTool *> (sender ()))
+
+// private slot
+void kpToolToolBar::slotToolActionActivated ()
+{
+ const kpTool *tool = CONST_KP_TOOL_SENDER ();
+
+#if DEBUG_KP_TOOL_TOOL_BAR
+ kdDebug () << "kpToolToolBar::slotToolActionActivated() tool="
+ << (tool ? tool->name () : "null")
+ << endl;
+#endif
+
+ if (m_currentTool)
+ {
+ // If the user clicks on the same KToggleAction, it unchecks it
+ // - this is inconsistent with the Tool Box so always make sure it's
+ // checked.
+ kpToolAction *action = m_currentTool->action ();
+ if (action)
+ {
+ action->setChecked (true);
+ }
+ }
+
+ selectTool (tool, true/*reselect if same tool*/);
+}
+
+// private slot
+void kpToolToolBar::slotToolActionToolTipChanged ()
+{
+ const kpTool *tool = CONST_KP_TOOL_SENDER ();
+
+#if DEBUG_KP_TOOL_TOOL_BAR
+ kdDebug () << "kpToolToolBar::slotToolActionToolTipChanged() tool="
+ << (tool ? tool->name () : "null")
+ << endl;
+#endif
+
+ if (!tool)
+ return;
+
+ for (QValueVector <kpButtonToolPair>::const_iterator it = m_buttonToolPairs.begin ();
+ it != m_buttonToolPairs.end ();
+ it++)
+ {
+ if (tool == (*it).m_tool)
+ {
+ QToolTip::add ((*it).m_button, tool->toolTip ());
+ return;
+ }
+ }
+}
+
+
+// public slot virtual [base QDockWindow]
+void kpToolToolBar::setOrientation (Qt::Orientation o)
+{
+#if DEBUG_KP_TOOL_TOOL_BAR
+ kdDebug () << "kpToolToolBar::setOrientation("
+ << (o == Qt::Vertical ? "vertical" : "horizontal")
+ << ") called!" << endl;
+#endif
+
+ // (QDockWindow::undock() calls us)
+ bool isOutsideDock = (place () == QDockWindow::OutsideDock);
+
+ if (!m_lastDockedOrientationSet || !isOutsideDock)
+ {
+ m_lastDockedOrientation = o;
+ m_lastDockedOrientationSet = true;
+ }
+
+ if (isOutsideDock)
+ {
+ #if DEBUG_KP_TOOL_TOOL_BAR
+ kdDebug () << "\toutside dock, forcing orientation to last" << endl;
+ #endif
+ o = m_lastDockedOrientation;
+ }
+
+ delete m_toolLayout;
+ delete m_baseLayout;
+ if (o == Qt::Vertical)
+ {
+ m_baseLayout = new QBoxLayout (m_baseWidget, QBoxLayout::TopToBottom,
+ 5/*margin*/,
+ 10/*spacing*/);
+ m_toolLayout = new QGridLayout (m_baseLayout,
+ 5/*arbitrary rows since toolBar auto-expands*/,
+ m_vertCols,
+ 0/*margin*/,
+ 0/*spacing*/);
+ }
+ else // if (o == Qt::Horizontal)
+ {
+ m_baseLayout = new QBoxLayout (m_baseWidget, QBoxLayout::LeftToRight,
+ 5/*margin*/,
+ 10/*spacing*/);
+ m_toolLayout = new QGridLayout (m_baseLayout,
+ m_vertCols/*rows in this case, since horiz*/,
+ 5/*arbitrary cols since toolBar auto-expands*/,
+ 0/*margin*/,
+ 0/*spacing*/);
+ }
+
+ int num = 0;
+
+ for (QValueVector <kpButtonToolPair>::iterator it = m_buttonToolPairs.begin ();
+ it != m_buttonToolPairs.end ();
+ it++)
+ {
+ addButton ((*it).m_button, o, num);
+ num++;
+ }
+
+ for (QValueVector <kpToolWidgetBase *>::const_iterator it = m_toolWidgets.begin ();
+ it != m_toolWidgets.end ();
+ it++)
+ {
+ if (*it)
+ {
+ m_baseLayout->addWidget (*it,
+ 0/*stretch*/,
+ o == Qt::Vertical ? Qt::AlignHCenter : Qt::AlignVCenter);
+ }
+ }
+
+ KToolBar::setOrientation (o);
+}
+
+// private
+void kpToolToolBar::addButton (QButton *button, Qt::Orientation o, int num)
+{
+ if (o == Qt::Vertical)
+ m_toolLayout->addWidget (button, num / m_vertCols, num % m_vertCols);
+ else
+ {
+ // maps Left (o = vertical) to Bottom (o = horizontal)
+ int row = (m_vertCols - 1) - (num % m_vertCols);
+ m_toolLayout->addWidget (button, row, num / m_vertCols);
+ }
+}
+
+
+#include <kptooltoolbar.moc>
diff --git a/kolourpaint/widgets/kptooltoolbar.h b/kolourpaint/widgets/kptooltoolbar.h
new file mode 100644
index 00000000..c3a7d1b7
--- /dev/null
+++ b/kolourpaint/widgets/kptooltoolbar.h
@@ -0,0 +1,155 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kp_tool_tool_bar_h__
+#define __kp_tool_tool_bar_h__
+
+#include <qvaluevector.h>
+
+#include <ktoolbar.h>
+
+
+class QBoxLayout;
+class QButton;
+class QButtonGroup;
+class QWidget;
+class QGridLayout;
+
+class kpMainWindow;
+class kpTool;
+
+class kpToolWidgetBase;
+class kpToolWidgetBrush;
+class kpToolWidgetEraserSize;
+class kpToolWidgetFillStyle;
+class kpToolWidgetLineWidth;
+class kpToolWidgetOpaqueOrTransparent;
+class kpToolWidgetSpraycanSize;
+
+class kpToolToolBar : public KToolBar
+{
+Q_OBJECT
+
+public:
+ kpToolToolBar (const QString &label, kpMainWindow *mainWindow, int colsOrRows = 2, const char *name = 0);
+ virtual ~kpToolToolBar ();
+
+private:
+ int defaultIconSize ();
+public:
+ void registerTool (kpTool *tool);
+ void unregisterTool (kpTool *tool);
+ void unregisterAllTools ();
+
+ kpTool *tool () const;
+ void selectTool (const kpTool *tool, bool reselectIfSameTool = false);
+
+ kpTool *previousTool () const;
+ void selectPreviousTool ();
+
+ void hideAllToolWidgets ();
+ // could this be cleaner (the tools have to access them individually somehow)?
+ kpToolWidgetBrush *toolWidgetBrush () const { return m_toolWidgetBrush; }
+ kpToolWidgetEraserSize *toolWidgetEraserSize () const { return m_toolWidgetEraserSize; }
+ kpToolWidgetFillStyle *toolWidgetFillStyle () const { return m_toolWidgetFillStyle; }
+ kpToolWidgetLineWidth *toolWidgetLineWidth () const { return m_toolWidgetLineWidth; }
+ kpToolWidgetOpaqueOrTransparent *toolWidgetOpaqueOrTransparent () const { return m_toolWidgetOpaqueOrTransparent; }
+ kpToolWidgetSpraycanSize *toolWidgetSpraycanSize () const { return m_toolWidgetSpraycanSize; }
+
+public:
+ int numShownToolWidgets () const;
+ kpToolWidgetBase *shownToolWidget (int which) const;
+
+ bool toolsSingleKeyTriggersEnabled () const;
+ void enableToolsSingleKeyTriggers (bool enable);
+
+signals:
+ void sigToolSelected (kpTool *tool); // tool may be 0
+ void toolWidgetOptionSelected ();
+
+private slots:
+ void slotToolButtonClicked ();
+
+ void slotToolActionActivated ();
+ void slotToolActionToolTipChanged ();
+
+public slots:
+ virtual void setOrientation (Qt::Orientation o);
+
+private:
+ void addButton (QButton *button, Qt::Orientation o, int num);
+
+ Qt::Orientation m_lastDockedOrientation;
+ bool m_lastDockedOrientationSet;
+ int m_vertCols;
+
+ QButtonGroup *m_buttonGroup;
+ QWidget *m_baseWidget;
+ QBoxLayout *m_baseLayout;
+ QGridLayout *m_toolLayout;
+
+ kpToolWidgetBrush *m_toolWidgetBrush;
+ kpToolWidgetEraserSize *m_toolWidgetEraserSize;
+ kpToolWidgetFillStyle *m_toolWidgetFillStyle;
+ kpToolWidgetLineWidth *m_toolWidgetLineWidth;
+ kpToolWidgetOpaqueOrTransparent *m_toolWidgetOpaqueOrTransparent;
+ kpToolWidgetSpraycanSize *m_toolWidgetSpraycanSize;
+
+ QValueVector <kpToolWidgetBase *> m_toolWidgets;
+
+private:
+ struct kpButtonToolPair
+ {
+ kpButtonToolPair (QButton *button, kpTool *tool)
+ : m_button (button), m_tool (tool)
+ {
+ }
+
+ kpButtonToolPair ()
+ : m_button (0), m_tool (0)
+ {
+ }
+
+ QButton *m_button;
+ kpTool *m_tool;
+ };
+
+ QValueVector <kpButtonToolPair> m_buttonToolPairs;
+
+ kpTool *m_previousTool, *m_currentTool;
+
+ int m_defaultIconSize;
+
+private:
+ // There is no need to maintain binary compatibility at this stage.
+ // The d-pointer is just so that you can experiment without recompiling
+ // the kitchen sink.
+ class kpToolToolBarPrivate *d;
+};
+
+#endif // __kp_tool_tool_bar_h__
diff --git a/kolourpaint/widgets/kptoolwidgetbase.cpp b/kolourpaint/widgets/kptoolwidgetbase.cpp
new file mode 100644
index 00000000..a0042dbc
--- /dev/null
+++ b/kolourpaint/widgets/kptoolwidgetbase.cpp
@@ -0,0 +1,608 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_TOOL_WIDGET_BASE 0
+
+
+#include <kptoolwidgetbase.h>
+
+#include <qbitmap.h>
+#include <qcolor.h>
+#include <qimage.h>
+#include <qpainter.h>
+#include <qtooltip.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+
+#include <kpdefs.h>
+#include <kpeffectinvert.h>
+
+
+kpToolWidgetBase::kpToolWidgetBase (QWidget *parent, const char *name)
+ : QFrame (parent, name),
+ m_invertSelectedPixmap (true),
+ m_selectedRow (-1), m_selectedCol (-1)
+{
+ if (!name)
+ kdError () << "kpToolWidgetBase::kpToolWidgetBase() without name" << endl;
+
+ setFrameStyle (QFrame::Panel | QFrame::Sunken);
+ setFixedSize (44, 66);
+}
+
+kpToolWidgetBase::~kpToolWidgetBase ()
+{
+}
+
+
+// public
+void kpToolWidgetBase::addOption (const QPixmap &pixmap, const QString &toolTip)
+{
+ if (m_pixmaps.isEmpty ())
+ startNewOptionRow ();
+
+ m_pixmaps.last ().append (pixmap);
+ m_pixmapRects.last ().append (QRect ());
+ m_toolTips.last ().append (toolTip);
+}
+
+// public
+void kpToolWidgetBase::startNewOptionRow ()
+{
+ m_pixmaps.resize (m_pixmaps.count () + 1);
+ m_pixmapRects.resize (m_pixmapRects.count () + 1);
+ m_toolTips.resize (m_toolTips.count () + 1);
+}
+
+// public
+void kpToolWidgetBase::finishConstruction (int fallBackRow, int fallBackCol)
+{
+#if DEBUG_KP_TOOL_WIDGET_BASE
+ kdDebug () << "kpToolWidgetBase(" << name ()
+ << ")::kpToolWidgetBase(fallBack:row=" << fallBackRow
+ << ",col=" << fallBackCol
+ << ")"
+ << endl;
+#endif
+
+ relayoutOptions ();
+
+ const QPair <int, int> rowColPair = defaultSelectedRowAndCol ();
+ if (!setSelected (rowColPair.first, rowColPair.second, false/*don't save*/))
+ {
+ if (!setSelected (fallBackRow, fallBackCol))
+ {
+ if (!setSelected (0, 0))
+ {
+ kdError () << "kpToolWidgetBase::finishConstruction() "
+ "can't even fall back to setSelected(row=0,col=0)" << endl;
+ }
+ }
+ }
+}
+
+
+// private
+QValueVector <int> kpToolWidgetBase::spreadOutElements (const QValueVector <int> &sizes, int max)
+{
+ if (sizes.count () == 0)
+ return QValueVector <int> ();
+ else if (sizes.count () == 1)
+ return QValueVector <int> (1, sizes.first () > max ? 0 : 1/*margin*/);
+
+ QValueVector <int> retOffsets (sizes.count ());
+
+ int totalSize = 0;
+ for (int i = 0; i < (int) sizes.count (); i++)
+ totalSize += sizes [i];
+
+ int margin = 1;
+
+ // if don't fit with margin, then just return elements
+ // packed right next to each other
+ if (totalSize + margin * 2 > max)
+ {
+ retOffsets [0] = 0;
+ for (int i = 1; i < (int) sizes.count (); i++)
+ retOffsets [i] = retOffsets [i - 1] + sizes [i - 1];
+
+ return retOffsets;
+ }
+
+ int maxLeftOver = max - (totalSize + margin * 2);
+
+ int startCompensating = -1;
+ int numCompensate = 0;
+
+ int spacing = 0;
+
+ spacing = maxLeftOver / (sizes.count () - 1);
+ if (spacing * int (sizes.count () - 1) < maxLeftOver)
+ {
+ numCompensate = maxLeftOver - spacing * (sizes.count () - 1);
+ startCompensating = ((sizes.count () - 1) - numCompensate) / 2;
+ }
+
+ retOffsets [0] = margin;
+ for (int i = 1; i < (int) sizes.count (); i++)
+ {
+ retOffsets [i] += retOffsets [i - 1] +
+ sizes [i - 1] +
+ spacing +
+ ((numCompensate &&
+ i >= startCompensating &&
+ i < startCompensating + numCompensate) ? 1 : 0);
+ }
+
+ return retOffsets;
+}
+
+
+// public
+QPair <int, int> kpToolWidgetBase::defaultSelectedRowAndCol () const
+{
+ int row = -1, col = -1;
+
+ if (name ())
+ {
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupTools);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ QString nameString = QString::fromLatin1 (name ());
+
+ row = cfg->readNumEntry (nameString + QString::fromLatin1 (" Row"), -1);
+ col = cfg->readNumEntry (nameString + QString::fromLatin1 (" Col"), -1);
+ }
+
+#if DEBUG_KP_TOOL_WIDGET_BASE
+ kdDebug () << "kpToolWidgetBase(" << name ()
+ << ")::defaultSelectedRowAndCol() returning row=" << row
+ << " col=" << col
+ << endl;
+#endif
+
+ return qMakePair (row, col);
+}
+
+// public
+int kpToolWidgetBase::defaultSelectedRow () const
+{
+ return defaultSelectedRowAndCol ().first;
+}
+
+// public
+int kpToolWidgetBase::defaultSelectedCol () const
+{
+ return defaultSelectedRowAndCol ().second;
+}
+
+// public
+void kpToolWidgetBase::saveSelectedAsDefault () const
+{
+#if DEBUG_KP_TOOL_WIDGET_BASE
+ kdDebug () << "kpToolWidgetBase(" << name ()
+ << ")::saveSelectedAsDefault() row=" << m_selectedRow
+ << " col=" << m_selectedCol << endl;
+#endif
+
+ if (!name ())
+ return;
+
+ KConfigGroupSaver cfgGroupSaver (kapp->config (), kpSettingsGroupTools);
+ KConfigBase *cfg = cfgGroupSaver.config ();
+
+ QString nameString = QString::fromLatin1 (name ());
+ cfg->writeEntry (nameString + QString::fromLatin1 (" Row"), m_selectedRow);
+ cfg->writeEntry (nameString + QString::fromLatin1 (" Col"), m_selectedCol);
+ cfg->sync ();
+}
+
+
+// public
+void kpToolWidgetBase::relayoutOptions ()
+{
+#if DEBUG_KP_TOOL_WIDGET_BASE
+ kdDebug () << "kpToolWidgetBase::relayoutOptions()" << endl;
+#endif
+
+ while (!m_pixmaps.isEmpty () && m_pixmaps.last ().count () == 0)
+ {
+ #if DEBUG_KP_TOOL_WIDGET_BASE
+ kdDebug () << "\tkilling #" << m_pixmaps.count () - 1 << endl;
+ #endif
+ m_pixmaps.resize (m_pixmaps.count () - 1);
+ m_pixmapRects.resize (m_pixmapRects.count () - 1);
+ m_toolTips.resize (m_toolTips.count () - 1);
+ }
+
+ if (m_pixmaps.isEmpty ())
+ return;
+
+#if DEBUG_KP_TOOL_WIDGET_BASE
+ kdDebug () << "\tsurvived killing of empty rows" << endl;
+ kdDebug () << "\tfinding heights of rows:" << endl;
+#endif
+
+ QValueVector <int> maxHeightOfRow (m_pixmaps.count ());
+
+ for (int r = 0; r < (int) m_pixmaps.count (); r++)
+ {
+ for (int c = 0; c < (int) m_pixmaps [r].count (); c++)
+ {
+ if (c == 0 || m_pixmaps [r][c].height () > maxHeightOfRow [r])
+ maxHeightOfRow [r] = m_pixmaps [r][c].height ();
+ }
+ #if DEBUG_KP_TOOL_WIDGET_BASE
+ kdDebug () << "\t\t" << r << ": " << maxHeightOfRow [r] << endl;
+ #endif
+ }
+
+ QValueVector <int> rowYOffset = spreadOutElements (maxHeightOfRow, height ());
+#if DEBUG_KP_TOOL_WIDGET_BASE
+ kdDebug () << "\tspread out offsets of rows:" << endl;
+ for (int r = 0; r < (int) rowYOffset.count (); r++)
+ kdDebug () << "\t\t" << r << ": " << rowYOffset [r] << endl;
+#endif
+
+ for (int r = 0; r < (int) m_pixmaps.count (); r++)
+ {
+ #if DEBUG_KP_TOOL_WIDGET_BASE
+ kdDebug () << "\tlaying out row " << r << ":" << endl;
+ #endif
+
+ QValueVector <int> widths (m_pixmaps [r].count ());
+ for (int c = 0; c < (int) m_pixmaps [r].count (); c++)
+ widths [c] = m_pixmaps [r][c].width ();
+ #if DEBUG_KP_TOOL_WIDGET_BASE
+ kdDebug () << "\t\twidths of cols:" << endl;
+ for (int c = 0; c < (int) m_pixmaps [r].count (); c++)
+ kdDebug () << "\t\t\t" << c << ": " << widths [c] << endl;
+ #endif
+
+ QValueVector <int> colXOffset = spreadOutElements (widths, width ());
+ #if DEBUG_KP_TOOL_WIDGET_BASE
+ kdDebug () << "\t\tspread out offsets of cols:" << endl;
+ for (int c = 0; c < (int) colXOffset.count (); c++)
+ kdDebug () << "\t\t\t" << c << ": " << colXOffset [c] << endl;
+ #endif
+
+ for (int c = 0; c < (int) colXOffset.count (); c++)
+ {
+ int x = colXOffset [c];
+ int y = rowYOffset [r];
+ int w, h;
+
+ if (c == (int) colXOffset.count () - 1)
+ {
+ if (x + m_pixmaps [r][c].width () >= width ())
+ w = m_pixmaps [r][c].width ();
+ else
+ w = width () - 1 - x;
+ }
+ else
+ w = colXOffset [c + 1] - x;
+
+ if (r == (int) m_pixmaps.count () - 1)
+ {
+ if (y + m_pixmaps [r][c].height () >= height ())
+ h = m_pixmaps [r][c].height ();
+ else
+ h = height () - 1 - y;
+ }
+ else
+ h = rowYOffset [r + 1] - y;
+
+ m_pixmapRects [r][c] = QRect (x, y, w, h);
+
+ if (!m_toolTips [r][c].isEmpty ())
+ QToolTip::add (this, m_pixmapRects [r][c], m_toolTips [r][c]);
+ }
+ }
+
+ update ();
+}
+
+
+// public
+int kpToolWidgetBase::selectedRow () const
+{
+ return m_selectedRow;
+}
+
+// public
+int kpToolWidgetBase::selectedCol () const
+{
+ return m_selectedCol;
+}
+
+// public
+int kpToolWidgetBase::selected () const
+{
+ if (m_selectedRow < 0 ||
+ m_selectedRow >= (int) m_pixmaps.count () ||
+ m_selectedCol < 0)
+ {
+ return -1;
+ }
+
+ int upto = 0;
+ for (int y = 0; y < m_selectedRow; y++)
+ upto += m_pixmaps [y].count ();
+
+ if (m_selectedCol >= (int) m_pixmaps [m_selectedRow].count ())
+ return -1;
+
+ upto += m_selectedCol;
+
+ return upto;
+}
+
+
+// public
+bool kpToolWidgetBase::hasPreviousOption (int *row, int *col) const
+{
+#if DEBUG_KP_TOOL_WIDGET_BASE
+ kdDebug () << "kpToolWidgetBase" << name ()
+ << "::hasPreviousOption() current row=" << m_selectedRow
+ << " col=" << m_selectedCol
+ << endl;
+#endif
+ if (row)
+ *row = -1;
+ if (col)
+ *col = -1;
+
+
+ if (m_selectedRow < 0 || m_selectedCol < 0)
+ return false;
+
+ int newRow = m_selectedRow,
+ newCol = m_selectedCol;
+
+ newCol--;
+ if (newCol < 0)
+ {
+ newRow--;
+ if (newRow < 0)
+ return false;
+
+ newCol = m_pixmaps [newRow].count () - 1;
+ if (newCol < 0)
+ return false;
+ }
+
+
+ if (row)
+ *row = newRow;
+ if (col)
+ *col = newCol;
+
+ return true;
+}
+
+// public
+bool kpToolWidgetBase::hasNextOption (int *row, int *col) const
+{
+#if DEBUG_KP_TOOL_WIDGET_BASE
+ kdDebug () << "kpToolWidgetBase" << name ()
+ << "::hasNextOption() current row=" << m_selectedRow
+ << " col=" << m_selectedCol
+ << endl;
+#endif
+
+ if (row)
+ *row = -1;
+ if (col)
+ *col = -1;
+
+
+ if (m_selectedRow < 0 || m_selectedCol < 0)
+ return false;
+
+ int newRow = m_selectedRow,
+ newCol = m_selectedCol;
+
+ newCol++;
+ if (newCol >= (int) m_pixmaps [newRow].count ())
+ {
+ newRow++;
+ if (newRow >= (int) m_pixmaps.count ())
+ return false;
+
+ newCol = 0;
+ if (newCol >= (int) m_pixmaps [newRow].count ())
+ return false;
+ }
+
+
+ if (row)
+ *row = newRow;
+ if (col)
+ *col = newCol;
+
+ return true;
+}
+
+
+// public slot virtual
+bool kpToolWidgetBase::setSelected (int row, int col, bool saveAsDefault)
+{
+#if DEBUG_KP_TOOL_WIDGET_BASE
+ kdDebug () << "kpToolWidgetBase::setSelected(row=" << row
+ << ",col=" << col
+ << ",saveAsDefault=" << saveAsDefault
+ << ")"
+ << endl;
+#endif
+
+ if (row < 0 || col < 0 ||
+ row >= (int) m_pixmapRects.count () || col >= (int) m_pixmapRects [row].count ())
+ {
+ #if DEBUG_KP_TOOL_WIDGET_BASE
+ kdDebug () << "\tout of range" << endl;
+ #endif
+ return false;
+ }
+
+ if (row == m_selectedRow && col == m_selectedCol)
+ {
+ #if DEBUG_KP_TOOL_WIDGET_BASE
+ kdDebug () << "\tNOP" << endl;
+ #endif
+
+ if (saveAsDefault)
+ saveSelectedAsDefault ();
+
+ return true;
+ }
+
+ const int wasSelectedRow = m_selectedRow;
+ const int wasSelectedCol = m_selectedCol;
+
+ m_selectedRow = row, m_selectedCol = col;
+
+ if (wasSelectedRow >= 0 && wasSelectedCol >= 0)
+ {
+ // unhighlight old option
+ update (m_pixmapRects [wasSelectedRow][wasSelectedCol]);
+ }
+
+ // highlight new option
+ update (m_pixmapRects [row][col]);
+
+#if DEBUG_KP_TOOL_WIDGET_BASE
+ kdDebug () << "\tOK" << endl;
+#endif
+
+ if (saveAsDefault)
+ saveSelectedAsDefault ();
+
+ emit optionSelected (row, col);
+ return true;
+}
+
+// public slot
+bool kpToolWidgetBase::setSelected (int row, int col)
+{
+ return setSelected (row, col, true/*set as default*/);
+}
+
+
+// public slot
+bool kpToolWidgetBase::selectPreviousOption ()
+{
+ int newRow, newCol;
+ if (!hasPreviousOption (&newRow, &newCol))
+ return false;
+
+ return setSelected (newRow, newCol);
+}
+
+// public slot
+bool kpToolWidgetBase::selectNextOption ()
+{
+ int newRow, newCol;
+ if (!hasNextOption (&newRow, &newCol))
+ return false;
+
+ return setSelected (newRow, newCol);
+}
+
+
+// protected virtual [base QWidget]
+void kpToolWidgetBase::mousePressEvent (QMouseEvent *e)
+{
+ e->ignore ();
+
+ if (e->button () != Qt::LeftButton)
+ return;
+
+
+ for (int i = 0; i < (int) m_pixmapRects.count (); i++)
+ {
+ for (int j = 0; j < (int) m_pixmapRects [i].count (); j++)
+ {
+ if (m_pixmapRects [i][j].contains (e->pos ()))
+ {
+ setSelected (i, j);
+ e->accept ();
+ return;
+ }
+ }
+ }
+}
+
+// protected virtual [base QFrame]
+void kpToolWidgetBase::drawContents (QPainter *painter)
+{
+#if DEBUG_KP_TOOL_WIDGET_BASE && 1
+ kdDebug () << "kpToolWidgetBase::drawContents(): rect=" << contentsRect () << endl;
+#endif
+
+ for (int i = 0; i < (int) m_pixmaps.count (); i++)
+ {
+ #if DEBUG_KP_TOOL_WIDGET_BASE && 1
+ kdDebug () << "\tRow: " << i << endl;
+ #endif
+
+ for (int j = 0; j < (int) m_pixmaps [i].count (); j++)
+ {
+ QRect rect = m_pixmapRects [i][j];
+ QPixmap pixmap = m_pixmaps [i][j];
+
+ #if DEBUG_KP_TOOL_WIDGET_BASE && 1
+ kdDebug () << "\t\tCol: " << j << " rect=" << rect << endl;
+ #endif
+
+ if (i == m_selectedRow && j == m_selectedCol)
+ {
+ painter->fillRect (rect, Qt::blue/*selection color*/);
+
+ if (m_invertSelectedPixmap)
+ kpEffectInvertCommand::apply (&pixmap);
+ }
+
+ #if DEBUG_KP_TOOL_WIDGET_BASE && 1
+ kdDebug () << "\t\t\tdraw pixmap @ x="
+ << rect.x () + (rect.width () - pixmap.width ()) / 2
+ << " y="
+ << rect.y () + (rect.height () - pixmap.height ()) / 2
+ << endl;
+
+ #endif
+
+ painter->drawPixmap (QPoint (rect.x () + (rect.width () - pixmap.width ()) / 2,
+ rect.y () + (rect.height () - pixmap.height ()) / 2),
+ pixmap);
+ }
+ }
+}
+
+#include <kptoolwidgetbase.moc>
diff --git a/kolourpaint/widgets/kptoolwidgetbase.h b/kolourpaint/widgets/kptoolwidgetbase.h
new file mode 100644
index 00000000..a23f9a16
--- /dev/null
+++ b/kolourpaint/widgets/kptoolwidgetbase.h
@@ -0,0 +1,112 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kp_tool_widget_base_h__
+#define __kp_tool_widget_base_h__
+
+#include <qframe.h>
+#include <qpair.h>
+#include <qpixmap.h>
+#include <qrect.h>
+#include <qvaluevector.h>
+#include <qwidget.h>
+
+
+class QPainter;
+
+
+// TODO: frame becomes a combobox when its parent kpToolToolBar becomes too small
+class kpToolWidgetBase : public QFrame
+{
+Q_OBJECT
+
+public:
+ kpToolWidgetBase (QWidget *parent, const char *name); // must provide a name for config to work
+ virtual ~kpToolWidgetBase ();
+
+public:
+ void addOption (const QPixmap &pixmap, const QString &toolTip = QString::null);
+ void startNewOptionRow ();
+
+ // Call this at the end of your constructor.
+ // If the default row & col could not be read from the config,
+ // <fallBackRow> & <fallBackCol> are passed to setSelected().
+ void finishConstruction (int fallBackRow, int fallBackCol);
+
+private:
+ QValueVector <int> spreadOutElements (const QValueVector <int> &sizes, int maxSize);
+
+public: // (only have to use these if you don't use finishConstruction())
+ // (rereads from config file)
+ QPair <int, int> defaultSelectedRowAndCol () const;
+ int defaultSelectedRow () const;
+ int defaultSelectedCol () const;
+
+ void saveSelectedAsDefault () const;
+
+ void relayoutOptions ();
+
+public:
+ int selectedRow () const;
+ int selectedCol () const;
+
+ int selected () const;
+
+ bool hasPreviousOption (int *row = 0, int *col = 0) const;
+ bool hasNextOption (int *row = 0, int *col = 0) const;
+
+public slots:
+ // (returns whether <row> and <col> were in range)
+ virtual bool setSelected (int row, int col, bool saveAsDefault);
+ bool setSelected (int row, int col);
+
+ bool selectPreviousOption ();
+ bool selectNextOption ();
+
+signals:
+ void optionSelected (int row, int col);
+
+protected:
+ virtual void mousePressEvent (QMouseEvent *e);
+ virtual void drawContents (QPainter *painter);
+
+ void setInvertSelectedPixmap (bool yes = true) { m_invertSelectedPixmap = yes; }
+ bool m_invertSelectedPixmap;
+
+ // coulbe be a QFrame or a ComboBox
+ QWidget *m_baseWidget;
+
+ QValueVector < QValueVector <QPixmap> > m_pixmaps;
+ QValueVector < QValueVector <QString> > m_toolTips;
+
+ QValueVector < QValueVector <QRect> > m_pixmapRects;
+
+ int m_selectedRow, m_selectedCol;
+};
+
+#endif // __kp_tool_widget_base_h__
diff --git a/kolourpaint/widgets/kptoolwidgetbrush.cpp b/kolourpaint/widgets/kptoolwidgetbrush.cpp
new file mode 100644
index 00000000..046dc8b5
--- /dev/null
+++ b/kolourpaint/widgets/kptoolwidgetbrush.cpp
@@ -0,0 +1,184 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_TOOL_WIDGET_BRUSH 0
+
+
+#include <kptoolwidgetbrush.h>
+
+#include <qbitmap.h>
+#include <qpainter.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpdefs.h>
+
+
+/* sync: <brushes> */
+static int brushSize [][3] =
+{
+ {8, 4, 1/*like Pen*/},
+ {9, 5, 2},
+ {9, 5, 2},
+ {9, 5, 2}
+};
+
+#define BRUSH_SIZE_NUM_COLS (int (sizeof (brushSize [0]) / sizeof (brushSize [0][0])))
+#define BRUSH_SIZE_NUM_ROWS (int (sizeof (brushSize) / sizeof (brushSize [0])))
+
+kpToolWidgetBrush::kpToolWidgetBrush (QWidget *parent, const char *name)
+ : kpToolWidgetBase (parent, name)
+{
+ setInvertSelectedPixmap ();
+
+ QPixmap *pm = m_brushBitmaps;
+
+ for (int shape = 0; shape < BRUSH_SIZE_NUM_ROWS; shape++)
+ {
+ for (int i = 0; i < BRUSH_SIZE_NUM_COLS; i++)
+ {
+ int w = (width () - 2/*margin*/ - 2/*spacing*/) / BRUSH_SIZE_NUM_COLS;
+ int h = (height () - 2/*margin*/ - 3/*spacing*/) / BRUSH_SIZE_NUM_ROWS;
+ pm->resize ((w <= 0 ? width () : w),
+ (h <= 0 ? height () : h));
+
+ const int s = brushSize [shape][i];
+ QRect rect;
+
+ if (s >= pm->width () || s >= pm->height ())
+ rect = QRect (0, 0, pm->width (), pm->height ());
+ else
+ {
+ rect = QRect ((pm->width () - s) / 2,
+ (pm->height () - s) / 2,
+ s,
+ s);
+ }
+
+ #if DEBUG_KP_TOOL_WIDGET_BRUSH
+ kdDebug () << "kpToolWidgetBrush::kpToolWidgetBrush() rect=" << rect << endl;
+ #endif
+
+ pm->fill (Qt::white);
+
+ QPainter painter (pm);
+ painter.setPen (Qt::black);
+ painter.setBrush (Qt::black);
+
+ // sync: <brushes>
+ switch (shape)
+ {
+ case 0:
+ painter.drawEllipse (rect);
+ break;
+ case 1:
+ painter.drawRect (rect);
+ break;
+ case 2:
+ painter.drawLine (rect.topRight (), rect.bottomLeft ());
+ break;
+ case 3:
+ painter.drawLine (rect.topLeft (), rect.bottomRight ());
+ break;
+ }
+ painter.end ();
+
+ pm->setMask (pm->createHeuristicMask ());
+ addOption (*pm, brushName (shape, i)/*tooltip*/);
+
+ pm++;
+ }
+
+ startNewOptionRow ();
+ }
+
+ finishConstruction (0, 0);
+}
+
+kpToolWidgetBrush::~kpToolWidgetBrush ()
+{
+}
+
+
+// private
+QString kpToolWidgetBrush::brushName (int shape, int whichSize)
+{
+ int s = brushSize [shape][whichSize];
+
+ if (s == 1)
+ return i18n ("1x1");
+
+ QString shapeName;
+
+ // sync: <brushes>
+ switch (shape)
+ {
+ case 0:
+ shapeName = i18n ("Circle");
+ break;
+ case 1:
+ shapeName = i18n ("Square");
+ break;
+ case 2:
+ // TODO: is this really the name of a shape? :)
+ shapeName = i18n ("Slash");
+ break;
+ case 3:
+ // TODO: is this really the name of a shape? :)
+ shapeName = i18n ("Backslash");
+ break;
+ }
+
+ if (shapeName.isEmpty ())
+ return QString::null;
+
+ return i18n ("%1x%2 %3").arg (s).arg (s).arg (shapeName);
+}
+
+QPixmap kpToolWidgetBrush::brush () const
+{
+ return m_brushBitmaps [selectedRow () * BRUSH_SIZE_NUM_COLS + selectedCol ()];
+}
+
+bool kpToolWidgetBrush::brushIsDiagonalLine () const
+{
+ // sync: <brushes>
+ return (selectedRow () >= 2);
+}
+
+// virtual protected slot [base kpToolWidgetBase]
+bool kpToolWidgetBrush::setSelected (int row, int col, bool saveAsDefault)
+{
+ const bool ret = kpToolWidgetBase::setSelected (row, col, saveAsDefault);
+ if (ret)
+ emit brushChanged (brush (), brushIsDiagonalLine ());
+ return ret;
+}
+
+#include <kptoolwidgetbrush.moc>
diff --git a/kolourpaint/widgets/kptoolwidgetbrush.h b/kolourpaint/widgets/kptoolwidgetbrush.h
new file mode 100644
index 00000000..db222e79
--- /dev/null
+++ b/kolourpaint/widgets/kptoolwidgetbrush.h
@@ -0,0 +1,61 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolwidgetbrush_h__
+#define __kptoolwidgetbrush_h__
+
+#include <qpixmap.h>
+
+#include <kptoolwidgetbase.h>
+
+class kpToolWidgetBrush : public kpToolWidgetBase
+{
+Q_OBJECT
+
+public:
+ kpToolWidgetBrush (QWidget *parent, const char *name);
+ virtual ~kpToolWidgetBrush ();
+
+private:
+ QString brushName (int shape, int whichSize);
+
+public:
+ QPixmap brush () const;
+ bool brushIsDiagonalLine () const;
+
+signals:
+ void brushChanged (const QPixmap &pixmap, bool isDiagonalLine);
+
+protected slots:
+ virtual bool setSelected (int row, int col, bool saveAsDefault);
+
+private:
+ QPixmap m_brushBitmaps [16];
+};
+
+#endif // __kptoolwidgetbrush_h__
diff --git a/kolourpaint/widgets/kptoolwidgeterasersize.cpp b/kolourpaint/widgets/kptoolwidgeterasersize.cpp
new file mode 100644
index 00000000..cc58c0d1
--- /dev/null
+++ b/kolourpaint/widgets/kptoolwidgeterasersize.cpp
@@ -0,0 +1,161 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_TOOL_WIDGET_ERASER_SIZE 0
+
+
+#include <kptoolwidgeterasersize.h>
+
+#include <qbitmap.h>
+#include <qpainter.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcolor.h>
+#include <kptool.h>
+
+
+static int eraserSizes [] = {2, 3, 5, 9, 17, 29};
+static const int numEraserSizes = int (sizeof (eraserSizes) / sizeof (eraserSizes [0]));
+
+
+kpToolWidgetEraserSize::kpToolWidgetEraserSize (QWidget *parent, const char *name)
+ : kpToolWidgetBase (parent, name)
+{
+ setInvertSelectedPixmap ();
+
+ m_cursorPixmaps = new QPixmap [numEraserSizes];
+ QPixmap *cursorPixmap = m_cursorPixmaps;
+
+ for (int i = 0; i < numEraserSizes; i++)
+ {
+ if (i == 3 || i == 5)
+ startNewOptionRow ();
+
+ int s = eraserSizes [i];
+
+ cursorPixmap->resize (s, s);
+ cursorPixmap->fill (Qt::black);
+
+
+ QPixmap previewPixmap (s, s);
+ if (i < 3)
+ {
+ // HACK: kpToolWidgetBase's layout code sucks and gives uneven spacing
+ previewPixmap.resize ((width () - 4) / 3, 9);
+ }
+
+ QPainter painter (&previewPixmap);
+ QRect rect ((previewPixmap.width () - s) / 2, (previewPixmap.height () - s) / 2, s, s);
+ painter.fillRect (rect, Qt::black);
+ painter.end ();
+
+ QBitmap mask (previewPixmap.width (), previewPixmap.height ());
+ mask.fill (Qt::color0/*transparent*/);
+
+ QPainter maskPainter (&mask);
+ maskPainter.fillRect (rect, Qt::color1/*opaque*/);
+ maskPainter.end ();
+
+ previewPixmap.setMask (mask);
+
+
+ addOption (previewPixmap, i18n ("%1x%2").arg (s).arg (s)/*tooltip*/);
+
+
+ cursorPixmap++;
+ }
+
+ finishConstruction (1, 0);
+}
+
+kpToolWidgetEraserSize::~kpToolWidgetEraserSize ()
+{
+ delete [] m_cursorPixmaps;
+}
+
+int kpToolWidgetEraserSize::eraserSize () const
+{
+ return eraserSizes [selected ()];
+}
+
+QPixmap kpToolWidgetEraserSize::cursorPixmap (const kpColor &color) const
+{
+#if DEBUG_KP_TOOL_WIDGET_ERASER_SIZE
+ kdDebug () << "kpToolWidgetEraseSize::cursorPixmap() selected=" << selected ()
+ << " numEraserSizes=" << numEraserSizes
+ << endl;
+#endif
+
+ // TODO: why are we even storing m_cursorPixmaps?
+ QPixmap pixmap = m_cursorPixmaps [selected ()];
+ if (color.isOpaque ())
+ pixmap.fill (color.toQColor ());
+
+
+ bool showBorder = (pixmap.width () > 2 && pixmap.height () > 2);
+
+ if (showBorder)
+ {
+ QPainter painter (&pixmap);
+ painter.setPen (Qt::black);
+ painter.drawRect (pixmap.rect ());
+ }
+
+
+ if (color.isTransparent ())
+ {
+ QBitmap maskBitmap (pixmap.width (), pixmap.height ());
+ maskBitmap.fill (Qt::color0/*transparent*/);
+
+
+ if (showBorder)
+ {
+ QPainter maskBitmapPainter (&maskBitmap);
+ maskBitmapPainter.setPen (Qt::color1/*opaque*/);
+ maskBitmapPainter.drawRect (maskBitmap.rect ());
+ }
+
+
+ pixmap.setMask (maskBitmap);
+ }
+
+
+ return pixmap;
+}
+
+// virtual protected slot [base kpToolWidgetBase]
+bool kpToolWidgetEraserSize::setSelected (int row, int col, bool saveAsDefault)
+{
+ const bool ret = kpToolWidgetBase::setSelected (row, col, saveAsDefault);
+ if (ret)
+ emit eraserSizeChanged (eraserSize ());
+ return ret;
+}
+
+#include <kptoolwidgeterasersize.moc>
diff --git a/kolourpaint/widgets/kptoolwidgeterasersize.h b/kolourpaint/widgets/kptoolwidgeterasersize.h
new file mode 100644
index 00000000..71093fd6
--- /dev/null
+++ b/kolourpaint/widgets/kptoolwidgeterasersize.h
@@ -0,0 +1,59 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolwidgeterasersize_h__
+#define __kptoolwidgeterasersize_h__
+
+#include <qpixmap.h>
+#include <kptoolwidgetbase.h>
+
+
+class kpColor;
+
+class kpToolWidgetEraserSize : public kpToolWidgetBase
+{
+Q_OBJECT
+
+public:
+ kpToolWidgetEraserSize (QWidget *parent, const char *name);
+ virtual ~kpToolWidgetEraserSize ();
+
+ int eraserSize () const;
+ QPixmap cursorPixmap (const kpColor &color) const;
+
+signals:
+ void eraserSizeChanged (int size);
+
+protected slots:
+ virtual bool setSelected (int row, int col, bool saveAsDefault);
+
+private:
+ QPixmap *m_cursorPixmaps;
+};
+
+#endif // __kptoolwidgeterasersize_h__
diff --git a/kolourpaint/widgets/kptoolwidgetfillstyle.cpp b/kolourpaint/widgets/kptoolwidgetfillstyle.cpp
new file mode 100644
index 00000000..74c174ce
--- /dev/null
+++ b/kolourpaint/widgets/kptoolwidgetfillstyle.cpp
@@ -0,0 +1,222 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_TOOL_WIDGET_FILL_STYLE 0
+
+
+#include <kptoolwidgetfillstyle.h>
+
+#include <qbitmap.h>
+#include <qbrush.h>
+#include <qpainter.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kpcolor.h>
+#include <kpdefs.h>
+#include <kptool.h>
+
+
+kpToolWidgetFillStyle::kpToolWidgetFillStyle (QWidget *parent, const char *name)
+ : kpToolWidgetBase (parent, name)
+{
+ setInvertSelectedPixmap ();
+
+ for (int i = 0; i < (int) FillStyleNum; i++)
+ {
+ QPixmap pixmap;
+
+ pixmap = fillStylePixmap ((FillStyle) i,
+ (width () - 2/*margin*/) * 3 / 4,
+ (height () - 2/*margin*/ - 2/*spacing*/) * 3 / (3 * 4));
+ addOption (pixmap, fillStyleName ((FillStyle) i)/*tooltip*/);
+
+ startNewOptionRow ();
+ }
+
+ finishConstruction (0, 0);
+}
+
+kpToolWidgetFillStyle::~kpToolWidgetFillStyle ()
+{
+}
+
+
+// private
+QPixmap kpToolWidgetFillStyle::fillStylePixmap (FillStyle fs, int w, int h)
+{
+ QPixmap pixmap ((w <= 0 ? width () : w), (h <= 0 ? height () : h));
+ pixmap.fill (Qt::white);
+
+ QPainter painter (&pixmap);
+
+ painter.setPen (QPen (Qt::black, 2));
+ painter.setBrush (brushForFillStyle (fs,
+ kpColor (Qt::black.rgb ())/*foreground*/,
+ kpColor (Qt::gray.rgb ())/*background*/));
+
+ painter.drawRect (2, 2, w - 3, h - 3);
+
+ painter.end ();
+
+
+ QBitmap mask (pixmap.width (), pixmap.height ());
+ mask.fill (Qt::color0);
+
+ painter.begin (&mask);
+ painter.setPen (QPen (Qt::color1, 2));
+
+ if (fs == FillWithBackground || fs == FillWithForeground)
+ painter.setBrush (Qt::color1);
+
+ painter.drawRect (2, 2, w - 3, h - 3);
+
+ painter.end ();
+
+ pixmap.setMask (mask);
+
+ return pixmap;
+}
+
+// private
+QString kpToolWidgetFillStyle::fillStyleName (FillStyle fs) const
+{
+ // do not complain about the "useless" breaks
+ // as the return statements might not be return statements one day
+
+ switch (fs)
+ {
+ case NoFill:
+ return i18n ("No Fill");
+ break;
+ case FillWithBackground:
+ return i18n ("Fill with Background Color");
+ break;
+ case FillWithForeground:
+ return i18n ("Fill with Foreground Color");
+ break;
+ default:
+ return QString::null;
+ break;
+ }
+}
+
+
+// public
+kpToolWidgetFillStyle::FillStyle kpToolWidgetFillStyle::fillStyle () const
+{
+#if DEBUG_KP_TOOL_WIDGET_FILL_STYLE
+ kdDebug () << "kpToolWidgetFillStyle::fillStyle() selected="
+ << selectedRow ()
+ << endl;
+#endif
+ return (FillStyle) selectedRow ();
+}
+
+// public static
+QBrush kpToolWidgetFillStyle::maskBrushForFillStyle (FillStyle fs,
+ const kpColor &foregroundColor,
+ const kpColor &backgroundColor)
+{
+ // do not complain about the "useless" breaks
+ // as the return statements might not be return statements one day
+
+ switch (fs)
+ {
+ case NoFill:
+ return Qt::NoBrush;
+ break;
+ case FillWithBackground:
+ return QBrush (backgroundColor.maskColor ());
+ break;
+ case FillWithForeground:
+ return QBrush (foregroundColor.maskColor ());
+ break;
+ default:
+ return Qt::NoBrush;
+ break;
+ }
+}
+
+QBrush kpToolWidgetFillStyle::maskBrush (const kpColor &foregroundColor,
+ const kpColor &backgroundColor)
+{
+ return maskBrushForFillStyle (fillStyle (), foregroundColor, backgroundColor);
+}
+
+// public static
+QBrush kpToolWidgetFillStyle::brushForFillStyle (FillStyle fs,
+ const kpColor &foregroundColor,
+ const kpColor &backgroundColor)
+{
+ // do not complain about the "useless" breaks
+ // as the return statements might not be return statements one day
+
+ // sync: kptoolpolygon.cpp pixmap()
+
+ switch (fs)
+ {
+ case NoFill:
+ return Qt::NoBrush;
+ break;
+ case FillWithBackground:
+ if (backgroundColor.isOpaque ())
+ return QBrush (backgroundColor.toQColor ());
+ else
+ return Qt::NoBrush;
+ break;
+ case FillWithForeground:
+ if (foregroundColor.isOpaque ())
+ return QBrush (foregroundColor.toQColor ());
+ else
+ return Qt::NoBrush;
+ break;
+ default:
+ return Qt::NoBrush;
+ break;
+ }
+}
+
+// public
+QBrush kpToolWidgetFillStyle::brush (const kpColor &foregroundColor,
+ const kpColor &backgroundColor)
+{
+ return brushForFillStyle (fillStyle (), foregroundColor, backgroundColor);
+}
+
+
+// virtual protected slot [base kpToolWidgetBase]
+bool kpToolWidgetFillStyle::setSelected (int row, int col, bool saveAsDefault)
+{
+ const bool ret = kpToolWidgetBase::setSelected (row, col, saveAsDefault);
+ if (ret)
+ emit fillStyleChanged (fillStyle ());
+ return ret;
+}
+
+#include <kptoolwidgetfillstyle.moc>
diff --git a/kolourpaint/widgets/kptoolwidgetfillstyle.h b/kolourpaint/widgets/kptoolwidgetfillstyle.h
new file mode 100644
index 00000000..219d47f2
--- /dev/null
+++ b/kolourpaint/widgets/kptoolwidgetfillstyle.h
@@ -0,0 +1,80 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolwidgetfillstyle_h__
+#define __kptoolwidgetfillstyle_h__
+
+#include <kptoolwidgetbase.h>
+
+class QBrush;
+
+class kpColor;
+
+class kpToolWidgetFillStyle : public kpToolWidgetBase
+{
+Q_OBJECT
+
+public:
+ kpToolWidgetFillStyle (QWidget *parent, const char *name);
+ virtual ~kpToolWidgetFillStyle ();
+
+ enum FillStyle
+ {
+ NoFill,
+ FillWithBackground,
+ FillWithForeground,
+ FillStyleNum /* not (a valid FillStyle) */
+ };
+
+private:
+ QPixmap fillStylePixmap (FillStyle fs, int width, int height);
+ QString fillStyleName (FillStyle fs) const;
+
+public:
+ FillStyle fillStyle () const;
+
+ static QBrush maskBrushForFillStyle (FillStyle fs,
+ const kpColor &foregroundColor,
+ const kpColor &backgroundColor);
+ QBrush maskBrush (const kpColor &foregroundColor,
+ const kpColor &backgroundColor);
+
+ static QBrush brushForFillStyle (FillStyle fs,
+ const kpColor &foregroundColor,
+ const kpColor &backgroundColor);
+ QBrush brush (const kpColor &foregroundColor,
+ const kpColor &backgroundColor);
+
+signals:
+ void fillStyleChanged (kpToolWidgetFillStyle::FillStyle fillStyle);
+
+protected slots:
+ virtual bool setSelected (int row, int col, bool saveAsDefault);
+};
+
+#endif // __kptoolwidgetfillstyle_h__
diff --git a/kolourpaint/widgets/kptoolwidgetlinewidth.cpp b/kolourpaint/widgets/kptoolwidgetlinewidth.cpp
new file mode 100644
index 00000000..27e34ecb
--- /dev/null
+++ b/kolourpaint/widgets/kptoolwidgetlinewidth.cpp
@@ -0,0 +1,97 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include <kptoolwidgetlinewidth.h>
+
+#include <qbitmap.h>
+#include <qpainter.h>
+
+#include <klocale.h>
+
+
+static int lineWidths [] = {1, 2, 3, 5, 8};
+
+kpToolWidgetLineWidth::kpToolWidgetLineWidth (QWidget *parent, const char *name)
+ : kpToolWidgetBase (parent, name)
+{
+ setInvertSelectedPixmap ();
+
+ int numLineWidths = sizeof (lineWidths) / sizeof (lineWidths [0]);
+
+ int w = (width () - 2/*margin*/) * 3 / 4;
+ int h = (height () - 2/*margin*/ - (numLineWidths - 1)/*spacing*/) * 3 / (numLineWidths * 4);
+
+ for (int i = 0; i < numLineWidths; i++)
+ {
+ QPixmap pixmap ((w <= 0 ? width () : w),
+ (h <= 0 ? height () : h));
+ pixmap.fill (Qt::white);
+
+ QBitmap maskBitmap (pixmap.width (), pixmap.height ());
+ maskBitmap.fill (Qt::color0/*transparent*/);
+
+
+ QPainter painter (&pixmap), maskPainter (&maskBitmap);
+ painter.setPen (Qt::black), maskPainter.setPen (Qt::color1/*opaque*/);
+ painter.setBrush (Qt::black), maskPainter.setBrush (Qt::color1/*opaque*/);
+
+ QRect rect = QRect (0, (pixmap.height () - lineWidths [i]) / 2,
+ pixmap.width (), lineWidths [i]);
+ painter.drawRect (rect), maskPainter.drawRect (rect);
+
+ painter.end (), maskPainter.end ();
+
+
+ pixmap.setMask (maskBitmap);
+
+ addOption (pixmap, QString::number (lineWidths [i]));
+ startNewOptionRow ();
+ }
+
+ finishConstruction (0, 0);
+}
+
+kpToolWidgetLineWidth::~kpToolWidgetLineWidth ()
+{
+}
+
+int kpToolWidgetLineWidth::lineWidth () const
+{
+ return lineWidths [selectedRow ()];
+}
+
+// virtual protected slot [base kpToolWidgetBase]
+bool kpToolWidgetLineWidth::setSelected (int row, int col, bool saveAsDefault)
+{
+ const bool ret = kpToolWidgetBase::setSelected (row, col, saveAsDefault);
+ if (ret)
+ emit lineWidthChanged (lineWidth ());
+ return ret;
+}
+
+#include <kptoolwidgetlinewidth.moc>
diff --git a/kolourpaint/widgets/kptoolwidgetlinewidth.h b/kolourpaint/widgets/kptoolwidgetlinewidth.h
new file mode 100644
index 00000000..3255e443
--- /dev/null
+++ b/kolourpaint/widgets/kptoolwidgetlinewidth.h
@@ -0,0 +1,51 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolwidgetlinewidth_h__
+#define __kptoolwidgetlinewidth_h__
+
+#include <kptoolwidgetbase.h>
+
+class kpToolWidgetLineWidth : public kpToolWidgetBase
+{
+Q_OBJECT
+
+public:
+ kpToolWidgetLineWidth (QWidget *parent, const char *name);
+ virtual ~kpToolWidgetLineWidth ();
+
+ int lineWidth () const;
+
+signals:
+ void lineWidthChanged (int width);
+
+protected slots:
+ virtual bool setSelected (int row, int col, bool saveAsDefault);
+};
+
+#endif // __kptoolwidgetlinewidth_h__
diff --git a/kolourpaint/widgets/kptoolwidgetopaqueortransparent.cpp b/kolourpaint/widgets/kptoolwidgetopaqueortransparent.cpp
new file mode 100644
index 00000000..41b55d0f
--- /dev/null
+++ b/kolourpaint/widgets/kptoolwidgetopaqueortransparent.cpp
@@ -0,0 +1,100 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define DEBUG_KP_TOOL_WIDGET_OPAQUE_OR_TRANSPARENT 0
+
+
+#include <kptoolwidgetopaqueortransparent.h>
+
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <klocale.h>
+
+
+kpToolWidgetOpaqueOrTransparent::kpToolWidgetOpaqueOrTransparent (QWidget *parent, const char *name)
+ : kpToolWidgetBase (parent, name)
+{
+ setInvertSelectedPixmap (false);
+
+ addOption (UserIcon ("option_opaque"), i18n ("Opaque")/*tooltip*/);
+ startNewOptionRow ();
+ addOption (UserIcon ("option_transparent"), i18n ("Transparent")/*tooltip*/);
+
+ finishConstruction (0, 0);
+}
+
+kpToolWidgetOpaqueOrTransparent::~kpToolWidgetOpaqueOrTransparent ()
+{
+}
+
+
+// public
+bool kpToolWidgetOpaqueOrTransparent::isOpaque () const
+{
+ return (selected () == 0);
+}
+
+// public
+bool kpToolWidgetOpaqueOrTransparent::isTransparent () const
+{
+ return (!isOpaque ());
+}
+
+// public
+void kpToolWidgetOpaqueOrTransparent::setOpaque (bool yes)
+{
+#if DEBUG_KP_TOOL_WIDGET_OPAQUE_OR_TRANSPARENT && 1
+ kdDebug () << "kpToolWidgetOpaqueOrTransparent::setOpaque(" << yes << ")" << endl;
+#endif
+ setSelected (yes ? 0 : 1, 0, false/*don't save*/);
+}
+
+// public
+void kpToolWidgetOpaqueOrTransparent::setTransparent (bool yes)
+{
+#if DEBUG_KP_TOOL_WIDGET_OPAQUE_OR_TRANSPARENT && 1
+ kdDebug () << "kpToolWidgetOpaqueOrTransparent::setTransparent(" << yes << ")" << endl;
+#endif
+ setSelected (yes ? 1 : 0, 0, false/*don't save*/);
+}
+
+
+// protected slot virtual [base kpToolWidgetBase]
+bool kpToolWidgetOpaqueOrTransparent::setSelected (int row, int col, bool saveAsDefault)
+{
+#if DEBUG_KP_TOOL_WIDGET_OPAQUE_OR_TRANSPARENT && 1
+ kdDebug () << "kpToolWidgetOpaqueOrTransparent::setSelected("
+ << row << "," << col << ")" << endl;
+#endif
+ const bool ret = kpToolWidgetBase::setSelected (row, col, saveAsDefault);
+ if (ret)
+ emit isOpaqueChanged (isOpaque ());
+ return ret;
+}
+
+
+#include <kptoolwidgetopaqueortransparent.moc>
diff --git a/kolourpaint/widgets/kptoolwidgetopaqueortransparent.h b/kolourpaint/widgets/kptoolwidgetopaqueortransparent.h
new file mode 100644
index 00000000..c24cd308
--- /dev/null
+++ b/kolourpaint/widgets/kptoolwidgetopaqueortransparent.h
@@ -0,0 +1,56 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kp_tool_widget_opaque_or_transparent_h__
+#define __kp_tool_widget_opaque_or_transparent_h__
+
+
+#include <kptoolwidgetbase.h>
+
+class kpToolWidgetOpaqueOrTransparent : public kpToolWidgetBase
+{
+Q_OBJECT
+
+public:
+ kpToolWidgetOpaqueOrTransparent (QWidget *parent, const char *name);
+ virtual ~kpToolWidgetOpaqueOrTransparent ();
+
+ bool isOpaque () const;
+ bool isTransparent () const;
+ void setOpaque (bool yes = true);
+ void setTransparent (bool yes = true);
+
+signals:
+ void isOpaqueChanged (bool isOpaque_);
+
+protected slots:
+ virtual bool setSelected (int row, int col, bool saveAsDefault);
+};
+
+
+#endif // kp_tool_widget_opaque_or_transparent_h__
diff --git a/kolourpaint/widgets/kptoolwidgetspraycansize.cpp b/kolourpaint/widgets/kptoolwidgetspraycansize.cpp
new file mode 100644
index 00000000..161e5015
--- /dev/null
+++ b/kolourpaint/widgets/kptoolwidgetspraycansize.cpp
@@ -0,0 +1,119 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define DEBUG_KP_TOOL_WIDGET_SPRAYCAN_SIZE 0
+
+
+#include <kptoolwidgetspraycansize.h>
+
+#include <qbitmap.h>
+#include <qimage.h>
+#include <qpainter.h>
+
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <klocale.h>
+
+#include <kppixmapfx.h>
+
+
+static int spraycanSizes [] = {9, 17, 29};
+
+kpToolWidgetSpraycanSize::kpToolWidgetSpraycanSize (QWidget *parent, const char *name)
+ : kpToolWidgetBase (parent, name)
+{
+#if DEBUG_KP_TOOL_WIDGET_SPRAYCAN_SIZE
+ kdDebug () << "kpToolWidgetSpraycanSize::kpToolWidgetSpraycanSize() CALLED!" << endl;
+#endif
+
+ for (int i = 0; i < int (sizeof (spraycanSizes) / sizeof (spraycanSizes [0])); i++)
+ {
+ int s = spraycanSizes [i];
+ QString iconName = QString ("tool_spraycan_%1x%1").arg (s).arg(s);
+
+ #if DEBUG_KP_TOOL_WIDGET_SPRAYCAN_SIZE
+ kdDebug () << "\ticonName=" << iconName << endl;
+ #endif
+
+ QPixmap pixmap (s, s);
+ pixmap.fill (Qt::white);
+
+ QPainter painter (&pixmap);
+ painter.drawPixmap (0, 0, UserIcon (iconName));
+ painter.end ();
+
+ QImage image = kpPixmapFX::convertToImage (pixmap);
+
+ QBitmap mask (pixmap.width (), pixmap.height ());
+ mask.fill (Qt::color0);
+
+ painter.begin (&mask);
+ painter.setPen (Qt::color1);
+
+ for (int y = 0; y < image.height (); y++)
+ {
+ for (int x = 0; x < image.width (); x++)
+ {
+ if ((image.pixel (x, y) & RGB_MASK) == 0/*black*/)
+ painter.drawPoint (x, y); // mark as opaque
+ }
+ }
+
+ painter.end ();
+
+ pixmap.setMask (mask);
+
+ addOption (pixmap, i18n ("%1x%2").arg (s).arg (s)/*tooltip*/);
+ if (i == 1)
+ startNewOptionRow ();
+ }
+
+ finishConstruction (0, 0);
+}
+
+kpToolWidgetSpraycanSize::~kpToolWidgetSpraycanSize ()
+{
+}
+
+
+// public
+int kpToolWidgetSpraycanSize::spraycanSize () const
+{
+ return spraycanSizes [selected ()];
+}
+
+// protected slot virtual [base kpToolWidgetBase]
+bool kpToolWidgetSpraycanSize::setSelected (int row, int col, bool saveAsDefault)
+{
+ const bool ret = kpToolWidgetBase::setSelected (row, col, saveAsDefault);
+ if (ret)
+ emit spraycanSizeChanged (spraycanSize ());
+ return ret;
+}
+
+#include <kptoolwidgetspraycansize.moc>
diff --git a/kolourpaint/widgets/kptoolwidgetspraycansize.h b/kolourpaint/widgets/kptoolwidgetspraycansize.h
new file mode 100644
index 00000000..b4233a80
--- /dev/null
+++ b/kolourpaint/widgets/kptoolwidgetspraycansize.h
@@ -0,0 +1,51 @@
+
+/*
+ Copyright (c) 2003,2004,2005 Clarence Dang <dang@kde.org>
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef __kptoolwidgetspraycansize_h__
+#define __kptoolwidgetspraycansize_h__
+
+#include <kptoolwidgetbase.h>
+
+class kpToolWidgetSpraycanSize : public kpToolWidgetBase
+{
+Q_OBJECT
+
+public:
+ kpToolWidgetSpraycanSize (QWidget *parent, const char *name);
+ virtual ~kpToolWidgetSpraycanSize ();
+
+ int spraycanSize () const;
+
+signals:
+ void spraycanSizeChanged (int size);
+
+protected slots:
+ virtual bool setSelected (int row, int col, bool saveAsDefault);
+};
+
+#endif // __kptoolwidgetspraycansize_h__
diff --git a/kooka/AUTHORS b/kooka/AUTHORS
new file mode 100644
index 00000000..41f6d7f2
--- /dev/null
+++ b/kooka/AUTHORS
@@ -0,0 +1,2 @@
+Ivan Shvedunov <ivan_iv@rf-hp.npi.msu.su>
+Klaas Freitag <freitag@SuSE.de>
diff --git a/kooka/CHANGES b/kooka/CHANGES
new file mode 100644
index 00000000..0b384de6
--- /dev/null
+++ b/kooka/CHANGES
@@ -0,0 +1,158 @@
+-> Nov. 2000, Klaas Freitag <freitag@suse.de>:
+initial version
+
+- December 2000, Klaas Freitag <freitag@suse.de>:
+
+Added support for calling the external ocr program gocr of Joerg
+Schulenburg and friends. See http://jocr.sourceforge.net for
+details. Mind that still everything is under construction, even if
+there could be some interesting screen hots around.
+
+OCR works best with smaller parts of text scanned black-and-white
+scanned with about 150 dpi.
+
+-> Released version 0.2 on kde.org
+
+- December 2000, Klaas Freitag <freitag@suse.de>:
+
+* Reworked the ocr integration: Nice start- and finish-dialog,
+ animated status image, opening a text editor with the result text
+ via mime mechanism of KDE (KRun). OCR-Parameter get stored via KConfig.
+ OCR may be performed on the entire image or the selection.
+
+* Reworked the save assistant: New layout and fully KDE2-Compliant.
+ Still no new Image format help texts.
+
+* Reworked the startup dialog: Allows to select the scan device from a
+ list of available devices, possible to set the startup scan device
+ 'forever'.
+
+* Resizing of the scan parameters. The scan parameters shell should
+ take as much as space as it needs. It is not longer fix sized now.
+
+* Mirroring in three kinds of the displayed image with toolbar and menubar
+ entries. That needed that the packager is able to handle changes on already
+ saved images.
+
+* Creation of new images from the selection on the image canvas.
+
+- Jan 2001, Klaas Freitag <freitag@suse.de>:
+
+* Rotating of images.
+
+* Opening images in a kde graphic app.
+
+* Proper error messages if a changed image cant be saved.
+
+* drag and drop support: Pull an image from konqueror on the scanpackager !
+ The image wil be importet.
+
+* print support (basic)
+
+* basic configuration support
+
+ ... and losts of other, small bug fixes, unfortunately not mentionend very
+ well here. Sorry for that, I will try to do better.
+
+/* ================================================================================ */
+
+-> Released version 0.3 in kdegraphics/kooka for KDE 2.2
+The released version does actually not have too many new
+
+- July 2001, Klaas Freitag <freitag@suse.de>
+
+* fixed the img_saver-bug that the 'Do not ask again' is not honored.
+ Now it should be, if it is checked, the format-Dialog will not be
+ displayed again.
+
+* added a new section Image saver to the properties dialog
+
+* some changes to the image saver to display the image type (Lineart etc. )
+
+* bugfixes in the image Saver
+
+/* ================================================================================ */
+Nov 2001:
+Added a combo box below kooka's gallery widget. Since the gallery and the
+the preview window are in a tabwidget together, user complained that they
+do not see the directory they are scanning to while working on the preview
+page. The combobox shows the currently selected directory and is always
+visible. The user can use the combo to change the target dir without leaving
+the preview page.
+
+Nov 2001:
+Replaced the old ScanPackager object by a new one based on the new KFileTreeView
+Widget in kdelibs/kfile. Hopefully soon full KURL support and more than one image
+repository.
+
+Nov 2001:
+Moved preview image to a hidden directory under $KDEHOME/share/apps/ScanImages/.previews
+That makes the preview images invisible in the Packager.
+
+/* ================================================================================ */
+
+many bugfixes for KDE 3.0 -> Released Kooka 0.35 for KDE 3.0
+
+Released Kooka 0.36 for KDE 3.0.1
+
+Mai 2002:
+ Added Thumbnail View with Preference Dialog => Kooka Release 0.37
+ Completed About dialog and added the Webpage http://kooka.kde.org
+
+/* ================================================================================ */
+
+For Kooka 0.38: Introduced KDockWidgets to make the GUI configurable to everybodies
+needs.
+
+/* ================================================================================ */
+
+For Kooka 0.39:
+
+* Fixed problem with gocr: gocr always resulted in (PICTURE) - fixed
+ it by changing the save format for images to gocr. This bug happens
+ only with gocr 0.3.5 (and probably higher).
+
+* Renaming images inline reimplemented again.
+
+* exported Gallery Actions to appear in the menu bar again.
+
+* added a progress bar and bugfixes to the thumbview
+
+* added halftoning to the scanservice and thus kooka
+
+* fixed bugs in the resolving of dependencies of scanner parameters.
+
+/* ================================================================================ */
+
+For Kooka 0.40:
+
+* Added Kadmos-Check to configure.in.in
+
+* Changed the Mainwindow to be KParts-Mainwindow,neccessary for using Parts in Kooka
+
+* OCR: Code massive reorganised. More ability to use different ocr engines.
+
+* OCR: Preparation to use Kadmos OCR engine.
+
+* OCR: Result not longer in a separat dialog, but in a editor part.
+
+* Scanpackager uses KookaImage more consequently. That provides meta data where needed
+
+* Improved image viewer from libkscan: Holds zoom settings over images
+
+* image information in status bar.
+
+/* ================================================================================ */
+
+For Kooka 0.41:
+
+* Added support for ocrad OCR software.
+
+* Added image printing tab to the tab dialog, good printing support.
+
+* fixed some bugs with OCR result image handling.
+
+* libkscan: Fixed a cast bug with scan source selection
+
+* Improved support for tiff images, handle images with different x- and y resolution
+ correctly.
diff --git a/kooka/COPYING b/kooka/COPYING
new file mode 100644
index 00000000..0b84a43f
--- /dev/null
+++ b/kooka/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/kooka/CREDITS b/kooka/CREDITS
new file mode 100644
index 00000000..cbb0bf8b
--- /dev/null
+++ b/kooka/CREDITS
@@ -0,0 +1,4 @@
+Kooka and KScan has been derived from the the 1997 work of Ivan
+Shvedunov <ivan_iv@rf-hp.npi.msu.su>, his homepage can be found at
+http://rf-hp.npi.msu.su.
+
diff --git a/kooka/INSTALL b/kooka/INSTALL
new file mode 100644
index 00000000..28fadaa7
--- /dev/null
+++ b/kooka/INSTALL
@@ -0,0 +1,181 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made.
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
+
diff --git a/kooka/Makefile.am b/kooka/Makefile.am
new file mode 100644
index 00000000..6fec098e
--- /dev/null
+++ b/kooka/Makefile.am
@@ -0,0 +1,46 @@
+## Makefile.am for kooka
+
+SUBDIRS = pics
+
+bin_PROGRAMS = kooka
+METASOURCES = AUTO
+
+kooka_SOURCES = main.cpp kooka.cpp kookaview.cpp kookapref.cpp \
+ img_saver.cpp ksaneocr.cpp \
+ kookaimage.cpp kookaimagemeta.cpp scanpackager.cpp \
+ imgnamecombo.cpp imageselectline.cpp \
+ thumbview.cpp thumbviewitem.cpp \
+ dwmenuaction.cpp kocrbase.cpp \
+ kocrgocr.cpp kocrkadmos.cpp kadmosocr.cpp ocrword.cpp \
+ ocrresedit.cpp kookaprint.cpp imgprintdialog.cpp \
+ kocrocrad.cpp
+# pagesetup.cpp
+
+kooka_LDADD = $(LIB_KFILE) -lkdeprint -lktexteditor $(LIBTIFF) $(top_builddir)/libkscan/libkscan.la $(KADMOS_LIB) $(LIB_KSPELL)
+kooka_LDFLAGS = $(KDE_RPATH) $(all_libraries)
+
+INCLUDES = -I$(top_srcdir)/libkscan $(all_includes) $(LIBSANE_INCLUDES) $(KADMOS_INC)
+
+noinst_HEADERS = \
+kookaview.h scanpackager.h \
+img_saver.h ksaneocr.h \
+formathelp.h kooka.h \
+kookaiface.h thumbview.h thumbviewitem.h \
+kookapref.h resource.h \
+imgnamecombo.h imageselectline.h kookaimage.h kookaimagemeta.h \
+kocrbase.h kocrgocr.h kocrkadmos.h \
+kadmosocr.h ocrword.h ocrresedit.h kookaprint.h imgprintdialog.h \
+kocrocrad.h
+
+# pagesetup.h
+
+appdatadir = $(kde_datadir)/kooka
+appdata_DATA = kookaui.rc
+
+kde_conf_DATA = kookarc
+
+xdg_apps_DATA = kooka.desktop
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/kooka.pot
+
diff --git a/kooka/README b/kooka/README
new file mode 100644
index 00000000..8ae6fa54
--- /dev/null
+++ b/kooka/README
@@ -0,0 +1,66 @@
+Kooka
+=====
+
+Kooka is a raster image scan program for the KDE system.
+
+ PLEASE READ THE FILE "WARNING" FIRST !
+
+It uses the SANE-lib (http://www.sane-project.org/) and the the
+KScan-library which is a KDE module for scanner access.
+
+KScan and Kooka are under construction. Don't expect everything to work
+fine. If you want to help, please send patches to freitag@suse.de.
+
+Features:
+=========
+
+Kooka's main features are:
+
+Scanner Support using SANE:
+- Scanner support using SANE. Kooka _DOES_NOT_ support all features that SANE
+ and its backends offer. It takes a small subset of the available options.
+- Kooka offers a GUI to change the most important scanner options like resolution,
+ mode, threshold etc. These options are generated on the fly, depending on the
+ scanner capabilities.
+- Kooka offers a preview-function and the user can select the scan area interactively
+ or automatically.
+
+Image Storage:
+- Kooka provides an assistant to save your acquired images.
+- Filenames are generated automatically to support multiple scans.
+- Kooka manages the scanned images in a tree view where the user can delete and
+ export images.
+
+Image Manipulation:
+- Kooka provides basic image manipulation functions like rotation, mirroring.
+- Cut images to fit size.
+
+Image Viewing:
+- Scanned images can be viewed by clicking them in the tree view.
+- The viewer has a zoom function.
+
+OCR:
+- Kooka supports Joerg Schulenburg's gocr, an open source program
+ for optical character recognition (OCR). Kooka starts the OCR program
+ and displays its output. Best results with bw-images scanned with ~150 DPI
+- Support for the commercial OCR/ICR package KADMOS of the reRecognition
+ GmbH Kreuzlingen. Please read README.KADMOS for more information.
+
+Problems:
+=========
+
+* Kooka does not yet support all options SANE offers. That will
+improve in the future. However, I don't know if it makes sense to
+support all, even not very common options, some scanners offer. Lets
+see what is necessary and makes sense for the purpose of Kooka.
+
+* Kooka does not yet have a strategy for very large images :(. It uses
+the Qt QImage/QPixmap as is. On some displays, that causes problems.
+
+* Automatic document feeder (ADF) support is not yet working correctly.
+
+----------------------------------------------------------------------
+Klaas Freitag <freitag@suse.de>
+
+$Id$
+
diff --git a/kooka/README.KADMOS b/kooka/README.KADMOS
new file mode 100644
index 00000000..a6242155
--- /dev/null
+++ b/kooka/README.KADMOS
@@ -0,0 +1,73 @@
+Kooka and KADMOS integration
+============================
+
+This file describes how to make Kooka working with the KADMOS OCR/ICR
+engine.
+
+KAMDOS is commercial OCR/ICR software component of the company
+
+ reRecognition GmbH
+ Hafenstr. 50B
+ 8280 Kreuzlingen
+ Switzerland
+ Tel.: +41 71 6780000
+ Fax: +41 71 6780099
+ www.reRecognition.com
+
+and Kooka can be build using the linux version of the component in
+order to achive very good ocr results.
+
+Please contact re Recognition directly if you like to obtain or test
+KADMOS. Note that if you are linking against KADMOS, you loose the
+permission to use the GPL Qt version, so you need a commercial Qt
+version as well.
+
+Configuration
+-------------
+
+As Kooka does not require KADMOS, it is neccessary to configure
+Kooka to use the KADMOS library. This could be done by calling the
+configure script of Kooka's source distribution with following
+parameter:
+./configure --with-kadmos-dir=/where/kadmos.h/resides/
+
+The configure script tries to locate the file kadmos.h in the
+directory that was specified. The KADMOS library is expected in the
+same directory. Build the source after configuring with KADMOS. Kooka
+enables the code to work with KADMOS in the source and links the
+library.
+
+Installation
+------------
+
+KADMOS is linked statically and thus there is no need for special
+installation of the KADMOS library.
+
+Installation of the Classifier Files:
+
+KADMOS needs classifier files for the ocr process which come with
+the KADMOS developer's toolkit. The classifier files need to be installed
+in the KDE application data directory for Kooka in a subdirectory named
+classifiers. If your KDE installation goes to /opt/kde3/, this is for
+example /opt/kde3/share/apps/kooka/classifiers. Kooka picks the
+available classifiers up automatically.
+
+The classifiers are named in the following way:
+
+[fontkind][country/region].rec,
+where fontkinds are
+ttf -> machine print font
+hand -> handprint (isolated)
+norm -> OCR norm font
+
+
+For example the following classifier names are used:
+
+ttfus.rec US machineprint classifiers
+handus.rec US handwriting classifiers
+norm.rec Special OCR character sets, not localized
+
+
+----------------------------------------------------------------------
+Klaas Freitag <freitag@suse.de>
+$Id$
diff --git a/kooka/TODO b/kooka/TODO
new file mode 100644
index 00000000..ce5f3967
--- /dev/null
+++ b/kooka/TODO
@@ -0,0 +1,26 @@
+To be continued:
+
+Object ScanParams:
+- Resizing. On startup, the object comes up in a nearly fixed size, suiting the
+ mustek-backend very well ;) - thats the one I use at home. The cool solution
+ would be if the object 'knows' and tells what size (especially height) it wants
+ to have.
+
+ -> This should be done now. Please check, if it works for other than mustek
+ backends.
+
+Startup:
+
+- Changing the 'Dont ask me on startup'-decision. If the user checks the button
+ in the startup dialog never to ask which scan device to use, it is not possible
+ to revert this decision. Need a page in the Preferences dialog.
+
+OCR:
+
+- The ocr result window does not appear properly on very large result images
+ provided by gocr. Kooka should resize the result image to a reasonable size.
+
+Scan Packager:
+
+- The scan packager needs major rework. Enhancements like metadata in XML etc
+ should be included.
diff --git a/kooka/WARNING b/kooka/WARNING
new file mode 100644
index 00000000..bee996d5
--- /dev/null
+++ b/kooka/WARNING
@@ -0,0 +1,28 @@
+
+Scanning with Kooka and KScan
+=============================
+
+Kooka and KScan use the SANE library to attach to the scanner
+hardware. It cannot be avoided by any library that a program sends
+commands to the scanner which can damage it. Especially very cheap
+scanners sometimes do not have a hardware protection against driving
+the bed to far, which can cause terrible noise and damage :-(
+
+That is why you should be warned running Kooka or the KDE scanservice
+the first time. Even if there were no reportings that something bad
+happens to any scanner models using Kooka yet, but it can not be
+garanteed.
+
+Starting to scan the first time, be sure to sit next to your scanner
+having your hand on the power-off switch. Switch off immediately if
+you hear unexpected noises or if something strange happens.
+
+If you find errors, please dont ask the SANE-people without having
+made sure that your error is _really_ a SANE error. Most probably, you
+found an KScan or Kooka-Error, which should be reported at
+http://bugs.kde.org
+
+
+- Klaas Freitag <freitag@suse.de>
+
+$Id$
diff --git a/kooka/configure.in.in b/kooka/configure.in.in
new file mode 100644
index 00000000..df590f5d
--- /dev/null
+++ b/kooka/configure.in.in
@@ -0,0 +1,33 @@
+dnl AC_SEARCH_LIBS(pgm2asc,Pgm2asc)
+dnl AC_CHECK_LIB(Pgm2asc,pgm2asc)
+dnl should define HAVE_LIBPGM2ASC if available
+
+AC_ARG_WITH([kadmos],
+ [AC_HELP_STRING([--with-kadmos],
+ [Enable the kadmos OCR engine @<:@default=check@:>@])],
+ [], with_kadmos=check)
+
+AC_ARG_WITH([kadmos-dir],
+ AC_HELP_STRING([--with-kadmos-dir],
+ [sets the path to the kadmos engine @<:@default=/usr/local@:>@]),
+ [ac_kadmos_value=$withval], [ac_kadmos_value=/usr/local])
+
+KADMOS_INC=
+KADMOS_LIB=
+
+if test "x$with_kadmos" != xno; then
+ if test -r "$ac_kadmos_value/kadmos.h"; then
+ KADMOS_INC="-I$ac_kadmos_value"
+ KADMOS_LIB="$ac_kadmos_value/librep.a"
+ AC_DEFINE_UNQUOTED(HAVE_KADMOS, 1, [Defines if your system has the kadmos libraries])
+ else
+ AC_MSG_WARN([couldn't find kadmos engine header file under $ac_kadmos_value/kadmos.h])
+ fi
+
+ if test "x$with_kadmos" != xcheck && test -z "$KADMOS_LIB"; then
+ AC_MSG_ERROR([--with-kadmos was given, but test for kadmos failed])
+ fi
+fi
+
+AC_SUBST(KADMOS_LIB)
+AC_SUBST(KADMOS_INC)
diff --git a/kooka/dwmenuaction.cpp b/kooka/dwmenuaction.cpp
new file mode 100644
index 00000000..abe57f23
--- /dev/null
+++ b/kooka/dwmenuaction.cpp
@@ -0,0 +1,72 @@
+/***************************************************************************
+ dwmenuaction.cpp - dockwidget visibility switches to actions
+ -------------------
+ begin : 16.07.2002
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+
+ $Id$
+ Based on code from the from Joseph Wenninger (kate project)
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include "dwmenuaction.h"
+#include "dwmenuaction.moc"
+//-------------------------------------
+
+dwMenuAction::dwMenuAction( const QString& text, const KShortcut& cut,
+ KDockWidget *dw,QObject* parent,
+ KDockMainWindow *mw, const char* name )
+ :KToggleAction(text,cut,parent,name),m_dw(dw),m_mw(mw)
+{
+ connect(this,SIGNAL(toggled(bool)),this,SLOT(slotToggled(bool)));
+ connect(m_dw->dockManager(),SIGNAL(change()),this,SLOT(anDWChanged()));
+ connect(m_dw,SIGNAL(destroyed()),this,SLOT(slotWidgetDestroyed()));
+ setChecked(m_dw->mayBeHide());
+}
+
+
+dwMenuAction::~dwMenuAction(){;}
+
+void dwMenuAction::anDWChanged()
+{
+ if (isChecked() && m_dw->mayBeShow()) setChecked(false);
+ else if ((!isChecked()) && m_dw->mayBeHide()) setChecked(true);
+}
+
+
+void dwMenuAction::slotToggled(bool t)
+{
+
+ if ((!t) && m_dw->mayBeHide() ) m_dw->undock();
+ else
+ if ( t && m_dw->mayBeShow() ) m_mw->makeDockVisible(m_dw);
+
+}
+
+
+void dwMenuAction::slotWidgetDestroyed()
+{
+ unplugAll();
+ deleteLater();
+}
+
+
+/* END */
diff --git a/kooka/dwmenuaction.h b/kooka/dwmenuaction.h
new file mode 100644
index 00000000..9b1698ed
--- /dev/null
+++ b/kooka/dwmenuaction.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+ dwmenuaction.h - dockwidget visibility switches to actions
+ -------------------
+ begin : 16.07.2002
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+
+ $Id$
+ Based on code from the from Joseph Wenninger (kate project)
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef __DW_MENU_ACTION
+#define __DW_MENU_ACTION
+#include <kdockwidget.h>
+#include <qstring.h>
+#include <kaction.h>
+
+/**
+ * This class is just a helper class since the KDockWidget classes do not yet
+ * export KActions but only a QPopup-Pointer, which is quite useless in case
+ * you have a xml-file driven gui.
+ * This class provides Actions for show and hide parts of the GUI (dockwidgets)
+ * Maybe that classes can be removed as soon the DockWidget know Actions
+ */
+class dwMenuAction:public KToggleAction
+{
+ Q_OBJECT
+public:
+ dwMenuAction( const QString& text,
+ const KShortcut& cut = KShortcut(),
+ KDockWidget *dw=0, QObject* parent = 0,
+ KDockMainWindow * mw=0, const char* name = 0 );
+ virtual ~dwMenuAction();
+
+private:
+ KDockWidget *m_dw;
+ KDockMainWindow *m_mw;
+protected slots:
+ void slotToggled(bool);
+ void anDWChanged();
+ void slotWidgetDestroyed();
+};
+
+#endif
diff --git a/kooka/formathelp.h b/kooka/formathelp.h
new file mode 100644
index 00000000..7887a240
--- /dev/null
+++ b/kooka/formathelp.h
@@ -0,0 +1,43 @@
+/***************************************************************************
+ formathelp.h - description
+ -------------------
+ begin : Mon Dec 27 1999
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#define HELP_BMP i18n("The <big>bitmap-format</big> is a well known format,\n" \
+ "often used for 256 color images under " \
+ "MS Windows.\n Suitable for color and " \
+ "<bold>lineart-pictures</bold>\n" )
+#define HELP_PNM i18n("Portable Anymap\n" \
+ ""\
+ "" )
+#define HELP_JPG i18n("Jpeg is a high compression,\nquality " \
+ "losing format for color\npictures " \
+ "with many different colors." \
+ "" )
+
+#define HELP_EPS i18n("EPS is Encapsulated Postscript.\n " \
+ "Initially it's a printer definition\n " \
+ "language. Use this format if you\n" \
+ "want to print the image or use\n" \
+ "it with e.g. TeX" )
diff --git a/kooka/imageselectline.cpp b/kooka/imageselectline.cpp
new file mode 100644
index 00000000..f8677f1f
--- /dev/null
+++ b/kooka/imageselectline.cpp
@@ -0,0 +1,105 @@
+/***************************************************************************
+ imageselectline.cpp - select a background image.
+ -------------------
+ begin : Fri Dec 17 1999
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+
+ $Id$
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+#include <qhbox.h>
+#include <qvbox.h>
+#include <qbutton.h>
+#include <qpushbutton.h>
+#include <qlabel.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kurl.h>
+#include <kurlcombobox.h>
+#include <kfiledialog.h>
+#include <kiconloader.h>
+
+#include "imageselectline.h"
+
+/* ############################################################################## */
+
+/*
+ * This widget just combines a label, a combobox holding a path and a select button
+ * together in a row. The button opens a file selector box to pick a file.
+ */
+
+ImageSelectLine::ImageSelectLine( QWidget *parent, const QString& text )
+ : QHBox( parent )
+{
+ setSpacing( 5 );
+ (void) new QLabel( text, this );
+ m_urlCombo = new KURLComboBox( KURLComboBox::Files, this );
+ m_buttFileSelect = new QPushButton( this );
+ m_buttFileSelect->setPixmap( SmallIcon( "fileopen" ) );
+
+ m_urlCombo->setMaxItems(5);
+
+ connect( m_urlCombo, SIGNAL( urlActivated( const KURL& )),
+ this, SLOT( slUrlActivated( const KURL& )));
+
+ connect( m_buttFileSelect, SIGNAL( clicked() ),
+ this, SLOT( slSelectFile()));
+}
+
+void ImageSelectLine::slSelectFile()
+{
+ KURL newUrl;
+ newUrl = KFileDialog::getImageOpenURL();
+
+ QStringList l = m_urlCombo->urls();
+
+ if( ! newUrl.isEmpty())
+ {
+ l.prepend( newUrl.url() );
+ m_urlCombo->setURLs( l );
+ m_currUrl = newUrl;
+ }
+}
+
+void ImageSelectLine::slUrlActivated( const KURL& url )
+{
+ kdDebug(28000) << "Activating url: " << url.url() << endl;
+ m_currUrl = url;
+}
+
+KURL ImageSelectLine::selectedURL() const
+{
+ return m_currUrl;
+}
+
+void ImageSelectLine::setURL( const KURL& url )
+{
+ if( m_urlCombo ) m_urlCombo->setURL( url );
+ m_currUrl = url;
+}
+
+void ImageSelectLine::setURLs( const QStringList& list )
+{
+ if( m_urlCombo ) m_urlCombo->setURLs( list );
+}
+
+#include "imageselectline.moc"
diff --git a/kooka/imageselectline.h b/kooka/imageselectline.h
new file mode 100644
index 00000000..991cb3fd
--- /dev/null
+++ b/kooka/imageselectline.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+ imageselectline.h - select a background image.
+ -------------------
+ begin : ?
+ copyright : (C) 2002 by Klaas Freitag
+ email : freitag@suse.de
+
+ $Id$
+***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef __IMGSELECTLINE_H__
+#define __IMGSELECTLINE_H__
+
+#include <qhbox.h>
+
+/**
+ *
+ */
+
+class KURL;
+class KURLComboBox;
+class QPushButton;
+class QStringList;
+
+class ImageSelectLine:public QHBox
+{
+ Q_OBJECT
+public:
+ ImageSelectLine( QWidget *parent, const QString& text );
+
+ KURL selectedURL() const;
+ void setURL( const KURL& );
+ void setURLs( const QStringList& );
+
+protected slots:
+ void slSelectFile();
+ void slUrlActivated( const KURL& );
+
+private:
+
+ KURL m_currUrl;
+ KURLComboBox *m_urlCombo;
+ QPushButton *m_buttFileSelect;
+
+};
+
+
+#endif
diff --git a/kooka/img_saver.cpp b/kooka/img_saver.cpp
new file mode 100644
index 00000000..1d7cf1d7
--- /dev/null
+++ b/kooka/img_saver.cpp
@@ -0,0 +1,897 @@
+/***************************************************************************
+ img_saver.cpp - description
+ -------------------
+ begin : Mon Dec 27 1999
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+
+#include <kglobal.h>
+#include <kconfig.h>
+#include <kdialog.h>
+#include <kimageio.h>
+#include <kseparator.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <kio/jobclasses.h>
+#include <kio/file.h>
+#include <kio/job.h>
+#include <kio/netaccess.h>
+#include <ktempfile.h>
+#include <kinputdialog.h>
+
+#include <qdir.h>
+#include <qlayout.h>
+#include <qfileinfo.h>
+#include <qimage.h>
+#include <qmessagebox.h>
+#include <qvbox.h>
+#include <qbuttongroup.h>
+
+#include "resource.h"
+#include "img_saver.h"
+#include "previewer.h"
+#include "kookaimage.h"
+
+FormatDialog::FormatDialog( QWidget *parent, const QString&, const char *name )
+ :KDialogBase( parent, name, true,
+ /* Tabbed,*/ i18n( "Kooka Save Assistant" ),
+ Ok|Cancel, Ok )
+
+{
+ buildHelp();
+ // readConfig();
+ // QFrame *page = addPage( QString( "Save the image") );
+ QFrame *page = new QFrame( this );
+ page->setFrameStyle( QFrame::Box | QFrame::Sunken );
+ Q_CHECK_PTR( page );
+ setMainWidget( page );
+
+ QVBoxLayout *bigdad = new QVBoxLayout( page, marginHint(), spacingHint());
+ Q_CHECK_PTR(bigdad);
+
+ // some nice words
+ QLabel *l0 = new QLabel( page );
+ Q_CHECK_PTR(l0);
+ l0->setText( i18n( "<B>Save Assistant</B><P>Select an image format to save the scanned image." ));
+ bigdad->addWidget( l0 );
+
+ KSeparator* sep = new KSeparator( KSeparator::HLine, page);
+ bigdad->addWidget( sep );
+
+ // Layout-Boxes
+ // QHBoxLayout *hl1= new QHBoxLayout( ); // Caption
+ QHBoxLayout *lhBigMiddle = new QHBoxLayout( spacingHint() ); // Big middle
+ Q_CHECK_PTR(lhBigMiddle);
+ bigdad->addLayout( lhBigMiddle );
+ QVBoxLayout *lvFormatSel = new QVBoxLayout( spacingHint() ); // Selection List
+ Q_CHECK_PTR(lvFormatSel);
+ lhBigMiddle->addLayout( lvFormatSel );
+
+ // Insert Scrolled List for formats
+ QLabel *l1 = new QLabel( page );
+ Q_CHECK_PTR(l1);
+ l1->setText( i18n( "Available image formats:" ));
+
+ lb_format = new QListBox( page, "ListBoxFormats" );
+ Q_CHECK_PTR(lb_format);
+
+#ifdef USE_KIMAGEIO
+ QStringList fo = KImageIO::types();
+#else
+ QStringList fo = QImage::outputFormatList();
+#endif
+ kdDebug(28000) << "#### have " << fo.count() << " image types" << endl;
+ lb_format->insertStringList( fo );
+ connect( lb_format, SIGNAL( highlighted(const QString&)),
+ SLOT( showHelp(const QString&)));
+
+ // Insert label for helptext
+ l_help = new QLabel( page );
+ Q_CHECK_PTR(l_help);
+ l_help->setFrameStyle( QFrame::Panel|QFrame::Sunken );
+ l_help->setText( i18n("-No format selected-" ));
+ l_help->setAlignment( AlignVCenter | AlignHCenter );
+ l_help->setMinimumWidth(230);
+
+ // Insert Selbox for subformat
+ l2 = new QLabel( page );
+ Q_CHECK_PTR(l2);
+ l2->setText( i18n( "Select the image sub-format" ));
+ cb_subf = new QComboBox( page, "ComboSubFormat" );
+ Q_CHECK_PTR( cb_subf );
+
+ // Checkbox to store setting
+ cbDontAsk = new QCheckBox(i18n("Don't ask again for the save format if it is defined."),
+ page );
+ Q_CHECK_PTR( cbDontAsk );
+
+ QFrame *hl = new QFrame(page);
+ Q_CHECK_PTR( hl );
+ hl->setFrameStyle( QFrame::HLine|QFrame::Sunken );
+
+ // bigdad->addWidget( l_caption, 1 );
+ lvFormatSel->addWidget( l1, 1 );
+ lvFormatSel->addWidget( lb_format, 6 );
+ lvFormatSel->addWidget( l2, 1 );
+ lvFormatSel->addWidget( cb_subf, 1 );
+
+ lhBigMiddle->addWidget( l_help, 2 );
+ //bigdad->addStretch(1);
+ bigdad->addWidget( hl, 1 );
+ bigdad->addWidget( cbDontAsk , 2 );
+
+ bigdad->activate();
+
+}
+
+void FormatDialog::showHelp( const QString& item )
+{
+ QString helptxt = format_help[ item ];
+
+ if( !helptxt.isEmpty() ) {
+ // Set the hint
+ l_help->setText( helptxt );
+
+ // and check subformats
+ check_subformat( helptxt );
+ } else {
+ l_help->setText( i18n("-no hint available-" ));
+ }
+}
+
+void FormatDialog::check_subformat( const QString & format )
+{
+ // not yet implemented
+ kdDebug(28000) << "This is format in check_subformat: " << format << endl;
+ cb_subf->setEnabled( false );
+ // l2 = Label "select subformat" ->bad name :-|
+ l2->setEnabled( false );
+}
+
+void FormatDialog::setSelectedFormat( QString fo )
+{
+ QListBoxItem *item = lb_format->findItem( fo );
+
+ if( item )
+ {
+ // Select it.
+ lb_format->setSelected( lb_format->index(item), true );
+ }
+}
+
+
+QString FormatDialog::getFormat( ) const
+{
+ int item = lb_format->currentItem();
+
+ if( item > -1 )
+ {
+ const QString f = lb_format->text( item );
+ return( f );
+ }
+ return( "BMP" );
+}
+
+
+QCString FormatDialog::getSubFormat( ) const
+{
+ // Not yet...
+ return( "" );
+}
+
+#include "formathelp.h"
+void FormatDialog::buildHelp( void )
+{
+ format_help.insert( QString::fromLatin1("BMP"), HELP_BMP );
+ format_help.insert( QString::fromLatin1("PNM"), HELP_PNM );
+ format_help.insert( QString::fromLatin1("JPEG"), HELP_JPG );
+ format_help.insert( QString::fromLatin1("JPG"), HELP_JPG );
+ format_help.insert( QString::fromLatin1("EPS"), HELP_EPS );
+}
+
+
+/* ********************************************************************** */
+
+ImgSaver::ImgSaver( QWidget *parent, const KURL dir_name )
+ : QObject( parent )
+{
+
+ if( dir_name.isEmpty() || dir_name.protocol() != "file" )
+ {
+ kdDebug(28000) << "ImageServer initialised with wrong dir " << dir_name.url() << endl;
+ directory = Previewer::galleryRoot();
+ }
+ else
+ {
+ /* A path was given */
+ if( dir_name.protocol() != "file" )
+ {
+ kdDebug(28000) << "ImgSaver: Can only save local image, sorry !" << endl;
+ }
+ else
+ {
+ directory = dir_name.directory(true, false);
+ }
+ }
+
+ kdDebug(28000) << "ImageSaver uses dir <" << directory << endl;
+ createDir( directory );
+ readConfig();
+
+ last_file = "";
+ last_format ="";
+
+}
+
+
+ImgSaver::ImgSaver( QWidget *parent )
+ :QObject( parent )
+{
+ directory = Previewer::galleryRoot();
+ createDir( directory );
+
+ readConfig();
+
+ last_file = "";
+ last_format ="";
+
+}
+
+
+/* Needs a full qualified directory name */
+void ImgSaver::createDir( const QString& dir )
+{
+ KURL url( dir );
+
+ if( ! KIO::NetAccess::exists(url, false, 0) )
+ {
+ kdDebug(28000) << "Wrn: Directory <" << dir << "> does not exist -> try to create !" << endl;
+ // if( mkdir( QFile::encodeName( dir ), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH ) != 0 )
+ if( KIO::mkdir( KURL(dir)))
+ {
+ KMessageBox::sorry(0, i18n("The folder\n%1\n does not exist and could not be created;\n"
+ "please check the permissions.").arg(dir));
+ }
+ }
+#if 0
+ if( ! fi.isWritable() )
+ {
+ KMessageBox::sorry(0, i18n("The directory\n%1\n is not writeable;\nplease check the permissions.")
+ .arg(dir));
+ }
+#endif
+}
+
+/**
+ * This function asks the user for a filename or creates
+ * one by itself, depending on the settings
+ **/
+ImgSaveStat ImgSaver::saveImage( QImage *image )
+{
+ ImgSaveStat stat;
+ picType imgType;
+
+ if( !image ) return( ISS_ERR_PARAM );
+
+ /* Find out what kind of image it is */
+ if( image->depth() > 8 )
+ {
+ imgType = PT_HICOLOR_IMAGE;
+ }
+ else
+ {
+ if( image->depth() == 1 || image->numColors() == 2 )
+ {
+ kdDebug(28000) << "This is black And White!" << endl;
+ imgType = PT_BW_IMAGE;
+ }
+ else
+ {
+ imgType = PT_COLOR_IMAGE;
+ if( image->allGray() )
+ {
+ imgType = PT_GRAY_IMAGE;
+ }
+ }
+ }
+
+
+ QString format = findFormat( imgType );
+ QString subformat = findSubFormat( format );
+ // Call save-Function with this params
+
+ if( format.isEmpty() )
+ {
+ kdDebug(28000) << "Save canceled by user -> no save !" << endl;
+ return( ISS_SAVE_CANCELED );
+ }
+
+ kdDebug(28000) << "saveImage: Directory is " << directory << endl;
+ QString filename = createFilename( format );
+
+ KConfig *konf = KGlobal::config ();
+ konf->setGroup( OP_FILE_GROUP );
+
+ if( konf->readBoolEntry( OP_ASK_FILENAME, false ) )
+ {
+ bool ok;
+ QString text = KInputDialog::getText( i18n( "Filename" ), i18n("Enter filename:"),
+ filename, &ok );
+
+ if(ok)
+ {
+ filename = text;
+ }
+ }
+
+ QString fi = directory + "/" + filename;
+
+ if( extension(fi).isEmpty() )
+ {
+ if( ! fi.endsWith( "." ) )
+ {
+ fi+= ".";
+ }
+ fi+=format.lower();
+ }
+
+
+ kdDebug(28000) << "saveImage: saving file <" << fi << ">" << endl;
+ stat = save( image, fi, format, subformat );
+
+ return( stat );
+
+}
+
+/**
+ * This member creates a filename for the image to save.
+ * This is done by numbering all existing files and adding
+ * one
+ **/
+QString ImgSaver::createFilename( QString format )
+{
+ if( format.isNull() || format.isEmpty() ) return( 0 );
+
+ QString s = "kscan_*." + format.lower();
+ QDir files( directory, s );
+ long c = 1;
+
+ QString num;
+ num.setNum(c);
+ QString fname = "kscan_" + num.rightJustify(4, '0') + "." + format.lower();
+
+ while( files.exists( fname ) ) {
+ num.setNum(++c);
+ fname = "kscan_" + num.rightJustify(4, '0') + "." + format.lower();
+ }
+
+ return( fname );
+}
+
+/**
+ * This function gets a filename from the parent. The filename must not be relative.
+ **/
+ImgSaveStat ImgSaver::saveImage( QImage *image, const KURL& filename, const QString& imgFormat )
+{
+ QString format = imgFormat;
+
+ /* Check if the filename is local */
+ if( !filename.isLocalFile())
+ {
+ kdDebug(29000) << "ImgSaver: Can only save local image, sorry !" << endl;
+ return( ISS_ERR_PROTOCOL );
+ }
+
+ QString localFilename;
+ localFilename = filename.directory( false, true) + filename.fileName();
+
+ kdDebug(28000) << "saveImage: Saving "<< localFilename << " in format " << format << endl;
+ if( format.isEmpty() )
+ format = "BMP";
+
+ return( save( image, localFilename, format, "" ) );
+}
+
+
+/*
+ * findFormat does all the stuff with the dialog.
+ */
+QString ImgSaver::findFormat( picType type )
+{
+ QString format;
+ KConfig *konf = KGlobal::config ();
+ konf->setGroup( OP_FILE_GROUP );
+
+ if( type == PT_THUMBNAIL )
+ {
+ return( "BMP" );
+ }
+
+ // real images
+ switch( type )
+ {
+ case PT_THUMBNAIL:
+ format = konf->readEntry( OP_FORMAT_THUMBNAIL, "BMP" );
+ kdDebug( 28000) << "Format for Thumbnails: " << format << endl;
+ break;
+ case PT_PREVIEW:
+ format = konf->readEntry( OP_PREVIEW_FORMAT, "BMP" );
+ kdDebug( 28000) << "Format for Preview: " << format << endl;
+ break;
+ case PT_COLOR_IMAGE:
+ format = konf->readEntry( OP_FORMAT_COLOR, "nothing" );
+ kdDebug( 28000 ) << "Format for Color: " << format << endl;
+ break;
+ case PT_GRAY_IMAGE:
+ format = konf->readEntry( OP_FORMAT_GRAY, "nothing" );
+ kdDebug( 28000 ) << "Format for Gray: " << format << endl;
+ break;
+ case PT_BW_IMAGE:
+ format = konf->readEntry( OP_FORMAT_BW, "nothing" );
+ kdDebug( 28000 ) << "Format for BlackAndWhite: " << format << endl;
+ break;
+ case PT_HICOLOR_IMAGE:
+ format = konf->readEntry( OP_FORMAT_HICOLOR, "nothing" );
+ kdDebug( 28000 ) << "Format for HiColorImage: " << format << endl;
+ break;
+ default:
+ format = "nothing";
+ kdDebug( 28000 ) << "ERR: Could not find image type !" << endl;
+
+ break;
+ }
+
+ if( type != PT_PREVIEW ) /* Use always bmp-Default for preview scans */
+ {
+ if( format == "nothing" || ask_for_format )
+ {
+ format = startFormatDialog( type );
+ }
+ }
+ return( format );
+
+}
+
+QString ImgSaver::picTypeAsString( picType type ) const
+{
+ QString res;
+
+ switch( type )
+ {
+ case PT_COLOR_IMAGE:
+ res = i18n( "palleted color image (16 or 24 bit depth)" );
+ break;
+ case PT_GRAY_IMAGE:
+ res = i18n( "palleted gray scale image (16 bit depth)" );
+ break;
+ case PT_BW_IMAGE:
+ res = i18n( "lineart image (black and white, 1 bit depth)" );
+ break;
+ case PT_HICOLOR_IMAGE:
+ res = i18n( "high (or true-) color image, not palleted" );
+ break;
+ default:
+ res = i18n( "Unknown image type" );
+ break;
+ }
+ return( res );
+}
+
+
+QString ImgSaver::startFormatDialog( picType type)
+{
+
+ FormatDialog fd( 0, picTypeAsString( type ), "FormatDialog" );
+
+ // set default values
+ if( type != PT_PREVIEW )
+ {
+ QString defFormat = getFormatForType( type );
+ fd.setSelectedFormat( defFormat );
+ }
+
+ QString format;
+ if( fd.exec() )
+ {
+ format = fd.getFormat();
+ kdDebug(28000) << "Storing to format <" << format << ">" << endl;
+ bool ask = fd.askForFormat();
+ kdDebug(28000)<< "Store askFor is " << ask << endl;
+ storeFormatForType( type, format, ask );
+ subformat = fd.getSubFormat();
+ }
+ return( format );
+}
+
+
+/*
+ * This method returns true if the image format given in format is remembered
+ * for that image type.
+ */
+bool ImgSaver::isRememberedFormat( picType type, QString format ) const
+{
+ if( getFormatForType( type ) == format )
+ {
+ return( true );
+ }
+ else
+ {
+ return( false );
+ }
+
+}
+
+
+
+
+QString ImgSaver::getFormatForType( picType type ) const
+{
+ KConfig *konf = KGlobal::config ();
+ Q_CHECK_PTR( konf );
+ konf->setGroup( OP_FILE_GROUP );
+
+ QString f;
+
+ switch( type )
+ {
+ case PT_COLOR_IMAGE:
+ f = konf->readEntry( OP_FORMAT_COLOR, "BMP" );
+ break;
+ case PT_GRAY_IMAGE:
+ f = konf->readEntry( OP_FORMAT_GRAY, "BMP" );
+ break;
+ case PT_BW_IMAGE:
+ f = konf->readEntry( OP_FORMAT_BW, "BMP" );
+ break;
+ case PT_HICOLOR_IMAGE:
+ f = konf->readEntry( OP_FORMAT_HICOLOR, "BMP" );
+ break;
+ default:
+ f = "BMP";
+ break;
+ }
+ return( f );
+}
+
+
+void ImgSaver::storeFormatForType( picType type, QString format, bool ask )
+{
+ KConfig *konf = KGlobal::config ();
+ Q_CHECK_PTR( konf );
+ konf->setGroup( OP_FILE_GROUP );
+
+ konf->writeEntry( OP_FILE_ASK_FORMAT, ask );
+ ask_for_format = ask;
+
+ switch( type )
+ {
+ case PT_COLOR_IMAGE:
+ konf->writeEntry( OP_FORMAT_COLOR, format );
+ break;
+ case PT_GRAY_IMAGE:
+ konf->writeEntry( OP_FORMAT_GRAY, format );
+ break;
+ case PT_BW_IMAGE:
+ konf->writeEntry( OP_FORMAT_BW, format );
+ break;
+ case PT_HICOLOR_IMAGE:
+ konf->writeEntry( OP_FORMAT_HICOLOR, format );
+ break;
+ default:
+ kdDebug(28000) << "Wrong Type - cant store format setting" << endl;
+ break;
+ }
+ konf->sync();
+}
+
+
+QString ImgSaver::findSubFormat( QString format )
+{
+ kdDebug(28000) << "Searching Subformat for " << format << endl;
+ return( subformat );
+
+}
+
+/**
+ private save() does the work to save the image.
+ the filename must be complete and local.
+**/
+ImgSaveStat ImgSaver::save( QImage *image, const QString &filename,
+ const QString &format,
+ const QString &subformat )
+{
+
+ bool result = false;
+ kdDebug(28000) << "in ImgSaver::save: saving " << filename << endl;
+ if( ! format || !image )
+ {
+ kdDebug(28000) << "ImgSaver ERROR: Wrong parameter Format <" << format << "> or image" << endl;
+ return( ISS_ERR_PARAM );
+ }
+
+ if( image )
+ {
+ // remember the last processed file - only the filename - no path
+ QFileInfo fi( filename );
+ QString dirPath = fi.dirPath();
+ QDir dir = QDir( dirPath );
+
+ if( ! dir.exists() )
+ {
+ /* The dir to save in always should exist, except in the first preview save */
+ kdDebug(28000) << "Creating dir " << dirPath << endl;
+ if( !dir.mkdir( dirPath ) )
+ {
+ kdDebug(28000) << "ERR: Could not create directory" << endl;
+ }
+ }
+
+ if( fi.exists() && !fi.isWritable() )
+ {
+ kdDebug(28000) << "Cant write to file <" << filename << ">, cant save !" << endl;
+ result = false;
+ return( ISS_ERR_PERM );
+ }
+
+ /* Check the format, is it writable ? */
+#ifdef USE_KIMAGEIO
+ if( ! KImageIO::canWrite( format ) )
+ {
+ kdDebug(28000) << "Cant write format <" << format << ">" << endl;
+ result = false;
+ return( ISS_ERR_FORMAT_NO_WRITE );
+ }
+#endif
+ kdDebug(28000) << "ImgSaver: saving image to <" << filename << "> as <" << format << "/" << subformat <<">" << endl;
+
+ result = image->save( filename, format.latin1() );
+
+
+ last_file = fi.absFilePath();
+ last_format = format.latin1();
+ }
+
+ if( result )
+ return( ISS_OK );
+ else {
+ last_file = "";
+ last_format = "";
+ return( ISS_ERR_UNKNOWN );
+ }
+
+}
+
+
+void ImgSaver::readConfig( void )
+{
+
+ KConfig *konf = KGlobal::config ();
+ Q_CHECK_PTR( konf );
+ konf->setGroup( OP_FILE_GROUP );
+ ask_for_format = konf->readBoolEntry( OP_FILE_ASK_FORMAT, true );
+
+ QDir home = QDir::home();
+}
+
+
+
+
+
+QString ImgSaver::errorString( ImgSaveStat stat )
+{
+ QString re;
+
+ switch( stat ) {
+ case ISS_OK: re = i18n( " image save OK " ); break;
+ case ISS_ERR_PERM: re = i18n( " permission error " ); break;
+ case ISS_ERR_FILENAME: re = i18n( " bad filename " ); break;
+ case ISS_ERR_NO_SPACE: re = i18n( " no space on device " ); break;
+ case ISS_ERR_FORMAT_NO_WRITE: re = i18n( " could not write image format " ); break;
+ case ISS_ERR_PROTOCOL: re = i18n( " can not write file using that protocol "); break;
+ case ISS_SAVE_CANCELED: re = i18n( " user canceled saving " ); break;
+ case ISS_ERR_UNKNOWN: re = i18n( " unknown error " ); break;
+ case ISS_ERR_PARAM: re = i18n( " parameter wrong " ); break;
+
+ default: re = "";
+ }
+ return( re );
+
+}
+
+QString ImgSaver::extension( const KURL& url )
+{
+ QString extension = url.fileName();
+
+ int dotPos = extension.findRev( '.' );
+ if( dotPos > 0 )
+ {
+ int len = extension.length();
+ extension = extension.right( len - dotPos -1 );
+ }
+ else
+ {
+ /* No extension was supplied */
+ extension = QString();
+ }
+ return extension;
+}
+
+
+bool ImgSaver::renameImage( const KURL& fromUrl, KURL& toUrl, bool askExt, QWidget *overWidget )
+{
+ /* Check if the provided filename has a extension */
+ QString extTo = extension( toUrl );
+ QString extFrom = extension( fromUrl );
+ KURL targetUrl( toUrl );
+
+ if( extTo.isEmpty() && !extFrom.isEmpty() )
+ {
+ /* Ask if the extension should be added */
+ int result = KMessageBox::Yes;
+ QString fName = toUrl.fileName();
+ if( ! fName.endsWith( "." ) )
+ {
+ fName += ".";
+ }
+ fName += extFrom;
+
+ if( askExt )
+ {
+
+ QString s;
+ s = i18n("The filename you supplied has no file extension.\nShould the correct one be added automatically? ");
+ s += i18n( "That would result in the new filename: %1" ).arg( fName);
+
+ result = KMessageBox::questionYesNo(overWidget, s, i18n( "Extension Missing"),
+ i18n("Add Extension"), i18n("Do Not Add"),
+ "AutoAddExtensions" );
+ }
+
+ if( result == KMessageBox::Yes )
+ {
+ targetUrl.setFileName( fName );
+ kdDebug(28000) << "Rename file to " << targetUrl.prettyURL() << endl;
+ }
+ }
+ else if( !extFrom.isEmpty() && extFrom != extTo )
+ {
+ if( ! ((extFrom.lower() == "jpeg" && extTo.lower() == "jpg") ||
+ (extFrom.lower() == "jpg" && extTo.lower() == "jpeg" )))
+ {
+ /* extensions differ -> TODO */
+ KMessageBox::error( overWidget,
+ i18n("Format changes of images are currently not supported."),
+ i18n("Wrong Extension Found" ));
+ return(false);
+ }
+ }
+
+ bool success = false;
+
+ if( KIO::NetAccess::exists( targetUrl, false,0 ) )
+ {
+ kdDebug(28000)<< "Target already exists - can not copy" << endl;
+ }
+ else
+ {
+ if( KIO::file_move(fromUrl, targetUrl) )
+ {
+ success = true;
+ }
+ }
+ return( success );
+}
+
+
+QString ImgSaver::tempSaveImage( KookaImage *img, const QString& format, int colors )
+{
+
+ KTempFile *tmpFile = new KTempFile( QString(), "."+format.lower());
+ tmpFile->setAutoDelete( false );
+ tmpFile->close();
+
+ KookaImage tmpImg;
+
+ if( colors != -1 && img->numColors() != colors )
+ {
+ // Need to convert image
+ if( colors == 1 || colors == 8 || colors == 24 || colors == 32 )
+ {
+ tmpImg = img->convertDepth( colors );
+ img = &tmpImg;
+ }
+ else
+ {
+ kdDebug(29000) << "ERROR: Wrong color depth requested: " << colors << endl;
+ img = 0;
+ }
+ }
+
+ QString name;
+ if( img )
+ {
+ name = tmpFile->name();
+
+ if( ! img->save( name, format.latin1() ) ) name = QString();
+ }
+ delete tmpFile;
+ return name;
+}
+
+bool ImgSaver::copyImage( const KURL& fromUrl, const KURL& toUrl, QWidget *overWidget )
+{
+
+ /* Check if the provided filename has a extension */
+ QString extTo = extension( toUrl );
+ QString extFrom = extension( fromUrl );
+ KURL targetUrl( toUrl );
+
+ if( extTo.isEmpty() && !extFrom.isEmpty())
+ {
+ /* Ask if the extension should be added */
+ int result = KMessageBox::Yes;
+ QString fName = toUrl.fileName();
+ if( ! fName.endsWith( "." ))
+ fName += ".";
+ fName += extFrom;
+
+ QString s;
+ s = i18n("The filename you supplied has no file extension.\nShould the correct one be added automatically? ");
+ s += i18n( "That would result in the new filename: %1" ).arg( fName);
+
+ result = KMessageBox::questionYesNo(overWidget, s, i18n( "Extension Missing"),
+ i18n("Add Extension"), i18n("Do Not Add"),
+ "AutoAddExtensions" );
+
+ if( result == KMessageBox::Yes )
+ {
+ targetUrl.setFileName( fName );
+ }
+ }
+ else if( !extFrom.isEmpty() && extFrom != extTo )
+ {
+ /* extensions differ -> TODO */
+ if( ! ((extFrom.lower() == "jpeg" && extTo.lower() == "jpg") ||
+ (extFrom.lower() == "jpg" && extTo.lower() == "jpeg" )))
+ {
+ KMessageBox::error( overWidget, i18n("Format changes of images are currently not supported."),
+ i18n("Wrong Extension Found" ));
+ return(false);
+ }
+ }
+
+ KIO::Job *copyjob = KIO::copy( fromUrl, targetUrl, false );
+
+ return( copyjob ? true : false );
+}
+
+
+/* extension needs to be added */
+
+#include "img_saver.moc"
diff --git a/kooka/img_saver.h b/kooka/img_saver.h
new file mode 100644
index 00000000..f9a29898
--- /dev/null
+++ b/kooka/img_saver.h
@@ -0,0 +1,208 @@
+/***************************************************************************
+ img_saver.h - description
+ -------------------
+ begin : Mon Dec 27 1999
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef __IMG_SAVER_H__
+#define __IMG_SAVER_H__
+#include <qobject.h>
+#include <qwidget.h>
+#include <qlabel.h>
+#include <qmemarray.h>
+#include <qstring.h>
+#include <qimage.h>
+#include <stdlib.h>
+#include <qdialog.h>
+#include <qpushbutton.h>
+#include <qcombobox.h>
+#include <qcheckbox.h>
+#include <qlistbox.h>
+#include <qmap.h>
+#include <kdialogbase.h>
+#include <kurl.h>
+
+
+#define OP_FILE_ASK_FORMAT "AskForSaveFormat"
+#define OP_ASK_FILENAME "AskForFilename"
+#define OP_FORMAT_HICOLOR "HiColorSaveFormat"
+#define OP_FORMAT_COLOR "ColorSaveFormat"
+#define OP_FORMAT_GRAY "GraySaveFormat"
+#define OP_FORMAT_BW "BWSaveFormat"
+#define OP_FORMAT_THUMBNAIL "ThumbnailFormat"
+#define OP_PREVIEW_GROUP "ScanPreview"
+#define OP_PREVIEW_FILE "PreviewFile"
+#define OP_PREVIEW_FORMAT "PreviewFormat"
+#define OP_FILE_GROUP "Files"
+
+
+/**
+ * enum ImgSaveStat:
+ * Errorflags for the save. These enums are returned by the
+ * all image save operations and the calling object my display
+ * a human readable Error-Message on this information
+ **/
+typedef enum {
+ ISS_OK, /* Image save OK */
+ ISS_ERR_PERM, /* permission Error */
+ ISS_ERR_FILENAME, /* bad filename */
+ ISS_ERR_NO_SPACE, /* no space on device */
+ ISS_ERR_FORMAT_NO_WRITE, /* Image format can not be written */
+ ISS_ERR_UNKNOWN,
+ ISS_ERR_PARAM, /* Parameter wrong */
+ ISS_ERR_PROTOCOL,
+ ISS_SAVE_CANCELED
+
+} ImgSaveStat;
+
+/**
+ * enum picType:
+ * Specifies the type of the image to save. This is important for
+ * getting the format.
+ **/
+typedef enum {
+ PT_PREVIEW,
+ PT_THUMBNAIL,
+ PT_HICOLOR_IMAGE,
+ PT_COLOR_IMAGE,
+ PT_GRAY_IMAGE,
+ PT_BW_IMAGE,
+ PT_FINISHED
+} picType;
+
+
+class KookaImage;
+/**
+ * Class FormatDialog:
+ * Asks the user for the image-Format and gives help for
+ * selecting it.
+ **/
+
+class FormatDialog:public KDialogBase
+{
+ Q_OBJECT
+public:
+ FormatDialog( QWidget *parent, const QString&, const char * );
+
+
+ QString getFormat( ) const;
+ QCString getSubFormat( ) const;
+ QString errorString( ImgSaveStat stat );
+
+ bool askForFormat( ) const
+ { return( ! cbDontAsk->isChecked()); }
+
+public slots:
+ void setSelectedFormat( QString );
+
+
+protected slots:
+ void showHelp( const QString& item );
+
+private:
+
+ void check_subformat( const QString & format );
+ void buildHelp( void );
+ void readConfig( void );
+
+ QMap<QString, QString> format_help;
+ QComboBox *cb_subf;
+ QListBox *lb_format;
+ QLabel *l_help;
+ QLabel *l2;
+ QCheckBox *cbRemember;
+ QCheckBox *cbDontAsk;
+};
+
+/**
+ * Class ImgSaver:
+ * The main class of this module. It manages all saving of images
+ * in kooka
+ * It asks the user for the img-format if desired, creates thumbnails
+ * and cares for database entries (later ;)
+ **/
+
+class ImgSaver:public QObject {
+ Q_OBJECT
+public:
+ /**
+ * constructor of the image-saver object.
+ * name is the name of a subdirectory of the save directory,
+ * which can be given in dir. If no dir is given, an
+ * dir ~/.ksane is created.
+ * @param dir Name of the save root directory
+ * @param name Name of a subdirectory in the saveroot.
+ **/
+ ImgSaver( QWidget *parent, const KURL );
+ ImgSaver( QWidget *parent );
+
+ QString errorString( ImgSaveStat );
+ /**
+ * returns the name of the last file that was saved by ImgSaver.
+ */
+ QString lastFilename() const { return( last_file ); }
+ KURL lastFileUrl() const { return( KURL(last_file )); }
+ /**
+ * returns the image format of the last saved image.
+ */
+ QCString lastSaveFormat( void ) const { return( last_format ); }
+
+ QString getFormatForType( picType ) const;
+ void storeFormatForType( picType, QString, bool );
+ bool isRememberedFormat( picType type, QString format ) const;
+
+ /* static function that exports a file */
+ static bool copyImage( const KURL& fromUrl, const KURL& toUrl, QWidget *overWidget=0 );
+ static bool renameImage( const KURL& fromUrl, KURL& toUrl, bool askExt=false, QWidget *overWidget=0 );
+ static QString tempSaveImage( KookaImage *img, const QString& format, int colors = -1 );
+
+ /* static function that returns the extension of an url */
+ static QString extension( const KURL& );
+
+public slots:
+ ImgSaveStat saveImage( QImage *image );
+ ImgSaveStat saveImage( QImage *image, const KURL& filename, const QString& imgFormat );
+
+private:
+ QString picTypeAsString( picType type ) const;
+ QString findFormat( picType type );
+ QString findSubFormat( QString format );
+ void createDir( const QString& );
+
+ ImgSaveStat save( QImage *image, const QString &filename, const QString &format,
+ const QString &subformat );
+ QString createFilename( QString format );
+ void readConfig( void );
+ QString startFormatDialog( picType );
+
+ // QStrList all_formats;
+ QString directory; // dir where the image should be saved
+ QString last_file;
+ QCString subformat;
+ QCString last_format;
+ bool ask_for_format;
+
+ // QDict<QString> formats;
+};
+
+#endif
diff --git a/kooka/imgnamecombo.cpp b/kooka/imgnamecombo.cpp
new file mode 100644
index 00000000..77b59a0d
--- /dev/null
+++ b/kooka/imgnamecombo.cpp
@@ -0,0 +1,93 @@
+/***************************************************************************
+ imgnamecombo.cpp - combobox for image names
+ -------------------
+ begin : Tue Nov 13 2001
+ copyright : (C) 2001 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qlistview.h>
+
+#include <kcombobox.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kfiletreebranch.h>
+
+#include "imgnamecombo.h"
+#include "img_saver.h"
+
+ImageNameCombo::ImageNameCombo( QWidget *parent )
+ : KComboBox( parent )
+{
+ setInsertionPolicy( QComboBox::AtTop );
+}
+
+ImageNameCombo::~ImageNameCombo()
+{
+
+}
+
+void ImageNameCombo::slotPathRemove( KFileTreeBranch *branch, const QString& relPath )
+{
+ QString path = branch->name() + QString::fromLatin1(" - ") + relPath;
+
+ kdDebug(28000) << "ImageNameCombo: Removing " << path << endl;
+ QString select = currentText();
+
+ if( items.contains( path ))
+ {
+ kdDebug(28000) << "ImageNameCombo: Item exists-> deleting" << endl;
+ items.remove( path );
+ }
+
+ /* */
+ rewriteList( branch, select );
+}
+
+void ImageNameCombo::rewriteList( KFileTreeBranch *branch, const QString& selText )
+{
+ clear();
+ for ( QStringList::Iterator it = items.begin(); it != items.end(); ++it )
+ {
+ insertItem( branch->pixmap(), *it );
+ }
+
+ int index = items.findIndex( selText );
+ setCurrentItem( index );
+}
+
+void ImageNameCombo::slotGalleryPathChanged( KFileTreeBranch* branch, const QString& relativPath )
+{
+ QString newPath;
+
+ newPath = branch->name() + QString::fromLatin1(" - ") + relativPath;
+
+ kdDebug( 28000) << "Inserting " << newPath << " to combobox" << endl;
+
+ setCurrentItem( newPath, true /* insert if missing */ );
+}
+
+/* The End */
+#include "imgnamecombo.moc"
diff --git a/kooka/imgnamecombo.h b/kooka/imgnamecombo.h
new file mode 100644
index 00000000..a577929e
--- /dev/null
+++ b/kooka/imgnamecombo.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+ imgnamecombo.h - combobox for image names
+ -------------------
+ begin : Tue Nov 13 2001
+ copyright : (C) 2001 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+
+#ifndef IMGNAMECOMBO_H
+#define IMGNAMECOMBO_H
+
+
+#include <kcombobox.h>
+
+/**
+ *@author Klaas Freitag
+*/
+
+class QListViewItem;
+class KFileBranch;
+
+class ImageNameCombo: public KComboBox
+{
+ Q_OBJECT
+public:
+ ImageNameCombo( QWidget* );
+ ~ImageNameCombo();
+
+public slots:
+
+ void slotGalleryPathChanged( KFileTreeBranch* branch, const QString& relativPath );
+ void slotPathRemove( KFileTreeBranch *branch, const QString& relPath );
+private:
+ void rewriteList( KFileTreeBranch *, const QString& selText );
+ QStringList items;
+};
+
+#endif
diff --git a/kooka/imgprintdialog.cpp b/kooka/imgprintdialog.cpp
new file mode 100644
index 00000000..f9aa3930
--- /dev/null
+++ b/kooka/imgprintdialog.cpp
@@ -0,0 +1,302 @@
+/***************************************************************************
+ imgprintdialog.h - Kooka's Image Printing
+ -------------------
+ begin : May 2003
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+#include "imgprintdialog.h"
+
+#include <klocale.h>
+#include <knuminput.h>
+#include <kdialog.h>
+
+#include <qstring.h>
+#include <qmap.h>
+#include <qlayout.h>
+#include <qvbuttongroup.h>
+#include <qcheckbox.h>
+#include <qradiobutton.h>
+#include "kookaimage.h"
+#include <qvgroupbox.h>
+#include <qpaintdevicemetrics.h>
+#include <qlabel.h>
+#include <qtooltip.h>
+#include <kdebug.h>
+
+#define ID_SCREEN 0
+#define ID_ORIG 1
+#define ID_CUSTOM 2
+#define ID_FIT_PAGE 3
+
+ImgPrintDialog::ImgPrintDialog( KookaImage *img, QWidget *parent, const char* name )
+ : KPrintDialogPage( parent, name ),
+ m_image(img),
+ m_ignoreSignal(false)
+{
+ setTitle(i18n("Image Printing"));
+ QVBoxLayout *layout = new QVBoxLayout( this );
+ // layout->setMargin( KDialog::marginHint() );
+ // layout->setSpacing( KDialog::spacingHint() );
+
+ m_scaleRadios = new QButtonGroup( 2, Qt::Vertical, i18n("Image Print Size"), this );
+ m_scaleRadios->setRadioButtonExclusive(true);
+ connect( m_scaleRadios, SIGNAL(clicked(int)), SLOT(slScaleChanged(int)));
+
+ m_rbScreen = new QRadioButton( i18n("Scale to same size as on screen"),
+ m_scaleRadios );
+ QToolTip::add( m_rbScreen, i18n("Screen scaling. That prints according to the screen resolution."));
+
+ m_scaleRadios->insert( m_rbScreen, ID_SCREEN );
+
+ m_rbOrigSize = new QRadioButton( i18n("Original size (calculate from scan resolution)"),
+ m_scaleRadios );
+ QToolTip::add( m_rbOrigSize,
+ i18n("Calculates the print size from the scan resolution. Enter the scan resolution in the dialog field below." ));
+ m_scaleRadios->insert( m_rbOrigSize, ID_ORIG );
+
+
+ m_rbScale = new QRadioButton( i18n("Scale image to custom dimension"), m_scaleRadios );
+ QToolTip::add( m_rbScale,
+ i18n("Set the print size yourself in the dialog below. The image is centered on the paper."));
+
+ m_scaleRadios->insert( m_rbScale, ID_CUSTOM );
+
+ m_rbFitPage = new QRadioButton( i18n("Scale image to fit to page"), m_scaleRadios );
+ QToolTip::add( m_rbFitPage, i18n("Printout uses maximum space on the selected pager. Aspect ratio is maintained."));
+ m_scaleRadios->insert( m_rbFitPage, ID_FIT_PAGE );
+
+ layout->addWidget( m_scaleRadios );
+
+
+ QHBoxLayout *hbox = new QHBoxLayout( this );
+ layout->addLayout( hbox );
+
+ /** Box for Image Resolutions **/
+ QVGroupBox *group1 = new QVGroupBox( i18n("Resolutions"), this );
+ hbox->addWidget( group1 );
+
+ /* Postscript generation resolution */
+ m_psDraft = new QCheckBox( i18n("Generate low resolution PostScript (fast draft print)"),
+ group1, "cbPostScriptRes" );
+ m_psDraft->setChecked( false );
+
+
+ /* Scan resolution of the image */
+ m_dpi = new KIntNumInput( group1 );
+ m_dpi->setLabel( i18n("Scan resolution (dpi) " ), AlignVCenter );
+ m_dpi->setValue( 300 );
+ m_dpi->setSuffix( i18n(" dpi"));
+
+ /* Label for displaying the screen Resolution */
+ m_screenRes = new QLabel( group1 );
+
+ /** Box for Image Print Size **/
+ QVGroupBox *group = new QVGroupBox( i18n("Image Print Size"), this );
+ hbox->addWidget( group );
+
+ m_sizeW = new KIntNumInput( group );
+ m_sizeW->setLabel( i18n("Image width:"), AlignVCenter );
+ m_sizeW->setSuffix( i18n(" mm"));
+ connect( m_sizeW, SIGNAL(valueChanged(int)), SLOT(slCustomWidthChanged(int)));
+ m_sizeH = new KIntNumInput( m_sizeW, AlignVCenter, group );
+ m_sizeH->setLabel( i18n("Image height:"), AlignVCenter);
+ m_sizeH->setSuffix( i18n(" mm"));
+ connect( m_sizeH, SIGNAL(valueChanged(int)), SLOT(slCustomHeightChanged(int)));
+
+ m_ratio = new QCheckBox( i18n("Maintain aspect ratio"), group, "cbAspectRatio" );
+ m_ratio->setChecked(true);
+
+
+ QWidget *spaceEater = new QWidget( this );
+ spaceEater->setSizePolicy( QSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored ));
+ layout->addWidget( spaceEater );
+
+ /* Set start values */
+ m_rbScreen->setChecked(true);
+ slScaleChanged( ID_SCREEN );
+}
+
+void ImgPrintDialog::setImage( KookaImage *img )
+{
+ if( ! img ) return;
+
+ // TODO: get scan resolution out of the image
+
+}
+
+void ImgPrintDialog::setOptions(const QMap<QString,QString>& opts)
+{
+ // m_autofit->setChecked(opts["app-img-autofit"] == "1");
+ QString scale = opts[OPT_SCALING];
+
+ kdDebug(28000) << "In setOption" << endl;
+
+ if( scale == "scan" )
+ m_rbOrigSize->setChecked(true);
+ else if( scale == "custom" )
+ m_rbScale->setChecked(true);
+ else
+ m_rbScreen->setChecked(true);
+
+ int help = opts[OPT_SCAN_RES].toInt();
+ m_dpi->setValue( help );
+
+ help = opts[OPT_WIDTH].toInt();
+ m_sizeW->setValue( help );
+
+ help = opts[OPT_HEIGHT].toInt();
+ m_sizeH->setValue( help );
+
+ help = opts[OPT_SCREEN_RES].toInt();
+ m_screenRes->setText(i18n( "Screen resolution: %1 dpi").arg(help));
+
+ help = opts[OPT_PSGEN_DRAFT].toInt();
+ m_psDraft->setChecked( help == 1 );
+
+ help = opts[OPT_RATIO].toInt();
+ m_ratio->setChecked( help == 1 );
+
+}
+
+
+void ImgPrintDialog::getOptions(QMap<QString,QString>& opts, bool )
+{
+ // TODO: Check for meaning of include_def !
+ // kdDebug(28000) << "In getOption with include_def: " << include_def << endl;
+
+ QString scale = "screen";
+ if( m_rbOrigSize->isChecked() )
+ scale = "scan";
+ else if( m_rbScale->isChecked() )
+ scale = "custom";
+ else if( m_rbFitPage->isChecked() )
+ scale = "fitpage";
+
+ opts[OPT_SCALING] = scale;
+
+ opts[OPT_SCAN_RES] = QString::number( m_dpi->value() );
+ opts[OPT_WIDTH] = QString::number( m_sizeW->value() );
+ opts[OPT_HEIGHT] = QString::number( m_sizeH->value() );
+ opts[OPT_PSGEN_DRAFT] = QString::number( m_psDraft->isChecked() );
+ opts[OPT_RATIO] = QString::number( m_ratio->isChecked() );
+
+ {
+ QPaintDeviceMetrics metric( this );
+ opts[OPT_SCREEN_RES] = QString::number( metric.logicalDpiX());
+ }
+}
+
+bool ImgPrintDialog::isValid(QString& msg)
+{
+ /* check if scan reso is higher than 0 in case its needed */
+ int id = m_scaleRadios->id( m_scaleRadios->selected());
+ if( id == ID_ORIG && m_dpi->value() == 0 )
+ {
+ msg = i18n("Please specify a scan resolution larger than 0");
+ return false;
+ }
+ else if( id == ID_CUSTOM && (m_sizeW->value() == 0 || m_sizeH->value() == 0 ) )
+ {
+ msg = i18n("For custom printing, a valid size should be specified.\n"
+ "At least one dimension is zero.");
+ }
+
+ return true;
+}
+
+void ImgPrintDialog::slScaleChanged( int id )
+{
+ if( id == ID_SCREEN )
+ {
+ /* disalbe size, scan res. */
+ m_dpi->setEnabled(false);
+ m_ratio->setEnabled(false);
+ m_sizeW->setEnabled(false);
+ m_sizeH->setEnabled(false);
+ }
+ else if( id == ID_ORIG )
+ {
+ /* disable size */
+ m_dpi->setEnabled(true);
+ m_ratio->setEnabled(false);
+ m_sizeW->setEnabled(false);
+ m_sizeH->setEnabled(false);
+ }
+ else if( id == ID_CUSTOM )
+ {
+ m_dpi->setEnabled(false);
+ m_ratio->setEnabled(true);
+ m_sizeW->setEnabled(true);
+ m_sizeH->setEnabled(true);
+ }
+ else if( id == ID_FIT_PAGE )
+ {
+ m_dpi->setEnabled(false);
+ m_ratio->setEnabled(true);
+ m_sizeW->setEnabled(false);
+ m_sizeH->setEnabled(false);
+ }
+}
+
+void ImgPrintDialog::slCustomWidthChanged( int val )
+{
+ if( m_ignoreSignal )
+ {
+ m_ignoreSignal = false;
+ return;
+ }
+
+ /* go out here if scaling is not custom */
+ if( m_scaleRadios->id( m_scaleRadios->selected()) != ID_CUSTOM ) return;
+
+ /* go out here if maintain aspect ration is off */
+ if( ! m_ratio->isChecked() ) return;
+
+ m_ignoreSignal = true;
+ kdDebug(28000) << "Setting value to horizontal size" << endl;
+ m_sizeH->setValue( int( double(val) *
+ double(m_image->height())/double(m_image->width()) ) );
+
+}
+
+void ImgPrintDialog::slCustomHeightChanged( int val )
+{
+ if( m_ignoreSignal )
+ {
+ m_ignoreSignal = false;
+ return;
+ }
+
+ /* go out here if scaling is not custom */
+ if( m_scaleRadios->id( m_scaleRadios->selected()) != ID_CUSTOM ) return;
+
+ /* go out here if maintain aspect ration is off */
+ if( ! m_ratio->isChecked() ) return;
+
+ m_ignoreSignal = true;
+ kdDebug(28000) << "Setting value to vertical size" << endl;
+ m_sizeW->setValue( int( double(val) *
+ double(m_image->width())/double(m_image->height()) ) );
+
+}
+
+#include "imgprintdialog.moc"
diff --git a/kooka/imgprintdialog.h b/kooka/imgprintdialog.h
new file mode 100644
index 00000000..845cc038
--- /dev/null
+++ b/kooka/imgprintdialog.h
@@ -0,0 +1,89 @@
+/***************************************************************************
+ imgprintdialog.h - Kooka's Image Printing
+ -------------------
+ begin : May 2003
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef __IMGPRINTDIALOG_H__
+#define __IMGPRINTDIALOG_H__
+
+#include <qmap.h>
+#include <qcheckbox.h>
+#include <kdeprint/kprintdialogpage.h>
+
+#include "kookaimage.h"
+
+#define OPT_SCALING "kde-kooka-scaling"
+#define OPT_SCAN_RES "kde-kooka-scanres"
+#define OPT_SCREEN_RES "kde-kooka-screenres"
+#define OPT_WIDTH "kde-kooka-width"
+#define OPT_HEIGHT "kde-kooka-height"
+#define OPT_PSGEN_DRAFT "kde-kooka-psdraft"
+#define OPT_RATIO "kde-kooka-ratio"
+#define OPT_FITPAGE "kde-kooka-fitpage"
+class QWidget;
+class QString;
+class QLabel;
+class KIntNumInput;
+class KookaImage;
+class QVButtonGroup;
+class QRadioButton;
+class QCheckBox;
+
+class ImgPrintDialog: public KPrintDialogPage
+{
+ Q_OBJECT
+public:
+ ImgPrintDialog( KookaImage *img, QWidget *parent=0L, const char* name=0L );
+
+ void setOptions(const QMap<QString,QString>& opts);
+ void getOptions(QMap<QString,QString>& opts, bool include_def = false);
+ bool isValid(QString& msg);
+
+ void setImage( KookaImage *img );
+
+protected slots:
+ void slScaleChanged( int id );
+ void slCustomWidthChanged(int);
+ void slCustomHeightChanged(int);
+
+private:
+ QButtonGroup *m_scaleRadios;
+ QRadioButton *m_rbOrigSize;
+ QRadioButton *m_rbScale;
+ QRadioButton *m_rbScreen;
+ QRadioButton *m_rbFitPage;
+
+ KIntNumInput *m_sizeW;
+ KIntNumInput *m_sizeH;
+ KIntNumInput *m_dpi;
+
+ QCheckBox *m_psDraft;
+ QCheckBox *m_ratio;
+
+ KookaImage *m_image;
+ QLabel *m_screenRes;
+ bool m_ignoreSignal;
+};
+
+#endif
diff --git a/kooka/kadmosocr.cpp b/kooka/kadmosocr.cpp
new file mode 100644
index 00000000..72f9324b
--- /dev/null
+++ b/kooka/kadmosocr.cpp
@@ -0,0 +1,432 @@
+/***************************************************************************
+ kadmosocr.cpp - Kadmos cpp interface
+ -------------------
+ begin : Fri Jun 30 2000
+
+ (c) 2002 re Recognition AG Hafenstrasse 50b CH-8280 Kreuzlingen
+ Switzerland Phone: +41 (0)71 6780000 Fax: +41 (0)71 6780099
+ Website: www.reRecognition.com E-mail: info@reRecognition.com
+
+ Author: Tamas Nagy (nagy@rerecognition.com)
+ Klaas Freitag <freitag@suse.de>
+ Heike Stuerzenhofecker <heike@freisturz.de>
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+/* Kadmos CPP object oriented interface */
+
+#include <qimage.h>
+#include <qpainter.h>
+#include <qstring.h>
+#include <qrect.h>
+#include <qstringlist.h>
+
+#include <assert.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <kdebug.h>
+
+#include "kadmosocr.h"
+#include "ocrword.h"
+
+#ifdef HAVE_KADMOS
+
+using namespace Kadmos;
+
+/* -------------------- CRep -------------------- */
+CRep::CRep()
+ :QObject()
+{
+ memset(&m_RepData, 0, sizeof(m_RepData));
+ m_Error = RE_SUCCESS;
+ m_undetectChar = QChar('_');
+}
+
+CRep::~CRep()
+{
+}
+
+RelGraph* CRep::getGraphKnode(int line, int offset )
+{
+ Kadmos::RepResult *res = getRepResult(line);
+ if( res )
+ return ( &(getRepResult(line)->rel_graph[0])+offset);
+ else
+ return 0L;
+
+}
+
+
+RepResult* CRep::getRepResult(int line)
+{
+ if( line<0 || line >= m_RepData.rep_result_len ) return 0L;
+ return &(m_RepData.rep_result[line]);
+}
+
+RelResult* CRep::getRelResult(int line, RelGraph* graph, int alternative)
+{
+ if( ! ( graph && getRepResult(line))) return 0L;
+ int offset = graph->result_number[alternative];
+ return( &(getRepResult(line)->rel_result[0]) + offset );
+}
+
+
+KADMOS_ERROR CRep::Init(const char* ClassifierFilename)
+{
+ /* prepare RepData structure */
+ m_RepData.init.rel_grid_maxlen = GRID_MAX_LEN;
+ m_RepData.init.rel_graph_maxlen = GRAPH_MAX_LEN;
+ m_RepData.init.rel_result_maxlen = CHAR_MAX_LEN;
+ m_RepData.init.rep_memory_size = LINE_MAX_LEN * sizeof(RepResult) +
+ (long)LINE_MAX_LEN * CHAR_MAX_LEN * (sizeof(RelGraph)+
+ sizeof(RelResult));
+ m_RepData.init.rep_memory = malloc( m_RepData.init.rep_memory_size );
+ if (!m_RepData.init.rep_memory) {
+ CheckError();
+ return m_Error;
+ }
+ strcpy(m_RepData.init.version, INC_KADMOS);
+
+ m_Error = rep_init(&m_RepData, (char*)ClassifierFilename);
+ CheckError();
+ return m_Error;
+}
+
+void CRep::run() // KADMOS_ERROR CRep::Recognize()
+{
+ kdDebug(28000) << "ooo Locked and ocr!" << endl;
+ m_Error = rep_do(&m_RepData);
+ CheckError();
+}
+
+KADMOS_ERROR CRep::End()
+{
+ m_Error = rep_end(&m_RepData);
+ CheckError();
+ return m_Error;
+}
+
+int CRep::GetMaxLine()
+{
+ return m_RepData.rep_result_len;
+}
+
+const char* CRep::RepTextLine(int nLine, unsigned char RejectLevel, int RejectChar, long Format)
+{
+ m_Error = rep_textline(&m_RepData, nLine, m_Line,
+ 2*CHAR_MAX_LEN, RejectLevel, RejectChar, Format);
+ CheckError();
+ return m_Line;
+}
+
+/**
+ * This method handles the given line. It takes repRes and goes through the
+ * kadmos result tree structures recursivly.
+ */
+ocrWordList CRep::getLineWords( int line )
+{
+ ocrWordList repWords;
+ bool ok = true;
+
+ Kadmos::RepResult *repRes = getRepResult(line);
+
+ if( ! repRes )
+ {
+ kdDebug(28000) << "repRes-Pointer is null" << endl;
+ ok = false;
+ }
+
+ if( ok )
+ {
+ int nextKnode=0;
+
+ do
+ {
+ QString resultWord;
+ QRect boundingRect;
+
+ int newNextKnode = nextBestWord( line, nextKnode, resultWord, boundingRect );
+ boundingRect.moveBy( repRes->left, repRes->top );
+
+ ocrWord newWord;
+ newWord = resultWord;
+ newWord.setKnode(nextKnode);
+ newWord.setLine(line);
+ newWord.setRect(boundingRect);
+ repWords.push_back(newWord);
+
+ /* set nextKnode to the next Knode */
+ nextKnode = newNextKnode;
+
+
+ // Alternativen:
+ // partStrings( line, nextKnode, QString()); // fills m_parts - list with alternative words
+ // nextKnode = newNextKnode;
+ // kdDebug(28000) << "NextKnodeWord: " << resultWord << endl;
+ }
+ while( nextKnode > 0 );
+ }
+ return repWords;
+}
+
+
+/* This fills theWord with the next best word and returns the
+ * next knode or 0 if there is no next node
+ */
+int CRep::nextBestWord( int line, int knode, QString& theWord, QRect& brect )
+{
+
+ Kadmos::RelGraph *relg = getGraphKnode( line, knode );
+ // kdDebug(28000) << "GraphKnode is " << knode << endl;
+ int nextKnode = knode;
+
+ while( relg )
+ {
+ Kadmos::RelResult *relr = getRelResult( line, relg, 0 ); // best alternative
+ if( relr )
+ {
+ // kdDebug(28000) << "Leading Blanks: " << relg->leading_blanks <<
+ // " und Knode " << knode << endl;
+ char c = relr->rec_char[0][0];
+ QChar newChar = c;
+ if( c == 0 )
+ {
+ kdDebug(28000) << "Undetected char found !" << endl;
+ newChar = m_undetectChar;
+ }
+
+ if ( (nextKnode != knode) && (relg->leading_blanks > 0))
+ {
+ /* this means the word ends here. */
+ // kdDebug(28000) << "----" << theWord << endl;
+ relg = 0L; /* Leave the loop. */
+ }
+ else
+ {
+ /* append the character */
+ theWord.append(newChar);
+
+ /* save the bounding rect */
+ // kdDebug(28000) << "LEFT: " << relr->left << " TOP: " << relr->top << endl;
+ QRect r( relr->left, relr->top, relr->width, relr->height );
+
+ if( brect.isNull() )
+ {
+ brect = r;
+ }
+ else
+ {
+ brect = brect.unite( r );
+ }
+
+ /* next knode */
+ if( relg->next[0] > 0 )
+ {
+ nextKnode = relg->next[0];
+ relg = getGraphKnode( line, nextKnode );
+ }
+ else
+ {
+ /* end of the line */
+ nextKnode = 0;
+ relg = 0L;
+ }
+ }
+ }
+ }
+ return( nextKnode );
+}
+
+
+
+void CRep::partStrings( int line, int graphKnode, QString soFar )
+{
+ /* The following knodes after a word break */
+ Kadmos::RelGraph *relg = getGraphKnode( line, graphKnode );
+ // kdDebug(28000) << "GraphKnode is " << graphKnode << endl;
+
+ QString theWord="";
+ for( int resNo=0; resNo < SEG_ALT; resNo++ )
+ {
+ // kdDebug(28000) << "Alternative " << resNo << " is " << relg->result_number[resNo] << endl;
+ if( relg->result_number[resNo] == -1 )
+ {
+ /* This means that there is no other alternative. Go out here. */
+ break;
+ }
+
+ Kadmos::RelResult *relr = getRelResult( line, relg, resNo );
+ theWord = QChar(relr->rec_char[0][0]);
+
+ if ( !soFar.isEmpty() && relg->leading_blanks )
+ {
+ /* this means the previous words end. */
+ // TODO: This forgets the alternatives of _this_ first character of the new word.
+
+ kdDebug(28000) << "---- " << soFar << endl;
+ m_parts << soFar;
+ break;
+ }
+ else
+ {
+ /* make a QString from this single char and append it. */
+ soFar += theWord;
+ }
+
+ if( relg->next[resNo] > 0 )
+ {
+ /* There is a follower to this knode. Combine the result list from a recursive call
+ * to this function with the follower knode.
+ */
+ partStrings( line, relg->next[resNo], soFar );
+ }
+ else
+ {
+ /* There is no follower */
+ kdDebug(28000) << "No followers - theWord is " << soFar << endl;
+ m_parts<<soFar;
+ break;
+ }
+ }
+}
+
+
+
+void CRep::drawCharBox( QPixmap *pix, const QRect& r )
+{
+ drawBox( pix, r, QColor( Qt::red ));
+}
+
+void CRep::drawLineBox( QPixmap* pix, const QRect& r )
+{
+ drawBox( pix, r, QColor( Qt::blue ));
+}
+
+void CRep::drawBox( QPixmap* pix, const QRect& r, const QColor& color )
+{
+ QPainter p;
+ p.begin(pix);
+
+ p.setPen( color );
+ p.drawRect(r);
+}
+
+
+
+KADMOS_ERROR CRep::SetImage( const QString file )
+{
+ ReImageHandle image_handle;
+ image_handle = re_readimage(file.latin1(), &m_RepData.image);
+ if( ! image_handle )
+ {
+ kdDebug(28000) << "Can not load input file" << endl;
+ }
+ CheckError();
+ return RE_SUCCESS;
+
+}
+
+KADMOS_ERROR CRep::SetImage(QImage *Image)
+{
+ // memcpy(&m_RepData.image, Image.bits(), Image.numBytes());
+ if( !Image ) return RE_PARAMETERERROR;
+
+ kdDebug(28000) << "Setting image manually." << endl;
+ m_RepData.image.data = (void*)Image->bits();
+ m_RepData.image.imgtype = IMGTYPE_PIXELARRAY;
+ m_RepData.image.width = Image->width();
+ m_RepData.image.height = Image->height();
+ m_RepData.image.bitsperpixel = Image->depth();
+ m_RepData.image.alignment = 1;
+ m_RepData.image.fillorder = FILLORDER_MSB2LSB;
+ // color
+ if( Image->depth() == 1 || (Image->numColors()==2 && Image->depth() == 8) )
+ {
+ m_RepData.image.color=COLOR_BINARY;
+ kdDebug(28000) << "Setting Binary" << endl;
+ } else if( Image->isGrayscale() ) {
+ m_RepData.image.color = COLOR_GRAY;
+ kdDebug(28000) << "Setting GRAY" << endl;
+
+ } else {
+ m_RepData.image.color = COLOR_RGB;
+ kdDebug(28000) << "Setting Color RGB" << endl;
+ }
+ // orientation
+ m_RepData.image.orientation = ORIENTATION_TOPLEFT;
+ m_RepData.image.photometric = PHOTOMETRIC_MINISWHITE;
+ m_RepData.image.resunit = RESUNIT_INCH;
+ m_RepData.image.xresolution = 200;
+ m_RepData.image.yresolution = 200;
+
+ CheckError();
+
+ return RE_SUCCESS;
+}
+
+void CRep::SetNoiseReduction(bool bNoiseReduction)
+{
+ if (bNoiseReduction) {
+ m_RepData.parm.prep |= PREP_AUTO_NOISEREDUCTION;
+ }
+ else {
+ m_RepData.parm.prep &= !PREP_AUTO_NOISEREDUCTION;
+ }
+}
+
+void CRep::SetScaling(bool bScaling)
+{
+ if (bScaling) {
+ m_RepData.parm.prep |= PREP_SCALING;
+ }
+ else {
+ m_RepData.parm.prep &= !PREP_SCALING;
+ }
+}
+
+void CRep::CheckError()
+{
+ if ( kadmosError() )
+ {
+ kdDebug(28000) << "KADMOS ERROR: " << getErrorText() << endl;
+ }
+}
+
+/* returns a QString containing the string describing the kadmos error */
+QString CRep::getErrorText() const
+{
+ re_ErrorText Err;
+ re_GetErrorText(&Err);
+ return QString::fromLocal8Bit( Err.text );
+}
+
+bool CRep::kadmosError()
+{
+ return m_Error != RE_SUCCESS;
+}
+
+#include "kadmosocr.moc"
+
+#endif /* HAVE_KADMOS */
+
+
+// } /* End of Kadmos namespace */
diff --git a/kooka/kadmosocr.h b/kooka/kadmosocr.h
new file mode 100644
index 00000000..12056209
--- /dev/null
+++ b/kooka/kadmosocr.h
@@ -0,0 +1,143 @@
+/***************************************************************************
+ kadmosocr.h - Kadmos cpp interface
+ -------------------
+ begin : Fri Jun 30 2000
+
+ (c) 2002 re Recognition AG Hafenstrasse 50b CH-8280 Kreuzlingen
+ Switzerland Phone: +41 (0)71 6780000 Fax: +41 (0)71 6780099
+ Website: www.reRecognition.com E-mail: info@reRecognition.com
+
+ Author: Tamas Nagy (nagy@rerecognition.com)
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef __KADMOS_OCR_
+#define __KADMOS_OCR_
+
+#include <qobject.h>
+#include <qstring.h>
+
+#include "config.h"
+
+#ifdef HAVE_KADMOS
+/* class declarations */
+class QImage;
+class QPixmap;
+class QColor;
+class QStringList;
+class QRect;
+
+
+class ocrWord;
+class ocrWordList;
+
+namespace Kadmos {
+
+/* include files */
+
+#include "kadmos.h"
+#include <qptrlist.h>
+
+/* ---------------------------------------- REP ---------------------------------------- */
+//! Maximum number of lines in a paragraph
+ const int LINE_MAX_LEN = 100;
+ const int GRID_MAX_LEN = 50; //!< Maximum number of grid elements in a line
+ const int GRAPH_MAX_LEN = 500; //!< Maximum number of graph elements in a line
+ const int CHAR_MAX_LEN = 500; //!< Maximum number of characters in a line
+
+ /* Error handling */
+ const char CPP_ERROR[] = "Kadmos CPP interface error";
+
+ /* ==== CRep ========================================= */
+ class CRep : public QObject
+ {
+ Q_OBJECT
+ public:
+ CRep();
+ virtual ~CRep();
+
+ RepResult* getRepResult(int line=0);
+ RelGraph* getGraphKnode(int line, int offset=0);
+ RelResult* getRelResult(int line, Kadmos::RelGraph* graph, int alternative=0);
+
+
+ /**
+ @param ClassifierFilename is a name of a classifier file (*.rec)
+ */
+ KADMOS_ERROR Init(const char* ClassifierFile);
+
+ virtual void run();
+ virtual bool finished() { return true; }
+ // KADMOS_ERROR Recognize();
+ KADMOS_ERROR End();
+
+ /**
+ @param Image is an image object
+ */
+ KADMOS_ERROR SetImage(QImage* Image);
+ KADMOS_ERROR SetImage( const QString );
+ int GetMaxLine();
+
+ ocrWordList getLineWords( int line );
+
+ const char* RepTextLine(int Line, unsigned char RejectLevel=128,
+ int RejectChar='~', long Format=TEXT_FORMAT_ANSI);
+
+ void analyseLine(int, QPixmap* );
+ /** Enable/disable noise reduction
+ @param TRUE(enable)/FALSE(disable) noise reduction
+ */
+ void SetNoiseReduction(bool bNoiseReduction);
+
+ /** Enable/disable scaling (size normalization)
+ @param TRUE(enable)/FALSE(disable) scaling (size normalization)
+ */
+ void SetScaling(bool bScaling);
+
+ /* draw graphic visualiser into the pixmap pointed to */
+ virtual void drawLineBox( QPixmap*, const QRect& );
+ virtual void drawCharBox( QPixmap*, const QRect& );
+ virtual void drawBox( QPixmap*, const QRect&, const QColor& );
+
+ int nextBestWord( int line, int knode, QString& theWord, QRect& brect );
+
+ /* Error text in QString */
+ QString getErrorText() const;
+ bool kadmosError();
+ private:
+ void partStrings( int line, int graphKnode, QString soFar );
+ void CheckError();
+
+ RepData m_RepData;
+ KADMOS_ERROR m_Error;
+ char m_Line[2*CHAR_MAX_LEN];
+ int m_currLine;
+ QStringList m_parts;
+ QString m_theWord;
+ int m_recurse;
+
+ QChar m_undetectChar;
+ };
+
+} /* End of Kadmos namespace */
+
+#endif /* HAVE KADMOS */
+
+#endif /* header tagging */
diff --git a/kooka/kocrbase.cpp b/kooka/kocrbase.cpp
new file mode 100644
index 00000000..889739e7
--- /dev/null
+++ b/kooka/kocrbase.cpp
@@ -0,0 +1,368 @@
+/***************************************************************************
+ kocrbase.cpp - base dialog for ocr
+ -------------------
+ begin : Fri Now 10 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qfileinfo.h>
+#include <qtooltip.h>
+#include <kio/job.h>
+#include <kio/previewjob.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kanimwidget.h>
+#include <kseparator.h>
+#include <kmessagebox.h>
+#include <kactivelabel.h>
+#include <qhbox.h>
+#include <qvbox.h>
+
+#include "resource.h"
+#include "kocrbase.h"
+#include "ksaneocr.h"
+#include "kookaimage.h"
+
+#include <kscanslider.h>
+#include <kstandarddirs.h>
+#include <kfilemetainfo.h>
+#include <ksconfig.h>
+#include <qstringlist.h>
+#include <qcolor.h>
+#include <qgrid.h>
+#include <qsizepolicy.h>
+#include <qgroupbox.h>
+#include <qcheckbox.h>
+
+KOCRBase::KOCRBase( QWidget *parent, KSpellConfig *spellConfig,
+ KDialogBase::DialogType face )
+ :KDialogBase( face, i18n("Optical Character Recognition"),
+ User2|Close|User1, User1, parent,0, false, true,
+ KGuiItem( i18n("Start OCR" ), "launch",
+ i18n("Start the Optical Character Recognition process" )),
+ KGuiItem( i18n("Cancel" ), "stopocr",
+ i18n("Stop the OCR Process" ))),
+ m_animation(0L),
+ m_metaBox(0L),
+ m_imgHBox(0L),
+ m_previewPix(0L),
+ m_currImg(0L),
+ m_spellConfig(spellConfig),
+ m_wantSpellCfg(true),
+ m_userWantsSpellCheck(true),
+ m_cbWantCheck(0L),
+ m_gbSpellOpts(0L)
+{
+ kdDebug(28000) << "OCR Base Dialog!" << endl;
+ // Layout-Boxes
+
+ KConfig *konf = KGlobal::config ();
+ KConfigGroupSaver gs( konf, CFG_OCR_KSPELL );
+ m_userWantsSpellCheck = konf->readBoolEntry(CFG_WANT_KSPELL, true);
+
+ /* Connect signals which disable the fields and store the configuration */
+ connect( this, SIGNAL( user1Clicked()), this, SLOT( writeConfig()));
+ connect( this, SIGNAL( user1Clicked()), this, SLOT( startOCR() ));
+ connect( this, SIGNAL( user2Clicked()), this, SLOT( stopOCR() ));
+ m_previewSize.setWidth(200);
+ m_previewSize.setHeight(300);
+
+ enableButton( User1, true ); /* start ocr */
+ enableButton( User2, false ); /* Cancel */
+ enableButton( Close, true );
+}
+
+
+KAnimWidget* KOCRBase::getAnimation(QWidget *parent)
+{
+ if( ! m_animation )
+ {
+ m_animation = new KAnimWidget( QString("kde"), 48, parent, "ANIMATION" );
+ }
+ return( m_animation );
+}
+
+EngineError KOCRBase::setupGui()
+{
+ ocrIntro();
+ imgIntro();
+ if( m_wantSpellCfg ) spellCheckIntro();
+
+ return ENG_OK;
+}
+
+void KOCRBase::imgIntro()
+{
+ m_imgPage = addVBoxPage( i18n("Image") );
+ (void) new QLabel( i18n("Image Information"), m_imgPage );
+
+ // Caption - Label and image
+ m_imgHBox = new QHBox( m_imgPage );
+
+ m_imgHBox->setSpacing( KDialog::spacingHint());
+
+ m_previewPix = new QLabel( m_imgHBox );
+ m_previewPix->setPixmap(QPixmap());
+ m_previewPix->setFixedSize(m_previewSize);
+ m_previewPix->setAlignment( Qt::AlignCenter );
+ m_previewPix->setFrameStyle( QFrame::Panel | QFrame::Sunken );
+ // m_previewPix->resize(m_previewSize);
+
+ /* See introduceImage where the meta box is filled with data from the
+ * incoming widget.
+ */
+ m_metaBox = new QVBox( m_imgHBox );
+}
+
+/*
+ * This creates a Tab OCR
+ */
+void KOCRBase::ocrIntro( )
+{
+ m_ocrPage = addVBoxPage( i18n("OCR") );
+
+ // Caption - Label and image
+ /* labelstring */
+ (void) new QLabel( i18n("<b>Starting Optical Character Recognition with %1</b><p>").
+ arg( ocrEngineName() ), m_ocrPage );
+ // Find the kadmos logo and display if available
+ KStandardDirs stdDir;
+ QString logo = stdDir.findResource( "data", "kooka/pics/" + ocrEngineLogo() );
+
+ kdDebug(28000)<< "Reading logo " << logo << endl;
+ QPixmap pix;
+ QWidget *pa = m_ocrPage;
+
+ if( pix.load( logo ))
+ {
+ QHBox *hb_cap = new QHBox( m_ocrPage );
+ hb_cap->setSpacing( KDialog::spacingHint());
+
+ QLabel *imgLab = new QLabel( hb_cap );
+ imgLab->setAlignment( Qt::AlignHCenter | Qt::AlignTop );
+ imgLab->setPixmap( pix );
+ pa = hb_cap;
+ }
+
+ (void) new KActiveLabel( ocrEngineDesc(), pa );
+}
+
+
+void KOCRBase::spellCheckIntro()
+{
+ m_spellchkPage = addVBoxPage( i18n("Spell-checking") );
+
+ /* Want the spell checking at all? Checkbox here */
+ QGroupBox *gb1 = new QGroupBox( 1, Qt::Horizontal, i18n("OCR Post Processing"), m_spellchkPage );
+ m_cbWantCheck = new QCheckBox( i18n("Enable spell-checking for validation of the OCR result"),
+ gb1 );
+ /* Spellcheck options */
+ m_gbSpellOpts = new QGroupBox( 1, Qt::Horizontal, i18n("Spell-Check Options"),
+ m_spellchkPage );
+
+ KSpellConfig *sCfg = new KSpellConfig( m_gbSpellOpts, "SPELLCHK", m_spellConfig, false );
+ /* A space eater */
+ QWidget *spaceEater = new QWidget(m_spellchkPage);
+ spaceEater->setSizePolicy( QSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored ));
+
+ /* connect toggle button */
+ connect( m_cbWantCheck, SIGNAL(toggled(bool)), this, SLOT(slWantSpellcheck(bool)));
+ m_cbWantCheck->setChecked( m_userWantsSpellCheck );
+ m_gbSpellOpts->setEnabled( m_userWantsSpellCheck );
+ m_spellConfig = sCfg;
+
+ connect( sCfg, SIGNAL(configChanged()),
+ this, SLOT(slSpellConfigChanged()));
+}
+
+void KOCRBase::slSpellConfigChanged()
+{
+ kdDebug(28000) << "Spellcheck config changed" << endl;
+}
+
+
+
+void KOCRBase::stopAnimation()
+{
+ if( m_animation )
+ m_animation->stop();
+}
+
+void KOCRBase::startAnimation()
+{
+ if( m_animation )
+ m_animation->start();
+}
+
+KOCRBase::~KOCRBase()
+{
+
+}
+
+void KOCRBase::introduceImage( KookaImage* img)
+{
+ if( ! (img && img->isFileBound()) ) return;
+ KFileMetaInfo info = img->fileMetaInfo();
+ QStringList groups;
+ if ( info.isValid() )
+ groups = info.preferredGroups();
+
+ delete m_metaBox;
+ m_metaBox = new QVBox( m_imgHBox );
+
+ /* Start to create a preview job for the thumb */
+ KURL::List li(img->url());
+ KIO::Job *m_job = KIO::filePreview(li, m_previewSize.width(),
+ m_previewSize.height());
+
+ if( m_job )
+ {
+ connect( m_job, SIGNAL( result( KIO::Job * )),
+ this, SLOT( slPreviewResult( KIO::Job * )));
+ connect( m_job, SIGNAL( gotPreview( const KFileItem*, const QPixmap& )),
+ SLOT( slGotPreview( const KFileItem*, const QPixmap& ) ));
+ /* KIO::Jo result is called in any way: Success, Failed, Error,
+ * thus connecting the failed is not really necessary.
+ */
+ }
+
+ for ( QStringList::Iterator it = groups.begin(); it != groups.end(); ++it )
+ {
+ QString theGroup(*it);
+
+ kdDebug(29000) << "handling the group " << theGroup << endl;
+
+ QStringList keys = info.group(theGroup).supportedKeys();
+
+ if( keys.count() > 0 )
+ {
+ // info.groupInfo( theGroup )->translatedName()
+ // FIXME: howto get the translated group name?
+ QLabel *lGroup = new QLabel( theGroup, m_metaBox );
+ lGroup->setBackgroundColor( QColor(gray));
+ lGroup->setMargin( KDialog::spacingHint());
+
+ QGrid *nGrid = new QGrid( 2, m_metaBox );
+ nGrid->setSpacing( KDialog::spacingHint());
+ for ( QStringList::Iterator keyIt = keys.begin(); keyIt != keys.end(); ++keyIt )
+ {
+ KFileMetaInfoItem item = info.item(*keyIt);
+ QString itKey = item.translatedKey();
+ if( itKey.isEmpty() )
+ itKey = item.key();
+ if( ! itKey.isEmpty() )
+ {
+ (void) new QLabel( item.translatedKey() + ": ", nGrid );
+ (void) new QLabel( item.string(), nGrid );
+ kdDebug(29000) << "hasKey " << *keyIt << endl;
+ }
+ }
+ }
+ }
+ QWidget *spaceEater = new QWidget( m_metaBox );
+ spaceEater->setSizePolicy( QSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored ));
+ m_metaBox->show();
+}
+
+void KOCRBase::slPreviewResult(KIO::Job *job )
+{
+ // nothing
+ if( job && job->error() > 0 )
+ {
+ kdDebug(28000) << "Thumbnail Creation ERROR: " << job->errorString() << endl;
+ job->showErrorDialog( 0 );
+ }
+}
+
+void KOCRBase::slGotPreview( const KFileItem*, const QPixmap& newPix )
+{
+ kdDebug(28000) << "Got the preview" << endl;
+ m_previewPix->setPixmap(newPix);
+
+ if( m_previewPix && m_currImg )
+ {
+ m_previewPix->setPixmap(newPix);
+ }
+}
+
+
+void KOCRBase::writeConfig()
+{
+
+}
+
+bool KOCRBase::wantSpellCheck()
+{
+ return m_userWantsSpellCheck;
+}
+
+void KOCRBase::startOCR()
+{
+ /* en- and disable the buttons */
+ kdDebug(28000) << "Base: Starting OCR" << endl;
+
+ enableFields(false);
+ enableButton( User1, false ); /* Start OCR */
+ enableButton( User2, true ); /* Stop OCR */
+ enableButton( Close, true );
+
+ startAnimation();
+}
+
+void KOCRBase::stopOCR()
+{
+ enableFields(true);
+
+ enableButton( User1, true ); /* start ocr */
+ enableButton( User2, false ); /* Cancel */
+ enableButton( Close, true );
+
+ stopAnimation();
+
+}
+
+void KOCRBase::enableFields(bool)
+{
+
+}
+
+void KOCRBase::slWantSpellcheck( bool wantIt )
+{
+ if( m_gbSpellOpts )
+ {
+ m_gbSpellOpts->setEnabled( wantIt );
+ }
+ m_userWantsSpellCheck = wantIt;
+
+ KConfig *konf = KGlobal::config ();
+ KConfigGroupSaver gs( konf, CFG_OCR_KSPELL );
+ konf->writeEntry( CFG_WANT_KSPELL, wantIt );
+}
+
+/* The End ;) */
+#include "kocrbase.moc"
diff --git a/kooka/kocrbase.h b/kooka/kocrbase.h
new file mode 100644
index 00000000..05987b1d
--- /dev/null
+++ b/kooka/kocrbase.h
@@ -0,0 +1,158 @@
+/***************************************************************************
+ kocrbase.h - base dialog for OCR
+ -------------------
+ begin : Sun Jun 11 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef KOCRBASE_H
+#define KOCRBASE_H
+
+#include <kdialogbase.h>
+#include <kio/previewjob.h>
+#include <qimage.h>
+#include <qstring.h>
+
+#include <kscanslider.h>
+#include <kanimwidget.h>
+#include <ksconfig.h>
+
+#include "ksaneocr.h"
+/**
+ *@author Klaas Freitag
+ */
+
+
+class KookaImage;
+class QHBox;
+class QVBox;
+class QLabel;
+class QSize;
+class KSpellConfig;
+class QCheckBox;
+class QGroupBox;
+
+class KOCRBase: public KDialogBase
+{
+ Q_OBJECT
+public:
+ KOCRBase( QWidget *, KSpellConfig *spellConfig,
+ KDialogBase::DialogType face = KDialogBase::Plain );
+ ~KOCRBase();
+
+ virtual EngineError setupGui();
+
+ /**
+ * @return the name of the ocr engine
+ */
+ virtual QString ocrEngineName() const { return QString(); }
+
+ /**
+ * @return the filename (without path) of the logo of the ocr engine.
+ * the logo needs to be installed in $KDEDIR/share/apps/kooka/pics
+ */
+ virtual QString ocrEngineLogo() const { return QString(); }
+
+ /**
+ * @return a description string of the ocr engine
+ */
+ virtual QString ocrEngineDesc() const { return QString(); }
+
+ QVBox* ocrPage() const { return m_ocrPage; }
+ QVBox* imagePage() const { return m_imgPage; }
+
+ KSpellConfig* spellConfig() const
+ { return m_spellConfig; }
+
+ bool wantSpellCheck();
+
+public slots:
+ virtual void stopAnimation();
+ virtual void startAnimation();
+
+ virtual void introduceImage( KookaImage* );
+
+ virtual void startOCR();
+ virtual void stopOCR();
+ /**
+ * enable or disable dialog fields. This slot is called when the ocr process starts
+ * with parameter state=false and called again if the gui should accept user input
+ * again after ocr finished with parameter true.
+ */
+ virtual void enableFields(bool state);
+
+protected:
+ /**
+ * This creates a a tab OCR in the dialog and creates a small intro about the
+ * ocr engine used.
+ * It calls the virtual subs ocrEngineName, ocrEngineLogo and ocrEngineDesc which
+ * must return the approbiate values for the engines.
+ * @return a pointer to a VBox in which further elements can be layouted
+ */
+ virtual void ocrIntro();
+
+ /**
+ * This creates a a tab Image Info in the dialog and creates a image description
+ * about the current image to ocr.
+ */
+ virtual void imgIntro();
+
+ /**
+ * This sets up the spellchecking configuration
+ */
+ virtual void spellCheckIntro();
+
+
+protected slots:
+ virtual KAnimWidget* getAnimation(QWidget*);
+ virtual void writeConfig();
+ virtual void slSpellConfigChanged();
+
+ /**
+ * hit if the user toggles the want-spellcheck checkbox
+ */
+ virtual void slWantSpellcheck( bool wantIt );
+
+private slots:
+ virtual void slPreviewResult( KIO::Job* );
+ virtual void slGotPreview( const KFileItem*, const QPixmap& );
+
+private:
+ KAnimWidget *m_animation;
+ QVBox *m_ocrPage;
+ QVBox *m_imgPage;
+ QVBox *m_spellchkPage;
+ QVBox *m_metaBox;
+ QHBox *m_imgHBox;
+ QLabel *m_previewPix;
+ KookaImage *m_currImg;
+
+ KSpellConfig *m_spellConfig;
+ bool m_wantSpellCfg; /* show the spellcheck options? */
+ bool m_userWantsSpellCheck; /* user has enabled/disabled spellcheck */
+ QSize m_previewSize;
+
+ QCheckBox *m_cbWantCheck;
+ QGroupBox *m_gbSpellOpts;
+};
+
+#endif
diff --git a/kooka/kocrgocr.cpp b/kooka/kocrgocr.cpp
new file mode 100644
index 00000000..cfc4c92c
--- /dev/null
+++ b/kooka/kocrgocr.cpp
@@ -0,0 +1,201 @@
+/***************************************************************************
+ kocrgocr.cpp - GOCR ocr dialog
+ -------------------
+ begin : Fri Now 10 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qfileinfo.h>
+#include <qtooltip.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kanimwidget.h>
+#include <kseparator.h>
+#include <kmessagebox.h>
+
+#include "resource.h"
+#include "ksaneocr.h" // TODO: Really needed?
+#include "kocrgocr.h"
+#include "kocrgocr.moc"
+#include <kscanslider.h>
+#include "kookaimage.h"
+#include "kookapref.h"
+#include <qvbox.h>
+#include <qhbox.h>
+
+/* defines for konfig-reading */
+
+#define CFG_GOCR_DUSTSIZE "gocrDustSize"
+#define CFG_GOCR_GRAYLEVEL "gocrGrayLevel"
+#define CFG_GOCR_SPACEWIDTH "gocrSpaceWidth"
+
+
+
+KGOCRDialog::KGOCRDialog( QWidget *parent, KSpellConfig *spellConfig )
+ :KOCRBase( parent, spellConfig, KDialogBase::Tabbed ),
+ m_ocrCmd( QString())
+{
+ kdDebug(28000) << "Starting KOCR-Start-Dialog!" << endl;
+ // Layout-Boxes
+}
+
+QString KGOCRDialog::ocrEngineLogo() const
+{
+ return "gocr.png";
+}
+
+QString KGOCRDialog::ocrEngineName() const
+{
+ return i18n("GOCR" );
+}
+
+QString KGOCRDialog::ocrEngineDesc() const
+{
+ return i18n("GOCR is an Open Source project "
+ "for optical character recognition.<P>"
+ "The author of gocr is <B>Joerg Schulenburg</B><BR>"
+ "For more information about gocr see "
+ "<A HREF=http://jocr.sourceforge.net>"
+ "http://jocr.sourceforge.net</A>");
+}
+
+EngineError KGOCRDialog::setupGui()
+{
+ KOCRBase::setupGui();
+
+ QVBox *page = ocrPage();
+ Q_CHECK_PTR( page );
+
+ KConfig *conf = KGlobal::config ();
+ conf->setGroup( CFG_GROUP_OCR_DIA );
+
+ // Horizontal line
+ // (void) new KSeparator( KSeparator::HLine, page);
+
+ // Entry-Field.
+ QString res = conf->readPathEntry( CFG_GOCR_BINARY, "notFound" );
+ if( res == "notFound" )
+ {
+ res = KookaPreferences::tryFindGocr();
+ if( res.isEmpty() )
+ {
+ /* Popup here telling that the config needs to be called */
+ KMessageBox::sorry( this, i18n( "The path to the gocr binary is not configured yet.\n"
+ "Please go to the Kooka configuration and enter the path manually."),
+ i18n("OCR Software Not Found") );
+ }
+ }
+
+ if( res.isEmpty() )
+ res = i18n("Not found");
+ else
+ m_ocrCmd = res;
+
+ (void) new QLabel( i18n("Using GOCR binary: ") + res, page );
+ (void) new KSeparator( KSeparator::HLine, page);
+
+ QHBox *hb = new QHBox(page);
+ hb->setSpacing( KDialog::spacingHint());
+ QVBox *innerBox = new QVBox( hb );
+ innerBox->setSpacing( KDialog::spacingHint());
+ /* This is for a 'work-in-progress'-Animation */
+ getAnimation(hb);
+
+ /* Slider for OCR-Options */
+ sliderGrayLevel = new KScanSlider( innerBox , i18n("&Gray level"), 0, 254, true, 160 );
+ int numdefault = conf->readNumEntry( CFG_GOCR_GRAYLEVEL, 160 );
+ sliderGrayLevel->slSetSlider( numdefault );
+ QToolTip::add( sliderGrayLevel,
+ i18n( "The numeric value gray pixels are \nconsidered to be black.\n\nDefault is 160"));
+
+ sliderDustSize = new KScanSlider( innerBox, i18n("&Dust size" ), 0, 60, true, 10 );
+ numdefault = conf->readNumEntry( CFG_GOCR_DUSTSIZE, 10 );
+ sliderDustSize->slSetSlider( numdefault );
+ QToolTip::add( sliderDustSize,
+ i18n( "Clusters smaller than this value\nwill be considered to be dust and \nremoved from the image.\n\nDefault is 10"));
+
+ sliderSpace = new KScanSlider( innerBox, i18n( "&Space width" ), 0, 60, true, 0 );
+ numdefault = conf->readNumEntry( CFG_GOCR_SPACEWIDTH, 0 );
+ sliderSpace->slSetSlider( numdefault );
+ QToolTip::add( sliderSpace, i18n("Spacing between characters.\n\nDefault is 0 what means autodetection"));
+
+ return ENG_OK;
+}
+
+void KGOCRDialog::introduceImage( KookaImage *img )
+{
+ if( !img ) return;
+
+ KOCRBase::introduceImage( img );
+
+
+ bool isOn = true;
+
+ if( img->numColors() > 0 && img->numColors() <3 )
+ {
+ kdDebug(29000) << "introduceImage: Have " << img->numColors() << " colors on depth " << img->depth() << endl;
+
+ /* that means it is a black-and-white image. Thus we do not need the GrayLevel slider */
+ isOn = false;
+ }
+
+ if( sliderGrayLevel )
+ sliderGrayLevel->setEnabled( isOn );
+
+}
+
+
+KGOCRDialog::~KGOCRDialog()
+{
+
+}
+
+void KGOCRDialog::writeConfig( void )
+{
+ KConfig *conf = KGlobal::config ();
+ conf->setGroup( CFG_GROUP_OCR_DIA );
+
+ conf->writeEntry( CFG_GOCR_BINARY, QString(getOCRCmd()));
+ conf->writeEntry( CFG_GOCR_GRAYLEVEL, getGraylevel());
+ conf->writeEntry( CFG_GOCR_DUSTSIZE, getDustsize());
+ conf->writeEntry( CFG_GOCR_SPACEWIDTH, getSpaceWidth());
+}
+
+
+void KGOCRDialog::enableFields(bool b)
+{
+ kdDebug(28000) << "About to disable the entry fields" << endl;
+ sliderGrayLevel->setEnabled( b );
+ sliderDustSize->setEnabled( b );
+ sliderSpace->setEnabled( b );
+}
+
+/* The End ;) */
+
diff --git a/kooka/kocrgocr.h b/kooka/kocrgocr.h
new file mode 100644
index 00000000..619cfedd
--- /dev/null
+++ b/kooka/kocrgocr.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ kocrgocr.h - ocr dialog for GOCR
+ -------------------
+ begin : Sun Jun 11 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+
+#ifndef KOCRGOCR_H
+#define KOCRGOCR_H
+
+#include <kdialogbase.h>
+#include <qimage.h>
+#include <qstring.h>
+
+#include <kscanslider.h>
+#include <kanimwidget.h>
+
+#include "kocrbase.h"
+/**
+ *@author Klaas Freitag
+ */
+
+class KSpellConfig;
+
+class KGOCRDialog: public KOCRBase
+{
+ Q_OBJECT
+public:
+ KGOCRDialog( QWidget*, KSpellConfig* );
+ ~KGOCRDialog();
+
+ QString getOCRCmd( void ) const
+ { return m_ocrCmd;}
+
+ int getGraylevel( void ) const
+ { return( sliderGrayLevel->value());}
+ int getDustsize( void ) const
+ { return( sliderDustSize->value());}
+ int getSpaceWidth( void ) const
+ { return( sliderSpace->value());}
+
+ EngineError setupGui();
+
+ QString ocrEngineName() const;
+ QString ocrEngineDesc() const;
+ QString ocrEngineLogo() const;
+
+public slots:
+ void enableFields(bool);
+ void introduceImage( KookaImage* );
+
+protected:
+ void writeConfig();
+
+
+private:
+
+
+ KScanSlider *sliderGrayLevel;
+ KScanSlider *sliderDustSize;
+ KScanSlider *sliderSpace;
+
+ QString m_ocrCmd;
+};
+
+#endif
diff --git a/kooka/kocrkadmos.cpp b/kooka/kocrkadmos.cpp
new file mode 100644
index 00000000..b4d58244
--- /dev/null
+++ b/kooka/kocrkadmos.cpp
@@ -0,0 +1,521 @@
+/***************************************************************************
+ kocrstartdia.cpp - description
+ -------------------
+ begin : Fri Now 10 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qfileinfo.h>
+#include <qtooltip.h>
+#include <qvbox.h>
+#include <qdict.h>
+#include <qdir.h>
+#include <qmap.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kanimwidget.h>
+#include <kseparator.h>
+#include <kmessagebox.h>
+
+#include "resource.h"
+#include "ksaneocr.h" // TODO: Really needed?
+#include "kocrkadmos.h"
+#include "kocrkadmos.moc"
+
+#include <kscanslider.h>
+#include <qcheckbox.h>
+#include <kstandarddirs.h>
+#include <qstringlist.h>
+
+
+/* defines for konfig-reading */
+#define CFG_GROUP_KADMOS "Kadmos"
+#define CFG_KADMOS_CLASSIFIER_PATH "classifierPath"
+#define CFG_KADMOS_CLASSIFIER "classifier"
+
+
+#define CNTRY_CZ i18n( "Czech Republic, Slovakia")
+#define CNTRY_GB i18n( "Great Britain, USA" )
+
+KadmosDialog::KadmosDialog( QWidget *parent, KSpellConfig *spellConfig )
+ :KOCRBase( parent, spellConfig, KDialogBase::Tabbed ),
+ m_cbNoise(0),
+ m_cbAutoscale(0),
+ m_haveNorm(false)
+{
+ kdDebug(28000) << "Starting KOCR-Start-Dialog!" << endl;
+ // Layout-Boxes
+ findClassifiers();
+}
+
+QString KadmosDialog::ocrEngineLogo() const
+{
+ return "kadmoslogo.png";
+}
+
+QString KadmosDialog::ocrEngineName() const
+{
+ return i18n("KADMOS OCR/ICR");
+}
+
+QString KadmosDialog::ocrEngineDesc() const
+{
+ return i18n("This version of Kooka was linked with the <I>KADMOS OCR/ICR engine</I>, a "
+ "commercial engine for optical character recognition.<P>"
+ "Kadmos is a product of <B>re Recognition AG</B><BR>"
+ "For more information about Kadmos OCR see "
+ "<A HREF=http://www.rerecognition.com>"
+ "http://www.rerecognition.com</A>");
+}
+
+
+EngineError KadmosDialog::findClassifiers()
+{
+ findClassifierPath();
+
+ KLocale *locale = KGlobal::locale();
+ QStringList allCountries = locale->allLanguagesTwoAlpha ();
+ for ( QStringList::Iterator it = allCountries.begin();
+ it != allCountries.end(); ++it )
+ {
+ m_longCountry2short[locale->twoAlphaToCountryName(*it)] = *it;
+ }
+ m_longCountry2short[i18n("European Countries")] = "eu";
+ m_longCountry2short[ CNTRY_CZ ] = "cz";
+ m_longCountry2short[ CNTRY_GB ] = "us";
+
+ QStringList lst;
+
+ /* custom Path */
+ if( ! m_customClassifierPath.isEmpty() )
+ {
+ QDir dir( m_customClassifierPath );
+
+ QStringList lst1 = dir.entryList( "ttf*.rec" );
+
+ for ( QStringList::Iterator it = lst1.begin(); it != lst1.end(); ++it )
+ {
+ lst << m_customClassifierPath + *it;
+ }
+
+ lst1 = dir.entryList( "hand*.rec" );
+
+ for ( QStringList::Iterator it = lst1.begin(); it != lst1.end(); ++it )
+ {
+ lst << m_customClassifierPath + *it;
+ }
+
+ lst1 = dir.entryList( "norm*.rec" );
+
+ for ( QStringList::Iterator it = lst1.begin(); it != lst1.end(); ++it )
+ {
+ lst << m_customClassifierPath + *it;
+ }
+ }
+ else
+ {
+ /* standard location */
+ KStandardDirs stdDir;
+ kdDebug(28000) << "Starting to read resource" << endl;
+
+ lst = stdDir.findAllResources( "data",
+ "kooka/classifiers/*.rec",
+ true, /* recursive */
+ true ); /* uniqu */
+ }
+
+
+ /* no go through lst and sort out hand-, ttf- and norm classifier */
+ for ( QStringList::Iterator it = lst.begin(); it != lst.end(); ++it )
+ {
+ QFileInfo fi( *it);
+ QString name = fi.fileName().lower();
+
+ kdDebug(28000) << "Checking file " << *it << endl;
+
+ if( name.startsWith( "ttf" ) )
+ {
+ QString lang = name.mid(3,2);
+ if( allCountries.contains(lang) )
+ {
+ QString lngCountry = locale->twoAlphaToCountryName(lang);
+ if( lngCountry.isEmpty() )
+ lngCountry = name;
+ m_ttfClassifier << lngCountry;
+ kdDebug(28000) << "ttf: Insert country " << lngCountry << endl;
+ }
+ else if( lang == "cz" )
+ {
+ m_ttfClassifier << CNTRY_CZ;
+ }
+ else if( lang == "us" )
+ {
+ m_ttfClassifier << CNTRY_GB;
+ }
+ else
+ {
+ m_ttfClassifier << name;
+ kdDebug(28000) << "ttf: Unknown country" << endl;
+ }
+ }
+ else if( name.startsWith( "hand" ) )
+ {
+ QString lang = name.mid(4,2);
+ if( allCountries.contains(lang) )
+ {
+ QString lngCountry = locale->twoAlphaToCountryName(lang);
+ if( lngCountry.isEmpty() )
+ lngCountry = name;
+ m_handClassifier << lngCountry;
+ }
+ else if( lang == "cz" )
+ {
+ m_handClassifier << i18n( "Czech Republic, Slovakia");
+ }
+ else if( lang == "us" )
+ {
+ m_handClassifier << i18n( "Great Britain, USA" );
+ }
+ else
+ {
+ kdDebug(28000) << "Hand: Unknown country " << lang << endl;
+ m_handClassifier << name;
+ }
+ }
+ else if( name.startsWith( "norm" ))
+ {
+ m_haveNorm = true;
+ }
+
+ kdDebug(28000) << "Found classifier: " << *it << endl;
+ m_classifierPath << *it;
+ }
+
+ if( m_handClassifier.count()+m_ttfClassifier.count()>0 )
+ {
+ /* There are classifiers */
+ return ENG_OK;
+ }
+ else
+ {
+ /* Classifier are missing */
+ return ENG_DATA_MISSING;
+ }
+}
+
+
+EngineError KadmosDialog::findClassifierPath()
+{
+ KStandardDirs stdDir;
+ EngineError err = ENG_OK;
+
+ KConfig *conf = KGlobal::config ();
+ KConfigGroupSaver gs( conf, CFG_GROUP_KADMOS );
+
+ m_customClassifierPath = conf->readPathEntry( CFG_KADMOS_CLASSIFIER_PATH );
+#if 0
+ if( m_customClassifierPath == "NotFound" )
+ {
+ /* Wants the classifiers from the standard kde paths */
+ KMessageBox::error(0, i18n("The classifier files for KADMOS could not be found.\n"
+ "OCR with KADMOS will not be possible!\n\n"
+ "Change the OCR engine in the preferences dialog."),
+ i18n("Installation Error") );
+ }
+ else
+ {
+ m_classifierPath = customPath;
+ }
+#endif
+ return err;
+
+}
+
+
+EngineError KadmosDialog::setupGui()
+{
+
+ EngineError err = KOCRBase::setupGui();
+
+ // setupPreprocessing( addVBoxPage( i18n("Preprocessing")));
+ // setupSegmentation( addVBoxPage( i18n("Segmentation")));
+ // setupClassification( addVBoxPage( i18n("Classification")));
+
+ /* continue page setup on the first page */
+ QVBox *page = ocrPage();
+
+ // Horizontal line
+ (void) new KSeparator( KSeparator::HLine, page);
+
+ // FIXME: dynamic classifier reading.
+
+ (void) new QLabel( i18n("Please classify the font type and language of the text on the image:"),
+ page );
+ QHBox *locBox = new QHBox( page );
+ m_bbFont = new QButtonGroup(1, Qt::Horizontal, i18n("Font Type Selection"), locBox);
+
+ m_rbMachine = new QRadioButton( i18n("Machine print"), m_bbFont );
+ m_rbHand = new QRadioButton( i18n("Hand writing"), m_bbFont );
+ m_rbNorm = new QRadioButton( i18n("Norm font"), m_bbFont );
+
+ m_gbLang = new QGroupBox(1, Qt::Horizontal, i18n("Country"), locBox);
+
+
+ m_cbLang = new QComboBox( m_gbLang );
+ m_cbLang->setCurrentText( KLocale::defaultCountry() );
+
+ connect( m_bbFont, SIGNAL(clicked(int)), this, SLOT(slFontChanged(int) ));
+ m_rbMachine->setChecked(true);
+
+ /* --- */
+ QHBox *innerBox = new QHBox( page );
+ innerBox->setSpacing( KDialog::spacingHint());
+
+ QButtonGroup *cbGroup = new QButtonGroup( 1, Qt::Horizontal, i18n("OCR Modifier"), innerBox );
+ Q_CHECK_PTR(cbGroup);
+
+ m_cbNoise = new QCheckBox( i18n( "Enable automatic noise reduction" ), cbGroup );
+ m_cbAutoscale = new QCheckBox( i18n( "Enable automatic scaling"), cbGroup );
+
+ getAnimation(innerBox);
+ // (void) new QWidget ( page );
+
+ if( err != ENG_OK )
+ {
+ enableFields(false);
+ enableButton(User1, false );
+ }
+
+ if( m_ttfClassifier.count() == 0 )
+ {
+ m_rbMachine->setEnabled(false);
+ }
+ if( m_handClassifier.count() == 0 )
+ {
+ m_rbHand->setEnabled(false);
+ }
+ if( !m_haveNorm )
+ m_rbNorm->setEnabled(false);
+
+ if( (m_ttfClassifier.count() + m_handClassifier.count()) == 0 && ! m_haveNorm )
+ {
+ KMessageBox::error(0, i18n("The classifier files for KADMOS could not be found.\n"
+ "OCR with KADMOS will not be possible!\n\n"
+ "Change the OCR engine in the preferences dialog."),
+ i18n("Installation Error") );
+ err = ENG_BAD_SETUP;
+ }
+ else
+ slFontChanged( 0 ); // Load machine print font language list
+ return err;
+}
+
+void KadmosDialog::slFontChanged( int id )
+{
+ m_cbLang->clear();
+
+ KConfig *conf = KGlobal::config ();
+ KConfigGroupSaver gs( conf, CFG_GROUP_KADMOS );
+
+
+
+ m_customClassifierPath = conf->readPathEntry( CFG_KADMOS_CLASSIFIER_PATH );
+
+ bool enable = true;
+
+ if( id == 0 ) /* Machine Print */
+ {
+ m_cbLang->insertStringList( m_ttfClassifier );
+ }
+ else if( id == 1 ) /* Hand Writing */
+ {
+ m_cbLang->insertStringList( m_handClassifier );
+ }
+ else if( id == 2 ) /* Norm Font */
+ {
+ enable = false;
+ }
+ m_cbLang->setEnabled( enable );
+}
+
+
+void KadmosDialog::setupPreprocessing( QVBox* )
+{
+
+}
+
+void KadmosDialog::setupSegmentation( QVBox* )
+{
+
+}
+
+void KadmosDialog::setupClassification( QVBox* )
+{
+
+}
+/*
+ * returns the complete path of the classifier selected in the
+ * GUI in the parameter path. The result value indicates if there
+ * was one found.
+ */
+
+bool KadmosDialog::getSelClassifier( QString& path ) const
+{
+ QString classifier = getSelClassifierName();
+
+ QString cmplPath;
+ /*
+ * Search the complete path for the classifier file name
+ * returned from the getSelClassifierName method
+ */
+ for ( QStringList::ConstIterator it = m_classifierPath.begin();
+ it != m_classifierPath.end(); ++it )
+ {
+ QFileInfo fi( *it );
+ if( fi.fileName() == classifier )
+ {
+ cmplPath = *it;
+ break;
+ }
+ }
+
+ bool res = true;
+
+ if( cmplPath.isEmpty() )
+ {
+ /* hm, no path was found */
+ kdDebug(28000) << "ERR; The entire path is empty, joking?" << endl;
+ res = false;
+ }
+ else
+ {
+ /* Check if the classifier exists on the HD. If not, return an empty string */
+ QFileInfo fi(cmplPath);
+
+ if( res && ! fi.exists() )
+ {
+ kdDebug(28000) << "Classifier file does not exist" << endl;
+ path = i18n("Classifier file %1 does not exist").arg(classifier);
+ res = false;
+ }
+
+ if( res && ! fi.isReadable() )
+ {
+ kdDebug(28000) << "Classifier file could not be read" << endl;
+ path = i18n("Classifier file %1 is not readable").arg(classifier);
+ res = false;
+ }
+
+ if( res )
+ path = cmplPath;
+ }
+ return res;
+}
+
+QString KadmosDialog::getSelClassifierName() const
+{
+ QButton *butt = m_bbFont->selected();
+
+ QString fType, rType;
+
+ if( butt )
+ {
+ int fontTypeID = m_bbFont->id(butt);
+ if( fontTypeID == 0 )
+ fType = "ttf";
+ else if( fontTypeID == 1 )
+ fType = "hand";
+ else if( fontTypeID == 2 )
+ fType = "norm";
+ else
+ kdDebug(28000) << "ERR: Wrong Font Type ID" << endl;
+ }
+
+ /* Get the long text from the combo box */
+ QString selLang = m_cbLang->currentText();
+ QString trans;
+ if( fType != "norm" && m_longCountry2short.contains( selLang ))
+ {
+ QString langType = m_longCountry2short[selLang];
+ trans = fType+langType+".rec";
+ }
+ else
+ {
+ if( selLang.endsWith( ".rec" ))
+ {
+ /* can be a undetected */
+ trans = selLang;
+ }
+ else if( fType == "norm" )
+ {
+ trans = "norm.rec";
+ }
+ else
+ kdDebug(28000) << "ERROR: Not a valid classifier" << endl;
+ }
+ kdDebug(28000) << "Returning trans. "<< trans << endl;
+ return( trans );
+}
+
+bool KadmosDialog::getAutoScale()
+{
+ return( m_cbAutoscale ? m_cbAutoscale->isChecked() : false );
+}
+
+bool KadmosDialog::getNoiseReduction()
+{
+ return( m_cbNoise ? m_cbNoise->isChecked() : false );
+
+}
+
+KadmosDialog::~KadmosDialog()
+{
+
+}
+
+void KadmosDialog::writeConfig( void )
+{
+
+}
+
+
+void KadmosDialog::enableFields( bool state )
+{
+ kdDebug(28000) << "About to disable the entry fields" << endl;
+ m_cbNoise->setEnabled( state );
+ m_cbAutoscale->setEnabled( state );
+
+ m_bbFont->setEnabled( state );
+ m_gbLang->setEnabled( state );
+}
+
+
+/* The End ;) */
+
diff --git a/kooka/kocrkadmos.h b/kooka/kocrkadmos.h
new file mode 100644
index 00000000..38247cc9
--- /dev/null
+++ b/kooka/kocrkadmos.h
@@ -0,0 +1,128 @@
+/***************************************************************************
+ kocrkadmos.h - ocr dialog for KADMOS ocr engine
+ -------------------
+ begin : Sun Jun 11 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+
+#ifndef KOCRKADMOS_H
+#define KOCRKADMOS_H
+
+#include <kdialogbase.h>
+#include <qmap.h>
+
+#include "kocrbase.h"
+/**
+ *@author Klaas Freitag
+ */
+
+
+
+class KScanCombo;
+class QWidget;
+class QButtonGroup;
+class KConfig;
+class QCheckBox;
+class KSpellConfig;
+class QRadioButton;
+
+class KadmosClassifier /* Not yet used FIXME */
+{
+public:
+ KadmosClassifier( QString lang, QString filename );
+ QString getCmplFilename() const { return path+filename; }
+ QString getFilename() const { return filename; }
+ QString language() const { return languagesName; }
+
+ void setPath( const QString& p ) { path=p; }
+private:
+
+ QString filename;
+ QString path;
+ QString languagesName;
+};
+
+
+class KadmosDialog: public KOCRBase
+{
+ Q_OBJECT
+public:
+ KadmosDialog( QWidget *, KSpellConfig *spellConfig );
+ ~KadmosDialog();
+
+ typedef QMap<QString, QString> StrMap;
+
+ EngineError setupGui();
+ bool getAutoScale();
+ bool getNoiseReduction();
+ bool getSelClassifier(QString&) const;
+ QString getSelClassifierName() const;
+
+ QString ocrEngineName() const;
+ QString ocrEngineDesc() const;
+ QString ocrEngineLogo() const;
+
+public slots:
+ void enableFields(bool);
+
+protected:
+ void writeConfig();
+
+ void setupPreprocessing( QVBox *box );
+ void setupSegmentation( QVBox *box );
+ void setupClassification( QVBox *box );
+
+ EngineError findClassifiers();
+ EngineError findClassifierPath();
+private slots:
+
+ void slFontChanged( int id );
+
+private:
+ StrMap m_classifierTranslate;
+
+ QCheckBox *m_cbNoise;
+ QCheckBox *m_cbAutoscale;
+ QString m_customClassifierPath;
+
+ QButtonGroup *m_bbFont;
+
+ QRadioButton *m_rbMachine;
+ QRadioButton *m_rbHand;
+ QRadioButton *m_rbNorm;
+
+ QGroupBox *m_gbLang;
+
+ QComboBox *m_cbLang;
+
+ QStringList m_ttfClassifier;
+ QStringList m_handClassifier;
+ QStringList m_classifierPath;
+
+ bool m_haveNorm;
+
+ typedef QMap<QString, QString> StringMap;
+ StringMap m_longCountry2short;
+};
+
+#endif
diff --git a/kooka/kocrocrad.cpp b/kooka/kocrocrad.cpp
new file mode 100644
index 00000000..1ce94f65
--- /dev/null
+++ b/kooka/kocrocrad.cpp
@@ -0,0 +1,263 @@
+/***************************************************************************
+ kocrocrad.cpp - ocrad dialog
+ -------------------
+ begin : Tue Jul 15 2003
+ copyright : (C) 2003 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qfileinfo.h>
+#include <qtooltip.h>
+#include <qregexp.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kanimwidget.h>
+#include <kseparator.h>
+#include <kmessagebox.h>
+#include <kurlrequester.h>
+#include <kprocess.h>
+
+#include "resource.h"
+#include "kocrocrad.h"
+#include <kscanslider.h>
+#include "kookaimage.h"
+#include "kookapref.h"
+#include <qvbox.h>
+#include <qhbox.h>
+#include <qcombobox.h>
+
+
+
+ocradDialog::ocradDialog( QWidget *parent, KSpellConfig *spellConfig )
+ :KOCRBase( parent, spellConfig, KDialogBase::Tabbed ),
+ m_ocrCmd( QString()),
+ m_orfUrlRequester(0L),
+ m_layoutMode(0),
+ m_binaryLabel(0),
+ m_proc(0),
+ m_version(0)
+{
+ kdDebug(28000) << "Starting ocrad-Start-Dialog!" << endl;
+ // Layout-Boxes
+}
+
+QString ocradDialog::ocrEngineLogo() const
+{
+ return "ocrad.png";
+}
+
+QString ocradDialog::ocrEngineName() const
+{
+ return i18n("ocrad" );
+}
+
+QString ocradDialog::ocrEngineDesc() const
+{
+ return i18n("ocrad is a Free Software project "
+ "for optical character recognition.<p>"
+ "The author of ocrad is <b>Antonio Diaz</b><br>"
+ "For more information about ocrad see "
+ "<A HREF=\"http://www.gnu.org/software/ocrad/ocrad.html\">"
+ "http://www.gnu.org/software/ocrad/ocrad.html</A><p>"
+ "Images should be scanned in black/white mode for ocrad.<br>"
+ "Best results are achieved if the characters are at least 20 pixels high.<p>"
+ "Problems arise, as usual, with very bold or very light or broken characters, "
+ "the same with merged character groups.");
+}
+
+
+int ocradDialog::layoutDetectionMode() const
+{
+ return m_layoutMode->currentItem();
+}
+
+EngineError ocradDialog::setupGui()
+{
+ KOCRBase::setupGui();
+
+ QVBox *page = ocrPage();
+ Q_CHECK_PTR( page );
+
+ KConfig *conf = KGlobal::config ();
+ conf->setGroup( CFG_GROUP_OCR_DIA );
+
+ // Horizontal line
+ // (void) new KSeparator( KSeparator::HLine, page);
+
+ // Entry-Field.
+ QString res = conf->readPathEntry( CFG_OCRAD_BINARY, "notFound" );
+ if( res == "notFound" )
+ {
+ res = KookaPreferences::tryFindBinary("ocrad", CFG_OCRAD_BINARY);
+ if( res.isEmpty() )
+ {
+ /* Popup here telling that the config needs to be called */
+ KMessageBox::sorry( this, i18n( "The path to the ocrad binary is not configured yet.\n"
+ "Please go to the Kooka configuration and enter the path manually."),
+ i18n("OCR Software Not Found") );
+ }
+ }
+
+ if( res.isEmpty() )
+ res = i18n("Not found");
+ else
+ m_ocrCmd = res;
+
+ /** layout detection button **/
+ conf->setGroup( CFG_GROUP_OCRAD );
+ int layoutDetect = conf->readNumEntry( CFG_OCRAD_LAYOUT_DETECTION, 0 );
+ kdDebug(28000) << "Layout detection from config: " << layoutDetect << endl;
+
+ (void) new KSeparator( KSeparator::HLine, page);
+ QHBox *hb1 = new QHBox(page);
+ hb1->setSpacing( KDialog::spacingHint() );
+ (void) new QLabel( i18n("OCRAD layout analysis mode: "), hb1);
+ m_layoutMode = new QComboBox(hb1);
+ m_layoutMode->insertItem(i18n("No Layout Detection"), 0 );
+ m_layoutMode->insertItem(i18n("Column Detection"), 1 );
+ m_layoutMode->insertItem(i18n("Full Layout Detection"), 2);
+ m_layoutMode->setCurrentItem(layoutDetect);
+
+ /** stating the ocrad binary **/
+ (void) new KSeparator( KSeparator::HLine, page);
+ QHBox *hb = new QHBox(page);
+ hb->setSpacing( KDialog::spacingHint());
+
+ m_binaryLabel = new QLabel( i18n("Using ocrad binary: ") + res, hb );
+
+ // retrieve Program version and display
+ version(res);
+
+ getAnimation(hb);
+
+ /* This is for a 'work-in-progress'-Animation */
+
+ return ENG_OK;
+}
+
+void ocradDialog::introduceImage( KookaImage *img )
+{
+ if( !img ) return;
+
+ KOCRBase::introduceImage( img );
+}
+
+
+ocradDialog::~ocradDialog()
+{
+ if( m_proc )
+ delete m_proc;
+}
+
+void ocradDialog::writeConfig( void )
+{
+ KConfig *conf = KGlobal::config ();
+ conf->setGroup( CFG_GROUP_OCR_DIA );
+
+ conf->writeEntry( CFG_OCRAD_BINARY, QString(getOCRCmd()));
+
+ conf->setGroup( CFG_GROUP_OCRAD );
+ conf->writeEntry( CFG_OCRAD_LAYOUT_DETECTION, m_layoutMode->currentItem());
+}
+
+
+void ocradDialog::enableFields(bool )
+{
+ kdDebug(28000) << "About to disable the entry fields" << endl;
+}
+
+/* Later: Allow interactive loading of orf files
+ * for now, return emty string
+ */
+QString ocradDialog::orfUrl() const
+{
+ if( m_orfUrlRequester )
+ return m_orfUrlRequester->url();
+ else
+ return QString();
+}
+
+void ocradDialog::version( const QString& exe )
+{
+ if( m_proc ) delete m_proc;
+
+ m_proc = new KProcess;
+
+ kdDebug(28000) << "Using " << exe << " as command" << endl;
+ *m_proc << exe;
+ *m_proc << QString("-V");
+
+ connect( m_proc, SIGNAL(receivedStdout(KProcess *, char *, int )),
+ this, SLOT(slReceiveStdIn(KProcess *, char *, int )));
+
+ if( ! m_proc->start( KProcess::NotifyOnExit, KProcess::Stdout ) )
+ {
+ slReceiveStdIn( 0, (char*) "unknown", 7 );
+ }
+}
+
+void ocradDialog::slReceiveStdIn( KProcess*, char *buffer, int buflen)
+{
+ QString vstr = QString::fromUtf8(buffer, buflen);
+
+ kdDebug(28000) << "Got input: "<< buffer << endl;
+
+ QRegExp rx;
+ rx.setPattern("GNU Ocrad version ([\\d\\.]+)");
+ if( rx.search( vstr ) > -1 )
+ {
+ QString vStr = rx.cap(1);
+ vStr.remove(0,2);
+
+ m_version = vStr.toInt();
+ QString v = i18n("Version: ") + rx.cap(1);
+
+ if( m_binaryLabel )
+ {
+ m_binaryLabel->setText(m_binaryLabel->text() + "\n" + v );
+ m_binaryLabel->update();
+ }
+ }
+}
+
+/*
+ * returns the numeric version of the ocrad program. It is queried in the slot
+ * slReceiveStdIn, which parses the output of the ocrad -V call.
+ *
+ * Attention: This method returns 10 for ocrad v. 0.10 and 8 for ocrad-0.8
+ */
+int ocradDialog::getNumVersion()
+{
+ return m_version;
+}
+
+#include "kocrocrad.moc"
+
+/* The End ;) */
+
diff --git a/kooka/kocrocrad.h b/kooka/kocrocrad.h
new file mode 100644
index 00000000..d268f403
--- /dev/null
+++ b/kooka/kocrocrad.h
@@ -0,0 +1,106 @@
+/***************************************************************************
+ kocrocrad.h - ocr dialog for ocrad
+ -------------------
+ begin : Tue Jul 15 2003
+ copyright : (C) 2003 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+
+#ifndef KOCROCRAD_H
+#define KOCROCRAD_H
+
+#include <kdialogbase.h>
+#include <qimage.h>
+#include <qstring.h>
+
+#include <kscanslider.h>
+#include <kanimwidget.h>
+
+#include "kocrbase.h"
+
+#define CFG_GROUP_OCRAD "ocrad"
+#define CFG_OCRAD_LAYOUT_DETECTION "layoutDetection"
+#define CFG_OCRAD_EXTRA_ARGUMENTS "extraArguments"
+#define CFG_OCRAD_FORMAT "format"
+#define CFG_OCRAD_CHARSET "charset"
+/**
+ *@author Klaas Freitag
+ */
+
+class KSpellConfig;
+class KURLRequester;
+class KProcess;
+class QLabel;
+class QComboBox;
+
+class ocradDialog: public KOCRBase
+{
+ Q_OBJECT
+public:
+ ocradDialog( QWidget*, KSpellConfig* );
+ ~ocradDialog();
+
+ QString getOCRCmd( void ) const
+ { return m_ocrCmd;}
+
+ EngineError setupGui();
+
+ QString ocrEngineName() const;
+ QString ocrEngineDesc() const;
+ QString ocrEngineLogo() const;
+
+ QString orfUrl() const;
+
+ int layoutDetectionMode() const;
+
+ /**
+ * returns the numeric version of the ocrad program.
+ *
+ * Attention: This method returns 10 for ocrad v. 0.10 and 8 for ocrad-0.8
+ */
+ int getNumVersion();
+
+public slots:
+ void enableFields(bool);
+ void introduceImage( KookaImage* );
+
+protected:
+ void writeConfig();
+
+
+private:
+ void version( const QString& exe );
+
+private slots:
+ void slReceiveStdIn( KProcess *proc, char *buffer, int buflen);
+
+private:
+
+ QString m_ocrCmd;
+ KURLRequester *m_orfUrlRequester;
+ QComboBox *m_layoutMode;
+ QLabel *m_binaryLabel;
+ KProcess *m_proc;
+ int m_version;
+};
+
+#endif
diff --git a/kooka/kooka.cpp b/kooka/kooka.cpp
new file mode 100644
index 00000000..3e3d660d
--- /dev/null
+++ b/kooka/kooka.cpp
@@ -0,0 +1,465 @@
+/**************************************************************************
+ kooka.cpp - Main program class
+ -------------------
+ begin : Sun Jan 16 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+#include "kooka.h"
+#include "kookaview.h"
+#include "resource.h"
+
+#include "kookapref.h"
+#include "imgprintdialog.h"
+
+#include <qlineedit.h>
+#include <qprinter.h>
+#include <qprintdialog.h>
+#include <qpainter.h>
+#include <qpaintdevicemetrics.h>
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <kmenubar.h>
+#include <kaccel.h>
+#include <kio/netaccess.h>
+#include <kfiledialog.h>
+#include <kconfig.h>
+#include <kprinter.h>
+#include <kstatusbar.h>
+#include <kurl.h>
+#include <kurlrequesterdlg.h>
+#include <qstrlist.h>
+#include <kedittoolbar.h>
+#include <kmessagebox.h>
+#include <kdockwidget.h>
+#include <kparts/partmanager.h>
+#include <kstdaccel.h>
+#include <kaction.h>
+#include <kstdaction.h>
+#include <qiconset.h>
+#include <kurldrag.h>
+
+#define DOCK_SIZES "DockSizes"
+
+
+Kooka::Kooka( const QCString& deviceToUse)
+ : KParts::DockMainWindow( 0, "Kooka" ),
+ m_printer(0),
+ m_prefDialogIndex(0)
+{
+ /* Start to create the main view framework */
+ m_view = new KookaView( this, deviceToUse);
+
+ /* Call createGUI on the ocr-result view */
+ setXMLFile( "kookaui.rc", true );
+
+ setAcceptDrops(false); // Waba: Not (yet?) supported
+ KConfig *konf = KGlobal::config ();
+ readDockConfig ( konf, DOCK_SIZES );
+
+ // then, setup our actions
+ setupActions();
+
+ createGUI(0L); // m_view->ocrResultPart());
+ // and a status bar
+ statusBar()->insertItem( QString(), KookaView::StatusTemp );
+ statusBar()->show();
+
+ // allow the view to change the statusbar and caption
+ connect(m_view, SIGNAL(signalChangeStatusbar(const QString&)),
+ this, SLOT(changeStatusbar(const QString&)));
+ connect(m_view, SIGNAL(signalCleanStatusbar(void)),
+ this, SLOT(cleanStatusbar()));
+ connect(m_view, SIGNAL(signalChangeCaption(const QString&)),
+ this, SLOT(changeCaption(const QString&)));
+
+ changeCaption( i18n( "KDE Scanning" ));
+
+ setAutoSaveSettings( QString::fromLatin1("General Options"),
+ true );
+}
+
+void Kooka::createMyGUI( KParts::Part *part )
+{
+ kdDebug(28000) << "Part changed, Creating gui" << endl;
+ createGUI(part);
+
+}
+
+Kooka::~Kooka()
+{
+ KConfig *konf = KGlobal::config ();
+ m_view->slCloseScanDevice();
+ writeDockConfig ( konf, DOCK_SIZES );
+ delete m_printer;
+}
+
+void Kooka::startup( void )
+{
+ kdDebug(29000) << "Starting startup !" << endl;
+ if( m_view ) m_view->loadStartupImage();
+}
+
+
+void Kooka::setupActions()
+{
+
+ KStdAction::print(this, SLOT(filePrint()), actionCollection());
+ KStdAction::quit(this , SLOT(close()), actionCollection());
+
+ KStdAction::keyBindings(guiFactory(), SLOT(configureShortcuts()),
+actionCollection());
+ KStdAction::configureToolbars(this, SLOT(optionsConfigureToolbars()),
+ actionCollection());
+ KStdAction::preferences(this, SLOT(optionsPreferences()), actionCollection());
+
+ m_view->createDockMenu(actionCollection(), this, "settings_show_docks" );
+
+ /* Image Viewer action Toolbar - OCR, Scaling etc. */
+ (void) new KAction(i18n("&OCR Image..."), "ocr", CTRL+Key_O,
+ m_view, SLOT(doOCR()),
+ actionCollection(), "ocrImage" );
+
+ (void) new KAction(i18n("O&CR on Selection..."), "ocr-select", CTRL+Key_C,
+ m_view, SLOT(doOCRonSelection()),
+ actionCollection(), "ocrImageSelect" );
+
+ KAction *act;
+ act = new KAction(i18n("Scale to W&idth"), "scaletowidth", CTRL+Key_I,
+ m_view, SLOT( slIVScaleToWidth()),
+ actionCollection(), "scaleToWidth" );
+ m_view->connectViewerAction( act );
+
+ act = new KAction(i18n("Scale to &Height"), "scaletoheight", CTRL+Key_H,
+ m_view, SLOT( slIVScaleToHeight()),
+ actionCollection(), "scaleToHeight" );
+ m_view->connectViewerAction( act );
+
+ act = new KAction(i18n("Original &Size"), "scaleorig", CTRL+Key_S,
+ m_view, SLOT( slIVScaleOriginal()),
+ actionCollection(), "scaleOriginal" );
+ m_view->connectViewerAction( act );
+
+#ifdef QICONSET_HONOUR_ON_OFF
+ /* The Toggleaction does not seem to handle the on/off icon from QIconSet */
+ QIconSet lockSet;
+ lockSet.setPixmap(BarIcon("lock") , QIconSet::Automatic, QIconSet::Normal, QIconSet::On );
+ lockSet.setPixmap(BarIcon("unlock"), QIconSet::Automatic, QIconSet::Normal, QIconSet::Off);
+ act = new KToggleAction ( i18n("Keep &Zoom Setting"), lockSet, CTRL+Key_Z,
+ actionCollection(), "keepZoom" );
+#else
+ act = new KToggleAction( i18n("Keep &Zoom Setting"), BarIcon("lockzoom"), CTRL+Key_Z,
+ actionCollection(), "keepZoom" );
+#endif
+
+ connect( act, SIGNAL( toggled( bool ) ), m_view->getImageViewer(),
+ SLOT(setKeepZoom(bool)));
+
+ m_view->connectViewerAction( act );
+
+ /* thumbview and gallery actions */
+ act = new KAction(i18n("Set Zoom..."), "viewmag", 0,
+ m_view, SLOT( slIVShowZoomDialog()),
+ actionCollection(), "showZoomDialog" );
+ m_view->connectViewerAction( act );
+
+ (void) new KAction(i18n("Create From Selectio&n"), "crop", CTRL+Key_N,
+ m_view, SLOT( slCreateNewImgFromSelection() ),
+ actionCollection(), "createFromSelection" );
+
+ (void) new KAction(i18n("Mirror Image &Vertically"), "mirror-vert", CTRL+Key_V,
+ this, SLOT( slMirrorVertical() ),
+ actionCollection(), "mirrorVertical" );
+
+ (void) new KAction(i18n("&Mirror Image Horizontally"), "mirror-horiz", CTRL+Key_M,
+ this, SLOT( slMirrorHorizontal() ),
+ actionCollection(), "mirrorHorizontal" );
+
+ (void) new KAction(i18n("Mirror Image &Both Directions"), "mirror-both", CTRL+Key_B,
+ this, SLOT( slMirrorBoth() ),
+ actionCollection(), "mirrorBoth" );
+
+ (void) new KAction(i18n("Open Image in &Graphic Application..."), "fileopen", CTRL+Key_G,
+ m_view, SLOT( slOpenCurrInGraphApp() ),
+ actionCollection(), "openInGraphApp" );
+
+ act = new KAction(i18n("&Rotate Image Clockwise"), "rotate_cw", CTRL+Key_R,
+ this, SLOT( slRotateClockWise() ),
+ actionCollection(), "rotateClockwise" );
+ m_view->connectViewerAction( act );
+
+ act = new KAction(i18n("Rotate Image Counter-Clock&wise"), "rotate_ccw", CTRL+Key_W,
+ this, SLOT( slRotateCounterClockWise() ),
+ actionCollection(), "rotateCounterClockwise" );
+ m_view->connectViewerAction( act );
+
+ act = new KAction(i18n("Rotate Image 180 &Degrees"), "rotate", CTRL+Key_D,
+ this, SLOT( slRotate180() ),
+ actionCollection(), "upsitedown" );
+ m_view->connectViewerAction( act );
+
+ /* Gallery actions */
+ act = new KAction(i18n("&Create Folder..."), "folder_new", 0,
+ m_view->gallery(), SLOT( slotCreateFolder() ),
+ actionCollection(), "foldernew" );
+ m_view->connectGalleryAction( act );
+
+ act = new KAction(i18n("&Save Image..."), "filesave", 0,
+ m_view->gallery(), SLOT( slotExportFile() ),
+ actionCollection(), "saveImage" );
+ m_view->connectGalleryAction( act );
+
+ act = new KAction(i18n("&Import Image..."), "inline_image", 0,
+ m_view->gallery(), SLOT( slotImportFile() ),
+ actionCollection(), "importImage" );
+ m_view->connectGalleryAction( act );
+
+ act = new KAction(i18n("&Delete Image"), "edittrash", 0,
+ m_view->gallery(), SLOT( slotDeleteItems() ),
+ actionCollection(), "deleteImage" );
+ m_view->connectGalleryAction( act );
+
+ act = new KAction(i18n("&Unload Image"), "fileclose", 0,
+ m_view->gallery(), SLOT( slotUnloadItems() ),
+ actionCollection(), "unloadImage" );
+ m_view->connectGalleryAction( act );
+
+#if 0
+ /* not yet supported actions - coming post 3.1 */
+ (void) new KAction(i18n("&Load Scan Parameters"), "bookmark_add", CTRL+Key_L,
+ m_view, SLOT(slLoadScanParams()),
+ actionCollection(), "loadscanparam" );
+
+ (void) new KAction(i18n("Save &Scan Parameters"), "bookmark_add", CTRL+Key_S,
+ m_view, SLOT(slSaveScanParams()),
+ actionCollection(), "savescanparam" );
+#endif
+
+ (void) new KAction(i18n("Select Scan Device"), "scanner", 0,
+ m_view, SLOT( slSelectDevice()),
+ actionCollection(), "selectsource" );
+
+ (void) new KAction( i18n("Enable All Warnings && Messages"), 0,
+ this, SLOT(slEnableWarnings()),
+ actionCollection(), "enable_msgs");
+
+
+ m_saveOCRTextAction = new KAction( i18n("Save OCR Res&ult Text"), "filesaveas", CTRL+Key_U,
+ m_view, SLOT(slSaveOCRResult()),
+ actionCollection(), "saveOCRResult");
+}
+
+
+void Kooka::saveProperties(KConfig *config)
+{
+ // the 'config' object points to the session managed
+ // config file. anything you write here will be available
+ // later when this app is restored
+
+ //if (!m_view->currentURL().isNull())
+ // config->writePathEntry("lastURL", m_view->currentURL());
+ kdDebug(28000) << "In kooka's saveProperties !" << endl;
+ config->setGroup( KOOKA_STATE_GROUP );
+ config->writeEntry( PREFERENCE_DIA_TAB, m_prefDialogIndex );
+ m_view->saveProperties( config );
+}
+
+void Kooka::readProperties(KConfig *config)
+{
+ (void) config;
+ // the 'config' object points to the session managed
+ // config file. this function is automatically called whenever
+ // the app is being restored. read in here whatever you wrote
+ // in 'saveProperties'
+ config->setGroup( KOOKA_STATE_GROUP );
+ m_prefDialogIndex = config->readNumEntry( PREFERENCE_DIA_TAB, 0 );
+ // QString url = config->readPathEntry("lastURL");
+
+}
+
+void Kooka::dragEnterEvent(QDragEnterEvent *event)
+{
+ // accept uri drops only
+ event->accept(KURLDrag::canDecode(event));
+}
+
+#if 0
+void Kooka::dropEvent(QDropEvent *event)
+{
+ // this is a very simplistic implementation of a drop event. we
+ // will only accept a dropped URL. the Qt dnd code can do *much*
+ // much more, so please read the docs there
+ KURL::List uri;
+
+ // see if we can decode a URI.. if not, just ignore it
+ if (KURLDrag::decode(event, uri) && !uri.isEmpty())
+ {
+ // okay, we have a URI.. process it
+ const KURL &url = uri.first();
+ kdDebug(29000) << "Importing URI " << url.url() << endl;
+
+ // TODO: Do something with url
+ // Waba: See also setAcceptDrops() above
+ }
+}
+
+void Kooka::fileNew()
+{
+ // this slot is called whenever the File->New menu is selected,
+ // the New shortcut is pressed (usually CTRL+N) or the New toolbar
+ // button is clicked
+
+ // create a new window
+ (new Kooka)->show();
+}
+
+void Kooka::fileOpen()
+{
+ // this slot is called whenever the File->Open menu is selected,
+ // the Open shortcut is pressed (usually CTRL+O) or the Open toolbar
+ // button is clicked
+}
+
+void Kooka::fileSave()
+{
+ // this slot is called whenever the File->Save menu is selected,
+ // the Save shortcut is pressed (usually CTRL+S) or the Save toolbar
+ // button is clicked
+
+ // save the current file
+}
+
+
+void Kooka::fileSaveAs()
+{
+ // this slot is called whenever the File->Save As menu is selected,
+ QStrList strlist;
+ strlist.append( "BMP" );
+ strlist.append( "JPEG" );
+ FormatDialog fd( 0, "FormatDialog", &strlist );
+ fd.exec();
+
+}
+#endif
+
+void Kooka::filePrint()
+{
+ // this slot is called whenever the File->Print menu is selected,
+ // the Print shortcut is pressed (usually CTRL+P) or the Print toolbar
+ // button is clicked
+ m_view->print();
+
+}
+
+void Kooka::optionsShowScanParams()
+{
+ m_view->slSetScanParamsVisible( m_scanParamsAction->isChecked() );
+}
+
+void Kooka::optionsShowPreviewer()
+{
+ m_view->slSetTabWVisible( m_previewerAction->isChecked());
+}
+
+void Kooka::optionsConfigureToolbars()
+{
+ // use the standard toolbar editor
+ saveMainWindowSettings(KGlobal::config(), autoSaveGroup());
+ KEditToolbar dlg(factory());
+ connect(&dlg, SIGNAL(newToolbarConfig()), SLOT(newToolbarConfig()));
+ dlg.exec();
+}
+
+void Kooka::newToolbarConfig()
+{
+ // OK/Apply pressed in the toolbar editor
+ applyMainWindowSettings(KGlobal::config(), autoSaveGroup());
+}
+
+void Kooka::optionsPreferences()
+{
+ // popup some sort of preference dialog, here
+ KookaPreferences dlg;
+ dlg.showPage( m_prefDialogIndex );
+ connect( &dlg, SIGNAL( dataSaved() ), m_view, SLOT(slFreshUpThumbView()));
+
+ if (dlg.exec())
+ {
+ // redo your settings
+ m_prefDialogIndex = dlg.activePageIndex();
+ // m_view->slFreshUpThumbView();
+ }
+}
+
+void Kooka::changeStatusbar(const QString& text)
+{
+ // display the text on the statusbar
+ statusBar()->changeItem( text, KookaView::StatusTemp );
+}
+
+void Kooka::changeCaption(const QString& text)
+{
+ // display the text on the caption
+ setCaption(text);
+}
+
+void Kooka::slMirrorVertical( void )
+{
+ m_view->slMirrorImage( KookaView::MirrorVertical );
+}
+
+void Kooka::slMirrorHorizontal( void )
+{
+ m_view->slMirrorImage( KookaView::MirrorHorizontal );
+}
+
+void Kooka::slMirrorBoth( void )
+{
+ m_view->slMirrorImage( KookaView::MirrorBoth );
+}
+
+void Kooka::slRotateClockWise( void )
+{
+ m_view->slRotateImage( 90 );
+}
+
+void Kooka::slRotateCounterClockWise( void )
+{
+ m_view->slRotateImage( -90 );
+
+}
+
+void Kooka::slRotate180( void )
+{
+ m_view->slRotateImage( 180 );
+}
+
+void Kooka::slEnableWarnings( )
+{
+ KMessageBox::information (this, i18n("All messages and warnings will now be shown."));
+ KMessageBox::enableAllMessages();
+ kapp->config()->reparseConfiguration();
+}
+
+#include "kooka.moc"
diff --git a/kooka/kooka.desktop b/kooka/kooka.desktop
new file mode 100644
index 00000000..19cd3f35
--- /dev/null
+++ b/kooka/kooka.desktop
@@ -0,0 +1,78 @@
+[Desktop Entry]
+Type=Application
+Exec=kooka %i %m %U
+Icon=scanner
+Path=
+Terminal=false
+DocPath=kooka/index.html
+GenericName=Scan & OCR Program
+GenericName[af]=Skandeer & Optiese karakter herkenning Program
+GenericName[ar]=برنامج للمسح الضوئي
+GenericName[bg]=Сканиране
+GenericName[bs]=Program za skeniranje i OCR
+GenericName[ca]=Programa d'escaneig i OCR
+GenericName[cs]=Program pro skenování a OCR
+GenericName[cy]=Rhaglen Sganio ac OCR
+GenericName[da]=Skanne- & OCR-program
+GenericName[de]=Scan- und OCR-Programm
+GenericName[el]=Πρόγραμμα Σάρωσης & OCR
+GenericName[eo]=Bildbitiga programo kaj tekstrekono
+GenericName[es]=OCR y explorador con un escáner
+GenericName[et]=Skaneerimise ja OMT rakendus
+GenericName[eu]=Eskaneatzeko eta OCR programa
+GenericName[fa]=پویش و برنامۀ OCR
+GenericName[fi]=Skannaus- ja tekstintunnistusohjelma
+GenericName[fr]=Numérisation et reconnaissance de caractères
+GenericName[gl]=Programa para escanear e facer OCR
+GenericName[he]=תוכנית סריקה וזיהוי תווים אופטי
+GenericName[hi]=स्कैन व ऑप्टिकल कैरेक्टर रिकॉग्नीशन प्रोग्राम (OCR)
+GenericName[hr]=Program za skaniranje i OCR
+GenericName[hu]=Lapolvasó
+GenericName[is]=Forrit til að skanna inn myndir
+GenericName[it]=Programma di scansione e OCR
+GenericName[ja]=スキャン & OCR プログラム
+GenericName[kk]=Сканерге түсіру және танып-талдау
+GenericName[km]=កម្មវិធី​ស្កេន & OCR
+GenericName[lt]=Skanavimo ir teksto atpažinimo programa
+GenericName[lv]=Skanēšanas un OCR Programma
+GenericName[ms]=Program Imbas & OCR
+GenericName[nb]=Et skanne-og OCR-program
+GenericName[nds]=Inlees- un OTR-Programm
+GenericName[ne]=स्क्यान र OCR कार्यक्रम
+GenericName[nl]=Scan- en OCR-programma
+GenericName[nn]=Skanne- og tekstattkjenningsprogram
+GenericName[pl]=Program do skanowania i rozpoznawania pisma
+GenericName[pt]=Programa de Digitalização e OCR
+GenericName[pt_BR]=Um programa de Digitalização & OCR
+GenericName[ro]=Scanare imagini şi OCR
+GenericName[ru]=Сканирование и распознавание текста
+GenericName[sk]=Skenovací program s OCR
+GenericName[sl]=Program za skeniranje in prepoznavanje znakov
+GenericName[sr]=Програм за скенирање и препознавање текста
+GenericName[sr@Latn]=Program za skeniranje i prepoznavanje teksta
+GenericName[sv]=Bildläsar- och OCR-program
+GenericName[ta]=வருடு & OCR நிரலி
+GenericName[tg]=Барномаи сканеронӣ ва шиносоии матн
+GenericName[th]=โปรแกรมสแกนภาพและ OCR
+GenericName[tr]=Tarayıcı ve karakter tanıma programı
+GenericName[uk]=Програма сканування та розпізнавання символів
+GenericName[ven]=U nanga & Mbekanyamushumo ya OCR
+GenericName[wa]=Programe di scanaedje eyet di ricnoxhance di tecse
+GenericName[xh]=Udweliso Lwenkqubo Yemita Yovavanyo
+GenericName[zh_CN]=扫描和文字识别程序
+GenericName[zh_HK]=掃描和文字辦識程式
+GenericName[zh_TW]=掃描和文字辦識程式
+GenericName[zu]=Scan & OCR Iprogremu
+Name=Kooka
+Name[ar]=برنامج Kooka
+Name[eo]=Kokao
+Name[hi]=कूका
+Name[is]=Skanni
+Name[ko]=쿠카
+Name[ne]=कोओका
+Name[pa]=ਕੋਕਾ
+Name[ta]=கூக்கா
+Name[zh_TW]=Kooka 掃描器
+
+X-DCOP-ServiceType=Multi
+Categories=Qt;KDE;Graphics;
diff --git a/kooka/kooka.h b/kooka/kooka.h
new file mode 100644
index 00000000..66f59e0c
--- /dev/null
+++ b/kooka/kooka.h
@@ -0,0 +1,141 @@
+/**************************************************************************
+ kooka.h - Main program class
+ -------------------
+ begin : Sun Jan 16 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef KOOKA_H
+#define KOOKA_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kapplication.h>
+#include <kmainwindow.h>
+#include <kdockwidget.h>
+#include <kparts/dockmainwindow.h>
+
+#define KOOKA_STATE_GROUP "State"
+#define PREFERENCE_DIA_TAB "PreferencesTab"
+
+class KPrinter;
+class KToggleAction;
+class KActionMenu;
+class KookaView;
+
+/**
+ * This class serves as the main window for Kooka. It handles the
+ * menus, toolbars, and status bars.
+ *
+ * @short Main window class
+ * @author Klaas Freitag <freitag@suse.de>
+ * @version 0.1
+ */
+class Kooka : public KParts::DockMainWindow
+{
+ Q_OBJECT
+public:
+ /**
+ * Default Constructor
+ */
+ Kooka(const QCString& deviceToUse);
+
+ /**
+ * Default Destructor
+ */
+ ~Kooka();
+
+ /**
+ * Startup, loads (at the moment) only the last displayed image
+ **/
+ void startup( void );
+
+
+protected:
+ /**
+ * Overridden virtuals for Qt drag 'n drop (XDND)
+ */
+ virtual void dragEnterEvent(QDragEnterEvent *event);
+ // virtual void dropEvent(QDropEvent *event);
+
+ /**
+ * This function is called when it is time for the app to save its
+ * properties for session management purposes.
+ */
+ void saveProperties(KConfig *);
+
+ /**
+ * This function is called when this app is restored. The KConfig
+ * object points to the session management config file that was saved
+ * with @ref saveProperties
+ */
+ void readProperties(KConfig *);
+
+
+private slots:
+
+ void createMyGUI( KParts::Part* );
+
+ void filePrint();
+ /* ImageViewer-Actions */
+
+ void optionsShowScanParams();
+ void optionsShowPreviewer();
+ void optionsConfigureToolbars();
+ void optionsPreferences();
+
+ void changeStatusbar(const QString& text);
+ void cleanStatusbar(void) { changeStatusbar(""); }
+ void changeCaption(const QString& text);
+ void newToolbarConfig();
+
+ // void fileSaveAs();
+
+ void slMirrorVertical( void );
+ void slMirrorHorizontal( void );
+ void slMirrorBoth( void );
+
+ void slRotateClockWise( void );
+ void slRotateCounterClockWise( void );
+ void slRotate180( void );
+
+ void slEnableWarnings();
+
+private:
+ void setupAccel();
+ void setupActions();
+
+private:
+ KookaView *m_view;
+
+ KPrinter *m_printer;
+ KToggleAction *m_scanParamsAction;
+ KToggleAction *m_previewerAction;
+ KActionMenu *m_settingsShowDocks;
+
+ KAction *m_saveOCRTextAction;
+ int m_prefDialogIndex;
+};
+
+#endif // KOOKA_H
diff --git a/kooka/kookaiface.h b/kooka/kookaiface.h
new file mode 100644
index 00000000..ab6fcbee
--- /dev/null
+++ b/kooka/kookaiface.h
@@ -0,0 +1,13 @@
+#ifndef KOOKAIFACE_H
+#define KOOKAIFACE_H
+
+#include <dcopobject.h>
+
+class KookaIface : virtual public DCOPObject
+{
+ K_DCOP
+public:
+
+};
+
+#endif // KOOKAIFACE_H
diff --git a/kooka/kookaimage.cpp b/kooka/kookaimage.cpp
new file mode 100644
index 00000000..4db87728
--- /dev/null
+++ b/kooka/kookaimage.cpp
@@ -0,0 +1,413 @@
+/***************************************************************************
+ kookaimage.cpp - Kooka's Image
+ -------------------
+ begin : Thu Nov 20 2001
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include <kdebug.h>
+#include <kurl.h>
+#include <kfileitem.h>
+
+#include "kookaimage.h"
+#include "config.h"
+#ifdef HAVE_LIBTIFF
+#include <tiffio.h>
+#include <tiff.h>
+#endif
+/**
+ *@author Klaas Freitag
+ */
+
+
+KookaImage::KookaImage( )
+ : QImage(),
+ m_subImages(-1),
+ m_subNo(0),
+ m_parent(0),
+ m_fileBound(false),
+ m_tileCols(0)
+{
+
+}
+
+/* constructor for subimages */
+KookaImage::KookaImage( int subNo, KookaImage *p )
+ : QImage(),
+ m_subImages(-1),
+ m_subNo(subNo),
+ m_parent( p ),
+ m_fileItem(0L),
+ m_fileBound(false),
+ m_tileCols(0)
+{
+ kdDebug(28000) << "Setting subimageNo to " << subNo << endl;
+}
+
+KookaImage& KookaImage::operator=(const KookaImage& img)
+{
+ QImage::operator=(img);
+
+ m_subImages = img.subImagesCount();
+ m_subNo = img.m_subNo;
+ m_parent = img.m_parent;
+ m_url = img.m_url;
+ m_fileItem = img.m_fileItem;
+
+ return *this;
+}
+
+KookaImage& KookaImage::operator=(const QImage& img)
+{
+ QImage::operator=(img);
+ return *this;
+}
+
+KFileItem* KookaImage::fileItem() const
+{
+ return m_fileItem;
+}
+
+void KookaImage::setFileItem( KFileItem* it )
+{
+ m_fileItem = it;
+}
+
+const KFileMetaInfo KookaImage::fileMetaInfo( )
+{
+ QString filename = localFileName( );
+ if( ! filename.isEmpty() )
+ {
+ kdDebug(28000) << "Fetching metainfo for " << filename << endl;
+ const KFileMetaInfo info( filename );
+ return info;
+ }
+ else
+ return KFileMetaInfo();
+}
+
+QString KookaImage::localFileName( ) const
+{
+
+ if( ! m_url.isEmpty() )
+ return( m_url.directory() + "/" + m_url.fileName());
+ else
+ return QString();
+}
+
+bool KookaImage::loadFromUrl( const KURL& url )
+{
+ bool ret = true;
+ m_url = url;
+ QString filename = localFileName( );
+ QString format ( imageFormat( filename ));
+
+ /* if the format was not recogniseable, check the extension, if it is tif, try to read it by
+ * tifflib */
+ if( format.isNull() )
+ {
+ if( filename.endsWith( "tif" ) || filename.endsWith( "tiff" ) ||
+ filename.endsWith( "TIF" ) || filename.endsWith( "TIFF" ) )
+ {
+ format = "tif";
+ kdDebug(28000) << "Setting format to tif by extension" << endl;
+ }
+ }
+
+ kdDebug(28000) << "Image format to load: <" << format << "> from file <" << filename << ">" << endl;
+ bool haveTiff = false;
+
+ if( !m_url.isLocalFile() )
+ {
+ kdDebug(28000)<<"ERROR: Can not laod non-local images -> not yet implemented!" << endl;
+ return false;
+ }
+
+#ifdef HAVE_LIBTIFF
+ TIFF* tif = 0;
+ m_subImages = 0;
+
+ if( format == "tif" ||
+ format == "TIF" ||
+ format == "TIFF" ||
+ format == "tiff" )
+ {
+ /* if it is tiff, check with Tifflib if it is multiple sided */
+ kdDebug(28000) << "Trying to load TIFF!" << endl;
+ tif = TIFFOpen(filename.latin1(), "r");
+ if (tif)
+ {
+ do {
+ m_subImages++;
+ } while (TIFFReadDirectory(tif));
+ kdDebug(28000) << m_subImages << " TIFF-directories found" << endl;
+
+ haveTiff = true;
+ }
+ }
+#endif
+ if( !haveTiff )
+ {
+ /* Qt can only read one image */
+ ret = load(filename);
+ if( ret )
+ {
+ m_subImages = 0;
+ m_subNo = 0;
+ }
+ }
+#ifdef HAVE_LIBTIFF
+ else
+ {
+ loadTiffDir( filename, 0);
+ /* its a tiff, read by tifflib directly */
+ // Find the width and height of the image
+ }
+#endif
+
+ m_fileBound = ret;
+ return( ret );
+}
+
+
+KookaImage::KookaImage( const QImage& img )
+ : QImage( img )
+ /* m_subImages( 1 ) */
+{
+ m_subImages = 0;
+
+ /* Load one QImage, can not be Tiff yet. */
+ kdDebug(28000) << "constructor from other image here " << endl;
+}
+
+
+/* loads the number stored in m_subNo */
+void KookaImage::extractNow()
+{
+ kdDebug(28000) << "extracting a subimage number " << m_subNo << endl;
+
+ KookaImage *parent = parentImage();
+
+ if( parent )
+ {
+ loadTiffDir( parent->localFileName(), m_subNo );
+ }
+ else
+ {
+ kdDebug(28000) << "ERR: No parent defined - can not laod subimage" << endl;
+ }
+}
+
+KURL KookaImage::url() const
+{
+ return m_url;
+}
+
+bool KookaImage::loadTiffDir( const QString& filename, int no )
+{
+#ifdef HAVE_LIBTIFF
+ int imgWidth, imgHeight;
+ TIFF* tif = 0;
+ /* if it is tiff, check with Tifflib if it is multiple sided */
+ kdDebug(28000) << "Trying to load TIFF, subimage number "<< no << endl;
+ tif = TIFFOpen(filename.latin1(), "r");
+ if (!tif)
+ return false;
+
+ if( ! TIFFSetDirectory( tif, no ) )
+ {
+ kdDebug(28000) << "ERR: could not set Directory " << no << endl;
+ TIFFClose(tif);
+ return false;
+ }
+
+ TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &imgWidth);
+ TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &imgHeight);
+
+
+ /* TODO: load bw-image correctly only 2 bit */
+ // KookaImage tmpImg;
+ create( imgWidth, imgHeight, 32 );
+ if (TIFFReadRGBAImage(tif, imgWidth, imgHeight, (uint32*) bits(),0))
+ {
+ // successfully read. now convert.
+ // reverse red and blue
+ uint32 *data;
+ data = (uint32 *)bits();
+ for( unsigned i = 0; i < unsigned(imgWidth * imgHeight); ++i )
+ {
+ uint32 red = ( 0x00FF0000 & data[i] ) >> 16;
+ uint32 blue = ( 0x000000FF & data[i] ) << 16;
+ data[i] &= 0xFF00FF00;
+ data[i] += red + blue;
+ }
+
+ // reverse image (it's upside down)
+ unsigned h = unsigned(imgHeight);
+ for( unsigned ctr = 0; ctr < h>>1; )
+ {
+ unsigned *line1 = (unsigned *)scanLine( ctr );
+ unsigned *line2 = (unsigned *)scanLine( imgHeight
+ - ( ++ctr ) );
+
+ unsigned w = unsigned(imgWidth);
+ for( unsigned x = 0; x < w; x++ )
+ {
+ int temp = *line1;
+ *line1 = *line2;
+ *line2 = temp;
+ line1++;
+ line2++;
+ }
+ }
+ }
+
+ /* fetch the x- and y-resolutions to adjust images */
+ float xReso, yReso;
+ bool resosFound;
+ resosFound = TIFFGetField(tif, TIFFTAG_XRESOLUTION, &xReso );
+ resosFound &= TIFFGetField(tif, TIFFTAG_YRESOLUTION, &yReso );
+ kdDebug(28000)<< "Tiff image: X-Resol.: " << xReso << " and Y-Resol.: " << yReso << endl;
+
+ TIFFClose(tif);
+
+ /* Check now if resolution in x- and y-direction differ. If so, stretch the image
+ * accordingly.
+ */
+ if( resosFound && xReso != yReso )
+ {
+ if( xReso > yReso )
+ {
+ float yScalefactor = xReso / yReso;
+ kdDebug(28000) << "Different resolution x/y, rescaling with factor " << yScalefactor << endl;
+ /* rescale the image */
+ *this = smoothScale( imgWidth, int(imgHeight*yScalefactor), QImage::ScaleFree );
+ }
+ else
+ {
+ /* yReso > xReso */
+ float scalefactor = yReso / xReso;
+ kdDebug(28000) << "Different resolution x/y, rescaling x with factor " << scalefactor << endl;
+ /* rescale the image */
+ *this = smoothScale( int(imgWidth*scalefactor), imgHeight, QImage::ScaleFree );
+
+ }
+ }
+
+#endif
+ return true;
+}
+
+
+int KookaImage::subImagesCount() const
+{
+ return( m_subImages );
+}
+
+KookaImage::~KookaImage()
+{
+
+}
+
+KookaImage* KookaImage::parentImage() const
+{
+ return( m_parent );
+}
+
+bool KookaImage::isSubImage() const
+{
+ return( subImagesCount() );
+}
+
+/*
+ * tiling
+ */
+int KookaImage::cutToTiles( const QSize maxSize, int& rows, int& cols, TileMode )
+{
+ QSize imgSize = size();
+
+ int w = imgSize.width();
+ if( w > maxSize.width() )
+ {
+ // image is wider than paper
+ w = maxSize.width();
+ }
+ int h = imgSize.height();
+ if( h > maxSize.height() )
+ {
+ // image is wider than paper
+ h = maxSize.height();
+ }
+
+ int absX = 0; // absolute x position from where to start print
+ int absY = 0; // on the image, left top corner of the part to print
+ rows = 0;
+
+ while( h ) // Loop over height, cut in vertical direction
+ {
+ rows++;
+ cols = 0;
+ while( w ) // Loop over width, cut in horizontal direction
+ {
+ cols++;
+ m_tileVector.append( QRect( absX, absY, w, h ));
+
+ absX += w+1;
+ w = imgSize.width() - absX;
+
+ // if w < 0, this was the last loop, set w to zero to stop loop
+ if( w < 0 ) w = 0;
+
+ // if > 0 here, a new page is required
+ if( w > 0 )
+ {
+ if( w > maxSize.width() ) w = maxSize.width();
+ }
+ }
+ // Reset the X-values to start on the left border again
+ absX = 0;
+ // start with full width again
+ w = imgSize.width();
+ if( w > maxSize.width() )
+ w = maxSize.width();
+
+ absY += h+1;
+ h = imgSize.height() - absY;
+
+ if( h < 0 ) h = 0; // be sure to meet the break condition
+ if( h > maxSize.height()) h = maxSize.height(); // limit to page height
+ }
+ m_tileCols = cols;
+
+ return m_tileVector.count();
+}
+
+
+
+QRect KookaImage::getTileRect( int rowPos, int colPos ) const
+{
+ int indx = rowPos*m_tileCols+colPos;
+ kdDebug(28000) << "Tile Index: " << indx << endl;
+ const QRect r = m_tileVector[(rowPos)*m_tileCols + colPos];
+
+ return r;
+}
diff --git a/kooka/kookaimage.h b/kooka/kookaimage.h
new file mode 100644
index 00000000..84018d4d
--- /dev/null
+++ b/kooka/kookaimage.h
@@ -0,0 +1,170 @@
+/***************************************************************************
+ kookaimage.h - Kooka's Image
+ -------------------
+ begin : Thu Nov 20 2001
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+
+
+#ifndef KOOKAIMAGE_H
+#define KOOKAIMAGE_H
+#include <kurl.h>
+#include <qimage.h>
+#include <qptrlist.h>
+#include <qvaluevector.h>
+#include <qrect.h>
+
+#include <kfilemetainfo.h>
+
+class KFileItem;
+
+/**
+ * @author Klaas Freitag
+ *
+ * class that represents an image, very much as QImage. But this one can contain
+ * multiple pages.
+ */
+
+typedef enum { MaxCut, MediumCut } TileMode;
+
+class KookaImage: public QImage
+{
+public:
+
+ KookaImage( );
+ /**
+ * creating a subimage for a parent image.
+ * @param subNo contains the sequence number of subimages to create.
+ * @param p is the parent image.
+ */
+ KookaImage( int subNo, KookaImage *p );
+ KookaImage( const QImage& img );
+
+ KookaImage& operator=(const KookaImage& );
+ KookaImage& operator=(const QImage& );
+ /**
+ * load an image from a KURL. This method reads the entire file and sets
+ * the values for subimage count.
+ */
+ bool loadFromUrl( const KURL& );
+
+ ~KookaImage();
+
+ /**
+ * the amount of subimages. This is 0 if there are no subimages.
+ */
+ int subImagesCount() const;
+
+ /**
+ * the parent image.
+ */
+ KookaImage* parentImage() const;
+
+ /**
+ * returns true if this is a subimage.
+ */
+ bool isSubImage() const;
+
+ /**
+ * extracts the correct subimage according to the number given in the constructor.
+ */
+ void extractNow();
+
+ KURL url() const;
+ QString localFileName( ) const;
+
+ /**
+ * Set and get the KFileItem of the image. Note that the KFileItem pointer returned
+ * may be zero.
+ */
+ KFileItem* fileItem() const;
+ void setFileItem( KFileItem* );
+
+ /**
+ * @return the KFileMetaInfo
+ **/
+ const KFileMetaInfo fileMetaInfo( );
+
+ /**
+ * set the url of the kooka image. Note that loadFromUrl sets this
+ * url automatically.
+ */
+ void setUrl( const KURL& url )
+ { m_url = url; }
+
+ /**
+ * checks if the image is file bound ie. was loaded from file. If this
+ * method returns false, fileMetaInfo and FileItem are undefined.
+ */
+ bool isFileBound()const { return m_fileBound; }
+
+ /**
+ * Create tiles on the given image. That is just cut the image in parts
+ * while non of the parts is larger than maxSize and store the rect list.
+ * The parameters rows and cols contain the number of rows and cols after
+ * tiling. If both are one, the image is smaller than maxSize, thus the
+ * left-top tile is index 1,1.
+ * Use getTile() to read the QRect list.
+ */
+ int cutToTiles( const QSize maxSize, int& rows, int& cols, TileMode mode = MaxCut );
+
+ /**
+ * read tiles from the tile list. The image needs to be tiled by method
+ * cutToTiles before.
+ */
+ QRect getTileRect( int rowPos, int colPos ) const;
+
+ /**
+ * retrieve the sub number of this image.
+ */
+ int subNumber() const { return m_subNo; }
+
+private:
+ int m_subImages;
+ bool loadTiffDir( const QString&, int );
+
+ /* if subNo is 0, the image is the one and only. If it is larger than 0, the
+ * parent contains the filename */
+ int m_subNo;
+
+ /* In case being a subimage */
+ KookaImage *m_parent;
+ KURL m_url;
+ /* Fileitem if available */
+ KFileItem *m_fileItem;
+ bool m_fileBound;
+
+ QValueVector<QRect> m_tileVector;
+ int m_tileCols; /* number of tile columns */
+};
+
+
+class KookaImageList: public QPtrList<KookaImage>
+{
+public:
+ KookaImageList() {}
+ ~KookaImageList() {}
+};
+
+
+#endif
diff --git a/kooka/kookaimagemeta.cpp b/kooka/kookaimagemeta.cpp
new file mode 100644
index 00000000..7ba1963d
--- /dev/null
+++ b/kooka/kookaimagemeta.cpp
@@ -0,0 +1,51 @@
+/***************************************************************************
+ kookaimage.cpp - Kooka's Image
+ -------------------
+ begin : Thu Nov 20 2001
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include "kookaimagemeta.h"
+
+KookaImageMeta::KookaImageMeta( ) :
+ m_scanResolution(-1),
+ m_scanResolutionY(-1)
+{
+
+}
+
+void KookaImageMeta::setScanResolution( int x, int y)
+{
+ m_scanResolutionY = y;
+ m_scanResolution = x;
+
+}
+
+int KookaImageMeta::getScanResolutionX() const
+{
+ return m_scanResolution;
+}
+
+int KookaImageMeta::getScanResolutionY() const
+{
+ return m_scanResolutionY;
+}
diff --git a/kooka/kookaimagemeta.h b/kooka/kookaimagemeta.h
new file mode 100644
index 00000000..fd269ddd
--- /dev/null
+++ b/kooka/kookaimagemeta.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+ kookaimagemeta.h - Kooka's Image Meta Data
+ -------------------
+ begin : Thu Nov 20 2001
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef KOOKAIMAGEMETA_H
+#define KOOKAIMAGEMETA_H
+
+
+/**
+ * @author Klaas Freitag
+ *
+ */
+
+
+class KookaImageMeta
+{
+public:
+
+ KookaImageMeta( );
+ ~KookaImageMeta() { ;}
+
+ void setScanResolution( int x, int y=-1);
+ int getScanResolutionX() const;
+ int getScanResolutionY() const;
+
+private:
+ int m_scanResolution;
+ int m_scanResolutionY;
+
+};
+
+#endif
diff --git a/kooka/kookapref.cpp b/kooka/kookapref.cpp
new file mode 100644
index 00000000..c5996275
--- /dev/null
+++ b/kooka/kookapref.cpp
@@ -0,0 +1,547 @@
+/***************************************************************************
+ kookapref.cpp - Kookas preferences dialog
+ -------------------
+ begin : Wed Jan 5 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email :
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+
+#include "kookapref.h"
+#include "img_saver.h"
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <knuminput.h>
+#include <kcolorbutton.h>
+#include <kstandarddirs.h>
+
+#include <qlayout.h>
+#include <qtooltip.h>
+#include <qvgroupbox.h>
+#include <qgrid.h>
+#include <qcheckbox.h>
+#include <qstringlist.h>
+
+#include <devselector.h>
+#include "config.h"
+#include "thumbview.h"
+#include "imageselectline.h"
+#include "kscanslider.h"
+#include "ksaneocr.h"
+
+#include <kmessagebox.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+#include <kurlrequester.h>
+
+KookaPreferences::KookaPreferences()
+ : KDialogBase(IconList, i18n("Preferences"),
+ Help|Default|Ok|Apply|Cancel, Ok )
+{
+ // this is the base class for your preferences dialog. it is now
+ // a Treelist dialog.. but there are a number of other
+ // possibilities (including Tab, Swallow, and just Plain)
+ konf = KGlobal::config ();
+
+ setupStartupPage();
+ setupSaveFormatPage();
+ setupThumbnailPage();
+ setupOCRPage();
+}
+
+void KookaPreferences::setupOCRPage()
+{
+ konf->setGroup( CFG_GROUP_OCR_DIA );
+
+ QFrame *page = addPage( i18n("OCR"), i18n("Optical Character Recognition" ),
+ BarIcon("ocrImage", KIcon::SizeMedium ) );
+
+ QVBoxLayout *top = new QVBoxLayout( page, 0, spacingHint() );
+
+ bool haveGocr = false;
+ bool haveOcrad = false;
+ bool haveKadmos = false;
+
+ /*
+ * Switch ocr engines
+ */
+ QButtonGroup *engGroup = new QButtonGroup( 1, Qt::Horizontal, i18n("OCR Engine to Use"), page );
+ m_gocrBut = new QRadioButton( i18n("GOCR engine") , engGroup );
+ m_kadmosBut = new QRadioButton( i18n("KADMOS engine"), engGroup );
+ m_ocradBut = new QRadioButton( i18n("OCRAD engine"), engGroup );
+ m_kadmosBut->setChecked(false);
+ m_gocrBut->setChecked(false);
+ m_ocradBut->setChecked(false);
+ top->addWidget( engGroup );
+
+ /*
+ * GOCR Option Box
+ */
+ QVGroupBox *gp = new QVGroupBox( i18n("GOCR OCR"), page );
+ m_urlReqGocr = binaryCheckBox( gp, "gocr" );
+ connect( m_urlReqGocr, SIGNAL( textChanged( const QString& )),
+ this, SLOT( slCheckOnGOCR( const QString& )));
+ QString cmdGocr = tryFindBinary( "gocr", CFG_GOCR_BINARY );
+ kdDebug(28000) << "Found gocr command: " << cmdGocr << endl;
+ m_gocrBut->setEnabled(false);
+ if( !cmdGocr.isEmpty() )
+ {
+ /* Found the command */
+ m_urlReqGocr->setURL( cmdGocr );
+ m_gocrBut->setEnabled(true);
+ haveGocr = true;
+ }
+ top->addWidget( gp );
+
+ /*
+ * OCRAD Option Box
+ */
+ gp = new QVGroupBox( i18n("OCRAD OCR"), page );
+ m_urlReqOcrad = binaryCheckBox( gp, "ocrad" );
+ connect( m_urlReqOcrad, SIGNAL( textChanged( const QString& )),
+ this, SLOT( slCheckOnOCRAD( const QString& )));
+ QString cmdOcrad = tryFindBinary( "ocrad", CFG_OCRAD_BINARY );
+ kdDebug(28000) << "Found ocrad command: " << cmdOcrad << endl;
+ m_ocradBut->setEnabled(false);
+ if( !cmdOcrad.isEmpty() )
+ {
+ /* Found the command */
+ m_urlReqOcrad->setURL( cmdOcrad );
+ m_ocradBut->setEnabled(true);
+ haveOcrad = true;
+ }
+ top->addWidget( gp );
+
+ /*
+ * Global Kadmos Options
+ */
+ QVGroupBox *kgp = new QVGroupBox( i18n("KADMOS OCR"), page );
+
+#ifdef HAVE_KADMOS
+ (void) new QLabel( i18n("The KADMOS OCR engine is available"), kgp);
+ m_kadmosBut->setChecked(true);
+ m_kadmosBut->setEnabled(true);
+ haveKadmos = true;
+#else
+ (void) new QLabel( i18n("The KADMOS OCR engine is not available in this version of Kooka"), kgp );
+ m_kadmosBut->setEnabled(false);
+#endif
+ top->addWidget( kgp );
+ QWidget *spaceEater = new QWidget( page );
+ spaceEater->setSizePolicy( QSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored ));
+ top->addWidget( spaceEater );
+
+ /*
+ * Now read the config value CFG_OCR_ENGINE and set the radios to the value if available
+ */
+ QString useEngine = konf->readEntry( CFG_OCR_ENGINE, "ocrad" );
+ if( useEngine != "notFound" )
+ {
+ if( useEngine == "gocr" && haveGocr )
+ {
+ m_gocrBut->setChecked(true);
+ m_prevOCREngine = "gocr";
+ }
+ else if( useEngine == "ocrad" && haveOcrad )
+ {
+ m_ocradBut->setChecked(true);
+ m_prevOCREngine = "ocrad";
+ }
+ else if( useEngine == "kadmos" && haveKadmos )
+ {
+ m_kadmosBut->setChecked(true);
+ m_prevOCREngine = "kadmos";
+ }
+ }
+}
+
+KURLRequester* KookaPreferences::binaryCheckBox( QWidget *parent, const QString& program )
+{
+ QHBox *hbox = new QHBox( parent );
+
+ (void) new QLabel( i18n("Select the %1 binary to use:").arg( program ), hbox );
+ KURLRequester* urlRequester = new KURLRequester( parent );
+ urlRequester->setMode( KFile::File | KFile::ExistingOnly | KFile::LocalOnly );
+
+ QToolTip::add( urlRequester,
+ i18n( "Enter the path to %1, the optical-character-recognition "
+ "command line tool.").arg(program));
+ return urlRequester;
+}
+
+
+QString KookaPreferences::tryFindGocr( void )
+{
+ return( tryFindBinary( "gocr", CFG_GOCR_BINARY ) );
+}
+
+QString KookaPreferences::tryFindBinary( const QString& bin, const QString& configKey )
+{
+
+ /* First check the config files for an entry */
+ KConfig *cfg = KGlobal::config();
+ cfg->setGroup(CFG_GROUP_OCR_DIA);
+ QString res = cfg->readPathEntry( configKey /* CFG_GOCR_BINARY */, "notFound" );
+
+ if( res != "notFound" )
+ {
+ QFileInfo fi( res );
+ if( fi.exists() && fi.isExecutable() && !fi.isDir() && res.contains(bin) )
+ {
+ return res;
+ }
+ }
+
+ res = QString();
+
+ QStringList locations;
+ locations.append( "/usr/bin/" + bin );
+ locations.append( "/bin/" + bin );
+ locations.append( "/usr/X11R6/bin/"+bin );
+ locations.append( "/usr/local/bin/"+bin );
+
+ for ( QStringList::Iterator it = locations.begin(); it != locations.end(); ++it )
+ {
+ QString cmd = *it;
+ kdDebug(28000) << "checking command " << cmd << endl;
+ QFileInfo fi( cmd );
+ if( fi.exists() && fi.isExecutable() && !fi.isDir())
+ {
+ res = cmd;
+ kdDebug(28000) << "found command " << res << endl;
+ break;
+ }
+ }
+
+ return( res );
+}
+
+
+void KookaPreferences::slCheckOnGOCR( const QString& cmd )
+{
+ if( checkOCRBinIntern( cmd, "gocr", false ))
+ {
+ // cmd exists and is executable
+ m_gocrBut->setEnabled( true );
+ }
+ else
+ {
+ m_gocrBut->setEnabled( false );
+ }
+}
+
+void KookaPreferences::slCheckOnOCRAD( const QString& cmd )
+{
+ if( checkOCRBinIntern( cmd, "ocrad", false ))
+ {
+ // cmd exists and is executable
+ m_ocradBut->setEnabled( true );
+ }
+ else
+ {
+ m_ocradBut->setEnabled( false );
+ }
+}
+
+#if 0
+void KookaPreferences::checkOCRBinarySilent( const QString& cmd )
+{
+ // checkOCRBinIntern( cmd, this->sender(), false);
+}
+#endif
+bool KookaPreferences::checkOCRBinIntern( const QString& cmd, const QString& tool, bool show_msg )
+{
+ if( ! cmd.contains( tool )) return false;
+
+ bool ret = true;
+ QFileInfo fi( cmd );
+ if( ! fi.exists() )
+ {
+ if( show_msg )
+ KMessageBox::sorry( this, i18n( "The path does not lead to a valid binary.\n"
+ "Please check your installation and/or install the program."),
+ i18n("OCR Software Not Found") );
+ ret = false;
+ }
+ else
+ {
+ /* File exists, check if not dir and executable */
+ if( fi.isDir() || (! fi.isExecutable()) )
+ {
+ if( show_msg )
+ KMessageBox::sorry( this, i18n( "The program exists, but is not executable.\n"
+ "Please check your installation and/or install the binary properly."),
+ i18n("OCR Software Not Executable") );
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+
+
+void KookaPreferences::setupStartupPage()
+{
+
+ /* startup options */
+ konf->setGroup( GROUP_STARTUP );
+
+ QFrame *page = addPage( i18n("Startup"), i18n("Kooka Startup Preferences" ),
+ BarIcon("gear", KIcon::SizeMedium ) );
+ QVBoxLayout *top = new QVBoxLayout( page, 0, spacingHint() );
+ /* Description-Label */
+ top->addWidget( new QLabel( i18n("Note that changing these options will affect Kooka's next start!"), page ));
+
+ /* Query for network scanner (Checkbox) */
+ cbNetQuery = new QCheckBox( i18n("Query network for available scanners"),
+ page, "CB_NET_QUERY" );
+ QToolTip::add( cbNetQuery,
+ i18n( "Check this if you want a network query for available scanners.\nNote that this does not mean a query over the entire network but only the stations configured for SANE!" ));
+ cbNetQuery->setChecked( ! (konf->readBoolEntry( STARTUP_ONLY_LOCAL, false )) );
+
+
+ /* Show scanner selection box on startup (Checkbox) */
+ cbShowScannerSelection = new QCheckBox( i18n("Show the scanner selection box on next startup"),
+ page, "CB_SHOW_SELECTION" );
+ QToolTip::add( cbShowScannerSelection,
+ i18n( "Check this if you once checked 'do not show the scanner selection on startup',\nbut you want to see it again." ));
+
+ cbShowScannerSelection->setChecked( !konf->readBoolEntry( STARTUP_SKIP_ASK, false ));
+
+ /* Read startup image on startup (Checkbox) */
+ cbReadStartupImage = new QCheckBox( i18n("Load the last image into the viewer on startup"),
+ page, "CB_LOAD_ON_START" );
+ QToolTip::add( cbReadStartupImage,
+ i18n( "Check this if you want Kooka to load the last selected image into the viewer on startup.\nIf your images are large, that might slow down Kooka's start." ));
+ cbReadStartupImage->setChecked( konf->readBoolEntry( STARTUP_READ_IMAGE, true));
+
+ /* -- */
+
+ top->addWidget( cbNetQuery );
+ top->addWidget( cbShowScannerSelection );
+ top->addWidget( cbReadStartupImage );
+
+ top->addStretch(10);
+
+}
+
+void KookaPreferences::setupSaveFormatPage( )
+{
+ konf->setGroup( OP_FILE_GROUP );
+ QFrame *page = addPage( i18n("Image Saving"), i18n("Configure Image Save Assistant" ),
+ BarIcon("filesave", KIcon::SizeMedium ) );
+ QVBoxLayout *top = new QVBoxLayout( page, 0, spacingHint() );
+
+ /* Skip the format asking if a format entry exists */
+ cbSkipFormatAsk = new QCheckBox( i18n("Always display image save assistant"),
+ page, "CB_IMGASSIST_QUERY" );
+ cbSkipFormatAsk->setChecked( konf->readBoolEntry( OP_FILE_ASK_FORMAT, true ));
+ QToolTip::add( cbSkipFormatAsk, i18n("Check this if you want to see the image save assistant even if there is a default format for the image type." ));
+ top->addWidget( cbSkipFormatAsk );
+
+ cbFilenameAsk = new QCheckBox( i18n("Ask for filename when saving file"),
+ page, "CB_ASK_FILENAME" );
+ cbFilenameAsk->setChecked( konf->readBoolEntry( OP_ASK_FILENAME, false));
+ QToolTip::add( cbFilenameAsk, i18n("Check this if you want to enter a filename when an image has been scanned." ));
+ top->addWidget( cbFilenameAsk );
+
+
+
+ top->addStretch(10);
+}
+
+void KookaPreferences::setupThumbnailPage()
+{
+ konf->setGroup( THUMB_GROUP );
+
+ QFrame *page = addPage( i18n("Thumbnail View"), i18n("Thumbnail Gallery View" ),
+ BarIcon("thumbnail", KIcon::SizeMedium ) );
+ QVBoxLayout *top = new QVBoxLayout( page, 0, spacingHint() );
+
+ top->addWidget( new QLabel( i18n("Here you can configure the appearance of the thumbnail view of your scan picture gallery."),page ));
+
+ /* Backgroundimage */
+ KStandardDirs stdDir;
+ QString bgImg = konf->readPathEntry( BG_WALLPAPER );
+ if( bgImg.isEmpty() )
+ bgImg = stdDir.findResource( "data", STD_TILE_IMG );
+
+ /* image file selector */
+ QVGroupBox *hgb1 = new QVGroupBox( i18n("Thumbview Background" ), page );
+ m_tileSelector = new ImageSelectLine( hgb1, i18n("Select background image:"));
+ kdDebug(28000) << "Setting tile url " << bgImg << endl;
+ m_tileSelector->setURL( KURL(bgImg) );
+
+ top->addWidget( hgb1 );
+
+ /* Add the Boxes to configure size, framestyle and background */
+ QVGroupBox *hgb2 = new QVGroupBox( i18n("Thumbnail Size" ), page );
+ QVGroupBox *hgb3 = new QVGroupBox( i18n("Thumbnail Frame" ), page );
+
+ /* Thumbnail size */
+ int w = konf->readNumEntry( PIXMAP_WIDTH, 100);
+ int h = konf->readNumEntry( PIXMAP_HEIGHT, 120 );
+ QGrid *lGrid = new QGrid( 2, hgb2 );
+ lGrid->setSpacing( 2 );
+ QLabel *l1 = new QLabel( i18n("Thumbnail maximum &width:"), lGrid );
+ m_thumbWidth = new KIntNumInput( w, lGrid );
+ m_thumbWidth->setMinValue(1);
+ l1->setBuddy( m_thumbWidth );
+
+ lGrid->setSpacing( 4 );
+ l1 = new QLabel( i18n("Thumbnail maximum &height:"), lGrid );
+ m_thumbHeight = new KIntNumInput( m_thumbWidth, h, lGrid );
+ m_thumbHeight->setMinValue(1);
+ l1->setBuddy( m_thumbHeight );
+
+ /* Frame Stuff */
+ int frameWidth = konf->readNumEntry( THUMB_MARGIN, 3 );
+ QColor col1 = konf->readColorEntry( MARGIN_COLOR1, &(colorGroup().base()));
+ QColor col2 = konf->readColorEntry( MARGIN_COLOR2, &(colorGroup().foreground()));
+
+ QGrid *fGrid = new QGrid( 2, hgb3 );
+ fGrid->setSpacing( 2 );
+ l1 = new QLabel(i18n("Thumbnail &frame width:"), fGrid );
+ m_frameWidth = new KIntNumInput( frameWidth, fGrid );
+ m_frameWidth->setMinValue(0);
+ l1->setBuddy( m_frameWidth );
+
+ l1 = new QLabel(i18n("Frame color &1: "), fGrid );
+ m_colButt1 = new KColorButton( col1, fGrid );
+ l1->setBuddy( m_colButt1 );
+
+ l1 = new QLabel(i18n("Frame color &2: "), fGrid );
+ m_colButt2 = new KColorButton( col2, fGrid );
+ l1->setBuddy( m_colButt2 );
+ /* TODO: Gradient type */
+
+ top->addWidget( hgb2, 10);
+ top->addWidget( hgb3, 10);
+ top->addStretch(10);
+
+}
+
+
+void KookaPreferences::slotOk( void )
+{
+ slotApply();
+ accept();
+
+}
+
+
+void KookaPreferences::slotApply( void )
+{
+ /* ** startup options ** */
+
+ /** write the global one, to read from libkscan also */
+ konf->setGroup(QString::fromLatin1(GROUP_STARTUP));
+ bool cbVal = !(cbShowScannerSelection->isChecked());
+ kdDebug(28000) << "Writing for " << STARTUP_SKIP_ASK << ": " << cbVal << endl;
+ konf->writeEntry( STARTUP_SKIP_ASK, cbVal, true, true ); /* global flag goes to kdeglobals */
+
+ /* only search for local (=non-net) scanners ? */
+ konf->writeEntry( STARTUP_ONLY_LOCAL, !cbNetQuery->isChecked(), true, true ); /* global */
+
+ /* Should kooka open the last displayed image in the viewer ? */
+ if( cbReadStartupImage )
+ konf->writeEntry( STARTUP_READ_IMAGE, cbReadStartupImage->isChecked());
+
+ /* ** Image saver option(s) ** */
+ konf->setGroup( OP_FILE_GROUP );
+ bool showFormatAssist = cbSkipFormatAsk->isChecked();
+ konf->writeEntry( OP_FILE_ASK_FORMAT, showFormatAssist );
+ konf->writeEntry( OP_ASK_FILENAME, cbFilenameAsk->isChecked() );
+
+ /* ** Thumbnail options ** */
+ konf->setGroup( THUMB_GROUP );
+ konf->writeEntry( PIXMAP_WIDTH, m_thumbWidth->value() );
+ konf->writeEntry( PIXMAP_HEIGHT, m_thumbHeight->value() );
+ konf->writeEntry( THUMB_MARGIN, m_frameWidth->value() );
+ konf->writeEntry( MARGIN_COLOR1, m_colButt1->color());
+ konf->writeEntry( MARGIN_COLOR2, m_colButt2->color());
+
+ KURL bgUrl = m_tileSelector->selectedURL().url();
+ bgUrl.setProtocol("");
+ kdDebug(28000) << "Writing tile-pixmap " << bgUrl.prettyURL() << endl;
+ konf->writePathEntry( BG_WALLPAPER, bgUrl.url() );
+
+ /* ** OCR Options ** */
+ konf->setGroup( CFG_GROUP_OCR_DIA );
+ QString eng( "gocr" );
+
+ if( m_ocradBut->isChecked() )
+ eng = "ocrad";
+
+ if( m_kadmosBut && m_kadmosBut->isChecked() )
+ eng = "kadmos";
+
+ if( eng != m_prevOCREngine )
+ {
+ // selection of the ocr engine has changed. Popup button.
+ KMessageBox::sorry( this, i18n( "The OCR engine settings were changed.\n"
+ "Note that Kooka needs to be restarted to change the OCR engine."),
+ i18n("OCR Engine Change") );
+ }
+
+ konf->writeEntry(CFG_OCR_ENGINE, eng );
+
+ QString path = m_urlReqGocr->url();
+ if( ! path.isEmpty() )
+ konf->writePathEntry( CFG_GOCR_BINARY, path );
+
+ path = m_urlReqOcrad->url();
+ if( ! path.isEmpty() )
+ konf->writePathEntry( CFG_OCRAD_BINARY, path );
+
+ konf->sync();
+
+ emit dataSaved();
+}
+
+void KookaPreferences::slotDefault( void )
+{
+ cbNetQuery->setChecked( true );
+ cbShowScannerSelection->setChecked( true);
+ cbReadStartupImage->setChecked( true);
+ cbSkipFormatAsk->setChecked( true );
+ KStandardDirs stdDir;
+ QString bgImg = stdDir.findResource( "data", STD_TILE_IMG );
+ m_tileSelector->setURL( KURL(bgImg) );
+ m_thumbWidth->setValue( 100 );
+ m_thumbHeight->setValue( 120 );
+ QColor col1 = QColor( colorGroup().base());
+ QColor col2 = QColor( colorGroup().foreground());
+
+ m_frameWidth->setValue( 3 );
+ m_colButt1->setColor( col1 );
+ m_colButt2->setColor( col2 );
+ m_gocrBut->setChecked(true);
+}
+
+
+
+#include "kookapref.moc"
+
diff --git a/kooka/kookapref.h b/kooka/kookapref.h
new file mode 100644
index 00000000..c5ab34c0
--- /dev/null
+++ b/kooka/kookapref.h
@@ -0,0 +1,100 @@
+/***************************************************************************
+ kookapref.h - Preferences
+ -------------------
+ begin : Sun Jan 16 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+#ifndef KOOKAPREF_H
+#define KOOKAPREF_H
+
+#include <kdialogbase.h>
+#include <qframe.h>
+
+class KConfig;
+class QLabel;
+class KIntNumInput;
+class KColorButton;
+class ImageSelectLine;
+class KScanEntry;
+class QRadioButton;
+class KURLRequester;
+class QCheckBox;
+
+#define STARTUP_READ_IMAGE "ReadImageOnStart"
+#define CFG_GROUP_OCR_DIA "ocrDialog"
+#define CFG_OCRAD_BINARY "ocradBinary"
+#define CFG_GOCR_BINARY "gocrBinary"
+
+class KookaPreferences : public KDialogBase
+{
+ Q_OBJECT
+public:
+ KookaPreferences();
+ static QString tryFindGocr( void );
+ static QString tryFindBinary( const QString&, const QString& );
+
+public slots:
+ void slotOk( void );
+ void slotApply( void );
+ void slotDefault( void );
+
+private slots:
+ bool checkOCRBinIntern( const QString&, const QString&, bool );
+
+ void slCheckOnGOCR( const QString& );
+ void slCheckOnOCRAD( const QString& );
+
+signals:
+ void dataSaved();
+
+private:
+ void setupStartupPage();
+ void setupSaveFormatPage();
+ void setupThumbnailPage();
+ void setupOCRPage();
+ KURLRequester* binaryCheckBox( QWidget *, const QString& );
+
+ QCheckBox *cbNetQuery;
+ QCheckBox *cbSkipFormatAsk;
+ QCheckBox *cbFilenameAsk;
+ QCheckBox *cbShowScannerSelection;
+ KConfig *konf;
+ QCheckBox *cbReadStartupImage;
+
+ KIntNumInput *m_thumbWidth;
+ KIntNumInput *m_thumbHeight;
+ KIntNumInput *m_frameWidth;
+ ImageSelectLine *m_tileSelector;
+ KColorButton *m_colButt1;
+ KColorButton *m_colButt2;
+
+ KURLRequester *m_urlReqGocr;
+ KURLRequester *m_urlReqOcrad;
+
+ QRadioButton *m_gocrBut;
+ QRadioButton *m_kadmosBut;
+ QRadioButton *m_ocradBut;
+ QString m_prevOCREngine;
+};
+
+
+#endif // KOOKAPREF_H
diff --git a/kooka/kookaprint.cpp b/kooka/kookaprint.cpp
new file mode 100644
index 00000000..6e0554e9
--- /dev/null
+++ b/kooka/kookaprint.cpp
@@ -0,0 +1,410 @@
+/***************************************************************************
+ kookaprint.cpp - Printing from the gallery
+ -------------------
+ begin : Tue May 13 2003
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include "kookaprint.h"
+#include "kookaimage.h"
+#include <kprinter.h>
+#include <qpainter.h>
+#include <qpaintdevicemetrics.h>
+#include <qfontmetrics.h>
+#include "imgprintdialog.h"
+#include <kdebug.h>
+#include <klocale.h>
+
+KookaPrint::KookaPrint( KPrinter *printer )
+ :QObject(),
+ m_printer(printer),
+ m_extraMarginPercent(10)
+{
+
+}
+
+bool KookaPrint::printImage( KookaImage *img )
+{
+ bool result = true;
+ if( ! m_printer || !img) return false;
+
+ QString psMode = m_printer->option( OPT_PSGEN_DRAFT );
+ kdDebug(28000) << "User setting for quality: " << psMode << endl;
+
+#if 0
+ if( psMode == "1" )
+ m_printer->setResolution( 75 );
+ else
+ m_printer->setResolution( 600 );
+#endif
+
+ /* Create painter _after_ setting Resolution */
+ QPainter painter(m_printer);
+ m_painter = &painter;
+ KookaImage tmpImg;
+ QPoint pt(0, 0); // the top-left corner (image will be centered)
+
+ // We use a QPaintDeviceMetrics to know the actual page size in pixel,
+ // this gives the real painting area
+ QPaintDeviceMetrics printermetrics( m_painter->device() );
+
+ int screenRes = m_printer->option( OPT_SCREEN_RES ).toInt();
+ // int printerRes = printermetrics.logicalDpiX();
+ int printerRes = m_printer->resolution();
+
+ QString scale = m_printer->option( OPT_SCALING );
+
+ int reso = screenRes;
+
+ if( scale == "scan" )
+ {
+ /* Scale to original size */
+ reso = m_printer->option( OPT_SCAN_RES ).toInt();
+ }
+ else if( scale == "custom" )
+ {
+ // kdDebug(28000) << "Not yet implemented: Custom scale" << endl;
+ double userWidthInch = (m_printer->option( OPT_WIDTH ).toDouble() / 25.4 );
+ reso = int( double(img->width()) / userWidthInch );
+
+ kdDebug(28000) << "Custom resolution: " << reso << endl;
+
+ }
+ else if( scale == "fitpage" )
+ {
+ kdDebug(28000) << "Printing using maximum space on page" << endl;
+ printFittingToPage( img );
+ reso = 0; // to skip the printing on this page.
+ }
+
+ /* Scale the image for printing */
+ kdDebug(28000) << "Printer-Resolution: " << printerRes << " and scale-Reso: " << reso << endl;
+ QSize margins = m_printer->margins();
+ kdDebug(28000) << "Printer-Margins left: " << margins.width() << " and top " << margins.height()
+ << endl;
+ if( reso > 0)
+ {
+ double sizeInch = double(img->width()) / double(reso);
+ int newWidth = int(sizeInch * printerRes);
+
+ printerRes = printermetrics.logicalDpiY();
+ sizeInch = double(img->height()) / double(reso);
+ int newHeight = int(sizeInch * printerRes );
+
+ kdDebug(28000) << "Scaling to printer size " << newWidth << " x " << newHeight << endl;
+
+ tmpImg = img->smoothScale(newWidth, newHeight, QImage::ScaleFree);
+
+ QSize sz = tmpImg.size(); // the current image size
+ QSize maxOnPage = maxPageSize(); // the maximum space on one side
+
+ int maxRows, maxCols;
+ int subpagesCnt = tmpImg.cutToTiles( maxOnPage, maxRows, maxCols );
+
+ kdDebug(28000) << "Subpages count: " << subpagesCnt <<
+ " Columns:" << maxCols << " Rows:" << maxRows << endl;
+
+ int cnt = 0;
+
+ for( int row = 0; row < maxRows; row++ )
+ {
+ for( int col = 0; col < maxCols; col++ )
+ {
+ const QRect part = tmpImg.getTileRect( row, col );
+ const QSize imgSize = part.size();
+
+ kdDebug(28000) << "Printing part from " << part.x() << "/" << part.y()
+ << " width:"<< part.width() << " and height " << part.height() << endl;
+ QImage tileImg = tmpImg.copy( part );
+
+ m_painter->drawImage( printPosTopLeft(imgSize), tileImg );
+ drawCornerMarker( imgSize, row, col, maxRows, maxCols );
+ cnt++;
+ if( cnt < subpagesCnt )
+ m_printer->newPage();
+ }
+ }
+ }
+
+ m_painter = 0; // no, this is not a memory leak.
+ return result;
+}
+
+void KookaPrint::printFittingToPage(KookaImage *img)
+{
+ if( ! img || ! m_painter ) return;
+
+ KookaImage tmpImg;
+
+ QString psMode = m_printer->option( OPT_RATIO );
+ bool maintainAspect = (psMode == "1");
+
+ QSize s = maxPageSize();
+
+ double wAspect = double(s.width()) / double(img->width());
+ double hAspect = double(s.height()) / double(img->height());
+
+ // take the smaller one.
+ double aspect = wAspect;
+ if( hAspect < wAspect ) aspect = hAspect;
+
+ // default: maintain aspect ratio.
+ int newWidth = int( double( img->width() ) * aspect );
+ int newHeight = int( double( img->height()) * aspect );
+
+ if( ! maintainAspect )
+ {
+ newWidth = int( double( img->width() ) * wAspect );
+ newHeight = int( double( img->height() ) * hAspect );
+ }
+
+ tmpImg = img->smoothScale(newWidth, newHeight, QImage::ScaleFree);
+
+ m_painter->drawImage( 0,0, tmpImg );
+
+}
+
+
+void KookaPrint::drawMarkerAroundPoint( const QPoint& p )
+{
+ if( ! m_painter ) return;
+ const int len = 10;
+
+ m_painter->drawLine( p-QPoint(len,0), p+QPoint(len,0));
+ m_painter->drawLine( p-QPoint(0,len), p+QPoint(0,len));
+
+}
+
+
+void KookaPrint::drawCutSign( const QPoint& p, int num, MarkerDirection dir )
+{
+ QBrush saveB = m_painter->brush();
+ int start = 0;
+ const int radius=20;
+
+ QColor brushColor( Qt::red );
+ int toffX=0;
+ int toffY=0;
+ QString numStr = QString::number(num);
+
+ QFontMetrics fm = m_painter->fontMetrics();
+ int textWidth = fm.width( numStr )/2;
+ int textHeight = fm.width( numStr )/2;
+ int textYOff = 0;
+ int textXOff = 0;
+ switch( dir )
+ {
+ case SW:
+ start = -90;
+ brushColor = Qt::green;
+ toffX =-1;
+ toffY = 1;
+ textXOff = -1*textWidth;
+ textYOff = textHeight;
+ break;
+ case NW:
+ start = -180;
+ brushColor = Qt::blue;
+ toffX =-1;
+ toffY =-1;
+ textXOff = -1*textWidth;
+ textYOff = textHeight;
+ break;
+ case NO:
+ start = -270;
+ brushColor = Qt::yellow;
+ toffX = 1;
+ toffY = -1;
+ textXOff = -1*textWidth;
+ textYOff = textHeight;
+
+ break;
+ case SO:
+ start = 0;
+ brushColor = Qt::magenta;
+ toffX = 1;
+ toffY = 1;
+ textXOff = -1*textWidth;
+ textYOff = textHeight;
+ break;
+ default:
+ start = 0;
+ }
+
+ /* to draw around the point p, subtraction of the half radius is needed */
+ int x = p.x()-radius/2;
+ int y = p.y()-radius/2;
+
+ // m_painter->drawRect( x, y, radius, radius ); /* debug !!! */
+ const int tAway = radius*3/4;
+
+ QRect bRect = fm.boundingRect( QString::number(num));
+ int textX = p.x()+ tAway * toffX + textXOff;
+ int textY = p.y()+ tAway * toffY + textYOff;
+
+ // m_painter->drawRect( textX, textY, bRect.width(), bRect.height() );
+ kdDebug(28000) << "Drawing to position " << textX << "/" << textY << endl;
+ m_painter->drawText( textX,
+ textY,
+ QString::number(num));
+ QBrush b( brushColor, NoBrush /* remove this to get debug color*/ );
+
+
+ m_painter->setBrush( b );
+ m_painter->drawPie( x, y, radius, radius, 16*start, -16*90 );
+
+ m_painter->setBrush( saveB );
+}
+
+
+/*
+ * draws the circle and the numbers that indicate the pages to glue to the side
+ */
+void KookaPrint::drawCornerMarker( const QSize& imgSize, int row, int col, int maxRows, int maxCols )
+{
+ QPoint p;
+
+ kdDebug(28000) << "Marker: Row: " << row << " and col " << col <<" from max "
+ << maxRows << "x" << maxCols << endl;
+
+ // Top left.
+ p = printPosTopLeft( imgSize );
+ drawMarkerAroundPoint( p );
+ int indx = maxCols*row+col+1;
+ if( maxRows > 1 || maxCols > 1 )
+ {
+ if( col > 0 )
+ drawCutSign( p, indx-1, SW );
+ if( row > 0 )
+ drawCutSign( p, indx-maxCols, NO );
+
+ if( row > 0 && col > 0 )
+ drawCutSign( p, indx-maxCols-1, NW );
+ }
+
+ // Top Right
+ p = printPosTopRight( imgSize );
+ drawMarkerAroundPoint( p );
+ if( maxRows > 1 || maxCols > 1 )
+ {
+ if( col < maxCols-1 )
+ drawCutSign( p, indx+1, SO );
+ if( row > 0 )
+ drawCutSign( p, indx-maxCols, NW );
+ if( row > 0 && col < maxCols-1 )
+ drawCutSign( p, indx-maxCols+1, NO );
+ }
+
+ // Bottom Right
+ p = printPosBottomRight( imgSize );
+ if( maxRows > 1 || maxCols > 1 )
+ {
+ if( col < maxCols-1 )
+ drawCutSign( p, indx+1, NO );
+ if( row < maxRows-1 )
+ drawCutSign( p, indx+maxCols, SW );
+ if( row < maxRows -1 && col < maxCols-1 )
+ drawCutSign( p, indx+maxCols, SO );
+ }
+
+ // p += QPoint( 1, 1 );
+ drawMarkerAroundPoint( p ); /* at bottom right */
+
+ /* Bottom left */
+ p = printPosBottomLeft( imgSize );
+ // p += QPoint( -1, 1 );
+ if( maxRows > 1 || maxCols > 1 )
+ {
+ if( col > 0 )
+ drawCutSign( p, indx-1, NW );
+ if( row < maxRows-1 )
+ drawCutSign( p, indx+maxCols, SO );
+ if( row < maxRows -1 && col > 0 )
+ drawCutSign( p, indx+maxCols-1, SW );
+ }
+ drawMarkerAroundPoint( p ); /* at bottom left */
+}
+
+QSize KookaPrint::maxPageSize( int extraShrinkPercent ) const
+{
+ if( ! m_painter ) return QSize();
+ QPaintDeviceMetrics printermetrics( m_painter->device() );
+
+ double extraShrink = double(100-extraShrinkPercent)/100.0;
+
+ QSize retSize( printermetrics.width(), printermetrics.height() );
+
+ if( extraShrinkPercent > 0 )
+ retSize = QSize( int(double(printermetrics.width())* extraShrink) ,
+ int(double(printermetrics.height())* extraShrink ));
+ return retSize;
+}
+
+int KookaPrint::extraMarginPix() const
+{
+ QSize max = maxPageSize();
+ /* take the half extra margin */
+ return int(double(max.width())*double(m_extraMarginPercent) / 100.0 / 2.0);
+}
+
+QPoint KookaPrint::printPosTopLeft( const QSize& imgSize ) const
+{
+ QSize max = maxPageSize();
+ /* take the half extra margin */
+ int eMargin = extraMarginPix();
+
+ return QPoint( eMargin + (max.width() - imgSize.width())/2,
+ eMargin + (max.height() - imgSize.height())/2 );
+}
+
+QPoint KookaPrint::printPosTopRight(const QSize& imgSize) const
+{
+ QSize max = maxPageSize();
+ /* take the half extra margin */
+ int eMargin = extraMarginPix();
+
+ return QPoint( eMargin + (max.width() - imgSize.width())/2+imgSize.width(),
+ eMargin + (max.height() - imgSize.height())/2 );
+}
+
+QPoint KookaPrint::printPosBottomLeft(const QSize& imgSize) const
+{
+ QSize max = maxPageSize();
+ int eMargin = extraMarginPix();
+ /* take the half extra margin */
+ return QPoint( eMargin+(max.width() - imgSize.width())/2,
+ eMargin+(max.height() - imgSize.height())/2 + imgSize.height() );
+}
+
+QPoint KookaPrint::printPosBottomRight(const QSize& imgSize) const
+{
+ QSize max = maxPageSize();
+ /* take the half extra margin */
+ int eMargin = extraMarginPix();
+
+ return QPoint( eMargin+(max.width() - imgSize.width())/2 + imgSize.width(),
+ eMargin+(max.height() - imgSize.height())/2 + imgSize.height() );
+}
+
+
+
+#include "kookaprint.moc"
diff --git a/kooka/kookaprint.h b/kooka/kookaprint.h
new file mode 100644
index 00000000..5f87d973
--- /dev/null
+++ b/kooka/kookaprint.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+ kookaprint.h - Printing from the gallery
+ -------------------
+ begin : Tue May 13 2003
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef __KOOKA_PRINT_H__
+#define __KOOKA_PRINT_H__
+
+#include <qobject.h>
+#include <qmap.h>
+#include <qstring.h>
+#include <kprinter.h>
+#include <kdeprint/kprintdialogpage.h>
+
+class KookaImage;
+class KPrinter;
+class QPainter;
+class KLineEdit;
+
+
+class ImageSettings : public KPrintDialogPage
+{
+public:
+ void setOptions( const QMap<QString, QString>& opts );
+ void getOptions( QMap<QString, QString>& opts, bool include_def = false );
+ bool isValid( QString& msg );
+
+private:
+ KLineEdit *m_width, *m_height;
+
+};
+
+
+class KookaPrint:public QObject
+{
+ Q_OBJECT
+public:
+ KookaPrint(KPrinter*);
+
+ /**
+ * The top left edge of the required print position
+ */
+ virtual QPoint printPosTopLeft(const QSize&) const;
+ virtual QPoint printPosTopRight(const QSize&) const;
+ virtual QPoint printPosBottomLeft(const QSize&) const;
+ virtual QPoint printPosBottomRight(const QSize&) const;
+
+ virtual int extraMarginPix() const;
+
+ /**
+ * The maximum pixel size of the image (or imagepart) on
+ * the current page
+ */
+ virtual QSize maxPageSize( int extraShrinkPercent = 0 ) const;
+
+public slots:
+
+ bool printImage( KookaImage* );
+ void printFittingToPage(KookaImage *img);
+protected:
+ typedef enum { SW, NW, NO, SO } MarkerDirection;
+
+ virtual void drawMarkerAroundPoint( const QPoint& );
+ virtual void drawCutSign( const QPoint&, int, MarkerDirection );
+ virtual void drawCornerMarker( const QSize&, int, int, int, int );
+
+private:
+
+ KPrinter *m_printer;
+ QPainter *m_painter;
+ int m_extraMarginPercent;
+};
+
+#endif
diff --git a/kooka/kookarc b/kooka/kookarc
new file mode 100644
index 00000000..13875fff
--- /dev/null
+++ b/kooka/kookarc
@@ -0,0 +1,121 @@
+[DockSizes]
+Kookas MainDock,Preview ,Thumbs:first_name=Kookas MainDock,Preview\s
+Kookas MainDock,Preview ,Thumbs:last_name=Thumbs
+Kookas MainDock,Preview ,Thumbs:orientation=0
+Kookas MainDock,Preview ,Thumbs:parent=yes
+Kookas MainDock,Preview ,Thumbs:sepPos=72
+Kookas MainDock,Preview ,Thumbs:stayButton=false
+Kookas MainDock,Preview ,Thumbs:type=GROUP
+Kookas MainDock,Preview :curTab=0
+Kookas MainDock,Preview :parent=yes
+Kookas MainDock,Preview :stayButton=false
+Kookas MainDock,Preview :tabNames=Kookas MainDock,Preview\s
+Kookas MainDock,Preview :type=TAB_GROUP
+Kookas MainDock,Thumbs,Preview :curTab=1
+Kookas MainDock,Thumbs,Preview :parent=yes
+Kookas MainDock,Thumbs,Preview :stayButton=false
+Kookas MainDock,Thumbs,Preview :tabNames=Kookas MainDock,Thumbs,Preview\s
+Kookas MainDock,Thumbs,Preview :type=TAB_GROUP
+Kookas MainDock,Thumbs:curTab=1
+Kookas MainDock,Thumbs:first_name=Kookas MainDock
+Kookas MainDock,Thumbs:last_name=Thumbs
+Kookas MainDock,Thumbs:orientation=0
+Kookas MainDock,Thumbs:parent=yes
+Kookas MainDock,Thumbs:sepPos=54
+Kookas MainDock,Thumbs:stayButton=false
+Kookas MainDock,Thumbs:tabNames=Kookas MainDock,Thumbs
+Kookas MainDock,Thumbs:type=TAB_GROUP
+Kookas MainDock:stayButton=false
+Kookas MainDock:type=DOCK
+Main:Geometry=40,60,980,760
+Main:dock=Kookas MainDock
+Main:view=Scanpackager,Recent,Scan Parameter,Kookas MainDock,Preview ,Thumbs
+Main:visible=false
+NameList=Kookas MainDock,Thumbs,Scanpackager,Recent,Scan Parameter,Preview ,Kookas MainDock\\,Preview ,Kookas MainDock\\,Preview \\,Thumbs,Recent\\,Scan Parameter,Scanpackager\\,Recent\\,Scan Parameter,Scanpackager\\,Recent\\,Scan Parameter\\,Kookas MainDock\\,Preview \\,Thumbs
+Preview ,Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs:first_name=Preview ,Scanpackager,Recent,Scan Parameter
+Preview ,Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs:last_name=Kookas MainDock,Thumbs
+Preview ,Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs:orientation=1
+Preview ,Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs:parent=yes
+Preview ,Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs:sepPos=38
+Preview ,Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs:stayButton=false
+Preview ,Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs:type=GROUP
+Preview ,Scanpackager,Recent,Scan Parameter:first_name=Preview ,Scanpackager,Recent
+Preview ,Scanpackager,Recent,Scan Parameter:last_name=Scan Parameter
+Preview ,Scanpackager,Recent,Scan Parameter:orientation=0
+Preview ,Scanpackager,Recent,Scan Parameter:parent=yes
+Preview ,Scanpackager,Recent,Scan Parameter:sepPos=50
+Preview ,Scanpackager,Recent,Scan Parameter:stayButton=false
+Preview ,Scanpackager,Recent,Scan Parameter:type=GROUP
+Preview ,Scanpackager,Recent:first_name=Preview ,Scanpackager
+Preview ,Scanpackager,Recent:last_name=Recent
+Preview ,Scanpackager,Recent:orientation=0
+Preview ,Scanpackager,Recent:parent=yes
+Preview ,Scanpackager,Recent:sepPos=84
+Preview ,Scanpackager,Recent:stayButton=false
+Preview ,Scanpackager,Recent:type=GROUP
+Preview ,Scanpackager:first_name=Preview\s
+Preview ,Scanpackager:last_name=Scanpackager
+Preview ,Scanpackager:orientation=0
+Preview ,Scanpackager:parent=yes
+Preview ,Scanpackager:sepPos=50
+Preview ,Scanpackager:stayButton=false
+Preview ,Scanpackager:type=GROUP
+Preview :stayButton=false
+Preview :type=DOCK
+Recent,Scan Parameter:first_name=Recent
+Recent,Scan Parameter:last_name=Scan Parameter
+Recent,Scan Parameter:orientation=0
+Recent,Scan Parameter:parent=yes
+Recent,Scan Parameter:sepPos=14
+Recent,Scan Parameter:stayButton=false
+Recent,Scan Parameter:type=GROUP
+Recent:stayButton=false
+Recent:type=DOCK
+Scan Parameter:stayButton=false
+Scan Parameter:type=DOCK
+Scanpackager,Preview ,Recent,Scan Parameter,Kookas MainDock,Thumbs:first_name=Scanpackager,Preview ,Recent,Scan Parameter
+Scanpackager,Preview ,Recent,Scan Parameter,Kookas MainDock,Thumbs:last_name=Kookas MainDock,Thumbs
+Scanpackager,Preview ,Recent,Scan Parameter,Kookas MainDock,Thumbs:orientation=1
+Scanpackager,Preview ,Recent,Scan Parameter,Kookas MainDock,Thumbs:parent=yes
+Scanpackager,Preview ,Recent,Scan Parameter,Kookas MainDock,Thumbs:sepPos=38
+Scanpackager,Preview ,Recent,Scan Parameter,Kookas MainDock,Thumbs:stayButton=false
+Scanpackager,Preview ,Recent,Scan Parameter,Kookas MainDock,Thumbs:type=GROUP
+Scanpackager,Preview ,Recent,Scan Parameter:first_name=Scanpackager,Preview\s
+Scanpackager,Preview ,Recent,Scan Parameter:last_name=Recent,Scan Parameter
+Scanpackager,Preview ,Recent,Scan Parameter:orientation=0
+Scanpackager,Preview ,Recent,Scan Parameter:parent=yes
+Scanpackager,Preview ,Recent,Scan Parameter:sepPos=48
+Scanpackager,Preview ,Recent,Scan Parameter:stayButton=false
+Scanpackager,Preview ,Recent,Scan Parameter:type=GROUP
+Scanpackager,Preview :curTab=0
+Scanpackager,Preview :parent=yes
+Scanpackager,Preview :stayButton=false
+Scanpackager,Preview :tabNames=Scanpackager,Preview\s
+Scanpackager,Preview :type=TAB_GROUP
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Preview ,Thumbs:first_name=Scanpackager,Recent,Scan Parameter
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Preview ,Thumbs:last_name=Kookas MainDock,Preview ,Thumbs
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Preview ,Thumbs:orientation=1
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Preview ,Thumbs:parent=yes
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Preview ,Thumbs:sepPos=41
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Preview ,Thumbs:stayButton=false
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Preview ,Thumbs:type=GROUP
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs,Preview :first_name=Scanpackager,Recent,Scan Parameter
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs,Preview :last_name=Kookas MainDock,Thumbs,Preview\s
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs,Preview :orientation=1
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs,Preview :parent=yes
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs,Preview :sepPos=38
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs,Preview :stayButton=false
+Scanpackager,Recent,Scan Parameter,Kookas MainDock,Thumbs,Preview :type=GROUP
+Scanpackager,Recent,Scan Parameter:first_name=Scanpackager
+Scanpackager,Recent,Scan Parameter:last_name=Recent,Scan Parameter
+Scanpackager,Recent,Scan Parameter:orientation=0
+Scanpackager,Recent,Scan Parameter:parent=yes
+Scanpackager,Recent,Scan Parameter:sepPos=42
+Scanpackager,Recent,Scan Parameter:stayButton=false
+Scanpackager,Recent,Scan Parameter:type=GROUP
+Scanpackager:stayButton=false
+Scanpackager:type=DOCK
+Thumbs:stayButton=false
+Thumbs:type=DOCK
+Version=0.0.5
+
diff --git a/kooka/kookaui.rc b/kooka/kookaui.rc
new file mode 100644
index 00000000..77d3cf4e
--- /dev/null
+++ b/kooka/kookaui.rc
@@ -0,0 +1,62 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="Kooka" version="3">
+<MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="foldernew"/>
+ <Action name="saveImage"/>
+ <Action name="importImage"/>
+ <Action name="deleteImage"/>
+ <Action name="unloadImage"/>
+ <Action name="saveOCRResult"/>
+ </Menu>
+ <Menu name="imgCanvas"><text>&amp;Image</text>
+ <Action name="openInGraphApp"/>
+ <Separator/>
+ <Action name="ocrImage"/>
+ <Action name="ocrImageSelect"/>
+ <Separator/>
+ <Action name="scaleToWidth"/>
+ <Action name="scaleToHeight"/>
+ <Action name="scaleOriginal"/>
+ <Separator/>
+ <Action name="createFromSelection"/>
+ <Separator/>
+ <Action name="mirrorVertical"/>
+ <Action name="mirrorHorizontal"/>
+ <Action name="mirrorBoth"/>
+ <Separator/>
+ <Action name="rotateClockwise"/>
+ <Action name="rotateCounterClockwise"/>
+ <Action name="upsitedown"/>
+ </Menu>
+ <Menu name="settings"><text>&amp;Settings</text>
+ <Action name="settings_show_docks" append="show_merge"/>
+ <Action name="enable_msgs" append="save_merge"/>
+ <Separator append="save_merge"/>
+ <Action name="selectsource" append="save_merge"/>
+ <Separator append="save_merge"/>
+ <Action name="loadscanparam" append="save_merge"/>
+ <Action name="savescanparam" append="save_merge"/>
+ </Menu>
+</MenuBar>
+ <ToolBar name="mainToolBar" fullWidth="true">
+ <text>Image Viewer Toolbar</text>
+ <Action name="ocrImage"/>
+ <Action name="ocrImageSelect"/>
+ <Separator/>
+ <Action name="scaleToWidth"/>
+ <Action name="scaleToHeight"/>
+ <Action name="scaleOriginal"/>
+ <Action name="keepZoom"/>
+ <Separator/>
+ <Action name="createFromSelection"/>
+ <Separator/>
+ <Action name="mirrorVertical"/>
+ <Action name="mirrorHorizontal"/>
+ <Action name="mirrorBoth"/>
+ <Separator/>
+ <Action name="rotateClockwise"/>
+ <Action name="rotateCounterClockwise"/>
+ <Action name="upsitedown"/>
+ </ToolBar>
+</kpartgui>
diff --git a/kooka/kookaview.cpp b/kooka/kookaview.cpp
new file mode 100644
index 00000000..f1c1d8d0
--- /dev/null
+++ b/kooka/kookaview.cpp
@@ -0,0 +1,1083 @@
+/***************************************************************************
+ kookaview.cpp - kookas visible stuff
+ -------------------
+ begin : ?
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+
+ $Id$
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include "kookaview.h"
+#include "resource.h"
+#include "kscandevice.h"
+#include "imgscaninfo.h"
+#include "devselector.h"
+#include "ksaneocr.h"
+#include "img_saver.h"
+#include "kookapref.h"
+#include "imgnamecombo.h"
+#include "thumbview.h"
+#include "dwmenuaction.h"
+#include "kookaimage.h"
+#include "kookaimagemeta.h"
+#include "ocrresedit.h"
+#include "kookaprint.h"
+#include "imgprintdialog.h"
+#if 0
+#include "paramsetdialogs.h"
+#endif
+#include <qlabel.h>
+#include <qpainter.h>
+#include <qlayout.h>
+#include <qsplitter.h>
+#include <qstrlist.h>
+#include <qpaintdevice.h>
+#include <qpaintdevicemetrics.h>
+#include <qpopupmenu.h>
+#include <qwidgetstack.h>
+
+#include <kurl.h>
+#include <krun.h>
+#include <kapplication.h>
+#include <kstatusbar.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <ktrader.h>
+#include <klibloader.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <keditcl.h>
+#include <kled.h>
+#include <kcombobox.h>
+#include <kaction.h>
+#include <kiconloader.h>
+#include <kshortcut.h>
+#include <kdockwidget.h>
+#include <qobject.h>
+
+#include <kparts/componentfactory.h>
+#include <qimage.h>
+#include <kpopupmenu.h>
+
+
+#define STARTUP_IMG_SELECTION "SelectedImageOnStartup"
+
+
+KookaView::KookaView( KParts::DockMainWindow *parent, const QCString& deviceToUse)
+ : QObject(),
+ m_ocrResultImg(0),
+ ocrFabric(0),
+ m_mainDock(0),
+ m_dockScanParam(0),
+ m_dockThumbs(0),
+ m_dockPackager(0),
+ m_dockRecent(0),
+ m_dockPreview(0),
+ m_dockOCRText(0),
+ m_mainWindow(parent),
+ m_ocrResEdit(0)
+{
+ KIconLoader *loader = KGlobal::iconLoader();
+ scan_params = 0L;
+ preview_canvas = 0L;
+
+ m_mainDock = parent->createDockWidget( "Kookas MainDock",
+ loader->loadIcon( "folder_image", KIcon::Small ),
+ 0L, i18n("Image Viewer"));
+ m_mainDock->setEnableDocking(KDockWidget::DockNone );
+ m_mainDock->setDockSite( KDockWidget::DockFullSite );
+
+ parent->setView( m_mainDock);
+ parent->setMainDockWidget( m_mainDock);
+
+ img_canvas = new ImageCanvas( m_mainDock );
+ img_canvas->setMinimumSize(100,200);
+ img_canvas->enableContextMenu(true);
+ connect( img_canvas, SIGNAL( imageReadOnly(bool)),
+ this, SLOT(slViewerReadOnly(bool)));
+
+ KPopupMenu *ctxtmenu = static_cast<KPopupMenu*>(img_canvas->contextMenu());
+ if( ctxtmenu )
+ ctxtmenu->insertTitle(i18n("Image View"));
+ m_mainDock->setWidget( img_canvas );
+
+ /** Thumbview **/
+ m_dockThumbs = parent->createDockWidget( "Thumbs",
+ loader->loadIcon( "thumbnail", KIcon::Small ),
+ 0L, i18n("Thumbnails"));
+ m_dockThumbs->setDockSite(KDockWidget::DockFullSite );
+
+ /* thumbnail viewer widget */
+ m_thumbview = new ThumbView( m_dockThumbs);
+ m_dockThumbs->setWidget( m_thumbview );
+
+ m_dockThumbs->manualDock( m_mainDock, // dock target
+ KDockWidget::DockBottom, // dock site
+ 20 ); // relation target/this (in percent)
+
+ /** Packager Dock **/
+ /* A new packager to contain the already scanned images */
+ m_dockPackager = parent->createDockWidget( "Scanpackager",
+ loader->loadIcon( "palette_color", KIcon::Small ),
+ 0L, i18n("Gallery"));
+ m_dockPackager->setDockSite(KDockWidget::DockFullSite);
+ packager = new ScanPackager( m_dockPackager );
+ m_dockPackager->setWidget( packager );
+ m_dockPackager->manualDock( m_mainDock, // dock target
+ KDockWidget::DockLeft, // dock site
+ 30 ); // relation target/this (in percent)
+
+
+ connect( packager, SIGNAL(showThumbnails( KFileTreeViewItem* )),
+ this, SLOT( slShowThumbnails( KFileTreeViewItem* )));
+ connect( m_thumbview, SIGNAL( selectFromThumbnail( const KURL& )),
+ packager, SLOT( slSelectImage(const KURL&)));
+
+ /*
+ * Create a Kombobox that holds the last folders visible even on the preview page
+ */
+ m_dockRecent = parent->createDockWidget( "Recent",
+ loader->loadIcon( "image", KIcon::Small ),
+ 0L, i18n("Gallery Folders"));
+
+ m_dockRecent->setDockSite(KDockWidget::DockFullSite);
+
+ QHBox *recentBox = new QHBox( m_dockRecent );
+ recentBox->setMargin(KDialog::marginHint());
+ QLabel *lab = new QLabel( i18n("Gallery:"), recentBox );
+ lab->setSizePolicy( QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed) );
+ recentFolder = new ImageNameCombo( recentBox );
+
+ m_dockRecent->setWidget( recentBox );
+ m_dockRecent->manualDock( m_dockPackager, // dock target
+ KDockWidget::DockBottom, // dock site
+ 5 ); // relation target/this (in percent)
+
+
+
+ connect( packager, SIGNAL( galleryPathSelected( KFileTreeBranch*, const QString&)),
+ recentFolder, SLOT( slotGalleryPathChanged( KFileTreeBranch*, const QString& )));
+
+ connect( packager, SIGNAL( directoryToRemove( KFileTreeBranch*, const QString&)),
+ recentFolder, SLOT( slotPathRemove( KFileTreeBranch*, const QString& )));
+
+ connect( recentFolder, SIGNAL(activated( const QString& )),
+ packager, SLOT(slotSelectDirectory( const QString& )));
+
+ /* the object from the kscan lib to handle low level scanning */
+ m_dockScanParam = parent->createDockWidget( "Scan Parameter",
+ loader->loadIcon( "folder", KIcon::Small ),
+ 0L, i18n("Scan Parameter"));
+ //
+ m_dockScanParam->setDockSite(KDockWidget::DockFullSite);
+
+ m_dockScanParam->setWidget( 0 ); // later
+ sane = new KScanDevice( m_dockScanParam );
+ Q_CHECK_PTR(sane);
+
+ m_dockScanParam->manualDock( m_dockRecent, // dock target
+ KDockWidget::DockBottom, // dock site
+ 20 ); // relation target/this (in percent)
+ m_dockScanParam->hide();
+
+ /* select the scan device, either user or from config, this creates and assembles
+ * the complete scanner options dialog
+ * scan_params must be zero for that */
+
+ m_dockPreview = parent->createDockWidget( "Preview ",
+ loader->loadIcon( "viewmag", KIcon::Small ),
+ 0L, i18n("Scan Preview"));
+
+ preview_canvas = new Previewer( m_dockPreview );
+ {
+ preview_canvas->setMinimumSize( 100,100);
+
+ /* since the scan_params will be created in slSelectDevice, do the
+ * connections later
+ */
+ }
+ m_dockPreview->setWidget( preview_canvas );
+ m_dockPreview->manualDock( m_mainDock, // dock target
+ KDockWidget::DockCenter, // dock site
+ 100 ); // relation target/this (in percent)
+
+ /* Create a text editor part for ocr results */
+
+ m_dockOCRText = parent->createDockWidget( "OCRResults",
+ loader->loadIcon("edit", KIcon::Small ),
+ 0L, i18n("OCR Result Text"));
+ // m_textEdit
+ m_ocrResEdit = new ocrResEdit( m_dockOCRText );
+
+ if( m_ocrResEdit )
+ {
+ m_dockOCRText->setWidget( m_ocrResEdit ); // m_textEdit->widget() );
+ m_dockOCRText->manualDock( m_dockThumbs, // dock target
+ KDockWidget::DockCenter, // dock site
+ 100 ); // relation target/this (in percent)
+
+ m_ocrResEdit->setTextFormat( Qt::PlainText );
+ m_ocrResEdit->setWordWrap( QTextEdit::NoWrap );
+ // m_dockOCRText->hide();
+ }
+
+ if( slSelectDevice(deviceToUse))
+ {
+ /* Load from config which tab page was selected last time */
+ }
+
+ /* New image created after scanning */
+ connect(sane, SIGNAL(sigNewImage(QImage*,ImgScanInfo*)), this, SLOT(slNewImageScanned(QImage*,ImgScanInfo*)));
+ /* New preview image */
+ connect(sane, SIGNAL(sigNewPreview(QImage*,ImgScanInfo *)), this, SLOT( slNewPreview(QImage*,ImgScanInfo *)));
+
+ connect( sane, SIGNAL( sigScanStart() ), this, SLOT( slScanStart()));
+ connect( sane, SIGNAL( sigScanFinished(KScanStat)), this, SLOT(slScanFinished(KScanStat)));
+ connect( sane, SIGNAL( sigAcquireStart()), this, SLOT( slAcquireStart()));
+ /* Image canvas should show a new document */
+ connect( packager, SIGNAL( showImage( KookaImage* )),
+ this, SLOT( slShowAImage( KookaImage*)));
+
+ connect( packager, SIGNAL( aboutToShowImage(const KURL&)),
+ this, SLOT( slStartLoading( const KURL& )));
+
+ /* Packager unloads the image */
+ connect( packager, SIGNAL( unloadImage( KookaImage* )),
+ this, SLOT( slUnloadAImage( KookaImage*)));
+
+ /* a image changed mostly through a image manipulation method like rotate */
+ connect( packager, SIGNAL( fileChanged( KFileItem* )),
+ m_thumbview, SLOT( slImageChanged( KFileItem* )));
+
+ connect( packager, SIGNAL( fileRenamed( KFileItem*, const KURL& )),
+ m_thumbview, SLOT( slImageRenamed( KFileItem*, const KURL& )));
+
+ connect( packager, SIGNAL( fileDeleted( KFileItem* )),
+ m_thumbview, SLOT( slImageDeleted( KFileItem* )));
+
+
+ packager->openRoots();
+
+ /* Status Bar */
+ KStatusBar *statBar = m_mainWindow->statusBar();
+
+ // statBar->insertItem(QString("1"), SBAR_ZOOM, 0, true );
+ statBar->insertItem( QString("-"), StatusImage, 0, true );
+
+ /* Set a large enough size */
+ int w = statBar->fontMetrics().
+ width(img_canvas->imageInfoString(2000, 2000, 48));
+ kdDebug(28000) << "Fixed size for status bar: " << w << " from string " << img_canvas->imageInfoString(2000, 2000, 48) << endl;
+ statBar->setItemFixed( StatusImage, w );
+
+}
+
+
+KookaView::~KookaView()
+{
+ saveProperties( KGlobal::config () );
+ delete preview_canvas;
+
+ kdDebug(28000)<< "Finished saving config data" << endl;
+}
+
+void KookaView::slViewerReadOnly( bool )
+{
+ /* retrieve actions that could change the image */
+}
+
+
+bool KookaView::slSelectDevice( const QCString& useDevice )
+{
+
+ kdDebug(28000) << "Kookaview: select a device!" << endl;
+ bool haveConnection = false;
+
+ QCString selDevice;
+ /* in case useDevice is the term 'gallery', the user does not want to
+ * connect to a scanner, but only work in gallery mode. Otherwise, try
+ * to read the device to use from config or from a user dialog */
+ if( useDevice != "gallery" )
+ {
+ selDevice = useDevice;
+ if( selDevice.isEmpty())
+ {
+ selDevice = userDeviceSelection();
+ }
+ }
+
+ if( !selDevice.isEmpty() )
+ {
+ kdDebug(28000) << "Opening device " << selDevice << endl;
+
+ if( connectedDevice == selDevice ) {
+ kdDebug( 28000) << "Device " << selDevice << " is already selected!" << endl;
+ return( true );
+ }
+
+ if( scan_params )
+ {
+ /* This deletes the existing scan_params^-object */
+ slCloseScanDevice();
+ }
+
+ /* This connects to the selected scanner */
+ scan_params = new ScanParams( m_dockScanParam );
+ Q_CHECK_PTR(scan_params);
+
+ if( sane->openDevice( selDevice ) == KSCAN_OK )
+ {
+ connect( scan_params, SIGNAL( scanResolutionChanged( int, int )),
+ preview_canvas, SLOT( slNewScanResolutions( int, int )));
+
+ if( ! scan_params->connectDevice( sane ) )
+ {
+ kdDebug(28000) << "Connecting to the scanner failed :( ->TODO" << endl;
+ }
+ else
+ {
+ haveConnection = true;
+ connectedDevice = selDevice;
+
+ /* New Rectangle selection in the preview, now scanimge exists */
+ ImageCanvas *previewCanvas = preview_canvas->getImageCanvas();
+ connect( previewCanvas , SIGNAL( newRect(QRect)),
+ scan_params, SLOT(slCustomScanSize(QRect)));
+ connect( previewCanvas, SIGNAL( noRect()),
+ scan_params, SLOT(slMaximalScanSize()));
+ // connect( scan_params, SIGNAL( scanResolutionChanged( int, int )),
+ // preview_canvas, SLOT( slNewScanResolutions( int, int )));
+ /* load the preview image */
+ if( preview_canvas )
+ {
+ preview_canvas->setPreviewImage( sane->loadPreviewImage() );
+
+ /* Call this after the devic is actually open */
+ preview_canvas->slConnectScanner( sane );
+ }
+ }
+ }
+ else
+ {
+ kdDebug(28000) << "Could not open device <" << selDevice << ">" << endl;
+ scan_params->connectDevice(0);
+ }
+
+ /* show the widget again */
+
+ m_dockScanParam->setWidget( scan_params );
+
+ m_dockScanParam->show();
+ }
+ else
+ {
+ // no devices available or starting in gallery mode
+ if( scan_params )
+ scan_params->connectDevice( 0L );
+ }
+ return( haveConnection );
+}
+
+QCString KookaView::userDeviceSelection( ) const
+{
+ /* Human readable scanner descriptions */
+ QStringList hrbackends;
+
+ /* a list of backends the scan backend knows */
+ QStrList backends = sane->getDevices();
+ QStrListIterator it( backends );
+
+ QCString selDevice;
+ if( backends.count() > 0 )
+ {
+ while( it )
+ {
+ kdDebug( 28000 ) << "Found backend: " << it.current() << endl;
+ hrbackends.append( sane->getScannerName( it.current() ));
+ ++it;
+ }
+
+ /* allow the user to select one */
+ DeviceSelector ds( 0, backends, hrbackends );
+ selDevice = ds.getDeviceFromConfig( );
+
+ if( selDevice.isEmpty() || selDevice.isNull() )
+ {
+ kdDebug(29000) << "selDevice not found - starting selector!" << selDevice << endl;
+ if ( ds.exec() == QDialog::Accepted )
+ {
+ selDevice = ds.getSelectedDevice();
+ }
+ }
+ }
+ return( selDevice );
+}
+
+
+void KookaView::loadStartupImage( void )
+{
+ kdDebug( 28000) << "Starting to load startup image" << endl;
+
+ /* Now set the configured stuff */
+ KConfig *konf = KGlobal::config ();
+ if( konf )
+ {
+ konf->setGroup(GROUP_STARTUP);
+ bool wantReadOnStart = konf->readBoolEntry( STARTUP_READ_IMAGE, true );
+
+ if( wantReadOnStart )
+ {
+ QString startup = konf->readPathEntry( STARTUP_IMG_SELECTION );
+
+ if( !startup.isEmpty() )
+ {
+ kdDebug(28000) << "Loading startup image !" << endl;
+ packager->slSelectImage( KURL(startup) );
+ }
+ }
+ else
+ {
+ kdDebug(28000) << "Do not load startup image due to config value" << endl;
+ }
+ }
+}
+
+
+void KookaView::print()
+{
+ /* For now, print a single file. Later, print multiple images to one page */
+ KookaImage *img = packager->getCurrImage();
+ if ( !img )
+ return;
+ KPrinter printer; // ( true, pMode );
+ printer.setUsePrinterResolution(true);
+ printer.addDialogPage( new ImgPrintDialog( img ));
+
+ if( printer.setup( m_mainWindow, i18n("Print %1").arg(img->localFileName().section('/', -1)) ))
+ {
+ KookaPrint kookaprint( &printer );
+ kookaprint.printImage(img);
+ }
+}
+
+void KookaView::slNewPreview( QImage *new_img, ImgScanInfo * )
+{
+ if( new_img )
+ {
+ if( ! new_img->isNull() )
+ {
+ /* flip preview to front */
+ m_dockPreview->makeDockVisible();
+ }
+ preview_canvas->newImage( new_img );
+ }
+}
+
+
+bool KookaView::ToggleVisibility( int item )
+{
+ QWidget *w = 0;
+ bool ret = false;
+
+ switch( item )
+ {
+ case ID_VIEW_SCANPARAMS:
+ w = scan_params;
+ break;
+ case ID_VIEW_POOL:
+ w = preview_canvas;
+ break;
+ default:
+ w = 0;
+ }
+
+ if( w )
+ {
+ if( w->isVisible() )
+ {
+ w->hide();
+ ret = false;
+ }
+ else
+ {
+ w->show();
+ ret = true;
+ }
+ }
+ return ret;
+}
+
+
+void KookaView::doOCRonSelection( void )
+{
+ emit( signalChangeStatusbar( i18n("Starting OCR on selection" )));
+
+ KookaImage img;
+
+ if( img_canvas->selectedImage(&img) )
+ {
+ startOCR( &img );
+ }
+ emit( signalCleanStatusbar() );
+}
+
+/* Does OCR on the entire picture */
+void KookaView::doOCR( void )
+{
+ emit( signalChangeStatusbar( i18n("Starting OCR on the entire image" )));
+ KookaImage *img = packager->getCurrImage();
+ startOCR( img );
+ emit( signalCleanStatusbar( ));
+}
+
+void KookaView::startOCR( KookaImage *img )
+{
+ if( img && ! img->isNull() )
+ {
+ if( ocrFabric == 0L )
+ {
+ ocrFabric = new KSANEOCR( m_mainDock, KGlobal::config() );
+ ocrFabric->setImageCanvas( img_canvas );
+
+ connect( ocrFabric, SIGNAL( newOCRResultText( const QString& )),
+ m_ocrResEdit, SLOT(setText( const QString& )));
+
+ connect( ocrFabric, SIGNAL( newOCRResultText( const QString& )),
+ m_dockOCRText, SLOT( show() ));
+
+ connect( ocrFabric, SIGNAL( repaintOCRResImage( )),
+ img_canvas, SLOT(repaint()));
+
+ connect( ocrFabric, SIGNAL( clearOCRResultText()),
+ m_ocrResEdit, SLOT(clear()));
+
+ connect( ocrFabric, SIGNAL( updateWord(int, const QString&, const QString& )),
+ m_ocrResEdit, SLOT( slUpdateOCRResult( int, const QString&, const QString& )));
+
+ connect( ocrFabric, SIGNAL( ignoreWord(int, const ocrWord&)),
+ m_ocrResEdit, SLOT( slIgnoreWrongWord( int, const ocrWord& )));
+
+ connect( ocrFabric, SIGNAL( markWordWrong(int, const ocrWord& )),
+ m_ocrResEdit, SLOT( slMarkWordWrong( int, const ocrWord& )));
+
+ connect( ocrFabric, SIGNAL( readOnlyEditor( bool )),
+ m_ocrResEdit, SLOT( setReadOnly( bool )));
+
+ connect( ocrFabric, SIGNAL( selectWord( int, const ocrWord& )),
+ m_ocrResEdit, SLOT( slSelectWord( int, const ocrWord& )));
+
+ }
+
+ Q_CHECK_PTR( ocrFabric );
+ ocrFabric->slSetImage( img );
+
+ if( !ocrFabric->startOCRVisible(m_mainDock) )
+ {
+ KMessageBox::sorry(0, i18n("Could not start OCR-Process.\n"
+ "Probably there is already one running." ));
+
+ }
+ }
+}
+
+
+void KookaView::slOCRResultImage( const QPixmap& pix )
+{
+ kdDebug(28000) << "Showing OCR Result Image" << endl;
+ if( ! img_canvas ) return;
+
+ if( m_ocrResultImg )
+ {
+ img_canvas->newImage(0L);
+ delete m_ocrResultImg;
+ }
+
+ m_ocrResultImg = new QImage();
+ *m_ocrResultImg = pix;
+ img_canvas->newImage( m_ocrResultImg );
+ img_canvas->setReadOnly(true); // ocr result images should be read only.
+}
+
+void KookaView::slScanStart( )
+{
+ kdDebug(28000) << "Scan starts " << endl;
+ if( scan_params )
+ {
+ scan_params->setEnabled( false );
+ KLed *led = scan_params->operationLED();
+ if( led )
+ {
+ led->setColor( Qt::red );
+ led->setState( KLed::On );
+ }
+ }
+}
+
+void KookaView::slAcquireStart( )
+{
+ kdDebug(28000) << "Acquire starts " << endl;
+ if( scan_params )
+ {
+ KLed *led = scan_params->operationLED();
+ if( led )
+ {
+ led->setColor( Qt::green );
+ }
+ }
+}
+
+void KookaView::slNewImageScanned( QImage* img, ImgScanInfo* si )
+{
+ KookaImageMeta *meta = new KookaImageMeta;
+ meta->setScanResolution(si->getXResolution(), si->getYResolution());
+ packager->slAddImage(img, meta);
+}
+
+
+
+void KookaView::slScanFinished( KScanStat stat )
+{
+ kdDebug(28000) << "Scan finished with status " << stat << endl;
+ if( scan_params )
+ {
+ scan_params->setEnabled( true );
+ KLed *led = scan_params->operationLED();
+ if( led )
+ {
+ led->setColor( Qt::green );
+ led->setState( KLed::Off );
+ }
+ }
+}
+
+
+void KookaView::slCloseScanDevice( )
+{
+ kdDebug(28000) << "Scanner Device closes down !" << endl;
+ if( scan_params ) {
+ delete scan_params;
+ scan_params = 0;
+ m_dockScanParam->setWidget(0L);
+ m_dockScanParam->hide();
+ }
+
+ sane->slCloseDevice();
+}
+
+void KookaView::slCreateNewImgFromSelection()
+{
+ if( img_canvas->rootImage() )
+ {
+ emit( signalChangeStatusbar( i18n("Create new image from selection" )));
+ QImage img;
+ if( img_canvas->selectedImage( &img ) )
+ {
+ packager->slAddImage( &img );
+ }
+ emit( signalCleanStatusbar( ));
+ }
+
+}
+
+
+void KookaView::slRotateImage(int angle)
+{
+ // QImage *img = (QImage*) img_canvas->rootImage();
+ KookaImage *img = packager->getCurrImage();
+ bool doUpdate = true;
+
+ if( img )
+ {
+ QImage resImg;
+
+ QApplication::setOverrideCursor(waitCursor);
+ switch( angle )
+ {
+ case 90:
+ emit( signalChangeStatusbar( i18n("Rotate image 90 degrees" )));
+ resImg = rotateRight( img );
+ break;
+ case 180:
+ emit( signalChangeStatusbar( i18n("Rotate image 180 degrees" )));
+ resImg = rotate180( img );
+ break;
+ case 270:
+ case -90:
+ emit( signalChangeStatusbar( i18n("Rotate image -90 degrees" )));
+ resImg = rotateLeft( img );
+
+ break;
+ default:
+ kdDebug(28000) << "Not supported yet !" << endl;
+ doUpdate = false;
+
+ break;
+ }
+ QApplication::restoreOverrideCursor();
+
+ /* updateCurrImage does the status-bar cleanup */
+ if( doUpdate )
+ updateCurrImage( resImg );
+ else
+ emit(signalCleanStatusbar());
+ }
+
+}
+
+
+
+void KookaView::slMirrorImage( MirrorType m )
+{
+ const QImage *img = img_canvas->rootImage();
+ bool doUpdate = true;
+
+ if( img )
+ {
+ QImage resImg;
+
+ QApplication::setOverrideCursor(waitCursor);
+ switch( m )
+ {
+ case MirrorVertical:
+ emit( signalChangeStatusbar( i18n("Mirroring image vertically" )));
+ resImg = img->mirror();
+ break;
+ case MirrorHorizontal:
+ emit( signalChangeStatusbar( i18n("Mirroring image horizontally" )));
+ resImg = img->mirror( true, false );
+ break;
+ case MirrorBoth:
+ emit( signalChangeStatusbar( i18n("Mirroring image in both directions" )));
+ resImg = img->mirror( true, true );
+ break;
+ default:
+ kdDebug(28000) << "Mirroring: no way ;)" << endl;
+ doUpdate = false;
+ }
+ QApplication::restoreOverrideCursor();
+
+ /* updateCurrImage does the status-bar cleanup */
+ if( doUpdate )
+ updateCurrImage( resImg );
+ else
+ emit(signalCleanStatusbar());
+
+ // img_canvas->newImage( );
+ }
+}
+
+
+void KookaView::slSaveOCRResult()
+{
+ if( ! m_ocrResEdit ) return;
+ m_ocrResEdit->slSaveText();
+
+}
+
+
+void KookaView::slLoadScanParams( )
+{
+ if( ! sane ) return;
+#if 0
+ /* not yet cooked */
+ LoadSetDialog loadDialog( m_mainDock, sane->shortScannerName(), sane );
+ if( loadDialog.exec())
+ {
+ kdDebug(28000)<< "Executed successfully" << endl;
+ }
+#endif
+}
+
+void KookaView::slSaveScanParams( )
+{
+ if( !sane ) return;
+
+ /* not yet cooked */
+#if 0
+ KScanOptSet optSet( "SaveSet" );
+
+ sane->getCurrentOptions( &optSet );
+ SaveSetDialog dialog( m_mainDock /* this */ , &optSet );
+ if( dialog.exec())
+ {
+ kdDebug(28000)<< "Executed successfully" << endl;
+ QString name = dialog.paramSetName();
+ QString desc = dialog.paramSetDescription();
+ sane->slSaveScanConfigSet( name, desc );
+ }
+#endif
+}
+
+void KookaView::slShowAImage( KookaImage *img )
+{
+ kdDebug(28000) << "Show new Image" << endl;
+ if( img_canvas )
+ {
+ img_canvas->newImage( img );
+ img_canvas->setReadOnly(false);
+ }
+
+ /* tell ocr about */
+ if( ocrFabric )
+ {
+ ocrFabric->slSetImage( img );
+ }
+
+ /* Status Bar */
+ KStatusBar *statBar = m_mainWindow->statusBar();
+ if( img_canvas )
+ statBar->changeItem( img_canvas->imageInfoString(), StatusImage );
+}
+
+void KookaView::slUnloadAImage( KookaImage * )
+{
+ kdDebug(28000) << "Unloading Image" << endl;
+ if( img_canvas )
+ {
+ img_canvas->newImage( 0L );
+ }
+}
+
+
+void KookaView::slShowThumbnails(KFileTreeViewItem *dirKfi, bool forceRedraw )
+{
+ /* If no item is specified, use the current one */
+ if( ! dirKfi )
+ {
+ /* do on the current visible dir */
+ KFileTreeViewItem *kftvi = packager->currentKFileTreeViewItem();
+ if ( !kftvi )
+ {
+ return;
+ }
+
+ if( kftvi->isDir())
+ {
+ dirKfi = kftvi;
+ }
+ else
+ {
+ kftvi = static_cast<KFileTreeViewItem*>(static_cast<QListViewItem*>(kftvi)->parent());
+ dirKfi = kftvi;
+ forceRedraw = true;
+ packager->setSelected( static_cast<QListViewItem*>(dirKfi), true );
+ }
+ }
+
+ kdDebug(28000) << "Showing thumbs for " << dirKfi->url().prettyURL() << endl;
+
+ /* Only do the new thumbview if the old is on another dir */
+ if( m_thumbview && (forceRedraw || m_thumbview->currentDir() != dirKfi->url()) )
+ {
+ m_thumbview->clear();
+ /* Find a list of child KFileItems */
+ if( forceRedraw ) m_thumbview->readSettings();
+
+ KFileItemList fileItemsList;
+
+ QListViewItem * myChild = dirKfi->firstChild();
+ while( myChild )
+ {
+ fileItemsList.append( static_cast<KFileTreeViewItem*>(myChild)->fileItem());
+ myChild = myChild->nextSibling();
+ }
+
+ m_thumbview->slNewFileItems( fileItemsList );
+ m_thumbview->setCurrentDir( dirKfi->url());
+ // m_thumbview->arrangeItemsInGrid();
+ }
+
+}
+
+/* this slot is called when the user clicks on an image in the packager
+ * and loading of the image starts
+ */
+void KookaView::slStartLoading( const KURL& url )
+{
+ emit( signalChangeStatusbar( i18n("Loading %1" ).arg( url.prettyURL() ) ));
+
+ // if( m_stack->visibleWidget() != img_canvas )
+ // {
+ // m_stack->raiseWidget( img_canvas );
+ // }
+
+}
+
+
+void KookaView::updateCurrImage( QImage& img )
+{
+ if( ! img_canvas->readOnly() )
+ {
+ emit( signalChangeStatusbar( i18n("Storing image changes" )));
+ packager->slotCurrentImageChanged( &img );
+ emit( signalCleanStatusbar());
+ }
+ else
+ {
+ emit( signalChangeStatusbar( i18n("Can not save image, it is write protected!")));
+ kdDebug(28000) << "Image is write protected, no saving!" << endl;
+ }
+}
+
+
+void KookaView::saveProperties(KConfig *config)
+{
+ kdDebug(28000) << "Saving Properties for KookaView !" << endl;
+ config->setGroup( GROUP_STARTUP );
+ /* Get with path */
+ config->writePathEntry( STARTUP_IMG_SELECTION, packager->getCurrImageFileName(true));
+
+}
+
+
+void KookaView::slOpenCurrInGraphApp( void )
+{
+ QString file;
+
+ if( packager )
+ {
+ KFileTreeViewItem *ftvi = packager->currentKFileTreeViewItem();
+
+ if( ! ftvi ) return;
+
+ kdDebug(28000) << "Trying to open <" << ftvi->url().prettyURL()<< ">" << endl;
+ KURL::List urllist;
+
+ urllist.append( ftvi->url());
+
+ KRun::displayOpenWithDialog( urllist );
+ }
+}
+
+
+QImage KookaView::rotateLeft( QImage *m_img )
+{
+ QImage rot;
+
+ if( m_img )
+ {
+ QWMatrix m;
+
+ m.rotate(-90);
+ rot = m_img->xForm(m);
+ }
+ return( rot );
+}
+
+QImage KookaView::rotateRight( QImage *m_img )
+{
+ QImage rot;
+
+ if( m_img )
+ {
+ QWMatrix m;
+
+ m.rotate(+90);
+ rot = m_img->xForm(m);
+ }
+ return( rot );
+}
+
+QImage KookaView::rotate180( QImage *m_img )
+{
+ QImage rot;
+
+ if( m_img )
+ {
+ QWMatrix m;
+
+ m.rotate(+180);
+ rot = m_img->xForm(m);
+ }
+ return( rot );
+}
+
+
+
+void KookaView::connectViewerAction( KAction *action )
+{
+ QPopupMenu *popup = img_canvas->contextMenu();
+ kdDebug(29000) << "This is the popup: " << popup << endl;
+ if( popup && action )
+ {
+ action->plug( popup );
+ }
+}
+
+void KookaView::connectGalleryAction( KAction *action )
+{
+ QPopupMenu *popup = packager->contextMenu();
+
+ if( popup && action )
+ {
+ action->plug( popup );
+ }
+}
+
+void KookaView::slFreshUpThumbView()
+{
+ if( m_thumbview )
+ {
+ /* readSettings returns true if something changes */
+ if( m_thumbview->readSettings() )
+ {
+ kdDebug(28000) << "Thumbview-Settings changed, readraw thumbs" << endl;
+ /* new settings */
+ slShowThumbnails(0, true);
+ }
+ }
+}
+
+void KookaView::createDockMenu( KActionCollection *col, KDockMainWindow *mainWin, const char * name )
+{
+ KActionMenu *actionMenu = new KActionMenu( i18n("Tool Views"), "view_icon", col, name );
+
+ actionMenu->insert( new dwMenuAction( i18n("Show Image Viewer"),
+ KShortcut(), m_mainDock, col,
+ mainWin, "dock_viewer" ));
+
+ actionMenu->insert( new dwMenuAction( i18n("Show Preview"),
+ KShortcut(), m_dockPreview, col,
+ mainWin, "dock_preview" ));
+
+ actionMenu->insert( new dwMenuAction( i18n("Show Recent Gallery Folders"),
+ KShortcut(), m_dockRecent, col,
+ mainWin, "dock_recent" ));
+ actionMenu->insert( new dwMenuAction( i18n("Show Gallery"),
+ KShortcut(), m_dockPackager, col,
+ mainWin, "dock_gallery" ));
+
+ actionMenu->insert( new dwMenuAction( i18n("Show Thumbnail Window"),
+ KShortcut(), m_dockThumbs, col,
+ mainWin, "dock_thumbs" ));
+
+ actionMenu->insert( new dwMenuAction( i18n("Show Scan Parameters"),
+ KShortcut(), m_dockScanParam, col,
+ mainWin, "dock_scanparams" ));
+
+ actionMenu->insert( new dwMenuAction( i18n("Show OCR Results"),
+ KShortcut(), m_dockOCRText, col,
+ mainWin, "dock_ocrResults" ));
+}
+
+
+#include "kookaview.moc"
diff --git a/kooka/kookaview.h b/kooka/kookaview.h
new file mode 100644
index 00000000..a1f7898a
--- /dev/null
+++ b/kooka/kookaview.h
@@ -0,0 +1,241 @@
+/***************************************************************************
+ kookaview.h - Main view
+ -------------------
+ begin : Sun Jan 16 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+#ifndef KOOKAVIEW_H
+#define KOOKAVIEW_H
+
+#include <qwidget.h>
+#include <kopenwith.h>
+#include "kookaiface.h"
+#include <kdockwidget.h>
+#include <qtabwidget.h>
+#include <qlayout.h>
+#include <qimage.h>
+#include <qsplitter.h>
+
+#include <kparts/dockmainwindow.h>
+#include <kparts/part.h>
+
+// application specific includes
+#include "kscandevice.h"
+#include "previewer.h"
+#include "scanpackager.h"
+#include "scanparams.h"
+#include "img_canvas.h"
+
+class KDockWidget;
+class QPainter;
+class KSANEOCR;
+class KConfig;
+class KPrinter;
+class KComboBox;
+class KAction;
+class KActionCollection;
+class ThumbView;
+class KookaImage;
+class QPixmap;
+class ocrResEdit;
+/**
+ * This is the main view class for Kooka. Most of the non-menu,
+ * non-toolbar, and non-statusbar (e.g., non frame) GUI code should go
+ * here.
+ *
+ * @short Main view
+ * @author Klaas Freitag <freitag@suse.de>
+ * @version 0.1
+ */
+class KookaView : public QObject
+{
+ Q_OBJECT
+public:
+ typedef enum { MirrorVertical, MirrorHorizontal, MirrorBoth } MirrorType;
+ typedef enum { StatusTemp, StatusImage } StatusBarIDs;
+
+ /**
+ * Default constructor
+ */
+ KookaView(KParts::DockMainWindow *parent, const QCString& deviceToUse);
+
+ /**
+ * Destructor
+ */
+ virtual ~KookaView();
+
+ /**
+ * Print this view to any medium -- paper or not
+ */
+ void print( );
+
+ bool ToggleVisibility( int );
+ void loadStartupImage( void );
+ KDockWidget *mainDockWidget( ) { return m_mainDock; }
+
+ void createDockMenu( KActionCollection*, KDockMainWindow *, const char *);
+
+ ScanPackager *gallery() { return packager; }
+
+ // KParts::Part* ocrResultPart() { return m_textEdit; }
+
+ ImageCanvas *getImageViewer() { return img_canvas; }
+public slots:
+ void slShowPreview() { }
+ void slShowPackager() { }
+ void slNewPreview( QImage *, ImgScanInfo * );
+
+ void slSetScanParamsVisible( bool v )
+ { if( v ) scan_params->show(); else scan_params->hide(); }
+ void slSetTabWVisible( bool v )
+ { if( v ) preview_canvas->show(); else preview_canvas->hide(); }
+
+ void doOCR( void );
+ void doOCRonSelection( void );
+
+ void slStartPreview() { if( scan_params ) scan_params->slAcquirePreview(); }
+ void slStartFinalScan() { if( scan_params ) scan_params->slStartScan(); }
+
+ void slCreateNewImgFromSelection( void );
+
+ void slRotateImage( int );
+
+ void slMirrorImage( MirrorType );
+
+ void slIVScaleToWidth( void )
+ { if( img_canvas ) img_canvas->handle_popup(ImageCanvas::ID_FIT_WIDTH );}
+ void slIVScaleToHeight( void )
+ { if( img_canvas ) img_canvas->handle_popup(ImageCanvas::ID_FIT_HEIGHT );}
+ void slIVScaleOriginal( void )
+ { if( img_canvas ) img_canvas->handle_popup(ImageCanvas::ID_ORIG_SIZE ); }
+ void slIVShowZoomDialog( )
+ { if( img_canvas ) img_canvas->handle_popup(ImageCanvas::ID_POP_ZOOM ); }
+
+ void slOpenCurrInGraphApp( void );
+
+ void slSaveOCRResult();
+
+ void slLoadScanParams( );
+ void slSaveScanParams( );
+
+ void slOCRResultImage( const QPixmap& );
+
+ void slShowThumbnails( KFileTreeViewItem *dirKfi = 0, bool forceRedraw=false);
+ void slFreshUpThumbView();
+
+ /**
+ * slot that show the image viewer
+ */
+ void slStartLoading( const KURL& url );
+ /**
+ * starts ocr on the image the parameter is pointing to
+ **/
+ void startOCR( KookaImage* );
+
+ void slCloseScanDevice();
+ void saveProperties( KConfig* );
+
+ /**
+ * slot to select the scanner device. Does all the work with selection
+ * of scanner, disconnection of the old device and connecting the new.
+ */
+ bool slSelectDevice(const QCString& useDevice=QCString());
+
+ void connectViewerAction( KAction *action );
+ void connectGalleryAction( KAction *action );
+
+ void slScanStart();
+ void slScanFinished( KScanStat stat );
+ void slAcquireStart();
+
+
+protected slots:
+
+ void slShowAImage( KookaImage* );
+ void slUnloadAImage( KookaImage* );
+
+ /**
+ * called from the scandevice if a new Image was successfully scanned.
+ * Needs to convert the one-page-QImage to a KookaImage
+ */
+ void slNewImageScanned(QImage*, ImgScanInfo*);
+
+ /**
+ * called if an viewer image was set to read only or back to read write state.
+ */
+ void slViewerReadOnly( bool ro );
+signals:
+ /**
+ * Use this signal to change the content of the statusbar
+ */
+ void signalChangeStatusbar(const QString& text);
+
+ /**
+ * Use this signal to clean up the statusbar
+ */
+ void signalCleanStatusbar( void );
+
+ /**
+ * Use this signal to change the content of the caption
+ */
+ void signalChangeCaption(const QString& text);
+
+private:
+ QImage rotateRight( QImage* );
+ QImage rotateLeft ( QImage* );
+ QImage rotate180 ( QImage* );
+ QCString userDeviceSelection( ) const;
+
+ void updateCurrImage( QImage& ) ;
+
+ ImageCanvas *img_canvas;
+ ThumbView *m_thumbview;
+
+ Previewer *preview_canvas;
+ ScanPackager *packager;
+ ScanParams *scan_params;
+
+ KScanDevice *sane;
+ KComboBox *recentFolder;
+
+ QCString connectedDevice;
+
+ QImage *m_ocrResultImg;
+ int image_pool_id;
+ int preview_id;
+
+ KSANEOCR *ocrFabric;
+
+ KDockWidget *m_mainDock;
+ KDockWidget *m_dockScanParam;
+ KDockWidget *m_dockThumbs;
+ KDockWidget *m_dockPackager;
+ KDockWidget *m_dockRecent;
+ KDockWidget *m_dockPreview;
+ KDockWidget *m_dockOCRText;
+
+ KMainWindow *m_mainWindow;
+
+ ocrResEdit *m_ocrResEdit;
+};
+
+#endif // KOOKAVIEW_H
diff --git a/kooka/ksaneocr.cpp b/kooka/ksaneocr.cpp
new file mode 100644
index 00000000..cf10d682
--- /dev/null
+++ b/kooka/ksaneocr.cpp
@@ -0,0 +1,1493 @@
+/***************************************************************************
+ ksaneocr.cpp - generic ocr
+ -------------------
+ begin : Fri Jun 30 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+/* $Id$ */
+
+#include <kdebug.h>
+#include <kmessagebox.h>
+#include <kconfig.h>
+#include <kapplication.h>
+#include <ktempfile.h>
+#include <kprocess.h>
+#include <stdlib.h>
+#include <kspell.h>
+#include <kspelldlg.h>
+#include <qfile.h>
+#include <qcolor.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <img_canvas.h>
+
+#include "img_saver.h"
+#include "kadmosocr.h"
+#include "kocrbase.h"
+#include "kocrkadmos.h"
+#include "kocrocrad.h"
+#include "config.h"
+#include "ksaneocr.h"
+#include "kocrgocr.h"
+#include "kookaimage.h"
+#include "kookapref.h"
+#include "ocrword.h"
+
+#include <qtimer.h>
+#include <qregexp.h>
+#include <klocale.h>
+#include <qpaintdevice.h>
+#include <qpainter.h>
+#include <qpen.h>
+#include <qbrush.h>
+#include <qfileinfo.h>
+
+/*
+ * Thread support is disabled here because the kadmos lib seems not to be
+ * thread save unfortunately. See slotKadmosResult-comments for more information
+ */
+
+KSANEOCR::KSANEOCR( QWidget*, KConfig *cfg ):
+ m_ocrProcessDia(0L),
+ daemon(0L),
+ visibleOCRRunning(false),
+ m_resultImage(0),
+ m_imgCanvas(0L),
+ m_spell(0L),
+ m_wantKSpell(true),
+ m_kspellVisible(true),
+ m_hideDiaWhileSpellcheck(true),
+ m_spellInitialConfig(0L),
+ m_parent(0L),
+ m_ocrCurrLine(0),
+ m_currHighlight(-1),
+ m_applyFilter(false),
+ m_unlinkORF(true)
+{
+ KConfig *konf = KGlobal::config ();
+ m_ocrEngine = OCRAD;
+ m_img = 0L;
+ m_tmpFile = 0L;
+
+ if( cfg )
+ m_hideDiaWhileSpellcheck = cfg->readBoolEntry( HIDE_BASE_DIALOG, true );
+ /*
+ * a initial config is needed as a starting point for the config dialog
+ * but also for ocr without visible dialog.
+ */
+ m_spellInitialConfig = new KSpellConfig( 0L, 0L ,0L, false );
+
+ if( konf )
+ {
+ /* -- ocr dialog information -- */
+ konf->setGroup( CFG_GROUP_OCR_DIA );
+ QString eng = konf->readEntry(CFG_OCR_ENGINE, "ocrad");
+
+ if( eng == "ocrad" )
+ {
+ m_ocrEngine = OCRAD;
+ }
+ else if( eng == "gocr" )
+ {
+ m_ocrEngine = GOCR;
+ }
+#ifdef HAVE_KADMOS
+ else if( eng == QString("kadmos") ) m_ocrEngine = KADMOS;
+#endif
+ kdDebug(28000) << "OCR engine is " << eng << endl;
+
+ m_unlinkORF = konf->readBoolEntry( CFG_OCR_CLEANUP, true );
+ }
+
+ /* resize m_blocks to size 1 since there is at least one block */
+ m_blocks.resize(1);
+
+}
+
+
+KSANEOCR::~KSANEOCR()
+{
+ if( daemon ) {
+ delete( daemon );
+ daemon = 0;
+ }
+ if ( m_tmpFile )
+ {
+ m_tmpFile->setAutoDelete( true );
+ delete m_tmpFile;
+ }
+
+ if( m_resultImage )
+ {
+ delete m_resultImage;
+ m_resultImage = 0;
+ }
+
+ if( m_img ) delete m_img;
+ if( m_spellInitialConfig ) delete m_spellInitialConfig;
+}
+
+/*
+ * This slot is called to introduce a new image, usually if the user clicks on a
+ * new image either in the gallery or on the thumbnailview.
+ */
+void KSANEOCR::slSetImage(KookaImage *img )
+{
+ if( ! img ) return ;
+
+ if( m_img )
+ delete m_img;
+
+ // FIXME: copy all the image is bad.
+ m_img = new KookaImage(*img);
+
+ if( m_ocrProcessDia )
+ {
+ m_ocrProcessDia->introduceImage( m_img );
+ }
+
+ m_applyFilter = false;
+}
+
+/*
+ * Request to visualise a line-box in the source image, KADMOS Engine
+ */
+void KSANEOCR::slLineBox( const QRect& )
+{
+ if( ! m_img ) return;
+}
+
+
+/*
+ * starts visual ocr process. Depending on the ocr engine, this function creates
+ * a new dialog, and shows it.
+ */
+bool KSANEOCR::startOCRVisible( QWidget *parent )
+{
+ if( visibleOCRRunning ) return( false );
+ bool res = true;
+
+ m_parent = parent;
+
+ if( m_ocrEngine == GOCR )
+ {
+ m_ocrProcessDia = new KGOCRDialog ( parent, m_spellInitialConfig );
+ }
+ else if( m_ocrEngine == OCRAD )
+ {
+ m_ocrProcessDia = new ocradDialog( parent, m_spellInitialConfig );
+ }
+ else if( m_ocrEngine == KADMOS )
+ {
+#ifdef HAVE_KADMOS
+/*** Kadmos Engine OCR ***/
+ m_ocrProcessDia = new KadmosDialog( parent, m_spellInitialConfig );
+#else
+ KMessageBox::sorry(0, i18n("This version of Kooka was not compiled with KADMOS support.\n"
+ "Please select another OCR engine in Kooka's options dialog."));
+ kdDebug(28000) << "Sorry, this version of Kooka has no KADMOS support" << endl;
+#endif /* HAVE_KADMOS */
+ }
+ else
+ {
+ kdDebug(28000) << "ERR Unknown OCR engine requested!" << endl;
+ }
+
+ /*
+ * this part is independant from the engine again
+ */
+ if( m_ocrProcessDia )
+ {
+ m_ocrProcessDia->setupGui();
+
+ m_ocrProcessDia->introduceImage( m_img );
+ visibleOCRRunning = true;
+
+ connect( m_ocrProcessDia, SIGNAL( user1Clicked()), this, SLOT( startOCRProcess() ));
+ connect( m_ocrProcessDia, SIGNAL( closeClicked()), this, SLOT( slotClose() ));
+ connect( m_ocrProcessDia, SIGNAL( user2Clicked()), this, SLOT( slotStopOCR() ));
+ m_ocrProcessDia->show();
+
+ }
+ return( res );
+}
+
+/**
+ * This method should be called by the engine specific finish slots.
+ * It does the not engine dependant cleanups like re-enabling buttons etc.
+ */
+
+void KSANEOCR::finishedOCRVisible( bool success )
+{
+ bool doSpellcheck = m_wantKSpell;
+
+ if( m_ocrProcessDia )
+ {
+ m_ocrProcessDia->stopOCR();
+ doSpellcheck = m_ocrProcessDia->wantSpellCheck();
+ }
+
+ if( success )
+ {
+ QString goof = ocrResultText();
+
+ emit newOCRResultText(goof);
+
+ if( m_imgCanvas )
+ {
+ if( m_resultImage != 0 ) delete m_resultImage;
+ kdDebug(28000) << "Result image name: " << m_ocrResultImage << endl;
+ m_resultImage = new QImage( m_ocrResultImage, "BMP" );
+ kdDebug(28000) << "New result image has dimensions: " << m_resultImage->width() << "x" << m_resultImage->height()<< endl;
+ /* The image canvas is non-zero. Set it to our image */
+ m_imgCanvas->newImageHoldZoom( m_resultImage );
+ m_imgCanvas->setReadOnly(true);
+
+ /* now handle double clicks to jump to the word */
+ m_applyFilter=true;
+ }
+
+ /** now it is time to invoke the dictionary if required **/
+ emit readOnlyEditor( false );
+
+ if( doSpellcheck )
+ {
+ m_ocrCurrLine = 0;
+ /*
+ * create a new kspell object, based on the config of the base dialog
+ */
+
+ connect( new KSpell( m_parent, i18n("Kooka OCR Dictionary Check"),
+ this, SLOT( slSpellReady(KSpell*)),
+ m_ocrProcessDia->spellConfig() ),
+ SIGNAL( death()), this, SLOT(slSpellDead()));
+ }
+
+ delete m_ocrProcessDia;
+ m_ocrProcessDia = 0L;
+
+ }
+
+ visibleOCRRunning = false;
+ cleanUpFiles();
+
+
+ kdDebug(28000) << "# ocr finished #" << endl;
+}
+
+/*
+ * starting the spell check on line m_ocrCurrLine if the line exists.
+ * If not, the function returns.
+ */
+void KSANEOCR::startLineSpellCheck()
+{
+ if( m_ocrCurrLine < m_ocrPage.size() )
+ {
+ m_checkStrings = (m_ocrPage[m_ocrCurrLine]).stringList();
+
+ /* In case the checklist is empty, call the result slot immediately */
+ if( m_checkStrings.count() == 0 )
+ {
+ slCheckListDone(false);
+ return;
+ }
+
+ kdDebug(28000)<< "Wordlist (size " << m_ocrPage[m_ocrCurrLine].count() << ", line " << m_ocrCurrLine << "):" << m_checkStrings.join(", ") << endl;
+
+ // if( list.count() > 0 )
+
+ m_spell->checkList( &m_checkStrings, m_kspellVisible );
+ kdDebug(28000)<< "Started!" << endl;
+ /**
+ * This call ends in three slots:
+ * 1. slMisspelling: Hit _before_ the dialog (if any) appears. Time to
+ * mark the wrong word.
+ * 2. slSpellCorrected: Hit if the user decided which word to use.
+ * 3. slCheckListDone: The line is finished. The global counter needs to be
+ * increased and this function needs to be called again.
+ **/
+
+ }
+ else
+ {
+ kdDebug(28000) << k_funcinfo <<" -- no more lines !" << endl;
+ m_spell->cleanUp();
+ }
+}
+
+
+
+/* User Cancel is called when the user does not really start the
+ * ocr but uses the cancel-Button to come out of the Dialog */
+void KSANEOCR::slotClose()
+{
+ kdDebug(28000) << "closing ocr Dialog" << endl;
+ if( daemon && daemon->isRunning() )
+ {
+ kdDebug(28000) << "Still running - Killing daemon with Sig. 9" << endl;
+ daemon->kill(9);
+ }
+ finishedOCRVisible(false);
+}
+
+void KSANEOCR::slotStopOCR()
+{
+ kdDebug(28000) << "closing ocr Dialog" << endl;
+ if( daemon && daemon->isRunning() )
+ {
+ kdDebug(28000) << "Killing daemon with Sig. 9" << endl;
+ daemon->kill(9);
+ // that leads to the process being destroyed.
+ KMessageBox::error(0, i18n("The OCR-process was stopped.") );
+ }
+
+}
+
+void KSANEOCR::startOCRAD( )
+{
+ ocradDialog *ocrDia = static_cast<ocradDialog*>(m_ocrProcessDia);
+
+ m_ocrResultImage = ocrDia->orfUrl();
+ const QString cmd = ocrDia->getOCRCmd();
+
+ // if( m_ocrResultImage.isEmpty() )
+ {
+ /* The url is empty. Start the program to fill up a temp file */
+ m_ocrResultImage = ImgSaver::tempSaveImage( m_img, "BMP", 8 ); // m_tmpFile->name();
+ kdDebug(28000) << "The new image name is <" << m_ocrResultImage << ">" << endl;
+ }
+
+ m_ocrImagePBM = ImgSaver::tempSaveImage( m_img, "PBM", 1 );
+
+ /* temporar file for orf result */
+ KTempFile *tmpOrf = new KTempFile( QString(), ".orf" );
+ tmpOrf->setAutoDelete( false );
+ tmpOrf->close();
+ m_tmpOrfName = QFile::encodeName(tmpOrf->name());
+
+
+ if( daemon )
+ {
+ delete( daemon );
+ daemon = 0;
+ }
+
+ daemon = new KProcess;
+ Q_CHECK_PTR(daemon);
+
+ *daemon << cmd;
+ *daemon << QString("-x");
+ *daemon << m_tmpOrfName; // the orf result file
+ *daemon << QFile::encodeName( m_ocrImagePBM ); // The name of the image
+ *daemon << QString("-l");
+ *daemon << QString::number( ocrDia->layoutDetectionMode());
+
+ KConfig *konf = KGlobal::config ();
+ KConfigGroupSaver( konf, CFG_GROUP_OCRAD );
+
+ QString format = konf->readEntry( CFG_OCRAD_FORMAT, "utf8");
+ *daemon << QString("-F");
+ *daemon << format;
+
+ QString charset = konf->readEntry( CFG_OCRAD_CHARSET, "iso-8859-15");
+ *daemon << QString("-c");
+ *daemon << charset;
+
+
+ QString addArgs = konf->readEntry( CFG_OCRAD_EXTRA_ARGUMENTS, QString() );
+
+ if( !addArgs.isEmpty() )
+ {
+ kdDebug(28000) << "Setting additional args from config for ocrad: " << addArgs << endl;
+ *daemon << addArgs;
+ }
+
+ m_ocrResultText = "";
+
+ connect(daemon, SIGNAL(processExited(KProcess *)),
+ this, SLOT( ocradExited(KProcess*)));
+ connect(daemon, SIGNAL(receivedStdout(KProcess *, char*, int)),
+ this, SLOT( ocradStdIn(KProcess*, char*, int)));
+ connect(daemon, SIGNAL(receivedStderr(KProcess *, char*, int)),
+ this, SLOT( ocradStdErr(KProcess*, char*, int)));
+
+ if (!daemon->start(KProcess::NotifyOnExit, KProcess::All))
+ {
+ kdDebug(28000) << "Error starting ocrad-daemon!" << endl;
+ }
+ else
+ {
+ kdDebug(28000) << "Start OK" << endl;
+
+ }
+ delete tmpOrf;
+}
+
+
+void KSANEOCR::ocradExited(KProcess* )
+{
+ kdDebug(28000) << "ocrad exit " << endl;
+ QString err;
+ bool parseRes = true;
+
+ if( ! readORF(m_tmpOrfName, err) )
+ {
+ KMessageBox::error( m_parent,
+ i18n("Parsing of the OCR Result File failed:") + err,
+ i18n("Parse Problem"));
+ parseRes = false;
+ }
+ finishedOCRVisible( parseRes );
+
+}
+
+void KSANEOCR::ocradStdErr(KProcess*, char* buffer, int buflen)
+{
+ QString errorBuffer = QString::fromLocal8Bit(buffer, buflen);
+ kdDebug(28000) << "ocrad says on stderr: " << errorBuffer << endl;
+
+}
+
+void KSANEOCR::ocradStdIn(KProcess*, char* buffer, int buflen)
+{
+ QString errorBuffer = QString::fromLocal8Bit(buffer, buflen);
+ kdDebug(28000) << "ocrad says on stdin: " << errorBuffer << endl;
+}
+
+
+
+
+/*
+ * This slot is fired if the user clicks on the 'Start' button of the GUI, no
+ * difference which engine is active.
+ */
+void KSANEOCR::startOCRProcess( void )
+{
+ if( ! m_ocrProcessDia ) return;
+
+ /* starting the animation, setting fields disabled */
+ m_ocrProcessDia->startOCR();
+
+ kapp->processEvents();
+ if( m_ocrEngine == OCRAD )
+ {
+ startOCRAD();
+ }
+
+ if( m_ocrEngine == GOCR )
+ {
+ /*
+ * Starting a gocr process
+ */
+
+ KGOCRDialog *gocrDia = static_cast<KGOCRDialog*>(m_ocrProcessDia);
+
+ const QString cmd = gocrDia->getOCRCmd();
+
+ /* Save the image to a temp file */
+
+ /**
+ * Save images formats:
+ * Black&White: PBM
+ * Gray: PGM
+ * Bunt: PPM
+ */
+ QString format;
+ if( m_img->depth() == 1 )
+ format = "PBM";
+ else if( m_img->isGrayscale() )
+ format = "PGM";
+ else
+ format = "PPM";
+
+ QString tmpFile = ImgSaver::tempSaveImage( m_img, format ); // m_tmpFile->name();
+
+ kdDebug(28000) << "Starting GOCR-Command: " << cmd << " on file " << tmpFile
+ << ", format " << format << endl;
+
+ if( daemon ) {
+ delete( daemon );
+ daemon = 0;
+ }
+
+ daemon = new KProcess;
+ Q_CHECK_PTR(daemon);
+ m_ocrResultText = "";
+
+ connect(daemon, SIGNAL(processExited(KProcess *)),
+ this, SLOT( gocrExited(KProcess*)));
+ connect(daemon, SIGNAL(receivedStdout(KProcess *, char*, int)),
+ this, SLOT( gocrStdIn(KProcess*, char*, int)));
+ connect(daemon, SIGNAL(receivedStderr(KProcess *, char*, int)),
+ this, SLOT( gocrStdErr(KProcess*, char*, int)));
+
+ QString opt;
+ *daemon << QFile::encodeName(cmd);
+ *daemon << "-x";
+ *daemon << "-";
+ if( !( m_img->numColors() > 0 && m_img->numColors() <3 )) /* not a bw-image */
+ {
+ *daemon << "-l";
+ opt.setNum(gocrDia->getGraylevel());
+ *daemon << opt;
+ }
+ *daemon << "-s";
+ opt.setNum(gocrDia->getSpaceWidth());
+ *daemon << opt;
+ *daemon << "-d";
+ opt.setNum(gocrDia->getDustsize());
+ *daemon << opt;
+
+ // Write an result image
+ *daemon << "-v";
+ *daemon << "32";
+
+ // Unfortunately this is fixed by gocr.
+ m_ocrResultImage = "out30.bmp";
+
+ *daemon << QFile::encodeName(tmpFile);
+
+ m_ocrCurrLine = 0; // Important in gocrStdIn to store the results
+
+ if (!daemon->start(KProcess::NotifyOnExit, KProcess::All))
+ {
+ kdDebug(28000) << "Error starting daemon!" << endl;
+ }
+ else
+ {
+ kdDebug(28000) << "Start OK" << endl;
+
+ }
+ }
+#ifdef HAVE_KADMOS
+ if( m_ocrEngine == KADMOS )
+ {
+ KadmosDialog *kadDia = static_cast<KadmosDialog*>(m_ocrProcessDia);
+
+ kdDebug(28000) << "Starting Kadmos OCR Engine" << endl;
+
+ QString clasPath; /* target where the clasPath is written in */
+ if( ! kadDia->getSelClassifier( clasPath ) )
+ {
+ KMessageBox::error( m_parent,
+ i18n("The classifier file necessary for OCR cannot be loaded: %1;\n"
+ "OCR with the KADMOS engine is not possible." ).
+ arg(clasPath), i18n("KADMOS Installation Problem"));
+ finishedOCRVisible(false);
+ return;
+ }
+ QCString c = clasPath.latin1();
+
+ kdDebug(28000) << "Using classifier " << c << endl;
+ m_rep.Init( c );
+ if( m_rep.kadmosError() ) /* check if kadmos initialised OK */
+ {
+ KMessageBox::error( m_parent,
+ i18n("The KADMOS OCR system could not be started:\n") +
+ m_rep.getErrorText()+
+ i18n("\nPlease check the configuration." ),
+ i18n("KADMOS Failure") );
+ }
+ else
+ {
+ /** Since initialising succeeded, we start the ocr here **/
+ m_rep.SetNoiseReduction( kadDia->getNoiseReduction() );
+ m_rep.SetScaling( kadDia->getAutoScale() );
+ kdDebug(28000) << "Image size " << m_img->width() << " x " << m_img->height() << endl;
+ kdDebug(28000) << "Image depth " << m_img->depth() << ", colors: " << m_img->numColors() << endl;
+#define USE_KADMOS_FILEOP /* use a save-file for OCR instead of filling the reImage struct manually */
+#ifdef USE_KADMOS_FILEOP
+ m_tmpFile = new KTempFile( QString(), QString("bmp"));
+ m_tmpFile->setAutoDelete( false );
+ m_tmpFile->close();
+ QString tmpFile = m_tmpFile->name();
+ kdDebug() << "Saving to file " << tmpFile << endl;
+ m_img->save( tmpFile, "BMP" );
+ m_rep.SetImage(tmpFile);
+#else
+ m_rep.SetImage(m_img);
+#endif
+ // rep.Recognize();
+ m_rep.run();
+
+ /* Dealing with threads or no threads (using QT_THREAD_SUPPORT to distinguish)
+ * If threads are here, the recognition task is started in its own thread. The gui thread
+ * needs to wait until the recognition thread is finished. Therefore, a timer is fired once
+ * that calls slotKadmosResult and checks if the recognition task is finished. If it is not,
+ * a new one-shot-timer is fired in slotKadmosResult. If it is, the OCR result can be
+ * processed.
+ * In case the system has no threads, the method start of the recognition engine does not
+ * return until it is ready, the user has to live with a non responsive gui while
+ * recognition is performed. The start()-method is implemented as a wrapper to the run()
+ * method of CRep, which does the recognition job. Instead of pulling up a timer, simply
+ * the result slot is called if start()=run() has finished. In the result slot, finished()
+ * is only a dummy always returning true to avoid more preprocessor tags here.
+ * Hope that works ...
+ * It does not :( That is why it is not used here. Maybe some day...
+ */
+ }
+#ifdef QT_THREAD_SUPPORT
+ /* start a timer and wait until it fires. */
+ QTimer::singleShot( 500, this, SLOT( slotKadmosResult() ));
+#else
+ slotKadmosResult();
+#endif
+
+ }
+#endif /* HAVE_KADMOS */
+}
+
+/*
+ * This method is called to check if the kadmos process was already finished, if
+ * thread support is enabled (check for preprocessor variable QT_THREAD_SUPPORT)
+ * The problem is that the kadmos library seems not to be thread stable so thread
+ * support should not be enabled by default. In case threads are enabled, this slot
+ * checks if the KADMOS engine is finished already and if not it fires a timer.
+ */
+
+void KSANEOCR::slotKadmosResult()
+{
+#ifdef HAVE_KADMOS
+ kdDebug(28000) << "check for Recognition finished" << endl;
+
+
+ if( m_rep.finished() )
+ {
+ /* The recognition thread is finished. */
+ kdDebug(28000) << "kadmos is finished." << endl;
+
+ m_ocrResultText = "";
+ if( ! m_rep.kadmosError() )
+ {
+ int lines = m_rep.GetMaxLine();
+ kdDebug(28000) << "Count lines: " << lines << endl;
+ m_ocrPage.clear();
+ m_ocrPage.resize( lines );
+
+ for( int line = 0; line < m_rep.GetMaxLine(); line++ )
+ {
+ // ocrWordList wordList = m_rep.getLineWords(line);
+ /* call an ocr engine independent method to use the spellbook */
+ ocrWordList words = m_rep.getLineWords(line);
+ kdDebug(28000) << "Have " << words.count() << " entries in list" << endl;
+ m_ocrPage[line]=words;
+ }
+
+ /* show results of ocr */
+ m_rep.End();
+ }
+ finishedOCRVisible( !m_rep.kadmosError() );
+
+ }
+ else
+ {
+ /* recognition thread is not yet finished. Wait another half a second. */
+ QTimer::singleShot( 500, this, SLOT( slotKadmosResult() ));
+ /* Never comes here if no threads exist on the system */
+ }
+#endif /* HAVE_KADMOS */
+}
+
+
+
+
+/*
+ *
+ */
+void KSANEOCR::gocrExited(KProcess* d)
+{
+ kdDebug(28000) << "daemonExited start !" << endl;
+
+ /* Now all the text of gocr is in the member m_ocrResultText. This one must
+ * be split up now to m_ocrPage. First break up the lines, resize m_ocrPage
+ * accordingly and than go through every line and create ocrwords for every
+ * word.
+ */
+ QStringList lines = QStringList::split( '\n', m_ocrResultText, true );
+
+ m_ocrPage.clear();
+ m_ocrPage.resize( lines.count() );
+
+ kdDebug(28000) << "RESULT " << m_ocrResultText << " was splitted to lines " << lines.count() << endl;
+
+ unsigned int lineCnt = 0;
+
+ for ( QStringList::Iterator it = lines.begin(); it != lines.end(); ++it )
+ {
+ kdDebug(28000) << "Splitting up line " << *it << endl;
+ ocrWordList ocrLine;
+
+ QStringList words = QStringList::split( QRegExp( "\\s+" ), *it, false );
+ for ( QStringList::Iterator itWord = words.begin(); itWord != words.end(); ++itWord )
+ {
+ kdDebug(28000) << "Appending to results: " << *itWord << endl;
+ ocrLine.append( ocrWord( *itWord ));
+ }
+ m_ocrPage[lineCnt] = ocrLine;
+ lineCnt++;
+ }
+ kdDebug(28000) << "Finished to split!" << endl;
+ /* set the result pixmap to the result pix of gocr */
+ if( ! m_resPixmap.load( m_ocrResultImage ) )
+ {
+ kdDebug(28000) << "Can not load result image!" << endl;
+ }
+
+ /* load the gocr result image */
+ if( m_img ) delete m_img;
+ m_img = new KookaImage();
+ m_img->load( "out30.bmp" );
+
+ finishedOCRVisible( d->normalExit() );
+}
+
+/*
+ * A sample orf snippet:
+ *
+ * # Ocr Results File. Created by GNU ocrad version 0.3pre1
+ * total blocks 2
+ * block 1 0 0 560 344
+ * lines 5
+ * line 1 chars 10 height 26
+ * 71 109 17 26;2,'0'1,'o'0
+ * 93 109 15 26;2,'1'1,'l'0
+ * 110 109 18 26;1,'2'0
+ * 131 109 18 26;1,'3'0
+ * 151 109 19 26;1,'4'0
+ * 172 109 17 26;1,'5'0
+ * 193 109 17 26;1,'6'0
+ * 213 108 17 27;1,'7'0
+ * 232 109 18 26;1,'8'0
+ * 253 109 17 26;1,'9'0
+ * line 2 chars 14 height 27
+ *
+ */
+
+bool KSANEOCR::readORF( const QString& fileName, QString& errStr )
+{
+ QFile file( fileName );
+ QRegExp rx;
+ bool error = false;
+
+ /* use a global line number counter here, not the one from the orf. The orf one
+ * starts at 0 for every block, but we want line-no counting page global here.
+ */
+ unsigned int lineNo = 0;
+ int blockCnt = 0;
+ int currBlock = -1;
+
+
+ /* Fetch the numeric version of ocrad */
+ ocradDialog *ocrDia = static_cast<ocradDialog*>(m_ocrProcessDia);
+ int ocradVersion = 0;
+ if( ocrDia )
+ {
+ ocradVersion = ocrDia->getNumVersion();
+ }
+
+ /* clear the ocr result page */
+ m_ocrPage.clear();
+ kdDebug(28000) << "***** starting to analyse orf at " << fileName << " *****" << endl;
+
+ /* some checks on the orf */
+ QFileInfo fi( fileName );
+ if( ! fi.exists() ) {
+ error = true;
+ errStr = i18n("The orf %1 does not exist.").arg(fileName);
+ }
+ if( ! error && ! fi.isReadable() ) {
+ error = true;
+ errStr = i18n("Permission denied on file %1.").arg(fileName);
+ }
+
+
+ if ( !error && file.open( IO_ReadOnly ) )
+ {
+ QTextStream stream( &file );
+ QString line;
+ QString recLine; // recognised line
+
+ while ( !stream.atEnd() )
+ {
+ line = stream.readLine().stripWhiteSpace(); // line of text excluding '\n'
+ int len = line.length();
+
+ if( ! line.startsWith( "#" )) // Comments
+ {
+ kdDebug(28000) << "# Line check |" << line << "|" << endl;
+ if( line.startsWith( "total blocks " ) ) // total count fo blocks, must be first line
+ {
+ blockCnt = line.right( len - 13 /* QString("total blocks ").length() */ ).toInt();
+ kdDebug(28000) << "Amount of blocks: " << blockCnt << endl;
+ m_blocks.resize(blockCnt);
+ }
+ else if( line.startsWith( "total text blocks " ))
+ {
+ blockCnt = line.right( len - 18 /* QString("total text blocks ").length() */ ).toInt();
+ kdDebug(28000) << "Amount of blocks (V. 10): " << blockCnt << endl;
+ m_blocks.resize(blockCnt);
+ }
+ else if( line.startsWith( "block ") || line.startsWith( "text block ") )
+ {
+ rx.setPattern("^.*block\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)");
+ if( rx.search( line ) > -1)
+ {
+ currBlock = (rx.cap(1).toInt())-1;
+ kdDebug(28000) << "Setting current block " << currBlock << endl;
+ QRect r( rx.cap(2).toInt(), rx.cap(3).toInt(), rx.cap(4).toInt(), rx.cap(5).toInt());
+ m_blocks[currBlock] = r;
+ }
+ else
+ {
+ kdDebug(28000) << "WRN: Unknown block line: " << line << endl;
+ // Not a killing bug
+ }
+ }
+ else if( line.startsWith( "lines " ))
+ {
+ int lineCnt = line.right( len - 6 /* QString("lines ").length() */).toInt();
+ m_ocrPage.resize(m_ocrPage.size()+lineCnt);
+ kdDebug(28000) << "Resized ocrPage to linecount " << lineCnt << endl;
+ }
+ else if( line.startsWith( "line" ))
+ {
+ // line 5 chars 13 height 20
+ rx.setPattern("^line\\s+(\\d+)\\s+chars\\s+(\\d+)\\s+height\\s+\\d+" );
+ if( rx.search( line )>-1 )
+ {
+ kdDebug(28000) << "RegExp-Result: " << rx.cap(1) << " : " << rx.cap(2) << endl;
+ int charCount = rx.cap(2).toInt();
+ ocrWord word;
+ QRect brect;
+ ocrWordList ocrLine;
+ ocrLine.setBlock(currBlock);
+ /* Loop over all characters in the line. Every char has it's own line
+ * defined in the orf file */
+ kdDebug(28000) << "Found " << charCount << " chars for line " << lineNo << endl;
+
+ for( int c=0; c < charCount && !stream.atEnd(); c++ )
+ {
+ /* Read one line per character */
+ QString charLine = stream.readLine();
+ int semiPos = charLine.find(';');
+ if( semiPos == -1 )
+ {
+ kdDebug(28000) << "invalid line: " << charLine << endl;
+ }
+ else
+ {
+ QString rectStr = charLine.left( semiPos );
+ QString results = charLine.remove(0, semiPos+1 );
+ bool lineErr = false;
+
+ // rectStr contains the rectangle info of for the character
+ // results contains the real result caracter
+
+ // find the amount of alternatives.
+ int altCount = 0;
+ int h = results.find(','); // search the first comma
+ if( h > -1 ) {
+ // kdDebug(28000) << "Results of count search: " << results.left(h) << endl;
+ altCount = results.left(h).toInt();
+ results = results.remove( 0, h+1 ).stripWhiteSpace();
+ } else {
+ lineErr = true;
+ }
+ // kdDebug(28000) << "Results-line after cutting the alter: " << results << endl;
+ QChar detectedChar = UndetectedChar;
+ if( !lineErr )
+ {
+ /* take the first alternative only FIXME */
+ if( altCount > 0 )
+ detectedChar = results[1];
+ // kdDebug(28000) << "Found " << altCount << " alternatives for "
+ // << QString(detectedChar) << endl;
+ }
+
+ /* Analyse the rectangle */
+ if( ! lineErr && detectedChar != ' ' )
+ {
+ // kdDebug(28000) << "STRING: " << rectStr << "<" << endl;
+ rx.setPattern( "(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)");
+ if( rx.search( rectStr ) != -1 )
+ {
+ /* unite the rectangles */
+ QRect privRect( rx.cap(1).toInt(), rx.cap(2).toInt(),
+ rx.cap(3).toInt(), rx.cap(4).toInt() );
+ word.setRect( word.rect() | privRect );
+ }
+ else
+ {
+ kdDebug(28000) << "ERR: Unable to read rect info for char!" << endl;
+ lineErr = true;
+ }
+ }
+
+ if( ! lineErr )
+ {
+ /* store word if finished by a space */
+ if( detectedChar == ' ' )
+ {
+ /* add the block offset to the rect of the word */
+ QRect r = word.rect();
+ if( ocradVersion < 10 )
+ {
+ QRect blockRect = m_blocks[currBlock];
+ r.moveBy( blockRect.x(), blockRect.y());
+ }
+
+ word.setRect( r );
+ ocrLine.append( word );
+ word = ocrWord();
+ }
+ else
+ {
+ word.append( detectedChar );
+ }
+ }
+ }
+ }
+ if( !word.isEmpty() )
+ {
+ /* add the block offset to the rect of the word */
+ QRect r = word.rect();
+ if( ocradVersion < 10 )
+ {
+ QRect blockRect = m_blocks[currBlock];
+ r.moveBy( blockRect.x(), blockRect.y());
+ }
+ word.setRect( r );
+
+ ocrLine.append( word );
+ }
+ if( lineNo < m_ocrPage.size() )
+ {
+ kdDebug(29000) << "Store result line no " << lineNo << "=\"" <<
+ ocrLine.first() << "..." << endl;
+ m_ocrPage[lineNo] = ocrLine;
+ lineNo++;
+ }
+ else
+ {
+ kdDebug(28000) << "ERR: line index overflow: " << lineNo << endl;
+ }
+ }
+ else
+ {
+ kdDebug(28000) << "ERR: Unknown line found: " << line << endl;
+ }
+ }
+ else
+ {
+ kdDebug(29000) << "Unknown line: " << line << endl;
+ }
+ } /* is a comment? */
+
+ }
+ file.close();
+ }
+ return !error;
+}
+
+
+void KSANEOCR::cleanUpFiles( void )
+{
+ if( m_tmpFile )
+ {
+ delete m_tmpFile;
+ m_tmpFile = 0L;
+ }
+
+ if( ! m_ocrResultImage.isEmpty())
+ {
+ kdDebug(28000) << "Unlinking OCR Result image file!" << endl;
+ unlink(QFile::encodeName(m_ocrResultImage));
+ m_ocrResultImage = QString();
+ }
+
+ if( ! m_ocrImagePBM.isEmpty())
+ {
+ kdDebug(28000) << "Unlinking OCR PBM file!" << endl;
+ unlink( QFile::encodeName(m_ocrImagePBM));
+ m_ocrImagePBM = QString();
+ }
+
+ if( ! m_tmpOrfName.isEmpty() )
+ {
+ if( m_unlinkORF )
+ {
+ unlink(QFile::encodeName(m_tmpOrfName));
+ m_tmpOrfName = QString();
+ }
+ else
+ {
+ kdDebug(28000) << "Do NOT unlink temp orf file " << m_tmpOrfName << endl;
+ }
+ }
+
+ /* Delete the debug images of gocr ;) */
+ unlink( "out20.bmp" );
+}
+
+
+void KSANEOCR::gocrStdErr(KProcess*, char* buffer, int buflen)
+{
+ QString errorBuffer = QString::fromLocal8Bit(buffer, buflen);
+ kdDebug(28000) << "gocr says: " << errorBuffer << endl;
+
+}
+
+
+void KSANEOCR::gocrStdIn(KProcess*, char* buffer, int buflen)
+{
+ QString aux = QString::fromLocal8Bit(buffer, buflen);
+
+ QRegExp rx( "^\\s*\\d+\\s+\\d+");
+ if( rx.search( aux ) > -1 )
+ {
+ /* calculate ocr progress for gocr */
+ int progress = rx.capturedTexts()[0].toInt();
+ int subProgress = rx.capturedTexts()[1].toInt();
+ // kdDebug(28000) << "Emitting progress: " << progress << endl;
+ emit ocrProgress( progress, subProgress );
+ }
+ else
+ {
+ m_ocrResultText += aux;
+ }
+
+ // kdDebug(28000) << aux << endl;
+
+}
+
+/*
+ * Assemble the result text
+ */
+QString KSANEOCR::ocrResultText()
+{
+ QString res;
+ const QString space(" ");
+
+ /* start from the back and search the original word to replace it */
+ QValueVector<ocrWordList>::iterator pageIt;
+
+ for( pageIt = m_ocrPage.begin(); pageIt != m_ocrPage.end(); ++pageIt )
+ {
+ /* thats goes over all lines */
+ QValueList<ocrWord>::iterator lineIt;
+ for( lineIt = (*pageIt).begin(); lineIt != (*pageIt).end(); ++lineIt )
+ {
+ res += space + *lineIt;
+ }
+ res += "\n";
+ }
+ kdDebug(28000) << "Returning result String " << res << endl;
+ return res;
+}
+
+
+/* --------------------------------------------------------------------------------
+ * event filter to filter the mouse events to the image viewer
+ */
+
+void KSANEOCR::setImageCanvas( ImageCanvas *canvas )
+{
+ m_imgCanvas = canvas;
+
+ m_imgCanvas->installEventFilter( this );
+}
+
+
+bool KSANEOCR::eventFilter( QObject *object, QEvent *event )
+{
+ QWidget *w = (QWidget*) object;
+
+ if( m_applyFilter && m_imgCanvas && w == m_imgCanvas )
+ {
+ if( event->type() == QEvent::MouseButtonDblClick )
+ {
+ QMouseEvent *mev = static_cast<QMouseEvent*>(event);
+
+ int x = mev->x();
+ int y = mev->y();
+ int scale = m_imgCanvas->getScaleFactor();
+
+ m_imgCanvas->viewportToContents( mev->x(), mev->y(),
+ x, y );
+
+ kdDebug(28000) << "Clicked to " << x << "/" << y << ", scale " << scale << endl;
+ if( scale != 100 )
+ {
+ // Scale is e.g. 50 that means tha the image is only half of size.
+ // thus the clicked coords must be multiplied with 2
+ y = int(double(y)*100/scale);
+ x = int(double(x)*100/scale);
+ }
+ /* now search the word that was clicked on */
+ QValueVector<ocrWordList>::iterator pageIt;
+
+ int line = 0;
+ bool valid = false;
+ ocrWord wordToFind;
+
+ for( pageIt = m_ocrPage.begin(); pageIt != m_ocrPage.end(); ++pageIt )
+ {
+ QRect r = (*pageIt).wordListRect();
+
+ if( y > r.top() && y < r.bottom() )
+ {
+ kdDebug(28000)<< "It is in between " << r.top() << "/" << r.bottom()
+ << ", line " << line << endl;
+ valid = true;
+ break;
+ }
+ line++;
+ }
+
+ /*
+ * If valid, we have the line into which the user clicked. Now we
+ * have to find out the actual word
+ */
+ if( valid )
+ {
+ valid = false;
+ /* find the word in the line and mark it */
+ ocrWordList words = *pageIt;
+ ocrWordList::iterator wordIt;
+
+ for( wordIt = words.begin(); wordIt != words.end() && !valid; ++wordIt )
+ {
+ QRect r = (*wordIt).rect();
+ if( x > r.left() && x < r.right() )
+ {
+ wordToFind = *wordIt;
+ valid = true;
+ }
+ }
+
+ }
+
+ /*
+ * if valid, the wordToFind contains the correct word now.
+ */
+ if( valid )
+ {
+ kdDebug(28000) << "Found the clicked word " << wordToFind << endl;
+ emit selectWord( line, wordToFind );
+ }
+
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+/* --------------------------------------------------------------------------------
+ * Spellbook support
+ */
+
+
+/*
+ * This slot is hit when the checkWord method of KSpell thinks a word is wrong.
+ * KSpell detects the correction by itself and delivers it in newword here.
+ * To see all alternatives KSpell proposes, slMissspelling must be used.
+ */
+void KSANEOCR::slSpellCorrected( const QString& originalword,
+ const QString& newword,
+ unsigned int pos )
+{
+ kdDebug(28000) << "Corrected: Original Word " << originalword << " was corrected to "
+ << newword << ", pos ist " << pos << endl;
+
+ kdDebug(28000) << "Dialog state is " << m_spell->dlgResult() << endl;
+
+ if( slUpdateWord( m_ocrCurrLine, pos, originalword, newword ) )
+ {
+ if( m_imgCanvas && m_currHighlight > -1 )
+ {
+ if( m_applyFilter )
+ m_imgCanvas->removeHighlight( m_currHighlight );
+ }
+ else
+ {
+ kdDebug(28000) << "No highlighting to remove!" << endl;
+ }
+ }
+
+}
+
+
+void KSANEOCR::slSpellIgnoreWord( const QString& word )
+{
+ ocrWord ignoreOCRWord;
+
+ ignoreOCRWord = ocrWordFromKSpellWord( m_ocrCurrLine, word );
+ if( ! ignoreOCRWord.isEmpty() )
+ {
+ emit ignoreWord( m_ocrCurrLine, ignoreOCRWord );
+
+ if( m_imgCanvas && m_currHighlight > -1 )
+ {
+ m_imgCanvas->removeHighlight( m_currHighlight );
+
+ /* create a new highlight. That will never be removed */
+ QBrush brush;
+ QPen pen( gray, 1 );
+ QRect r = ignoreOCRWord.rect();
+ r.moveBy(0,2); // a bit offset to the top
+
+ if( m_applyFilter )
+ m_imgCanvas->highlight( r, pen, brush );
+ }
+ }
+}
+
+ocrWord KSANEOCR::ocrWordFromKSpellWord( int line, const QString& word )
+{
+ ocrWord resWord;
+ if( lineValid(line) )
+ {
+ ocrWordList words = m_ocrPage[line];
+
+ words.findFuzzyIndex( word, resWord );
+ }
+
+ return resWord;
+}
+
+
+bool KSANEOCR::lineValid( int line )
+{
+ bool ret = false;
+
+ if( line >= 0 && (uint)line < m_ocrPage.count() )
+ ret = true;
+
+ return ret;
+}
+
+void KSANEOCR::slMisspelling( const QString& originalword, const QStringList& suggestions,
+ unsigned int pos )
+{
+ /* for the first try, use the first suggestion */
+ ocrWord s( suggestions.first());
+ kdDebug(28000) << "Misspelled: " << originalword << " at position " << pos << endl;
+
+ int line = m_ocrCurrLine;
+ m_currHighlight = -1;
+
+ // ocrWord resWord = ocrWordFromKSpellWord( line, originalword );
+ ocrWordList words = m_ocrPage[line];
+ ocrWord resWord;
+ kdDebug(28000) << "Size of wordlist (line " << line << "): " << words.count() << endl;
+
+ if( pos < words.count() )
+ {
+ resWord = words[pos];
+ }
+
+ if( ! resWord.isEmpty() )
+ {
+ QBrush brush;
+ brush.setColor( QColor(red)); // , "Dense4Pattern" );
+ brush.setStyle( Qt::Dense4Pattern );
+ QPen pen( red, 2 );
+ QRect r = resWord.rect();
+
+ r.moveBy(0,2); // a bit offset to the top
+
+ if( m_applyFilter )
+ m_currHighlight = m_imgCanvas->highlight( r, pen, brush, true );
+
+ kdDebug(28000) << "Position ist " << r.x() << ", " << r.y() << ", width: "
+ << r.width() << ", height: " << r.height() << endl;
+
+ /* draw a line under the word to check */
+
+ /* copy the source */
+ emit repaintOCRResImage();
+ }
+ else
+ {
+ kdDebug(28000) << "Could not find the ocrword for " << originalword << endl;
+ }
+
+ emit markWordWrong( line, resWord );
+}
+
+/*
+ * This is the global starting point for spell checking of the ocr result.
+ * After the KSpell object was created in method finishedOCRVisible, this
+ * slot is called if the KSpell-object feels itself ready for operation.
+ * Coming into this slot, the spelling starts in a line by line manner
+ */
+void KSANEOCR::slSpellReady( KSpell *spell )
+{
+ m_spell = spell;
+ connect ( m_spell, SIGNAL( misspelling( const QString&, const QStringList&,
+ unsigned int )),
+ this, SLOT( slMisspelling(const QString& ,
+ const QStringList& ,
+ unsigned int )));
+ connect( m_spell, SIGNAL( corrected ( const QString&, const QString&, unsigned int )),
+ this, SLOT( slSpellCorrected( const QString&, const QString&, unsigned int )));
+
+ connect( m_spell, SIGNAL( ignoreword( const QString& )),
+ this, SLOT( slSpellIgnoreWord( const QString& )));
+
+ connect( m_spell, SIGNAL( done(bool)), this, SLOT(slCheckListDone(bool)));
+
+ kdDebug(28000) << "Spellcheck available" << endl;
+
+ if( m_ocrProcessDia && m_hideDiaWhileSpellcheck )
+ m_ocrProcessDia->hide();
+ emit readOnlyEditor( true );
+ startLineSpellCheck();
+}
+
+/**
+ * slot called after either the spellcheck finished or the KSpell object found
+ * out that it does not want to run because of whatever problems came up.
+ * If it is an KSpell-init problem, the m_spell variable is still zero and
+ * Kooka pops up a warning.
+ */
+void KSANEOCR::slSpellDead()
+{
+ if( ! m_spell )
+ {
+ kdDebug(28000) << "Spellcheck NOT available" << endl;
+ /* Spellchecking has not yet been existing, thus there is a base problem with
+ * spellcheck on this system.
+ */
+ KMessageBox::error( m_parent,
+ i18n("Spell-checking cannot be started on this system.\n"
+ "Please check the configuration" ),
+ i18n("Spell-Check") );
+
+ }
+ else
+ {
+ if( m_spell->status() == KSpell::Cleaning )
+ {
+ kdDebug(28000) << "KSpell cleans up" << endl;
+ }
+ else if( m_spell->status() == KSpell::Finished )
+ {
+ kdDebug(28000) << "KSpell finished" << endl;
+ }
+ else if( m_spell->status() == KSpell::Error )
+ {
+ kdDebug(28000) << "KSpell finished with Errors" << endl;
+ }
+ else if( m_spell->status() == KSpell::Crashed )
+ {
+ kdDebug(28000) << "KSpell Chrashed" << endl;
+ }
+ else
+ {
+ kdDebug(28000) << "KSpell finished with unknown state!" << endl;
+ }
+
+ /* save the current config */
+ delete m_spell;
+ m_spell = 0L;
+
+ /* reset values */
+ m_checkStrings.clear();
+ m_ocrCurrLine = 0;
+ if( m_imgCanvas && m_currHighlight > -1 )
+ m_imgCanvas->removeHighlight( m_currHighlight );
+
+ }
+ if( m_ocrProcessDia )
+ m_ocrProcessDia->show();
+ emit readOnlyEditor( false );
+}
+
+
+/**
+ * This slot reads the current line from the member m_ocrCurrLine and
+ * writes the corrected wordlist to the member page word lists
+ */
+void KSANEOCR::slCheckListDone(bool)
+{
+
+ /*
+ * nothing needs to be updated here in the texts, because it is already done
+ * in the slSpellCorrected slot
+ */
+
+ /* Check the dialog state here */
+ if( m_spell->dlgResult() == KS_CANCEL ||
+ m_spell->dlgResult() == KS_STOP )
+ {
+ /* stop processing */
+ m_spell->cleanUp();
+ }
+ else
+ {
+ m_ocrCurrLine++;
+ kdDebug(28000) << "Starting spellcheck from CheckListDone" << endl;
+ startLineSpellCheck();
+ }
+}
+
+/**
+ * updates the word at position spellWordIndx in line line to the new word newWord.
+ * The original word was origWord. This slot is called from slSpellCorrected
+ *
+ */
+bool KSANEOCR::slUpdateWord( int line, int spellWordIndx, const QString& origWord,
+ const QString& newWord )
+{
+ bool result = false;
+
+ if( lineValid( line ))
+ {
+ ocrWordList words = m_ocrPage[line];
+ kdDebug(28000) << "Updating word " << origWord << " to " << newWord << endl;
+
+ if( words.updateOCRWord( words[spellWordIndx] /* origWord */, newWord ) ) // searches for the word and updates
+ {
+ result = true;
+ emit updateWord( line, origWord, newWord );
+ }
+ else
+ kdDebug(28000) << "WRN: Update from " << origWord << " to " << newWord << " failed" << endl;
+
+ }
+ else
+ {
+ kdDebug(28000) << "WRN: Line " << line << " no not valid!" << endl;
+ }
+ return result;
+}
+
+
+char KSANEOCR::UndetectedChar = '_';
+
+/* -- */
+#include "ksaneocr.moc"
diff --git a/kooka/ksaneocr.h b/kooka/ksaneocr.h
new file mode 100644
index 00000000..425718dc
--- /dev/null
+++ b/kooka/ksaneocr.h
@@ -0,0 +1,285 @@
+/***************************************************************************
+ ksaneocr.h - ocr-engine class
+ -------------------
+ begin : Fri Jun 30 2000
+ copyright : (C) 2000 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef KSANEOCR_H
+#define KSANEOCR_H
+#include <qwidget.h>
+#include <qobject.h>
+
+#include "ocrword.h"
+
+#define CFG_OCR_ENGINE "ocrEngine"
+#define CFG_OCR_CLEANUP "unlinkORF" /* delete orf file? */
+
+#define CFG_OCR_KSPELL "ocrSpellSettings"
+#define CFG_WANT_KSPELL "ocrKSpellEnabled"
+#define CFG_KS_NOROOTAFFIX "KSpell_NoRootAffix"
+#define CFG_KS_RUNTOGETHER "KSpell_RunTogether"
+#define CFG_KS_DICTIONARY "KSpell_Dictionary"
+#define CFG_KS_DICTFROMLIST "KSpell_DictFromList"
+#define CFG_KS_ENCODING "KSpell_Encoding"
+#define CFG_KS_CLIENT "KSpell_Client"
+
+
+#define HIDE_BASE_DIALOG "hideOCRDialogWhileSpellCheck"
+/**
+ *@author Klaas Freitag
+ */
+
+class KOCRBase;
+class KookaImage;
+class KTempFile;
+class KProcess;
+class QRect;
+class QPixmap;
+class QStringList;
+class KSpell;
+class KSpellConfig;
+class ImageCanvas;
+class KConfig;
+// class ocrWord;
+// class ocrPage;
+
+#ifdef HAVE_KADMOS
+#include "kadmosocr.h"
+#endif
+
+/*
+ * Error Classifier the report errors on bad engine setup
+ */
+typedef enum{ ENG_ERROR, ENG_OK, ENG_DATA_MISSING, ENG_BAD_SETUP } EngineError;
+
+class KSANEOCR : public QObject
+{
+ Q_OBJECT
+public:
+ enum OCREngines{ GOCR, OCRAD, KADMOS };
+
+ KSANEOCR( QWidget*, KConfig *);
+ ~KSANEOCR();
+
+ bool startOCRVisible( QWidget* parent=0);
+
+ void finishedOCRVisible( bool );
+
+ /**
+ * checks after a ocr run if the line number exists in the result
+ */
+ bool lineValid( int line );
+
+#ifdef HAVE_KADMOS
+ bool startKadmosOCR();
+#endif
+
+ /**
+ * return the final ocr result
+ */
+
+ QString ocrResultText();
+
+ /**
+ * @return the current spell config.
+ */
+ KSpellConfig* ocrSpellConfig() const
+ { return m_spellInitialConfig; }
+
+
+ /**
+ * Sets an image Canvas that displays the result image of ocr. If this
+ * is set to zero (or never set) no result image is displayed.
+ * The ocr fabric passes a new image to the canvas which is a copy of
+ * the image to ocr.
+ */
+ void setImageCanvas( ImageCanvas* canvas );
+
+signals:
+ void newOCRResultText( const QString& );
+ void clearOCRResultText();
+ void newOCRResultPixmap( const QPixmap& );
+
+ /**
+ * progress of the ocr process. The first integer is the main progress,
+ * the second the sub progress. If there is only on progress, it is the
+ * first parameter, the second is always -1 than.
+ * Both have a range from 0..100.
+ * Note that this signal may not be emitted if the engine does not support
+ * progress.
+ */
+ void ocrProgress(int, int);
+
+ /**
+ * select a word in the editor in line line.
+ */
+ void selectWord( int line, const ocrWord& word );
+
+ /**
+ * signal to indicate that a ocr text must be updated due to better results
+ * retrieved from spell check. The internal ocr data structure is already
+ * updated when this signal is fired.
+ *
+ * @param line the line in which the word must be changed (start at 0)
+ * @param wordFrom the original word
+ * @param wordTo the new word(s).
+ */
+ void updateWord( int line, const QString& wordFrom, const QString& wordTo );
+
+ /**
+ * signal to indicate that word word was ignored by the user. This should result
+ * in a special coloring in the editor.
+ */
+ void ignoreWord( int, const ocrWord& );
+
+ /**
+ * signal that comes if a word is considered to be wrong in the editor.
+ * The word should be marked in any way, e.g. with a signal color.
+ **/
+ void markWordWrong( int, const ocrWord& );
+
+ /**
+ * signal the tells that the result image was modified.
+ */
+ void repaintOCRResImage( );
+
+ /**
+ * indicates that the text editor holding the text that came through
+ * newOCRResultText should be set to readonly or not. Can be connected
+ * to QTextEdit::setReadOnly directly.
+ */
+ void readOnlyEditor( bool );
+
+public slots:
+ void slSetImage( KookaImage* );
+
+ void slLineBox( const QRect& );
+
+protected:
+ /**
+ * Start spell checking on a specific line that is stored in m_ocrCurrLine.
+ * This method starts the spell checking.
+ **/
+ void startLineSpellCheck();
+ ocrWord ocrWordFromKSpellWord( int line, const QString& word );
+
+ /**
+ * Eventhandler to handle the mouse events to the image viewer showing the
+ * ocr result image
+ */
+ bool eventFilter( QObject *object, QEvent *event );
+
+ void startOCRAD();
+protected slots:
+ void slotClose ();
+ void slotStopOCR();
+
+ void slSpellReady( KSpell* );
+ void slSpellDead( );
+ /**
+ * a new list of ocr results of the current ocr process arrived and is available
+ * in the member m_ocrPage[line]
+ */
+ // void gotOCRLine( int line );
+
+ void slMisspelling( const QString& originalword,
+ const QStringList& suggestions,
+ unsigned int pos );
+ void slSpellCorrected( const QString& originalword,
+ const QString& newword,
+ unsigned int pos );
+
+ void slSpellIgnoreWord( const QString& word );
+
+ void slCheckListDone( bool );
+
+ bool slUpdateWord( int line, int spellWordIndx,
+ const QString& origWord,
+ const QString& newWord );
+
+private slots:
+
+ void slotKadmosResult();
+ void startOCRProcess( void );
+ void gocrStdIn(KProcess*, char* buffer, int buflen);
+ void gocrStdErr(KProcess*, char* buffer, int buflen);
+ void gocrExited(KProcess*);
+
+ void ocradStdIn(KProcess*, char* buffer, int buflen);
+ void ocradStdErr(KProcess*, char* buffer, int buflen);
+ void ocradExited(KProcess*);
+
+ /*
+ * reads orf files from a file and fills the result structures
+ * accordingly.
+ */
+ bool readORF( const QString&, QString& );
+
+private:
+ void cleanUpFiles( void );
+
+
+ KOCRBase *m_ocrProcessDia;
+ KProcess *daemon;
+ bool visibleOCRRunning;
+ KTempFile *m_tmpFile;
+
+ KookaImage *m_img;
+ QString m_ocrResultText;
+ QString m_ocrResultImage;
+ QString m_ocrImagePBM;
+ QString m_tmpOrfName;
+ QImage *m_resultImage;
+
+ OCREngines m_ocrEngine;
+ QPixmap m_resPixmap;
+ QPixmap m_storePixmap;
+
+ ImageCanvas *m_imgCanvas;
+
+ KSpell *m_spell;
+ bool m_wantKSpell;
+ bool m_kspellVisible;
+ bool m_hideDiaWhileSpellcheck;
+ KSpellConfig *m_spellInitialConfig;
+
+ /* ValueVector of wordLists for every line of ocr results */
+ ocrBlock m_ocrPage; /* one block contains all lines of the page */
+ QWidget *m_parent;
+ /* current processed line to speed kspell correction */
+ unsigned m_ocrCurrLine;
+ QStringList m_checkStrings;
+
+ int m_currHighlight;
+ bool m_applyFilter;
+
+ bool m_unlinkORF;
+ rectList m_blocks; // dimensions of blocks
+
+ static char UndetectedChar;
+#ifdef HAVE_KADMOS
+ Kadmos::CRep m_rep;
+#endif
+};
+
+#endif
diff --git a/kooka/main.cpp b/kooka/main.cpp
new file mode 100644
index 00000000..086d3ddf
--- /dev/null
+++ b/kooka/main.cpp
@@ -0,0 +1,121 @@
+/***************************************************************************
+ main.cpp - description
+ -------------------
+ begin : Thu Dec 9 20:16:54 MET 1999
+
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include <qdict.h>
+#include <qpixmap.h>
+
+#include <kapplication.h>
+#include <dcopclient.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kimageio.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+#include <kwin.h>
+
+#include "kooka.h"
+#include "version.h"
+
+static const char description[] =
+ "Kooka is a KDE application which provides access to scanner hardware\n"
+ "using the SANE library.\n"
+ "Kooka helps you scan, save your image in the correct image format\n"
+ "and perform Optical Character Recognition on it, using gocr, Joerg\n"
+ "Schulenburg's and friends' Open Source ocr program.";
+
+static const char license[] =
+"This program is distributed under the terms of the GPL v2 as publishec by\n"
+"the Free Software Foundation\n\n"
+"As a special exception, permission is given to link this program\n"
+"with any version of the KADMOS ocr/icr engine of reRecognition GmbH,\n"
+"Kreuzlingen and distribute the resulting executable without\n"
+"including the source code for KADMOS in the source distribution.\n\n"
+"As a special exception, permission is given to link this program\n"
+"with any edition of Qt, and distribute the resulting executable,\n"
+"without including the source code for Qt in the source distribution.\n";
+
+
+static KCmdLineOptions options[] =
+{
+ { "d ", I18N_NOOP("The SANE compatible device specification (e.g. umax:/dev/sg0)"), "" },
+ { "g", I18N_NOOP("Gallery mode - do not connect to scanner"), "" },
+ KCmdLineLastOption
+};
+
+
+
+int main( int argc, char *argv[] )
+{
+ KAboutData about("kooka", I18N_NOOP("Kooka"), KOOKA_VERSION, I18N_NOOP(description),
+ KAboutData::License_GPL_V2, "(C) 2000 Klaas Freitag", 0,
+ I18N_NOOP("http://kooka.kde.org"));
+
+ about.addAuthor( "Klaas Freitag", I18N_NOOP("developer"), "freitag@suse.de" );
+ about.addAuthor( "Mat Colton", I18N_NOOP("graphics, web"), "mat@colton.de" );
+ about.setLicenseText( license );
+
+ KCmdLineArgs::init(argc, argv, &about);
+ KCmdLineArgs::addCmdLineOptions( options ); // Add my own options.
+
+ KApplication app;
+ KGlobal::locale()->insertCatalogue("libkscan");
+ KImageIO::registerFormats();
+ KIconLoader *loader = KGlobal::iconLoader();
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ QCString devToUse = args->getOption( "d" );
+ if( args->isSet("g") )
+ {
+ devToUse = "gallery";
+ }
+ kdDebug( 29000) << "DevToUse is " << devToUse << endl;
+
+ if (args->count() == 1)
+ {
+ args->usage();
+ // exit(-1);
+ }
+
+
+ Kooka *kooka = new Kooka(devToUse);
+ app.setMainWidget( kooka );
+
+ KWin::setIcons(kooka->winId(), loader->loadIcon( "scanner", KIcon::Desktop ),
+ loader->loadIcon("scanner", KIcon::Small) );
+
+ kooka->show();
+ app.processEvents();
+ kooka->startup();
+ args->clear();
+ int ret = app.exec();
+
+ return ret;
+
+}
diff --git a/kooka/ocrresedit.cpp b/kooka/ocrresedit.cpp
new file mode 100644
index 00000000..a289a079
--- /dev/null
+++ b/kooka/ocrresedit.cpp
@@ -0,0 +1,148 @@
+/***************************************************************************
+ ocrresedit.cpp - ocr result editor widget
+ -------------------
+ begin : Tue 12 Feb 2003
+ copyright : (C) 2003 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+#include <qcolor.h>
+
+#include "ocrresedit.h"
+#include "ocrword.h"
+#include <kdebug.h>
+#include <kfiledialog.h>
+#include <klocale.h>
+
+#include <qfile.h>
+#include <qtextstream.h>
+
+/* -------------------- ocrResEdit -------------------- */
+
+ocrResEdit::ocrResEdit( QWidget *parent )
+ : QTextEdit(parent)
+{
+ m_updateColor.setNamedColor( "SeaGreen");
+ m_ignoreColor.setNamedColor( "CadetBlue4" );
+ m_wrnColor.setNamedColor( "firebrick2" );
+}
+
+
+void ocrResEdit::slMarkWordWrong( int line, const ocrWord& word )
+{
+ // m_textEdit->setSelection( line,
+ slReplaceWord( line, word, word, m_wrnColor );
+}
+
+
+void ocrResEdit::slUpdateOCRResult( int line, const QString& wordFrom,
+ const QString& wordTo )
+{
+ /* the index is quite useless here, since the text could have had been
+ * changed by corrections before. Thus better search the word and update
+ * it.
+ */
+ slReplaceWord( line, wordFrom, wordTo, m_updateColor );
+
+}
+
+
+void ocrResEdit::slIgnoreWrongWord( int line, const ocrWord& word )
+{
+ slReplaceWord( line, word, word, m_ignoreColor );
+}
+
+
+void ocrResEdit::slSelectWord( int line, const ocrWord& word )
+{
+ if( line < paragraphs() )
+ {
+ QString editLine = text(line);
+ int cnt = editLine.contains( word);
+
+ if( cnt > 0 )
+ {
+ int pos = editLine.find(word);
+ setCursorPosition( line, pos );
+ setSelection( line, pos, line, pos + word.length());
+ }
+ }
+}
+
+void ocrResEdit::slReplaceWord( int line, const QString& wordFrom,
+ const QString& wordTo, const QColor& color )
+{
+ kdDebug(28000) << "Updating word " << wordFrom << " in line " << line << endl;
+
+ bool isRO = isReadOnly();
+
+ if( line < paragraphs() )
+ {
+ QString editLine = text(line);
+ int cnt = editLine.contains( wordFrom );
+
+ if( cnt > 0 )
+ {
+ int pos = editLine.find(wordFrom);
+ setSelection( line, pos, line, pos+wordFrom.length());
+
+ QColor saveCol = this->color();
+ setColor( color );
+ if( isRO ) {
+ setReadOnly(false);
+ }
+ insert( wordTo, unsigned (4) );
+ if( isRO ) {
+ setReadOnly( true );
+ }
+ setColor(saveCol);
+ }
+ else
+ {
+ kdDebug(28000) << "WRN: Paragraph does not contain word " << wordFrom << endl;
+ }
+
+ }
+ else
+ {
+ kdDebug(28000) << "WRN: editor does not have line " << line << endl;
+ }
+}
+
+
+void ocrResEdit::slSaveText()
+{
+ QString fileName = KFileDialog::getSaveFileName( (QDir::home()).path(),
+ "*.txt",
+ this,
+ i18n("Save OCR Result Text") );
+ if( fileName.isEmpty() )
+ return;
+ QFile file( fileName );
+ if ( file.open( IO_WriteOnly ) )
+ {
+ QTextStream stream( &file );
+ stream << text();
+ file.close();
+ }
+}
+
+#include "ocrresedit.moc"
+/* */
diff --git a/kooka/ocrresedit.h b/kooka/ocrresedit.h
new file mode 100644
index 00000000..6c483db4
--- /dev/null
+++ b/kooka/ocrresedit.h
@@ -0,0 +1,65 @@
+/***************************************************************************
+ ocrresedit.h - ocr-result edit widget
+ -------------------
+ begin : Fri 12 Feb 2003
+ copyright : (C) 2003 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef _OCR_RESEDIT_
+#define _OCR_RESEDIT_
+
+#include <qtextedit.h>
+
+class QString;
+class QColor;
+class ocrWord;
+
+class ocrResEdit : public QTextEdit
+{
+ Q_OBJECT
+public:
+ ocrResEdit( QWidget *parent );
+
+public slots:
+ void slUpdateOCRResult( int line, const QString& wordFrom,
+ const QString& wordTo );
+
+ void slMarkWordWrong( int line, const ocrWord& word );
+
+ void slIgnoreWrongWord( int line, const ocrWord& word );
+
+ void slSelectWord( int line, const ocrWord& word );
+
+ void slSaveText();
+
+protected slots:
+ void slReplaceWord( int line, const QString& wordFrom,
+ const QString& wordTo, const QColor& color );
+
+private:
+ QColor m_updateColor;
+ QColor m_ignoreColor;
+ QColor m_wrnColor;
+
+};
+
+#endif
diff --git a/kooka/ocrword.cpp b/kooka/ocrword.cpp
new file mode 100644
index 00000000..1bd29f3e
--- /dev/null
+++ b/kooka/ocrword.cpp
@@ -0,0 +1,157 @@
+/***************************************************************************
+ ocrword.cpp - ocr-result word and wordlist
+ -------------------
+ begin : Fri Jan 10 2003
+ copyright : (C) 2003 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include <qstring.h>
+#include "ocrword.h"
+#include <qrect.h>
+#include <qptrlist.h>
+#include <kdebug.h>
+#include <qregexp.h>
+
+/* -------------------- ocrWord -------------------- */
+ocrWord::ocrWord( const QString& s )
+ : QString(s)
+{
+
+}
+
+ocrWord::ocrWord() : QString()
+{
+
+}
+
+#if 0
+QRect ocrWord::boundingRect()
+{
+ QRect r;
+
+ return r;
+}
+#endif
+
+/* -------------------- CocrWordList ------------------ */
+ocrWordList::ocrWordList()
+ :QValueList<ocrWord>(),
+ m_block(0)
+{
+ // setAutoDelete( true );
+}
+
+QStringList ocrWordList::stringList()
+{
+ QStringList res;
+ QRegExp rx("[,\\.-]");
+ ocrWordList::iterator it;
+
+ for ( it = begin(); it != end(); ++it )
+ {
+#if 0
+ /* Uncommented this to prevent an error that occurs if the lenght of the
+ * spellchecked stringlist and the ocr_page wordlist are not the same length.
+ * For the ocrpage words connected with a dash are one word while the code
+ * below parts them into two. That confuses the replacement code if the user
+ * decided. Solution: KSpell should treat dash-linked words correctly.
+ * We live with the problem here that dashes bring confusion ;-)
+ */
+ if( (*it).contains( rx ) )
+ res += QStringList::split( rx, (*it) );
+ else
+#endif
+ res << *it;
+ }
+ return res;
+
+}
+
+bool ocrWordList::updateOCRWord( const QString& from, const QString& to )
+{
+ ocrWordList::iterator it;
+ bool res = false;
+
+ for( it = begin(); it != end(); ++it )
+ {
+ QString word = (*it);
+ kdDebug(28000) << "updateOCRWord in list: Comparing word " << word << endl;
+ if( word.contains( from, true ) ) // case sensitive search
+ {
+ word.replace( from, to );
+ *it = ocrWord( word );
+ res = true;
+ break;
+ }
+ }
+ return res;
+}
+
+QRect ocrWordList::wordListRect()
+{
+ QRect rect;
+
+ ocrWordList::iterator it;
+
+ for( it = begin(); it != end(); ++it )
+ {
+ rect = rect.unite( (*it).rect() );
+ }
+ return rect;
+}
+
+
+/*
+ * since kspell removes , - | / etc. from words while they remain in the words
+ * in the ocr wordlist.
+ * This search goes through the wordlist and tries to find the words without caring
+ * for special chars. It simply removes all chars from the words that are not alphanumeric.
+ */
+bool ocrWordList::findFuzzyIndex( const QString& word, ocrWord& resWord )
+{
+ ocrWordList::iterator it;
+ bool res = false;
+
+ for( it = begin(); it != end() && !res; ++it )
+ {
+ QString fuzzyword = (*it);
+ fuzzyword.remove( QRegExp( "\\W" )); // Remove all non-word characters.
+ fuzzyword.remove( '_' );
+
+ // kdDebug(28000) << "findFuzzy: Comparing word " << fuzzyword << " which was "
+ // << (*it) << " with " << word << endl;
+ if( fuzzyword == word )
+ {
+ resWord = *it;
+ res = true;
+ }
+ }
+ return res;
+
+}
+
+void ocrWordList::setBlock( int b )
+{
+ m_block = b;
+}
+
+/* */
diff --git a/kooka/ocrword.h b/kooka/ocrword.h
new file mode 100644
index 00000000..606acb9f
--- /dev/null
+++ b/kooka/ocrword.h
@@ -0,0 +1,111 @@
+/***************************************************************************
+ ocrword.h - ocr-result word and wordlist
+ -------------------
+ begin : Fri 10 Jan 2003
+ copyright : (C) 2003 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef _OCR_WORD_
+#define _OCR_WORD_
+
+#include <qstringlist.h>
+#include <qvaluevector.h>
+#include <qvaluelist.h>
+#include <qrect.h>
+
+class QString;
+class QRect;
+
+
+/* ==== ocrWord ====================================== */
+class ocrWord : public QString
+{
+public:
+ ocrWord(const QString& s);
+ ocrWord();
+ QStringList getAlternatives()
+ { return m_alternatives; }
+
+ void setAlternatives( const QString& s )
+ { m_alternatives.append(s); }
+
+ // QRect boundingRect();
+
+ void setKnode( int k )
+ { m_startKnode = k; }
+ void setLine( int l )
+ { m_line = l; }
+
+ int getLine() const { return m_line; }
+ int getKnode() const { return m_startKnode; }
+
+ void setRect( const QRect& r )
+ { m_position = r; }
+ QRect rect()
+ { return m_position; }
+
+private:
+ QStringList m_alternatives;
+ int m_startKnode;
+ int m_line;
+ QRect m_position;
+};
+
+/* ==== ocrWordList ====================================== */
+
+/**
+ * This represents a line of words in an ocr'ed document
+ */
+class ocrWordList : public QValueList<ocrWord>
+{
+public:
+ ocrWordList();
+ QStringList stringList();
+
+ bool updateOCRWord( const QString& from, const QString& to );
+
+ bool findFuzzyIndex( const QString& word, ocrWord& resWord );
+
+ QRect wordListRect( );
+
+ void setBlock( int b );
+ int block() const { return m_block; }
+
+private:
+ int m_block;
+};
+
+/**
+ * All lines of a block: A value vector containing as much as entries
+ * as lines are available in a block. Needs to be resized acordingly.
+ */
+typedef QValueVector<ocrWordList> ocrBlock;
+
+/**
+ * Blocks taken together form the page.
+ * Attention: Needs to be resized to the amount of blocks !!
+ */
+typedef QValueVector<ocrBlock> ocrBlockPage;
+
+typedef QValueVector<QRect> rectList;
+
+#endif
diff --git a/kooka/pics/Makefile.am b/kooka/pics/Makefile.am
new file mode 100644
index 00000000..f8f4440b
--- /dev/null
+++ b/kooka/pics/Makefile.am
@@ -0,0 +1,8 @@
+# Add all of your pixmaps here
+pics_DATA = mirror-both.png mirror-horiz.png mirror-vert.png scaletoheight.png \
+ scaletowidth.png scaleorig.png ocr.png ocr-select.png newfromselect.png \
+ thumbviewtile.png gocr.png ocrad.png lockzoom.png
+
+
+# This is where it will all be installed
+picsdir = $(kde_datadir)/kooka/pics
diff --git a/kooka/pics/gocr.png b/kooka/pics/gocr.png
new file mode 100644
index 00000000..575ebea9
--- /dev/null
+++ b/kooka/pics/gocr.png
Binary files differ
diff --git a/kooka/pics/lockzoom.png b/kooka/pics/lockzoom.png
new file mode 100644
index 00000000..dbfa1a7e
--- /dev/null
+++ b/kooka/pics/lockzoom.png
Binary files differ
diff --git a/kooka/pics/mirror-both.png b/kooka/pics/mirror-both.png
new file mode 100644
index 00000000..e275689b
--- /dev/null
+++ b/kooka/pics/mirror-both.png
Binary files differ
diff --git a/kooka/pics/mirror-horiz.png b/kooka/pics/mirror-horiz.png
new file mode 100644
index 00000000..eb537f40
--- /dev/null
+++ b/kooka/pics/mirror-horiz.png
Binary files differ
diff --git a/kooka/pics/mirror-vert.png b/kooka/pics/mirror-vert.png
new file mode 100644
index 00000000..d3c29462
--- /dev/null
+++ b/kooka/pics/mirror-vert.png
Binary files differ
diff --git a/kooka/pics/newfromselect.png b/kooka/pics/newfromselect.png
new file mode 100644
index 00000000..93a75ec8
--- /dev/null
+++ b/kooka/pics/newfromselect.png
Binary files differ
diff --git a/kooka/pics/ocr-select.png b/kooka/pics/ocr-select.png
new file mode 100644
index 00000000..db076898
--- /dev/null
+++ b/kooka/pics/ocr-select.png
Binary files differ
diff --git a/kooka/pics/ocr.png b/kooka/pics/ocr.png
new file mode 100644
index 00000000..c68f0616
--- /dev/null
+++ b/kooka/pics/ocr.png
Binary files differ
diff --git a/kooka/pics/ocrad.png b/kooka/pics/ocrad.png
new file mode 100644
index 00000000..01e41184
--- /dev/null
+++ b/kooka/pics/ocrad.png
Binary files differ
diff --git a/kooka/pics/scaleorig.png b/kooka/pics/scaleorig.png
new file mode 100644
index 00000000..8c696f48
--- /dev/null
+++ b/kooka/pics/scaleorig.png
Binary files differ
diff --git a/kooka/pics/scaletoheight.png b/kooka/pics/scaletoheight.png
new file mode 100644
index 00000000..b84d971b
--- /dev/null
+++ b/kooka/pics/scaletoheight.png
Binary files differ
diff --git a/kooka/pics/scaletowidth.png b/kooka/pics/scaletowidth.png
new file mode 100644
index 00000000..90e33617
--- /dev/null
+++ b/kooka/pics/scaletowidth.png
Binary files differ
diff --git a/kooka/pics/thumbviewtile.png b/kooka/pics/thumbviewtile.png
new file mode 100644
index 00000000..6f806851
--- /dev/null
+++ b/kooka/pics/thumbviewtile.png
Binary files differ
diff --git a/kooka/resource.h b/kooka/resource.h
new file mode 100644
index 00000000..51c9488f
--- /dev/null
+++ b/kooka/resource.h
@@ -0,0 +1,94 @@
+/***************************************************************************
+ resource.h - description
+ -------------------
+ begin : Thu Dec 9 20:16:54 MET 1999
+
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef RESSOURCE_H
+#define RESSOURCE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+///////////////////////////////////////////////////////////////////
+// resource.h -- contains macros used for commands
+
+
+///////////////////////////////////////////////////////////////////
+// COMMAND VALUES FOR MENUBAR AND TOOLBAR ENTRIES
+
+
+///////////////////////////////////////////////////////////////////
+// File-menu entries
+#define ID_FILE_NEW 10020
+#define ID_FILE_OPEN 10030
+
+#define ID_FILE_SAVE 10050
+#define ID_FILE_SAVE_AS 10060
+#define ID_FILE_CLOSE 10070
+
+#define ID_FILE_PRINT 10080
+
+#define ID_FILE_QUIT 10100
+
+
+///////////////////////////////////////////////////////////////////
+// Edit-menu entries
+#define ID_EDIT_UNDO 11010
+#define ID_EDIT_REDO 11020
+#define ID_EDIT_COPY 11030
+#define ID_EDIT_CUT 11040
+#define ID_EDIT_PASTE 11050
+#define ID_EDIT_SELECT_ALL 11060
+
+
+///////////////////////////////////////////////////////////////////
+// View-menu entries
+#define ID_VIEW_TOOLBAR 12010
+#define ID_VIEW_STATUSBAR 12020
+#define ID_VIEW_PREVIEW 12021
+#define ID_VIEW_POOL 12022
+#define ID_VIEW_SCANPARAMS 12023
+
+
+///////////////////////////////////////////////////////////////////
+// View-menu entries
+#define ID_SCAN_PREVIEW 13010
+#define ID_SCAN_FINAL 13020
+
+///////////////////////////////////////////////////////////////////
+// Help-menu entries
+#define ID_HELP_ABOUT 1002
+
+///////////////////////////////////////////////////////////////////
+// General application values
+#define IDS_APP_ABOUT "Ksanetest\n Version " VERSION
+
+#define IDS_DEFAULT "Ready."
+
+#endif // RESOURCE_H
+
+
diff --git a/kooka/scanpackager.cpp b/kooka/scanpackager.cpp
new file mode 100644
index 00000000..7af7f151
--- /dev/null
+++ b/kooka/scanpackager.cpp
@@ -0,0 +1,1261 @@
+/***************************************************************************
+ scanpackager.cpp - description
+ -------------------
+ begin : Fri Dec 17 1999
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+
+ $Id$
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include "scanpackager.h"
+#include "resource.h"
+#include "img_saver.h"
+#include "kookaimage.h"
+#include "kookaimagemeta.h"
+#include "previewer.h"
+#include "devselector.h"
+
+#include <qapplication.h>
+#include <qdir.h>
+#include <qfile.h>
+#include <qpopupmenu.h>
+#include <qdict.h>
+#include <qpixmap.h>
+#include <kmessagebox.h>
+#include <qfiledialog.h>
+#include <qstringlist.h>
+#include <qheader.h>
+
+#include <kfiletreeview.h>
+#include <kfiletreeviewitem.h>
+#include <kfiletreebranch.h>
+
+#include <kurldrag.h>
+#include <kpopupmenu.h>
+#include <kaction.h>
+#include <kinputdialog.h>
+#include <kiconloader.h>
+#include <kfiledialog.h>
+#include <kurl.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kio/global.h>
+#include <kio/progressbase.h>
+#include <kio/netaccess.h>
+#include <kio/jobclasses.h>
+#include <kio/file.h>
+#include <kio/job.h>
+
+#define STARTUP_FIRST_START "firstStart"
+
+
+/* ----------------------------------------------------------------------- */
+/* Constructor Scan Packager */
+ScanPackager::ScanPackager( QWidget *parent ) : KFileTreeView( parent )
+{
+ // TODO:
+ setItemsRenameable (true );
+ setDefaultRenameAction( QListView::Reject );
+ addColumn( i18n("Image Name" ));
+ setColumnAlignment( 0, AlignLeft );
+
+ addColumn( i18n("Size") );
+ setColumnAlignment( 1, AlignRight );
+ setColumnAlignment( 2, AlignRight );
+
+ addColumn( i18n("Format" )); setColumnAlignment( 3, AlignRight );
+
+ /* Drag and Drop */
+ setDragEnabled( true );
+ setDropVisualizer(true);
+ setAcceptDrops(true);
+
+ connect( this, SIGNAL(dropped( QWidget*, QDropEvent*, KURL::List&, KURL& )),
+ this, SLOT( slotUrlsDropped( QWidget*, QDropEvent*, KURL::List&, KURL& )));
+
+ kdDebug(28000) << "connected Drop-Signal" << endl;
+ setRenameable ( 0, true );
+ setRenameable ( 1, false );
+ setRenameable ( 2, false );
+ setRenameable ( 3, false );
+
+ setRootIsDecorated( false );
+
+ connect( this, SIGNAL( clicked( QListViewItem*)),
+ SLOT( slClicked(QListViewItem*)));
+
+ connect( this, SIGNAL( rightButtonPressed( QListViewItem *, const QPoint &, int )),
+ SLOT( slShowContextMenue(QListViewItem *, const QPoint &, int )));
+
+ connect( this, SIGNAL(itemRenamed (QListViewItem*, const QString &, int ) ), this,
+ SLOT(slFileRename( QListViewItem*, const QString&, int)));
+
+
+ img_counter = 1;
+ /* Set the current export dir to home */
+ m_currCopyDir = QDir::home().absPath();
+ m_currImportDir = m_currCopyDir;
+
+ /* Preload frequently used icons */
+ KIconLoader *loader = KGlobal::iconLoader();
+ m_floppyPixmap = loader->loadIcon( "3floppy_unmount", KIcon::Small );
+ m_grayPixmap = loader->loadIcon( "palette_gray", KIcon::Small );
+ m_bwPixmap = loader->loadIcon( "palette_lineart", KIcon::Small );
+ m_colorPixmap = loader->loadIcon( "palette_color", KIcon::Small );
+
+ m_startup = true;
+
+ /* create a context menu and set the title */
+ m_contextMenu = new KPopupMenu();
+ static_cast<KPopupMenu*>(m_contextMenu)->insertTitle( i18n( "Gallery" ));
+
+}
+
+void ScanPackager::openRoots()
+{
+ /* standard root always exists, ImgRoot creates it */
+ KURL rootUrl(Previewer::galleryRoot());
+ kdDebug(28000) << "Open standard root " << rootUrl.url() << endl;
+
+ openRoot( rootUrl, true );
+ m_defaultBranch->setOpen(true);
+
+ /* open more configurable image repositories TODO */
+}
+
+KFileTreeBranch* ScanPackager::openRoot( const KURL& root, bool )
+{
+ KIconLoader *loader = KGlobal::iconLoader();
+
+ /* working on the global branch. FIXME */
+ m_defaultBranch = addBranch( root, i18n("Kooka Gallery"),
+ loader->loadIcon( "folder_image", KIcon::Small ),
+ false /* do not showHidden */ );
+
+ // Q_CHECK_PTR( m_defaultBranch );
+ m_defaultBranch->setOpenPixmap( loader->loadIcon( "folder_blue_open", KIcon::Small ));
+
+ setDirOnlyMode( m_defaultBranch, false );
+ m_defaultBranch->setShowExtensions( true ); // false );
+
+ connect( m_defaultBranch, SIGNAL( newTreeViewItems( KFileTreeBranch*, const KFileTreeViewItemList& )),
+ this, SLOT( slotDecorate(KFileTreeBranch*, const KFileTreeViewItemList& )));
+
+ connect( m_defaultBranch, SIGNAL( directoryChildCount( KFileTreeViewItem* , int )),
+ this, SLOT( slotDirCount( KFileTreeViewItem *, int )));
+
+ connect( m_defaultBranch, SIGNAL( deleteItem( KFileItem* )),
+ this, SLOT( slotDeleteFromBranch(KFileItem*)));
+
+ connect( m_defaultBranch, SIGNAL( populateFinished( KFileTreeViewItem * )),
+ this, SLOT( slotStartupFinished( KFileTreeViewItem * )));
+
+
+ return( m_defaultBranch );
+}
+
+void ScanPackager::slotStartupFinished( KFileTreeViewItem *it )
+{
+ if( m_startup && (it == m_defaultBranch->root()) )
+ {
+ kdDebug(28000) << "Slot population finished hit!" << endl;
+
+ /* If nothing is selected, select the root. */
+ if( ! currentKFileTreeViewItem() )
+ {
+ (m_defaultBranch->root())->setSelected( true );
+ }
+
+ m_startup = false;
+ }
+}
+
+void ScanPackager::slotDirCount( KFileTreeViewItem* item, int cnt )
+{
+ if( item && item->isDir() )
+ {
+ QString cc = i18n( "one item", "%n items", cnt);
+ item->setText( 1, cc );
+ }
+ else
+ {
+ kdDebug(28000) << "Item is NOT directory - do not set child count!" << endl;
+ }
+}
+
+void ScanPackager::slotDecorate( KFileTreeViewItem* item )
+{
+ if( !item ) return;
+ if( item->isDir())
+ {
+ // done in extra slot.
+ kdDebug(28000) << "Decorating directory!" << endl;
+ }
+ else
+
+ {
+ KFileItem *kfi = item->fileItem();
+
+ KookaImage *img = 0L;
+
+ if( kfi )
+ {
+ img = static_cast<KookaImage*>(kfi->extraData( this ));
+ }
+
+ if( img )
+ {
+
+ /* The image appears to be loaded to memory. */
+ if( img->depth() == 1 )
+ {
+ /* a bw-image */
+ item->setPixmap( 0, m_bwPixmap );
+ }
+ else
+ {
+ if( img->isGrayscale() )
+ {
+ item->setPixmap( 0, m_grayPixmap );
+ }
+ else
+ {
+ item->setPixmap( 0, m_colorPixmap );
+ }
+ }
+
+ /* set image size in pixels */
+ QString t = i18n( "%1 x %2" ).arg( img->width()).arg(img->height());
+ item->setText( 1, t );
+ kdDebug( 28000) << "Image loaded and decorated!" << endl;
+ }
+ else
+ {
+ /* Item is not yet loaded. Display file information */
+ item->setPixmap( 0, m_floppyPixmap );
+ if ( kfi )
+ {
+ item->setText(1, KIO::convertSize( kfi->size() ));
+ }
+ }
+
+ /* Image format */
+ QString format = getImgFormat( item );
+ item->setText( 2, format );
+ }
+
+ // This code is quite similar to m_nextUrlToSelect in KFileTreeView::slotNewTreeViewItems
+ // When scanning a new image, we wait for the KDirLister to notice the new file,
+ // and then we have the KFileTreeViewItem that we need to display the image.
+ if ( ! m_nextUrlToShow.isEmpty() )
+ {
+ if( m_nextUrlToShow.equals(item->url(), true ))
+ {
+ m_nextUrlToShow = KURL(); // do this first to prevent recursion
+ slClicked( item );
+ setCurrentItem(item); // neccessary in case of new file from D&D
+ }
+ }
+}
+
+
+
+
+void ScanPackager::slotDecorate( KFileTreeBranch* branch, const KFileTreeViewItemList& list )
+{
+ (void) branch;
+ kdDebug(28000) << "decorating slot for list !" << endl;
+
+ KFileTreeViewItemListIterator it( list );
+
+ bool end = false;
+ for( ; !end && it.current(); ++it )
+ {
+ KFileTreeViewItem *kftvi = *it;
+ slotDecorate( kftvi );
+ emit fileChanged( kftvi->fileItem() );
+ }
+}
+
+
+
+void ScanPackager::slFileRename( QListViewItem* it, const QString& newStr, int )
+{
+
+ bool success = true;
+ if( !it ) return;
+
+ if( newStr.isEmpty() )
+ success = false;
+
+ KFileTreeViewItem *item = static_cast<KFileTreeViewItem*>(it);
+
+ /* Free memory and imform everybody who is interested. */
+ KURL urlFrom = item->url();
+ KURL urlTo( urlFrom );
+
+ /* clean filename and apply new name */
+ urlTo.setFileName("");
+ urlTo.setFileName(newStr);
+
+ if( success )
+ {
+ if( urlFrom == urlTo )
+ {
+ kdDebug(28000) << "Renaming to same url does not make sense!" << endl;
+ success = false;
+ }
+ else
+ {
+ /* clear selection, because the renamed image comes in through
+ * kdirlister again
+ */
+ slotUnloadItem( item );
+
+ kdDebug(28000) << "Renaming to " << urlTo.prettyURL() <<
+ " from " << urlFrom.prettyURL() << endl;
+
+ /* to urlTo the really used filename is written */
+ setSelected( item, false );
+
+ if( ImgSaver::renameImage( urlFrom, urlTo, false, this ) )
+ {
+ kdDebug(28000) << "renaming OK" << endl;
+ emit fileRenamed( item->fileItem(), urlTo );
+ success=true;
+ }
+ else
+ {
+ success = false;
+ }
+ }
+ }
+
+ if( !success )
+ {
+ kdDebug(28000) << "renaming failed" << endl;
+ /* restore the name */
+ item->setText(0, urlFrom.fileName() );
+ setSelected( item, true );
+
+ }
+
+}
+
+
+/* ----------------------------------------------------------------------- */
+/*
+ * Method that checks if the new filename a user enters while renaming an image is valid.
+ * It checks for a proper extension.
+ */
+QString ScanPackager::buildNewFilename( QString cmplFilename, QString currFormat ) const
+{
+ /* cmplFilename = new name the user wishes.
+ * currFormat = the current format of the image.
+ * if the new filename has a valid extension, which is the same as the
+ * format of the current, fine. A ''-String has to be returned.
+ */
+ QFileInfo fiNew( cmplFilename );
+ QString base = fiNew.baseName();
+ QString newExt = fiNew.extension( false ).lower();
+ QString nowExt = currFormat.lower();
+ QString ext = "";
+
+ kdDebug(28000) << "Filename wanted: "<< cmplFilename << " <"<<newExt<<"> <" << nowExt<<">" <<endl;
+
+ if( newExt.isEmpty() )
+ {
+ /* ok, fine -> return the currFormat-Extension */
+ ext = base + "." + currFormat;
+ }
+ else if( newExt == nowExt )
+ {
+ /* also good, no reason to put another extension */
+ ext = cmplFilename;
+ }
+ else
+ {
+ /* new Ext. differs from the current extension. Later. */
+ KMessageBox::sorry( 0L, i18n( "You entered a file extension that differs from the existing one. That is not yet possible. Converting 'on the fly' is planned for a future release.\n"
+ "Kooka corrects the extension."),
+ i18n("On the Fly Conversion"));
+ ext = base + "." + currFormat;
+ }
+ return( ext );
+}
+
+/* ----------------------------------------------------------------------- */
+/* This method returns the directory of an image or directory.
+ */
+QString ScanPackager::itemDirectory( const KFileTreeViewItem* item, bool relativ ) const
+{
+ if( ! item )
+ {
+ kdDebug(28000) << "ERR: itemDirectory without item" << endl;
+ return QString::null;
+ }
+
+ QString relativUrl= (item->url()).prettyURL();
+
+ if( ! item->isDir() )
+ {
+ // Cut off the filename in case it is not a dir
+ relativUrl.truncate( relativUrl.findRev( '/' )+1);
+ }
+ else
+ {
+ /* add a "/" to the directory if not there */
+ if( ! relativUrl.endsWith( "/" ) )
+ relativUrl.append( "/" );
+ }
+
+ if( relativ )
+ {
+ KFileTreeBranch *branch = item->branch();
+ if( branch )
+ {
+ kdDebug(28000) << "Relativ URL of the file " << relativUrl << endl;
+ QString rootUrl = (branch->rootUrl()).prettyURL(); // directory of branch root
+
+ if( relativUrl.startsWith( rootUrl ))
+ {
+ relativUrl.remove( 0, rootUrl.length() );
+
+ if( relativUrl.isEmpty() ) relativUrl = "/"; // The root
+ }
+ else
+ {
+ kdDebug(28000) << "ERR: Item-URL does not start with root url " << rootUrl << endl;
+ }
+ }
+ }
+ return( relativUrl );
+}
+/* ----------------------------------------------------------------------- */
+/* This slot receives a string from the gallery-path combobox shown under the
+ * image gallery. The form of the string coming in here is <branch-name> - <
+ * relativ directory under the branch. Now it is to assemble a complete path
+ * from the data, find out which KFileTreeViewItem is associated with it and
+ * call slClicked with it.
+ */
+
+void ScanPackager::slotSelectDirectory( const QString & dirString )
+{
+ kdDebug(28000) << "Trying to decode directory string " << dirString << endl;
+
+ QString searchFor = QString::fromLatin1(" - ");
+ int pos = dirString.find( searchFor );
+
+ if( pos > -1 )
+ {
+ /* Splitting up the string coming in */
+ QString branchName = dirString.left( pos );
+ QString relPath( dirString );
+
+ relPath = relPath.remove( 0, pos + searchFor.length());
+
+ kdDebug(28000) << "Splitted up to branch <" << branchName << "> and <" << relPath << endl;
+
+ KFileTreeViewItem *kfi = findItem( branchName, relPath );
+
+ if( kfi )
+ {
+ kdDebug(28000) << "got a new item to select !" << endl;
+ ensureItemVisible(kfi);
+ setCurrentItem(kfi);
+ slClicked(kfi); // load thumbnails for this dir etc.
+ }
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+/* This slot is called when clicking on an item. */
+void ScanPackager::slClicked( QListViewItem *newItem )
+{
+ KFileTreeViewItem *item = static_cast<KFileTreeViewItem*>(newItem);
+
+ if( item ) // can be 0, when clicking where no item is present
+ {
+ kdDebug(28000) << "Clicked - newItem !" << endl;
+ /* Check if directory, hide image for now, later show a thumb view */
+ if( item->isDir())
+ {
+ kdDebug(28000) << "clicked: Is a directory !" << endl;
+ emit( showImage( 0L ));
+ kdDebug(28000) << "emitting showThumbnails" << endl;
+ }
+ else
+ {
+ /* if not a dir, load the image if necessary. This is done by loadImageForItem,
+ * which is async( TODO ). The image finally arrives in slotImageArrived */
+ QApplication::setOverrideCursor(waitCursor);
+ emit( aboutToShowImage( item->url()));
+ loadImageForItem( item );
+ QApplication::restoreOverrideCursor();
+ }
+
+ /* emit a signal indicating the new directory if there is a new one */
+ QString wholeDir = itemDirectory( item, false ); /* not relativ to root */
+
+ if( currSelectedDir != wholeDir )
+ {
+ currSelectedDir = wholeDir;
+ QString relativUrl = itemDirectory( item, true );
+ kdDebug(28000) << "Emitting " << relativUrl << " as new relative Url" << endl;
+ /* Emit the signal with branch and the relative path */
+ emit( galleryPathSelected( item->branch(), relativUrl ));
+
+ if( item->isDir() )
+ {
+ emit( showThumbnails( item ));
+ }
+ else
+ {
+ emit( showThumbnails( static_cast<KFileTreeViewItem*>(item->parent())));
+ }
+ }
+ else
+ {
+ // kdDebug(28000) << "directory is not new: " << currSelectedDir << endl;
+ }
+ }
+}
+
+void ScanPackager::loadImageForItem( KFileTreeViewItem *item )
+{
+
+ if( ! item ) return;
+ bool result = true;
+
+ KFileItem *kfi = item->fileItem();
+ if( ! kfi ) return;
+
+ KookaImage *img = static_cast<KookaImage*>( kfi->extraData(this));
+
+ if( img )
+ {
+ kdDebug(28000) << "Image already loaded." << endl;
+ /* result is still true, image must be shown. */
+ }
+ else
+ {
+ /* The image needs to be loaded. Possibly it is a multi-page image.
+ * If it is, the kookaImage has a subImageCount larger than one. We
+ * create an subimage-item for every subimage, but do not yet load
+ * them.
+ */
+ KURL url = item->url();
+
+ img = new KookaImage( );
+ if( !img || !img->loadFromUrl( url ) )
+ {
+ kdDebug(28000) << "Loading KookaImage from File failed!" << endl;
+ result = false;
+ }
+ else
+ {
+ /* store the fileitem */
+ img->setFileItem( kfi );
+
+ /* care for subimages, create items for them */
+ kdDebug(28000) << "subImage-count: " << img->subImagesCount() << endl;
+ if( img->subImagesCount() > 1 )
+ {
+ KIconLoader *loader = KGlobal::iconLoader();
+ kdDebug(28000) << "SubImages existing!" << endl;
+
+ /* Start at the image with index 1, that makes one less than are actually in the
+ * image. But image 0 was already created above. */
+ KFileTreeViewItem *prevItem=0;
+ for( int i = 1; i < img->subImagesCount(); i++ )
+ {
+ kdDebug(28000) << "Creating subimage no " << i << endl;
+ KFileItem *newKfi = new KFileItem( *kfi );
+ KFileTreeViewItem *subImgItem = new KFileTreeViewItem( item, newKfi, item->branch());
+
+ if( prevItem )
+ {
+ subImgItem->moveItem( prevItem );
+ }
+ prevItem = subImgItem;
+
+ subImgItem->setPixmap( 0, loader->loadIcon( "editcopy", KIcon::Small ));
+ subImgItem->setText( 0, i18n("Sub-image %1").arg( i ) );
+ KookaImage *subImgImg = new KookaImage( i, img );
+ subImgImg->setFileItem( newKfi );
+ newKfi->setExtraData( (void*) this, (void*) subImgImg );
+ }
+ }
+ }
+ }
+
+
+ if( result && img )
+ {
+ if( img->isSubImage() )
+ {
+ kdDebug(28000) << "it _is_ a subimage" << endl;
+ /* load if not loaded */
+ if( img->isNull())
+ {
+ kdDebug(28000) << "extracting subimage" << endl;
+ img->extractNow();
+ }
+ else
+ {
+ kdDebug(28000) << "Is not a null image" << endl;
+ }
+ }
+ slImageArrived( item, img );
+ }
+}
+
+/* Hit this slot with a file for a kfiletreeviewitem. */
+void ScanPackager::slImageArrived( KFileTreeViewItem *item, KookaImage* image )
+{
+ if( item && image )
+ {
+ /* Associate the image for the Scanpackager-Object. */
+ KFileItem *kfi = item->fileItem();
+ if( kfi )
+ {
+ kfi->setExtraData( (void*) this, (void*) image );
+ }
+ slotDecorate( item );
+ emit( showImage( image ));
+ }
+}
+
+KookaImage* ScanPackager::getCurrImage() const
+{
+ KFileTreeViewItem *curr = currentKFileTreeViewItem();
+ KookaImage *img = 0L;
+
+ if( curr )
+ {
+ KFileItem *kfi = curr->fileItem();
+ if( kfi )
+ {
+ img = static_cast<KookaImage*>(kfi->extraData( this ));
+ }
+ }
+ return(img);
+}
+
+
+QString ScanPackager::getCurrImageFileName( bool withPath = true ) const
+{
+ QString result = "";
+
+ KFileTreeViewItem *curr = currentKFileTreeViewItem();
+ if( ! curr )
+ {
+ kdDebug( 28000) << "getCurrImageFileName: nothing selected !"<< endl;
+ }
+ else
+ {
+ if( withPath )
+ {
+ result = localFileName(curr);
+ }
+ else
+ {
+ KURL url( localFileName(curr));
+ url = curr->url();
+ result = url.fileName();
+ }
+ }
+ return( result );
+}
+
+/* ----------------------------------------------------------------------- */
+QCString ScanPackager::getImgFormat( KFileTreeViewItem* item ) const
+{
+
+ QCString cstr;
+
+ if( !item ) return( cstr );
+#if 0
+ KFileItem *kfi = item->fileItem();
+
+ QString mime = kfi->mimetype();
+#endif
+
+ // TODO find the real extension for use with the filename !
+ // temporarely:
+ QString f = localFileName( item );
+
+ return( QImage::imageFormat( f ));
+
+}
+
+QString ScanPackager::localFileName( KFileTreeViewItem *it ) const
+{
+ if( ! it ) return( QString::null );
+
+ KURL url = it->url();
+
+ QString res;
+
+ if( url.isLocalFile())
+ {
+ res = url.directory( false, true ) + url.fileName();
+ }
+
+ return( res );
+}
+
+/* Called if the image exists but was changed by image manipulation func */
+void ScanPackager::slotCurrentImageChanged( QImage *img )
+{
+ KFileTreeViewItem *curr = currentKFileTreeViewItem();
+ if( ! curr )
+ {
+ kdDebug(28000) << "ImageChanged: nothing selected !" << endl;
+ return;
+ }
+
+ /* Do not save directories */
+ if( curr->isDir() ) return;
+
+ /* unload image and free memory */
+ slotUnloadItem( curr );
+
+ const QString filename = localFileName( curr );
+ const QCString format = getImgFormat( curr );
+ ImgSaver saver( this );
+ ImgSaveStat is_stat = ISS_OK;
+ is_stat = saver.saveImage( img, filename, format );
+
+ if( is_stat == ISS_ERR_FORMAT_NO_WRITE )
+ {
+ KMessageBox::error( this, i18n( "Cannot write this image format.\nImage will not be saved!"),
+ i18n("Save Error") );
+ }
+ else if( is_stat == ISS_ERR_PERM )
+ {
+ KMessageBox::error( this, i18n( "Image file is write protected.\nImage will not be saved!"),
+ i18n("Save Error") );
+
+ }
+ else if( is_stat == ISS_ERR_PROTOCOL )
+ {
+ KMessageBox::sorry( this, i18n( "Cannot save the image, because the file is local.\n"
+ "Kooka will support other protocols later."),
+ i18n("Save Error") );
+
+ }
+ else if( is_stat != ISS_OK )
+ {
+ kdDebug(28000) << "Error while saving existing image !" << endl;
+ }
+
+ if( img && !img->isNull())
+ {
+ emit( imageChanged( curr->fileItem()));
+ KookaImage *newImage = new KookaImage(*img);
+ slImageArrived( curr, newImage );
+ }
+}
+
+
+/* ----------------------------------------------------------------------- */
+/* This slot takes a new scanned Picture and saves it.
+ * It urgently needs to make a deep copy of the image !
+ */
+void ScanPackager::slAddImage( QImage *img, KookaImageMeta* )
+{
+ ImgSaveStat is_stat = ISS_OK;
+ /* Save the image with the help of the ImgSaver */
+ if( ! img ) return;
+
+ /* currently selected item is the directory or a file item */
+ KFileTreeViewItem *curr = currentKFileTreeViewItem();
+
+ /* Use root if nothing is selected */
+ if( ! curr )
+ {
+ KFileTreeBranch *b = branches().at(0); /* There should be at least one */
+
+ if( b )
+ {
+ curr = findItem( b, i18n( "Incoming/" ) );
+ if( ! curr ) curr = b->root();
+ }
+
+ /* If curr is still undefined, something very tough has happend. Go away here */
+ if( !curr ) return;
+
+ setSelected( curr, true );
+ }
+
+ /* find the directory above the current one */
+
+ KURL dir(itemDirectory( curr ));
+
+ /* Path of curr sel item */
+ ImgSaver img_saver( this, dir );
+
+ is_stat = img_saver.saveImage( img );
+ if( is_stat == ISS_ERR_FORMAT_NO_WRITE )
+ {
+ KMessageBox::error( this, i18n( "Cannot write this image format.\nImage will not be saved!"),
+ i18n("Save Error") );
+ }
+ else if( is_stat == ISS_ERR_PERM )
+ {
+ KMessageBox::error( this, i18n( "Image file is write protected.\nImage will not be saved!"),
+ i18n("Save Error") );
+
+ }
+ else if( is_stat != ISS_OK )
+ {
+ if( is_stat == ISS_SAVE_CANCELED )
+ {
+ return;
+ }
+ kdDebug(28000) << "ERROR: Saving failed: " << img_saver.errorString( is_stat ) << endl;
+ /* And now ?? */
+ }
+
+ /* Add the new image to the list of new images */
+ KURL lurl = img_saver.lastFileUrl();
+
+ KFileTreeBranchList branchlist = branches();
+ KFileTreeBranch *kookaBranch = branchlist.at(0);
+
+ QString strdir = itemDirectory(curr);
+ if(strdir.endsWith(QString("/"))) strdir.truncate( strdir.length() - 1 );
+ kdDebug(28000) << "Updating directory with " << strdir << endl;
+
+ if( kookaBranch ) kookaBranch->updateDirectory( KURL(strdir) );
+ slotSetNextUrlToSelect( lurl );
+ m_nextUrlToShow = lurl;
+
+ QString s;
+ /* Count amount of children of the father */
+ QListViewItem *paps = curr->parent();
+ if( curr->isDir() ) /* take only father if the is no directory */
+ paps = curr;
+
+ if( paps )
+ {
+ int childcount = paps->childCount();
+ s = i18n("%1 images").arg(childcount);
+ paps->setText( 1, s);
+ setOpen( paps, true );
+ }
+
+}
+
+/* ----------------------------------------------------------------------- */
+/* selects and opens the file with the given name. This is used to restore the
+ * last displayed image by its name.
+ */
+void ScanPackager::slSelectImage( const KURL& name )
+{
+
+ KFileTreeViewItem *found = spFindItem( UrlSearch, name.url() );
+
+ if( found )
+ {
+ kdDebug(28000) << "slSelectImage: Found an item !" << endl;
+ ensureItemVisible( found );
+ setCurrentItem( found );
+ slClicked( found );
+ }
+
+}
+
+
+KFileTreeViewItem *ScanPackager::spFindItem( SearchType type, const QString name, const KFileTreeBranch *branch )
+{
+ /* Prepare a list of branches to go through. If the parameter branch is set, search
+ * only in the parameter branch. If it is zero, search all branches returned by
+ * kfiletreeview.branches()
+ */
+ KFileTreeBranchList branchList;
+
+ if( branch )
+ {
+ branchList.append( branch );
+ }
+ else
+ {
+ branchList = branches();
+ }
+
+
+ KFileTreeBranchIterator it( branchList );
+ KFileItem *kfi = 0L;
+ KFileTreeViewItem *foundItem = 0L;
+
+ /* Leave the loop in case kfi is defined */
+ KFileTreeBranch *branchloop = 0L;
+ for( ; !kfi && it.current(); ++it )
+ {
+ branchloop = *it;
+ KURL url(name);
+ switch( type )
+ {
+ case Dummy:
+ kdDebug(28000) << "Dummy search skipped !" << endl;
+ break;
+ case NameSearch:
+ kdDebug(28000) << "ScanPackager: searching for " << name << endl;
+ kfi = branchloop->findByName( name );
+ break;
+ case UrlSearch:
+ kdDebug(28000) << "ScanPackager: URL search for " << name << endl;
+ kfi = branchloop->find( url );
+ break;
+ default:
+ kdDebug(28000) << "Scanpackager: Wrong search type !" << endl;
+ break;
+ }
+
+ }
+ if( kfi )
+ {
+ foundItem = static_cast<KFileTreeViewItem*>(kfi->extraData(branchloop));
+ kdDebug(28000) << "spFindItem: Success !" << foundItem << endl;
+ }
+ return( foundItem );
+}
+
+/* ----------------------------------------------------------------------- */
+void ScanPackager::slShowContextMenue(QListViewItem *lvi, const QPoint &p, int col )
+{
+ kdDebug(28000) << "Showing Context Menue" << endl;
+ (void) col;
+
+ KFileTreeViewItem *curr = 0;
+
+ if( lvi )
+ {
+ curr = currentKFileTreeViewItem();
+ if( curr->isDir() )
+ setSelected( curr, true );
+ }
+
+ if( m_contextMenu )
+ {
+ m_contextMenu->exec( p );
+ }
+
+}
+
+/* ----------------------------------------------------------------------- */
+
+void ScanPackager::slotExportFile( )
+{
+ KFileTreeViewItem *curr = currentKFileTreeViewItem();
+ if( ! curr ) return;
+
+ if( curr->isDir() )
+ {
+ kdDebug(28000) << "Not yet implemented!" << endl;
+ }
+ else
+ {
+ KURL fromUrl( curr->url());
+ QString filter = "*." + getImgFormat(curr).lower();
+ filter += "\n*|" + i18n( "All Files" );
+
+ // initial += fromUrl.filename(false);
+ QString initial = m_currCopyDir + "/";
+ initial += fromUrl.filename(false);
+ KURL fileName = KFileDialog::getSaveURL ( initial,
+ filter, this );
+
+ if ( fileName.isValid() ) // got a file name
+ {
+ if( fromUrl == fileName ) return;
+
+ /* Since it is asynchron, we will never get if it succeeded. */
+ ImgSaver::copyImage( fromUrl, fileName );
+
+ /* remember the filename for the next export */
+ fileName.setFileName( QString());
+ m_currCopyDir = fileName.url( );
+ }
+ }
+}
+
+
+void ScanPackager::slotImportFile()
+{
+ KFileTreeViewItem *curr = currentKFileTreeViewItem();
+ if( ! curr ) return;
+
+ KURL impTarget = curr->url();
+
+ if( ! curr->isDir() )
+ {
+ KFileTreeViewItem *pa = static_cast<KFileTreeViewItem*>(curr->parent());
+ impTarget = pa->url();
+ }
+ kdDebug(28000) << "Importing to " << impTarget.url() << endl;
+
+ KURL impUrl = KFileDialog::getImageOpenURL ( m_currImportDir, this, i18n("Import Image File to Gallery"));
+
+ if( ! impUrl.isEmpty() )
+ {
+ m_currImportDir = impUrl.url();
+ impTarget.addPath( impUrl.fileName()); // append the name of the sourcefile to the path
+ m_nextUrlToShow = impTarget;
+ ImgSaver::copyImage( impUrl, impTarget );
+ }
+}
+
+
+
+void ScanPackager::slotUrlsDropped( QWidget*, QDropEvent* ev, KURL::List& urls, KURL& copyTo )
+{
+ if( !urls.isEmpty() )
+ {
+ kdDebug(28000) << "Kooka drop event!" << endl;
+ // kdDebug(28000) << "Kooka drop event. First src url=" << urls.first() << " copyTo=" << copyTo
+ // << " move=" << ( ev->action() == QDropEvent::Move ) << endl;
+
+ /* first make the last url to copy to the one to select next */
+ if( ! urls.empty() )
+ {
+ KURL nextSel = copyTo;
+ nextSel.addPath( urls.back().fileName(false));
+
+ kdDebug(28000) << "Selecting next url: " << nextSel.url() << endl;
+ m_nextUrlToShow = nextSel;
+ // slotSetNextUrlToSelect( nextSel );
+ }
+
+ if ( ev->action() == QDropEvent::Move )
+ copyjob = KIO::move( urls, copyTo, true );
+ else
+ copyjob = KIO::copy( urls, copyTo, true );
+ }
+}
+
+void ScanPackager::slotCanceled( KIO::Job* )
+{
+ kdDebug(28000) << i18n("Canceled by user") << endl;
+}
+
+
+/* ----------------------------------------------------------------------- */
+void ScanPackager::slotUnloadItems( )
+{
+ KFileTreeViewItem *curr = currentKFileTreeViewItem();
+ emit( showImage( 0L ));
+ slotUnloadItem( curr );
+}
+
+void ScanPackager::slotUnloadItem( KFileTreeViewItem *curr )
+{
+ if( ! curr ) return;
+
+ if( curr->isDir())
+ {
+ KFileTreeViewItem *child = static_cast<KFileTreeViewItem*>(curr->firstChild());
+ while( child )
+ {
+ kdDebug(28000) << "Unloading item " << child << endl;
+ slotUnloadItem( child );
+ child = static_cast<KFileTreeViewItem*> (child->nextSibling());
+ }
+ }
+ else
+ {
+ KFileItem *kfi = curr->fileItem();
+ KookaImage *image = static_cast<KookaImage*>(kfi->extraData( this ));
+
+ /* If image is zero, ok, than there is nothing to unload :) */
+ if( image )
+ {
+ if( image->subImagesCount() > 0 )
+ {
+ KFileTreeViewItem *child = static_cast<KFileTreeViewItem*>(curr->firstChild());
+
+ while( child )
+ {
+ KFileTreeViewItem *nextChild = 0;
+ kdDebug(28000) << "Unloading subimage item " << child << endl;
+ slotUnloadItem( child );
+ nextChild = static_cast<KFileTreeViewItem*> (child->nextSibling());
+ delete child;
+ child = nextChild;
+ }
+ }
+
+ emit( unloadImage( image ));
+ delete image;
+ kfi->removeExtraData( this );
+ slotDecorate( curr );
+ }
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+void ScanPackager::slotDeleteItems( )
+{
+ KFileTreeViewItem *curr = currentKFileTreeViewItem();
+ if( ! curr ) return;
+
+ KURL urlToDel = curr->url();
+ QListViewItem *nextToSelect = curr->nextSibling();
+
+ kdDebug(28000) << "Deleting: " << urlToDel.prettyURL() << endl;
+ bool ask = true; /* for later use */
+
+ int result = KMessageBox::Yes;
+
+ KFileItem *item = curr->fileItem();
+ if( ask )
+ {
+ QString s;
+ s = i18n("Do you really want to delete this image?\nIt cannot be restored!" );
+ if( item->isDir() )
+ {
+ s = i18n("Do you really want to delete the folder %1\nand all the images inside?").arg("");
+ }
+ result = KMessageBox::warningContinueCancel(this, s, i18n( "Delete Collection Item"),
+ KStdGuiItem::del(), "AskForDeleteFiles" );
+ }
+
+ /* Since we are currently talking about local files here, NetAccess is OK */
+ if( result == KMessageBox::Continue )
+ {
+ if( KIO::NetAccess::del( urlToDel, 0 ))
+ {
+ if( nextToSelect )
+ setSelected( nextToSelect, true );
+ /* TODO: remove the directory from the imageNameCombobox */
+ if( curr && item->isDir() )
+ {
+ /* The directory needs to be removed from the name combo */
+ emit(directoryToRemove( curr->branch(), itemDirectory( curr, true ) ));
+ }
+
+ }
+ else
+ kdDebug(28000) << "Deleting files failed" << endl;
+
+ }
+}
+
+/* ----------------------------------------------------------------------- */
+void ScanPackager::slotCreateFolder( )
+{
+ bool ok;
+ QString folder = KInputDialog::getText( i18n( "New Folder" ),
+ i18n( "Please enter a name for the new folder:" ), QString::null,
+ &ok, this );
+
+ if( ok )
+ {
+ /* KIO create folder goes here */
+
+ KFileTreeViewItem *it = currentKFileTreeViewItem();
+ if( it )
+ {
+ KURL url = it->url();
+
+ /* If a directory is selected, the filename needs not to be deleted */
+ if( ! it->isDir())
+ url.setFileName( "" );
+ /* add the folder name from user input */
+ url.addPath( folder );
+ kdDebug(28000) << "Creating folder " << url.prettyURL() << endl;
+
+ /* Since the new directory arrives in the packager in the newItems-slot, we set a
+ * variable urlToSelectOnArrive here. The newItems-slot will honor it and select
+ * the treeviewitem with that url.
+ */
+ slotSetNextUrlToSelect( url );
+
+ if( ! KIO::NetAccess::mkdir( url, 0, -1 ))
+ {
+ kdDebug(28000) << "ERR: creation of " << url.prettyURL() << " failed !" << endl;
+ }
+ else
+ {
+ /* created successfully */
+ /* open the branch if necessary and select the new folder */
+
+ }
+ }
+ }
+}
+
+
+/* ----------------------------------------------------------------------- */
+QString ScanPackager::getImgName( QString name_on_disk )
+{
+ QString s;
+ (void) name_on_disk;
+
+ s = i18n("image %1").arg(img_counter++);
+ return( s );
+}
+
+/* ----------------------------------------------------------------------- */
+ScanPackager::~ScanPackager(){
+ kdDebug(29000) << "Destructor of ScanPackager" << endl;
+
+}
+
+/* called whenever one branch detects a deleted file */
+void ScanPackager::slotDeleteFromBranch( KFileItem* kfi )
+{
+ emit fileDeleted( kfi );
+}
+
+void ScanPackager::contentsDragMoveEvent( QDragMoveEvent *e )
+{
+ if( ! acceptDrag( e ) )
+ {
+ e->ignore();
+ return;
+ }
+
+ QListViewItem *afterme = 0;
+ QListViewItem *parent = 0;
+
+ findDrop( e->pos(), parent, afterme );
+
+ // "afterme" is 0 when aiming at a directory itself
+ QListViewItem *item = afterme ? afterme : parent;
+
+ if( item )
+ {
+ bool isDir = static_cast<KFileTreeViewItem*> (item)->isDir();
+ if( isDir ) {
+ KFileTreeView::contentsDragMoveEvent( e ); // for the autoopen code
+ return;
+ }
+ }
+ e->acceptAction();
+}
+
+
+#include "scanpackager.moc"
diff --git a/kooka/scanpackager.h b/kooka/scanpackager.h
new file mode 100644
index 00000000..13173050
--- /dev/null
+++ b/kooka/scanpackager.h
@@ -0,0 +1,167 @@
+/***************************************************************************
+ scanpackager.h - description
+ -------------------
+ begin : Fri Dec 17 1999
+ copyright : (C) 1999 by Klaas Freitag
+ email : freitag@suse.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+
+#ifndef SCANPACKAGER_H
+#define SCANPACKAGER_H
+
+#include <qlistview.h>
+#include <qimage.h>
+#include <qpixmap.h>
+#include <qdragobject.h>
+#include <qmap.h>
+#include <klistview.h>
+#include <kio/job.h>
+#include <kio/global.h>
+#include <kio/file.h>
+#include <kfiletreeview.h>
+
+
+/**
+ *@author Klaas Freitag
+ */
+
+class KURL;
+class QPopupMenu;
+class KFileTreeViewItem;
+class KookaImage;
+class KookaImageMeta;
+class KFileTreeBranch;
+
+
+typedef enum{ Dummy, NameSearch, UrlSearch } SearchType;
+
+class JobDescription
+{
+public:
+ enum JobType { NoJob, ImportJob, RenameJob, ExportJob };
+ JobDescription():jobType( NoJob ), kioJob(0L), pitem(0L) {}
+ JobDescription( KIO::Job* kiojob, KFileTreeViewItem *new_item, JobType type ) :
+ jobType(type), kioJob(kiojob), pitem(new_item) {}
+
+ JobType type( void ) { return( jobType ); }
+ KFileTreeViewItem *item( void ) { return( pitem ); }
+ KIO::Job* job( void ){ return( kioJob ); }
+private:
+ JobType jobType;
+ KIO::Job* kioJob;
+ KFileTreeViewItem* pitem;
+};
+
+class ScanPackager : public KFileTreeView
+{
+ Q_OBJECT
+public:
+ ScanPackager( QWidget *parent);
+ ~ScanPackager();
+ virtual QString getImgName( QString name_on_disk );
+
+ QString getCurrImageFileName( bool ) const;
+ KookaImage* getCurrImage() const;
+
+ KFileTreeBranch* openRoot( const KURL&, bool open=false );
+
+ QPopupMenu *contextMenu() const { return m_contextMenu; }
+ void openRoots();
+
+public slots:
+ void slSelectImage( const KURL& );
+ void slAddImage( QImage *img, KookaImageMeta* meta = 0 );
+ void slShowContextMenue(QListViewItem *, const QPoint &, int );
+
+ void slotExportFile( );
+ void slotImportFile();
+ void slotCanceled(KIO::Job*);
+ void slotCurrentImageChanged( QImage* );
+
+ void slotDecorate( KFileTreeViewItem* );
+ void slotDecorate( KFileTreeBranch*, const KFileTreeViewItemList& );
+
+ void slotSelectDirectory( const QString& );
+
+protected:
+ virtual void contentsDragMoveEvent( QDragMoveEvent *e );
+
+protected slots:
+ void slClicked( QListViewItem * );
+ void slFileRename( QListViewItem*, const QString&, int );
+ // void slFilenameChanged( KFileTreeViewItem*, const KURL & );
+ void slImageArrived( KFileTreeViewItem *item, KookaImage* image );
+ void slotCreateFolder( );
+ void slotDeleteItems( );
+ void slotUnloadItems( );
+ void slotUnloadItem( KFileTreeViewItem *curr );
+ void slotDirCount( KFileTreeViewItem *item, int cnt );
+ void slotUrlsDropped( QWidget*, QDropEvent*, KURL::List& urls, KURL& copyTo );
+ void slotDeleteFromBranch( KFileItem* );
+ void slotStartupFinished( KFileTreeViewItem * );
+signals:
+ void showImage ( KookaImage* );
+ void deleteImage( KookaImage* );
+ void unloadImage( KookaImage* );
+ void galleryPathSelected( KFileTreeBranch* branch, const QString& relativPath );
+ void directoryToRemove( KFileTreeBranch *branch, const QString& relativPath );
+ void showThumbnails( KFileTreeViewItem* );
+
+ void aboutToShowImage( const KURL& ); /* starting to load image */
+ void imageChanged( KFileItem* ); /* the image has changed */
+
+ void fileDeleted( KFileItem* );
+ void fileChanged( KFileItem* );
+ void fileRenamed( KFileItem*, const KURL& );
+
+private:
+ QString localFileName( KFileTreeViewItem* it ) const;
+ void loadImageForItem( KFileTreeViewItem* item );
+ QCString getImgFormat( KFileTreeViewItem* item ) const;
+
+ QString buildNewFilename( QString cmplFilename, QString currFormat ) const;
+ KFileTreeViewItem *spFindItem( SearchType type, const QString name, const KFileTreeBranch* branch = 0 );
+ QString itemDirectory( const KFileTreeViewItem*, bool relativ = false ) const;
+
+ // int readDir( QListViewItem *parent, QString dir_to_read );
+ void showContextMenu( QPoint p, bool show_folder = true );
+
+ QString m_currImportDir;
+ QString m_currCopyDir;
+ QString currSelectedDir;
+ KIO::Job *copyjob;
+ int img_counter;
+ QPopupMenu *m_contextMenu;
+
+ // like m_nextUrlToSelect in KFileTreeView but for our own purposes (showing the image)
+ KURL m_nextUrlToShow;
+
+ QPixmap m_floppyPixmap;
+ QPixmap m_grayPixmap;
+ QPixmap m_bwPixmap;
+ QPixmap m_colorPixmap;
+
+ KFileTreeBranch *m_defaultBranch;
+ bool m_startup;
+};
+
+#endif
diff --git a/kooka/thumbview.cpp b/kooka/thumbview.cpp
new file mode 100644
index 00000000..5dfa93b6
--- /dev/null
+++ b/kooka/thumbview.cpp
@@ -0,0 +1,494 @@
+/***************************************************************************
+ thumbview.cpp - Class to display thumbnailed images
+ -------------------
+ begin : Tue Apr 18 2002
+ copyright : (C) 2002 by Klaas Freitag
+ email : freitag@suse.de
+
+ $Id$
+ ***************************************************************************/
+
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include <qpixmap.h>
+#include <qpainter.h>
+
+#include <kio/previewjob.h>
+#include <kdebug.h>
+#include <kfileitem.h>
+#include <kfileiconview.h>
+#include <kfiletreeviewitem.h>
+#include <kimageeffect.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kprogress.h>
+
+#include "thumbview.h"
+#include "thumbview.moc"
+
+#include "thumbviewitem.h"
+
+
+
+ThumbView::ThumbView( QWidget *parent, const char *name )
+ : QVBox( parent ),
+ m_iconView(0),
+ m_job(0)
+{
+ setMargin(3);
+ m_pixWidth = 0;
+ m_pixHeight = 0;
+ m_thumbMargin = 5;
+ m_iconView = new KIconView( this, name );
+ m_progress = new KProgress( this );
+ m_progress->hide();
+
+ m_pixWidth = 100;
+ m_pixHeight = 100;
+
+ readSettings();
+
+ m_basePix.resize( QSize( m_pixWidth, m_pixHeight ) );
+ m_basePix.fill(); // fills white per default TODO
+
+
+ m_iconView->setItemsMovable( false );
+
+ slSetBackGround();
+
+ connect( m_iconView, SIGNAL( executed( QIconViewItem* )),
+ this, SLOT( slDoubleClicked( QIconViewItem* )));
+
+ m_pendingJobs.setAutoDelete(false);
+}
+
+ThumbView::~ThumbView()
+{
+ saveConfig();
+}
+
+bool ThumbView::readSettings()
+{
+ KConfig *cfg = KGlobal::config();
+ cfg->setGroup( THUMB_GROUP );
+ bool dirty = false;
+
+ QColor color;
+ color = cfg->readColorEntry( MARGIN_COLOR1, &(colorGroup().base()));
+ if( color != m_marginColor1 )
+ {
+ dirty = true;
+ m_marginColor1 = color;
+ }
+
+ color = cfg->readColorEntry( MARGIN_COLOR2, &(colorGroup().foreground()));
+ if( color != m_marginColor2 )
+ {
+ dirty = true;
+ m_marginColor2 = color;
+ }
+
+ int value;
+ bool sizeDirty = false;
+ value = cfg->readNumEntry( THUMB_MARGIN, 5 );
+ if( value != m_thumbMargin )
+ {
+ sizeDirty = true;
+ m_thumbMargin = value;
+ }
+
+ value = cfg->readNumEntry( PIXMAP_WIDTH, 100 );
+ if( value != m_pixWidth || m_pixWidth == 0 )
+ {
+ sizeDirty = true;
+ m_pixWidth = value;
+ }
+
+ value = cfg->readNumEntry( PIXMAP_HEIGHT, 120 );
+ if( value != m_pixHeight || m_pixHeight == 0 )
+ {
+ sizeDirty = true;
+ m_pixHeight = value;
+ }
+
+ if( sizeDirty )
+ {
+ int gX = 2*m_thumbMargin+m_pixWidth+10;
+ int gY = 2*m_thumbMargin+m_pixHeight+10;
+ m_iconView->setGridX(gX);
+ m_iconView->setGridY(gY);
+ kdDebug(28000) << "Setting Grid " << gX << " - " << gY << endl;
+ }
+
+ KStandardDirs stdDir;
+ QString newBgImg = cfg->readEntry( BG_WALLPAPER, stdDir.findResource( "data", STD_TILE_IMG ) );
+
+ if( m_bgImg != newBgImg )
+ {
+ m_bgImg = newBgImg;
+ slSetBackGround();
+ }
+
+ return (sizeDirty || dirty);
+}
+
+void ThumbView::slDoubleClicked( QIconViewItem *qIt )
+{
+ ThumbViewItem *it = static_cast<ThumbViewItem*>( qIt );
+
+ if( it )
+ {
+ const KURL url = it->itemUrl();
+
+ emit( selectFromThumbnail( url ));
+ }
+}
+
+void ThumbView::slSetBackGround( )
+{
+ QPixmap bgPix;
+ if( m_bgImg.isEmpty())
+ {
+ bgPix.resize( QSize(16, 16));
+ bgPix.fill( QPixmap::blue );
+ }
+ else
+ {
+ bgPix.load( m_bgImg );
+ }
+
+ m_iconView->setPaletteBackgroundPixmap ( bgPix );
+ setPaletteBackgroundPixmap ( bgPix );
+
+}
+
+void ThumbView::slImageChanged( KFileItem *kfit )
+{
+ if( ! kfit ) return;
+ // kdDebug(28000) << "changes to one thumbnail!" << endl;
+
+ KURL thumbDir = currentDir();
+ KURL itemUrl = kfit->url();
+
+ /* delete filename */
+ itemUrl.setFileName( QString());
+ if( !itemUrl.equals( thumbDir, true ))
+ {
+ // kdDebug(28000) << "returning, because directory does not match: " << itemUrl.prettyURL() << endl;
+ // kdDebug(28000) << "and my URL: " << thumbDir.prettyURL() << endl;
+ return;
+ }
+
+ if( deleteImage( kfit ))
+ {
+ kdDebug(28000) << "was changed, deleted first!" << endl;
+ }
+ /* Trigger a new reading */
+ KFileItemList li;
+ li.append( kfit );
+ slNewFileItems( li );
+}
+
+void ThumbView::slImageRenamed( KFileItem *kfit, const KURL& newUrl )
+{
+ const KURL url = kfit->url();
+
+ if( kfit->isDir() ) {
+ clear();
+ }
+
+ for ( QIconViewItem *item = m_iconView->firstItem(); item; item = item->nextItem() )
+ {
+ ThumbViewItem *it=static_cast<ThumbViewItem*>( item );
+
+ if( url == it->itemUrl() )
+ {
+ it->setItemUrl( newUrl );
+
+ break;
+ }
+ }
+}
+
+
+void ThumbView::slCheckForUpdate( KFileItem *kfit )
+{
+ if( ! kfit ) return;
+
+ kdDebug(28000) << "Checking for update of thumbview!" << endl;
+
+ KURL searchUrl = kfit->url();
+ bool haveItem = false;
+
+ /* iterate over all icon items and compare urls.
+ * TODO: Check the parent url to avoid iteration over all */
+ for ( QIconViewItem *item = m_iconView->firstItem(); item && !haveItem;
+ item = item->nextItem() )
+ {
+ if( searchUrl == static_cast<ThumbViewItem*>(item)->itemUrl() )
+ {
+ haveItem = true;
+ }
+ }
+
+ /* if we still do not have the item, it is not in the thumbview. */
+ if( ! haveItem )
+ {
+ KFileItemList kfiList;
+
+ kfiList.append( kfit );
+ slNewFileItems( kfiList );
+ }
+
+}
+
+
+bool ThumbView::deleteImage( KFileItem *kfit )
+{
+ if( ! kfit ) return false;
+
+
+ KURL searchUrl = kfit->url();
+ bool haveItem = false;
+
+ /* iterate over all icon items and compare urls.
+ * TODO: Check the parent url to avoid iteration over all */
+ for ( QIconViewItem *item = m_iconView->firstItem(); item && !haveItem; item = item->nextItem() )
+ {
+ if( searchUrl == static_cast<ThumbViewItem*>(item)->itemUrl() )
+ {
+ m_iconView->takeItem( item );
+ haveItem = true;
+ }
+ }
+ kdDebug(28000) << "Deleting image from thumbview, result is " << haveItem << endl;
+ return( haveItem );
+}
+
+void ThumbView::slImageDeleted( KFileItem *kfit )
+{
+ deleteImage( kfit );
+
+
+ /*
+ From a mail from Waldo pointing out two probs in Thumbview:
+
+ 1) KDirLister is the owner of the KFileItems it emits, this means
+ that you must watch it's deleteItem() signal vigourously,
+ otherwise you may end up with KFileItems that are already
+ deleted. This burden is propagated to classes that use
+ KDirLister, such as KFileIconView.
+
+ This has a tendency to go wrong in combination with PreviewJob,
+ because it stores a list of KFileItems while running. This has
+ the potential to crash if the fileitems are being deleted
+ during this time. The remedy is to make sure to remove
+ fileitems that get deleted from the PreviewJob with
+ PreviewJob::removeItem.
+
+ */
+ if( m_job ) /* is a job running? Remove the item from it if existing. */
+ {
+ m_job->removeItem( kfit );
+ }
+
+ /* check if it is in the pending list */
+ m_pendingJobs.removeRef(kfit);
+}
+
+
+void ThumbView::slNewFileItems( const KFileItemList& items )
+{
+ kdDebug(28000) << "Creating thumbnails for fileItemList" << endl;
+
+ /* Fill the pending jobs list. */
+ KFileItemListIterator it( items );
+ KFileItem *item = 0;
+ for ( ; (item = it.current()); ++it )
+ {
+ QString filename = item->url().prettyURL();
+ if( item->isDir() )
+ {
+ /* create a dir pixmap */
+ }
+ else
+ {
+ QPixmap p(m_basePix) ;
+ QPixmap mime( item->pixmap(0) );
+
+ if( p.width() > mime.width() && p.height() > mime.height() )
+ {
+ QPainter paint( &p );
+ paint.drawPixmap( (p.width()-mime.width())/2,
+ (p.height()-mime.height())/2,
+ mime );
+ paint.flush();
+ }
+
+ /* Create a new empty preview pixmap and store the pointer to it */
+ ThumbViewItem *newIconViewIt = new ThumbViewItem( m_iconView,
+ item->url().filename(),
+ createPixmap( p ),
+ item );
+
+ newIconViewIt->setItemUrl( item->url() );
+
+ /* tell the file item about the iconView-representation */
+ item->setExtraData( this, newIconViewIt );
+
+ m_pendingJobs.append( item );
+ }
+ }
+
+ /*
+ From a mail from Waldo Bastian pointing out problems with thumbview:
+
+ 2) I think you may end up creating two PreviewJob's in parallel
+ when the slNewFileItems() function is called two times in
+ quick succession. The current code doesn't seem to expect
+ that, given the comment in slPreviewResult(). In the light of
+ 1) it might become fatal since you will not be able to call
+ PreviewJob::removeItem on the proper job. I suggest to queue
+ new items when a job is already running and start a new job
+ once the first one is finished when there are any items left
+ in the queue. Don't forget to delete items from the queue if
+ they get deleted in the mean time.
+
+ The strategy is as follows: In the global list m_pendingJobs
+ the jobs to start are appended. Only if m_job is zero (no job
+ is running) a job is started on the current m_pendingJobs list.
+ The m_pendingJobs list is clear afterwords.
+ */
+
+ if( ! m_job && m_pendingJobs.count() > 0 )
+ {
+ /* Progress-Bar */
+ m_progress->show();
+ m_progress->setTotalSteps(m_pendingJobs.count());
+ m_cntJobsStarted = 0;
+
+ /* start a preview-job */
+ m_job = KIO::filePreview(m_pendingJobs, m_pixWidth, m_pixHeight );
+
+ if( m_job )
+ {
+ connect( m_job, SIGNAL( result( KIO::Job * )),
+ this, SLOT( slPreviewResult( KIO::Job * )));
+ connect( m_job, SIGNAL( gotPreview( const KFileItem*, const QPixmap& )),
+ SLOT( slGotPreview( const KFileItem*, const QPixmap& ) ));
+
+ m_pendingJobs.clear();
+
+ /* KIO::Jo result is called in any way: Success, Failed, Error,
+ * thus connecting the failed is not really necessary.
+ */
+ // connect( job, SIGNAL( failed( const KFileItem* )),
+ // this, SLOT( slotFailed( const KFileItem* ) ));
+
+ }
+ }
+}
+
+
+
+void ThumbView::slGotPreview( const KFileItem* newFileItem, const QPixmap& newPix )
+{
+ if( ! newFileItem ) return;
+ KFileIconViewItem *item = static_cast<KFileIconViewItem*>(const_cast<void*>(newFileItem->extraData( this )));
+
+ if( ! item ) return;
+
+ item->setPixmap( createPixmap(newPix) );
+ m_cntJobsStarted+=1;
+
+ m_progress->setProgress(m_cntJobsStarted);
+
+ // kdDebug(28000)<< "jobs-Counter: " << m_cntJobsStarted << endl;
+
+}
+
+void ThumbView::slPreviewResult( KIO::Job *job )
+{
+ if( job && job->error() > 0 )
+ {
+ kdDebug(28000) << "Thumbnail Creation ERROR: " << job->errorString() << endl;
+ job->showErrorDialog( 0 );
+ }
+
+ if( job != m_job )
+ {
+ kdDebug(28000) << "Very obscure: Job finished is not mine!" << endl;
+ }
+ /* finished */
+ kdDebug(28000) << "Thumbnail job finished." << endl;
+ m_cntJobsStarted = 0;
+ m_progress->reset();
+ m_progress->hide();
+ m_job = 0L;
+
+ /* maybe there is a new job to start because of pending items? */
+ if( m_pendingJobs.count() > 0 )
+ {
+ slNewFileItems( KFileItemList() ); /* Call with an empty list */
+ }
+}
+
+
+QPixmap ThumbView::createPixmap( const QPixmap& preview ) const
+{
+ QImage ires = KImageEffect::unbalancedGradient( QSize( 2*m_thumbMargin+ preview.width(),
+ 2*m_thumbMargin+ preview.height()),
+ m_marginColor1, m_marginColor2,
+ KImageEffect::DiagonalGradient );
+
+
+ QPixmap pixRet;
+ pixRet.convertFromImage( ires );
+ QPainter p( &pixRet );
+
+ p.drawPixmap( m_thumbMargin, m_thumbMargin, preview );
+ p.flush();
+ // draw on pixmap
+
+ return( pixRet );
+}
+
+
+void ThumbView::clear()
+{
+ if( m_job )
+ m_job->kill( false /* not silently to get result-signal */ );
+ m_iconView->clear();
+}
+
+
+void ThumbView::saveConfig()
+{
+ KConfig *cfg = KGlobal::config();
+ cfg->setGroup( THUMB_GROUP );
+
+ cfg->writeEntry( MARGIN_COLOR1, m_marginColor1 );
+ cfg->writeEntry( MARGIN_COLOR2, m_marginColor2 );
+ cfg->writeEntry( PIXMAP_WIDTH, m_pixWidth );
+ cfg->writeEntry( PIXMAP_HEIGHT, m_pixHeight );
+ cfg->writeEntry( THUMB_MARGIN, m_thumbMargin );
+
+
+}
diff --git a/kooka/thumbview.h b/kooka/thumbview.h
new file mode 100644
index 00000000..c16afa84
--- /dev/null
+++ b/kooka/thumbview.h
@@ -0,0 +1,153 @@
+/***************************************************************************
+ thumbview.h - Class to display thumbnailed images
+ -------------------
+ begin : Tue Apr 18 2002
+ copyright : (C) 2002 by Klaas Freitag
+ email : freitag@suse.de
+
+ $Id$
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef __THUMBVIEW_H__
+#define __THUMBVIEW_H__
+
+#include <qwidget.h>
+#include <qimage.h>
+#include <qpixmap.h>
+#include <qcolor.h>
+#include <qvbox.h>
+
+#include <kiconview.h>
+#include <kurl.h>
+#include <kio/previewjob.h>
+#include <kfileitem.h>
+#include <kfileiconview.h>
+
+/* KConfig group definitions */
+#define MARGIN_COLOR1 "MarginColor1"
+#define MARGIN_COLOR2 "MarginColor2"
+#define PIXMAP_WIDTH "pixmapWidth"
+#define PIXMAP_HEIGHT "pixmapHeight"
+#define THUMB_MARGIN "thumbnailMargin"
+#define THUMB_GROUP "thumbnailView"
+#define BG_WALLPAPER "BackGroundTile"
+#define STD_TILE_IMG "kooka/pics/thumbviewtile.png"
+
+class QPixmap;
+class QListViewItem;
+class KProgress;
+class KIO::PreviewJob;
+
+class ThumbView: public QVBox /* KIconView */
+{
+ Q_OBJECT
+
+public:
+
+ ThumbView( QWidget *parent, const char *name=0 );
+ ~ThumbView();
+
+ void setCurrentDir( const KURL& s)
+ { m_currentDir = s; }
+ KURL currentDir( ) const
+ { return m_currentDir; }
+
+ QSize tumbSize( ) const
+ {
+ return( QSize( m_pixWidth, m_pixHeight ));
+ }
+
+ int thumbMargin() const
+ {
+ return m_thumbMargin;
+ }
+public slots:
+ void slSetThumbSize( int w, int h )
+ {
+ m_pixWidth = w;
+ m_pixHeight = h;
+ }
+ void slSetThumbSize( const QSize& s )
+ {
+ m_pixWidth = s.width();
+ m_pixHeight = s.height();
+ }
+
+ void slSetThumbMargin( int m )
+ {
+ m_thumbMargin = m;
+ }
+
+ void slNewFileItems( const KFileItemList& );
+ void slGotPreview( const KFileItem*, const QPixmap& );
+ void slPreviewResult( KIO::Job* );
+
+ /**
+ * This connects to the IconView's executed signal and tells the packager
+ * to select the image
+ */
+ void slDoubleClicked( QIconViewItem* );
+
+ /**
+ * indication that a image changed, needs to be reloaded.
+ */
+ void slImageChanged( KFileItem * );
+ void slImageDeleted( KFileItem * );
+ void slSetBackGround( );
+ void slCheckForUpdate( KFileItem* );
+ bool readSettings();
+ void clear();
+
+ void slImageRenamed( KFileItem*, const KURL& );
+
+protected:
+
+ void saveConfig();
+
+signals:
+ /**
+ * selects a QListViewItem from the thumbnail. This signal only makes
+ * sense if connected to a ScanPackager.
+ */
+ void selectFromThumbnail( const KURL& );
+
+private:
+ QPixmap createPixmap( const QPixmap& ) const;
+
+ bool deleteImage( KFileItem* );
+ KIconView *m_iconView;
+ KProgress *m_progress;
+
+ KURL m_currentDir;
+ QPixmap m_basePix;
+ int m_pixWidth;
+ int m_pixHeight;
+ int m_thumbMargin;
+ QColor m_marginColor1;
+ QColor m_marginColor2;
+ QString m_bgImg;
+ int m_cntJobsStarted;
+ KIO::PreviewJob *m_job;
+
+ KFileItemList m_pendingJobs;
+};
+
+#endif
diff --git a/kooka/thumbviewitem.cpp b/kooka/thumbviewitem.cpp
new file mode 100644
index 00000000..7f2d01f6
--- /dev/null
+++ b/kooka/thumbviewitem.cpp
@@ -0,0 +1,49 @@
+/***************************************************************************
+ thumbviewitem.cpp - Thumbview item class
+ -------------------
+ begin : Tue Apr 24 2002
+ copyright : (C) 2002 by Klaas Freitag
+ email : freitag@suse.de
+
+ $Id$
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#include <kfileitem.h>
+#include <kfileiconview.h>
+
+#include "thumbview.h"
+#include "thumbviewitem.h"
+
+ThumbViewItem::ThumbViewItem(QIconView *parent, const QString &text,
+ const QPixmap &pixmap,
+ KFileItem *fi )
+ :KFileIconViewItem( parent, text, pixmap,fi )
+{
+
+}
+
+void ThumbViewItem:: setItemUrl( const KURL& u )
+{
+ m_url = u;
+ setText( m_url.fileName());
+}
+
+
diff --git a/kooka/thumbviewitem.h b/kooka/thumbviewitem.h
new file mode 100644
index 00000000..745c2b25
--- /dev/null
+++ b/kooka/thumbviewitem.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+ thumbviewitem.h - Thumbnailview items
+ -------------------
+ begin : Tue Apr 24 2002
+ copyright : (C) 2002 by Klaas Freitag
+ email : freitag@suse.de
+
+ $Id$
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This file may be distributed and/or modified under the terms of the *
+ * GNU General Public License version 2 as published by the Free Software *
+ * Foundation and appearing in the file COPYING included in the *
+ * packaging of this file. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any version of the KADMOS ocr/icr engine of reRecognition GmbH, *
+ * Kreuzlingen and distribute the resulting executable without *
+ * including the source code for KADMOS in the source distribution. *
+ *
+ * As a special exception, permission is given to link this program *
+ * with any edition of Qt, and distribute the resulting executable, *
+ * without including the source code for Qt in the source distribution. *
+ * *
+ ***************************************************************************/
+
+#ifndef __THUMBVIEWITEM_H__
+#define __THUMBVIEWITEM_H__
+
+#include <kiconview.h>
+#include <kurl.h>
+#include <kio/previewjob.h>
+#include <kfileitem.h>
+#include <kfileiconview.h>
+
+class KFileTreeViewItem;
+
+
+class ThumbViewItem: public KFileIconViewItem
+{
+public:
+ ThumbViewItem( QIconView *parent,
+ const QString &text,
+ const QPixmap &pixmap,
+ KFileItem *fi );
+
+ void setItemUrl( const KURL& u );
+
+ KURL itemUrl() const
+ { return m_url; }
+
+private:
+ KURL m_url;
+
+
+};
+
+#endif
diff --git a/kooka/version.h b/kooka/version.h
new file mode 100644
index 00000000..2d9da5f7
--- /dev/null
+++ b/kooka/version.h
@@ -0,0 +1,4 @@
+#ifndef KOOKA_VERSION
+#define KOOKA_VERSION "0.44"
+#endif
+
diff --git a/kpdf/AUTHORS b/kpdf/AUTHORS
new file mode 100644
index 00000000..e0aae2a7
--- /dev/null
+++ b/kpdf/AUTHORS
@@ -0,0 +1,6 @@
+Albert Astals Cid <tsdgeos@yahoo.es>
+Enrico Ros <eros.kde@email.it>
+Wilco Greven <greven@kde.org>
+Christophe Devriese <oelewapperke@ulyssis.org>
+
+XPdf is written by Glyph & Cog, LLC
diff --git a/kpdf/COPYING b/kpdf/COPYING
new file mode 100644
index 00000000..0b84a43f
--- /dev/null
+++ b/kpdf/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/kpdf/Makefile.am b/kpdf/Makefile.am
new file mode 100644
index 00000000..fd5ccb49
--- /dev/null
+++ b/kpdf/Makefile.am
@@ -0,0 +1,30 @@
+SUBDIRS = xpdf conf core ui shell
+
+INCLUDES = -I$(srcdir)/xpdf -I$(srcdir)/xpdf/goo -I$(top_builddir)/kpdf $(all_includes) $(FREETYPE_CFLAGS)
+
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(EXTRACTRC) `find . -name "*.rc" -o -name "*.ui"` >> rc.cpp
+ $(XGETTEXT) `find . -name "*.cpp" -o -name "*.cc" -o -name "*.h"` -o $(podir)/kpdf.pot
+
+KDE_ICON = kpdf
+
+#########################################################################
+# KPART SECTION
+#########################################################################
+kde_module_LTLIBRARIES = libkpdfpart.la
+
+libkpdfpart_la_SOURCES = dcop.skel error.cpp part.cpp
+libkpdfpart_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+libkpdfpart_la_LIBADD = xpdf/xpdf/libxpdf.la conf/libkpdfconf.la \
+ core/libkpdfcore.la ui/libkpdfui.la $(LIB_KPARTS) \
+ $(LIB_KFILE) $(LIB_KDEPRINT) $(LIB_KUTILS) -lm
+
+partdesktopdir = $(kde_servicesdir)
+partdesktop_DATA = kpdf_part.desktop
+
+partrcdir = $(kde_datadir)/kpdfpart
+partrc_DATA = part.rc
+
+part.lo: conf/settings.h
diff --git a/kpdf/README.internals.png b/kpdf/README.internals.png
new file mode 100644
index 00000000..92153173
--- /dev/null
+++ b/kpdf/README.internals.png
Binary files differ
diff --git a/kpdf/TODO b/kpdf/TODO
new file mode 100644
index 00000000..6a00e14a
--- /dev/null
+++ b/kpdf/TODO
@@ -0,0 +1,173 @@
+TODO - KPdf MAIN HEAD
+Legend:
+ ADD - ADDed (new feature)
+ CHG - CHanGed (existing behavior)
+ FIX - FIXed (bug or regression)
+ MRG - MeRGed (code from a branch or a patch)
+
+In progress:
+ -- 2005-Feb-26: Merge from 'kpdf_annotations' branch --
+
+More items (first items will enter 'In progress list' first):
+-> pageview: add scrollbar marks for bookmarks (like kate)
+-> screen editing (annotations): framework (BR67300,BR62793)
+-> screen editing (annotations): tools (BR67300), yellow notes 'post-it' like
+-> go to next/previous bookmark actions (showing in thumbnailslist rmb popup too)
+-> viewport restoring: sometimes it seems to restore the viewport a bit under where it was
+-> viewport restoring: save the page width setting between runs (save/restore zoom factor)
+-> presentation: provide a pageX/totalPages indicator in addition to the circle one
+-> cleanup code and update README.png
+-> search: use shortcut for 'find next' action (not the default one) in find-ahead
+-> show Viewport in ThumbnailsList (blended/contour)
+-> Delay TOC (DocumentSynapsis) generation (and move it on thread)
+-> add a way to handle "named xpdf links" in KPDFLink instead of resolving all destinations
+ when displaying a page (speedups a lot generation of page with many links)
+-> refactor ThumbnailsList to do internal rendering as pageview does (way faster
+ than using QScrollView + inserted Widgets and saves 8% on document loading)
+-> usability: layout 2PPV [1 2,3 4,5 6] -> [1,2 3,4 5]. add option for 'ebook' style alignment
+-> usability: trigger redraw on 'filter text' on current page (need new highligh engine first)
+-> abstract TextPage generation (the last xpdf dependant class!). then go dancing in the
+ streets.
+-> Dom framework to cache document metadata. It should archive those types of data:
+ (NOTE: already Dom'ed object is marked with 'X')
+ - <X> Synopsis will go there after 1st generation (so we can edit it too)
+ - <X> Document info (after the 1st gen)
+ - <X> Bookmarked pages
+ - <X> Current Viewport and 10 history steps
+ - Edited pages (rotated/with_data for example)
+ - Overlay editing (hilighting/notations/etc..)
+ - Presentation related overrides (FS mode, individual / global transitions)
+ - ..more stuff.. but this isn't a problem, since a QDom is flexible by design
+ The Object will reside into the Document and must not be accessible by Oservers in
+ a direct way. Dom format, relations to other classes and accessing must be specified
+ in a separated diagram or text file.
+-> add kpdf manual in PDF format loaded on the first startup or on menu->help->manual
+ this visually explains basic usage, mouse buttons functions & more..
+-> take care of TODOs in code
+-> ADD: click over image allows "save image" [60% done (activerect of type image)]
+-> export all text in plain_text/html
+-> extract(export?) images (have a look at ImageOutputDev.cc and pdfimages.cc from xpdf (not in our xpdf sources))
+-> text selection in wordprocessor style (very hard)
+-> zoom: fit text (with configurable margin)
+-> bookview: 3d opengl widget for viewing the document as a real book (turning pages, etc..)
+-> open gzipped (.pdf.gz?) files
+-> kspeech TTS interface. speech {document / page / selection(done)}
+-> automatic online dictionaries / translators (BR80338)
+-> core: pdf forms support
+-> add OCR for building TextPages out of pure graphical (aka scanned) pages
+-> rotate the whole document / individual pages - Have a look at the fifth parameter of displayPage, it is the rotation, so it should not be THAT hard to implement
+-> presentation: implement missing transitions (6/11 done)
+-> presentation: add some gfx tools (like a red pencil)
+-> presentation: save a flag (to the xml) to open a pdf in presentation mode
+-> presentation: wheel not visible on black. gradient appreciated on lighter backgrounds.
+-> investigate 'Splash' lack of smoothness at low resolutions (see lines in thumbnails)
+-> add search on the toc widget (a 'prune on type' lineedit like in thumbnails widget)
+-> goto 'logical' page (usually differs from pdf's page) (req. by Luca Burrelli)
+-> use shortcuts for next and prev page even in presenatation mode (by Tobias Koenig)
+-> move some document related features from part to the document (see find, goto dialog, ...)
+-> Albert: Read pdf specification and see if paths with length = 1 are allowed, in case they are allowed see how to fix 97131 without skipping paths with length = 1
+-> tools: ruler, measure: distance, perimeter, ?area?, color picker
+-> export: export to other formats keeping formatting (a dream.. except for PNG :-) (PS is easy, we just have PSOutputDev that does it :-D)
+-> history as a toolbox child (collecting Doc's viewport changes notifications)
+
+Done (newest features come first):
+-- merging from kdpf_annotations branch --
+-> ADD: presentation: link following (BR98388)
+-> ADD: Save zoom setting on exit
+-> ADD: Put fonts used by the document on the properties dialog
+-> ADD: partial implementation of XYZ links
+-> ADD: google-like search on thumbnails
+-> ADD: use kde wallet for storing passwords of protected files
+-> ADD: Obey DRM is now a configuration option
+-> FIX: leakfix when closing document while thread was running (no more leaks now)
+-> FIX: direct hi-performance pixels manipulation for highlighting (instead of the obsoleted setRasterOp)
+-> CHG: new search api. supports multiple searches at once, multiple highlighs per page
+-> ADD: pageView moves smoothly when searching / moving in history
+-> ADD: better bookmark rendering in thumbnailslist (show 'clip overlay')
+-> CHG: changes and cleanups in pageView's mouse handling functions
+-> ADD: KTTSD simple support: speech selection using kspeech api via pure dcop (don't break compatibiltiy)
+-> CHG: right click and drag while in 'normal' mode changes to 'selection' mode and selects
+-> FIX: complete valgrind check and leakfix (2 leaks were present) [27-Jan-04]
+-> ADD: history, forward/back history actions, history links and xml storage (10 steps)
+-> ADD: rmb popup on thumbnailslist (the popup shared with pageView: same behavior)
+-> ADD: display 'current page' / 'total pages' with analog indicator, active labels, etc
+-> CHG: Presentation mode is now Ctrl+Shift+p instead of F9 because it was colliding with Konqueror's toggle sidebar
+-> FIX: various in memory unallocator, preload with single pages, pageview
+-> FIX: optimized pageView (removed 1 waster req on start, lowered reqs)
+-> FIX: memory unloading order and hard swap avoiding
+-> CHG: open and open-recent buttons unified in Shell
+-> CHG: lens icon for the find-ahead messages
+-> ADD: page preloading
+-> FIX: smarter memory management / prioritize queries
+-> ADD: type ahead search in pageview (type '/' then the word to search..) (JakubS)
+-> FIX: scroll page if the the searched string is not visible
+-> FIX: use a global Viewport over the document (linked views, real link following, location restoring, etc)
+-> FIX: wrong zoom buttons order (BR74248) (check consistancy with kdvi/kviewshell/kghostview/.. (not konq))
+-> ADD: presentation: cursor modes: hidden, visible, hidden with delay (Tobias)
+-> ADD: presentation: default transition which is used when no transition is defined in document (Tobias)
+-> ADD: presentation: support for automatic advance and loop on last page (Tobias)
+-> ADD: presentation: add additional presentation page to settings dialog (Tobias)
+-> CHG: presentation: the round wheel indicator can be clicked to change page
+-> FIX: layout margins on pageView
+-> ADD: restore the last active page when a file is opened again
+-> ADD: Save bookmarks into a file so you they get recovered when opening the same file again (Albert)
+-> FIX: searchline back to work
+-> CHG: DocumentInfo is now a DomTree and the properties dialog is dynamically generated (Tobias)
+-> ADD: Presentation transitions are loaded from the pdf files as well as fullscreen state (Tobias)
+-> Merged on HEAD on 2005-01-02 (The branch is frozen, development continues here)
+-> FIX: Fix my update cursor FIX :-D
+-> ADD: Make kpdf aware of Find and GoToPage actions
+-> FIX: Update cursor correctly when a link moves to a page and the cursor is over a link on that page
+-> ADD: Asyncronous PDF Generator implementation (for the user: faster UI, preloading, etc..)
+-> FIX: Memory manager (free cache if needed, avoid disk swap and oom)
+-> ADD: Presentation View (only the 'glitter' transition implemented for now)
+-> FIX: FixPack1 [dyn_zoom repaints, initial panel width, zoom_lineedit focus proxy, searchwidget refactor{thumbs restoring on clear, buttons size, less code}, hilight bookmarked thumbnails]
+-> FIX: Some fullScreen loving, if we are on fullscreen put an action on RMB menu ti get out of it, if we were on fullScreen mode on exit bring back correctly if we were also seeing toolbar or menubar
+-> FIX: When in non continuous mode and scrolling up a page, set the viewport at the bottom of the page (Albert)
+-> ADD: Show the window maximized when the user opens the program for the very first time (Albert)
+-> ADD: Use 'Generators' as providers for contents generation
+-> ADD: Add properties dialog (Albert)
+-> ADD: Support for show/hide menubar in rmb menu, different from HEAD so that supports Konqueror too (Albert)
+-> ADD: Watch File option (Albert)
+-> ADD: import Marco Martin's "another kpdf icon" (kde-look: 16146) (Albert)
+-> ADD: dynamic zoom with mid mouse button (click and drag up-down to zoom in-out)
+-> FIX: merge select text & select gfx, two sections on the same pop-up menu
+-> ADD: reading aids (inverted display, recolor, black/white, draw link border, draw image border)
+-> FIX: zoom preserved when switching modes and flickerless drawing
+-> ADD: Printing as PS instead of as image (Albert)
+-> ADD: Remember page on session logout and put the document in it on session restore (Albert)
+-> ADD: gfx capturing tool
+-> ADD: composited renderer framework (in addition to a fast light one)
+-> FIX: pageview repaint done internally (speed boost and reduced memory consumption)
+-> ADD: KConfigXT settings framework and Accessibility config (acc. code mostly not done)
+-> FIX: workaround for scrollview bug 1/2 (painting hidden widgets under certain circumstances)
+-> ADD: zoom into a rect defined by mouse (aka zoom to window)
+-> FIX: sheet rotation in landscape case
+-> ADD: Some dcop functions (goToPage, openDocument and give # of pages) (Albert)
+-> MRG: link following ('actionMovie' kind is missing)
+-> ADD: text selection (rectangular blocks) in selection mode
+-> ADD: autoscroll page with Shift+Up/Dn keys (exact konqueror's behavior)
+-> CHG: remake single page mode
+-> FIX: zoom buttons in sync with text
+-> ADD: continuous mode
+-> ADD: multiple pages per view (gui selects 1 or 2 ppv)
+-> MRG: the option to open password protected files (from head)
+-> MRG: the Table Of Contents (from head)
+-> ADD: a 'search bar' with prune-as-you-type feature
+-> MRG: Albert's search ported and implemented case sensitive
+-> CHG: smart handling of pixmap using an Observer ID (thumbnails are gone, only pixmaps now)
+-> FIX: some toolbar/menu changes
+-> ADD: outline bottom and right edges (of pages)
+-> FIX: centering pages in the view
+-> FIX: kpdf output at 100% has exactly the same size as acroread now
+-> CHG: qsplitter layouting
+-> FIX: zooming works as expected (and added 'fit to page' too)
+-> ADD: new go to page dialog
+-> GHG: previews sorted by visible areas (prioritize items where the scrollbar is)
+-> FIX: previews speedup: 50-100%
+-> CHG: use local instead of X memory for thumbnails (..)
+-> MRG: merge lots of kpdf_part and part (centralview) code (to simplify/clenup)
+-> The branch 'kpdf_experiments' was created at this point. Code refactoring started.
+-> ADD: Completely use xpdf code for rendering that solves most font problems (Albert)
+-> MRG: Replace xpdf version with lastest one (3.00) that supports PDF 1.5 (Albert)
+-> newest added features are at the top of the list
diff --git a/kpdf/VERSION b/kpdf/VERSION
new file mode 100644
index 00000000..146734d9
--- /dev/null
+++ b/kpdf/VERSION
@@ -0,0 +1 @@
+KPDF v0.5.10
diff --git a/kpdf/conf/Makefile.am b/kpdf/conf/Makefile.am
new file mode 100644
index 00000000..d115e8f9
--- /dev/null
+++ b/kpdf/conf/Makefile.am
@@ -0,0 +1,13 @@
+INCLUDES = -I$(srcdir)/.. -I$(top_builddir)/kpdf $(all_includes)
+
+METASOURCES = AUTO
+
+libkpdfconf_la_SOURCES = dlggeneral.ui dlgperformance.ui dlgaccessibility.ui \
+ dlgpresentation.ui \
+ preferencesdialog.cpp settings.kcfgc
+
+noinst_LTLIBRARIES = libkpdfconf.la
+
+kde_kcfg_DATA = kpdf.kcfg
+
+preferencesdialog.lo: settings.h
diff --git a/kpdf/conf/dlgaccessibility.ui b/kpdf/conf/dlgaccessibility.ui
new file mode 100644
index 00000000..a9f6495d
--- /dev/null
+++ b/kpdf/conf/dlgaccessibility.ui
@@ -0,0 +1,576 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>DlgAccessibility</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>DlgAccessibility</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>376</width>
+ <height>364</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_HighlightImages</cstring>
+ </property>
+ <property name="text">
+ <string>Draw border around &amp;Images</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_HighlightLinks</cstring>
+ </property>
+ <property name="text">
+ <string>Draw border around &amp;Links</string>
+ </property>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>kcfg_ChangeColors</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Change &amp;Colors</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>warn</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="paletteForegroundColor">
+ <color>
+ <red>80</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </property>
+ <property name="text">
+ <string>Warning: these options can badly affect drawing speed.</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>kcfg_RenderMode</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioInverted</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Invert colors</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioNormal</cstring>
+ </property>
+ <property name="text">
+ <string>Change &amp;paper color</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer14_3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Paper color:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_PaperColor</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton">
+ <property name="name">
+ <cstring>kcfg_PaperColor</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer7_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>30</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioRecolor</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Change dark and light colors</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <spacer row="1" column="3">
+ <property name="name">
+ <cstring>spacer12_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>48</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KColorButton" row="1" column="2">
+ <property name="name">
+ <cstring>kcfg_RecolorBackground</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer14_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KColorButton" row="0" column="2">
+ <property name="name">
+ <cstring>kcfg_RecolorForeground</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <spacer row="0" column="3">
+ <property name="name">
+ <cstring>spacer12</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>48</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>textLabel3_2</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Light color:</string>
+ </property>
+ </widget>
+ <spacer row="0" column="0">
+ <property name="name">
+ <cstring>spacer14</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Dark color:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioContrast</cstring>
+ </property>
+ <property name="text">
+ <string>Convert to &amp;black and white</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Contrast:</string>
+ </property>
+ </widget>
+ <spacer row="1" column="3">
+ <property name="name">
+ <cstring>spacer10_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>48</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer11_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="0" column="0">
+ <property name="name">
+ <cstring>spacer11</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="0" column="3">
+ <property name="name">
+ <cstring>spacer10</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>48</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QSlider" row="1" column="2">
+ <property name="name">
+ <cstring>kcfg_BWContrast</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="pageStep">
+ <number>1</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QSlider" row="0" column="2">
+ <property name="name">
+ <cstring>kcfg_BWThreshold</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="pageStep">
+ <number>16</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Threshold:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>radioRecolor</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>textLabel3</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>radioRecolor</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_RecolorForeground</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>radioRecolor</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>textLabel3_2</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>radioRecolor</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_RecolorBackground</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>radioContrast</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>textLabel2</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>radioContrast</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_BWThreshold</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>radioNormal</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>textLabel1</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>radioNormal</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_PaperColor</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>radioContrast</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>textLabel2_2</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>radioContrast</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_BWContrast</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>kcfg_ChangeColors</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_RenderMode</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="global" impldecl="in implementation">kdialog.h</include>
+</includes>
+<layoutdefaults spacing="5" margin="11"/>
+<includehints>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kpdf/conf/dlggeneral.ui b/kpdf/conf/dlggeneral.ui
new file mode 100644
index 00000000..0319d1b4
--- /dev/null
+++ b/kpdf/conf/dlggeneral.ui
@@ -0,0 +1,171 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>DlgGeneral</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>DlgGeneral</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>320</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>Program Look</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_ShowSearchBar</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Show &amp;search bar in thumbnails list</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_SyncThumbnailsViewport</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Link the &amp;thumbnails with the page</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_ShowScrollBars</cstring>
+ </property>
+ <property name="text">
+ <string>Show scroll&amp;bars</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_ShowOSD</cstring>
+ </property>
+ <property name="text">
+ <string>Show &amp;hints and info messages</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_ObeyDRM</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Obey DRM limitations</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_WatchFile</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Watch file</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3_2</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>pixmapLabel1_2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="pixmap">
+ <pixmap>"kpdf", 32</pixmap>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacerV1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Minimum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>1</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<includes>
+ <include location="global" impldecl="in implementation">kdialog.h</include>
+ <include location="global" impldecl="in implementation">kiconloader.h</include>
+ <include location="local" impldecl="in implementation">dlggeneral.ui.h</include>
+</includes>
+<functions>
+ <function access="protected" specifier="non virtual">showEvent( QShowEvent * )</function>
+</functions>
+<pixmapfunction>DesktopIcon</pixmapfunction>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kpdf/conf/dlggeneral.ui.h b/kpdf/conf/dlggeneral.ui.h
new file mode 100644
index 00000000..8eafde39
--- /dev/null
+++ b/kpdf/conf/dlggeneral.ui.h
@@ -0,0 +1,26 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you want to add, delete, or rename functions or slots, use
+** Qt Designer to update this file, preserving your code.
+**
+** You should not define a constructor or destructor in this file.
+** Instead, write your code in functions called init() and destroy().
+** These will automatically be called by the form's constructor and
+** destructor.
+*****************************************************************************/
+
+#include <kapplication.h>
+
+#include <config.h>
+
+void DlgGeneral::showEvent( QShowEvent * )
+{
+#if KPDF_FORCE_DRM
+ kcfg_ObeyDRM->hide();
+#else
+ if (kapp->authorize("skip_drm")) kcfg_ObeyDRM->show();
+ else kcfg_ObeyDRM->hide();
+#endif
+}
+
diff --git a/kpdf/conf/dlgperformance.ui b/kpdf/conf/dlgperformance.ui
new file mode 100644
index 00000000..c0c90eb1
--- /dev/null
+++ b/kpdf/conf/dlgperformance.ui
@@ -0,0 +1,278 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>DlgPerformance</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>DlgPerformance</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>284</width>
+ <height>222</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>CPU Usage</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout9</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_EnableCompositing</cstring>
+ </property>
+ <property name="text">
+ <string>Enable &amp;transparency effects</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>kcfg_EnableThreading</cstring>
+ </property>
+ <property name="text">
+ <string>Enable &amp;background generation</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout6_2</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>pixmapLabel1_2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="pixmap">
+ <pixmap>"kcmprocessor", 32</pixmap>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer7_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Minimum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>1</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>kcfg_MemoryLevel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Memory Usage</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>descLabel</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ <property name="alignment">
+ <set>WordBreak|AlignVCenter</set>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>lowRadio</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Low</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>normalRadio</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Normal (default)</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>aggressiveRadio</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Aggressive</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="1">
+ <property name="name">
+ <cstring>layout6</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>pixmapLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="pixmap">
+ <pixmap>"kcmmemory", 32</pixmap>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Minimum</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>1</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>21</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>lowRadio</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>DlgPerformance</receiver>
+ <slot>lowRadio_toggled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>normalRadio</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>DlgPerformance</receiver>
+ <slot>normalRadio_toggled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>aggressiveRadio</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>DlgPerformance</receiver>
+ <slot>aggressiveRadio_toggled(bool)</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="global" impldecl="in implementation">kdialog.h</include>
+ <include location="global" impldecl="in implementation">kiconloader.h</include>
+ <include location="local" impldecl="in implementation">dlgperformance.ui.h</include>
+</includes>
+<slots>
+ <slot>lowRadio_toggled( bool on )</slot>
+ <slot>normalRadio_toggled( bool on )</slot>
+ <slot>aggressiveRadio_toggled( bool on )</slot>
+</slots>
+<functions>
+ <function access="private">init()</function>
+</functions>
+<pixmapfunction>DesktopIcon</pixmapfunction>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kpdf/conf/dlgperformance.ui.h b/kpdf/conf/dlgperformance.ui.h
new file mode 100644
index 00000000..4a13310e
--- /dev/null
+++ b/kpdf/conf/dlgperformance.ui.h
@@ -0,0 +1,38 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <klocale.h>
+
+// The purpose of this file is only to display a sort of descriptive text
+// when the user clicks on each memory profile.
+
+void DlgPerformance::init()
+{
+ QFont labelFont = descLabel->font();
+ labelFont.setBold( true );
+ descLabel->setFont( labelFont );
+}
+
+void DlgPerformance::lowRadio_toggled( bool on )
+{
+ if ( on )
+ descLabel->setText( i18n("Keeps used memory as low as possible. Do not reuse anything. (For systems with low memory.)") );
+}
+
+void DlgPerformance::normalRadio_toggled( bool on )
+{
+ if ( on )
+ descLabel->setText( i18n("A good compromise between memory usage and speed gain. Preload next page and boost searches. (For systems with 256MB of memory, typically.)") );
+}
+
+void DlgPerformance::aggressiveRadio_toggled( bool on )
+{
+ if ( on )
+ descLabel->setText( i18n("Keeps everything in memory. Preload next pages. Boost searches. (For systems with more than 512MB of memory.)") );
+}
diff --git a/kpdf/conf/dlgpresentation.ui b/kpdf/conf/dlgpresentation.ui
new file mode 100644
index 00000000..ba65f7b1
--- /dev/null
+++ b/kpdf/conf/dlgpresentation.ui
@@ -0,0 +1,282 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>DlgPresentation</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>DlgPresentation</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>294</width>
+ <height>261</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Navigation</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout1</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QSpinBox" row="0" column="1">
+ <property name="name">
+ <cstring>kcfg_SlidesAdvanceTime</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="suffix">
+ <string> sec.</string>
+ </property>
+ <property name="value">
+ <number>5</number>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="0">
+ <property name="name">
+ <cstring>kcfg_SlidesAdvance</cstring>
+ </property>
+ <property name="text">
+ <string>Advance every:</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="2" column="0">
+ <property name="name">
+ <cstring>kcfg_SlidesLoop</cstring>
+ </property>
+ <property name="text">
+ <string>Loop after last page</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>groupBox2</cstring>
+ </property>
+ <property name="title">
+ <string>Appearance</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QComboBox" row="1" column="1">
+ <item>
+ <property name="text">
+ <string>Blinds Vertical</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Blinds Horizontal</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Box In</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Box Out</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Dissolve</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Glitter Down</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Glitter Right</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Glitter Right-Down</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Random Transition</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Replace</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Split Horizontal In</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Split Horizontal Out</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Split Vertical In</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Split Vertical Out</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Wipe Down</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Wipe Right</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Wipe Left</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Wipe Up</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>kcfg_SlidesTransition</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Default transition:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Mouse cursor:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="2" column="1">
+ <item>
+ <property name="text">
+ <string>Hidden After Delay</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Always Visible</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Always Hidden</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>kcfg_SlidesCursor</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Background color:</string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="0" column="1">
+ <property name="name">
+ <cstring>kcfg_SlidesBackgroundColor</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="4" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>kcfg_SlidesShowSummary</cstring>
+ </property>
+ <property name="text">
+ <string>Show s&amp;ummary page</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="3" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>kcfg_SlidesShowProgress</cstring>
+ </property>
+ <property name="text">
+ <string>Show &amp;progress indicator</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>bspace</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>1</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>kcfg_SlidesAdvance</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_SlidesAdvanceTime</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kcolorbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kpdf/conf/kpdf.kcfg b/kpdf/conf/kpdf.kcfg
new file mode 100644
index 00000000..d980fd95
--- /dev/null
+++ b/kpdf/conf/kpdf.kcfg
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="kpdfpartrc" />
+ <group name="Accessibility" >
+ <entry key="PaperColor" type="Color" >
+ <default code="true" >Qt::white</default>
+ </entry>
+ <entry key="HighlightImages" type="Bool" >
+ <default>false</default>
+ </entry>
+ <entry key="HighlightLinks" type="Bool" >
+ <default>false</default>
+ </entry>
+ <entry key="ChangeColors" type="Bool" >
+ <default>false</default>
+ </entry>
+ <entry key="RenderMode" type="Enum" >
+ <default>Inverted</default>
+ <choices>
+ <choice name="Inverted" />
+ <choice name="Paper" />
+ <choice name="pad_paper_color" />
+ <choice name="Recolor" />
+ <choice name="pad_fg_color" />
+ <choice name="pad_bg_color" />
+ <choice name="BlackWhite" />
+ </choices>
+ </entry>
+ <entry key="RecolorForeground" type="Color" >
+ <default code="true" >0x600000</default>
+ </entry>
+ <entry key="RecolorBackground" type="Color" >
+ <default code="true" >0xF0F0F0</default>
+ </entry>
+ <entry key="BWThreshold" type="UInt" >
+ <default>127</default>
+ <min>2</min>
+ <max>253</max>
+ </entry>
+ <entry key="BWContrast" type="UInt" >
+ <default>2</default>
+ <min>2</min>
+ <max>6</max>
+ </entry>
+ </group>
+ <group name="General" >
+ <entry key="ShowOSD" type="Bool" >
+ <default>true</default>
+ </entry>
+ <entry key="WatchFile" type="Bool" >
+ <default>true</default>
+ </entry>
+ <entry key="ObeyDRM" type="Bool" >
+ <default>true</default>
+ </entry>
+ </group>
+ <group name="MainView" >
+ <entry key="ShowLeftPanel" type="Bool" >
+ <default>true</default>
+ </entry>
+ <entry key="ShowSearchBar" type="Bool" >
+ <default>true</default>
+ </entry>
+ <entry key="SplitterSizes" type="IntList" />
+ </group>
+ <group name="PageView" >
+ <entry key="ShowScrollBars" type="Bool" >
+ <default>true</default>
+ </entry>
+ <entry key="ViewContinuous" type="Bool" >
+ <default>true</default>
+ </entry>
+ <entry key="ViewColumns" type="UInt" >
+ <default>1</default>
+ <min>1</min>
+ <max>8</max>
+ </entry>
+ <entry key="ZoomMode" type="UInt" >
+ <default>0</default>
+ <max>2</max>
+ </entry>
+ <entry key="ZoomFactor" type="Double" >
+ <default>1.0</default>
+ <min>0.1</min>
+ <max>4.0</max>
+ </entry>
+ </group>
+ <group name="ThumbnailsList" >
+ <entry key="SyncThumbnailsViewport" type="Bool" >
+ <default>true</default>
+ </entry>
+ </group>
+ <group name="Performance" >
+ <entry key="MemoryLevel" type="Enum" >
+ <default>Normal</default>
+ <choices>
+ <choice name="Low" />
+ <choice name="Normal" />
+ <choice name="Aggressive" />
+ <choice name="pad_description" />
+ </choices>
+ </entry>
+ <entry key="EnableCompositing" type="Bool" >
+ <default>true</default>
+ </entry>
+ <entry key="EnableThreading" type="Bool" >
+ <default>true</default>
+ </entry>
+ </group>
+ <group name="Presentation" >
+ <entry key="SlidesAdvance" type="Bool" >
+ <default>false</default>
+ </entry>
+ <entry key="SlidesAdvanceTime" type="UInt" >
+ <default>5</default>
+ <min>1</min>
+ <max>3600</max>
+ </entry>
+ <entry key="SlidesLoop" type="Bool" >
+ <default>false</default>
+ </entry>
+ <entry key="SlidesBackgroundColor" type="Color" >
+ <default code="true" >Qt::black</default>
+ </entry>
+ <entry key="SlidesTransition" type="Enum" >
+ <default>Replace</default>
+ <choices>
+ <choice name="BlindsHorizontal" />
+ <choice name="BlindsVertical" />
+ <choice name="BoxIn" />
+ <choice name="BoxOut" />
+ <choice name="Dissolve" />
+ <choice name="GlitterDown" />
+ <choice name="GlitterRight" />
+ <choice name="GlitterRightDown" />
+ <choice name="Random" />
+ <choice name="Replace" />
+ <choice name="SplitHorizontalIn" />
+ <choice name="SplitHorizontalOut" />
+ <choice name="SplitVerticalIn" />
+ <choice name="SplitVerticalOut" />
+ <choice name="WipeDown" />
+ <choice name="WipeRight" />
+ <choice name="WipeLeft" />
+ <choice name="WipeUp" />
+ </choices>
+ </entry>
+ <entry key="SlidesCursor" type="Enum" >
+ <default>HiddenDelay</default>
+ <choices>
+ <choice name="HiddenDelay" />
+ <choice name="Visible" />
+ <choice name="Hidden" />
+ </choices>
+ </entry>
+ <entry key="SlidesShowProgress" type="Bool" >
+ <default>true</default>
+ </entry>
+ <entry key="SlidesShowSummary" type="Bool" >
+ <default>false</default>
+ </entry>
+ </group>
+ <group name="Internal Status" >
+ <entry key="FilterBookmarks" type="Bool" >
+ <default>false</default>
+ </entry>
+ <entry key="UseKTTSD" type="Bool" />
+ </group>
+ <group name="Debugging Options" >
+ <entry key="DebugDrawBoundaries" type="Bool" >
+ <default>false</default>
+ </entry>
+ </group>
+</kcfg>
diff --git a/kpdf/conf/preferencesdialog.cpp b/kpdf/conf/preferencesdialog.cpp
new file mode 100644
index 00000000..7968d3fd
--- /dev/null
+++ b/kpdf/conf/preferencesdialog.cpp
@@ -0,0 +1,34 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <klocale.h>
+
+// single config pages
+#include "dlggeneral.h"
+#include "dlgperformance.h"
+#include "dlgaccessibility.h"
+#include "dlgpresentation.h"
+
+// reimplementing this
+#include "preferencesdialog.h"
+
+PreferencesDialog::PreferencesDialog( QWidget * parent, KConfigSkeleton * skeleton )
+ : KConfigDialog( parent, "preferences", skeleton )
+{
+ m_general = new DlgGeneral(0);
+ m_performance = new DlgPerformance(0);
+ m_accessibility = new DlgAccessibility(0);
+ m_presentation = new DlgPresentation(0);
+
+ addPage( m_general, i18n("General"), "kpdf", i18n("General Options") );
+ addPage( m_accessibility, i18n("Accessibility"), "access", i18n("Reading Aids") );
+ addPage( m_performance, i18n("Performance"), "launch", i18n("Performance Tuning") );
+ addPage( m_presentation, i18n("Presentation"), "kpresenter_kpr",
+ i18n("Options for Presentation Mode") );
+}
diff --git a/kpdf/conf/preferencesdialog.h b/kpdf/conf/preferencesdialog.h
new file mode 100644
index 00000000..475320ab
--- /dev/null
+++ b/kpdf/conf/preferencesdialog.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef _PREFERENCESDIALOG_H
+#define _PREFERENCESDIALOG_H
+
+#include <kconfigdialog.h>
+#include "conf/settings.h"
+
+class QWidget;
+class KConfigSkeleton;
+
+class DlgGeneral;
+class DlgPerformance;
+class DlgAccessibility;
+class DlgPresentation;
+
+class PreferencesDialog : public KConfigDialog
+{
+
+ public:
+ PreferencesDialog( QWidget * parent, KConfigSkeleton * config );
+
+ protected:
+// void updateSettings(); // Called when OK/Apply is pressed.
+// void updateWidgets(); // Called upon construction or when Reset is pressed
+// void updateWidgetsDefault(); // Called when Defaults button is pressed
+// bool hasChanged(); // In order to correctly disable/enable Apply button
+// bool isDefault(); // In order to correctly disable/enable Defaults button
+
+ private:
+ DlgGeneral * m_general;
+ DlgPerformance * m_performance;
+ DlgAccessibility * m_accessibility;
+ DlgPresentation * m_presentation;
+};
+
+#endif
diff --git a/kpdf/conf/settings.kcfgc b/kpdf/conf/settings.kcfgc
new file mode 100644
index 00000000..bfdad9ee
--- /dev/null
+++ b/kpdf/conf/settings.kcfgc
@@ -0,0 +1,4 @@
+ClassName=KpdfSettings
+File=kpdf.kcfg
+Mutators=true
+Singleton=true
diff --git a/kpdf/configure.in.bot b/kpdf/configure.in.bot
new file mode 100644
index 00000000..03feefcc
--- /dev/null
+++ b/kpdf/configure.in.bot
@@ -0,0 +1,30 @@
+if test -z "$FREETYPE_CONFIG"; then
+ echo ""
+ echo "You're missing freetype development libs."
+ echo "KPDF will not be build without them"
+ echo ""
+fi
+
+if test x$FREETYPE_VERSION != x; then
+ if test $FREETYPE_VERSION -lt 9008003; then
+ echo ""
+ echo "You're using freetype older than 2.1.10, it is not mandatory"
+ echo "to use 2.1.10 but kpdf improves its rendering in some pdf with it"
+ echo ""
+ fi
+fi
+
+if test -z "$XFT_LIBS"; then
+ echo ""
+ echo "You're missing XFT development libs."
+ echo "KPDF will not be build without them"
+ echo ""
+fi
+
+if test "$HAVE_LIBJPEG" = "no"; then
+ echo ""
+ echo "You're missing libjpeg development libs."
+ echo "KPDF will not be build without them"
+ echo ""
+fi
+
diff --git a/kpdf/configure.in.in b/kpdf/configure.in.in
new file mode 100644
index 00000000..db883adb
--- /dev/null
+++ b/kpdf/configure.in.in
@@ -0,0 +1,124 @@
+dnl ##### Check for FreeType 2.0.5+.
+dnl ##### (Note: FT_Get_Name_Index was added in FT 2.0.5, and is
+dnl ##### the reason that Xpdf requires 2.0.5+.)
+
+KDE_FIND_PATH(freetype-config, FREETYPE_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin], [
+ AC_MSG_WARN([Could not find libfreetype anywhere, check http://www.freetype.org/])
+])
+
+if test -n "$FREETYPE_CONFIG"; then
+ FREETYPE_VERSION=`$FREETYPE_CONFIG --version 2>/dev/null | sed -e 's/libfreetype //' | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'`
+ if test -n "$FREETYPE_VERSION" && test "$FREETYPE_VERSION" -ge 9000000; then
+ LIBFREETYPE_LIBS="`$FREETYPE_CONFIG --libs`"
+ LIBFREETYPE_RPATH=
+ for args in $LIBFREETYPE_LIBS; do
+ case $args in
+ -L*) LIBFREETYPE_RPATH="$LIBFREETYPE_RPATH $args" ;;
+ esac
+ done
+ LIBFREETYPE_RPATH=`echo $LIBFREETYPE_RPATH | sed -e "s/-L/-R/g"`
+ LIBFREETYPE_CFLAGS="`$FREETYPE_CONFIG --cflags`"
+ AC_DEFINE_UNQUOTED(HAVE_FREETYPE, 1, [Defines if your system has the freetype library])
+ else
+ AC_MSG_WARN([You need at least libfreetype 2.0.5])
+ DO_NOT_COMPILE="$DO_NOT_COMPILE kpdf"
+ fi
+else
+ DO_NOT_COMPILE="$DO_NOT_COMPILE kpdf"
+fi
+
+AC_SUBST(FREETYPE_VERSION)
+AC_SUBST(LIBFREETYPE_LIBS)
+AC_SUBST(LIBFREETYPE_CFLAGS)
+AC_SUBST(LIBFREETYPE_RPATH)
+
+# Check for dirent
+AC_HEADER_DIRENT
+
+# Check for xft
+KDE_PKG_CHECK_MODULES(XFT, xft >= 2.0, ,
+ # This older xft-config stuff can (eventually) go away.
+ KDE_FIND_PATH(xft-config, XFT_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin],)
+ if "$XFT_CONFIG"; then
+ XFT_CFLAGS="`$XFT_CONFIG --cflags`"
+ XFT_LIBS="`$XFT_CONFIG --libs`"
+ fi
+ AC_SUBST(XFT_CFLAGS)
+ AC_SUBST(XFT_LIBS)
+)
+
+if test -z "$XFT_LIBS"; then
+ DO_NOT_COMPILE="$DO_NOT_COMPILE kpdf"
+fi
+
+dnl ##### Check for libpaper (Debian).
+LIBPAPER_LIBS=
+KDE_CHECK_HEADER(paper.h, [
+ LIBPAPER_LIBS='-lpaper'
+ AC_DEFINE_UNQUOTED(HAVE_PAPER_H, 1, [Define to 1 if you have the <paper.h> header file.])
+],
+ AC_DEFINE_UNQUOTED(HAVE_PAPER_H, 0, [Define to 1 if you have the <paper.h> header file.])
+)
+AC_SUBST(LIBPAPER_LIBS)
+
+AC_CHECK_FUNCS(fseek64 mkstemp mkstemps popen)
+
+AC_FIND_FILE(xpdfrc, [/etc /usr/local/etc /etc/xpdf], xpdfrc)
+if test "$xpdfrc" != NO; then
+ AC_DEFINE_UNQUOTED(SYSTEM_XPDFRC, "$xpdfrc/xpdfrc", [Define the location your xpdfrc])
+fi
+
+dnl #### Check for FSEEK variants
+KDE_CHECK_LARGEFILE
+AC_FUNC_FSEEKO
+AC_CHECK_FUNCS(fseek64, xpdf_cv_func_fseek64=yes, xpdf_cv_func_fseek64=no)
+AC_CHECK_FUNCS(ftell64, xpdf_cv_func_ftell64=yes, xpdf_cv_func_ftell64=no)
+if test "$xpdf_cv_func_fseek64" = yes -a "$xpdf_cv_func_ftell64" = yes; then
+ AC_DEFINE(HAVE_FSEEK64, 1)
+else
+ AC_DEFINE(HAVE_FSEEK64, 0)
+fi
+
+dnl #### Enable the user to enable multithearind on xpdf
+AC_ARG_ENABLE(multithreaded-kpdf,
+ AC_HELP_STRING([--enable-multithreaded-kpdf],[include support for multithreading in xpdf code inside kpdf. Has nothing to do with threaded generation of contents, this is configurable via a dialog inside the program itself]),
+[
+ case $enableval in
+ yes)
+ AC_DEFINE(MULTITHREADED, 1, [Defines if use multithreading in xpdf code inside kpdf])
+ ;;
+ no)
+ AC_DEFINE(MULTITHREADED, 0, [Defines if use multithreading in xpdf code inside kpdf])
+ ;;
+ *)
+ AC_DEFINE(MULTITHREADED, 1, [Defines if use multithreading in xpdf code inside kpdf])
+ ;;
+ esac
+]
+, AC_DEFINE(MULTITHREADED, 0, [Defines if use multithreading in xpdf code inside kpdf])
+)
+
+dnl #### Enable the user to decide if he wants to force drm or not
+AC_ARG_ENABLE(force-kpdf-drm,
+ AC_HELP_STRING([--enable-force-kpdf-drm],[Forces kpdf to check for DRM to decide if you can copy/print protected pdf. (default=no)]),
+[
+ case $enableval in
+ yes)
+ AC_DEFINE(KPDF_FORCE_DRM, 1, [Defines if force the use DRM in kpdf])
+ ;;
+ no)
+ AC_DEFINE(KPDF_FORCE_DRM, 0, [Defines if force the use DRM in kpdf])
+ ;;
+ *)
+ AC_DEFINE(KPDF_FORCE_DRM, 1, [Defines if force the use DRM in kpdf])
+ ;;
+ esac
+]
+, AC_DEFINE(KPDF_FORCE_DRM, 0, [Defines if force the use DRM in kpdf])
+)
+
+KDE_CHECK_COMPILER_FLAG([fno-regmove], SUPPORTS_NOREGMOVE=true, SUPPORTS_NOREGMOVE=false)
+if test "x$SUPPORTS_NOREGMOVE" = xtrue; then
+ NOREGMOVE="-fno-regmove"
+fi
+AC_SUBST(NOREGMOVE)
diff --git a/kpdf/core/Makefile.am b/kpdf/core/Makefile.am
new file mode 100644
index 00000000..74c77485
--- /dev/null
+++ b/kpdf/core/Makefile.am
@@ -0,0 +1,13 @@
+SUBDIRS = generator_pdf generator_kimgio
+
+INCLUDES = -I$(srcdir)/generator_pdf -I$(srcdir)/.. -I$(srcdir)/../xpdf -I$(srcdir)/../xpdf/goo -I$(top_builddir)/kpdf $(all_includes)
+
+METASOURCES = AUTO
+
+libkpdfcore_la_LIBADD = ./generator_pdf/libgeneratorpdf.la ./generator_kimgio/libgeneratorkimgio.la
+libkpdfcore_la_SOURCES = document.cpp link.cpp page.cpp pagetransition.cpp
+
+noinst_LTLIBRARIES = libkpdfcore.la
+
+document.lo: ../conf/settings.h
+page.lo: ../conf/settings.h
diff --git a/kpdf/core/document.cpp b/kpdf/core/document.cpp
new file mode 100644
index 00000000..25e19d9a
--- /dev/null
+++ b/kpdf/core/document.cpp
@@ -0,0 +1,1634 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
+ * Copyright (C) 2004-2005 by Albert Astals Cid <tsdgeos@terra.es> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+// qt/kde/system includes
+#include <qdir.h>
+#include <qfile.h>
+#include <qfileinfo.h>
+#include <qimage.h>
+#include <qtextstream.h>
+#include <qvaluevector.h>
+#include <qtimer.h>
+#include <qmap.h>
+#include <kdebug.h>
+#include <kimageio.h>
+#include <klocale.h>
+#include <kfinddialog.h>
+#include <kmessagebox.h>
+#include <kapplication.h>
+#include <kuserprofile.h>
+#include <krun.h>
+#include <kstandarddirs.h>
+
+// local includes
+#include "document.h"
+#include "observer.h"
+#include "page.h"
+#include "link.h"
+#include "generator_pdf/generator_pdf.h" // PDF generator
+#include "generator_kimgio/generator_kimgio.h" // KIMGIO generator
+#include "conf/settings.h"
+
+// structures used internally by KPDFDocument for local variables storage
+class AllocatedPixmap;
+class RunningSearch;
+class KPDFDocumentPrivate
+{
+ public:
+ // find descriptors, mapped by ID (we handle multiple searches)
+ QMap< int, RunningSearch * > searches;
+ int m_lastSearchID;
+
+ // needed because for remote documents docFileName is a local file and
+ // we want the remote url when the document refers to relativeNames
+ KURL url;
+
+ // cached stuff
+ QString docFileName;
+ QString xmlFileName;
+
+ // a list of the mimetypes qimage can understand
+ QStringList kimgioMimes;
+
+ // viewport stuff
+ QValueList< DocumentViewport > viewportHistory;
+ QValueList< DocumentViewport >::iterator viewportIterator;
+ DocumentViewport nextDocumentViewport; // see KPDFLink::Goto for an explanation
+
+ // observers / requests / allocator stuff
+ QMap< int, DocumentObserver * > observers;
+ QValueList< PixmapRequest * > pixmapRequestsStack;
+ QValueList< AllocatedPixmap * > allocatedPixmapsFifo;
+ int allocatedPixmapsTotalMemory;
+
+ // timers (memory checking / info saver)
+ QTimer * memCheckTimer;
+ QTimer * saveBookmarksTimer;
+};
+
+struct AllocatedPixmap
+{
+ // owner of the page
+ int id;
+ int page;
+ int memory;
+ // public constructor: initialize data
+ AllocatedPixmap( int i, int p, int m ) : id( i ), page( p ), memory( m ) {};
+};
+
+struct RunningSearch
+{
+ // store search properties
+ int continueOnPage;
+ NormalizedRect continueOnMatch;
+ QValueList< int > highlightedPages;
+
+ // fields related to previous searches (used for 'continueSearch')
+ QString cachedString;
+ KPDFDocument::SearchType cachedType;
+ bool cachedCaseSensitive;
+ bool cachedViewportMove;
+ bool cachedNoDialogs;
+ QColor cachedColor;
+};
+
+#define foreachObserver( cmd ) {\
+ QMap< int, DocumentObserver * >::iterator it=d->observers.begin(), end=d->observers.end();\
+ for ( ; it != end ; ++ it ) { (*it)-> cmd ; } }
+
+
+/** KPDFDocument **/
+
+KPDFDocument::KPDFDocument(QWidget *widget)
+ : QObject(widget), generator( 0 ), d( new KPDFDocumentPrivate )
+{
+ d->allocatedPixmapsTotalMemory = 0;
+ d->memCheckTimer = 0;
+ d->saveBookmarksTimer = 0;
+ d->m_lastSearchID = -1;
+ KImageIO::registerFormats();
+ QStringList list = QImage::inputFormatList();
+ QStringList::Iterator it = list.begin();
+ while( it != list.end() )
+ {
+ d->kimgioMimes << KMimeType::findByPath(QString("foo.%1").arg(*it), 0, true)->name();
+ ++it;
+ }
+}
+
+KPDFDocument::~KPDFDocument()
+{
+ // delete generator, pages, and related stuff
+ closeDocument();
+
+ // delete the private structure
+ delete d;
+}
+
+
+bool KPDFDocument::openDocument( const QString & docFile, const KURL & url, const KMimeType::Ptr &mime )
+{
+ // docFile is always local so we can use QFile on it
+ QFile fileReadTest( docFile );
+ if ( !fileReadTest.open( IO_ReadOnly ) )
+ {
+ d->docFileName = QString::null;
+ return false;
+ }
+ // determine the related "xml document-info" filename
+ d->url = url;
+ d->docFileName = docFile;
+ QString fn = docFile.contains('/') ? docFile.section('/', -1, -1) : docFile;
+ fn = "kpdf/" + QString::number(fileReadTest.size()) + "." + fn + ".xml";
+ fileReadTest.close();
+ d->xmlFileName = locateLocal( "data", fn );
+
+ // create the generator based on the file's mimetype
+ if ( (*mime).is( "application/pdf" ) )
+ generator = new PDFGenerator( this );
+// else if ( mimeName == "application/postscript" )
+// kdError() << "PS generator not available" << endl;
+ else
+ {
+ QStringList::Iterator it = d->kimgioMimes.begin();
+ while( it != d->kimgioMimes.end() )
+ {
+ kdDebug() << *it << endl;
+ if ( (*mime).is( *it ) )
+ {
+ generator = new KIMGIOGenerator( this );
+ break;
+ }
+ ++it;
+ }
+ if ( it == d->kimgioMimes.end() )
+ {
+ kdWarning() << "Unknown mimetype '" << mime->name() << "'." << endl;
+ return false;
+ }
+ }
+
+ // 1. load Document (and set busy cursor while loading)
+ QApplication::setOverrideCursor( waitCursor );
+ bool openOk = generator->loadDocument( docFile, pages_vector );
+ QApplication::restoreOverrideCursor();
+ if ( !openOk || pages_vector.size() <= 0 )
+ {
+ delete generator;
+ generator = 0;
+ return openOk;
+ }
+
+ // 2. load Additional Data (our bookmarks and metadata) about the document
+ loadDocumentInfo();
+
+ // 3. setup observers inernal lists and data
+ foreachObserver( notifySetup( pages_vector, true ) );
+
+ // 4. set initial page (restoring the page saved in xml if loaded)
+ DocumentViewport loadedViewport = (*d->viewportIterator);
+ if ( loadedViewport.pageNumber != -1 )
+ (*d->viewportIterator) = DocumentViewport();
+ else
+ loadedViewport.pageNumber = 0;
+ setViewport( loadedViewport );
+
+ // start bookmark saver timer
+ if ( !d->saveBookmarksTimer )
+ {
+ d->saveBookmarksTimer = new QTimer( this );
+ connect( d->saveBookmarksTimer, SIGNAL( timeout() ), this, SLOT( saveDocumentInfo() ) );
+ }
+ d->saveBookmarksTimer->start( 5 * 60 * 1000 );
+
+ // start memory check timer
+ if ( !d->memCheckTimer )
+ {
+ d->memCheckTimer = new QTimer( this );
+ connect( d->memCheckTimer, SIGNAL( timeout() ), this, SLOT( slotTimedMemoryCheck() ) );
+ }
+ d->memCheckTimer->start( 2000 );
+
+ if (d->nextDocumentViewport.pageNumber != -1)
+ {
+ setViewport(d->nextDocumentViewport);
+ d->nextDocumentViewport = DocumentViewport();
+ }
+
+ return true;
+}
+
+void KPDFDocument::closeDocument()
+{
+ // save document info if a document is still opened
+ if ( generator && pages_vector.size() > 0 )
+ saveDocumentInfo();
+
+ // stop timers
+ if ( d->memCheckTimer )
+ d->memCheckTimer->stop();
+ if ( d->saveBookmarksTimer )
+ d->saveBookmarksTimer->stop();
+
+ // delete contents generator
+ delete generator;
+ generator = 0;
+
+ d->url = KURL();
+
+ // remove requests left in queue
+ QValueList< PixmapRequest * >::iterator sIt = d->pixmapRequestsStack.begin();
+ QValueList< PixmapRequest * >::iterator sEnd = d->pixmapRequestsStack.end();
+ for ( ; sIt != sEnd; ++sIt )
+ delete *sIt;
+ d->pixmapRequestsStack.clear();
+
+ // send an empty list to observers (to free their data)
+ foreachObserver( notifySetup( QValueVector< KPDFPage * >(), true ) );
+
+ // delete pages and clear 'pages_vector' container
+ QValueVector< KPDFPage * >::iterator pIt = pages_vector.begin();
+ QValueVector< KPDFPage * >::iterator pEnd = pages_vector.end();
+ for ( ; pIt != pEnd; ++pIt )
+ delete *pIt;
+ pages_vector.clear();
+
+ // clear 'memory allocation' descriptors
+ QValueList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin();
+ QValueList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end();
+ for ( ; aIt != aEnd; ++aIt )
+ delete *aIt;
+ d->allocatedPixmapsFifo.clear();
+
+ // clear 'running searches' descriptors
+ QMap< int, RunningSearch * >::iterator rIt = d->searches.begin();
+ QMap< int, RunningSearch * >::iterator rEnd = d->searches.end();
+ for ( ; rIt != rEnd; ++rIt )
+ delete *rIt;
+ d->searches.clear();
+
+ // reset internal variables
+ d->viewportHistory.clear();
+ d->viewportHistory.append( DocumentViewport() );
+ d->viewportIterator = d->viewportHistory.begin();
+ d->allocatedPixmapsTotalMemory = 0;
+}
+
+
+void KPDFDocument::addObserver( DocumentObserver * pObserver )
+{
+ // keep the pointer to the observer in a map
+ d->observers[ pObserver->observerId() ] = pObserver;
+
+ // if the observer is added while a document is already opened, tell it
+ if ( !pages_vector.isEmpty() )
+ {
+ pObserver->notifySetup( pages_vector, true );
+ pObserver->notifyViewportChanged( false /*disables smoothMove*/ );
+ }
+}
+
+void KPDFDocument::removeObserver( DocumentObserver * pObserver )
+{
+ // remove observer from the map. it won't receive notifications anymore
+ if ( d->observers.contains( pObserver->observerId() ) )
+ {
+ // free observer's pixmap data
+ int observerId = pObserver->observerId();
+ QValueVector<KPDFPage*>::iterator it = pages_vector.begin(), end = pages_vector.end();
+ for ( ; it != end; ++it )
+ (*it)->deletePixmap( observerId );
+
+ // [MEM] free observer's allocation descriptors
+ QValueList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin();
+ QValueList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end();
+ while ( aIt != aEnd )
+ {
+ AllocatedPixmap * p = *aIt;
+ if ( p->id == observerId )
+ {
+ aIt = d->allocatedPixmapsFifo.remove( aIt );
+ delete p;
+ }
+ else
+ ++aIt;
+ }
+
+ // delete observer entry from the map
+ d->observers.remove( observerId );
+ }
+}
+
+void KPDFDocument::reparseConfig()
+{
+ // reparse generator config and if something changed clear KPDFPages
+ if ( generator && generator->reparseConfig() )
+ {
+ // invalidate pixmaps
+ QValueVector<KPDFPage*>::iterator it = pages_vector.begin(), end = pages_vector.end();
+ for ( ; it != end; ++it )
+ (*it)->deletePixmapsAndRects();
+
+ // [MEM] remove allocation descriptors
+ QValueList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin();
+ QValueList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end();
+ for ( ; aIt != aEnd; ++aIt )
+ delete *aIt;
+ d->allocatedPixmapsFifo.clear();
+ d->allocatedPixmapsTotalMemory = 0;
+
+ // send reload signals to observers
+ foreachObserver( notifyContentsCleared( DocumentObserver::Pixmap ) );
+ }
+
+ // free memory if in 'low' profile
+ if ( KpdfSettings::memoryLevel() == KpdfSettings::EnumMemoryLevel::Low &&
+ !d->allocatedPixmapsFifo.isEmpty() && !pages_vector.isEmpty() )
+ cleanupPixmapMemory();
+}
+
+
+QWidget *KPDFDocument::widget() const
+{
+ return static_cast<QWidget*>(parent());
+}
+
+bool KPDFDocument::isOpened() const
+{
+ return generator;
+}
+
+const DocumentInfo * KPDFDocument::documentInfo() const
+{
+ return generator ? generator->generateDocumentInfo() : NULL;
+}
+
+const DocumentSynopsis * KPDFDocument::documentSynopsis() const
+{
+ return generator ? generator->generateDocumentSynopsis() : NULL;
+}
+
+const KPDFPage * KPDFDocument::page( uint n ) const
+{
+ return ( n < pages_vector.count() ) ? pages_vector[n] : 0;
+}
+
+const DocumentViewport & KPDFDocument::viewport() const
+{
+ return (*d->viewportIterator);
+}
+
+uint KPDFDocument::currentPage() const
+{
+ return (*d->viewportIterator).pageNumber;
+}
+
+uint KPDFDocument::pages() const
+{
+ return pages_vector.size();
+}
+
+KURL KPDFDocument::currentDocument() const
+{
+ return d->url;
+}
+
+bool KPDFDocument::isAllowed( int flags ) const
+{
+ return generator ? generator->isAllowed( flags ) : false;
+}
+
+bool KPDFDocument::historyAtBegin() const
+{
+ return d->viewportIterator == d->viewportHistory.begin();
+}
+
+bool KPDFDocument::historyAtEnd() const
+{
+ return d->viewportIterator == --(d->viewportHistory.end());
+}
+
+QString KPDFDocument::getMetaData( const QString & key, const QString & option ) const
+{
+ return generator ? generator->getMetaData( key, option ) : QString();
+}
+
+bool KPDFDocument::supportsSearching() const
+{
+ return generator ? generator->supportsSearching() : false;
+}
+
+bool KPDFDocument::hasFonts() const
+{
+ return generator ? generator->hasFonts() : false;
+}
+
+void KPDFDocument::putFontInfo(KListView *list)
+{
+ if (generator) generator->putFontInfo(list);
+}
+
+void KPDFDocument::requestPixmaps( const QValueList< PixmapRequest * > & requests )
+{
+ if ( !generator )
+ {
+ // delete requests..
+ QValueList< PixmapRequest * >::const_iterator rIt = requests.begin(), rEnd = requests.end();
+ for ( ; rIt != rEnd; ++rIt )
+ delete *rIt;
+ // ..and return
+ return;
+ }
+
+ // 1. [CLEAN STACK] remove previous requests of requesterID
+ int requesterID = requests.first()->id;
+ QValueList< PixmapRequest * >::iterator sIt = d->pixmapRequestsStack.begin(), sEnd = d->pixmapRequestsStack.end();
+ while ( sIt != sEnd )
+ {
+ if ( (*sIt)->id == requesterID )
+ {
+ // delete request and remove it from stack
+ delete *sIt;
+ sIt = d->pixmapRequestsStack.remove( sIt );
+ }
+ else
+ ++sIt;
+ }
+
+ // 2. [ADD TO STACK] add requests to stack
+ bool threadingDisabled = !KpdfSettings::enableThreading();
+ QValueList< PixmapRequest * >::const_iterator rIt = requests.begin(), rEnd = requests.end();
+ for ( ; rIt != rEnd; ++rIt )
+ {
+ // set the 'page field' (see PixmapRequest) and check if it is valid
+ PixmapRequest * request = *rIt;
+ if ( !(request->page = pages_vector[ request->pageNumber ]) )
+ {
+ // skip requests referencing an invalid page (must not happen)
+ delete request;
+ continue;
+ }
+
+ if ( !request->async )
+ request->priority = 0;
+
+ if ( request->async && threadingDisabled )
+ request->async = false;
+
+ // add request to the 'stack' at the right place
+ if ( !request->priority )
+ // add priority zero requests to the top of the stack
+ d->pixmapRequestsStack.append( request );
+ else
+ {
+ // insert in stack sorted by priority
+ sIt = d->pixmapRequestsStack.begin();
+ sEnd = d->pixmapRequestsStack.end();
+ while ( sIt != sEnd && (*sIt)->priority > request->priority )
+ ++sIt;
+ d->pixmapRequestsStack.insert( sIt, request );
+ }
+ }
+
+ // 3. [START FIRST GENERATION] if generator is ready, start a new generation,
+ // or else (if gen is running) it will be started when the new contents will
+ //come from generator (in requestDone())
+ if ( generator->canGeneratePixmap() )
+ sendGeneratorRequest();
+}
+
+void KPDFDocument::requestTextPage( uint page )
+{
+ KPDFPage * kp = pages_vector[ page ];
+ if ( !generator || !kp )
+ return;
+
+ // Memory management for TextPages
+
+ generator->generateSyncTextPage( kp );
+}
+/* REFERENCE IMPLEMENTATION: better calling setViewport from other code
+void KPDFDocument::setNextPage()
+{
+ // advance page and set viewport on observers
+ if ( (*d->viewportIterator).pageNumber < (int)pages_vector.count() - 1 )
+ setViewport( DocumentViewport( (*d->viewportIterator).pageNumber + 1 ) );
+}
+
+void KPDFDocument::setPrevPage()
+{
+ // go to previous page and set viewport on observers
+ if ( (*d->viewportIterator).pageNumber > 0 )
+ setViewport( DocumentViewport( (*d->viewportIterator).pageNumber - 1 ) );
+}
+*/
+void KPDFDocument::setViewportPage( int page, int excludeId, bool smoothMove )
+{
+ // clamp page in range [0 ... numPages-1]
+ if ( page < 0 )
+ page = 0;
+ else if ( page > (int)pages_vector.count() )
+ page = pages_vector.count() - 1;
+
+ // make a viewport from the page and broadcast it
+ setViewport( DocumentViewport( page ), excludeId, smoothMove );
+}
+
+void KPDFDocument::setViewport( const DocumentViewport & viewport, int excludeId, bool smoothMove )
+{
+ // if already broadcasted, don't redo it
+ DocumentViewport & oldViewport = *d->viewportIterator;
+ if ( viewport == oldViewport )
+ kdDebug() << "setViewport with the same viewport." << endl;
+
+ // set internal viewport taking care of history
+ if ( oldViewport.pageNumber == viewport.pageNumber || oldViewport.pageNumber == -1 )
+ {
+ // if page is unchanged save the viewport at current position in queue
+ oldViewport = viewport;
+ }
+ else
+ {
+ // remove elements after viewportIterator in queue
+ d->viewportHistory.erase( ++d->viewportIterator, d->viewportHistory.end() );
+
+ // keep the list to a reasonable size by removing head when needed
+ if ( d->viewportHistory.count() >= 100 )
+ d->viewportHistory.pop_front();
+
+ // add the item at the end of the queue
+ d->viewportIterator = d->viewportHistory.append( viewport );
+ }
+
+ // notify change to all other (different from id) observers
+ QMap< int, DocumentObserver * >::iterator it = d->observers.begin(), end = d->observers.end();
+ for ( ; it != end ; ++ it )
+ if ( it.key() != excludeId )
+ (*it)->notifyViewportChanged( smoothMove );
+
+ // [MEM] raise position of currently viewed page in allocation queue
+ if ( d->allocatedPixmapsFifo.count() > 1 )
+ {
+ const int page = viewport.pageNumber;
+ QValueList< AllocatedPixmap * > viewportPixmaps;
+ QValueList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin();
+ QValueList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end();
+ while ( aIt != aEnd )
+ {
+ if ( (*aIt)->page == page )
+ {
+ viewportPixmaps.append( *aIt );
+ aIt = d->allocatedPixmapsFifo.remove( aIt );
+ continue;
+ }
+ ++aIt;
+ }
+ if ( !viewportPixmaps.isEmpty() )
+ d->allocatedPixmapsFifo += viewportPixmaps;
+ }
+}
+
+void KPDFDocument::setPrevViewport()
+// restore viewport from the history
+{
+ if ( d->viewportIterator != d->viewportHistory.begin() )
+ {
+ // restore previous viewport and notify it to observers
+ --d->viewportIterator;
+ foreachObserver( notifyViewportChanged( true ) );
+ }
+}
+
+void KPDFDocument::setNextViewport()
+// restore next viewport from the history
+{
+ QValueList< DocumentViewport >::iterator nextIterator = d->viewportIterator;
+ ++nextIterator;
+ if ( nextIterator != d->viewportHistory.end() )
+ {
+ // restore next viewport and notify it to observers
+ ++d->viewportIterator;
+ foreachObserver( notifyViewportChanged( true ) );
+ }
+}
+
+void KPDFDocument::setNextDocumentViewport( const DocumentViewport & viewport )
+{
+ d->nextDocumentViewport = viewport;
+}
+
+
+bool KPDFDocument::searchText( int searchID, const QString & text, bool fromStart, bool caseSensitive,
+ SearchType type, bool moveViewport, const QColor & color, bool noDialogs )
+{
+ // don't perform searches on empty docs
+ if ( !generator || pages_vector.isEmpty() )
+ return false;
+
+ // if searchID search not recorded, create new descriptor and init params
+ if ( !d->searches.contains( searchID ) )
+ {
+ RunningSearch * search = new RunningSearch();
+ search->continueOnPage = -1;
+ d->searches[ searchID ] = search;
+ }
+ if (d->m_lastSearchID != searchID)
+ {
+ resetSearch(d->m_lastSearchID);
+ }
+ d->m_lastSearchID = searchID;
+ RunningSearch * s = d->searches[ searchID ];
+
+ // update search stucture
+ bool newText = text != s->cachedString;
+ s->cachedString = text;
+ s->cachedType = type;
+ s->cachedCaseSensitive = caseSensitive;
+ s->cachedViewportMove = moveViewport;
+ s->cachedNoDialogs = noDialogs;
+ s->cachedColor = color;
+
+ // global data for search
+ bool foundAMatch = false;
+ QValueList< int > pagesToNotify;
+
+ // remove highlights from pages and queue them for notifying changes
+ pagesToNotify += s->highlightedPages;
+ QValueList< int >::iterator it = s->highlightedPages.begin(), end = s->highlightedPages.end();
+ for ( ; it != end; ++it )
+ pages_vector[ *it ]->deleteHighlights( searchID );
+ s->highlightedPages.clear();
+
+ // set hourglass cursor
+ QApplication::setOverrideCursor( waitCursor );
+
+ // 1. ALLDOC - proces all document marking pages
+ if ( type == AllDoc )
+ {
+ // search and highlight text on all pages
+ QValueVector< KPDFPage * >::iterator it = pages_vector.begin(), end = pages_vector.end();
+ for ( ; it != end; ++it )
+ {
+ // get page (from the first to the last)
+ KPDFPage * page = *it;
+ int pageNumber = page->number();
+
+ // request search page if needed
+ if ( !page->hasSearchPage() )
+ requestTextPage( pageNumber );
+
+ // loop on a page adding highlights for all found items
+ bool addedHighlights = false;
+ NormalizedRect * lastMatch = 0;
+ while ( 1 )
+ {
+ if ( lastMatch )
+ lastMatch = page->findText( text, caseSensitive, lastMatch );
+ else
+ lastMatch = page->findText( text, caseSensitive );
+
+ if ( !lastMatch )
+ break;
+
+ // add highligh rect to the page
+ page->setHighlight( searchID, lastMatch, color );
+ addedHighlights = true;
+ }
+
+ // if added highlights, udpate internals and queue page for notify
+ if ( addedHighlights )
+ {
+ foundAMatch = true;
+ s->highlightedPages.append( pageNumber );
+ if ( !pagesToNotify.contains( pageNumber ) )
+ pagesToNotify.append( pageNumber );
+ }
+ }
+
+ // reset cursor to previous shape
+ QApplication::restoreOverrideCursor();
+
+ // send page lists if found anything new
+ //if ( foundAMatch ) ?maybe?
+ foreachObserver( notifySetup( pages_vector, false ) );
+ }
+ // 2. NEXTMATCH - find next matching item (or start from top)
+ else if ( type == NextMatch )
+ {
+ // find out from where to start/resume search from
+ int viewportPage = (*d->viewportIterator).pageNumber;
+ int currentPage = fromStart ? 0 : ((s->continueOnPage != -1) ? s->continueOnPage : viewportPage);
+ KPDFPage * lastPage = fromStart ? 0 : pages_vector[ currentPage ];
+
+ // continue checking last SearchPage first (if it is the current page)
+ NormalizedRect * match = 0;
+ if ( lastPage && lastPage->number() == s->continueOnPage )
+ {
+ if ( newText )
+ match = lastPage->findText( text, caseSensitive );
+ else
+ match = lastPage->findText( text, caseSensitive, &s->continueOnMatch );
+ if ( !match )
+ currentPage++;
+ }
+
+ // if no match found, loop through the whole doc, starting from currentPage
+ if ( !match )
+ {
+ const int pageCount = pages_vector.count();
+ for ( int i = 0; i < pageCount; i++ )
+ {
+ if ( currentPage >= pageCount )
+ {
+ if ( noDialogs || KMessageBox::questionYesNo(widget(), i18n("End of document reached.\nContinue from the beginning?"), QString::null, KStdGuiItem::cont(), KStdGuiItem::cancel()) == KMessageBox::Yes )
+ currentPage = 0;
+ else
+ break;
+ }
+ // get page
+ KPDFPage * page = pages_vector[ currentPage ];
+ // request search page if needed
+ if ( !page->hasSearchPage() )
+ requestTextPage( page->number() );
+ // if found a match on the current page, end the loop
+ if ( (match = page->findText( text, caseSensitive )) )
+ break;
+ currentPage++;
+ }
+ }
+
+ // reset cursor to previous shape
+ QApplication::restoreOverrideCursor();
+
+ // if a match has been found..
+ if ( match )
+ {
+ // update the RunningSearch structure adding this match..
+ foundAMatch = true;
+ s->continueOnPage = currentPage;
+ s->continueOnMatch = *match;
+ s->highlightedPages.append( currentPage );
+ // ..add highlight to the page..
+ pages_vector[ currentPage ]->setHighlight( searchID, match, color );
+
+ // ..queue page for notifying changes..
+ if ( !pagesToNotify.contains( currentPage ) )
+ pagesToNotify.append( currentPage );
+
+ // ..move the viewport to show the searched word centered
+ if ( moveViewport )
+ {
+ DocumentViewport searchViewport( currentPage );
+ searchViewport.rePos.enabled = true;
+ searchViewport.rePos.normalizedX = (match->left + match->right) / 2.0;
+ searchViewport.rePos.normalizedY = (match->top + match->bottom) / 2.0;
+ setViewport( searchViewport, -1, true );
+ }
+ }
+ else if ( !noDialogs )
+ KMessageBox::information( widget(), i18n("No matches found for '%1'.").arg( text ) );
+ }
+ // 3. PREVMATCH //TODO
+ else if ( type == PrevMatch )
+ {
+ }
+ // 4. GOOGLE* - process all document marking pages
+ else if ( type == GoogleAll || type == GoogleAny )
+ {
+ // search and highlight every word in 'text' on all pages
+ bool matchAll = type == GoogleAll;
+ QStringList words = QStringList::split( " ", text );
+ int wordsCount = words.count(),
+ hueStep = (wordsCount > 1) ? (60 / (wordsCount - 1)) : 60,
+ baseHue, baseSat, baseVal;
+ color.getHsv( &baseHue, &baseSat, &baseVal );
+ QValueVector< KPDFPage * >::iterator it = pages_vector.begin(), end = pages_vector.end();
+ for ( ; it != end; ++it )
+ {
+ // get page (from the first to the last)
+ KPDFPage * page = *it;
+ int pageNumber = page->number();
+
+ // request search page if needed
+ if ( !page->hasSearchPage() )
+ requestTextPage( pageNumber );
+
+ // loop on a page adding highlights for all found items
+ bool allMatched = wordsCount > 0,
+ anyMatched = false;
+ for ( int w = 0; w < wordsCount; w++ )
+ {
+ QString word = words[ w ];
+ int newHue = baseHue - w * hueStep;
+ if ( newHue < 0 )
+ newHue += 360;
+ QColor wordColor = QColor( newHue, baseSat, baseVal, QColor::Hsv );
+ NormalizedRect * lastMatch = 0;
+ // add all highlights for current word
+ bool wordMatched = false;
+ while ( 1 )
+ {
+ if ( lastMatch )
+ lastMatch = page->findText( word, caseSensitive, lastMatch );
+ else
+ lastMatch = page->findText( word, caseSensitive );
+
+ if ( !lastMatch )
+ break;
+
+ // add highligh rect to the page
+ page->setHighlight( searchID, lastMatch, wordColor );
+ wordMatched = true;
+ }
+ allMatched = allMatched && wordMatched;
+ anyMatched = anyMatched || wordMatched;
+ }
+
+ // if not all words are present in page, remove partial highlights
+ if ( !allMatched && matchAll )
+ page->deleteHighlights( searchID );
+
+ // if page contains all words, udpate internals and queue page for notify
+ if ( (allMatched && matchAll) || (anyMatched && !matchAll) )
+ {
+ foundAMatch = true;
+ s->highlightedPages.append( pageNumber );
+ if ( !pagesToNotify.contains( pageNumber ) )
+ pagesToNotify.append( pageNumber );
+ }
+ }
+
+ // reset cursor to previous shape
+ QApplication::restoreOverrideCursor();
+
+ // send page lists to update observers (since some filter on bookmarks)
+ foreachObserver( notifySetup( pages_vector, false ) );
+ }
+
+ // notify observers about highlights changes
+ QValueList< int >::iterator nIt = pagesToNotify.begin(), nEnd = pagesToNotify.end();
+ for ( ; nIt != nEnd; ++nIt )
+ foreachObserver( notifyPageChanged( *nIt, DocumentObserver::Highlights ) );
+
+ // return if search has found one or more matches
+ return foundAMatch;
+}
+
+bool KPDFDocument::continueSearch( int searchID )
+{
+ // check if searchID is present in runningSearches
+ if ( !d->searches.contains( searchID ) )
+ return false;
+
+ // start search with cached parameters from last search by searchID
+ RunningSearch * p = d->searches[ searchID ];
+ return searchText( searchID, p->cachedString, false, p->cachedCaseSensitive,
+ p->cachedType, p->cachedViewportMove, p->cachedColor,
+ p->cachedNoDialogs );
+}
+
+void KPDFDocument::resetSearch( int searchID )
+{
+ // check if searchID is present in runningSearches
+ if ( !d->searches.contains( searchID ) )
+ return;
+
+ // get previous parameters for search
+ RunningSearch * s = d->searches[ searchID ];
+
+ // unhighlight pages and inform observers about that
+ QValueList< int >::iterator it = s->highlightedPages.begin(), end = s->highlightedPages.end();
+ for ( ; it != end; ++it )
+ {
+ int pageNumber = *it;
+ pages_vector[ pageNumber ]->deleteHighlights( searchID );
+ foreachObserver( notifyPageChanged( pageNumber, DocumentObserver::Highlights ) );
+ }
+
+ // send the setup signal too (to update views that filter on matches)
+ foreachObserver( notifySetup( pages_vector, false ) );
+
+ // remove serch from the runningSearches list and delete it
+ d->searches.remove( searchID );
+ delete s;
+}
+
+bool KPDFDocument::continueLastSearch()
+{
+ return continueSearch( d->m_lastSearchID );
+}
+
+
+void KPDFDocument::toggleBookmark( int n )
+{
+ KPDFPage * page = ( n < (int)pages_vector.count() ) ? pages_vector[ n ] : 0;
+ if ( page )
+ {
+ page->setBookmark( !page->hasBookmark() );
+ foreachObserver( notifyPageChanged( n, DocumentObserver::Bookmark ) );
+ }
+}
+
+void KPDFDocument::processLink( const KPDFLink * link )
+{
+ if ( !link )
+ return;
+
+ switch( link->linkType() )
+ {
+ case KPDFLink::Goto: {
+ const KPDFLinkGoto * go = static_cast< const KPDFLinkGoto * >( link );
+ d->nextDocumentViewport = go->destViewport();
+
+ // Explanation of why d->nextDocumentViewport is needed
+ // all openRelativeFile does is launch a signal telling we
+ // want to open another URL, the problem is that when the file is
+ // non local, the loading is done assynchronously so you can't
+ // do a setViewport after the if as it was because you are doing the setViewport
+ // on the old file and when the new arrives there is no setViewport for it and
+ // it does not show anything
+
+ // first open filename if link is pointing outside this document
+ if ( go->isExternal() && !openRelativeFile( go->fileName() ) )
+ {
+ kdWarning() << "Link: Error opening '" << go->fileName() << "'." << endl;
+ return;
+ }
+ else
+ {
+ if (d->nextDocumentViewport.pageNumber == -1) return;
+ setViewport( d->nextDocumentViewport, -1, true );
+ d->nextDocumentViewport = DocumentViewport();
+ }
+
+ } break;
+
+ case KPDFLink::Execute: {
+ const KPDFLinkExecute * exe = static_cast< const KPDFLinkExecute * >( link );
+ QString fileName = exe->fileName();
+ if ( fileName.endsWith( ".pdf" ) || fileName.endsWith( ".PDF" ) )
+ {
+ openRelativeFile( fileName );
+ return;
+ }
+
+ // Albert: the only pdf i have that has that kind of link don't define
+ // an application and use the fileName as the file to open
+ fileName = giveAbsolutePath( fileName );
+ KMimeType::Ptr mime = KMimeType::findByPath( fileName );
+ // Check executables
+ if ( KRun::isExecutableFile( fileName, mime->name() ) )
+ {
+ // Don't have any pdf that uses this code path, just a guess on how it should work
+ if ( !exe->parameters().isEmpty() )
+ {
+ fileName = giveAbsolutePath( exe->parameters() );
+ mime = KMimeType::findByPath( fileName );
+ if ( KRun::isExecutableFile( fileName, mime->name() ) )
+ {
+ // this case is a link pointing to an executable with a parameter
+ // that also is an executable, possibly a hand-crafted pdf
+ KMessageBox::information( widget(), i18n("The pdf file is trying to execute an external application and for your safety kpdf does not allow that.") );
+ return;
+ }
+ }
+ else
+ {
+ // this case is a link pointing to an executable with no parameters
+ // core developers find unacceptable executing it even after asking the user
+ KMessageBox::information( widget(), i18n("The pdf file is trying to execute an external application and for your safety kpdf does not allow that.") );
+ return;
+ }
+ }
+
+ KService::Ptr ptr = KServiceTypeProfile::preferredService( mime->name(), "Application" );
+ if ( ptr )
+ {
+ KURL::List lst;
+ lst.append( fileName );
+ KRun::run( *ptr, lst );
+ }
+ else
+ KMessageBox::information( widget(), i18n( "No application found for opening file of mimetype %1." ).arg( mime->name() ) );
+ } break;
+
+ case KPDFLink::Action: {
+ const KPDFLinkAction * action = static_cast< const KPDFLinkAction * >( link );
+ switch( action->actionType() )
+ {
+ case KPDFLinkAction::PageFirst:
+ setViewportPage( 0 );
+ break;
+ case KPDFLinkAction::PagePrev:
+ if ( (*d->viewportIterator).pageNumber > 0 )
+ setViewportPage( (*d->viewportIterator).pageNumber - 1 );
+ break;
+ case KPDFLinkAction::PageNext:
+ if ( (*d->viewportIterator).pageNumber < (int)pages_vector.count() - 1 )
+ setViewportPage( (*d->viewportIterator).pageNumber + 1 );
+ break;
+ case KPDFLinkAction::PageLast:
+ setViewportPage( pages_vector.count() - 1 );
+ break;
+ case KPDFLinkAction::HistoryBack:
+ setPrevViewport();
+ break;
+ case KPDFLinkAction::HistoryForward:
+ setNextViewport();
+ break;
+ case KPDFLinkAction::Quit:
+ emit quit();
+ break;
+ case KPDFLinkAction::Presentation:
+ emit linkPresentation();
+ break;
+ case KPDFLinkAction::EndPresentation:
+ emit linkEndPresentation();
+ break;
+ case KPDFLinkAction::Find:
+ emit linkFind();
+ break;
+ case KPDFLinkAction::GoToPage:
+ emit linkGoToPage();
+ break;
+ case KPDFLinkAction::Close:
+ emit close();
+ break;
+ }
+ } break;
+
+ case KPDFLink::Browse: {
+ const KPDFLinkBrowse * browse = static_cast< const KPDFLinkBrowse * >( link );
+ // if the url is a mailto one, invoke mailer
+ if ( browse->url().startsWith( "mailto:", false ) )
+ kapp->invokeMailer( browse->url() );
+ else
+ {
+ QString url = browse->url();
+
+ // fix for #100366, documents with relative links that are the form of http:foo.pdf
+ if (url.find("http:") == 0 && url.find("http://") == -1 && url.right(4) == ".pdf")
+ {
+ openRelativeFile(url.mid(5));
+ return;
+ }
+
+ // Albert: this is not a leak!
+ new KRun(url);
+ }
+ } break;
+
+ case KPDFLink::Movie:
+ //const KPDFLinkMovie * browse = static_cast< const KPDFLinkMovie * >( link );
+ // TODO this (Movie link)
+ break;
+ }
+}
+
+bool KPDFDocument::print( KPrinter &printer )
+{
+ return generator ? generator->print( printer ) : false;
+}
+
+void KPDFDocument::requestDone( PixmapRequest * req )
+{
+#ifndef NDEBUG
+ if ( !generator->canGeneratePixmap() )
+ kdDebug() << "requestDone with generator not in READY state." << endl;
+#endif
+
+ // [MEM] 1.1 find and remove a previous entry for the same page and id
+ QValueList< AllocatedPixmap * >::iterator aIt = d->allocatedPixmapsFifo.begin();
+ QValueList< AllocatedPixmap * >::iterator aEnd = d->allocatedPixmapsFifo.end();
+ for ( ; aIt != aEnd; ++aIt )
+ if ( (*aIt)->page == req->pageNumber && (*aIt)->id == req->id )
+ {
+ AllocatedPixmap * p = *aIt;
+ d->allocatedPixmapsFifo.remove( aIt );
+ d->allocatedPixmapsTotalMemory -= p->memory;
+ delete p;
+ break;
+ }
+
+ if ( d->observers.contains( req->id ) )
+ {
+ // [MEM] 1.2 append memory allocation descriptor to the FIFO
+ int memoryBytes = 4 * req->width * req->height;
+ AllocatedPixmap * memoryPage = new AllocatedPixmap( req->id, req->pageNumber, memoryBytes );
+ d->allocatedPixmapsFifo.append( memoryPage );
+ d->allocatedPixmapsTotalMemory += memoryBytes;
+
+ // 2. notify an observer that its pixmap changed
+ d->observers[ req->id ]->notifyPageChanged( req->pageNumber, DocumentObserver::Pixmap );
+ }
+#ifndef NDEBUG
+ else
+ kdWarning() << "Receiving a done request for the defunct observer " << req->id << endl;
+#endif
+
+ // 3. delete request
+ delete req;
+
+ // 4. start a new generation if some is pending
+ if ( !d->pixmapRequestsStack.isEmpty() )
+ sendGeneratorRequest();
+}
+
+void KPDFDocument::sendGeneratorRequest()
+{
+ // find a request
+ PixmapRequest * request = 0;
+ while ( !d->pixmapRequestsStack.isEmpty() && !request )
+ {
+ PixmapRequest * r = d->pixmapRequestsStack.last();
+ d->pixmapRequestsStack.pop_back();
+ // request only if page isn't already present
+ if ( !r->page->hasPixmap( r->id, r->width, r->height ) )
+ request = r;
+ else
+ delete r;
+ }
+
+ // if no request found (or already generated), return
+ if ( !request )
+ return;
+
+ // [MEM] preventive memory freeing
+ int pixmapBytes = 4 * request->width * request->height;
+ if ( pixmapBytes > (1024 * 1024) )
+ cleanupPixmapMemory( pixmapBytes );
+
+ // submit the request to the generator
+ generator->generatePixmap( request );
+}
+
+void KPDFDocument::cleanupPixmapMemory( int /*sure? bytesOffset*/ )
+{
+ // [MEM] choose memory parameters based on configuration profile
+ int clipValue = -1;
+ int memoryToFree = -1;
+ switch ( KpdfSettings::memoryLevel() )
+ {
+ case KpdfSettings::EnumMemoryLevel::Low:
+ memoryToFree = d->allocatedPixmapsTotalMemory;
+ break;
+
+ case KpdfSettings::EnumMemoryLevel::Normal:
+ memoryToFree = d->allocatedPixmapsTotalMemory - getTotalMemory() / 3;
+ clipValue = (d->allocatedPixmapsTotalMemory - getFreeMemory()) / 2;
+ break;
+
+ case KpdfSettings::EnumMemoryLevel::Aggressive:
+ clipValue = (d->allocatedPixmapsTotalMemory - getFreeMemory()) / 2;
+ break;
+ }
+
+ if ( clipValue > memoryToFree )
+ memoryToFree = clipValue;
+
+ if ( memoryToFree > 0 )
+ {
+ // [MEM] free memory starting from older pixmaps
+ int pagesFreed = 0;
+ QValueList< AllocatedPixmap * >::iterator pIt = d->allocatedPixmapsFifo.begin();
+ QValueList< AllocatedPixmap * >::iterator pEnd = d->allocatedPixmapsFifo.end();
+ while ( (pIt != pEnd) && (memoryToFree > 0) )
+ {
+ AllocatedPixmap * p = *pIt;
+ if ( d->observers[ p->id ]->canUnloadPixmap( p->page ) )
+ {
+ // update internal variables
+ pIt = d->allocatedPixmapsFifo.remove( pIt );
+ d->allocatedPixmapsTotalMemory -= p->memory;
+ memoryToFree -= p->memory;
+ pagesFreed++;
+ // delete pixmap
+ pages_vector[ p->page ]->deletePixmap( p->id );
+ // delete allocation descriptor
+ delete p;
+ } else
+ ++pIt;
+ }
+ //p--rintf("freeMemory A:[%d -%d = %d] \n", d->allocatedPixmapsFifo.count() + pagesFreed, pagesFreed, d->allocatedPixmapsFifo.count() );
+ }
+}
+
+int KPDFDocument::getTotalMemory()
+{
+ static int cachedValue = 0;
+ if ( cachedValue )
+ return cachedValue;
+
+#ifdef __linux__
+ // if /proc/meminfo doesn't exist, return 128MB
+ QFile memFile( "/proc/meminfo" );
+ if ( !memFile.open( IO_ReadOnly ) )
+ return (cachedValue = 134217728);
+
+ // read /proc/meminfo and sum up the contents of 'MemFree', 'Buffers'
+ // and 'Cached' fields. consider swapped memory as used memory.
+ QTextStream readStream( &memFile );
+ while ( !readStream.atEnd() )
+ {
+ QString entry = readStream.readLine();
+ if ( entry.startsWith( "MemTotal:" ) )
+ return (cachedValue = (1024 * entry.section( ' ', -2, -2 ).toInt()));
+ }
+#endif
+ return (cachedValue = 134217728);
+}
+
+int KPDFDocument::getFreeMemory()
+{
+ static QTime lastUpdate = QTime::currentTime();
+ static int cachedValue = 0;
+
+ if ( lastUpdate.secsTo( QTime::currentTime() ) <= 2 )
+ return cachedValue;
+
+#ifdef __linux__
+ // if /proc/meminfo doesn't exist, return MEMORY FULL
+ QFile memFile( "/proc/meminfo" );
+ if ( !memFile.open( IO_ReadOnly ) )
+ return 0;
+
+ // read /proc/meminfo and sum up the contents of 'MemFree', 'Buffers'
+ // and 'Cached' fields. consider swapped memory as used memory.
+ int memoryFree = 0;
+ QString entry;
+ QTextStream readStream( &memFile );
+ while ( !readStream.atEnd() )
+ {
+ entry = readStream.readLine();
+ if ( entry.startsWith( "MemFree:" ) ||
+ entry.startsWith( "Buffers:" ) ||
+ entry.startsWith( "Cached:" ) ||
+ entry.startsWith( "SwapFree:" ) )
+ memoryFree += entry.section( ' ', -2, -2 ).toInt();
+ if ( entry.startsWith( "SwapTotal:" ) )
+ memoryFree -= entry.section( ' ', -2, -2 ).toInt();
+ }
+ memFile.close();
+
+ lastUpdate = QTime::currentTime();
+
+ return ( cachedValue = ( 1024 * memoryFree ) );
+#else
+ // tell the memory is full.. will act as in LOW profile
+ return 0;
+#endif
+}
+
+void KPDFDocument::loadDocumentInfo()
+// note: load data and stores it internally (document or pages). observers
+// are still uninitialized at this point so don't access them
+{
+ //kdDebug() << "Using '" << d->xmlFileName << "' as document info file." << endl;
+ QFile infoFile( d->xmlFileName );
+ if ( !infoFile.exists() || !infoFile.open( IO_ReadOnly ) )
+ return;
+
+ // Load DOM from XML file
+ QDomDocument doc( "documentInfo" );
+ if ( !doc.setContent( &infoFile ) )
+ {
+ kdDebug() << "Could not set content" << endl;
+ infoFile.close();
+ return;
+ }
+ infoFile.close();
+
+ QDomElement root = doc.documentElement();
+ if ( root.tagName() != "documentInfo" )
+ return;
+
+ // Parse the DOM tree
+ QDomNode topLevelNode = root.firstChild();
+ while ( topLevelNode.isElement() )
+ {
+ QString catName = topLevelNode.toElement().tagName();
+
+ // Get bookmarks list from DOM
+ if ( catName == "bookmarkList" )
+ {
+ QDomNode n = topLevelNode.firstChild();
+ QDomElement e;
+ int pageNumber;
+ bool ok;
+ while ( n.isElement() )
+ {
+ e = n.toElement();
+ if (e.tagName() == "page")
+ {
+ pageNumber = e.text().toInt(&ok);
+ if ( ok && pageNumber >= 0 && pageNumber < (int)pages_vector.count() )
+ pages_vector[ pageNumber ]->setBookmark( true );
+ }
+ n = n.nextSibling();
+ }
+ } // </bookmarkList>
+ // Get 'general info' from the DOM
+ else if ( catName == "generalInfo" )
+ {
+ QDomNode infoNode = topLevelNode.firstChild();
+ while ( infoNode.isElement() )
+ {
+ QDomElement infoElement = infoNode.toElement();
+
+ // compatibility: [pre-3.4 viewport storage] @remove after 3.4 relase
+ if ( infoElement.tagName() == "activePage" )
+ {
+ if ( infoElement.hasAttribute( "viewport" ) )
+ *d->viewportIterator = DocumentViewport( infoElement.attribute( "viewport" ) );
+ }
+
+ // restore viewports history
+ if ( infoElement.tagName() == "history" )
+ {
+ // clear history
+ d->viewportHistory.clear();
+ // append old viewports
+ QDomNode historyNode = infoNode.firstChild();
+ while ( historyNode.isElement() )
+ {
+ QDomElement historyElement = historyNode.toElement();
+ if ( historyElement.hasAttribute( "viewport" ) )
+ {
+ QString vpString = historyElement.attribute( "viewport" );
+ d->viewportIterator = d->viewportHistory.append(
+ DocumentViewport( vpString ) );
+ }
+ historyNode = historyNode.nextSibling();
+ }
+ // consistancy check
+ if ( d->viewportHistory.isEmpty() )
+ d->viewportIterator = d->viewportHistory.append( DocumentViewport() );
+ }
+ infoNode = infoNode.nextSibling();
+ }
+ } // </generalInfo>
+ topLevelNode = topLevelNode.nextSibling();
+ } // </documentInfo>
+}
+
+QString KPDFDocument::giveAbsolutePath( const QString & fileName )
+{
+ if ( !d->url.isValid() )
+ return QString::null;
+
+ return d->url.upURL().url() + fileName;
+}
+
+bool KPDFDocument::openRelativeFile( const QString & fileName )
+{
+ QString absFileName = giveAbsolutePath( fileName );
+ if ( absFileName.isNull() )
+ return false;
+
+ kdDebug() << "openDocument: '" << absFileName << "'" << endl;
+
+ emit openURL( absFileName );
+ return true;
+}
+
+
+void KPDFDocument::saveDocumentInfo() const
+{
+ if ( d->docFileName.isNull() )
+ return;
+
+ QFile infoFile( d->xmlFileName );
+ if (infoFile.open( IO_WriteOnly | IO_Truncate) )
+ {
+ // Create DOM
+ QDomDocument doc( "documentInfo" );
+ QDomElement root = doc.createElement( "documentInfo" );
+ doc.appendChild( root );
+
+ // Add bookmark list to DOM
+ QDomElement bookmarkList = doc.createElement( "bookmarkList" );
+ root.appendChild( bookmarkList );
+
+ for ( uint i = 0; i < pages_vector.count() ; i++ )
+ {
+ if ( pages_vector[i]->hasBookmark() )
+ {
+ QDomElement page = doc.createElement( "page" );
+ page.appendChild( doc.createTextNode( QString::number(i) ) );
+
+ bookmarkList.appendChild( page );
+ }
+ }
+
+ // Add general info to DOM
+ QDomElement generalInfo = doc.createElement( "generalInfo" );
+ root.appendChild( generalInfo );
+
+ // <general info><history> ... </history> saves history up to 10 viewports
+ QValueList< DocumentViewport >::iterator backIterator = d->viewportIterator;
+ if ( backIterator != d->viewportHistory.end() )
+ {
+ // go back up to 10 steps from the current viewportIterator
+ int backSteps = 10;
+ while ( backSteps-- && backIterator != d->viewportHistory.begin() )
+ --backIterator;
+
+ // create history root node
+ QDomElement historyNode = doc.createElement( "history" );
+ generalInfo.appendChild( historyNode );
+
+ // add old[backIterator] and present[viewportIterator] items
+ QValueList< DocumentViewport >::iterator endIt = d->viewportIterator;
+ ++endIt;
+ while ( backIterator != endIt )
+ {
+ QString name = (backIterator == d->viewportIterator) ? "current" : "oldPage";
+ QDomElement historyEntry = doc.createElement( name );
+ historyEntry.setAttribute( "viewport", (*backIterator).toString() );
+ historyNode.appendChild( historyEntry );
+ ++backIterator;
+ }
+ }
+
+ // Save DOM to XML file
+ QString xml = doc.toString();
+ QTextStream os( &infoFile );
+ os << xml;
+ }
+ infoFile.close();
+}
+
+void KPDFDocument::slotTimedMemoryCheck()
+{
+ // [MEM] clean memory (for 'free mem dependant' profiles only)
+ if ( KpdfSettings::memoryLevel() != KpdfSettings::EnumMemoryLevel::Low &&
+ d->allocatedPixmapsTotalMemory > 1024*1024 )
+ cleanupPixmapMemory();
+}
+
+
+/** DocumentViewport **/
+
+DocumentViewport::DocumentViewport( int n )
+ : pageNumber( n )
+{
+ // default settings
+ rePos.enabled = false;
+ rePos.normalizedX = 0.5;
+ rePos.normalizedY = 0.0;
+ rePos.pos = Center;
+ autoFit.enabled = false;
+ autoFit.width = false;
+ autoFit.height = false;
+}
+
+DocumentViewport::DocumentViewport( const QString & xmlDesc )
+ : pageNumber( -1 )
+{
+ // default settings (maybe overridden below)
+ rePos.enabled = false;
+ rePos.normalizedX = 0.5;
+ rePos.normalizedY = 0.0;
+ rePos.pos = Center;
+ autoFit.enabled = false;
+ autoFit.width = false;
+ autoFit.height = false;
+
+ // check for string presence
+ if ( xmlDesc.isEmpty() )
+ return;
+
+ // decode the string
+ bool ok;
+ int field = 0;
+ QString token = xmlDesc.section( ';', field, field );
+ while ( !token.isEmpty() )
+ {
+ // decode the current token
+ if ( field == 0 )
+ {
+ pageNumber = token.toInt( &ok );
+ if ( !ok )
+ return;
+ }
+ else if ( token.startsWith( "C1" ) )
+ {
+ rePos.enabled = true;
+ rePos.normalizedX = token.section( ':', 1, 1 ).toDouble();
+ rePos.normalizedY = token.section( ':', 2, 2 ).toDouble();
+ rePos.pos = Center;
+ }
+ else if ( token.startsWith( "C2" ) )
+ {
+ rePos.enabled = true;
+ rePos.normalizedX = token.section( ':', 1, 1 ).toDouble();
+ rePos.normalizedY = token.section( ':', 2, 2 ).toDouble();
+ if (token.section( ':', 3, 3 ).toInt() == 1) rePos.pos = Center;
+ else rePos.pos = TopLeft;
+ }
+ else if ( token.startsWith( "AF1" ) )
+ {
+ autoFit.enabled = true;
+ autoFit.width = token.section( ':', 1, 1 ) == "T";
+ autoFit.height = token.section( ':', 2, 2 ) == "T";
+ }
+ // proceed tokenizing string
+ field++;
+ token = xmlDesc.section( ';', field, field );
+ }
+}
+
+QString DocumentViewport::toString() const
+{
+ // start string with page number
+ QString s = QString::number( pageNumber );
+ // if has center coordinates, save them on string
+ if ( rePos.enabled )
+ s += QString( ";C2:" ) + QString::number( rePos.normalizedX ) +
+ ':' + QString::number( rePos.normalizedY ) +
+ ':' + QString::number( rePos.pos );
+ // if has autofit enabled, save its state on string
+ if ( autoFit.enabled )
+ s += QString( ";AF1:" ) + (autoFit.width ? "T" : "F") +
+ ':' + (autoFit.height ? "T" : "F");
+ return s;
+}
+
+bool DocumentViewport::operator==( const DocumentViewport & vp ) const
+{
+ bool equal = ( pageNumber == vp.pageNumber ) &&
+ ( rePos.enabled == vp.rePos.enabled ) &&
+ ( autoFit.enabled == vp.autoFit.enabled );
+ if ( !equal )
+ return false;
+ if ( rePos.enabled &&
+ (( rePos.normalizedX != vp.rePos.normalizedX) ||
+ ( rePos.normalizedY != vp.rePos.normalizedY ) || rePos.pos != vp.rePos.pos) )
+ return false;
+ if ( autoFit.enabled &&
+ (( autoFit.width != vp.autoFit.width ) ||
+ ( autoFit.height != vp.autoFit.height )) )
+ return false;
+ return true;
+}
+
+
+/** DocumentInfo **/
+
+DocumentInfo::DocumentInfo()
+ : QDomDocument( "DocumentInformation" )
+{
+ QDomElement docElement = createElement( "DocumentInfo" );
+ appendChild( docElement );
+}
+
+void DocumentInfo::set( const QString &key, const QString &value,
+ const QString &title )
+{
+ QDomElement docElement = documentElement();
+ QDomElement element;
+
+ // check whether key already exists
+ QDomNodeList list = docElement.elementsByTagName( key );
+ if ( list.count() > 0 )
+ element = list.item( 0 ).toElement();
+ else
+ element = createElement( key );
+
+ element.setAttribute( "value", value );
+ element.setAttribute( "title", title );
+
+ if ( list.count() == 0 )
+ docElement.appendChild( element );
+}
+
+QString DocumentInfo::get( const QString &key ) const
+{
+ QDomElement docElement = documentElement();
+ QDomElement element;
+
+ // check whether key already exists
+ QDomNodeList list = docElement.elementsByTagName( key );
+ if ( list.count() > 0 )
+ return list.item( 0 ).toElement().attribute( "value" );
+ else
+ return QString();
+}
+
+
+/** DocumentSynopsis **/
+
+DocumentSynopsis::DocumentSynopsis()
+ : QDomDocument( "DocumentSynopsis" )
+{
+ // void implementation, only subclassed for naming
+}
+
+#include "document.moc"
diff --git a/kpdf/core/document.h b/kpdf/core/document.h
new file mode 100644
index 00000000..8e4c1d8e
--- /dev/null
+++ b/kpdf/core/document.h
@@ -0,0 +1,225 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
+ * Copyright (C) 2004-2005 by Albert Astals Cid <tsdgeos@terra.es> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef _KPDF_DOCUMENT_H_
+#define _KPDF_DOCUMENT_H_
+
+#include <qobject.h>
+#include <qvaluevector.h>
+#include <qstring.h>
+#include <qdom.h>
+
+#include <kmimetype.h>
+
+class KPDFPage;
+class KPDFLink;
+class DocumentObserver;
+class DocumentViewport;
+class DocumentInfo;
+class DocumentSynopsis;
+class Generator;
+class PixmapRequest;
+class KListView;
+class KPrinter;
+class KURL;
+
+/**
+ * @short The Document. Heart of everything. Actions take place here.
+ *
+ * The Document is the main object in KPDF. All views query the Document to
+ * get data/properties or even for accessing pages (in a 'const' way).
+ *
+ * It is designed to keep it detached from the document type (pdf, ps, you
+ * name it..) so whenever you want to get some data, it asks its internals
+ * generator to do the job and return results in a format-indepedent way.
+ *
+ * Apart from the generator (the currently running one) the document stores
+ * all the Pages ('KPDFPage' class) of the current document in a vector and
+ * notifies all the registered DocumentObservers when some content changes.
+ *
+ * For a better understanding of hieracies @see README.internals.png
+ * @see DocumentObserver, KPDFPage
+ */
+class KPDFDocument : public QObject
+{
+ Q_OBJECT
+ public:
+ KPDFDocument( QWidget *widget );
+ ~KPDFDocument();
+
+ // document handling
+ bool openDocument( const QString & docFile, const KURL & url, const KMimeType::Ptr &mime );
+ void closeDocument();
+
+ // misc methods
+ void addObserver( DocumentObserver * pObserver );
+ void removeObserver( DocumentObserver * pObserver );
+ void reparseConfig();
+
+ // enum definitions
+ enum Permission { AllowModify = 1, AllowCopy = 2, AllowPrint = 4, AllowNotes = 8 };
+
+ // returns the widget where the document is shown
+ QWidget *widget() const;
+
+ // query methods (const ones)
+ bool isOpened() const;
+ const DocumentInfo * documentInfo() const;
+ const DocumentSynopsis * documentSynopsis() const;
+ const KPDFPage * page( uint page ) const;
+ const DocumentViewport & viewport() const;
+ uint currentPage() const;
+ uint pages() const;
+ KURL currentDocument() const;
+ bool isAllowed( int /*Document::Permisison(s)*/ ) const;
+ bool historyAtBegin() const;
+ bool historyAtEnd() const;
+ QString getMetaData( const QString & key, const QString & option = QString() ) const;
+ bool supportsSearching() const;
+ bool hasFonts() const;
+ void putFontInfo(KListView *list);
+
+ // perform actions on document / pages
+ void setViewportPage( int page, int excludeId = -1, bool smoothMove = false );
+ void setViewport( const DocumentViewport & viewport, int excludeId = -1, bool smoothMove = false );
+ void setPrevViewport();
+ void setNextViewport();
+ void setNextDocumentViewport( const DocumentViewport & viewport );
+ void requestPixmaps( const QValueList< PixmapRequest * > & requests );
+ void requestTextPage( uint page );
+
+ enum SearchType { NextMatch, PrevMatch, AllDoc, GoogleAll, GoogleAny };
+ bool searchText( int searchID, const QString & text, bool fromStart, bool caseSensitive,
+ SearchType type, bool moveViewport, const QColor & color, bool noDialogs = false );
+ bool continueSearch( int searchID );
+ void resetSearch( int searchID );
+ bool continueLastSearch();
+ void toggleBookmark( int page );
+ void processLink( const KPDFLink * link );
+ bool print( KPrinter &printer );
+
+ // notifications sent by generator
+ void requestDone( PixmapRequest * request );
+
+ signals:
+ void close();
+ void quit();
+ void linkFind();
+ void linkGoToPage();
+ void openURL(const KURL &url);
+ void linkPresentation();
+ void linkEndPresentation();
+
+ private:
+ void sendGeneratorRequest();
+ // memory management related functions
+ void cleanupPixmapMemory( int bytesOffset = 0 );
+ int getTotalMemory();
+ int getFreeMemory();
+ // more private functions
+ void loadDocumentInfo();
+ QString giveAbsolutePath( const QString & fileName );
+ bool openRelativeFile( const QString & fileName );
+
+ Generator * generator;
+ QValueVector< KPDFPage * > pages_vector;
+ class KPDFDocumentPrivate * d;
+
+ private slots:
+ void saveDocumentInfo() const;
+ void slotTimedMemoryCheck();
+};
+
+
+/**
+ * @short A view on the document.
+ *
+ * The Viewport structure is the 'current view' over the document. Contained
+ * data is broadcasted between observers to syncronize their viewports to get
+ * the 'I scroll one view and others scroll too' views.
+ */
+class DocumentViewport
+{
+ public:
+ /** data fields **/
+ // the page nearest the center of the viewport
+ int pageNumber;
+
+ // enum definitions
+ enum Position { Center = 1, TopLeft = 2};
+
+ // if reCenter.enabled, this contains the viewport center
+ struct {
+ bool enabled;
+ double normalizedX;
+ double normalizedY;
+ Position pos;
+ } rePos;
+
+ // if autoFit.enabled, page must be autofitted in the viewport
+ struct {
+ bool enabled;
+ bool width;
+ bool height;
+ } autoFit;
+
+ /** class methods **/
+ // allowed constructors, don't use others
+ DocumentViewport( int pageNumber = -1 );
+ DocumentViewport( const QString & xmlDesc );
+ QString toString() const;
+ bool operator==( const DocumentViewport & vp ) const;
+};
+
+/**
+ * @short A dom tree containing informations about the document.
+ *
+ * The Info structure can be filled in by generators to display metadata
+ * about the currently opened file.
+ */
+class DocumentInfo : public QDomDocument
+{
+ public:
+ DocumentInfo();
+
+ /**
+ * Sets a value for a special key. The title should be an i18n'ed
+ * string, since it's used in the document information dialog.
+ */
+ void set( const QString &key, const QString &value,
+ const QString &title = QString() );
+
+ /**
+ * Returns the value for a given key or an empty string when the
+ * key doesn't exist.
+ */
+ QString get( const QString &key ) const;
+};
+
+/**
+ * @short A Dom tree that describes the Table of Contents.
+ *
+ * The Synopsis (TOC or Table Of Contents for friends) is represented via
+ * a dom tree where each nod has an internal name (displayed in the listview)
+ * and one or more attributes.
+ *
+ * In the tree the tag name is the 'screen' name of the entry. A tag can have
+ * attributes. Here follows the list of tag attributes with meaning:
+ * - Viewport: A string description of the referred viewport
+ * - ViewportName: A 'named reference' to the viewport that must be converted
+ * using getMetaData( "NamedViewport", *viewport_name* )
+ */
+class DocumentSynopsis : public QDomDocument
+{
+ public:
+ DocumentSynopsis();
+};
+
+#endif
diff --git a/kpdf/core/generator.h b/kpdf/core/generator.h
new file mode 100644
index 00000000..ca0ea015
--- /dev/null
+++ b/kpdf/core/generator.h
@@ -0,0 +1,115 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef _KPDF_GENERATOR_H_
+#define _KPDF_GENERATOR_H_
+
+#include <qobject.h>
+#include <qvaluevector.h>
+#include <qstring.h>
+#include "core/document.h"
+class KListView;
+class KPrinter;
+class KPDFPage;
+class KPDFLink;
+class PixmapRequest;
+
+/* Note: on contents generation and asyncronous queries.
+ * Many observers may want to request data syncronously or asyncronously.
+ * - Sync requests. These should be done in-place.
+ * - Async request must be done in real background. That usually means a
+ * thread, such as QThread derived classes.
+ * Once contents are available, they must be immediately stored in the
+ * KPDFPage they refer to, and a signal is emitted as soon as storing
+ * (even for sync or async queries) has been done.
+ */
+
+/**
+ * @short [Abstract Class] The information generator.
+ *
+ * Most of class members are pure virtuals and they must be implemented to
+ * provide a class that builds contents (graphics and text).
+ *
+ * Generation/query is requested by the 'KPDFDocument' class only, and that
+ * class stores the resulting data into 'KPDFPage's. The data will then be
+ * displayed by the GUI components (pageView, thumbnailList, etc..).
+ */
+class Generator : public QObject
+{
+ public:
+ /** virtual methods to reimplement **/
+ // load a document and fill up the pagesVector
+ virtual bool loadDocument( const QString & fileName, QValueVector< KPDFPage * > & pagesVector ) = 0;
+
+ // Document description and Table of contents
+ virtual const DocumentInfo * generateDocumentInfo() { return 0L; }
+ virtual const DocumentSynopsis * generateDocumentSynopsis() { return 0L; }
+
+ // DRM handling
+ virtual bool isAllowed( int /*Document::Permisison(s)*/ ) { return true; }
+
+ // page contents generation
+ virtual bool canGeneratePixmap() = 0;
+ virtual void generatePixmap( PixmapRequest * request ) = 0;
+ virtual void generateSyncTextPage( KPDFPage * page ) = 0;
+
+ // capability querying
+ virtual bool supportsSearching() const = 0;
+ virtual bool hasFonts() const = 0;
+
+ // font related
+ virtual void putFontInfo(KListView *list) = 0;
+
+ // print document using already configured kprinter
+ virtual bool print( KPrinter& /*printer*/ ) { return false; }
+ // access meta data of the generator
+ virtual QString getMetaData( const QString &/*key*/, const QString &/*option*/ ) { return QString(); }
+ // tell generator to re-parse configuration and return true if something changed
+ virtual bool reparseConfig() { return false; }
+
+ /** 'signals' to send events the KPDFDocument **/
+ // tell the document that the job has been completed
+ void signalRequestDone( PixmapRequest * request ) { m_document->requestDone( request ); }
+
+ /** constructor: takes the Document as a parameter **/
+ Generator( KPDFDocument * doc ) : m_document( doc ) {};
+
+ protected:
+ KPDFDocument * m_document;
+
+ private:
+ Generator();
+};
+
+/**
+ * @short Describes a pixmap type request.
+ */
+struct PixmapRequest
+{
+ PixmapRequest( int rId, int n, int w, int h, int p, bool a = false )
+ : id( rId ), pageNumber( n ), width( w ), height( h ),
+ priority( p ), async( a ), page( 0 ) {};
+
+ // observer id
+ int id;
+ // page number and size
+ int pageNumber;
+ int width;
+ int height;
+ // asyncronous request priority (less is better, 0 is max)
+ int priority;
+ // generate the pixmap in a thread and notify observer when done
+ bool async;
+
+ // this field is set by the Docuemnt prior passing the
+ // request to the generator
+ KPDFPage * page;
+};
+
+#endif
diff --git a/kpdf/core/generator_kimgio/Makefile.am b/kpdf/core/generator_kimgio/Makefile.am
new file mode 100644
index 00000000..5a93221d
--- /dev/null
+++ b/kpdf/core/generator_kimgio/Makefile.am
@@ -0,0 +1,6 @@
+INCLUDES = -I$(srcdir)/../../ $(all_includes)
+
+libgeneratorkimgio_la_LDFLAGS = $(all_libraries)
+libgeneratorkimgio_la_SOURCES = generator_kimgio.cpp
+
+noinst_LTLIBRARIES = libgeneratorkimgio.la
diff --git a/kpdf/core/generator_kimgio/generator_kimgio.cpp b/kpdf/core/generator_kimgio/generator_kimgio.cpp
new file mode 100644
index 00000000..bb754686
--- /dev/null
+++ b/kpdf/core/generator_kimgio/generator_kimgio.cpp
@@ -0,0 +1,72 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Albert Astals Cid <tsdgeos@terra.es> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <kprinter.h>
+
+#include "core/page.h"
+#include "generator_kimgio.h"
+
+KIMGIOGenerator::KIMGIOGenerator( KPDFDocument * document ) : Generator( document )
+{
+}
+
+KIMGIOGenerator::~KIMGIOGenerator()
+{
+ delete m_pix;
+}
+
+bool KIMGIOGenerator::loadDocument( const QString & fileName, QValueVector<KPDFPage*> & pagesVector )
+{
+ m_pix = new QPixmap(fileName);
+
+ pagesVector.resize( 1 );
+
+ KPDFPage * page = new KPDFPage( 0, m_pix->width(), m_pix->height(), 0 );
+ pagesVector[0] = page;
+
+ return true;
+}
+
+bool KIMGIOGenerator::canGeneratePixmap()
+{
+ return true;
+}
+
+void KIMGIOGenerator::generatePixmap( PixmapRequest * request )
+{
+ QPixmap *p = new QPixmap(*m_pix);
+ request->page->setPixmap(request->id, p);
+}
+
+void KIMGIOGenerator::generateSyncTextPage( KPDFPage * )
+{
+}
+
+bool KIMGIOGenerator::supportsSearching() const
+{
+ return false;
+}
+
+bool KIMGIOGenerator::hasFonts() const
+{
+ return false;
+}
+
+void KIMGIOGenerator::putFontInfo( KListView * )
+{
+}
+
+bool KIMGIOGenerator::print( KPrinter& printer )
+{
+ QPainter p(&printer);
+ p.drawPixmap(0, 0, *m_pix);
+ return true;
+}
diff --git a/kpdf/core/generator_kimgio/generator_kimgio.h b/kpdf/core/generator_kimgio/generator_kimgio.h
new file mode 100644
index 00000000..bda411f2
--- /dev/null
+++ b/kpdf/core/generator_kimgio/generator_kimgio.h
@@ -0,0 +1,43 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Albert Astals Cid <tsdgeos@terra.es> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef _KPDF_GENERATOR_PNG_H_
+#define _KPDF_GENERATOR_PNG_H_
+
+#include "core/generator.h"
+
+class KIMGIOGenerator : public Generator
+{
+ public:
+ KIMGIOGenerator( KPDFDocument * document );
+ virtual ~KIMGIOGenerator();
+
+ // [INHERITED] load a document and fill up the pagesVector
+ bool loadDocument( const QString & fileName, QValueVector<KPDFPage*> & pagesVector );
+
+ // [INHERITED] perform actions on document / pages
+ bool canGeneratePixmap();
+ void generatePixmap( PixmapRequest * request );
+ void generateSyncTextPage( KPDFPage * page );
+
+ // [INHERITED] capability querying
+ bool supportsSearching() const;
+ bool hasFonts() const;
+
+ // font related
+ void putFontInfo(KListView *list);
+
+ // [INHERITED] print document using already configured kprinter
+ bool print( KPrinter& printer );
+
+ private:
+ QPixmap *m_pix;
+};
+
+#endif
diff --git a/kpdf/core/generator_pdf/Makefile.am b/kpdf/core/generator_pdf/Makefile.am
new file mode 100644
index 00000000..700740b7
--- /dev/null
+++ b/kpdf/core/generator_pdf/Makefile.am
@@ -0,0 +1,10 @@
+INCLUDES = -I$(srcdir)/../.. -I$(srcdir)/../../xpdf -I$(srcdir)/../../xpdf/goo -I$(srcdir)/../../xpdf/splash -I$(top_builddir)/kpdf $(all_includes)
+
+libgeneratorpdf_la_LDFLAGS = $(all_libraries)
+libgeneratorpdf_la_SOURCES = generator_pdf.cpp gp_outputdev.cpp
+
+noinst_LTLIBRARIES = libgeneratorpdf.la
+
+KDE_OPTIONS = nofinal
+
+generator_pdf.lo: ../../conf/settings.h
diff --git a/kpdf/core/generator_pdf/generator_pdf.cpp b/kpdf/core/generator_pdf/generator_pdf.cpp
new file mode 100644
index 00000000..7ad34152
--- /dev/null
+++ b/kpdf/core/generator_pdf/generator_pdf.cpp
@@ -0,0 +1,1258 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Albert Astals Cid <tsdgeos@terra.es> *
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+// qt/kde includes
+#include <qfile.h>
+#include <qevent.h>
+#include <qimage.h>
+#include <qapplication.h>
+#include <qpaintdevicemetrics.h>
+#include <qregexp.h>
+#include <qvariant.h>
+#include <kapplication.h>
+#include <klistview.h>
+#include <klocale.h>
+#include <kpassdlg.h>
+#include <kwallet.h>
+#include <kprinter.h>
+#include <ktempfile.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+
+// xpdf includes
+#include "xpdf/Object.h"
+#include "xpdf/Dict.h"
+#include "xpdf/Annot.h"
+#include "xpdf/PSOutputDev.h"
+#include "xpdf/TextOutputDev.h"
+#include "xpdf/Link.h"
+#include "xpdf/ErrorCodes.h"
+#include "xpdf/UnicodeMap.h"
+#include "xpdf/Outline.h"
+#include "goo/GList.h"
+
+// local includes
+#include "generator_pdf.h"
+#include "gp_outputdev.h"
+#include "core/observer.h" //for PAGEVIEW_ID
+#include "core/page.h"
+#include "core/pagetransition.h"
+#include "conf/settings.h"
+
+#include <stdlib.h>
+
+#include <config.h>
+
+// id for DATA_READY PDFPixmapGeneratorThread Event
+#define TGE_DATAREADY_ID 6969
+
+/** NOTES on threading:
+ * internal: thread race prevention is done via the 'docLock' mutex. the
+ * mutex is needed only because we have the asyncronous thread; else
+ * the operations are all within the 'gui' thread, scheduled by the
+ * Qt scheduler and no mutex is needed.
+ * external: dangerous operations are all locked via mutex internally, and the
+ * only needed external thing is the 'canGeneratePixmap' method
+ * that tells if the generator is free (since we don't want an
+ * internal queue to store PixmapRequests). A generatedPixmap call
+ * without the 'ready' flag set, results in undefined behavior.
+ * So, as example, printing while generating a pixmap asyncronously is safe,
+ * it might only block the gui thread by 1) waiting for the mutex to unlock
+ * in async thread and 2) doing the 'heavy' print operation.
+ */
+
+PDFGenerator::PDFGenerator( KPDFDocument * doc )
+ : Generator( doc ), pdfdoc( 0 ), kpdfOutputDev( 0 ), ready( true ),
+ pixmapRequest( 0 ), docInfoDirty( true ), docSynopsisDirty( true )
+{
+ // generate kpdfOutputDev and cache page color
+ reparseConfig();
+ // generate the pixmapGeneratorThread
+ generatorThread = new PDFPixmapGeneratorThread( this );
+}
+
+PDFGenerator::~PDFGenerator()
+{
+ // first stop and delete the generator thread
+ if ( generatorThread )
+ {
+ generatorThread->wait();
+ delete generatorThread;
+ }
+ // remove other internal objects
+ docLock.lock();
+ delete kpdfOutputDev;
+ delete pdfdoc;
+ docLock.unlock();
+}
+
+
+//BEGIN Generator inherited functions
+bool PDFGenerator::loadDocument( const QString & filePath, QValueVector<KPDFPage*> & pagesVector )
+{
+#ifndef NDEBUG
+ if ( pdfdoc )
+ {
+ kdDebug() << "PDFGenerator: multiple calls to loadDocument. Check it." << endl;
+ return false;
+ }
+#endif
+ // create PDFDoc for the given file
+ pdfdoc = new PDFDoc( new GString( QFile::encodeName( filePath ) ), 0, 0 );
+
+ // if the file didn't open correctly it might be encrypted, so ask for a pass
+ bool firstInput = true;
+ bool triedWallet = false;
+ KWallet::Wallet * wallet = 0;
+ int keep = 1;
+ while ( !pdfdoc->isOk() && pdfdoc->getErrorCode() == errEncrypted )
+ {
+ QCString password;
+
+ // 1.A. try to retrieve the first password from the kde wallet system
+ if ( !triedWallet )
+ {
+ QString walletName = KWallet::Wallet::NetworkWallet();
+ wallet = KWallet::Wallet::openWallet( walletName );
+ if ( wallet )
+ {
+ // use the KPdf folder (and create if missing)
+ if ( !wallet->hasFolder( "KPdf" ) )
+ wallet->createFolder( "KPdf" );
+ wallet->setFolder( "KPdf" );
+
+ // look for the pass in that folder
+ QString retrievedPass;
+ if ( !wallet->readPassword( filePath.section('/', -1, -1), retrievedPass ) )
+ password = retrievedPass.local8Bit();
+ }
+ triedWallet = true;
+ }
+
+ // 1.B. if not retrieved, ask the password using the kde password dialog
+ if ( password.isNull() )
+ {
+ QString prompt;
+ if ( firstInput )
+ prompt = i18n( "Please insert the password to read the document:" );
+ else
+ prompt = i18n( "Incorrect password. Try again:" );
+ firstInput = false;
+
+ // if the user presses cancel, abort opening
+ if ( KPasswordDialog::getPassword( password, prompt, wallet ? &keep : 0 ) != KPasswordDialog::Accepted )
+ break;
+ }
+
+ // 2. reopen the document using the password
+ GString * pwd2 = new GString( QString::fromLocal8Bit(password.data()).latin1() );
+ delete pdfdoc;
+ pdfdoc = new PDFDoc( new GString( QFile::encodeName( filePath ) ), pwd2, pwd2 );
+ delete pwd2;
+
+ // 3. if the password is correct and the user chose to remember it, store it to the wallet
+ if ( pdfdoc->isOk() && wallet && /*safety check*/ wallet->isOpen() && keep > 0 )
+ {
+ QString goodPass = QString::fromLocal8Bit( password.data() );
+ wallet->writePassword( filePath.section('/', -1, -1), goodPass );
+ }
+ }
+ if ( !pdfdoc->isOk() )
+ {
+ delete pdfdoc;
+ pdfdoc = 0;
+ return false;
+ }
+
+ // initialize output device for rendering current pdf
+ kpdfOutputDev->initDevice( pdfdoc );
+
+ // build Pages (currentPage was set -1 by deletePages)
+ uint pageCount = pdfdoc->getNumPages();
+ pagesVector.resize( pageCount );
+ for ( uint i = 0; i < pageCount ; i++ )
+ {
+ KPDFPage * page = new KPDFPage( i, pdfdoc->getPageCropWidth(i+1),
+ pdfdoc->getPageCropHeight(i+1),
+ pdfdoc->getPageRotate(i+1) );
+ addTransition( i, page );
+ pagesVector[i] = page;
+ }
+
+ // the file has been loaded correctly
+ return true;
+}
+
+
+const DocumentInfo * PDFGenerator::generateDocumentInfo()
+{
+ if ( docInfoDirty )
+ {
+ docLock.lock();
+ // compile internal structure reading properties from PDFDoc
+ docInfo.set( "title", getDocumentInfo("Title"), i18n("Title") );
+ docInfo.set( "subject", getDocumentInfo("Subject"), i18n("Subject") );
+ docInfo.set( "author", getDocumentInfo("Author"), i18n("Author") );
+ docInfo.set( "keywords", getDocumentInfo("Keywords"), i18n("Keywords") );
+ docInfo.set( "creator", getDocumentInfo("Creator"), i18n("Creator") );
+ docInfo.set( "producer", getDocumentInfo("Producer"), i18n("Producer") );
+ docInfo.set( "creationDate", getDocumentDate("CreationDate"), i18n("Created") );
+ docInfo.set( "modificationDate", getDocumentDate("ModDate"), i18n("Modified") );
+ docInfo.set( "mimeType", "application/pdf" );
+ if ( pdfdoc )
+ {
+ docInfo.set( "format", i18n( "PDF v. <version>", "PDF v. %1" )
+ .arg( QString::number( pdfdoc->getPDFVersion() ) ), i18n( "Format" ) );
+ docInfo.set( "encryption", pdfdoc->isEncrypted() ? i18n( "Encrypted" ) : i18n( "Unencrypted" ),
+ i18n("Security") );
+ docInfo.set( "optimization", pdfdoc->isLinearized() ? i18n( "Yes" ) : i18n( "No" ),
+ i18n("Optimized") );
+ docInfo.set( "pages", QString::number( pdfdoc->getCatalog()->getNumPages() ), i18n("Pages") );
+ }
+ else
+ {
+ docInfo.set( "format", "PDF", i18n( "Format" ) );
+ docInfo.set( "encryption", i18n( "Unknown Encryption" ), i18n( "Security" ) );
+ docInfo.set( "optimization", i18n( "Unknown Optimization" ), i18n( "Optimized" ) );
+ }
+ docLock.unlock();
+
+ // if pdfdoc is valid then we cached good info -> don't cache them again
+ if ( pdfdoc )
+ docInfoDirty = false;
+ }
+ return &docInfo;
+}
+
+const DocumentSynopsis * PDFGenerator::generateDocumentSynopsis()
+{
+ if ( !docSynopsisDirty )
+ return &docSyn;
+
+ if ( !pdfdoc )
+ return NULL;
+
+ Outline * outline = pdfdoc->getOutline();
+ if ( !outline )
+ return NULL;
+
+ GList * items = outline->getItems();
+ if ( !items || items->getLength() < 1 )
+ return NULL;
+
+ docLock.lock();
+ docSyn = DocumentSynopsis();
+ if ( items->getLength() > 0 )
+ addSynopsisChildren( &docSyn, items );
+ docLock.unlock();
+
+ docSynopsisDirty = false;
+ return &docSyn;
+}
+
+bool PDFGenerator::isAllowed( int permissions )
+{
+#if !KPDF_FORCE_DRM
+ if (kapp->authorize("skip_drm") && !KpdfSettings::obeyDRM()) return true;
+#endif
+
+ bool b = true;
+ if (permissions & KPDFDocument::AllowModify) b = b && pdfdoc->okToChange();
+ if (permissions & KPDFDocument::AllowCopy) b = b && pdfdoc->okToCopy();
+ if (permissions & KPDFDocument::AllowPrint) b = b && pdfdoc->okToPrint();
+ if (permissions & KPDFDocument::AllowNotes) b = b && pdfdoc->okToAddNotes();
+ return b;
+}
+
+bool PDFGenerator::canGeneratePixmap()
+{
+ return ready;
+}
+
+void PDFGenerator::generatePixmap( PixmapRequest * request )
+{
+#ifndef NDEBUG
+ if ( !ready )
+ kdDebug() << "calling generatePixmap() when not in READY state!" << endl;
+#endif
+ // update busy state (not really needed here, because the flag needs to
+ // be set only to prevent asking a pixmap while the thread is running)
+ ready = false;
+
+ // debug requests to this (xpdf) generator
+ //kdDebug() << "id: " << request->id << " is requesting " << (request->async ? "ASYNC" : "sync") << " pixmap for page " << request->page->number() << " [" << request->width << " x " << request->height << "]." << endl;
+
+ /** asyncronous requests (generation in PDFPixmapGeneratorThread::run() **/
+ if ( request->async )
+ {
+ // start the generation into the thread
+ generatorThread->startGeneration( request );
+ return;
+ }
+
+ /** syncronous request: in-place generation **/
+ // compute dpi used to get an image with desired width and height
+ KPDFPage * page = request->page;
+ double fakeDpiX = request->width * 72.0 / page->width(),
+ fakeDpiY = request->height * 72.0 / page->height();
+
+ // setup kpdf output device: text page is generated only if we are at 72dpi.
+ // since we can pre-generate the TextPage at the right res.. why not?
+ bool genTextPage = !page->hasSearchPage() && (request->width == page->width()) &&
+ (request->height == page->height());
+ // generate links and image rects if rendering pages on pageview
+ bool genObjectRects = request->id & (PAGEVIEW_ID | PRESENTATION_ID);
+
+ // 0. LOCK [waits for the thread end]
+ docLock.lock();
+
+ // 1. Set OutputDev parameters and Generate contents
+ // note: thread safety is set on 'false' for the GUI (this) thread
+ kpdfOutputDev->setParams( request->width, request->height, genObjectRects, genObjectRects, false );
+ pdfdoc->displayPage( kpdfOutputDev, page->number() + 1, fakeDpiX, fakeDpiY, 0, false, true, false );
+ if ( genObjectRects )
+ pdfdoc->processLinks( kpdfOutputDev, page->number() + 1 );
+
+ // 2. Take data from outputdev and attach it to the Page
+ page->setPixmap( request->id, kpdfOutputDev->takePixmap() );
+ if ( genObjectRects )
+ page->setObjectRects( kpdfOutputDev->takeObjectRects() );
+
+ // 3. UNLOCK [re-enables shared access]
+ docLock.unlock();
+
+ if ( genTextPage )
+ generateSyncTextPage( page );
+
+ // update ready state
+ ready = true;
+
+ // notify the new generation
+ signalRequestDone( request );
+}
+
+void PDFGenerator::generateSyncTextPage( KPDFPage * page )
+{
+ // build a TextPage...
+ TextOutputDev td(NULL, gTrue, gFalse, gFalse);
+ docLock.lock();
+ pdfdoc->displayPage( &td, page->number()+1, 72, 72, 0, false, true, false );
+ // ..and attach it to the page
+ page->setSearchPage( td.takeText() );
+ docLock.unlock();
+}
+
+bool PDFGenerator::supportsSearching() const
+{
+ return true;
+}
+
+bool PDFGenerator::hasFonts() const
+{
+ return true;
+}
+
+void PDFGenerator::putFontInfo(KListView *list)
+{
+ Page *page;
+ Dict *resDict;
+ Annots *annots;
+ Object obj1, obj2;
+ int pg, i;
+
+ Ref *fonts;
+ int fontsLen;
+ int fontsSize;
+
+ list->addColumn(i18n("Name"));
+ list->addColumn(i18n("Type"));
+ list->addColumn(i18n("Embedded"));
+ list->addColumn(i18n("File"));
+
+ docLock.lock();
+
+ fonts = NULL;
+ fontsLen = fontsSize = 0;
+ QValueVector<Ref> visitedXObjects;
+ for (pg = 1; pg <= pdfdoc->getNumPages(); ++pg)
+ {
+ page = pdfdoc->getCatalog()->getPage(pg);
+ if ((resDict = page->getResourceDict()))
+ {
+ scanFonts(resDict, list, &fonts, fontsLen, fontsSize, &visitedXObjects);
+ }
+ annots = new Annots(pdfdoc->getXRef(), pdfdoc->getCatalog(), page->getAnnots(&obj1));
+ obj1.free();
+ for (i = 0; i < annots->getNumAnnots(); ++i)
+ {
+ if (annots->getAnnot(i)->getAppearance(&obj1)->isStream())
+ {
+ obj1.streamGetDict()->lookup("Resources", &obj2);
+ if (obj2.isDict())
+ {
+ scanFonts(obj2.getDict(), list, &fonts, fontsLen, fontsSize, &visitedXObjects);
+ }
+ obj2.free();
+ }
+ obj1.free();
+ }
+ delete annots;
+ }
+ gfree(fonts);
+
+ docLock.unlock();
+}
+
+bool PDFGenerator::print( KPrinter& printer )
+{
+ // PageSize is a CUPS artificially created setting
+ QString ps = printer.option("PageSize");
+ int paperWidth, paperHeight;
+ int marginTop, marginLeft, marginRight, marginBottom;
+ marginTop = (int)printer.option("kde-margin-top").toDouble();
+ marginLeft = (int)printer.option("kde-margin-left").toDouble();
+ marginRight = (int)printer.option("kde-margin-right").toDouble();
+ marginBottom = (int)printer.option("kde-margin-bottom").toDouble();
+ bool forceRasterize = printer.option("kde-kpdf-forceRaster").toInt();
+
+ if (ps.find(QRegExp("w\\d+h\\d+")) == 0)
+ {
+ // size not supported by Qt, CUPS gives us the size as wWIDTHhHEIGHT, at least on the printers i tester
+ // remove the w
+ ps = ps.mid(1);
+ int hPos = ps.find("h");
+ paperWidth = ps.left(hPos).toInt();
+ paperHeight = ps.mid(hPos+1).toInt();
+ }
+ else
+ {
+ // size is supported by Qt, we get either the pageSize name or nothing because the CUPS driver
+ // does not do any translation, then use KPrinter::pageSize to get the page size
+ KPrinter::PageSize qtPageSize;
+ if (!ps.isEmpty()) qtPageSize = pageNameToPageSize(ps);
+ else qtPageSize = printer.pageSize();
+
+ QPrinter dummy(QPrinter::PrinterResolution);
+ dummy.setFullPage(true);
+ dummy.setPageSize((QPrinter::PageSize)qtPageSize);
+
+ QPaintDeviceMetrics metrics(&dummy);
+ paperWidth = metrics.width();
+ paperHeight = metrics.height();
+ }
+
+ KTempFile tf( QString::null, ".ps" );
+ globalParams->setPSPaperWidth(paperWidth);
+ globalParams->setPSPaperHeight(paperHeight);
+ QString pstitle = getDocumentInfo("Title", true);
+ if ( pstitle.isEmpty() )
+ {
+ pstitle = m_document->currentDocument().fileName( false );
+ }
+ // this looks non-unicode-safe and it is. anything other than ASCII is not specified
+ // and some printers actually stop printing when they encounter non-ASCII characters in the
+ // Postscript %%Title tag
+ QCString pstitle8Bit = pstitle.latin1();
+ const char* pstitlechar;
+ if (!pstitle.isEmpty())
+ {
+ pstitlechar = pstitle8Bit.data();
+ for (unsigned char* p = (unsigned char*) pstitle8Bit.data(); *p; ++p)
+ if (*p >= 0x80)
+ *p = '?';
+
+ printer.setDocName(pstitle);
+ }
+ else
+ {
+ pstitlechar = 0;
+ }
+ PSOutputDev *psOut = new PSOutputDev(const_cast<char*>(tf.name().latin1()), const_cast<char*>(pstitlechar), pdfdoc->getXRef(), pdfdoc->getCatalog(), 1, pdfdoc->getNumPages(), psModePS, marginLeft, marginBottom, paperWidth - marginRight, paperHeight - marginTop, forceRasterize);
+
+ if (psOut->isOk())
+ {
+ double xScale = ((double)paperWidth - (double)marginLeft - (double)marginRight) / (double)paperWidth;
+ double yScale = ((double)paperHeight - (double)marginBottom - (double)marginTop) / (double)paperHeight;
+
+ if ( abs((int)(xScale * 100) - (int)(yScale * 100)) > 5 ) {
+ int result = KMessageBox::questionYesNo(m_document->widget(),
+ i18n("The margins you specified change the page aspect ratio. Do you want to print with the aspect ratio changed or do you want the margins to be adapted so that the aspect ratio is preserved?"),
+ i18n("Aspect ratio change"),
+ i18n("Print with specified margins"),
+ i18n("Print adapting margins to keep aspect ratio"),
+ "kpdfStrictlyObeyMargins");
+ if (result == KMessageBox::Yes) psOut->setScale(xScale, yScale);
+ }
+
+ QValueList<int> pageList;
+
+ if (!printer.previewOnly())
+ {
+ pageList = printer.pageList();
+ }
+ else
+ {
+ for(int i = 1; i <= pdfdoc->getNumPages(); i++) pageList.append(i);
+ }
+
+ QValueList<int>::const_iterator pIt = pageList.begin(), pEnd = pageList.end();
+ docLock.lock();
+ for ( ; pIt != pEnd; ++pIt )
+ {
+ pdfdoc->displayPage(psOut, *pIt, 72, 72, 0, false, globalParams->getPSCrop(), gTrue);
+ }
+ docLock.unlock();
+
+ // needs to be here so that the file is flushed, do not merge with the one
+ // in the else
+ delete psOut;
+ printer.printFiles(tf.name(), true);
+ return true;
+ }
+ else
+ {
+ delete psOut;
+ return false;
+ }
+}
+
+static GString *QStringToGString(const QString &s) {
+ int len = s.length();
+ char *cstring = (char *)gmallocn(s.length(), sizeof(char));
+ for (int i = 0; i < len; ++i)
+ cstring[i] = s.at(i).unicode();
+ return new GString(cstring, len);
+}
+
+static QString unicodeToQString(Unicode* u, int len) {
+ QString ret;
+ ret.setLength(len);
+ QChar* qch = (QChar*) ret.unicode();
+ for (;len;--len)
+ *qch++ = (QChar) *u++;
+ return ret;
+}
+
+static QString UnicodeParsedString(GString *s1) {
+ GBool isUnicode;
+ int i;
+ Unicode u;
+ QString result;
+ if ( ( s1->getChar(0) & 0xff ) == 0xfe && ( s1->getChar(1) & 0xff ) == 0xff )
+ {
+ isUnicode = gTrue;
+ i = 2;
+ }
+ else
+ {
+ isUnicode = gFalse;
+ i = 0;
+ }
+ while ( i < s1->getLength() )
+ {
+ if ( isUnicode )
+ {
+ u = ( ( s1->getChar(i) & 0xff ) << 8 ) | ( s1->getChar(i+1) & 0xff );
+ i += 2;
+ }
+ else
+ {
+ u = s1->getChar(i) & 0xff;
+ ++i;
+ }
+ result += unicodeToQString( &u, 1 );
+ }
+ return result;
+}
+
+QString PDFGenerator::getMetaData( const QString & key, const QString & option )
+{
+ if ( key == "StartFullScreen" )
+ {
+ // asking for the 'start in fullscreen mode' (pdf property)
+ if ( pdfdoc->getCatalog()->getPageMode() == Catalog::FullScreen )
+ return "yes";
+ }
+ else if ( key == "NamedViewport" && !option.isEmpty() )
+ {
+ // asking for the page related to a 'named link destination'. the
+ // option is the link name. @see addSynopsisChildren.
+ DocumentViewport viewport;
+ GString * namedDest = QStringToGString(option);
+ docLock.lock();
+ LinkDest * destination = pdfdoc->findDest( namedDest );
+ if ( destination )
+ {
+ fillViewportFromLink( viewport, destination );
+ }
+ docLock.unlock();
+ delete namedDest;
+ if ( viewport.pageNumber >= 0 )
+ return viewport.toString();
+ }
+ else if ( key == "OpenTOC" )
+ {
+ if ( pdfdoc->getCatalog()->getPageMode() == Catalog::UseOutlines )
+ return "yes";
+ }
+ return QString();
+}
+
+bool PDFGenerator::reparseConfig()
+{
+ // load paper color from Settings or use the white default color
+ QColor color = ( (KpdfSettings::renderMode() == KpdfSettings::EnumRenderMode::Paper ) &&
+ KpdfSettings::changeColors() ) ? KpdfSettings::paperColor() : Qt::white;
+ // if paper color is changed we have to rebuild every visible pixmap in addition
+ // to the outputDevice. it's the 'heaviest' case, other effect are just recoloring
+ // over the page rendered on 'standard' white background.
+ if ( color != paperColor || !kpdfOutputDev )
+ {
+ paperColor = color;
+ SplashColor splashCol;
+ splashCol[0] = paperColor.red();
+ splashCol[1] = paperColor.green();
+ splashCol[2] = paperColor.blue();
+ // rebuild the output device using the new paper color and initialize it
+ docLock.lock();
+ delete kpdfOutputDev;
+ kpdfOutputDev = new KPDFOutputDev( splashCol );
+ if ( pdfdoc )
+ kpdfOutputDev->initDevice( pdfdoc );
+ docLock.unlock();
+ return true;
+ }
+ return false;
+}
+//END Generator inherited functions
+
+void PDFGenerator::scanFonts(Dict *resDict, KListView *list, Ref **fonts, int &fontsLen, int &fontsSize, QValueVector<Ref> *visitedXObjects)
+{
+ Object obj1, obj2, xObjDict, xObj, xObj2, resObj;
+ Ref r;
+ GfxFontDict *gfxFontDict;
+ GfxFont *font;
+ int i;
+
+ // scan the fonts in this resource dictionary
+ gfxFontDict = NULL;
+ resDict->lookupNF("Font", &obj1);
+ if (obj1.isRef())
+ {
+ obj1.fetch(pdfdoc->getXRef(), &obj2);
+ if (obj2.isDict())
+ {
+ r = obj1.getRef();
+ gfxFontDict = new GfxFontDict(pdfdoc->getXRef(), &r, obj2.getDict());
+ }
+ obj2.free();
+ }
+ else if (obj1.isDict())
+ {
+ gfxFontDict = new GfxFontDict(pdfdoc->getXRef(), NULL, obj1.getDict());
+ }
+ if (gfxFontDict)
+ {
+ for (i = 0; i < gfxFontDict->getNumFonts(); ++i)
+ {
+ if ((font = gfxFontDict->getFont(i))) scanFont(font, list, fonts, fontsLen, fontsSize);
+ }
+ delete gfxFontDict;
+ }
+ obj1.free();
+
+ // recursively scan any resource dictionaries in objects in this
+ // resource dictionary
+ resDict->lookup("XObject", &xObjDict);
+ if (xObjDict.isDict()) {
+ for (i = 0; i < xObjDict.dictGetLength(); ++i) {
+ xObjDict.dictGetValNF(i, &xObj);
+ if (xObj.isRef()) {
+ bool alreadySeen = false;
+ // check for an already-seen XObject
+ for (int k = 0; k < visitedXObjects->count(); ++k) {
+ if (xObj.getRef().num == visitedXObjects->at(k).num &&
+ xObj.getRef().gen == visitedXObjects->at(k).gen) {
+ alreadySeen = true;
+ }
+ }
+
+ if (alreadySeen) {
+ xObj.free();
+ continue;
+ }
+
+ visitedXObjects->append(xObj.getRef());
+ }
+
+ xObj.fetch(pdfdoc->getXRef(), &xObj2);
+
+ if (xObj2.isStream()) {
+ xObj2.streamGetDict()->lookup("Resources", &resObj);
+ if (resObj.isDict() && resObj.getDict() != resDict) {
+ scanFonts(resObj.getDict(), list, fonts, fontsLen, fontsSize, visitedXObjects);
+ }
+ resObj.free();
+ }
+ xObj.free();
+ xObj2.free();
+ }
+ }
+ xObjDict.free();
+}
+
+void PDFGenerator::scanFont(GfxFont *font, KListView *list, Ref **fonts, int &fontsLen, int &fontsSize)
+{
+ Ref fontRef, embRef;
+ Object fontObj, toUnicodeObj;
+ GString *name;
+ GBool emb;
+ int i;
+
+ QString fontTypeNames[12] = {
+ i18n("unknown"),
+ i18n("Type 1"),
+ i18n("Type 1C"),
+ i18n("OT means OpenType", "Type 1C (OT)"),
+ i18n("Type 3"),
+ i18n("TrueType"),
+ i18n("OT means OpenType", "TrueType (OT)"),
+ i18n("CID Type 0"),
+ i18n("CID Type 0C"),
+ i18n("OT means OpenType", "CID Type 0C (OT)"),
+ i18n("CID TrueType"),
+ i18n("OT means OpenType", "CID TrueType (OT)")
+ };
+
+ fontRef = *font->getID();
+
+ // check for an already-seen font
+ for (i = 0; i < fontsLen; ++i)
+ {
+ if (fontRef.num == (*fonts)[i].num && fontRef.gen == (*fonts)[i].gen)
+ {
+ return;
+ }
+ }
+
+ // font name
+ name = font->getOrigName();
+
+ // check for an embedded font
+ if (font->getType() == fontType3) emb = gTrue;
+ else emb = font->getEmbeddedFontID(&embRef);
+
+ QString sName, sEmb, sPath;
+ if (name)
+ {
+ sName = name->getCString();
+ if (!emb)
+ {
+ DisplayFontParam *dfp = globalParams->getDisplayFont(name);
+ if (dfp)
+ {
+ if (dfp -> kind == displayFontT1) sPath = dfp->t1.fileName->getCString();
+ else sPath = dfp->tt.fileName->getCString();
+ }
+ else sPath = i18n("-");
+ }
+ else sPath = i18n("-");
+ }
+ else
+ {
+ sName = i18n("[none]");
+ sPath = i18n("-");
+ }
+ sEmb = emb ? i18n("Yes") : i18n("No");
+ new KListViewItem(list, sName, fontTypeNames[font->getType()], sEmb, sPath);
+
+ // add this font to the list
+ if (fontsLen == fontsSize)
+ {
+ fontsSize += 32;
+ *fonts = (Ref *)grealloc(*fonts, fontsSize * sizeof(Ref));
+ }
+ (*fonts)[fontsLen++] = *font->getID();
+}
+
+QString PDFGenerator::getDocumentInfo( const QString & data, bool canReturnNull ) const
+// note: MUTEX is LOCKED while calling this
+{
+ // [Albert] Code adapted from pdfinfo.cc on xpdf
+ Object info;
+ if ( !pdfdoc )
+ return canReturnNull ? QString::null : i18n( "Unknown" );
+
+ pdfdoc->getDocInfo( &info );
+ if ( !info.isDict() )
+ return canReturnNull ? QString::null : i18n( "Unknown" );
+
+ Object obj;
+ Dict *infoDict = info.getDict();
+
+ if ( infoDict->lookup( (char*)data.latin1(), &obj )->isString() )
+ {
+ QString result = UnicodeParsedString(obj.getString());
+ obj.free();
+ info.free();
+ return result;
+ }
+ obj.free();
+ info.free();
+ return canReturnNull ? QString::null : i18n( "Unknown" );
+}
+
+QString PDFGenerator::getDocumentDate( const QString & data ) const
+// note: MUTEX is LOCKED while calling this
+{
+ // [Albert] Code adapted from pdfinfo.cc on xpdf
+ if ( !pdfdoc )
+ return i18n( "Unknown Date" );
+
+ Object info;
+ pdfdoc->getDocInfo( &info );
+ if ( !info.isDict() )
+ return i18n( "Unknown Date" );
+
+ Object obj;
+ int year, mon, day, hour, min, sec;
+ Dict *infoDict = info.getDict();
+ UnicodeMap *uMap = globalParams->getTextEncoding();
+ QString result;
+
+ if ( !uMap )
+ return i18n( "Unknown Date" );
+
+ if ( infoDict->lookup( (char*)data.latin1(), &obj )->isString() )
+ {
+ QString s = UnicodeParsedString(obj.getString());
+ if ( s[0] == 'D' && s[1] == ':' )
+ s = s.mid(2);
+
+ if ( !s.isEmpty() && sscanf( s.latin1(), "%4d%2d%2d%2d%2d%2d", &year, &mon, &day, &hour, &min, &sec ) == 6 )
+ {
+ QDate d( year, mon, day ); //CHECK: it was mon-1, Jan->0 (??)
+ QTime t( hour, min, sec );
+ if ( d.isValid() && t.isValid() )
+ result = KGlobal::locale()->formatDateTime( QDateTime(d, t), false, true );
+ else
+ result = s;
+ }
+ else
+ result = s;
+ }
+ else
+ result = i18n( "Unknown Date" );
+ obj.free();
+ info.free();
+ return result;
+}
+
+void PDFGenerator::addSynopsisChildren( QDomNode * parent, GList * items )
+{
+ int numItems = items->getLength();
+ for ( int i = 0; i < numItems; ++i )
+ {
+ // iterate over every object in 'items'
+ OutlineItem * outlineItem = (OutlineItem *)items->get( i );
+
+ // 1. create element using outlineItem's title as tagName
+ QString name;
+ Unicode * uniChar = outlineItem->getTitle();
+ int titleLength = outlineItem->getTitleLength();
+ name = unicodeToQString(uniChar, titleLength);
+ if ( name.isEmpty() )
+ continue;
+ QDomElement item = docSyn.createElement( name );
+ parent->appendChild( item );
+
+ // 2. find the page the link refers to
+ LinkAction * a = outlineItem->getAction();
+ if ( a && ( a->getKind() == actionGoTo || a->getKind() == actionGoToR ) )
+ {
+ // page number is contained/referenced in a LinkGoTo
+ LinkGoTo * g = static_cast< LinkGoTo * >( a );
+ LinkDest * destination = g->getDest();
+ if ( !destination && g->getNamedDest() )
+ {
+ // no 'destination' but an internal 'named reference'. we could
+ // get the destination for the page now, but it's VERY time consuming,
+ // so better storing the reference and provide the viewport as metadata
+ // on demand
+ GString *s = g->getNamedDest();
+ QChar *charArray = new QChar[s->getLength()];
+ for (int i = 0; i < s->getLength(); ++i) charArray[i] = QChar(s->getCString()[i]);
+ QString option(charArray, s->getLength());
+ item.setAttribute( "ViewportName", option );
+ delete[] charArray;
+ }
+ else if ( destination && destination->isOk() )
+ {
+ DocumentViewport vp;
+ fillViewportFromLink( vp, destination );
+ item.setAttribute( "Viewport", vp.toString() );
+ }
+ if ( a->getKind() == actionGoToR )
+ {
+ LinkGoToR * g2 = static_cast< LinkGoToR * >( a );
+ item.setAttribute( "ExternalFileName", g2->getFileName()->getCString() );
+ }
+ }
+
+ item.setAttribute( "Open", QVariant( (bool)outlineItem->isOpen() ).toString() );
+
+ // 3. recursively descend over children
+ outlineItem->open();
+ GList * children = outlineItem->getKids();
+ if ( children )
+ addSynopsisChildren( &item, children );
+ }
+}
+
+void PDFGenerator::fillViewportFromLink( DocumentViewport &viewport, LinkDest *destination )
+{
+ if ( !destination->isPageRef() )
+ viewport.pageNumber = destination->getPageNum() - 1;
+ else
+ {
+ Ref ref = destination->getPageRef();
+ viewport.pageNumber = pdfdoc->findPage( ref.num, ref.gen ) - 1;
+ }
+
+ if (viewport.pageNumber < 0) return;
+ if (viewport.pageNumber >= pdfdoc->getNumPages()) return;
+
+ // get destination position
+ // TODO add other attributes to the viewport (taken from link)
+// switch ( destination->getKind() )
+// {
+// case destXYZ:
+ if (destination->getChangeLeft() || destination->getChangeTop())
+ {
+ double CTM[6];
+ Page *page = pdfdoc->getCatalog()->getPage( viewport.pageNumber + 1 );
+ // TODO remember to change this if we implement DPI and/or rotation
+ page->getDefaultCTM(CTM, 72.0, 72.0, 0, gFalse, gTrue);
+
+ int left, top;
+ // this is OutputDev::cvtUserToDev
+ left = (int)(CTM[0] * destination->getLeft() + CTM[2] * destination->getTop() + CTM[4] + 0.5);
+ top = (int)(CTM[1] * destination->getLeft() + CTM[3] * destination->getTop() + CTM[5] + 0.5);
+
+ viewport.rePos.normalizedX = (double)left / (double)page->getCropWidth();
+ viewport.rePos.normalizedY = (double)top / (double)page->getCropHeight();
+ viewport.rePos.enabled = true;
+ viewport.rePos.pos = DocumentViewport::TopLeft;
+ }
+ /* TODO
+ if ( dest->getChangeZoom() )
+ make zoom change*/
+/* break;
+
+ default:
+ // implement the others cases
+ break;*/
+// }
+}
+
+void PDFGenerator::addTransition( int pageNumber, KPDFPage * page )
+{
+ Page *pdfPage = pdfdoc->getCatalog()->getPage( pageNumber + 1 );
+ if ( !pdfPage )
+ return;
+
+ PageTransition *pdfTransition = pdfPage->getTransition();
+ if ( !pdfTransition || pdfTransition->getType() == PageTransition::Replace )
+ return;
+
+ KPDFPageTransition *transition = new KPDFPageTransition();
+ switch ( pdfTransition->getType() ) {
+ case PageTransition::Replace:
+ // won't get here, added to avoid warning
+ break;
+ case PageTransition::Split:
+ transition->setType( KPDFPageTransition::Split );
+ break;
+ case PageTransition::Blinds:
+ transition->setType( KPDFPageTransition::Blinds );
+ break;
+ case PageTransition::Box:
+ transition->setType( KPDFPageTransition::Box );
+ break;
+ case PageTransition::Wipe:
+ transition->setType( KPDFPageTransition::Wipe );
+ break;
+ case PageTransition::Dissolve:
+ transition->setType( KPDFPageTransition::Dissolve );
+ break;
+ case PageTransition::Glitter:
+ transition->setType( KPDFPageTransition::Glitter );
+ break;
+ case PageTransition::Fly:
+ transition->setType( KPDFPageTransition::Fly );
+ break;
+ case PageTransition::Push:
+ transition->setType( KPDFPageTransition::Push );
+ break;
+ case PageTransition::Cover:
+ transition->setType( KPDFPageTransition::Cover );
+ break;
+ case PageTransition::Uncover:
+ transition->setType( KPDFPageTransition::Uncover );
+ break;
+ case PageTransition::Fade:
+ transition->setType( KPDFPageTransition::Fade );
+ break;
+ }
+
+ transition->setDuration( pdfTransition->getDuration() );
+
+ switch ( pdfTransition->getAlignment() ) {
+ case PageTransition::Horizontal:
+ transition->setAlignment( KPDFPageTransition::Horizontal );
+ break;
+ case PageTransition::Vertical:
+ transition->setAlignment( KPDFPageTransition::Vertical );
+ break;
+ }
+
+ switch ( pdfTransition->getDirection() ) {
+ case PageTransition::Inward:
+ transition->setDirection( KPDFPageTransition::Inward );
+ break;
+ case PageTransition::Outward:
+ transition->setDirection( KPDFPageTransition::Outward );
+ break;
+ }
+
+ transition->setAngle( pdfTransition->getAngle() );
+ transition->setScale( pdfTransition->getScale() );
+ transition->setIsRectangular( pdfTransition->isRectangular() == gTrue );
+
+ page->setTransition( transition );
+}
+
+
+
+void PDFGenerator::customEvent( QCustomEvent * event )
+{
+ // catch generator 'ready events' only
+ if ( event->type() != TGE_DATAREADY_ID )
+ return;
+
+#if 0
+ // check if thread is running (has to be stopped now)
+ if ( generatorThread->running() )
+ {
+ // if so, wait for effective thread termination
+ if ( !generatorThread->wait( 9999 /*10s timeout*/ ) )
+ {
+ kdWarning() << "PDFGenerator: thread sent 'data available' "
+ << "signal but had problems ending." << endl;
+ return;
+ }
+}
+#endif
+
+ // 1. the mutex must be unlocked now
+ if ( docLock.locked() )
+ {
+ kdWarning() << "PDFGenerator: 'data available' but mutex still "
+ << "held. Recovering." << endl;
+ // syncronize GUI thread (must not happen)
+ docLock.lock();
+ docLock.unlock();
+ }
+
+ // 2. put thread's generated data into the KPDFPage
+ PixmapRequest * request = static_cast< PixmapRequest * >( event->data() );
+ QImage * outImage = generatorThread->takeImage();
+ TextPage * outTextPage = generatorThread->takeTextPage();
+ QValueList< ObjectRect * > outRects = generatorThread->takeObjectRects();
+
+ request->page->setPixmap( request->id, new QPixmap( *outImage ) );
+ delete outImage;
+ if ( outTextPage )
+ request->page->setSearchPage( outTextPage );
+ if ( !outRects.isEmpty() )
+ request->page->setObjectRects( outRects );
+
+ // 3. tell generator that data has been taken
+ generatorThread->endGeneration();
+
+ // update ready state
+ ready = true;
+ // notify the new generation
+ signalRequestDone( request );
+}
+
+
+
+/** The PDF Pixmap Generator Thread **/
+
+struct PPGThreadPrivate
+{
+ // reference to main objects
+ PDFGenerator * generator;
+ PixmapRequest * currentRequest;
+
+ // internal temp stored items. don't delete this.
+ QImage * m_image;
+ TextPage * m_textPage;
+ QValueList< ObjectRect * > m_rects;
+ bool m_rectsTaken;
+};
+
+PDFPixmapGeneratorThread::PDFPixmapGeneratorThread( PDFGenerator * gen )
+ : d( new PPGThreadPrivate() )
+{
+ d->generator = gen;
+ d->currentRequest = 0;
+ d->m_image = 0;
+ d->m_textPage = 0;
+ d->m_rectsTaken = true;
+}
+
+PDFPixmapGeneratorThread::~PDFPixmapGeneratorThread()
+{
+ // delete internal objects if the class is deleted before the gui thread
+ // takes the data
+ delete d->m_image;
+ delete d->m_textPage;
+ if ( !d->m_rectsTaken && d->m_rects.count() )
+ {
+ QValueList< ObjectRect * >::iterator it = d->m_rects.begin(), end = d->m_rects.end();
+ for ( ; it != end; ++it )
+ delete *it;
+ }
+ delete d->currentRequest;
+ // delete internal storage structure
+ delete d;
+}
+
+void PDFPixmapGeneratorThread::startGeneration( PixmapRequest * request )
+{
+#ifndef NDEBUG
+ // check if a generation is already running
+ if ( d->currentRequest )
+ {
+ kdDebug() << "PDFPixmapGeneratorThread: requesting a pixmap "
+ << "when another is being generated." << endl;
+ delete request;
+ return;
+ }
+
+ // check if the mutex is already held
+ if ( d->generator->docLock.locked() )
+ {
+ kdDebug() << "PDFPixmapGeneratorThread: requesting a pixmap "
+ << "with the mutex already held." << endl;
+ delete request;
+ return;
+ }
+#endif
+ // set generation parameters and run thread
+ d->currentRequest = request;
+ start( QThread::InheritPriority );
+}
+
+void PDFPixmapGeneratorThread::endGeneration()
+{
+#ifndef NDEBUG
+ // check if a generation is already running
+ if ( !d->currentRequest )
+ {
+ kdDebug() << "PDFPixmapGeneratorThread: 'end generation' called "
+ << "but generation was not started." << endl;
+ return;
+ }
+#endif
+ // reset internal members preparing for a new generation
+ d->currentRequest = 0;
+}
+
+QImage * PDFPixmapGeneratorThread::takeImage() const
+{
+ QImage * img = d->m_image;
+ d->m_image = 0;
+ return img;
+}
+
+TextPage * PDFPixmapGeneratorThread::takeTextPage() const
+{
+ TextPage * tp = d->m_textPage;
+ d->m_textPage = 0;
+ return tp;
+}
+
+QValueList< ObjectRect * > PDFPixmapGeneratorThread::takeObjectRects() const
+{
+ d->m_rectsTaken = true;
+ return d->m_rects;
+}
+
+void PDFPixmapGeneratorThread::run()
+// perform contents generation, when the MUTEX is already LOCKED
+// @see PDFGenerator::generatePixmap( .. ) (and be aware to sync the code)
+{
+ // compute dpi used to get an image with desired width and height
+ KPDFPage * page = d->currentRequest->page;
+ int width = d->currentRequest->width,
+ height = d->currentRequest->height;
+ double fakeDpiX = width * 72.0 / page->width(),
+ fakeDpiY = height * 72.0 / page->height();
+
+ // setup kpdf output device: text page is generated only if we are at 72dpi.
+ // since we can pre-generate the TextPage at the right res.. why not?
+ bool genTextPage = !page->hasSearchPage() &&
+ ( width == page->width() ) &&
+ ( height == page->height() );
+
+ // generate links and image rects if rendering pages on pageview
+ bool genObjectRects = d->currentRequest->id & (PAGEVIEW_ID | PRESENTATION_ID);
+
+ // 0. LOCK s[tart locking XPDF thread unsafe classes]
+ d->generator->docLock.lock();
+
+ // 1. set OutputDev parameters and Generate contents
+ d->generator->kpdfOutputDev->setParams( width, height,
+ genObjectRects, genObjectRects, TRUE /*thread safety*/ );
+ d->generator->pdfdoc->displayPage( d->generator->kpdfOutputDev, page->number() + 1,
+ fakeDpiX, fakeDpiY, 0, false, true, false );
+ if ( genObjectRects )
+ d->generator->pdfdoc->processLinks( d->generator->kpdfOutputDev, page->number() + 1 );
+
+ // 2. grab data from the OutputDev and store it locally (note takeIMAGE)
+#ifndef NDEBUG
+ if ( d->m_image )
+ kdDebug() << "PDFPixmapGeneratorThread: previous image not taken" << endl;
+ if ( d->m_textPage )
+ kdDebug() << "PDFPixmapGeneratorThread: previous textpage not taken" << endl;
+#endif
+ d->m_image = d->generator->kpdfOutputDev->takeImage();
+ d->m_rects = d->generator->kpdfOutputDev->takeObjectRects();
+ d->m_rectsTaken = false;
+
+ if ( genTextPage )
+ {
+ TextOutputDev td(NULL, gTrue, gFalse, gFalse);
+ d->generator->pdfdoc->displayPage( &td, page->number()+1, 72, 72, 0, false, true, false );
+ // ..and attach it to the page
+ d->m_textPage = td.takeText();
+ }
+
+ // 3. [UNLOCK] mutex
+ d->generator->docLock.unlock();
+
+ // notify the GUI thread that data is pending and can be read
+ QCustomEvent * readyEvent = new QCustomEvent( TGE_DATAREADY_ID );
+ readyEvent->setData( d->currentRequest );
+ QApplication::postEvent( d->generator, readyEvent );
+}
diff --git a/kpdf/core/generator_pdf/generator_pdf.h b/kpdf/core/generator_pdf/generator_pdf.h
new file mode 100644
index 00000000..ca267b18
--- /dev/null
+++ b/kpdf/core/generator_pdf/generator_pdf.h
@@ -0,0 +1,150 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Albert Astals Cid <tsdgeos@terra.es> *
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef _KPDF_GENERATOR_PDF_H_
+#define _KPDF_GENERATOR_PDF_H_
+
+#include <qmutex.h>
+#include <qcolor.h>
+#include <qstring.h>
+#include <qthread.h>
+#include "core/generator.h"
+#include "core/document.h"
+#include "core/link.h"
+
+class Dict;
+class GfxFont;
+class LinkDest;
+class Ref;
+class PDFDoc;
+class GList;
+class TextPage;
+
+class ObjectRect;
+class KPDFOutputDev;
+class PDFPixmapGeneratorThread;
+
+/**
+ * @short A generator that builds contents from a PDF document.
+ *
+ * All Generator features are supported and implented by this one.
+ * Internally this holds a reference to xpdf's core objects and provides
+ * contents generation using the PDFDoc object and a couple of OutputDevices
+ * called KPDFOutputDev and KPDFTextDev (both defined in gp_outputdev.h).
+ *
+ * For generating page contents we tell PDFDoc to render a page and grab
+ * contents from out OutputDevs when rendering finishes.
+ *
+ * Background asyncronous contents providing is done via a QThread inherited
+ * class defined at the bottom of the file.
+ */
+class PDFGenerator : public Generator
+{
+ public:
+ PDFGenerator( KPDFDocument * document );
+ virtual ~PDFGenerator();
+
+ // [INHERITED] load a document and fill up the pagesVector
+ bool loadDocument( const QString & fileName, QValueVector<KPDFPage*> & pagesVector );
+
+ // [INHERITED] document informations
+ const DocumentInfo * generateDocumentInfo();
+ const DocumentSynopsis * generateDocumentSynopsis();
+
+ // [INHERITED] document informations
+ bool isAllowed( int permissions );
+
+ // [INHERITED] perform actions on document / pages
+ bool canGeneratePixmap();
+ void generatePixmap( PixmapRequest * request );
+ void generateSyncTextPage( KPDFPage * page );
+
+ // [INHERITED] capability querying
+ bool supportsSearching() const;
+ bool hasFonts() const;
+
+ // [INHERITED] font related
+ void putFontInfo(KListView *list);
+
+ // [INHERITED] print page using an already configured kprinter
+ bool print( KPrinter& printer );
+
+ // [INHERITED] reply to some metadata requests
+ QString getMetaData( const QString & key, const QString & option );
+
+ // [INHERITED] reparse configuration
+ bool reparseConfig();
+
+ private:
+ // friend class to access private document related variables
+ friend class PDFPixmapGeneratorThread;
+
+ void scanFonts(Dict *resDict, KListView *list, Ref **fonts, int &fontsLen, int &fontsSize, QValueVector<Ref> *visitedXObjects);
+ void scanFont(GfxFont *font, KListView *list, Ref **fonts, int &fontsLen, int &fontsSize);
+
+ void fillViewportFromLink( DocumentViewport &viewport, LinkDest *destination );
+
+ // private functions for accessing document informations via PDFDoc
+ QString getDocumentInfo( const QString & data, bool canReturnNull = false ) const;
+ QString getDocumentDate( const QString & data ) const;
+ // private function for creating the document synopsis hieracy
+ void addSynopsisChildren( QDomNode * parent, GList * items );
+ // private function for creating the transition information
+ void addTransition( int pageNumber, KPDFPage * page );
+ // (async related) receive data from the generator thread
+ void customEvent( QCustomEvent * );
+
+ // xpdf dependant stuff
+ QMutex docLock;
+ PDFDoc * pdfdoc;
+ KPDFOutputDev * kpdfOutputDev;
+ QColor paperColor;
+
+ // asyncronous generation related stuff
+ PDFPixmapGeneratorThread * generatorThread;
+
+ // misc variables for document info and synopsis caching
+ bool ready;
+ PixmapRequest * pixmapRequest;
+ bool docInfoDirty;
+ DocumentInfo docInfo;
+ bool docSynopsisDirty;
+ DocumentSynopsis docSyn;
+};
+
+
+/**
+ * @short A thread that builds contents for PDFGenerator in the background.
+ *
+ */
+class PDFPixmapGeneratorThread : public QThread
+{
+ public:
+ PDFPixmapGeneratorThread( PDFGenerator * generator );
+ ~PDFPixmapGeneratorThread();
+
+ // set the request to the thread (it will be reparented)
+ void startGeneration( PixmapRequest * request );
+ // end generation
+ void endGeneration();
+
+ // methods for getting contents from the GUI thread
+ QImage * takeImage() const;
+ TextPage * takeTextPage() const;
+ QValueList< ObjectRect * > takeObjectRects() const;
+
+ private:
+ // can't be called from the outside (but from startGeneration)
+ void run();
+
+ class PPGThreadPrivate * d;
+};
+
+#endif
diff --git a/kpdf/core/generator_pdf/gp_outputdev.cpp b/kpdf/core/generator_pdf/gp_outputdev.cpp
new file mode 100644
index 00000000..c55ccd7c
--- /dev/null
+++ b/kpdf/core/generator_pdf/gp_outputdev.cpp
@@ -0,0 +1,397 @@
+/***************************************************************************
+ * Copyright (C) 2003-2004 by Christophe Devriese *
+ * <Christophe.Devriese@student.kuleuven.ac.be> *
+ * Copyright (C) 2003 by Andy Goossens <andygoossens@telenet.be> *
+ * Copyright (C) 2003 by Scott Wheeler <wheeler@kde.org> *
+ * Copyright (C) 2003 by Ingo Klöcker <kloecker@kde.org> *
+ * Copyright (C) 2003 by Will Andrews <will@csociety.org> *
+ * Copyright (C) 2004 by Dominique Devriese <devriese@kde.org> *
+ * Copyright (C) 2004 by Waldo Bastian <bastian@kde.org> *
+ * Copyright (C) 2004 by Albert Astals Cid <tsdgeos@terra.es> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <kdebug.h>
+#include <qpixmap.h>
+#include <qimage.h>
+
+#include "gp_outputdev.h"
+#include "generator_pdf.h"
+#include "core/document.h" // for DocumentViewport
+#include "core/page.h"
+#include "core/link.h"
+#include "xpdf/Link.h"
+#include "xpdf/GfxState.h"
+#include "xpdf/TextOutputDev.h"
+#include "splash/SplashBitmap.h"
+
+//NOTE: XPDF/Splash *implementation dependant* code is marked with '###'
+
+/** KPDFOutputDev implementation **/
+
+KPDFOutputDev::KPDFOutputDev( SplashColor paperColor )
+ : SplashOutputDev( splashModeRGB8, 4, false, paperColor ),
+ m_doc( 0 ), m_pixmap( 0 ), m_image( 0 )
+{
+}
+
+KPDFOutputDev::~KPDFOutputDev()
+{
+ clear();
+}
+
+void KPDFOutputDev::initDevice( PDFDoc * pdfDoc )
+{
+ m_doc = pdfDoc;
+ startDoc( pdfDoc->getXRef() );
+}
+
+void KPDFOutputDev::setParams( int width, int height, bool genL, bool genI, bool safe )
+{
+ clear();
+
+ m_pixmapWidth = width;
+ m_pixmapHeight = height;
+
+ m_qtThreadSafety = safe;
+ m_generateLinks = genL;
+ m_generateImages = genI;
+}
+
+QPixmap * KPDFOutputDev::takePixmap()
+{
+ QPixmap * pix = m_pixmap;
+ m_pixmap = 0;
+ return pix;
+}
+
+QImage * KPDFOutputDev::takeImage()
+{
+ QImage * img = m_image;
+ m_image = 0;
+ return img;
+}
+
+QValueList< ObjectRect * > KPDFOutputDev::takeObjectRects()
+{
+ if ( m_rects.isEmpty() )
+ return m_rects;
+ QValueList< ObjectRect * > rectsCopy( m_rects );
+ m_rects.clear();
+ return rectsCopy;
+}
+
+//BEGIN - OutputDev hooked calls
+void KPDFOutputDev::endPage()
+{
+ SplashOutputDev::endPage();
+
+ int bh = getBitmap()->getHeight(),
+ bw = getBitmap()->getWidth();
+ // TODO The below loop can be avoided if using the code that is commented here and
+ // we change splashModeRGB8 to splashModeARGB8 the problem is that then bug101800.pdf
+ // does not work
+/* SplashColorPtr dataPtr = getBitmap()->getDataPtr();
+ // construct a qimage SHARING the raw bitmap data in memory
+ QImage * img = new QImage( dataPtr, bw, bh, 32, 0, 0, QImage::IgnoreEndian );*/
+ QImage * img = new QImage( bw, bh, 32 );
+ SplashColorPtr pixel = new Guchar[4];
+ for (int i = 0; i < bw; i++)
+ {
+ for (int j = 0; j < bh; j++)
+ {
+ getBitmap()->getPixel(i, j, pixel);
+ img->setPixel( i, j, qRgb( pixel[0], pixel[1], pixel[2] ) );
+ }
+ }
+ delete [] pixel;
+
+ // use the QImage or convert it immediately to QPixmap for better
+ // handling and memory unloading
+ if ( m_qtThreadSafety )
+ {
+ delete m_image;
+ // it may happen (in fact it doesn't) that we need a rescaling
+ if ( bw != m_pixmapWidth && bh != m_pixmapHeight )
+ m_image = new QImage( img->smoothScale( m_pixmapWidth, m_pixmapHeight ) );
+ else
+ // dereference image from the xpdf memory
+ m_image = new QImage( img->copy() );
+ }
+ else
+ {
+ delete m_pixmap;
+ // it may happen (in fact it doesn't) that we need a rescaling
+ if ( bw != m_pixmapWidth || bh != m_pixmapHeight )
+ m_pixmap = new QPixmap( img->smoothScale( m_pixmapWidth, m_pixmapHeight ) );
+ else
+ m_pixmap = new QPixmap( *img );
+ }
+
+ // destroy the shared descriptor and (###) unload underlying xpdf bitmap
+ delete img;
+ SplashOutputDev::startPage( 0, NULL );
+}
+
+void KPDFOutputDev::processLink( Link * link, Catalog * catalog )
+{
+ if ( !link->isOk() )
+ return;
+
+ if ( m_generateLinks )
+ {
+ // create the link descriptor
+ KPDFLink * l = generateLink( link->getAction() );
+ if ( l )
+ {
+ // create the page rect representing the link
+ double x1, y1, x2, y2;
+ link->getRect( &x1, &y1, &x2, &y2 );
+ int left, top, right, bottom;
+ cvtUserToDev( x1, y1, &left, &top );
+ cvtUserToDev( x2, y2, &right, &bottom );
+ double nl = (double)left / (double)m_pixmapWidth,
+ nt = (double)top / (double)m_pixmapHeight,
+ nr = (double)right / (double)m_pixmapWidth,
+ nb = (double)bottom / (double)m_pixmapHeight;
+ // create the rect using normalized coords and attach the KPDFLink to it
+ ObjectRect * rect = new ObjectRect( nl, nt, nr, nb, ObjectRect::Link, l );
+ // add the ObjectRect to the vector container
+ m_rects.push_front( rect );
+ }
+ }
+ SplashOutputDev::processLink( link, catalog );
+}
+
+void KPDFOutputDev::drawImage( GfxState *state, Object *ref, Stream *str,
+ int _width, int _height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg )
+{
+ if ( m_generateImages )
+ {
+ // find out image rect from the Coord Transform Matrix
+ double * ctm = state->getCTM();
+ int left = (int)ctm[4],
+ top = (int)ctm[5],
+ width = (int)ctm[0],
+ height = (int)ctm[3];
+ // normalize width
+ if ( width < 0 )
+ {
+ width = -width;
+ left -= width;
+ }
+ // normalize height
+ if ( height < 0 )
+ {
+ height = -height;
+ top -= height;
+ }
+ if ( width > 10 && height > 10 )
+ {
+ // build a descriptor for the image rect
+ double nl = (double)left / (double)m_pixmapWidth,
+ nt = (double)top / (double)m_pixmapHeight,
+ nr = (double)(left + width) / (double)m_pixmapWidth,
+ nb = (double)(top + height) / (double)m_pixmapHeight;
+ // create the rect using normalized coords and set it of KPDFImage type
+ ObjectRect * rect = new ObjectRect( nl, nt, nr, nb, ObjectRect::Image, 0 );
+ // add the ObjectRect to the vector container
+ m_rects.push_back( rect );
+ }
+ }
+ SplashOutputDev::drawImage( state, ref, str, _width, _height, colorMap, maskColors, inlineImg );
+}
+//END - OutputDev hooked calls
+
+//BEGIN - private helpers
+void KPDFOutputDev::clear()
+{
+ // delete rects
+ if ( m_rects.count() )
+ {
+ QValueList< ObjectRect * >::iterator it = m_rects.begin(), end = m_rects.end();
+ for ( ; it != end; ++it )
+ delete *it;
+ m_rects.clear();
+ }
+ // delete pixmap
+ if ( m_pixmap )
+ {
+ delete m_pixmap;
+ m_pixmap = 0;
+ }
+ // delete image
+ if ( m_image )
+ {
+ delete m_image;
+ m_image = 0;
+ }
+}
+
+KPDFLink * KPDFOutputDev::generateLink( LinkAction * a )
+// note: this function is called when processing a page, when the MUTEX is already LOCKED
+{
+ KPDFLink * link = NULL;
+ if ( a ) switch ( a->getKind() )
+ {
+ case actionGoTo:
+ {
+ LinkGoTo * g = (LinkGoTo *) a;
+ // ceate link: no ext file, namedDest, object pointer
+ link = new KPDFLinkGoto( QString::null, decodeViewport( g->getNamedDest(), g->getDest() ) );
+ }
+ break;
+
+ case actionGoToR:
+ {
+ LinkGoToR * g = (LinkGoToR *) a;
+ // copy link file
+ const char * fileName = g->getFileName()->getCString();
+ // ceate link: fileName, namedDest, object pointer
+ link = new KPDFLinkGoto( (QString)fileName, decodeViewport( g->getNamedDest(), g->getDest() ) );
+ }
+ break;
+
+ case actionLaunch:
+ {
+ LinkLaunch * e = (LinkLaunch *)a;
+ GString * p = e->getParams();
+ link = new KPDFLinkExecute( e->getFileName()->getCString(), p ? p->getCString() : 0 );
+ }
+ break;
+
+ case actionNamed:
+ {
+ const char * name = ((LinkNamed *)a)->getName()->getCString();
+ if ( !strcmp( name, "NextPage" ) )
+ link = new KPDFLinkAction( KPDFLinkAction::PageNext );
+ else if ( !strcmp( name, "PrevPage" ) )
+ link = new KPDFLinkAction( KPDFLinkAction::PagePrev );
+ else if ( !strcmp( name, "FirstPage" ) )
+ link = new KPDFLinkAction( KPDFLinkAction::PageFirst );
+ else if ( !strcmp( name, "LastPage" ) )
+ link = new KPDFLinkAction( KPDFLinkAction::PageLast );
+ else if ( !strcmp( name, "GoBack" ) )
+ link = new KPDFLinkAction( KPDFLinkAction::HistoryBack );
+ else if ( !strcmp( name, "GoForward" ) )
+ link = new KPDFLinkAction( KPDFLinkAction::HistoryForward );
+ else if ( !strcmp( name, "Quit" ) )
+ link = new KPDFLinkAction( KPDFLinkAction::Quit );
+ else if ( !strcmp( name, "GoToPage" ) )
+ link = new KPDFLinkAction( KPDFLinkAction::GoToPage );
+ else if ( !strcmp( name, "Find" ) )
+ link = new KPDFLinkAction( KPDFLinkAction::Find );
+ else if ( !strcmp( name, "Close" ) )
+ link = new KPDFLinkAction( KPDFLinkAction::Close );
+ else
+ kdDebug() << "Unknown named action: '" << name << "'" << endl;
+ }
+ break;
+
+ case actionURI:
+ link = new KPDFLinkBrowse( ((LinkURI *)a)->getURI()->getCString() );
+ break;
+
+ case actionMovie:
+/* { TODO this (Movie link)
+ m_type = Movie;
+ LinkMovie * m = (LinkMovie *) a;
+ // copy Movie parameters (2 IDs and a const char *)
+ Ref * r = m->getAnnotRef();
+ m_refNum = r->num;
+ m_refGen = r->gen;
+ copyString( m_uri, m->getTitle()->getCString() );
+ }
+*/ break;
+
+ case actionUnknown:
+ kdDebug() << "Unknown link." << endl;
+ break;
+ }
+
+ // link may be zero at that point
+ return link;
+}
+
+DocumentViewport KPDFOutputDev::decodeViewport( GString * namedDest, LinkDest * dest )
+// note: this function is called when processing a page, when the MUTEX is already LOCKED
+{
+ DocumentViewport vp( -1 );
+ bool deleteDest = false;
+
+ if ( namedDest && !dest )
+ {
+ deleteDest = true;
+ dest = m_doc->findDest( namedDest );
+ }
+
+ if ( !dest || !dest->isOk() )
+ {
+ if (deleteDest) delete dest;
+ return vp;
+ }
+
+ // get destination page number
+ if ( !dest->isPageRef() )
+ vp.pageNumber = dest->getPageNum() - 1;
+ else
+ {
+ Ref ref = dest->getPageRef();
+ vp.pageNumber = m_doc->findPage( ref.num, ref.gen ) - 1;
+ }
+
+ // get destination position
+ // TODO add other attributes to the viewport (taken from link)
+ switch ( dest->getKind() )
+ {
+ case destXYZ:
+ if (dest->getChangeLeft() || dest->getChangeTop())
+ {
+ int left, top;
+ cvtUserToDev( dest->getLeft(), dest->getTop(), &left, &top );
+ vp.rePos.normalizedX = (double)left / (double)m_pixmapWidth;
+ vp.rePos.normalizedY = (double)top / (double)m_pixmapHeight;
+ vp.rePos.enabled = true;
+ vp.rePos.pos = DocumentViewport::TopLeft;
+ }
+ /* TODO
+ if ( dest->getChangeZoom() )
+ make zoom change*/
+ break;
+
+ case destFit:
+ case destFitB:
+ //vp.fitWidth = true;
+ //vp.fitHeight = true;
+ break;
+
+ case destFitH:
+ case destFitBH:
+// read top, fit Width
+ //vp.fitWidth = true;
+ break;
+
+ case destFitV:
+ case destFitBV:
+// read left, fit Height
+ //vp.fitHeight = true;
+ break;
+
+ case destFitR:
+// read and fit left,bottom,right,top
+ break;
+ }
+
+ if (deleteDest) delete dest;
+ return vp;
+}
+//END - private helpers
+
diff --git a/kpdf/core/generator_pdf/gp_outputdev.h b/kpdf/core/generator_pdf/gp_outputdev.h
new file mode 100644
index 00000000..e08724e0
--- /dev/null
+++ b/kpdf/core/generator_pdf/gp_outputdev.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+ * Copyright (C) 2003-2004 by Christophe Devriese *
+ * <Christophe.Devriese@student.kuleuven.ac.be> *
+ * Copyright (C) 2003 by Helio Chissini de Castro *
+ * <helio@conectiva.com.br> *
+ * Copyright (C) 2004 by Dominique Devriese <devriese@kde.org> *
+ * Copyright (C) 2004 by Albert Astals Cid <tsdgeos@terra.es> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef KPDFOUTPUTDEV_H
+#define KPDFOUTPUTDEV_H
+
+#ifdef __GNUC__
+#pragma interface
+#endif
+
+#include <qvaluelist.h>
+#include "xpdf/PDFDoc.h" // for 'Object'
+#include "xpdf/SplashOutputDev.h"
+
+class QPixmap;
+class KPDFLink;
+class ObjectRect;
+class DocumentViewport;
+
+/**
+ * @short A SplashOutputDev renderer that grabs text and links.
+ *
+ * This output device:
+ * - renders the page using SplashOutputDev (its parent)
+ * - harvests text into a textPage (for searching text)
+ * - harvests links and collects them
+ * - collects images and collects them
+ */
+class KPDFOutputDev : public SplashOutputDev
+{
+ public:
+ KPDFOutputDev( SplashColor paperColor );
+ virtual ~KPDFOutputDev();
+
+ // initialize device -> attach device to PDFDoc
+ void initDevice( class PDFDoc * pdfDoc );
+
+ // set parameters before rendering *each* page
+ // @param qtThreadSafety: duplicate memory buffer (slow but safe)
+ void setParams( int pixmapWidth, int pixmapHeight,
+ bool decodeLinks, bool decodeImages, bool qtThreadSafety = false );
+
+ // takes pointers out of the class (so deletion it's up to others)
+ QPixmap * takePixmap();
+ QImage * takeImage();
+ QValueList< ObjectRect * > takeObjectRects();
+
+ /** inherited from OutputDev */
+ // End a page.
+ virtual void endPage();
+ //----- link borders
+ virtual void processLink(Link *link, Catalog *catalog);
+ //----- image drawing
+ virtual void drawImage(GfxState *state, Object *ref, Stream *str, int width, int height,
+ GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg);
+
+ private:
+ // delete all interal objects and data
+ void clear();
+ // generate a valid KPDFLink subclass (or null) from a xpdf's LinkAction
+ KPDFLink * generateLink( LinkAction * a );
+ // fills up a Viewport structure out of a given LinkGoto link
+ DocumentViewport decodeViewport( GString *, class LinkDest * );
+
+ // generator switches and parameters
+ bool m_qtThreadSafety;
+ bool m_generateLinks;
+ bool m_generateImages;
+ int m_pixmapWidth;
+ int m_pixmapHeight;
+
+ // Internal objects
+ PDFDoc * m_doc;
+ QPixmap * m_pixmap;
+ QImage * m_image;
+ QValueList< ObjectRect * > m_rects; // objectRects (links/images)
+};
+
+#endif
diff --git a/kpdf/core/link.cpp b/kpdf/core/link.cpp
new file mode 100644
index 00000000..d8e47a49
--- /dev/null
+++ b/kpdf/core/link.cpp
@@ -0,0 +1,65 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+// local includes
+#include "link.h"
+
+#include <klocale.h>
+
+KPDFLink::~KPDFLink()
+{
+}
+
+QString KPDFLinkGoto::linkTip() const
+{
+ return m_extFileName.isEmpty() ? ( m_vp.pageNumber != -1 ? i18n( "Go to page %1" ).arg( m_vp.pageNumber + 1 ) : QString::null ) : i18n("Open external file");
+}
+
+QString KPDFLinkExecute::linkTip() const
+{
+ return i18n( "Execute '%1'..." ).arg( m_fileName );
+}
+
+QString KPDFLinkBrowse::linkTip() const
+{
+ return m_url;
+}
+
+QString KPDFLinkAction::linkTip() const
+{
+ switch ( m_type )
+ {
+ case PageFirst:
+ return i18n( "First Page" );
+ case PagePrev:
+ return i18n( "Previous Page" );
+ case PageNext:
+ return i18n( "Next Page" );
+ case PageLast:
+ return i18n( "Last Page" );
+ case HistoryBack:
+ return i18n( "Back" );
+ case HistoryForward:
+ return i18n( "Forward" );
+ case Quit:
+ return i18n( "Quit" );
+ case Presentation:
+ return i18n( "Start Presentation" );
+ case EndPresentation:
+ return i18n( "End Presentation" );
+ case Find:
+ return i18n( "Find..." );
+ case GoToPage:
+ return i18n( "Go To Page..." );
+ case Close:
+ default: ;
+ }
+
+ return QString::null;
+}
diff --git a/kpdf/core/link.h b/kpdf/core/link.h
new file mode 100644
index 00000000..10420c50
--- /dev/null
+++ b/kpdf/core/link.h
@@ -0,0 +1,118 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef _KPDF_LINK_H_
+#define _KPDF_LINK_H_
+
+#include <qstring.h>
+#include <qrect.h>
+#include "core/document.h" // for DocumentViewport
+
+/**
+ * @short Encapsulates data that describes a link.
+ *
+ * This is the base class for links. It makes mandatory for inherited
+ * widgets to reimplement the 'linkType' method and return the type of
+ * the link described by the reimplemented class.
+ */
+class KPDFLink
+{
+ public:
+ // get link type (inherited classes mustreturn an unique identifier)
+ enum LinkType { Goto, Execute, Browse, Action, Movie };
+ virtual LinkType linkType() const = 0;
+ virtual QString linkTip() const { return QString::null; }
+
+ // virtual destructor (remove warnings)
+ virtual ~KPDFLink();
+};
+
+
+/** Goto: a viewport and maybe a reference to an external filename **/
+class KPDFLinkGoto : public KPDFLink
+{
+ public:
+ // query for goto parameters
+ bool isExternal() const { return !m_extFileName.isEmpty(); }
+ const QString & fileName() const { return m_extFileName; }
+ const DocumentViewport & destViewport() const { return m_vp; }
+
+ // create a KPDFLink_Goto
+ KPDFLinkGoto( QString extFileName, const DocumentViewport & vp ) { m_extFileName = extFileName; m_vp = vp; }
+ LinkType linkType() const { return Goto; }
+ QString linkTip() const;
+
+ private:
+ QString m_extFileName;
+ DocumentViewport m_vp;
+};
+
+/** Execute: filename and parameters to execute **/
+class KPDFLinkExecute : public KPDFLink
+{
+ public:
+ // query for filename / parameters
+ const QString & fileName() const { return m_fileName; }
+ const QString & parameters() const { return m_parameters; }
+
+ // create a KPDFLink_Execute
+ KPDFLinkExecute( const QString & file, const QString & params ) { m_fileName = file; m_parameters = params; }
+ LinkType linkType() const { return Execute; }
+ QString linkTip() const;
+
+ private:
+ QString m_fileName;
+ QString m_parameters;
+};
+
+/** Browse: an URL to open, ranging from 'http://' to 'mailto:' etc.. **/
+class KPDFLinkBrowse : public KPDFLink
+{
+ public:
+ // query for URL
+ const QString & url() const { return m_url; }
+
+ // create a KPDFLink_Browse
+ KPDFLinkBrowse( const QString &url ) { m_url = url; }
+ LinkType linkType() const { return Browse; }
+ QString linkTip() const;
+
+ private:
+ QString m_url;
+};
+
+/** Action: contains an action to perform on document / kpdf **/
+class KPDFLinkAction : public KPDFLink
+{
+ public:
+ // define types of actions
+ enum ActionType { PageFirst, PagePrev, PageNext, PageLast, HistoryBack, HistoryForward, Quit, Presentation, EndPresentation, Find, GoToPage, Close };
+
+ // query for action type
+ ActionType actionType() const { return m_type; }
+
+ // create a KPDFLink_Action
+ KPDFLinkAction( enum ActionType actionType ) { m_type = actionType; }
+ LinkType linkType() const { return Action; }
+ QString linkTip() const;
+
+ private:
+ ActionType m_type;
+};
+
+/** Movie: Not yet defined -> think renaming to 'Media' link **/
+class KPDFLinkMovie : public KPDFLink
+// TODO this (Movie link)
+{
+ public:
+ KPDFLinkMovie() {};
+ LinkType linkType() const { return Movie; }
+};
+
+#endif
diff --git a/kpdf/core/observer.h b/kpdf/core/observer.h
new file mode 100644
index 00000000..28f07bf5
--- /dev/null
+++ b/kpdf/core/observer.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Enrico Ros <eros.kde@email.it> *
+ * Copyright (C) 2005 by Albert Astals Cid <tsdgeos@terra.es> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef _KPDF_DOCUMENTOBSERVER_H_
+#define _KPDF_DOCUMENTOBSERVER_H_
+
+#include <qvaluevector.h>
+#include <qrect.h>
+
+/** IDs for observers. Globally defined here. **/
+#define PRESENTATION_ID 1
+#define PART_ID 2
+#define PAGEVIEW_ID 3
+#define THUMBNAILS_ID 4
+#define TOC_ID 5
+#define MINIBAR_ID 6
+
+/** PRIORITIES for requests. Globally defined here. **/
+#define PAGEVIEW_PRIO 1
+#define PAGEVIEW_PRELOAD_PRIO 4
+#define THUMBNAILS_PRIO 2
+#define THUMBNAILS_PRELOAD_PRIO 5
+#define PRESENTATION_PRIO 0
+#define PRESENTATION_PRELOAD_PRIO 3
+
+class KPDFPage;
+
+/**
+ * @short Base class for objects being notified when something changes.
+ *
+ * Inherit this class and call KPDFDocument->addObserver( yourClass ) to get
+ * notified of asyncronous events (new pixmap generated, or changed, etc..).
+ */
+class DocumentObserver
+{
+ public:
+ // you must give each observer a unique ID (used for notifications)
+ virtual uint observerId() const = 0;
+
+ // commands from the Document to all observers
+ enum ChangedFlags { Pixmap = 1, Bookmark = 2, Highlights = 4 };
+ virtual void notifySetup( const QValueVector< KPDFPage * > & /*pages*/, bool /*documentChanged*/ ) {};
+ virtual void notifyViewportChanged( bool /*smoothMove*/ ) {};
+ virtual void notifyPageChanged( int /*pageNumber*/, int /*changedFlags*/ ) {};
+ virtual void notifyContentsCleared( int /*changedFlags*/ ) {};
+
+ // queries to observers
+ virtual bool canUnloadPixmap( int /*pageNum*/ ) { return true; }
+};
+
+#endif
diff --git a/kpdf/core/page.cpp b/kpdf/core/page.cpp
new file mode 100644
index 00000000..e6a847a8
--- /dev/null
+++ b/kpdf/core/page.cpp
@@ -0,0 +1,327 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+// qt/kde includes
+#include <qpixmap.h>
+#include <qstring.h>
+#include <qmap.h>
+#include <kdebug.h>
+
+// local includes
+#include "page.h"
+#include "pagetransition.h"
+#include "link.h"
+#include "conf/settings.h"
+#include "xpdf/TextOutputDev.h"
+
+
+/** class KPDFPage **/
+
+KPDFPage::KPDFPage( uint page, float w, float h, int r )
+ : m_number( page ), m_rotation( r ), m_width( w ), m_height( h ),
+ m_bookmarked( false ), m_text( 0 ), m_transition( 0 )
+{
+ // if landscape swap width <-> height (rotate 90deg CCW)
+ if ( r == 90 || r == 270 )
+ {
+ m_width = h;
+ m_height = w;
+ }
+ // avoid Division-By-Zero problems in the program
+ if ( m_width <= 0 )
+ m_width = 1;
+ if ( m_height <= 0 )
+ m_height = 1;
+}
+
+KPDFPage::~KPDFPage()
+{
+ deletePixmapsAndRects();
+ deleteHighlights();
+ delete m_text;
+ delete m_transition;
+}
+
+
+bool KPDFPage::hasPixmap( int id, int width, int height ) const
+{
+ if ( !m_pixmaps.contains( id ) )
+ return false;
+ if ( width == -1 || height == -1 )
+ return true;
+ QPixmap * p = m_pixmaps[ id ];
+ return p ? ( p->width() == width && p->height() == height ) : false;
+}
+
+bool KPDFPage::hasSearchPage() const
+{
+ return m_text != 0;
+}
+
+bool KPDFPage::hasBookmark() const
+{
+ return m_bookmarked;
+}
+
+bool KPDFPage::hasObjectRect( double x, double y ) const
+{
+ if ( m_rects.count() < 1 )
+ return false;
+ QValueList< ObjectRect * >::const_iterator it = m_rects.begin(), end = m_rects.end();
+ for ( ; it != end; ++it )
+ if ( (*it)->contains( x, y ) )
+ return true;
+ return false;
+}
+
+bool KPDFPage::hasHighlights( int s_id ) const
+{
+ // simple case: have no highlights
+ if ( m_highlights.isEmpty() )
+ return false;
+ // simple case: we have highlights and no id to match
+ if ( s_id == -1 )
+ return true;
+ // iterate on the highlights list to find an entry by id
+ QValueList< HighlightRect * >::const_iterator it = m_highlights.begin(), end = m_highlights.end();
+ for ( ; it != end; ++it )
+ if ( (*it)->s_id == s_id )
+ return true;
+ return false;
+}
+
+bool KPDFPage::hasTransition() const
+{
+ return m_transition != 0;
+}
+
+
+NormalizedRect * KPDFPage::findText( const QString & text, bool strictCase, NormalizedRect * lastRect ) const
+{
+ if ( text.isEmpty() )
+ return 0;
+
+ // create a xpf's Unicode (unsigned int) array for the given text
+ const QChar * str = text.unicode();
+ int len = text.length();
+ QMemArray<Unicode> u(len);
+ for (int i = 0; i < len; ++i)
+ u[i] = str[i].unicode();
+
+ // find out the direction of search
+ enum SearchDir { FromTop, NextMatch, PrevMatch } dir = lastRect ? NextMatch : FromTop;
+ double sLeft, sTop, sRight, sBottom;
+ if ( dir == NextMatch )
+ {
+ sLeft = lastRect->left * m_width;
+ sTop = lastRect->top * m_height;
+ sRight = lastRect->right * m_width;
+ sBottom = lastRect->bottom * m_height;
+ }
+
+ // this loop is only for 'bad case' matches
+ bool found = false;
+ while ( !found )
+ {
+ if ( dir == FromTop )
+ found = m_text->findText( const_cast<Unicode*>(static_cast<const Unicode*>(u)), len, gTrue, gTrue, gFalse, gFalse, strictCase, gFalse, &sLeft, &sTop, &sRight, &sBottom );
+ else if ( dir == NextMatch )
+ found = m_text->findText( const_cast<Unicode*>(static_cast<const Unicode*>(u)), len, gFalse, gTrue, gTrue, gFalse, strictCase, gFalse, &sLeft, &sTop, &sRight, &sBottom );
+ else if ( dir == PrevMatch )
+ // FIXME: this doesn't work as expected (luckily backward search isn't yet used)
+ // TODO: check if the new xpdf 3.01 code is able of searching backwards
+ found = m_text->findText( const_cast<Unicode*>(static_cast<const Unicode*>(u)), len, gTrue, gFalse, gFalse, gTrue, strictCase, gTrue, &sLeft, &sTop, &sRight, &sBottom );
+
+ // if not found (even in case unsensitive search), terminate
+ if ( !found )
+ break;
+ }
+
+ // if the page was found, return a new normalizedRect
+ if ( found )
+ return new NormalizedRect( sLeft / m_width, sTop / m_height, sRight / m_width, sBottom / m_height );
+ return 0;
+}
+
+const QString KPDFPage::getText( const NormalizedRect & rect ) const
+{
+ if ( !m_text )
+ return QString::null;
+ int left = (int)( rect.left * m_width ),
+ top = (int)( rect.top * m_height ),
+ right = (int)( rect.right * m_width ),
+ bottom = (int)( rect.bottom * m_height );
+ GString * text = m_text->getText( left, top, right, bottom );
+ QString result = QString::fromUtf8( text->getCString() );
+ delete text;
+ return result;
+}
+
+const ObjectRect * KPDFPage::hasObject( ObjectRect::ObjectType type, double x, double y ) const
+{
+ QValueList< ObjectRect * >::const_iterator it = m_rects.begin(), end = m_rects.end();
+ for ( ; it != end; ++it )
+ if ( (*it)->contains( x, y ) )
+ if ((*it)->objectType() == type) return *it;
+ return 0;
+}
+
+const KPDFPageTransition * KPDFPage::getTransition() const
+{
+ return m_transition;
+}
+
+
+void KPDFPage::setPixmap( int id, QPixmap * pixmap )
+{
+ if ( m_pixmaps.contains( id ) )
+ delete m_pixmaps[id];
+ m_pixmaps[id] = pixmap;
+}
+
+void KPDFPage::setSearchPage( TextPage * tp )
+{
+ delete m_text;
+ m_text = tp;
+}
+
+void KPDFPage::setBookmark( bool state )
+{
+ m_bookmarked = state;
+}
+
+void KPDFPage::setObjectRects( const QValueList< ObjectRect * > rects )
+{
+ QValueList< ObjectRect * >::iterator it = m_rects.begin(), end = m_rects.end();
+ for ( ; it != end; ++it )
+ delete *it;
+ m_rects = rects;
+}
+
+void KPDFPage::setHighlight( int s_id, NormalizedRect * &rect, const QColor & color )
+{
+ // create a HighlightRect descriptor taking values from params
+ HighlightRect * hr = new HighlightRect();
+ hr->s_id = s_id;
+ hr->color = color;
+ hr->left = rect->left;
+ hr->top = rect->top;
+ hr->right = rect->right;
+ hr->bottom = rect->bottom;
+ // append the HighlightRect to the list
+ m_highlights.append( hr );
+ // delete old object and change reference
+ delete rect;
+ rect = hr;
+}
+
+void KPDFPage::setTransition( KPDFPageTransition * transition )
+{
+ delete m_transition;
+ m_transition = transition;
+}
+
+void KPDFPage::deletePixmap( int id )
+{
+ if ( m_pixmaps.contains( id ) )
+ {
+ delete m_pixmaps[ id ];
+ m_pixmaps.remove( id );
+ }
+}
+
+void KPDFPage::deletePixmapsAndRects()
+{
+ // delete all stored pixmaps
+ QMap<int,QPixmap *>::iterator it = m_pixmaps.begin(), end = m_pixmaps.end();
+ for ( ; it != end; ++it )
+ delete *it;
+ m_pixmaps.clear();
+ // delete ObjectRects
+ QValueList< ObjectRect * >::iterator rIt = m_rects.begin(), rEnd = m_rects.end();
+ for ( ; rIt != rEnd; ++rIt )
+ delete *rIt;
+ m_rects.clear();
+}
+
+void KPDFPage::deleteHighlights( int s_id )
+{
+ // delete highlights by ID
+ QValueList< HighlightRect * >::iterator it = m_highlights.begin(), end = m_highlights.end();
+ while ( it != end )
+ {
+ HighlightRect * highlight = *it;
+ if ( s_id == -1 || highlight->s_id == s_id )
+ {
+ it = m_highlights.remove( it );
+ delete highlight;
+ }
+ else
+ ++it;
+ }
+}
+
+
+/** class NormalizedRect **/
+
+NormalizedRect::NormalizedRect()
+ : left( 0.0 ), top( 0.0 ), right( 0.0 ), bottom( 0.0 ) {}
+
+NormalizedRect::NormalizedRect( double l, double t, double r, double b )
+ // note: check for swapping coords?
+ : left( l ), top( t ), right( r ), bottom( b ) {}
+
+NormalizedRect::NormalizedRect( const QRect & r, double xScale, double yScale )
+ : left( (double)r.left() / xScale ), top( (double)r.top() / yScale ),
+ right( (double)r.right() / xScale ), bottom( (double)r.bottom() / yScale ) {}
+
+bool NormalizedRect::contains( double x, double y ) const
+{
+ return x >= left && x <= right && y >= top && y <= bottom;
+}
+
+bool NormalizedRect::intersects( const NormalizedRect & r ) const
+{
+ return (r.left < right) && (r.right > left) && (r.top < bottom) && (r.bottom > top);
+}
+
+bool NormalizedRect::intersects( double l, double t, double r, double b ) const
+{
+ return (l < right) && (r > left) && (t < bottom) && (b > top);
+}
+
+QRect NormalizedRect::geometry( int xScale, int yScale ) const
+{
+ int l = (int)( left * xScale ),
+ t = (int)( top * yScale ),
+ r = (int)( right * xScale ),
+ b = (int)( bottom * yScale );
+ return QRect( l, t, r - l + 1, b - t + 1 );
+}
+
+
+/** class ObjectRect **/
+
+ObjectRect::ObjectRect( double l, double t, double r, double b, ObjectType type, void * pnt )
+ // assign coordinates swapping them if negative width or height
+ : NormalizedRect( r > l ? l : r, b > t ? t : b, r > l ? r : l, b > t ? b : t ),
+ m_objectType( type ), m_pointer( pnt )
+{
+}
+
+ObjectRect::~ObjectRect()
+{
+ if ( !m_pointer )
+ return;
+
+ if ( m_objectType == Link )
+ delete static_cast<KPDFLink*>( m_pointer );
+ else
+ kdDebug() << "Object deletion not implemented for type '" << m_objectType << "' ." << endl;
+}
diff --git a/kpdf/core/page.h b/kpdf/core/page.h
new file mode 100644
index 00000000..ebd6e522
--- /dev/null
+++ b/kpdf/core/page.h
@@ -0,0 +1,149 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef _KPDF_PAGE_H_
+#define _KPDF_PAGE_H_
+
+#include <qmap.h>
+#include <qvaluelist.h>
+
+class QPixmap;
+class QRect;
+class TextPage;
+class KPDFPageTransition;
+class HighlightRect;
+class Annotation;
+
+/**
+ * @short A rect in normalized [0,1] coordinates.
+ */
+class NormalizedRect
+{
+ public:
+ double left, top, right, bottom;
+
+ NormalizedRect();
+ NormalizedRect( double l, double t, double r, double b );
+ NormalizedRect( const QRect & r, double xScale, double yScale );
+
+ bool contains( double x, double y ) const;
+ bool intersects( const NormalizedRect & normRect ) const;
+ bool intersects( double l, double t, double r, double b ) const;
+
+ QRect geometry( int xScale, int yScale ) const;
+};
+
+/**
+ * @short NormalizedRect that contains a reference to an object.
+ *
+ * These rects contains a pointer to a kpdf object (such as a link or something
+ * like that). The pointer is read and stored as 'void pointer' so cast is
+ * performed by accessors based on the value returned by objectType(). Objects
+ * are reparented to this class.
+ *
+ * Type / Class correspondency tab:
+ * - Link : class KPDFLink : description of a link
+ * - Image : class KPDFImage : description of an image (n/a)
+ */
+class ObjectRect : public NormalizedRect
+{
+ public:
+ // definition of the types of storable objects
+ enum ObjectType { Link, Image };
+
+ // default constructor: initialize all parameters
+ ObjectRect( double l, double t, double r, double b, ObjectType typ, void * obj );
+ ~ObjectRect();
+
+ // query type and get a const pointer to the stored object
+ inline ObjectType objectType() const { return m_objectType; }
+ inline const void * pointer() const { return m_pointer; }
+
+ private:
+ ObjectType m_objectType;
+ void * m_pointer;
+};
+
+/**
+ * @short Collector for all the data belonging to a page.
+ *
+ * The KPDFPage class contains pixmaps (referenced using observers id as key),
+ * a search page (a class used internally for retrieving text), rect classes
+ * (that describe links or other active areas in the current page) and more.
+ *
+ * All coordinates are normalized to the page, so {x,y} are valid in [0,1]
+ * range as long as NormalizedRect components.
+ *
+ * Note: The class takes ownership of all objects.
+ */
+class KPDFPage
+{
+ public:
+ KPDFPage( uint number, float width, float height, int rotation );
+ ~KPDFPage();
+
+ // query properties (const read-only methods)
+ inline int number() const { return m_number; }
+ inline int rotation() const { return m_rotation; }
+ inline float width() const { return m_width; }
+ inline float height() const { return m_height; }
+ inline float ratio() const { return m_height / m_width; }
+ bool hasPixmap( int p_id, int width = -1, int height = -1 ) const;
+ bool hasSearchPage() const;
+ bool hasBookmark() const;
+ bool hasObjectRect( double x, double y ) const;
+ bool hasHighlights( int s_id = -1 ) const;
+ //bool hasAnnotation( double x, double y ) const;
+ bool hasTransition() const;
+
+ NormalizedRect * findText( const QString & text, bool keepCase, NormalizedRect * last = 0 ) const;
+ const QString getText( const NormalizedRect & rect ) const;
+ const ObjectRect * hasObject( ObjectRect::ObjectType type, double x, double y ) const;
+ //const Annotation * getAnnotation( double x, double y ) const;
+ const KPDFPageTransition * getTransition() const;
+
+ // operations: set/delete contents (by KPDFDocument)
+ void setPixmap( int p_id, QPixmap * pixmap );
+ void setSearchPage( TextPage * text );
+ void setBookmark( bool state );
+ void setObjectRects( const QValueList< ObjectRect * > rects );
+ void setHighlight( int s_id, NormalizedRect * &r, const QColor & color );
+ //void setAnnotation( Annotation * annotation );
+ void setTransition( KPDFPageTransition * transition );
+ void deletePixmap( int p_id );
+ void deletePixmapsAndRects();
+ void deleteHighlights( int s_id = -1 );
+
+ private:
+ friend class PagePainter;
+ int m_number, m_rotation;
+ float m_width, m_height;
+ bool m_bookmarked;
+
+ QMap< int, QPixmap * > m_pixmaps;
+ TextPage * m_text;
+ QValueList< ObjectRect * > m_rects;
+ QValueList< HighlightRect * > m_highlights;
+ //QValueList< Annotation * > m_annotations;
+ KPDFPageTransition * m_transition;
+};
+
+
+/**
+ * Internal Storage: normalized colored highlight owned by id
+ */
+struct HighlightRect : public NormalizedRect
+{
+ // searchID of the highlight owner
+ int s_id;
+ // color of the highlight
+ QColor color;
+};
+
+#endif
diff --git a/kpdf/core/pagetransition.cpp b/kpdf/core/pagetransition.cpp
new file mode 100644
index 00000000..cdf04a7f
--- /dev/null
+++ b/kpdf/core/pagetransition.cpp
@@ -0,0 +1,28 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Tobias Koenig <tokoe@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. *
+ ***************************************************************************/
+
+// local includes
+#include "pagetransition.h"
+
+/** class KPDFPageTransition **/
+
+KPDFPageTransition::KPDFPageTransition( Type type )
+ : m_type( type ),
+ m_duration( 1 ),
+ m_alignment( Horizontal ),
+ m_direction( Inward ),
+ m_angle( 0 ),
+ m_scale( 1.0 ),
+ m_rectangular( false )
+{
+}
+
+KPDFPageTransition::~KPDFPageTransition()
+{
+}
diff --git a/kpdf/core/pagetransition.h b/kpdf/core/pagetransition.h
new file mode 100644
index 00000000..70792355
--- /dev/null
+++ b/kpdf/core/pagetransition.h
@@ -0,0 +1,86 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Tobias Koenig <tokoe@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. *
+ ***************************************************************************/
+
+#ifndef _KPDF_PAGE_TRANSITION_H_
+#define _KPDF_PAGE_TRANSITION_H_
+
+/**
+ * @short Information object for the transition effect of a page.
+ */
+class KPDFPageTransition
+{
+ public:
+ enum Type {
+ Replace,
+ Split,
+ Blinds,
+ Box,
+ Wipe,
+ Dissolve,
+ Glitter,
+ Fly,
+ Push,
+ Cover,
+ Uncover,
+ Fade
+ };
+
+ enum Alignment {
+ Horizontal,
+ Vertical
+ };
+
+ enum Direction {
+ Inward,
+ Outward
+ };
+
+ KPDFPageTransition( Type type = Replace );
+ ~KPDFPageTransition();
+
+ // Get type of the transition.
+ inline Type type() const { return m_type; }
+
+ // Get duration of the transition in seconds.
+ inline int duration() const { return m_duration; }
+
+ // Get dimension in which the transition effect occurs.
+ inline Alignment alignment() const { return m_alignment; }
+
+ // Get direction of motion of the transition effect.
+ inline Direction direction() const { return m_direction; }
+
+ // Get direction in which the transition effect moves.
+ inline int angle() const { return m_angle; }
+
+ // Get starting or ending scale. (Fly only)
+ inline double scale() const { return m_scale; }
+
+ // Returns true if the area to be flown is rectangular and opaque. (Fly only)
+ inline bool isRectangular() const { return m_rectangular; }
+
+ inline void setType( Type type ) { m_type = type; }
+ inline void setDuration( int duration ) { m_duration = duration; }
+ inline void setAlignment( Alignment alignment ) { m_alignment = alignment; }
+ inline void setDirection( Direction direction ) { m_direction = direction; }
+ inline void setAngle( int angle ) { m_angle = angle; }
+ inline void setScale( double scale ) { m_scale = scale; }
+ inline void setIsRectangular( bool rectangular ) { m_rectangular = rectangular; }
+
+ private:
+ Type m_type;
+ int m_duration;
+ Alignment m_alignment;
+ Direction m_direction;
+ int m_angle;
+ double m_scale;
+ bool m_rectangular;
+};
+
+#endif
diff --git a/kpdf/dcop.h b/kpdf/dcop.h
new file mode 100644
index 00000000..61a916d8
--- /dev/null
+++ b/kpdf/dcop.h
@@ -0,0 +1,35 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Albert Astals Cid <tsdgeos@terra.es> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef MY_INTERFACE_H
+#define MY_INTERFACE_H
+
+#include <dcopobject.h>
+#include <kurl.h>
+
+class kpdf_dcop : virtual public DCOPObject
+{
+K_DCOP
+ k_dcop:
+ virtual ASYNC goToPage(uint page) = 0;
+ virtual ASYNC openDocument(KURL doc) = 0;
+ virtual uint pages() = 0;
+ virtual uint currentPage() = 0;
+ virtual KURL currentDocument() = 0;
+ virtual void slotPreferences() = 0;
+ virtual void slotFind() = 0;
+ virtual void slotPrintPreview() = 0;
+ virtual void slotPreviousPage() = 0;
+ virtual void slotNextPage() = 0;
+ virtual void slotGotoFirst() = 0;
+ virtual void slotGotoLast() = 0;
+ virtual void slotTogglePresentation() = 0;
+};
+
+#endif
diff --git a/kpdf/error.cpp b/kpdf/error.cpp
new file mode 100644
index 00000000..028fe7e3
--- /dev/null
+++ b/kpdf/error.cpp
@@ -0,0 +1,44 @@
+/***************************************************************************
+ * Copyright (C) 1996-2003 Glyph & Cog, LLC *
+ * Copyright (C) 2004 by Albert Astals Cid <tsdgeos@terra.es> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include "xpdf/GlobalParams.h"
+#include "xpdf/Error.h"
+
+#include <qstring.h>
+
+#include <kdebug.h>
+
+void CDECL error(int pos, char *msg, ...) {
+ va_list args;
+ QString emsg, tmsg;
+ char buffer[1024]; // should be big enough
+
+ // NB: this can be called before the globalParams object is created
+ if (globalParams && globalParams->getErrQuiet()) {
+ return;
+ }
+ if (pos >= 0) {
+ emsg = QString("Error (%1): ").arg(pos);
+ } else {
+ emsg = "Error: ";
+ }
+ va_start(args, msg);
+ vsprintf(buffer, msg, args);
+ va_end(args);
+ emsg += buffer;
+ kdDebug() << emsg << endl;
+}
diff --git a/kpdf/hi128-app-kpdf.png b/kpdf/hi128-app-kpdf.png
new file mode 100644
index 00000000..c89f9472
--- /dev/null
+++ b/kpdf/hi128-app-kpdf.png
Binary files differ
diff --git a/kpdf/hi16-app-kpdf.png b/kpdf/hi16-app-kpdf.png
new file mode 100644
index 00000000..b4616cbd
--- /dev/null
+++ b/kpdf/hi16-app-kpdf.png
Binary files differ
diff --git a/kpdf/hi22-app-kpdf.png b/kpdf/hi22-app-kpdf.png
new file mode 100644
index 00000000..12d9aaad
--- /dev/null
+++ b/kpdf/hi22-app-kpdf.png
Binary files differ
diff --git a/kpdf/hi32-app-kpdf.png b/kpdf/hi32-app-kpdf.png
new file mode 100644
index 00000000..2f721dfb
--- /dev/null
+++ b/kpdf/hi32-app-kpdf.png
Binary files differ
diff --git a/kpdf/hi48-app-kpdf.png b/kpdf/hi48-app-kpdf.png
new file mode 100644
index 00000000..086fad9c
--- /dev/null
+++ b/kpdf/hi48-app-kpdf.png
Binary files differ
diff --git a/kpdf/hi64-app-kpdf.png b/kpdf/hi64-app-kpdf.png
new file mode 100644
index 00000000..46fac6ac
--- /dev/null
+++ b/kpdf/hi64-app-kpdf.png
Binary files differ
diff --git a/kpdf/hisc-app-kpdf.svgz b/kpdf/hisc-app-kpdf.svgz
new file mode 100644
index 00000000..259103a2
--- /dev/null
+++ b/kpdf/hisc-app-kpdf.svgz
Binary files differ
diff --git a/kpdf/kpdf_part.desktop b/kpdf/kpdf_part.desktop
new file mode 100644
index 00000000..ec55d0dd
--- /dev/null
+++ b/kpdf/kpdf_part.desktop
@@ -0,0 +1,11 @@
+[Desktop Entry]
+Icon=kpdf
+Name=KPDF
+Name[ar]=برنامج KPDF
+Name[hi]=के-पीडीएफ
+Name[zh_TW]=KPDF 檢視器
+MimeType=application/pdf
+InitialPreference=7
+ServiceTypes=KParts/ReadOnlyPart
+X-KDE-Library=libkpdfpart
+Type=Service
diff --git a/kpdf/part.cpp b/kpdf/part.cpp
new file mode 100644
index 00000000..69ad7f00
--- /dev/null
+++ b/kpdf/part.cpp
@@ -0,0 +1,1100 @@
+/***************************************************************************
+ * Copyright (C) 2002 by Wilco Greven <greven@kde.org> *
+ * Copyright (C) 2002 by Chris Cheney <ccheney@cheney.cx> *
+ * Copyright (C) 2002 by Malcolm Hunter <malcolm.hunter@gmx.co.uk> *
+ * Copyright (C) 2003-2004 by Christophe Devriese *
+ * <Christophe.Devriese@student.kuleuven.ac.be> *
+ * Copyright (C) 2003 by Daniel Molkentin <molkentin@kde.org> *
+ * Copyright (C) 2003 by Andy Goossens <andygoossens@telenet.be> *
+ * Copyright (C) 2003 by Dirk Mueller <mueller@kde.org> *
+ * Copyright (C) 2003 by Laurent Montel <montel@kde.org> *
+ * Copyright (C) 2004 by Dominique Devriese <devriese@kde.org> *
+ * Copyright (C) 2004 by Christoph Cullmann <crossfire@babylon2k.de> *
+ * Copyright (C) 2004 by Henrique Pinto <stampede@coltec.ufmg.br> *
+ * Copyright (C) 2004 by Waldo Bastian <bastian@kde.org> *
+ * Copyright (C) 2004-2006 by Albert Astals Cid <tsdgeos@terra.es> *
+ * Copyright (C) 2004 by Antti Markus <antti.markus@starman.ee> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+// qt/kde includes
+#include <qcheckbox.h>
+#include <qsplitter.h>
+#include <qpainter.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qvbox.h>
+#include <qtoolbox.h>
+#include <qtooltip.h>
+#include <qpushbutton.h>
+#include <qwhatsthis.h>
+#include <dcopobject.h>
+#include <dcopclient.h>
+#include <kapplication.h>
+#include <kaction.h>
+#include <kdirwatch.h>
+#include <kinstance.h>
+#include <kprinter.h>
+#include <kdeprint/kprintdialogpage.h>
+#include <kstdaction.h>
+#include <kdeversion.h>
+#include <kparts/genericfactory.h>
+#include <kurldrag.h>
+#include <kfiledialog.h>
+#include <kmessagebox.h>
+#include <kfinddialog.h>
+#include <knuminput.h>
+#include <kiconloader.h>
+#include <kio/netaccess.h>
+#include <kio/job.h>
+#include <kpopupmenu.h>
+#include <kprocess.h>
+#include <kstandarddirs.h>
+#include <ktempfile.h>
+#include <ktrader.h>
+#include <kxmlguiclient.h>
+#include <kxmlguifactory.h>
+
+// local includes
+#include "xpdf/GlobalParams.h"
+#include "part.h"
+#include "ui/pageview.h"
+#include "ui/thumbnaillist.h"
+#include "ui/searchwidget.h"
+#include "ui/toc.h"
+#include "ui/minibar.h"
+#include "ui/propertiesdialog.h"
+#include "ui/presentationwidget.h"
+#include "conf/preferencesdialog.h"
+#include "conf/settings.h"
+#include "core/document.h"
+#include "core/page.h"
+
+class PDFOptionsPage : public KPrintDialogPage
+{
+ public:
+ PDFOptionsPage()
+ {
+ setTitle( i18n( "PDF Options" ) );
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ m_forceRaster = new QCheckBox(i18n("Force rasterization"), this);
+ QToolTip::add(m_forceRaster, i18n("Rasterize into an image before printing"));
+ QWhatsThis::add(m_forceRaster, i18n("Forces the rasterization of each page into an image before printing it. This usually gives somewhat worse results, but is useful when printing documents that appear to print incorrectly."));
+ layout->addWidget(m_forceRaster);
+ layout->addStretch(1);
+ }
+
+ void getOptions( QMap<QString,QString>& opts, bool incldef = false )
+ {
+ Q_UNUSED(incldef);
+ opts[ "kde-kpdf-forceRaster" ] = QString::number( m_forceRaster->isChecked() );
+ }
+
+ void setOptions( const QMap<QString,QString>& opts )
+ {
+ m_forceRaster->setChecked( opts[ "kde-kpdf-forceRaster" ].toInt() );
+ }
+
+ private:
+ QCheckBox *m_forceRaster;
+};
+
+// definition of searchID for this class
+#define PART_SEARCH_ID 1
+
+typedef KParts::GenericFactory<KPDF::Part> KPDFPartFactory;
+K_EXPORT_COMPONENT_FACTORY(libkpdfpart, KPDFPartFactory)
+
+using namespace KPDF;
+
+unsigned int Part::m_count = 0;
+
+Part::Part(QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name,
+ const QStringList & /*args*/ )
+ : DCOPObject("kpdf"), KParts::ReadOnlyPart(parent, name), m_showMenuBarAction(0), m_showFullScreenAction(0),
+ m_actionsSearched(false), m_searchStarted(false)
+{
+ // connect the started signal to tell the job the mimetypes we like
+ connect(this, SIGNAL(started(KIO::Job *)), this, SLOT(setMimeTypes(KIO::Job *)));
+
+ // connect the completed signal so we can put the window caption when loading remote files
+ connect(this, SIGNAL(completed()), this, SLOT(emitWindowCaption()));
+ connect(this, SIGNAL(canceled(const QString &)), this, SLOT(emitWindowCaption()));
+
+ // load catalog for translation
+ KGlobal::locale()->insertCatalogue("kpdf");
+
+ // create browser extension (for printing when embedded into browser)
+ m_bExtension = new BrowserExtension(this);
+
+ // xpdf 'extern' global class (m_count is a static instance counter)
+ //if ( m_count ) TODO check if we need to insert these lines..
+ // delete globalParams;
+ globalParams = new GlobalParams("");
+ globalParams->setupBaseFonts(NULL);
+ m_count++;
+
+ // we need an instance
+ setInstance(KPDFPartFactory::instance());
+
+ // build the document
+ m_document = new KPDFDocument(widget());
+ connect( m_document, SIGNAL( linkFind() ), this, SLOT( slotFind() ) );
+ connect( m_document, SIGNAL( linkGoToPage() ), this, SLOT( slotGoToPage() ) );
+ connect( m_document, SIGNAL( linkPresentation() ), this, SLOT( slotShowPresentation() ) );
+ connect( m_document, SIGNAL( linkEndPresentation() ), this, SLOT( slotHidePresentation() ) );
+ connect( m_document, SIGNAL( openURL(const KURL &) ), this, SLOT( openURLFromDocument(const KURL &) ) );
+ connect( m_document, SIGNAL( close() ), this, SLOT( close() ) );
+
+ if (parent && parent->metaObject()->slotNames(true).contains("slotQuit()"))
+ connect( m_document, SIGNAL( quit() ), parent, SLOT( slotQuit() ) );
+ else
+ connect( m_document, SIGNAL( quit() ), this, SLOT( cannotQuit() ) );
+
+ // widgets: ^searchbar (toolbar containing label and SearchWidget)
+// m_searchToolBar = new KToolBar( parentWidget, "searchBar" );
+// m_searchToolBar->boxLayout()->setSpacing( KDialog::spacingHint() );
+// QLabel * sLabel = new QLabel( i18n( "&Search:" ), m_searchToolBar, "kde toolbar widget" );
+// m_searchWidget = new SearchWidget( m_searchToolBar, m_document );
+// sLabel->setBuddy( m_searchWidget );
+// m_searchToolBar->setStretchableWidget( m_searchWidget );
+
+ // widgets: [] splitter []
+ m_splitter = new QSplitter( parentWidget, widgetName );
+ m_splitter->setOpaqueResize( true );
+ setWidget( m_splitter );
+
+ m_showLeftPanel = new KToggleAction( i18n( "Show &Navigation Panel"), "show_side_panel", 0, this, SLOT( slotShowLeftPanel() ), actionCollection(), "show_leftpanel" );
+ m_showLeftPanel->setCheckedState( i18n( "Hide &Navigation Panel") );
+ m_showLeftPanel->setShortcut( "CTRL+L" );
+ m_showLeftPanel->setChecked( KpdfSettings::showLeftPanel() );
+
+ // widgets: [left panel] | []
+ m_leftPanel = new QWidget( m_splitter );
+ m_leftPanel->setMinimumWidth( 90 );
+ m_leftPanel->setMaximumWidth( 300 );
+ QVBoxLayout * leftPanelLayout = new QVBoxLayout( m_leftPanel );
+
+ // widgets: [left toolbox/..] | []
+ m_toolBox = new QToolBox( m_leftPanel );
+ leftPanelLayout->addWidget( m_toolBox );
+
+ int index;
+ // [left toolbox: Table of Contents] | []
+ // dummy wrapper with layout to enable horizontal scroll bars (bug: 147233)
+ QWidget *tocWrapper = new QWidget(m_toolBox);
+ QVBoxLayout *tocWrapperLayout = new QVBoxLayout(tocWrapper);
+ m_tocFrame = new TOC( tocWrapper, m_document );
+ tocWrapperLayout->add(m_tocFrame);
+ connect(m_tocFrame, SIGNAL(hasTOC(bool)), this, SLOT(enableTOC(bool)));
+ index = m_toolBox->addItem( tocWrapper, QIconSet(SmallIcon("text_left")), i18n("Contents") );
+ m_toolBox->setItemToolTip(index, i18n("Contents"));
+ enableTOC( false );
+
+ // [left toolbox: Thumbnails and Bookmarks] | []
+ QVBox * thumbsBox = new ThumbnailsBox( m_toolBox );
+ m_searchWidget = new SearchWidget( thumbsBox, m_document );
+ m_thumbnailList = new ThumbnailList( thumbsBox, m_document );
+// ThumbnailController * m_tc = new ThumbnailController( thumbsBox, m_thumbnailList );
+ connect( m_thumbnailList, SIGNAL( urlDropped( const KURL& ) ), SLOT( openURLFromDocument( const KURL & )) );
+ connect( m_thumbnailList, SIGNAL( rightClick(const KPDFPage *, const QPoint &) ), this, SLOT( slotShowMenu(const KPDFPage *, const QPoint &) ) );
+ // shrink the bottom controller toolbar (too hackish..)
+ thumbsBox->setStretchFactor( m_searchWidget, 100 );
+ thumbsBox->setStretchFactor( m_thumbnailList, 100 );
+// thumbsBox->setStretchFactor( m_tc, 1 );
+ index = m_toolBox->addItem( thumbsBox, QIconSet(SmallIcon("thumbnail")), i18n("Thumbnails") );
+ m_toolBox->setItemToolTip(index, i18n("Thumbnails"));
+ m_toolBox->setCurrentItem( thumbsBox );
+
+ slotShowLeftPanel();
+
+/* // [left toolbox: Annotations] | []
+ QFrame * editFrame = new QFrame( m_toolBox );
+ int iIdx = m_toolBox->addItem( editFrame, QIconSet(SmallIcon("pencil")), i18n("Annotations") );
+ m_toolBox->setItemEnabled( iIdx, false );*/
+
+ // widgets: [../miniBarContainer] | []
+ QWidget * miniBarContainer = new QWidget( m_leftPanel );
+ leftPanelLayout->addWidget( miniBarContainer );
+ QVBoxLayout * miniBarLayout = new QVBoxLayout( miniBarContainer );
+ // widgets: [../[spacer/..]] | []
+ QWidget * miniSpacer = new QWidget( miniBarContainer );
+ miniSpacer->setFixedHeight( 6 );
+ miniBarLayout->addWidget( miniSpacer );
+ // widgets: [../[../MiniBar]] | []
+ m_miniBar = new MiniBar( miniBarContainer, m_document );
+ miniBarLayout->addWidget( m_miniBar );
+
+ // widgets: [] | [right 'pageView']
+ m_pageView = new PageView( m_splitter, m_document );
+ m_pageView->setFocus(); //usability setting
+ m_splitter->setFocusProxy(m_pageView);
+ connect( m_pageView, SIGNAL( urlDropped( const KURL& ) ), SLOT( openURLFromDocument( const KURL & )));
+ connect( m_pageView, SIGNAL( rightClick(const KPDFPage *, const QPoint &) ), this, SLOT( slotShowMenu(const KPDFPage *, const QPoint &) ) );
+
+ // add document observers
+ m_document->addObserver( this );
+ m_document->addObserver( m_thumbnailList );
+ m_document->addObserver( m_pageView );
+ m_document->addObserver( m_tocFrame );
+ m_document->addObserver( m_miniBar );
+
+ // ACTIONS
+ KActionCollection * ac = actionCollection();
+
+ // Page Traversal actions
+ m_gotoPage = KStdAction::gotoPage( this, SLOT( slotGoToPage() ), ac, "goto_page" );
+ m_gotoPage->setShortcut( "CTRL+G" );
+ // dirty way to activate gotopage when pressing miniBar's button
+ connect( m_miniBar, SIGNAL( gotoPage() ), m_gotoPage, SLOT( activate() ) );
+
+ m_prevPage = KStdAction::prior(this, SLOT(slotPreviousPage()), ac, "previous_page");
+ m_prevPage->setWhatsThis( i18n( "Moves to the previous page of the document" ) );
+ m_prevPage->setShortcut( 0 );
+ // dirty way to activate prev page when pressing miniBar's button
+ connect( m_miniBar, SIGNAL( prevPage() ), m_prevPage, SLOT( activate() ) );
+
+ m_nextPage = KStdAction::next(this, SLOT(slotNextPage()), ac, "next_page" );
+ m_nextPage->setWhatsThis( i18n( "Moves to the next page of the document" ) );
+ m_nextPage->setShortcut( 0 );
+ // dirty way to activate next page when pressing miniBar's button
+ connect( m_miniBar, SIGNAL( nextPage() ), m_nextPage, SLOT( activate() ) );
+
+ m_firstPage = KStdAction::firstPage( this, SLOT( slotGotoFirst() ), ac, "first_page" );
+ m_firstPage->setWhatsThis( i18n( "Moves to the first page of the document" ) );
+
+ m_lastPage = KStdAction::lastPage( this, SLOT( slotGotoLast() ), ac, "last_page" );
+ m_lastPage->setWhatsThis( i18n( "Moves to the last page of the document" ) );
+
+ m_historyBack = KStdAction::back( this, SLOT( slotHistoryBack() ), ac, "history_back" );
+ m_historyBack->setWhatsThis( i18n( "Go to the place you were before" ) );
+
+ m_historyNext = KStdAction::forward( this, SLOT( slotHistoryNext() ), ac, "history_forward" );
+ m_historyNext->setWhatsThis( i18n( "Go to the place you were after" ) );
+
+ // Find and other actions
+ m_find = KStdAction::find( this, SLOT( slotFind() ), ac, "find" );
+ m_find->setEnabled( false );
+
+ m_findNext = KStdAction::findNext( this, SLOT( slotFindNext() ), ac, "find_next" );
+ m_findNext->setEnabled( false );
+
+ m_saveAs = KStdAction::saveAs( this, SLOT( slotSaveFileAs() ), ac, "save" );
+ m_saveAs->setEnabled( false );
+ KAction * prefs = KStdAction::preferences( this, SLOT( slotPreferences() ), ac, "preferences" );
+ prefs->setText( i18n( "Configure KPDF..." ) );
+ m_printPreview = KStdAction::printPreview( this, SLOT( slotPrintPreview() ), ac );
+ m_printPreview->setEnabled( false );
+
+ m_showProperties = new KAction(i18n("&Properties"), "info", 0, this, SLOT(slotShowProperties()), ac, "properties");
+ m_showProperties->setEnabled( false );
+
+ m_showPresentation = new KAction( i18n("P&resentation"), "kpresenter_kpr", "Ctrl+Shift+P", this, SLOT(slotShowPresentation()), ac, "presentation");
+ m_showPresentation->setEnabled( false );
+
+ // attach the actions of the children widgets too
+ m_pageView->setupActions( ac );
+
+ // apply configuration (both internal settings and GUI configured items)
+ QValueList<int> splitterSizes = KpdfSettings::splitterSizes();
+ if ( !splitterSizes.count() )
+ {
+ // the first time use 1/10 for the panel and 9/10 for the pageView
+ splitterSizes.push_back( 50 );
+ splitterSizes.push_back( 500 );
+ }
+ m_splitter->setSizes( splitterSizes );
+ // get notified about splitter size changes (HACK that will be removed
+ // by connecting to Qt4::QSplitter's sliderMoved())
+ m_pageView->installEventFilter( this );
+ m_watcher = new KDirWatch( this );
+ connect( m_watcher, SIGNAL( dirty( const QString& ) ), this, SLOT( slotFileDirty( const QString& ) ) );
+ m_dirtyHandler = new QTimer( this );
+ connect( m_dirtyHandler, SIGNAL( timeout() ),this, SLOT( slotDoFileDirty() ) );
+ m_saveSplitterSizeTimer = new QTimer( this );
+ connect( m_saveSplitterSizeTimer, SIGNAL( timeout() ),this, SLOT( saveSplitterSize() ) );
+
+ slotNewConfig();
+
+ // [SPEECH] check for KTTSD presence and usability
+ KTrader::OfferList offers = KTrader::self()->query("DCOP/Text-to-Speech", "Name == 'KTTSD'");
+ KpdfSettings::setUseKTTSD( (offers.count() > 0) );
+ KpdfSettings::writeConfig();
+
+ // set our XML-UI resource file
+ setXMLFile("part.rc");
+ updateViewActions();
+}
+
+Part::~Part()
+{
+ delete m_tocFrame;
+ delete m_pageView;
+ delete m_thumbnailList;
+ delete m_miniBar;
+
+ delete m_document;
+ if ( --m_count == 0 )
+ delete globalParams;
+}
+
+void Part::notifyViewportChanged( bool /*smoothMove*/ )
+{
+ // update actions if the page is changed
+ static int lastPage = -1;
+ int viewportPage = m_document->viewport().pageNumber;
+ if ( viewportPage != lastPage )
+ {
+ updateViewActions();
+ lastPage = viewportPage;
+ }
+}
+
+void Part::goToPage(uint i)
+{
+ if ( i <= m_document->pages() )
+ m_document->setViewportPage( i - 1 );
+}
+
+void Part::openDocument(KURL doc)
+{
+ openURL(doc);
+}
+
+uint Part::pages()
+{
+ return m_document->pages();
+}
+
+uint Part::currentPage()
+{
+ if ( m_document->pages() == 0 ) return 0;
+ else return m_document->currentPage()+1;
+}
+
+KURL Part::currentDocument()
+{
+ return m_document->currentDocument();
+}
+
+//this don't go anywhere but is required by genericfactory.h
+KAboutData* Part::createAboutData()
+{
+ // the non-i18n name here must be the same as the directory in
+ // which the part's rc file is installed ('partrcdir' in the
+ // Makefile)
+ KAboutData* aboutData = new KAboutData("kpdfpart", I18N_NOOP("KPDF::Part"), "0.1");
+ aboutData->addAuthor("Wilco Greven", 0, "greven@kde.org");
+ return aboutData;
+}
+
+bool Part::openFile()
+{
+ KMimeType::Ptr mime;
+ if ( m_bExtension->urlArgs().serviceType.isEmpty() )
+ {
+ if (!m_jobMime.isEmpty())
+ {
+ mime = KMimeType::mimeType(m_jobMime);
+ if ( mime->is( "application/octet-stream" ) )
+ {
+ mime = KMimeType::findByPath( m_file );
+ }
+ }
+ else
+ {
+ mime = KMimeType::findByPath( m_file );
+ }
+ }
+ else
+ {
+ mime = KMimeType::mimeType( m_bExtension->urlArgs().serviceType );
+ }
+ if ( (*mime).is( "application/postscript" ) )
+ {
+ QString app = KStandardDirs::findExe( "ps2pdf" );
+ if ( !app.isNull() )
+ {
+ if ( QFile::exists(m_file) )
+ {
+ KTempFile tf( QString::null, ".pdf" );
+ if ( tf.status() == 0 )
+ {
+ tf.close();
+ m_temporaryLocalFile = tf.name();
+
+ KProcess *p = new KProcess;
+ *p << app;
+ *p << m_file << m_temporaryLocalFile;
+ m_pageView->showText(i18n("Converting from ps to pdf..."), 0);
+ connect(p, SIGNAL(processExited(KProcess *)), this, SLOT(psTransformEnded()));
+ p -> start();
+ return true;
+ }
+ else return false;
+ }
+ else return false;
+ }
+ else
+ {
+ KMessageBox::error(widget(), i18n("You do not have ps2pdf installed, so kpdf cannot open postscript files."));
+ return false;
+ }
+ }
+
+ m_temporaryLocalFile = QString::null;
+
+ bool ok = m_document->openDocument( m_file, url(), mime );
+
+ // update one-time actions
+ m_find->setEnabled( ok && m_document-> supportsSearching());
+ m_findNext->setEnabled( ok && m_document-> supportsSearching());
+ m_saveAs->setEnabled( ok );
+ m_printPreview->setEnabled( ok );
+ m_showProperties->setEnabled( ok );
+ m_showPresentation->setEnabled( ok );
+
+ // update viewing actions
+ updateViewActions();
+
+ if ( !ok )
+ {
+ // if can't open document, update windows so they display blank contents
+ m_pageView->updateContents();
+ m_thumbnailList->updateContents();
+ return false;
+ }
+
+ // set the file to the fileWatcher
+ if ( !m_watcher->contains(m_file) )
+ m_watcher->addFile(m_file);
+
+ // if the 'OpenTOC' flag is set, open the TOC
+ if ( m_document->getMetaData( "OpenTOC" ) == "yes" && m_toolBox->isItemEnabled( 0 ) )
+ {
+ m_toolBox->setCurrentIndex( 0 );
+ }
+ // if the 'StartFullScreen' flag is set, start presentation
+ if ( m_document->getMetaData( "StartFullScreen" ) == "yes" )
+ {
+ KMessageBox::information(m_presentationWidget, i18n("The document is going to be launched on presentation mode because the file requested it."), QString::null, "autoPresentationWarning");
+ slotShowPresentation();
+ }
+
+ return true;
+}
+
+void Part::openURLFromDocument(const KURL &url)
+{
+ m_bExtension->openURLNotify();
+ m_bExtension->setLocationBarURL(url.prettyURL());
+ openURL(url);
+}
+
+bool Part::openURL(const KURL &url)
+{
+ // note: this can be the right place to check the file for gz or bz2 extension
+ // if it matches then: download it (if not local) extract to a temp file using
+ // KTar and proceed with the URL of the temporary file
+
+ m_jobMime = QString::null;
+
+ // this calls the above 'openURL' method
+ bool b = KParts::ReadOnlyPart::openURL(url);
+
+ // these setWindowCaption calls only work for local files
+ if ( !b )
+ {
+ KMessageBox::error( widget(), i18n("Could not open %1").arg( url.prettyURL() ) );
+ emit setWindowCaption("");
+ }
+ else
+ {
+ m_viewportDirty.pageNumber = -1;
+ emit setWindowCaption(url.filename());
+ }
+ emit enablePrintAction(b);
+ return b;
+}
+
+void Part::setMimeTypes(KIO::Job *job)
+{
+ if (job)
+ {
+ job->addMetaData("accept", "application/pdf, */*;q=0.5");
+ connect(job, SIGNAL(mimetype(KIO::Job*,const QString&)), this, SLOT(readMimeType(KIO::Job*,const QString&)));
+ }
+}
+
+void Part::readMimeType(KIO::Job *, const QString &mime)
+{
+ m_jobMime = mime;
+}
+
+void Part::emitWindowCaption()
+{
+ // these setWindowCaption call only works for remote files
+ if (m_document->isOpened()) emit setWindowCaption(url().filename());
+ else emit setWindowCaption("");
+}
+
+bool Part::closeURL()
+{
+ if (!m_temporaryLocalFile.isNull())
+ {
+ QFile::remove( m_temporaryLocalFile );
+ m_temporaryLocalFile = QString::null;
+ }
+
+ slotHidePresentation();
+ m_find->setEnabled( false );
+ m_findNext->setEnabled( false );
+ m_saveAs->setEnabled( false );
+ m_printPreview->setEnabled( false );
+ m_showProperties->setEnabled( false );
+ m_showPresentation->setEnabled( false );
+ emit setWindowCaption("");
+ emit enablePrintAction(false);
+ m_searchStarted = false;
+ if (!m_file.isEmpty()) m_watcher->removeFile(m_file);
+ m_document->closeDocument();
+ updateViewActions();
+ m_searchWidget->clearText();
+ return KParts::ReadOnlyPart::closeURL();
+}
+
+bool Part::eventFilter( QObject * watched, QEvent * e )
+{
+ // if pageView has been resized, save splitter sizes
+ if ( watched == m_pageView && e->type() == QEvent::Resize )
+ m_saveSplitterSizeTimer->start(500, true);
+
+ // only intercept events, don't block them
+ return false;
+}
+
+void Part::slotShowLeftPanel()
+{
+ bool showLeft = m_showLeftPanel->isChecked();
+ KpdfSettings::setShowLeftPanel(showLeft);
+ KpdfSettings::writeConfig();
+ // show/hide left qtoolbox
+ m_leftPanel->setShown( showLeft );
+ // this needs to be hidden explicitly to disable thumbnails gen
+ m_thumbnailList->setShown( showLeft );
+}
+
+void Part::slotFileDirty( const QString& fileName )
+{
+ // The beauty of this is that each start cancels the previous one.
+ // This means that timeout() is only fired when there have
+ // no changes to the file for the last 750 milisecs.
+ // This is supposed to ensure that we don't update on every other byte
+ // that gets written to the file.
+ if ( fileName == m_file )
+ {
+ m_dirtyHandler->start( 750, true );
+ }
+}
+
+void Part::slotDoFileDirty()
+{
+ if (m_viewportDirty.pageNumber == -1)
+ {
+ m_viewportDirty = m_document->viewport();
+ m_dirtyToolboxIndex = m_toolBox->currentIndex();
+ m_wasPresentationOpen = ((PresentationWidget*)m_presentationWidget != 0);
+ m_pageView->showText(i18n("Reloading the document..."), 0);
+ }
+
+ if (KParts::ReadOnlyPart::openURL(KURL::fromPathOrURL(m_file)))
+ {
+ if (m_viewportDirty.pageNumber >= (int)m_document->pages()) m_viewportDirty.pageNumber = (int)m_document->pages() - 1;
+ m_document->setViewport(m_viewportDirty);
+ m_viewportDirty.pageNumber = -1;
+ if ( m_toolBox->currentIndex() != m_dirtyToolboxIndex && m_toolBox->isItemEnabled( m_dirtyToolboxIndex ) )
+ {
+ m_toolBox->setCurrentIndex( m_dirtyToolboxIndex );
+ }
+ if (m_wasPresentationOpen) slotShowPresentation();
+ emit enablePrintAction(true);
+ emit setWindowCaption(url().filename());
+ }
+ else
+ {
+ m_watcher->addFile(m_file);
+ m_dirtyHandler->start( 750, true );
+ }
+}
+
+void Part::close()
+{
+ if (parent() && strcmp(parent()->name(), "KPDF::Shell") == 0)
+ {
+ closeURL();
+ }
+ else KMessageBox::information(widget(), i18n("This link points to a close document action that does not work when using the embedded viewer."), QString::null, "warnNoCloseIfNotInKPDF");
+}
+
+void Part::updateViewActions()
+{
+ bool opened = m_document->pages() > 0;
+ if ( opened )
+ {
+ bool atBegin = m_document->currentPage() < 1;
+ bool atEnd = m_document->currentPage() >= (m_document->pages() - 1);
+ m_gotoPage->setEnabled( m_document->pages() > 1 );
+ m_firstPage->setEnabled( !atBegin );
+ m_prevPage->setEnabled( !atBegin );
+ m_lastPage->setEnabled( !atEnd );
+ m_nextPage->setEnabled( !atEnd );
+ m_historyBack->setEnabled( !m_document->historyAtBegin() );
+ m_historyNext->setEnabled( !m_document->historyAtEnd() );
+ }
+ else
+ {
+ m_gotoPage->setEnabled( false );
+ m_firstPage->setEnabled( false );
+ m_lastPage->setEnabled( false );
+ m_prevPage->setEnabled( false );
+ m_nextPage->setEnabled( false );
+ m_historyBack->setEnabled( false );
+ m_historyNext->setEnabled( false );
+ }
+}
+
+void Part::enableTOC(bool enable)
+{
+ m_toolBox->setItemEnabled(0, enable);
+}
+
+void Part::psTransformEnded()
+{
+ QString aux = m_file;
+ m_file = m_temporaryLocalFile;
+ openFile();
+ m_file = aux; // so watching works, we have to watch the ps file not the autogenerated pdf
+ m_watcher->removeFile(m_temporaryLocalFile);
+ if ( !m_watcher->contains(m_file) )
+ m_watcher->addFile(m_file);
+}
+
+void Part::cannotQuit()
+{
+ KMessageBox::information(widget(), i18n("This link points to a quit application action that does not work when using the embedded viewer."), QString::null, "warnNoQuitIfNotInKPDF");
+}
+
+void Part::saveSplitterSize()
+{
+ KpdfSettings::setSplitterSizes( m_splitter->sizes() );
+ KpdfSettings::writeConfig();
+}
+
+//BEGIN go to page dialog
+class KPDFGotoPageDialog : public KDialogBase
+{
+public:
+ KPDFGotoPageDialog(QWidget *p, int current, int max) : KDialogBase(p, 0L, true, i18n("Go to Page"), Ok | Cancel, Ok) {
+ QWidget *w = new QWidget(this);
+ setMainWidget(w);
+
+ QVBoxLayout *topLayout = new QVBoxLayout( w, 0, spacingHint() );
+ e1 = new KIntNumInput(current, w);
+ e1->setRange(1, max);
+ e1->setEditFocus(true);
+
+ QLabel *label = new QLabel( e1,i18n("&Page:"), w );
+ topLayout->addWidget(label);
+ topLayout->addWidget(e1);
+ topLayout->addSpacing(spacingHint()); // A little bit extra space
+ topLayout->addStretch(10);
+ e1->setFocus();
+ }
+
+ int getPage() {
+ return e1->value();
+ }
+
+ protected:
+ KIntNumInput *e1;
+};
+//END go to page dialog
+
+void Part::slotGoToPage()
+{
+ KPDFGotoPageDialog pageDialog( m_pageView, m_document->currentPage() + 1, m_document->pages() );
+ if ( pageDialog.exec() == QDialog::Accepted )
+ m_document->setViewportPage( pageDialog.getPage() - 1 );
+}
+
+void Part::slotPreviousPage()
+{
+ if ( m_document->isOpened() && !(m_document->currentPage() < 1) )
+ m_document->setViewportPage( m_document->currentPage() - 1 );
+}
+
+void Part::slotNextPage()
+{
+ if ( m_document->isOpened() && m_document->currentPage() < (m_document->pages() - 1) )
+ m_document->setViewportPage( m_document->currentPage() + 1 );
+}
+
+void Part::slotGotoFirst()
+{
+ if ( m_document->isOpened() )
+ m_document->setViewportPage( 0 );
+}
+
+void Part::slotGotoLast()
+{
+ if ( m_document->isOpened() )
+ m_document->setViewportPage( m_document->pages() - 1 );
+}
+
+void Part::slotHistoryBack()
+{
+ m_document->setPrevViewport();
+}
+
+void Part::slotHistoryNext()
+{
+ m_document->setNextViewport();
+}
+
+void Part::slotFind()
+{
+ static bool savedCaseSensitive = false;
+ KFindDialog dlg( widget() );
+ dlg.setHasCursor( false );
+ if ( !m_searchHistory.empty() )
+ dlg.setFindHistory( m_searchHistory );
+#if KDE_IS_VERSION(3,3,90)
+ dlg.setSupportsBackwardsFind( false );
+ dlg.setSupportsWholeWordsFind( false );
+ dlg.setSupportsRegularExpressionFind( false );
+#endif
+ if ( savedCaseSensitive )
+ {
+ dlg.setOptions( dlg.options() | KFindDialog::CaseSensitive );
+ }
+ if ( dlg.exec() == QDialog::Accepted )
+ {
+ savedCaseSensitive = dlg.options() & KFindDialog::CaseSensitive;
+ m_searchHistory = dlg.findHistory();
+ m_searchStarted = true;
+ m_document->resetSearch( PART_SEARCH_ID );
+ m_document->searchText( PART_SEARCH_ID, dlg.pattern(), false, savedCaseSensitive,
+ KPDFDocument::NextMatch, true, qRgb( 255, 255, 64 ) );
+ }
+}
+
+void Part::slotFindNext()
+{
+ if (!m_document->continueLastSearch())
+ slotFind();
+}
+
+void Part::slotSaveFileAs()
+{
+ KURL saveURL = KFileDialog::getSaveURL( url().isLocalFile() ? url().url() : url().fileName(), QString::null, widget() );
+ if ( saveURL.isValid() && !saveURL.isEmpty() )
+ {
+ if (saveURL == url())
+ {
+ KMessageBox::information( widget(), i18n("You are trying to overwrite \"%1\" with itself. This is not allowed. Please save it in another location.").arg(saveURL.filename()) );
+ return;
+ }
+ if ( KIO::NetAccess::exists( saveURL, false, widget() ) )
+ {
+ if (KMessageBox::warningContinueCancel( widget(), i18n("A file named \"%1\" already exists. Are you sure you want to overwrite it?").arg(saveURL.filename()), QString::null, i18n("Overwrite")) != KMessageBox::Continue)
+ return;
+ }
+
+ if ( !KIO::NetAccess::file_copy( m_file, saveURL, -1, true ) )
+ KMessageBox::information( 0, i18n("File could not be saved in '%1'. Try to save it to another location.").arg( saveURL.prettyURL() ) );
+ }
+}
+
+void Part::slotPreferences()
+{
+ // an instance the dialog could be already created and could be cached,
+ // in which case you want to display the cached dialog
+ if ( PreferencesDialog::showDialog( "preferences" ) )
+ return;
+
+ // we didn't find an instance of this dialog, so lets create it
+ PreferencesDialog * dialog = new PreferencesDialog( m_pageView, KpdfSettings::self() );
+ // keep us informed when the user changes settings
+ connect( dialog, SIGNAL( settingsChanged() ), this, SLOT( slotNewConfig() ) );
+
+ dialog->show();
+}
+
+void Part::slotNewConfig()
+{
+ // Apply settings here. A good policy is to check wether the setting has
+ // changed before applying changes.
+
+ // Watch File
+ bool watchFile = KpdfSettings::watchFile();
+ if ( watchFile && m_watcher->isStopped() )
+ m_watcher->startScan();
+ if ( !watchFile && !m_watcher->isStopped() )
+ {
+ m_dirtyHandler->stop();
+ m_watcher->stopScan();
+ }
+
+ bool showSearch = KpdfSettings::showSearchBar();
+ if ( m_searchWidget->isShown() != showSearch )
+ m_searchWidget->setShown( showSearch );
+
+ // Main View (pageView)
+ QScrollView::ScrollBarMode scrollBarMode = KpdfSettings::showScrollBars() ?
+ QScrollView::AlwaysOn : QScrollView::AlwaysOff;
+ if ( m_pageView->hScrollBarMode() != scrollBarMode )
+ {
+ m_pageView->setHScrollBarMode( scrollBarMode );
+ m_pageView->setVScrollBarMode( scrollBarMode );
+ }
+
+ // update document settings
+ m_document->reparseConfig();
+
+ // update Main View and ThumbnailList contents
+ // TODO do this only when changing KpdfSettings::renderMode()
+ m_pageView->updateContents();
+ if ( KpdfSettings::showLeftPanel() && m_thumbnailList->isShown() )
+ m_thumbnailList->updateWidgets();
+}
+
+void Part::slotPrintPreview()
+{
+ if (m_document->pages() == 0) return;
+
+ double width, height;
+ int landscape, portrait;
+ KPrinter printer;
+ const KPDFPage *page;
+
+ printer.setMinMax(1, m_document->pages());
+ printer.setPreviewOnly( true );
+
+ // if some pages are landscape and others are not the most common win as kprinter does
+ // not accept a per page setting
+ landscape = 0;
+ portrait = 0;
+ for (uint i = 0; i < m_document->pages(); i++)
+ {
+ page = m_document->page(i);
+ width = page->width();
+ height = page->height();
+ if (page->rotation() == 90 || page->rotation() == 270) qSwap(width, height);
+ if (width > height) landscape++;
+ else portrait++;
+ }
+ if (landscape > portrait) printer.setOption("orientation-requested", "4");
+
+ doPrint(printer);
+}
+
+void Part::slotShowMenu(const KPDFPage *page, const QPoint &point)
+{
+ bool reallyShow = false;
+ if (!m_actionsSearched)
+ {
+ // the quest for options_show_menubar
+ KXMLGUIClient *client;
+ KActionCollection *ac;
+ KActionPtrList::const_iterator it, end, begin;
+ KActionPtrList actions;
+
+ if (factory())
+ {
+ QPtrList<KXMLGUIClient> clients(factory()->clients());
+ QPtrListIterator<KXMLGUIClient> clientsIt( clients );
+ for( ; (!m_showMenuBarAction || !m_showFullScreenAction) && clientsIt.current(); ++clientsIt)
+ {
+ client = clientsIt.current();
+ ac = client->actionCollection();
+ actions = ac->actions();
+ end = actions.end();
+ begin = actions.begin();
+ for ( it = begin; it != end; ++it )
+ {
+ if (QString((*it)->name()) == "options_show_menubar") m_showMenuBarAction = (KToggleAction*)(*it);
+ if (QString((*it)->name()) == "fullscreen") m_showFullScreenAction = (KToggleAction*)(*it);
+ }
+ }
+ }
+ m_actionsSearched = true;
+ }
+
+
+ KPopupMenu *popup = new KPopupMenu( widget(), "rmb popup" );
+ if (page)
+ {
+ popup->insertTitle( i18n( "Page %1" ).arg( page->number() + 1 ) );
+ if ( page->hasBookmark() )
+ popup->insertItem( SmallIcon("bookmark"), i18n("Remove Bookmark"), 1 );
+ else
+ popup->insertItem( SmallIcon("bookmark_add"), i18n("Add Bookmark"), 1 );
+ if ( m_pageView->canFitPageWidth() )
+ popup->insertItem( SmallIcon("viewmagfit"), i18n("Fit Width"), 2 );
+ //popup->insertItem( SmallIcon("pencil"), i18n("Edit"), 3 );
+ //popup->setItemEnabled( 3, false );
+ reallyShow = true;
+ }
+/*
+ //Albert says: I have not ported this as i don't see it does anything
+ if ( d->mouseOnRect ) // and rect->objectType() == ObjectRect::Image ...
+ {
+ m_popup->insertItem( SmallIcon("filesave"), i18n("Save Image..."), 4 );
+ m_popup->setItemEnabled( 4, false );
+}*/
+
+ if ((m_showMenuBarAction && !m_showMenuBarAction->isChecked()) || (m_showFullScreenAction && m_showFullScreenAction->isChecked()))
+ {
+ popup->insertTitle( i18n( "Tools" ) );
+ if (m_showMenuBarAction && !m_showMenuBarAction->isChecked()) m_showMenuBarAction->plug(popup);
+ if (m_showFullScreenAction && m_showFullScreenAction->isChecked()) m_showFullScreenAction->plug(popup);
+ reallyShow = true;
+
+ }
+
+ if (reallyShow)
+ {
+ switch ( popup->exec(point) )
+ {
+ case 1:
+ m_document->toggleBookmark( page->number() );
+ break;
+ case 2:
+ m_pageView->fitPageWidth( page->number() );
+ break;
+ // case 3: // switch to edit mode
+ // break;
+ }
+ }
+ delete popup;
+}
+
+void Part::slotShowProperties()
+{
+ PropertiesDialog *d = new PropertiesDialog(widget(), m_document);
+ d->exec();
+ delete d;
+}
+
+void Part::slotShowPresentation()
+{
+ if ( !m_presentationWidget )
+ {
+ m_presentationWidget = new PresentationWidget( widget(), m_document );
+ m_presentationWidget->setupActions( actionCollection() );
+ }
+}
+
+void Part::slotHidePresentation()
+{
+ if ( m_presentationWidget )
+ delete (PresentationWidget*) m_presentationWidget;
+}
+
+void Part::slotTogglePresentation()
+{
+ if ( m_document->isOpened() )
+ {
+ if ( !m_presentationWidget )
+ {
+ m_presentationWidget = new PresentationWidget( widget(), m_document );
+ m_presentationWidget->setupActions( actionCollection() );
+ }
+ else delete (PresentationWidget*) m_presentationWidget;
+ }
+}
+
+void Part::slotPrint()
+{
+ if (m_document->pages() == 0) return;
+
+ double width, height;
+ int landscape, portrait;
+ KPrinter printer;
+ const KPDFPage *page;
+
+ printer.setPageSelection(KPrinter::ApplicationSide);
+ printer.setMinMax(1, m_document->pages());
+ printer.setCurrentPage(m_document->currentPage()+1);
+
+ // if some pages are landscape and others are not the most common win as kprinter does
+ // not accept a per page setting
+ landscape = 0;
+ portrait = 0;
+ for (uint i = 0; i < m_document->pages(); i++)
+ {
+ page = m_document->page(i);
+ width = page->width();
+ height = page->height();
+ if (page->rotation() == 90 || page->rotation() == 270) qSwap(width, height);
+ if (width > height) landscape++;
+ else portrait++;
+ }
+ if (landscape > portrait) printer.setOrientation(KPrinter::Landscape);
+
+ KPrinter::addDialogPage(new PDFOptionsPage());
+ if (printer.setup(widget())) doPrint( printer );
+}
+
+void Part::doPrint(KPrinter &printer)
+{
+ if (!m_document->isAllowed(KPDFDocument::AllowPrint))
+ {
+ KMessageBox::error(widget(), i18n("Printing this document is not allowed."));
+ return;
+ }
+
+ if (!m_document->print(printer))
+ {
+ KMessageBox::error(widget(), i18n("Could not print the document. Please report to bugs.kde.org"));
+ }
+}
+
+void Part::restoreDocument(KConfig* config)
+{
+ KURL url ( config->readPathEntry( "URL" ) );
+ if ( url.isValid() )
+ {
+ QString viewport = config->readEntry( "Viewport" );
+ if (!viewport.isEmpty()) m_document->setNextDocumentViewport( DocumentViewport( viewport ) );
+ openURL( url );
+ }
+}
+
+void Part::saveDocumentRestoreInfo(KConfig* config)
+{
+ config->writePathEntry( "URL", url().url() );
+ config->writeEntry( "Viewport", m_document->viewport().toString() );
+}
+
+/*
+* BrowserExtension class
+*/
+BrowserExtension::BrowserExtension(Part* parent)
+ : KParts::BrowserExtension( parent, "KPDF::BrowserExtension" )
+{
+ emit enableAction("print", true);
+ setURLDropHandlingEnabled(true);
+}
+
+void BrowserExtension::print()
+{
+ static_cast<Part*>(parent())->slotPrint();
+}
+
+#include "part.moc"
diff --git a/kpdf/part.h b/kpdf/part.h
new file mode 100644
index 00000000..be572c5f
--- /dev/null
+++ b/kpdf/part.h
@@ -0,0 +1,212 @@
+/***************************************************************************
+ * Copyright (C) 2002 by Wilco Greven <greven@kde.org> *
+ * Copyright (C) 2003-2004 by Christophe Devriese *
+ * <Christophe.Devriese@student.kuleuven.ac.be> *
+ * Copyright (C) 2003 by Andy Goossens <andygoossens@telenet.be> *
+ * Copyright (C) 2003 by Laurent Montel <montel@kde.org> *
+ * Copyright (C) 2004 by Dominique Devriese <devriese@kde.org> *
+ * Copyright (C) 2004-2006 by Albert Astals Cid <tsdgeos@terra.es> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef _KPDF_PART_H_
+#define _KPDF_PART_H_
+
+#include <kparts/browserextension.h>
+#include <kparts/part.h>
+#include <qguardedptr.h>
+#include "core/document.h"
+#include "core/observer.h"
+#include "dcop.h"
+
+class QWidget;
+class QSplitter;
+class QToolBox;
+
+class KURL;
+class KAction;
+class KConfig;
+class KDirWatch;
+class KToggleAction;
+class KSelectAction;
+class KAboutData;
+class KPrinter;
+
+class ThumbnailList;
+class ThumbnailController;
+class PageView;
+class PresentationWidget;
+class SearchWidget;
+class TOC;
+class MiniBar;
+
+namespace KPDF {
+
+class BrowserExtension;
+
+/**
+ * This is a "Part". It that does all the real work in a KPart
+ * application.
+ *
+ * @short Main Part
+ * @author Wilco Greven <greven@kde.org>
+ * @version 0.2
+ */
+class Part : public KParts::ReadOnlyPart, public DocumentObserver, virtual public kpdf_dcop
+{
+Q_OBJECT
+
+public:
+ // Default constructor
+ Part(QWidget* parentWidget, const char* widgetName,
+ QObject* parent, const char* name, const QStringList& args);
+
+ // Destructor
+ ~Part();
+
+ // inherited from DocumentObserver
+ uint observerId() const { return PART_ID; }
+ void notifyViewportChanged( bool smoothMove );
+
+ static KAboutData* createAboutData();
+
+ ASYNC goToPage(uint page);
+ ASYNC openDocument(KURL doc);
+ uint pages();
+ uint currentPage();
+ KURL currentDocument();
+
+signals:
+ void enablePrintAction(bool enable);
+
+protected:
+ // reimplemented from KParts::ReadOnlyPart
+ bool openFile();
+ bool openURL(const KURL &url);
+ bool closeURL();
+ // filter that watches for splitter size changes
+ bool eventFilter( QObject * watched, QEvent * e );
+
+protected slots:
+ void openURLFromDocument(const KURL &url);
+ // connected to actions
+ void slotGoToPage();
+ void slotPreviousPage();
+ void slotNextPage();
+ void slotGotoFirst();
+ void slotGotoLast();
+ void slotHistoryBack();
+ void slotHistoryNext();
+ void slotFind();
+ void slotFindNext();
+ void slotSaveFileAs();
+ void slotPreferences();
+ void slotNewConfig();
+ void slotPrintPreview();
+ void slotShowMenu(const KPDFPage *page, const QPoint &point);
+ void slotShowProperties();
+ void slotShowLeftPanel();
+ void slotShowPresentation();
+ void slotHidePresentation();
+ void slotTogglePresentation();
+ void close();
+ // can be connected to widget elements
+ void updateViewActions();
+ void enableTOC(bool enable);
+ void psTransformEnded();
+ void cannotQuit();
+ void saveSplitterSize();
+ void setMimeTypes(KIO::Job *job);
+ void readMimeType(KIO::Job *job, const QString &mime);
+ void emitWindowCaption();
+
+public slots:
+ // connected to Shell action (and browserExtension), not local one
+ void slotPrint();
+ void restoreDocument(KConfig* config);
+ void saveDocumentRestoreInfo(KConfig* config);
+ void slotFileDirty( const QString& );
+ void slotDoFileDirty();
+
+private:
+ void doPrint( KPrinter& printer );
+
+ // the document
+ KPDFDocument * m_document;
+ QString m_temporaryLocalFile;
+
+ // main widgets
+ QSplitter *m_splitter;
+ QWidget *m_leftPanel;
+ QToolBox *m_toolBox;
+ SearchWidget *m_searchWidget;
+ QGuardedPtr<ThumbnailList> m_thumbnailList;
+ QGuardedPtr<PageView> m_pageView;
+ QGuardedPtr<TOC> m_tocFrame;
+ QGuardedPtr<MiniBar> m_miniBar;
+ QGuardedPtr<PresentationWidget> m_presentationWidget;
+
+ // static instances counter
+ static unsigned int m_count;
+
+ // this is a hack because we can not use writeConfig on part destructor
+ // and we don't want to writeconfig every time someone moves the splitter
+ // so we use a QTimer each 500 ms
+ QTimer *m_saveSplitterSizeTimer;
+
+ KDirWatch *m_watcher;
+ QTimer *m_dirtyHandler;
+ DocumentViewport m_viewportDirty;
+ bool m_wasPresentationOpen;
+ int m_dirtyToolboxIndex;
+
+ // Remember the search history
+ QStringList m_searchHistory;
+
+ // mimetype got from the job
+ QString m_jobMime;
+
+ // actions
+ KAction *m_gotoPage;
+ KAction *m_prevPage;
+ KAction *m_nextPage;
+ KAction *m_firstPage;
+ KAction *m_lastPage;
+ KAction *m_historyBack;
+ KAction *m_historyNext;
+ KAction *m_find;
+ KAction *m_findNext;
+ KAction *m_saveAs;
+ KAction *m_printPreview;
+ KAction *m_showProperties;
+ KAction *m_showPresentation;
+ KToggleAction* m_showMenuBarAction;
+ KToggleAction* m_showLeftPanel;
+ KToggleAction* m_showFullScreenAction;
+ bool m_actionsSearched;
+ bool m_searchStarted;
+ BrowserExtension *m_bExtension;
+};
+
+
+class BrowserExtension : public KParts::BrowserExtension
+{
+Q_OBJECT
+
+public:
+ BrowserExtension(Part*);
+
+public slots:
+ // Automatically detected by the host.
+ void print();
+};
+
+}
+
+#endif
+
+// vim:ts=2:sw=2:tw=78:et
diff --git a/kpdf/part.rc b/kpdf/part.rc
new file mode 100644
index 00000000..aa7409c8
--- /dev/null
+++ b/kpdf/part.rc
@@ -0,0 +1,64 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="kpdf_part" version="18">
+<MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="save" group="file_save"/>
+ <Action name="file_print" group="file_print"/>
+ <Action name="file_print_preview" group="file_print"/>
+ <Action name="properties" group="file_print"/>
+ </Menu>
+ <Menu name="edit"><text>&amp;Edit</text>
+ <Action name="find"/>
+ <Action name="find_next"/>
+ </Menu>
+ <Menu name="view"><text>&amp;View</text>
+ <Action name="presentation"/>
+ <Separator/>
+ <Action name="zoom_in"/>
+ <Action name="zoom_out"/>
+ <Action name="zoom_fit_width"/>
+ <Action name="zoom_fit_page"/>
+ <Action name="zoom_fit_rect"/>
+ <Separator/>
+ <Action name="view_continuous"/>
+ <Action name="view_twopages"/>
+ </Menu>
+ <Menu name="go"><text>&amp;Go</text>
+ <Action name="previous_page"/>
+ <Action name="next_page"/>
+ <Separator/>
+ <Action name="first_page"/>
+ <Action name="last_page"/>
+ <Separator/>
+ <Action name="history_back"/>
+ <Action name="history_forward" />
+ <Separator/>
+ <Action name="goto_page"/>
+ </Menu>
+ <Menu name="tools"><text>&amp;Tools</text>
+ <Action name="mouse_drag"/>
+ <Action name="mouse_zoom"/>
+ <Action name="mouse_select"/>
+ </Menu>
+ <Menu name="settings"><text>&amp;Settings</text>
+ <Action name="show_leftpanel" group="show_merge"/>
+ <Action name="preferences"/>
+ </Menu>
+</MenuBar>
+<ToolBar name="mainToolBar"><text>Main Toolbar</text>
+ <Separator/>
+ <Action name="history_back"/>
+ <Action name="history_forward" />
+ <Separator/>
+ <Action name="zoom_in"/>
+ <Action name="zoom_to" />
+ <Action name="zoom_out"/>
+ <Separator/>
+ <Action name="zoom_fit_width"/>
+ <Action name="zoom_fit_page"/>
+ <Separator/>
+ <Action name="mouse_drag"/>
+ <Action name="mouse_zoom"/>
+ <Action name="mouse_select"/>
+</ToolBar>
+</kpartgui>
diff --git a/kpdf/shell/Makefile.am b/kpdf/shell/Makefile.am
new file mode 100644
index 00000000..e8416ef1
--- /dev/null
+++ b/kpdf/shell/Makefile.am
@@ -0,0 +1,15 @@
+INCLUDES = -I$(srcdir)/xpdf -I$(srcdir)/xpdf/goo -I$(top_builddir)/kpdf $(all_includes) $(FREETYPE_CFLAGS)
+
+METASOURCES = AUTO
+
+bin_PROGRAMS = kpdf
+
+kpdf_SOURCES = main.cpp shell.cpp
+kpdf_LDFLAGS = $(KDE_RPATH) $(all_libraries)
+kpdf_LDADD = $(LIB_KPARTS)
+
+EXTRA_DIST = kpdf.desktop
+xdg_apps_DATA = kpdf.desktop
+
+shellrcdir = $(kde_datadir)/kpdf
+shellrc_DATA = shell.rc
diff --git a/kpdf/shell/kpdf.desktop b/kpdf/shell/kpdf.desktop
new file mode 100644
index 00000000..a276611d
--- /dev/null
+++ b/kpdf/shell/kpdf.desktop
@@ -0,0 +1,82 @@
+[Desktop Entry]
+MimeType=application/pdf;
+Terminal=false
+Name=KPDF
+Name[ar]=برنامج KPDF
+Name[hi]=के-पीडीएफ
+Name[zh_TW]=KPDF 檢視器
+GenericName=PDF Viewer
+GenericName[ar]=عارض ملفات PDF
+GenericName[az]=PDF Nümayişçisi
+GenericName[bg]=Преглед на документи PDF
+GenericName[br]=Gweler PDF
+GenericName[bs]=Preglednik PDF dokumenata
+GenericName[ca]=Visualitzador de PDF
+GenericName[cs]=Prohlížeč PDF souborů
+GenericName[cy]=Gwelydd PDF
+GenericName[da]=PDF-fremviser
+GenericName[de]=PDF-Betrachter
+GenericName[el]=Προβολέας PDF
+GenericName[eo]=PDF-rigardilo
+GenericName[es]=Visor de PDF
+GenericName[et]=PDF-failide näitaja
+GenericName[eu]=PDF ikustailua
+GenericName[fa]=مشاهده‌گر PDF
+GenericName[fi]=PDF-näytin
+GenericName[fr]=Afficheur PDF
+GenericName[ga]=Amharcán PDF
+GenericName[gl]=Visor PDF
+GenericName[he]=מציג PDF
+GenericName[hi]=पीडीएफ प्रदर्शक
+GenericName[hr]=Preglednik PDF dokumenata
+GenericName[hu]=PDF-nézegető
+GenericName[id]=Viewer PDF
+GenericName[is]=PDF sjá
+GenericName[it]=Visore PDF
+GenericName[ja]=PDF ビューア
+GenericName[kk]=PDF файлдарын қарау
+GenericName[km]=កម្មវិធី​មើល PDF
+GenericName[lt]=PDF Žiūriklis
+GenericName[lv]=PDF Skatītājs
+GenericName[mk]=Прикажувач на PDF датотеки
+GenericName[ms]=Pemapar PDF
+GenericName[mt]=Werrej PDF
+GenericName[nb]=PDF-fremviser
+GenericName[nds]=PDF-Kieker
+GenericName[ne]=PDF दर्शक
+GenericName[nl]=PDF-weergaveprogramma
+GenericName[nn]=PDF-lesar
+GenericName[pa]=PDF ਦਰਸ਼ਕ
+GenericName[pl]=Przeglądarka plików PDF
+GenericName[pt]=Visualizador de PDFs
+GenericName[pt_BR]=Visualizador de arquivos PDF
+GenericName[ro]=Vizualizor PDF
+GenericName[ru]=Просмотр PDF
+GenericName[rw]=Mugaragaza PDF
+GenericName[se]=PDF-čájeheaddji
+GenericName[sk]=Prehliadač PDF
+GenericName[sl]=Pregledovalnik datotek PDF
+GenericName[sr]=PDF приказивач
+GenericName[sr@Latn]=PDF prikazivač
+GenericName[sv]=PDF-visare
+GenericName[ta]=PS/PDF காட்சி
+GenericName[tg]=Хондани санадоти PDF
+GenericName[th]=ตัวแสดงผล PDF
+GenericName[tr]=PDF Görüntüleyici
+GenericName[uk]=Переглядач PDF
+GenericName[uz]=PDF koʻruvchi
+GenericName[uz@cyrillic]=PDF кўрувчи
+GenericName[ven]=Tshivhoni tsha PDF
+GenericName[wa]=Håyneu di documints PDF
+GenericName[xh]=Umboniseli we PDF
+GenericName[zh_CN]=PDF 查看器
+GenericName[zh_HK]=PDF 檢視器
+GenericName[zh_TW]=PDF 檢視器
+GenericName[zu]=Umboniseli we PDF
+Exec=kpdf %U %i -caption "%c"
+Icon=kpdf
+Type=Application
+DocPath=kpdf/index.html
+InitialPreference=7
+Categories=Qt;KDE;Graphics;Viewer;
+
diff --git a/kpdf/shell/main.cpp b/kpdf/shell/main.cpp
new file mode 100644
index 00000000..20aa3eee
--- /dev/null
+++ b/kpdf/shell/main.cpp
@@ -0,0 +1,82 @@
+/***************************************************************************
+ * Copyright (C) 2002 by Wilco Greven <greven@kde.org> *
+ * Copyright (C) 2003 by Christophe Devriese *
+ * <Christophe.Devriese@student.kuleuven.ac.be> *
+ * Copyright (C) 2003 by Laurent Montel <montel@kde.org> *
+ * Copyright (C) 2003-2004 by Albert Astals Cid <tsdgeos@terra.es> *
+ * Copyright (C) 2004 by Andy Goossens <andygoossens@telenet.be> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#include "shell.h"
+#include <kapplication.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+
+static const char description[] =
+I18N_NOOP("kpdf, a kde pdf viewer based on xpdf");
+
+static const char version[] = "0.5.10";
+
+static KCmdLineOptions options[] =
+{
+ { "+[URL]", I18N_NOOP("Document to open"), 0 },
+ KCmdLineLastOption
+};
+
+int main(int argc, char** argv)
+{
+ KAboutData about(
+ "kpdf",
+ I18N_NOOP("KPDF"),
+ version,
+ description,
+ KAboutData::License_GPL,
+ "(C) 2002 Wilco Greven, Christophe Devriese\n(C) 2004-2005 Albert Astals Cid, Enrico Ros");
+
+ about.addAuthor("Wilco Greven", 0, "greven@kde.org");
+ about.addAuthor("Christophe Devriese", 0, "oelewapperke@oelewapperke.org");
+ about.addAuthor("Laurent Montel", 0, "montel@kde.org");
+ about.addAuthor("Albert Astals Cid", I18N_NOOP("Current mantainer"), "astals11@terra.es");
+ about.addAuthor("Enrico Ros", 0, "eros.kde@email.it");
+
+ about.addCredit("Derek Noonburg", I18N_NOOP("Xpdf author"), 0, "http://www.foolabs.com/xpdf/");
+ about.addCredit("Marco Martin", I18N_NOOP("Icon"), 0, "m4rt@libero.it");
+
+ KCmdLineArgs::init(argc, argv, &about);
+ KCmdLineArgs::addCmdLineOptions( options );
+ KApplication app;
+
+ // see if we are starting with session management
+ if (app.isRestored())
+ {
+ RESTORE(KPDF::Shell);
+ } else {
+ // no session.. just start up normally
+ KCmdLineArgs* args = KCmdLineArgs::parsedArgs();
+
+ if (args->count() == 0)
+ {
+ KPDF::Shell* widget = new KPDF::Shell;
+ widget->show();
+ }
+ else
+ {
+ for (int i = 0; i < args->count(); ++i)
+ {
+ KPDF::Shell* widget = new KPDF::Shell(args->url(i));
+ widget->show();
+ }
+ }
+ args->clear();
+ }
+
+ return app.exec();
+}
+
+// vim:ts=2:sw=2:tw=78:et
diff --git a/kpdf/shell/shell.cpp b/kpdf/shell/shell.cpp
new file mode 100644
index 00000000..82b18fa6
--- /dev/null
+++ b/kpdf/shell/shell.cpp
@@ -0,0 +1,262 @@
+/***************************************************************************
+ * Copyright (C) 2002 by Wilco Greven <greven@kde.org> *
+ * Copyright (C) 2002 by Chris Cheney <ccheney@cheney.cx> *
+ * Copyright (C) 2003 by Benjamin Meyer <benjamin@csh.rit.edu> *
+ * Copyright (C) 2003-2004 by Christophe Devriese *
+ * <Christophe.Devriese@student.kuleuven.ac.be> *
+ * Copyright (C) 2003 by Laurent Montel <montel@kde.org> *
+ * Copyright (C) 2003-2004 by Albert Astals Cid <tsdgeos@terra.es> *
+ * Copyright (C) 2003 by Luboš Luňák <l.lunak@kde.org> *
+ * Copyright (C) 2003 by Malcolm Hunter <malcolm.hunter@gmx.co.uk> *
+ * Copyright (C) 2004 by Dominique Devriese <devriese@kde.org> *
+ * Copyright (C) 2004 by Dirk Mueller <mueller@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. *
+ ***************************************************************************/
+
+// qt/kde includes
+#include <qcursor.h>
+#include <qtimer.h>
+#include <kaction.h>
+#include <kapplication.h>
+#include <kedittoolbar.h>
+#include <kfiledialog.h>
+#include <klibloader.h>
+#include <kmessagebox.h>
+#include <kstdaction.h>
+#include <kurl.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmenubar.h>
+#include <kparts/componentfactory.h>
+#include <kio/netaccess.h>
+#include <kmainwindowiface.h>
+
+// local includes
+#include "shell.h"
+
+using namespace KPDF;
+
+Shell::Shell()
+ : KParts::MainWindow(0, "KPDF::Shell"), m_menuBarWasShown(true), m_toolBarWasShown(true)
+{
+ init();
+}
+
+Shell::Shell(const KURL &url)
+ : KParts::MainWindow(0, "KPDF::Shell"), m_menuBarWasShown(true), m_toolBarWasShown(true)
+{
+ m_openUrl = url;
+ init();
+}
+
+void Shell::init()
+{
+ // set the shell's ui resource file
+ setXMLFile("shell.rc");
+
+ // this routine will find and load our Part. it finds the Part by
+ // name which is a bad idea usually.. but it's alright in this
+ // case since our Part is made for this Shell
+ KParts::Factory *factory = (KParts::Factory *) KLibLoader::self()->factory("libkpdfpart");
+ if (factory)
+ {
+ // now that the Part is loaded, we cast it to a Part to get
+ // our hands on it
+ m_part = (KParts::ReadOnlyPart*) factory->createPart(this, "kpdf_part", this, 0, "KParts::ReadOnlyPart");
+ if (m_part)
+ {
+ // then, setup our actions
+ setupActions();
+ // tell the KParts::MainWindow that this is indeed the main widget
+ setCentralWidget(m_part->widget());
+ // and integrate the part's GUI with the shell's
+ setupGUI(Keys | Save);
+ createGUI(m_part);
+ m_showToolBarAction = static_cast<KToggleAction*>(toolBarMenuAction());
+ }
+ }
+ else
+ {
+ // if we couldn't find our Part, we exit since the Shell by
+ // itself can't do anything useful
+ KMessageBox::error(this, i18n("Unable to find kpdf part."));
+ m_part = 0;
+ return;
+ }
+ connect( this, SIGNAL( restoreDocument(KConfig*) ),m_part, SLOT( restoreDocument(KConfig*)));
+ connect( this, SIGNAL( saveDocumentRestoreInfo(KConfig*) ), m_part, SLOT( saveDocumentRestoreInfo(KConfig*)));
+ connect( m_part, SIGNAL( enablePrintAction(bool) ), m_printAction, SLOT( setEnabled(bool)));
+
+ readSettings();
+ if (!KGlobal::config()->hasGroup("MainWindow"))
+ {
+ KMainWindowInterface kmwi(this);
+ kmwi.maximize();
+ }
+ setAutoSaveSettings();
+
+ if (m_openUrl.isValid()) QTimer::singleShot(0, this, SLOT(delayedOpen()));
+}
+
+void Shell::delayedOpen()
+{
+ openURL(m_openUrl);
+}
+
+Shell::~Shell()
+{
+ if(m_part) writeSettings();
+}
+
+void Shell::openURL( const KURL & url )
+{
+ if ( m_part )
+ {
+ bool openOk = m_part->openURL( url );
+ if ( openOk )
+ m_recent->addURL( url );
+ else
+ m_recent->removeURL( url );
+ }
+}
+
+
+void Shell::readSettings()
+{
+ m_recent->loadEntries( KGlobal::config() );
+ m_recent->setEnabled( true ); // force enabling
+ m_recent->setToolTip( i18n("Click to open a file\nClick and hold to open a recent file") );
+
+ KGlobal::config()->setDesktopGroup();
+ bool fullScreen = KGlobal::config()->readBoolEntry( "FullScreen", false );
+ setFullScreen( fullScreen );
+}
+
+void Shell::writeSettings()
+{
+ m_recent->saveEntries( KGlobal::config() );
+ KGlobal::config()->setDesktopGroup();
+ KGlobal::config()->writeEntry( "FullScreen", m_fullScreenAction->isChecked());
+ KGlobal::config()->sync();
+}
+
+void Shell::setupActions()
+{
+ KAction * openAction = KStdAction::open(this, SLOT(fileOpen()), actionCollection());
+ m_recent = KStdAction::openRecent( this, SLOT( openURL( const KURL& ) ), actionCollection() );
+ connect( m_recent, SIGNAL( activated() ), openAction, SLOT( activate() ) );
+ m_recent->setWhatsThis( i18n( "<b>Click</b> to open a file or <b>Click and hold</b> to select a recent file" ) );
+ m_printAction = KStdAction::print( m_part, SLOT( slotPrint() ), actionCollection() );
+ m_printAction->setEnabled( false );
+ KStdAction::quit(this, SLOT(slotQuit()), actionCollection());
+
+ setStandardToolBarMenuEnabled(true);
+
+ m_showMenuBarAction = KStdAction::showMenubar( this, SLOT( slotShowMenubar() ), actionCollection());
+ KStdAction::configureToolbars(this, SLOT(optionsConfigureToolbars()), actionCollection());
+ m_fullScreenAction = KStdAction::fullScreen( this, SLOT( slotUpdateFullScreen() ), actionCollection(), this );
+}
+
+void Shell::saveProperties(KConfig* config)
+{
+ // the 'config' object points to the session managed
+ // config file. anything you write here will be available
+ // later when this app is restored
+ emit saveDocumentRestoreInfo(config);
+}
+
+void Shell::readProperties(KConfig* config)
+{
+ // the 'config' object points to the session managed
+ // config file. this function is automatically called whenever
+ // the app is being restored. read in here whatever you wrote
+ // in 'saveProperties'
+ if(m_part)
+ {
+ emit restoreDocument(config);
+ }
+}
+
+ void
+Shell::fileOpen()
+{
+ // this slot is called whenever the File->Open menu is selected,
+ // the Open shortcut is pressed (usually CTRL+O) or the Open toolbar
+ // button is clicked
+ KURL url = KFileDialog::getOpenURL( QString::null, "application/pdf application/postscript" );//getOpenFileName();
+
+ if (!url.isEmpty())
+ openURL(url);
+}
+
+ void
+Shell::optionsConfigureToolbars()
+{
+ KEditToolbar dlg(factory());
+ connect(&dlg, SIGNAL(newToolbarConfig()), this, SLOT(applyNewToolbarConfig()));
+ dlg.exec();
+}
+
+ void
+Shell::applyNewToolbarConfig()
+{
+ applyMainWindowSettings(KGlobal::config(), "MainWindow");
+}
+
+void Shell::slotQuit()
+{
+ kapp->closeAllWindows();
+}
+
+// only called when starting the program
+void Shell::setFullScreen( bool useFullScreen )
+{
+ if( useFullScreen )
+ showFullScreen();
+ else
+ showNormal();
+}
+
+void Shell::slotUpdateFullScreen()
+{
+ if(m_fullScreenAction->isChecked())
+ {
+ m_menuBarWasShown = m_showMenuBarAction->isChecked();
+ m_showMenuBarAction->setChecked(false);
+ menuBar()->hide();
+
+ m_toolBarWasShown = m_showToolBarAction->isChecked();
+ m_showToolBarAction->setChecked(false);
+ toolBar()->hide();
+
+ showFullScreen();
+ }
+ else
+ {
+ if (m_menuBarWasShown)
+ {
+ m_showMenuBarAction->setChecked(true);
+ menuBar()->show();
+ }
+ if (m_toolBarWasShown)
+ {
+ m_showToolBarAction->setChecked(true);
+ toolBar()->show();
+ }
+ showNormal();
+ }
+}
+
+void Shell::slotShowMenubar()
+{
+ if ( m_showMenuBarAction->isChecked() )
+ menuBar()->show();
+ else
+ menuBar()->hide();
+}
+
+#include "shell.moc"
diff --git a/kpdf/shell/shell.h b/kpdf/shell/shell.h
new file mode 100644
index 00000000..f92df5ce
--- /dev/null
+++ b/kpdf/shell/shell.h
@@ -0,0 +1,112 @@
+/***************************************************************************
+ * Copyright (C) 2002 by Wilco Greven <greven@kde.org> *
+ * Copyright (C) 2003 by Benjamin Meyer <benjamin@csh.rit.edu> *
+ * Copyright (C) 2003 by Laurent Montel <montel@kde.org> *
+ * Copyright (C) 2003 by Luboš Luňák <l.lunak@kde.org> *
+ * Copyright (C) 2004 by Christophe Devriese *
+ * <Christophe.Devriese@student.kuleuven.ac.be> *
+ * Copyright (C) 2004 by Albert Astals Cid <tsdgeos@terra.es> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef _KPDF_SHELL_H_
+#define _KPDF_SHELL_H_
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kparts/mainwindow.h>
+
+namespace KPDF
+{
+ class Part;
+ /**
+ * This is the application "Shell". It has a menubar and a toolbar
+ * but relies on the "Part" to do all the real work.
+ *
+ * @short Application Shell
+ * @author Wilco Greven <greven@kde.org>
+ * @version 0.1
+ */
+ class Shell : public KParts::MainWindow
+ {
+ Q_OBJECT
+
+ public:
+ /**
+ * Default Constructor
+ */
+ Shell();
+
+ /**
+ * Open an url
+ */
+ Shell(const KURL &url);
+
+ /**
+ * Default Destructor
+ */
+ virtual ~Shell();
+
+ protected:
+ /**
+ * This method is called when it is time for the app to save its
+ * properties for session management purposes.
+ */
+ void saveProperties(KConfig*);
+
+ /**
+ * This method is called when this app is restored. The KConfig
+ * object points to the session management config file that was saved
+ * with @ref saveProperties
+ */
+ void readProperties(KConfig*);
+ void readSettings();
+ void writeSettings();
+ void setFullScreen( bool );
+
+ public slots:
+ void slotQuit();
+
+ private slots:
+ void fileOpen();
+
+ void optionsConfigureToolbars();
+ void applyNewToolbarConfig();
+ void slotUpdateFullScreen();
+ void slotShowMenubar();
+
+ void openURL( const KURL & url );
+ void delayedOpen();
+
+ signals:
+ void restoreDocument(KConfig* config);
+ void saveDocumentRestoreInfo(KConfig* config);
+
+
+ private:
+ void setupAccel();
+ void setupActions();
+ void init();
+
+ private:
+ KParts::ReadOnlyPart* m_part;
+ KRecentFilesAction* m_recent;
+ KAction* m_printAction;
+ KToggleAction* m_fullScreenAction;
+ KToggleAction* m_showMenuBarAction;
+ KToggleAction* m_showToolBarAction;
+ bool m_menuBarWasShown, m_toolBarWasShown;
+ KURL m_openUrl;
+ };
+
+}
+
+#endif
+
+// vim:ts=2:sw=2:tw=78:et
diff --git a/kpdf/shell/shell.rc b/kpdf/shell/shell.rc
new file mode 100644
index 00000000..134d34c7
--- /dev/null
+++ b/kpdf/shell/shell.rc
@@ -0,0 +1,21 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui version="7" name="kpdf_shell" >
+ <MenuBar>
+ <Menu name="file" >
+ <DefineGroup append="save_merge" name="file_save" />
+ <DefineGroup append="print_merge" name="file_print" />
+ </Menu>
+ <!--Menu name="view" >
+ <Action name="fullscreen" />
+ </Menu-->
+ <Menu name="settings" >
+ <DefineGroup append="show_merge" name="show_merge" />
+ </Menu>
+ <Merge/>
+ </MenuBar>
+ <ToolBar noMerge="1" name="mainToolBar" >
+ <text>Main Toolbar</text>
+ <Action name="file_open_recent" />
+ <!--Action name="file_print" /-->
+ </ToolBar>
+</kpartgui>
diff --git a/kpdf/ui/Makefile.am b/kpdf/ui/Makefile.am
new file mode 100644
index 00000000..16a4ad50
--- /dev/null
+++ b/kpdf/ui/Makefile.am
@@ -0,0 +1,17 @@
+INCLUDES = -I$(srcdir)/.. -I$(top_builddir)/kpdf $(all_includes)
+
+METASOURCES = AUTO
+
+libkpdfui_la_SOURCES = pagepainter.cpp pageview.cpp pageviewutils.cpp \
+ minibar.cpp thumbnaillist.cpp searchwidget.cpp \
+ toc.cpp propertiesdialog.cpp presentationwidget.cpp
+
+noinst_LTLIBRARIES = libkpdfui.la
+
+pagepainter.lo: ../conf/settings.h
+pageview.lo: ../conf/settings.h
+pageviewutils.lo: ../conf/settings.h
+presentationwidget.lo: ../conf/settings.h
+searchwidget.lo: ../conf/settings.h
+thumbnaillist.lo: ../conf/settings.h
+
diff --git a/kpdf/ui/minibar.cpp b/kpdf/ui/minibar.cpp
new file mode 100644
index 00000000..1a259add
--- /dev/null
+++ b/kpdf/ui/minibar.cpp
@@ -0,0 +1,436 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Enrico Ros <eros.kde@email.it> *
+ * Copyright (C) 2006 by Albert Astals Cid <aacid@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. *
+ ***************************************************************************/
+
+// qt / kde includes
+#include <qapplication.h>
+#include <qpushbutton.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qlayout.h>
+#include <qvalidator.h>
+#include <qpainter.h>
+#include <kiconloader.h>
+#include <kaccelmanager.h>
+#include <kdeversion.h>
+
+// local includes
+#include "core/document.h"
+#include "minibar.h"
+
+// [private widget] show progress
+class ProgressWidget : public QWidget
+{
+ public:
+ ProgressWidget( MiniBar * parent );
+ void setProgress( float percentage );
+
+ protected:
+ void mouseMoveEvent( QMouseEvent * e );
+ void mousePressEvent( QMouseEvent * e );
+ void wheelEvent( QWheelEvent * e );
+ void paintEvent( QPaintEvent * e );
+
+ private:
+ MiniBar * m_miniBar;
+ float m_progressPercentage;
+};
+
+// [private widget] lineEdit for entering/validating page numbers
+class PagesEdit : public QLineEdit
+{
+ public:
+ PagesEdit( MiniBar * parent );
+ void setPagesNumber( int pages );
+ void setText( const QString & );
+
+ protected:
+ void focusInEvent( QFocusEvent * e );
+ void focusOutEvent( QFocusEvent * e );
+ void mousePressEvent( QMouseEvent * e );
+ void wheelEvent( QWheelEvent * e );
+
+ private:
+ MiniBar * m_miniBar;
+ bool m_eatClick;
+ QString backString;
+ QIntValidator * m_validator;
+};
+
+// [private widget] a flat qpushbutton that enlights on hover
+class HoverButton : public QPushButton
+{
+ public:
+ HoverButton( QWidget * parent );
+
+ protected:
+ void paintEvent( QPaintEvent * e );
+ void enterEvent( QPaintEvent * e );
+ void leaveEvent( QPaintEvent * e );
+};
+
+
+/** MiniBar **/
+
+MiniBar::MiniBar( QWidget * parent, KPDFDocument * document )
+ : QFrame( parent, "miniBar" ), m_document( document ),
+ m_currentPage( -1 )
+{
+ // left spacer
+ QHBoxLayout * horLayout = new QHBoxLayout( this );
+ QSpacerItem * spacerL = new QSpacerItem( 20, 10, QSizePolicy::Expanding );
+ horLayout->addItem( spacerL );
+
+ // central 2r by 3c grid layout that contains all components
+ QGridLayout * gridLayout = new QGridLayout( 0, 3,5, 2,1 );
+ // top spacer 6x6 px
+// QSpacerItem * spacerTop = new QSpacerItem( 6, 6, QSizePolicy::Fixed, QSizePolicy::Fixed );
+// gridLayout->addMultiCell( spacerTop, 0, 0, 0, 4 );
+ // center progress widget
+ m_progressWidget = new ProgressWidget( this );
+ gridLayout->addMultiCellWidget( m_progressWidget, 0, 0, 0, 4 );
+ // bottom: left prev_page button
+ m_prevButton = new HoverButton( this );
+ m_prevButton->setIconSet( SmallIconSet( QApplication::reverseLayout() ? "1rightarrow" : "1leftarrow" ) );
+ gridLayout->addWidget( m_prevButton, 1, 0 );
+ // bottom: left lineEdit (current page box)
+ m_pagesEdit = new PagesEdit( this );
+ gridLayout->addWidget( m_pagesEdit, 1, 1 );
+ // bottom: central '/' label
+ gridLayout->addWidget( new QLabel( "/", this ), 1, 2 );
+ // bottom: right button
+ m_pagesButton = new HoverButton( this );
+ gridLayout->addWidget( m_pagesButton, 1, 3 );
+ // bottom: right next_page button
+ m_nextButton = new HoverButton( this );
+ m_nextButton->setIconSet( SmallIconSet( QApplication::reverseLayout() ? "1leftarrow" : "1rightarrow" ) );
+ gridLayout->addWidget( m_nextButton, 1, 4 );
+ horLayout->addLayout( gridLayout );
+
+ // right spacer
+ QSpacerItem * spacerR = new QSpacerItem( 20, 10, QSizePolicy::Expanding );
+ horLayout->addItem( spacerR );
+
+ // customize own look
+ setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
+
+ // connect signals from child widgets to internal handlers / signals bouncers
+ connect( m_pagesEdit, SIGNAL( returnPressed() ), this, SLOT( slotChangePage() ) );
+ connect( m_pagesButton, SIGNAL( clicked() ), this, SIGNAL( gotoPage() ) );
+ connect( m_prevButton, SIGNAL( clicked() ), this, SIGNAL( prevPage() ) );
+ connect( m_nextButton, SIGNAL( clicked() ), this, SIGNAL( nextPage() ) );
+
+ // widget starts hidden (will be shown after opening a document)
+ parent->hide();
+}
+
+MiniBar::~MiniBar()
+{
+ m_document->removeObserver( this );
+}
+
+void MiniBar::notifySetup( const QValueVector< KPDFPage * > & pageVector, bool changed )
+{
+ // only process data when document changes
+ if ( !changed )
+ return;
+
+ // if document is closed or has no pages, hide widget
+ int pages = pageVector.count();
+ if ( pages < 1 )
+ {
+ m_currentPage = -1;
+ static_cast<QWidget*>( parent() )->hide();
+ return;
+ }
+
+ // resize width of widgets
+ int numberWidth = 10 + fontMetrics().width( QString::number( pages ) );
+ m_pagesEdit->setMinimumWidth( numberWidth );
+ m_pagesEdit->setMaximumWidth( 2 * numberWidth );
+ m_pagesButton->setMinimumWidth( numberWidth );
+ m_pagesButton->setMaximumWidth( 2 * numberWidth );
+
+ // resize height of widgets
+ int fixedHeight = fontMetrics().height() + 2;
+ if ( fixedHeight < 18 )
+ fixedHeight = 18;
+ m_pagesEdit->setFixedHeight( fixedHeight );
+ m_pagesButton->setFixedHeight( fixedHeight );
+ m_prevButton->setFixedHeight( fixedHeight );
+ m_nextButton->setFixedHeight( fixedHeight );
+
+ // update child widgets
+ m_pagesEdit->setPagesNumber( pages );
+ m_pagesButton->setText( QString::number( pages ) );
+ m_prevButton->setEnabled( false );
+ m_nextButton->setEnabled( false );
+ static_cast<QWidget*>( parent() )->show();
+}
+
+void MiniBar::notifyViewportChanged( bool /*smoothMove*/ )
+{
+ // get current page number
+ int page = m_document->viewport().pageNumber;
+ int pages = m_document->pages();
+
+ // if the document is opened and page is changed
+ if ( page != m_currentPage && pages > 0 )
+ {
+ // update percentage
+ m_currentPage = page;
+ float percentage = pages < 2 ? 1.0 : (float)page / (float)(pages - 1);
+ m_progressWidget->setProgress( percentage );
+ // update prev/next button state
+ m_prevButton->setEnabled( page > 0 );
+ m_nextButton->setEnabled( page < ( pages - 1 ) );
+ // update text on widgets
+ m_pagesEdit->setText( QString::number( page + 1 ) );
+ }
+}
+
+void MiniBar::resizeEvent( QResizeEvent * e )
+{
+ // auto-hide 'prev' and 'next' buttons if not enough space
+ const QSize & myHint = minimumSizeHint();
+ bool shown = m_prevButton->isVisible() && m_nextButton->isVisible();
+ if ( shown && e->size().width() < myHint.width() )
+ {
+ m_prevButton->hide();
+ m_nextButton->hide();
+ updateGeometry();
+ }
+ else if ( !shown )
+ {
+ int histeresis = m_prevButton->sizeHint().width() * 2 + 2;
+ if ( e->size().width() > (myHint.width() + histeresis) )
+ {
+ m_prevButton->show();
+ m_nextButton->show();
+ updateGeometry();
+ }
+ }
+}
+
+void MiniBar::slotChangePage()
+{
+ // get text from the lineEdit
+ QString pageNumber = m_pagesEdit->text();
+
+ // convert it to page number and go to that page
+ bool ok;
+ int number = pageNumber.toInt( &ok ) - 1;
+ if ( ok && number >= 0 && number < (int)m_document->pages() &&
+ number != m_currentPage )
+ {
+ m_document->setViewportPage( number );
+ m_pagesEdit->clearFocus();
+ }
+}
+
+void MiniBar::slotGotoNormalizedPage( float index )
+{
+ // figure out page number and go to that page
+ int number = (int)( index * (float)m_document->pages() );
+ if ( number >= 0 && number < (int)m_document->pages() &&
+ number != m_currentPage )
+ m_document->setViewportPage( number );
+}
+
+void MiniBar::slotEmitNextPage()
+{
+ // emit signal
+ nextPage();
+}
+
+void MiniBar::slotEmitPrevPage()
+{
+ // emit signal
+ prevPage();
+}
+
+
+
+/** ProgressWidget **/
+
+ProgressWidget::ProgressWidget( MiniBar * parent )
+ : QWidget( parent, "progress", WNoAutoErase ),
+ m_miniBar( parent ), m_progressPercentage( -1 )
+{
+ setFixedHeight( 4 );
+ setMouseTracking( true );
+}
+
+void ProgressWidget::setProgress( float percentage )
+{
+ m_progressPercentage = percentage;
+ update();
+}
+
+void ProgressWidget::mouseMoveEvent( QMouseEvent * e )
+{
+ if ( e->state() == Qt::LeftButton && width() > 0 )
+ m_miniBar->slotGotoNormalizedPage( (float)( QApplication::reverseLayout() ? width() - e->x() : e->x() ) / (float)width() );
+}
+
+void ProgressWidget::mousePressEvent( QMouseEvent * e )
+{
+ if ( e->button() == Qt::LeftButton && width() > 0 )
+ m_miniBar->slotGotoNormalizedPage( (float)( QApplication::reverseLayout() ? width() - e->x() : e->x() ) / (float)width() );
+}
+
+void ProgressWidget::wheelEvent( QWheelEvent * e )
+{
+ if ( e->delta() > 0 )
+ m_miniBar->slotEmitNextPage();
+ else
+ m_miniBar->slotEmitPrevPage();
+}
+
+void ProgressWidget::paintEvent( QPaintEvent * e )
+{
+ if ( m_progressPercentage < 0.0 )
+ return;
+
+ // find out the 'fill' and the 'clear' rectangles
+ int w = width(),
+ h = height(),
+ l = (int)( (float)w * m_progressPercentage );
+ QRect cRect = ( QApplication::reverseLayout() ? QRect( 0, 0, w - l, h ) : QRect( l, 0, w - l, h ) ).intersect( e->rect() );
+ QRect fRect = ( QApplication::reverseLayout() ? QRect( w - l, 0, l, h ) : QRect( 0, 0, l, h ) ).intersect( e->rect() );
+
+ // paint rects and a separator line
+ QPainter p( this );
+ if ( cRect.isValid() )
+ p.fillRect( cRect, palette().active().highlightedText() );
+ if ( fRect.isValid() )
+ p.fillRect( fRect, palette().active().highlight() );
+ if ( l && l != w )
+ {
+ p.setPen( palette().active().highlight().dark( 120 ) );
+ int delta = QApplication::reverseLayout() ? w - l : l;
+ p.drawLine( delta, 0, delta, h );
+ }
+ // draw a frame-like outline
+ //p.setPen( palette().active().mid() );
+ //p.drawRect( 0,0, w, h );
+}
+
+
+/** PagesEdit **/
+
+PagesEdit::PagesEdit( MiniBar * parent )
+ : QLineEdit( parent ), m_miniBar( parent ), m_eatClick( false )
+{
+ // customize look
+ setFrameShadow( QFrame::Raised );
+ focusOutEvent( 0 );
+
+ // use an integer validator
+ m_validator = new QIntValidator( 1, 1, this );
+ setValidator( m_validator );
+
+ // customize text properties
+ setAlignment( Qt::AlignCenter );
+ setMaxLength( 4 );
+}
+
+void PagesEdit::setPagesNumber( int pages )
+{
+ m_validator->setTop( pages );
+}
+
+void PagesEdit::setText( const QString & text )
+{
+ // store a copy of the string
+ backString = text;
+ // call default handler if hasn't focus
+ if ( !hasFocus() )
+ QLineEdit::setText( text );
+}
+
+void PagesEdit::focusInEvent( QFocusEvent * e )
+{
+ // select all text
+ selectAll();
+ if ( e->reason() == QFocusEvent::Mouse )
+ m_eatClick = true;
+ // change background color to the default 'edit' color
+ setLineWidth( 2 );
+ setPaletteBackgroundColor( Qt::white );
+ // call default handler
+ QLineEdit::focusInEvent( e );
+}
+
+void PagesEdit::focusOutEvent( QFocusEvent * e )
+{
+ // change background color to a dark tone
+ setLineWidth( 1 );
+ setPaletteBackgroundColor( palette().active().background().light( 105 ) );
+ // restore text
+ QLineEdit::setText( backString );
+ // call default handler
+ QLineEdit::focusOutEvent( e );
+}
+
+void PagesEdit::mousePressEvent( QMouseEvent * e )
+{
+ // if this click got the focus in, don't process the event
+ if ( !m_eatClick )
+ QLineEdit::mousePressEvent( e );
+ m_eatClick = false;
+}
+
+void PagesEdit::wheelEvent( QWheelEvent * e )
+{
+ if ( e->delta() > 0 )
+ m_miniBar->slotEmitNextPage();
+ else
+ m_miniBar->slotEmitPrevPage();
+}
+
+
+/** HoverButton **/
+
+HoverButton::HoverButton( QWidget * parent )
+ : QPushButton( parent )
+{
+ setMouseTracking( true );
+#if KDE_IS_VERSION(3,3,90)
+ KAcceleratorManager::setNoAccel( this );
+#endif
+}
+
+void HoverButton::enterEvent( QPaintEvent * e )
+{
+ update();
+ QPushButton::enterEvent( e );
+}
+
+void HoverButton::leaveEvent( QPaintEvent * e )
+{
+ update();
+ QPushButton::leaveEvent( e );
+}
+
+void HoverButton::paintEvent( QPaintEvent * e )
+{
+ if ( hasMouse() )
+ {
+ QPushButton::paintEvent( e );
+ }
+ else
+ {
+ QPainter p( this );
+ p.fillRect(e->rect(), parentWidget() ? parentWidget()->palette().brush(QPalette::Active, QColorGroup::Background) : paletteBackgroundColor());
+ drawButtonLabel( &p );
+ }
+}
+
+#include "minibar.moc"
diff --git a/kpdf/ui/minibar.h b/kpdf/ui/minibar.h
new file mode 100644
index 00000000..7c815e5e
--- /dev/null
+++ b/kpdf/ui/minibar.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Enrico Ros <eros.kde@email.it> *
+ * Copyright (C) 2006 by Albert Astals Cid <aacid@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. *
+ ***************************************************************************/
+
+#ifndef _KPDF_MINIBAR_H_
+#define _KPDF_MINIBAR_H_
+
+#include <qframe.h>
+#include "core/observer.h"
+
+class KPDFDocument;
+class PagesEdit;
+class HoverButton;
+class ProgressWidget;
+
+/**
+ * @short A widget to display page number and change current page.
+ */
+class MiniBar : public QFrame, public DocumentObserver
+{
+ Q_OBJECT
+ public:
+ MiniBar( QWidget *parent, KPDFDocument * document );
+ ~MiniBar();
+
+ // [INHERITED] from DocumentObserver
+ uint observerId() const { return MINIBAR_ID; }
+ void notifySetup( const QValueVector< KPDFPage * > & pages, bool );
+ void notifyViewportChanged( bool smoothMove );
+
+ signals:
+ void gotoPage();
+ void prevPage();
+ void nextPage();
+
+ public slots:
+ void slotChangePage();
+ void slotGotoNormalizedPage( float normIndex );
+ void slotEmitNextPage();
+ void slotEmitPrevPage();
+
+ protected:
+ void resizeEvent( QResizeEvent * );
+
+ private:
+ KPDFDocument * m_document;
+ PagesEdit * m_pagesEdit;
+ HoverButton * m_prevButton;
+ HoverButton * m_pagesButton;
+ HoverButton * m_nextButton;
+ ProgressWidget * m_progressWidget;
+ int m_currentPage;
+};
+
+#endif
diff --git a/kpdf/ui/pagepainter.cpp b/kpdf/ui/pagepainter.cpp
new file mode 100644
index 00000000..f68df254
--- /dev/null
+++ b/kpdf/ui/pagepainter.cpp
@@ -0,0 +1,252 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Enrico Ros <eros.kde@email.it> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+// qt / kde includes
+#include <qrect.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qimage.h>
+#include <qapplication.h>
+#include <kimageeffect.h>
+
+// local includes
+#include "pagepainter.h"
+#include "core/page.h"
+#include "conf/settings.h"
+
+void PagePainter::paintPageOnPainter( const KPDFPage * page, int id, int flags,
+ QPainter * destPainter, const QRect & limits, int width, int height )
+{
+ QPixmap * pixmap = 0;
+
+ // if a pixmap is present for given id, use it
+ if ( page->m_pixmaps.contains( id ) )
+ pixmap = page->m_pixmaps[ id ];
+
+ // else find the closest match using pixmaps of other IDs (great optim!)
+ else if ( !page->m_pixmaps.isEmpty() && width != -1 )
+ {
+ int minDistance = -1;
+ QMap< int,QPixmap * >::const_iterator it = page->m_pixmaps.begin(), end = page->m_pixmaps.end();
+ for ( ; it != end; ++it )
+ {
+ int pixWidth = (*it)->width(),
+ distance = pixWidth > width ? pixWidth - width : width - pixWidth;
+ if ( minDistance == -1 || distance < minDistance )
+ {
+ pixmap = *it;
+ minDistance = distance;
+ }
+ }
+ }
+
+ // if have no pixmap, draw blank page with gray cross and exit
+ if ( !pixmap )
+ {
+ QColor color = Qt::white;
+ if ( KpdfSettings::changeColors() )
+ {
+ switch ( KpdfSettings::renderMode() )
+ {
+ case KpdfSettings::EnumRenderMode::Inverted:
+ color = Qt::black;
+ break;
+ case KpdfSettings::EnumRenderMode::Paper:
+ color = KpdfSettings::paperColor();
+ break;
+ case KpdfSettings::EnumRenderMode::Recolor:
+ color = KpdfSettings::recolorBackground();
+ break;
+ default: ;
+ }
+ }
+ destPainter->fillRect( limits, color );
+
+ // draw a cross (to that the pixmap as not yet been loaded)
+ // helps a lot on pages that take much to render
+ destPainter->setPen( Qt::gray );
+ destPainter->drawLine( 0, 0, width-1, height-1 );
+ destPainter->drawLine( 0, height-1, width-1, 0 );
+ // idea here: draw a hourglass (or kpdf icon :-) on top-left corner
+ return;
+ }
+
+ // find out what to paint over the pixmap (manipulations / overlays)
+ bool paintAccessibility = (flags & Accessibility) && KpdfSettings::changeColors() && (KpdfSettings::renderMode() != KpdfSettings::EnumRenderMode::Paper);
+ bool paintHighlights = (flags & Highlights) && !page->m_highlights.isEmpty();
+ bool enhanceLinks = (flags & EnhanceLinks) && KpdfSettings::highlightLinks();
+ bool enhanceImages = (flags & EnhanceImages) && KpdfSettings::highlightImages();
+ // check if there are really some highlightRects to paint
+ if ( paintHighlights )
+ {
+ // precalc normalized 'limits rect' for intersection
+ double nXMin = (double)limits.left() / (double)width,
+ nXMax = (double)limits.right() / (double)width,
+ nYMin = (double)limits.top() / (double)height,
+ nYMax = (double)limits.bottom() / (double)height;
+ // if no rect intersects limits, disable paintHighlights
+ paintHighlights = false;
+ QValueList< HighlightRect * >::const_iterator hIt = page->m_highlights.begin(), hEnd = page->m_highlights.end();
+ for ( ; hIt != hEnd; ++hIt )
+ {
+ if ( (*hIt)->intersects( nXMin, nYMin, nXMax, nYMax ) )
+ {
+ paintHighlights = true;
+ break;
+ }
+ }
+ }
+
+ // use backBuffer if 'pixmap direct manipulation' is needed
+ bool backBuffer = paintAccessibility || paintHighlights;
+ QPixmap * backPixmap = 0;
+ QPainter * p = destPainter;
+ if ( backBuffer )
+ {
+ // let's paint using a buffered painter
+ backPixmap = new QPixmap( limits.width(), limits.height() );
+ p = new QPainter( backPixmap );
+ p->translate( -limits.left(), -limits.top() );
+ }
+
+ // 1. fast blit the pixmap if it has the right size..
+ if ( pixmap->width() == width && pixmap->height() == height )
+ p->drawPixmap( limits.topLeft(), *pixmap, limits );
+ // ..else set a scale matrix to the painter and paint a quick 'zoomed' pixmap
+ else
+ {
+ p->save();
+ // TODO paint only the needed part (note: hope that Qt4 transforms are faster)
+ p->scale( width / (double)pixmap->width(), height / (double)pixmap->height() );
+ p->drawPixmap( 0,0, *pixmap, 0,0, pixmap->width(), pixmap->height() );
+ p->restore();
+ }
+
+ // 2. mangle pixmap: convert it to 32-bit qimage and perform pixel-level manipulations
+ if ( backBuffer )
+ {
+ QImage backImage = backPixmap->convertToImage();
+ // 2.1. modify pixmap following accessibility settings
+ if ( paintAccessibility )
+ {
+ switch ( KpdfSettings::renderMode() )
+ {
+ case KpdfSettings::EnumRenderMode::Inverted:
+ // Invert image pixels using QImage internal function
+ backImage.invertPixels(false);
+ break;
+ case KpdfSettings::EnumRenderMode::Recolor:
+ // Recolor image using KImageEffect::flatten with dither:0
+ KImageEffect::flatten( backImage, KpdfSettings::recolorForeground(), KpdfSettings::recolorBackground() );
+ break;
+ case KpdfSettings::EnumRenderMode::BlackWhite:
+ // Manual Gray and Contrast
+ unsigned int * data = (unsigned int *)backImage.bits();
+ int val, pixels = backImage.width() * backImage.height(),
+ con = KpdfSettings::bWContrast(), thr = 255 - KpdfSettings::bWThreshold();
+ for( int i = 0; i < pixels; ++i )
+ {
+ val = qGray( data[i] );
+ if ( val > thr )
+ val = 128 + (127 * (val - thr)) / (255 - thr);
+ else if ( val < thr )
+ val = (128 * val) / thr;
+ if ( con > 2 )
+ {
+ val = con * ( val - thr ) / 2 + thr;
+ if ( val > 255 )
+ val = 255;
+ else if ( val < 0 )
+ val = 0;
+ }
+ data[i] = qRgba( val, val, val, 255 );
+ }
+ break;
+ }
+ }
+ // 2.2. highlight rects in page
+ if ( paintHighlights )
+ {
+ // draw highlights that are inside the 'limits' paint region
+ QValueList< HighlightRect * >::const_iterator hIt = page->m_highlights.begin(), hEnd = page->m_highlights.end();
+ for ( ; hIt != hEnd; ++hIt )
+ {
+ HighlightRect * r = *hIt;
+ QRect highlightRect = r->geometry( width, height );
+ if ( highlightRect.isValid() && highlightRect.intersects( limits ) )
+ {
+ // find out the rect to highlight on pixmap
+ highlightRect = highlightRect.intersect( limits );
+ highlightRect.moveBy( -limits.left(), -limits.top() );
+
+ // highlight composition (product: highlight color * destcolor)
+ unsigned int * data = (unsigned int *)backImage.bits();
+ int val, newR, newG, newB,
+ rh = r->color.red(),
+ gh = r->color.green(),
+ bh = r->color.blue(),
+ offset = highlightRect.top() * backImage.width();
+ for( int y = highlightRect.top(); y <= highlightRect.bottom(); ++y )
+ {
+ for( int x = highlightRect.left(); x <= highlightRect.right(); ++x )
+ {
+ val = data[ x + offset ];
+ newR = (qRed(val) * rh) / 255;
+ newG = (qGreen(val) * gh) / 255;
+ newB = (qBlue(val) * bh) / 255;
+ data[ x + offset ] = qRgba( newR, newG, newB, 255 );
+ }
+ offset += backImage.width();
+ }
+ }
+ }
+ }
+ backPixmap->convertFromImage( backImage );
+ }
+
+ // 3. visually enchance links and images if requested
+ if ( enhanceLinks || enhanceImages )
+ {
+ QColor normalColor = QApplication::palette().active().highlight();
+ QColor lightColor = normalColor.light( 140 );
+ // enlarging limits for intersection is like growing the 'rectGeometry' below
+ QRect limitsEnlarged = limits;
+ limitsEnlarged.addCoords( -2, -2, 2, 2 );
+ // draw rects that are inside the 'limits' paint region as opaque rects
+ QValueList< ObjectRect * >::const_iterator lIt = page->m_rects.begin(), lEnd = page->m_rects.end();
+ for ( ; lIt != lEnd; ++lIt )
+ {
+ ObjectRect * rect = *lIt;
+ if ( (enhanceLinks && rect->objectType() == ObjectRect::Link) ||
+ (enhanceImages && rect->objectType() == ObjectRect::Image) )
+ {
+ QRect rectGeometry = rect->geometry( width, height );
+ if ( rectGeometry.intersects( limitsEnlarged ) )
+ {
+ // expand rect and draw inner border
+ rectGeometry.addCoords( -1,-1,1,1 );
+ p->setPen( lightColor );
+ p->drawRect( rectGeometry );
+ // expand rect to draw outer border
+ rectGeometry.addCoords( -1,-1,1,1 );
+ p->setPen( normalColor );
+ p->drawRect( rectGeometry );
+ }
+ }
+ }
+ }
+
+ // 4. if was backbuffering, copy the backPixmap to destination
+ if ( backBuffer )
+ {
+ delete p;
+ destPainter->drawPixmap( limits.left(), limits.top(), *backPixmap );
+ delete backPixmap;
+ }
+}
diff --git a/kpdf/ui/pagepainter.h b/kpdf/ui/pagepainter.h
new file mode 100644
index 00000000..21ef7629
--- /dev/null
+++ b/kpdf/ui/pagepainter.h
@@ -0,0 +1,36 @@
+/***************************************************************************
+ * Copyright (C) 2005 by Enrico Ros <eros.kde@email.it> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef _KPDF_PAGEPAINTER_H_
+#define _KPDF_PAGEPAINTER_H_
+
+class KPDFPage;
+class QPainter;
+class QRect;
+
+/**
+ * @short Paints a KPDFPage to an open painter using given flags.
+ */
+class PagePainter
+{
+ public:
+ // list of flags passed to the painting function. by OR-ing those flags
+ // you can decide wether or not to permit drawing of a certain feature.
+ enum PagePainterFlags { Accessibility = 1, EnhanceLinks = 2,
+ EnhanceImages = 4, Highlights = 8 };
+
+ // draw (using painter 'p') the 'page' requested by 'id' using features
+ // in 'flags'. 'limits' is the bounding rect of the paint operation,
+ // 'width' and 'height' the expected size of page contents (used only
+ // to pick up an alternative pixmap if the pixmap of 'id' is missing.
+ static void paintPageOnPainter( const KPDFPage * page, int id, int flags,
+ QPainter * p, const QRect & limits, int width = -1, int height = -1 );
+};
+
+#endif
diff --git a/kpdf/ui/pageview.cpp b/kpdf/ui/pageview.cpp
new file mode 100644
index 00000000..247f1b1b
--- /dev/null
+++ b/kpdf/ui/pageview.cpp
@@ -0,0 +1,2114 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
+ * Copyright (C) 2004-2006 by Albert Astals Cid <tsdgeos@terra.es> *
+ * *
+ * With portions of code from kpdf/kpdf_pagewidget.cc by: *
+ * Copyright (C) 2002 by Wilco Greven <greven@kde.org> *
+ * Copyright (C) 2003 by Christophe Devriese *
+ * <Christophe.Devriese@student.kuleuven.ac.be> *
+ * Copyright (C) 2003 by Laurent Montel <montel@kde.org> *
+ * Copyright (C) 2003 by Dirk Mueller <mueller@kde.org> *
+ * Copyright (C) 2004 by James Ots <kde@jamesots.com> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+// qt/kde includes
+#include <qcursor.h>
+#include <qpainter.h>
+#include <qtimer.h>
+#include <qdatetime.h>
+#include <qpushbutton.h>
+#include <qtooltip.h>
+#include <qapplication.h>
+#include <qclipboard.h>
+#include <dcopclient.h>
+#include <kcursor.h>
+#include <kiconloader.h>
+#include <kurldrag.h>
+#include <kaction.h>
+#include <kstdaccel.h>
+#include <kactioncollection.h>
+#include <kpopupmenu.h>
+#include <klocale.h>
+#include <kfiledialog.h>
+#include <kimageeffect.h>
+#include <kimageio.h>
+#include <kapplication.h>
+#include <kdebug.h>
+
+// system includes
+#include <math.h>
+#include <stdlib.h>
+
+// local includes
+#include "pageview.h"
+#include "pageviewutils.h"
+#include "pagepainter.h"
+#include "core/document.h"
+#include "core/page.h"
+#include "core/link.h"
+#include "core/generator.h"
+#include "conf/settings.h"
+
+#define ROUND(x) (int(x + 0.5))
+
+// definition of searchID for this class
+#define PAGEVIEW_SEARCH_ID 2
+
+// structure used internally by PageView for data storage
+class PageViewPrivate
+{
+public:
+ // the document, pageviewItems and the 'visible cache'
+ KPDFDocument * document;
+ QValueVector< PageViewItem * > items;
+ QValueList< PageViewItem * > visibleItems;
+
+ // view layout (columns and continuous in Settings), zoom and mouse
+ PageView::ZoomMode zoomMode;
+ float zoomFactor;
+ PageView::MouseMode mouseMode;
+ QPoint mouseGrabPos;
+ QPoint mousePressPos;
+ int mouseMidStartY;
+ bool mouseOnRect;
+ QRect mouseSelectionRect;
+ QColor selectionRectColor;
+
+ // type ahead find
+ bool typeAheadActive;
+ QString typeAheadString;
+ QTimer * findTimeoutTimer;
+ // viewport move
+ bool viewportMoveActive;
+ QTime viewportMoveTime;
+ QPoint viewportMoveDest;
+ QTimer * viewportMoveTimer;
+ // auto scroll
+ int scrollIncrement;
+ QTimer * autoScrollTimer;
+ // other stuff
+ QTimer * delayResizeTimer;
+ bool dirtyLayout;
+ bool blockViewport; // prevents changes to viewport
+ bool blockPixmapsRequest; // prevent pixmap requests
+ PageViewMessage * messageWindow; // in pageviewutils.h
+ PageViewTip * tip;
+
+ // drag scroll
+ QPoint dragScrollVector;
+ QTimer dragScrollTimer;
+
+ // actions
+ KToggleAction * aMouseNormal;
+ KToggleAction * aMouseSelect;
+ KToggleAction * aMouseEdit;
+ KSelectAction * aZoom;
+ KToggleAction * aZoomFitWidth;
+ KToggleAction * aZoomFitPage;
+ KToggleAction * aZoomFitText;
+ KToggleAction * aViewTwoPages;
+ KToggleAction * aViewContinuous;
+ KAction * aPrevAction;
+};
+
+
+
+class PageViewTip : public QToolTip
+{
+ public:
+ PageViewTip( PageView * view )
+ : QToolTip( view->viewport() ), m_view( view )
+ {
+ }
+
+ ~PageViewTip()
+ {
+ remove( m_view->viewport() );
+ }
+
+
+ protected:
+ void maybeTip( const QPoint &p );
+
+ private:
+ PageView * m_view;
+};
+
+void PageViewTip::maybeTip( const QPoint &_p )
+{
+ QPoint p( _p.x() + m_view->contentsX(), _p.y() + m_view->contentsY() );
+ PageViewItem * pageItem = m_view->pickItemOnPoint( p.x(), p.y() );
+ if ( pageItem && m_view->d->mouseMode == PageView::MouseNormal )
+ {
+ double nX = (double)(p.x() - pageItem->geometry().left()) / (double)pageItem->width(),
+ nY = (double)(p.y() - pageItem->geometry().top()) / (double)pageItem->height();
+
+ // if over a ObjectRect (of type Link) change cursor to hand
+ const ObjectRect * object = pageItem->page()->hasObject( ObjectRect::Link, nX, nY );
+ if ( object )
+ {
+ // set tooltip over link's rect
+ KPDFLink *link = (KPDFLink *)object->pointer();
+ QString strtip = link->linkTip();
+ if ( !strtip.isEmpty() )
+ {
+ QRect linkRect = object->geometry( pageItem->width(), pageItem->height() );
+ linkRect.moveBy( - m_view->contentsX() + pageItem->geometry().left(), - m_view->contentsY() + pageItem->geometry().top() );
+ tip( linkRect, strtip );
+ }
+ }
+ }
+}
+
+
+
+/* PageView. What's in this file? -> quick overview.
+ * Code weight (in rows) and meaning:
+ * 160 - constructor and creating actions plus their connected slots (empty stuff)
+ * 70 - DocumentObserver inherited methodes (important)
+ * 550 - events: mouse, keyboard, drag/drop
+ * 170 - slotRelayoutPages: set contents of the scrollview on continuous/single modes
+ * 100 - zoom: zooming pages in different ways, keeping update the toolbar actions, etc..
+ * other misc functions: only slotRequestVisiblePixmaps and pickItemOnPoint noticeable,
+ * and many insignificant stuff like this comment :-)
+ */
+PageView::PageView( QWidget *parent, KPDFDocument *document )
+ : QScrollView( parent, "KPDF::pageView", WStaticContents | WNoAutoErase )
+{
+ // create and initialize private storage structure
+ d = new PageViewPrivate();
+ d->document = document;
+ d->zoomMode = (PageView::ZoomMode)KpdfSettings::zoomMode();
+ d->zoomFactor = KpdfSettings::zoomFactor();
+ d->mouseMode = MouseNormal;
+ d->mouseMidStartY = -1;
+ d->mouseOnRect = false;
+ d->typeAheadActive = false;
+ d->findTimeoutTimer = 0;
+ d->viewportMoveActive = false;
+ d->viewportMoveTimer = 0;
+ d->scrollIncrement = 0;
+ d->autoScrollTimer = 0;
+ d->delayResizeTimer = 0;
+ d->dirtyLayout = false;
+ d->blockViewport = false;
+ d->blockPixmapsRequest = false;
+ d->messageWindow = new PageViewMessage(this);
+ d->tip = new PageViewTip( this );
+ d->aPrevAction = 0;
+
+ // widget setup: setup focus, accept drops and track mouse
+ viewport()->setFocusProxy( this );
+ viewport()->setFocusPolicy( StrongFocus );
+ //viewport()->setPaletteBackgroundColor( Qt::white );
+ viewport()->setBackgroundMode( Qt::NoBackground );
+ setResizePolicy( Manual );
+ setAcceptDrops( true );
+ setDragAutoScroll( false );
+ viewport()->setMouseTracking( true );
+
+ // conntect the padding of the viewport to pixmaps requests
+ connect( this, SIGNAL(contentsMoving(int, int)), this, SLOT(slotRequestVisiblePixmaps(int, int)) );
+ connect( &d->dragScrollTimer, SIGNAL(timeout()), this, SLOT(slotDragScroll()) );
+
+ // set a corner button to resize the view to the page size
+// QPushButton * resizeButton = new QPushButton( viewport() );
+// resizeButton->setPixmap( SmallIcon("crop") );
+// setCornerWidget( resizeButton );
+// resizeButton->setEnabled( false );
+ // connect(...);
+ setInputMethodEnabled( true );
+
+ // schedule the welcome message
+ QTimer::singleShot( 0, this, SLOT( slotShowWelcome() ) );
+}
+
+PageView::~PageView()
+{
+ // delete all widgets
+ QValueVector< PageViewItem * >::iterator dIt = d->items.begin(), dEnd = d->items.end();
+ for ( ; dIt != dEnd; ++dIt )
+ delete *dIt;
+ delete d->tip;
+ d->tip = 0;
+ d->document->removeObserver( this );
+ delete d;
+}
+
+void PageView::setupActions( KActionCollection * ac )
+{
+ // Zoom actions ( higher scales takes lots of memory! )
+ d->aZoom = new KSelectAction( i18n( "Zoom" ), "viewmag", 0, this, SLOT( slotZoom() ), ac, "zoom_to" );
+ d->aZoom->setEditable( true );
+#if KDE_IS_VERSION(3,4,89)
+ d->aZoom->setMaxComboViewCount( 13 );
+#endif
+ updateZoomText();
+
+ KStdAction::zoomIn( this, SLOT( slotZoomIn() ), ac, "zoom_in" );
+
+ KStdAction::zoomOut( this, SLOT( slotZoomOut() ), ac, "zoom_out" );
+
+ d->aZoomFitWidth = new KToggleAction( i18n("Fit to Page &Width"), "view_fit_width", 0, ac, "zoom_fit_width" );
+ connect( d->aZoomFitWidth, SIGNAL( toggled( bool ) ), SLOT( slotFitToWidthToggled( bool ) ) );
+
+ d->aZoomFitPage = new KToggleAction( i18n("Fit to &Page"), "view_fit_window", 0, ac, "zoom_fit_page" );
+ connect( d->aZoomFitPage, SIGNAL( toggled( bool ) ), SLOT( slotFitToPageToggled( bool ) ) );
+
+ d->aZoomFitText = new KToggleAction( i18n("Fit to &Text"), "viewmagfit", 0, ac, "zoom_fit_text" );
+ connect( d->aZoomFitText, SIGNAL( toggled( bool ) ), SLOT( slotFitToTextToggled( bool ) ) );
+
+ // View-Layout actions
+ d->aViewTwoPages = new KToggleAction( i18n("&Two Pages"), "view_left_right", 0, ac, "view_twopages" );
+ connect( d->aViewTwoPages, SIGNAL( toggled( bool ) ), SLOT( slotTwoPagesToggled( bool ) ) );
+ d->aViewTwoPages->setChecked( KpdfSettings::viewColumns() > 1 );
+
+ d->aViewContinuous = new KToggleAction( i18n("&Continuous"), "view_text", 0, ac, "view_continuous" );
+ connect( d->aViewContinuous, SIGNAL( toggled( bool ) ), SLOT( slotContinuousToggled( bool ) ) );
+ d->aViewContinuous->setChecked( KpdfSettings::viewContinuous() );
+
+ // Mouse-Mode actions
+ d->aMouseNormal = new KRadioAction( i18n("&Browse Tool"), "mouse", 0, this, SLOT( slotSetMouseNormal() ), ac, "mouse_drag" );
+ d->aMouseNormal->setExclusiveGroup( "MouseType" );
+ d->aMouseNormal->setChecked( true );
+
+ KToggleAction * mz = new KRadioAction( i18n("&Zoom Tool"), "viewmag", 0, this, SLOT( slotSetMouseZoom() ), ac, "mouse_zoom" );
+ mz->setExclusiveGroup( "MouseType" );
+
+ d->aMouseSelect = new KRadioAction( i18n("&Select Tool"), "frame_edit", 0, this, SLOT( slotSetMouseSelect() ), ac, "mouse_select" );
+ d->aMouseSelect->setExclusiveGroup( "MouseType" );
+
+/* d->aMouseEdit = new KRadioAction( i18n("Draw"), "edit", 0, this, SLOT( slotSetMouseDraw() ), ac, "mouse_draw" );
+ d->aMouseEdit->setExclusiveGroup("MouseType");
+ d->aMouseEdit->setEnabled( false ); // implement feature before removing this line*/
+
+ // Other actions
+ KAction * su = new KAction( i18n("Scroll Up"), 0, this, SLOT( slotScrollUp() ), ac, "view_scroll_up" );
+ su->setShortcut( "Shift+Up" );
+
+ KAction * sd = new KAction( i18n("Scroll Down"), 0, this, SLOT( slotScrollDown() ), ac, "view_scroll_down" );
+ sd->setShortcut( "Shift+Down" );
+}
+
+bool PageView::canFitPageWidth()
+{
+ return d->zoomMode != ZoomFitWidth;
+}
+
+void PageView::fitPageWidth( int /*page*/ )
+{
+ d->aZoom->setCurrentItem(0);
+ slotZoom();
+}
+
+//BEGIN DocumentObserver inherited methods
+void PageView::notifySetup( const QValueVector< KPDFPage * > & pageSet, bool documentChanged )
+{
+ // reuse current pages if nothing new
+ if ( ( pageSet.count() == d->items.count() ) && !documentChanged )
+ {
+ int count = pageSet.count();
+ for ( int i = 0; (i < count) && !documentChanged; i++ )
+ if ( (int)pageSet[i]->number() != d->items[i]->pageNumber() )
+ documentChanged = true;
+ if ( !documentChanged )
+ return;
+ }
+
+ // delete all widgets (one for each page in pageSet)
+ QValueVector< PageViewItem * >::iterator dIt = d->items.begin(), dEnd = d->items.end();
+ for ( ; dIt != dEnd; ++dIt )
+ delete *dIt;
+ d->items.clear();
+ d->visibleItems.clear();
+
+ // create children widgets
+ QValueVector< KPDFPage * >::const_iterator setIt = pageSet.begin(), setEnd = pageSet.end();
+ for ( ; setIt != setEnd; ++setIt )
+ d->items.push_back( new PageViewItem( *setIt ) );
+
+ if ( pageSet.count() > 0 )
+ // TODO for Enrico: Check if doing always the slotRelayoutPages() is not
+ // suboptimal in some cases, i'd say it is not but a recheck will not hurt
+ // Need slotRelayoutPages() here instead of d->dirtyLayout = true
+ // because opening a pdf from another pdf will not trigger a viewportchange
+ // so pages are never relayouted
+ QTimer::singleShot(0, this, SLOT(slotRelayoutPages()));
+ else
+ {
+ // update the mouse cursor when closing because we may have close through a link and
+ // want the cursor to come back to the normal cursor
+ updateCursor( viewportToContents( mapFromGlobal( QCursor::pos() ) ) );
+ resizeContents( 0, 0 );
+ }
+
+ // OSD to display pages
+ if ( documentChanged && pageSet.count() > 0 && KpdfSettings::showOSD() )
+ d->messageWindow->display(
+ i18n(" Loaded a one-page document.",
+ " Loaded a %n-page document.",
+ pageSet.count() ),
+ PageViewMessage::Info, 4000 );
+}
+
+void PageView::notifyViewportChanged( bool smoothMove )
+{
+ // if we are the one changing viewport, skip this nofity
+ if ( d->blockViewport )
+ return;
+
+ // block setViewport outgoing calls
+ d->blockViewport = true;
+
+ // find PageViewItem matching the viewport description
+ const DocumentViewport & vp = d->document->viewport();
+ PageViewItem * item = 0;
+ QValueVector< PageViewItem * >::iterator iIt = d->items.begin(), iEnd = d->items.end();
+ for ( ; iIt != iEnd; ++iIt )
+ if ( (*iIt)->pageNumber() == vp.pageNumber )
+ {
+ item = *iIt;
+ break;
+ }
+ if ( !item )
+ {
+ kdDebug() << "viewport has no matching item!" << endl;
+ d->blockViewport = false;
+ return;
+ }
+
+ // relayout in "Single Pages" mode or if a relayout is pending
+ d->blockPixmapsRequest = true;
+ if ( !KpdfSettings::viewContinuous() || d->dirtyLayout )
+ slotRelayoutPages();
+
+ // restore viewport center or use default {x-center,v-top} alignment
+ const QRect & r = item->geometry();
+ int newCenterX = r.left(),
+ newCenterY = r.top();
+ if ( vp.rePos.enabled )
+ {
+ if (vp.rePos.pos == DocumentViewport::Center)
+ {
+ newCenterX += (int)( vp.rePos.normalizedX * (double)r.width() );
+ newCenterY += (int)( vp.rePos.normalizedY * (double)r.height() );
+ }
+ else
+ {
+ // TopLeft
+ newCenterX += (int)( vp.rePos.normalizedX * (double)r.width() + viewport()->width() / 2 );
+ newCenterY += (int)( vp.rePos.normalizedY * (double)r.height() + viewport()->height() / 2 );
+ }
+ }
+ else
+ {
+ newCenterX += r.width() / 2;
+ newCenterY += visibleHeight() / 2 - 10;
+ }
+
+ // if smooth movement requested, setup parameters and start it
+ if ( smoothMove )
+ {
+ d->viewportMoveActive = true;
+ d->viewportMoveTime.start();
+ d->viewportMoveDest.setX( newCenterX );
+ d->viewportMoveDest.setY( newCenterY );
+ if ( !d->viewportMoveTimer )
+ {
+ d->viewportMoveTimer = new QTimer( this );
+ connect( d->viewportMoveTimer, SIGNAL( timeout() ),
+ this, SLOT( slotMoveViewport() ) );
+ }
+ d->viewportMoveTimer->start( 25 );
+ verticalScrollBar()->setEnabled( false );
+ horizontalScrollBar()->setEnabled( false );
+ }
+ else
+ center( newCenterX, newCenterY );
+ d->blockPixmapsRequest = false;
+
+ // request visible pixmaps in the current viewport and recompute it
+ slotRequestVisiblePixmaps();
+
+ // enable setViewport calls
+ d->blockViewport = false;
+
+ // update zoom text if in a ZoomFit/* zoom mode
+ if ( d->zoomMode != ZoomFixed )
+ updateZoomText();
+
+ // since the page has moved below cursor, update it
+ updateCursor( viewportToContents( mapFromGlobal( QCursor::pos() ) ) );
+}
+
+void PageView::notifyPageChanged( int pageNumber, int changedFlags )
+{
+ // only handle pixmap / highlight changes notifies
+ if ( changedFlags & DocumentObserver::Bookmark )
+ return;
+
+ // iterate over visible items: if page(pageNumber) is one of them, repaint it
+ QValueList< PageViewItem * >::iterator iIt = d->visibleItems.begin(), iEnd = d->visibleItems.end();
+ for ( ; iIt != iEnd; ++iIt )
+ if ( (*iIt)->pageNumber() == pageNumber )
+ {
+ // update item's rectangle plus the little outline
+ QRect expandedRect = (*iIt)->geometry();
+ expandedRect.addCoords( -1, -1, 3, 3 );
+ updateContents( expandedRect );
+
+ // if we were "zoom-dragging" do not overwrite the "zoom-drag" cursor
+ if ( cursor().shape() != Qt::SizeVerCursor )
+ {
+ // since the page has been regenerated below cursor, update it
+ updateCursor( viewportToContents( mapFromGlobal( QCursor::pos() ) ) );
+ }
+ break;
+ }
+}
+
+void PageView::notifyContentsCleared( int changedFlags )
+{
+ // if pixmaps were cleared, re-ask them
+ if ( changedFlags & DocumentObserver::Pixmap )
+ slotRequestVisiblePixmaps();
+}
+
+bool PageView::canUnloadPixmap( int pageNumber )
+{
+ // if the item is visible, forbid unloading
+ QValueList< PageViewItem * >::iterator vIt = d->visibleItems.begin(), vEnd = d->visibleItems.end();
+ for ( ; vIt != vEnd; ++vIt )
+ if ( (*vIt)->pageNumber() == pageNumber )
+ return false;
+ // if hidden premit unloading
+ return true;
+}
+//END DocumentObserver inherited methods
+
+
+void PageView::showText( const QString &text, int ms )
+{
+ d->messageWindow->display(text, PageViewMessage::Info, ms );
+}
+
+
+//BEGIN widget events
+void PageView::viewportPaintEvent( QPaintEvent * pe )
+{
+ // create the rect into contents from the clipped screen rect
+ QRect viewportRect = viewport()->rect();
+ QRect contentsRect = pe->rect().intersect( viewportRect );
+ contentsRect.moveBy( contentsX(), contentsY() );
+ if ( !contentsRect.isValid() )
+ return;
+
+ // create the screen painter. a pixel painted ar contentsX,contentsY
+ // appears to the top-left corner of the scrollview.
+ QPainter screenPainter( viewport(), true );
+ screenPainter.translate( -contentsX(), -contentsY() );
+
+ // selectionRect is the normalized mouse selection rect
+ QRect selectionRect = d->mouseSelectionRect;
+ if ( !selectionRect.isNull() )
+ selectionRect = selectionRect.normalize();
+ // selectionRectInternal without the border
+ QRect selectionRectInternal = selectionRect;
+ selectionRectInternal.addCoords( 1, 1, -1, -1 );
+ // color for blending
+ QColor selBlendColor = (selectionRect.width() > 8 || selectionRect.height() > 8) ?
+ d->selectionRectColor : Qt::red;
+
+ // subdivide region into rects
+ QMemArray<QRect> allRects = pe->region().rects();
+ uint numRects = allRects.count();
+
+ // preprocess rects area to see if it worths or not using subdivision
+ uint summedArea = 0;
+ for ( uint i = 0; i < numRects; i++ )
+ {
+ const QRect & r = allRects[i];
+ summedArea += r.width() * r.height();
+ }
+ // very elementary check: SUMj(Region[j].area) is less than boundingRect.area
+ bool useSubdivision = summedArea < (0.7 * contentsRect.width() * contentsRect.height());
+ if ( !useSubdivision )
+ numRects = 1;
+
+ // iterate over the rects (only one loop if not using subdivision)
+ for ( uint i = 0; i < numRects; i++ )
+ {
+ if ( useSubdivision )
+ {
+ // set 'contentsRect' to a part of the sub-divided region
+ contentsRect = allRects[i].normalize().intersect( viewportRect );
+ contentsRect.moveBy( contentsX(), contentsY() );
+ if ( !contentsRect.isValid() )
+ continue;
+ }
+
+ // note: this check will take care of all things requiring alpha blending (not only selection)
+ bool wantCompositing = !selectionRect.isNull() && contentsRect.intersects( selectionRect );
+
+ if ( wantCompositing && KpdfSettings::enableCompositing() )
+ {
+ // create pixmap and open a painter over it (contents{left,top} becomes pixmap {0,0})
+ QPixmap doubleBuffer( contentsRect.size() );
+ QPainter pixmapPainter( &doubleBuffer );
+ pixmapPainter.translate( -contentsRect.left(), -contentsRect.top() );
+
+ // 1) Layer 0: paint items and clear bg on unpainted rects
+ paintItems( &pixmapPainter, contentsRect );
+ // 2) Layer 1: pixmap manipulated areas
+ // 3) Layer 2: paint (blend) transparent selection
+ if ( !selectionRect.isNull() && selectionRect.intersects( contentsRect ) &&
+ !selectionRectInternal.contains( contentsRect ) )
+ {
+ QRect blendRect = selectionRectInternal.intersect( contentsRect );
+ // skip rectangles covered by the selection's border
+ if ( blendRect.isValid() )
+ {
+ // grab current pixmap into a new one to colorize contents
+ QPixmap blendedPixmap( blendRect.width(), blendRect.height() );
+ copyBlt( &blendedPixmap, 0,0, &doubleBuffer,
+ blendRect.left() - contentsRect.left(), blendRect.top() - contentsRect.top(),
+ blendRect.width(), blendRect.height() );
+ // blend selBlendColor into the background pixmap
+ QImage blendedImage = blendedPixmap.convertToImage();
+ KImageEffect::blend( selBlendColor.dark(140), blendedImage, 0.2 );
+ // copy the blended pixmap back to its place
+ pixmapPainter.drawPixmap( blendRect.left(), blendRect.top(), blendedImage );
+ }
+ // draw border (red if the selection is too small)
+ pixmapPainter.setPen( selBlendColor );
+ pixmapPainter.drawRect( selectionRect );
+ }
+ // 4) Layer 3: overlays
+ if ( KpdfSettings::debugDrawBoundaries() )
+ {
+ pixmapPainter.setPen( Qt::blue );
+ pixmapPainter.drawRect( contentsRect );
+ }
+
+ // finish painting and draw contents
+ pixmapPainter.end();
+ screenPainter.drawPixmap( contentsRect.left(), contentsRect.top(), doubleBuffer );
+ }
+ else
+ {
+ // 1) Layer 0: paint items and clear bg on unpainted rects
+ paintItems( &screenPainter, contentsRect );
+ // 2) Layer 1: opaque manipulated ares (filled / contours)
+ // 3) Layer 2: paint opaque selection
+ if ( !selectionRect.isNull() && selectionRect.intersects( contentsRect ) &&
+ !selectionRectInternal.contains( contentsRect ) )
+ {
+ screenPainter.setPen( palette().active().highlight().dark(110) );
+ screenPainter.drawRect( selectionRect );
+ }
+ // 4) Layer 3: overlays
+ if ( KpdfSettings::debugDrawBoundaries() )
+ {
+ screenPainter.setPen( Qt::red );
+ screenPainter.drawRect( contentsRect );
+ }
+ }
+ }
+}
+
+void PageView::viewportResizeEvent( QResizeEvent * )
+{
+ // start a timer that will refresh the pixmap after 0.5s
+ if ( !d->delayResizeTimer )
+ {
+ d->delayResizeTimer = new QTimer( this );
+ connect( d->delayResizeTimer, SIGNAL( timeout() ), this, SLOT( slotRelayoutPages() ) );
+ }
+ d->delayResizeTimer->start( 333, true );
+}
+
+void PageView::keyPressEvent( QKeyEvent * e )
+{
+ e->accept();
+
+ // if performing a selection or dyn zooming, disable keys handling
+ if ( ( !d->mouseSelectionRect.isNull() && e->key() != Qt::Key_Escape ) || d->mouseMidStartY != -1 )
+ return;
+
+ // handle 'find as you type' (based on khtml/khtmlview.cpp)
+ if( d->typeAheadActive )
+ {
+ // backspace: remove a char and search or terminates search
+ if( e->key() == Key_BackSpace )
+ {
+ if( d->typeAheadString.length() > 1 )
+ {
+ d->typeAheadString = d->typeAheadString.left( d->typeAheadString.length() - 1 );
+ bool found = d->document->searchText( PAGEVIEW_SEARCH_ID, d->typeAheadString, true, false,
+ KPDFDocument::NextMatch, true, qRgb( 128, 255, 128 ), true );
+ QString status = found ? i18n("Text found: \"%1\".") : i18n("Text not found: \"%1\".");
+ d->messageWindow->display( status.arg(d->typeAheadString.lower()),
+ found ? PageViewMessage::Find : PageViewMessage::Warning, 4000 );
+ d->findTimeoutTimer->start( 3000, true );
+ }
+ else
+ {
+ findAheadStop();
+ d->document->resetSearch( PAGEVIEW_SEARCH_ID );
+ }
+ }
+ // F3: go to next occurrency
+ else if( e->key() == KStdAccel::findNext() )
+ {
+ // part doesn't get this key event because of the keyboard grab
+ d->findTimeoutTimer->stop(); // restore normal operation during possible messagebox is displayed
+ // it is needed to grab the keyboard becase people may have Space assigned to a
+ // accel and without grabbing the keyboard you can not vim-search for space
+ // because it activates the accel
+ releaseKeyboard();
+ if ( d->document->continueSearch( PAGEVIEW_SEARCH_ID ) )
+ d->messageWindow->display( i18n("Text found: \"%1\".").arg(d->typeAheadString.lower()),
+ PageViewMessage::Find, 3000 );
+ d->findTimeoutTimer->start( 3000, true );
+ // it is needed to grab the keyboard becase people may have Space assigned to a
+ // accel and without grabbing the keyboard you can not vim-search for space
+ // because it activates the accel
+ grabKeyboard();
+ }
+ // esc and return: end search
+ else if( e->key() == Key_Escape || e->key() == Key_Return )
+ {
+ findAheadStop();
+ }
+ // other key: add to text and search
+ else if( !e->text().isEmpty() )
+ {
+ d->typeAheadString += e->text();
+ doTypeAheadSearch();
+ }
+ return;
+ }
+ else if( e->key() == '/' && d->document->isOpened() && d->document->supportsSearching() )
+ {
+ // stop scrolling the page (if doing it)
+ if ( d->autoScrollTimer )
+ {
+ d->scrollIncrement = 0;
+ d->autoScrollTimer->stop();
+ }
+ // start type-adeas search
+ d->typeAheadString = QString();
+ d->messageWindow->display( i18n("Starting -- find text as you type"), PageViewMessage::Find, 3000 );
+ d->typeAheadActive = true;
+ if ( !d->findTimeoutTimer )
+ {
+ // create the timer on demand
+ d->findTimeoutTimer = new QTimer( this );
+ connect( d->findTimeoutTimer, SIGNAL( timeout() ), this, SLOT( findAheadStop() ) );
+ }
+ d->findTimeoutTimer->start( 3000, true );
+ // it is needed to grab the keyboard becase people may have Space assigned to a
+ // accel and without grabbing the keyboard you can not vim-search for space
+ // because it activates the accel
+ grabKeyboard();
+ return;
+ }
+
+ // if viewport is moving, disable keys handling
+ if ( d->viewportMoveActive )
+ return;
+
+ // move/scroll page by using keys
+ switch ( e->key() )
+ {
+ case Key_Up:
+ case Key_PageUp:
+ case Key_Backspace:
+ // if in single page mode and at the top of the screen, go to previous page
+ if ( KpdfSettings::viewContinuous() || verticalScrollBar()->value() > verticalScrollBar()->minValue() )
+ {
+ if ( e->key() == Key_Up )
+ verticalScrollBar()->subtractLine();
+ else
+ verticalScrollBar()->subtractPage();
+ }
+ else if ( d->document->currentPage() > 0 )
+ {
+ // more optimized than document->setPrevPage and then move view to bottom
+ DocumentViewport newViewport = d->document->viewport();
+ newViewport.pageNumber -= 1;
+ newViewport.rePos.enabled = true;
+ newViewport.rePos.normalizedY = 1.0;
+ d->document->setViewport( newViewport );
+ }
+ break;
+ case Key_Down:
+ case Key_PageDown:
+ case Key_Space:
+ // if in single page mode and at the bottom of the screen, go to next page
+ if ( KpdfSettings::viewContinuous() || verticalScrollBar()->value() < verticalScrollBar()->maxValue() )
+ {
+ if ( e->key() == Key_Down )
+ verticalScrollBar()->addLine();
+ else
+ verticalScrollBar()->addPage();
+ }
+ else if ( d->document->currentPage() < d->items.count() - 1 )
+ {
+ // more optmized than document->setNextPage and then move view to top
+ DocumentViewport newViewport = d->document->viewport();
+ newViewport.pageNumber += 1;
+ newViewport.rePos.enabled = true;
+ newViewport.rePos.normalizedY = 0.0;
+ d->document->setViewport( newViewport );
+ }
+ break;
+ case Key_Left:
+ horizontalScrollBar()->subtractLine();
+ break;
+ case Key_Right:
+ horizontalScrollBar()->addLine();
+ break;
+ case Qt::Key_Escape:
+ selectionClear();
+ d->mousePressPos = QPoint();
+ if ( d->aPrevAction )
+ {
+ d->aPrevAction->activate();
+ d->aPrevAction = 0;
+ }
+ break;
+ case Key_Shift:
+ case Key_Control:
+ if ( d->autoScrollTimer )
+ {
+ if ( d->autoScrollTimer->isActive() )
+ d->autoScrollTimer->stop();
+ else
+ slotAutoScoll();
+ return;
+ }
+ // else fall trhough
+ default:
+ e->ignore();
+ return;
+ }
+ // if a known key has been pressed, stop scrolling the page
+ if ( d->autoScrollTimer )
+ {
+ d->scrollIncrement = 0;
+ d->autoScrollTimer->stop();
+ }
+}
+
+void PageView::imEndEvent( QIMEvent * e )
+{
+ if( d->typeAheadActive )
+ {
+ if( !e->text().isEmpty() )
+ {
+ d->typeAheadString += e->text();
+ doTypeAheadSearch();
+ e->accept();
+ }
+ }
+}
+
+void PageView::contentsMouseMoveEvent( QMouseEvent * e )
+{
+ // don't perform any mouse action when no document is shown
+ if ( d->items.isEmpty() )
+ return;
+
+ // don't perform any mouse action when viewport is autoscrolling
+ if ( d->viewportMoveActive )
+ return;
+
+ // if holding mouse mid button, perform zoom
+ if ( (e->state() & MidButton) && d->mouseMidStartY >= 0 )
+ {
+ int deltaY = d->mouseMidStartY - e->globalPos().y();
+ d->mouseMidStartY = e->globalPos().y();
+ d->zoomFactor *= ( 1.0 + ( (double)deltaY / 500.0 ) );
+ updateZoom( ZoomRefreshCurrent );
+ // uncomment following line to force a complete redraw
+ viewport()->repaint( false );
+ return;
+ }
+
+ bool leftButton = e->state() & LeftButton,
+ rightButton = e->state() & RightButton;
+ switch ( d->mouseMode )
+ {
+ case MouseNormal:
+ if ( leftButton )
+ {
+ // drag page
+ if ( !d->mouseGrabPos.isNull() )
+ {
+ // scroll page by position increment
+ QPoint delta = d->mouseGrabPos - e->globalPos();
+ scrollBy( delta.x(), delta.y() );
+ d->mouseGrabPos = e->globalPos();
+ }
+ }
+ else if ( rightButton && !d->mousePressPos.isNull() )
+ {
+ // if mouse moves 5 px away from the press point, switch to 'selection'
+ int deltaX = d->mousePressPos.x() - e->globalPos().x(),
+ deltaY = d->mousePressPos.y() - e->globalPos().y();
+ if ( deltaX > 5 || deltaX < -5 || deltaY > 5 || deltaY < -5 )
+ {
+ d->aPrevAction = d->aMouseNormal;
+ d->aMouseSelect->activate();
+ QColor selColor = palette().active().highlight().light( 120 );
+ selectionStart( e->x() + deltaX, e->y() + deltaY, selColor, false );
+ selectionEndPoint( e->x(), e->y() );
+ break;
+ }
+ }
+ else
+ {
+ // only hovering the page, so update the cursor
+ updateCursor( e->pos() );
+ }
+ break;
+
+ case MouseZoom:
+ case MouseSelect:
+ // set second corner of selection
+ if ( !d->mousePressPos.isNull() && ( leftButton || d->aPrevAction ) )
+ selectionEndPoint( e->x(), e->y() );
+ break;
+
+ case MouseEdit: // ? update graphics ?
+ break;
+ }
+}
+
+void PageView::contentsMousePressEvent( QMouseEvent * e )
+{
+ // don't perform any mouse action when no document is shown
+ if ( d->items.isEmpty() )
+ return;
+
+ // if performing a selection or dyn zooming, disable mouse press
+ if ( !d->mouseSelectionRect.isNull() || d->mouseMidStartY != -1 ||
+ d->viewportMoveActive )
+ return;
+
+ // if the page is scrolling, stop it
+ if ( d->autoScrollTimer )
+ {
+ d->scrollIncrement = 0;
+ d->autoScrollTimer->stop();
+ }
+
+ // if pressing mid mouse button while not doing other things, begin 'comtinous zoom' mode
+ if ( e->button() & MidButton )
+ {
+ d->mouseMidStartY = e->globalPos().y();
+ setCursor( KCursor::sizeVerCursor() );
+ return;
+ }
+
+ // update press / 'start drag' mouse position
+ d->mousePressPos = e->globalPos();
+
+ // handle mode dependant mouse press actions
+ bool leftButton = e->button() & LeftButton,
+ rightButton = e->button() & RightButton;
+ switch ( d->mouseMode )
+ {
+ case MouseNormal: // drag start / click / link following
+ if ( leftButton )
+ {
+ d->mouseGrabPos = d->mouseOnRect ? QPoint() : d->mousePressPos;
+ if ( !d->mouseOnRect )
+ setCursor( KCursor::sizeAllCursor() );
+ }
+ break;
+
+ case MouseZoom: // set first corner of the zoom rect
+ if ( leftButton )
+ selectionStart( e->x(), e->y(), palette().active().highlight(), false );
+ else if ( rightButton )
+ updateZoom( ZoomOut );
+ break;
+
+ case MouseSelect: // set first corner of the selection rect
+ if ( leftButton )
+ {
+ QColor selColor = palette().active().highlight().light( 120 );
+ selectionStart( e->x(), e->y(), selColor, false );
+ }
+ break;
+
+ case MouseEdit: // ..to do..
+ break;
+ }
+}
+
+void PageView::contentsMouseReleaseEvent( QMouseEvent * e )
+{
+ // stop the drag scrolling
+ d->dragScrollTimer.stop();
+
+ // don't perform any mouse action when no document is shown
+ if ( d->items.isEmpty() )
+ {
+ // ..except for right Clicks (emitted even it viewport is empty)
+ if ( e->button() == RightButton )
+ emit rightClick( 0, e->globalPos() );
+ return;
+ }
+
+ // don't perform any mouse action when viewport is autoscrolling
+ if ( d->viewportMoveActive )
+ return;
+
+ // handle mode indepent mid buttom zoom
+ bool midButton = e->button() & MidButton;
+ if ( midButton && d->mouseMidStartY > 0 )
+ {
+ d->mouseMidStartY = -1;
+ // while drag-zooming we could have gone over a link
+ updateCursor( e->pos() );
+ return;
+ }
+
+ bool leftButton = e->button() & LeftButton,
+ rightButton = e->button() & RightButton;
+ switch ( d->mouseMode )
+ {
+ case MouseNormal:{
+ // return the cursor to its normal state after dragging
+ if ( cursor().shape() == Qt::SizeAllCursor )
+ updateCursor( e->pos() );
+
+ PageViewItem * pageItem = pickItemOnPoint( e->x(), e->y() );
+
+ // if the mouse has not moved since the press, that's a -click-
+ if ( leftButton && pageItem && d->mousePressPos == e->globalPos())
+ {
+ double nX = (double)(e->x() - pageItem->geometry().left()) / (double)pageItem->width(),
+ nY = (double)(e->y() - pageItem->geometry().top()) / (double)pageItem->height();
+ const ObjectRect * linkRect, * imageRect;
+ linkRect = pageItem->page()->hasObject( ObjectRect::Link, nX, nY );
+ if ( linkRect )
+ {
+ // handle click over a link
+ const KPDFLink * link = static_cast< const KPDFLink * >( linkRect->pointer() );
+ d->document->processLink( link );
+ }
+ else
+ {
+ // a link can move us to another page or even to another document, there's no point in trying to process the click on the image once we have processes the click on the link
+ imageRect = pageItem->page()->hasObject( ObjectRect::Image, nX, nY );
+ if ( imageRect )
+ {
+ // handle click over a image
+ }
+ // Enrico and me have decided this is not worth the trouble it generates
+ // else
+ // {
+ // if not on a rect, the click selects the page
+ // d->document->setViewportPage( pageItem->pageNumber(), PAGEVIEW_ID );
+ // }
+ }
+ }
+ else if ( rightButton )
+ {
+ // right click (if not within 5 px of the press point, the mode
+ // had been already changed to 'Selection' instead of 'Normal')
+ emit rightClick( pageItem ? pageItem->page() : 0, e->globalPos() );
+ }
+ }break;
+
+ case MouseZoom:
+ // if a selection rect has been defined, zoom into it
+ if ( leftButton && !d->mouseSelectionRect.isNull() )
+ {
+ QRect selRect = d->mouseSelectionRect.normalize();
+ if ( selRect.width() <= 8 && selRect.height() <= 8 )
+ {
+ selectionClear();
+ break;
+ }
+
+ // find out new zoom ratio and normalized view center (relative to the contentsRect)
+ double zoom = QMIN( (double)visibleWidth() / (double)selRect.width(), (double)visibleHeight() / (double)selRect.height() );
+ double nX = (double)(selRect.left() + selRect.right()) / (2.0 * (double)contentsWidth());
+ double nY = (double)(selRect.top() + selRect.bottom()) / (2.0 * (double)contentsHeight());
+
+ // zoom up to 400%
+ if ( d->zoomFactor <= 4.0 || zoom <= 1.0 )
+ {
+ d->zoomFactor *= zoom;
+ viewport()->setUpdatesEnabled( false );
+ updateZoom( ZoomRefreshCurrent );
+ viewport()->setUpdatesEnabled( true );
+ }
+
+ // recenter view and update the viewport
+ center( (int)(nX * contentsWidth()), (int)(nY * contentsHeight()) );
+ updateContents();
+
+ // hide message box and delete overlay window
+ selectionClear();
+ }
+ break;
+
+ case MouseSelect:{
+
+ if (d->mouseSelectionRect.isNull() && rightButton)
+ {
+ PageViewItem * pageItem = pickItemOnPoint( e->x(), e->y() );
+ emit rightClick( pageItem ? pageItem->page() : 0, e->globalPos() );
+ }
+
+ // if a selection is defined, display a popup
+ if ( (!leftButton && !d->aPrevAction) || (leftButton && d->aPrevAction) ||
+ d->mouseSelectionRect.isNull() )
+ break;
+
+ QRect selectionRect = d->mouseSelectionRect.normalize();
+ if ( selectionRect.width() <= 8 && selectionRect.height() <= 8 )
+ {
+ selectionClear();
+ if ( d->aPrevAction )
+ {
+ d->aPrevAction->activate();
+ d->aPrevAction = 0;
+ }
+ break;
+ }
+
+ // grab text in selection by extracting it from all intersected pages
+ QString selectedText;
+ QValueVector< PageViewItem * >::iterator iIt = d->items.begin(), iEnd = d->items.end();
+ for ( ; iIt != iEnd; ++iIt )
+ {
+ PageViewItem * item = *iIt;
+ const QRect & itemRect = item->geometry();
+ if ( selectionRect.intersects( itemRect ) )
+ {
+ // request the textpage if there isn't one
+ const KPDFPage * kpdfPage = item->page();
+ if ( !kpdfPage->hasSearchPage() )
+ d->document->requestTextPage( kpdfPage->number() );
+ // grab text in the rect that intersects itemRect
+ QRect relativeRect = selectionRect.intersect( itemRect );
+ relativeRect.moveBy( -itemRect.left(), -itemRect.top() );
+ NormalizedRect normRect( relativeRect, item->width(), item->height() );
+ selectedText += kpdfPage->getText( normRect );
+ }
+ }
+
+ // popup that ask to copy:text and copy/save:image
+ KPopupMenu menu( this );
+ if ( !selectedText.isEmpty() )
+ {
+ menu.insertTitle( i18n( "Text (1 character)", "Text (%n characters)", selectedText.length() ) );
+ menu.insertItem( SmallIcon("editcopy"), i18n( "Copy to Clipboard" ), 1 );
+ if ( !d->document->isAllowed( KPDFDocument::AllowCopy ) )
+ menu.setItemEnabled( 1, false );
+ if ( KpdfSettings::useKTTSD() )
+ menu.insertItem( SmallIcon("kttsd"), i18n( "Speak Text" ), 2 );
+ }
+ menu.insertTitle( i18n( "Image (%1 by %2 pixels)" ).arg( selectionRect.width() ).arg( selectionRect.height() ) );
+ menu.insertItem( SmallIcon("image"), i18n( "Copy to Clipboard" ), 3 );
+ menu.insertItem( SmallIcon("filesave"), i18n( "Save to File..." ), 4 );
+ int choice = menu.exec( e->globalPos() );
+ // IMAGE operation choosen
+ if ( choice > 2 )
+ {
+ // renders page into a pixmap
+ QPixmap copyPix( selectionRect.width(), selectionRect.height() );
+ QPainter copyPainter( &copyPix );
+ copyPainter.translate( -selectionRect.left(), -selectionRect.top() );
+ paintItems( &copyPainter, selectionRect );
+
+ if ( choice == 3 )
+ {
+ // [2] copy pixmap to clipboard
+ QClipboard *cb = QApplication::clipboard();
+ cb->setPixmap( copyPix, QClipboard::Clipboard );
+ if ( cb->supportsSelection() )
+ cb->setPixmap( copyPix, QClipboard::Selection );
+ d->messageWindow->display( i18n( "Image [%1x%2] copied to clipboard." ).arg( copyPix.width() ).arg( copyPix.height() ) );
+ }
+ else if ( choice == 4 )
+ {
+ // [3] save pixmap to file
+ QString fileName = KFileDialog::getSaveFileName( QString::null, "image/png image/jpeg", this );
+ if ( fileName.isNull() )
+ d->messageWindow->display( i18n( "File not saved." ), PageViewMessage::Warning );
+ else
+ {
+ QString type( KImageIO::type( fileName ) );
+ if ( type.isNull() )
+ type = "PNG";
+ copyPix.save( fileName, type.latin1() );
+ d->messageWindow->display( i18n( "Image [%1x%2] saved to %3 file." ).arg( copyPix.width() ).arg( copyPix.height() ).arg( type ) );
+ }
+ }
+ }
+ // TEXT operation choosen
+ else
+ {
+ if ( choice == 1 )
+ {
+ // [1] copy text to clipboard
+ QClipboard *cb = QApplication::clipboard();
+ cb->setText( selectedText, QClipboard::Clipboard );
+ if ( cb->supportsSelection() )
+ cb->setText( selectedText, QClipboard::Selection );
+ }
+ else if ( choice == 2 )
+ {
+ // [2] speech selection using KTTSD
+ DCOPClient * client = DCOPClient::mainClient();
+ // Albert says is this ever necessary?
+ // we already attached on Part constructor
+ // if ( !client->isAttached() )
+ // client->attach();
+ // If KTTSD not running, start it.
+ if (!client->isApplicationRegistered("kttsd"))
+ {
+ QString error;
+ if (KApplication::startServiceByDesktopName("kttsd", QStringList(), &error))
+ {
+ d->messageWindow->display( i18n("Starting KTTSD Failed: %1").arg(error) );
+ KpdfSettings::setUseKTTSD(false);
+ KpdfSettings::writeConfig();
+ }
+ }
+ if ( KpdfSettings::useKTTSD() )
+ {
+ // serialize the text to speech (selectedText) and the
+ // preferred reader ("" is the default voice) ...
+ QByteArray data;
+ QDataStream arg( data, IO_WriteOnly );
+ arg << selectedText;
+ arg << QString();
+ QCString replyType;
+ QByteArray replyData;
+ // ..and send it to KTTSD
+ if (client->call( "kttsd", "KSpeech", "setText(QString,QString)", data, replyType, replyData, true ))
+ {
+ QByteArray data2;
+ QDataStream arg2(data2, IO_WriteOnly);
+ arg2 << 0;
+ client->send("kttsd", "KSpeech", "startText(uint)", data2 );
+ }
+ }
+ }
+ }
+
+ // clear widget selection and invalidate rect
+ selectionClear();
+
+ // restore previous action if came from it using right button
+ if ( d->aPrevAction )
+ {
+ d->aPrevAction->activate();
+ d->aPrevAction = 0;
+ }
+ }break;
+
+ case MouseEdit: // ? apply [tool] ?
+ break;
+ }
+
+ // reset mouse press / 'drag start' position
+ d->mousePressPos = QPoint();
+}
+
+void PageView::wheelEvent( QWheelEvent *e )
+{
+ // don't perform any mouse action when viewport is autoscrolling
+ if ( d->viewportMoveActive )
+ return;
+
+ if ( !d->document->isOpened() )
+ {
+ QScrollView::wheelEvent( e );
+ return;
+ }
+
+ int delta = e->delta(),
+ vScroll = verticalScrollBar()->value();
+ e->accept();
+ if ( (e->state() & ControlButton) == ControlButton ) {
+ if ( e->delta() < 0 )
+ slotZoomOut();
+ else
+ slotZoomIn();
+ }
+ else if ( delta <= -120 && !KpdfSettings::viewContinuous() && vScroll == verticalScrollBar()->maxValue() )
+ {
+ // go to next page
+ if ( d->document->currentPage() < d->items.count() - 1 )
+ {
+ // more optmized than document->setNextPage and then move view to top
+ DocumentViewport newViewport = d->document->viewport();
+ newViewport.pageNumber += 1;
+ newViewport.rePos.enabled = true;
+ newViewport.rePos.normalizedY = 0.0;
+ d->document->setViewport( newViewport );
+ }
+ }
+ else if ( delta >= 120 && !KpdfSettings::viewContinuous() && vScroll == verticalScrollBar()->minValue() )
+ {
+ // go to prev page
+ if ( d->document->currentPage() > 0 )
+ {
+ // more optmized than document->setPrevPage and then move view to bottom
+ DocumentViewport newViewport = d->document->viewport();
+ newViewport.pageNumber -= 1;
+ newViewport.rePos.enabled = true;
+ newViewport.rePos.normalizedY = 1.0;
+ d->document->setViewport( newViewport );
+ }
+ }
+ else
+ QScrollView::wheelEvent( e );
+
+ QPoint cp = viewportToContents(e->pos());
+ updateCursor(cp);
+}
+
+void PageView::dragEnterEvent( QDragEnterEvent * ev )
+{
+ ev->accept();
+}
+
+void PageView::dropEvent( QDropEvent * ev )
+{
+ KURL::List lst;
+ if ( KURLDrag::decode( ev, lst ) )
+ emit urlDropped( lst.first() );
+}
+//END widget events
+
+void PageView::paintItems( QPainter * p, const QRect & contentsRect )
+{
+ // when checking if an Item is contained in contentsRect, instead of
+ // growing PageViewItems rects (for keeping outline into account), we
+ // grow the contentsRect
+ QRect checkRect = contentsRect;
+ checkRect.addCoords( -3, -3, 1, 1 );
+
+ // create a region from wich we'll subtract painted rects
+ QRegion remainingArea( contentsRect );
+
+ //QValueVector< PageViewItem * >::iterator iIt = d->visibleItems.begin(), iEnd = d->visibleItems.end();
+ QValueVector< PageViewItem * >::iterator iIt = d->items.begin(), iEnd = d->items.end();
+ for ( ; iIt != iEnd; ++iIt )
+ {
+ // check if a piece of the page intersects the contents rect
+ if ( !(*iIt)->geometry().intersects( checkRect ) )
+ continue;
+
+ PageViewItem * item = *iIt;
+ QRect pixmapGeometry = item->geometry();
+
+ // translate the painter so we draw top-left pixmap corner in 0,0
+ p->save();
+ p->translate( pixmapGeometry.left(), pixmapGeometry.top() );
+
+ // item pixmap and outline geometry
+ QRect outlineGeometry = pixmapGeometry;
+ outlineGeometry.addCoords( -1, -1, 3, 3 );
+
+ // draw the page outline (little black border and 2px shadow)
+ if ( !pixmapGeometry.contains( contentsRect ) )
+ {
+ int pixmapWidth = pixmapGeometry.width(),
+ pixmapHeight = pixmapGeometry.height();
+ // draw simple outline
+ p->setPen( Qt::black );
+ p->drawRect( -1, -1, pixmapWidth + 2, pixmapHeight + 2 );
+ // draw bottom/right gradient
+ int levels = 2;
+ int r = Qt::gray.red() / (levels + 2),
+ g = Qt::gray.green() / (levels + 2),
+ b = Qt::gray.blue() / (levels + 2);
+ for ( int i = 0; i < levels; i++ )
+ {
+ p->setPen( QColor( r * (i+2), g * (i+2), b * (i+2) ) );
+ p->drawLine( i, i + pixmapHeight + 1, i + pixmapWidth + 1, i + pixmapHeight + 1 );
+ p->drawLine( i + pixmapWidth + 1, i, i + pixmapWidth + 1, i + pixmapHeight );
+ p->setPen( Qt::gray );
+ p->drawLine( -1, i + pixmapHeight + 1, i - 1, i + pixmapHeight + 1 );
+ p->drawLine( i + pixmapWidth + 1, -1, i + pixmapWidth + 1, i - 1 );
+ }
+ }
+
+ // draw the pixmap (note: this modifies the painter)
+ if ( contentsRect.intersects( pixmapGeometry ) )
+ {
+ QRect pixmapRect = contentsRect.intersect( pixmapGeometry );
+ pixmapRect.moveBy( -pixmapGeometry.left(), -pixmapGeometry.top() );
+ int flags = PagePainter::Accessibility | PagePainter::EnhanceLinks |
+ PagePainter::EnhanceImages | PagePainter::Highlights;
+ PagePainter::paintPageOnPainter( item->page(), PAGEVIEW_ID, flags, p, pixmapRect,
+ pixmapGeometry.width(), pixmapGeometry.height() );
+ }
+
+ // remove painted area from 'remainingArea' and restore painter
+ remainingArea -= outlineGeometry.intersect( contentsRect );
+ p->restore();
+ }
+
+ // paint with background color the unpainted area
+ QMemArray<QRect> backRects = remainingArea.rects();
+ uint backRectsNumber = backRects.count();
+ for ( uint jr = 0; jr < backRectsNumber; jr++ )
+ p->fillRect( backRects[ jr ], Qt::gray );
+}
+
+void PageView::updateItemSize( PageViewItem * item, int colWidth, int rowHeight )
+{
+ const KPDFPage * kpdfPage = item->page();
+ double width = kpdfPage->width(),
+ height = kpdfPage->height(),
+ zoom = d->zoomFactor;
+
+ if ( d->zoomMode == ZoomFixed )
+ {
+ width *= zoom;
+ height *= zoom;
+ item->setWHZ( (int)width, (int)height, d->zoomFactor );
+ }
+ else if ( d->zoomMode == ZoomFitWidth )
+ {
+ height = kpdfPage->ratio() * colWidth;
+ item->setWHZ( colWidth, (int)height, (double)colWidth / width );
+ d->zoomFactor = (double)colWidth / width;
+ }
+ else if ( d->zoomMode == ZoomFitPage )
+ {
+ double scaleW = (double)colWidth / (double)width;
+ double scaleH = (double)rowHeight / (double)height;
+ zoom = QMIN( scaleW, scaleH );
+ item->setWHZ( (int)(zoom * width), (int)(zoom * height), zoom );
+ d->zoomFactor = zoom;
+ }
+#ifndef NDEBUG
+ else
+ kdDebug() << "calling updateItemSize with unrecognized d->zoomMode!" << endl;
+#endif
+}
+
+PageViewItem * PageView::pickItemOnPoint( int x, int y )
+{
+ PageViewItem * item = 0;
+ QValueList< PageViewItem * >::iterator iIt = d->visibleItems.begin(), iEnd = d->visibleItems.end();
+ for ( ; iIt != iEnd; ++iIt )
+ {
+ PageViewItem * i = *iIt;
+ const QRect & r = i->geometry();
+ if ( x < r.right() && x > r.left() && y < r.bottom() )
+ {
+ if ( y > r.top() )
+ item = i;
+ break;
+ }
+ }
+ return item;
+}
+
+void PageView::selectionStart( int x, int y, const QColor & color, bool /*aboveAll*/ )
+{
+ d->mouseSelectionRect.setRect( x, y, 1, 1 );
+ d->selectionRectColor = color;
+ // ensures page doesn't scroll
+ if ( d->autoScrollTimer )
+ {
+ d->scrollIncrement = 0;
+ d->autoScrollTimer->stop();
+ }
+}
+
+void PageView::selectionEndPoint( int x, int y )
+{
+ if (x < contentsX()) d->dragScrollVector.setX(x - contentsX());
+ else if (contentsX() + viewport()->width() < x) d->dragScrollVector.setX(x - contentsX() - viewport()->width());
+ else d->dragScrollVector.setX(0);
+
+ if (y < contentsY()) d->dragScrollVector.setY(y - contentsY());
+ else if (contentsY() + viewport()->height() < y) d->dragScrollVector.setY(y - contentsY() - viewport()->height());
+ else d->dragScrollVector.setY(0);
+
+ if (d->dragScrollVector != QPoint(0, 0))
+ {
+ if (!d->dragScrollTimer.isActive()) d->dragScrollTimer.start(100);
+ }
+ else d->dragScrollTimer.stop();
+
+ // clip selection to the viewport
+ QRect viewportRect( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
+ x = QMAX( QMIN( x, viewportRect.right() ), viewportRect.left() );
+ y = QMAX( QMIN( y, viewportRect.bottom() ), viewportRect.top() );
+ // if selection changed update rect
+ if ( d->mouseSelectionRect.right() != x || d->mouseSelectionRect.bottom() != y )
+ {
+ // send incremental paint events
+ QRect oldRect = d->mouseSelectionRect.normalize();
+ d->mouseSelectionRect.setRight( x );
+ d->mouseSelectionRect.setBottom( y );
+ QRect newRect = d->mouseSelectionRect.normalize();
+ // generate diff region: [ OLD.unite(NEW) - OLD.intersect(NEW) ]
+ QRegion compoundRegion = QRegion( oldRect ).unite( newRect );
+ if ( oldRect.intersects( newRect ) )
+ {
+ QRect intersection = oldRect.intersect( newRect );
+ intersection.addCoords( 1, 1, -1, -1 );
+ if ( intersection.width() > 20 && intersection.height() > 20 )
+ compoundRegion -= intersection;
+ }
+ // tassellate region with rects and enqueue paint events
+ QMemArray<QRect> rects = compoundRegion.rects();
+ for ( uint i = 0; i < rects.count(); i++ )
+ updateContents( rects[i] );
+ }
+}
+
+void PageView::selectionClear()
+{
+ updateContents( d->mouseSelectionRect.normalize() );
+ d->mouseSelectionRect.setCoords( 0, 0, -1, -1 );
+}
+
+void PageView::updateZoom( ZoomMode newZoomMode )
+{
+ if ( newZoomMode == ZoomFixed )
+ {
+ if ( d->aZoom->currentItem() == 0 )
+ newZoomMode = ZoomFitWidth;
+ else if ( d->aZoom->currentItem() == 1 )
+ newZoomMode = ZoomFitPage;
+ }
+
+ float newFactor = d->zoomFactor;
+ KAction * checkedZoomAction = 0;
+ switch ( newZoomMode )
+ {
+ case ZoomFixed:{ //ZoomFixed case
+ QString z = d->aZoom->currentText();
+ newFactor = KGlobal::locale()->readNumber( z.remove( z.find( '%' ), 1 ) ) / 100.0;
+ }break;
+ case ZoomIn:
+ newFactor += (newFactor > 0.99) ? ( newFactor > 1.99 ? 0.5 : 0.2 ) : 0.1;
+ newZoomMode = ZoomFixed;
+ break;
+ case ZoomOut:
+ newFactor -= (newFactor > 0.99) ? ( newFactor > 1.99 ? 0.5 : 0.2 ) : 0.1;
+ newZoomMode = ZoomFixed;
+ break;
+ case ZoomFitWidth:
+ checkedZoomAction = d->aZoomFitWidth;
+ break;
+ case ZoomFitPage:
+ checkedZoomAction = d->aZoomFitPage;
+ break;
+ case ZoomFitText:
+ checkedZoomAction = d->aZoomFitText;
+ break;
+ case ZoomRefreshCurrent:
+ newZoomMode = ZoomFixed;
+ d->zoomFactor = -1;
+ break;
+ }
+ if ( newFactor > 4.0 )
+ newFactor = 4.0;
+ if ( newFactor < 0.1 )
+ newFactor = 0.1;
+
+ if ( newZoomMode != d->zoomMode || (newZoomMode == ZoomFixed && newFactor != d->zoomFactor ) )
+ {
+ // rebuild layout and update the whole viewport
+ d->zoomMode = newZoomMode;
+ d->zoomFactor = newFactor;
+ // be sure to block updates to document's viewport
+ bool prevState = d->blockViewport;
+ d->blockViewport = true;
+ slotRelayoutPages();
+ d->blockViewport = prevState;
+ // request pixmaps
+ slotRequestVisiblePixmaps();
+ // update zoom text
+ updateZoomText();
+ // update actions checked state
+ d->aZoomFitWidth->setChecked( checkedZoomAction == d->aZoomFitWidth );
+ d->aZoomFitPage->setChecked( checkedZoomAction == d->aZoomFitPage );
+ d->aZoomFitText->setChecked( checkedZoomAction == d->aZoomFitText );
+
+ // save selected zoom factor
+ KpdfSettings::setZoomMode(newZoomMode);
+ KpdfSettings::setZoomFactor(newFactor);
+ KpdfSettings::writeConfig();
+ }
+}
+
+void PageView::updateZoomText()
+{
+ // use current page zoom as zoomFactor if in ZoomFit/* mode
+ if ( d->zoomMode != ZoomFixed && d->items.count() > 0 )
+ d->zoomFactor = d->items[ QMAX( 0, (int)d->document->currentPage() ) ]->zoomFactor();
+ float newFactor = d->zoomFactor;
+ d->aZoom->clear();
+
+ // add items that describe fit actions
+ QStringList translated;
+ translated << i18n("Fit Width") << i18n("Fit Page"); // << i18n("Fit Text");
+
+ // add percent items
+ QString double_oh( "00" );
+ const float zoomValue[10] = { 0.125, 0.25, 0.333, 0.5, 0.667, 0.75, 1, 1.25, 1.50, 2 };
+ int idx = 0,
+ selIdx = 2; // use 3 if "fit text" present
+ bool inserted = false; //use: "d->zoomMode != ZoomFixed" to hide Fit/* zoom ratio
+ while ( idx < 10 || !inserted )
+ {
+ float value = idx < 10 ? zoomValue[ idx ] : newFactor;
+ if ( !inserted && newFactor < (value - 0.0001) )
+ value = newFactor;
+ else
+ idx ++;
+ if ( value > (newFactor - 0.0001) && value < (newFactor + 0.0001) )
+ inserted = true;
+ if ( !inserted )
+ selIdx++;
+ QString localValue( KGlobal::locale()->formatNumber( value * 100.0, 2 ) );
+ localValue.remove( KGlobal::locale()->decimalSymbol() + double_oh );
+ translated << QString( "%1%" ).arg( localValue );
+ }
+ d->aZoom->setItems( translated );
+
+ // select current item in list
+ if ( d->zoomMode == ZoomFitWidth )
+ selIdx = 0;
+ else if ( d->zoomMode == ZoomFitPage )
+ selIdx = 1;
+ else if ( d->zoomMode == ZoomFitText )
+ selIdx = 2;
+ d->aZoom->setCurrentItem( selIdx );
+}
+
+void PageView::updateCursor( const QPoint &p )
+{
+ // detect the underlaying page (if present)
+ PageViewItem * pageItem = pickItemOnPoint( p.x(), p.y() );
+ if ( pageItem && d->mouseMode == MouseNormal )
+ {
+ double nX = (double)(p.x() - pageItem->geometry().left()) / (double)pageItem->width(),
+ nY = (double)(p.y() - pageItem->geometry().top()) / (double)pageItem->height();
+
+ // if over a ObjectRect (of type Link) change cursor to hand
+ d->mouseOnRect = pageItem->page()->hasObject( ObjectRect::Link, nX, nY );
+ if ( d->mouseOnRect )
+ setCursor( KCursor::handCursor() );
+ else
+ setCursor( KCursor::arrowCursor() );
+ }
+ else
+ {
+ // if there's no page over the cursor and we were showing the pointingHandCursor
+ // go back to the normal one
+ d->mouseOnRect = false;
+ setCursor( KCursor::arrowCursor() );
+ }
+}
+
+void PageView::doTypeAheadSearch()
+{
+ bool found = d->document->searchText( PAGEVIEW_SEARCH_ID, d->typeAheadString, false, false,
+ KPDFDocument::NextMatch, true, qRgb( 128, 255, 128 ), true );
+ QString status = found ? i18n("Text found: \"%1\".") : i18n("Text not found: \"%1\".");
+ d->messageWindow->display( status.arg(d->typeAheadString.lower()),
+ found ? PageViewMessage::Find : PageViewMessage::Warning, 4000 );
+ d->findTimeoutTimer->start( 3000, true );
+}
+
+//BEGIN private SLOTS
+void PageView::slotRelayoutPages()
+// called by: notifySetup, viewportResizeEvent, slotTwoPagesToggled, slotContinuousToggled, updateZoom
+{
+ // set an empty container if we have no pages
+ int pageCount = d->items.count();
+ if ( pageCount < 1 )
+ {
+ resizeContents( 0, 0 );
+ return;
+ }
+
+ // if viewport was auto-moving, stop it
+ if ( d->viewportMoveActive )
+ {
+ d->viewportMoveActive = false;
+ d->viewportMoveTimer->stop();
+ verticalScrollBar()->setEnabled( true );
+ horizontalScrollBar()->setEnabled( true );
+ }
+
+ // common iterator used in this method and viewport parameters
+ QValueVector< PageViewItem * >::iterator iIt, iEnd = d->items.end();
+ int viewportWidth = visibleWidth(),
+ viewportHeight = visibleHeight(),
+ fullWidth = 0,
+ fullHeight = 0;
+ QRect viewportRect( contentsX(), contentsY(), viewportWidth, viewportHeight );
+
+ // set all items geometry and resize contents. handle 'continuous' and 'single' modes separately
+ if ( KpdfSettings::viewContinuous() )
+ {
+ // Here we find out column's width and row's height to compute a table
+ // so we can place widgets 'centered in virtual cells'.
+ int nCols = KpdfSettings::viewColumns(),
+ nRows = (int)ceil( (float)pageCount / (float)nCols ),
+ * colWidth = new int[ nCols ],
+ * rowHeight = new int[ nRows ],
+ cIdx = 0,
+ rIdx = 0;
+ for ( int i = 0; i < nCols; i++ )
+ colWidth[ i ] = viewportWidth / nCols;
+ for ( int i = 0; i < nRows; i++ )
+ rowHeight[ i ] = 0;
+
+ // 1) find the maximum columns width and rows height for a grid in
+ // which each page must well-fit inside a cell
+ for ( iIt = d->items.begin(); iIt != iEnd; ++iIt )
+ {
+ PageViewItem * item = *iIt;
+ // update internal page size (leaving a little margin in case of Fit* modes)
+ updateItemSize( item, colWidth[ cIdx ] - 6, viewportHeight - 8 );
+ // find row's maximum height and column's max width
+ if ( item->width() + 6 > colWidth[ cIdx ] )
+ colWidth[ cIdx ] = item->width() + 6;
+ if ( item->height() > rowHeight[ rIdx ] )
+ rowHeight[ rIdx ] = item->height();
+ // update col/row indices
+ if ( ++cIdx == nCols )
+ {
+ cIdx = 0;
+ rIdx++;
+ }
+ }
+
+ // 2) arrange widgets inside cells
+ int insertX = 0,
+ insertY = 4; // 2 + 4*d->zoomFactor ?
+ cIdx = 0;
+ rIdx = 0;
+ for ( iIt = d->items.begin(); iIt != iEnd; ++iIt )
+ {
+ PageViewItem * item = *iIt;
+ int cWidth = colWidth[ cIdx ],
+ rHeight = rowHeight[ rIdx ];
+ // center widget inside 'cells'
+ item->moveTo( insertX + (cWidth - item->width()) / 2,
+ insertY + (rHeight - item->height()) / 2 );
+ // advance col/row index
+ insertX += cWidth;
+ if ( ++cIdx == nCols )
+ {
+ cIdx = 0;
+ rIdx++;
+ insertX = 0;
+ insertY += rHeight + 15; // 5 + 15*d->zoomFactor ?
+ }
+ }
+
+ fullHeight = cIdx ? (insertY + rowHeight[ rIdx ] + 10) : insertY;
+ for ( int i = 0; i < nCols; i++ )
+ fullWidth += colWidth[ i ];
+
+ delete [] colWidth;
+ delete [] rowHeight;
+ }
+ else // viewContinuous is FALSE
+ {
+ PageViewItem * currentItem = d->items[ QMAX( 0, (int)d->document->currentPage() ) ];
+
+ // setup varialbles for a 1(row) x N(columns) grid
+ int nCols = KpdfSettings::viewColumns(),
+ * colWidth = new int[ nCols ],
+ cIdx = 0;
+ fullHeight = viewportHeight;
+ for ( int i = 0; i < nCols; i++ )
+ colWidth[ i ] = viewportWidth / nCols;
+
+ // 1) find out maximum area extension for the pages
+ for ( iIt = d->items.begin(); iIt != iEnd; ++iIt )
+ {
+ PageViewItem * item = *iIt;
+ if ( item == currentItem || (cIdx > 0 && cIdx < nCols) )
+ {
+ // update internal page size (leaving a little margin in case of Fit* modes)
+ updateItemSize( item, colWidth[ cIdx ] - 6, viewportHeight - 8 );
+ // find row's maximum height and column's max width
+ if ( item->width() + 6 > colWidth[ cIdx ] )
+ colWidth[ cIdx ] = item->width() + 6;
+ if ( item->height() + 8 > fullHeight )
+ fullHeight = item->height() + 8;
+ cIdx++;
+ }
+ }
+
+ // 2) hide all widgets except the displayable ones and dispose those
+ int insertX = 0;
+ cIdx = 0;
+ for ( iIt = d->items.begin(); iIt != iEnd; ++iIt )
+ {
+ PageViewItem * item = *iIt;
+ if ( item == currentItem || (cIdx > 0 && cIdx < nCols) )
+ {
+ // center widget inside 'cells'
+ item->moveTo( insertX + (colWidth[ cIdx ] - item->width()) / 2,
+ (fullHeight - item->height()) / 2 );
+ // advance col index
+ insertX += colWidth[ cIdx ];
+ cIdx++;
+ } else
+ item->setGeometry( 0, 0, -1, -1 );
+ }
+
+ for ( int i = 0; i < nCols; i++ )
+ fullWidth += colWidth[ i ];
+
+ delete [] colWidth;
+ }
+
+ // 3) reset dirty state
+ d->dirtyLayout = false;
+
+ // 4) update scrollview's contents size and recenter view
+ bool wasUpdatesEnabled = viewport()->isUpdatesEnabled();
+ if ( fullWidth != contentsWidth() || fullHeight != contentsHeight() )
+ {
+ // disable updates and resize the viewportContents
+ if ( wasUpdatesEnabled )
+ viewport()->setUpdatesEnabled( false );
+ resizeContents( fullWidth, fullHeight );
+ // restore previous viewport if defined and updates enabled
+ if ( wasUpdatesEnabled )
+ {
+ const DocumentViewport & vp = d->document->viewport();
+ if ( vp.pageNumber >= 0 )
+ {
+ int prevX = contentsX(),
+ prevY = contentsY();
+ const QRect & geometry = d->items[ vp.pageNumber ]->geometry();
+ double nX = vp.rePos.enabled ? vp.rePos.normalizedX : 0.5,
+ nY = vp.rePos.enabled ? vp.rePos.normalizedY : 0.0;
+ center( geometry.left() + ROUND( nX * (double)geometry.width() ),
+ geometry.top() + ROUND( nY * (double)geometry.height() ) );
+ // center() usually moves the viewport, that requests pixmaps too.
+ // if that doesn't happen we have to request them by hand
+ if ( prevX == contentsX() && prevY == contentsY() )
+ slotRequestVisiblePixmaps();
+ }
+ // or else go to center page
+ else
+ center( fullWidth / 2, 0 );
+ viewport()->setUpdatesEnabled( true );
+ }
+ }
+
+ // 5) update the whole viewport if updated enabled
+ if ( wasUpdatesEnabled )
+ updateContents();
+}
+
+void PageView::slotRequestVisiblePixmaps( int newLeft, int newTop )
+{
+ // if requests are blocked (because raised by an unwanted event), exit
+ if ( d->blockPixmapsRequest || d->viewportMoveActive )
+ return;
+
+ // precalc view limits for intersecting with page coords inside the lOOp
+ bool isEvent = newLeft != -1 && newTop != -1 && !d->blockViewport;
+ QRect viewportRect( isEvent ? newLeft : contentsX(),
+ isEvent ? newTop : contentsY(),
+ visibleWidth(), visibleHeight() );
+
+ // some variables used to determine the viewport
+ int nearPageNumber = -1;
+ double viewportCenterX = (viewportRect.left() + viewportRect.right()) / 2.0,
+ viewportCenterY = (viewportRect.top() + viewportRect.bottom()) / 2.0,
+ focusedX = 0.5,
+ focusedY = 0.0,
+ minDistance = -1.0;
+
+ // iterate over all items
+ d->visibleItems.clear();
+ QValueList< PixmapRequest * > requestedPixmaps;
+ QValueVector< PageViewItem * >::iterator iIt = d->items.begin(), iEnd = d->items.end();
+ for ( ; iIt != iEnd; ++iIt )
+ {
+ PageViewItem * i = *iIt;
+
+ // if the item doesn't intersect the viewport, skip it
+ if ( !viewportRect.intersects( i->geometry() ) )
+ continue;
+
+ // add the item to the 'visible list'
+ d->visibleItems.push_back( i );
+
+ // if the item has not the right pixmap, add a request for it
+ if ( !i->page()->hasPixmap( PAGEVIEW_ID, i->width(), i->height() ) )
+ {
+ PixmapRequest * p = new PixmapRequest(
+ PAGEVIEW_ID, i->pageNumber(), i->width(), i->height(), PAGEVIEW_PRIO, true );
+ requestedPixmaps.push_back( p );
+ }
+
+ // look for the item closest to viewport center and the relative
+ // position between the item and the viewport center
+ if ( isEvent )
+ {
+ const QRect & geometry = i->geometry();
+ // compute distance between item center and viewport center
+ double distance = hypot( (geometry.left() + geometry.right()) / 2 - viewportCenterX,
+ (geometry.top() + geometry.bottom()) / 2 - viewportCenterY );
+ if ( distance >= minDistance && nearPageNumber != -1 )
+ continue;
+ nearPageNumber = i->pageNumber();
+ minDistance = distance;
+ if ( geometry.height() > 0 && geometry.width() > 0 )
+ {
+ focusedX = ( viewportCenterX - (double)geometry.left() ) / (double)geometry.width();
+ focusedY = ( viewportCenterY - (double)geometry.top() ) / (double)geometry.height();
+ }
+ }
+ }
+
+ // if preloading is enabled, add the pages before and after in preloading
+ if ( !d->visibleItems.isEmpty() &&
+ KpdfSettings::memoryLevel() != KpdfSettings::EnumMemoryLevel::Low &&
+ KpdfSettings::enableThreading() )
+ {
+ // as the requests are done in the order as they appear in the list,
+ // request first the next page and then the previous
+
+ // add the page after the 'visible series' in preload
+ int tailRequest = d->visibleItems.last()->pageNumber() + 1;
+ if ( tailRequest < (int)d->items.count() )
+ {
+ PageViewItem * i = d->items[ tailRequest ];
+ // request the pixmap if not already present
+ if ( !i->page()->hasPixmap( PAGEVIEW_ID, i->width(), i->height() ) && i->width() > 0 )
+ requestedPixmaps.push_back( new PixmapRequest(
+ PAGEVIEW_ID, i->pageNumber(), i->width(), i->height(), PAGEVIEW_PRELOAD_PRIO, true ) );
+ }
+
+ // add the page before the 'visible series' in preload
+ int headRequest = d->visibleItems.first()->pageNumber() - 1;
+ if ( headRequest >= 0 )
+ {
+ PageViewItem * i = d->items[ headRequest ];
+ // request the pixmap if not already present
+ if ( !i->page()->hasPixmap( PAGEVIEW_ID, i->width(), i->height() ) && i->width() > 0 )
+ requestedPixmaps.push_back( new PixmapRequest(
+ PAGEVIEW_ID, i->pageNumber(), i->width(), i->height(), PAGEVIEW_PRELOAD_PRIO, true ) );
+ }
+ }
+
+ // send requests to the document
+ if ( !requestedPixmaps.isEmpty() )
+ d->document->requestPixmaps( requestedPixmaps );
+
+ // if this functions was invoked by viewport events, send update to document
+ if ( isEvent && nearPageNumber != -1 )
+ {
+ // determine the document viewport
+ DocumentViewport newViewport( nearPageNumber );
+ newViewport.rePos.enabled = true;
+ newViewport.rePos.normalizedX = focusedX;
+ newViewport.rePos.normalizedY = focusedY;
+ // set the viewport to other observers
+ d->document->setViewport( newViewport , PAGEVIEW_ID);
+ }
+}
+
+void PageView::slotMoveViewport()
+{
+ // converge to viewportMoveDest in 1 second
+ int diffTime = d->viewportMoveTime.elapsed();
+ if ( diffTime >= 667 || !d->viewportMoveActive )
+ {
+ center( d->viewportMoveDest.x(), d->viewportMoveDest.y() );
+ d->viewportMoveTimer->stop();
+ d->viewportMoveActive = false;
+ slotRequestVisiblePixmaps();
+ verticalScrollBar()->setEnabled( true );
+ horizontalScrollBar()->setEnabled( true );
+ return;
+ }
+
+ // move the viewport smoothly (kmplot: p(x)=x+x*(1-x)*(1-x))
+ float convergeSpeed = (float)diffTime / 667.0,
+ x = ((float)visibleWidth() / 2.0) + contentsX(),
+ y = ((float)visibleHeight() / 2.0) + contentsY(),
+ diffX = (float)d->viewportMoveDest.x() - x,
+ diffY = (float)d->viewportMoveDest.y() - y;
+ convergeSpeed *= convergeSpeed * (1.4 - convergeSpeed);
+ center( (int)(x + diffX * convergeSpeed),
+ (int)(y + diffY * convergeSpeed ) );
+}
+
+void PageView::slotAutoScoll()
+{
+ // the first time create the timer
+ if ( !d->autoScrollTimer )
+ {
+ d->autoScrollTimer = new QTimer( this );
+ connect( d->autoScrollTimer, SIGNAL( timeout() ), this, SLOT( slotAutoScoll() ) );
+ }
+
+ // if scrollIncrement is zero, stop the timer
+ if ( !d->scrollIncrement )
+ {
+ d->autoScrollTimer->stop();
+ return;
+ }
+
+ // compute delay between timer ticks and scroll amount per tick
+ int index = abs( d->scrollIncrement ) - 1; // 0..9
+ const int scrollDelay[10] = { 200, 100, 50, 30, 20, 30, 25, 20, 30, 20 };
+ const int scrollOffset[10] = { 1, 1, 1, 1, 1, 2, 2, 2, 4, 4 };
+ d->autoScrollTimer->changeInterval( scrollDelay[ index ] );
+ scrollBy( 0, d->scrollIncrement > 0 ? scrollOffset[ index ] : -scrollOffset[ index ] );
+}
+
+void PageView::slotDragScroll()
+{
+ scrollBy(d->dragScrollVector.x(), d->dragScrollVector.y());
+ QPoint p = viewportToContents( mapFromGlobal( QCursor::pos() ) );
+ selectionEndPoint( p.x(), p.y() );
+}
+
+void PageView::findAheadStop()
+{
+ d->typeAheadActive = false;
+ d->typeAheadString = "";
+ d->messageWindow->display( i18n("Find stopped."), PageViewMessage::Find, 1000 );
+ // it is needed to grab the keyboard becase people may have Space assigned to a
+ // accel and without grabbing the keyboard you can not vim-search for space
+ // because it activates the accel
+ releaseKeyboard();
+}
+
+void PageView::slotShowWelcome()
+{
+ // show initial welcome text
+ d->messageWindow->display( i18n( "Welcome" ), PageViewMessage::Info, 2000 );
+}
+
+void PageView::slotZoom()
+{
+ setFocus();
+ updateZoom( ZoomFixed );
+}
+
+void PageView::slotZoomIn()
+{
+ updateZoom( ZoomIn );
+}
+
+void PageView::slotZoomOut()
+{
+ updateZoom( ZoomOut );
+}
+
+void PageView::slotFitToWidthToggled( bool on )
+{
+ if ( on ) updateZoom( ZoomFitWidth );
+}
+
+void PageView::slotFitToPageToggled( bool on )
+{
+ if ( on ) updateZoom( ZoomFitPage );
+}
+
+void PageView::slotFitToTextToggled( bool on )
+{
+ if ( on ) updateZoom( ZoomFitText );
+}
+
+void PageView::slotTwoPagesToggled( bool on )
+{
+ uint newColumns = on ? 2 : 1;
+ if ( KpdfSettings::viewColumns() != newColumns )
+ {
+ KpdfSettings::setViewColumns( newColumns );
+ KpdfSettings::writeConfig();
+ if ( d->document->pages() > 0 )
+ slotRelayoutPages();
+ }
+}
+
+void PageView::slotContinuousToggled( bool on )
+{
+ if ( KpdfSettings::viewContinuous() != on )
+ {
+ KpdfSettings::setViewContinuous( on );
+ KpdfSettings::writeConfig();
+ if ( d->document->pages() > 0 )
+ slotRelayoutPages();
+ }
+}
+
+void PageView::slotSetMouseNormal()
+{
+ d->mouseMode = MouseNormal;
+ d->messageWindow->hide();
+}
+
+void PageView::slotSetMouseZoom()
+{
+ d->mouseMode = MouseZoom;
+ d->messageWindow->display( i18n( "Select zooming area. Right-click to zoom out." ), PageViewMessage::Info, -1 );
+}
+
+void PageView::slotSetMouseSelect()
+{
+ d->mouseMode = MouseSelect;
+ d->messageWindow->display( i18n( "Draw a rectangle around the text/graphics to copy." ), PageViewMessage::Info, -1 );
+}
+
+void PageView::slotSetMouseDraw()
+{
+ d->mouseMode = MouseEdit;
+ d->aMouseEdit->setChecked( true );
+ d->messageWindow->hide();
+}
+
+void PageView::slotScrollUp()
+{
+ if ( d->scrollIncrement < -9 )
+ return;
+ d->scrollIncrement--;
+ slotAutoScoll();
+ setFocus();
+}
+
+void PageView::slotScrollDown()
+{
+ if ( d->scrollIncrement > 9 )
+ return;
+ d->scrollIncrement++;
+ slotAutoScoll();
+ setFocus();
+}
+//END private SLOTS
+
+#include "pageview.moc"
diff --git a/kpdf/ui/pageview.h b/kpdf/ui/pageview.h
new file mode 100644
index 00000000..f6e40991
--- /dev/null
+++ b/kpdf/ui/pageview.h
@@ -0,0 +1,148 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
+ * Copyright (C) 2004 by Albert Astals Cid <tsdgeos@terra.es> *
+ * *
+ * With portions of code from kpdf/kpdf_pagewidget.h by: *
+ * Copyright (C) 2002 by Wilco Greven <greven@kde.org> *
+ * Copyright (C) 2003 by Christophe Devriese *
+ * <Christophe.Devriese@student.kuleuven.ac.be> *
+ * Copyright (C) 2003 by Laurent Montel <montel@kde.org> *
+ * Copyright (C) 2003 by Kurt Pfeifle <kpfeifle@danka.de> *
+ * *
+ * 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 file follows coding style described in kdebase/kicker/HACKING
+
+#ifndef _KPDF_PAGEVIEW_H_
+#define _KPDF_PAGEVIEW_H_
+
+#include <qscrollview.h>
+#include <qvaluevector.h>
+#include "core/observer.h"
+
+class KURL;
+class KActionCollection;
+
+class KPDFDocument;
+class PageViewItem;
+class PageViewPrivate;
+class PageViewTip;
+
+/**
+ * @short The main view. Handles zoom and continuous mode.. oh, and page
+ * @short display of course :-)
+ * ...
+ */
+class PageView : public QScrollView, public DocumentObserver
+{
+ Q_OBJECT
+
+ friend class PageViewTip;
+
+ public:
+ PageView( QWidget *parent, KPDFDocument *document );
+ ~PageView();
+
+ // Zoom mode ( last 4 are internally used only! )
+ enum ZoomMode { ZoomFixed, ZoomFitWidth, ZoomFitPage, ZoomFitText,
+ ZoomIn, ZoomOut, ZoomRefreshCurrent };
+ enum MouseMode { MouseNormal, MouseZoom, MouseSelect, MouseEdit };
+
+ // create actions that interact with this widget
+ void setupActions( KActionCollection * collection );
+
+ // used from RMB menu
+ bool canFitPageWidth();
+ void fitPageWidth( int page );
+
+ // inherited from DocumentObserver
+ uint observerId() const { return PAGEVIEW_ID; }
+ void notifySetup( const QValueVector< KPDFPage * > & pages, bool documentChanged );
+ void notifyViewportChanged( bool smoothMove );
+ void notifyPageChanged( int pageNumber, int changedFlags );
+ void notifyContentsCleared( int changedFlags );
+ bool canUnloadPixmap( int pageNum );
+
+ void showText( const QString &text, int ms );
+
+ signals:
+ void urlDropped( const KURL& );
+ void rightClick( const KPDFPage *, const QPoint & );
+
+ protected:
+ // main draw loop, draws pageViews on viewport
+ void viewportPaintEvent( QPaintEvent * pe );
+ void viewportResizeEvent( QResizeEvent* );
+
+ // mouse / keyboard events
+ void keyPressEvent( QKeyEvent* );
+ void imEndEvent( QIMEvent * );
+ void contentsMouseMoveEvent( QMouseEvent* );
+ void contentsMousePressEvent( QMouseEvent* );
+ void contentsMouseReleaseEvent( QMouseEvent* );
+ void wheelEvent( QWheelEvent* );
+
+ // drag and drop related events
+ void dragEnterEvent( QDragEnterEvent* );
+ void dropEvent( QDropEvent* );
+
+ private:
+ // draw items on the opened qpainter
+ void paintItems( QPainter * p, const QRect & clipRect );
+ // update item width and height using current zoom parameters
+ void updateItemSize( PageViewItem * item, int columnWidth, int rowHeight );
+ // return the widget placed on a certain point or 0 if clicking on empty space
+ PageViewItem * pickItemOnPoint( int x, int y );
+ // start / modify / clear selection rectangle
+ void selectionStart( int x, int y, const QColor & color, bool aboveAll = false );
+ void selectionEndPoint( int x, int y );
+ void selectionClear();
+ // update internal zoom values and end in a slotRelayoutPages();
+ void updateZoom( ZoomMode newZm );
+ // update the text on the label using global zoom value or current page's one
+ void updateZoomText();
+ // updates cursor
+ void updateCursor( const QPoint &p );
+ // does the type ahead search
+ void doTypeAheadSearch();
+
+ // don't want to expose classes in here
+ class PageViewPrivate * d;
+
+ private slots:
+ // activated either directly or via QTimer on the viewportResizeEvent
+ void slotRelayoutPages();
+ // activated either directly or via the contentsMoving(int,int) signal
+ void slotRequestVisiblePixmaps( int left = -1, int top = -1 );
+ // activated by the viewport move timer
+ void slotMoveViewport();
+ // activated by the autoscroll timer (Shift+Up/Down keys)
+ void slotAutoScoll();
+ // activated by the dragScroll timer
+ void slotDragScroll();
+ // type-ahead find timeout
+ void findAheadStop();
+ // show the welcome message
+ void slotShowWelcome();
+
+ // connected to local actions (toolbar, menu, ..)
+ void slotZoom();
+ void slotZoomIn();
+ void slotZoomOut();
+ void slotFitToWidthToggled( bool );
+ void slotFitToPageToggled( bool );
+ void slotFitToTextToggled( bool );
+ void slotTwoPagesToggled( bool );
+ void slotContinuousToggled( bool );
+ void slotSetMouseNormal();
+ void slotSetMouseZoom();
+ void slotSetMouseSelect();
+ void slotSetMouseDraw();
+ void slotScrollUp();
+ void slotScrollDown();
+};
+
+#endif
diff --git a/kpdf/ui/pageviewutils.cpp b/kpdf/ui/pageviewutils.cpp
new file mode 100644
index 00000000..b9d84137
--- /dev/null
+++ b/kpdf/ui/pageviewutils.cpp
@@ -0,0 +1,207 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+// qt/kde includes
+#include <qbitmap.h>
+#include <qpainter.h>
+#include <qimage.h>
+#include <qtimer.h>
+#include <kapplication.h>
+#include <kimageeffect.h>
+#include <kiconloader.h>
+
+// local includes
+#include "pageviewutils.h"
+#include "core/page.h"
+#include "conf/settings.h"
+
+PageViewMessage::PageViewMessage( QWidget * parent )
+ : QWidget( parent, "pageViewMessage" ), m_timer( 0 )
+{
+ setFocusPolicy( NoFocus );
+ setBackgroundMode( NoBackground );
+ setPaletteBackgroundColor(kapp->palette().color(QPalette::Active, QColorGroup::Background));
+ // if the layout is LtR, we can safely place it in the right position
+ if ( !QApplication::reverseLayout() )
+ move( 10, 10 );
+ resize( 0, 0 );
+ hide();
+}
+
+void PageViewMessage::display( const QString & message, Icon icon, int durationMs )
+// give to Caesar what Caesar owns: code taken from Amarok's osd.h/.cpp
+// "redde (reddite, pl.) cesari quae sunt cesaris", just btw. ;)
+{
+ if ( !KpdfSettings::showOSD() )
+ {
+ hide();
+ return;
+ }
+
+ // determine text rectangle
+ QRect textRect = fontMetrics().boundingRect( message );
+ textRect.moveBy( -textRect.left(), -textRect.top() );
+ textRect.addCoords( 0, 0, 2, 2 );
+ int width = textRect.width(),
+ height = textRect.height(),
+ textXOffset = 0,
+ iconXOffset = 0,
+ shadowOffset = 1;
+
+ // load icon (if set) and update geometry
+ QPixmap symbol;
+ if ( icon != None )
+ {
+ switch ( icon )
+ {
+ case Find:
+ symbol = SmallIcon( "viewmag" );
+ break;
+ case Error:
+ symbol = SmallIcon( "messagebox_critical" );
+ break;
+ case Warning:
+ symbol = SmallIcon( "messagebox_warning" );
+ break;
+ default:
+ symbol = SmallIcon( "messagebox_info" );
+ break;
+ }
+ if ( QApplication::reverseLayout() )
+ {
+ iconXOffset = 2 + textRect.width();
+ }
+ else
+ {
+ textXOffset = 2 + symbol.width();
+ }
+ width += 2 + symbol.width();
+ height = QMAX( height, symbol.height() );
+ }
+ QRect geometry( 0, 0, width + 10, height + 8 );
+
+ // resize pixmap, mask and widget
+ static QBitmap mask;
+ mask.resize( geometry.size() );
+ m_pixmap.resize( geometry.size() );
+ resize( geometry.size() );
+
+ // create and set transparency mask
+ QPainter maskPainter( &mask);
+ mask.fill( Qt::black );
+ maskPainter.setBrush( Qt::white );
+ maskPainter.drawRoundRect( geometry, 1600 / geometry.width(), 1600 / geometry.height() );
+ setMask( mask );
+
+ // draw background
+ QPainter bufferPainter( &m_pixmap );
+ bufferPainter.setPen( Qt::black );
+ bufferPainter.setBrush( paletteBackgroundColor() );
+ bufferPainter.drawRoundRect( geometry, 1600 / geometry.width(), 1600 / geometry.height() );
+
+ // draw icon if present
+ if ( !symbol.isNull() )
+ bufferPainter.drawPixmap( 5 + iconXOffset, 4, symbol, 0, 0, symbol.width(), symbol.height() );
+
+ // draw shadow and text
+ int yText = geometry.height() - height / 2;
+ bufferPainter.setPen( paletteBackgroundColor().dark( 115 ) );
+ bufferPainter.drawText( 5 + textXOffset + shadowOffset, yText + 1, message );
+ bufferPainter.setPen( foregroundColor() );
+ bufferPainter.drawText( 5 + textXOffset, yText, message );
+
+ // if the layout is RtL, we can move it to the right place only after we
+ // know how much size it will take
+ if ( QApplication::reverseLayout() )
+ move( parentWidget()->width() - geometry.width() - 10, 10 );
+
+ // show widget and schedule a repaint
+ show();
+ update();
+
+ // close the message window after given mS
+ if ( durationMs > 0 )
+ {
+ if ( !m_timer )
+ {
+ m_timer = new QTimer( this );
+ connect( m_timer, SIGNAL( timeout() ), SLOT( hide() ) );
+ }
+ m_timer->start( durationMs, true );
+ } else if ( m_timer )
+ m_timer->stop();
+}
+
+void PageViewMessage::paintEvent( QPaintEvent * e )
+{
+ QPainter p( this );
+ p.drawPixmap( e->rect().topLeft(), m_pixmap, e->rect() );
+}
+
+void PageViewMessage::mousePressEvent( QMouseEvent * /*e*/ )
+{
+ if ( m_timer )
+ m_timer->stop();
+ hide();
+}
+
+
+
+PageViewItem::PageViewItem( const KPDFPage * page )
+ : m_page( page ), m_zoomFactor( 1.0 )
+{
+}
+
+const KPDFPage * PageViewItem::page() const
+{
+ return m_page;
+}
+
+int PageViewItem::pageNumber() const
+{
+ return m_page->number();
+}
+
+const QRect& PageViewItem::geometry() const
+{
+ return m_geometry;
+}
+
+int PageViewItem::width() const
+{
+ return m_geometry.width();
+}
+
+int PageViewItem::height() const
+{
+ return m_geometry.height();
+}
+
+double PageViewItem::zoomFactor() const
+{
+ return m_zoomFactor;
+}
+
+void PageViewItem::setGeometry( int x, int y, int width, int height )
+{
+ m_geometry.setRect( x, y, width, height );
+}
+
+void PageViewItem::setWHZ( int w, int h, double z )
+{
+ m_geometry.setWidth( w );
+ m_geometry.setHeight( h );
+ m_zoomFactor = z;
+}
+
+void PageViewItem::moveTo( int x, int y )
+{
+ m_geometry.moveLeft( x );
+ m_geometry.moveTop( y );
+}
diff --git a/kpdf/ui/pageviewutils.h b/kpdf/ui/pageviewutils.h
new file mode 100644
index 00000000..bde9b8d3
--- /dev/null
+++ b/kpdf/ui/pageviewutils.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef _PAGEVIEW_UTILS_H
+#define _PAGEVIEW_UTILS_H
+
+#include <qwidget.h>
+#include <qpixmap.h>
+#include <qpainter.h>
+#include <qrect.h>
+
+class QTimer;
+
+class PageView;
+class KPDFPage;
+
+/**
+ * @short PageViewItem represents graphically a kpdfpage into the PageView.
+ *
+ * It has methods for settings Item's geometry and other visual properties such
+ * as the individual zoom factor.
+ */
+class PageViewItem
+{
+ public:
+ PageViewItem( const KPDFPage * page );
+
+ const KPDFPage * page() const;
+ int pageNumber() const;
+ const QRect& geometry() const;
+ int width() const;
+ int height() const;
+ double zoomFactor() const;
+
+ void setGeometry( int x, int y, int width, int height );
+ void setWHZ( int w, int h, double zoom );
+ void moveTo( int x, int y );
+
+ private:
+ const KPDFPage * m_page;
+ double m_zoomFactor;
+ QRect m_geometry;
+};
+
+
+/**
+ * @short A widget that displays messages in the top-left corner.
+ */
+class PageViewMessage : public QWidget
+{
+ public:
+ PageViewMessage( QWidget * parent );
+
+ enum Icon { None, Info, Warning, Error, Find };
+ void display( const QString & message, Icon icon = Info, int durationMs = 4000 );
+
+ protected:
+ void paintEvent( QPaintEvent * e );
+ void mousePressEvent( QMouseEvent * e );
+
+ private:
+ QPixmap m_pixmap;
+ QTimer * m_timer;
+};
+
+#endif
diff --git a/kpdf/ui/presentationwidget.cpp b/kpdf/ui/presentationwidget.cpp
new file mode 100644
index 00000000..c57e2f95
--- /dev/null
+++ b/kpdf/ui/presentationwidget.cpp
@@ -0,0 +1,1330 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+// qt/kde includes
+#include <qtimer.h>
+#include <qimage.h>
+#include <qpainter.h>
+#include <qapplication.h>
+#include <qdesktopwidget.h>
+#include <qtooltip.h>
+#include <kaccel.h>
+#include <kactioncollection.h>
+#include <kapplication.h>
+#include <kcursor.h>
+#include <ktoolbar.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kimageeffect.h>
+#include <kmessagebox.h>
+#include <kwin.h>
+
+// system includes
+#include <stdlib.h>
+#include <math.h>
+
+// local includes
+#include "presentationwidget.h"
+#include "pagepainter.h"
+#include "core/generator.h"
+#include "core/page.h"
+#include "core/link.h"
+#include "conf/settings.h"
+
+
+// comment this to disable the top-right progress indicator
+#define ENABLE_PROGRESS_OVERLAY
+
+
+// a frame contains a pointer to the page object, its geometry and the
+// transition effect to the next frame
+struct PresentationFrame
+{
+ const KPDFPage * page;
+ QRect geometry;
+};
+
+
+PresentationWidget::PresentationWidget( QWidget * parent, KPDFDocument * doc )
+ : QDialog( parent, "presentationWidget", true, WDestructiveClose | WStyle_NoBorder),
+ m_pressedLink( 0 ), m_handCursor( false ), m_document( doc ), m_frameIndex( -1 )
+{
+ // set look and geometry
+ setBackgroundMode( Qt::NoBackground );
+
+ m_width = -1;
+
+ m_accel = new KAccel( this, this, "presentationmode-accel" );
+
+ // show widget and take control
+ showFullScreen();
+
+ // misc stuff
+ setMouseTracking( true );
+ m_transitionTimer = new QTimer( this );
+ connect( m_transitionTimer, SIGNAL( timeout() ), this, SLOT( slotTransitionStep() ) );
+ m_overlayHideTimer = new QTimer( this );
+ connect( m_overlayHideTimer, SIGNAL( timeout() ), this, SLOT( slotHideOverlay() ) );
+ m_nextPageTimer = new QTimer( this );
+ connect( m_nextPageTimer, SIGNAL( timeout() ), this, SLOT( slotNextPage() ) );
+
+ // handle cursor appearance as specified in configuration
+ if ( KpdfSettings::slidesCursor() == KpdfSettings::EnumSlidesCursor::HiddenDelay )
+ {
+ KCursor::setAutoHideCursor( this, true );
+ KCursor::setHideCursorDelay( 3000 );
+ }
+ else if ( KpdfSettings::slidesCursor() == KpdfSettings::EnumSlidesCursor::Hidden )
+ {
+ setCursor( KCursor::blankCursor() );
+ }
+}
+
+PresentationWidget::~PresentationWidget()
+{
+ // remove this widget from document observer
+ m_document->removeObserver( this );
+
+ // delete frames
+ QValueVector< PresentationFrame * >::iterator fIt = m_frames.begin(), fEnd = m_frames.end();
+ for ( ; fIt != fEnd; ++fIt )
+ delete *fIt;
+}
+
+void PresentationWidget::setupActions( KActionCollection * ac )
+{
+ m_accel->insert( "previous_page", ac->action( "previous_page" )->shortcut(), this, SLOT( slotPrevPage() ), false, true );
+ m_accel->insert( "next_page", ac->action( "next_page" )->shortcut(), this, SLOT( slotNextPage() ), false, true );
+ m_accel->insert( "first_page", ac->action( "first_page" )->shortcut(), this, SLOT( slotFirstPage() ), false, true );
+ m_accel->insert( "last_page", ac->action( "last_page" )->shortcut(), this, SLOT( slotLastPage() ), false, true );
+ m_accel->insert( "presentation", ac->action( "presentation" )->shortcut(), this, SLOT( close() ), false, true );
+}
+
+void PresentationWidget::notifySetup( const QValueVector< KPDFPage * > & pageSet, bool /*documentChanged*/ )
+{
+ // delete previous frames (if any (shouldn't be))
+ QValueVector< PresentationFrame * >::iterator fIt = m_frames.begin(), fEnd = m_frames.end();
+ for ( ; fIt != fEnd; ++fIt )
+ delete *fIt;
+ if ( !m_frames.isEmpty() )
+ kdWarning() << "Frames setup changed while a Presentation is in progress." << endl;
+ m_frames.clear();
+
+ // create the new frames
+ QValueVector< KPDFPage * >::const_iterator setIt = pageSet.begin(), setEnd = pageSet.end();
+ float screenRatio = (float)m_height / (float)m_width;
+ for ( ; setIt != setEnd; ++setIt )
+ {
+ PresentationFrame * frame = new PresentationFrame();
+ frame->page = *setIt;
+ // calculate frame geometry keeping constant aspect ratio
+ float pageRatio = frame->page->ratio();
+ int pageWidth = m_width,
+ pageHeight = m_height;
+ if ( pageRatio > screenRatio )
+ pageWidth = (int)( (float)pageHeight / pageRatio );
+ else
+ pageHeight = (int)( (float)pageWidth * pageRatio );
+ frame->geometry.setRect( (m_width - pageWidth) / 2,
+ (m_height - pageHeight) / 2,
+ pageWidth, pageHeight );
+ // add the frame to the vector
+ m_frames.push_back( frame );
+ }
+
+ // get metadata from the document
+ m_metaStrings.clear();
+ const DocumentInfo * info = m_document->documentInfo();
+ if ( info )
+ {
+ if ( !info->get( "title" ).isNull() )
+ m_metaStrings += i18n( "Title: %1" ).arg( info->get( "title" ) );
+ if ( !info->get( "author" ).isNull() )
+ m_metaStrings += i18n( "Author: %1" ).arg( info->get( "author" ) );
+ }
+ m_metaStrings += i18n( "Pages: %1" ).arg( m_document->pages() );
+ m_metaStrings += i18n( "Click to begin" );
+}
+
+void PresentationWidget::notifyViewportChanged( bool /*smoothMove*/ )
+{
+ // discard notifications if displaying the summary
+ if ( m_frameIndex == -1 && KpdfSettings::slidesShowSummary() )
+ return;
+
+ // display the current page
+ changePage( m_document->viewport().pageNumber );
+
+ // auto advance to the next page if set
+ if ( KpdfSettings::slidesAdvance() )
+ m_nextPageTimer->start( KpdfSettings::slidesAdvanceTime() * 1000 );
+}
+
+void PresentationWidget::notifyPageChanged( int pageNumber, int changedFlags )
+{
+ // check if it's the last requested pixmap. if so update the widget.
+ if ( (changedFlags & DocumentObserver::Pixmap) && pageNumber == m_frameIndex )
+ generatePage();
+}
+
+bool PresentationWidget::canUnloadPixmap( int pageNumber )
+{
+ // can unload all pixmaps except for the currently visible one
+ return pageNumber != m_frameIndex;
+}
+
+
+// <widget events>
+/* This hack was here to fix 103718 but it's no longer necessary on KDE 3.5 and Lubos asked me to remove it
+bool PresentationWidget::event ( QEvent * e )
+{
+ if (e -> type() == QEvent::WindowDeactivate) KWin::clearState(winId(), NET::StaysOnTop);
+ else if (e -> type() == QEvent::WindowActivate) KWin::setState(winId(), NET::StaysOnTop);
+ return QDialog::event(e);
+}
+*/
+
+void PresentationWidget::keyPressEvent( QKeyEvent * e )
+{
+ if (m_width == -1) return;
+
+ if ( e->key() == Key_Left || e->key() == Key_Backspace || e->key() == Key_Prior )
+ slotPrevPage();
+ else if ( e->key() == Key_Right || e->key() == Key_Space || e->key() == Key_Next )
+ slotNextPage();
+ else if ( e->key() == Key_Home )
+ slotFirstPage();
+ else if ( e->key() == Key_End )
+ slotLastPage();
+ else if ( e->key() == Key_Escape )
+ {
+ if ( m_topBar->isShown() )
+ m_topBar->hide();
+ else
+ close();
+ }
+}
+
+void PresentationWidget::wheelEvent( QWheelEvent * e )
+{
+ // performance note: don't remove the clipping
+ int div = e->delta() / 120;
+ if ( div > 0 )
+ {
+ if ( div > 3 )
+ div = 3;
+ while ( div-- )
+ slotPrevPage();
+ }
+ else if ( div < 0 )
+ {
+ if ( div < -3 )
+ div = -3;
+ while ( div++ )
+ slotNextPage();
+ }
+}
+
+void PresentationWidget::mousePressEvent( QMouseEvent * e )
+{
+ // pressing left button
+ if ( e->button() == Qt::LeftButton )
+ {
+ // if pressing on a link, skip other checks
+ if ( ( m_pressedLink = getLink( e->x(), e->y() ) ) )
+ return;
+
+ // handle clicking on top-right overlay
+ if ( m_overlayGeometry.contains( e->pos() ) )
+ {
+ overlayClick( e->pos() );
+ return;
+ }
+
+ // if no other actions, go to next page
+ slotNextPage();
+ }
+ // pressing right button
+ else if ( e->button() == Qt::RightButton )
+ slotPrevPage();
+}
+
+void PresentationWidget::mouseReleaseEvent( QMouseEvent * e )
+{
+ // if releasing on the same link we pressed over, execute it
+ if ( m_pressedLink && e->button() == Qt::LeftButton )
+ {
+ const KPDFLink * link = getLink( e->x(), e->y() );
+ if ( link == m_pressedLink )
+ m_document->processLink( link );
+ m_pressedLink = 0;
+ }
+}
+
+void PresentationWidget::mouseMoveEvent( QMouseEvent * e )
+{
+ // safety check
+ if ( m_width == -1 )
+ return;
+
+ // update cursor and tooltip if hovering a link
+ if ( KpdfSettings::slidesCursor() != KpdfSettings::EnumSlidesCursor::Hidden )
+ testCursorOnLink( e->x(), e->y() );
+
+ if ( m_topBar->isShown() )
+ {
+ // hide a shown bar when exiting the area
+ if ( e->y() > ( m_topBar->height() + 1 ) )
+ m_topBar->hide();
+ }
+ else
+ {
+ // show the bar if reaching top 2 pixels
+ if ( e->y() <= (geometry().top() + 1) )
+ m_topBar->show();
+ // handle "dragging the wheel" if clicking on its geometry
+ else if ( e->state() == Qt::LeftButton && m_overlayGeometry.contains( e->pos() ) )
+ overlayClick( e->pos() );
+ }
+}
+
+void PresentationWidget::paintEvent( QPaintEvent * pe )
+{
+ if (m_width == -1)
+ {
+ QRect d = KGlobalSettings::desktopGeometry(this);
+ m_width = d.width();
+ m_height = d.height();
+
+ // create top toolbar
+ m_topBar = new KToolBar( this, "presentationBar" );
+ m_topBar->setIconSize( 32 );
+ m_topBar->setMovingEnabled( false );
+ m_topBar->insertButton( QApplication::reverseLayout() ? "1rightarrow" : "1leftarrow", 2, SIGNAL( clicked() ), this, SLOT( slotPrevPage() ) );
+ m_topBar->insertButton( QApplication::reverseLayout() ? "1leftarrow" : "1rightarrow", 3, SIGNAL( clicked() ), this, SLOT( slotNextPage() ) );
+ m_topBar->insertButton( "exit", 1, SIGNAL( clicked() ), this, SLOT( close() ) );
+ m_topBar->setGeometry( 0, 0, m_width, 32 + 10 );
+ m_topBar->alignItemRight( 1 );
+ m_topBar->hide();
+ // change topbar background color
+ QPalette p = m_topBar->palette();
+ p.setColor( QPalette::Active, QColorGroup::Button, Qt::gray );
+ p.setColor( QPalette::Active, QColorGroup::Background, Qt::darkGray );
+ m_topBar->setPalette( p );
+
+ // register this observer in document. events will come immediately
+ m_document->addObserver( this );
+
+ // show summary if requested
+ if ( KpdfSettings::slidesShowSummary() )
+ generatePage();
+
+ KMessageBox::information(this, i18n("There are two ways of exiting presentation mode, you can press either ESC key or click with the quit button that appears when placing the mouse in the top-right corner. Of course you can cycle windows (Alt+TAB by default)"), QString::null, "presentationInfo");
+ }
+
+ // check painting rect consistancy
+ QRect r = pe->rect().intersect( geometry() );
+ if ( r.isNull() || m_lastRenderedPixmap.isNull() )
+ return;
+
+ // blit the pixmap to the screen
+ QMemArray<QRect> allRects = pe->region().rects();
+ uint numRects = allRects.count();
+ for ( uint i = 0; i < numRects; i++ )
+ {
+ const QRect & r = allRects[i];
+ if ( !r.isValid() )
+ continue;
+#ifdef ENABLE_PROGRESS_OVERLAY
+ if ( KpdfSettings::slidesShowProgress() && r.intersects( m_overlayGeometry ) )
+ {
+ // backbuffer the overlay operation
+ QPixmap backPixmap( r.size() );
+ QPainter pixPainter( &backPixmap );
+
+ // first draw the background on the backbuffer
+ pixPainter.drawPixmap( QPoint(0,0), m_lastRenderedPixmap, r );
+
+ // then blend the overlay (a piece of) over the background
+ QRect ovr = m_overlayGeometry.intersect( r );
+ pixPainter.drawPixmap( ovr.left() - r.left(), ovr.top() - r.top(),
+ m_lastRenderedOverlay, ovr.left() - m_overlayGeometry.left(),
+ ovr.top() - m_overlayGeometry.top(), ovr.width(), ovr.height() );
+
+ // finally blit the pixmap to the screen
+ pixPainter.end();
+ bitBlt( this, r.topLeft(), &backPixmap, backPixmap.rect() );
+ } else
+#endif
+ // copy the rendered pixmap to the screen
+ bitBlt( this, r.topLeft(), &m_lastRenderedPixmap, r );
+ }
+}
+// </widget events>
+
+
+const KPDFLink * PresentationWidget::getLink( int x, int y, QRect * geometry ) const
+{
+ // no links on invalid pages
+ if ( geometry && !geometry->isNull() )
+ geometry->setRect( 0, 0, -1, -1 );
+ if ( m_frameIndex < 0 || m_frameIndex >= (int)m_frames.size() )
+ return 0;
+
+ // get frame, page and geometry
+ const PresentationFrame * frame = m_frames[ m_frameIndex ];
+ const KPDFPage * page = frame->page;
+ const QRect & frameGeometry = frame->geometry;
+
+ // compute normalized x and y
+ double nx = (double)(x - frameGeometry.left()) / (double)frameGeometry.width();
+ double ny = (double)(y - frameGeometry.top()) / (double)frameGeometry.height();
+
+ // no links outside the pages
+ if ( nx < 0 || nx > 1 || ny < 0 || ny > 1 )
+ return 0;
+
+ // check if 1) there is an object and 2) it's a link
+ const ObjectRect * object = page->hasObject( ObjectRect::Link, nx, ny );
+ if ( !object )
+ return 0;
+
+ // compute link geometry if destination rect present
+ if ( geometry )
+ {
+ *geometry = object->geometry( frameGeometry.width(), frameGeometry.height() );
+ geometry->moveBy( frameGeometry.left(), frameGeometry.top() );
+ }
+
+ // return the link pointer
+ return (KPDFLink *)object->pointer();
+}
+
+void PresentationWidget::testCursorOnLink( int x, int y )
+{
+ // get rect
+ QRect linkRect;
+ const KPDFLink * link = getLink( x, y, &linkRect );
+
+ // only react on changes (in/out from a link)
+ if ( (link && !m_handCursor) || (!link && m_handCursor) )
+ {
+ // change cursor shape
+ m_handCursor = link != 0;
+ setCursor( m_handCursor ? KCursor::handCursor() : KCursor::arrowCursor());
+
+ // set tooltip over link's rect
+ QString tip = link ? link->linkTip() : QString::null;
+ if ( m_handCursor && !tip.isEmpty() )
+ QToolTip::add( this, linkRect, tip );
+ }
+}
+
+void PresentationWidget::overlayClick( const QPoint & position )
+{
+ // clicking the progress indicator
+ int xPos = position.x() - m_overlayGeometry.x() - m_overlayGeometry.width() / 2,
+ yPos = m_overlayGeometry.height() / 2 - position.y();
+ if ( !xPos && !yPos )
+ return;
+
+ // compute angle relative to indicator (note coord transformation)
+ float angle = 0.5 + 0.5 * atan2( -xPos, -yPos ) / M_PI;
+ int pageIndex = (int)( angle * ( m_frames.count() - 1 ) + 0.5 );
+
+ // go to selected page
+ changePage( pageIndex );
+}
+
+void PresentationWidget::changePage( int newPage )
+{
+ if ( m_frameIndex == newPage )
+ return;
+
+ // check if pixmap exists or else request it
+ m_frameIndex = newPage;
+ PresentationFrame * frame = m_frames[ m_frameIndex ];
+ int pixW = frame->geometry.width();
+ int pixH = frame->geometry.height();
+
+ // if pixmap not inside the KPDFPage we request it and wait for
+ // notifyPixmapChanged call or else we can proceed to pixmap generation
+ if ( !frame->page->hasPixmap( PRESENTATION_ID, pixW, pixH ) )
+ {
+ // operation will take long: set busy cursor
+ QApplication::setOverrideCursor( KCursor::workingCursor() );
+ // request the pixmap
+ QValueList< PixmapRequest * > requests;
+ requests.push_back( new PixmapRequest( PRESENTATION_ID, m_frameIndex, pixW, pixH, PRESENTATION_PRIO ) );
+ // restore cursor
+ QApplication::restoreOverrideCursor();
+ // ask for next and previous page if not in low memory usage setting
+ if (KpdfSettings::memoryLevel() != KpdfSettings::EnumMemoryLevel::Low && KpdfSettings::enableThreading()) {
+ if (newPage + 1 < (int)m_document->pages())
+ {
+ PresentationFrame *nextFrame = m_frames[ newPage + 1 ];
+ pixW = nextFrame->geometry.width();
+ pixH = nextFrame->geometry.height();
+ if ( !nextFrame->page->hasPixmap( PRESENTATION_ID, pixW, pixH ) )
+ requests.push_back( new PixmapRequest( PRESENTATION_ID, newPage + 1, pixW, pixH, PRESENTATION_PRELOAD_PRIO, true ) );
+ }
+ if (newPage - 1 >= 0)
+ {
+ PresentationFrame *prevFrame = m_frames[ newPage - 1 ];
+ pixW = prevFrame->geometry.width();
+ pixH = prevFrame->geometry.height();
+ if ( !prevFrame->page->hasPixmap( PRESENTATION_ID, pixW, pixH ) )
+ requests.push_back( new PixmapRequest( PRESENTATION_ID, newPage - 1, pixW, pixH, PRESENTATION_PRELOAD_PRIO, true ) );
+ }
+ }
+ m_document->requestPixmaps( requests );
+ }
+ else
+ {
+ // make the background pixmap
+ generatePage();
+ }
+
+ // set a new viewport in document if page number differs
+ if ( m_frameIndex != -1 && m_frameIndex != m_document->viewport().pageNumber )
+ m_document->setViewportPage( m_frameIndex, PRESENTATION_ID );
+}
+
+void PresentationWidget::generatePage()
+{
+ if ( m_lastRenderedPixmap.isNull() )
+ m_lastRenderedPixmap.resize( m_width, m_height );
+
+ // opens the painter over the pixmap
+ QPainter pixmapPainter;
+ pixmapPainter.begin( &m_lastRenderedPixmap );
+ // generate welcome page
+ if ( m_frameIndex == -1 )
+ generateIntroPage( pixmapPainter );
+ // generate a normal pixmap with extended margin filling
+ if ( m_frameIndex >= 0 && m_frameIndex < (int)m_document->pages() )
+ generateContentsPage( m_frameIndex, pixmapPainter );
+ pixmapPainter.end();
+
+ // generate the top-right corner overlay
+#ifdef ENABLE_PROGRESS_OVERLAY
+ if ( KpdfSettings::slidesShowProgress() && m_frameIndex != -1 )
+ generateOverlay();
+#endif
+
+ // start transition on pages that have one
+ const KPDFPageTransition * transition = m_frameIndex != -1 ?
+ m_frames[ m_frameIndex ]->page->getTransition() : 0;
+ if ( transition )
+ initTransition( transition );
+ else {
+ KPDFPageTransition trans = defaultTransition();
+ initTransition( &trans );
+ }
+
+ // update cursor + tooltip
+ if ( KpdfSettings::slidesCursor() != KpdfSettings::EnumSlidesCursor::Hidden )
+ {
+ QPoint p = mapFromGlobal( QCursor::pos() );
+ testCursorOnLink( p.x(), p.y() );
+ }
+}
+
+void PresentationWidget::generateIntroPage( QPainter & p )
+{
+ // use a vertical gray gradient background
+ int blend1 = m_height / 10,
+ blend2 = 9 * m_height / 10;
+ int baseTint = Qt::gray.red();
+ for ( int i = 0; i < m_height; i++ )
+ {
+ int k = baseTint;
+ if ( i < blend1 )
+ k -= (int)( baseTint * (i-blend1)*(i-blend1) / (float)(blend1 * blend1) );
+ if ( i > blend2 )
+ k += (int)( (255-baseTint) * (i-blend2)*(i-blend2) / (float)(blend1 * blend1) );
+ p.fillRect( 0, i, m_width, 1, QColor( k, k, k ) );
+ }
+
+ // draw kpdf logo in the four corners
+ QPixmap logo = DesktopIcon( "kpdf", 64 );
+ if ( !logo.isNull() )
+ {
+ p.drawPixmap( 5, 5, logo );
+ p.drawPixmap( m_width - 5 - logo.width(), 5, logo );
+ p.drawPixmap( m_width - 5 - logo.width(), m_height - 5 - logo.height(), logo );
+ p.drawPixmap( 5, m_height - 5 - logo.height(), logo );
+ }
+
+ // draw metadata text (the last line is 'click to begin')
+ int strNum = m_metaStrings.count(),
+ strHeight = m_height / ( strNum + 4 ),
+ fontHeight = 2 * strHeight / 3;
+ QFont font( p.font() );
+ font.setPixelSize( fontHeight );
+ QFontMetrics metrics( font );
+ for ( int i = 0; i < strNum; i++ )
+ {
+ // set a font to fit text width
+ float wScale = (float)metrics.boundingRect( m_metaStrings[i] ).width() / (float)m_width;
+ QFont f( font );
+ if ( wScale > 1.0 )
+ f.setPixelSize( (int)( (float)fontHeight / (float)wScale ) );
+ p.setFont( f );
+
+ // text shadow
+ p.setPen( Qt::darkGray );
+ p.drawText( 2, m_height / 4 + strHeight * i + 2, m_width, strHeight,
+ AlignHCenter | AlignVCenter, m_metaStrings[i] );
+ // text body
+ p.setPen( 128 + (127 * i) / strNum );
+ p.drawText( 0, m_height / 4 + strHeight * i, m_width, strHeight,
+ AlignHCenter | AlignVCenter, m_metaStrings[i] );
+ }
+}
+
+void PresentationWidget::generateContentsPage( int pageNum, QPainter & p )
+{
+ PresentationFrame * frame = m_frames[ pageNum ];
+
+ // translate painter and contents rect
+ QRect geom( frame->geometry );
+ p.translate( geom.left(), geom.top() );
+ geom.moveBy( -geom.left(), -geom.top() );
+
+ // draw the page using the shared PagePainter class
+ int flags = PagePainter::Accessibility;
+ PagePainter::paintPageOnPainter( frame->page, PRESENTATION_ID, flags,
+ &p, geom, geom.width(), geom.height() );
+
+ // restore painter
+ p.translate( -frame->geometry.left(), -frame->geometry.top() );
+
+ // fill unpainted areas with background color
+ QRegion unpainted( QRect( 0, 0, m_width, m_height ) );
+ QMemArray<QRect> rects = unpainted.subtract( frame->geometry ).rects();
+ for ( uint i = 0; i < rects.count(); i++ )
+ {
+ const QRect & r = rects[i];
+ p.fillRect( r, KpdfSettings::slidesBackgroundColor() );
+ }
+}
+
+// from Arthur - Qt4 - (is defined elsewhere as 'qt_div_255' to not break final compilation)
+inline int qt_div255(int x) { return (x + (x>>8) + 0x80) >> 8; }
+void PresentationWidget::generateOverlay()
+{
+#ifdef ENABLE_PROGRESS_OVERLAY
+ // calculate overlay geometry and resize pixmap if needed
+ int side = m_width / 16;
+ m_overlayGeometry.setRect( m_width - side - 4, 4, side, side );
+ if ( m_lastRenderedOverlay.width() != side )
+ m_lastRenderedOverlay.resize( side, side );
+
+ // note: to get a sort of antialiasing, we render the pixmap double sized
+ // and the resulting image is smoothly scaled down. So here we open a
+ // painter on the double sized pixmap.
+ side *= 2;
+ QPixmap doublePixmap( side, side );
+ doublePixmap.fill( Qt::black );
+ QPainter pixmapPainter( &doublePixmap );
+
+ // draw PIE SLICES in blue levels (the levels will then be the alpha component)
+ int pages = m_document->pages();
+ if ( pages > 28 )
+ { // draw continuous slices
+ int degrees = (int)( 360 * (float)(m_frameIndex + 1) / (float)pages );
+ pixmapPainter.setPen( 0x05 );
+ pixmapPainter.setBrush( 0x40 );
+ pixmapPainter.drawPie( 2, 2, side - 4, side - 4, 90*16, (360-degrees)*16 );
+ pixmapPainter.setPen( 0x40 );
+ pixmapPainter.setBrush( 0xF0 );
+ pixmapPainter.drawPie( 2, 2, side - 4, side - 4, 90*16, -degrees*16 );
+ }
+ else
+ { // draw discrete slices
+ float oldCoord = -90;
+ for ( int i = 0; i < pages; i++ )
+ {
+ float newCoord = -90 + 360 * (float)(i + 1) / (float)pages;
+ pixmapPainter.setPen( i <= m_frameIndex ? 0x40 : 0x05 );
+ pixmapPainter.setBrush( i <= m_frameIndex ? 0xF0 : 0x40 );
+ pixmapPainter.drawPie( 2, 2, side - 4, side - 4,
+ (int)( -16*(oldCoord + 1) ), (int)( -16*(newCoord - (oldCoord + 2)) ) );
+ oldCoord = newCoord;
+ }
+ }
+ int circleOut = side / 4;
+ pixmapPainter.setPen( Qt::black );
+ pixmapPainter.setBrush( Qt::black );
+ pixmapPainter.drawEllipse( circleOut, circleOut, side - 2*circleOut, side - 2*circleOut );
+
+ // draw TEXT using maximum opacity
+ QFont f( pixmapPainter.font() );
+ f.setPixelSize( side / 4 );
+ pixmapPainter.setFont( f );
+ pixmapPainter.setPen( 0xFF );
+ // use a little offset to prettify output
+ pixmapPainter.drawText( 2, 2, side, side, Qt::AlignCenter, QString::number( m_frameIndex + 1 ) );
+
+ // end drawing pixmap and halve image
+ pixmapPainter.end();
+ QImage image( doublePixmap.convertToImage().smoothScale( side / 2, side / 2 ) );
+ image.setAlphaBuffer( true );
+
+ // draw circular shadow using the same technique
+ doublePixmap.fill( Qt::black );
+ pixmapPainter.begin( &doublePixmap );
+ pixmapPainter.setPen( 0x40 );
+ pixmapPainter.setBrush( 0x80 );
+ pixmapPainter.drawEllipse( 0, 0, side, side );
+ pixmapPainter.end();
+ QImage shadow( doublePixmap.convertToImage().smoothScale( side / 2, side / 2 ) );
+
+ // generate a 2 colors pixmap using mixing shadow (made with highlight color)
+ // and image (made with highlightedText color)
+ QColor color = palette().active().highlightedText();
+ int red = color.red(), green = color.green(), blue = color.blue();
+ color = palette().active().highlight();
+ int sRed = color.red(), sGreen = color.green(), sBlue = color.blue();
+ // pointers
+ unsigned int * data = (unsigned int *)image.bits(),
+ * shadowData = (unsigned int *)shadow.bits(),
+ pixels = image.width() * image.height();
+ // cache data (reduce computation time to 26%!)
+ int c1 = -1, c2 = -1, cR = 0, cG = 0, cB = 0, cA = 0;
+ // foreach pixel
+ for( unsigned int i = 0; i < pixels; ++i )
+ {
+ // alpha for shadow and image
+ int shadowAlpha = shadowData[i] & 0xFF,
+ srcAlpha = data[i] & 0xFF;
+ // cache values
+ if ( srcAlpha != c1 || shadowAlpha != c2 )
+ {
+ c1 = srcAlpha;
+ c2 = shadowAlpha;
+ // fuse color components and alpha value of image over shadow
+ data[i] = qRgba(
+ cR = qt_div255( srcAlpha * red + (255 - srcAlpha) * sRed ),
+ cG = qt_div255( srcAlpha * green + (255 - srcAlpha) * sGreen ),
+ cB = qt_div255( srcAlpha * blue + (255 - srcAlpha) * sBlue ),
+ cA = qt_div255( srcAlpha * srcAlpha + (255 - srcAlpha) * shadowAlpha )
+ );
+ }
+ else
+ data[i] = qRgba( cR, cG, cB, cA );
+ }
+ m_lastRenderedOverlay.convertFromImage( image );
+
+ // start the autohide timer
+ repaint( m_overlayGeometry, false /*clear*/ ); // toggle with next line
+ //update( m_overlayGeometry );
+ m_overlayHideTimer->start( 2500, true );
+#endif
+}
+
+
+
+void PresentationWidget::slotNextPage()
+{
+ // loop when configured
+ if ( m_frameIndex == (int)m_frames.count() - 1 && KpdfSettings::slidesLoop() )
+ m_frameIndex = -1;
+
+ if ( m_frameIndex < (int)m_frames.count() - 1 )
+ {
+ // go to next page
+ changePage( m_frameIndex + 1 );
+
+ // auto advance to the next page if set
+ if ( KpdfSettings::slidesAdvance() )
+ m_nextPageTimer->start( KpdfSettings::slidesAdvanceTime() * 1000 );
+ }
+ else
+ {
+#ifdef ENABLE_PROGRESS_OVERLAY
+ if ( KpdfSettings::slidesShowProgress() )
+ generateOverlay();
+#endif
+ if ( m_transitionTimer->isActive() )
+ {
+ m_transitionTimer->stop();
+ update();
+ }
+ }
+
+ // we need the setFocus() call here to let KCursor::autoHide() work correctly
+ setFocus();
+}
+
+void PresentationWidget::slotPrevPage()
+{
+ if ( m_frameIndex > 0 )
+ {
+ // go to previous page
+ changePage( m_frameIndex - 1 );
+
+ // auto advance to the next page if set
+ if ( KpdfSettings::slidesAdvance() )
+ m_nextPageTimer->start( KpdfSettings::slidesAdvanceTime() * 1000 );
+ }
+ else
+ {
+#ifdef ENABLE_PROGRESS_OVERLAY
+ if ( KpdfSettings::slidesShowProgress() )
+ generateOverlay();
+#endif
+ if ( m_transitionTimer->isActive() )
+ {
+ m_transitionTimer->stop();
+ update();
+ }
+ }
+}
+
+void PresentationWidget::slotFirstPage()
+{
+ changePage( 0 );
+}
+
+void PresentationWidget::slotLastPage()
+{
+ changePage( (int)m_frames.count() - 1 );
+}
+
+void PresentationWidget::slotHideOverlay()
+{
+ QRect geom( m_overlayGeometry );
+ m_overlayGeometry.setCoords( 0, 0, -1, -1 );
+ update( geom );
+}
+
+void PresentationWidget::slotTransitionStep()
+{
+ if ( m_transitionRects.empty() )
+ {
+ // it's better to fix the transition to cover the whole screen than
+ // enabling the following line that wastes cpu for nothing
+ //update();
+ return;
+ }
+
+ for ( int i = 0; i < m_transitionMul && !m_transitionRects.empty(); i++ )
+ {
+ update( m_transitionRects.first() );
+ m_transitionRects.pop_front();
+ }
+ m_transitionTimer->start( m_transitionDelay, true );
+}
+
+const KPDFPageTransition PresentationWidget::defaultTransition() const
+{
+ return defaultTransition( KpdfSettings::slidesTransition() );
+}
+
+const KPDFPageTransition PresentationWidget::defaultTransition( int type ) const
+{
+ switch ( type )
+ {
+ case KpdfSettings::EnumSlidesTransition::BlindsHorizontal:
+ {
+ KPDFPageTransition transition( KPDFPageTransition::Blinds );
+ transition.setAlignment( KPDFPageTransition::Horizontal );
+ return transition;
+ break;
+ }
+ case KpdfSettings::EnumSlidesTransition::BlindsVertical:
+ {
+ KPDFPageTransition transition( KPDFPageTransition::Blinds );
+ transition.setAlignment( KPDFPageTransition::Vertical );
+ return transition;
+ break;
+ }
+ case KpdfSettings::EnumSlidesTransition::BoxIn:
+ {
+ KPDFPageTransition transition( KPDFPageTransition::Box );
+ transition.setDirection( KPDFPageTransition::Inward );
+ return transition;
+ break;
+ }
+ case KpdfSettings::EnumSlidesTransition::BoxOut:
+ {
+ KPDFPageTransition transition( KPDFPageTransition::Box );
+ transition.setDirection( KPDFPageTransition::Outward );
+ return transition;
+ break;
+ }
+ case KpdfSettings::EnumSlidesTransition::Dissolve:
+ {
+ return KPDFPageTransition( KPDFPageTransition::Dissolve );
+ break;
+ }
+ case KpdfSettings::EnumSlidesTransition::GlitterDown:
+ {
+ KPDFPageTransition transition( KPDFPageTransition::Glitter );
+ transition.setAngle( 270 );
+ return transition;
+ break;
+ }
+ case KpdfSettings::EnumSlidesTransition::GlitterRight:
+ {
+ KPDFPageTransition transition( KPDFPageTransition::Glitter );
+ transition.setAngle( 0 );
+ return transition;
+ break;
+ }
+ case KpdfSettings::EnumSlidesTransition::GlitterRightDown:
+ {
+ KPDFPageTransition transition( KPDFPageTransition::Glitter );
+ transition.setAngle( 315 );
+ return transition;
+ break;
+ }
+ case KpdfSettings::EnumSlidesTransition::Random:
+ {
+ return defaultTransition( KApplication::random() % 18 );
+ break;
+ }
+ case KpdfSettings::EnumSlidesTransition::SplitHorizontalIn:
+ {
+ KPDFPageTransition transition( KPDFPageTransition::Split );
+ transition.setAlignment( KPDFPageTransition::Horizontal );
+ transition.setDirection( KPDFPageTransition::Inward );
+ return transition;
+ break;
+ }
+ case KpdfSettings::EnumSlidesTransition::SplitHorizontalOut:
+ {
+ KPDFPageTransition transition( KPDFPageTransition::Split );
+ transition.setAlignment( KPDFPageTransition::Horizontal );
+ transition.setDirection( KPDFPageTransition::Outward );
+ return transition;
+ break;
+ }
+ case KpdfSettings::EnumSlidesTransition::SplitVerticalIn:
+ {
+ KPDFPageTransition transition( KPDFPageTransition::Split );
+ transition.setAlignment( KPDFPageTransition::Vertical );
+ transition.setDirection( KPDFPageTransition::Inward );
+ return transition;
+ break;
+ }
+ case KpdfSettings::EnumSlidesTransition::SplitVerticalOut:
+ {
+ KPDFPageTransition transition( KPDFPageTransition::Split );
+ transition.setAlignment( KPDFPageTransition::Vertical );
+ transition.setDirection( KPDFPageTransition::Outward );
+ return transition;
+ break;
+ }
+ case KpdfSettings::EnumSlidesTransition::WipeDown:
+ {
+ KPDFPageTransition transition( KPDFPageTransition::Wipe );
+ transition.setAngle( 270 );
+ return transition;
+ break;
+ }
+ case KpdfSettings::EnumSlidesTransition::WipeRight:
+ {
+ KPDFPageTransition transition( KPDFPageTransition::Wipe );
+ transition.setAngle( 0 );
+ return transition;
+ break;
+ }
+ case KpdfSettings::EnumSlidesTransition::WipeLeft:
+ {
+ KPDFPageTransition transition( KPDFPageTransition::Wipe );
+ transition.setAngle( 180 );
+ return transition;
+ break;
+ }
+ case KpdfSettings::EnumSlidesTransition::WipeUp:
+ {
+ KPDFPageTransition transition( KPDFPageTransition::Wipe );
+ transition.setAngle( 90 );
+ return transition;
+ break;
+ }
+ case KpdfSettings::EnumSlidesTransition::Replace:
+ default:
+ return KPDFPageTransition( KPDFPageTransition::Replace );
+ break;
+ }
+}
+
+/** ONLY the TRANSITIONS GENERATION function from here on **/
+void PresentationWidget::initTransition( const KPDFPageTransition *transition )
+{
+ // if it's just a 'replace' transition, repaint the screen
+ if ( transition->type() == KPDFPageTransition::Replace )
+ {
+ update();
+ return;
+ }
+
+ const bool isInward = transition->direction() == KPDFPageTransition::Inward;
+ const bool isHorizontal = transition->alignment() == KPDFPageTransition::Horizontal;
+ const float totalTime = transition->duration();
+
+ m_transitionRects.clear();
+
+ switch( transition->type() )
+ {
+ // split: horizontal / vertical and inward / outward
+ case KPDFPageTransition::Split:
+ {
+ const int steps = isHorizontal ? 100 : 75;
+ if ( isHorizontal )
+ {
+ if ( isInward )
+ {
+ int xPosition = 0;
+ for ( int i = 0; i < steps; i++ )
+ {
+ int xNext = ((i + 1) * m_width) / (2 * steps);
+ m_transitionRects.push_back( QRect( xPosition, 0, xNext - xPosition, m_height ) );
+ m_transitionRects.push_back( QRect( m_width - xNext, 0, xNext - xPosition, m_height ) );
+ xPosition = xNext;
+ }
+ }
+ else
+ {
+ int xPosition = m_width / 2;
+ for ( int i = 0; i < steps; i++ )
+ {
+ int xNext = ((steps - (i + 1)) * m_width) / (2 * steps);
+ m_transitionRects.push_back( QRect( xNext, 0, xPosition - xNext, m_height ) );
+ m_transitionRects.push_back( QRect( m_width - xPosition, 0, xPosition - xNext, m_height ) );
+ xPosition = xNext;
+ }
+ }
+ }
+ else
+ {
+ if ( isInward )
+ {
+ int yPosition = 0;
+ for ( int i = 0; i < steps; i++ )
+ {
+ int yNext = ((i + 1) * m_height) / (2 * steps);
+ m_transitionRects.push_back( QRect( 0, yPosition, m_width, yNext - yPosition ) );
+ m_transitionRects.push_back( QRect( 0, m_height - yNext, m_width, yNext - yPosition ) );
+ yPosition = yNext;
+ }
+ }
+ else
+ {
+ int yPosition = m_height / 2;
+ for ( int i = 0; i < steps; i++ )
+ {
+ int yNext = ((steps - (i + 1)) * m_height) / (2 * steps);
+ m_transitionRects.push_back( QRect( 0, yNext, m_width, yPosition - yNext ) );
+ m_transitionRects.push_back( QRect( 0, m_height - yPosition, m_width, yPosition - yNext ) );
+ yPosition = yNext;
+ }
+ }
+ }
+ m_transitionMul = 2;
+ m_transitionDelay = (int)( (totalTime * 1000) / steps );
+ } break;
+
+ // blinds: horizontal(l-to-r) / vertical(t-to-b)
+ case KPDFPageTransition::Blinds:
+ {
+ const int blinds = isHorizontal ? 8 : 6;
+ const int steps = m_width / (4 * blinds);
+ if ( isHorizontal )
+ {
+ int xPosition[ 8 ];
+ for ( int b = 0; b < blinds; b++ )
+ xPosition[ b ] = (b * m_width) / blinds;
+
+ for ( int i = 0; i < steps; i++ )
+ {
+ int stepOffset = (int)( ((float)i * (float)m_width) / ((float)blinds * (float)steps) );
+ for ( int b = 0; b < blinds; b++ )
+ {
+ m_transitionRects.push_back( QRect( xPosition[ b ], 0, stepOffset, m_height ) );
+ xPosition[ b ] = stepOffset + (b * m_width) / blinds;
+ }
+ }
+ }
+ else
+ {
+ int yPosition[ 6 ];
+ for ( int b = 0; b < blinds; b++ )
+ yPosition[ b ] = (b * m_height) / blinds;
+
+ for ( int i = 0; i < steps; i++ )
+ {
+ int stepOffset = (int)( ((float)i * (float)m_height) / ((float)blinds * (float)steps) );
+ for ( int b = 0; b < blinds; b++ )
+ {
+ m_transitionRects.push_back( QRect( 0, yPosition[ b ], m_width, stepOffset ) );
+ yPosition[ b ] = stepOffset + (b * m_height) / blinds;
+ }
+ }
+ }
+ m_transitionMul = blinds;
+ m_transitionDelay = (int)( (totalTime * 1000) / steps );
+ } break;
+
+ // box: inward / outward
+ case KPDFPageTransition::Box:
+ {
+ const int steps = m_width / 10;
+ if ( isInward )
+ {
+ int L = 0, T = 0, R = m_width, B = m_height;
+ for ( int i = 0; i < steps; i++ )
+ {
+ // compure shrinked box coords
+ int newL = ((i + 1) * m_width) / (2 * steps);
+ int newT = ((i + 1) * m_height) / (2 * steps);
+ int newR = m_width - newL;
+ int newB = m_height - newT;
+ // add left, right, topcenter, bottomcenter rects
+ m_transitionRects.push_back( QRect( L, T, newL - L, B - T ) );
+ m_transitionRects.push_back( QRect( newR, T, R - newR, B - T ) );
+ m_transitionRects.push_back( QRect( newL, T, newR - newL, newT - T ) );
+ m_transitionRects.push_back( QRect( newL, newB, newR - newL, B - newB ) );
+ L = newL; T = newT; R = newR, B = newB;
+ }
+ }
+ else
+ {
+ int L = m_width / 2, T = m_height / 2, R = L, B = T;
+ for ( int i = 0; i < steps; i++ )
+ {
+ // compure shrinked box coords
+ int newL = ((steps - (i + 1)) * m_width) / (2 * steps);
+ int newT = ((steps - (i + 1)) * m_height) / (2 * steps);
+ int newR = m_width - newL;
+ int newB = m_height - newT;
+ // add left, right, topcenter, bottomcenter rects
+ m_transitionRects.push_back( QRect( newL, newT, L - newL, newB - newT ) );
+ m_transitionRects.push_back( QRect( R, newT, newR - R, newB - newT ) );
+ m_transitionRects.push_back( QRect( L, newT, R - L, T - newT ) );
+ m_transitionRects.push_back( QRect( L, B, R - L, newB - B ) );
+ L = newL; T = newT; R = newR, B = newB;
+ }
+ }
+ m_transitionMul = 4;
+ m_transitionDelay = (int)( (totalTime * 1000) / steps );
+ } break;
+
+ // wipe: implemented for 4 canonical angles
+ case KPDFPageTransition::Wipe:
+ {
+ const int angle = transition->angle();
+ const int steps = (angle == 0) || (angle == 180) ? m_width / 8 : m_height / 8;
+ if ( angle == 0 )
+ {
+ int xPosition = 0;
+ for ( int i = 0; i < steps; i++ )
+ {
+ int xNext = ((i + 1) * m_width) / steps;
+ m_transitionRects.push_back( QRect( xPosition, 0, xNext - xPosition, m_height ) );
+ xPosition = xNext;
+ }
+ }
+ else if ( angle == 90 )
+ {
+ int yPosition = m_height;
+ for ( int i = 0; i < steps; i++ )
+ {
+ int yNext = ((steps - (i + 1)) * m_height) / steps;
+ m_transitionRects.push_back( QRect( 0, yNext, m_width, yPosition - yNext ) );
+ yPosition = yNext;
+ }
+ }
+ else if ( angle == 180 )
+ {
+ int xPosition = m_width;
+ for ( int i = 0; i < steps; i++ )
+ {
+ int xNext = ((steps - (i + 1)) * m_width) / steps;
+ m_transitionRects.push_back( QRect( xNext, 0, xPosition - xNext, m_height ) );
+ xPosition = xNext;
+ }
+ }
+ else if ( angle == 270 )
+ {
+ int yPosition = 0;
+ for ( int i = 0; i < steps; i++ )
+ {
+ int yNext = ((i + 1) * m_height) / steps;
+ m_transitionRects.push_back( QRect( 0, yPosition, m_width, yNext - yPosition ) );
+ yPosition = yNext;
+ }
+ }
+ else
+ {
+ update();
+ return;
+ }
+ m_transitionMul = 1;
+ m_transitionDelay = (int)( (totalTime * 1000) / steps );
+ } break;
+
+ // dissolve: replace 'random' rects
+ case KPDFPageTransition::Dissolve:
+ {
+ const int gridXsteps = 50;
+ const int gridYsteps = 38;
+ const int steps = gridXsteps * gridYsteps;
+ int oldX = 0;
+ int oldY = 0;
+ // create a grid of gridXstep by gridYstep QRects
+ for ( int y = 0; y < gridYsteps; y++ )
+ {
+ int newY = (int)( m_height * ((float)(y+1) / (float)gridYsteps) );
+ for ( int x = 0; x < gridXsteps; x++ )
+ {
+ int newX = (int)( m_width * ((float)(x+1) / (float)gridXsteps) );
+ m_transitionRects.push_back( QRect( oldX, oldY, newX - oldX, newY - oldY ) );
+ oldX = newX;
+ }
+ oldX = 0;
+ oldY = newY;
+ }
+ // randomize the grid
+ for ( int i = 0; i < steps; i++ )
+ {
+ int n1 = (int)(steps * drand48());
+ int n2 = (int)(steps * drand48());
+ // swap items if index differs
+ if ( n1 != n2 )
+ {
+ QRect r = m_transitionRects[ n2 ];
+ m_transitionRects[ n2 ] = m_transitionRects[ n1 ];
+ m_transitionRects[ n1 ] = r;
+ }
+ }
+ // set global transition parameters
+ m_transitionMul = 40;
+ m_transitionDelay = (int)( (m_transitionMul * 1000 * totalTime) / steps );
+ } break;
+
+ // glitter: similar to dissolve but has a direction
+ case KPDFPageTransition::Glitter:
+ {
+ const int gridXsteps = 50;
+ const int gridYsteps = 38;
+ const int steps = gridXsteps * gridYsteps;
+ const int angle = transition->angle();
+ // generate boxes using a given direction
+ if ( angle == 90 )
+ {
+ int yPosition = m_height;
+ for ( int i = 0; i < gridYsteps; i++ )
+ {
+ int yNext = ((gridYsteps - (i + 1)) * m_height) / gridYsteps;
+ int xPosition = 0;
+ for ( int j = 0; j < gridXsteps; j++ )
+ {
+ int xNext = ((j + 1) * m_width) / gridXsteps;
+ m_transitionRects.push_back( QRect( xPosition, yNext, xNext - xPosition, yPosition - yNext ) );
+ xPosition = xNext;
+ }
+ yPosition = yNext;
+ }
+ }
+ else if ( angle == 180 )
+ {
+ int xPosition = m_width;
+ for ( int i = 0; i < gridXsteps; i++ )
+ {
+ int xNext = ((gridXsteps - (i + 1)) * m_width) / gridXsteps;
+ int yPosition = 0;
+ for ( int j = 0; j < gridYsteps; j++ )
+ {
+ int yNext = ((j + 1) * m_height) / gridYsteps;
+ m_transitionRects.push_back( QRect( xNext, yPosition, xPosition - xNext, yNext - yPosition ) );
+ yPosition = yNext;
+ }
+ xPosition = xNext;
+ }
+ }
+ else if ( angle == 270 )
+ {
+ int yPosition = 0;
+ for ( int i = 0; i < gridYsteps; i++ )
+ {
+ int yNext = ((i + 1) * m_height) / gridYsteps;
+ int xPosition = 0;
+ for ( int j = 0; j < gridXsteps; j++ )
+ {
+ int xNext = ((j + 1) * m_width) / gridXsteps;
+ m_transitionRects.push_back( QRect( xPosition, yPosition, xNext - xPosition, yNext - yPosition ) );
+ xPosition = xNext;
+ }
+ yPosition = yNext;
+ }
+ }
+ else // if angle is 0 or 315
+ {
+ int xPosition = 0;
+ for ( int i = 0; i < gridXsteps; i++ )
+ {
+ int xNext = ((i + 1) * m_width) / gridXsteps;
+ int yPosition = 0;
+ for ( int j = 0; j < gridYsteps; j++ )
+ {
+ int yNext = ((j + 1) * m_height) / gridYsteps;
+ m_transitionRects.push_back( QRect( xPosition, yPosition, xNext - xPosition, yNext - yPosition ) );
+ yPosition = yNext;
+ }
+ xPosition = xNext;
+ }
+ }
+ // add a 'glitter' (1 over 10 pieces is randomized)
+ int randomSteps = steps / 20;
+ for ( int i = 0; i < randomSteps; i++ )
+ {
+ int n1 = (int)(steps * drand48());
+ int n2 = (int)(steps * drand48());
+ // swap items if index differs
+ if ( n1 != n2 )
+ {
+ QRect r = m_transitionRects[ n2 ];
+ m_transitionRects[ n2 ] = m_transitionRects[ n1 ];
+ m_transitionRects[ n1 ] = r;
+ }
+ }
+ // set global transition parameters
+ m_transitionMul = (angle == 90) || (angle == 270) ? gridYsteps : gridXsteps;
+ m_transitionMul /= 2;
+ m_transitionDelay = (int)( (m_transitionMul * 1000 * totalTime) / steps );
+ } break;
+
+ // implement missing transitions (a binary raster engine needed here)
+ case KPDFPageTransition::Fly:
+
+ case KPDFPageTransition::Push:
+
+ case KPDFPageTransition::Cover:
+
+ case KPDFPageTransition::Uncover:
+
+ case KPDFPageTransition::Fade:
+
+ default:
+ update();
+ return;
+ }
+
+ // send the first start to the timer
+ m_transitionTimer->start( 0, true );
+}
+
+
+#include "presentationwidget.moc"
diff --git a/kpdf/ui/presentationwidget.h b/kpdf/ui/presentationwidget.h
new file mode 100644
index 00000000..4b0cdf19
--- /dev/null
+++ b/kpdf/ui/presentationwidget.h
@@ -0,0 +1,108 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef _KPDF_PRESENTATIONWIDGET_H_
+#define _KPDF_PRESENTATIONWIDGET_H_
+
+#include <qdialog.h>
+#include <qpixmap.h>
+#include <qstringlist.h>
+#include <qvaluevector.h>
+#include "core/observer.h"
+#include "core/pagetransition.h"
+
+class KAccel;
+class KActionCollection;
+class KToolBar;
+class QTimer;
+
+class KPDFDocument;
+class KPDFPage;
+class KPDFLink;
+class PresentationFrame;
+
+/**
+ * @short A widget that shows pages as fullscreen slides (with transitions fx).
+ *
+ * This is a fullscreen widget that displays
+ */
+class PresentationWidget : public QDialog, public DocumentObserver
+{
+ Q_OBJECT
+ public:
+ PresentationWidget( QWidget * parent, KPDFDocument * doc );
+ ~PresentationWidget();
+
+ void setupActions( KActionCollection * ac );
+
+ // inherited from DocumentObserver
+ uint observerId() const { return PRESENTATION_ID; }
+ void notifySetup( const QValueVector< KPDFPage * > & pages, bool documentChanged );
+ void notifyViewportChanged( bool smoothMove );
+ void notifyPageChanged( int pageNumber, int changedFlags );
+ bool canUnloadPixmap( int pageNumber );
+
+ protected:
+ // widget events
+// bool event( QEvent * e );
+ void keyPressEvent( QKeyEvent * e );
+ void wheelEvent( QWheelEvent * e );
+ void mousePressEvent( QMouseEvent * e );
+ void mouseReleaseEvent( QMouseEvent * e );
+ void mouseMoveEvent( QMouseEvent * e );
+ void paintEvent( QPaintEvent * e );
+
+ private:
+ const KPDFLink * getLink( int x, int y, QRect * geometry = 0 ) const;
+ void testCursorOnLink( int x, int y );
+ void overlayClick( const QPoint & position );
+ void changePage( int newPage );
+ void generatePage();
+ void generateIntroPage( QPainter & p );
+ void generateContentsPage( int page, QPainter & p );
+ void generateOverlay();
+ void initTransition( const KPDFPageTransition *transition );
+ const KPDFPageTransition defaultTransition() const;
+ const KPDFPageTransition defaultTransition( int ) const;
+
+ // cache stuff
+ int m_width;
+ int m_height;
+ QPixmap m_lastRenderedPixmap;
+ QPixmap m_lastRenderedOverlay;
+ QRect m_overlayGeometry;
+ const KPDFLink * m_pressedLink;
+ bool m_handCursor;
+
+ // transition related
+ QTimer * m_transitionTimer;
+ QTimer * m_overlayHideTimer;
+ QTimer * m_nextPageTimer;
+ int m_transitionDelay;
+ int m_transitionMul;
+ QValueList< QRect > m_transitionRects;
+
+ // misc stuff
+ KPDFDocument * m_document;
+ QValueVector< PresentationFrame * > m_frames;
+ int m_frameIndex;
+ QStringList m_metaStrings;
+ KToolBar * m_topBar;
+ KAccel * m_accel;
+
+ private slots:
+ void slotNextPage();
+ void slotPrevPage();
+ void slotFirstPage();
+ void slotLastPage();
+ void slotHideOverlay();
+ void slotTransitionStep();
+};
+
+#endif
diff --git a/kpdf/ui/propertiesdialog.cpp b/kpdf/ui/propertiesdialog.cpp
new file mode 100644
index 00000000..d5810a07
--- /dev/null
+++ b/kpdf/ui/propertiesdialog.cpp
@@ -0,0 +1,94 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Albert Astals Cid <tsdgeos@terra.es> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+// qt/kde includes
+#include <qlayout.h>
+#include <qlabel.h>
+#include <klistview.h>
+#include <klocale.h>
+#include <ksqueezedtextlabel.h>
+#include <kglobalsettings.h>
+
+// local includes
+#include "propertiesdialog.h"
+#include "core/document.h"
+
+PropertiesDialog::PropertiesDialog(QWidget *parent, KPDFDocument *doc)
+ : KDialogBase( Tabbed, i18n( "Unknown File" ), Ok, Ok, parent, 0, true, true )
+{
+ // Properties
+ QFrame *page = addPage(i18n("Properties"));
+ QGridLayout *layout = new QGridLayout( page, 2, 2, marginHint(), spacingHint() );
+
+ // get document info, if not present display blank data and a warning
+ const DocumentInfo * info = doc->documentInfo();
+ if ( !info ) {
+ layout->addWidget( new QLabel( i18n( "No document opened." ), page ), 0, 0 );
+ return;
+ }
+
+ // mime name based on mimetype id
+ QString mimeName = info->get( "mimeType" ).section( '/', -1 ).upper();
+ setCaption( i18n("%1 Properties").arg( mimeName ) );
+
+ QDomElement docElement = info->documentElement();
+
+ int row = 0;
+ int valMaxWidth = 100;
+ for ( QDomNode node = docElement.firstChild(); !node.isNull(); node = node.nextSibling() ) {
+ QDomElement element = node.toElement();
+
+ QString titleString = element.attribute( "title" );
+ QString valueString = element.attribute( "value" );
+ if ( titleString.isEmpty() || valueString.isEmpty() )
+ continue;
+
+ // create labels and layout them
+ QLabel *key = new QLabel( i18n( "%1:" ).arg( titleString ), page );
+ QLabel *value = new KSqueezedTextLabel( valueString, page );
+ layout->addWidget( key, row, 0, AlignRight );
+ layout->addWidget( value, row, 1 );
+ row++;
+
+ // refine maximum width of 'value' labels
+ valMaxWidth = QMAX( valMaxWidth, fontMetrics().width( valueString ) );
+ }
+
+ // add the number of pages if the generator hasn't done it already
+ QDomNodeList list = docElement.elementsByTagName( "pages" );
+ if ( list.count() == 0 ) {
+ QLabel *key = new QLabel( i18n( "Pages:" ), page );
+ QLabel *value = new QLabel( QString::number( doc->pages() ), page );
+
+ layout->addWidget( key, row, 0 );
+ layout->addWidget( value, row, 1 );
+ }
+
+ // Fonts
+ QVBoxLayout *page2Layout = 0;
+ if (doc->hasFonts())
+ {
+ QFrame *page2 = addPage(i18n("Fonts"));
+ page2Layout = new QVBoxLayout(page2, 0, KDialog::spacingHint());
+ KListView *lv = new KListView(page2);
+ page2Layout->add(lv);
+ doc->putFontInfo(lv);
+ }
+
+ // current width: left column + right column + dialog borders
+ int width = layout->minimumSize().width() + valMaxWidth + marginHint() + spacingHint() + marginHint() + 30;
+ if (page2Layout)
+ {
+ width = QMAX( width, page2Layout->sizeHint().width() + marginHint() + spacingHint() + 31 );
+ }
+ // stay inside the 2/3 of the screen width
+ QRect screenContainer = KGlobalSettings::desktopGeometry( this );
+ width = QMIN( width, 2*screenContainer.width()/3 );
+ resize(width, 1);
+}
diff --git a/kpdf/ui/propertiesdialog.h b/kpdf/ui/propertiesdialog.h
new file mode 100644
index 00000000..7bc39e5a
--- /dev/null
+++ b/kpdf/ui/propertiesdialog.h
@@ -0,0 +1,23 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Albert Astals Cid <tsdgeos@terra.es> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef _PROPERTIESDIALOG_H_
+#define _PROPERTIESDIALOG_H_
+
+#include <kdialogbase.h>
+
+class KPDFDocument;
+
+class PropertiesDialog : public KDialogBase
+{
+ public:
+ PropertiesDialog( QWidget *parent, KPDFDocument *doc );
+};
+
+#endif
diff --git a/kpdf/ui/searchwidget.cpp b/kpdf/ui/searchwidget.cpp
new file mode 100644
index 00000000..30a5bcf2
--- /dev/null
+++ b/kpdf/ui/searchwidget.cpp
@@ -0,0 +1,135 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+// qt/kde includes
+#include <qtooltip.h>
+#include <qapplication.h>
+#include <qtimer.h>
+#include <kaction.h>
+#include <kactioncollection.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <klineedit.h>
+#include <kpopupmenu.h>
+#include <ktoolbarbutton.h>
+
+// local includes
+#include "searchwidget.h"
+#include "core/document.h"
+#include "conf/settings.h"
+
+#define CLEAR_ID 1
+#define LEDIT_ID 2
+#define FIND_ID 3
+
+SearchWidget::SearchWidget( QWidget * parent, KPDFDocument * document )
+ : KToolBar( parent, "iSearchBar" ), m_document( document ),
+ m_searchType( 0 ), m_caseSensitive( false )
+{
+ // change toolbar appearance
+ setMargin( 3 );
+ setFlat( true );
+ setIconSize( 16 );
+ setMovingEnabled( false );
+
+ // a timer to ensure that we don't flood the document with requests to search
+ m_inputDelayTimer = new QTimer(this);
+ connect( m_inputDelayTimer, SIGNAL( timeout() ),
+ this, SLOT( startSearch() ) );
+
+ // 1. text line
+ insertLined( QString::null, LEDIT_ID, SIGNAL( textChanged(const QString &) ),
+ this, SLOT( slotTextChanged(const QString &) ), true,
+ i18n( "Enter at least 3 letters to filter pages" ), 0/*size*/, 1 );
+
+ // 2. clear button (uses a lineEdit slot, so it must be created after)
+ insertButton( QApplication::reverseLayout() ? "clear_left" : "locationbar_erase",
+ CLEAR_ID, SIGNAL( clicked() ),
+ getLined( LEDIT_ID ), SLOT( clear() ), true,
+ i18n( "Clear filter" ), 0/*index*/ );
+
+ // 3.1. create the popup menu for changing filtering features
+ m_menu = new KPopupMenu( this );
+ m_menu->insertItem( i18n("Case Sensitive"), 1 );
+ m_menu->insertSeparator( 2 );
+ m_menu->insertItem( i18n("Match Phrase"), 3 );
+ m_menu->insertItem( i18n("Match All Words"), 4 );
+ m_menu->insertItem( i18n("Match Any Word"), 5 );
+ m_menu->setItemChecked( 3, true );
+ connect( m_menu, SIGNAL( activated(int) ), SLOT( slotMenuChaged(int) ) );
+
+ // 3.2. create the toolbar button that spawns the popup menu
+ insertButton( "kpdf", FIND_ID, m_menu, true, i18n( "Filter Options" ), 2/*index*/ );
+
+ // always maximize the text line
+ setItemAutoSized( LEDIT_ID );
+}
+
+void SearchWidget::clearText()
+{
+ getLined( LEDIT_ID )->clear();
+}
+
+void SearchWidget::slotTextChanged( const QString & text )
+{
+ // if 0<length<3 set 'red' text and send a blank string to document
+ QColor color = text.length() > 0 && text.length() < 3 ? Qt::darkRed : palette().active().text();
+ KLineEdit * lineEdit = getLined( LEDIT_ID );
+ lineEdit->setPaletteForegroundColor( color );
+ lineEdit->setPaletteBackgroundColor( palette().active().base() );
+ m_inputDelayTimer->stop();
+ m_inputDelayTimer->start(333, true);
+}
+
+void SearchWidget::slotMenuChaged( int index )
+{
+ // update internal variables and checked state
+ if ( index == 1 )
+ {
+ m_caseSensitive = !m_caseSensitive;
+ m_menu->setItemChecked( 1, m_caseSensitive );
+ }
+ else if ( index >= 3 && index <= 5 )
+ {
+ m_searchType = index - 3;
+ for ( int i = 0; i < 3; i++ )
+ m_menu->setItemChecked( i + 3, m_searchType == i );
+ }
+ else
+ return;
+
+ // update search
+ slotTextChanged( getLined( LEDIT_ID )->text() );
+}
+
+void SearchWidget::startSearch()
+{
+ // search text if have more than 3 chars or else clear search
+ QString text = getLined( LEDIT_ID )->text();
+ bool ok = true;
+ if ( text.length() >= 3 )
+ {
+ KPDFDocument::SearchType type = !m_searchType ? KPDFDocument::AllDoc :
+ ( (m_searchType > 1) ? KPDFDocument::GoogleAny :
+ KPDFDocument::GoogleAll );
+ ok = m_document->searchText( SW_SEARCH_ID, text, true, m_caseSensitive,
+ type, false, qRgb( 0, 183, 255 ) );
+ }
+ else
+ m_document->resetSearch( SW_SEARCH_ID );
+ // if not found, use warning colors
+ if ( !ok )
+ {
+ KLineEdit * lineEdit = getLined( LEDIT_ID );
+ lineEdit->setPaletteForegroundColor( Qt::white );
+ lineEdit->setPaletteBackgroundColor( Qt::red );
+ }
+}
+
+#include "searchwidget.moc"
diff --git a/kpdf/ui/searchwidget.h b/kpdf/ui/searchwidget.h
new file mode 100644
index 00000000..9f2a1e44
--- /dev/null
+++ b/kpdf/ui/searchwidget.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef _KPDF_SEARCHWIDGET_H_
+#define _KPDF_SEARCHWIDGET_H_
+
+#include <ktoolbar.h>
+
+class KPopupMenu;
+class KPDFDocument;
+class m_inputDelayTimer;
+
+// definition of searchID for this class (publicly available to ThumbnailsList)
+#define SW_SEARCH_ID 3
+
+/**
+ * @short A widget for find-as-you-type search. Outputs to the Document.
+ *
+ * This widget accepts keyboard input and performs a call to findTextAll(..)
+ * in the KPDFDocument class when there are 3 or more chars to search for.
+ * It supports case sensitive/unsensitive(default) and provieds a button
+ * for switching between the 2 modes.
+ */
+class SearchWidget : public KToolBar
+{
+ Q_OBJECT
+ public:
+ SearchWidget( QWidget *parent, KPDFDocument *document );
+ void clearText();
+
+ private:
+ KPDFDocument * m_document;
+ KPopupMenu * m_menu;
+ QTimer * m_inputDelayTimer;
+ int m_searchType;
+ bool m_caseSensitive;
+
+ private slots:
+ void slotTextChanged( const QString & text );
+ void slotMenuChaged( int index );
+ void startSearch();
+};
+
+#endif
diff --git a/kpdf/ui/thumbnaillist.cpp b/kpdf/ui/thumbnaillist.cpp
new file mode 100644
index 00000000..60324533
--- /dev/null
+++ b/kpdf/ui/thumbnaillist.cpp
@@ -0,0 +1,575 @@
+/***************************************************************************
+ * Copyright (C) 2004-2006 by Albert Astals Cid <tsdgeos@terra.es> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+// qt/kde includes
+#include <qtimer.h>
+#include <qpainter.h>
+#include <klocale.h>
+#include <kurl.h>
+#include <kurldrag.h>
+#include <kaction.h>
+#include <kiconloader.h>
+#include <kactioncollection.h>
+
+// local includes
+#include "thumbnaillist.h"
+#include "pagepainter.h"
+#include "searchwidget.h" // for SW_SEARCH_ID
+#include "core/document.h"
+#include "core/generator.h"
+#include "core/page.h"
+#include "conf/settings.h"
+
+// ThumbnailWidget represents a single thumbnail in the ThumbnailList
+class ThumbnailWidget : public QWidget
+{
+ public:
+ ThumbnailWidget( QWidget * parent, const KPDFPage * page, ThumbnailList * tl );
+
+ // set internal parameters to fit the page in the given width
+ void resizeFitWidth( int width );
+ // set thumbnail's selected state
+ void setSelected( bool selected );
+
+ // query methods
+ int heightHint() const { return m_pixmapHeight + m_labelHeight + m_margin; }
+ int pixmapWidth() const { return m_pixmapWidth; }
+ int pixmapHeight() const { return m_pixmapHeight; }
+ int pageNumber() const { return m_page->number(); }
+ const KPDFPage * page() const { return m_page; }
+
+ protected:
+ void mouseReleaseEvent( QMouseEvent * e );
+ void paintEvent(QPaintEvent *);
+
+ private:
+ // the margin around the widget
+ static int const m_margin = 16;
+
+ // used to access 'forwardRightClick( .. )' and 'getBookmarkOverlay()'
+ ThumbnailList * m_tl;
+ const KPDFPage * m_page;
+ bool m_selected;
+ int m_pixmapWidth, m_pixmapHeight;
+ int m_labelHeight, m_labelNumber;
+};
+
+
+/** ThumbnailList implementation **/
+
+ThumbnailList::ThumbnailList( QWidget *parent, KPDFDocument *document )
+ : QScrollView( parent, "KPDF::Thumbnails", WNoAutoErase | WStaticContents ),
+ m_document( document ), m_selected( 0 ), m_delayTimer( 0 ), m_bookmarkOverlay( 0 )
+{
+ // set scrollbars
+ setHScrollBarMode( QScrollView::AlwaysOff );
+ setVScrollBarMode( QScrollView::AlwaysOn );
+
+ // dealing with large areas so enable clipper
+ enableClipper( true );
+
+ // widget setup: can be focused by tab and mouse click (not wheel)
+ viewport()->setFocusProxy( this );
+ viewport()->setFocusPolicy( StrongFocus );
+ setResizePolicy( Manual );
+ setAcceptDrops( true );
+ setDragAutoScroll( false );
+
+ // set contents background to the 'base' color
+ viewport()->setPaletteBackgroundColor( palette().active().base() );
+
+ setFrameStyle( StyledPanel | Raised );
+ connect( this, SIGNAL(contentsMoving(int, int)), this, SLOT(slotRequestVisiblePixmaps(int, int)) );
+}
+
+ThumbnailList::~ThumbnailList()
+{
+ m_document->removeObserver( this );
+ delete m_bookmarkOverlay;
+}
+
+//BEGIN DocumentObserver inherited methods
+void ThumbnailList::notifySetup( const QValueVector< KPDFPage * > & pages, bool documentChanged )
+{
+ // if there was a widget selected, save its pagenumber to restore
+ // its selection (if available in the new set of pages)
+ int prevPage = -1;
+ if ( !documentChanged && m_selected )
+ {
+ prevPage = m_selected->page()->number();
+ }
+
+ // delete all the Thumbnails
+ QValueVector<ThumbnailWidget *>::iterator tIt = m_thumbnails.begin(), tEnd = m_thumbnails.end();
+ for ( ; tIt != tEnd; ++tIt )
+ delete *tIt;
+ m_thumbnails.clear();
+ m_visibleThumbnails.clear();
+ m_selected = 0;
+
+ if ( pages.count() < 1 )
+ {
+ resizeContents( 0, 0 );
+ return;
+ }
+
+ // show pages containing hilighted text or bookmarked ones
+ //RESTORE THIS int flags = Settings::filterBookmarks() ? KPDFPage::Bookmark : KPDFPage::Highlight;
+
+ // if no page matches filter rule, then display all pages
+ QValueVector< KPDFPage * >::const_iterator pIt = pages.begin(), pEnd = pages.end();
+ bool skipCheck = true;
+ for ( ; pIt != pEnd ; ++pIt )
+ //if ( (*pIt)->attributes() & flags )
+ if ( (*pIt)->hasHighlights( SW_SEARCH_ID ) )
+ skipCheck = false;
+
+ // generate Thumbnails for the given set of pages
+ int width = clipper()->width(),
+ totalHeight = 0;
+ for ( pIt = pages.begin(); pIt != pEnd ; ++pIt )
+ //if ( skipCheck || (*pIt)->attributes() & flags )
+ if ( skipCheck || (*pIt)->hasHighlights( SW_SEARCH_ID ) )
+ {
+ ThumbnailWidget * t = new ThumbnailWidget( viewport(), *pIt, this );
+ t->setFocusProxy( this );
+ // add to the scrollview
+ addChild( t, 0, totalHeight );
+ // add to the internal queue
+ m_thumbnails.push_back( t );
+ // update total height (asking widget its own height)
+ t->resizeFitWidth( width );
+ totalHeight += t->heightHint() + 4;
+ if ( (*pIt)->number() == prevPage )
+ {
+ m_selected = t;
+ m_selected->setSelected( true );
+ }
+ t->show();
+ }
+
+ // update scrollview's contents size (sets scrollbars limits)
+ resizeContents( width, totalHeight );
+
+ // request for thumbnail generation
+ delayedRequestVisiblePixmaps( 200 );
+}
+
+void ThumbnailList::notifyViewportChanged( bool /*smoothMove*/ )
+{
+ // skip notifies for the current page (already selected)
+ int newPage = m_document->viewport().pageNumber;
+ if ( m_selected && m_selected->pageNumber() == newPage )
+ return;
+
+ // deselect previous thumbnail
+ if ( m_selected )
+ m_selected->setSelected( false );
+ m_selected = 0;
+
+ // select the page with viewport and ensure it's centered in the view
+ m_vectorIndex = 0;
+ QValueVector<ThumbnailWidget *>::iterator tIt = m_thumbnails.begin(), tEnd = m_thumbnails.end();
+ for ( ; tIt != tEnd; ++tIt )
+ {
+ if ( (*tIt)->pageNumber() == newPage )
+ {
+ m_selected = *tIt;
+ m_selected->setSelected( true );
+ if ( KpdfSettings::syncThumbnailsViewport() )
+ {
+ int yOffset = QMAX( visibleHeight() / 4, m_selected->height() / 2 );
+ ensureVisible( 0, childY( m_selected ) + m_selected->height()/2, 0, yOffset );
+ }
+ break;
+ }
+ m_vectorIndex++;
+ }
+}
+
+void ThumbnailList::notifyPageChanged( int pageNumber, int /*changedFlags*/ )
+{
+ // only handle pixmap changed notifies (the only defined for now)
+ //if ( !(changedFlags & DocumentObserver::Pixmap) )
+ // return;
+
+ // iterate over visible items: if page(pageNumber) is one of them, repaint it
+ QValueList<ThumbnailWidget *>::iterator vIt = m_visibleThumbnails.begin(), vEnd = m_visibleThumbnails.end();
+ for ( ; vIt != vEnd; ++vIt )
+ if ( (*vIt)->pageNumber() == pageNumber )
+ {
+ (*vIt)->update();
+ break;
+ }
+}
+
+void ThumbnailList::notifyContentsCleared( int changedFlags )
+{
+ // if pixmaps were cleared, re-ask them
+ if ( changedFlags & DocumentObserver::Pixmap )
+ slotRequestVisiblePixmaps();
+}
+
+bool ThumbnailList::canUnloadPixmap( int pageNumber )
+{
+ // if the thubnail 'pageNumber' is one of the visible ones, forbid unloading
+ QValueList<ThumbnailWidget *>::iterator vIt = m_visibleThumbnails.begin(), vEnd = m_visibleThumbnails.end();
+ for ( ; vIt != vEnd; ++vIt )
+ if ( (*vIt)->pageNumber() == pageNumber )
+ return false;
+ // if hidden permit unloading
+ return true;
+}
+//END DocumentObserver inherited methods
+
+
+void ThumbnailList::updateWidgets()
+{
+ // find all widgets that intersects the viewport and update them
+ QRect viewportRect( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
+ QValueList<ThumbnailWidget *>::iterator vIt = m_visibleThumbnails.begin(), vEnd = m_visibleThumbnails.end();
+ for ( ; vIt != vEnd; ++vIt )
+ {
+ ThumbnailWidget * t = *vIt;
+ QRect widgetRect( childX( t ), childY( t ), t->width(), t->height() );
+ // update only the exposed area of the widget (saves pixels..)
+ QRect relativeRect = viewportRect.intersect( widgetRect );
+ if ( !relativeRect.isValid() )
+ continue;
+ relativeRect.moveBy( -widgetRect.left(), -widgetRect.top() );
+ t->update( relativeRect );
+ }
+}
+
+void ThumbnailList::forwardRightClick( const KPDFPage * p, const QPoint & t )
+{
+ emit rightClick( p, t );
+}
+
+const QPixmap * ThumbnailList::getBookmarkOverlay() const
+{
+ return m_bookmarkOverlay;
+}
+
+void ThumbnailList::slotFilterBookmarks( bool filterOn )
+{
+ // save state
+ KpdfSettings::setFilterBookmarks( filterOn );
+ KpdfSettings::writeConfig();
+ // ask for the 'notifySetup' with a little trick (on reinsertion the
+ // document sends the list again)
+ m_document->removeObserver( this );
+ m_document->addObserver( this );
+}
+
+
+//BEGIN widget events
+void ThumbnailList::keyPressEvent( QKeyEvent * keyEvent )
+{
+ if ( m_thumbnails.count() < 1 )
+ return keyEvent->ignore();
+
+ int nextPage = -1;
+ if ( keyEvent->key() == Key_Up )
+ {
+ if ( !m_selected )
+ nextPage = 0;
+ else if ( m_vectorIndex > 0 )
+ nextPage = m_thumbnails[ m_vectorIndex - 1 ]->pageNumber();
+ }
+ else if ( keyEvent->key() == Key_Down )
+ {
+ if ( !m_selected )
+ nextPage = 0;
+ else if ( m_vectorIndex < (int)m_thumbnails.count() - 1 )
+ nextPage = m_thumbnails[ m_vectorIndex + 1 ]->pageNumber();
+ }
+ else if ( keyEvent->key() == Key_PageUp )
+ verticalScrollBar()->subtractPage();
+ else if ( keyEvent->key() == Key_PageDown )
+ verticalScrollBar()->addPage();
+ else if ( keyEvent->key() == Key_Home )
+ nextPage = m_thumbnails[ 0 ]->pageNumber();
+ else if ( keyEvent->key() == Key_End )
+ nextPage = m_thumbnails[ m_thumbnails.count() - 1 ]->pageNumber();
+
+ if ( nextPage == -1 )
+ return keyEvent->ignore();
+
+ keyEvent->accept();
+ if ( m_selected )
+ m_selected->setSelected( false );
+ m_selected = 0;
+ m_document->setViewportPage( nextPage );
+}
+
+void ThumbnailList::contentsMousePressEvent( QMouseEvent * e )
+{
+ if ( e->button() != Qt::LeftButton )
+ return;
+ int clickY = e->y();
+ QValueList<ThumbnailWidget *>::iterator vIt = m_visibleThumbnails.begin(), vEnd = m_visibleThumbnails.end();
+ for ( ; vIt != vEnd; ++vIt )
+ {
+ ThumbnailWidget * t = *vIt;
+ int childTop = childY(t);
+ if ( clickY > childTop && clickY < (childTop + t->height()) )
+ {
+ if ( m_document->viewport().pageNumber != t->pageNumber() )
+ m_document->setViewportPage( t->pageNumber() );
+ break;
+ }
+ }
+}
+
+void ThumbnailList::viewportResizeEvent( QResizeEvent * e )
+{
+ if ( m_thumbnails.count() < 1 || width() < 1 )
+ return;
+
+ // if width changed resize all the Thumbnails, reposition them to the
+ // right place and recalculate the contents area
+ if ( e->size().width() != e->oldSize().width() )
+ {
+ // runs the timer avoiding a thumbnail regeneration by 'contentsMoving'
+ delayedRequestVisiblePixmaps( 2000 );
+
+ // resize and reposition items
+ int totalHeight = 0,
+ newWidth = e->size().width();
+ QValueVector<ThumbnailWidget *>::iterator tIt = m_thumbnails.begin(), tEnd = m_thumbnails.end();
+ for ( ; tIt != tEnd; ++tIt )
+ {
+ ThumbnailWidget *t = *tIt;
+ moveChild( t, 0, totalHeight );
+ t->resizeFitWidth( newWidth );
+ totalHeight += t->heightHint() + 4;
+ }
+
+ // update scrollview's contents size (sets scrollbars limits)
+ resizeContents( newWidth, totalHeight );
+
+ // ensure selected item remains visible
+ if ( m_selected )
+ ensureVisible( 0, childY( m_selected ) + m_selected->height()/2, 0, visibleHeight()/2 );
+ }
+ else if ( e->size().height() <= e->oldSize().height() )
+ return;
+
+ // invalidate the bookmark overlay
+ if ( m_bookmarkOverlay )
+ {
+ delete m_bookmarkOverlay;
+ m_bookmarkOverlay = 0;
+ }
+
+ // update Thumbnails since width has changed or height has increased
+ delayedRequestVisiblePixmaps( 500 );
+}
+
+void ThumbnailList::dragEnterEvent( QDragEnterEvent * ev )
+{
+ ev->accept();
+}
+
+void ThumbnailList::dropEvent( QDropEvent * ev )
+{
+ KURL::List lst;
+ if ( KURLDrag::decode( ev, lst ) )
+ emit urlDropped( lst.first() );
+}
+//END widget events
+
+//BEGIN internal SLOTS
+void ThumbnailList::slotRequestVisiblePixmaps( int /*newContentsX*/, int newContentsY )
+{
+ // if an update is already scheduled or the widget is hidden, don't proceed
+ if ( (m_delayTimer && m_delayTimer->isActive()) || !isShown() )
+ return;
+
+ int vHeight = visibleHeight(),
+ vOffset = newContentsY == -1 ? contentsY() : newContentsY;
+
+ // scroll from the top to the last visible thumbnail
+ m_visibleThumbnails.clear();
+ QValueList< PixmapRequest * > requestedPixmaps;
+ QValueVector<ThumbnailWidget *>::iterator tIt = m_thumbnails.begin(), tEnd = m_thumbnails.end();
+ for ( ; tIt != tEnd; ++tIt )
+ {
+ ThumbnailWidget * t = *tIt;
+ int top = childY( t ) - vOffset;
+ if ( top > vHeight )
+ break;
+ if ( top + t->height() < 0 )
+ continue;
+ // add ThumbnailWidget to visible list
+ m_visibleThumbnails.push_back( t );
+ // if pixmap not present add it to requests
+ if ( !t->page()->hasPixmap( THUMBNAILS_ID, t->pixmapWidth(), t->pixmapHeight() ) )
+ {
+ PixmapRequest * p = new PixmapRequest(
+ THUMBNAILS_ID, t->pageNumber(), t->pixmapWidth(), t->pixmapHeight(), THUMBNAILS_PRIO, true );
+ requestedPixmaps.push_back( p );
+ }
+ }
+
+ // actually request pixmaps
+ if ( !requestedPixmaps.isEmpty() )
+ m_document->requestPixmaps( requestedPixmaps );
+}
+
+void ThumbnailList::slotDelayTimeout()
+{
+ // resize the bookmark overlay
+ delete m_bookmarkOverlay;
+ int expectedWidth = contentsWidth() / 4;
+ if ( expectedWidth > 10 )
+ m_bookmarkOverlay = new QPixmap( DesktopIcon( "attach", expectedWidth ) );
+ else
+ m_bookmarkOverlay = 0;
+
+ // request pixmaps
+ slotRequestVisiblePixmaps();
+}
+//END internal SLOTS
+
+void ThumbnailList::delayedRequestVisiblePixmaps( int delayMs )
+{
+ if ( !m_delayTimer )
+ {
+ m_delayTimer = new QTimer( this );
+ connect( m_delayTimer, SIGNAL( timeout() ), this, SLOT( slotDelayTimeout() ) );
+ }
+ m_delayTimer->start( delayMs, true );
+}
+
+
+/** ThumbnailWidget implementation **/
+
+ThumbnailWidget::ThumbnailWidget( QWidget * parent, const KPDFPage * kp, ThumbnailList * tl )
+ : QWidget( parent, 0, WNoAutoErase ), m_tl( tl ), m_page( kp ),
+ m_selected( false ), m_pixmapWidth( 10 ), m_pixmapHeight( 10 )
+{
+ m_labelNumber = m_page->number() + 1;
+ m_labelHeight = QFontMetrics( font() ).height();
+}
+
+void ThumbnailWidget::resizeFitWidth( int width )
+{
+ m_pixmapWidth = width - m_margin;
+ m_pixmapHeight = (int)(m_page->ratio() * m_pixmapWidth);
+ resize( width, heightHint() );
+}
+
+void ThumbnailWidget::setSelected( bool selected )
+{
+ // update selected state
+ if ( m_selected != selected )
+ {
+ m_selected = selected;
+ update( 0, 0, width(), height() );
+ }
+}
+
+void ThumbnailWidget::mouseReleaseEvent( QMouseEvent * e )
+{
+ if ( e->button() != Qt::RightButton )
+ return;
+
+ m_tl->forwardRightClick( m_page, e->globalPos() );
+}
+
+void ThumbnailWidget::paintEvent( QPaintEvent * e )
+{
+ int width = m_pixmapWidth + m_margin;
+ int height = m_pixmapHeight + m_margin + m_labelHeight;
+ QRect clipRect = e->rect();
+ if ( !clipRect.isValid() )
+ return;
+ QPainter p( this );
+
+ // draw the bottom label + highlight mark
+ QColor fillColor = m_selected ? palette().active().highlight() : palette().active().base();
+ p.fillRect( 0, 0, width, height, fillColor );
+ p.setPen( m_selected ? palette().active().highlightedText() : palette().active().text() );
+ p.drawText( 0, m_pixmapHeight + m_margin, width, m_labelHeight, Qt::AlignCenter, QString::number( m_labelNumber ) );
+
+ // draw page outline and pixmap
+ if ( clipRect.top() < m_pixmapHeight + m_margin )
+ {
+ // if page is bookmarked draw a colored border
+ bool isBookmarked = m_page->hasBookmark();
+ // draw the inner rect
+ p.setPen( isBookmarked ? QColor( 0xFF8000 ) : Qt::black );
+ p.drawRect( m_margin/2 - 1, m_margin/2 - 1, m_pixmapWidth + 2, m_pixmapHeight + 2 );
+ // draw the clear rect
+ p.setPen( isBookmarked ? QColor( 0x804000 ) : palette().active().base() );
+ // draw the bottom and right shadow edges
+ if ( !isBookmarked )
+ {
+ int left, right, bottom, top;
+ left = m_margin/2 + 1;
+ right = m_margin/2 + m_pixmapWidth + 1;
+ bottom = m_pixmapHeight + m_margin/2 + 1;
+ top = m_margin/2 + 1;
+ p.setPen( Qt::gray );
+ p.drawLine( left, bottom, right, bottom );
+ p.drawLine( right, top, right, bottom );
+ }
+
+ // draw the page using the shared PagePainter class
+ p.translate( m_margin/2, m_margin/2 );
+ clipRect.moveBy( -m_margin/2, -m_margin/2 );
+ clipRect = clipRect.intersect( QRect( 0, 0, m_pixmapWidth, m_pixmapHeight ) );
+ if ( clipRect.isValid() )
+ {
+ int flags = PagePainter::Accessibility | PagePainter::Highlights;
+ PagePainter::paintPageOnPainter( m_page, THUMBNAILS_ID, flags, &p,
+ clipRect, m_pixmapWidth, m_pixmapHeight );
+ }
+
+ // draw the bookmark overlay on the top-right corner
+ const QPixmap * bookmarkPixmap = m_tl->getBookmarkOverlay();
+ if ( isBookmarked && bookmarkPixmap )
+ {
+ int pixW = bookmarkPixmap->width(),
+ pixH = bookmarkPixmap->height();
+ clipRect = clipRect.intersect( QRect( m_pixmapWidth - pixW, 0, pixW, pixH ) );
+ if ( clipRect.isValid() )
+ p.drawPixmap( m_pixmapWidth - pixW, -pixH/8, *bookmarkPixmap );
+ }
+ }
+}
+
+
+/** ThumbnailsController implementation **/
+
+#define FILTERB_ID 1
+
+ThumbnailController::ThumbnailController( QWidget * parent, ThumbnailList * list )
+ : KToolBar( parent, "ThumbsControlBar" )
+{
+ // change toolbar appearance
+ setMargin( 3 );
+ setFlat( true );
+ setIconSize( 16 );
+ setMovingEnabled( false );
+
+ // insert a togglebutton [show only bookmarked pages]
+ //insertSeparator();
+ insertButton( "bookmark", FILTERB_ID, SIGNAL( toggled( bool ) ),
+ list, SLOT( slotFilterBookmarks( bool ) ),
+ true, i18n( "Show bookmarked pages only" ) );
+ setToggle( FILTERB_ID );
+ setButton( FILTERB_ID, KpdfSettings::filterBookmarks() );
+ //insertLineSeparator();
+}
+
+
+#include "thumbnaillist.moc"
diff --git a/kpdf/ui/thumbnaillist.h b/kpdf/ui/thumbnaillist.h
new file mode 100644
index 00000000..e0f84610
--- /dev/null
+++ b/kpdf/ui/thumbnaillist.h
@@ -0,0 +1,121 @@
+/***************************************************************************
+ * Copyright (C) 2004 by Albert Astals Cid <tsdgeos@terra.es> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef _KPDF_THUMBNAILLIST_H_
+#define _KPDF_THUMBNAILLIST_H_
+
+#include <qscrollview.h>
+#include <qvaluevector.h>
+#include <qvbox.h>
+#include <ktoolbar.h>
+#include "core/observer.h"
+
+class QTimer;
+class KActionCollection;
+
+class KPDFDocument;
+class ThumbnailWidget;
+
+/**
+ * @short A scrollview that displays pages pixmaps previews (aka thumbnails).
+ *
+ * ...
+ */
+class ThumbnailList : public QScrollView, public DocumentObserver
+{
+Q_OBJECT
+ public:
+ ThumbnailList(QWidget *parent, KPDFDocument *document);
+ ~ThumbnailList();
+
+ // inherited: return thumbnails observer id
+ uint observerId() const { return THUMBNAILS_ID; }
+ // inherited: create thumbnails ( inherited as a DocumentObserver )
+ void notifySetup( const QValueVector< KPDFPage * > & pages, bool documentChanged );
+ // inherited: hilihght current thumbnail ( inherited as DocumentObserver )
+ void notifyViewportChanged( bool smoothMove );
+ // inherited: redraw thumbnail ( inherited as DocumentObserver )
+ void notifyPageChanged( int pageNumber, int changedFlags );
+ // inherited: request all visible pixmap (due to a global shange or so..)
+ void notifyContentsCleared( int changedFlags );
+ // inherited: tell if pixmap is hidden and can be unloaded
+ bool canUnloadPixmap( int pageNumber );
+
+ // redraw visible widgets (useful for refreshing contents...)
+ void updateWidgets();
+
+ // called by ThumbnailWidgets to send (forward) rightClick signals
+ void forwardRightClick( const KPDFPage *, const QPoint & );
+ // called by ThumbnailWidgets to get the overlay bookmark pixmap
+ const QPixmap * getBookmarkOverlay() const;
+
+ public slots:
+ // these are connected to ThumbnailController buttons
+ void slotFilterBookmarks( bool filterOn );
+
+ protected:
+ // scroll up/down the view
+ void keyPressEvent( QKeyEvent * e );
+
+ // select a thumbnail by clicking on it
+ void contentsMousePressEvent( QMouseEvent * );
+
+ // resize thumbnails to fit the width
+ void viewportResizeEvent( QResizeEvent * );
+
+ // file drop related events (an url may be dropped even here)
+ void dragEnterEvent( QDragEnterEvent* );
+ void dropEvent( QDropEvent* );
+
+ signals:
+ void urlDropped( const KURL& );
+ void rightClick( const KPDFPage *, const QPoint & );
+
+ private:
+ void delayedRequestVisiblePixmaps( int delayMs = 0 );
+ KPDFDocument *m_document;
+ ThumbnailWidget *m_selected;
+ QTimer *m_delayTimer;
+ QPixmap *m_bookmarkOverlay;
+ QValueVector<ThumbnailWidget *> m_thumbnails;
+ QValueList<ThumbnailWidget *> m_visibleThumbnails;
+ int m_vectorIndex;
+
+ private slots:
+ // make requests for generating pixmaps for visible thumbnails
+ void slotRequestVisiblePixmaps( int newContentsX = -1, int newContentsY = -1 );
+ // delay timeout: resize overlays and requests pixmaps
+ void slotDelayTimeout();
+};
+
+/**
+ * @short A vertical boxed container with zero size hint (for insertion on left toolbox)
+ */
+class ThumbnailsBox : public QVBox
+{
+ public:
+ ThumbnailsBox( QWidget * parent ) : QVBox( parent ) {};
+ QSize sizeHint() const { return QSize(); }
+};
+
+/**
+ * @short A toolbar thar set ThumbnailList properties when clicking on items
+ *
+ * This class is the small tolbar that resides in the bottom of the
+ * ThumbnailsBox container (below ThumbnailList and the SearchLine) and
+ * emits signals whenever a button is pressed. A click action results
+ * in invoking some method (or slot) in ThumbnailList.
+ */
+class ThumbnailController : public KToolBar
+{
+ public:
+ ThumbnailController( QWidget * parent, ThumbnailList * thumbnailList );
+};
+
+#endif
diff --git a/kpdf/ui/toc.cpp b/kpdf/ui/toc.cpp
new file mode 100644
index 00000000..6db19933
--- /dev/null
+++ b/kpdf/ui/toc.cpp
@@ -0,0 +1,175 @@
+/***************************************************************************
+ * Copyright (C) 2004-2006 by Albert Astals Cid <tsdgeos@terra.es> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+// qt/kde includes
+#include <qheader.h>
+#include <qvariant.h>
+#include <klocale.h>
+
+// local includes
+#include "toc.h"
+#include "core/link.h"
+#include "core/page.h"
+
+// uncomment following to enable a 2nd column showing the page referred
+// by each tree entry note: PDF uses often references to viewports and
+// they're slow when converted to page number. drop the 2nd column idea.
+//#define TOC_ENABLE_PAGE_COLUMN
+
+class TOCItem : public KListViewItem
+{
+ public:
+ TOCItem( KListView *parent, TOCItem *after, const QDomElement & e )
+ : KListViewItem( parent, after, e.tagName() ), m_element( e )
+ {
+#ifdef TOC_ENABLE_PAGE_COLUMN
+ if ( e.hasAttribute( "Page" ) )
+ setText( 1, e.attribute( "Page" ) );
+#endif
+ setMultiLinesEnabled(true);
+ }
+
+ TOCItem( KListViewItem *parent, TOCItem *after, const QDomElement & e )
+ : KListViewItem( parent, after, e.tagName() ), m_element( e )
+ {
+#ifdef TOC_ENABLE_PAGE_COLUMN
+ if ( e.hasAttribute( "Page" ) )
+ setText( 1, e.attribute( "Page" ) );
+#endif
+ setMultiLinesEnabled(true);
+ }
+
+ const QDomElement & element() const
+ {
+ return m_element;
+ }
+
+ private:
+ QDomElement m_element;
+};
+
+TOC::TOC(QWidget *parent, KPDFDocument *document) : KListView(parent), m_document(document)
+{
+ addColumn( i18n("Topic") );
+#ifdef TOC_ENABLE_PAGE_COLUMN
+ addColumn( i18n("Page") );
+#else
+ header() -> hide();
+#endif
+ setSorting(-1);
+ setRootIsDecorated(true);
+ // the next line causes bug:147233
+// setResizeMode(AllColumns);
+ setAllColumnsShowFocus(true);
+ connect(this, SIGNAL(clicked(QListViewItem *)), this, SLOT(slotExecuted(QListViewItem *)));
+ connect(this, SIGNAL(returnPressed(QListViewItem *)), this, SLOT(slotExecuted(QListViewItem *)));
+}
+
+TOC::~TOC()
+{
+ m_document->removeObserver( this );
+}
+
+uint TOC::observerId() const
+{
+ return TOC_ID;
+}
+
+void TOC::notifySetup( const QValueVector< KPDFPage * > & /*pages*/, bool documentChanged )
+{
+ if ( !documentChanged )
+ return;
+
+ // clear contents
+ clear();
+
+ // request synopsis description (is a dom tree)
+ const DocumentSynopsis * syn = m_document->documentSynopsis();
+
+ // if not present, disable the contents tab
+ if ( !syn )
+ {
+ emit hasTOC( false );
+ return;
+ }
+
+ // else populate the listview and enable the tab
+ addChildren( *syn );
+ emit hasTOC( true );
+}
+
+void TOC::addChildren( const QDomNode & parentNode, KListViewItem * parentItem )
+{
+ // keep track of the current listViewItem
+ TOCItem * currentItem = 0;
+ QDomNode n = parentNode.firstChild();
+ while( !n.isNull() )
+ {
+ // convert the node to an element (sure it is)
+ QDomElement e = n.toElement();
+
+ // insert the entry as top level (listview parented) or 2nd+ level
+ if ( !parentItem )
+ currentItem = new TOCItem( this, currentItem, e );
+ else
+ currentItem = new TOCItem( parentItem, currentItem, e );
+
+ // descend recursively and advance to the next node
+ if ( e.hasChildNodes() )
+ addChildren( n, currentItem );
+
+ // open/keep close the item
+ bool isOpen = false;
+ if ( e.hasAttribute( "Open" ) )
+ isOpen = QVariant( e.attribute( "Open" ) ).toBool();
+ currentItem->setOpen( isOpen );
+
+ n = n.nextSibling();
+ }
+}
+
+void TOC::slotExecuted( QListViewItem *i )
+{
+ TOCItem* tocItem = dynamic_cast<TOCItem*>( i );
+ // that filters clicks on [+] that for a strange reason don't seem to be TOCItem*
+ if (tocItem == NULL)
+ return;
+ const QDomElement & e = tocItem->element();
+
+ QString externalFileName = e.attribute( "ExternalFileName" );
+ if ( !externalFileName.isEmpty() )
+ {
+ KPDFLinkGoto link( externalFileName, getViewport( e ) );
+ m_document->processLink( &link );
+ }
+ else
+ {
+ m_document->setViewport( getViewport( e ), TOC_ID );
+ }
+}
+
+DocumentViewport TOC::getViewport( const QDomElement &e ) const
+{
+ if ( e.hasAttribute( "Viewport" ) )
+ {
+ // if the node has a viewport, set it
+ return DocumentViewport( e.attribute( "Viewport" ) );
+ }
+ else if ( e.hasAttribute( "ViewportName" ) )
+ {
+ // if the node references a viewport, get the reference and set it
+ const QString & page = e.attribute( "ViewportName" );
+ const QString & viewport = m_document->getMetaData( "NamedViewport", page );
+ if ( !viewport.isNull() )
+ return DocumentViewport( viewport );
+ }
+ return DocumentViewport();
+}
+
+#include "toc.moc"
diff --git a/kpdf/ui/toc.h b/kpdf/ui/toc.h
new file mode 100644
index 00000000..eaa398a5
--- /dev/null
+++ b/kpdf/ui/toc.h
@@ -0,0 +1,43 @@
+/***************************************************************************
+ * Copyright (C) 2004-2006 by Albert Astals Cid <tsdgeos@terra.es> *
+ * *
+ * 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. *
+ ***************************************************************************/
+
+#ifndef _KPDF_TOC_H_
+#define _KPDF_TOC_H_
+
+#include <qdom.h>
+#include <klistview.h>
+#include "core/document.h"
+#include "core/observer.h"
+
+class KPDFDocument;
+
+class TOC : public KListView, public DocumentObserver
+{
+Q_OBJECT
+ public:
+ TOC(QWidget *parent, KPDFDocument *document);
+ ~TOC();
+
+ // inherited from DocumentObserver
+ uint observerId() const;
+ void notifySetup( const QValueVector< KPDFPage * > & pages, bool documentChanged );
+
+ signals:
+ void hasTOC(bool has);
+
+ private slots:
+ void slotExecuted(QListViewItem *i);
+
+ private:
+ void addChildren( const QDomNode & parentNode, KListViewItem * parentItem = 0 );
+ DocumentViewport getViewport( const QDomElement &e ) const;
+ KPDFDocument *m_document;
+};
+
+#endif
diff --git a/kpdf/xpdf/Makefile.am b/kpdf/xpdf/Makefile.am
new file mode 100644
index 00000000..0474692c
--- /dev/null
+++ b/kpdf/xpdf/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = fofi goo splash xpdf
diff --git a/kpdf/xpdf/README.xpdf b/kpdf/xpdf/README.xpdf
new file mode 100644
index 00000000..71fd62e3
--- /dev/null
+++ b/kpdf/xpdf/README.xpdf
@@ -0,0 +1,405 @@
+Xpdf
+====
+
+version 3.02
+2007-feb-27
+
+The Xpdf software and documentation are
+copyright 1996-2007 Glyph & Cog, LLC.
+
+Email: derekn@foolabs.com
+WWW: http://www.foolabs.com/xpdf/
+
+The PDF data structures, operators, and specification are
+copyright 1985-2006 Adobe Systems Inc.
+
+
+What is Xpdf?
+-------------
+
+Xpdf is an open source viewer for Portable Document Format (PDF)
+files. (These are also sometimes also called 'Acrobat' files, from
+the name of Adobe's PDF software.) The Xpdf project also includes a
+PDF text extractor, PDF-to-PostScript converter, and various other
+utilities.
+
+Xpdf runs under the X Window System on UNIX, VMS, and OS/2. The non-X
+components (pdftops, pdftotext, etc.) also run on Win32 systems and
+should run on pretty much any system with a decent C++ compiler.
+
+Xpdf is designed to be small and efficient. It can use Type 1 or
+TrueType fonts.
+
+
+Distribution
+------------
+
+Xpdf is licensed under the GNU General Public License (GPL), version
+2. In my opinion, the GPL is a convoluted, confusing, ambiguous mess.
+But it's also pervasive, and I'm sick of arguing. And even if it is
+confusing, the basic idea is good.
+
+In order to cut down on the confusion a little bit, here are some
+informal clarifications:
+
+- I don't mind if you redistribute Xpdf in source and/or binary form,
+ as long as you include all of the documentation: README, man pages
+ (or help files), and COPYING. (Note that the README file contains a
+ pointer to a web page with the source code.)
+
+- Selling a CD-ROM that contains Xpdf is fine with me, as long as it
+ includes the documentation. I wouldn't mind receiving a sample
+ copy, but it's not necessary.
+
+- If you make useful changes to Xpdf, please make the source code
+ available -- post it on a web site, email it to me, whatever.
+
+If you're interested in commercial licensing, please see the Glyph &
+Cog web site:
+
+ http://www.glyphandcog.com/
+
+
+Compatibility
+-------------
+
+Xpdf is developed and tested on a Linux 2.4 x86 system.
+
+In addition, it has been compiled by others on Solaris, AIX, HP-UX,
+Digital Unix, Irix, and numerous other Unix implementations, as well
+as VMS and OS/2. It should work on pretty much any system which runs
+X11 and has Unix-like libraries. You'll need ANSI C++ and C compilers
+to compile it.
+
+The non-X components of Xpdf (pdftops, pdftotext, pdfinfo, pdffonts,
+pdftoppm, and pdfimages) can also be compiled on Win32 systems. See
+the Xpdf web page for details.
+
+If you compile Xpdf for a system not listed on the web page, please
+let me know. If you're willing to make your binary available by ftp
+or on the web, I'll be happy to add a link from the Xpdf web page. I
+have decided not to host any binaries I didn't compile myself (for
+disk space and support reasons).
+
+If you can't get Xpdf to compile on your system, send me email and
+I'll try to help.
+
+Xpdf has been ported to the Acorn, Amiga, BeOS, and EPOC. See the
+Xpdf web page for links.
+
+
+Getting Xpdf
+------------
+
+The latest version is available from:
+
+ http://www.foolabs.com/xpdf/
+
+or:
+
+ ftp://ftp.foolabs.com/pub/xpdf/
+
+Source code and several precompiled executables are available.
+
+Announcements of new versions are posted to several newsgroups
+(comp.text.pdf, comp.os.linux.announce, and others) and emailed to a
+list of people. If you'd like to receive email notification of new
+versions, just let me know.
+
+
+Running Xpdf
+------------
+
+To run xpdf, simply type:
+
+ xpdf file.pdf
+
+To generate a PostScript file, hit the "print" button in xpdf, or run
+pdftops:
+
+ pdftops file.pdf
+
+To generate a plain text file, run pdftotext:
+
+ pdftotext file.pdf
+
+There are four additional utilities (which are fully described in
+their man pages):
+
+ pdfinfo -- dumps a PDF file's Info dictionary (plus some other
+ useful information)
+ pdffonts -- lists the fonts used in a PDF file along with various
+ information for each font
+ pdftoppm -- converts a PDF file to a series of PPM/PGM/PBM-format
+ bitmaps
+ pdfimages -- extracts the images from a PDF file
+
+Command line options and many other details are described in the man
+pages (xpdf.1, etc.) and the VMS help files (xpdf.hlp, etc.).
+
+
+Upgrading from Xpdf 2.xx
+------------------------
+
+WARNING: Xpdf 3.00 switched to a new PDF rasterizer, which no longer
+uses X fonts. You'll need a set of Base-14 fonts -- the URW fonts
+distributed with ghostscript can be used for this. Xpdf will search
+for the URW fonts, but if you have them installed in a non-standard
+directory, you'll need to set up an xpdfrc config file to point to
+them. For full details, please see the xpdfrc(5) man page.
+
+
+Compiling Xpdf
+--------------
+
+See the separate file, INSTALL.
+
+
+Bugs
+----
+
+If you find a bug in Xpdf, i.e., if it prints an error message,
+crashes, or incorrectly displays a document, and you don't see that
+bug listed here, please send me email, with a pointer (URL, ftp site,
+etc.) to the PDF file.
+
+
+Acknowledgments
+---------------
+
+Thanks to:
+
+* Patrick Voigt for help with the remote server code.
+* Patrick Moreau, Martin P.J. Zinser, and David Mathog for the VMS
+ port.
+* David Boldt and Rick Rodgers for sample man pages.
+* Brendan Miller for the icon idea.
+* Olly Betts for help testing pdftotext.
+* Peter Ganten for the OS/2 port.
+* Michael Richmond for the Win32 port of pdftops and pdftotext and the
+ xpdf/cygwin/XFree86 build instructions.
+* Frank M. Siegert for improvements in the PostScript code.
+* Leo Smiers for the decryption patches.
+* Rainer Menzner for creating t1lib, and for helping me adapt it to
+ xpdf.
+* Pine Tree Systems A/S for funding the OPI and EPS support in
+ pdftops.
+* Easy Software Products for funding several improvements to the
+ PostScript output code.
+* Tom Kacvinsky for help with FreeType and for being my interface to
+ the FreeType team.
+* Theppitak Karoonboonyanan for help with Thai support.
+* Leonard Rosenthol for help and contributions on a bunch of things.
+* Alexandros Diamantidis and Maria Adaloglou for help with Greek
+ support.
+* Lawrence Lai for help with the CJK Unicode maps.
+
+Various people have contributed modifications made for use by the
+pdftex project:
+
+* Han The Thanh
+* Martin Schrder of ArtCom GmbH
+
+
+References
+----------
+
+Adobe Systems Inc., _PDF Reference, sixth edition: Adobe Portable
+Document Format version 1.7_.
+http://www.adobe.com/devnet/pdf/pdf_reference.html
+[The manual for PDF version 1.7.]
+
+Adobe Systems Inc., "Errata for the PDF Reference, sixth edition,
+version 1.7", October 16, 2006.
+http://www.adobe.com/devnet/pdf/pdf_reference.html
+[The errata for the PDF 1.7 spec.]
+
+Adobe Systems Inc., _PostScript Language Reference_, 3rd ed.
+Addison-Wesley, 1999, ISBN 0-201-37922-8.
+[The official PostScript manual.]
+
+Adobe Systems, Inc., _The Type 42 Font Format Specification_,
+Adobe Developer Support Technical Specification #5012. 1998.
+http://partners.adobe.com/asn/developer/pdfs/tn/5012.Type42_Spec.pdf
+[Type 42 is the format used to embed TrueType fonts in PostScript
+files.]
+
+Adobe Systems, Inc., _Adobe CMap and CIDFont Files Specification_,
+Adobe Developer Support Technical Specification #5014. 1995.
+http://www.adobe.com/supportservice/devrelations/PDFS/TN/5014.CIDFont_Spec.pdf
+[CMap file format needed for Japanese and Chinese font support.]
+
+Adobe Systems, Inc., _Adobe-Japan1-4 Character Collection for
+CID-Keyed Fonts_, Adobe Developer Support Technical Note #5078.
+2000.
+http://partners.adobe.com/asn/developer/PDFS/TN/5078.CID_Glyph.pdf
+[The Adobe Japanese character set.]
+
+Adobe Systems, Inc., _Adobe-GB1-4 Character Collection for
+CID-Keyed Fonts_, Adobe Developer Support Technical Note #5079.
+2000.
+http://partners.adobe.com/asn/developer/pdfs/tn/5079.Adobe-GB1-4.pdf
+[The Adobe Chinese GB (simplified) character set.]
+
+Adobe Systems, Inc., _Adobe-CNS1-3 Character Collection for
+CID-Keyed Fonts_, Adobe Developer Support Technical Note #5080.
+2000.
+http://partners.adobe.com/asn/developer/PDFS/TN/5080.CNS_CharColl.pdf
+[The Adobe Chinese CNS (traditional) character set.]
+
+Adobe Systems Inc., _Supporting the DCT Filters in PostScript Level
+2_, Adobe Developer Support Technical Note #5116. 1992.
+http://www.adobe.com/supportservice/devrelations/PDFS/TN/5116.PS2_DCT.PDF
+[Description of the DCTDecode filter parameters.]
+
+Adobe Systems Inc., _Open Prepress Interface (OPI) Specification -
+Version 2.0_, Adobe Developer Support Technical Note #5660. 2000.
+http://partners.adobe.com/asn/developer/PDFS/TN/5660.OPI_2.0.pdf
+
+Adobe Systems Inc., CMap files.
+ftp://ftp.oreilly.com/pub/examples/nutshell/cjkv/adobe/
+[The actual CMap files for the 16-bit CJK encodings.]
+
+Adobe Systems Inc., Unicode glyph lists.
+http://partners.adobe.com/asn/developer/type/unicodegn.html
+http://partners.adobe.com/asn/developer/type/glyphlist.txt
+http://partners.adobe.com/asn/developer/type/corporateuse.txt
+http://partners.adobe.com/asn/developer/type/zapfdingbats.txt
+[Mappings between character names to Unicode.]
+
+Adobe Systems Inc., OpenType Specification v. 1.4.
+http://partners.adobe.com/public/developer/opentype/index_spec.html
+[The OpenType font format spec.]
+
+Aldus Corp., _OPI: Open Prepress Interface Specification 1.3_. 1993.
+http://partners.adobe.com/asn/developer/PDFS/TN/OPI_13.pdf
+
+Anonymous, RC4 source code.
+ftp://ftp.ox.ac.uk/pub/crypto/misc/rc4.tar.gz
+ftp://idea.sec.dsi.unimi.it/pub/crypt/code/rc4.tar.gz
+[This is the algorithm used to encrypt PDF files.]
+
+T. Boutell, et al., "PNG (Portable Network Graphics) Specification,
+Version 1.0". RFC 2083.
+[PDF uses the PNG filter algorithms.]
+
+CCITT, "Information Technology - Digital Compression and Coding of
+Continuous-tone Still Images - Requirements and Guidelines", CCITT
+Recommendation T.81.
+http://www.w3.org/Graphics/JPEG/
+[The official JPEG spec.]
+
+A. Chernov, "Registration of a Cyrillic Character Set". RFC 1489.
+[Documentation for the KOI8-R Cyrillic encoding.]
+
+Roman Czyborra, "The ISO 8859 Alphabet Soup".
+http://czyborra.com/charsets/iso8859.html
+[Documentation on the various ISO 859 encodings.]
+
+L. Peter Deutsch, "ZLIB Compressed Data Format Specification version
+3.3". RFC 1950.
+[Information on the general format used in FlateDecode streams.]
+
+L. Peter Deutsch, "DEFLATE Compressed Data Format Specification
+version 1.3". RFC 1951.
+[The definition of the compression algorithm used in FlateDecode
+streams.]
+
+Morris Dworkin, "Recommendation for Block Cipher Modes of Operation",
+National Institute of Standards, NIST Special Publication 800-38A,
+2001.
+[The cipher block chaining (CBC) mode used with AES in PDF files.]
+
+Federal Information Processing Standards Publication 197 (FIPS PUBS
+197), "Advanced Encryption Standard (AES)", November 26, 2001.
+[AES encryption, used in PDF 1.6.]
+
+Jim Flowers, "X Logical Font Description Conventions", Version 1.5, X
+Consortium Standard, X Version 11, Release 6.1.
+ftp://ftp.x.org/pub/R6.1/xc/doc/hardcopy/XLFD/xlfd.PS.Z
+[The official specification of X font descriptors, including font
+transformation matrices.]
+
+Foley, van Dam, Feiner, and Hughes, _Computer Graphics: Principles and
+Practice_, 2nd ed. Addison-Wesley, 1990, ISBN 0-201-12110-7.
+[Colorspace conversion functions, Bezier spline math.]
+
+Robert L. Hummel, _Programmer's Technical Reference: Data and Fax
+Communications_. Ziff-Davis Press, 1993, ISBN 1-56276-077-7.
+[CCITT Group 3 and 4 fax decoding.]
+
+ISO/IEC, _Information technology -- Lossy/lossless coding of bi-level
+images_. ISO/IEC 14492, First edition (2001-12-15).
+http://webstore.ansi.org/
+[The official JBIG2 standard. The final draft of this spec is
+available from http://www.jpeg.org/jbighomepage.html.]
+
+ISO/IEC, _Information technology -- JPEG 2000 image coding system --
+Part 1: Core coding system_. ISO/IEC 15444-1, First edition
+(2000-12-15).
+http://webstore.ansi.org/
+[The official JPEG 2000 standard. The final committee draft of this
+spec is available from http://www.jpeg.org/JPEG2000.html, but there
+were changes made to the bitstream format between that draft and the
+published spec.]
+
+ITU, "Standardization of Group 3 facsimile terminals for document
+transmission", ITU-T Recommendation T.4, 1999.
+ITU, "Facsimile coding schemes and coding control functions for Group 4
+facsimile apparatus", ITU-T Recommendation T.6, 1993.
+http://www.itu.int/
+[The official Group 3 and 4 fax standards - used by the CCITTFaxDecode
+stream, as well as the JBIG2Decode stream.]
+
+B. Kaliski, "PKCS #5: Password-Based Cryptography Specification,
+Version 2.0". RFC 2898.
+[Defines the padding scheme used with AES encryption in PDF files.]
+
+Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz, "Practical
+Fast 1-D DCT Algorithms with 11 Multiplications". IEEE Intl. Conf. on
+Acoustics, Speech & Signal Processing, 1989, 988-991.
+[The fast IDCT algorithm used in the DCTDecode filter.]
+
+Microsoft, _TrueType 1.0 Font Files_, rev. 1.66. 1995.
+http://www.microsoft.com/typography/tt/tt.htm
+[The TrueType font spec (in MS Word format, naturally).]
+
+V. Ostromoukhov, R.D. Hersch, "Stochastic Clustered-Dot Dithering",
+Conf. Color Imaging: Device-Independent Color, Color Hardcopy, and
+Graphic Arts IV, 1999, SPIE Vol. 3648, 496-505.
+http://diwww.epfl.ch/w3lsp/publications/colour/scd.html
+[The stochastic dithering algorithm used in Xpdf.]
+
+P. Peterlin, "ISO 8859-2 (Latin 2) Resources".
+http://sizif.mf.uni-lj.si/linux/cee/iso8859-2.html
+[This is a web page with all sorts of useful Latin-2 character set and
+font information.]
+
+Charles Poynton, "Color FAQ".
+http://www.inforamp.net/~poynton/ColorFAQ.html
+[The mapping from the CIE 1931 (XYZ) color space to RGB.]
+
+R. Rivest, "The MD5 Message-Digest Algorithm". RFC 1321.
+[MD5 is used in PDF document encryption.]
+
+Thai Industrial Standard, "Standard for Thai Character Codes for
+Computers", TIS-620-2533 (1990).
+http://www.nectec.or.th/it-standards/std620/std620.htm
+[The TIS-620 Thai encoding.]
+
+Unicode Consortium, "Unicode Home Page".
+http://www.unicode.org/
+[Online copy of the Unicode spec.]
+
+W3C Recommendation, "PNG (Portable Network Graphics) Specification
+Version 1.0".
+http://www.w3.org/Graphics/PNG/
+[Defines the PNG image predictor.]
+
+Gregory K. Wallace, "The JPEG Still Picture Compression Standard".
+ftp://ftp.uu.net/graphics/jpeg/wallace.ps.gz
+[Good description of the JPEG standard. Also published in CACM, April
+1991, and submitted to IEEE Transactions on Consumer Electronics.]
+
+F. Yergeau, "UTF-8, a transformation format of ISO 10646". RFC 2279.
+[A commonly used Unicode encoding.]
diff --git a/kpdf/xpdf/aconf.h b/kpdf/xpdf/aconf.h
new file mode 100644
index 00000000..43b28397
--- /dev/null
+++ b/kpdf/xpdf/aconf.h
@@ -0,0 +1,17 @@
+/* define it to 0, if you have it, config.h will have it defined to 1 and that will be used*/
+#define HAVE_FSEEK0 0
+
+#include <config.h>
+
+#define HAVE_T1LIB_H 0
+#define HAVE_FREETYPE_H HAVE_FREETYPE
+#define HAVE_FREETYPE_FREETYPE_H HAVE_FREETYPE
+#define OPI_SUPPORT 0
+#define TEXTOUT_WORD_LIST 0
+#define HAVE_MKSTEMPS 1 //libkdefakes provides it
+#define HAVE_SPLASH 1
+#define SPLASH_CMYK 1
+#define HAVE_XPDFCORE 0
+#define HAVE_WINPDFCORE 0
+#define USE_EXCEPTIONS 0
+#define USE_FIXEDPOINT 0
diff --git a/kpdf/xpdf/fofi/FoFiBase.cc b/kpdf/xpdf/fofi/FoFiBase.cc
new file mode 100644
index 00000000..28d0b8ca
--- /dev/null
+++ b/kpdf/xpdf/fofi/FoFiBase.cc
@@ -0,0 +1,156 @@
+//========================================================================
+//
+// FoFiBase.cc
+//
+// Copyright 1999-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include "gmem.h"
+#include "FoFiBase.h"
+
+//------------------------------------------------------------------------
+// FoFiBase
+//------------------------------------------------------------------------
+
+FoFiBase::FoFiBase(char *fileA, int lenA, GBool freeFileDataA) {
+ fileData = file = (Guchar *)fileA;
+ len = lenA;
+ freeFileData = freeFileDataA;
+}
+
+FoFiBase::~FoFiBase() {
+ if (freeFileData) {
+ gfree(fileData);
+ }
+}
+
+char *FoFiBase::readFile(char *fileName, int *fileLen) {
+ FILE *f;
+ char *buf;
+ int n;
+
+ if (!(f = fopen(fileName, "rb"))) {
+ return NULL;
+ }
+ fseek(f, 0, SEEK_END);
+ n = (int)ftell(f);
+ fseek(f, 0, SEEK_SET);
+ buf = (char *)gmalloc(n);
+ if ((int)fread(buf, 1, n, f) != n) {
+ gfree(buf);
+ fclose(f);
+ return NULL;
+ }
+ fclose(f);
+ *fileLen = n;
+ return buf;
+}
+
+int FoFiBase::getS8(int pos, GBool *ok) {
+ int x;
+
+ if (pos < 0 || pos >= len) {
+ *ok = gFalse;
+ return 0;
+ }
+ x = file[pos];
+ if (x & 0x80) {
+ x |= ~0xff;
+ }
+ return x;
+}
+
+int FoFiBase::getU8(int pos, GBool *ok) {
+ if (pos < 0 || pos >= len) {
+ *ok = gFalse;
+ return 0;
+ }
+ return file[pos];
+}
+
+int FoFiBase::getS16BE(int pos, GBool *ok) {
+ int x;
+
+ if (pos < 0 || pos+1 >= len) {
+ *ok = gFalse;
+ return 0;
+ }
+ x = file[pos];
+ x = (x << 8) + file[pos+1];
+ if (x & 0x8000) {
+ x |= ~0xffff;
+ }
+ return x;
+}
+
+int FoFiBase::getU16BE(int pos, GBool *ok) {
+ int x;
+
+ if (pos < 0 || pos+1 >= len) {
+ *ok = gFalse;
+ return 0;
+ }
+ x = file[pos];
+ x = (x << 8) + file[pos+1];
+ return x;
+}
+
+int FoFiBase::getS32BE(int pos, GBool *ok) {
+ int x;
+
+ if (pos < 0 || pos+3 >= len) {
+ *ok = gFalse;
+ return 0;
+ }
+ x = file[pos];
+ x = (x << 8) + file[pos+1];
+ x = (x << 8) + file[pos+2];
+ x = (x << 8) + file[pos+3];
+ if (x & 0x80000000) {
+ x |= ~0xffffffff;
+ }
+ return x;
+}
+
+Guint FoFiBase::getU32BE(int pos, GBool *ok) {
+ Guint x;
+
+ if (pos < 0 || pos+3 >= len) {
+ *ok = gFalse;
+ return 0;
+ }
+ x = file[pos];
+ x = (x << 8) + file[pos+1];
+ x = (x << 8) + file[pos+2];
+ x = (x << 8) + file[pos+3];
+ return x;
+}
+
+Guint FoFiBase::getUVarBE(int pos, int size, GBool *ok) {
+ Guint x;
+ int i;
+
+ if (pos < 0 || pos + size > len) {
+ *ok = gFalse;
+ return 0;
+ }
+ x = 0;
+ for (i = 0; i < size; ++i) {
+ x = (x << 8) + file[pos + i];
+ }
+ return x;
+}
+
+GBool FoFiBase::checkRegion(int pos, int size) {
+ return pos >= 0 &&
+ pos + size >= pos &&
+ pos + size <= len;
+}
diff --git a/kpdf/xpdf/fofi/FoFiBase.h b/kpdf/xpdf/fofi/FoFiBase.h
new file mode 100644
index 00000000..b78840b2
--- /dev/null
+++ b/kpdf/xpdf/fofi/FoFiBase.h
@@ -0,0 +1,57 @@
+//========================================================================
+//
+// FoFiBase.h
+//
+// Copyright 1999-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef FOFIBASE_H
+#define FOFIBASE_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+
+//------------------------------------------------------------------------
+
+typedef void (*FoFiOutputFunc)(void *stream, char *data, int len);
+
+//------------------------------------------------------------------------
+// FoFiBase
+//------------------------------------------------------------------------
+
+class FoFiBase {
+public:
+
+ virtual ~FoFiBase();
+
+protected:
+
+ FoFiBase(char *fileA, int lenA, GBool freeFileDataA);
+ static char *readFile(char *fileName, int *fileLen);
+
+ // S = signed / U = unsigned
+ // 8/16/32/Var = word length, in bytes
+ // BE = big endian
+ int getS8(int pos, GBool *ok);
+ int getU8(int pos, GBool *ok);
+ int getS16BE(int pos, GBool *ok);
+ int getU16BE(int pos, GBool *ok);
+ int getS32BE(int pos, GBool *ok);
+ Guint getU32BE(int pos, GBool *ok);
+ Guint getUVarBE(int pos, int size, GBool *ok);
+
+ GBool checkRegion(int pos, int size);
+
+ Guchar *fileData;
+ Guchar *file;
+ int len;
+ GBool freeFileData;
+};
+
+#endif
diff --git a/kpdf/xpdf/fofi/FoFiEncodings.cc b/kpdf/xpdf/fofi/FoFiEncodings.cc
new file mode 100644
index 00000000..37a17f5d
--- /dev/null
+++ b/kpdf/xpdf/fofi/FoFiEncodings.cc
@@ -0,0 +1,994 @@
+//========================================================================
+//
+// FoFiEncodings.cc
+//
+// Copyright 1999-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include "FoFiEncodings.h"
+
+//------------------------------------------------------------------------
+// Type 1 and 1C font data
+//------------------------------------------------------------------------
+
+char *fofiType1StandardEncoding[256] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "space",
+ "exclam",
+ "quotedbl",
+ "numbersign",
+ "dollar",
+ "percent",
+ "ampersand",
+ "quoteright",
+ "parenleft",
+ "parenright",
+ "asterisk",
+ "plus",
+ "comma",
+ "hyphen",
+ "period",
+ "slash",
+ "zero",
+ "one",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "colon",
+ "semicolon",
+ "less",
+ "equal",
+ "greater",
+ "question",
+ "at",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "bracketleft",
+ "backslash",
+ "bracketright",
+ "asciicircum",
+ "underscore",
+ "quoteleft",
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f",
+ "g",
+ "h",
+ "i",
+ "j",
+ "k",
+ "l",
+ "m",
+ "n",
+ "o",
+ "p",
+ "q",
+ "r",
+ "s",
+ "t",
+ "u",
+ "v",
+ "w",
+ "x",
+ "y",
+ "z",
+ "braceleft",
+ "bar",
+ "braceright",
+ "asciitilde",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "exclamdown",
+ "cent",
+ "sterling",
+ "fraction",
+ "yen",
+ "florin",
+ "section",
+ "currency",
+ "quotesingle",
+ "quotedblleft",
+ "guillemotleft",
+ "guilsinglleft",
+ "guilsinglright",
+ "fi",
+ "fl",
+ NULL,
+ "endash",
+ "dagger",
+ "daggerdbl",
+ "periodcentered",
+ NULL,
+ "paragraph",
+ "bullet",
+ "quotesinglbase",
+ "quotedblbase",
+ "quotedblright",
+ "guillemotright",
+ "ellipsis",
+ "perthousand",
+ NULL,
+ "questiondown",
+ NULL,
+ "grave",
+ "acute",
+ "circumflex",
+ "tilde",
+ "macron",
+ "breve",
+ "dotaccent",
+ "dieresis",
+ NULL,
+ "ring",
+ "cedilla",
+ NULL,
+ "hungarumlaut",
+ "ogonek",
+ "caron",
+ "emdash",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "AE",
+ NULL,
+ "ordfeminine",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Lslash",
+ "Oslash",
+ "OE",
+ "ordmasculine",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "ae",
+ NULL,
+ NULL,
+ NULL,
+ "dotlessi",
+ NULL,
+ NULL,
+ "lslash",
+ "oslash",
+ "oe",
+ "germandbls",
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+char *fofiType1ExpertEncoding[256] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "space",
+ "exclamsmall",
+ "Hungarumlautsmall",
+ NULL,
+ "dollaroldstyle",
+ "dollarsuperior",
+ "ampersandsmall",
+ "Acutesmall",
+ "parenleftsuperior",
+ "parenrightsuperior",
+ "twodotenleader",
+ "onedotenleader",
+ "comma",
+ "hyphen",
+ "period",
+ "fraction",
+ "zerooldstyle",
+ "oneoldstyle",
+ "twooldstyle",
+ "threeoldstyle",
+ "fouroldstyle",
+ "fiveoldstyle",
+ "sixoldstyle",
+ "sevenoldstyle",
+ "eightoldstyle",
+ "nineoldstyle",
+ "colon",
+ "semicolon",
+ "commasuperior",
+ "threequartersemdash",
+ "periodsuperior",
+ "questionsmall",
+ NULL,
+ "asuperior",
+ "bsuperior",
+ "centsuperior",
+ "dsuperior",
+ "esuperior",
+ NULL,
+ NULL,
+ NULL,
+ "isuperior",
+ NULL,
+ NULL,
+ "lsuperior",
+ "msuperior",
+ "nsuperior",
+ "osuperior",
+ NULL,
+ NULL,
+ "rsuperior",
+ "ssuperior",
+ "tsuperior",
+ NULL,
+ "ff",
+ "fi",
+ "fl",
+ "ffi",
+ "ffl",
+ "parenleftinferior",
+ NULL,
+ "parenrightinferior",
+ "Circumflexsmall",
+ "hyphensuperior",
+ "Gravesmall",
+ "Asmall",
+ "Bsmall",
+ "Csmall",
+ "Dsmall",
+ "Esmall",
+ "Fsmall",
+ "Gsmall",
+ "Hsmall",
+ "Ismall",
+ "Jsmall",
+ "Ksmall",
+ "Lsmall",
+ "Msmall",
+ "Nsmall",
+ "Osmall",
+ "Psmall",
+ "Qsmall",
+ "Rsmall",
+ "Ssmall",
+ "Tsmall",
+ "Usmall",
+ "Vsmall",
+ "Wsmall",
+ "Xsmall",
+ "Ysmall",
+ "Zsmall",
+ "colonmonetary",
+ "onefitted",
+ "rupiah",
+ "Tildesmall",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "exclamdownsmall",
+ "centoldstyle",
+ "Lslashsmall",
+ NULL,
+ NULL,
+ "Scaronsmall",
+ "Zcaronsmall",
+ "Dieresissmall",
+ "Brevesmall",
+ "Caronsmall",
+ NULL,
+ "Dotaccentsmall",
+ NULL,
+ NULL,
+ "Macronsmall",
+ NULL,
+ NULL,
+ "figuredash",
+ "hypheninferior",
+ NULL,
+ NULL,
+ "Ogoneksmall",
+ "Ringsmall",
+ "Cedillasmall",
+ NULL,
+ NULL,
+ NULL,
+ "onequarter",
+ "onehalf",
+ "threequarters",
+ "questiondownsmall",
+ "oneeighth",
+ "threeeighths",
+ "fiveeighths",
+ "seveneighths",
+ "onethird",
+ "twothirds",
+ NULL,
+ NULL,
+ "zerosuperior",
+ "onesuperior",
+ "twosuperior",
+ "threesuperior",
+ "foursuperior",
+ "fivesuperior",
+ "sixsuperior",
+ "sevensuperior",
+ "eightsuperior",
+ "ninesuperior",
+ "zeroinferior",
+ "oneinferior",
+ "twoinferior",
+ "threeinferior",
+ "fourinferior",
+ "fiveinferior",
+ "sixinferior",
+ "seveninferior",
+ "eightinferior",
+ "nineinferior",
+ "centinferior",
+ "dollarinferior",
+ "periodinferior",
+ "commainferior",
+ "Agravesmall",
+ "Aacutesmall",
+ "Acircumflexsmall",
+ "Atildesmall",
+ "Adieresissmall",
+ "Aringsmall",
+ "AEsmall",
+ "Ccedillasmall",
+ "Egravesmall",
+ "Eacutesmall",
+ "Ecircumflexsmall",
+ "Edieresissmall",
+ "Igravesmall",
+ "Iacutesmall",
+ "Icircumflexsmall",
+ "Idieresissmall",
+ "Ethsmall",
+ "Ntildesmall",
+ "Ogravesmall",
+ "Oacutesmall",
+ "Ocircumflexsmall",
+ "Otildesmall",
+ "Odieresissmall",
+ "OEsmall",
+ "Oslashsmall",
+ "Ugravesmall",
+ "Uacutesmall",
+ "Ucircumflexsmall",
+ "Udieresissmall",
+ "Yacutesmall",
+ "Thornsmall",
+ "Ydieresissmall"
+};
+
+//------------------------------------------------------------------------
+// Type 1C font data
+//------------------------------------------------------------------------
+
+char *fofiType1CStdStrings[391] = {
+ ".notdef",
+ "space",
+ "exclam",
+ "quotedbl",
+ "numbersign",
+ "dollar",
+ "percent",
+ "ampersand",
+ "quoteright",
+ "parenleft",
+ "parenright",
+ "asterisk",
+ "plus",
+ "comma",
+ "hyphen",
+ "period",
+ "slash",
+ "zero",
+ "one",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "colon",
+ "semicolon",
+ "less",
+ "equal",
+ "greater",
+ "question",
+ "at",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "bracketleft",
+ "backslash",
+ "bracketright",
+ "asciicircum",
+ "underscore",
+ "quoteleft",
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f",
+ "g",
+ "h",
+ "i",
+ "j",
+ "k",
+ "l",
+ "m",
+ "n",
+ "o",
+ "p",
+ "q",
+ "r",
+ "s",
+ "t",
+ "u",
+ "v",
+ "w",
+ "x",
+ "y",
+ "z",
+ "braceleft",
+ "bar",
+ "braceright",
+ "asciitilde",
+ "exclamdown",
+ "cent",
+ "sterling",
+ "fraction",
+ "yen",
+ "florin",
+ "section",
+ "currency",
+ "quotesingle",
+ "quotedblleft",
+ "guillemotleft",
+ "guilsinglleft",
+ "guilsinglright",
+ "fi",
+ "fl",
+ "endash",
+ "dagger",
+ "daggerdbl",
+ "periodcentered",
+ "paragraph",
+ "bullet",
+ "quotesinglbase",
+ "quotedblbase",
+ "quotedblright",
+ "guillemotright",
+ "ellipsis",
+ "perthousand",
+ "questiondown",
+ "grave",
+ "acute",
+ "circumflex",
+ "tilde",
+ "macron",
+ "breve",
+ "dotaccent",
+ "dieresis",
+ "ring",
+ "cedilla",
+ "hungarumlaut",
+ "ogonek",
+ "caron",
+ "emdash",
+ "AE",
+ "ordfeminine",
+ "Lslash",
+ "Oslash",
+ "OE",
+ "ordmasculine",
+ "ae",
+ "dotlessi",
+ "lslash",
+ "oslash",
+ "oe",
+ "germandbls",
+ "onesuperior",
+ "logicalnot",
+ "mu",
+ "trademark",
+ "Eth",
+ "onehalf",
+ "plusminus",
+ "Thorn",
+ "onequarter",
+ "divide",
+ "brokenbar",
+ "degree",
+ "thorn",
+ "threequarters",
+ "twosuperior",
+ "registered",
+ "minus",
+ "eth",
+ "multiply",
+ "threesuperior",
+ "copyright",
+ "Aacute",
+ "Acircumflex",
+ "Adieresis",
+ "Agrave",
+ "Aring",
+ "Atilde",
+ "Ccedilla",
+ "Eacute",
+ "Ecircumflex",
+ "Edieresis",
+ "Egrave",
+ "Iacute",
+ "Icircumflex",
+ "Idieresis",
+ "Igrave",
+ "Ntilde",
+ "Oacute",
+ "Ocircumflex",
+ "Odieresis",
+ "Ograve",
+ "Otilde",
+ "Scaron",
+ "Uacute",
+ "Ucircumflex",
+ "Udieresis",
+ "Ugrave",
+ "Yacute",
+ "Ydieresis",
+ "Zcaron",
+ "aacute",
+ "acircumflex",
+ "adieresis",
+ "agrave",
+ "aring",
+ "atilde",
+ "ccedilla",
+ "eacute",
+ "ecircumflex",
+ "edieresis",
+ "egrave",
+ "iacute",
+ "icircumflex",
+ "idieresis",
+ "igrave",
+ "ntilde",
+ "oacute",
+ "ocircumflex",
+ "odieresis",
+ "ograve",
+ "otilde",
+ "scaron",
+ "uacute",
+ "ucircumflex",
+ "udieresis",
+ "ugrave",
+ "yacute",
+ "ydieresis",
+ "zcaron",
+ "exclamsmall",
+ "Hungarumlautsmall",
+ "dollaroldstyle",
+ "dollarsuperior",
+ "ampersandsmall",
+ "Acutesmall",
+ "parenleftsuperior",
+ "parenrightsuperior",
+ "twodotenleader",
+ "onedotenleader",
+ "zerooldstyle",
+ "oneoldstyle",
+ "twooldstyle",
+ "threeoldstyle",
+ "fouroldstyle",
+ "fiveoldstyle",
+ "sixoldstyle",
+ "sevenoldstyle",
+ "eightoldstyle",
+ "nineoldstyle",
+ "commasuperior",
+ "threequartersemdash",
+ "periodsuperior",
+ "questionsmall",
+ "asuperior",
+ "bsuperior",
+ "centsuperior",
+ "dsuperior",
+ "esuperior",
+ "isuperior",
+ "lsuperior",
+ "msuperior",
+ "nsuperior",
+ "osuperior",
+ "rsuperior",
+ "ssuperior",
+ "tsuperior",
+ "ff",
+ "ffi",
+ "ffl",
+ "parenleftinferior",
+ "parenrightinferior",
+ "Circumflexsmall",
+ "hyphensuperior",
+ "Gravesmall",
+ "Asmall",
+ "Bsmall",
+ "Csmall",
+ "Dsmall",
+ "Esmall",
+ "Fsmall",
+ "Gsmall",
+ "Hsmall",
+ "Ismall",
+ "Jsmall",
+ "Ksmall",
+ "Lsmall",
+ "Msmall",
+ "Nsmall",
+ "Osmall",
+ "Psmall",
+ "Qsmall",
+ "Rsmall",
+ "Ssmall",
+ "Tsmall",
+ "Usmall",
+ "Vsmall",
+ "Wsmall",
+ "Xsmall",
+ "Ysmall",
+ "Zsmall",
+ "colonmonetary",
+ "onefitted",
+ "rupiah",
+ "Tildesmall",
+ "exclamdownsmall",
+ "centoldstyle",
+ "Lslashsmall",
+ "Scaronsmall",
+ "Zcaronsmall",
+ "Dieresissmall",
+ "Brevesmall",
+ "Caronsmall",
+ "Dotaccentsmall",
+ "Macronsmall",
+ "figuredash",
+ "hypheninferior",
+ "Ogoneksmall",
+ "Ringsmall",
+ "Cedillasmall",
+ "questiondownsmall",
+ "oneeighth",
+ "threeeighths",
+ "fiveeighths",
+ "seveneighths",
+ "onethird",
+ "twothirds",
+ "zerosuperior",
+ "foursuperior",
+ "fivesuperior",
+ "sixsuperior",
+ "sevensuperior",
+ "eightsuperior",
+ "ninesuperior",
+ "zeroinferior",
+ "oneinferior",
+ "twoinferior",
+ "threeinferior",
+ "fourinferior",
+ "fiveinferior",
+ "sixinferior",
+ "seveninferior",
+ "eightinferior",
+ "nineinferior",
+ "centinferior",
+ "dollarinferior",
+ "periodinferior",
+ "commainferior",
+ "Agravesmall",
+ "Aacutesmall",
+ "Acircumflexsmall",
+ "Atildesmall",
+ "Adieresissmall",
+ "Aringsmall",
+ "AEsmall",
+ "Ccedillasmall",
+ "Egravesmall",
+ "Eacutesmall",
+ "Ecircumflexsmall",
+ "Edieresissmall",
+ "Igravesmall",
+ "Iacutesmall",
+ "Icircumflexsmall",
+ "Idieresissmall",
+ "Ethsmall",
+ "Ntildesmall",
+ "Ogravesmall",
+ "Oacutesmall",
+ "Ocircumflexsmall",
+ "Otildesmall",
+ "Odieresissmall",
+ "OEsmall",
+ "Oslashsmall",
+ "Ugravesmall",
+ "Uacutesmall",
+ "Ucircumflexsmall",
+ "Udieresissmall",
+ "Yacutesmall",
+ "Thornsmall",
+ "Ydieresissmall",
+ "001.000",
+ "001.001",
+ "001.002",
+ "001.003",
+ "Black",
+ "Bold",
+ "Book",
+ "Light",
+ "Medium",
+ "Regular",
+ "Roman",
+ "Semibold"
+};
+
+Gushort fofiType1CISOAdobeCharset[229] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
+ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+ 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
+ 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
+ 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+ 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
+ 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
+ 180, 181, 182, 183, 184, 185, 186, 187, 188, 189,
+ 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
+ 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
+ 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
+ 220, 221, 222, 223, 224, 225, 226, 227, 228
+};
+
+Gushort fofiType1CExpertCharset[166] = {
+ 0, 1, 229, 230, 231, 232, 233, 234, 235, 236,
+ 237, 238, 13, 14, 15, 99, 239, 240, 241, 242,
+ 243, 244, 245, 246, 247, 248, 27, 28, 249, 250,
+ 251, 252, 253, 254, 255, 256, 257, 258, 259, 260,
+ 261, 262, 263, 264, 265, 266, 109, 110, 267, 268,
+ 269, 270, 271, 272, 273, 274, 275, 276, 277, 278,
+ 279, 280, 281, 282, 283, 284, 285, 286, 287, 288,
+ 289, 290, 291, 292, 293, 294, 295, 296, 297, 298,
+ 299, 300, 301, 302, 303, 304, 305, 306, 307, 308,
+ 309, 310, 311, 312, 313, 314, 315, 316, 317, 318,
+ 158, 155, 163, 319, 320, 321, 322, 323, 324, 325,
+ 326, 150, 164, 169, 327, 328, 329, 330, 331, 332,
+ 333, 334, 335, 336, 337, 338, 339, 340, 341, 342,
+ 343, 344, 345, 346, 347, 348, 349, 350, 351, 352,
+ 353, 354, 355, 356, 357, 358, 359, 360, 361, 362,
+ 363, 364, 365, 366, 367, 368, 369, 370, 371, 372,
+ 373, 374, 375, 376, 377, 378
+};
+
+Gushort fofiType1CExpertSubsetCharset[87] = {
+ 0, 1, 231, 232, 235, 236, 237, 238, 13, 14,
+ 15, 99, 239, 240, 241, 242, 243, 244, 245, 246,
+ 247, 248, 27, 28, 249, 250, 251, 253, 254, 255,
+ 256, 257, 258, 259, 260, 261, 262, 263, 264, 265,
+ 266, 109, 110, 267, 268, 269, 270, 272, 300, 301,
+ 302, 305, 314, 315, 158, 155, 163, 320, 321, 322,
+ 323, 324, 325, 326, 150, 164, 169, 327, 328, 329,
+ 330, 331, 332, 333, 334, 335, 336, 337, 338, 339,
+ 340, 341, 342, 343, 344, 345, 346
+};
diff --git a/kpdf/xpdf/fofi/FoFiEncodings.h b/kpdf/xpdf/fofi/FoFiEncodings.h
new file mode 100644
index 00000000..50e285d7
--- /dev/null
+++ b/kpdf/xpdf/fofi/FoFiEncodings.h
@@ -0,0 +1,36 @@
+//========================================================================
+//
+// FoFiEncodings.h
+//
+// Copyright 1999-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef FOFIENCODINGS_H
+#define FOFIENCODINGS_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+
+//------------------------------------------------------------------------
+// Type 1 and 1C font data
+//------------------------------------------------------------------------
+
+extern char *fofiType1StandardEncoding[256];
+extern char *fofiType1ExpertEncoding[256];
+
+//------------------------------------------------------------------------
+// Type 1C font data
+//------------------------------------------------------------------------
+
+extern char *fofiType1CStdStrings[391];
+extern Gushort fofiType1CISOAdobeCharset[229];
+extern Gushort fofiType1CExpertCharset[166];
+extern Gushort fofiType1CExpertSubsetCharset[87];
+
+#endif
diff --git a/kpdf/xpdf/fofi/FoFiTrueType.cc b/kpdf/xpdf/fofi/FoFiTrueType.cc
new file mode 100644
index 00000000..a205a068
--- /dev/null
+++ b/kpdf/xpdf/fofi/FoFiTrueType.cc
@@ -0,0 +1,2040 @@
+//========================================================================
+//
+// FoFiTrueType.cc
+//
+// Copyright 1999-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include "gtypes.h"
+#include "gmem.h"
+#include "GString.h"
+#include "GHash.h"
+#include "FoFiType1C.h"
+#include "FoFiTrueType.h"
+
+//
+// Terminology
+// -----------
+//
+// character code = number used as an element of a text string
+//
+// character name = glyph name = name for a particular glyph within a
+// font
+//
+// glyph index = GID = position (within some internal table in the font)
+// where the instructions to draw a particular glyph are
+// stored
+//
+// Type 1 fonts
+// ------------
+//
+// Type 1 fonts contain:
+//
+// Encoding: array of glyph names, maps char codes to glyph names
+//
+// Encoding[charCode] = charName
+//
+// CharStrings: dictionary of instructions, keyed by character names,
+// maps character name to glyph data
+//
+// CharStrings[charName] = glyphData
+//
+// TrueType fonts
+// --------------
+//
+// TrueType fonts contain:
+//
+// 'cmap' table: mapping from character code to glyph index; there may
+// be multiple cmaps in a TrueType font
+//
+// cmap[charCode] = gid
+//
+// 'post' table: mapping from glyph index to glyph name
+//
+// post[gid] = glyphName
+//
+// Type 42 fonts
+// -------------
+//
+// Type 42 fonts contain:
+//
+// Encoding: array of glyph names, maps char codes to glyph names
+//
+// Encoding[charCode] = charName
+//
+// CharStrings: dictionary of glyph indexes, keyed by character names,
+// maps character name to glyph index
+//
+// CharStrings[charName] = gid
+//
+
+//------------------------------------------------------------------------
+
+#define ttcfTag 0x74746366
+
+//------------------------------------------------------------------------
+
+struct TrueTypeTable {
+ Guint tag;
+ Guint checksum;
+ int offset;
+ int origOffset;
+ int len;
+};
+
+struct TrueTypeCmap {
+ int platform;
+ int encoding;
+ int offset;
+ int len;
+ int fmt;
+};
+
+struct TrueTypeLoca {
+ int idx;
+ int origOffset;
+ int newOffset;
+ int len;
+};
+
+#define cmapTag 0x636d6170
+#define glyfTag 0x676c7966
+#define headTag 0x68656164
+#define hheaTag 0x68686561
+#define hmtxTag 0x686d7478
+#define locaTag 0x6c6f6361
+#define nameTag 0x6e616d65
+#define os2Tag 0x4f532f32
+#define postTag 0x706f7374
+
+static int cmpTrueTypeLocaOffset(const void *p1, const void *p2) {
+ TrueTypeLoca *loca1 = (TrueTypeLoca *)p1;
+ TrueTypeLoca *loca2 = (TrueTypeLoca *)p2;
+
+ if (loca1->origOffset == loca2->origOffset) {
+ return loca1->idx - loca2->idx;
+ }
+ return loca1->origOffset - loca2->origOffset;
+}
+
+static int cmpTrueTypeLocaIdx(const void *p1, const void *p2) {
+ TrueTypeLoca *loca1 = (TrueTypeLoca *)p1;
+ TrueTypeLoca *loca2 = (TrueTypeLoca *)p2;
+
+ return loca1->idx - loca2->idx;
+}
+
+static int cmpTrueTypeTableTag(const void *p1, const void *p2) {
+ TrueTypeTable *tab1 = (TrueTypeTable *)p1;
+ TrueTypeTable *tab2 = (TrueTypeTable *)p2;
+
+ return (int)tab1->tag - (int)tab2->tag;
+}
+
+//------------------------------------------------------------------------
+
+struct T42Table {
+ char *tag; // 4-byte tag
+ GBool required; // required by the TrueType spec?
+};
+
+// TrueType tables to be embedded in Type 42 fonts.
+// NB: the table names must be in alphabetical order here.
+#define nT42Tables 11
+static T42Table t42Tables[nT42Tables] = {
+ { "cvt ", gTrue },
+ { "fpgm", gTrue },
+ { "glyf", gTrue },
+ { "head", gTrue },
+ { "hhea", gTrue },
+ { "hmtx", gTrue },
+ { "loca", gTrue },
+ { "maxp", gTrue },
+ { "prep", gTrue },
+ { "vhea", gFalse },
+ { "vmtx", gFalse }
+};
+#define t42HeadTable 3
+#define t42LocaTable 6
+#define t42GlyfTable 2
+#define t42VheaTable 9
+#define t42VmtxTable 10
+
+//------------------------------------------------------------------------
+
+// Glyph names in some arbitrary standard order that Apple uses for
+// their TrueType fonts.
+static char *macGlyphNames[258] = {
+ ".notdef", "null", "CR", "space",
+ "exclam", "quotedbl", "numbersign", "dollar",
+ "percent", "ampersand", "quotesingle", "parenleft",
+ "parenright", "asterisk", "plus", "comma",
+ "hyphen", "period", "slash", "zero",
+ "one", "two", "three", "four",
+ "five", "six", "seven", "eight",
+ "nine", "colon", "semicolon", "less",
+ "equal", "greater", "question", "at",
+ "A", "B", "C", "D",
+ "E", "F", "G", "H",
+ "I", "J", "K", "L",
+ "M", "N", "O", "P",
+ "Q", "R", "S", "T",
+ "U", "V", "W", "X",
+ "Y", "Z", "bracketleft", "backslash",
+ "bracketright", "asciicircum", "underscore", "grave",
+ "a", "b", "c", "d",
+ "e", "f", "g", "h",
+ "i", "j", "k", "l",
+ "m", "n", "o", "p",
+ "q", "r", "s", "t",
+ "u", "v", "w", "x",
+ "y", "z", "braceleft", "bar",
+ "braceright", "asciitilde", "Adieresis", "Aring",
+ "Ccedilla", "Eacute", "Ntilde", "Odieresis",
+ "Udieresis", "aacute", "agrave", "acircumflex",
+ "adieresis", "atilde", "aring", "ccedilla",
+ "eacute", "egrave", "ecircumflex", "edieresis",
+ "iacute", "igrave", "icircumflex", "idieresis",
+ "ntilde", "oacute", "ograve", "ocircumflex",
+ "odieresis", "otilde", "uacute", "ugrave",
+ "ucircumflex", "udieresis", "dagger", "degree",
+ "cent", "sterling", "section", "bullet",
+ "paragraph", "germandbls", "registered", "copyright",
+ "trademark", "acute", "dieresis", "notequal",
+ "AE", "Oslash", "infinity", "plusminus",
+ "lessequal", "greaterequal", "yen", "mu1",
+ "partialdiff", "summation", "product", "pi",
+ "integral", "ordfeminine", "ordmasculine", "Ohm",
+ "ae", "oslash", "questiondown", "exclamdown",
+ "logicalnot", "radical", "florin", "approxequal",
+ "increment", "guillemotleft", "guillemotright", "ellipsis",
+ "nbspace", "Agrave", "Atilde", "Otilde",
+ "OE", "oe", "endash", "emdash",
+ "quotedblleft", "quotedblright", "quoteleft", "quoteright",
+ "divide", "lozenge", "ydieresis", "Ydieresis",
+ "fraction", "currency", "guilsinglleft", "guilsinglright",
+ "fi", "fl", "daggerdbl", "periodcentered",
+ "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex",
+ "Ecircumflex", "Aacute", "Edieresis", "Egrave",
+ "Iacute", "Icircumflex", "Idieresis", "Igrave",
+ "Oacute", "Ocircumflex", "applelogo", "Ograve",
+ "Uacute", "Ucircumflex", "Ugrave", "dotlessi",
+ "circumflex", "tilde", "overscore", "breve",
+ "dotaccent", "ring", "cedilla", "hungarumlaut",
+ "ogonek", "caron", "Lslash", "lslash",
+ "Scaron", "scaron", "Zcaron", "zcaron",
+ "brokenbar", "Eth", "eth", "Yacute",
+ "yacute", "Thorn", "thorn", "minus",
+ "multiply", "onesuperior", "twosuperior", "threesuperior",
+ "onehalf", "onequarter", "threequarters", "franc",
+ "Gbreve", "gbreve", "Idot", "Scedilla",
+ "scedilla", "Cacute", "cacute", "Ccaron",
+ "ccaron", "dmacron"
+};
+
+//------------------------------------------------------------------------
+// FoFiTrueType
+//------------------------------------------------------------------------
+
+FoFiTrueType *FoFiTrueType::make(char *fileA, int lenA, int faceIndexA) {
+ FoFiTrueType *ff;
+
+ ff = new FoFiTrueType(fileA, lenA, gFalse, faceIndexA);
+ if (!ff->parsedOk) {
+ delete ff;
+ return NULL;
+ }
+ return ff;
+}
+
+FoFiTrueType *FoFiTrueType::load(char *fileName, int faceIndexA) {
+ FoFiTrueType *ff;
+ char *fileA;
+ int lenA;
+
+ if (!(fileA = FoFiBase::readFile(fileName, &lenA))) {
+ return NULL;
+ }
+ ff = new FoFiTrueType(fileA, lenA, gTrue, faceIndexA);
+ if (!ff->parsedOk) {
+ delete ff;
+ return NULL;
+ }
+ return ff;
+}
+
+FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, int faceIndexA):
+ FoFiBase(fileA, lenA, freeFileDataA)
+{
+ tables = NULL;
+ nTables = 0;
+ cmaps = NULL;
+ nCmaps = 0;
+ nameToGID = NULL;
+ parsedOk = gFalse;
+ faceIndex = faceIndexA;
+
+ parse();
+}
+
+FoFiTrueType::~FoFiTrueType() {
+ gfree(tables);
+ gfree(cmaps);
+ if (nameToGID) {
+ delete nameToGID;
+ }
+}
+
+int FoFiTrueType::getNumCmaps() {
+ return nCmaps;
+}
+
+int FoFiTrueType::getCmapPlatform(int i) {
+ return cmaps[i].platform;
+}
+
+int FoFiTrueType::getCmapEncoding(int i) {
+ return cmaps[i].encoding;
+}
+
+int FoFiTrueType::findCmap(int platform, int encoding) {
+ int i;
+
+ for (i = 0; i < nCmaps; ++i) {
+ if (cmaps[i].platform == platform && cmaps[i].encoding == encoding) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+Gushort FoFiTrueType::mapCodeToGID(int i, int c) {
+ Gushort gid;
+ int segCnt, segEnd, segStart, segDelta, segOffset;
+ int cmapFirst, cmapLen;
+ int pos, a, b, m;
+ GBool ok;
+
+ if (i < 0 || i >= nCmaps) {
+ return 0;
+ }
+ ok = gTrue;
+ pos = cmaps[i].offset;
+ switch (cmaps[i].fmt) {
+ case 0:
+ if (c < 0 || c >= cmaps[i].len - 6) {
+ return 0;
+ }
+ gid = getU8(cmaps[i].offset + 6 + c, &ok);
+ break;
+ case 4:
+ segCnt = getU16BE(pos + 6, &ok) / 2;
+ a = -1;
+ b = segCnt - 1;
+ segEnd = getU16BE(pos + 14 + 2*b, &ok);
+ if (c > segEnd) {
+ // malformed font -- the TrueType spec requires the last segEnd
+ // to be 0xffff
+ return 0;
+ }
+ // invariant: seg[a].end < code <= seg[b].end
+ while (b - a > 1 && ok) {
+ m = (a + b) / 2;
+ segEnd = getU16BE(pos + 14 + 2*m, &ok);
+ if (segEnd < c) {
+ a = m;
+ } else {
+ b = m;
+ }
+ }
+ segStart = getU16BE(pos + 16 + 2*segCnt + 2*b, &ok);
+ segDelta = getU16BE(pos + 16 + 4*segCnt + 2*b, &ok);
+ segOffset = getU16BE(pos + 16 + 6*segCnt + 2*b, &ok);
+ if (c < segStart) {
+ return 0;
+ }
+ if (segOffset == 0) {
+ gid = (c + segDelta) & 0xffff;
+ } else {
+ gid = getU16BE(pos + 16 + 6*segCnt + 2*b +
+ segOffset + 2 * (c - segStart), &ok);
+ if (gid != 0) {
+ gid = (gid + segDelta) & 0xffff;
+ }
+ }
+ break;
+ case 6:
+ cmapFirst = getU16BE(pos + 6, &ok);
+ cmapLen = getU16BE(pos + 8, &ok);
+ if (c < cmapFirst || c >= cmapFirst + cmapLen) {
+ return 0;
+ }
+ gid = getU16BE(pos + 10 + 2 * (c - cmapFirst), &ok);
+ break;
+ default:
+ return 0;
+ }
+ if (!ok) {
+ return 0;
+ }
+ return gid;
+}
+
+int FoFiTrueType::mapNameToGID(char *name) {
+ if (!nameToGID) {
+ return 0;
+ }
+ return nameToGID->lookupInt(name);
+}
+
+Gushort *FoFiTrueType::getCIDToGIDMap(int *nCIDs) {
+ FoFiType1C *ff;
+ Gushort *map;
+ int i;
+
+ *nCIDs = 0;
+ if (!openTypeCFF) {
+ return NULL;
+ }
+ i = seekTable("CFF ");
+ if (!checkRegion(tables[i].offset, tables[i].len)) {
+ return NULL;
+ }
+ if (!(ff = FoFiType1C::make((char *)file + tables[i].offset,
+ tables[i].len))) {
+ return NULL;
+ }
+ map = ff->getCIDToGIDMap(nCIDs);
+ delete ff;
+ return map;
+}
+
+int FoFiTrueType::getEmbeddingRights() {
+ int i, fsType;
+ GBool ok;
+
+ if ((i = seekTable("OS/2")) < 0) {
+ return 4;
+ }
+ ok = gTrue;
+ fsType = getU16BE(tables[i].offset + 8, &ok);
+ if (!ok) {
+ return 4;
+ }
+ if (fsType & 0x0008) {
+ return 2;
+ }
+ if (fsType & 0x0004) {
+ return 1;
+ }
+ if (fsType & 0x0002) {
+ return 0;
+ }
+ return 3;
+}
+
+void FoFiTrueType::convertToType42(char *psName, char **encoding,
+ Gushort *codeToGID,
+ FoFiOutputFunc outputFunc,
+ void *outputStream) {
+ GString *buf;
+ GBool ok;
+
+ if (openTypeCFF) {
+ return;
+ }
+
+ // write the header
+ ok = gTrue;
+ buf = GString::format("%!PS-TrueTypeFont-{0:2g}\n",
+ (double)getS32BE(0, &ok) / 65536.0);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+
+ // begin the font dictionary
+ (*outputFunc)(outputStream, "10 dict begin\n", 14);
+ (*outputFunc)(outputStream, "/FontName /", 11);
+ (*outputFunc)(outputStream, psName, strlen(psName));
+ (*outputFunc)(outputStream, " def\n", 5);
+ (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
+ (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+ buf = GString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n",
+ bbox[0], bbox[1], bbox[2], bbox[3]);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
+
+ // write the guts of the dictionary
+ cvtEncoding(encoding, outputFunc, outputStream);
+ cvtCharStrings(encoding, codeToGID, outputFunc, outputStream);
+ cvtSfnts(outputFunc, outputStream, NULL, gFalse);
+
+ // end the dictionary and define the font
+ (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
+}
+
+void FoFiTrueType::convertToType1(char *psName, char **newEncoding,
+ GBool ascii, FoFiOutputFunc outputFunc,
+ void *outputStream) {
+ FoFiType1C *ff;
+ int i;
+
+ if (!openTypeCFF) {
+ return;
+ }
+ i = seekTable("CFF ");
+ if (!checkRegion(tables[i].offset, tables[i].len)) {
+ return;
+ }
+ if (!(ff = FoFiType1C::make((char *)file + tables[i].offset,
+ tables[i].len))) {
+ return;
+ }
+ ff->convertToType1(psName, newEncoding, ascii, outputFunc, outputStream);
+ delete ff;
+}
+
+void FoFiTrueType::convertToCIDType2(char *psName,
+ Gushort *cidMap, int nCIDs,
+ GBool needVerticalMetrics,
+ FoFiOutputFunc outputFunc,
+ void *outputStream) {
+ GString *buf;
+ Gushort cid;
+ GBool ok;
+ int i, j, k;
+
+ if (openTypeCFF) {
+ return;
+ }
+
+ // write the header
+ ok = gTrue;
+ buf = GString::format("%!PS-TrueTypeFont-{0:2g}\n",
+ (double)getS32BE(0, &ok) / 65536.0);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+
+ // begin the font dictionary
+ (*outputFunc)(outputStream, "20 dict begin\n", 14);
+ (*outputFunc)(outputStream, "/CIDFontName /", 14);
+ (*outputFunc)(outputStream, psName, strlen(psName));
+ (*outputFunc)(outputStream, " def\n", 5);
+ (*outputFunc)(outputStream, "/CIDFontType 2 def\n", 19);
+ (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
+ (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32);
+ (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24);
+ (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27);
+ (*outputFunc)(outputStream, " /Supplement 0 def\n", 20);
+ (*outputFunc)(outputStream, " end def\n", 10);
+ (*outputFunc)(outputStream, "/GDBytes 2 def\n", 15);
+ if (cidMap) {
+ buf = GString::format("/CIDCount {0:d} def\n", nCIDs);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ if (nCIDs > 32767) {
+ (*outputFunc)(outputStream, "/CIDMap [", 9);
+ for (i = 0; i < nCIDs; i += 32768 - 16) {
+ (*outputFunc)(outputStream, "<\n", 2);
+ for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) {
+ (*outputFunc)(outputStream, " ", 2);
+ for (k = 0; k < 16 && i+j+k < nCIDs; ++k) {
+ cid = cidMap[i+j+k];
+ buf = GString::format("{0:02x}{1:02x}",
+ (cid >> 8) & 0xff, cid & 0xff);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ (*outputFunc)(outputStream, "\n", 1);
+ }
+ (*outputFunc)(outputStream, " >", 3);
+ }
+ (*outputFunc)(outputStream, "\n", 1);
+ (*outputFunc)(outputStream, "] def\n", 6);
+ } else {
+ (*outputFunc)(outputStream, "/CIDMap <\n", 10);
+ for (i = 0; i < nCIDs; i += 16) {
+ (*outputFunc)(outputStream, " ", 2);
+ for (j = 0; j < 16 && i+j < nCIDs; ++j) {
+ cid = cidMap[i+j];
+ buf = GString::format("{0:02x}{1:02x}",
+ (cid >> 8) & 0xff, cid & 0xff);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ (*outputFunc)(outputStream, "\n", 1);
+ }
+ (*outputFunc)(outputStream, "> def\n", 6);
+ }
+ } else {
+ // direct mapping - just fill the string(s) with s[i]=i
+ buf = GString::format("/CIDCount {0:d} def\n", nGlyphs);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ if (nGlyphs > 32767) {
+ (*outputFunc)(outputStream, "/CIDMap [\n", 10);
+ for (i = 0; i < nGlyphs; i += 32767) {
+ j = nGlyphs - i < 32767 ? nGlyphs - i : 32767;
+ buf = GString::format(" {0:d} string 0 1 {1:d} {{\n", 2 * j, j - 1);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ buf = GString::format(" 2 copy dup 2 mul exch {0:d} add -8 bitshift put\n",
+ i);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ buf = GString::format(" 1 index exch dup 2 mul 1 add exch {0:d} add"
+ " 255 and put\n", i);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ (*outputFunc)(outputStream, " } for\n", 8);
+ }
+ (*outputFunc)(outputStream, "] def\n", 6);
+ } else {
+ buf = GString::format("/CIDMap {0:d} string\n", 2 * nGlyphs);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ buf = GString::format(" 0 1 {0:d} {{\n", nGlyphs - 1);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ (*outputFunc)(outputStream,
+ " 2 copy dup 2 mul exch -8 bitshift put\n", 42);
+ (*outputFunc)(outputStream,
+ " 1 index exch dup 2 mul 1 add exch 255 and put\n", 50);
+ (*outputFunc)(outputStream, " } for\n", 8);
+ (*outputFunc)(outputStream, "def\n", 4);
+ }
+ }
+ (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+ buf = GString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n",
+ bbox[0], bbox[1], bbox[2], bbox[3]);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
+ (*outputFunc)(outputStream, "/Encoding [] readonly def\n", 26);
+ (*outputFunc)(outputStream, "/CharStrings 1 dict dup begin\n", 30);
+ (*outputFunc)(outputStream, " /.notdef 0 def\n", 17);
+ (*outputFunc)(outputStream, " end readonly def\n", 19);
+
+ // write the guts of the dictionary
+ cvtSfnts(outputFunc, outputStream, NULL, needVerticalMetrics);
+
+ // end the dictionary and define the font
+ (*outputFunc)(outputStream,
+ "CIDFontName currentdict end /CIDFont defineresource pop\n",
+ 56);
+}
+
+void FoFiTrueType::convertToCIDType0(char *psName,
+ FoFiOutputFunc outputFunc,
+ void *outputStream) {
+ FoFiType1C *ff;
+ int i;
+
+ if (!openTypeCFF) {
+ return;
+ }
+ i = seekTable("CFF ");
+ if (!checkRegion(tables[i].offset, tables[i].len)) {
+ return;
+ }
+ if (!(ff = FoFiType1C::make((char *)file + tables[i].offset,
+ tables[i].len))) {
+ return;
+ }
+ ff->convertToCIDType0(psName, outputFunc, outputStream);
+ delete ff;
+}
+
+void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs,
+ GBool needVerticalMetrics,
+ FoFiOutputFunc outputFunc,
+ void *outputStream) {
+ GString *buf;
+ GString *sfntsName;
+ int n, i, j;
+
+ if (openTypeCFF) {
+ return;
+ }
+
+ // write the Type 42 sfnts array
+ sfntsName = (new GString(psName))->append("_sfnts");
+ cvtSfnts(outputFunc, outputStream, sfntsName, needVerticalMetrics);
+ delete sfntsName;
+
+ // write the descendant Type 42 fonts
+ n = cidMap ? nCIDs : nGlyphs;
+ for (i = 0; i < n; i += 256) {
+ (*outputFunc)(outputStream, "10 dict begin\n", 14);
+ (*outputFunc)(outputStream, "/FontName /", 11);
+ (*outputFunc)(outputStream, psName, strlen(psName));
+ buf = GString::format("_{0:02x} def\n", i >> 8);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
+ (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+ buf = GString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n",
+ bbox[0], bbox[1], bbox[2], bbox[3]);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
+ (*outputFunc)(outputStream, "/sfnts ", 7);
+ (*outputFunc)(outputStream, psName, strlen(psName));
+ (*outputFunc)(outputStream, "_sfnts def\n", 11);
+ (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
+ for (j = 0; j < 256 && i+j < n; ++j) {
+ buf = GString::format("dup {0:d} /c{1:02x} put\n", j, j);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ (*outputFunc)(outputStream, "readonly def\n", 13);
+ (*outputFunc)(outputStream, "/CharStrings 257 dict dup begin\n", 32);
+ (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
+ for (j = 0; j < 256 && i+j < n; ++j) {
+ buf = GString::format("/c{0:02x} {1:d} def\n",
+ j, cidMap ? cidMap[i+j] : i+j);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ (*outputFunc)(outputStream, "end readonly def\n", 17);
+ (*outputFunc)(outputStream,
+ "FontName currentdict end definefont pop\n", 40);
+ }
+
+ // write the Type 0 parent font
+ (*outputFunc)(outputStream, "16 dict begin\n", 14);
+ (*outputFunc)(outputStream, "/FontName /", 11);
+ (*outputFunc)(outputStream, psName, strlen(psName));
+ (*outputFunc)(outputStream, " def\n", 5);
+ (*outputFunc)(outputStream, "/FontType 0 def\n", 16);
+ (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+ (*outputFunc)(outputStream, "/FMapType 2 def\n", 16);
+ (*outputFunc)(outputStream, "/Encoding [\n", 12);
+ for (i = 0; i < n; i += 256) {
+ buf = GString::format("{0:d}\n", i >> 8);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ (*outputFunc)(outputStream, "] def\n", 6);
+ (*outputFunc)(outputStream, "/FDepVector [\n", 14);
+ for (i = 0; i < n; i += 256) {
+ (*outputFunc)(outputStream, "/", 1);
+ (*outputFunc)(outputStream, psName, strlen(psName));
+ buf = GString::format("_{0:02x} findfont\n", i >> 8);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ (*outputFunc)(outputStream, "] def\n", 6);
+ (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
+}
+
+void FoFiTrueType::convertToType0(char *psName,
+ FoFiOutputFunc outputFunc,
+ void *outputStream) {
+ FoFiType1C *ff;
+ int i;
+
+ if (!openTypeCFF) {
+ return;
+ }
+ i = seekTable("CFF ");
+ if (!checkRegion(tables[i].offset, tables[i].len)) {
+ return;
+ }
+ if (!(ff = FoFiType1C::make((char *)file + tables[i].offset,
+ tables[i].len))) {
+ return;
+ }
+ ff->convertToType0(psName, outputFunc, outputStream);
+ delete ff;
+}
+
+void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc,
+ void *outputStream, char *name,
+ Gushort *codeToGID) {
+ // this substitute cmap table maps char codes 0000-ffff directly to
+ // glyphs 0000-ffff
+ static char cmapTab[36] = {
+ 0, 0, // table version number
+ 0, 1, // number of encoding tables
+ 0, 1, // platform ID
+ 0, 0, // encoding ID
+ 0, 0, 0, 12, // offset of subtable
+ 0, 4, // subtable format
+ 0, 24, // subtable length
+ 0, 0, // subtable version
+ 0, 2, // segment count * 2
+ 0, 2, // 2 * 2 ^ floor(log2(segCount))
+ 0, 0, // floor(log2(segCount))
+ 0, 0, // 2*segCount - 2*2^floor(log2(segCount))
+ (char)0xff, (char)0xff, // endCount[0]
+ 0, 0, // reserved
+ 0, 0, // startCount[0]
+ 0, 0, // idDelta[0]
+ 0, 0 // pad to a mulitple of four bytes
+ };
+ static char nameTab[8] = {
+ 0, 0, // format
+ 0, 0, // number of name records
+ 0, 6, // offset to start of string storage
+ 0, 0 // pad to multiple of four bytes
+ };
+ static char postTab[32] = {
+ 0, 1, 0, 0, // format
+ 0, 0, 0, 0, // italic angle
+ 0, 0, // underline position
+ 0, 0, // underline thickness
+ 0, 0, 0, 0, // fixed pitch
+ 0, 0, 0, 0, // min Type 42 memory
+ 0, 0, 0, 0, // max Type 42 memory
+ 0, 0, 0, 0, // min Type 1 memory
+ 0, 0, 0, 0 // max Type 1 memory
+ };
+ static char os2Tab[86] = {
+ 0, 1, // version
+ 0, 1, // xAvgCharWidth
+ 0, 0, // usWeightClass
+ 0, 0, // usWidthClass
+ 0, 0, // fsType
+ 0, 0, // ySubscriptXSize
+ 0, 0, // ySubscriptYSize
+ 0, 0, // ySubscriptXOffset
+ 0, 0, // ySubscriptYOffset
+ 0, 0, // ySuperscriptXSize
+ 0, 0, // ySuperscriptYSize
+ 0, 0, // ySuperscriptXOffset
+ 0, 0, // ySuperscriptYOffset
+ 0, 0, // yStrikeoutSize
+ 0, 0, // yStrikeoutPosition
+ 0, 0, // sFamilyClass
+ 0, 0, 0, 0, 0, // panose
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, // ulUnicodeRange1
+ 0, 0, 0, 0, // ulUnicodeRange2
+ 0, 0, 0, 0, // ulUnicodeRange3
+ 0, 0, 0, 0, // ulUnicodeRange4
+ 0, 0, 0, 0, // achVendID
+ 0, 0, // fsSelection
+ 0, 0, // usFirstCharIndex
+ 0, 0, // usLastCharIndex
+ 0, 0, // sTypoAscender
+ 0, 0, // sTypoDescender
+ 0, 0, // sTypoLineGap
+ 0, 0, // usWinAscent
+ 0, 0, // usWinDescent
+ 0, 0, 0, 0, // ulCodePageRange1
+ 0, 0, 0, 0 // ulCodePageRange2
+ };
+ GBool missingCmap, missingName, missingPost, missingOS2;
+ GBool unsortedLoca, badCmapLen, abbrevHMTX;
+ int nZeroLengthTables;
+ int nHMetrics, advWidth, lsb;
+ TrueTypeLoca *locaTable;
+ TrueTypeTable *newTables;
+ char *newNameTab, *newCmapTab, *newHHEATab, *newHMTXTab;
+ int nNewTables, cmapIdx, cmapLen, glyfLen, newNameLen, newCmapLen, next;
+ int newHHEALen, newHMTXLen;
+ Guint locaChecksum, glyfChecksum, fileChecksum;
+ char *tableDir;
+ char locaBuf[4], checksumBuf[4];
+ GBool ok;
+ Guint t;
+ int pos, i, j, k, n;
+
+ if (openTypeCFF) {
+ return;
+ }
+
+ // check for missing tables
+ // (Note: if the OS/2 table is missing, the Microsoft PCL5 driver
+ // will embed a PCL TrueType font with the pitch field set to zero,
+ // which apparently causes divide-by-zero errors. As far as I can
+ // tell, the only important field in the OS/2 table is
+ // xAvgCharWidth.)
+ missingCmap = (cmapIdx = seekTable("cmap")) < 0;
+ missingName = seekTable("name") < 0;
+ missingPost = seekTable("post") < 0;
+ missingOS2 = seekTable("OS/2") < 0;
+
+ // read the loca table, check to see if it's sorted
+ locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca));
+ unsortedLoca = gFalse;
+ i = seekTable("loca");
+ pos = tables[i].offset;
+ ok = gTrue;
+ for (i = 0; i <= nGlyphs; ++i) {
+ if (locaFmt) {
+ locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok);
+ } else {
+ locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok);
+ }
+ if (i > 0 && locaTable[i].origOffset < locaTable[i-1].origOffset) {
+ unsortedLoca = gTrue;
+ }
+ // glyph descriptions must be at least 12 bytes long (nContours,
+ // xMin, yMin, xMax, yMax, instructionLength - two bytes each);
+ // invalid glyph descriptions (even if they're never used) make
+ // Windows choke, so we work around that problem here (ideally,
+ // this would parse the glyph descriptions in the glyf table and
+ // remove any that were invalid, but this quick test is a decent
+ // start)
+ if (i > 0 &&
+ locaTable[i].origOffset - locaTable[i-1].origOffset > 0 &&
+ locaTable[i].origOffset - locaTable[i-1].origOffset < 12) {
+ locaTable[i-1].origOffset = locaTable[i].origOffset;
+ unsortedLoca = gTrue;
+ }
+ locaTable[i].idx = i;
+ }
+
+ // check for zero-length tables
+ nZeroLengthTables = 0;
+ for (i = 0; i < nTables; ++i) {
+ if (tables[i].len == 0) {
+ ++nZeroLengthTables;
+ }
+ }
+
+ // check for an incorrect cmap table length
+ badCmapLen = gFalse;
+ cmapLen = 0; // make gcc happy
+ if (!missingCmap) {
+ cmapLen = cmaps[0].offset + cmaps[0].len;
+ for (i = 1; i < nCmaps; ++i) {
+ if (cmaps[i].offset + cmaps[i].len > cmapLen) {
+ cmapLen = cmaps[i].offset + cmaps[i].len;
+ }
+ }
+ cmapLen -= tables[cmapIdx].offset;
+ if (cmapLen > tables[cmapIdx].len) {
+ badCmapLen = gTrue;
+ }
+ }
+
+ // check for an abbreviated hmtx table (this is completely legal,
+ // but confuses the Microsoft PCL5 printer driver, which generates
+ // embedded fonts with the pitch field set to zero)
+ i = seekTable("hhea");
+ nHMetrics = getU16BE(tables[i].offset + 34, &ok);
+ abbrevHMTX = nHMetrics < nGlyphs;
+
+ // if nothing is broken, just write the TTF file as is
+ if (!missingCmap && !missingName && !missingPost && !missingOS2 &&
+ !unsortedLoca && !badCmapLen && !abbrevHMTX && nZeroLengthTables == 0 &&
+ !name && !codeToGID) {
+ (*outputFunc)(outputStream, (char *)file, len);
+ goto done1;
+ }
+
+ // sort the 'loca' table: some (non-compliant) fonts have
+ // out-of-order loca tables; in order to correctly handle the case
+ // where (compliant) fonts have empty entries in the middle of the
+ // table, cmpTrueTypeLocaOffset uses offset as its primary sort key,
+ // and idx as its secondary key (ensuring that adjacent entries with
+ // the same pos value remain in the same order)
+ glyfLen = 0; // make gcc happy
+ if (unsortedLoca) {
+ qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
+ &cmpTrueTypeLocaOffset);
+ for (i = 0; i < nGlyphs; ++i) {
+ locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset;
+ }
+ locaTable[nGlyphs].len = 0;
+ qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
+ &cmpTrueTypeLocaIdx);
+ pos = 0;
+ for (i = 0; i <= nGlyphs; ++i) {
+ locaTable[i].newOffset = pos;
+ pos += locaTable[i].len;
+ if (pos & 3) {
+ pos += 4 - (pos & 3);
+ }
+ }
+ glyfLen = pos;
+ }
+
+ // compute checksums for the loca and glyf tables
+ locaChecksum = glyfChecksum = 0;
+ if (unsortedLoca) {
+ if (locaFmt) {
+ for (j = 0; j <= nGlyphs; ++j) {
+ locaChecksum += locaTable[j].newOffset;
+ }
+ } else {
+ for (j = 0; j <= nGlyphs; j += 2) {
+ locaChecksum += locaTable[j].newOffset << 16;
+ if (j + 1 <= nGlyphs) {
+ locaChecksum += locaTable[j+1].newOffset;
+ }
+ }
+ }
+ pos = tables[seekTable("glyf")].offset;
+ for (j = 0; j < nGlyphs; ++j) {
+ n = locaTable[j].len;
+ if (n > 0) {
+ k = locaTable[j].origOffset;
+ if (checkRegion(pos + k, n)) {
+ glyfChecksum += computeTableChecksum(file + pos + k, n);
+ }
+ }
+ }
+ }
+
+ // construct the new name table
+ if (name) {
+ n = strlen(name);
+ newNameLen = (6 + 4*12 + 2 * (3*n + 7) + 3) & ~3;
+ newNameTab = (char *)gmalloc(newNameLen);
+ memset(newNameTab, 0, newNameLen);
+ newNameTab[0] = 0; // format selector
+ newNameTab[1] = 0;
+ newNameTab[2] = 0; // number of name records
+ newNameTab[3] = 4;
+ newNameTab[4] = 0; // offset to start of string storage
+ newNameTab[5] = 6 + 4*12;
+ next = 0;
+ for (i = 0; i < 4; ++i) {
+ newNameTab[6 + i*12 + 0] = 0; // platform ID = Microsoft
+ newNameTab[6 + i*12 + 1] = 3;
+ newNameTab[6 + i*12 + 2] = 0; // encoding ID = Unicode
+ newNameTab[6 + i*12 + 3] = 1;
+ newNameTab[6 + i*12 + 4] = 0x04; // language ID = American English
+ newNameTab[6 + i*12 + 5] = 0x09;
+ newNameTab[6 + i*12 + 6] = 0; // name ID
+ newNameTab[6 + i*12 + 7] = i + 1;
+ newNameTab[6 + i*12 + 8] = i+1 == 2 ? 0 : ((2*n) >> 8); // string length
+ newNameTab[6 + i*12 + 9] = i+1 == 2 ? 14 : ((2*n) & 0xff);
+ newNameTab[6 + i*12 + 10] = next >> 8; // string offset
+ newNameTab[6 + i*12 + 11] = next & 0xff;
+ if (i+1 == 2) {
+ memcpy(newNameTab + 6 + 4*12 + next, "\0R\0e\0g\0u\0l\0a\0r", 14);
+ next += 14;
+ } else {
+ for (j = 0; j < n; ++j) {
+ newNameTab[6 + 4*12 + next + 2*j] = 0;
+ newNameTab[6 + 4*12 + next + 2*j + 1] = name[j];
+ }
+ next += 2*n;
+ }
+ }
+ } else {
+ newNameLen = 0;
+ newNameTab = NULL;
+ }
+
+ // construct the new cmap table
+ if (codeToGID) {
+ newCmapLen = 44 + 256 * 2;
+ newCmapTab = (char *)gmalloc(newCmapLen);
+ newCmapTab[0] = 0; // table version number = 0
+ newCmapTab[1] = 0;
+ newCmapTab[2] = 0; // number of encoding tables = 1
+ newCmapTab[3] = 1;
+ newCmapTab[4] = 0; // platform ID = Microsoft
+ newCmapTab[5] = 3;
+ newCmapTab[6] = 0; // encoding ID = Unicode
+ newCmapTab[7] = 1;
+ newCmapTab[8] = 0; // offset of subtable
+ newCmapTab[9] = 0;
+ newCmapTab[10] = 0;
+ newCmapTab[11] = 12;
+ newCmapTab[12] = 0; // subtable format = 4
+ newCmapTab[13] = 4;
+ newCmapTab[14] = 0x02; // subtable length
+ newCmapTab[15] = 0x20;
+ newCmapTab[16] = 0; // subtable version = 0
+ newCmapTab[17] = 0;
+ newCmapTab[18] = 0; // segment count * 2
+ newCmapTab[19] = 4;
+ newCmapTab[20] = 0; // 2 * 2 ^ floor(log2(segCount))
+ newCmapTab[21] = 4;
+ newCmapTab[22] = 0; // floor(log2(segCount))
+ newCmapTab[23] = 1;
+ newCmapTab[24] = 0; // 2*segCount - 2*2^floor(log2(segCount))
+ newCmapTab[25] = 0;
+ newCmapTab[26] = 0x00; // endCount[0]
+ newCmapTab[27] = (char)0xff;
+ newCmapTab[28] = (char)0xff; // endCount[1]
+ newCmapTab[29] = (char)0xff;
+ newCmapTab[30] = 0; // reserved
+ newCmapTab[31] = 0;
+ newCmapTab[32] = 0x00; // startCount[0]
+ newCmapTab[33] = 0x00;
+ newCmapTab[34] = (char)0xff; // startCount[1]
+ newCmapTab[35] = (char)0xff;
+ newCmapTab[36] = 0; // idDelta[0]
+ newCmapTab[37] = 0;
+ newCmapTab[38] = 0; // idDelta[1]
+ newCmapTab[39] = 1;
+ newCmapTab[40] = 0; // idRangeOffset[0]
+ newCmapTab[41] = 4;
+ newCmapTab[42] = 0; // idRangeOffset[1]
+ newCmapTab[43] = 0;
+ for (i = 0; i < 256; ++i) {
+ newCmapTab[44 + 2*i] = codeToGID[i] >> 8;
+ newCmapTab[44 + 2*i + 1] = codeToGID[i] & 0xff;
+ }
+ } else {
+ newCmapLen = 0;
+ newCmapTab = NULL;
+ }
+
+ // generate the new hmtx table and the updated hhea table
+ if (abbrevHMTX) {
+ i = seekTable("hhea");
+ pos = tables[i].offset;
+ newHHEALen = 36;
+ newHHEATab = (char *)gmalloc(newHHEALen);
+ for (i = 0; i < newHHEALen; ++i) {
+ newHHEATab[i] = getU8(pos++, &ok);
+ }
+ newHHEATab[34] = nGlyphs >> 8;
+ newHHEATab[35] = nGlyphs & 0xff;
+ i = seekTable("hmtx");
+ pos = tables[i].offset;
+ newHMTXLen = 4 * nGlyphs;
+ newHMTXTab = (char *)gmalloc(newHMTXLen);
+ advWidth = 0;
+ for (i = 0; i < nHMetrics; ++i) {
+ advWidth = getU16BE(pos, &ok);
+ lsb = getU16BE(pos + 2, &ok);
+ pos += 4;
+ newHMTXTab[4*i ] = advWidth >> 8;
+ newHMTXTab[4*i + 1] = advWidth & 0xff;
+ newHMTXTab[4*i + 2] = lsb >> 8;
+ newHMTXTab[4*i + 3] = lsb & 0xff;
+ }
+ for (; i < nGlyphs; ++i) {
+ lsb = getU16BE(pos, &ok);
+ pos += 2;
+ newHMTXTab[4*i ] = advWidth >> 8;
+ newHMTXTab[4*i + 1] = advWidth & 0xff;
+ newHMTXTab[4*i + 2] = lsb >> 8;
+ newHMTXTab[4*i + 3] = lsb & 0xff;
+ }
+ } else {
+ newHHEATab = newHMTXTab = NULL;
+ newHHEALen = newHMTXLen = 0; // make gcc happy
+ }
+
+ // construct the new table directory:
+ // - keep all original tables with non-zero length
+ // - fix the cmap table's length, if necessary
+ // - add missing tables
+ // - sort the table by tag
+ // - compute new table positions, including 4-byte alignment
+ // - (re)compute table checksums
+ nNewTables = nTables - nZeroLengthTables +
+ (missingCmap ? 1 : 0) + (missingName ? 1 : 0) +
+ (missingPost ? 1 : 0) + (missingOS2 ? 1 : 0);
+ newTables = (TrueTypeTable *)gmallocn(nNewTables, sizeof(TrueTypeTable));
+ j = 0;
+ for (i = 0; i < nTables; ++i) {
+ if (tables[i].len > 0) {
+ newTables[j] = tables[i];
+ newTables[j].origOffset = tables[i].offset;
+ if (checkRegion(tables[i].offset, newTables[i].len)) {
+ newTables[j].checksum =
+ computeTableChecksum(file + tables[i].offset, tables[i].len);
+ if (tables[i].tag == headTag) {
+ // don't include the file checksum
+ newTables[j].checksum -= getU32BE(tables[i].offset + 8, &ok);
+ }
+ }
+ if (newTables[j].tag == cmapTag && codeToGID) {
+ newTables[j].len = newCmapLen;
+ newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab,
+ newCmapLen);
+ } else if (newTables[j].tag == cmapTag && badCmapLen) {
+ newTables[j].len = cmapLen;
+ } else if (newTables[j].tag == locaTag && unsortedLoca) {
+ newTables[j].len = (nGlyphs + 1) * (locaFmt ? 4 : 2);
+ newTables[j].checksum = locaChecksum;
+ } else if (newTables[j].tag == glyfTag && unsortedLoca) {
+ newTables[j].len = glyfLen;
+ newTables[j].checksum = glyfChecksum;
+ } else if (newTables[j].tag == nameTag && name) {
+ newTables[j].len = newNameLen;
+ newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab,
+ newNameLen);
+ } else if (newTables[j].tag == hheaTag && abbrevHMTX) {
+ newTables[j].len = newHHEALen;
+ newTables[j].checksum = computeTableChecksum((Guchar *)newHHEATab,
+ newHHEALen);
+ } else if (newTables[j].tag == hmtxTag && abbrevHMTX) {
+ newTables[j].len = newHMTXLen;
+ newTables[j].checksum = computeTableChecksum((Guchar *)newHMTXTab,
+ newHMTXLen);
+ }
+ ++j;
+ }
+ }
+ if (missingCmap) {
+ newTables[j].tag = cmapTag;
+ if (codeToGID) {
+ newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab,
+ newCmapLen);
+ newTables[j].len = newCmapLen;
+ } else {
+ newTables[j].checksum = computeTableChecksum((Guchar *)cmapTab,
+ sizeof(cmapTab));
+ newTables[j].len = sizeof(cmapTab);
+ }
+ ++j;
+ }
+ if (missingName) {
+ newTables[j].tag = nameTag;
+ if (name) {
+ newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab,
+ newNameLen);
+ newTables[j].len = newNameLen;
+ } else {
+ newTables[j].checksum = computeTableChecksum((Guchar *)nameTab,
+ sizeof(nameTab));
+ newTables[j].len = sizeof(nameTab);
+ }
+ ++j;
+ }
+ if (missingPost) {
+ newTables[j].tag = postTag;
+ newTables[j].checksum = computeTableChecksum((Guchar *)postTab,
+ sizeof(postTab));
+ newTables[j].len = sizeof(postTab);
+ ++j;
+ }
+ if (missingOS2) {
+ newTables[j].tag = os2Tag;
+ newTables[j].checksum = computeTableChecksum((Guchar *)os2Tab,
+ sizeof(os2Tab));
+ newTables[j].len = sizeof(os2Tab);
+ ++j;
+ }
+ qsort(newTables, nNewTables, sizeof(TrueTypeTable),
+ &cmpTrueTypeTableTag);
+ pos = 12 + nNewTables * 16;
+ for (i = 0; i < nNewTables; ++i) {
+ newTables[i].offset = pos;
+ pos += newTables[i].len;
+ if (pos & 3) {
+ pos += 4 - (pos & 3);
+ }
+ }
+
+ // write the table directory
+ tableDir = (char *)gmalloc(12 + nNewTables * 16);
+ tableDir[0] = 0x00; // sfnt version
+ tableDir[1] = 0x01;
+ tableDir[2] = 0x00;
+ tableDir[3] = 0x00;
+ tableDir[4] = (char)((nNewTables >> 8) & 0xff); // numTables
+ tableDir[5] = (char)(nNewTables & 0xff);
+ for (i = -1, t = (Guint)nNewTables; t; ++i, t >>= 1) ;
+ t = 1 << (4 + i);
+ tableDir[6] = (char)((t >> 8) & 0xff); // searchRange
+ tableDir[7] = (char)(t & 0xff);
+ tableDir[8] = (char)((i >> 8) & 0xff); // entrySelector
+ tableDir[9] = (char)(i & 0xff);
+ t = nNewTables * 16 - t;
+ tableDir[10] = (char)((t >> 8) & 0xff); // rangeShift
+ tableDir[11] = (char)(t & 0xff);
+ pos = 12;
+ for (i = 0; i < nNewTables; ++i) {
+ tableDir[pos ] = (char)(newTables[i].tag >> 24);
+ tableDir[pos+ 1] = (char)(newTables[i].tag >> 16);
+ tableDir[pos+ 2] = (char)(newTables[i].tag >> 8);
+ tableDir[pos+ 3] = (char) newTables[i].tag;
+ tableDir[pos+ 4] = (char)(newTables[i].checksum >> 24);
+ tableDir[pos+ 5] = (char)(newTables[i].checksum >> 16);
+ tableDir[pos+ 6] = (char)(newTables[i].checksum >> 8);
+ tableDir[pos+ 7] = (char) newTables[i].checksum;
+ tableDir[pos+ 8] = (char)(newTables[i].offset >> 24);
+ tableDir[pos+ 9] = (char)(newTables[i].offset >> 16);
+ tableDir[pos+10] = (char)(newTables[i].offset >> 8);
+ tableDir[pos+11] = (char) newTables[i].offset;
+ tableDir[pos+12] = (char)(newTables[i].len >> 24);
+ tableDir[pos+13] = (char)(newTables[i].len >> 16);
+ tableDir[pos+14] = (char)(newTables[i].len >> 8);
+ tableDir[pos+15] = (char) newTables[i].len;
+ pos += 16;
+ }
+ (*outputFunc)(outputStream, tableDir, 12 + nNewTables * 16);
+
+ // compute the file checksum
+ fileChecksum = computeTableChecksum((Guchar *)tableDir,
+ 12 + nNewTables * 16);
+ for (i = 0; i < nNewTables; ++i) {
+ fileChecksum += newTables[i].checksum;
+ }
+ fileChecksum = 0xb1b0afba - fileChecksum;
+
+ // write the tables
+ for (i = 0; i < nNewTables; ++i) {
+ if (newTables[i].tag == headTag) {
+ if (checkRegion(newTables[i].origOffset, newTables[i].len)) {
+ (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, 8);
+ checksumBuf[0] = fileChecksum >> 24;
+ checksumBuf[1] = fileChecksum >> 16;
+ checksumBuf[2] = fileChecksum >> 8;
+ checksumBuf[3] = fileChecksum;
+ (*outputFunc)(outputStream, checksumBuf, 4);
+ (*outputFunc)(outputStream,
+ (char *)file + newTables[i].origOffset + 12,
+ newTables[i].len - 12);
+ } else {
+ for (j = 0; j < newTables[i].len; ++j) {
+ (*outputFunc)(outputStream, "\0", 1);
+ }
+ }
+ } else if (newTables[i].tag == cmapTag && codeToGID) {
+ (*outputFunc)(outputStream, newCmapTab, newTables[i].len);
+ } else if (newTables[i].tag == cmapTag && missingCmap) {
+ (*outputFunc)(outputStream, cmapTab, newTables[i].len);
+ } else if (newTables[i].tag == nameTag && name) {
+ (*outputFunc)(outputStream, newNameTab, newTables[i].len);
+ } else if (newTables[i].tag == nameTag && missingName) {
+ (*outputFunc)(outputStream, nameTab, newTables[i].len);
+ } else if (newTables[i].tag == postTag && missingPost) {
+ (*outputFunc)(outputStream, postTab, newTables[i].len);
+ } else if (newTables[i].tag == os2Tag && missingOS2) {
+ (*outputFunc)(outputStream, os2Tab, newTables[i].len);
+ } else if (newTables[i].tag == hheaTag && abbrevHMTX) {
+ (*outputFunc)(outputStream, newHHEATab, newTables[i].len);
+ } else if (newTables[i].tag == hmtxTag && abbrevHMTX) {
+ (*outputFunc)(outputStream, newHMTXTab, newTables[i].len);
+ } else if (newTables[i].tag == locaTag && unsortedLoca) {
+ for (j = 0; j <= nGlyphs; ++j) {
+ if (locaFmt) {
+ locaBuf[0] = (char)(locaTable[j].newOffset >> 24);
+ locaBuf[1] = (char)(locaTable[j].newOffset >> 16);
+ locaBuf[2] = (char)(locaTable[j].newOffset >> 8);
+ locaBuf[3] = (char) locaTable[j].newOffset;
+ (*outputFunc)(outputStream, locaBuf, 4);
+ } else {
+ locaBuf[0] = (char)(locaTable[j].newOffset >> 9);
+ locaBuf[1] = (char)(locaTable[j].newOffset >> 1);
+ (*outputFunc)(outputStream, locaBuf, 2);
+ }
+ }
+ } else if (newTables[i].tag == glyfTag && unsortedLoca) {
+ pos = tables[seekTable("glyf")].offset;
+ for (j = 0; j < nGlyphs; ++j) {
+ n = locaTable[j].len;
+ if (n > 0) {
+ k = locaTable[j].origOffset;
+ if (checkRegion(pos + k, n)) {
+ (*outputFunc)(outputStream, (char *)file + pos + k, n);
+ } else {
+ for (k = 0; k < n; ++k) {
+ (*outputFunc)(outputStream, "\0", 1);
+ }
+ }
+ if ((k = locaTable[j].len & 3)) {
+ (*outputFunc)(outputStream, "\0\0\0\0", 4 - k);
+ }
+ }
+ }
+ } else {
+ if (checkRegion(newTables[i].origOffset, newTables[i].len)) {
+ (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset,
+ newTables[i].len);
+ } else {
+ for (j = 0; j < newTables[i].len; ++j) {
+ (*outputFunc)(outputStream, "\0", 1);
+ }
+ }
+ }
+ if (newTables[i].len & 3) {
+ (*outputFunc)(outputStream, "\0\0\0", 4 - (newTables[i].len & 3));
+ }
+ }
+
+ gfree(newHMTXTab);
+ gfree(newHHEATab);
+ gfree(newCmapTab);
+ gfree(newNameTab);
+ gfree(tableDir);
+ gfree(newTables);
+ done1:
+ gfree(locaTable);
+}
+
+void FoFiTrueType::cvtEncoding(char **encoding,
+ FoFiOutputFunc outputFunc,
+ void *outputStream) {
+ char *name;
+ GString *buf;
+ int i;
+
+ (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
+ if (encoding) {
+ for (i = 0; i < 256; ++i) {
+ if (!(name = encoding[i])) {
+ name = ".notdef";
+ }
+ buf = GString::format("dup {0:d} /", i);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ (*outputFunc)(outputStream, name, strlen(name));
+ (*outputFunc)(outputStream, " put\n", 5);
+ }
+ } else {
+ for (i = 0; i < 256; ++i) {
+ buf = GString::format("dup {0:d} /c{1:02x} put\n", i, i);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ }
+ (*outputFunc)(outputStream, "readonly def\n", 13);
+}
+
+void FoFiTrueType::cvtCharStrings(char **encoding,
+ Gushort *codeToGID,
+ FoFiOutputFunc outputFunc,
+ void *outputStream) {
+ char *name;
+ GString *buf;
+ char buf2[16];
+ int i, k;
+
+ // always define '.notdef'
+ (*outputFunc)(outputStream, "/CharStrings 256 dict dup begin\n", 32);
+ (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
+
+ // if there's no 'cmap' table, punt
+ if (nCmaps == 0) {
+ goto err;
+ }
+
+ // map char name to glyph index:
+ // 1. use encoding to map name to char code
+ // 2. use codeToGID to map char code to glyph index
+ // N.B. We do this in reverse order because font subsets can have
+ // weird encodings that use the same character name twice, and
+ // the first definition is probably the one we want.
+ k = 0; // make gcc happy
+ for (i = 255; i >= 0; --i) {
+ if (encoding) {
+ name = encoding[i];
+ } else {
+ sprintf(buf2, "c%02x", i);
+ name = buf2;
+ }
+ if (name && strcmp(name, ".notdef")) {
+ k = codeToGID[i];
+ // note: Distiller (maybe Adobe's PS interpreter in general)
+ // doesn't like TrueType fonts that have CharStrings entries
+ // which point to nonexistent glyphs, hence the (k < nGlyphs)
+ // test
+ if (k > 0 && k < nGlyphs) {
+ (*outputFunc)(outputStream, "/", 1);
+ (*outputFunc)(outputStream, name, strlen(name));
+ buf = GString::format(" {0:d} def\n", k);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ }
+ }
+
+ err:
+ (*outputFunc)(outputStream, "end readonly def\n", 17);
+}
+
+void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc,
+ void *outputStream, GString *name,
+ GBool needVerticalMetrics) {
+ Guchar headData[54];
+ TrueTypeLoca *locaTable;
+ Guchar *locaData;
+ TrueTypeTable newTables[nT42Tables];
+ Guchar tableDir[12 + nT42Tables*16];
+ GBool ok;
+ Guint checksum;
+ int nNewTables;
+ int length, pos, glyfPos, i, j, k;
+ Guchar vheaTab[36] = {
+ 0, 1, 0, 0, // table version number
+ 0, 0, // ascent
+ 0, 0, // descent
+ 0, 0, // reserved
+ 0, 0, // max advance height
+ 0, 0, // min top side bearing
+ 0, 0, // min bottom side bearing
+ 0, 0, // y max extent
+ 0, 0, // caret slope rise
+ 0, 1, // caret slope run
+ 0, 0, // caret offset
+ 0, 0, // reserved
+ 0, 0, // reserved
+ 0, 0, // reserved
+ 0, 0, // reserved
+ 0, 0, // metric data format
+ 0, 1 // number of advance heights in vmtx table
+ };
+ Guchar *vmtxTab;
+ GBool needVhea, needVmtx;
+ int advance;
+
+ // construct the 'head' table, zero out the font checksum
+ i = seekTable("head");
+ pos = tables[i].offset;
+ if (!checkRegion(pos, 54)) {
+ return;
+ }
+ memcpy(headData, file + pos, 54);
+ headData[8] = headData[9] = headData[10] = headData[11] = (Guchar)0;
+
+ // read the original 'loca' table, pad entries out to 4 bytes, and
+ // sort it into proper order -- some (non-compliant) fonts have
+ // out-of-order loca tables; in order to correctly handle the case
+ // where (compliant) fonts have empty entries in the middle of the
+ // table, cmpTrueTypeLocaPos uses offset as its primary sort key,
+ // and idx as its secondary key (ensuring that adjacent entries with
+ // the same pos value remain in the same order)
+ locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca));
+ i = seekTable("loca");
+ pos = tables[i].offset;
+ ok = gTrue;
+ for (i = 0; i <= nGlyphs; ++i) {
+ locaTable[i].idx = i;
+ if (locaFmt) {
+ locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok);
+ } else {
+ locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok);
+ }
+ }
+ qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
+ &cmpTrueTypeLocaOffset);
+ for (i = 0; i < nGlyphs; ++i) {
+ locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset;
+ }
+ locaTable[nGlyphs].len = 0;
+ qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
+ &cmpTrueTypeLocaIdx);
+ pos = 0;
+ for (i = 0; i <= nGlyphs; ++i) {
+ locaTable[i].newOffset = pos;
+ pos += locaTable[i].len;
+ if (pos & 3) {
+ pos += 4 - (pos & 3);
+ }
+ }
+
+ // construct the new 'loca' table
+ locaData = (Guchar *)gmallocn(nGlyphs + 1, (locaFmt ? 4 : 2));
+ for (i = 0; i <= nGlyphs; ++i) {
+ pos = locaTable[i].newOffset;
+ if (locaFmt) {
+ locaData[4*i ] = (Guchar)(pos >> 24);
+ locaData[4*i+1] = (Guchar)(pos >> 16);
+ locaData[4*i+2] = (Guchar)(pos >> 8);
+ locaData[4*i+3] = (Guchar) pos;
+ } else {
+ locaData[2*i ] = (Guchar)(pos >> 9);
+ locaData[2*i+1] = (Guchar)(pos >> 1);
+ }
+ }
+
+ // count the number of tables
+ nNewTables = 0;
+ for (i = 0; i < nT42Tables; ++i) {
+ if (t42Tables[i].required ||
+ seekTable(t42Tables[i].tag) >= 0) {
+ ++nNewTables;
+ }
+ }
+ vmtxTab = NULL; // make gcc happy
+ advance = 0; // make gcc happy
+ if (needVerticalMetrics) {
+ needVhea = seekTable("vhea") < 0;
+ needVmtx = seekTable("vmtx") < 0;
+ if (needVhea || needVmtx) {
+ i = seekTable("head");
+ advance = getU16BE(tables[i].offset + 18, &ok); // units per em
+ if (needVhea) {
+ ++nNewTables;
+ }
+ if (needVmtx) {
+ ++nNewTables;
+ }
+ }
+ }
+
+ // construct the new table headers, including table checksums
+ // (pad each table out to a multiple of 4 bytes)
+ pos = 12 + nNewTables*16;
+ k = 0;
+ for (i = 0; i < nT42Tables; ++i) {
+ length = -1;
+ checksum = 0; // make gcc happy
+ if (i == t42HeadTable) {
+ length = 54;
+ checksum = computeTableChecksum(headData, 54);
+ } else if (i == t42LocaTable) {
+ length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
+ checksum = computeTableChecksum(locaData, length);
+ } else if (i == t42GlyfTable) {
+ length = 0;
+ checksum = 0;
+ glyfPos = tables[seekTable("glyf")].offset;
+ for (j = 0; j < nGlyphs; ++j) {
+ length += locaTable[j].len;
+ if (length & 3) {
+ length += 4 - (length & 3);
+ }
+ if (checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) {
+ checksum +=
+ computeTableChecksum(file + glyfPos + locaTable[j].origOffset,
+ locaTable[j].len);
+ }
+ }
+ } else {
+ if ((j = seekTable(t42Tables[i].tag)) >= 0) {
+ length = tables[j].len;
+ if (checkRegion(tables[j].offset, length)) {
+ checksum = computeTableChecksum(file + tables[j].offset, length);
+ }
+ } else if (needVerticalMetrics && i == t42VheaTable) {
+ vheaTab[10] = advance / 256; // max advance height
+ vheaTab[11] = advance % 256;
+ length = sizeof(vheaTab);
+ checksum = computeTableChecksum(vheaTab, length);
+ } else if (needVerticalMetrics && i == t42VmtxTable) {
+ length = 4 + (nGlyphs - 1) * 4;
+ vmtxTab = (Guchar *)gmalloc(length);
+ vmtxTab[0] = advance / 256;
+ vmtxTab[1] = advance % 256;
+ for (j = 2; j < length; j += 2) {
+ vmtxTab[j] = 0;
+ vmtxTab[j+1] = 0;
+ }
+ checksum = computeTableChecksum(vmtxTab, length);
+ } else if (t42Tables[i].required) {
+ //~ error(-1, "Embedded TrueType font is missing a required table ('%s')",
+ //~ t42Tables[i].tag);
+ length = 0;
+ checksum = 0;
+ }
+ }
+ if (length >= 0) {
+ newTables[k].tag = ((t42Tables[i].tag[0] & 0xff) << 24) |
+ ((t42Tables[i].tag[1] & 0xff) << 16) |
+ ((t42Tables[i].tag[2] & 0xff) << 8) |
+ (t42Tables[i].tag[3] & 0xff);
+ newTables[k].checksum = checksum;
+ newTables[k].offset = pos;
+ newTables[k].len = length;
+ pos += length;
+ if (pos & 3) {
+ pos += 4 - (length & 3);
+ }
+ ++k;
+ }
+ }
+
+ // construct the table directory
+ tableDir[0] = 0x00; // sfnt version
+ tableDir[1] = 0x01;
+ tableDir[2] = 0x00;
+ tableDir[3] = 0x00;
+ tableDir[4] = 0; // numTables
+ tableDir[5] = nNewTables;
+ tableDir[6] = 0; // searchRange
+ tableDir[7] = (Guchar)128;
+ tableDir[8] = 0; // entrySelector
+ tableDir[9] = 3;
+ tableDir[10] = 0; // rangeShift
+ tableDir[11] = (Guchar)(16 * nNewTables - 128);
+ pos = 12;
+ for (i = 0; i < nNewTables; ++i) {
+ tableDir[pos ] = (Guchar)(newTables[i].tag >> 24);
+ tableDir[pos+ 1] = (Guchar)(newTables[i].tag >> 16);
+ tableDir[pos+ 2] = (Guchar)(newTables[i].tag >> 8);
+ tableDir[pos+ 3] = (Guchar) newTables[i].tag;
+ tableDir[pos+ 4] = (Guchar)(newTables[i].checksum >> 24);
+ tableDir[pos+ 5] = (Guchar)(newTables[i].checksum >> 16);
+ tableDir[pos+ 6] = (Guchar)(newTables[i].checksum >> 8);
+ tableDir[pos+ 7] = (Guchar) newTables[i].checksum;
+ tableDir[pos+ 8] = (Guchar)(newTables[i].offset >> 24);
+ tableDir[pos+ 9] = (Guchar)(newTables[i].offset >> 16);
+ tableDir[pos+10] = (Guchar)(newTables[i].offset >> 8);
+ tableDir[pos+11] = (Guchar) newTables[i].offset;
+ tableDir[pos+12] = (Guchar)(newTables[i].len >> 24);
+ tableDir[pos+13] = (Guchar)(newTables[i].len >> 16);
+ tableDir[pos+14] = (Guchar)(newTables[i].len >> 8);
+ tableDir[pos+15] = (Guchar) newTables[i].len;
+ pos += 16;
+ }
+
+ // compute the font checksum and store it in the head table
+ checksum = computeTableChecksum(tableDir, 12 + nNewTables*16);
+ for (i = 0; i < nNewTables; ++i) {
+ checksum += newTables[i].checksum;
+ }
+ checksum = 0xb1b0afba - checksum; // because the TrueType spec says so
+ headData[ 8] = (Guchar)(checksum >> 24);
+ headData[ 9] = (Guchar)(checksum >> 16);
+ headData[10] = (Guchar)(checksum >> 8);
+ headData[11] = (Guchar) checksum;
+
+ // start the sfnts array
+ if (name) {
+ (*outputFunc)(outputStream, "/", 1);
+ (*outputFunc)(outputStream, name->getCString(), name->getLength());
+ (*outputFunc)(outputStream, " [\n", 3);
+ } else {
+ (*outputFunc)(outputStream, "/sfnts [\n", 9);
+ }
+
+ // write the table directory
+ dumpString(tableDir, 12 + nNewTables*16, outputFunc, outputStream);
+
+ // write the tables
+ for (i = 0; i < nNewTables; ++i) {
+ if (i == t42HeadTable) {
+ dumpString(headData, 54, outputFunc, outputStream);
+ } else if (i == t42LocaTable) {
+ length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
+ dumpString(locaData, length, outputFunc, outputStream);
+ } else if (i == t42GlyfTable) {
+ glyfPos = tables[seekTable("glyf")].offset;
+ for (j = 0; j < nGlyphs; ++j) {
+ if (locaTable[j].len > 0 &&
+ checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) {
+ dumpString(file + glyfPos + locaTable[j].origOffset,
+ locaTable[j].len, outputFunc, outputStream);
+ }
+ }
+ } else {
+ // length == 0 means the table is missing and the error was
+ // already reported during the construction of the table
+ // headers
+ if ((length = newTables[i].len) > 0) {
+ if ((j = seekTable(t42Tables[i].tag)) >= 0 &&
+ checkRegion(tables[j].offset, tables[j].len)) {
+ dumpString(file + tables[j].offset, tables[j].len,
+ outputFunc, outputStream);
+ } else if (needVerticalMetrics && i == t42VheaTable) {
+ dumpString(vheaTab, length, outputFunc, outputStream);
+ } else if (needVerticalMetrics && i == t42VmtxTable) {
+ dumpString(vmtxTab, length, outputFunc, outputStream);
+ gfree(vmtxTab);
+ }
+ }
+ }
+ }
+
+ // end the sfnts array
+ (*outputFunc)(outputStream, "] def\n", 6);
+
+ gfree(locaData);
+ gfree(locaTable);
+}
+
+void FoFiTrueType::dumpString(Guchar *s, int length,
+ FoFiOutputFunc outputFunc,
+ void *outputStream) {
+ GString *buf;
+ int pad, i, j;
+
+ (*outputFunc)(outputStream, "<", 1);
+ for (i = 0; i < length; i += 32) {
+ for (j = 0; j < 32 && i+j < length; ++j) {
+ buf = GString::format("{0:02x}", s[i+j] & 0xff);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ if (i % (65536 - 32) == 65536 - 64) {
+ (*outputFunc)(outputStream, ">\n<", 3);
+ } else if (i+32 < length) {
+ (*outputFunc)(outputStream, "\n", 1);
+ }
+ }
+ if (length & 3) {
+ pad = 4 - (length & 3);
+ for (i = 0; i < pad; ++i) {
+ (*outputFunc)(outputStream, "00", 2);
+ }
+ }
+ // add an extra zero byte because the Adobe Type 42 spec says so
+ (*outputFunc)(outputStream, "00>\n", 4);
+}
+
+Guint FoFiTrueType::computeTableChecksum(Guchar *data, int length) {
+ Guint checksum, word;
+ int i;
+
+ checksum = 0;
+ for (i = 0; i+3 < length; i += 4) {
+ word = ((data[i ] & 0xff) << 24) +
+ ((data[i+1] & 0xff) << 16) +
+ ((data[i+2] & 0xff) << 8) +
+ (data[i+3] & 0xff);
+ checksum += word;
+ }
+ if (length & 3) {
+ word = 0;
+ i = length & ~3;
+ switch (length & 3) {
+ case 3:
+ word |= (data[i+2] & 0xff) << 8;
+ case 2:
+ word |= (data[i+1] & 0xff) << 16;
+ case 1:
+ word |= (data[i ] & 0xff) << 24;
+ break;
+ }
+ checksum += word;
+ }
+ return checksum;
+}
+
+void FoFiTrueType::parse() {
+ Guint topTag;
+ int pos, ver, i, j;
+
+ parsedOk = gTrue;
+
+ // look for a collection (TTC)
+ topTag = getU32BE(0, &parsedOk);
+ if (!parsedOk) {
+ return;
+ }
+ if (topTag == ttcfTag) {
+ /* TTC font */
+ int dircount;
+
+ dircount = getU32BE(8, &parsedOk);
+ if (!parsedOk)
+ return;
+ if (! dircount) {
+ parsedOk = gFalse;
+ return;
+ }
+
+ if (faceIndex >= dircount)
+ faceIndex = 0;
+ pos = getU32BE(12 + faceIndex * 4, &parsedOk);
+ if (! parsedOk)
+ return;
+ } else {
+ pos = 0;
+ }
+
+ // check the sfnt version
+ ver = getU32BE(pos, &parsedOk);
+ if (!parsedOk) {
+ return;
+ }
+ openTypeCFF = ver == 0x4f54544f; // 'OTTO'
+
+ // read the table directory
+ nTables = getU16BE(pos + 4, &parsedOk);
+ if (!parsedOk) {
+ return;
+ }
+ tables = (TrueTypeTable *)gmallocn(nTables, sizeof(TrueTypeTable));
+ pos += 12;
+ for (i = 0; i < nTables; ++i) {
+ tables[i].tag = getU32BE(pos, &parsedOk);
+ tables[i].checksum = getU32BE(pos + 4, &parsedOk);
+ tables[i].offset = (int)getU32BE(pos + 8, &parsedOk);
+ tables[i].len = (int)getU32BE(pos + 12, &parsedOk);
+ if (tables[i].offset + tables[i].len < tables[i].offset ||
+ tables[i].offset + tables[i].len > len) {
+ parsedOk = gFalse;
+ }
+ pos += 16;
+ }
+ if (!parsedOk) {
+ return;
+ }
+
+ // check for tables that are required by both the TrueType spec and
+ // the Type 42 spec
+ if (seekTable("head") < 0 ||
+ seekTable("hhea") < 0 ||
+ seekTable("maxp") < 0 ||
+ seekTable("hmtx") < 0 ||
+ (!openTypeCFF && seekTable("loca") < 0) ||
+ (!openTypeCFF && seekTable("glyf") < 0) ||
+ (openTypeCFF && seekTable("CFF ") < 0)) {
+ parsedOk = gFalse;
+ return;
+ }
+
+ // read the cmaps
+ if ((i = seekTable("cmap")) >= 0) {
+ pos = tables[i].offset + 2;
+ nCmaps = getU16BE(pos, &parsedOk);
+ pos += 2;
+ if (!parsedOk) {
+ return;
+ }
+ cmaps = (TrueTypeCmap *)gmallocn(nCmaps, sizeof(TrueTypeCmap));
+ for (j = 0; j < nCmaps; ++j) {
+ cmaps[j].platform = getU16BE(pos, &parsedOk);
+ cmaps[j].encoding = getU16BE(pos + 2, &parsedOk);
+ cmaps[j].offset = tables[i].offset + getU32BE(pos + 4, &parsedOk);
+ pos += 8;
+ cmaps[j].fmt = getU16BE(cmaps[j].offset, &parsedOk);
+ cmaps[j].len = getU16BE(cmaps[j].offset + 2, &parsedOk);
+ }
+ if (!parsedOk) {
+ return;
+ }
+ } else {
+ nCmaps = 0;
+ }
+
+ // get the number of glyphs from the maxp table
+ i = seekTable("maxp");
+ nGlyphs = getU16BE(tables[i].offset + 4, &parsedOk);
+ if (!parsedOk) {
+ return;
+ }
+
+ // get the bbox and loca table format from the head table
+ i = seekTable("head");
+ bbox[0] = getS16BE(tables[i].offset + 36, &parsedOk);
+ bbox[1] = getS16BE(tables[i].offset + 38, &parsedOk);
+ bbox[2] = getS16BE(tables[i].offset + 40, &parsedOk);
+ bbox[3] = getS16BE(tables[i].offset + 42, &parsedOk);
+ locaFmt = getS16BE(tables[i].offset + 50, &parsedOk);
+ if (!parsedOk) {
+ return;
+ }
+
+ // make sure the loca table is sane (correct length and entries are
+ // in bounds)
+ if (!openTypeCFF) {
+ i = seekTable("loca");
+ if (tables[i].len < 0) {
+ parsedOk = gFalse;
+ return;
+ }
+ if (tables[i].len < (nGlyphs + 1) * (locaFmt ? 4 : 2)) {
+ nGlyphs = tables[i].len / (locaFmt ? 4 : 2) - 1;
+ }
+ for (j = 0; j <= nGlyphs; ++j) {
+ if (locaFmt) {
+ pos = (int)getU32BE(tables[i].offset + j*4, &parsedOk);
+ } else {
+ pos = getU16BE(tables[i].offset + j*2, &parsedOk);
+ }
+ if (pos < 0 || pos > len) {
+ parsedOk = gFalse;
+ }
+ }
+ if (!parsedOk) {
+ return;
+ }
+ }
+
+ // read the post table
+ readPostTable();
+}
+
+void FoFiTrueType::readPostTable() {
+ GString *name;
+ int tablePos, postFmt, stringIdx, stringPos;
+ GBool ok;
+ int i, j, n, m;
+
+ ok = gTrue;
+ if ((i = seekTable("post")) < 0) {
+ return;
+ }
+ tablePos = tables[i].offset;
+ postFmt = getU32BE(tablePos, &ok);
+ if (!ok) {
+ goto err;
+ }
+ if (postFmt == 0x00010000) {
+ nameToGID = new GHash(gTrue);
+ for (i = 0; i < 258; ++i) {
+ nameToGID->add(new GString(macGlyphNames[i]), i);
+ }
+ } else if (postFmt == 0x00020000) {
+ nameToGID = new GHash(gTrue);
+ n = getU16BE(tablePos + 32, &ok);
+ if (!ok) {
+ goto err;
+ }
+ if (n > nGlyphs) {
+ n = nGlyphs;
+ }
+ stringIdx = 0;
+ stringPos = tablePos + 34 + 2*n;
+ for (i = 0; i < n; ++i) {
+ j = getU16BE(tablePos + 34 + 2*i, &ok);
+ if (j < 258) {
+ nameToGID->removeInt(macGlyphNames[j]);
+ nameToGID->add(new GString(macGlyphNames[j]), i);
+ } else {
+ j -= 258;
+ if (j != stringIdx) {
+ for (stringIdx = 0, stringPos = tablePos + 34 + 2*n;
+ stringIdx < j;
+ ++stringIdx, stringPos += 1 + getU8(stringPos, &ok)) ;
+ if (!ok) {
+ goto err;
+ }
+ }
+ m = getU8(stringPos, &ok);
+ if (!ok || !checkRegion(stringPos + 1, m)) {
+ goto err;
+ }
+ name = new GString((char *)&file[stringPos + 1], m);
+ nameToGID->removeInt(name);
+ nameToGID->add(name, i);
+ ++stringIdx;
+ stringPos += 1 + m;
+ }
+ }
+ } else if (postFmt == 0x00028000) {
+ nameToGID = new GHash(gTrue);
+ for (i = 0; i < nGlyphs; ++i) {
+ j = getU8(tablePos + 32 + i, &ok);
+ if (!ok) {
+ goto err;
+ }
+ if (j < 258) {
+ nameToGID->removeInt(macGlyphNames[j]);
+ nameToGID->add(new GString(macGlyphNames[j]), i);
+ }
+ }
+ }
+
+ return;
+
+ err:
+ if (nameToGID) {
+ delete nameToGID;
+ nameToGID = NULL;
+ }
+}
+
+int FoFiTrueType::seekTable(char *tag) {
+ Guint tagI;
+ int i;
+
+ tagI = ((tag[0] & 0xff) << 24) |
+ ((tag[1] & 0xff) << 16) |
+ ((tag[2] & 0xff) << 8) |
+ (tag[3] & 0xff);
+ for (i = 0; i < nTables; ++i) {
+ if (tables[i].tag == tagI) {
+ return i;
+ }
+ }
+ return -1;
+}
diff --git a/kpdf/xpdf/fofi/FoFiTrueType.h b/kpdf/xpdf/fofi/FoFiTrueType.h
new file mode 100644
index 00000000..eadf5c9f
--- /dev/null
+++ b/kpdf/xpdf/fofi/FoFiTrueType.h
@@ -0,0 +1,175 @@
+//========================================================================
+//
+// FoFiTrueType.h
+//
+// Copyright 1999-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef FOFITRUETYPE_H
+#define FOFITRUETYPE_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "FoFiBase.h"
+
+class GString;
+class GHash;
+struct TrueTypeTable;
+struct TrueTypeCmap;
+
+//------------------------------------------------------------------------
+// FoFiTrueType
+//------------------------------------------------------------------------
+
+class FoFiTrueType: public FoFiBase {
+public:
+
+ // Create a FoFiTrueType object from a memory buffer.
+ static FoFiTrueType *make(char *fileA, int lenA, int faceIndexA=0);
+
+ // Create a FoFiTrueType object from a file on disk.
+ static FoFiTrueType *load(char *fileName, int faceIndexA=0);
+
+ virtual ~FoFiTrueType();
+
+ // Returns true if this an OpenType font containing CFF data, false
+ // if it's a TrueType font (or OpenType font with TrueType data).
+ GBool isOpenTypeCFF() { return openTypeCFF; }
+
+ // Return the number of cmaps defined by this font.
+ int getNumCmaps();
+
+ // Return the platform ID of the <i>th cmap.
+ int getCmapPlatform(int i);
+
+ // Return the encoding ID of the <i>th cmap.
+ int getCmapEncoding(int i);
+
+ // Return the index of the cmap for <platform>, <encoding>. Returns
+ // -1 if there is no corresponding cmap.
+ int findCmap(int platform, int encoding);
+
+ // Return the GID corresponding to <c> according to the <i>th cmap.
+ Gushort mapCodeToGID(int i, int c);
+
+ // Returns the GID corresponding to <name> according to the post
+ // table. Returns 0 if there is no mapping for <name> or if the
+ // font does not have a post table.
+ int mapNameToGID(char *name);
+
+ // Return the mapping from CIDs to GIDs, and return the number of
+ // CIDs in *<nCIDs>. This is only useful for CID fonts. (Only
+ // useful for OpenType CFF fonts.)
+ Gushort *getCIDToGIDMap(int *nCIDs);
+
+ // Returns the least restrictive embedding licensing right (as
+ // defined by the TrueType spec):
+ // * 4: OS/2 table is missing or invalid
+ // * 3: installable embedding
+ // * 2: editable embedding
+ // * 1: preview & print embedding
+ // * 0: restricted license embedding
+ int getEmbeddingRights();
+
+ // Convert to a Type 42 font, suitable for embedding in a PostScript
+ // file. <psName> will be used as the PostScript font name (so we
+ // don't need to depend on the 'name' table in the font). The
+ // <encoding> array specifies the mapping from char codes to names.
+ // If <encoding> is NULL, the encoding is unknown or undefined. The
+ // <codeToGID> array specifies the mapping from char codes to GIDs.
+ // (Not useful for OpenType CFF fonts.)
+ void convertToType42(char *psName, char **encoding,
+ Gushort *codeToGID,
+ FoFiOutputFunc outputFunc, void *outputStream);
+
+ // Convert to a Type 1 font, suitable for embedding in a PostScript
+ // file. This is only useful with 8-bit fonts. If <newEncoding> is
+ // not NULL, it will be used in place of the encoding in the Type 1C
+ // font. If <ascii> is true the eexec section will be hex-encoded,
+ // otherwise it will be left as binary data. If <psName> is
+ // non-NULL, it will be used as the PostScript font name. (Only
+ // useful for OpenType CFF fonts.)
+ void convertToType1(char *psName, char **newEncoding, GBool ascii,
+ FoFiOutputFunc outputFunc, void *outputStream);
+
+ // Convert to a Type 2 CIDFont, suitable for embedding in a
+ // PostScript file. <psName> will be used as the PostScript font
+ // name (so we don't need to depend on the 'name' table in the
+ // font). The <cidMap> array maps CIDs to GIDs; it has <nCIDs>
+ // entries. (Not useful for OpenType CFF fonts.)
+ void convertToCIDType2(char *psName, Gushort *cidMap, int nCIDs,
+ GBool needVerticalMetrics,
+ FoFiOutputFunc outputFunc, void *outputStream);
+
+ // Convert to a Type 0 CIDFont, suitable for embedding in a
+ // PostScript file. <psName> will be used as the PostScript font
+ // name. (Only useful for OpenType CFF fonts.)
+ void convertToCIDType0(char *psName,
+ FoFiOutputFunc outputFunc, void *outputStream);
+
+ // Convert to a Type 0 (but non-CID) composite font, suitable for
+ // embedding in a PostScript file. <psName> will be used as the
+ // PostScript font name (so we don't need to depend on the 'name'
+ // table in the font). The <cidMap> array maps CIDs to GIDs; it has
+ // <nCIDs> entries. (Not useful for OpenType CFF fonts.)
+ void convertToType0(char *psName, Gushort *cidMap, int nCIDs,
+ GBool needVerticalMetrics,
+ FoFiOutputFunc outputFunc, void *outputStream);
+
+ // Convert to a Type 0 (but non-CID) composite font, suitable for
+ // embedding in a PostScript file. <psName> will be used as the
+ // PostScript font name. (Only useful for OpenType CFF fonts.)
+ void convertToType0(char *psName,
+ FoFiOutputFunc outputFunc, void *outputStream);
+
+ // Write a clean TTF file, filling in missing tables and correcting
+ // various other errors. If <name> is non-NULL, the font is renamed
+ // to <name>. If <codeToGID> is non-NULL, the font is re-encoded,
+ // using a Windows Unicode cmap. If <name> is NULL and the font is
+ // complete and correct, it will be written unmodified. (Not useful
+ // for OpenType CFF fonts.)
+ void writeTTF(FoFiOutputFunc outputFunc, void *outputStream,
+ char *name = NULL, Gushort *codeToGID = NULL);
+
+private:
+
+ FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, int faceIndexA);
+ void cvtEncoding(char **encoding,
+ FoFiOutputFunc outputFunc,
+ void *outputStream);
+ void cvtCharStrings(char **encoding,
+ Gushort *codeToGID,
+ FoFiOutputFunc outputFunc,
+ void *outputStream);
+ void cvtSfnts(FoFiOutputFunc outputFunc,
+ void *outputStream, GString *name,
+ GBool needVerticalMetrics);
+ void dumpString(Guchar *s, int length,
+ FoFiOutputFunc outputFunc,
+ void *outputStream);
+ Guint computeTableChecksum(Guchar *data, int length);
+ void parse();
+ void readPostTable();
+ int seekTable(char *tag);
+
+ TrueTypeTable *tables;
+ int nTables;
+ TrueTypeCmap *cmaps;
+ int nCmaps;
+ int nGlyphs;
+ int locaFmt;
+ int bbox[4];
+ GHash *nameToGID;
+ GBool openTypeCFF;
+
+ GBool parsedOk;
+ int faceIndex;
+};
+
+#endif
diff --git a/kpdf/xpdf/fofi/FoFiType1.cc b/kpdf/xpdf/fofi/FoFiType1.cc
new file mode 100644
index 00000000..efad5ee4
--- /dev/null
+++ b/kpdf/xpdf/fofi/FoFiType1.cc
@@ -0,0 +1,252 @@
+//========================================================================
+//
+// FoFiType1.cc
+//
+// Copyright 1999-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include "gmem.h"
+#include "FoFiEncodings.h"
+#include "FoFiType1.h"
+
+//------------------------------------------------------------------------
+// FoFiType1
+//------------------------------------------------------------------------
+
+FoFiType1 *FoFiType1::make(char *fileA, int lenA) {
+ return new FoFiType1(fileA, lenA, gFalse);
+}
+
+FoFiType1 *FoFiType1::load(char *fileName) {
+ char *fileA;
+ int lenA;
+
+ if (!(fileA = FoFiBase::readFile(fileName, &lenA))) {
+ return NULL;
+ }
+ return new FoFiType1(fileA, lenA, gTrue);
+}
+
+FoFiType1::FoFiType1(char *fileA, int lenA, GBool freeFileDataA):
+ FoFiBase(fileA, lenA, freeFileDataA)
+{
+ name = NULL;
+ encoding = NULL;
+ parsed = gFalse;
+}
+
+FoFiType1::~FoFiType1() {
+ int i;
+
+ if (name) {
+ gfree(name);
+ }
+ if (encoding && encoding != fofiType1StandardEncoding) {
+ for (i = 0; i < 256; ++i) {
+ gfree(encoding[i]);
+ }
+ gfree(encoding);
+ }
+}
+
+char *FoFiType1::getName() {
+ if (!parsed) {
+ parse();
+ }
+ return name;
+}
+
+char **FoFiType1::getEncoding() {
+ if (!parsed) {
+ parse();
+ }
+ return encoding;
+}
+
+void FoFiType1::writeEncoded(char **newEncoding,
+ FoFiOutputFunc outputFunc, void *outputStream) {
+ char buf[512];
+ char *line, *line2, *p;
+ int i;
+
+ // copy everything up to the encoding
+ for (line = (char *)file;
+ line && strncmp(line, "/Encoding", 9);
+ line = getNextLine(line)) ;
+ if (!line) {
+ // no encoding - just copy the whole font file
+ (*outputFunc)(outputStream, (char *)file, len);
+ return;
+ }
+ (*outputFunc)(outputStream, (char *)file, line - (char *)file);
+
+ // write the new encoding
+ (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
+ (*outputFunc)(outputStream,
+ "0 1 255 {1 index exch /.notdef put} for\n", 40);
+ for (i = 0; i < 256; ++i) {
+ if (newEncoding[i]) {
+ sprintf(buf, "dup %d /%s put\n", i, newEncoding[i]);
+ (*outputFunc)(outputStream, buf, strlen(buf));
+ }
+ }
+ (*outputFunc)(outputStream, "readonly def\n", 13);
+
+ // find the end of the encoding data
+ //~ this ought to parse PostScript tokens
+ if (!strncmp(line, "/Encoding StandardEncoding def", 30)) {
+ line = getNextLine(line);
+ } else {
+ // skip "/Encoding" + one whitespace char,
+ // then look for 'def' preceded by PostScript whitespace
+ p = line + 10;
+ line = NULL;
+ for (; p < (char *)file + len; ++p) {
+ if ((*p == ' ' || *p == '\t' || *p == '\x0a' ||
+ *p == '\x0d' || *p == '\x0c' || *p == '\0') &&
+ p + 4 <= (char *)file + len &&
+ !strncmp(p + 1, "def", 3)) {
+ line = p + 4;
+ break;
+ }
+ }
+ }
+
+ // some fonts have two /Encoding entries in their dictionary, so we
+ // check for a second one here
+ if (line) {
+ for (line2 = line, i = 0;
+ i < 20 && line2 && strncmp(line2, "/Encoding", 9);
+ line2 = getNextLine(line2), ++i) ;
+ if (i < 20 && line2) {
+ (*outputFunc)(outputStream, line, line2 - line);
+ if (!strncmp(line2, "/Encoding StandardEncoding def", 30)) {
+ line = getNextLine(line2);
+ } else {
+ // skip "/Encoding" + one whitespace char,
+ // then look for 'def' preceded by PostScript whitespace
+ p = line2 + 10;
+ line = NULL;
+ for (; p < (char *)file + len; ++p) {
+ if ((*p == ' ' || *p == '\t' || *p == '\x0a' ||
+ *p == '\x0d' || *p == '\x0c' || *p == '\0') &&
+ p + 4 <= (char *)file + len &&
+ !strncmp(p + 1, "def", 3)) {
+ line = p + 4;
+ break;
+ }
+ }
+ }
+ }
+
+ // copy everything after the encoding
+ if (line) {
+ (*outputFunc)(outputStream, line, ((char *)file + len) - line);
+ }
+ }
+}
+
+char *FoFiType1::getNextLine(char *line) {
+ while (line < (char *)file + len && *line != '\x0a' && *line != '\x0d') {
+ ++line;
+ }
+ if (line < (char *)file + len && *line == '\x0d') {
+ ++line;
+ }
+ if (line < (char *)file + len && *line == '\x0a') {
+ ++line;
+ }
+ if (line >= (char *)file + len) {
+ return NULL;
+ }
+ return line;
+}
+
+void FoFiType1::parse() {
+ char *line, *line1, *p, *p2;
+ char buf[256];
+ char c;
+ int n, code, i, j;
+
+ for (i = 1, line = (char *)file;
+ i <= 100 && line && (!name || !encoding);
+ ++i) {
+
+ // get font name
+ if (!name && !strncmp(line, "/FontName", 9)) {
+ strncpy(buf, line, 255);
+ buf[255] = '\0';
+ if ((p = strchr(buf+9, '/')) &&
+ (p = strtok(p+1, " \t\n\r"))) {
+ name = copyString(p);
+ }
+ line = getNextLine(line);
+
+ // get encoding
+ } else if (!encoding &&
+ !strncmp(line, "/Encoding StandardEncoding def", 30)) {
+ encoding = fofiType1StandardEncoding;
+ } else if (!encoding &&
+ !strncmp(line, "/Encoding 256 array", 19)) {
+ encoding = (char **)gmallocn(256, sizeof(char *));
+ for (j = 0; j < 256; ++j) {
+ encoding[j] = NULL;
+ }
+ for (j = 0, line = getNextLine(line);
+ j < 300 && line && (line1 = getNextLine(line));
+ ++j, line = line1) {
+ if ((n = line1 - line) > 255) {
+ n = 255;
+ }
+ strncpy(buf, line, n);
+ buf[n] = '\0';
+ for (p = buf; *p == ' ' || *p == '\t'; ++p) ;
+ if (!strncmp(p, "dup", 3)) {
+ for (p += 3; *p == ' ' || *p == '\t'; ++p) ;
+ for (p2 = p; *p2 >= '0' && *p2 <= '9'; ++p2) ;
+ if (*p2) {
+ c = *p2;
+ *p2 = '\0';
+ code = atoi(p);
+ *p2 = c;
+ if (code == 8 && *p2 == '#') {
+ code = 0;
+ for (++p2; *p2 >= '0' && *p2 <= '7'; ++p2) {
+ code = code * 8 + (*p2 - '0');
+ }
+ }
+ if (code < 256) {
+ for (p = p2; *p == ' ' || *p == '\t'; ++p) ;
+ if (*p == '/') {
+ ++p;
+ for (p2 = p; *p2 && *p2 != ' ' && *p2 != '\t'; ++p2) ;
+ *p2 = '\0';
+ encoding[code] = copyString(p);
+ }
+ }
+ }
+ } else {
+ if (strtok(buf, " \t") &&
+ (p = strtok(NULL, " \t\n\r")) && !strcmp(p, "def")) {
+ break;
+ }
+ }
+ }
+ //~ check for getinterval/putinterval junk
+
+ } else {
+ line = getNextLine(line);
+ }
+ }
+
+ parsed = gTrue;
+}
diff --git a/kpdf/xpdf/fofi/FoFiType1.h b/kpdf/xpdf/fofi/FoFiType1.h
new file mode 100644
index 00000000..843352b2
--- /dev/null
+++ b/kpdf/xpdf/fofi/FoFiType1.h
@@ -0,0 +1,59 @@
+//========================================================================
+//
+// FoFiType1.h
+//
+// Copyright 1999-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef FOFITYPE1_H
+#define FOFITYPE1_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "FoFiBase.h"
+
+//------------------------------------------------------------------------
+// FoFiType1
+//------------------------------------------------------------------------
+
+class FoFiType1: public FoFiBase {
+public:
+
+ // Create a FoFiType1 object from a memory buffer.
+ static FoFiType1 *make(char *fileA, int lenA);
+
+ // Create a FoFiType1 object from a file on disk.
+ static FoFiType1 *load(char *fileName);
+
+ virtual ~FoFiType1();
+
+ // Return the font name.
+ char *getName();
+
+ // Return the encoding, as an array of 256 names (any of which may
+ // be NULL).
+ char **getEncoding();
+
+ // Write a version of the Type 1 font file with a new encoding.
+ void writeEncoded(char **newEncoding,
+ FoFiOutputFunc outputFunc, void *outputStream);
+
+private:
+
+ FoFiType1(char *fileA, int lenA, GBool freeFileDataA);
+
+ char *getNextLine(char *line);
+ void parse();
+
+ char *name;
+ char **encoding;
+ GBool parsed;
+};
+
+#endif
diff --git a/kpdf/xpdf/fofi/FoFiType1C.cc b/kpdf/xpdf/fofi/FoFiType1C.cc
new file mode 100644
index 00000000..3b28f321
--- /dev/null
+++ b/kpdf/xpdf/fofi/FoFiType1C.cc
@@ -0,0 +1,2603 @@
+//========================================================================
+//
+// FoFiType1C.cc
+//
+// Copyright 1999-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "gmem.h"
+#include "GString.h"
+#include "FoFiEncodings.h"
+#include "FoFiType1C.h"
+
+//------------------------------------------------------------------------
+
+static char hexChars[17] = "0123456789ABCDEF";
+
+//------------------------------------------------------------------------
+// FoFiType1C
+//------------------------------------------------------------------------
+
+FoFiType1C *FoFiType1C::make(char *fileA, int lenA) {
+ FoFiType1C *ff;
+
+ ff = new FoFiType1C(fileA, lenA, gFalse);
+ if (!ff->parse()) {
+ delete ff;
+ return NULL;
+ }
+ return ff;
+}
+
+FoFiType1C *FoFiType1C::load(char *fileName) {
+ FoFiType1C *ff;
+ char *fileA;
+ int lenA;
+
+ if (!(fileA = FoFiBase::readFile(fileName, &lenA))) {
+ return NULL;
+ }
+ ff = new FoFiType1C(fileA, lenA, gTrue);
+ if (!ff->parse()) {
+ delete ff;
+ return NULL;
+ }
+ return ff;
+}
+
+FoFiType1C::FoFiType1C(char *fileA, int lenA, GBool freeFileDataA):
+ FoFiBase(fileA, lenA, freeFileDataA)
+{
+ name = NULL;
+ encoding = NULL;
+ privateDicts = NULL;
+ fdSelect = NULL;
+ charset = NULL;
+}
+
+FoFiType1C::~FoFiType1C() {
+ int i;
+
+ if (name) {
+ delete name;
+ }
+ if (encoding &&
+ encoding != fofiType1StandardEncoding &&
+ encoding != fofiType1ExpertEncoding) {
+ for (i = 0; i < 256; ++i) {
+ gfree(encoding[i]);
+ }
+ gfree(encoding);
+ }
+ if (privateDicts) {
+ gfree(privateDicts);
+ }
+ if (fdSelect) {
+ gfree(fdSelect);
+ }
+ if (charset &&
+ charset != fofiType1CISOAdobeCharset &&
+ charset != fofiType1CExpertCharset &&
+ charset != fofiType1CExpertSubsetCharset) {
+ gfree(charset);
+ }
+}
+
+char *FoFiType1C::getName() {
+ return name ? name->getCString() : (char *)NULL;
+}
+
+char **FoFiType1C::getEncoding() {
+ return encoding;
+}
+
+Gushort *FoFiType1C::getCIDToGIDMap(int *nCIDs) {
+ Gushort *map;
+ int n, i;
+
+ // a CID font's top dict has ROS as the first operator
+ if (topDict.firstOp != 0x0c1e) {
+ *nCIDs = 0;
+ return NULL;
+ }
+
+ // in a CID font, the charset data is the GID-to-CID mapping, so all
+ // we have to do is reverse it
+ n = 0;
+ for (i = 0; i < nGlyphs; ++i) {
+ if (charset[i] > n) {
+ n = charset[i];
+ }
+ }
+ ++n;
+ map = (Gushort *)gmallocn(n, sizeof(Gushort));
+ memset(map, 0, n * sizeof(Gushort));
+ for (i = 0; i < nGlyphs; ++i) {
+ map[charset[i]] = i;
+ }
+ *nCIDs = n;
+ return map;
+}
+
+void FoFiType1C::convertToType1(char *psName, char **newEncoding, GBool ascii,
+ FoFiOutputFunc outputFunc,
+ void *outputStream) {
+ int psNameLen;
+ Type1CEexecBuf eb;
+ Type1CIndex subrIdx;
+ Type1CIndexVal val;
+ GString *buf;
+ char buf2[256];
+ char **enc;
+ GBool ok;
+ int i;
+
+ if (psName) {
+ psNameLen = strlen(psName);
+ } else {
+ psName = name->getCString();
+ psNameLen = name->getLength();
+ }
+
+ // write header and font dictionary, up to encoding
+ ok = gTrue;
+ (*outputFunc)(outputStream, "%!FontType1-1.0: ", 17);
+ (*outputFunc)(outputStream, psName, psNameLen);
+ if (topDict.versionSID != 0) {
+ getString(topDict.versionSID, buf2, &ok);
+ (*outputFunc)(outputStream, buf2, strlen(buf2));
+ }
+ (*outputFunc)(outputStream, "\n", 1);
+ // the dictionary needs room for 12 entries: the following 9, plus
+ // Private and CharStrings (in the eexec section) and FID (which is
+ // added by definefont)
+ (*outputFunc)(outputStream, "12 dict begin\n", 14);
+ (*outputFunc)(outputStream, "/FontInfo 10 dict dup begin\n", 28);
+ if (topDict.versionSID != 0) {
+ (*outputFunc)(outputStream, "/version (", 10);
+ (*outputFunc)(outputStream, buf2, strlen(buf2));
+ (*outputFunc)(outputStream, ") readonly def\n", 15);
+ }
+ if (topDict.noticeSID != 0) {
+ getString(topDict.noticeSID, buf2, &ok);
+ (*outputFunc)(outputStream, "/Notice (", 9);
+ (*outputFunc)(outputStream, buf2, strlen(buf2));
+ (*outputFunc)(outputStream, ") readonly def\n", 15);
+ }
+ if (topDict.copyrightSID != 0) {
+ getString(topDict.copyrightSID, buf2, &ok);
+ (*outputFunc)(outputStream, "/Copyright (", 12);
+ (*outputFunc)(outputStream, buf2, strlen(buf2));
+ (*outputFunc)(outputStream, ") readonly def\n", 15);
+ }
+ if (topDict.fullNameSID != 0) {
+ getString(topDict.fullNameSID, buf2, &ok);
+ (*outputFunc)(outputStream, "/FullName (", 11);
+ (*outputFunc)(outputStream, buf2, strlen(buf2));
+ (*outputFunc)(outputStream, ") readonly def\n", 15);
+ }
+ if (topDict.familyNameSID != 0) {
+ getString(topDict.familyNameSID, buf2, &ok);
+ (*outputFunc)(outputStream, "/FamilyName (", 13);
+ (*outputFunc)(outputStream, buf2, strlen(buf2));
+ (*outputFunc)(outputStream, ") readonly def\n", 15);
+ }
+ if (topDict.weightSID != 0) {
+ getString(topDict.weightSID, buf2, &ok);
+ (*outputFunc)(outputStream, "/Weight (", 9);
+ (*outputFunc)(outputStream, buf2, strlen(buf2));
+ (*outputFunc)(outputStream, ") readonly def\n", 15);
+ }
+ if (topDict.isFixedPitch) {
+ (*outputFunc)(outputStream, "/isFixedPitch true def\n", 23);
+ } else {
+ (*outputFunc)(outputStream, "/isFixedPitch false def\n", 24);
+ }
+ buf = GString::format("/ItalicAngle {0:.4g} def\n", topDict.italicAngle);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ buf = GString::format("/UnderlinePosition {0:.4g} def\n",
+ topDict.underlinePosition);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ buf = GString::format("/UnderlineThickness {0:.4g} def\n",
+ topDict.underlineThickness);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ (*outputFunc)(outputStream, "end readonly def\n", 17);
+ (*outputFunc)(outputStream, "/FontName /", 11);
+ (*outputFunc)(outputStream, psName, psNameLen);
+ (*outputFunc)(outputStream, " def\n", 5);
+ buf = GString::format("/PaintType {0:d} def\n", topDict.paintType);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ (*outputFunc)(outputStream, "/FontType 1 def\n", 16);
+ buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] readonly def\n",
+ topDict.fontMatrix[0], topDict.fontMatrix[1],
+ topDict.fontMatrix[2], topDict.fontMatrix[3],
+ topDict.fontMatrix[4], topDict.fontMatrix[5]);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ buf = GString::format("/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] readonly def\n",
+ topDict.fontBBox[0], topDict.fontBBox[1],
+ topDict.fontBBox[2], topDict.fontBBox[3]);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ buf = GString::format("/StrokeWidth {0:.4g} def\n", topDict.strokeWidth);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ if (topDict.uniqueID != 0) {
+ buf = GString::format("/UniqueID {0:d} def\n", topDict.uniqueID);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+
+ // write the encoding
+ (*outputFunc)(outputStream, "/Encoding ", 10);
+ if (!newEncoding && encoding == fofiType1StandardEncoding) {
+ (*outputFunc)(outputStream, "StandardEncoding def\n", 21);
+ } else {
+ (*outputFunc)(outputStream, "256 array\n", 10);
+ (*outputFunc)(outputStream,
+ "0 1 255 {1 index exch /.notdef put} for\n", 40);
+ enc = newEncoding ? newEncoding : encoding;
+ for (i = 0; i < 256; ++i) {
+ if (enc[i]) {
+ buf = GString::format("dup {0:d} /{1:s} put\n", i, enc[i]);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ }
+ (*outputFunc)(outputStream, "readonly def\n", 13);
+ }
+ (*outputFunc)(outputStream, "currentdict end\n", 16);
+
+ // start the binary section
+ (*outputFunc)(outputStream, "currentfile eexec\n", 18);
+ eb.outputFunc = outputFunc;
+ eb.outputStream = outputStream;
+ eb.ascii = ascii;
+ eb.r1 = 55665;
+ eb.line = 0;
+
+ // write the private dictionary
+ eexecWrite(&eb, "\x83\xca\x73\xd5");
+ eexecWrite(&eb, "dup /Private 32 dict dup begin\n");
+ eexecWrite(&eb, "/RD {string currentfile exch readstring pop}"
+ " executeonly def\n");
+ eexecWrite(&eb, "/ND {noaccess def} executeonly def\n");
+ eexecWrite(&eb, "/NP {noaccess put} executeonly def\n");
+ eexecWrite(&eb, "/MinFeature {16 16} def\n");
+ eexecWrite(&eb, "/password 5839 def\n");
+ if (privateDicts[0].nBlueValues) {
+ eexecWrite(&eb, "/BlueValues [");
+ for (i = 0; i < privateDicts[0].nBlueValues; ++i) {
+ buf = GString::format("{0:s}{1:d}",
+ i > 0 ? " " : "", privateDicts[0].blueValues[i]);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ eexecWrite(&eb, "] def\n");
+ }
+ if (privateDicts[0].nOtherBlues) {
+ eexecWrite(&eb, "/OtherBlues [");
+ for (i = 0; i < privateDicts[0].nOtherBlues; ++i) {
+ buf = GString::format("{0:s}{1:d}",
+ i > 0 ? " " : "", privateDicts[0].otherBlues[i]);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ eexecWrite(&eb, "] def\n");
+ }
+ if (privateDicts[0].nFamilyBlues) {
+ eexecWrite(&eb, "/FamilyBlues [");
+ for (i = 0; i < privateDicts[0].nFamilyBlues; ++i) {
+ buf = GString::format("{0:s}{1:d}",
+ i > 0 ? " " : "", privateDicts[0].familyBlues[i]);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ eexecWrite(&eb, "] def\n");
+ }
+ if (privateDicts[0].nFamilyOtherBlues) {
+ eexecWrite(&eb, "/FamilyOtherBlues [");
+ for (i = 0; i < privateDicts[0].nFamilyOtherBlues; ++i) {
+ buf = GString::format("{0:s}{1:d}", i > 0 ? " " : "",
+ privateDicts[0].familyOtherBlues[i]);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ eexecWrite(&eb, "] def\n");
+ }
+ if (privateDicts[0].blueScale != 0.039625) {
+ buf = GString::format("/BlueScale {0:.4g} def\n",
+ privateDicts[0].blueScale);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ if (privateDicts[0].blueShift != 7) {
+ buf = GString::format("/BlueShift {0:d} def\n", privateDicts[0].blueShift);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ if (privateDicts[0].blueFuzz != 1) {
+ buf = GString::format("/BlueFuzz {0:d} def\n", privateDicts[0].blueFuzz);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ if (privateDicts[0].hasStdHW) {
+ buf = GString::format("/StdHW [{0:.4g}] def\n", privateDicts[0].stdHW);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ if (privateDicts[0].hasStdVW) {
+ buf = GString::format("/StdVW [{0:.4g}] def\n", privateDicts[0].stdVW);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ if (privateDicts[0].nStemSnapH) {
+ eexecWrite(&eb, "/StemSnapH [");
+ for (i = 0; i < privateDicts[0].nStemSnapH; ++i) {
+ buf = GString::format("{0:s}{1:.4g}",
+ i > 0 ? " " : "", privateDicts[0].stemSnapH[i]);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ eexecWrite(&eb, "] def\n");
+ }
+ if (privateDicts[0].nStemSnapV) {
+ eexecWrite(&eb, "/StemSnapV [");
+ for (i = 0; i < privateDicts[0].nStemSnapV; ++i) {
+ buf = GString::format("{0:s}{1:.4g}",
+ i > 0 ? " " : "", privateDicts[0].stemSnapV[i]);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ eexecWrite(&eb, "] def\n");
+ }
+ if (privateDicts[0].hasForceBold) {
+ buf = GString::format("/ForceBold {0:s} def\n",
+ privateDicts[0].forceBold ? "true" : "false");
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ if (privateDicts[0].forceBoldThreshold != 0) {
+ buf = GString::format("/ForceBoldThreshold {0:.4g} def\n",
+ privateDicts[0].forceBoldThreshold);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ if (privateDicts[0].languageGroup != 0) {
+ buf = GString::format("/LanguageGroup {0:d} def\n",
+ privateDicts[0].languageGroup);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ if (privateDicts[0].expansionFactor != 0.06) {
+ buf = GString::format("/ExpansionFactor {0:.4g} def\n",
+ privateDicts[0].expansionFactor);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+
+ // set up subroutines
+ ok = gTrue;
+ getIndex(privateDicts[0].subrsOffset, &subrIdx, &ok);
+ if (!ok) {
+ subrIdx.pos = -1;
+ }
+
+ // write the CharStrings
+ buf = GString::format("2 index /CharStrings {0:d} dict dup begin\n",
+ nGlyphs);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ for (i = 0; i < nGlyphs; ++i) {
+ ok = gTrue;
+ getIndexVal(&charStringsIdx, i, &val, &ok);
+ if (ok) {
+ getString(charset[i], buf2, &ok);
+ if (ok) {
+ eexecCvtGlyph(&eb, buf2, val.pos, val.len, &subrIdx, &privateDicts[0]);
+ }
+ }
+ }
+ eexecWrite(&eb, "end\n");
+ eexecWrite(&eb, "end\n");
+ eexecWrite(&eb, "readonly put\n");
+ eexecWrite(&eb, "noaccess put\n");
+ eexecWrite(&eb, "dup /FontName get exch definefont pop\n");
+ eexecWrite(&eb, "mark currentfile closefile\n");
+
+ // trailer
+ if (ascii && eb.line > 0) {
+ (*outputFunc)(outputStream, "\n", 1);
+ }
+ for (i = 0; i < 8; ++i) {
+ (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65);
+ }
+ (*outputFunc)(outputStream, "cleartomark\n", 12);
+}
+
+void FoFiType1C::convertToCIDType0(char *psName,
+ FoFiOutputFunc outputFunc,
+ void *outputStream) {
+ int *cidMap;
+ GString *charStrings;
+ int *charStringOffsets;
+ Type1CIndex subrIdx;
+ Type1CIndexVal val;
+ int nCIDs, gdBytes;
+ GString *buf;
+ char buf2[256];
+ GBool ok;
+ int gid, offset, n, i, j, k;
+
+ // compute the CID count and build the CID-to-GID mapping
+ nCIDs = 0;
+ for (i = 0; i < nGlyphs; ++i) {
+ if (charset[i] >= nCIDs) {
+ nCIDs = charset[i] + 1;
+ }
+ }
+ cidMap = (int *)gmallocn(nCIDs, sizeof(int));
+ for (i = 0; i < nCIDs; ++i) {
+ cidMap[i] = -1;
+ }
+ for (i = 0; i < nGlyphs; ++i) {
+ cidMap[charset[i]] = i;
+ }
+
+ // build the charstrings
+ charStrings = new GString();
+ charStringOffsets = (int *)gmallocn(nCIDs + 1, sizeof(int));
+ for (i = 0; i < nCIDs; ++i) {
+ charStringOffsets[i] = charStrings->getLength();
+ if ((gid = cidMap[i]) >= 0) {
+ ok = gTrue;
+ getIndexVal(&charStringsIdx, gid, &val, &ok);
+ if (ok) {
+ getIndex(privateDicts[fdSelect[gid]].subrsOffset, &subrIdx, &ok);
+ if (!ok) {
+ subrIdx.pos = -1;
+ }
+ cvtGlyph(val.pos, val.len, charStrings,
+ &subrIdx, &privateDicts[fdSelect[gid]], gTrue);
+ }
+ }
+ }
+ charStringOffsets[nCIDs] = charStrings->getLength();
+
+ // compute gdBytes = number of bytes needed for charstring offsets
+ // (offset size needs to account for the charstring offset table,
+ // with a worst case of five bytes per entry, plus the charstrings
+ // themselves)
+ i = (nCIDs + 1) * 5 + charStrings->getLength();
+ if (i < 0x100) {
+ gdBytes = 1;
+ } else if (i < 0x10000) {
+ gdBytes = 2;
+ } else if (i < 0x1000000) {
+ gdBytes = 3;
+ } else {
+ gdBytes = 4;
+ }
+
+ // begin the font dictionary
+ (*outputFunc)(outputStream, "/CIDInit /ProcSet findresource begin\n", 37);
+ (*outputFunc)(outputStream, "20 dict begin\n", 14);
+ (*outputFunc)(outputStream, "/CIDFontName /", 14);
+ (*outputFunc)(outputStream, psName, strlen(psName));
+ (*outputFunc)(outputStream, " def\n", 5);
+ (*outputFunc)(outputStream, "/CIDFontType 0 def\n", 19);
+ (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32);
+ if (topDict.registrySID > 0 && topDict.orderingSID > 0) {
+ ok = gTrue;
+ getString(topDict.registrySID, buf2, &ok);
+ if (ok) {
+ (*outputFunc)(outputStream, " /Registry (", 13);
+ (*outputFunc)(outputStream, buf2, strlen(buf2));
+ (*outputFunc)(outputStream, ") def\n", 6);
+ }
+ ok = gTrue;
+ getString(topDict.orderingSID, buf2, &ok);
+ if (ok) {
+ (*outputFunc)(outputStream, " /Ordering (", 13);
+ (*outputFunc)(outputStream, buf2, strlen(buf2));
+ (*outputFunc)(outputStream, ") def\n", 6);
+ }
+ } else {
+ (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24);
+ (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27);
+ }
+ buf = GString::format(" /Supplement {0:d} def\n", topDict.supplement);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ (*outputFunc)(outputStream, "end def\n", 8);
+ if (topDict.hasFontMatrix) {
+ buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n",
+ topDict.fontMatrix[0], topDict.fontMatrix[1],
+ topDict.fontMatrix[2], topDict.fontMatrix[3],
+ topDict.fontMatrix[4], topDict.fontMatrix[5]);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ } else if (privateDicts[0].hasFontMatrix) {
+ (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+ } else {
+ (*outputFunc)(outputStream,
+ "/FontMatrix [0.001 0 0 0.001 0 0] def\n", 38);
+ }
+ buf = GString::format("/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] def\n",
+ topDict.fontBBox[0], topDict.fontBBox[1],
+ topDict.fontBBox[2], topDict.fontBBox[3]);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ (*outputFunc)(outputStream, "/FontInfo 1 dict dup begin\n", 27);
+ (*outputFunc)(outputStream, " /FSType 8 def\n", 16);
+ (*outputFunc)(outputStream, "end def\n", 8);
+
+ // CIDFont-specific entries
+ buf = GString::format("/CIDCount {0:d} def\n", nCIDs);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ (*outputFunc)(outputStream, "/FDBytes 1 def\n", 15);
+ buf = GString::format("/GDBytes {0:d} def\n", gdBytes);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ (*outputFunc)(outputStream, "/CIDMapOffset 0 def\n", 20);
+ if (topDict.paintType != 0) {
+ buf = GString::format("/PaintType {0:d} def\n", topDict.paintType);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ buf = GString::format("/StrokeWidth {0:.4g} def\n", topDict.strokeWidth);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+
+ // FDArray entry
+ buf = GString::format("/FDArray {0:d} array\n", nFDs);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ for (i = 0; i < nFDs; ++i) {
+ buf = GString::format("dup {0:d} 10 dict begin\n", i);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ (*outputFunc)(outputStream, "/FontType 1 def\n", 16);
+ if (privateDicts[i].hasFontMatrix) {
+ buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n",
+ privateDicts[i].fontMatrix[0],
+ privateDicts[i].fontMatrix[1],
+ privateDicts[i].fontMatrix[2],
+ privateDicts[i].fontMatrix[3],
+ privateDicts[i].fontMatrix[4],
+ privateDicts[i].fontMatrix[5]);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ } else {
+ (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+ }
+ buf = GString::format("/PaintType {0:d} def\n", topDict.paintType);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ (*outputFunc)(outputStream, "/Private 32 dict begin\n", 23);
+ if (privateDicts[i].nBlueValues) {
+ (*outputFunc)(outputStream, "/BlueValues [", 13);
+ for (j = 0; j < privateDicts[i].nBlueValues; ++j) {
+ buf = GString::format("{0:s}{1:d}",
+ j > 0 ? " " : "", privateDicts[i].blueValues[j]);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ (*outputFunc)(outputStream, "] def\n", 6);
+ }
+ if (privateDicts[i].nOtherBlues) {
+ (*outputFunc)(outputStream, "/OtherBlues [", 13);
+ for (j = 0; j < privateDicts[i].nOtherBlues; ++j) {
+ buf = GString::format("{0:s}{1:d}",
+ j > 0 ? " " : "", privateDicts[i].otherBlues[j]);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ (*outputFunc)(outputStream, "] def\n", 6);
+ }
+ if (privateDicts[i].nFamilyBlues) {
+ (*outputFunc)(outputStream, "/FamilyBlues [", 14);
+ for (j = 0; j < privateDicts[i].nFamilyBlues; ++j) {
+ buf = GString::format("{0:s}{1:d}",
+ j > 0 ? " " : "",
+ privateDicts[i].familyBlues[j]);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ (*outputFunc)(outputStream, "] def\n", 6);
+ }
+ if (privateDicts[i].nFamilyOtherBlues) {
+ (*outputFunc)(outputStream, "/FamilyOtherBlues [", 19);
+ for (j = 0; j < privateDicts[i].nFamilyOtherBlues; ++j) {
+ buf = GString::format("{0:s}{1:d}", j > 0 ? " " : "",
+ privateDicts[i].familyOtherBlues[j]);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ (*outputFunc)(outputStream, "] def\n", 6);
+ }
+ if (privateDicts[i].blueScale != 0.039625) {
+ buf = GString::format("/BlueScale {0:.4g} def\n",
+ privateDicts[i].blueScale);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ if (privateDicts[i].blueShift != 7) {
+ buf = GString::format("/BlueShift {0:d} def\n",
+ privateDicts[i].blueShift);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ if (privateDicts[i].blueFuzz != 1) {
+ buf = GString::format("/BlueFuzz {0:d} def\n", privateDicts[i].blueFuzz);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ if (privateDicts[i].hasStdHW) {
+ buf = GString::format("/StdHW [{0:.4g}] def\n", privateDicts[i].stdHW);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ if (privateDicts[i].hasStdVW) {
+ buf = GString::format("/StdVW [{0:.4g}] def\n", privateDicts[i].stdVW);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ if (privateDicts[i].nStemSnapH) {
+ (*outputFunc)(outputStream, "/StemSnapH [", 12);
+ for (j = 0; j < privateDicts[i].nStemSnapH; ++j) {
+ buf = GString::format("{0:s}{1:.4g}",
+ j > 0 ? " " : "", privateDicts[i].stemSnapH[j]);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ (*outputFunc)(outputStream, "] def\n", 6);
+ }
+ if (privateDicts[i].nStemSnapV) {
+ (*outputFunc)(outputStream, "/StemSnapV [", 12);
+ for (j = 0; j < privateDicts[i].nStemSnapV; ++j) {
+ buf = GString::format("{0:s}{1:.4g}",
+ j > 0 ? " " : "", privateDicts[i].stemSnapV[j]);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ (*outputFunc)(outputStream, "] def\n", 6);
+ }
+ if (privateDicts[i].hasForceBold) {
+ buf = GString::format("/ForceBold {0:s} def\n",
+ privateDicts[i].forceBold ? "true" : "false");
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ if (privateDicts[i].forceBoldThreshold != 0) {
+ buf = GString::format("/ForceBoldThreshold {0:.4g} def\n",
+ privateDicts[i].forceBoldThreshold);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ if (privateDicts[i].languageGroup != 0) {
+ buf = GString::format("/LanguageGroup {0:d} def\n",
+ privateDicts[i].languageGroup);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ if (privateDicts[i].expansionFactor != 0.06) {
+ buf = GString::format("/ExpansionFactor {0:.4g} def\n",
+ privateDicts[i].expansionFactor);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ (*outputFunc)(outputStream, "currentdict end def\n", 20);
+ (*outputFunc)(outputStream, "currentdict end put\n", 20);
+ }
+ (*outputFunc)(outputStream, "def\n", 4);
+
+ // start the binary section
+ offset = (nCIDs + 1) * (1 + gdBytes);
+ buf = GString::format("(Hex) {0:d} StartData\n",
+ offset + charStrings->getLength());
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+
+ // write the charstring offset (CIDMap) table
+ for (i = 0; i <= nCIDs; i += 6) {
+ for (j = 0; j < 6 && i+j <= nCIDs; ++j) {
+ if (i+j < nCIDs && cidMap[i+j] >= 0) {
+ buf2[0] = (char)fdSelect[cidMap[i+j]];
+ } else {
+ buf2[0] = (char)0;
+ }
+ n = offset + charStringOffsets[i+j];
+ for (k = gdBytes; k >= 1; --k) {
+ buf2[k] = (char)(n & 0xff);
+ n >>= 8;
+ }
+ for (k = 0; k <= gdBytes; ++k) {
+ buf = GString::format("{0:02x}", buf2[k] & 0xff);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ }
+ (*outputFunc)(outputStream, "\n", 1);
+ }
+
+ // write the charstring data
+ n = charStrings->getLength();
+ for (i = 0; i < n; i += 32) {
+ for (j = 0; j < 32 && i+j < n; ++j) {
+ buf = GString::format("{0:02x}", charStrings->getChar(i+j) & 0xff);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ if (i + 32 >= n) {
+ (*outputFunc)(outputStream, ">", 1);
+ }
+ (*outputFunc)(outputStream, "\n", 1);
+ }
+
+ gfree(charStringOffsets);
+ delete charStrings;
+ gfree(cidMap);
+}
+
+void FoFiType1C::convertToType0(char *psName,
+ FoFiOutputFunc outputFunc,
+ void *outputStream) {
+ int *cidMap;
+ Type1CIndex subrIdx;
+ Type1CIndexVal val;
+ int nCIDs;
+ GString *buf;
+ Type1CEexecBuf eb;
+ GBool ok;
+ int fd, i, j, k;
+
+ // compute the CID count and build the CID-to-GID mapping
+ nCIDs = 0;
+ for (i = 0; i < nGlyphs; ++i) {
+ if (charset[i] >= nCIDs) {
+ nCIDs = charset[i] + 1;
+ }
+ }
+ cidMap = (int *)gmallocn(nCIDs, sizeof(int));
+ for (i = 0; i < nCIDs; ++i) {
+ cidMap[i] = -1;
+ }
+ for (i = 0; i < nGlyphs; ++i) {
+ cidMap[charset[i]] = i;
+ }
+
+ // write the descendant Type 1 fonts
+ for (i = 0; i < nCIDs; i += 256) {
+
+ //~ this assumes that all CIDs in this block have the same FD --
+ //~ to handle multiple FDs correctly, need to somehow divide the
+ //~ font up by FD; as a kludge we ignore CID 0, which is .notdef
+ fd = 0;
+ for (j = i==0 ? 1 : 0; j < 256 && i+j < nCIDs; ++j) {
+ if (cidMap[i+j] >= 0) {
+ fd = fdSelect[cidMap[i+j]];
+ break;
+ }
+ }
+
+ // font dictionary (unencrypted section)
+ (*outputFunc)(outputStream, "16 dict begin\n", 14);
+ (*outputFunc)(outputStream, "/FontName /", 11);
+ (*outputFunc)(outputStream, psName, strlen(psName));
+ buf = GString::format("_{0:02x} def\n", i >> 8);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ (*outputFunc)(outputStream, "/FontType 1 def\n", 16);
+ if (privateDicts[fd].hasFontMatrix) {
+ buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n",
+ privateDicts[fd].fontMatrix[0],
+ privateDicts[fd].fontMatrix[1],
+ privateDicts[fd].fontMatrix[2],
+ privateDicts[fd].fontMatrix[3],
+ privateDicts[fd].fontMatrix[4],
+ privateDicts[fd].fontMatrix[5]);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ } else if (topDict.hasFontMatrix) {
+ (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+ } else {
+ (*outputFunc)(outputStream,
+ "/FontMatrix [0.001 0 0 0.001 0 0] def\n", 38);
+ }
+ buf = GString::format("/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] def\n",
+ topDict.fontBBox[0], topDict.fontBBox[1],
+ topDict.fontBBox[2], topDict.fontBBox[3]);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ buf = GString::format("/PaintType {0:d} def\n", topDict.paintType);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ if (topDict.paintType != 0) {
+ buf = GString::format("/StrokeWidth {0:.4g} def\n", topDict.strokeWidth);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
+ for (j = 0; j < 256 && i+j < nCIDs; ++j) {
+ buf = GString::format("dup {0:d} /c{1:02x} put\n", j, j);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ if (j < 256) {
+ buf = GString::format("{0:d} 1 255 {{ 1 index exch /.notdef put }} for\n",
+ j);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ (*outputFunc)(outputStream, "readonly def\n", 13);
+ (*outputFunc)(outputStream, "currentdict end\n", 16);
+
+ // start the binary section
+ (*outputFunc)(outputStream, "currentfile eexec\n", 18);
+ eb.outputFunc = outputFunc;
+ eb.outputStream = outputStream;
+ eb.ascii = gTrue;
+ eb.r1 = 55665;
+ eb.line = 0;
+
+ // start the private dictionary
+ eexecWrite(&eb, "\x83\xca\x73\xd5");
+ eexecWrite(&eb, "dup /Private 32 dict dup begin\n");
+ eexecWrite(&eb, "/RD {string currentfile exch readstring pop}"
+ " executeonly def\n");
+ eexecWrite(&eb, "/ND {noaccess def} executeonly def\n");
+ eexecWrite(&eb, "/NP {noaccess put} executeonly def\n");
+ eexecWrite(&eb, "/MinFeature {16 16} def\n");
+ eexecWrite(&eb, "/password 5839 def\n");
+ if (privateDicts[fd].nBlueValues) {
+ eexecWrite(&eb, "/BlueValues [");
+ for (k = 0; k < privateDicts[fd].nBlueValues; ++k) {
+ buf = GString::format("{0:s}{1:d}",
+ k > 0 ? " " : "",
+ privateDicts[fd].blueValues[k]);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ eexecWrite(&eb, "] def\n");
+ }
+ if (privateDicts[fd].nOtherBlues) {
+ eexecWrite(&eb, "/OtherBlues [");
+ for (k = 0; k < privateDicts[fd].nOtherBlues; ++k) {
+ buf = GString::format("{0:s}{1:d}",
+ k > 0 ? " " : "",
+ privateDicts[fd].otherBlues[k]);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ eexecWrite(&eb, "] def\n");
+ }
+ if (privateDicts[fd].nFamilyBlues) {
+ eexecWrite(&eb, "/FamilyBlues [");
+ for (k = 0; k < privateDicts[fd].nFamilyBlues; ++k) {
+ buf = GString::format("{0:s}{1:d}", k > 0 ? " " : "",
+ privateDicts[fd].familyBlues[k]);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ eexecWrite(&eb, "] def\n");
+ }
+ if (privateDicts[fd].nFamilyOtherBlues) {
+ eexecWrite(&eb, "/FamilyOtherBlues [");
+ for (k = 0; k < privateDicts[fd].nFamilyOtherBlues; ++k) {
+ buf = GString::format("{0:s}{1:d}", k > 0 ? " " : "",
+ privateDicts[fd].familyOtherBlues[k]);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ eexecWrite(&eb, "] def\n");
+ }
+ if (privateDicts[fd].blueScale != 0.039625) {
+ buf = GString::format("/BlueScale {0:.4g} def\n",
+ privateDicts[fd].blueScale);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ if (privateDicts[fd].blueShift != 7) {
+ buf = GString::format("/BlueShift {0:d} def\n",
+ privateDicts[fd].blueShift);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ if (privateDicts[fd].blueFuzz != 1) {
+ buf = GString::format("/BlueFuzz {0:d} def\n",
+ privateDicts[fd].blueFuzz);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ if (privateDicts[fd].hasStdHW) {
+ buf = GString::format("/StdHW [{0:.4g}] def\n", privateDicts[fd].stdHW);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ if (privateDicts[fd].hasStdVW) {
+ buf = GString::format("/StdVW [{0:.4g}] def\n", privateDicts[fd].stdVW);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ if (privateDicts[fd].nStemSnapH) {
+ eexecWrite(&eb, "/StemSnapH [");
+ for (k = 0; k < privateDicts[fd].nStemSnapH; ++k) {
+ buf = GString::format("{0:s}{1:.4g}",
+ k > 0 ? " " : "", privateDicts[fd].stemSnapH[k]);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ eexecWrite(&eb, "] def\n");
+ }
+ if (privateDicts[fd].nStemSnapV) {
+ eexecWrite(&eb, "/StemSnapV [");
+ for (k = 0; k < privateDicts[fd].nStemSnapV; ++k) {
+ buf = GString::format("{0:s}{1:.4g}",
+ k > 0 ? " " : "", privateDicts[fd].stemSnapV[k]);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ eexecWrite(&eb, "] def\n");
+ }
+ if (privateDicts[fd].hasForceBold) {
+ buf = GString::format("/ForceBold {0:s} def\n",
+ privateDicts[fd].forceBold ? "true" : "false");
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ if (privateDicts[fd].forceBoldThreshold != 0) {
+ buf = GString::format("/ForceBoldThreshold {0:.4g} def\n",
+ privateDicts[fd].forceBoldThreshold);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ if (privateDicts[fd].languageGroup != 0) {
+ buf = GString::format("/LanguageGroup {0:d} def\n",
+ privateDicts[fd].languageGroup);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ if (privateDicts[fd].expansionFactor != 0.06) {
+ buf = GString::format("/ExpansionFactor {0:.4g} def\n",
+ privateDicts[fd].expansionFactor);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+
+ // set up the subroutines
+ ok = gTrue;
+ getIndex(privateDicts[fd].subrsOffset, &subrIdx, &ok);
+ if (!ok) {
+ subrIdx.pos = -1;
+ }
+
+ // start the CharStrings
+ eexecWrite(&eb, "2 index /CharStrings 256 dict dup begin\n");
+
+ // write the .notdef CharString
+ ok = gTrue;
+ getIndexVal(&charStringsIdx, 0, &val, &ok);
+ if (ok) {
+ eexecCvtGlyph(&eb, ".notdef", val.pos, val.len,
+ &subrIdx, &privateDicts[fd]);
+ }
+
+ // write the CharStrings
+ for (j = 0; j < 256 && i+j < nCIDs; ++j) {
+ if (cidMap[i+j] >= 0) {
+ ok = gTrue;
+ getIndexVal(&charStringsIdx, cidMap[i+j], &val, &ok);
+ if (ok) {
+ buf = GString::format("c{0:02x}", j);
+ eexecCvtGlyph(&eb, buf->getCString(), val.pos, val.len,
+ &subrIdx, &privateDicts[fd]);
+ delete buf;
+ }
+ }
+ }
+ eexecWrite(&eb, "end\n");
+ eexecWrite(&eb, "end\n");
+ eexecWrite(&eb, "readonly put\n");
+ eexecWrite(&eb, "noaccess put\n");
+ eexecWrite(&eb, "dup /FontName get exch definefont pop\n");
+ eexecWrite(&eb, "mark currentfile closefile\n");
+
+ // trailer
+ if (eb.line > 0) {
+ (*outputFunc)(outputStream, "\n", 1);
+ }
+ for (j = 0; j < 8; ++j) {
+ (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65);
+ }
+ (*outputFunc)(outputStream, "cleartomark\n", 12);
+ }
+
+ // write the Type 0 parent font
+ (*outputFunc)(outputStream, "16 dict begin\n", 14);
+ (*outputFunc)(outputStream, "/FontName /", 11);
+ (*outputFunc)(outputStream, psName, strlen(psName));
+ (*outputFunc)(outputStream, " def\n", 5);
+ (*outputFunc)(outputStream, "/FontType 0 def\n", 16);
+ if (topDict.hasFontMatrix) {
+ buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n",
+ topDict.fontMatrix[0], topDict.fontMatrix[1],
+ topDict.fontMatrix[2], topDict.fontMatrix[3],
+ topDict.fontMatrix[4], topDict.fontMatrix[5]);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ } else {
+ (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+ }
+ (*outputFunc)(outputStream, "/FMapType 2 def\n", 16);
+ (*outputFunc)(outputStream, "/Encoding [\n", 12);
+ for (i = 0; i < nCIDs; i += 256) {
+ buf = GString::format("{0:d}\n", i >> 8);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ (*outputFunc)(outputStream, "] def\n", 6);
+ (*outputFunc)(outputStream, "/FDepVector [\n", 14);
+ for (i = 0; i < nCIDs; i += 256) {
+ (*outputFunc)(outputStream, "/", 1);
+ (*outputFunc)(outputStream, psName, strlen(psName));
+ buf = GString::format("_{0:02x} findfont\n", i >> 8);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ (*outputFunc)(outputStream, "] def\n", 6);
+ (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
+
+ gfree(cidMap);
+}
+
+void FoFiType1C::eexecCvtGlyph(Type1CEexecBuf *eb, char *glyphName,
+ int offset, int nBytes,
+ Type1CIndex *subrIdx,
+ Type1CPrivateDict *pDict) {
+ GString *buf;
+ GString *charBuf;
+
+ // generate the charstring
+ charBuf = new GString();
+ cvtGlyph(offset, nBytes, charBuf, subrIdx, pDict, gTrue);
+
+ buf = GString::format("/{0:s} {1:d} RD ", glyphName, charBuf->getLength());
+ eexecWrite(eb, buf->getCString());
+ delete buf;
+ eexecWriteCharstring(eb, (Guchar *)charBuf->getCString(),
+ charBuf->getLength());
+ eexecWrite(eb, " ND\n");
+
+ delete charBuf;
+}
+
+void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf,
+ Type1CIndex *subrIdx, Type1CPrivateDict *pDict,
+ GBool top) {
+ Type1CIndexVal val;
+ GBool ok, dFP;
+ double d, dx, dy;
+ Gushort r2;
+ Guchar byte;
+ int pos, subrBias, start, i, k;
+
+ start = charBuf->getLength();
+ if (top) {
+ charBuf->append((char)73);
+ charBuf->append((char)58);
+ charBuf->append((char)147);
+ charBuf->append((char)134);
+ nOps = 0;
+ nHints = 0;
+ firstOp = gTrue;
+ openPath = gFalse;
+ }
+
+ pos = offset;
+ while (pos < offset + nBytes) {
+ ok = gTrue;
+ pos = getOp(pos, gTrue, &ok);
+ if (!ok) {
+ break;
+ }
+ if (!ops[nOps - 1].isNum) {
+ --nOps; // drop the operator
+ switch (ops[nOps].op) {
+ case 0x0001: // hstem
+ if (firstOp) {
+ cvtGlyphWidth(nOps & 1, charBuf, pDict);
+ firstOp = gFalse;
+ }
+ if (nOps & 1) {
+ //~ error(-1, "Wrong number of args (%d) to Type 2 hstem", nOps);
+ }
+ d = 0;
+ dFP = gFalse;
+ for (k = 0; k < nOps; k += 2) {
+ // convert Type 2 edge hints (-20 or -21) to Type 1 ghost hints
+ if (ops[k+1].num < 0) {
+ d += ops[k].num + ops[k+1].num;
+ dFP |= ops[k].isFP | ops[k+1].isFP;
+ cvtNum(d, dFP, charBuf);
+ cvtNum(-ops[k+1].num, ops[k+1].isFP, charBuf);
+ } else {
+ d += ops[k].num;
+ dFP |= ops[k].isFP;
+ cvtNum(d, dFP, charBuf);
+ cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf);
+ d += ops[k+1].num;
+ dFP |= ops[k+1].isFP;
+ }
+ charBuf->append((char)1);
+ }
+ nHints += nOps / 2;
+ nOps = 0;
+ break;
+ case 0x0003: // vstem
+ if (firstOp) {
+ cvtGlyphWidth(nOps & 1, charBuf, pDict);
+ firstOp = gFalse;
+ }
+ if (nOps & 1) {
+ //~ error(-1, "Wrong number of args (%d) to Type 2 vstem", nOps);
+ }
+ d = 0;
+ dFP = gFalse;
+ for (k = 0; k < nOps; k += 2) {
+ // convert Type 2 edge hints (-20 or -21) to Type 1 ghost hints
+ if (ops[k+1].num < 0) {
+ d += ops[k].num + ops[k+1].num;
+ dFP |= ops[k].isFP | ops[k+1].isFP;
+ cvtNum(d, dFP, charBuf);
+ cvtNum(-ops[k+1].num, ops[k+1].isFP, charBuf);
+ } else {
+ d += ops[k].num;
+ dFP |= ops[k].isFP;
+ cvtNum(d, dFP, charBuf);
+ cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf);
+ d += ops[k+1].num;
+ dFP |= ops[k+1].isFP;
+ }
+ charBuf->append((char)3);
+ }
+ nHints += nOps / 2;
+ nOps = 0;
+ break;
+ case 0x0004: // vmoveto
+ if (firstOp) {
+ cvtGlyphWidth(nOps == 2, charBuf, pDict);
+ firstOp = gFalse;
+ }
+ if (openPath) {
+ charBuf->append((char)9);
+ openPath = gFalse;
+ }
+ if (nOps != 1) {
+ //~ error(-1, "Wrong number of args (%d) to Type 2 vmoveto", nOps);
+ }
+ cvtNum(ops[0].num, ops[0].isFP, charBuf);
+ charBuf->append((char)4);
+ nOps = 0;
+ break;
+ case 0x0005: // rlineto
+ if (nOps < 2 || nOps % 2 != 0) {
+ //~ error(-1, "Wrong number of args (%d) to Type 2 rlineto", nOps);
+ }
+ for (k = 0; k < nOps; k += 2) {
+ cvtNum(ops[k].num, ops[k].isFP, charBuf);
+ cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf);
+ charBuf->append((char)5);
+ }
+ nOps = 0;
+ openPath = gTrue;
+ break;
+ case 0x0006: // hlineto
+ if (nOps < 1) {
+ //~ error(-1, "Wrong number of args (%d) to Type 2 hlineto", nOps);
+ }
+ for (k = 0; k < nOps; ++k) {
+ cvtNum(ops[k].num, ops[k].isFP, charBuf);
+ charBuf->append((char)((k & 1) ? 7 : 6));
+ }
+ nOps = 0;
+ openPath = gTrue;
+ break;
+ case 0x0007: // vlineto
+ if (nOps < 1) {
+ //~ error(-1, "Wrong number of args (%d) to Type 2 vlineto", nOps);
+ }
+ for (k = 0; k < nOps; ++k) {
+ cvtNum(ops[k].num, ops[k].isFP, charBuf);
+ charBuf->append((char)((k & 1) ? 6 : 7));
+ }
+ nOps = 0;
+ openPath = gTrue;
+ break;
+ case 0x0008: // rrcurveto
+ if (nOps < 6 || nOps % 6 != 0) {
+ //~ error(-1, "Wrong number of args (%d) to Type 2 rrcurveto", nOps);
+ }
+ for (k = 0; k < nOps; k += 6) {
+ cvtNum(ops[k].num, ops[k].isFP, charBuf);
+ cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf);
+ cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf);
+ cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf);
+ cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf);
+ cvtNum(ops[k+5].num, ops[k+5].isFP, charBuf);
+ charBuf->append((char)8);
+ }
+ nOps = 0;
+ openPath = gTrue;
+ break;
+ case 0x000a: // callsubr
+ if (nOps >= 1) {
+ subrBias = (subrIdx->len < 1240)
+ ? 107 : (subrIdx->len < 33900) ? 1131 : 32768;
+ k = subrBias + (int)ops[nOps - 1].num;
+ --nOps;
+ ok = gTrue;
+ getIndexVal(subrIdx, k, &val, &ok);
+ if (ok) {
+ cvtGlyph(val.pos, val.len, charBuf, subrIdx, pDict, gFalse);
+ }
+ } else {
+ //~ error(-1, "Too few args to Type 2 callsubr");
+ }
+ // don't clear the stack
+ break;
+ case 0x000b: // return
+ // don't clear the stack
+ break;
+ case 0x000e: // endchar / seac
+ if (firstOp) {
+ cvtGlyphWidth(nOps == 1 || nOps == 5, charBuf, pDict);
+ firstOp = gFalse;
+ }
+ if (openPath) {
+ charBuf->append((char)9);
+ openPath = gFalse;
+ }
+ if (nOps == 4) {
+ cvtNum(0, gFalse, charBuf);
+ cvtNum(ops[0].num, ops[0].isFP, charBuf);
+ cvtNum(ops[1].num, ops[1].isFP, charBuf);
+ cvtNum(ops[2].num, ops[2].isFP, charBuf);
+ cvtNum(ops[3].num, ops[3].isFP, charBuf);
+ charBuf->append((char)12)->append((char)6);
+ } else if (nOps == 0) {
+ charBuf->append((char)14);
+ } else {
+ //~ error(-1, "Wrong number of args (%d) to Type 2 endchar", nOps);
+ }
+ nOps = 0;
+ break;
+ case 0x000f: // (obsolete)
+ // this op is ignored, but we need the glyph width
+ if (firstOp) {
+ cvtGlyphWidth(nOps > 0, charBuf, pDict);
+ firstOp = gFalse;
+ }
+ nOps = 0;
+ break;
+ case 0x0010: // blend
+ //~ error(-1, "Unimplemented Type 2 charstring op: %d", file[i]);
+ nOps = 0;
+ break;
+ case 0x0012: // hstemhm
+ // ignored
+ if (firstOp) {
+ cvtGlyphWidth(nOps & 1, charBuf, pDict);
+ firstOp = gFalse;
+ }
+ if (nOps & 1) {
+ //~ error(-1, "Wrong number of args (%d) to Type 2 hstemhm", nOps);
+ }
+ nHints += nOps / 2;
+ nOps = 0;
+ break;
+ case 0x0013: // hintmask
+ // ignored
+ if (firstOp) {
+ cvtGlyphWidth(nOps & 1, charBuf, pDict);
+ firstOp = gFalse;
+ }
+ if (nOps > 0) {
+ if (nOps & 1) {
+ //~ error(-1, "Wrong number of args (%d) to Type 2 hintmask/vstemhm",
+ //~ nOps);
+ }
+ nHints += nOps / 2;
+ }
+ pos += (nHints + 7) >> 3;
+ nOps = 0;
+ break;
+ case 0x0014: // cntrmask
+ // ignored
+ if (firstOp) {
+ cvtGlyphWidth(nOps & 1, charBuf, pDict);
+ firstOp = gFalse;
+ }
+ if (nOps > 0) {
+ if (nOps & 1) {
+ //~ error(-1, "Wrong number of args (%d) to Type 2 cntrmask/vstemhm",
+ //~ nOps);
+ }
+ nHints += nOps / 2;
+ }
+ pos += (nHints + 7) >> 3;
+ nOps = 0;
+ break;
+ case 0x0015: // rmoveto
+ if (firstOp) {
+ cvtGlyphWidth(nOps == 3, charBuf, pDict);
+ firstOp = gFalse;
+ }
+ if (openPath) {
+ charBuf->append((char)9);
+ openPath = gFalse;
+ }
+ if (nOps != 2) {
+ //~ error(-1, "Wrong number of args (%d) to Type 2 rmoveto", nOps);
+ }
+ cvtNum(ops[0].num, ops[0].isFP, charBuf);
+ cvtNum(ops[1].num, ops[1].isFP, charBuf);
+ charBuf->append((char)21);
+ nOps = 0;
+ break;
+ case 0x0016: // hmoveto
+ if (firstOp) {
+ cvtGlyphWidth(nOps == 2, charBuf, pDict);
+ firstOp = gFalse;
+ }
+ if (openPath) {
+ charBuf->append((char)9);
+ openPath = gFalse;
+ }
+ if (nOps != 1) {
+ //~ error(-1, "Wrong number of args (%d) to Type 2 hmoveto", nOps);
+ }
+ cvtNum(ops[0].num, ops[0].isFP, charBuf);
+ charBuf->append((char)22);
+ nOps = 0;
+ break;
+ case 0x0017: // vstemhm
+ // ignored
+ if (firstOp) {
+ cvtGlyphWidth(nOps & 1, charBuf, pDict);
+ firstOp = gFalse;
+ }
+ if (nOps & 1) {
+ //~ error(-1, "Wrong number of args (%d) to Type 2 vstemhm", nOps);
+ }
+ nHints += nOps / 2;
+ nOps = 0;
+ break;
+ case 0x0018: // rcurveline
+ if (nOps < 8 || (nOps - 2) % 6 != 0) {
+ //~ error(-1, "Wrong number of args (%d) to Type 2 rcurveline", nOps);
+ }
+ for (k = 0; k < nOps - 2; k += 6) {
+ cvtNum(ops[k].num, ops[k].isFP, charBuf);
+ cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf);
+ cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf);
+ cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf);
+ cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf);
+ cvtNum(ops[k+5].num, ops[k+5].isFP, charBuf);
+ charBuf->append((char)8);
+ }
+ cvtNum(ops[k].num, ops[k].isFP, charBuf);
+ cvtNum(ops[k+1].num, ops[k].isFP, charBuf);
+ charBuf->append((char)5);
+ nOps = 0;
+ openPath = gTrue;
+ break;
+ case 0x0019: // rlinecurve
+ if (nOps < 8 || (nOps - 6) % 2 != 0) {
+ //~ error(-1, "Wrong number of args (%d) to Type 2 rlinecurve", nOps);
+ }
+ for (k = 0; k < nOps - 6; k += 2) {
+ cvtNum(ops[k].num, ops[k].isFP, charBuf);
+ cvtNum(ops[k+1].num, ops[k].isFP, charBuf);
+ charBuf->append((char)5);
+ }
+ cvtNum(ops[k].num, ops[k].isFP, charBuf);
+ cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf);
+ cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf);
+ cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf);
+ cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf);
+ cvtNum(ops[k+5].num, ops[k+5].isFP, charBuf);
+ charBuf->append((char)8);
+ nOps = 0;
+ openPath = gTrue;
+ break;
+ case 0x001a: // vvcurveto
+ if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) {
+ //~ error(-1, "Wrong number of args (%d) to Type 2 vvcurveto", nOps);
+ }
+ if (nOps % 2 == 1) {
+ cvtNum(ops[0].num, ops[0].isFP, charBuf);
+ cvtNum(ops[1].num, ops[1].isFP, charBuf);
+ cvtNum(ops[2].num, ops[2].isFP, charBuf);
+ cvtNum(ops[3].num, ops[3].isFP, charBuf);
+ cvtNum(0, gFalse, charBuf);
+ cvtNum(ops[4].num, ops[4].isFP, charBuf);
+ charBuf->append((char)8);
+ k = 5;
+ } else {
+ k = 0;
+ }
+ for (; k < nOps; k += 4) {
+ cvtNum(0, gFalse, charBuf);
+ cvtNum(ops[k].num, ops[k].isFP, charBuf);
+ cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf);
+ cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf);
+ cvtNum(0, gFalse, charBuf);
+ cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf);
+ charBuf->append((char)8);
+ }
+ nOps = 0;
+ openPath = gTrue;
+ break;
+ case 0x001b: // hhcurveto
+ if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) {
+ //~ error(-1, "Wrong number of args (%d) to Type 2 hhcurveto", nOps);
+ }
+ if (nOps % 2 == 1) {
+ cvtNum(ops[1].num, ops[1].isFP, charBuf);
+ cvtNum(ops[0].num, ops[0].isFP, charBuf);
+ cvtNum(ops[2].num, ops[2].isFP, charBuf);
+ cvtNum(ops[3].num, ops[3].isFP, charBuf);
+ cvtNum(ops[4].num, ops[4].isFP, charBuf);
+ cvtNum(0, gFalse, charBuf);
+ charBuf->append((char)8);
+ k = 5;
+ } else {
+ k = 0;
+ }
+ for (; k < nOps; k += 4) {
+ cvtNum(ops[k].num, ops[k].isFP, charBuf);
+ cvtNum(0, gFalse, charBuf);
+ cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf);
+ cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf);
+ cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf);
+ cvtNum(0, gFalse, charBuf);
+ charBuf->append((char)8);
+ }
+ nOps = 0;
+ openPath = gTrue;
+ break;
+ case 0x001d: // callgsubr
+ if (nOps >= 1) {
+ k = gsubrBias + (int)ops[nOps - 1].num;
+ --nOps;
+ ok = gTrue;
+ getIndexVal(&gsubrIdx, k, &val, &ok);
+ if (ok) {
+ cvtGlyph(val.pos, val.len, charBuf, subrIdx, pDict, gFalse);
+ }
+ } else {
+ //~ error(-1, "Too few args to Type 2 callgsubr");
+ }
+ // don't clear the stack
+ break;
+ case 0x001e: // vhcurveto
+ if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) {
+ //~ error(-1, "Wrong number of args (%d) to Type 2 vhcurveto", nOps);
+ }
+ for (k = 0; k < nOps && k != nOps-5; k += 4) {
+ if (k % 8 == 0) {
+ cvtNum(ops[k].num, ops[k].isFP, charBuf);
+ cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf);
+ cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf);
+ cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf);
+ charBuf->append((char)30);
+ } else {
+ cvtNum(ops[k].num, ops[k].isFP, charBuf);
+ cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf);
+ cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf);
+ cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf);
+ charBuf->append((char)31);
+ }
+ }
+ if (k == nOps-5) {
+ if (k % 8 == 0) {
+ cvtNum(0, gFalse, charBuf);
+ cvtNum(ops[k].num, ops[k].isFP, charBuf);
+ cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf);
+ cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf);
+ cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf);
+ cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf);
+ } else {
+ cvtNum(ops[k].num, ops[k].isFP, charBuf);
+ cvtNum(0, gFalse, charBuf);
+ cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf);
+ cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf);
+ cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf);
+ cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf);
+ }
+ charBuf->append((char)8);
+ }
+ nOps = 0;
+ openPath = gTrue;
+ break;
+ case 0x001f: // hvcurveto
+ if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) {
+ //~ error(-1, "Wrong number of args (%d) to Type 2 hvcurveto", nOps);
+ }
+ for (k = 0; k < nOps && k != nOps-5; k += 4) {
+ if (k % 8 == 0) {
+ cvtNum(ops[k].num, ops[k].isFP, charBuf);
+ cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf);
+ cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf);
+ cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf);
+ charBuf->append((char)31);
+ } else {
+ cvtNum(ops[k].num, ops[k].isFP, charBuf);
+ cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf);
+ cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf);
+ cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf);
+ charBuf->append((char)30);
+ }
+ }
+ if (k == nOps-5) {
+ if (k % 8 == 0) {
+ cvtNum(ops[k].num, ops[k].isFP, charBuf);
+ cvtNum(0, gFalse, charBuf);
+ cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf);
+ cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf);
+ cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf);
+ cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf);
+ } else {
+ cvtNum(0, gFalse, charBuf);
+ cvtNum(ops[k].num, ops[k].isFP, charBuf);
+ cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf);
+ cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf);
+ cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf);
+ cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf);
+ }
+ charBuf->append((char)8);
+ }
+ nOps = 0;
+ openPath = gTrue;
+ break;
+ case 0x0c00: // dotsection (should be Type 1 only?)
+ // ignored
+ nOps = 0;
+ break;
+ case 0x0c03: // and
+ case 0x0c04: // or
+ case 0x0c05: // not
+ case 0x0c08: // store
+ case 0x0c09: // abs
+ case 0x0c0a: // add
+ case 0x0c0b: // sub
+ case 0x0c0c: // div
+ case 0x0c0d: // load
+ case 0x0c0e: // neg
+ case 0x0c0f: // eq
+ case 0x0c12: // drop
+ case 0x0c14: // put
+ case 0x0c15: // get
+ case 0x0c16: // ifelse
+ case 0x0c17: // random
+ case 0x0c18: // mul
+ case 0x0c1a: // sqrt
+ case 0x0c1b: // dup
+ case 0x0c1c: // exch
+ case 0x0c1d: // index
+ case 0x0c1e: // roll
+ //~ error(-1, "Unimplemented Type 2 charstring op: 12.%d", file[i+1]);
+ nOps = 0;
+ break;
+ case 0x0c22: // hflex
+ if (nOps != 7) {
+ //~ error(-1, "Wrong number of args (%d) to Type 2 hflex", nOps);
+ }
+ cvtNum(ops[0].num, ops[0].isFP, charBuf);
+ cvtNum(0, gFalse, charBuf);
+ cvtNum(ops[1].num, ops[1].isFP, charBuf);
+ cvtNum(ops[2].num, ops[2].isFP, charBuf);
+ cvtNum(ops[3].num, ops[3].isFP, charBuf);
+ cvtNum(0, gFalse, charBuf);
+ charBuf->append((char)8);
+ cvtNum(ops[4].num, ops[4].isFP, charBuf);
+ cvtNum(0, gFalse, charBuf);
+ cvtNum(ops[5].num, ops[5].isFP, charBuf);
+ cvtNum(-ops[2].num, ops[2].isFP, charBuf);
+ cvtNum(ops[6].num, ops[6].isFP, charBuf);
+ cvtNum(0, gFalse, charBuf);
+ charBuf->append((char)8);
+ nOps = 0;
+ openPath = gTrue;
+ break;
+ case 0x0c23: // flex
+ if (nOps != 13) {
+ //~ error(-1, "Wrong number of args (%d) to Type 2 flex", nOps);
+ }
+ cvtNum(ops[0].num, ops[0].isFP, charBuf);
+ cvtNum(ops[1].num, ops[1].isFP, charBuf);
+ cvtNum(ops[2].num, ops[2].isFP, charBuf);
+ cvtNum(ops[3].num, ops[3].isFP, charBuf);
+ cvtNum(ops[4].num, ops[4].isFP, charBuf);
+ cvtNum(ops[5].num, ops[5].isFP, charBuf);
+ charBuf->append((char)8);
+ cvtNum(ops[6].num, ops[6].isFP, charBuf);
+ cvtNum(ops[7].num, ops[7].isFP, charBuf);
+ cvtNum(ops[8].num, ops[8].isFP, charBuf);
+ cvtNum(ops[9].num, ops[9].isFP, charBuf);
+ cvtNum(ops[10].num, ops[10].isFP, charBuf);
+ cvtNum(ops[11].num, ops[11].isFP, charBuf);
+ charBuf->append((char)8);
+ nOps = 0;
+ openPath = gTrue;
+ break;
+ case 0x0c24: // hflex1
+ if (nOps != 9) {
+ //~ error(-1, "Wrong number of args (%d) to Type 2 hflex1", nOps);
+ }
+ cvtNum(ops[0].num, ops[0].isFP, charBuf);
+ cvtNum(ops[1].num, ops[1].isFP, charBuf);
+ cvtNum(ops[2].num, ops[2].isFP, charBuf);
+ cvtNum(ops[3].num, ops[3].isFP, charBuf);
+ cvtNum(ops[4].num, ops[4].isFP, charBuf);
+ cvtNum(0, gFalse, charBuf);
+ charBuf->append((char)8);
+ cvtNum(ops[5].num, ops[5].isFP, charBuf);
+ cvtNum(0, gFalse, charBuf);
+ cvtNum(ops[6].num, ops[6].isFP, charBuf);
+ cvtNum(ops[7].num, ops[7].isFP, charBuf);
+ cvtNum(ops[8].num, ops[8].isFP, charBuf);
+ cvtNum(-(ops[1].num + ops[3].num + ops[7].num),
+ ops[1].isFP | ops[3].isFP | ops[7].isFP, charBuf);
+ charBuf->append((char)8);
+ nOps = 0;
+ openPath = gTrue;
+ break;
+ case 0x0c25: // flex1
+ if (nOps != 11) {
+ //~ error(-1, "Wrong number of args (%d) to Type 2 flex1", nOps);
+ }
+ cvtNum(ops[0].num, ops[0].isFP, charBuf);
+ cvtNum(ops[1].num, ops[1].isFP, charBuf);
+ cvtNum(ops[2].num, ops[2].isFP, charBuf);
+ cvtNum(ops[3].num, ops[3].isFP, charBuf);
+ cvtNum(ops[4].num, ops[4].isFP, charBuf);
+ cvtNum(ops[5].num, ops[5].isFP, charBuf);
+ charBuf->append((char)8);
+ cvtNum(ops[6].num, ops[6].isFP, charBuf);
+ cvtNum(ops[7].num, ops[7].isFP, charBuf);
+ cvtNum(ops[8].num, ops[8].isFP, charBuf);
+ cvtNum(ops[9].num, ops[9].isFP, charBuf);
+ dx = ops[0].num + ops[2].num + ops[4].num + ops[6].num + ops[8].num;
+ dy = ops[1].num + ops[3].num + ops[5].num + ops[7].num + ops[9].num;
+ if (fabs(dx) > fabs(dy)) {
+ cvtNum(ops[10].num, ops[10].isFP, charBuf);
+ cvtNum(-dy, ops[1].isFP | ops[3].isFP | ops[5].isFP |
+ ops[7].isFP | ops[9].isFP, charBuf);
+ } else {
+ cvtNum(-dx, ops[0].isFP | ops[2].isFP | ops[4].isFP |
+ ops[6].isFP | ops[8].isFP, charBuf);
+ cvtNum(ops[10].num, ops[10].isFP, charBuf);
+ }
+ charBuf->append((char)8);
+ nOps = 0;
+ openPath = gTrue;
+ break;
+ default:
+ //~ error(-1, "Illegal Type 2 charstring op: %04x",
+ //~ ops[nOps].op);
+ nOps = 0;
+ break;
+ }
+ }
+ }
+
+ // charstring encryption
+ if (top) {
+ r2 = 4330;
+ for (i = start; i < charBuf->getLength(); ++i) {
+ byte = charBuf->getChar(i) ^ (r2 >> 8);
+ charBuf->setChar(i, byte);
+ r2 = (byte + r2) * 52845 + 22719;
+ }
+ }
+}
+
+void FoFiType1C::cvtGlyphWidth(GBool useOp, GString *charBuf,
+ Type1CPrivateDict *pDict) {
+ double w;
+ GBool wFP;
+ int i;
+
+ if (useOp) {
+ w = pDict->nominalWidthX + ops[0].num;
+ wFP = pDict->nominalWidthXFP | ops[0].isFP;
+ for (i = 1; i < nOps; ++i) {
+ ops[i-1] = ops[i];
+ }
+ --nOps;
+ } else {
+ w = pDict->defaultWidthX;
+ wFP = pDict->defaultWidthXFP;
+ }
+ cvtNum(0, gFalse, charBuf);
+ cvtNum(w, wFP, charBuf);
+ charBuf->append((char)13);
+}
+
+void FoFiType1C::cvtNum(double x, GBool isFP, GString *charBuf) {
+ Guchar buf[12];
+ int y, n;
+
+ n = 0;
+ if (isFP) {
+ if (x >= -32768 && x < 32768) {
+ y = (int)(x * 256.0);
+ buf[0] = 255;
+ buf[1] = (Guchar)(y >> 24);
+ buf[2] = (Guchar)(y >> 16);
+ buf[3] = (Guchar)(y >> 8);
+ buf[4] = (Guchar)y;
+ buf[5] = 255;
+ buf[6] = 0;
+ buf[7] = 0;
+ buf[8] = 1;
+ buf[9] = 0;
+ buf[10] = 12;
+ buf[11] = 12;
+ n = 12;
+ } else {
+ //~ error(-1, "Type 2 fixed point constant out of range");
+ }
+ } else {
+ y = (int)x;
+ if (y >= -107 && y <= 107) {
+ buf[0] = (Guchar)(y + 139);
+ n = 1;
+ } else if (y > 107 && y <= 1131) {
+ y -= 108;
+ buf[0] = (Guchar)((y >> 8) + 247);
+ buf[1] = (Guchar)(y & 0xff);
+ n = 2;
+ } else if (y < -107 && y >= -1131) {
+ y = -y - 108;
+ buf[0] = (Guchar)((y >> 8) + 251);
+ buf[1] = (Guchar)(y & 0xff);
+ n = 2;
+ } else {
+ buf[0] = 255;
+ buf[1] = (Guchar)(y >> 24);
+ buf[2] = (Guchar)(y >> 16);
+ buf[3] = (Guchar)(y >> 8);
+ buf[4] = (Guchar)y;
+ n = 5;
+ }
+ }
+ charBuf->append((char *)buf, n);
+}
+
+void FoFiType1C::eexecWrite(Type1CEexecBuf *eb, char *s) {
+ Guchar *p;
+ Guchar x;
+
+ for (p = (Guchar *)s; *p; ++p) {
+ x = *p ^ (eb->r1 >> 8);
+ eb->r1 = (x + eb->r1) * 52845 + 22719;
+ if (eb->ascii) {
+ (*eb->outputFunc)(eb->outputStream, &hexChars[x >> 4], 1);
+ (*eb->outputFunc)(eb->outputStream, &hexChars[x & 0x0f], 1);
+ eb->line += 2;
+ if (eb->line == 64) {
+ (*eb->outputFunc)(eb->outputStream, "\n", 1);
+ eb->line = 0;
+ }
+ } else {
+ (*eb->outputFunc)(eb->outputStream, (char *)&x, 1);
+ }
+ }
+}
+
+void FoFiType1C::eexecWriteCharstring(Type1CEexecBuf *eb,
+ Guchar *s, int n) {
+ Guchar x;
+ int i;
+
+ // eexec encryption
+ for (i = 0; i < n; ++i) {
+ x = s[i] ^ (eb->r1 >> 8);
+ eb->r1 = (x + eb->r1) * 52845 + 22719;
+ if (eb->ascii) {
+ (*eb->outputFunc)(eb->outputStream, &hexChars[x >> 4], 1);
+ (*eb->outputFunc)(eb->outputStream, &hexChars[x & 0x0f], 1);
+ eb->line += 2;
+ if (eb->line == 64) {
+ (*eb->outputFunc)(eb->outputStream, "\n", 1);
+ eb->line = 0;
+ }
+ } else {
+ (*eb->outputFunc)(eb->outputStream, (char *)&x, 1);
+ }
+ }
+}
+
+GBool FoFiType1C::parse() {
+ Type1CIndex fdIdx;
+ Type1CIndexVal val;
+ int i;
+
+ parsedOk = gTrue;
+
+ // some tools embed Type 1C fonts with an extra whitespace char at
+ // the beginning
+ if (len > 0 && file[0] != '\x01') {
+ ++file;
+ --len;
+ }
+
+ // find the indexes
+ getIndex(getU8(2, &parsedOk), &nameIdx, &parsedOk);
+ getIndex(nameIdx.endPos, &topDictIdx, &parsedOk);
+ getIndex(topDictIdx.endPos, &stringIdx, &parsedOk);
+ getIndex(stringIdx.endPos, &gsubrIdx, &parsedOk);
+ if (!parsedOk) {
+ return gFalse;
+ }
+ gsubrBias = (gsubrIdx.len < 1240) ? 107
+ : (gsubrIdx.len < 33900) ? 1131 : 32768;
+
+ // read the first font name
+ getIndexVal(&nameIdx, 0, &val, &parsedOk);
+ if (!parsedOk) {
+ return gFalse;
+ }
+ name = new GString((char *)&file[val.pos], val.len);
+
+ // read the top dict for the first font
+ readTopDict();
+
+ // for CID fonts: read the FDArray dicts and private dicts
+ if (topDict.firstOp == 0x0c1e) {
+ if (topDict.fdArrayOffset == 0) {
+ nFDs = 1;
+ privateDicts = (Type1CPrivateDict *)gmalloc(sizeof(Type1CPrivateDict));
+ readPrivateDict(0, 0, &privateDicts[0]);
+ } else {
+ getIndex(topDict.fdArrayOffset, &fdIdx, &parsedOk);
+ if (!parsedOk) {
+ return gFalse;
+ }
+ nFDs = fdIdx.len;
+ privateDicts = (Type1CPrivateDict *)
+ gmallocn(nFDs, sizeof(Type1CPrivateDict));
+ for (i = 0; i < nFDs; ++i) {
+ getIndexVal(&fdIdx, i, &val, &parsedOk);
+ if (!parsedOk) {
+ return gFalse;
+ }
+ readFD(val.pos, val.len, &privateDicts[i]);
+ }
+ }
+
+ // for 8-bit fonts: read the private dict
+ } else {
+ privateDicts = (Type1CPrivateDict *)gmalloc(sizeof(Type1CPrivateDict));
+ readPrivateDict(topDict.privateOffset, topDict.privateSize,
+ &privateDicts[0]);
+ }
+
+ // check for parse errors in the private dict(s)
+ if (!parsedOk) {
+ return gFalse;
+ }
+
+ // get the charstrings index
+ if (topDict.charStringsOffset <= 0) {
+ parsedOk = gFalse;
+ return gFalse;
+ }
+ getIndex(topDict.charStringsOffset, &charStringsIdx, &parsedOk);
+ if (!parsedOk) {
+ return gFalse;
+ }
+ nGlyphs = charStringsIdx.len;
+
+ // for CID fonts: read the FDSelect table
+ if (topDict.firstOp == 0x0c1e) {
+ readFDSelect();
+ if (!parsedOk) {
+ return gFalse;
+ }
+ }
+
+ // read the charset
+ if (!readCharset()) {
+ parsedOk = gFalse;
+ return gFalse;
+ }
+
+ // for 8-bit fonts: build the encoding
+ if (topDict.firstOp != 0x0c14 && topDict.firstOp != 0x0c1e) {
+ buildEncoding();
+ if (!parsedOk) {
+ return gFalse;
+ }
+ }
+
+ return parsedOk;
+}
+
+void FoFiType1C::readTopDict() {
+ Type1CIndexVal topDictPtr;
+ int pos;
+
+ topDict.firstOp = -1;
+ topDict.versionSID = 0;
+ topDict.noticeSID = 0;
+ topDict.copyrightSID = 0;
+ topDict.fullNameSID = 0;
+ topDict.familyNameSID = 0;
+ topDict.weightSID = 0;
+ topDict.isFixedPitch = 0;
+ topDict.italicAngle = 0;
+ topDict.underlinePosition = -100;
+ topDict.underlineThickness = 50;
+ topDict.paintType = 0;
+ topDict.charstringType = 2;
+ topDict.fontMatrix[0] = 0.001;
+ topDict.fontMatrix[1] = 0;
+ topDict.fontMatrix[2] = 0;
+ topDict.fontMatrix[3] = 0.001;
+ topDict.fontMatrix[4] = 0;
+ topDict.fontMatrix[5] = 0;
+ topDict.hasFontMatrix = gFalse;
+ topDict.uniqueID = 0;
+ topDict.fontBBox[0] = 0;
+ topDict.fontBBox[1] = 0;
+ topDict.fontBBox[2] = 0;
+ topDict.fontBBox[3] = 0;
+ topDict.strokeWidth = 0;
+ topDict.charsetOffset = 0;
+ topDict.encodingOffset = 0;
+ topDict.charStringsOffset = 0;
+ topDict.privateSize = 0;
+ topDict.privateOffset = 0;
+ topDict.registrySID = 0;
+ topDict.orderingSID = 0;
+ topDict.supplement = 0;
+ topDict.fdArrayOffset = 0;
+ topDict.fdSelectOffset = 0;
+
+ getIndexVal(&topDictIdx, 0, &topDictPtr, &parsedOk);
+ pos = topDictPtr.pos;
+ nOps = 0;
+ while (pos < topDictPtr.pos + topDictPtr.len) {
+ pos = getOp(pos, gFalse, &parsedOk);
+ if (!parsedOk) {
+ break;
+ }
+ if (!ops[nOps - 1].isNum) {
+ --nOps; // drop the operator
+ if (topDict.firstOp < 0) {
+ topDict.firstOp = ops[nOps].op;
+ }
+ switch (ops[nOps].op) {
+ case 0x0000: topDict.versionSID = (int)ops[0].num; break;
+ case 0x0001: topDict.noticeSID = (int)ops[0].num; break;
+ case 0x0c00: topDict.copyrightSID = (int)ops[0].num; break;
+ case 0x0002: topDict.fullNameSID = (int)ops[0].num; break;
+ case 0x0003: topDict.familyNameSID = (int)ops[0].num; break;
+ case 0x0004: topDict.weightSID = (int)ops[0].num; break;
+ case 0x0c01: topDict.isFixedPitch = (int)ops[0].num; break;
+ case 0x0c02: topDict.italicAngle = ops[0].num; break;
+ case 0x0c03: topDict.underlinePosition = ops[0].num; break;
+ case 0x0c04: topDict.underlineThickness = ops[0].num; break;
+ case 0x0c05: topDict.paintType = (int)ops[0].num; break;
+ case 0x0c06: topDict.charstringType = (int)ops[0].num; break;
+ case 0x0c07: topDict.fontMatrix[0] = ops[0].num;
+ topDict.fontMatrix[1] = ops[1].num;
+ topDict.fontMatrix[2] = ops[2].num;
+ topDict.fontMatrix[3] = ops[3].num;
+ topDict.fontMatrix[4] = ops[4].num;
+ topDict.fontMatrix[5] = ops[5].num;
+ topDict.hasFontMatrix = gTrue; break;
+ case 0x000d: topDict.uniqueID = (int)ops[0].num; break;
+ case 0x0005: topDict.fontBBox[0] = ops[0].num;
+ topDict.fontBBox[1] = ops[1].num;
+ topDict.fontBBox[2] = ops[2].num;
+ topDict.fontBBox[3] = ops[3].num; break;
+ case 0x0c08: topDict.strokeWidth = ops[0].num; break;
+ case 0x000f: topDict.charsetOffset = (int)ops[0].num; break;
+ case 0x0010: topDict.encodingOffset = (int)ops[0].num; break;
+ case 0x0011: topDict.charStringsOffset = (int)ops[0].num; break;
+ case 0x0012: topDict.privateSize = (int)ops[0].num;
+ topDict.privateOffset = (int)ops[1].num; break;
+ case 0x0c1e: topDict.registrySID = (int)ops[0].num;
+ topDict.orderingSID = (int)ops[1].num;
+ topDict.supplement = (int)ops[2].num; break;
+ case 0x0c24: topDict.fdArrayOffset = (int)ops[0].num; break;
+ case 0x0c25: topDict.fdSelectOffset = (int)ops[0].num; break;
+ }
+ nOps = 0;
+ }
+ }
+}
+
+// Read a CID font dict (FD) - this pulls out the private dict
+// pointer, and reads the private dict. It also pulls the FontMatrix
+// (if any) out of the FD.
+void FoFiType1C::readFD(int offset, int length, Type1CPrivateDict *pDict) {
+ int pos, pSize, pOffset;
+ double fontMatrix[6];
+ GBool hasFontMatrix;
+
+ hasFontMatrix = gFalse;
+ pSize = pOffset = 0;
+ pos = offset;
+ nOps = 0;
+ while (pos < offset + length) {
+ pos = getOp(pos, gFalse, &parsedOk);
+ if (!parsedOk) {
+ return;
+ }
+ if (!ops[nOps - 1].isNum) {
+ if (ops[nOps - 1].op == 0x0012) {
+ if (nOps < 3) {
+ parsedOk = gFalse;
+ return;
+ }
+ pSize = (int)ops[0].num;
+ pOffset = (int)ops[1].num;
+ break;
+ } else if (ops[nOps - 1].op == 0x0c07) {
+ fontMatrix[0] = ops[0].num;
+ fontMatrix[1] = ops[1].num;
+ fontMatrix[2] = ops[2].num;
+ fontMatrix[3] = ops[3].num;
+ fontMatrix[4] = ops[4].num;
+ fontMatrix[5] = ops[5].num;
+ hasFontMatrix = gTrue;
+ }
+ nOps = 0;
+ }
+ }
+ readPrivateDict(pOffset, pSize, pDict);
+ if (hasFontMatrix) {
+ pDict->fontMatrix[0] = fontMatrix[0];
+ pDict->fontMatrix[1] = fontMatrix[1];
+ pDict->fontMatrix[2] = fontMatrix[2];
+ pDict->fontMatrix[3] = fontMatrix[3];
+ pDict->fontMatrix[4] = fontMatrix[4];
+ pDict->fontMatrix[5] = fontMatrix[5];
+ pDict->hasFontMatrix = gTrue;
+ }
+}
+
+void FoFiType1C::readPrivateDict(int offset, int length,
+ Type1CPrivateDict *pDict) {
+ int pos;
+
+ pDict->hasFontMatrix = gFalse;
+ pDict->nBlueValues = 0;
+ pDict->nOtherBlues = 0;
+ pDict->nFamilyBlues = 0;
+ pDict->nFamilyOtherBlues = 0;
+ pDict->blueScale = 0.039625;
+ pDict->blueShift = 7;
+ pDict->blueFuzz = 1;
+ pDict->hasStdHW = gFalse;
+ pDict->hasStdVW = gFalse;
+ pDict->nStemSnapH = 0;
+ pDict->nStemSnapV = 0;
+ pDict->hasForceBold = gFalse;
+ pDict->forceBoldThreshold = 0;
+ pDict->languageGroup = 0;
+ pDict->expansionFactor = 0.06;
+ pDict->initialRandomSeed = 0;
+ pDict->subrsOffset = 0;
+ pDict->defaultWidthX = 0;
+ pDict->defaultWidthXFP = gFalse;
+ pDict->nominalWidthX = 0;
+ pDict->nominalWidthXFP = gFalse;
+
+ // no dictionary
+ if (offset == 0 || length == 0) {
+ return;
+ }
+
+ pos = offset;
+ nOps = 0;
+ while (pos < offset + length) {
+ pos = getOp(pos, gFalse, &parsedOk);
+ if (!parsedOk) {
+ break;
+ }
+ if (!ops[nOps - 1].isNum) {
+ --nOps; // drop the operator
+ switch (ops[nOps].op) {
+ case 0x0006:
+ pDict->nBlueValues = getDeltaIntArray(pDict->blueValues,
+ type1CMaxBlueValues);
+ break;
+ case 0x0007:
+ pDict->nOtherBlues = getDeltaIntArray(pDict->otherBlues,
+ type1CMaxOtherBlues);
+ break;
+ case 0x0008:
+ pDict->nFamilyBlues = getDeltaIntArray(pDict->familyBlues,
+ type1CMaxBlueValues);
+ break;
+ case 0x0009:
+ pDict->nFamilyOtherBlues = getDeltaIntArray(pDict->familyOtherBlues,
+ type1CMaxOtherBlues);
+ break;
+ case 0x0c09:
+ pDict->blueScale = ops[0].num;
+ break;
+ case 0x0c0a:
+ pDict->blueShift = (int)ops[0].num;
+ break;
+ case 0x0c0b:
+ pDict->blueFuzz = (int)ops[0].num;
+ break;
+ case 0x000a:
+ pDict->stdHW = ops[0].num;
+ pDict->hasStdHW = gTrue;
+ break;
+ case 0x000b:
+ pDict->stdVW = ops[0].num;
+ pDict->hasStdVW = gTrue;
+ break;
+ case 0x0c0c:
+ pDict->nStemSnapH = getDeltaFPArray(pDict->stemSnapH,
+ type1CMaxStemSnap);
+ break;
+ case 0x0c0d:
+ pDict->nStemSnapV = getDeltaFPArray(pDict->stemSnapV,
+ type1CMaxStemSnap);
+ break;
+ case 0x0c0e:
+ pDict->forceBold = ops[0].num != 0;
+ pDict->hasForceBold = gTrue;
+ break;
+ case 0x0c0f:
+ pDict->forceBoldThreshold = ops[0].num;
+ break;
+ case 0x0c11:
+ pDict->languageGroup = (int)ops[0].num;
+ break;
+ case 0x0c12:
+ pDict->expansionFactor = ops[0].num;
+ break;
+ case 0x0c13:
+ pDict->initialRandomSeed = (int)ops[0].num;
+ break;
+ case 0x0013:
+ pDict->subrsOffset = offset + (int)ops[0].num;
+ break;
+ case 0x0014:
+ pDict->defaultWidthX = ops[0].num;
+ pDict->defaultWidthXFP = ops[0].isFP;
+ break;
+ case 0x0015:
+ pDict->nominalWidthX = ops[0].num;
+ pDict->nominalWidthXFP = ops[0].isFP;
+ break;
+ }
+ nOps = 0;
+ }
+ }
+}
+
+void FoFiType1C::readFDSelect() {
+ int fdSelectFmt, pos, nRanges, gid0, gid1, fd, i, j;
+
+ fdSelect = (Guchar *)gmalloc(nGlyphs);
+ if (topDict.fdSelectOffset == 0) {
+ for (i = 0; i < nGlyphs; ++i) {
+ fdSelect[i] = 0;
+ }
+ } else {
+ pos = topDict.fdSelectOffset;
+ fdSelectFmt = getU8(pos++, &parsedOk);
+ if (!parsedOk) {
+ return;
+ }
+ if (fdSelectFmt == 0) {
+ if (!checkRegion(pos, nGlyphs)) {
+ parsedOk = gFalse;
+ return;
+ }
+ memcpy(fdSelect, file + pos, nGlyphs);
+ } else if (fdSelectFmt == 3) {
+ nRanges = getU16BE(pos, &parsedOk);
+ pos += 2;
+ gid0 = getU16BE(pos, &parsedOk);
+ pos += 2;
+ for (i = 1; i <= nRanges; ++i) {
+ fd = getU8(pos++, &parsedOk);
+ gid1 = getU16BE(pos, &parsedOk);
+ if (!parsedOk) {
+ return;
+ }
+ pos += 2;
+ if (gid0 > gid1 || gid1 > nGlyphs) {
+ //~ error(-1, "Bad FDSelect table in CID font");
+ parsedOk = gFalse;
+ return;
+ }
+ for (j = gid0; j < gid1; ++j) {
+ fdSelect[j] = fd;
+ }
+ gid0 = gid1;
+ }
+ } else {
+ //~ error(-1, "Unknown FDSelect table format in CID font");
+ for (i = 0; i < nGlyphs; ++i) {
+ fdSelect[i] = 0;
+ }
+ }
+ }
+}
+
+void FoFiType1C::buildEncoding() {
+ char buf[256];
+ int nCodes, nRanges, encFormat;
+ int pos, c, sid, nLeft, nSups, i, j;
+
+ if (topDict.encodingOffset == 0) {
+ encoding = fofiType1StandardEncoding;
+
+ } else if (topDict.encodingOffset == 1) {
+ encoding = fofiType1ExpertEncoding;
+
+ } else {
+ encoding = (char **)gmallocn(256, sizeof(char *));
+ for (i = 0; i < 256; ++i) {
+ encoding[i] = NULL;
+ }
+ pos = topDict.encodingOffset;
+ encFormat = getU8(pos++, &parsedOk);
+ if (!parsedOk) {
+ return;
+ }
+ if ((encFormat & 0x7f) == 0) {
+ nCodes = 1 + getU8(pos++, &parsedOk);
+ if (!parsedOk) {
+ return;
+ }
+ if (nCodes > nGlyphs) {
+ nCodes = nGlyphs;
+ }
+ for (i = 1; i < nCodes; ++i) {
+ c = getU8(pos++, &parsedOk);
+ if (!parsedOk) {
+ return;
+ }
+ if (encoding[c]) {
+ gfree(encoding[c]);
+ }
+ encoding[c] = copyString(getString(charset[i], buf, &parsedOk));
+ }
+ } else if ((encFormat & 0x7f) == 1) {
+ nRanges = getU8(pos++, &parsedOk);
+ if (!parsedOk) {
+ return;
+ }
+ nCodes = 1;
+ for (i = 0; i < nRanges; ++i) {
+ c = getU8(pos++, &parsedOk);
+ nLeft = getU8(pos++, &parsedOk);
+ if (!parsedOk) {
+ return;
+ }
+ for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) {
+ if (c < 256) {
+ if (encoding[c]) {
+ gfree(encoding[c]);
+ }
+ encoding[c] = copyString(getString(charset[nCodes], buf,
+ &parsedOk));
+ }
+ ++nCodes;
+ ++c;
+ }
+ }
+ }
+ if (encFormat & 0x80) {
+ nSups = getU8(pos++, &parsedOk);
+ if (!parsedOk) {
+ return;
+ }
+ for (i = 0; i < nSups; ++i) {
+ c = getU8(pos++, &parsedOk);;
+ if (!parsedOk) {
+ return;;
+ }
+ sid = getU16BE(pos, &parsedOk);
+ pos += 2;
+ if (!parsedOk) {
+ return;
+ }
+ if (encoding[c]) {
+ gfree(encoding[c]);
+ }
+ encoding[c] = copyString(getString(sid, buf, &parsedOk));
+ }
+ }
+ }
+}
+
+GBool FoFiType1C::readCharset() {
+ int charsetFormat, c, pos;
+ int nLeft, i, j;
+
+ if (topDict.charsetOffset == 0) {
+ charset = fofiType1CISOAdobeCharset;
+ } else if (topDict.charsetOffset == 1) {
+ charset = fofiType1CExpertCharset;
+ } else if (topDict.charsetOffset == 2) {
+ charset = fofiType1CExpertSubsetCharset;
+ } else {
+ charset = (Gushort *)gmallocn(nGlyphs, sizeof(Gushort));
+ for (i = 0; i < nGlyphs; ++i) {
+ charset[i] = 0;
+ }
+ pos = topDict.charsetOffset;
+ charsetFormat = getU8(pos++, &parsedOk);
+ if (charsetFormat == 0) {
+ for (i = 1; i < nGlyphs; ++i) {
+ charset[i] = (Gushort)getU16BE(pos, &parsedOk);
+ pos += 2;
+ if (!parsedOk) {
+ break;
+ }
+ }
+ } else if (charsetFormat == 1) {
+ i = 1;
+ while (i < nGlyphs) {
+ c = getU16BE(pos, &parsedOk);
+ pos += 2;
+ nLeft = getU8(pos++, &parsedOk);
+ if (!parsedOk) {
+ break;
+ }
+ for (j = 0; j <= nLeft && i < nGlyphs; ++j) {
+ charset[i++] = (Gushort)c++;
+ }
+ }
+ } else if (charsetFormat == 2) {
+ i = 1;
+ while (i < nGlyphs) {
+ c = getU16BE(pos, &parsedOk);
+ pos += 2;
+ nLeft = getU16BE(pos, &parsedOk);
+ pos += 2;
+ if (!parsedOk) {
+ break;
+ }
+ for (j = 0; j <= nLeft && i < nGlyphs; ++j) {
+ charset[i++] = (Gushort)c++;
+ }
+ }
+ }
+ if (!parsedOk) {
+ gfree(charset);
+ charset = NULL;
+ return gFalse;
+ }
+ }
+ return gTrue;
+}
+
+int FoFiType1C::getOp(int pos, GBool charstring, GBool *ok) {
+ static char nybChars[16] = "0123456789.ee -";
+ Type1COp op;
+ char buf[65];
+ int b0, b1, nyb0, nyb1, x, i;
+
+ b0 = getU8(pos++, ok);
+ op.isNum = gTrue;
+ op.isFP = gFalse;
+
+ if (b0 == 28) {
+ x = getU8(pos++, ok);
+ x = (x << 8) | getU8(pos++, ok);
+ if (x & 0x8000) {
+ x |= ~0xffff;
+ }
+ op.num = x;
+
+ } else if (!charstring && b0 == 29) {
+ x = getU8(pos++, ok);
+ x = (x << 8) | getU8(pos++, ok);
+ x = (x << 8) | getU8(pos++, ok);
+ x = (x << 8) | getU8(pos++, ok);
+ if (x & 0x80000000) {
+ x |= ~0xffffffff;
+ }
+ op.num = x;
+
+ } else if (!charstring && b0 == 30) {
+ i = 0;
+ do {
+ b1 = getU8(pos++, ok);
+ nyb0 = b1 >> 4;
+ nyb1 = b1 & 0x0f;
+ if (nyb0 == 0xf) {
+ break;
+ }
+ buf[i++] = nybChars[nyb0];
+ if (i == 64) {
+ break;
+ }
+ if (nyb0 == 0xc) {
+ buf[i++] = '-';
+ }
+ if (i == 64) {
+ break;
+ }
+ if (nyb1 == 0xf) {
+ break;
+ }
+ buf[i++] = nybChars[nyb1];
+ if (i == 64) {
+ break;
+ }
+ if (nyb1 == 0xc) {
+ buf[i++] = '-';
+ }
+ } while (i < 64);
+ buf[i] = '\0';
+ op.num = atof(buf);
+ op.isFP = gTrue;
+
+ } else if (b0 >= 32 && b0 <= 246) {
+ op.num = b0 - 139;
+
+ } else if (b0 >= 247 && b0 <= 250) {
+ op.num = ((b0 - 247) << 8) + getU8(pos++, ok) + 108;
+
+ } else if (b0 >= 251 && b0 <= 254) {
+ op.num = -((b0 - 251) << 8) - getU8(pos++, ok) - 108;
+
+ } else if (charstring && b0 == 255) {
+ x = getU8(pos++, ok);
+ x = (x << 8) | getU8(pos++, ok);
+ x = (x << 8) | getU8(pos++, ok);
+ x = (x << 8) | getU8(pos++, ok);
+ if (x & 0x80000000) {
+ x |= ~0xffffffff;
+ }
+ op.num = (double)x / 65536.0;
+ op.isFP = gTrue;
+
+ } else if (b0 == 12) {
+ op.isNum = gFalse;
+ op.op = 0x0c00 + getU8(pos++, ok);
+
+ } else {
+ op.isNum = gFalse;
+ op.op = b0;
+ }
+
+ if (nOps < 49) {
+ ops[nOps++] = op;
+ }
+
+ return pos;
+}
+
+// Convert the delta-encoded ops array to an array of ints.
+int FoFiType1C::getDeltaIntArray(int *arr, int maxLen) {
+ int x;
+ int n, i;
+
+ if ((n = nOps) > maxLen) {
+ n = maxLen;
+ }
+ x = 0;
+ for (i = 0; i < n; ++i) {
+ x += (int)ops[i].num;
+ arr[i] = x;
+ }
+ return n;
+}
+
+// Convert the delta-encoded ops array to an array of doubles.
+int FoFiType1C::getDeltaFPArray(double *arr, int maxLen) {
+ double x;
+ int n, i;
+
+ if ((n = nOps) > maxLen) {
+ n = maxLen;
+ }
+ x = 0;
+ for (i = 0; i < n; ++i) {
+ x += ops[i].num;
+ arr[i] = x;
+ }
+ return n;
+}
+
+void FoFiType1C::getIndex(int pos, Type1CIndex *idx, GBool *ok) {
+ idx->pos = pos;
+ idx->len = getU16BE(pos, ok);
+ if (idx->len == 0) {
+ // empty indexes are legal and contain just the length field
+ idx->offSize = 0;
+ idx->startPos = idx->endPos = pos + 2;
+ } else {
+ idx->offSize = getU8(pos + 2, ok);
+ if (idx->offSize < 1 || idx->offSize > 4) {
+ *ok = gFalse;
+ }
+ idx->startPos = pos + 3 + (idx->len + 1) * idx->offSize - 1;
+ if (idx->startPos < 0 || idx->startPos >= len) {
+ *ok = gFalse;
+ }
+ idx->endPos = idx->startPos + getUVarBE(pos + 3 + idx->len * idx->offSize,
+ idx->offSize, ok);
+ if (idx->endPos < idx->startPos || idx->endPos > len) {
+ *ok = gFalse;
+ }
+ }
+}
+
+void FoFiType1C::getIndexVal(Type1CIndex *idx, int i,
+ Type1CIndexVal *val, GBool *ok) {
+ int pos0, pos1;
+
+ if (i < 0 || i >= idx->len) {
+ *ok = gFalse;
+ return;
+ }
+ pos0 = idx->startPos + getUVarBE(idx->pos + 3 + i * idx->offSize,
+ idx->offSize, ok);
+ pos1 = idx->startPos + getUVarBE(idx->pos + 3 + (i + 1) * idx->offSize,
+ idx->offSize, ok);
+ if (pos0 < idx->startPos || pos0 > idx->endPos ||
+ pos1 <= idx->startPos || pos1 > idx->endPos ||
+ pos1 < pos0) {
+ *ok = gFalse;
+ }
+ val->pos = pos0;
+ val->len = pos1 - pos0;
+}
+
+char *FoFiType1C::getString(int sid, char *buf, GBool *ok) {
+ Type1CIndexVal val;
+ int n;
+
+ if (sid < 391) {
+ strcpy(buf, fofiType1CStdStrings[sid]);
+ } else {
+ sid -= 391;
+ getIndexVal(&stringIdx, sid, &val, ok);
+ if (*ok) {
+ if ((n = val.len) > 255) {
+ n = 255;
+ }
+ strncpy(buf, (char *)&file[val.pos], n);
+ buf[n] = '\0';
+ } else {
+ buf[0] = '\0';
+ }
+ }
+ return buf;
+}
diff --git a/kpdf/xpdf/fofi/FoFiType1C.h b/kpdf/xpdf/fofi/FoFiType1C.h
new file mode 100644
index 00000000..eec27555
--- /dev/null
+++ b/kpdf/xpdf/fofi/FoFiType1C.h
@@ -0,0 +1,233 @@
+//========================================================================
+//
+// FoFiType1C.h
+//
+// Copyright 1999-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef FOFITYPE1C_H
+#define FOFITYPE1C_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "FoFiBase.h"
+
+class GString;
+
+//------------------------------------------------------------------------
+
+struct Type1CIndex {
+ int pos; // absolute position in file
+ int len; // length (number of entries)
+ int offSize; // offset size
+ int startPos; // position of start of index data - 1
+ int endPos; // position one byte past end of the index
+};
+
+struct Type1CIndexVal {
+ int pos; // absolute position in file
+ int len; // length, in bytes
+};
+
+struct Type1CTopDict {
+ int firstOp;
+
+ int versionSID;
+ int noticeSID;
+ int copyrightSID;
+ int fullNameSID;
+ int familyNameSID;
+ int weightSID;
+ int isFixedPitch;
+ double italicAngle;
+ double underlinePosition;
+ double underlineThickness;
+ int paintType;
+ int charstringType;
+ double fontMatrix[6];
+ GBool hasFontMatrix; // CID fonts are allowed to put their
+ // FontMatrix in the FD instead of the
+ // top dict
+ int uniqueID;
+ double fontBBox[4];
+ double strokeWidth;
+ int charsetOffset;
+ int encodingOffset;
+ int charStringsOffset;
+ int privateSize;
+ int privateOffset;
+
+ // CIDFont entries
+ int registrySID;
+ int orderingSID;
+ int supplement;
+ int fdArrayOffset;
+ int fdSelectOffset;
+};
+
+#define type1CMaxBlueValues 14
+#define type1CMaxOtherBlues 10
+#define type1CMaxStemSnap 12
+
+struct Type1CPrivateDict {
+ double fontMatrix[6];
+ GBool hasFontMatrix;
+ int blueValues[type1CMaxBlueValues];
+ int nBlueValues;
+ int otherBlues[type1CMaxOtherBlues];
+ int nOtherBlues;
+ int familyBlues[type1CMaxBlueValues];
+ int nFamilyBlues;
+ int familyOtherBlues[type1CMaxOtherBlues];
+ int nFamilyOtherBlues;
+ double blueScale;
+ int blueShift;
+ int blueFuzz;
+ double stdHW;
+ GBool hasStdHW;
+ double stdVW;
+ GBool hasStdVW;
+ double stemSnapH[type1CMaxStemSnap];
+ int nStemSnapH;
+ double stemSnapV[type1CMaxStemSnap];
+ int nStemSnapV;
+ GBool forceBold;
+ GBool hasForceBold;
+ double forceBoldThreshold;
+ int languageGroup;
+ double expansionFactor;
+ int initialRandomSeed;
+ int subrsOffset;
+ double defaultWidthX;
+ GBool defaultWidthXFP;
+ double nominalWidthX;
+ GBool nominalWidthXFP;
+};
+
+struct Type1COp {
+ GBool isNum; // true -> number, false -> operator
+ GBool isFP; // true -> floating point number, false -> int
+ union {
+ double num; // if num is true
+ int op; // if num is false
+ };
+};
+
+struct Type1CEexecBuf {
+ FoFiOutputFunc outputFunc;
+ void *outputStream;
+ GBool ascii; // ASCII encoding?
+ Gushort r1; // eexec encryption key
+ int line; // number of eexec chars left on current line
+};
+
+//------------------------------------------------------------------------
+// FoFiType1C
+//------------------------------------------------------------------------
+
+class FoFiType1C: public FoFiBase {
+public:
+
+ // Create a FoFiType1C object from a memory buffer.
+ static FoFiType1C *make(char *fileA, int lenA);
+
+ // Create a FoFiType1C object from a file on disk.
+ static FoFiType1C *load(char *fileName);
+
+ virtual ~FoFiType1C();
+
+ // Return the font name.
+ char *getName();
+
+ // Return the encoding, as an array of 256 names (any of which may
+ // be NULL). This is only useful with 8-bit fonts.
+ char **getEncoding();
+
+ // Return the mapping from CIDs to GIDs, and return the number of
+ // CIDs in *<nCIDs>. This is only useful for CID fonts.
+ Gushort *getCIDToGIDMap(int *nCIDs);
+
+ // Convert to a Type 1 font, suitable for embedding in a PostScript
+ // file. This is only useful with 8-bit fonts. If <newEncoding> is
+ // not NULL, it will be used in place of the encoding in the Type 1C
+ // font. If <ascii> is true the eexec section will be hex-encoded,
+ // otherwise it will be left as binary data. If <psName> is non-NULL,
+ // it will be used as the PostScript font name.
+ void convertToType1(char *psName, char **newEncoding, GBool ascii,
+ FoFiOutputFunc outputFunc, void *outputStream);
+
+ // Convert to a Type 0 CIDFont, suitable for embedding in a
+ // PostScript file. <psName> will be used as the PostScript font
+ // name.
+ void convertToCIDType0(char *psName,
+ FoFiOutputFunc outputFunc, void *outputStream);
+
+ // Convert to a Type 0 (but non-CID) composite font, suitable for
+ // embedding in a PostScript file. <psName> will be used as the
+ // PostScript font name.
+ void convertToType0(char *psName,
+ FoFiOutputFunc outputFunc, void *outputStream);
+
+private:
+
+ FoFiType1C(char *fileA, int lenA, GBool freeFileDataA);
+ void eexecCvtGlyph(Type1CEexecBuf *eb, char *glyphName,
+ int offset, int nBytes,
+ Type1CIndex *subrIdx,
+ Type1CPrivateDict *pDict);
+ void cvtGlyph(int offset, int nBytes, GString *charBuf,
+ Type1CIndex *subrIdx, Type1CPrivateDict *pDict,
+ GBool top);
+ void cvtGlyphWidth(GBool useOp, GString *charBuf,
+ Type1CPrivateDict *pDict);
+ void cvtNum(double x, GBool isFP, GString *charBuf);
+ void eexecWrite(Type1CEexecBuf *eb, char *s);
+ void eexecWriteCharstring(Type1CEexecBuf *eb, Guchar *s, int n);
+ GBool parse();
+ void readTopDict();
+ void readFD(int offset, int length, Type1CPrivateDict *pDict);
+ void readPrivateDict(int offset, int length, Type1CPrivateDict *pDict);
+ void readFDSelect();
+ void buildEncoding();
+ GBool readCharset();
+ int getOp(int pos, GBool charstring, GBool *ok);
+ int getDeltaIntArray(int *arr, int maxLen);
+ int getDeltaFPArray(double *arr, int maxLen);
+ void getIndex(int pos, Type1CIndex *idx, GBool *ok);
+ void getIndexVal(Type1CIndex *idx, int i, Type1CIndexVal *val, GBool *ok);
+ char *getString(int sid, char *buf, GBool *ok);
+
+ GString *name;
+ char **encoding;
+
+ Type1CIndex nameIdx;
+ Type1CIndex topDictIdx;
+ Type1CIndex stringIdx;
+ Type1CIndex gsubrIdx;
+ Type1CIndex charStringsIdx;
+
+ Type1CTopDict topDict;
+ Type1CPrivateDict *privateDicts;
+
+ int nGlyphs;
+ int nFDs;
+ Guchar *fdSelect;
+ Gushort *charset;
+ int gsubrBias;
+
+ GBool parsedOk;
+
+ Type1COp ops[49]; // operands and operator
+ int nOps; // number of operands
+ int nHints; // number of hints for the current glyph
+ GBool firstOp; // true if we haven't hit the first op yet
+ GBool openPath; // true if there is an unclosed path
+};
+
+#endif
diff --git a/kpdf/xpdf/fofi/Makefile.am b/kpdf/xpdf/fofi/Makefile.am
new file mode 100644
index 00000000..7ca93922
--- /dev/null
+++ b/kpdf/xpdf/fofi/Makefile.am
@@ -0,0 +1,9 @@
+INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../goo $(all_includes)
+
+libfofi_la_LDFLAGS = $(all_libraries)
+libfofi_la_SOURCES = FoFiBase.cc FoFiEncodings.cc FoFiTrueType.cc \
+ FoFiType1.cc FoFiType1C.cc
+
+METASOURCES = AUTO
+
+noinst_LTLIBRARIES = libfofi.la
diff --git a/kpdf/xpdf/goo/GHash.cc b/kpdf/xpdf/goo/GHash.cc
new file mode 100644
index 00000000..b51a7643
--- /dev/null
+++ b/kpdf/xpdf/goo/GHash.cc
@@ -0,0 +1,380 @@
+//========================================================================
+//
+// GHash.cc
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "gmem.h"
+#include "GString.h"
+#include "GHash.h"
+
+//------------------------------------------------------------------------
+
+struct GHashBucket {
+ GString *key;
+ union {
+ void *p;
+ int i;
+ } val;
+ GHashBucket *next;
+};
+
+struct GHashIter {
+ int h;
+ GHashBucket *p;
+};
+
+//------------------------------------------------------------------------
+
+GHash::GHash(GBool deleteKeysA) {
+ int h;
+
+ deleteKeys = deleteKeysA;
+ size = 7;
+ tab = (GHashBucket **)gmallocn(size, sizeof(GHashBucket *));
+ for (h = 0; h < size; ++h) {
+ tab[h] = NULL;
+ }
+ len = 0;
+}
+
+GHash::~GHash() {
+ GHashBucket *p;
+ int h;
+
+ for (h = 0; h < size; ++h) {
+ while (tab[h]) {
+ p = tab[h];
+ tab[h] = p->next;
+ if (deleteKeys) {
+ delete p->key;
+ }
+ delete p;
+ }
+ }
+ gfree(tab);
+}
+
+void GHash::add(GString *key, void *val) {
+ GHashBucket *p;
+ int h;
+
+ // expand the table if necessary
+ if (len >= size) {
+ expand();
+ }
+
+ // add the new symbol
+ p = new GHashBucket;
+ p->key = key;
+ p->val.p = val;
+ h = hash(key);
+ p->next = tab[h];
+ tab[h] = p;
+ ++len;
+}
+
+void GHash::add(GString *key, int val) {
+ GHashBucket *p;
+ int h;
+
+ // expand the table if necessary
+ if (len >= size) {
+ expand();
+ }
+
+ // add the new symbol
+ p = new GHashBucket;
+ p->key = key;
+ p->val.i = val;
+ h = hash(key);
+ p->next = tab[h];
+ tab[h] = p;
+ ++len;
+}
+
+void GHash::replace(GString *key, void *val) {
+ GHashBucket *p;
+ int h;
+
+ if ((p = find(key, &h))) {
+ p->val.p = val;
+ delete key;
+ } else {
+ add(key, val);
+ }
+}
+
+void GHash::replace(GString *key, int val) {
+ GHashBucket *p;
+ int h;
+
+ if ((p = find(key, &h))) {
+ p->val.i = val;
+ delete key;
+ } else {
+ add(key, val);
+ }
+}
+
+void *GHash::lookup(GString *key) {
+ GHashBucket *p;
+ int h;
+
+ if (!(p = find(key, &h))) {
+ return NULL;
+ }
+ return p->val.p;
+}
+
+int GHash::lookupInt(GString *key) {
+ GHashBucket *p;
+ int h;
+
+ if (!(p = find(key, &h))) {
+ return 0;
+ }
+ return p->val.i;
+}
+
+void *GHash::lookup(char *key) {
+ GHashBucket *p;
+ int h;
+
+ if (!(p = find(key, &h))) {
+ return NULL;
+ }
+ return p->val.p;
+}
+
+int GHash::lookupInt(char *key) {
+ GHashBucket *p;
+ int h;
+
+ if (!(p = find(key, &h))) {
+ return 0;
+ }
+ return p->val.i;
+}
+
+void *GHash::remove(GString *key) {
+ GHashBucket *p;
+ GHashBucket **q;
+ void *val;
+ int h;
+
+ if (!(p = find(key, &h))) {
+ return NULL;
+ }
+ q = &tab[h];
+ while (*q != p) {
+ q = &((*q)->next);
+ }
+ *q = p->next;
+ if (deleteKeys) {
+ delete p->key;
+ }
+ val = p->val.p;
+ delete p;
+ --len;
+ return val;
+}
+
+int GHash::removeInt(GString *key) {
+ GHashBucket *p;
+ GHashBucket **q;
+ int val;
+ int h;
+
+ if (!(p = find(key, &h))) {
+ return 0;
+ }
+ q = &tab[h];
+ while (*q != p) {
+ q = &((*q)->next);
+ }
+ *q = p->next;
+ if (deleteKeys) {
+ delete p->key;
+ }
+ val = p->val.i;
+ delete p;
+ --len;
+ return val;
+}
+
+void *GHash::remove(char *key) {
+ GHashBucket *p;
+ GHashBucket **q;
+ void *val;
+ int h;
+
+ if (!(p = find(key, &h))) {
+ return NULL;
+ }
+ q = &tab[h];
+ while (*q != p) {
+ q = &((*q)->next);
+ }
+ *q = p->next;
+ if (deleteKeys) {
+ delete p->key;
+ }
+ val = p->val.p;
+ delete p;
+ --len;
+ return val;
+}
+
+int GHash::removeInt(char *key) {
+ GHashBucket *p;
+ GHashBucket **q;
+ int val;
+ int h;
+
+ if (!(p = find(key, &h))) {
+ return 0;
+ }
+ q = &tab[h];
+ while (*q != p) {
+ q = &((*q)->next);
+ }
+ *q = p->next;
+ if (deleteKeys) {
+ delete p->key;
+ }
+ val = p->val.i;
+ delete p;
+ --len;
+ return val;
+}
+
+void GHash::startIter(GHashIter **iter) {
+ *iter = new GHashIter;
+ (*iter)->h = -1;
+ (*iter)->p = NULL;
+}
+
+GBool GHash::getNext(GHashIter **iter, GString **key, void **val) {
+ if (!*iter) {
+ return gFalse;
+ }
+ if ((*iter)->p) {
+ (*iter)->p = (*iter)->p->next;
+ }
+ while (!(*iter)->p) {
+ if (++(*iter)->h == size) {
+ delete *iter;
+ *iter = NULL;
+ return gFalse;
+ }
+ (*iter)->p = tab[(*iter)->h];
+ }
+ *key = (*iter)->p->key;
+ *val = (*iter)->p->val.p;
+ return gTrue;
+}
+
+GBool GHash::getNext(GHashIter **iter, GString **key, int *val) {
+ if (!*iter) {
+ return gFalse;
+ }
+ if ((*iter)->p) {
+ (*iter)->p = (*iter)->p->next;
+ }
+ while (!(*iter)->p) {
+ if (++(*iter)->h == size) {
+ delete *iter;
+ *iter = NULL;
+ return gFalse;
+ }
+ (*iter)->p = tab[(*iter)->h];
+ }
+ *key = (*iter)->p->key;
+ *val = (*iter)->p->val.i;
+ return gTrue;
+}
+
+void GHash::killIter(GHashIter **iter) {
+ delete *iter;
+ *iter = NULL;
+}
+
+void GHash::expand() {
+ GHashBucket **oldTab;
+ GHashBucket *p;
+ int oldSize, h, i;
+
+ oldSize = size;
+ oldTab = tab;
+ size = 2*size + 1;
+ tab = (GHashBucket **)gmallocn(size, sizeof(GHashBucket *));
+ for (h = 0; h < size; ++h) {
+ tab[h] = NULL;
+ }
+ for (i = 0; i < oldSize; ++i) {
+ while (oldTab[i]) {
+ p = oldTab[i];
+ oldTab[i] = oldTab[i]->next;
+ h = hash(p->key);
+ p->next = tab[h];
+ tab[h] = p;
+ }
+ }
+ gfree(oldTab);
+}
+
+GHashBucket *GHash::find(GString *key, int *h) {
+ GHashBucket *p;
+
+ *h = hash(key);
+ for (p = tab[*h]; p; p = p->next) {
+ if (!p->key->cmp(key)) {
+ return p;
+ }
+ }
+ return NULL;
+}
+
+GHashBucket *GHash::find(char *key, int *h) {
+ GHashBucket *p;
+
+ *h = hash(key);
+ for (p = tab[*h]; p; p = p->next) {
+ if (!p->key->cmp(key)) {
+ return p;
+ }
+ }
+ return NULL;
+}
+
+int GHash::hash(GString *key) {
+ char *p;
+ unsigned int h;
+ int i;
+
+ h = 0;
+ for (p = key->getCString(), i = 0; i < key->getLength(); ++p, ++i) {
+ h = 17 * h + (int)(*p & 0xff);
+ }
+ return (int)(h % size);
+}
+
+int GHash::hash(char *key) {
+ char *p;
+ unsigned int h;
+
+ h = 0;
+ for (p = key; *p; ++p) {
+ h = 17 * h + (int)(*p & 0xff);
+ }
+ return (int)(h % size);
+}
diff --git a/kpdf/xpdf/goo/GHash.h b/kpdf/xpdf/goo/GHash.h
new file mode 100644
index 00000000..31aba932
--- /dev/null
+++ b/kpdf/xpdf/goo/GHash.h
@@ -0,0 +1,78 @@
+//========================================================================
+//
+// GHash.h
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef GHASH_H
+#define GHASH_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+
+class GString;
+struct GHashBucket;
+struct GHashIter;
+
+//------------------------------------------------------------------------
+
+class GHash {
+public:
+
+ GHash(GBool deleteKeysA = gFalse);
+ ~GHash();
+ void add(GString *key, void *val);
+ void add(GString *key, int val);
+ void replace(GString *key, void *val);
+ void replace(GString *key, int val);
+ void *lookup(GString *key);
+ int lookupInt(GString *key);
+ void *lookup(char *key);
+ int lookupInt(char *key);
+ void *remove(GString *key);
+ int removeInt(GString *key);
+ void *remove(char *key);
+ int removeInt(char *key);
+ int getLength() { return len; }
+ void startIter(GHashIter **iter);
+ GBool getNext(GHashIter **iter, GString **key, void **val);
+ GBool getNext(GHashIter **iter, GString **key, int *val);
+ void killIter(GHashIter **iter);
+
+private:
+
+ void expand();
+ GHashBucket *find(GString *key, int *h);
+ GHashBucket *find(char *key, int *h);
+ int hash(GString *key);
+ int hash(char *key);
+
+ GBool deleteKeys; // set if key strings should be deleted
+ int size; // number of buckets
+ int len; // number of entries
+ GHashBucket **tab;
+};
+
+#define deleteGHash(hash, T) \
+ do { \
+ GHash *_hash = (hash); \
+ { \
+ GHashIter *_iter; \
+ GString *_key; \
+ void *_p; \
+ _hash->startIter(&_iter); \
+ while (_hash->getNext(&_iter, &_key, &_p)) { \
+ delete (T*)_p; \
+ } \
+ delete _hash; \
+ } \
+ } while(0)
+
+#endif
diff --git a/kpdf/xpdf/goo/GList.cc b/kpdf/xpdf/goo/GList.cc
new file mode 100644
index 00000000..fb5fd628
--- /dev/null
+++ b/kpdf/xpdf/goo/GList.cc
@@ -0,0 +1,97 @@
+//========================================================================
+//
+// GList.cc
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include "gmem.h"
+#include "GList.h"
+
+//------------------------------------------------------------------------
+// GList
+//------------------------------------------------------------------------
+
+GList::GList() {
+ size = 8;
+ data = (void **)gmallocn(size, sizeof(void*));
+ length = 0;
+ inc = 0;
+}
+
+GList::GList(int sizeA) {
+ size = sizeA;
+ data = (void **)gmallocn(size, sizeof(void*));
+ length = 0;
+ inc = 0;
+}
+
+GList::~GList() {
+ gfree(data);
+}
+
+void GList::append(void *p) {
+ if (length >= size) {
+ expand();
+ }
+ data[length++] = p;
+}
+
+void GList::append(GList *list) {
+ int i;
+
+ while (length + list->length > size) {
+ expand();
+ }
+ for (i = 0; i < list->length; ++i) {
+ data[length++] = list->data[i];
+ }
+}
+
+void GList::insert(int i, void *p) {
+ if (length >= size) {
+ expand();
+ }
+ if (i < length) {
+ memmove(data+i+1, data+i, (length - i) * sizeof(void *));
+ }
+ data[i] = p;
+ ++length;
+}
+
+void *GList::del(int i) {
+ void *p;
+
+ p = data[i];
+ if (i < length - 1) {
+ memmove(data+i, data+i+1, (length - i - 1) * sizeof(void *));
+ }
+ --length;
+ if (size - length >= ((inc > 0) ? inc : size/2)) {
+ shrink();
+ }
+ return p;
+}
+
+void GList::sort(int (*cmp)(const void *obj1, const void *obj2)) {
+ qsort(data, length, sizeof(void *), cmp);
+}
+
+void GList::expand() {
+ size += (inc > 0) ? inc : size;
+ data = (void **)greallocn(data, size, sizeof(void*));
+}
+
+void GList::shrink() {
+ size -= (inc > 0) ? inc : size/2;
+ data = (void **)greallocn(data, size, sizeof(void*));
+}
diff --git a/kpdf/xpdf/goo/GList.h b/kpdf/xpdf/goo/GList.h
new file mode 100644
index 00000000..e4d8ff8f
--- /dev/null
+++ b/kpdf/xpdf/goo/GList.h
@@ -0,0 +1,96 @@
+//========================================================================
+//
+// GList.h
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef GLIST_H
+#define GLIST_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+
+//------------------------------------------------------------------------
+// GList
+//------------------------------------------------------------------------
+
+class GList {
+public:
+
+ // Create an empty list.
+ GList();
+
+ // Create an empty list with space for <size1> elements.
+ GList(int sizeA);
+
+ // Destructor - does not free pointed-to objects.
+ ~GList();
+
+ //----- general
+
+ // Get the number of elements.
+ int getLength() { return length; }
+
+ //----- ordered list support
+
+ // Return the <i>th element.
+ // Assumes 0 <= i < length.
+ void *get(int i) { return data[i]; }
+
+ // Append an element to the end of the list.
+ void append(void *p);
+
+ // Append another list to the end of this one.
+ void append(GList *list);
+
+ // Insert an element at index <i>.
+ // Assumes 0 <= i <= length.
+ void insert(int i, void *p);
+
+ // Deletes and returns the element at index <i>.
+ // Assumes 0 <= i < length.
+ void *del(int i);
+
+ // Sort the list accoring to the given comparison function.
+ // NB: this sorts an array of pointers, so the pointer args need to
+ // be double-dereferenced.
+ void sort(int (*cmp)(const void *ptr1, const void *ptr2));
+
+ //----- control
+
+ // Set allocation increment to <inc>. If inc > 0, that many
+ // elements will be allocated every time the list is expanded.
+ // If inc <= 0, the list will be doubled in size.
+ void setAllocIncr(int incA) { inc = incA; }
+
+private:
+
+ void expand();
+ void shrink();
+
+ void **data; // the list elements
+ int size; // size of data array
+ int length; // number of elements on list
+ int inc; // allocation increment
+};
+
+#define deleteGList(list, T) \
+ do { \
+ GList *_list = (list); \
+ { \
+ int _i; \
+ for (_i = 0; _i < _list->getLength(); ++_i) { \
+ delete (T*)_list->get(_i); \
+ } \
+ delete _list; \
+ } \
+ } while (0)
+
+#endif
diff --git a/kpdf/xpdf/goo/GMutex.h b/kpdf/xpdf/goo/GMutex.h
new file mode 100644
index 00000000..7fa93d85
--- /dev/null
+++ b/kpdf/xpdf/goo/GMutex.h
@@ -0,0 +1,49 @@
+//========================================================================
+//
+// GMutex.h
+//
+// Portable mutex macros.
+//
+// Copyright 2002-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef GMUTEX_H
+#define GMUTEX_H
+
+// Usage:
+//
+// GMutex m;
+// gInitMutex(&m);
+// ...
+// gLockMutex(&m);
+// ... critical section ...
+// gUnlockMutex(&m);
+// ...
+// gDestroyMutex(&m);
+
+#ifdef WIN32
+
+#include <windows.h>
+
+typedef CRITICAL_SECTION GMutex;
+
+#define gInitMutex(m) InitializeCriticalSection(m)
+#define gDestroyMutex(m) DeleteCriticalSection(m)
+#define gLockMutex(m) EnterCriticalSection(m)
+#define gUnlockMutex(m) LeaveCriticalSection(m)
+
+#else // assume pthreads
+
+#include <pthread.h>
+
+typedef pthread_mutex_t GMutex;
+
+#define gInitMutex(m) pthread_mutex_init(m, NULL)
+#define gDestroyMutex(m) pthread_mutex_destroy(m)
+#define gLockMutex(m) pthread_mutex_lock(m)
+#define gUnlockMutex(m) pthread_mutex_unlock(m)
+
+#endif
+
+#endif
diff --git a/kpdf/xpdf/goo/GString.cc b/kpdf/xpdf/goo/GString.cc
new file mode 100644
index 00000000..e21fd3ea
--- /dev/null
+++ b/kpdf/xpdf/goo/GString.cc
@@ -0,0 +1,718 @@
+//========================================================================
+//
+// GString.cc
+//
+// Simple variable-length string type.
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include "gmem.h"
+#include "GString.h"
+
+//------------------------------------------------------------------------
+
+union GStringFormatArg {
+ int i;
+ Guint ui;
+ long l;
+ Gulong ul;
+ double f;
+ char c;
+ char *s;
+ GString *gs;
+};
+
+enum GStringFormatType {
+ fmtIntDecimal,
+ fmtIntHex,
+ fmtIntOctal,
+ fmtIntBinary,
+ fmtUIntDecimal,
+ fmtUIntHex,
+ fmtUIntOctal,
+ fmtUIntBinary,
+ fmtLongDecimal,
+ fmtLongHex,
+ fmtLongOctal,
+ fmtLongBinary,
+ fmtULongDecimal,
+ fmtULongHex,
+ fmtULongOctal,
+ fmtULongBinary,
+ fmtDouble,
+ fmtDoubleTrim,
+ fmtChar,
+ fmtString,
+ fmtGString,
+ fmtSpace
+};
+
+static char *formatStrings[] = {
+ "d", "x", "o", "b", "ud", "ux", "uo", "ub",
+ "ld", "lx", "lo", "lb", "uld", "ulx", "ulo", "ulb",
+ "f", "g",
+ "c",
+ "s",
+ "t",
+ "w",
+ NULL
+};
+
+//------------------------------------------------------------------------
+
+static inline int size(int len) {
+ int delta;
+ for (delta = 8; delta < len && delta < 0x100000; delta <<= 1) ;
+ // this is ((len + 1) + (delta - 1)) & ~(delta - 1)
+ return (len + delta) & ~(delta - 1);
+}
+
+inline void GString::resize(int length1) {
+ char *s1;
+
+ if (!s) {
+ s = new char[size(length1)];
+ } else if (size(length1) != size(length)) {
+ s1 = new char[size(length1)];
+ if (length1 < length) {
+ memcpy(s1, s, length1);
+ s1[length1] = '\0';
+ } else {
+ memcpy(s1, s, length + 1);
+ }
+ delete[] s;
+ s = s1;
+ }
+}
+
+GString::GString() {
+ s = NULL;
+ resize(length = 0);
+ s[0] = '\0';
+}
+
+GString::GString(const char *sA) {
+ int n = strlen(sA);
+
+ s = NULL;
+ resize(length = n);
+ memcpy(s, sA, n + 1);
+}
+
+GString::GString(const char *sA, int lengthA) {
+ s = NULL;
+ resize(length = lengthA);
+ memcpy(s, sA, length * sizeof(char));
+ s[length] = '\0';
+}
+
+GString::GString(GString *str, int idx, int lengthA) {
+ s = NULL;
+ resize(length = lengthA);
+ memcpy(s, str->getCString() + idx, length);
+ s[length] = '\0';
+}
+
+GString::GString(GString *str) {
+ s = NULL;
+ resize(length = str->getLength());
+ memcpy(s, str->getCString(), length + 1);
+}
+
+GString::GString(GString *str1, GString *str2) {
+ int n1 = str1->getLength();
+ int n2 = str2->getLength();
+
+ s = NULL;
+ resize(length = n1 + n2);
+ memcpy(s, str1->getCString(), n1);
+ memcpy(s + n1, str2->getCString(), n2 + 1);
+}
+
+GString *GString::fromInt(int x) {
+ char buf[24]; // enough space for 64-bit ints plus a little extra
+ char *p;
+ int len;
+
+ formatInt(x, buf, sizeof(buf), gFalse, 0, 10, &p, &len);
+ return new GString(p, len);
+}
+
+GString *GString::format(char *fmt, ...) {
+ va_list argList;
+ GString *s;
+
+ s = new GString();
+ va_start(argList, fmt);
+ s->appendfv(fmt, argList);
+ va_end(argList);
+ return s;
+}
+
+GString *GString::formatv(char *fmt, va_list argList) {
+ GString *s;
+
+ s = new GString();
+ s->appendfv(fmt, argList);
+ return s;
+}
+
+GString::~GString() {
+ delete[] s;
+}
+
+GString *GString::clear() {
+ s[length = 0] = '\0';
+ resize(0);
+ return this;
+}
+
+GString *GString::append(char c) {
+ resize(length + 1);
+ s[length++] = c;
+ s[length] = '\0';
+ return this;
+}
+
+GString *GString::append(GString *str) {
+ int n = str->getLength();
+
+ resize(length + n);
+ memcpy(s + length, str->getCString(), n + 1);
+ length += n;
+ return this;
+}
+
+GString *GString::append(const char *str) {
+ int n = strlen(str);
+
+ resize(length + n);
+ memcpy(s + length, str, n + 1);
+ length += n;
+ return this;
+}
+
+GString *GString::append(const char *str, int lengthA) {
+ resize(length + lengthA);
+ memcpy(s + length, str, lengthA);
+ length += lengthA;
+ s[length] = '\0';
+ return this;
+}
+
+GString *GString::appendf(char *fmt, ...) {
+ va_list argList;
+
+ va_start(argList, fmt);
+ appendfv(fmt, argList);
+ va_end(argList);
+ return this;
+}
+
+GString *GString::appendfv(char *fmt, va_list argList) {
+ GStringFormatArg *args;
+ int argsLen, argsSize;
+ GStringFormatArg arg;
+ int idx, width, prec;
+ GBool reverseAlign, zeroFill;
+ GStringFormatType ft;
+ char buf[65];
+ int len, i;
+ char *p0, *p1, *str;
+
+ argsLen = 0;
+ argsSize = 8;
+ args = (GStringFormatArg *)gmallocn(argsSize, sizeof(GStringFormatArg));
+
+ p0 = fmt;
+ while (*p0) {
+ if (*p0 == '{') {
+ ++p0;
+ if (*p0 == '{') {
+ ++p0;
+ append('{');
+ } else {
+
+ // parse the format string
+ if (!(*p0 >= '0' && *p0 <= '9')) {
+ break;
+ }
+ idx = *p0 - '0';
+ for (++p0; *p0 >= '0' && *p0 <= '9'; ++p0) {
+ idx = 10 * idx + (*p0 - '0');
+ }
+ if (*p0 != ':') {
+ break;
+ }
+ ++p0;
+ if (*p0 == '-') {
+ reverseAlign = gTrue;
+ ++p0;
+ } else {
+ reverseAlign = gFalse;
+ }
+ width = 0;
+ zeroFill = *p0 == '0';
+ for (; *p0 >= '0' && *p0 <= '9'; ++p0) {
+ width = 10 * width + (*p0 - '0');
+ }
+ if (*p0 == '.') {
+ ++p0;
+ prec = 0;
+ for (; *p0 >= '0' && *p0 <= '9'; ++p0) {
+ prec = 10 * prec + (*p0 - '0');
+ }
+ } else {
+ prec = 0;
+ }
+ for (ft = (GStringFormatType)0;
+ formatStrings[ft];
+ ft = (GStringFormatType)(ft + 1)) {
+ if (!strncmp(p0, formatStrings[ft], strlen(formatStrings[ft]))) {
+ break;
+ }
+ }
+ if (!formatStrings[ft]) {
+ break;
+ }
+ p0 += strlen(formatStrings[ft]);
+ if (*p0 != '}') {
+ break;
+ }
+ ++p0;
+
+ // fetch the argument
+ if (idx > argsLen) {
+ break;
+ }
+ if (idx == argsLen) {
+ if (argsLen == argsSize) {
+ argsSize *= 2;
+ args = (GStringFormatArg *)greallocn(args, argsSize,
+ sizeof(GStringFormatArg));
+ }
+ switch (ft) {
+ case fmtIntDecimal:
+ case fmtIntHex:
+ case fmtIntOctal:
+ case fmtIntBinary:
+ case fmtSpace:
+ args[argsLen].i = va_arg(argList, int);
+ break;
+ case fmtUIntDecimal:
+ case fmtUIntHex:
+ case fmtUIntOctal:
+ case fmtUIntBinary:
+ args[argsLen].ui = va_arg(argList, Guint);
+ break;
+ case fmtLongDecimal:
+ case fmtLongHex:
+ case fmtLongOctal:
+ case fmtLongBinary:
+ args[argsLen].l = va_arg(argList, long);
+ break;
+ case fmtULongDecimal:
+ case fmtULongHex:
+ case fmtULongOctal:
+ case fmtULongBinary:
+ args[argsLen].ul = va_arg(argList, Gulong);
+ break;
+ case fmtDouble:
+ case fmtDoubleTrim:
+ args[argsLen].f = va_arg(argList, double);
+ break;
+ case fmtChar:
+ args[argsLen].c = (char)va_arg(argList, int);
+ break;
+ case fmtString:
+ args[argsLen].s = va_arg(argList, char *);
+ break;
+ case fmtGString:
+ args[argsLen].gs = va_arg(argList, GString *);
+ break;
+ }
+ ++argsLen;
+ }
+
+ // format the argument
+ arg = args[idx];
+ switch (ft) {
+ case fmtIntDecimal:
+ formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 10, &str, &len);
+ break;
+ case fmtIntHex:
+ formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 16, &str, &len);
+ break;
+ case fmtIntOctal:
+ formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
+ break;
+ case fmtIntBinary:
+ formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
+ break;
+ case fmtUIntDecimal:
+ formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 10,
+ &str, &len);
+ break;
+ case fmtUIntHex:
+ formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 16,
+ &str, &len);
+ break;
+ case fmtUIntOctal:
+ formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
+ break;
+ case fmtUIntBinary:
+ formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
+ break;
+ case fmtLongDecimal:
+ formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 10, &str, &len);
+ break;
+ case fmtLongHex:
+ formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 16, &str, &len);
+ break;
+ case fmtLongOctal:
+ formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
+ break;
+ case fmtLongBinary:
+ formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
+ break;
+ case fmtULongDecimal:
+ formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 10,
+ &str, &len);
+ break;
+ case fmtULongHex:
+ formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 16,
+ &str, &len);
+ break;
+ case fmtULongOctal:
+ formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 8, &str, &len);
+ break;
+ case fmtULongBinary:
+ formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 2, &str, &len);
+ break;
+ case fmtDouble:
+ formatDouble(arg.f, buf, sizeof(buf), prec, gFalse, &str, &len);
+ break;
+ case fmtDoubleTrim:
+ formatDouble(arg.f, buf, sizeof(buf), prec, gTrue, &str, &len);
+ break;
+ case fmtChar:
+ buf[0] = arg.c;
+ str = buf;
+ len = 1;
+ reverseAlign = !reverseAlign;
+ break;
+ case fmtString:
+ str = arg.s;
+ len = strlen(str);
+ reverseAlign = !reverseAlign;
+ break;
+ case fmtGString:
+ str = arg.gs->getCString();
+ len = arg.gs->getLength();
+ reverseAlign = !reverseAlign;
+ break;
+ case fmtSpace:
+ str = buf;
+ len = 0;
+ width = arg.i;
+ break;
+ }
+
+ // append the formatted arg, handling width and alignment
+ if (!reverseAlign && len < width) {
+ for (i = len; i < width; ++i) {
+ append(' ');
+ }
+ }
+ append(str, len);
+ if (reverseAlign && len < width) {
+ for (i = len; i < width; ++i) {
+ append(' ');
+ }
+ }
+ }
+
+ } else if (*p0 == '}') {
+ ++p0;
+ if (*p0 == '}') {
+ ++p0;
+ }
+ append('}');
+
+ } else {
+ for (p1 = p0 + 1; *p1 && *p1 != '{' && *p1 != '}'; ++p1) ;
+ append(p0, p1 - p0);
+ p0 = p1;
+ }
+ }
+
+ gfree(args);
+ return this;
+}
+
+void GString::formatInt(long x, char *buf, int bufSize,
+ GBool zeroFill, int width, int base,
+ char **p, int *len) {
+ static char vals[17] = "0123456789abcdef";
+ GBool neg;
+ int start, i, j;
+
+ i = bufSize;
+ if ((neg = x < 0)) {
+ x = -x;
+ }
+ start = neg ? 1 : 0;
+ if (x == 0) {
+ buf[--i] = '0';
+ } else {
+ while (i > start && x) {
+ buf[--i] = vals[x % base];
+ x /= base;
+ }
+ }
+ if (zeroFill) {
+ for (j = bufSize - i; i > start && j < width - start; ++j) {
+ buf[--i] = '0';
+ }
+ }
+ if (neg) {
+ buf[--i] = '-';
+ }
+ *p = buf + i;
+ *len = bufSize - i;
+}
+
+void GString::formatUInt(Gulong x, char *buf, int bufSize,
+ GBool zeroFill, int width, int base,
+ char **p, int *len) {
+ static char vals[17] = "0123456789abcdef";
+ int i, j;
+
+ i = bufSize;
+ if (x == 0) {
+ buf[--i] = '0';
+ } else {
+ while (i > 0 && x) {
+ buf[--i] = vals[x % base];
+ x /= base;
+ }
+ }
+ if (zeroFill) {
+ for (j = bufSize - i; i > 0 && j < width; ++j) {
+ buf[--i] = '0';
+ }
+ }
+ *p = buf + i;
+ *len = bufSize - i;
+}
+
+void GString::formatDouble(double x, char *buf, int bufSize, int prec,
+ GBool trim, char **p, int *len) {
+ GBool neg, started;
+ double x2;
+ int d, i, j;
+
+ if ((neg = x < 0)) {
+ x = -x;
+ }
+ x = floor(x * pow(10, prec) + 0.5);
+ i = bufSize;
+ started = !trim;
+ for (j = 0; j < prec && i > 1; ++j) {
+ x2 = floor(0.1 * (x + 0.5));
+ d = (int)floor(x - 10 * x2 + 0.5);
+ if (started || d != 0) {
+ buf[--i] = '0' + d;
+ started = gTrue;
+ }
+ x = x2;
+ }
+ if (i > 1 && started) {
+ buf[--i] = '.';
+ }
+ if (i > 1) {
+ do {
+ x2 = floor(0.1 * (x + 0.5));
+ d = (int)floor(x - 10 * x2 + 0.5);
+ buf[--i] = '0' + d;
+ x = x2;
+ } while (i > 1 && x);
+ }
+ if (neg) {
+ buf[--i] = '-';
+ }
+ *p = buf + i;
+ *len = bufSize - i;
+}
+
+GString *GString::insert(int i, char c) {
+ int j;
+
+ resize(length + 1);
+ for (j = length + 1; j > i; --j)
+ s[j] = s[j-1];
+ s[i] = c;
+ ++length;
+ return this;
+}
+
+GString *GString::insert(int i, GString *str) {
+ int n = str->getLength();
+ int j;
+
+ resize(length + n);
+ for (j = length; j >= i; --j)
+ s[j+n] = s[j];
+ memcpy(s+i, str->getCString(), n);
+ length += n;
+ return this;
+}
+
+GString *GString::insert(int i, const char *str) {
+ int n = strlen(str);
+ int j;
+
+ resize(length + n);
+ for (j = length; j >= i; --j)
+ s[j+n] = s[j];
+ memcpy(s+i, str, n);
+ length += n;
+ return this;
+}
+
+GString *GString::insert(int i, const char *str, int lengthA) {
+ int j;
+
+ resize(length + lengthA);
+ for (j = length; j >= i; --j)
+ s[j+lengthA] = s[j];
+ memcpy(s+i, str, lengthA);
+ length += lengthA;
+ return this;
+}
+
+GString *GString::del(int i, int n) {
+ int j;
+
+ if (n > 0) {
+ if (i + n > length) {
+ n = length - i;
+ }
+ for (j = i; j <= length - n; ++j) {
+ s[j] = s[j + n];
+ }
+ resize(length -= n);
+ }
+ return this;
+}
+
+GString *GString::upperCase() {
+ int i;
+
+ for (i = 0; i < length; ++i) {
+ if (islower(s[i]))
+ s[i] = toupper(s[i]);
+ }
+ return this;
+}
+
+GString *GString::lowerCase() {
+ int i;
+
+ for (i = 0; i < length; ++i) {
+ if (isupper(s[i]))
+ s[i] = tolower(s[i]);
+ }
+ return this;
+}
+
+int GString::cmp(GString *str) {
+ int n1, n2, i, x;
+ char *p1, *p2;
+
+ n1 = length;
+ n2 = str->length;
+ for (i = 0, p1 = s, p2 = str->s; i < n1 && i < n2; ++i, ++p1, ++p2) {
+ x = *p1 - *p2;
+ if (x != 0) {
+ return x;
+ }
+ }
+ return n1 - n2;
+}
+
+int GString::cmpN(GString *str, int n) {
+ int n1, n2, i, x;
+ char *p1, *p2;
+
+ n1 = length;
+ n2 = str->length;
+ for (i = 0, p1 = s, p2 = str->s;
+ i < n1 && i < n2 && i < n;
+ ++i, ++p1, ++p2) {
+ x = *p1 - *p2;
+ if (x != 0) {
+ return x;
+ }
+ }
+ if (i == n) {
+ return 0;
+ }
+ return n1 - n2;
+}
+
+int GString::cmp(const char *sA) {
+ int n1, i, x;
+ const char *p1, *p2;
+
+ n1 = length;
+ for (i = 0, p1 = s, p2 = sA; i < n1 && *p2; ++i, ++p1, ++p2) {
+ x = *p1 - *p2;
+ if (x != 0) {
+ return x;
+ }
+ }
+ if (i < n1) {
+ return 1;
+ }
+ if (*p2) {
+ return -1;
+ }
+ return 0;
+}
+
+int GString::cmpN(const char *sA, int n) {
+ int n1, i, x;
+ const char *p1, *p2;
+
+ n1 = length;
+ for (i = 0, p1 = s, p2 = sA; i < n1 && *p2 && i < n; ++i, ++p1, ++p2) {
+ x = *p1 - *p2;
+ if (x != 0) {
+ return x;
+ }
+ }
+ if (i == n) {
+ return 0;
+ }
+ if (i < n1) {
+ return 1;
+ }
+ if (*p2) {
+ return -1;
+ }
+ return 0;
+}
diff --git a/kpdf/xpdf/goo/GString.h b/kpdf/xpdf/goo/GString.h
new file mode 100644
index 00000000..dd22e2d8
--- /dev/null
+++ b/kpdf/xpdf/goo/GString.h
@@ -0,0 +1,136 @@
+//========================================================================
+//
+// GString.h
+//
+// Simple variable-length string type.
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef GSTRING_H
+#define GSTRING_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include <stdarg.h>
+#include "gtypes.h"
+
+class GString {
+public:
+
+ // Create an empty string.
+ GString();
+
+ // Create a string from a C string.
+ GString(const char *sA);
+
+ // Create a string from <lengthA> chars at <sA>. This string
+ // can contain null characters.
+ GString(const char *sA, int lengthA);
+
+ // Create a string from <lengthA> chars at <idx> in <str>.
+ GString(GString *str, int idx, int lengthA);
+
+ // Copy a string.
+ GString(GString *str);
+ GString *copy() { return new GString(this); }
+
+ // Concatenate two strings.
+ GString(GString *str1, GString *str2);
+
+ // Convert an integer to a string.
+ static GString *fromInt(int x);
+
+ // Create a formatted string. Similar to printf, but without the
+ // string overflow issues. Formatting elements consist of:
+ // {<arg>:[<width>][.<precision>]<type>}
+ // where:
+ // - <arg> is the argument number (arg 0 is the first argument
+ // following the format string) -- NB: args must be first used in
+ // order; they can be reused in any order
+ // - <width> is the field width -- negative to reverse the alignment;
+ // starting with a leading zero to zero-fill (for integers)
+ // - <precision> is the number of digits to the right of the decimal
+ // point (for floating point numbers)
+ // - <type> is one of:
+ // d, x, o, b -- int in decimal, hex, octal, binary
+ // ud, ux, uo, ub -- unsigned int
+ // ld, lx, lo, lb, uld, ulx, ulo, ulb -- long, unsigned long
+ // f, g -- double
+ // c -- char
+ // s -- string (char *)
+ // t -- GString *
+ // w -- blank space; arg determines width
+ // To get literal curly braces, use {{ or }}.
+ static GString *format(char *fmt, ...);
+ static GString *formatv(char *fmt, va_list argList);
+
+ // Destructor.
+ ~GString();
+
+ // Get length.
+ int getLength() { return length; }
+
+ // Get C string.
+ char *getCString() { return s; }
+
+ // Get <i>th character.
+ char getChar(int i) { return s[i]; }
+
+ // Change <i>th character.
+ void setChar(int i, char c) { s[i] = c; }
+
+ // Clear string to zero length.
+ GString *clear();
+
+ // Append a character or string.
+ GString *append(char c);
+ GString *append(GString *str);
+ GString *append(const char *str);
+ GString *append(const char *str, int lengthA);
+
+ // Append a formatted string.
+ GString *appendf(char *fmt, ...);
+ GString *appendfv(char *fmt, va_list argList);
+
+ // Insert a character or string.
+ GString *insert(int i, char c);
+ GString *insert(int i, GString *str);
+ GString *insert(int i, const char *str);
+ GString *insert(int i, const char *str, int lengthA);
+
+ // Delete a character or range of characters.
+ GString *del(int i, int n = 1);
+
+ // Convert string to all-upper/all-lower case.
+ GString *upperCase();
+ GString *lowerCase();
+
+ // Compare two strings: -1:< 0:= +1:>
+ int cmp(GString *str);
+ int cmpN(GString *str, int n);
+ int cmp(const char *sA);
+ int cmpN(const char *sA, int n);
+
+private:
+
+ int length;
+ char *s;
+
+ void resize(int length1);
+ static void formatInt(long x, char *buf, int bufSize,
+ GBool zeroFill, int width, int base,
+ char **p, int *len);
+ static void formatUInt(Gulong x, char *buf, int bufSize,
+ GBool zeroFill, int width, int base,
+ char **p, int *len);
+ static void formatDouble(double x, char *buf, int bufSize, int prec,
+ GBool trim, char **p, int *len);
+};
+
+#endif
diff --git a/kpdf/xpdf/goo/Makefile.am b/kpdf/xpdf/goo/Makefile.am
new file mode 100644
index 00000000..04933cee
--- /dev/null
+++ b/kpdf/xpdf/goo/Makefile.am
@@ -0,0 +1,5 @@
+INCLUDES = -I$(srcdir)/..
+
+libgoo_la_SOURCES = GHash.cc GList.cc GString.cc gfile.cc gmem.cc gmempp.cc
+
+noinst_LTLIBRARIES = libgoo.la
diff --git a/kpdf/xpdf/goo/gfile.cc b/kpdf/xpdf/goo/gfile.cc
new file mode 100644
index 00000000..54a7be3d
--- /dev/null
+++ b/kpdf/xpdf/goo/gfile.cc
@@ -0,0 +1,731 @@
+//========================================================================
+//
+// gfile.cc
+//
+// Miscellaneous file and directory name manipulation.
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef WIN32
+# include <time.h>
+#else
+# if defined(MACOS)
+# include <sys/stat.h>
+# elif !defined(ACORN)
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <fcntl.h>
+# endif
+# include <limits.h>
+# include <string.h>
+# if !defined(VMS) && !defined(ACORN) && !defined(MACOS)
+# include <pwd.h>
+# endif
+# if defined(VMS) && (__DECCXX_VER < 50200000)
+# include <unixlib.h>
+# endif
+#endif // WIN32
+#include "GString.h"
+#include "gfile.h"
+
+// Some systems don't define this, so just make it something reasonably
+// large.
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+//------------------------------------------------------------------------
+
+GString *getHomeDir() {
+#ifdef VMS
+ //---------- VMS ----------
+ return new GString("SYS$LOGIN:");
+
+#elif defined(__EMX__) || defined(WIN32)
+ //---------- OS/2+EMX and Win32 ----------
+ char *s;
+ GString *ret;
+
+ if ((s = getenv("HOME")))
+ ret = new GString(s);
+ else
+ ret = new GString(".");
+ return ret;
+
+#elif defined(ACORN)
+ //---------- RISCOS ----------
+ return new GString("@");
+
+#elif defined(MACOS)
+ //---------- MacOS ----------
+ return new GString(":");
+
+#else
+ //---------- Unix ----------
+ char *s;
+ struct passwd *pw;
+ GString *ret;
+
+ if ((s = getenv("HOME"))) {
+ ret = new GString(s);
+ } else {
+ if ((s = getenv("USER")))
+ pw = getpwnam(s);
+ else
+ pw = getpwuid(getuid());
+ if (pw)
+ ret = new GString(pw->pw_dir);
+ else
+ ret = new GString(".");
+ }
+ return ret;
+#endif
+}
+
+GString *getCurrentDir() {
+ char buf[PATH_MAX+1];
+
+#if defined(__EMX__)
+ if (_getcwd2(buf, sizeof(buf)))
+#elif defined(WIN32)
+ if (GetCurrentDirectory(sizeof(buf), buf))
+#elif defined(ACORN)
+ if (strcpy(buf, "@"))
+#elif defined(MACOS)
+ if (strcpy(buf, ":"))
+#else
+ if (getcwd(buf, sizeof(buf)))
+#endif
+ return new GString(buf);
+ return new GString();
+}
+
+GString *appendToPath(GString *path, char *fileName) {
+#if defined(VMS)
+ //---------- VMS ----------
+ //~ this should handle everything necessary for file
+ //~ requesters, but it's certainly not complete
+ char *p0, *p1, *p2;
+ char *q1;
+
+ p0 = path->getCString();
+ p1 = p0 + path->getLength() - 1;
+ if (!strcmp(fileName, "-")) {
+ if (*p1 == ']') {
+ for (p2 = p1; p2 > p0 && *p2 != '.' && *p2 != '['; --p2) ;
+ if (*p2 == '[')
+ ++p2;
+ path->del(p2 - p0, p1 - p2);
+ } else if (*p1 == ':') {
+ path->append("[-]");
+ } else {
+ path->clear();
+ path->append("[-]");
+ }
+ } else if ((q1 = strrchr(fileName, '.')) && !strncmp(q1, ".DIR;", 5)) {
+ if (*p1 == ']') {
+ path->insert(p1 - p0, '.');
+ path->insert(p1 - p0 + 1, fileName, q1 - fileName);
+ } else if (*p1 == ':') {
+ path->append('[');
+ path->append(']');
+ path->append(fileName, q1 - fileName);
+ } else {
+ path->clear();
+ path->append(fileName, q1 - fileName);
+ }
+ } else {
+ if (*p1 != ']' && *p1 != ':')
+ path->clear();
+ path->append(fileName);
+ }
+ return path;
+
+#elif defined(WIN32)
+ //---------- Win32 ----------
+ GString *tmp;
+ char buf[256];
+ char *fp;
+
+ tmp = new GString(path);
+ tmp->append('/');
+ tmp->append(fileName);
+ GetFullPathName(tmp->getCString(), sizeof(buf), buf, &fp);
+ delete tmp;
+ path->clear();
+ path->append(buf);
+ return path;
+
+#elif defined(ACORN)
+ //---------- RISCOS ----------
+ char *p;
+ int i;
+
+ path->append(".");
+ i = path->getLength();
+ path->append(fileName);
+ for (p = path->getCString() + i; *p; ++p) {
+ if (*p == '/') {
+ *p = '.';
+ } else if (*p == '.') {
+ *p = '/';
+ }
+ }
+ return path;
+
+#elif defined(MACOS)
+ //---------- MacOS ----------
+ char *p;
+ int i;
+
+ path->append(":");
+ i = path->getLength();
+ path->append(fileName);
+ for (p = path->getCString() + i; *p; ++p) {
+ if (*p == '/') {
+ *p = ':';
+ } else if (*p == '.') {
+ *p = ':';
+ }
+ }
+ return path;
+
+#elif defined(__EMX__)
+ //---------- OS/2+EMX ----------
+ int i;
+
+ // appending "." does nothing
+ if (!strcmp(fileName, "."))
+ return path;
+
+ // appending ".." goes up one directory
+ if (!strcmp(fileName, "..")) {
+ for (i = path->getLength() - 2; i >= 0; --i) {
+ if (path->getChar(i) == '/' || path->getChar(i) == '\\' ||
+ path->getChar(i) == ':')
+ break;
+ }
+ if (i <= 0) {
+ if (path->getChar(0) == '/' || path->getChar(0) == '\\') {
+ path->del(1, path->getLength() - 1);
+ } else if (path->getLength() >= 2 && path->getChar(1) == ':') {
+ path->del(2, path->getLength() - 2);
+ } else {
+ path->clear();
+ path->append("..");
+ }
+ } else {
+ if (path->getChar(i-1) == ':')
+ ++i;
+ path->del(i, path->getLength() - i);
+ }
+ return path;
+ }
+
+ // otherwise, append "/" and new path component
+ if (path->getLength() > 0 &&
+ path->getChar(path->getLength() - 1) != '/' &&
+ path->getChar(path->getLength() - 1) != '\\')
+ path->append('/');
+ path->append(fileName);
+ return path;
+
+#else
+ //---------- Unix ----------
+ int i;
+
+ // appending "." does nothing
+ if (!strcmp(fileName, "."))
+ return path;
+
+ // appending ".." goes up one directory
+ if (!strcmp(fileName, "..")) {
+ for (i = path->getLength() - 2; i >= 0; --i) {
+ if (path->getChar(i) == '/')
+ break;
+ }
+ if (i <= 0) {
+ if (path->getChar(0) == '/') {
+ path->del(1, path->getLength() - 1);
+ } else {
+ path->clear();
+ path->append("..");
+ }
+ } else {
+ path->del(i, path->getLength() - i);
+ }
+ return path;
+ }
+
+ // otherwise, append "/" and new path component
+ if (path->getLength() > 0 &&
+ path->getChar(path->getLength() - 1) != '/')
+ path->append('/');
+ path->append(fileName);
+ return path;
+#endif
+}
+
+GString *grabPath(char *fileName) {
+#ifdef VMS
+ //---------- VMS ----------
+ char *p;
+
+ if ((p = strrchr(fileName, ']')))
+ return new GString(fileName, p + 1 - fileName);
+ if ((p = strrchr(fileName, ':')))
+ return new GString(fileName, p + 1 - fileName);
+ return new GString();
+
+#elif defined(__EMX__) || defined(WIN32)
+ //---------- OS/2+EMX and Win32 ----------
+ char *p;
+
+ if ((p = strrchr(fileName, '/')))
+ return new GString(fileName, p - fileName);
+ if ((p = strrchr(fileName, '\\')))
+ return new GString(fileName, p - fileName);
+ if ((p = strrchr(fileName, ':')))
+ return new GString(fileName, p + 1 - fileName);
+ return new GString();
+
+#elif defined(ACORN)
+ //---------- RISCOS ----------
+ char *p;
+
+ if ((p = strrchr(fileName, '.')))
+ return new GString(fileName, p - fileName);
+ return new GString();
+
+#elif defined(MACOS)
+ //---------- MacOS ----------
+ char *p;
+
+ if ((p = strrchr(fileName, ':')))
+ return new GString(fileName, p - fileName);
+ return new GString();
+
+#else
+ //---------- Unix ----------
+ char *p;
+
+ if ((p = strrchr(fileName, '/')))
+ return new GString(fileName, p - fileName);
+ return new GString();
+#endif
+}
+
+GBool isAbsolutePath(char *path) {
+#ifdef VMS
+ //---------- VMS ----------
+ return strchr(path, ':') ||
+ (path[0] == '[' && path[1] != '.' && path[1] != '-');
+
+#elif defined(__EMX__) || defined(WIN32)
+ //---------- OS/2+EMX and Win32 ----------
+ return path[0] == '/' || path[0] == '\\' || path[1] == ':';
+
+#elif defined(ACORN)
+ //---------- RISCOS ----------
+ return path[0] == '$';
+
+#elif defined(MACOS)
+ //---------- MacOS ----------
+ return path[0] != ':';
+
+#else
+ //---------- Unix ----------
+ return path[0] == '/';
+#endif
+}
+
+GString *makePathAbsolute(GString *path) {
+#ifdef VMS
+ //---------- VMS ----------
+ char buf[PATH_MAX+1];
+
+ if (!isAbsolutePath(path->getCString())) {
+ if (getcwd(buf, sizeof(buf))) {
+ path->insert(0, buf);
+ }
+ }
+ return path;
+
+#elif defined(WIN32)
+ //---------- Win32 ----------
+ char buf[_MAX_PATH];
+ char *fp;
+
+ buf[0] = '\0';
+ if (!GetFullPathName(path->getCString(), _MAX_PATH, buf, &fp)) {
+ path->clear();
+ return path;
+ }
+ path->clear();
+ path->append(buf);
+ return path;
+
+#elif defined(ACORN)
+ //---------- RISCOS ----------
+ path->insert(0, '@');
+ return path;
+
+#elif defined(MACOS)
+ //---------- MacOS ----------
+ path->del(0, 1);
+ return path;
+
+#else
+ //---------- Unix and OS/2+EMX ----------
+ struct passwd *pw;
+ char buf[PATH_MAX+1];
+ GString *s;
+ char *p1, *p2;
+ int n;
+
+ if (path->getChar(0) == '~') {
+ if (path->getChar(1) == '/' ||
+#ifdef __EMX__
+ path->getChar(1) == '\\' ||
+#endif
+ path->getLength() == 1) {
+ path->del(0, 1);
+ s = getHomeDir();
+ path->insert(0, s);
+ delete s;
+ } else {
+ p1 = path->getCString() + 1;
+#ifdef __EMX__
+ for (p2 = p1; *p2 && *p2 != '/' && *p2 != '\\'; ++p2) ;
+#else
+ for (p2 = p1; *p2 && *p2 != '/'; ++p2) ;
+#endif
+ if ((n = p2 - p1) > PATH_MAX)
+ n = PATH_MAX;
+ strncpy(buf, p1, n);
+ buf[n] = '\0';
+ if ((pw = getpwnam(buf))) {
+ path->del(0, p2 - p1 + 1);
+ path->insert(0, pw->pw_dir);
+ }
+ }
+ } else if (!isAbsolutePath(path->getCString())) {
+ if (getcwd(buf, sizeof(buf))) {
+#ifndef __EMX__
+ path->insert(0, '/');
+#endif
+ path->insert(0, buf);
+ }
+ }
+ return path;
+#endif
+}
+
+time_t getModTime(char *fileName) {
+#ifdef WIN32
+ //~ should implement this, but it's (currently) only used in xpdf
+ return 0;
+#else
+ struct stat statBuf;
+
+ if (stat(fileName, &statBuf)) {
+ return 0;
+ }
+ return statBuf.st_mtime;
+#endif
+}
+
+GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) {
+#if defined(WIN32)
+ //---------- Win32 ----------
+ char *tempDir;
+ GString *s, *s2;
+ char buf[32];
+ FILE *f2;
+ int t, i;
+
+ // this has the standard race condition problem, but I haven't found
+ // a better way to generate temp file names with extensions on
+ // Windows
+ if ((tempDir = getenv("TEMP"))) {
+ s = new GString(tempDir);
+ s->append('\\');
+ } else {
+ s = new GString();
+ }
+ s->append("x");
+ t = (int)time(NULL);
+ for (i = 0; i < 1000; ++i) {
+ sprintf(buf, "%d", t + i);
+ s2 = s->copy()->append(buf);
+ if (ext) {
+ s2->append(ext);
+ }
+ if (!(f2 = fopen(s2->getCString(), "r"))) {
+ if (!(f2 = fopen(s2->getCString(), mode))) {
+ delete s2;
+ delete s;
+ return gFalse;
+ }
+ *name = s2;
+ *f = f2;
+ delete s;
+ return gTrue;
+ }
+ fclose(f2);
+ delete s2;
+ }
+ delete s;
+ return gFalse;
+#elif defined(VMS) || defined(__EMX__) || defined(ACORN) || defined(MACOS)
+ //---------- non-Unix ----------
+ char *s;
+
+ // There is a security hole here: an attacker can create a symlink
+ // with this file name after the tmpnam call and before the fopen
+ // call. I will happily accept fixes to this function for non-Unix
+ // OSs.
+ if (!(s = tmpnam(NULL))) {
+ return gFalse;
+ }
+ *name = new GString(s);
+ if (ext) {
+ (*name)->append(ext);
+ }
+ if (!(*f = fopen((*name)->getCString(), mode))) {
+ delete (*name);
+ return gFalse;
+ }
+ return gTrue;
+#else
+ //---------- Unix ----------
+ char *s;
+ int fd;
+
+ if (ext) {
+#if HAVE_MKSTEMPS
+ if ((s = getenv("TMPDIR"))) {
+ *name = new GString(s);
+ } else {
+ *name = new GString("/tmp");
+ }
+ (*name)->append("/XXXXXX")->append(ext);
+ fd = mkstemps((*name)->getCString(), strlen(ext));
+#else
+ if (!(s = tmpnam(NULL))) {
+ return gFalse;
+ }
+ *name = new GString(s);
+ (*name)->append(ext);
+ fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
+#endif
+ } else {
+#if HAVE_MKSTEMP
+ if ((s = getenv("TMPDIR"))) {
+ *name = new GString(s);
+ } else {
+ *name = new GString("/tmp");
+ }
+ (*name)->append("/XXXXXX");
+ fd = mkstemp((*name)->getCString());
+#else // HAVE_MKSTEMP
+ if (!(s = tmpnam(NULL))) {
+ return gFalse;
+ }
+ *name = new GString(s);
+ fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
+#endif // HAVE_MKSTEMP
+ }
+ if (fd < 0 || !(*f = fdopen(fd, mode))) {
+ delete *name;
+ return gFalse;
+ }
+ return gTrue;
+#endif
+}
+
+GBool executeCommand(char *cmd) {
+#ifdef VMS
+ return system(cmd) ? gTrue : gFalse;
+#else
+ return system(cmd) ? gFalse : gTrue;
+#endif
+}
+
+char *getLine(char *buf, int size, FILE *f) {
+ int c, i;
+
+ i = 0;
+ while (i < size - 1) {
+ if ((c = fgetc(f)) == EOF) {
+ break;
+ }
+ buf[i++] = (char)c;
+ if (c == '\x0a') {
+ break;
+ }
+ if (c == '\x0d') {
+ c = fgetc(f);
+ if (c == '\x0a' && i < size - 1) {
+ buf[i++] = (char)c;
+ } else if (c != EOF) {
+ ungetc(c, f);
+ }
+ break;
+ }
+ }
+ buf[i] = '\0';
+ if (i == 0) {
+ return NULL;
+ }
+ return buf;
+}
+
+//------------------------------------------------------------------------
+// GDir and GDirEntry
+//------------------------------------------------------------------------
+
+GDirEntry::GDirEntry(char *dirPath, char *nameA, GBool doStat) {
+#ifdef VMS
+ char *p;
+#elif defined(WIN32)
+ int fa;
+ GString *s;
+#elif defined(ACORN)
+#else
+ struct stat st;
+ GString *s;
+#endif
+
+ name = new GString(nameA);
+ dir = gFalse;
+ if (doStat) {
+#ifdef VMS
+ if (!strcmp(nameA, "-") ||
+ ((p = strrchr(nameA, '.')) && !strncmp(p, ".DIR;", 5)))
+ dir = gTrue;
+#elif defined(ACORN)
+#else
+ s = new GString(dirPath);
+ appendToPath(s, nameA);
+#ifdef WIN32
+ fa = GetFileAttributes(s->getCString());
+ dir = (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY));
+#else
+ if (stat(s->getCString(), &st) == 0)
+ dir = S_ISDIR(st.st_mode);
+#endif
+ delete s;
+#endif
+ }
+}
+
+GDirEntry::~GDirEntry() {
+ delete name;
+}
+
+GDir::GDir(char *name, GBool doStatA) {
+ path = new GString(name);
+ doStat = doStatA;
+#if defined(WIN32)
+ GString *tmp;
+
+ tmp = path->copy();
+ tmp->append("/*.*");
+ hnd = FindFirstFile(tmp->getCString(), &ffd);
+ delete tmp;
+#elif defined(ACORN)
+#elif defined(MACOS)
+#else
+ dir = opendir(name);
+#ifdef VMS
+ needParent = strchr(name, '[') != NULL;
+#endif
+#endif
+}
+
+GDir::~GDir() {
+ delete path;
+#if defined(WIN32)
+ if (hnd) {
+ FindClose(hnd);
+ hnd = NULL;
+ }
+#elif defined(ACORN)
+#elif defined(MACOS)
+#else
+ if (dir)
+ closedir(dir);
+#endif
+}
+
+GDirEntry *GDir::getNextEntry() {
+ GDirEntry *e;
+
+#if defined(WIN32)
+ if (hnd) {
+ e = new GDirEntry(path->getCString(), ffd.cFileName, doStat);
+ if (hnd && !FindNextFile(hnd, &ffd)) {
+ FindClose(hnd);
+ hnd = NULL;
+ }
+ } else {
+ e = NULL;
+ }
+#elif defined(ACORN)
+#elif defined(MACOS)
+#elif defined(VMS)
+ struct dirent *ent;
+ e = NULL;
+ if (dir) {
+ if (needParent) {
+ e = new GDirEntry(path->getCString(), "-", doStat);
+ needParent = gFalse;
+ return e;
+ }
+ ent = readdir(dir);
+ if (ent) {
+ e = new GDirEntry(path->getCString(), ent->d_name, doStat);
+ }
+ }
+#else
+ struct dirent *ent;
+ e = NULL;
+ if (dir) {
+ ent = (struct dirent *)readdir(dir);
+ if (ent && !strcmp(ent->d_name, ".")) {
+ ent = (struct dirent *)readdir(dir);
+ }
+ if (ent) {
+ e = new GDirEntry(path->getCString(), ent->d_name, doStat);
+ }
+ }
+#endif
+
+ return e;
+}
+
+void GDir::rewind() {
+#ifdef WIN32
+ GString *tmp;
+
+ if (hnd)
+ FindClose(hnd);
+ tmp = path->copy();
+ tmp->append("/*.*");
+ hnd = FindFirstFile(tmp->getCString(), &ffd);
+ delete tmp;
+#elif defined(ACORN)
+#elif defined(MACOS)
+#else
+ if (dir)
+ rewinddir(dir);
+#ifdef VMS
+ needParent = strchr(path->getCString(), '[') != NULL;
+#endif
+#endif
+}
diff --git a/kpdf/xpdf/goo/gfile.h b/kpdf/xpdf/goo/gfile.h
new file mode 100644
index 00000000..82f1d7a9
--- /dev/null
+++ b/kpdf/xpdf/goo/gfile.h
@@ -0,0 +1,138 @@
+//========================================================================
+//
+// gfile.h
+//
+// Miscellaneous file and directory name manipulation.
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef GFILE_H
+#define GFILE_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#if defined(WIN32)
+# include <sys/stat.h>
+# ifdef FPTEX
+# include <win32lib.h>
+# else
+# include <windows.h>
+# endif
+#elif defined(ACORN)
+#elif defined(MACOS)
+# include <ctime.h>
+#else
+# include <unistd.h>
+# include <sys/types.h>
+# ifdef VMS
+# include "vms_dirent.h"
+# elif HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(d) strlen((d)->d_name)
+# else
+# define dirent direct
+# define NAMLEN(d) (d)->d_namlen
+# if HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# if HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# if HAVE_NDIR_H
+# include <ndir.h>
+# endif
+# endif
+#endif
+#include "gtypes.h"
+
+class GString;
+
+//------------------------------------------------------------------------
+
+// Get home directory path.
+extern GString *getHomeDir();
+
+// Get current directory.
+extern GString *getCurrentDir();
+
+// Append a file name to a path string. <path> may be an empty
+// string, denoting the current directory). Returns <path>.
+extern GString *appendToPath(GString *path, char *fileName);
+
+// Grab the path from the front of the file name. If there is no
+// directory component in <fileName>, returns an empty string.
+extern GString *grabPath(char *fileName);
+
+// Is this an absolute path or file name?
+extern GBool isAbsolutePath(char *path);
+
+// Make this path absolute by prepending current directory (if path is
+// relative) or prepending user's directory (if path starts with '~').
+extern GString *makePathAbsolute(GString *path);
+
+// Get the modification time for <fileName>. Returns 0 if there is an
+// error.
+extern time_t getModTime(char *fileName);
+
+// Create a temporary file and open it for writing. If <ext> is not
+// NULL, it will be used as the file name extension. Returns both the
+// name and the file pointer. For security reasons, all writing
+// should be done to the returned file pointer; the file may be
+// reopened later for reading, but not for writing. The <mode> string
+// should be "w" or "wb". Returns true on success.
+extern GBool openTempFile(GString **name, FILE **f, char *mode, char *ext);
+
+// Execute <command>. Returns true on success.
+extern GBool executeCommand(char *cmd);
+
+// Just like fgets, but handles Unix, Mac, and/or DOS end-of-line
+// conventions.
+extern char *getLine(char *buf, int size, FILE *f);
+
+//------------------------------------------------------------------------
+// GDir and GDirEntry
+//------------------------------------------------------------------------
+
+class GDirEntry {
+public:
+
+ GDirEntry(char *dirPath, char *nameA, GBool doStat);
+ ~GDirEntry();
+ GString *getName() { return name; }
+ GBool isDir() { return dir; }
+
+private:
+
+ GString *name; // dir/file name
+ GBool dir; // is it a directory?
+};
+
+class GDir {
+public:
+
+ GDir(char *name, GBool doStatA = gTrue);
+ ~GDir();
+ GDirEntry *getNextEntry();
+ void rewind();
+
+private:
+
+ GString *path; // directory path
+ GBool doStat; // call stat() for each entry?
+#if defined(WIN32)
+ WIN32_FIND_DATA ffd;
+ HANDLE hnd;
+#elif defined(ACORN)
+#elif defined(MACOS)
+#else
+ DIR *dir; // the DIR structure from opendir()
+#ifdef VMS
+ GBool needParent; // need to return an entry for [-]
+#endif
+#endif
+};
+
+#endif
diff --git a/kpdf/xpdf/goo/gmem.cc b/kpdf/xpdf/goo/gmem.cc
new file mode 100644
index 00000000..d8962aba
--- /dev/null
+++ b/kpdf/xpdf/goo/gmem.cc
@@ -0,0 +1,315 @@
+/*
+ * gmem.c
+ *
+ * Memory routines with out-of-memory checking.
+ *
+ * Copyright 1996-2003 Glyph & Cog, LLC
+ */
+
+#include <aconf.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <limits.h>
+#include "gmem.h"
+
+#ifdef DEBUG_MEM
+
+typedef struct _GMemHdr {
+ unsigned int magic;
+ int size;
+ int index;
+ struct _GMemHdr *next, *prev;
+} GMemHdr;
+
+#define gMemHdrSize ((sizeof(GMemHdr) + 7) & ~7)
+#define gMemTrlSize (sizeof(long))
+
+#define gMemMagic 0xabcd9999
+
+#if gmemTrlSize==8
+#define gMemDeadVal 0xdeadbeefdeadbeefUL
+#else
+#define gMemDeadVal 0xdeadbeefUL
+#endif
+
+/* round data size so trailer will be aligned */
+#define gMemDataSize(size) \
+ ((((size) + gMemTrlSize - 1) / gMemTrlSize) * gMemTrlSize)
+
+static GMemHdr *gMemHead = NULL;
+static GMemHdr *gMemTail = NULL;
+
+static int gMemIndex = 0;
+static int gMemAlloc = 0;
+static int gMemInUse = 0;
+
+#endif /* DEBUG_MEM */
+
+void *gmalloc(int size) GMEM_EXCEP {
+#ifdef DEBUG_MEM
+ int size1;
+ char *mem;
+ GMemHdr *hdr;
+ void *data;
+ unsigned long *trl, *p;
+
+ if (size < 0) {
+#if USE_EXCEPTIONS
+ throw GMemException();
+#else
+ fprintf(stderr, "Invalid memory allocation size\n");
+ exit(1);
+#endif
+ }
+ if (size == 0) {
+ return NULL;
+ }
+ size1 = gMemDataSize(size);
+ if (!(mem = (char *)malloc(size1 + gMemHdrSize + gMemTrlSize))) {
+#if USE_EXCEPTIONS
+ throw GMemException();
+#else
+ fprintf(stderr, "Out of memory\n");
+ exit(1);
+#endif
+ }
+ hdr = (GMemHdr *)mem;
+ data = (void *)(mem + gMemHdrSize);
+ trl = (unsigned long *)(mem + gMemHdrSize + size1);
+ hdr->magic = gMemMagic;
+ hdr->size = size;
+ hdr->index = gMemIndex++;
+ if (gMemTail) {
+ gMemTail->next = hdr;
+ hdr->prev = gMemTail;
+ gMemTail = hdr;
+ } else {
+ hdr->prev = NULL;
+ gMemHead = gMemTail = hdr;
+ }
+ hdr->next = NULL;
+ ++gMemAlloc;
+ gMemInUse += size;
+ for (p = (unsigned long *)data; p <= trl; ++p) {
+ *p = gMemDeadVal;
+ }
+ return data;
+#else
+ void *p;
+
+ if (size < 0) {
+#if USE_EXCEPTIONS
+ throw GMemException();
+#else
+ fprintf(stderr, "Invalid memory allocation size\n");
+ exit(1);
+#endif
+ }
+ if (size == 0) {
+ return NULL;
+ }
+ if (!(p = malloc(size))) {
+#if USE_EXCEPTIONS
+ throw GMemException();
+#else
+ fprintf(stderr, "Out of memory\n");
+ exit(1);
+#endif
+ }
+ return p;
+#endif
+}
+
+void *grealloc(void *p, int size) GMEM_EXCEP {
+#ifdef DEBUG_MEM
+ GMemHdr *hdr;
+ void *q;
+ int oldSize;
+
+ if (size < 0) {
+#if USE_EXCEPTIONS
+ throw GMemException();
+#else
+ fprintf(stderr, "Invalid memory allocation size\n");
+ exit(1);
+#endif
+ }
+ if (size == 0) {
+ if (p) {
+ gfree(p);
+ }
+ return NULL;
+ }
+ if (p) {
+ hdr = (GMemHdr *)((char *)p - gMemHdrSize);
+ oldSize = hdr->size;
+ q = gmalloc(size);
+ memcpy(q, p, size < oldSize ? size : oldSize);
+ gfree(p);
+ } else {
+ q = gmalloc(size);
+ }
+ return q;
+#else
+ void *q;
+
+ if (size < 0) {
+#if USE_EXCEPTIONS
+ throw GMemException();
+#else
+ fprintf(stderr, "Invalid memory allocation size\n");
+ exit(1);
+#endif
+ }
+ if (size == 0) {
+ if (p) {
+ free(p);
+ }
+ return NULL;
+ }
+ if (p) {
+ q = realloc(p, size);
+ } else {
+ q = malloc(size);
+ }
+ if (!q) {
+#if USE_EXCEPTIONS
+ throw GMemException();
+#else
+ fprintf(stderr, "Out of memory\n");
+ exit(1);
+#endif
+ }
+ return q;
+#endif
+}
+
+void *gmallocn(int nObjs, int objSize) GMEM_EXCEP {
+ int n;
+
+ if (nObjs == 0) {
+ return NULL;
+ }
+ n = nObjs * objSize;
+ if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) {
+#if USE_EXCEPTIONS
+ throw GMemException();
+#else
+ fprintf(stderr, "Bogus memory allocation size\n");
+ exit(1);
+#endif
+ }
+ return gmalloc(n);
+}
+
+void *gmallocn_checkoverflow(int nObjs, int objSize) GMEM_EXCEP {
+ int n;
+
+ if (nObjs == 0) {
+ return NULL;
+ }
+ n = nObjs * objSize;
+ if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) {
+#if USE_EXCEPTIONS
+ throw GMemException();
+#else
+ fprintf(stderr, "Bogus memory allocation size\n");
+ return NULL;
+#endif
+ }
+ return gmalloc(n);
+}
+
+
+void *greallocn(void *p, int nObjs, int objSize) GMEM_EXCEP {
+ int n;
+
+ if (nObjs == 0) {
+ if (p) {
+ gfree(p);
+ }
+ return NULL;
+ }
+ n = nObjs * objSize;
+ if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) {
+#if USE_EXCEPTIONS
+ throw GMemException();
+#else
+ fprintf(stderr, "Bogus memory allocation size\n");
+ exit(1);
+#endif
+ }
+ return grealloc(p, n);
+}
+
+void gfree(void *p) {
+#ifdef DEBUG_MEM
+ int size;
+ GMemHdr *hdr;
+ unsigned long *trl, *clr;
+
+ if (p) {
+ hdr = (GMemHdr *)((char *)p - gMemHdrSize);
+ if (hdr->magic == gMemMagic &&
+ ((hdr->prev == NULL) == (hdr == gMemHead)) &&
+ ((hdr->next == NULL) == (hdr == gMemTail))) {
+ if (hdr->prev) {
+ hdr->prev->next = hdr->next;
+ } else {
+ gMemHead = hdr->next;
+ }
+ if (hdr->next) {
+ hdr->next->prev = hdr->prev;
+ } else {
+ gMemTail = hdr->prev;
+ }
+ --gMemAlloc;
+ gMemInUse -= hdr->size;
+ size = gMemDataSize(hdr->size);
+ trl = (unsigned long *)((char *)hdr + gMemHdrSize + size);
+ if (*trl != gMemDeadVal) {
+ fprintf(stderr, "Overwrite past end of block %d at address %p\n",
+ hdr->index, p);
+ }
+ for (clr = (unsigned long *)hdr; clr <= trl; ++clr) {
+ *clr = gMemDeadVal;
+ }
+ free(hdr);
+ } else {
+ fprintf(stderr, "Attempted to free bad address %p\n", p);
+ }
+ }
+#else
+ if (p) {
+ free(p);
+ }
+#endif
+}
+
+#ifdef DEBUG_MEM
+void gMemReport(FILE *f) {
+ GMemHdr *p;
+
+ fprintf(f, "%d memory allocations in all\n", gMemIndex);
+ if (gMemAlloc > 0) {
+ fprintf(f, "%d memory blocks left allocated:\n", gMemAlloc);
+ fprintf(f, " index size\n");
+ fprintf(f, "-------- --------\n");
+ for (p = gMemHead; p; p = p->next) {
+ fprintf(f, "%8d %8d\n", p->index, p->size);
+ }
+ } else {
+ fprintf(f, "No memory blocks left allocated\n");
+ }
+}
+#endif
+
+char *copyString(char *s) {
+ char *s1;
+
+ s1 = (char *)gmalloc(strlen(s) + 1);
+ strcpy(s1, s);
+ return s1;
+}
diff --git a/kpdf/xpdf/goo/gmem.h b/kpdf/xpdf/goo/gmem.h
new file mode 100644
index 00000000..ffe5b0da
--- /dev/null
+++ b/kpdf/xpdf/goo/gmem.h
@@ -0,0 +1,80 @@
+/*
+ * gmem.h
+ *
+ * Memory routines with out-of-memory checking.
+ *
+ * Copyright 1996-2003 Glyph & Cog, LLC
+ */
+
+#ifndef GMEM_H
+#define GMEM_H
+
+#include <stdio.h>
+#include <aconf.h>
+
+#if USE_EXCEPTIONS
+
+class GMemException {
+public:
+ GMemException() {}
+ ~GMemException() {}
+};
+
+#define GMEM_EXCEP throw(GMemException)
+
+#else // USE_EXCEPTIONS
+
+#define GMEM_EXCEP
+
+#endif // USE_EXCEPTIONS
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Same as malloc, but prints error message and exits if malloc()
+ * returns NULL.
+ */
+extern void *gmalloc(int size) GMEM_EXCEP;
+
+/*
+ * Same as realloc, but prints error message and exits if realloc()
+ * returns NULL. If <p> is NULL, calls malloc instead of realloc().
+ */
+extern void *grealloc(void *p, int size) GMEM_EXCEP;
+
+/*
+ * These are similar to gmalloc and grealloc, but take an object count
+ * and size. The result is similar to allocating nObjs * objSize
+ * bytes, but there is an additional error check that the total size
+ * doesn't overflow an int.
+ */
+extern void *gmallocn(int nObjs, int objSize) GMEM_EXCEP;
+extern void *greallocn(void *p, int nObjs, int objSize) GMEM_EXCEP;
+extern void *gmallocn_checkoverflow(int nObjs, int objSize) GMEM_EXCEP;
+
+/*
+ * Same as free, but checks for and ignores NULL pointers.
+ */
+extern void gfree(void *p);
+
+#ifdef DEBUG_MEM
+/*
+ * Report on unfreed memory.
+ */
+extern void gMemReport(FILE *f);
+#else
+#define gMemReport(f)
+#endif
+
+/*
+ * Allocate memory and copy a string into it.
+ */
+extern char *copyString(char *s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/kpdf/xpdf/goo/gmempp.cc b/kpdf/xpdf/goo/gmempp.cc
new file mode 100644
index 00000000..b1ee970d
--- /dev/null
+++ b/kpdf/xpdf/goo/gmempp.cc
@@ -0,0 +1,32 @@
+//========================================================================
+//
+// gmempp.cc
+//
+// Use gmalloc/gfree for C++ new/delete operators.
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+#include "gmem.h"
+
+#ifdef DEBUG_MEM
+
+void *operator new(size_t size) {
+ return gmalloc((int)size);
+}
+
+void *operator new[](size_t size) {
+ return gmalloc((int)size);
+}
+
+void operator delete(void *p) {
+ gfree(p);
+}
+
+void operator delete[](void *p) {
+ gfree(p);
+}
+
+#endif
diff --git a/kpdf/xpdf/goo/gtypes.h b/kpdf/xpdf/goo/gtypes.h
new file mode 100644
index 00000000..9f64f57d
--- /dev/null
+++ b/kpdf/xpdf/goo/gtypes.h
@@ -0,0 +1,29 @@
+/*
+ * gtypes.h
+ *
+ * Some useful simple types.
+ *
+ * Copyright 1996-2003 Glyph & Cog, LLC
+ */
+
+#ifndef GTYPES_H
+#define GTYPES_H
+
+/*
+ * These have stupid names to avoid conflicts with some (but not all)
+ * C++ compilers which define them.
+ */
+typedef int GBool;
+#define gTrue 1
+#define gFalse 0
+
+/*
+ * These have stupid names to avoid conflicts with <sys/types.h>,
+ * which on various systems defines some random subset of these.
+ */
+typedef unsigned char Guchar;
+typedef unsigned short Gushort;
+typedef unsigned int Guint;
+typedef unsigned long Gulong;
+
+#endif
diff --git a/kpdf/xpdf/splash/Makefile.am b/kpdf/xpdf/splash/Makefile.am
new file mode 100644
index 00000000..34d41419
--- /dev/null
+++ b/kpdf/xpdf/splash/Makefile.am
@@ -0,0 +1,8 @@
+INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../fofi -I$(srcdir)/../goo $(LIBFREETYPE_CFLAGS) $(USER_INCLUDES)
+
+libsplash_la_SOURCES = Splash.cc SplashBitmap.cc SplashClip.cc SplashFTFont.cc SplashFTFontEngine.cc \
+ SplashFTFontFile.cc SplashFont.cc SplashFontEngine.cc SplashFontFile.cc SplashFontFileID.cc \
+ SplashPath.cc SplashPattern.cc SplashScreen.cc SplashState.cc SplashT1Font.cc \
+ SplashT1FontEngine.cc SplashT1FontFile.cc SplashXPath.cc SplashXPathScanner.cc
+
+noinst_LTLIBRARIES = libsplash.la
diff --git a/kpdf/xpdf/splash/Splash.cc b/kpdf/xpdf/splash/Splash.cc
new file mode 100644
index 00000000..30179fda
--- /dev/null
+++ b/kpdf/xpdf/splash/Splash.cc
@@ -0,0 +1,3335 @@
+//========================================================================
+//
+// Splash.cc
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include "gmem.h"
+#include "SplashErrorCodes.h"
+#include "SplashMath.h"
+#include "SplashBitmap.h"
+#include "SplashState.h"
+#include "SplashPath.h"
+#include "SplashXPath.h"
+#include "SplashXPathScanner.h"
+#include "SplashPattern.h"
+#include "SplashScreen.h"
+#include "SplashFont.h"
+#include "SplashGlyphBitmap.h"
+#include "Splash.h"
+
+//------------------------------------------------------------------------
+
+// distance of Bezier control point from center for circle approximation
+// = (4 * (sqrt(2) - 1) / 3) * r
+#define bezierCircle ((SplashCoord)0.55228475)
+#define bezierCircle2 ((SplashCoord)(0.5 * 0.55228475))
+
+// Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result.
+static inline Guchar div255(int x) {
+ return (Guchar)((x + (x >> 8) + 0x80) >> 8);
+}
+
+//------------------------------------------------------------------------
+// SplashPipe
+//------------------------------------------------------------------------
+
+#define splashPipeMaxStages 9
+
+struct SplashPipe {
+ // pixel coordinates
+ int x, y;
+
+ // source pattern
+ SplashPattern *pattern;
+
+ // source alpha and color
+ SplashCoord aInput;
+ GBool usesShape;
+ Guchar aSrc;
+ SplashColorPtr cSrc;
+ SplashColor cSrcVal;
+
+ // non-isolated group alpha0
+ Guchar *alpha0Ptr;
+
+ // soft mask
+ SplashColorPtr softMaskPtr;
+
+ // destination alpha and color
+ SplashColorPtr destColorPtr;
+ int destColorMask;
+ Guchar *destAlphaPtr;
+
+ // shape
+ SplashCoord shape;
+
+ // result alpha and color
+ GBool noTransparency;
+ SplashPipeResultColorCtrl resultColorCtrl;
+
+ // non-isolated group correction
+ int nonIsolatedGroup;
+};
+
+SplashPipeResultColorCtrl Splash::pipeResultColorNoAlphaBlend[] = {
+ splashPipeResultColorNoAlphaBlendMono,
+ splashPipeResultColorNoAlphaBlendMono,
+ splashPipeResultColorNoAlphaBlendRGB,
+ splashPipeResultColorNoAlphaBlendRGB
+#if SPLASH_CMYK
+ ,
+ splashPipeResultColorNoAlphaBlendCMYK
+#endif
+};
+
+SplashPipeResultColorCtrl Splash::pipeResultColorAlphaNoBlend[] = {
+ splashPipeResultColorAlphaNoBlendMono,
+ splashPipeResultColorAlphaNoBlendMono,
+ splashPipeResultColorAlphaNoBlendRGB,
+ splashPipeResultColorAlphaNoBlendRGB
+#if SPLASH_CMYK
+ ,
+ splashPipeResultColorAlphaNoBlendCMYK
+#endif
+};
+
+SplashPipeResultColorCtrl Splash::pipeResultColorAlphaBlend[] = {
+ splashPipeResultColorAlphaBlendMono,
+ splashPipeResultColorAlphaBlendMono,
+ splashPipeResultColorAlphaBlendRGB,
+ splashPipeResultColorAlphaBlendRGB
+#if SPLASH_CMYK
+ ,
+ splashPipeResultColorAlphaBlendCMYK
+#endif
+};
+
+//------------------------------------------------------------------------
+
+static void blendXor(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+ int i;
+
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ blend[i] = src[i] ^ dest[i];
+ }
+}
+
+//------------------------------------------------------------------------
+// modified region
+//------------------------------------------------------------------------
+
+void Splash::clearModRegion() {
+ modXMin = bitmap->getWidth();
+ modYMin = bitmap->getHeight();
+ modXMax = -1;
+ modYMax = -1;
+}
+
+inline void Splash::updateModX(int x) {
+ if (x < modXMin) {
+ modXMin = x;
+ }
+ if (x > modXMax) {
+ modXMax = x;
+ }
+}
+
+inline void Splash::updateModY(int y) {
+ if (y < modYMin) {
+ modYMin = y;
+ }
+ if (y > modYMax) {
+ modYMax = y;
+ }
+}
+
+//------------------------------------------------------------------------
+// pipeline
+//------------------------------------------------------------------------
+
+inline void Splash::pipeInit(SplashPipe *pipe, int x, int y,
+ SplashPattern *pattern, SplashColorPtr cSrc,
+ SplashCoord aInput, GBool usesShape,
+ GBool nonIsolatedGroup) {
+ pipeSetXY(pipe, x, y);
+ pipe->pattern = NULL;
+
+ // source color
+ if (pattern) {
+ if (pattern->isStatic()) {
+ pattern->getColor(x, y, pipe->cSrcVal);
+ } else {
+ pipe->pattern = pattern;
+ }
+ pipe->cSrc = pipe->cSrcVal;
+ } else {
+ pipe->cSrc = cSrc;
+ }
+
+ // source alpha
+ pipe->aInput = aInput;
+ if (!state->softMask) {
+ if (usesShape) {
+ pipe->aInput *= 255;
+ } else {
+ pipe->aSrc = (Guchar)splashRound(pipe->aInput * 255);
+ }
+ }
+ pipe->usesShape = usesShape;
+
+ // result alpha
+ if (aInput == 1 && !state->softMask && !usesShape &&
+ !state->inNonIsolatedGroup) {
+ pipe->noTransparency = gTrue;
+ } else {
+ pipe->noTransparency = gFalse;
+ }
+
+ // result color
+ if (pipe->noTransparency) {
+ // the !state->blendFunc case is handled separately in pipeRun
+ pipe->resultColorCtrl = pipeResultColorNoAlphaBlend[bitmap->mode];
+ } else if (!state->blendFunc) {
+ pipe->resultColorCtrl = pipeResultColorAlphaNoBlend[bitmap->mode];
+ } else {
+ pipe->resultColorCtrl = pipeResultColorAlphaBlend[bitmap->mode];
+ }
+
+ // non-isolated group correction
+ if (nonIsolatedGroup) {
+ pipe->nonIsolatedGroup = splashColorModeNComps[bitmap->mode];
+ } else {
+ pipe->nonIsolatedGroup = 0;
+ }
+}
+
+inline void Splash::pipeRun(SplashPipe *pipe) {
+ Guchar aSrc, aDest, alpha2, alpha0, aResult;
+ SplashColor cDest, cBlend;
+ Guchar cResult0, cResult1, cResult2, cResult3;
+
+ //----- source color
+
+ // static pattern: handled in pipeInit
+ // fixed color: handled in pipeInit
+
+ // dynamic pattern
+ if (pipe->pattern) {
+ pipe->pattern->getColor(pipe->x, pipe->y, pipe->cSrcVal);
+ }
+
+ if (pipe->noTransparency && !state->blendFunc) {
+
+ //----- write destination pixel
+
+ switch (bitmap->mode) {
+ case splashModeMono1:
+ cResult0 = pipe->cSrc[0];
+ if (state->screen->test(pipe->x, pipe->y, cResult0)) {
+ *pipe->destColorPtr |= pipe->destColorMask;
+ } else {
+ *pipe->destColorPtr &= ~pipe->destColorMask;
+ }
+ if (!(pipe->destColorMask >>= 1)) {
+ pipe->destColorMask = 0x80;
+ ++pipe->destColorPtr;
+ }
+ break;
+ case splashModeMono8:
+ *pipe->destColorPtr++ = pipe->cSrc[0];
+ break;
+ case splashModeRGB8:
+ *pipe->destColorPtr++ = pipe->cSrc[0];
+ *pipe->destColorPtr++ = pipe->cSrc[1];
+ *pipe->destColorPtr++ = pipe->cSrc[2];
+ break;
+ case splashModeBGR8:
+ *pipe->destColorPtr++ = pipe->cSrc[2];
+ *pipe->destColorPtr++ = pipe->cSrc[1];
+ *pipe->destColorPtr++ = pipe->cSrc[0];
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ *pipe->destColorPtr++ = pipe->cSrc[0];
+ *pipe->destColorPtr++ = pipe->cSrc[1];
+ *pipe->destColorPtr++ = pipe->cSrc[2];
+ *pipe->destColorPtr++ = pipe->cSrc[3];
+ break;
+#endif
+ }
+ if (pipe->destAlphaPtr) {
+ *pipe->destAlphaPtr++ = 255;
+ }
+
+ } else {
+
+ //----- read destination pixel
+
+ switch (bitmap->mode) {
+ case splashModeMono1:
+ cDest[0] = (*pipe->destColorPtr & pipe->destColorMask) ? 0xff : 0x00;
+ break;
+ case splashModeMono8:
+ cDest[0] = *pipe->destColorPtr;
+ break;
+ case splashModeRGB8:
+ cDest[0] = pipe->destColorPtr[0];
+ cDest[1] = pipe->destColorPtr[1];
+ cDest[2] = pipe->destColorPtr[2];
+ break;
+ case splashModeBGR8:
+ cDest[0] = pipe->destColorPtr[2];
+ cDest[1] = pipe->destColorPtr[1];
+ cDest[2] = pipe->destColorPtr[0];
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ cDest[0] = pipe->destColorPtr[0];
+ cDest[1] = pipe->destColorPtr[1];
+ cDest[2] = pipe->destColorPtr[2];
+ cDest[3] = pipe->destColorPtr[3];
+ break;
+#endif
+ }
+ if (pipe->destAlphaPtr) {
+ aDest = *pipe->destAlphaPtr;
+ } else {
+ aDest = 0xff;
+ }
+
+ //----- blend function
+
+ if (state->blendFunc) {
+ (*state->blendFunc)(pipe->cSrc, cDest, cBlend, bitmap->mode);
+ }
+
+ //----- source alpha
+
+ if (state->softMask) {
+ if (pipe->usesShape) {
+ aSrc = (Guchar)splashRound(pipe->aInput * *pipe->softMaskPtr++
+ * pipe->shape);
+ } else {
+ aSrc = (Guchar)splashRound(pipe->aInput * *pipe->softMaskPtr++);
+ }
+ } else if (pipe->usesShape) {
+ // pipe->aInput is premultiplied by 255 in pipeInit
+ aSrc = (Guchar)splashRound(pipe->aInput * pipe->shape);
+ } else {
+ // precomputed in pipeInit
+ aSrc = pipe->aSrc;
+ }
+
+ //----- result alpha and non-isolated group element correction
+
+ if (pipe->noTransparency) {
+ alpha2 = aResult = 255;
+ } else {
+ aResult = aSrc + aDest - div255(aSrc * aDest);
+
+ if (pipe->alpha0Ptr) {
+ alpha0 = *pipe->alpha0Ptr++;
+ alpha2 = aResult + alpha0 - div255(aResult * alpha0);
+ } else {
+ alpha2 = aResult;
+ }
+ }
+
+ //----- result color
+
+ cResult0 = cResult1 = cResult2 = cResult3 = 0; // make gcc happy
+
+ switch (pipe->resultColorCtrl) {
+
+#if SPLASH_CMYK
+ case splashPipeResultColorNoAlphaBlendCMYK:
+ cResult3 = div255((255 - aDest) * pipe->cSrc[3] + aDest * cBlend[3]);
+#endif
+ case splashPipeResultColorNoAlphaBlendRGB:
+ cResult2 = div255((255 - aDest) * pipe->cSrc[2] + aDest * cBlend[2]);
+ cResult1 = div255((255 - aDest) * pipe->cSrc[1] + aDest * cBlend[1]);
+ case splashPipeResultColorNoAlphaBlendMono:
+ cResult0 = div255((255 - aDest) * pipe->cSrc[0] + aDest * cBlend[0]);
+ break;
+
+ case splashPipeResultColorAlphaNoBlendMono:
+ if (alpha2 == 0) {
+ cResult0 = 0;
+ } else {
+ cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
+ aSrc * pipe->cSrc[0]) / alpha2);
+ }
+ break;
+ case splashPipeResultColorAlphaNoBlendRGB:
+ if (alpha2 == 0) {
+ cResult0 = 0;
+ cResult1 = 0;
+ cResult2 = 0;
+ } else {
+ cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
+ aSrc * pipe->cSrc[0]) / alpha2);
+ cResult1 = (Guchar)(((alpha2 - aSrc) * cDest[1] +
+ aSrc * pipe->cSrc[1]) / alpha2);
+ cResult2 = (Guchar)(((alpha2 - aSrc) * cDest[2] +
+ aSrc * pipe->cSrc[2]) / alpha2);
+ }
+ break;
+#if SPLASH_CMYK
+ case splashPipeResultColorAlphaNoBlendCMYK:
+ if (alpha2 == 0) {
+ cResult0 = 0;
+ cResult1 = 0;
+ cResult2 = 0;
+ cResult3 = 0;
+ } else {
+ cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
+ aSrc * pipe->cSrc[0]) / alpha2);
+ cResult1 = (Guchar)(((alpha2 - aSrc) * cDest[1] +
+ aSrc * pipe->cSrc[1]) / alpha2);
+ cResult2 = (Guchar)(((alpha2 - aSrc) * cDest[2] +
+ aSrc * pipe->cSrc[2]) / alpha2);
+ cResult3 = (Guchar)(((alpha2 - aSrc) * cDest[3] +
+ aSrc * pipe->cSrc[3]) / alpha2);
+ }
+ break;
+#endif
+
+ case splashPipeResultColorAlphaBlendMono:
+ if (alpha2 == 0) {
+ cResult0 = 0;
+ } else {
+ cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
+ aSrc * ((255 - aDest) * pipe->cSrc[0] +
+ aDest * cBlend[0]) / 255) /
+ alpha2);
+ }
+ break;
+ case splashPipeResultColorAlphaBlendRGB:
+ if (alpha2 == 0) {
+ cResult0 = 0;
+ cResult1 = 0;
+ cResult2 = 0;
+ } else {
+ cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
+ aSrc * ((255 - aDest) * pipe->cSrc[0] +
+ aDest * cBlend[0]) / 255) /
+ alpha2);
+ cResult1 = (Guchar)(((alpha2 - aSrc) * cDest[1] +
+ aSrc * ((255 - aDest) * pipe->cSrc[1] +
+ aDest * cBlend[1]) / 255) /
+ alpha2);
+ cResult2 = (Guchar)(((alpha2 - aSrc) * cDest[2] +
+ aSrc * ((255 - aDest) * pipe->cSrc[2] +
+ aDest * cBlend[2]) / 255) /
+ alpha2);
+ }
+ break;
+#if SPLASH_CMYK
+ case splashPipeResultColorAlphaBlendCMYK:
+ if (alpha2 == 0) {
+ cResult0 = 0;
+ cResult1 = 0;
+ cResult2 = 0;
+ cResult3 = 0;
+ } else {
+ cResult0 = (Guchar)(((alpha2 - aSrc) * cDest[0] +
+ aSrc * ((255 - aDest) * pipe->cSrc[0] +
+ aDest * cBlend[0]) / 255) /
+ alpha2);
+ cResult1 = (Guchar)(((alpha2 - aSrc) * cDest[1] +
+ aSrc * ((255 - aDest) * pipe->cSrc[1] +
+ aDest * cBlend[1]) / 255) /
+ alpha2);
+ cResult2 = (Guchar)(((alpha2 - aSrc) * cDest[2] +
+ aSrc * ((255 - aDest) * pipe->cSrc[2] +
+ aDest * cBlend[2]) / 255) /
+ alpha2);
+ cResult3 = (Guchar)(((alpha2 - aSrc) * cDest[3] +
+ aSrc * ((255 - aDest) * pipe->cSrc[3] +
+ aDest * cBlend[3]) / 255) /
+ alpha2);
+ }
+ break;
+#endif
+ }
+
+ //----- non-isolated group correction
+
+ if (aResult != 0) {
+ switch (pipe->nonIsolatedGroup) {
+#if SPLASH_CMYK
+ case 4:
+ cResult3 += (cResult3 - cDest[3]) * aDest *
+ (255 - aResult) / (255 * aResult);
+#endif
+ case 3:
+ cResult2 += (cResult2 - cDest[2]) * aDest *
+ (255 - aResult) / (255 * aResult);
+ cResult1 += (cResult1 - cDest[1]) * aDest *
+ (255 - aResult) / (255 * aResult);
+ case 1:
+ cResult0 += (cResult0 - cDest[0]) * aDest *
+ (255 - aResult) / (255 * aResult);
+ case 0:
+ break;
+ }
+ }
+
+ //----- write destination pixel
+
+ switch (bitmap->mode) {
+ case splashModeMono1:
+ if (state->screen->test(pipe->x, pipe->y, cResult0)) {
+ *pipe->destColorPtr |= pipe->destColorMask;
+ } else {
+ *pipe->destColorPtr &= ~pipe->destColorMask;
+ }
+ if (!(pipe->destColorMask >>= 1)) {
+ pipe->destColorMask = 0x80;
+ ++pipe->destColorPtr;
+ }
+ break;
+ case splashModeMono8:
+ *pipe->destColorPtr++ = cResult0;
+ break;
+ case splashModeRGB8:
+ *pipe->destColorPtr++ = cResult0;
+ *pipe->destColorPtr++ = cResult1;
+ *pipe->destColorPtr++ = cResult2;
+ break;
+ case splashModeBGR8:
+ *pipe->destColorPtr++ = cResult2;
+ *pipe->destColorPtr++ = cResult1;
+ *pipe->destColorPtr++ = cResult0;
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ *pipe->destColorPtr++ = cResult0;
+ *pipe->destColorPtr++ = cResult1;
+ *pipe->destColorPtr++ = cResult2;
+ *pipe->destColorPtr++ = cResult3;
+ break;
+#endif
+ }
+ if (pipe->destAlphaPtr) {
+ *pipe->destAlphaPtr++ = aResult;
+ }
+
+ }
+
+ ++pipe->x;
+}
+
+inline void Splash::pipeSetXY(SplashPipe *pipe, int x, int y) {
+ pipe->x = x;
+ pipe->y = y;
+ if (state->softMask) {
+ pipe->softMaskPtr =
+ &state->softMask->data[y * state->softMask->rowSize + x];
+ }
+ switch (bitmap->mode) {
+ case splashModeMono1:
+ pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + (x >> 3)];
+ pipe->destColorMask = 0x80 >> (x & 7);
+ break;
+ case splashModeMono8:
+ pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + x];
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x];
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x];
+ break;
+#endif
+ }
+ if (bitmap->alpha) {
+ pipe->destAlphaPtr = &bitmap->alpha[y * bitmap->width + x];
+ } else {
+ pipe->destAlphaPtr = NULL;
+ }
+ if (state->inNonIsolatedGroup && alpha0Bitmap->alpha) {
+ pipe->alpha0Ptr =
+ &alpha0Bitmap->alpha[(alpha0Y + y) * alpha0Bitmap->width +
+ (alpha0X + x)];
+ } else {
+ pipe->alpha0Ptr = NULL;
+ }
+}
+
+inline void Splash::pipeIncX(SplashPipe *pipe) {
+ ++pipe->x;
+ if (state->softMask) {
+ ++pipe->softMaskPtr;
+ }
+ switch (bitmap->mode) {
+ case splashModeMono1:
+ if (!(pipe->destColorMask >>= 1)) {
+ pipe->destColorMask = 0x80;
+ ++pipe->destColorPtr;
+ }
+ break;
+ case splashModeMono8:
+ ++pipe->destColorPtr;
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ pipe->destColorPtr += 3;
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ pipe->destColorPtr += 4;
+ break;
+#endif
+ }
+ if (pipe->destAlphaPtr) {
+ ++pipe->destAlphaPtr;
+ }
+ if (pipe->alpha0Ptr) {
+ ++pipe->alpha0Ptr;
+ }
+}
+
+inline void Splash::drawPixel(SplashPipe *pipe, int x, int y, GBool noClip) {
+ if (noClip || state->clip->test(x, y)) {
+ pipeSetXY(pipe, x, y);
+ pipeRun(pipe);
+ updateModX(x);
+ updateModY(y);
+ }
+}
+
+inline void Splash::drawAAPixelInit() {
+ aaBufY = -1;
+}
+
+inline void Splash::drawAAPixel(SplashPipe *pipe, int x, int y) {
+#if splashAASize == 4
+ static int bitCount4[16] = { 0, 1, 1, 2, 1, 2, 2, 3,
+ 1, 2, 2, 3, 2, 3, 3, 4 };
+ int w;
+#else
+ int xx, yy;
+#endif
+ SplashColorPtr p;
+ int x0, x1, t;
+
+ if (x < 0 || x >= bitmap->width ||
+ y < state->clip->getYMinI() || y > state->clip->getYMaxI()) {
+ return;
+ }
+
+ // update aaBuf
+ if (y != aaBufY) {
+ memset(aaBuf->getDataPtr(), 0xff,
+ aaBuf->getRowSize() * aaBuf->getHeight());
+ x0 = 0;
+ x1 = bitmap->width - 1;
+ state->clip->clipAALine(aaBuf, &x0, &x1, y);
+ aaBufY = y;
+ }
+
+ // compute the shape value
+#if splashAASize == 4
+ p = aaBuf->getDataPtr() + (x >> 1);
+ w = aaBuf->getRowSize();
+ if (x & 1) {
+ t = bitCount4[*p & 0x0f] + bitCount4[p[w] & 0x0f] +
+ bitCount4[p[2*w] & 0x0f] + bitCount4[p[3*w] & 0x0f];
+ } else {
+ t = bitCount4[*p >> 4] + bitCount4[p[w] >> 4] +
+ bitCount4[p[2*w] >> 4] + bitCount4[p[3*w] >> 4];
+ }
+#else
+ t = 0;
+ for (yy = 0; yy < splashAASize; ++yy) {
+ for (xx = 0; xx < splashAASize; ++xx) {
+ p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() +
+ ((x * splashAASize + xx) >> 3);
+ t += (*p >> (7 - ((x * splashAASize + xx) & 7))) & 1;
+ }
+ }
+#endif
+
+ // draw the pixel
+ if (t != 0) {
+ pipeSetXY(pipe, x, y);
+ pipe->shape *= aaGamma[t];
+ pipeRun(pipe);
+ updateModX(x);
+ updateModY(y);
+ }
+}
+
+inline void Splash::drawSpan(SplashPipe *pipe, int x0, int x1, int y,
+ GBool noClip) {
+ int x;
+
+ pipeSetXY(pipe, x0, y);
+ if (noClip) {
+ for (x = x0; x <= x1; ++x) {
+ pipeRun(pipe);
+ }
+ updateModX(x0);
+ updateModX(x1);
+ updateModY(y);
+ } else {
+ for (x = x0; x <= x1; ++x) {
+ if (state->clip->test(x, y)) {
+ pipeRun(pipe);
+ updateModX(x);
+ updateModY(y);
+ } else {
+ pipeIncX(pipe);
+ }
+ }
+ }
+}
+
+inline void Splash::drawAALine(SplashPipe *pipe, int x0, int x1, int y) {
+#if splashAASize == 4
+ static int bitCount4[16] = { 0, 1, 1, 2, 1, 2, 2, 3,
+ 1, 2, 2, 3, 2, 3, 3, 4 };
+ SplashColorPtr p0, p1, p2, p3;
+ int t;
+#else
+ SplashColorPtr p;
+ int xx, yy, t;
+#endif
+ int x;
+
+#if splashAASize == 4
+ p0 = aaBuf->getDataPtr() + (x0 >> 1);
+ p1 = p0 + aaBuf->getRowSize();
+ p2 = p1 + aaBuf->getRowSize();
+ p3 = p2 + aaBuf->getRowSize();
+#endif
+ pipeSetXY(pipe, x0, y);
+ for (x = x0; x <= x1; ++x) {
+
+ // compute the shape value
+#if splashAASize == 4
+ if (x & 1) {
+ t = bitCount4[*p0 & 0x0f] + bitCount4[*p1 & 0x0f] +
+ bitCount4[*p2 & 0x0f] + bitCount4[*p3 & 0x0f];
+ ++p0; ++p1; ++p2; ++p3;
+ } else {
+ t = bitCount4[*p0 >> 4] + bitCount4[*p1 >> 4] +
+ bitCount4[*p2 >> 4] + bitCount4[*p3 >> 4];
+ }
+#else
+ t = 0;
+ for (yy = 0; yy < splashAASize; ++yy) {
+ for (xx = 0; xx < splashAASize; ++xx) {
+ p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() +
+ ((x * splashAASize + xx) >> 3);
+ t += (*p >> (7 - ((x * splashAASize + xx) & 7))) & 1;
+ }
+ }
+#endif
+
+ if (t != 0) {
+ pipe->shape = aaGamma[t];
+ pipeRun(pipe);
+ updateModX(x);
+ updateModY(y);
+ } else {
+ pipeIncX(pipe);
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+
+// Transform a point from user space to device space.
+inline void Splash::transform(SplashCoord *matrix,
+ SplashCoord xi, SplashCoord yi,
+ SplashCoord *xo, SplashCoord *yo) {
+ // [ m[0] m[1] 0 ]
+ // [xo yo 1] = [xi yi 1] * [ m[2] m[3] 0 ]
+ // [ m[4] m[5] 1 ]
+ *xo = xi * matrix[0] + yi * matrix[2] + matrix[4];
+ *yo = xi * matrix[1] + yi * matrix[3] + matrix[5];
+}
+
+//------------------------------------------------------------------------
+// Splash
+//------------------------------------------------------------------------
+
+Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
+ SplashScreenParams *screenParams) {
+ int i;
+
+ bitmap = bitmapA;
+ vectorAntialias = vectorAntialiasA;
+ state = new SplashState(bitmap->width, bitmap->height, vectorAntialias,
+ screenParams);
+ if (vectorAntialias) {
+ aaBuf = new SplashBitmap(splashAASize * bitmap->width, splashAASize,
+ 1, splashModeMono1, gFalse);
+ for (i = 0; i <= splashAASize * splashAASize; ++i) {
+ aaGamma[i] = splashPow((SplashCoord)i /
+ (SplashCoord)(splashAASize * splashAASize),
+ 1.5);
+ }
+ } else {
+ aaBuf = NULL;
+ }
+ clearModRegion();
+ debugMode = gFalse;
+}
+
+Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
+ SplashScreen *screenA) {
+ int i;
+
+ bitmap = bitmapA;
+ vectorAntialias = vectorAntialiasA;
+ state = new SplashState(bitmap->width, bitmap->height, vectorAntialias,
+ screenA);
+ if (vectorAntialias) {
+ aaBuf = new SplashBitmap(splashAASize * bitmap->width, splashAASize,
+ 1, splashModeMono1, gFalse);
+ for (i = 0; i <= splashAASize * splashAASize; ++i) {
+ aaGamma[i] = splashPow((SplashCoord)i /
+ (SplashCoord)(splashAASize * splashAASize),
+ 1.5);
+ }
+ } else {
+ aaBuf = NULL;
+ }
+ clearModRegion();
+ debugMode = gFalse;
+}
+
+Splash::~Splash() {
+ while (state->next) {
+ restoreState();
+ }
+ delete state;
+ if (vectorAntialias) {
+ delete aaBuf;
+ }
+}
+
+//------------------------------------------------------------------------
+// state read
+//------------------------------------------------------------------------
+
+SplashCoord *Splash::getMatrix() {
+ return state->matrix;
+}
+
+SplashPattern *Splash::getStrokePattern() {
+ return state->strokePattern;
+}
+
+SplashPattern *Splash::getFillPattern() {
+ return state->fillPattern;
+}
+
+SplashScreen *Splash::getScreen() {
+ return state->screen;
+}
+
+SplashBlendFunc Splash::getBlendFunc() {
+ return state->blendFunc;
+}
+
+SplashCoord Splash::getStrokeAlpha() {
+ return state->strokeAlpha;
+}
+
+SplashCoord Splash::getFillAlpha() {
+ return state->fillAlpha;
+}
+
+SplashCoord Splash::getLineWidth() {
+ return state->lineWidth;
+}
+
+int Splash::getLineCap() {
+ return state->lineCap;
+}
+
+int Splash::getLineJoin() {
+ return state->lineJoin;
+}
+
+SplashCoord Splash::getMiterLimit() {
+ return state->miterLimit;
+}
+
+SplashCoord Splash::getFlatness() {
+ return state->flatness;
+}
+
+SplashCoord *Splash::getLineDash() {
+ return state->lineDash;
+}
+
+int Splash::getLineDashLength() {
+ return state->lineDashLength;
+}
+
+SplashCoord Splash::getLineDashPhase() {
+ return state->lineDashPhase;
+}
+
+SplashClip *Splash::getClip() {
+ return state->clip;
+}
+
+SplashBitmap *Splash::getSoftMask() {
+ return state->softMask;
+}
+
+GBool Splash::getInNonIsolatedGroup() {
+ return state->inNonIsolatedGroup;
+}
+
+//------------------------------------------------------------------------
+// state write
+//------------------------------------------------------------------------
+
+void Splash::setMatrix(SplashCoord *matrix) {
+ memcpy(state->matrix, matrix, 6 * sizeof(SplashCoord));
+}
+
+void Splash::setStrokePattern(SplashPattern *strokePattern) {
+ state->setStrokePattern(strokePattern);
+}
+
+void Splash::setFillPattern(SplashPattern *fillPattern) {
+ state->setFillPattern(fillPattern);
+}
+
+void Splash::setScreen(SplashScreen *screen) {
+ state->setScreen(screen);
+}
+
+void Splash::setBlendFunc(SplashBlendFunc func) {
+ state->blendFunc = func;
+}
+
+void Splash::setStrokeAlpha(SplashCoord alpha) {
+ state->strokeAlpha = alpha;
+}
+
+void Splash::setFillAlpha(SplashCoord alpha) {
+ state->fillAlpha = alpha;
+}
+
+void Splash::setLineWidth(SplashCoord lineWidth) {
+ state->lineWidth = lineWidth;
+}
+
+void Splash::setLineCap(int lineCap) {
+ state->lineCap = lineCap;
+}
+
+void Splash::setLineJoin(int lineJoin) {
+ state->lineJoin = lineJoin;
+}
+
+void Splash::setMiterLimit(SplashCoord miterLimit) {
+ state->miterLimit = miterLimit;
+}
+
+void Splash::setFlatness(SplashCoord flatness) {
+ if (flatness < 1) {
+ state->flatness = 1;
+ } else {
+ state->flatness = flatness;
+ }
+}
+
+void Splash::setLineDash(SplashCoord *lineDash, int lineDashLength,
+ SplashCoord lineDashPhase) {
+ state->setLineDash(lineDash, lineDashLength, lineDashPhase);
+}
+
+void Splash::setStrokeAdjust(GBool strokeAdjust) {
+ state->strokeAdjust = strokeAdjust;
+}
+
+void Splash::clipResetToRect(SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1) {
+ state->clip->resetToRect(x0, y0, x1, y1);
+}
+
+SplashError Splash::clipToRect(SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1) {
+ return state->clip->clipToRect(x0, y0, x1, y1);
+}
+
+SplashError Splash::clipToPath(SplashPath *path, GBool eo) {
+ return state->clip->clipToPath(path, state->matrix, state->flatness, eo);
+}
+
+void Splash::setSoftMask(SplashBitmap *softMask) {
+ state->setSoftMask(softMask);
+}
+
+void Splash::setInNonIsolatedGroup(SplashBitmap *alpha0BitmapA,
+ int alpha0XA, int alpha0YA) {
+ alpha0Bitmap = alpha0BitmapA;
+ alpha0X = alpha0XA;
+ alpha0Y = alpha0YA;
+ state->inNonIsolatedGroup = gTrue;
+}
+
+//------------------------------------------------------------------------
+// state save/restore
+//------------------------------------------------------------------------
+
+void Splash::saveState() {
+ SplashState *newState;
+
+ newState = state->copy();
+ newState->next = state;
+ state = newState;
+}
+
+SplashError Splash::restoreState() {
+ SplashState *oldState;
+
+ if (!state->next) {
+ return splashErrNoSave;
+ }
+ oldState = state;
+ state = state->next;
+ delete oldState;
+ return splashOk;
+}
+
+//------------------------------------------------------------------------
+// drawing operations
+//------------------------------------------------------------------------
+
+void Splash::clear(SplashColorPtr color, Guchar alpha) {
+ SplashColorPtr row, p;
+ Guchar mono;
+ int x, y;
+
+ switch (bitmap->mode) {
+ case splashModeMono1:
+ mono = (color[0] & 0x80) ? 0xff : 0x00;
+ if (bitmap->rowSize < 0) {
+ memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
+ mono, -bitmap->rowSize * bitmap->height);
+ } else {
+ memset(bitmap->data, mono, bitmap->rowSize * bitmap->height);
+ }
+ break;
+ case splashModeMono8:
+ if (bitmap->rowSize < 0) {
+ memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
+ color[0], -bitmap->rowSize * bitmap->height);
+ } else {
+ memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
+ }
+ break;
+ case splashModeRGB8:
+ if (color[0] == color[1] && color[1] == color[2]) {
+ if (bitmap->rowSize < 0) {
+ memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
+ color[0], -bitmap->rowSize * bitmap->height);
+ } else {
+ memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
+ }
+ } else {
+ row = bitmap->data;
+ for (y = 0; y < bitmap->height; ++y) {
+ p = row;
+ for (x = 0; x < bitmap->width; ++x) {
+ *p++ = color[2];
+ *p++ = color[1];
+ *p++ = color[0];
+ }
+ row += bitmap->rowSize;
+ }
+ }
+ break;
+ case splashModeBGR8:
+ if (color[0] == color[1] && color[1] == color[2]) {
+ if (bitmap->rowSize < 0) {
+ memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
+ color[0], -bitmap->rowSize * bitmap->height);
+ } else {
+ memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
+ }
+ } else {
+ row = bitmap->data;
+ for (y = 0; y < bitmap->height; ++y) {
+ p = row;
+ for (x = 0; x < bitmap->width; ++x) {
+ *p++ = color[0];
+ *p++ = color[1];
+ *p++ = color[2];
+ }
+ row += bitmap->rowSize;
+ }
+ }
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ if (color[0] == color[1] && color[1] == color[2] && color[2] == color[3]) {
+ if (bitmap->rowSize < 0) {
+ memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1),
+ color[0], -bitmap->rowSize * bitmap->height);
+ } else {
+ memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height);
+ }
+ } else {
+ row = bitmap->data;
+ for (y = 0; y < bitmap->height; ++y) {
+ p = row;
+ for (x = 0; x < bitmap->width; ++x) {
+ *p++ = color[0];
+ *p++ = color[1];
+ *p++ = color[2];
+ *p++ = color[3];
+ }
+ row += bitmap->rowSize;
+ }
+ }
+ break;
+#endif
+ }
+
+ if (bitmap->alpha) {
+ memset(bitmap->alpha, alpha, bitmap->width * bitmap->height);
+ }
+
+ updateModX(0);
+ updateModY(0);
+ updateModX(bitmap->width - 1);
+ updateModY(bitmap->height - 1);
+}
+
+SplashError Splash::stroke(SplashPath *path) {
+ SplashPath *path2, *dPath;
+
+ if (debugMode) {
+ printf("stroke [dash:%d] [width:%.2f]:\n",
+ state->lineDashLength, (double)state->lineWidth);
+ dumpPath(path);
+ }
+ opClipRes = splashClipAllOutside;
+ if (path->length == 0) {
+ return splashErrEmptyPath;
+ }
+ path2 = flattenPath(path, state->matrix, state->flatness);
+ if (state->lineDashLength > 0) {
+ dPath = makeDashedPath(path2);
+ delete path2;
+ path2 = dPath;
+ }
+ if (state->lineWidth == 0) {
+ strokeNarrow(path2);
+ } else {
+ strokeWide(path2);
+ }
+ delete path2;
+ return splashOk;
+}
+
+void Splash::strokeNarrow(SplashPath *path) {
+ SplashPipe pipe;
+ SplashXPath *xPath;
+ SplashXPathSeg *seg;
+ int x0, x1, x2, x3, y0, y1, x, y, t;
+ SplashCoord dx, dy, dxdy;
+ SplashClipResult clipRes;
+ int nClipRes[3];
+ int i;
+
+ nClipRes[0] = nClipRes[1] = nClipRes[2] = 0;
+
+ xPath = new SplashXPath(path, state->matrix, state->flatness, gFalse);
+
+ pipeInit(&pipe, 0, 0, state->strokePattern, NULL, state->strokeAlpha,
+ gFalse, gFalse);
+
+ for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) {
+
+ x0 = splashFloor(seg->x0);
+ x1 = splashFloor(seg->x1);
+ y0 = splashFloor(seg->y0);
+ y1 = splashFloor(seg->y1);
+
+ // horizontal segment
+ if (y0 == y1) {
+ if (x0 > x1) {
+ t = x0; x0 = x1; x1 = t;
+ }
+ if ((clipRes = state->clip->testSpan(x0, x1, y0))
+ != splashClipAllOutside) {
+ drawSpan(&pipe, x0, x1, y0, clipRes == splashClipAllInside);
+ }
+
+ // segment with |dx| > |dy|
+ } else if (splashAbs(seg->dxdy) > 1) {
+ dx = seg->x1 - seg->x0;
+ dy = seg->y1 - seg->y0;
+ dxdy = seg->dxdy;
+ if (y0 > y1) {
+ t = y0; y0 = y1; y1 = t;
+ t = x0; x0 = x1; x1 = t;
+ dx = -dx;
+ dy = -dy;
+ }
+ if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0,
+ x0 <= x1 ? x1 : x0, y1))
+ != splashClipAllOutside) {
+ if (dx > 0) {
+ x2 = x0;
+ x3 = splashFloor(seg->x0 + ((SplashCoord)y0 + 1 - seg->y0) * dxdy);
+ drawSpan(&pipe, x2, (x2 <= x3 - 1) ? x3 - 1 : x2, y0,
+ clipRes == splashClipAllInside);
+ x2 = x3;
+ for (y = y0 + 1; y <= y1 - 1; ++y) {
+ x3 = splashFloor(seg->x0 + ((SplashCoord)y + 1 - seg->y0) * dxdy);
+ drawSpan(&pipe, x2, x3 - 1, y, clipRes == splashClipAllInside);
+ x2 = x3;
+ }
+ drawSpan(&pipe, x2, x2 <= x1 ? x1 : x2, y1,
+ clipRes == splashClipAllInside);
+ } else {
+ x2 = x0;
+ x3 = splashFloor(seg->x0 + ((SplashCoord)y0 + 1 - seg->y0) * dxdy);
+ drawSpan(&pipe, (x3 + 1 <= x2) ? x3 + 1 : x2, x2, y0,
+ clipRes == splashClipAllInside);
+ x2 = x3;
+ for (y = y0 + 1; y <= y1 - 1; ++y) {
+ x3 = splashFloor(seg->x0 + ((SplashCoord)y + 1 - seg->y0) * dxdy);
+ drawSpan(&pipe, x3 + 1, x2, y, clipRes == splashClipAllInside);
+ x2 = x3;
+ }
+ drawSpan(&pipe, x1, (x1 <= x2) ? x2 : x1, y1,
+ clipRes == splashClipAllInside);
+ }
+ }
+
+ // segment with |dy| > |dx|
+ } else {
+ dxdy = seg->dxdy;
+ if (y0 > y1) {
+ t = x0; x0 = x1; x1 = t;
+ t = y0; y0 = y1; y1 = t;
+ }
+ if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0,
+ x0 <= x1 ? x1 : x0, y1))
+ != splashClipAllOutside) {
+ drawPixel(&pipe, x0, y0, clipRes == splashClipAllInside);
+ for (y = y0 + 1; y <= y1 - 1; ++y) {
+ x = splashFloor(seg->x0 + ((SplashCoord)y - seg->y0) * dxdy);
+ drawPixel(&pipe, x, y, clipRes == splashClipAllInside);
+ }
+ drawPixel(&pipe, x1, y1, clipRes == splashClipAllInside);
+ }
+ }
+ ++nClipRes[clipRes];
+ }
+ if (nClipRes[splashClipPartial] ||
+ (nClipRes[splashClipAllInside] && nClipRes[splashClipAllOutside])) {
+ opClipRes = splashClipPartial;
+ } else if (nClipRes[splashClipAllInside]) {
+ opClipRes = splashClipAllInside;
+ } else {
+ opClipRes = splashClipAllOutside;
+ }
+
+ delete xPath;
+}
+
+void Splash::strokeWide(SplashPath *path) {
+ SplashPath *path2;
+
+ path2 = makeStrokePath(path, gFalse);
+ fillWithPattern(path2, gFalse, state->strokePattern, state->strokeAlpha);
+ delete path2;
+}
+
+SplashPath *Splash::flattenPath(SplashPath *path, SplashCoord *matrix,
+ SplashCoord flatness) {
+ SplashPath *fPath;
+ SplashCoord flatness2;
+ Guchar flag;
+ int i;
+
+ fPath = new SplashPath();
+ flatness2 = flatness * flatness;
+ i = 0;
+ while (i < path->length) {
+ flag = path->flags[i];
+ if (flag & splashPathFirst) {
+ fPath->moveTo(path->pts[i].x, path->pts[i].y);
+ ++i;
+ } else {
+ if (flag & splashPathCurve) {
+ flattenCurve(path->pts[i-1].x, path->pts[i-1].y,
+ path->pts[i ].x, path->pts[i ].y,
+ path->pts[i+1].x, path->pts[i+1].y,
+ path->pts[i+2].x, path->pts[i+2].y,
+ matrix, flatness2, fPath);
+ i += 3;
+ } else {
+ fPath->lineTo(path->pts[i].x, path->pts[i].y);
+ ++i;
+ }
+ if (path->flags[i-1] & splashPathClosed) {
+ fPath->close();
+ }
+ }
+ }
+ return fPath;
+}
+
+void Splash::flattenCurve(SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1,
+ SplashCoord x2, SplashCoord y2,
+ SplashCoord x3, SplashCoord y3,
+ SplashCoord *matrix, SplashCoord flatness2,
+ SplashPath *fPath) {
+ SplashCoord cx[splashMaxCurveSplits + 1][3];
+ SplashCoord cy[splashMaxCurveSplits + 1][3];
+ int cNext[splashMaxCurveSplits + 1];
+ SplashCoord xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh;
+ SplashCoord yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh;
+ SplashCoord dx, dy, mx, my, tx, ty, d1, d2;
+ int p1, p2, p3;
+
+ // initial segment
+ p1 = 0;
+ p2 = splashMaxCurveSplits;
+ cx[p1][0] = x0; cy[p1][0] = y0;
+ cx[p1][1] = x1; cy[p1][1] = y1;
+ cx[p1][2] = x2; cy[p1][2] = y2;
+ cx[p2][0] = x3; cy[p2][0] = y3;
+ cNext[p1] = p2;
+
+ while (p1 < splashMaxCurveSplits) {
+
+ // get the next segment
+ xl0 = cx[p1][0]; yl0 = cy[p1][0];
+ xx1 = cx[p1][1]; yy1 = cy[p1][1];
+ xx2 = cx[p1][2]; yy2 = cy[p1][2];
+ p2 = cNext[p1];
+ xr3 = cx[p2][0]; yr3 = cy[p2][0];
+
+ // compute the distances (in device space) from the control points
+ // to the midpoint of the straight line (this is a bit of a hack,
+ // but it's much faster than computing the actual distances to the
+ // line)
+ transform(matrix, (xl0 + xr3) * 0.5, (yl0 + yr3) * 0.5, &mx, &my);
+ transform(matrix, xx1, yy1, &tx, &ty);
+ dx = tx - mx;
+ dy = ty - my;
+ d1 = dx*dx + dy*dy;
+ transform(matrix, xx2, yy2, &tx, &ty);
+ dx = tx - mx;
+ dy = ty - my;
+ d2 = dx*dx + dy*dy;
+
+ // if the curve is flat enough, or no more subdivisions are
+ // allowed, add the straight line segment
+ if (p2 - p1 == 1 || (d1 <= flatness2 && d2 <= flatness2)) {
+ fPath->lineTo(xr3, yr3);
+ p1 = p2;
+
+ // otherwise, subdivide the curve
+ } else {
+ xl1 = (xl0 + xx1) * 0.5;
+ yl1 = (yl0 + yy1) * 0.5;
+ xh = (xx1 + xx2) * 0.5;
+ yh = (yy1 + yy2) * 0.5;
+ xl2 = (xl1 + xh) * 0.5;
+ yl2 = (yl1 + yh) * 0.5;
+ xr2 = (xx2 + xr3) * 0.5;
+ yr2 = (yy2 + yr3) * 0.5;
+ xr1 = (xh + xr2) * 0.5;
+ yr1 = (yh + yr2) * 0.5;
+ xr0 = (xl2 + xr1) * 0.5;
+ yr0 = (yl2 + yr1) * 0.5;
+ // add the new subdivision points
+ p3 = (p1 + p2) / 2;
+ cx[p1][1] = xl1; cy[p1][1] = yl1;
+ cx[p1][2] = xl2; cy[p1][2] = yl2;
+ cNext[p1] = p3;
+ cx[p3][0] = xr0; cy[p3][0] = yr0;
+ cx[p3][1] = xr1; cy[p3][1] = yr1;
+ cx[p3][2] = xr2; cy[p3][2] = yr2;
+ cNext[p3] = p2;
+ }
+ }
+}
+
+SplashPath *Splash::makeDashedPath(SplashPath *path) {
+ SplashPath *dPath;
+ SplashCoord lineDashTotal;
+ SplashCoord lineDashStartPhase, lineDashDist, segLen;
+ SplashCoord x0, y0, x1, y1, xa, ya;
+ GBool lineDashStartOn, lineDashOn, newPath;
+ int lineDashStartIdx, lineDashIdx;
+ int i, j, k;
+
+ lineDashTotal = 0;
+ for (i = 0; i < state->lineDashLength; ++i) {
+ lineDashTotal += state->lineDash[i];
+ }
+ lineDashStartPhase = state->lineDashPhase;
+ i = splashFloor(lineDashStartPhase / lineDashTotal);
+ lineDashStartPhase -= (SplashCoord)i * lineDashTotal;
+ lineDashStartOn = gTrue;
+ lineDashStartIdx = 0;
+ while (lineDashStartPhase >= state->lineDash[lineDashStartIdx]) {
+ lineDashStartOn = !lineDashStartOn;
+ lineDashStartPhase -= state->lineDash[lineDashStartIdx];
+ ++lineDashStartIdx;
+ }
+
+ dPath = new SplashPath();
+
+ // process each subpath
+ i = 0;
+ while (i < path->length) {
+
+ // find the end of the subpath
+ for (j = i;
+ j < path->length - 1 && !(path->flags[j] & splashPathLast);
+ ++j) ;
+
+ // initialize the dash parameters
+ lineDashOn = lineDashStartOn;
+ lineDashIdx = lineDashStartIdx;
+ lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase;
+
+ // process each segment of the subpath
+ newPath = gTrue;
+ for (k = i; k < j; ++k) {
+
+ // grab the segment
+ x0 = path->pts[k].x;
+ y0 = path->pts[k].y;
+ x1 = path->pts[k+1].x;
+ y1 = path->pts[k+1].y;
+ segLen = splashDist(x0, y0, x1, y1);
+
+ // process the segment
+ while (segLen > 0) {
+
+ if (lineDashDist >= segLen) {
+ if (lineDashOn) {
+ if (newPath) {
+ dPath->moveTo(x0, y0);
+ newPath = gFalse;
+ }
+ dPath->lineTo(x1, y1);
+ }
+ lineDashDist -= segLen;
+ segLen = 0;
+
+ } else {
+ xa = x0 + (lineDashDist / segLen) * (x1 - x0);
+ ya = y0 + (lineDashDist / segLen) * (y1 - y0);
+ if (lineDashOn) {
+ if (newPath) {
+ dPath->moveTo(x0, y0);
+ newPath = gFalse;
+ }
+ dPath->lineTo(xa, ya);
+ }
+ x0 = xa;
+ y0 = ya;
+ segLen -= lineDashDist;
+ lineDashDist = 0;
+ }
+
+ // get the next entry in the dash array
+ if (lineDashDist <= 0) {
+ lineDashOn = !lineDashOn;
+ if (++lineDashIdx == state->lineDashLength) {
+ lineDashIdx = 0;
+ }
+ lineDashDist = state->lineDash[lineDashIdx];
+ newPath = gTrue;
+ }
+ }
+ }
+ i = j + 1;
+ }
+
+ return dPath;
+}
+
+SplashError Splash::fill(SplashPath *path, GBool eo) {
+ if (debugMode) {
+ printf("fill [eo:%d]:\n", eo);
+ dumpPath(path);
+ }
+ return fillWithPattern(path, eo, state->fillPattern, state->fillAlpha);
+}
+
+SplashError Splash::fillWithPattern(SplashPath *path, GBool eo,
+ SplashPattern *pattern,
+ SplashCoord alpha) {
+ SplashPipe pipe;
+ SplashXPath *xPath;
+ SplashXPathScanner *scanner;
+ int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
+ SplashClipResult clipRes, clipRes2;
+
+ if (path->length == 0) {
+ return splashErrEmptyPath;
+ }
+ xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue);
+ if (vectorAntialias) {
+ xPath->aaScale();
+ }
+ xPath->sort();
+ scanner = new SplashXPathScanner(xPath, eo);
+
+ // get the min and max x and y values
+ if (vectorAntialias) {
+ scanner->getBBoxAA(&xMinI, &yMinI, &xMaxI, &yMaxI);
+ } else {
+ scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI);
+ }
+
+ // check clipping
+ if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI))
+ != splashClipAllOutside) {
+
+ // limit the y range
+ if (yMinI < state->clip->getYMinI()) {
+ yMinI = state->clip->getYMinI();
+ }
+ if (yMaxI > state->clip->getYMaxI()) {
+ yMaxI = state->clip->getYMaxI();
+ }
+
+ pipeInit(&pipe, 0, yMinI, pattern, NULL, alpha, vectorAntialias, gFalse);
+
+ // draw the spans
+ if (vectorAntialias) {
+ for (y = yMinI; y <= yMaxI; ++y) {
+ scanner->renderAALine(aaBuf, &x0, &x1, y);
+ if (clipRes != splashClipAllInside) {
+ state->clip->clipAALine(aaBuf, &x0, &x1, y);
+ }
+ drawAALine(&pipe, x0, x1, y);
+ }
+ } else {
+ for (y = yMinI; y <= yMaxI; ++y) {
+ while (scanner->getNextSpan(y, &x0, &x1)) {
+ if (clipRes == splashClipAllInside) {
+ drawSpan(&pipe, x0, x1, y, gTrue);
+ } else {
+ // limit the x range
+ if (x0 < state->clip->getXMinI()) {
+ x0 = state->clip->getXMinI();
+ }
+ if (x1 > state->clip->getXMaxI()) {
+ x1 = state->clip->getXMaxI();
+ }
+ clipRes2 = state->clip->testSpan(x0, x1, y);
+ drawSpan(&pipe, x0, x1, y, clipRes2 == splashClipAllInside);
+ }
+ }
+ }
+ }
+ }
+ opClipRes = clipRes;
+
+ delete scanner;
+ delete xPath;
+ return splashOk;
+}
+
+SplashError Splash::xorFill(SplashPath *path, GBool eo) {
+ SplashPipe pipe;
+ SplashXPath *xPath;
+ SplashXPathScanner *scanner;
+ int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y;
+ SplashClipResult clipRes, clipRes2;
+ SplashBlendFunc origBlendFunc;
+
+ if (path->length == 0) {
+ return splashErrEmptyPath;
+ }
+ xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue);
+ xPath->sort();
+ scanner = new SplashXPathScanner(xPath, eo);
+
+ // get the min and max x and y values
+ scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI);
+
+ // check clipping
+ if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI))
+ != splashClipAllOutside) {
+
+ // limit the y range
+ if (yMinI < state->clip->getYMinI()) {
+ yMinI = state->clip->getYMinI();
+ }
+ if (yMaxI > state->clip->getYMaxI()) {
+ yMaxI = state->clip->getYMaxI();
+ }
+
+ origBlendFunc = state->blendFunc;
+ state->blendFunc = &blendXor;
+ pipeInit(&pipe, 0, yMinI, state->fillPattern, NULL, 1, gFalse, gFalse);
+
+ // draw the spans
+ for (y = yMinI; y <= yMaxI; ++y) {
+ while (scanner->getNextSpan(y, &x0, &x1)) {
+ if (clipRes == splashClipAllInside) {
+ drawSpan(&pipe, x0, x1, y, gTrue);
+ } else {
+ // limit the x range
+ if (x0 < state->clip->getXMinI()) {
+ x0 = state->clip->getXMinI();
+ }
+ if (x1 > state->clip->getXMaxI()) {
+ x1 = state->clip->getXMaxI();
+ }
+ clipRes2 = state->clip->testSpan(x0, x1, y);
+ drawSpan(&pipe, x0, x1, y, clipRes2 == splashClipAllInside);
+ }
+ }
+ }
+ state->blendFunc = origBlendFunc;
+ }
+ opClipRes = clipRes;
+
+ delete scanner;
+ delete xPath;
+ return splashOk;
+}
+
+SplashError Splash::fillChar(SplashCoord x, SplashCoord y,
+ int c, SplashFont *font) {
+ SplashGlyphBitmap glyph;
+ SplashCoord xt, yt;
+ int x0, y0, xFrac, yFrac;
+ SplashClipResult clipRes;
+
+ if (debugMode) {
+ printf("fillChar: x=%.2f y=%.2f c=%3d=0x%02x='%c'\n",
+ (double)x, (double)y, c, c, c);
+ }
+ transform(state->matrix, x, y, &xt, &yt);
+ x0 = splashFloor(xt);
+ xFrac = splashFloor((xt - x0) * splashFontFraction);
+ y0 = splashFloor(yt);
+ yFrac = splashFloor((yt - y0) * splashFontFraction);
+ if (!font->getGlyph(c, xFrac, yFrac, &glyph, x0, y0, state->clip, &clipRes)) {
+ return splashErrNoGlyph;
+ }
+ if (clipRes != splashClipAllOutside) {
+ fillGlyph2(x0, y0, &glyph, clipRes == splashClipAllInside);
+ }
+ opClipRes = clipRes;
+ if (glyph.freeData) {
+ gfree(glyph.data);
+ }
+ return splashOk;
+}
+
+void Splash::fillGlyph(SplashCoord x, SplashCoord y,
+ SplashGlyphBitmap *glyph) {
+ SplashCoord xt, yt;
+ int x0, y0;
+
+ transform(state->matrix, x, y, &xt, &yt);
+ x0 = splashFloor(xt);
+ y0 = splashFloor(yt);
+ SplashClipResult clipRes = state->clip->testRect(x0 - glyph->x,
+ y0 - glyph->y,
+ x0 - glyph->x + glyph->w - 1,
+ y0 - glyph->y + glyph->h - 1);
+ if (clipRes != splashClipAllOutside) {
+ fillGlyph2(x0, y0, glyph, clipRes == splashClipAllInside);
+ }
+ opClipRes = clipRes;
+}
+
+void Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noClip) {
+ SplashPipe pipe;
+ int alpha0, alpha;
+ Guchar *p;
+ int x1, y1, xx, xx1, yy;
+
+ p = glyph->data;
+ int xStart = x0 - glyph->x;
+ int yStart = y0 - glyph->y;
+ int xxLimit = glyph->w;
+ int yyLimit = glyph->h;
+
+ if (yStart < 0)
+ {
+ p += glyph->w * -yStart; // move p to the beginning of the first painted row
+ yyLimit += yStart;
+ yStart = 0;
+ }
+
+ if (xStart < 0)
+ {
+ p += -xStart; // move p to the first painted pixel
+ xxLimit += xStart;
+ xStart = 0;
+ }
+
+ if (xxLimit + xStart >= bitmap->width) xxLimit = bitmap->width - xStart;
+ if (yyLimit + yStart >= bitmap->height) yyLimit = bitmap->height - yStart;
+
+ if (noClip) {
+ if (glyph->aa) {
+ pipeInit(&pipe, xStart, yStart,
+ state->fillPattern, NULL, state->fillAlpha, gTrue, gFalse);
+ for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) {
+ pipeSetXY(&pipe, xStart, y1);
+ for (xx = 0, x1 = xStart; xx < xxLimit; ++xx, ++x1) {
+ alpha = p[xx];
+ if (alpha != 0) {
+ pipe.shape = (SplashCoord)(alpha / 255.0);
+ pipeRun(&pipe);
+ updateModX(x1);
+ updateModY(y1);
+ } else {
+ pipeIncX(&pipe);
+ }
+ }
+ p += glyph->w;
+ }
+ } else {
+ const int widthEight = (int)ceil(glyph->w / 8.0);
+
+ pipeInit(&pipe, xStart, yStart,
+ state->fillPattern, NULL, state->fillAlpha, gFalse, gFalse);
+ for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) {
+ pipeSetXY(&pipe, xStart, y1);
+ for (xx = 0, x1 = xStart; xx < xxLimit; xx += 8) {
+ alpha0 = p[xx / 8];
+ for (xx1 = 0; xx1 < 8 && xx + xx1 < xxLimit; ++xx1, ++x1) {
+ if (alpha0 & 0x80) {
+ pipeRun(&pipe);
+ updateModX(x1);
+ updateModY(y1);
+ } else {
+ pipeIncX(&pipe);
+ }
+ alpha0 <<= 1;
+ }
+ }
+ p += widthEight;
+ }
+ }
+ } else {
+ if (glyph->aa) {
+ pipeInit(&pipe, xStart, yStart,
+ state->fillPattern, NULL, state->fillAlpha, gTrue, gFalse);
+ for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) {
+ pipeSetXY(&pipe, xStart, y1);
+ for (xx = 0, x1 = xStart; xx < xxLimit; ++xx, ++x1) {
+ if (state->clip->test(x1, y1)) {
+ alpha = p[xx];
+ if (alpha != 0) {
+ pipe.shape = (SplashCoord)(alpha / 255.0);
+ pipeRun(&pipe);
+ updateModX(x1);
+ updateModY(y1);
+ } else {
+ pipeIncX(&pipe);
+ }
+ } else {
+ pipeIncX(&pipe);
+ }
+ }
+ p += glyph->w;
+ }
+ } else {
+ const int widthEight = (int)ceil(glyph->w / 8.0);
+
+ pipeInit(&pipe, xStart, yStart,
+ state->fillPattern, NULL, state->fillAlpha, gFalse, gFalse);
+ for (yy = 0, y1 = yStart; yy < yyLimit; ++yy, ++y1) {
+ pipeSetXY(&pipe, xStart, y1);
+ for (xx = 0, x1 = xStart; xx < xxLimit; xx += 8) {
+ alpha0 = p[xx / 8];
+ for (xx1 = 0; xx1 < 8 && xx + xx1 < xxLimit; ++xx1, ++x1) {
+ if (state->clip->test(x1, y1)) {
+ if (alpha0 & 0x80) {
+ pipeRun(&pipe);
+ updateModX(x1);
+ updateModY(y1);
+ } else {
+ pipeIncX(&pipe);
+ }
+ } else {
+ pipeIncX(&pipe);
+ }
+ alpha0 <<= 1;
+ }
+ }
+ p += widthEight;
+ }
+ }
+ }
+}
+
+SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData,
+ int w, int h, SplashCoord *mat,
+ GBool glyphMode) {
+ SplashPipe pipe;
+ GBool rot;
+ SplashCoord xScale, yScale, xShear, yShear, yShear1;
+ int tx, tx2, ty, ty2, scaledWidth, scaledHeight, xSign, ySign;
+ int ulx, uly, llx, lly, urx, ury, lrx, lry;
+ int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1;
+ int xMin, xMax, yMin, yMax;
+ SplashClipResult clipRes, clipRes2;
+ int yp, yq, yt, yStep, lastYStep;
+ int xp, xq, xt, xStep, xSrc;
+ int k1, spanXMin, spanXMax, spanY;
+ SplashColorPtr pixBuf, p;
+ int pixAcc;
+ int x, y, x1, x2, y2;
+ SplashCoord y1;
+ int n, m, i, j;
+
+ if (debugMode) {
+ printf("fillImageMask: w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
+ w, h, (double)mat[0], (double)mat[1], (double)mat[2],
+ (double)mat[3], (double)mat[4], (double)mat[5]);
+ }
+
+ if (w == 0 && h == 0) return splashErrZeroImage;
+
+ // check for singular matrix
+ if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) {
+ return splashErrSingularMatrix;
+ }
+
+ // compute scale, shear, rotation, translation parameters
+ rot = splashAbs(mat[1]) > splashAbs(mat[0]);
+ if (rot) {
+ xScale = -mat[1];
+ yScale = mat[2] - (mat[0] * mat[3]) / mat[1];
+ xShear = -mat[3] / yScale;
+ yShear = -mat[0] / mat[1];
+ } else {
+ xScale = mat[0];
+ yScale = mat[3] - (mat[1] * mat[2]) / mat[0];
+ xShear = mat[2] / yScale;
+ yShear = mat[1] / mat[0];
+ }
+ // Note 1: The PDF spec says that all pixels whose *centers* lie
+ // within the region get painted -- but that doesn't seem to match
+ // up with what Acrobat actually does: it ends up leaving gaps
+ // between image stripes. So we use the same rule here as for
+ // fills: any pixel that overlaps the region gets painted.
+ // Note 2: The "glyphMode" flag is a kludge: it switches back to
+ // "correct" behavior (matching the spec), for use in rendering Type
+ // 3 fonts.
+ // Note 3: The +/-0.01 in these computations is to avoid floating
+ // point precision problems which can lead to gaps between image
+ // stripes (it can cause image stripes to overlap, but that's a much
+ // less visible problem).
+ if (glyphMode) {
+ if (xScale >= 0) {
+ tx = splashRound(mat[4]);
+ tx2 = splashRound(mat[4] + xScale) - 1;
+ } else {
+ tx = splashRound(mat[4]) - 1;
+ tx2 = splashRound(mat[4] + xScale);
+ }
+ } else {
+ if (xScale >= 0) {
+ tx = splashFloor(mat[4] - 0.01);
+ tx2 = splashFloor(mat[4] + xScale + 0.01);
+ } else {
+ tx = splashFloor(mat[4] + 0.01);
+ tx2 = splashFloor(mat[4] + xScale - 0.01);
+ }
+ }
+ scaledWidth = abs(tx2 - tx) + 1;
+ if (glyphMode) {
+ if (yScale >= 0) {
+ ty = splashRound(mat[5]);
+ ty2 = splashRound(mat[5] + yScale) - 1;
+ } else {
+ ty = splashRound(mat[5]) - 1;
+ ty2 = splashRound(mat[5] + yScale);
+ }
+ } else {
+ if (yScale >= 0) {
+ ty = splashFloor(mat[5] - 0.01);
+ ty2 = splashFloor(mat[5] + yScale + 0.01);
+ } else {
+ ty = splashFloor(mat[5] + 0.01);
+ ty2 = splashFloor(mat[5] + yScale - 0.01);
+ }
+ }
+ scaledHeight = abs(ty2 - ty) + 1;
+ xSign = (xScale < 0) ? -1 : 1;
+ ySign = (yScale < 0) ? -1 : 1;
+ yShear1 = (SplashCoord)xSign * yShear;
+
+ // clipping
+ ulx1 = 0;
+ uly1 = 0;
+ urx1 = xSign * (scaledWidth - 1);
+ ury1 = (int)(yShear * urx1);
+ llx1 = splashRound(xShear * ySign * (scaledHeight - 1));
+ lly1 = ySign * (scaledHeight - 1) + (int)(yShear * llx1);
+ lrx1 = xSign * (scaledWidth - 1) +
+ splashRound(xShear * ySign * (scaledHeight - 1));
+ lry1 = ySign * (scaledHeight - 1) + (int)(yShear * lrx1);
+ if (rot) {
+ ulx = tx + uly1; uly = ty - ulx1;
+ urx = tx + ury1; ury = ty - urx1;
+ llx = tx + lly1; lly = ty - llx1;
+ lrx = tx + lry1; lry = ty - lrx1;
+ } else {
+ ulx = tx + ulx1; uly = ty + uly1;
+ urx = tx + urx1; ury = ty + ury1;
+ llx = tx + llx1; lly = ty + lly1;
+ lrx = tx + lrx1; lry = ty + lry1;
+ }
+ xMin = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx
+ : (llx < lrx) ? llx : lrx
+ : (urx < llx) ? (urx < lrx) ? urx : lrx
+ : (llx < lrx) ? llx : lrx;
+ xMax = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx
+ : (llx > lrx) ? llx : lrx
+ : (urx > llx) ? (urx > lrx) ? urx : lrx
+ : (llx > lrx) ? llx : lrx;
+ yMin = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry
+ : (lly < lry) ? lly : lry
+ : (ury < lly) ? (ury < lry) ? ury : lry
+ : (lly < lry) ? lly : lry;
+ yMax = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry
+ : (lly > lry) ? lly : lry
+ : (ury > lly) ? (ury > lry) ? ury : lry
+ : (lly > lry) ? lly : lry;
+ clipRes = state->clip->testRect(xMin, yMin, xMax, yMax);
+ opClipRes = clipRes;
+
+ // compute Bresenham parameters for x and y scaling
+ yp = h / scaledHeight;
+ yq = h % scaledHeight;
+ xp = w / scaledWidth;
+ xq = w % scaledWidth;
+
+ // allocate pixel buffer
+ pixBuf = (SplashColorPtr)gmalloc((yp + 1) * w);
+
+ // initialize the pixel pipe
+ pipeInit(&pipe, 0, 0, state->fillPattern, NULL, state->fillAlpha,
+ gTrue, gFalse);
+ if (vectorAntialias) {
+ drawAAPixelInit();
+ }
+
+ // init y scale Bresenham
+ yt = 0;
+ lastYStep = 1;
+
+ for (y = 0; y < scaledHeight; ++y) {
+
+ // y scale Bresenham
+ yStep = yp;
+ yt += yq;
+ if (yt >= scaledHeight) {
+ yt -= scaledHeight;
+ ++yStep;
+ }
+
+ // read row(s) from image
+ n = (yp > 0) ? yStep : lastYStep;
+ if (n > 0) {
+ p = pixBuf;
+ for (i = 0; i < n; ++i) {
+ (*src)(srcData, p);
+ p += w;
+ }
+ }
+ lastYStep = yStep;
+
+ // loop-invariant constants
+ k1 = splashRound(xShear * ySign * y);
+
+ // clipping test
+ if (clipRes != splashClipAllInside &&
+ !rot &&
+ (int)(yShear * k1) ==
+ (int)(yShear * (xSign * (scaledWidth - 1) + k1))) {
+ if (xSign > 0) {
+ spanXMin = tx + k1;
+ spanXMax = spanXMin + (scaledWidth - 1);
+ } else {
+ spanXMax = tx + k1;
+ spanXMin = spanXMax - (scaledWidth - 1);
+ }
+ spanY = ty + ySign * y + (int)(yShear * k1);
+ clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY);
+ if (clipRes2 == splashClipAllOutside) {
+ continue;
+ }
+ } else {
+ clipRes2 = clipRes;
+ }
+
+ // init x scale Bresenham
+ xt = 0;
+ xSrc = 0;
+
+ // x shear
+ x1 = k1;
+
+ // y shear
+ y1 = (SplashCoord)ySign * y + yShear * x1;
+ // this is a kludge: if yShear1 is negative, then (int)y1 would
+ // change immediately after the first pixel, which is not what we
+ // want
+ if (yShear1 < 0) {
+ y1 += 0.999;
+ }
+
+ // loop-invariant constants
+ n = yStep > 0 ? yStep : 1;
+
+ for (x = 0; x < scaledWidth; ++x) {
+
+ // x scale Bresenham
+ xStep = xp;
+ xt += xq;
+ if (xt >= scaledWidth) {
+ xt -= scaledWidth;
+ ++xStep;
+ }
+
+ // rotation
+ if (rot) {
+ x2 = (int)y1;
+ y2 = -x1;
+ } else {
+ x2 = x1;
+ y2 = (int)y1;
+ }
+
+ // compute the alpha value for (x,y) after the x and y scaling
+ // operations
+ m = xStep > 0 ? xStep : 1;
+ p = pixBuf + xSrc;
+ pixAcc = 0;
+ for (i = 0; i < n; ++i) {
+ for (j = 0; j < m; ++j) {
+ pixAcc += *p++;
+ }
+ p += w - m;
+ }
+
+ // blend fill color with background
+ if (pixAcc != 0) {
+ pipe.shape = (pixAcc == n * m)
+ ? (SplashCoord)1
+ : (SplashCoord)pixAcc / (SplashCoord)(n * m);
+ if (vectorAntialias && clipRes2 != splashClipAllInside) {
+ drawAAPixel(&pipe, tx + x2, ty + y2);
+ } else {
+ drawPixel(&pipe, tx + x2, ty + y2, clipRes2 == splashClipAllInside);
+ }
+ }
+
+ // x scale Bresenham
+ xSrc += xStep;
+
+ // x shear
+ x1 += xSign;
+
+ // y shear
+ y1 += yShear1;
+ }
+ }
+
+ // free memory
+ gfree(pixBuf);
+
+ return splashOk;
+}
+
+SplashError Splash::drawImage(SplashImageSource src, void *srcData,
+ SplashColorMode srcMode, GBool srcAlpha,
+ int w, int h, SplashCoord *mat) {
+ SplashPipe pipe;
+ GBool ok, rot;
+ SplashCoord xScale, yScale, xShear, yShear, yShear1;
+ int tx, tx2, ty, ty2, scaledWidth, scaledHeight, xSign, ySign;
+ int ulx, uly, llx, lly, urx, ury, lrx, lry;
+ int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1;
+ int xMin, xMax, yMin, yMax;
+ SplashClipResult clipRes, clipRes2;
+ int yp, yq, yt, yStep, lastYStep;
+ int xp, xq, xt, xStep, xSrc;
+ int k1, spanXMin, spanXMax, spanY;
+ SplashColorPtr colorBuf, p;
+ SplashColor pix;
+ Guchar *alphaBuf, *q;
+#if SPLASH_CMYK
+ int pixAcc0, pixAcc1, pixAcc2, pixAcc3;
+#else
+ int pixAcc0, pixAcc1, pixAcc2;
+#endif
+ int alphaAcc;
+ SplashCoord pixMul, alphaMul, alpha;
+ int x, y, x1, x2, y2;
+ SplashCoord y1;
+ int nComps, n, m, i, j;
+
+ if (debugMode) {
+ printf("drawImage: srcMode=%d srcAlpha=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n",
+ srcMode, srcAlpha, w, h, (double)mat[0], (double)mat[1], (double)mat[2],
+ (double)mat[3], (double)mat[4], (double)mat[5]);
+ }
+
+ // check color modes
+ ok = gFalse; // make gcc happy
+ nComps = 0; // make gcc happy
+ switch (bitmap->mode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ ok = srcMode == splashModeMono8;
+ nComps = 1;
+ break;
+ case splashModeRGB8:
+ ok = srcMode == splashModeRGB8;
+ nComps = 3;
+ break;
+ case splashModeBGR8:
+ ok = srcMode == splashModeBGR8;
+ nComps = 3;
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ ok = srcMode == splashModeCMYK8;
+ nComps = 4;
+ break;
+#endif
+ }
+ if (!ok) {
+ return splashErrModeMismatch;
+ }
+
+ // check for singular matrix
+ if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) {
+ return splashErrSingularMatrix;
+ }
+
+ // compute scale, shear, rotation, translation parameters
+ rot = splashAbs(mat[1]) > splashAbs(mat[0]);
+ if (rot) {
+ xScale = -mat[1];
+ yScale = mat[2] - (mat[0] * mat[3]) / mat[1];
+ xShear = -mat[3] / yScale;
+ yShear = -mat[0] / mat[1];
+ } else {
+ xScale = mat[0];
+ yScale = mat[3] - (mat[1] * mat[2]) / mat[0];
+ xShear = mat[2] / yScale;
+ yShear = mat[1] / mat[0];
+ }
+ // Note 1: The PDF spec says that all pixels whose *centers* lie
+ // within the region get painted -- but that doesn't seem to match
+ // up with what Acrobat actually does: it ends up leaving gaps
+ // between image stripes. So we use the same rule here as for
+ // fills: any pixel that overlaps the region gets painted.
+ // Note 2: The +/-0.01 in these computations is to avoid floating
+ // point precision problems which can lead to gaps between image
+ // stripes (it can cause image stripes to overlap, but that's a much
+ // less visible problem).
+ if (xScale >= 0) {
+ tx = splashFloor(mat[4] - 0.01);
+ tx2 = splashFloor(mat[4] + xScale + 0.01);
+ } else {
+ tx = splashFloor(mat[4] + 0.01);
+ tx2 = splashFloor(mat[4] + xScale - 0.01);
+ }
+ scaledWidth = abs(tx2 - tx) + 1;
+ if (yScale >= 0) {
+ ty = splashFloor(mat[5] - 0.01);
+ ty2 = splashFloor(mat[5] + yScale + 0.01);
+ } else {
+ ty = splashFloor(mat[5] + 0.01);
+ ty2 = splashFloor(mat[5] + yScale - 0.01);
+ }
+ scaledHeight = abs(ty2 - ty) + 1;
+ xSign = (xScale < 0) ? -1 : 1;
+ ySign = (yScale < 0) ? -1 : 1;
+ yShear1 = (SplashCoord)xSign * yShear;
+
+ // clipping
+ ulx1 = 0;
+ uly1 = 0;
+ urx1 = xSign * (scaledWidth - 1);
+ ury1 = (int)(yShear * urx1);
+ llx1 = splashRound(xShear * ySign * (scaledHeight - 1));
+ lly1 = ySign * (scaledHeight - 1) + (int)(yShear * llx1);
+ lrx1 = xSign * (scaledWidth - 1) +
+ splashRound(xShear * ySign * (scaledHeight - 1));
+ lry1 = ySign * (scaledHeight - 1) + (int)(yShear * lrx1);
+ if (rot) {
+ ulx = tx + uly1; uly = ty - ulx1;
+ urx = tx + ury1; ury = ty - urx1;
+ llx = tx + lly1; lly = ty - llx1;
+ lrx = tx + lry1; lry = ty - lrx1;
+ } else {
+ ulx = tx + ulx1; uly = ty + uly1;
+ urx = tx + urx1; ury = ty + ury1;
+ llx = tx + llx1; lly = ty + lly1;
+ lrx = tx + lrx1; lry = ty + lry1;
+ }
+ xMin = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx
+ : (llx < lrx) ? llx : lrx
+ : (urx < llx) ? (urx < lrx) ? urx : lrx
+ : (llx < lrx) ? llx : lrx;
+ xMax = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx
+ : (llx > lrx) ? llx : lrx
+ : (urx > llx) ? (urx > lrx) ? urx : lrx
+ : (llx > lrx) ? llx : lrx;
+ yMin = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry
+ : (lly < lry) ? lly : lry
+ : (ury < lly) ? (ury < lry) ? ury : lry
+ : (lly < lry) ? lly : lry;
+ yMax = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry
+ : (lly > lry) ? lly : lry
+ : (ury > lly) ? (ury > lry) ? ury : lry
+ : (lly > lry) ? lly : lry;
+ clipRes = state->clip->testRect(xMin, yMin, xMax, yMax);
+ opClipRes = clipRes;
+ if (clipRes == splashClipAllOutside) {
+ return splashOk;
+ }
+
+ // compute Bresenham parameters for x and y scaling
+ yp = h / scaledHeight;
+ yq = h % scaledHeight;
+ xp = w / scaledWidth;
+ xq = w % scaledWidth;
+
+ // allocate pixel buffers
+ colorBuf = (SplashColorPtr)gmalloc((yp + 1) * w * nComps);
+ if (srcAlpha) {
+ alphaBuf = (Guchar *)gmalloc((yp + 1) * w);
+ } else {
+ alphaBuf = NULL;
+ }
+
+ pixAcc0 = pixAcc1 = pixAcc2 = 0; // make gcc happy
+#if SPLASH_CMYK
+ pixAcc3 = 0; // make gcc happy
+#endif
+
+ // initialize the pixel pipe
+ pipeInit(&pipe, 0, 0, NULL, pix, state->fillAlpha,
+ srcAlpha || (vectorAntialias && clipRes != splashClipAllInside),
+ gFalse);
+ if (vectorAntialias) {
+ drawAAPixelInit();
+ }
+
+ if (srcAlpha) {
+
+ // init y scale Bresenham
+ yt = 0;
+ lastYStep = 1;
+
+ for (y = 0; y < scaledHeight; ++y) {
+
+ // y scale Bresenham
+ yStep = yp;
+ yt += yq;
+ if (yt >= scaledHeight) {
+ yt -= scaledHeight;
+ ++yStep;
+ }
+
+ // read row(s) from image
+ n = (yp > 0) ? yStep : lastYStep;
+ if (n > 0) {
+ p = colorBuf;
+ q = alphaBuf;
+ for (i = 0; i < n; ++i) {
+ (*src)(srcData, p, q);
+ p += w * nComps;
+ q += w;
+ }
+ }
+ lastYStep = yStep;
+
+ // loop-invariant constants
+ k1 = splashRound(xShear * ySign * y);
+
+ // clipping test
+ if (clipRes != splashClipAllInside &&
+ !rot &&
+ (int)(yShear * k1) ==
+ (int)(yShear * (xSign * (scaledWidth - 1) + k1))) {
+ if (xSign > 0) {
+ spanXMin = tx + k1;
+ spanXMax = spanXMin + (scaledWidth - 1);
+ } else {
+ spanXMax = tx + k1;
+ spanXMin = spanXMax - (scaledWidth - 1);
+ }
+ spanY = ty + ySign * y + (int)(yShear * k1);
+ clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY);
+ if (clipRes2 == splashClipAllOutside) {
+ continue;
+ }
+ } else {
+ clipRes2 = clipRes;
+ }
+
+ // init x scale Bresenham
+ xt = 0;
+ xSrc = 0;
+
+ // x shear
+ x1 = k1;
+
+ // y shear
+ y1 = (SplashCoord)ySign * y + yShear * x1;
+ // this is a kludge: if yShear1 is negative, then (int)y1 would
+ // change immediately after the first pixel, which is not what
+ // we want
+ if (yShear1 < 0) {
+ y1 += 0.999;
+ }
+
+ // loop-invariant constants
+ n = yStep > 0 ? yStep : 1;
+
+ switch (srcMode) {
+
+ case splashModeMono1:
+ case splashModeMono8:
+ for (x = 0; x < scaledWidth; ++x) {
+
+ // x scale Bresenham
+ xStep = xp;
+ xt += xq;
+ if (xt >= scaledWidth) {
+ xt -= scaledWidth;
+ ++xStep;
+ }
+
+ // rotation
+ if (rot) {
+ x2 = (int)y1;
+ y2 = -x1;
+ } else {
+ x2 = x1;
+ y2 = (int)y1;
+ }
+
+ // compute the filtered pixel at (x,y) after the x and y scaling
+ // operations
+ m = xStep > 0 ? xStep : 1;
+ alphaAcc = 0;
+ p = colorBuf + xSrc;
+ q = alphaBuf + xSrc;
+ pixAcc0 = 0;
+ for (i = 0; i < n; ++i) {
+ for (j = 0; j < m; ++j) {
+ pixAcc0 += *p++;
+ alphaAcc += *q++;
+ }
+ p += w - m;
+ q += w - m;
+ }
+ pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
+ alphaMul = pixMul * (1.0 / 255.0);
+ alpha = (SplashCoord)alphaAcc * alphaMul;
+
+ if (alpha > 0) {
+ pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
+
+ // set pixel
+ pipe.shape = alpha;
+ if (vectorAntialias && clipRes != splashClipAllInside) {
+ drawAAPixel(&pipe, tx + x2, ty + y2);
+ } else {
+ drawPixel(&pipe, tx + x2, ty + y2,
+ clipRes2 == splashClipAllInside);
+ }
+ }
+
+ // x scale Bresenham
+ xSrc += xStep;
+
+ // x shear
+ x1 += xSign;
+
+ // y shear
+ y1 += yShear1;
+ }
+ break;
+
+ case splashModeRGB8:
+ case splashModeBGR8:
+ for (x = 0; x < scaledWidth; ++x) {
+
+ // x scale Bresenham
+ xStep = xp;
+ xt += xq;
+ if (xt >= scaledWidth) {
+ xt -= scaledWidth;
+ ++xStep;
+ }
+
+ // rotation
+ if (rot) {
+ x2 = (int)y1;
+ y2 = -x1;
+ } else {
+ x2 = x1;
+ y2 = (int)y1;
+ }
+
+ // compute the filtered pixel at (x,y) after the x and y scaling
+ // operations
+ m = xStep > 0 ? xStep : 1;
+ alphaAcc = 0;
+ p = colorBuf + xSrc * 3;
+ q = alphaBuf + xSrc;
+ pixAcc0 = pixAcc1 = pixAcc2 = 0;
+ for (i = 0; i < n; ++i) {
+ for (j = 0; j < m; ++j) {
+ pixAcc0 += *p++;
+ pixAcc1 += *p++;
+ pixAcc2 += *p++;
+ alphaAcc += *q++;
+ }
+ p += 3 * (w - m);
+ q += w - m;
+ }
+ pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
+ alphaMul = pixMul * (1.0 / 255.0);
+ alpha = (SplashCoord)alphaAcc * alphaMul;
+
+ if (alpha > 0) {
+ pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
+ pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
+ pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
+
+ // set pixel
+ pipe.shape = alpha;
+ if (vectorAntialias && clipRes != splashClipAllInside) {
+ drawAAPixel(&pipe, tx + x2, ty + y2);
+ } else {
+ drawPixel(&pipe, tx + x2, ty + y2,
+ clipRes2 == splashClipAllInside);
+ }
+ }
+
+ // x scale Bresenham
+ xSrc += xStep;
+
+ // x shear
+ x1 += xSign;
+
+ // y shear
+ y1 += yShear1;
+ }
+ break;
+
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ for (x = 0; x < scaledWidth; ++x) {
+
+ // x scale Bresenham
+ xStep = xp;
+ xt += xq;
+ if (xt >= scaledWidth) {
+ xt -= scaledWidth;
+ ++xStep;
+ }
+
+ // rotation
+ if (rot) {
+ x2 = (int)y1;
+ y2 = -x1;
+ } else {
+ x2 = x1;
+ y2 = (int)y1;
+ }
+
+ // compute the filtered pixel at (x,y) after the x and y scaling
+ // operations
+ m = xStep > 0 ? xStep : 1;
+ alphaAcc = 0;
+ p = colorBuf + xSrc * 4;
+ q = alphaBuf + xSrc;
+ pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0;
+ for (i = 0; i < n; ++i) {
+ for (j = 0; j < m; ++j) {
+ pixAcc0 += *p++;
+ pixAcc1 += *p++;
+ pixAcc2 += *p++;
+ pixAcc3 += *p++;
+ alphaAcc += *q++;
+ }
+ p += 4 * (w - m);
+ q += w - m;
+ }
+ pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
+ alphaMul = pixMul * (1.0 / 255.0);
+ alpha = (SplashCoord)alphaAcc * alphaMul;
+
+ if (alpha > 0) {
+ pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
+ pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
+ pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
+ pix[3] = (int)((SplashCoord)pixAcc3 * pixMul);
+
+ // set pixel
+ pipe.shape = alpha;
+ if (vectorAntialias && clipRes != splashClipAllInside) {
+ drawAAPixel(&pipe, tx + x2, ty + y2);
+ } else {
+ drawPixel(&pipe, tx + x2, ty + y2,
+ clipRes2 == splashClipAllInside);
+ }
+ }
+
+ // x scale Bresenham
+ xSrc += xStep;
+
+ // x shear
+ x1 += xSign;
+
+ // y shear
+ y1 += yShear1;
+ }
+ break;
+#endif // SPLASH_CMYK
+ }
+ }
+
+ } else {
+
+ // init y scale Bresenham
+ yt = 0;
+ lastYStep = 1;
+
+ for (y = 0; y < scaledHeight; ++y) {
+
+ // y scale Bresenham
+ yStep = yp;
+ yt += yq;
+ if (yt >= scaledHeight) {
+ yt -= scaledHeight;
+ ++yStep;
+ }
+
+ // read row(s) from image
+ n = (yp > 0) ? yStep : lastYStep;
+ if (n > 0) {
+ p = colorBuf;
+ for (i = 0; i < n; ++i) {
+ (*src)(srcData, p, NULL);
+ p += w * nComps;
+ }
+ }
+ lastYStep = yStep;
+
+ // loop-invariant constants
+ k1 = splashRound(xShear * ySign * y);
+
+ // clipping test
+ if (clipRes != splashClipAllInside &&
+ !rot &&
+ (int)(yShear * k1) ==
+ (int)(yShear * (xSign * (scaledWidth - 1) + k1))) {
+ if (xSign > 0) {
+ spanXMin = tx + k1;
+ spanXMax = spanXMin + (scaledWidth - 1);
+ } else {
+ spanXMax = tx + k1;
+ spanXMin = spanXMax - (scaledWidth - 1);
+ }
+ spanY = ty + ySign * y + (int)(yShear * k1);
+ clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY);
+ if (clipRes2 == splashClipAllOutside) {
+ continue;
+ }
+ } else {
+ clipRes2 = clipRes;
+ }
+
+ // init x scale Bresenham
+ xt = 0;
+ xSrc = 0;
+
+ // x shear
+ x1 = k1;
+
+ // y shear
+ y1 = (SplashCoord)ySign * y + yShear * x1;
+ // this is a kludge: if yShear1 is negative, then (int)y1 would
+ // change immediately after the first pixel, which is not what
+ // we want
+ if (yShear1 < 0) {
+ y1 += 0.999;
+ }
+
+ // loop-invariant constants
+ n = yStep > 0 ? yStep : 1;
+
+ switch (srcMode) {
+
+ case splashModeMono1:
+ case splashModeMono8:
+ for (x = 0; x < scaledWidth; ++x) {
+
+ // x scale Bresenham
+ xStep = xp;
+ xt += xq;
+ if (xt >= scaledWidth) {
+ xt -= scaledWidth;
+ ++xStep;
+ }
+
+ // rotation
+ if (rot) {
+ x2 = (int)y1;
+ y2 = -x1;
+ } else {
+ x2 = x1;
+ y2 = (int)y1;
+ }
+
+ // compute the filtered pixel at (x,y) after the x and y scaling
+ // operations
+ m = xStep > 0 ? xStep : 1;
+ p = colorBuf + xSrc;
+ pixAcc0 = 0;
+ for (i = 0; i < n; ++i) {
+ for (j = 0; j < m; ++j) {
+ pixAcc0 += *p++;
+ }
+ p += w - m;
+ }
+ pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
+
+ pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
+
+ // set pixel
+ if (vectorAntialias && clipRes != splashClipAllInside) {
+ pipe.shape = (SplashCoord)1;
+ drawAAPixel(&pipe, tx + x2, ty + y2);
+ } else {
+ drawPixel(&pipe, tx + x2, ty + y2,
+ clipRes2 == splashClipAllInside);
+ }
+
+ // x scale Bresenham
+ xSrc += xStep;
+
+ // x shear
+ x1 += xSign;
+
+ // y shear
+ y1 += yShear1;
+ }
+ break;
+
+ case splashModeRGB8:
+ case splashModeBGR8:
+ for (x = 0; x < scaledWidth; ++x) {
+
+ // x scale Bresenham
+ xStep = xp;
+ xt += xq;
+ if (xt >= scaledWidth) {
+ xt -= scaledWidth;
+ ++xStep;
+ }
+
+ // rotation
+ if (rot) {
+ x2 = (int)y1;
+ y2 = -x1;
+ } else {
+ x2 = x1;
+ y2 = (int)y1;
+ }
+
+ // compute the filtered pixel at (x,y) after the x and y scaling
+ // operations
+ m = xStep > 0 ? xStep : 1;
+ p = colorBuf + xSrc * 3;
+ pixAcc0 = pixAcc1 = pixAcc2 = 0;
+ for (i = 0; i < n; ++i) {
+ for (j = 0; j < m; ++j) {
+ pixAcc0 += *p++;
+ pixAcc1 += *p++;
+ pixAcc2 += *p++;
+ }
+ p += 3 * (w - m);
+ }
+ pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
+
+ pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
+ pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
+ pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
+
+ // set pixel
+ if (vectorAntialias && clipRes != splashClipAllInside) {
+ pipe.shape = (SplashCoord)1;
+ drawAAPixel(&pipe, tx + x2, ty + y2);
+ } else {
+ drawPixel(&pipe, tx + x2, ty + y2,
+ clipRes2 == splashClipAllInside);
+ }
+
+ // x scale Bresenham
+ xSrc += xStep;
+
+ // x shear
+ x1 += xSign;
+
+ // y shear
+ y1 += yShear1;
+ }
+ break;
+
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ for (x = 0; x < scaledWidth; ++x) {
+
+ // x scale Bresenham
+ xStep = xp;
+ xt += xq;
+ if (xt >= scaledWidth) {
+ xt -= scaledWidth;
+ ++xStep;
+ }
+
+ // rotation
+ if (rot) {
+ x2 = (int)y1;
+ y2 = -x1;
+ } else {
+ x2 = x1;
+ y2 = (int)y1;
+ }
+
+ // compute the filtered pixel at (x,y) after the x and y scaling
+ // operations
+ m = xStep > 0 ? xStep : 1;
+ p = colorBuf + xSrc * 4;
+ pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0;
+ for (i = 0; i < n; ++i) {
+ for (j = 0; j < m; ++j) {
+ pixAcc0 += *p++;
+ pixAcc1 += *p++;
+ pixAcc2 += *p++;
+ pixAcc3 += *p++;
+ }
+ p += 4 * (w - m);
+ }
+ pixMul = (SplashCoord)1 / (SplashCoord)(n * m);
+
+ pix[0] = (int)((SplashCoord)pixAcc0 * pixMul);
+ pix[1] = (int)((SplashCoord)pixAcc1 * pixMul);
+ pix[2] = (int)((SplashCoord)pixAcc2 * pixMul);
+ pix[3] = (int)((SplashCoord)pixAcc3 * pixMul);
+
+ // set pixel
+ if (vectorAntialias && clipRes != splashClipAllInside) {
+ pipe.shape = (SplashCoord)1;
+ drawAAPixel(&pipe, tx + x2, ty + y2);
+ } else {
+ drawPixel(&pipe, tx + x2, ty + y2,
+ clipRes2 == splashClipAllInside);
+ }
+
+ // x scale Bresenham
+ xSrc += xStep;
+
+ // x shear
+ x1 += xSign;
+
+ // y shear
+ y1 += yShear1;
+ }
+ break;
+#endif // SPLASH_CMYK
+ }
+ }
+
+ }
+
+ gfree(colorBuf);
+ gfree(alphaBuf);
+
+ return splashOk;
+}
+
+SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc,
+ int xDest, int yDest, int w, int h,
+ GBool noClip, GBool nonIsolated) {
+ SplashPipe pipe;
+ SplashColor pixel;
+ Guchar alpha;
+ Guchar *ap;
+ int x, y;
+
+ if (src->mode != bitmap->mode) {
+ return splashErrModeMismatch;
+ }
+
+ if (src->alpha) {
+ pipeInit(&pipe, xDest, yDest, NULL, pixel, state->fillAlpha,
+ gTrue, nonIsolated);
+ for (y = 0; y < h; ++y) {
+ pipeSetXY(&pipe, xDest, yDest + y);
+ ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc;
+ for (x = 0; x < w; ++x) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ alpha = *ap++;
+ if (noClip || state->clip->test(xDest + x, yDest + y)) {
+ // this uses shape instead of alpha, which isn't technically
+ // correct, but works out the same
+ pipe.shape = (SplashCoord)(alpha / 255.0);
+ pipeRun(&pipe);
+ updateModX(xDest + x);
+ updateModY(yDest + y);
+ } else {
+ pipeIncX(&pipe);
+ }
+ }
+ }
+ } else {
+ pipeInit(&pipe, xDest, yDest, NULL, pixel, state->fillAlpha,
+ gFalse, nonIsolated);
+ for (y = 0; y < h; ++y) {
+ pipeSetXY(&pipe, xDest, yDest + y);
+ for (x = 0; x < w; ++x) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ if (noClip || state->clip->test(xDest + x, yDest + y)) {
+ pipeRun(&pipe);
+ updateModX(xDest + x);
+ updateModY(yDest + y);
+ } else {
+ pipeIncX(&pipe);
+ }
+ }
+ }
+ }
+
+ return splashOk;
+}
+
+void Splash::compositeBackground(SplashColorPtr color) {
+ SplashColorPtr p;
+ Guchar *q;
+ Guchar alpha, alpha1, c, color0, color1, color2, color3;
+ int x, y, mask;
+
+ switch (bitmap->mode) {
+ case splashModeMono1:
+ color0 = color[0];
+ for (y = 0; y < bitmap->height; ++y) {
+ p = &bitmap->data[y * bitmap->rowSize];
+ q = &bitmap->alpha[y * bitmap->width];
+ mask = 0x80;
+ for (x = 0; x < bitmap->width; ++x) {
+ alpha = *q++;
+ alpha1 = 255 - alpha;
+ c = (*p & mask) ? 0xff : 0x00;
+ c = div255(alpha1 * color0 + alpha * c);
+ if (c & 0x80) {
+ *p |= mask;
+ } else {
+ *p &= ~mask;
+ }
+ if (!(mask >>= 1)) {
+ mask = 0x80;
+ ++p;
+ }
+ }
+ }
+ break;
+ case splashModeMono8:
+ color0 = color[0];
+ for (y = 0; y < bitmap->height; ++y) {
+ p = &bitmap->data[y * bitmap->rowSize];
+ q = &bitmap->alpha[y * bitmap->width];
+ for (x = 0; x < bitmap->width; ++x) {
+ alpha = *q++;
+ alpha1 = 255 - alpha;
+ p[0] = div255(alpha1 * color0 + alpha * p[0]);
+ ++p;
+ }
+ }
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ color0 = color[0];
+ color1 = color[1];
+ color2 = color[2];
+ for (y = 0; y < bitmap->height; ++y) {
+ p = &bitmap->data[y * bitmap->rowSize];
+ q = &bitmap->alpha[y * bitmap->width];
+ for (x = 0; x < bitmap->width; ++x) {
+ alpha = *q++;
+ alpha1 = 255 - alpha;
+ p[0] = div255(alpha1 * color0 + alpha * p[0]);
+ p[1] = div255(alpha1 * color1 + alpha * p[1]);
+ p[2] = div255(alpha1 * color2 + alpha * p[2]);
+ p += 3;
+ }
+ }
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ color0 = color[0];
+ color1 = color[1];
+ color2 = color[2];
+ color3 = color[3];
+ for (y = 0; y < bitmap->height; ++y) {
+ p = &bitmap->data[y * bitmap->rowSize];
+ q = &bitmap->alpha[y * bitmap->width];
+ for (x = 0; x < bitmap->width; ++x) {
+ alpha = *q++;
+ alpha1 = 255 - alpha;
+ p[0] = div255(alpha1 * color0 + alpha * p[0]);
+ p[1] = div255(alpha1 * color1 + alpha * p[1]);
+ p[2] = div255(alpha1 * color2 + alpha * p[2]);
+ p[3] = div255(alpha1 * color3 + alpha * p[3]);
+ p += 4;
+ }
+ }
+ break;
+#endif
+ }
+ memset(bitmap->alpha, 255, bitmap->width * bitmap->height);
+}
+
+SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
+ int xDest, int yDest, int w, int h) {
+ SplashColor pixel;
+ SplashColorPtr p;
+ Guchar *q;
+ int x, y, mask;
+
+ if (src->mode != bitmap->mode) {
+ return splashErrModeMismatch;
+ }
+
+ switch (bitmap->mode) {
+ case splashModeMono1:
+ for (y = 0; y < h; ++y) {
+ p = &bitmap->data[(yDest + y) * bitmap->rowSize + (xDest >> 3)];
+ mask = 0x80 >> (xDest & 7);
+ for (x = 0; x < w; ++x) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ if (pixel[0]) {
+ *p |= mask;
+ } else {
+ *p &= ~mask;
+ }
+ if (!(mask >>= 1)) {
+ mask = 0x80;
+ ++p;
+ }
+ }
+ }
+ break;
+ case splashModeMono8:
+ for (y = 0; y < h; ++y) {
+ p = &bitmap->data[(yDest + y) * bitmap->rowSize + xDest];
+ for (x = 0; x < w; ++x) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ *p++ = pixel[0];
+ }
+ }
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ for (y = 0; y < h; ++y) {
+ p = &bitmap->data[(yDest + y) * bitmap->rowSize + 3 * xDest];
+ for (x = 0; x < w; ++x) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ *p++ = pixel[0];
+ *p++ = pixel[1];
+ *p++ = pixel[2];
+ }
+ }
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ for (y = 0; y < h; ++y) {
+ p = &bitmap->data[(yDest + y) * bitmap->rowSize + 4 * xDest];
+ for (x = 0; x < w; ++x) {
+ src->getPixel(xSrc + x, ySrc + y, pixel);
+ *p++ = pixel[0];
+ *p++ = pixel[1];
+ *p++ = pixel[2];
+ *p++ = pixel[3];
+ }
+ }
+ break;
+#endif
+ }
+
+ if (bitmap->alpha) {
+ for (y = 0; y < h; ++y) {
+ q = &bitmap->alpha[(yDest + y) * bitmap->width + xDest];
+ for (x = 0; x < w; ++x) {
+ *q++ = 0x00;
+ }
+ }
+ }
+
+ return splashOk;
+}
+
+SplashPath *Splash::makeStrokePath(SplashPath *path, GBool flatten) {
+ SplashPath *pathIn, *pathOut;
+ SplashCoord w, d, dx, dy, wdx, wdy, dxNext, dyNext, wdxNext, wdyNext;
+ SplashCoord crossprod, dotprod, miter, m;
+ GBool first, last, closed;
+ int subpathStart, next, i;
+ int left0, left1, left2, right0, right1, right2, join0, join1, join2;
+ int leftFirst, rightFirst, firstPt;
+
+ if (flatten) {
+ pathIn = flattenPath(path, state->matrix, state->flatness);
+ if (state->lineDashLength > 0) {
+ pathOut = makeDashedPath(pathIn);
+ delete pathIn;
+ pathIn = pathOut;
+ }
+ } else {
+ pathIn = path;
+ }
+
+ subpathStart = 0; // make gcc happy
+ closed = gFalse; // make gcc happy
+ left0 = left1 = right0 = right1 = join0 = join1 = 0; // make gcc happy
+ leftFirst = rightFirst = firstPt = 0; // make gcc happy
+
+ pathOut = new SplashPath();
+ w = state->lineWidth;
+
+ for (i = 0; i < pathIn->length - 1; ++i) {
+ if (pathIn->flags[i] & splashPathLast) {
+ continue;
+ }
+ if ((first = pathIn->flags[i] & splashPathFirst)) {
+ subpathStart = i;
+ closed = pathIn->flags[i] & splashPathClosed;
+ }
+ last = pathIn->flags[i+1] & splashPathLast;
+
+ // compute the deltas for segment (i, i+1)
+ d = splashDist(pathIn->pts[i].x, pathIn->pts[i].y,
+ pathIn->pts[i+1].x, pathIn->pts[i+1].y);
+ if (d == 0) {
+ // we need to draw end caps on zero-length lines
+ //~ not clear what the behavior should be for splashLineCapButt
+ //~ with d==0
+ dx = 0;
+ dy = 1;
+ } else {
+ d = (SplashCoord)1 / d;
+ dx = d * (pathIn->pts[i+1].x - pathIn->pts[i].x);
+ dy = d * (pathIn->pts[i+1].y - pathIn->pts[i].y);
+ }
+ wdx = (SplashCoord)0.5 * w * dx;
+ wdy = (SplashCoord)0.5 * w * dy;
+
+ // compute the deltas for segment (i+1, next)
+ next = last ? subpathStart + 1 : i + 2;
+ d = splashDist(pathIn->pts[i+1].x, pathIn->pts[i+1].y,
+ pathIn->pts[next].x, pathIn->pts[next].y);
+ if (d == 0) {
+ // we need to draw end caps on zero-length lines
+ //~ not clear what the behavior should be for splashLineCapButt
+ //~ with d==0
+ dxNext = 0;
+ dyNext = 1;
+ } else {
+ d = (SplashCoord)1 / d;
+ dxNext = d * (pathIn->pts[next].x - pathIn->pts[i+1].x);
+ dyNext = d * (pathIn->pts[next].y - pathIn->pts[i+1].y);
+ }
+ wdxNext = (SplashCoord)0.5 * w * dxNext;
+ wdyNext = (SplashCoord)0.5 * w * dyNext;
+
+ // draw the start cap
+ pathOut->moveTo(pathIn->pts[i].x - wdy, pathIn->pts[i].y + wdx);
+ if (i == subpathStart) {
+ firstPt = pathOut->length - 1;
+ }
+ if (first && !closed) {
+ switch (state->lineCap) {
+ case splashLineCapButt:
+ pathOut->lineTo(pathIn->pts[i].x + wdy, pathIn->pts[i].y - wdx);
+ break;
+ case splashLineCapRound:
+ pathOut->curveTo(pathIn->pts[i].x - wdy - bezierCircle * wdx,
+ pathIn->pts[i].y + wdx - bezierCircle * wdy,
+ pathIn->pts[i].x - wdx - bezierCircle * wdy,
+ pathIn->pts[i].y - wdy + bezierCircle * wdx,
+ pathIn->pts[i].x - wdx,
+ pathIn->pts[i].y - wdy);
+ pathOut->curveTo(pathIn->pts[i].x - wdx + bezierCircle * wdy,
+ pathIn->pts[i].y - wdy - bezierCircle * wdx,
+ pathIn->pts[i].x + wdy - bezierCircle * wdx,
+ pathIn->pts[i].y - wdx - bezierCircle * wdy,
+ pathIn->pts[i].x + wdy,
+ pathIn->pts[i].y - wdx);
+ break;
+ case splashLineCapProjecting:
+ pathOut->lineTo(pathIn->pts[i].x - wdx - wdy,
+ pathIn->pts[i].y + wdx - wdy);
+ pathOut->lineTo(pathIn->pts[i].x - wdx + wdy,
+ pathIn->pts[i].y - wdx - wdy);
+ pathOut->lineTo(pathIn->pts[i].x + wdy,
+ pathIn->pts[i].y - wdx);
+ break;
+ }
+ } else {
+ pathOut->lineTo(pathIn->pts[i].x + wdy, pathIn->pts[i].y - wdx);
+ }
+
+ // draw the left side of the segment rectangle
+ left2 = pathOut->length - 1;
+ pathOut->lineTo(pathIn->pts[i+1].x + wdy, pathIn->pts[i+1].y - wdx);
+
+ // draw the end cap
+ if (last && !closed) {
+ switch (state->lineCap) {
+ case splashLineCapButt:
+ pathOut->lineTo(pathIn->pts[i+1].x - wdy, pathIn->pts[i+1].y + wdx);
+ break;
+ case splashLineCapRound:
+ pathOut->curveTo(pathIn->pts[i+1].x + wdy + bezierCircle * wdx,
+ pathIn->pts[i+1].y - wdx + bezierCircle * wdy,
+ pathIn->pts[i+1].x + wdx + bezierCircle * wdy,
+ pathIn->pts[i+1].y + wdy - bezierCircle * wdx,
+ pathIn->pts[i+1].x + wdx,
+ pathIn->pts[i+1].y + wdy);
+ pathOut->curveTo(pathIn->pts[i+1].x + wdx - bezierCircle * wdy,
+ pathIn->pts[i+1].y + wdy + bezierCircle * wdx,
+ pathIn->pts[i+1].x - wdy + bezierCircle * wdx,
+ pathIn->pts[i+1].y + wdx + bezierCircle * wdy,
+ pathIn->pts[i+1].x - wdy,
+ pathIn->pts[i+1].y + wdx);
+ break;
+ case splashLineCapProjecting:
+ pathOut->lineTo(pathIn->pts[i+1].x + wdy + wdx,
+ pathIn->pts[i+1].y - wdx + wdy);
+ pathOut->lineTo(pathIn->pts[i+1].x - wdy + wdx,
+ pathIn->pts[i+1].y + wdx + wdy);
+ pathOut->lineTo(pathIn->pts[i+1].x - wdy,
+ pathIn->pts[i+1].y + wdx);
+ break;
+ }
+ } else {
+ pathOut->lineTo(pathIn->pts[i+1].x - wdy, pathIn->pts[i+1].y + wdx);
+ }
+
+ // draw the right side of the segment rectangle
+ right2 = pathOut->length - 1;
+ pathOut->close();
+
+ // draw the join
+ join2 = pathOut->length;
+ if (!last || closed) {
+ crossprod = dx * dyNext - dy * dxNext;
+ dotprod = -(dx * dxNext + dy * dyNext);
+ if (dotprod > 0.99999) {
+ // avoid a divide-by-zero -- set miter to something arbitrary
+ // such that sqrt(miter) will exceed miterLimit (and m is never
+ // used in that situation)
+ miter = (state->miterLimit + 1) * (state->miterLimit + 1);
+ m = 0;
+ } else {
+ miter = (SplashCoord)2 / ((SplashCoord)1 - dotprod);
+ if (miter < 1) {
+ // this can happen because of floating point inaccuracies
+ miter = 1;
+ }
+ m = splashSqrt(miter - 1);
+ }
+
+ // round join
+ if (state->lineJoin == splashLineJoinRound) {
+ pathOut->moveTo(pathIn->pts[i+1].x + (SplashCoord)0.5 * w,
+ pathIn->pts[i+1].y);
+ pathOut->curveTo(pathIn->pts[i+1].x + (SplashCoord)0.5 * w,
+ pathIn->pts[i+1].y + bezierCircle2 * w,
+ pathIn->pts[i+1].x + bezierCircle2 * w,
+ pathIn->pts[i+1].y + (SplashCoord)0.5 * w,
+ pathIn->pts[i+1].x,
+ pathIn->pts[i+1].y + (SplashCoord)0.5 * w);
+ pathOut->curveTo(pathIn->pts[i+1].x - bezierCircle2 * w,
+ pathIn->pts[i+1].y + (SplashCoord)0.5 * w,
+ pathIn->pts[i+1].x - (SplashCoord)0.5 * w,
+ pathIn->pts[i+1].y + bezierCircle2 * w,
+ pathIn->pts[i+1].x - (SplashCoord)0.5 * w,
+ pathIn->pts[i+1].y);
+ pathOut->curveTo(pathIn->pts[i+1].x - (SplashCoord)0.5 * w,
+ pathIn->pts[i+1].y - bezierCircle2 * w,
+ pathIn->pts[i+1].x - bezierCircle2 * w,
+ pathIn->pts[i+1].y - (SplashCoord)0.5 * w,
+ pathIn->pts[i+1].x,
+ pathIn->pts[i+1].y - (SplashCoord)0.5 * w);
+ pathOut->curveTo(pathIn->pts[i+1].x + bezierCircle2 * w,
+ pathIn->pts[i+1].y - (SplashCoord)0.5 * w,
+ pathIn->pts[i+1].x + (SplashCoord)0.5 * w,
+ pathIn->pts[i+1].y - bezierCircle2 * w,
+ pathIn->pts[i+1].x + (SplashCoord)0.5 * w,
+ pathIn->pts[i+1].y);
+
+ } else {
+ pathOut->moveTo(pathIn->pts[i+1].x, pathIn->pts[i+1].y);
+
+ // angle < 180
+ if (crossprod < 0) {
+ pathOut->lineTo(pathIn->pts[i+1].x - wdyNext,
+ pathIn->pts[i+1].y + wdxNext);
+ // miter join inside limit
+ if (state->lineJoin == splashLineJoinMiter &&
+ splashSqrt(miter) <= state->miterLimit) {
+ pathOut->lineTo(pathIn->pts[i+1].x - wdy + wdx * m,
+ pathIn->pts[i+1].y + wdx + wdy * m);
+ pathOut->lineTo(pathIn->pts[i+1].x - wdy,
+ pathIn->pts[i+1].y + wdx);
+ // bevel join or miter join outside limit
+ } else {
+ pathOut->lineTo(pathIn->pts[i+1].x - wdy, pathIn->pts[i+1].y + wdx);
+ }
+
+ // angle >= 180
+ } else {
+ pathOut->lineTo(pathIn->pts[i+1].x + wdy,
+ pathIn->pts[i+1].y - wdx);
+ // miter join inside limit
+ if (state->lineJoin == splashLineJoinMiter &&
+ splashSqrt(miter) <= state->miterLimit) {
+ pathOut->lineTo(pathIn->pts[i+1].x + wdy + wdx * m,
+ pathIn->pts[i+1].y - wdx + wdy * m);
+ pathOut->lineTo(pathIn->pts[i+1].x + wdyNext,
+ pathIn->pts[i+1].y - wdxNext);
+ // bevel join or miter join outside limit
+ } else {
+ pathOut->lineTo(pathIn->pts[i+1].x + wdyNext,
+ pathIn->pts[i+1].y - wdxNext);
+ }
+ }
+ }
+
+ pathOut->close();
+ }
+
+ // add stroke adjustment hints
+ if (state->strokeAdjust) {
+ if (i >= subpathStart + 1) {
+ if (i >= subpathStart + 2) {
+ pathOut->addStrokeAdjustHint(left1, right1, left0 + 1, right0);
+ pathOut->addStrokeAdjustHint(left1, right1, join0, left2);
+ } else {
+ pathOut->addStrokeAdjustHint(left1, right1, firstPt, left2);
+ }
+ pathOut->addStrokeAdjustHint(left1, right1, right2 + 1, right2 + 1);
+ }
+ left0 = left1;
+ left1 = left2;
+ right0 = right1;
+ right1 = right2;
+ join0 = join1;
+ join1 = join2;
+ if (i == subpathStart) {
+ leftFirst = left2;
+ rightFirst = right2;
+ }
+ if (last) {
+ if (i >= subpathStart + 2) {
+ pathOut->addStrokeAdjustHint(left1, right1, left0 + 1, right0);
+ pathOut->addStrokeAdjustHint(left1, right1,
+ join0, pathOut->length - 1);
+ } else {
+ pathOut->addStrokeAdjustHint(left1, right1,
+ firstPt, pathOut->length - 1);
+ }
+ if (closed) {
+ pathOut->addStrokeAdjustHint(left1, right1, firstPt, leftFirst);
+ pathOut->addStrokeAdjustHint(left1, right1,
+ rightFirst + 1, rightFirst + 1);
+ pathOut->addStrokeAdjustHint(leftFirst, rightFirst,
+ left1 + 1, right1);
+ pathOut->addStrokeAdjustHint(leftFirst, rightFirst,
+ join1, pathOut->length - 1);
+ }
+ }
+ }
+ }
+
+ if (pathIn != path) {
+ delete pathIn;
+ }
+
+ return pathOut;
+}
+
+void Splash::dumpPath(SplashPath *path) {
+ int i;
+
+ for (i = 0; i < path->length; ++i) {
+ printf(" %3d: x=%8.2f y=%8.2f%s%s%s%s\n",
+ i, (double)path->pts[i].x, (double)path->pts[i].y,
+ (path->flags[i] & splashPathFirst) ? " first" : "",
+ (path->flags[i] & splashPathLast) ? " last" : "",
+ (path->flags[i] & splashPathClosed) ? " closed" : "",
+ (path->flags[i] & splashPathCurve) ? " curve" : "");
+ }
+}
+
+void Splash::dumpXPath(SplashXPath *path) {
+ int i;
+
+ for (i = 0; i < path->length; ++i) {
+ printf(" %4d: x0=%8.2f y0=%8.2f x1=%8.2f y1=%8.2f %s%s%s%s%s%s%s\n",
+ i, (double)path->segs[i].x0, (double)path->segs[i].y0,
+ (double)path->segs[i].x1, (double)path->segs[i].y1,
+ (path->segs[i].flags & splashXPathFirst) ? "F" : " ",
+ (path->segs[i].flags & splashXPathLast) ? "L" : " ",
+ (path->segs[i].flags & splashXPathEnd0) ? "0" : " ",
+ (path->segs[i].flags & splashXPathEnd1) ? "1" : " ",
+ (path->segs[i].flags & splashXPathHoriz) ? "H" : " ",
+ (path->segs[i].flags & splashXPathVert) ? "V" : " ",
+ (path->segs[i].flags & splashXPathFlip) ? "P" : " ");
+ }
+}
diff --git a/kpdf/xpdf/splash/Splash.h b/kpdf/xpdf/splash/Splash.h
new file mode 100644
index 00000000..3c7571fb
--- /dev/null
+++ b/kpdf/xpdf/splash/Splash.h
@@ -0,0 +1,293 @@
+//========================================================================
+//
+// Splash.h
+//
+//========================================================================
+
+#ifndef SPLASH_H
+#define SPLASH_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "SplashTypes.h"
+#include "SplashClip.h"
+
+class Splash;
+class SplashBitmap;
+struct SplashGlyphBitmap;
+class SplashState;
+class SplashPattern;
+class SplashScreen;
+class SplashPath;
+class SplashXPath;
+class SplashFont;
+struct SplashPipe;
+
+//------------------------------------------------------------------------
+
+// Retrieves the next line of pixels in an image mask. Normally,
+// fills in *<line> and returns true. If the image stream is
+// exhausted, returns false.
+typedef GBool (*SplashImageMaskSource)(void *data, SplashColorPtr pixel);
+
+// Retrieves the next line of pixels in an image. Normally, fills in
+// *<line> and returns true. If the image stream is exhausted,
+// returns false.
+typedef GBool (*SplashImageSource)(void *data, SplashColorPtr colorLine,
+ Guchar *alphaLine);
+
+//------------------------------------------------------------------------
+
+enum SplashPipeResultColorCtrl {
+#if SPLASH_CMYK
+ splashPipeResultColorNoAlphaBlendCMYK,
+#endif
+ splashPipeResultColorNoAlphaBlendRGB,
+ splashPipeResultColorNoAlphaBlendMono,
+ splashPipeResultColorAlphaNoBlendMono,
+ splashPipeResultColorAlphaNoBlendRGB,
+#if SPLASH_CMYK
+ splashPipeResultColorAlphaNoBlendCMYK,
+#endif
+ splashPipeResultColorAlphaBlendMono,
+ splashPipeResultColorAlphaBlendRGB
+#if SPLASH_CMYK
+ ,
+ splashPipeResultColorAlphaBlendCMYK
+#endif
+};
+
+//------------------------------------------------------------------------
+// Splash
+//------------------------------------------------------------------------
+
+class Splash {
+public:
+
+ // Create a new rasterizer object.
+ Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
+ SplashScreenParams *screenParams = NULL);
+ Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA,
+ SplashScreen *screenA);
+
+ ~Splash();
+
+ //----- state read
+
+ SplashCoord *getMatrix();
+ SplashPattern *getStrokePattern();
+ SplashPattern *getFillPattern();
+ SplashScreen *getScreen();
+ SplashBlendFunc getBlendFunc();
+ SplashCoord getStrokeAlpha();
+ SplashCoord getFillAlpha();
+ SplashCoord getLineWidth();
+ int getLineCap();
+ int getLineJoin();
+ SplashCoord getMiterLimit();
+ SplashCoord getFlatness();
+ SplashCoord *getLineDash();
+ int getLineDashLength();
+ SplashCoord getLineDashPhase();
+ SplashClip *getClip();
+ SplashBitmap *getSoftMask();
+ GBool getInNonIsolatedGroup();
+
+ //----- state write
+
+ void setMatrix(SplashCoord *matrix);
+ void setStrokePattern(SplashPattern *strokeColor);
+ void setFillPattern(SplashPattern *fillColor);
+ void setScreen(SplashScreen *screen);
+ void setBlendFunc(SplashBlendFunc func);
+ void setStrokeAlpha(SplashCoord alpha);
+ void setFillAlpha(SplashCoord alpha);
+ void setLineWidth(SplashCoord lineWidth);
+ void setLineCap(int lineCap);
+ void setLineJoin(int lineJoin);
+ void setMiterLimit(SplashCoord miterLimit);
+ void setFlatness(SplashCoord flatness);
+ // the <lineDash> array will be copied
+ void setLineDash(SplashCoord *lineDash, int lineDashLength,
+ SplashCoord lineDashPhase);
+ void setStrokeAdjust(GBool strokeAdjust);
+ // NB: uses transformed coordinates.
+ void clipResetToRect(SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1);
+ // NB: uses transformed coordinates.
+ SplashError clipToRect(SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1);
+ // NB: uses untransformed coordinates.
+ SplashError clipToPath(SplashPath *path, GBool eo);
+ void setSoftMask(SplashBitmap *softMask);
+ void setInNonIsolatedGroup(SplashBitmap *alpha0BitmapA,
+ int alpha0XA, int alpha0YA);
+
+ //----- state save/restore
+
+ void saveState();
+ SplashError restoreState();
+
+ //----- drawing operations
+
+ // Fill the bitmap with <color>. This is not subject to clipping.
+ void clear(SplashColorPtr color, Guchar alpha = 0x00);
+
+ // Stroke a path using the current stroke pattern.
+ SplashError stroke(SplashPath *path);
+
+ // Fill a path using the current fill pattern.
+ SplashError fill(SplashPath *path, GBool eo);
+
+ // Fill a path, XORing with the current fill pattern.
+ SplashError xorFill(SplashPath *path, GBool eo);
+
+ // Draw a character, using the current fill pattern.
+ SplashError fillChar(SplashCoord x, SplashCoord y, int c, SplashFont *font);
+
+ // Draw a glyph, using the current fill pattern. This function does
+ // not free any data, i.e., it ignores glyph->freeData.
+ void fillGlyph(SplashCoord x, SplashCoord y,
+ SplashGlyphBitmap *glyph);
+
+ // Draws an image mask using the fill color. This will read <h>
+ // lines of <w> pixels from <src>, starting with the top line. "1"
+ // pixels will be drawn with the current fill color; "0" pixels are
+ // transparent. The matrix:
+ // [ mat[0] mat[1] 0 ]
+ // [ mat[2] mat[3] 0 ]
+ // [ mat[4] mat[5] 1 ]
+ // maps a unit square to the desired destination for the image, in
+ // PostScript style:
+ // [x' y' 1] = [x y 1] * mat
+ // Note that the Splash y axis points downward, and the image source
+ // is assumed to produce pixels in raster order, starting from the
+ // top line.
+ SplashError fillImageMask(SplashImageMaskSource src, void *srcData,
+ int w, int h, SplashCoord *mat,
+ GBool glyphMode);
+
+ // Draw an image. This will read <h> lines of <w> pixels from
+ // <src>, starting with the top line. These pixels are assumed to
+ // be in the source mode, <srcMode>. If <srcAlpha> is true, the
+ // alpha values returned by <src> are used; otherwise they are
+ // ignored. The following combinations of source and target modes
+ // are supported:
+ // source target
+ // ------ ------
+ // Mono1 Mono1
+ // Mono8 Mono1 -- with dithering
+ // Mono8 Mono8
+ // RGB8 RGB8
+ // BGR8 BGR8
+ // CMYK8 CMYK8
+ // The matrix behaves as for fillImageMask.
+ SplashError drawImage(SplashImageSource src, void *srcData,
+ SplashColorMode srcMode, GBool srcAlpha,
+ int w, int h, SplashCoord *mat);
+
+ // Composite a rectangular region from <src> onto this Splash
+ // object.
+ SplashError composite(SplashBitmap *src, int xSrc, int ySrc,
+ int xDest, int yDest, int w, int h,
+ GBool noClip, GBool nonIsolated);
+
+ // Composite this Splash object onto a background color. The
+ // background alpha is assumed to be 1.
+ void compositeBackground(SplashColorPtr color);
+
+ // Copy a rectangular region from <src> onto the bitmap belonging to
+ // this Splash object. The destination alpha values are all set to
+ // zero.
+ SplashError blitTransparent(SplashBitmap *src, int xSrc, int ySrc,
+ int xDest, int yDest, int w, int h);
+
+ //----- misc
+
+ // Construct a path for a stroke, given the path to be stroked, and
+ // using the current line parameters. If <flatten> is true, this
+ // function will first flatten the path and handle the linedash.
+ SplashPath *makeStrokePath(SplashPath *path, GBool flatten = gTrue);
+
+ // Return the associated bitmap.
+ SplashBitmap *getBitmap() { return bitmap; }
+
+ // Get a bounding box which includes all modifications since the
+ // last call to clearModRegion.
+ void getModRegion(int *xMin, int *yMin, int *xMax, int *yMax)
+ { *xMin = modXMin; *yMin = modYMin; *xMax = modXMax; *yMax = modYMax; }
+
+ // Clear the modified region bounding box.
+ void clearModRegion();
+
+ // Get clipping status for the last drawing operation subject to
+ // clipping.
+ SplashClipResult getClipRes() { return opClipRes; }
+
+ // Toggle debug mode on or off.
+ void setDebugMode(GBool debugModeA) { debugMode = debugModeA; }
+
+#if 1 //~tmp: turn off anti-aliasing temporarily
+ GBool getVectorAntialias() { return vectorAntialias; }
+ void setVectorAntialias(GBool vaa) { vectorAntialias = vaa; }
+#endif
+
+private:
+
+ void pipeInit(SplashPipe *pipe, int x, int y,
+ SplashPattern *pattern, SplashColorPtr cSrc,
+ SplashCoord aInput, GBool usesShape,
+ GBool nonIsolatedGroup);
+ void pipeRun(SplashPipe *pipe);
+ void pipeSetXY(SplashPipe *pipe, int x, int y);
+ void pipeIncX(SplashPipe *pipe);
+ void drawPixel(SplashPipe *pipe, int x, int y, GBool noClip);
+ void drawAAPixelInit();
+ void drawAAPixel(SplashPipe *pipe, int x, int y);
+ void drawSpan(SplashPipe *pipe, int x0, int x1, int y, GBool noClip);
+ void drawAALine(SplashPipe *pipe, int x0, int x1, int y);
+ void transform(SplashCoord *matrix, SplashCoord xi, SplashCoord yi,
+ SplashCoord *xo, SplashCoord *yo);
+ void updateModX(int x);
+ void updateModY(int y);
+ void strokeNarrow(SplashPath *path);
+ void strokeWide(SplashPath *path);
+ SplashPath *flattenPath(SplashPath *path, SplashCoord *matrix,
+ SplashCoord flatness);
+ void flattenCurve(SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1,
+ SplashCoord x2, SplashCoord y2,
+ SplashCoord x3, SplashCoord y3,
+ SplashCoord *matrix, SplashCoord flatness2,
+ SplashPath *fPath);
+ SplashPath *makeDashedPath(SplashPath *xPath);
+ SplashError fillWithPattern(SplashPath *path, GBool eo,
+ SplashPattern *pattern, SplashCoord alpha);
+ void fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph, GBool noclip);
+ void dumpPath(SplashPath *path);
+ void dumpXPath(SplashXPath *path);
+
+ static SplashPipeResultColorCtrl pipeResultColorNoAlphaBlend[];
+ static SplashPipeResultColorCtrl pipeResultColorAlphaNoBlend[];
+ static SplashPipeResultColorCtrl pipeResultColorAlphaBlend[];
+ static int pipeNonIsoGroupCorrection[];
+
+ SplashBitmap *bitmap;
+ SplashState *state;
+ SplashBitmap *aaBuf;
+ int aaBufY;
+ SplashBitmap *alpha0Bitmap; // for non-isolated groups, this is the
+ // bitmap containing the alpha0 values
+ int alpha0X, alpha0Y; // offset within alpha0Bitmap
+ SplashCoord aaGamma[splashAASize * splashAASize + 1];
+ int modXMin, modYMin, modXMax, modYMax;
+ SplashClipResult opClipRes;
+ GBool vectorAntialias;
+ GBool debugMode;
+};
+
+#endif
diff --git a/kpdf/xpdf/splash/SplashBitmap.cc b/kpdf/xpdf/splash/SplashBitmap.cc
new file mode 100644
index 00000000..0cb1a752
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashBitmap.cc
@@ -0,0 +1,188 @@
+//========================================================================
+//
+// SplashBitmap.cc
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include "gmem.h"
+#include "SplashErrorCodes.h"
+#include "SplashBitmap.h"
+
+//------------------------------------------------------------------------
+// SplashBitmap
+//------------------------------------------------------------------------
+
+SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad,
+ SplashColorMode modeA, GBool alphaA,
+ GBool topDown) {
+ width = widthA;
+ height = heightA;
+ mode = modeA;
+ switch (mode) {
+ case splashModeMono1:
+ rowSize = (width + 7) >> 3;
+ break;
+ case splashModeMono8:
+ rowSize = width;
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ rowSize = width * 3;
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ rowSize = width * 4;
+ break;
+#endif
+ }
+ rowSize += rowPad - 1;
+ rowSize -= rowSize % rowPad;
+ data = (SplashColorPtr)gmalloc(rowSize * height);
+ if (!topDown) {
+ data += (height - 1) * rowSize;
+ rowSize = -rowSize;
+ }
+ if (alphaA) {
+ alpha = (Guchar *)gmalloc(width * height);
+ } else {
+ alpha = NULL;
+ }
+}
+
+
+SplashBitmap::~SplashBitmap() {
+ if (rowSize < 0) {
+ gfree(data + (height - 1) * rowSize);
+ } else {
+ gfree(data);
+ }
+ gfree(alpha);
+}
+
+SplashError SplashBitmap::writePNMFile(char *fileName) {
+ FILE *f;
+ SplashColorPtr row, p;
+ int x, y;
+
+ if (!(f = fopen(fileName, "wb"))) {
+ return splashErrOpenFile;
+ }
+
+ switch (mode) {
+
+ case splashModeMono1:
+ fprintf(f, "P4\n%d %d\n", width, height);
+ row = data;
+ for (y = 0; y < height; ++y) {
+ p = row;
+ for (x = 0; x < width; x += 8) {
+ fputc(*p ^ 0xff, f);
+ ++p;
+ }
+ row += rowSize;
+ }
+ break;
+
+ case splashModeMono8:
+ fprintf(f, "P5\n%d %d\n255\n", width, height);
+ row = data;
+ for (y = 0; y < height; ++y) {
+ p = row;
+ for (x = 0; x < width; ++x) {
+ fputc(*p, f);
+ ++p;
+ }
+ row += rowSize;
+ }
+ break;
+
+ case splashModeRGB8:
+ fprintf(f, "P6\n%d %d\n255\n", width, height);
+ row = data;
+ for (y = 0; y < height; ++y) {
+ p = row;
+ for (x = 0; x < width; ++x) {
+ fputc(splashRGB8R(p), f);
+ fputc(splashRGB8G(p), f);
+ fputc(splashRGB8B(p), f);
+ p += 3;
+ }
+ row += rowSize;
+ }
+ break;
+
+ case splashModeBGR8:
+ fprintf(f, "P6\n%d %d\n255\n", width, height);
+ row = data;
+ for (y = 0; y < height; ++y) {
+ p = row;
+ for (x = 0; x < width; ++x) {
+ fputc(splashBGR8R(p), f);
+ fputc(splashBGR8G(p), f);
+ fputc(splashBGR8B(p), f);
+ p += 3;
+ }
+ row += rowSize;
+ }
+ break;
+
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ // PNM doesn't support CMYK
+ break;
+#endif
+ }
+
+ fclose(f);
+ return splashOk;
+}
+
+void SplashBitmap::getPixel(int x, int y, SplashColorPtr pixel) {
+ SplashColorPtr p;
+
+ if (y < 0 || y >= height || x < 0 || x >= width) {
+ return;
+ }
+ switch (mode) {
+ case splashModeMono1:
+ p = &data[y * rowSize + (x >> 3)];
+ pixel[0] = (p[0] & (0x80 >> (x & 7))) ? 0xff : 0x00;
+ break;
+ case splashModeMono8:
+ p = &data[y * rowSize + x];
+ pixel[0] = p[0];
+ break;
+ case splashModeRGB8:
+ p = &data[y * rowSize + 3 * x];
+ pixel[0] = p[0];
+ pixel[1] = p[1];
+ pixel[2] = p[2];
+ break;
+ case splashModeBGR8:
+ p = &data[y * rowSize + 3 * x];
+ pixel[0] = p[2];
+ pixel[1] = p[1];
+ pixel[2] = p[0];
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ p = &data[y * rowSize + 4 * x];
+ pixel[0] = p[0];
+ pixel[1] = p[1];
+ pixel[2] = p[2];
+ pixel[3] = p[3];
+ break;
+#endif
+ }
+}
+
+Guchar SplashBitmap::getAlpha(int x, int y) {
+ return alpha[y * width + x];
+}
diff --git a/kpdf/xpdf/splash/SplashBitmap.h b/kpdf/xpdf/splash/SplashBitmap.h
new file mode 100644
index 00000000..69ab058e
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashBitmap.h
@@ -0,0 +1,61 @@
+//========================================================================
+//
+// SplashBitmap.h
+//
+//========================================================================
+
+#ifndef SPLASHBITMAP_H
+#define SPLASHBITMAP_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "SplashTypes.h"
+
+//------------------------------------------------------------------------
+// SplashBitmap
+//------------------------------------------------------------------------
+
+class SplashBitmap {
+public:
+
+ // Create a new bitmap. It will have <widthA> x <heightA> pixels in
+ // color mode <modeA>. Rows will be padded out to a multiple of
+ // <rowPad> bytes. If <topDown> is false, the bitmap will be stored
+ // upside-down, i.e., with the last row first in memory.
+ SplashBitmap(int widthA, int heightA, int rowPad,
+ SplashColorMode modeA, GBool alphaA,
+ GBool topDown = gTrue);
+
+ ~SplashBitmap();
+
+ int getWidth() { return width; }
+ int getHeight() { return height; }
+ int getRowSize() { return rowSize; }
+ int getAlphaRowSize() { return width; }
+ SplashColorMode getMode() { return mode; }
+ SplashColorPtr getDataPtr() { return data; }
+ Guchar *getAlphaPtr() { return alpha; }
+
+ SplashError writePNMFile(char *fileName);
+
+ void getPixel(int x, int y, SplashColorPtr pixel);
+ Guchar getAlpha(int x, int y);
+
+private:
+
+ int width, height; // size of bitmap
+ int rowSize; // size of one row of data, in bytes
+ // - negative for bottom-up bitmaps
+ SplashColorMode mode; // color mode
+ SplashColorPtr data; // pointer to row zero of the color data
+ Guchar *alpha; // pointer to row zero of the alpha data
+ // (always top-down)
+
+ friend class Splash;
+};
+
+#endif
diff --git a/kpdf/xpdf/splash/SplashClip.cc b/kpdf/xpdf/splash/SplashClip.cc
new file mode 100644
index 00000000..ef8acbab
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashClip.cc
@@ -0,0 +1,382 @@
+//========================================================================
+//
+// SplashClip.cc
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include "gmem.h"
+#include "SplashErrorCodes.h"
+#include "SplashPath.h"
+#include "SplashXPath.h"
+#include "SplashXPathScanner.h"
+#include "SplashBitmap.h"
+#include "SplashClip.h"
+
+//------------------------------------------------------------------------
+// SplashClip.flags
+//------------------------------------------------------------------------
+
+#define splashClipEO 0x01 // use even-odd rule
+
+//------------------------------------------------------------------------
+// SplashClip
+//------------------------------------------------------------------------
+
+SplashClip::SplashClip(SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1,
+ GBool antialiasA) {
+ antialias = antialiasA;
+ if (x0 < x1) {
+ xMin = x0;
+ xMax = x1;
+ } else {
+ xMin = x1;
+ xMax = x0;
+ }
+ if (y0 < y1) {
+ yMin = y0;
+ yMax = y1;
+ } else {
+ yMin = y1;
+ yMax = y0;
+ }
+ xMinI = splashFloor(xMin);
+ yMinI = splashFloor(yMin);
+ xMaxI = splashFloor(xMax);
+ yMaxI = splashFloor(yMax);
+ paths = NULL;
+ flags = NULL;
+ scanners = NULL;
+ length = size = 0;
+}
+
+SplashClip::SplashClip(SplashClip *clip) {
+ int i;
+
+ antialias = clip->antialias;
+ xMin = clip->xMin;
+ yMin = clip->yMin;
+ xMax = clip->xMax;
+ yMax = clip->yMax;
+ xMinI = clip->xMinI;
+ yMinI = clip->yMinI;
+ xMaxI = clip->xMaxI;
+ yMaxI = clip->yMaxI;
+ length = clip->length;
+ size = clip->size;
+ paths = (SplashXPath **)gmallocn(size, sizeof(SplashXPath *));
+ flags = (Guchar *)gmallocn(size, sizeof(Guchar));
+ scanners = (SplashXPathScanner **)
+ gmallocn(size, sizeof(SplashXPathScanner *));
+ for (i = 0; i < length; ++i) {
+ paths[i] = clip->paths[i]->copy();
+ flags[i] = clip->flags[i];
+ scanners[i] = new SplashXPathScanner(paths[i], flags[i] & splashClipEO);
+ }
+}
+
+SplashClip::~SplashClip() {
+ int i;
+
+ for (i = 0; i < length; ++i) {
+ delete paths[i];
+ delete scanners[i];
+ }
+ gfree(paths);
+ gfree(flags);
+ gfree(scanners);
+}
+
+void SplashClip::grow(int nPaths) {
+ if (length + nPaths > size) {
+ if (size == 0) {
+ size = 32;
+ }
+ while (size < length + nPaths) {
+ size *= 2;
+ }
+ paths = (SplashXPath **)greallocn(paths, size, sizeof(SplashXPath *));
+ flags = (Guchar *)greallocn(flags, size, sizeof(Guchar));
+ scanners = (SplashXPathScanner **)
+ greallocn(scanners, size, sizeof(SplashXPathScanner *));
+ }
+}
+
+void SplashClip::resetToRect(SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1) {
+ int i;
+
+ for (i = 0; i < length; ++i) {
+ delete paths[i];
+ delete scanners[i];
+ }
+ gfree(paths);
+ gfree(flags);
+ gfree(scanners);
+ paths = NULL;
+ flags = NULL;
+ scanners = NULL;
+ length = size = 0;
+
+ if (x0 < x1) {
+ xMin = x0;
+ xMax = x1;
+ } else {
+ xMin = x1;
+ xMax = x0;
+ }
+ if (y0 < y1) {
+ yMin = y0;
+ yMax = y1;
+ } else {
+ yMin = y1;
+ yMax = y0;
+ }
+ xMinI = splashFloor(xMin);
+ yMinI = splashFloor(yMin);
+ xMaxI = splashFloor(xMax);
+ yMaxI = splashFloor(yMax);
+}
+
+SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1) {
+ if (x0 < x1) {
+ if (x0 > xMin) {
+ xMin = x0;
+ xMinI = splashFloor(xMin);
+ }
+ if (x1 < xMax) {
+ xMax = x1;
+ xMaxI = splashFloor(xMax);
+ }
+ } else {
+ if (x1 > xMin) {
+ xMin = x1;
+ xMinI = splashFloor(xMin);
+ }
+ if (x0 < xMax) {
+ xMax = x0;
+ xMaxI = splashFloor(xMax);
+ }
+ }
+ if (y0 < y1) {
+ if (y0 > yMin) {
+ yMin = y0;
+ yMinI = splashFloor(yMin);
+ }
+ if (y1 < yMax) {
+ yMax = y1;
+ yMaxI = splashFloor(yMax);
+ }
+ } else {
+ if (y1 > yMin) {
+ yMin = y1;
+ yMinI = splashFloor(yMin);
+ }
+ if (y0 < yMax) {
+ yMax = y0;
+ yMaxI = splashFloor(yMax);
+ }
+ }
+ return splashOk;
+}
+
+SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord *matrix,
+ SplashCoord flatness, GBool eo) {
+ SplashXPath *xPath;
+
+ xPath = new SplashXPath(path, matrix, flatness, gTrue);
+
+ // check for an empty path
+ if (xPath->length == 0) {
+ xMax = xMin - 1;
+ yMax = yMin - 1;
+ xMaxI = splashFloor(xMax);
+ yMaxI = splashFloor(yMax);
+ delete xPath;
+
+ // check for a rectangle
+ } else if (xPath->length == 4 &&
+ ((xPath->segs[0].x0 == xPath->segs[0].x1 &&
+ xPath->segs[0].x0 == xPath->segs[1].x0 &&
+ xPath->segs[0].x0 == xPath->segs[3].x1 &&
+ xPath->segs[2].x0 == xPath->segs[2].x1 &&
+ xPath->segs[2].x0 == xPath->segs[1].x1 &&
+ xPath->segs[2].x0 == xPath->segs[3].x0 &&
+ xPath->segs[1].y0 == xPath->segs[1].y1 &&
+ xPath->segs[1].y0 == xPath->segs[0].y1 &&
+ xPath->segs[1].y0 == xPath->segs[2].y0 &&
+ xPath->segs[3].y0 == xPath->segs[3].y1 &&
+ xPath->segs[3].y0 == xPath->segs[0].y0 &&
+ xPath->segs[3].y0 == xPath->segs[2].y1) ||
+ (xPath->segs[0].y0 == xPath->segs[0].y1 &&
+ xPath->segs[0].y0 == xPath->segs[1].y0 &&
+ xPath->segs[0].y0 == xPath->segs[3].y1 &&
+ xPath->segs[2].y0 == xPath->segs[2].y1 &&
+ xPath->segs[2].y0 == xPath->segs[1].y1 &&
+ xPath->segs[2].y0 == xPath->segs[3].y0 &&
+ xPath->segs[1].x0 == xPath->segs[1].x1 &&
+ xPath->segs[1].x0 == xPath->segs[0].x1 &&
+ xPath->segs[1].x0 == xPath->segs[2].x0 &&
+ xPath->segs[3].x0 == xPath->segs[3].x1 &&
+ xPath->segs[3].x0 == xPath->segs[0].x0 &&
+ xPath->segs[3].x0 == xPath->segs[2].x1))) {
+ clipToRect(xPath->segs[0].x0, xPath->segs[0].y0,
+ xPath->segs[2].x0, xPath->segs[2].y0);
+ delete xPath;
+
+ } else {
+ grow(1);
+ if (antialias) {
+ xPath->aaScale();
+ }
+ xPath->sort();
+ paths[length] = xPath;
+ flags[length] = eo ? splashClipEO : 0;
+ scanners[length] = new SplashXPathScanner(xPath, eo);
+ ++length;
+ }
+
+ return splashOk;
+}
+
+GBool SplashClip::test(int x, int y) {
+ int i;
+
+ // check the rectangle
+ if (x < xMinI || x > xMaxI || y < yMinI || y > yMaxI) {
+ return gFalse;
+ }
+
+ // check the paths
+ if (antialias) {
+ for (i = 0; i < length; ++i) {
+ if (!scanners[i]->test(x * splashAASize, y * splashAASize)) {
+ return gFalse;
+ }
+ }
+ } else {
+ for (i = 0; i < length; ++i) {
+ if (!scanners[i]->test(x, y)) {
+ return gFalse;
+ }
+ }
+ }
+
+ return gTrue;
+}
+
+SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin,
+ int rectXMax, int rectYMax) {
+ // This tests the rectangle:
+ // x = [rectXMin, rectXMax + 1) (note: rect coords are ints)
+ // y = [rectYMin, rectYMax + 1)
+ // against the clipping region:
+ // x = [xMin, xMax] (note: clipping coords are fp)
+ // y = [yMin, yMax]
+ if ((SplashCoord)(rectXMax + 1) <= xMin || (SplashCoord)rectXMin > xMax ||
+ (SplashCoord)(rectYMax + 1) <= yMin || (SplashCoord)rectYMin > yMax) {
+ return splashClipAllOutside;
+ }
+ if ((SplashCoord)rectXMin >= xMin && (SplashCoord)(rectXMax + 1) <= xMax &&
+ (SplashCoord)rectYMin >= yMin && (SplashCoord)(rectYMax + 1) <= yMax &&
+ length == 0) {
+ return splashClipAllInside;
+ }
+ return splashClipPartial;
+}
+
+SplashClipResult SplashClip::testSpan(int spanXMin, int spanXMax, int spanY) {
+ int i;
+
+ // This tests the rectangle:
+ // x = [spanXMin, spanXMax + 1) (note: span coords are ints)
+ // y = [spanY, spanY + 1)
+ // against the clipping region:
+ // x = [xMin, xMax] (note: clipping coords are fp)
+ // y = [yMin, yMax]
+ if ((SplashCoord)(spanXMax + 1) <= xMin || (SplashCoord)spanXMin > xMax ||
+ (SplashCoord)(spanY + 1) <= yMin || (SplashCoord)spanY > yMax) {
+ return splashClipAllOutside;
+ }
+ if (!((SplashCoord)spanXMin >= xMin && (SplashCoord)(spanXMax + 1) <= xMax &&
+ (SplashCoord)spanY >= yMin && (SplashCoord)(spanY + 1) <= yMax)) {
+ return splashClipPartial;
+ }
+ if (antialias) {
+ for (i = 0; i < length; ++i) {
+ if (!scanners[i]->testSpan(spanXMin * splashAASize,
+ spanXMax * splashAASize + (splashAASize - 1),
+ spanY * splashAASize)) {
+ return splashClipPartial;
+ }
+ }
+ } else {
+ for (i = 0; i < length; ++i) {
+ if (!scanners[i]->testSpan(spanXMin, spanXMax, spanY)) {
+ return splashClipPartial;
+ }
+ }
+ }
+ return splashClipAllInside;
+}
+
+void SplashClip::clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y) {
+ int xx0, xx1, xx, yy, i;
+ SplashColorPtr p;
+
+ // zero out pixels with x < xMin
+ xx0 = *x0 * splashAASize;
+ xx1 = splashFloor(xMin * splashAASize);
+ if (xx1 > aaBuf->getWidth()) {
+ xx1 = aaBuf->getWidth();
+ }
+ if (xx0 < xx1) {
+ xx0 &= ~7;
+ for (yy = 0; yy < splashAASize; ++yy) {
+ p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3);
+ for (xx = xx0; xx + 7 < xx1; xx += 8) {
+ *p++ = 0;
+ }
+ if (xx < xx1) {
+ *p &= 0xff >> (xx1 & 7);
+ }
+ }
+ *x0 = splashFloor(xMin);
+ }
+
+ // zero out pixels with x > xMax
+ xx0 = splashFloor(xMax * splashAASize) + 1;
+ if (xx0 < 0) {
+ xx0 = 0;
+ }
+ xx1 = (*x1 + 1) * splashAASize;
+ if (xx0 < xx1) {
+ for (yy = 0; yy < splashAASize; ++yy) {
+ p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3);
+ xx = xx0;
+ if (xx & 7) {
+ *p &= 0xff00 >> (xx & 7);
+ xx = (xx & ~7) + 8;
+ ++p;
+ }
+ for (; xx < xx1; xx += 8) {
+ *p++ = 0;
+ }
+ }
+ *x1 = splashFloor(xMax);
+ }
+
+ // check the paths
+ for (i = 0; i < length; ++i) {
+ scanners[i]->clipAALine(aaBuf, x0, x1, y);
+ }
+}
diff --git a/kpdf/xpdf/splash/SplashClip.h b/kpdf/xpdf/splash/SplashClip.h
new file mode 100644
index 00000000..8ae2154b
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashClip.h
@@ -0,0 +1,107 @@
+//========================================================================
+//
+// SplashClip.h
+//
+//========================================================================
+
+#ifndef SPLASHCLIP_H
+#define SPLASHCLIP_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "SplashTypes.h"
+#include "SplashMath.h"
+
+class SplashPath;
+class SplashXPath;
+class SplashXPathScanner;
+class SplashBitmap;
+
+//------------------------------------------------------------------------
+
+enum SplashClipResult {
+ splashClipAllInside,
+ splashClipAllOutside,
+ splashClipPartial
+};
+
+//------------------------------------------------------------------------
+// SplashClip
+//------------------------------------------------------------------------
+
+class SplashClip {
+public:
+
+ // Create a clip, for the given rectangle.
+ SplashClip(SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1,
+ GBool antialiasA);
+
+ // Copy a clip.
+ SplashClip *copy() { return new SplashClip(this); }
+
+ ~SplashClip();
+
+ // Reset the clip to a rectangle.
+ void resetToRect(SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1);
+
+ // Intersect the clip with a rectangle.
+ SplashError clipToRect(SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1);
+
+ // Interesect the clip with <path>.
+ SplashError clipToPath(SplashPath *path, SplashCoord *matrix,
+ SplashCoord flatness, GBool eo);
+
+ // Returns true if (<x>,<y>) is inside the clip.
+ GBool test(int x, int y);
+
+ // Tests a rectangle against the clipping region. Returns one of:
+ // - splashClipAllInside if the entire rectangle is inside the
+ // clipping region, i.e., all pixels in the rectangle are
+ // visible
+ // - splashClipAllOutside if the entire rectangle is outside the
+ // clipping region, i.e., all the pixels in the rectangle are
+ // clipped
+ // - splashClipPartial if the rectangle is part inside and part
+ // outside the clipping region
+ SplashClipResult testRect(int rectXMin, int rectYMin,
+ int rectXMax, int rectYMax);
+
+ // Similar to testRect, but tests a horizontal span.
+ SplashClipResult testSpan(int spanXMin, int spanXMax, int spanY);
+
+ // Clips an anti-aliased line by setting pixels to zero. On entry,
+ // all non-zero pixels are between <x0> and <x1>. This function
+ // will update <x0> and <x1>.
+ void clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y);
+
+ // Get the rectangle part of the clip region, in integer coordinates.
+ int getXMinI() { return xMinI; }
+ int getXMaxI() { return xMaxI; }
+ int getYMinI() { return yMinI; }
+ int getYMaxI() { return yMaxI; }
+
+ // Get the number of arbitrary paths used by the clip region.
+ int getNumPaths() { return length; }
+
+private:
+
+ SplashClip(SplashClip *clip);
+ void grow(int nPaths);
+
+ GBool antialias;
+ SplashCoord xMin, yMin, xMax, yMax;
+ int xMinI, yMinI, xMaxI, yMaxI;
+ SplashXPath **paths;
+ Guchar *flags;
+ SplashXPathScanner **scanners;
+ int length, size;
+};
+
+#endif
diff --git a/kpdf/xpdf/splash/SplashErrorCodes.h b/kpdf/xpdf/splash/SplashErrorCodes.h
new file mode 100644
index 00000000..e7f1f0b5
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashErrorCodes.h
@@ -0,0 +1,34 @@
+//========================================================================
+//
+// SplashErrorCodes.h
+//
+//========================================================================
+
+#ifndef SPLASHERRORCODES_H
+#define SPLASHERRORCODES_H
+
+#include <aconf.h>
+
+//------------------------------------------------------------------------
+
+#define splashOk 0 // no error
+
+#define splashErrNoCurPt 1 // no current point
+
+#define splashErrEmptyPath 2 // zero points in path
+
+#define splashErrBogusPath 3 // only one point in subpath
+
+#define splashErrNoSave 4 // state stack is empty
+
+#define splashErrOpenFile 5 // couldn't open file
+
+#define splashErrNoGlyph 6 // couldn't get the requested glyph
+
+#define splashErrModeMismatch 7 // invalid combination of color modes
+
+#define splashErrSingularMatrix 8 // matrix is singular
+
+#define splashErrZeroImage 9 // image of 0x0
+
+#endif
diff --git a/kpdf/xpdf/splash/SplashFTFont.cc b/kpdf/xpdf/splash/SplashFTFont.cc
new file mode 100644
index 00000000..42d92af4
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashFTFont.cc
@@ -0,0 +1,375 @@
+//========================================================================
+//
+// SplashFTFont.cc
+//
+//========================================================================
+
+#include <aconf.h>
+
+#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <ft2build.h>
+#include FT_OUTLINE_H
+#include FT_SIZES_H
+#include FT_GLYPH_H
+#include "gmem.h"
+#include "SplashMath.h"
+#include "SplashGlyphBitmap.h"
+#include "SplashPath.h"
+#include "SplashFTFontEngine.h"
+#include "SplashFTFontFile.h"
+#include "SplashFTFont.h"
+
+//------------------------------------------------------------------------
+
+static int glyphPathMoveTo(const FT_Vector *pt, void *path);
+static int glyphPathLineTo(const FT_Vector *pt, void *path);
+static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt,
+ void *path);
+static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2,
+ const FT_Vector *pt, void *path);
+
+//------------------------------------------------------------------------
+// SplashFTFont
+//------------------------------------------------------------------------
+
+SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA,
+ SplashCoord *textMatA):
+ SplashFont(fontFileA, matA, textMatA, fontFileA->engine->aa)
+{
+ FT_Face face;
+ SplashCoord size, div;
+ int x, y;
+
+ face = fontFileA->face;
+ if (FT_New_Size(face, &sizeObj)) {
+ return;
+ }
+ face->size = sizeObj;
+ size = splashSqrt(mat[2]*mat[2] + mat[3]*mat[3]);
+ if (FT_Set_Pixel_Sizes(face, 0, (int)size)) {
+ return;
+ }
+ // if the textMat values are too small, FreeType's fixed point
+ // arithmetic doesn't work so well
+ textScale = splashSqrt(textMat[2]*textMat[2] + textMat[3]*textMat[3]) / size;
+
+ div = face->bbox.xMax > 20000 ? 65536 : 1;
+
+ // transform the four corners of the font bounding box -- the min
+ // and max values form the bounding box of the transformed font
+ x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMin) /
+ (div * face->units_per_EM));
+ xMin = xMax = x;
+ y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMin) /
+ (div * face->units_per_EM));
+ yMin = yMax = y;
+ x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMax) /
+ (div * face->units_per_EM));
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMax) /
+ (div * face->units_per_EM));
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMin) /
+ (div * face->units_per_EM));
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMin) /
+ (div * face->units_per_EM));
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMax) /
+ (div * face->units_per_EM));
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMax) /
+ (div * face->units_per_EM));
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ // This is a kludge: some buggy PDF generators embed fonts with
+ // zero bounding boxes.
+ if (xMax == xMin) {
+ xMin = 0;
+ xMax = (int)size;
+ }
+ if (yMax == yMin) {
+ yMin = 0;
+ yMax = (int)((SplashCoord)1.2 * size);
+ }
+
+ // compute the transform matrix
+#if USE_FIXEDPOINT
+ matrix.xx = (FT_Fixed)((mat[0] / size).getRaw());
+ matrix.yx = (FT_Fixed)((mat[1] / size).getRaw());
+ matrix.xy = (FT_Fixed)((mat[2] / size).getRaw());
+ matrix.yy = (FT_Fixed)((mat[3] / size).getRaw());
+ textMatrix.xx = (FT_Fixed)((textMat[0] / (size * textScale)).getRaw());
+ textMatrix.yx = (FT_Fixed)((textMat[1] / (size * textScale)).getRaw());
+ textMatrix.xy = (FT_Fixed)((textMat[2] / (size * textScale)).getRaw());
+ textMatrix.yy = (FT_Fixed)((textMat[3] / (size * textScale)).getRaw());
+#else
+ matrix.xx = (FT_Fixed)((mat[0] / size) * 65536);
+ matrix.yx = (FT_Fixed)((mat[1] / size) * 65536);
+ matrix.xy = (FT_Fixed)((mat[2] / size) * 65536);
+ matrix.yy = (FT_Fixed)((mat[3] / size) * 65536);
+ textMatrix.xx = (FT_Fixed)((textMat[0] / (size * textScale)) * 65536);
+ textMatrix.yx = (FT_Fixed)((textMat[1] / (size * textScale)) * 65536);
+ textMatrix.xy = (FT_Fixed)((textMat[2] / (size * textScale)) * 65536);
+ textMatrix.yy = (FT_Fixed)((textMat[3] / (size * textScale)) * 65536);
+#endif
+}
+
+SplashFTFont::~SplashFTFont() {
+}
+
+GBool SplashFTFont::getGlyph(int c, int xFrac, int /*yFrac*/,
+ SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) {
+ return SplashFont::getGlyph(c, xFrac, 0, bitmap, x0, y0, clip, clipRes);
+}
+
+GBool SplashFTFont::makeGlyph(int c, int xFrac, int /*yFrac*/,
+ SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) {
+ SplashFTFontFile *ff;
+ FT_Vector offset;
+ FT_GlyphSlot slot;
+ FT_UInt gid;
+ int rowSize;
+ Guchar *p, *q;
+ int i;
+
+ ff = (SplashFTFontFile *)fontFile;
+
+ ff->face->size = sizeObj;
+ offset.x = (FT_Pos)(int)((SplashCoord)xFrac * splashFontFractionMul * 64);
+ offset.y = 0;
+ FT_Set_Transform(ff->face, &matrix, &offset);
+ slot = ff->face->glyph;
+
+ if (ff->codeToGID && c < ff->codeToGIDLen) {
+ gid = (FT_UInt)ff->codeToGID[c];
+ } else {
+ gid = (FT_UInt)c;
+ }
+ if (ff->trueType && gid == 0) {
+ // skip the TrueType notdef glyph
+ return gFalse;
+ }
+
+ // if we have the FT2 bytecode interpreter, autohinting won't be used
+#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER
+ if (FT_Load_Glyph(ff->face, gid,
+ aa ? FT_LOAD_NO_BITMAP : FT_LOAD_DEFAULT)) {
+ return gFalse;
+ }
+#else
+ // FT2's autohinting doesn't always work very well (especially with
+ // font subsets), so turn it off if anti-aliasing is enabled; if
+ // anti-aliasing is disabled, this seems to be a tossup - some fonts
+ // look better with hinting, some without, so leave hinting on
+ if (FT_Load_Glyph(ff->face, gid,
+ aa ? FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP
+ : FT_LOAD_DEFAULT)) {
+ return gFalse;
+ }
+#endif
+
+ FT_Glyph_Metrics *glyphMetrics = &(ff->face->glyph->metrics);
+ // prelimirary values from FT_Glyph_Metrics
+ bitmap->x = splashRound(-glyphMetrics->horiBearingX / 64.0);
+ bitmap->y = splashRound(glyphMetrics->horiBearingY / 64.0);
+ bitmap->w = splashRound(glyphMetrics->width / 64.0);
+ bitmap->h = splashRound(glyphMetrics->height / 64.0);
+
+ *clipRes = clip->testRect(x0 - bitmap->x,
+ y0 - bitmap->y,
+ x0 - bitmap->x + bitmap->w - 1,
+ y0 - bitmap->y + bitmap->h - 1);
+ if (*clipRes == splashClipAllOutside)
+ {
+ bitmap->freeData = gFalse;
+ return gTrue;
+ }
+
+ if (FT_Render_Glyph(slot, aa ? ft_render_mode_normal
+ : ft_render_mode_mono)) {
+ return gFalse;
+ }
+
+ bitmap->x = -slot->bitmap_left;
+ bitmap->y = slot->bitmap_top;
+ bitmap->w = slot->bitmap.width;
+ bitmap->h = slot->bitmap.rows;
+ bitmap->aa = aa;
+ if (aa) {
+ rowSize = bitmap->w;
+ } else {
+ rowSize = (bitmap->w + 7) >> 3;
+ }
+ bitmap->data = (Guchar *)gmalloc(rowSize * bitmap->h);
+ bitmap->freeData = gTrue;
+ for (i = 0, p = bitmap->data, q = slot->bitmap.buffer;
+ i < bitmap->h;
+ ++i, p += rowSize, q += slot->bitmap.pitch) {
+ memcpy(p, q, rowSize);
+ }
+
+ return gTrue;
+}
+
+struct SplashFTFontPath {
+ SplashPath *path;
+ SplashCoord textScale;
+ GBool needClose;
+};
+
+SplashPath *SplashFTFont::getGlyphPath(int c) {
+ static FT_Outline_Funcs outlineFuncs = {
+#if FREETYPE_MINOR <= 1
+ (int (*)(FT_Vector *, void *))&glyphPathMoveTo,
+ (int (*)(FT_Vector *, void *))&glyphPathLineTo,
+ (int (*)(FT_Vector *, FT_Vector *, void *))&glyphPathConicTo,
+ (int (*)(FT_Vector *, FT_Vector *, FT_Vector *, void *))&glyphPathCubicTo,
+#else
+ &glyphPathMoveTo,
+ &glyphPathLineTo,
+ &glyphPathConicTo,
+ &glyphPathCubicTo,
+#endif
+ 0, 0
+ };
+ SplashFTFontFile *ff;
+ SplashFTFontPath path;
+ FT_GlyphSlot slot;
+ FT_UInt gid;
+ FT_Glyph glyph;
+
+ ff = (SplashFTFontFile *)fontFile;
+ ff->face->size = sizeObj;
+ FT_Set_Transform(ff->face, &textMatrix, NULL);
+ slot = ff->face->glyph;
+ if (ff->codeToGID && c < ff->codeToGIDLen) {
+ gid = ff->codeToGID[c];
+ } else {
+ gid = (FT_UInt)c;
+ }
+ if (ff->trueType && gid == 0) {
+ // skip the TrueType notdef glyph
+ return NULL;
+ }
+ if (FT_Load_Glyph(ff->face, gid, FT_LOAD_NO_BITMAP)) {
+ return NULL;
+ }
+ if (FT_Get_Glyph(slot, &glyph)) {
+ return NULL;
+ }
+ path.path = new SplashPath();
+ path.textScale = textScale;
+ path.needClose = gFalse;
+ FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline,
+ &outlineFuncs, &path);
+ if (path.needClose) {
+ path.path->close();
+ }
+ FT_Done_Glyph(glyph);
+ return path.path;
+}
+
+static int glyphPathMoveTo(const FT_Vector *pt, void *path) {
+ SplashFTFontPath *p = (SplashFTFontPath *)path;
+
+ if (p->needClose) {
+ p->path->close();
+ p->needClose = gFalse;
+ }
+ p->path->moveTo((SplashCoord)pt->x * p->textScale / 64.0,
+ (SplashCoord)pt->y * p->textScale / 64.0);
+ return 0;
+}
+
+static int glyphPathLineTo(const FT_Vector *pt, void *path) {
+ SplashFTFontPath *p = (SplashFTFontPath *)path;
+
+ p->path->lineTo((SplashCoord)pt->x * p->textScale / 64.0,
+ (SplashCoord)pt->y * p->textScale / 64.0);
+ p->needClose = gTrue;
+ return 0;
+}
+
+static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt,
+ void *path) {
+ SplashFTFontPath *p = (SplashFTFontPath *)path;
+ SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xc, yc;
+
+ if (!p->path->getCurPt(&x0, &y0)) {
+ return 0;
+ }
+ xc = (SplashCoord)ctrl->x * p->textScale / 64.0;
+ yc = (SplashCoord)ctrl->y * p->textScale / 64.0;
+ x3 = (SplashCoord)pt->x * p->textScale / 64.0;
+ y3 = (SplashCoord)pt->y * p->textScale / 64.0;
+
+ // A second-order Bezier curve is defined by two endpoints, p0 and
+ // p3, and one control point, pc:
+ //
+ // p(t) = (1-t)^2*p0 + t*(1-t)*pc + t^2*p3
+ //
+ // A third-order Bezier curve is defined by the same two endpoints,
+ // p0 and p3, and two control points, p1 and p2:
+ //
+ // p(t) = (1-t)^3*p0 + 3t*(1-t)^2*p1 + 3t^2*(1-t)*p2 + t^3*p3
+ //
+ // Applying some algebra, we can convert a second-order curve to a
+ // third-order curve:
+ //
+ // p1 = (1/3) * (p0 + 2pc)
+ // p2 = (1/3) * (2pc + p3)
+
+ x1 = (SplashCoord)(1.0 / 3.0) * (x0 + (SplashCoord)2 * xc);
+ y1 = (SplashCoord)(1.0 / 3.0) * (y0 + (SplashCoord)2 * yc);
+ x2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * xc + x3);
+ y2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * yc + y3);
+
+ p->path->curveTo(x1, y1, x2, y2, x3, y3);
+ p->needClose = gTrue;
+ return 0;
+}
+
+static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2,
+ const FT_Vector *pt, void *path) {
+ SplashFTFontPath *p = (SplashFTFontPath *)path;
+
+ p->path->curveTo((SplashCoord)ctrl1->x * p->textScale / 64.0,
+ (SplashCoord)ctrl1->y * p->textScale / 64.0,
+ (SplashCoord)ctrl2->x * p->textScale / 64.0,
+ (SplashCoord)ctrl2->y * p->textScale / 64.0,
+ (SplashCoord)pt->x * p->textScale / 64.0,
+ (SplashCoord)pt->y * p->textScale / 64.0);
+ p->needClose = gTrue;
+ return 0;
+}
+
+#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
diff --git a/kpdf/xpdf/splash/SplashFTFont.h b/kpdf/xpdf/splash/SplashFTFont.h
new file mode 100644
index 00000000..e014ba3f
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashFTFont.h
@@ -0,0 +1,58 @@
+//========================================================================
+//
+// SplashFTFont.h
+//
+//========================================================================
+
+#ifndef SPLASHFTFONT_H
+#define SPLASHFTFONT_H
+
+#include <aconf.h>
+
+#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include "SplashFont.h"
+
+class SplashFTFontFile;
+
+//------------------------------------------------------------------------
+// SplashFTFont
+//------------------------------------------------------------------------
+
+class SplashFTFont: public SplashFont {
+public:
+
+ SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA,
+ SplashCoord *textMatA);
+
+ virtual ~SplashFTFont();
+
+ // Munge xFrac and yFrac before calling SplashFont::getGlyph.
+ virtual GBool getGlyph(int c, int xFrac, int yFrac,
+ SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes);
+
+ // Rasterize a glyph. The <xFrac> and <yFrac> values are the same
+ // as described for getGlyph.
+ virtual GBool makeGlyph(int c, int xFrac, int yFrac,
+ SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes);
+
+ // Return the path for a glyph.
+ virtual SplashPath *getGlyphPath(int c);
+
+private:
+
+ FT_Size sizeObj;
+ FT_Matrix matrix;
+ FT_Matrix textMatrix;
+ SplashCoord textScale;
+};
+
+#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+
+#endif
diff --git a/kpdf/xpdf/splash/SplashFTFontEngine.cc b/kpdf/xpdf/splash/SplashFTFontEngine.cc
new file mode 100644
index 00000000..02996de7
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashFTFontEngine.cc
@@ -0,0 +1,194 @@
+//========================================================================
+//
+// SplashFTFontEngine.cc
+//
+//========================================================================
+
+#include <aconf.h>
+
+#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#ifndef WIN32
+# include <unistd.h>
+#endif
+#include "gmem.h"
+#include "GString.h"
+#include "gfile.h"
+#include "FoFiTrueType.h"
+#include "FoFiType1C.h"
+#include "SplashFTFontFile.h"
+#include "SplashFTFontEngine.h"
+
+#ifdef VMS
+#if (__VMS_VER < 70000000)
+extern "C" int unlink(char *filename);
+#endif
+#endif
+
+//------------------------------------------------------------------------
+/*
+static void fileWrite(void *stream, char *data, int len) {
+ fwrite(data, 1, len, (FILE *)stream);
+}
+*/
+
+//------------------------------------------------------------------------
+// SplashFTFontEngine
+//------------------------------------------------------------------------
+
+SplashFTFontEngine::SplashFTFontEngine(GBool aaA, FT_Library libA) {
+ FT_Int major, minor, patch;
+
+ aa = aaA;
+ lib = libA;
+
+ // as of FT 2.1.8, CID fonts are indexed by CID instead of GID
+ FT_Library_Version(lib, &major, &minor, &patch);
+ useCIDs = major > 2 ||
+ (major == 2 && (minor > 1 || (minor == 1 && patch > 7)));
+}
+
+SplashFTFontEngine *SplashFTFontEngine::init(GBool aaA) {
+ FT_Library libA;
+
+ if (FT_Init_FreeType(&libA)) {
+ return NULL;
+ }
+ return new SplashFTFontEngine(aaA, libA);
+}
+
+SplashFTFontEngine::~SplashFTFontEngine() {
+ FT_Done_FreeType(lib);
+}
+
+SplashFontFile *SplashFTFontEngine::loadType1Font(SplashFontFileID *idA,
+ SplashFontSrc *src,
+ char **enc) {
+ return SplashFTFontFile::loadType1Font(this, idA, src, enc);
+}
+
+SplashFontFile *SplashFTFontEngine::loadType1CFont(SplashFontFileID *idA,
+ SplashFontSrc *src,
+ char **enc) {
+ return SplashFTFontFile::loadType1Font(this, idA, src, enc);
+}
+
+SplashFontFile *SplashFTFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA,
+ SplashFontSrc *src,
+ char **enc) {
+ return SplashFTFontFile::loadType1Font(this, idA, src, enc);
+}
+
+SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA,
+ SplashFontSrc *src) {
+ FoFiType1C *ff;
+ Gushort *cidToGIDMap;
+ int nCIDs;
+ SplashFontFile *ret;
+
+ // check for a CFF font
+ if (useCIDs) {
+ cidToGIDMap = NULL;
+ nCIDs = 0;
+ } else {
+ if (src->isFile) {
+ ff = FoFiType1C::load(src->fileName->getCString());
+ } else {
+ ff = FoFiType1C::make(src->buf, src->bufLen);
+ }
+ if (ff) {
+ cidToGIDMap = ff->getCIDToGIDMap(&nCIDs);
+ delete ff;
+ } else {
+ cidToGIDMap = NULL;
+ nCIDs = 0;
+ }
+ }
+ ret = SplashFTFontFile::loadCIDFont(this, idA, src, cidToGIDMap, nCIDs);
+ if (!ret) {
+ gfree(cidToGIDMap);
+ }
+ return ret;
+}
+
+SplashFontFile *SplashFTFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA,
+ SplashFontSrc *src) {
+ FoFiTrueType *ff;
+ GBool isCID;
+ Gushort *cidToGIDMap;
+ int nCIDs;
+ SplashFontFile *ret;
+
+ cidToGIDMap = NULL;
+ nCIDs = 0;
+ isCID = gFalse;
+ if (!useCIDs) {
+ if (src->isFile) {
+ ff = FoFiTrueType::load(src->fileName->getCString());
+ } else {
+ ff = FoFiTrueType::make(src->buf, src->bufLen);
+ }
+ if (ff) {
+ if (ff->isOpenTypeCFF()) {
+ cidToGIDMap = ff->getCIDToGIDMap(&nCIDs);
+ }
+ delete ff;
+ }
+ }
+ ret = SplashFTFontFile::loadCIDFont(this, idA, src,
+ cidToGIDMap, nCIDs);
+ if (!ret) {
+ gfree(cidToGIDMap);
+ }
+ return ret;
+}
+
+SplashFontFile *SplashFTFontEngine::loadTrueTypeFont(SplashFontFileID *idA,
+ SplashFontSrc *src,
+ Gushort *codeToGID,
+ int codeToGIDLen,
+ int faceIndex) {
+#if 0
+ FoFiTrueType *ff;
+ GString *tmpFileName;
+ FILE *tmpFile;
+ SplashFontFile *ret;
+
+ if (!(ff = FoFiTrueType::load(fileName))) {
+ return NULL;
+ }
+ tmpFileName = NULL;
+ if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) {
+ delete ff;
+ return NULL;
+ }
+ ff->writeTTF(&fileWrite, tmpFile);
+ delete ff;
+ fclose(tmpFile);
+ ret = SplashFTFontFile::loadTrueTypeFont(this, idA,
+ tmpFileName->getCString(),
+ gTrue, codeToGID, codeToGIDLen);
+ if (ret) {
+ if (deleteFile) {
+ unlink(fileName);
+ }
+ } else {
+ unlink(tmpFileName->getCString());
+ }
+ delete tmpFileName;
+ return ret;
+#else
+ SplashFontFile *ret;
+ ret = SplashFTFontFile::loadTrueTypeFont(this, idA, src,
+ codeToGID, codeToGIDLen,
+ faceIndex);
+ return ret;
+#endif
+}
+
+#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
diff --git a/kpdf/xpdf/splash/SplashFTFontEngine.h b/kpdf/xpdf/splash/SplashFTFontEngine.h
new file mode 100644
index 00000000..294d20c6
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashFTFontEngine.h
@@ -0,0 +1,60 @@
+//========================================================================
+//
+// SplashFTFontEngine.h
+//
+//========================================================================
+
+#ifndef SPLASHFTFONTENGINE_H
+#define SPLASHFTFONTENGINE_H
+
+#include <aconf.h>
+
+#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include "gtypes.h"
+
+class SplashFontFile;
+class SplashFontFileID;
+class SplashFontSrc;
+
+//------------------------------------------------------------------------
+// SplashFTFontEngine
+//------------------------------------------------------------------------
+
+class SplashFTFontEngine {
+public:
+
+ static SplashFTFontEngine *init(GBool aaA);
+
+ ~SplashFTFontEngine();
+
+ // Load fonts.
+ SplashFontFile *loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, char **enc);
+ SplashFontFile *loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, char **enc);
+ SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA, SplashFontSrc *src, char **enc);
+ SplashFontFile *loadCIDFont(SplashFontFileID *idA, SplashFontSrc *src);
+ SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, SplashFontSrc *src);
+ SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, SplashFontSrc *src,
+ Gushort *codeToGID, int codeToGIDLen, int faceIndex = 0);
+
+private:
+
+ SplashFTFontEngine(GBool aaA, FT_Library libA);
+
+ GBool aa;
+ FT_Library lib;
+ GBool useCIDs;
+
+ friend class SplashFTFontFile;
+ friend class SplashFTFont;
+};
+
+#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+
+#endif
diff --git a/kpdf/xpdf/splash/SplashFTFontFile.cc b/kpdf/xpdf/splash/SplashFTFontFile.cc
new file mode 100644
index 00000000..12725497
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashFTFontFile.cc
@@ -0,0 +1,125 @@
+//========================================================================
+//
+// SplashFTFontFile.cc
+//
+//========================================================================
+
+#include <aconf.h>
+
+#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "gmem.h"
+#include "SplashFTFontEngine.h"
+#include "SplashFTFont.h"
+#include "SplashFTFontFile.h"
+#include "GString.h"
+
+//------------------------------------------------------------------------
+// SplashFTFontFile
+//------------------------------------------------------------------------
+
+SplashFontFile *SplashFTFontFile::loadType1Font(SplashFTFontEngine *engineA,
+ SplashFontFileID *idA,
+ SplashFontSrc *src,
+ char **encA) {
+ FT_Face faceA;
+ Gushort *codeToGIDA;
+ char *name;
+ int i;
+
+ if (src->isFile) {
+ if (FT_New_Face(engineA->lib, src->fileName->getCString(), 0, &faceA))
+ return NULL;
+ } else {
+ if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, 0, &faceA))
+ return NULL;
+ }
+ codeToGIDA = (Gushort *)gmallocn(256, sizeof(int));
+ for (i = 0; i < 256; ++i) {
+ codeToGIDA[i] = 0;
+ if ((name = encA[i])) {
+ codeToGIDA[i] = (Gushort)FT_Get_Name_Index(faceA, name);
+ }
+ }
+
+ return new SplashFTFontFile(engineA, idA, src,
+ faceA, codeToGIDA, 256, gFalse);
+}
+
+SplashFontFile *SplashFTFontFile::loadCIDFont(SplashFTFontEngine *engineA,
+ SplashFontFileID *idA,
+ SplashFontSrc *src,
+ Gushort *codeToGIDA,
+ int codeToGIDLenA) {
+ FT_Face faceA;
+
+ if (src->isFile) {
+ if (FT_New_Face(engineA->lib, src->fileName->getCString(), 0, &faceA))
+ return NULL;
+ } else {
+ if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, 0, &faceA))
+ return NULL;
+ }
+
+ return new SplashFTFontFile(engineA, idA, src,
+ faceA, codeToGIDA, codeToGIDLenA, gFalse);
+}
+
+SplashFontFile *SplashFTFontFile::loadTrueTypeFont(SplashFTFontEngine *engineA,
+ SplashFontFileID *idA,
+ SplashFontSrc *src,
+ Gushort *codeToGIDA,
+ int codeToGIDLenA,
+ int faceIndexA) {
+ FT_Face faceA;
+
+ if (src->isFile) {
+ if (FT_New_Face(engineA->lib, src->fileName->getCString(), faceIndexA, &faceA))
+ return NULL;
+ } else {
+ if (FT_New_Memory_Face(engineA->lib, (const FT_Byte *)src->buf, src->bufLen, faceIndexA, &faceA))
+ return NULL;
+ }
+
+ return new SplashFTFontFile(engineA, idA, src,
+ faceA, codeToGIDA, codeToGIDLenA, gTrue);
+}
+
+SplashFTFontFile::SplashFTFontFile(SplashFTFontEngine *engineA,
+ SplashFontFileID *idA,
+ SplashFontSrc *src,
+ FT_Face faceA,
+ Gushort *codeToGIDA, int codeToGIDLenA,
+ GBool trueTypeA):
+ SplashFontFile(idA, src)
+{
+ engine = engineA;
+ face = faceA;
+ codeToGID = codeToGIDA;
+ codeToGIDLen = codeToGIDLenA;
+ trueType = trueTypeA;
+}
+
+SplashFTFontFile::~SplashFTFontFile() {
+ if (face) {
+ FT_Done_Face(face);
+ }
+ if (codeToGID) {
+ gfree(codeToGID);
+ }
+}
+
+SplashFont *SplashFTFontFile::makeFont(SplashCoord *mat,
+ SplashCoord *textMat) {
+ SplashFont *font;
+
+ font = new SplashFTFont(this, mat, textMat);
+ font->initCache();
+ return font;
+}
+
+#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
diff --git a/kpdf/xpdf/splash/SplashFTFontFile.h b/kpdf/xpdf/splash/SplashFTFontFile.h
new file mode 100644
index 00000000..dedc25cf
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashFTFontFile.h
@@ -0,0 +1,72 @@
+//========================================================================
+//
+// SplashFTFontFile.h
+//
+//========================================================================
+
+#ifndef SPLASHFTFONTFILE_H
+#define SPLASHFTFONTFILE_H
+
+#include <aconf.h>
+
+#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include "SplashFontFile.h"
+
+class SplashFontFileID;
+class SplashFTFontEngine;
+
+//------------------------------------------------------------------------
+// SplashFTFontFile
+//------------------------------------------------------------------------
+
+class SplashFTFontFile: public SplashFontFile {
+public:
+
+ static SplashFontFile *loadType1Font(SplashFTFontEngine *engineA,
+ SplashFontFileID *idA, SplashFontSrc *src,
+ char **encA);
+ static SplashFontFile *loadCIDFont(SplashFTFontEngine *engineA,
+ SplashFontFileID *idA, SplashFontSrc *src,
+ Gushort *codeToCIDA, int codeToGIDLenA);
+ static SplashFontFile *loadTrueTypeFont(SplashFTFontEngine *engineA,
+ SplashFontFileID *idA,
+ SplashFontSrc *src,
+ Gushort *codeToGIDA,
+ int codeToGIDLenA,
+ int faceIndexA=0);
+
+ virtual ~SplashFTFontFile();
+
+ // Create a new SplashFTFont, i.e., a scaled instance of this font
+ // file.
+ virtual SplashFont *makeFont(SplashCoord *mat,
+ SplashCoord *textMat);
+
+private:
+
+ SplashFTFontFile(SplashFTFontEngine *engineA,
+ SplashFontFileID *idA,
+ SplashFontSrc *src,
+ FT_Face faceA,
+ Gushort *codeToGIDA, int codeToGIDLenA,
+ GBool trueTypeA);
+
+ SplashFTFontEngine *engine;
+ FT_Face face;
+ Gushort *codeToGID;
+ int codeToGIDLen;
+ GBool trueType;
+
+ friend class SplashFTFont;
+};
+
+#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+
+#endif
diff --git a/kpdf/xpdf/splash/SplashFont.cc b/kpdf/xpdf/splash/SplashFont.cc
new file mode 100644
index 00000000..4a91d5e8
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashFont.cc
@@ -0,0 +1,201 @@
+//========================================================================
+//
+// SplashFont.cc
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <string.h>
+#include "gmem.h"
+#include "SplashMath.h"
+#include "SplashGlyphBitmap.h"
+#include "SplashFontFile.h"
+#include "SplashFont.h"
+
+//------------------------------------------------------------------------
+
+struct SplashFontCacheTag {
+ int c;
+ short xFrac, yFrac; // x and y fractions
+ int mru; // valid bit (0x80000000) and MRU index
+ int x, y, w, h; // offset and size of glyph
+};
+
+//------------------------------------------------------------------------
+// SplashFont
+//------------------------------------------------------------------------
+
+SplashFont::SplashFont(SplashFontFile *fontFileA, SplashCoord *matA,
+ SplashCoord *textMatA, GBool aaA) {
+ fontFile = fontFileA;
+ fontFile->incRefCnt();
+ mat[0] = matA[0];
+ mat[1] = matA[1];
+ mat[2] = matA[2];
+ mat[3] = matA[3];
+ textMat[0] = textMatA[0];
+ textMat[1] = textMatA[1];
+ textMat[2] = textMatA[2];
+ textMat[3] = textMatA[3];
+ aa = aaA;
+
+ cache = NULL;
+ cacheTags = NULL;
+
+ xMin = yMin = xMax = yMax = 0;
+}
+
+void SplashFont::initCache() {
+ int i;
+
+ // this should be (max - min + 1), but we add some padding to
+ // deal with rounding errors
+ glyphW = xMax - xMin + 3;
+ glyphH = yMax - yMin + 3;
+ if (aa) {
+ glyphSize = glyphW * glyphH;
+ } else {
+ glyphSize = ((glyphW + 7) >> 3) * glyphH;
+ }
+
+ // set up the glyph pixmap cache
+ cacheAssoc = 8;
+ if (glyphSize <= 256) {
+ cacheSets = 8;
+ } else if (glyphSize <= 512) {
+ cacheSets = 4;
+ } else if (glyphSize <= 1024) {
+ cacheSets = 2;
+ } else {
+ cacheSets = 1;
+ }
+ cache = (Guchar *)gmallocn_checkoverflow(cacheSets * cacheAssoc, glyphSize);
+ if (cache != NULL) {
+ cacheTags = (SplashFontCacheTag *)gmallocn(cacheSets * cacheAssoc,
+ sizeof(SplashFontCacheTag));
+ for (i = 0; i < cacheSets * cacheAssoc; ++i) {
+ cacheTags[i].mru = i & (cacheAssoc - 1);
+ }
+ } else {
+ cacheAssoc = 0;
+ }
+}
+
+SplashFont::~SplashFont() {
+ fontFile->decRefCnt();
+ if (cache) {
+ gfree(cache);
+ }
+ if (cacheTags) {
+ gfree(cacheTags);
+ }
+}
+
+GBool SplashFont::getGlyph(int c, int xFrac, int yFrac,
+ SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) {
+ SplashGlyphBitmap bitmap2;
+ int size;
+ Guchar *p;
+ int i, j, k;
+
+ // no fractional coordinates for large glyphs or non-anti-aliased
+ // glyphs
+ if (!aa || glyphH > 50) {
+ xFrac = yFrac = 0;
+ }
+
+ // check the cache
+ i = (c & (cacheSets - 1)) * cacheAssoc;
+ for (j = 0; j < cacheAssoc; ++j) {
+ if ((cacheTags[i+j].mru & 0x80000000) &&
+ cacheTags[i+j].c == c &&
+ (int)cacheTags[i+j].xFrac == xFrac &&
+ (int)cacheTags[i+j].yFrac == yFrac) {
+ bitmap->x = cacheTags[i+j].x;
+ bitmap->y = cacheTags[i+j].y;
+ bitmap->w = cacheTags[i+j].w;
+ bitmap->h = cacheTags[i+j].h;
+ for (k = 0; k < cacheAssoc; ++k) {
+ if (k != j &&
+ (cacheTags[i+k].mru & 0x7fffffff) <
+ (cacheTags[i+j].mru & 0x7fffffff)) {
+ ++cacheTags[i+k].mru;
+ }
+ }
+ cacheTags[i+j].mru = 0x80000000;
+ bitmap->aa = aa;
+ bitmap->data = cache + (i+j) * glyphSize;
+ bitmap->freeData = gFalse;
+
+ *clipRes = clip->testRect(x0 - bitmap->x,
+ y0 - bitmap->y,
+ x0 - bitmap->x + bitmap->w - 1,
+ y0 - bitmap->y + bitmap->h - 1);
+
+ return gTrue;
+ }
+ }
+
+ // generate the glyph bitmap
+ if (!makeGlyph(c, xFrac, yFrac, &bitmap2, x0, y0, clip, clipRes)) {
+ return gFalse;
+ }
+
+ if (*clipRes == splashClipAllOutside)
+ {
+ bitmap->freeData = gFalse;
+ if (bitmap2.freeData) gfree(bitmap2.data);
+ return gTrue;
+ }
+
+ // if the glyph doesn't fit in the bounding box, return a temporary
+ // uncached bitmap
+ if (bitmap2.w > glyphW || bitmap2.h > glyphH) {
+ *bitmap = bitmap2;
+ return gTrue;
+ }
+
+ // insert glyph pixmap in cache
+ if (aa) {
+ size = bitmap2.w * bitmap2.h;
+ } else {
+ size = ((bitmap2.w + 7) >> 3) * bitmap2.h;
+ }
+ p = NULL; // make gcc happy
+ if (cacheAssoc == 0)
+ {
+ // we had problems on the malloc of the cache, so ignore it
+ *bitmap = bitmap2;
+ }
+ else
+ {
+ for (j = 0; j < cacheAssoc; ++j) {
+ if ((cacheTags[i+j].mru & 0x7fffffff) == cacheAssoc - 1) {
+ cacheTags[i+j].mru = 0x80000000;
+ cacheTags[i+j].c = c;
+ cacheTags[i+j].xFrac = (short)xFrac;
+ cacheTags[i+j].yFrac = (short)yFrac;
+ cacheTags[i+j].x = bitmap2.x;
+ cacheTags[i+j].y = bitmap2.y;
+ cacheTags[i+j].w = bitmap2.w;
+ cacheTags[i+j].h = bitmap2.h;
+ p = cache + (i+j) * glyphSize;
+ memcpy(p, bitmap2.data, size);
+ } else {
+ ++cacheTags[i+j].mru;
+ }
+ }
+ *bitmap = bitmap2;
+ bitmap->data = p;
+ bitmap->freeData = gFalse;
+ if (bitmap2.freeData) {
+ gfree(bitmap2.data);
+ }
+ }
+ return gTrue;
+}
diff --git a/kpdf/xpdf/splash/SplashFont.h b/kpdf/xpdf/splash/SplashFont.h
new file mode 100644
index 00000000..82ee0370
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashFont.h
@@ -0,0 +1,105 @@
+//========================================================================
+//
+// SplashFont.h
+//
+//========================================================================
+
+#ifndef SPLASHFONT_H
+#define SPLASHFONT_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "SplashTypes.h"
+#include "SplashClip.h"
+
+struct SplashGlyphBitmap;
+struct SplashFontCacheTag;
+class SplashFontFile;
+class SplashPath;
+
+//------------------------------------------------------------------------
+
+// Fractional positioning uses this many bits to the right of the
+// decimal points.
+#define splashFontFractionBits 2
+#define splashFontFraction (1 << splashFontFractionBits)
+#define splashFontFractionMul \
+ ((SplashCoord)1 / (SplashCoord)splashFontFraction)
+
+//------------------------------------------------------------------------
+// SplashFont
+//------------------------------------------------------------------------
+
+class SplashFont {
+public:
+
+ SplashFont(SplashFontFile *fontFileA, SplashCoord *matA,
+ SplashCoord *textMatA, GBool aaA);
+
+ // This must be called after the constructor, so that the subclass
+ // constructor has a chance to compute the bbox.
+ void initCache();
+
+ virtual ~SplashFont();
+
+ SplashFontFile *getFontFile() { return fontFile; }
+
+ // Return true if <this> matches the specified font file and matrix.
+ GBool matches(SplashFontFile *fontFileA, SplashCoord *matA,
+ SplashCoord *textMatA) {
+ return fontFileA == fontFile &&
+ matA[0] == mat[0] && matA[1] == mat[1] &&
+ matA[2] == mat[2] && matA[3] == mat[3] &&
+ textMatA[0] == textMat[0] && textMatA[1] == textMat[1] &&
+ textMatA[2] == textMat[2] && textMatA[3] == textMat[3];
+ }
+
+ // Get a glyph - this does a cache lookup first, and if not found,
+ // creates a new bitmap and adds it to the cache. The <xFrac> and
+ // <yFrac> values are splashFontFractionBits bits each, representing
+ // the numerators of fractions in [0, 1), where the denominator is
+ // splashFontFraction = 1 << splashFontFractionBits. Subclasses
+ // should override this to zero out xFrac and/or yFrac if they don't
+ // support fractional coordinates.
+ virtual GBool getGlyph(int c, int xFrac, int yFrac,
+ SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes);
+
+ // Rasterize a glyph. The <xFrac> and <yFrac> values are the same
+ // as described for getGlyph.
+ virtual GBool makeGlyph(int c, int xFrac, int yFrac,
+ SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) = 0;
+
+ // Return the path for a glyph.
+ virtual SplashPath *getGlyphPath(int c) = 0;
+
+ // Return the font transform matrix.
+ SplashCoord *getMatrix() { return mat; }
+
+ // Return the glyph bounding box.
+ void getBBox(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA)
+ { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; }
+
+protected:
+
+ SplashFontFile *fontFile;
+ SplashCoord mat[4]; // font transform matrix
+ // (text space -> device space)
+ SplashCoord textMat[4]; // text transform matrix
+ // (text space -> user space)
+ GBool aa; // anti-aliasing
+ int xMin, yMin, xMax, yMax; // glyph bounding box
+ Guchar *cache; // glyph bitmap cache
+ SplashFontCacheTag * // cache tags
+ cacheTags;
+ int glyphW, glyphH; // size of glyph bitmaps
+ int glyphSize; // size of glyph bitmaps, in bytes
+ int cacheSets; // number of sets in cache
+ int cacheAssoc; // cache associativity (glyphs per set)
+};
+
+#endif
diff --git a/kpdf/xpdf/splash/SplashFontEngine.cc b/kpdf/xpdf/splash/SplashFontEngine.cc
new file mode 100644
index 00000000..4dc1b35b
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashFontEngine.cc
@@ -0,0 +1,295 @@
+//========================================================================
+//
+// SplashFontEngine.cc
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#if HAVE_T1LIB_H
+#include <t1lib.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#ifndef WIN32
+# include <unistd.h>
+#endif
+#include "gmem.h"
+#include "GString.h"
+#include "SplashMath.h"
+#include "SplashT1FontEngine.h"
+#include "SplashFTFontEngine.h"
+#include "SplashFontFile.h"
+#include "SplashFontFileID.h"
+#include "SplashFont.h"
+#include "SplashFontEngine.h"
+
+#ifdef VMS
+#if (__VMS_VER < 70000000)
+extern "C" int unlink(char *filename);
+#endif
+#endif
+
+//------------------------------------------------------------------------
+// SplashFontEngine
+//------------------------------------------------------------------------
+
+SplashFontEngine::SplashFontEngine(
+#if HAVE_T1LIB_H
+ GBool enableT1lib,
+#endif
+#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+ GBool enableFreeType,
+#endif
+ GBool aa) {
+ int i;
+
+ for (i = 0; i < splashFontCacheSize; ++i) {
+ fontCache[i] = NULL;
+ }
+
+#if HAVE_T1LIB_H
+ if (enableT1lib) {
+ t1Engine = SplashT1FontEngine::init(aa);
+ } else {
+ t1Engine = NULL;
+ }
+#endif
+#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+ if (enableFreeType) {
+ ftEngine = SplashFTFontEngine::init(aa);
+ } else {
+ ftEngine = NULL;
+ }
+#endif
+}
+
+SplashFontEngine::~SplashFontEngine() {
+ int i;
+
+ for (i = 0; i < splashFontCacheSize; ++i) {
+ if (fontCache[i]) {
+ delete fontCache[i];
+ }
+ }
+
+#if HAVE_T1LIB_H
+ if (t1Engine) {
+ delete t1Engine;
+ }
+#endif
+#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+ if (ftEngine) {
+ delete ftEngine;
+ }
+#endif
+}
+
+SplashFontFile *SplashFontEngine::getFontFile(SplashFontFileID *id) {
+ SplashFontFile *fontFile;
+ int i;
+
+ for (i = 0; i < splashFontCacheSize; ++i) {
+ if (fontCache[i]) {
+ fontFile = fontCache[i]->getFontFile();
+ if (fontFile && fontFile->getID()->matches(id)) {
+ return fontFile;
+ }
+ }
+ }
+ return NULL;
+}
+
+SplashFontFile *SplashFontEngine::loadType1Font(SplashFontFileID *idA,
+ SplashFontSrc *src,
+ char **enc) {
+ SplashFontFile *fontFile;
+
+ fontFile = NULL;
+#if HAVE_T1LIB_H
+ if (!fontFile && t1Engine) {
+ fontFile = t1Engine->loadType1Font(idA, src, enc);
+ }
+#endif
+#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+ if (!fontFile && ftEngine) {
+ fontFile = ftEngine->loadType1Font(idA, src, enc);
+ }
+#endif
+
+ // delete the (temporary) font file -- with Unix hard link
+ // semantics, this will remove the last link; otherwise it will
+ // return an error, leaving the file to be deleted later (if
+ // loadXYZFont failed, the file will always be deleted)
+ if (src->isFile)
+ src->unref();
+
+ return fontFile;
+}
+
+SplashFontFile *SplashFontEngine::loadType1CFont(SplashFontFileID *idA,
+ SplashFontSrc *src,
+ char **enc) {
+ SplashFontFile *fontFile;
+
+ fontFile = NULL;
+#if HAVE_T1LIB_H
+ if (!fontFile && t1Engine) {
+ fontFile = t1Engine->loadType1CFont(idA, sec, enc);
+ }
+#endif
+#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+ if (!fontFile && ftEngine) {
+ fontFile = ftEngine->loadType1CFont(idA, src, enc);
+ }
+#endif
+
+ // delete the (temporary) font file -- with Unix hard link
+ // semantics, this will remove the last link; otherwise it will
+ // return an error, leaving the file to be deleted later (if
+ // loadXYZFont failed, the file will always be deleted)
+ if (src->isFile)
+ src->unref();
+
+ return fontFile;
+}
+
+SplashFontFile *SplashFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA,
+ SplashFontSrc *src,
+ char **enc) {
+ SplashFontFile *fontFile;
+
+ fontFile = NULL;
+#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+ if (!fontFile && ftEngine) {
+ fontFile = ftEngine->loadOpenTypeT1CFont(idA, src, enc);
+ }
+#endif
+
+ // delete the (temporary) font file -- with Unix hard link
+ // semantics, this will remove the last link; otherwise it will
+ // return an error, leaving the file to be deleted later (if
+ // loadXYZFont failed, the file will always be deleted)
+ if (src->isFile)
+ src->unref();
+
+ return fontFile;
+}
+
+SplashFontFile *SplashFontEngine::loadCIDFont(SplashFontFileID *idA,
+ SplashFontSrc *src) {
+ SplashFontFile *fontFile;
+
+ fontFile = NULL;
+#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+ if (!fontFile && ftEngine) {
+ fontFile = ftEngine->loadCIDFont(idA, src);
+ }
+#endif
+
+ // delete the (temporary) font file -- with Unix hard link
+ // semantics, this will remove the last link; otherwise it will
+ // return an error, leaving the file to be deleted later (if
+ // loadXYZFont failed, the file will always be deleted)
+ if (src->isFile)
+ src->unref();
+
+ return fontFile;
+}
+
+SplashFontFile *SplashFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA,
+ SplashFontSrc *src) {
+ SplashFontFile *fontFile;
+
+ fontFile = NULL;
+#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+ if (!fontFile && ftEngine) {
+ fontFile = ftEngine->loadOpenTypeCFFFont(idA, src);
+ }
+#endif
+
+ // delete the (temporary) font file -- with Unix hard link
+ // semantics, this will remove the last link; otherwise it will
+ // return an error, leaving the file to be deleted later (if
+ // loadXYZFont failed, the file will always be deleted)
+ if (src->isFile)
+ src->unref();
+
+ return fontFile;
+}
+
+SplashFontFile *SplashFontEngine::loadTrueTypeFont(SplashFontFileID *idA,
+ SplashFontSrc *src,
+ Gushort *codeToGID,
+ int codeToGIDLen,
+ int faceIndex) {
+ SplashFontFile *fontFile;
+
+ fontFile = NULL;
+#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+ if (!fontFile && ftEngine) {
+ fontFile = ftEngine->loadTrueTypeFont(idA, src,
+ codeToGID, codeToGIDLen, faceIndex);
+ }
+#endif
+
+ if (!fontFile) {
+ gfree(codeToGID);
+ }
+
+ // delete the (temporary) font file -- with Unix hard link
+ // semantics, this will remove the last link; otherwise it will
+ // return an error, leaving the file to be deleted later (if
+ // loadXYZFont failed, the file will always be deleted)
+ if (src->isFile)
+ src->unref();
+
+ return fontFile;
+}
+
+SplashFont *SplashFontEngine::getFont(SplashFontFile *fontFile,
+ SplashCoord *textMat,
+ SplashCoord *ctm) {
+ SplashCoord mat[4];
+ SplashFont *font;
+ int i, j;
+
+ mat[0] = textMat[0] * ctm[0] + textMat[1] * ctm[2];
+ mat[1] = -(textMat[0] * ctm[1] + textMat[1] * ctm[3]);
+ mat[2] = textMat[2] * ctm[0] + textMat[3] * ctm[2];
+ mat[3] = -(textMat[2] * ctm[1] + textMat[3] * ctm[3]);
+ if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.01) {
+ // avoid a singular (or close-to-singular) matrix
+ mat[0] = 0.01; mat[1] = 0;
+ mat[2] = 0; mat[3] = 0.01;
+ }
+
+ font = fontCache[0];
+ if (font && font->matches(fontFile, mat, textMat)) {
+ return font;
+ }
+ for (i = 1; i < splashFontCacheSize; ++i) {
+ font = fontCache[i];
+ if (font && font->matches(fontFile, mat, textMat)) {
+ for (j = i; j > 0; --j) {
+ fontCache[j] = fontCache[j-1];
+ }
+ fontCache[0] = font;
+ return font;
+ }
+ }
+ font = fontFile->makeFont(mat, textMat);
+ if (fontCache[splashFontCacheSize - 1]) {
+ delete fontCache[splashFontCacheSize - 1];
+ }
+ for (j = splashFontCacheSize - 1; j > 0; --j) {
+ fontCache[j] = fontCache[j-1];
+ }
+ fontCache[0] = font;
+ return font;
+}
diff --git a/kpdf/xpdf/splash/SplashFontEngine.h b/kpdf/xpdf/splash/SplashFontEngine.h
new file mode 100644
index 00000000..ace5e9ae
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashFontEngine.h
@@ -0,0 +1,86 @@
+//========================================================================
+//
+// SplashFontEngine.h
+//
+//========================================================================
+
+#ifndef SPLASHFONTENGINE_H
+#define SPLASHFONTENGINE_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+
+class SplashT1FontEngine;
+class SplashFTFontEngine;
+class SplashDTFontEngine;
+class SplashDT4FontEngine;
+class SplashFontFile;
+class SplashFontFileID;
+class SplashFont;
+class SplashFontSrc;
+
+//------------------------------------------------------------------------
+
+#define splashFontCacheSize 16
+
+//------------------------------------------------------------------------
+// SplashFontEngine
+//------------------------------------------------------------------------
+
+class SplashFontEngine {
+public:
+
+ // Create a font engine.
+ SplashFontEngine(
+#if HAVE_T1LIB_H
+ GBool enableT1lib,
+#endif
+#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+ GBool enableFreeType,
+#endif
+ GBool aa);
+
+ ~SplashFontEngine();
+
+ // Get a font file from the cache. Returns NULL if there is no
+ // matching entry in the cache.
+ SplashFontFile *getFontFile(SplashFontFileID *id);
+
+ // Load fonts - these create new SplashFontFile objects.
+ SplashFontFile *loadType1Font(SplashFontFileID *idA, SplashFontSrc *src, char **enc);
+ SplashFontFile *loadType1CFont(SplashFontFileID *idA, SplashFontSrc *src, char **enc);
+ SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA, SplashFontSrc *src, char **enc);
+ SplashFontFile *loadCIDFont(SplashFontFileID *idA, SplashFontSrc *src);
+ SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, SplashFontSrc *src);
+ SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, SplashFontSrc *src,
+ Gushort *codeToGID, int codeToGIDLen, int faceIndex = 0);
+
+ // Get a font - this does a cache lookup first, and if not found,
+ // creates a new SplashFont object and adds it to the cache. The
+ // matrix, mat = textMat * ctm:
+ // [ mat[0] mat[1] ]
+ // [ mat[2] mat[3] ]
+ // specifies the font transform in PostScript style:
+ // [x' y'] = [x y] * mat
+ // Note that the Splash y axis points downward.
+ SplashFont *getFont(SplashFontFile *fontFile,
+ SplashCoord *textMat, SplashCoord *ctm);
+
+private:
+
+ SplashFont *fontCache[splashFontCacheSize];
+
+#if HAVE_T1LIB_H
+ SplashT1FontEngine *t1Engine;
+#endif
+#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+ SplashFTFontEngine *ftEngine;
+#endif
+};
+
+#endif
diff --git a/kpdf/xpdf/splash/SplashFontFile.cc b/kpdf/xpdf/splash/SplashFontFile.cc
new file mode 100644
index 00000000..ad58c22d
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashFontFile.cc
@@ -0,0 +1,108 @@
+//========================================================================
+//
+// SplashFontFile.cc
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#ifndef WIN32
+# include <unistd.h>
+#endif
+#include "gmem.h"
+#include "GString.h"
+#include "SplashFontFile.h"
+#include "SplashFontFileID.h"
+
+#ifdef VMS
+#if (__VMS_VER < 70000000)
+extern "C" int unlink(char *filename);
+#endif
+#endif
+
+//------------------------------------------------------------------------
+// SplashFontFile
+//------------------------------------------------------------------------
+
+SplashFontFile::SplashFontFile(SplashFontFileID *idA, SplashFontSrc *srcA) {
+ id = idA;
+ src = srcA;
+ src->ref();
+ refCnt = 0;
+}
+
+SplashFontFile::~SplashFontFile() {
+ src->unref();
+ delete id;
+}
+
+void SplashFontFile::incRefCnt() {
+ ++refCnt;
+}
+
+void SplashFontFile::decRefCnt() {
+ if (!--refCnt) {
+ delete this;
+ }
+}
+
+//
+
+SplashFontSrc::SplashFontSrc() {
+ isFile = gFalse;
+ deleteSrc = gFalse;
+ fileName = NULL;
+ buf = NULL;
+ refcnt = 1;
+}
+
+SplashFontSrc::~SplashFontSrc() {
+ if (deleteSrc) {
+ if (isFile) {
+ if (fileName)
+ unlink(fileName->getCString());
+ } else {
+ if (buf)
+ gfree(buf);
+ }
+ }
+
+ if (isFile && fileName)
+ delete fileName;
+}
+
+void SplashFontSrc::ref() {
+ refcnt++;
+}
+
+void SplashFontSrc::unref() {
+ if (! --refcnt)
+ delete this;
+}
+
+void SplashFontSrc::setFile(GString *file, GBool del)
+{
+ isFile = gTrue;
+ fileName = file->copy();
+ deleteSrc = del;
+}
+
+void SplashFontSrc::setFile(const char *file, GBool del)
+{
+ isFile = gTrue;
+ fileName = new GString(file);
+ deleteSrc = del;
+}
+
+void SplashFontSrc::setBuf(char *bufA, int bufLenA, GBool del)
+{
+ isFile = gFalse;
+ buf = bufA;
+ bufLen = bufLenA;
+ deleteSrc = del;
+}
diff --git a/kpdf/xpdf/splash/SplashFontFile.h b/kpdf/xpdf/splash/SplashFontFile.h
new file mode 100644
index 00000000..698d620c
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashFontFile.h
@@ -0,0 +1,77 @@
+//========================================================================
+//
+// SplashFontFile.h
+//
+//========================================================================
+
+#ifndef SPLASHFONTFILE_H
+#define SPLASHFONTFILE_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "SplashTypes.h"
+
+class GString;
+class SplashFontEngine;
+class SplashFont;
+class SplashFontFileID;
+
+//------------------------------------------------------------------------
+// SplashFontFile
+//------------------------------------------------------------------------
+
+struct SplashFontSrc {
+ SplashFontSrc();
+ ~SplashFontSrc();
+
+ void setFile(GString *file, GBool del);
+ void setFile(const char *file, GBool del);
+ void setBuf(char *bufA, int buflenA, GBool del);
+
+ void ref();
+ void unref();
+
+ GBool isFile;
+ GString *fileName;
+ char *buf;
+ int bufLen;
+ GBool deleteSrc;
+ int refcnt;
+};
+
+class SplashFontFile {
+public:
+
+ virtual ~SplashFontFile();
+
+ // Create a new SplashFont, i.e., a scaled instance of this font
+ // file.
+ virtual SplashFont *makeFont(SplashCoord *mat, SplashCoord *textMat) = 0;
+
+ // Get the font file ID.
+ SplashFontFileID *getID() { return id; }
+
+ // Increment the reference count.
+ void incRefCnt();
+
+ // Decrement the reference count. If the new value is zero, delete
+ // the SplashFontFile object.
+ void decRefCnt();
+
+protected:
+
+ SplashFontFile(SplashFontFileID *idA, SplashFontSrc *srcA);
+
+ SplashFontFileID *id;
+ SplashFontSrc *src;
+ int refCnt;
+
+ friend class SplashFontEngine;
+};
+
+#endif
diff --git a/kpdf/xpdf/splash/SplashFontFileID.cc b/kpdf/xpdf/splash/SplashFontFileID.cc
new file mode 100644
index 00000000..af37cb2f
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashFontFileID.cc
@@ -0,0 +1,23 @@
+//========================================================================
+//
+// SplashFontFileID.cc
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "SplashFontFileID.h"
+
+//------------------------------------------------------------------------
+// SplashFontFileID
+//------------------------------------------------------------------------
+
+SplashFontFileID::SplashFontFileID() {
+}
+
+SplashFontFileID::~SplashFontFileID() {
+}
diff --git a/kpdf/xpdf/splash/SplashFontFileID.h b/kpdf/xpdf/splash/SplashFontFileID.h
new file mode 100644
index 00000000..bed11d33
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashFontFileID.h
@@ -0,0 +1,30 @@
+//========================================================================
+//
+// SplashFontFileID.h
+//
+//========================================================================
+
+#ifndef SPLASHFONTFILEID_H
+#define SPLASHFONTFILEID_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+
+//------------------------------------------------------------------------
+// SplashFontFileID
+//------------------------------------------------------------------------
+
+class SplashFontFileID {
+public:
+
+ SplashFontFileID();
+ virtual ~SplashFontFileID();
+ virtual GBool matches(SplashFontFileID *id) = 0;
+};
+
+#endif
diff --git a/kpdf/xpdf/splash/SplashGlyphBitmap.h b/kpdf/xpdf/splash/SplashGlyphBitmap.h
new file mode 100644
index 00000000..044ba4a6
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashGlyphBitmap.h
@@ -0,0 +1,26 @@
+//========================================================================
+//
+// SplashGlyphBitmap.h
+//
+//========================================================================
+
+#ifndef SPLASHGLYPHBITMAP_H
+#define SPLASHGLYPHBITMAP_H
+
+#include <aconf.h>
+
+#include "gtypes.h"
+
+//------------------------------------------------------------------------
+// SplashGlyphBitmap
+//------------------------------------------------------------------------
+
+struct SplashGlyphBitmap {
+ int x, y, w, h; // offset and size of glyph
+ GBool aa; // anti-aliased: true means 8-bit alpha
+ // bitmap; false means 1-bit
+ Guchar *data; // bitmap data
+ GBool freeData; // true if data memory should be freed
+};
+
+#endif
diff --git a/kpdf/xpdf/splash/SplashMath.h b/kpdf/xpdf/splash/SplashMath.h
new file mode 100644
index 00000000..12e0eec1
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashMath.h
@@ -0,0 +1,89 @@
+//========================================================================
+//
+// SplashMath.h
+//
+//========================================================================
+
+#ifndef SPLASHMATH_H
+#define SPLASHMATH_H
+
+#include <aconf.h>
+#if USE_FIXEDPOINT
+#include "FixedPoint.h"
+#else
+#include <math.h>
+#endif
+#include "SplashTypes.h"
+
+static inline SplashCoord splashAbs(SplashCoord x) {
+#if USE_FIXEDPOINT
+ return FixedPoint::abs(x);
+#else
+ return fabs(x);
+#endif
+}
+
+static inline int splashFloor(SplashCoord x) {
+#if USE_FIXEDPOINT
+ return FixedPoint::floor(x);
+#else
+ return (int)floor(x);
+#endif
+}
+
+static inline int splashCeil(SplashCoord x) {
+#if USE_FIXEDPOINT
+ return FixedPoint::ceil(x);
+#else
+ return (int)ceil(x);
+#endif
+}
+
+static inline int splashRound(SplashCoord x) {
+#if USE_FIXEDPOINT
+ return FixedPoint::round(x);
+#else
+ return (int)floor(x + 0.5);
+#endif
+}
+
+static inline SplashCoord splashSqrt(SplashCoord x) {
+#if USE_FIXEDPOINT
+ return FixedPoint::sqrt(x);
+#else
+ return sqrt(x);
+#endif
+}
+
+static inline SplashCoord splashPow(SplashCoord x, SplashCoord y) {
+#if USE_FIXEDPOINT
+ return FixedPoint::pow(x, y);
+#else
+ return pow(x, y);
+#endif
+}
+
+static inline SplashCoord splashDist(SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1) {
+ SplashCoord dx, dy;
+ dx = x1 - x0;
+ dy = y1 - y0;
+#if USE_FIXEDPOINT
+ // this handles the situation where dx*dx or dy*dy is too large to
+ // fit in the 16.16 fixed point format
+ SplashCoord dxa, dya;
+ dxa = splashAbs(dx);
+ dya = splashAbs(dy);
+ if (dxa == 0 && dya == 0) {
+ return 0;
+ } else if (dxa > dya) {
+ return dxa * FixedPoint::sqrt(dya / dxa + 1);
+ } else {
+ return dya * FixedPoint::sqrt(dxa / dya + 1);
+ }
+#else
+ return sqrt(dx * dx + dy * dy);
+#endif
+}
+
+#endif
diff --git a/kpdf/xpdf/splash/SplashPath.cc b/kpdf/xpdf/splash/SplashPath.cc
new file mode 100644
index 00000000..e3a89271
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashPath.cc
@@ -0,0 +1,184 @@
+//========================================================================
+//
+// SplashPath.cc
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <string.h>
+#include "gmem.h"
+#include "SplashErrorCodes.h"
+#include "SplashPath.h"
+
+//------------------------------------------------------------------------
+// SplashPath
+//------------------------------------------------------------------------
+
+// A path can be in three possible states:
+//
+// 1. no current point -- zero or more finished subpaths
+// [curSubpath == length]
+//
+// 2. one point in subpath
+// [curSubpath == length - 1]
+//
+// 3. open subpath with two or more points
+// [curSubpath < length - 1]
+
+SplashPath::SplashPath() {
+ pts = NULL;
+ flags = NULL;
+ length = size = 0;
+ curSubpath = 0;
+ hints = NULL;
+ hintsLength = hintsSize = 0;
+}
+
+SplashPath::SplashPath(SplashPath *path) {
+ length = path->length;
+ size = path->size;
+ pts = (SplashPathPoint *)gmallocn(size, sizeof(SplashPathPoint));
+ flags = (Guchar *)gmallocn(size, sizeof(Guchar));
+ memcpy(pts, path->pts, length * sizeof(SplashPathPoint));
+ memcpy(flags, path->flags, length * sizeof(Guchar));
+ curSubpath = path->curSubpath;
+ if (path->hints) {
+ hintsLength = hintsSize = path->hintsLength;
+ hints = (SplashPathHint *)gmallocn(hintsSize, sizeof(SplashPathHint));
+ memcpy(hints, path->hints, hintsLength * sizeof(SplashPathHint));
+ } else {
+ hints = NULL;
+ }
+}
+
+SplashPath::~SplashPath() {
+ gfree(pts);
+ gfree(flags);
+ gfree(hints);
+}
+
+// Add space for <nPts> more points.
+void SplashPath::grow(int nPts) {
+ if (length + nPts > size) {
+ if (size == 0) {
+ size = 32;
+ }
+ while (size < length + nPts) {
+ size *= 2;
+ }
+ pts = (SplashPathPoint *)greallocn(pts, size, sizeof(SplashPathPoint));
+ flags = (Guchar *)greallocn(flags, size, sizeof(Guchar));
+ }
+}
+
+void SplashPath::append(SplashPath *path) {
+ int i;
+
+ curSubpath = length + path->curSubpath;
+ grow(path->length);
+ for (i = 0; i < path->length; ++i) {
+ pts[length] = path->pts[i];
+ flags[length] = path->flags[i];
+ ++length;
+ }
+}
+
+SplashError SplashPath::moveTo(SplashCoord x, SplashCoord y) {
+ if (onePointSubpath()) {
+ return splashErrBogusPath;
+ }
+ grow(1);
+ pts[length].x = x;
+ pts[length].y = y;
+ flags[length] = splashPathFirst | splashPathLast;
+ curSubpath = length++;
+ return splashOk;
+}
+
+SplashError SplashPath::lineTo(SplashCoord x, SplashCoord y) {
+ if (noCurrentPoint()) {
+ return splashErrNoCurPt;
+ }
+ flags[length-1] &= ~splashPathLast;
+ grow(1);
+ pts[length].x = x;
+ pts[length].y = y;
+ flags[length] = splashPathLast;
+ ++length;
+ return splashOk;
+}
+
+SplashError SplashPath::curveTo(SplashCoord x1, SplashCoord y1,
+ SplashCoord x2, SplashCoord y2,
+ SplashCoord x3, SplashCoord y3) {
+ if (noCurrentPoint()) {
+ return splashErrNoCurPt;
+ }
+ flags[length-1] &= ~splashPathLast;
+ grow(3);
+ pts[length].x = x1;
+ pts[length].y = y1;
+ flags[length] = splashPathCurve;
+ ++length;
+ pts[length].x = x2;
+ pts[length].y = y2;
+ flags[length] = splashPathCurve;
+ ++length;
+ pts[length].x = x3;
+ pts[length].y = y3;
+ flags[length] = splashPathLast;
+ ++length;
+ return splashOk;
+}
+
+SplashError SplashPath::close() {
+ if (noCurrentPoint()) {
+ return splashErrNoCurPt;
+ }
+ if (curSubpath == length - 1 ||
+ pts[length - 1].x != pts[curSubpath].x ||
+ pts[length - 1].y != pts[curSubpath].y) {
+ lineTo(pts[curSubpath].x, pts[curSubpath].y);
+ }
+ flags[curSubpath] |= splashPathClosed;
+ flags[length - 1] |= splashPathClosed;
+ curSubpath = length;
+ return splashOk;
+}
+
+void SplashPath::addStrokeAdjustHint(int ctrl0, int ctrl1,
+ int firstPt, int lastPt) {
+ if (hintsLength == hintsSize) {
+ hintsSize = hintsLength ? 2 * hintsLength : 8;
+ hints = (SplashPathHint *)greallocn(hints, hintsSize,
+ sizeof(SplashPathHint));
+ }
+ hints[hintsLength].ctrl0 = ctrl0;
+ hints[hintsLength].ctrl1 = ctrl1;
+ hints[hintsLength].firstPt = firstPt;
+ hints[hintsLength].lastPt = lastPt;
+ ++hintsLength;
+}
+
+void SplashPath::offset(SplashCoord dx, SplashCoord dy) {
+ int i;
+
+ for (i = 0; i < length; ++i) {
+ pts[i].x += dx;
+ pts[i].y += dy;
+ }
+}
+
+GBool SplashPath::getCurPt(SplashCoord *x, SplashCoord *y) {
+ if (noCurrentPoint()) {
+ return gFalse;
+ }
+ *x = pts[length - 1].x;
+ *y = pts[length - 1].y;
+ return gTrue;
+}
diff --git a/kpdf/xpdf/splash/SplashPath.h b/kpdf/xpdf/splash/SplashPath.h
new file mode 100644
index 00000000..b63ee5df
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashPath.h
@@ -0,0 +1,121 @@
+//========================================================================
+//
+// SplashPath.h
+//
+//========================================================================
+
+#ifndef SPLASHPATH_H
+#define SPLASHPATH_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "SplashTypes.h"
+
+//------------------------------------------------------------------------
+// SplashPathPoint
+//------------------------------------------------------------------------
+
+struct SplashPathPoint {
+ SplashCoord x, y;
+};
+
+//------------------------------------------------------------------------
+// SplashPath.flags
+//------------------------------------------------------------------------
+
+// first point on each subpath sets this flag
+#define splashPathFirst 0x01
+
+// last point on each subpath sets this flag
+#define splashPathLast 0x02
+
+// if the subpath is closed, its first and last points must be
+// identical, and must set this flag
+#define splashPathClosed 0x04
+
+// curve control points set this flag
+#define splashPathCurve 0x08
+
+//------------------------------------------------------------------------
+// SplashPathHint
+//------------------------------------------------------------------------
+
+struct SplashPathHint {
+ int ctrl0, ctrl1;
+ int firstPt, lastPt;
+};
+
+//------------------------------------------------------------------------
+// SplashPath
+//------------------------------------------------------------------------
+
+class SplashPath {
+public:
+
+ // Create an empty path.
+ SplashPath();
+
+ // Copy a path.
+ SplashPath *copy() { return new SplashPath(this); }
+
+ ~SplashPath();
+
+ // Append <path> to <this>.
+ void append(SplashPath *path);
+
+ // Start a new subpath.
+ SplashError moveTo(SplashCoord x, SplashCoord y);
+
+ // Add a line segment to the last subpath.
+ SplashError lineTo(SplashCoord x, SplashCoord y);
+
+ // Add a third-order (cubic) Bezier curve segment to the last
+ // subpath.
+ SplashError curveTo(SplashCoord x1, SplashCoord y1,
+ SplashCoord x2, SplashCoord y2,
+ SplashCoord x3, SplashCoord y3);
+
+ // Close the last subpath, adding a line segment if necessary.
+ SplashError close();
+
+ // Add a stroke adjustment hint. The controlling segments are
+ // <ctrl0> and <ctrl1> (where segments are identified by their first
+ // point), and the points to be adjusted are <firstPt> .. <lastPt>.
+ void addStrokeAdjustHint(int ctrl0, int ctrl1, int firstPt, int lastPt);
+
+ // Add (<dx>, <dy>) to every point on this path.
+ void offset(SplashCoord dx, SplashCoord dy);
+
+ // Get the points on the path.
+ int getLength() { return length; }
+ void getPoint(int i, double *x, double *y, Guchar *f)
+ { *x = pts[i].x; *y = pts[i].y; *f = flags[i]; }
+
+ // Get the current point.
+ GBool getCurPt(SplashCoord *x, SplashCoord *y);
+
+private:
+
+ SplashPath(SplashPath *path);
+ void grow(int nPts);
+ GBool noCurrentPoint() { return curSubpath == length; }
+ GBool onePointSubpath() { return curSubpath == length - 1; }
+ GBool openSubpath() { return curSubpath < length - 1; }
+
+ SplashPathPoint *pts; // array of points
+ Guchar *flags; // array of flags
+ int length, size; // length/size of the pts and flags arrays
+ int curSubpath; // index of first point in last subpath
+
+ SplashPathHint *hints; // list of hints
+ int hintsLength, hintsSize;
+
+ friend class SplashXPath;
+ friend class Splash;
+};
+
+#endif
diff --git a/kpdf/xpdf/splash/SplashPattern.cc b/kpdf/xpdf/splash/SplashPattern.cc
new file mode 100644
index 00000000..e6a37852
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashPattern.cc
@@ -0,0 +1,40 @@
+//========================================================================
+//
+// SplashPattern.cc
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "SplashMath.h"
+#include "SplashScreen.h"
+#include "SplashPattern.h"
+
+//------------------------------------------------------------------------
+// SplashPattern
+//------------------------------------------------------------------------
+
+SplashPattern::SplashPattern() {
+}
+
+SplashPattern::~SplashPattern() {
+}
+
+//------------------------------------------------------------------------
+// SplashSolidColor
+//------------------------------------------------------------------------
+
+SplashSolidColor::SplashSolidColor(SplashColorPtr colorA) {
+ splashColorCopy(color, colorA);
+}
+
+SplashSolidColor::~SplashSolidColor() {
+}
+
+void SplashSolidColor::getColor(int /*x*/, int /*y*/, SplashColorPtr c) {
+ splashColorCopy(c, color);
+}
diff --git a/kpdf/xpdf/splash/SplashPattern.h b/kpdf/xpdf/splash/SplashPattern.h
new file mode 100644
index 00000000..0a02e9c2
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashPattern.h
@@ -0,0 +1,65 @@
+//========================================================================
+//
+// SplashPattern.h
+//
+//========================================================================
+
+#ifndef SPLASHPATTERN_H
+#define SPLASHPATTERN_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "SplashTypes.h"
+
+class SplashScreen;
+
+//------------------------------------------------------------------------
+// SplashPattern
+//------------------------------------------------------------------------
+
+class SplashPattern {
+public:
+
+ SplashPattern();
+
+ virtual SplashPattern *copy() = 0;
+
+ virtual ~SplashPattern();
+
+ // Return the color value for a specific pixel.
+ virtual void getColor(int x, int y, SplashColorPtr c) = 0;
+
+ // Returns true if this pattern object will return the same color
+ // value for all pixels.
+ virtual GBool isStatic() = 0;
+
+private:
+};
+
+//------------------------------------------------------------------------
+// SplashSolidColor
+//------------------------------------------------------------------------
+
+class SplashSolidColor: public SplashPattern {
+public:
+
+ SplashSolidColor(SplashColorPtr colorA);
+
+ virtual SplashPattern *copy() { return new SplashSolidColor(color); }
+
+ virtual ~SplashSolidColor();
+
+ virtual void getColor(int x, int y, SplashColorPtr c);
+
+ virtual GBool isStatic() { return gTrue; }
+
+private:
+
+ SplashColor color;
+};
+
+#endif
diff --git a/kpdf/xpdf/splash/SplashScreen.cc b/kpdf/xpdf/splash/SplashScreen.cc
new file mode 100644
index 00000000..3e8d36ca
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashScreen.cc
@@ -0,0 +1,385 @@
+//========================================================================
+//
+// SplashScreen.cc
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include "gmem.h"
+#include "SplashMath.h"
+#include "SplashScreen.h"
+
+//------------------------------------------------------------------------
+
+static SplashScreenParams defaultParams = {
+ splashScreenDispersed, // type
+ 2, // size
+ 2, // dotRadius
+ 1.0, // gamma
+ 0.0, // blackThreshold
+ 1.0 // whiteThreshold
+};
+
+//------------------------------------------------------------------------
+
+struct SplashScreenPoint {
+ int x, y;
+ int dist;
+};
+
+static int cmpDistances(const void *p0, const void *p1) {
+ return ((SplashScreenPoint *)p0)->dist - ((SplashScreenPoint *)p1)->dist;
+}
+
+//------------------------------------------------------------------------
+// SplashScreen
+//------------------------------------------------------------------------
+
+// If <clustered> is true, this generates a 45 degree screen using a
+// circular dot spot function. DPI = resolution / ((size / 2) *
+// sqrt(2)). If <clustered> is false, this generates an optimal
+// threshold matrix using recursive tesselation. Gamma correction
+// (gamma = 1 / 1.33) is also computed here.
+SplashScreen::SplashScreen(SplashScreenParams *params) {
+ Guchar u, black, white;
+ int i;
+
+ if (!params) {
+ params = &defaultParams;
+ }
+
+ switch (params->type) {
+
+ case splashScreenDispersed:
+ // size must be a power of 2
+ for (size = 1; size < params->size; size <<= 1) ;
+ mat = (Guchar *)gmallocn(size * size, sizeof(Guchar));
+ buildDispersedMatrix(size/2, size/2, 1, size/2, 1);
+ break;
+
+ case splashScreenClustered:
+ // size must be even
+ size = (params->size >> 1) << 1;
+ if (size < 2) {
+ size = 2;
+ }
+ mat = (Guchar *)gmallocn(size * size, sizeof(Guchar));
+ buildClusteredMatrix();
+ break;
+
+ case splashScreenStochasticClustered:
+ // size must be at least 2*r
+ if (params->size < 2 * params->dotRadius) {
+ size = 2 * params->dotRadius;
+ } else {
+ size = params->size;
+ }
+ mat = (Guchar *)gmallocn(size * size, sizeof(Guchar));
+ buildSCDMatrix(params->dotRadius);
+ break;
+ }
+
+ // do gamma correction and compute minVal/maxVal
+ minVal = 255;
+ maxVal = 0;
+ black = splashRound((SplashCoord)255.0 * params->blackThreshold);
+ if (black < 1) {
+ black = 1;
+ }
+ int whiteAux = splashRound((SplashCoord)255.0 * params->whiteThreshold);
+ if (whiteAux > 255) {
+ white = 255;
+ } else {
+ white = whiteAux;
+ }
+ for (i = 0; i < size * size; ++i) {
+ u = splashRound((SplashCoord)255.0 *
+ splashPow((SplashCoord)mat[i] / 255.0, params->gamma));
+ if (u < black) {
+ u = black;
+ } else if (u >= white) {
+ u = white;
+ }
+ mat[i] = u;
+ if (u < minVal) {
+ minVal = u;
+ } else if (u > maxVal) {
+ maxVal = u;
+ }
+ }
+}
+
+void SplashScreen::buildDispersedMatrix(int i, int j, int val,
+ int delta, int offset) {
+ if (delta == 0) {
+ // map values in [1, size^2] --> [1, 255]
+ mat[i * size + j] = 1 + (254 * (val - 1)) / (size * size - 1);
+ } else {
+ buildDispersedMatrix(i, j,
+ val, delta / 2, 4*offset);
+ buildDispersedMatrix((i + delta) % size, (j + delta) % size,
+ val + offset, delta / 2, 4*offset);
+ buildDispersedMatrix((i + delta) % size, j,
+ val + 2*offset, delta / 2, 4*offset);
+ buildDispersedMatrix((i + 2*delta) % size, (j + delta) % size,
+ val + 3*offset, delta / 2, 4*offset);
+ }
+}
+
+void SplashScreen::buildClusteredMatrix() {
+ SplashCoord *dist;
+ SplashCoord u, v, d;
+ Guchar val;
+ int size2, x, y, x1, y1, i;
+
+ size2 = size >> 1;
+
+ // initialize the threshold matrix
+ for (y = 0; y < size; ++y) {
+ for (x = 0; x < size; ++x) {
+ mat[y * size + x] = 0;
+ }
+ }
+
+ // build the distance matrix
+ dist = (SplashCoord *)gmallocn(size * size2, sizeof(SplashCoord));
+ for (y = 0; y < size2; ++y) {
+ for (x = 0; x < size2; ++x) {
+ if (x + y < size2 - 1) {
+ u = (SplashCoord)x + 0.5 - 0;
+ v = (SplashCoord)y + 0.5 - 0;
+ } else {
+ u = (SplashCoord)x + 0.5 - (SplashCoord)size2;
+ v = (SplashCoord)y + 0.5 - (SplashCoord)size2;
+ }
+ dist[y * size2 + x] = u*u + v*v;
+ }
+ }
+ for (y = 0; y < size2; ++y) {
+ for (x = 0; x < size2; ++x) {
+ if (x < y) {
+ u = (SplashCoord)x + 0.5 - 0;
+ v = (SplashCoord)y + 0.5 - (SplashCoord)size2;
+ } else {
+ u = (SplashCoord)x + 0.5 - (SplashCoord)size2;
+ v = (SplashCoord)y + 0.5 - 0;
+ }
+ dist[(size2 + y) * size2 + x] = u*u + v*v;
+ }
+ }
+
+ // build the threshold matrix
+ minVal = 1;
+ maxVal = 0;
+ x1 = y1 = 0; // make gcc happy
+ for (i = 0; i < size * size2; ++i) {
+ d = -1;
+ for (y = 0; y < size; ++y) {
+ for (x = 0; x < size2; ++x) {
+ if (mat[y * size + x] == 0 &&
+ dist[y * size2 + x] > d) {
+ x1 = x;
+ y1 = y;
+ d = dist[y1 * size2 + x1];
+ }
+ }
+ }
+ // map values in [0, 2*size*size2-1] --> [1, 255]
+ val = 1 + (254 * (2*i)) / (2*size*size2 - 1);
+ mat[y1 * size + x1] = val;
+ val = 1 + (254 * (2*i+1)) / (2*size*size2 - 1);
+ if (y1 < size2) {
+ mat[(y1 + size2) * size + x1 + size2] = val;
+ } else {
+ mat[(y1 - size2) * size + x1 + size2] = val;
+ }
+ }
+
+ gfree(dist);
+}
+
+// Compute the distance between two points on a toroid.
+int SplashScreen::distance(int x0, int y0, int x1, int y1) {
+ int dx0, dx1, dx, dy0, dy1, dy;
+
+ dx0 = abs(x0 - x1);
+ dx1 = size - dx0;
+ dx = dx0 < dx1 ? dx0 : dx1;
+ dy0 = abs(y0 - y1);
+ dy1 = size - dy0;
+ dy = dy0 < dy1 ? dy0 : dy1;
+ return dx * dx + dy * dy;
+}
+
+// Algorithm taken from:
+// Victor Ostromoukhov and Roger D. Hersch, "Stochastic Clustered-Dot
+// Dithering" in Color Imaging: Device-Independent Color, Color
+// Hardcopy, and Graphic Arts IV, SPIE Vol. 3648, pp. 496-505, 1999.
+void SplashScreen::buildSCDMatrix(int r) {
+ SplashScreenPoint *dots, *pts;
+ int dotsLen, dotsSize;
+ char *tmpl;
+ char *grid;
+ int *region, *dist;
+ int x, y, xx, yy, x0, x1, y0, y1, i, j, d, iMin, dMin, n;
+
+ //~ this should probably happen somewhere else
+ srand(123);
+
+ // generate the random space-filling curve
+ pts = (SplashScreenPoint *)gmallocn(size * size, sizeof(SplashScreenPoint));
+ i = 0;
+ for (y = 0; y < size; ++y) {
+ for (x = 0; x < size; ++x) {
+ pts[i].x = x;
+ pts[i].y = y;
+ ++i;
+ }
+ }
+ for (i = 0; i < size * size; ++i) {
+ j = i + (int)((double)(size * size - i) *
+ (double)rand() / ((double)RAND_MAX + 1.0));
+ x = pts[i].x;
+ y = pts[i].y;
+ pts[i].x = pts[j].x;
+ pts[i].y = pts[j].y;
+ pts[j].x = x;
+ pts[j].y = y;
+ }
+
+ // construct the circle template
+ tmpl = (char *)gmallocn((r+1)*(r+1), sizeof(char));
+ for (y = 0; y <= r; ++y) {
+ for (x = 0; x <= r; ++x) {
+ tmpl[y*(r+1) + x] = (x * y <= r * r) ? 1 : 0;
+ }
+ }
+
+ // mark all grid cells as free
+ grid = (char *)gmallocn(size * size, sizeof(char));
+ for (y = 0; y < size; ++y) {
+ for (x = 0; x < size; ++x) {
+ grid[y*size + x] = 0;
+ }
+ }
+
+ // walk the space-filling curve, adding dots
+ dotsLen = 0;
+ dotsSize = 32;
+ dots = (SplashScreenPoint *)gmallocn(dotsSize, sizeof(SplashScreenPoint));
+ for (i = 0; i < size * size; ++i) {
+ x = pts[i].x;
+ y = pts[i].y;
+ if (!grid[y*size + x]) {
+ if (dotsLen == dotsSize) {
+ dotsSize *= 2;
+ dots = (SplashScreenPoint *)greallocn(dots, dotsSize,
+ sizeof(SplashScreenPoint));
+ }
+ dots[dotsLen++] = pts[i];
+ for (yy = 0; yy <= r; ++yy) {
+ y0 = (y + yy) % size;
+ y1 = (y - yy + size) % size;
+ for (xx = 0; xx <= r; ++xx) {
+ if (tmpl[yy*(r+1) + xx]) {
+ x0 = (x + xx) % size;
+ x1 = (x - xx + size) % size;
+ grid[y0*size + x0] = 1;
+ grid[y0*size + x1] = 1;
+ grid[y1*size + x0] = 1;
+ grid[y1*size + x1] = 1;
+ }
+ }
+ }
+ }
+ }
+
+ gfree(tmpl);
+ gfree(grid);
+
+ // assign each cell to a dot, compute distance to center of dot
+ region = (int *)gmallocn(size * size, sizeof(int));
+ dist = (int *)gmallocn(size * size, sizeof(int));
+ for (y = 0; y < size; ++y) {
+ for (x = 0; x < size; ++x) {
+ iMin = 0;
+ dMin = distance(dots[0].x, dots[0].y, x, y);
+ for (i = 1; i < dotsLen; ++i) {
+ d = distance(dots[i].x, dots[i].y, x, y);
+ if (d < dMin) {
+ iMin = i;
+ dMin = d;
+ }
+ }
+ region[y*size + x] = iMin;
+ dist[y*size + x] = dMin;
+ }
+ }
+
+ // compute threshold values
+ for (i = 0; i < dotsLen; ++i) {
+ n = 0;
+ for (y = 0; y < size; ++y) {
+ for (x = 0; x < size; ++x) {
+ if (region[y*size + x] == i) {
+ pts[n].x = x;
+ pts[n].y = y;
+ pts[n].dist = distance(dots[i].x, dots[i].y, x, y);
+ ++n;
+ }
+ }
+ }
+ qsort(pts, n, sizeof(SplashScreenPoint), &cmpDistances);
+ for (j = 0; j < n; ++j) {
+ // map values in [0 .. n-1] --> [255 .. 1]
+ mat[pts[j].y * size + pts[j].x] = 255 - (254 * j) / (n - 1);
+ }
+ }
+
+ gfree(pts);
+ gfree(region);
+ gfree(dist);
+
+ gfree(dots);
+}
+
+SplashScreen::SplashScreen(SplashScreen *screen) {
+ size = screen->size;
+ mat = (Guchar *)gmallocn(size * size, sizeof(Guchar));
+ memcpy(mat, screen->mat, size * size * sizeof(Guchar));
+ minVal = screen->minVal;
+ maxVal = screen->maxVal;
+}
+
+SplashScreen::~SplashScreen() {
+ gfree(mat);
+}
+
+int SplashScreen::test(int x, int y, Guchar value) {
+ int xx, yy;
+
+ if (value < minVal) {
+ return 0;
+ }
+ if (value >= maxVal) {
+ return 1;
+ }
+ if ((xx = x % size) < 0) {
+ xx = -xx;
+ }
+ if ((yy = y % size) < 0) {
+ yy = -yy;
+ }
+ return value < mat[yy * size + xx] ? 0 : 1;
+}
+
+GBool SplashScreen::isStatic(Guchar value) {
+ return value < minVal || value >= maxVal;
+}
diff --git a/kpdf/xpdf/splash/SplashScreen.h b/kpdf/xpdf/splash/SplashScreen.h
new file mode 100644
index 00000000..2baa9b5d
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashScreen.h
@@ -0,0 +1,56 @@
+//========================================================================
+//
+// SplashScreen.h
+//
+//========================================================================
+
+#ifndef SPLASHSCREEN_H
+#define SPLASHSCREEN_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "SplashTypes.h"
+
+//------------------------------------------------------------------------
+// SplashScreen
+//------------------------------------------------------------------------
+
+class SplashScreen {
+public:
+
+ SplashScreen(SplashScreenParams *params);
+ SplashScreen(SplashScreen *screen);
+ ~SplashScreen();
+
+ SplashScreen *copy() { return new SplashScreen(this); }
+
+ // Return the computed pixel value (0=black, 1=white) for the gray
+ // level <value> at (<x>, <y>).
+ int test(int x, int y, Guchar value);
+
+ // Returns true if value is above the white threshold or below the
+ // black threshold, i.e., if the corresponding halftone will be
+ // solid white or black.
+ GBool isStatic(Guchar value);
+
+private:
+
+ void buildDispersedMatrix(int i, int j, int val,
+ int delta, int offset);
+ void buildClusteredMatrix();
+ int distance(int x0, int y0, int x1, int y1);
+ void buildSCDMatrix(int r);
+
+ Guchar *mat; // threshold matrix
+ int size; // size of the threshold matrix
+ Guchar minVal; // any pixel value below minVal generates
+ // solid black
+ Guchar maxVal; // any pixel value above maxVal generates
+ // solid white
+};
+
+#endif
diff --git a/kpdf/xpdf/splash/SplashState.cc b/kpdf/xpdf/splash/SplashState.cc
new file mode 100644
index 00000000..e2c34c44
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashState.cc
@@ -0,0 +1,165 @@
+//========================================================================
+//
+// SplashState.cc
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <string.h>
+#include "gmem.h"
+#include "SplashPattern.h"
+#include "SplashScreen.h"
+#include "SplashClip.h"
+#include "SplashBitmap.h"
+#include "SplashState.h"
+
+//------------------------------------------------------------------------
+// SplashState
+//------------------------------------------------------------------------
+
+// number of components in each color mode
+int splashColorModeNComps[] = {
+ 1, 1, 3, 3, 4
+};
+
+SplashState::SplashState(int width, int height, GBool vectorAntialias,
+ SplashScreenParams *screenParams) {
+ SplashColor color;
+
+ matrix[0] = 1; matrix[1] = 0;
+ matrix[2] = 0; matrix[3] = 1;
+ matrix[4] = 0; matrix[5] = 0;
+ memset(&color, 0, sizeof(SplashColor));
+ strokePattern = new SplashSolidColor(color);
+ fillPattern = new SplashSolidColor(color);
+ screen = new SplashScreen(screenParams);
+ blendFunc = NULL;
+ strokeAlpha = 1;
+ fillAlpha = 1;
+ lineWidth = 0;
+ lineCap = splashLineCapButt;
+ lineJoin = splashLineJoinMiter;
+ miterLimit = 10;
+ flatness = 1;
+ lineDash = NULL;
+ lineDashLength = 0;
+ lineDashPhase = 0;
+ strokeAdjust = gFalse;
+ clip = new SplashClip(0, 0, width - 0.001, height - 0.001, vectorAntialias);
+ softMask = NULL;
+ deleteSoftMask = gFalse;
+ inNonIsolatedGroup = gFalse;
+ next = NULL;
+}
+
+SplashState::SplashState(int width, int height, GBool vectorAntialias,
+ SplashScreen *screenA) {
+ SplashColor color;
+
+ matrix[0] = 1; matrix[1] = 0;
+ matrix[2] = 0; matrix[3] = 1;
+ matrix[4] = 0; matrix[5] = 0;
+ memset(&color, 0, sizeof(SplashColor));
+ strokePattern = new SplashSolidColor(color);
+ fillPattern = new SplashSolidColor(color);
+ screen = screenA->copy();
+ blendFunc = NULL;
+ strokeAlpha = 1;
+ fillAlpha = 1;
+ lineWidth = 0;
+ lineCap = splashLineCapButt;
+ lineJoin = splashLineJoinMiter;
+ miterLimit = 10;
+ flatness = 1;
+ lineDash = NULL;
+ lineDashLength = 0;
+ lineDashPhase = 0;
+ strokeAdjust = gFalse;
+ clip = new SplashClip(0, 0, width - 0.001, height - 0.001, vectorAntialias);
+ softMask = NULL;
+ deleteSoftMask = gFalse;
+ inNonIsolatedGroup = gFalse;
+ next = NULL;
+}
+
+SplashState::SplashState(SplashState *state) {
+ memcpy(matrix, state->matrix, 6 * sizeof(SplashCoord));
+ strokePattern = state->strokePattern->copy();
+ fillPattern = state->fillPattern->copy();
+ screen = state->screen->copy();
+ blendFunc = state->blendFunc;
+ strokeAlpha = state->strokeAlpha;
+ fillAlpha = state->fillAlpha;
+ lineWidth = state->lineWidth;
+ lineCap = state->lineCap;
+ lineJoin = state->lineJoin;
+ miterLimit = state->miterLimit;
+ flatness = state->flatness;
+ if (state->lineDash) {
+ lineDashLength = state->lineDashLength;
+ lineDash = (SplashCoord *)gmallocn(lineDashLength, sizeof(SplashCoord));
+ memcpy(lineDash, state->lineDash, lineDashLength * sizeof(SplashCoord));
+ } else {
+ lineDash = NULL;
+ lineDashLength = 0;
+ }
+ lineDashPhase = state->lineDashPhase;
+ strokeAdjust = state->strokeAdjust;
+ clip = state->clip->copy();
+ softMask = state->softMask;
+ deleteSoftMask = gFalse;
+ inNonIsolatedGroup = state->inNonIsolatedGroup;
+ next = NULL;
+}
+
+SplashState::~SplashState() {
+ delete strokePattern;
+ delete fillPattern;
+ delete screen;
+ gfree(lineDash);
+ delete clip;
+ if (deleteSoftMask && softMask) {
+ delete softMask;
+ }
+}
+
+void SplashState::setStrokePattern(SplashPattern *strokePatternA) {
+ delete strokePattern;
+ strokePattern = strokePatternA;
+}
+
+void SplashState::setFillPattern(SplashPattern *fillPatternA) {
+ delete fillPattern;
+ fillPattern = fillPatternA;
+}
+
+void SplashState::setScreen(SplashScreen *screenA) {
+ delete screen;
+ screen = screenA;
+}
+
+void SplashState::setLineDash(SplashCoord *lineDashA, int lineDashLengthA,
+ SplashCoord lineDashPhaseA) {
+ gfree(lineDash);
+ lineDashLength = lineDashLengthA;
+ if (lineDashLength > 0) {
+ lineDash = (SplashCoord *)gmallocn(lineDashLength, sizeof(SplashCoord));
+ memcpy(lineDash, lineDashA, lineDashLength * sizeof(SplashCoord));
+ } else {
+ lineDash = NULL;
+ }
+ lineDashPhase = lineDashPhaseA;
+}
+
+void SplashState::setSoftMask(SplashBitmap *softMaskA) {
+ if (deleteSoftMask) {
+ delete softMask;
+ }
+ softMask = softMaskA;
+ deleteSoftMask = gTrue;
+}
diff --git a/kpdf/xpdf/splash/SplashState.h b/kpdf/xpdf/splash/SplashState.h
new file mode 100644
index 00000000..1f5a88da
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashState.h
@@ -0,0 +1,103 @@
+//========================================================================
+//
+// SplashState.h
+//
+//========================================================================
+
+#ifndef SPLASHSTATE_H
+#define SPLASHSTATE_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "SplashTypes.h"
+
+class SplashPattern;
+class SplashScreen;
+class SplashClip;
+class SplashBitmap;
+
+//------------------------------------------------------------------------
+// line cap values
+//------------------------------------------------------------------------
+
+#define splashLineCapButt 0
+#define splashLineCapRound 1
+#define splashLineCapProjecting 2
+
+//------------------------------------------------------------------------
+// line join values
+//------------------------------------------------------------------------
+
+#define splashLineJoinMiter 0
+#define splashLineJoinRound 1
+#define splashLineJoinBevel 2
+
+//------------------------------------------------------------------------
+// SplashState
+//------------------------------------------------------------------------
+
+class SplashState {
+public:
+
+ // Create a new state object, initialized with default settings.
+ SplashState(int width, int height, GBool vectorAntialias,
+ SplashScreenParams *screenParams);
+ SplashState(int width, int height, GBool vectorAntialias,
+ SplashScreen *screenA);
+
+ // Copy a state object.
+ SplashState *copy() { return new SplashState(this); }
+
+ ~SplashState();
+
+ // Set the stroke pattern. This does not copy <strokePatternA>.
+ void setStrokePattern(SplashPattern *strokePatternA);
+
+ // Set the fill pattern. This does not copy <fillPatternA>.
+ void setFillPattern(SplashPattern *fillPatternA);
+
+ // Set the screen. This does not copy <screenA>.
+ void setScreen(SplashScreen *screenA);
+
+ // Set the line dash pattern. This copies the <lineDashA> array.
+ void setLineDash(SplashCoord *lineDashA, int lineDashLengthA,
+ SplashCoord lineDashPhaseA);
+
+ // Set the soft mask bitmap.
+ void setSoftMask(SplashBitmap *softMaskA);
+
+private:
+
+ SplashState(SplashState *state);
+
+ SplashCoord matrix[6];
+ SplashPattern *strokePattern;
+ SplashPattern *fillPattern;
+ SplashScreen *screen;
+ SplashBlendFunc blendFunc;
+ SplashCoord strokeAlpha;
+ SplashCoord fillAlpha;
+ SplashCoord lineWidth;
+ int lineCap;
+ int lineJoin;
+ SplashCoord miterLimit;
+ SplashCoord flatness;
+ SplashCoord *lineDash;
+ int lineDashLength;
+ SplashCoord lineDashPhase;
+ GBool strokeAdjust;
+ SplashClip *clip;
+ SplashBitmap *softMask;
+ GBool deleteSoftMask;
+ GBool inNonIsolatedGroup;
+
+ SplashState *next; // used by Splash class
+
+ friend class Splash;
+};
+
+#endif
diff --git a/kpdf/xpdf/splash/SplashT1Font.cc b/kpdf/xpdf/splash/SplashT1Font.cc
new file mode 100644
index 00000000..19237e1d
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashT1Font.cc
@@ -0,0 +1,292 @@
+//========================================================================
+//
+// SplashT1Font.cc
+//
+//========================================================================
+
+#include <aconf.h>
+
+#if HAVE_T1LIB_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <t1lib.h>
+#include "gmem.h"
+#include "SplashMath.h"
+#include "SplashGlyphBitmap.h"
+#include "SplashPath.h"
+#include "SplashT1FontEngine.h"
+#include "SplashT1FontFile.h"
+#include "SplashT1Font.h"
+
+//------------------------------------------------------------------------
+
+static Guchar bitReverse[256] = {
+ 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
+ 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
+ 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
+ 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
+ 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
+ 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
+ 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
+ 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
+ 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
+ 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
+ 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
+ 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
+ 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
+ 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
+ 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
+ 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
+ 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
+ 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
+ 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
+ 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
+ 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
+ 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
+ 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
+ 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
+ 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
+ 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
+ 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
+ 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
+ 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
+ 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
+ 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
+ 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
+};
+
+//------------------------------------------------------------------------
+// SplashT1Font
+//------------------------------------------------------------------------
+
+SplashT1Font::SplashT1Font(SplashT1FontFile *fontFileA, SplashCoord *matA,
+ SplashCoord *textMatA):
+ SplashFont(fontFileA, matA, textMatA, fontFileA->engine->aa)
+{
+ T1_TMATRIX matrix;
+ BBox bbox;
+ SplashCoord bbx0, bby0, bbx1, bby1;
+ int x, y;
+
+ t1libID = T1_CopyFont(fontFileA->t1libID);
+ outlineID = -1;
+
+ // compute font size
+ size = (float)splashSqrt(mat[2]*mat[2] + mat[3]*mat[3]);
+
+ // transform the four corners of the font bounding box -- the min
+ // and max values form the bounding box of the transformed font
+ bbox = T1_GetFontBBox(t1libID);
+ bbx0 = 0.001 * bbox.llx;
+ bby0 = 0.001 * bbox.lly;
+ bbx1 = 0.001 * bbox.urx;
+ bby1 = 0.001 * bbox.ury;
+ // some fonts are completely broken, so we fake it (with values
+ // large enough that most glyphs should fit)
+ if (bbx0 == 0 && bby0 == 0 && bbx1 == 0 && bby1 == 0) {
+ bbx0 = bby0 = -0.5;
+ bbx1 = bby1 = 1.5;
+ }
+ x = (int)(mat[0] * bbx0 + mat[2] * bby0);
+ xMin = xMax = x;
+ y = (int)(mat[1] * bbx0 + mat[3] * bby0);
+ yMin = yMax = y;
+ x = (int)(mat[0] * bbx0 + mat[2] * bby1);
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ y = (int)(mat[1] * bbx0 + mat[3] * bby1);
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ x = (int)(mat[0] * bbx1 + mat[2] * bby0);
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ y = (int)(mat[1] * bbx1 + mat[3] * bby0);
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ x = (int)(mat[0] * bbx1 + mat[2] * bby1);
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ y = (int)(mat[1] * bbx1 + mat[3] * bby1);
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ // This is a kludge: some buggy PDF generators embed fonts with
+ // zero bounding boxes.
+ if (xMax == xMin) {
+ xMin = 0;
+ xMax = (int)size;
+ }
+ if (yMax == yMin) {
+ yMin = 0;
+ yMax = (int)(1.2 * size);
+ }
+ // Another kludge: an unusually large xMin or yMin coordinate is
+ // probably wrong.
+ if (xMin > 0) {
+ xMin = 0;
+ }
+ if (yMin > 0) {
+ yMin = 0;
+ }
+ // Another kludge: t1lib doesn't correctly handle fonts with
+ // real (non-integer) bounding box coordinates.
+ if (xMax - xMin > 5000) {
+ xMin = 0;
+ xMax = (int)size;
+ }
+ if (yMax - yMin > 5000) {
+ yMin = 0;
+ yMax = (int)(1.2 * size);
+ }
+
+ // transform the font
+ matrix.cxx = (double)mat[0] / size;
+ matrix.cxy = (double)mat[1] / size;
+ matrix.cyx = (double)mat[2] / size;
+ matrix.cyy = (double)mat[3] / size;
+ T1_TransformFont(t1libID, &matrix);
+}
+
+SplashT1Font::~SplashT1Font() {
+ T1_DeleteFont(t1libID);
+ if (outlineID >= 0) {
+ T1_DeleteFont(outlineID);
+ }
+}
+
+GBool SplashT1Font::getGlyph(int c, int xFrac, int yFrac,
+ SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) {
+ return SplashFont::getGlyph(c, 0, 0, bitmap, x0, y0, clip, clipRes);
+}
+
+GBool SplashT1Font::makeGlyph(int c, int xFrac, int yFrac,
+ SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes) {
+ GLYPH *glyph;
+ int n, i;
+
+ if (aa) {
+ glyph = T1_AASetChar(t1libID, c, size, NULL);
+ } else {
+ glyph = T1_SetChar(t1libID, c, size, NULL);
+ }
+ if (!glyph) {
+ return gFalse;
+ }
+
+ bitmap->x = -glyph->metrics.leftSideBearing;
+ bitmap->y = glyph->metrics.ascent;
+ bitmap->w = glyph->metrics.rightSideBearing - glyph->metrics.leftSideBearing;
+ bitmap->h = glyph->metrics.ascent - glyph->metrics.descent;
+ bitmap->aa = aa;
+ if (aa) {
+ bitmap->data = (Guchar *)glyph->bits;
+ bitmap->freeData = gFalse;
+ } else {
+ n = bitmap->h * ((bitmap->w + 7) >> 3);
+ bitmap->data = (Guchar *)gmalloc(n);
+ for (i = 0; i < n; ++i) {
+ bitmap->data[i] = bitReverse[glyph->bits[i] & 0xff];
+ }
+ bitmap->freeData = gTrue;
+ }
+
+ *clipRes = clip->testRect(x0 - bitmap->x,
+ y0 - bitmap->y,
+ x0 - bitmap->x + bitmap->w - 1,
+ y0 - bitmap->y + bitmap->h - 1);
+
+ return gTrue;
+}
+
+SplashPath *SplashT1Font::getGlyphPath(int c) {
+ T1_TMATRIX matrix;
+ SplashPath *path;
+ T1_OUTLINE *outline;
+ T1_PATHSEGMENT *seg;
+ T1_BEZIERSEGMENT *bez;
+ SplashCoord x, y, x1, y1;
+ GBool needClose;
+
+ if (outlineID < 0) {
+ outlineID = T1_CopyFont(((SplashT1FontFile *)fontFile)->t1libID);
+ outlineSize = (float)splashSqrt(textMat[2]*textMat[2] +
+ textMat[3]*textMat[3]);
+ matrix.cxx = (double)textMat[0] / outlineSize;
+ matrix.cxy = (double)textMat[1] / outlineSize;
+ matrix.cyx = (double)textMat[2] / outlineSize;
+ matrix.cyy = (double)textMat[3] / outlineSize;
+ // t1lib doesn't seem to handle small sizes correctly here, so set
+ // the size to 1000, and scale the resulting coordinates later
+ outlineMul = (float)(outlineSize / 65536000.0);
+ outlineSize = 1000;
+ T1_TransformFont(outlineID, &matrix);
+ }
+
+ path = new SplashPath();
+ if ((outline = T1_GetCharOutline(outlineID, c, outlineSize, NULL))) {
+ x = 0;
+ y = 0;
+ needClose = gFalse;
+ for (seg = outline; seg; seg = seg->link) {
+ switch (seg->type) {
+ case T1_PATHTYPE_MOVE:
+ if (needClose) {
+ path->close();
+ needClose = gFalse;
+ }
+ x += seg->dest.x * outlineMul;
+ y += seg->dest.y * outlineMul;
+ path->moveTo(x, -y);
+ break;
+ case T1_PATHTYPE_LINE:
+ x += seg->dest.x * outlineMul;
+ y += seg->dest.y * outlineMul;
+ path->lineTo(x, -y);
+ needClose = gTrue;
+ break;
+ case T1_PATHTYPE_BEZIER:
+ bez = (T1_BEZIERSEGMENT *)seg;
+ x1 = x + (SplashCoord)(bez->dest.x * outlineMul);
+ y1 = y + (SplashCoord)(bez->dest.y * outlineMul);
+ path->curveTo(x + (SplashCoord)(bez->B.x * outlineMul),
+ -(y + (SplashCoord)(bez->B.y * outlineMul)),
+ x + (SplashCoord)(bez->C.x * outlineMul),
+ -(y + (SplashCoord)(bez->C.y * outlineMul)),
+ x1, -y1);
+ x = x1;
+ y = y1;
+ needClose = gTrue;
+ break;
+ }
+ }
+ if (needClose) {
+ path->close();
+ }
+ T1_FreeOutline(outline);
+ }
+
+ return path;
+}
+
+#endif // HAVE_T1LIB_H
diff --git a/kpdf/xpdf/splash/SplashT1Font.h b/kpdf/xpdf/splash/SplashT1Font.h
new file mode 100644
index 00000000..129c6ad5
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashT1Font.h
@@ -0,0 +1,57 @@
+//========================================================================
+//
+// SplashT1Font.h
+//
+//========================================================================
+
+#ifndef SPLASHT1FONT_H
+#define SPLASHT1FONT_H
+
+#include <aconf.h>
+
+#if HAVE_T1LIB_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "SplashFont.h"
+
+class SplashT1FontFile;
+
+//------------------------------------------------------------------------
+// SplashT1Font
+//------------------------------------------------------------------------
+
+class SplashT1Font: public SplashFont {
+public:
+
+ SplashT1Font(SplashT1FontFile *fontFileA, SplashCoord *matA,
+ SplashCoord *textMatA);
+
+ virtual ~SplashT1Font();
+
+ // Munge xFrac and yFrac before calling SplashFont::getGlyph.
+ virtual GBool getGlyph(int c, int xFrac, int yFrac,
+ SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes);
+
+ // Rasterize a glyph. The <xFrac> and <yFrac> values are the same
+ // as described for getGlyph.
+ virtual GBool makeGlyph(int c, int xFrac, int yFrac,
+ SplashGlyphBitmap *bitmap, int x0, int y0, SplashClip *clip, SplashClipResult *clipRes);
+
+ // Return the path for a glyph.
+ virtual SplashPath *getGlyphPath(int c);
+
+private:
+
+ int t1libID; // t1lib font ID
+ int outlineID; // t1lib font ID for glyph outlines
+ float size;
+ float outlineSize; // size for glyph outlines
+ float outlineMul;
+};
+
+#endif // HAVE_T1LIB_H
+
+#endif
diff --git a/kpdf/xpdf/splash/SplashT1FontEngine.cc b/kpdf/xpdf/splash/SplashT1FontEngine.cc
new file mode 100644
index 00000000..68530e88
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashT1FontEngine.cc
@@ -0,0 +1,122 @@
+//========================================================================
+//
+// SplashT1FontEngine.cc
+//
+//========================================================================
+
+#include <aconf.h>
+
+#if HAVE_T1LIB_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#ifndef WIN32
+# include <unistd.h>
+#endif
+#include <t1lib.h>
+#include "GString.h"
+#include "gfile.h"
+#include "FoFiType1C.h"
+#include "SplashT1FontFile.h"
+#include "SplashT1FontEngine.h"
+
+#ifdef VMS
+#if (__VMS_VER < 70000000)
+extern "C" int unlink(char *filename);
+#endif
+#endif
+
+//------------------------------------------------------------------------
+
+int SplashT1FontEngine::t1libInitCount = 0;
+
+//------------------------------------------------------------------------
+
+static void fileWrite(void *stream, char *data, int len) {
+ fwrite(data, 1, len, (FILE *)stream);
+}
+
+//------------------------------------------------------------------------
+// SplashT1FontEngine
+//------------------------------------------------------------------------
+
+SplashT1FontEngine::SplashT1FontEngine(GBool aaA) {
+ aa = aaA;
+}
+
+SplashT1FontEngine *SplashT1FontEngine::init(GBool aaA) {
+ // grayVals[i] = round(i * 255 / 16)
+ static unsigned long grayVals[17] = {
+ 0, 16, 32, 48, 64, 80, 96, 112, 128, 143, 159, 175, 191, 207, 223, 239, 255
+ };
+
+ //~ for multithreading: need a mutex here
+ if (t1libInitCount == 0) {
+ T1_SetBitmapPad(8);
+ if (!T1_InitLib(NO_LOGFILE | IGNORE_CONFIGFILE | IGNORE_FONTDATABASE |
+ T1_NO_AFM)) {
+ return NULL;
+ }
+ if (aaA) {
+ T1_AASetBitsPerPixel(8);
+ T1_AASetLevel(T1_AA_HIGH);
+ T1_AAHSetGrayValues(grayVals);
+ } else {
+ T1_AANSetGrayValues(0, 1);
+ }
+ }
+ ++t1libInitCount;
+
+ return new SplashT1FontEngine(aaA);
+}
+
+SplashT1FontEngine::~SplashT1FontEngine() {
+ //~ for multithreading: need a mutex here
+ if (--t1libInitCount == 0) {
+ T1_CloseLib();
+ }
+}
+
+SplashFontFile *SplashT1FontEngine::loadType1Font(SplashFontFileID *idA,
+ SplashFontSrc *src,
+ char **enc) {
+ return SplashT1FontFile::loadType1Font(this, idA, fileName, deleteFile, enc);
+}
+
+SplashFontFile *SplashT1FontEngine::loadType1CFont(SplashFontFileID *idA,
+ SplashFontSrc *src,
+ char **enc) {
+ FoFiType1C *ff;
+ GString *tmpFileName;
+ FILE *tmpFile;
+ SplashFontFile *ret;
+ SplashFontSrc *newsrc;
+
+ if (src->isFile)
+ ff = FoFiType1C::load(src->fileName);
+ else
+ ff = new FoFiType1C(src->buf, src->bufLen, gFalse);
+ if (! ff)
+ return NULL;
+ }
+ tmpFileName = NULL;
+ if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) {
+ delete ff;
+ return NULL;
+ }
+ ff->convertToType1(NULL, NULL, gTrue, &fileWrite, tmpFile);
+ delete ff;
+ fclose(tmpFile);
+ newsrc = new SplashFontSrc;
+ newsrc->setFile(tmpFileName, gTrue);
+ delete tmpFileName;
+ ret = SplashT1FontFile::loadType1Font(this, idA, newsrc, enc);
+ newsrc->unref();
+ return ret;
+}
+
+#endif // HAVE_T1LIB_H
diff --git a/kpdf/xpdf/splash/SplashT1FontEngine.h b/kpdf/xpdf/splash/SplashT1FontEngine.h
new file mode 100644
index 00000000..57a04487
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashT1FontEngine.h
@@ -0,0 +1,53 @@
+//========================================================================
+//
+// SplashT1FontEngine.h
+//
+//========================================================================
+
+#ifndef SPLASHT1FONTENGINE_H
+#define SPLASHT1FONTENGINE_H
+
+#include <aconf.h>
+
+#if HAVE_T1LIB_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+
+class SplashFontFile;
+class SplashFontFileID;
+
+//------------------------------------------------------------------------
+// SplashT1FontEngine
+//------------------------------------------------------------------------
+
+class SplashT1FontEngine {
+public:
+
+ static SplashT1FontEngine *init(GBool aaA);
+
+ ~SplashT1FontEngine();
+
+ // Load fonts.
+ SplashFontFile *loadType1Font(SplashFontFileID *idA, char *fileName,
+ GBool deleteFile, char **enc);
+ SplashFontFile *loadType1CFont(SplashFontFileID *idA, char *fileName,
+ GBool deleteFile, char **enc);
+
+private:
+
+ SplashT1FontEngine(GBool aaA);
+
+ static int t1libInitCount;
+ GBool aa;
+
+ friend class SplashT1FontFile;
+ friend class SplashT1Font;
+};
+
+#endif // HAVE_T1LIB_H
+
+#endif
diff --git a/kpdf/xpdf/splash/SplashT1FontFile.cc b/kpdf/xpdf/splash/SplashT1FontFile.cc
new file mode 100644
index 00000000..54312055
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashT1FontFile.cc
@@ -0,0 +1,117 @@
+//========================================================================
+//
+// SplashT1FontFile.cc
+//
+//========================================================================
+
+#include <aconf.h>
+
+#if HAVE_T1LIB_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <string.h>
+#include <t1lib.h>
+#include "gmem.h"
+#include "SplashT1FontEngine.h"
+#include "SplashT1Font.h"
+#include "SplashT1FontFile.h"
+
+//------------------------------------------------------------------------
+// SplashT1FontFile
+//------------------------------------------------------------------------
+
+SplashFontFile *SplashT1FontFile::loadType1Font(SplashT1FontEngine *engineA,
+ SplashFontFileID *idA,
+ SplashFontSrc *src,
+ char **encA) {
+ int t1libIDA;
+ char **encTmp;
+ char *encStrTmp;
+ int encStrSize;
+ char *encPtr;
+ int i;
+
+ GString *fileNameA;
+ SplashFontSrc *newsrc = NULL;
+ SplashFontFile *ff;
+
+ if (! src->isFile) {
+ GString *tmpFileName;
+ FILE *tmpFile;
+ if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL))
+ return NULL;
+ fwrite(src->buf, 1, src->bufLen, tmpFile);
+ fclose(tmpFile);
+ newsrc = new SplashFontSrc;
+ newsrc->setFile(tmpFileName, gTrue);
+ src = newsrc;
+ delete tmpFileName;
+ }
+ fileNameA = src->fileName;
+ // load the font file
+ if ((t1libIDA = T1_AddFont(fileNameA)) < 0) {
+ delete newsrc;
+ return NULL;
+ }
+ T1_LoadFont(t1libIDA);
+
+ // reencode it
+ encStrSize = 0;
+ for (i = 0; i < 256; ++i) {
+ if (encA[i]) {
+ encStrSize += strlen(encA[i]) + 1;
+ }
+ }
+ encTmp = (char **)gmallocn(257, sizeof(char *));
+ encStrTmp = (char *)gmallocn(encStrSize, sizeof(char));
+ encPtr = encStrTmp;
+ for (i = 0; i < 256; ++i) {
+ if (encA[i]) {
+ strcpy(encPtr, encA[i]);
+ encTmp[i] = encPtr;
+ encPtr += strlen(encPtr) + 1;
+ } else {
+ encTmp[i] = ".notdef";
+ }
+ }
+ encTmp[256] = "custom";
+ T1_ReencodeFont(t1libIDA, encTmp);
+
+ ff = new SplashT1FontFile(engineA, idA, src,
+ t1libIDA, encTmp, encStrTmp);
+ if (newsrc)
+ newsrc->unref();
+ return ff;
+}
+
+SplashT1FontFile::SplashT1FontFile(SplashT1FontEngine *engineA,
+ SplashFontFileID *idA,
+ SplashFontSrc *srcA,
+ int t1libIDA, char **encA, char *encStrA):
+ SplashFontFile(idA, srcA)
+{
+ engine = engineA;
+ t1libID = t1libIDA;
+ enc = encA;
+ encStr = encStrA;
+}
+
+SplashT1FontFile::~SplashT1FontFile() {
+ gfree(encStr);
+ gfree(enc);
+ T1_DeleteFont(t1libID);
+}
+
+SplashFont *SplashT1FontFile::makeFont(SplashCoord *mat,
+ SplashCoord *textMat) {
+ SplashFont *font;
+
+ font = new SplashT1Font(this, mat, textMat);
+ font->initCache();
+ return font;
+}
+
+#endif // HAVE_T1LIB_H
diff --git a/kpdf/xpdf/splash/SplashT1FontFile.h b/kpdf/xpdf/splash/SplashT1FontFile.h
new file mode 100644
index 00000000..4dc93cbf
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashT1FontFile.h
@@ -0,0 +1,58 @@
+//========================================================================
+//
+// SplashT1FontFile.h
+//
+//========================================================================
+
+#ifndef SPLASHT1FONTFILE_H
+#define SPLASHT1FONTFILE_H
+
+#include <aconf.h>
+
+#if HAVE_T1LIB_H
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "SplashFontFile.h"
+
+class SplashT1FontEngine;
+
+//------------------------------------------------------------------------
+// SplashT1FontFile
+//------------------------------------------------------------------------
+
+class SplashT1FontFile: public SplashFontFile {
+public:
+
+ static SplashFontFile *loadType1Font(SplashT1FontEngine *engineA,
+ SplashFontFileID *idA,
+ char *fileNameA,
+ char **encA);
+
+ virtual ~SplashT1FontFile();
+
+ // Create a new SplashT1Font, i.e., a scaled instance of this font
+ // file.
+ virtual SplashFont *makeFont(SplashCoord *mat,
+ SplashCoord *textMat);
+
+private:
+
+ SplashT1FontFile(SplashT1FontEngine *engineA,
+ SplashFontFileID *idA,
+ char *fileNameA,
+ int t1libIDA, char **encA, char *encStrA);
+
+ SplashT1FontEngine *engine;
+ int t1libID; // t1lib font ID
+ char **enc;
+ char *encStr;
+
+ friend class SplashT1Font;
+};
+
+#endif // HAVE_T1LIB_H
+
+#endif
diff --git a/kpdf/xpdf/splash/SplashTypes.h b/kpdf/xpdf/splash/SplashTypes.h
new file mode 100644
index 00000000..35551b90
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashTypes.h
@@ -0,0 +1,132 @@
+//========================================================================
+//
+// SplashTypes.h
+//
+//========================================================================
+
+#ifndef SPLASHTYPES_H
+#define SPLASHTYPES_H
+
+#include <aconf.h>
+#include "gtypes.h"
+
+//------------------------------------------------------------------------
+// coordinates
+//------------------------------------------------------------------------
+
+#if USE_FIXEDPOINT
+#include "FixedPoint.h"
+typedef FixedPoint SplashCoord;
+#else
+typedef double SplashCoord;
+#endif
+
+//------------------------------------------------------------------------
+// antialiasing
+//------------------------------------------------------------------------
+
+#define splashAASize 4
+
+//------------------------------------------------------------------------
+// colors
+//------------------------------------------------------------------------
+
+enum SplashColorMode {
+ splashModeMono1, // 1 bit per component, 8 pixels per byte,
+ // MSbit is on the left
+ splashModeMono8, // 1 byte per component, 1 byte per pixel
+ splashModeRGB8, // 1 byte per component, 3 bytes per pixel:
+ // RGBRGB...
+ splashModeBGR8 // 1 byte per component, 3 bytes per pixel:
+ // BGRBGR...
+
+#if SPLASH_CMYK
+ ,
+ splashModeCMYK8 // 1 byte per component, 4 bytes per pixel:
+ // CMYKCMYK...
+#endif
+};
+
+// number of components in each color mode
+// (defined in SplashState.cc)
+extern int splashColorModeNComps[];
+
+// max number of components in any SplashColor
+#if SPLASH_CMYK
+# define splashMaxColorComps 4
+#else
+# define splashMaxColorComps 3
+#endif
+
+typedef Guchar SplashColor[splashMaxColorComps];
+typedef Guchar *SplashColorPtr;
+
+// RGB8
+static inline Guchar splashRGB8R(SplashColorPtr rgb8) { return rgb8[0]; }
+static inline Guchar splashRGB8G(SplashColorPtr rgb8) { return rgb8[1]; }
+static inline Guchar splashRGB8B(SplashColorPtr rgb8) { return rgb8[2]; }
+
+// BGR8
+static inline Guchar splashBGR8R(SplashColorPtr bgr8) { return bgr8[2]; }
+static inline Guchar splashBGR8G(SplashColorPtr bgr8) { return bgr8[1]; }
+static inline Guchar splashBGR8B(SplashColorPtr bgr8) { return bgr8[0]; }
+
+#if SPLASH_CMYK
+// CMYK8
+static inline Guchar splashCMYK8C(SplashColorPtr cmyk8) { return cmyk8[0]; }
+static inline Guchar splashCMYK8M(SplashColorPtr cmyk8) { return cmyk8[1]; }
+static inline Guchar splashCMYK8Y(SplashColorPtr cmyk8) { return cmyk8[2]; }
+static inline Guchar splashCMYK8K(SplashColorPtr cmyk8) { return cmyk8[3]; }
+#endif
+
+static inline void splashColorCopy(SplashColorPtr dest, SplashColorPtr src) {
+ dest[0] = src[0];
+ dest[1] = src[1];
+ dest[2] = src[2];
+#if SPLASH_CMYK
+ dest[3] = src[3];
+#endif
+}
+
+static inline void splashColorXor(SplashColorPtr dest, SplashColorPtr src) {
+ dest[0] ^= src[0];
+ dest[1] ^= src[1];
+ dest[2] ^= src[2];
+#if SPLASH_CMYK
+ dest[3] ^= src[3];
+#endif
+}
+
+//------------------------------------------------------------------------
+// blend functions
+//------------------------------------------------------------------------
+
+typedef void (*SplashBlendFunc)(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm);
+
+//------------------------------------------------------------------------
+// screen parameters
+//------------------------------------------------------------------------
+
+enum SplashScreenType {
+ splashScreenDispersed,
+ splashScreenClustered,
+ splashScreenStochasticClustered
+};
+
+struct SplashScreenParams {
+ SplashScreenType type;
+ int size;
+ int dotRadius;
+ SplashCoord gamma;
+ SplashCoord blackThreshold;
+ SplashCoord whiteThreshold;
+};
+
+//------------------------------------------------------------------------
+// error results
+//------------------------------------------------------------------------
+
+typedef int SplashError;
+
+#endif
diff --git a/kpdf/xpdf/splash/SplashXPath.cc b/kpdf/xpdf/splash/SplashXPath.cc
new file mode 100644
index 00000000..71481eff
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashXPath.cc
@@ -0,0 +1,443 @@
+//========================================================================
+//
+// SplashXPath.cc
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include "gmem.h"
+#include "SplashMath.h"
+#include "SplashPath.h"
+#include "SplashXPath.h"
+
+//------------------------------------------------------------------------
+
+struct SplashXPathPoint {
+ SplashCoord x, y;
+};
+
+struct SplashXPathAdjust {
+ int firstPt, lastPt; // range of points
+ GBool vert; // vertical or horizontal hint
+ SplashCoord x0a, x0b, // hint boundaries
+ xma, xmb,
+ x1a, x1b;
+ SplashCoord x0, x1, xm; // adjusted coordinates
+};
+
+//------------------------------------------------------------------------
+
+// Transform a point from user space to device space.
+inline void SplashXPath::transform(SplashCoord *matrix,
+ SplashCoord xi, SplashCoord yi,
+ SplashCoord *xo, SplashCoord *yo) {
+ // [ m[0] m[1] 0 ]
+ // [xo yo 1] = [xi yi 1] * [ m[2] m[3] 0 ]
+ // [ m[4] m[5] 1 ]
+ *xo = xi * matrix[0] + yi * matrix[2] + matrix[4];
+ *yo = xi * matrix[1] + yi * matrix[3] + matrix[5];
+}
+
+//------------------------------------------------------------------------
+// SplashXPath
+//------------------------------------------------------------------------
+
+SplashXPath::SplashXPath() {
+ segs = NULL;
+ length = size = 0;
+}
+
+SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix,
+ SplashCoord flatness, GBool closeSubpaths) {
+ SplashPathHint *hint;
+ SplashXPathPoint *pts;
+ SplashXPathAdjust *adjusts, *adjust;
+ SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xsp, ysp;
+ SplashCoord adj0, adj1, w;
+ int ww;
+ int curSubpath, curSubpathX, i, j;
+
+ // transform the points
+ pts = (SplashXPathPoint *)gmallocn(path->length, sizeof(SplashXPathPoint));
+ for (i = 0; i < path->length; ++i) {
+ transform(matrix, path->pts[i].x, path->pts[i].y, &pts[i].x, &pts[i].y);
+ }
+
+ // set up the stroke adjustment hints
+ if (path->hints) {
+ adjusts = (SplashXPathAdjust *)gmallocn(path->hintsLength,
+ sizeof(SplashXPathAdjust));
+ for (i = 0; i < path->hintsLength; ++i) {
+ hint = &path->hints[i];
+ if (hint->ctrl0 + 1 >= path->length || hint->ctrl1 + 1 >= path->length) {
+ gfree(adjusts);
+ adjusts = NULL;
+ break;
+ }
+ x0 = pts[hint->ctrl0 ].x; y0 = pts[hint->ctrl0 ].y;
+ x1 = pts[hint->ctrl0 + 1].x; y1 = pts[hint->ctrl0 + 1].y;
+ x2 = pts[hint->ctrl1 ].x; y2 = pts[hint->ctrl1 ].y;
+ x3 = pts[hint->ctrl1 + 1].x; y3 = pts[hint->ctrl1 + 1].y;
+ if (x0 == x1 && x2 == x3) {
+ adjusts[i].vert = gTrue;
+ adj0 = x0;
+ adj1 = x2;
+ } else if (y0 == y1 && y2 == y3) {
+ adjusts[i].vert = gFalse;
+ adj0 = y0;
+ adj1 = y2;
+ } else {
+ gfree(adjusts);
+ adjusts = NULL;
+ break;
+ }
+ if (adj0 > adj1) {
+ x0 = adj0;
+ adj0 = adj1;
+ adj1 = x0;
+ }
+ w = adj1 - adj0;
+ ww = splashRound(w);
+ if (ww == 0) {
+ ww = 1;
+ }
+ adjusts[i].x0a = adj0 - 0.01;
+ adjusts[i].x0b = adj0 + 0.01;
+ adjusts[i].xma = (SplashCoord)0.5 * (adj0 + adj1) - 0.01;
+ adjusts[i].xmb = (SplashCoord)0.5 * (adj0 + adj1) + 0.01;
+ adjusts[i].x1a = adj1 - 0.01;
+ adjusts[i].x1b = adj1 + 0.01;
+ adjusts[i].x0 = (SplashCoord)splashRound(adj0);
+ adjusts[i].x1 = adjusts[i].x0 + ww - 0.01;
+ adjusts[i].xm = (SplashCoord)0.5 * (adjusts[i].x0 + adjusts[i].x1);
+ adjusts[i].firstPt = hint->firstPt;
+ adjusts[i].lastPt = hint->lastPt;
+ }
+
+ } else {
+ adjusts = NULL;
+ }
+
+ // perform stroke adjustment
+ if (adjusts) {
+ for (i = 0, adjust = adjusts; i < path->hintsLength; ++i, ++adjust) {
+ for (j = adjust->firstPt; j <= adjust->lastPt; ++j) {
+ strokeAdjust(adjust, &pts[j].x, &pts[j].y);
+ }
+ }
+ gfree(adjusts);
+ }
+
+ segs = NULL;
+ length = size = 0;
+
+ x0 = y0 = xsp = ysp = 0; // make gcc happy
+ adj0 = adj1 = 0; // make gcc happy
+ curSubpath = 0;
+ curSubpathX = 0;
+ i = 0;
+ while (i < path->length) {
+
+ // first point in subpath - skip it
+ if (path->flags[i] & splashPathFirst) {
+ x0 = pts[i].x;
+ y0 = pts[i].y;
+ xsp = x0;
+ ysp = y0;
+ curSubpath = i;
+ curSubpathX = length;
+ ++i;
+
+ } else {
+
+ // curve segment
+ if (path->flags[i] & splashPathCurve) {
+ x1 = pts[i].x;
+ y1 = pts[i].y;
+ x2 = pts[i+1].x;
+ y2 = pts[i+1].y;
+ x3 = pts[i+2].x;
+ y3 = pts[i+2].y;
+ addCurve(x0, y0, x1, y1, x2, y2, x3, y3,
+ flatness,
+ (path->flags[i-1] & splashPathFirst),
+ (path->flags[i+2] & splashPathLast),
+ !closeSubpaths &&
+ (path->flags[i-1] & splashPathFirst) &&
+ !(path->flags[i-1] & splashPathClosed),
+ !closeSubpaths &&
+ (path->flags[i+2] & splashPathLast) &&
+ !(path->flags[i+2] & splashPathClosed));
+ x0 = x3;
+ y0 = y3;
+ i += 3;
+
+ // line segment
+ } else {
+ x1 = pts[i].x;
+ y1 = pts[i].y;
+ addSegment(x0, y0, x1, y1,
+ path->flags[i-1] & splashPathFirst,
+ path->flags[i] & splashPathLast,
+ !closeSubpaths &&
+ (path->flags[i-1] & splashPathFirst) &&
+ !(path->flags[i-1] & splashPathClosed),
+ !closeSubpaths &&
+ (path->flags[i] & splashPathLast) &&
+ !(path->flags[i] & splashPathClosed));
+ x0 = x1;
+ y0 = y1;
+ ++i;
+ }
+
+ // close a subpath
+ if (closeSubpaths &&
+ (path->flags[i-1] & splashPathLast) &&
+ (pts[i-1].x != pts[curSubpath].x ||
+ pts[i-1].y != pts[curSubpath].y)) {
+ addSegment(x0, y0, xsp, ysp,
+ gFalse, gTrue, gFalse, gFalse);
+ }
+ }
+ }
+
+ gfree(pts);
+}
+
+// Apply the stroke adjust hints to point <pt>: (*<xp>, *<yp>).
+void SplashXPath::strokeAdjust(SplashXPathAdjust *adjust,
+ SplashCoord *xp, SplashCoord *yp) {
+ SplashCoord x, y;
+
+ if (adjust->vert) {
+ x = *xp;
+ if (x > adjust->x0a && x < adjust->x0b) {
+ *xp = adjust->x0;
+ } else if (x > adjust->xma && x < adjust->xmb) {
+ *xp = adjust->xm;
+ } else if (x > adjust->x1a && x < adjust->x1b) {
+ *xp = adjust->x1;
+ }
+ } else {
+ y = *yp;
+ if (y > adjust->x0a && y < adjust->x0b) {
+ *yp = adjust->x0;
+ } else if (y > adjust->xma && y < adjust->xmb) {
+ *yp = adjust->xm;
+ } else if (y > adjust->x1a && y < adjust->x1b) {
+ *yp = adjust->x1;
+ }
+ }
+}
+
+SplashXPath::SplashXPath(SplashXPath *xPath) {
+ length = xPath->length;
+ size = xPath->size;
+ segs = (SplashXPathSeg *)gmallocn(size, sizeof(SplashXPathSeg));
+ memcpy(segs, xPath->segs, length * sizeof(SplashXPathSeg));
+}
+
+SplashXPath::~SplashXPath() {
+ gfree(segs);
+}
+
+// Add space for <nSegs> more segments
+void SplashXPath::grow(int nSegs) {
+ if (length + nSegs > size) {
+ if (size == 0) {
+ size = 32;
+ }
+ while (size < length + nSegs) {
+ size *= 2;
+ }
+ segs = (SplashXPathSeg *)greallocn(segs, size, sizeof(SplashXPathSeg));
+ }
+}
+
+void SplashXPath::addCurve(SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1,
+ SplashCoord x2, SplashCoord y2,
+ SplashCoord x3, SplashCoord y3,
+ SplashCoord flatness,
+ GBool first, GBool last, GBool end0, GBool end1) {
+ SplashCoord cx[splashMaxCurveSplits + 1][3];
+ SplashCoord cy[splashMaxCurveSplits + 1][3];
+ int cNext[splashMaxCurveSplits + 1];
+ SplashCoord xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh;
+ SplashCoord yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh;
+ SplashCoord dx, dy, mx, my, d1, d2, flatness2;
+ int p1, p2, p3;
+
+ flatness2 = flatness * flatness;
+
+ // initial segment
+ p1 = 0;
+ p2 = splashMaxCurveSplits;
+ cx[p1][0] = x0; cy[p1][0] = y0;
+ cx[p1][1] = x1; cy[p1][1] = y1;
+ cx[p1][2] = x2; cy[p1][2] = y2;
+ cx[p2][0] = x3; cy[p2][0] = y3;
+ cNext[p1] = p2;
+
+ while (p1 < splashMaxCurveSplits) {
+
+ // get the next segment
+ xl0 = cx[p1][0]; yl0 = cy[p1][0];
+ xx1 = cx[p1][1]; yy1 = cy[p1][1];
+ xx2 = cx[p1][2]; yy2 = cy[p1][2];
+ p2 = cNext[p1];
+ xr3 = cx[p2][0]; yr3 = cy[p2][0];
+
+ // compute the distances from the control points to the
+ // midpoint of the straight line (this is a bit of a hack, but
+ // it's much faster than computing the actual distances to the
+ // line)
+ mx = (xl0 + xr3) * 0.5;
+ my = (yl0 + yr3) * 0.5;
+ dx = xx1 - mx;
+ dy = yy1 - my;
+ d1 = dx*dx + dy*dy;
+ dx = xx2 - mx;
+ dy = yy2 - my;
+ d2 = dx*dx + dy*dy;
+
+ // if the curve is flat enough, or no more subdivisions are
+ // allowed, add the straight line segment
+ if (p2 - p1 == 1 || (d1 <= flatness2 && d2 <= flatness2)) {
+ addSegment(xl0, yl0, xr3, yr3,
+ p1 == 0 && first,
+ p2 == splashMaxCurveSplits && last,
+ p1 == 0 && end0,
+ p2 == splashMaxCurveSplits && end1);
+ p1 = p2;
+
+ // otherwise, subdivide the curve
+ } else {
+ xl1 = (xl0 + xx1) * 0.5;
+ yl1 = (yl0 + yy1) * 0.5;
+ xh = (xx1 + xx2) * 0.5;
+ yh = (yy1 + yy2) * 0.5;
+ xl2 = (xl1 + xh) * 0.5;
+ yl2 = (yl1 + yh) * 0.5;
+ xr2 = (xx2 + xr3) * 0.5;
+ yr2 = (yy2 + yr3) * 0.5;
+ xr1 = (xh + xr2) * 0.5;
+ yr1 = (yh + yr2) * 0.5;
+ xr0 = (xl2 + xr1) * 0.5;
+ yr0 = (yl2 + yr1) * 0.5;
+ // add the new subdivision points
+ p3 = (p1 + p2) / 2;
+ cx[p1][1] = xl1; cy[p1][1] = yl1;
+ cx[p1][2] = xl2; cy[p1][2] = yl2;
+ cNext[p1] = p3;
+ cx[p3][0] = xr0; cy[p3][0] = yr0;
+ cx[p3][1] = xr1; cy[p3][1] = yr1;
+ cx[p3][2] = xr2; cy[p3][2] = yr2;
+ cNext[p3] = p2;
+ }
+ }
+}
+
+void SplashXPath::addSegment(SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1,
+ GBool first, GBool last, GBool end0, GBool end1) {
+ grow(1);
+ segs[length].x0 = x0;
+ segs[length].y0 = y0;
+ segs[length].x1 = x1;
+ segs[length].y1 = y1;
+ segs[length].flags = 0;
+ if (first) {
+ segs[length].flags |= splashXPathFirst;
+ }
+ if (last) {
+ segs[length].flags |= splashXPathLast;
+ }
+ if (end0) {
+ segs[length].flags |= splashXPathEnd0;
+ }
+ if (end1) {
+ segs[length].flags |= splashXPathEnd1;
+ }
+ if (y1 == y0) {
+ segs[length].dxdy = segs[length].dydx = 0;
+ segs[length].flags |= splashXPathHoriz;
+ if (x1 == x0) {
+ segs[length].flags |= splashXPathVert;
+ }
+ } else if (x1 == x0) {
+ segs[length].dxdy = segs[length].dydx = 0;
+ segs[length].flags |= splashXPathVert;
+ } else {
+#if USE_FIXEDPOINT
+ if (FixedPoint::divCheck(x1 - x0, y1 - y0, &segs[length].dxdy)) {
+ segs[length].dydx = (SplashCoord)1 / segs[length].dxdy;
+ } else {
+ segs[length].dxdy = segs[length].dydx = 0;
+ if (splashAbs(x1 - x0) > splashAbs(y1 - y0)) {
+ segs[length].flags |= splashXPathHoriz;
+ } else {
+ segs[length].flags |= splashXPathVert;
+ }
+ }
+#else
+ segs[length].dxdy = (x1 - x0) / (y1 - y0);
+ segs[length].dydx = (SplashCoord)1 / segs[length].dxdy;
+#endif
+ }
+ if (y0 > y1) {
+ segs[length].flags |= splashXPathFlip;
+ }
+ ++length;
+}
+
+static int cmpXPathSegs(const void *arg0, const void *arg1) {
+ SplashXPathSeg *seg0 = (SplashXPathSeg *)arg0;
+ SplashXPathSeg *seg1 = (SplashXPathSeg *)arg1;
+ SplashCoord x0, y0, x1, y1;
+
+ if (seg0->flags & splashXPathFlip) {
+ x0 = seg0->x1;
+ y0 = seg0->y1;
+ } else {
+ x0 = seg0->x0;
+ y0 = seg0->y0;
+ }
+ if (seg1->flags & splashXPathFlip) {
+ x1 = seg1->x1;
+ y1 = seg1->y1;
+ } else {
+ x1 = seg1->x0;
+ y1 = seg1->y0;
+ }
+ if (y0 != y1) {
+ return (y0 > y1) ? 1 : -1;
+ }
+ if (x0 != x1) {
+ return (x0 > x1) ? 1 : -1;
+ }
+ return 0;
+}
+
+void SplashXPath::aaScale() {
+ SplashXPathSeg *seg;
+ int i;
+
+ for (i = 0, seg = segs; i < length; ++i, ++seg) {
+ seg->x0 *= splashAASize;
+ seg->y0 *= splashAASize;
+ seg->x1 *= splashAASize;
+ seg->y1 *= splashAASize;
+ }
+}
+
+void SplashXPath::sort() {
+ qsort(segs, length, sizeof(SplashXPathSeg), &cmpXPathSegs);
+}
diff --git a/kpdf/xpdf/splash/SplashXPath.h b/kpdf/xpdf/splash/SplashXPath.h
new file mode 100644
index 00000000..43276b84
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashXPath.h
@@ -0,0 +1,100 @@
+//========================================================================
+//
+// SplashXPath.h
+//
+//========================================================================
+
+#ifndef SPLASHXPATH_H
+#define SPLASHXPATH_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "SplashTypes.h"
+
+class SplashPath;
+struct SplashXPathAdjust;
+
+//------------------------------------------------------------------------
+
+#define splashMaxCurveSplits (1 << 10)
+
+//------------------------------------------------------------------------
+// SplashXPathSeg
+//------------------------------------------------------------------------
+
+struct SplashXPathSeg {
+ SplashCoord x0, y0; // first endpoint
+ SplashCoord x1, y1; // second endpoint
+ SplashCoord dxdy; // slope: delta-x / delta-y
+ SplashCoord dydx; // slope: delta-y / delta-x
+ Guint flags;
+};
+
+#define splashXPathFirst 0x01 // first segment of a subpath
+#define splashXPathLast 0x02 // last segment of a subpath
+#define splashXPathEnd0 0x04 // first endpoint is end of an open subpath
+#define splashXPathEnd1 0x08 // second endpoint is end of an open subpath
+#define splashXPathHoriz 0x10 // segment is vertical (y0 == y1)
+ // (dxdy is undef)
+#define splashXPathVert 0x20 // segment is horizontal (x0 == x1)
+ // (dydx is undef)
+#define splashXPathFlip 0x40 // y0 > y1
+
+//------------------------------------------------------------------------
+// SplashXPath
+//------------------------------------------------------------------------
+
+class SplashXPath {
+public:
+
+ // Expands (converts to segments) and flattens (converts curves to
+ // lines) <path>. Transforms all points from user space to device
+ // space, via <matrix>. If <closeSubpaths> is true, closes all open
+ // subpaths.
+ SplashXPath(SplashPath *path, SplashCoord *matrix,
+ SplashCoord flatness, GBool closeSubpaths);
+
+ // Copy an expanded path.
+ SplashXPath *copy() { return new SplashXPath(this); }
+
+ ~SplashXPath();
+
+ // Multiply all coordinates by splashAASize, in preparation for
+ // anti-aliased rendering.
+ void aaScale();
+
+ // Sort by upper coordinate (lower y), in y-major order.
+ void sort();
+
+private:
+
+ SplashXPath();
+ SplashXPath(SplashXPath *xPath);
+ void transform(SplashCoord *matrix, SplashCoord xi, SplashCoord yi,
+ SplashCoord *xo, SplashCoord *yo);
+ void strokeAdjust(SplashXPathAdjust *adjust,
+ SplashCoord *xp, SplashCoord *yp);
+ void grow(int nSegs);
+ void addCurve(SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1,
+ SplashCoord x2, SplashCoord y2,
+ SplashCoord x3, SplashCoord y3,
+ SplashCoord flatness,
+ GBool first, GBool last, GBool end0, GBool end1);
+ void addSegment(SplashCoord x0, SplashCoord y0,
+ SplashCoord x1, SplashCoord y1,
+ GBool first, GBool last, GBool end0, GBool end1);
+
+ SplashXPathSeg *segs;
+ int length, size; // length and size of segs array
+
+ friend class SplashXPathScanner;
+ friend class SplashClip;
+ friend class Splash;
+};
+
+#endif
diff --git a/kpdf/xpdf/splash/SplashXPathScanner.cc b/kpdf/xpdf/splash/SplashXPathScanner.cc
new file mode 100644
index 00000000..97e5a9bc
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashXPathScanner.cc
@@ -0,0 +1,429 @@
+//========================================================================
+//
+// SplashXPathScanner.cc
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include "gmem.h"
+#include "SplashMath.h"
+#include "SplashXPath.h"
+#include "SplashBitmap.h"
+#include "SplashXPathScanner.h"
+
+//------------------------------------------------------------------------
+
+struct SplashIntersect {
+ int x0, x1; // intersection of segment with [y, y+1)
+ int count; // EO/NZWN counter increment
+};
+
+static int cmpIntersect(const void *p0, const void *p1) {
+ return ((SplashIntersect *)p0)->x0 - ((SplashIntersect *)p1)->x0;
+}
+
+//------------------------------------------------------------------------
+// SplashXPathScanner
+//------------------------------------------------------------------------
+
+SplashXPathScanner::SplashXPathScanner(SplashXPath *xPathA, GBool eoA) {
+ SplashXPathSeg *seg;
+ SplashCoord xMinFP, yMinFP, xMaxFP, yMaxFP;
+ int i;
+
+ xPath = xPathA;
+ eo = eoA;
+
+ // compute the bbox
+ if (xPath->length == 0) {
+ xMin = yMin = 1;
+ xMax = yMax = 0;
+ } else {
+ seg = &xPath->segs[0];
+ if (seg->x0 <= seg->x1) {
+ xMinFP = seg->x0;
+ xMaxFP = seg->x1;
+ } else {
+ xMinFP = seg->x1;
+ xMaxFP = seg->x0;
+ }
+ if (seg->flags & splashXPathFlip) {
+ yMinFP = seg->y1;
+ yMaxFP = seg->y0;
+ } else {
+ yMinFP = seg->y0;
+ yMaxFP = seg->y1;
+ }
+ for (i = 1; i < xPath->length; ++i) {
+ seg = &xPath->segs[i];
+ if (seg->x0 < xMinFP) {
+ xMinFP = seg->x0;
+ } else if (seg->x0 > xMaxFP) {
+ xMaxFP = seg->x0;
+ }
+ if (seg->x1 < xMinFP) {
+ xMinFP = seg->x1;
+ } else if (seg->x1 > xMaxFP) {
+ xMaxFP = seg->x1;
+ }
+ if (seg->flags & splashXPathFlip) {
+ if (seg->y0 > yMaxFP) {
+ yMaxFP = seg->y0;
+ }
+ } else {
+ if (seg->y1 > yMaxFP) {
+ yMaxFP = seg->y1;
+ }
+ }
+ }
+ xMin = splashFloor(xMinFP);
+ xMax = splashFloor(xMaxFP);
+ yMin = splashFloor(yMinFP);
+ yMax = splashFloor(yMaxFP);
+ }
+
+ interY = yMin - 1;
+ xPathIdx = 0;
+ inter = NULL;
+ interLen = interSize = 0;
+}
+
+SplashXPathScanner::~SplashXPathScanner() {
+ gfree(inter);
+}
+
+void SplashXPathScanner::getBBoxAA(int *xMinA, int *yMinA,
+ int *xMaxA, int *yMaxA) {
+ *xMinA = xMin / splashAASize;
+ *yMinA = yMin / splashAASize;
+ *xMaxA = xMax / splashAASize;
+ *yMaxA = yMax / splashAASize;
+}
+
+void SplashXPathScanner::getSpanBounds(int y, int *spanXMin, int *spanXMax) {
+ if (interY != y) {
+ computeIntersections(y);
+ }
+ if (interLen > 0) {
+ *spanXMin = inter[0].x0;
+ *spanXMax = inter[interLen - 1].x1;
+ } else {
+ *spanXMin = xMax + 1;
+ *spanXMax = xMax;
+ }
+}
+
+GBool SplashXPathScanner::test(int x, int y) {
+ int count, i;
+
+ if (interY != y) {
+ computeIntersections(y);
+ }
+ count = 0;
+ for (i = 0; i < interLen && inter[i].x0 <= x; ++i) {
+ if (x <= inter[i].x1) {
+ return gTrue;
+ }
+ count += inter[i].count;
+ }
+ return eo ? (count & 1) : (count != 0);
+}
+
+GBool SplashXPathScanner::testSpan(int x0, int x1, int y) {
+ int count, xx1, i;
+
+ if (interY != y) {
+ computeIntersections(y);
+ }
+
+ count = 0;
+ for (i = 0; i < interLen && inter[i].x1 < x0; ++i) {
+ count += inter[i].count;
+ }
+
+ // invariant: the subspan [x0,xx1] is inside the path
+ xx1 = x0 - 1;
+ while (xx1 < x1) {
+ if (i >= interLen) {
+ return gFalse;
+ }
+ if (inter[i].x0 > xx1 + 1 &&
+ !(eo ? (count & 1) : (count != 0))) {
+ return gFalse;
+ }
+ if (inter[i].x1 > xx1) {
+ xx1 = inter[i].x1;
+ }
+ count += inter[i].count;
+ ++i;
+ }
+
+ return gTrue;
+}
+
+GBool SplashXPathScanner::getNextSpan(int y, int *x0, int *x1) {
+ int xx0, xx1;
+
+ if (interY != y) {
+ computeIntersections(y);
+ }
+ if (interIdx >= interLen) {
+ return gFalse;
+ }
+ xx0 = inter[interIdx].x0;
+ xx1 = inter[interIdx].x1;
+ interCount += inter[interIdx].count;
+ ++interIdx;
+ while (interIdx < interLen &&
+ (inter[interIdx].x0 <= xx1 ||
+ (eo ? (interCount & 1) : (interCount != 0)))) {
+ if (inter[interIdx].x1 > xx1) {
+ xx1 = inter[interIdx].x1;
+ }
+ interCount += inter[interIdx].count;
+ ++interIdx;
+ }
+ *x0 = xx0;
+ *x1 = xx1;
+ return gTrue;
+}
+
+void SplashXPathScanner::computeIntersections(int y) {
+ SplashCoord xSegMin, xSegMax, ySegMin, ySegMax, xx0, xx1;
+ SplashXPathSeg *seg;
+ int i, j;
+
+ // find the first segment that intersects [y, y+1)
+ i = (y >= interY) ? xPathIdx : 0;
+ while (i < xPath->length &&
+ xPath->segs[i].y0 < y && xPath->segs[i].y1 < y) {
+ ++i;
+ }
+ xPathIdx = i;
+
+ // find all of the segments that intersect [y, y+1) and create an
+ // Intersect element for each one
+ interLen = 0;
+ for (j = i; j < xPath->length; ++j) {
+ seg = &xPath->segs[j];
+ if (seg->flags & splashXPathFlip) {
+ ySegMin = seg->y1;
+ ySegMax = seg->y0;
+ } else {
+ ySegMin = seg->y0;
+ ySegMax = seg->y1;
+ }
+
+ // ensure that: ySegMin < y+1
+ // y <= ySegMax
+ if (ySegMin >= y + 1) {
+ break;
+ }
+ if (ySegMax < y) {
+ continue;
+ }
+
+ if (interLen == interSize) {
+ if (interSize == 0) {
+ interSize = 16;
+ } else {
+ interSize *= 2;
+ }
+ inter = (SplashIntersect *)greallocn(inter, interSize,
+ sizeof(SplashIntersect));
+ }
+
+ if (seg->flags & splashXPathHoriz) {
+ xx0 = seg->x0;
+ xx1 = seg->x1;
+ } else if (seg->flags & splashXPathVert) {
+ xx0 = xx1 = seg->x0;
+ } else {
+ if (seg->x0 < seg->x1) {
+ xSegMin = seg->x0;
+ xSegMax = seg->x1;
+ } else {
+ xSegMin = seg->x1;
+ xSegMax = seg->x0;
+ }
+ // intersection with top edge
+ xx0 = seg->x0 + ((SplashCoord)y - seg->y0) * seg->dxdy;
+ // intersection with bottom edge
+ xx1 = seg->x0 + ((SplashCoord)y + 1 - seg->y0) * seg->dxdy;
+ // the segment may not actually extend to the top and/or bottom edges
+ if (xx0 < xSegMin) {
+ xx0 = xSegMin;
+ } else if (xx0 > xSegMax) {
+ xx0 = xSegMax;
+ }
+ if (xx1 < xSegMin) {
+ xx1 = xSegMin;
+ } else if (xx1 > xSegMax) {
+ xx1 = xSegMax;
+ }
+ }
+ if (xx0 < xx1) {
+ inter[interLen].x0 = splashFloor(xx0);
+ inter[interLen].x1 = splashFloor(xx1);
+ } else {
+ inter[interLen].x0 = splashFloor(xx1);
+ inter[interLen].x1 = splashFloor(xx0);
+ }
+ if (ySegMin <= y &&
+ (SplashCoord)y < ySegMax &&
+ !(seg->flags & splashXPathHoriz)) {
+ inter[interLen].count = eo ? 1
+ : (seg->flags & splashXPathFlip) ? 1 : -1;
+ } else {
+ inter[interLen].count = 0;
+ }
+ ++interLen;
+ }
+
+ qsort(inter, interLen, sizeof(SplashIntersect), &cmpIntersect);
+
+ interY = y;
+ interIdx = 0;
+ interCount = 0;
+}
+
+void SplashXPathScanner::renderAALine(SplashBitmap *aaBuf,
+ int *x0, int *x1, int y) {
+ int xx0, xx1, xx, xxMin, xxMax, yy;
+ Guchar mask;
+ SplashColorPtr p;
+
+ memset(aaBuf->getDataPtr(), 0, aaBuf->getRowSize() * aaBuf->getHeight());
+ xxMin = aaBuf->getWidth();
+ xxMax = -1;
+ for (yy = 0; yy < splashAASize; ++yy) {
+ computeIntersections(splashAASize * y + yy);
+ while (interIdx < interLen) {
+ xx0 = inter[interIdx].x0;
+ xx1 = inter[interIdx].x1;
+ interCount += inter[interIdx].count;
+ ++interIdx;
+ while (interIdx < interLen &&
+ (inter[interIdx].x0 <= xx1 ||
+ (eo ? (interCount & 1) : (interCount != 0)))) {
+ if (inter[interIdx].x1 > xx1) {
+ xx1 = inter[interIdx].x1;
+ }
+ interCount += inter[interIdx].count;
+ ++interIdx;
+ }
+ if (xx0 < 0) {
+ xx0 = 0;
+ }
+ ++xx1;
+ if (xx1 > aaBuf->getWidth()) {
+ xx1 = aaBuf->getWidth();
+ }
+ // set [xx0, xx1) to 1
+ if (xx0 < xx1) {
+ xx = xx0;
+ p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3);
+ if (xx & 7) {
+ mask = 0xff >> (xx & 7);
+ if ((xx & ~7) == (xx1 & ~7)) {
+ mask &= (Guchar)(0xff00 >> (xx1 & 7));
+ }
+ *p++ |= mask;
+ xx = (xx & ~7) + 8;
+ }
+ for (; xx + 7 < xx1; xx += 8) {
+ *p++ |= 0xff;
+ }
+ if (xx < xx1) {
+ *p |= (Guchar)(0xff00 >> (xx1 & 7));
+ }
+ }
+ if (xx0 < xxMin) {
+ xxMin = xx0;
+ }
+ if (xx1 > xxMax) {
+ xxMax = xx1;
+ }
+ }
+ }
+ *x0 = xxMin / splashAASize;
+ *x1 = (xxMax - 1) / splashAASize;
+}
+
+void SplashXPathScanner::clipAALine(SplashBitmap *aaBuf,
+ int *x0, int *x1, int y) {
+ int xx0, xx1, xx, yy;
+ Guchar mask;
+ SplashColorPtr p;
+
+ for (yy = 0; yy < splashAASize; ++yy) {
+ xx = *x0 * splashAASize;
+ computeIntersections(splashAASize * y + yy);
+ while (interIdx < interLen && xx < (*x1 + 1) * splashAASize) {
+ xx0 = inter[interIdx].x0;
+ xx1 = inter[interIdx].x1;
+ interCount += inter[interIdx].count;
+ ++interIdx;
+ while (interIdx < interLen &&
+ (inter[interIdx].x0 <= xx1 ||
+ (eo ? (interCount & 1) : (interCount != 0)))) {
+ if (inter[interIdx].x1 > xx1) {
+ xx1 = inter[interIdx].x1;
+ }
+ interCount += inter[interIdx].count;
+ ++interIdx;
+ }
+ if (xx0 > aaBuf->getWidth()) {
+ xx0 = aaBuf->getWidth();
+ }
+ // set [xx, xx0) to 0
+ if (xx < xx0) {
+ p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3);
+ if (xx & 7) {
+ mask = (Guchar)(0xff00 >> (xx & 7));
+ if ((xx & ~7) == (xx0 & ~7)) {
+ mask |= 0xff >> (xx0 & 7);
+ }
+ *p++ &= mask;
+ xx = (xx & ~7) + 8;
+ }
+ for (; xx + 7 <= xx0; xx += 8) {
+ *p++ = 0x00;
+ }
+ if (xx < xx0) {
+ *p &= 0xff >> (xx0 & 7);
+ }
+ }
+ if (xx1 >= xx) {
+ xx = xx1 + 1;
+ }
+ }
+ xx0 = (*x1 + 1) * splashAASize;
+ if (xx0 > aaBuf->getWidth()) xx0 = aaBuf->getWidth();
+ // set [xx, xx0) to 0
+ if (xx < xx0) {
+ p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3);
+ if (xx & 7) {
+ mask = (Guchar)(0xff00 >> (xx & 7));
+ if ((xx & ~7) == (xx0 & ~7)) {
+ mask &= 0xff >> (xx0 & 7);
+ }
+ *p++ &= mask;
+ xx = (xx & ~7) + 8;
+ }
+ for (; xx + 7 <= xx0; xx += 8) {
+ *p++ = 0x00;
+ }
+ if (xx < xx0) {
+ *p &= 0xff >> (xx0 & 7);
+ }
+ }
+ }
+}
diff --git a/kpdf/xpdf/splash/SplashXPathScanner.h b/kpdf/xpdf/splash/SplashXPathScanner.h
new file mode 100644
index 00000000..ab02fcc9
--- /dev/null
+++ b/kpdf/xpdf/splash/SplashXPathScanner.h
@@ -0,0 +1,87 @@
+//========================================================================
+//
+// SplashXPathScanner.h
+//
+//========================================================================
+
+#ifndef SPLASHXPATHSCANNER_H
+#define SPLASHXPATHSCANNER_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "SplashTypes.h"
+
+class SplashXPath;
+class SplashBitmap;
+struct SplashIntersect;
+
+//------------------------------------------------------------------------
+// SplashXPathScanner
+//------------------------------------------------------------------------
+
+class SplashXPathScanner {
+public:
+
+ // Create a new SplashXPathScanner object. <xPathA> must be sorted.
+ SplashXPathScanner(SplashXPath *xPathA, GBool eoA);
+
+ ~SplashXPathScanner();
+
+ // Return the path's bounding box.
+ void getBBox(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA)
+ { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; }
+
+ // Return the path's bounding box.
+ void getBBoxAA(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA);
+
+ // Return the min/max x values for the span at <y>.
+ void getSpanBounds(int y, int *spanXMin, int *spanXMax);
+
+ // Returns true if (<x>,<y>) is inside the path.
+ GBool test(int x, int y);
+
+ // Returns true if the entire span ([<x0>,<x1>], <y>) is inside the
+ // path.
+ GBool testSpan(int x0, int x1, int y);
+
+ // Returns the next span inside the path at <y>. If <y> is
+ // different than the previous call to getNextSpan, this returns the
+ // first span at <y>; otherwise it returns the next span (relative
+ // to the previous call to getNextSpan). Returns false if there are
+ // no more spans at <y>.
+ GBool getNextSpan(int y, int *x0, int *x1);
+
+ // Renders one anti-aliased line into <aaBuf>. Returns the min and
+ // max x coordinates with non-zero pixels in <x0> and <x1>.
+ void renderAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y);
+
+ // Clips an anti-aliased line by setting pixels to zero. On entry,
+ // all non-zero pixels are between <x0> and <x1>. This function
+ // will update <x0> and <x1>.
+ void clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y);
+
+private:
+
+ void computeIntersections(int y);
+
+ SplashXPath *xPath;
+ GBool eo;
+ int xMin, yMin, xMax, yMax;
+
+ int interY; // current y value
+ int interIdx; // current index into <inter> - used by
+ // getNextSpan
+ int interCount; // current EO/NZWN counter - used by
+ // getNextSpan
+ int xPathIdx; // current index into <xPath> - used by
+ // computeIntersections
+ SplashIntersect *inter; // intersections array for <interY>
+ int interLen; // number of intersections in <inter>
+ int interSize; // size of the <inter> array
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/Annot.cc b/kpdf/xpdf/xpdf/Annot.cc
new file mode 100644
index 00000000..23df25df
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Annot.cc
@@ -0,0 +1,1556 @@
+//========================================================================
+//
+// Annot.cc
+//
+// Copyright 2000-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <math.h>
+#include "gmem.h"
+#include "GList.h"
+#include "Error.h"
+#include "Object.h"
+#include "Catalog.h"
+#include "Gfx.h"
+#include "GfxFont.h"
+#include "Lexer.h"
+#include "Annot.h"
+
+//------------------------------------------------------------------------
+
+#define annotFlagHidden 0x0002
+#define annotFlagPrint 0x0004
+#define annotFlagNoView 0x0020
+
+#define fieldFlagReadOnly 0x00000001
+#define fieldFlagRequired 0x00000002
+#define fieldFlagNoExport 0x00000004
+#define fieldFlagMultiline 0x00001000
+#define fieldFlagPassword 0x00002000
+#define fieldFlagNoToggleToOff 0x00004000
+#define fieldFlagRadio 0x00008000
+#define fieldFlagPushbutton 0x00010000
+#define fieldFlagCombo 0x00020000
+#define fieldFlagEdit 0x00040000
+#define fieldFlagSort 0x00080000
+#define fieldFlagFileSelect 0x00100000
+#define fieldFlagMultiSelect 0x00200000
+#define fieldFlagDoNotSpellCheck 0x00400000
+#define fieldFlagDoNotScroll 0x00800000
+#define fieldFlagComb 0x01000000
+#define fieldFlagRichText 0x02000000
+#define fieldFlagRadiosInUnison 0x02000000
+#define fieldFlagCommitOnSelChange 0x04000000
+
+#define fieldQuadLeft 0
+#define fieldQuadCenter 1
+#define fieldQuadRight 2
+
+// distance of Bezier control point from center for circle approximation
+// = (4 * (sqrt(2) - 1) / 3) * r
+#define bezierCircle 0.55228475
+
+//------------------------------------------------------------------------
+// AnnotBorderStyle
+//------------------------------------------------------------------------
+
+AnnotBorderStyle::AnnotBorderStyle(AnnotBorderType typeA, double widthA,
+ double *dashA, int dashLengthA,
+ double rA, double gA, double bA) {
+ type = typeA;
+ width = widthA;
+ dash = dashA;
+ dashLength = dashLengthA;
+ r = rA;
+ g = gA;
+ b = bA;
+}
+
+AnnotBorderStyle::~AnnotBorderStyle() {
+ if (dash) {
+ gfree(dash);
+ }
+}
+
+//------------------------------------------------------------------------
+// Annot
+//------------------------------------------------------------------------
+
+Annot::Annot(XRef *xrefA, Dict * /*acroForm*/, Dict *dict, Ref *refA) {
+ Object apObj, asObj, obj1, obj2, obj3;
+ AnnotBorderType borderType;
+ double borderWidth;
+ double *borderDash;
+ int borderDashLength;
+ double borderR, borderG, borderB;
+ double t;
+ int i;
+
+ ok = gTrue;
+ xref = xrefA;
+ ref = *refA;
+ type = NULL;
+ appearBuf = NULL;
+ borderStyle = NULL;
+
+ //----- parse the type
+
+ if (dict->lookup("Subtype", &obj1)->isName()) {
+ type = new GString(obj1.getName());
+ }
+ obj1.free();
+
+ //----- parse the rectangle
+
+ if (dict->lookup("Rect", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 4) {
+ xMin = yMin = xMax = yMax = 0;
+ if (obj1.arrayGet(0, &obj2)->isNum()) {
+ xMin = obj2.getNum();
+ }
+ obj2.free();
+ if (obj1.arrayGet(1, &obj2)->isNum()) {
+ yMin = obj2.getNum();
+ }
+ obj2.free();
+ if (obj1.arrayGet(2, &obj2)->isNum()) {
+ xMax = obj2.getNum();
+ }
+ obj2.free();
+ if (obj1.arrayGet(3, &obj2)->isNum()) {
+ yMax = obj2.getNum();
+ }
+ obj2.free();
+ if (xMin > xMax) {
+ t = xMin; xMin = xMax; xMax = t;
+ }
+ if (yMin > yMax) {
+ t = yMin; yMin = yMax; yMax = t;
+ }
+ } else {
+ error(-1, "Bad bounding box for annotation");
+ ok = gFalse;
+ }
+ obj1.free();
+
+ //----- parse the flags
+
+ if (dict->lookup("F", &obj1)->isInt()) {
+ flags = obj1.getInt();
+ } else {
+ flags = 0;
+ }
+ obj1.free();
+
+ //----- parse the border style
+
+ borderType = annotBorderSolid;
+ borderWidth = 1;
+ borderDash = NULL;
+ borderDashLength = 0;
+ borderR = 0;
+ borderG = 0;
+ borderB = 1;
+ if (dict->lookup("BS", &obj1)->isDict()) {
+ if (obj1.dictLookup("S", &obj2)->isName()) {
+ if (obj2.isName("S")) {
+ borderType = annotBorderSolid;
+ } else if (obj2.isName("D")) {
+ borderType = annotBorderDashed;
+ } else if (obj2.isName("B")) {
+ borderType = annotBorderBeveled;
+ } else if (obj2.isName("I")) {
+ borderType = annotBorderInset;
+ } else if (obj2.isName("U")) {
+ borderType = annotBorderUnderlined;
+ }
+ }
+ obj2.free();
+ if (obj1.dictLookup("W", &obj2)->isNum()) {
+ borderWidth = obj2.getNum();
+ }
+ obj2.free();
+ if (obj1.dictLookup("D", &obj2)->isArray()) {
+ borderDashLength = obj2.arrayGetLength();
+ borderDash = (double *)gmallocn(borderDashLength, sizeof(double));
+ for (i = 0; i < borderDashLength; ++i) {
+ if (obj2.arrayGet(i, &obj3)->isNum()) {
+ borderDash[i] = obj3.getNum();
+ } else {
+ borderDash[i] = 1;
+ }
+ obj3.free();
+ }
+ }
+ obj2.free();
+ } else {
+ obj1.free();
+ if (dict->lookup("Border", &obj1)->isArray()) {
+ if (obj1.arrayGetLength() >= 3) {
+ if (obj1.arrayGet(2, &obj2)->isNum()) {
+ borderWidth = obj2.getNum();
+ }
+ obj2.free();
+ if (obj1.arrayGetLength() >= 4) {
+ if (obj1.arrayGet(3, &obj2)->isArray()) {
+ borderType = annotBorderDashed;
+ borderDashLength = obj2.arrayGetLength();
+ borderDash = (double *)gmallocn(borderDashLength, sizeof(double));
+ for (i = 0; i < borderDashLength; ++i) {
+ if (obj2.arrayGet(i, &obj3)->isNum()) {
+ borderDash[i] = obj3.getNum();
+ } else {
+ borderDash[i] = 1;
+ }
+ obj3.free();
+ }
+ } else {
+ // Adobe draws no border at all if the last element is of
+ // the wrong type.
+ borderWidth = 0;
+ }
+ obj2.free();
+ }
+ }
+ }
+ }
+ obj1.free();
+ if (dict->lookup("C", &obj1)->isArray() && obj1.arrayGetLength() == 3) {
+ if (obj1.arrayGet(0, &obj2)->isNum()) {
+ borderR = obj2.getNum();
+ }
+ obj1.free();
+ if (obj1.arrayGet(1, &obj2)->isNum()) {
+ borderG = obj2.getNum();
+ }
+ obj1.free();
+ if (obj1.arrayGet(2, &obj2)->isNum()) {
+ borderB = obj2.getNum();
+ }
+ obj1.free();
+ }
+ obj1.free();
+ borderStyle = new AnnotBorderStyle(borderType, borderWidth,
+ borderDash, borderDashLength,
+ borderR, borderG, borderB);
+
+ //----- get the annotation appearance
+
+ if (dict->lookup("AP", &apObj)->isDict()) {
+ if (dict->lookup("AS", &asObj)->isName()) {
+ if (apObj.dictLookup("N", &obj1)->isDict()) {
+ if (obj1.dictLookupNF(asObj.getName(), &obj2)->isRef()) {
+ obj2.copy(&appearance);
+ ok = gTrue;
+ } else {
+ obj2.free();
+ if (obj1.dictLookupNF("Off", &obj2)->isRef()) {
+ obj2.copy(&appearance);
+ }
+ }
+ obj2.free();
+ }
+ obj1.free();
+ } else {
+ if (apObj.dictLookupNF("N", &obj1)->isRef()) {
+ obj1.copy(&appearance);
+ }
+ obj1.free();
+ }
+ asObj.free();
+ }
+ apObj.free();
+}
+
+Annot::~Annot() {
+ if (type) {
+ delete type;
+ }
+ appearance.free();
+ if (appearBuf) {
+ delete appearBuf;
+ }
+ if (borderStyle) {
+ delete borderStyle;
+ }
+}
+
+void Annot::generateFieldAppearance(Dict *field, Dict *annot, Dict *acroForm) {
+ Object mkObj, ftObj, appearDict, drObj, obj1, obj2, obj3;
+ Dict *mkDict;
+ MemStream *appearStream;
+ GfxFontDict *fontDict;
+ GBool hasCaption;
+ double w, dx, dy, r;
+ double *dash;
+ GString *caption, *da;
+ GString **text;
+ GBool *selection;
+ int dashLength, ff, quadding, comb, nOptions, topIdx, i, j;
+
+ // must be a Widget annotation
+ if (type->cmp("Widget")) {
+ return;
+ }
+
+ appearBuf = new GString();
+
+ // get the appearance characteristics (MK) dictionary
+ if (annot->lookup("MK", &mkObj)->isDict()) {
+ mkDict = mkObj.getDict();
+ } else {
+ mkDict = NULL;
+ }
+
+ // draw the background
+ if (mkDict) {
+ if (mkDict->lookup("BG", &obj1)->isArray() &&
+ obj1.arrayGetLength() > 0) {
+ setColor(obj1.getArray(), gTrue, 0);
+ appearBuf->appendf("0 0 {0:.2f} {1:.2f} re f\n",
+ xMax - xMin, yMax - yMin);
+ }
+ obj1.free();
+ }
+
+ // get the field type
+ fieldLookup(field, "FT", &ftObj);
+
+ // get the field flags (Ff) value
+ if (fieldLookup(field, "Ff", &obj1)->isInt()) {
+ ff = obj1.getInt();
+ } else {
+ ff = 0;
+ }
+ obj1.free();
+
+ // draw the border
+ if (mkDict) {
+ w = borderStyle->getWidth();
+ if (w > 0) {
+ mkDict->lookup("BC", &obj1);
+ if (!(obj1.isArray() && obj1.arrayGetLength() > 0)) {
+ mkDict->lookup("BG", &obj1);
+ }
+ if (obj1.isArray() && obj1.arrayGetLength() > 0) {
+ dx = xMax - xMin;
+ dy = yMax - yMin;
+
+ // radio buttons with no caption have a round border
+ hasCaption = mkDict->lookup("CA", &obj2)->isString();
+ obj2.free();
+ if (ftObj.isName("Btn") && (ff & fieldFlagRadio) && !hasCaption) {
+ r = 0.5 * (dx < dy ? dx : dy);
+ switch (borderStyle->getType()) {
+ case annotBorderDashed:
+ appearBuf->append("[");
+ borderStyle->getDash(&dash, &dashLength);
+ for (i = 0; i < dashLength; ++i) {
+ appearBuf->appendf(" {0:.2f}", dash[i]);
+ }
+ appearBuf->append("] 0 d\n");
+ // fall through to the solid case
+ case annotBorderSolid:
+ case annotBorderUnderlined:
+ appearBuf->appendf("{0:.2f} w\n", w);
+ setColor(obj1.getArray(), gFalse, 0);
+ drawCircle(0.5 * dx, 0.5 * dy, r - 0.5 * w, gFalse);
+ break;
+ case annotBorderBeveled:
+ case annotBorderInset:
+ appearBuf->appendf("{0:.2f} w\n", 0.5 * w);
+ setColor(obj1.getArray(), gFalse, 0);
+ drawCircle(0.5 * dx, 0.5 * dy, r - 0.25 * w, gFalse);
+ setColor(obj1.getArray(), gFalse,
+ borderStyle->getType() == annotBorderBeveled ? 1 : -1);
+ drawCircleTopLeft(0.5 * dx, 0.5 * dy, r - 0.75 * w);
+ setColor(obj1.getArray(), gFalse,
+ borderStyle->getType() == annotBorderBeveled ? -1 : 1);
+ drawCircleBottomRight(0.5 * dx, 0.5 * dy, r - 0.75 * w);
+ break;
+ }
+
+ } else {
+ switch (borderStyle->getType()) {
+ case annotBorderDashed:
+ appearBuf->append("[");
+ borderStyle->getDash(&dash, &dashLength);
+ for (i = 0; i < dashLength; ++i) {
+ appearBuf->appendf(" {0:.2f}", dash[i]);
+ }
+ appearBuf->append("] 0 d\n");
+ // fall through to the solid case
+ case annotBorderSolid:
+ appearBuf->appendf("{0:.2f} w\n", w);
+ setColor(obj1.getArray(), gFalse, 0);
+ appearBuf->appendf("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re s\n",
+ 0.5 * w, dx - w, dy - w);
+ break;
+ case annotBorderBeveled:
+ case annotBorderInset:
+ setColor(obj1.getArray(), gTrue,
+ borderStyle->getType() == annotBorderBeveled ? 1 : -1);
+ appearBuf->append("0 0 m\n");
+ appearBuf->appendf("0 {0:.2f} l\n", dy);
+ appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx, dy);
+ appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, dy - w);
+ appearBuf->appendf("{0:.2f} {1:.2f} l\n", w, dy - w);
+ appearBuf->appendf("{0:.2f} {0:.2f} l\n", w);
+ appearBuf->append("f\n");
+ setColor(obj1.getArray(), gTrue,
+ borderStyle->getType() == annotBorderBeveled ? -1 : 1);
+ appearBuf->append("0 0 m\n");
+ appearBuf->appendf("{0:.2f} 0 l\n", dx);
+ appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx, dy);
+ appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, dy - w);
+ appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, w);
+ appearBuf->appendf("{0:.2f} {0:.2f} l\n", w);
+ appearBuf->append("f\n");
+ break;
+ case annotBorderUnderlined:
+ appearBuf->appendf("{0:.2f} w\n", w);
+ setColor(obj1.getArray(), gFalse, 0);
+ appearBuf->appendf("0 0 m {0:.2f} 0 l s\n", dx);
+ break;
+ }
+
+ // clip to the inside of the border
+ appearBuf->appendf("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re W n\n",
+ w, dx - 2 * w, dy - 2 * w);
+ }
+ }
+ obj1.free();
+ }
+ }
+
+ // get the resource dictionary
+ acroForm->lookup("DR", &drObj);
+
+ // build the font dictionary
+ if (drObj.isDict() && drObj.dictLookup("Font", &obj1)->isDict()) {
+ fontDict = new GfxFontDict(xref, NULL, obj1.getDict());
+ } else {
+ fontDict = NULL;
+ }
+ obj1.free();
+
+ // get the default appearance string
+ if (fieldLookup(field, "DA", &obj1)->isNull()) {
+ obj1.free();
+ acroForm->lookup("DA", &obj1);
+ }
+ if (obj1.isString()) {
+ da = obj1.getString()->copy();
+ } else {
+ da = NULL;
+ }
+ obj1.free();
+
+ // draw the field contents
+ if (ftObj.isName("Btn")) {
+ caption = NULL;
+ if (mkDict) {
+ if (mkDict->lookup("CA", &obj1)->isString()) {
+ caption = obj1.getString()->copy();
+ }
+ obj1.free();
+ }
+ // radio button
+ if (ff & fieldFlagRadio) {
+ //~ Acrobat doesn't draw a caption if there is no AP dict (?)
+ if (fieldLookup(field, "V", &obj1)->isName()) {
+ if (annot->lookup("AS", &obj2)->isName(obj1.getName())) {
+ if (caption) {
+ drawText(caption, da, fontDict, gFalse, 0, fieldQuadCenter,
+ gFalse, gTrue);
+ } else {
+ if (mkDict) {
+ if (mkDict->lookup("BC", &obj3)->isArray() &&
+ obj3.arrayGetLength() > 0) {
+ dx = xMax - xMin;
+ dy = yMax - yMin;
+ setColor(obj3.getArray(), gTrue, 0);
+ drawCircle(0.5 * dx, 0.5 * dy, 0.2 * (dx < dy ? dx : dy),
+ gTrue);
+ }
+ obj3.free();
+ }
+ }
+ }
+ obj2.free();
+ }
+ obj1.free();
+ // pushbutton
+ } else if (ff & fieldFlagPushbutton) {
+ if (caption) {
+ drawText(caption, da, fontDict, gFalse, 0, fieldQuadCenter,
+ gFalse, gFalse);
+ }
+ // checkbox
+ } else {
+ // According to the PDF spec the off state must be named "Off",
+ // and the on state can be named anything, but Acrobat apparently
+ // looks for "Yes" and treats anything else as off.
+ if (fieldLookup(field, "V", &obj1)->isName("Yes")) {
+ if (!caption) {
+ caption = new GString("3"); // ZapfDingbats checkmark
+ }
+ drawText(caption, da, fontDict, gFalse, 0, fieldQuadCenter,
+ gFalse, gTrue);
+ }
+ obj1.free();
+ }
+ if (caption) {
+ delete caption;
+ }
+ } else if (ftObj.isName("Tx")) {
+ //~ value strings can be Unicode
+ if (fieldLookup(field, "V", &obj1)->isString()) {
+ if (fieldLookup(field, "Q", &obj2)->isInt()) {
+ quadding = obj2.getInt();
+ } else {
+ quadding = fieldQuadLeft;
+ }
+ obj2.free();
+ comb = 0;
+ if (ff & fieldFlagComb) {
+ if (fieldLookup(field, "MaxLen", &obj2)->isInt()) {
+ comb = obj2.getInt();
+ }
+ obj2.free();
+ }
+ drawText(obj1.getString(), da, fontDict,
+ ff & fieldFlagMultiline, comb, quadding, gTrue, gFalse);
+ }
+ obj1.free();
+ } else if (ftObj.isName("Ch")) {
+ //~ value/option strings can be Unicode
+ if (fieldLookup(field, "Q", &obj1)->isInt()) {
+ quadding = obj1.getInt();
+ } else {
+ quadding = fieldQuadLeft;
+ }
+ obj1.free();
+ // combo box
+ if (ff & fieldFlagCombo) {
+ if (fieldLookup(field, "V", &obj1)->isString()) {
+ drawText(obj1.getString(), da, fontDict,
+ gFalse, 0, quadding, gTrue, gFalse);
+ //~ Acrobat draws a popup icon on the right side
+ }
+ obj1.free();
+ // list box
+ } else {
+ if (field->lookup("Opt", &obj1)->isArray()) {
+ nOptions = obj1.arrayGetLength();
+ // get the option text
+ text = (GString **)gmallocn(nOptions, sizeof(GString *));
+ for (i = 0; i < nOptions; ++i) {
+ text[i] = NULL;
+ obj1.arrayGet(i, &obj2);
+ if (obj2.isString()) {
+ text[i] = obj2.getString()->copy();
+ } else if (obj2.isArray() && obj2.arrayGetLength() == 2) {
+ if (obj2.arrayGet(1, &obj3)->isString()) {
+ text[i] = obj3.getString()->copy();
+ }
+ obj3.free();
+ }
+ obj2.free();
+ if (!text[i]) {
+ text[i] = new GString();
+ }
+ }
+ // get the selected option(s)
+ selection = (GBool *)gmallocn(nOptions, sizeof(GBool));
+ //~ need to use the I field in addition to the V field
+ fieldLookup(field, "V", &obj2);
+ for (i = 0; i < nOptions; ++i) {
+ selection[i] = gFalse;
+ if (obj2.isString()) {
+ if (!obj2.getString()->cmp(text[i])) {
+ selection[i] = gTrue;
+ }
+ } else if (obj2.isArray()) {
+ for (j = 0; j < obj2.arrayGetLength(); ++j) {
+ if (obj2.arrayGet(j, &obj3)->isString() &&
+ !obj3.getString()->cmp(text[i])) {
+ selection[i] = gTrue;
+ }
+ obj3.free();
+ }
+ }
+ }
+ obj2.free();
+ // get the top index
+ if (field->lookup("TI", &obj2)->isInt()) {
+ topIdx = obj2.getInt();
+ } else {
+ topIdx = 0;
+ }
+ obj2.free();
+ // draw the text
+ drawListBox(text, selection, nOptions, topIdx, da, fontDict, quadding);
+ for (i = 0; i < nOptions; ++i) {
+ delete text[i];
+ }
+ gfree(text);
+ gfree(selection);
+ }
+ obj1.free();
+ }
+ } else if (ftObj.isName("Sig")) {
+ //~unimp
+ } else {
+ error(-1, "Unknown field type");
+ }
+
+ if (da) {
+ delete da;
+ }
+
+ // build the appearance stream dictionary
+ appearDict.initDict(xref);
+ appearDict.dictAdd(copyString("Length"),
+ obj1.initInt(appearBuf->getLength()));
+ appearDict.dictAdd(copyString("Subtype"), obj1.initName("Form"));
+ obj1.initArray(xref);
+ obj1.arrayAdd(obj2.initReal(0));
+ obj1.arrayAdd(obj2.initReal(0));
+ obj1.arrayAdd(obj2.initReal(xMax - xMin));
+ obj1.arrayAdd(obj2.initReal(yMax - yMin));
+ appearDict.dictAdd(copyString("BBox"), &obj1);
+
+ // set the resource dictionary
+ if (drObj.isDict()) {
+ appearDict.dictAdd(copyString("Resources"), drObj.copy(&obj1));
+ }
+ drObj.free();
+
+ // build the appearance stream
+ appearStream = new MemStream(appearBuf->getCString(), 0,
+ appearBuf->getLength(), &appearDict);
+ appearance.free();
+ appearance.initStream(appearStream);
+
+ if (fontDict) {
+ delete fontDict;
+ }
+ ftObj.free();
+ mkObj.free();
+}
+
+// Set the current fill or stroke color, based on <a> (which should
+// have 1, 3, or 4 elements). If <adjust> is +1, color is brightened;
+// if <adjust> is -1, color is darkened; otherwise color is not
+// modified.
+void Annot::setColor(Array *a, GBool fill, int adjust) {
+ Object obj1;
+ double color[4];
+ int nComps, i;
+
+ nComps = a->getLength();
+ if (nComps > 4) {
+ nComps = 4;
+ }
+ for (i = 0; i < nComps && i < 4; ++i) {
+ if (a->get(i, &obj1)->isNum()) {
+ color[i] = obj1.getNum();
+ } else {
+ color[i] = 0;
+ }
+ obj1.free();
+ }
+ if (nComps == 4) {
+ adjust = -adjust;
+ }
+ if (adjust > 0) {
+ for (i = 0; i < nComps; ++i) {
+ color[i] = 0.5 * color[i] + 0.5;
+ }
+ } else if (adjust < 0) {
+ for (i = 0; i < nComps; ++i) {
+ color[i] = 0.5 * color[i];
+ }
+ }
+ if (nComps == 4) {
+ appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:c}\n",
+ color[0], color[1], color[2], color[3],
+ fill ? 'k' : 'K');
+ } else if (nComps == 3) {
+ appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:s}\n",
+ color[0], color[1], color[2],
+ fill ? "rg" : "RG");
+ } else {
+ appearBuf->appendf("{0:.2f} {1:c}\n",
+ color[0],
+ fill ? 'g' : 'G');
+ }
+}
+
+// Draw the variable text or caption for a field.
+void Annot::drawText(GString *text, GString *da, GfxFontDict *fontDict,
+ GBool multiline, int comb, int quadding,
+ GBool txField, GBool forceZapfDingbats) {
+ GList *daToks;
+ GString *tok;
+ GfxFont *font;
+ double fontSize, fontSize2, border, x, xPrev, y, w, w2, wMax;
+ int tfPos, tmPos, i, j, k, c;
+
+ //~ if there is no MK entry, this should use the existing content stream,
+ //~ and only replace the marked content portion of it
+ //~ (this is only relevant for Tx fields)
+
+ // parse the default appearance string
+ tfPos = tmPos = -1;
+ if (da) {
+ daToks = new GList();
+ i = 0;
+ while (i < da->getLength()) {
+ while (i < da->getLength() && Lexer::isSpace(da->getChar(i))) {
+ ++i;
+ }
+ if (i < da->getLength()) {
+ for (j = i + 1;
+ j < da->getLength() && !Lexer::isSpace(da->getChar(j));
+ ++j) ;
+ daToks->append(new GString(da, i, j - i));
+ i = j;
+ }
+ }
+ for (i = 2; i < daToks->getLength(); ++i) {
+ if (i >= 2 && !((GString *)daToks->get(i))->cmp("Tf")) {
+ tfPos = i - 2;
+ } else if (i >= 6 && !((GString *)daToks->get(i))->cmp("Tm")) {
+ tmPos = i - 6;
+ }
+ }
+ } else {
+ daToks = NULL;
+ }
+
+ // force ZapfDingbats
+ //~ this should create the font if needed (?)
+ if (forceZapfDingbats) {
+ if (tfPos >= 0) {
+ tok = (GString *)daToks->get(tfPos);
+ if (tok->cmp("/ZaDb")) {
+ tok->clear();
+ tok->append("/ZaDb");
+ }
+ }
+ }
+
+ // get the font and font size
+ font = NULL;
+ fontSize = 0;
+ if (tfPos >= 0) {
+ tok = (GString *)daToks->get(tfPos);
+ if (tok->getLength() >= 1 && tok->getChar(0) == '/') {
+ if (!fontDict || !(font = fontDict->lookup(tok->getCString() + 1))) {
+ error(-1, "Unknown font in field's DA string");
+ }
+ } else {
+ error(-1, "Invalid font name in 'Tf' operator in field's DA string");
+ }
+ tok = (GString *)daToks->get(tfPos + 1);
+ fontSize = atof(tok->getCString());
+ } else {
+ error(-1, "Missing 'Tf' operator in field's DA string");
+ }
+
+ // get the border width
+ border = borderStyle->getWidth();
+
+ // setup
+ if (txField) {
+ appearBuf->append("/Tx BMC\n");
+ }
+ appearBuf->append("q\n");
+ appearBuf->append("BT\n");
+
+ // multi-line text
+ if (multiline) {
+ // note: the comb flag is ignored in multiline mode
+
+ wMax = xMax - xMin - 2 * border - 4;
+
+ // compute font autosize
+ if (fontSize == 0) {
+ for (fontSize = 20; fontSize > 1; --fontSize) {
+ y = yMax - yMin;
+ w2 = 0;
+ i = 0;
+ while (i < text->getLength()) {
+ getNextLine(text, i, font, fontSize, wMax, &j, &w, &k);
+ if (w > w2) {
+ w2 = w;
+ }
+ i = k;
+ y -= fontSize;
+ }
+ // approximate the descender for the last line
+ if (y >= 0.33 * fontSize) {
+ break;
+ }
+ }
+ if (tfPos >= 0) {
+ tok = (GString *)daToks->get(tfPos + 1);
+ tok->clear();
+ tok->appendf("{0:.2f}", fontSize);
+ }
+ }
+
+ // starting y coordinate
+ // (note: each line of text starts with a Td operator that moves
+ // down a line)
+ y = yMax - yMin;
+
+ // set the font matrix
+ if (tmPos >= 0) {
+ tok = (GString *)daToks->get(tmPos + 4);
+ tok->clear();
+ tok->append('0');
+ tok = (GString *)daToks->get(tmPos + 5);
+ tok->clear();
+ tok->appendf("{0:.2f}", y);
+ }
+
+ // write the DA string
+ if (daToks) {
+ for (i = 0; i < daToks->getLength(); ++i) {
+ appearBuf->append((GString *)daToks->get(i))->append(' ');
+ }
+ }
+
+ // write the font matrix (if not part of the DA string)
+ if (tmPos < 0) {
+ appearBuf->appendf("1 0 0 1 0 {0:.2f} Tm\n", y);
+ }
+
+ // write a series of lines of text
+ i = 0;
+ xPrev = 0;
+ while (i < text->getLength()) {
+
+ getNextLine(text, i, font, fontSize, wMax, &j, &w, &k);
+
+ // compute text start position
+ switch (quadding) {
+ case fieldQuadLeft:
+ default:
+ x = border + 2;
+ break;
+ case fieldQuadCenter:
+ x = (xMax - xMin - w) / 2;
+ break;
+ case fieldQuadRight:
+ x = xMax - xMin - border - 2 - w;
+ break;
+ }
+
+ // draw the line
+ appearBuf->appendf("{0:.2f} {1:.2f} Td\n", x - xPrev, -fontSize);
+ appearBuf->append('(');
+ for (; i < j; ++i) {
+ c = text->getChar(i) & 0xff;
+ if (c == '(' || c == ')' || c == '\\') {
+ appearBuf->append('\\');
+ appearBuf->append(c);
+ } else if (c < 0x20 || c >= 0x80) {
+ appearBuf->appendf("\\{0:03o}", c);
+ } else {
+ appearBuf->append(c);
+ }
+ }
+ appearBuf->append(") Tj\n");
+
+ // next line
+ i = k;
+ xPrev = x;
+ }
+
+ // single-line text
+ } else {
+ //~ replace newlines with spaces? - what does Acrobat do?
+
+ // comb formatting
+ if (comb > 0) {
+
+ // compute comb spacing
+ w = (xMax - xMin - 2 * border) / comb;
+
+ // compute font autosize
+ if (fontSize == 0) {
+ fontSize = yMax - yMin - 2 * border;
+ if (w < fontSize) {
+ fontSize = w;
+ }
+ fontSize = floor(fontSize);
+ if (tfPos >= 0) {
+ tok = (GString *)daToks->get(tfPos + 1);
+ tok->clear();
+ tok->appendf("{0:.2f}", fontSize);
+ }
+ }
+
+ // compute text start position
+ switch (quadding) {
+ case fieldQuadLeft:
+ default:
+ x = border + 2;
+ break;
+ case fieldQuadCenter:
+ x = border + 2 + 0.5 * (comb - text->getLength()) * w;
+ break;
+ case fieldQuadRight:
+ x = border + 2 + (comb - text->getLength()) * w;
+ break;
+ }
+ y = 0.5 * (yMax - yMin) - 0.4 * fontSize;
+
+ // set the font matrix
+ if (tmPos >= 0) {
+ tok = (GString *)daToks->get(tmPos + 4);
+ tok->clear();
+ tok->appendf("{0:.2f}", x);
+ tok = (GString *)daToks->get(tmPos + 5);
+ tok->clear();
+ tok->appendf("{0:.2f}", y);
+ }
+
+ // write the DA string
+ if (daToks) {
+ for (i = 0; i < daToks->getLength(); ++i) {
+ appearBuf->append((GString *)daToks->get(i))->append(' ');
+ }
+ }
+
+ // write the font matrix (if not part of the DA string)
+ if (tmPos < 0) {
+ appearBuf->appendf("1 0 0 1 {0:.2f} {1:.2f} Tm\n", x, y);
+ }
+
+ // write the text string
+ //~ this should center (instead of left-justify) each character within
+ //~ its comb cell
+ for (i = 0; i < text->getLength(); ++i) {
+ if (i > 0) {
+ appearBuf->appendf("{0:.2f} 0 Td\n", w);
+ }
+ appearBuf->append('(');
+ c = text->getChar(i) & 0xff;
+ if (c == '(' || c == ')' || c == '\\') {
+ appearBuf->append('\\');
+ appearBuf->append(c);
+ } else if (c < 0x20 || c >= 0x80) {
+ appearBuf->appendf("{0:.2f} 0 Td\n", w);
+ } else {
+ appearBuf->append(c);
+ }
+ appearBuf->append(") Tj\n");
+ }
+
+ // regular (non-comb) formatting
+ } else {
+
+ // compute string width
+ if (font && !font->isCIDFont()) {
+ w = 0;
+ for (i = 0; i < text->getLength(); ++i) {
+ w += ((Gfx8BitFont *)font)->getWidth(text->getChar(i));
+ }
+ } else {
+ // otherwise, make a crude estimate
+ w = text->getLength() * 0.5;
+ }
+
+ // compute font autosize
+ if (fontSize == 0) {
+ fontSize = yMax - yMin - 2 * border;
+ fontSize2 = (xMax - xMin - 4 - 2 * border) / w;
+ if (fontSize2 < fontSize) {
+ fontSize = fontSize2;
+ }
+ fontSize = floor(fontSize);
+ if (tfPos >= 0) {
+ tok = (GString *)daToks->get(tfPos + 1);
+ tok->clear();
+ tok->appendf("{0:.2f}", fontSize);
+ }
+ }
+
+ // compute text start position
+ w *= fontSize;
+ switch (quadding) {
+ case fieldQuadLeft:
+ default:
+ x = border + 2;
+ break;
+ case fieldQuadCenter:
+ x = (xMax - xMin - w) / 2;
+ break;
+ case fieldQuadRight:
+ x = xMax - xMin - border - 2 - w;
+ break;
+ }
+ y = 0.5 * (yMax - yMin) - 0.4 * fontSize;
+
+ // set the font matrix
+ if (tmPos >= 0) {
+ tok = (GString *)daToks->get(tmPos + 4);
+ tok->clear();
+ tok->appendf("{0:.2f}", x);
+ tok = (GString *)daToks->get(tmPos + 5);
+ tok->clear();
+ tok->appendf("{0:.2f}", y);
+ }
+
+ // write the DA string
+ if (daToks) {
+ for (i = 0; i < daToks->getLength(); ++i) {
+ appearBuf->append((GString *)daToks->get(i))->append(' ');
+ }
+ }
+
+ // write the font matrix (if not part of the DA string)
+ if (tmPos < 0) {
+ appearBuf->appendf("1 0 0 1 {0:.2f} {1:.2f} Tm\n", x, y);
+ }
+
+ // write the text string
+ appearBuf->append('(');
+ for (i = 0; i < text->getLength(); ++i) {
+ c = text->getChar(i) & 0xff;
+ if (c == '(' || c == ')' || c == '\\') {
+ appearBuf->append('\\');
+ appearBuf->append(c);
+ } else if (c < 0x20 || c >= 0x80) {
+ appearBuf->appendf("\\{0:03o}", c);
+ } else {
+ appearBuf->append(c);
+ }
+ }
+ appearBuf->append(") Tj\n");
+ }
+ }
+
+ // cleanup
+ appearBuf->append("ET\n");
+ appearBuf->append("Q\n");
+ if (txField) {
+ appearBuf->append("EMC\n");
+ }
+
+ if (daToks) {
+ deleteGList(daToks, GString);
+ }
+}
+
+// Draw the variable text or caption for a field.
+void Annot::drawListBox(GString **text, GBool *selection,
+ int nOptions, int topIdx,
+ GString *da, GfxFontDict *fontDict, GBool quadding) {
+ GList *daToks;
+ GString *tok;
+ GfxFont *font;
+ double fontSize, fontSize2, border, x, y, w, wMax;
+ int tfPos, tmPos, i, j, c;
+
+ //~ if there is no MK entry, this should use the existing content stream,
+ //~ and only replace the marked content portion of it
+ //~ (this is only relevant for Tx fields)
+
+ // parse the default appearance string
+ tfPos = tmPos = -1;
+ if (da) {
+ daToks = new GList();
+ i = 0;
+ while (i < da->getLength()) {
+ while (i < da->getLength() && Lexer::isSpace(da->getChar(i))) {
+ ++i;
+ }
+ if (i < da->getLength()) {
+ for (j = i + 1;
+ j < da->getLength() && !Lexer::isSpace(da->getChar(j));
+ ++j) ;
+ daToks->append(new GString(da, i, j - i));
+ i = j;
+ }
+ }
+ for (i = 2; i < daToks->getLength(); ++i) {
+ if (i >= 2 && !((GString *)daToks->get(i))->cmp("Tf")) {
+ tfPos = i - 2;
+ } else if (i >= 6 && !((GString *)daToks->get(i))->cmp("Tm")) {
+ tmPos = i - 6;
+ }
+ }
+ } else {
+ daToks = NULL;
+ }
+
+ // get the font and font size
+ font = NULL;
+ fontSize = 0;
+ if (tfPos >= 0) {
+ tok = (GString *)daToks->get(tfPos);
+ if (tok->getLength() >= 1 && tok->getChar(0) == '/') {
+ if (!fontDict || !(font = fontDict->lookup(tok->getCString() + 1))) {
+ error(-1, "Unknown font in field's DA string");
+ }
+ } else {
+ error(-1, "Invalid font name in 'Tf' operator in field's DA string");
+ }
+ tok = (GString *)daToks->get(tfPos + 1);
+ fontSize = atof(tok->getCString());
+ } else {
+ error(-1, "Missing 'Tf' operator in field's DA string");
+ }
+
+ // get the border width
+ border = borderStyle->getWidth();
+
+ // compute font autosize
+ if (fontSize == 0) {
+ wMax = 0;
+ for (i = 0; i < nOptions; ++i) {
+ if (font && !font->isCIDFont()) {
+ w = 0;
+ for (j = 0; j < text[i]->getLength(); ++j) {
+ w += ((Gfx8BitFont *)font)->getWidth(text[i]->getChar(j));
+ }
+ } else {
+ // otherwise, make a crude estimate
+ w = text[i]->getLength() * 0.5;
+ }
+ if (w > wMax) {
+ wMax = w;
+ }
+ }
+ fontSize = yMax - yMin - 2 * border;
+ fontSize2 = (xMax - xMin - 4 - 2 * border) / wMax;
+ if (fontSize2 < fontSize) {
+ fontSize = fontSize2;
+ }
+ fontSize = floor(fontSize);
+ if (tfPos >= 0) {
+ tok = (GString *)daToks->get(tfPos + 1);
+ tok->clear();
+ tok->appendf("{0:.2f}", fontSize);
+ }
+ }
+
+ // draw the text
+ y = yMax - yMin - 1.1 * fontSize;
+ for (i = topIdx; i < nOptions; ++i) {
+
+ // setup
+ appearBuf->append("q\n");
+
+ // draw the background if selected
+ if (selection[i]) {
+ appearBuf->append("0 g f\n");
+ appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} re f\n",
+ border,
+ y - 0.2 * fontSize,
+ xMax - xMin - 2 * border,
+ 1.1 * fontSize);
+ }
+
+ // setup
+ appearBuf->append("BT\n");
+
+ // compute string width
+ if (font && !font->isCIDFont()) {
+ w = 0;
+ for (j = 0; j < text[i]->getLength(); ++j) {
+ w += ((Gfx8BitFont *)font)->getWidth(text[i]->getChar(j));
+ }
+ } else {
+ // otherwise, make a crude estimate
+ w = text[i]->getLength() * 0.5;
+ }
+
+ // compute text start position
+ w *= fontSize;
+ switch (quadding) {
+ case fieldQuadLeft:
+ default:
+ x = border + 2;
+ break;
+ case fieldQuadCenter:
+ x = (xMax - xMin - w) / 2;
+ break;
+ case fieldQuadRight:
+ x = xMax - xMin - border - 2 - w;
+ break;
+ }
+
+ // set the font matrix
+ if (tmPos >= 0) {
+ tok = (GString *)daToks->get(tmPos + 4);
+ tok->clear();
+ tok->appendf("{0:.2f}", x);
+ tok = (GString *)daToks->get(tmPos + 5);
+ tok->clear();
+ tok->appendf("{0:.2f}", y);
+ }
+
+ // write the DA string
+ if (daToks) {
+ for (j = 0; j < daToks->getLength(); ++j) {
+ appearBuf->append((GString *)daToks->get(j))->append(' ');
+ }
+ }
+
+ // write the font matrix (if not part of the DA string)
+ if (tmPos < 0) {
+ appearBuf->appendf("1 0 0 1 {0:.2f} {1:.2f} Tm\n", x, y);
+ }
+
+ // change the text color if selected
+ if (selection[i]) {
+ appearBuf->append("1 g\n");
+ }
+
+ // write the text string
+ appearBuf->append('(');
+ for (j = 0; j < text[i]->getLength(); ++j) {
+ c = text[i]->getChar(j) & 0xff;
+ if (c == '(' || c == ')' || c == '\\') {
+ appearBuf->append('\\');
+ appearBuf->append(c);
+ } else if (c < 0x20 || c >= 0x80) {
+ appearBuf->appendf("\\{0:03o}", c);
+ } else {
+ appearBuf->append(c);
+ }
+ }
+ appearBuf->append(") Tj\n");
+
+ // cleanup
+ appearBuf->append("ET\n");
+ appearBuf->append("Q\n");
+
+ // next line
+ y -= 1.1 * fontSize;
+ }
+
+ if (daToks) {
+ deleteGList(daToks, GString);
+ }
+}
+
+// Figure out how much text will fit on the next line. Returns:
+// *end = one past the last character to be included
+// *width = width of the characters start .. end-1
+// *next = index of first character on the following line
+void Annot::getNextLine(GString *text, int start,
+ GfxFont *font, double fontSize, double wMax,
+ int *end, double *width, int *next) {
+ double w, dw;
+ int j, k, c;
+
+ // figure out how much text will fit on the line
+ //~ what does Adobe do with tabs?
+ w = 0;
+ for (j = start; j < text->getLength() && w <= wMax; ++j) {
+ c = text->getChar(j) & 0xff;
+ if (c == 0x0a || c == 0x0d) {
+ break;
+ }
+ if (font && !font->isCIDFont()) {
+ dw = ((Gfx8BitFont *)font)->getWidth(c) * fontSize;
+ } else {
+ // otherwise, make a crude estimate
+ dw = 0.5 * fontSize;
+ }
+ w += dw;
+ }
+ if (w > wMax) {
+ for (k = j; k > start && text->getChar(k-1) != ' '; --k) ;
+ for (; k > start && text->getChar(k-1) == ' '; --k) ;
+ if (k > start) {
+ j = k;
+ }
+ if (j == start) {
+ // handle the pathological case where the first character is
+ // too wide to fit on the line all by itself
+ j = start + 1;
+ }
+ }
+ *end = j;
+
+ // compute the width
+ w = 0;
+ for (k = start; k < j; ++k) {
+ if (font && !font->isCIDFont()) {
+ dw = ((Gfx8BitFont *)font)->getWidth(text->getChar(k)) * fontSize;
+ } else {
+ // otherwise, make a crude estimate
+ dw = 0.5 * fontSize;
+ }
+ w += dw;
+ }
+ *width = w;
+
+ // next line
+ while (j < text->getLength() && text->getChar(j) == ' ') {
+ ++j;
+ }
+ if (j < text->getLength() && text->getChar(j) == 0x0d) {
+ ++j;
+ }
+ if (j < text->getLength() && text->getChar(j) == 0x0a) {
+ ++j;
+ }
+ *next = j;
+}
+
+// Draw an (approximate) circle of radius <r> centered at (<cx>, <cy>).
+// If <fill> is true, the circle is filled; otherwise it is stroked.
+void Annot::drawCircle(double cx, double cy, double r, GBool fill) {
+ appearBuf->appendf("{0:.2f} {1:.2f} m\n",
+ cx + r, cy);
+ appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
+ cx + r, cy + bezierCircle * r,
+ cx + bezierCircle * r, cy + r,
+ cx, cy + r);
+ appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
+ cx - bezierCircle * r, cy + r,
+ cx - r, cy + bezierCircle * r,
+ cx - r, cy);
+ appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
+ cx - r, cy - bezierCircle * r,
+ cx - bezierCircle * r, cy - r,
+ cx, cy - r);
+ appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
+ cx + bezierCircle * r, cy - r,
+ cx + r, cy - bezierCircle * r,
+ cx + r, cy);
+ appearBuf->append(fill ? "f\n" : "s\n");
+}
+
+// Draw the top-left half of an (approximate) circle of radius <r>
+// centered at (<cx>, <cy>).
+void Annot::drawCircleTopLeft(double cx, double cy, double r) {
+ double r2;
+
+ r2 = r / sqrt(2.0);
+ appearBuf->appendf("{0:.2f} {1:.2f} m\n",
+ cx + r2, cy + r2);
+ appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
+ cx + (1 - bezierCircle) * r2,
+ cy + (1 + bezierCircle) * r2,
+ cx - (1 - bezierCircle) * r2,
+ cy + (1 + bezierCircle) * r2,
+ cx - r2,
+ cy + r2);
+ appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
+ cx - (1 + bezierCircle) * r2,
+ cy + (1 - bezierCircle) * r2,
+ cx - (1 + bezierCircle) * r2,
+ cy - (1 - bezierCircle) * r2,
+ cx - r2,
+ cy - r2);
+ appearBuf->append("S\n");
+}
+
+// Draw the bottom-right half of an (approximate) circle of radius <r>
+// centered at (<cx>, <cy>).
+void Annot::drawCircleBottomRight(double cx, double cy, double r) {
+ double r2;
+
+ r2 = r / sqrt(2.0);
+ appearBuf->appendf("{0:.2f} {1:.2f} m\n",
+ cx - r2, cy - r2);
+ appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
+ cx - (1 - bezierCircle) * r2,
+ cy - (1 + bezierCircle) * r2,
+ cx + (1 - bezierCircle) * r2,
+ cy - (1 + bezierCircle) * r2,
+ cx + r2,
+ cy - r2);
+ appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n",
+ cx + (1 + bezierCircle) * r2,
+ cy - (1 - bezierCircle) * r2,
+ cx + (1 + bezierCircle) * r2,
+ cy + (1 - bezierCircle) * r2,
+ cx + r2,
+ cy + r2);
+ appearBuf->append("S\n");
+}
+
+// Look up an inheritable field dictionary entry.
+Object *Annot::fieldLookup(Dict *field, char *key, Object *obj) {
+ Dict *dict;
+ Object parent;
+
+ dict = field;
+ if (!dict->lookup(key, obj)->isNull()) {
+ return obj;
+ }
+ obj->free();
+ if (dict->lookup("Parent", &parent)->isDict()) {
+ fieldLookup(parent.getDict(), key, obj);
+ } else {
+ obj->initNull();
+ }
+ parent.free();
+ return obj;
+}
+
+void Annot::draw(Gfx *gfx, GBool printing) {
+ Object obj;
+ GBool isLink;
+
+ // check the flags
+ if ((flags & annotFlagHidden) ||
+ (printing && !(flags & annotFlagPrint)) ||
+ (!printing && (flags & annotFlagNoView))) {
+ return;
+ }
+
+ // draw the appearance stream
+ isLink = type && !type->cmp("Link");
+ appearance.fetch(xref, &obj);
+ gfx->drawAnnot(&obj, isLink ? borderStyle : (AnnotBorderStyle *)NULL,
+ xMin, yMin, xMax, yMax);
+ obj.free();
+}
+
+//------------------------------------------------------------------------
+// Annots
+//------------------------------------------------------------------------
+
+Annots::Annots(XRef *xref, Catalog *catalog, Object *annotsObj) {
+ Dict *acroForm;
+ Annot *annot;
+ Object obj1;
+ Ref ref;
+ int size;
+ int i;
+
+ annots = NULL;
+ size = 0;
+ nAnnots = 0;
+
+ acroForm = catalog->getAcroForm()->isDict() ?
+ catalog->getAcroForm()->getDict() : NULL;
+ if (annotsObj->isArray()) {
+ for (i = 0; i < annotsObj->arrayGetLength(); ++i) {
+ if (annotsObj->arrayGetNF(i, &obj1)->isRef()) {
+ ref = obj1.getRef();
+ obj1.free();
+ annotsObj->arrayGet(i, &obj1);
+ } else {
+ ref.num = ref.gen = -1;
+ }
+ if (obj1.isDict()) {
+ annot = new Annot(xref, acroForm, obj1.getDict(), &ref);
+ if (annot->isOk()) {
+ if (nAnnots >= size) {
+ size += 16;
+ annots = (Annot **)greallocn(annots, size, sizeof(Annot *));
+ }
+ annots[nAnnots++] = annot;
+ } else {
+ delete annot;
+ }
+ }
+ obj1.free();
+ }
+ }
+}
+
+Annots::~Annots() {
+ int i;
+
+ for (i = 0; i < nAnnots; ++i) {
+ delete annots[i];
+ }
+ gfree(annots);
+}
+
+void Annots::generateAppearances(Dict *acroForm) {
+ Object obj1, obj2;
+ Ref ref;
+ int i;
+
+ if (acroForm->lookup("Fields", &obj1)->isArray()) {
+ for (i = 0; i < obj1.arrayGetLength(); ++i) {
+ if (obj1.arrayGetNF(i, &obj2)->isRef()) {
+ ref = obj2.getRef();
+ obj2.free();
+ obj1.arrayGet(i, &obj2);
+ } else {
+ ref.num = ref.gen = -1;
+ }
+ if (obj2.isDict()) {
+ scanFieldAppearances(obj2.getDict(), &ref, NULL, acroForm);
+ }
+ obj2.free();
+ }
+ }
+ obj1.free();
+}
+
+void Annots::scanFieldAppearances(Dict *node, Ref *ref, Dict *parent,
+ Dict *acroForm) {
+ Annot *annot;
+ Object obj1, obj2;
+ Ref ref2;
+ int i;
+
+ // non-terminal node: scan the children
+ if (node->lookup("Kids", &obj1)->isArray()) {
+ for (i = 0; i < obj1.arrayGetLength(); ++i) {
+ if (obj1.arrayGetNF(i, &obj2)->isRef()) {
+ ref2 = obj2.getRef();
+ obj2.free();
+ obj1.arrayGet(i, &obj2);
+ } else {
+ ref2.num = ref2.gen = -1;
+ }
+ if (obj2.isDict()) {
+ scanFieldAppearances(obj2.getDict(), &ref2, node, acroForm);
+ }
+ obj2.free();
+ }
+ obj1.free();
+ return;
+ }
+ obj1.free();
+
+ // terminal node: this is either a combined annot/field dict, or an
+ // annot dict whose parent is a field
+ if ((annot = findAnnot(ref))) {
+ node->lookupNF("Parent", &obj1);
+ if (!parent || !obj1.isNull()) {
+ annot->generateFieldAppearance(node, node, acroForm);
+ } else {
+ annot->generateFieldAppearance(parent, node, acroForm);
+ }
+ obj1.free();
+ }
+}
+
+Annot *Annots::findAnnot(Ref *ref) {
+ int i;
+
+ for (i = 0; i < nAnnots; ++i) {
+ if (annots[i]->match(ref)) {
+ return annots[i];
+ }
+ }
+ return NULL;
+}
diff --git a/kpdf/xpdf/xpdf/Annot.h b/kpdf/xpdf/xpdf/Annot.h
new file mode 100644
index 00000000..5c4de39c
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Annot.h
@@ -0,0 +1,143 @@
+//========================================================================
+//
+// Annot.h
+//
+// Copyright 2000-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef ANNOT_H
+#define ANNOT_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+class XRef;
+class Catalog;
+class Gfx;
+class GfxFont;
+class GfxFontDict;
+
+//------------------------------------------------------------------------
+// AnnotBorderStyle
+//------------------------------------------------------------------------
+
+enum AnnotBorderType {
+ annotBorderSolid,
+ annotBorderDashed,
+ annotBorderBeveled,
+ annotBorderInset,
+ annotBorderUnderlined
+};
+
+class AnnotBorderStyle {
+public:
+
+ AnnotBorderStyle(AnnotBorderType typeA, double widthA,
+ double *dashA, int dashLengthA,
+ double rA, double gA, double bA);
+ ~AnnotBorderStyle();
+
+ AnnotBorderType getType() { return type; }
+ double getWidth() { return width; }
+ void getDash(double **dashA, int *dashLengthA)
+ { *dashA = dash; *dashLengthA = dashLength; }
+ void getColor(double *rA, double *gA, double *bA)
+ { *rA = r; *gA = g; *bA = b; }
+
+private:
+
+ AnnotBorderType type;
+ double width;
+ double *dash;
+ int dashLength;
+ double r, g, b;
+};
+
+//------------------------------------------------------------------------
+// Annot
+//------------------------------------------------------------------------
+
+class Annot {
+public:
+
+ Annot(XRef *xrefA, Dict *acroForm, Dict *dict, Ref *refA);
+ ~Annot();
+ GBool isOk() { return ok; }
+
+ void draw(Gfx *gfx, GBool printing);
+
+ // Get appearance object.
+ Object *getAppearance(Object *obj) { return appearance.fetch(xref, obj); }
+
+ AnnotBorderStyle *getBorderStyle() { return borderStyle; }
+
+ GBool match(Ref *refA)
+ { return ref.num == refA->num && ref.gen == refA->gen; }
+
+ void generateFieldAppearance(Dict *field, Dict *annot, Dict *acroForm);
+
+private:
+
+ void setColor(Array *a, GBool fill, int adjust);
+ void drawText(GString *text, GString *da, GfxFontDict *fontDict,
+ GBool multiline, int comb, int quadding,
+ GBool txField, GBool forceZapfDingbats);
+ void drawListBox(GString **text, GBool *selection,
+ int nOptions, int topIdx,
+ GString *da, GfxFontDict *fontDict, GBool quadding);
+ void getNextLine(GString *text, int start,
+ GfxFont *font, double fontSize, double wMax,
+ int *end, double *width, int *next);
+ void drawCircle(double cx, double cy, double r, GBool fill);
+ void drawCircleTopLeft(double cx, double cy, double r);
+ void drawCircleBottomRight(double cx, double cy, double r);
+ Object *fieldLookup(Dict *field, char *key, Object *obj);
+
+ XRef *xref; // the xref table for this PDF file
+ Ref ref; // object ref identifying this annotation
+ GString *type; // annotation type
+ Object appearance; // a reference to the Form XObject stream
+ // for the normal appearance
+ GString *appearBuf;
+ double xMin, yMin, // annotation rectangle
+ xMax, yMax;
+ Guint flags;
+ AnnotBorderStyle *borderStyle;
+ GBool ok;
+};
+
+//------------------------------------------------------------------------
+// Annots
+//------------------------------------------------------------------------
+
+class Annots {
+public:
+
+ // Build a list of Annot objects.
+ Annots(XRef *xref, Catalog *catalog, Object *annotsObj);
+
+ ~Annots();
+
+ // Iterate through list of annotations.
+ int getNumAnnots() { return nAnnots; }
+ Annot *getAnnot(int i) { return annots[i]; }
+
+ // (Re)generate the appearance streams for all annotations belonging
+ // to a form field.
+ void generateAppearances(Dict *acroForm);
+
+private:
+
+ void scanFieldAppearances(Dict *node, Ref *ref, Dict *parent,
+ Dict *acroForm);
+ Annot *findAnnot(Ref *ref);
+
+ Annot **annots;
+ int nAnnots;
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/Array.cc b/kpdf/xpdf/xpdf/Array.cc
new file mode 100644
index 00000000..8232037b
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Array.cc
@@ -0,0 +1,88 @@
+//========================================================================
+//
+// Array.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <stddef.h>
+#include "gmem.h"
+#include "Object.h"
+#include "Array.h"
+
+//------------------------------------------------------------------------
+// Array
+//------------------------------------------------------------------------
+
+Array::Array(XRef *xrefA) {
+ xref = xrefA;
+ elems = NULL;
+ size = length = 0;
+ ref = 1;
+}
+
+Array::~Array() {
+ int i;
+
+ for (i = 0; i < length; ++i)
+ elems[i].free();
+ gfree(elems);
+}
+
+void Array::add(Object *elem) {
+ if (length == size) {
+ if (length == 0) {
+ size = 8;
+ } else {
+ size *= 2;
+ }
+ elems = (Object *)greallocn(elems, size, sizeof(Object));
+ }
+ elems[length] = *elem;
+ ++length;
+}
+
+Object *Array::get(int i, Object *obj) {
+ if (i < 0 || i >= length) {
+#ifdef DEBUG_MEM
+ abort();
+#else
+ return obj->initNull();
+#endif
+ }
+ return elems[i].fetch(xref, obj);
+}
+
+Object *Array::getNF(int i, Object *obj) {
+ if (i < 0 || i >= length) {
+#ifdef DEBUG_MEM
+ abort();
+#else
+ return obj->initNull();
+#endif
+ }
+ return elems[i].copy(obj);
+}
+
+GBool Array::getString(int i, GString *string)
+{
+ Object obj;
+
+ if (getNF(i, &obj)->isString()) {
+ string->clear();
+ string->append(obj.getString());
+ obj.free();
+ return gTrue;
+ } else {
+ obj.free();
+ return gFalse;
+ }
+}
diff --git a/kpdf/xpdf/xpdf/Array.h b/kpdf/xpdf/xpdf/Array.h
new file mode 100644
index 00000000..1ef65dba
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Array.h
@@ -0,0 +1,59 @@
+//========================================================================
+//
+// Array.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef ARRAY_H
+#define ARRAY_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "Object.h"
+
+class XRef;
+
+//------------------------------------------------------------------------
+// Array
+//------------------------------------------------------------------------
+
+class Array {
+public:
+
+ // Constructor.
+ Array(XRef *xrefA);
+
+ // Destructor.
+ ~Array();
+
+ // Reference counting.
+ int incRef() { return ++ref; }
+ int decRef() { return --ref; }
+
+ // Get number of elements.
+ int getLength() { return length; }
+
+ // Add an element.
+ void add(Object *elem);
+
+ // Accessors.
+ Object *get(int i, Object *obj);
+ Object *getNF(int i, Object *obj);
+ GBool getString(int i, GString *string);
+
+private:
+
+ XRef *xref; // the xref table for this PDF file
+ Object *elems; // array of elements
+ int size; // size of <elems> array
+ int length; // number of elements in array
+ int ref; // reference count
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/BuiltinFont.cc b/kpdf/xpdf/xpdf/BuiltinFont.cc
new file mode 100644
index 00000000..ce989571
--- /dev/null
+++ b/kpdf/xpdf/xpdf/BuiltinFont.cc
@@ -0,0 +1,65 @@
+//========================================================================
+//
+// BuiltinFont.cc
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include "gmem.h"
+#include "FontEncodingTables.h"
+#include "BuiltinFont.h"
+
+//------------------------------------------------------------------------
+
+BuiltinFontWidths::BuiltinFontWidths(BuiltinFontWidth *widths, int sizeA) {
+ int i, h;
+
+ size = sizeA;
+ tab = (BuiltinFontWidth **)gmallocn(size, sizeof(BuiltinFontWidth *));
+ for (i = 0; i < size; ++i) {
+ tab[i] = NULL;
+ }
+ for (i = 0; i < sizeA; ++i) {
+ h = hash(widths[i].name);
+ widths[i].next = tab[h];
+ tab[h] = &widths[i];
+ }
+}
+
+BuiltinFontWidths::~BuiltinFontWidths() {
+ gfree(tab);
+}
+
+GBool BuiltinFontWidths::getWidth(char *name, Gushort *width) {
+ int h;
+ BuiltinFontWidth *p;
+
+ h = hash(name);
+ for (p = tab[h]; p; p = p->next) {
+ if (!strcmp(p->name, name)) {
+ *width = p->width;
+ return gTrue;
+ }
+ }
+ return gFalse;
+}
+
+int BuiltinFontWidths::hash(char *name) {
+ char *p;
+ unsigned int h;
+
+ h = 0;
+ for (p = name; *p; ++p) {
+ h = 17 * h + (int)(*p & 0xff);
+ }
+ return (int)(h % size);
+}
diff --git a/kpdf/xpdf/xpdf/BuiltinFont.h b/kpdf/xpdf/xpdf/BuiltinFont.h
new file mode 100644
index 00000000..903ed19e
--- /dev/null
+++ b/kpdf/xpdf/xpdf/BuiltinFont.h
@@ -0,0 +1,57 @@
+//========================================================================
+//
+// BuiltinFont.h
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef BUILTINFONT_H
+#define BUILTINFONT_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+
+struct BuiltinFont;
+class BuiltinFontWidths;
+
+//------------------------------------------------------------------------
+
+struct BuiltinFont {
+ char *name;
+ char **defaultBaseEnc;
+ short ascent;
+ short descent;
+ short bbox[4];
+ BuiltinFontWidths *widths;
+};
+
+//------------------------------------------------------------------------
+
+struct BuiltinFontWidth {
+ char *name;
+ Gushort width;
+ BuiltinFontWidth *next;
+};
+
+class BuiltinFontWidths {
+public:
+
+ BuiltinFontWidths(BuiltinFontWidth *widths, int sizeA);
+ ~BuiltinFontWidths();
+ GBool getWidth(char *name, Gushort *width);
+
+private:
+
+ int hash(char *name);
+
+ BuiltinFontWidth **tab;
+ int size;
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/BuiltinFontTables.cc b/kpdf/xpdf/xpdf/BuiltinFontTables.cc
new file mode 100644
index 00000000..9c362389
--- /dev/null
+++ b/kpdf/xpdf/xpdf/BuiltinFontTables.cc
@@ -0,0 +1,4284 @@
+//========================================================================
+//
+// BuiltinFontTables.cc
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+#include <stdlib.h>
+#include "FontEncodingTables.h"
+#include "BuiltinFontTables.h"
+
+static BuiltinFontWidth courierWidthsTab[] = {
+ { "Ntilde", 600, NULL },
+ { "rcaron", 600, NULL },
+ { "kcommaaccent", 600, NULL },
+ { "Ncommaaccent", 600, NULL },
+ { "Zacute", 600, NULL },
+ { "comma", 600, NULL },
+ { "cedilla", 600, NULL },
+ { "plusminus", 600, NULL },
+ { "circumflex", 600, NULL },
+ { "dotaccent", 600, NULL },
+ { "edotaccent", 600, NULL },
+ { "asciitilde", 600, NULL },
+ { "colon", 600, NULL },
+ { "onehalf", 600, NULL },
+ { "dollar", 600, NULL },
+ { "Lcaron", 600, NULL },
+ { "ntilde", 600, NULL },
+ { "Aogonek", 600, NULL },
+ { "ncommaaccent", 600, NULL },
+ { "minus", 600, NULL },
+ { "Iogonek", 600, NULL },
+ { "zacute", 600, NULL },
+ { "yen", 600, NULL },
+ { "space", 600, NULL },
+ { "Omacron", 600, NULL },
+ { "questiondown", 600, NULL },
+ { "emdash", 600, NULL },
+ { "Agrave", 600, NULL },
+ { "three", 600, NULL },
+ { "numbersign", 600, NULL },
+ { "lcaron", 600, NULL },
+ { "A", 600, NULL },
+ { "B", 600, NULL },
+ { "C", 600, NULL },
+ { "aogonek", 600, NULL },
+ { "D", 600, NULL },
+ { "E", 600, NULL },
+ { "onequarter", 600, NULL },
+ { "F", 600, NULL },
+ { "G", 600, NULL },
+ { "H", 600, NULL },
+ { "I", 600, NULL },
+ { "J", 600, NULL },
+ { "K", 600, NULL },
+ { "iogonek", 600, NULL },
+ { "L", 600, NULL },
+ { "backslash", 600, NULL },
+ { "periodcentered", 600, NULL },
+ { "M", 600, NULL },
+ { "N", 600, NULL },
+ { "omacron", 600, NULL },
+ { "Tcommaaccent", 600, NULL },
+ { "O", 600, NULL },
+ { "P", 600, NULL },
+ { "Q", 600, NULL },
+ { "Uhungarumlaut", 600, NULL },
+ { "R", 600, NULL },
+ { "Aacute", 600, NULL },
+ { "caron", 600, NULL },
+ { "S", 600, NULL },
+ { "T", 600, NULL },
+ { "U", 600, NULL },
+ { "agrave", 600, NULL },
+ { "V", 600, NULL },
+ { "W", 600, NULL },
+ { "equal", 600, NULL },
+ { "question", 600, NULL },
+ { "X", 600, NULL },
+ { "Y", 600, NULL },
+ { "Z", 600, NULL },
+ { "four", 600, NULL },
+ { "a", 600, NULL },
+ { "Gcommaaccent", 600, NULL },
+ { "b", 600, NULL },
+ { "c", 600, NULL },
+ { "d", 600, NULL },
+ { "e", 600, NULL },
+ { "f", 600, NULL },
+ { "g", 600, NULL },
+ { "bullet", 600, NULL },
+ { "h", 600, NULL },
+ { "i", 600, NULL },
+ { "Oslash", 600, NULL },
+ { "dagger", 600, NULL },
+ { "j", 600, NULL },
+ { "k", 600, NULL },
+ { "l", 600, NULL },
+ { "m", 600, NULL },
+ { "n", 600, NULL },
+ { "tcommaaccent", 600, NULL },
+ { "o", 600, NULL },
+ { "ordfeminine", 600, NULL },
+ { "ring", 600, NULL },
+ { "p", 600, NULL },
+ { "q", 600, NULL },
+ { "uhungarumlaut", 600, NULL },
+ { "r", 600, NULL },
+ { "twosuperior", 600, NULL },
+ { "aacute", 600, NULL },
+ { "s", 600, NULL },
+ { "OE", 600, NULL },
+ { "t", 600, NULL },
+ { "divide", 600, NULL },
+ { "u", 600, NULL },
+ { "Ccaron", 600, NULL },
+ { "v", 600, NULL },
+ { "w", 600, NULL },
+ { "x", 600, NULL },
+ { "y", 600, NULL },
+ { "z", 600, NULL },
+ { "Gbreve", 600, NULL },
+ { "commaaccent", 600, NULL },
+ { "hungarumlaut", 600, NULL },
+ { "Idotaccent", 600, NULL },
+ { "Nacute", 600, NULL },
+ { "quotedbl", 600, NULL },
+ { "gcommaaccent", 600, NULL },
+ { "mu", 600, NULL },
+ { "greaterequal", 600, NULL },
+ { "Scaron", 600, NULL },
+ { "Lslash", 600, NULL },
+ { "semicolon", 600, NULL },
+ { "oslash", 600, NULL },
+ { "lessequal", 600, NULL },
+ { "lozenge", 600, NULL },
+ { "parenright", 600, NULL },
+ { "ccaron", 600, NULL },
+ { "Ecircumflex", 600, NULL },
+ { "gbreve", 600, NULL },
+ { "trademark", 600, NULL },
+ { "daggerdbl", 600, NULL },
+ { "nacute", 600, NULL },
+ { "macron", 600, NULL },
+ { "Otilde", 600, NULL },
+ { "Emacron", 600, NULL },
+ { "ellipsis", 600, NULL },
+ { "scaron", 600, NULL },
+ { "AE", 600, NULL },
+ { "Ucircumflex", 600, NULL },
+ { "lslash", 600, NULL },
+ { "quotedblleft", 600, NULL },
+ { "hyphen", 600, NULL },
+ { "guilsinglright", 600, NULL },
+ { "quotesingle", 600, NULL },
+ { "eight", 600, NULL },
+ { "exclamdown", 600, NULL },
+ { "endash", 600, NULL },
+ { "oe", 600, NULL },
+ { "Abreve", 600, NULL },
+ { "Umacron", 600, NULL },
+ { "ecircumflex", 600, NULL },
+ { "Adieresis", 600, NULL },
+ { "copyright", 600, NULL },
+ { "Egrave", 600, NULL },
+ { "slash", 600, NULL },
+ { "Edieresis", 600, NULL },
+ { "otilde", 600, NULL },
+ { "Idieresis", 600, NULL },
+ { "parenleft", 600, NULL },
+ { "one", 600, NULL },
+ { "emacron", 600, NULL },
+ { "Odieresis", 600, NULL },
+ { "ucircumflex", 600, NULL },
+ { "bracketleft", 600, NULL },
+ { "Ugrave", 600, NULL },
+ { "quoteright", 600, NULL },
+ { "Udieresis", 600, NULL },
+ { "perthousand", 600, NULL },
+ { "Ydieresis", 600, NULL },
+ { "umacron", 600, NULL },
+ { "abreve", 600, NULL },
+ { "Eacute", 600, NULL },
+ { "adieresis", 600, NULL },
+ { "egrave", 600, NULL },
+ { "edieresis", 600, NULL },
+ { "idieresis", 600, NULL },
+ { "Eth", 600, NULL },
+ { "ae", 600, NULL },
+ { "asterisk", 600, NULL },
+ { "odieresis", 600, NULL },
+ { "Uacute", 600, NULL },
+ { "ugrave", 600, NULL },
+ { "five", 600, NULL },
+ { "nine", 600, NULL },
+ { "udieresis", 600, NULL },
+ { "Zcaron", 600, NULL },
+ { "Scommaaccent", 600, NULL },
+ { "threequarters", 600, NULL },
+ { "guillemotright", 600, NULL },
+ { "Ccedilla", 600, NULL },
+ { "ydieresis", 600, NULL },
+ { "tilde", 600, NULL },
+ { "at", 600, NULL },
+ { "eacute", 600, NULL },
+ { "underscore", 600, NULL },
+ { "Euro", 600, NULL },
+ { "Dcroat", 600, NULL },
+ { "zero", 600, NULL },
+ { "multiply", 600, NULL },
+ { "eth", 600, NULL },
+ { "Scedilla", 600, NULL },
+ { "Racute", 600, NULL },
+ { "Ograve", 600, NULL },
+ { "partialdiff", 600, NULL },
+ { "uacute", 600, NULL },
+ { "braceleft", 600, NULL },
+ { "Thorn", 600, NULL },
+ { "zcaron", 600, NULL },
+ { "scommaaccent", 600, NULL },
+ { "ccedilla", 600, NULL },
+ { "Dcaron", 600, NULL },
+ { "dcroat", 600, NULL },
+ { "scedilla", 600, NULL },
+ { "Oacute", 600, NULL },
+ { "Ocircumflex", 600, NULL },
+ { "ogonek", 600, NULL },
+ { "ograve", 600, NULL },
+ { "racute", 600, NULL },
+ { "Tcaron", 600, NULL },
+ { "Eogonek", 600, NULL },
+ { "thorn", 600, NULL },
+ { "degree", 600, NULL },
+ { "registered", 600, NULL },
+ { "radical", 600, NULL },
+ { "Aring", 600, NULL },
+ { "percent", 600, NULL },
+ { "six", 600, NULL },
+ { "paragraph", 600, NULL },
+ { "dcaron", 600, NULL },
+ { "Uogonek", 600, NULL },
+ { "two", 600, NULL },
+ { "summation", 600, NULL },
+ { "Igrave", 600, NULL },
+ { "Lacute", 600, NULL },
+ { "ocircumflex", 600, NULL },
+ { "oacute", 600, NULL },
+ { "Uring", 600, NULL },
+ { "Lcommaaccent", 600, NULL },
+ { "tcaron", 600, NULL },
+ { "eogonek", 600, NULL },
+ { "Delta", 600, NULL },
+ { "Ohungarumlaut", 600, NULL },
+ { "asciicircum", 600, NULL },
+ { "aring", 600, NULL },
+ { "grave", 600, NULL },
+ { "uogonek", 600, NULL },
+ { "bracketright", 600, NULL },
+ { "ampersand", 600, NULL },
+ { "Iacute", 600, NULL },
+ { "lacute", 600, NULL },
+ { "igrave", 600, NULL },
+ { "Ncaron", 600, NULL },
+ { "plus", 600, NULL },
+ { "uring", 600, NULL },
+ { "quotesinglbase", 600, NULL },
+ { "lcommaaccent", 600, NULL },
+ { "Yacute", 600, NULL },
+ { "ohungarumlaut", 600, NULL },
+ { "threesuperior", 600, NULL },
+ { "acute", 600, NULL },
+ { "section", 600, NULL },
+ { "dieresis", 600, NULL },
+ { "quotedblbase", 600, NULL },
+ { "iacute", 600, NULL },
+ { "ncaron", 600, NULL },
+ { "florin", 600, NULL },
+ { "yacute", 600, NULL },
+ { "Rcommaaccent", 600, NULL },
+ { "fi", 600, NULL },
+ { "fl", 600, NULL },
+ { "Acircumflex", 600, NULL },
+ { "Cacute", 600, NULL },
+ { "Icircumflex", 600, NULL },
+ { "guillemotleft", 600, NULL },
+ { "germandbls", 600, NULL },
+ { "seven", 600, NULL },
+ { "Amacron", 600, NULL },
+ { "Sacute", 600, NULL },
+ { "ordmasculine", 600, NULL },
+ { "dotlessi", 600, NULL },
+ { "sterling", 600, NULL },
+ { "notequal", 600, NULL },
+ { "Imacron", 600, NULL },
+ { "rcommaaccent", 600, NULL },
+ { "Zdotaccent", 600, NULL },
+ { "acircumflex", 600, NULL },
+ { "cacute", 600, NULL },
+ { "Ecaron", 600, NULL },
+ { "braceright", 600, NULL },
+ { "icircumflex", 600, NULL },
+ { "quotedblright", 600, NULL },
+ { "amacron", 600, NULL },
+ { "sacute", 600, NULL },
+ { "imacron", 600, NULL },
+ { "cent", 600, NULL },
+ { "currency", 600, NULL },
+ { "logicalnot", 600, NULL },
+ { "zdotaccent", 600, NULL },
+ { "Atilde", 600, NULL },
+ { "breve", 600, NULL },
+ { "bar", 600, NULL },
+ { "fraction", 600, NULL },
+ { "less", 600, NULL },
+ { "ecaron", 600, NULL },
+ { "guilsinglleft", 600, NULL },
+ { "exclam", 600, NULL },
+ { "period", 600, NULL },
+ { "Rcaron", 600, NULL },
+ { "Kcommaaccent", 600, NULL },
+ { "greater", 600, NULL },
+ { "atilde", 600, NULL },
+ { "brokenbar", 600, NULL },
+ { "quoteleft", 600, NULL },
+ { "Edotaccent", 600, NULL },
+ { "onesuperior", 600, NULL }
+};
+
+static BuiltinFontWidth courierBoldWidthsTab[] = {
+ { "Ntilde", 600, NULL },
+ { "rcaron", 600, NULL },
+ { "kcommaaccent", 600, NULL },
+ { "Ncommaaccent", 600, NULL },
+ { "Zacute", 600, NULL },
+ { "comma", 600, NULL },
+ { "cedilla", 600, NULL },
+ { "plusminus", 600, NULL },
+ { "circumflex", 600, NULL },
+ { "dotaccent", 600, NULL },
+ { "edotaccent", 600, NULL },
+ { "asciitilde", 600, NULL },
+ { "colon", 600, NULL },
+ { "onehalf", 600, NULL },
+ { "dollar", 600, NULL },
+ { "Lcaron", 600, NULL },
+ { "ntilde", 600, NULL },
+ { "Aogonek", 600, NULL },
+ { "ncommaaccent", 600, NULL },
+ { "minus", 600, NULL },
+ { "Iogonek", 600, NULL },
+ { "zacute", 600, NULL },
+ { "yen", 600, NULL },
+ { "space", 600, NULL },
+ { "Omacron", 600, NULL },
+ { "questiondown", 600, NULL },
+ { "emdash", 600, NULL },
+ { "Agrave", 600, NULL },
+ { "three", 600, NULL },
+ { "numbersign", 600, NULL },
+ { "lcaron", 600, NULL },
+ { "A", 600, NULL },
+ { "B", 600, NULL },
+ { "C", 600, NULL },
+ { "aogonek", 600, NULL },
+ { "D", 600, NULL },
+ { "E", 600, NULL },
+ { "onequarter", 600, NULL },
+ { "F", 600, NULL },
+ { "G", 600, NULL },
+ { "H", 600, NULL },
+ { "I", 600, NULL },
+ { "J", 600, NULL },
+ { "K", 600, NULL },
+ { "iogonek", 600, NULL },
+ { "backslash", 600, NULL },
+ { "L", 600, NULL },
+ { "periodcentered", 600, NULL },
+ { "M", 600, NULL },
+ { "N", 600, NULL },
+ { "omacron", 600, NULL },
+ { "Tcommaaccent", 600, NULL },
+ { "O", 600, NULL },
+ { "P", 600, NULL },
+ { "Q", 600, NULL },
+ { "Uhungarumlaut", 600, NULL },
+ { "R", 600, NULL },
+ { "Aacute", 600, NULL },
+ { "caron", 600, NULL },
+ { "S", 600, NULL },
+ { "T", 600, NULL },
+ { "U", 600, NULL },
+ { "agrave", 600, NULL },
+ { "V", 600, NULL },
+ { "W", 600, NULL },
+ { "X", 600, NULL },
+ { "question", 600, NULL },
+ { "equal", 600, NULL },
+ { "Y", 600, NULL },
+ { "Z", 600, NULL },
+ { "four", 600, NULL },
+ { "a", 600, NULL },
+ { "Gcommaaccent", 600, NULL },
+ { "b", 600, NULL },
+ { "c", 600, NULL },
+ { "d", 600, NULL },
+ { "e", 600, NULL },
+ { "f", 600, NULL },
+ { "g", 600, NULL },
+ { "bullet", 600, NULL },
+ { "h", 600, NULL },
+ { "i", 600, NULL },
+ { "Oslash", 600, NULL },
+ { "dagger", 600, NULL },
+ { "j", 600, NULL },
+ { "k", 600, NULL },
+ { "l", 600, NULL },
+ { "m", 600, NULL },
+ { "n", 600, NULL },
+ { "tcommaaccent", 600, NULL },
+ { "o", 600, NULL },
+ { "ordfeminine", 600, NULL },
+ { "ring", 600, NULL },
+ { "p", 600, NULL },
+ { "q", 600, NULL },
+ { "uhungarumlaut", 600, NULL },
+ { "r", 600, NULL },
+ { "twosuperior", 600, NULL },
+ { "aacute", 600, NULL },
+ { "s", 600, NULL },
+ { "OE", 600, NULL },
+ { "t", 600, NULL },
+ { "divide", 600, NULL },
+ { "u", 600, NULL },
+ { "Ccaron", 600, NULL },
+ { "v", 600, NULL },
+ { "w", 600, NULL },
+ { "x", 600, NULL },
+ { "y", 600, NULL },
+ { "z", 600, NULL },
+ { "Gbreve", 600, NULL },
+ { "commaaccent", 600, NULL },
+ { "hungarumlaut", 600, NULL },
+ { "Idotaccent", 600, NULL },
+ { "Nacute", 600, NULL },
+ { "quotedbl", 600, NULL },
+ { "gcommaaccent", 600, NULL },
+ { "mu", 600, NULL },
+ { "greaterequal", 600, NULL },
+ { "Scaron", 600, NULL },
+ { "Lslash", 600, NULL },
+ { "semicolon", 600, NULL },
+ { "oslash", 600, NULL },
+ { "lessequal", 600, NULL },
+ { "lozenge", 600, NULL },
+ { "parenright", 600, NULL },
+ { "ccaron", 600, NULL },
+ { "Ecircumflex", 600, NULL },
+ { "gbreve", 600, NULL },
+ { "trademark", 600, NULL },
+ { "daggerdbl", 600, NULL },
+ { "nacute", 600, NULL },
+ { "macron", 600, NULL },
+ { "Otilde", 600, NULL },
+ { "Emacron", 600, NULL },
+ { "ellipsis", 600, NULL },
+ { "scaron", 600, NULL },
+ { "AE", 600, NULL },
+ { "Ucircumflex", 600, NULL },
+ { "lslash", 600, NULL },
+ { "quotedblleft", 600, NULL },
+ { "guilsinglright", 600, NULL },
+ { "hyphen", 600, NULL },
+ { "quotesingle", 600, NULL },
+ { "eight", 600, NULL },
+ { "exclamdown", 600, NULL },
+ { "endash", 600, NULL },
+ { "oe", 600, NULL },
+ { "Abreve", 600, NULL },
+ { "Umacron", 600, NULL },
+ { "ecircumflex", 600, NULL },
+ { "Adieresis", 600, NULL },
+ { "copyright", 600, NULL },
+ { "Egrave", 600, NULL },
+ { "slash", 600, NULL },
+ { "Edieresis", 600, NULL },
+ { "otilde", 600, NULL },
+ { "Idieresis", 600, NULL },
+ { "parenleft", 600, NULL },
+ { "one", 600, NULL },
+ { "emacron", 600, NULL },
+ { "Odieresis", 600, NULL },
+ { "ucircumflex", 600, NULL },
+ { "bracketleft", 600, NULL },
+ { "Ugrave", 600, NULL },
+ { "quoteright", 600, NULL },
+ { "Udieresis", 600, NULL },
+ { "perthousand", 600, NULL },
+ { "Ydieresis", 600, NULL },
+ { "umacron", 600, NULL },
+ { "abreve", 600, NULL },
+ { "Eacute", 600, NULL },
+ { "adieresis", 600, NULL },
+ { "egrave", 600, NULL },
+ { "edieresis", 600, NULL },
+ { "idieresis", 600, NULL },
+ { "Eth", 600, NULL },
+ { "ae", 600, NULL },
+ { "asterisk", 600, NULL },
+ { "odieresis", 600, NULL },
+ { "Uacute", 600, NULL },
+ { "ugrave", 600, NULL },
+ { "nine", 600, NULL },
+ { "five", 600, NULL },
+ { "udieresis", 600, NULL },
+ { "Zcaron", 600, NULL },
+ { "Scommaaccent", 600, NULL },
+ { "threequarters", 600, NULL },
+ { "guillemotright", 600, NULL },
+ { "Ccedilla", 600, NULL },
+ { "ydieresis", 600, NULL },
+ { "tilde", 600, NULL },
+ { "at", 600, NULL },
+ { "eacute", 600, NULL },
+ { "underscore", 600, NULL },
+ { "Euro", 600, NULL },
+ { "Dcroat", 600, NULL },
+ { "multiply", 600, NULL },
+ { "zero", 600, NULL },
+ { "eth", 600, NULL },
+ { "Scedilla", 600, NULL },
+ { "Ograve", 600, NULL },
+ { "Racute", 600, NULL },
+ { "partialdiff", 600, NULL },
+ { "uacute", 600, NULL },
+ { "braceleft", 600, NULL },
+ { "Thorn", 600, NULL },
+ { "zcaron", 600, NULL },
+ { "scommaaccent", 600, NULL },
+ { "ccedilla", 600, NULL },
+ { "Dcaron", 600, NULL },
+ { "dcroat", 600, NULL },
+ { "Ocircumflex", 600, NULL },
+ { "Oacute", 600, NULL },
+ { "scedilla", 600, NULL },
+ { "ogonek", 600, NULL },
+ { "ograve", 600, NULL },
+ { "racute", 600, NULL },
+ { "Tcaron", 600, NULL },
+ { "Eogonek", 600, NULL },
+ { "thorn", 600, NULL },
+ { "degree", 600, NULL },
+ { "registered", 600, NULL },
+ { "radical", 600, NULL },
+ { "Aring", 600, NULL },
+ { "percent", 600, NULL },
+ { "six", 600, NULL },
+ { "paragraph", 600, NULL },
+ { "dcaron", 600, NULL },
+ { "Uogonek", 600, NULL },
+ { "two", 600, NULL },
+ { "summation", 600, NULL },
+ { "Igrave", 600, NULL },
+ { "Lacute", 600, NULL },
+ { "ocircumflex", 600, NULL },
+ { "oacute", 600, NULL },
+ { "Uring", 600, NULL },
+ { "Lcommaaccent", 600, NULL },
+ { "tcaron", 600, NULL },
+ { "eogonek", 600, NULL },
+ { "Delta", 600, NULL },
+ { "Ohungarumlaut", 600, NULL },
+ { "asciicircum", 600, NULL },
+ { "aring", 600, NULL },
+ { "grave", 600, NULL },
+ { "uogonek", 600, NULL },
+ { "bracketright", 600, NULL },
+ { "Iacute", 600, NULL },
+ { "ampersand", 600, NULL },
+ { "igrave", 600, NULL },
+ { "lacute", 600, NULL },
+ { "Ncaron", 600, NULL },
+ { "plus", 600, NULL },
+ { "uring", 600, NULL },
+ { "quotesinglbase", 600, NULL },
+ { "lcommaaccent", 600, NULL },
+ { "Yacute", 600, NULL },
+ { "ohungarumlaut", 600, NULL },
+ { "threesuperior", 600, NULL },
+ { "acute", 600, NULL },
+ { "section", 600, NULL },
+ { "dieresis", 600, NULL },
+ { "iacute", 600, NULL },
+ { "quotedblbase", 600, NULL },
+ { "ncaron", 600, NULL },
+ { "florin", 600, NULL },
+ { "yacute", 600, NULL },
+ { "Rcommaaccent", 600, NULL },
+ { "fi", 600, NULL },
+ { "fl", 600, NULL },
+ { "Acircumflex", 600, NULL },
+ { "Cacute", 600, NULL },
+ { "Icircumflex", 600, NULL },
+ { "guillemotleft", 600, NULL },
+ { "germandbls", 600, NULL },
+ { "Amacron", 600, NULL },
+ { "seven", 600, NULL },
+ { "Sacute", 600, NULL },
+ { "ordmasculine", 600, NULL },
+ { "dotlessi", 600, NULL },
+ { "sterling", 600, NULL },
+ { "notequal", 600, NULL },
+ { "Imacron", 600, NULL },
+ { "rcommaaccent", 600, NULL },
+ { "Zdotaccent", 600, NULL },
+ { "acircumflex", 600, NULL },
+ { "cacute", 600, NULL },
+ { "Ecaron", 600, NULL },
+ { "icircumflex", 600, NULL },
+ { "braceright", 600, NULL },
+ { "quotedblright", 600, NULL },
+ { "amacron", 600, NULL },
+ { "sacute", 600, NULL },
+ { "imacron", 600, NULL },
+ { "cent", 600, NULL },
+ { "currency", 600, NULL },
+ { "logicalnot", 600, NULL },
+ { "zdotaccent", 600, NULL },
+ { "Atilde", 600, NULL },
+ { "breve", 600, NULL },
+ { "bar", 600, NULL },
+ { "fraction", 600, NULL },
+ { "less", 600, NULL },
+ { "ecaron", 600, NULL },
+ { "guilsinglleft", 600, NULL },
+ { "exclam", 600, NULL },
+ { "period", 600, NULL },
+ { "Rcaron", 600, NULL },
+ { "Kcommaaccent", 600, NULL },
+ { "greater", 600, NULL },
+ { "atilde", 600, NULL },
+ { "brokenbar", 600, NULL },
+ { "quoteleft", 600, NULL },
+ { "Edotaccent", 600, NULL },
+ { "onesuperior", 600, NULL }
+};
+
+static BuiltinFontWidth courierBoldObliqueWidthsTab[] = {
+ { "Ntilde", 600, NULL },
+ { "rcaron", 600, NULL },
+ { "kcommaaccent", 600, NULL },
+ { "Ncommaaccent", 600, NULL },
+ { "Zacute", 600, NULL },
+ { "comma", 600, NULL },
+ { "cedilla", 600, NULL },
+ { "plusminus", 600, NULL },
+ { "circumflex", 600, NULL },
+ { "dotaccent", 600, NULL },
+ { "edotaccent", 600, NULL },
+ { "asciitilde", 600, NULL },
+ { "colon", 600, NULL },
+ { "onehalf", 600, NULL },
+ { "dollar", 600, NULL },
+ { "Lcaron", 600, NULL },
+ { "ntilde", 600, NULL },
+ { "Aogonek", 600, NULL },
+ { "ncommaaccent", 600, NULL },
+ { "minus", 600, NULL },
+ { "Iogonek", 600, NULL },
+ { "zacute", 600, NULL },
+ { "yen", 600, NULL },
+ { "space", 600, NULL },
+ { "Omacron", 600, NULL },
+ { "questiondown", 600, NULL },
+ { "emdash", 600, NULL },
+ { "Agrave", 600, NULL },
+ { "three", 600, NULL },
+ { "numbersign", 600, NULL },
+ { "lcaron", 600, NULL },
+ { "A", 600, NULL },
+ { "B", 600, NULL },
+ { "C", 600, NULL },
+ { "aogonek", 600, NULL },
+ { "D", 600, NULL },
+ { "E", 600, NULL },
+ { "onequarter", 600, NULL },
+ { "F", 600, NULL },
+ { "G", 600, NULL },
+ { "H", 600, NULL },
+ { "I", 600, NULL },
+ { "J", 600, NULL },
+ { "K", 600, NULL },
+ { "iogonek", 600, NULL },
+ { "backslash", 600, NULL },
+ { "L", 600, NULL },
+ { "periodcentered", 600, NULL },
+ { "M", 600, NULL },
+ { "N", 600, NULL },
+ { "omacron", 600, NULL },
+ { "Tcommaaccent", 600, NULL },
+ { "O", 600, NULL },
+ { "P", 600, NULL },
+ { "Q", 600, NULL },
+ { "Uhungarumlaut", 600, NULL },
+ { "R", 600, NULL },
+ { "Aacute", 600, NULL },
+ { "caron", 600, NULL },
+ { "S", 600, NULL },
+ { "T", 600, NULL },
+ { "U", 600, NULL },
+ { "agrave", 600, NULL },
+ { "V", 600, NULL },
+ { "W", 600, NULL },
+ { "X", 600, NULL },
+ { "question", 600, NULL },
+ { "equal", 600, NULL },
+ { "Y", 600, NULL },
+ { "Z", 600, NULL },
+ { "four", 600, NULL },
+ { "a", 600, NULL },
+ { "Gcommaaccent", 600, NULL },
+ { "b", 600, NULL },
+ { "c", 600, NULL },
+ { "d", 600, NULL },
+ { "e", 600, NULL },
+ { "f", 600, NULL },
+ { "g", 600, NULL },
+ { "bullet", 600, NULL },
+ { "h", 600, NULL },
+ { "i", 600, NULL },
+ { "Oslash", 600, NULL },
+ { "dagger", 600, NULL },
+ { "j", 600, NULL },
+ { "k", 600, NULL },
+ { "l", 600, NULL },
+ { "m", 600, NULL },
+ { "n", 600, NULL },
+ { "tcommaaccent", 600, NULL },
+ { "o", 600, NULL },
+ { "ordfeminine", 600, NULL },
+ { "ring", 600, NULL },
+ { "p", 600, NULL },
+ { "q", 600, NULL },
+ { "uhungarumlaut", 600, NULL },
+ { "r", 600, NULL },
+ { "twosuperior", 600, NULL },
+ { "aacute", 600, NULL },
+ { "s", 600, NULL },
+ { "OE", 600, NULL },
+ { "t", 600, NULL },
+ { "divide", 600, NULL },
+ { "u", 600, NULL },
+ { "Ccaron", 600, NULL },
+ { "v", 600, NULL },
+ { "w", 600, NULL },
+ { "x", 600, NULL },
+ { "y", 600, NULL },
+ { "z", 600, NULL },
+ { "Gbreve", 600, NULL },
+ { "commaaccent", 600, NULL },
+ { "hungarumlaut", 600, NULL },
+ { "Idotaccent", 600, NULL },
+ { "Nacute", 600, NULL },
+ { "quotedbl", 600, NULL },
+ { "gcommaaccent", 600, NULL },
+ { "mu", 600, NULL },
+ { "greaterequal", 600, NULL },
+ { "Scaron", 600, NULL },
+ { "Lslash", 600, NULL },
+ { "semicolon", 600, NULL },
+ { "oslash", 600, NULL },
+ { "lessequal", 600, NULL },
+ { "lozenge", 600, NULL },
+ { "parenright", 600, NULL },
+ { "ccaron", 600, NULL },
+ { "Ecircumflex", 600, NULL },
+ { "gbreve", 600, NULL },
+ { "trademark", 600, NULL },
+ { "daggerdbl", 600, NULL },
+ { "nacute", 600, NULL },
+ { "macron", 600, NULL },
+ { "Otilde", 600, NULL },
+ { "Emacron", 600, NULL },
+ { "ellipsis", 600, NULL },
+ { "scaron", 600, NULL },
+ { "AE", 600, NULL },
+ { "Ucircumflex", 600, NULL },
+ { "lslash", 600, NULL },
+ { "quotedblleft", 600, NULL },
+ { "guilsinglright", 600, NULL },
+ { "hyphen", 600, NULL },
+ { "quotesingle", 600, NULL },
+ { "eight", 600, NULL },
+ { "exclamdown", 600, NULL },
+ { "endash", 600, NULL },
+ { "oe", 600, NULL },
+ { "Abreve", 600, NULL },
+ { "Umacron", 600, NULL },
+ { "ecircumflex", 600, NULL },
+ { "Adieresis", 600, NULL },
+ { "copyright", 600, NULL },
+ { "Egrave", 600, NULL },
+ { "slash", 600, NULL },
+ { "Edieresis", 600, NULL },
+ { "otilde", 600, NULL },
+ { "Idieresis", 600, NULL },
+ { "parenleft", 600, NULL },
+ { "one", 600, NULL },
+ { "emacron", 600, NULL },
+ { "Odieresis", 600, NULL },
+ { "ucircumflex", 600, NULL },
+ { "bracketleft", 600, NULL },
+ { "Ugrave", 600, NULL },
+ { "quoteright", 600, NULL },
+ { "Udieresis", 600, NULL },
+ { "perthousand", 600, NULL },
+ { "Ydieresis", 600, NULL },
+ { "umacron", 600, NULL },
+ { "abreve", 600, NULL },
+ { "Eacute", 600, NULL },
+ { "adieresis", 600, NULL },
+ { "egrave", 600, NULL },
+ { "edieresis", 600, NULL },
+ { "idieresis", 600, NULL },
+ { "Eth", 600, NULL },
+ { "ae", 600, NULL },
+ { "asterisk", 600, NULL },
+ { "odieresis", 600, NULL },
+ { "Uacute", 600, NULL },
+ { "ugrave", 600, NULL },
+ { "nine", 600, NULL },
+ { "five", 600, NULL },
+ { "udieresis", 600, NULL },
+ { "Zcaron", 600, NULL },
+ { "Scommaaccent", 600, NULL },
+ { "threequarters", 600, NULL },
+ { "guillemotright", 600, NULL },
+ { "Ccedilla", 600, NULL },
+ { "ydieresis", 600, NULL },
+ { "tilde", 600, NULL },
+ { "at", 600, NULL },
+ { "eacute", 600, NULL },
+ { "underscore", 600, NULL },
+ { "Euro", 600, NULL },
+ { "Dcroat", 600, NULL },
+ { "multiply", 600, NULL },
+ { "zero", 600, NULL },
+ { "eth", 600, NULL },
+ { "Scedilla", 600, NULL },
+ { "Ograve", 600, NULL },
+ { "Racute", 600, NULL },
+ { "partialdiff", 600, NULL },
+ { "uacute", 600, NULL },
+ { "braceleft", 600, NULL },
+ { "Thorn", 600, NULL },
+ { "zcaron", 600, NULL },
+ { "scommaaccent", 600, NULL },
+ { "ccedilla", 600, NULL },
+ { "Dcaron", 600, NULL },
+ { "dcroat", 600, NULL },
+ { "Ocircumflex", 600, NULL },
+ { "Oacute", 600, NULL },
+ { "scedilla", 600, NULL },
+ { "ogonek", 600, NULL },
+ { "ograve", 600, NULL },
+ { "racute", 600, NULL },
+ { "Tcaron", 600, NULL },
+ { "Eogonek", 600, NULL },
+ { "thorn", 600, NULL },
+ { "degree", 600, NULL },
+ { "registered", 600, NULL },
+ { "radical", 600, NULL },
+ { "Aring", 600, NULL },
+ { "percent", 600, NULL },
+ { "six", 600, NULL },
+ { "paragraph", 600, NULL },
+ { "dcaron", 600, NULL },
+ { "Uogonek", 600, NULL },
+ { "two", 600, NULL },
+ { "summation", 600, NULL },
+ { "Igrave", 600, NULL },
+ { "Lacute", 600, NULL },
+ { "ocircumflex", 600, NULL },
+ { "oacute", 600, NULL },
+ { "Uring", 600, NULL },
+ { "Lcommaaccent", 600, NULL },
+ { "tcaron", 600, NULL },
+ { "eogonek", 600, NULL },
+ { "Delta", 600, NULL },
+ { "Ohungarumlaut", 600, NULL },
+ { "asciicircum", 600, NULL },
+ { "aring", 600, NULL },
+ { "grave", 600, NULL },
+ { "uogonek", 600, NULL },
+ { "bracketright", 600, NULL },
+ { "Iacute", 600, NULL },
+ { "ampersand", 600, NULL },
+ { "igrave", 600, NULL },
+ { "lacute", 600, NULL },
+ { "Ncaron", 600, NULL },
+ { "plus", 600, NULL },
+ { "uring", 600, NULL },
+ { "quotesinglbase", 600, NULL },
+ { "lcommaaccent", 600, NULL },
+ { "Yacute", 600, NULL },
+ { "ohungarumlaut", 600, NULL },
+ { "threesuperior", 600, NULL },
+ { "acute", 600, NULL },
+ { "section", 600, NULL },
+ { "dieresis", 600, NULL },
+ { "iacute", 600, NULL },
+ { "quotedblbase", 600, NULL },
+ { "ncaron", 600, NULL },
+ { "florin", 600, NULL },
+ { "yacute", 600, NULL },
+ { "Rcommaaccent", 600, NULL },
+ { "fi", 600, NULL },
+ { "fl", 600, NULL },
+ { "Acircumflex", 600, NULL },
+ { "Cacute", 600, NULL },
+ { "Icircumflex", 600, NULL },
+ { "guillemotleft", 600, NULL },
+ { "germandbls", 600, NULL },
+ { "Amacron", 600, NULL },
+ { "seven", 600, NULL },
+ { "Sacute", 600, NULL },
+ { "ordmasculine", 600, NULL },
+ { "dotlessi", 600, NULL },
+ { "sterling", 600, NULL },
+ { "notequal", 600, NULL },
+ { "Imacron", 600, NULL },
+ { "rcommaaccent", 600, NULL },
+ { "Zdotaccent", 600, NULL },
+ { "acircumflex", 600, NULL },
+ { "cacute", 600, NULL },
+ { "Ecaron", 600, NULL },
+ { "icircumflex", 600, NULL },
+ { "braceright", 600, NULL },
+ { "quotedblright", 600, NULL },
+ { "amacron", 600, NULL },
+ { "sacute", 600, NULL },
+ { "imacron", 600, NULL },
+ { "cent", 600, NULL },
+ { "currency", 600, NULL },
+ { "logicalnot", 600, NULL },
+ { "zdotaccent", 600, NULL },
+ { "Atilde", 600, NULL },
+ { "breve", 600, NULL },
+ { "bar", 600, NULL },
+ { "fraction", 600, NULL },
+ { "less", 600, NULL },
+ { "ecaron", 600, NULL },
+ { "guilsinglleft", 600, NULL },
+ { "exclam", 600, NULL },
+ { "period", 600, NULL },
+ { "Rcaron", 600, NULL },
+ { "Kcommaaccent", 600, NULL },
+ { "greater", 600, NULL },
+ { "atilde", 600, NULL },
+ { "brokenbar", 600, NULL },
+ { "quoteleft", 600, NULL },
+ { "Edotaccent", 600, NULL },
+ { "onesuperior", 600, NULL }
+};
+
+static BuiltinFontWidth courierObliqueWidthsTab[] = {
+ { "Ntilde", 600, NULL },
+ { "rcaron", 600, NULL },
+ { "kcommaaccent", 600, NULL },
+ { "Ncommaaccent", 600, NULL },
+ { "Zacute", 600, NULL },
+ { "comma", 600, NULL },
+ { "cedilla", 600, NULL },
+ { "plusminus", 600, NULL },
+ { "circumflex", 600, NULL },
+ { "dotaccent", 600, NULL },
+ { "edotaccent", 600, NULL },
+ { "asciitilde", 600, NULL },
+ { "colon", 600, NULL },
+ { "onehalf", 600, NULL },
+ { "dollar", 600, NULL },
+ { "Lcaron", 600, NULL },
+ { "ntilde", 600, NULL },
+ { "Aogonek", 600, NULL },
+ { "ncommaaccent", 600, NULL },
+ { "minus", 600, NULL },
+ { "Iogonek", 600, NULL },
+ { "zacute", 600, NULL },
+ { "yen", 600, NULL },
+ { "space", 600, NULL },
+ { "Omacron", 600, NULL },
+ { "questiondown", 600, NULL },
+ { "emdash", 600, NULL },
+ { "Agrave", 600, NULL },
+ { "three", 600, NULL },
+ { "numbersign", 600, NULL },
+ { "lcaron", 600, NULL },
+ { "A", 600, NULL },
+ { "B", 600, NULL },
+ { "C", 600, NULL },
+ { "aogonek", 600, NULL },
+ { "D", 600, NULL },
+ { "E", 600, NULL },
+ { "onequarter", 600, NULL },
+ { "F", 600, NULL },
+ { "G", 600, NULL },
+ { "H", 600, NULL },
+ { "I", 600, NULL },
+ { "J", 600, NULL },
+ { "K", 600, NULL },
+ { "iogonek", 600, NULL },
+ { "backslash", 600, NULL },
+ { "L", 600, NULL },
+ { "periodcentered", 600, NULL },
+ { "M", 600, NULL },
+ { "N", 600, NULL },
+ { "omacron", 600, NULL },
+ { "Tcommaaccent", 600, NULL },
+ { "O", 600, NULL },
+ { "P", 600, NULL },
+ { "Q", 600, NULL },
+ { "Uhungarumlaut", 600, NULL },
+ { "R", 600, NULL },
+ { "Aacute", 600, NULL },
+ { "caron", 600, NULL },
+ { "S", 600, NULL },
+ { "T", 600, NULL },
+ { "U", 600, NULL },
+ { "agrave", 600, NULL },
+ { "V", 600, NULL },
+ { "W", 600, NULL },
+ { "X", 600, NULL },
+ { "question", 600, NULL },
+ { "equal", 600, NULL },
+ { "Y", 600, NULL },
+ { "Z", 600, NULL },
+ { "four", 600, NULL },
+ { "a", 600, NULL },
+ { "Gcommaaccent", 600, NULL },
+ { "b", 600, NULL },
+ { "c", 600, NULL },
+ { "d", 600, NULL },
+ { "e", 600, NULL },
+ { "f", 600, NULL },
+ { "g", 600, NULL },
+ { "bullet", 600, NULL },
+ { "h", 600, NULL },
+ { "i", 600, NULL },
+ { "Oslash", 600, NULL },
+ { "dagger", 600, NULL },
+ { "j", 600, NULL },
+ { "k", 600, NULL },
+ { "l", 600, NULL },
+ { "m", 600, NULL },
+ { "n", 600, NULL },
+ { "tcommaaccent", 600, NULL },
+ { "o", 600, NULL },
+ { "ordfeminine", 600, NULL },
+ { "ring", 600, NULL },
+ { "p", 600, NULL },
+ { "q", 600, NULL },
+ { "uhungarumlaut", 600, NULL },
+ { "r", 600, NULL },
+ { "twosuperior", 600, NULL },
+ { "aacute", 600, NULL },
+ { "s", 600, NULL },
+ { "OE", 600, NULL },
+ { "t", 600, NULL },
+ { "divide", 600, NULL },
+ { "u", 600, NULL },
+ { "Ccaron", 600, NULL },
+ { "v", 600, NULL },
+ { "w", 600, NULL },
+ { "x", 600, NULL },
+ { "y", 600, NULL },
+ { "z", 600, NULL },
+ { "Gbreve", 600, NULL },
+ { "commaaccent", 600, NULL },
+ { "hungarumlaut", 600, NULL },
+ { "Idotaccent", 600, NULL },
+ { "Nacute", 600, NULL },
+ { "quotedbl", 600, NULL },
+ { "gcommaaccent", 600, NULL },
+ { "mu", 600, NULL },
+ { "greaterequal", 600, NULL },
+ { "Scaron", 600, NULL },
+ { "Lslash", 600, NULL },
+ { "semicolon", 600, NULL },
+ { "oslash", 600, NULL },
+ { "lessequal", 600, NULL },
+ { "lozenge", 600, NULL },
+ { "parenright", 600, NULL },
+ { "ccaron", 600, NULL },
+ { "Ecircumflex", 600, NULL },
+ { "gbreve", 600, NULL },
+ { "trademark", 600, NULL },
+ { "daggerdbl", 600, NULL },
+ { "nacute", 600, NULL },
+ { "macron", 600, NULL },
+ { "Otilde", 600, NULL },
+ { "Emacron", 600, NULL },
+ { "ellipsis", 600, NULL },
+ { "scaron", 600, NULL },
+ { "AE", 600, NULL },
+ { "Ucircumflex", 600, NULL },
+ { "lslash", 600, NULL },
+ { "quotedblleft", 600, NULL },
+ { "guilsinglright", 600, NULL },
+ { "hyphen", 600, NULL },
+ { "quotesingle", 600, NULL },
+ { "eight", 600, NULL },
+ { "exclamdown", 600, NULL },
+ { "endash", 600, NULL },
+ { "oe", 600, NULL },
+ { "Abreve", 600, NULL },
+ { "Umacron", 600, NULL },
+ { "ecircumflex", 600, NULL },
+ { "Adieresis", 600, NULL },
+ { "copyright", 600, NULL },
+ { "Egrave", 600, NULL },
+ { "slash", 600, NULL },
+ { "Edieresis", 600, NULL },
+ { "otilde", 600, NULL },
+ { "Idieresis", 600, NULL },
+ { "parenleft", 600, NULL },
+ { "one", 600, NULL },
+ { "emacron", 600, NULL },
+ { "Odieresis", 600, NULL },
+ { "ucircumflex", 600, NULL },
+ { "bracketleft", 600, NULL },
+ { "Ugrave", 600, NULL },
+ { "quoteright", 600, NULL },
+ { "Udieresis", 600, NULL },
+ { "perthousand", 600, NULL },
+ { "Ydieresis", 600, NULL },
+ { "umacron", 600, NULL },
+ { "abreve", 600, NULL },
+ { "Eacute", 600, NULL },
+ { "adieresis", 600, NULL },
+ { "egrave", 600, NULL },
+ { "edieresis", 600, NULL },
+ { "idieresis", 600, NULL },
+ { "Eth", 600, NULL },
+ { "ae", 600, NULL },
+ { "asterisk", 600, NULL },
+ { "odieresis", 600, NULL },
+ { "Uacute", 600, NULL },
+ { "ugrave", 600, NULL },
+ { "nine", 600, NULL },
+ { "five", 600, NULL },
+ { "udieresis", 600, NULL },
+ { "Zcaron", 600, NULL },
+ { "Scommaaccent", 600, NULL },
+ { "threequarters", 600, NULL },
+ { "guillemotright", 600, NULL },
+ { "Ccedilla", 600, NULL },
+ { "ydieresis", 600, NULL },
+ { "tilde", 600, NULL },
+ { "at", 600, NULL },
+ { "eacute", 600, NULL },
+ { "underscore", 600, NULL },
+ { "Euro", 600, NULL },
+ { "Dcroat", 600, NULL },
+ { "multiply", 600, NULL },
+ { "zero", 600, NULL },
+ { "eth", 600, NULL },
+ { "Scedilla", 600, NULL },
+ { "Ograve", 600, NULL },
+ { "Racute", 600, NULL },
+ { "partialdiff", 600, NULL },
+ { "uacute", 600, NULL },
+ { "braceleft", 600, NULL },
+ { "Thorn", 600, NULL },
+ { "zcaron", 600, NULL },
+ { "scommaaccent", 600, NULL },
+ { "ccedilla", 600, NULL },
+ { "Dcaron", 600, NULL },
+ { "dcroat", 600, NULL },
+ { "Ocircumflex", 600, NULL },
+ { "Oacute", 600, NULL },
+ { "scedilla", 600, NULL },
+ { "ogonek", 600, NULL },
+ { "ograve", 600, NULL },
+ { "racute", 600, NULL },
+ { "Tcaron", 600, NULL },
+ { "Eogonek", 600, NULL },
+ { "thorn", 600, NULL },
+ { "degree", 600, NULL },
+ { "registered", 600, NULL },
+ { "radical", 600, NULL },
+ { "Aring", 600, NULL },
+ { "percent", 600, NULL },
+ { "six", 600, NULL },
+ { "paragraph", 600, NULL },
+ { "dcaron", 600, NULL },
+ { "Uogonek", 600, NULL },
+ { "two", 600, NULL },
+ { "summation", 600, NULL },
+ { "Igrave", 600, NULL },
+ { "Lacute", 600, NULL },
+ { "ocircumflex", 600, NULL },
+ { "oacute", 600, NULL },
+ { "Uring", 600, NULL },
+ { "Lcommaaccent", 600, NULL },
+ { "tcaron", 600, NULL },
+ { "eogonek", 600, NULL },
+ { "Delta", 600, NULL },
+ { "Ohungarumlaut", 600, NULL },
+ { "asciicircum", 600, NULL },
+ { "aring", 600, NULL },
+ { "grave", 600, NULL },
+ { "uogonek", 600, NULL },
+ { "bracketright", 600, NULL },
+ { "Iacute", 600, NULL },
+ { "ampersand", 600, NULL },
+ { "igrave", 600, NULL },
+ { "lacute", 600, NULL },
+ { "Ncaron", 600, NULL },
+ { "plus", 600, NULL },
+ { "uring", 600, NULL },
+ { "quotesinglbase", 600, NULL },
+ { "lcommaaccent", 600, NULL },
+ { "Yacute", 600, NULL },
+ { "ohungarumlaut", 600, NULL },
+ { "threesuperior", 600, NULL },
+ { "acute", 600, NULL },
+ { "section", 600, NULL },
+ { "dieresis", 600, NULL },
+ { "iacute", 600, NULL },
+ { "quotedblbase", 600, NULL },
+ { "ncaron", 600, NULL },
+ { "florin", 600, NULL },
+ { "yacute", 600, NULL },
+ { "Rcommaaccent", 600, NULL },
+ { "fi", 600, NULL },
+ { "fl", 600, NULL },
+ { "Acircumflex", 600, NULL },
+ { "Cacute", 600, NULL },
+ { "Icircumflex", 600, NULL },
+ { "guillemotleft", 600, NULL },
+ { "germandbls", 600, NULL },
+ { "Amacron", 600, NULL },
+ { "seven", 600, NULL },
+ { "Sacute", 600, NULL },
+ { "ordmasculine", 600, NULL },
+ { "dotlessi", 600, NULL },
+ { "sterling", 600, NULL },
+ { "notequal", 600, NULL },
+ { "Imacron", 600, NULL },
+ { "rcommaaccent", 600, NULL },
+ { "Zdotaccent", 600, NULL },
+ { "acircumflex", 600, NULL },
+ { "cacute", 600, NULL },
+ { "Ecaron", 600, NULL },
+ { "icircumflex", 600, NULL },
+ { "braceright", 600, NULL },
+ { "quotedblright", 600, NULL },
+ { "amacron", 600, NULL },
+ { "sacute", 600, NULL },
+ { "imacron", 600, NULL },
+ { "cent", 600, NULL },
+ { "currency", 600, NULL },
+ { "logicalnot", 600, NULL },
+ { "zdotaccent", 600, NULL },
+ { "Atilde", 600, NULL },
+ { "breve", 600, NULL },
+ { "bar", 600, NULL },
+ { "fraction", 600, NULL },
+ { "less", 600, NULL },
+ { "ecaron", 600, NULL },
+ { "guilsinglleft", 600, NULL },
+ { "exclam", 600, NULL },
+ { "period", 600, NULL },
+ { "Rcaron", 600, NULL },
+ { "Kcommaaccent", 600, NULL },
+ { "greater", 600, NULL },
+ { "atilde", 600, NULL },
+ { "brokenbar", 600, NULL },
+ { "quoteleft", 600, NULL },
+ { "Edotaccent", 600, NULL },
+ { "onesuperior", 600, NULL }
+};
+
+static BuiltinFontWidth helveticaWidthsTab[] = {
+ { "Ntilde", 722, NULL },
+ { "rcaron", 333, NULL },
+ { "kcommaaccent", 500, NULL },
+ { "Ncommaaccent", 722, NULL },
+ { "Zacute", 611, NULL },
+ { "comma", 278, NULL },
+ { "cedilla", 333, NULL },
+ { "plusminus", 584, NULL },
+ { "circumflex", 333, NULL },
+ { "dotaccent", 333, NULL },
+ { "edotaccent", 556, NULL },
+ { "asciitilde", 584, NULL },
+ { "colon", 278, NULL },
+ { "onehalf", 834, NULL },
+ { "dollar", 556, NULL },
+ { "Lcaron", 556, NULL },
+ { "ntilde", 556, NULL },
+ { "Aogonek", 667, NULL },
+ { "ncommaaccent", 556, NULL },
+ { "minus", 584, NULL },
+ { "Iogonek", 278, NULL },
+ { "zacute", 500, NULL },
+ { "yen", 556, NULL },
+ { "space", 278, NULL },
+ { "Omacron", 778, NULL },
+ { "questiondown", 611, NULL },
+ { "emdash", 1000, NULL },
+ { "Agrave", 667, NULL },
+ { "three", 556, NULL },
+ { "numbersign", 556, NULL },
+ { "lcaron", 299, NULL },
+ { "A", 667, NULL },
+ { "B", 667, NULL },
+ { "C", 722, NULL },
+ { "aogonek", 556, NULL },
+ { "D", 722, NULL },
+ { "E", 667, NULL },
+ { "onequarter", 834, NULL },
+ { "F", 611, NULL },
+ { "G", 778, NULL },
+ { "H", 722, NULL },
+ { "I", 278, NULL },
+ { "J", 500, NULL },
+ { "K", 667, NULL },
+ { "iogonek", 222, NULL },
+ { "backslash", 278, NULL },
+ { "L", 556, NULL },
+ { "periodcentered", 278, NULL },
+ { "M", 833, NULL },
+ { "N", 722, NULL },
+ { "omacron", 556, NULL },
+ { "Tcommaaccent", 611, NULL },
+ { "O", 778, NULL },
+ { "P", 667, NULL },
+ { "Q", 778, NULL },
+ { "Uhungarumlaut", 722, NULL },
+ { "R", 722, NULL },
+ { "Aacute", 667, NULL },
+ { "caron", 333, NULL },
+ { "S", 667, NULL },
+ { "T", 611, NULL },
+ { "U", 722, NULL },
+ { "agrave", 556, NULL },
+ { "V", 667, NULL },
+ { "W", 944, NULL },
+ { "X", 667, NULL },
+ { "question", 556, NULL },
+ { "equal", 584, NULL },
+ { "Y", 667, NULL },
+ { "Z", 611, NULL },
+ { "four", 556, NULL },
+ { "a", 556, NULL },
+ { "Gcommaaccent", 778, NULL },
+ { "b", 556, NULL },
+ { "c", 500, NULL },
+ { "d", 556, NULL },
+ { "e", 556, NULL },
+ { "f", 278, NULL },
+ { "g", 556, NULL },
+ { "bullet", 350, NULL },
+ { "h", 556, NULL },
+ { "i", 222, NULL },
+ { "Oslash", 778, NULL },
+ { "dagger", 556, NULL },
+ { "j", 222, NULL },
+ { "k", 500, NULL },
+ { "l", 222, NULL },
+ { "m", 833, NULL },
+ { "n", 556, NULL },
+ { "tcommaaccent", 278, NULL },
+ { "o", 556, NULL },
+ { "ordfeminine", 370, NULL },
+ { "ring", 333, NULL },
+ { "p", 556, NULL },
+ { "q", 556, NULL },
+ { "uhungarumlaut", 556, NULL },
+ { "r", 333, NULL },
+ { "twosuperior", 333, NULL },
+ { "aacute", 556, NULL },
+ { "s", 500, NULL },
+ { "OE", 1000, NULL },
+ { "t", 278, NULL },
+ { "divide", 584, NULL },
+ { "u", 556, NULL },
+ { "Ccaron", 722, NULL },
+ { "v", 500, NULL },
+ { "w", 722, NULL },
+ { "x", 500, NULL },
+ { "y", 500, NULL },
+ { "z", 500, NULL },
+ { "Gbreve", 778, NULL },
+ { "commaaccent", 250, NULL },
+ { "hungarumlaut", 333, NULL },
+ { "Idotaccent", 278, NULL },
+ { "Nacute", 722, NULL },
+ { "quotedbl", 355, NULL },
+ { "gcommaaccent", 556, NULL },
+ { "mu", 556, NULL },
+ { "greaterequal", 549, NULL },
+ { "Scaron", 667, NULL },
+ { "Lslash", 556, NULL },
+ { "semicolon", 278, NULL },
+ { "oslash", 611, NULL },
+ { "lessequal", 549, NULL },
+ { "lozenge", 471, NULL },
+ { "parenright", 333, NULL },
+ { "ccaron", 500, NULL },
+ { "Ecircumflex", 667, NULL },
+ { "gbreve", 556, NULL },
+ { "trademark", 1000, NULL },
+ { "daggerdbl", 556, NULL },
+ { "nacute", 556, NULL },
+ { "macron", 333, NULL },
+ { "Otilde", 778, NULL },
+ { "Emacron", 667, NULL },
+ { "ellipsis", 1000, NULL },
+ { "scaron", 500, NULL },
+ { "AE", 1000, NULL },
+ { "Ucircumflex", 722, NULL },
+ { "lslash", 222, NULL },
+ { "quotedblleft", 333, NULL },
+ { "guilsinglright", 333, NULL },
+ { "hyphen", 333, NULL },
+ { "quotesingle", 191, NULL },
+ { "eight", 556, NULL },
+ { "exclamdown", 333, NULL },
+ { "endash", 556, NULL },
+ { "oe", 944, NULL },
+ { "Abreve", 667, NULL },
+ { "Umacron", 722, NULL },
+ { "ecircumflex", 556, NULL },
+ { "Adieresis", 667, NULL },
+ { "copyright", 737, NULL },
+ { "Egrave", 667, NULL },
+ { "slash", 278, NULL },
+ { "Edieresis", 667, NULL },
+ { "otilde", 556, NULL },
+ { "Idieresis", 278, NULL },
+ { "parenleft", 333, NULL },
+ { "one", 556, NULL },
+ { "emacron", 556, NULL },
+ { "Odieresis", 778, NULL },
+ { "ucircumflex", 556, NULL },
+ { "bracketleft", 278, NULL },
+ { "Ugrave", 722, NULL },
+ { "quoteright", 222, NULL },
+ { "Udieresis", 722, NULL },
+ { "perthousand", 1000, NULL },
+ { "Ydieresis", 667, NULL },
+ { "umacron", 556, NULL },
+ { "abreve", 556, NULL },
+ { "Eacute", 667, NULL },
+ { "adieresis", 556, NULL },
+ { "egrave", 556, NULL },
+ { "edieresis", 556, NULL },
+ { "idieresis", 278, NULL },
+ { "Eth", 722, NULL },
+ { "ae", 889, NULL },
+ { "asterisk", 389, NULL },
+ { "odieresis", 556, NULL },
+ { "Uacute", 722, NULL },
+ { "ugrave", 556, NULL },
+ { "nine", 556, NULL },
+ { "five", 556, NULL },
+ { "udieresis", 556, NULL },
+ { "Zcaron", 611, NULL },
+ { "Scommaaccent", 667, NULL },
+ { "threequarters", 834, NULL },
+ { "guillemotright", 556, NULL },
+ { "Ccedilla", 722, NULL },
+ { "ydieresis", 500, NULL },
+ { "tilde", 333, NULL },
+ { "at", 1015, NULL },
+ { "eacute", 556, NULL },
+ { "underscore", 556, NULL },
+ { "Euro", 556, NULL },
+ { "Dcroat", 722, NULL },
+ { "multiply", 584, NULL },
+ { "zero", 556, NULL },
+ { "eth", 556, NULL },
+ { "Scedilla", 667, NULL },
+ { "Ograve", 778, NULL },
+ { "Racute", 722, NULL },
+ { "partialdiff", 476, NULL },
+ { "uacute", 556, NULL },
+ { "braceleft", 334, NULL },
+ { "Thorn", 667, NULL },
+ { "zcaron", 500, NULL },
+ { "scommaaccent", 500, NULL },
+ { "ccedilla", 500, NULL },
+ { "Dcaron", 722, NULL },
+ { "dcroat", 556, NULL },
+ { "Ocircumflex", 778, NULL },
+ { "Oacute", 778, NULL },
+ { "scedilla", 500, NULL },
+ { "ogonek", 333, NULL },
+ { "ograve", 556, NULL },
+ { "racute", 333, NULL },
+ { "Tcaron", 611, NULL },
+ { "Eogonek", 667, NULL },
+ { "thorn", 556, NULL },
+ { "degree", 400, NULL },
+ { "registered", 737, NULL },
+ { "radical", 453, NULL },
+ { "Aring", 667, NULL },
+ { "percent", 889, NULL },
+ { "six", 556, NULL },
+ { "paragraph", 537, NULL },
+ { "dcaron", 643, NULL },
+ { "Uogonek", 722, NULL },
+ { "two", 556, NULL },
+ { "summation", 600, NULL },
+ { "Igrave", 278, NULL },
+ { "Lacute", 556, NULL },
+ { "ocircumflex", 556, NULL },
+ { "oacute", 556, NULL },
+ { "Uring", 722, NULL },
+ { "Lcommaaccent", 556, NULL },
+ { "tcaron", 317, NULL },
+ { "eogonek", 556, NULL },
+ { "Delta", 612, NULL },
+ { "Ohungarumlaut", 778, NULL },
+ { "asciicircum", 469, NULL },
+ { "aring", 556, NULL },
+ { "grave", 333, NULL },
+ { "uogonek", 556, NULL },
+ { "bracketright", 278, NULL },
+ { "Iacute", 278, NULL },
+ { "ampersand", 667, NULL },
+ { "igrave", 278, NULL },
+ { "lacute", 222, NULL },
+ { "Ncaron", 722, NULL },
+ { "plus", 584, NULL },
+ { "uring", 556, NULL },
+ { "quotesinglbase", 222, NULL },
+ { "lcommaaccent", 222, NULL },
+ { "Yacute", 667, NULL },
+ { "ohungarumlaut", 556, NULL },
+ { "threesuperior", 333, NULL },
+ { "acute", 333, NULL },
+ { "section", 556, NULL },
+ { "dieresis", 333, NULL },
+ { "iacute", 278, NULL },
+ { "quotedblbase", 333, NULL },
+ { "ncaron", 556, NULL },
+ { "florin", 556, NULL },
+ { "yacute", 500, NULL },
+ { "Rcommaaccent", 722, NULL },
+ { "fi", 500, NULL },
+ { "fl", 500, NULL },
+ { "Acircumflex", 667, NULL },
+ { "Cacute", 722, NULL },
+ { "Icircumflex", 278, NULL },
+ { "guillemotleft", 556, NULL },
+ { "germandbls", 611, NULL },
+ { "Amacron", 667, NULL },
+ { "seven", 556, NULL },
+ { "Sacute", 667, NULL },
+ { "ordmasculine", 365, NULL },
+ { "dotlessi", 278, NULL },
+ { "sterling", 556, NULL },
+ { "notequal", 549, NULL },
+ { "Imacron", 278, NULL },
+ { "rcommaaccent", 333, NULL },
+ { "Zdotaccent", 611, NULL },
+ { "acircumflex", 556, NULL },
+ { "cacute", 500, NULL },
+ { "Ecaron", 667, NULL },
+ { "icircumflex", 278, NULL },
+ { "braceright", 334, NULL },
+ { "quotedblright", 333, NULL },
+ { "amacron", 556, NULL },
+ { "sacute", 500, NULL },
+ { "imacron", 278, NULL },
+ { "cent", 556, NULL },
+ { "currency", 556, NULL },
+ { "logicalnot", 584, NULL },
+ { "zdotaccent", 500, NULL },
+ { "Atilde", 667, NULL },
+ { "breve", 333, NULL },
+ { "bar", 260, NULL },
+ { "fraction", 167, NULL },
+ { "less", 584, NULL },
+ { "ecaron", 556, NULL },
+ { "guilsinglleft", 333, NULL },
+ { "exclam", 278, NULL },
+ { "period", 278, NULL },
+ { "Rcaron", 722, NULL },
+ { "Kcommaaccent", 667, NULL },
+ { "greater", 584, NULL },
+ { "atilde", 556, NULL },
+ { "brokenbar", 260, NULL },
+ { "quoteleft", 222, NULL },
+ { "Edotaccent", 667, NULL },
+ { "onesuperior", 333, NULL }
+};
+
+static BuiltinFontWidth helveticaBoldWidthsTab[] = {
+ { "Ntilde", 722, NULL },
+ { "rcaron", 389, NULL },
+ { "kcommaaccent", 556, NULL },
+ { "Ncommaaccent", 722, NULL },
+ { "Zacute", 611, NULL },
+ { "comma", 278, NULL },
+ { "cedilla", 333, NULL },
+ { "plusminus", 584, NULL },
+ { "circumflex", 333, NULL },
+ { "dotaccent", 333, NULL },
+ { "edotaccent", 556, NULL },
+ { "asciitilde", 584, NULL },
+ { "colon", 333, NULL },
+ { "onehalf", 834, NULL },
+ { "dollar", 556, NULL },
+ { "Lcaron", 611, NULL },
+ { "ntilde", 611, NULL },
+ { "Aogonek", 722, NULL },
+ { "ncommaaccent", 611, NULL },
+ { "minus", 584, NULL },
+ { "Iogonek", 278, NULL },
+ { "zacute", 500, NULL },
+ { "yen", 556, NULL },
+ { "space", 278, NULL },
+ { "Omacron", 778, NULL },
+ { "questiondown", 611, NULL },
+ { "emdash", 1000, NULL },
+ { "Agrave", 722, NULL },
+ { "three", 556, NULL },
+ { "numbersign", 556, NULL },
+ { "lcaron", 400, NULL },
+ { "A", 722, NULL },
+ { "B", 722, NULL },
+ { "C", 722, NULL },
+ { "aogonek", 556, NULL },
+ { "D", 722, NULL },
+ { "E", 667, NULL },
+ { "onequarter", 834, NULL },
+ { "F", 611, NULL },
+ { "G", 778, NULL },
+ { "H", 722, NULL },
+ { "I", 278, NULL },
+ { "J", 556, NULL },
+ { "K", 722, NULL },
+ { "iogonek", 278, NULL },
+ { "backslash", 278, NULL },
+ { "L", 611, NULL },
+ { "periodcentered", 278, NULL },
+ { "M", 833, NULL },
+ { "N", 722, NULL },
+ { "omacron", 611, NULL },
+ { "Tcommaaccent", 611, NULL },
+ { "O", 778, NULL },
+ { "P", 667, NULL },
+ { "Q", 778, NULL },
+ { "Uhungarumlaut", 722, NULL },
+ { "R", 722, NULL },
+ { "Aacute", 722, NULL },
+ { "caron", 333, NULL },
+ { "S", 667, NULL },
+ { "T", 611, NULL },
+ { "U", 722, NULL },
+ { "agrave", 556, NULL },
+ { "V", 667, NULL },
+ { "W", 944, NULL },
+ { "X", 667, NULL },
+ { "question", 611, NULL },
+ { "equal", 584, NULL },
+ { "Y", 667, NULL },
+ { "Z", 611, NULL },
+ { "four", 556, NULL },
+ { "a", 556, NULL },
+ { "Gcommaaccent", 778, NULL },
+ { "b", 611, NULL },
+ { "c", 556, NULL },
+ { "d", 611, NULL },
+ { "e", 556, NULL },
+ { "f", 333, NULL },
+ { "g", 611, NULL },
+ { "bullet", 350, NULL },
+ { "h", 611, NULL },
+ { "i", 278, NULL },
+ { "Oslash", 778, NULL },
+ { "dagger", 556, NULL },
+ { "j", 278, NULL },
+ { "k", 556, NULL },
+ { "l", 278, NULL },
+ { "m", 889, NULL },
+ { "n", 611, NULL },
+ { "tcommaaccent", 333, NULL },
+ { "o", 611, NULL },
+ { "ordfeminine", 370, NULL },
+ { "ring", 333, NULL },
+ { "p", 611, NULL },
+ { "q", 611, NULL },
+ { "uhungarumlaut", 611, NULL },
+ { "r", 389, NULL },
+ { "twosuperior", 333, NULL },
+ { "aacute", 556, NULL },
+ { "s", 556, NULL },
+ { "OE", 1000, NULL },
+ { "t", 333, NULL },
+ { "divide", 584, NULL },
+ { "u", 611, NULL },
+ { "Ccaron", 722, NULL },
+ { "v", 556, NULL },
+ { "w", 778, NULL },
+ { "x", 556, NULL },
+ { "y", 556, NULL },
+ { "z", 500, NULL },
+ { "Gbreve", 778, NULL },
+ { "commaaccent", 250, NULL },
+ { "hungarumlaut", 333, NULL },
+ { "Idotaccent", 278, NULL },
+ { "Nacute", 722, NULL },
+ { "quotedbl", 474, NULL },
+ { "gcommaaccent", 611, NULL },
+ { "mu", 611, NULL },
+ { "greaterequal", 549, NULL },
+ { "Scaron", 667, NULL },
+ { "Lslash", 611, NULL },
+ { "semicolon", 333, NULL },
+ { "oslash", 611, NULL },
+ { "lessequal", 549, NULL },
+ { "lozenge", 494, NULL },
+ { "parenright", 333, NULL },
+ { "ccaron", 556, NULL },
+ { "Ecircumflex", 667, NULL },
+ { "gbreve", 611, NULL },
+ { "trademark", 1000, NULL },
+ { "daggerdbl", 556, NULL },
+ { "nacute", 611, NULL },
+ { "macron", 333, NULL },
+ { "Otilde", 778, NULL },
+ { "Emacron", 667, NULL },
+ { "ellipsis", 1000, NULL },
+ { "scaron", 556, NULL },
+ { "AE", 1000, NULL },
+ { "Ucircumflex", 722, NULL },
+ { "lslash", 278, NULL },
+ { "quotedblleft", 500, NULL },
+ { "guilsinglright", 333, NULL },
+ { "hyphen", 333, NULL },
+ { "quotesingle", 238, NULL },
+ { "eight", 556, NULL },
+ { "exclamdown", 333, NULL },
+ { "endash", 556, NULL },
+ { "oe", 944, NULL },
+ { "Abreve", 722, NULL },
+ { "Umacron", 722, NULL },
+ { "ecircumflex", 556, NULL },
+ { "Adieresis", 722, NULL },
+ { "copyright", 737, NULL },
+ { "Egrave", 667, NULL },
+ { "slash", 278, NULL },
+ { "Edieresis", 667, NULL },
+ { "otilde", 611, NULL },
+ { "Idieresis", 278, NULL },
+ { "parenleft", 333, NULL },
+ { "one", 556, NULL },
+ { "emacron", 556, NULL },
+ { "Odieresis", 778, NULL },
+ { "ucircumflex", 611, NULL },
+ { "bracketleft", 333, NULL },
+ { "Ugrave", 722, NULL },
+ { "quoteright", 278, NULL },
+ { "Udieresis", 722, NULL },
+ { "perthousand", 1000, NULL },
+ { "Ydieresis", 667, NULL },
+ { "umacron", 611, NULL },
+ { "abreve", 556, NULL },
+ { "Eacute", 667, NULL },
+ { "adieresis", 556, NULL },
+ { "egrave", 556, NULL },
+ { "edieresis", 556, NULL },
+ { "idieresis", 278, NULL },
+ { "Eth", 722, NULL },
+ { "ae", 889, NULL },
+ { "asterisk", 389, NULL },
+ { "odieresis", 611, NULL },
+ { "Uacute", 722, NULL },
+ { "ugrave", 611, NULL },
+ { "nine", 556, NULL },
+ { "five", 556, NULL },
+ { "udieresis", 611, NULL },
+ { "Zcaron", 611, NULL },
+ { "Scommaaccent", 667, NULL },
+ { "threequarters", 834, NULL },
+ { "guillemotright", 556, NULL },
+ { "Ccedilla", 722, NULL },
+ { "ydieresis", 556, NULL },
+ { "tilde", 333, NULL },
+ { "dbldaggerumlaut", 556, NULL },
+ { "at", 975, NULL },
+ { "eacute", 556, NULL },
+ { "underscore", 556, NULL },
+ { "Euro", 556, NULL },
+ { "Dcroat", 722, NULL },
+ { "multiply", 584, NULL },
+ { "zero", 556, NULL },
+ { "eth", 611, NULL },
+ { "Scedilla", 667, NULL },
+ { "Ograve", 778, NULL },
+ { "Racute", 722, NULL },
+ { "partialdiff", 494, NULL },
+ { "uacute", 611, NULL },
+ { "braceleft", 389, NULL },
+ { "Thorn", 667, NULL },
+ { "zcaron", 500, NULL },
+ { "scommaaccent", 556, NULL },
+ { "ccedilla", 556, NULL },
+ { "Dcaron", 722, NULL },
+ { "dcroat", 611, NULL },
+ { "Ocircumflex", 778, NULL },
+ { "Oacute", 778, NULL },
+ { "scedilla", 556, NULL },
+ { "ogonek", 333, NULL },
+ { "ograve", 611, NULL },
+ { "racute", 389, NULL },
+ { "Tcaron", 611, NULL },
+ { "Eogonek", 667, NULL },
+ { "thorn", 611, NULL },
+ { "degree", 400, NULL },
+ { "registered", 737, NULL },
+ { "radical", 549, NULL },
+ { "Aring", 722, NULL },
+ { "percent", 889, NULL },
+ { "six", 556, NULL },
+ { "paragraph", 556, NULL },
+ { "dcaron", 743, NULL },
+ { "Uogonek", 722, NULL },
+ { "two", 556, NULL },
+ { "summation", 600, NULL },
+ { "Igrave", 278, NULL },
+ { "Lacute", 611, NULL },
+ { "ocircumflex", 611, NULL },
+ { "oacute", 611, NULL },
+ { "Uring", 722, NULL },
+ { "Lcommaaccent", 611, NULL },
+ { "tcaron", 389, NULL },
+ { "eogonek", 556, NULL },
+ { "Delta", 612, NULL },
+ { "Ohungarumlaut", 778, NULL },
+ { "asciicircum", 584, NULL },
+ { "aring", 556, NULL },
+ { "grave", 333, NULL },
+ { "uogonek", 611, NULL },
+ { "bracketright", 333, NULL },
+ { "Iacute", 278, NULL },
+ { "ampersand", 722, NULL },
+ { "igrave", 278, NULL },
+ { "lacute", 278, NULL },
+ { "Ncaron", 722, NULL },
+ { "plus", 584, NULL },
+ { "uring", 611, NULL },
+ { "quotesinglbase", 278, NULL },
+ { "lcommaaccent", 278, NULL },
+ { "Yacute", 667, NULL },
+ { "ohungarumlaut", 611, NULL },
+ { "threesuperior", 333, NULL },
+ { "acute", 333, NULL },
+ { "section", 556, NULL },
+ { "dieresis", 333, NULL },
+ { "iacute", 278, NULL },
+ { "quotedblbase", 500, NULL },
+ { "ncaron", 611, NULL },
+ { "florin", 556, NULL },
+ { "yacute", 556, NULL },
+ { "Rcommaaccent", 722, NULL },
+ { "fi", 611, NULL },
+ { "fl", 611, NULL },
+ { "Acircumflex", 722, NULL },
+ { "Cacute", 722, NULL },
+ { "Icircumflex", 278, NULL },
+ { "guillemotleft", 556, NULL },
+ { "germandbls", 611, NULL },
+ { "Amacron", 722, NULL },
+ { "seven", 556, NULL },
+ { "Sacute", 667, NULL },
+ { "ordmasculine", 365, NULL },
+ { "dotlessi", 278, NULL },
+ { "sterling", 556, NULL },
+ { "notequal", 549, NULL },
+ { "Imacron", 278, NULL },
+ { "rcommaaccent", 389, NULL },
+ { "Zdotaccent", 611, NULL },
+ { "acircumflex", 556, NULL },
+ { "cacute", 556, NULL },
+ { "Ecaron", 667, NULL },
+ { "icircumflex", 278, NULL },
+ { "braceright", 389, NULL },
+ { "quotedblright", 500, NULL },
+ { "amacron", 556, NULL },
+ { "sacute", 556, NULL },
+ { "imacron", 278, NULL },
+ { "cent", 556, NULL },
+ { "currency", 556, NULL },
+ { "logicalnot", 584, NULL },
+ { "zdotaccent", 500, NULL },
+ { "Atilde", 722, NULL },
+ { "breve", 333, NULL },
+ { "bar", 280, NULL },
+ { "fraction", 167, NULL },
+ { "less", 584, NULL },
+ { "ecaron", 556, NULL },
+ { "guilsinglleft", 333, NULL },
+ { "exclam", 333, NULL },
+ { "period", 278, NULL },
+ { "Rcaron", 722, NULL },
+ { "Kcommaaccent", 722, NULL },
+ { "greater", 584, NULL },
+ { "atilde", 556, NULL },
+ { "brokenbar", 280, NULL },
+ { "quoteleft", 278, NULL },
+ { "Edotaccent", 667, NULL },
+ { "onesuperior", 333, NULL }
+};
+
+static BuiltinFontWidth helveticaBoldObliqueWidthsTab[] = {
+ { "Ntilde", 722, NULL },
+ { "rcaron", 389, NULL },
+ { "kcommaaccent", 556, NULL },
+ { "Ncommaaccent", 722, NULL },
+ { "Zacute", 611, NULL },
+ { "comma", 278, NULL },
+ { "cedilla", 333, NULL },
+ { "plusminus", 584, NULL },
+ { "circumflex", 333, NULL },
+ { "dotaccent", 333, NULL },
+ { "edotaccent", 556, NULL },
+ { "asciitilde", 584, NULL },
+ { "colon", 333, NULL },
+ { "onehalf", 834, NULL },
+ { "dollar", 556, NULL },
+ { "Lcaron", 611, NULL },
+ { "ntilde", 611, NULL },
+ { "Aogonek", 722, NULL },
+ { "ncommaaccent", 611, NULL },
+ { "minus", 584, NULL },
+ { "Iogonek", 278, NULL },
+ { "zacute", 500, NULL },
+ { "yen", 556, NULL },
+ { "space", 278, NULL },
+ { "Omacron", 778, NULL },
+ { "questiondown", 611, NULL },
+ { "emdash", 1000, NULL },
+ { "Agrave", 722, NULL },
+ { "three", 556, NULL },
+ { "numbersign", 556, NULL },
+ { "lcaron", 400, NULL },
+ { "A", 722, NULL },
+ { "B", 722, NULL },
+ { "C", 722, NULL },
+ { "aogonek", 556, NULL },
+ { "D", 722, NULL },
+ { "E", 667, NULL },
+ { "onequarter", 834, NULL },
+ { "F", 611, NULL },
+ { "G", 778, NULL },
+ { "H", 722, NULL },
+ { "I", 278, NULL },
+ { "J", 556, NULL },
+ { "K", 722, NULL },
+ { "iogonek", 278, NULL },
+ { "backslash", 278, NULL },
+ { "L", 611, NULL },
+ { "periodcentered", 278, NULL },
+ { "M", 833, NULL },
+ { "N", 722, NULL },
+ { "omacron", 611, NULL },
+ { "Tcommaaccent", 611, NULL },
+ { "O", 778, NULL },
+ { "P", 667, NULL },
+ { "Q", 778, NULL },
+ { "Uhungarumlaut", 722, NULL },
+ { "R", 722, NULL },
+ { "Aacute", 722, NULL },
+ { "caron", 333, NULL },
+ { "S", 667, NULL },
+ { "T", 611, NULL },
+ { "U", 722, NULL },
+ { "agrave", 556, NULL },
+ { "V", 667, NULL },
+ { "W", 944, NULL },
+ { "X", 667, NULL },
+ { "question", 611, NULL },
+ { "equal", 584, NULL },
+ { "Y", 667, NULL },
+ { "Z", 611, NULL },
+ { "four", 556, NULL },
+ { "a", 556, NULL },
+ { "Gcommaaccent", 778, NULL },
+ { "b", 611, NULL },
+ { "c", 556, NULL },
+ { "d", 611, NULL },
+ { "e", 556, NULL },
+ { "f", 333, NULL },
+ { "g", 611, NULL },
+ { "bullet", 350, NULL },
+ { "h", 611, NULL },
+ { "i", 278, NULL },
+ { "Oslash", 778, NULL },
+ { "dagger", 556, NULL },
+ { "j", 278, NULL },
+ { "k", 556, NULL },
+ { "l", 278, NULL },
+ { "m", 889, NULL },
+ { "n", 611, NULL },
+ { "tcommaaccent", 333, NULL },
+ { "o", 611, NULL },
+ { "ordfeminine", 370, NULL },
+ { "ring", 333, NULL },
+ { "p", 611, NULL },
+ { "q", 611, NULL },
+ { "uhungarumlaut", 611, NULL },
+ { "r", 389, NULL },
+ { "twosuperior", 333, NULL },
+ { "aacute", 556, NULL },
+ { "s", 556, NULL },
+ { "OE", 1000, NULL },
+ { "t", 333, NULL },
+ { "divide", 584, NULL },
+ { "u", 611, NULL },
+ { "Ccaron", 722, NULL },
+ { "v", 556, NULL },
+ { "w", 778, NULL },
+ { "x", 556, NULL },
+ { "y", 556, NULL },
+ { "z", 500, NULL },
+ { "Gbreve", 778, NULL },
+ { "commaaccent", 250, NULL },
+ { "hungarumlaut", 333, NULL },
+ { "Idotaccent", 278, NULL },
+ { "Nacute", 722, NULL },
+ { "quotedbl", 474, NULL },
+ { "gcommaaccent", 611, NULL },
+ { "mu", 611, NULL },
+ { "greaterequal", 549, NULL },
+ { "Scaron", 667, NULL },
+ { "Lslash", 611, NULL },
+ { "semicolon", 333, NULL },
+ { "oslash", 611, NULL },
+ { "lessequal", 549, NULL },
+ { "lozenge", 494, NULL },
+ { "parenright", 333, NULL },
+ { "ccaron", 556, NULL },
+ { "Ecircumflex", 667, NULL },
+ { "gbreve", 611, NULL },
+ { "trademark", 1000, NULL },
+ { "daggerdbl", 556, NULL },
+ { "nacute", 611, NULL },
+ { "macron", 333, NULL },
+ { "Otilde", 778, NULL },
+ { "Emacron", 667, NULL },
+ { "ellipsis", 1000, NULL },
+ { "scaron", 556, NULL },
+ { "AE", 1000, NULL },
+ { "Ucircumflex", 722, NULL },
+ { "lslash", 278, NULL },
+ { "quotedblleft", 500, NULL },
+ { "guilsinglright", 333, NULL },
+ { "hyphen", 333, NULL },
+ { "quotesingle", 238, NULL },
+ { "eight", 556, NULL },
+ { "exclamdown", 333, NULL },
+ { "endash", 556, NULL },
+ { "oe", 944, NULL },
+ { "Abreve", 722, NULL },
+ { "Umacron", 722, NULL },
+ { "ecircumflex", 556, NULL },
+ { "Adieresis", 722, NULL },
+ { "copyright", 737, NULL },
+ { "Egrave", 667, NULL },
+ { "slash", 278, NULL },
+ { "Edieresis", 667, NULL },
+ { "otilde", 611, NULL },
+ { "Idieresis", 278, NULL },
+ { "parenleft", 333, NULL },
+ { "one", 556, NULL },
+ { "emacron", 556, NULL },
+ { "Odieresis", 778, NULL },
+ { "ucircumflex", 611, NULL },
+ { "bracketleft", 333, NULL },
+ { "Ugrave", 722, NULL },
+ { "quoteright", 278, NULL },
+ { "Udieresis", 722, NULL },
+ { "perthousand", 1000, NULL },
+ { "Ydieresis", 667, NULL },
+ { "umacron", 611, NULL },
+ { "abreve", 556, NULL },
+ { "Eacute", 667, NULL },
+ { "adieresis", 556, NULL },
+ { "egrave", 556, NULL },
+ { "edieresis", 556, NULL },
+ { "idieresis", 278, NULL },
+ { "Eth", 722, NULL },
+ { "ae", 889, NULL },
+ { "asterisk", 389, NULL },
+ { "odieresis", 611, NULL },
+ { "Uacute", 722, NULL },
+ { "ugrave", 611, NULL },
+ { "nine", 556, NULL },
+ { "five", 556, NULL },
+ { "udieresis", 611, NULL },
+ { "Zcaron", 611, NULL },
+ { "Scommaaccent", 667, NULL },
+ { "threequarters", 834, NULL },
+ { "guillemotright", 556, NULL },
+ { "Ccedilla", 722, NULL },
+ { "ydieresis", 556, NULL },
+ { "tilde", 333, NULL },
+ { "at", 975, NULL },
+ { "eacute", 556, NULL },
+ { "underscore", 556, NULL },
+ { "Euro", 556, NULL },
+ { "Dcroat", 722, NULL },
+ { "multiply", 584, NULL },
+ { "zero", 556, NULL },
+ { "eth", 611, NULL },
+ { "Scedilla", 667, NULL },
+ { "Ograve", 778, NULL },
+ { "Racute", 722, NULL },
+ { "partialdiff", 494, NULL },
+ { "uacute", 611, NULL },
+ { "braceleft", 389, NULL },
+ { "Thorn", 667, NULL },
+ { "zcaron", 500, NULL },
+ { "scommaaccent", 556, NULL },
+ { "ccedilla", 556, NULL },
+ { "Dcaron", 722, NULL },
+ { "dcroat", 611, NULL },
+ { "Ocircumflex", 778, NULL },
+ { "Oacute", 778, NULL },
+ { "scedilla", 556, NULL },
+ { "ogonek", 333, NULL },
+ { "ograve", 611, NULL },
+ { "racute", 389, NULL },
+ { "Tcaron", 611, NULL },
+ { "Eogonek", 667, NULL },
+ { "thorn", 611, NULL },
+ { "degree", 400, NULL },
+ { "registered", 737, NULL },
+ { "radical", 549, NULL },
+ { "Aring", 722, NULL },
+ { "percent", 889, NULL },
+ { "six", 556, NULL },
+ { "paragraph", 556, NULL },
+ { "dcaron", 743, NULL },
+ { "Uogonek", 722, NULL },
+ { "two", 556, NULL },
+ { "summation", 600, NULL },
+ { "Igrave", 278, NULL },
+ { "Lacute", 611, NULL },
+ { "ocircumflex", 611, NULL },
+ { "oacute", 611, NULL },
+ { "Uring", 722, NULL },
+ { "Lcommaaccent", 611, NULL },
+ { "tcaron", 389, NULL },
+ { "eogonek", 556, NULL },
+ { "Delta", 612, NULL },
+ { "Ohungarumlaut", 778, NULL },
+ { "asciicircum", 584, NULL },
+ { "aring", 556, NULL },
+ { "grave", 333, NULL },
+ { "uogonek", 611, NULL },
+ { "bracketright", 333, NULL },
+ { "Iacute", 278, NULL },
+ { "ampersand", 722, NULL },
+ { "igrave", 278, NULL },
+ { "lacute", 278, NULL },
+ { "Ncaron", 722, NULL },
+ { "plus", 584, NULL },
+ { "uring", 611, NULL },
+ { "quotesinglbase", 278, NULL },
+ { "lcommaaccent", 278, NULL },
+ { "Yacute", 667, NULL },
+ { "ohungarumlaut", 611, NULL },
+ { "threesuperior", 333, NULL },
+ { "acute", 333, NULL },
+ { "section", 556, NULL },
+ { "dieresis", 333, NULL },
+ { "iacute", 278, NULL },
+ { "quotedblbase", 500, NULL },
+ { "ncaron", 611, NULL },
+ { "florin", 556, NULL },
+ { "yacute", 556, NULL },
+ { "Rcommaaccent", 722, NULL },
+ { "fi", 611, NULL },
+ { "fl", 611, NULL },
+ { "Acircumflex", 722, NULL },
+ { "Cacute", 722, NULL },
+ { "Icircumflex", 278, NULL },
+ { "guillemotleft", 556, NULL },
+ { "germandbls", 611, NULL },
+ { "Amacron", 722, NULL },
+ { "seven", 556, NULL },
+ { "Sacute", 667, NULL },
+ { "ordmasculine", 365, NULL },
+ { "dotlessi", 278, NULL },
+ { "sterling", 556, NULL },
+ { "notequal", 549, NULL },
+ { "Imacron", 278, NULL },
+ { "rcommaaccent", 389, NULL },
+ { "Zdotaccent", 611, NULL },
+ { "acircumflex", 556, NULL },
+ { "cacute", 556, NULL },
+ { "Ecaron", 667, NULL },
+ { "icircumflex", 278, NULL },
+ { "braceright", 389, NULL },
+ { "quotedblright", 500, NULL },
+ { "amacron", 556, NULL },
+ { "sacute", 556, NULL },
+ { "imacron", 278, NULL },
+ { "cent", 556, NULL },
+ { "currency", 556, NULL },
+ { "logicalnot", 584, NULL },
+ { "zdotaccent", 500, NULL },
+ { "Atilde", 722, NULL },
+ { "breve", 333, NULL },
+ { "bar", 280, NULL },
+ { "fraction", 167, NULL },
+ { "less", 584, NULL },
+ { "ecaron", 556, NULL },
+ { "guilsinglleft", 333, NULL },
+ { "exclam", 333, NULL },
+ { "period", 278, NULL },
+ { "Rcaron", 722, NULL },
+ { "Kcommaaccent", 722, NULL },
+ { "greater", 584, NULL },
+ { "atilde", 556, NULL },
+ { "brokenbar", 280, NULL },
+ { "quoteleft", 278, NULL },
+ { "Edotaccent", 667, NULL },
+ { "onesuperior", 333, NULL }
+};
+
+static BuiltinFontWidth helveticaObliqueWidthsTab[] = {
+ { "Ntilde", 722, NULL },
+ { "rcaron", 333, NULL },
+ { "kcommaaccent", 500, NULL },
+ { "Ncommaaccent", 722, NULL },
+ { "Zacute", 611, NULL },
+ { "comma", 278, NULL },
+ { "cedilla", 333, NULL },
+ { "plusminus", 584, NULL },
+ { "circumflex", 333, NULL },
+ { "dotaccent", 333, NULL },
+ { "edotaccent", 556, NULL },
+ { "asciitilde", 584, NULL },
+ { "colon", 278, NULL },
+ { "onehalf", 834, NULL },
+ { "dollar", 556, NULL },
+ { "Lcaron", 556, NULL },
+ { "ntilde", 556, NULL },
+ { "Aogonek", 667, NULL },
+ { "ncommaaccent", 556, NULL },
+ { "minus", 584, NULL },
+ { "Iogonek", 278, NULL },
+ { "zacute", 500, NULL },
+ { "yen", 556, NULL },
+ { "space", 278, NULL },
+ { "Omacron", 778, NULL },
+ { "questiondown", 611, NULL },
+ { "emdash", 1000, NULL },
+ { "Agrave", 667, NULL },
+ { "three", 556, NULL },
+ { "numbersign", 556, NULL },
+ { "lcaron", 299, NULL },
+ { "A", 667, NULL },
+ { "B", 667, NULL },
+ { "C", 722, NULL },
+ { "aogonek", 556, NULL },
+ { "D", 722, NULL },
+ { "E", 667, NULL },
+ { "onequarter", 834, NULL },
+ { "F", 611, NULL },
+ { "G", 778, NULL },
+ { "H", 722, NULL },
+ { "I", 278, NULL },
+ { "J", 500, NULL },
+ { "K", 667, NULL },
+ { "iogonek", 222, NULL },
+ { "backslash", 278, NULL },
+ { "L", 556, NULL },
+ { "periodcentered", 278, NULL },
+ { "M", 833, NULL },
+ { "N", 722, NULL },
+ { "omacron", 556, NULL },
+ { "Tcommaaccent", 611, NULL },
+ { "O", 778, NULL },
+ { "P", 667, NULL },
+ { "Q", 778, NULL },
+ { "Uhungarumlaut", 722, NULL },
+ { "R", 722, NULL },
+ { "Aacute", 667, NULL },
+ { "caron", 333, NULL },
+ { "S", 667, NULL },
+ { "T", 611, NULL },
+ { "U", 722, NULL },
+ { "agrave", 556, NULL },
+ { "V", 667, NULL },
+ { "W", 944, NULL },
+ { "X", 667, NULL },
+ { "question", 556, NULL },
+ { "equal", 584, NULL },
+ { "Y", 667, NULL },
+ { "Z", 611, NULL },
+ { "four", 556, NULL },
+ { "a", 556, NULL },
+ { "Gcommaaccent", 778, NULL },
+ { "b", 556, NULL },
+ { "c", 500, NULL },
+ { "d", 556, NULL },
+ { "e", 556, NULL },
+ { "f", 278, NULL },
+ { "g", 556, NULL },
+ { "bullet", 350, NULL },
+ { "h", 556, NULL },
+ { "i", 222, NULL },
+ { "Oslash", 778, NULL },
+ { "dagger", 556, NULL },
+ { "j", 222, NULL },
+ { "k", 500, NULL },
+ { "l", 222, NULL },
+ { "m", 833, NULL },
+ { "n", 556, NULL },
+ { "tcommaaccent", 278, NULL },
+ { "o", 556, NULL },
+ { "ordfeminine", 370, NULL },
+ { "ring", 333, NULL },
+ { "p", 556, NULL },
+ { "q", 556, NULL },
+ { "uhungarumlaut", 556, NULL },
+ { "r", 333, NULL },
+ { "twosuperior", 333, NULL },
+ { "aacute", 556, NULL },
+ { "s", 500, NULL },
+ { "OE", 1000, NULL },
+ { "t", 278, NULL },
+ { "divide", 584, NULL },
+ { "u", 556, NULL },
+ { "Ccaron", 722, NULL },
+ { "v", 500, NULL },
+ { "w", 722, NULL },
+ { "x", 500, NULL },
+ { "y", 500, NULL },
+ { "z", 500, NULL },
+ { "Gbreve", 778, NULL },
+ { "commaaccent", 250, NULL },
+ { "hungarumlaut", 333, NULL },
+ { "Idotaccent", 278, NULL },
+ { "Nacute", 722, NULL },
+ { "quotedbl", 355, NULL },
+ { "gcommaaccent", 556, NULL },
+ { "mu", 556, NULL },
+ { "greaterequal", 549, NULL },
+ { "Scaron", 667, NULL },
+ { "Lslash", 556, NULL },
+ { "semicolon", 278, NULL },
+ { "oslash", 611, NULL },
+ { "lessequal", 549, NULL },
+ { "lozenge", 471, NULL },
+ { "parenright", 333, NULL },
+ { "ccaron", 500, NULL },
+ { "Ecircumflex", 667, NULL },
+ { "gbreve", 556, NULL },
+ { "trademark", 1000, NULL },
+ { "daggerdbl", 556, NULL },
+ { "nacute", 556, NULL },
+ { "macron", 333, NULL },
+ { "Otilde", 778, NULL },
+ { "Emacron", 667, NULL },
+ { "ellipsis", 1000, NULL },
+ { "scaron", 500, NULL },
+ { "AE", 1000, NULL },
+ { "Ucircumflex", 722, NULL },
+ { "lslash", 222, NULL },
+ { "quotedblleft", 333, NULL },
+ { "guilsinglright", 333, NULL },
+ { "hyphen", 333, NULL },
+ { "quotesingle", 191, NULL },
+ { "eight", 556, NULL },
+ { "exclamdown", 333, NULL },
+ { "endash", 556, NULL },
+ { "oe", 944, NULL },
+ { "Abreve", 667, NULL },
+ { "Umacron", 722, NULL },
+ { "ecircumflex", 556, NULL },
+ { "Adieresis", 667, NULL },
+ { "copyright", 737, NULL },
+ { "Egrave", 667, NULL },
+ { "slash", 278, NULL },
+ { "Edieresis", 667, NULL },
+ { "otilde", 556, NULL },
+ { "Idieresis", 278, NULL },
+ { "parenleft", 333, NULL },
+ { "one", 556, NULL },
+ { "emacron", 556, NULL },
+ { "Odieresis", 778, NULL },
+ { "ucircumflex", 556, NULL },
+ { "bracketleft", 278, NULL },
+ { "Ugrave", 722, NULL },
+ { "quoteright", 222, NULL },
+ { "Udieresis", 722, NULL },
+ { "perthousand", 1000, NULL },
+ { "Ydieresis", 667, NULL },
+ { "umacron", 556, NULL },
+ { "abreve", 556, NULL },
+ { "Eacute", 667, NULL },
+ { "adieresis", 556, NULL },
+ { "egrave", 556, NULL },
+ { "edieresis", 556, NULL },
+ { "idieresis", 278, NULL },
+ { "Eth", 722, NULL },
+ { "ae", 889, NULL },
+ { "asterisk", 389, NULL },
+ { "odieresis", 556, NULL },
+ { "Uacute", 722, NULL },
+ { "ugrave", 556, NULL },
+ { "nine", 556, NULL },
+ { "five", 556, NULL },
+ { "udieresis", 556, NULL },
+ { "Zcaron", 611, NULL },
+ { "Scommaaccent", 667, NULL },
+ { "threequarters", 834, NULL },
+ { "guillemotright", 556, NULL },
+ { "Ccedilla", 722, NULL },
+ { "ydieresis", 500, NULL },
+ { "tilde", 333, NULL },
+ { "at", 1015, NULL },
+ { "eacute", 556, NULL },
+ { "underscore", 556, NULL },
+ { "Euro", 556, NULL },
+ { "Dcroat", 722, NULL },
+ { "multiply", 584, NULL },
+ { "zero", 556, NULL },
+ { "eth", 556, NULL },
+ { "Scedilla", 667, NULL },
+ { "Ograve", 778, NULL },
+ { "Racute", 722, NULL },
+ { "partialdiff", 476, NULL },
+ { "uacute", 556, NULL },
+ { "braceleft", 334, NULL },
+ { "Thorn", 667, NULL },
+ { "zcaron", 500, NULL },
+ { "scommaaccent", 500, NULL },
+ { "ccedilla", 500, NULL },
+ { "Dcaron", 722, NULL },
+ { "dcroat", 556, NULL },
+ { "Ocircumflex", 778, NULL },
+ { "Oacute", 778, NULL },
+ { "scedilla", 500, NULL },
+ { "ogonek", 333, NULL },
+ { "ograve", 556, NULL },
+ { "racute", 333, NULL },
+ { "Tcaron", 611, NULL },
+ { "Eogonek", 667, NULL },
+ { "thorn", 556, NULL },
+ { "degree", 400, NULL },
+ { "registered", 737, NULL },
+ { "radical", 453, NULL },
+ { "Aring", 667, NULL },
+ { "percent", 889, NULL },
+ { "six", 556, NULL },
+ { "paragraph", 537, NULL },
+ { "dcaron", 643, NULL },
+ { "Uogonek", 722, NULL },
+ { "two", 556, NULL },
+ { "summation", 600, NULL },
+ { "Igrave", 278, NULL },
+ { "Lacute", 556, NULL },
+ { "ocircumflex", 556, NULL },
+ { "oacute", 556, NULL },
+ { "Uring", 722, NULL },
+ { "Lcommaaccent", 556, NULL },
+ { "tcaron", 317, NULL },
+ { "eogonek", 556, NULL },
+ { "Delta", 612, NULL },
+ { "Ohungarumlaut", 778, NULL },
+ { "asciicircum", 469, NULL },
+ { "aring", 556, NULL },
+ { "grave", 333, NULL },
+ { "uogonek", 556, NULL },
+ { "bracketright", 278, NULL },
+ { "Iacute", 278, NULL },
+ { "ampersand", 667, NULL },
+ { "igrave", 278, NULL },
+ { "lacute", 222, NULL },
+ { "Ncaron", 722, NULL },
+ { "plus", 584, NULL },
+ { "uring", 556, NULL },
+ { "quotesinglbase", 222, NULL },
+ { "lcommaaccent", 222, NULL },
+ { "Yacute", 667, NULL },
+ { "ohungarumlaut", 556, NULL },
+ { "threesuperior", 333, NULL },
+ { "acute", 333, NULL },
+ { "section", 556, NULL },
+ { "dieresis", 333, NULL },
+ { "iacute", 278, NULL },
+ { "quotedblbase", 333, NULL },
+ { "ncaron", 556, NULL },
+ { "florin", 556, NULL },
+ { "yacute", 500, NULL },
+ { "Rcommaaccent", 722, NULL },
+ { "fi", 500, NULL },
+ { "fl", 500, NULL },
+ { "Acircumflex", 667, NULL },
+ { "Cacute", 722, NULL },
+ { "Icircumflex", 278, NULL },
+ { "guillemotleft", 556, NULL },
+ { "germandbls", 611, NULL },
+ { "Amacron", 667, NULL },
+ { "seven", 556, NULL },
+ { "Sacute", 667, NULL },
+ { "ordmasculine", 365, NULL },
+ { "dotlessi", 278, NULL },
+ { "sterling", 556, NULL },
+ { "notequal", 549, NULL },
+ { "Imacron", 278, NULL },
+ { "rcommaaccent", 333, NULL },
+ { "Zdotaccent", 611, NULL },
+ { "acircumflex", 556, NULL },
+ { "cacute", 500, NULL },
+ { "Ecaron", 667, NULL },
+ { "icircumflex", 278, NULL },
+ { "braceright", 334, NULL },
+ { "quotedblright", 333, NULL },
+ { "amacron", 556, NULL },
+ { "sacute", 500, NULL },
+ { "imacron", 278, NULL },
+ { "cent", 556, NULL },
+ { "currency", 556, NULL },
+ { "logicalnot", 584, NULL },
+ { "zdotaccent", 500, NULL },
+ { "Atilde", 667, NULL },
+ { "breve", 333, NULL },
+ { "bar", 260, NULL },
+ { "fraction", 167, NULL },
+ { "less", 584, NULL },
+ { "ecaron", 556, NULL },
+ { "guilsinglleft", 333, NULL },
+ { "exclam", 278, NULL },
+ { "period", 278, NULL },
+ { "Rcaron", 722, NULL },
+ { "Kcommaaccent", 667, NULL },
+ { "greater", 584, NULL },
+ { "atilde", 556, NULL },
+ { "brokenbar", 260, NULL },
+ { "quoteleft", 222, NULL },
+ { "Edotaccent", 667, NULL },
+ { "onesuperior", 333, NULL }
+};
+
+static BuiltinFontWidth symbolWidthsTab[] = {
+ { "bracketleftex", 384, NULL },
+ { "alpha", 631, NULL },
+ { "union", 768, NULL },
+ { "infinity", 713, NULL },
+ { "comma", 250, NULL },
+ { "copyrightsans", 790, NULL },
+ { "plusminus", 549, NULL },
+ { "arrowup", 603, NULL },
+ { "apple", 790, NULL },
+ { "parenleftbt", 384, NULL },
+ { "notelement", 713, NULL },
+ { "colon", 278, NULL },
+ { "beta", 549, NULL },
+ { "braceleftbt", 494, NULL },
+ { "Lambda", 686, NULL },
+ { "Phi", 763, NULL },
+ { "minus", 549, NULL },
+ { "space", 250, NULL },
+ { "Sigma", 592, NULL },
+ { "approxequal", 549, NULL },
+ { "minute", 247, NULL },
+ { "circleplus", 768, NULL },
+ { "Omicron", 722, NULL },
+ { "three", 500, NULL },
+ { "numbersign", 500, NULL },
+ { "lambda", 549, NULL },
+ { "phi", 521, NULL },
+ { "aleph", 823, NULL },
+ { "Tau", 611, NULL },
+ { "spade", 753, NULL },
+ { "logicaland", 603, NULL },
+ { "sigma", 603, NULL },
+ { "propersuperset", 713, NULL },
+ { "omicron", 549, NULL },
+ { "question", 444, NULL },
+ { "equal", 549, NULL },
+ { "Epsilon", 611, NULL },
+ { "emptyset", 823, NULL },
+ { "diamond", 753, NULL },
+ { "four", 500, NULL },
+ { "Mu", 889, NULL },
+ { "parenlefttp", 384, NULL },
+ { "club", 753, NULL },
+ { "bullet", 460, NULL },
+ { "Omega", 768, NULL },
+ { "tau", 439, NULL },
+ { "Upsilon", 690, NULL },
+ { "bracelefttp", 494, NULL },
+ { "heart", 753, NULL },
+ { "divide", 549, NULL },
+ { "epsilon", 439, NULL },
+ { "logicalor", 603, NULL },
+ { "parenleftex", 384, NULL },
+ { "greaterequal", 549, NULL },
+ { "mu", 576, NULL },
+ { "Nu", 722, NULL },
+ { "therefore", 863, NULL },
+ { "notsubset", 713, NULL },
+ { "omega", 686, NULL },
+ { "semicolon", 278, NULL },
+ { "element", 713, NULL },
+ { "upsilon", 576, NULL },
+ { "existential", 549, NULL },
+ { "integralbt", 686, NULL },
+ { "lessequal", 549, NULL },
+ { "phi1", 603, NULL },
+ { "lozenge", 494, NULL },
+ { "trademarkserif", 890, NULL },
+ { "parenright", 333, NULL },
+ { "reflexsuperset", 713, NULL },
+ { "sigma1", 439, NULL },
+ { "nu", 521, NULL },
+ { "Gamma", 603, NULL },
+ { "angleright", 329, NULL },
+ { "ellipsis", 1000, NULL },
+ { "Rho", 556, NULL },
+ { "parenrightbt", 384, NULL },
+ { "radicalex", 500, NULL },
+ { "eight", 500, NULL },
+ { "angleleft", 329, NULL },
+ { "arrowdbldown", 603, NULL },
+ { "congruent", 549, NULL },
+ { "Theta", 741, NULL },
+ { "intersection", 768, NULL },
+ { "Pi", 768, NULL },
+ { "slash", 278, NULL },
+ { "registerserif", 790, NULL },
+ { "parenleft", 333, NULL },
+ { "one", 500, NULL },
+ { "gamma", 411, NULL },
+ { "bracketleft", 333, NULL },
+ { "rho", 549, NULL },
+ { "circlemultiply", 768, NULL },
+ { "Chi", 722, NULL },
+ { "theta", 521, NULL },
+ { "pi", 549, NULL },
+ { "integraltp", 686, NULL },
+ { "Eta", 722, NULL },
+ { "product", 823, NULL },
+ { "nine", 500, NULL },
+ { "five", 500, NULL },
+ { "propersubset", 713, NULL },
+ { "bracketrightbt", 384, NULL },
+ { "trademarksans", 786, NULL },
+ { "dotmath", 250, NULL },
+ { "integralex", 686, NULL },
+ { "chi", 549, NULL },
+ { "parenrighttp", 384, NULL },
+ { "eta", 603, NULL },
+ { "underscore", 500, NULL },
+ { "Euro", 750, NULL },
+ { "multiply", 549, NULL },
+ { "zero", 500, NULL },
+ { "partialdiff", 494, NULL },
+ { "angle", 768, NULL },
+ { "arrowdblleft", 987, NULL },
+ { "braceleft", 480, NULL },
+ { "parenrightex", 384, NULL },
+ { "Rfraktur", 795, NULL },
+ { "Zeta", 611, NULL },
+ { "braceex", 494, NULL },
+ { "arrowdblup", 603, NULL },
+ { "arrowdown", 603, NULL },
+ { "Ifraktur", 686, NULL },
+ { "degree", 400, NULL },
+ { "Iota", 333, NULL },
+ { "perpendicular", 658, NULL },
+ { "radical", 549, NULL },
+ { "asteriskmath", 500, NULL },
+ { "percent", 833, NULL },
+ { "zeta", 494, NULL },
+ { "six", 500, NULL },
+ { "two", 500, NULL },
+ { "weierstrass", 987, NULL },
+ { "summation", 713, NULL },
+ { "bracketrighttp", 384, NULL },
+ { "carriagereturn", 658, NULL },
+ { "suchthat", 439, NULL },
+ { "arrowvertex", 603, NULL },
+ { "Delta", 612, NULL },
+ { "iota", 329, NULL },
+ { "arrowhorizex", 1000, NULL },
+ { "bracketrightex", 384, NULL },
+ { "bracketright", 333, NULL },
+ { "ampersand", 778, NULL },
+ { "plus", 549, NULL },
+ { "proportional", 713, NULL },
+ { "delta", 494, NULL },
+ { "copyrightserif", 790, NULL },
+ { "bracerightmid", 494, NULL },
+ { "arrowleft", 987, NULL },
+ { "second", 411, NULL },
+ { "arrowdblboth", 1042, NULL },
+ { "florin", 500, NULL },
+ { "Psi", 795, NULL },
+ { "bracerightbt", 494, NULL },
+ { "bracketleftbt", 384, NULL },
+ { "seven", 500, NULL },
+ { "braceleftmid", 494, NULL },
+ { "notequal", 549, NULL },
+ { "psi", 686, NULL },
+ { "equivalence", 549, NULL },
+ { "universal", 713, NULL },
+ { "arrowdblright", 987, NULL },
+ { "braceright", 480, NULL },
+ { "reflexsubset", 713, NULL },
+ { "Xi", 645, NULL },
+ { "theta1", 631, NULL },
+ { "logicalnot", 713, NULL },
+ { "Kappa", 722, NULL },
+ { "similar", 549, NULL },
+ { "bar", 200, NULL },
+ { "fraction", 167, NULL },
+ { "less", 549, NULL },
+ { "registersans", 790, NULL },
+ { "omega1", 713, NULL },
+ { "exclam", 333, NULL },
+ { "Upsilon1", 620, NULL },
+ { "bracerighttp", 494, NULL },
+ { "xi", 493, NULL },
+ { "period", 250, NULL },
+ { "Alpha", 722, NULL },
+ { "arrowright", 987, NULL },
+ { "greater", 549, NULL },
+ { "bracketlefttp", 384, NULL },
+ { "kappa", 549, NULL },
+ { "gradient", 713, NULL },
+ { "integral", 274, NULL },
+ { "arrowboth", 1042, NULL },
+ { "Beta", 667, NULL }
+};
+
+static BuiltinFontWidth timesBoldWidthsTab[] = {
+ { "Ntilde", 722, NULL },
+ { "rcaron", 444, NULL },
+ { "kcommaaccent", 556, NULL },
+ { "Ncommaaccent", 722, NULL },
+ { "Zacute", 667, NULL },
+ { "comma", 250, NULL },
+ { "cedilla", 333, NULL },
+ { "plusminus", 570, NULL },
+ { "circumflex", 333, NULL },
+ { "dotaccent", 333, NULL },
+ { "edotaccent", 444, NULL },
+ { "asciitilde", 520, NULL },
+ { "colon", 333, NULL },
+ { "onehalf", 750, NULL },
+ { "dollar", 500, NULL },
+ { "Lcaron", 667, NULL },
+ { "ntilde", 556, NULL },
+ { "Aogonek", 722, NULL },
+ { "ncommaaccent", 556, NULL },
+ { "minus", 570, NULL },
+ { "Iogonek", 389, NULL },
+ { "zacute", 444, NULL },
+ { "yen", 500, NULL },
+ { "space", 250, NULL },
+ { "Omacron", 778, NULL },
+ { "questiondown", 500, NULL },
+ { "emdash", 1000, NULL },
+ { "Agrave", 722, NULL },
+ { "three", 500, NULL },
+ { "numbersign", 500, NULL },
+ { "lcaron", 394, NULL },
+ { "A", 722, NULL },
+ { "B", 667, NULL },
+ { "C", 722, NULL },
+ { "aogonek", 500, NULL },
+ { "D", 722, NULL },
+ { "E", 667, NULL },
+ { "onequarter", 750, NULL },
+ { "F", 611, NULL },
+ { "G", 778, NULL },
+ { "H", 778, NULL },
+ { "I", 389, NULL },
+ { "J", 500, NULL },
+ { "K", 778, NULL },
+ { "iogonek", 278, NULL },
+ { "backslash", 278, NULL },
+ { "L", 667, NULL },
+ { "periodcentered", 250, NULL },
+ { "M", 944, NULL },
+ { "N", 722, NULL },
+ { "omacron", 500, NULL },
+ { "Tcommaaccent", 667, NULL },
+ { "O", 778, NULL },
+ { "P", 611, NULL },
+ { "Q", 778, NULL },
+ { "Uhungarumlaut", 722, NULL },
+ { "R", 722, NULL },
+ { "Aacute", 722, NULL },
+ { "caron", 333, NULL },
+ { "S", 556, NULL },
+ { "T", 667, NULL },
+ { "U", 722, NULL },
+ { "agrave", 500, NULL },
+ { "V", 722, NULL },
+ { "W", 1000, NULL },
+ { "X", 722, NULL },
+ { "question", 500, NULL },
+ { "equal", 570, NULL },
+ { "Y", 722, NULL },
+ { "Z", 667, NULL },
+ { "four", 500, NULL },
+ { "a", 500, NULL },
+ { "Gcommaaccent", 778, NULL },
+ { "b", 556, NULL },
+ { "c", 444, NULL },
+ { "d", 556, NULL },
+ { "e", 444, NULL },
+ { "f", 333, NULL },
+ { "g", 500, NULL },
+ { "bullet", 350, NULL },
+ { "h", 556, NULL },
+ { "i", 278, NULL },
+ { "Oslash", 778, NULL },
+ { "dagger", 500, NULL },
+ { "j", 333, NULL },
+ { "k", 556, NULL },
+ { "l", 278, NULL },
+ { "m", 833, NULL },
+ { "n", 556, NULL },
+ { "tcommaaccent", 333, NULL },
+ { "o", 500, NULL },
+ { "ordfeminine", 300, NULL },
+ { "ring", 333, NULL },
+ { "p", 556, NULL },
+ { "q", 556, NULL },
+ { "uhungarumlaut", 556, NULL },
+ { "r", 444, NULL },
+ { "twosuperior", 300, NULL },
+ { "aacute", 500, NULL },
+ { "s", 389, NULL },
+ { "OE", 1000, NULL },
+ { "t", 333, NULL },
+ { "divide", 570, NULL },
+ { "u", 556, NULL },
+ { "Ccaron", 722, NULL },
+ { "v", 500, NULL },
+ { "w", 722, NULL },
+ { "x", 500, NULL },
+ { "y", 500, NULL },
+ { "z", 444, NULL },
+ { "Gbreve", 778, NULL },
+ { "commaaccent", 250, NULL },
+ { "hungarumlaut", 333, NULL },
+ { "Idotaccent", 389, NULL },
+ { "Nacute", 722, NULL },
+ { "quotedbl", 555, NULL },
+ { "gcommaaccent", 500, NULL },
+ { "mu", 556, NULL },
+ { "greaterequal", 549, NULL },
+ { "Scaron", 556, NULL },
+ { "Lslash", 667, NULL },
+ { "semicolon", 333, NULL },
+ { "oslash", 500, NULL },
+ { "lessequal", 549, NULL },
+ { "lozenge", 494, NULL },
+ { "parenright", 333, NULL },
+ { "ccaron", 444, NULL },
+ { "Ecircumflex", 667, NULL },
+ { "gbreve", 500, NULL },
+ { "trademark", 1000, NULL },
+ { "daggerdbl", 500, NULL },
+ { "nacute", 556, NULL },
+ { "macron", 333, NULL },
+ { "Otilde", 778, NULL },
+ { "Emacron", 667, NULL },
+ { "ellipsis", 1000, NULL },
+ { "scaron", 389, NULL },
+ { "AE", 1000, NULL },
+ { "Ucircumflex", 722, NULL },
+ { "lslash", 278, NULL },
+ { "quotedblleft", 500, NULL },
+ { "guilsinglright", 333, NULL },
+ { "hyphen", 333, NULL },
+ { "quotesingle", 278, NULL },
+ { "eight", 500, NULL },
+ { "exclamdown", 333, NULL },
+ { "endash", 500, NULL },
+ { "oe", 722, NULL },
+ { "Abreve", 722, NULL },
+ { "Umacron", 722, NULL },
+ { "ecircumflex", 444, NULL },
+ { "Adieresis", 722, NULL },
+ { "copyright", 747, NULL },
+ { "Egrave", 667, NULL },
+ { "slash", 278, NULL },
+ { "Edieresis", 667, NULL },
+ { "otilde", 500, NULL },
+ { "Idieresis", 389, NULL },
+ { "parenleft", 333, NULL },
+ { "one", 500, NULL },
+ { "emacron", 444, NULL },
+ { "Odieresis", 778, NULL },
+ { "ucircumflex", 556, NULL },
+ { "bracketleft", 333, NULL },
+ { "Ugrave", 722, NULL },
+ { "quoteright", 333, NULL },
+ { "Udieresis", 722, NULL },
+ { "perthousand", 1000, NULL },
+ { "Ydieresis", 722, NULL },
+ { "umacron", 556, NULL },
+ { "abreve", 500, NULL },
+ { "Eacute", 667, NULL },
+ { "adieresis", 500, NULL },
+ { "egrave", 444, NULL },
+ { "edieresis", 444, NULL },
+ { "idieresis", 278, NULL },
+ { "Eth", 722, NULL },
+ { "ae", 722, NULL },
+ { "asterisk", 500, NULL },
+ { "odieresis", 500, NULL },
+ { "Uacute", 722, NULL },
+ { "ugrave", 556, NULL },
+ { "nine", 500, NULL },
+ { "five", 500, NULL },
+ { "udieresis", 556, NULL },
+ { "Zcaron", 667, NULL },
+ { "Scommaaccent", 556, NULL },
+ { "threequarters", 750, NULL },
+ { "guillemotright", 500, NULL },
+ { "Ccedilla", 722, NULL },
+ { "ydieresis", 500, NULL },
+ { "tilde", 333, NULL },
+ { "at", 930, NULL },
+ { "eacute", 444, NULL },
+ { "underscore", 500, NULL },
+ { "Euro", 500, NULL },
+ { "Dcroat", 722, NULL },
+ { "multiply", 570, NULL },
+ { "zero", 500, NULL },
+ { "eth", 500, NULL },
+ { "Scedilla", 556, NULL },
+ { "Ograve", 778, NULL },
+ { "Racute", 722, NULL },
+ { "partialdiff", 494, NULL },
+ { "uacute", 556, NULL },
+ { "braceleft", 394, NULL },
+ { "Thorn", 611, NULL },
+ { "zcaron", 444, NULL },
+ { "scommaaccent", 389, NULL },
+ { "ccedilla", 444, NULL },
+ { "Dcaron", 722, NULL },
+ { "dcroat", 556, NULL },
+ { "Ocircumflex", 778, NULL },
+ { "Oacute", 778, NULL },
+ { "scedilla", 389, NULL },
+ { "ogonek", 333, NULL },
+ { "ograve", 500, NULL },
+ { "racute", 444, NULL },
+ { "Tcaron", 667, NULL },
+ { "Eogonek", 667, NULL },
+ { "thorn", 556, NULL },
+ { "degree", 400, NULL },
+ { "registered", 747, NULL },
+ { "radical", 549, NULL },
+ { "Aring", 722, NULL },
+ { "percent", 1000, NULL },
+ { "six", 500, NULL },
+ { "paragraph", 540, NULL },
+ { "dcaron", 672, NULL },
+ { "Uogonek", 722, NULL },
+ { "two", 500, NULL },
+ { "summation", 600, NULL },
+ { "Igrave", 389, NULL },
+ { "Lacute", 667, NULL },
+ { "ocircumflex", 500, NULL },
+ { "oacute", 500, NULL },
+ { "Uring", 722, NULL },
+ { "Lcommaaccent", 667, NULL },
+ { "tcaron", 416, NULL },
+ { "eogonek", 444, NULL },
+ { "Delta", 612, NULL },
+ { "Ohungarumlaut", 778, NULL },
+ { "asciicircum", 581, NULL },
+ { "aring", 500, NULL },
+ { "grave", 333, NULL },
+ { "uogonek", 556, NULL },
+ { "bracketright", 333, NULL },
+ { "Iacute", 389, NULL },
+ { "ampersand", 833, NULL },
+ { "igrave", 278, NULL },
+ { "lacute", 278, NULL },
+ { "Ncaron", 722, NULL },
+ { "plus", 570, NULL },
+ { "uring", 556, NULL },
+ { "quotesinglbase", 333, NULL },
+ { "lcommaaccent", 278, NULL },
+ { "Yacute", 722, NULL },
+ { "ohungarumlaut", 500, NULL },
+ { "threesuperior", 300, NULL },
+ { "acute", 333, NULL },
+ { "section", 500, NULL },
+ { "dieresis", 333, NULL },
+ { "iacute", 278, NULL },
+ { "quotedblbase", 500, NULL },
+ { "ncaron", 556, NULL },
+ { "florin", 500, NULL },
+ { "yacute", 500, NULL },
+ { "Rcommaaccent", 722, NULL },
+ { "fi", 556, NULL },
+ { "fl", 556, NULL },
+ { "Acircumflex", 722, NULL },
+ { "Cacute", 722, NULL },
+ { "Icircumflex", 389, NULL },
+ { "guillemotleft", 500, NULL },
+ { "germandbls", 556, NULL },
+ { "Amacron", 722, NULL },
+ { "seven", 500, NULL },
+ { "Sacute", 556, NULL },
+ { "ordmasculine", 330, NULL },
+ { "dotlessi", 278, NULL },
+ { "sterling", 500, NULL },
+ { "notequal", 549, NULL },
+ { "Imacron", 389, NULL },
+ { "rcommaaccent", 444, NULL },
+ { "Zdotaccent", 667, NULL },
+ { "acircumflex", 500, NULL },
+ { "cacute", 444, NULL },
+ { "Ecaron", 667, NULL },
+ { "icircumflex", 278, NULL },
+ { "braceright", 394, NULL },
+ { "quotedblright", 500, NULL },
+ { "amacron", 500, NULL },
+ { "sacute", 389, NULL },
+ { "imacron", 278, NULL },
+ { "cent", 500, NULL },
+ { "currency", 500, NULL },
+ { "logicalnot", 570, NULL },
+ { "zdotaccent", 444, NULL },
+ { "Atilde", 722, NULL },
+ { "breve", 333, NULL },
+ { "bar", 220, NULL },
+ { "fraction", 167, NULL },
+ { "less", 570, NULL },
+ { "ecaron", 444, NULL },
+ { "guilsinglleft", 333, NULL },
+ { "exclam", 333, NULL },
+ { "period", 250, NULL },
+ { "Rcaron", 722, NULL },
+ { "Kcommaaccent", 778, NULL },
+ { "greater", 570, NULL },
+ { "atilde", 500, NULL },
+ { "brokenbar", 220, NULL },
+ { "quoteleft", 333, NULL },
+ { "Edotaccent", 667, NULL },
+ { "onesuperior", 300, NULL }
+};
+
+static BuiltinFontWidth timesBoldItalicWidthsTab[] = {
+ { "Ntilde", 722, NULL },
+ { "rcaron", 389, NULL },
+ { "kcommaaccent", 500, NULL },
+ { "Ncommaaccent", 722, NULL },
+ { "Zacute", 611, NULL },
+ { "comma", 250, NULL },
+ { "cedilla", 333, NULL },
+ { "plusminus", 570, NULL },
+ { "circumflex", 333, NULL },
+ { "dotaccent", 333, NULL },
+ { "edotaccent", 444, NULL },
+ { "asciitilde", 570, NULL },
+ { "colon", 333, NULL },
+ { "onehalf", 750, NULL },
+ { "dollar", 500, NULL },
+ { "Lcaron", 611, NULL },
+ { "ntilde", 556, NULL },
+ { "Aogonek", 667, NULL },
+ { "ncommaaccent", 556, NULL },
+ { "minus", 606, NULL },
+ { "Iogonek", 389, NULL },
+ { "zacute", 389, NULL },
+ { "yen", 500, NULL },
+ { "space", 250, NULL },
+ { "Omacron", 722, NULL },
+ { "questiondown", 500, NULL },
+ { "emdash", 1000, NULL },
+ { "Agrave", 667, NULL },
+ { "three", 500, NULL },
+ { "numbersign", 500, NULL },
+ { "lcaron", 382, NULL },
+ { "A", 667, NULL },
+ { "B", 667, NULL },
+ { "C", 667, NULL },
+ { "aogonek", 500, NULL },
+ { "D", 722, NULL },
+ { "E", 667, NULL },
+ { "onequarter", 750, NULL },
+ { "F", 667, NULL },
+ { "G", 722, NULL },
+ { "H", 778, NULL },
+ { "I", 389, NULL },
+ { "J", 500, NULL },
+ { "K", 667, NULL },
+ { "iogonek", 278, NULL },
+ { "backslash", 278, NULL },
+ { "L", 611, NULL },
+ { "periodcentered", 250, NULL },
+ { "M", 889, NULL },
+ { "N", 722, NULL },
+ { "omacron", 500, NULL },
+ { "Tcommaaccent", 611, NULL },
+ { "O", 722, NULL },
+ { "P", 611, NULL },
+ { "Q", 722, NULL },
+ { "Uhungarumlaut", 722, NULL },
+ { "R", 667, NULL },
+ { "Aacute", 667, NULL },
+ { "caron", 333, NULL },
+ { "S", 556, NULL },
+ { "T", 611, NULL },
+ { "U", 722, NULL },
+ { "agrave", 500, NULL },
+ { "V", 667, NULL },
+ { "W", 889, NULL },
+ { "X", 667, NULL },
+ { "question", 500, NULL },
+ { "equal", 570, NULL },
+ { "Y", 611, NULL },
+ { "Z", 611, NULL },
+ { "four", 500, NULL },
+ { "a", 500, NULL },
+ { "Gcommaaccent", 722, NULL },
+ { "b", 500, NULL },
+ { "c", 444, NULL },
+ { "d", 500, NULL },
+ { "e", 444, NULL },
+ { "f", 333, NULL },
+ { "g", 500, NULL },
+ { "bullet", 350, NULL },
+ { "h", 556, NULL },
+ { "i", 278, NULL },
+ { "Oslash", 722, NULL },
+ { "dagger", 500, NULL },
+ { "j", 278, NULL },
+ { "k", 500, NULL },
+ { "l", 278, NULL },
+ { "m", 778, NULL },
+ { "n", 556, NULL },
+ { "tcommaaccent", 278, NULL },
+ { "o", 500, NULL },
+ { "ordfeminine", 266, NULL },
+ { "ring", 333, NULL },
+ { "p", 500, NULL },
+ { "q", 500, NULL },
+ { "uhungarumlaut", 556, NULL },
+ { "r", 389, NULL },
+ { "twosuperior", 300, NULL },
+ { "aacute", 500, NULL },
+ { "s", 389, NULL },
+ { "OE", 944, NULL },
+ { "t", 278, NULL },
+ { "divide", 570, NULL },
+ { "u", 556, NULL },
+ { "Ccaron", 667, NULL },
+ { "v", 444, NULL },
+ { "w", 667, NULL },
+ { "x", 500, NULL },
+ { "y", 444, NULL },
+ { "z", 389, NULL },
+ { "Gbreve", 722, NULL },
+ { "commaaccent", 250, NULL },
+ { "hungarumlaut", 333, NULL },
+ { "Idotaccent", 389, NULL },
+ { "Nacute", 722, NULL },
+ { "quotedbl", 555, NULL },
+ { "gcommaaccent", 500, NULL },
+ { "mu", 576, NULL },
+ { "greaterequal", 549, NULL },
+ { "Scaron", 556, NULL },
+ { "Lslash", 611, NULL },
+ { "semicolon", 333, NULL },
+ { "oslash", 500, NULL },
+ { "lessequal", 549, NULL },
+ { "lozenge", 494, NULL },
+ { "parenright", 333, NULL },
+ { "ccaron", 444, NULL },
+ { "Ecircumflex", 667, NULL },
+ { "gbreve", 500, NULL },
+ { "trademark", 1000, NULL },
+ { "daggerdbl", 500, NULL },
+ { "nacute", 556, NULL },
+ { "macron", 333, NULL },
+ { "Otilde", 722, NULL },
+ { "Emacron", 667, NULL },
+ { "ellipsis", 1000, NULL },
+ { "scaron", 389, NULL },
+ { "AE", 944, NULL },
+ { "Ucircumflex", 722, NULL },
+ { "lslash", 278, NULL },
+ { "quotedblleft", 500, NULL },
+ { "guilsinglright", 333, NULL },
+ { "hyphen", 333, NULL },
+ { "quotesingle", 278, NULL },
+ { "eight", 500, NULL },
+ { "exclamdown", 389, NULL },
+ { "endash", 500, NULL },
+ { "oe", 722, NULL },
+ { "Abreve", 667, NULL },
+ { "Umacron", 722, NULL },
+ { "ecircumflex", 444, NULL },
+ { "Adieresis", 667, NULL },
+ { "copyright", 747, NULL },
+ { "Egrave", 667, NULL },
+ { "slash", 278, NULL },
+ { "Edieresis", 667, NULL },
+ { "otilde", 500, NULL },
+ { "Idieresis", 389, NULL },
+ { "parenleft", 333, NULL },
+ { "one", 500, NULL },
+ { "emacron", 444, NULL },
+ { "Odieresis", 722, NULL },
+ { "ucircumflex", 556, NULL },
+ { "bracketleft", 333, NULL },
+ { "Ugrave", 722, NULL },
+ { "quoteright", 333, NULL },
+ { "Udieresis", 722, NULL },
+ { "perthousand", 1000, NULL },
+ { "Ydieresis", 611, NULL },
+ { "umacron", 556, NULL },
+ { "abreve", 500, NULL },
+ { "Eacute", 667, NULL },
+ { "adieresis", 500, NULL },
+ { "egrave", 444, NULL },
+ { "edieresis", 444, NULL },
+ { "idieresis", 278, NULL },
+ { "Eth", 722, NULL },
+ { "ae", 722, NULL },
+ { "asterisk", 500, NULL },
+ { "odieresis", 500, NULL },
+ { "Uacute", 722, NULL },
+ { "ugrave", 556, NULL },
+ { "nine", 500, NULL },
+ { "five", 500, NULL },
+ { "udieresis", 556, NULL },
+ { "Zcaron", 611, NULL },
+ { "Scommaaccent", 556, NULL },
+ { "threequarters", 750, NULL },
+ { "guillemotright", 500, NULL },
+ { "Ccedilla", 667, NULL },
+ { "ydieresis", 444, NULL },
+ { "tilde", 333, NULL },
+ { "at", 832, NULL },
+ { "eacute", 444, NULL },
+ { "underscore", 500, NULL },
+ { "Euro", 500, NULL },
+ { "Dcroat", 722, NULL },
+ { "multiply", 570, NULL },
+ { "zero", 500, NULL },
+ { "eth", 500, NULL },
+ { "Scedilla", 556, NULL },
+ { "Ograve", 722, NULL },
+ { "Racute", 667, NULL },
+ { "partialdiff", 494, NULL },
+ { "uacute", 556, NULL },
+ { "braceleft", 348, NULL },
+ { "Thorn", 611, NULL },
+ { "zcaron", 389, NULL },
+ { "scommaaccent", 389, NULL },
+ { "ccedilla", 444, NULL },
+ { "Dcaron", 722, NULL },
+ { "dcroat", 500, NULL },
+ { "Ocircumflex", 722, NULL },
+ { "Oacute", 722, NULL },
+ { "scedilla", 389, NULL },
+ { "ogonek", 333, NULL },
+ { "ograve", 500, NULL },
+ { "racute", 389, NULL },
+ { "Tcaron", 611, NULL },
+ { "Eogonek", 667, NULL },
+ { "thorn", 500, NULL },
+ { "degree", 400, NULL },
+ { "registered", 747, NULL },
+ { "radical", 549, NULL },
+ { "Aring", 667, NULL },
+ { "percent", 833, NULL },
+ { "six", 500, NULL },
+ { "paragraph", 500, NULL },
+ { "dcaron", 608, NULL },
+ { "Uogonek", 722, NULL },
+ { "two", 500, NULL },
+ { "summation", 600, NULL },
+ { "Igrave", 389, NULL },
+ { "Lacute", 611, NULL },
+ { "ocircumflex", 500, NULL },
+ { "oacute", 500, NULL },
+ { "Uring", 722, NULL },
+ { "Lcommaaccent", 611, NULL },
+ { "tcaron", 366, NULL },
+ { "eogonek", 444, NULL },
+ { "Delta", 612, NULL },
+ { "Ohungarumlaut", 722, NULL },
+ { "asciicircum", 570, NULL },
+ { "aring", 500, NULL },
+ { "grave", 333, NULL },
+ { "uogonek", 556, NULL },
+ { "bracketright", 333, NULL },
+ { "Iacute", 389, NULL },
+ { "ampersand", 778, NULL },
+ { "igrave", 278, NULL },
+ { "lacute", 278, NULL },
+ { "Ncaron", 722, NULL },
+ { "plus", 570, NULL },
+ { "uring", 556, NULL },
+ { "quotesinglbase", 333, NULL },
+ { "lcommaaccent", 278, NULL },
+ { "Yacute", 611, NULL },
+ { "ohungarumlaut", 500, NULL },
+ { "threesuperior", 300, NULL },
+ { "acute", 333, NULL },
+ { "section", 500, NULL },
+ { "dieresis", 333, NULL },
+ { "iacute", 278, NULL },
+ { "quotedblbase", 500, NULL },
+ { "ncaron", 556, NULL },
+ { "florin", 500, NULL },
+ { "yacute", 444, NULL },
+ { "Rcommaaccent", 667, NULL },
+ { "fi", 556, NULL },
+ { "fl", 556, NULL },
+ { "Acircumflex", 667, NULL },
+ { "Cacute", 667, NULL },
+ { "Icircumflex", 389, NULL },
+ { "guillemotleft", 500, NULL },
+ { "germandbls", 500, NULL },
+ { "Amacron", 667, NULL },
+ { "seven", 500, NULL },
+ { "Sacute", 556, NULL },
+ { "ordmasculine", 300, NULL },
+ { "dotlessi", 278, NULL },
+ { "sterling", 500, NULL },
+ { "notequal", 549, NULL },
+ { "Imacron", 389, NULL },
+ { "rcommaaccent", 389, NULL },
+ { "Zdotaccent", 611, NULL },
+ { "acircumflex", 500, NULL },
+ { "cacute", 444, NULL },
+ { "Ecaron", 667, NULL },
+ { "icircumflex", 278, NULL },
+ { "braceright", 348, NULL },
+ { "quotedblright", 500, NULL },
+ { "amacron", 500, NULL },
+ { "sacute", 389, NULL },
+ { "imacron", 278, NULL },
+ { "cent", 500, NULL },
+ { "currency", 500, NULL },
+ { "logicalnot", 606, NULL },
+ { "zdotaccent", 389, NULL },
+ { "Atilde", 667, NULL },
+ { "breve", 333, NULL },
+ { "bar", 220, NULL },
+ { "fraction", 167, NULL },
+ { "less", 570, NULL },
+ { "ecaron", 444, NULL },
+ { "guilsinglleft", 333, NULL },
+ { "exclam", 389, NULL },
+ { "period", 250, NULL },
+ { "Rcaron", 667, NULL },
+ { "Kcommaaccent", 667, NULL },
+ { "greater", 570, NULL },
+ { "atilde", 500, NULL },
+ { "brokenbar", 220, NULL },
+ { "quoteleft", 333, NULL },
+ { "Edotaccent", 667, NULL },
+ { "onesuperior", 300, NULL }
+};
+
+static BuiltinFontWidth timesItalicWidthsTab[] = {
+ { "Ntilde", 667, NULL },
+ { "rcaron", 389, NULL },
+ { "kcommaaccent", 444, NULL },
+ { "Ncommaaccent", 667, NULL },
+ { "Zacute", 556, NULL },
+ { "comma", 250, NULL },
+ { "cedilla", 333, NULL },
+ { "plusminus", 675, NULL },
+ { "circumflex", 333, NULL },
+ { "dotaccent", 333, NULL },
+ { "edotaccent", 444, NULL },
+ { "asciitilde", 541, NULL },
+ { "colon", 333, NULL },
+ { "onehalf", 750, NULL },
+ { "dollar", 500, NULL },
+ { "Lcaron", 611, NULL },
+ { "ntilde", 500, NULL },
+ { "Aogonek", 611, NULL },
+ { "ncommaaccent", 500, NULL },
+ { "minus", 675, NULL },
+ { "Iogonek", 333, NULL },
+ { "zacute", 389, NULL },
+ { "yen", 500, NULL },
+ { "space", 250, NULL },
+ { "Omacron", 722, NULL },
+ { "questiondown", 500, NULL },
+ { "emdash", 889, NULL },
+ { "Agrave", 611, NULL },
+ { "three", 500, NULL },
+ { "numbersign", 500, NULL },
+ { "lcaron", 300, NULL },
+ { "A", 611, NULL },
+ { "B", 611, NULL },
+ { "C", 667, NULL },
+ { "aogonek", 500, NULL },
+ { "D", 722, NULL },
+ { "E", 611, NULL },
+ { "onequarter", 750, NULL },
+ { "F", 611, NULL },
+ { "G", 722, NULL },
+ { "H", 722, NULL },
+ { "I", 333, NULL },
+ { "J", 444, NULL },
+ { "K", 667, NULL },
+ { "iogonek", 278, NULL },
+ { "backslash", 278, NULL },
+ { "L", 556, NULL },
+ { "periodcentered", 250, NULL },
+ { "M", 833, NULL },
+ { "N", 667, NULL },
+ { "omacron", 500, NULL },
+ { "Tcommaaccent", 556, NULL },
+ { "O", 722, NULL },
+ { "P", 611, NULL },
+ { "Q", 722, NULL },
+ { "Uhungarumlaut", 722, NULL },
+ { "R", 611, NULL },
+ { "Aacute", 611, NULL },
+ { "caron", 333, NULL },
+ { "S", 500, NULL },
+ { "T", 556, NULL },
+ { "U", 722, NULL },
+ { "agrave", 500, NULL },
+ { "V", 611, NULL },
+ { "W", 833, NULL },
+ { "X", 611, NULL },
+ { "question", 500, NULL },
+ { "equal", 675, NULL },
+ { "Y", 556, NULL },
+ { "Z", 556, NULL },
+ { "four", 500, NULL },
+ { "a", 500, NULL },
+ { "Gcommaaccent", 722, NULL },
+ { "b", 500, NULL },
+ { "c", 444, NULL },
+ { "d", 500, NULL },
+ { "e", 444, NULL },
+ { "f", 278, NULL },
+ { "g", 500, NULL },
+ { "bullet", 350, NULL },
+ { "h", 500, NULL },
+ { "i", 278, NULL },
+ { "Oslash", 722, NULL },
+ { "dagger", 500, NULL },
+ { "j", 278, NULL },
+ { "k", 444, NULL },
+ { "l", 278, NULL },
+ { "m", 722, NULL },
+ { "n", 500, NULL },
+ { "tcommaaccent", 278, NULL },
+ { "o", 500, NULL },
+ { "ordfeminine", 276, NULL },
+ { "ring", 333, NULL },
+ { "p", 500, NULL },
+ { "q", 500, NULL },
+ { "uhungarumlaut", 500, NULL },
+ { "r", 389, NULL },
+ { "twosuperior", 300, NULL },
+ { "aacute", 500, NULL },
+ { "s", 389, NULL },
+ { "OE", 944, NULL },
+ { "t", 278, NULL },
+ { "divide", 675, NULL },
+ { "u", 500, NULL },
+ { "Ccaron", 667, NULL },
+ { "v", 444, NULL },
+ { "w", 667, NULL },
+ { "x", 444, NULL },
+ { "y", 444, NULL },
+ { "z", 389, NULL },
+ { "Gbreve", 722, NULL },
+ { "commaaccent", 250, NULL },
+ { "hungarumlaut", 333, NULL },
+ { "Idotaccent", 333, NULL },
+ { "Nacute", 667, NULL },
+ { "quotedbl", 420, NULL },
+ { "gcommaaccent", 500, NULL },
+ { "mu", 500, NULL },
+ { "greaterequal", 549, NULL },
+ { "Scaron", 500, NULL },
+ { "Lslash", 556, NULL },
+ { "semicolon", 333, NULL },
+ { "oslash", 500, NULL },
+ { "lessequal", 549, NULL },
+ { "lozenge", 471, NULL },
+ { "parenright", 333, NULL },
+ { "ccaron", 444, NULL },
+ { "Ecircumflex", 611, NULL },
+ { "gbreve", 500, NULL },
+ { "trademark", 980, NULL },
+ { "daggerdbl", 500, NULL },
+ { "nacute", 500, NULL },
+ { "macron", 333, NULL },
+ { "Otilde", 722, NULL },
+ { "Emacron", 611, NULL },
+ { "ellipsis", 889, NULL },
+ { "scaron", 389, NULL },
+ { "AE", 889, NULL },
+ { "Ucircumflex", 722, NULL },
+ { "lslash", 278, NULL },
+ { "quotedblleft", 556, NULL },
+ { "guilsinglright", 333, NULL },
+ { "hyphen", 333, NULL },
+ { "quotesingle", 214, NULL },
+ { "eight", 500, NULL },
+ { "exclamdown", 389, NULL },
+ { "endash", 500, NULL },
+ { "oe", 667, NULL },
+ { "Abreve", 611, NULL },
+ { "Umacron", 722, NULL },
+ { "ecircumflex", 444, NULL },
+ { "Adieresis", 611, NULL },
+ { "copyright", 760, NULL },
+ { "Egrave", 611, NULL },
+ { "slash", 278, NULL },
+ { "Edieresis", 611, NULL },
+ { "otilde", 500, NULL },
+ { "Idieresis", 333, NULL },
+ { "parenleft", 333, NULL },
+ { "one", 500, NULL },
+ { "emacron", 444, NULL },
+ { "Odieresis", 722, NULL },
+ { "ucircumflex", 500, NULL },
+ { "bracketleft", 389, NULL },
+ { "Ugrave", 722, NULL },
+ { "quoteright", 333, NULL },
+ { "Udieresis", 722, NULL },
+ { "perthousand", 1000, NULL },
+ { "Ydieresis", 556, NULL },
+ { "umacron", 500, NULL },
+ { "abreve", 500, NULL },
+ { "Eacute", 611, NULL },
+ { "adieresis", 500, NULL },
+ { "egrave", 444, NULL },
+ { "edieresis", 444, NULL },
+ { "idieresis", 278, NULL },
+ { "Eth", 722, NULL },
+ { "ae", 667, NULL },
+ { "asterisk", 500, NULL },
+ { "odieresis", 500, NULL },
+ { "Uacute", 722, NULL },
+ { "ugrave", 500, NULL },
+ { "nine", 500, NULL },
+ { "five", 500, NULL },
+ { "udieresis", 500, NULL },
+ { "Zcaron", 556, NULL },
+ { "Scommaaccent", 500, NULL },
+ { "threequarters", 750, NULL },
+ { "guillemotright", 500, NULL },
+ { "Ccedilla", 667, NULL },
+ { "ydieresis", 444, NULL },
+ { "tilde", 333, NULL },
+ { "at", 920, NULL },
+ { "eacute", 444, NULL },
+ { "underscore", 500, NULL },
+ { "Euro", 500, NULL },
+ { "Dcroat", 722, NULL },
+ { "multiply", 675, NULL },
+ { "zero", 500, NULL },
+ { "eth", 500, NULL },
+ { "Scedilla", 500, NULL },
+ { "Ograve", 722, NULL },
+ { "Racute", 611, NULL },
+ { "partialdiff", 476, NULL },
+ { "uacute", 500, NULL },
+ { "braceleft", 400, NULL },
+ { "Thorn", 611, NULL },
+ { "zcaron", 389, NULL },
+ { "scommaaccent", 389, NULL },
+ { "ccedilla", 444, NULL },
+ { "Dcaron", 722, NULL },
+ { "dcroat", 500, NULL },
+ { "Ocircumflex", 722, NULL },
+ { "Oacute", 722, NULL },
+ { "scedilla", 389, NULL },
+ { "ogonek", 333, NULL },
+ { "ograve", 500, NULL },
+ { "racute", 389, NULL },
+ { "Tcaron", 556, NULL },
+ { "Eogonek", 611, NULL },
+ { "thorn", 500, NULL },
+ { "degree", 400, NULL },
+ { "registered", 760, NULL },
+ { "radical", 453, NULL },
+ { "Aring", 611, NULL },
+ { "percent", 833, NULL },
+ { "six", 500, NULL },
+ { "paragraph", 523, NULL },
+ { "dcaron", 544, NULL },
+ { "Uogonek", 722, NULL },
+ { "two", 500, NULL },
+ { "summation", 600, NULL },
+ { "Igrave", 333, NULL },
+ { "Lacute", 556, NULL },
+ { "ocircumflex", 500, NULL },
+ { "oacute", 500, NULL },
+ { "Uring", 722, NULL },
+ { "Lcommaaccent", 556, NULL },
+ { "tcaron", 300, NULL },
+ { "eogonek", 444, NULL },
+ { "Delta", 612, NULL },
+ { "Ohungarumlaut", 722, NULL },
+ { "asciicircum", 422, NULL },
+ { "aring", 500, NULL },
+ { "grave", 333, NULL },
+ { "uogonek", 500, NULL },
+ { "bracketright", 389, NULL },
+ { "Iacute", 333, NULL },
+ { "ampersand", 778, NULL },
+ { "igrave", 278, NULL },
+ { "lacute", 278, NULL },
+ { "Ncaron", 667, NULL },
+ { "plus", 675, NULL },
+ { "uring", 500, NULL },
+ { "quotesinglbase", 333, NULL },
+ { "lcommaaccent", 278, NULL },
+ { "Yacute", 556, NULL },
+ { "ohungarumlaut", 500, NULL },
+ { "threesuperior", 300, NULL },
+ { "acute", 333, NULL },
+ { "section", 500, NULL },
+ { "dieresis", 333, NULL },
+ { "iacute", 278, NULL },
+ { "quotedblbase", 556, NULL },
+ { "ncaron", 500, NULL },
+ { "florin", 500, NULL },
+ { "yacute", 444, NULL },
+ { "Rcommaaccent", 611, NULL },
+ { "fi", 500, NULL },
+ { "fl", 500, NULL },
+ { "Acircumflex", 611, NULL },
+ { "Cacute", 667, NULL },
+ { "Icircumflex", 333, NULL },
+ { "guillemotleft", 500, NULL },
+ { "germandbls", 500, NULL },
+ { "Amacron", 611, NULL },
+ { "seven", 500, NULL },
+ { "Sacute", 500, NULL },
+ { "ordmasculine", 310, NULL },
+ { "dotlessi", 278, NULL },
+ { "sterling", 500, NULL },
+ { "notequal", 549, NULL },
+ { "Imacron", 333, NULL },
+ { "rcommaaccent", 389, NULL },
+ { "Zdotaccent", 556, NULL },
+ { "acircumflex", 500, NULL },
+ { "cacute", 444, NULL },
+ { "Ecaron", 611, NULL },
+ { "icircumflex", 278, NULL },
+ { "braceright", 400, NULL },
+ { "quotedblright", 556, NULL },
+ { "amacron", 500, NULL },
+ { "sacute", 389, NULL },
+ { "imacron", 278, NULL },
+ { "cent", 500, NULL },
+ { "currency", 500, NULL },
+ { "logicalnot", 675, NULL },
+ { "zdotaccent", 389, NULL },
+ { "Atilde", 611, NULL },
+ { "breve", 333, NULL },
+ { "bar", 275, NULL },
+ { "fraction", 167, NULL },
+ { "less", 675, NULL },
+ { "ecaron", 444, NULL },
+ { "guilsinglleft", 333, NULL },
+ { "exclam", 333, NULL },
+ { "period", 250, NULL },
+ { "Rcaron", 611, NULL },
+ { "Kcommaaccent", 667, NULL },
+ { "greater", 675, NULL },
+ { "atilde", 500, NULL },
+ { "brokenbar", 275, NULL },
+ { "quoteleft", 333, NULL },
+ { "Edotaccent", 611, NULL },
+ { "onesuperior", 300, NULL }
+};
+
+static BuiltinFontWidth timesRomanWidthsTab[] = {
+ { "Ntilde", 722, NULL },
+ { "rcaron", 333, NULL },
+ { "kcommaaccent", 500, NULL },
+ { "Ncommaaccent", 722, NULL },
+ { "Zacute", 611, NULL },
+ { "comma", 250, NULL },
+ { "cedilla", 333, NULL },
+ { "plusminus", 564, NULL },
+ { "circumflex", 333, NULL },
+ { "dotaccent", 333, NULL },
+ { "edotaccent", 444, NULL },
+ { "asciitilde", 541, NULL },
+ { "colon", 278, NULL },
+ { "onehalf", 750, NULL },
+ { "dollar", 500, NULL },
+ { "Lcaron", 611, NULL },
+ { "ntilde", 500, NULL },
+ { "Aogonek", 722, NULL },
+ { "ncommaaccent", 500, NULL },
+ { "minus", 564, NULL },
+ { "Iogonek", 333, NULL },
+ { "zacute", 444, NULL },
+ { "yen", 500, NULL },
+ { "space", 250, NULL },
+ { "Omacron", 722, NULL },
+ { "questiondown", 444, NULL },
+ { "emdash", 1000, NULL },
+ { "Agrave", 722, NULL },
+ { "three", 500, NULL },
+ { "numbersign", 500, NULL },
+ { "lcaron", 344, NULL },
+ { "A", 722, NULL },
+ { "B", 667, NULL },
+ { "C", 667, NULL },
+ { "aogonek", 444, NULL },
+ { "D", 722, NULL },
+ { "E", 611, NULL },
+ { "onequarter", 750, NULL },
+ { "F", 556, NULL },
+ { "G", 722, NULL },
+ { "H", 722, NULL },
+ { "I", 333, NULL },
+ { "J", 389, NULL },
+ { "K", 722, NULL },
+ { "iogonek", 278, NULL },
+ { "backslash", 278, NULL },
+ { "L", 611, NULL },
+ { "periodcentered", 250, NULL },
+ { "M", 889, NULL },
+ { "N", 722, NULL },
+ { "omacron", 500, NULL },
+ { "Tcommaaccent", 611, NULL },
+ { "O", 722, NULL },
+ { "P", 556, NULL },
+ { "Q", 722, NULL },
+ { "Uhungarumlaut", 722, NULL },
+ { "R", 667, NULL },
+ { "Aacute", 722, NULL },
+ { "caron", 333, NULL },
+ { "S", 556, NULL },
+ { "T", 611, NULL },
+ { "U", 722, NULL },
+ { "agrave", 444, NULL },
+ { "V", 722, NULL },
+ { "W", 944, NULL },
+ { "X", 722, NULL },
+ { "question", 444, NULL },
+ { "equal", 564, NULL },
+ { "Y", 722, NULL },
+ { "Z", 611, NULL },
+ { "four", 500, NULL },
+ { "a", 444, NULL },
+ { "Gcommaaccent", 722, NULL },
+ { "b", 500, NULL },
+ { "c", 444, NULL },
+ { "d", 500, NULL },
+ { "e", 444, NULL },
+ { "f", 333, NULL },
+ { "g", 500, NULL },
+ { "bullet", 350, NULL },
+ { "h", 500, NULL },
+ { "i", 278, NULL },
+ { "Oslash", 722, NULL },
+ { "dagger", 500, NULL },
+ { "j", 278, NULL },
+ { "k", 500, NULL },
+ { "l", 278, NULL },
+ { "m", 778, NULL },
+ { "n", 500, NULL },
+ { "tcommaaccent", 278, NULL },
+ { "o", 500, NULL },
+ { "ordfeminine", 276, NULL },
+ { "ring", 333, NULL },
+ { "p", 500, NULL },
+ { "q", 500, NULL },
+ { "uhungarumlaut", 500, NULL },
+ { "r", 333, NULL },
+ { "twosuperior", 300, NULL },
+ { "aacute", 444, NULL },
+ { "s", 389, NULL },
+ { "OE", 889, NULL },
+ { "t", 278, NULL },
+ { "divide", 564, NULL },
+ { "u", 500, NULL },
+ { "Ccaron", 667, NULL },
+ { "v", 500, NULL },
+ { "w", 722, NULL },
+ { "x", 500, NULL },
+ { "y", 500, NULL },
+ { "z", 444, NULL },
+ { "Gbreve", 722, NULL },
+ { "commaaccent", 250, NULL },
+ { "hungarumlaut", 333, NULL },
+ { "Idotaccent", 333, NULL },
+ { "Nacute", 722, NULL },
+ { "quotedbl", 408, NULL },
+ { "gcommaaccent", 500, NULL },
+ { "mu", 500, NULL },
+ { "greaterequal", 549, NULL },
+ { "Scaron", 556, NULL },
+ { "Lslash", 611, NULL },
+ { "semicolon", 278, NULL },
+ { "oslash", 500, NULL },
+ { "lessequal", 549, NULL },
+ { "lozenge", 471, NULL },
+ { "parenright", 333, NULL },
+ { "ccaron", 444, NULL },
+ { "Ecircumflex", 611, NULL },
+ { "gbreve", 500, NULL },
+ { "trademark", 980, NULL },
+ { "daggerdbl", 500, NULL },
+ { "nacute", 500, NULL },
+ { "macron", 333, NULL },
+ { "Otilde", 722, NULL },
+ { "Emacron", 611, NULL },
+ { "ellipsis", 1000, NULL },
+ { "scaron", 389, NULL },
+ { "AE", 889, NULL },
+ { "Ucircumflex", 722, NULL },
+ { "lslash", 278, NULL },
+ { "quotedblleft", 444, NULL },
+ { "guilsinglright", 333, NULL },
+ { "hyphen", 333, NULL },
+ { "quotesingle", 180, NULL },
+ { "eight", 500, NULL },
+ { "exclamdown", 333, NULL },
+ { "endash", 500, NULL },
+ { "oe", 722, NULL },
+ { "Abreve", 722, NULL },
+ { "Umacron", 722, NULL },
+ { "ecircumflex", 444, NULL },
+ { "Adieresis", 722, NULL },
+ { "copyright", 760, NULL },
+ { "Egrave", 611, NULL },
+ { "slash", 278, NULL },
+ { "Edieresis", 611, NULL },
+ { "otilde", 500, NULL },
+ { "Idieresis", 333, NULL },
+ { "parenleft", 333, NULL },
+ { "one", 500, NULL },
+ { "emacron", 444, NULL },
+ { "Odieresis", 722, NULL },
+ { "ucircumflex", 500, NULL },
+ { "bracketleft", 333, NULL },
+ { "Ugrave", 722, NULL },
+ { "quoteright", 333, NULL },
+ { "Udieresis", 722, NULL },
+ { "perthousand", 1000, NULL },
+ { "Ydieresis", 722, NULL },
+ { "umacron", 500, NULL },
+ { "abreve", 444, NULL },
+ { "Eacute", 611, NULL },
+ { "adieresis", 444, NULL },
+ { "egrave", 444, NULL },
+ { "edieresis", 444, NULL },
+ { "idieresis", 278, NULL },
+ { "Eth", 722, NULL },
+ { "ae", 667, NULL },
+ { "asterisk", 500, NULL },
+ { "odieresis", 500, NULL },
+ { "Uacute", 722, NULL },
+ { "ugrave", 500, NULL },
+ { "nine", 500, NULL },
+ { "five", 500, NULL },
+ { "udieresis", 500, NULL },
+ { "Zcaron", 611, NULL },
+ { "Scommaaccent", 556, NULL },
+ { "threequarters", 750, NULL },
+ { "guillemotright", 500, NULL },
+ { "Ccedilla", 667, NULL },
+ { "ydieresis", 500, NULL },
+ { "tilde", 333, NULL },
+ { "at", 921, NULL },
+ { "eacute", 444, NULL },
+ { "underscore", 500, NULL },
+ { "Euro", 500, NULL },
+ { "Dcroat", 722, NULL },
+ { "multiply", 564, NULL },
+ { "zero", 500, NULL },
+ { "eth", 500, NULL },
+ { "Scedilla", 556, NULL },
+ { "Ograve", 722, NULL },
+ { "Racute", 667, NULL },
+ { "partialdiff", 476, NULL },
+ { "uacute", 500, NULL },
+ { "braceleft", 480, NULL },
+ { "Thorn", 556, NULL },
+ { "zcaron", 444, NULL },
+ { "scommaaccent", 389, NULL },
+ { "ccedilla", 444, NULL },
+ { "Dcaron", 722, NULL },
+ { "dcroat", 500, NULL },
+ { "Ocircumflex", 722, NULL },
+ { "Oacute", 722, NULL },
+ { "scedilla", 389, NULL },
+ { "ogonek", 333, NULL },
+ { "ograve", 500, NULL },
+ { "racute", 333, NULL },
+ { "Tcaron", 611, NULL },
+ { "Eogonek", 611, NULL },
+ { "thorn", 500, NULL },
+ { "degree", 400, NULL },
+ { "registered", 760, NULL },
+ { "radical", 453, NULL },
+ { "Aring", 722, NULL },
+ { "percent", 833, NULL },
+ { "six", 500, NULL },
+ { "paragraph", 453, NULL },
+ { "dcaron", 588, NULL },
+ { "Uogonek", 722, NULL },
+ { "two", 500, NULL },
+ { "summation", 600, NULL },
+ { "Igrave", 333, NULL },
+ { "Lacute", 611, NULL },
+ { "ocircumflex", 500, NULL },
+ { "oacute", 500, NULL },
+ { "Uring", 722, NULL },
+ { "Lcommaaccent", 611, NULL },
+ { "tcaron", 326, NULL },
+ { "eogonek", 444, NULL },
+ { "Delta", 612, NULL },
+ { "Ohungarumlaut", 722, NULL },
+ { "asciicircum", 469, NULL },
+ { "aring", 444, NULL },
+ { "grave", 333, NULL },
+ { "uogonek", 500, NULL },
+ { "bracketright", 333, NULL },
+ { "Iacute", 333, NULL },
+ { "ampersand", 778, NULL },
+ { "igrave", 278, NULL },
+ { "lacute", 278, NULL },
+ { "Ncaron", 722, NULL },
+ { "plus", 564, NULL },
+ { "uring", 500, NULL },
+ { "quotesinglbase", 333, NULL },
+ { "lcommaaccent", 278, NULL },
+ { "Yacute", 722, NULL },
+ { "ohungarumlaut", 500, NULL },
+ { "threesuperior", 300, NULL },
+ { "acute", 333, NULL },
+ { "section", 500, NULL },
+ { "dieresis", 333, NULL },
+ { "iacute", 278, NULL },
+ { "quotedblbase", 444, NULL },
+ { "ncaron", 500, NULL },
+ { "florin", 500, NULL },
+ { "yacute", 500, NULL },
+ { "Rcommaaccent", 667, NULL },
+ { "fi", 556, NULL },
+ { "fl", 556, NULL },
+ { "Acircumflex", 722, NULL },
+ { "Cacute", 667, NULL },
+ { "Icircumflex", 333, NULL },
+ { "guillemotleft", 500, NULL },
+ { "germandbls", 500, NULL },
+ { "Amacron", 722, NULL },
+ { "seven", 500, NULL },
+ { "Sacute", 556, NULL },
+ { "ordmasculine", 310, NULL },
+ { "dotlessi", 278, NULL },
+ { "sterling", 500, NULL },
+ { "notequal", 549, NULL },
+ { "Imacron", 333, NULL },
+ { "rcommaaccent", 333, NULL },
+ { "Zdotaccent", 611, NULL },
+ { "acircumflex", 444, NULL },
+ { "cacute", 444, NULL },
+ { "Ecaron", 611, NULL },
+ { "icircumflex", 278, NULL },
+ { "braceright", 480, NULL },
+ { "quotedblright", 444, NULL },
+ { "amacron", 444, NULL },
+ { "sacute", 389, NULL },
+ { "imacron", 278, NULL },
+ { "cent", 500, NULL },
+ { "currency", 500, NULL },
+ { "logicalnot", 564, NULL },
+ { "zdotaccent", 444, NULL },
+ { "Atilde", 722, NULL },
+ { "breve", 333, NULL },
+ { "bar", 200, NULL },
+ { "fraction", 167, NULL },
+ { "less", 564, NULL },
+ { "ecaron", 444, NULL },
+ { "guilsinglleft", 333, NULL },
+ { "exclam", 333, NULL },
+ { "period", 250, NULL },
+ { "Rcaron", 667, NULL },
+ { "Kcommaaccent", 722, NULL },
+ { "greater", 564, NULL },
+ { "atilde", 444, NULL },
+ { "brokenbar", 200, NULL },
+ { "quoteleft", 333, NULL },
+ { "Edotaccent", 611, NULL },
+ { "onesuperior", 300, NULL }
+};
+
+static BuiltinFontWidth zapfDingbatsWidthsTab[] = {
+ { "a81", 438, NULL },
+ { "a82", 138, NULL },
+ { "a83", 277, NULL },
+ { "a84", 415, NULL },
+ { "a85", 509, NULL },
+ { "a86", 410, NULL },
+ { "a87", 234, NULL },
+ { "a88", 234, NULL },
+ { "a89", 390, NULL },
+ { "a140", 788, NULL },
+ { "a141", 788, NULL },
+ { "a142", 788, NULL },
+ { "a143", 788, NULL },
+ { "a144", 788, NULL },
+ { "a145", 788, NULL },
+ { "a146", 788, NULL },
+ { "a147", 788, NULL },
+ { "a148", 788, NULL },
+ { "a149", 788, NULL },
+ { "a90", 390, NULL },
+ { "a91", 276, NULL },
+ { "a92", 276, NULL },
+ { "space", 278, NULL },
+ { "a93", 317, NULL },
+ { "a94", 317, NULL },
+ { "a95", 334, NULL },
+ { "a96", 334, NULL },
+ { "a97", 392, NULL },
+ { "a98", 392, NULL },
+ { "a99", 668, NULL },
+ { "a150", 788, NULL },
+ { "a151", 788, NULL },
+ { "a152", 788, NULL },
+ { "a153", 788, NULL },
+ { "a154", 788, NULL },
+ { "a155", 788, NULL },
+ { "a156", 788, NULL },
+ { "a157", 788, NULL },
+ { "a158", 788, NULL },
+ { "a159", 788, NULL },
+ { "a160", 894, NULL },
+ { "a161", 838, NULL },
+ { "a162", 924, NULL },
+ { "a163", 1016, NULL },
+ { "a164", 458, NULL },
+ { "a165", 924, NULL },
+ { "a166", 918, NULL },
+ { "a167", 927, NULL },
+ { "a168", 928, NULL },
+ { "a169", 928, NULL },
+ { "a170", 834, NULL },
+ { "a171", 873, NULL },
+ { "a172", 828, NULL },
+ { "a173", 924, NULL },
+ { "a174", 917, NULL },
+ { "a175", 930, NULL },
+ { "a176", 931, NULL },
+ { "a177", 463, NULL },
+ { "a178", 883, NULL },
+ { "a179", 836, NULL },
+ { "a180", 867, NULL },
+ { "a181", 696, NULL },
+ { "a182", 874, NULL },
+ { "a183", 760, NULL },
+ { "a184", 946, NULL },
+ { "a185", 865, NULL },
+ { "a186", 967, NULL },
+ { "a187", 831, NULL },
+ { "a188", 873, NULL },
+ { "a189", 927, NULL },
+ { "a1", 974, NULL },
+ { "a2", 961, NULL },
+ { "a3", 980, NULL },
+ { "a4", 719, NULL },
+ { "a5", 789, NULL },
+ { "a6", 494, NULL },
+ { "a7", 552, NULL },
+ { "a8", 537, NULL },
+ { "a9", 577, NULL },
+ { "a190", 970, NULL },
+ { "a191", 918, NULL },
+ { "a192", 748, NULL },
+ { "a193", 836, NULL },
+ { "a194", 771, NULL },
+ { "a195", 888, NULL },
+ { "a196", 748, NULL },
+ { "a197", 771, NULL },
+ { "a198", 888, NULL },
+ { "a199", 867, NULL },
+ { "a10", 692, NULL },
+ { "a11", 960, NULL },
+ { "a12", 939, NULL },
+ { "a13", 549, NULL },
+ { "a14", 855, NULL },
+ { "a15", 911, NULL },
+ { "a16", 933, NULL },
+ { "a17", 945, NULL },
+ { "a18", 974, NULL },
+ { "a19", 755, NULL },
+ { "a20", 846, NULL },
+ { "a21", 762, NULL },
+ { "a22", 761, NULL },
+ { "a23", 571, NULL },
+ { "a24", 677, NULL },
+ { "a25", 763, NULL },
+ { "a26", 760, NULL },
+ { "a27", 759, NULL },
+ { "a28", 754, NULL },
+ { "a29", 786, NULL },
+ { "a30", 788, NULL },
+ { "a31", 788, NULL },
+ { "a32", 790, NULL },
+ { "a33", 793, NULL },
+ { "a34", 794, NULL },
+ { "a35", 816, NULL },
+ { "a36", 823, NULL },
+ { "a37", 789, NULL },
+ { "a38", 841, NULL },
+ { "a39", 823, NULL },
+ { "a40", 833, NULL },
+ { "a41", 816, NULL },
+ { "a42", 831, NULL },
+ { "a43", 923, NULL },
+ { "a44", 744, NULL },
+ { "a45", 723, NULL },
+ { "a46", 749, NULL },
+ { "a47", 790, NULL },
+ { "a48", 792, NULL },
+ { "a49", 695, NULL },
+ { "a100", 668, NULL },
+ { "a101", 732, NULL },
+ { "a102", 544, NULL },
+ { "a103", 544, NULL },
+ { "a104", 910, NULL },
+ { "a105", 911, NULL },
+ { "a106", 667, NULL },
+ { "a107", 760, NULL },
+ { "a108", 760, NULL },
+ { "a109", 626, NULL },
+ { "a50", 776, NULL },
+ { "a51", 768, NULL },
+ { "a52", 792, NULL },
+ { "a53", 759, NULL },
+ { "a54", 707, NULL },
+ { "a55", 708, NULL },
+ { "a56", 682, NULL },
+ { "a57", 701, NULL },
+ { "a58", 826, NULL },
+ { "a59", 815, NULL },
+ { "a110", 694, NULL },
+ { "a111", 595, NULL },
+ { "a112", 776, NULL },
+ { "a117", 690, NULL },
+ { "a118", 791, NULL },
+ { "a119", 790, NULL },
+ { "a60", 789, NULL },
+ { "a61", 789, NULL },
+ { "a62", 707, NULL },
+ { "a63", 687, NULL },
+ { "a64", 696, NULL },
+ { "a65", 689, NULL },
+ { "a66", 786, NULL },
+ { "a67", 787, NULL },
+ { "a68", 713, NULL },
+ { "a69", 791, NULL },
+ { "a200", 696, NULL },
+ { "a201", 874, NULL },
+ { "a120", 788, NULL },
+ { "a121", 788, NULL },
+ { "a202", 974, NULL },
+ { "a122", 788, NULL },
+ { "a203", 762, NULL },
+ { "a123", 788, NULL },
+ { "a204", 759, NULL },
+ { "a124", 788, NULL },
+ { "a205", 509, NULL },
+ { "a125", 788, NULL },
+ { "a206", 410, NULL },
+ { "a126", 788, NULL },
+ { "a127", 788, NULL },
+ { "a128", 788, NULL },
+ { "a129", 788, NULL },
+ { "a70", 785, NULL },
+ { "a71", 791, NULL },
+ { "a72", 873, NULL },
+ { "a73", 761, NULL },
+ { "a74", 762, NULL },
+ { "a75", 759, NULL },
+ { "a76", 892, NULL },
+ { "a77", 892, NULL },
+ { "a78", 788, NULL },
+ { "a79", 784, NULL },
+ { "a130", 788, NULL },
+ { "a131", 788, NULL },
+ { "a132", 788, NULL },
+ { "a133", 788, NULL },
+ { "a134", 788, NULL },
+ { "a135", 788, NULL },
+ { "a136", 788, NULL },
+ { "a137", 788, NULL },
+ { "a138", 788, NULL },
+ { "a139", 788, NULL }
+};
+
+BuiltinFont builtinFonts[] = {
+ { "Courier", standardEncoding, 629, -157, { -23, -250, 715, 805}, NULL },
+ { "Courier-Bold", standardEncoding, 629, -157, {-113, -250, 749, 801}, NULL },
+ { "Courier-BoldOblique", standardEncoding, 629, -157, { -57, -250, 869, 801}, NULL },
+ { "Courier-Oblique", standardEncoding, 629, -157, { -27, -250, 849, 805}, NULL },
+ { "Helvetica", standardEncoding, 718, -207, {-166, -225, 1000, 931}, NULL },
+ { "Helvetica-Bold", standardEncoding, 718, -207, {-170, -228, 1003, 962}, NULL },
+ { "Helvetica-BoldOblique", standardEncoding, 718, -207, {-174, -228, 1114, 962}, NULL },
+ { "Helvetica-Oblique", standardEncoding, 718, -207, {-170, -225, 1116, 931}, NULL },
+ { "Symbol", symbolEncoding, 1010, -293, {-180, -293, 1090, 1010}, NULL },
+ { "Times-Bold", standardEncoding, 683, -217, {-168, -218, 1000, 935}, NULL },
+ { "Times-BoldItalic", standardEncoding, 683, -217, {-200, -218, 996, 921}, NULL },
+ { "Times-Italic", standardEncoding, 683, -217, {-169, -217, 1010, 883}, NULL },
+ { "Times-Roman", standardEncoding, 683, -217, {-168, -218, 1000, 898}, NULL },
+ { "ZapfDingbats", zapfDingbatsEncoding, 820, -143, { -1, -143, 981, 820}, NULL }
+};
+
+BuiltinFont *builtinFontSubst[] = {
+ &builtinFonts[0],
+ &builtinFonts[3],
+ &builtinFonts[1],
+ &builtinFonts[2],
+ &builtinFonts[4],
+ &builtinFonts[7],
+ &builtinFonts[5],
+ &builtinFonts[6],
+ &builtinFonts[12],
+ &builtinFonts[11],
+ &builtinFonts[9],
+ &builtinFonts[10]
+};
+
+void initBuiltinFontTables() {
+ builtinFonts[0].widths = new BuiltinFontWidths(courierWidthsTab, 315);
+ builtinFonts[1].widths = new BuiltinFontWidths(courierBoldWidthsTab, 315);
+ builtinFonts[2].widths = new BuiltinFontWidths(courierBoldObliqueWidthsTab, 315);
+ builtinFonts[3].widths = new BuiltinFontWidths(courierObliqueWidthsTab, 315);
+ builtinFonts[4].widths = new BuiltinFontWidths(helveticaWidthsTab, 315);
+ builtinFonts[5].widths = new BuiltinFontWidths(helveticaBoldWidthsTab, 316);
+ builtinFonts[6].widths = new BuiltinFontWidths(helveticaBoldObliqueWidthsTab, 315);
+ builtinFonts[7].widths = new BuiltinFontWidths(helveticaObliqueWidthsTab, 315);
+ builtinFonts[8].widths = new BuiltinFontWidths(symbolWidthsTab, 190);
+ builtinFonts[9].widths = new BuiltinFontWidths(timesBoldWidthsTab, 315);
+ builtinFonts[10].widths = new BuiltinFontWidths(timesBoldItalicWidthsTab, 315);
+ builtinFonts[11].widths = new BuiltinFontWidths(timesItalicWidthsTab, 315);
+ builtinFonts[12].widths = new BuiltinFontWidths(timesRomanWidthsTab, 315);
+ builtinFonts[13].widths = new BuiltinFontWidths(zapfDingbatsWidthsTab, 202);
+}
+
+void freeBuiltinFontTables() {
+ int i;
+
+ for (i = 0; i < 14; ++i) {
+ delete builtinFonts[i].widths;
+ }
+}
diff --git a/kpdf/xpdf/xpdf/BuiltinFontTables.h b/kpdf/xpdf/xpdf/BuiltinFontTables.h
new file mode 100644
index 00000000..eb45549e
--- /dev/null
+++ b/kpdf/xpdf/xpdf/BuiltinFontTables.h
@@ -0,0 +1,23 @@
+//========================================================================
+//
+// BuiltinFontTables.h
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef BUILTINFONTTABLES_H
+#define BUILTINFONTTABLES_H
+
+#include "BuiltinFont.h"
+
+#define nBuiltinFonts 14
+#define nBuiltinFontSubsts 12
+
+extern BuiltinFont builtinFonts[nBuiltinFonts];
+extern BuiltinFont *builtinFontSubst[nBuiltinFontSubsts];
+
+extern void initBuiltinFontTables();
+extern void freeBuiltinFontTables();
+
+#endif
diff --git a/kpdf/xpdf/xpdf/CMap.cc b/kpdf/xpdf/xpdf/CMap.cc
new file mode 100644
index 00000000..89905a8c
--- /dev/null
+++ b/kpdf/xpdf/xpdf/CMap.cc
@@ -0,0 +1,408 @@
+//========================================================================
+//
+// CMap.cc
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "gmem.h"
+#include "gfile.h"
+#include "GString.h"
+#include "Error.h"
+#include "GlobalParams.h"
+#include "PSTokenizer.h"
+#include "CMap.h"
+
+//------------------------------------------------------------------------
+
+struct CMapVectorEntry {
+ GBool isVector;
+ union {
+ CMapVectorEntry *vector;
+ CID cid;
+ };
+};
+
+//------------------------------------------------------------------------
+
+static int CMap_getCharFromFile(void *data) {
+ return fgetc((FILE *)data);
+}
+
+//------------------------------------------------------------------------
+
+CMap *CMap::parse(CMapCache *cache, GString *collectionA,
+ GString *cMapNameA) {
+ FILE *f;
+ CMap *cmap;
+ PSTokenizer *pst;
+ char tok1[256], tok2[256], tok3[256];
+ int n1, n2, n3;
+ Guint start, end, code;
+
+ if (!(f = globalParams->findCMapFile(collectionA, cMapNameA))) {
+
+ // Check for an identity CMap.
+ if (!cMapNameA->cmp("Identity") || !cMapNameA->cmp("Identity-H")) {
+ return new CMap(collectionA->copy(), cMapNameA->copy(), 0);
+ }
+ if (!cMapNameA->cmp("Identity-V")) {
+ return new CMap(collectionA->copy(), cMapNameA->copy(), 1);
+ }
+
+ error(-1, "Couldn't find '%s' CMap file for '%s' collection",
+ cMapNameA->getCString(), collectionA->getCString());
+ return NULL;
+ }
+
+ cmap = new CMap(collectionA->copy(), cMapNameA->copy());
+
+ pst = new PSTokenizer(&CMap_getCharFromFile, f);
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ while (pst->getToken(tok2, sizeof(tok2), &n2)) {
+ if (!strcmp(tok2, "usecmap")) {
+ if (tok1[0] == '/') {
+ cmap->useCMap(cache, tok1 + 1);
+ }
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ } else if (!strcmp(tok1, "/WMode")) {
+ cmap->wMode = atoi(tok2);
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ } else if (!strcmp(tok2, "begincodespacerange")) {
+ while (pst->getToken(tok1, sizeof(tok1), &n1)) {
+ if (!strcmp(tok1, "endcodespacerange")) {
+ break;
+ }
+ if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
+ !strcmp(tok2, "endcodespacerange")) {
+ error(-1, "Illegal entry in codespacerange block in CMap");
+ break;
+ }
+ if (tok1[0] == '<' && tok2[0] == '<' &&
+ n1 == n2 && n1 >= 4 && (n1 & 1) == 0) {
+ tok1[n1 - 1] = tok2[n1 - 1] = '\0';
+ sscanf(tok1 + 1, "%x", &start);
+ sscanf(tok2 + 1, "%x", &end);
+ n1 = (n1 - 2) / 2;
+ cmap->addCodeSpace(cmap->vector, start, end, n1);
+ }
+ }
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ } else if (!strcmp(tok2, "begincidchar")) {
+ while (pst->getToken(tok1, sizeof(tok1), &n1)) {
+ if (!strcmp(tok1, "endcidchar")) {
+ break;
+ }
+ if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
+ !strcmp(tok2, "endcidchar")) {
+ error(-1, "Illegal entry in cidchar block in CMap");
+ break;
+ }
+ if (!(tok1[0] == '<' && tok1[n1 - 1] == '>' &&
+ n1 >= 4 && (n1 & 1) == 0)) {
+ error(-1, "Illegal entry in cidchar block in CMap");
+ continue;
+ }
+ tok1[n1 - 1] = '\0';
+ if (sscanf(tok1 + 1, "%x", &code) != 1) {
+ error(-1, "Illegal entry in cidchar block in CMap");
+ continue;
+ }
+ n1 = (n1 - 2) / 2;
+ cmap->addCIDs(code, code, n1, (CID)atoi(tok2));
+ }
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ } else if (!strcmp(tok2, "begincidrange")) {
+ while (pst->getToken(tok1, sizeof(tok1), &n1)) {
+ if (!strcmp(tok1, "endcidrange")) {
+ break;
+ }
+ if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
+ !strcmp(tok2, "endcidrange") ||
+ !pst->getToken(tok3, sizeof(tok3), &n3) ||
+ !strcmp(tok3, "endcidrange")) {
+ error(-1, "Illegal entry in cidrange block in CMap");
+ break;
+ }
+ if (tok1[0] == '<' && tok2[0] == '<' &&
+ n1 == n2 && n1 >= 4 && (n1 & 1) == 0) {
+ tok1[n1 - 1] = tok2[n1 - 1] = '\0';
+ sscanf(tok1 + 1, "%x", &start);
+ sscanf(tok2 + 1, "%x", &end);
+ n1 = (n1 - 2) / 2;
+ cmap->addCIDs(start, end, n1, (CID)atoi(tok3));
+ }
+ }
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ } else {
+ strcpy(tok1, tok2);
+ }
+ }
+ delete pst;
+
+ fclose(f);
+
+ return cmap;
+}
+
+CMap::CMap(GString *collectionA, GString *cMapNameA) {
+ int i;
+
+ collection = collectionA;
+ cMapName = cMapNameA;
+ wMode = 0;
+ vector = (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry));
+ for (i = 0; i < 256; ++i) {
+ vector[i].isVector = gFalse;
+ vector[i].cid = 0;
+ }
+ refCnt = 1;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+}
+
+CMap::CMap(GString *collectionA, GString *cMapNameA, int wModeA) {
+ collection = collectionA;
+ cMapName = cMapNameA;
+ wMode = wModeA;
+ vector = NULL;
+ refCnt = 1;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+}
+
+void CMap::useCMap(CMapCache *cache, char *useName) {
+ GString *useNameStr;
+ CMap *subCMap;
+
+ useNameStr = new GString(useName);
+ subCMap = cache->getCMap(collection, useNameStr);
+ delete useNameStr;
+ if (!subCMap) {
+ return;
+ }
+ copyVector(vector, subCMap->vector);
+ subCMap->decRefCnt();
+}
+
+void CMap::copyVector(CMapVectorEntry *dest, CMapVectorEntry *src) {
+ int i, j;
+
+ for (i = 0; i < 256; ++i) {
+ if (src[i].isVector) {
+ if (!dest[i].isVector) {
+ dest[i].isVector = gTrue;
+ dest[i].vector =
+ (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry));
+ for (j = 0; j < 256; ++j) {
+ dest[i].vector[j].isVector = gFalse;
+ dest[i].vector[j].cid = 0;
+ }
+ }
+ copyVector(dest[i].vector, src[i].vector);
+ } else {
+ if (dest[i].isVector) {
+ error(-1, "Collision in usecmap");
+ } else {
+ dest[i].cid = src[i].cid;
+ }
+ }
+ }
+}
+
+void CMap::addCodeSpace(CMapVectorEntry *vec, Guint start, Guint end,
+ Guint nBytes) {
+ Guint start2, end2;
+ int startByte, endByte, i, j;
+
+ if (nBytes > 1) {
+ startByte = (start >> (8 * (nBytes - 1))) & 0xff;
+ endByte = (end >> (8 * (nBytes - 1))) & 0xff;
+ start2 = start & ((1 << (8 * (nBytes - 1))) - 1);
+ end2 = end & ((1 << (8 * (nBytes - 1))) - 1);
+ for (i = startByte; i <= endByte; ++i) {
+ if (!vec[i].isVector) {
+ vec[i].isVector = gTrue;
+ vec[i].vector =
+ (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry));
+ for (j = 0; j < 256; ++j) {
+ vec[i].vector[j].isVector = gFalse;
+ vec[i].vector[j].cid = 0;
+ }
+ }
+ addCodeSpace(vec[i].vector, start2, end2, nBytes - 1);
+ }
+ }
+}
+
+void CMap::addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID) {
+ CMapVectorEntry *vec;
+ CID cid;
+ int byte;
+ Guint i;
+
+ vec = vector;
+ for (i = nBytes - 1; i >= 1; --i) {
+ byte = (start >> (8 * i)) & 0xff;
+ if (!vec[byte].isVector) {
+ error(-1, "Invalid CID (%0*x - %0*x) in CMap",
+ 2*nBytes, start, 2*nBytes, end);
+ return;
+ }
+ vec = vec[byte].vector;
+ }
+ cid = firstCID;
+ for (byte = (int)(start & 0xff); byte <= (int)(end & 0xff); ++byte) {
+ if (vec[byte].isVector) {
+ error(-1, "Invalid CID (%0*x - %0*x) in CMap",
+ 2*nBytes, start, 2*nBytes, end);
+ } else {
+ vec[byte].cid = cid;
+ }
+ ++cid;
+ }
+}
+
+CMap::~CMap() {
+ delete collection;
+ delete cMapName;
+ if (vector) {
+ freeCMapVector(vector);
+ }
+#if MULTITHREADED
+ gDestroyMutex(&mutex);
+#endif
+}
+
+void CMap::freeCMapVector(CMapVectorEntry *vec) {
+ int i;
+
+ for (i = 0; i < 256; ++i) {
+ if (vec[i].isVector) {
+ freeCMapVector(vec[i].vector);
+ }
+ }
+ gfree(vec);
+}
+
+void CMap::incRefCnt() {
+#if MULTITHREADED
+ gLockMutex(&mutex);
+#endif
+ ++refCnt;
+#if MULTITHREADED
+ gUnlockMutex(&mutex);
+#endif
+}
+
+void CMap::decRefCnt() {
+ GBool done;
+
+#if MULTITHREADED
+ gLockMutex(&mutex);
+#endif
+ done = --refCnt == 0;
+#if MULTITHREADED
+ gUnlockMutex(&mutex);
+#endif
+ if (done) {
+ delete this;
+ }
+}
+
+GBool CMap::match(GString *collectionA, GString *cMapNameA) {
+ return !collection->cmp(collectionA) && !cMapName->cmp(cMapNameA);
+}
+
+CID CMap::getCID(char *s, int len, int *nUsed) {
+ CMapVectorEntry *vec;
+ int n, i;
+
+ if (!(vec = vector)) {
+ // identity CMap
+ *nUsed = 2;
+ if (len < 2) {
+ return 0;
+ }
+ return ((s[0] & 0xff) << 8) + (s[1] & 0xff);
+ }
+ n = 0;
+ while (1) {
+ if (n >= len) {
+ *nUsed = n;
+ return 0;
+ }
+ i = s[n++] & 0xff;
+ if (!vec[i].isVector) {
+ *nUsed = n;
+ return vec[i].cid;
+ }
+ vec = vec[i].vector;
+ }
+}
+
+//------------------------------------------------------------------------
+
+CMapCache::CMapCache() {
+ int i;
+
+ for (i = 0; i < cMapCacheSize; ++i) {
+ cache[i] = NULL;
+ }
+}
+
+CMapCache::~CMapCache() {
+ int i;
+
+ for (i = 0; i < cMapCacheSize; ++i) {
+ if (cache[i]) {
+ cache[i]->decRefCnt();
+ }
+ }
+}
+
+CMap *CMapCache::getCMap(GString *collection, GString *cMapName) {
+ CMap *cmap;
+ int i, j;
+
+ if (cache[0] && cache[0]->match(collection, cMapName)) {
+ cache[0]->incRefCnt();
+ return cache[0];
+ }
+ for (i = 1; i < cMapCacheSize; ++i) {
+ if (cache[i] && cache[i]->match(collection, cMapName)) {
+ cmap = cache[i];
+ for (j = i; j >= 1; --j) {
+ cache[j] = cache[j - 1];
+ }
+ cache[0] = cmap;
+ cmap->incRefCnt();
+ return cmap;
+ }
+ }
+ if ((cmap = CMap::parse(this, collection, cMapName))) {
+ if (cache[cMapCacheSize - 1]) {
+ cache[cMapCacheSize - 1]->decRefCnt();
+ }
+ for (j = cMapCacheSize - 1; j >= 1; --j) {
+ cache[j] = cache[j - 1];
+ }
+ cache[0] = cmap;
+ cmap->incRefCnt();
+ return cmap;
+ }
+ return NULL;
+}
diff --git a/kpdf/xpdf/xpdf/CMap.h b/kpdf/xpdf/xpdf/CMap.h
new file mode 100644
index 00000000..c321a57a
--- /dev/null
+++ b/kpdf/xpdf/xpdf/CMap.h
@@ -0,0 +1,102 @@
+//========================================================================
+//
+// CMap.h
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef CMAP_H
+#define CMAP_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "CharTypes.h"
+
+#if MULTITHREADED
+#include "GMutex.h"
+#endif
+
+class GString;
+struct CMapVectorEntry;
+class CMapCache;
+
+//------------------------------------------------------------------------
+
+class CMap {
+public:
+
+ // Create the CMap specified by <collection> and <cMapName>. Sets
+ // the initial reference count to 1. Returns NULL on failure.
+ static CMap *parse(CMapCache *cache, GString *collectionA,
+ GString *cMapNameA);
+
+ ~CMap();
+
+ void incRefCnt();
+ void decRefCnt();
+
+ // Return collection name (<registry>-<ordering>).
+ GString *getCollection() { return collection; }
+
+ // Return true if this CMap matches the specified <collectionA>, and
+ // <cMapNameA>.
+ GBool match(GString *collectionA, GString *cMapNameA);
+
+ // Return the CID corresponding to the character code starting at
+ // <s>, which contains <len> bytes. Sets *<nUsed> to the number of
+ // bytes used by the char code.
+ CID getCID(char *s, int len, int *nUsed);
+
+ // Return the writing mode (0=horizontal, 1=vertical).
+ int getWMode() { return wMode; }
+
+private:
+
+ CMap(GString *collectionA, GString *cMapNameA);
+ CMap(GString *collectionA, GString *cMapNameA, int wModeA);
+ void useCMap(CMapCache *cache, char *useName);
+ void copyVector(CMapVectorEntry *dest, CMapVectorEntry *src);
+ void addCodeSpace(CMapVectorEntry *vec, Guint start, Guint end,
+ Guint nBytes);
+ void addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID);
+ void freeCMapVector(CMapVectorEntry *vec);
+
+ GString *collection;
+ GString *cMapName;
+ int wMode; // writing mode (0=horizontal, 1=vertical)
+ CMapVectorEntry *vector; // vector for first byte (NULL for
+ // identity CMap)
+ int refCnt;
+#if MULTITHREADED
+ GMutex mutex;
+#endif
+};
+
+//------------------------------------------------------------------------
+
+#define cMapCacheSize 4
+
+class CMapCache {
+public:
+
+ CMapCache();
+ ~CMapCache();
+
+ // Get the <cMapName> CMap for the specified character collection.
+ // Increments its reference count; there will be one reference for
+ // the cache plus one for the caller of this function. Returns NULL
+ // on failure.
+ CMap *getCMap(GString *collection, GString *cMapName);
+
+private:
+
+ CMap *cache[cMapCacheSize];
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/Catalog.cc b/kpdf/xpdf/xpdf/Catalog.cc
new file mode 100644
index 00000000..198703a4
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Catalog.cc
@@ -0,0 +1,443 @@
+//========================================================================
+//
+// Catalog.cc
+//
+// Copyright 1996-2007 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stddef.h>
+#include <stdlib.h>
+#include "gmem.h"
+#include "Object.h"
+#include "XRef.h"
+#include "Array.h"
+#include "Dict.h"
+#include "Page.h"
+#include "Error.h"
+#include "Link.h"
+#include "Catalog.h"
+
+//------------------------------------------------------------------------
+// Catalog
+//------------------------------------------------------------------------
+
+Catalog::Catalog(XRef *xrefA) {
+ Object catDict, pagesDict, pagesDictRef;
+ Object obj, obj2;
+ char *alreadyRead;
+ int numPages0;
+ int i;
+
+ ok = gTrue;
+ xref = xrefA;
+ pages = NULL;
+ pageRefs = NULL;
+ numPages = pagesSize = 0;
+ baseURI = NULL;
+
+ xref->getCatalog(&catDict);
+ if (!catDict.isDict()) {
+ error(-1, "Catalog object is wrong type (%s)", catDict.getTypeName());
+ goto err1;
+ }
+
+ // read page tree
+ catDict.dictLookup("Pages", &pagesDict);
+ // This should really be isDict("Pages"), but I've seen at least one
+ // PDF file where the /Type entry is missing.
+ if (!pagesDict.isDict()) {
+ error(-1, "Top-level pages object is wrong type (%s)",
+ pagesDict.getTypeName());
+ goto err2;
+ }
+ pagesDict.dictLookup("Count", &obj);
+ // some PDF files actually use real numbers here ("/Count 9.0")
+ if (!obj.isNum()) {
+ error(-1, "Page count in top-level pages object is wrong type (%s)",
+ obj.getTypeName());
+ goto err3;
+ }
+ pagesSize = numPages0 = (int)obj.getNum();
+ obj.free();
+ pages = (Page **)gmallocn(pagesSize, sizeof(Page *));
+ pageRefs = (Ref *)gmallocn(pagesSize, sizeof(Ref));
+ for (i = 0; i < pagesSize; ++i) {
+ pages[i] = NULL;
+ pageRefs[i].num = -1;
+ pageRefs[i].gen = -1;
+ }
+ alreadyRead = (char *)gmalloc(xref->getNumObjects());
+ memset(alreadyRead, 0, xref->getNumObjects());
+ if (catDict.dictLookupNF("Pages", &pagesDictRef)->isRef() &&
+ pagesDictRef.getRefNum() >= 0 &&
+ pagesDictRef.getRefNum() < xref->getNumObjects()) {
+ alreadyRead[pagesDictRef.getRefNum()] = 1;
+ }
+ pagesDictRef.free();
+ numPages = readPageTree(pagesDict.getDict(), NULL, 0, alreadyRead);
+ gfree(alreadyRead);
+ if (numPages != numPages0) {
+ error(-1, "Page count in top-level pages object is incorrect");
+ }
+ pagesDict.free();
+
+ // read named destination dictionary
+ catDict.dictLookup("Dests", &dests);
+
+ // read root of named destination tree
+ if (catDict.dictLookup("Names", &obj)->isDict()) {
+ obj.dictLookup("Dests", &obj2);
+ destNameTree.init(xref, &obj2);
+ obj2.free();
+ }
+ obj.free();
+
+ // read base URI
+ if (catDict.dictLookup("URI", &obj)->isDict()) {
+ if (obj.dictLookup("Base", &obj2)->isString()) {
+ baseURI = obj2.getString()->copy();
+ }
+ obj2.free();
+ }
+ obj.free();
+
+ // read page mode
+ if (catDict.dictLookup("PageMode", &obj)->isName()) {
+ if (strcmp(obj.getName(), "UseNone") == 0)
+ pageMode = UseNone;
+ else if (strcmp(obj.getName(), "UseOutlines") == 0)
+ pageMode = UseOutlines;
+ else if (strcmp(obj.getName(), "UseThumbs") == 0)
+ pageMode = UseThumbs;
+ else if (strcmp(obj.getName(), "FullScreen") == 0)
+ pageMode = FullScreen;
+ else if (strcmp(obj.getName(), "UseOC") == 0)
+ pageMode = UseOC;
+ else
+ pageMode = UseNone;
+ } else {
+ pageMode = UseNone;
+ }
+ obj.free();
+
+ // get the metadata stream
+ catDict.dictLookup("Metadata", &metadata);
+
+ // get the structure tree root
+ catDict.dictLookup("StructTreeRoot", &structTreeRoot);
+
+ // get the outline dictionary
+ catDict.dictLookup("Outlines", &outline);
+
+ // get the AcroForm dictionary
+ catDict.dictLookup("AcroForm", &acroForm);
+
+ catDict.free();
+ return;
+
+ err3:
+ obj.free();
+ err2:
+ pagesDict.free();
+ err1:
+ catDict.free();
+ dests.initNull();
+ ok = gFalse;
+}
+
+Catalog::~Catalog() {
+ int i;
+
+ if (pages) {
+ for (i = 0; i < pagesSize; ++i) {
+ if (pages[i]) {
+ delete pages[i];
+ }
+ }
+ gfree(pages);
+ gfree(pageRefs);
+ }
+ dests.free();
+ destNameTree.free();
+ if (baseURI) {
+ delete baseURI;
+ }
+ metadata.free();
+ structTreeRoot.free();
+ outline.free();
+ acroForm.free();
+}
+
+GString *Catalog::readMetadata() {
+ GString *s;
+ Dict *dict;
+ Object obj;
+ int c;
+
+ if (!metadata.isStream()) {
+ return NULL;
+ }
+ dict = metadata.streamGetDict();
+ if (!dict->lookup("Subtype", &obj)->isName("XML")) {
+ error(-1, "Unknown Metadata type: '%s'",
+ obj.isName() ? obj.getName() : "???");
+ }
+ obj.free();
+ s = new GString();
+ metadata.streamReset();
+ while ((c = metadata.streamGetChar()) != EOF) {
+ s->append(c);
+ }
+ metadata.streamClose();
+ return s;
+}
+
+int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start,
+ char *alreadyRead) {
+ Object kids;
+ Object kid;
+ Object kidRef;
+ PageAttrs *attrs1, *attrs2;
+ Page *page;
+ int i, j;
+
+ attrs1 = new PageAttrs(attrs, pagesDict);
+ pagesDict->lookup("Kids", &kids);
+ if (!kids.isArray()) {
+ error(-1, "Kids object (page %d) is wrong type (%s)",
+ start+1, kids.getTypeName());
+ goto err1;
+ }
+ for (i = 0; i < kids.arrayGetLength(); ++i) {
+ kids.arrayGetNF(i, &kidRef);
+ if (kidRef.isRef() &&
+ kidRef.getRefNum() >= 0 &&
+ kidRef.getRefNum() < xref->getNumObjects()) {
+ if (alreadyRead[kidRef.getRefNum()]) {
+ error(-1, "Loop in Pages tree");
+ kidRef.free();
+ continue;
+ }
+ alreadyRead[kidRef.getRefNum()] = 1;
+ }
+ kids.arrayGet(i, &kid);
+ if (kid.isDict("Page")) {
+ attrs2 = new PageAttrs(attrs1, kid.getDict());
+ page = new Page(xref, start+1, kid.getDict(), attrs2);
+ if (!page->isOk()) {
+ ++start;
+ goto err3;
+ }
+ if (start >= pagesSize) {
+ pagesSize += 32;
+ pages = (Page **)greallocn(pages, pagesSize, sizeof(Page *));
+ pageRefs = (Ref *)greallocn(pageRefs, pagesSize, sizeof(Ref));
+ for (j = pagesSize - 32; j < pagesSize; ++j) {
+ pages[j] = NULL;
+ pageRefs[j].num = -1;
+ pageRefs[j].gen = -1;
+ }
+ }
+ pages[start] = page;
+ if (kidRef.isRef()) {
+ pageRefs[start].num = kidRef.getRefNum();
+ pageRefs[start].gen = kidRef.getRefGen();
+ }
+ ++start;
+ // This should really be isDict("Pages"), but I've seen at least one
+ // PDF file where the /Type entry is missing.
+ } else if (kid.isDict()) {
+ if ((start = readPageTree(kid.getDict(), attrs1, start, alreadyRead))
+ < 0)
+ goto err2;
+ } else {
+ error(-1, "Kid object (page %d) is wrong type (%s)",
+ start+1, kid.getTypeName());
+ }
+ kid.free();
+ kidRef.free();
+ }
+ delete attrs1;
+ kids.free();
+ return start;
+
+ err3:
+ delete page;
+ err2:
+ kid.free();
+ err1:
+ kids.free();
+ delete attrs1;
+ ok = gFalse;
+ return -1;
+}
+
+int Catalog::findPage(int num, int gen) {
+ int i;
+
+ for (i = 0; i < numPages; ++i) {
+ if (pageRefs[i].num == num && pageRefs[i].gen == gen)
+ return i + 1;
+ }
+ return 0;
+}
+
+LinkDest *Catalog::findDest(GString *name) {
+ LinkDest *dest;
+ Object obj1, obj2;
+ GBool found;
+
+ // try named destination dictionary then name tree
+ found = gFalse;
+ if (dests.isDict()) {
+ if (!dests.dictLookup(name->getCString(), &obj1)->isNull())
+ found = gTrue;
+ else
+ obj1.free();
+ }
+ if (!found) {
+ if (destNameTree.lookup(name, &obj1))
+ found = gTrue;
+ else
+ obj1.free();
+ }
+ if (!found)
+ return NULL;
+
+ // construct LinkDest
+ dest = NULL;
+ if (obj1.isArray()) {
+ dest = new LinkDest(obj1.getArray());
+ } else if (obj1.isDict()) {
+ if (obj1.dictLookup("D", &obj2)->isArray())
+ dest = new LinkDest(obj2.getArray());
+ else
+ error(-1, "Bad named destination value");
+ obj2.free();
+ } else {
+ error(-1, "Bad named destination value");
+ }
+ obj1.free();
+ if (dest && !dest->isOk()) {
+ delete dest;
+ dest = NULL;
+ }
+
+ return dest;
+}
+
+NameTree::NameTree()
+{
+ size = 0;
+ length = 0;
+ entries = NULL;
+}
+
+NameTree::Entry::Entry(Array *array, int index) {
+ if (!array->getString(index, &name) || !array->getNF(index + 1, &value))
+ error(-1, "Invalid page tree");
+}
+
+NameTree::Entry::~Entry() {
+ value.free();
+}
+
+void NameTree::addEntry(Entry *entry)
+{
+ if (length == size) {
+ if (length == 0) {
+ size = 8;
+ } else {
+ size *= 2;
+ }
+ entries = (Entry **) grealloc (entries, sizeof (Entry *) * size);
+ }
+
+ entries[length] = entry;
+ ++length;
+}
+
+void NameTree::init(XRef *xrefA, Object *tree) {
+ xref = xrefA;
+ parse(tree);
+}
+
+void NameTree::parse(Object *tree) {
+ Object names;
+ Object kids, kid;
+ int i;
+
+ if (!tree->isDict())
+ return;
+
+ // leaf node
+ if (tree->dictLookup("Names", &names)->isArray()) {
+ for (i = 0; i < names.arrayGetLength(); i += 2) {
+ NameTree::Entry *entry;
+
+ entry = new Entry(names.getArray(), i);
+ addEntry(entry);
+ }
+ }
+ names.free();
+
+ // root or intermediate node
+ if (tree->dictLookup("Kids", &kids)->isArray()) {
+ for (i = 0; i < kids.arrayGetLength(); ++i) {
+ if (kids.arrayGet(i, &kid)->isDict())
+ parse(&kid);
+ kid.free();
+ }
+ }
+ kids.free();
+}
+
+int NameTree::Entry::cmp(const void *voidKey, const void *voidEntry)
+{
+ GString *key = (GString *) voidKey;
+ Entry *entry = *(NameTree::Entry **) voidEntry;
+
+ return key->cmp(&entry->name);
+}
+
+GBool NameTree::lookup(GString *name, Object *obj)
+{
+ Entry *entry;
+
+ Entry **e = (Entry **) bsearch(name, entries,
+ length, sizeof(Entry *), Entry::cmp);
+ if (e) entry = *e;
+ else
+ {
+ error(-1, "failed to look up %s\n", name->getCString());
+ obj->initNull();
+ return gFalse;
+ }
+ if (entry != NULL) {
+ entry->value.fetch(xref, obj);
+ return gTrue;
+ } else {
+ error(-1, "failed to look up %s\n", name->getCString());
+
+ obj->initNull();
+
+ return gFalse;
+ }
+}
+
+void NameTree::free()
+{
+ int i;
+
+ for (i = 0; i < length; i++)
+ delete entries[i];
+
+ gfree(entries);
+}
diff --git a/kpdf/xpdf/xpdf/Catalog.h b/kpdf/xpdf/xpdf/Catalog.h
new file mode 100644
index 00000000..e89ec04d
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Catalog.h
@@ -0,0 +1,137 @@
+//========================================================================
+//
+// Catalog.h
+//
+// Copyright 1996-2007 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef CATALOG_H
+#define CATALOG_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+class XRef;
+class Object;
+class Page;
+class PageAttrs;
+struct Ref;
+class LinkDest;
+
+//------------------------------------------------------------------------
+// NameTree
+//------------------------------------------------------------------------
+
+class NameTree {
+public:
+ NameTree();
+ void init(XRef *xref, Object *tree);
+ void parse(Object *tree);
+ GBool lookup(GString *name, Object *obj);
+ void free();
+
+private:
+ struct Entry {
+ Entry(Array *array, int index);
+ ~Entry();
+ GString name;
+ Object value;
+ void free();
+ static int cmp(const void *key, const void *entry);
+ };
+
+ void addEntry(Entry *entry);
+
+ XRef *xref;
+ Object *root;
+ Entry **entries;
+ int size, length;
+};
+
+//------------------------------------------------------------------------
+// Catalog
+//------------------------------------------------------------------------
+
+class Catalog {
+public:
+
+ enum PageMode {
+ UseNone,
+ UseOutlines,
+ UseThumbs,
+ FullScreen,
+ UseOC
+ };
+
+ // Constructor.
+ Catalog(XRef *xrefA);
+
+ // Destructor.
+ ~Catalog();
+
+ // Is catalog valid?
+ GBool isOk() { return ok; }
+
+ // Get number of pages.
+ int getNumPages() { return numPages; }
+
+ // Get a page.
+ Page *getPage(int i) { return pages[i-1]; }
+
+ // Get the reference for a page object.
+ Ref *getPageRef(int i) { return &pageRefs[i-1]; }
+
+ // Return base URI, or NULL if none.
+ GString *getBaseURI() { return baseURI; }
+
+ // Returns the page mode.
+ PageMode getPageMode() { return pageMode; }
+
+ // Return the contents of the metadata stream, or NULL if there is
+ // no metadata.
+ GString *readMetadata();
+
+ // Return the structure tree root object.
+ Object *getStructTreeRoot() { return &structTreeRoot; }
+
+ // Find a page, given its object ID. Returns page number, or 0 if
+ // not found.
+ int findPage(int num, int gen);
+
+ // Find a named destination. Returns the link destination, or
+ // NULL if <name> is not a destination.
+ LinkDest *findDest(GString *name);
+
+ Object *getDests() { return &dests; }
+
+ Object *getOutline() { return &outline; }
+
+ Object *getAcroForm() { return &acroForm; }
+
+private:
+
+ XRef *xref; // the xref table for this PDF file
+ Page **pages; // array of pages
+ Ref *pageRefs; // object ID for each page
+ int numPages; // number of pages
+ int pagesSize; // size of pages array
+ Object dests; // named destination dictionary
+ NameTree destNameTree; // name tree
+ GString *baseURI; // base URI for URI-type links
+ PageMode pageMode; // page mode
+ Object metadata; // metadata stream
+ Object structTreeRoot; // structure tree root dictionary
+ Object outline; // outline dictionary
+ Object acroForm; // AcroForm dictionary
+ GBool ok; // true if catalog is valid
+
+ int readPageTree(Dict *pages, PageAttrs *attrs, int start,
+ char *alreadyRead);
+ Object *findDestInTree(Object *tree, GString *name, Object *obj);
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/CharCodeToUnicode.cc b/kpdf/xpdf/xpdf/CharCodeToUnicode.cc
new file mode 100644
index 00000000..3702a16d
--- /dev/null
+++ b/kpdf/xpdf/xpdf/CharCodeToUnicode.cc
@@ -0,0 +1,540 @@
+//========================================================================
+//
+// CharCodeToUnicode.cc
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include "gmem.h"
+#include "gfile.h"
+#include "GString.h"
+#include "Error.h"
+#include "GlobalParams.h"
+#include "PSTokenizer.h"
+#include "CharCodeToUnicode.h"
+
+//------------------------------------------------------------------------
+
+#define maxUnicodeString 8
+
+struct CharCodeToUnicodeString {
+ CharCode c;
+ Unicode u[maxUnicodeString];
+ int len;
+};
+
+//------------------------------------------------------------------------
+
+static int getCharFromString(void *data) {
+ char *p;
+ int c;
+
+ p = *(char **)data;
+ if (*p) {
+ c = *p++;
+ *(char **)data = p;
+ } else {
+ c = EOF;
+ }
+ return c;
+}
+
+static int getCharFromFile(void *data) {
+ return fgetc((FILE *)data);
+}
+
+//------------------------------------------------------------------------
+
+CharCodeToUnicode *CharCodeToUnicode::parseCIDToUnicode(GString *fileName,
+ GString *collection) {
+ FILE *f;
+ Unicode *mapA;
+ CharCode size, mapLenA;
+ char buf[64];
+ Unicode u;
+ CharCodeToUnicode *ctu;
+
+ if (!(f = fopen(fileName->getCString(), "r"))) {
+ error(-1, "Couldn't open cidToUnicode file '%s'",
+ fileName->getCString());
+ return NULL;
+ }
+
+ size = 32768;
+ mapA = (Unicode *)gmallocn(size, sizeof(Unicode));
+ mapLenA = 0;
+
+ while (getLine(buf, sizeof(buf), f)) {
+ if (mapLenA == size) {
+ size *= 2;
+ mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode));
+ }
+ if (sscanf(buf, "%x", &u) == 1) {
+ mapA[mapLenA] = u;
+ } else {
+ error(-1, "Bad line (%d) in cidToUnicode file '%s'",
+ (int)(mapLenA + 1), fileName->getCString());
+ mapA[mapLenA] = 0;
+ }
+ ++mapLenA;
+ }
+ fclose(f);
+
+ ctu = new CharCodeToUnicode(collection->copy(), mapA, mapLenA, gTrue,
+ NULL, 0, 0);
+ gfree(mapA);
+ return ctu;
+}
+
+CharCodeToUnicode *CharCodeToUnicode::parseUnicodeToUnicode(
+ GString *fileName) {
+ FILE *f;
+ Unicode *mapA;
+ CharCodeToUnicodeString *sMapA;
+ CharCode size, oldSize, len, sMapSizeA, sMapLenA;
+ char buf[256];
+ char *tok;
+ Unicode u0;
+ Unicode uBuf[maxUnicodeString];
+ CharCodeToUnicode *ctu;
+ int line, n, i;
+
+ if (!(f = fopen(fileName->getCString(), "r"))) {
+ error(-1, "Couldn't open unicodeToUnicode file '%s'",
+ fileName->getCString());
+ return NULL;
+ }
+
+ size = 4096;
+ mapA = (Unicode *)gmallocn(size, sizeof(Unicode));
+ memset(mapA, 0, size * sizeof(Unicode));
+ len = 0;
+ sMapA = NULL;
+ sMapSizeA = sMapLenA = 0;
+
+ line = 0;
+ while (getLine(buf, sizeof(buf), f)) {
+ ++line;
+ if (!(tok = strtok(buf, " \t\r\n")) ||
+ sscanf(tok, "%x", &u0) != 1) {
+ error(-1, "Bad line (%d) in unicodeToUnicode file '%s'",
+ line, fileName->getCString());
+ continue;
+ }
+ n = 0;
+ while (n < maxUnicodeString) {
+ if (!(tok = strtok(NULL, " \t\r\n"))) {
+ break;
+ }
+ if (sscanf(tok, "%x", &uBuf[n]) != 1) {
+ error(-1, "Bad line (%d) in unicodeToUnicode file '%s'",
+ line, fileName->getCString());
+ break;
+ }
+ ++n;
+ }
+ if (n < 1) {
+ error(-1, "Bad line (%d) in unicodeToUnicode file '%s'",
+ line, fileName->getCString());
+ continue;
+ }
+ if (u0 >= size) {
+ oldSize = size;
+ while (u0 >= size) {
+ size *= 2;
+ }
+ mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode));
+ memset(mapA + oldSize, 0, (size - oldSize) * sizeof(Unicode));
+ }
+ if (n == 1) {
+ mapA[u0] = uBuf[0];
+ } else {
+ mapA[u0] = 0;
+ if (sMapLenA == sMapSizeA) {
+ sMapSizeA += 16;
+ sMapA = (CharCodeToUnicodeString *)
+ greallocn(sMapA, sMapSizeA, sizeof(CharCodeToUnicodeString));
+ }
+ sMapA[sMapLenA].c = u0;
+ for (i = 0; i < n; ++i) {
+ sMapA[sMapLenA].u[i] = uBuf[i];
+ }
+ sMapA[sMapLenA].len = n;
+ ++sMapLenA;
+ }
+ if (u0 >= len) {
+ len = u0 + 1;
+ }
+ }
+ fclose(f);
+
+ ctu = new CharCodeToUnicode(fileName->copy(), mapA, len, gTrue,
+ sMapA, sMapLenA, sMapSizeA);
+ gfree(mapA);
+ return ctu;
+}
+
+CharCodeToUnicode *CharCodeToUnicode::make8BitToUnicode(Unicode *toUnicode) {
+ return new CharCodeToUnicode(NULL, toUnicode, 256, gTrue, NULL, 0, 0);
+}
+
+CharCodeToUnicode *CharCodeToUnicode::parseCMap(GString *buf, int nBits) {
+ CharCodeToUnicode *ctu;
+ char *p;
+
+ ctu = new CharCodeToUnicode(NULL);
+ p = buf->getCString();
+ ctu->parseCMap1(&getCharFromString, &p, nBits);
+ return ctu;
+}
+
+void CharCodeToUnicode::mergeCMap(GString *buf, int nBits) {
+ char *p;
+
+ p = buf->getCString();
+ parseCMap1(&getCharFromString, &p, nBits);
+}
+
+void CharCodeToUnicode::parseCMap1(int (*getCharFunc)(void *), void *data,
+ int nBits) {
+ PSTokenizer *pst;
+ char tok1[256], tok2[256], tok3[256];
+ int nDigits, n1, n2, n3;
+ CharCode i;
+ CharCode code1, code2;
+ GString *name;
+ FILE *f;
+
+ nDigits = nBits / 4;
+ pst = new PSTokenizer(getCharFunc, data);
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ while (pst->getToken(tok2, sizeof(tok2), &n2)) {
+ if (!strcmp(tok2, "usecmap")) {
+ if (tok1[0] == '/') {
+ name = new GString(tok1 + 1);
+ if ((f = globalParams->findToUnicodeFile(name))) {
+ parseCMap1(&getCharFromFile, f, nBits);
+ fclose(f);
+ } else {
+ error(-1, "Couldn't find ToUnicode CMap file for '%s'",
+ name->getCString());
+ }
+ delete name;
+ }
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ } else if (!strcmp(tok2, "beginbfchar")) {
+ while (pst->getToken(tok1, sizeof(tok1), &n1)) {
+ if (!strcmp(tok1, "endbfchar")) {
+ break;
+ }
+ if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
+ !strcmp(tok2, "endbfchar")) {
+ error(-1, "Illegal entry in bfchar block in ToUnicode CMap");
+ break;
+ }
+ if (!(n1 == 2 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' &&
+ tok2[0] == '<' && tok2[n2 - 1] == '>')) {
+ error(-1, "Illegal entry in bfchar block in ToUnicode CMap");
+ continue;
+ }
+ tok1[n1 - 1] = tok2[n2 - 1] = '\0';
+ if (sscanf(tok1 + 1, "%x", &code1) != 1) {
+ error(-1, "Illegal entry in bfchar block in ToUnicode CMap");
+ continue;
+ }
+ addMapping(code1, tok2 + 1, n2 - 2, 0);
+ }
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ } else if (!strcmp(tok2, "beginbfrange")) {
+ while (pst->getToken(tok1, sizeof(tok1), &n1)) {
+ if (!strcmp(tok1, "endbfrange")) {
+ break;
+ }
+ if (!pst->getToken(tok2, sizeof(tok2), &n2) ||
+ !strcmp(tok2, "endbfrange") ||
+ !pst->getToken(tok3, sizeof(tok3), &n3) ||
+ !strcmp(tok3, "endbfrange")) {
+ error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
+ break;
+ }
+ if (!(n1 == 2 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' &&
+ n2 == 2 + nDigits && tok2[0] == '<' && tok2[n2 - 1] == '>')) {
+ error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
+ continue;
+ }
+ tok1[n1 - 1] = tok2[n2 - 1] = '\0';
+ if (sscanf(tok1 + 1, "%x", &code1) != 1 ||
+ sscanf(tok2 + 1, "%x", &code2) != 1) {
+ error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
+ continue;
+ }
+ if (!strcmp(tok3, "[")) {
+ i = 0;
+ while (pst->getToken(tok1, sizeof(tok1), &n1) &&
+ code1 + i <= code2) {
+ if (!strcmp(tok1, "]")) {
+ break;
+ }
+ if (tok1[0] == '<' && tok1[n1 - 1] == '>') {
+ tok1[n1 - 1] = '\0';
+ addMapping(code1 + i, tok1 + 1, n1 - 2, 0);
+ } else {
+ error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
+ }
+ ++i;
+ }
+ } else if (tok3[0] == '<' && tok3[n3 - 1] == '>') {
+ tok3[n3 - 1] = '\0';
+ for (i = 0; code1 <= code2; ++code1, ++i) {
+ addMapping(code1, tok3 + 1, n3 - 2, i);
+ }
+
+ } else {
+ error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
+ }
+ }
+ pst->getToken(tok1, sizeof(tok1), &n1);
+ } else {
+ strcpy(tok1, tok2);
+ }
+ }
+ delete pst;
+}
+
+void CharCodeToUnicode::addMapping(CharCode code, char *uStr, int n,
+ int offset) {
+ CharCode oldLen, i;
+ Unicode u;
+ char uHex[5];
+ int j;
+
+ if (code >= mapLen) {
+ oldLen = mapLen;
+ mapLen = (code + 256) & ~255;
+ map = (Unicode *)greallocn(map, mapLen, sizeof(Unicode));
+ for (i = oldLen; i < mapLen; ++i) {
+ map[i] = 0;
+ }
+ }
+ if (n <= 4) {
+ if (sscanf(uStr, "%x", &u) != 1) {
+ error(-1, "Illegal entry in ToUnicode CMap");
+ return;
+ }
+ map[code] = u + offset;
+ } else {
+ if (sMapLen >= sMapSize) {
+ sMapSize = sMapSize + 16;
+ sMap = (CharCodeToUnicodeString *)
+ greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString));
+ }
+ map[code] = 0;
+ sMap[sMapLen].c = code;
+ sMap[sMapLen].len = n / 4;
+ for (j = 0; j < sMap[sMapLen].len && j < maxUnicodeString; ++j) {
+ strncpy(uHex, uStr + j*4, 4);
+ uHex[4] = '\0';
+ if (sscanf(uHex, "%x", &sMap[sMapLen].u[j]) != 1) {
+ error(-1, "Illegal entry in ToUnicode CMap");
+ }
+ }
+ sMap[sMapLen].u[sMap[sMapLen].len - 1] += offset;
+ ++sMapLen;
+ }
+}
+
+CharCodeToUnicode::CharCodeToUnicode(GString *tagA) {
+ CharCode i;
+
+ tag = tagA;
+ mapLen = 256;
+ map = (Unicode *)gmallocn(mapLen, sizeof(Unicode));
+ for (i = 0; i < mapLen; ++i) {
+ map[i] = 0;
+ }
+ sMap = NULL;
+ sMapLen = sMapSize = 0;
+ refCnt = 1;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+}
+
+CharCodeToUnicode::CharCodeToUnicode(GString *tagA, Unicode *mapA,
+ CharCode mapLenA, GBool copyMap,
+ CharCodeToUnicodeString *sMapA,
+ int sMapLenA, int sMapSizeA) {
+ tag = tagA;
+ mapLen = mapLenA;
+ if (copyMap) {
+ map = (Unicode *)gmallocn(mapLen, sizeof(Unicode));
+ memcpy(map, mapA, mapLen * sizeof(Unicode));
+ } else {
+ map = mapA;
+ }
+ sMap = sMapA;
+ sMapLen = sMapLenA;
+ sMapSize = sMapSizeA;
+ refCnt = 1;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+}
+
+CharCodeToUnicode::~CharCodeToUnicode() {
+ if (tag) {
+ delete tag;
+ }
+ gfree(map);
+ if (sMap) {
+ gfree(sMap);
+ }
+#if MULTITHREADED
+ gDestroyMutex(&mutex);
+#endif
+}
+
+void CharCodeToUnicode::incRefCnt() {
+#if MULTITHREADED
+ gLockMutex(&mutex);
+#endif
+ ++refCnt;
+#if MULTITHREADED
+ gUnlockMutex(&mutex);
+#endif
+}
+
+void CharCodeToUnicode::decRefCnt() {
+ GBool done;
+
+#if MULTITHREADED
+ gLockMutex(&mutex);
+#endif
+ done = --refCnt == 0;
+#if MULTITHREADED
+ gUnlockMutex(&mutex);
+#endif
+ if (done) {
+ delete this;
+ }
+}
+
+GBool CharCodeToUnicode::match(GString *tagA) {
+ return tag && !tag->cmp(tagA);
+}
+
+void CharCodeToUnicode::setMapping(CharCode c, Unicode *u, int len) {
+ int i, j;
+
+ if (len == 1) {
+ map[c] = u[0];
+ } else {
+ for (i = 0; i < sMapLen; ++i) {
+ if (sMap[i].c == c) {
+ break;
+ }
+ }
+ if (i == sMapLen) {
+ if (sMapLen == sMapSize) {
+ sMapSize += 8;
+ sMap = (CharCodeToUnicodeString *)
+ greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString));
+ }
+ ++sMapLen;
+ }
+ map[c] = 0;
+ sMap[i].c = c;
+ sMap[i].len = len;
+ for (j = 0; j < len && j < maxUnicodeString; ++j) {
+ sMap[i].u[j] = u[j];
+ }
+ }
+}
+
+int CharCodeToUnicode::mapToUnicode(CharCode c, Unicode *u, int size) {
+ int i, j;
+
+ if (c >= mapLen) {
+ return 0;
+ }
+ if (map[c]) {
+ u[0] = map[c];
+ return 1;
+ }
+ for (i = 0; i < sMapLen; ++i) {
+ if (sMap[i].c == c) {
+ for (j = 0; j < sMap[i].len && j < size; ++j) {
+ u[j] = sMap[i].u[j];
+ }
+ return j;
+ }
+ }
+ return 0;
+}
+
+//------------------------------------------------------------------------
+
+CharCodeToUnicodeCache::CharCodeToUnicodeCache(int sizeA) {
+ int i;
+
+ size = sizeA;
+ cache = (CharCodeToUnicode **)gmallocn(size, sizeof(CharCodeToUnicode *));
+ for (i = 0; i < size; ++i) {
+ cache[i] = NULL;
+ }
+}
+
+CharCodeToUnicodeCache::~CharCodeToUnicodeCache() {
+ int i;
+
+ for (i = 0; i < size; ++i) {
+ if (cache[i]) {
+ cache[i]->decRefCnt();
+ }
+ }
+ gfree(cache);
+}
+
+CharCodeToUnicode *CharCodeToUnicodeCache::getCharCodeToUnicode(GString *tag) {
+ CharCodeToUnicode *ctu;
+ int i, j;
+
+ if (cache[0] && cache[0]->match(tag)) {
+ cache[0]->incRefCnt();
+ return cache[0];
+ }
+ for (i = 1; i < size; ++i) {
+ if (cache[i] && cache[i]->match(tag)) {
+ ctu = cache[i];
+ for (j = i; j >= 1; --j) {
+ cache[j] = cache[j - 1];
+ }
+ cache[0] = ctu;
+ ctu->incRefCnt();
+ return ctu;
+ }
+ }
+ return NULL;
+}
+
+void CharCodeToUnicodeCache::add(CharCodeToUnicode *ctu) {
+ int i;
+
+ if (cache[size - 1]) {
+ cache[size - 1]->decRefCnt();
+ }
+ for (i = size - 1; i >= 1; --i) {
+ cache[i] = cache[i - 1];
+ }
+ cache[0] = ctu;
+ ctu->incRefCnt();
+}
diff --git a/kpdf/xpdf/xpdf/CharCodeToUnicode.h b/kpdf/xpdf/xpdf/CharCodeToUnicode.h
new file mode 100644
index 00000000..04852aea
--- /dev/null
+++ b/kpdf/xpdf/xpdf/CharCodeToUnicode.h
@@ -0,0 +1,117 @@
+//========================================================================
+//
+// CharCodeToUnicode.h
+//
+// Mapping from character codes to Unicode.
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef CHARCODETOUNICODE_H
+#define CHARCODETOUNICODE_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "CharTypes.h"
+
+#if MULTITHREADED
+#include "GMutex.h"
+#endif
+
+struct CharCodeToUnicodeString;
+
+//------------------------------------------------------------------------
+
+class CharCodeToUnicode {
+public:
+
+ // Read the CID-to-Unicode mapping for <collection> from the file
+ // specified by <fileName>. Sets the initial reference count to 1.
+ // Returns NULL on failure.
+ static CharCodeToUnicode *parseCIDToUnicode(GString *fileName,
+ GString *collection);
+
+ // Create a Unicode-to-Unicode mapping from the file specified by
+ // <fileName>. Sets the initial reference count to 1. Returns NULL
+ // on failure.
+ static CharCodeToUnicode *parseUnicodeToUnicode(GString *fileName);
+
+ // Create the CharCode-to-Unicode mapping for an 8-bit font.
+ // <toUnicode> is an array of 256 Unicode indexes. Sets the initial
+ // reference count to 1.
+ static CharCodeToUnicode *make8BitToUnicode(Unicode *toUnicode);
+
+ // Parse a ToUnicode CMap for an 8- or 16-bit font.
+ static CharCodeToUnicode *parseCMap(GString *buf, int nBits);
+
+ // Parse a ToUnicode CMap for an 8- or 16-bit font, merging it into
+ // <this>.
+ void mergeCMap(GString *buf, int nBits);
+
+ ~CharCodeToUnicode();
+
+ void incRefCnt();
+ void decRefCnt();
+
+ // Return true if this mapping matches the specified <tagA>.
+ GBool match(GString *tagA);
+
+ // Set the mapping for <c>.
+ void setMapping(CharCode c, Unicode *u, int len);
+
+ // Map a CharCode to Unicode.
+ int mapToUnicode(CharCode c, Unicode *u, int size);
+
+ // Return the mapping's length, i.e., one more than the max char
+ // code supported by the mapping.
+ CharCode getLength() { return mapLen; }
+
+private:
+
+ void parseCMap1(int (*getCharFunc)(void *), void *data, int nBits);
+ void addMapping(CharCode code, char *uStr, int n, int offset);
+ CharCodeToUnicode(GString *tagA);
+ CharCodeToUnicode(GString *tagA, Unicode *mapA,
+ CharCode mapLenA, GBool copyMap,
+ CharCodeToUnicodeString *sMapA,
+ int sMapLenA, int sMapSizeA);
+
+ GString *tag;
+ Unicode *map;
+ CharCode mapLen;
+ CharCodeToUnicodeString *sMap;
+ int sMapLen, sMapSize;
+ int refCnt;
+#if MULTITHREADED
+ GMutex mutex;
+#endif
+};
+
+//------------------------------------------------------------------------
+
+class CharCodeToUnicodeCache {
+public:
+
+ CharCodeToUnicodeCache(int sizeA);
+ ~CharCodeToUnicodeCache();
+
+ // Get the CharCodeToUnicode object for <tag>. Increments its
+ // reference count; there will be one reference for the cache plus
+ // one for the caller of this function. Returns NULL on failure.
+ CharCodeToUnicode *getCharCodeToUnicode(GString *tag);
+
+ // Insert <ctu> into the cache, in the most-recently-used position.
+ void add(CharCodeToUnicode *ctu);
+
+private:
+
+ CharCodeToUnicode **cache;
+ int size;
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/CharTypes.h b/kpdf/xpdf/xpdf/CharTypes.h
new file mode 100644
index 00000000..d0df630d
--- /dev/null
+++ b/kpdf/xpdf/xpdf/CharTypes.h
@@ -0,0 +1,24 @@
+//========================================================================
+//
+// CharTypes.h
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef CHARTYPES_H
+#define CHARTYPES_H
+
+// Unicode character.
+typedef unsigned int Unicode;
+
+// Character ID for CID character collections.
+typedef unsigned int CID;
+
+// This is large enough to hold any of the following:
+// - 8-bit char code
+// - 16-bit CID
+// - Unicode
+typedef unsigned int CharCode;
+
+#endif
diff --git a/kpdf/xpdf/xpdf/CompactFontTables.h b/kpdf/xpdf/xpdf/CompactFontTables.h
new file mode 100644
index 00000000..28e16e77
--- /dev/null
+++ b/kpdf/xpdf/xpdf/CompactFontTables.h
@@ -0,0 +1,464 @@
+//========================================================================
+//
+// CompactFontTables.h
+//
+// Copyright 1999-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef COMPACTFONTINFO_H
+#define COMPACTFONTINFO_H
+
+static char *type1CStdStrings[391] = {
+ ".notdef",
+ "space",
+ "exclam",
+ "quotedbl",
+ "numbersign",
+ "dollar",
+ "percent",
+ "ampersand",
+ "quoteright",
+ "parenleft",
+ "parenright",
+ "asterisk",
+ "plus",
+ "comma",
+ "hyphen",
+ "period",
+ "slash",
+ "zero",
+ "one",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "colon",
+ "semicolon",
+ "less",
+ "equal",
+ "greater",
+ "question",
+ "at",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "bracketleft",
+ "backslash",
+ "bracketright",
+ "asciicircum",
+ "underscore",
+ "quoteleft",
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f",
+ "g",
+ "h",
+ "i",
+ "j",
+ "k",
+ "l",
+ "m",
+ "n",
+ "o",
+ "p",
+ "q",
+ "r",
+ "s",
+ "t",
+ "u",
+ "v",
+ "w",
+ "x",
+ "y",
+ "z",
+ "braceleft",
+ "bar",
+ "braceright",
+ "asciitilde",
+ "exclamdown",
+ "cent",
+ "sterling",
+ "fraction",
+ "yen",
+ "florin",
+ "section",
+ "currency",
+ "quotesingle",
+ "quotedblleft",
+ "guillemotleft",
+ "guilsinglleft",
+ "guilsinglright",
+ "fi",
+ "fl",
+ "endash",
+ "dagger",
+ "daggerdbl",
+ "periodcentered",
+ "paragraph",
+ "bullet",
+ "quotesinglbase",
+ "quotedblbase",
+ "quotedblright",
+ "guillemotright",
+ "ellipsis",
+ "perthousand",
+ "questiondown",
+ "grave",
+ "acute",
+ "circumflex",
+ "tilde",
+ "macron",
+ "breve",
+ "dotaccent",
+ "dieresis",
+ "ring",
+ "cedilla",
+ "hungarumlaut",
+ "ogonek",
+ "caron",
+ "emdash",
+ "AE",
+ "ordfeminine",
+ "Lslash",
+ "Oslash",
+ "OE",
+ "ordmasculine",
+ "ae",
+ "dotlessi",
+ "lslash",
+ "oslash",
+ "oe",
+ "germandbls",
+ "onesuperior",
+ "logicalnot",
+ "mu",
+ "trademark",
+ "Eth",
+ "onehalf",
+ "plusminus",
+ "Thorn",
+ "onequarter",
+ "divide",
+ "brokenbar",
+ "degree",
+ "thorn",
+ "threequarters",
+ "twosuperior",
+ "registered",
+ "minus",
+ "eth",
+ "multiply",
+ "threesuperior",
+ "copyright",
+ "Aacute",
+ "Acircumflex",
+ "Adieresis",
+ "Agrave",
+ "Aring",
+ "Atilde",
+ "Ccedilla",
+ "Eacute",
+ "Ecircumflex",
+ "Edieresis",
+ "Egrave",
+ "Iacute",
+ "Icircumflex",
+ "Idieresis",
+ "Igrave",
+ "Ntilde",
+ "Oacute",
+ "Ocircumflex",
+ "Odieresis",
+ "Ograve",
+ "Otilde",
+ "Scaron",
+ "Uacute",
+ "Ucircumflex",
+ "Udieresis",
+ "Ugrave",
+ "Yacute",
+ "Ydieresis",
+ "Zcaron",
+ "aacute",
+ "acircumflex",
+ "adieresis",
+ "agrave",
+ "aring",
+ "atilde",
+ "ccedilla",
+ "eacute",
+ "ecircumflex",
+ "edieresis",
+ "egrave",
+ "iacute",
+ "icircumflex",
+ "idieresis",
+ "igrave",
+ "ntilde",
+ "oacute",
+ "ocircumflex",
+ "odieresis",
+ "ograve",
+ "otilde",
+ "scaron",
+ "uacute",
+ "ucircumflex",
+ "udieresis",
+ "ugrave",
+ "yacute",
+ "ydieresis",
+ "zcaron",
+ "exclamsmall",
+ "Hungarumlautsmall",
+ "dollaroldstyle",
+ "dollarsuperior",
+ "ampersandsmall",
+ "Acutesmall",
+ "parenleftsuperior",
+ "parenrightsuperior",
+ "twodotenleader",
+ "onedotenleader",
+ "zerooldstyle",
+ "oneoldstyle",
+ "twooldstyle",
+ "threeoldstyle",
+ "fouroldstyle",
+ "fiveoldstyle",
+ "sixoldstyle",
+ "sevenoldstyle",
+ "eightoldstyle",
+ "nineoldstyle",
+ "commasuperior",
+ "threequartersemdash",
+ "periodsuperior",
+ "questionsmall",
+ "asuperior",
+ "bsuperior",
+ "centsuperior",
+ "dsuperior",
+ "esuperior",
+ "isuperior",
+ "lsuperior",
+ "msuperior",
+ "nsuperior",
+ "osuperior",
+ "rsuperior",
+ "ssuperior",
+ "tsuperior",
+ "ff",
+ "ffi",
+ "ffl",
+ "parenleftinferior",
+ "parenrightinferior",
+ "Circumflexsmall",
+ "hyphensuperior",
+ "Gravesmall",
+ "Asmall",
+ "Bsmall",
+ "Csmall",
+ "Dsmall",
+ "Esmall",
+ "Fsmall",
+ "Gsmall",
+ "Hsmall",
+ "Ismall",
+ "Jsmall",
+ "Ksmall",
+ "Lsmall",
+ "Msmall",
+ "Nsmall",
+ "Osmall",
+ "Psmall",
+ "Qsmall",
+ "Rsmall",
+ "Ssmall",
+ "Tsmall",
+ "Usmall",
+ "Vsmall",
+ "Wsmall",
+ "Xsmall",
+ "Ysmall",
+ "Zsmall",
+ "colonmonetary",
+ "onefitted",
+ "rupiah",
+ "Tildesmall",
+ "exclamdownsmall",
+ "centoldstyle",
+ "Lslashsmall",
+ "Scaronsmall",
+ "Zcaronsmall",
+ "Dieresissmall",
+ "Brevesmall",
+ "Caronsmall",
+ "Dotaccentsmall",
+ "Macronsmall",
+ "figuredash",
+ "hypheninferior",
+ "Ogoneksmall",
+ "Ringsmall",
+ "Cedillasmall",
+ "questiondownsmall",
+ "oneeighth",
+ "threeeighths",
+ "fiveeighths",
+ "seveneighths",
+ "onethird",
+ "twothirds",
+ "zerosuperior",
+ "foursuperior",
+ "fivesuperior",
+ "sixsuperior",
+ "sevensuperior",
+ "eightsuperior",
+ "ninesuperior",
+ "zeroinferior",
+ "oneinferior",
+ "twoinferior",
+ "threeinferior",
+ "fourinferior",
+ "fiveinferior",
+ "sixinferior",
+ "seveninferior",
+ "eightinferior",
+ "nineinferior",
+ "centinferior",
+ "dollarinferior",
+ "periodinferior",
+ "commainferior",
+ "Agravesmall",
+ "Aacutesmall",
+ "Acircumflexsmall",
+ "Atildesmall",
+ "Adieresissmall",
+ "Aringsmall",
+ "AEsmall",
+ "Ccedillasmall",
+ "Egravesmall",
+ "Eacutesmall",
+ "Ecircumflexsmall",
+ "Edieresissmall",
+ "Igravesmall",
+ "Iacutesmall",
+ "Icircumflexsmall",
+ "Idieresissmall",
+ "Ethsmall",
+ "Ntildesmall",
+ "Ogravesmall",
+ "Oacutesmall",
+ "Ocircumflexsmall",
+ "Otildesmall",
+ "Odieresissmall",
+ "OEsmall",
+ "Oslashsmall",
+ "Ugravesmall",
+ "Uacutesmall",
+ "Ucircumflexsmall",
+ "Udieresissmall",
+ "Yacutesmall",
+ "Thornsmall",
+ "Ydieresissmall",
+ "001.000",
+ "001.001",
+ "001.002",
+ "001.003",
+ "Black",
+ "Bold",
+ "Book",
+ "Light",
+ "Medium",
+ "Regular",
+ "Roman",
+ "Semibold"
+};
+
+static Gushort type1CISOAdobeCharset[229] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+ 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
+ 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,
+ 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
+ 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
+ 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+ 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
+ 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
+ 180, 181, 182, 183, 184, 185, 186, 187, 188, 189,
+ 190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
+ 200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
+ 210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
+ 220, 221, 222, 223, 224, 225, 226, 227, 228
+};
+
+static Gushort type1CExpertCharset[166] = {
+ 0, 1, 229, 230, 231, 232, 233, 234, 235, 236,
+ 237, 238, 13, 14, 15, 99, 239, 240, 241, 242,
+ 243, 244, 245, 246, 247, 248, 27, 28, 249, 250,
+ 251, 252, 253, 254, 255, 256, 257, 258, 259, 260,
+ 261, 262, 263, 264, 265, 266, 109, 110, 267, 268,
+ 269, 270, 271, 272, 273, 274, 275, 276, 277, 278,
+ 279, 280, 281, 282, 283, 284, 285, 286, 287, 288,
+ 289, 290, 291, 292, 293, 294, 295, 296, 297, 298,
+ 299, 300, 301, 302, 303, 304, 305, 306, 307, 308,
+ 309, 310, 311, 312, 313, 314, 315, 316, 317, 318,
+ 158, 155, 163, 319, 320, 321, 322, 323, 324, 325,
+ 326, 150, 164, 169, 327, 328, 329, 330, 331, 332,
+ 333, 334, 335, 336, 337, 338, 339, 340, 341, 342,
+ 343, 344, 345, 346, 347, 348, 349, 350, 351, 352,
+ 353, 354, 355, 356, 357, 358, 359, 360, 361, 362,
+ 363, 364, 365, 366, 367, 368, 369, 370, 371, 372,
+ 373, 374, 375, 376, 377, 378
+};
+
+static Gushort type1CExpertSubsetCharset[87] = {
+ 0, 1, 231, 232, 235, 236, 237, 238, 13, 14,
+ 15, 99, 239, 240, 241, 242, 243, 244, 245, 246,
+ 247, 248, 27, 28, 249, 250, 251, 253, 254, 255,
+ 256, 257, 258, 259, 260, 261, 262, 263, 264, 265,
+ 266, 109, 110, 267, 268, 269, 270, 272, 300, 301,
+ 302, 305, 314, 315, 158, 155, 163, 320, 321, 322,
+ 323, 324, 325, 326, 150, 164, 169, 327, 328, 329,
+ 330, 331, 332, 333, 334, 335, 336, 337, 338, 339,
+ 340, 341, 342, 343, 344, 345, 346
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/Decrypt.cc b/kpdf/xpdf/xpdf/Decrypt.cc
new file mode 100644
index 00000000..51e56fb1
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Decrypt.cc
@@ -0,0 +1,776 @@
+//========================================================================
+//
+// Decrypt.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <string.h>
+#include "gmem.h"
+#include "Decrypt.h"
+
+static void rc4InitKey(Guchar *key, int keyLen, Guchar *state);
+static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c);
+static void aesKeyExpansion(DecryptAESState *s,
+ Guchar *objKey, int objKeyLen);
+static void aesDecryptBlock(DecryptAESState *s, Guchar *in, GBool last);
+static void md5(Guchar *msg, int msgLen, Guchar *digest);
+
+static Guchar passwordPad[32] = {
+ 0x28, 0xbf, 0x4e, 0x5e, 0x4e, 0x75, 0x8a, 0x41,
+ 0x64, 0x00, 0x4e, 0x56, 0xff, 0xfa, 0x01, 0x08,
+ 0x2e, 0x2e, 0x00, 0xb6, 0xd0, 0x68, 0x3e, 0x80,
+ 0x2f, 0x0c, 0xa9, 0xfe, 0x64, 0x53, 0x69, 0x7a
+};
+
+//------------------------------------------------------------------------
+// Decrypt
+//------------------------------------------------------------------------
+
+GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength,
+ GString *ownerKey, GString *userKey,
+ int permissions, GString *fileID,
+ GString *ownerPassword, GString *userPassword,
+ Guchar *fileKey, GBool encryptMetadata,
+ GBool *ownerPasswordOk) {
+ Guchar test[32], test2[32];
+ GString *userPassword2;
+ Guchar fState[256];
+ Guchar tmpKey[16];
+ Guchar fx, fy;
+ int len, i, j;
+
+ // try using the supplied owner password to generate the user password
+ *ownerPasswordOk = gFalse;
+ if (ownerPassword) {
+ len = ownerPassword->getLength();
+ if (len < 32) {
+ memcpy(test, ownerPassword->getCString(), len);
+ memcpy(test + len, passwordPad, 32 - len);
+ } else {
+ memcpy(test, ownerPassword->getCString(), 32);
+ }
+ md5(test, 32, test);
+ if (encRevision == 3) {
+ for (i = 0; i < 50; ++i) {
+ md5(test, 16, test);
+ }
+ }
+ if (encRevision == 2) {
+ rc4InitKey(test, keyLength, fState);
+ fx = fy = 0;
+ for (i = 0; i < 32; ++i) {
+ test2[i] = rc4DecryptByte(fState, &fx, &fy, ownerKey->getChar(i));
+ }
+ } else {
+ memcpy(test2, ownerKey->getCString(), 32);
+ for (i = 19; i >= 0; --i) {
+ for (j = 0; j < keyLength; ++j) {
+ tmpKey[j] = test[j] ^ i;
+ }
+ rc4InitKey(tmpKey, keyLength, fState);
+ fx = fy = 0;
+ for (j = 0; j < 32; ++j) {
+ test2[j] = rc4DecryptByte(fState, &fx, &fy, test2[j]);
+ }
+ }
+ }
+ userPassword2 = new GString((char *)test2, 32);
+ if (makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey,
+ permissions, fileID, userPassword2, fileKey,
+ encryptMetadata)) {
+ *ownerPasswordOk = gTrue;
+ delete userPassword2;
+ return gTrue;
+ }
+ delete userPassword2;
+ }
+
+ // try using the supplied user password
+ return makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey,
+ permissions, fileID, userPassword, fileKey,
+ encryptMetadata);
+}
+
+GBool Decrypt::makeFileKey2(int /*encVersion*/, int encRevision, int keyLength,
+ GString *ownerKey, GString *userKey,
+ int permissions, GString *fileID,
+ GString *userPassword, Guchar *fileKey,
+ GBool encryptMetadata) {
+ Guchar *buf;
+ Guchar test[32];
+ Guchar fState[256];
+ Guchar tmpKey[16];
+ Guchar fx, fy;
+ int len, i, j;
+ GBool ok;
+
+ // generate file key
+ buf = (Guchar *)gmalloc(72 + fileID->getLength());
+ if (userPassword) {
+ len = userPassword->getLength();
+ if (len < 32) {
+ memcpy(buf, userPassword->getCString(), len);
+ memcpy(buf + len, passwordPad, 32 - len);
+ } else {
+ memcpy(buf, userPassword->getCString(), 32);
+ }
+ } else {
+ memcpy(buf, passwordPad, 32);
+ }
+ memcpy(buf + 32, ownerKey->getCString(), 32);
+ buf[64] = permissions & 0xff;
+ buf[65] = (permissions >> 8) & 0xff;
+ buf[66] = (permissions >> 16) & 0xff;
+ buf[67] = (permissions >> 24) & 0xff;
+ memcpy(buf + 68, fileID->getCString(), fileID->getLength());
+ len = 68 + fileID->getLength();
+ if (!encryptMetadata) {
+ buf[len++] = 0xff;
+ buf[len++] = 0xff;
+ buf[len++] = 0xff;
+ buf[len++] = 0xff;
+ }
+ md5(buf, len, fileKey);
+ if (encRevision == 3) {
+ for (i = 0; i < 50; ++i) {
+ md5(fileKey, keyLength, fileKey);
+ }
+ }
+
+ // test user password
+ if (encRevision == 2) {
+ rc4InitKey(fileKey, keyLength, fState);
+ fx = fy = 0;
+ for (i = 0; i < 32; ++i) {
+ test[i] = rc4DecryptByte(fState, &fx, &fy, userKey->getChar(i));
+ }
+ ok = memcmp(test, passwordPad, 32) == 0;
+ } else if (encRevision == 3) {
+ memcpy(test, userKey->getCString(), 32);
+ for (i = 19; i >= 0; --i) {
+ for (j = 0; j < keyLength; ++j) {
+ tmpKey[j] = fileKey[j] ^ i;
+ }
+ rc4InitKey(tmpKey, keyLength, fState);
+ fx = fy = 0;
+ for (j = 0; j < 32; ++j) {
+ test[j] = rc4DecryptByte(fState, &fx, &fy, test[j]);
+ }
+ }
+ memcpy(buf, passwordPad, 32);
+ memcpy(buf + 32, fileID->getCString(), fileID->getLength());
+ md5(buf, 32 + fileID->getLength(), buf);
+ ok = memcmp(test, buf, 16) == 0;
+ } else {
+ ok = gFalse;
+ }
+
+ gfree(buf);
+ return ok;
+}
+
+//------------------------------------------------------------------------
+// DecryptStream
+//------------------------------------------------------------------------
+
+DecryptStream::DecryptStream(Stream *strA, Guchar *fileKey,
+ CryptAlgorithm algoA, int keyLength,
+ int objNum, int objGen):
+ FilterStream(strA)
+{
+ int n, i;
+
+ algo = algoA;
+
+ // construct object key
+ for (i = 0; i < keyLength; ++i) {
+ objKey[i] = fileKey[i];
+ }
+ objKey[keyLength] = objNum & 0xff;
+ objKey[keyLength + 1] = (objNum >> 8) & 0xff;
+ objKey[keyLength + 2] = (objNum >> 16) & 0xff;
+ objKey[keyLength + 3] = objGen & 0xff;
+ objKey[keyLength + 4] = (objGen >> 8) & 0xff;
+ if (algo == cryptAES) {
+ objKey[keyLength + 5] = 0x73; // 's'
+ objKey[keyLength + 6] = 0x41; // 'A'
+ objKey[keyLength + 7] = 0x6c; // 'l'
+ objKey[keyLength + 8] = 0x54; // 'T'
+ n = keyLength + 9;
+ } else {
+ n = keyLength + 5;
+ }
+ md5(objKey, n, objKey);
+ if ((objKeyLength = keyLength + 5) > 16) {
+ objKeyLength = 16;
+ }
+}
+
+DecryptStream::~DecryptStream() {
+ delete str;
+}
+
+void DecryptStream::reset() {
+ int i;
+
+ str->reset();
+ switch (algo) {
+ case cryptRC4:
+ state.rc4.x = state.rc4.y = 0;
+ rc4InitKey(objKey, objKeyLength, state.rc4.state);
+ state.rc4.buf = EOF;
+ break;
+ case cryptAES:
+ aesKeyExpansion(&state.aes, objKey, objKeyLength);
+ for (i = 0; i < 16; ++i) {
+ state.aes.cbc[i] = str->getChar();
+ }
+ state.aes.bufIdx = 16;
+ break;
+ }
+}
+
+int DecryptStream::getChar() {
+ Guchar in[16];
+ int c, i;
+
+ c = EOF; // make gcc happy
+ switch (algo) {
+ case cryptRC4:
+ if (state.rc4.buf == EOF) {
+ c = str->getChar();
+ if (c != EOF) {
+ state.rc4.buf = rc4DecryptByte(state.rc4.state, &state.rc4.x,
+ &state.rc4.y, (Guchar)c);
+ }
+ }
+ c = state.rc4.buf;
+ state.rc4.buf = EOF;
+ break;
+ case cryptAES:
+ if (state.aes.bufIdx == 16) {
+ for (i = 0; i < 16; ++i) {
+ if ((c = str->getChar()) == EOF) {
+ return EOF;
+ }
+ in[i] = (Guchar)c;
+ }
+ aesDecryptBlock(&state.aes, in, str->lookChar() == EOF);
+ }
+ if (state.aes.bufIdx == 16) {
+ c = EOF;
+ } else {
+ c = state.aes.buf[state.aes.bufIdx++];
+ }
+ break;
+ }
+ return c;
+}
+
+int DecryptStream::lookChar() {
+ Guchar in[16];
+ int c, i;
+
+ c = EOF; // make gcc happy
+ switch (algo) {
+ case cryptRC4:
+ if (state.rc4.buf == EOF) {
+ c = str->getChar();
+ if (c != EOF) {
+ state.rc4.buf = rc4DecryptByte(state.rc4.state, &state.rc4.x,
+ &state.rc4.y, (Guchar)c);
+ }
+ }
+ c = state.rc4.buf;
+ break;
+ case cryptAES:
+ if (state.aes.bufIdx == 16) {
+ for (i = 0; i < 16; ++i) {
+ if ((c = str->getChar()) == EOF) {
+ return EOF;
+ }
+ in[i] = c;
+ }
+ aesDecryptBlock(&state.aes, in, str->lookChar() == EOF);
+ }
+ if (state.aes.bufIdx == 16) {
+ c = EOF;
+ } else {
+ c = state.aes.buf[state.aes.bufIdx];
+ }
+ break;
+ }
+ return c;
+}
+
+GBool DecryptStream::isBinary(GBool last) {
+ return str->isBinary(last);
+}
+
+//------------------------------------------------------------------------
+// RC4-compatible decryption
+//------------------------------------------------------------------------
+
+static void rc4InitKey(Guchar *key, int keyLen, Guchar *state) {
+ Guchar index1, index2;
+ Guchar t;
+ int i;
+
+ for (i = 0; i < 256; ++i)
+ state[i] = i;
+ index1 = index2 = 0;
+ for (i = 0; i < 256; ++i) {
+ index2 = (key[index1] + state[i] + index2) % 256;
+ t = state[i];
+ state[i] = state[index2];
+ state[index2] = t;
+ index1 = (index1 + 1) % keyLen;
+ }
+}
+
+static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c) {
+ Guchar x1, y1, tx, ty;
+
+ x1 = *x = (*x + 1) % 256;
+ y1 = *y = (state[*x] + *y) % 256;
+ tx = state[x1];
+ ty = state[y1];
+ state[x1] = ty;
+ state[y1] = tx;
+ return c ^ state[(tx + ty) % 256];
+}
+
+//------------------------------------------------------------------------
+// AES decryption
+//------------------------------------------------------------------------
+
+static Guchar sbox[256] = {
+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
+ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
+ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
+ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
+ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
+ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
+ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
+ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
+ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
+ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
+};
+
+static Guchar invSbox[256] = {
+ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
+ 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
+ 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
+ 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
+ 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
+ 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
+ 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
+ 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
+ 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
+ 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
+ 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
+ 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
+ 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
+ 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
+ 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
+ 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
+};
+
+static Guint rcon[11] = {
+ 0x00000000, // unused
+ 0x01000000,
+ 0x02000000,
+ 0x04000000,
+ 0x08000000,
+ 0x10000000,
+ 0x20000000,
+ 0x40000000,
+ 0x80000000,
+ 0x1b000000,
+ 0x36000000
+};
+
+static inline Guint subWord(Guint x) {
+ return (sbox[x >> 24] << 24)
+ | (sbox[(x >> 16) & 0xff] << 16)
+ | (sbox[(x >> 8) & 0xff] << 8)
+ | sbox[x & 0xff];
+}
+
+static inline Guint rotWord(Guint x) {
+ return ((x << 8) & 0xffffffff) | (x >> 24);
+}
+
+static inline void invSubBytes(Guchar *state) {
+ int i;
+
+ for (i = 0; i < 16; ++i) {
+ state[i] = invSbox[state[i]];
+ }
+}
+
+static inline void invShiftRows(Guchar *state) {
+ Guchar t;
+
+ t = state[7];
+ state[7] = state[6];
+ state[6] = state[5];
+ state[5] = state[4];
+ state[4] = t;
+
+ t = state[8];
+ state[8] = state[10];
+ state[10] = t;
+ t = state[9];
+ state[9] = state[11];
+ state[11] = t;
+
+ t = state[12];
+ state[12] = state[13];
+ state[13] = state[14];
+ state[14] = state[15];
+ state[15] = t;
+}
+
+// {09} \cdot s
+static inline Guchar mul09(Guchar s) {
+ Guchar s2, s4, s8;
+
+ s2 = (s & 0x80) ? ((s << 1) ^ 0x1b) : (s << 1);
+ s4 = (s2 & 0x80) ? ((s2 << 1) ^ 0x1b) : (s2 << 1);
+ s8 = (s4 & 0x80) ? ((s4 << 1) ^ 0x1b) : (s4 << 1);
+ return s ^ s8;
+}
+
+// {0b} \cdot s
+static inline Guchar mul0b(Guchar s) {
+ Guchar s2, s4, s8;
+
+ s2 = (s & 0x80) ? ((s << 1) ^ 0x1b) : (s << 1);
+ s4 = (s2 & 0x80) ? ((s2 << 1) ^ 0x1b) : (s2 << 1);
+ s8 = (s4 & 0x80) ? ((s4 << 1) ^ 0x1b) : (s4 << 1);
+ return s ^ s2 ^ s8;
+}
+
+// {0d} \cdot s
+static inline Guchar mul0d(Guchar s) {
+ Guchar s2, s4, s8;
+
+ s2 = (s & 0x80) ? ((s << 1) ^ 0x1b) : (s << 1);
+ s4 = (s2 & 0x80) ? ((s2 << 1) ^ 0x1b) : (s2 << 1);
+ s8 = (s4 & 0x80) ? ((s4 << 1) ^ 0x1b) : (s4 << 1);
+ return s ^ s4 ^ s8;
+}
+
+// {0e} \cdot s
+static inline Guchar mul0e(Guchar s) {
+ Guchar s2, s4, s8;
+
+ s2 = (s & 0x80) ? ((s << 1) ^ 0x1b) : (s << 1);
+ s4 = (s2 & 0x80) ? ((s2 << 1) ^ 0x1b) : (s2 << 1);
+ s8 = (s4 & 0x80) ? ((s4 << 1) ^ 0x1b) : (s4 << 1);
+ return s2 ^ s4 ^ s8;
+}
+
+static inline void invMixColumns(Guchar *state) {
+ int c;
+ Guchar s0, s1, s2, s3;
+
+ for (c = 0; c < 4; ++c) {
+ s0 = state[c];
+ s1 = state[4+c];
+ s2 = state[8+c];
+ s3 = state[12+c];
+ state[c] = mul0e(s0) ^ mul0b(s1) ^ mul0d(s2) ^ mul09(s3);
+ state[4+c] = mul09(s0) ^ mul0e(s1) ^ mul0b(s2) ^ mul0d(s3);
+ state[8+c] = mul0d(s0) ^ mul09(s1) ^ mul0e(s2) ^ mul0b(s3);
+ state[12+c] = mul0b(s0) ^ mul0d(s1) ^ mul09(s2) ^ mul0e(s3);
+ }
+}
+
+static inline void invMixColumnsW(Guint *w) {
+ int c;
+ Guchar s0, s1, s2, s3;
+
+ for (c = 0; c < 4; ++c) {
+ s0 = w[c] >> 24;
+ s1 = w[c] >> 16;
+ s2 = w[c] >> 8;
+ s3 = w[c];
+ w[c] = ((mul0e(s0) ^ mul0b(s1) ^ mul0d(s2) ^ mul09(s3)) << 24)
+ | ((mul09(s0) ^ mul0e(s1) ^ mul0b(s2) ^ mul0d(s3)) << 16)
+ | ((mul0d(s0) ^ mul09(s1) ^ mul0e(s2) ^ mul0b(s3)) << 8)
+ | (mul0b(s0) ^ mul0d(s1) ^ mul09(s2) ^ mul0e(s3));
+ }
+}
+
+static inline void addRoundKey(Guchar *state, Guint *w) {
+ int c;
+
+ for (c = 0; c < 4; ++c) {
+ state[c] ^= w[c] >> 24;
+ state[4+c] ^= w[c] >> 16;
+ state[8+c] ^= w[c] >> 8;
+ state[12+c] ^= w[c];
+ }
+}
+
+static void aesKeyExpansion(DecryptAESState *s,
+ Guchar *objKey, int /*objKeyLen*/) {
+ Guint temp;
+ int i, round;
+
+ //~ this assumes objKeyLen == 16
+
+ for (i = 0; i < 4; ++i) {
+ s->w[i] = (objKey[4*i] << 24) + (objKey[4*i+1] << 16) +
+ (objKey[4*i+2] << 8) + objKey[4*i+3];
+ }
+ for (i = 4; i < 44; ++i) {
+ temp = s->w[i-1];
+ if (!(i & 3)) {
+ temp = subWord(rotWord(temp)) ^ rcon[i/4];
+ }
+ s->w[i] = s->w[i-4] ^ temp;
+ }
+ for (round = 1; round <= 9; ++round) {
+ invMixColumnsW(&s->w[round * 4]);
+ }
+}
+
+static void aesDecryptBlock(DecryptAESState *s, Guchar *in, GBool last) {
+ int c, round, n, i;
+
+ // initial state
+ for (c = 0; c < 4; ++c) {
+ s->state[c] = in[4*c];
+ s->state[4+c] = in[4*c+1];
+ s->state[8+c] = in[4*c+2];
+ s->state[12+c] = in[4*c+3];
+ }
+
+ // round 0
+ addRoundKey(s->state, &s->w[10 * 4]);
+
+ // rounds 1-9
+ for (round = 9; round >= 1; --round) {
+ invSubBytes(s->state);
+ invShiftRows(s->state);
+ invMixColumns(s->state);
+ addRoundKey(s->state, &s->w[round * 4]);
+ }
+
+ // round 10
+ invSubBytes(s->state);
+ invShiftRows(s->state);
+ addRoundKey(s->state, &s->w[0]);
+
+ // CBC
+ for (c = 0; c < 4; ++c) {
+ s->buf[4*c] = s->state[c] ^ s->cbc[4*c];
+ s->buf[4*c+1] = s->state[4+c] ^ s->cbc[4*c+1];
+ s->buf[4*c+2] = s->state[8+c] ^ s->cbc[4*c+2];
+ s->buf[4*c+3] = s->state[12+c] ^ s->cbc[4*c+3];
+ }
+
+ // save the input block for the next CBC
+ for (i = 0; i < 16; ++i) {
+ s->cbc[i] = in[i];
+ }
+
+ // remove padding
+ s->bufIdx = 0;
+ if (last) {
+ n = s->buf[15];
+ for (i = 15; i >= n; --i) {
+ s->buf[i] = s->buf[i-n];
+ }
+ s->bufIdx = n;
+ }
+}
+
+//------------------------------------------------------------------------
+// MD5 message digest
+//------------------------------------------------------------------------
+
+// this works around a bug in older Sun compilers
+static inline Gulong rotateLeft(Gulong x, int r) {
+ x &= 0xffffffff;
+ return ((x << r) | (x >> (32 - r))) & 0xffffffff;
+}
+
+static inline Gulong md5Round1(Gulong a, Gulong b, Gulong c, Gulong d,
+ Gulong Xk, Gulong s, Gulong Ti) {
+ return b + rotateLeft((a + ((b & c) | (~b & d)) + Xk + Ti), s);
+}
+
+static inline Gulong md5Round2(Gulong a, Gulong b, Gulong c, Gulong d,
+ Gulong Xk, Gulong s, Gulong Ti) {
+ return b + rotateLeft((a + ((b & d) | (c & ~d)) + Xk + Ti), s);
+}
+
+static inline Gulong md5Round3(Gulong a, Gulong b, Gulong c, Gulong d,
+ Gulong Xk, Gulong s, Gulong Ti) {
+ return b + rotateLeft((a + (b ^ c ^ d) + Xk + Ti), s);
+}
+
+static inline Gulong md5Round4(Gulong a, Gulong b, Gulong c, Gulong d,
+ Gulong Xk, Gulong s, Gulong Ti) {
+ return b + rotateLeft((a + (c ^ (b | ~d)) + Xk + Ti), s);
+}
+
+static void md5(Guchar *msg, int msgLen, Guchar *digest) {
+ Gulong x[16];
+ Gulong a, b, c, d, aa, bb, cc, dd;
+ int n64;
+ int i, j, k;
+
+ // compute number of 64-byte blocks
+ // (length + pad byte (0x80) + 8 bytes for length)
+ n64 = (msgLen + 1 + 8 + 63) / 64;
+
+ // initialize a, b, c, d
+ a = 0x67452301;
+ b = 0xefcdab89;
+ c = 0x98badcfe;
+ d = 0x10325476;
+
+ // loop through blocks
+ k = 0;
+ for (i = 0; i < n64; ++i) {
+
+ // grab a 64-byte block
+ for (j = 0; j < 16 && k < msgLen - 3; ++j, k += 4)
+ x[j] = (((((msg[k+3] << 8) + msg[k+2]) << 8) + msg[k+1]) << 8) + msg[k];
+ if (i == n64 - 1) {
+ if (k == msgLen - 3)
+ x[j] = 0x80000000 + (((msg[k+2] << 8) + msg[k+1]) << 8) + msg[k];
+ else if (k == msgLen - 2)
+ x[j] = 0x800000 + (msg[k+1] << 8) + msg[k];
+ else if (k == msgLen - 1)
+ x[j] = 0x8000 + msg[k];
+ else
+ x[j] = 0x80;
+ ++j;
+ while (j < 16)
+ x[j++] = 0;
+ x[14] = msgLen << 3;
+ }
+
+ // save a, b, c, d
+ aa = a;
+ bb = b;
+ cc = c;
+ dd = d;
+
+ // round 1
+ a = md5Round1(a, b, c, d, x[0], 7, 0xd76aa478);
+ d = md5Round1(d, a, b, c, x[1], 12, 0xe8c7b756);
+ c = md5Round1(c, d, a, b, x[2], 17, 0x242070db);
+ b = md5Round1(b, c, d, a, x[3], 22, 0xc1bdceee);
+ a = md5Round1(a, b, c, d, x[4], 7, 0xf57c0faf);
+ d = md5Round1(d, a, b, c, x[5], 12, 0x4787c62a);
+ c = md5Round1(c, d, a, b, x[6], 17, 0xa8304613);
+ b = md5Round1(b, c, d, a, x[7], 22, 0xfd469501);
+ a = md5Round1(a, b, c, d, x[8], 7, 0x698098d8);
+ d = md5Round1(d, a, b, c, x[9], 12, 0x8b44f7af);
+ c = md5Round1(c, d, a, b, x[10], 17, 0xffff5bb1);
+ b = md5Round1(b, c, d, a, x[11], 22, 0x895cd7be);
+ a = md5Round1(a, b, c, d, x[12], 7, 0x6b901122);
+ d = md5Round1(d, a, b, c, x[13], 12, 0xfd987193);
+ c = md5Round1(c, d, a, b, x[14], 17, 0xa679438e);
+ b = md5Round1(b, c, d, a, x[15], 22, 0x49b40821);
+
+ // round 2
+ a = md5Round2(a, b, c, d, x[1], 5, 0xf61e2562);
+ d = md5Round2(d, a, b, c, x[6], 9, 0xc040b340);
+ c = md5Round2(c, d, a, b, x[11], 14, 0x265e5a51);
+ b = md5Round2(b, c, d, a, x[0], 20, 0xe9b6c7aa);
+ a = md5Round2(a, b, c, d, x[5], 5, 0xd62f105d);
+ d = md5Round2(d, a, b, c, x[10], 9, 0x02441453);
+ c = md5Round2(c, d, a, b, x[15], 14, 0xd8a1e681);
+ b = md5Round2(b, c, d, a, x[4], 20, 0xe7d3fbc8);
+ a = md5Round2(a, b, c, d, x[9], 5, 0x21e1cde6);
+ d = md5Round2(d, a, b, c, x[14], 9, 0xc33707d6);
+ c = md5Round2(c, d, a, b, x[3], 14, 0xf4d50d87);
+ b = md5Round2(b, c, d, a, x[8], 20, 0x455a14ed);
+ a = md5Round2(a, b, c, d, x[13], 5, 0xa9e3e905);
+ d = md5Round2(d, a, b, c, x[2], 9, 0xfcefa3f8);
+ c = md5Round2(c, d, a, b, x[7], 14, 0x676f02d9);
+ b = md5Round2(b, c, d, a, x[12], 20, 0x8d2a4c8a);
+
+ // round 3
+ a = md5Round3(a, b, c, d, x[5], 4, 0xfffa3942);
+ d = md5Round3(d, a, b, c, x[8], 11, 0x8771f681);
+ c = md5Round3(c, d, a, b, x[11], 16, 0x6d9d6122);
+ b = md5Round3(b, c, d, a, x[14], 23, 0xfde5380c);
+ a = md5Round3(a, b, c, d, x[1], 4, 0xa4beea44);
+ d = md5Round3(d, a, b, c, x[4], 11, 0x4bdecfa9);
+ c = md5Round3(c, d, a, b, x[7], 16, 0xf6bb4b60);
+ b = md5Round3(b, c, d, a, x[10], 23, 0xbebfbc70);
+ a = md5Round3(a, b, c, d, x[13], 4, 0x289b7ec6);
+ d = md5Round3(d, a, b, c, x[0], 11, 0xeaa127fa);
+ c = md5Round3(c, d, a, b, x[3], 16, 0xd4ef3085);
+ b = md5Round3(b, c, d, a, x[6], 23, 0x04881d05);
+ a = md5Round3(a, b, c, d, x[9], 4, 0xd9d4d039);
+ d = md5Round3(d, a, b, c, x[12], 11, 0xe6db99e5);
+ c = md5Round3(c, d, a, b, x[15], 16, 0x1fa27cf8);
+ b = md5Round3(b, c, d, a, x[2], 23, 0xc4ac5665);
+
+ // round 4
+ a = md5Round4(a, b, c, d, x[0], 6, 0xf4292244);
+ d = md5Round4(d, a, b, c, x[7], 10, 0x432aff97);
+ c = md5Round4(c, d, a, b, x[14], 15, 0xab9423a7);
+ b = md5Round4(b, c, d, a, x[5], 21, 0xfc93a039);
+ a = md5Round4(a, b, c, d, x[12], 6, 0x655b59c3);
+ d = md5Round4(d, a, b, c, x[3], 10, 0x8f0ccc92);
+ c = md5Round4(c, d, a, b, x[10], 15, 0xffeff47d);
+ b = md5Round4(b, c, d, a, x[1], 21, 0x85845dd1);
+ a = md5Round4(a, b, c, d, x[8], 6, 0x6fa87e4f);
+ d = md5Round4(d, a, b, c, x[15], 10, 0xfe2ce6e0);
+ c = md5Round4(c, d, a, b, x[6], 15, 0xa3014314);
+ b = md5Round4(b, c, d, a, x[13], 21, 0x4e0811a1);
+ a = md5Round4(a, b, c, d, x[4], 6, 0xf7537e82);
+ d = md5Round4(d, a, b, c, x[11], 10, 0xbd3af235);
+ c = md5Round4(c, d, a, b, x[2], 15, 0x2ad7d2bb);
+ b = md5Round4(b, c, d, a, x[9], 21, 0xeb86d391);
+
+ // increment a, b, c, d
+ a += aa;
+ b += bb;
+ c += cc;
+ d += dd;
+ }
+
+ // break digest into bytes
+ digest[0] = (Guchar)(a & 0xff);
+ digest[1] = (Guchar)((a >>= 8) & 0xff);
+ digest[2] = (Guchar)((a >>= 8) & 0xff);
+ digest[3] = (Guchar)((a >>= 8) & 0xff);
+ digest[4] = (Guchar)(b & 0xff);
+ digest[5] = (Guchar)((b >>= 8) & 0xff);
+ digest[6] = (Guchar)((b >>= 8) & 0xff);
+ digest[7] = (Guchar)((b >>= 8) & 0xff);
+ digest[8] = (Guchar)(c & 0xff);
+ digest[9] = (Guchar)((c >>= 8) & 0xff);
+ digest[10] = (Guchar)((c >>= 8) & 0xff);
+ digest[11] = (Guchar)((c >>= 8) & 0xff);
+ digest[12] = (Guchar)(d & 0xff);
+ digest[13] = (Guchar)((d >>= 8) & 0xff);
+ digest[14] = (Guchar)((d >>= 8) & 0xff);
+ digest[15] = (Guchar)((d >>= 8) & 0xff);
+}
diff --git a/kpdf/xpdf/xpdf/Decrypt.h b/kpdf/xpdf/xpdf/Decrypt.h
new file mode 100644
index 00000000..56f34b77
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Decrypt.h
@@ -0,0 +1,95 @@
+//========================================================================
+//
+// Decrypt.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef DECRYPT_H
+#define DECRYPT_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "GString.h"
+#include "Object.h"
+#include "Stream.h"
+
+//------------------------------------------------------------------------
+// Decrypt
+//------------------------------------------------------------------------
+
+class Decrypt {
+public:
+
+ // Generate a file key. The <fileKey> buffer must have space for at
+ // least 16 bytes. Checks <ownerPassword> and then <userPassword>
+ // and returns true if either is correct. Sets <ownerPasswordOk> if
+ // the owner password was correct. Either or both of the passwords
+ // may be NULL, which is treated as an empty string.
+ static GBool makeFileKey(int encVersion, int encRevision, int keyLength,
+ GString *ownerKey, GString *userKey,
+ int permissions, GString *fileID,
+ GString *ownerPassword, GString *userPassword,
+ Guchar *fileKey, GBool encryptMetadata,
+ GBool *ownerPasswordOk);
+
+private:
+
+ static GBool makeFileKey2(int encVersion, int encRevision, int keyLength,
+ GString *ownerKey, GString *userKey,
+ int permissions, GString *fileID,
+ GString *userPassword, Guchar *fileKey,
+ GBool encryptMetadata);
+};
+
+//------------------------------------------------------------------------
+// DecryptStream
+//------------------------------------------------------------------------
+
+struct DecryptRC4State {
+ Guchar state[256];
+ Guchar x, y;
+ int buf;
+};
+
+struct DecryptAESState {
+ Guint w[44];
+ Guchar state[16];
+ Guchar cbc[16];
+ Guchar buf[16];
+ int bufIdx;
+};
+
+class DecryptStream: public FilterStream {
+public:
+
+ DecryptStream(Stream *strA, Guchar *fileKey,
+ CryptAlgorithm algoA, int keyLength,
+ int objNum, int objGen);
+ virtual ~DecryptStream();
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ virtual int getChar();
+ virtual int lookChar();
+ virtual GBool isBinary(GBool last);
+ virtual Stream *getUndecodedStream() { return this; }
+
+private:
+
+ CryptAlgorithm algo;
+ int objKeyLength;
+ Guchar objKey[16 + 9];
+
+ union {
+ DecryptRC4State rc4;
+ DecryptAESState aes;
+ } state;
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/Dict.cc b/kpdf/xpdf/xpdf/Dict.cc
new file mode 100644
index 00000000..dd1517f0
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Dict.cc
@@ -0,0 +1,95 @@
+//========================================================================
+//
+// Dict.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stddef.h>
+#include <string.h>
+#include "gmem.h"
+#include "Object.h"
+#include "XRef.h"
+#include "Dict.h"
+
+//------------------------------------------------------------------------
+// Dict
+//------------------------------------------------------------------------
+
+Dict::Dict(XRef *xrefA) {
+ xref = xrefA;
+ entries = NULL;
+ size = length = 0;
+ ref = 1;
+}
+
+Dict::~Dict() {
+ int i;
+
+ for (i = 0; i < length; ++i) {
+ gfree(entries[i].key);
+ entries[i].val.free();
+ }
+ gfree(entries);
+}
+
+void Dict::add(char *key, Object *val) {
+ if (length == size) {
+ if (length == 0) {
+ size = 8;
+ } else {
+ size *= 2;
+ }
+ entries = (DictEntry *)greallocn(entries, size, sizeof(DictEntry));
+ }
+ entries[length].key = key;
+ entries[length].val = *val;
+ ++length;
+}
+
+inline DictEntry *Dict::find(char *key) {
+ int i;
+
+ for (i = 0; i < length; ++i) {
+ if (!strcmp(key, entries[i].key))
+ return &entries[i];
+ }
+ return NULL;
+}
+
+GBool Dict::is(char *type) {
+ DictEntry *e;
+
+ return (e = find("Type")) && e->val.isName(type);
+}
+
+Object *Dict::lookup(char *key, Object *obj) {
+ DictEntry *e;
+
+ return (e = find(key)) ? e->val.fetch(xref, obj) : obj->initNull();
+}
+
+Object *Dict::lookupNF(char *key, Object *obj) {
+ DictEntry *e;
+
+ return (e = find(key)) ? e->val.copy(obj) : obj->initNull();
+}
+
+char *Dict::getKey(int i) {
+ return entries[i].key;
+}
+
+Object *Dict::getVal(int i, Object *obj) {
+ return entries[i].val.fetch(xref, obj);
+}
+
+Object *Dict::getValNF(int i, Object *obj) {
+ return entries[i].val.copy(obj);
+}
diff --git a/kpdf/xpdf/xpdf/Dict.h b/kpdf/xpdf/xpdf/Dict.h
new file mode 100644
index 00000000..08f55ecd
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Dict.h
@@ -0,0 +1,77 @@
+//========================================================================
+//
+// Dict.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef DICT_H
+#define DICT_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "Object.h"
+
+//------------------------------------------------------------------------
+// Dict
+//------------------------------------------------------------------------
+
+struct DictEntry {
+ char *key;
+ Object val;
+};
+
+class Dict {
+public:
+
+ // Constructor.
+ Dict(XRef *xrefA);
+
+ // Destructor.
+ ~Dict();
+
+ // Reference counting.
+ int incRef() { return ++ref; }
+ int decRef() { return --ref; }
+
+ // Get number of entries.
+ int getLength() { return length; }
+
+ // Add an entry. NB: does not copy key.
+ void add(char *key, Object *val);
+
+ // Check if dictionary is of specified type.
+ GBool is(char *type);
+
+ // Look up an entry and return the value. Returns a null object
+ // if <key> is not in the dictionary.
+ Object *lookup(char *key, Object *obj);
+ Object *lookupNF(char *key, Object *obj);
+
+ // Iterative accessors.
+ char *getKey(int i);
+ Object *getVal(int i, Object *obj);
+ Object *getValNF(int i, Object *obj);
+
+ // Set the xref pointer. This is only used in one special case: the
+ // trailer dictionary, which is read before the xref table is
+ // parsed.
+ void setXRef(XRef *xrefA) { xref = xrefA; }
+
+private:
+
+ XRef *xref; // the xref table for this PDF file
+ DictEntry *entries; // array of entries
+ int size; // size of <entries> array
+ int length; // number of entries in dictionary
+ int ref; // reference count
+
+ DictEntry *find(char *key);
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/Error.h b/kpdf/xpdf/xpdf/Error.h
new file mode 100644
index 00000000..c7bda4b6
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Error.h
@@ -0,0 +1,23 @@
+//========================================================================
+//
+// Error.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef ERROR_H
+#define ERROR_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include <stdio.h>
+#include "xpdf_config.h"
+
+extern void CDECL error(int pos, char *msg, ...);
+
+#endif
diff --git a/kpdf/xpdf/xpdf/ErrorCodes.h b/kpdf/xpdf/xpdf/ErrorCodes.h
new file mode 100644
index 00000000..b28528df
--- /dev/null
+++ b/kpdf/xpdf/xpdf/ErrorCodes.h
@@ -0,0 +1,36 @@
+//========================================================================
+//
+// ErrorCodes.h
+//
+// Copyright 2002-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef ERRORCODES_H
+#define ERRORCODES_H
+
+#define errNone 0 // no error
+
+#define errOpenFile 1 // couldn't open the PDF file
+
+#define errBadCatalog 2 // couldn't read the page catalog
+
+#define errDamaged 3 // PDF file was damaged and couldn't be
+ // repaired
+
+#define errEncrypted 4 // file was encrypted and password was
+ // incorrect or not supplied
+
+#define errHighlightFile 5 // nonexistent or invalid highlight file
+
+#define errBadPrinter 6 // invalid printer
+
+#define errPrinting 7 // error during printing
+
+#define errPermission 8 // PDF file doesn't allow that operation
+
+#define errBadPageNum 9 // invalid page number
+
+#define errFileIO 10 // file I/O error
+
+#endif
diff --git a/kpdf/xpdf/xpdf/FontEncodingTables.cc b/kpdf/xpdf/xpdf/FontEncodingTables.cc
new file mode 100644
index 00000000..f3b9280a
--- /dev/null
+++ b/kpdf/xpdf/xpdf/FontEncodingTables.cc
@@ -0,0 +1,1824 @@
+//========================================================================
+//
+// FontEncodingTables.cc
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+#include <stdlib.h>
+#include "FontEncodingTables.h"
+
+char *macRomanEncoding[256] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "space",
+ "exclam",
+ "quotedbl",
+ "numbersign",
+ "dollar",
+ "percent",
+ "ampersand",
+ "quotesingle",
+ "parenleft",
+ "parenright",
+ "asterisk",
+ "plus",
+ "comma",
+ "hyphen",
+ "period",
+ "slash",
+ "zero",
+ "one",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "colon",
+ "semicolon",
+ "less",
+ "equal",
+ "greater",
+ "question",
+ "at",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "bracketleft",
+ "backslash",
+ "bracketright",
+ "asciicircum",
+ "underscore",
+ "grave",
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f",
+ "g",
+ "h",
+ "i",
+ "j",
+ "k",
+ "l",
+ "m",
+ "n",
+ "o",
+ "p",
+ "q",
+ "r",
+ "s",
+ "t",
+ "u",
+ "v",
+ "w",
+ "x",
+ "y",
+ "z",
+ "braceleft",
+ "bar",
+ "braceright",
+ "asciitilde",
+ NULL,
+ "Adieresis",
+ "Aring",
+ "Ccedilla",
+ "Eacute",
+ "Ntilde",
+ "Odieresis",
+ "Udieresis",
+ "aacute",
+ "agrave",
+ "acircumflex",
+ "adieresis",
+ "atilde",
+ "aring",
+ "ccedilla",
+ "eacute",
+ "egrave",
+ "ecircumflex",
+ "edieresis",
+ "iacute",
+ "igrave",
+ "icircumflex",
+ "idieresis",
+ "ntilde",
+ "oacute",
+ "ograve",
+ "ocircumflex",
+ "odieresis",
+ "otilde",
+ "uacute",
+ "ugrave",
+ "ucircumflex",
+ "udieresis",
+ "dagger",
+ "degree",
+ "cent",
+ "sterling",
+ "section",
+ "bullet",
+ "paragraph",
+ "germandbls",
+ "registered",
+ "copyright",
+ "trademark",
+ "acute",
+ "dieresis",
+ "notequal",
+ "AE",
+ "Oslash",
+ "infinity",
+ "plusminus",
+ "lessequal",
+ "greaterequal",
+ "yen",
+ "mu",
+ "partialdiff",
+ "summation",
+ "product",
+ "pi",
+ "integral",
+ "ordfeminine",
+ "ordmasculine",
+ "Omega",
+ "ae",
+ "oslash",
+ "questiondown",
+ "exclamdown",
+ "logicalnot",
+ "radical",
+ "florin",
+ "approxequal",
+ "Delta",
+ "guillemotleft",
+ "guillemotright",
+ "ellipsis",
+ "space",
+ "Agrave",
+ "Atilde",
+ "Otilde",
+ "OE",
+ "oe",
+ "endash",
+ "emdash",
+ "quotedblleft",
+ "quotedblright",
+ "quoteleft",
+ "quoteright",
+ "divide",
+ "lozenge",
+ "ydieresis",
+ "Ydieresis",
+ "fraction",
+ "currency",
+ "guilsinglleft",
+ "guilsinglright",
+ "fi",
+ "fl",
+ "daggerdbl",
+ "periodcentered",
+ "quotesinglbase",
+ "quotedblbase",
+ "perthousand",
+ "Acircumflex",
+ "Ecircumflex",
+ "Aacute",
+ "Edieresis",
+ "Egrave",
+ "Iacute",
+ "Icircumflex",
+ "Idieresis",
+ "Igrave",
+ "Oacute",
+ "Ocircumflex",
+ "apple",
+ "Ograve",
+ "Uacute",
+ "Ucircumflex",
+ "Ugrave",
+ "dotlessi",
+ "circumflex",
+ "tilde",
+ "macron",
+ "breve",
+ "dotaccent",
+ "ring",
+ "cedilla",
+ "hungarumlaut",
+ "ogonek",
+ "caron"
+};
+
+char *macExpertEncoding[256] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "space",
+ "exclamsmall",
+ "Hungarumlautsmall",
+ "centoldstyle",
+ "dollaroldstyle",
+ "dollarsuperior",
+ "ampersandsmall",
+ "Acutesmall",
+ "parenleftsuperior",
+ "parenrightsuperior",
+ "twodotenleader",
+ "onedotenleader",
+ "comma",
+ "hyphen",
+ "period",
+ "fraction",
+ "zerooldstyle",
+ "oneoldstyle",
+ "twooldstyle",
+ "threeoldstyle",
+ "fouroldstyle",
+ "fiveoldstyle",
+ "sixoldstyle",
+ "sevenoldstyle",
+ "eightoldstyle",
+ "nineoldstyle",
+ "colon",
+ "semicolon",
+ NULL,
+ "threequartersemdash",
+ NULL,
+ "questionsmall",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Ethsmall",
+ NULL,
+ NULL,
+ "onequarter",
+ "onehalf",
+ "threequarters",
+ "oneeighth",
+ "threeeighths",
+ "fiveeighths",
+ "seveneighths",
+ "onethird",
+ "twothirds",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "ff",
+ "fi",
+ "fl",
+ "ffi",
+ "ffl",
+ "parenleftinferior",
+ NULL,
+ "parenrightinferior",
+ "Circumflexsmall",
+ "hypheninferior",
+ "Gravesmall",
+ "Asmall",
+ "Bsmall",
+ "Csmall",
+ "Dsmall",
+ "Esmall",
+ "Fsmall",
+ "Gsmall",
+ "Hsmall",
+ "Ismall",
+ "Jsmall",
+ "Ksmall",
+ "Lsmall",
+ "Msmall",
+ "Nsmall",
+ "Osmall",
+ "Psmall",
+ "Qsmall",
+ "Rsmall",
+ "Ssmall",
+ "Tsmall",
+ "Usmall",
+ "Vsmall",
+ "Wsmall",
+ "Xsmall",
+ "Ysmall",
+ "Zsmall",
+ "colonmonetary",
+ "onefitted",
+ "rupiah",
+ "Tildesmall",
+ NULL,
+ NULL,
+ "asuperior",
+ "centsuperior",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Aacutesmall",
+ "Agravesmall",
+ "Acircumflexsmall",
+ "Adieresissmall",
+ "Atildesmall",
+ "Aringsmall",
+ "Ccedillasmall",
+ "Eacutesmall",
+ "Egravesmall",
+ "Ecircumflexsmall",
+ "Edieresissmall",
+ "Iacutesmall",
+ "Igravesmall",
+ "Icircumflexsmall",
+ "Idieresissmall",
+ "Ntildesmall",
+ "Oacutesmall",
+ "Ogravesmall",
+ "Ocircumflexsmall",
+ "Odieresissmall",
+ "Otildesmall",
+ "Uacutesmall",
+ "Ugravesmall",
+ "Ucircumflexsmall",
+ "Udieresissmall",
+ NULL,
+ "eightsuperior",
+ "fourinferior",
+ "threeinferior",
+ "sixinferior",
+ "eightinferior",
+ "seveninferior",
+ "Scaronsmall",
+ NULL,
+ "centinferior",
+ "twoinferior",
+ NULL,
+ "Dieresissmall",
+ NULL,
+ "Caronsmall",
+ "osuperior",
+ "fiveinferior",
+ NULL,
+ "commainferior",
+ "periodinferior",
+ "Yacutesmall",
+ NULL,
+ "dollarinferior",
+ NULL,
+ NULL,
+ "Thornsmall",
+ NULL,
+ "nineinferior",
+ "zeroinferior",
+ "Zcaronsmall",
+ "AEsmall",
+ "Oslashsmall",
+ "questiondownsmall",
+ "oneinferior",
+ "Lslashsmall",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Cedillasmall",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "OEsmall",
+ "figuredash",
+ "hyphensuperior",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "exclamdownsmall",
+ NULL,
+ "Ydieresissmall",
+ NULL,
+ "onesuperior",
+ "twosuperior",
+ "threesuperior",
+ "foursuperior",
+ "fivesuperior",
+ "sixsuperior",
+ "sevensuperior",
+ "ninesuperior",
+ "zerosuperior",
+ NULL,
+ "esuperior",
+ "rsuperior",
+ "tsuperior",
+ NULL,
+ NULL,
+ "isuperior",
+ "ssuperior",
+ "dsuperior",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "lsuperior",
+ "Ogoneksmall",
+ "Brevesmall",
+ "Macronsmall",
+ "bsuperior",
+ "nsuperior",
+ "msuperior",
+ "commasuperior",
+ "periodsuperior",
+ "Dotaccentsmall",
+ "Ringsmall",
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+char *winAnsiEncoding[256] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "space",
+ "exclam",
+ "quotedbl",
+ "numbersign",
+ "dollar",
+ "percent",
+ "ampersand",
+ "quotesingle",
+ "parenleft",
+ "parenright",
+ "asterisk",
+ "plus",
+ "comma",
+ "hyphen",
+ "period",
+ "slash",
+ "zero",
+ "one",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "colon",
+ "semicolon",
+ "less",
+ "equal",
+ "greater",
+ "question",
+ "at",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "bracketleft",
+ "backslash",
+ "bracketright",
+ "asciicircum",
+ "underscore",
+ "grave",
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f",
+ "g",
+ "h",
+ "i",
+ "j",
+ "k",
+ "l",
+ "m",
+ "n",
+ "o",
+ "p",
+ "q",
+ "r",
+ "s",
+ "t",
+ "u",
+ "v",
+ "w",
+ "x",
+ "y",
+ "z",
+ "braceleft",
+ "bar",
+ "braceright",
+ "asciitilde",
+ "bullet",
+ "Euro",
+ "bullet",
+ "quotesinglbase",
+ "florin",
+ "quotedblbase",
+ "ellipsis",
+ "dagger",
+ "daggerdbl",
+ "circumflex",
+ "perthousand",
+ "Scaron",
+ "guilsinglleft",
+ "OE",
+ "bullet",
+ "Zcaron",
+ "bullet",
+ "bullet",
+ "quoteleft",
+ "quoteright",
+ "quotedblleft",
+ "quotedblright",
+ "bullet",
+ "endash",
+ "emdash",
+ "tilde",
+ "trademark",
+ "scaron",
+ "guilsinglright",
+ "oe",
+ "bullet",
+ "zcaron",
+ "Ydieresis",
+ "space",
+ "exclamdown",
+ "cent",
+ "sterling",
+ "currency",
+ "yen",
+ "brokenbar",
+ "section",
+ "dieresis",
+ "copyright",
+ "ordfeminine",
+ "guillemotleft",
+ "logicalnot",
+ "hyphen",
+ "registered",
+ "macron",
+ "degree",
+ "plusminus",
+ "twosuperior",
+ "threesuperior",
+ "acute",
+ "mu",
+ "paragraph",
+ "periodcentered",
+ "cedilla",
+ "onesuperior",
+ "ordmasculine",
+ "guillemotright",
+ "onequarter",
+ "onehalf",
+ "threequarters",
+ "questiondown",
+ "Agrave",
+ "Aacute",
+ "Acircumflex",
+ "Atilde",
+ "Adieresis",
+ "Aring",
+ "AE",
+ "Ccedilla",
+ "Egrave",
+ "Eacute",
+ "Ecircumflex",
+ "Edieresis",
+ "Igrave",
+ "Iacute",
+ "Icircumflex",
+ "Idieresis",
+ "Eth",
+ "Ntilde",
+ "Ograve",
+ "Oacute",
+ "Ocircumflex",
+ "Otilde",
+ "Odieresis",
+ "multiply",
+ "Oslash",
+ "Ugrave",
+ "Uacute",
+ "Ucircumflex",
+ "Udieresis",
+ "Yacute",
+ "Thorn",
+ "germandbls",
+ "agrave",
+ "aacute",
+ "acircumflex",
+ "atilde",
+ "adieresis",
+ "aring",
+ "ae",
+ "ccedilla",
+ "egrave",
+ "eacute",
+ "ecircumflex",
+ "edieresis",
+ "igrave",
+ "iacute",
+ "icircumflex",
+ "idieresis",
+ "eth",
+ "ntilde",
+ "ograve",
+ "oacute",
+ "ocircumflex",
+ "otilde",
+ "odieresis",
+ "divide",
+ "oslash",
+ "ugrave",
+ "uacute",
+ "ucircumflex",
+ "udieresis",
+ "yacute",
+ "thorn",
+ "ydieresis"
+};
+
+char *standardEncoding[256] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "space",
+ "exclam",
+ "quotedbl",
+ "numbersign",
+ "dollar",
+ "percent",
+ "ampersand",
+ "quoteright",
+ "parenleft",
+ "parenright",
+ "asterisk",
+ "plus",
+ "comma",
+ "hyphen",
+ "period",
+ "slash",
+ "zero",
+ "one",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "colon",
+ "semicolon",
+ "less",
+ "equal",
+ "greater",
+ "question",
+ "at",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "bracketleft",
+ "backslash",
+ "bracketright",
+ "asciicircum",
+ "underscore",
+ "quoteleft",
+ "a",
+ "b",
+ "c",
+ "d",
+ "e",
+ "f",
+ "g",
+ "h",
+ "i",
+ "j",
+ "k",
+ "l",
+ "m",
+ "n",
+ "o",
+ "p",
+ "q",
+ "r",
+ "s",
+ "t",
+ "u",
+ "v",
+ "w",
+ "x",
+ "y",
+ "z",
+ "braceleft",
+ "bar",
+ "braceright",
+ "asciitilde",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "exclamdown",
+ "cent",
+ "sterling",
+ "fraction",
+ "yen",
+ "florin",
+ "section",
+ "currency",
+ "quotesingle",
+ "quotedblleft",
+ "guillemotleft",
+ "guilsinglleft",
+ "guilsinglright",
+ "fi",
+ "fl",
+ NULL,
+ "endash",
+ "dagger",
+ "daggerdbl",
+ "periodcentered",
+ NULL,
+ "paragraph",
+ "bullet",
+ "quotesinglbase",
+ "quotedblbase",
+ "quotedblright",
+ "guillemotright",
+ "ellipsis",
+ "perthousand",
+ NULL,
+ "questiondown",
+ NULL,
+ "grave",
+ "acute",
+ "circumflex",
+ "tilde",
+ "macron",
+ "breve",
+ "dotaccent",
+ "dieresis",
+ NULL,
+ "ring",
+ "cedilla",
+ NULL,
+ "hungarumlaut",
+ "ogonek",
+ "caron",
+ "emdash",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "AE",
+ NULL,
+ "ordfeminine",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Lslash",
+ "Oslash",
+ "OE",
+ "ordmasculine",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "ae",
+ NULL,
+ NULL,
+ NULL,
+ "dotlessi",
+ NULL,
+ NULL,
+ "lslash",
+ "oslash",
+ "oe",
+ "germandbls",
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+char *expertEncoding[256] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "space",
+ "exclamsmall",
+ "Hungarumlautsmall",
+ NULL,
+ "dollaroldstyle",
+ "dollarsuperior",
+ "ampersandsmall",
+ "Acutesmall",
+ "parenleftsuperior",
+ "parenrightsuperior",
+ "twodotenleader",
+ "onedotenleader",
+ "comma",
+ "hyphen",
+ "period",
+ "fraction",
+ "zerooldstyle",
+ "oneoldstyle",
+ "twooldstyle",
+ "threeoldstyle",
+ "fouroldstyle",
+ "fiveoldstyle",
+ "sixoldstyle",
+ "sevenoldstyle",
+ "eightoldstyle",
+ "nineoldstyle",
+ "colon",
+ "semicolon",
+ "commasuperior",
+ "threequartersemdash",
+ "periodsuperior",
+ "questionsmall",
+ NULL,
+ "asuperior",
+ "bsuperior",
+ "centsuperior",
+ "dsuperior",
+ "esuperior",
+ NULL,
+ NULL,
+ NULL,
+ "isuperior",
+ NULL,
+ NULL,
+ "lsuperior",
+ "msuperior",
+ "nsuperior",
+ "osuperior",
+ NULL,
+ NULL,
+ "rsuperior",
+ "ssuperior",
+ "tsuperior",
+ NULL,
+ "ff",
+ "fi",
+ "fl",
+ "ffi",
+ "ffl",
+ "parenleftinferior",
+ NULL,
+ "parenrightinferior",
+ "Circumflexsmall",
+ "hyphensuperior",
+ "Gravesmall",
+ "Asmall",
+ "Bsmall",
+ "Csmall",
+ "Dsmall",
+ "Esmall",
+ "Fsmall",
+ "Gsmall",
+ "Hsmall",
+ "Ismall",
+ "Jsmall",
+ "Ksmall",
+ "Lsmall",
+ "Msmall",
+ "Nsmall",
+ "Osmall",
+ "Psmall",
+ "Qsmall",
+ "Rsmall",
+ "Ssmall",
+ "Tsmall",
+ "Usmall",
+ "Vsmall",
+ "Wsmall",
+ "Xsmall",
+ "Ysmall",
+ "Zsmall",
+ "colonmonetary",
+ "onefitted",
+ "rupiah",
+ "Tildesmall",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "exclamdownsmall",
+ "centoldstyle",
+ "Lslashsmall",
+ NULL,
+ NULL,
+ "Scaronsmall",
+ "Zcaronsmall",
+ "Dieresissmall",
+ "Brevesmall",
+ "Caronsmall",
+ NULL,
+ "Dotaccentsmall",
+ NULL,
+ NULL,
+ "Macronsmall",
+ NULL,
+ NULL,
+ "figuredash",
+ "hypheninferior",
+ NULL,
+ NULL,
+ "Ogoneksmall",
+ "Ringsmall",
+ "Cedillasmall",
+ NULL,
+ NULL,
+ NULL,
+ "onequarter",
+ "onehalf",
+ "threequarters",
+ "questiondownsmall",
+ "oneeighth",
+ "threeeighths",
+ "fiveeighths",
+ "seveneighths",
+ "onethird",
+ "twothirds",
+ NULL,
+ NULL,
+ "zerosuperior",
+ "onesuperior",
+ "twosuperior",
+ "threesuperior",
+ "foursuperior",
+ "fivesuperior",
+ "sixsuperior",
+ "sevensuperior",
+ "eightsuperior",
+ "ninesuperior",
+ "zeroinferior",
+ "oneinferior",
+ "twoinferior",
+ "threeinferior",
+ "fourinferior",
+ "fiveinferior",
+ "sixinferior",
+ "seveninferior",
+ "eightinferior",
+ "nineinferior",
+ "centinferior",
+ "dollarinferior",
+ "periodinferior",
+ "commainferior",
+ "Agravesmall",
+ "Aacutesmall",
+ "Acircumflexsmall",
+ "Atildesmall",
+ "Adieresissmall",
+ "Aringsmall",
+ "AEsmall",
+ "Ccedillasmall",
+ "Egravesmall",
+ "Eacutesmall",
+ "Ecircumflexsmall",
+ "Edieresissmall",
+ "Igravesmall",
+ "Iacutesmall",
+ "Icircumflexsmall",
+ "Idieresissmall",
+ "Ethsmall",
+ "Ntildesmall",
+ "Ogravesmall",
+ "Oacutesmall",
+ "Ocircumflexsmall",
+ "Otildesmall",
+ "Odieresissmall",
+ "OEsmall",
+ "Oslashsmall",
+ "Ugravesmall",
+ "Uacutesmall",
+ "Ucircumflexsmall",
+ "Udieresissmall",
+ "Yacutesmall",
+ "Thornsmall",
+ "Ydieresissmall"
+};
+
+char *symbolEncoding[256] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "space",
+ "exclam",
+ "universal",
+ "numbersign",
+ "existential",
+ "percent",
+ "ampersand",
+ "suchthat",
+ "parenleft",
+ "parenright",
+ "asteriskmath",
+ "plus",
+ "comma",
+ "minus",
+ "period",
+ "slash",
+ "zero",
+ "one",
+ "two",
+ "three",
+ "four",
+ "five",
+ "six",
+ "seven",
+ "eight",
+ "nine",
+ "colon",
+ "semicolon",
+ "less",
+ "equal",
+ "greater",
+ "question",
+ "congruent",
+ "Alpha",
+ "Beta",
+ "Chi",
+ "Delta",
+ "Epsilon",
+ "Phi",
+ "Gamma",
+ "Eta",
+ "Iota",
+ "theta1",
+ "Kappa",
+ "Lambda",
+ "Mu",
+ "Nu",
+ "Omicron",
+ "Pi",
+ "Theta",
+ "Rho",
+ "Sigma",
+ "Tau",
+ "Upsilon",
+ "sigma1",
+ "Omega",
+ "Xi",
+ "Psi",
+ "Zeta",
+ "bracketleft",
+ "therefore",
+ "bracketright",
+ "perpendicular",
+ "underscore",
+ "radicalex",
+ "alpha",
+ "beta",
+ "chi",
+ "delta",
+ "epsilon",
+ "phi",
+ "gamma",
+ "eta",
+ "iota",
+ "phi1",
+ "kappa",
+ "lambda",
+ "mu",
+ "nu",
+ "omicron",
+ "pi",
+ "theta",
+ "rho",
+ "sigma",
+ "tau",
+ "upsilon",
+ "omega1",
+ "omega",
+ "xi",
+ "psi",
+ "zeta",
+ "braceleft",
+ "bar",
+ "braceright",
+ "similar",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Upsilon1",
+ "minute",
+ "lessequal",
+ "fraction",
+ "infinity",
+ "florin",
+ "club",
+ "diamond",
+ "heart",
+ "spade",
+ "arrowboth",
+ "arrowleft",
+ "arrowup",
+ "arrowright",
+ "arrowdown",
+ "degree",
+ "plusminus",
+ "second",
+ "greaterequal",
+ "multiply",
+ "proportional",
+ "partialdiff",
+ "bullet",
+ "divide",
+ "notequal",
+ "equivalence",
+ "approxequal",
+ "ellipsis",
+ "arrowvertex",
+ "arrowhorizex",
+ "carriagereturn",
+ "aleph",
+ "Ifraktur",
+ "Rfraktur",
+ "weierstrass",
+ "circlemultiply",
+ "circleplus",
+ "emptyset",
+ "intersection",
+ "union",
+ "propersuperset",
+ "reflexsuperset",
+ "notsubset",
+ "propersubset",
+ "reflexsubset",
+ "element",
+ "notelement",
+ "angle",
+ "gradient",
+ "registerserif",
+ "copyrightserif",
+ "trademarkserif",
+ "product",
+ "radical",
+ "dotmath",
+ "logicalnot",
+ "logicaland",
+ "logicalor",
+ "arrowdblboth",
+ "arrowdblleft",
+ "arrowdblup",
+ "arrowdblright",
+ "arrowdbldown",
+ "lozenge",
+ "angleleft",
+ "registersans",
+ "copyrightsans",
+ "trademarksans",
+ "summation",
+ "parenlefttp",
+ "parenleftex",
+ "parenleftbt",
+ "bracketlefttp",
+ "bracketleftex",
+ "bracketleftbt",
+ "bracelefttp",
+ "braceleftmid",
+ "braceleftbt",
+ "braceex",
+ NULL,
+ "angleright",
+ "integral",
+ "integraltp",
+ "integralex",
+ "integralbt",
+ "parenrighttp",
+ "parenrightex",
+ "parenrightbt",
+ "bracketrighttp",
+ "bracketrightex",
+ "bracketrightbt",
+ "bracerighttp",
+ "bracerightmid",
+ "bracerightbt",
+ NULL
+};
+
+char *zapfDingbatsEncoding[256] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "space",
+ "a1",
+ "a2",
+ "a202",
+ "a3",
+ "a4",
+ "a5",
+ "a119",
+ "a118",
+ "a117",
+ "a11",
+ "a12",
+ "a13",
+ "a14",
+ "a15",
+ "a16",
+ "a105",
+ "a17",
+ "a18",
+ "a19",
+ "a20",
+ "a21",
+ "a22",
+ "a23",
+ "a24",
+ "a25",
+ "a26",
+ "a27",
+ "a28",
+ "a6",
+ "a7",
+ "a8",
+ "a9",
+ "a10",
+ "a29",
+ "a30",
+ "a31",
+ "a32",
+ "a33",
+ "a34",
+ "a35",
+ "a36",
+ "a37",
+ "a38",
+ "a39",
+ "a40",
+ "a41",
+ "a42",
+ "a43",
+ "a44",
+ "a45",
+ "a46",
+ "a47",
+ "a48",
+ "a49",
+ "a50",
+ "a51",
+ "a52",
+ "a53",
+ "a54",
+ "a55",
+ "a56",
+ "a57",
+ "a58",
+ "a59",
+ "a60",
+ "a61",
+ "a62",
+ "a63",
+ "a64",
+ "a65",
+ "a66",
+ "a67",
+ "a68",
+ "a69",
+ "a70",
+ "a71",
+ "a72",
+ "a73",
+ "a74",
+ "a203",
+ "a75",
+ "a204",
+ "a76",
+ "a77",
+ "a78",
+ "a79",
+ "a81",
+ "a82",
+ "a83",
+ "a84",
+ "a97",
+ "a98",
+ "a99",
+ "a100",
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "a101",
+ "a102",
+ "a103",
+ "a104",
+ "a106",
+ "a107",
+ "a108",
+ "a112",
+ "a111",
+ "a110",
+ "a109",
+ "a120",
+ "a121",
+ "a122",
+ "a123",
+ "a124",
+ "a125",
+ "a126",
+ "a127",
+ "a128",
+ "a129",
+ "a130",
+ "a131",
+ "a132",
+ "a133",
+ "a134",
+ "a135",
+ "a136",
+ "a137",
+ "a138",
+ "a139",
+ "a140",
+ "a141",
+ "a142",
+ "a143",
+ "a144",
+ "a145",
+ "a146",
+ "a147",
+ "a148",
+ "a149",
+ "a150",
+ "a151",
+ "a152",
+ "a153",
+ "a154",
+ "a155",
+ "a156",
+ "a157",
+ "a158",
+ "a159",
+ "a160",
+ "a161",
+ "a163",
+ "a164",
+ "a196",
+ "a165",
+ "a192",
+ "a166",
+ "a167",
+ "a168",
+ "a169",
+ "a170",
+ "a171",
+ "a172",
+ "a173",
+ "a162",
+ "a174",
+ "a175",
+ "a176",
+ "a177",
+ "a178",
+ "a179",
+ "a193",
+ "a180",
+ "a199",
+ "a181",
+ "a200",
+ "a182",
+ NULL,
+ "a201",
+ "a183",
+ "a184",
+ "a197",
+ "a185",
+ "a194",
+ "a198",
+ "a186",
+ "a195",
+ "a187",
+ "a188",
+ "a189",
+ "a190",
+ "a191",
+ NULL
+};
diff --git a/kpdf/xpdf/xpdf/FontEncodingTables.h b/kpdf/xpdf/xpdf/FontEncodingTables.h
new file mode 100644
index 00000000..8b0a1e7e
--- /dev/null
+++ b/kpdf/xpdf/xpdf/FontEncodingTables.h
@@ -0,0 +1,20 @@
+//========================================================================
+//
+// FontEncodingTables.h
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef FONTENCODINGTABLES_H
+#define FONTENCODINGTABLES_H
+
+extern char *macRomanEncoding[];
+extern char *macExpertEncoding[];
+extern char *winAnsiEncoding[];
+extern char *standardEncoding[];
+extern char *expertEncoding[];
+extern char *symbolEncoding[];
+extern char *zapfDingbatsEncoding[];
+
+#endif
diff --git a/kpdf/xpdf/xpdf/Function.cc b/kpdf/xpdf/xpdf/Function.cc
new file mode 100644
index 00000000..eaf8e974
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Function.cc
@@ -0,0 +1,1575 @@
+//========================================================================
+//
+// Function.cc
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include "gmem.h"
+#include "Object.h"
+#include "Dict.h"
+#include "Stream.h"
+#include "Error.h"
+#include "Function.h"
+
+//------------------------------------------------------------------------
+// Function
+//------------------------------------------------------------------------
+
+Function::Function() {
+}
+
+Function::~Function() {
+}
+
+Function *Function::parse(Object *funcObj) {
+ Function *func;
+ Dict *dict;
+ int funcType;
+ Object obj1;
+
+ if (funcObj->isStream()) {
+ dict = funcObj->streamGetDict();
+ } else if (funcObj->isDict()) {
+ dict = funcObj->getDict();
+ } else if (funcObj->isName("Identity")) {
+ return new IdentityFunction();
+ } else {
+ error(-1, "Expected function dictionary or stream");
+ return NULL;
+ }
+
+ if (!dict->lookup("FunctionType", &obj1)->isInt()) {
+ error(-1, "Function type is missing or wrong type");
+ obj1.free();
+ return NULL;
+ }
+ funcType = obj1.getInt();
+ obj1.free();
+
+ if (funcType == 0) {
+ func = new SampledFunction(funcObj, dict);
+ } else if (funcType == 2) {
+ func = new ExponentialFunction(funcObj, dict);
+ } else if (funcType == 3) {
+ func = new StitchingFunction(funcObj, dict);
+ } else if (funcType == 4) {
+ func = new PostScriptFunction(funcObj, dict);
+ } else {
+ error(-1, "Unimplemented function type (%d)", funcType);
+ return NULL;
+ }
+ if (!func->isOk()) {
+ delete func;
+ return NULL;
+ }
+
+ return func;
+}
+
+GBool Function::init(Dict *dict) {
+ Object obj1, obj2;
+ int i;
+
+ //----- Domain
+ if (!dict->lookup("Domain", &obj1)->isArray()) {
+ error(-1, "Function is missing domain");
+ goto err2;
+ }
+ m = obj1.arrayGetLength() / 2;
+ if (m > funcMaxInputs) {
+ error(-1, "Functions with more than %d inputs are unsupported",
+ funcMaxInputs);
+ goto err2;
+ }
+ for (i = 0; i < m; ++i) {
+ obj1.arrayGet(2*i, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function domain array");
+ goto err1;
+ }
+ domain[i][0] = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2*i+1, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function domain array");
+ goto err1;
+ }
+ domain[i][1] = obj2.getNum();
+ obj2.free();
+ }
+ obj1.free();
+
+ //----- Range
+ hasRange = gFalse;
+ n = 0;
+ if (dict->lookup("Range", &obj1)->isArray()) {
+ hasRange = gTrue;
+ n = obj1.arrayGetLength() / 2;
+ if (n > funcMaxOutputs) {
+ error(-1, "Functions with more than %d outputs are unsupported",
+ funcMaxOutputs);
+ goto err2;
+ }
+ for (i = 0; i < n; ++i) {
+ obj1.arrayGet(2*i, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function range array");
+ goto err1;
+ }
+ range[i][0] = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2*i+1, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function range array");
+ goto err1;
+ }
+ range[i][1] = obj2.getNum();
+ obj2.free();
+ }
+ }
+ obj1.free();
+
+ return gTrue;
+
+ err1:
+ obj2.free();
+ err2:
+ obj1.free();
+ return gFalse;
+}
+
+//------------------------------------------------------------------------
+// IdentityFunction
+//------------------------------------------------------------------------
+
+IdentityFunction::IdentityFunction() {
+ int i;
+
+ // fill these in with arbitrary values just in case they get used
+ // somewhere
+ m = funcMaxInputs;
+ n = funcMaxOutputs;
+ for (i = 0; i < funcMaxInputs; ++i) {
+ domain[i][0] = 0;
+ domain[i][1] = 1;
+ }
+ hasRange = gFalse;
+}
+
+IdentityFunction::~IdentityFunction() {
+}
+
+void IdentityFunction::transform(double *in, double *out) {
+ int i;
+
+ for (i = 0; i < funcMaxOutputs; ++i) {
+ out[i] = in[i];
+ }
+}
+
+//------------------------------------------------------------------------
+// SampledFunction
+//------------------------------------------------------------------------
+
+SampledFunction::SampledFunction(Object *funcObj, Dict *dict) {
+ Stream *str;
+ int sampleBits;
+ double sampleMul;
+ Object obj1, obj2;
+ Guint buf, bitMask;
+ int bits;
+ Guint s;
+ int i;
+
+ samples = NULL;
+ sBuf = NULL;
+ ok = gFalse;
+
+ //----- initialize the generic stuff
+ if (!init(dict)) {
+ goto err1;
+ }
+ if (!hasRange) {
+ error(-1, "Type 0 function is missing range");
+ goto err1;
+ }
+ if (m > sampledFuncMaxInputs) {
+ error(-1, "Sampled functions with more than %d inputs are unsupported",
+ sampledFuncMaxInputs);
+ goto err1;
+ }
+
+ //----- buffer
+ sBuf = (double *)gmallocn(1 << m, sizeof(double));
+
+ //----- get the stream
+ if (!funcObj->isStream()) {
+ error(-1, "Type 0 function isn't a stream");
+ goto err1;
+ }
+ str = funcObj->getStream();
+
+ //----- Size
+ if (!dict->lookup("Size", &obj1)->isArray() ||
+ obj1.arrayGetLength() != m) {
+ error(-1, "Function has missing or invalid size array");
+ goto err2;
+ }
+ for (i = 0; i < m; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!obj2.isInt()) {
+ error(-1, "Illegal value in function size array");
+ goto err3;
+ }
+ sampleSize[i] = obj2.getInt();
+ obj2.free();
+ }
+ obj1.free();
+ idxMul[0] = n;
+ for (i = 1; i < m; ++i) {
+ idxMul[i] = idxMul[i-1] * sampleSize[i-1];
+ }
+
+ //----- BitsPerSample
+ if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
+ error(-1, "Function has missing or invalid BitsPerSample");
+ goto err2;
+ }
+ sampleBits = obj1.getInt();
+ sampleMul = 1.0 / (pow(2.0, (double)sampleBits) - 1);
+ obj1.free();
+
+ //----- Encode
+ if (dict->lookup("Encode", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2*m) {
+ for (i = 0; i < m; ++i) {
+ obj1.arrayGet(2*i, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function encode array");
+ goto err3;
+ }
+ encode[i][0] = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2*i+1, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function encode array");
+ goto err3;
+ }
+ encode[i][1] = obj2.getNum();
+ obj2.free();
+ }
+ } else {
+ for (i = 0; i < m; ++i) {
+ encode[i][0] = 0;
+ encode[i][1] = sampleSize[i] - 1;
+ }
+ }
+ obj1.free();
+ for (i = 0; i < m; ++i) {
+ inputMul[i] = (encode[i][1] - encode[i][0]) /
+ (domain[i][1] - domain[i][0]);
+ }
+
+ //----- Decode
+ if (dict->lookup("Decode", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2*n) {
+ for (i = 0; i < n; ++i) {
+ obj1.arrayGet(2*i, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function decode array");
+ goto err3;
+ }
+ decode[i][0] = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2*i+1, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function decode array");
+ goto err3;
+ }
+ decode[i][1] = obj2.getNum();
+ obj2.free();
+ }
+ } else {
+ for (i = 0; i < n; ++i) {
+ decode[i][0] = range[i][0];
+ decode[i][1] = range[i][1];
+ }
+ }
+ obj1.free();
+
+ //----- samples
+ nSamples = n;
+ for (i = 0; i < m; ++i)
+ nSamples *= sampleSize[i];
+ samples = (double *)gmallocn(nSamples, sizeof(double));
+ buf = 0;
+ bits = 0;
+ bitMask = (1 << sampleBits) - 1;
+ str->reset();
+ for (i = 0; i < nSamples; ++i) {
+ if (sampleBits == 8) {
+ s = str->getChar();
+ } else if (sampleBits == 16) {
+ s = str->getChar();
+ s = (s << 8) + str->getChar();
+ } else if (sampleBits == 32) {
+ s = str->getChar();
+ s = (s << 8) + str->getChar();
+ s = (s << 8) + str->getChar();
+ s = (s << 8) + str->getChar();
+ } else {
+ while (bits < sampleBits) {
+ buf = (buf << 8) | (str->getChar() & 0xff);
+ bits += 8;
+ }
+ s = (buf >> (bits - sampleBits)) & bitMask;
+ bits -= sampleBits;
+ }
+ samples[i] = (double)s * sampleMul;
+ }
+ str->close();
+
+ ok = gTrue;
+ return;
+
+ err3:
+ obj2.free();
+ err2:
+ obj1.free();
+ err1:
+ return;
+}
+
+SampledFunction::~SampledFunction() {
+ if (samples) {
+ gfree(samples);
+ }
+ if (sBuf) {
+ gfree(sBuf);
+ }
+}
+
+SampledFunction::SampledFunction(SampledFunction *func) {
+ memcpy(this, func, sizeof(SampledFunction));
+ samples = (double *)gmallocn(nSamples, sizeof(double));
+ memcpy(samples, func->samples, nSamples * sizeof(double));
+ sBuf = (double *)gmallocn(1 << m, sizeof(double));
+}
+
+void SampledFunction::transform(double *in, double *out) {
+ double x;
+ int e[funcMaxInputs][2];
+ double efrac0[funcMaxInputs];
+ double efrac1[funcMaxInputs];
+ int i, j, k, idx, t;
+
+ // map input values into sample array
+ for (i = 0; i < m; ++i) {
+ x = (in[i] - domain[i][0]) * inputMul[i] + encode[i][0];
+ if (x < 0) {
+ x = 0;
+ } else if (x > sampleSize[i] - 1) {
+ x = sampleSize[i] - 1;
+ }
+ e[i][0] = (int)x;
+ if ((e[i][1] = e[i][0] + 1) >= sampleSize[i]) {
+ // this happens if in[i] = domain[i][1]
+ e[i][1] = e[i][0];
+ }
+ efrac1[i] = x - e[i][0];
+ efrac0[i] = 1 - efrac1[i];
+ }
+
+ // for each output, do m-linear interpolation
+ for (i = 0; i < n; ++i) {
+
+ // pull 2^m values out of the sample array
+ for (j = 0; j < (1<<m); ++j) {
+ idx = i;
+ for (k = 0, t = j; k < m; ++k, t >>= 1) {
+ idx += idxMul[k] * (e[k][t & 1]);
+ }
+ sBuf[j] = samples[idx];
+ }
+
+ // do m sets of interpolations
+ for (j = 0, t = (1<<m); j < m; ++j, t >>= 1) {
+ for (k = 0; k < t; k += 2) {
+ sBuf[k >> 1] = efrac0[j] * sBuf[k] + efrac1[j] * sBuf[k+1];
+ }
+ }
+
+ // map output value to range
+ out[i] = sBuf[0] * (decode[i][1] - decode[i][0]) + decode[i][0];
+ if (out[i] < range[i][0]) {
+ out[i] = range[i][0];
+ } else if (out[i] > range[i][1]) {
+ out[i] = range[i][1];
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+// ExponentialFunction
+//------------------------------------------------------------------------
+
+ExponentialFunction::ExponentialFunction(Object * /*funcObj*/, Dict *dict) {
+ Object obj1, obj2;
+ int i;
+
+ ok = gFalse;
+
+ //----- initialize the generic stuff
+ if (!init(dict)) {
+ goto err1;
+ }
+ if (m != 1) {
+ error(-1, "Exponential function with more than one input");
+ goto err1;
+ }
+
+ //----- C0
+ if (dict->lookup("C0", &obj1)->isArray()) {
+ if (hasRange && obj1.arrayGetLength() != n) {
+ error(-1, "Function's C0 array is wrong length");
+ goto err2;
+ }
+ n = obj1.arrayGetLength();
+ for (i = 0; i < n; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function C0 array");
+ goto err3;
+ }
+ c0[i] = obj2.getNum();
+ obj2.free();
+ }
+ } else {
+ if (hasRange && n != 1) {
+ error(-1, "Function's C0 array is wrong length");
+ goto err2;
+ }
+ n = 1;
+ c0[0] = 0;
+ }
+ obj1.free();
+
+ //----- C1
+ if (dict->lookup("C1", &obj1)->isArray()) {
+ if (obj1.arrayGetLength() != n) {
+ error(-1, "Function's C1 array is wrong length");
+ goto err2;
+ }
+ for (i = 0; i < n; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function C1 array");
+ goto err3;
+ }
+ c1[i] = obj2.getNum();
+ obj2.free();
+ }
+ } else {
+ if (n != 1) {
+ error(-1, "Function's C1 array is wrong length");
+ goto err2;
+ }
+ c1[0] = 1;
+ }
+ obj1.free();
+
+ //----- N (exponent)
+ if (!dict->lookup("N", &obj1)->isNum()) {
+ error(-1, "Function has missing or invalid N");
+ goto err2;
+ }
+ e = obj1.getNum();
+ obj1.free();
+
+ ok = gTrue;
+ return;
+
+ err3:
+ obj2.free();
+ err2:
+ obj1.free();
+ err1:
+ return;
+}
+
+ExponentialFunction::~ExponentialFunction() {
+}
+
+ExponentialFunction::ExponentialFunction(ExponentialFunction *func) {
+ memcpy(this, func, sizeof(ExponentialFunction));
+}
+
+void ExponentialFunction::transform(double *in, double *out) {
+ double x;
+ int i;
+
+ if (in[0] < domain[0][0]) {
+ x = domain[0][0];
+ } else if (in[0] > domain[0][1]) {
+ x = domain[0][1];
+ } else {
+ x = in[0];
+ }
+ for (i = 0; i < n; ++i) {
+ out[i] = c0[i] + pow(x, e) * (c1[i] - c0[i]);
+ if (hasRange) {
+ if (out[i] < range[i][0]) {
+ out[i] = range[i][0];
+ } else if (out[i] > range[i][1]) {
+ out[i] = range[i][1];
+ }
+ }
+ }
+ return;
+}
+
+//------------------------------------------------------------------------
+// StitchingFunction
+//------------------------------------------------------------------------
+
+StitchingFunction::StitchingFunction(Object * /*funcObj*/, Dict *dict) {
+ Object obj1, obj2;
+ int i;
+
+ ok = gFalse;
+ funcs = NULL;
+ bounds = NULL;
+ encode = NULL;
+ scale = NULL;
+
+ //----- initialize the generic stuff
+ if (!init(dict)) {
+ goto err1;
+ }
+ if (m != 1) {
+ error(-1, "Stitching function with more than one input");
+ goto err1;
+ }
+
+ //----- Functions
+ if (!dict->lookup("Functions", &obj1)->isArray()) {
+ error(-1, "Missing 'Functions' entry in stitching function");
+ goto err1;
+ }
+ k = obj1.arrayGetLength();
+ funcs = (Function **)gmallocn(k, sizeof(Function *));
+ bounds = (double *)gmallocn(k + 1, sizeof(double));
+ encode = (double *)gmallocn(2 * k, sizeof(double));
+ scale = (double *)gmallocn(k, sizeof(double));
+ for (i = 0; i < k; ++i) {
+ funcs[i] = NULL;
+ }
+ for (i = 0; i < k; ++i) {
+ if (!(funcs[i] = Function::parse(obj1.arrayGet(i, &obj2)))) {
+ goto err2;
+ }
+ if (i > 0 && (funcs[i]->getInputSize() != 1 ||
+ funcs[i]->getOutputSize() != funcs[0]->getOutputSize())) {
+ error(-1, "Incompatible subfunctions in stitching function");
+ goto err2;
+ }
+ obj2.free();
+ }
+ obj1.free();
+
+ //----- Bounds
+ if (!dict->lookup("Bounds", &obj1)->isArray() ||
+ obj1.arrayGetLength() != k - 1) {
+ error(-1, "Missing or invalid 'Bounds' entry in stitching function");
+ goto err1;
+ }
+ bounds[0] = domain[0][0];
+ for (i = 1; i < k; ++i) {
+ if (!obj1.arrayGet(i - 1, &obj2)->isNum()) {
+ error(-1, "Invalid type in 'Bounds' array in stitching function");
+ goto err2;
+ }
+ bounds[i] = obj2.getNum();
+ obj2.free();
+ }
+ bounds[k] = domain[0][1];
+ obj1.free();
+
+ //----- Encode
+ if (!dict->lookup("Encode", &obj1)->isArray() ||
+ obj1.arrayGetLength() != 2 * k) {
+ error(-1, "Missing or invalid 'Encode' entry in stitching function");
+ goto err1;
+ }
+ for (i = 0; i < 2 * k; ++i) {
+ if (!obj1.arrayGet(i, &obj2)->isNum()) {
+ error(-1, "Invalid type in 'Encode' array in stitching function");
+ goto err2;
+ }
+ encode[i] = obj2.getNum();
+ obj2.free();
+ }
+ obj1.free();
+
+ //----- pre-compute the scale factors
+ for (i = 0; i < k; ++i) {
+ if (bounds[i] == bounds[i+1]) {
+ // avoid a divide-by-zero -- in this situation, function i will
+ // never be used anyway
+ scale[i] = 0;
+ } else {
+ scale[i] = (encode[2*i+1] - encode[2*i]) / (bounds[i+1] - bounds[i]);
+ }
+ }
+
+ ok = gTrue;
+ return;
+
+ err2:
+ obj2.free();
+ err1:
+ obj1.free();
+}
+
+StitchingFunction::StitchingFunction(StitchingFunction *func) {
+ int i;
+
+ k = func->k;
+ funcs = (Function **)gmallocn(k, sizeof(Function *));
+ for (i = 0; i < k; ++i) {
+ funcs[i] = func->funcs[i]->copy();
+ }
+ bounds = (double *)gmallocn(k + 1, sizeof(double));
+ memcpy(bounds, func->bounds, (k + 1) * sizeof(double));
+ encode = (double *)gmallocn(2 * k, sizeof(double));
+ memcpy(encode, func->encode, 2 * k * sizeof(double));
+ scale = (double *)gmallocn(k, sizeof(double));
+ memcpy(scale, func->scale, k * sizeof(double));
+ ok = gTrue;
+}
+
+StitchingFunction::~StitchingFunction() {
+ int i;
+
+ if (funcs) {
+ for (i = 0; i < k; ++i) {
+ if (funcs[i]) {
+ delete funcs[i];
+ }
+ }
+ }
+ gfree(funcs);
+ gfree(bounds);
+ gfree(encode);
+ gfree(scale);
+}
+
+void StitchingFunction::transform(double *in, double *out) {
+ double x;
+ int i;
+
+ if (in[0] < domain[0][0]) {
+ x = domain[0][0];
+ } else if (in[0] > domain[0][1]) {
+ x = domain[0][1];
+ } else {
+ x = in[0];
+ }
+ for (i = 0; i < k - 1; ++i) {
+ if (x < bounds[i+1]) {
+ break;
+ }
+ }
+ x = encode[2*i] + (x - bounds[i]) * scale[i];
+ funcs[i]->transform(&x, out);
+}
+
+//------------------------------------------------------------------------
+// PostScriptFunction
+//------------------------------------------------------------------------
+
+enum PSOp {
+ psOpAbs,
+ psOpAdd,
+ psOpAnd,
+ psOpAtan,
+ psOpBitshift,
+ psOpCeiling,
+ psOpCopy,
+ psOpCos,
+ psOpCvi,
+ psOpCvr,
+ psOpDiv,
+ psOpDup,
+ psOpEq,
+ psOpExch,
+ psOpExp,
+ psOpFalse,
+ psOpFloor,
+ psOpGe,
+ psOpGt,
+ psOpIdiv,
+ psOpIndex,
+ psOpLe,
+ psOpLn,
+ psOpLog,
+ psOpLt,
+ psOpMod,
+ psOpMul,
+ psOpNe,
+ psOpNeg,
+ psOpNot,
+ psOpOr,
+ psOpPop,
+ psOpRoll,
+ psOpRound,
+ psOpSin,
+ psOpSqrt,
+ psOpSub,
+ psOpTrue,
+ psOpTruncate,
+ psOpXor,
+ psOpIf,
+ psOpIfelse,
+ psOpReturn
+};
+
+// Note: 'if' and 'ifelse' are parsed separately.
+// The rest are listed here in alphabetical order.
+// The index in this table is equivalent to the entry in PSOp.
+char *psOpNames[] = {
+ "abs",
+ "add",
+ "and",
+ "atan",
+ "bitshift",
+ "ceiling",
+ "copy",
+ "cos",
+ "cvi",
+ "cvr",
+ "div",
+ "dup",
+ "eq",
+ "exch",
+ "exp",
+ "false",
+ "floor",
+ "ge",
+ "gt",
+ "idiv",
+ "index",
+ "le",
+ "ln",
+ "log",
+ "lt",
+ "mod",
+ "mul",
+ "ne",
+ "neg",
+ "not",
+ "or",
+ "pop",
+ "roll",
+ "round",
+ "sin",
+ "sqrt",
+ "sub",
+ "true",
+ "truncate",
+ "xor"
+};
+
+#define nPSOps (sizeof(psOpNames) / sizeof(char *))
+
+enum PSObjectType {
+ psBool,
+ psInt,
+ psReal,
+ psOperator,
+ psBlock
+};
+
+// In the code array, 'if'/'ifelse' operators take up three slots
+// plus space for the code in the subclause(s).
+//
+// +---------------------------------+
+// | psOperator: psOpIf / psOpIfelse |
+// +---------------------------------+
+// | psBlock: ptr=<A> |
+// +---------------------------------+
+// | psBlock: ptr=<B> |
+// +---------------------------------+
+// | if clause |
+// | ... |
+// | psOperator: psOpReturn |
+// +---------------------------------+
+// <A> | else clause |
+// | ... |
+// | psOperator: psOpReturn |
+// +---------------------------------+
+// <B> | ... |
+//
+// For 'if', pointer <A> is present in the code stream but unused.
+
+struct PSObject {
+ PSObjectType type;
+ union {
+ GBool booln; // boolean (stack only)
+ int intg; // integer (stack and code)
+ double real; // real (stack and code)
+ PSOp op; // operator (code only)
+ int blk; // if/ifelse block pointer (code only)
+ };
+};
+
+#define psStackSize 100
+
+class PSStack {
+public:
+
+ PSStack() { sp = psStackSize; }
+ void pushBool(GBool booln);
+ void pushInt(int intg);
+ void pushReal(double real);
+ GBool popBool();
+ int popInt();
+ double popNum();
+ GBool empty() { return sp == psStackSize; }
+ GBool topIsInt() { return sp < psStackSize && stack[sp].type == psInt; }
+ GBool topTwoAreInts()
+ { return sp < psStackSize - 1 &&
+ stack[sp].type == psInt &&
+ stack[sp+1].type == psInt; }
+ GBool topIsReal() { return sp < psStackSize && stack[sp].type == psReal; }
+ GBool topTwoAreNums()
+ { return sp < psStackSize - 1 &&
+ (stack[sp].type == psInt || stack[sp].type == psReal) &&
+ (stack[sp+1].type == psInt || stack[sp+1].type == psReal); }
+ void copy(int n);
+ void roll(int n, int j);
+ void index(int i);
+ void pop();
+
+private:
+
+ GBool checkOverflow(int n = 1);
+ GBool checkUnderflow();
+ GBool checkType(PSObjectType t1, PSObjectType t2);
+
+ PSObject stack[psStackSize];
+ int sp;
+};
+
+GBool PSStack::checkOverflow(int n) {
+ if (sp - n < 0) {
+ error(-1, "Stack overflow in PostScript function");
+ return gFalse;
+ }
+ return gTrue;
+}
+
+GBool PSStack::checkUnderflow() {
+ if (sp == psStackSize) {
+ error(-1, "Stack underflow in PostScript function");
+ return gFalse;
+ }
+ return gTrue;
+}
+
+GBool PSStack::checkType(PSObjectType t1, PSObjectType t2) {
+ if (stack[sp].type != t1 && stack[sp].type != t2) {
+ error(-1, "Type mismatch in PostScript function");
+ return gFalse;
+ }
+ return gTrue;
+}
+
+void PSStack::pushBool(GBool booln) {
+ if (checkOverflow()) {
+ stack[--sp].type = psBool;
+ stack[sp].booln = booln;
+ }
+}
+
+void PSStack::pushInt(int intg) {
+ if (checkOverflow()) {
+ stack[--sp].type = psInt;
+ stack[sp].intg = intg;
+ }
+}
+
+void PSStack::pushReal(double real) {
+ if (checkOverflow()) {
+ stack[--sp].type = psReal;
+ stack[sp].real = real;
+ }
+}
+
+GBool PSStack::popBool() {
+ if (checkUnderflow() && checkType(psBool, psBool)) {
+ return stack[sp++].booln;
+ }
+ return gFalse;
+}
+
+int PSStack::popInt() {
+ if (checkUnderflow() && checkType(psInt, psInt)) {
+ return stack[sp++].intg;
+ }
+ return 0;
+}
+
+double PSStack::popNum() {
+ double ret;
+
+ if (checkUnderflow() && checkType(psInt, psReal)) {
+ ret = (stack[sp].type == psInt) ? (double)stack[sp].intg : stack[sp].real;
+ ++sp;
+ return ret;
+ }
+ return 0;
+}
+
+void PSStack::copy(int n) {
+ int i;
+
+ if (sp + n > psStackSize) {
+ error(-1, "Stack underflow in PostScript function");
+ return;
+ }
+ if (!checkOverflow(n)) {
+ return;
+ }
+ for (i = sp + n - 1; i >= sp; --i) {
+ stack[i - n] = stack[i];
+ }
+ sp -= n;
+}
+
+void PSStack::roll(int n, int j) {
+ PSObject obj;
+ int i, k;
+
+ if (j >= 0) {
+ j %= n;
+ } else {
+ j = -j % n;
+ if (j != 0) {
+ j = n - j;
+ }
+ }
+ if (n <= 0 || j == 0) {
+ return;
+ }
+ for (i = 0; i < j; ++i) {
+ obj = stack[sp];
+ for (k = sp; k < sp + n - 1; ++k) {
+ stack[k] = stack[k+1];
+ }
+ stack[sp + n - 1] = obj;
+ }
+}
+
+void PSStack::index(int i) {
+ if (!checkOverflow()) {
+ return;
+ }
+ --sp;
+ stack[sp] = stack[sp + 1 + i];
+}
+
+void PSStack::pop() {
+ if (!checkUnderflow()) {
+ return;
+ }
+ ++sp;
+}
+
+PostScriptFunction::PostScriptFunction(Object *funcObj, Dict *dict) {
+ Stream *str;
+ int codePtr;
+ GString *tok;
+
+ code = NULL;
+ codeSize = 0;
+ ok = gFalse;
+
+ //----- initialize the generic stuff
+ if (!init(dict)) {
+ goto err1;
+ }
+ if (!hasRange) {
+ error(-1, "Type 4 function is missing range");
+ goto err1;
+ }
+
+ //----- get the stream
+ if (!funcObj->isStream()) {
+ error(-1, "Type 4 function isn't a stream");
+ goto err1;
+ }
+ str = funcObj->getStream();
+
+ //----- parse the function
+ codeString = new GString();
+ str->reset();
+ if (!(tok = getToken(str)) || tok->cmp("{")) {
+ error(-1, "Expected '{' at start of PostScript function");
+ if (tok) {
+ delete tok;
+ }
+ goto err1;
+ }
+ delete tok;
+ codePtr = 0;
+ if (!parseCode(str, &codePtr)) {
+ goto err2;
+ }
+ str->close();
+
+ ok = gTrue;
+
+ err2:
+ str->close();
+ err1:
+ return;
+}
+
+PostScriptFunction::PostScriptFunction(PostScriptFunction *func) {
+ memcpy(this, func, sizeof(PostScriptFunction));
+ code = (PSObject *)gmallocn(codeSize, sizeof(PSObject));
+ memcpy(code, func->code, codeSize * sizeof(PSObject));
+ codeString = func->codeString->copy();
+}
+
+PostScriptFunction::~PostScriptFunction() {
+ gfree(code);
+ delete codeString;
+}
+
+void PostScriptFunction::transform(double *in, double *out) {
+ PSStack *stack;
+ int i;
+
+ stack = new PSStack();
+ for (i = 0; i < m; ++i) {
+ //~ may need to check for integers here
+ stack->pushReal(in[i]);
+ }
+ exec(stack, 0);
+ for (i = n - 1; i >= 0; --i) {
+ out[i] = stack->popNum();
+ if (out[i] < range[i][0]) {
+ out[i] = range[i][0];
+ } else if (out[i] > range[i][1]) {
+ out[i] = range[i][1];
+ }
+ }
+ // if (!stack->empty()) {
+ // error(-1, "Extra values on stack at end of PostScript function");
+ // }
+ delete stack;
+}
+
+GBool PostScriptFunction::parseCode(Stream *str, int *codePtr) {
+ GString *tok;
+ char *p;
+ GBool isReal;
+ int opPtr, elsePtr;
+ int a, b, mid, cmp;
+
+ while (1) {
+ if (!(tok = getToken(str))) {
+ error(-1, "Unexpected end of PostScript function stream");
+ return gFalse;
+ }
+ p = tok->getCString();
+ if (isdigit(*p) || *p == '.' || *p == '-') {
+ isReal = gFalse;
+ for (++p; *p; ++p) {
+ if (*p == '.') {
+ isReal = gTrue;
+ break;
+ }
+ }
+ resizeCode(*codePtr);
+ if (isReal) {
+ code[*codePtr].type = psReal;
+ code[*codePtr].real = atof(tok->getCString());
+ } else {
+ code[*codePtr].type = psInt;
+ code[*codePtr].intg = atoi(tok->getCString());
+ }
+ ++*codePtr;
+ delete tok;
+ } else if (!tok->cmp("{")) {
+ delete tok;
+ opPtr = *codePtr;
+ *codePtr += 3;
+ resizeCode(opPtr + 2);
+ if (!parseCode(str, codePtr)) {
+ return gFalse;
+ }
+ if (!(tok = getToken(str))) {
+ error(-1, "Unexpected end of PostScript function stream");
+ return gFalse;
+ }
+ if (!tok->cmp("{")) {
+ elsePtr = *codePtr;
+ if (!parseCode(str, codePtr)) {
+ return gFalse;
+ }
+ delete tok;
+ if (!(tok = getToken(str))) {
+ error(-1, "Unexpected end of PostScript function stream");
+ return gFalse;
+ }
+ } else {
+ elsePtr = -1;
+ }
+ if (!tok->cmp("if")) {
+ if (elsePtr >= 0) {
+ error(-1, "Got 'if' operator with two blocks in PostScript function");
+ return gFalse;
+ }
+ code[opPtr].type = psOperator;
+ code[opPtr].op = psOpIf;
+ code[opPtr+2].type = psBlock;
+ code[opPtr+2].blk = *codePtr;
+ } else if (!tok->cmp("ifelse")) {
+ if (elsePtr < 0) {
+ error(-1, "Got 'ifelse' operator with one blocks in PostScript function");
+ return gFalse;
+ }
+ code[opPtr].type = psOperator;
+ code[opPtr].op = psOpIfelse;
+ code[opPtr+1].type = psBlock;
+ code[opPtr+1].blk = elsePtr;
+ code[opPtr+2].type = psBlock;
+ code[opPtr+2].blk = *codePtr;
+ } else {
+ error(-1, "Expected if/ifelse operator in PostScript function");
+ delete tok;
+ return gFalse;
+ }
+ delete tok;
+ } else if (!tok->cmp("}")) {
+ delete tok;
+ resizeCode(*codePtr);
+ code[*codePtr].type = psOperator;
+ code[*codePtr].op = psOpReturn;
+ ++*codePtr;
+ break;
+ } else {
+ a = -1;
+ b = nPSOps;
+ // invariant: psOpNames[a] < tok < psOpNames[b]
+ while (b - a > 1) {
+ mid = (a + b) / 2;
+ cmp = tok->cmp(psOpNames[mid]);
+ if (cmp > 0) {
+ a = mid;
+ } else if (cmp < 0) {
+ b = mid;
+ } else {
+ a = b = mid;
+ }
+ }
+ if (cmp != 0) {
+ error(-1, "Unknown operator '%s' in PostScript function",
+ tok->getCString());
+ delete tok;
+ return gFalse;
+ }
+ delete tok;
+ resizeCode(*codePtr);
+ code[*codePtr].type = psOperator;
+ code[*codePtr].op = (PSOp)a;
+ ++*codePtr;
+ }
+ }
+ return gTrue;
+}
+
+GString *PostScriptFunction::getToken(Stream *str) {
+ GString *s;
+ int c;
+ GBool comment;
+
+ s = new GString();
+ comment = gFalse;
+ while (1) {
+ if ((c = str->getChar()) == EOF) {
+ break;
+ }
+ codeString->append(c);
+ if (comment) {
+ if (c == '\x0a' || c == '\x0d') {
+ comment = gFalse;
+ }
+ } else if (c == '%') {
+ comment = gTrue;
+ } else if (!isspace(c)) {
+ break;
+ }
+ }
+ if (c == '{' || c == '}') {
+ s->append((char)c);
+ } else if (isdigit(c) || c == '.' || c == '-') {
+ while (1) {
+ s->append((char)c);
+ c = str->lookChar();
+ if (c == EOF || !(isdigit(c) || c == '.' || c == '-')) {
+ break;
+ }
+ str->getChar();
+ codeString->append(c);
+ }
+ } else {
+ while (1) {
+ s->append((char)c);
+ c = str->lookChar();
+ if (c == EOF || !isalnum(c)) {
+ break;
+ }
+ str->getChar();
+ codeString->append(c);
+ }
+ }
+ return s;
+}
+
+void PostScriptFunction::resizeCode(int newSize) {
+ if (newSize >= codeSize) {
+ codeSize += 64;
+ code = (PSObject *)greallocn(code, codeSize, sizeof(PSObject));
+ }
+}
+
+void PostScriptFunction::exec(PSStack *stack, int codePtr) {
+ int i1, i2;
+ double r1, r2, result;
+ GBool b1, b2;
+
+ while (1) {
+ switch (code[codePtr].type) {
+ case psInt:
+ stack->pushInt(code[codePtr++].intg);
+ break;
+ case psReal:
+ stack->pushReal(code[codePtr++].real);
+ break;
+ case psOperator:
+ switch (code[codePtr++].op) {
+ case psOpAbs:
+ if (stack->topIsInt()) {
+ stack->pushInt(abs(stack->popInt()));
+ } else {
+ stack->pushReal(fabs(stack->popNum()));
+ }
+ break;
+ case psOpAdd:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushInt(i1 + i2);
+ } else {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushReal(r1 + r2);
+ }
+ break;
+ case psOpAnd:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushInt(i1 & i2);
+ } else {
+ b2 = stack->popBool();
+ b1 = stack->popBool();
+ stack->pushBool(b1 && b2);
+ }
+ break;
+ case psOpAtan:
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ result = atan2(r1, r2) * 180.0 / M_PI;
+ if (result < 0) result += 360.0;
+ stack->pushReal(result);
+ break;
+ case psOpBitshift:
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ if (i2 > 0) {
+ stack->pushInt(i1 << i2);
+ } else if (i2 < 0) {
+ stack->pushInt((int)((Guint)i1 >> i2));
+ } else {
+ stack->pushInt(i1);
+ }
+ break;
+ case psOpCeiling:
+ if (!stack->topIsInt()) {
+ stack->pushReal(ceil(stack->popNum()));
+ }
+ break;
+ case psOpCopy:
+ stack->copy(stack->popInt());
+ break;
+ case psOpCos:
+ stack->pushReal(cos(stack->popNum() * M_PI / 180.0));
+ break;
+ case psOpCvi:
+ if (!stack->topIsInt()) {
+ stack->pushInt((int)stack->popNum());
+ }
+ break;
+ case psOpCvr:
+ if (!stack->topIsReal()) {
+ stack->pushReal(stack->popNum());
+ }
+ break;
+ case psOpDiv:
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushReal(r1 / r2);
+ break;
+ case psOpDup:
+ stack->copy(1);
+ break;
+ case psOpEq:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushBool(i1 == i2);
+ } else if (stack->topTwoAreNums()) {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushBool(r1 == r2);
+ } else {
+ b2 = stack->popBool();
+ b1 = stack->popBool();
+ stack->pushBool(b1 == b2);
+ }
+ break;
+ case psOpExch:
+ stack->roll(2, 1);
+ break;
+ case psOpExp:
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushReal(pow(r1, r2));
+ break;
+ case psOpFalse:
+ stack->pushBool(gFalse);
+ break;
+ case psOpFloor:
+ if (!stack->topIsInt()) {
+ stack->pushReal(floor(stack->popNum()));
+ }
+ break;
+ case psOpGe:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushBool(i1 >= i2);
+ } else {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushBool(r1 >= r2);
+ }
+ break;
+ case psOpGt:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushBool(i1 > i2);
+ } else {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushBool(r1 > r2);
+ }
+ break;
+ case psOpIdiv:
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushInt(i1 / i2);
+ break;
+ case psOpIndex:
+ stack->index(stack->popInt());
+ break;
+ case psOpLe:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushBool(i1 <= i2);
+ } else {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushBool(r1 <= r2);
+ }
+ break;
+ case psOpLn:
+ stack->pushReal(log(stack->popNum()));
+ break;
+ case psOpLog:
+ stack->pushReal(log10(stack->popNum()));
+ break;
+ case psOpLt:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushBool(i1 < i2);
+ } else {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushBool(r1 < r2);
+ }
+ break;
+ case psOpMod:
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushInt(i1 % i2);
+ break;
+ case psOpMul:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ //~ should check for out-of-range, and push a real instead
+ stack->pushInt(i1 * i2);
+ } else {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushReal(r1 * r2);
+ }
+ break;
+ case psOpNe:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushBool(i1 != i2);
+ } else if (stack->topTwoAreNums()) {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushBool(r1 != r2);
+ } else {
+ b2 = stack->popBool();
+ b1 = stack->popBool();
+ stack->pushBool(b1 != b2);
+ }
+ break;
+ case psOpNeg:
+ if (stack->topIsInt()) {
+ stack->pushInt(-stack->popInt());
+ } else {
+ stack->pushReal(-stack->popNum());
+ }
+ break;
+ case psOpNot:
+ if (stack->topIsInt()) {
+ stack->pushInt(~stack->popInt());
+ } else {
+ stack->pushBool(!stack->popBool());
+ }
+ break;
+ case psOpOr:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushInt(i1 | i2);
+ } else {
+ b2 = stack->popBool();
+ b1 = stack->popBool();
+ stack->pushBool(b1 || b2);
+ }
+ break;
+ case psOpPop:
+ stack->pop();
+ break;
+ case psOpRoll:
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->roll(i1, i2);
+ break;
+ case psOpRound:
+ if (!stack->topIsInt()) {
+ r1 = stack->popNum();
+ stack->pushReal((r1 >= 0) ? floor(r1 + 0.5) : ceil(r1 - 0.5));
+ }
+ break;
+ case psOpSin:
+ stack->pushReal(sin(stack->popNum() * M_PI / 180.0));
+ break;
+ case psOpSqrt:
+ stack->pushReal(sqrt(stack->popNum()));
+ break;
+ case psOpSub:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushInt(i1 - i2);
+ } else {
+ r2 = stack->popNum();
+ r1 = stack->popNum();
+ stack->pushReal(r1 - r2);
+ }
+ break;
+ case psOpTrue:
+ stack->pushBool(gTrue);
+ break;
+ case psOpTruncate:
+ if (!stack->topIsInt()) {
+ r1 = stack->popNum();
+ stack->pushReal((r1 >= 0) ? floor(r1) : ceil(r1));
+ }
+ break;
+ case psOpXor:
+ if (stack->topTwoAreInts()) {
+ i2 = stack->popInt();
+ i1 = stack->popInt();
+ stack->pushInt(i1 ^ i2);
+ } else {
+ b2 = stack->popBool();
+ b1 = stack->popBool();
+ stack->pushBool(b1 ^ b2);
+ }
+ break;
+ case psOpIf:
+ b1 = stack->popBool();
+ if (b1) {
+ exec(stack, codePtr + 2);
+ }
+ codePtr = code[codePtr + 1].blk;
+ break;
+ case psOpIfelse:
+ b1 = stack->popBool();
+ if (b1) {
+ exec(stack, codePtr + 2);
+ } else {
+ exec(stack, code[codePtr].blk);
+ }
+ codePtr = code[codePtr + 1].blk;
+ break;
+ case psOpReturn:
+ return;
+ }
+ break;
+ default:
+ error(-1, "Internal: bad object in PostScript function code");
+ break;
+ }
+ }
+}
diff --git a/kpdf/xpdf/xpdf/Function.h b/kpdf/xpdf/xpdf/Function.h
new file mode 100644
index 00000000..334a4390
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Function.h
@@ -0,0 +1,229 @@
+//========================================================================
+//
+// Function.h
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef FUNCTION_H
+#define FUNCTION_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "Object.h"
+
+class Dict;
+class Stream;
+struct PSObject;
+class PSStack;
+
+//------------------------------------------------------------------------
+// Function
+//------------------------------------------------------------------------
+
+#define funcMaxInputs 32
+#define funcMaxOutputs 32
+#define sampledFuncMaxInputs 16
+
+class Function {
+public:
+
+ Function();
+
+ virtual ~Function();
+
+ // Construct a function. Returns NULL if unsuccessful.
+ static Function *parse(Object *funcObj);
+
+ // Initialize the entries common to all function types.
+ GBool init(Dict *dict);
+
+ virtual Function *copy() = 0;
+
+ // Return the function type:
+ // -1 : identity
+ // 0 : sampled
+ // 2 : exponential
+ // 3 : stitching
+ // 4 : PostScript
+ virtual int getType() = 0;
+
+ // Return size of input and output tuples.
+ int getInputSize() { return m; }
+ int getOutputSize() { return n; }
+
+ double getDomainMin(int i) { return domain[i][0]; }
+ double getDomainMax(int i) { return domain[i][1]; }
+ double getRangeMin(int i) { return range[i][0]; }
+ double getRangeMax(int i) { return range[i][1]; }
+ GBool getHasRange() { return hasRange; }
+
+ // Transform an input tuple into an output tuple.
+ virtual void transform(double *in, double *out) = 0;
+
+ virtual GBool isOk() = 0;
+
+protected:
+
+ int m, n; // size of input and output tuples
+ double // min and max values for function domain
+ domain[funcMaxInputs][2];
+ double // min and max values for function range
+ range[funcMaxOutputs][2];
+ GBool hasRange; // set if range is defined
+};
+
+//------------------------------------------------------------------------
+// IdentityFunction
+//------------------------------------------------------------------------
+
+class IdentityFunction: public Function {
+public:
+
+ IdentityFunction();
+ virtual ~IdentityFunction();
+ virtual Function *copy() { return new IdentityFunction(); }
+ virtual int getType() { return -1; }
+ virtual void transform(double *in, double *out);
+ virtual GBool isOk() { return gTrue; }
+
+private:
+};
+
+//------------------------------------------------------------------------
+// SampledFunction
+//------------------------------------------------------------------------
+
+class SampledFunction: public Function {
+public:
+
+ SampledFunction(Object *funcObj, Dict *dict);
+ virtual ~SampledFunction();
+ virtual Function *copy() { return new SampledFunction(this); }
+ virtual int getType() { return 0; }
+ virtual void transform(double *in, double *out);
+ virtual GBool isOk() { return ok; }
+
+ int getSampleSize(int i) { return sampleSize[i]; }
+ double getEncodeMin(int i) { return encode[i][0]; }
+ double getEncodeMax(int i) { return encode[i][1]; }
+ double getDecodeMin(int i) { return decode[i][0]; }
+ double getDecodeMax(int i) { return decode[i][1]; }
+ double *getSamples() { return samples; }
+
+private:
+
+ SampledFunction(SampledFunction *func);
+
+ int // number of samples for each domain element
+ sampleSize[funcMaxInputs];
+ double // min and max values for domain encoder
+ encode[funcMaxInputs][2];
+ double // min and max values for range decoder
+ decode[funcMaxOutputs][2];
+ double // input multipliers
+ inputMul[funcMaxInputs];
+ int idxMul[funcMaxInputs]; // sample array index multipliers
+ double *samples; // the samples
+ int nSamples; // size of the samples array
+ double *sBuf; // buffer for the transform function
+ GBool ok;
+};
+
+//------------------------------------------------------------------------
+// ExponentialFunction
+//------------------------------------------------------------------------
+
+class ExponentialFunction: public Function {
+public:
+
+ ExponentialFunction(Object *funcObj, Dict *dict);
+ virtual ~ExponentialFunction();
+ virtual Function *copy() { return new ExponentialFunction(this); }
+ virtual int getType() { return 2; }
+ virtual void transform(double *in, double *out);
+ virtual GBool isOk() { return ok; }
+
+ double *getC0() { return c0; }
+ double *getC1() { return c1; }
+ double getE() { return e; }
+
+private:
+
+ ExponentialFunction(ExponentialFunction *func);
+
+ double c0[funcMaxOutputs];
+ double c1[funcMaxOutputs];
+ double e;
+ GBool ok;
+};
+
+//------------------------------------------------------------------------
+// StitchingFunction
+//------------------------------------------------------------------------
+
+class StitchingFunction: public Function {
+public:
+
+ StitchingFunction(Object *funcObj, Dict *dict);
+ virtual ~StitchingFunction();
+ virtual Function *copy() { return new StitchingFunction(this); }
+ virtual int getType() { return 3; }
+ virtual void transform(double *in, double *out);
+ virtual GBool isOk() { return ok; }
+
+ int getNumFuncs() { return k; }
+ Function *getFunc(int i) { return funcs[i]; }
+ double *getBounds() { return bounds; }
+ double *getEncode() { return encode; }
+ double *getScale() { return scale; }
+
+private:
+
+ StitchingFunction(StitchingFunction *func);
+
+ int k;
+ Function **funcs;
+ double *bounds;
+ double *encode;
+ double *scale;
+ GBool ok;
+};
+
+//------------------------------------------------------------------------
+// PostScriptFunction
+//------------------------------------------------------------------------
+
+class PostScriptFunction: public Function {
+public:
+
+ PostScriptFunction(Object *funcObj, Dict *dict);
+ virtual ~PostScriptFunction();
+ virtual Function *copy() { return new PostScriptFunction(this); }
+ virtual int getType() { return 4; }
+ virtual void transform(double *in, double *out);
+ virtual GBool isOk() { return ok; }
+
+ GString *getCodeString() { return codeString; }
+
+private:
+
+ PostScriptFunction(PostScriptFunction *func);
+ GBool parseCode(Stream *str, int *codePtr);
+ GString *getToken(Stream *str);
+ void resizeCode(int newSize);
+ void exec(PSStack *stack, int codePtr);
+
+ GString *codeString;
+ PSObject *code;
+ int codeSize;
+ GBool ok;
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/Gfx.cc b/kpdf/xpdf/xpdf/Gfx.cc
new file mode 100644
index 00000000..b37dcb54
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Gfx.cc
@@ -0,0 +1,4187 @@
+//========================================================================
+//
+// Gfx.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <string.h>
+#include <math.h>
+#include "gmem.h"
+#include "GlobalParams.h"
+#include "CharTypes.h"
+#include "Object.h"
+#include "Array.h"
+#include "Dict.h"
+#include "Stream.h"
+#include "Lexer.h"
+#include "Parser.h"
+#include "GfxFont.h"
+#include "GfxState.h"
+#include "OutputDev.h"
+#include "Page.h"
+#include "Annot.h"
+#include "Error.h"
+#include "Gfx.h"
+
+// the MSVC math.h doesn't define this
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+//------------------------------------------------------------------------
+// constants
+//------------------------------------------------------------------------
+
+// Max recursive depth for a function shading fill.
+#define functionMaxDepth 6
+
+// Max delta allowed in any color component for a function shading fill.
+#define functionColorDelta (dblToCol(1 / 256.0))
+
+// Max number of splits along the t axis for an axial shading fill.
+#define axialMaxSplits 256
+
+// Max delta allowed in any color component for an axial shading fill.
+#define axialColorDelta (dblToCol(1 / 256.0))
+
+// Max number of splits along the t axis for a radial shading fill.
+#define radialMaxSplits 256
+
+// Max delta allowed in any color component for a radial shading fill.
+#define radialColorDelta (dblToCol(1 / 256.0))
+
+// Max recursive depth for a Gouraud triangle shading fill.
+#define gouraudMaxDepth 6
+
+// Max delta allowed in any color component for a Gouraud triangle
+// shading fill.
+#define gouraudColorDelta (dblToCol(1 / 256.0))
+
+// Max recursive depth for a patch mesh shading fill.
+#define patchMaxDepth 6
+
+// Max delta allowed in any color component for a patch mesh shading
+// fill.
+#define patchColorDelta (dblToCol(1 / 256.0))
+
+//------------------------------------------------------------------------
+// Operator table
+//------------------------------------------------------------------------
+
+#ifdef WIN32 // this works around a bug in the VC7 compiler
+# pragma optimize("",off)
+#endif
+
+Operator Gfx::opTab[] = {
+ {"\"", 3, {tchkNum, tchkNum, tchkString},
+ &Gfx::opMoveSetShowText},
+ {"'", 1, {tchkString},
+ &Gfx::opMoveShowText},
+ {"B", 0, {tchkNone},
+ &Gfx::opFillStroke},
+ {"B*", 0, {tchkNone},
+ &Gfx::opEOFillStroke},
+ {"BDC", 2, {tchkName, tchkProps},
+ &Gfx::opBeginMarkedContent},
+ {"BI", 0, {tchkNone},
+ &Gfx::opBeginImage},
+ {"BMC", 1, {tchkName},
+ &Gfx::opBeginMarkedContent},
+ {"BT", 0, {tchkNone},
+ &Gfx::opBeginText},
+ {"BX", 0, {tchkNone},
+ &Gfx::opBeginIgnoreUndef},
+ {"CS", 1, {tchkName},
+ &Gfx::opSetStrokeColorSpace},
+ {"DP", 2, {tchkName, tchkProps},
+ &Gfx::opMarkPoint},
+ {"Do", 1, {tchkName},
+ &Gfx::opXObject},
+ {"EI", 0, {tchkNone},
+ &Gfx::opEndImage},
+ {"EMC", 0, {tchkNone},
+ &Gfx::opEndMarkedContent},
+ {"ET", 0, {tchkNone},
+ &Gfx::opEndText},
+ {"EX", 0, {tchkNone},
+ &Gfx::opEndIgnoreUndef},
+ {"F", 0, {tchkNone},
+ &Gfx::opFill},
+ {"G", 1, {tchkNum},
+ &Gfx::opSetStrokeGray},
+ {"ID", 0, {tchkNone},
+ &Gfx::opImageData},
+ {"J", 1, {tchkInt},
+ &Gfx::opSetLineCap},
+ {"K", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
+ &Gfx::opSetStrokeCMYKColor},
+ {"M", 1, {tchkNum},
+ &Gfx::opSetMiterLimit},
+ {"MP", 1, {tchkName},
+ &Gfx::opMarkPoint},
+ {"Q", 0, {tchkNone},
+ &Gfx::opRestore},
+ {"RG", 3, {tchkNum, tchkNum, tchkNum},
+ &Gfx::opSetStrokeRGBColor},
+ {"S", 0, {tchkNone},
+ &Gfx::opStroke},
+ {"SC", -4, {tchkNum, tchkNum, tchkNum, tchkNum},
+ &Gfx::opSetStrokeColor},
+ {"SCN", -33, {tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN},
+ &Gfx::opSetStrokeColorN},
+ {"T*", 0, {tchkNone},
+ &Gfx::opTextNextLine},
+ {"TD", 2, {tchkNum, tchkNum},
+ &Gfx::opTextMoveSet},
+ {"TJ", 1, {tchkArray},
+ &Gfx::opShowSpaceText},
+ {"TL", 1, {tchkNum},
+ &Gfx::opSetTextLeading},
+ {"Tc", 1, {tchkNum},
+ &Gfx::opSetCharSpacing},
+ {"Td", 2, {tchkNum, tchkNum},
+ &Gfx::opTextMove},
+ {"Tf", 2, {tchkName, tchkNum},
+ &Gfx::opSetFont},
+ {"Tj", 1, {tchkString},
+ &Gfx::opShowText},
+ {"Tm", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
+ tchkNum, tchkNum},
+ &Gfx::opSetTextMatrix},
+ {"Tr", 1, {tchkInt},
+ &Gfx::opSetTextRender},
+ {"Ts", 1, {tchkNum},
+ &Gfx::opSetTextRise},
+ {"Tw", 1, {tchkNum},
+ &Gfx::opSetWordSpacing},
+ {"Tz", 1, {tchkNum},
+ &Gfx::opSetHorizScaling},
+ {"W", 0, {tchkNone},
+ &Gfx::opClip},
+ {"W*", 0, {tchkNone},
+ &Gfx::opEOClip},
+ {"b", 0, {tchkNone},
+ &Gfx::opCloseFillStroke},
+ {"b*", 0, {tchkNone},
+ &Gfx::opCloseEOFillStroke},
+ {"c", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
+ tchkNum, tchkNum},
+ &Gfx::opCurveTo},
+ {"cm", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
+ tchkNum, tchkNum},
+ &Gfx::opConcat},
+ {"cs", 1, {tchkName},
+ &Gfx::opSetFillColorSpace},
+ {"d", 2, {tchkArray, tchkNum},
+ &Gfx::opSetDash},
+ {"d0", 2, {tchkNum, tchkNum},
+ &Gfx::opSetCharWidth},
+ {"d1", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
+ tchkNum, tchkNum},
+ &Gfx::opSetCacheDevice},
+ {"f", 0, {tchkNone},
+ &Gfx::opFill},
+ {"f*", 0, {tchkNone},
+ &Gfx::opEOFill},
+ {"g", 1, {tchkNum},
+ &Gfx::opSetFillGray},
+ {"gs", 1, {tchkName},
+ &Gfx::opSetExtGState},
+ {"h", 0, {tchkNone},
+ &Gfx::opClosePath},
+ {"i", 1, {tchkNum},
+ &Gfx::opSetFlat},
+ {"j", 1, {tchkInt},
+ &Gfx::opSetLineJoin},
+ {"k", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
+ &Gfx::opSetFillCMYKColor},
+ {"l", 2, {tchkNum, tchkNum},
+ &Gfx::opLineTo},
+ {"m", 2, {tchkNum, tchkNum},
+ &Gfx::opMoveTo},
+ {"n", 0, {tchkNone},
+ &Gfx::opEndPath},
+ {"q", 0, {tchkNone},
+ &Gfx::opSave},
+ {"re", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
+ &Gfx::opRectangle},
+ {"rg", 3, {tchkNum, tchkNum, tchkNum},
+ &Gfx::opSetFillRGBColor},
+ {"ri", 1, {tchkName},
+ &Gfx::opSetRenderingIntent},
+ {"s", 0, {tchkNone},
+ &Gfx::opCloseStroke},
+ {"sc", -4, {tchkNum, tchkNum, tchkNum, tchkNum},
+ &Gfx::opSetFillColor},
+ {"scn", -33, {tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN, tchkSCN, tchkSCN, tchkSCN,
+ tchkSCN},
+ &Gfx::opSetFillColorN},
+ {"sh", 1, {tchkName},
+ &Gfx::opShFill},
+ {"v", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
+ &Gfx::opCurveTo1},
+ {"w", 1, {tchkNum},
+ &Gfx::opSetLineWidth},
+ {"y", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
+ &Gfx::opCurveTo2},
+};
+
+#ifdef WIN32 // this works around a bug in the VC7 compiler
+# pragma optimize("",on)
+#endif
+
+#define numOps (sizeof(opTab) / sizeof(Operator))
+
+//------------------------------------------------------------------------
+// GfxResources
+//------------------------------------------------------------------------
+
+GfxResources::GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA) {
+ Object obj1, obj2;
+ Ref r;
+
+ if (resDict) {
+
+ // build font dictionary
+ fonts = NULL;
+ resDict->lookupNF("Font", &obj1);
+ if (obj1.isRef()) {
+ obj1.fetch(xref, &obj2);
+ if (obj2.isDict()) {
+ r = obj1.getRef();
+ fonts = new GfxFontDict(xref, &r, obj2.getDict());
+ }
+ obj2.free();
+ } else if (obj1.isDict()) {
+ fonts = new GfxFontDict(xref, NULL, obj1.getDict());
+ }
+ obj1.free();
+
+ // get XObject dictionary
+ resDict->lookup("XObject", &xObjDict);
+
+ // get color space dictionary
+ resDict->lookup("ColorSpace", &colorSpaceDict);
+
+ // get pattern dictionary
+ resDict->lookup("Pattern", &patternDict);
+
+ // get shading dictionary
+ resDict->lookup("Shading", &shadingDict);
+
+ // get graphics state parameter dictionary
+ resDict->lookup("ExtGState", &gStateDict);
+
+ } else {
+ fonts = NULL;
+ xObjDict.initNull();
+ colorSpaceDict.initNull();
+ patternDict.initNull();
+ shadingDict.initNull();
+ gStateDict.initNull();
+ }
+
+ next = nextA;
+}
+
+GfxResources::~GfxResources() {
+ if (fonts) {
+ delete fonts;
+ }
+ xObjDict.free();
+ colorSpaceDict.free();
+ patternDict.free();
+ shadingDict.free();
+ gStateDict.free();
+}
+
+GfxFont *GfxResources::lookupFont(char *name) {
+ GfxFont *font;
+ GfxResources *resPtr;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->fonts) {
+ if ((font = resPtr->fonts->lookup(name)))
+ return font;
+ }
+ }
+ error(-1, "Unknown font tag '%s'", name);
+ return NULL;
+}
+
+GBool GfxResources::lookupXObject(char *name, Object *obj) {
+ GfxResources *resPtr;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->xObjDict.isDict()) {
+ if (!resPtr->xObjDict.dictLookup(name, obj)->isNull())
+ return gTrue;
+ obj->free();
+ }
+ }
+ error(-1, "XObject '%s' is unknown", name);
+ return gFalse;
+}
+
+GBool GfxResources::lookupXObjectNF(char *name, Object *obj) {
+ GfxResources *resPtr;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->xObjDict.isDict()) {
+ if (!resPtr->xObjDict.dictLookupNF(name, obj)->isNull())
+ return gTrue;
+ obj->free();
+ }
+ }
+ error(-1, "XObject '%s' is unknown", name);
+ return gFalse;
+}
+
+void GfxResources::lookupColorSpace(char *name, Object *obj) {
+ GfxResources *resPtr;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->colorSpaceDict.isDict()) {
+ if (!resPtr->colorSpaceDict.dictLookup(name, obj)->isNull()) {
+ return;
+ }
+ obj->free();
+ }
+ }
+ obj->initNull();
+}
+
+GfxPattern *GfxResources::lookupPattern(char *name) {
+ GfxResources *resPtr;
+ GfxPattern *pattern;
+ Object obj;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->patternDict.isDict()) {
+ if (!resPtr->patternDict.dictLookup(name, &obj)->isNull()) {
+ pattern = GfxPattern::parse(&obj);
+ obj.free();
+ return pattern;
+ }
+ obj.free();
+ }
+ }
+ error(-1, "Unknown pattern '%s'", name);
+ return NULL;
+}
+
+GfxShading *GfxResources::lookupShading(char *name) {
+ GfxResources *resPtr;
+ GfxShading *shading;
+ Object obj;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->shadingDict.isDict()) {
+ if (!resPtr->shadingDict.dictLookup(name, &obj)->isNull()) {
+ shading = GfxShading::parse(&obj);
+ obj.free();
+ return shading;
+ }
+ obj.free();
+ }
+ }
+ error(-1, "Unknown shading '%s'", name);
+ return NULL;
+}
+
+GBool GfxResources::lookupGState(char *name, Object *obj) {
+ GfxResources *resPtr;
+
+ for (resPtr = this; resPtr; resPtr = resPtr->next) {
+ if (resPtr->gStateDict.isDict()) {
+ if (!resPtr->gStateDict.dictLookup(name, obj)->isNull()) {
+ return gTrue;
+ }
+ obj->free();
+ }
+ }
+ error(-1, "ExtGState '%s' is unknown", name);
+ return gFalse;
+}
+
+//------------------------------------------------------------------------
+// Gfx
+//------------------------------------------------------------------------
+
+Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict,
+ double hDPI, double vDPI, PDFRectangle *box,
+ PDFRectangle *cropBox, int rotate,
+ GBool (*abortCheckCbkA)(void *data),
+ void *abortCheckCbkDataA) {
+ int i;
+
+ xref = xrefA;
+ subPage = gFalse;
+ printCommands = globalParams->getPrintCommands();
+
+ // start the resource stack
+ res = new GfxResources(xref, resDict, NULL);
+
+ // initialize
+ out = outA;
+ state = new GfxState(hDPI, vDPI, box, rotate, out->upsideDown());
+ fontChanged = gFalse;
+ clip = clipNone;
+ ignoreUndef = 0;
+ out->startPage(pageNum, state);
+ out->setDefaultCTM(state->getCTM());
+ out->updateAll(state);
+ for (i = 0; i < 6; ++i) {
+ baseMatrix[i] = state->getCTM()[i];
+ }
+ formDepth = 0;
+ abortCheckCbk = abortCheckCbkA;
+ abortCheckCbkData = abortCheckCbkDataA;
+
+ // set crop box
+ if (cropBox) {
+ state->moveTo(cropBox->x1, cropBox->y1);
+ state->lineTo(cropBox->x2, cropBox->y1);
+ state->lineTo(cropBox->x2, cropBox->y2);
+ state->lineTo(cropBox->x1, cropBox->y2);
+ state->closePath();
+ state->clip();
+ out->clip(state);
+ state->clearPath();
+ }
+}
+
+Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict,
+ PDFRectangle *box, PDFRectangle *cropBox,
+ GBool (*abortCheckCbkA)(void *data),
+ void *abortCheckCbkDataA) {
+ int i;
+
+ xref = xrefA;
+ subPage = gTrue;
+ printCommands = globalParams->getPrintCommands();
+
+ // start the resource stack
+ res = new GfxResources(xref, resDict, NULL);
+
+ // initialize
+ out = outA;
+ state = new GfxState(72, 72, box, 0, gFalse);
+ fontChanged = gFalse;
+ clip = clipNone;
+ ignoreUndef = 0;
+ for (i = 0; i < 6; ++i) {
+ baseMatrix[i] = state->getCTM()[i];
+ }
+ formDepth = 0;
+ abortCheckCbk = abortCheckCbkA;
+ abortCheckCbkData = abortCheckCbkDataA;
+
+ // set crop box
+ if (cropBox) {
+ state->moveTo(cropBox->x1, cropBox->y1);
+ state->lineTo(cropBox->x2, cropBox->y1);
+ state->lineTo(cropBox->x2, cropBox->y2);
+ state->lineTo(cropBox->x1, cropBox->y2);
+ state->closePath();
+ state->clip();
+ out->clip(state);
+ state->clearPath();
+ }
+}
+
+Gfx::~Gfx() {
+ while (state->hasSaves()) {
+ restoreState();
+ }
+ if (!subPage) {
+ out->endPage();
+ }
+ while (res) {
+ popResources();
+ }
+ if (state) {
+ delete state;
+ }
+}
+
+void Gfx::display(Object *obj, GBool topLevel) {
+ Object obj2;
+ int i;
+
+ if (obj->isArray()) {
+ for (i = 0; i < obj->arrayGetLength(); ++i) {
+ obj->arrayGet(i, &obj2);
+ if (!obj2.isStream()) {
+ error(-1, "Weird page contents");
+ obj2.free();
+ return;
+ }
+ obj2.free();
+ }
+ } else if (!obj->isStream()) {
+ error(-1, "Weird page contents");
+ return;
+ }
+ parser = new Parser(xref, new Lexer(xref, obj), gFalse);
+ go(topLevel);
+ delete parser;
+ parser = NULL;
+}
+
+void Gfx::go(GBool topLevel) {
+ Object obj;
+ Object args[maxArgs];
+ int numArgs, i;
+ int lastAbortCheck;
+
+ // scan a sequence of objects
+ updateLevel = lastAbortCheck = 0;
+ numArgs = 0;
+ parser->getObj(&obj);
+ while (!obj.isEOF()) {
+
+ // got a command - execute it
+ if (obj.isCmd()) {
+ if (printCommands) {
+ obj.print(stdout);
+ for (i = 0; i < numArgs; ++i) {
+ printf(" ");
+ args[i].print(stdout);
+ }
+ printf("\n");
+ fflush(stdout);
+ }
+ execOp(&obj, args, numArgs);
+ obj.free();
+ for (i = 0; i < numArgs; ++i)
+ args[i].free();
+ numArgs = 0;
+
+ // periodically update display
+ if (++updateLevel >= 20000) {
+ out->dump();
+ updateLevel = 0;
+ }
+
+ // check for an abort
+ if (abortCheckCbk) {
+ if (updateLevel - lastAbortCheck > 10) {
+ if ((*abortCheckCbk)(abortCheckCbkData)) {
+ break;
+ }
+ lastAbortCheck = updateLevel;
+ }
+ }
+
+ // got an argument - save it
+ } else if (numArgs < maxArgs) {
+ args[numArgs++] = obj;
+
+ // too many arguments - something is wrong
+ } else {
+ error(getPos(), "Too many args in content stream");
+ if (printCommands) {
+ printf("throwing away arg: ");
+ obj.print(stdout);
+ printf("\n");
+ fflush(stdout);
+ }
+ obj.free();
+ }
+
+ // grab the next object
+ parser->getObj(&obj);
+ }
+ obj.free();
+
+ // args at end with no command
+ if (numArgs > 0) {
+ error(getPos(), "Leftover args in content stream");
+ if (printCommands) {
+ printf("%d leftovers:", numArgs);
+ for (i = 0; i < numArgs; ++i) {
+ printf(" ");
+ args[i].print(stdout);
+ }
+ printf("\n");
+ fflush(stdout);
+ }
+ for (i = 0; i < numArgs; ++i)
+ args[i].free();
+ }
+
+ // update display
+ if (topLevel && updateLevel > 0) {
+ out->dump();
+ }
+}
+
+void Gfx::execOp(Object *cmd, Object args[], int numArgs) {
+ Operator *op;
+ char *name;
+ Object *argPtr;
+ int i;
+
+ // find operator
+ name = cmd->getCmd();
+ if (!(op = findOp(name))) {
+ if (ignoreUndef == 0)
+ error(getPos(), "Unknown operator '%s'", name);
+ return;
+ }
+
+ // type check args
+ argPtr = args;
+ if (op->numArgs >= 0) {
+ if (numArgs < op->numArgs) {
+ error(getPos(), "Too few (%d) args to '%s' operator", numArgs, name);
+ return;
+ }
+ if (numArgs > op->numArgs) {
+#if 0
+ error(getPos(), "Too many (%d) args to '%s' operator", numArgs, name);
+#endif
+ argPtr += numArgs - op->numArgs;
+ numArgs = op->numArgs;
+ }
+ } else {
+ if (numArgs > -op->numArgs) {
+ error(getPos(), "Too many (%d) args to '%s' operator",
+ numArgs, name);
+ return;
+ }
+ }
+ for (i = 0; i < numArgs; ++i) {
+ if (!checkArg(&argPtr[i], op->tchk[i])) {
+ error(getPos(), "Arg #%d to '%s' operator is wrong type (%s)",
+ i, name, argPtr[i].getTypeName());
+ return;
+ }
+ }
+
+ // do it
+ (this->*op->func)(argPtr, numArgs);
+}
+
+Operator *Gfx::findOp(char *name) {
+ int a, b, m, cmp;
+
+ a = -1;
+ b = numOps;
+ // invariant: opTab[a] < name < opTab[b]
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ cmp = strcmp(opTab[m].name, name);
+ if (cmp < 0)
+ a = m;
+ else if (cmp > 0)
+ b = m;
+ else
+ a = b = m;
+ }
+ if (cmp != 0)
+ return NULL;
+ return &opTab[a];
+}
+
+GBool Gfx::checkArg(Object *arg, TchkType type) {
+ switch (type) {
+ case tchkBool: return arg->isBool();
+ case tchkInt: return arg->isInt();
+ case tchkNum: return arg->isNum();
+ case tchkString: return arg->isString();
+ case tchkName: return arg->isName();
+ case tchkArray: return arg->isArray();
+ case tchkProps: return arg->isDict() || arg->isName();
+ case tchkSCN: return arg->isNum() || arg->isName();
+ case tchkNone: return gFalse;
+ }
+ return gFalse;
+}
+
+int Gfx::getPos() {
+ return parser ? parser->getPos() : -1;
+}
+
+//------------------------------------------------------------------------
+// graphics state operators
+//------------------------------------------------------------------------
+
+void Gfx::opSave(Object * /*args[]*/, int /*numArgs*/) {
+ saveState();
+}
+
+void Gfx::opRestore(Object * /*args[]*/, int /*numArgs*/) {
+ restoreState();
+}
+
+void Gfx::opConcat(Object args[], int /*numArgs*/) {
+ state->concatCTM(args[0].getNum(), args[1].getNum(),
+ args[2].getNum(), args[3].getNum(),
+ args[4].getNum(), args[5].getNum());
+ out->updateCTM(state, args[0].getNum(), args[1].getNum(),
+ args[2].getNum(), args[3].getNum(),
+ args[4].getNum(), args[5].getNum());
+ fontChanged = gTrue;
+}
+
+void Gfx::opSetDash(Object args[], int /*numArgs*/) {
+ Array *a;
+ int length;
+ Object obj;
+ double *dash;
+ int i;
+
+ a = args[0].getArray();
+ length = a->getLength();
+ if (length == 0) {
+ dash = NULL;
+ } else {
+ dash = (double *)gmallocn(length, sizeof(double));
+ for (i = 0; i < length; ++i) {
+ dash[i] = a->get(i, &obj)->getNum();
+ obj.free();
+ }
+ }
+ state->setLineDash(dash, length, args[1].getNum());
+ out->updateLineDash(state);
+}
+
+void Gfx::opSetFlat(Object args[], int /*numArgs*/) {
+ state->setFlatness((int)args[0].getNum());
+ out->updateFlatness(state);
+}
+
+void Gfx::opSetLineJoin(Object args[], int /*numArgs*/) {
+ state->setLineJoin(args[0].getInt());
+ out->updateLineJoin(state);
+}
+
+void Gfx::opSetLineCap(Object args[], int /*numArgs*/) {
+ state->setLineCap(args[0].getInt());
+ out->updateLineCap(state);
+}
+
+void Gfx::opSetMiterLimit(Object args[], int /*numArgs*/) {
+ state->setMiterLimit(args[0].getNum());
+ out->updateMiterLimit(state);
+}
+
+void Gfx::opSetLineWidth(Object args[], int /*numArgs*/) {
+ state->setLineWidth(args[0].getNum());
+ out->updateLineWidth(state);
+}
+
+void Gfx::opSetExtGState(Object args[], int /*numArgs*/) {
+ Object obj1, obj2, obj3, obj4, obj5;
+ GfxBlendMode mode;
+ GBool haveFillOP;
+ Function *funcs[4];
+ GfxColor backdropColor;
+ GBool haveBackdropColor;
+ GfxColorSpace *blendingColorSpace;
+ GBool alpha, isolated, knockout;
+ int i;
+
+ if (!res->lookupGState(args[0].getName(), &obj1)) {
+ return;
+ }
+ if (!obj1.isDict()) {
+ error(getPos(), "ExtGState '%s' is wrong type", args[0].getName());
+ obj1.free();
+ return;
+ }
+ if (printCommands) {
+ printf(" gfx state dict: ");
+ obj1.print();
+ printf("\n");
+ }
+
+ // transparency support: blend mode, fill/stroke opacity
+ if (!obj1.dictLookup("BM", &obj2)->isNull()) {
+ if (state->parseBlendMode(&obj2, &mode)) {
+ state->setBlendMode(mode);
+ out->updateBlendMode(state);
+ } else {
+ error(getPos(), "Invalid blend mode in ExtGState");
+ }
+ }
+ obj2.free();
+ if (obj1.dictLookup("ca", &obj2)->isNum()) {
+ state->setFillOpacity(obj2.getNum());
+ out->updateFillOpacity(state);
+ }
+ obj2.free();
+ if (obj1.dictLookup("CA", &obj2)->isNum()) {
+ state->setStrokeOpacity(obj2.getNum());
+ out->updateStrokeOpacity(state);
+ }
+ obj2.free();
+
+ // fill/stroke overprint
+ if ((haveFillOP = (obj1.dictLookup("op", &obj2)->isBool()))) {
+ state->setFillOverprint(obj2.getBool());
+ out->updateFillOverprint(state);
+ }
+ obj2.free();
+ if (obj1.dictLookup("OP", &obj2)->isBool()) {
+ state->setStrokeOverprint(obj2.getBool());
+ out->updateStrokeOverprint(state);
+ if (!haveFillOP) {
+ state->setFillOverprint(obj2.getBool());
+ out->updateFillOverprint(state);
+ }
+ }
+ obj2.free();
+
+ // stroke adjust
+ if (obj1.dictLookup("SA", &obj2)->isBool()) {
+ state->setStrokeAdjust(obj2.getBool());
+ out->updateStrokeAdjust(state);
+ }
+ obj2.free();
+
+ // transfer function
+ if (obj1.dictLookup("TR2", &obj2)->isNull()) {
+ obj2.free();
+ obj1.dictLookup("TR", &obj2);
+ }
+ if (obj2.isName("Default") ||
+ obj2.isName("Identity")) {
+ funcs[0] = funcs[1] = funcs[2] = funcs[3] = NULL;
+ state->setTransfer(funcs);
+ out->updateTransfer(state);
+ } else if (obj2.isArray() && obj2.arrayGetLength() == 4) {
+ for (i = 0; i < 4; ++i) {
+ obj2.arrayGet(i, &obj3);
+ funcs[i] = Function::parse(&obj3);
+ obj3.free();
+ if (!funcs[i]) {
+ break;
+ }
+ }
+ if (i == 4) {
+ state->setTransfer(funcs);
+ out->updateTransfer(state);
+ }
+ } else if (obj2.isName() || obj2.isDict() || obj2.isStream()) {
+ if ((funcs[0] = Function::parse(&obj2))) {
+ funcs[1] = funcs[2] = funcs[3] = NULL;
+ state->setTransfer(funcs);
+ out->updateTransfer(state);
+ }
+ } else if (!obj2.isNull()) {
+ error(getPos(), "Invalid transfer function in ExtGState");
+ }
+ obj2.free();
+
+ // soft mask
+ if (!obj1.dictLookup("SMask", &obj2)->isNull()) {
+ if (obj2.isName("None")) {
+ out->clearSoftMask(state);
+ } else if (obj2.isDict()) {
+ if (obj2.dictLookup("S", &obj3)->isName("Alpha")) {
+ alpha = gTrue;
+ } else { // "Luminosity"
+ alpha = gFalse;
+ }
+ obj3.free();
+ funcs[0] = NULL;
+ if (!obj2.dictLookup("TR", &obj3)->isNull()) {
+ funcs[0] = Function::parse(&obj3);
+ if (funcs[0]->getInputSize() != 1 ||
+ funcs[0]->getOutputSize() != 1) {
+ error(getPos(),
+ "Invalid transfer function in soft mask in ExtGState");
+ delete funcs[0];
+ funcs[0] = NULL;
+ }
+ }
+ obj3.free();
+ if ((haveBackdropColor = obj2.dictLookup("BC", &obj3)->isArray())) {
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ backdropColor.c[i] = 0;
+ }
+ for (i = 0; i < obj3.arrayGetLength() && i < gfxColorMaxComps; ++i) {
+ obj3.arrayGet(i, &obj4);
+ if (obj4.isNum()) {
+ backdropColor.c[i] = dblToCol(obj4.getNum());
+ }
+ obj4.free();
+ }
+ }
+ obj3.free();
+ if (obj2.dictLookup("G", &obj3)->isStream()) {
+ if (obj3.streamGetDict()->lookup("Group", &obj4)->isDict()) {
+ blendingColorSpace = NULL;
+ isolated = knockout = gFalse;
+ if (!obj4.dictLookup("CS", &obj5)->isNull()) {
+ blendingColorSpace = GfxColorSpace::parse(&obj5);
+ }
+ obj5.free();
+ if (obj4.dictLookup("I", &obj5)->isBool()) {
+ isolated = obj5.getBool();
+ }
+ obj5.free();
+ if (obj4.dictLookup("K", &obj5)->isBool()) {
+ knockout = obj5.getBool();
+ }
+ obj5.free();
+ if (!haveBackdropColor) {
+ if (blendingColorSpace) {
+ blendingColorSpace->getDefaultColor(&backdropColor);
+ } else {
+ //~ need to get the parent or default color space (?)
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ backdropColor.c[i] = 0;
+ }
+ }
+ }
+ doSoftMask(&obj3, alpha, blendingColorSpace,
+ isolated, knockout, funcs[0], &backdropColor);
+ if (funcs[0]) {
+ delete funcs[0];
+ }
+ } else {
+ error(getPos(), "Invalid soft mask in ExtGState - missing group");
+ }
+ obj4.free();
+ } else {
+ error(getPos(), "Invalid soft mask in ExtGState - missing group");
+ }
+ obj3.free();
+ } else if (!obj2.isNull()) {
+ error(getPos(), "Invalid soft mask in ExtGState");
+ }
+ }
+ obj2.free();
+
+ obj1.free();
+}
+
+void Gfx::doSoftMask(Object *str, GBool alpha,
+ GfxColorSpace *blendingColorSpace,
+ GBool isolated, GBool knockout,
+ Function *transferFunc, GfxColor *backdropColor) {
+ Dict *dict, *resDict;
+ double m[6], bbox[4];
+ Object obj1, obj2;
+ int i;
+
+ // check for excessive recursion
+ if (formDepth > 20) {
+ return;
+ }
+
+ // get stream dict
+ dict = str->streamGetDict();
+
+ // check form type
+ dict->lookup("FormType", &obj1);
+ if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
+ error(getPos(), "Unknown form type");
+ }
+ obj1.free();
+
+ // get bounding box
+ dict->lookup("BBox", &obj1);
+ if (!obj1.isArray()) {
+ obj1.free();
+ error(getPos(), "Bad form bounding box");
+ return;
+ }
+ for (i = 0; i < 4; ++i) {
+ obj1.arrayGet(i, &obj2);
+ bbox[i] = obj2.getNum();
+ obj2.free();
+ }
+ obj1.free();
+
+ // get matrix
+ dict->lookup("Matrix", &obj1);
+ if (obj1.isArray()) {
+ for (i = 0; i < 6; ++i) {
+ obj1.arrayGet(i, &obj2);
+ m[i] = obj2.getNum();
+ obj2.free();
+ }
+ } else {
+ m[0] = 1; m[1] = 0;
+ m[2] = 0; m[3] = 1;
+ m[4] = 0; m[5] = 0;
+ }
+ obj1.free();
+
+ // get resources
+ dict->lookup("Resources", &obj1);
+ resDict = obj1.isDict() ? obj1.getDict() : (Dict *)NULL;
+
+ // draw it
+ ++formDepth;
+ doForm1(str, resDict, m, bbox, gTrue, gTrue,
+ blendingColorSpace, isolated, knockout,
+ alpha, transferFunc, backdropColor);
+ --formDepth;
+
+ if (blendingColorSpace) {
+ delete blendingColorSpace;
+ }
+ obj1.free();
+}
+
+void Gfx::opSetRenderingIntent(Object * /*args[]*/, int /*numArgs*/) {
+}
+
+//------------------------------------------------------------------------
+// color operators
+//------------------------------------------------------------------------
+
+void Gfx::opSetFillGray(Object args[], int /*numArgs*/) {
+ GfxColor color;
+
+ state->setFillPattern(NULL);
+ state->setFillColorSpace(new GfxDeviceGrayColorSpace());
+ out->updateFillColorSpace(state);
+ color.c[0] = dblToCol(args[0].getNum());
+ state->setFillColor(&color);
+ out->updateFillColor(state);
+}
+
+void Gfx::opSetStrokeGray(Object args[], int /*numArgs*/) {
+ GfxColor color;
+
+ state->setStrokePattern(NULL);
+ state->setStrokeColorSpace(new GfxDeviceGrayColorSpace());
+ out->updateStrokeColorSpace(state);
+ color.c[0] = dblToCol(args[0].getNum());
+ state->setStrokeColor(&color);
+ out->updateStrokeColor(state);
+}
+
+void Gfx::opSetFillCMYKColor(Object args[], int /*numArgs*/) {
+ GfxColor color;
+ int i;
+
+ state->setFillPattern(NULL);
+ state->setFillColorSpace(new GfxDeviceCMYKColorSpace());
+ out->updateFillColorSpace(state);
+ for (i = 0; i < 4; ++i) {
+ color.c[i] = dblToCol(args[i].getNum());
+ }
+ state->setFillColor(&color);
+ out->updateFillColor(state);
+}
+
+void Gfx::opSetStrokeCMYKColor(Object args[], int /*numArgs*/) {
+ GfxColor color;
+ int i;
+
+ state->setStrokePattern(NULL);
+ state->setStrokeColorSpace(new GfxDeviceCMYKColorSpace());
+ out->updateStrokeColorSpace(state);
+ for (i = 0; i < 4; ++i) {
+ color.c[i] = dblToCol(args[i].getNum());
+ }
+ state->setStrokeColor(&color);
+ out->updateStrokeColor(state);
+}
+
+void Gfx::opSetFillRGBColor(Object args[], int /*numArgs*/) {
+ GfxColor color;
+ int i;
+
+ state->setFillPattern(NULL);
+ state->setFillColorSpace(new GfxDeviceRGBColorSpace());
+ out->updateFillColorSpace(state);
+ for (i = 0; i < 3; ++i) {
+ color.c[i] = dblToCol(args[i].getNum());
+ }
+ state->setFillColor(&color);
+ out->updateFillColor(state);
+}
+
+void Gfx::opSetStrokeRGBColor(Object args[], int /*numArgs*/) {
+ GfxColor color;
+ int i;
+
+ state->setStrokePattern(NULL);
+ state->setStrokeColorSpace(new GfxDeviceRGBColorSpace());
+ out->updateStrokeColorSpace(state);
+ for (i = 0; i < 3; ++i) {
+ color.c[i] = dblToCol(args[i].getNum());
+ }
+ state->setStrokeColor(&color);
+ out->updateStrokeColor(state);
+}
+
+void Gfx::opSetFillColorSpace(Object args[], int /*numArgs*/) {
+ Object obj;
+ GfxColorSpace *colorSpace;
+ GfxColor color;
+
+ state->setFillPattern(NULL);
+ res->lookupColorSpace(args[0].getName(), &obj);
+ if (obj.isNull()) {
+ colorSpace = GfxColorSpace::parse(&args[0]);
+ } else {
+ colorSpace = GfxColorSpace::parse(&obj);
+ }
+ obj.free();
+ if (colorSpace) {
+ state->setFillColorSpace(colorSpace);
+ out->updateFillColorSpace(state);
+ colorSpace->getDefaultColor(&color);
+ state->setFillColor(&color);
+ out->updateFillColor(state);
+ } else {
+ error(getPos(), "Bad color space (fill)");
+ }
+}
+
+void Gfx::opSetStrokeColorSpace(Object args[], int /*numArgs*/) {
+ Object obj;
+ GfxColorSpace *colorSpace;
+ GfxColor color;
+
+ state->setStrokePattern(NULL);
+ res->lookupColorSpace(args[0].getName(), &obj);
+ if (obj.isNull()) {
+ colorSpace = GfxColorSpace::parse(&args[0]);
+ } else {
+ colorSpace = GfxColorSpace::parse(&obj);
+ }
+ obj.free();
+ if (colorSpace) {
+ state->setStrokeColorSpace(colorSpace);
+ out->updateStrokeColorSpace(state);
+ colorSpace->getDefaultColor(&color);
+ state->setStrokeColor(&color);
+ out->updateStrokeColor(state);
+ } else {
+ error(getPos(), "Bad color space (stroke)");
+ }
+}
+
+void Gfx::opSetFillColor(Object args[], int numArgs) {
+ GfxColor color;
+ int i;
+
+ if (numArgs != state->getFillColorSpace()->getNComps()) {
+ error(getPos(), "Incorrect number of arguments in 'sc' command");
+ return;
+ }
+ state->setFillPattern(NULL);
+ for (i = 0; i < numArgs; ++i) {
+ color.c[i] = dblToCol(args[i].getNum());
+ }
+ state->setFillColor(&color);
+ out->updateFillColor(state);
+}
+
+void Gfx::opSetStrokeColor(Object args[], int numArgs) {
+ GfxColor color;
+ int i;
+
+ if (numArgs != state->getStrokeColorSpace()->getNComps()) {
+ error(getPos(), "Incorrect number of arguments in 'SC' command");
+ return;
+ }
+ state->setStrokePattern(NULL);
+ for (i = 0; i < numArgs; ++i) {
+ color.c[i] = dblToCol(args[i].getNum());
+ }
+ state->setStrokeColor(&color);
+ out->updateStrokeColor(state);
+}
+
+void Gfx::opSetFillColorN(Object args[], int numArgs) {
+ GfxColor color;
+ GfxPattern *pattern;
+ int i;
+
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ if (numArgs > 1) {
+ if (!((GfxPatternColorSpace *)state->getFillColorSpace())->getUnder() ||
+ numArgs - 1 != ((GfxPatternColorSpace *)state->getFillColorSpace())
+ ->getUnder()->getNComps()) {
+ error(getPos(), "Incorrect number of arguments in 'scn' command");
+ return;
+ }
+ for (i = 0; i < numArgs - 1 && i < gfxColorMaxComps; ++i) {
+ if (args[i].isNum()) {
+ color.c[i] = dblToCol(args[i].getNum());
+ }
+ }
+ state->setFillColor(&color);
+ out->updateFillColor(state);
+ }
+ if (args[numArgs-1].isName() &&
+ (pattern = res->lookupPattern(args[numArgs-1].getName()))) {
+ state->setFillPattern(pattern);
+ }
+
+ } else {
+ if (numArgs != state->getFillColorSpace()->getNComps()) {
+ error(getPos(), "Incorrect number of arguments in 'scn' command");
+ return;
+ }
+ state->setFillPattern(NULL);
+ for (i = 0; i < numArgs && i < gfxColorMaxComps; ++i) {
+ if (args[i].isNum()) {
+ color.c[i] = dblToCol(args[i].getNum());
+ }
+ }
+ state->setFillColor(&color);
+ out->updateFillColor(state);
+ }
+}
+
+void Gfx::opSetStrokeColorN(Object args[], int numArgs) {
+ GfxColor color;
+ GfxPattern *pattern;
+ int i;
+
+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
+ if (numArgs > 1) {
+ if (!((GfxPatternColorSpace *)state->getStrokeColorSpace())
+ ->getUnder() ||
+ numArgs - 1 != ((GfxPatternColorSpace *)state->getStrokeColorSpace())
+ ->getUnder()->getNComps()) {
+ error(getPos(), "Incorrect number of arguments in 'SCN' command");
+ return;
+ }
+ for (i = 0; i < numArgs - 1 && i < gfxColorMaxComps; ++i) {
+ if (args[i].isNum()) {
+ color.c[i] = dblToCol(args[i].getNum());
+ }
+ }
+ state->setStrokeColor(&color);
+ out->updateStrokeColor(state);
+ }
+ if (args[numArgs-1].isName() &&
+ (pattern = res->lookupPattern(args[numArgs-1].getName()))) {
+ state->setStrokePattern(pattern);
+ }
+
+ } else {
+ if (numArgs != state->getStrokeColorSpace()->getNComps()) {
+ error(getPos(), "Incorrect number of arguments in 'SCN' command");
+ return;
+ }
+ state->setStrokePattern(NULL);
+ for (i = 0; i < numArgs && i < gfxColorMaxComps; ++i) {
+ if (args[i].isNum()) {
+ color.c[i] = dblToCol(args[i].getNum());
+ }
+ }
+ state->setStrokeColor(&color);
+ out->updateStrokeColor(state);
+ }
+}
+
+//------------------------------------------------------------------------
+// path segment operators
+//------------------------------------------------------------------------
+
+void Gfx::opMoveTo(Object args[], int /*numArgs*/) {
+ state->moveTo(args[0].getNum(), args[1].getNum());
+}
+
+void Gfx::opLineTo(Object args[], int /*numArgs*/) {
+ if (!state->isCurPt()) {
+ error(getPos(), "No current point in lineto");
+ return;
+ }
+ state->lineTo(args[0].getNum(), args[1].getNum());
+}
+
+void Gfx::opCurveTo(Object args[], int /*numArgs*/) {
+ double x1, y1, x2, y2, x3, y3;
+
+ if (!state->isCurPt()) {
+ error(getPos(), "No current point in curveto");
+ return;
+ }
+ x1 = args[0].getNum();
+ y1 = args[1].getNum();
+ x2 = args[2].getNum();
+ y2 = args[3].getNum();
+ x3 = args[4].getNum();
+ y3 = args[5].getNum();
+ state->curveTo(x1, y1, x2, y2, x3, y3);
+}
+
+void Gfx::opCurveTo1(Object args[], int /*numArgs*/) {
+ double x1, y1, x2, y2, x3, y3;
+
+ if (!state->isCurPt()) {
+ error(getPos(), "No current point in curveto1");
+ return;
+ }
+ x1 = state->getCurX();
+ y1 = state->getCurY();
+ x2 = args[0].getNum();
+ y2 = args[1].getNum();
+ x3 = args[2].getNum();
+ y3 = args[3].getNum();
+ state->curveTo(x1, y1, x2, y2, x3, y3);
+}
+
+void Gfx::opCurveTo2(Object args[], int /*numArgs*/) {
+ double x1, y1, x2, y2, x3, y3;
+
+ if (!state->isCurPt()) {
+ error(getPos(), "No current point in curveto2");
+ return;
+ }
+ x1 = args[0].getNum();
+ y1 = args[1].getNum();
+ x2 = args[2].getNum();
+ y2 = args[3].getNum();
+ x3 = x2;
+ y3 = y2;
+ state->curveTo(x1, y1, x2, y2, x3, y3);
+}
+
+void Gfx::opRectangle(Object args[], int /*numArgs*/) {
+ double x, y, w, h;
+
+ x = args[0].getNum();
+ y = args[1].getNum();
+ w = args[2].getNum();
+ h = args[3].getNum();
+ state->moveTo(x, y);
+ state->lineTo(x + w, y);
+ state->lineTo(x + w, y + h);
+ state->lineTo(x, y + h);
+ state->closePath();
+}
+
+void Gfx::opClosePath(Object * /*args[]*/, int /*numArgs*/) {
+ if (!state->isCurPt()) {
+ error(getPos(), "No current point in closepath");
+ return;
+ }
+ state->closePath();
+}
+
+//------------------------------------------------------------------------
+// path painting operators
+//------------------------------------------------------------------------
+
+void Gfx::opEndPath(Object * /*args[]*/, int /*numArgs*/) {
+ doEndPath();
+}
+
+void Gfx::opStroke(Object * /*args[]*/, int /*numArgs*/) {
+ if (!state->isCurPt()) {
+ //error(getPos(), "No path in stroke");
+ return;
+ }
+ if (state->isPath()) {
+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
+ doPatternStroke();
+ } else {
+ out->stroke(state);
+ }
+ }
+ doEndPath();
+}
+
+void Gfx::opCloseStroke(Object * /*args[]*/, int /*numArgs*/) {
+ if (!state->isCurPt()) {
+ //error(getPos(), "No path in closepath/stroke");
+ return;
+ }
+ if (state->isPath()) {
+ state->closePath();
+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
+ doPatternStroke();
+ } else {
+ out->stroke(state);
+ }
+ }
+ doEndPath();
+}
+
+void Gfx::opFill(Object * /*args[]*/, int /*numArgs*/) {
+ if (!state->isCurPt()) {
+ //error(getPos(), "No path in fill");
+ return;
+ }
+ if (state->isPath()) {
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ doPatternFill(gFalse);
+ } else {
+ out->fill(state);
+ }
+ }
+ doEndPath();
+}
+
+void Gfx::opEOFill(Object * /*args[]*/, int /*numArgs*/) {
+ if (!state->isCurPt()) {
+ //error(getPos(), "No path in eofill");
+ return;
+ }
+ if (state->isPath()) {
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ doPatternFill(gTrue);
+ } else {
+ out->eoFill(state);
+ }
+ }
+ doEndPath();
+}
+
+void Gfx::opFillStroke(Object * /*args[]*/, int /*numArgs*/) {
+ if (!state->isCurPt()) {
+ //error(getPos(), "No path in fill/stroke");
+ return;
+ }
+ if (state->isPath()) {
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ doPatternFill(gFalse);
+ } else {
+ out->fill(state);
+ }
+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
+ doPatternStroke();
+ } else {
+ out->stroke(state);
+ }
+ }
+ doEndPath();
+}
+
+void Gfx::opCloseFillStroke(Object * /*args[]*/, int /*numArgs*/) {
+ if (!state->isCurPt()) {
+ //error(getPos(), "No path in closepath/fill/stroke");
+ return;
+ }
+ if (state->isPath()) {
+ state->closePath();
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ doPatternFill(gFalse);
+ } else {
+ out->fill(state);
+ }
+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
+ doPatternStroke();
+ } else {
+ out->stroke(state);
+ }
+ }
+ doEndPath();
+}
+
+void Gfx::opEOFillStroke(Object * /*args[]*/, int /*numArgs*/) {
+ if (!state->isCurPt()) {
+ //error(getPos(), "No path in eofill/stroke");
+ return;
+ }
+ if (state->isPath()) {
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ doPatternFill(gTrue);
+ } else {
+ out->eoFill(state);
+ }
+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
+ doPatternStroke();
+ } else {
+ out->stroke(state);
+ }
+ }
+ doEndPath();
+}
+
+void Gfx::opCloseEOFillStroke(Object * /*args[]*/, int /*numArgs*/) {
+ if (!state->isCurPt()) {
+ //error(getPos(), "No path in closepath/eofill/stroke");
+ return;
+ }
+ if (state->isPath()) {
+ state->closePath();
+ if (state->getFillColorSpace()->getMode() == csPattern) {
+ doPatternFill(gTrue);
+ } else {
+ out->eoFill(state);
+ }
+ if (state->getStrokeColorSpace()->getMode() == csPattern) {
+ doPatternStroke();
+ } else {
+ out->stroke(state);
+ }
+ }
+ doEndPath();
+}
+
+void Gfx::doPatternFill(GBool eoFill) {
+ GfxPattern *pattern;
+
+ // this is a bit of a kludge -- patterns can be really slow, so we
+ // skip them if we're only doing text extraction, since they almost
+ // certainly don't contain any text
+ if (!out->needNonText()) {
+ return;
+ }
+
+ if (!(pattern = state->getFillPattern())) {
+ return;
+ }
+ switch (pattern->getType()) {
+ case 1:
+ doTilingPatternFill((GfxTilingPattern *)pattern, gFalse, eoFill);
+ break;
+ case 2:
+ doShadingPatternFill((GfxShadingPattern *)pattern, gFalse, eoFill);
+ break;
+ default:
+ error(getPos(), "Unimplemented pattern type (%d) in fill",
+ pattern->getType());
+ break;
+ }
+}
+
+void Gfx::doPatternStroke() {
+ GfxPattern *pattern;
+
+ // this is a bit of a kludge -- patterns can be really slow, so we
+ // skip them if we're only doing text extraction, since they almost
+ // certainly don't contain any text
+ if (!out->needNonText()) {
+ return;
+ }
+
+ if (!(pattern = state->getStrokePattern())) {
+ return;
+ }
+ switch (pattern->getType()) {
+ case 1:
+ doTilingPatternFill((GfxTilingPattern *)pattern, gTrue, gFalse);
+ break;
+ case 2:
+ doShadingPatternFill((GfxShadingPattern *)pattern, gTrue, gFalse);
+ break;
+ default:
+ error(getPos(), "Unimplemented pattern type (%d) in stroke",
+ pattern->getType());
+ break;
+ }
+}
+
+void Gfx::doTilingPatternFill(GfxTilingPattern *tPat,
+ GBool stroke, GBool eoFill) {
+ GfxPatternColorSpace *patCS;
+ GfxColorSpace *cs;
+ GfxPath *savedPath;
+ double xMin, yMin, xMax, yMax, x, y, x1, y1;
+ double cxMin, cyMin, cxMax, cyMax;
+ int xi0, yi0, xi1, yi1, xi, yi;
+ double *ctm, *btm, *ptm;
+ double m[6], ictm[6], m1[6], imb[6];
+ double det;
+ double xstep, ystep;
+ int i;
+
+ // get color space
+ patCS = (GfxPatternColorSpace *)(stroke ? state->getStrokeColorSpace()
+ : state->getFillColorSpace());
+
+ // construct a (pattern space) -> (current space) transform matrix
+ ctm = state->getCTM();
+ btm = baseMatrix;
+ ptm = tPat->getMatrix();
+ // iCTM = invert CTM
+ det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
+ ictm[0] = ctm[3] * det;
+ ictm[1] = -ctm[1] * det;
+ ictm[2] = -ctm[2] * det;
+ ictm[3] = ctm[0] * det;
+ ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
+ ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
+ // m1 = PTM * BTM = PTM * base transform matrix
+ m1[0] = ptm[0] * btm[0] + ptm[1] * btm[2];
+ m1[1] = ptm[0] * btm[1] + ptm[1] * btm[3];
+ m1[2] = ptm[2] * btm[0] + ptm[3] * btm[2];
+ m1[3] = ptm[2] * btm[1] + ptm[3] * btm[3];
+ m1[4] = ptm[4] * btm[0] + ptm[5] * btm[2] + btm[4];
+ m1[5] = ptm[4] * btm[1] + ptm[5] * btm[3] + btm[5];
+ // m = m1 * iCTM = (PTM * BTM) * (iCTM)
+ m[0] = m1[0] * ictm[0] + m1[1] * ictm[2];
+ m[1] = m1[0] * ictm[1] + m1[1] * ictm[3];
+ m[2] = m1[2] * ictm[0] + m1[3] * ictm[2];
+ m[3] = m1[2] * ictm[1] + m1[3] * ictm[3];
+ m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4];
+ m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5];
+
+ // construct a (device space) -> (pattern space) transform matrix
+ det = 1 / (m1[0] * m1[3] - m1[1] * m1[2]);
+ imb[0] = m1[3] * det;
+ imb[1] = -m1[1] * det;
+ imb[2] = -m1[2] * det;
+ imb[3] = m1[0] * det;
+ imb[4] = (m1[2] * m1[5] - m1[3] * m1[4]) * det;
+ imb[5] = (m1[1] * m1[4] - m1[0] * m1[5]) * det;
+
+ // save current graphics state
+ savedPath = state->getPath()->copy();
+ saveState();
+
+ // set underlying color space (for uncolored tiling patterns); set
+ // various other parameters (stroke color, line width) to match
+ // Adobe's behavior
+ if (tPat->getPaintType() == 2 && (cs = patCS->getUnder())) {
+ state->setFillColorSpace(cs->copy());
+ out->updateFillColorSpace(state);
+ state->setStrokeColorSpace(cs->copy());
+ out->updateStrokeColorSpace(state);
+ state->setStrokeColor(state->getFillColor());
+ } else {
+ state->setFillColorSpace(new GfxDeviceGrayColorSpace());
+ out->updateFillColorSpace(state);
+ state->setStrokeColorSpace(new GfxDeviceGrayColorSpace());
+ out->updateStrokeColorSpace(state);
+ }
+ state->setFillPattern(NULL);
+ out->updateFillColor(state);
+ state->setStrokePattern(NULL);
+ out->updateStrokeColor(state);
+ if (!stroke) {
+ state->setLineWidth(0);
+ out->updateLineWidth(state);
+ }
+
+ // clip to current path
+ if (stroke) {
+ state->clipToStrokePath();
+ out->clipToStrokePath(state);
+ } else {
+ state->clip();
+ if (eoFill) {
+ out->eoClip(state);
+ } else {
+ out->clip(state);
+ }
+ }
+ state->clearPath();
+
+ // get the clip region, check for empty
+ state->getClipBBox(&cxMin, &cyMin, &cxMax, &cyMax);
+ if (cxMin > cxMax || cyMin > cyMax) {
+ goto err;
+ }
+
+ // transform clip region bbox to pattern space
+ xMin = xMax = cxMin * imb[0] + cyMin * imb[2] + imb[4];
+ yMin = yMax = cxMin * imb[1] + cyMin * imb[3] + imb[5];
+ x1 = cxMin * imb[0] + cyMax * imb[2] + imb[4];
+ y1 = cxMin * imb[1] + cyMax * imb[3] + imb[5];
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+ x1 = cxMax * imb[0] + cyMin * imb[2] + imb[4];
+ y1 = cxMax * imb[1] + cyMin * imb[3] + imb[5];
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+ x1 = cxMax * imb[0] + cyMax * imb[2] + imb[4];
+ y1 = cxMax * imb[1] + cyMax * imb[3] + imb[5];
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+
+ // draw the pattern
+ //~ this should treat negative steps differently -- start at right/top
+ //~ edge instead of left/bottom (?)
+ xstep = fabs(tPat->getXStep());
+ ystep = fabs(tPat->getYStep());
+ xi0 = (int)ceil((xMin - tPat->getBBox()[2]) / xstep);
+ xi1 = (int)floor((xMax - tPat->getBBox()[0]) / xstep) + 1;
+ yi0 = (int)ceil((yMin - tPat->getBBox()[3]) / ystep);
+ yi1 = (int)floor((yMax - tPat->getBBox()[1]) / ystep) + 1;
+ for (i = 0; i < 4; ++i) {
+ m1[i] = m[i];
+ }
+ if (out->useTilingPatternFill()) {
+ m1[4] = m[4];
+ m1[5] = m[5];
+ out->tilingPatternFill(state, tPat->getContentStream(),
+ tPat->getPaintType(), tPat->getResDict(),
+ m1, tPat->getBBox(),
+ xi0, yi0, xi1, yi1, xstep, ystep);
+ } else {
+ for (yi = yi0; yi < yi1; ++yi) {
+ for (xi = xi0; xi < xi1; ++xi) {
+ x = xi * xstep;
+ y = yi * ystep;
+ m1[4] = x * m[0] + y * m[2] + m[4];
+ m1[5] = x * m[1] + y * m[3] + m[5];
+ doForm1(tPat->getContentStream(), tPat->getResDict(),
+ m1, tPat->getBBox());
+ }
+ }
+ }
+
+ // restore graphics state
+ err:
+ restoreState();
+ state->setPath(savedPath);
+}
+
+void Gfx::doShadingPatternFill(GfxShadingPattern *sPat,
+ GBool stroke, GBool eoFill) {
+ GfxShading *shading;
+ GfxPath *savedPath;
+ double *ctm, *btm, *ptm;
+ double m[6], ictm[6], m1[6];
+ double xMin, yMin, xMax, yMax;
+ double det;
+
+ shading = sPat->getShading();
+
+ // save current graphics state
+ savedPath = state->getPath()->copy();
+ saveState();
+
+ // clip to bbox
+ if (shading->getHasBBox()) {
+ shading->getBBox(&xMin, &yMin, &xMax, &yMax);
+ state->moveTo(xMin, yMin);
+ state->lineTo(xMax, yMin);
+ state->lineTo(xMax, yMax);
+ state->lineTo(xMin, yMax);
+ state->closePath();
+ state->clip();
+ out->clip(state);
+ state->setPath(savedPath->copy());
+ }
+
+ // clip to current path
+ if (stroke) {
+ state->clipToStrokePath();
+ out->clipToStrokePath(state);
+ } else {
+ state->clip();
+ if (eoFill) {
+ out->eoClip(state);
+ } else {
+ out->clip(state);
+ }
+ }
+
+ // set the color space
+ state->setFillColorSpace(shading->getColorSpace()->copy());
+ out->updateFillColorSpace(state);
+
+ // background color fill
+ if (shading->getHasBackground()) {
+ state->setFillColor(shading->getBackground());
+ out->updateFillColor(state);
+ out->fill(state);
+ }
+ state->clearPath();
+
+ // construct a (pattern space) -> (current space) transform matrix
+ ctm = state->getCTM();
+ btm = baseMatrix;
+ ptm = sPat->getMatrix();
+ // iCTM = invert CTM
+ det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
+ ictm[0] = ctm[3] * det;
+ ictm[1] = -ctm[1] * det;
+ ictm[2] = -ctm[2] * det;
+ ictm[3] = ctm[0] * det;
+ ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
+ ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
+ // m1 = PTM * BTM = PTM * base transform matrix
+ m1[0] = ptm[0] * btm[0] + ptm[1] * btm[2];
+ m1[1] = ptm[0] * btm[1] + ptm[1] * btm[3];
+ m1[2] = ptm[2] * btm[0] + ptm[3] * btm[2];
+ m1[3] = ptm[2] * btm[1] + ptm[3] * btm[3];
+ m1[4] = ptm[4] * btm[0] + ptm[5] * btm[2] + btm[4];
+ m1[5] = ptm[4] * btm[1] + ptm[5] * btm[3] + btm[5];
+ // m = m1 * iCTM = (PTM * BTM) * (iCTM)
+ m[0] = m1[0] * ictm[0] + m1[1] * ictm[2];
+ m[1] = m1[0] * ictm[1] + m1[1] * ictm[3];
+ m[2] = m1[2] * ictm[0] + m1[3] * ictm[2];
+ m[3] = m1[2] * ictm[1] + m1[3] * ictm[3];
+ m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4];
+ m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5];
+
+ // set the new matrix
+ state->concatCTM(m[0], m[1], m[2], m[3], m[4], m[5]);
+ out->updateCTM(state, m[0], m[1], m[2], m[3], m[4], m[5]);
+
+#if 1 //~tmp: turn off anti-aliasing temporarily
+ GBool vaa = out->getVectorAntialias();
+ if (vaa) {
+ out->setVectorAntialias(gFalse);
+ }
+#endif
+
+ // do shading type-specific operations
+ switch (shading->getType()) {
+ case 1:
+ doFunctionShFill((GfxFunctionShading *)shading);
+ break;
+ case 2:
+ doAxialShFill((GfxAxialShading *)shading);
+ break;
+ case 3:
+ doRadialShFill((GfxRadialShading *)shading);
+ break;
+ case 4:
+ case 5:
+ doGouraudTriangleShFill((GfxGouraudTriangleShading *)shading);
+ break;
+ case 6:
+ case 7:
+ doPatchMeshShFill((GfxPatchMeshShading *)shading);
+ break;
+ }
+
+#if 1 //~tmp: turn off anti-aliasing temporarily
+ if (vaa) {
+ out->setVectorAntialias(gTrue);
+ }
+#endif
+
+ // restore graphics state
+ restoreState();
+ state->setPath(savedPath);
+}
+
+void Gfx::opShFill(Object args[], int /*numArgs*/) {
+ GfxShading *shading;
+ GfxPath *savedPath;
+ double xMin, yMin, xMax, yMax;
+
+ if (!(shading = res->lookupShading(args[0].getName()))) {
+ return;
+ }
+
+ // save current graphics state
+ savedPath = state->getPath()->copy();
+ saveState();
+
+ // clip to bbox
+ if (shading->getHasBBox()) {
+ shading->getBBox(&xMin, &yMin, &xMax, &yMax);
+ state->moveTo(xMin, yMin);
+ state->lineTo(xMax, yMin);
+ state->lineTo(xMax, yMax);
+ state->lineTo(xMin, yMax);
+ state->closePath();
+ state->clip();
+ out->clip(state);
+ state->clearPath();
+ }
+
+ // set the color space
+ state->setFillColorSpace(shading->getColorSpace()->copy());
+ out->updateFillColorSpace(state);
+
+#if 1 //~tmp: turn off anti-aliasing temporarily
+ GBool vaa = out->getVectorAntialias();
+ if (vaa) {
+ out->setVectorAntialias(gFalse);
+ }
+#endif
+
+ // do shading type-specific operations
+ switch (shading->getType()) {
+ case 1:
+ doFunctionShFill((GfxFunctionShading *)shading);
+ break;
+ case 2:
+ doAxialShFill((GfxAxialShading *)shading);
+ break;
+ case 3:
+ doRadialShFill((GfxRadialShading *)shading);
+ break;
+ case 4:
+ case 5:
+ doGouraudTriangleShFill((GfxGouraudTriangleShading *)shading);
+ break;
+ case 6:
+ case 7:
+ doPatchMeshShFill((GfxPatchMeshShading *)shading);
+ break;
+ }
+
+#if 1 //~tmp: turn off anti-aliasing temporarily
+ if (vaa) {
+ out->setVectorAntialias(gTrue);
+ }
+#endif
+
+ // restore graphics state
+ restoreState();
+ state->setPath(savedPath);
+
+ delete shading;
+}
+
+void Gfx::doFunctionShFill(GfxFunctionShading *shading) {
+ double x0, y0, x1, y1;
+ GfxColor colors[4];
+
+ if (out->useShadedFills() &&
+ out->functionShadedFill(state, shading)) {
+ return;
+ }
+
+ shading->getDomain(&x0, &y0, &x1, &y1);
+ shading->getColor(x0, y0, &colors[0]);
+ shading->getColor(x0, y1, &colors[1]);
+ shading->getColor(x1, y0, &colors[2]);
+ shading->getColor(x1, y1, &colors[3]);
+ doFunctionShFill1(shading, x0, y0, x1, y1, colors, 0);
+}
+
+void Gfx::doFunctionShFill1(GfxFunctionShading *shading,
+ double x0, double y0,
+ double x1, double y1,
+ GfxColor *colors, int depth) {
+ GfxColor fillColor;
+ GfxColor color0M, color1M, colorM0, colorM1, colorMM;
+ GfxColor colors2[4];
+ double *matrix;
+ double xM, yM;
+ int nComps, i, j;
+
+ nComps = shading->getColorSpace()->getNComps();
+ matrix = shading->getMatrix();
+
+ // compare the four corner colors
+ for (i = 0; i < 4; ++i) {
+ for (j = 0; j < nComps; ++j) {
+ if (abs(colors[i].c[j] - colors[(i+1)&3].c[j]) > functionColorDelta) {
+ break;
+ }
+ }
+ if (j < nComps) {
+ break;
+ }
+ }
+
+ // center of the rectangle
+ xM = 0.5 * (x0 + x1);
+ yM = 0.5 * (y0 + y1);
+
+ // the four corner colors are close (or we hit the recursive limit)
+ // -- fill the rectangle; but require at least one subdivision
+ // (depth==0) to avoid problems when the four outer corners of the
+ // shaded region are the same color
+ if ((i == 4 && depth > 0) || depth == functionMaxDepth) {
+
+ // use the center color
+ shading->getColor(xM, yM, &fillColor);
+ state->setFillColor(&fillColor);
+ out->updateFillColor(state);
+
+ // fill the rectangle
+ state->moveTo(x0 * matrix[0] + y0 * matrix[2] + matrix[4],
+ x0 * matrix[1] + y0 * matrix[3] + matrix[5]);
+ state->lineTo(x1 * matrix[0] + y0 * matrix[2] + matrix[4],
+ x1 * matrix[1] + y0 * matrix[3] + matrix[5]);
+ state->lineTo(x1 * matrix[0] + y1 * matrix[2] + matrix[4],
+ x1 * matrix[1] + y1 * matrix[3] + matrix[5]);
+ state->lineTo(x0 * matrix[0] + y1 * matrix[2] + matrix[4],
+ x0 * matrix[1] + y1 * matrix[3] + matrix[5]);
+ state->closePath();
+ out->fill(state);
+ state->clearPath();
+
+ // the four corner colors are not close enough -- subdivide the
+ // rectangle
+ } else {
+
+ // colors[0] colorM0 colors[2]
+ // (x0,y0) (xM,y0) (x1,y0)
+ // +----------+----------+
+ // | | |
+ // | UL | UR |
+ // color0M | colorMM | color1M
+ // (x0,yM) +----------+----------+ (x1,yM)
+ // | (xM,yM) |
+ // | LL | LR |
+ // | | |
+ // +----------+----------+
+ // colors[1] colorM1 colors[3]
+ // (x0,y1) (xM,y1) (x1,y1)
+
+ shading->getColor(x0, yM, &color0M);
+ shading->getColor(x1, yM, &color1M);
+ shading->getColor(xM, y0, &colorM0);
+ shading->getColor(xM, y1, &colorM1);
+ shading->getColor(xM, yM, &colorMM);
+
+ // upper-left sub-rectangle
+ colors2[0] = colors[0];
+ colors2[1] = color0M;
+ colors2[2] = colorM0;
+ colors2[3] = colorMM;
+ doFunctionShFill1(shading, x0, y0, xM, yM, colors2, depth + 1);
+
+ // lower-left sub-rectangle
+ colors2[0] = color0M;
+ colors2[1] = colors[1];
+ colors2[2] = colorMM;
+ colors2[3] = colorM1;
+ doFunctionShFill1(shading, x0, yM, xM, y1, colors2, depth + 1);
+
+ // upper-right sub-rectangle
+ colors2[0] = colorM0;
+ colors2[1] = colorMM;
+ colors2[2] = colors[2];
+ colors2[3] = color1M;
+ doFunctionShFill1(shading, xM, y0, x1, yM, colors2, depth + 1);
+
+ // lower-right sub-rectangle
+ colors2[0] = colorMM;
+ colors2[1] = colorM1;
+ colors2[2] = color1M;
+ colors2[3] = colors[3];
+ doFunctionShFill1(shading, xM, yM, x1, y1, colors2, depth + 1);
+ }
+}
+
+void Gfx::doAxialShFill(GfxAxialShading *shading) {
+ double xMin, yMin, xMax, yMax;
+ double x0, y0, x1, y1;
+ double dx, dy, mul;
+ GBool dxZero, dyZero;
+ double tMin, tMax, t, tx, ty;
+ double s[4], sMin, sMax, tmp;
+ double ux0, uy0, ux1, uy1, vx0, vy0, vx1, vy1;
+ double t0, t1, tt;
+ double ta[axialMaxSplits + 1];
+ int next[axialMaxSplits + 1];
+ GfxColor color0, color1;
+ int nComps;
+ int i, j, k, kk;
+
+ if (out->useShadedFills() &&
+ out->axialShadedFill(state, shading)) {
+ return;
+ }
+
+ // get the clip region bbox
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+
+ // compute min and max t values, based on the four corners of the
+ // clip region bbox
+ shading->getCoords(&x0, &y0, &x1, &y1);
+ dx = x1 - x0;
+ dy = y1 - y0;
+ dxZero = fabs(dx) < 0.01;
+ dyZero = fabs(dy) < 0.01;
+ if (dxZero && dyZero) {
+ tMin = tMax = 0;
+ } else {
+ mul = 1 / (dx * dx + dy * dy);
+ tMin = tMax = ((xMin - x0) * dx + (yMin - y0) * dy) * mul;
+ t = ((xMin - x0) * dx + (yMax - y0) * dy) * mul;
+ if (t < tMin) {
+ tMin = t;
+ } else if (t > tMax) {
+ tMax = t;
+ }
+ t = ((xMax - x0) * dx + (yMin - y0) * dy) * mul;
+ if (t < tMin) {
+ tMin = t;
+ } else if (t > tMax) {
+ tMax = t;
+ }
+ t = ((xMax - x0) * dx + (yMax - y0) * dy) * mul;
+ if (t < tMin) {
+ tMin = t;
+ } else if (t > tMax) {
+ tMax = t;
+ }
+ if (tMin < 0 && !shading->getExtend0()) {
+ tMin = 0;
+ }
+ if (tMax > 1 && !shading->getExtend1()) {
+ tMax = 1;
+ }
+ }
+
+ // get the function domain
+ t0 = shading->getDomain0();
+ t1 = shading->getDomain1();
+
+ // Traverse the t axis and do the shading.
+ //
+ // For each point (tx, ty) on the t axis, consider a line through
+ // that point perpendicular to the t axis:
+ //
+ // x(s) = tx + s * -dy --> s = (x - tx) / -dy
+ // y(s) = ty + s * dx --> s = (y - ty) / dx
+ //
+ // Then look at the intersection of this line with the bounding box
+ // (xMin, yMin, xMax, yMax). In the general case, there are four
+ // intersection points:
+ //
+ // s0 = (xMin - tx) / -dy
+ // s1 = (xMax - tx) / -dy
+ // s2 = (yMin - ty) / dx
+ // s3 = (yMax - ty) / dx
+ //
+ // and we want the middle two s values.
+ //
+ // In the case where dx = 0, take s0 and s1; in the case where dy =
+ // 0, take s2 and s3.
+ //
+ // Each filled polygon is bounded by two of these line segments
+ // perpdendicular to the t axis.
+ //
+ // The t axis is bisected into smaller regions until the color
+ // difference across a region is small enough, and then the region
+ // is painted with a single color.
+
+ // set up: require at least one split to avoid problems when the two
+ // ends of the t axis have the same color
+ nComps = shading->getColorSpace()->getNComps();
+ ta[0] = tMin;
+ next[0] = axialMaxSplits / 2;
+ ta[axialMaxSplits / 2] = 0.5 * (tMin + tMax);
+ next[axialMaxSplits / 2] = axialMaxSplits;
+ ta[axialMaxSplits] = tMax;
+
+ // compute the color at t = tMin
+ if (tMin < 0) {
+ tt = t0;
+ } else if (tMin > 1) {
+ tt = t1;
+ } else {
+ tt = t0 + (t1 - t0) * tMin;
+ }
+ shading->getColor(tt, &color0);
+
+ // compute the coordinates of the point on the t axis at t = tMin;
+ // then compute the intersection of the perpendicular line with the
+ // bounding box
+ tx = x0 + tMin * dx;
+ ty = y0 + tMin * dy;
+ if (dxZero && dyZero) {
+ sMin = sMax = 0;
+ } else if (dxZero) {
+ sMin = (xMin - tx) / -dy;
+ sMax = (xMax - tx) / -dy;
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ } else if (dyZero) {
+ sMin = (yMin - ty) / dx;
+ sMax = (yMax - ty) / dx;
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ } else {
+ s[0] = (yMin - ty) / dx;
+ s[1] = (yMax - ty) / dx;
+ s[2] = (xMin - tx) / -dy;
+ s[3] = (xMax - tx) / -dy;
+ for (j = 0; j < 3; ++j) {
+ kk = j;
+ for (k = j + 1; k < 4; ++k) {
+ if (s[k] < s[kk]) {
+ kk = k;
+ }
+ }
+ tmp = s[j]; s[j] = s[kk]; s[kk] = tmp;
+ }
+ sMin = s[1];
+ sMax = s[2];
+ }
+ ux0 = tx - sMin * dy;
+ uy0 = ty + sMin * dx;
+ vx0 = tx - sMax * dy;
+ vy0 = ty + sMax * dx;
+
+ i = 0;
+ while (i < axialMaxSplits) {
+
+ // bisect until color difference is small enough or we hit the
+ // bisection limit
+ j = next[i];
+ while (j > i + 1) {
+ if (ta[j] < 0) {
+ tt = t0;
+ } else if (ta[j] > 1) {
+ tt = t1;
+ } else {
+ tt = t0 + (t1 - t0) * ta[j];
+ }
+ shading->getColor(tt, &color1);
+ for (k = 0; k < nComps; ++k) {
+ if (abs(color1.c[k] - color0.c[k]) > axialColorDelta) {
+ break;
+ }
+ }
+ if (k == nComps) {
+ break;
+ }
+ k = (i + j) / 2;
+ ta[k] = 0.5 * (ta[i] + ta[j]);
+ next[i] = k;
+ next[k] = j;
+ j = k;
+ }
+
+ // use the average of the colors of the two sides of the region
+ for (k = 0; k < nComps; ++k) {
+ color0.c[k] = (color0.c[k] + color1.c[k]) / 2;
+ }
+
+ // compute the coordinates of the point on the t axis; then
+ // compute the intersection of the perpendicular line with the
+ // bounding box
+ tx = x0 + ta[j] * dx;
+ ty = y0 + ta[j] * dy;
+ if (dxZero && dyZero) {
+ sMin = sMax = 0;
+ } else if (dxZero) {
+ sMin = (xMin - tx) / -dy;
+ sMax = (xMax - tx) / -dy;
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ } else if (dyZero) {
+ sMin = (yMin - ty) / dx;
+ sMax = (yMax - ty) / dx;
+ if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; }
+ } else {
+ s[0] = (yMin - ty) / dx;
+ s[1] = (yMax - ty) / dx;
+ s[2] = (xMin - tx) / -dy;
+ s[3] = (xMax - tx) / -dy;
+ for (j = 0; j < 3; ++j) {
+ kk = j;
+ for (k = j + 1; k < 4; ++k) {
+ if (s[k] < s[kk]) {
+ kk = k;
+ }
+ }
+ tmp = s[j]; s[j] = s[kk]; s[kk] = tmp;
+ }
+ sMin = s[1];
+ sMax = s[2];
+ }
+ ux1 = tx - sMin * dy;
+ uy1 = ty + sMin * dx;
+ vx1 = tx - sMax * dy;
+ vy1 = ty + sMax * dx;
+
+ // set the color
+ state->setFillColor(&color0);
+ out->updateFillColor(state);
+
+ // fill the region
+ state->moveTo(ux0, uy0);
+ state->lineTo(vx0, vy0);
+ state->lineTo(vx1, vy1);
+ state->lineTo(ux1, uy1);
+ state->closePath();
+ out->fill(state);
+ state->clearPath();
+
+ // set up for next region
+ ux0 = ux1;
+ uy0 = uy1;
+ vx0 = vx1;
+ vy0 = vy1;
+ color0 = color1;
+ i = next[i];
+ }
+}
+
+void Gfx::doRadialShFill(GfxRadialShading *shading) {
+ double xMin, yMin, xMax, yMax;
+ double x0, y0, r0, x1, y1, r1, t0, t1;
+ int nComps;
+ GfxColor colorA, colorB;
+ double xa, ya, xb, yb, ra, rb;
+ double ta, tb, sa, sb;
+ double sz, xz, yz, sMin, sMax;
+ GBool enclosed;
+ int ia, ib, k, n;
+ double *ctm;
+ double theta, alpha, angle, t;
+
+ if (out->useShadedFills() &&
+ out->radialShadedFill(state, shading)) {
+ return;
+ }
+
+ // get the shading info
+ shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1);
+ t0 = shading->getDomain0();
+ t1 = shading->getDomain1();
+ nComps = shading->getColorSpace()->getNComps();
+
+ // Compute the point at which r(s) = 0; check for the enclosed
+ // circles case; and compute the angles for the tangent lines.
+ if (x0 == x1 && y0 == y1) {
+ enclosed = gTrue;
+ theta = 0; // make gcc happy
+ sz = 0; // make gcc happy
+ } else if (r0 == r1) {
+ enclosed = gFalse;
+ theta = 0;
+ sz = 0; // make gcc happy
+ } else {
+ sz = -r0 / (r1 - r0);
+ xz = x0 + sz * (x1 - x0);
+ yz = y0 + sz * (y1 - y0);
+ enclosed = (xz - x0) * (xz - x0) + (yz - y0) * (yz - y0) <= r0 * r0;
+ theta = asin(r0 / sqrt((x0 - xz) * (x0 - xz) + (y0 - yz) * (y0 - yz)));
+ if (r0 > r1) {
+ theta = -theta;
+ }
+ }
+ if (enclosed) {
+ alpha = 0;
+ } else {
+ alpha = atan2(y1 - y0, x1 - x0);
+ }
+
+ // compute the (possibly extended) s range
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+ if (enclosed) {
+ sMin = 0;
+ sMax = 1;
+ } else {
+ sMin = 1;
+ sMax = 0;
+ // solve for x(s) + r(s) = xMin
+ if ((x1 + r1) - (x0 + r0) != 0) {
+ sa = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0));
+ if (sa < sMin) {
+ sMin = sa;
+ } else if (sa > sMax) {
+ sMax = sa;
+ }
+ }
+ // solve for x(s) - r(s) = xMax
+ if ((x1 - r1) - (x0 - r0) != 0) {
+ sa = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0));
+ if (sa < sMin) {
+ sMin = sa;
+ } else if (sa > sMax) {
+ sMax = sa;
+ }
+ }
+ // solve for y(s) + r(s) = yMin
+ if ((y1 + r1) - (y0 + r0) != 0) {
+ sa = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0));
+ if (sa < sMin) {
+ sMin = sa;
+ } else if (sa > sMax) {
+ sMax = sa;
+ }
+ }
+ // solve for y(s) - r(s) = yMax
+ if ((y1 - r1) - (y0 - r0) != 0) {
+ sa = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0));
+ if (sa < sMin) {
+ sMin = sa;
+ } else if (sa > sMax) {
+ sMax = sa;
+ }
+ }
+ // check against sz
+ if (r0 < r1) {
+ if (sMin < sz) {
+ sMin = sz;
+ }
+ } else if (r0 > r1) {
+ if (sMax > sz) {
+ sMax = sz;
+ }
+ }
+ // check the 'extend' flags
+ if (!shading->getExtend0() && sMin < 0) {
+ sMin = 0;
+ }
+ if (!shading->getExtend1() && sMax > 1) {
+ sMax = 1;
+ }
+ }
+
+ // compute the number of steps into which circles must be divided to
+ // achieve a curve flatness of 0.1 pixel in device space for the
+ // largest circle (note that "device space" is 72 dpi when generating
+ // PostScript, hence the relatively small 0.1 pixel accuracy)
+ ctm = state->getCTM();
+ t = fabs(ctm[0]);
+ if (fabs(ctm[1]) > t) {
+ t = fabs(ctm[1]);
+ }
+ if (fabs(ctm[2]) > t) {
+ t = fabs(ctm[2]);
+ }
+ if (fabs(ctm[3]) > t) {
+ t = fabs(ctm[3]);
+ }
+ if (r0 > r1) {
+ t *= r0;
+ } else {
+ t *= r1;
+ }
+ if (t < 1) {
+ n = 3;
+ } else {
+ n = (int)(M_PI / acos(1 - 0.1 / t));
+ if (n < 3) {
+ n = 3;
+ } else if (n > 200) {
+ n = 200;
+ }
+ }
+
+ // setup for the start circle
+ ia = 0;
+ sa = sMin;
+ ta = t0 + sa * (t1 - t0);
+ xa = x0 + sa * (x1 - x0);
+ ya = y0 + sa * (y1 - y0);
+ ra = r0 + sa * (r1 - r0);
+ if (ta < t0) {
+ shading->getColor(t0, &colorA);
+ } else if (ta > t1) {
+ shading->getColor(t1, &colorA);
+ } else {
+ shading->getColor(ta, &colorA);
+ }
+
+ // fill the circles
+ while (ia < radialMaxSplits) {
+
+ // go as far along the t axis (toward t1) as we can, such that the
+ // color difference is within the tolerance (radialColorDelta) --
+ // this uses bisection (between the current value, t, and t1),
+ // limited to radialMaxSplits points along the t axis; require at
+ // least one split to avoid problems when the innermost and
+ // outermost colors are the same
+ ib = radialMaxSplits;
+ sb = sMax;
+ tb = t0 + sb * (t1 - t0);
+ if (tb < t0) {
+ shading->getColor(t0, &colorB);
+ } else if (tb > t1) {
+ shading->getColor(t1, &colorB);
+ } else {
+ shading->getColor(tb, &colorB);
+ }
+ while (ib - ia > 1) {
+ for (k = 0; k < nComps; ++k) {
+ if (abs(colorB.c[k] - colorA.c[k]) > radialColorDelta) {
+ break;
+ }
+ }
+ if (k == nComps && ib < radialMaxSplits) {
+ break;
+ }
+ ib = (ia + ib) / 2;
+ sb = sMin + ((double)ib / (double)radialMaxSplits) * (sMax - sMin);
+ tb = t0 + sb * (t1 - t0);
+ if (tb < t0) {
+ shading->getColor(t0, &colorB);
+ } else if (tb > t1) {
+ shading->getColor(t1, &colorB);
+ } else {
+ shading->getColor(tb, &colorB);
+ }
+ }
+
+ // compute center and radius of the circle
+ xb = x0 + sb * (x1 - x0);
+ yb = y0 + sb * (y1 - y0);
+ rb = r0 + sb * (r1 - r0);
+
+ // use the average of the colors at the two circles
+ for (k = 0; k < nComps; ++k) {
+ colorA.c[k] = (colorA.c[k] + colorB.c[k]) / 2;
+ }
+ state->setFillColor(&colorA);
+ out->updateFillColor(state);
+
+ if (enclosed) {
+
+ // construct path for first circle (counterclockwise)
+ state->moveTo(xa + ra, ya);
+ for (k = 1; k < n; ++k) {
+ angle = ((double)k / (double)n) * 2 * M_PI;
+ state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
+ }
+ state->closePath();
+
+ // construct and append path for second circle (clockwise)
+ state->moveTo(xb + rb, yb);
+ for (k = 1; k < n; ++k) {
+ angle = -((double)k / (double)n) * 2 * M_PI;
+ state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle));
+ }
+ state->closePath();
+
+ } else {
+
+ // construct the first subpath (clockwise)
+ state->moveTo(xa + ra * cos(alpha + theta + 0.5 * M_PI),
+ ya + ra * sin(alpha + theta + 0.5 * M_PI));
+ for (k = 0; k < n; ++k) {
+ angle = alpha + theta + 0.5 * M_PI
+ - ((double)k / (double)n) * (2 * theta + M_PI);
+ state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle));
+ }
+ for (k = 0; k < n; ++k) {
+ angle = alpha - theta - 0.5 * M_PI
+ + ((double)k / (double)n) * (2 * theta - M_PI);
+ state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
+ }
+ state->closePath();
+
+ // construct the second subpath (counterclockwise)
+ state->moveTo(xa + ra * cos(alpha + theta + 0.5 * M_PI),
+ ya + ra * sin(alpha + theta + 0.5 * M_PI));
+ for (k = 0; k < n; ++k) {
+ angle = alpha + theta + 0.5 * M_PI
+ + ((double)k / (double)n) * (-2 * theta + M_PI);
+ state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle));
+ }
+ for (k = 0; k < n; ++k) {
+ angle = alpha - theta - 0.5 * M_PI
+ + ((double)k / (double)n) * (2 * theta + M_PI);
+ state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
+ }
+ state->closePath();
+ }
+
+ // fill the path
+ out->fill(state);
+ state->clearPath();
+
+ // step to the next value of t
+ ia = ib;
+ sa = sb;
+ ta = tb;
+ xa = xb;
+ ya = yb;
+ ra = rb;
+ colorA = colorB;
+ }
+
+ if (enclosed) {
+ // extend the smaller circle
+ if ((shading->getExtend0() && r0 <= r1) ||
+ (shading->getExtend1() && r1 < r0)) {
+ if (r0 <= r1) {
+ ta = t0;
+ ra = r0;
+ xa = x0;
+ ya = y0;
+ } else {
+ ta = t1;
+ ra = r1;
+ xa = x1;
+ ya = y1;
+ }
+ shading->getColor(ta, &colorA);
+ state->setFillColor(&colorA);
+ out->updateFillColor(state);
+ state->moveTo(xa + ra, ya);
+ for (k = 1; k < n; ++k) {
+ angle = ((double)k / (double)n) * 2 * M_PI;
+ state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
+ }
+ state->closePath();
+ out->fill(state);
+ state->clearPath();
+ }
+
+ // extend the larger circle
+ if ((shading->getExtend0() && r0 > r1) ||
+ (shading->getExtend1() && r1 >= r0)) {
+ if (r0 > r1) {
+ ta = t0;
+ ra = r0;
+ xa = x0;
+ ya = y0;
+ } else {
+ ta = t1;
+ ra = r1;
+ xa = x1;
+ ya = y1;
+ }
+ shading->getColor(ta, &colorA);
+ state->setFillColor(&colorA);
+ out->updateFillColor(state);
+ state->moveTo(xMin, yMin);
+ state->lineTo(xMin, yMax);
+ state->lineTo(xMax, yMax);
+ state->lineTo(xMax, yMin);
+ state->closePath();
+ state->moveTo(xa + ra, ya);
+ for (k = 1; k < n; ++k) {
+ angle = ((double)k / (double)n) * 2 * M_PI;
+ state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
+ }
+ state->closePath();
+ out->fill(state);
+ state->clearPath();
+ }
+ }
+}
+
+void Gfx::doGouraudTriangleShFill(GfxGouraudTriangleShading *shading) {
+ double x0, y0, x1, y1, x2, y2;
+ GfxColor color0, color1, color2;
+ int i;
+
+ for (i = 0; i < shading->getNTriangles(); ++i) {
+ shading->getTriangle(i, &x0, &y0, &color0,
+ &x1, &y1, &color1,
+ &x2, &y2, &color2);
+ gouraudFillTriangle(x0, y0, &color0, x1, y1, &color1, x2, y2, &color2,
+ shading->getColorSpace()->getNComps(), 0);
+ }
+}
+
+void Gfx::gouraudFillTriangle(double x0, double y0, GfxColor *color0,
+ double x1, double y1, GfxColor *color1,
+ double x2, double y2, GfxColor *color2,
+ int nComps, int depth) {
+ double x01, y01, x12, y12, x20, y20;
+ GfxColor color01, color12, color20;
+ int i;
+
+ for (i = 0; i < nComps; ++i) {
+ if (abs(color0->c[i] - color1->c[i]) > gouraudColorDelta ||
+ abs(color1->c[i] - color2->c[i]) > gouraudColorDelta) {
+ break;
+ }
+ }
+ if (i == nComps || depth == gouraudMaxDepth) {
+ state->setFillColor(color0);
+ out->updateFillColor(state);
+ state->moveTo(x0, y0);
+ state->lineTo(x1, y1);
+ state->lineTo(x2, y2);
+ state->closePath();
+ out->fill(state);
+ state->clearPath();
+ } else {
+ x01 = 0.5 * (x0 + x1);
+ y01 = 0.5 * (y0 + y1);
+ x12 = 0.5 * (x1 + x2);
+ y12 = 0.5 * (y1 + y2);
+ x20 = 0.5 * (x2 + x0);
+ y20 = 0.5 * (y2 + y0);
+ //~ if the shading has a Function, this should interpolate on the
+ //~ function parameter, not on the color components
+ for (i = 0; i < nComps; ++i) {
+ color01.c[i] = (color0->c[i] + color1->c[i]) / 2;
+ color12.c[i] = (color1->c[i] + color2->c[i]) / 2;
+ color20.c[i] = (color2->c[i] + color0->c[i]) / 2;
+ }
+ gouraudFillTriangle(x0, y0, color0, x01, y01, &color01,
+ x20, y20, &color20, nComps, depth + 1);
+ gouraudFillTriangle(x01, y01, &color01, x1, y1, color1,
+ x12, y12, &color12, nComps, depth + 1);
+ gouraudFillTriangle(x01, y01, &color01, x12, y12, &color12,
+ x20, y20, &color20, nComps, depth + 1);
+ gouraudFillTriangle(x20, y20, &color20, x12, y12, &color12,
+ x2, y2, color2, nComps, depth + 1);
+ }
+}
+
+void Gfx::doPatchMeshShFill(GfxPatchMeshShading *shading) {
+ int start, i;
+
+ if (shading->getNPatches() > 128) {
+ start = 3;
+ } else if (shading->getNPatches() > 64) {
+ start = 2;
+ } else if (shading->getNPatches() > 16) {
+ start = 1;
+ } else {
+ start = 0;
+ }
+ for (i = 0; i < shading->getNPatches(); ++i) {
+ fillPatch(shading->getPatch(i), shading->getColorSpace()->getNComps(),
+ start);
+ }
+}
+
+void Gfx::fillPatch(GfxPatch *patch, int nComps, int depth) {
+ GfxPatch patch00, patch01, patch10, patch11;
+ double xx[4][8], yy[4][8];
+ double xxm, yym;
+ int i;
+
+ for (i = 0; i < nComps; ++i) {
+ if (abs(patch->color[0][0].c[i] - patch->color[0][1].c[i])
+ > patchColorDelta ||
+ abs(patch->color[0][1].c[i] - patch->color[1][1].c[i])
+ > patchColorDelta ||
+ abs(patch->color[1][1].c[i] - patch->color[1][0].c[i])
+ > patchColorDelta ||
+ abs(patch->color[1][0].c[i] - patch->color[0][0].c[i])
+ > patchColorDelta) {
+ break;
+ }
+ }
+ if (i == nComps || depth == patchMaxDepth) {
+ state->setFillColor(&patch->color[0][0]);
+ out->updateFillColor(state);
+ state->moveTo(patch->x[0][0], patch->y[0][0]);
+ state->curveTo(patch->x[0][1], patch->y[0][1],
+ patch->x[0][2], patch->y[0][2],
+ patch->x[0][3], patch->y[0][3]);
+ state->curveTo(patch->x[1][3], patch->y[1][3],
+ patch->x[2][3], patch->y[2][3],
+ patch->x[3][3], patch->y[3][3]);
+ state->curveTo(patch->x[3][2], patch->y[3][2],
+ patch->x[3][1], patch->y[3][1],
+ patch->x[3][0], patch->y[3][0]);
+ state->curveTo(patch->x[2][0], patch->y[2][0],
+ patch->x[1][0], patch->y[1][0],
+ patch->x[0][0], patch->y[0][0]);
+ state->closePath();
+ out->fill(state);
+ state->clearPath();
+ } else {
+ for (i = 0; i < 4; ++i) {
+ xx[i][0] = patch->x[i][0];
+ yy[i][0] = patch->y[i][0];
+ xx[i][1] = 0.5 * (patch->x[i][0] + patch->x[i][1]);
+ yy[i][1] = 0.5 * (patch->y[i][0] + patch->y[i][1]);
+ xxm = 0.5 * (patch->x[i][1] + patch->x[i][2]);
+ yym = 0.5 * (patch->y[i][1] + patch->y[i][2]);
+ xx[i][6] = 0.5 * (patch->x[i][2] + patch->x[i][3]);
+ yy[i][6] = 0.5 * (patch->y[i][2] + patch->y[i][3]);
+ xx[i][2] = 0.5 * (xx[i][1] + xxm);
+ yy[i][2] = 0.5 * (yy[i][1] + yym);
+ xx[i][5] = 0.5 * (xxm + xx[i][6]);
+ yy[i][5] = 0.5 * (yym + yy[i][6]);
+ xx[i][3] = xx[i][4] = 0.5 * (xx[i][2] + xx[i][5]);
+ yy[i][3] = yy[i][4] = 0.5 * (yy[i][2] + yy[i][5]);
+ xx[i][7] = patch->x[i][3];
+ yy[i][7] = patch->y[i][3];
+ }
+ for (i = 0; i < 4; ++i) {
+ patch00.x[0][i] = xx[0][i];
+ patch00.y[0][i] = yy[0][i];
+ patch00.x[1][i] = 0.5 * (xx[0][i] + xx[1][i]);
+ patch00.y[1][i] = 0.5 * (yy[0][i] + yy[1][i]);
+ xxm = 0.5 * (xx[1][i] + xx[2][i]);
+ yym = 0.5 * (yy[1][i] + yy[2][i]);
+ patch10.x[2][i] = 0.5 * (xx[2][i] + xx[3][i]);
+ patch10.y[2][i] = 0.5 * (yy[2][i] + yy[3][i]);
+ patch00.x[2][i] = 0.5 * (patch00.x[1][i] + xxm);
+ patch00.y[2][i] = 0.5 * (patch00.y[1][i] + yym);
+ patch10.x[1][i] = 0.5 * (xxm + patch10.x[2][i]);
+ patch10.y[1][i] = 0.5 * (yym + patch10.y[2][i]);
+ patch00.x[3][i] = 0.5 * (patch00.x[2][i] + patch10.x[1][i]);
+ patch00.y[3][i] = 0.5 * (patch00.y[2][i] + patch10.y[1][i]);
+ patch10.x[0][i] = patch00.x[3][i];
+ patch10.y[0][i] = patch00.y[3][i];
+ patch10.x[3][i] = xx[3][i];
+ patch10.y[3][i] = yy[3][i];
+ }
+ for (i = 4; i < 8; ++i) {
+ patch01.x[0][i-4] = xx[0][i];
+ patch01.y[0][i-4] = yy[0][i];
+ patch01.x[1][i-4] = 0.5 * (xx[0][i] + xx[1][i]);
+ patch01.y[1][i-4] = 0.5 * (yy[0][i] + yy[1][i]);
+ xxm = 0.5 * (xx[1][i] + xx[2][i]);
+ yym = 0.5 * (yy[1][i] + yy[2][i]);
+ patch11.x[2][i-4] = 0.5 * (xx[2][i] + xx[3][i]);
+ patch11.y[2][i-4] = 0.5 * (yy[2][i] + yy[3][i]);
+ patch01.x[2][i-4] = 0.5 * (patch01.x[1][i-4] + xxm);
+ patch01.y[2][i-4] = 0.5 * (patch01.y[1][i-4] + yym);
+ patch11.x[1][i-4] = 0.5 * (xxm + patch11.x[2][i-4]);
+ patch11.y[1][i-4] = 0.5 * (yym + patch11.y[2][i-4]);
+ patch01.x[3][i-4] = 0.5 * (patch01.x[2][i-4] + patch11.x[1][i-4]);
+ patch01.y[3][i-4] = 0.5 * (patch01.y[2][i-4] + patch11.y[1][i-4]);
+ patch11.x[0][i-4] = patch01.x[3][i-4];
+ patch11.y[0][i-4] = patch01.y[3][i-4];
+ patch11.x[3][i-4] = xx[3][i];
+ patch11.y[3][i-4] = yy[3][i];
+ }
+ //~ if the shading has a Function, this should interpolate on the
+ //~ function parameter, not on the color components
+ for (i = 0; i < nComps; ++i) {
+ patch00.color[0][0].c[i] = patch->color[0][0].c[i];
+ patch00.color[0][1].c[i] = (patch->color[0][0].c[i] +
+ patch->color[0][1].c[i]) / 2;
+ patch01.color[0][0].c[i] = patch00.color[0][1].c[i];
+ patch01.color[0][1].c[i] = patch->color[0][1].c[i];
+ patch01.color[1][1].c[i] = (patch->color[0][1].c[i] +
+ patch->color[1][1].c[i]) / 2;
+ patch11.color[0][1].c[i] = patch01.color[1][1].c[i];
+ patch11.color[1][1].c[i] = patch->color[1][1].c[i];
+ patch11.color[1][0].c[i] = (patch->color[1][1].c[i] +
+ patch->color[1][0].c[i]) / 2;
+ patch10.color[1][1].c[i] = patch11.color[1][0].c[i];
+ patch10.color[1][0].c[i] = patch->color[1][0].c[i];
+ patch10.color[0][0].c[i] = (patch->color[1][0].c[i] +
+ patch->color[0][0].c[i]) / 2;
+ patch00.color[1][0].c[i] = patch10.color[0][0].c[i];
+ patch00.color[1][1].c[i] = (patch00.color[1][0].c[i] +
+ patch01.color[1][1].c[i]) / 2;
+ patch01.color[1][0].c[i] = patch00.color[1][1].c[i];
+ patch11.color[0][0].c[i] = patch00.color[1][1].c[i];
+ patch10.color[0][1].c[i] = patch00.color[1][1].c[i];
+ }
+ fillPatch(&patch00, nComps, depth + 1);
+ fillPatch(&patch10, nComps, depth + 1);
+ fillPatch(&patch01, nComps, depth + 1);
+ fillPatch(&patch11, nComps, depth + 1);
+ }
+}
+
+void Gfx::doEndPath() {
+ if (state->isCurPt() && clip != clipNone) {
+ state->clip();
+ if (clip == clipNormal) {
+ out->clip(state);
+ } else {
+ out->eoClip(state);
+ }
+ }
+ clip = clipNone;
+ state->clearPath();
+}
+
+//------------------------------------------------------------------------
+// path clipping operators
+//------------------------------------------------------------------------
+
+void Gfx::opClip(Object * /*args[]*/, int /*numArgs*/) {
+ clip = clipNormal;
+}
+
+void Gfx::opEOClip(Object * /*args[]*/, int /*numArgs*/) {
+ clip = clipEO;
+}
+
+//------------------------------------------------------------------------
+// text object operators
+//------------------------------------------------------------------------
+
+void Gfx::opBeginText(Object * /*args[]*/, int /*numArgs*/) {
+ state->setTextMat(1, 0, 0, 1, 0, 0);
+ state->textMoveTo(0, 0);
+ out->updateTextMat(state);
+ out->updateTextPos(state);
+ fontChanged = gTrue;
+}
+
+void Gfx::opEndText(Object * /*args[]*/, int /*numArgs*/) {
+ out->endTextObject(state);
+}
+
+//------------------------------------------------------------------------
+// text state operators
+//------------------------------------------------------------------------
+
+void Gfx::opSetCharSpacing(Object args[], int /*numArgs*/) {
+ state->setCharSpace(args[0].getNum());
+ out->updateCharSpace(state);
+}
+
+void Gfx::opSetFont(Object args[], int /*numArgs*/) {
+ GfxFont *font;
+
+ if (!(font = res->lookupFont(args[0].getName()))) {
+ return;
+ }
+ if (printCommands) {
+ printf(" font: tag=%s name='%s' %g\n",
+ font->getTag()->getCString(),
+ font->getName() ? font->getName()->getCString() : "???",
+ args[1].getNum());
+ fflush(stdout);
+ }
+ state->setFont(font, args[1].getNum());
+ fontChanged = gTrue;
+}
+
+void Gfx::opSetTextLeading(Object args[], int /*numArgs*/) {
+ state->setLeading(args[0].getNum());
+}
+
+void Gfx::opSetTextRender(Object args[], int /*numArgs*/) {
+ state->setRender(args[0].getInt());
+ out->updateRender(state);
+}
+
+void Gfx::opSetTextRise(Object args[], int /*numArgs*/) {
+ state->setRise(args[0].getNum());
+ out->updateRise(state);
+}
+
+void Gfx::opSetWordSpacing(Object args[], int /*numArgs*/) {
+ state->setWordSpace(args[0].getNum());
+ out->updateWordSpace(state);
+}
+
+void Gfx::opSetHorizScaling(Object args[], int /*numArgs*/) {
+ state->setHorizScaling(args[0].getNum());
+ out->updateHorizScaling(state);
+ fontChanged = gTrue;
+}
+
+//------------------------------------------------------------------------
+// text positioning operators
+//------------------------------------------------------------------------
+
+void Gfx::opTextMove(Object args[], int /*numArgs*/) {
+ double tx, ty;
+
+ tx = state->getLineX() + args[0].getNum();
+ ty = state->getLineY() + args[1].getNum();
+ state->textMoveTo(tx, ty);
+ out->updateTextPos(state);
+}
+
+void Gfx::opTextMoveSet(Object args[], int /*numArgs*/) {
+ double tx, ty;
+
+ tx = state->getLineX() + args[0].getNum();
+ ty = args[1].getNum();
+ state->setLeading(-ty);
+ ty += state->getLineY();
+ state->textMoveTo(tx, ty);
+ out->updateTextPos(state);
+}
+
+void Gfx::opSetTextMatrix(Object args[], int /*numArgs*/) {
+ state->setTextMat(args[0].getNum(), args[1].getNum(),
+ args[2].getNum(), args[3].getNum(),
+ args[4].getNum(), args[5].getNum());
+ state->textMoveTo(0, 0);
+ out->updateTextMat(state);
+ out->updateTextPos(state);
+ fontChanged = gTrue;
+}
+
+void Gfx::opTextNextLine(Object * /*args[]*/, int /*numArgs*/) {
+ double tx, ty;
+
+ tx = state->getLineX();
+ ty = state->getLineY() - state->getLeading();
+ state->textMoveTo(tx, ty);
+ out->updateTextPos(state);
+}
+
+//------------------------------------------------------------------------
+// text string operators
+//------------------------------------------------------------------------
+
+void Gfx::opShowText(Object args[], int /*numArgs*/) {
+ if (!state->getFont()) {
+ error(getPos(), "No font in show");
+ return;
+ }
+ if (fontChanged) {
+ out->updateFont(state);
+ fontChanged = gFalse;
+ }
+ out->beginStringOp(state);
+ doShowText(args[0].getString());
+ out->endStringOp(state);
+}
+
+void Gfx::opMoveShowText(Object args[], int /*numArgs*/) {
+ double tx, ty;
+
+ if (!state->getFont()) {
+ error(getPos(), "No font in move/show");
+ return;
+ }
+ if (fontChanged) {
+ out->updateFont(state);
+ fontChanged = gFalse;
+ }
+ tx = state->getLineX();
+ ty = state->getLineY() - state->getLeading();
+ state->textMoveTo(tx, ty);
+ out->updateTextPos(state);
+ out->beginStringOp(state);
+ doShowText(args[0].getString());
+ out->endStringOp(state);
+}
+
+void Gfx::opMoveSetShowText(Object args[], int /*numArgs*/) {
+ double tx, ty;
+
+ if (!state->getFont()) {
+ error(getPos(), "No font in move/set/show");
+ return;
+ }
+ if (fontChanged) {
+ out->updateFont(state);
+ fontChanged = gFalse;
+ }
+ state->setWordSpace(args[0].getNum());
+ state->setCharSpace(args[1].getNum());
+ tx = state->getLineX();
+ ty = state->getLineY() - state->getLeading();
+ state->textMoveTo(tx, ty);
+ out->updateWordSpace(state);
+ out->updateCharSpace(state);
+ out->updateTextPos(state);
+ out->beginStringOp(state);
+ doShowText(args[2].getString());
+ out->endStringOp(state);
+}
+
+void Gfx::opShowSpaceText(Object args[], int /*numArgs*/) {
+ Array *a;
+ Object obj;
+ int wMode;
+ int i;
+
+ if (!state->getFont()) {
+ error(getPos(), "No font in show/space");
+ return;
+ }
+ if (fontChanged) {
+ out->updateFont(state);
+ fontChanged = gFalse;
+ }
+ out->beginStringOp(state);
+ wMode = state->getFont()->getWMode();
+ a = args[0].getArray();
+ for (i = 0; i < a->getLength(); ++i) {
+ a->get(i, &obj);
+ if (obj.isNum()) {
+ // this uses the absolute value of the font size to match
+ // Acrobat's behavior
+ if (wMode) {
+ state->textShift(0, -obj.getNum() * 0.001 *
+ fabs(state->getFontSize()));
+ } else {
+ state->textShift(-obj.getNum() * 0.001 *
+ fabs(state->getFontSize()), 0);
+ }
+ out->updateTextShift(state, obj.getNum());
+ } else if (obj.isString()) {
+ doShowText(obj.getString());
+ } else {
+ error(getPos(), "Element of show/space array must be number or string");
+ }
+ obj.free();
+ }
+ out->endStringOp(state);
+}
+
+void Gfx::doShowText(GString *s) {
+ GfxFont *font;
+ int wMode;
+ double riseX, riseY;
+ CharCode code;
+ Unicode u[8];
+ double x, y, dx, dy, dx2, dy2, curX, curY, tdx, tdy, lineX, lineY;
+ double originX, originY, tOriginX, tOriginY;
+ double oldCTM[6], newCTM[6];
+ double *mat;
+ Object charProc;
+ Dict *resDict;
+ Parser *oldParser;
+ char *p;
+ int len, n, uLen, nChars, nSpaces, i;
+
+ font = state->getFont();
+ wMode = font->getWMode();
+
+ if (out->useDrawChar()) {
+ out->beginString(state, s);
+ }
+
+ // handle a Type 3 char
+ if (font->getType() == fontType3 && out->interpretType3Chars()) {
+ mat = state->getCTM();
+ for (i = 0; i < 6; ++i) {
+ oldCTM[i] = mat[i];
+ }
+ mat = state->getTextMat();
+ newCTM[0] = mat[0] * oldCTM[0] + mat[1] * oldCTM[2];
+ newCTM[1] = mat[0] * oldCTM[1] + mat[1] * oldCTM[3];
+ newCTM[2] = mat[2] * oldCTM[0] + mat[3] * oldCTM[2];
+ newCTM[3] = mat[2] * oldCTM[1] + mat[3] * oldCTM[3];
+ mat = font->getFontMatrix();
+ newCTM[0] = mat[0] * newCTM[0] + mat[1] * newCTM[2];
+ newCTM[1] = mat[0] * newCTM[1] + mat[1] * newCTM[3];
+ newCTM[2] = mat[2] * newCTM[0] + mat[3] * newCTM[2];
+ newCTM[3] = mat[2] * newCTM[1] + mat[3] * newCTM[3];
+ newCTM[0] *= state->getFontSize();
+ newCTM[1] *= state->getFontSize();
+ newCTM[2] *= state->getFontSize();
+ newCTM[3] *= state->getFontSize();
+ newCTM[0] *= state->getHorizScaling();
+ newCTM[2] *= state->getHorizScaling();
+ state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
+ curX = state->getCurX();
+ curY = state->getCurY();
+ lineX = state->getLineX();
+ lineY = state->getLineY();
+ oldParser = parser;
+ p = s->getCString();
+ len = s->getLength();
+ while (len > 0) {
+ n = font->getNextChar(p, len, &code,
+ u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
+ &dx, &dy, &originX, &originY);
+ dx = dx * state->getFontSize() + state->getCharSpace();
+ if (n == 1 && *p == ' ') {
+ dx += state->getWordSpace();
+ }
+ dx *= state->getHorizScaling();
+ dy *= state->getFontSize();
+ state->textTransformDelta(dx, dy, &tdx, &tdy);
+ state->transform(curX + riseX, curY + riseY, &x, &y);
+ saveState();
+ state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y);
+ //~ the CTM concat values here are wrong (but never used)
+ out->updateCTM(state, 1, 0, 0, 1, 0, 0);
+ if (!out->beginType3Char(state, curX + riseX, curY + riseY, tdx, tdy,
+ code, u, uLen)) {
+ ((Gfx8BitFont *)font)->getCharProc(code, &charProc);
+ if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
+ pushResources(resDict);
+ }
+ if (charProc.isStream()) {
+ display(&charProc, gFalse);
+ } else {
+ error(getPos(), "Missing or bad Type3 CharProc entry");
+ }
+ out->endType3Char(state);
+ if (resDict) {
+ popResources();
+ }
+ charProc.free();
+ }
+ restoreState();
+ // GfxState::restore() does *not* restore the current position,
+ // so we deal with it here using (curX, curY) and (lineX, lineY)
+ curX += tdx;
+ curY += tdy;
+ state->moveTo(curX, curY);
+ state->textSetPos(lineX, lineY);
+ p += n;
+ len -= n;
+ }
+ parser = oldParser;
+
+ } else if (out->useDrawChar()) {
+ state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
+ p = s->getCString();
+ len = s->getLength();
+ while (len > 0) {
+ n = font->getNextChar(p, len, &code,
+ u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
+ &dx, &dy, &originX, &originY);
+ if (wMode) {
+ dx *= state->getFontSize();
+ dy = dy * state->getFontSize() + state->getCharSpace();
+ if (n == 1 && *p == ' ') {
+ dy += state->getWordSpace();
+ }
+ } else {
+ dx = dx * state->getFontSize() + state->getCharSpace();
+ if (n == 1 && *p == ' ') {
+ dx += state->getWordSpace();
+ }
+ dx *= state->getHorizScaling();
+ dy *= state->getFontSize();
+ }
+ state->textTransformDelta(dx, dy, &tdx, &tdy);
+ originX *= state->getFontSize();
+ originY *= state->getFontSize();
+ state->textTransformDelta(originX, originY, &tOriginX, &tOriginY);
+ out->drawChar(state, state->getCurX() + riseX, state->getCurY() + riseY,
+ tdx, tdy, tOriginX, tOriginY, code, n, u, uLen);
+ state->shift(tdx, tdy);
+ p += n;
+ len -= n;
+ }
+
+ } else {
+ dx = dy = 0;
+ p = s->getCString();
+ len = s->getLength();
+ nChars = nSpaces = 0;
+ while (len > 0) {
+ n = font->getNextChar(p, len, &code,
+ u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
+ &dx2, &dy2, &originX, &originY);
+ dx += dx2;
+ dy += dy2;
+ if (n == 1 && *p == ' ') {
+ ++nSpaces;
+ }
+ ++nChars;
+ p += n;
+ len -= n;
+ }
+ if (wMode) {
+ dx *= state->getFontSize();
+ dy = dy * state->getFontSize()
+ + nChars * state->getCharSpace()
+ + nSpaces * state->getWordSpace();
+ } else {
+ dx = dx * state->getFontSize()
+ + nChars * state->getCharSpace()
+ + nSpaces * state->getWordSpace();
+ dx *= state->getHorizScaling();
+ dy *= state->getFontSize();
+ }
+ state->textTransformDelta(dx, dy, &tdx, &tdy);
+ out->drawString(state, s);
+ state->shift(tdx, tdy);
+ }
+
+ if (out->useDrawChar()) {
+ out->endString(state);
+ }
+
+ updateLevel += 10 * s->getLength();
+}
+
+//------------------------------------------------------------------------
+// XObject operators
+//------------------------------------------------------------------------
+
+void Gfx::opXObject(Object args[], int /*numArgs*/) {
+ char *name;
+ Object obj1, obj2, obj3, refObj;
+#if OPI_SUPPORT
+ Object opiDict;
+#endif
+
+ name = args[0].getName();
+ if (!res->lookupXObject(name, &obj1)) {
+ return;
+ }
+ if (!obj1.isStream()) {
+ error(getPos(), "XObject '%s' is wrong type", name);
+ obj1.free();
+ return;
+ }
+#if OPI_SUPPORT
+ obj1.streamGetDict()->lookup("OPI", &opiDict);
+ if (opiDict.isDict()) {
+ out->opiBegin(state, opiDict.getDict());
+ }
+#endif
+ obj1.streamGetDict()->lookup("Subtype", &obj2);
+ if (obj2.isName("Image")) {
+ if (out->needNonText()) {
+ res->lookupXObjectNF(name, &refObj);
+ doImage(&refObj, obj1.getStream(), gFalse);
+ refObj.free();
+ }
+ } else if (obj2.isName("Form")) {
+ res->lookupXObjectNF(name, &refObj);
+ if (out->useDrawForm() && refObj.isRef()) {
+ out->drawForm(refObj.getRef());
+ } else {
+ doForm(&obj1);
+ }
+ refObj.free();
+ } else if (obj2.isName("PS")) {
+ obj1.streamGetDict()->lookup("Level1", &obj3);
+ out->psXObject(obj1.getStream(),
+ obj3.isStream() ? obj3.getStream() : (Stream *)NULL);
+ } else if (obj2.isName()) {
+ error(getPos(), "Unknown XObject subtype '%s'", obj2.getName());
+ } else {
+ error(getPos(), "XObject subtype is missing or wrong type");
+ }
+ obj2.free();
+#if OPI_SUPPORT
+ if (opiDict.isDict()) {
+ out->opiEnd(state, opiDict.getDict());
+ }
+ opiDict.free();
+#endif
+ obj1.free();
+}
+
+void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
+ Dict *dict, *maskDict;
+ int width, height;
+ int bits, maskBits;
+ StreamColorSpaceMode csMode;
+ GBool mask;
+ GBool invert;
+ GfxColorSpace *colorSpace, *maskColorSpace;
+ GfxImageColorMap *colorMap, *maskColorMap;
+ Object maskObj, smaskObj;
+ GBool haveColorKeyMask, haveExplicitMask, haveSoftMask;
+ int maskColors[2*gfxColorMaxComps];
+ int maskWidth, maskHeight;
+ GBool maskInvert;
+ Stream *maskStr;
+ Object obj1, obj2;
+ int i;
+
+ // get info from the stream
+ bits = 0;
+ csMode = streamCSNone;
+ str->getImageParams(&bits, &csMode);
+
+ // get stream dict
+ dict = str->getDict();
+
+ // get size
+ dict->lookup("Width", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("W", &obj1);
+ }
+ if (obj1.isInt())
+ width = obj1.getInt();
+ else if (obj1.isReal())
+ width = (int)obj1.getReal();
+ else
+ goto err2;
+ obj1.free();
+ dict->lookup("Height", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("H", &obj1);
+ }
+ if (obj1.isInt())
+ height = obj1.getInt();
+ else if (obj1.isReal())
+ height = (int)obj1.getReal();
+ else
+ goto err2;
+ obj1.free();
+
+ // image or mask?
+ dict->lookup("ImageMask", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("IM", &obj1);
+ }
+ mask = gFalse;
+ if (obj1.isBool())
+ mask = obj1.getBool();
+ else if (!obj1.isNull())
+ goto err2;
+ obj1.free();
+
+ // bit depth
+ if (bits == 0) {
+ dict->lookup("BitsPerComponent", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("BPC", &obj1);
+ }
+ if (obj1.isInt()) {
+ bits = obj1.getInt();
+ } else if (mask) {
+ bits = 1;
+ } else {
+ goto err2;
+ }
+ obj1.free();
+ }
+
+ // display a mask
+ if (mask) {
+
+ // check for inverted mask
+ if (bits != 1)
+ goto err1;
+ invert = gFalse;
+ dict->lookup("Decode", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("D", &obj1);
+ }
+ if (obj1.isArray()) {
+ obj1.arrayGet(0, &obj2);
+ if (obj2.isInt() && obj2.getInt() == 1)
+ invert = gTrue;
+ obj2.free();
+ } else if (!obj1.isNull()) {
+ goto err2;
+ }
+ obj1.free();
+
+ // draw it
+ out->drawImageMask(state, ref, str, width, height, invert, inlineImg);
+
+ } else {
+
+ // get color space and color map
+ dict->lookup("ColorSpace", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("CS", &obj1);
+ }
+ if (obj1.isName()) {
+ res->lookupColorSpace(obj1.getName(), &obj2);
+ if (!obj2.isNull()) {
+ obj1.free();
+ obj1 = obj2;
+ } else {
+ obj2.free();
+ }
+ }
+ if (!obj1.isNull()) {
+ colorSpace = GfxColorSpace::parse(&obj1);
+ } else if (csMode == streamCSDeviceGray) {
+ colorSpace = new GfxDeviceGrayColorSpace();
+ } else if (csMode == streamCSDeviceRGB) {
+ colorSpace = new GfxDeviceRGBColorSpace();
+ } else if (csMode == streamCSDeviceCMYK) {
+ colorSpace = new GfxDeviceCMYKColorSpace();
+ } else {
+ colorSpace = NULL;
+ }
+ obj1.free();
+ if (!colorSpace) {
+ goto err1;
+ }
+ dict->lookup("Decode", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ dict->lookup("D", &obj1);
+ }
+ colorMap = new GfxImageColorMap(bits, &obj1, colorSpace);
+ obj1.free();
+ if (!colorMap->isOk()) {
+ delete colorMap;
+ goto err1;
+ }
+
+ // get the mask
+ haveColorKeyMask = haveExplicitMask = haveSoftMask = gFalse;
+ maskStr = NULL; // make gcc happy
+ maskWidth = maskHeight = 0; // make gcc happy
+ maskInvert = gFalse; // make gcc happy
+ maskColorMap = NULL; // make gcc happy
+ dict->lookup("Mask", &maskObj);
+ dict->lookup("SMask", &smaskObj);
+ if (smaskObj.isStream()) {
+ // soft mask
+ if (inlineImg) {
+ goto err1;
+ }
+ maskStr = smaskObj.getStream();
+ maskDict = smaskObj.streamGetDict();
+ maskDict->lookup("Width", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("W", &obj1);
+ }
+ if (!obj1.isInt()) {
+ goto err2;
+ }
+ maskWidth = obj1.getInt();
+ obj1.free();
+ maskDict->lookup("Height", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("H", &obj1);
+ }
+ if (!obj1.isInt()) {
+ goto err2;
+ }
+ maskHeight = obj1.getInt();
+ obj1.free();
+ maskDict->lookup("BitsPerComponent", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("BPC", &obj1);
+ }
+ if (!obj1.isInt()) {
+ goto err2;
+ }
+ maskBits = obj1.getInt();
+ obj1.free();
+ maskDict->lookup("ColorSpace", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("CS", &obj1);
+ }
+ if (obj1.isName()) {
+ res->lookupColorSpace(obj1.getName(), &obj2);
+ if (!obj2.isNull()) {
+ obj1.free();
+ obj1 = obj2;
+ } else {
+ obj2.free();
+ }
+ }
+ maskColorSpace = GfxColorSpace::parse(&obj1);
+ obj1.free();
+ if (!maskColorSpace || maskColorSpace->getMode() != csDeviceGray) {
+ goto err1;
+ }
+ maskDict->lookup("Decode", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("D", &obj1);
+ }
+ maskColorMap = new GfxImageColorMap(maskBits, &obj1, maskColorSpace);
+ obj1.free();
+ if (!maskColorMap->isOk()) {
+ delete maskColorMap;
+ goto err1;
+ }
+ //~ handle the Matte entry
+ haveSoftMask = gTrue;
+ } else if (maskObj.isArray()) {
+ // color key mask
+ for (i = 0;
+ i < maskObj.arrayGetLength() && i < 2*gfxColorMaxComps;
+ ++i) {
+ maskObj.arrayGet(i, &obj1);
+ maskColors[i] = obj1.getInt();
+ obj1.free();
+ }
+ haveColorKeyMask = gTrue;
+ } else if (maskObj.isStream()) {
+ // explicit mask
+ if (inlineImg) {
+ goto err1;
+ }
+ maskStr = maskObj.getStream();
+ maskDict = maskObj.streamGetDict();
+ maskDict->lookup("Width", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("W", &obj1);
+ }
+ if (!obj1.isInt()) {
+ goto err2;
+ }
+ maskWidth = obj1.getInt();
+ obj1.free();
+ maskDict->lookup("Height", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("H", &obj1);
+ }
+ if (!obj1.isInt()) {
+ goto err2;
+ }
+ maskHeight = obj1.getInt();
+ obj1.free();
+ maskDict->lookup("ImageMask", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("IM", &obj1);
+ }
+ if (!obj1.isBool() || !obj1.getBool()) {
+ goto err2;
+ }
+ obj1.free();
+ maskInvert = gFalse;
+ maskDict->lookup("Decode", &obj1);
+ if (obj1.isNull()) {
+ obj1.free();
+ maskDict->lookup("D", &obj1);
+ }
+ if (obj1.isArray()) {
+ obj1.arrayGet(0, &obj2);
+ if (obj2.isInt() && obj2.getInt() == 1) {
+ maskInvert = gTrue;
+ }
+ obj2.free();
+ } else if (!obj1.isNull()) {
+ goto err2;
+ }
+ obj1.free();
+ haveExplicitMask = gTrue;
+ }
+
+ // draw it
+ if (haveSoftMask) {
+ out->drawSoftMaskedImage(state, ref, str, width, height, colorMap,
+ maskStr, maskWidth, maskHeight, maskColorMap);
+ delete maskColorMap;
+ } else if (haveExplicitMask) {
+ out->drawMaskedImage(state, ref, str, width, height, colorMap,
+ maskStr, maskWidth, maskHeight, maskInvert);
+ } else {
+ out->drawImage(state, ref, str, width, height, colorMap,
+ haveColorKeyMask ? maskColors : (int *)NULL, inlineImg);
+ }
+ delete colorMap;
+
+ maskObj.free();
+ smaskObj.free();
+ }
+
+ if ((i = width * height) > 1000) {
+ i = 1000;
+ }
+ updateLevel += i;
+
+ return;
+
+ err2:
+ obj1.free();
+ err1:
+ error(getPos(), "Bad image parameters");
+}
+
+void Gfx::doForm(Object *str) {
+ Dict *dict;
+ GBool transpGroup, isolated, knockout;
+ GfxColorSpace *blendingColorSpace;
+ Object matrixObj, bboxObj;
+ double m[6], bbox[4];
+ Object resObj;
+ Dict *resDict;
+ Object obj1, obj2, obj3;
+ int i;
+
+ // check for excessive recursion
+ if (formDepth > 20) {
+ return;
+ }
+
+ // get stream dict
+ dict = str->streamGetDict();
+
+ // check form type
+ dict->lookup("FormType", &obj1);
+ if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
+ error(getPos(), "Unknown form type");
+ }
+ obj1.free();
+
+ // get bounding box
+ dict->lookup("BBox", &bboxObj);
+ if (!bboxObj.isArray()) {
+ bboxObj.free();
+ error(getPos(), "Bad form bounding box");
+ return;
+ }
+ for (i = 0; i < 4; ++i) {
+ bboxObj.arrayGet(i, &obj1);
+ bbox[i] = obj1.getNum();
+ obj1.free();
+ }
+ bboxObj.free();
+
+ // get matrix
+ dict->lookup("Matrix", &matrixObj);
+ if (matrixObj.isArray()) {
+ for (i = 0; i < 6; ++i) {
+ matrixObj.arrayGet(i, &obj1);
+ m[i] = obj1.getNum();
+ obj1.free();
+ }
+ } else {
+ m[0] = 1; m[1] = 0;
+ m[2] = 0; m[3] = 1;
+ m[4] = 0; m[5] = 0;
+ }
+ matrixObj.free();
+
+ // get resources
+ dict->lookup("Resources", &resObj);
+ resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
+
+ // check for a transparency group
+ transpGroup = isolated = knockout = gFalse;
+ blendingColorSpace = NULL;
+ if (dict->lookup("Group", &obj1)->isDict()) {
+ if (obj1.dictLookup("S", &obj2)->isName("Transparency")) {
+ transpGroup = gTrue;
+ if (!obj1.dictLookup("CS", &obj3)->isNull()) {
+ blendingColorSpace = GfxColorSpace::parse(&obj3);
+ }
+ obj3.free();
+ if (obj1.dictLookup("I", &obj3)->isBool()) {
+ isolated = obj3.getBool();
+ }
+ obj3.free();
+ if (obj1.dictLookup("K", &obj3)->isBool()) {
+ knockout = obj3.getBool();
+ }
+ obj3.free();
+ }
+ obj2.free();
+ }
+ obj1.free();
+
+ // draw it
+ ++formDepth;
+ doForm1(str, resDict, m, bbox,
+ transpGroup, gFalse, blendingColorSpace, isolated, knockout);
+ --formDepth;
+
+ if (blendingColorSpace) {
+ delete blendingColorSpace;
+ }
+ resObj.free();
+}
+
+void Gfx::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox,
+ GBool transpGroup, GBool softMask,
+ GfxColorSpace *blendingColorSpace,
+ GBool isolated, GBool knockout,
+ GBool alpha, Function *transferFunc,
+ GfxColor *backdropColor) {
+ Parser *oldParser;
+ double oldBaseMatrix[6];
+ int i;
+
+ // push new resources on stack
+ pushResources(resDict);
+
+ // save current graphics state
+ saveState();
+
+ // kill any pre-existing path
+ state->clearPath();
+
+ // save current parser
+ oldParser = parser;
+
+ // set form transformation matrix
+ state->concatCTM(matrix[0], matrix[1], matrix[2],
+ matrix[3], matrix[4], matrix[5]);
+ out->updateCTM(state, matrix[0], matrix[1], matrix[2],
+ matrix[3], matrix[4], matrix[5]);
+
+ // set form bounding box
+ state->moveTo(bbox[0], bbox[1]);
+ state->lineTo(bbox[2], bbox[1]);
+ state->lineTo(bbox[2], bbox[3]);
+ state->lineTo(bbox[0], bbox[3]);
+ state->closePath();
+ state->clip();
+ out->clip(state);
+ state->clearPath();
+
+ if (softMask || transpGroup) {
+ if (state->getBlendMode() != gfxBlendNormal) {
+ state->setBlendMode(gfxBlendNormal);
+ out->updateBlendMode(state);
+ }
+ if (state->getFillOpacity() != 1) {
+ state->setFillOpacity(1);
+ out->updateFillOpacity(state);
+ }
+ if (state->getStrokeOpacity() != 1) {
+ state->setStrokeOpacity(1);
+ out->updateStrokeOpacity(state);
+ }
+ out->clearSoftMask(state);
+ out->beginTransparencyGroup(state, bbox, blendingColorSpace,
+ isolated, knockout, softMask);
+ }
+
+ // set new base matrix
+ for (i = 0; i < 6; ++i) {
+ oldBaseMatrix[i] = baseMatrix[i];
+ baseMatrix[i] = state->getCTM()[i];
+ }
+
+ // draw the form
+ display(str, gFalse);
+
+ if (softMask || transpGroup) {
+ out->endTransparencyGroup(state);
+ }
+
+ // restore base matrix
+ for (i = 0; i < 6; ++i) {
+ baseMatrix[i] = oldBaseMatrix[i];
+ }
+
+ // restore parser
+ parser = oldParser;
+
+ // restore graphics state
+ restoreState();
+
+ // pop resource stack
+ popResources();
+
+ if (softMask) {
+ out->setSoftMask(state, bbox, alpha, transferFunc, backdropColor);
+ } else if (transpGroup) {
+ out->paintTransparencyGroup(state, bbox);
+ }
+
+ return;
+}
+
+//------------------------------------------------------------------------
+// in-line image operators
+//------------------------------------------------------------------------
+
+void Gfx::opBeginImage(Object * /*args[]*/, int /*numArgs*/) {
+ Stream *str;
+ int c1, c2;
+
+ // build dict/stream
+ str = buildImageStream();
+
+ // display the image
+ if (str) {
+ doImage(NULL, str, gTrue);
+
+ // skip 'EI' tag
+ c1 = str->getUndecodedStream()->getChar();
+ c2 = str->getUndecodedStream()->getChar();
+ while (!(c1 == 'E' && c2 == 'I') && c2 != EOF) {
+ c1 = c2;
+ c2 = str->getUndecodedStream()->getChar();
+ }
+ delete str;
+ }
+}
+
+Stream *Gfx::buildImageStream() {
+ Object dict;
+ Object obj;
+ char *key;
+ Stream *str;
+
+ // build dictionary
+ dict.initDict(xref);
+ parser->getObj(&obj);
+ while (!obj.isCmd("ID") && !obj.isEOF()) {
+ if (!obj.isName()) {
+ error(getPos(), "Inline image dictionary key must be a name object");
+ obj.free();
+ } else {
+ key = copyString(obj.getName());
+ obj.free();
+ parser->getObj(&obj);
+ if (obj.isEOF() || obj.isError()) {
+ gfree(key);
+ break;
+ }
+ dict.dictAdd(key, &obj);
+ }
+ parser->getObj(&obj);
+ }
+ if (obj.isEOF()) {
+ error(getPos(), "End of file in inline image");
+ obj.free();
+ dict.free();
+ return NULL;
+ }
+ obj.free();
+
+ // make stream
+ str = new EmbedStream(parser->getStream(), &dict, gFalse, 0);
+ str = str->addFilters(&dict);
+
+ return str;
+}
+
+void Gfx::opImageData(Object * /*args[]*/, int /*numArgs*/) {
+ error(getPos(), "Internal: got 'ID' operator");
+}
+
+void Gfx::opEndImage(Object * /*args[]*/, int /*numArgs*/) {
+ error(getPos(), "Internal: got 'EI' operator");
+}
+
+//------------------------------------------------------------------------
+// type 3 font operators
+//------------------------------------------------------------------------
+
+void Gfx::opSetCharWidth(Object args[], int /*numArgs*/) {
+ out->type3D0(state, args[0].getNum(), args[1].getNum());
+}
+
+void Gfx::opSetCacheDevice(Object args[], int /*numArgs*/) {
+ out->type3D1(state, args[0].getNum(), args[1].getNum(),
+ args[2].getNum(), args[3].getNum(),
+ args[4].getNum(), args[5].getNum());
+}
+
+//------------------------------------------------------------------------
+// compatibility operators
+//------------------------------------------------------------------------
+
+void Gfx::opBeginIgnoreUndef(Object * /*args[]*/, int /*numArgs*/) {
+ ++ignoreUndef;
+}
+
+void Gfx::opEndIgnoreUndef(Object * /*args[]*/, int /*numArgs*/) {
+ if (ignoreUndef > 0)
+ --ignoreUndef;
+}
+
+//------------------------------------------------------------------------
+// marked content operators
+//------------------------------------------------------------------------
+
+void Gfx::opBeginMarkedContent(Object args[], int numArgs) {
+ if (printCommands) {
+ printf(" marked content: %s ", args[0].getName());
+ if (numArgs == 2)
+ args[2].print(stdout);
+ printf("\n");
+ fflush(stdout);
+ }
+}
+
+void Gfx::opEndMarkedContent(Object * /*args[]*/, int /*numArgs*/) {
+}
+
+void Gfx::opMarkPoint(Object args[], int numArgs) {
+ if (printCommands) {
+ printf(" mark point: %s ", args[0].getName());
+ if (numArgs == 2)
+ args[2].print(stdout);
+ printf("\n");
+ fflush(stdout);
+ }
+}
+
+//------------------------------------------------------------------------
+// misc
+//------------------------------------------------------------------------
+
+void Gfx::drawAnnot(Object *str, AnnotBorderStyle *borderStyle,
+ double xMin, double yMin, double xMax, double yMax) {
+ Dict *dict, *resDict;
+ Object matrixObj, bboxObj, resObj;
+ Object obj1;
+ double m[6], bbox[4], ictm[6];
+ double *ctm;
+ double formX0, formY0, formX1, formY1;
+ double annotX0, annotY0, annotX1, annotY1;
+ double det, x, y, sx, sy;
+ double r, g, b;
+ GfxColor color;
+ double *dash, *dash2;
+ int dashLength;
+ int i;
+
+ //~ can we assume that we're in default user space?
+ //~ (i.e., baseMatrix = ctm)
+
+ // transform the annotation bbox from default user space to user
+ // space: (bbox * baseMatrix) * iCTM
+ ctm = state->getCTM();
+ det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
+ ictm[0] = ctm[3] * det;
+ ictm[1] = -ctm[1] * det;
+ ictm[2] = -ctm[2] * det;
+ ictm[3] = ctm[0] * det;
+ ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
+ ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
+ x = baseMatrix[0] * xMin + baseMatrix[2] * yMin + baseMatrix[4];
+ y = baseMatrix[1] * xMin + baseMatrix[3] * yMin + baseMatrix[5];
+ annotX0 = ictm[0] * x + ictm[2] * y + ictm[4];
+ annotY0 = ictm[1] * x + ictm[3] * y + ictm[5];
+ x = baseMatrix[0] * xMax + baseMatrix[2] * yMax + baseMatrix[4];
+ y = baseMatrix[1] * xMax + baseMatrix[3] * yMax + baseMatrix[5];
+ annotX1 = ictm[0] * x + ictm[2] * y + ictm[4];
+ annotY1 = ictm[1] * x + ictm[3] * y + ictm[5];
+ if (annotX0 > annotX1) {
+ x = annotX0; annotX0 = annotX1; annotX1 = x;
+ }
+ if (annotY0 > annotY1) {
+ y = annotY0; annotY0 = annotY1; annotY1 = y;
+ }
+
+ // draw the appearance stream (if there is one)
+ if (str->isStream()) {
+
+ // get stream dict
+ dict = str->streamGetDict();
+
+ // get the form bounding box
+ dict->lookup("BBox", &bboxObj);
+ if (!bboxObj.isArray()) {
+ bboxObj.free();
+ error(getPos(), "Bad form bounding box");
+ return;
+ }
+ for (i = 0; i < 4; ++i) {
+ bboxObj.arrayGet(i, &obj1);
+ bbox[i] = obj1.getNum();
+ obj1.free();
+ }
+ bboxObj.free();
+
+ // get the form matrix
+ dict->lookup("Matrix", &matrixObj);
+ if (matrixObj.isArray()) {
+ for (i = 0; i < 6; ++i) {
+ matrixObj.arrayGet(i, &obj1);
+ m[i] = obj1.getNum();
+ obj1.free();
+ }
+ } else {
+ m[0] = 1; m[1] = 0;
+ m[2] = 0; m[3] = 1;
+ m[4] = 0; m[5] = 0;
+ }
+ matrixObj.free();
+
+ // transform the form bbox from form space to user space
+ formX0 = bbox[0] * m[0] + bbox[1] * m[2] + m[4];
+ formY0 = bbox[0] * m[1] + bbox[1] * m[3] + m[5];
+ formX1 = bbox[2] * m[0] + bbox[3] * m[2] + m[4];
+ formY1 = bbox[2] * m[1] + bbox[3] * m[3] + m[5];
+ if (formX0 > formX1) {
+ x = formX0; formX0 = formX1; formX1 = x;
+ }
+ if (formY0 > formY1) {
+ y = formY0; formY0 = formY1; formY1 = y;
+ }
+
+ // scale the form to fit the annotation bbox
+ if (formX1 == formX0) {
+ // this shouldn't happen
+ sx = 1;
+ } else {
+ sx = (annotX1 - annotX0) / (formX1 - formX0);
+ }
+ if (formY1 == formY0) {
+ // this shouldn't happen
+ sy = 1;
+ } else {
+ sy = (annotY1 - annotY0) / (formY1 - formY0);
+ }
+ m[0] *= sx;
+ m[2] *= sx;
+ m[4] = (m[4] - formX0) * sx + annotX0;
+ m[1] *= sy;
+ m[3] *= sy;
+ m[5] = (m[5] - formY0) * sy + annotY0;
+
+ // get resources
+ dict->lookup("Resources", &resObj);
+ resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
+
+ // draw it
+ doForm1(str, resDict, m, bbox);
+
+ resObj.free();
+ }
+
+ // draw the border
+ if (borderStyle && borderStyle->getWidth() > 0) {
+ if (state->getStrokeColorSpace()->getMode() != csDeviceRGB) {
+ state->setStrokePattern(NULL);
+ state->setStrokeColorSpace(new GfxDeviceRGBColorSpace());
+ out->updateStrokeColorSpace(state);
+ }
+ borderStyle->getColor(&r, &g, &b);
+ color.c[0] = dblToCol(r);
+ color.c[1] = dblToCol(g);
+ color.c[2] = dblToCol(b);
+ state->setStrokeColor(&color);
+ out->updateStrokeColor(state);
+ // compute the width scale factor when going from default user
+ // space to user space
+ x = (baseMatrix[0] + baseMatrix[2]) * ictm[0] +
+ (baseMatrix[1] + baseMatrix[3]) * ictm[2];
+ y = (baseMatrix[0] + baseMatrix[2]) * ictm[1] +
+ (baseMatrix[1] + baseMatrix[3]) * ictm[3];
+ x = sqrt(0.5 * (x * x + y * y));
+ state->setLineWidth(x * borderStyle->getWidth());
+ out->updateLineWidth(state);
+ borderStyle->getDash(&dash, &dashLength);
+ if (borderStyle->getType() == annotBorderDashed && dashLength > 0) {
+ dash2 = (double *)gmallocn(dashLength, sizeof(double));
+ for (i = 0; i < dashLength; ++i) {
+ dash2[i] = x * dash[i];
+ }
+ state->setLineDash(dash2, dashLength, 0);
+ out->updateLineDash(state);
+ }
+ //~ this doesn't currently handle the beveled and engraved styles
+ state->clearPath();
+ state->moveTo(annotX0, out->upsideDown() ? annotY0 : annotY1);
+ state->lineTo(annotX1, out->upsideDown() ? annotY0 : annotY1);
+ if (borderStyle->getType() != annotBorderUnderlined) {
+ state->lineTo(annotX1, out->upsideDown() ? annotY1 : annotY0);
+ state->lineTo(annotX0, out->upsideDown() ? annotY1 : annotY0);
+ state->closePath();
+ }
+ out->stroke(state);
+ }
+}
+
+void Gfx::saveState() {
+ out->saveState(state);
+ state = state->save();
+}
+
+void Gfx::restoreState() {
+ state = state->restore();
+ out->restoreState(state);
+}
+
+void Gfx::pushResources(Dict *resDict) {
+ res = new GfxResources(xref, resDict, res);
+}
+
+void Gfx::popResources() {
+ GfxResources *resPtr;
+
+ resPtr = res->getNext();
+ delete res;
+ res = resPtr;
+}
diff --git a/kpdf/xpdf/xpdf/Gfx.h b/kpdf/xpdf/xpdf/Gfx.h
new file mode 100644
index 00000000..0e4263ce
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Gfx.h
@@ -0,0 +1,312 @@
+//========================================================================
+//
+// Gfx.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef GFX_H
+#define GFX_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+
+class GString;
+class XRef;
+class Array;
+class Stream;
+class Parser;
+class Dict;
+class Function;
+class OutputDev;
+class GfxFontDict;
+class GfxFont;
+class GfxPattern;
+class GfxTilingPattern;
+class GfxShadingPattern;
+class GfxShading;
+class GfxFunctionShading;
+class GfxAxialShading;
+class GfxRadialShading;
+class GfxGouraudTriangleShading;
+class GfxPatchMeshShading;
+struct GfxPatch;
+class GfxState;
+struct GfxColor;
+class GfxColorSpace;
+class Gfx;
+class PDFRectangle;
+class AnnotBorderStyle;
+
+//------------------------------------------------------------------------
+
+enum GfxClipType {
+ clipNone,
+ clipNormal,
+ clipEO
+};
+
+enum TchkType {
+ tchkBool, // boolean
+ tchkInt, // integer
+ tchkNum, // number (integer or real)
+ tchkString, // string
+ tchkName, // name
+ tchkArray, // array
+ tchkProps, // properties (dictionary or name)
+ tchkSCN, // scn/SCN args (number of name)
+ tchkNone // used to avoid empty initializer lists
+};
+
+#define maxArgs 33
+
+struct Operator {
+ char name[4];
+ int numArgs;
+ TchkType tchk[maxArgs];
+ void (Gfx::*func)(Object args[], int numArgs);
+};
+
+//------------------------------------------------------------------------
+
+class GfxResources {
+public:
+
+ GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA);
+ ~GfxResources();
+
+ GfxFont *lookupFont(char *name);
+ GBool lookupXObject(char *name, Object *obj);
+ GBool lookupXObjectNF(char *name, Object *obj);
+ void lookupColorSpace(char *name, Object *obj);
+ GfxPattern *lookupPattern(char *name);
+ GfxShading *lookupShading(char *name);
+ GBool lookupGState(char *name, Object *obj);
+
+ GfxResources *getNext() { return next; }
+
+private:
+
+ GfxFontDict *fonts;
+ Object xObjDict;
+ Object colorSpaceDict;
+ Object patternDict;
+ Object shadingDict;
+ Object gStateDict;
+ GfxResources *next;
+};
+
+//------------------------------------------------------------------------
+// Gfx
+//------------------------------------------------------------------------
+
+class Gfx {
+public:
+
+ // Constructor for regular output.
+ Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict,
+ double hDPI, double vDPI, PDFRectangle *box,
+ PDFRectangle *cropBox, int rotate,
+ GBool (*abortCheckCbkA)(void *data) = NULL,
+ void *abortCheckCbkDataA = NULL);
+
+ // Constructor for a sub-page object.
+ Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict,
+ PDFRectangle *box, PDFRectangle *cropBox,
+ GBool (*abortCheckCbkA)(void *data) = NULL,
+ void *abortCheckCbkDataA = NULL);
+
+ ~Gfx();
+
+ // Interpret a stream or array of streams.
+ void display(Object *obj, GBool topLevel = gTrue);
+
+ // Display an annotation, given its appearance (a Form XObject),
+ // border style, and bounding box (in default user space).
+ void drawAnnot(Object *str, AnnotBorderStyle *borderStyle,
+ double xMin, double yMin, double xMax, double yMax);
+
+ // Save graphics state.
+ void saveState();
+
+ // Restore graphics state.
+ void restoreState();
+
+ // Get the current graphics state object.
+ GfxState *getState() { return state; }
+
+private:
+
+ XRef *xref; // the xref table for this PDF file
+ OutputDev *out; // output device
+ GBool subPage; // is this a sub-page object?
+ GBool printCommands; // print the drawing commands (for debugging)
+ GfxResources *res; // resource stack
+ int updateLevel;
+
+ GfxState *state; // current graphics state
+ GBool fontChanged; // set if font or text matrix has changed
+ GfxClipType clip; // do a clip?
+ int ignoreUndef; // current BX/EX nesting level
+ double baseMatrix[6]; // default matrix for most recent
+ // page/form/pattern
+ int formDepth;
+
+ Parser *parser; // parser for page content stream(s)
+
+ GBool // callback to check for an abort
+ (*abortCheckCbk)(void *data);
+ void *abortCheckCbkData;
+
+ static Operator opTab[]; // table of operators
+
+ void go(GBool topLevel);
+ void execOp(Object *cmd, Object args[], int numArgs);
+ Operator *findOp(char *name);
+ GBool checkArg(Object *arg, TchkType type);
+ int getPos();
+
+ // graphics state operators
+ void opSave(Object args[], int numArgs);
+ void opRestore(Object args[], int numArgs);
+ void opConcat(Object args[], int numArgs);
+ void opSetDash(Object args[], int numArgs);
+ void opSetFlat(Object args[], int numArgs);
+ void opSetLineJoin(Object args[], int numArgs);
+ void opSetLineCap(Object args[], int numArgs);
+ void opSetMiterLimit(Object args[], int numArgs);
+ void opSetLineWidth(Object args[], int numArgs);
+ void opSetExtGState(Object args[], int numArgs);
+ void doSoftMask(Object *str, GBool alpha,
+ GfxColorSpace *blendingColorSpace,
+ GBool isolated, GBool knockout,
+ Function *transferFunc, GfxColor *backdropColor);
+ void opSetRenderingIntent(Object args[], int numArgs);
+
+ // color operators
+ void opSetFillGray(Object args[], int numArgs);
+ void opSetStrokeGray(Object args[], int numArgs);
+ void opSetFillCMYKColor(Object args[], int numArgs);
+ void opSetStrokeCMYKColor(Object args[], int numArgs);
+ void opSetFillRGBColor(Object args[], int numArgs);
+ void opSetStrokeRGBColor(Object args[], int numArgs);
+ void opSetFillColorSpace(Object args[], int numArgs);
+ void opSetStrokeColorSpace(Object args[], int numArgs);
+ void opSetFillColor(Object args[], int numArgs);
+ void opSetStrokeColor(Object args[], int numArgs);
+ void opSetFillColorN(Object args[], int numArgs);
+ void opSetStrokeColorN(Object args[], int numArgs);
+
+ // path segment operators
+ void opMoveTo(Object args[], int numArgs);
+ void opLineTo(Object args[], int numArgs);
+ void opCurveTo(Object args[], int numArgs);
+ void opCurveTo1(Object args[], int numArgs);
+ void opCurveTo2(Object args[], int numArgs);
+ void opRectangle(Object args[], int numArgs);
+ void opClosePath(Object args[], int numArgs);
+
+ // path painting operators
+ void opEndPath(Object args[], int numArgs);
+ void opStroke(Object args[], int numArgs);
+ void opCloseStroke(Object args[], int numArgs);
+ void opFill(Object args[], int numArgs);
+ void opEOFill(Object args[], int numArgs);
+ void opFillStroke(Object args[], int numArgs);
+ void opCloseFillStroke(Object args[], int numArgs);
+ void opEOFillStroke(Object args[], int numArgs);
+ void opCloseEOFillStroke(Object args[], int numArgs);
+ void doPatternFill(GBool eoFill);
+ void doPatternStroke();
+ void doTilingPatternFill(GfxTilingPattern *tPat,
+ GBool stroke, GBool eoFill);
+ void doShadingPatternFill(GfxShadingPattern *sPat,
+ GBool stroke, GBool eoFill);
+ void opShFill(Object args[], int numArgs);
+ void doFunctionShFill(GfxFunctionShading *shading);
+ void doFunctionShFill1(GfxFunctionShading *shading,
+ double x0, double y0,
+ double x1, double y1,
+ GfxColor *colors, int depth);
+ void doAxialShFill(GfxAxialShading *shading);
+ void doRadialShFill(GfxRadialShading *shading);
+ void doGouraudTriangleShFill(GfxGouraudTriangleShading *shading);
+ void gouraudFillTriangle(double x0, double y0, GfxColor *color0,
+ double x1, double y1, GfxColor *color1,
+ double x2, double y2, GfxColor *color2,
+ int nComps, int depth);
+ void doPatchMeshShFill(GfxPatchMeshShading *shading);
+ void fillPatch(GfxPatch *patch, int nComps, int depth);
+ void doEndPath();
+
+ // path clipping operators
+ void opClip(Object args[], int numArgs);
+ void opEOClip(Object args[], int numArgs);
+
+ // text object operators
+ void opBeginText(Object args[], int numArgs);
+ void opEndText(Object args[], int numArgs);
+
+ // text state operators
+ void opSetCharSpacing(Object args[], int numArgs);
+ void opSetFont(Object args[], int numArgs);
+ void opSetTextLeading(Object args[], int numArgs);
+ void opSetTextRender(Object args[], int numArgs);
+ void opSetTextRise(Object args[], int numArgs);
+ void opSetWordSpacing(Object args[], int numArgs);
+ void opSetHorizScaling(Object args[], int numArgs);
+
+ // text positioning operators
+ void opTextMove(Object args[], int numArgs);
+ void opTextMoveSet(Object args[], int numArgs);
+ void opSetTextMatrix(Object args[], int numArgs);
+ void opTextNextLine(Object args[], int numArgs);
+
+ // text string operators
+ void opShowText(Object args[], int numArgs);
+ void opMoveShowText(Object args[], int numArgs);
+ void opMoveSetShowText(Object args[], int numArgs);
+ void opShowSpaceText(Object args[], int numArgs);
+ void doShowText(GString *s);
+
+ // XObject operators
+ void opXObject(Object args[], int numArgs);
+ void doImage(Object *ref, Stream *str, GBool inlineImg);
+ void doForm(Object *str);
+ void doForm1(Object *str, Dict *resDict, double *matrix, double *bbox,
+ GBool transpGroup = gFalse, GBool softMask = gFalse,
+ GfxColorSpace *blendingColorSpace = NULL,
+ GBool isolated = gFalse, GBool knockout = gFalse,
+ GBool alpha = gFalse, Function *transferFunc = NULL,
+ GfxColor *backdropColor = NULL);
+
+ // in-line image operators
+ void opBeginImage(Object args[], int numArgs);
+ Stream *buildImageStream();
+ void opImageData(Object args[], int numArgs);
+ void opEndImage(Object args[], int numArgs);
+
+ // type 3 font operators
+ void opSetCharWidth(Object args[], int numArgs);
+ void opSetCacheDevice(Object args[], int numArgs);
+
+ // compatibility operators
+ void opBeginIgnoreUndef(Object args[], int numArgs);
+ void opEndIgnoreUndef(Object args[], int numArgs);
+
+ // marked content operators
+ void opBeginMarkedContent(Object args[], int numArgs);
+ void opEndMarkedContent(Object args[], int numArgs);
+ void opMarkPoint(Object args[], int numArgs);
+
+ void pushResources(Dict *resDict);
+ void popResources();
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/GfxFont.cc b/kpdf/xpdf/xpdf/GfxFont.cc
new file mode 100644
index 00000000..8694be47
--- /dev/null
+++ b/kpdf/xpdf/xpdf/GfxFont.cc
@@ -0,0 +1,1616 @@
+//========================================================================
+//
+// GfxFont.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "gmem.h"
+#include "Error.h"
+#include "Object.h"
+#include "Dict.h"
+#include "GlobalParams.h"
+#include "CMap.h"
+#include "CharCodeToUnicode.h"
+#include "FontEncodingTables.h"
+#include "BuiltinFontTables.h"
+#include "FoFiType1.h"
+#include "FoFiType1C.h"
+#include "FoFiTrueType.h"
+#include "GfxFont.h"
+
+//------------------------------------------------------------------------
+
+struct StdFontMapEntry {
+ char *altName;
+ char *properName;
+};
+
+// Acrobat 4.0 and earlier substituted Base14-compatible fonts without
+// providing Widths and a FontDescriptor, so we munge the names into
+// the proper Base14 names. This table is from implementation note 44
+// in the PDF 1.4 spec, with some additions based on empirical
+// evidence.
+static StdFontMapEntry stdFontMap[] = {
+ { "Arial", "Helvetica" },
+ { "Arial,Bold", "Helvetica-Bold" },
+ { "Arial,BoldItalic", "Helvetica-BoldOblique" },
+ { "Arial,Italic", "Helvetica-Oblique" },
+ { "Arial-Bold", "Helvetica-Bold" },
+ { "Arial-BoldItalic", "Helvetica-BoldOblique" },
+ { "Arial-BoldItalicMT", "Helvetica-BoldOblique" },
+ { "Arial-BoldMT", "Helvetica-Bold" },
+ { "Arial-Italic", "Helvetica-Oblique" },
+ { "Arial-ItalicMT", "Helvetica-Oblique" },
+ { "ArialMT", "Helvetica" },
+ { "Courier,Bold", "Courier-Bold" },
+ { "Courier,BoldItalic", "Courier-BoldOblique" },
+ { "Courier,Italic", "Courier-Oblique" },
+ { "CourierNew", "Courier" },
+ { "CourierNew,Bold", "Courier-Bold" },
+ { "CourierNew,BoldItalic", "Courier-BoldOblique" },
+ { "CourierNew,Italic", "Courier-Oblique" },
+ { "CourierNew-Bold", "Courier-Bold" },
+ { "CourierNew-BoldItalic", "Courier-BoldOblique" },
+ { "CourierNew-Italic", "Courier-Oblique" },
+ { "CourierNewPS-BoldItalicMT", "Courier-BoldOblique" },
+ { "CourierNewPS-BoldMT", "Courier-Bold" },
+ { "CourierNewPS-ItalicMT", "Courier-Oblique" },
+ { "CourierNewPSMT", "Courier" },
+ { "Helvetica,Bold", "Helvetica-Bold" },
+ { "Helvetica,BoldItalic", "Helvetica-BoldOblique" },
+ { "Helvetica,Italic", "Helvetica-Oblique" },
+ { "Helvetica-BoldItalic", "Helvetica-BoldOblique" },
+ { "Helvetica-Italic", "Helvetica-Oblique" },
+ { "Symbol,Bold", "Symbol" },
+ { "Symbol,BoldItalic", "Symbol" },
+ { "Symbol,Italic", "Symbol" },
+ { "TimesNewRoman", "Times-Roman" },
+ { "TimesNewRoman,Bold", "Times-Bold" },
+ { "TimesNewRoman,BoldItalic", "Times-BoldItalic" },
+ { "TimesNewRoman,Italic", "Times-Italic" },
+ { "TimesNewRoman-Bold", "Times-Bold" },
+ { "TimesNewRoman-BoldItalic", "Times-BoldItalic" },
+ { "TimesNewRoman-Italic", "Times-Italic" },
+ { "TimesNewRomanPS", "Times-Roman" },
+ { "TimesNewRomanPS-Bold", "Times-Bold" },
+ { "TimesNewRomanPS-BoldItalic", "Times-BoldItalic" },
+ { "TimesNewRomanPS-BoldItalicMT", "Times-BoldItalic" },
+ { "TimesNewRomanPS-BoldMT", "Times-Bold" },
+ { "TimesNewRomanPS-Italic", "Times-Italic" },
+ { "TimesNewRomanPS-ItalicMT", "Times-Italic" },
+ { "TimesNewRomanPSMT", "Times-Roman" },
+ { "TimesNewRomanPSMT,Bold", "Times-Bold" },
+ { "TimesNewRomanPSMT,BoldItalic", "Times-BoldItalic" },
+ { "TimesNewRomanPSMT,Italic", "Times-Italic" }
+};
+
+//------------------------------------------------------------------------
+// GfxFont
+//------------------------------------------------------------------------
+
+GfxFont *GfxFont::makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict) {
+ GString *nameA;
+ GfxFont *font;
+ Object obj1;
+
+ // get base font name
+ nameA = NULL;
+ fontDict->lookup("BaseFont", &obj1);
+ if (obj1.isName()) {
+ nameA = new GString(obj1.getName());
+ }
+ obj1.free();
+
+ // get font type
+ font = NULL;
+ fontDict->lookup("Subtype", &obj1);
+ if (obj1.isName("Type1") || obj1.isName("MMType1")) {
+ font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType1, fontDict);
+ } else if (obj1.isName("Type1C")) {
+ font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType1C, fontDict);
+ } else if (obj1.isName("Type3")) {
+ font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType3, fontDict);
+ } else if (obj1.isName("TrueType")) {
+ font = new Gfx8BitFont(xref, tagA, idA, nameA, fontTrueType, fontDict);
+ } else if (obj1.isName("Type0")) {
+ font = new GfxCIDFont(xref, tagA, idA, nameA, fontDict);
+ } else {
+ error(-1, "Unknown font type: '%s'",
+ obj1.isName() ? obj1.getName() : "???");
+ font = new Gfx8BitFont(xref, tagA, idA, nameA, fontUnknownType, fontDict);
+ }
+ obj1.free();
+
+ return font;
+}
+
+GfxFont::GfxFont(char *tagA, Ref idA, GString *nameA) {
+ ok = gFalse;
+ tag = new GString(tagA);
+ id = idA;
+ name = nameA;
+ origName = nameA;
+ embFontName = NULL;
+ extFontFile = NULL;
+}
+
+GfxFont::~GfxFont() {
+ delete tag;
+ if (origName && origName != name) {
+ delete origName;
+ }
+ if (name) {
+ delete name;
+ }
+ if (embFontName) {
+ delete embFontName;
+ }
+ if (extFontFile) {
+ delete extFontFile;
+ }
+}
+
+void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) {
+ Object obj1, obj2, obj3, obj4;
+ double t;
+ int i;
+
+ // assume Times-Roman by default (for substitution purposes)
+ flags = fontSerif;
+
+ embFontID.num = -1;
+ embFontID.gen = -1;
+ missingWidth = 0;
+
+ if (fontDict->lookup("FontDescriptor", &obj1)->isDict()) {
+
+ // get flags
+ if (obj1.dictLookup("Flags", &obj2)->isInt()) {
+ flags = obj2.getInt();
+ }
+ obj2.free();
+
+ // get name
+ obj1.dictLookup("FontName", &obj2);
+ if (obj2.isName()) {
+ embFontName = new GString(obj2.getName());
+ }
+ obj2.free();
+
+ // look for embedded font file
+ if (obj1.dictLookupNF("FontFile", &obj2)->isRef()) {
+ embFontID = obj2.getRef();
+ if (type != fontType1) {
+ error(-1, "Mismatch between font type and embedded font file");
+ type = fontType1;
+ }
+ }
+ obj2.free();
+ if (embFontID.num == -1 &&
+ obj1.dictLookupNF("FontFile2", &obj2)->isRef()) {
+ embFontID = obj2.getRef();
+ if (type != fontTrueType && type != fontCIDType2) {
+ error(-1, "Mismatch between font type and embedded font file");
+ type = type == fontCIDType0 ? fontCIDType2 : fontTrueType;
+ }
+ }
+ obj2.free();
+ if (embFontID.num == -1 &&
+ obj1.dictLookupNF("FontFile3", &obj2)->isRef()) {
+ if (obj2.fetch(xref, &obj3)->isStream()) {
+ obj3.streamGetDict()->lookup("Subtype", &obj4);
+ if (obj4.isName("Type1")) {
+ embFontID = obj2.getRef();
+ if (type != fontType1) {
+ error(-1, "Mismatch between font type and embedded font file");
+ type = fontType1;
+ }
+ } else if (obj4.isName("Type1C")) {
+ embFontID = obj2.getRef();
+ if (type != fontType1 && type != fontType1C) {
+ error(-1, "Mismatch between font type and embedded font file");
+ }
+ type = fontType1C;
+ } else if (obj4.isName("TrueType")) {
+ embFontID = obj2.getRef();
+ if (type != fontTrueType) {
+ error(-1, "Mismatch between font type and embedded font file");
+ type = fontTrueType;
+ }
+ } else if (obj4.isName("CIDFontType0C")) {
+ embFontID = obj2.getRef();
+ if (type != fontCIDType0) {
+ error(-1, "Mismatch between font type and embedded font file");
+ }
+ type = fontCIDType0C;
+ } else if (obj4.isName("OpenType")) {
+ embFontID = obj2.getRef();
+ if (type == fontTrueType) {
+ type = fontTrueTypeOT;
+ } else if (type == fontType1) {
+ type = fontType1COT;
+ } else if (type == fontCIDType0) {
+ type = fontCIDType0COT;
+ } else if (type == fontCIDType2) {
+ type = fontCIDType2OT;
+ } else {
+ error(-1, "Mismatch between font type and embedded font file");
+ }
+ } else {
+ error(-1, "Unknown embedded font type '%s'",
+ obj4.isName() ? obj4.getName() : "???");
+ }
+ obj4.free();
+ }
+ obj3.free();
+ }
+ obj2.free();
+
+ // look for MissingWidth
+ obj1.dictLookup("MissingWidth", &obj2);
+ if (obj2.isNum()) {
+ missingWidth = obj2.getNum();
+ }
+ obj2.free();
+
+ // get Ascent and Descent
+ obj1.dictLookup("Ascent", &obj2);
+ if (obj2.isNum()) {
+ t = 0.001 * obj2.getNum();
+ // some broken font descriptors set ascent and descent to 0
+ if (t != 0) {
+ ascent = t;
+ }
+ }
+ obj2.free();
+ obj1.dictLookup("Descent", &obj2);
+ if (obj2.isNum()) {
+ t = 0.001 * obj2.getNum();
+ // some broken font descriptors set ascent and descent to 0
+ if (t != 0) {
+ descent = t;
+ }
+ // some broken font descriptors specify a positive descent
+ if (descent > 0) {
+ descent = -descent;
+ }
+ }
+ obj2.free();
+
+ // font FontBBox
+ if (obj1.dictLookup("FontBBox", &obj2)->isArray()) {
+ for (i = 0; i < 4 && i < obj2.arrayGetLength(); ++i) {
+ if (obj2.arrayGet(i, &obj3)->isNum()) {
+ fontBBox[i] = 0.001 * obj3.getNum();
+ }
+ obj3.free();
+ }
+ }
+ obj2.free();
+
+ }
+ obj1.free();
+}
+
+CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits,
+ CharCodeToUnicode *ctu) {
+ GString *buf;
+ Object obj1;
+ int c;
+
+ if (!fontDict->lookup("ToUnicode", &obj1)->isStream()) {
+ obj1.free();
+ return NULL;
+ }
+ buf = new GString();
+ obj1.streamReset();
+ while ((c = obj1.streamGetChar()) != EOF) {
+ buf->append(c);
+ }
+ obj1.streamClose();
+ obj1.free();
+ if (ctu) {
+ ctu->mergeCMap(buf, nBits);
+ } else {
+ ctu = CharCodeToUnicode::parseCMap(buf, nBits);
+ }
+ delete buf;
+ return ctu;
+}
+
+void GfxFont::findExtFontFile() {
+ static char *type1Exts[] = { ".pfa", ".pfb", ".ps", "", NULL };
+ static char *ttExts[] = { ".ttf", ".ttc", NULL };
+
+ if (name) {
+ if (type == fontType1) {
+ extFontFile = globalParams->findFontFile(name, type1Exts);
+ } else if (type == fontTrueType) {
+ extFontFile = globalParams->findFontFile(name, ttExts);
+ }
+ }
+}
+
+char *GfxFont::readExtFontFile(int *len) {
+ FILE *f;
+ char *buf;
+
+ if (!(f = fopen(extFontFile->getCString(), "rb"))) {
+ error(-1, "External font file '%s' vanished", extFontFile->getCString());
+ return NULL;
+ }
+ fseek(f, 0, SEEK_END);
+ *len = (int)ftell(f);
+ fseek(f, 0, SEEK_SET);
+ buf = (char *)gmalloc(*len);
+ if ((int)fread(buf, 1, *len, f) != *len) {
+ error(-1, "Error reading external font file '%s'",
+ extFontFile->getCString());
+ }
+ fclose(f);
+ return buf;
+}
+
+char *GfxFont::readEmbFontFile(XRef *xref, int *len) {
+ char *buf;
+ Object obj1, obj2;
+ Stream *str;
+ int c;
+ int size, i;
+
+ obj1.initRef(embFontID.num, embFontID.gen);
+ obj1.fetch(xref, &obj2);
+ if (!obj2.isStream()) {
+ error(-1, "Embedded font file is not a stream");
+ obj2.free();
+ obj1.free();
+ embFontID.num = -1;
+ return NULL;
+ }
+ str = obj2.getStream();
+
+ buf = NULL;
+ i = size = 0;
+ str->reset();
+ while ((c = str->getChar()) != EOF) {
+ if (i == size) {
+ size += 4096;
+ buf = (char *)grealloc(buf, size);
+ }
+ buf[i++] = c;
+ }
+ *len = i;
+ str->close();
+
+ obj2.free();
+ obj1.free();
+
+ return buf;
+}
+
+//------------------------------------------------------------------------
+// Gfx8BitFont
+//------------------------------------------------------------------------
+
+Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
+ GfxFontType typeA, Dict *fontDict):
+ GfxFont(tagA, idA, nameA)
+{
+ GString *name2;
+ BuiltinFont *builtinFont;
+ char **baseEnc;
+ GBool baseEncFromFontFile;
+ char *buf;
+ int len;
+ FoFiType1 *ffT1;
+ FoFiType1C *ffT1C;
+ int code, code2;
+ char *charName;
+ GBool missing, hex;
+ Unicode toUnicode[256];
+ CharCodeToUnicode *utu, *ctu2;
+ Unicode uBuf[8];
+ double mul;
+ int firstChar, lastChar;
+ Gushort w;
+ Object obj1, obj2, obj3;
+ int n, i, a, b, m;
+
+ type = typeA;
+ ctu = NULL;
+
+ // do font name substitution for various aliases of the Base 14 font
+ // names
+ if (name) {
+ name2 = name->copy();
+ i = 0;
+ while (i < name2->getLength()) {
+ if (name2->getChar(i) == ' ') {
+ name2->del(i);
+ } else {
+ ++i;
+ }
+ }
+ a = 0;
+ b = sizeof(stdFontMap) / sizeof(StdFontMapEntry);
+ // invariant: stdFontMap[a].altName <= name2 < stdFontMap[b].altName
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ if (name2->cmp(stdFontMap[m].altName) >= 0) {
+ a = m;
+ } else {
+ b = m;
+ }
+ }
+ if (!name2->cmp(stdFontMap[a].altName)) {
+ name = new GString(stdFontMap[a].properName);
+ }
+ delete name2;
+ }
+
+ // is it a built-in font?
+ builtinFont = NULL;
+ if (name) {
+ for (i = 0; i < nBuiltinFonts; ++i) {
+ if (!name->cmp(builtinFonts[i].name)) {
+ builtinFont = &builtinFonts[i];
+ break;
+ }
+ }
+ }
+
+ // default ascent/descent values
+ if (builtinFont) {
+ ascent = 0.001 * builtinFont->ascent;
+ descent = 0.001 * builtinFont->descent;
+ fontBBox[0] = 0.001 * builtinFont->bbox[0];
+ fontBBox[1] = 0.001 * builtinFont->bbox[1];
+ fontBBox[2] = 0.001 * builtinFont->bbox[2];
+ fontBBox[3] = 0.001 * builtinFont->bbox[3];
+ } else {
+ ascent = 0.95;
+ descent = -0.35;
+ fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0;
+ }
+
+ // get info from font descriptor
+ readFontDescriptor(xref, fontDict);
+
+ // for non-embedded fonts, don't trust the ascent/descent/bbox
+ // values from the font descriptor
+ if (builtinFont && embFontID.num < 0) {
+ ascent = 0.001 * builtinFont->ascent;
+ descent = 0.001 * builtinFont->descent;
+ fontBBox[0] = 0.001 * builtinFont->bbox[0];
+ fontBBox[1] = 0.001 * builtinFont->bbox[1];
+ fontBBox[2] = 0.001 * builtinFont->bbox[2];
+ fontBBox[3] = 0.001 * builtinFont->bbox[3];
+ }
+
+ // look for an external font file
+ findExtFontFile();
+
+ // get font matrix
+ fontMat[0] = fontMat[3] = 1;
+ fontMat[1] = fontMat[2] = fontMat[4] = fontMat[5] = 0;
+ if (fontDict->lookup("FontMatrix", &obj1)->isArray()) {
+ for (i = 0; i < 6 && i < obj1.arrayGetLength(); ++i) {
+ if (obj1.arrayGet(i, &obj2)->isNum()) {
+ fontMat[i] = obj2.getNum();
+ }
+ obj2.free();
+ }
+ }
+ obj1.free();
+
+ // get Type 3 bounding box, font definition, and resources
+ if (type == fontType3) {
+ if (fontDict->lookup("FontBBox", &obj1)->isArray()) {
+ for (i = 0; i < 4 && i < obj1.arrayGetLength(); ++i) {
+ if (obj1.arrayGet(i, &obj2)->isNum()) {
+ fontBBox[i] = obj2.getNum();
+ }
+ obj2.free();
+ }
+ }
+ obj1.free();
+ if (!fontDict->lookup("CharProcs", &charProcs)->isDict()) {
+ error(-1, "Missing or invalid CharProcs dictionary in Type 3 font");
+ charProcs.free();
+ }
+ if (!fontDict->lookup("Resources", &resources)->isDict()) {
+ resources.free();
+ }
+ }
+
+ //----- build the font encoding -----
+
+ // Encodings start with a base encoding, which can come from
+ // (in order of priority):
+ // 1. FontDict.Encoding or FontDict.Encoding.BaseEncoding
+ // - MacRoman / MacExpert / WinAnsi / Standard
+ // 2. embedded or external font file
+ // 3. default:
+ // - builtin --> builtin encoding
+ // - TrueType --> WinAnsiEncoding
+ // - others --> StandardEncoding
+ // and then add a list of differences (if any) from
+ // FontDict.Encoding.Differences.
+
+ // check FontDict for base encoding
+ hasEncoding = gFalse;
+ usesMacRomanEnc = gFalse;
+ baseEnc = NULL;
+ baseEncFromFontFile = gFalse;
+ fontDict->lookup("Encoding", &obj1);
+ if (obj1.isDict()) {
+ obj1.dictLookup("BaseEncoding", &obj2);
+ if (obj2.isName("MacRomanEncoding")) {
+ hasEncoding = gTrue;
+ usesMacRomanEnc = gTrue;
+ baseEnc = macRomanEncoding;
+ } else if (obj2.isName("MacExpertEncoding")) {
+ hasEncoding = gTrue;
+ baseEnc = macExpertEncoding;
+ } else if (obj2.isName("WinAnsiEncoding")) {
+ hasEncoding = gTrue;
+ baseEnc = winAnsiEncoding;
+ }
+ obj2.free();
+ } else if (obj1.isName("MacRomanEncoding")) {
+ hasEncoding = gTrue;
+ usesMacRomanEnc = gTrue;
+ baseEnc = macRomanEncoding;
+ } else if (obj1.isName("MacExpertEncoding")) {
+ hasEncoding = gTrue;
+ baseEnc = macExpertEncoding;
+ } else if (obj1.isName("WinAnsiEncoding")) {
+ hasEncoding = gTrue;
+ baseEnc = winAnsiEncoding;
+ }
+
+ // check embedded or external font file for base encoding
+ // (only for Type 1 fonts - trying to get an encoding out of a
+ // TrueType font is a losing proposition)
+ ffT1 = NULL;
+ ffT1C = NULL;
+ buf = NULL;
+ if (type == fontType1 && (extFontFile || embFontID.num >= 0)) {
+ if (extFontFile) {
+ ffT1 = FoFiType1::load(extFontFile->getCString());
+ } else {
+ buf = readEmbFontFile(xref, &len);
+ ffT1 = FoFiType1::make(buf, len);
+ }
+ if (ffT1) {
+ if (ffT1->getName()) {
+ if (embFontName) {
+ delete embFontName;
+ }
+ embFontName = new GString(ffT1->getName());
+ }
+ if (!baseEnc) {
+ baseEnc = ffT1->getEncoding();
+ baseEncFromFontFile = gTrue;
+ }
+ }
+ } else if (type == fontType1C && (extFontFile || embFontID.num >= 0)) {
+ if (extFontFile) {
+ ffT1C = FoFiType1C::load(extFontFile->getCString());
+ } else {
+ buf = readEmbFontFile(xref, &len);
+ ffT1C = FoFiType1C::make(buf, len);
+ }
+ if (ffT1C) {
+ if (ffT1C->getName()) {
+ if (embFontName) {
+ delete embFontName;
+ }
+ embFontName = new GString(ffT1C->getName());
+ }
+ if (!baseEnc) {
+ baseEnc = ffT1C->getEncoding();
+ baseEncFromFontFile = gTrue;
+ }
+ }
+ }
+ if (buf) {
+ gfree(buf);
+ }
+
+ // get default base encoding
+ if (!baseEnc) {
+ if (builtinFont && embFontID.num < 0) {
+ baseEnc = builtinFont->defaultBaseEnc;
+ hasEncoding = gTrue;
+ } else if (type == fontTrueType) {
+ baseEnc = winAnsiEncoding;
+ } else {
+ baseEnc = standardEncoding;
+ }
+ }
+
+ // copy the base encoding
+ for (i = 0; i < 256; ++i) {
+ enc[i] = baseEnc[i];
+ if ((encFree[i] = baseEncFromFontFile) && enc[i]) {
+ enc[i] = copyString(baseEnc[i]);
+ }
+ }
+
+ // some Type 1C font files have empty encodings, which can break the
+ // T1C->T1 conversion (since the 'seac' operator depends on having
+ // the accents in the encoding), so we fill in any gaps from
+ // StandardEncoding
+ if (type == fontType1C && (extFontFile || embFontID.num >= 0) &&
+ baseEncFromFontFile) {
+ for (i = 0; i < 256; ++i) {
+ if (!enc[i] && standardEncoding[i]) {
+ enc[i] = standardEncoding[i];
+ encFree[i] = gFalse;
+ }
+ }
+ }
+
+ // merge differences into encoding
+ if (obj1.isDict()) {
+ obj1.dictLookup("Differences", &obj2);
+ if (obj2.isArray()) {
+ hasEncoding = gTrue;
+ code = 0;
+ for (i = 0; i < obj2.arrayGetLength(); ++i) {
+ obj2.arrayGet(i, &obj3);
+ if (obj3.isInt()) {
+ code = obj3.getInt();
+ } else if (obj3.isName()) {
+ if (code >= 0 && code < 256) {
+ if (encFree[code]) {
+ gfree(enc[code]);
+ }
+ enc[code] = copyString(obj3.getName());
+ encFree[code] = gTrue;
+ }
+ ++code;
+ } else {
+ error(-1, "Wrong type in font encoding resource differences (%s)",
+ obj3.getTypeName());
+ }
+ obj3.free();
+ }
+ }
+ obj2.free();
+ }
+ obj1.free();
+ if (ffT1) {
+ delete ffT1;
+ }
+ if (ffT1C) {
+ delete ffT1C;
+ }
+
+ //----- build the mapping to Unicode -----
+
+ // pass 1: use the name-to-Unicode mapping table
+ missing = hex = gFalse;
+ for (code = 0; code < 256; ++code) {
+ if ((charName = enc[code])) {
+ if (!(toUnicode[code] = globalParams->mapNameToUnicode(charName)) &&
+ strcmp(charName, ".notdef")) {
+ // if it wasn't in the name-to-Unicode table, check for a
+ // name that looks like 'Axx' or 'xx', where 'A' is any letter
+ // and 'xx' is two hex digits
+ if ((strlen(charName) == 3 &&
+ isalpha(charName[0]) &&
+ isxdigit(charName[1]) && isxdigit(charName[2]) &&
+ ((charName[1] >= 'a' && charName[1] <= 'f') ||
+ (charName[1] >= 'A' && charName[1] <= 'F') ||
+ (charName[2] >= 'a' && charName[2] <= 'f') ||
+ (charName[2] >= 'A' && charName[2] <= 'F'))) ||
+ (strlen(charName) == 2 &&
+ isxdigit(charName[0]) && isxdigit(charName[1]) &&
+ ((charName[0] >= 'a' && charName[0] <= 'f') ||
+ (charName[0] >= 'A' && charName[0] <= 'F') ||
+ (charName[1] >= 'a' && charName[1] <= 'f') ||
+ (charName[1] >= 'A' && charName[1] <= 'F')))) {
+ hex = gTrue;
+ }
+ missing = gTrue;
+ }
+ } else {
+ toUnicode[code] = 0;
+ }
+ }
+
+ // pass 2: try to fill in the missing chars, looking for names of
+ // the form 'Axx', 'xx', 'Ann', 'ABnn', or 'nn', where 'A' and 'B'
+ // are any letters, 'xx' is two hex digits, and 'nn' is 2-4
+ // decimal digits
+ if (missing && globalParams->getMapNumericCharNames()) {
+ for (code = 0; code < 256; ++code) {
+ if ((charName = enc[code]) && !toUnicode[code] &&
+ strcmp(charName, ".notdef")) {
+ n = strlen(charName);
+ code2 = -1;
+ if (hex && n == 3 && isalpha(charName[0]) &&
+ isxdigit(charName[1]) && isxdigit(charName[2])) {
+ sscanf(charName+1, "%x", &code2);
+ } else if (hex && n == 2 &&
+ isxdigit(charName[0]) && isxdigit(charName[1])) {
+ sscanf(charName, "%x", &code2);
+ } else if (!hex && n >= 2 && n <= 4 &&
+ isdigit(charName[0]) && isdigit(charName[1])) {
+ code2 = atoi(charName);
+ } else if (n >= 3 && n <= 5 &&
+ isdigit(charName[1]) && isdigit(charName[2])) {
+ code2 = atoi(charName+1);
+ } else if (n >= 4 && n <= 6 &&
+ isdigit(charName[2]) && isdigit(charName[3])) {
+ code2 = atoi(charName+2);
+ }
+ if (code2 >= 0 && code2 <= 0xff) {
+ toUnicode[code] = (Unicode)code2;
+ }
+ }
+ }
+
+ // if the 'mapUnknownCharNames' flag is set, do a simple pass-through
+ // mapping for unknown character names
+ } else if (missing && globalParams->getMapUnknownCharNames()) {
+ for (code = 0; code < 256; ++code) {
+ if (!toUnicode[code]) {
+ toUnicode[code] = code;
+ }
+ }
+ }
+
+ // construct the char code -> Unicode mapping object
+ ctu = CharCodeToUnicode::make8BitToUnicode(toUnicode);
+
+ // merge in a ToUnicode CMap, if there is one -- this overwrites
+ // existing entries in ctu, i.e., the ToUnicode CMap takes
+ // precedence, but the other encoding info is allowed to fill in any
+ // holes
+ readToUnicodeCMap(fontDict, 8, ctu);
+
+ // look for a Unicode-to-Unicode mapping
+ if (name && (utu = globalParams->getUnicodeToUnicode(name))) {
+ for (i = 0; i < 256; ++i) {
+ toUnicode[i] = 0;
+ }
+ ctu2 = CharCodeToUnicode::make8BitToUnicode(toUnicode);
+ for (i = 0; i < 256; ++i) {
+ n = ctu->mapToUnicode((CharCode)i, uBuf, 8);
+ if (n >= 1) {
+ n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8);
+ if (n >= 1) {
+ ctu2->setMapping((CharCode)i, uBuf, n);
+ }
+ }
+ }
+ utu->decRefCnt();
+ delete ctu;
+ ctu = ctu2;
+ }
+
+ //----- get the character widths -----
+
+ // initialize all widths
+ for (code = 0; code < 256; ++code) {
+ widths[code] = missingWidth * 0.001;
+ }
+
+ // use widths from font dict, if present
+ fontDict->lookup("FirstChar", &obj1);
+ firstChar = obj1.isInt() ? obj1.getInt() : 0;
+ obj1.free();
+ if (firstChar < 0 || firstChar > 255) {
+ firstChar = 0;
+ }
+ fontDict->lookup("LastChar", &obj1);
+ lastChar = obj1.isInt() ? obj1.getInt() : 255;
+ obj1.free();
+ if (lastChar < 0 || lastChar > 255) {
+ lastChar = 255;
+ }
+ mul = (type == fontType3) ? fontMat[0] : 0.001;
+ fontDict->lookup("Widths", &obj1);
+ if (obj1.isArray()) {
+ flags |= fontFixedWidth;
+ if (obj1.arrayGetLength() < lastChar - firstChar + 1) {
+ lastChar = firstChar + obj1.arrayGetLength() - 1;
+ }
+ for (code = firstChar; code <= lastChar; ++code) {
+ obj1.arrayGet(code - firstChar, &obj2);
+ if (obj2.isNum()) {
+ widths[code] = obj2.getNum() * mul;
+ if (widths[code] != widths[firstChar]) {
+ flags &= ~fontFixedWidth;
+ }
+ }
+ obj2.free();
+ }
+
+ // use widths from built-in font
+ } else if (builtinFont) {
+ // this is a kludge for broken PDF files that encode char 32
+ // as .notdef
+ if (builtinFont->widths->getWidth("space", &w)) {
+ widths[32] = 0.001 * w;
+ }
+ for (code = 0; code < 256; ++code) {
+ if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) {
+ widths[code] = 0.001 * w;
+ }
+ }
+
+ // couldn't find widths -- use defaults
+ } else {
+ // this is technically an error -- the Widths entry is required
+ // for all but the Base-14 fonts -- but certain PDF generators
+ // apparently don't include widths for Arial and TimesNewRoman
+ if (isFixedWidth()) {
+ i = 0;
+ } else if (isSerif()) {
+ i = 8;
+ } else {
+ i = 4;
+ }
+ if (isBold()) {
+ i += 2;
+ }
+ if (isItalic()) {
+ i += 1;
+ }
+ builtinFont = builtinFontSubst[i];
+ // this is a kludge for broken PDF files that encode char 32
+ // as .notdef
+ if (builtinFont->widths->getWidth("space", &w)) {
+ widths[32] = 0.001 * w;
+ }
+ for (code = 0; code < 256; ++code) {
+ if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) {
+ widths[code] = 0.001 * w;
+ }
+ }
+ }
+ obj1.free();
+
+ ok = gTrue;
+}
+
+Gfx8BitFont::~Gfx8BitFont() {
+ int i;
+
+ for (i = 0; i < 256; ++i) {
+ if (encFree[i] && enc[i]) {
+ gfree(enc[i]);
+ }
+ }
+ ctu->decRefCnt();
+ if (charProcs.isDict()) {
+ charProcs.free();
+ }
+ if (resources.isDict()) {
+ resources.free();
+ }
+}
+
+int Gfx8BitFont::getNextChar(char *s, int /*len*/, CharCode *code,
+ Unicode *u, int uSize, int *uLen,
+ double *dx, double *dy, double *ox, double *oy) {
+ CharCode c;
+
+ *code = c = (CharCode)(*s & 0xff);
+ *uLen = ctu->mapToUnicode(c, u, uSize);
+ *dx = widths[c];
+ *dy = *ox = *oy = 0;
+ return 1;
+}
+
+CharCodeToUnicode *Gfx8BitFont::getToUnicode() {
+ ctu->incRefCnt();
+ return ctu;
+}
+
+Gushort *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) {
+ Gushort *map;
+ int cmapPlatform, cmapEncoding;
+ int unicodeCmap, macRomanCmap, msSymbolCmap, cmap;
+ GBool useMacRoman, useUnicode;
+ char *charName;
+ Unicode u;
+ int code, i, n;
+
+ map = (Gushort *)gmallocn(256, sizeof(Gushort));
+ for (i = 0; i < 256; ++i) {
+ map[i] = 0;
+ }
+
+ // To match up with the Adobe-defined behaviour, we choose a cmap
+ // like this:
+ // 1. If the PDF font has an encoding:
+ // 1a. If the PDF font specified MacRomanEncoding and the
+ // TrueType font has a Macintosh Roman cmap, use it, and
+ // reverse map the char names through MacRomanEncoding to
+ // get char codes.
+ // 1b. If the TrueType font has a Microsoft Unicode cmap or a
+ // non-Microsoft Unicode cmap, use it, and use the Unicode
+ // indexes, not the char codes.
+ // 1c. If the PDF font is symbolic and the TrueType font has a
+ // Microsoft Symbol cmap, use it, and use char codes
+ // directly (possibly with an offset of 0xf000).
+ // 1d. If the TrueType font has a Macintosh Roman cmap, use it,
+ // as in case 1a.
+ // 2. If the PDF font does not have an encoding or the PDF font is
+ // symbolic:
+ // 2a. If the TrueType font has a Macintosh Roman cmap, use it,
+ // and use char codes directly (possibly with an offset of
+ // 0xf000).
+ // 2b. If the TrueType font has a Microsoft Symbol cmap, use it,
+ // and use char codes directly (possible with an offset of
+ // 0xf000).
+ // 3. If none of these rules apply, use the first cmap and hope for
+ // the best (this shouldn't happen).
+ unicodeCmap = macRomanCmap = msSymbolCmap = -1;
+ for (i = 0; i < ff->getNumCmaps(); ++i) {
+ cmapPlatform = ff->getCmapPlatform(i);
+ cmapEncoding = ff->getCmapEncoding(i);
+ if ((cmapPlatform == 3 && cmapEncoding == 1) ||
+ cmapPlatform == 0) {
+ unicodeCmap = i;
+ } else if (cmapPlatform == 1 && cmapEncoding == 0) {
+ macRomanCmap = i;
+ } else if (cmapPlatform == 3 && cmapEncoding == 0) {
+ msSymbolCmap = i;
+ }
+ }
+ cmap = 0;
+ useMacRoman = gFalse;
+ useUnicode = gFalse;
+ if (hasEncoding) {
+ if (usesMacRomanEnc && macRomanCmap >= 0) {
+ cmap = macRomanCmap;
+ useMacRoman = gTrue;
+ } else if (unicodeCmap >= 0) {
+ cmap = unicodeCmap;
+ useUnicode = gTrue;
+ } else if ((flags & fontSymbolic) && msSymbolCmap >= 0) {
+ cmap = msSymbolCmap;
+ } else if ((flags & fontSymbolic) && macRomanCmap >= 0) {
+ cmap = macRomanCmap;
+ } else if (macRomanCmap >= 0) {
+ cmap = macRomanCmap;
+ useMacRoman = gTrue;
+ }
+ } else {
+ if (msSymbolCmap >= 0) {
+ cmap = msSymbolCmap;
+ } else if (macRomanCmap >= 0) {
+ cmap = macRomanCmap;
+ }
+ }
+
+ // reverse map the char names through MacRomanEncoding, then map the
+ // char codes through the cmap
+ if (useMacRoman) {
+ for (i = 0; i < 256; ++i) {
+ if ((charName = enc[i])) {
+ if ((code = globalParams->getMacRomanCharCode(charName))) {
+ map[i] = ff->mapCodeToGID(cmap, code);
+ }
+ }
+ }
+
+ // map Unicode through the cmap
+ } else if (useUnicode) {
+ for (i = 0; i < 256; ++i) {
+ if (((charName = enc[i]) &&
+ (u = globalParams->mapNameToUnicode(charName))) ||
+ (n = ctu->mapToUnicode((CharCode)i, &u, 1))) {
+ map[i] = ff->mapCodeToGID(cmap, u);
+ }
+ }
+
+ // map the char codes through the cmap, possibly with an offset of
+ // 0xf000
+ } else {
+ for (i = 0; i < 256; ++i) {
+ if (!(map[i] = ff->mapCodeToGID(cmap, i))) {
+ map[i] = ff->mapCodeToGID(cmap, 0xf000 + i);
+ }
+ }
+ }
+
+ // try the TrueType 'post' table to handle any unmapped characters
+ for (i = 0; i < 256; ++i) {
+ if (!map[i] && (charName = enc[i])) {
+ map[i] = (Gushort)(int)ff->mapNameToGID(charName);
+ }
+ }
+
+ return map;
+}
+
+Dict *Gfx8BitFont::getCharProcs() {
+ return charProcs.isDict() ? charProcs.getDict() : (Dict *)NULL;
+}
+
+Object *Gfx8BitFont::getCharProc(int code, Object *proc) {
+ if (enc[code] && charProcs.isDict()) {
+ charProcs.dictLookup(enc[code], proc);
+ } else {
+ proc->initNull();
+ }
+ return proc;
+}
+
+Dict *Gfx8BitFont::getResources() {
+ return resources.isDict() ? resources.getDict() : (Dict *)NULL;
+}
+
+//------------------------------------------------------------------------
+// GfxCIDFont
+//------------------------------------------------------------------------
+
+static int CDECL cmpWidthExcep(const void *w1, const void *w2) {
+ return ((GfxFontCIDWidthExcep *)w1)->first -
+ ((GfxFontCIDWidthExcep *)w2)->first;
+}
+
+static int CDECL cmpWidthExcepV(const void *w1, const void *w2) {
+ return ((GfxFontCIDWidthExcepV *)w1)->first -
+ ((GfxFontCIDWidthExcepV *)w2)->first;
+}
+
+GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
+ Dict *fontDict):
+ GfxFont(tagA, idA, nameA)
+{
+ Dict *desFontDict;
+ GString *collection, *cMapName;
+ Object desFontDictObj;
+ Object obj1, obj2, obj3, obj4, obj5, obj6;
+ CharCodeToUnicode *utu;
+ CharCode c;
+ Unicode uBuf[8];
+ int c1, c2;
+ int excepsSize, i, j, k, n;
+
+ ascent = 0.95;
+ descent = -0.35;
+ fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0;
+ cMap = NULL;
+ ctu = NULL;
+ widths.defWidth = 1.0;
+ widths.defHeight = -1.0;
+ widths.defVY = 0.880;
+ widths.exceps = NULL;
+ widths.nExceps = 0;
+ widths.excepsV = NULL;
+ widths.nExcepsV = 0;
+ cidToGID = NULL;
+ cidToGIDLen = 0;
+
+ // get the descendant font
+ if (!fontDict->lookup("DescendantFonts", &obj1)->isArray()) {
+ error(-1, "Missing DescendantFonts entry in Type 0 font");
+ obj1.free();
+ goto err1;
+ }
+ if (!obj1.arrayGet(0, &desFontDictObj)->isDict()) {
+ error(-1, "Bad descendant font in Type 0 font");
+ goto err3;
+ }
+ obj1.free();
+ desFontDict = desFontDictObj.getDict();
+
+ // font type
+ if (!desFontDict->lookup("Subtype", &obj1)) {
+ error(-1, "Missing Subtype entry in Type 0 descendant font");
+ goto err3;
+ }
+ if (obj1.isName("CIDFontType0")) {
+ type = fontCIDType0;
+ } else if (obj1.isName("CIDFontType2")) {
+ type = fontCIDType2;
+ } else {
+ error(-1, "Unknown Type 0 descendant font type '%s'",
+ obj1.isName() ? obj1.getName() : "???");
+ goto err3;
+ }
+ obj1.free();
+
+ // get info from font descriptor
+ readFontDescriptor(xref, desFontDict);
+
+ // look for an external font file
+ findExtFontFile();
+
+ //----- encoding info -----
+
+ // char collection
+ if (!desFontDict->lookup("CIDSystemInfo", &obj1)->isDict()) {
+ error(-1, "Missing CIDSystemInfo dictionary in Type 0 descendant font");
+ goto err3;
+ }
+ obj1.dictLookup("Registry", &obj2);
+ obj1.dictLookup("Ordering", &obj3);
+ if (!obj2.isString() || !obj3.isString()) {
+ error(-1, "Invalid CIDSystemInfo dictionary in Type 0 descendant font");
+ goto err4;
+ }
+ collection = obj2.getString()->copy()->append('-')->append(obj3.getString());
+ obj3.free();
+ obj2.free();
+ obj1.free();
+
+ // look for a ToUnicode CMap
+ if (!(ctu = readToUnicodeCMap(fontDict, 16, NULL))) {
+
+ // the "Adobe-Identity" and "Adobe-UCS" collections don't have
+ // cidToUnicode files
+ if (collection->cmp("Adobe-Identity") &&
+ collection->cmp("Adobe-UCS")) {
+
+ // look for a user-supplied .cidToUnicode file
+ if (!(ctu = globalParams->getCIDToUnicode(collection))) {
+ error(-1, "Unknown character collection '%s'",
+ collection->getCString());
+ // fall-through, assuming the Identity mapping -- this appears
+ // to match Adobe's behavior
+ }
+ }
+ }
+
+ // look for a Unicode-to-Unicode mapping
+ if (name && (utu = globalParams->getUnicodeToUnicode(name))) {
+ if (ctu) {
+ for (c = 0; c < ctu->getLength(); ++c) {
+ n = ctu->mapToUnicode(c, uBuf, 8);
+ if (n >= 1) {
+ n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8);
+ if (n >= 1) {
+ ctu->setMapping(c, uBuf, n);
+ }
+ }
+ }
+ utu->decRefCnt();
+ } else {
+ ctu = utu;
+ }
+ }
+
+ // encoding (i.e., CMap)
+ //~ need to handle a CMap stream here
+ //~ also need to deal with the UseCMap entry in the stream dict
+ if (!fontDict->lookup("Encoding", &obj1)->isName()) {
+ error(-1, "Missing or invalid Encoding entry in Type 0 font");
+ delete collection;
+ goto err3;
+ }
+ cMapName = new GString(obj1.getName());
+ obj1.free();
+ if (!(cMap = globalParams->getCMap(collection, cMapName))) {
+ error(-1, "Unknown CMap '%s' for character collection '%s'",
+ cMapName->getCString(), collection->getCString());
+ delete collection;
+ delete cMapName;
+ goto err2;
+ }
+ delete collection;
+ delete cMapName;
+
+ // CIDToGIDMap (for embedded TrueType fonts)
+ if (type == fontCIDType2) {
+ desFontDict->lookup("CIDToGIDMap", &obj1);
+ if (obj1.isStream()) {
+ cidToGIDLen = 0;
+ i = 64;
+ cidToGID = (Gushort *)gmallocn(i, sizeof(Gushort));
+ obj1.streamReset();
+ while ((c1 = obj1.streamGetChar()) != EOF &&
+ (c2 = obj1.streamGetChar()) != EOF) {
+ if (cidToGIDLen == i) {
+ i *= 2;
+ cidToGID = (Gushort *)greallocn(cidToGID, i, sizeof(Gushort));
+ }
+ cidToGID[cidToGIDLen++] = (Gushort)((c1 << 8) + c2);
+ }
+ } else if (!obj1.isName("Identity") && !obj1.isNull()) {
+ error(-1, "Invalid CIDToGIDMap entry in CID font");
+ }
+ obj1.free();
+ }
+
+ //----- character metrics -----
+
+ // default char width
+ if (desFontDict->lookup("DW", &obj1)->isInt()) {
+ widths.defWidth = obj1.getInt() * 0.001;
+ }
+ obj1.free();
+
+ // char width exceptions
+ if (desFontDict->lookup("W", &obj1)->isArray()) {
+ excepsSize = 0;
+ i = 0;
+ while (i + 1 < obj1.arrayGetLength()) {
+ obj1.arrayGet(i, &obj2);
+ obj1.arrayGet(i + 1, &obj3);
+ if (obj2.isInt() && obj3.isInt() && i + 2 < obj1.arrayGetLength()) {
+ if (obj1.arrayGet(i + 2, &obj4)->isNum()) {
+ if (widths.nExceps == excepsSize) {
+ excepsSize += 16;
+ widths.exceps = (GfxFontCIDWidthExcep *)
+ greallocn(widths.exceps,
+ excepsSize, sizeof(GfxFontCIDWidthExcep));
+ }
+ widths.exceps[widths.nExceps].first = obj2.getInt();
+ widths.exceps[widths.nExceps].last = obj3.getInt();
+ widths.exceps[widths.nExceps].width = obj4.getNum() * 0.001;
+ ++widths.nExceps;
+ } else {
+ error(-1, "Bad widths array in Type 0 font");
+ }
+ obj4.free();
+ i += 3;
+ } else if (obj2.isInt() && obj3.isArray()) {
+ if (widths.nExceps + obj3.arrayGetLength() > excepsSize) {
+ excepsSize = (widths.nExceps + obj3.arrayGetLength() + 15) & ~15;
+ widths.exceps = (GfxFontCIDWidthExcep *)
+ greallocn(widths.exceps,
+ excepsSize, sizeof(GfxFontCIDWidthExcep));
+ }
+ j = obj2.getInt();
+ for (k = 0; k < obj3.arrayGetLength(); ++k) {
+ if (obj3.arrayGet(k, &obj4)->isNum()) {
+ widths.exceps[widths.nExceps].first = j;
+ widths.exceps[widths.nExceps].last = j;
+ widths.exceps[widths.nExceps].width = obj4.getNum() * 0.001;
+ ++j;
+ ++widths.nExceps;
+ } else {
+ error(-1, "Bad widths array in Type 0 font");
+ }
+ obj4.free();
+ }
+ i += 2;
+ } else {
+ error(-1, "Bad widths array in Type 0 font");
+ ++i;
+ }
+ obj3.free();
+ obj2.free();
+ }
+ qsort(widths.exceps, widths.nExceps, sizeof(GfxFontCIDWidthExcep),
+ &cmpWidthExcep);
+ }
+ obj1.free();
+
+ // default metrics for vertical font
+ if (desFontDict->lookup("DW2", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2) {
+ if (obj1.arrayGet(0, &obj2)->isNum()) {
+ widths.defVY = obj2.getNum() * 0.001;
+ }
+ obj2.free();
+ if (obj1.arrayGet(1, &obj2)->isNum()) {
+ widths.defHeight = obj2.getNum() * 0.001;
+ }
+ obj2.free();
+ }
+ obj1.free();
+
+ // char metric exceptions for vertical font
+ if (desFontDict->lookup("W2", &obj1)->isArray()) {
+ excepsSize = 0;
+ i = 0;
+ while (i + 1 < obj1.arrayGetLength()) {
+ obj1.arrayGet(i, &obj2);
+ obj1.arrayGet(i+ 1, &obj3);
+ if (obj2.isInt() && obj3.isInt() && i + 4 < obj1.arrayGetLength()) {
+ if (obj1.arrayGet(i + 2, &obj4)->isNum() &&
+ obj1.arrayGet(i + 3, &obj5)->isNum() &&
+ obj1.arrayGet(i + 4, &obj6)->isNum()) {
+ if (widths.nExcepsV == excepsSize) {
+ excepsSize += 16;
+ widths.excepsV = (GfxFontCIDWidthExcepV *)
+ greallocn(widths.excepsV,
+ excepsSize, sizeof(GfxFontCIDWidthExcepV));
+ }
+ widths.excepsV[widths.nExcepsV].first = obj2.getInt();
+ widths.excepsV[widths.nExcepsV].last = obj3.getInt();
+ widths.excepsV[widths.nExcepsV].height = obj4.getNum() * 0.001;
+ widths.excepsV[widths.nExcepsV].vx = obj5.getNum() * 0.001;
+ widths.excepsV[widths.nExcepsV].vy = obj6.getNum() * 0.001;
+ ++widths.nExcepsV;
+ } else {
+ error(-1, "Bad widths (W2) array in Type 0 font");
+ }
+ obj6.free();
+ obj5.free();
+ obj4.free();
+ i += 5;
+ } else if (obj2.isInt() && obj3.isArray()) {
+ if (widths.nExcepsV + obj3.arrayGetLength() / 3 > excepsSize) {
+ excepsSize =
+ (widths.nExcepsV + obj3.arrayGetLength() / 3 + 15) & ~15;
+ widths.excepsV = (GfxFontCIDWidthExcepV *)
+ greallocn(widths.excepsV,
+ excepsSize, sizeof(GfxFontCIDWidthExcepV));
+ }
+ j = obj2.getInt();
+ for (k = 0; k < obj3.arrayGetLength(); k += 3) {
+ if (obj3.arrayGet(k, &obj4)->isNum() &&
+ obj3.arrayGet(k+1, &obj5)->isNum() &&
+ obj3.arrayGet(k+2, &obj6)->isNum()) {
+ widths.excepsV[widths.nExceps].first = j;
+ widths.excepsV[widths.nExceps].last = j;
+ widths.excepsV[widths.nExceps].height = obj4.getNum() * 0.001;
+ widths.excepsV[widths.nExceps].vx = obj5.getNum() * 0.001;
+ widths.excepsV[widths.nExceps].vy = obj6.getNum() * 0.001;
+ ++j;
+ ++widths.nExcepsV;
+ } else {
+ error(-1, "Bad widths (W2) array in Type 0 font");
+ }
+ obj6.free();
+ obj5.free();
+ obj4.free();
+ }
+ i += 2;
+ } else {
+ error(-1, "Bad widths (W2) array in Type 0 font");
+ ++i;
+ }
+ obj3.free();
+ obj2.free();
+ }
+ qsort(widths.excepsV, widths.nExcepsV, sizeof(GfxFontCIDWidthExcepV),
+ &cmpWidthExcepV);
+ }
+ obj1.free();
+
+ desFontDictObj.free();
+ ok = gTrue;
+ return;
+
+ err4:
+ obj3.free();
+ obj2.free();
+ err3:
+ obj1.free();
+ err2:
+ desFontDictObj.free();
+ err1:;
+}
+
+GfxCIDFont::~GfxCIDFont() {
+ if (cMap) {
+ cMap->decRefCnt();
+ }
+ if (ctu) {
+ ctu->decRefCnt();
+ }
+ gfree(widths.exceps);
+ gfree(widths.excepsV);
+ if (cidToGID) {
+ gfree(cidToGID);
+ }
+}
+
+int GfxCIDFont::getNextChar(char *s, int len, CharCode *code,
+ Unicode *u, int uSize, int *uLen,
+ double *dx, double *dy, double *ox, double *oy) {
+ CID cid;
+ double w, h, vx, vy;
+ int n, a, b, m;
+
+ if (!cMap) {
+ *code = 0;
+ *uLen = 0;
+ *dx = *dy = 0;
+ return 1;
+ }
+
+ *code = (CharCode)(cid = cMap->getCID(s, len, &n));
+ if (ctu) {
+ *uLen = ctu->mapToUnicode(cid, u, uSize);
+ } else {
+ *uLen = 0;
+ }
+
+ // horizontal
+ if (cMap->getWMode() == 0) {
+ w = widths.defWidth;
+ h = vx = vy = 0;
+ if (widths.nExceps > 0 && cid >= widths.exceps[0].first) {
+ a = 0;
+ b = widths.nExceps;
+ // invariant: widths.exceps[a].first <= cid < widths.exceps[b].first
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ if (widths.exceps[m].first <= cid) {
+ a = m;
+ } else {
+ b = m;
+ }
+ }
+ if (cid <= widths.exceps[a].last) {
+ w = widths.exceps[a].width;
+ }
+ }
+
+ // vertical
+ } else {
+ w = 0;
+ h = widths.defHeight;
+ vx = widths.defWidth / 2;
+ vy = widths.defVY;
+ if (widths.nExcepsV > 0 && cid >= widths.excepsV[0].first) {
+ a = 0;
+ b = widths.nExcepsV;
+ // invariant: widths.excepsV[a].first <= cid < widths.excepsV[b].first
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ if (widths.excepsV[m].last <= cid) {
+ a = m;
+ } else {
+ b = m;
+ }
+ }
+ if (cid <= widths.excepsV[a].last) {
+ h = widths.excepsV[a].height;
+ vx = widths.excepsV[a].vx;
+ vy = widths.excepsV[a].vy;
+ }
+ }
+ }
+
+ *dx = w;
+ *dy = h;
+ *ox = vx;
+ *oy = vy;
+
+ return n;
+}
+
+int GfxCIDFont::getWMode() {
+ return cMap ? cMap->getWMode() : 0;
+}
+
+CharCodeToUnicode *GfxCIDFont::getToUnicode() {
+ if (ctu) {
+ ctu->incRefCnt();
+ }
+ return ctu;
+}
+
+GString *GfxCIDFont::getCollection() {
+ return cMap ? cMap->getCollection() : (GString *)NULL;
+}
+
+Gushort *GfxCIDFont::getCodeToGIDMap(FoFiTrueType *ff, int *mapsizep) {
+ Gushort *map;
+ int cmapPlatform, cmapEncoding;
+ int /*unicodeCmap, macRomanCmap, msSymbolCmap, */cmap;
+// GBool useMacRoman, useUnicode;
+// char *charName;
+ Unicode u;
+ int /*code, */i;
+ int mapsize;
+ int cidlen;
+
+ *mapsizep = 0;
+ if (!ctu) return NULL;
+
+ /* we use only unicode cmap */
+ cmap = -1;
+ for (i = 0; i < ff->getNumCmaps(); ++i) {
+ cmapPlatform = ff->getCmapPlatform(i);
+ cmapEncoding = ff->getCmapEncoding(i);
+ if ((cmapPlatform == 3 && cmapEncoding == 1) || cmapPlatform == 0)
+ cmap = i;
+ }
+ if (cmap < 0)
+ return NULL;
+
+ cidlen = 0;
+ mapsize = 64;
+ map = (Gushort *)gmalloc(mapsize * sizeof(Gushort));
+
+ while (cidlen < ctu->getLength()) {
+ int n;
+ if ((n = ctu->mapToUnicode((CharCode)cidlen, &u, 1)) == 0) {
+ cidlen++;
+ continue;
+ }
+ if (cidlen >= mapsize) {
+ while (cidlen >= mapsize)
+ mapsize *= 2;
+ map = (Gushort *)grealloc(map, mapsize * sizeof(Gushort));
+ }
+ map[cidlen] = ff->mapCodeToGID(cmap, u);
+ cidlen++;
+ }
+
+ *mapsizep = cidlen;
+ return map;
+}
+
+//------------------------------------------------------------------------
+// GfxFontDict
+//------------------------------------------------------------------------
+
+GfxFontDict::GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict) {
+ int i;
+ Object obj1, obj2;
+ Ref r;
+
+ numFonts = fontDict->getLength();
+ fonts = (GfxFont **)gmallocn(numFonts, sizeof(GfxFont *));
+ for (i = 0; i < numFonts; ++i) {
+ fontDict->getValNF(i, &obj1);
+ obj1.fetch(xref, &obj2);
+ if (obj2.isDict()) {
+ if (obj1.isRef()) {
+ r = obj1.getRef();
+ } else {
+ // no indirect reference for this font, so invent a unique one
+ // (legal generation numbers are five digits, so any 6-digit
+ // number would be safe)
+ r.num = i;
+ if (fontDictRef) {
+ r.gen = 100000 + fontDictRef->num;
+ } else {
+ r.gen = 999999;
+ }
+ }
+ fonts[i] = GfxFont::makeFont(xref, fontDict->getKey(i),
+ r, obj2.getDict());
+ if (fonts[i] && !fonts[i]->isOk()) {
+ delete fonts[i];
+ fonts[i] = NULL;
+ }
+ } else {
+ error(-1, "font resource is not a dictionary");
+ fonts[i] = NULL;
+ }
+ obj1.free();
+ obj2.free();
+ }
+}
+
+GfxFontDict::~GfxFontDict() {
+ int i;
+
+ for (i = 0; i < numFonts; ++i) {
+ if (fonts[i]) {
+ delete fonts[i];
+ }
+ }
+ gfree(fonts);
+}
+
+GfxFont *GfxFontDict::lookup(char *tag) {
+ int i;
+
+ for (i = 0; i < numFonts; ++i) {
+ if (fonts[i] && fonts[i]->matches(tag)) {
+ return fonts[i];
+ }
+ }
+ return NULL;
+}
diff --git a/kpdf/xpdf/xpdf/GfxFont.h b/kpdf/xpdf/xpdf/GfxFont.h
new file mode 100644
index 00000000..b4e84812
--- /dev/null
+++ b/kpdf/xpdf/xpdf/GfxFont.h
@@ -0,0 +1,322 @@
+//========================================================================
+//
+// GfxFont.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef GFXFONT_H
+#define GFXFONT_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "GString.h"
+#include "Object.h"
+#include "CharTypes.h"
+
+class Dict;
+class CMap;
+class CharCodeToUnicode;
+class FoFiTrueType;
+struct GfxFontCIDWidths;
+
+//------------------------------------------------------------------------
+// GfxFontType
+//------------------------------------------------------------------------
+
+enum GfxFontType {
+ //----- Gfx8BitFont
+ fontUnknownType,
+ fontType1,
+ fontType1C,
+ fontType1COT,
+ fontType3,
+ fontTrueType,
+ fontTrueTypeOT,
+ //----- GfxCIDFont
+ fontCIDType0,
+ fontCIDType0C,
+ fontCIDType0COT,
+ fontCIDType2,
+ fontCIDType2OT
+};
+
+//------------------------------------------------------------------------
+// GfxFontCIDWidths
+//------------------------------------------------------------------------
+
+struct GfxFontCIDWidthExcep {
+ CID first; // this record applies to
+ CID last; // CIDs <first>..<last>
+ double width; // char width
+};
+
+struct GfxFontCIDWidthExcepV {
+ CID first; // this record applies to
+ CID last; // CIDs <first>..<last>
+ double height; // char height
+ double vx, vy; // origin position
+};
+
+struct GfxFontCIDWidths {
+ double defWidth; // default char width
+ double defHeight; // default char height
+ double defVY; // default origin position
+ GfxFontCIDWidthExcep *exceps; // exceptions
+ int nExceps; // number of valid entries in exceps
+ GfxFontCIDWidthExcepV * // exceptions for vertical font
+ excepsV;
+ int nExcepsV; // number of valid entries in excepsV
+};
+
+//------------------------------------------------------------------------
+// GfxFont
+//------------------------------------------------------------------------
+
+#define fontFixedWidth (1 << 0)
+#define fontSerif (1 << 1)
+#define fontSymbolic (1 << 2)
+#define fontItalic (1 << 6)
+#define fontBold (1 << 18)
+
+class GfxFont {
+public:
+
+ // Build a GfxFont object.
+ static GfxFont *makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict);
+
+ GfxFont(char *tagA, Ref idA, GString *nameA);
+
+ virtual ~GfxFont();
+
+ GBool isOk() { return ok; }
+
+ // Get font tag.
+ GString *getTag() { return tag; }
+
+ // Get font dictionary ID.
+ Ref *getID() { return &id; }
+
+ // Does this font match the tag?
+ GBool matches(char *tagA) { return !tag->cmp(tagA); }
+
+ // Get base font name.
+ GString *getName() { return name; }
+
+ // Get the original font name (ignornig any munging that might have
+ // been done to map to a canonical Base-14 font name).
+ GString *getOrigName() { return origName; }
+
+ // Get font type.
+ GfxFontType getType() { return type; }
+ virtual GBool isCIDFont() { return gFalse; }
+
+ // Get embedded font ID, i.e., a ref for the font file stream.
+ // Returns false if there is no embedded font.
+ GBool getEmbeddedFontID(Ref *embID)
+ { *embID = embFontID; return embFontID.num >= 0; }
+
+ // Get the PostScript font name for the embedded font. Returns
+ // NULL if there is no embedded font.
+ GString *getEmbeddedFontName() { return embFontName; }
+
+ // Get the name of the external font file. Returns NULL if there
+ // is no external font file.
+ GString *getExtFontFile() { return extFontFile; }
+
+ // Get font descriptor flags.
+ int getFlags() { return flags; }
+ GBool isFixedWidth() { return flags & fontFixedWidth; }
+ GBool isSerif() { return flags & fontSerif; }
+ GBool isSymbolic() { return flags & fontSymbolic; }
+ GBool isItalic() { return flags & fontItalic; }
+ GBool isBold() { return flags & fontBold; }
+
+ // Return the font matrix.
+ double *getFontMatrix() { return fontMat; }
+
+ // Return the font bounding box.
+ double *getFontBBox() { return fontBBox; }
+
+ // Return the ascent and descent values.
+ double getAscent() { return ascent; }
+ double getDescent() { return descent; }
+
+ // Return the writing mode (0=horizontal, 1=vertical).
+ virtual int getWMode() { return 0; }
+
+ // Read an external or embedded font file into a buffer.
+ char *readExtFontFile(int *len);
+ char *readEmbFontFile(XRef *xref, int *len);
+
+ // Get the next char from a string <s> of <len> bytes, returning the
+ // char <code>, its Unicode mapping <u>, its displacement vector
+ // (<dx>, <dy>), and its origin offset vector (<ox>, <oy>). <uSize>
+ // is the number of entries available in <u>, and <uLen> is set to
+ // the number actually used. Returns the number of bytes used by
+ // the char code.
+ virtual int getNextChar(char *s, int len, CharCode *code,
+ Unicode *u, int uSize, int *uLen,
+ double *dx, double *dy, double *ox, double *oy) = 0;
+
+protected:
+
+ void readFontDescriptor(XRef *xref, Dict *fontDict);
+ CharCodeToUnicode *readToUnicodeCMap(Dict *fontDict, int nBits,
+ CharCodeToUnicode *ctu);
+ void findExtFontFile();
+
+ GString *tag; // PDF font tag
+ Ref id; // reference (used as unique ID)
+ GString *name; // font name
+ GString *origName; // original font name
+ GfxFontType type; // type of font
+ int flags; // font descriptor flags
+ GString *embFontName; // name of embedded font
+ Ref embFontID; // ref to embedded font file stream
+ GString *extFontFile; // external font file name
+ double fontMat[6]; // font matrix (Type 3 only)
+ double fontBBox[4]; // font bounding box (Type 3 only)
+ double missingWidth; // "default" width
+ double ascent; // max height above baseline
+ double descent; // max depth below baseline
+ GBool ok;
+};
+
+//------------------------------------------------------------------------
+// Gfx8BitFont
+//------------------------------------------------------------------------
+
+class Gfx8BitFont: public GfxFont {
+public:
+
+ Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
+ GfxFontType typeA, Dict *fontDict);
+
+ virtual ~Gfx8BitFont();
+
+ virtual int getNextChar(char *s, int len, CharCode *code,
+ Unicode *u, int uSize, int *uLen,
+ double *dx, double *dy, double *ox, double *oy);
+
+ // Return the encoding.
+ char **getEncoding() { return enc; }
+
+ // Return the Unicode map.
+ CharCodeToUnicode *getToUnicode();
+
+ // Return the character name associated with <code>.
+ char *getCharName(int code) { return enc[code]; }
+
+ // Returns true if the PDF font specified an encoding.
+ GBool getHasEncoding() { return hasEncoding; }
+
+ // Returns true if the PDF font specified MacRomanEncoding.
+ GBool getUsesMacRomanEnc() { return usesMacRomanEnc; }
+
+ // Get width of a character.
+ double getWidth(Guchar c) { return widths[c]; }
+
+ // Return a char code-to-GID mapping for the provided font file.
+ // (This is only useful for TrueType fonts.)
+ Gushort *getCodeToGIDMap(FoFiTrueType *ff);
+
+ // Return the Type 3 CharProc dictionary, or NULL if none.
+ Dict *getCharProcs();
+
+ // Return the Type 3 CharProc for the character associated with <code>.
+ Object *getCharProc(int code, Object *proc);
+
+ // Return the Type 3 Resources dictionary, or NULL if none.
+ Dict *getResources();
+
+private:
+
+ char *enc[256]; // char code --> char name
+ char encFree[256]; // boolean for each char name: if set,
+ // the string is malloc'ed
+ CharCodeToUnicode *ctu; // char code --> Unicode
+ GBool hasEncoding;
+ GBool usesMacRomanEnc;
+ double widths[256]; // character widths
+ Object charProcs; // Type 3 CharProcs dictionary
+ Object resources; // Type 3 Resources dictionary
+};
+
+//------------------------------------------------------------------------
+// GfxCIDFont
+//------------------------------------------------------------------------
+
+class GfxCIDFont: public GfxFont {
+public:
+
+ GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
+ Dict *fontDict);
+
+ virtual ~GfxCIDFont();
+
+ virtual GBool isCIDFont() { return gTrue; }
+
+ virtual int getNextChar(char *s, int len, CharCode *code,
+ Unicode *u, int uSize, int *uLen,
+ double *dx, double *dy, double *ox, double *oy);
+
+ // Return the writing mode (0=horizontal, 1=vertical).
+ virtual int getWMode();
+
+ // Return the Unicode map.
+ CharCodeToUnicode *getToUnicode();
+
+ // Get the collection name (<registry>-<ordering>).
+ GString *getCollection();
+
+ // Return the CID-to-GID mapping table. These should only be called
+ // if type is fontCIDType2.
+ Gushort *getCIDToGID() { return cidToGID; }
+ int getCIDToGIDLen() { return cidToGIDLen; }
+
+ Gushort *getCodeToGIDMap(FoFiTrueType *ff, int *length);
+
+private:
+
+ CMap *cMap; // char code --> CID
+ CharCodeToUnicode *ctu; // CID --> Unicode
+ GfxFontCIDWidths widths; // character widths
+ Gushort *cidToGID; // CID --> GID mapping (for embedded
+ // TrueType fonts)
+ int cidToGIDLen;
+};
+
+//------------------------------------------------------------------------
+// GfxFontDict
+//------------------------------------------------------------------------
+
+class GfxFontDict {
+public:
+
+ // Build the font dictionary, given the PDF font dictionary.
+ GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict);
+
+ // Destructor.
+ ~GfxFontDict();
+
+ // Get the specified font.
+ GfxFont *lookup(char *tag);
+
+ // Iterative access.
+ int getNumFonts() { return numFonts; }
+ GfxFont *getFont(int i) { return fonts[i]; }
+
+private:
+
+ GfxFont **fonts; // list of fonts
+ int numFonts; // number of fonts
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/GfxState.cc b/kpdf/xpdf/xpdf/GfxState.cc
new file mode 100644
index 00000000..a00dabe1
--- /dev/null
+++ b/kpdf/xpdf/xpdf/GfxState.cc
@@ -0,0 +1,4137 @@
+//========================================================================
+//
+// GfxState.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stddef.h>
+#include <math.h>
+#include <string.h>
+#include "gmem.h"
+#include "Error.h"
+#include "Object.h"
+#include "Array.h"
+#include "Page.h"
+#include "GfxState.h"
+
+//------------------------------------------------------------------------
+
+static inline GfxColorComp clip01(GfxColorComp x) {
+ return (x < 0) ? 0 : (x > gfxColorComp1) ? gfxColorComp1 : x;
+}
+
+static inline double clip01(double x) {
+ return (x < 0) ? 0 : (x > 1) ? 1 : x;
+}
+
+//------------------------------------------------------------------------
+
+struct GfxBlendModeInfo {
+ char *name;
+ GfxBlendMode mode;
+};
+
+static GfxBlendModeInfo gfxBlendModeNames[] = {
+ { "Normal", gfxBlendNormal },
+ { "Compatible", gfxBlendNormal },
+ { "Multiply", gfxBlendMultiply },
+ { "Screen", gfxBlendScreen },
+ { "Overlay", gfxBlendOverlay },
+ { "Darken", gfxBlendDarken },
+ { "Lighten", gfxBlendLighten },
+ { "ColorDodge", gfxBlendColorDodge },
+ { "ColorBurn", gfxBlendColorBurn },
+ { "HardLight", gfxBlendHardLight },
+ { "SoftLight", gfxBlendSoftLight },
+ { "Difference", gfxBlendDifference },
+ { "Exclusion", gfxBlendExclusion },
+ { "Hue", gfxBlendHue },
+ { "Saturation", gfxBlendSaturation },
+ { "Color", gfxBlendColor },
+ { "Luminosity", gfxBlendLuminosity }
+};
+
+#define nGfxBlendModeNames \
+ ((int)((sizeof(gfxBlendModeNames) / sizeof(GfxBlendModeInfo))))
+
+//------------------------------------------------------------------------
+
+// NB: This must match the GfxColorSpaceMode enum defined in
+// GfxState.h
+static char *gfxColorSpaceModeNames[] = {
+ "DeviceGray",
+ "CalGray",
+ "DeviceRGB",
+ "CalRGB",
+ "DeviceCMYK",
+ "Lab",
+ "ICCBased",
+ "Indexed",
+ "Separation",
+ "DeviceN",
+ "Pattern"
+};
+
+#define nGfxColorSpaceModes ((sizeof(gfxColorSpaceModeNames) / sizeof(char *)))
+
+//------------------------------------------------------------------------
+// GfxColorSpace
+//------------------------------------------------------------------------
+
+GfxColorSpace::GfxColorSpace() {
+}
+
+GfxColorSpace::~GfxColorSpace() {
+}
+
+GfxColorSpace *GfxColorSpace::parse(Object *csObj) {
+ GfxColorSpace *cs;
+ Object obj1;
+
+ cs = NULL;
+ if (csObj->isName()) {
+ if (csObj->isName("DeviceGray") || csObj->isName("G")) {
+ cs = new GfxDeviceGrayColorSpace();
+ } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) {
+ cs = new GfxDeviceRGBColorSpace();
+ } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) {
+ cs = new GfxDeviceCMYKColorSpace();
+ } else if (csObj->isName("Pattern")) {
+ cs = new GfxPatternColorSpace(NULL);
+ } else {
+ error(-1, "Bad color space '%s'", csObj->getName());
+ }
+ } else if (csObj->isArray()) {
+ csObj->arrayGet(0, &obj1);
+ if (obj1.isName("DeviceGray") || obj1.isName("G")) {
+ cs = new GfxDeviceGrayColorSpace();
+ } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) {
+ cs = new GfxDeviceRGBColorSpace();
+ } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) {
+ cs = new GfxDeviceCMYKColorSpace();
+ } else if (obj1.isName("CalGray")) {
+ cs = GfxCalGrayColorSpace::parse(csObj->getArray());
+ } else if (obj1.isName("CalRGB")) {
+ cs = GfxCalRGBColorSpace::parse(csObj->getArray());
+ } else if (obj1.isName("Lab")) {
+ cs = GfxLabColorSpace::parse(csObj->getArray());
+ } else if (obj1.isName("ICCBased")) {
+ cs = GfxICCBasedColorSpace::parse(csObj->getArray());
+ } else if (obj1.isName("Indexed") || obj1.isName("I")) {
+ cs = GfxIndexedColorSpace::parse(csObj->getArray());
+ } else if (obj1.isName("Separation")) {
+ cs = GfxSeparationColorSpace::parse(csObj->getArray());
+ } else if (obj1.isName("DeviceN")) {
+ cs = GfxDeviceNColorSpace::parse(csObj->getArray());
+ } else if (obj1.isName("Pattern")) {
+ cs = GfxPatternColorSpace::parse(csObj->getArray());
+ } else {
+ error(-1, "Bad color space");
+ }
+ obj1.free();
+ } else {
+ error(-1, "Bad color space - expected name or array");
+ }
+ return cs;
+}
+
+void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
+ int /*maxImgPixel*/) {
+ int i;
+
+ for (i = 0; i < getNComps(); ++i) {
+ decodeLow[i] = 0;
+ decodeRange[i] = 1;
+ }
+}
+
+int GfxColorSpace::getNumColorSpaceModes() {
+ return nGfxColorSpaceModes;
+}
+
+char *GfxColorSpace::getColorSpaceModeName(int idx) {
+ return gfxColorSpaceModeNames[idx];
+}
+
+//------------------------------------------------------------------------
+// GfxDeviceGrayColorSpace
+//------------------------------------------------------------------------
+
+GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
+}
+
+GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
+}
+
+GfxColorSpace *GfxDeviceGrayColorSpace::copy() {
+ return new GfxDeviceGrayColorSpace();
+}
+
+void GfxDeviceGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ *gray = clip01(color->c[0]);
+}
+
+void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
+}
+
+void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ cmyk->c = cmyk->m = cmyk->y = 0;
+ cmyk->k = clip01(gfxColorComp1 - color->c[0]);
+}
+
+void GfxDeviceGrayColorSpace::getDefaultColor(GfxColor *color) {
+ color->c[0] = 0;
+}
+
+//------------------------------------------------------------------------
+// GfxCalGrayColorSpace
+//------------------------------------------------------------------------
+
+GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
+ whiteX = whiteY = whiteZ = 1;
+ blackX = blackY = blackZ = 0;
+ gamma = 1;
+}
+
+GfxCalGrayColorSpace::~GfxCalGrayColorSpace() {
+}
+
+GfxColorSpace *GfxCalGrayColorSpace::copy() {
+ GfxCalGrayColorSpace *cs;
+
+ cs = new GfxCalGrayColorSpace();
+ cs->whiteX = whiteX;
+ cs->whiteY = whiteY;
+ cs->whiteZ = whiteZ;
+ cs->blackX = blackX;
+ cs->blackY = blackY;
+ cs->blackZ = blackZ;
+ cs->gamma = gamma;
+ return cs;
+}
+
+GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) {
+ GfxCalGrayColorSpace *cs;
+ Object obj1, obj2, obj3;
+
+ arr->get(1, &obj1);
+ if (!obj1.isDict()) {
+ error(-1, "Bad CalGray color space");
+ obj1.free();
+ return NULL;
+ }
+ cs = new GfxCalGrayColorSpace();
+ if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 3) {
+ obj2.arrayGet(0, &obj3);
+ cs->whiteX = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(1, &obj3);
+ cs->whiteY = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2, &obj3);
+ cs->whiteZ = obj3.getNum();
+ obj3.free();
+ }
+ obj2.free();
+ if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 3) {
+ obj2.arrayGet(0, &obj3);
+ cs->blackX = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(1, &obj3);
+ cs->blackY = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2, &obj3);
+ cs->blackZ = obj3.getNum();
+ obj3.free();
+ }
+ obj2.free();
+ if (obj1.dictLookup("Gamma", &obj2)->isNum()) {
+ cs->gamma = obj2.getNum();
+ }
+ obj2.free();
+ obj1.free();
+ return cs;
+}
+
+void GfxCalGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ *gray = clip01(color->c[0]);
+}
+
+void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
+}
+
+void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ cmyk->c = cmyk->m = cmyk->y = 0;
+ cmyk->k = clip01(gfxColorComp1 - color->c[0]);
+}
+
+void GfxCalGrayColorSpace::getDefaultColor(GfxColor *color) {
+ color->c[0] = 0;
+}
+
+//------------------------------------------------------------------------
+// GfxDeviceRGBColorSpace
+//------------------------------------------------------------------------
+
+GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
+}
+
+GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
+}
+
+GfxColorSpace *GfxDeviceRGBColorSpace::copy() {
+ return new GfxDeviceRGBColorSpace();
+}
+
+void GfxDeviceRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ *gray = clip01((GfxColorComp)(0.3 * color->c[0] +
+ 0.59 * color->c[1] +
+ 0.11 * color->c[2] + 0.5));
+}
+
+void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ rgb->r = clip01(color->c[0]);
+ rgb->g = clip01(color->c[1]);
+ rgb->b = clip01(color->c[2]);
+}
+
+void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ GfxColorComp c, m, y, k;
+
+ c = clip01(gfxColorComp1 - color->c[0]);
+ m = clip01(gfxColorComp1 - color->c[1]);
+ y = clip01(gfxColorComp1 - color->c[2]);
+ k = c;
+ if (m < k) {
+ k = m;
+ }
+ if (y < k) {
+ k = y;
+ }
+ cmyk->c = c - k;
+ cmyk->m = m - k;
+ cmyk->y = y - k;
+ cmyk->k = k;
+}
+
+void GfxDeviceRGBColorSpace::getDefaultColor(GfxColor *color) {
+ color->c[0] = 0;
+ color->c[1] = 0;
+ color->c[2] = 0;
+}
+
+//------------------------------------------------------------------------
+// GfxCalRGBColorSpace
+//------------------------------------------------------------------------
+
+GfxCalRGBColorSpace::GfxCalRGBColorSpace() {
+ whiteX = whiteY = whiteZ = 1;
+ blackX = blackY = blackZ = 0;
+ gammaR = gammaG = gammaB = 1;
+ mat[0] = 1; mat[1] = 0; mat[2] = 0;
+ mat[3] = 0; mat[4] = 1; mat[5] = 0;
+ mat[6] = 0; mat[7] = 0; mat[8] = 1;
+}
+
+GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
+}
+
+GfxColorSpace *GfxCalRGBColorSpace::copy() {
+ GfxCalRGBColorSpace *cs;
+ int i;
+
+ cs = new GfxCalRGBColorSpace();
+ cs->whiteX = whiteX;
+ cs->whiteY = whiteY;
+ cs->whiteZ = whiteZ;
+ cs->blackX = blackX;
+ cs->blackY = blackY;
+ cs->blackZ = blackZ;
+ cs->gammaR = gammaR;
+ cs->gammaG = gammaG;
+ cs->gammaB = gammaB;
+ for (i = 0; i < 9; ++i) {
+ cs->mat[i] = mat[i];
+ }
+ return cs;
+}
+
+GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) {
+ GfxCalRGBColorSpace *cs;
+ Object obj1, obj2, obj3;
+ int i;
+
+ arr->get(1, &obj1);
+ if (!obj1.isDict()) {
+ error(-1, "Bad CalRGB color space");
+ obj1.free();
+ return NULL;
+ }
+ cs = new GfxCalRGBColorSpace();
+ if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 3) {
+ obj2.arrayGet(0, &obj3);
+ cs->whiteX = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(1, &obj3);
+ cs->whiteY = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2, &obj3);
+ cs->whiteZ = obj3.getNum();
+ obj3.free();
+ }
+ obj2.free();
+ if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 3) {
+ obj2.arrayGet(0, &obj3);
+ cs->blackX = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(1, &obj3);
+ cs->blackY = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2, &obj3);
+ cs->blackZ = obj3.getNum();
+ obj3.free();
+ }
+ obj2.free();
+ if (obj1.dictLookup("Gamma", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 3) {
+ obj2.arrayGet(0, &obj3);
+ cs->gammaR = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(1, &obj3);
+ cs->gammaG = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2, &obj3);
+ cs->gammaB = obj3.getNum();
+ obj3.free();
+ }
+ obj2.free();
+ if (obj1.dictLookup("Matrix", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 9) {
+ for (i = 0; i < 9; ++i) {
+ obj2.arrayGet(i, &obj3);
+ cs->mat[i] = obj3.getNum();
+ obj3.free();
+ }
+ }
+ obj2.free();
+ obj1.free();
+ return cs;
+}
+
+void GfxCalRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ *gray = clip01((GfxColorComp)(0.299 * color->c[0] +
+ 0.587 * color->c[1] +
+ 0.114 * color->c[2] + 0.5));
+}
+
+void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ rgb->r = clip01(color->c[0]);
+ rgb->g = clip01(color->c[1]);
+ rgb->b = clip01(color->c[2]);
+}
+
+void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ GfxColorComp c, m, y, k;
+
+ c = clip01(gfxColorComp1 - color->c[0]);
+ m = clip01(gfxColorComp1 - color->c[1]);
+ y = clip01(gfxColorComp1 - color->c[2]);
+ k = c;
+ if (m < k) {
+ k = m;
+ }
+ if (y < k) {
+ k = y;
+ }
+ cmyk->c = c - k;
+ cmyk->m = m - k;
+ cmyk->y = y - k;
+ cmyk->k = k;
+}
+
+void GfxCalRGBColorSpace::getDefaultColor(GfxColor *color) {
+ color->c[0] = 0;
+ color->c[1] = 0;
+ color->c[2] = 0;
+}
+
+//------------------------------------------------------------------------
+// GfxDeviceCMYKColorSpace
+//------------------------------------------------------------------------
+
+GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
+}
+
+GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
+}
+
+GfxColorSpace *GfxDeviceCMYKColorSpace::copy() {
+ return new GfxDeviceCMYKColorSpace();
+}
+
+void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ *gray = clip01((GfxColorComp)(gfxColorComp1 - color->c[3]
+ - 0.3 * color->c[0]
+ - 0.59 * color->c[1]
+ - 0.11 * color->c[2] + 0.5));
+}
+
+void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ double c, m, y, k, c1, m1, y1, k1, r, g, b, x;
+
+ c = colToDbl(color->c[0]);
+ m = colToDbl(color->c[1]);
+ y = colToDbl(color->c[2]);
+ k = colToDbl(color->c[3]);
+ c1 = 1 - c;
+ m1 = 1 - m;
+ y1 = 1 - y;
+ k1 = 1 - k;
+ // this is a matrix multiplication, unrolled for performance
+ // C M Y K
+ x = c1 * m1 * y1 * k1; // 0 0 0 0
+ r = g = b = x;
+ x = c1 * m1 * y1 * k; // 0 0 0 1
+ r += 0.1373 * x;
+ g += 0.1216 * x;
+ b += 0.1255 * x;
+ x = c1 * m1 * y * k1; // 0 0 1 0
+ r += x;
+ g += 0.9490 * x;
+ x = c1 * m1 * y * k; // 0 0 1 1
+ r += 0.1098 * x;
+ g += 0.1020 * x;
+ x = c1 * m * y1 * k1; // 0 1 0 0
+ r += 0.9255 * x;
+ b += 0.5490 * x;
+ x = c1 * m * y1 * k; // 0 1 0 1
+ r += 0.1412 * x;
+ x = c1 * m * y * k1; // 0 1 1 0
+ r += 0.9294 * x;
+ g += 0.1098 * x;
+ b += 0.1412 * x;
+ x = c1 * m * y * k; // 0 1 1 1
+ r += 0.1333 * x;
+ x = c * m1 * y1 * k1; // 1 0 0 0
+ g += 0.6784 * x;
+ b += 0.9373 * x;
+ x = c * m1 * y1 * k; // 1 0 0 1
+ g += 0.0588 * x;
+ b += 0.1412 * x;
+ x = c * m1 * y * k1; // 1 0 1 0
+ g += 0.6510 * x;
+ b += 0.3137 * x;
+ x = c * m1 * y * k; // 1 0 1 1
+ g += 0.0745 * x;
+ x = c * m * y1 * k1; // 1 1 0 0
+ r += 0.1804 * x;
+ g += 0.1922 * x;
+ b += 0.5725 * x;
+ x = c * m * y1 * k; // 1 1 0 1
+ b += 0.0078 * x;
+ x = c * m * y * k1; // 1 1 1 0
+ r += 0.2118 * x;
+ g += 0.2119 * x;
+ b += 0.2235 * x;
+ rgb->r = clip01(dblToCol(r));
+ rgb->g = clip01(dblToCol(g));
+ rgb->b = clip01(dblToCol(b));
+}
+
+void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ cmyk->c = clip01(color->c[0]);
+ cmyk->m = clip01(color->c[1]);
+ cmyk->y = clip01(color->c[2]);
+ cmyk->k = clip01(color->c[3]);
+}
+
+void GfxDeviceCMYKColorSpace::getDefaultColor(GfxColor *color) {
+ color->c[0] = 0;
+ color->c[1] = 0;
+ color->c[2] = 0;
+ color->c[3] = gfxColorComp1;
+}
+
+//------------------------------------------------------------------------
+// GfxLabColorSpace
+//------------------------------------------------------------------------
+
+// This is the inverse of MatrixLMN in Example 4.10 from the PostScript
+// Language Reference, Third Edition.
+static double xyzrgb[3][3] = {
+ { 3.240449, -1.537136, -0.498531 },
+ { -0.969265, 1.876011, 0.041556 },
+ { 0.055643, -0.204026, 1.057229 }
+};
+
+GfxLabColorSpace::GfxLabColorSpace() {
+ whiteX = whiteY = whiteZ = 1;
+ blackX = blackY = blackZ = 0;
+ aMin = bMin = -100;
+ aMax = bMax = 100;
+}
+
+GfxLabColorSpace::~GfxLabColorSpace() {
+}
+
+GfxColorSpace *GfxLabColorSpace::copy() {
+ GfxLabColorSpace *cs;
+
+ cs = new GfxLabColorSpace();
+ cs->whiteX = whiteX;
+ cs->whiteY = whiteY;
+ cs->whiteZ = whiteZ;
+ cs->blackX = blackX;
+ cs->blackY = blackY;
+ cs->blackZ = blackZ;
+ cs->aMin = aMin;
+ cs->aMax = aMax;
+ cs->bMin = bMin;
+ cs->bMax = bMax;
+ cs->kr = kr;
+ cs->kg = kg;
+ cs->kb = kb;
+ return cs;
+}
+
+GfxColorSpace *GfxLabColorSpace::parse(Array *arr) {
+ GfxLabColorSpace *cs;
+ Object obj1, obj2, obj3;
+
+ arr->get(1, &obj1);
+ if (!obj1.isDict()) {
+ error(-1, "Bad Lab color space");
+ obj1.free();
+ return NULL;
+ }
+ cs = new GfxLabColorSpace();
+ if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 3) {
+ obj2.arrayGet(0, &obj3);
+ cs->whiteX = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(1, &obj3);
+ cs->whiteY = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2, &obj3);
+ cs->whiteZ = obj3.getNum();
+ obj3.free();
+ }
+ obj2.free();
+ if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 3) {
+ obj2.arrayGet(0, &obj3);
+ cs->blackX = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(1, &obj3);
+ cs->blackY = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2, &obj3);
+ cs->blackZ = obj3.getNum();
+ obj3.free();
+ }
+ obj2.free();
+ if (obj1.dictLookup("Range", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 4) {
+ obj2.arrayGet(0, &obj3);
+ cs->aMin = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(1, &obj3);
+ cs->aMax = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2, &obj3);
+ cs->bMin = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(3, &obj3);
+ cs->bMax = obj3.getNum();
+ obj3.free();
+ }
+ obj2.free();
+ obj1.free();
+
+ cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
+ xyzrgb[0][1] * cs->whiteY +
+ xyzrgb[0][2] * cs->whiteZ);
+ cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
+ xyzrgb[1][1] * cs->whiteY +
+ xyzrgb[1][2] * cs->whiteZ);
+ cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
+ xyzrgb[2][1] * cs->whiteY +
+ xyzrgb[2][2] * cs->whiteZ);
+
+ return cs;
+}
+
+void GfxLabColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ GfxRGB rgb;
+
+ getRGB(color, &rgb);
+ *gray = clip01((GfxColorComp)(0.299 * rgb.r +
+ 0.587 * rgb.g +
+ 0.114 * rgb.b + 0.5));
+}
+
+void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ double X, Y, Z;
+ double t1, t2;
+ double r, g, b;
+
+ // convert L*a*b* to CIE 1931 XYZ color space
+ t1 = (colToDbl(color->c[0]) + 16) / 116;
+ t2 = t1 + colToDbl(color->c[1]) / 500;
+ if (t2 >= (6.0 / 29.0)) {
+ X = t2 * t2 * t2;
+ } else {
+ X = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
+ }
+ X *= whiteX;
+ if (t1 >= (6.0 / 29.0)) {
+ Y = t1 * t1 * t1;
+ } else {
+ Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
+ }
+ Y *= whiteY;
+ t2 = t1 - colToDbl(color->c[2]) / 200;
+ if (t2 >= (6.0 / 29.0)) {
+ Z = t2 * t2 * t2;
+ } else {
+ Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
+ }
+ Z *= whiteZ;
+
+ // convert XYZ to RGB, including gamut mapping and gamma correction
+ r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
+ g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
+ b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
+ rgb->r = dblToCol(pow(clip01(r * kr), 0.5));
+ rgb->g = dblToCol(pow(clip01(g * kg), 0.5));
+ rgb->b = dblToCol(pow(clip01(b * kb), 0.5));
+}
+
+void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ GfxRGB rgb;
+ GfxColorComp c, m, y, k;
+
+ getRGB(color, &rgb);
+ c = clip01(gfxColorComp1 - rgb.r);
+ m = clip01(gfxColorComp1 - rgb.g);
+ y = clip01(gfxColorComp1 - rgb.b);
+ k = c;
+ if (m < k) {
+ k = m;
+ }
+ if (y < k) {
+ k = y;
+ }
+ cmyk->c = c - k;
+ cmyk->m = m - k;
+ cmyk->y = y - k;
+ cmyk->k = k;
+}
+
+void GfxLabColorSpace::getDefaultColor(GfxColor *color) {
+ color->c[0] = 0;
+ if (aMin > 0) {
+ color->c[1] = dblToCol(aMin);
+ } else if (aMax < 0) {
+ color->c[1] = dblToCol(aMax);
+ } else {
+ color->c[1] = 0;
+ }
+ if (bMin > 0) {
+ color->c[2] = dblToCol(bMin);
+ } else if (bMax < 0) {
+ color->c[2] = dblToCol(bMax);
+ } else {
+ color->c[2] = 0;
+ }
+}
+
+void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange,
+ int /*maxImgPixel*/) {
+ decodeLow[0] = 0;
+ decodeRange[0] = 100;
+ decodeLow[1] = aMin;
+ decodeRange[1] = aMax - aMin;
+ decodeLow[2] = bMin;
+ decodeRange[2] = bMax - bMin;
+}
+
+//------------------------------------------------------------------------
+// GfxICCBasedColorSpace
+//------------------------------------------------------------------------
+
+GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
+ Ref *iccProfileStreamA) {
+ nComps = nCompsA;
+ alt = altA;
+ iccProfileStream = *iccProfileStreamA;
+ rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
+ rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
+}
+
+GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
+ delete alt;
+}
+
+GfxColorSpace *GfxICCBasedColorSpace::copy() {
+ GfxICCBasedColorSpace *cs;
+ int i;
+
+ cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream);
+ for (i = 0; i < 4; ++i) {
+ cs->rangeMin[i] = rangeMin[i];
+ cs->rangeMax[i] = rangeMax[i];
+ }
+ return cs;
+}
+
+GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
+ GfxICCBasedColorSpace *cs;
+ Ref iccProfileStreamA;
+ int nCompsA;
+ GfxColorSpace *altA;
+ Dict *dict;
+ Object obj1, obj2, obj3;
+ int i;
+
+ arr->getNF(1, &obj1);
+ if (obj1.isRef()) {
+ iccProfileStreamA = obj1.getRef();
+ } else {
+ iccProfileStreamA.num = 0;
+ iccProfileStreamA.gen = 0;
+ }
+ obj1.free();
+ arr->get(1, &obj1);
+ if (!obj1.isStream()) {
+ error(-1, "Bad ICCBased color space (stream)");
+ obj1.free();
+ return NULL;
+ }
+ dict = obj1.streamGetDict();
+ if (!dict->lookup("N", &obj2)->isInt()) {
+ error(-1, "Bad ICCBased color space (N)");
+ obj2.free();
+ obj1.free();
+ return NULL;
+ }
+ nCompsA = obj2.getInt();
+ obj2.free();
+ if (nCompsA > gfxColorMaxComps) {
+ error(-1, "ICCBased color space with too many (%d > %d) components",
+ nCompsA, gfxColorMaxComps);
+ nCompsA = gfxColorMaxComps;
+ }
+ if (dict->lookup("Alternate", &obj2)->isNull() ||
+ !(altA = GfxColorSpace::parse(&obj2))) {
+ switch (nCompsA) {
+ case 1:
+ altA = new GfxDeviceGrayColorSpace();
+ break;
+ case 3:
+ altA = new GfxDeviceRGBColorSpace();
+ break;
+ case 4:
+ altA = new GfxDeviceCMYKColorSpace();
+ break;
+ default:
+ error(-1, "Bad ICCBased color space - invalid N");
+ obj2.free();
+ obj1.free();
+ return NULL;
+ }
+ }
+ obj2.free();
+ cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
+ if (dict->lookup("Range", &obj2)->isArray() &&
+ obj2.arrayGetLength() == 2 * nCompsA) {
+ for (i = 0; i < nCompsA; ++i) {
+ obj2.arrayGet(2*i, &obj3);
+ cs->rangeMin[i] = obj3.getNum();
+ obj3.free();
+ obj2.arrayGet(2*i+1, &obj3);
+ cs->rangeMax[i] = obj3.getNum();
+ obj3.free();
+ }
+ }
+ obj2.free();
+ obj1.free();
+ return cs;
+}
+
+void GfxICCBasedColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ alt->getGray(color, gray);
+}
+
+void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ alt->getRGB(color, rgb);
+}
+
+void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ alt->getCMYK(color, cmyk);
+}
+
+void GfxICCBasedColorSpace::getDefaultColor(GfxColor *color) {
+ int i;
+
+ for (i = 0; i < nComps; ++i) {
+ if (rangeMin[i] > 0) {
+ color->c[i] = dblToCol(rangeMin[i]);
+ } else if (rangeMax[i] < 0) {
+ color->c[i] = dblToCol(rangeMax[i]);
+ } else {
+ color->c[i] = 0;
+ }
+ }
+}
+
+void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow,
+ double *decodeRange,
+ int maxImgPixel) {
+ alt->getDefaultRanges(decodeLow, decodeRange, maxImgPixel);
+
+#if 0
+ // this is nominally correct, but some PDF files don't set the
+ // correct ranges in the ICCBased dict
+ int i;
+
+ for (i = 0; i < nComps; ++i) {
+ decodeLow[i] = rangeMin[i];
+ decodeRange[i] = rangeMax[i] - rangeMin[i];
+ }
+#endif
+}
+
+//------------------------------------------------------------------------
+// GfxIndexedColorSpace
+//------------------------------------------------------------------------
+
+GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
+ int indexHighA) {
+ base = baseA;
+ indexHigh = indexHighA;
+ lookup = (Guchar *)gmallocn((indexHigh + 1) * base->getNComps(),
+ sizeof(Guchar));
+}
+
+GfxIndexedColorSpace::~GfxIndexedColorSpace() {
+ delete base;
+ gfree(lookup);
+}
+
+GfxColorSpace *GfxIndexedColorSpace::copy() {
+ GfxIndexedColorSpace *cs;
+
+ cs = new GfxIndexedColorSpace(base->copy(), indexHigh);
+ memcpy(cs->lookup, lookup,
+ (indexHigh + 1) * base->getNComps() * sizeof(Guchar));
+ return cs;
+}
+
+GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
+ GfxIndexedColorSpace *cs;
+ GfxColorSpace *baseA;
+ int indexHighA;
+ Object obj1;
+ int x;
+ char *s;
+ int n, i, j;
+
+ if (arr->getLength() != 4) {
+ error(-1, "Bad Indexed color space");
+ goto err1;
+ }
+ arr->get(1, &obj1);
+ if (!(baseA = GfxColorSpace::parse(&obj1))) {
+ error(-1, "Bad Indexed color space (base color space)");
+ goto err2;
+ }
+ obj1.free();
+ if (!arr->get(2, &obj1)->isInt()) {
+ error(-1, "Bad Indexed color space (hival)");
+ delete baseA;
+ goto err2;
+ }
+ indexHighA = obj1.getInt();
+ if (indexHighA < 0 || indexHighA > 255) {
+ // the PDF spec requires indexHigh to be in [0,255] -- allowing
+ // values larger than 255 creates a security hole: if nComps *
+ // indexHigh is greater than 2^31, the loop below may overwrite
+ // past the end of the array
+ error(-1, "Bad Indexed color space (invalid indexHigh value)");
+ delete baseA;
+ goto err2;
+ }
+ obj1.free();
+ cs = new GfxIndexedColorSpace(baseA, indexHighA);
+ arr->get(3, &obj1);
+ n = baseA->getNComps();
+ if (obj1.isStream()) {
+ obj1.streamReset();
+ for (i = 0; i <= indexHighA; ++i) {
+ for (j = 0; j < n; ++j) {
+ if ((x = obj1.streamGetChar()) == EOF) {
+ error(-1, "Bad Indexed color space (lookup table stream too short)");
+ goto err3;
+ }
+ cs->lookup[i*n + j] = (Guchar)x;
+ }
+ }
+ obj1.streamClose();
+ } else if (obj1.isString()) {
+ if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
+ error(-1, "Bad Indexed color space (lookup table string too short)");
+ goto err3;
+ }
+ s = obj1.getString()->getCString();
+ for (i = 0; i <= indexHighA; ++i) {
+ for (j = 0; j < n; ++j) {
+ cs->lookup[i*n + j] = (Guchar)*s++;
+ }
+ }
+ } else {
+ error(-1, "Bad Indexed color space (lookup table)");
+ goto err3;
+ }
+ obj1.free();
+ return cs;
+
+ err3:
+ delete cs;
+ err2:
+ obj1.free();
+ err1:
+ return NULL;
+}
+
+GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color,
+ GfxColor *baseColor) {
+ Guchar *p;
+ double low[gfxColorMaxComps], range[gfxColorMaxComps];
+ int n, i;
+
+ n = base->getNComps();
+ base->getDefaultRanges(low, range, indexHigh);
+ p = &lookup[(int)(colToDbl(color->c[0]) + 0.5) * n];
+ for (i = 0; i < n; ++i) {
+ baseColor->c[i] = dblToCol(low[i] + (p[i] / 255.0) * range[i]);
+ }
+ return baseColor;
+}
+
+void GfxIndexedColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ GfxColor color2;
+
+ base->getGray(mapColorToBase(color, &color2), gray);
+}
+
+void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ GfxColor color2;
+
+ base->getRGB(mapColorToBase(color, &color2), rgb);
+}
+
+void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ GfxColor color2;
+
+ base->getCMYK(mapColorToBase(color, &color2), cmyk);
+}
+
+void GfxIndexedColorSpace::getDefaultColor(GfxColor *color) {
+ color->c[0] = 0;
+}
+
+void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow,
+ double *decodeRange,
+ int maxImgPixel) {
+ decodeLow[0] = 0;
+ decodeRange[0] = maxImgPixel;
+}
+
+//------------------------------------------------------------------------
+// GfxSeparationColorSpace
+//------------------------------------------------------------------------
+
+GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA,
+ GfxColorSpace *altA,
+ Function *funcA) {
+ name = nameA;
+ alt = altA;
+ func = funcA;
+ nonMarking = !name->cmp("None");
+}
+
+GfxSeparationColorSpace::~GfxSeparationColorSpace() {
+ delete name;
+ delete alt;
+ delete func;
+}
+
+GfxColorSpace *GfxSeparationColorSpace::copy() {
+ return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy());
+}
+
+//~ handle the 'All' and 'None' colorants
+GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) {
+ GfxSeparationColorSpace *cs;
+ GString *nameA;
+ GfxColorSpace *altA;
+ Function *funcA;
+ Object obj1;
+
+ if (arr->getLength() != 4) {
+ error(-1, "Bad Separation color space");
+ goto err1;
+ }
+ if (!arr->get(1, &obj1)->isName()) {
+ error(-1, "Bad Separation color space (name)");
+ goto err2;
+ }
+ nameA = new GString(obj1.getName());
+ obj1.free();
+ arr->get(2, &obj1);
+ if (!(altA = GfxColorSpace::parse(&obj1))) {
+ error(-1, "Bad Separation color space (alternate color space)");
+ goto err3;
+ }
+ obj1.free();
+ arr->get(3, &obj1);
+ if (!(funcA = Function::parse(&obj1))) {
+ goto err4;
+ }
+ obj1.free();
+ cs = new GfxSeparationColorSpace(nameA, altA, funcA);
+ return cs;
+
+ err4:
+ delete altA;
+ err3:
+ delete nameA;
+ err2:
+ obj1.free();
+ err1:
+ return NULL;
+}
+
+void GfxSeparationColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ double x;
+ double c[gfxColorMaxComps];
+ GfxColor color2;
+ int i;
+
+ x = colToDbl(color->c[0]);
+ func->transform(&x, c);
+ for (i = 0; i < alt->getNComps(); ++i) {
+ color2.c[i] = dblToCol(c[i]);
+ }
+ alt->getGray(&color2, gray);
+}
+
+void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ double x;
+ double c[gfxColorMaxComps];
+ GfxColor color2;
+ int i;
+
+ x = colToDbl(color->c[0]);
+ func->transform(&x, c);
+ for (i = 0; i < alt->getNComps(); ++i) {
+ color2.c[i] = dblToCol(c[i]);
+ }
+ alt->getRGB(&color2, rgb);
+}
+
+void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ double x;
+ double c[gfxColorMaxComps];
+ GfxColor color2;
+ int i;
+
+ x = colToDbl(color->c[0]);
+ func->transform(&x, c);
+ for (i = 0; i < alt->getNComps(); ++i) {
+ color2.c[i] = dblToCol(c[i]);
+ }
+ alt->getCMYK(&color2, cmyk);
+}
+
+void GfxSeparationColorSpace::getDefaultColor(GfxColor *color) {
+ color->c[0] = gfxColorComp1;
+}
+
+//------------------------------------------------------------------------
+// GfxDeviceNColorSpace
+//------------------------------------------------------------------------
+
+GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
+ GfxColorSpace *altA,
+ Function *funcA) {
+ nComps = nCompsA;
+ alt = altA;
+ func = funcA;
+ nonMarking = gFalse;
+}
+
+GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
+ int i;
+
+ for (i = 0; i < nComps; ++i) {
+ delete names[i];
+ }
+ delete alt;
+ delete func;
+}
+
+GfxColorSpace *GfxDeviceNColorSpace::copy() {
+ GfxDeviceNColorSpace *cs;
+ int i;
+
+ cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy());
+ for (i = 0; i < nComps; ++i) {
+ cs->names[i] = names[i]->copy();
+ }
+ cs->nonMarking = nonMarking;
+ return cs;
+}
+
+//~ handle the 'None' colorant
+GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
+ GfxDeviceNColorSpace *cs;
+ int nCompsA;
+ GString *namesA[gfxColorMaxComps];
+ GfxColorSpace *altA;
+ Function *funcA;
+ Object obj1, obj2;
+ int i;
+
+ if (arr->getLength() != 4 && arr->getLength() != 5) {
+ error(-1, "Bad DeviceN color space");
+ goto err1;
+ }
+ if (!arr->get(1, &obj1)->isArray()) {
+ error(-1, "Bad DeviceN color space (names)");
+ goto err2;
+ }
+ nCompsA = obj1.arrayGetLength();
+ if (nCompsA > gfxColorMaxComps) {
+ error(-1, "DeviceN color space with too many (%d > %d) components",
+ nCompsA, gfxColorMaxComps);
+ nCompsA = gfxColorMaxComps;
+ }
+ for (i = 0; i < nCompsA; ++i) {
+ if (!obj1.arrayGet(i, &obj2)->isName()) {
+ error(-1, "Bad DeviceN color space (names)");
+ obj2.free();
+ goto err2;
+ }
+ namesA[i] = new GString(obj2.getName());
+ obj2.free();
+ }
+ obj1.free();
+ arr->get(2, &obj1);
+ if (!(altA = GfxColorSpace::parse(&obj1))) {
+ error(-1, "Bad DeviceN color space (alternate color space)");
+ goto err3;
+ }
+ obj1.free();
+ arr->get(3, &obj1);
+ if (!(funcA = Function::parse(&obj1))) {
+ goto err4;
+ }
+ obj1.free();
+ cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
+ cs->nonMarking = gTrue;
+ for (i = 0; i < nCompsA; ++i) {
+ cs->names[i] = namesA[i];
+ if (namesA[i]->cmp("None")) {
+ cs->nonMarking = gFalse;
+ }
+ }
+ return cs;
+
+ err4:
+ delete altA;
+ err3:
+ for (i = 0; i < nCompsA; ++i) {
+ delete namesA[i];
+ }
+ err2:
+ obj1.free();
+ err1:
+ return NULL;
+}
+
+void GfxDeviceNColorSpace::getGray(GfxColor *color, GfxGray *gray) {
+ double x[gfxColorMaxComps], c[gfxColorMaxComps];
+ GfxColor color2;
+ int i;
+
+ for (i = 0; i < nComps; ++i) {
+ x[i] = colToDbl(color->c[i]);
+ }
+ func->transform(x, c);
+ for (i = 0; i < alt->getNComps(); ++i) {
+ color2.c[i] = dblToCol(c[i]);
+ }
+ alt->getGray(&color2, gray);
+}
+
+void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
+ double x[gfxColorMaxComps], c[gfxColorMaxComps];
+ GfxColor color2;
+ int i;
+
+ for (i = 0; i < nComps; ++i) {
+ x[i] = colToDbl(color->c[i]);
+ }
+ func->transform(x, c);
+ for (i = 0; i < alt->getNComps(); ++i) {
+ color2.c[i] = dblToCol(c[i]);
+ }
+ alt->getRGB(&color2, rgb);
+}
+
+void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
+ double x[gfxColorMaxComps], c[gfxColorMaxComps];
+ GfxColor color2;
+ int i;
+
+ for (i = 0; i < nComps; ++i) {
+ x[i] = colToDbl(color->c[i]);
+ }
+ func->transform(x, c);
+ for (i = 0; i < alt->getNComps(); ++i) {
+ color2.c[i] = dblToCol(c[i]);
+ }
+ alt->getCMYK(&color2, cmyk);
+}
+
+void GfxDeviceNColorSpace::getDefaultColor(GfxColor *color) {
+ int i;
+
+ for (i = 0; i < nComps; ++i) {
+ color->c[i] = gfxColorComp1;
+ }
+}
+
+//------------------------------------------------------------------------
+// GfxPatternColorSpace
+//------------------------------------------------------------------------
+
+GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) {
+ under = underA;
+}
+
+GfxPatternColorSpace::~GfxPatternColorSpace() {
+ if (under) {
+ delete under;
+ }
+}
+
+GfxColorSpace *GfxPatternColorSpace::copy() {
+ return new GfxPatternColorSpace(under ? under->copy() :
+ (GfxColorSpace *)NULL);
+}
+
+GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
+ GfxPatternColorSpace *cs;
+ GfxColorSpace *underA;
+ Object obj1;
+
+ if (arr->getLength() != 1 && arr->getLength() != 2) {
+ error(-1, "Bad Pattern color space");
+ return NULL;
+ }
+ underA = NULL;
+ if (arr->getLength() == 2) {
+ arr->get(1, &obj1);
+ if (!(underA = GfxColorSpace::parse(&obj1))) {
+ error(-1, "Bad Pattern color space (underlying color space)");
+ obj1.free();
+ return NULL;
+ }
+ obj1.free();
+ }
+ cs = new GfxPatternColorSpace(underA);
+ return cs;
+}
+
+void GfxPatternColorSpace::getGray(GfxColor * /*color*/, GfxGray *gray) {
+ *gray = 0;
+}
+
+void GfxPatternColorSpace::getRGB(GfxColor * /*color*/, GfxRGB *rgb) {
+ rgb->r = rgb->g = rgb->b = 0;
+}
+
+void GfxPatternColorSpace::getCMYK(GfxColor * /*color*/, GfxCMYK *cmyk) {
+ cmyk->c = cmyk->m = cmyk->y = 0;
+ cmyk->k = 1;
+}
+
+void GfxPatternColorSpace::getDefaultColor(GfxColor * /*color*/) {
+ // not used
+}
+
+//------------------------------------------------------------------------
+// Pattern
+//------------------------------------------------------------------------
+
+GfxPattern::GfxPattern(int typeA) {
+ type = typeA;
+}
+
+GfxPattern::~GfxPattern() {
+}
+
+GfxPattern *GfxPattern::parse(Object *obj) {
+ GfxPattern *pattern;
+ Object obj1;
+
+ if (obj->isDict()) {
+ obj->dictLookup("PatternType", &obj1);
+ } else if (obj->isStream()) {
+ obj->streamGetDict()->lookup("PatternType", &obj1);
+ } else {
+ return NULL;
+ }
+ pattern = NULL;
+ if (obj1.isInt() && obj1.getInt() == 1) {
+ pattern = GfxTilingPattern::parse(obj);
+ } else if (obj1.isInt() && obj1.getInt() == 2) {
+ pattern = GfxShadingPattern::parse(obj);
+ }
+ obj1.free();
+ return pattern;
+}
+
+//------------------------------------------------------------------------
+// GfxTilingPattern
+//------------------------------------------------------------------------
+
+GfxTilingPattern *GfxTilingPattern::parse(Object *patObj) {
+ GfxTilingPattern *pat;
+ Dict *dict;
+ int paintTypeA, tilingTypeA;
+ double bboxA[4], matrixA[6];
+ double xStepA, yStepA;
+ Object resDictA;
+ Object obj1, obj2;
+ int i;
+
+ if (!patObj->isStream()) {
+ return NULL;
+ }
+ dict = patObj->streamGetDict();
+
+ if (dict->lookup("PaintType", &obj1)->isInt()) {
+ paintTypeA = obj1.getInt();
+ } else {
+ paintTypeA = 1;
+ error(-1, "Invalid or missing PaintType in pattern");
+ }
+ obj1.free();
+ if (dict->lookup("TilingType", &obj1)->isInt()) {
+ tilingTypeA = obj1.getInt();
+ } else {
+ tilingTypeA = 1;
+ error(-1, "Invalid or missing TilingType in pattern");
+ }
+ obj1.free();
+ bboxA[0] = bboxA[1] = 0;
+ bboxA[2] = bboxA[3] = 1;
+ if (dict->lookup("BBox", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 4) {
+ for (i = 0; i < 4; ++i) {
+ if (obj1.arrayGet(i, &obj2)->isNum()) {
+ bboxA[i] = obj2.getNum();
+ }
+ obj2.free();
+ }
+ } else {
+ error(-1, "Invalid or missing BBox in pattern");
+ }
+ obj1.free();
+ if (dict->lookup("XStep", &obj1)->isNum()) {
+ xStepA = obj1.getNum();
+ } else {
+ xStepA = 1;
+ error(-1, "Invalid or missing XStep in pattern");
+ }
+ obj1.free();
+ if (dict->lookup("YStep", &obj1)->isNum()) {
+ yStepA = obj1.getNum();
+ } else {
+ yStepA = 1;
+ error(-1, "Invalid or missing YStep in pattern");
+ }
+ obj1.free();
+ if (!dict->lookup("Resources", &resDictA)->isDict()) {
+ resDictA.free();
+ resDictA.initNull();
+ error(-1, "Invalid or missing Resources in pattern");
+ }
+ matrixA[0] = 1; matrixA[1] = 0;
+ matrixA[2] = 0; matrixA[3] = 1;
+ matrixA[4] = 0; matrixA[5] = 0;
+ if (dict->lookup("Matrix", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 6) {
+ for (i = 0; i < 6; ++i) {
+ if (obj1.arrayGet(i, &obj2)->isNum()) {
+ matrixA[i] = obj2.getNum();
+ }
+ obj2.free();
+ }
+ }
+ obj1.free();
+
+ pat = new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA,
+ &resDictA, matrixA, patObj);
+ resDictA.free();
+ return pat;
+}
+
+GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA,
+ double *bboxA, double xStepA, double yStepA,
+ Object *resDictA, double *matrixA,
+ Object *contentStreamA):
+ GfxPattern(1)
+{
+ int i;
+
+ paintType = paintTypeA;
+ tilingType = tilingTypeA;
+ for (i = 0; i < 4; ++i) {
+ bbox[i] = bboxA[i];
+ }
+ xStep = xStepA;
+ yStep = yStepA;
+ resDictA->copy(&resDict);
+ for (i = 0; i < 6; ++i) {
+ matrix[i] = matrixA[i];
+ }
+ contentStreamA->copy(&contentStream);
+}
+
+GfxTilingPattern::~GfxTilingPattern() {
+ resDict.free();
+ contentStream.free();
+}
+
+GfxPattern *GfxTilingPattern::copy() {
+ return new GfxTilingPattern(paintType, tilingType, bbox, xStep, yStep,
+ &resDict, matrix, &contentStream);
+}
+
+//------------------------------------------------------------------------
+// GfxShadingPattern
+//------------------------------------------------------------------------
+
+GfxShadingPattern *GfxShadingPattern::parse(Object *patObj) {
+ Dict *dict;
+ GfxShading *shadingA;
+ double matrixA[6];
+ Object obj1, obj2;
+ int i;
+
+ if (!patObj->isDict()) {
+ return NULL;
+ }
+ dict = patObj->getDict();
+
+ dict->lookup("Shading", &obj1);
+ shadingA = GfxShading::parse(&obj1);
+ obj1.free();
+ if (!shadingA) {
+ return NULL;
+ }
+
+ matrixA[0] = 1; matrixA[1] = 0;
+ matrixA[2] = 0; matrixA[3] = 1;
+ matrixA[4] = 0; matrixA[5] = 0;
+ if (dict->lookup("Matrix", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 6) {
+ for (i = 0; i < 6; ++i) {
+ if (obj1.arrayGet(i, &obj2)->isNum()) {
+ matrixA[i] = obj2.getNum();
+ }
+ obj2.free();
+ }
+ }
+ obj1.free();
+
+ return new GfxShadingPattern(shadingA, matrixA);
+}
+
+GfxShadingPattern::GfxShadingPattern(GfxShading *shadingA, double *matrixA):
+ GfxPattern(2)
+{
+ int i;
+
+ shading = shadingA;
+ for (i = 0; i < 6; ++i) {
+ matrix[i] = matrixA[i];
+ }
+}
+
+GfxShadingPattern::~GfxShadingPattern() {
+ delete shading;
+}
+
+GfxPattern *GfxShadingPattern::copy() {
+ return new GfxShadingPattern(shading->copy(), matrix);
+}
+
+//------------------------------------------------------------------------
+// GfxShading
+//------------------------------------------------------------------------
+
+GfxShading::GfxShading(int typeA) {
+ type = typeA;
+ colorSpace = NULL;
+}
+
+GfxShading::GfxShading(GfxShading *shading) {
+ int i;
+
+ type = shading->type;
+ colorSpace = shading->colorSpace->copy();
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ background.c[i] = shading->background.c[i];
+ }
+ hasBackground = shading->hasBackground;
+ xMin = shading->xMin;
+ yMin = shading->yMin;
+ xMax = shading->xMax;
+ yMax = shading->yMax;
+ hasBBox = shading->hasBBox;
+}
+
+GfxShading::~GfxShading() {
+ if (colorSpace) {
+ delete colorSpace;
+ }
+}
+
+GfxShading *GfxShading::parse(Object *obj) {
+ GfxShading *shading;
+ Dict *dict;
+ int typeA;
+ Object obj1;
+
+ if (obj->isDict()) {
+ dict = obj->getDict();
+ } else if (obj->isStream()) {
+ dict = obj->streamGetDict();
+ } else {
+ return NULL;
+ }
+
+ if (!dict->lookup("ShadingType", &obj1)->isInt()) {
+ error(-1, "Invalid ShadingType in shading dictionary");
+ obj1.free();
+ return NULL;
+ }
+ typeA = obj1.getInt();
+ obj1.free();
+
+ switch (typeA) {
+ case 1:
+ shading = GfxFunctionShading::parse(dict);
+ break;
+ case 2:
+ shading = GfxAxialShading::parse(dict);
+ break;
+ case 3:
+ shading = GfxRadialShading::parse(dict);
+ break;
+ case 4:
+ if (obj->isStream()) {
+ shading = GfxGouraudTriangleShading::parse(4, dict, obj->getStream());
+ } else {
+ error(-1, "Invalid Type 4 shading object");
+ goto err1;
+ }
+ break;
+ case 5:
+ if (obj->isStream()) {
+ shading = GfxGouraudTriangleShading::parse(5, dict, obj->getStream());
+ } else {
+ error(-1, "Invalid Type 5 shading object");
+ goto err1;
+ }
+ break;
+ case 6:
+ if (obj->isStream()) {
+ shading = GfxPatchMeshShading::parse(6, dict, obj->getStream());
+ } else {
+ error(-1, "Invalid Type 6 shading object");
+ goto err1;
+ }
+ break;
+ case 7:
+ if (obj->isStream()) {
+ shading = GfxPatchMeshShading::parse(7, dict, obj->getStream());
+ } else {
+ error(-1, "Invalid Type 7 shading object");
+ goto err1;
+ }
+ break;
+ default:
+ error(-1, "Unimplemented shading type %d", typeA);
+ goto err1;
+ }
+
+ return shading;
+
+ err1:
+ return NULL;
+}
+
+GBool GfxShading::init(Dict *dict) {
+ Object obj1, obj2;
+ int i;
+
+ dict->lookup("ColorSpace", &obj1);
+ if (!(colorSpace = GfxColorSpace::parse(&obj1))) {
+ error(-1, "Bad color space in shading dictionary");
+ obj1.free();
+ return gFalse;
+ }
+ obj1.free();
+
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ background.c[i] = 0;
+ }
+ hasBackground = gFalse;
+ if (dict->lookup("Background", &obj1)->isArray()) {
+ if (obj1.arrayGetLength() == colorSpace->getNComps()) {
+ hasBackground = gTrue;
+ for (i = 0; i < colorSpace->getNComps(); ++i) {
+ background.c[i] = dblToCol(obj1.arrayGet(i, &obj2)->getNum());
+ obj2.free();
+ }
+ } else {
+ error(-1, "Bad Background in shading dictionary");
+ }
+ }
+ obj1.free();
+
+ xMin = yMin = xMax = yMax = 0;
+ hasBBox = gFalse;
+ if (dict->lookup("BBox", &obj1)->isArray()) {
+ if (obj1.arrayGetLength() == 4) {
+ hasBBox = gTrue;
+ xMin = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ yMin = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ xMax = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ yMax = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ } else {
+ error(-1, "Bad BBox in shading dictionary");
+ }
+ }
+ obj1.free();
+
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
+// GfxFunctionShading
+//------------------------------------------------------------------------
+
+GfxFunctionShading::GfxFunctionShading(double x0A, double y0A,
+ double x1A, double y1A,
+ double *matrixA,
+ Function **funcsA, int nFuncsA):
+ GfxShading(1)
+{
+ int i;
+
+ x0 = x0A;
+ y0 = y0A;
+ x1 = x1A;
+ y1 = y1A;
+ for (i = 0; i < 6; ++i) {
+ matrix[i] = matrixA[i];
+ }
+ nFuncs = nFuncsA;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = funcsA[i];
+ }
+}
+
+GfxFunctionShading::GfxFunctionShading(GfxFunctionShading *shading):
+ GfxShading(shading)
+{
+ int i;
+
+ x0 = shading->x0;
+ y0 = shading->y0;
+ x1 = shading->x1;
+ y1 = shading->y1;
+ for (i = 0; i < 6; ++i) {
+ matrix[i] = shading->matrix[i];
+ }
+ nFuncs = shading->nFuncs;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = shading->funcs[i]->copy();
+ }
+}
+
+GfxFunctionShading::~GfxFunctionShading() {
+ int i;
+
+ for (i = 0; i < nFuncs; ++i) {
+ delete funcs[i];
+ }
+}
+
+GfxFunctionShading *GfxFunctionShading::parse(Dict *dict) {
+ GfxFunctionShading *shading;
+ double x0A, y0A, x1A, y1A;
+ double matrixA[6];
+ Function *funcsA[gfxColorMaxComps];
+ int nFuncsA;
+ Object obj1, obj2;
+ int i;
+
+ x0A = y0A = 0;
+ x1A = y1A = 1;
+ if (dict->lookup("Domain", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 4) {
+ x0A = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ x1A = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ y0A = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ y1A = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ }
+ obj1.free();
+
+ matrixA[0] = 1; matrixA[1] = 0;
+ matrixA[2] = 0; matrixA[3] = 1;
+ matrixA[4] = 0; matrixA[5] = 0;
+ if (dict->lookup("Matrix", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 6) {
+ matrixA[0] = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ matrixA[1] = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ matrixA[2] = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ matrixA[3] = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ matrixA[4] = obj1.arrayGet(4, &obj2)->getNum();
+ obj2.free();
+ matrixA[5] = obj1.arrayGet(5, &obj2)->getNum();
+ obj2.free();
+ }
+ obj1.free();
+
+ dict->lookup("Function", &obj1);
+ if (obj1.isArray()) {
+ nFuncsA = obj1.arrayGetLength();
+ if (nFuncsA > gfxColorMaxComps) {
+ error(-1, "Invalid Function array in shading dictionary");
+ goto err1;
+ }
+ for (i = 0; i < nFuncsA; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!(funcsA[i] = Function::parse(&obj2))) {
+ goto err2;
+ }
+ obj2.free();
+ }
+ } else {
+ nFuncsA = 1;
+ if (!(funcsA[0] = Function::parse(&obj1))) {
+ goto err1;
+ }
+ }
+ obj1.free();
+
+ shading = new GfxFunctionShading(x0A, y0A, x1A, y1A, matrixA,
+ funcsA, nFuncsA);
+ if (!shading->init(dict)) {
+ delete shading;
+ return NULL;
+ }
+ return shading;
+
+ err2:
+ obj2.free();
+ err1:
+ obj1.free();
+ return NULL;
+}
+
+GfxShading *GfxFunctionShading::copy() {
+ return new GfxFunctionShading(this);
+}
+
+void GfxFunctionShading::getColor(double x, double y, GfxColor *color) {
+ double in[2], out[gfxColorMaxComps];
+ int i;
+
+ // NB: there can be one function with n outputs or n functions with
+ // one output each (where n = number of color components)
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ out[i] = 0;
+ }
+ in[0] = x;
+ in[1] = y;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i]->transform(in, &out[i]);
+ }
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ color->c[i] = dblToCol(out[i]);
+ }
+}
+
+//------------------------------------------------------------------------
+// GfxAxialShading
+//------------------------------------------------------------------------
+
+GfxAxialShading::GfxAxialShading(double x0A, double y0A,
+ double x1A, double y1A,
+ double t0A, double t1A,
+ Function **funcsA, int nFuncsA,
+ GBool extend0A, GBool extend1A):
+ GfxShading(2)
+{
+ int i;
+
+ x0 = x0A;
+ y0 = y0A;
+ x1 = x1A;
+ y1 = y1A;
+ t0 = t0A;
+ t1 = t1A;
+ nFuncs = nFuncsA;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = funcsA[i];
+ }
+ extend0 = extend0A;
+ extend1 = extend1A;
+}
+
+GfxAxialShading::GfxAxialShading(GfxAxialShading *shading):
+ GfxShading(shading)
+{
+ int i;
+
+ x0 = shading->x0;
+ y0 = shading->y0;
+ x1 = shading->x1;
+ y1 = shading->y1;
+ t0 = shading->t0;
+ y1 = shading->t1;
+ nFuncs = shading->nFuncs;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = shading->funcs[i]->copy();
+ }
+ extend0 = shading->extend0;
+ extend1 = shading->extend1;
+}
+
+GfxAxialShading::~GfxAxialShading() {
+ int i;
+
+ for (i = 0; i < nFuncs; ++i) {
+ delete funcs[i];
+ }
+}
+
+GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
+ GfxAxialShading *shading;
+ double x0A, y0A, x1A, y1A;
+ double t0A, t1A;
+ Function *funcsA[gfxColorMaxComps];
+ int nFuncsA;
+ GBool extend0A, extend1A;
+ Object obj1, obj2;
+ int i;
+
+ x0A = y0A = x1A = y1A = 0;
+ if (dict->lookup("Coords", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 4) {
+ x0A = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ y0A = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ x1A = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ y1A = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ } else {
+ error(-1, "Missing or invalid Coords in shading dictionary");
+ goto err1;
+ }
+ obj1.free();
+
+ t0A = 0;
+ t1A = 1;
+ if (dict->lookup("Domain", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2) {
+ t0A = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ t1A = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ }
+ obj1.free();
+
+ dict->lookup("Function", &obj1);
+ if (obj1.isArray()) {
+ nFuncsA = obj1.arrayGetLength();
+ if (nFuncsA > gfxColorMaxComps) {
+ error(-1, "Invalid Function array in shading dictionary");
+ goto err1;
+ }
+ for (i = 0; i < nFuncsA; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!(funcsA[i] = Function::parse(&obj2))) {
+ obj1.free();
+ obj2.free();
+ goto err1;
+ }
+ obj2.free();
+ }
+ } else {
+ nFuncsA = 1;
+ if (!(funcsA[0] = Function::parse(&obj1))) {
+ obj1.free();
+ goto err1;
+ }
+ }
+ obj1.free();
+
+ extend0A = extend1A = gFalse;
+ if (dict->lookup("Extend", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2) {
+ extend0A = obj1.arrayGet(0, &obj2)->getBool();
+ obj2.free();
+ extend1A = obj1.arrayGet(1, &obj2)->getBool();
+ obj2.free();
+ }
+ obj1.free();
+
+ shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
+ funcsA, nFuncsA, extend0A, extend1A);
+ if (!shading->init(dict)) {
+ delete shading;
+ return NULL;
+ }
+ return shading;
+
+ err1:
+ return NULL;
+}
+
+GfxShading *GfxAxialShading::copy() {
+ return new GfxAxialShading(this);
+}
+
+void GfxAxialShading::getColor(double t, GfxColor *color) {
+ double out[gfxColorMaxComps];
+ int i;
+
+ // NB: there can be one function with n outputs or n functions with
+ // one output each (where n = number of color components)
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ out[i] = 0;
+ }
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i]->transform(&t, &out[i]);
+ }
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ color->c[i] = dblToCol(out[i]);
+ }
+}
+
+//------------------------------------------------------------------------
+// GfxRadialShading
+//------------------------------------------------------------------------
+
+GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
+ double x1A, double y1A, double r1A,
+ double t0A, double t1A,
+ Function **funcsA, int nFuncsA,
+ GBool extend0A, GBool extend1A):
+ GfxShading(3)
+{
+ int i;
+
+ x0 = x0A;
+ y0 = y0A;
+ r0 = r0A;
+ x1 = x1A;
+ y1 = y1A;
+ r1 = r1A;
+ t0 = t0A;
+ t1 = t1A;
+ nFuncs = nFuncsA;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = funcsA[i];
+ }
+ extend0 = extend0A;
+ extend1 = extend1A;
+}
+
+GfxRadialShading::GfxRadialShading(GfxRadialShading *shading):
+ GfxShading(shading)
+{
+ int i;
+
+ x0 = shading->x0;
+ y0 = shading->y0;
+ r0 = shading->r0;
+ x1 = shading->x1;
+ y1 = shading->y1;
+ r1 = shading->r1;
+ t0 = shading->t0;
+ y1 = shading->t1;
+ nFuncs = shading->nFuncs;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = shading->funcs[i]->copy();
+ }
+ extend0 = shading->extend0;
+ extend1 = shading->extend1;
+}
+
+GfxRadialShading::~GfxRadialShading() {
+ int i;
+
+ for (i = 0; i < nFuncs; ++i) {
+ delete funcs[i];
+ }
+}
+
+GfxRadialShading *GfxRadialShading::parse(Dict *dict) {
+ GfxRadialShading *shading;
+ double x0A, y0A, r0A, x1A, y1A, r1A;
+ double t0A, t1A;
+ Function *funcsA[gfxColorMaxComps];
+ int nFuncsA;
+ GBool extend0A, extend1A;
+ Object obj1, obj2;
+ int i;
+
+ x0A = y0A = r0A = x1A = y1A = r1A = 0;
+ if (dict->lookup("Coords", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 6) {
+ x0A = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ y0A = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ r0A = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ x1A = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ y1A = obj1.arrayGet(4, &obj2)->getNum();
+ obj2.free();
+ r1A = obj1.arrayGet(5, &obj2)->getNum();
+ obj2.free();
+ } else {
+ error(-1, "Missing or invalid Coords in shading dictionary");
+ goto err1;
+ }
+ obj1.free();
+
+ t0A = 0;
+ t1A = 1;
+ if (dict->lookup("Domain", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2) {
+ t0A = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ t1A = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ }
+ obj1.free();
+
+ dict->lookup("Function", &obj1);
+ if (obj1.isArray()) {
+ nFuncsA = obj1.arrayGetLength();
+ if (nFuncsA > gfxColorMaxComps) {
+ error(-1, "Invalid Function array in shading dictionary");
+ goto err1;
+ }
+ for (i = 0; i < nFuncsA; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!(funcsA[i] = Function::parse(&obj2))) {
+ obj1.free();
+ obj2.free();
+ goto err1;
+ }
+ obj2.free();
+ }
+ } else {
+ nFuncsA = 1;
+ if (!(funcsA[0] = Function::parse(&obj1))) {
+ obj1.free();
+ goto err1;
+ }
+ }
+ obj1.free();
+
+ extend0A = extend1A = gFalse;
+ if (dict->lookup("Extend", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2) {
+ extend0A = obj1.arrayGet(0, &obj2)->getBool();
+ obj2.free();
+ extend1A = obj1.arrayGet(1, &obj2)->getBool();
+ obj2.free();
+ }
+ obj1.free();
+
+ shading = new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
+ funcsA, nFuncsA, extend0A, extend1A);
+ if (!shading->init(dict)) {
+ delete shading;
+ return NULL;
+ }
+ return shading;
+
+ err1:
+ return NULL;
+}
+
+GfxShading *GfxRadialShading::copy() {
+ return new GfxRadialShading(this);
+}
+
+void GfxRadialShading::getColor(double t, GfxColor *color) {
+ double out[gfxColorMaxComps];
+ int i;
+
+ // NB: there can be one function with n outputs or n functions with
+ // one output each (where n = number of color components)
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ out[i] = 0;
+ }
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i]->transform(&t, &out[i]);
+ }
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ color->c[i] = dblToCol(out[i]);
+ }
+}
+
+//------------------------------------------------------------------------
+// GfxShadingBitBuf
+//------------------------------------------------------------------------
+
+class GfxShadingBitBuf {
+public:
+
+ GfxShadingBitBuf(Stream *strA);
+ ~GfxShadingBitBuf();
+ GBool getBits(int n, Guint *val);
+ void flushBits();
+
+private:
+
+ Stream *str;
+ int bitBuf;
+ int nBits;
+};
+
+GfxShadingBitBuf::GfxShadingBitBuf(Stream *strA) {
+ str = strA;
+ str->reset();
+ bitBuf = 0;
+ nBits = 0;
+}
+
+GfxShadingBitBuf::~GfxShadingBitBuf() {
+ str->close();
+}
+
+GBool GfxShadingBitBuf::getBits(int n, Guint *val) {
+ int x;
+
+ if (nBits >= n) {
+ x = (bitBuf >> (nBits - n)) & ((1 << n) - 1);
+ nBits -= n;
+ } else {
+ x = 0;
+ if (nBits > 0) {
+ x = bitBuf & ((1 << nBits) - 1);
+ n -= nBits;
+ nBits = 0;
+ }
+ while (n > 0) {
+ if ((bitBuf = str->getChar()) == EOF) {
+ nBits = 0;
+ return gFalse;
+ }
+ if (n >= 8) {
+ x = (x << 8) | bitBuf;
+ n -= 8;
+ } else {
+ x = (x << n) | (bitBuf >> (8 - n));
+ nBits = 8 - n;
+ n = 0;
+ }
+ }
+ }
+ *val = x;
+ return gTrue;
+}
+
+void GfxShadingBitBuf::flushBits() {
+ bitBuf = 0;
+ nBits = 0;
+}
+
+//------------------------------------------------------------------------
+// GfxGouraudTriangleShading
+//------------------------------------------------------------------------
+
+GfxGouraudTriangleShading::GfxGouraudTriangleShading(
+ int typeA,
+ GfxGouraudVertex *verticesA, int nVerticesA,
+ int (*trianglesA)[3], int nTrianglesA,
+ Function **funcsA, int nFuncsA):
+ GfxShading(typeA)
+{
+ int i;
+
+ vertices = verticesA;
+ nVertices = nVerticesA;
+ triangles = trianglesA;
+ nTriangles = nTrianglesA;
+ nFuncs = nFuncsA;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = funcsA[i];
+ }
+}
+
+GfxGouraudTriangleShading::GfxGouraudTriangleShading(
+ GfxGouraudTriangleShading *shading):
+ GfxShading(shading)
+{
+ int i;
+
+ nVertices = shading->nVertices;
+ vertices = (GfxGouraudVertex *)gmallocn(nVertices, sizeof(GfxGouraudVertex));
+ memcpy(vertices, shading->vertices, nVertices * sizeof(GfxGouraudVertex));
+ nTriangles = shading->nTriangles;
+ triangles = (int (*)[3])gmallocn(nTriangles * 3, sizeof(int));
+ memcpy(triangles, shading->triangles, nTriangles * 3 * sizeof(int));
+ nFuncs = shading->nFuncs;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = shading->funcs[i]->copy();
+ }
+}
+
+GfxGouraudTriangleShading::~GfxGouraudTriangleShading() {
+ int i;
+
+ gfree(vertices);
+ gfree(triangles);
+ for (i = 0; i < nFuncs; ++i) {
+ delete funcs[i];
+ }
+}
+
+GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse(int typeA,
+ Dict *dict,
+ Stream *str) {
+ GfxGouraudTriangleShading *shading;
+ Function *funcsA[gfxColorMaxComps];
+ int nFuncsA;
+ int coordBits, compBits, flagBits, vertsPerRow, nRows;
+ double xMin, xMax, yMin, yMax;
+ double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps];
+ double xMul, yMul;
+ double cMul[gfxColorMaxComps];
+ GfxGouraudVertex *verticesA;
+ int (*trianglesA)[3];
+ int nComps, nVerticesA, nTrianglesA, vertSize, triSize;
+ Guint x, y, flag;
+ Guint c[gfxColorMaxComps];
+ GfxShadingBitBuf *bitBuf;
+ Object obj1, obj2;
+ int i, j, k, state;
+
+ if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) {
+ coordBits = obj1.getInt();
+ } else {
+ error(-1, "Missing or invalid BitsPerCoordinate in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+ if (dict->lookup("BitsPerComponent", &obj1)->isInt()) {
+ compBits = obj1.getInt();
+ } else {
+ error(-1, "Missing or invalid BitsPerComponent in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+ flagBits = vertsPerRow = 0; // make gcc happy
+ if (typeA == 4) {
+ if (dict->lookup("BitsPerFlag", &obj1)->isInt()) {
+ flagBits = obj1.getInt();
+ } else {
+ error(-1, "Missing or invalid BitsPerFlag in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+ } else {
+ if (dict->lookup("VerticesPerRow", &obj1)->isInt()) {
+ vertsPerRow = obj1.getInt();
+ } else {
+ error(-1, "Missing or invalid VerticesPerRow in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+ }
+ if (dict->lookup("Decode", &obj1)->isArray() &&
+ obj1.arrayGetLength() >= 6) {
+ xMin = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ xMax = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1);
+ yMin = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ yMax = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1);
+ for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) {
+ cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum();
+ obj2.free();
+ cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum();
+ obj2.free();
+ cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1);
+ }
+ nComps = i;
+ } else {
+ error(-1, "Missing or invalid Decode array in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+
+ if (!dict->lookup("Function", &obj1)->isNull()) {
+ if (obj1.isArray()) {
+ nFuncsA = obj1.arrayGetLength();
+ if (nFuncsA > gfxColorMaxComps) {
+ error(-1, "Invalid Function array in shading dictionary");
+ goto err1;
+ }
+ for (i = 0; i < nFuncsA; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!(funcsA[i] = Function::parse(&obj2))) {
+ obj1.free();
+ obj2.free();
+ goto err1;
+ }
+ obj2.free();
+ }
+ } else {
+ nFuncsA = 1;
+ if (!(funcsA[0] = Function::parse(&obj1))) {
+ obj1.free();
+ goto err1;
+ }
+ }
+ } else {
+ nFuncsA = 0;
+ }
+ obj1.free();
+
+ nVerticesA = nTrianglesA = 0;
+ verticesA = NULL;
+ trianglesA = NULL;
+ vertSize = triSize = 0;
+ state = 0;
+ flag = 0; // make gcc happy
+ bitBuf = new GfxShadingBitBuf(str);
+ while (1) {
+ if (typeA == 4) {
+ if (!bitBuf->getBits(flagBits, &flag)) {
+ break;
+ }
+ }
+ if (!bitBuf->getBits(coordBits, &x) ||
+ !bitBuf->getBits(coordBits, &y)) {
+ break;
+ }
+ for (i = 0; i < nComps; ++i) {
+ if (!bitBuf->getBits(compBits, &c[i])) {
+ break;
+ }
+ }
+ if (i < nComps) {
+ break;
+ }
+ if (nVerticesA == vertSize) {
+ vertSize = (vertSize == 0) ? 16 : 2 * vertSize;
+ verticesA = (GfxGouraudVertex *)
+ greallocn(verticesA, vertSize, sizeof(GfxGouraudVertex));
+ }
+ verticesA[nVerticesA].x = xMin + xMul * (double)x;
+ verticesA[nVerticesA].y = yMin + yMul * (double)y;
+ for (i = 0; i < nComps; ++i) {
+ verticesA[nVerticesA].color.c[i] =
+ dblToCol(cMin[i] + cMul[i] * (double)c[i]);
+ }
+ ++nVerticesA;
+ bitBuf->flushBits();
+ if (typeA == 4) {
+ if (state == 0 || state == 1) {
+ ++state;
+ } else if (state == 2 || flag > 0) {
+ if (nTrianglesA == triSize) {
+ triSize = (triSize == 0) ? 16 : 2 * triSize;
+ trianglesA = (int (*)[3])
+ greallocn(trianglesA, triSize * 3, sizeof(int));
+ }
+ if (state == 2) {
+ trianglesA[nTrianglesA][0] = nVerticesA - 3;
+ trianglesA[nTrianglesA][1] = nVerticesA - 2;
+ trianglesA[nTrianglesA][2] = nVerticesA - 1;
+ ++state;
+ } else if (flag == 1) {
+ trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][1];
+ trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2];
+ trianglesA[nTrianglesA][2] = nVerticesA - 1;
+ } else { // flag == 2
+ trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][0];
+ trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2];
+ trianglesA[nTrianglesA][2] = nVerticesA - 1;
+ }
+ ++nTrianglesA;
+ } else { // state == 3 && flag == 0
+ state = 1;
+ }
+ }
+ }
+ delete bitBuf;
+ if (typeA == 5) {
+ nRows = nVerticesA / vertsPerRow;
+ nTrianglesA = (nRows - 1) * 2 * (vertsPerRow - 1);
+ trianglesA = (int (*)[3])gmallocn(nTrianglesA * 3, sizeof(int));
+ k = 0;
+ for (i = 0; i < nRows - 1; ++i) {
+ for (j = 0; j < vertsPerRow - 1; ++j) {
+ trianglesA[k][0] = i * vertsPerRow + j;
+ trianglesA[k][1] = i * vertsPerRow + j+1;
+ trianglesA[k][2] = (i+1) * vertsPerRow + j;
+ ++k;
+ trianglesA[k][0] = i * vertsPerRow + j+1;
+ trianglesA[k][1] = (i+1) * vertsPerRow + j;
+ trianglesA[k][2] = (i+1) * vertsPerRow + j+1;
+ ++k;
+ }
+ }
+ }
+
+ shading = new GfxGouraudTriangleShading(typeA, verticesA, nVerticesA,
+ trianglesA, nTrianglesA,
+ funcsA, nFuncsA);
+ if (!shading->init(dict)) {
+ delete shading;
+ return NULL;
+ }
+ return shading;
+
+ err2:
+ obj1.free();
+ err1:
+ return NULL;
+}
+
+GfxShading *GfxGouraudTriangleShading::copy() {
+ return new GfxGouraudTriangleShading(this);
+}
+
+void GfxGouraudTriangleShading::getTriangle(
+ int i,
+ double *x0, double *y0, GfxColor *color0,
+ double *x1, double *y1, GfxColor *color1,
+ double *x2, double *y2, GfxColor *color2) {
+ double in;
+ double out[gfxColorMaxComps];
+ int v, j;
+
+ v = triangles[i][0];
+ *x0 = vertices[v].x;
+ *y0 = vertices[v].y;
+ if (nFuncs > 0) {
+ in = colToDbl(vertices[v].color.c[0]);
+ for (j = 0; j < nFuncs; ++j) {
+ funcs[j]->transform(&in, &out[j]);
+ }
+ for (j = 0; j < gfxColorMaxComps; ++j) {
+ color0->c[j] = dblToCol(out[j]);
+ }
+ } else {
+ *color0 = vertices[v].color;
+ }
+ v = triangles[i][1];
+ *x1 = vertices[v].x;
+ *y1 = vertices[v].y;
+ if (nFuncs > 0) {
+ in = colToDbl(vertices[v].color.c[0]);
+ for (j = 0; j < nFuncs; ++j) {
+ funcs[j]->transform(&in, &out[j]);
+ }
+ for (j = 0; j < gfxColorMaxComps; ++j) {
+ color1->c[j] = dblToCol(out[j]);
+ }
+ } else {
+ *color1 = vertices[v].color;
+ }
+ v = triangles[i][2];
+ *x2 = vertices[v].x;
+ *y2 = vertices[v].y;
+ if (nFuncs > 0) {
+ in = colToDbl(vertices[v].color.c[0]);
+ for (j = 0; j < nFuncs; ++j) {
+ funcs[j]->transform(&in, &out[j]);
+ }
+ for (j = 0; j < gfxColorMaxComps; ++j) {
+ color2->c[j] = dblToCol(out[j]);
+ }
+ } else {
+ *color2 = vertices[v].color;
+ }
+}
+
+//------------------------------------------------------------------------
+// GfxPatchMeshShading
+//------------------------------------------------------------------------
+
+GfxPatchMeshShading::GfxPatchMeshShading(int typeA,
+ GfxPatch *patchesA, int nPatchesA,
+ Function **funcsA, int nFuncsA):
+ GfxShading(typeA)
+{
+ int i;
+
+ patches = patchesA;
+ nPatches = nPatchesA;
+ nFuncs = nFuncsA;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = funcsA[i];
+ }
+}
+
+GfxPatchMeshShading::GfxPatchMeshShading(GfxPatchMeshShading *shading):
+ GfxShading(shading)
+{
+ int i;
+
+ nPatches = shading->nPatches;
+ patches = (GfxPatch *)gmallocn(nPatches, sizeof(GfxPatch));
+ memcpy(patches, shading->patches, nPatches * sizeof(GfxPatch));
+ nFuncs = shading->nFuncs;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = shading->funcs[i]->copy();
+ }
+}
+
+GfxPatchMeshShading::~GfxPatchMeshShading() {
+ int i;
+
+ gfree(patches);
+ for (i = 0; i < nFuncs; ++i) {
+ delete funcs[i];
+ }
+}
+
+GfxPatchMeshShading *GfxPatchMeshShading::parse(int typeA, Dict *dict,
+ Stream *str) {
+ GfxPatchMeshShading *shading;
+ Function *funcsA[gfxColorMaxComps];
+ int nFuncsA;
+ int coordBits, compBits, flagBits;
+ double xMin, xMax, yMin, yMax;
+ double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps];
+ double xMul, yMul;
+ double cMul[gfxColorMaxComps];
+ GfxPatch *patchesA, *p;
+ int nComps, nPatchesA, patchesSize, nPts, nColors;
+ Guint flag;
+ double x[16], y[16];
+ Guint xi, yi;
+ GfxColorComp c[4][gfxColorMaxComps];
+ Guint ci[4];
+ GfxShadingBitBuf *bitBuf;
+ Object obj1, obj2;
+ int i, j;
+
+ if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) {
+ coordBits = obj1.getInt();
+ } else {
+ error(-1, "Missing or invalid BitsPerCoordinate in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+ if (dict->lookup("BitsPerComponent", &obj1)->isInt()) {
+ compBits = obj1.getInt();
+ } else {
+ error(-1, "Missing or invalid BitsPerComponent in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+ if (dict->lookup("BitsPerFlag", &obj1)->isInt()) {
+ flagBits = obj1.getInt();
+ } else {
+ error(-1, "Missing or invalid BitsPerFlag in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+ if (dict->lookup("Decode", &obj1)->isArray() &&
+ obj1.arrayGetLength() >= 6) {
+ xMin = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ xMax = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1);
+ yMin = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ yMax = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1);
+ for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) {
+ cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum();
+ obj2.free();
+ cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum();
+ obj2.free();
+ cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1);
+ }
+ nComps = i;
+ } else {
+ error(-1, "Missing or invalid Decode array in shading dictionary");
+ goto err2;
+ }
+ obj1.free();
+
+ if (!dict->lookup("Function", &obj1)->isNull()) {
+ if (obj1.isArray()) {
+ nFuncsA = obj1.arrayGetLength();
+ if (nFuncsA > gfxColorMaxComps) {
+ error(-1, "Invalid Function array in shading dictionary");
+ goto err1;
+ }
+ for (i = 0; i < nFuncsA; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!(funcsA[i] = Function::parse(&obj2))) {
+ obj1.free();
+ obj2.free();
+ goto err1;
+ }
+ obj2.free();
+ }
+ } else {
+ nFuncsA = 1;
+ if (!(funcsA[0] = Function::parse(&obj1))) {
+ obj1.free();
+ goto err1;
+ }
+ }
+ } else {
+ nFuncsA = 0;
+ }
+ obj1.free();
+
+ nPatchesA = 0;
+ patchesA = NULL;
+ patchesSize = 0;
+ bitBuf = new GfxShadingBitBuf(str);
+ while (1) {
+ if (!bitBuf->getBits(flagBits, &flag)) {
+ break;
+ }
+ if (typeA == 6) {
+ switch (flag) {
+ case 0: nPts = 12; nColors = 4; break;
+ case 1:
+ case 2:
+ case 3:
+ default: nPts = 8; nColors = 2; break;
+ }
+ } else {
+ switch (flag) {
+ case 0: nPts = 16; nColors = 4; break;
+ case 1:
+ case 2:
+ case 3:
+ default: nPts = 12; nColors = 2; break;
+ }
+ }
+ for (i = 0; i < nPts; ++i) {
+ if (!bitBuf->getBits(coordBits, &xi) ||
+ !bitBuf->getBits(coordBits, &yi)) {
+ break;
+ }
+ x[i] = xMin + xMul * (double)xi;
+ y[i] = yMin + yMul * (double)yi;
+ }
+ if (i < nPts) {
+ break;
+ }
+ for (i = 0; i < nColors; ++i) {
+ for (j = 0; j < nComps; ++j) {
+ if (!bitBuf->getBits(compBits, &ci[j])) {
+ break;
+ }
+ c[i][j] = dblToCol(cMin[j] + cMul[j] * (double)ci[j]);
+ }
+ if (j < nComps) {
+ break;
+ }
+ }
+ if (i < nColors) {
+ break;
+ }
+ if (nPatchesA == patchesSize) {
+ patchesSize = (patchesSize == 0) ? 16 : 2 * patchesSize;
+ patchesA = (GfxPatch *)greallocn(patchesA,
+ patchesSize, sizeof(GfxPatch));
+ }
+ p = &patchesA[nPatchesA];
+ if (typeA == 6) {
+ switch (flag) {
+ case 0:
+ p->x[0][0] = x[0];
+ p->y[0][0] = y[0];
+ p->x[0][1] = x[1];
+ p->y[0][1] = y[1];
+ p->x[0][2] = x[2];
+ p->y[0][2] = y[2];
+ p->x[0][3] = x[3];
+ p->y[0][3] = y[3];
+ p->x[1][3] = x[4];
+ p->y[1][3] = y[4];
+ p->x[2][3] = x[5];
+ p->y[2][3] = y[5];
+ p->x[3][3] = x[6];
+ p->y[3][3] = y[6];
+ p->x[3][2] = x[7];
+ p->y[3][2] = y[7];
+ p->x[3][1] = x[8];
+ p->y[3][1] = y[8];
+ p->x[3][0] = x[9];
+ p->y[3][0] = y[9];
+ p->x[2][0] = x[10];
+ p->y[2][0] = y[10];
+ p->x[1][0] = x[11];
+ p->y[1][0] = y[11];
+ for (j = 0; j < nComps; ++j) {
+ p->color[0][0].c[j] = c[0][j];
+ p->color[0][1].c[j] = c[1][j];
+ p->color[1][1].c[j] = c[2][j];
+ p->color[1][0].c[j] = c[3][j];
+ }
+ break;
+ case 1:
+ p->x[0][0] = patchesA[nPatchesA-1].x[0][3];
+ p->y[0][0] = patchesA[nPatchesA-1].y[0][3];
+ p->x[0][1] = patchesA[nPatchesA-1].x[1][3];
+ p->y[0][1] = patchesA[nPatchesA-1].y[1][3];
+ p->x[0][2] = patchesA[nPatchesA-1].x[2][3];
+ p->y[0][2] = patchesA[nPatchesA-1].y[2][3];
+ p->x[0][3] = patchesA[nPatchesA-1].x[3][3];
+ p->y[0][3] = patchesA[nPatchesA-1].y[3][3];
+ p->x[1][3] = x[0];
+ p->y[1][3] = y[0];
+ p->x[2][3] = x[1];
+ p->y[2][3] = y[1];
+ p->x[3][3] = x[2];
+ p->y[3][3] = y[2];
+ p->x[3][2] = x[3];
+ p->y[3][2] = y[3];
+ p->x[3][1] = x[4];
+ p->y[3][1] = y[4];
+ p->x[3][0] = x[5];
+ p->y[3][0] = y[5];
+ p->x[2][0] = x[6];
+ p->y[2][0] = y[6];
+ p->x[1][0] = x[7];
+ p->y[1][0] = y[7];
+ for (j = 0; j < nComps; ++j) {
+ p->color[0][0].c[j] = patchesA[nPatchesA-1].color[0][1].c[j];
+ p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][1].c[j];
+ p->color[1][1].c[j] = c[0][j];
+ p->color[1][0].c[j] = c[1][j];
+ }
+ break;
+ case 2:
+ p->x[0][0] = patchesA[nPatchesA-1].x[3][3];
+ p->y[0][0] = patchesA[nPatchesA-1].y[3][3];
+ p->x[0][1] = patchesA[nPatchesA-1].x[3][2];
+ p->y[0][1] = patchesA[nPatchesA-1].y[3][2];
+ p->x[0][2] = patchesA[nPatchesA-1].x[3][1];
+ p->y[0][2] = patchesA[nPatchesA-1].y[3][1];
+ p->x[0][3] = patchesA[nPatchesA-1].x[3][0];
+ p->y[0][3] = patchesA[nPatchesA-1].y[3][0];
+ p->x[1][3] = x[0];
+ p->y[1][3] = y[0];
+ p->x[2][3] = x[1];
+ p->y[2][3] = y[1];
+ p->x[3][3] = x[2];
+ p->y[3][3] = y[2];
+ p->x[3][2] = x[3];
+ p->y[3][2] = y[3];
+ p->x[3][1] = x[4];
+ p->y[3][1] = y[4];
+ p->x[3][0] = x[5];
+ p->y[3][0] = y[5];
+ p->x[2][0] = x[6];
+ p->y[2][0] = y[6];
+ p->x[1][0] = x[7];
+ p->y[1][0] = y[7];
+ for (j = 0; j < nComps; ++j) {
+ p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][1].c[j];
+ p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j];
+ p->color[1][1].c[j] = c[0][j];
+ p->color[1][0].c[j] = c[1][j];
+ }
+ break;
+ case 3:
+ p->x[0][0] = patchesA[nPatchesA-1].x[3][0];
+ p->y[0][0] = patchesA[nPatchesA-1].y[3][0];
+ p->x[0][1] = patchesA[nPatchesA-1].x[2][0];
+ p->y[0][1] = patchesA[nPatchesA-1].y[2][0];
+ p->x[0][2] = patchesA[nPatchesA-1].x[1][0];
+ p->y[0][2] = patchesA[nPatchesA-1].y[1][0];
+ p->x[0][3] = patchesA[nPatchesA-1].x[0][0];
+ p->y[0][3] = patchesA[nPatchesA-1].y[0][0];
+ p->x[1][3] = x[0];
+ p->y[1][3] = y[0];
+ p->x[2][3] = x[1];
+ p->y[2][3] = y[1];
+ p->x[3][3] = x[2];
+ p->y[3][3] = y[2];
+ p->x[3][2] = x[3];
+ p->y[3][2] = y[3];
+ p->x[3][1] = x[4];
+ p->y[3][1] = y[4];
+ p->x[3][0] = x[5];
+ p->y[3][0] = y[5];
+ p->x[2][0] = x[6];
+ p->y[2][0] = y[6];
+ p->x[1][0] = x[7];
+ p->y[1][0] = y[7];
+ for (j = 0; j < nComps; ++j) {
+ p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j];
+ p->color[0][1].c[j] = patchesA[nPatchesA-1].color[0][0].c[j];
+ p->color[1][1].c[j] = c[0][j];
+ p->color[1][0].c[j] = c[1][j];
+ }
+ break;
+ }
+ } else {
+ switch (flag) {
+ case 0:
+ p->x[0][0] = x[0];
+ p->y[0][0] = y[0];
+ p->x[0][1] = x[1];
+ p->y[0][1] = y[1];
+ p->x[0][2] = x[2];
+ p->y[0][2] = y[2];
+ p->x[0][3] = x[3];
+ p->y[0][3] = y[3];
+ p->x[1][3] = x[4];
+ p->y[1][3] = y[4];
+ p->x[2][3] = x[5];
+ p->y[2][3] = y[5];
+ p->x[3][3] = x[6];
+ p->y[3][3] = y[6];
+ p->x[3][2] = x[7];
+ p->y[3][2] = y[7];
+ p->x[3][1] = x[8];
+ p->y[3][1] = y[8];
+ p->x[3][0] = x[9];
+ p->y[3][0] = y[9];
+ p->x[2][0] = x[10];
+ p->y[2][0] = y[10];
+ p->x[1][0] = x[11];
+ p->y[1][0] = y[11];
+ p->x[1][1] = x[12];
+ p->y[1][1] = y[12];
+ p->x[1][2] = x[13];
+ p->y[1][2] = y[13];
+ p->x[2][2] = x[14];
+ p->y[2][2] = y[14];
+ p->x[2][1] = x[15];
+ p->y[2][1] = y[15];
+ for (j = 0; j < nComps; ++j) {
+ p->color[0][0].c[j] = c[0][j];
+ p->color[0][1].c[j] = c[1][j];
+ p->color[1][1].c[j] = c[2][j];
+ p->color[1][0].c[j] = c[3][j];
+ }
+ break;
+ case 1:
+ p->x[0][0] = patchesA[nPatchesA-1].x[0][3];
+ p->y[0][0] = patchesA[nPatchesA-1].y[0][3];
+ p->x[0][1] = patchesA[nPatchesA-1].x[1][3];
+ p->y[0][1] = patchesA[nPatchesA-1].y[1][3];
+ p->x[0][2] = patchesA[nPatchesA-1].x[2][3];
+ p->y[0][2] = patchesA[nPatchesA-1].y[2][3];
+ p->x[0][3] = patchesA[nPatchesA-1].x[3][3];
+ p->y[0][3] = patchesA[nPatchesA-1].y[3][3];
+ p->x[1][3] = x[0];
+ p->y[1][3] = y[0];
+ p->x[2][3] = x[1];
+ p->y[2][3] = y[1];
+ p->x[3][3] = x[2];
+ p->y[3][3] = y[2];
+ p->x[3][2] = x[3];
+ p->y[3][2] = y[3];
+ p->x[3][1] = x[4];
+ p->y[3][1] = y[4];
+ p->x[3][0] = x[5];
+ p->y[3][0] = y[5];
+ p->x[2][0] = x[6];
+ p->y[2][0] = y[6];
+ p->x[1][0] = x[7];
+ p->y[1][0] = y[7];
+ p->x[1][1] = x[8];
+ p->y[1][1] = y[8];
+ p->x[1][2] = x[9];
+ p->y[1][2] = y[9];
+ p->x[2][2] = x[10];
+ p->y[2][2] = y[10];
+ p->x[2][1] = x[11];
+ p->y[2][1] = y[11];
+ for (j = 0; j < nComps; ++j) {
+ p->color[0][0].c[j] = patchesA[nPatchesA-1].color[0][1].c[j];
+ p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][1].c[j];
+ p->color[1][1].c[j] = c[0][j];
+ p->color[1][0].c[j] = c[1][j];
+ }
+ break;
+ case 2:
+ p->x[0][0] = patchesA[nPatchesA-1].x[3][3];
+ p->y[0][0] = patchesA[nPatchesA-1].y[3][3];
+ p->x[0][1] = patchesA[nPatchesA-1].x[3][2];
+ p->y[0][1] = patchesA[nPatchesA-1].y[3][2];
+ p->x[0][2] = patchesA[nPatchesA-1].x[3][1];
+ p->y[0][2] = patchesA[nPatchesA-1].y[3][1];
+ p->x[0][3] = patchesA[nPatchesA-1].x[3][0];
+ p->y[0][3] = patchesA[nPatchesA-1].y[3][0];
+ p->x[1][3] = x[0];
+ p->y[1][3] = y[0];
+ p->x[2][3] = x[1];
+ p->y[2][3] = y[1];
+ p->x[3][3] = x[2];
+ p->y[3][3] = y[2];
+ p->x[3][2] = x[3];
+ p->y[3][2] = y[3];
+ p->x[3][1] = x[4];
+ p->y[3][1] = y[4];
+ p->x[3][0] = x[5];
+ p->y[3][0] = y[5];
+ p->x[2][0] = x[6];
+ p->y[2][0] = y[6];
+ p->x[1][0] = x[7];
+ p->y[1][0] = y[7];
+ p->x[1][1] = x[8];
+ p->y[1][1] = y[8];
+ p->x[1][2] = x[9];
+ p->y[1][2] = y[9];
+ p->x[2][2] = x[10];
+ p->y[2][2] = y[10];
+ p->x[2][1] = x[11];
+ p->y[2][1] = y[11];
+ for (j = 0; j < nComps; ++j) {
+ p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][1].c[j];
+ p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j];
+ p->color[1][1].c[j] = c[0][j];
+ p->color[1][0].c[j] = c[1][j];
+ }
+ break;
+ case 3:
+ p->x[0][0] = patchesA[nPatchesA-1].x[3][0];
+ p->y[0][0] = patchesA[nPatchesA-1].y[3][0];
+ p->x[0][1] = patchesA[nPatchesA-1].x[2][0];
+ p->y[0][1] = patchesA[nPatchesA-1].y[2][0];
+ p->x[0][2] = patchesA[nPatchesA-1].x[1][0];
+ p->y[0][2] = patchesA[nPatchesA-1].y[1][0];
+ p->x[0][3] = patchesA[nPatchesA-1].x[0][0];
+ p->y[0][3] = patchesA[nPatchesA-1].y[0][0];
+ p->x[1][3] = x[0];
+ p->y[1][3] = y[0];
+ p->x[2][3] = x[1];
+ p->y[2][3] = y[1];
+ p->x[3][3] = x[2];
+ p->y[3][3] = y[2];
+ p->x[3][2] = x[3];
+ p->y[3][2] = y[3];
+ p->x[3][1] = x[4];
+ p->y[3][1] = y[4];
+ p->x[3][0] = x[5];
+ p->y[3][0] = y[5];
+ p->x[2][0] = x[6];
+ p->y[2][0] = y[6];
+ p->x[1][0] = x[7];
+ p->y[1][0] = y[7];
+ p->x[1][1] = x[8];
+ p->y[1][1] = y[8];
+ p->x[1][2] = x[9];
+ p->y[1][2] = y[9];
+ p->x[2][2] = x[10];
+ p->y[2][2] = y[10];
+ p->x[2][1] = x[11];
+ p->y[2][1] = y[11];
+ for (j = 0; j < nComps; ++j) {
+ p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][0].c[j];
+ p->color[0][1].c[j] = patchesA[nPatchesA-1].color[0][0].c[j];
+ p->color[1][1].c[j] = c[0][j];
+ p->color[1][0].c[j] = c[1][j];
+ }
+ break;
+ }
+ }
+ ++nPatchesA;
+ bitBuf->flushBits();
+ }
+ delete bitBuf;
+
+ if (typeA == 6) {
+ for (i = 0; i < nPatchesA; ++i) {
+ p = &patchesA[i];
+ p->x[1][1] = (-4 * p->x[0][0]
+ +6 * (p->x[0][1] + p->x[1][0])
+ -2 * (p->x[0][3] + p->x[3][0])
+ +3 * (p->x[3][1] + p->x[1][3])
+ - p->x[3][3]) / 9;
+ p->y[1][1] = (-4 * p->y[0][0]
+ +6 * (p->y[0][1] + p->y[1][0])
+ -2 * (p->y[0][3] + p->y[3][0])
+ +3 * (p->y[3][1] + p->y[1][3])
+ - p->y[3][3]) / 9;
+ p->x[1][2] = (-4 * p->x[0][3]
+ +6 * (p->x[0][2] + p->x[1][3])
+ -2 * (p->x[0][0] + p->x[3][3])
+ +3 * (p->x[3][2] + p->x[1][0])
+ - p->x[3][0]) / 9;
+ p->y[1][2] = (-4 * p->y[0][3]
+ +6 * (p->y[0][2] + p->y[1][3])
+ -2 * (p->y[0][0] + p->y[3][3])
+ +3 * (p->y[3][2] + p->y[1][0])
+ - p->y[3][0]) / 9;
+ p->x[2][1] = (-4 * p->x[3][0]
+ +6 * (p->x[3][1] + p->x[2][0])
+ -2 * (p->x[3][3] + p->x[0][0])
+ +3 * (p->x[0][1] + p->x[2][3])
+ - p->x[0][3]) / 9;
+ p->y[2][1] = (-4 * p->y[3][0]
+ +6 * (p->y[3][1] + p->y[2][0])
+ -2 * (p->y[3][3] + p->y[0][0])
+ +3 * (p->y[0][1] + p->y[2][3])
+ - p->y[0][3]) / 9;
+ p->x[2][2] = (-4 * p->x[3][3]
+ +6 * (p->x[3][2] + p->x[2][3])
+ -2 * (p->x[3][0] + p->x[0][3])
+ +3 * (p->x[0][2] + p->x[2][0])
+ - p->x[0][0]) / 9;
+ p->y[2][2] = (-4 * p->y[3][3]
+ +6 * (p->y[3][2] + p->y[2][3])
+ -2 * (p->y[3][0] + p->y[0][3])
+ +3 * (p->y[0][2] + p->y[2][0])
+ - p->y[0][0]) / 9;
+ }
+ }
+
+ shading = new GfxPatchMeshShading(typeA, patchesA, nPatchesA,
+ funcsA, nFuncsA);
+ if (!shading->init(dict)) {
+ delete shading;
+ return NULL;
+ }
+ return shading;
+
+ err2:
+ obj1.free();
+ err1:
+ return NULL;
+}
+
+GfxShading *GfxPatchMeshShading::copy() {
+ return new GfxPatchMeshShading(this);
+}
+
+//------------------------------------------------------------------------
+// GfxImageColorMap
+//------------------------------------------------------------------------
+
+GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
+ GfxColorSpace *colorSpaceA) {
+ GfxIndexedColorSpace *indexedCS;
+ GfxSeparationColorSpace *sepCS;
+ int maxPixel, indexHigh;
+ Guchar *lookup2;
+ Function *sepFunc;
+ Object obj;
+ double x[gfxColorMaxComps];
+ double y[gfxColorMaxComps];
+ int i, j, k;
+
+ ok = gTrue;
+
+ // bits per component and color space
+ bits = bitsA;
+ maxPixel = (1 << bits) - 1;
+ colorSpace = colorSpaceA;
+
+ // initialize
+ for (k = 0; k < gfxColorMaxComps; ++k) {
+ lookup[k] = NULL;
+ }
+
+ // get decode map
+ if (decode->isNull()) {
+ nComps = colorSpace->getNComps();
+ colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel);
+ } else if (decode->isArray()) {
+ nComps = decode->arrayGetLength() / 2;
+ if (nComps != colorSpace->getNComps()) {
+ goto err1;
+ }
+ for (i = 0; i < nComps; ++i) {
+ decode->arrayGet(2*i, &obj);
+ if (!obj.isNum()) {
+ goto err2;
+ }
+ decodeLow[i] = obj.getNum();
+ obj.free();
+ decode->arrayGet(2*i+1, &obj);
+ if (!obj.isNum()) {
+ goto err2;
+ }
+ decodeRange[i] = obj.getNum() - decodeLow[i];
+ obj.free();
+ }
+ } else {
+ goto err1;
+ }
+
+ // Construct a lookup table -- this stores pre-computed decoded
+ // values for each component, i.e., the result of applying the
+ // decode mapping to each possible image pixel component value.
+ //
+ // Optimization: for Indexed and Separation color spaces (which have
+ // only one component), we store color values in the lookup table
+ // rather than component values.
+ colorSpace2 = NULL;
+ nComps2 = 0;
+ if (colorSpace->getMode() == csIndexed) {
+ // Note that indexHigh may not be the same as maxPixel --
+ // Distiller will remove unused palette entries, resulting in
+ // indexHigh < maxPixel.
+ indexedCS = (GfxIndexedColorSpace *)colorSpace;
+ colorSpace2 = indexedCS->getBase();
+ indexHigh = indexedCS->getIndexHigh();
+ nComps2 = colorSpace2->getNComps();
+ lookup2 = indexedCS->getLookup();
+ colorSpace2->getDefaultRanges(x, y, indexHigh);
+ for (k = 0; k < nComps2; ++k) {
+ lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
+ sizeof(GfxColorComp));
+ for (i = 0; i <= maxPixel; ++i) {
+ j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5);
+ if (j < 0) {
+ j = 0;
+ } else if (j > indexHigh) {
+ j = indexHigh;
+ }
+ lookup[k][i] =
+ dblToCol(x[k] + (lookup2[j*nComps2 + k] / 255.0) * y[k]);
+ }
+ }
+ } else if (colorSpace->getMode() == csSeparation) {
+ sepCS = (GfxSeparationColorSpace *)colorSpace;
+ colorSpace2 = sepCS->getAlt();
+ nComps2 = colorSpace2->getNComps();
+ sepFunc = sepCS->getFunc();
+ for (k = 0; k < nComps2; ++k) {
+ lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
+ sizeof(GfxColorComp));
+ for (i = 0; i <= maxPixel; ++i) {
+ x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
+ sepFunc->transform(x, y);
+ lookup[k][i] = dblToCol(y[k]);
+ }
+ }
+ } else {
+ for (k = 0; k < nComps; ++k) {
+ lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1,
+ sizeof(GfxColorComp));
+ for (i = 0; i <= maxPixel; ++i) {
+ lookup[k][i] = dblToCol(decodeLow[k] +
+ (i * decodeRange[k]) / maxPixel);
+ }
+ }
+ }
+
+ return;
+
+ err2:
+ obj.free();
+ err1:
+ ok = gFalse;
+}
+
+GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) {
+ int n, i, k;
+
+ colorSpace = colorMap->colorSpace->copy();
+ bits = colorMap->bits;
+ nComps = colorMap->nComps;
+ nComps2 = colorMap->nComps2;
+ colorSpace2 = NULL;
+ for (k = 0; k < gfxColorMaxComps; ++k) {
+ lookup[k] = NULL;
+ }
+ n = 1 << bits;
+ if (colorSpace->getMode() == csIndexed) {
+ colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase();
+ for (k = 0; k < nComps2; ++k) {
+ lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
+ memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
+ }
+ } else if (colorSpace->getMode() == csSeparation) {
+ colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt();
+ for (k = 0; k < nComps2; ++k) {
+ lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
+ memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
+ }
+ } else {
+ for (k = 0; k < nComps; ++k) {
+ lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp));
+ memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp));
+ }
+ }
+ for (i = 0; i < nComps; ++i) {
+ decodeLow[i] = colorMap->decodeLow[i];
+ decodeRange[i] = colorMap->decodeRange[i];
+ }
+ ok = gTrue;
+}
+
+GfxImageColorMap::~GfxImageColorMap() {
+ int i;
+
+ delete colorSpace;
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ gfree(lookup[i]);
+ }
+}
+
+void GfxImageColorMap::getGray(Guchar *x, GfxGray *gray) {
+ GfxColor color;
+ int i;
+
+ if (colorSpace2) {
+ for (i = 0; i < nComps2; ++i) {
+ color.c[i] = lookup[i][x[0]];
+ }
+ colorSpace2->getGray(&color, gray);
+ } else {
+ for (i = 0; i < nComps; ++i) {
+ color.c[i] = lookup[i][x[i]];
+ }
+ colorSpace->getGray(&color, gray);
+ }
+}
+
+void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
+ GfxColor color;
+ int i;
+
+ if (colorSpace2) {
+ for (i = 0; i < nComps2; ++i) {
+ color.c[i] = lookup[i][x[0]];
+ }
+ colorSpace2->getRGB(&color, rgb);
+ } else {
+ for (i = 0; i < nComps; ++i) {
+ color.c[i] = lookup[i][x[i]];
+ }
+ colorSpace->getRGB(&color, rgb);
+ }
+}
+
+void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
+ GfxColor color;
+ int i;
+
+ if (colorSpace2) {
+ for (i = 0; i < nComps2; ++i) {
+ color.c[i] = lookup[i][x[0]];
+ }
+ colorSpace2->getCMYK(&color, cmyk);
+ } else {
+ for (i = 0; i < nComps; ++i) {
+ color.c[i] = lookup[i][x[i]];
+ }
+ colorSpace->getCMYK(&color, cmyk);
+ }
+}
+
+void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) {
+ int maxPixel, i;
+
+ maxPixel = (1 << bits) - 1;
+ for (i = 0; i < nComps; ++i) {
+ color->c[i] = dblToCol(decodeLow[i] + (x[i] * decodeRange[i]) / maxPixel);
+ }
+}
+
+//------------------------------------------------------------------------
+// GfxSubpath and GfxPath
+//------------------------------------------------------------------------
+
+GfxSubpath::GfxSubpath(double x1, double y1) {
+ size = 16;
+ x = (double *)gmallocn(size, sizeof(double));
+ y = (double *)gmallocn(size, sizeof(double));
+ curve = (GBool *)gmallocn(size, sizeof(GBool));
+ n = 1;
+ x[0] = x1;
+ y[0] = y1;
+ curve[0] = gFalse;
+ closed = gFalse;
+}
+
+GfxSubpath::~GfxSubpath() {
+ gfree(x);
+ gfree(y);
+ gfree(curve);
+}
+
+// Used for copy().
+GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
+ size = subpath->size;
+ n = subpath->n;
+ x = (double *)gmallocn(size, sizeof(double));
+ y = (double *)gmallocn(size, sizeof(double));
+ curve = (GBool *)gmallocn(size, sizeof(GBool));
+ memcpy(x, subpath->x, n * sizeof(double));
+ memcpy(y, subpath->y, n * sizeof(double));
+ memcpy(curve, subpath->curve, n * sizeof(GBool));
+ closed = subpath->closed;
+}
+
+void GfxSubpath::lineTo(double x1, double y1) {
+ if (n >= size) {
+ size += 16;
+ x = (double *)greallocn(x, size, sizeof(double));
+ y = (double *)greallocn(y, size, sizeof(double));
+ curve = (GBool *)greallocn(curve, size, sizeof(GBool));
+ }
+ x[n] = x1;
+ y[n] = y1;
+ curve[n] = gFalse;
+ ++n;
+}
+
+void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
+ double x3, double y3) {
+ if (n+3 > size) {
+ size += 16;
+ x = (double *)greallocn(x, size, sizeof(double));
+ y = (double *)greallocn(y, size, sizeof(double));
+ curve = (GBool *)greallocn(curve, size, sizeof(GBool));
+ }
+ x[n] = x1;
+ y[n] = y1;
+ x[n+1] = x2;
+ y[n+1] = y2;
+ x[n+2] = x3;
+ y[n+2] = y3;
+ curve[n] = curve[n+1] = gTrue;
+ curve[n+2] = gFalse;
+ n += 3;
+}
+
+void GfxSubpath::close() {
+ if (x[n-1] != x[0] || y[n-1] != y[0]) {
+ lineTo(x[0], y[0]);
+ }
+ closed = gTrue;
+}
+
+void GfxSubpath::offset(double dx, double dy) {
+ int i;
+
+ for (i = 0; i < n; ++i) {
+ x[i] += dx;
+ y[i] += dy;
+ }
+}
+
+GfxPath::GfxPath() {
+ justMoved = gFalse;
+ size = 16;
+ n = 0;
+ firstX = firstY = 0;
+ subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *));
+}
+
+GfxPath::~GfxPath() {
+ int i;
+
+ for (i = 0; i < n; ++i)
+ delete subpaths[i];
+ gfree(subpaths);
+}
+
+// Used for copy().
+GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
+ GfxSubpath **subpaths1, int n1, int size1) {
+ int i;
+
+ justMoved = justMoved1;
+ firstX = firstX1;
+ firstY = firstY1;
+ size = size1;
+ n = n1;
+ subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *));
+ for (i = 0; i < n; ++i)
+ subpaths[i] = subpaths1[i]->copy();
+}
+
+void GfxPath::moveTo(double x, double y) {
+ justMoved = gTrue;
+ firstX = x;
+ firstY = y;
+}
+
+void GfxPath::lineTo(double x, double y) {
+ if (justMoved) {
+ if (n >= size) {
+ size += 16;
+ subpaths = (GfxSubpath **)
+ greallocn(subpaths, size, sizeof(GfxSubpath *));
+ }
+ subpaths[n] = new GfxSubpath(firstX, firstY);
+ ++n;
+ justMoved = gFalse;
+ }
+ subpaths[n-1]->lineTo(x, y);
+}
+
+void GfxPath::curveTo(double x1, double y1, double x2, double y2,
+ double x3, double y3) {
+ if (justMoved) {
+ if (n >= size) {
+ size += 16;
+ subpaths = (GfxSubpath **)
+ greallocn(subpaths, size, sizeof(GfxSubpath *));
+ }
+ subpaths[n] = new GfxSubpath(firstX, firstY);
+ ++n;
+ justMoved = gFalse;
+ }
+ subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
+}
+
+void GfxPath::close() {
+ // this is necessary to handle the pathological case of
+ // moveto/closepath/clip, which defines an empty clipping region
+ if (justMoved) {
+ if (n >= size) {
+ size += 16;
+ subpaths = (GfxSubpath **)
+ greallocn(subpaths, size, sizeof(GfxSubpath *));
+ }
+ subpaths[n] = new GfxSubpath(firstX, firstY);
+ ++n;
+ justMoved = gFalse;
+ }
+ subpaths[n-1]->close();
+}
+
+void GfxPath::append(GfxPath *path) {
+ int i;
+
+ if (n + path->n > size) {
+ size = n + path->n;
+ subpaths = (GfxSubpath **)
+ greallocn(subpaths, size, sizeof(GfxSubpath *));
+ }
+ for (i = 0; i < path->n; ++i) {
+ subpaths[n++] = path->subpaths[i]->copy();
+ }
+ justMoved = gFalse;
+}
+
+void GfxPath::offset(double dx, double dy) {
+ int i;
+
+ for (i = 0; i < n; ++i) {
+ subpaths[i]->offset(dx, dy);
+ }
+}
+
+//------------------------------------------------------------------------
+// GfxState
+//------------------------------------------------------------------------
+
+GfxState::GfxState(double hDPIA, double vDPIA, PDFRectangle *pageBox,
+ int rotateA, GBool upsideDown) {
+ double kx, ky;
+
+ hDPI = hDPIA;
+ vDPI = vDPIA;
+ rotate = rotateA;
+ px1 = pageBox->x1;
+ py1 = pageBox->y1;
+ px2 = pageBox->x2;
+ py2 = pageBox->y2;
+ kx = hDPI / 72.0;
+ ky = vDPI / 72.0;
+ if (rotate == 90) {
+ ctm[0] = 0;
+ ctm[1] = upsideDown ? ky : -ky;
+ ctm[2] = kx;
+ ctm[3] = 0;
+ ctm[4] = -kx * py1;
+ ctm[5] = ky * (upsideDown ? -px1 : px2);
+ pageWidth = kx * (py2 - py1);
+ pageHeight = ky * (px2 - px1);
+ } else if (rotate == 180) {
+ ctm[0] = -kx;
+ ctm[1] = 0;
+ ctm[2] = 0;
+ ctm[3] = upsideDown ? ky : -ky;
+ ctm[4] = kx * px2;
+ ctm[5] = ky * (upsideDown ? -py1 : py2);
+ pageWidth = kx * (px2 - px1);
+ pageHeight = ky * (py2 - py1);
+ } else if (rotate == 270) {
+ ctm[0] = 0;
+ ctm[1] = upsideDown ? -ky : ky;
+ ctm[2] = -kx;
+ ctm[3] = 0;
+ ctm[4] = kx * py2;
+ ctm[5] = ky * (upsideDown ? px2 : -px1);
+ pageWidth = kx * (py2 - py1);
+ pageHeight = ky * (px2 - px1);
+ } else {
+ ctm[0] = kx;
+ ctm[1] = 0;
+ ctm[2] = 0;
+ ctm[3] = upsideDown ? -ky : ky;
+ ctm[4] = -kx * px1;
+ ctm[5] = ky * (upsideDown ? py2 : -py1);
+ pageWidth = kx * (px2 - px1);
+ pageHeight = ky * (py2 - py1);
+ }
+
+ fillColorSpace = new GfxDeviceGrayColorSpace();
+ strokeColorSpace = new GfxDeviceGrayColorSpace();
+ fillColor.c[0] = 0;
+ strokeColor.c[0] = 0;
+ fillPattern = NULL;
+ strokePattern = NULL;
+ blendMode = gfxBlendNormal;
+ fillOpacity = 1;
+ strokeOpacity = 1;
+ fillOverprint = gFalse;
+ strokeOverprint = gFalse;
+ transfer[0] = transfer[1] = transfer[2] = transfer[3] = NULL;
+
+ lineWidth = 1;
+ lineDash = NULL;
+ lineDashLength = 0;
+ lineDashStart = 0;
+ flatness = 1;
+ lineJoin = 0;
+ lineCap = 0;
+ miterLimit = 10;
+ strokeAdjust = gFalse;
+
+ font = NULL;
+ fontSize = 0;
+ textMat[0] = 1; textMat[1] = 0;
+ textMat[2] = 0; textMat[3] = 1;
+ textMat[4] = 0; textMat[5] = 0;
+ charSpace = 0;
+ wordSpace = 0;
+ horizScaling = 1;
+ leading = 0;
+ rise = 0;
+ render = 0;
+
+ path = new GfxPath();
+ curX = curY = 0;
+ lineX = lineY = 0;
+
+ clipXMin = 0;
+ clipYMin = 0;
+ clipXMax = pageWidth;
+ clipYMax = pageHeight;
+
+ saved = NULL;
+}
+
+GfxState::~GfxState() {
+ int i;
+
+ if (fillColorSpace) {
+ delete fillColorSpace;
+ }
+ if (strokeColorSpace) {
+ delete strokeColorSpace;
+ }
+ if (fillPattern) {
+ delete fillPattern;
+ }
+ if (strokePattern) {
+ delete strokePattern;
+ }
+ for (i = 0; i < 4; ++i) {
+ if (transfer[i]) {
+ delete transfer[i];
+ }
+ }
+ gfree(lineDash);
+ if (path) {
+ // this gets set to NULL by restore()
+ delete path;
+ }
+ if (saved) {
+ delete saved;
+ }
+}
+
+// Used for copy();
+GfxState::GfxState(GfxState *state) {
+ int i;
+
+ memcpy(this, state, sizeof(GfxState));
+ if (fillColorSpace) {
+ fillColorSpace = state->fillColorSpace->copy();
+ }
+ if (strokeColorSpace) {
+ strokeColorSpace = state->strokeColorSpace->copy();
+ }
+ if (fillPattern) {
+ fillPattern = state->fillPattern->copy();
+ }
+ if (strokePattern) {
+ strokePattern = state->strokePattern->copy();
+ }
+ for (i = 0; i < 4; ++i) {
+ if (transfer[i]) {
+ transfer[i] = state->transfer[i]->copy();
+ }
+ }
+ if (lineDashLength > 0) {
+ lineDash = (double *)gmallocn(lineDashLength, sizeof(double));
+ memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
+ }
+ saved = NULL;
+}
+
+void GfxState::setPath(GfxPath *pathA) {
+ delete path;
+ path = pathA;
+}
+
+void GfxState::getUserClipBBox(double *xMin, double *yMin,
+ double *xMax, double *yMax) {
+ double ictm[6];
+ double xMin1, yMin1, xMax1, yMax1, det, tx, ty;
+
+ // invert the CTM
+ det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
+ ictm[0] = ctm[3] * det;
+ ictm[1] = -ctm[1] * det;
+ ictm[2] = -ctm[2] * det;
+ ictm[3] = ctm[0] * det;
+ ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
+ ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
+
+ // transform all four corners of the clip bbox; find the min and max
+ // x and y values
+ xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4];
+ yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5];
+ tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4];
+ ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5];
+ if (tx < xMin1) {
+ xMin1 = tx;
+ } else if (tx > xMax1) {
+ xMax1 = tx;
+ }
+ if (ty < yMin1) {
+ yMin1 = ty;
+ } else if (ty > yMax1) {
+ yMax1 = ty;
+ }
+ tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4];
+ ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5];
+ if (tx < xMin1) {
+ xMin1 = tx;
+ } else if (tx > xMax1) {
+ xMax1 = tx;
+ }
+ if (ty < yMin1) {
+ yMin1 = ty;
+ } else if (ty > yMax1) {
+ yMax1 = ty;
+ }
+ tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4];
+ ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5];
+ if (tx < xMin1) {
+ xMin1 = tx;
+ } else if (tx > xMax1) {
+ xMax1 = tx;
+ }
+ if (ty < yMin1) {
+ yMin1 = ty;
+ } else if (ty > yMax1) {
+ yMax1 = ty;
+ }
+
+ *xMin = xMin1;
+ *yMin = yMin1;
+ *xMax = xMax1;
+ *yMax = yMax1;
+}
+
+double GfxState::transformWidth(double w) {
+ double x, y;
+
+ x = ctm[0] + ctm[2];
+ y = ctm[1] + ctm[3];
+ return w * sqrt(0.5 * (x * x + y * y));
+}
+
+double GfxState::getTransformedFontSize() {
+ double x1, y1, x2, y2;
+
+ x1 = textMat[2] * fontSize;
+ y1 = textMat[3] * fontSize;
+ x2 = ctm[0] * x1 + ctm[2] * y1;
+ y2 = ctm[1] * x1 + ctm[3] * y1;
+ return sqrt(x2 * x2 + y2 * y2);
+}
+
+void GfxState::getFontTransMat(double *m11, double *m12,
+ double *m21, double *m22) {
+ *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
+ *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
+ *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
+ *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
+}
+
+void GfxState::setCTM(double a, double b, double c,
+ double d, double e, double f) {
+ int i;
+
+ ctm[0] = a;
+ ctm[1] = b;
+ ctm[2] = c;
+ ctm[3] = d;
+ ctm[4] = e;
+ ctm[5] = f;
+
+ // avoid FP exceptions on badly messed up PDF files
+ for (i = 0; i < 6; ++i) {
+ if (ctm[i] > 1e10) {
+ ctm[i] = 1e10;
+ } else if (ctm[i] < -1e10) {
+ ctm[i] = -1e10;
+ }
+ }
+}
+
+void GfxState::concatCTM(double a, double b, double c,
+ double d, double e, double f) {
+ double a1 = ctm[0];
+ double b1 = ctm[1];
+ double c1 = ctm[2];
+ double d1 = ctm[3];
+ int i;
+
+ ctm[0] = a * a1 + b * c1;
+ ctm[1] = a * b1 + b * d1;
+ ctm[2] = c * a1 + d * c1;
+ ctm[3] = c * b1 + d * d1;
+ ctm[4] = e * a1 + f * c1 + ctm[4];
+ ctm[5] = e * b1 + f * d1 + ctm[5];
+
+ // avoid FP exceptions on badly messed up PDF files
+ for (i = 0; i < 6; ++i) {
+ if (ctm[i] > 1e10) {
+ ctm[i] = 1e10;
+ } else if (ctm[i] < -1e10) {
+ ctm[i] = -1e10;
+ }
+ }
+}
+
+void GfxState::shiftCTM(double tx, double ty) {
+ ctm[4] += tx;
+ ctm[5] += ty;
+ clipXMin += tx;
+ clipYMin += ty;
+ clipXMax += tx;
+ clipYMax += ty;
+}
+
+void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
+ if (fillColorSpace) {
+ delete fillColorSpace;
+ }
+ fillColorSpace = colorSpace;
+}
+
+void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
+ if (strokeColorSpace) {
+ delete strokeColorSpace;
+ }
+ strokeColorSpace = colorSpace;
+}
+
+void GfxState::setFillPattern(GfxPattern *pattern) {
+ if (fillPattern) {
+ delete fillPattern;
+ }
+ fillPattern = pattern;
+}
+
+void GfxState::setStrokePattern(GfxPattern *pattern) {
+ if (strokePattern) {
+ delete strokePattern;
+ }
+ strokePattern = pattern;
+}
+
+void GfxState::setTransfer(Function **funcs) {
+ int i;
+
+ for (i = 0; i < 4; ++i) {
+ if (transfer[i]) {
+ delete transfer[i];
+ }
+ transfer[i] = funcs[i];
+ }
+}
+
+void GfxState::setLineDash(double *dash, int length, double start) {
+ if (lineDash)
+ gfree(lineDash);
+ lineDash = dash;
+ lineDashLength = length;
+ lineDashStart = start;
+}
+
+void GfxState::clearPath() {
+ delete path;
+ path = new GfxPath();
+}
+
+void GfxState::clip() {
+ double xMin, yMin, xMax, yMax, x, y;
+ GfxSubpath *subpath;
+ int i, j;
+
+ xMin = xMax = yMin = yMax = 0; // make gcc happy
+ for (i = 0; i < path->getNumSubpaths(); ++i) {
+ subpath = path->getSubpath(i);
+ for (j = 0; j < subpath->getNumPoints(); ++j) {
+ transform(subpath->getX(j), subpath->getY(j), &x, &y);
+ if (i == 0 && j == 0) {
+ xMin = xMax = x;
+ yMin = yMax = y;
+ } else {
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ }
+ }
+ }
+ if (xMin > clipXMin) {
+ clipXMin = xMin;
+ }
+ if (yMin > clipYMin) {
+ clipYMin = yMin;
+ }
+ if (xMax < clipXMax) {
+ clipXMax = xMax;
+ }
+ if (yMax < clipYMax) {
+ clipYMax = yMax;
+ }
+}
+
+void GfxState::clipToStrokePath() {
+ double xMin, yMin, xMax, yMax, x, y, t0, t1;
+ GfxSubpath *subpath;
+ int i, j;
+
+ xMin = xMax = yMin = yMax = 0; // make gcc happy
+ for (i = 0; i < path->getNumSubpaths(); ++i) {
+ subpath = path->getSubpath(i);
+ for (j = 0; j < subpath->getNumPoints(); ++j) {
+ transform(subpath->getX(j), subpath->getY(j), &x, &y);
+ if (i == 0 && j == 0) {
+ xMin = xMax = x;
+ yMin = yMax = y;
+ } else {
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ }
+ }
+ }
+
+ // allow for the line width
+ //~ miter joins can extend farther than this
+ t0 = fabs(ctm[0]);
+ t1 = fabs(ctm[2]);
+ if (t0 > t1) {
+ xMin -= 0.5 * lineWidth * t0;
+ xMax += 0.5 * lineWidth * t0;
+ } else {
+ xMin -= 0.5 * lineWidth * t1;
+ xMax += 0.5 * lineWidth * t1;
+ }
+ t0 = fabs(ctm[0]);
+ t1 = fabs(ctm[3]);
+ if (t0 > t1) {
+ yMin -= 0.5 * lineWidth * t0;
+ yMax += 0.5 * lineWidth * t0;
+ } else {
+ yMin -= 0.5 * lineWidth * t1;
+ yMax += 0.5 * lineWidth * t1;
+ }
+
+ if (xMin > clipXMin) {
+ clipXMin = xMin;
+ }
+ if (yMin > clipYMin) {
+ clipYMin = yMin;
+ }
+ if (xMax < clipXMax) {
+ clipXMax = xMax;
+ }
+ if (yMax < clipYMax) {
+ clipYMax = yMax;
+ }
+}
+
+void GfxState::textShift(double tx, double ty) {
+ double dx, dy;
+
+ textTransformDelta(tx, ty, &dx, &dy);
+ curX += dx;
+ curY += dy;
+}
+
+void GfxState::shift(double dx, double dy) {
+ curX += dx;
+ curY += dy;
+}
+
+GfxState *GfxState::save() {
+ GfxState *newState;
+
+ newState = copy();
+ newState->saved = this;
+ return newState;
+}
+
+GfxState *GfxState::restore() {
+ GfxState *oldState;
+
+ if (saved) {
+ oldState = saved;
+
+ // these attributes aren't saved/restored by the q/Q operators
+ oldState->path = path;
+ oldState->curX = curX;
+ oldState->curY = curY;
+ oldState->lineX = lineX;
+ oldState->lineY = lineY;
+
+ path = NULL;
+ saved = NULL;
+ delete this;
+
+ } else {
+ oldState = this;
+ }
+
+ return oldState;
+}
+
+GBool GfxState::parseBlendMode(Object *obj, GfxBlendMode *mode) {
+ Object obj2;
+ int i, j;
+
+ if (obj->isName()) {
+ for (i = 0; i < nGfxBlendModeNames; ++i) {
+ if (!strcmp(obj->getName(), gfxBlendModeNames[i].name)) {
+ *mode = gfxBlendModeNames[i].mode;
+ return gTrue;
+ }
+ }
+ return gFalse;
+ } else if (obj->isArray()) {
+ for (i = 0; i < obj->arrayGetLength(); ++i) {
+ obj->arrayGet(i, &obj2);
+ if (!obj2.isName()) {
+ obj2.free();
+ return gFalse;
+ }
+ for (j = 0; j < nGfxBlendModeNames; ++j) {
+ if (!strcmp(obj2.getName(), gfxBlendModeNames[j].name)) {
+ obj2.free();
+ *mode = gfxBlendModeNames[j].mode;
+ return gTrue;
+ }
+ }
+ obj2.free();
+ }
+ *mode = gfxBlendNormal;
+ return gTrue;
+ } else {
+ return gFalse;
+ }
+}
diff --git a/kpdf/xpdf/xpdf/GfxState.h b/kpdf/xpdf/xpdf/GfxState.h
new file mode 100644
index 00000000..f85643dc
--- /dev/null
+++ b/kpdf/xpdf/xpdf/GfxState.h
@@ -0,0 +1,1244 @@
+//========================================================================
+//
+// GfxState.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef GFXSTATE_H
+#define GFXSTATE_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "Object.h"
+#include "Function.h"
+
+class Array;
+class GfxFont;
+class PDFRectangle;
+class GfxShading;
+
+//------------------------------------------------------------------------
+// GfxBlendMode
+//------------------------------------------------------------------------
+
+enum GfxBlendMode {
+ gfxBlendNormal,
+ gfxBlendMultiply,
+ gfxBlendScreen,
+ gfxBlendOverlay,
+ gfxBlendDarken,
+ gfxBlendLighten,
+ gfxBlendColorDodge,
+ gfxBlendColorBurn,
+ gfxBlendHardLight,
+ gfxBlendSoftLight,
+ gfxBlendDifference,
+ gfxBlendExclusion,
+ gfxBlendHue,
+ gfxBlendSaturation,
+ gfxBlendColor,
+ gfxBlendLuminosity
+};
+
+//------------------------------------------------------------------------
+// GfxColorComp
+//------------------------------------------------------------------------
+
+// 16.16 fixed point color component
+typedef int GfxColorComp;
+
+#define gfxColorComp1 0x10000
+
+static inline GfxColorComp dblToCol(double x) {
+ return (GfxColorComp)(x * gfxColorComp1);
+}
+
+static inline double colToDbl(GfxColorComp x) {
+ return (double)x / (double)gfxColorComp1;
+}
+
+static inline GfxColorComp byteToCol(Guchar x) {
+ // (x / 255) << 16 = (0.0000000100000001... * x) << 16
+ // = ((x << 8) + (x) + (x >> 8) + ...) << 16
+ // = (x << 8) + (x) + (x >> 7)
+ // [for rounding]
+ return (GfxColorComp)((x << 8) + x + (x >> 7));
+}
+
+static inline Guchar colToByte(GfxColorComp x) {
+ // 255 * x + 0.5 = 256 * x - x + 0x8000
+ return (Guchar)(((x << 8) - x + 0x8000) >> 16);
+}
+
+//------------------------------------------------------------------------
+// GfxColor
+//------------------------------------------------------------------------
+
+#define gfxColorMaxComps funcMaxOutputs
+
+struct GfxColor {
+ GfxColorComp c[gfxColorMaxComps];
+};
+
+//------------------------------------------------------------------------
+// GfxGray
+//------------------------------------------------------------------------
+
+typedef GfxColorComp GfxGray;
+
+//------------------------------------------------------------------------
+// GfxRGB
+//------------------------------------------------------------------------
+
+struct GfxRGB {
+ GfxColorComp r, g, b;
+};
+
+//------------------------------------------------------------------------
+// GfxCMYK
+//------------------------------------------------------------------------
+
+struct GfxCMYK {
+ GfxColorComp c, m, y, k;
+};
+
+//------------------------------------------------------------------------
+// GfxColorSpace
+//------------------------------------------------------------------------
+
+// NB: The nGfxColorSpaceModes constant and the gfxColorSpaceModeNames
+// array defined in GfxState.cc must match this enum.
+enum GfxColorSpaceMode {
+ csDeviceGray,
+ csCalGray,
+ csDeviceRGB,
+ csCalRGB,
+ csDeviceCMYK,
+ csLab,
+ csICCBased,
+ csIndexed,
+ csSeparation,
+ csDeviceN,
+ csPattern
+};
+
+class GfxColorSpace {
+public:
+
+ GfxColorSpace();
+ virtual ~GfxColorSpace();
+ virtual GfxColorSpace *copy() = 0;
+ virtual GfxColorSpaceMode getMode() = 0;
+
+ // Construct a color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(Object *csObj);
+
+ // Convert to gray, RGB, or CMYK.
+ virtual void getGray(GfxColor *color, GfxGray *gray) = 0;
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb) = 0;
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk) = 0;
+
+ // Return the number of color components.
+ virtual int getNComps() = 0;
+
+ // Get this color space's default color.
+ virtual void getDefaultColor(GfxColor *color) = 0;
+
+ // Return the default ranges for each component, assuming an image
+ // with a max pixel value of <maxImgPixel>.
+ virtual void getDefaultRanges(double *decodeLow, double *decodeRange,
+ int maxImgPixel);
+
+ // Returns true if painting operations in this color space never
+ // mark the page (e.g., the "None" colorant).
+ virtual GBool isNonMarking() { return gFalse; }
+
+ // Return the number of color space modes
+ static int getNumColorSpaceModes();
+
+ // Return the name of the <idx>th color space mode.
+ static char *getColorSpaceModeName(int idx);
+
+private:
+};
+
+//------------------------------------------------------------------------
+// GfxDeviceGrayColorSpace
+//------------------------------------------------------------------------
+
+class GfxDeviceGrayColorSpace: public GfxColorSpace {
+public:
+
+ GfxDeviceGrayColorSpace();
+ virtual ~GfxDeviceGrayColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csDeviceGray; }
+
+ virtual void getGray(GfxColor *color, GfxGray *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+
+ virtual int getNComps() { return 1; }
+ virtual void getDefaultColor(GfxColor *color);
+
+private:
+};
+
+//------------------------------------------------------------------------
+// GfxCalGrayColorSpace
+//------------------------------------------------------------------------
+
+class GfxCalGrayColorSpace: public GfxColorSpace {
+public:
+
+ GfxCalGrayColorSpace();
+ virtual ~GfxCalGrayColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csCalGray; }
+
+ // Construct a CalGray color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(Array *arr);
+
+ virtual void getGray(GfxColor *color, GfxGray *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+
+ virtual int getNComps() { return 1; }
+ virtual void getDefaultColor(GfxColor *color);
+
+ // CalGray-specific access.
+ double getWhiteX() { return whiteX; }
+ double getWhiteY() { return whiteY; }
+ double getWhiteZ() { return whiteZ; }
+ double getBlackX() { return blackX; }
+ double getBlackY() { return blackY; }
+ double getBlackZ() { return blackZ; }
+ double getGamma() { return gamma; }
+
+private:
+
+ double whiteX, whiteY, whiteZ; // white point
+ double blackX, blackY, blackZ; // black point
+ double gamma; // gamma value
+};
+
+//------------------------------------------------------------------------
+// GfxDeviceRGBColorSpace
+//------------------------------------------------------------------------
+
+class GfxDeviceRGBColorSpace: public GfxColorSpace {
+public:
+
+ GfxDeviceRGBColorSpace();
+ virtual ~GfxDeviceRGBColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csDeviceRGB; }
+
+ virtual void getGray(GfxColor *color, GfxGray *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+
+ virtual int getNComps() { return 3; }
+ virtual void getDefaultColor(GfxColor *color);
+
+private:
+};
+
+//------------------------------------------------------------------------
+// GfxCalRGBColorSpace
+//------------------------------------------------------------------------
+
+class GfxCalRGBColorSpace: public GfxColorSpace {
+public:
+
+ GfxCalRGBColorSpace();
+ virtual ~GfxCalRGBColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csCalRGB; }
+
+ // Construct a CalRGB color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(Array *arr);
+
+ virtual void getGray(GfxColor *color, GfxGray *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+
+ virtual int getNComps() { return 3; }
+ virtual void getDefaultColor(GfxColor *color);
+
+ // CalRGB-specific access.
+ double getWhiteX() { return whiteX; }
+ double getWhiteY() { return whiteY; }
+ double getWhiteZ() { return whiteZ; }
+ double getBlackX() { return blackX; }
+ double getBlackY() { return blackY; }
+ double getBlackZ() { return blackZ; }
+ double getGammaR() { return gammaR; }
+ double getGammaG() { return gammaG; }
+ double getGammaB() { return gammaB; }
+ double *getMatrix() { return mat; }
+
+private:
+
+ double whiteX, whiteY, whiteZ; // white point
+ double blackX, blackY, blackZ; // black point
+ double gammaR, gammaG, gammaB; // gamma values
+ double mat[9]; // ABC -> XYZ transform matrix
+};
+
+//------------------------------------------------------------------------
+// GfxDeviceCMYKColorSpace
+//------------------------------------------------------------------------
+
+class GfxDeviceCMYKColorSpace: public GfxColorSpace {
+public:
+
+ GfxDeviceCMYKColorSpace();
+ virtual ~GfxDeviceCMYKColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csDeviceCMYK; }
+
+ virtual void getGray(GfxColor *color, GfxGray *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+
+ virtual int getNComps() { return 4; }
+ virtual void getDefaultColor(GfxColor *color);
+
+private:
+};
+
+//------------------------------------------------------------------------
+// GfxLabColorSpace
+//------------------------------------------------------------------------
+
+class GfxLabColorSpace: public GfxColorSpace {
+public:
+
+ GfxLabColorSpace();
+ virtual ~GfxLabColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csLab; }
+
+ // Construct a Lab color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(Array *arr);
+
+ virtual void getGray(GfxColor *color, GfxGray *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+
+ virtual int getNComps() { return 3; }
+ virtual void getDefaultColor(GfxColor *color);
+
+ virtual void getDefaultRanges(double *decodeLow, double *decodeRange,
+ int maxImgPixel);
+
+ // Lab-specific access.
+ double getWhiteX() { return whiteX; }
+ double getWhiteY() { return whiteY; }
+ double getWhiteZ() { return whiteZ; }
+ double getBlackX() { return blackX; }
+ double getBlackY() { return blackY; }
+ double getBlackZ() { return blackZ; }
+ double getAMin() { return aMin; }
+ double getAMax() { return aMax; }
+ double getBMin() { return bMin; }
+ double getBMax() { return bMax; }
+
+private:
+
+ double whiteX, whiteY, whiteZ; // white point
+ double blackX, blackY, blackZ; // black point
+ double aMin, aMax, bMin, bMax; // range for the a and b components
+ double kr, kg, kb; // gamut mapping mulitpliers
+};
+
+//------------------------------------------------------------------------
+// GfxICCBasedColorSpace
+//------------------------------------------------------------------------
+
+class GfxICCBasedColorSpace: public GfxColorSpace {
+public:
+
+ GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
+ Ref *iccProfileStreamA);
+ virtual ~GfxICCBasedColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csICCBased; }
+
+ // Construct an ICCBased color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(Array *arr);
+
+ virtual void getGray(GfxColor *color, GfxGray *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+
+ virtual int getNComps() { return nComps; }
+ virtual void getDefaultColor(GfxColor *color);
+
+ virtual void getDefaultRanges(double *decodeLow, double *decodeRange,
+ int maxImgPixel);
+
+ // ICCBased-specific access.
+ GfxColorSpace *getAlt() { return alt; }
+
+private:
+
+ int nComps; // number of color components (1, 3, or 4)
+ GfxColorSpace *alt; // alternate color space
+ double rangeMin[4]; // min values for each component
+ double rangeMax[4]; // max values for each component
+ Ref iccProfileStream; // the ICC profile
+};
+
+//------------------------------------------------------------------------
+// GfxIndexedColorSpace
+//------------------------------------------------------------------------
+
+class GfxIndexedColorSpace: public GfxColorSpace {
+public:
+
+ GfxIndexedColorSpace(GfxColorSpace *baseA, int indexHighA);
+ virtual ~GfxIndexedColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csIndexed; }
+
+ // Construct a Lab color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(Array *arr);
+
+ virtual void getGray(GfxColor *color, GfxGray *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+
+ virtual int getNComps() { return 1; }
+ virtual void getDefaultColor(GfxColor *color);
+
+ virtual void getDefaultRanges(double *decodeLow, double *decodeRange,
+ int maxImgPixel);
+
+ // Indexed-specific access.
+ GfxColorSpace *getBase() { return base; }
+ int getIndexHigh() { return indexHigh; }
+ Guchar *getLookup() { return lookup; }
+ GfxColor *mapColorToBase(GfxColor *color, GfxColor *baseColor);
+
+private:
+
+ GfxColorSpace *base; // base color space
+ int indexHigh; // max pixel value
+ Guchar *lookup; // lookup table
+};
+
+//------------------------------------------------------------------------
+// GfxSeparationColorSpace
+//------------------------------------------------------------------------
+
+class GfxSeparationColorSpace: public GfxColorSpace {
+public:
+
+ GfxSeparationColorSpace(GString *nameA, GfxColorSpace *altA,
+ Function *funcA);
+ virtual ~GfxSeparationColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csSeparation; }
+
+ // Construct a Separation color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(Array *arr);
+
+ virtual void getGray(GfxColor *color, GfxGray *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+
+ virtual int getNComps() { return 1; }
+ virtual void getDefaultColor(GfxColor *color);
+
+ virtual GBool isNonMarking() { return nonMarking; }
+
+ // Separation-specific access.
+ GString *getName() { return name; }
+ GfxColorSpace *getAlt() { return alt; }
+ Function *getFunc() { return func; }
+
+private:
+
+ GString *name; // colorant name
+ GfxColorSpace *alt; // alternate color space
+ Function *func; // tint transform (into alternate color space)
+ GBool nonMarking;
+};
+
+//------------------------------------------------------------------------
+// GfxDeviceNColorSpace
+//------------------------------------------------------------------------
+
+class GfxDeviceNColorSpace: public GfxColorSpace {
+public:
+
+ GfxDeviceNColorSpace(int nCompsA, GfxColorSpace *alt, Function *func);
+ virtual ~GfxDeviceNColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csDeviceN; }
+
+ // Construct a DeviceN color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(Array *arr);
+
+ virtual void getGray(GfxColor *color, GfxGray *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+
+ virtual int getNComps() { return nComps; }
+ virtual void getDefaultColor(GfxColor *color);
+
+ virtual GBool isNonMarking() { return nonMarking; }
+
+ // DeviceN-specific access.
+ GString *getColorantName(int i) { return names[i]; }
+ GfxColorSpace *getAlt() { return alt; }
+ Function *getTintTransformFunc() { return func; }
+
+private:
+
+ int nComps; // number of components
+ GString // colorant names
+ *names[gfxColorMaxComps];
+ GfxColorSpace *alt; // alternate color space
+ Function *func; // tint transform (into alternate color space)
+ GBool nonMarking;
+};
+
+//------------------------------------------------------------------------
+// GfxPatternColorSpace
+//------------------------------------------------------------------------
+
+class GfxPatternColorSpace: public GfxColorSpace {
+public:
+
+ GfxPatternColorSpace(GfxColorSpace *underA);
+ virtual ~GfxPatternColorSpace();
+ virtual GfxColorSpace *copy();
+ virtual GfxColorSpaceMode getMode() { return csPattern; }
+
+ // Construct a Pattern color space. Returns NULL if unsuccessful.
+ static GfxColorSpace *parse(Array *arr);
+
+ virtual void getGray(GfxColor *color, GfxGray *gray);
+ virtual void getRGB(GfxColor *color, GfxRGB *rgb);
+ virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk);
+
+ virtual int getNComps() { return 0; }
+ virtual void getDefaultColor(GfxColor *color);
+
+ // Pattern-specific access.
+ GfxColorSpace *getUnder() { return under; }
+
+private:
+
+ GfxColorSpace *under; // underlying color space (for uncolored
+ // patterns)
+};
+
+//------------------------------------------------------------------------
+// GfxPattern
+//------------------------------------------------------------------------
+
+class GfxPattern {
+public:
+
+ GfxPattern(int typeA);
+ virtual ~GfxPattern();
+
+ static GfxPattern *parse(Object *obj);
+
+ virtual GfxPattern *copy() = 0;
+
+ int getType() { return type; }
+
+private:
+
+ int type;
+};
+
+//------------------------------------------------------------------------
+// GfxTilingPattern
+//------------------------------------------------------------------------
+
+class GfxTilingPattern: public GfxPattern {
+public:
+
+ static GfxTilingPattern *parse(Object *patObj);
+ virtual ~GfxTilingPattern();
+
+ virtual GfxPattern *copy();
+
+ int getPaintType() { return paintType; }
+ int getTilingType() { return tilingType; }
+ double *getBBox() { return bbox; }
+ double getXStep() { return xStep; }
+ double getYStep() { return yStep; }
+ Dict *getResDict()
+ { return resDict.isDict() ? resDict.getDict() : (Dict *)NULL; }
+ double *getMatrix() { return matrix; }
+ Object *getContentStream() { return &contentStream; }
+
+private:
+
+ GfxTilingPattern(int paintTypeA, int tilingTypeA,
+ double *bboxA, double xStepA, double yStepA,
+ Object *resDictA, double *matrixA,
+ Object *contentStreamA);
+
+ int paintType;
+ int tilingType;
+ double bbox[4];
+ double xStep, yStep;
+ Object resDict;
+ double matrix[6];
+ Object contentStream;
+};
+
+//------------------------------------------------------------------------
+// GfxShadingPattern
+//------------------------------------------------------------------------
+
+class GfxShadingPattern: public GfxPattern {
+public:
+
+ static GfxShadingPattern *parse(Object *patObj);
+ virtual ~GfxShadingPattern();
+
+ virtual GfxPattern *copy();
+
+ GfxShading *getShading() { return shading; }
+ double *getMatrix() { return matrix; }
+
+private:
+
+ GfxShadingPattern(GfxShading *shadingA, double *matrixA);
+
+ GfxShading *shading;
+ double matrix[6];
+};
+
+//------------------------------------------------------------------------
+// GfxShading
+//------------------------------------------------------------------------
+
+class GfxShading {
+public:
+
+ GfxShading(int typeA);
+ GfxShading(GfxShading *shading);
+ virtual ~GfxShading();
+
+ static GfxShading *parse(Object *obj);
+
+ virtual GfxShading *copy() = 0;
+
+ int getType() { return type; }
+ GfxColorSpace *getColorSpace() { return colorSpace; }
+ GfxColor *getBackground() { return &background; }
+ GBool getHasBackground() { return hasBackground; }
+ void getBBox(double *xMinA, double *yMinA, double *xMaxA, double *yMaxA)
+ { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; }
+ GBool getHasBBox() { return hasBBox; }
+
+protected:
+
+ GBool init(Dict *dict);
+
+ int type;
+ GfxColorSpace *colorSpace;
+ GfxColor background;
+ GBool hasBackground;
+ double xMin, yMin, xMax, yMax;
+ GBool hasBBox;
+};
+
+//------------------------------------------------------------------------
+// GfxFunctionShading
+//------------------------------------------------------------------------
+
+class GfxFunctionShading: public GfxShading {
+public:
+
+ GfxFunctionShading(double x0A, double y0A,
+ double x1A, double y1A,
+ double *matrixA,
+ Function **funcsA, int nFuncsA);
+ GfxFunctionShading(GfxFunctionShading *shading);
+ virtual ~GfxFunctionShading();
+
+ static GfxFunctionShading *parse(Dict *dict);
+
+ virtual GfxShading *copy();
+
+ void getDomain(double *x0A, double *y0A, double *x1A, double *y1A)
+ { *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; }
+ double *getMatrix() { return matrix; }
+ int getNFuncs() { return nFuncs; }
+ Function *getFunc(int i) { return funcs[i]; }
+ void getColor(double x, double y, GfxColor *color);
+
+private:
+
+ double x0, y0, x1, y1;
+ double matrix[6];
+ Function *funcs[gfxColorMaxComps];
+ int nFuncs;
+};
+
+//------------------------------------------------------------------------
+// GfxAxialShading
+//------------------------------------------------------------------------
+
+class GfxAxialShading: public GfxShading {
+public:
+
+ GfxAxialShading(double x0A, double y0A,
+ double x1A, double y1A,
+ double t0A, double t1A,
+ Function **funcsA, int nFuncsA,
+ GBool extend0A, GBool extend1A);
+ GfxAxialShading(GfxAxialShading *shading);
+ virtual ~GfxAxialShading();
+
+ static GfxAxialShading *parse(Dict *dict);
+
+ virtual GfxShading *copy();
+
+ void getCoords(double *x0A, double *y0A, double *x1A, double *y1A)
+ { *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; }
+ double getDomain0() { return t0; }
+ double getDomain1() { return t1; }
+ GBool getExtend0() { return extend0; }
+ GBool getExtend1() { return extend1; }
+ int getNFuncs() { return nFuncs; }
+ Function *getFunc(int i) { return funcs[i]; }
+ void getColor(double t, GfxColor *color);
+
+private:
+
+ double x0, y0, x1, y1;
+ double t0, t1;
+ Function *funcs[gfxColorMaxComps];
+ int nFuncs;
+ GBool extend0, extend1;
+};
+
+//------------------------------------------------------------------------
+// GfxRadialShading
+//------------------------------------------------------------------------
+
+class GfxRadialShading: public GfxShading {
+public:
+
+ GfxRadialShading(double x0A, double y0A, double r0A,
+ double x1A, double y1A, double r1A,
+ double t0A, double t1A,
+ Function **funcsA, int nFuncsA,
+ GBool extend0A, GBool extend1A);
+ GfxRadialShading(GfxRadialShading *shading);
+ virtual ~GfxRadialShading();
+
+ static GfxRadialShading *parse(Dict *dict);
+
+ virtual GfxShading *copy();
+
+ void getCoords(double *x0A, double *y0A, double *r0A,
+ double *x1A, double *y1A, double *r1A)
+ { *x0A = x0; *y0A = y0; *r0A = r0; *x1A = x1; *y1A = y1; *r1A = r1; }
+ double getDomain0() { return t0; }
+ double getDomain1() { return t1; }
+ GBool getExtend0() { return extend0; }
+ GBool getExtend1() { return extend1; }
+ int getNFuncs() { return nFuncs; }
+ Function *getFunc(int i) { return funcs[i]; }
+ void getColor(double t, GfxColor *color);
+
+private:
+
+ double x0, y0, r0, x1, y1, r1;
+ double t0, t1;
+ Function *funcs[gfxColorMaxComps];
+ int nFuncs;
+ GBool extend0, extend1;
+};
+
+//------------------------------------------------------------------------
+// GfxGouraudTriangleShading
+//------------------------------------------------------------------------
+
+struct GfxGouraudVertex {
+ double x, y;
+ GfxColor color;
+};
+
+class GfxGouraudTriangleShading: public GfxShading {
+public:
+
+ GfxGouraudTriangleShading(int typeA,
+ GfxGouraudVertex *verticesA, int nVerticesA,
+ int (*trianglesA)[3], int nTrianglesA,
+ Function **funcsA, int nFuncsA);
+ GfxGouraudTriangleShading(GfxGouraudTriangleShading *shading);
+ virtual ~GfxGouraudTriangleShading();
+
+ static GfxGouraudTriangleShading *parse(int typeA, Dict *dict, Stream *str);
+
+ virtual GfxShading *copy();
+
+ int getNTriangles() { return nTriangles; }
+ void getTriangle(int i, double *x0, double *y0, GfxColor *color0,
+ double *x1, double *y1, GfxColor *color1,
+ double *x2, double *y2, GfxColor *color2);
+
+private:
+
+ GfxGouraudVertex *vertices;
+ int nVertices;
+ int (*triangles)[3];
+ int nTriangles;
+ Function *funcs[gfxColorMaxComps];
+ int nFuncs;
+};
+
+//------------------------------------------------------------------------
+// GfxPatchMeshShading
+//------------------------------------------------------------------------
+
+struct GfxPatch {
+ double x[4][4];
+ double y[4][4];
+ GfxColor color[2][2];
+};
+
+class GfxPatchMeshShading: public GfxShading {
+public:
+
+ GfxPatchMeshShading(int typeA, GfxPatch *patchesA, int nPatchesA,
+ Function **funcsA, int nFuncsA);
+ GfxPatchMeshShading(GfxPatchMeshShading *shading);
+ virtual ~GfxPatchMeshShading();
+
+ static GfxPatchMeshShading *parse(int typeA, Dict *dict, Stream *str);
+
+ virtual GfxShading *copy();
+
+ int getNPatches() { return nPatches; }
+ GfxPatch *getPatch(int i) { return &patches[i]; }
+
+private:
+
+ GfxPatch *patches;
+ int nPatches;
+ Function *funcs[gfxColorMaxComps];
+ int nFuncs;
+};
+
+//------------------------------------------------------------------------
+// GfxImageColorMap
+//------------------------------------------------------------------------
+
+class GfxImageColorMap {
+public:
+
+ // Constructor.
+ GfxImageColorMap(int bitsA, Object *decode, GfxColorSpace *colorSpaceA);
+
+ // Destructor.
+ ~GfxImageColorMap();
+
+ // Return a copy of this color map.
+ GfxImageColorMap *copy() { return new GfxImageColorMap(this); }
+
+ // Is color map valid?
+ GBool isOk() { return ok; }
+
+ // Get the color space.
+ GfxColorSpace *getColorSpace() { return colorSpace; }
+
+ // Get stream decoding info.
+ int getNumPixelComps() { return nComps; }
+ int getBits() { return bits; }
+
+ // Get decode table.
+ double getDecodeLow(int i) { return decodeLow[i]; }
+ double getDecodeHigh(int i) { return decodeLow[i] + decodeRange[i]; }
+
+ // Convert an image pixel to a color.
+ void getGray(Guchar *x, GfxGray *gray);
+ void getRGB(Guchar *x, GfxRGB *rgb);
+ void getCMYK(Guchar *x, GfxCMYK *cmyk);
+ void getColor(Guchar *x, GfxColor *color);
+
+private:
+
+ GfxImageColorMap(GfxImageColorMap *colorMap);
+
+ GfxColorSpace *colorSpace; // the image color space
+ int bits; // bits per component
+ int nComps; // number of components in a pixel
+ GfxColorSpace *colorSpace2; // secondary color space
+ int nComps2; // number of components in colorSpace2
+ GfxColorComp * // lookup table
+ lookup[gfxColorMaxComps];
+ double // minimum values for each component
+ decodeLow[gfxColorMaxComps];
+ double // max - min value for each component
+ decodeRange[gfxColorMaxComps];
+ GBool ok;
+};
+
+//------------------------------------------------------------------------
+// GfxSubpath and GfxPath
+//------------------------------------------------------------------------
+
+class GfxSubpath {
+public:
+
+ // Constructor.
+ GfxSubpath(double x1, double y1);
+
+ // Destructor.
+ ~GfxSubpath();
+
+ // Copy.
+ GfxSubpath *copy() { return new GfxSubpath(this); }
+
+ // Get points.
+ int getNumPoints() { return n; }
+ double getX(int i) { return x[i]; }
+ double getY(int i) { return y[i]; }
+ GBool getCurve(int i) { return curve[i]; }
+
+ // Get last point.
+ double getLastX() { return x[n-1]; }
+ double getLastY() { return y[n-1]; }
+
+ // Add a line segment.
+ void lineTo(double x1, double y1);
+
+ // Add a Bezier curve.
+ void curveTo(double x1, double y1, double x2, double y2,
+ double x3, double y3);
+
+ // Close the subpath.
+ void close();
+ GBool isClosed() { return closed; }
+
+ // Add (<dx>, <dy>) to each point in the subpath.
+ void offset(double dx, double dy);
+
+private:
+
+ double *x, *y; // points
+ GBool *curve; // curve[i] => point i is a control point
+ // for a Bezier curve
+ int n; // number of points
+ int size; // size of x/y arrays
+ GBool closed; // set if path is closed
+
+ GfxSubpath(GfxSubpath *subpath);
+};
+
+class GfxPath {
+public:
+
+ // Constructor.
+ GfxPath();
+
+ // Destructor.
+ ~GfxPath();
+
+ // Copy.
+ GfxPath *copy()
+ { return new GfxPath(justMoved, firstX, firstY, subpaths, n, size); }
+
+ // Is there a current point?
+ GBool isCurPt() { return n > 0 || justMoved; }
+
+ // Is the path non-empty, i.e., is there at least one segment?
+ GBool isPath() { return n > 0; }
+
+ // Get subpaths.
+ int getNumSubpaths() { return n; }
+ GfxSubpath *getSubpath(int i) { return subpaths[i]; }
+
+ // Get last point on last subpath.
+ double getLastX() { return subpaths[n-1]->getLastX(); }
+ double getLastY() { return subpaths[n-1]->getLastY(); }
+
+ // Move the current point.
+ void moveTo(double x, double y);
+
+ // Add a segment to the last subpath.
+ void lineTo(double x, double y);
+
+ // Add a Bezier curve to the last subpath
+ void curveTo(double x1, double y1, double x2, double y2,
+ double x3, double y3);
+
+ // Close the last subpath.
+ void close();
+
+ // Append <path> to <this>.
+ void append(GfxPath *path);
+
+ // Add (<dx>, <dy>) to each point in the path.
+ void offset(double dx, double dy);
+
+private:
+
+ GBool justMoved; // set if a new subpath was just started
+ double firstX, firstY; // first point in new subpath
+ GfxSubpath **subpaths; // subpaths
+ int n; // number of subpaths
+ int size; // size of subpaths array
+
+ GfxPath(GBool justMoved1, double firstX1, double firstY1,
+ GfxSubpath **subpaths1, int n1, int size1);
+};
+
+//------------------------------------------------------------------------
+// GfxState
+//------------------------------------------------------------------------
+
+class GfxState {
+public:
+
+ // Construct a default GfxState, for a device with resolution <hDPI>
+ // x <vDPI>, page box <pageBox>, page rotation <rotateA>, and
+ // coordinate system specified by <upsideDown>.
+ GfxState(double hDPIA, double vDPIA, PDFRectangle *pageBox,
+ int rotateA, GBool upsideDown);
+
+ // Destructor.
+ ~GfxState();
+
+ // Copy.
+ GfxState *copy() { return new GfxState(this); }
+
+ // Accessors.
+ double getHDPI() { return hDPI; }
+ double getVDPI() { return vDPI; }
+ double *getCTM() { return ctm; }
+ double getX1() { return px1; }
+ double getY1() { return py1; }
+ double getX2() { return px2; }
+ double getY2() { return py2; }
+ double getPageWidth() { return pageWidth; }
+ double getPageHeight() { return pageHeight; }
+ int getRotate() { return rotate; }
+ GfxColor *getFillColor() { return &fillColor; }
+ GfxColor *getStrokeColor() { return &strokeColor; }
+ void getFillGray(GfxGray *gray)
+ { fillColorSpace->getGray(&fillColor, gray); }
+ void getStrokeGray(GfxGray *gray)
+ { strokeColorSpace->getGray(&strokeColor, gray); }
+ void getFillRGB(GfxRGB *rgb)
+ { fillColorSpace->getRGB(&fillColor, rgb); }
+ void getStrokeRGB(GfxRGB *rgb)
+ { strokeColorSpace->getRGB(&strokeColor, rgb); }
+ void getFillCMYK(GfxCMYK *cmyk)
+ { fillColorSpace->getCMYK(&fillColor, cmyk); }
+ void getStrokeCMYK(GfxCMYK *cmyk)
+ { strokeColorSpace->getCMYK(&strokeColor, cmyk); }
+ GfxColorSpace *getFillColorSpace() { return fillColorSpace; }
+ GfxColorSpace *getStrokeColorSpace() { return strokeColorSpace; }
+ GfxPattern *getFillPattern() { return fillPattern; }
+ GfxPattern *getStrokePattern() { return strokePattern; }
+ GfxBlendMode getBlendMode() { return blendMode; }
+ double getFillOpacity() { return fillOpacity; }
+ double getStrokeOpacity() { return strokeOpacity; }
+ GBool getFillOverprint() { return fillOverprint; }
+ GBool getStrokeOverprint() { return strokeOverprint; }
+ Function **getTransfer() { return transfer; }
+ double getLineWidth() { return lineWidth; }
+ void getLineDash(double **dash, int *length, double *start)
+ { *dash = lineDash; *length = lineDashLength; *start = lineDashStart; }
+ int getFlatness() { return flatness; }
+ int getLineJoin() { return lineJoin; }
+ int getLineCap() { return lineCap; }
+ double getMiterLimit() { return miterLimit; }
+ GBool getStrokeAdjust() { return strokeAdjust; }
+ GfxFont *getFont() { return font; }
+ double getFontSize() { return fontSize; }
+ double *getTextMat() { return textMat; }
+ double getCharSpace() { return charSpace; }
+ double getWordSpace() { return wordSpace; }
+ double getHorizScaling() { return horizScaling; }
+ double getLeading() { return leading; }
+ double getRise() { return rise; }
+ int getRender() { return render; }
+ GfxPath *getPath() { return path; }
+ void setPath(GfxPath *pathA);
+ double getCurX() { return curX; }
+ double getCurY() { return curY; }
+ void getClipBBox(double *xMin, double *yMin, double *xMax, double *yMax)
+ { *xMin = clipXMin; *yMin = clipYMin; *xMax = clipXMax; *yMax = clipYMax; }
+ void getUserClipBBox(double *xMin, double *yMin, double *xMax, double *yMax);
+ double getLineX() { return lineX; }
+ double getLineY() { return lineY; }
+
+ // Is there a current point/path?
+ GBool isCurPt() { return path->isCurPt(); }
+ GBool isPath() { return path->isPath(); }
+
+ // Transforms.
+ void transform(double x1, double y1, double *x2, double *y2)
+ { *x2 = ctm[0] * x1 + ctm[2] * y1 + ctm[4];
+ *y2 = ctm[1] * x1 + ctm[3] * y1 + ctm[5]; }
+ void transformDelta(double x1, double y1, double *x2, double *y2)
+ { *x2 = ctm[0] * x1 + ctm[2] * y1;
+ *y2 = ctm[1] * x1 + ctm[3] * y1; }
+ void textTransform(double x1, double y1, double *x2, double *y2)
+ { *x2 = textMat[0] * x1 + textMat[2] * y1 + textMat[4];
+ *y2 = textMat[1] * x1 + textMat[3] * y1 + textMat[5]; }
+ void textTransformDelta(double x1, double y1, double *x2, double *y2)
+ { *x2 = textMat[0] * x1 + textMat[2] * y1;
+ *y2 = textMat[1] * x1 + textMat[3] * y1; }
+ double transformWidth(double w);
+ double getTransformedLineWidth()
+ { return transformWidth(lineWidth); }
+ double getTransformedFontSize();
+ void getFontTransMat(double *m11, double *m12, double *m21, double *m22);
+
+ // Change state parameters.
+ void setCTM(double a, double b, double c,
+ double d, double e, double f);
+ void concatCTM(double a, double b, double c,
+ double d, double e, double f);
+ void shiftCTM(double tx, double ty);
+ void setFillColorSpace(GfxColorSpace *colorSpace);
+ void setStrokeColorSpace(GfxColorSpace *colorSpace);
+ void setFillColor(GfxColor *color) { fillColor = *color; }
+ void setStrokeColor(GfxColor *color) { strokeColor = *color; }
+ void setFillPattern(GfxPattern *pattern);
+ void setStrokePattern(GfxPattern *pattern);
+ void setBlendMode(GfxBlendMode mode) { blendMode = mode; }
+ void setFillOpacity(double opac) { fillOpacity = opac; }
+ void setStrokeOpacity(double opac) { strokeOpacity = opac; }
+ void setFillOverprint(GBool op) { fillOverprint = op; }
+ void setStrokeOverprint(GBool op) { strokeOverprint = op; }
+ void setTransfer(Function **funcs);
+ void setLineWidth(double width) { lineWidth = width; }
+ void setLineDash(double *dash, int length, double start);
+ void setFlatness(int flatness1) { flatness = flatness1; }
+ void setLineJoin(int lineJoin1) { lineJoin = lineJoin1; }
+ void setLineCap(int lineCap1) { lineCap = lineCap1; }
+ void setMiterLimit(double limit) { miterLimit = limit; }
+ void setStrokeAdjust(GBool sa) { strokeAdjust = sa; }
+ void setFont(GfxFont *fontA, double fontSizeA)
+ { font = fontA; fontSize = fontSizeA; }
+ void setTextMat(double a, double b, double c,
+ double d, double e, double f)
+ { textMat[0] = a; textMat[1] = b; textMat[2] = c;
+ textMat[3] = d; textMat[4] = e; textMat[5] = f; }
+ void setCharSpace(double space)
+ { charSpace = space; }
+ void setWordSpace(double space)
+ { wordSpace = space; }
+ void setHorizScaling(double scale)
+ { horizScaling = 0.01 * scale; }
+ void setLeading(double leadingA)
+ { leading = leadingA; }
+ void setRise(double riseA)
+ { rise = riseA; }
+ void setRender(int renderA)
+ { render = renderA; }
+
+ // Add to path.
+ void moveTo(double x, double y)
+ { path->moveTo(curX = x, curY = y); }
+ void lineTo(double x, double y)
+ { path->lineTo(curX = x, curY = y); }
+ void curveTo(double x1, double y1, double x2, double y2,
+ double x3, double y3)
+ { path->curveTo(x1, y1, x2, y2, curX = x3, curY = y3); }
+ void closePath()
+ { path->close(); curX = path->getLastX(); curY = path->getLastY(); }
+ void clearPath();
+
+ // Update clip region.
+ void clip();
+ void clipToStrokePath();
+
+ // Text position.
+ void textSetPos(double tx, double ty) { lineX = tx; lineY = ty; }
+ void textMoveTo(double tx, double ty)
+ { lineX = tx; lineY = ty; textTransform(tx, ty, &curX, &curY); }
+ void textShift(double tx, double ty);
+ void shift(double dx, double dy);
+
+ // Push/pop GfxState on/off stack.
+ GfxState *save();
+ GfxState *restore();
+ GBool hasSaves() { return saved != NULL; }
+
+ // Misc
+ GBool parseBlendMode(Object *obj, GfxBlendMode *mode);
+
+private:
+
+ double hDPI, vDPI; // resolution
+ double ctm[6]; // coord transform matrix
+ double px1, py1, px2, py2; // page corners (user coords)
+ double pageWidth, pageHeight; // page size (pixels)
+ int rotate; // page rotation angle
+
+ GfxColorSpace *fillColorSpace; // fill color space
+ GfxColorSpace *strokeColorSpace; // stroke color space
+ GfxColor fillColor; // fill color
+ GfxColor strokeColor; // stroke color
+ GfxPattern *fillPattern; // fill pattern
+ GfxPattern *strokePattern; // stroke pattern
+ GfxBlendMode blendMode; // transparency blend mode
+ double fillOpacity; // fill opacity
+ double strokeOpacity; // stroke opacity
+ GBool fillOverprint; // fill overprint
+ GBool strokeOverprint; // stroke overprint
+ Function *transfer[4]; // transfer function (entries may be: all
+ // NULL = identity; last three NULL =
+ // single function; all four non-NULL =
+ // R,G,B,gray functions)
+
+ double lineWidth; // line width
+ double *lineDash; // line dash
+ int lineDashLength;
+ double lineDashStart;
+ int flatness; // curve flatness
+ int lineJoin; // line join style
+ int lineCap; // line cap style
+ double miterLimit; // line miter limit
+ GBool strokeAdjust; // stroke adjustment
+
+ GfxFont *font; // font
+ double fontSize; // font size
+ double textMat[6]; // text matrix
+ double charSpace; // character spacing
+ double wordSpace; // word spacing
+ double horizScaling; // horizontal scaling
+ double leading; // text leading
+ double rise; // text rise
+ int render; // text rendering mode
+
+ GfxPath *path; // array of path elements
+ double curX, curY; // current point (user coords)
+ double lineX, lineY; // start of current text line (text coords)
+
+ double clipXMin, clipYMin, // bounding box for clip region
+ clipXMax, clipYMax;
+
+ GfxState *saved; // next GfxState on stack
+
+ GfxState(GfxState *state);
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/GlobalParams.cc b/kpdf/xpdf/xpdf/GlobalParams.cc
new file mode 100644
index 00000000..b1083777
--- /dev/null
+++ b/kpdf/xpdf/xpdf/GlobalParams.cc
@@ -0,0 +1,2989 @@
+//========================================================================
+//
+// GlobalParams.cc
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <string.h>
+#include <strings.h>
+// KPDF: additional includes for Qt and Xft
+#include <qstring.h>
+#include <qregexp.h>
+#include <qwindowdefs.h>
+// -- gentoo compile fix (XFree 4.3.0, FC 2.2.3, FreeType 2.1.9) --
+// on other distros these 2 lines should't harm
+#include <ft2build.h>
+#include FT_FREETYPE_H
+// -- ---------------------------------------------------------- --
+#include <X11/Xlib.h>
+#include <X11/Xft/Xft.h>
+#include <X11/Xft/XftCompat.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#ifdef ENABLE_PLUGINS
+# ifndef WIN32
+# include <dlfcn.h>
+# endif
+#endif
+#ifdef WIN32
+# include <shlobj.h>
+#endif
+#if HAVE_PAPER_H
+#include <paper.h>
+#endif
+#include "gmem.h"
+#include "GString.h"
+#include "GList.h"
+#include "GHash.h"
+#include "gfile.h"
+#include "Error.h"
+#include "NameToCharCode.h"
+#include "CharCodeToUnicode.h"
+#include "UnicodeMap.h"
+#include "CMap.h"
+#include "BuiltinFontTables.h"
+#include "FontEncodingTables.h"
+#ifdef ENABLE_PLUGINS
+# include "XpdfPluginAPI.h"
+#endif
+#include "GlobalParams.h"
+
+#include <qstring.h>
+#include <qregexp.h>
+#include <fontconfig/fontconfig.h>
+
+#ifdef WIN32
+# define strcasecmp stricmp
+#endif
+
+#if MULTITHREADED
+# define lockGlobalParams gLockMutex(&mutex)
+# define lockUnicodeMapCache gLockMutex(&unicodeMapCacheMutex)
+# define lockCMapCache gLockMutex(&cMapCacheMutex)
+# define unlockGlobalParams gUnlockMutex(&mutex)
+# define unlockUnicodeMapCache gUnlockMutex(&unicodeMapCacheMutex)
+# define unlockCMapCache gUnlockMutex(&cMapCacheMutex)
+#else
+# define lockGlobalParams
+# define lockUnicodeMapCache
+# define lockCMapCache
+# define unlockGlobalParams
+# define unlockUnicodeMapCache
+# define unlockCMapCache
+#endif
+
+#include "NameToUnicodeTable.h"
+#include "UnicodeMapTables.h"
+#include "UTF8.h"
+
+#ifdef ENABLE_PLUGINS
+# ifdef WIN32
+extern XpdfPluginVecTable xpdfPluginVecTable;
+# endif
+#endif
+
+//------------------------------------------------------------------------
+
+#define cidToUnicodeCacheSize 4
+#define unicodeToUnicodeCacheSize 4
+
+//------------------------------------------------------------------------
+
+static struct {
+ char *name;
+ char *t1FileName;
+ char *ttFileName;
+} displayFontTab[] = {
+ {"Courier", "n022003l.pfb", "cour.ttf"},
+ {"Courier-Bold", "n022004l.pfb", "courbd.ttf"},
+ {"Courier-BoldOblique", "n022024l.pfb", "courbi.ttf"},
+ {"Courier-Oblique", "n022023l.pfb", "couri.ttf"},
+ {"Helvetica", "n019003l.pfb", "arial.ttf"},
+ {"Helvetica-Bold", "n019004l.pfb", "arialbd.ttf"},
+ {"Helvetica-BoldOblique", "n019024l.pfb", "arialbi.ttf"},
+ {"Helvetica-Oblique", "n019023l.pfb", "ariali.ttf"},
+ {"Symbol", "s050000l.pfb", NULL},
+ {"Times-Bold", "n021004l.pfb", "timesbd.ttf"},
+ {"Times-BoldItalic", "n021024l.pfb", "timesbi.ttf"},
+ {"Times-Italic", "n021023l.pfb", "timesi.ttf"},
+ {"Times-Roman", "n021003l.pfb", "times.ttf"},
+ {"ZapfDingbats", "d050000l.pfb", NULL},
+ {NULL, NULL, NULL}
+};
+
+#ifdef WIN32
+static char *displayFontDirs[] = {
+ "c:/windows/fonts",
+ "c:/winnt/fonts",
+ NULL
+};
+#else
+static char *displayFontDirs[] = {
+ "/usr/share/ghostscript/fonts",
+ "/usr/pkg/share/ghostscript/fonts",
+ "/usr/local/share/ghostscript/fonts",
+ "/usr/share/fonts/default/Type1",
+ "/usr/X11R6/lib/X11/fonts/Type1",
+ "/usr/share/fonts/default/ghostscript",
+ "/usr/share/fonts/type1/gsfonts",
+ "/usr/share/fonts/Type1",
+ NULL
+};
+#endif
+
+//------------------------------------------------------------------------
+
+GlobalParams *globalParams = NULL;
+
+//------------------------------------------------------------------------
+// DisplayFontParam
+//------------------------------------------------------------------------
+
+DisplayFontParam::DisplayFontParam(GString *nameA,
+ DisplayFontParamKind kindA) {
+ name = nameA;
+ kind = kindA;
+ switch (kind) {
+ case displayFontT1:
+ t1.fileName = NULL;
+ break;
+ case displayFontTT:
+ tt.fileName = NULL;
+ break;
+ }
+}
+
+DisplayFontParam::~DisplayFontParam() {
+ delete name;
+ switch (kind) {
+ case displayFontT1:
+ if (t1.fileName) {
+ delete t1.fileName;
+ }
+ break;
+ case displayFontTT:
+ if (tt.fileName) {
+ delete tt.fileName;
+ }
+ break;
+ }
+}
+
+#ifdef WIN32
+
+//------------------------------------------------------------------------
+// WinFontInfo
+//------------------------------------------------------------------------
+
+class WinFontInfo: public DisplayFontParam {
+public:
+
+ GBool bold, italic;
+
+ static WinFontInfo *make(GString *nameA, GBool boldA, GBool italicA,
+ HKEY regKey, char *winFontDir);
+ WinFontInfo(GString *nameA, GBool boldA, GBool italicA,
+ GString *fileNameA);
+ virtual ~WinFontInfo();
+ GBool equals(WinFontInfo *fi);
+};
+
+WinFontInfo *WinFontInfo::make(GString *nameA, GBool boldA, GBool italicA,
+ HKEY regKey, char *winFontDir) {
+ GString *regName;
+ GString *fileNameA;
+ char buf[MAX_PATH];
+ DWORD n;
+ char c;
+ int i;
+
+ //----- find the font file
+ fileNameA = NULL;
+ regName = nameA->copy();
+ if (boldA) {
+ regName->append(" Bold");
+ }
+ if (italicA) {
+ regName->append(" Italic");
+ }
+ regName->append(" (TrueType)");
+ n = sizeof(buf);
+ if (RegQueryValueEx(regKey, regName->getCString(), NULL, NULL,
+ (LPBYTE)buf, &n) == ERROR_SUCCESS) {
+ fileNameA = new GString(winFontDir);
+ fileNameA->append('\\')->append(buf);
+ }
+ delete regName;
+ if (!fileNameA) {
+ delete nameA;
+ return NULL;
+ }
+
+ //----- normalize the font name
+ i = 0;
+ while (i < nameA->getLength()) {
+ c = nameA->getChar(i);
+ if (c == ' ' || c == ',' || c == '-') {
+ nameA->del(i);
+ } else {
+ ++i;
+ }
+ }
+
+ return new WinFontInfo(nameA, boldA, italicA, fileNameA);
+}
+
+WinFontInfo::WinFontInfo(GString *nameA, GBool boldA, GBool italicA,
+ GString *fileNameA):
+ DisplayFontParam(nameA, displayFontTT)
+{
+ bold = boldA;
+ italic = italicA;
+ tt.fileName = fileNameA;
+}
+
+WinFontInfo::~WinFontInfo() {
+}
+
+GBool WinFontInfo::equals(WinFontInfo *fi) {
+ return !name->cmp(fi->name) && bold == fi->bold && italic == fi->italic;
+}
+
+//------------------------------------------------------------------------
+// WinFontList
+//------------------------------------------------------------------------
+
+class WinFontList {
+public:
+
+ WinFontList(char *winFontDirA);
+ ~WinFontList();
+ WinFontInfo *find(GString *font);
+
+private:
+
+ void add(WinFontInfo *fi);
+ static int CALLBACK enumFunc1(CONST LOGFONT *font,
+ CONST TEXTMETRIC *metrics,
+ DWORD type, LPARAM data);
+ static int CALLBACK enumFunc2(CONST LOGFONT *font,
+ CONST TEXTMETRIC *metrics,
+ DWORD type, LPARAM data);
+
+ GList *fonts; // [WinFontInfo]
+ HDC dc; // (only used during enumeration)
+ HKEY regKey; // (only used during enumeration)
+ char *winFontDir; // (only used during enumeration)
+};
+
+WinFontList::WinFontList(char *winFontDirA) {
+ OSVERSIONINFO version;
+ char *path;
+
+ fonts = new GList();
+ dc = GetDC(NULL);
+ winFontDir = winFontDirA;
+ version.dwOSVersionInfoSize = sizeof(version);
+ GetVersionEx(&version);
+ if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
+ path = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts\\";
+ } else {
+ path = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts\\";
+ }
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, path, 0,
+ KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
+ &regKey) == ERROR_SUCCESS) {
+ EnumFonts(dc, NULL, &WinFontList::enumFunc1, (LPARAM)this);
+ RegCloseKey(regKey);
+ }
+ ReleaseDC(NULL, dc);
+}
+
+WinFontList::~WinFontList() {
+ deleteGList(fonts, WinFontInfo);
+}
+
+void WinFontList::add(WinFontInfo *fi) {
+ int i;
+
+ for (i = 0; i < fonts->getLength(); ++i) {
+ if (((WinFontInfo *)fonts->get(i))->equals(fi)) {
+ delete fi;
+ return;
+ }
+ }
+ fonts->append(fi);
+}
+
+WinFontInfo *WinFontList::find(GString *font) {
+ GString *name;
+ GBool bold, italic;
+ WinFontInfo *fi;
+ char c;
+ int n, i;
+
+ name = font->copy();
+
+ // remove space, comma, dash chars
+ i = 0;
+ while (i < name->getLength()) {
+ c = name->getChar(i);
+ if (c == ' ' || c == ',' || c == '-') {
+ name->del(i);
+ } else {
+ ++i;
+ }
+ }
+ n = name->getLength();
+
+ // remove trailing "MT" (Foo-MT, Foo-BoldMT, etc.)
+ if (!strcmp(name->getCString() + n - 2, "MT")) {
+ name->del(n - 2, 2);
+ n -= 2;
+ }
+
+ // look for "Italic"
+ if (!strcmp(name->getCString() + n - 6, "Italic")) {
+ name->del(n - 6, 6);
+ italic = gTrue;
+ n -= 6;
+ } else {
+ italic = gFalse;
+ }
+
+ // look for "Bold"
+ if (!strcmp(name->getCString() + n - 4, "Bold")) {
+ name->del(n - 4, 4);
+ bold = gTrue;
+ n -= 4;
+ } else {
+ bold = gFalse;
+ }
+
+ // remove trailing "MT" (FooMT-Bold, etc.)
+ if (!strcmp(name->getCString() + n - 2, "MT")) {
+ name->del(n - 2, 2);
+ n -= 2;
+ }
+
+ // remove trailing "PS"
+ if (!strcmp(name->getCString() + n - 2, "PS")) {
+ name->del(n - 2, 2);
+ n -= 2;
+ }
+
+ // search for the font
+ fi = NULL;
+ for (i = 0; i < fonts->getLength(); ++i) {
+ fi = (WinFontInfo *)fonts->get(i);
+ if (!fi->name->cmp(name) && fi->bold == bold && fi->italic == italic) {
+ break;
+ }
+ fi = NULL;
+ }
+
+ delete name;
+ return fi;
+}
+
+int CALLBACK WinFontList::enumFunc1(CONST LOGFONT *font,
+ CONST TEXTMETRIC *metrics,
+ DWORD type, LPARAM data) {
+ WinFontList *fl = (WinFontList *)data;
+
+ EnumFonts(fl->dc, font->lfFaceName, &WinFontList::enumFunc2, (LPARAM)fl);
+ return 1;
+}
+
+int CALLBACK WinFontList::enumFunc2(CONST LOGFONT *font,
+ CONST TEXTMETRIC *metrics,
+ DWORD type, LPARAM data) {
+ WinFontList *fl = (WinFontList *)data;
+ WinFontInfo *fi;
+
+ if (type & TRUETYPE_FONTTYPE) {
+ if ((fi = WinFontInfo::make(new GString(font->lfFaceName),
+ font->lfWeight >= 600,
+ font->lfItalic ? gTrue : gFalse,
+ fl->regKey, fl->winFontDir))) {
+ fl->add(fi);
+ }
+ }
+ return 1;
+}
+
+#endif // WIN32
+
+//------------------------------------------------------------------------
+// PSFontParam
+//------------------------------------------------------------------------
+
+PSFontParam::PSFontParam(GString *pdfFontNameA, int wModeA,
+ GString *psFontNameA, GString *encodingA) {
+ pdfFontName = pdfFontNameA;
+ wMode = wModeA;
+ psFontName = psFontNameA;
+ encoding = encodingA;
+}
+
+PSFontParam::~PSFontParam() {
+ delete pdfFontName;
+ delete psFontName;
+ if (encoding) {
+ delete encoding;
+ }
+}
+
+//------------------------------------------------------------------------
+// KeyBinding
+//------------------------------------------------------------------------
+
+KeyBinding::KeyBinding(int codeA, int modsA, int contextA, char *cmd0) {
+ code = codeA;
+ mods = modsA;
+ context = contextA;
+ cmds = new GList();
+ cmds->append(new GString(cmd0));
+}
+
+KeyBinding::KeyBinding(int codeA, int modsA, int contextA,
+ char *cmd0, char *cmd1) {
+ code = codeA;
+ mods = modsA;
+ context = contextA;
+ cmds = new GList();
+ cmds->append(new GString(cmd0));
+ cmds->append(new GString(cmd1));
+}
+
+KeyBinding::KeyBinding(int codeA, int modsA, int contextA, GList *cmdsA) {
+ code = codeA;
+ mods = modsA;
+ context = contextA;
+ cmds = cmdsA;
+}
+
+KeyBinding::~KeyBinding() {
+ deleteGList(cmds, GString);
+}
+
+#ifdef ENABLE_PLUGINS
+//------------------------------------------------------------------------
+// Plugin
+//------------------------------------------------------------------------
+
+class Plugin {
+public:
+
+ static Plugin *load(char *type, char *name);
+ ~Plugin();
+
+private:
+
+#ifdef WIN32
+ Plugin(HMODULE libA);
+ HMODULE lib;
+#else
+ Plugin(void *dlA);
+ void *dl;
+#endif
+};
+
+Plugin *Plugin::load(char *type, char *name) {
+ GString *path;
+ Plugin *plugin;
+ XpdfPluginVecTable *vt;
+ XpdfBool (*xpdfInitPlugin)(void);
+#ifdef WIN32
+ HMODULE libA;
+#else
+ void *dlA;
+#endif
+
+ path = globalParams->getBaseDir();
+ appendToPath(path, "plugins");
+ appendToPath(path, type);
+ appendToPath(path, name);
+
+#ifdef WIN32
+ path->append(".dll");
+ if (!(libA = LoadLibrary(path->getCString()))) {
+ error(-1, "Failed to load plugin '%s'",
+ path->getCString());
+ goto err1;
+ }
+ if (!(vt = (XpdfPluginVecTable *)
+ GetProcAddress(libA, "xpdfPluginVecTable"))) {
+ error(-1, "Failed to find xpdfPluginVecTable in plugin '%s'",
+ path->getCString());
+ goto err2;
+ }
+#else
+ //~ need to deal with other extensions here
+ path->append(".so");
+ if (!(dlA = dlopen(path->getCString(), RTLD_NOW))) {
+ error(-1, "Failed to load plugin '%s': %s",
+ path->getCString(), dlerror());
+ goto err1;
+ }
+ if (!(vt = (XpdfPluginVecTable *)dlsym(dlA, "xpdfPluginVecTable"))) {
+ error(-1, "Failed to find xpdfPluginVecTable in plugin '%s'",
+ path->getCString());
+ goto err2;
+ }
+#endif
+
+ if (vt->version != xpdfPluginVecTable.version) {
+ error(-1, "Plugin '%s' is wrong version", path->getCString());
+ goto err2;
+ }
+ memcpy(vt, &xpdfPluginVecTable, sizeof(xpdfPluginVecTable));
+
+#ifdef WIN32
+ if (!(xpdfInitPlugin = (XpdfBool (*)(void))
+ GetProcAddress(libA, "xpdfInitPlugin"))) {
+ error(-1, "Failed to find xpdfInitPlugin in plugin '%s'",
+ path->getCString());
+ goto err2;
+ }
+#else
+ if (!(xpdfInitPlugin = (XpdfBool (*)(void))dlsym(dlA, "xpdfInitPlugin"))) {
+ error(-1, "Failed to find xpdfInitPlugin in plugin '%s'",
+ path->getCString());
+ goto err2;
+ }
+#endif
+
+ if (!(*xpdfInitPlugin)()) {
+ error(-1, "Initialization of plugin '%s' failed",
+ path->getCString());
+ goto err2;
+ }
+
+#ifdef WIN32
+ plugin = new Plugin(libA);
+#else
+ plugin = new Plugin(dlA);
+#endif
+
+ delete path;
+ return plugin;
+
+ err2:
+#ifdef WIN32
+ FreeLibrary(libA);
+#else
+ dlclose(dlA);
+#endif
+ err1:
+ delete path;
+ return NULL;
+}
+
+#ifdef WIN32
+Plugin::Plugin(HMODULE libA) {
+ lib = libA;
+}
+#else
+Plugin::Plugin(void *dlA) {
+ dl = dlA;
+}
+#endif
+
+Plugin::~Plugin() {
+ void (*xpdfFreePlugin)(void);
+
+#ifdef WIN32
+ if ((xpdfFreePlugin = (void (*)(void))
+ GetProcAddress(lib, "xpdfFreePlugin"))) {
+ (*xpdfFreePlugin)();
+ }
+ FreeLibrary(lib);
+#else
+ if ((xpdfFreePlugin = (void (*)(void))dlsym(dl, "xpdfFreePlugin"))) {
+ (*xpdfFreePlugin)();
+ }
+ dlclose(dl);
+#endif
+}
+
+#endif // ENABLE_PLUGINS
+
+//------------------------------------------------------------------------
+// parsing
+//------------------------------------------------------------------------
+
+GlobalParams::GlobalParams(char *cfgFileName) {
+ UnicodeMap *map;
+ GString *fileName;
+ FILE *f;
+ int i;
+
+#if MULTITHREADED
+ gInitMutex(&mutex);
+ gInitMutex(&unicodeMapCacheMutex);
+ gInitMutex(&cMapCacheMutex);
+#endif
+
+ initBuiltinFontTables();
+
+ // scan the encoding in reverse because we want the lowest-numbered
+ // index for each char name ('space' is encoded twice)
+ macRomanReverseMap = new NameToCharCode();
+ for (i = 255; i >= 0; --i) {
+ if (macRomanEncoding[i]) {
+ macRomanReverseMap->add(macRomanEncoding[i], (CharCode)i);
+ }
+ }
+
+#ifdef WIN32
+ // baseDir will be set by a call to setBaseDir
+ baseDir = new GString();
+#else
+ baseDir = appendToPath(getHomeDir(), ".xpdf");
+#endif
+ nameToUnicode = new NameToCharCode();
+ cidToUnicodes = new GHash(gTrue);
+ unicodeToUnicodes = new GHash(gTrue);
+ residentUnicodeMaps = new GHash();
+ unicodeMaps = new GHash(gTrue);
+ cMapDirs = new GHash(gTrue);
+ toUnicodeDirs = new GList();
+ displayFonts = new GHash();
+ displayCIDFonts = new GHash();
+ displayNamedCIDFonts = new GHash();
+#if HAVE_PAPER_H
+ char *paperName;
+ const struct paper *paperType;
+ paperinit();
+ if ((paperName = systempapername())) {
+ paperType = paperinfo(paperName);
+ psPaperWidth = (int)paperpswidth(paperType);
+ psPaperHeight = (int)paperpsheight(paperType);
+ } else {
+ error(-1, "No paper information available - using defaults");
+ psPaperWidth = defPaperWidth;
+ psPaperHeight = defPaperHeight;
+ }
+ paperdone();
+#else
+ psPaperWidth = defPaperWidth;
+ psPaperHeight = defPaperHeight;
+#endif
+ psImageableLLX = psImageableLLY = 0;
+ psImageableURX = psPaperWidth;
+ psImageableURY = psPaperHeight;
+ psCrop = gTrue;
+ psExpandSmaller = gFalse;
+ psShrinkLarger = gTrue;
+ psCenter = gTrue;
+ psDuplex = gFalse;
+ psLevel = psLevel2;
+ psFile = NULL;
+ psFonts = new GHash();
+ psNamedFonts16 = new GList();
+ psFonts16 = new GList();
+ psEmbedType1 = gTrue;
+ psEmbedTrueType = gTrue;
+ psEmbedCIDPostScript = gTrue;
+ psEmbedCIDTrueType = gTrue;
+ psPreload = gFalse;
+ psOPI = gFalse;
+ psASCIIHex = gFalse;
+ // KPDF: use always UTF-8 and QString::fromUtf
+ textEncoding = new GString("UTF-8");
+#if defined(WIN32)
+ textEOL = eolDOS;
+#elif defined(MACOS)
+ textEOL = eolMac;
+#else
+ textEOL = eolUnix;
+#endif
+ textPageBreaks = gTrue;
+ textKeepTinyChars = gFalse;
+ fontDirs = new GList();
+ initialZoom = new GString("125");
+ continuousView = gFalse;
+ enableT1lib = gTrue;
+ enableFreeType = gTrue;
+ antialias = gTrue;
+ vectorAntialias = gTrue;
+ strokeAdjust = gTrue;
+ screenType = screenUnset;
+ screenSize = -1;
+ screenDotRadius = -1;
+ screenGamma = 1.0;
+ screenBlackThreshold = 0.0;
+ screenWhiteThreshold = 1.0;
+ urlCommand = NULL;
+ movieCommand = NULL;
+ mapNumericCharNames = gTrue;
+ mapUnknownCharNames = gFalse;
+ createDefaultKeyBindings();
+ printCommands = gFalse;
+ errQuiet = gFalse;
+
+ cidToUnicodeCache = new CharCodeToUnicodeCache(cidToUnicodeCacheSize);
+ unicodeToUnicodeCache =
+ new CharCodeToUnicodeCache(unicodeToUnicodeCacheSize);
+ unicodeMapCache = new UnicodeMapCache();
+ cMapCache = new CMapCache();
+
+#ifdef WIN32
+ winFontList = NULL;
+#endif
+
+#ifdef ENABLE_PLUGINS
+ plugins = new GList();
+ securityHandlers = new GList();
+#endif
+
+ // set up the initial nameToUnicode table
+ for (i = 0; nameToUnicodeTab[i].name; ++i) {
+ nameToUnicode->add(nameToUnicodeTab[i].name, nameToUnicodeTab[i].u);
+ }
+
+ // set up the residentUnicodeMaps table
+ map = new UnicodeMap("Latin1", gFalse,
+ latin1UnicodeMapRanges, latin1UnicodeMapLen);
+ residentUnicodeMaps->add(map->getEncodingName(), map);
+ map = new UnicodeMap("ASCII7", gFalse,
+ ascii7UnicodeMapRanges, ascii7UnicodeMapLen);
+ residentUnicodeMaps->add(map->getEncodingName(), map);
+ map = new UnicodeMap("Symbol", gFalse,
+ symbolUnicodeMapRanges, symbolUnicodeMapLen);
+ residentUnicodeMaps->add(map->getEncodingName(), map);
+ map = new UnicodeMap("ZapfDingbats", gFalse, zapfDingbatsUnicodeMapRanges,
+ zapfDingbatsUnicodeMapLen);
+ residentUnicodeMaps->add(map->getEncodingName(), map);
+ map = new UnicodeMap("UTF-8", gTrue, &mapUTF8);
+ residentUnicodeMaps->add(map->getEncodingName(), map);
+ map = new UnicodeMap("UCS-2", gTrue, &mapUCS2);
+ residentUnicodeMaps->add(map->getEncodingName(), map);
+
+ // look for a user config file, then a system-wide config file
+ f = NULL;
+ fileName = NULL;
+ if (cfgFileName && cfgFileName[0]) {
+ fileName = new GString(cfgFileName);
+ if (!(f = fopen(fileName->getCString(), "r"))) {
+ delete fileName;
+ }
+ }
+ if (!f) {
+ fileName = appendToPath(getHomeDir(), xpdfUserConfigFile);
+ if (!(f = fopen(fileName->getCString(), "r"))) {
+ delete fileName;
+ }
+ }
+ if (!f) {
+#if defined(WIN32) && !defined(__CYGWIN32__)
+ char buf[512];
+ i = GetModuleFileName(NULL, buf, sizeof(buf));
+ if (i <= 0 || i >= sizeof(buf)) {
+ // error or path too long for buffer - just use the current dir
+ buf[0] = '\0';
+ }
+ fileName = grabPath(buf);
+ appendToPath(fileName, xpdfSysConfigFile);
+#else
+ fileName = new GString(xpdfSysConfigFile);
+#endif
+ if (!(f = fopen(fileName->getCString(), "r"))) {
+ delete fileName;
+ }
+ }
+ if (f) {
+ parseFile(fileName, f);
+ delete fileName;
+ fclose(f);
+ }
+}
+
+void GlobalParams::createDefaultKeyBindings() {
+ keyBindings = new GList();
+
+ //----- mouse buttons
+ keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress1, xpdfKeyModNone,
+ xpdfKeyContextAny, "startSelection"));
+ keyBindings->append(new KeyBinding(xpdfKeyCodeMouseRelease1, xpdfKeyModNone,
+ xpdfKeyContextAny, "endSelection",
+ "followLinkNoSel"));
+ keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress2, xpdfKeyModNone,
+ xpdfKeyContextAny, "startPan"));
+ keyBindings->append(new KeyBinding(xpdfKeyCodeMouseRelease2, xpdfKeyModNone,
+ xpdfKeyContextAny, "endPan"));
+ keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress3, xpdfKeyModNone,
+ xpdfKeyContextAny, "postPopupMenu"));
+ keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress4, xpdfKeyModNone,
+ xpdfKeyContextAny,
+ "scrollUpPrevPage(16)"));
+ keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress5, xpdfKeyModNone,
+ xpdfKeyContextAny,
+ "scrollDownNextPage(16)"));
+ keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress6, xpdfKeyModNone,
+ xpdfKeyContextAny, "scrollLeft(16)"));
+ keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress7, xpdfKeyModNone,
+ xpdfKeyContextAny, "scrollRight(16)"));
+
+ //----- keys
+ keyBindings->append(new KeyBinding(xpdfKeyCodeHome, xpdfKeyModCtrl,
+ xpdfKeyContextAny, "gotoPage(1)"));
+ keyBindings->append(new KeyBinding(xpdfKeyCodeHome, xpdfKeyModNone,
+ xpdfKeyContextAny, "scrollToTopLeft"));
+ keyBindings->append(new KeyBinding(xpdfKeyCodeEnd, xpdfKeyModCtrl,
+ xpdfKeyContextAny, "gotoLastPage"));
+ keyBindings->append(new KeyBinding(xpdfKeyCodeEnd, xpdfKeyModNone,
+ xpdfKeyContextAny,
+ "scrollToBottomRight"));
+ keyBindings->append(new KeyBinding(xpdfKeyCodePgUp, xpdfKeyModNone,
+ xpdfKeyContextAny, "pageUp"));
+ keyBindings->append(new KeyBinding(xpdfKeyCodeBackspace, xpdfKeyModNone,
+ xpdfKeyContextAny, "pageUp"));
+ keyBindings->append(new KeyBinding(xpdfKeyCodeDelete, xpdfKeyModNone,
+ xpdfKeyContextAny, "pageUp"));
+ keyBindings->append(new KeyBinding(xpdfKeyCodePgDn, xpdfKeyModNone,
+ xpdfKeyContextAny, "pageDown"));
+ keyBindings->append(new KeyBinding(' ', xpdfKeyModNone,
+ xpdfKeyContextAny, "pageDown"));
+ keyBindings->append(new KeyBinding(xpdfKeyCodeLeft, xpdfKeyModNone,
+ xpdfKeyContextAny, "scrollLeft(16)"));
+ keyBindings->append(new KeyBinding(xpdfKeyCodeRight, xpdfKeyModNone,
+ xpdfKeyContextAny, "scrollRight(16)"));
+ keyBindings->append(new KeyBinding(xpdfKeyCodeUp, xpdfKeyModNone,
+ xpdfKeyContextAny, "scrollUp(16)"));
+ keyBindings->append(new KeyBinding(xpdfKeyCodeDown, xpdfKeyModNone,
+ xpdfKeyContextAny, "scrollDown(16)"));
+ keyBindings->append(new KeyBinding('o', xpdfKeyModNone,
+ xpdfKeyContextAny, "open"));
+ keyBindings->append(new KeyBinding('O', xpdfKeyModNone,
+ xpdfKeyContextAny, "open"));
+ keyBindings->append(new KeyBinding('r', xpdfKeyModNone,
+ xpdfKeyContextAny, "reload"));
+ keyBindings->append(new KeyBinding('R', xpdfKeyModNone,
+ xpdfKeyContextAny, "reload"));
+ keyBindings->append(new KeyBinding('f', xpdfKeyModNone,
+ xpdfKeyContextAny, "find"));
+ keyBindings->append(new KeyBinding('F', xpdfKeyModNone,
+ xpdfKeyContextAny, "find"));
+ keyBindings->append(new KeyBinding('f', xpdfKeyModCtrl,
+ xpdfKeyContextAny, "find"));
+ keyBindings->append(new KeyBinding('g', xpdfKeyModCtrl,
+ xpdfKeyContextAny, "findNext"));
+ keyBindings->append(new KeyBinding('p', xpdfKeyModCtrl,
+ xpdfKeyContextAny, "print"));
+ keyBindings->append(new KeyBinding('n', xpdfKeyModNone,
+ xpdfKeyContextScrLockOff, "nextPage"));
+ keyBindings->append(new KeyBinding('N', xpdfKeyModNone,
+ xpdfKeyContextScrLockOff, "nextPage"));
+ keyBindings->append(new KeyBinding('n', xpdfKeyModNone,
+ xpdfKeyContextScrLockOn,
+ "nextPageNoScroll"));
+ keyBindings->append(new KeyBinding('N', xpdfKeyModNone,
+ xpdfKeyContextScrLockOn,
+ "nextPageNoScroll"));
+ keyBindings->append(new KeyBinding('p', xpdfKeyModNone,
+ xpdfKeyContextScrLockOff, "prevPage"));
+ keyBindings->append(new KeyBinding('P', xpdfKeyModNone,
+ xpdfKeyContextScrLockOff, "prevPage"));
+ keyBindings->append(new KeyBinding('p', xpdfKeyModNone,
+ xpdfKeyContextScrLockOn,
+ "prevPageNoScroll"));
+ keyBindings->append(new KeyBinding('P', xpdfKeyModNone,
+ xpdfKeyContextScrLockOn,
+ "prevPageNoScroll"));
+ keyBindings->append(new KeyBinding('v', xpdfKeyModNone,
+ xpdfKeyContextAny, "goForward"));
+ keyBindings->append(new KeyBinding('b', xpdfKeyModNone,
+ xpdfKeyContextAny, "goBackward"));
+ keyBindings->append(new KeyBinding('g', xpdfKeyModNone,
+ xpdfKeyContextAny, "focusToPageNum"));
+ keyBindings->append(new KeyBinding('0', xpdfKeyModNone,
+ xpdfKeyContextAny, "zoomPercent(125)"));
+ keyBindings->append(new KeyBinding('+', xpdfKeyModNone,
+ xpdfKeyContextAny, "zoomIn"));
+ keyBindings->append(new KeyBinding('-', xpdfKeyModNone,
+ xpdfKeyContextAny, "zoomOut"));
+ keyBindings->append(new KeyBinding('z', xpdfKeyModNone,
+ xpdfKeyContextAny, "zoomFitPage"));
+ keyBindings->append(new KeyBinding('w', xpdfKeyModNone,
+ xpdfKeyContextAny, "zoomFitWidth"));
+ keyBindings->append(new KeyBinding('f', xpdfKeyModAlt,
+ xpdfKeyContextAny,
+ "toggleFullScreenMode"));
+ keyBindings->append(new KeyBinding('l', xpdfKeyModCtrl,
+ xpdfKeyContextAny, "redraw"));
+ keyBindings->append(new KeyBinding('w', xpdfKeyModCtrl,
+ xpdfKeyContextAny, "closeWindow"));
+ keyBindings->append(new KeyBinding('?', xpdfKeyModNone,
+ xpdfKeyContextAny, "about"));
+ keyBindings->append(new KeyBinding('q', xpdfKeyModNone,
+ xpdfKeyContextAny, "quit"));
+ keyBindings->append(new KeyBinding('Q', xpdfKeyModNone,
+ xpdfKeyContextAny, "quit"));
+}
+
+void GlobalParams::parseFile(GString *fileName, FILE *f) {
+ int line;
+ char buf[512];
+
+ line = 1;
+ while (getLine(buf, sizeof(buf) - 1, f)) {
+ parseLine(buf, fileName, line);
+ ++line;
+ }
+}
+
+void GlobalParams::parseLine(char *buf, GString *fileName, int line) {
+ GList *tokens;
+ GString *cmd, *incFile;
+ char *p1, *p2;
+ FILE *f2;
+
+ // break the line into tokens
+ tokens = new GList();
+ p1 = buf;
+ while (*p1) {
+ for (; *p1 && isspace(*p1); ++p1) ;
+ if (!*p1) {
+ break;
+ }
+ if (*p1 == '"' || *p1 == '\'') {
+ for (p2 = p1 + 1; *p2 && *p2 != *p1; ++p2) ;
+ ++p1;
+ } else {
+ for (p2 = p1 + 1; *p2 && !isspace(*p2); ++p2) ;
+ }
+ tokens->append(new GString(p1, p2 - p1));
+ p1 = *p2 ? p2 + 1 : p2;
+ }
+
+ // parse the line
+ if (tokens->getLength() > 0 &&
+ ((GString *)tokens->get(0))->getChar(0) != '#') {
+ cmd = (GString *)tokens->get(0);
+ if (!cmd->cmp("include")) {
+ if (tokens->getLength() == 2) {
+ incFile = (GString *)tokens->get(1);
+ if ((f2 = fopen(incFile->getCString(), "r"))) {
+ parseFile(incFile, f2);
+ fclose(f2);
+ } else {
+ error(-1, "Couldn't find included config file: '%s' (%s:%d)",
+ incFile->getCString(), fileName->getCString(), line);
+ }
+ } else {
+ error(-1, "Bad 'include' config file command (%s:%d)",
+ fileName->getCString(), line);
+ }
+ } else if (!cmd->cmp("nameToUnicode")) {
+ parseNameToUnicode(tokens, fileName, line);
+ } else if (!cmd->cmp("cidToUnicode")) {
+ parseCIDToUnicode(tokens, fileName, line);
+ } else if (!cmd->cmp("unicodeToUnicode")) {
+ parseUnicodeToUnicode(tokens, fileName, line);
+ } else if (!cmd->cmp("unicodeMap")) {
+ parseUnicodeMap(tokens, fileName, line);
+ } else if (!cmd->cmp("cMapDir")) {
+ parseCMapDir(tokens, fileName, line);
+ } else if (!cmd->cmp("toUnicodeDir")) {
+ parseToUnicodeDir(tokens, fileName, line);
+ } else if (!cmd->cmp("displayFontT1")) {
+ parseDisplayFont(tokens, displayFonts, displayFontT1, fileName, line);
+ } else if (!cmd->cmp("displayFontTT")) {
+ parseDisplayFont(tokens, displayFonts, displayFontTT, fileName, line);
+ } else if (!cmd->cmp("displayNamedCIDFontT1")) {
+ parseDisplayFont(tokens, displayNamedCIDFonts,
+ displayFontT1, fileName, line);
+ } else if (!cmd->cmp("displayCIDFontT1")) {
+ parseDisplayFont(tokens, displayCIDFonts,
+ displayFontT1, fileName, line);
+ } else if (!cmd->cmp("displayNamedCIDFontTT")) {
+ parseDisplayFont(tokens, displayNamedCIDFonts,
+ displayFontTT, fileName, line);
+ } else if (!cmd->cmp("displayCIDFontTT")) {
+ parseDisplayFont(tokens, displayCIDFonts,
+ displayFontTT, fileName, line);
+ } else if (!cmd->cmp("psFile")) {
+ parsePSFile(tokens, fileName, line);
+ } else if (!cmd->cmp("psFont")) {
+ parsePSFont(tokens, fileName, line);
+ } else if (!cmd->cmp("psNamedFont16")) {
+ parsePSFont16("psNamedFont16", psNamedFonts16,
+ tokens, fileName, line);
+ } else if (!cmd->cmp("psFont16")) {
+ parsePSFont16("psFont16", psFonts16, tokens, fileName, line);
+ } else if (!cmd->cmp("psPaperSize")) {
+ parsePSPaperSize(tokens, fileName, line);
+ } else if (!cmd->cmp("psImageableArea")) {
+ parsePSImageableArea(tokens, fileName, line);
+ } else if (!cmd->cmp("psCrop")) {
+ parseYesNo("psCrop", &psCrop, tokens, fileName, line);
+ } else if (!cmd->cmp("psExpandSmaller")) {
+ parseYesNo("psExpandSmaller", &psExpandSmaller,
+ tokens, fileName, line);
+ } else if (!cmd->cmp("psShrinkLarger")) {
+ parseYesNo("psShrinkLarger", &psShrinkLarger, tokens, fileName, line);
+ } else if (!cmd->cmp("psCenter")) {
+ parseYesNo("psCenter", &psCenter, tokens, fileName, line);
+ } else if (!cmd->cmp("psDuplex")) {
+ parseYesNo("psDuplex", &psDuplex, tokens, fileName, line);
+ } else if (!cmd->cmp("psLevel")) {
+ parsePSLevel(tokens, fileName, line);
+ } else if (!cmd->cmp("psEmbedType1Fonts")) {
+ parseYesNo("psEmbedType1", &psEmbedType1, tokens, fileName, line);
+ } else if (!cmd->cmp("psEmbedTrueTypeFonts")) {
+ parseYesNo("psEmbedTrueType", &psEmbedTrueType,
+ tokens, fileName, line);
+ } else if (!cmd->cmp("psEmbedCIDPostScriptFonts")) {
+ parseYesNo("psEmbedCIDPostScript", &psEmbedCIDPostScript,
+ tokens, fileName, line);
+ } else if (!cmd->cmp("psEmbedCIDTrueTypeFonts")) {
+ parseYesNo("psEmbedCIDTrueType", &psEmbedCIDTrueType,
+ tokens, fileName, line);
+ } else if (!cmd->cmp("psPreload")) {
+ parseYesNo("psPreload", &psPreload, tokens, fileName, line);
+ } else if (!cmd->cmp("psOPI")) {
+ parseYesNo("psOPI", &psOPI, tokens, fileName, line);
+ } else if (!cmd->cmp("psASCIIHex")) {
+ parseYesNo("psASCIIHex", &psASCIIHex, tokens, fileName, line);
+ } else if (!cmd->cmp("textEncoding")) {
+// Always use UTF-8 and allow QString do the magic
+// parseTextEncoding(tokens, fileName, line);
+ } else if (!cmd->cmp("textEOL")) {
+ parseTextEOL(tokens, fileName, line);
+ } else if (!cmd->cmp("textPageBreaks")) {
+ parseYesNo("textPageBreaks", &textPageBreaks,
+ tokens, fileName, line);
+ } else if (!cmd->cmp("textKeepTinyChars")) {
+ parseYesNo("textKeepTinyChars", &textKeepTinyChars,
+ tokens, fileName, line);
+ } else if (!cmd->cmp("fontDir")) {
+ parseFontDir(tokens, fileName, line);
+ } else if (!cmd->cmp("initialZoom")) {
+ parseInitialZoom(tokens, fileName, line);
+ } else if (!cmd->cmp("continuousView")) {
+ parseYesNo("continuousView", &continuousView, tokens, fileName, line);
+ } else if (!cmd->cmp("enableT1lib")) {
+ parseYesNo("enableT1lib", &enableT1lib, tokens, fileName, line);
+ } else if (!cmd->cmp("enableFreeType")) {
+ parseYesNo("enableFreeType", &enableFreeType, tokens, fileName, line);
+ } else if (!cmd->cmp("antialias")) {
+ parseYesNo("antialias", &antialias, tokens, fileName, line);
+ } else if (!cmd->cmp("vectorAntialias")) {
+ parseYesNo("vectorAntialias", &vectorAntialias,
+ tokens, fileName, line);
+ } else if (!cmd->cmp("strokeAdjust")) {
+ parseYesNo("strokeAdjust", &strokeAdjust, tokens, fileName, line);
+ } else if (!cmd->cmp("screenType")) {
+ parseScreenType(tokens, fileName, line);
+ } else if (!cmd->cmp("screenSize")) {
+ parseInteger("screenSize", &screenSize, tokens, fileName, line);
+ } else if (!cmd->cmp("screenDotRadius")) {
+ parseInteger("screenDotRadius", &screenDotRadius,
+ tokens, fileName, line);
+ } else if (!cmd->cmp("screenGamma")) {
+ parseFloat("screenGamma", &screenGamma,
+ tokens, fileName, line);
+ } else if (!cmd->cmp("screenBlackThreshold")) {
+ parseFloat("screenBlackThreshold", &screenBlackThreshold,
+ tokens, fileName, line);
+ } else if (!cmd->cmp("screenWhiteThreshold")) {
+ parseFloat("screenWhiteThreshold", &screenWhiteThreshold,
+ tokens, fileName, line);
+ } else if (!cmd->cmp("urlCommand")) {
+ parseCommand("urlCommand", &urlCommand, tokens, fileName, line);
+ } else if (!cmd->cmp("movieCommand")) {
+ parseCommand("movieCommand", &movieCommand, tokens, fileName, line);
+ } else if (!cmd->cmp("mapNumericCharNames")) {
+ parseYesNo("mapNumericCharNames", &mapNumericCharNames,
+ tokens, fileName, line);
+ } else if (!cmd->cmp("mapUnknownCharNames")) {
+ parseYesNo("mapUnknownCharNames", &mapUnknownCharNames,
+ tokens, fileName, line);
+ } else if (!cmd->cmp("bind")) {
+ parseBind(tokens, fileName, line);
+ } else if (!cmd->cmp("unbind")) {
+ parseUnbind(tokens, fileName, line);
+ } else if (!cmd->cmp("printCommands")) {
+ parseYesNo("printCommands", &printCommands, tokens, fileName, line);
+ } else if (!cmd->cmp("errQuiet")) {
+ parseYesNo("errQuiet", &errQuiet, tokens, fileName, line);
+ } else {
+ error(-1, "Unknown config file command '%s' (%s:%d)",
+ cmd->getCString(), fileName->getCString(), line);
+ if (!cmd->cmp("displayFontX") ||
+ !cmd->cmp("displayNamedCIDFontX") ||
+ !cmd->cmp("displayCIDFontX")) {
+ error(-1, "-- Xpdf no longer supports X fonts");
+ } else if (!cmd->cmp("t1libControl") || !cmd->cmp("freetypeControl")) {
+ error(-1, "-- The t1libControl and freetypeControl options have been replaced");
+ error(-1, " by the enableT1lib, enableFreeType, and antialias options");
+ } else if (!cmd->cmp("fontpath") || !cmd->cmp("fontmap")) {
+ error(-1, "-- the config file format has changed since Xpdf 0.9x");
+ }
+ }
+ }
+
+ deleteGList(tokens, GString);
+}
+
+void GlobalParams::parseNameToUnicode(GList *tokens, GString *fileName,
+ int line) {
+ GString *name;
+ char *tok1, *tok2;
+ FILE *f;
+ char buf[256];
+ int line2;
+ Unicode u;
+
+ if (tokens->getLength() != 2) {
+ error(-1, "Bad 'nameToUnicode' config file command (%s:%d)",
+ fileName->getCString(), line);
+ return;
+ }
+ name = (GString *)tokens->get(1);
+ if (!(f = fopen(name->getCString(), "r"))) {
+ error(-1, "Couldn't open 'nameToUnicode' file '%s'",
+ name->getCString());
+ return;
+ }
+ line2 = 1;
+ while (getLine(buf, sizeof(buf), f)) {
+ tok1 = strtok(buf, " \t\r\n");
+ tok2 = strtok(NULL, " \t\r\n");
+ if (tok1 && tok2) {
+ sscanf(tok1, "%x", &u);
+ nameToUnicode->add(tok2, u);
+ } else {
+ error(-1, "Bad line in 'nameToUnicode' file (%s:%d)", name, line2);
+ }
+ ++line2;
+ }
+ fclose(f);
+}
+
+void GlobalParams::parseCIDToUnicode(GList *tokens, GString *fileName,
+ int line) {
+ GString *collection, *name, *old;
+
+ if (tokens->getLength() != 3) {
+ error(-1, "Bad 'cidToUnicode' config file command (%s:%d)",
+ fileName->getCString(), line);
+ return;
+ }
+ collection = (GString *)tokens->get(1);
+ name = (GString *)tokens->get(2);
+ if ((old = (GString *)cidToUnicodes->remove(collection))) {
+ delete old;
+ }
+ cidToUnicodes->add(collection->copy(), name->copy());
+}
+
+void GlobalParams::parseUnicodeToUnicode(GList *tokens, GString *fileName,
+ int line) {
+ GString *font, *file, *old;
+
+ if (tokens->getLength() != 3) {
+ error(-1, "Bad 'unicodeToUnicode' config file command (%s:%d)",
+ fileName->getCString(), line);
+ return;
+ }
+ font = (GString *)tokens->get(1);
+ file = (GString *)tokens->get(2);
+ if ((old = (GString *)unicodeToUnicodes->remove(font))) {
+ delete old;
+ }
+ unicodeToUnicodes->add(font->copy(), file->copy());
+}
+
+void GlobalParams::parseUnicodeMap(GList *tokens, GString *fileName,
+ int line) {
+ GString *encodingName, *name, *old;
+
+ if (tokens->getLength() != 3) {
+ error(-1, "Bad 'unicodeMap' config file command (%s:%d)",
+ fileName->getCString(), line);
+ return;
+ }
+ encodingName = (GString *)tokens->get(1);
+ name = (GString *)tokens->get(2);
+ if ((old = (GString *)unicodeMaps->remove(encodingName))) {
+ delete old;
+ }
+ unicodeMaps->add(encodingName->copy(), name->copy());
+}
+
+void GlobalParams::parseCMapDir(GList *tokens, GString *fileName, int line) {
+ GString *collection, *dir;
+ GList *list;
+
+ if (tokens->getLength() != 3) {
+ error(-1, "Bad 'cMapDir' config file command (%s:%d)",
+ fileName->getCString(), line);
+ return;
+ }
+ collection = (GString *)tokens->get(1);
+ dir = (GString *)tokens->get(2);
+ if (!(list = (GList *)cMapDirs->lookup(collection))) {
+ list = new GList();
+ cMapDirs->add(collection->copy(), list);
+ }
+ list->append(dir->copy());
+}
+
+void GlobalParams::parseToUnicodeDir(GList *tokens, GString *fileName,
+ int line) {
+ if (tokens->getLength() != 2) {
+ error(-1, "Bad 'toUnicodeDir' config file command (%s:%d)",
+ fileName->getCString(), line);
+ return;
+ }
+ toUnicodeDirs->append(((GString *)tokens->get(1))->copy());
+}
+
+void GlobalParams::parseDisplayFont(GList *tokens, GHash *fontHash,
+ DisplayFontParamKind kind,
+ GString *fileName, int line) {
+ DisplayFontParam *param, *old;
+ struct stat statbuf;
+
+ if (tokens->getLength() < 2) {
+ goto err1;
+ }
+ param = new DisplayFontParam(((GString *)tokens->get(1))->copy(), kind);
+
+ switch (kind) {
+ case displayFontT1:
+ if (tokens->getLength() != 3) {
+ goto err2;
+ }
+ param->t1.fileName = ((GString *)tokens->get(2))->copy();
+ if (stat((param->t1.fileName->getCString)(), &statbuf)) {
+ delete param; // silently ignore non-existing files
+ return;
+ }
+ break;
+ case displayFontTT:
+ if (tokens->getLength() < 3) {
+ goto err2;
+ }
+ param->tt.fileName = ((GString *)tokens->get(2))->copy();
+ if (stat((param->tt.fileName->getCString)(), &statbuf)) {
+ delete param; // silently ignore non-existing files
+ return;
+ }
+ if (tokens->getLength() > 3)
+ param->tt.faceIndex = atoi(((GString *)tokens->get(3))->getCString());
+ else
+ param->tt.faceIndex = 0;
+ break;
+ }
+
+ if ((old = (DisplayFontParam *)fontHash->remove(param->name))) {
+ delete old;
+ }
+ fontHash->add(param->name, param);
+ return;
+
+ err2:
+ delete param;
+ err1:
+ error(-1, "Bad 'display*Font*' config file command (%s:%d)",
+ fileName->getCString(), line);
+}
+
+void GlobalParams::parsePSPaperSize(GList *tokens, GString *fileName,
+ int line) {
+ GString *tok;
+
+ if (tokens->getLength() == 2) {
+ tok = (GString *)tokens->get(1);
+ if (!setPSPaperSize(tok->getCString())) {
+ error(-1, "Bad 'psPaperSize' config file command (%s:%d)",
+ fileName->getCString(), line);
+ }
+ } else if (tokens->getLength() == 3) {
+ tok = (GString *)tokens->get(1);
+ psPaperWidth = atoi(tok->getCString());
+ tok = (GString *)tokens->get(2);
+ psPaperHeight = atoi(tok->getCString());
+ psImageableLLX = psImageableLLY = 0;
+ psImageableURX = psPaperWidth;
+ psImageableURY = psPaperHeight;
+ } else {
+ error(-1, "Bad 'psPaperSize' config file command (%s:%d)",
+ fileName->getCString(), line);
+ }
+}
+
+void GlobalParams::parsePSImageableArea(GList *tokens, GString *fileName,
+ int line) {
+ if (tokens->getLength() != 5) {
+ error(-1, "Bad 'psImageableArea' config file command (%s:%d)",
+ fileName->getCString(), line);
+ return;
+ }
+ psImageableLLX = atoi(((GString *)tokens->get(1))->getCString());
+ psImageableLLY = atoi(((GString *)tokens->get(2))->getCString());
+ psImageableURX = atoi(((GString *)tokens->get(3))->getCString());
+ psImageableURY = atoi(((GString *)tokens->get(4))->getCString());
+}
+
+void GlobalParams::parsePSLevel(GList *tokens, GString *fileName, int line) {
+ GString *tok;
+
+ if (tokens->getLength() != 2) {
+ error(-1, "Bad 'psLevel' config file command (%s:%d)",
+ fileName->getCString(), line);
+ return;
+ }
+ tok = (GString *)tokens->get(1);
+ if (!tok->cmp("level1")) {
+ psLevel = psLevel1;
+ } else if (!tok->cmp("level1sep")) {
+ psLevel = psLevel1Sep;
+ } else if (!tok->cmp("level2")) {
+ psLevel = psLevel2;
+ } else if (!tok->cmp("level2sep")) {
+ psLevel = psLevel2Sep;
+ } else if (!tok->cmp("level3")) {
+ psLevel = psLevel3;
+ } else if (!tok->cmp("level3Sep")) {
+ psLevel = psLevel3Sep;
+ } else {
+ error(-1, "Bad 'psLevel' config file command (%s:%d)",
+ fileName->getCString(), line);
+ }
+}
+
+void GlobalParams::parsePSFile(GList *tokens, GString *fileName, int line) {
+ if (tokens->getLength() != 2) {
+ error(-1, "Bad 'psFile' config file command (%s:%d)",
+ fileName->getCString(), line);
+ return;
+ }
+ if (psFile) {
+ delete psFile;
+ }
+ psFile = ((GString *)tokens->get(1))->copy();
+}
+
+void GlobalParams::parsePSFont(GList *tokens, GString *fileName, int line) {
+ PSFontParam *param;
+
+ if (tokens->getLength() != 3) {
+ error(-1, "Bad 'psFont' config file command (%s:%d)",
+ fileName->getCString(), line);
+ return;
+ }
+ param = new PSFontParam(((GString *)tokens->get(1))->copy(), 0,
+ ((GString *)tokens->get(2))->copy(), NULL);
+ psFonts->add(param->pdfFontName, param);
+}
+
+void GlobalParams::parsePSFont16(char *cmdName, GList *fontList,
+ GList *tokens, GString *fileName, int line) {
+ PSFontParam *param;
+ int wMode;
+ GString *tok;
+
+ if (tokens->getLength() != 5) {
+ error(-1, "Bad '%s' config file command (%s:%d)",
+ cmdName, fileName->getCString(), line);
+ return;
+ }
+ tok = (GString *)tokens->get(2);
+ if (!tok->cmp("H")) {
+ wMode = 0;
+ } else if (!tok->cmp("V")) {
+ wMode = 1;
+ } else {
+ error(-1, "Bad '%s' config file command (%s:%d)",
+ cmdName, fileName->getCString(), line);
+ return;
+ }
+ param = new PSFontParam(((GString *)tokens->get(1))->copy(),
+ wMode,
+ ((GString *)tokens->get(3))->copy(),
+ ((GString *)tokens->get(4))->copy());
+ fontList->append(param);
+}
+
+void GlobalParams::parseTextEncoding(GList *tokens, GString *fileName,
+ int line) {
+ if (tokens->getLength() != 2) {
+ error(-1, "Bad 'textEncoding' config file command (%s:%d)",
+ fileName->getCString(), line);
+ return;
+ }
+ delete textEncoding;
+ textEncoding = ((GString *)tokens->get(1))->copy();
+}
+
+void GlobalParams::parseTextEOL(GList *tokens, GString *fileName, int line) {
+ GString *tok;
+
+ if (tokens->getLength() != 2) {
+ error(-1, "Bad 'textEOL' config file command (%s:%d)",
+ fileName->getCString(), line);
+ return;
+ }
+ tok = (GString *)tokens->get(1);
+ if (!tok->cmp("unix")) {
+ textEOL = eolUnix;
+ } else if (!tok->cmp("dos")) {
+ textEOL = eolDOS;
+ } else if (!tok->cmp("mac")) {
+ textEOL = eolMac;
+ } else {
+ error(-1, "Bad 'textEOL' config file command (%s:%d)",
+ fileName->getCString(), line);
+ }
+}
+
+void GlobalParams::parseFontDir(GList *tokens, GString *fileName, int line) {
+ if (tokens->getLength() != 2) {
+ error(-1, "Bad 'fontDir' config file command (%s:%d)",
+ fileName->getCString(), line);
+ return;
+ }
+ fontDirs->append(((GString *)tokens->get(1))->copy());
+}
+
+void GlobalParams::parseInitialZoom(GList *tokens,
+ GString *fileName, int line) {
+ if (tokens->getLength() != 2) {
+ error(-1, "Bad 'initialZoom' config file command (%s:%d)",
+ fileName->getCString(), line);
+ return;
+ }
+ delete initialZoom;
+ initialZoom = ((GString *)tokens->get(1))->copy();
+}
+
+void GlobalParams::parseScreenType(GList *tokens, GString *fileName,
+ int line) {
+ GString *tok;
+
+ if (tokens->getLength() != 2) {
+ error(-1, "Bad 'screenType' config file command (%s:%d)",
+ fileName->getCString(), line);
+ return;
+ }
+ tok = (GString *)tokens->get(1);
+ if (!tok->cmp("dispersed")) {
+ screenType = screenDispersed;
+ } else if (!tok->cmp("clustered")) {
+ screenType = screenClustered;
+ } else if (!tok->cmp("stochasticClustered")) {
+ screenType = screenStochasticClustered;
+ } else {
+ error(-1, "Bad 'screenType' config file command (%s:%d)",
+ fileName->getCString(), line);
+ }
+}
+
+void GlobalParams::parseBind(GList *tokens, GString *fileName, int line) {
+ KeyBinding *binding;
+ GList *cmds;
+ int code, mods, context, i;
+
+ if (tokens->getLength() < 4) {
+ error(-1, "Bad 'bind' config file command (%s:%d)",
+ fileName->getCString(), line);
+ return;
+ }
+ if (!parseKey((GString *)tokens->get(1), (GString *)tokens->get(2),
+ &code, &mods, &context,
+ "bind", tokens, fileName, line)) {
+ return;
+ }
+ for (i = 0; i < keyBindings->getLength(); ++i) {
+ binding = (KeyBinding *)keyBindings->get(i);
+ if (binding->code == code &&
+ binding->mods == mods &&
+ binding->context == context) {
+ delete (KeyBinding *)keyBindings->del(i);
+ break;
+ }
+ }
+ cmds = new GList();
+ for (i = 3; i < tokens->getLength(); ++i) {
+ cmds->append(((GString *)tokens->get(i))->copy());
+ }
+ keyBindings->append(new KeyBinding(code, mods, context, cmds));
+}
+
+void GlobalParams::parseUnbind(GList *tokens, GString *fileName, int line) {
+ KeyBinding *binding;
+ int code, mods, context, i;
+
+ if (tokens->getLength() != 3) {
+ error(-1, "Bad 'unbind' config file command (%s:%d)",
+ fileName->getCString(), line);
+ return;
+ }
+ if (!parseKey((GString *)tokens->get(1), (GString *)tokens->get(2),
+ &code, &mods, &context,
+ "unbind", tokens, fileName, line)) {
+ return;
+ }
+ for (i = 0; i < keyBindings->getLength(); ++i) {
+ binding = (KeyBinding *)keyBindings->get(i);
+ if (binding->code == code &&
+ binding->mods == mods &&
+ binding->context == context) {
+ delete (KeyBinding *)keyBindings->del(i);
+ break;
+ }
+ }
+}
+
+GBool GlobalParams::parseKey(GString *modKeyStr, GString *contextStr,
+ int *code, int *mods, int *context,
+ char *cmdName,
+ GList * /*tokens*/, GString *fileName, int line) {
+ char *p0;
+
+ *mods = xpdfKeyModNone;
+ p0 = modKeyStr->getCString();
+ while (1) {
+ if (!strncmp(p0, "shift-", 6)) {
+ *mods |= xpdfKeyModShift;
+ p0 += 6;
+ } else if (!strncmp(p0, "ctrl-", 5)) {
+ *mods |= xpdfKeyModCtrl;
+ p0 += 5;
+ } else if (!strncmp(p0, "alt-", 4)) {
+ *mods |= xpdfKeyModAlt;
+ p0 += 4;
+ } else {
+ break;
+ }
+ }
+
+ if (!strcmp(p0, "space")) {
+ *code = ' ';
+ } else if (!strcmp(p0, "tab")) {
+ *code = xpdfKeyCodeTab;
+ } else if (!strcmp(p0, "return")) {
+ *code = xpdfKeyCodeReturn;
+ } else if (!strcmp(p0, "enter")) {
+ *code = xpdfKeyCodeEnter;
+ } else if (!strcmp(p0, "backspace")) {
+ *code = xpdfKeyCodeBackspace;
+ } else if (!strcmp(p0, "insert")) {
+ *code = xpdfKeyCodeInsert;
+ } else if (!strcmp(p0, "delete")) {
+ *code = xpdfKeyCodeDelete;
+ } else if (!strcmp(p0, "home")) {
+ *code = xpdfKeyCodeHome;
+ } else if (!strcmp(p0, "end")) {
+ *code = xpdfKeyCodeEnd;
+ } else if (!strcmp(p0, "pgup")) {
+ *code = xpdfKeyCodePgUp;
+ } else if (!strcmp(p0, "pgdn")) {
+ *code = xpdfKeyCodePgDn;
+ } else if (!strcmp(p0, "left")) {
+ *code = xpdfKeyCodeLeft;
+ } else if (!strcmp(p0, "right")) {
+ *code = xpdfKeyCodeRight;
+ } else if (!strcmp(p0, "up")) {
+ *code = xpdfKeyCodeUp;
+ } else if (!strcmp(p0, "down")) {
+ *code = xpdfKeyCodeDown;
+ } else if (p0[0] == 'f' && p0[1] >= '1' && p0[1] <= '9' && !p0[2]) {
+ *code = xpdfKeyCodeF1 + (p0[1] - '1');
+ } else if (p0[0] == 'f' &&
+ ((p0[1] >= '1' && p0[1] <= '2' && p0[2] >= '0' && p0[2] <= '9') ||
+ (p0[1] == '3' && p0[2] >= '0' && p0[2] <= '5')) &&
+ !p0[3]) {
+ *code = xpdfKeyCodeF1 + 10 * (p0[1] - '0') + (p0[2] - '0') - 1;
+ } else if (!strncmp(p0, "mousePress", 10) &&
+ p0[10] >= '1' && p0[10] <= '7' && !p0[11]) {
+ *code = xpdfKeyCodeMousePress1 + (p0[10] - '1');
+ } else if (!strncmp(p0, "mouseRelease", 12) &&
+ p0[12] >= '1' && p0[12] <= '7' && !p0[13]) {
+ *code = xpdfKeyCodeMouseRelease1 + (p0[12] - '1');
+ } else if (*p0 >= 0x20 && *p0 <= 0x7e && !p0[1]) {
+ *code = (int)*p0;
+ } else {
+ error(-1, "Bad key/modifier in '%s' config file command (%s:%d)",
+ cmdName, fileName->getCString(), line);
+ return gFalse;
+ }
+
+ p0 = contextStr->getCString();
+ if (!strcmp(p0, "any")) {
+ *context = xpdfKeyContextAny;
+ } else {
+ *context = xpdfKeyContextAny;
+ while (1) {
+ if (!strncmp(p0, "fullScreen", 10)) {
+ *context |= xpdfKeyContextFullScreen;
+ p0 += 10;
+ } else if (!strncmp(p0, "window", 6)) {
+ *context |= xpdfKeyContextWindow;
+ p0 += 6;
+ } else if (!strncmp(p0, "continuous", 10)) {
+ *context |= xpdfKeyContextContinuous;
+ p0 += 10;
+ } else if (!strncmp(p0, "singlePage", 10)) {
+ *context |= xpdfKeyContextSinglePage;
+ p0 += 10;
+ } else if (!strncmp(p0, "overLink", 8)) {
+ *context |= xpdfKeyContextOverLink;
+ p0 += 8;
+ } else if (!strncmp(p0, "offLink", 7)) {
+ *context |= xpdfKeyContextOffLink;
+ p0 += 7;
+ } else if (!strncmp(p0, "outline", 7)) {
+ *context |= xpdfKeyContextOutline;
+ p0 += 7;
+ } else if (!strncmp(p0, "mainWin", 7)) {
+ *context |= xpdfKeyContextMainWin;
+ p0 += 7;
+ } else if (!strncmp(p0, "scrLockOn", 9)) {
+ *context |= xpdfKeyContextScrLockOn;
+ p0 += 9;
+ } else if (!strncmp(p0, "scrLockOff", 10)) {
+ *context |= xpdfKeyContextScrLockOff;
+ p0 += 10;
+ } else {
+ error(-1, "Bad context in '%s' config file command (%s:%d)",
+ cmdName, fileName->getCString(), line);
+ return gFalse;
+ }
+ if (!*p0) {
+ break;
+ }
+ if (*p0 != ',') {
+ error(-1, "Bad context in '%s' config file command (%s:%d)",
+ cmdName, fileName->getCString(), line);
+ return gFalse;
+ }
+ ++p0;
+ }
+ }
+
+ return gTrue;
+}
+
+void GlobalParams::parseCommand(char *cmdName, GString **val,
+ GList *tokens, GString *fileName, int line) {
+ if (tokens->getLength() != 2) {
+ error(-1, "Bad '%s' config file command (%s:%d)",
+ cmdName, fileName->getCString(), line);
+ return;
+ }
+ if (*val) {
+ delete *val;
+ }
+ *val = ((GString *)tokens->get(1))->copy();
+}
+
+void GlobalParams::parseYesNo(char *cmdName, GBool *flag,
+ GList *tokens, GString *fileName, int line) {
+ GString *tok;
+
+ if (tokens->getLength() != 2) {
+ error(-1, "Bad '%s' config file command (%s:%d)",
+ cmdName, fileName->getCString(), line);
+ return;
+ }
+ tok = (GString *)tokens->get(1);
+ if (!parseYesNo2(tok->getCString(), flag)) {
+ error(-1, "Bad '%s' config file command (%s:%d)",
+ cmdName, fileName->getCString(), line);
+ }
+}
+
+GBool GlobalParams::parseYesNo2(char *token, GBool *flag) {
+ if (!strcmp(token, "yes")) {
+ *flag = gTrue;
+ } else if (!strcmp(token, "no")) {
+ *flag = gFalse;
+ } else {
+ return gFalse;
+ }
+ return gTrue;
+}
+
+void GlobalParams::parseInteger(char *cmdName, int *val,
+ GList *tokens, GString *fileName, int line) {
+ GString *tok;
+ int i;
+
+ if (tokens->getLength() != 2) {
+ error(-1, "Bad '%s' config file command (%s:%d)",
+ cmdName, fileName->getCString(), line);
+ return;
+ }
+ tok = (GString *)tokens->get(1);
+ if (tok->getLength() == 0) {
+ error(-1, "Bad '%s' config file command (%s:%d)",
+ cmdName, fileName->getCString(), line);
+ return;
+ }
+ if (tok->getChar(0) == '-') {
+ i = 1;
+ } else {
+ i = 0;
+ }
+ for (; i < tok->getLength(); ++i) {
+ if (tok->getChar(i) < '0' || tok->getChar(i) > '9') {
+ error(-1, "Bad '%s' config file command (%s:%d)",
+ cmdName, fileName->getCString(), line);
+ return;
+ }
+ }
+ *val = atoi(tok->getCString());
+}
+
+void GlobalParams::parseFloat(char *cmdName, double *val,
+ GList *tokens, GString *fileName, int line) {
+ GString *tok;
+ int i;
+
+ if (tokens->getLength() != 2) {
+ error(-1, "Bad '%s' config file command (%s:%d)",
+ cmdName, fileName->getCString(), line);
+ return;
+ }
+ tok = (GString *)tokens->get(1);
+ if (tok->getLength() == 0) {
+ error(-1, "Bad '%s' config file command (%s:%d)",
+ cmdName, fileName->getCString(), line);
+ return;
+ }
+ if (tok->getChar(0) == '-') {
+ i = 1;
+ } else {
+ i = 0;
+ }
+ for (; i < tok->getLength(); ++i) {
+ if (!((tok->getChar(i) >= '0' && tok->getChar(i) <= '9') ||
+ tok->getChar(i) == '.')) {
+ error(-1, "Bad '%s' config file command (%s:%d)",
+ cmdName, fileName->getCString(), line);
+ return;
+ }
+ }
+ *val = atof(tok->getCString());
+}
+
+GlobalParams::~GlobalParams() {
+ GHashIter *iter;
+ GString *key;
+ GList *list;
+
+ freeBuiltinFontTables();
+
+ delete macRomanReverseMap;
+
+ delete baseDir;
+ delete nameToUnicode;
+ deleteGHash(cidToUnicodes, GString);
+ deleteGHash(unicodeToUnicodes, GString);
+ deleteGHash(residentUnicodeMaps, UnicodeMap);
+ deleteGHash(unicodeMaps, GString);
+ deleteGList(toUnicodeDirs, GString);
+ deleteGHash(displayFonts, DisplayFontParam);
+ deleteGHash(displayCIDFonts, DisplayFontParam);
+ deleteGHash(displayNamedCIDFonts, DisplayFontParam);
+#ifdef WIN32
+ if (winFontList) {
+ delete winFontList;
+ }
+#endif
+ if (psFile) {
+ delete psFile;
+ }
+ deleteGHash(psFonts, PSFontParam);
+ deleteGList(psNamedFonts16, PSFontParam);
+ deleteGList(psFonts16, PSFontParam);
+ delete textEncoding;
+ deleteGList(fontDirs, GString);
+ delete initialZoom;
+ if (urlCommand) {
+ delete urlCommand;
+ }
+ if (movieCommand) {
+ delete movieCommand;
+ }
+ deleteGList(keyBindings, KeyBinding);
+
+ cMapDirs->startIter(&iter);
+ while (cMapDirs->getNext(&iter, &key, (void **)&list)) {
+ deleteGList(list, GString);
+ }
+ delete cMapDirs;
+
+ delete cidToUnicodeCache;
+ delete unicodeToUnicodeCache;
+ delete unicodeMapCache;
+ delete cMapCache;
+
+#ifdef ENABLE_PLUGINS
+ delete securityHandlers;
+ deleteGList(plugins, Plugin);
+#endif
+
+#if MULTITHREADED
+ gDestroyMutex(&mutex);
+ gDestroyMutex(&unicodeMapCacheMutex);
+ gDestroyMutex(&cMapCacheMutex);
+#endif
+}
+
+//------------------------------------------------------------------------
+
+void GlobalParams::setBaseDir(char *dir) {
+ delete baseDir;
+ baseDir = new GString(dir);
+}
+
+void GlobalParams::setupBaseFonts(char *dir) {
+ GString *fontName;
+ GString *fileName;
+#ifdef WIN32
+ HMODULE shell32Lib;
+ BOOL (__stdcall *SHGetSpecialFolderPathFunc)(HWND hwndOwner,
+ LPTSTR lpszPath,
+ int nFolder,
+ BOOL fCreate);
+ char winFontDir[MAX_PATH];
+#endif
+ FILE *f;
+ DisplayFontParamKind kind;
+ DisplayFontParam *dfp;
+ int i, j;
+
+#ifdef WIN32
+ // SHGetSpecialFolderPath isn't available in older versions of
+ // shell32.dll (Win95 and WinNT4), so do a dynamic load
+ winFontDir[0] = '\0';
+ if ((shell32Lib = LoadLibrary("shell32.dll"))) {
+ if ((SHGetSpecialFolderPathFunc =
+ (BOOL (__stdcall *)(HWND hwndOwner, LPTSTR lpszPath,
+ int nFolder, BOOL fCreate))
+ GetProcAddress(shell32Lib, "SHGetSpecialFolderPathA"))) {
+ if (!(*SHGetSpecialFolderPathFunc)(NULL, winFontDir,
+ CSIDL_FONTS, FALSE)) {
+ winFontDir[0] = '\0';
+ }
+ }
+ }
+#endif
+ for (i = 0; displayFontTab[i].name; ++i) {
+ fontName = new GString(displayFontTab[i].name);
+ fileName = NULL;
+ kind = displayFontT1; // make gcc happy
+ if (dir) {
+ fileName = appendToPath(new GString(dir), displayFontTab[i].t1FileName);
+ kind = displayFontT1;
+ if ((f = fopen(fileName->getCString(), "rb"))) {
+ fclose(f);
+ } else {
+ delete fileName;
+ fileName = NULL;
+ }
+ }
+#ifdef WIN32
+ if (!fileName && winFontDir[0] && displayFontTab[i].ttFileName) {
+ fileName = appendToPath(new GString(winFontDir),
+ displayFontTab[i].ttFileName);
+ kind = displayFontTT;
+ if ((f = fopen(fileName->getCString(), "rb"))) {
+ fclose(f);
+ } else {
+ delete fileName;
+ fileName = NULL;
+ }
+ }
+ // SHGetSpecialFolderPath(CSIDL_FONTS) doesn't work on Win 2k Server
+ // or Win2003 Server, or with older versions of shell32.dll, so check
+ // the "standard" directories
+ if (displayFontTab[i].ttFileName) {
+ for (j = 0; !fileName && displayFontDirs[j]; ++j) {
+ fileName = appendToPath(new GString(displayFontDirs[j]),
+ displayFontTab[i].ttFileName);
+ kind = displayFontTT;
+ if ((f = fopen(fileName->getCString(), "rb"))) {
+ fclose(f);
+ } else {
+ delete fileName;
+ fileName = NULL;
+ }
+ }
+ }
+#else
+ for (j = 0; !fileName && displayFontDirs[j]; ++j) {
+ fileName = appendToPath(new GString(displayFontDirs[j]),
+ displayFontTab[i].t1FileName);
+ kind = displayFontT1;
+ if ((f = fopen(fileName->getCString(), "rb"))) {
+ fclose(f);
+ } else {
+ delete fileName;
+ fileName = NULL;
+ }
+ }
+#endif
+ if (!fileName) {
+ error(-1, "No display font for '%s'", displayFontTab[i].name);
+ delete fontName;
+ continue;
+ }
+ dfp = new DisplayFontParam(fontName, kind);
+ dfp->t1.fileName = fileName;
+ globalParams->addDisplayFont(dfp);
+ }
+
+#ifdef WIN32
+ if (winFontDir[0]) {
+ winFontList = new WinFontList(winFontDir);
+ }
+#endif
+}
+
+//------------------------------------------------------------------------
+// accessors
+//------------------------------------------------------------------------
+
+CharCode GlobalParams::getMacRomanCharCode(char *charName) {
+ // no need to lock - macRomanReverseMap is constant
+ return macRomanReverseMap->lookup(charName);
+}
+
+GString *GlobalParams::getBaseDir() {
+ GString *s;
+
+ lockGlobalParams;
+ s = baseDir->copy();
+ unlockGlobalParams;
+ return s;
+}
+
+Unicode GlobalParams::mapNameToUnicode(char *charName) {
+ // no need to lock - nameToUnicode is constant
+ return nameToUnicode->lookup(charName);
+}
+
+UnicodeMap *GlobalParams::getResidentUnicodeMap(GString *encodingName) {
+ UnicodeMap *map;
+
+ lockGlobalParams;
+ map = (UnicodeMap *)residentUnicodeMaps->lookup(encodingName);
+ unlockGlobalParams;
+ if (map) {
+ map->incRefCnt();
+ }
+ return map;
+}
+
+FILE *GlobalParams::getUnicodeMapFile(GString *encodingName) {
+ GString *fileName;
+ FILE *f;
+
+ lockGlobalParams;
+ if ((fileName = (GString *)unicodeMaps->lookup(encodingName))) {
+ f = fopen(fileName->getCString(), "r");
+ } else {
+ f = NULL;
+ }
+ unlockGlobalParams;
+ return f;
+}
+
+FILE *GlobalParams::findCMapFile(GString *collection, GString *cMapName) {
+ GList *list;
+ GString *dir;
+ GString *fileName;
+ FILE *f;
+ int i;
+
+ lockGlobalParams;
+ if (!(list = (GList *)cMapDirs->lookup(collection))) {
+ unlockGlobalParams;
+ return NULL;
+ }
+ for (i = 0; i < list->getLength(); ++i) {
+ dir = (GString *)list->get(i);
+ fileName = appendToPath(dir->copy(), cMapName->getCString());
+ f = fopen(fileName->getCString(), "r");
+ delete fileName;
+ if (f) {
+ unlockGlobalParams;
+ return f;
+ }
+ }
+ unlockGlobalParams;
+ return NULL;
+}
+
+FILE *GlobalParams::findToUnicodeFile(GString *name) {
+ GString *dir, *fileName;
+ FILE *f;
+ int i;
+
+ lockGlobalParams;
+ for (i = 0; i < toUnicodeDirs->getLength(); ++i) {
+ dir = (GString *)toUnicodeDirs->get(i);
+ fileName = appendToPath(dir->copy(), name->getCString());
+ f = fopen(fileName->getCString(), "r");
+ delete fileName;
+ if (f) {
+ unlockGlobalParams;
+ return f;
+ }
+ }
+ unlockGlobalParams;
+ return NULL;
+}
+
+// KPDF: parse xpdf font name into family and style
+// Helvetica-BoldOblique => name=Helvetica, weight=Bold, slant=Oblique
+
+void parseStyle(QString& name, int& weight, int& slant, int& width)
+{
+ if (name.find("MS-") == 0) name = "MS " + name.remove(0,3);
+
+ if (!name.contains('-') && !name.contains(',')) return;
+ QString type = name.section(QRegExp("[-,]"),-1);
+ name = name.section(QRegExp("[-,]"),0,-2);
+ if (type.contains("Oblique")) slant=FC_SLANT_OBLIQUE;
+ if (type.contains("Italic")) slant=FC_SLANT_ITALIC;
+ if (type.contains("Bold")) weight=FC_WEIGHT_BOLD;
+ if (type.contains("Light")) weight=FC_WEIGHT_LIGHT;
+ if (type.contains("Condensed")) width=FC_WIDTH_CONDENSED;
+}
+
+DisplayFontParam *GlobalParams::getDisplayFont(GString *fontName) {
+ DisplayFontParam *dfp;
+ FcPattern *p=0,*m=0;
+ FcChar8* s;
+ char * ext;
+ FcResult res;
+
+ lockGlobalParams;
+ dfp = (DisplayFontParam *)displayFonts->lookup(fontName);
+ // KPDF: try to find font using Xft
+ if (!dfp) {
+ int weight=FC_WEIGHT_MEDIUM, slant=FC_SLANT_ROMAN, width=FC_WIDTH_NORMAL;
+ QString name(fontName->getCString());
+
+ parseStyle(name,weight,slant,width);
+ p = FcPatternBuild(0,FC_FAMILY,FcTypeString, name.ascii(),
+ FC_SLANT, FcTypeInteger, slant, FC_WEIGHT, FcTypeInteger, weight,
+ FC_WIDTH, FcTypeInteger, width, FC_LANG, FcTypeString, "xx", (char*)0);
+ if (!p) goto fin;
+ m = XftFontMatch(qt_xdisplay(),qt_xscreen(),p,&res);
+ if (!m) goto fin;
+ res = FcPatternGetString (m, FC_FILE, 0, &s);
+ if (res != FcResultMatch || !s) goto fin;
+ ext = rindex((char*)s,'.');
+ if (!ext) goto fin;
+ if (!strncasecmp(ext,".ttf",4) || !strncasecmp(ext,".ttc",4)) {
+ dfp = new DisplayFontParam(fontName->copy(), displayFontTT);
+ dfp->tt.fileName = new GString((char*)s);
+ FcPatternGetInteger(m, FC_INDEX, 0, &(dfp->tt.faceIndex));
+ } else if (!strncasecmp(ext,".pfa",4) || !strncasecmp(ext,".pfb",4)) {
+ dfp = new DisplayFontParam(fontName->copy(), displayFontT1);
+ dfp->t1.fileName = new GString((char*)s);
+ } else goto fin;
+ displayFonts->add(dfp->name,dfp);
+ }
+fin: unlockGlobalParams;
+ if (m) FcPatternDestroy(m);
+ if (p) FcPatternDestroy(p);
+ return dfp;
+}
+
+DisplayFontParam *GlobalParams::getDisplayCIDFont(GString *fontName,
+ GString *collection) {
+ DisplayFontParam *dfp;
+
+ lockGlobalParams;
+ if (!fontName ||
+ !(dfp = (DisplayFontParam *)displayNamedCIDFonts->lookup(fontName))) {
+ dfp = (DisplayFontParam *)displayCIDFonts->lookup(collection);
+ }
+ unlockGlobalParams;
+ if (!dfp) dfp = getDisplayFont(fontName);
+ return dfp;
+}
+
+GString *GlobalParams::getPSFile() {
+ GString *s;
+
+ lockGlobalParams;
+ s = psFile ? psFile->copy() : (GString *)NULL;
+ unlockGlobalParams;
+ return s;
+}
+
+int GlobalParams::getPSPaperWidth() {
+ int w;
+
+ lockGlobalParams;
+ w = psPaperWidth;
+ unlockGlobalParams;
+ return w;
+}
+
+int GlobalParams::getPSPaperHeight() {
+ int h;
+
+ lockGlobalParams;
+ h = psPaperHeight;
+ unlockGlobalParams;
+ return h;
+}
+
+void GlobalParams::getPSImageableArea(int *llx, int *lly, int *urx, int *ury) {
+ lockGlobalParams;
+ *llx = psImageableLLX;
+ *lly = psImageableLLY;
+ *urx = psImageableURX;
+ *ury = psImageableURY;
+ unlockGlobalParams;
+}
+
+GBool GlobalParams::getPSCrop() {
+ GBool f;
+
+ lockGlobalParams;
+ f = psCrop;
+ unlockGlobalParams;
+ return f;
+}
+
+GBool GlobalParams::getPSExpandSmaller() {
+ GBool f;
+
+ lockGlobalParams;
+ f = psExpandSmaller;
+ unlockGlobalParams;
+ return f;
+}
+
+GBool GlobalParams::getPSShrinkLarger() {
+ GBool f;
+
+ lockGlobalParams;
+ f = psShrinkLarger;
+ unlockGlobalParams;
+ return f;
+}
+
+GBool GlobalParams::getPSCenter() {
+ GBool f;
+
+ lockGlobalParams;
+ f = psCenter;
+ unlockGlobalParams;
+ return f;
+}
+
+GBool GlobalParams::getPSDuplex() {
+ GBool d;
+
+ lockGlobalParams;
+ d = psDuplex;
+ unlockGlobalParams;
+ return d;
+}
+
+PSLevel GlobalParams::getPSLevel() {
+ PSLevel level;
+
+ lockGlobalParams;
+ level = psLevel;
+ unlockGlobalParams;
+ return level;
+}
+
+PSFontParam *GlobalParams::getPSFont(GString *fontName) {
+ PSFontParam *p;
+
+ lockGlobalParams;
+ p = (PSFontParam *)psFonts->lookup(fontName);
+ unlockGlobalParams;
+ return p;
+}
+
+PSFontParam *GlobalParams::getPSFont16(GString *fontName,
+ GString *collection, int wMode) {
+ PSFontParam *p;
+ int i;
+
+ lockGlobalParams;
+ p = NULL;
+ if (fontName) {
+ for (i = 0; i < psNamedFonts16->getLength(); ++i) {
+ p = (PSFontParam *)psNamedFonts16->get(i);
+ if (!p->pdfFontName->cmp(fontName) &&
+ p->wMode == wMode) {
+ break;
+ }
+ p = NULL;
+ }
+ }
+ if (!p && collection) {
+ for (i = 0; i < psFonts16->getLength(); ++i) {
+ p = (PSFontParam *)psFonts16->get(i);
+ if (!p->pdfFontName->cmp(collection) &&
+ p->wMode == wMode) {
+ break;
+ }
+ p = NULL;
+ }
+ }
+ unlockGlobalParams;
+ return p;
+}
+
+GBool GlobalParams::getPSEmbedType1() {
+ GBool e;
+
+ lockGlobalParams;
+ e = psEmbedType1;
+ unlockGlobalParams;
+ return e;
+}
+
+GBool GlobalParams::getPSEmbedTrueType() {
+ GBool e;
+
+ lockGlobalParams;
+ e = psEmbedTrueType;
+ unlockGlobalParams;
+ return e;
+}
+
+GBool GlobalParams::getPSEmbedCIDPostScript() {
+ GBool e;
+
+ lockGlobalParams;
+ e = psEmbedCIDPostScript;
+ unlockGlobalParams;
+ return e;
+}
+
+GBool GlobalParams::getPSEmbedCIDTrueType() {
+ GBool e;
+
+ lockGlobalParams;
+ e = psEmbedCIDTrueType;
+ unlockGlobalParams;
+ return e;
+}
+
+GBool GlobalParams::getPSPreload() {
+ GBool preload;
+
+ lockGlobalParams;
+ preload = psPreload;
+ unlockGlobalParams;
+ return preload;
+}
+
+GBool GlobalParams::getPSOPI() {
+ GBool opi;
+
+ lockGlobalParams;
+ opi = psOPI;
+ unlockGlobalParams;
+ return opi;
+}
+
+GBool GlobalParams::getPSASCIIHex() {
+ GBool ah;
+
+ lockGlobalParams;
+ ah = psASCIIHex;
+ unlockGlobalParams;
+ return ah;
+}
+
+GString *GlobalParams::getTextEncodingName() {
+ GString *s;
+
+ lockGlobalParams;
+ s = textEncoding->copy();
+ unlockGlobalParams;
+ return s;
+}
+
+EndOfLineKind GlobalParams::getTextEOL() {
+ EndOfLineKind eol;
+
+ lockGlobalParams;
+ eol = textEOL;
+ unlockGlobalParams;
+ return eol;
+}
+
+GBool GlobalParams::getTextPageBreaks() {
+ GBool pageBreaks;
+
+ lockGlobalParams;
+ pageBreaks = textPageBreaks;
+ unlockGlobalParams;
+ return pageBreaks;
+}
+
+GBool GlobalParams::getTextKeepTinyChars() {
+ GBool tiny;
+
+ lockGlobalParams;
+ tiny = textKeepTinyChars;
+ unlockGlobalParams;
+ return tiny;
+}
+
+GString *GlobalParams::findFontFile(GString *fontName, char **exts) {
+ GString *dir, *fileName;
+ char **ext;
+ FILE *f;
+ int i;
+
+ lockGlobalParams;
+ for (i = 0; i < fontDirs->getLength(); ++i) {
+ dir = (GString *)fontDirs->get(i);
+ for (ext = exts; *ext; ++ext) {
+ fileName = appendToPath(dir->copy(), fontName->getCString());
+ fileName->append(*ext);
+ if ((f = fopen(fileName->getCString(), "rb"))) {
+ fclose(f);
+ unlockGlobalParams;
+ return fileName;
+ }
+ delete fileName;
+ }
+ }
+ unlockGlobalParams;
+ return NULL;
+}
+
+GString *GlobalParams::getInitialZoom() {
+ GString *s;
+
+ lockGlobalParams;
+ s = initialZoom->copy();
+ unlockGlobalParams;
+ return s;
+}
+
+GBool GlobalParams::getContinuousView() {
+ GBool f;
+
+ lockGlobalParams;
+ f = continuousView;
+ unlockGlobalParams;
+ return f;
+}
+
+GBool GlobalParams::getEnableT1lib() {
+ GBool f;
+
+ lockGlobalParams;
+ f = enableT1lib;
+ unlockGlobalParams;
+ return f;
+}
+
+GBool GlobalParams::getEnableFreeType() {
+ GBool f;
+
+ lockGlobalParams;
+ f = enableFreeType;
+ unlockGlobalParams;
+ return f;
+}
+
+
+GBool GlobalParams::getAntialias() {
+ GBool f;
+
+ lockGlobalParams;
+ f = antialias;
+ unlockGlobalParams;
+ return f;
+}
+
+GBool GlobalParams::getVectorAntialias() {
+ GBool f;
+
+ lockGlobalParams;
+ f = vectorAntialias;
+ unlockGlobalParams;
+ return f;
+}
+
+GBool GlobalParams::getStrokeAdjust() {
+ GBool f;
+
+ lockGlobalParams;
+ f = strokeAdjust;
+ unlockGlobalParams;
+ return f;
+}
+
+ScreenType GlobalParams::getScreenType() {
+ ScreenType t;
+
+ lockGlobalParams;
+ t = screenType;
+ unlockGlobalParams;
+ return t;
+}
+
+int GlobalParams::getScreenSize() {
+ int size;
+
+ lockGlobalParams;
+ size = screenSize;
+ unlockGlobalParams;
+ return size;
+}
+
+int GlobalParams::getScreenDotRadius() {
+ int r;
+
+ lockGlobalParams;
+ r = screenDotRadius;
+ unlockGlobalParams;
+ return r;
+}
+
+double GlobalParams::getScreenGamma() {
+ double gamma;
+
+ lockGlobalParams;
+ gamma = screenGamma;
+ unlockGlobalParams;
+ return gamma;
+}
+
+double GlobalParams::getScreenBlackThreshold() {
+ double thresh;
+
+ lockGlobalParams;
+ thresh = screenBlackThreshold;
+ unlockGlobalParams;
+ return thresh;
+}
+
+double GlobalParams::getScreenWhiteThreshold() {
+ double thresh;
+
+ lockGlobalParams;
+ thresh = screenWhiteThreshold;
+ unlockGlobalParams;
+ return thresh;
+}
+
+GBool GlobalParams::getMapNumericCharNames() {
+ GBool map;
+
+ lockGlobalParams;
+ map = mapNumericCharNames;
+ unlockGlobalParams;
+ return map;
+}
+
+GBool GlobalParams::getMapUnknownCharNames() {
+ GBool map;
+
+ lockGlobalParams;
+ map = mapUnknownCharNames;
+ unlockGlobalParams;
+ return map;
+}
+
+GList *GlobalParams::getKeyBinding(int code, int mods, int context) {
+ KeyBinding *binding;
+ GList *cmds;
+ int modMask;
+ int i, j;
+
+ lockGlobalParams;
+ cmds = NULL;
+ // for ASCII chars, ignore the shift modifier
+ modMask = code <= 0xff ? ~xpdfKeyModShift : ~0;
+ for (i = 0; i < keyBindings->getLength(); ++i) {
+ binding = (KeyBinding *)keyBindings->get(i);
+ if (binding->code == code &&
+ (binding->mods & modMask) == (mods & modMask) &&
+ (~binding->context | context) == ~0) {
+ cmds = new GList();
+ for (j = 0; j < binding->cmds->getLength(); ++j) {
+ cmds->append(((GString *)binding->cmds->get(j))->copy());
+ }
+ break;
+ }
+ }
+ unlockGlobalParams;
+ return cmds;
+}
+
+GBool GlobalParams::getPrintCommands() {
+ GBool p;
+
+ lockGlobalParams;
+ p = printCommands;
+ unlockGlobalParams;
+ return p;
+}
+
+GBool GlobalParams::getErrQuiet() {
+ // no locking -- this function may get called from inside a locked
+ // section
+ return errQuiet;
+}
+
+CharCodeToUnicode *GlobalParams::getCIDToUnicode(GString *collection) {
+ GString *fileName;
+ CharCodeToUnicode *ctu;
+
+ lockGlobalParams;
+ if (!(ctu = cidToUnicodeCache->getCharCodeToUnicode(collection))) {
+ if ((fileName = (GString *)cidToUnicodes->lookup(collection)) &&
+ (ctu = CharCodeToUnicode::parseCIDToUnicode(fileName, collection))) {
+ cidToUnicodeCache->add(ctu);
+ }
+ }
+ unlockGlobalParams;
+ return ctu;
+}
+
+CharCodeToUnicode *GlobalParams::getUnicodeToUnicode(GString *fontName) {
+ CharCodeToUnicode *ctu;
+ GHashIter *iter;
+ GString *fontPattern, *fileName;
+
+ lockGlobalParams;
+ fileName = NULL;
+ unicodeToUnicodes->startIter(&iter);
+ while (unicodeToUnicodes->getNext(&iter, &fontPattern, (void **)&fileName)) {
+ if (strstr(fontName->getCString(), fontPattern->getCString())) {
+ unicodeToUnicodes->killIter(&iter);
+ break;
+ }
+ fileName = NULL;
+ }
+ if (fileName) {
+ if (!(ctu = unicodeToUnicodeCache->getCharCodeToUnicode(fileName))) {
+ if ((ctu = CharCodeToUnicode::parseUnicodeToUnicode(fileName))) {
+ unicodeToUnicodeCache->add(ctu);
+ }
+ }
+ } else {
+ ctu = NULL;
+ }
+ unlockGlobalParams;
+ return ctu;
+}
+
+UnicodeMap *GlobalParams::getUnicodeMap(GString *encodingName) {
+ return getUnicodeMap2(encodingName);
+}
+
+UnicodeMap *GlobalParams::getUnicodeMap2(GString *encodingName) {
+ UnicodeMap *map;
+
+ if (!(map = getResidentUnicodeMap(encodingName))) {
+ lockUnicodeMapCache;
+ map = unicodeMapCache->getUnicodeMap(encodingName);
+ unlockUnicodeMapCache;
+ }
+ return map;
+}
+
+CMap *GlobalParams::getCMap(GString *collection, GString *cMapName) {
+ CMap *cMap;
+
+ lockCMapCache;
+ cMap = cMapCache->getCMap(collection, cMapName);
+ unlockCMapCache;
+ return cMap;
+}
+
+UnicodeMap *GlobalParams::getTextEncoding() {
+ return getUnicodeMap2(textEncoding);
+}
+
+//------------------------------------------------------------------------
+// functions to set parameters
+//------------------------------------------------------------------------
+
+void GlobalParams::addDisplayFont(DisplayFontParam *param) {
+ DisplayFontParam *old;
+
+ lockGlobalParams;
+ if ((old = (DisplayFontParam *)displayFonts->remove(param->name))) {
+ delete old;
+ }
+ displayFonts->add(param->name, param);
+ unlockGlobalParams;
+}
+
+void GlobalParams::setPSFile(char *file) {
+ lockGlobalParams;
+ if (psFile) {
+ delete psFile;
+ }
+ psFile = new GString(file);
+ unlockGlobalParams;
+}
+
+GBool GlobalParams::setPSPaperSize(char *size) {
+ lockGlobalParams;
+ if (!strcmp(size, "match")) {
+ psPaperWidth = psPaperHeight = -1;
+ } else if (!strcmp(size, "letter")) {
+ psPaperWidth = 612;
+ psPaperHeight = 792;
+ } else if (!strcmp(size, "legal")) {
+ psPaperWidth = 612;
+ psPaperHeight = 1008;
+ } else if (!strcmp(size, "A4")) {
+ psPaperWidth = 595;
+ psPaperHeight = 842;
+ } else if (!strcmp(size, "A3")) {
+ psPaperWidth = 842;
+ psPaperHeight = 1190;
+ } else {
+ unlockGlobalParams;
+ return gFalse;
+ }
+ psImageableLLX = psImageableLLY = 0;
+ psImageableURX = psPaperWidth;
+ psImageableURY = psPaperHeight;
+ unlockGlobalParams;
+ return gTrue;
+}
+
+void GlobalParams::setPSPaperWidth(int width) {
+ lockGlobalParams;
+ psPaperWidth = width;
+ psImageableLLX = 0;
+ psImageableURX = psPaperWidth;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setPSPaperHeight(int height) {
+ lockGlobalParams;
+ psPaperHeight = height;
+ psImageableLLY = 0;
+ psImageableURY = psPaperHeight;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setPSImageableArea(int llx, int lly, int urx, int ury) {
+ lockGlobalParams;
+ psImageableLLX = llx;
+ psImageableLLY = lly;
+ psImageableURX = urx;
+ psImageableURY = ury;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setPSCrop(GBool crop) {
+ lockGlobalParams;
+ psCrop = crop;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setPSExpandSmaller(GBool expand) {
+ lockGlobalParams;
+ psExpandSmaller = expand;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setPSShrinkLarger(GBool shrink) {
+ lockGlobalParams;
+ psShrinkLarger = shrink;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setPSCenter(GBool center) {
+ lockGlobalParams;
+ psCenter = center;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setPSDuplex(GBool duplex) {
+ lockGlobalParams;
+ psDuplex = duplex;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setPSLevel(PSLevel level) {
+ lockGlobalParams;
+ psLevel = level;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setPSEmbedType1(GBool embed) {
+ lockGlobalParams;
+ psEmbedType1 = embed;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setPSEmbedTrueType(GBool embed) {
+ lockGlobalParams;
+ psEmbedTrueType = embed;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setPSEmbedCIDPostScript(GBool embed) {
+ lockGlobalParams;
+ psEmbedCIDPostScript = embed;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setPSEmbedCIDTrueType(GBool embed) {
+ lockGlobalParams;
+ psEmbedCIDTrueType = embed;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setPSPreload(GBool preload) {
+ lockGlobalParams;
+ psPreload = preload;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setPSOPI(GBool opi) {
+ lockGlobalParams;
+ psOPI = opi;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setPSASCIIHex(GBool hex) {
+ lockGlobalParams;
+ psASCIIHex = hex;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setTextEncoding(char *encodingName) {
+ lockGlobalParams;
+ delete textEncoding;
+ textEncoding = new GString(encodingName);
+ unlockGlobalParams;
+}
+
+GBool GlobalParams::setTextEOL(char *s) {
+ lockGlobalParams;
+ if (!strcmp(s, "unix")) {
+ textEOL = eolUnix;
+ } else if (!strcmp(s, "dos")) {
+ textEOL = eolDOS;
+ } else if (!strcmp(s, "mac")) {
+ textEOL = eolMac;
+ } else {
+ unlockGlobalParams;
+ return gFalse;
+ }
+ unlockGlobalParams;
+ return gTrue;
+}
+
+void GlobalParams::setTextPageBreaks(GBool pageBreaks) {
+ lockGlobalParams;
+ textPageBreaks = pageBreaks;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setTextKeepTinyChars(GBool keep) {
+ lockGlobalParams;
+ textKeepTinyChars = keep;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setInitialZoom(char *s) {
+ lockGlobalParams;
+ delete initialZoom;
+ initialZoom = new GString(s);
+ unlockGlobalParams;
+}
+
+void GlobalParams::setContinuousView(GBool cont) {
+ lockGlobalParams;
+ continuousView = cont;
+ unlockGlobalParams;
+}
+
+GBool GlobalParams::setEnableT1lib(char *s) {
+ GBool ok;
+
+ lockGlobalParams;
+ ok = parseYesNo2(s, &enableT1lib);
+ unlockGlobalParams;
+ return ok;
+}
+
+GBool GlobalParams::setEnableFreeType(char *s) {
+ GBool ok;
+
+ lockGlobalParams;
+ ok = parseYesNo2(s, &enableFreeType);
+ unlockGlobalParams;
+ return ok;
+}
+
+
+GBool GlobalParams::setAntialias(char *s) {
+ GBool ok;
+
+ lockGlobalParams;
+ ok = parseYesNo2(s, &antialias);
+ unlockGlobalParams;
+ return ok;
+}
+
+GBool GlobalParams::setVectorAntialias(char *s) {
+ GBool ok;
+
+ lockGlobalParams;
+ ok = parseYesNo2(s, &vectorAntialias);
+ unlockGlobalParams;
+ return ok;
+}
+
+void GlobalParams::setScreenType(ScreenType t) {
+ lockGlobalParams;
+ screenType = t;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setScreenSize(int size) {
+ lockGlobalParams;
+ screenSize = size;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setScreenDotRadius(int r) {
+ lockGlobalParams;
+ screenDotRadius = r;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setScreenGamma(double gamma) {
+ lockGlobalParams;
+ screenGamma = gamma;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setScreenBlackThreshold(double thresh) {
+ lockGlobalParams;
+ screenBlackThreshold = thresh;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setScreenWhiteThreshold(double thresh) {
+ lockGlobalParams;
+ screenWhiteThreshold = thresh;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setMapNumericCharNames(GBool map) {
+ lockGlobalParams;
+ mapNumericCharNames = map;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setMapUnknownCharNames(GBool map) {
+ lockGlobalParams;
+ mapUnknownCharNames = map;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setPrintCommands(GBool printCommandsA) {
+ lockGlobalParams;
+ printCommands = printCommandsA;
+ unlockGlobalParams;
+}
+
+void GlobalParams::setErrQuiet(GBool errQuietA) {
+ lockGlobalParams;
+ errQuiet = errQuietA;
+ unlockGlobalParams;
+}
+
+void GlobalParams::addSecurityHandler(XpdfSecurityHandler *handler) {
+#ifdef ENABLE_PLUGINS
+ lockGlobalParams;
+ securityHandlers->append(handler);
+ unlockGlobalParams;
+#else
+ (void)handler;
+#endif
+}
+
+XpdfSecurityHandler *GlobalParams::getSecurityHandler(char *name) {
+#ifdef ENABLE_PLUGINS
+ XpdfSecurityHandler *hdlr;
+ int i;
+
+ lockGlobalParams;
+ for (i = 0; i < securityHandlers->getLength(); ++i) {
+ hdlr = (XpdfSecurityHandler *)securityHandlers->get(i);
+ if (!strcasecmp(hdlr->name, name)) {
+ unlockGlobalParams;
+ return hdlr;
+ }
+ }
+ unlockGlobalParams;
+
+ if (!loadPlugin("security", name)) {
+ return NULL;
+ }
+
+ lockGlobalParams;
+ for (i = 0; i < securityHandlers->getLength(); ++i) {
+ hdlr = (XpdfSecurityHandler *)securityHandlers->get(i);
+ if (!strcmp(hdlr->name, name)) {
+ unlockGlobalParams;
+ return hdlr;
+ }
+ }
+ unlockGlobalParams;
+#else
+ (void)name;
+#endif
+
+ return NULL;
+}
+
+#ifdef ENABLE_PLUGINS
+//------------------------------------------------------------------------
+// plugins
+//------------------------------------------------------------------------
+
+GBool GlobalParams::loadPlugin(char *type, char *name) {
+ Plugin *plugin;
+
+ if (!(plugin = Plugin::load(type, name))) {
+ return gFalse;
+ }
+ lockGlobalParams;
+ plugins->append(plugin);
+ unlockGlobalParams;
+ return gTrue;
+}
+
+#endif // ENABLE_PLUGINS
diff --git a/kpdf/xpdf/xpdf/GlobalParams.h b/kpdf/xpdf/xpdf/GlobalParams.h
new file mode 100644
index 00000000..c0543eda
--- /dev/null
+++ b/kpdf/xpdf/xpdf/GlobalParams.h
@@ -0,0 +1,464 @@
+//========================================================================
+//
+// GlobalParams.h
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef GLOBALPARAMS_H
+#define GLOBALPARAMS_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include <stdio.h>
+#include "gtypes.h"
+#include "CharTypes.h"
+
+#if MULTITHREADED
+#include "GMutex.h"
+#endif
+
+class GString;
+class GList;
+class GHash;
+class NameToCharCode;
+class CharCodeToUnicode;
+class CharCodeToUnicodeCache;
+class UnicodeMap;
+class UnicodeMapCache;
+class CMap;
+class CMapCache;
+struct XpdfSecurityHandler;
+class GlobalParams;
+#ifdef WIN32
+class WinFontList;
+#endif
+
+//------------------------------------------------------------------------
+
+// The global parameters object.
+extern GlobalParams *globalParams;
+
+//------------------------------------------------------------------------
+
+enum DisplayFontParamKind {
+ displayFontT1,
+ displayFontTT
+};
+
+struct DisplayFontParamT1 {
+ GString *fileName;
+};
+
+struct DisplayFontParamTT {
+ GString *fileName;
+ int faceIndex;
+};
+
+class DisplayFontParam {
+public:
+
+ GString *name; // font name for 8-bit fonts and named
+ // CID fonts; collection name for
+ // generic CID fonts
+ DisplayFontParamKind kind;
+ union {
+ DisplayFontParamT1 t1;
+ DisplayFontParamTT tt;
+ };
+
+ DisplayFontParam(GString *nameA, DisplayFontParamKind kindA);
+ virtual ~DisplayFontParam();
+};
+
+//------------------------------------------------------------------------
+
+class PSFontParam {
+public:
+
+ GString *pdfFontName; // PDF font name for 8-bit fonts and
+ // named 16-bit fonts; char collection
+ // name for generic 16-bit fonts
+ int wMode; // writing mode (0=horiz, 1=vert) for
+ // 16-bit fonts
+ GString *psFontName; // PostScript font name
+ GString *encoding; // encoding, for 16-bit fonts only
+
+ PSFontParam(GString *pdfFontNameA, int wModeA,
+ GString *psFontNameA, GString *encodingA);
+ ~PSFontParam();
+};
+
+//------------------------------------------------------------------------
+
+enum PSLevel {
+ psLevel1,
+ psLevel1Sep,
+ psLevel2,
+ psLevel2Sep,
+ psLevel3,
+ psLevel3Sep
+};
+
+//------------------------------------------------------------------------
+
+enum EndOfLineKind {
+ eolUnix, // LF
+ eolDOS, // CR+LF
+ eolMac // CR
+};
+
+//------------------------------------------------------------------------
+
+enum ScreenType {
+ screenUnset,
+ screenDispersed,
+ screenClustered,
+ screenStochasticClustered
+};
+
+//------------------------------------------------------------------------
+
+class KeyBinding {
+public:
+
+ int code; // 0x20 .. 0xfe = ASCII,
+ // >=0x10000 = special keys, mouse buttons,
+ // etc. (xpdfKeyCode* symbols)
+ int mods; // modifiers (xpdfKeyMod* symbols, or-ed
+ // together)
+ int context; // context (xpdfKeyContext* symbols, or-ed
+ // together)
+ GList *cmds; // list of commands [GString]
+
+ KeyBinding(int codeA, int modsA, int contextA, char *cmd0);
+ KeyBinding(int codeA, int modsA, int contextA, char *cmd0, char *cmd1);
+ KeyBinding(int codeA, int modsA, int contextA, GList *cmdsA);
+ ~KeyBinding();
+};
+
+#define xpdfKeyCodeTab 0x1000
+#define xpdfKeyCodeReturn 0x1001
+#define xpdfKeyCodeEnter 0x1002
+#define xpdfKeyCodeBackspace 0x1003
+#define xpdfKeyCodeInsert 0x1004
+#define xpdfKeyCodeDelete 0x1005
+#define xpdfKeyCodeHome 0x1006
+#define xpdfKeyCodeEnd 0x1007
+#define xpdfKeyCodePgUp 0x1008
+#define xpdfKeyCodePgDn 0x1009
+#define xpdfKeyCodeLeft 0x100a
+#define xpdfKeyCodeRight 0x100b
+#define xpdfKeyCodeUp 0x100c
+#define xpdfKeyCodeDown 0x100d
+#define xpdfKeyCodeF1 0x1100
+#define xpdfKeyCodeF35 0x1122
+#define xpdfKeyCodeMousePress1 0x2001
+#define xpdfKeyCodeMousePress2 0x2002
+#define xpdfKeyCodeMousePress3 0x2003
+#define xpdfKeyCodeMousePress4 0x2004
+#define xpdfKeyCodeMousePress5 0x2005
+#define xpdfKeyCodeMousePress6 0x2006
+#define xpdfKeyCodeMousePress7 0x2007
+#define xpdfKeyCodeMouseRelease1 0x2101
+#define xpdfKeyCodeMouseRelease2 0x2102
+#define xpdfKeyCodeMouseRelease3 0x2103
+#define xpdfKeyCodeMouseRelease4 0x2104
+#define xpdfKeyCodeMouseRelease5 0x2105
+#define xpdfKeyCodeMouseRelease6 0x2106
+#define xpdfKeyCodeMouseRelease7 0x2107
+#define xpdfKeyModNone 0
+#define xpdfKeyModShift (1 << 0)
+#define xpdfKeyModCtrl (1 << 1)
+#define xpdfKeyModAlt (1 << 2)
+#define xpdfKeyContextAny 0
+#define xpdfKeyContextFullScreen (1 << 0)
+#define xpdfKeyContextWindow (2 << 0)
+#define xpdfKeyContextContinuous (1 << 2)
+#define xpdfKeyContextSinglePage (2 << 2)
+#define xpdfKeyContextOverLink (1 << 4)
+#define xpdfKeyContextOffLink (2 << 4)
+#define xpdfKeyContextOutline (1 << 6)
+#define xpdfKeyContextMainWin (2 << 6)
+#define xpdfKeyContextScrLockOn (1 << 8)
+#define xpdfKeyContextScrLockOff (2 << 8)
+
+//------------------------------------------------------------------------
+
+class GlobalParams {
+public:
+
+ // Initialize the global parameters by attempting to read a config
+ // file.
+ GlobalParams(char *cfgFileName);
+
+ ~GlobalParams();
+
+ void setBaseDir(char *dir);
+ void setupBaseFonts(char *dir);
+
+ void parseLine(char *buf, GString *fileName, int line);
+
+ //----- accessors
+
+ CharCode getMacRomanCharCode(char *charName);
+
+ GString *getBaseDir();
+ Unicode mapNameToUnicode(char *charName);
+ UnicodeMap *getResidentUnicodeMap(GString *encodingName);
+ FILE *getUnicodeMapFile(GString *encodingName);
+ FILE *findCMapFile(GString *collection, GString *cMapName);
+ FILE *findToUnicodeFile(GString *name);
+ DisplayFontParam *getDisplayFont(GString *fontName);
+ DisplayFontParam *getDisplayCIDFont(GString *fontName, GString *collection);
+ GString *getPSFile();
+ int getPSPaperWidth();
+ int getPSPaperHeight();
+ void getPSImageableArea(int *llx, int *lly, int *urx, int *ury);
+ GBool getPSDuplex();
+ GBool getPSCrop();
+ GBool getPSExpandSmaller();
+ GBool getPSShrinkLarger();
+ GBool getPSCenter();
+ PSLevel getPSLevel();
+ PSFontParam *getPSFont(GString *fontName);
+ PSFontParam *getPSFont16(GString *fontName, GString *collection, int wMode);
+ GBool getPSEmbedType1();
+ GBool getPSEmbedTrueType();
+ GBool getPSEmbedCIDPostScript();
+ GBool getPSEmbedCIDTrueType();
+ GBool getPSPreload();
+ GBool getPSOPI();
+ GBool getPSASCIIHex();
+ GString *getTextEncodingName();
+ EndOfLineKind getTextEOL();
+ GBool getTextPageBreaks();
+ GBool getTextKeepTinyChars();
+ GString *findFontFile(GString *fontName, char **exts);
+ GString *getInitialZoom();
+ GBool getContinuousView();
+ GBool getEnableT1lib();
+ GBool getEnableFreeType();
+ GBool getAntialias();
+ GBool getVectorAntialias();
+ GBool getStrokeAdjust();
+ ScreenType getScreenType();
+ int getScreenSize();
+ int getScreenDotRadius();
+ double getScreenGamma();
+ double getScreenBlackThreshold();
+ double getScreenWhiteThreshold();
+ GString *getURLCommand() { return urlCommand; }
+ GString *getMovieCommand() { return movieCommand; }
+ GBool getMapNumericCharNames();
+ GBool getMapUnknownCharNames();
+ GList *getKeyBinding(int code, int mods, int context);
+ GBool getPrintCommands();
+ GBool getErrQuiet();
+
+ CharCodeToUnicode *getCIDToUnicode(GString *collection);
+ CharCodeToUnicode *getUnicodeToUnicode(GString *fontName);
+ UnicodeMap *getUnicodeMap(GString *encodingName);
+ CMap *getCMap(GString *collection, GString *cMapName);
+ UnicodeMap *getTextEncoding();
+
+ //----- functions to set parameters
+
+ void addDisplayFont(DisplayFontParam *param);
+ void setPSFile(char *file);
+ GBool setPSPaperSize(char *size);
+ void setPSPaperWidth(int width);
+ void setPSPaperHeight(int height);
+ void setPSImageableArea(int llx, int lly, int urx, int ury);
+ void setPSDuplex(GBool duplex);
+ void setPSCrop(GBool crop);
+ void setPSExpandSmaller(GBool expand);
+ void setPSShrinkLarger(GBool shrink);
+ void setPSCenter(GBool center);
+ void setPSLevel(PSLevel level);
+ void setPSEmbedType1(GBool embed);
+ void setPSEmbedTrueType(GBool embed);
+ void setPSEmbedCIDPostScript(GBool embed);
+ void setPSEmbedCIDTrueType(GBool embed);
+ void setPSPreload(GBool preload);
+ void setPSOPI(GBool opi);
+ void setPSASCIIHex(GBool hex);
+ void setTextEncoding(char *encodingName);
+ GBool setTextEOL(char *s);
+ void setTextPageBreaks(GBool pageBreaks);
+ void setTextKeepTinyChars(GBool keep);
+ void setInitialZoom(char *s);
+ void setContinuousView(GBool cont);
+ GBool setEnableT1lib(char *s);
+ GBool setEnableFreeType(char *s);
+ GBool setAntialias(char *s);
+ GBool setVectorAntialias(char *s);
+ void setScreenType(ScreenType t);
+ void setScreenSize(int size);
+ void setScreenDotRadius(int r);
+ void setScreenGamma(double gamma);
+ void setScreenBlackThreshold(double thresh);
+ void setScreenWhiteThreshold(double thresh);
+ void setMapNumericCharNames(GBool map);
+ void setMapUnknownCharNames(GBool map);
+ void setPrintCommands(GBool printCommandsA);
+ void setErrQuiet(GBool errQuietA);
+
+ //----- security handlers
+
+ void addSecurityHandler(XpdfSecurityHandler *handler);
+ XpdfSecurityHandler *getSecurityHandler(char *name);
+
+private:
+
+ void createDefaultKeyBindings();
+ void parseFile(GString *fileName, FILE *f);
+ void parseNameToUnicode(GList *tokens, GString *fileName, int line);
+ void parseCIDToUnicode(GList *tokens, GString *fileName, int line);
+ void parseUnicodeToUnicode(GList *tokens, GString *fileName, int line);
+ void parseUnicodeMap(GList *tokens, GString *fileName, int line);
+ void parseCMapDir(GList *tokens, GString *fileName, int line);
+ void parseToUnicodeDir(GList *tokens, GString *fileName, int line);
+ void parseDisplayFont(GList *tokens, GHash *fontHash,
+ DisplayFontParamKind kind,
+ GString *fileName, int line);
+ void parsePSFile(GList *tokens, GString *fileName, int line);
+ void parsePSPaperSize(GList *tokens, GString *fileName, int line);
+ void parsePSImageableArea(GList *tokens, GString *fileName, int line);
+ void parsePSLevel(GList *tokens, GString *fileName, int line);
+ void parsePSFont(GList *tokens, GString *fileName, int line);
+ void parsePSFont16(char *cmdName, GList *fontList,
+ GList *tokens, GString *fileName, int line);
+ void parseTextEncoding(GList *tokens, GString *fileName, int line);
+ void parseTextEOL(GList *tokens, GString *fileName, int line);
+ void parseFontDir(GList *tokens, GString *fileName, int line);
+ void parseInitialZoom(GList *tokens, GString *fileName, int line);
+ void parseScreenType(GList *tokens, GString *fileName, int line);
+ void parseBind(GList *tokens, GString *fileName, int line);
+ void parseUnbind(GList *tokens, GString *fileName, int line);
+ GBool parseKey(GString *modKeyStr, GString *contextStr,
+ int *code, int *mods, int *context,
+ char *cmdName,
+ GList *tokens, GString *fileName, int line);
+ void parseCommand(char *cmdName, GString **val,
+ GList *tokens, GString *fileName, int line);
+ void parseYesNo(char *cmdName, GBool *flag,
+ GList *tokens, GString *fileName, int line);
+ GBool parseYesNo2(char *token, GBool *flag);
+ void parseInteger(char *cmdName, int *val,
+ GList *tokens, GString *fileName, int line);
+ void parseFloat(char *cmdName, double *val,
+ GList *tokens, GString *fileName, int line);
+ UnicodeMap *getUnicodeMap2(GString *encodingName);
+#ifdef ENABLE_PLUGINS
+ GBool loadPlugin(char *type, char *name);
+#endif
+
+ //----- static tables
+
+ NameToCharCode * // mapping from char name to
+ macRomanReverseMap; // MacRomanEncoding index
+
+ //----- user-modifiable settings
+
+ GString *baseDir; // base directory - for plugins, etc.
+ NameToCharCode * // mapping from char name to Unicode
+ nameToUnicode;
+ GHash *cidToUnicodes; // files for mappings from char collections
+ // to Unicode, indexed by collection name
+ // [GString]
+ GHash *unicodeToUnicodes; // files for Unicode-to-Unicode mappings,
+ // indexed by font name pattern [GString]
+ GHash *residentUnicodeMaps; // mappings from Unicode to char codes,
+ // indexed by encoding name [UnicodeMap]
+ GHash *unicodeMaps; // files for mappings from Unicode to char
+ // codes, indexed by encoding name [GString]
+ GHash *cMapDirs; // list of CMap dirs, indexed by collection
+ // name [GList[GString]]
+ GList *toUnicodeDirs; // list of ToUnicode CMap dirs [GString]
+ GHash *displayFonts; // display font info, indexed by font name
+ // [DisplayFontParam]
+#ifdef WIN32
+ WinFontList *winFontList; // system TrueType fonts
+#endif
+ GHash *displayCIDFonts; // display CID font info, indexed by
+ // collection [DisplayFontParam]
+ GHash *displayNamedCIDFonts; // display CID font info, indexed by
+ // font name [DisplayFontParam]
+ GString *psFile; // PostScript file or command (for xpdf)
+ int psPaperWidth; // paper size, in PostScript points, for
+ int psPaperHeight; // PostScript output
+ int psImageableLLX, // imageable area, in PostScript points,
+ psImageableLLY, // for PostScript output
+ psImageableURX,
+ psImageableURY;
+ GBool psCrop; // crop PS output to CropBox
+ GBool psExpandSmaller; // expand smaller pages to fill paper
+ GBool psShrinkLarger; // shrink larger pages to fit paper
+ GBool psCenter; // center pages on the paper
+ GBool psDuplex; // enable duplexing in PostScript?
+ PSLevel psLevel; // PostScript level to generate
+ GHash *psFonts; // PostScript font info, indexed by PDF
+ // font name [PSFontParam]
+ GList *psNamedFonts16; // named 16-bit fonts [PSFontParam]
+ GList *psFonts16; // generic 16-bit fonts [PSFontParam]
+ GBool psEmbedType1; // embed Type 1 fonts?
+ GBool psEmbedTrueType; // embed TrueType fonts?
+ GBool psEmbedCIDPostScript; // embed CID PostScript fonts?
+ GBool psEmbedCIDTrueType; // embed CID TrueType fonts?
+ GBool psPreload; // preload PostScript images and forms into
+ // memory
+ GBool psOPI; // generate PostScript OPI comments?
+ GBool psASCIIHex; // use ASCIIHex instead of ASCII85?
+ GString *textEncoding; // encoding (unicodeMap) to use for text
+ // output
+ EndOfLineKind textEOL; // type of EOL marker to use for text
+ // output
+ GBool textPageBreaks; // insert end-of-page markers?
+ GBool textKeepTinyChars; // keep all characters in text output
+ GList *fontDirs; // list of font dirs [GString]
+ GString *initialZoom; // initial zoom level
+ GBool continuousView; // continuous view mode
+ GBool enableT1lib; // t1lib enable flag
+ GBool enableFreeType; // FreeType enable flag
+ GBool antialias; // font anti-aliasing enable flag
+ GBool vectorAntialias; // vector anti-aliasing enable flag
+ GBool strokeAdjust; // stroke adjustment enable flag
+ ScreenType screenType; // halftone screen type
+ int screenSize; // screen matrix size
+ int screenDotRadius; // screen dot radius
+ double screenGamma; // screen gamma correction
+ double screenBlackThreshold; // screen black clamping threshold
+ double screenWhiteThreshold; // screen white clamping threshold
+ GString *urlCommand; // command executed for URL links
+ GString *movieCommand; // command executed for movie annotations
+ GBool mapNumericCharNames; // map numeric char names (from font subsets)?
+ GBool mapUnknownCharNames; // map unknown char names?
+ GList *keyBindings; // key & mouse button bindings [KeyBinding]
+ GBool printCommands; // print the drawing commands
+ GBool errQuiet; // suppress error messages?
+
+ CharCodeToUnicodeCache *cidToUnicodeCache;
+ CharCodeToUnicodeCache *unicodeToUnicodeCache;
+ UnicodeMapCache *unicodeMapCache;
+ CMapCache *cMapCache;
+
+#ifdef ENABLE_PLUGINS
+ GList *plugins; // list of plugins [Plugin]
+ GList *securityHandlers; // list of loaded security handlers
+ // [XpdfSecurityHandler]
+#endif
+
+#if MULTITHREADED
+ GMutex mutex;
+ GMutex unicodeMapCacheMutex;
+ GMutex cMapCacheMutex;
+#endif
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/JArithmeticDecoder.cc b/kpdf/xpdf/xpdf/JArithmeticDecoder.cc
new file mode 100644
index 00000000..195b73e1
--- /dev/null
+++ b/kpdf/xpdf/xpdf/JArithmeticDecoder.cc
@@ -0,0 +1,322 @@
+//========================================================================
+//
+// JArithmeticDecoder.cc
+//
+// Copyright 2002-2004 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "Object.h"
+#include "Stream.h"
+#include "JArithmeticDecoder.h"
+
+//------------------------------------------------------------------------
+// JArithmeticDecoderStates
+//------------------------------------------------------------------------
+
+JArithmeticDecoderStats::JArithmeticDecoderStats(int contextSizeA) {
+ contextSize = contextSizeA;
+ cxTab = (Guchar *)gmallocn(contextSize, sizeof(Guchar));
+ reset();
+}
+
+JArithmeticDecoderStats::~JArithmeticDecoderStats() {
+ gfree(cxTab);
+}
+
+JArithmeticDecoderStats *JArithmeticDecoderStats::copy() {
+ JArithmeticDecoderStats *stats;
+
+ stats = new JArithmeticDecoderStats(contextSize);
+ memcpy(stats->cxTab, cxTab, contextSize);
+ return stats;
+}
+
+void JArithmeticDecoderStats::reset() {
+ memset(cxTab, 0, contextSize);
+}
+
+void JArithmeticDecoderStats::copyFrom(JArithmeticDecoderStats *stats) {
+ memcpy(cxTab, stats->cxTab, contextSize);
+}
+
+void JArithmeticDecoderStats::setEntry(Guint cx, int i, int mps) {
+ cxTab[cx] = (i << 1) + mps;
+}
+
+//------------------------------------------------------------------------
+// JArithmeticDecoder
+//------------------------------------------------------------------------
+
+Guint JArithmeticDecoder::qeTab[47] = {
+ 0x56010000, 0x34010000, 0x18010000, 0x0AC10000,
+ 0x05210000, 0x02210000, 0x56010000, 0x54010000,
+ 0x48010000, 0x38010000, 0x30010000, 0x24010000,
+ 0x1C010000, 0x16010000, 0x56010000, 0x54010000,
+ 0x51010000, 0x48010000, 0x38010000, 0x34010000,
+ 0x30010000, 0x28010000, 0x24010000, 0x22010000,
+ 0x1C010000, 0x18010000, 0x16010000, 0x14010000,
+ 0x12010000, 0x11010000, 0x0AC10000, 0x09C10000,
+ 0x08A10000, 0x05210000, 0x04410000, 0x02A10000,
+ 0x02210000, 0x01410000, 0x01110000, 0x00850000,
+ 0x00490000, 0x00250000, 0x00150000, 0x00090000,
+ 0x00050000, 0x00010000, 0x56010000
+};
+
+int JArithmeticDecoder::nmpsTab[47] = {
+ 1, 2, 3, 4, 5, 38, 7, 8, 9, 10, 11, 12, 13, 29, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 45, 46
+};
+
+int JArithmeticDecoder::nlpsTab[47] = {
+ 1, 6, 9, 12, 29, 33, 6, 14, 14, 14, 17, 18, 20, 21, 14, 14,
+ 15, 16, 17, 18, 19, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 46
+};
+
+int JArithmeticDecoder::switchTab[47] = {
+ 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+JArithmeticDecoder::JArithmeticDecoder() {
+ str = NULL;
+ dataLen = 0;
+ limitStream = gFalse;
+}
+
+inline Guint JArithmeticDecoder::readByte() {
+ if (limitStream) {
+ --dataLen;
+ if (dataLen < 0) {
+ return 0xff;
+ }
+ }
+ return (Guint)str->getChar() & 0xff;
+}
+
+JArithmeticDecoder::~JArithmeticDecoder() {
+ cleanup();
+}
+
+void JArithmeticDecoder::start() {
+ buf0 = readByte();
+ buf1 = readByte();
+
+ // INITDEC
+ c = (buf0 ^ 0xff) << 16;
+ byteIn();
+ c <<= 7;
+ ct -= 7;
+ a = 0x80000000;
+}
+
+void JArithmeticDecoder::restart(int dataLenA) {
+ int oldDataLen;
+
+ oldDataLen = dataLen;
+ dataLen = dataLenA;
+ if (oldDataLen == -1) {
+ buf1 = readByte();
+ } else if (oldDataLen <= -2) {
+ buf0 = readByte();
+ buf1 = readByte();
+ }
+}
+
+void JArithmeticDecoder::cleanup() {
+ if (limitStream) {
+ while (dataLen > 0) {
+ buf0 = buf1;
+ buf1 = readByte();
+ }
+ }
+}
+
+int JArithmeticDecoder::decodeBit(Guint context,
+ JArithmeticDecoderStats *stats) {
+ int bit;
+ Guint qe;
+ int iCX, mpsCX;
+
+ iCX = stats->cxTab[context] >> 1;
+ mpsCX = stats->cxTab[context] & 1;
+ qe = qeTab[iCX];
+ a -= qe;
+ if (c < a) {
+ if (a & 0x80000000) {
+ bit = mpsCX;
+ } else {
+ // MPS_EXCHANGE
+ if (a < qe) {
+ bit = 1 - mpsCX;
+ if (switchTab[iCX]) {
+ stats->cxTab[context] = (nlpsTab[iCX] << 1) | (1 - mpsCX);
+ } else {
+ stats->cxTab[context] = (nlpsTab[iCX] << 1) | mpsCX;
+ }
+ } else {
+ bit = mpsCX;
+ stats->cxTab[context] = (nmpsTab[iCX] << 1) | mpsCX;
+ }
+ // RENORMD
+ do {
+ if (ct == 0) {
+ byteIn();
+ }
+ a <<= 1;
+ c <<= 1;
+ --ct;
+ } while (!(a & 0x80000000));
+ }
+ } else {
+ c -= a;
+ // LPS_EXCHANGE
+ if (a < qe) {
+ bit = mpsCX;
+ stats->cxTab[context] = (nmpsTab[iCX] << 1) | mpsCX;
+ } else {
+ bit = 1 - mpsCX;
+ if (switchTab[iCX]) {
+ stats->cxTab[context] = (nlpsTab[iCX] << 1) | (1 - mpsCX);
+ } else {
+ stats->cxTab[context] = (nlpsTab[iCX] << 1) | mpsCX;
+ }
+ }
+ a = qe;
+ // RENORMD
+ do {
+ if (ct == 0) {
+ byteIn();
+ }
+ a <<= 1;
+ c <<= 1;
+ --ct;
+ } while (!(a & 0x80000000));
+ }
+ return bit;
+}
+
+int JArithmeticDecoder::decodeByte(Guint context,
+ JArithmeticDecoderStats *stats) {
+ int byte;
+ int i;
+
+ byte = 0;
+ for (i = 0; i < 8; ++i) {
+ byte = (byte << 1) | decodeBit(context, stats);
+ }
+ return byte;
+}
+
+GBool JArithmeticDecoder::decodeInt(int *x, JArithmeticDecoderStats *stats) {
+ int s;
+ Guint v;
+ int i;
+
+ prev = 1;
+ s = decodeIntBit(stats);
+ if (decodeIntBit(stats)) {
+ if (decodeIntBit(stats)) {
+ if (decodeIntBit(stats)) {
+ if (decodeIntBit(stats)) {
+ if (decodeIntBit(stats)) {
+ v = 0;
+ for (i = 0; i < 32; ++i) {
+ v = (v << 1) | decodeIntBit(stats);
+ }
+ v += 4436;
+ } else {
+ v = 0;
+ for (i = 0; i < 12; ++i) {
+ v = (v << 1) | decodeIntBit(stats);
+ }
+ v += 340;
+ }
+ } else {
+ v = 0;
+ for (i = 0; i < 8; ++i) {
+ v = (v << 1) | decodeIntBit(stats);
+ }
+ v += 84;
+ }
+ } else {
+ v = 0;
+ for (i = 0; i < 6; ++i) {
+ v = (v << 1) | decodeIntBit(stats);
+ }
+ v += 20;
+ }
+ } else {
+ v = decodeIntBit(stats);
+ v = (v << 1) | decodeIntBit(stats);
+ v = (v << 1) | decodeIntBit(stats);
+ v = (v << 1) | decodeIntBit(stats);
+ v += 4;
+ }
+ } else {
+ v = decodeIntBit(stats);
+ v = (v << 1) | decodeIntBit(stats);
+ }
+
+ if (s) {
+ if (v == 0) {
+ return gFalse;
+ }
+ *x = -(int)v;
+ } else {
+ *x = (int)v;
+ }
+ return gTrue;
+}
+
+int JArithmeticDecoder::decodeIntBit(JArithmeticDecoderStats *stats) {
+ int bit;
+
+ bit = decodeBit(prev, stats);
+ if (prev < 0x100) {
+ prev = (prev << 1) | bit;
+ } else {
+ prev = (((prev << 1) | bit) & 0x1ff) | 0x100;
+ }
+ return bit;
+}
+
+Guint JArithmeticDecoder::decodeIAID(Guint codeLen,
+ JArithmeticDecoderStats *stats) {
+ Guint i;
+ int bit;
+
+ prev = 1;
+ for (i = 0; i < codeLen; ++i) {
+ bit = decodeBit(prev, stats);
+ prev = (prev << 1) | bit;
+ }
+ return prev - (1 << codeLen);
+}
+
+void JArithmeticDecoder::byteIn() {
+ if (buf0 == 0xff) {
+ if (buf1 > 0x8f) {
+ ct = 8;
+ } else {
+ buf0 = buf1;
+ buf1 = readByte();
+ c = c + 0xfe00 - (buf0 << 9);
+ ct = 7;
+ }
+ } else {
+ buf0 = buf1;
+ buf1 = readByte();
+ c = c + 0xff00 - (buf0 << 8);
+ ct = 8;
+ }
+}
diff --git a/kpdf/xpdf/xpdf/JArithmeticDecoder.h b/kpdf/xpdf/xpdf/JArithmeticDecoder.h
new file mode 100644
index 00000000..a40823dd
--- /dev/null
+++ b/kpdf/xpdf/xpdf/JArithmeticDecoder.h
@@ -0,0 +1,109 @@
+//========================================================================
+//
+// JArithmeticDecoder.h
+//
+// Arithmetic decoder used by the JBIG2 and JPEG2000 decoders.
+//
+// Copyright 2002-2004 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef JARITHMETICDECODER_H
+#define JARITHMETICDECODER_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+
+class Stream;
+
+//------------------------------------------------------------------------
+// JArithmeticDecoderStats
+//------------------------------------------------------------------------
+
+class JArithmeticDecoderStats {
+public:
+
+ JArithmeticDecoderStats(int contextSizeA);
+ ~JArithmeticDecoderStats();
+ JArithmeticDecoderStats *copy();
+ void reset();
+ int getContextSize() { return contextSize; }
+ void copyFrom(JArithmeticDecoderStats *stats);
+ void setEntry(Guint cx, int i, int mps);
+
+private:
+
+ Guchar *cxTab; // cxTab[cx] = (i[cx] << 1) + mps[cx]
+ int contextSize;
+
+ friend class JArithmeticDecoder;
+};
+
+//------------------------------------------------------------------------
+// JArithmeticDecoder
+//------------------------------------------------------------------------
+
+class JArithmeticDecoder {
+public:
+
+ JArithmeticDecoder();
+ ~JArithmeticDecoder();
+
+ void setStream(Stream *strA)
+ { str = strA; dataLen = 0; limitStream = gFalse; }
+ void setStream(Stream *strA, int dataLenA)
+ { str = strA; dataLen = dataLenA; limitStream = gTrue; }
+
+ // Start decoding on a new stream. This fills the byte buffers and
+ // runs INITDEC.
+ void start();
+
+ // Restart decoding on an interrupted stream. This refills the
+ // buffers if needed, but does not run INITDEC. (This is used in
+ // JPEG 2000 streams when codeblock data is split across multiple
+ // packets/layers.)
+ void restart(int dataLenA);
+
+ // Read any leftover data in the stream.
+ void cleanup();
+
+ // Decode one bit.
+ int decodeBit(Guint context, JArithmeticDecoderStats *stats);
+
+ // Decode eight bits.
+ int decodeByte(Guint context, JArithmeticDecoderStats *stats);
+
+ // Returns false for OOB, otherwise sets *<x> and returns true.
+ GBool decodeInt(int *x, JArithmeticDecoderStats *stats);
+
+ Guint decodeIAID(Guint codeLen,
+ JArithmeticDecoderStats *stats);
+
+private:
+
+ Guint readByte();
+ int decodeIntBit(JArithmeticDecoderStats *stats);
+ void byteIn();
+
+ static Guint qeTab[47];
+ static int nmpsTab[47];
+ static int nlpsTab[47];
+ static int switchTab[47];
+
+ Guint buf0, buf1;
+ Guint c, a;
+ int ct;
+
+ Guint prev; // for the integer decoder
+
+ Stream *str;
+ int dataLen;
+ GBool limitStream;
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/JBIG2Stream.cc b/kpdf/xpdf/xpdf/JBIG2Stream.cc
new file mode 100644
index 00000000..43f17712
--- /dev/null
+++ b/kpdf/xpdf/xpdf/JBIG2Stream.cc
@@ -0,0 +1,3648 @@
+//========================================================================
+//
+// JBIG2Stream.cc
+//
+// Copyright 2002-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <limits.h>
+#include "GList.h"
+#include "Error.h"
+#include "JArithmeticDecoder.h"
+#include "JBIG2Stream.h"
+
+//~ share these tables
+#include "Stream-CCITT.h"
+
+//------------------------------------------------------------------------
+
+static int contextSize[4] = { 16, 13, 10, 10 };
+static int refContextSize[2] = { 13, 10 };
+
+//------------------------------------------------------------------------
+// JBIG2HuffmanTable
+//------------------------------------------------------------------------
+
+#define jbig2HuffmanLOW 0xfffffffd
+#define jbig2HuffmanOOB 0xfffffffe
+#define jbig2HuffmanEOT 0xffffffff
+
+struct JBIG2HuffmanTable {
+ int val;
+ Guint prefixLen;
+ Guint rangeLen; // can also be LOW, OOB, or EOT
+ Guint prefix;
+};
+
+JBIG2HuffmanTable huffTableA[] = {
+ { 0, 1, 4, 0x000 },
+ { 16, 2, 8, 0x002 },
+ { 272, 3, 16, 0x006 },
+ { 65808, 3, 32, 0x007 },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+JBIG2HuffmanTable huffTableB[] = {
+ { 0, 1, 0, 0x000 },
+ { 1, 2, 0, 0x002 },
+ { 2, 3, 0, 0x006 },
+ { 3, 4, 3, 0x00e },
+ { 11, 5, 6, 0x01e },
+ { 75, 6, 32, 0x03e },
+ { 0, 6, jbig2HuffmanOOB, 0x03f },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+JBIG2HuffmanTable huffTableC[] = {
+ { 0, 1, 0, 0x000 },
+ { 1, 2, 0, 0x002 },
+ { 2, 3, 0, 0x006 },
+ { 3, 4, 3, 0x00e },
+ { 11, 5, 6, 0x01e },
+ { 0, 6, jbig2HuffmanOOB, 0x03e },
+ { 75, 7, 32, 0x0fe },
+ { -256, 8, 8, 0x0fe },
+ { -257, 8, jbig2HuffmanLOW, 0x0ff },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+JBIG2HuffmanTable huffTableD[] = {
+ { 1, 1, 0, 0x000 },
+ { 2, 2, 0, 0x002 },
+ { 3, 3, 0, 0x006 },
+ { 4, 4, 3, 0x00e },
+ { 12, 5, 6, 0x01e },
+ { 76, 5, 32, 0x01f },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+JBIG2HuffmanTable huffTableE[] = {
+ { 1, 1, 0, 0x000 },
+ { 2, 2, 0, 0x002 },
+ { 3, 3, 0, 0x006 },
+ { 4, 4, 3, 0x00e },
+ { 12, 5, 6, 0x01e },
+ { 76, 6, 32, 0x03e },
+ { -255, 7, 8, 0x07e },
+ { -256, 7, jbig2HuffmanLOW, 0x07f },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+JBIG2HuffmanTable huffTableF[] = {
+ { 0, 2, 7, 0x000 },
+ { 128, 3, 7, 0x002 },
+ { 256, 3, 8, 0x003 },
+ { -1024, 4, 9, 0x008 },
+ { -512, 4, 8, 0x009 },
+ { -256, 4, 7, 0x00a },
+ { -32, 4, 5, 0x00b },
+ { 512, 4, 9, 0x00c },
+ { 1024, 4, 10, 0x00d },
+ { -2048, 5, 10, 0x01c },
+ { -128, 5, 6, 0x01d },
+ { -64, 5, 5, 0x01e },
+ { -2049, 6, jbig2HuffmanLOW, 0x03e },
+ { 2048, 6, 32, 0x03f },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+JBIG2HuffmanTable huffTableG[] = {
+ { -512, 3, 8, 0x000 },
+ { 256, 3, 8, 0x001 },
+ { 512, 3, 9, 0x002 },
+ { 1024, 3, 10, 0x003 },
+ { -1024, 4, 9, 0x008 },
+ { -256, 4, 7, 0x009 },
+ { -32, 4, 5, 0x00a },
+ { 0, 4, 5, 0x00b },
+ { 128, 4, 7, 0x00c },
+ { -128, 5, 6, 0x01a },
+ { -64, 5, 5, 0x01b },
+ { 32, 5, 5, 0x01c },
+ { 64, 5, 6, 0x01d },
+ { -1025, 5, jbig2HuffmanLOW, 0x01e },
+ { 2048, 5, 32, 0x01f },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+JBIG2HuffmanTable huffTableH[] = {
+ { 0, 2, 1, 0x000 },
+ { 0, 2, jbig2HuffmanOOB, 0x001 },
+ { 4, 3, 4, 0x004 },
+ { -1, 4, 0, 0x00a },
+ { 22, 4, 4, 0x00b },
+ { 38, 4, 5, 0x00c },
+ { 2, 5, 0, 0x01a },
+ { 70, 5, 6, 0x01b },
+ { 134, 5, 7, 0x01c },
+ { 3, 6, 0, 0x03a },
+ { 20, 6, 1, 0x03b },
+ { 262, 6, 7, 0x03c },
+ { 646, 6, 10, 0x03d },
+ { -2, 7, 0, 0x07c },
+ { 390, 7, 8, 0x07d },
+ { -15, 8, 3, 0x0fc },
+ { -5, 8, 1, 0x0fd },
+ { -7, 9, 1, 0x1fc },
+ { -3, 9, 0, 0x1fd },
+ { -16, 9, jbig2HuffmanLOW, 0x1fe },
+ { 1670, 9, 32, 0x1ff },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+JBIG2HuffmanTable huffTableI[] = {
+ { 0, 2, jbig2HuffmanOOB, 0x000 },
+ { -1, 3, 1, 0x002 },
+ { 1, 3, 1, 0x003 },
+ { 7, 3, 5, 0x004 },
+ { -3, 4, 1, 0x00a },
+ { 43, 4, 5, 0x00b },
+ { 75, 4, 6, 0x00c },
+ { 3, 5, 1, 0x01a },
+ { 139, 5, 7, 0x01b },
+ { 267, 5, 8, 0x01c },
+ { 5, 6, 1, 0x03a },
+ { 39, 6, 2, 0x03b },
+ { 523, 6, 8, 0x03c },
+ { 1291, 6, 11, 0x03d },
+ { -5, 7, 1, 0x07c },
+ { 779, 7, 9, 0x07d },
+ { -31, 8, 4, 0x0fc },
+ { -11, 8, 2, 0x0fd },
+ { -15, 9, 2, 0x1fc },
+ { -7, 9, 1, 0x1fd },
+ { -32, 9, jbig2HuffmanLOW, 0x1fe },
+ { 3339, 9, 32, 0x1ff },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+JBIG2HuffmanTable huffTableJ[] = {
+ { -2, 2, 2, 0x000 },
+ { 6, 2, 6, 0x001 },
+ { 0, 2, jbig2HuffmanOOB, 0x002 },
+ { -3, 5, 0, 0x018 },
+ { 2, 5, 0, 0x019 },
+ { 70, 5, 5, 0x01a },
+ { 3, 6, 0, 0x036 },
+ { 102, 6, 5, 0x037 },
+ { 134, 6, 6, 0x038 },
+ { 198, 6, 7, 0x039 },
+ { 326, 6, 8, 0x03a },
+ { 582, 6, 9, 0x03b },
+ { 1094, 6, 10, 0x03c },
+ { -21, 7, 4, 0x07a },
+ { -4, 7, 0, 0x07b },
+ { 4, 7, 0, 0x07c },
+ { 2118, 7, 11, 0x07d },
+ { -5, 8, 0, 0x0fc },
+ { 5, 8, 0, 0x0fd },
+ { -22, 8, jbig2HuffmanLOW, 0x0fe },
+ { 4166, 8, 32, 0x0ff },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+JBIG2HuffmanTable huffTableK[] = {
+ { 1, 1, 0, 0x000 },
+ { 2, 2, 1, 0x002 },
+ { 4, 4, 0, 0x00c },
+ { 5, 4, 1, 0x00d },
+ { 7, 5, 1, 0x01c },
+ { 9, 5, 2, 0x01d },
+ { 13, 6, 2, 0x03c },
+ { 17, 7, 2, 0x07a },
+ { 21, 7, 3, 0x07b },
+ { 29, 7, 4, 0x07c },
+ { 45, 7, 5, 0x07d },
+ { 77, 7, 6, 0x07e },
+ { 141, 7, 32, 0x07f },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+JBIG2HuffmanTable huffTableL[] = {
+ { 1, 1, 0, 0x000 },
+ { 2, 2, 0, 0x002 },
+ { 3, 3, 1, 0x006 },
+ { 5, 5, 0, 0x01c },
+ { 6, 5, 1, 0x01d },
+ { 8, 6, 1, 0x03c },
+ { 10, 7, 0, 0x07a },
+ { 11, 7, 1, 0x07b },
+ { 13, 7, 2, 0x07c },
+ { 17, 7, 3, 0x07d },
+ { 25, 7, 4, 0x07e },
+ { 41, 8, 5, 0x0fe },
+ { 73, 8, 32, 0x0ff },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+JBIG2HuffmanTable huffTableM[] = {
+ { 1, 1, 0, 0x000 },
+ { 2, 3, 0, 0x004 },
+ { 7, 3, 3, 0x005 },
+ { 3, 4, 0, 0x00c },
+ { 5, 4, 1, 0x00d },
+ { 4, 5, 0, 0x01c },
+ { 15, 6, 1, 0x03a },
+ { 17, 6, 2, 0x03b },
+ { 21, 6, 3, 0x03c },
+ { 29, 6, 4, 0x03d },
+ { 45, 6, 5, 0x03e },
+ { 77, 7, 6, 0x07e },
+ { 141, 7, 32, 0x07f },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+JBIG2HuffmanTable huffTableN[] = {
+ { 0, 1, 0, 0x000 },
+ { -2, 3, 0, 0x004 },
+ { -1, 3, 0, 0x005 },
+ { 1, 3, 0, 0x006 },
+ { 2, 3, 0, 0x007 },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+JBIG2HuffmanTable huffTableO[] = {
+ { 0, 1, 0, 0x000 },
+ { -1, 3, 0, 0x004 },
+ { 1, 3, 0, 0x005 },
+ { -2, 4, 0, 0x00c },
+ { 2, 4, 0, 0x00d },
+ { -4, 5, 1, 0x01c },
+ { 3, 5, 1, 0x01d },
+ { -8, 6, 2, 0x03c },
+ { 5, 6, 2, 0x03d },
+ { -24, 7, 4, 0x07c },
+ { 9, 7, 4, 0x07d },
+ { -25, 7, jbig2HuffmanLOW, 0x07e },
+ { 25, 7, 32, 0x07f },
+ { 0, 0, jbig2HuffmanEOT, 0 }
+};
+
+//------------------------------------------------------------------------
+// JBIG2HuffmanDecoder
+//------------------------------------------------------------------------
+
+class JBIG2HuffmanDecoder {
+public:
+
+ JBIG2HuffmanDecoder();
+ ~JBIG2HuffmanDecoder();
+ void setStream(Stream *strA) { str = strA; }
+
+ void reset();
+
+ // Returns false for OOB, otherwise sets *<x> and returns true.
+ GBool decodeInt(int *x, JBIG2HuffmanTable *table);
+
+ Guint readBits(Guint n);
+ Guint readBit();
+
+ // Sort the table by prefix length and assign prefix values.
+ void buildTable(JBIG2HuffmanTable *table, Guint len);
+
+private:
+
+ Stream *str;
+ Guint buf;
+ Guint bufLen;
+};
+
+JBIG2HuffmanDecoder::JBIG2HuffmanDecoder() {
+ str = NULL;
+ reset();
+}
+
+JBIG2HuffmanDecoder::~JBIG2HuffmanDecoder() {
+}
+
+void JBIG2HuffmanDecoder::reset() {
+ buf = 0;
+ bufLen = 0;
+}
+
+//~ optimize this
+GBool JBIG2HuffmanDecoder::decodeInt(int *x, JBIG2HuffmanTable *table) {
+ Guint i, len, prefix;
+
+ i = 0;
+ len = 0;
+ prefix = 0;
+ while (table[i].rangeLen != jbig2HuffmanEOT) {
+ while (len < table[i].prefixLen) {
+ prefix = (prefix << 1) | readBit();
+ ++len;
+ }
+ if (prefix == table[i].prefix) {
+ if (table[i].rangeLen == jbig2HuffmanOOB) {
+ return gFalse;
+ }
+ if (table[i].rangeLen == jbig2HuffmanLOW) {
+ *x = table[i].val - readBits(32);
+ } else if (table[i].rangeLen > 0) {
+ *x = table[i].val + readBits(table[i].rangeLen);
+ } else {
+ *x = table[i].val;
+ }
+ return gTrue;
+ }
+ ++i;
+ }
+ return gFalse;
+}
+
+Guint JBIG2HuffmanDecoder::readBits(Guint n) {
+ Guint x, mask, nLeft;
+
+ mask = (n == 32) ? 0xffffffff : ((1 << n) - 1);
+ if (bufLen >= n) {
+ x = (buf >> (bufLen - n)) & mask;
+ bufLen -= n;
+ } else {
+ x = buf & ((1 << bufLen) - 1);
+ nLeft = n - bufLen;
+ bufLen = 0;
+ while (nLeft >= 8) {
+ x = (x << 8) | (str->getChar() & 0xff);
+ nLeft -= 8;
+ }
+ if (nLeft > 0) {
+ buf = str->getChar();
+ bufLen = 8 - nLeft;
+ x = (x << nLeft) | ((buf >> bufLen) & ((1 << nLeft) - 1));
+ }
+ }
+ return x;
+}
+
+Guint JBIG2HuffmanDecoder::readBit() {
+ if (bufLen == 0) {
+ buf = str->getChar();
+ bufLen = 8;
+ }
+ --bufLen;
+ return (buf >> bufLen) & 1;
+}
+
+void JBIG2HuffmanDecoder::buildTable(JBIG2HuffmanTable *table, Guint len) {
+ Guint i, j, k, prefix;
+ JBIG2HuffmanTable tab;
+
+ // stable selection sort:
+ // - entries with prefixLen > 0, in ascending prefixLen order
+ // - entry with prefixLen = 0, rangeLen = EOT
+ // - all other entries with prefixLen = 0
+ // (on entry, table[len] has prefixLen = 0, rangeLen = EOT)
+ for (i = 0; i < len; ++i) {
+ for (j = i; j < len && table[j].prefixLen == 0; ++j) ;
+ if (j == len) {
+ break;
+ }
+ for (k = j + 1; k < len; ++k) {
+ if (table[k].prefixLen > 0 &&
+ table[k].prefixLen < table[j].prefixLen) {
+ j = k;
+ }
+ }
+ if (j != i) {
+ tab = table[j];
+ for (k = j; k > i; --k) {
+ table[k] = table[k - 1];
+ }
+ table[i] = tab;
+ }
+ }
+ table[i] = table[len];
+
+ // assign prefixes
+ if (table[0].rangeLen != jbig2HuffmanEOT) {
+ i = 0;
+ prefix = 0;
+ table[i++].prefix = prefix++;
+ for (; table[i].rangeLen != jbig2HuffmanEOT; ++i) {
+ prefix <<= table[i].prefixLen - table[i-1].prefixLen;
+ table[i].prefix = prefix++;
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+// JBIG2MMRDecoder
+//------------------------------------------------------------------------
+
+class JBIG2MMRDecoder {
+public:
+
+ JBIG2MMRDecoder();
+ ~JBIG2MMRDecoder();
+ void setStream(Stream *strA) { str = strA; }
+ void reset();
+ int get2DCode();
+ int getBlackCode();
+ int getWhiteCode();
+ Guint get24Bits();
+ void skipTo(Guint length);
+
+private:
+
+ Stream *str;
+ Guint buf;
+ Guint bufLen;
+ Guint nBytesRead;
+};
+
+JBIG2MMRDecoder::JBIG2MMRDecoder() {
+ str = NULL;
+ reset();
+}
+
+JBIG2MMRDecoder::~JBIG2MMRDecoder() {
+}
+
+void JBIG2MMRDecoder::reset() {
+ buf = 0;
+ bufLen = 0;
+ nBytesRead = 0;
+}
+
+int JBIG2MMRDecoder::get2DCode() {
+ CCITTCode *p;
+
+ if (bufLen == 0) {
+ buf = str->getChar() & 0xff;
+ bufLen = 8;
+ ++nBytesRead;
+ p = &twoDimTab1[(buf >> 1) & 0x7f];
+ } else if (bufLen == 8) {
+ p = &twoDimTab1[(buf >> 1) & 0x7f];
+ } else {
+ p = &twoDimTab1[(buf << (7 - bufLen)) & 0x7f];
+ if (p->bits < 0 || p->bits > (int)bufLen) {
+ buf = (buf << 8) | (str->getChar() & 0xff);
+ bufLen += 8;
+ ++nBytesRead;
+ p = &twoDimTab1[(buf >> (bufLen - 7)) & 0x7f];
+ }
+ }
+ if (p->bits < 0) {
+ error(str->getPos(), "Bad two dim code in JBIG2 MMR stream");
+ return EOF;
+ }
+ bufLen -= p->bits;
+ return p->n;
+}
+
+int JBIG2MMRDecoder::getWhiteCode() {
+ CCITTCode *p;
+ Guint code;
+
+ if (bufLen == 0) {
+ buf = str->getChar() & 0xff;
+ bufLen = 8;
+ ++nBytesRead;
+ }
+ while (1) {
+ if (bufLen >= 11 && ((buf >> (bufLen - 7)) & 0x7f) == 0) {
+ if (bufLen <= 12) {
+ code = buf << (12 - bufLen);
+ } else {
+ code = buf >> (bufLen - 12);
+ }
+ p = &whiteTab1[code & 0x1f];
+ } else {
+ if (bufLen <= 9) {
+ code = buf << (9 - bufLen);
+ } else {
+ code = buf >> (bufLen - 9);
+ }
+ p = &whiteTab2[code & 0x1ff];
+ }
+ if (p->bits > 0 && p->bits <= (int)bufLen) {
+ bufLen -= p->bits;
+ return p->n;
+ }
+ if (bufLen >= 12) {
+ break;
+ }
+ buf = (buf << 8) | (str->getChar() & 0xff);
+ bufLen += 8;
+ ++nBytesRead;
+ }
+ error(str->getPos(), "Bad white code in JBIG2 MMR stream");
+ // eat a bit and return a positive number so that the caller doesn't
+ // go into an infinite loop
+ --bufLen;
+ return 1;
+}
+
+int JBIG2MMRDecoder::getBlackCode() {
+ CCITTCode *p;
+ Guint code;
+
+ if (bufLen == 0) {
+ buf = str->getChar() & 0xff;
+ bufLen = 8;
+ ++nBytesRead;
+ }
+ while (1) {
+ if (bufLen >= 10 && ((buf >> (bufLen - 6)) & 0x3f) == 0) {
+ if (bufLen <= 13) {
+ code = buf << (13 - bufLen);
+ } else {
+ code = buf >> (bufLen - 13);
+ }
+ p = &blackTab1[code & 0x7f];
+ } else if (bufLen >= 7 && ((buf >> (bufLen - 4)) & 0x0f) == 0 &&
+ ((buf >> (bufLen - 6)) & 0x03) != 0) {
+ if (bufLen <= 12) {
+ code = buf << (12 - bufLen);
+ } else {
+ code = buf >> (bufLen - 12);
+ }
+ p = &blackTab2[(code & 0xff) - 64];
+ } else {
+ if (bufLen <= 6) {
+ code = buf << (6 - bufLen);
+ } else {
+ code = buf >> (bufLen - 6);
+ }
+ p = &blackTab3[code & 0x3f];
+ }
+ if (p->bits > 0 && p->bits <= (int)bufLen) {
+ bufLen -= p->bits;
+ return p->n;
+ }
+ if (bufLen >= 13) {
+ break;
+ }
+ buf = (buf << 8) | (str->getChar() & 0xff);
+ bufLen += 8;
+ ++nBytesRead;
+ }
+ error(str->getPos(), "Bad black code in JBIG2 MMR stream");
+ // eat a bit and return a positive number so that the caller doesn't
+ // go into an infinite loop
+ --bufLen;
+ return 1;
+}
+
+Guint JBIG2MMRDecoder::get24Bits() {
+ while (bufLen < 24) {
+ buf = (buf << 8) | (str->getChar() & 0xff);
+ bufLen += 8;
+ ++nBytesRead;
+ }
+ return (buf >> (bufLen - 24)) & 0xffffff;
+}
+
+void JBIG2MMRDecoder::skipTo(Guint length) {
+ while (nBytesRead < length) {
+ str->getChar();
+ ++nBytesRead;
+ }
+}
+
+//------------------------------------------------------------------------
+// JBIG2Segment
+//------------------------------------------------------------------------
+
+enum JBIG2SegmentType {
+ jbig2SegBitmap,
+ jbig2SegSymbolDict,
+ jbig2SegPatternDict,
+ jbig2SegCodeTable
+};
+
+class JBIG2Segment {
+public:
+
+ JBIG2Segment(Guint segNumA) { segNum = segNumA; }
+ virtual ~JBIG2Segment() {}
+ void setSegNum(Guint segNumA) { segNum = segNumA; }
+ Guint getSegNum() { return segNum; }
+ virtual JBIG2SegmentType getType() = 0;
+
+private:
+
+ Guint segNum;
+};
+
+//------------------------------------------------------------------------
+// JBIG2Bitmap
+//------------------------------------------------------------------------
+
+struct JBIG2BitmapPtr {
+ Guchar *p;
+ int shift;
+ int x;
+};
+
+class JBIG2Bitmap: public JBIG2Segment {
+public:
+
+ JBIG2Bitmap(Guint segNumA, int wA, int hA);
+ virtual ~JBIG2Bitmap();
+ virtual JBIG2SegmentType getType() { return jbig2SegBitmap; }
+ JBIG2Bitmap *copy() { return new JBIG2Bitmap(0, this); }
+ JBIG2Bitmap *getSlice(Guint x, Guint y, Guint wA, Guint hA);
+ void expand(int newH, Guint pixel);
+ void clearToZero();
+ void clearToOne();
+ int getWidth() { return w; }
+ int getHeight() { return h; }
+ int getPixel(int x, int y)
+ { return (x < 0 || x >= w || y < 0 || y >= h) ? 0 :
+ (data[y * line + (x >> 3)] >> (7 - (x & 7))) & 1; }
+ void setPixel(int x, int y)
+ { data[y * line + (x >> 3)] |= 1 << (7 - (x & 7)); }
+ void clearPixel(int x, int y)
+ { data[y * line + (x >> 3)] &= 0x7f7f >> (x & 7); }
+ void getPixelPtr(int x, int y, JBIG2BitmapPtr *ptr);
+ int nextPixel(JBIG2BitmapPtr *ptr);
+ void duplicateRow(int yDest, int ySrc);
+ void combine(JBIG2Bitmap *bitmap, int x, int y, Guint combOp);
+ Guchar *getDataPtr() { return data; }
+ int getDataSize() { return h * line; }
+
+private:
+
+ JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap);
+
+ int w, h, line;
+ Guchar *data;
+};
+
+JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, int wA, int hA):
+ JBIG2Segment(segNumA)
+{
+ w = wA;
+ h = hA;
+ line = (wA + 7) >> 3;
+ if (w <= 0 || h <= 0 || line <= 0 || h >= (INT_MAX - 1) / line) {
+ // force a call to gmalloc(-1), which will throw an exception
+ h = -1;
+ line = 2;
+ }
+ // need to allocate one extra guard byte for use in combine()
+ data = (Guchar *)gmalloc(h * line + 1);
+ data[h * line] = 0;
+}
+
+JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap):
+ JBIG2Segment(segNumA)
+{
+ w = bitmap->w;
+ h = bitmap->h;
+ line = bitmap->line;
+ if (w <= 0 || h <= 0 || line <= 0 || h >= (INT_MAX - 1) / line) {
+ // force a call to gmalloc(-1), which will throw an exception
+ h = -1;
+ line = 2;
+ }
+ // need to allocate one extra guard byte for use in combine()
+ data = (Guchar *)gmalloc(h * line + 1);
+ memcpy(data, bitmap->data, h * line);
+ data[h * line] = 0;
+}
+
+JBIG2Bitmap::~JBIG2Bitmap() {
+ gfree(data);
+}
+
+//~ optimize this
+JBIG2Bitmap *JBIG2Bitmap::getSlice(Guint x, Guint y, Guint wA, Guint hA) {
+ JBIG2Bitmap *slice;
+ Guint xx, yy;
+
+ slice = new JBIG2Bitmap(0, wA, hA);
+ slice->clearToZero();
+ for (yy = 0; yy < hA; ++yy) {
+ for (xx = 0; xx < wA; ++xx) {
+ if (getPixel(x + xx, y + yy)) {
+ slice->setPixel(xx, yy);
+ }
+ }
+ }
+ return slice;
+}
+
+void JBIG2Bitmap::expand(int newH, Guint pixel) {
+ if (newH <= h || line <= 0 || newH >= (INT_MAX - 1) / line) {
+ return;
+ }
+ // need to allocate one extra guard byte for use in combine()
+ data = (Guchar *)grealloc(data, newH * line + 1);
+ if (pixel) {
+ memset(data + h * line, 0xff, (newH - h) * line);
+ } else {
+ memset(data + h * line, 0x00, (newH - h) * line);
+ }
+ h = newH;
+ data[h * line] = 0;
+}
+
+void JBIG2Bitmap::clearToZero() {
+ memset(data, 0, h * line);
+}
+
+void JBIG2Bitmap::clearToOne() {
+ memset(data, 0xff, h * line);
+}
+
+inline void JBIG2Bitmap::getPixelPtr(int x, int y, JBIG2BitmapPtr *ptr) {
+ if (y < 0 || y >= h || x >= w) {
+ ptr->p = NULL;
+ ptr->shift = 0; // make gcc happy
+ ptr->x = 0; // make gcc happy
+ } else if (x < 0) {
+ ptr->p = &data[y * line];
+ ptr->shift = 7;
+ ptr->x = x;
+ } else {
+ ptr->p = &data[y * line + (x >> 3)];
+ ptr->shift = 7 - (x & 7);
+ ptr->x = x;
+ }
+}
+
+inline int JBIG2Bitmap::nextPixel(JBIG2BitmapPtr *ptr) {
+ int pix;
+
+ if (!ptr->p) {
+ pix = 0;
+ } else if (ptr->x < 0) {
+ ++ptr->x;
+ pix = 0;
+ } else {
+ pix = (*ptr->p >> ptr->shift) & 1;
+ if (++ptr->x == w) {
+ ptr->p = NULL;
+ } else if (ptr->shift == 0) {
+ ++ptr->p;
+ ptr->shift = 7;
+ } else {
+ --ptr->shift;
+ }
+ }
+ return pix;
+}
+
+void JBIG2Bitmap::duplicateRow(int yDest, int ySrc) {
+ memcpy(data + yDest * line, data + ySrc * line, line);
+}
+
+void JBIG2Bitmap::combine(JBIG2Bitmap *bitmap, int x, int y,
+ Guint combOp) {
+ int x0, x1, y0, y1, xx, yy;
+ Guchar *srcPtr, *destPtr;
+ Guint src0, src1, src, dest, s1, s2, m1, m2, m3;
+ GBool oneByte;
+
+ // check for the pathological case where y = -2^31
+ if (y < -0x7fffffff) {
+ return;
+ }
+ if (y < 0) {
+ y0 = -y;
+ } else {
+ y0 = 0;
+ }
+ if (y + bitmap->h > h) {
+ y1 = h - y;
+ } else {
+ y1 = bitmap->h;
+ }
+ if (y0 >= y1) {
+ return;
+ }
+
+ if (x >= 0) {
+ x0 = x & ~7;
+ } else {
+ x0 = 0;
+ }
+ x1 = x + bitmap->w;
+ if (x1 > w) {
+ x1 = w;
+ }
+ if (x0 >= x1) {
+ return;
+ }
+
+ s1 = x & 7;
+ s2 = 8 - s1;
+ m1 = 0xff >> (x1 & 7);
+ m2 = 0xff << (((x1 & 7) == 0) ? 0 : 8 - (x1 & 7));
+ m3 = (0xff >> s1) & m2;
+
+ oneByte = x0 == ((x1 - 1) & ~7);
+
+ for (yy = y0; yy < y1; ++yy) {
+
+ // one byte per line -- need to mask both left and right side
+ if (oneByte) {
+ if (x >= 0) {
+ destPtr = data + (y + yy) * line + (x >> 3);
+ srcPtr = bitmap->data + yy * bitmap->line;
+ dest = *destPtr;
+ src1 = *srcPtr;
+ switch (combOp) {
+ case 0: // or
+ dest |= (src1 >> s1) & m2;
+ break;
+ case 1: // and
+ dest &= ((0xff00 | src1) >> s1) | m1;
+ break;
+ case 2: // xor
+ dest ^= (src1 >> s1) & m2;
+ break;
+ case 3: // xnor
+ dest ^= ((src1 ^ 0xff) >> s1) & m2;
+ break;
+ case 4: // replace
+ dest = (dest & ~m3) | ((src1 >> s1) & m3);
+ break;
+ }
+ *destPtr = dest;
+ } else {
+ destPtr = data + (y + yy) * line;
+ srcPtr = bitmap->data + yy * bitmap->line + (-x >> 3);
+ dest = *destPtr;
+ src1 = *srcPtr;
+ switch (combOp) {
+ case 0: // or
+ dest |= src1 & m2;
+ break;
+ case 1: // and
+ dest &= src1 | m1;
+ break;
+ case 2: // xor
+ dest ^= src1 & m2;
+ break;
+ case 3: // xnor
+ dest ^= (src1 ^ 0xff) & m2;
+ break;
+ case 4: // replace
+ dest = (src1 & m2) | (dest & m1);
+ break;
+ }
+ *destPtr = dest;
+ }
+
+ // multiple bytes per line -- need to mask left side of left-most
+ // byte and right side of right-most byte
+ } else {
+
+ // left-most byte
+ if (x >= 0) {
+ destPtr = data + (y + yy) * line + (x >> 3);
+ srcPtr = bitmap->data + yy * bitmap->line;
+ src1 = *srcPtr++;
+ dest = *destPtr;
+ switch (combOp) {
+ case 0: // or
+ dest |= src1 >> s1;
+ break;
+ case 1: // and
+ dest &= (0xff00 | src1) >> s1;
+ break;
+ case 2: // xor
+ dest ^= src1 >> s1;
+ break;
+ case 3: // xnor
+ dest ^= (src1 ^ 0xff) >> s1;
+ break;
+ case 4: // replace
+ dest = (dest & (0xff << s2)) | (src1 >> s1);
+ break;
+ }
+ *destPtr++ = dest;
+ xx = x0 + 8;
+ } else {
+ destPtr = data + (y + yy) * line;
+ srcPtr = bitmap->data + yy * bitmap->line + (-x >> 3);
+ src1 = *srcPtr++;
+ xx = x0;
+ }
+
+ // middle bytes
+ for (; xx < x1 - 8; xx += 8) {
+ dest = *destPtr;
+ src0 = src1;
+ src1 = *srcPtr++;
+ src = (((src0 << 8) | src1) >> s1) & 0xff;
+ switch (combOp) {
+ case 0: // or
+ dest |= src;
+ break;
+ case 1: // and
+ dest &= src;
+ break;
+ case 2: // xor
+ dest ^= src;
+ break;
+ case 3: // xnor
+ dest ^= src ^ 0xff;
+ break;
+ case 4: // replace
+ dest = src;
+ break;
+ }
+ *destPtr++ = dest;
+ }
+
+ // right-most byte
+ // note: this last byte (src1) may not actually be used, depending
+ // on the values of s1, m1, and m2 - and in fact, it may be off
+ // the edge of the source bitmap, which means we need to allocate
+ // one extra guard byte at the end of each bitmap
+ dest = *destPtr;
+ src0 = src1;
+ src1 = *srcPtr++;
+ src = (((src0 << 8) | src1) >> s1) & 0xff;
+ switch (combOp) {
+ case 0: // or
+ dest |= src & m2;
+ break;
+ case 1: // and
+ dest &= src | m1;
+ break;
+ case 2: // xor
+ dest ^= src & m2;
+ break;
+ case 3: // xnor
+ dest ^= (src ^ 0xff) & m2;
+ break;
+ case 4: // replace
+ dest = (src & m2) | (dest & m1);
+ break;
+ }
+ *destPtr = dest;
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+// JBIG2SymbolDict
+//------------------------------------------------------------------------
+
+class JBIG2SymbolDict: public JBIG2Segment {
+public:
+
+ JBIG2SymbolDict(Guint segNumA, Guint sizeA);
+ virtual ~JBIG2SymbolDict();
+ virtual JBIG2SegmentType getType() { return jbig2SegSymbolDict; }
+ Guint getSize() { return size; }
+ void setBitmap(Guint idx, JBIG2Bitmap *bitmap) { bitmaps[idx] = bitmap; }
+ JBIG2Bitmap *getBitmap(Guint idx) { return bitmaps[idx]; }
+ void setGenericRegionStats(JArithmeticDecoderStats *stats)
+ { genericRegionStats = stats; }
+ void setRefinementRegionStats(JArithmeticDecoderStats *stats)
+ { refinementRegionStats = stats; }
+ JArithmeticDecoderStats *getGenericRegionStats()
+ { return genericRegionStats; }
+ JArithmeticDecoderStats *getRefinementRegionStats()
+ { return refinementRegionStats; }
+
+private:
+
+ Guint size;
+ JBIG2Bitmap **bitmaps;
+ JArithmeticDecoderStats *genericRegionStats;
+ JArithmeticDecoderStats *refinementRegionStats;
+};
+
+JBIG2SymbolDict::JBIG2SymbolDict(Guint segNumA, Guint sizeA):
+ JBIG2Segment(segNumA)
+{
+ Guint i;
+
+ size = sizeA;
+ bitmaps = (JBIG2Bitmap **)gmallocn(size, sizeof(JBIG2Bitmap *));
+ for (i = 0; i < size; ++i) {
+ bitmaps[i] = NULL;
+ }
+ genericRegionStats = NULL;
+ refinementRegionStats = NULL;
+}
+
+JBIG2SymbolDict::~JBIG2SymbolDict() {
+ Guint i;
+
+ for (i = 0; i < size; ++i) {
+ if (bitmaps[i]) {
+ delete bitmaps[i];
+ }
+ }
+ gfree(bitmaps);
+ if (genericRegionStats) {
+ delete genericRegionStats;
+ }
+ if (refinementRegionStats) {
+ delete refinementRegionStats;
+ }
+}
+
+//------------------------------------------------------------------------
+// JBIG2PatternDict
+//------------------------------------------------------------------------
+
+class JBIG2PatternDict: public JBIG2Segment {
+public:
+
+ JBIG2PatternDict(Guint segNumA, Guint sizeA);
+ virtual ~JBIG2PatternDict();
+ virtual JBIG2SegmentType getType() { return jbig2SegPatternDict; }
+ Guint getSize() { return size; }
+ void setBitmap(Guint idx, JBIG2Bitmap *bitmap) { bitmaps[idx] = bitmap; }
+ JBIG2Bitmap *getBitmap(Guint idx) { return bitmaps[idx]; }
+
+private:
+
+ Guint size;
+ JBIG2Bitmap **bitmaps;
+};
+
+JBIG2PatternDict::JBIG2PatternDict(Guint segNumA, Guint sizeA):
+ JBIG2Segment(segNumA)
+{
+ size = sizeA;
+ bitmaps = (JBIG2Bitmap **)gmallocn(size, sizeof(JBIG2Bitmap *));
+}
+
+JBIG2PatternDict::~JBIG2PatternDict() {
+ Guint i;
+
+ for (i = 0; i < size; ++i) {
+ delete bitmaps[i];
+ }
+ gfree(bitmaps);
+}
+
+//------------------------------------------------------------------------
+// JBIG2CodeTable
+//------------------------------------------------------------------------
+
+class JBIG2CodeTable: public JBIG2Segment {
+public:
+
+ JBIG2CodeTable(Guint segNumA, JBIG2HuffmanTable *tableA);
+ virtual ~JBIG2CodeTable();
+ virtual JBIG2SegmentType getType() { return jbig2SegCodeTable; }
+ JBIG2HuffmanTable *getHuffTable() { return table; }
+
+private:
+
+ JBIG2HuffmanTable *table;
+};
+
+JBIG2CodeTable::JBIG2CodeTable(Guint segNumA, JBIG2HuffmanTable *tableA):
+ JBIG2Segment(segNumA)
+{
+ table = tableA;
+}
+
+JBIG2CodeTable::~JBIG2CodeTable() {
+ gfree(table);
+}
+
+//------------------------------------------------------------------------
+// JBIG2Stream
+//------------------------------------------------------------------------
+
+JBIG2Stream::JBIG2Stream(Stream *strA, Object *globalsStreamA):
+ FilterStream(strA)
+{
+ pageBitmap = NULL;
+
+ arithDecoder = new JArithmeticDecoder();
+ genericRegionStats = new JArithmeticDecoderStats(1 << 1);
+ refinementRegionStats = new JArithmeticDecoderStats(1 << 1);
+ iadhStats = new JArithmeticDecoderStats(1 << 9);
+ iadwStats = new JArithmeticDecoderStats(1 << 9);
+ iaexStats = new JArithmeticDecoderStats(1 << 9);
+ iaaiStats = new JArithmeticDecoderStats(1 << 9);
+ iadtStats = new JArithmeticDecoderStats(1 << 9);
+ iaitStats = new JArithmeticDecoderStats(1 << 9);
+ iafsStats = new JArithmeticDecoderStats(1 << 9);
+ iadsStats = new JArithmeticDecoderStats(1 << 9);
+ iardxStats = new JArithmeticDecoderStats(1 << 9);
+ iardyStats = new JArithmeticDecoderStats(1 << 9);
+ iardwStats = new JArithmeticDecoderStats(1 << 9);
+ iardhStats = new JArithmeticDecoderStats(1 << 9);
+ iariStats = new JArithmeticDecoderStats(1 << 9);
+ iaidStats = new JArithmeticDecoderStats(1 << 1);
+ huffDecoder = new JBIG2HuffmanDecoder();
+ mmrDecoder = new JBIG2MMRDecoder();
+
+ globalsStreamA->copy(&globalsStream);
+ segments = globalSegments = NULL;
+ curStr = NULL;
+ dataPtr = dataEnd = NULL;
+}
+
+JBIG2Stream::~JBIG2Stream() {
+ close();
+ globalsStream.free();
+ delete arithDecoder;
+ delete genericRegionStats;
+ delete refinementRegionStats;
+ delete iadhStats;
+ delete iadwStats;
+ delete iaexStats;
+ delete iaaiStats;
+ delete iadtStats;
+ delete iaitStats;
+ delete iafsStats;
+ delete iadsStats;
+ delete iardxStats;
+ delete iardyStats;
+ delete iardwStats;
+ delete iardhStats;
+ delete iariStats;
+ delete iaidStats;
+ delete huffDecoder;
+ delete mmrDecoder;
+ delete str;
+}
+
+void JBIG2Stream::reset() {
+ // read the globals stream
+ globalSegments = new GList();
+ if (globalsStream.isStream()) {
+ segments = globalSegments;
+ curStr = globalsStream.getStream();
+ curStr->reset();
+ arithDecoder->setStream(curStr);
+ huffDecoder->setStream(curStr);
+ mmrDecoder->setStream(curStr);
+ readSegments();
+ curStr->close();
+ }
+
+ // read the main stream
+ segments = new GList();
+ curStr = str;
+ curStr->reset();
+ arithDecoder->setStream(curStr);
+ huffDecoder->setStream(curStr);
+ mmrDecoder->setStream(curStr);
+ readSegments();
+
+ if (pageBitmap) {
+ dataPtr = pageBitmap->getDataPtr();
+ dataEnd = dataPtr + pageBitmap->getDataSize();
+ } else {
+ dataPtr = dataEnd = NULL;
+ }
+}
+
+void JBIG2Stream::close() {
+ if (pageBitmap) {
+ delete pageBitmap;
+ pageBitmap = NULL;
+ }
+ if (segments) {
+ deleteGList(segments, JBIG2Segment);
+ segments = NULL;
+ }
+ if (globalSegments) {
+ deleteGList(globalSegments, JBIG2Segment);
+ globalSegments = NULL;
+ }
+ dataPtr = dataEnd = NULL;
+ FilterStream::close();
+}
+
+int JBIG2Stream::getChar() {
+ if (dataPtr && dataPtr < dataEnd) {
+ return (*dataPtr++ ^ 0xff) & 0xff;
+ }
+ return EOF;
+}
+
+int JBIG2Stream::lookChar() {
+ if (dataPtr && dataPtr < dataEnd) {
+ return (*dataPtr ^ 0xff) & 0xff;
+ }
+ return EOF;
+}
+
+GString *JBIG2Stream::getPSFilter(int /*psLevel*/, char * /*indent*/) {
+ return NULL;
+}
+
+GBool JBIG2Stream::isBinary(GBool /*last*/) {
+ return str->isBinary(gTrue);
+}
+
+void JBIG2Stream::readSegments() {
+ Guint segNum, segFlags, segType, page, segLength;
+ Guint refFlags, nRefSegs;
+ Guint *refSegs;
+ int segDataPos;
+ int c1, c2, c3;
+ Guint i;
+
+ while (readULong(&segNum)) {
+
+ // segment header flags
+ if (!readUByte(&segFlags)) {
+ goto eofError1;
+ }
+ segType = segFlags & 0x3f;
+
+ // referred-to segment count and retention flags
+ if (!readUByte(&refFlags)) {
+ goto eofError1;
+ }
+ nRefSegs = refFlags >> 5;
+ if (nRefSegs == 7) {
+ if ((c1 = curStr->getChar()) == EOF ||
+ (c2 = curStr->getChar()) == EOF ||
+ (c3 = curStr->getChar()) == EOF) {
+ goto eofError1;
+ }
+ refFlags = (refFlags << 24) | (c1 << 16) | (c2 << 8) | c3;
+ nRefSegs = refFlags & 0x1fffffff;
+ for (i = 0; i < (nRefSegs + 9) >> 3; ++i) {
+ c1 = curStr->getChar();
+ }
+ }
+
+ // referred-to segment numbers
+ refSegs = (Guint *)gmallocn(nRefSegs, sizeof(Guint));
+ if (segNum <= 256) {
+ for (i = 0; i < nRefSegs; ++i) {
+ if (!readUByte(&refSegs[i])) {
+ goto eofError2;
+ }
+ }
+ } else if (segNum <= 65536) {
+ for (i = 0; i < nRefSegs; ++i) {
+ if (!readUWord(&refSegs[i])) {
+ goto eofError2;
+ }
+ }
+ } else {
+ for (i = 0; i < nRefSegs; ++i) {
+ if (!readULong(&refSegs[i])) {
+ goto eofError2;
+ }
+ }
+ }
+
+ // segment page association
+ if (segFlags & 0x40) {
+ if (!readULong(&page)) {
+ goto eofError2;
+ }
+ } else {
+ if (!readUByte(&page)) {
+ goto eofError2;
+ }
+ }
+
+ // segment data length
+ if (!readULong(&segLength)) {
+ goto eofError2;
+ }
+
+ // keep track of the start of the segment data
+ segDataPos = getPos();
+
+ // check for missing page information segment
+ if (!pageBitmap && ((segType >= 4 && segType <= 7) ||
+ (segType >= 20 && segType <= 43))) {
+ error(getPos(), "First JBIG2 segment associated with a page must be a page information segment");
+ goto syntaxError;
+ }
+
+ // read the segment data
+ switch (segType) {
+ case 0:
+ if (!readSymbolDictSeg(segNum, segLength, refSegs, nRefSegs)) {
+ goto syntaxError;
+ }
+ break;
+ case 4:
+ readTextRegionSeg(segNum, gFalse, gFalse, segLength, refSegs, nRefSegs);
+ break;
+ case 6:
+ readTextRegionSeg(segNum, gTrue, gFalse, segLength, refSegs, nRefSegs);
+ break;
+ case 7:
+ readTextRegionSeg(segNum, gTrue, gTrue, segLength, refSegs, nRefSegs);
+ break;
+ case 16:
+ readPatternDictSeg(segNum, segLength);
+ break;
+ case 20:
+ readHalftoneRegionSeg(segNum, gFalse, gFalse, segLength,
+ refSegs, nRefSegs);
+ break;
+ case 22:
+ readHalftoneRegionSeg(segNum, gTrue, gFalse, segLength,
+ refSegs, nRefSegs);
+ break;
+ case 23:
+ readHalftoneRegionSeg(segNum, gTrue, gTrue, segLength,
+ refSegs, nRefSegs);
+ break;
+ case 36:
+ readGenericRegionSeg(segNum, gFalse, gFalse, segLength);
+ break;
+ case 38:
+ readGenericRegionSeg(segNum, gTrue, gFalse, segLength);
+ break;
+ case 39:
+ readGenericRegionSeg(segNum, gTrue, gTrue, segLength);
+ break;
+ case 40:
+ readGenericRefinementRegionSeg(segNum, gFalse, gFalse, segLength,
+ refSegs, nRefSegs);
+ break;
+ case 42:
+ readGenericRefinementRegionSeg(segNum, gTrue, gFalse, segLength,
+ refSegs, nRefSegs);
+ break;
+ case 43:
+ readGenericRefinementRegionSeg(segNum, gTrue, gTrue, segLength,
+ refSegs, nRefSegs);
+ break;
+ case 48:
+ readPageInfoSeg(segLength);
+ break;
+ case 50:
+ readEndOfStripeSeg(segLength);
+ break;
+ case 52:
+ readProfilesSeg(segLength);
+ break;
+ case 53:
+ readCodeTableSeg(segNum, segLength);
+ break;
+ case 62:
+ readExtensionSeg(segLength);
+ break;
+ default:
+ error(getPos(), "Unknown segment type in JBIG2 stream");
+ for (i = 0; i < segLength; ++i) {
+ if ((c1 = curStr->getChar()) == EOF) {
+ goto eofError2;
+ }
+ }
+ break;
+ }
+
+ // Make sure the segment handler read all of the bytes in the
+ // segment data, unless this segment is marked as having an
+ // unknown length (section 7.2.7 of the JBIG2 Final Committee Draft)
+
+ if (segLength != 0xffffffff) {
+
+ int segExtraBytes = segDataPos + segLength - getPos();
+ if (segExtraBytes > 0) {
+
+ // If we didn't read all of the bytes in the segment data,
+ // indicate an error, and throw away the rest of the data.
+
+ // v.3.1.01.13 of the LuraTech PDF Compressor Server will
+ // sometimes generate an extraneous NULL byte at the end of
+ // arithmetic-coded symbol dictionary segments when numNewSyms
+ // == 0. Segments like this often occur for blank pages.
+
+ error(getPos(), "%d extraneous byte%s after segment",
+ segExtraBytes, (segExtraBytes > 1) ? "s" : "");
+
+ // Burn through the remaining bytes -- inefficient, but
+ // hopefully we're not doing this much
+
+ int trash;
+ for (int i = segExtraBytes; i > 0; i--) {
+ readByte(&trash);
+ }
+
+ } else if (segExtraBytes < 0) {
+
+ // If we read more bytes than we should have, according to the
+ // segment length field, note an error.
+
+ error(getPos(), "Previous segment handler read too many bytes");
+
+ }
+
+ }
+
+ gfree(refSegs);
+ }
+
+ return;
+
+ syntaxError:
+ gfree(refSegs);
+ return;
+
+ eofError2:
+ gfree(refSegs);
+ eofError1:
+ error(getPos(), "Unexpected EOF in JBIG2 stream");
+}
+
+GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint /*length*/,
+ Guint *refSegs, Guint nRefSegs) {
+ JBIG2SymbolDict *symbolDict;
+ JBIG2HuffmanTable *huffDHTable, *huffDWTable;
+ JBIG2HuffmanTable *huffBMSizeTable, *huffAggInstTable;
+ JBIG2Segment *seg;
+ GList *codeTables;
+ JBIG2SymbolDict *inputSymbolDict;
+ Guint flags, sdTemplate, sdrTemplate, huff, refAgg;
+ Guint huffDH, huffDW, huffBMSize, huffAggInst;
+ Guint contextUsed, contextRetained;
+ int sdATX[4], sdATY[4], sdrATX[2], sdrATY[2];
+ Guint numExSyms, numNewSyms, numInputSyms, symCodeLen;
+ JBIG2Bitmap **bitmaps;
+ JBIG2Bitmap *collBitmap, *refBitmap;
+ Guint *symWidths;
+ Guint symHeight, symWidth, totalWidth, x, symID;
+ int dh, dw, refAggNum, refDX, refDY, bmSize;
+ GBool ex;
+ int run, cnt;
+ Guint i, j, k;
+ Guchar *p;
+
+ symWidths = NULL;
+
+ // symbol dictionary flags
+ if (!readUWord(&flags)) {
+ goto eofError;
+ }
+ sdTemplate = (flags >> 10) & 3;
+ sdrTemplate = (flags >> 12) & 1;
+ huff = flags & 1;
+ refAgg = (flags >> 1) & 1;
+ huffDH = (flags >> 2) & 3;
+ huffDW = (flags >> 4) & 3;
+ huffBMSize = (flags >> 6) & 1;
+ huffAggInst = (flags >> 7) & 1;
+ contextUsed = (flags >> 8) & 1;
+ contextRetained = (flags >> 9) & 1;
+
+ // symbol dictionary AT flags
+ if (!huff) {
+ if (sdTemplate == 0) {
+ if (!readByte(&sdATX[0]) ||
+ !readByte(&sdATY[0]) ||
+ !readByte(&sdATX[1]) ||
+ !readByte(&sdATY[1]) ||
+ !readByte(&sdATX[2]) ||
+ !readByte(&sdATY[2]) ||
+ !readByte(&sdATX[3]) ||
+ !readByte(&sdATY[3])) {
+ goto eofError;
+ }
+ } else {
+ if (!readByte(&sdATX[0]) ||
+ !readByte(&sdATY[0])) {
+ goto eofError;
+ }
+ }
+ }
+
+ // symbol dictionary refinement AT flags
+ if (refAgg && !sdrTemplate) {
+ if (!readByte(&sdrATX[0]) ||
+ !readByte(&sdrATY[0]) ||
+ !readByte(&sdrATX[1]) ||
+ !readByte(&sdrATY[1])) {
+ goto eofError;
+ }
+ }
+
+ // SDNUMEXSYMS and SDNUMNEWSYMS
+ if (!readULong(&numExSyms) || !readULong(&numNewSyms)) {
+ goto eofError;
+ }
+
+ // get referenced segments: input symbol dictionaries and code tables
+ codeTables = new GList();
+ numInputSyms = 0;
+ for (i = 0; i < nRefSegs; ++i) {
+ if ((seg = findSegment(refSegs[i]))) {
+ if (seg->getType() == jbig2SegSymbolDict) {
+ j = ((JBIG2SymbolDict *)seg)->getSize();
+ if (numInputSyms > UINT_MAX - j) {
+ error(getPos(), "Too many input symbols in JBIG2 symbol dictionary");
+ delete codeTables;
+ goto eofError;
+ }
+ numInputSyms += j;
+ } else if (seg->getType() == jbig2SegCodeTable) {
+ codeTables->append(seg);
+ }
+ }
+ }
+ if (numInputSyms > UINT_MAX - numNewSyms) {
+ error(getPos(), "Too many input symbols in JBIG2 symbol dictionary");
+ delete codeTables;
+ goto eofError;
+ }
+
+ // compute symbol code length
+ symCodeLen = 1;
+ i = (numInputSyms + numNewSyms) >> 1;
+ while (i) {
+ ++symCodeLen;
+ i >>= 1;
+ }
+
+ // get the input symbol bitmaps
+ bitmaps = (JBIG2Bitmap **)gmallocn(numInputSyms + numNewSyms,
+ sizeof(JBIG2Bitmap *));
+ for (i = 0; i < numInputSyms + numNewSyms; ++i) {
+ bitmaps[i] = NULL;
+ }
+ k = 0;
+ inputSymbolDict = NULL;
+ for (i = 0; i < nRefSegs; ++i) {
+ if ((seg = findSegment(refSegs[i]))) {
+ if (seg->getType() == jbig2SegSymbolDict) {
+ inputSymbolDict = (JBIG2SymbolDict *)seg;
+ for (j = 0; j < inputSymbolDict->getSize(); ++j) {
+ bitmaps[k++] = inputSymbolDict->getBitmap(j);
+ }
+ }
+ }
+ }
+
+ // get the Huffman tables
+ huffDHTable = huffDWTable = NULL; // make gcc happy
+ huffBMSizeTable = huffAggInstTable = NULL; // make gcc happy
+ i = 0;
+ if (huff) {
+ if (huffDH == 0) {
+ huffDHTable = huffTableD;
+ } else if (huffDH == 1) {
+ huffDHTable = huffTableE;
+ } else {
+ if (i >= (Guint)codeTables->getLength()) {
+ goto codeTableError;
+ }
+ huffDHTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
+ }
+ if (huffDW == 0) {
+ huffDWTable = huffTableB;
+ } else if (huffDW == 1) {
+ huffDWTable = huffTableC;
+ } else {
+ if (i >= (Guint)codeTables->getLength()) {
+ goto codeTableError;
+ }
+ huffDWTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
+ }
+ if (huffBMSize == 0) {
+ huffBMSizeTable = huffTableA;
+ } else {
+ if (i >= (Guint)codeTables->getLength()) {
+ goto codeTableError;
+ }
+ huffBMSizeTable =
+ ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
+ }
+ if (huffAggInst == 0) {
+ huffAggInstTable = huffTableA;
+ } else {
+ if (i >= (Guint)codeTables->getLength()) {
+ goto codeTableError;
+ }
+ huffAggInstTable =
+ ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
+ }
+ }
+ delete codeTables;
+
+ // set up the Huffman decoder
+ if (huff) {
+ huffDecoder->reset();
+
+ // set up the arithmetic decoder
+ } else {
+ if (contextUsed && inputSymbolDict) {
+ resetGenericStats(sdTemplate, inputSymbolDict->getGenericRegionStats());
+ } else {
+ resetGenericStats(sdTemplate, NULL);
+ }
+ resetIntStats(symCodeLen);
+ arithDecoder->start();
+ }
+
+ // set up the arithmetic decoder for refinement/aggregation
+ if (refAgg) {
+ if (contextUsed && inputSymbolDict) {
+ resetRefinementStats(sdrTemplate,
+ inputSymbolDict->getRefinementRegionStats());
+ } else {
+ resetRefinementStats(sdrTemplate, NULL);
+ }
+ }
+
+ // allocate symbol widths storage
+ if (huff && !refAgg) {
+ symWidths = (Guint *)gmallocn(numNewSyms, sizeof(Guint));
+ }
+
+ symHeight = 0;
+ i = 0;
+ while (i < numNewSyms) {
+
+ // read the height class delta height
+ if (huff) {
+ huffDecoder->decodeInt(&dh, huffDHTable);
+ } else {
+ arithDecoder->decodeInt(&dh, iadhStats);
+ }
+ if (dh < 0 && (Guint)-dh >= symHeight) {
+ error(getPos(), "Bad delta-height value in JBIG2 symbol dictionary");
+ goto syntaxError;
+ }
+ symHeight += dh;
+ symWidth = 0;
+ totalWidth = 0;
+ j = i;
+
+ // read the symbols in this height class
+ while (1) {
+
+ // read the delta width
+ if (huff) {
+ if (!huffDecoder->decodeInt(&dw, huffDWTable)) {
+ break;
+ }
+ } else {
+ if (!arithDecoder->decodeInt(&dw, iadwStats)) {
+ break;
+ }
+ }
+ if (dw < 0 && (Guint)-dw >= symWidth) {
+ error(getPos(), "Bad delta-height value in JBIG2 symbol dictionary");
+ goto syntaxError;
+ }
+ symWidth += dw;
+ if (i >= numNewSyms) {
+ error(getPos(), "Too many symbols in JBIG2 symbol dictionary");
+ goto syntaxError;
+ }
+
+ // using a collective bitmap, so don't read a bitmap here
+ if (huff && !refAgg) {
+ symWidths[i] = symWidth;
+ totalWidth += symWidth;
+
+ // refinement/aggregate coding
+ } else if (refAgg) {
+ if (huff) {
+ if (!huffDecoder->decodeInt(&refAggNum, huffAggInstTable)) {
+ break;
+ }
+ } else {
+ if (!arithDecoder->decodeInt(&refAggNum, iaaiStats)) {
+ break;
+ }
+ }
+#if 0 //~ This special case was added about a year before the final draft
+ //~ of the JBIG2 spec was released. I have encountered some old
+ //~ JBIG2 images that predate it.
+ if (0) {
+#else
+ if (refAggNum == 1) {
+#endif
+ if (huff) {
+ symID = huffDecoder->readBits(symCodeLen);
+ huffDecoder->decodeInt(&refDX, huffTableO);
+ huffDecoder->decodeInt(&refDY, huffTableO);
+ huffDecoder->decodeInt(&bmSize, huffTableA);
+ huffDecoder->reset();
+ arithDecoder->start();
+ } else {
+ symID = arithDecoder->decodeIAID(symCodeLen, iaidStats);
+ arithDecoder->decodeInt(&refDX, iardxStats);
+ arithDecoder->decodeInt(&refDY, iardyStats);
+ }
+ if (symID >= numInputSyms + i) {
+ error(getPos(), "Invalid symbol ID in JBIG2 symbol dictionary");
+ goto syntaxError;
+ }
+ refBitmap = bitmaps[symID];
+ bitmaps[numInputSyms + i] =
+ readGenericRefinementRegion(symWidth, symHeight,
+ sdrTemplate, gFalse,
+ refBitmap, refDX, refDY,
+ sdrATX, sdrATY);
+ //~ do we need to use the bmSize value here (in Huffman mode)?
+ } else {
+ bitmaps[numInputSyms + i] =
+ readTextRegion(huff, gTrue, symWidth, symHeight,
+ refAggNum, 0, numInputSyms + i, NULL,
+ symCodeLen, bitmaps, 0, 0, 0, 1, 0,
+ huffTableF, huffTableH, huffTableK, huffTableO,
+ huffTableO, huffTableO, huffTableO, huffTableA,
+ sdrTemplate, sdrATX, sdrATY);
+ }
+
+ // non-ref/agg coding
+ } else {
+ bitmaps[numInputSyms + i] =
+ readGenericBitmap(gFalse, symWidth, symHeight,
+ sdTemplate, gFalse, gFalse, NULL,
+ sdATX, sdATY, 0);
+ }
+
+ ++i;
+ }
+
+ // read the collective bitmap
+ if (huff && !refAgg) {
+ huffDecoder->decodeInt(&bmSize, huffBMSizeTable);
+ huffDecoder->reset();
+ if (bmSize == 0) {
+ collBitmap = new JBIG2Bitmap(0, totalWidth, symHeight);
+ bmSize = symHeight * ((totalWidth + 7) >> 3);
+ p = collBitmap->getDataPtr();
+ for (k = 0; k < (Guint)bmSize; ++k) {
+ *p++ = curStr->getChar();
+ }
+ } else {
+ collBitmap = readGenericBitmap(gTrue, totalWidth, symHeight,
+ 0, gFalse, gFalse, NULL, NULL, NULL,
+ bmSize);
+ }
+ x = 0;
+ for (; j < i; ++j) {
+ bitmaps[numInputSyms + j] =
+ collBitmap->getSlice(x, 0, symWidths[j], symHeight);
+ x += symWidths[j];
+ }
+ delete collBitmap;
+ }
+ }
+
+ // create the symbol dict object
+ symbolDict = new JBIG2SymbolDict(segNum, numExSyms);
+
+ // exported symbol list
+ i = j = 0;
+ ex = gFalse;
+ while (i < numInputSyms + numNewSyms) {
+ if (huff) {
+ huffDecoder->decodeInt(&run, huffTableA);
+ } else {
+ arithDecoder->decodeInt(&run, iaexStats);
+ }
+ if (i + run > numInputSyms + numNewSyms ||
+ (ex && j + run > numExSyms)) {
+ error(getPos(), "Too many exported symbols in JBIG2 symbol dictionary");
+ delete symbolDict;
+ goto syntaxError;
+ }
+ if (ex) {
+ for (cnt = 0; cnt < run; ++cnt) {
+ symbolDict->setBitmap(j++, bitmaps[i++]->copy());
+ }
+ } else {
+ i += run;
+ }
+ ex = !ex;
+ }
+ if (j != numExSyms) {
+ error(getPos(), "Too few symbols in JBIG2 symbol dictionary");
+ delete symbolDict;
+ goto syntaxError;
+ }
+
+ for (i = 0; i < numNewSyms; ++i) {
+ delete bitmaps[numInputSyms + i];
+ }
+ gfree(bitmaps);
+ if (symWidths) {
+ gfree(symWidths);
+ }
+
+ // save the arithmetic decoder stats
+ if (!huff && contextRetained) {
+ symbolDict->setGenericRegionStats(genericRegionStats->copy());
+ if (refAgg) {
+ symbolDict->setRefinementRegionStats(refinementRegionStats->copy());
+ }
+ }
+
+ // store the new symbol dict
+ segments->append(symbolDict);
+
+ return gTrue;
+
+ codeTableError:
+ error(getPos(), "Missing code table in JBIG2 symbol dictionary");
+ delete codeTables;
+
+ syntaxError:
+ for (i = 0; i < numNewSyms; ++i) {
+ if (bitmaps[numInputSyms + i]) {
+ delete bitmaps[numInputSyms + i];
+ }
+ }
+ gfree(bitmaps);
+ if (symWidths) {
+ gfree(symWidths);
+ }
+ return gFalse;
+
+ eofError:
+ error(getPos(), "Unexpected EOF in JBIG2 stream");
+ return gFalse;
+}
+
+void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm,
+ GBool /*lossless*/, Guint /*length*/,
+ Guint *refSegs, Guint nRefSegs) {
+ JBIG2Bitmap *bitmap;
+ JBIG2HuffmanTable runLengthTab[36];
+ JBIG2HuffmanTable *symCodeTab;
+ JBIG2HuffmanTable *huffFSTable, *huffDSTable, *huffDTTable;
+ JBIG2HuffmanTable *huffRDWTable, *huffRDHTable;
+ JBIG2HuffmanTable *huffRDXTable, *huffRDYTable, *huffRSizeTable;
+ JBIG2Segment *seg;
+ GList *codeTables;
+ JBIG2SymbolDict *symbolDict;
+ JBIG2Bitmap **syms;
+ Guint w, h, x, y, segInfoFlags, extCombOp;
+ Guint flags, huff, refine, logStrips, refCorner, transposed;
+ Guint combOp, defPixel, templ;
+ int sOffset;
+ Guint huffFlags, huffFS, huffDS, huffDT;
+ Guint huffRDW, huffRDH, huffRDX, huffRDY, huffRSize;
+ Guint numInstances, numSyms, symCodeLen;
+ int atx[2], aty[2];
+ Guint i, k, kk;
+ int j;
+
+ // region segment info field
+ if (!readULong(&w) || !readULong(&h) ||
+ !readULong(&x) || !readULong(&y) ||
+ !readUByte(&segInfoFlags)) {
+ goto eofError;
+ }
+ extCombOp = segInfoFlags & 7;
+
+ // rest of the text region header
+ if (!readUWord(&flags)) {
+ goto eofError;
+ }
+ huff = flags & 1;
+ refine = (flags >> 1) & 1;
+ logStrips = (flags >> 2) & 3;
+ refCorner = (flags >> 4) & 3;
+ transposed = (flags >> 6) & 1;
+ combOp = (flags >> 7) & 3;
+ defPixel = (flags >> 9) & 1;
+ sOffset = (flags >> 10) & 0x1f;
+ if (sOffset & 0x10) {
+ sOffset |= -1 - 0x0f;
+ }
+ templ = (flags >> 15) & 1;
+ huffFS = huffDS = huffDT = 0; // make gcc happy
+ huffRDW = huffRDH = huffRDX = huffRDY = huffRSize = 0; // make gcc happy
+ if (huff) {
+ if (!readUWord(&huffFlags)) {
+ goto eofError;
+ }
+ huffFS = huffFlags & 3;
+ huffDS = (huffFlags >> 2) & 3;
+ huffDT = (huffFlags >> 4) & 3;
+ huffRDW = (huffFlags >> 6) & 3;
+ huffRDH = (huffFlags >> 8) & 3;
+ huffRDX = (huffFlags >> 10) & 3;
+ huffRDY = (huffFlags >> 12) & 3;
+ huffRSize = (huffFlags >> 14) & 1;
+ }
+ if (refine && templ == 0) {
+ if (!readByte(&atx[0]) || !readByte(&aty[0]) ||
+ !readByte(&atx[1]) || !readByte(&aty[1])) {
+ goto eofError;
+ }
+ }
+ if (!readULong(&numInstances)) {
+ goto eofError;
+ }
+
+ // get symbol dictionaries and tables
+ codeTables = new GList();
+ numSyms = 0;
+ for (i = 0; i < nRefSegs; ++i) {
+ if ((seg = findSegment(refSegs[i]))) {
+ if (seg->getType() == jbig2SegSymbolDict) {
+ numSyms += ((JBIG2SymbolDict *)seg)->getSize();
+ } else if (seg->getType() == jbig2SegCodeTable) {
+ codeTables->append(seg);
+ }
+ } else {
+ error(getPos(), "Invalid segment reference in JBIG2 text region");
+ delete codeTables;
+ return;
+ }
+ }
+ symCodeLen = 0;
+ i = 1;
+ while (i < numSyms) {
+ ++symCodeLen;
+ i <<= 1;
+ }
+
+ // get the symbol bitmaps
+ syms = (JBIG2Bitmap **)gmallocn(numSyms, sizeof(JBIG2Bitmap *));
+ kk = 0;
+ for (i = 0; i < nRefSegs; ++i) {
+ if ((seg = findSegment(refSegs[i]))) {
+ if (seg->getType() == jbig2SegSymbolDict) {
+ symbolDict = (JBIG2SymbolDict *)seg;
+ for (k = 0; k < symbolDict->getSize(); ++k) {
+ syms[kk++] = symbolDict->getBitmap(k);
+ }
+ }
+ }
+ }
+
+ // get the Huffman tables
+ huffFSTable = huffDSTable = huffDTTable = NULL; // make gcc happy
+ huffRDWTable = huffRDHTable = NULL; // make gcc happy
+ huffRDXTable = huffRDYTable = huffRSizeTable = NULL; // make gcc happy
+ i = 0;
+ if (huff) {
+ if (huffFS == 0) {
+ huffFSTable = huffTableF;
+ } else if (huffFS == 1) {
+ huffFSTable = huffTableG;
+ } else {
+ if (i >= (Guint)codeTables->getLength()) {
+ goto codeTableError;
+ }
+ huffFSTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
+ }
+ if (huffDS == 0) {
+ huffDSTable = huffTableH;
+ } else if (huffDS == 1) {
+ huffDSTable = huffTableI;
+ } else if (huffDS == 2) {
+ huffDSTable = huffTableJ;
+ } else {
+ if (i >= (Guint)codeTables->getLength()) {
+ goto codeTableError;
+ }
+ huffDSTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
+ }
+ if (huffDT == 0) {
+ huffDTTable = huffTableK;
+ } else if (huffDT == 1) {
+ huffDTTable = huffTableL;
+ } else if (huffDT == 2) {
+ huffDTTable = huffTableM;
+ } else {
+ if (i >= (Guint)codeTables->getLength()) {
+ goto codeTableError;
+ }
+ huffDTTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
+ }
+ if (huffRDW == 0) {
+ huffRDWTable = huffTableN;
+ } else if (huffRDW == 1) {
+ huffRDWTable = huffTableO;
+ } else {
+ if (i >= (Guint)codeTables->getLength()) {
+ goto codeTableError;
+ }
+ huffRDWTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
+ }
+ if (huffRDH == 0) {
+ huffRDHTable = huffTableN;
+ } else if (huffRDH == 1) {
+ huffRDHTable = huffTableO;
+ } else {
+ if (i >= (Guint)codeTables->getLength()) {
+ goto codeTableError;
+ }
+ huffRDHTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
+ }
+ if (huffRDX == 0) {
+ huffRDXTable = huffTableN;
+ } else if (huffRDX == 1) {
+ huffRDXTable = huffTableO;
+ } else {
+ if (i >= (Guint)codeTables->getLength()) {
+ goto codeTableError;
+ }
+ huffRDXTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
+ }
+ if (huffRDY == 0) {
+ huffRDYTable = huffTableN;
+ } else if (huffRDY == 1) {
+ huffRDYTable = huffTableO;
+ } else {
+ if (i >= (Guint)codeTables->getLength()) {
+ goto codeTableError;
+ }
+ huffRDYTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
+ }
+ if (huffRSize == 0) {
+ huffRSizeTable = huffTableA;
+ } else {
+ if (i >= (Guint)codeTables->getLength()) {
+ goto codeTableError;
+ }
+ huffRSizeTable =
+ ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable();
+ }
+ }
+ delete codeTables;
+
+ // symbol ID Huffman decoding table
+ if (huff) {
+ huffDecoder->reset();
+ for (i = 0; i < 32; ++i) {
+ runLengthTab[i].val = i;
+ runLengthTab[i].prefixLen = huffDecoder->readBits(4);
+ runLengthTab[i].rangeLen = 0;
+ }
+ runLengthTab[32].val = 0x103;
+ runLengthTab[32].prefixLen = huffDecoder->readBits(4);
+ runLengthTab[32].rangeLen = 2;
+ runLengthTab[33].val = 0x203;
+ runLengthTab[33].prefixLen = huffDecoder->readBits(4);
+ runLengthTab[33].rangeLen = 3;
+ runLengthTab[34].val = 0x20b;
+ runLengthTab[34].prefixLen = huffDecoder->readBits(4);
+ runLengthTab[34].rangeLen = 7;
+ runLengthTab[35].prefixLen = 0;
+ runLengthTab[35].rangeLen = jbig2HuffmanEOT;
+ huffDecoder->buildTable(runLengthTab, 35);
+ symCodeTab = (JBIG2HuffmanTable *)gmallocn(numSyms + 1,
+ sizeof(JBIG2HuffmanTable));
+ for (i = 0; i < numSyms; ++i) {
+ symCodeTab[i].val = i;
+ symCodeTab[i].rangeLen = 0;
+ }
+ i = 0;
+ while (i < numSyms) {
+ huffDecoder->decodeInt(&j, runLengthTab);
+ if (j > 0x200) {
+ for (j -= 0x200; j && i < numSyms; --j) {
+ symCodeTab[i++].prefixLen = 0;
+ }
+ } else if (j > 0x100) {
+ for (j -= 0x100; j && i < numSyms; --j) {
+ symCodeTab[i].prefixLen = symCodeTab[i-1].prefixLen;
+ ++i;
+ }
+ } else {
+ symCodeTab[i++].prefixLen = j;
+ }
+ }
+ symCodeTab[numSyms].prefixLen = 0;
+ symCodeTab[numSyms].rangeLen = jbig2HuffmanEOT;
+ huffDecoder->buildTable(symCodeTab, numSyms);
+ huffDecoder->reset();
+
+ // set up the arithmetic decoder
+ } else {
+ symCodeTab = NULL;
+ resetIntStats(symCodeLen);
+ arithDecoder->start();
+ }
+ if (refine) {
+ resetRefinementStats(templ, NULL);
+ }
+
+ bitmap = readTextRegion(huff, refine, w, h, numInstances,
+ logStrips, numSyms, symCodeTab, symCodeLen, syms,
+ defPixel, combOp, transposed, refCorner, sOffset,
+ huffFSTable, huffDSTable, huffDTTable,
+ huffRDWTable, huffRDHTable,
+ huffRDXTable, huffRDYTable, huffRSizeTable,
+ templ, atx, aty);
+
+ gfree(syms);
+
+ // combine the region bitmap into the page bitmap
+ if (imm) {
+ if (pageH == 0xffffffff && y + h > curPageH) {
+ pageBitmap->expand(y + h, pageDefPixel);
+ }
+ pageBitmap->combine(bitmap, x, y, extCombOp);
+ delete bitmap;
+
+ // store the region bitmap
+ } else {
+ bitmap->setSegNum(segNum);
+ segments->append(bitmap);
+ }
+
+ // clean up the Huffman decoder
+ if (huff) {
+ gfree(symCodeTab);
+ }
+
+ return;
+
+ codeTableError:
+ error(getPos(), "Missing code table in JBIG2 text region");
+ gfree(codeTables);
+ delete syms;
+ return;
+
+ eofError:
+ error(getPos(), "Unexpected EOF in JBIG2 stream");
+ return;
+}
+
+JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine,
+ int w, int h,
+ Guint numInstances,
+ Guint logStrips,
+ int numSyms,
+ JBIG2HuffmanTable *symCodeTab,
+ Guint symCodeLen,
+ JBIG2Bitmap **syms,
+ Guint defPixel, Guint combOp,
+ Guint transposed, Guint refCorner,
+ int sOffset,
+ JBIG2HuffmanTable *huffFSTable,
+ JBIG2HuffmanTable *huffDSTable,
+ JBIG2HuffmanTable *huffDTTable,
+ JBIG2HuffmanTable *huffRDWTable,
+ JBIG2HuffmanTable *huffRDHTable,
+ JBIG2HuffmanTable *huffRDXTable,
+ JBIG2HuffmanTable *huffRDYTable,
+ JBIG2HuffmanTable *huffRSizeTable,
+ Guint templ,
+ int *atx, int *aty) {
+ JBIG2Bitmap *bitmap;
+ JBIG2Bitmap *symbolBitmap;
+ Guint strips;
+ int t, dt, tt, s, ds, sFirst, j;
+ int rdw, rdh, rdx, rdy, ri, refDX, refDY, bmSize;
+ Guint symID, inst, bw, bh;
+
+ strips = 1 << logStrips;
+
+ // allocate the bitmap
+ bitmap = new JBIG2Bitmap(0, w, h);
+ if (defPixel) {
+ bitmap->clearToOne();
+ } else {
+ bitmap->clearToZero();
+ }
+
+ // decode initial T value
+ if (huff) {
+ huffDecoder->decodeInt(&t, huffDTTable);
+ } else {
+ arithDecoder->decodeInt(&t, iadtStats);
+ }
+ t *= -(int)strips;
+
+ inst = 0;
+ sFirst = 0;
+ while (inst < numInstances) {
+
+ // decode delta-T
+ if (huff) {
+ huffDecoder->decodeInt(&dt, huffDTTable);
+ } else {
+ arithDecoder->decodeInt(&dt, iadtStats);
+ }
+ t += dt * strips;
+
+ // first S value
+ if (huff) {
+ huffDecoder->decodeInt(&ds, huffFSTable);
+ } else {
+ arithDecoder->decodeInt(&ds, iafsStats);
+ }
+ sFirst += ds;
+ s = sFirst;
+
+ // read the instances
+ while (1) {
+
+ // T value
+ if (strips == 1) {
+ dt = 0;
+ } else if (huff) {
+ dt = huffDecoder->readBits(logStrips);
+ } else {
+ arithDecoder->decodeInt(&dt, iaitStats);
+ }
+ tt = t + dt;
+
+ // symbol ID
+ if (huff) {
+ if (symCodeTab) {
+ huffDecoder->decodeInt(&j, symCodeTab);
+ symID = (Guint)j;
+ } else {
+ symID = huffDecoder->readBits(symCodeLen);
+ }
+ } else {
+ symID = arithDecoder->decodeIAID(symCodeLen, iaidStats);
+ }
+
+ if (symID >= (Guint)numSyms) {
+ error(getPos(), "Invalid symbol number in JBIG2 text region");
+ } else {
+
+ // get the symbol bitmap
+ symbolBitmap = NULL;
+ if (refine) {
+ if (huff) {
+ ri = (int)huffDecoder->readBit();
+ } else {
+ arithDecoder->decodeInt(&ri, iariStats);
+ }
+ } else {
+ ri = 0;
+ }
+ if (ri) {
+ if (huff) {
+ huffDecoder->decodeInt(&rdw, huffRDWTable);
+ huffDecoder->decodeInt(&rdh, huffRDHTable);
+ huffDecoder->decodeInt(&rdx, huffRDXTable);
+ huffDecoder->decodeInt(&rdy, huffRDYTable);
+ huffDecoder->decodeInt(&bmSize, huffRSizeTable);
+ huffDecoder->reset();
+ arithDecoder->start();
+ } else {
+ arithDecoder->decodeInt(&rdw, iardwStats);
+ arithDecoder->decodeInt(&rdh, iardhStats);
+ arithDecoder->decodeInt(&rdx, iardxStats);
+ arithDecoder->decodeInt(&rdy, iardyStats);
+ }
+ refDX = ((rdw >= 0) ? rdw : rdw - 1) / 2 + rdx;
+ refDY = ((rdh >= 0) ? rdh : rdh - 1) / 2 + rdy;
+
+ symbolBitmap =
+ readGenericRefinementRegion(rdw + syms[symID]->getWidth(),
+ rdh + syms[symID]->getHeight(),
+ templ, gFalse, syms[symID],
+ refDX, refDY, atx, aty);
+ //~ do we need to use the bmSize value here (in Huffman mode)?
+ } else {
+ symbolBitmap = syms[symID];
+ }
+
+ // combine the symbol bitmap into the region bitmap
+ //~ something is wrong here - refCorner shouldn't degenerate into
+ //~ two cases
+ bw = symbolBitmap->getWidth() - 1;
+ bh = symbolBitmap->getHeight() - 1;
+ if (transposed) {
+ switch (refCorner) {
+ case 0: // bottom left
+ bitmap->combine(symbolBitmap, tt, s, combOp);
+ break;
+ case 1: // top left
+ bitmap->combine(symbolBitmap, tt, s, combOp);
+ break;
+ case 2: // bottom right
+ bitmap->combine(symbolBitmap, tt - bw, s, combOp);
+ break;
+ case 3: // top right
+ bitmap->combine(symbolBitmap, tt - bw, s, combOp);
+ break;
+ }
+ s += bh;
+ } else {
+ switch (refCorner) {
+ case 0: // bottom left
+ bitmap->combine(symbolBitmap, s, tt - bh, combOp);
+ break;
+ case 1: // top left
+ bitmap->combine(symbolBitmap, s, tt, combOp);
+ break;
+ case 2: // bottom right
+ bitmap->combine(symbolBitmap, s, tt - bh, combOp);
+ break;
+ case 3: // top right
+ bitmap->combine(symbolBitmap, s, tt, combOp);
+ break;
+ }
+ s += bw;
+ }
+ if (ri) {
+ delete symbolBitmap;
+ }
+ }
+
+ // next instance
+ ++inst;
+
+ // next S value
+ if (huff) {
+ if (!huffDecoder->decodeInt(&ds, huffDSTable)) {
+ break;
+ }
+ } else {
+ if (!arithDecoder->decodeInt(&ds, iadsStats)) {
+ break;
+ }
+ }
+ s += sOffset + ds;
+ }
+ }
+
+ return bitmap;
+}
+
+void JBIG2Stream::readPatternDictSeg(Guint segNum, Guint length) {
+ JBIG2PatternDict *patternDict;
+ JBIG2Bitmap *bitmap;
+ Guint flags, patternW, patternH, grayMax, templ, mmr;
+ int atx[4], aty[4];
+ Guint i, x;
+
+ // halftone dictionary flags, pattern width and height, max gray value
+ if (!readUByte(&flags) ||
+ !readUByte(&patternW) ||
+ !readUByte(&patternH) ||
+ !readULong(&grayMax)) {
+ goto eofError;
+ }
+ templ = (flags >> 1) & 3;
+ mmr = flags & 1;
+
+ // set up the arithmetic decoder
+ if (!mmr) {
+ resetGenericStats(templ, NULL);
+ arithDecoder->start();
+ }
+
+ // read the bitmap
+ atx[0] = -(int)patternW; aty[0] = 0;
+ atx[1] = -3; aty[1] = -1;
+ atx[2] = 2; aty[2] = -2;
+ atx[3] = -2; aty[3] = -2;
+ bitmap = readGenericBitmap(mmr, (grayMax + 1) * patternW, patternH,
+ templ, gFalse, gFalse, NULL,
+ atx, aty, length - 7);
+
+ // create the pattern dict object
+ patternDict = new JBIG2PatternDict(segNum, grayMax + 1);
+
+ // split up the bitmap
+ x = 0;
+ for (i = 0; i <= grayMax; ++i) {
+ patternDict->setBitmap(i, bitmap->getSlice(x, 0, patternW, patternH));
+ x += patternW;
+ }
+
+ // free memory
+ delete bitmap;
+
+ // store the new pattern dict
+ segments->append(patternDict);
+
+ return;
+
+ eofError:
+ error(getPos(), "Unexpected EOF in JBIG2 stream");
+}
+
+void JBIG2Stream::readHalftoneRegionSeg(Guint segNum, GBool imm,
+ GBool /*lossless*/, Guint /*length*/,
+ Guint *refSegs, Guint nRefSegs) {
+ JBIG2Bitmap *bitmap;
+ JBIG2Segment *seg;
+ JBIG2PatternDict *patternDict;
+ JBIG2Bitmap *skipBitmap;
+ Guint *grayImg;
+ JBIG2Bitmap *grayBitmap;
+ JBIG2Bitmap *patternBitmap;
+ Guint w, h, x, y, segInfoFlags, extCombOp;
+ Guint flags, mmr, templ, enableSkip, combOp;
+ Guint gridW, gridH, stepX, stepY, patW, patH;
+ int atx[4], aty[4];
+ int gridX, gridY, xx, yy, bit, j;
+ Guint bpp, m, n, i;
+
+ // region segment info field
+ if (!readULong(&w) || !readULong(&h) ||
+ !readULong(&x) || !readULong(&y) ||
+ !readUByte(&segInfoFlags)) {
+ goto eofError;
+ }
+ extCombOp = segInfoFlags & 7;
+
+ // rest of the halftone region header
+ if (!readUByte(&flags)) {
+ goto eofError;
+ }
+ mmr = flags & 1;
+ templ = (flags >> 1) & 3;
+ enableSkip = (flags >> 3) & 1;
+ combOp = (flags >> 4) & 7;
+ if (!readULong(&gridW) || !readULong(&gridH) ||
+ !readLong(&gridX) || !readLong(&gridY) ||
+ !readUWord(&stepX) || !readUWord(&stepY)) {
+ goto eofError;
+ }
+ if (w == 0 || h == 0 || w >= INT_MAX / h) {
+ error(getPos(), "Bad bitmap size in JBIG2 halftone segment");
+ return;
+ }
+ if (gridH == 0 || gridW >= INT_MAX / gridH) {
+ error(getPos(), "Bad grid size in JBIG2 halftone segment");
+ return;
+ }
+
+ // get pattern dictionary
+ if (nRefSegs != 1) {
+ error(getPos(), "Bad symbol dictionary reference in JBIG2 halftone segment");
+ return;
+ }
+ if (!(seg = findSegment(refSegs[0])) ||
+ seg->getType() != jbig2SegPatternDict) {
+ error(getPos(), "Bad symbol dictionary reference in JBIG2 halftone segment");
+ return;
+ }
+ patternDict = (JBIG2PatternDict *)seg;
+ bpp = 0;
+ i = 1;
+ while (i < patternDict->getSize()) {
+ ++bpp;
+ i <<= 1;
+ }
+ patW = patternDict->getBitmap(0)->getWidth();
+ patH = patternDict->getBitmap(0)->getHeight();
+
+ // set up the arithmetic decoder
+ if (!mmr) {
+ resetGenericStats(templ, NULL);
+ arithDecoder->start();
+ }
+
+ // allocate the bitmap
+ bitmap = new JBIG2Bitmap(segNum, w, h);
+ if (flags & 0x80) { // HDEFPIXEL
+ bitmap->clearToOne();
+ } else {
+ bitmap->clearToZero();
+ }
+
+ // compute the skip bitmap
+ skipBitmap = NULL;
+ if (enableSkip) {
+ skipBitmap = new JBIG2Bitmap(0, gridW, gridH);
+ skipBitmap->clearToZero();
+ for (m = 0; m < gridH; ++m) {
+ for (n = 0; n < gridW; ++n) {
+ xx = gridX + m * stepY + n * stepX;
+ yy = gridY + m * stepX - n * stepY;
+ if (((xx + (int)patW) >> 8) <= 0 || (xx >> 8) >= (int)w ||
+ ((yy + (int)patH) >> 8) <= 0 || (yy >> 8) >= (int)h) {
+ skipBitmap->setPixel(n, m);
+ }
+ }
+ }
+ }
+
+ // read the gray-scale image
+ grayImg = (Guint *)gmallocn(gridW * gridH, sizeof(Guint));
+ memset(grayImg, 0, gridW * gridH * sizeof(Guint));
+ atx[0] = templ <= 1 ? 3 : 2; aty[0] = -1;
+ atx[1] = -3; aty[1] = -1;
+ atx[2] = 2; aty[2] = -2;
+ atx[3] = -2; aty[3] = -2;
+ for (j = bpp - 1; j >= 0; --j) {
+ grayBitmap = readGenericBitmap(mmr, gridW, gridH, templ, gFalse,
+ enableSkip, skipBitmap, atx, aty, -1);
+ i = 0;
+ for (m = 0; m < gridH; ++m) {
+ for (n = 0; n < gridW; ++n) {
+ bit = grayBitmap->getPixel(n, m) ^ (grayImg[i] & 1);
+ grayImg[i] = (grayImg[i] << 1) | bit;
+ ++i;
+ }
+ }
+ delete grayBitmap;
+ }
+
+ // decode the image
+ i = 0;
+ for (m = 0; m < gridH; ++m) {
+ xx = gridX + m * stepY;
+ yy = gridY + m * stepX;
+ for (n = 0; n < gridW; ++n) {
+ if (!(enableSkip && skipBitmap->getPixel(n, m))) {
+ patternBitmap = patternDict->getBitmap(grayImg[i]);
+ bitmap->combine(patternBitmap, xx >> 8, yy >> 8, combOp);
+ }
+ xx += stepX;
+ yy -= stepY;
+ ++i;
+ }
+ }
+
+ gfree(grayImg);
+ if (skipBitmap) {
+ delete skipBitmap;
+ }
+
+ // combine the region bitmap into the page bitmap
+ if (imm) {
+ if (pageH == 0xffffffff && y + h > curPageH) {
+ pageBitmap->expand(y + h, pageDefPixel);
+ }
+ pageBitmap->combine(bitmap, x, y, extCombOp);
+ delete bitmap;
+
+ // store the region bitmap
+ } else {
+ segments->append(bitmap);
+ }
+
+ return;
+
+ eofError:
+ error(getPos(), "Unexpected EOF in JBIG2 stream");
+}
+
+void JBIG2Stream::readGenericRegionSeg(Guint segNum, GBool imm,
+ GBool /*lossless*/, Guint length) {
+ JBIG2Bitmap *bitmap;
+ Guint w, h, x, y, segInfoFlags, extCombOp;
+ Guint flags, mmr, templ, tpgdOn;
+ int atx[4], aty[4];
+
+ // region segment info field
+ if (!readULong(&w) || !readULong(&h) ||
+ !readULong(&x) || !readULong(&y) ||
+ !readUByte(&segInfoFlags)) {
+ goto eofError;
+ }
+ extCombOp = segInfoFlags & 7;
+
+ // rest of the generic region segment header
+ if (!readUByte(&flags)) {
+ goto eofError;
+ }
+ mmr = flags & 1;
+ templ = (flags >> 1) & 3;
+ tpgdOn = (flags >> 3) & 1;
+
+ // AT flags
+ if (!mmr) {
+ if (templ == 0) {
+ if (!readByte(&atx[0]) ||
+ !readByte(&aty[0]) ||
+ !readByte(&atx[1]) ||
+ !readByte(&aty[1]) ||
+ !readByte(&atx[2]) ||
+ !readByte(&aty[2]) ||
+ !readByte(&atx[3]) ||
+ !readByte(&aty[3])) {
+ goto eofError;
+ }
+ } else {
+ if (!readByte(&atx[0]) ||
+ !readByte(&aty[0])) {
+ goto eofError;
+ }
+ }
+ }
+
+ // set up the arithmetic decoder
+ if (!mmr) {
+ resetGenericStats(templ, NULL);
+ arithDecoder->start();
+ }
+
+ // read the bitmap
+ bitmap = readGenericBitmap(mmr, w, h, templ, tpgdOn, gFalse,
+ NULL, atx, aty, mmr ? length - 18 : 0);
+
+ // combine the region bitmap into the page bitmap
+ if (imm) {
+ if (pageH == 0xffffffff && y + h > curPageH) {
+ pageBitmap->expand(y + h, pageDefPixel);
+ }
+ pageBitmap->combine(bitmap, x, y, extCombOp);
+ delete bitmap;
+
+ // store the region bitmap
+ } else {
+ bitmap->setSegNum(segNum);
+ segments->append(bitmap);
+ }
+
+ return;
+
+ eofError:
+ error(getPos(), "Unexpected EOF in JBIG2 stream");
+}
+
+inline void JBIG2Stream::mmrAddPixels(int a1, int blackPixels,
+ int *codingLine, int *a0i, int w) {
+ if (a1 > codingLine[*a0i]) {
+ if (a1 > w) {
+ error(getPos(), "JBIG2 MMR row is wrong length ({0:d})", a1);
+ a1 = w;
+ }
+ if ((*a0i & 1) ^ blackPixels) {
+ ++*a0i;
+ }
+ codingLine[*a0i] = a1;
+ }
+}
+
+inline void JBIG2Stream::mmrAddPixelsNeg(int a1, int blackPixels,
+ int *codingLine, int *a0i, int w) {
+ if (a1 > codingLine[*a0i]) {
+ if (a1 > w) {
+ error(getPos(), "JBIG2 MMR row is wrong length ({0:d})", a1);
+ a1 = w;
+ }
+ if ((*a0i & 1) ^ blackPixels) {
+ ++*a0i;
+ }
+ codingLine[*a0i] = a1;
+ } else if (a1 < codingLine[*a0i]) {
+ if (a1 < 0) {
+ error(getPos(), "Invalid JBIG2 MMR code");
+ a1 = 0;
+ }
+ while (*a0i > 0 && a1 <= codingLine[*a0i - 1]) {
+ --*a0i;
+ }
+ codingLine[*a0i] = a1;
+ }
+}
+
+JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h,
+ int templ, GBool tpgdOn,
+ GBool useSkip, JBIG2Bitmap *skip,
+ int *atx, int *aty,
+ int mmrDataLength) {
+ JBIG2Bitmap *bitmap;
+ GBool ltp;
+ Guint ltpCX, cx, cx0, cx1, cx2;
+ JBIG2BitmapPtr cxPtr0, cxPtr1;
+ JBIG2BitmapPtr atPtr0, atPtr1, atPtr2, atPtr3;
+ int *refLine, *codingLine;
+ int code1, code2, code3;
+ int x, y, a0i, b1i, blackPixels, pix, i;
+
+ bitmap = new JBIG2Bitmap(0, w, h);
+ bitmap->clearToZero();
+
+ //----- MMR decode
+
+ if (mmr) {
+
+ mmrDecoder->reset();
+ if (w > INT_MAX - 2) {
+ error(getPos(), "Bad width in JBIG2 generic bitmap");
+ // force a call to gmalloc(-1), which will throw an exception
+ w = -3;
+ }
+ // 0 <= codingLine[0] < codingLine[1] < ... < codingLine[n] = w
+ // ---> max codingLine size = w + 1
+ // refLine has one extra guard entry at the end
+ // ---> max refLine size = w + 2
+ codingLine = (int *)gmallocn(w + 1, sizeof(int));
+ refLine = (int *)gmallocn(w + 2, sizeof(int));
+ codingLine[0] = w;
+
+ for (y = 0; y < h; ++y) {
+
+ // copy coding line to ref line
+ for (i = 0; codingLine[i] < w; ++i) {
+ refLine[i] = codingLine[i];
+ }
+ refLine[i++] = w;
+ refLine[i] = w;
+
+ // decode a line
+ codingLine[0] = 0;
+ a0i = 0;
+ b1i = 0;
+ blackPixels = 0;
+ // invariant:
+ // refLine[b1i-1] <= codingLine[a0i] < refLine[b1i] < refLine[b1i+1] <= w
+ // exception at left edge:
+ // codingLine[a0i = 0] = refLine[b1i = 0] = 0 is possible
+ // exception at right edge:
+ // refLine[b1i] = refLine[b1i+1] = w is possible
+ while (codingLine[a0i] < w) {
+ code1 = mmrDecoder->get2DCode();
+ switch (code1) {
+ case twoDimPass:
+ mmrAddPixels(refLine[b1i + 1], blackPixels, codingLine, &a0i, w);
+ if (refLine[b1i + 1] < w) {
+ b1i += 2;
+ }
+ break;
+ case twoDimHoriz:
+ code1 = code2 = 0;
+ if (blackPixels) {
+ do {
+ code1 += code3 = mmrDecoder->getBlackCode();
+ } while (code3 >= 64);
+ do {
+ code2 += code3 = mmrDecoder->getWhiteCode();
+ } while (code3 >= 64);
+ } else {
+ do {
+ code1 += code3 = mmrDecoder->getWhiteCode();
+ } while (code3 >= 64);
+ do {
+ code2 += code3 = mmrDecoder->getBlackCode();
+ } while (code3 >= 64);
+ }
+ mmrAddPixels(codingLine[a0i] + code1, blackPixels,
+ codingLine, &a0i, w);
+ if (codingLine[a0i] < w) {
+ mmrAddPixels(codingLine[a0i] + code2, blackPixels ^ 1,
+ codingLine, &a0i, w);
+ }
+ while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) {
+ b1i += 2;
+ }
+ break;
+ case twoDimVertR3:
+ mmrAddPixels(refLine[b1i] + 3, blackPixels, codingLine, &a0i, w);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < w) {
+ ++b1i;
+ while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) {
+ b1i += 2;
+ }
+ }
+ break;
+ case twoDimVertR2:
+ mmrAddPixels(refLine[b1i] + 2, blackPixels, codingLine, &a0i, w);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < w) {
+ ++b1i;
+ while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) {
+ b1i += 2;
+ }
+ }
+ break;
+ case twoDimVertR1:
+ mmrAddPixels(refLine[b1i] + 1, blackPixels, codingLine, &a0i, w);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < w) {
+ ++b1i;
+ while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) {
+ b1i += 2;
+ }
+ }
+ break;
+ case twoDimVert0:
+ mmrAddPixels(refLine[b1i], blackPixels, codingLine, &a0i, w);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < w) {
+ ++b1i;
+ while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) {
+ b1i += 2;
+ }
+ }
+ break;
+ case twoDimVertL3:
+ mmrAddPixelsNeg(refLine[b1i] - 3, blackPixels, codingLine, &a0i, w);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < w) {
+ if (b1i > 0) {
+ --b1i;
+ } else {
+ ++b1i;
+ }
+ while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) {
+ b1i += 2;
+ }
+ }
+ break;
+ case twoDimVertL2:
+ mmrAddPixelsNeg(refLine[b1i] - 2, blackPixels, codingLine, &a0i, w);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < w) {
+ if (b1i > 0) {
+ --b1i;
+ } else {
+ ++b1i;
+ }
+ while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) {
+ b1i += 2;
+ }
+ }
+ break;
+ case twoDimVertL1:
+ mmrAddPixelsNeg(refLine[b1i] - 1, blackPixels, codingLine, &a0i, w);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < w) {
+ if (b1i > 0) {
+ --b1i;
+ } else {
+ ++b1i;
+ }
+ while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) {
+ b1i += 2;
+ }
+ }
+ break;
+ case EOF:
+ mmrAddPixels(w, 0, codingLine, &a0i, w);
+ break;
+ default:
+ error(getPos(), "Illegal code in JBIG2 MMR bitmap data");
+ mmrAddPixels(w, 0, codingLine, &a0i, w);
+ break;
+ }
+ }
+
+ // convert the run lengths to a bitmap line
+ i = 0;
+ while (1) {
+ for (x = codingLine[i]; x < codingLine[i+1]; ++x) {
+ bitmap->setPixel(x, y);
+ }
+ if (codingLine[i+1] >= w || codingLine[i+2] >= w) {
+ break;
+ }
+ i += 2;
+ }
+ }
+
+ if (mmrDataLength >= 0) {
+ mmrDecoder->skipTo(mmrDataLength);
+ } else {
+ if (mmrDecoder->get24Bits() != 0x001001) {
+ error(getPos(), "Missing EOFB in JBIG2 MMR bitmap data");
+ }
+ }
+
+ gfree(refLine);
+ gfree(codingLine);
+
+ //----- arithmetic decode
+
+ } else {
+ // set up the typical row context
+ ltpCX = 0; // make gcc happy
+ if (tpgdOn) {
+ switch (templ) {
+ case 0:
+ ltpCX = 0x3953; // 001 11001 0101 0011
+ break;
+ case 1:
+ ltpCX = 0x079a; // 0011 11001 101 0
+ break;
+ case 2:
+ ltpCX = 0x0e3; // 001 1100 01 1
+ break;
+ case 3:
+ ltpCX = 0x18a; // 01100 0101 1
+ break;
+ }
+ }
+
+ ltp = 0;
+ cx = cx0 = cx1 = cx2 = 0; // make gcc happy
+ for (y = 0; y < h; ++y) {
+
+ // check for a "typical" (duplicate) row
+ if (tpgdOn) {
+ if (arithDecoder->decodeBit(ltpCX, genericRegionStats)) {
+ ltp = !ltp;
+ }
+ if (ltp) {
+ if (y > 0) {
+ bitmap->duplicateRow(y, y-1);
+ }
+ continue;
+ }
+ }
+
+ switch (templ) {
+ case 0:
+
+ // set up the context
+ bitmap->getPixelPtr(0, y-2, &cxPtr0);
+ cx0 = bitmap->nextPixel(&cxPtr0);
+ cx0 = (cx0 << 1) | bitmap->nextPixel(&cxPtr0);
+ bitmap->getPixelPtr(0, y-1, &cxPtr1);
+ cx1 = bitmap->nextPixel(&cxPtr1);
+ cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1);
+ cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1);
+ cx2 = 0;
+ bitmap->getPixelPtr(atx[0], y + aty[0], &atPtr0);
+ bitmap->getPixelPtr(atx[1], y + aty[1], &atPtr1);
+ bitmap->getPixelPtr(atx[2], y + aty[2], &atPtr2);
+ bitmap->getPixelPtr(atx[3], y + aty[3], &atPtr3);
+
+ // decode the row
+ for (x = 0; x < w; ++x) {
+
+ // build the context
+ cx = (cx0 << 13) | (cx1 << 8) | (cx2 << 4) |
+ (bitmap->nextPixel(&atPtr0) << 3) |
+ (bitmap->nextPixel(&atPtr1) << 2) |
+ (bitmap->nextPixel(&atPtr2) << 1) |
+ bitmap->nextPixel(&atPtr3);
+
+ // check for a skipped pixel
+ if (useSkip && skip->getPixel(x, y)) {
+ pix = 0;
+
+ // decode the pixel
+ } else if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) {
+ bitmap->setPixel(x, y);
+ }
+
+ // update the context
+ cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 0x07;
+ cx1 = ((cx1 << 1) | bitmap->nextPixel(&cxPtr1)) & 0x1f;
+ cx2 = ((cx2 << 1) | pix) & 0x0f;
+ }
+ break;
+
+ case 1:
+
+ // set up the context
+ bitmap->getPixelPtr(0, y-2, &cxPtr0);
+ cx0 = bitmap->nextPixel(&cxPtr0);
+ cx0 = (cx0 << 1) | bitmap->nextPixel(&cxPtr0);
+ cx0 = (cx0 << 1) | bitmap->nextPixel(&cxPtr0);
+ bitmap->getPixelPtr(0, y-1, &cxPtr1);
+ cx1 = bitmap->nextPixel(&cxPtr1);
+ cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1);
+ cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1);
+ cx2 = 0;
+ bitmap->getPixelPtr(atx[0], y + aty[0], &atPtr0);
+
+ // decode the row
+ for (x = 0; x < w; ++x) {
+
+ // build the context
+ cx = (cx0 << 9) | (cx1 << 4) | (cx2 << 1) |
+ bitmap->nextPixel(&atPtr0);
+
+ // check for a skipped pixel
+ if (useSkip && skip->getPixel(x, y)) {
+ pix = 0;
+
+ // decode the pixel
+ } else if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) {
+ bitmap->setPixel(x, y);
+ }
+
+ // update the context
+ cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 0x0f;
+ cx1 = ((cx1 << 1) | bitmap->nextPixel(&cxPtr1)) & 0x1f;
+ cx2 = ((cx2 << 1) | pix) & 0x07;
+ }
+ break;
+
+ case 2:
+
+ // set up the context
+ bitmap->getPixelPtr(0, y-2, &cxPtr0);
+ cx0 = bitmap->nextPixel(&cxPtr0);
+ cx0 = (cx0 << 1) | bitmap->nextPixel(&cxPtr0);
+ bitmap->getPixelPtr(0, y-1, &cxPtr1);
+ cx1 = bitmap->nextPixel(&cxPtr1);
+ cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1);
+ cx2 = 0;
+ bitmap->getPixelPtr(atx[0], y + aty[0], &atPtr0);
+
+ // decode the row
+ for (x = 0; x < w; ++x) {
+
+ // build the context
+ cx = (cx0 << 7) | (cx1 << 3) | (cx2 << 1) |
+ bitmap->nextPixel(&atPtr0);
+
+ // check for a skipped pixel
+ if (useSkip && skip->getPixel(x, y)) {
+ pix = 0;
+
+ // decode the pixel
+ } else if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) {
+ bitmap->setPixel(x, y);
+ }
+
+ // update the context
+ cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 0x07;
+ cx1 = ((cx1 << 1) | bitmap->nextPixel(&cxPtr1)) & 0x0f;
+ cx2 = ((cx2 << 1) | pix) & 0x03;
+ }
+ break;
+
+ case 3:
+
+ // set up the context
+ bitmap->getPixelPtr(0, y-1, &cxPtr1);
+ cx1 = bitmap->nextPixel(&cxPtr1);
+ cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1);
+ cx2 = 0;
+ bitmap->getPixelPtr(atx[0], y + aty[0], &atPtr0);
+
+ // decode the row
+ for (x = 0; x < w; ++x) {
+
+ // build the context
+ cx = (cx1 << 5) | (cx2 << 1) |
+ bitmap->nextPixel(&atPtr0);
+
+ // check for a skipped pixel
+ if (useSkip && skip->getPixel(x, y)) {
+ pix = 0;
+
+ // decode the pixel
+ } else if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) {
+ bitmap->setPixel(x, y);
+ }
+
+ // update the context
+ cx1 = ((cx1 << 1) | bitmap->nextPixel(&cxPtr1)) & 0x1f;
+ cx2 = ((cx2 << 1) | pix) & 0x0f;
+ }
+ break;
+ }
+ }
+ }
+
+ return bitmap;
+}
+
+void JBIG2Stream::readGenericRefinementRegionSeg(Guint segNum, GBool imm,
+ GBool /*lossless*/, Guint /*length*/,
+ Guint *refSegs,
+ Guint nRefSegs) {
+ JBIG2Bitmap *bitmap, *refBitmap;
+ Guint w, h, x, y, segInfoFlags, extCombOp;
+ Guint flags, templ, tpgrOn;
+ int atx[2], aty[2];
+ JBIG2Segment *seg;
+
+ // region segment info field
+ if (!readULong(&w) || !readULong(&h) ||
+ !readULong(&x) || !readULong(&y) ||
+ !readUByte(&segInfoFlags)) {
+ goto eofError;
+ }
+ extCombOp = segInfoFlags & 7;
+
+ // rest of the generic refinement region segment header
+ if (!readUByte(&flags)) {
+ goto eofError;
+ }
+ templ = flags & 1;
+ tpgrOn = (flags >> 1) & 1;
+
+ // AT flags
+ if (!templ) {
+ if (!readByte(&atx[0]) || !readByte(&aty[0]) ||
+ !readByte(&atx[1]) || !readByte(&aty[1])) {
+ goto eofError;
+ }
+ }
+
+ // resize the page bitmap if needed
+ if (nRefSegs == 0 || imm) {
+ if (pageH == 0xffffffff && y + h > curPageH) {
+ pageBitmap->expand(y + h, pageDefPixel);
+ }
+ }
+
+ // get referenced bitmap
+ if (nRefSegs > 1) {
+ error(getPos(), "Bad reference in JBIG2 generic refinement segment");
+ return;
+ }
+ if (nRefSegs == 1) {
+ if (!(seg = findSegment(refSegs[0])) ||
+ seg->getType() != jbig2SegBitmap) {
+ error(getPos(), "Bad bitmap reference in JBIG2 generic refinement segment");
+ return;
+ }
+ refBitmap = (JBIG2Bitmap *)seg;
+ } else {
+ refBitmap = pageBitmap->getSlice(x, y, w, h);
+ }
+
+ // set up the arithmetic decoder
+ resetRefinementStats(templ, NULL);
+ arithDecoder->start();
+
+ // read
+ bitmap = readGenericRefinementRegion(w, h, templ, tpgrOn,
+ refBitmap, 0, 0, atx, aty);
+
+ // combine the region bitmap into the page bitmap
+ if (imm) {
+ pageBitmap->combine(bitmap, x, y, extCombOp);
+ delete bitmap;
+
+ // store the region bitmap
+ } else {
+ bitmap->setSegNum(segNum);
+ segments->append(bitmap);
+ }
+
+ // delete the referenced bitmap
+ if (nRefSegs == 1) {
+ discardSegment(refSegs[0]);
+ } else {
+ delete refBitmap;
+ }
+
+ return;
+
+ eofError:
+ error(getPos(), "Unexpected EOF in JBIG2 stream");
+}
+
+JBIG2Bitmap *JBIG2Stream::readGenericRefinementRegion(int w, int h,
+ int templ, GBool tpgrOn,
+ JBIG2Bitmap *refBitmap,
+ int refDX, int refDY,
+ int *atx, int *aty) {
+ JBIG2Bitmap *bitmap;
+ GBool ltp;
+ Guint ltpCX, cx, cx0, cx2, cx3, cx4, tpgrCX0, tpgrCX1, tpgrCX2;
+ JBIG2BitmapPtr cxPtr0, cxPtr1, cxPtr2, cxPtr3, cxPtr4, cxPtr5, cxPtr6;
+ JBIG2BitmapPtr tpgrCXPtr0, tpgrCXPtr1, tpgrCXPtr2;
+ int x, y, pix;
+
+ bitmap = new JBIG2Bitmap(0, w, h);
+ bitmap->clearToZero();
+
+ // set up the typical row context
+ if (templ) {
+ ltpCX = 0x008;
+ } else {
+ ltpCX = 0x0010;
+ }
+
+ ltp = 0;
+ for (y = 0; y < h; ++y) {
+
+ if (templ) {
+
+ // set up the context
+ bitmap->getPixelPtr(0, y-1, &cxPtr0);
+ cx0 = bitmap->nextPixel(&cxPtr0);
+ bitmap->getPixelPtr(-1, y, &cxPtr1);
+ refBitmap->getPixelPtr(-refDX, y-1-refDY, &cxPtr2);
+ refBitmap->getPixelPtr(-1-refDX, y-refDY, &cxPtr3);
+ cx3 = refBitmap->nextPixel(&cxPtr3);
+ cx3 = (cx3 << 1) | refBitmap->nextPixel(&cxPtr3);
+ refBitmap->getPixelPtr(-refDX, y+1-refDY, &cxPtr4);
+ cx4 = refBitmap->nextPixel(&cxPtr4);
+
+ // set up the typical prediction context
+ tpgrCX0 = tpgrCX1 = tpgrCX2 = 0; // make gcc happy
+ if (tpgrOn) {
+ refBitmap->getPixelPtr(-1-refDX, y-1-refDY, &tpgrCXPtr0);
+ tpgrCX0 = refBitmap->nextPixel(&tpgrCXPtr0);
+ tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0);
+ tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0);
+ refBitmap->getPixelPtr(-1-refDX, y-refDY, &tpgrCXPtr1);
+ tpgrCX1 = refBitmap->nextPixel(&tpgrCXPtr1);
+ tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1);
+ tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1);
+ refBitmap->getPixelPtr(-1-refDX, y+1-refDY, &tpgrCXPtr2);
+ tpgrCX2 = refBitmap->nextPixel(&tpgrCXPtr2);
+ tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2);
+ tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2);
+ } else {
+ tpgrCXPtr0.p = tpgrCXPtr1.p = tpgrCXPtr2.p = NULL; // make gcc happy
+ tpgrCXPtr0.shift = tpgrCXPtr1.shift = tpgrCXPtr2.shift = 0;
+ tpgrCXPtr0.x = tpgrCXPtr1.x = tpgrCXPtr2.x = 0;
+ }
+
+ for (x = 0; x < w; ++x) {
+
+ // update the context
+ cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 7;
+ cx3 = ((cx3 << 1) | refBitmap->nextPixel(&cxPtr3)) & 7;
+ cx4 = ((cx4 << 1) | refBitmap->nextPixel(&cxPtr4)) & 3;
+
+ if (tpgrOn) {
+ // update the typical predictor context
+ tpgrCX0 = ((tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0)) & 7;
+ tpgrCX1 = ((tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1)) & 7;
+ tpgrCX2 = ((tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2)) & 7;
+
+ // check for a "typical" pixel
+ if (arithDecoder->decodeBit(ltpCX, refinementRegionStats)) {
+ ltp = !ltp;
+ }
+ if (tpgrCX0 == 0 && tpgrCX1 == 0 && tpgrCX2 == 0) {
+ bitmap->clearPixel(x, y);
+ continue;
+ } else if (tpgrCX0 == 7 && tpgrCX1 == 7 && tpgrCX2 == 7) {
+ bitmap->setPixel(x, y);
+ continue;
+ }
+ }
+
+ // build the context
+ cx = (cx0 << 7) | (bitmap->nextPixel(&cxPtr1) << 6) |
+ (refBitmap->nextPixel(&cxPtr2) << 5) |
+ (cx3 << 2) | cx4;
+
+ // decode the pixel
+ if ((pix = arithDecoder->decodeBit(cx, refinementRegionStats))) {
+ bitmap->setPixel(x, y);
+ }
+ }
+
+ } else {
+
+ // set up the context
+ bitmap->getPixelPtr(0, y-1, &cxPtr0);
+ cx0 = bitmap->nextPixel(&cxPtr0);
+ bitmap->getPixelPtr(-1, y, &cxPtr1);
+ refBitmap->getPixelPtr(-refDX, y-1-refDY, &cxPtr2);
+ cx2 = refBitmap->nextPixel(&cxPtr2);
+ refBitmap->getPixelPtr(-1-refDX, y-refDY, &cxPtr3);
+ cx3 = refBitmap->nextPixel(&cxPtr3);
+ cx3 = (cx3 << 1) | refBitmap->nextPixel(&cxPtr3);
+ refBitmap->getPixelPtr(-1-refDX, y+1-refDY, &cxPtr4);
+ cx4 = refBitmap->nextPixel(&cxPtr4);
+ cx4 = (cx4 << 1) | refBitmap->nextPixel(&cxPtr4);
+ bitmap->getPixelPtr(atx[0], y+aty[0], &cxPtr5);
+ refBitmap->getPixelPtr(atx[1]-refDX, y+aty[1]-refDY, &cxPtr6);
+
+ // set up the typical prediction context
+ tpgrCX0 = tpgrCX1 = tpgrCX2 = 0; // make gcc happy
+ if (tpgrOn) {
+ refBitmap->getPixelPtr(-1-refDX, y-1-refDY, &tpgrCXPtr0);
+ tpgrCX0 = refBitmap->nextPixel(&tpgrCXPtr0);
+ tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0);
+ tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0);
+ refBitmap->getPixelPtr(-1-refDX, y-refDY, &tpgrCXPtr1);
+ tpgrCX1 = refBitmap->nextPixel(&tpgrCXPtr1);
+ tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1);
+ tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1);
+ refBitmap->getPixelPtr(-1-refDX, y+1-refDY, &tpgrCXPtr2);
+ tpgrCX2 = refBitmap->nextPixel(&tpgrCXPtr2);
+ tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2);
+ tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2);
+ } else {
+ tpgrCXPtr0.p = tpgrCXPtr1.p = tpgrCXPtr2.p = NULL; // make gcc happy
+ tpgrCXPtr0.shift = tpgrCXPtr1.shift = tpgrCXPtr2.shift = 0;
+ tpgrCXPtr0.x = tpgrCXPtr1.x = tpgrCXPtr2.x = 0;
+ }
+
+ for (x = 0; x < w; ++x) {
+
+ // update the context
+ cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 3;
+ cx2 = ((cx2 << 1) | refBitmap->nextPixel(&cxPtr2)) & 3;
+ cx3 = ((cx3 << 1) | refBitmap->nextPixel(&cxPtr3)) & 7;
+ cx4 = ((cx4 << 1) | refBitmap->nextPixel(&cxPtr4)) & 7;
+
+ if (tpgrOn) {
+ // update the typical predictor context
+ tpgrCX0 = ((tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0)) & 7;
+ tpgrCX1 = ((tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1)) & 7;
+ tpgrCX2 = ((tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2)) & 7;
+
+ // check for a "typical" pixel
+ if (arithDecoder->decodeBit(ltpCX, refinementRegionStats)) {
+ ltp = !ltp;
+ }
+ if (tpgrCX0 == 0 && tpgrCX1 == 0 && tpgrCX2 == 0) {
+ bitmap->clearPixel(x, y);
+ continue;
+ } else if (tpgrCX0 == 7 && tpgrCX1 == 7 && tpgrCX2 == 7) {
+ bitmap->setPixel(x, y);
+ continue;
+ }
+ }
+
+ // build the context
+ cx = (cx0 << 11) | (bitmap->nextPixel(&cxPtr1) << 10) |
+ (cx2 << 8) | (cx3 << 5) | (cx4 << 2) |
+ (bitmap->nextPixel(&cxPtr5) << 1) |
+ refBitmap->nextPixel(&cxPtr6);
+
+ // decode the pixel
+ if ((pix = arithDecoder->decodeBit(cx, refinementRegionStats))) {
+ bitmap->setPixel(x, y);
+ }
+ }
+ }
+ }
+
+ return bitmap;
+}
+
+void JBIG2Stream::readPageInfoSeg(Guint /*length*/) {
+ Guint xRes, yRes, flags, striping;
+
+ if (!readULong(&pageW) || !readULong(&pageH) ||
+ !readULong(&xRes) || !readULong(&yRes) ||
+ !readUByte(&flags) || !readUWord(&striping)) {
+ goto eofError;
+ }
+ pageDefPixel = (flags >> 2) & 1;
+ defCombOp = (flags >> 3) & 3;
+
+ // allocate the page bitmap
+ if (pageH == 0xffffffff) {
+ curPageH = striping & 0x7fff;
+ } else {
+ curPageH = pageH;
+ }
+ pageBitmap = new JBIG2Bitmap(0, pageW, curPageH);
+
+ // default pixel value
+ if (pageDefPixel) {
+ pageBitmap->clearToOne();
+ } else {
+ pageBitmap->clearToZero();
+ }
+
+ return;
+
+ eofError:
+ error(getPos(), "Unexpected EOF in JBIG2 stream");
+}
+
+void JBIG2Stream::readEndOfStripeSeg(Guint length) {
+ Guint i;
+
+ // skip the segment
+ for (i = 0; i < length; ++i) {
+ curStr->getChar();
+ }
+}
+
+void JBIG2Stream::readProfilesSeg(Guint length) {
+ Guint i;
+
+ // skip the segment
+ for (i = 0; i < length; ++i) {
+ curStr->getChar();
+ }
+}
+
+void JBIG2Stream::readCodeTableSeg(Guint segNum, Guint /*length*/) {
+ JBIG2HuffmanTable *huffTab;
+ Guint flags, oob, prefixBits, rangeBits;
+ int lowVal, highVal, val;
+ Guint huffTabSize, i;
+
+ if (!readUByte(&flags) || !readLong(&lowVal) || !readLong(&highVal)) {
+ goto eofError;
+ }
+ oob = flags & 1;
+ prefixBits = ((flags >> 1) & 7) + 1;
+ rangeBits = ((flags >> 4) & 7) + 1;
+
+ huffDecoder->reset();
+ huffTabSize = 8;
+ huffTab = (JBIG2HuffmanTable *)
+ gmallocn(huffTabSize, sizeof(JBIG2HuffmanTable));
+ i = 0;
+ val = lowVal;
+ while (val < highVal) {
+ if (i == huffTabSize) {
+ huffTabSize *= 2;
+ huffTab = (JBIG2HuffmanTable *)
+ greallocn(huffTab, huffTabSize, sizeof(JBIG2HuffmanTable));
+ }
+ huffTab[i].val = val;
+ huffTab[i].prefixLen = huffDecoder->readBits(prefixBits);
+ huffTab[i].rangeLen = huffDecoder->readBits(rangeBits);
+ val += 1 << huffTab[i].rangeLen;
+ ++i;
+ }
+ if (i + oob + 3 > huffTabSize) {
+ huffTabSize = i + oob + 3;
+ huffTab = (JBIG2HuffmanTable *)
+ greallocn(huffTab, huffTabSize, sizeof(JBIG2HuffmanTable));
+ }
+ huffTab[i].val = lowVal - 1;
+ huffTab[i].prefixLen = huffDecoder->readBits(prefixBits);
+ huffTab[i].rangeLen = jbig2HuffmanLOW;
+ ++i;
+ huffTab[i].val = highVal;
+ huffTab[i].prefixLen = huffDecoder->readBits(prefixBits);
+ huffTab[i].rangeLen = 32;
+ ++i;
+ if (oob) {
+ huffTab[i].val = 0;
+ huffTab[i].prefixLen = huffDecoder->readBits(prefixBits);
+ huffTab[i].rangeLen = jbig2HuffmanOOB;
+ ++i;
+ }
+ huffTab[i].val = 0;
+ huffTab[i].prefixLen = 0;
+ huffTab[i].rangeLen = jbig2HuffmanEOT;
+ huffDecoder->buildTable(huffTab, i);
+
+ // create and store the new table segment
+ segments->append(new JBIG2CodeTable(segNum, huffTab));
+
+ return;
+
+ eofError:
+ error(getPos(), "Unexpected EOF in JBIG2 stream");
+}
+
+void JBIG2Stream::readExtensionSeg(Guint length) {
+ Guint i;
+
+ // skip the segment
+ for (i = 0; i < length; ++i) {
+ curStr->getChar();
+ }
+}
+
+JBIG2Segment *JBIG2Stream::findSegment(Guint segNum) {
+ JBIG2Segment *seg;
+ int i;
+
+ for (i = 0; i < globalSegments->getLength(); ++i) {
+ seg = (JBIG2Segment *)globalSegments->get(i);
+ if (seg->getSegNum() == segNum) {
+ return seg;
+ }
+ }
+ for (i = 0; i < segments->getLength(); ++i) {
+ seg = (JBIG2Segment *)segments->get(i);
+ if (seg->getSegNum() == segNum) {
+ return seg;
+ }
+ }
+ return NULL;
+}
+
+void JBIG2Stream::discardSegment(Guint segNum) {
+ JBIG2Segment *seg;
+ int i;
+
+ for (i = 0; i < globalSegments->getLength(); ++i) {
+ seg = (JBIG2Segment *)globalSegments->get(i);
+ if (seg->getSegNum() == segNum) {
+ globalSegments->del(i);
+ return;
+ }
+ }
+ for (i = 0; i < segments->getLength(); ++i) {
+ seg = (JBIG2Segment *)segments->get(i);
+ if (seg->getSegNum() == segNum) {
+ segments->del(i);
+ return;
+ }
+ }
+}
+
+void JBIG2Stream::resetGenericStats(Guint templ,
+ JArithmeticDecoderStats *prevStats) {
+ int size;
+
+ size = contextSize[templ];
+ if (prevStats && prevStats->getContextSize() == size) {
+ if (genericRegionStats->getContextSize() == size) {
+ genericRegionStats->copyFrom(prevStats);
+ } else {
+ delete genericRegionStats;
+ genericRegionStats = prevStats->copy();
+ }
+ } else {
+ if (genericRegionStats->getContextSize() == size) {
+ genericRegionStats->reset();
+ } else {
+ delete genericRegionStats;
+ genericRegionStats = new JArithmeticDecoderStats(1 << size);
+ }
+ }
+}
+
+void JBIG2Stream::resetRefinementStats(Guint templ,
+ JArithmeticDecoderStats *prevStats) {
+ int size;
+
+ size = refContextSize[templ];
+ if (prevStats && prevStats->getContextSize() == size) {
+ if (refinementRegionStats->getContextSize() == size) {
+ refinementRegionStats->copyFrom(prevStats);
+ } else {
+ delete refinementRegionStats;
+ refinementRegionStats = prevStats->copy();
+ }
+ } else {
+ if (refinementRegionStats->getContextSize() == size) {
+ refinementRegionStats->reset();
+ } else {
+ delete refinementRegionStats;
+ refinementRegionStats = new JArithmeticDecoderStats(1 << size);
+ }
+ }
+}
+
+void JBIG2Stream::resetIntStats(int symCodeLen) {
+ iadhStats->reset();
+ iadwStats->reset();
+ iaexStats->reset();
+ iaaiStats->reset();
+ iadtStats->reset();
+ iaitStats->reset();
+ iafsStats->reset();
+ iadsStats->reset();
+ iardxStats->reset();
+ iardyStats->reset();
+ iardwStats->reset();
+ iardhStats->reset();
+ iariStats->reset();
+ if (iaidStats->getContextSize() == 1 << (symCodeLen + 1)) {
+ iaidStats->reset();
+ } else {
+ delete iaidStats;
+ iaidStats = new JArithmeticDecoderStats(1 << (symCodeLen + 1));
+ }
+}
+
+GBool JBIG2Stream::readUByte(Guint *x) {
+ int c0;
+
+ if ((c0 = curStr->getChar()) == EOF) {
+ return gFalse;
+ }
+ *x = (Guint)c0;
+ return gTrue;
+}
+
+GBool JBIG2Stream::readByte(int *x) {
+ int c0;
+
+ if ((c0 = curStr->getChar()) == EOF) {
+ return gFalse;
+ }
+ *x = c0;
+ if (c0 & 0x80) {
+ *x |= -1 - 0xff;
+ }
+ return gTrue;
+}
+
+GBool JBIG2Stream::readUWord(Guint *x) {
+ int c0, c1;
+
+ if ((c0 = curStr->getChar()) == EOF ||
+ (c1 = curStr->getChar()) == EOF) {
+ return gFalse;
+ }
+ *x = (Guint)((c0 << 8) | c1);
+ return gTrue;
+}
+
+GBool JBIG2Stream::readULong(Guint *x) {
+ int c0, c1, c2, c3;
+
+ if ((c0 = curStr->getChar()) == EOF ||
+ (c1 = curStr->getChar()) == EOF ||
+ (c2 = curStr->getChar()) == EOF ||
+ (c3 = curStr->getChar()) == EOF) {
+ return gFalse;
+ }
+ *x = (Guint)((c0 << 24) | (c1 << 16) | (c2 << 8) | c3);
+ return gTrue;
+}
+
+GBool JBIG2Stream::readLong(int *x) {
+ int c0, c1, c2, c3;
+
+ if ((c0 = curStr->getChar()) == EOF ||
+ (c1 = curStr->getChar()) == EOF ||
+ (c2 = curStr->getChar()) == EOF ||
+ (c3 = curStr->getChar()) == EOF) {
+ return gFalse;
+ }
+ *x = ((c0 << 24) | (c1 << 16) | (c2 << 8) | c3);
+ if (c0 & 0x80) {
+ *x |= -1 - (int)0xffffffff;
+ }
+ return gTrue;
+}
diff --git a/kpdf/xpdf/xpdf/JBIG2Stream.h b/kpdf/xpdf/xpdf/JBIG2Stream.h
new file mode 100644
index 00000000..f3443b3d
--- /dev/null
+++ b/kpdf/xpdf/xpdf/JBIG2Stream.h
@@ -0,0 +1,149 @@
+//========================================================================
+//
+// JBIG2Stream.h
+//
+// Copyright 2002-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef JBIG2STREAM_H
+#define JBIG2STREAM_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "Object.h"
+#include "Stream.h"
+
+class GList;
+class JBIG2Segment;
+class JBIG2Bitmap;
+class JArithmeticDecoder;
+class JArithmeticDecoderStats;
+class JBIG2HuffmanDecoder;
+struct JBIG2HuffmanTable;
+class JBIG2MMRDecoder;
+
+//------------------------------------------------------------------------
+
+class JBIG2Stream: public FilterStream {
+public:
+
+ JBIG2Stream(Stream *strA, Object *globalsStreamA);
+ virtual ~JBIG2Stream();
+ virtual StreamKind getKind() { return strJBIG2; }
+ virtual void reset();
+ virtual void close();
+ virtual int getChar();
+ virtual int lookChar();
+ virtual GString *getPSFilter(int psLevel, char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+
+private:
+
+ void readSegments();
+ GBool readSymbolDictSeg(Guint segNum, Guint length,
+ Guint *refSegs, Guint nRefSegs);
+ void readTextRegionSeg(Guint segNum, GBool imm,
+ GBool lossless, Guint length,
+ Guint *refSegs, Guint nRefSegs);
+ JBIG2Bitmap *readTextRegion(GBool huff, GBool refine,
+ int w, int h,
+ Guint numInstances,
+ Guint logStrips,
+ int numSyms,
+ JBIG2HuffmanTable *symCodeTab,
+ Guint symCodeLen,
+ JBIG2Bitmap **syms,
+ Guint defPixel, Guint combOp,
+ Guint transposed, Guint refCorner,
+ int sOffset,
+ JBIG2HuffmanTable *huffFSTable,
+ JBIG2HuffmanTable *huffDSTable,
+ JBIG2HuffmanTable *huffDTTable,
+ JBIG2HuffmanTable *huffRDWTable,
+ JBIG2HuffmanTable *huffRDHTable,
+ JBIG2HuffmanTable *huffRDXTable,
+ JBIG2HuffmanTable *huffRDYTable,
+ JBIG2HuffmanTable *huffRSizeTable,
+ Guint templ,
+ int *atx, int *aty);
+ void readPatternDictSeg(Guint segNum, Guint length);
+ void readHalftoneRegionSeg(Guint segNum, GBool imm,
+ GBool lossless, Guint length,
+ Guint *refSegs, Guint nRefSegs);
+ void readGenericRegionSeg(Guint segNum, GBool imm,
+ GBool lossless, Guint length);
+ void mmrAddPixels(int a1, int blackPixels,
+ int *codingLine, int *a0i, int w);
+ void mmrAddPixelsNeg(int a1, int blackPixels,
+ int *codingLine, int *a0i, int w);
+ JBIG2Bitmap *readGenericBitmap(GBool mmr, int w, int h,
+ int templ, GBool tpgdOn,
+ GBool useSkip, JBIG2Bitmap *skip,
+ int *atx, int *aty,
+ int mmrDataLength);
+ void readGenericRefinementRegionSeg(Guint segNum, GBool imm,
+ GBool lossless, Guint length,
+ Guint *refSegs,
+ Guint nRefSegs);
+ JBIG2Bitmap *readGenericRefinementRegion(int w, int h,
+ int templ, GBool tpgrOn,
+ JBIG2Bitmap *refBitmap,
+ int refDX, int refDY,
+ int *atx, int *aty);
+ void readPageInfoSeg(Guint length);
+ void readEndOfStripeSeg(Guint length);
+ void readProfilesSeg(Guint length);
+ void readCodeTableSeg(Guint segNum, Guint length);
+ void readExtensionSeg(Guint length);
+ JBIG2Segment *findSegment(Guint segNum);
+ void discardSegment(Guint segNum);
+ void resetGenericStats(Guint templ,
+ JArithmeticDecoderStats *prevStats);
+ void resetRefinementStats(Guint templ,
+ JArithmeticDecoderStats *prevStats);
+ void resetIntStats(int symCodeLen);
+ GBool readUByte(Guint *x);
+ GBool readByte(int *x);
+ GBool readUWord(Guint *x);
+ GBool readULong(Guint *x);
+ GBool readLong(int *x);
+
+ Object globalsStream;
+ Guint pageW, pageH, curPageH;
+ Guint pageDefPixel;
+ JBIG2Bitmap *pageBitmap;
+ Guint defCombOp;
+ GList *segments; // [JBIG2Segment]
+ GList *globalSegments; // [JBIG2Segment]
+ Stream *curStr;
+ Guchar *dataPtr;
+ Guchar *dataEnd;
+
+ JArithmeticDecoder *arithDecoder;
+ JArithmeticDecoderStats *genericRegionStats;
+ JArithmeticDecoderStats *refinementRegionStats;
+ JArithmeticDecoderStats *iadhStats;
+ JArithmeticDecoderStats *iadwStats;
+ JArithmeticDecoderStats *iaexStats;
+ JArithmeticDecoderStats *iaaiStats;
+ JArithmeticDecoderStats *iadtStats;
+ JArithmeticDecoderStats *iaitStats;
+ JArithmeticDecoderStats *iafsStats;
+ JArithmeticDecoderStats *iadsStats;
+ JArithmeticDecoderStats *iardxStats;
+ JArithmeticDecoderStats *iardyStats;
+ JArithmeticDecoderStats *iardwStats;
+ JArithmeticDecoderStats *iardhStats;
+ JArithmeticDecoderStats *iariStats;
+ JArithmeticDecoderStats *iaidStats;
+ JBIG2HuffmanDecoder *huffDecoder;
+ JBIG2MMRDecoder *mmrDecoder;
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/JPXStream.cc b/kpdf/xpdf/xpdf/JPXStream.cc
new file mode 100644
index 00000000..54a9e103
--- /dev/null
+++ b/kpdf/xpdf/xpdf/JPXStream.cc
@@ -0,0 +1,3144 @@
+//========================================================================
+//
+// JPXStream.cc
+//
+// Copyright 2002-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <limits.h>
+#include "gmem.h"
+#include "Error.h"
+#include "JArithmeticDecoder.h"
+#include "JPXStream.h"
+
+//~ to do:
+// - precincts
+// - ROI
+// - progression order changes
+// - packed packet headers
+// - support for palettes, channel maps, etc.
+// - make sure all needed JP2/JPX subboxes are parsed (readBoxes)
+// - can we assume that QCC segments must come after the QCD segment?
+// - skip EPH markers (readTilePartData)
+// - handle tilePartToEOC in readTilePartData
+// - deal with multiple codeword segments (readTilePartData,
+// readCodeBlockData)
+// - progression orders 2, 3, and 4
+// - in coefficient decoding (readCodeBlockData):
+// - termination pattern: terminate after every coding pass
+// - error resilience segmentation symbol
+// - selective arithmetic coding bypass
+// - vertically causal context formation
+// - coeffs longer than 31 bits (should just ignore the extra bits?)
+// - handle boxes larger than 2^32 bytes
+// - the fixed-point arithmetic won't handle 16-bit pixels
+
+//------------------------------------------------------------------------
+
+// number of contexts for the arithmetic decoder
+#define jpxNContexts 19
+
+#define jpxContextSigProp 0 // 0 - 8: significance prop and cleanup
+#define jpxContextSign 9 // 9 - 13: sign
+#define jpxContextMagRef 14 // 14 -16: magnitude refinement
+#define jpxContextRunLength 17 // cleanup: run length
+#define jpxContextUniform 18 // cleanup: first signif coeff
+
+//------------------------------------------------------------------------
+
+#define jpxPassSigProp 0
+#define jpxPassMagRef 1
+#define jpxPassCleanup 2
+
+//------------------------------------------------------------------------
+
+// arithmetic decoder context for the significance propagation and
+// cleanup passes:
+// [horiz][vert][diag][subband]
+// where subband = 0 for HL
+// = 1 for LH and LL
+// = 2 for HH
+static Guint sigPropContext[3][3][5][3] = {
+ {{{ 0, 0, 0 }, // horiz=0, vert=0, diag=0
+ { 1, 1, 3 }, // horiz=0, vert=0, diag=1
+ { 2, 2, 6 }, // horiz=0, vert=0, diag=2
+ { 2, 2, 8 }, // horiz=0, vert=0, diag=3
+ { 2, 2, 8 }}, // horiz=0, vert=0, diag=4
+ {{ 5, 3, 1 }, // horiz=0, vert=1, diag=0
+ { 6, 3, 4 }, // horiz=0, vert=1, diag=1
+ { 6, 3, 7 }, // horiz=0, vert=1, diag=2
+ { 6, 3, 8 }, // horiz=0, vert=1, diag=3
+ { 6, 3, 8 }}, // horiz=0, vert=1, diag=4
+ {{ 8, 4, 2 }, // horiz=0, vert=2, diag=0
+ { 8, 4, 5 }, // horiz=0, vert=2, diag=1
+ { 8, 4, 7 }, // horiz=0, vert=2, diag=2
+ { 8, 4, 8 }, // horiz=0, vert=2, diag=3
+ { 8, 4, 8 }}}, // horiz=0, vert=2, diag=4
+ {{{ 3, 5, 1 }, // horiz=1, vert=0, diag=0
+ { 3, 6, 4 }, // horiz=1, vert=0, diag=1
+ { 3, 6, 7 }, // horiz=1, vert=0, diag=2
+ { 3, 6, 8 }, // horiz=1, vert=0, diag=3
+ { 3, 6, 8 }}, // horiz=1, vert=0, diag=4
+ {{ 7, 7, 2 }, // horiz=1, vert=1, diag=0
+ { 7, 7, 5 }, // horiz=1, vert=1, diag=1
+ { 7, 7, 7 }, // horiz=1, vert=1, diag=2
+ { 7, 7, 8 }, // horiz=1, vert=1, diag=3
+ { 7, 7, 8 }}, // horiz=1, vert=1, diag=4
+ {{ 8, 7, 2 }, // horiz=1, vert=2, diag=0
+ { 8, 7, 5 }, // horiz=1, vert=2, diag=1
+ { 8, 7, 7 }, // horiz=1, vert=2, diag=2
+ { 8, 7, 8 }, // horiz=1, vert=2, diag=3
+ { 8, 7, 8 }}}, // horiz=1, vert=2, diag=4
+ {{{ 4, 8, 2 }, // horiz=2, vert=0, diag=0
+ { 4, 8, 5 }, // horiz=2, vert=0, diag=1
+ { 4, 8, 7 }, // horiz=2, vert=0, diag=2
+ { 4, 8, 8 }, // horiz=2, vert=0, diag=3
+ { 4, 8, 8 }}, // horiz=2, vert=0, diag=4
+ {{ 7, 8, 2 }, // horiz=2, vert=1, diag=0
+ { 7, 8, 5 }, // horiz=2, vert=1, diag=1
+ { 7, 8, 7 }, // horiz=2, vert=1, diag=2
+ { 7, 8, 8 }, // horiz=2, vert=1, diag=3
+ { 7, 8, 8 }}, // horiz=2, vert=1, diag=4
+ {{ 8, 8, 2 }, // horiz=2, vert=2, diag=0
+ { 8, 8, 5 }, // horiz=2, vert=2, diag=1
+ { 8, 8, 7 }, // horiz=2, vert=2, diag=2
+ { 8, 8, 8 }, // horiz=2, vert=2, diag=3
+ { 8, 8, 8 }}} // horiz=2, vert=2, diag=4
+};
+
+// arithmetic decoder context and xor bit for the sign bit in the
+// significance propagation pass:
+// [horiz][vert][k]
+// where horiz/vert are offset by 2 (i.e., range is -2 .. 2)
+// and k = 0 for the context
+// = 1 for the xor bit
+static Guint signContext[5][5][2] = {
+ {{ 13, 1 }, // horiz=-2, vert=-2
+ { 13, 1 }, // horiz=-2, vert=-1
+ { 12, 1 }, // horiz=-2, vert= 0
+ { 11, 1 }, // horiz=-2, vert=+1
+ { 11, 1 }}, // horiz=-2, vert=+2
+ {{ 13, 1 }, // horiz=-1, vert=-2
+ { 13, 1 }, // horiz=-1, vert=-1
+ { 12, 1 }, // horiz=-1, vert= 0
+ { 11, 1 }, // horiz=-1, vert=+1
+ { 11, 1 }}, // horiz=-1, vert=+2
+ {{ 10, 1 }, // horiz= 0, vert=-2
+ { 10, 1 }, // horiz= 0, vert=-1
+ { 9, 0 }, // horiz= 0, vert= 0
+ { 10, 0 }, // horiz= 0, vert=+1
+ { 10, 0 }}, // horiz= 0, vert=+2
+ {{ 11, 0 }, // horiz=+1, vert=-2
+ { 11, 0 }, // horiz=+1, vert=-1
+ { 12, 0 }, // horiz=+1, vert= 0
+ { 13, 0 }, // horiz=+1, vert=+1
+ { 13, 0 }}, // horiz=+1, vert=+2
+ {{ 11, 0 }, // horiz=+2, vert=-2
+ { 11, 0 }, // horiz=+2, vert=-1
+ { 12, 0 }, // horiz=+2, vert= 0
+ { 13, 0 }, // horiz=+2, vert=+1
+ { 13, 0 }}, // horiz=+2, vert=+2
+};
+
+//------------------------------------------------------------------------
+
+// constants used in the IDWT
+#define idwtAlpha -1.586134342059924
+#define idwtBeta -0.052980118572961
+#define idwtGamma 0.882911075530934
+#define idwtDelta 0.443506852043971
+#define idwtKappa 1.230174104914001
+#define idwtIKappa (1.0 / idwtKappa)
+
+// number of bits to the right of the decimal point for the fixed
+// point arithmetic used in the IDWT
+#define fracBits 16
+
+//------------------------------------------------------------------------
+
+// floor(x / y)
+#define jpxFloorDiv(x, y) ((x) / (y))
+
+// floor(x / 2^y)
+#define jpxFloorDivPow2(x, y) ((x) >> (y))
+
+// ceil(x / y)
+#define jpxCeilDiv(x, y) (((x) + (y) - 1) / (y))
+
+// ceil(x / 2^y)
+#define jpxCeilDivPow2(x, y) (((x) + (1 << (y)) - 1) >> (y))
+
+//------------------------------------------------------------------------
+
+#if 1 //----- disable coverage tracking
+
+#define cover(idx)
+
+#else //----- enable coverage tracking
+
+class JPXCover {
+public:
+
+ JPXCover(int sizeA);
+ ~JPXCover();
+ void incr(int idx);
+
+private:
+
+ int size, used;
+ int *data;
+};
+
+JPXCover::JPXCover(int sizeA) {
+ size = sizeA;
+ used = -1;
+ data = (int *)gmallocn(size, sizeof(int));
+ memset(data, 0, size * sizeof(int));
+}
+
+JPXCover::~JPXCover() {
+ int i;
+
+ printf("JPX coverage:\n");
+ for (i = 0; i <= used; ++i) {
+ printf(" %4d: %8d\n", i, data[i]);
+ }
+ gfree(data);
+}
+
+void JPXCover::incr(int idx) {
+ if (idx < size) {
+ ++data[idx];
+ if (idx > used) {
+ used = idx;
+ }
+ }
+}
+
+JPXCover jpxCover(150);
+
+#define cover(idx) jpxCover.incr(idx)
+
+#endif //----- coverage tracking
+
+//------------------------------------------------------------------------
+
+JPXStream::JPXStream(Stream *strA):
+ FilterStream(strA)
+{
+ nComps = 0;
+ bpc = NULL;
+ width = height = 0;
+ haveCS = gFalse;
+ havePalette = gFalse;
+ haveCompMap = gFalse;
+ haveChannelDefn = gFalse;
+
+ img.tiles = NULL;
+ bitBuf = 0;
+ bitBufLen = 0;
+ bitBufSkip = gFalse;
+ byteCount = 0;
+}
+
+JPXStream::~JPXStream() {
+ close();
+ delete str;
+}
+
+void JPXStream::reset() {
+ str->reset();
+ if (readBoxes()) {
+ curY = img.yOffset;
+ } else {
+ // readBoxes reported an error, so we go immediately to EOF
+ curY = img.ySize;
+ }
+ curX = img.xOffset;
+ curComp = 0;
+ readBufLen = 0;
+}
+
+void JPXStream::close() {
+ JPXTile *tile;
+ JPXTileComp *tileComp;
+ JPXResLevel *resLevel;
+ JPXPrecinct *precinct;
+ JPXSubband *subband;
+ JPXCodeBlock *cb;
+ Guint comp, i, k, r, pre, sb;
+
+ gfree(bpc);
+ bpc = NULL;
+ if (havePalette) {
+ gfree(palette.bpc);
+ gfree(palette.c);
+ havePalette = gFalse;
+ }
+ if (haveCompMap) {
+ gfree(compMap.comp);
+ gfree(compMap.type);
+ gfree(compMap.pComp);
+ haveCompMap = gFalse;
+ }
+ if (haveChannelDefn) {
+ gfree(channelDefn.idx);
+ gfree(channelDefn.type);
+ gfree(channelDefn.assoc);
+ haveChannelDefn = gFalse;
+ }
+
+ if (img.tiles) {
+ for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
+ tile = &img.tiles[i];
+ if (tile->tileComps) {
+ for (comp = 0; comp < img.nComps; ++comp) {
+ tileComp = &tile->tileComps[comp];
+ gfree(tileComp->quantSteps);
+ gfree(tileComp->data);
+ gfree(tileComp->buf);
+ if (tileComp->resLevels) {
+ for (r = 0; r <= tileComp->nDecompLevels; ++r) {
+ resLevel = &tileComp->resLevels[r];
+ if (resLevel->precincts) {
+ for (pre = 0; pre < 1; ++pre) {
+ precinct = &resLevel->precincts[pre];
+ if (precinct->subbands) {
+ for (sb = 0; sb < (Guint)(r == 0 ? 1 : 3); ++sb) {
+ subband = &precinct->subbands[sb];
+ gfree(subband->inclusion);
+ gfree(subband->zeroBitPlane);
+ if (subband->cbs) {
+ for (k = 0; k < subband->nXCBs * subband->nYCBs; ++k) {
+ cb = &subband->cbs[k];
+ gfree(cb->coeffs);
+ if (cb->arithDecoder) {
+ delete cb->arithDecoder;
+ }
+ if (cb->stats) {
+ delete cb->stats;
+ }
+ }
+ gfree(subband->cbs);
+ }
+ }
+ gfree(precinct->subbands);
+ }
+ }
+ gfree(img.tiles[i].tileComps[comp].resLevels[r].precincts);
+ }
+ }
+ gfree(img.tiles[i].tileComps[comp].resLevels);
+ }
+ }
+ gfree(img.tiles[i].tileComps);
+ }
+ }
+ gfree(img.tiles);
+ img.tiles = NULL;
+ }
+ FilterStream::close();
+}
+
+int JPXStream::getChar() {
+ int c;
+
+ if (readBufLen < 8) {
+ fillReadBuf();
+ }
+ if (readBufLen == 8) {
+ c = readBuf & 0xff;
+ readBufLen = 0;
+ } else if (readBufLen > 8) {
+ c = (readBuf >> (readBufLen - 8)) & 0xff;
+ readBufLen -= 8;
+ } else if (readBufLen == 0) {
+ c = EOF;
+ } else {
+ c = (readBuf << (8 - readBufLen)) & 0xff;
+ readBufLen = 0;
+ }
+ return c;
+}
+
+int JPXStream::lookChar() {
+ int c;
+
+ if (readBufLen < 8) {
+ fillReadBuf();
+ }
+ if (readBufLen == 8) {
+ c = readBuf & 0xff;
+ } else if (readBufLen > 8) {
+ c = (readBuf >> (readBufLen - 8)) & 0xff;
+ } else if (readBufLen == 0) {
+ c = EOF;
+ } else {
+ c = (readBuf << (8 - readBufLen)) & 0xff;
+ }
+ return c;
+}
+
+void JPXStream::fillReadBuf() {
+ JPXTileComp *tileComp;
+ Guint tileIdx, tx, ty;
+ int pix, pixBits;
+
+ do {
+ if (curY >= img.ySize) {
+ return;
+ }
+ tileIdx = ((curY - img.yTileOffset) / img.yTileSize) * img.nXTiles
+ + (curX - img.xTileOffset) / img.xTileSize;
+#if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid
+ tileComp = &img.tiles[tileIdx].tileComps[curComp];
+#else
+ tileComp = &img.tiles[tileIdx].tileComps[havePalette ? 0 : curComp];
+#endif
+ tx = jpxCeilDiv((curX - img.xTileOffset) % img.xTileSize, tileComp->hSep);
+ ty = jpxCeilDiv((curY - img.yTileOffset) % img.yTileSize, tileComp->vSep);
+ pix = (int)tileComp->data[ty * (tileComp->x1 - tileComp->x0) + tx];
+ pixBits = tileComp->prec;
+#if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid
+ if (++curComp == img.nComps) {
+#else
+ if (havePalette) {
+ if (pix >= 0 && pix < palette.nEntries) {
+ pix = palette.c[pix * palette.nComps + curComp];
+ } else {
+ pix =
+ pixBits = palette.bpc[curComp];
+ }
+ if (++curComp == (Guint)(havePalette ? palette.nComps : img.nComps)) {
+#endif
+ curComp = 0;
+ if (++curX == img.xSize) {
+ curX = img.xOffset;
+ ++curY;
+ }
+ }
+ if (pixBits == 8) {
+ readBuf = (readBuf << 8) | (pix & 0xff);
+ } else {
+ readBuf = (readBuf << pixBits) | (pix & ((1 << pixBits) - 1));
+ }
+ readBufLen += pixBits;
+ } while (readBufLen < 8);
+}
+
+GString *JPXStream::getPSFilter(int /*psLevel*/, char * /*indent*/) {
+ return NULL;
+}
+
+GBool JPXStream::isBinary(GBool /*last*/) {
+ return str->isBinary(gTrue);
+}
+
+void JPXStream::getImageParams(int *bitsPerComponent,
+ StreamColorSpaceMode *csMode) {
+ Guint boxType, boxLen, dataLen, csEnum;
+ Guint bpc1, dummy, i;
+ int csMeth, csPrec, csPrec1, dummy2;
+ StreamColorSpaceMode csMode1;
+ GBool haveBPC, haveCSMode;
+
+ csPrec = 0; // make gcc happy
+ haveBPC = haveCSMode = gFalse;
+ str->reset();
+ if (str->lookChar() == 0xff) {
+ getImageParams2(bitsPerComponent, csMode);
+ } else {
+ while (readBoxHdr(&boxType, &boxLen, &dataLen)) {
+ if (boxType == 0x6a703268) { // JP2 header
+ cover(0);
+ // skip the superbox
+ } else if (boxType == 0x69686472) { // image header
+ cover(1);
+ if (readULong(&dummy) &&
+ readULong(&dummy) &&
+ readUWord(&dummy) &&
+ readUByte(&bpc1) &&
+ readUByte(&dummy) &&
+ readUByte(&dummy) &&
+ readUByte(&dummy)) {
+ *bitsPerComponent = bpc1 + 1;
+ haveBPC = gTrue;
+ }
+ } else if (boxType == 0x636F6C72) { // color specification
+ cover(2);
+ if (readByte(&csMeth) &&
+ readByte(&csPrec1) &&
+ readByte(&dummy2)) {
+ if (csMeth == 1) {
+ if (readULong(&csEnum)) {
+ csMode1 = streamCSNone;
+ if (csEnum == jpxCSBiLevel ||
+ csEnum == jpxCSGrayscale) {
+ csMode1 = streamCSDeviceGray;
+ } else if (csEnum == jpxCSCMYK) {
+ csMode1 = streamCSDeviceCMYK;
+ } else if (csEnum == jpxCSsRGB ||
+ csEnum == jpxCSCISesRGB ||
+ csEnum == jpxCSROMMRGB) {
+ csMode1 = streamCSDeviceRGB;
+ }
+ if (csMode1 != streamCSNone &&
+ (!haveCSMode || csPrec1 > csPrec)) {
+ *csMode = csMode1;
+ csPrec = csPrec1;
+ haveCSMode = gTrue;
+ }
+ for (i = 0; i < dataLen - 7; ++i) {
+ str->getChar();
+ }
+ }
+ } else {
+ for (i = 0; i < dataLen - 3; ++i) {
+ str->getChar();
+ }
+ }
+ }
+ } else if (boxType == 0x6A703263) { // codestream
+ cover(3);
+ if (!(haveBPC && haveCSMode)) {
+ getImageParams2(bitsPerComponent, csMode);
+ }
+ break;
+ } else {
+ cover(4);
+ for (i = 0; i < dataLen; ++i) {
+ str->getChar();
+ }
+ }
+ }
+ }
+ str->close();
+}
+
+// Get image parameters from the codestream.
+void JPXStream::getImageParams2(int *bitsPerComponent,
+ StreamColorSpaceMode *csMode) {
+ int segType;
+ Guint segLen, nComps1, bpc1, dummy, i;
+
+ while (readMarkerHdr(&segType, &segLen)) {
+ if (segType == 0x51) { // SIZ - image and tile size
+ cover(5);
+ if (readUWord(&dummy) &&
+ readULong(&dummy) &&
+ readULong(&dummy) &&
+ readULong(&dummy) &&
+ readULong(&dummy) &&
+ readULong(&dummy) &&
+ readULong(&dummy) &&
+ readULong(&dummy) &&
+ readULong(&dummy) &&
+ readUWord(&nComps1) &&
+ readUByte(&bpc1)) {
+ *bitsPerComponent = (bpc1 & 0x7f) + 1;
+ // if there's no color space info, take a guess
+ if (nComps1 == 1) {
+ *csMode = streamCSDeviceGray;
+ } else if (nComps1 == 3) {
+ *csMode = streamCSDeviceRGB;
+ } else if (nComps1 == 4) {
+ *csMode = streamCSDeviceCMYK;
+ }
+ }
+ break;
+ } else {
+ cover(6);
+ if (segLen > 2) {
+ for (i = 0; i < segLen - 2; ++i) {
+ str->getChar();
+ }
+ }
+ }
+ }
+}
+
+GBool JPXStream::readBoxes() {
+ Guint boxType, boxLen, dataLen;
+ Guint bpc1, compression, unknownColorspace, ipr;
+ Guint i, j;
+
+ haveImgHdr = gFalse;
+
+ // check for a naked JPEG 2000 codestream (without the JP2/JPX
+ // wrapper) -- this appears to be a violation of the PDF spec, but
+ // Acrobat allows it
+ if (str->lookChar() == 0xff) {
+ cover(7);
+ error(getPos(), "Naked JPEG 2000 codestream, missing JP2/JPX wrapper");
+ readCodestream(0);
+ nComps = img.nComps;
+ bpc = (Guint *)gmallocn(nComps, sizeof(Guint));
+ for (i = 0; i < nComps; ++i) {
+ bpc[i] = img.tiles[0].tileComps[i].prec;
+ }
+ width = img.xSize - img.xOffset;
+ height = img.ySize - img.yOffset;
+ return gTrue;
+ }
+
+ while (readBoxHdr(&boxType, &boxLen, &dataLen)) {
+ switch (boxType) {
+ case 0x6a703268: // JP2 header
+ // this is a grouping box ('superbox') which has no real
+ // contents and doesn't appear to be used consistently, i.e.,
+ // some things which should be subboxes of the JP2 header box
+ // show up outside of it - so we simply ignore the JP2 header
+ // box
+ cover(8);
+ break;
+ case 0x69686472: // image header
+ cover(9);
+ if (!readULong(&height) ||
+ !readULong(&width) ||
+ !readUWord(&nComps) ||
+ !readUByte(&bpc1) ||
+ !readUByte(&compression) ||
+ !readUByte(&unknownColorspace) ||
+ !readUByte(&ipr)) {
+ error(getPos(), "Unexpected EOF in JPX stream");
+ return gFalse;
+ }
+ if (compression != 7) {
+ error(getPos(), "Unknown compression type in JPX stream");
+ return gFalse;
+ }
+ bpc = (Guint *)gmallocn(nComps, sizeof(Guint));
+ for (i = 0; i < nComps; ++i) {
+ bpc[i] = bpc1;
+ }
+ haveImgHdr = gTrue;
+ break;
+ case 0x62706363: // bits per component
+ cover(10);
+ if (!haveImgHdr) {
+ error(getPos(), "Found bits per component box before image header box in JPX stream");
+ return gFalse;
+ }
+ if (dataLen != nComps) {
+ error(getPos(), "Invalid bits per component box in JPX stream");
+ return gFalse;
+ }
+ for (i = 0; i < nComps; ++i) {
+ if (!readUByte(&bpc[i])) {
+ error(getPos(), "Unexpected EOF in JPX stream");
+ return gFalse;
+ }
+ }
+ break;
+ case 0x636F6C72: // color specification
+ cover(11);
+ if (!readColorSpecBox(dataLen)) {
+ return gFalse;
+ }
+ break;
+ case 0x70636c72: // palette
+ cover(12);
+ if (!readUWord(&palette.nEntries) ||
+ !readUByte(&palette.nComps)) {
+ error(getPos(), "Unexpected EOF in JPX stream");
+ return gFalse;
+ }
+ palette.bpc = (Guint *)gmallocn(palette.nComps, sizeof(Guint));
+ palette.c =
+ (int *)gmallocn(palette.nEntries * palette.nComps, sizeof(int));
+ for (i = 0; i < palette.nComps; ++i) {
+ if (!readUByte(&palette.bpc[i])) {
+ error(getPos(), "Unexpected EOF in JPX stream");
+ return gFalse;
+ }
+ ++palette.bpc[i];
+ }
+ for (i = 0; i < palette.nEntries; ++i) {
+ for (j = 0; j < palette.nComps; ++j) {
+ if (!readNBytes(((palette.bpc[j] & 0x7f) + 7) >> 3,
+ (palette.bpc[j] & 0x80) ? gTrue : gFalse,
+ &palette.c[i * palette.nComps + j])) {
+ error(getPos(), "Unexpected EOF in JPX stream");
+ return gFalse;
+ }
+ }
+ }
+ havePalette = gTrue;
+ break;
+ case 0x636d6170: // component mapping
+ cover(13);
+ compMap.nChannels = dataLen / 4;
+ compMap.comp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint));
+ compMap.type = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint));
+ compMap.pComp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint));
+ for (i = 0; i < compMap.nChannels; ++i) {
+ if (!readUWord(&compMap.comp[i]) ||
+ !readUByte(&compMap.type[i]) ||
+ !readUByte(&compMap.pComp[i])) {
+ error(getPos(), "Unexpected EOF in JPX stream");
+ return gFalse;
+ }
+ }
+ haveCompMap = gTrue;
+ break;
+ case 0x63646566: // channel definition
+ cover(14);
+ if (!readUWord(&channelDefn.nChannels)) {
+ error(getPos(), "Unexpected EOF in JPX stream");
+ return gFalse;
+ }
+ channelDefn.idx =
+ (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint));
+ channelDefn.type =
+ (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint));
+ channelDefn.assoc =
+ (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint));
+ for (i = 0; i < channelDefn.nChannels; ++i) {
+ if (!readUWord(&channelDefn.idx[i]) ||
+ !readUWord(&channelDefn.type[i]) ||
+ !readUWord(&channelDefn.assoc[i])) {
+ error(getPos(), "Unexpected EOF in JPX stream");
+ return gFalse;
+ }
+ }
+ haveChannelDefn = gTrue;
+ break;
+ case 0x6A703263: // contiguous codestream
+ cover(15);
+ if (!bpc) {
+ error(getPos(), "JPX stream is missing the image header box");
+ }
+ if (!haveCS) {
+ error(getPos(), "JPX stream has no supported color spec");
+ }
+ if (!readCodestream(dataLen)) {
+ return gFalse;
+ }
+ break;
+ default:
+ cover(16);
+ for (i = 0; i < dataLen; ++i) {
+ if (str->getChar() == EOF) {
+ error(getPos(), "Unexpected EOF in JPX stream");
+ return gFalse;
+ }
+ }
+ break;
+ }
+ }
+ return gTrue;
+}
+
+GBool JPXStream::readColorSpecBox(Guint dataLen) {
+ JPXColorSpec newCS;
+ Guint csApprox, csEnum;
+ Guint i;
+ GBool ok;
+
+ ok = gFalse;
+ if (!readUByte(&newCS.meth) ||
+ !readByte(&newCS.prec) ||
+ !readUByte(&csApprox)) {
+ goto err;
+ }
+ switch (newCS.meth) {
+ case 1: // enumerated colorspace
+ cover(17);
+ if (!readULong(&csEnum)) {
+ goto err;
+ }
+ newCS.enumerated.type = (JPXColorSpaceType)csEnum;
+ switch (newCS.enumerated.type) {
+ case jpxCSBiLevel:
+ ok = gTrue;
+ break;
+ case jpxCSYCbCr1:
+ ok = gTrue;
+ break;
+ case jpxCSYCbCr2:
+ ok = gTrue;
+ break;
+ case jpxCSYCBCr3:
+ ok = gTrue;
+ break;
+ case jpxCSPhotoYCC:
+ ok = gTrue;
+ break;
+ case jpxCSCMY:
+ ok = gTrue;
+ break;
+ case jpxCSCMYK:
+ ok = gTrue;
+ break;
+ case jpxCSYCCK:
+ ok = gTrue;
+ break;
+ case jpxCSCIELab:
+ if (dataLen == 7 + 7*4) {
+ if (!readULong(&newCS.enumerated.cieLab.rl) ||
+ !readULong(&newCS.enumerated.cieLab.ol) ||
+ !readULong(&newCS.enumerated.cieLab.ra) ||
+ !readULong(&newCS.enumerated.cieLab.oa) ||
+ !readULong(&newCS.enumerated.cieLab.rb) ||
+ !readULong(&newCS.enumerated.cieLab.ob) ||
+ !readULong(&newCS.enumerated.cieLab.il)) {
+ goto err;
+ }
+ } else if (dataLen == 7) {
+ //~ this assumes the 8-bit case
+ cover(92);
+ newCS.enumerated.cieLab.rl = 100;
+ newCS.enumerated.cieLab.ol = 0;
+ newCS.enumerated.cieLab.ra = 255;
+ newCS.enumerated.cieLab.oa = 128;
+ newCS.enumerated.cieLab.rb = 255;
+ newCS.enumerated.cieLab.ob = 96;
+ newCS.enumerated.cieLab.il = 0x00443530;
+ } else {
+ goto err;
+ }
+ ok = gTrue;
+ break;
+ case jpxCSsRGB:
+ ok = gTrue;
+ break;
+ case jpxCSGrayscale:
+ ok = gTrue;
+ break;
+ case jpxCSBiLevel2:
+ ok = gTrue;
+ break;
+ case jpxCSCIEJab:
+ // not allowed in PDF
+ goto err;
+ case jpxCSCISesRGB:
+ ok = gTrue;
+ break;
+ case jpxCSROMMRGB:
+ ok = gTrue;
+ break;
+ case jpxCSsRGBYCbCr:
+ ok = gTrue;
+ break;
+ case jpxCSYPbPr1125:
+ ok = gTrue;
+ break;
+ case jpxCSYPbPr1250:
+ ok = gTrue;
+ break;
+ default:
+ goto err;
+ }
+ break;
+ case 2: // restricted ICC profile
+ case 3: // any ICC profile (JPX)
+ case 4: // vendor color (JPX)
+ cover(18);
+ for (i = 0; i < dataLen - 3; ++i) {
+ if (str->getChar() == EOF) {
+ goto err;
+ }
+ }
+ break;
+ }
+
+ if (ok && (!haveCS || newCS.prec > cs.prec)) {
+ cs = newCS;
+ haveCS = gTrue;
+ }
+
+ return gTrue;
+
+ err:
+ error(getPos(), "Error in JPX color spec");
+ return gFalse;
+}
+
+GBool JPXStream::readCodestream(Guint /*len*/) {
+ JPXTile *tile;
+ JPXTileComp *tileComp;
+ int segType;
+ GBool haveSIZ, haveCOD, haveQCD, haveSOT;
+ Guint precinctSize, style;
+ Guint segLen, capabilities, comp, i, j, r;
+
+ //----- main header
+ haveSIZ = haveCOD = haveQCD = haveSOT = gFalse;
+ do {
+ if (!readMarkerHdr(&segType, &segLen)) {
+ error(getPos(), "Error in JPX codestream");
+ return gFalse;
+ }
+ switch (segType) {
+ case 0x4f: // SOC - start of codestream
+ // marker only
+ cover(19);
+ break;
+ case 0x51: // SIZ - image and tile size
+ cover(20);
+ if (!readUWord(&capabilities) ||
+ !readULong(&img.xSize) ||
+ !readULong(&img.ySize) ||
+ !readULong(&img.xOffset) ||
+ !readULong(&img.yOffset) ||
+ !readULong(&img.xTileSize) ||
+ !readULong(&img.yTileSize) ||
+ !readULong(&img.xTileOffset) ||
+ !readULong(&img.yTileOffset) ||
+ !readUWord(&img.nComps)) {
+ error(getPos(), "Error in JPX SIZ marker segment");
+ return gFalse;
+ }
+ if (haveImgHdr && img.nComps != nComps) {
+ error(getPos(), "Different number of components in JPX SIZ marker segment");
+ return gFalse;
+ }
+ img.nXTiles = (img.xSize - img.xTileOffset + img.xTileSize - 1)
+ / img.xTileSize;
+ img.nYTiles = (img.ySize - img.yTileOffset + img.yTileSize - 1)
+ / img.yTileSize;
+ // check for overflow before allocating memory
+ if (img.nXTiles <= 0 || img.nYTiles <= 0 ||
+ img.nXTiles >= INT_MAX / img.nYTiles) {
+ error(getPos(), "Bad tile count in JPX SIZ marker segment");
+ return gFalse;
+ }
+ img.tiles = (JPXTile *)gmallocn(img.nXTiles * img.nYTiles,
+ sizeof(JPXTile));
+ for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
+ img.tiles[i].tileComps = (JPXTileComp *)gmallocn(img.nComps,
+ sizeof(JPXTileComp));
+ for (comp = 0; comp < img.nComps; ++comp) {
+ img.tiles[i].tileComps[comp].quantSteps = NULL;
+ img.tiles[i].tileComps[comp].data = NULL;
+ img.tiles[i].tileComps[comp].buf = NULL;
+ img.tiles[i].tileComps[comp].resLevels = NULL;
+ }
+ }
+ for (comp = 0; comp < img.nComps; ++comp) {
+ if (!readUByte(&img.tiles[0].tileComps[comp].prec) ||
+ !readUByte(&img.tiles[0].tileComps[comp].hSep) ||
+ !readUByte(&img.tiles[0].tileComps[comp].vSep)) {
+ error(getPos(), "Error in JPX SIZ marker segment");
+ return gFalse;
+ }
+ img.tiles[0].tileComps[comp].sgned =
+ (img.tiles[0].tileComps[comp].prec & 0x80) ? gTrue : gFalse;
+ img.tiles[0].tileComps[comp].prec =
+ (img.tiles[0].tileComps[comp].prec & 0x7f) + 1;
+ for (i = 1; i < img.nXTiles * img.nYTiles; ++i) {
+ img.tiles[i].tileComps[comp] = img.tiles[0].tileComps[comp];
+ }
+ }
+ haveSIZ = gTrue;
+ break;
+ case 0x52: // COD - coding style default
+ cover(21);
+ if (!readUByte(&img.tiles[0].tileComps[0].style) ||
+ !readUByte(&img.tiles[0].progOrder) ||
+ !readUWord(&img.tiles[0].nLayers) ||
+ !readUByte(&img.tiles[0].multiComp) ||
+ !readUByte(&img.tiles[0].tileComps[0].nDecompLevels) ||
+ !readUByte(&img.tiles[0].tileComps[0].codeBlockW) ||
+ !readUByte(&img.tiles[0].tileComps[0].codeBlockH) ||
+ !readUByte(&img.tiles[0].tileComps[0].codeBlockStyle) ||
+ !readUByte(&img.tiles[0].tileComps[0].transform)) {
+ error(getPos(), "Error in JPX COD marker segment");
+ return gFalse;
+ }
+ img.tiles[0].tileComps[0].codeBlockW += 2;
+ img.tiles[0].tileComps[0].codeBlockH += 2;
+ for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
+ if (i != 0) {
+ img.tiles[i].progOrder = img.tiles[0].progOrder;
+ img.tiles[i].nLayers = img.tiles[0].nLayers;
+ img.tiles[i].multiComp = img.tiles[0].multiComp;
+ }
+ for (comp = 0; comp < img.nComps; ++comp) {
+ if (!(i == 0 && comp == 0)) {
+ img.tiles[i].tileComps[comp].style =
+ img.tiles[0].tileComps[0].style;
+ img.tiles[i].tileComps[comp].nDecompLevels =
+ img.tiles[0].tileComps[0].nDecompLevels;
+ img.tiles[i].tileComps[comp].codeBlockW =
+ img.tiles[0].tileComps[0].codeBlockW;
+ img.tiles[i].tileComps[comp].codeBlockH =
+ img.tiles[0].tileComps[0].codeBlockH;
+ img.tiles[i].tileComps[comp].codeBlockStyle =
+ img.tiles[0].tileComps[0].codeBlockStyle;
+ img.tiles[i].tileComps[comp].transform =
+ img.tiles[0].tileComps[0].transform;
+ }
+ img.tiles[i].tileComps[comp].resLevels =
+ (JPXResLevel *)gmallocn(
+ (img.tiles[i].tileComps[comp].nDecompLevels + 1),
+ sizeof(JPXResLevel));
+ for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
+ img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL;
+ }
+ }
+ }
+ for (r = 0; r <= img.tiles[0].tileComps[0].nDecompLevels; ++r) {
+ if (img.tiles[0].tileComps[0].style & 0x01) {
+ cover(91);
+ if (!readUByte(&precinctSize)) {
+ error(getPos(), "Error in JPX COD marker segment");
+ return gFalse;
+ }
+ img.tiles[0].tileComps[0].resLevels[r].precinctWidth =
+ precinctSize & 0x0f;
+ img.tiles[0].tileComps[0].resLevels[r].precinctHeight =
+ (precinctSize >> 4) & 0x0f;
+ } else {
+ img.tiles[0].tileComps[0].resLevels[r].precinctWidth = 15;
+ img.tiles[0].tileComps[0].resLevels[r].precinctHeight = 15;
+ }
+ }
+ for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
+ for (comp = 0; comp < img.nComps; ++comp) {
+ if (!(i == 0 && comp == 0)) {
+ for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
+ img.tiles[i].tileComps[comp].resLevels[r].precinctWidth =
+ img.tiles[0].tileComps[0].resLevels[r].precinctWidth;
+ img.tiles[i].tileComps[comp].resLevels[r].precinctHeight =
+ img.tiles[0].tileComps[0].resLevels[r].precinctHeight;
+ }
+ }
+ }
+ }
+ haveCOD = gTrue;
+ break;
+ case 0x53: // COC - coding style component
+ cover(22);
+ if (!haveCOD) {
+ error(getPos(), "JPX COC marker segment before COD segment");
+ return gFalse;
+ }
+ if ((img.nComps > 256 && !readUWord(&comp)) ||
+ (img.nComps <= 256 && !readUByte(&comp)) ||
+ comp >= img.nComps ||
+ !readUByte(&style) ||
+ !readUByte(&img.tiles[0].tileComps[comp].nDecompLevels) ||
+ !readUByte(&img.tiles[0].tileComps[comp].codeBlockW) ||
+ !readUByte(&img.tiles[0].tileComps[comp].codeBlockH) ||
+ !readUByte(&img.tiles[0].tileComps[comp].codeBlockStyle) ||
+ !readUByte(&img.tiles[0].tileComps[comp].transform)) {
+ error(getPos(), "Error in JPX COC marker segment");
+ return gFalse;
+ }
+ img.tiles[0].tileComps[comp].style =
+ (img.tiles[0].tileComps[comp].style & ~1) | (style & 1);
+ img.tiles[0].tileComps[comp].codeBlockW += 2;
+ img.tiles[0].tileComps[comp].codeBlockH += 2;
+ for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
+ if (i != 0) {
+ img.tiles[i].tileComps[comp].style =
+ img.tiles[0].tileComps[comp].style;
+ img.tiles[i].tileComps[comp].nDecompLevels =
+ img.tiles[0].tileComps[comp].nDecompLevels;
+ img.tiles[i].tileComps[comp].codeBlockW =
+ img.tiles[0].tileComps[comp].codeBlockW;
+ img.tiles[i].tileComps[comp].codeBlockH =
+ img.tiles[0].tileComps[comp].codeBlockH;
+ img.tiles[i].tileComps[comp].codeBlockStyle =
+ img.tiles[0].tileComps[comp].codeBlockStyle;
+ img.tiles[i].tileComps[comp].transform =
+ img.tiles[0].tileComps[comp].transform;
+ }
+ img.tiles[i].tileComps[comp].resLevels =
+ (JPXResLevel *)greallocn(
+ img.tiles[i].tileComps[comp].resLevels,
+ (img.tiles[i].tileComps[comp].nDecompLevels + 1),
+ sizeof(JPXResLevel));
+ for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
+ img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL;
+ }
+ }
+ for (r = 0; r <= img.tiles[0].tileComps[comp].nDecompLevels; ++r) {
+ if (img.tiles[0].tileComps[comp].style & 0x01) {
+ if (!readUByte(&precinctSize)) {
+ error(getPos(), "Error in JPX COD marker segment");
+ return gFalse;
+ }
+ img.tiles[0].tileComps[comp].resLevels[r].precinctWidth =
+ precinctSize & 0x0f;
+ img.tiles[0].tileComps[comp].resLevels[r].precinctHeight =
+ (precinctSize >> 4) & 0x0f;
+ } else {
+ img.tiles[0].tileComps[comp].resLevels[r].precinctWidth = 15;
+ img.tiles[0].tileComps[comp].resLevels[r].precinctHeight = 15;
+ }
+ }
+ for (i = 1; i < img.nXTiles * img.nYTiles; ++i) {
+ for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) {
+ img.tiles[i].tileComps[comp].resLevels[r].precinctWidth =
+ img.tiles[0].tileComps[comp].resLevels[r].precinctWidth;
+ img.tiles[i].tileComps[comp].resLevels[r].precinctHeight =
+ img.tiles[0].tileComps[comp].resLevels[r].precinctHeight;
+ }
+ }
+ break;
+ case 0x5c: // QCD - quantization default
+ cover(23);
+ if (!readUByte(&img.tiles[0].tileComps[0].quantStyle)) {
+ error(getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x00) {
+ img.tiles[0].tileComps[0].nQuantSteps = segLen - 3;
+ img.tiles[0].tileComps[0].quantSteps =
+ (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps,
+ img.tiles[0].tileComps[0].nQuantSteps,
+ sizeof(Guint));
+ for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) {
+ if (!readUByte(&img.tiles[0].tileComps[0].quantSteps[i])) {
+ error(getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ }
+ } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x01) {
+ img.tiles[0].tileComps[0].nQuantSteps = 1;
+ img.tiles[0].tileComps[0].quantSteps =
+ (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps,
+ img.tiles[0].tileComps[0].nQuantSteps,
+ sizeof(Guint));
+ if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[0])) {
+ error(getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x02) {
+ img.tiles[0].tileComps[0].nQuantSteps = (segLen - 3) / 2;
+ img.tiles[0].tileComps[0].quantSteps =
+ (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps,
+ img.tiles[0].tileComps[0].nQuantSteps,
+ sizeof(Guint));
+ for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) {
+ if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[i])) {
+ error(getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ }
+ } else {
+ error(getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
+ for (comp = 0; comp < img.nComps; ++comp) {
+ if (!(i == 0 && comp == 0)) {
+ img.tiles[i].tileComps[comp].quantStyle =
+ img.tiles[0].tileComps[0].quantStyle;
+ img.tiles[i].tileComps[comp].nQuantSteps =
+ img.tiles[0].tileComps[0].nQuantSteps;
+ img.tiles[i].tileComps[comp].quantSteps =
+ (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps,
+ img.tiles[0].tileComps[0].nQuantSteps,
+ sizeof(Guint));
+ for (j = 0; j < img.tiles[0].tileComps[0].nQuantSteps; ++j) {
+ img.tiles[i].tileComps[comp].quantSteps[j] =
+ img.tiles[0].tileComps[0].quantSteps[j];
+ }
+ }
+ }
+ }
+ haveQCD = gTrue;
+ break;
+ case 0x5d: // QCC - quantization component
+ cover(24);
+ if (!haveQCD) {
+ error(getPos(), "JPX QCC marker segment before QCD segment");
+ return gFalse;
+ }
+ if ((img.nComps > 256 && !readUWord(&comp)) ||
+ (img.nComps <= 256 && !readUByte(&comp)) ||
+ comp >= img.nComps ||
+ !readUByte(&img.tiles[0].tileComps[comp].quantStyle)) {
+ error(getPos(), "Error in JPX QCC marker segment");
+ return gFalse;
+ }
+ if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x00) {
+ img.tiles[0].tileComps[comp].nQuantSteps =
+ segLen - (img.nComps > 256 ? 5 : 4);
+ img.tiles[0].tileComps[comp].quantSteps =
+ (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps,
+ img.tiles[0].tileComps[comp].nQuantSteps,
+ sizeof(Guint));
+ for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) {
+ if (!readUByte(&img.tiles[0].tileComps[comp].quantSteps[i])) {
+ error(getPos(), "Error in JPX QCC marker segment");
+ return gFalse;
+ }
+ }
+ } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x01) {
+ img.tiles[0].tileComps[comp].nQuantSteps = 1;
+ img.tiles[0].tileComps[comp].quantSteps =
+ (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps,
+ img.tiles[0].tileComps[comp].nQuantSteps,
+ sizeof(Guint));
+ if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[0])) {
+ error(getPos(), "Error in JPX QCC marker segment");
+ return gFalse;
+ }
+ } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x02) {
+ img.tiles[0].tileComps[comp].nQuantSteps =
+ (segLen - (img.nComps > 256 ? 5 : 4)) / 2;
+ img.tiles[0].tileComps[comp].quantSteps =
+ (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps,
+ img.tiles[0].tileComps[comp].nQuantSteps,
+ sizeof(Guint));
+ for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) {
+ if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[i])) {
+ error(getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ }
+ } else {
+ error(getPos(), "Error in JPX QCC marker segment");
+ return gFalse;
+ }
+ for (i = 1; i < img.nXTiles * img.nYTiles; ++i) {
+ img.tiles[i].tileComps[comp].quantStyle =
+ img.tiles[0].tileComps[comp].quantStyle;
+ img.tiles[i].tileComps[comp].nQuantSteps =
+ img.tiles[0].tileComps[comp].nQuantSteps;
+ img.tiles[i].tileComps[comp].quantSteps =
+ (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps,
+ img.tiles[0].tileComps[comp].nQuantSteps,
+ sizeof(Guint));
+ for (j = 0; j < img.tiles[0].tileComps[comp].nQuantSteps; ++j) {
+ img.tiles[i].tileComps[comp].quantSteps[j] =
+ img.tiles[0].tileComps[comp].quantSteps[j];
+ }
+ }
+ break;
+ case 0x5e: // RGN - region of interest
+ cover(25);
+#if 1 //~ ROI is unimplemented
+ fprintf(stderr, "RGN\n");
+ for (i = 0; i < segLen - 2; ++i) {
+ if (str->getChar() == EOF) {
+ error(getPos(), "Error in JPX PPM marker segment");
+ return gFalse;
+ }
+ }
+#else
+ if ((img.nComps > 256 && !readUWord(&comp)) ||
+ (img.nComps <= 256 && !readUByte(&comp)) ||
+ comp >= img.nComps ||
+ !readUByte(&compInfo[comp].defROI.style) ||
+ !readUByte(&compInfo[comp].defROI.shift)) {
+ error(getPos(), "Error in JPX RGN marker segment");
+ return gFalse;
+ }
+#endif
+ break;
+ case 0x5f: // POC - progression order change
+ cover(26);
+#if 1 //~ progression order changes are unimplemented
+ fprintf(stderr, "POC\n");
+ for (i = 0; i < segLen - 2; ++i) {
+ if (str->getChar() == EOF) {
+ error(getPos(), "Error in JPX PPM marker segment");
+ return gFalse;
+ }
+ }
+#else
+ nProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7);
+ progs = (JPXProgOrder *)gmallocn(nProgs, sizeof(JPXProgOrder));
+ for (i = 0; i < nProgs; ++i) {
+ if (!readUByte(&progs[i].startRes) ||
+ !(img.nComps > 256 && readUWord(&progs[i].startComp)) ||
+ !(img.nComps <= 256 && readUByte(&progs[i].startComp)) ||
+ !readUWord(&progs[i].endLayer) ||
+ !readUByte(&progs[i].endRes) ||
+ !(img.nComps > 256 && readUWord(&progs[i].endComp)) ||
+ !(img.nComps <= 256 && readUByte(&progs[i].endComp)) ||
+ !readUByte(&progs[i].progOrder)) {
+ error(getPos(), "Error in JPX POC marker segment");
+ return gFalse;
+ }
+ }
+#endif
+ break;
+ case 0x60: // PPM - packed packet headers, main header
+ cover(27);
+#if 1 //~ packed packet headers are unimplemented
+ fprintf(stderr, "PPM\n");
+ for (i = 0; i < segLen - 2; ++i) {
+ if (str->getChar() == EOF) {
+ error(getPos(), "Error in JPX PPM marker segment");
+ return gFalse;
+ }
+ }
+#endif
+ break;
+ case 0x55: // TLM - tile-part lengths
+ // skipped
+ cover(28);
+ for (i = 0; i < segLen - 2; ++i) {
+ if (str->getChar() == EOF) {
+ error(getPos(), "Error in JPX TLM marker segment");
+ return gFalse;
+ }
+ }
+ break;
+ case 0x57: // PLM - packet length, main header
+ // skipped
+ cover(29);
+ for (i = 0; i < segLen - 2; ++i) {
+ if (str->getChar() == EOF) {
+ error(getPos(), "Error in JPX PLM marker segment");
+ return gFalse;
+ }
+ }
+ break;
+ case 0x63: // CRG - component registration
+ // skipped
+ cover(30);
+ for (i = 0; i < segLen - 2; ++i) {
+ if (str->getChar() == EOF) {
+ error(getPos(), "Error in JPX CRG marker segment");
+ return gFalse;
+ }
+ }
+ break;
+ case 0x64: // COM - comment
+ // skipped
+ cover(31);
+ for (i = 0; i < segLen - 2; ++i) {
+ if (str->getChar() == EOF) {
+ error(getPos(), "Error in JPX COM marker segment");
+ return gFalse;
+ }
+ }
+ break;
+ case 0x90: // SOT - start of tile
+ cover(32);
+ haveSOT = gTrue;
+ break;
+ default:
+ cover(33);
+ error(getPos(), "Unknown marker segment %02x in JPX stream", segType);
+ for (i = 0; i < segLen - 2; ++i) {
+ if (str->getChar() == EOF) {
+ break;
+ }
+ }
+ break;
+ }
+ } while (!haveSOT);
+
+ if (!haveSIZ) {
+ error(getPos(), "Missing SIZ marker segment in JPX stream");
+ return gFalse;
+ }
+ if (!haveCOD) {
+ error(getPos(), "Missing COD marker segment in JPX stream");
+ return gFalse;
+ }
+ if (!haveQCD) {
+ error(getPos(), "Missing QCD marker segment in JPX stream");
+ return gFalse;
+ }
+
+ //----- read the tile-parts
+ while (1) {
+ if (!readTilePart()) {
+ return gFalse;
+ }
+ if (!readMarkerHdr(&segType, &segLen)) {
+ error(getPos(), "Error in JPX codestream");
+ return gFalse;
+ }
+ if (segType != 0x90) { // SOT - start of tile
+ break;
+ }
+ }
+
+ if (segType != 0xd9) { // EOC - end of codestream
+ error(getPos(), "Missing EOC marker in JPX codestream");
+ return gFalse;
+ }
+
+ //----- finish decoding the image
+ for (i = 0; i < img.nXTiles * img.nYTiles; ++i) {
+ tile = &img.tiles[i];
+ for (comp = 0; comp < img.nComps; ++comp) {
+ tileComp = &tile->tileComps[comp];
+ inverseTransform(tileComp);
+ }
+ if (!inverseMultiCompAndDC(tile)) {
+ return gFalse;
+ }
+ }
+
+ //~ can free memory below tileComps here, and also tileComp.buf
+
+ return gTrue;
+}
+
+GBool JPXStream::readTilePart() {
+ JPXTile *tile;
+ JPXTileComp *tileComp;
+ JPXResLevel *resLevel;
+ JPXPrecinct *precinct;
+ JPXSubband *subband;
+ JPXCodeBlock *cb;
+ GBool haveSOD;
+ Guint tileIdx, tilePartLen, tilePartIdx, nTileParts;
+ GBool tilePartToEOC;
+ Guint precinctSize, style;
+ Guint n, nSBs, nx, ny, sbx0, sby0, comp, segLen;
+ Guint i, j, k, cbX, cbY, r, pre, sb, cbi;
+ int segType, level;
+
+ // process the SOT marker segment
+ if (!readUWord(&tileIdx) ||
+ !readULong(&tilePartLen) ||
+ !readUByte(&tilePartIdx) ||
+ !readUByte(&nTileParts)) {
+ error(getPos(), "Error in JPX SOT marker segment");
+ return gFalse;
+ }
+
+ if (tileIdx >= img.nXTiles * img.nYTiles) {
+ error(getPos(), "Weird tile index in JPX stream");
+ return gFalse;
+ }
+
+ tilePartToEOC = tilePartLen == 0;
+ tilePartLen -= 12; // subtract size of SOT segment
+
+ haveSOD = gFalse;
+ do {
+ if (!readMarkerHdr(&segType, &segLen)) {
+ error(getPos(), "Error in JPX tile-part codestream");
+ return gFalse;
+ }
+ tilePartLen -= 2 + segLen;
+ switch (segType) {
+ case 0x52: // COD - coding style default
+ cover(34);
+ if (!readUByte(&img.tiles[tileIdx].tileComps[0].style) ||
+ !readUByte(&img.tiles[tileIdx].progOrder) ||
+ !readUWord(&img.tiles[tileIdx].nLayers) ||
+ !readUByte(&img.tiles[tileIdx].multiComp) ||
+ !readUByte(&img.tiles[tileIdx].tileComps[0].nDecompLevels) ||
+ !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockW) ||
+ !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockH) ||
+ !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockStyle) ||
+ !readUByte(&img.tiles[tileIdx].tileComps[0].transform)) {
+ error(getPos(), "Error in JPX COD marker segment");
+ return gFalse;
+ }
+ img.tiles[tileIdx].tileComps[0].codeBlockW += 2;
+ img.tiles[tileIdx].tileComps[0].codeBlockH += 2;
+ for (comp = 0; comp < img.nComps; ++comp) {
+ if (comp != 0) {
+ img.tiles[tileIdx].tileComps[comp].style =
+ img.tiles[tileIdx].tileComps[0].style;
+ img.tiles[tileIdx].tileComps[comp].nDecompLevels =
+ img.tiles[tileIdx].tileComps[0].nDecompLevels;
+ img.tiles[tileIdx].tileComps[comp].codeBlockW =
+ img.tiles[tileIdx].tileComps[0].codeBlockW;
+ img.tiles[tileIdx].tileComps[comp].codeBlockH =
+ img.tiles[tileIdx].tileComps[0].codeBlockH;
+ img.tiles[tileIdx].tileComps[comp].codeBlockStyle =
+ img.tiles[tileIdx].tileComps[0].codeBlockStyle;
+ img.tiles[tileIdx].tileComps[comp].transform =
+ img.tiles[tileIdx].tileComps[0].transform;
+ }
+ img.tiles[tileIdx].tileComps[comp].resLevels =
+ (JPXResLevel *)greallocn(
+ img.tiles[tileIdx].tileComps[comp].resLevels,
+ (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1),
+ sizeof(JPXResLevel));
+ for (r = 0;
+ r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels;
+ ++r) {
+ img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL;
+ }
+ }
+ for (r = 0; r <= img.tiles[tileIdx].tileComps[0].nDecompLevels; ++r) {
+ if (img.tiles[tileIdx].tileComps[0].style & 0x01) {
+ if (!readUByte(&precinctSize)) {
+ error(getPos(), "Error in JPX COD marker segment");
+ return gFalse;
+ }
+ img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth =
+ precinctSize & 0x0f;
+ img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight =
+ (precinctSize >> 4) & 0x0f;
+ } else {
+ img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth = 15;
+ img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight = 15;
+ }
+ }
+ for (comp = 1; comp < img.nComps; ++comp) {
+ for (r = 0;
+ r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels;
+ ++r) {
+ img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth =
+ img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth;
+ img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight =
+ img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight;
+ }
+ }
+ break;
+ case 0x53: // COC - coding style component
+ cover(35);
+ if ((img.nComps > 256 && !readUWord(&comp)) ||
+ (img.nComps <= 256 && !readUByte(&comp)) ||
+ comp >= img.nComps ||
+ !readUByte(&style) ||
+ !readUByte(&img.tiles[tileIdx].tileComps[comp].nDecompLevels) ||
+ !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockW) ||
+ !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockH) ||
+ !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockStyle) ||
+ !readUByte(&img.tiles[tileIdx].tileComps[comp].transform)) {
+ error(getPos(), "Error in JPX COC marker segment");
+ return gFalse;
+ }
+ img.tiles[tileIdx].tileComps[comp].style =
+ (img.tiles[tileIdx].tileComps[comp].style & ~1) | (style & 1);
+ img.tiles[tileIdx].tileComps[comp].codeBlockW += 2;
+ img.tiles[tileIdx].tileComps[comp].codeBlockH += 2;
+ img.tiles[tileIdx].tileComps[comp].resLevels =
+ (JPXResLevel *)greallocn(
+ img.tiles[tileIdx].tileComps[comp].resLevels,
+ (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1),
+ sizeof(JPXResLevel));
+ for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) {
+ img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL;
+ }
+ for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) {
+ if (img.tiles[tileIdx].tileComps[comp].style & 0x01) {
+ if (!readUByte(&precinctSize)) {
+ error(getPos(), "Error in JPX COD marker segment");
+ return gFalse;
+ }
+ img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth =
+ precinctSize & 0x0f;
+ img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight =
+ (precinctSize >> 4) & 0x0f;
+ } else {
+ img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth = 15;
+ img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight = 15;
+ }
+ }
+ break;
+ case 0x5c: // QCD - quantization default
+ cover(36);
+ if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantStyle)) {
+ error(getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x00) {
+ img.tiles[tileIdx].tileComps[0].nQuantSteps =
+ segLen - 3;
+ img.tiles[tileIdx].tileComps[0].quantSteps =
+ (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps,
+ img.tiles[tileIdx].tileComps[0].nQuantSteps,
+ sizeof(Guint));
+ for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) {
+ if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) {
+ error(getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ }
+ } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x01) {
+ img.tiles[tileIdx].tileComps[0].nQuantSteps = 1;
+ img.tiles[tileIdx].tileComps[0].quantSteps =
+ (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps,
+ img.tiles[tileIdx].tileComps[0].nQuantSteps,
+ sizeof(Guint));
+ if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[0])) {
+ error(getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x02) {
+ img.tiles[tileIdx].tileComps[0].nQuantSteps = (segLen - 3) / 2;
+ img.tiles[tileIdx].tileComps[0].quantSteps =
+ (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps,
+ img.tiles[tileIdx].tileComps[0].nQuantSteps,
+ sizeof(Guint));
+ for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) {
+ if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) {
+ error(getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ }
+ } else {
+ error(getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ for (comp = 1; comp < img.nComps; ++comp) {
+ img.tiles[tileIdx].tileComps[comp].quantStyle =
+ img.tiles[tileIdx].tileComps[0].quantStyle;
+ img.tiles[tileIdx].tileComps[comp].nQuantSteps =
+ img.tiles[tileIdx].tileComps[0].nQuantSteps;
+ img.tiles[tileIdx].tileComps[comp].quantSteps =
+ (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
+ img.tiles[tileIdx].tileComps[0].nQuantSteps,
+ sizeof(Guint));
+ for (j = 0; j < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++j) {
+ img.tiles[tileIdx].tileComps[comp].quantSteps[j] =
+ img.tiles[tileIdx].tileComps[0].quantSteps[j];
+ }
+ }
+ break;
+ case 0x5d: // QCC - quantization component
+ cover(37);
+ if ((img.nComps > 256 && !readUWord(&comp)) ||
+ (img.nComps <= 256 && !readUByte(&comp)) ||
+ comp >= img.nComps ||
+ !readUByte(&img.tiles[tileIdx].tileComps[comp].quantStyle)) {
+ error(getPos(), "Error in JPX QCC marker segment");
+ return gFalse;
+ }
+ if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f) == 0x00) {
+ img.tiles[tileIdx].tileComps[comp].nQuantSteps =
+ segLen - (img.nComps > 256 ? 5 : 4);
+ img.tiles[tileIdx].tileComps[comp].quantSteps =
+ (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
+ img.tiles[tileIdx].tileComps[comp].nQuantSteps,
+ sizeof(Guint));
+ for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) {
+ if (!readUByte(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) {
+ error(getPos(), "Error in JPX QCC marker segment");
+ return gFalse;
+ }
+ }
+ } else if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f)
+ == 0x01) {
+ img.tiles[tileIdx].tileComps[comp].nQuantSteps = 1;
+ img.tiles[tileIdx].tileComps[comp].quantSteps =
+ (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
+ img.tiles[tileIdx].tileComps[comp].nQuantSteps,
+ sizeof(Guint));
+ if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[0])) {
+ error(getPos(), "Error in JPX QCC marker segment");
+ return gFalse;
+ }
+ } else if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f)
+ == 0x02) {
+ img.tiles[tileIdx].tileComps[comp].nQuantSteps =
+ (segLen - (img.nComps > 256 ? 5 : 4)) / 2;
+ img.tiles[tileIdx].tileComps[comp].quantSteps =
+ (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps,
+ img.tiles[tileIdx].tileComps[comp].nQuantSteps,
+ sizeof(Guint));
+ for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) {
+ if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) {
+ error(getPos(), "Error in JPX QCD marker segment");
+ return gFalse;
+ }
+ }
+ } else {
+ error(getPos(), "Error in JPX QCC marker segment");
+ return gFalse;
+ }
+ break;
+ case 0x5e: // RGN - region of interest
+ cover(38);
+#if 1 //~ ROI is unimplemented
+ fprintf(stderr, "RGN\n");
+ for (i = 0; i < segLen - 2; ++i) {
+ if (str->getChar() == EOF) {
+ error(getPos(), "Error in JPX PPM marker segment");
+ return gFalse;
+ }
+ }
+#else
+ if ((img.nComps > 256 && !readUWord(&comp)) ||
+ (img.nComps <= 256 && !readUByte(&comp)) ||
+ comp >= img.nComps ||
+ !readUByte(&compInfo[comp].roi.style) ||
+ !readUByte(&compInfo[comp].roi.shift)) {
+ error(getPos(), "Error in JPX RGN marker segment");
+ return gFalse;
+ }
+#endif
+ break;
+ case 0x5f: // POC - progression order change
+ cover(39);
+#if 1 //~ progression order changes are unimplemented
+ fprintf(stderr, "POC\n");
+ for (i = 0; i < segLen - 2; ++i) {
+ if (str->getChar() == EOF) {
+ error(getPos(), "Error in JPX PPM marker segment");
+ return gFalse;
+ }
+ }
+#else
+ nTileProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7);
+ tileProgs = (JPXProgOrder *)gmallocn(nTileProgs, sizeof(JPXProgOrder));
+ for (i = 0; i < nTileProgs; ++i) {
+ if (!readUByte(&tileProgs[i].startRes) ||
+ !(img.nComps > 256 && readUWord(&tileProgs[i].startComp)) ||
+ !(img.nComps <= 256 && readUByte(&tileProgs[i].startComp)) ||
+ !readUWord(&tileProgs[i].endLayer) ||
+ !readUByte(&tileProgs[i].endRes) ||
+ !(img.nComps > 256 && readUWord(&tileProgs[i].endComp)) ||
+ !(img.nComps <= 256 && readUByte(&tileProgs[i].endComp)) ||
+ !readUByte(&tileProgs[i].progOrder)) {
+ error(getPos(), "Error in JPX POC marker segment");
+ return gFalse;
+ }
+ }
+#endif
+ break;
+ case 0x61: // PPT - packed packet headers, tile-part hdr
+ cover(40);
+#if 1 //~ packed packet headers are unimplemented
+ fprintf(stderr, "PPT\n");
+ for (i = 0; i < segLen - 2; ++i) {
+ if (str->getChar() == EOF) {
+ error(getPos(), "Error in JPX PPT marker segment");
+ return gFalse;
+ }
+ }
+#endif
+ case 0x58: // PLT - packet length, tile-part header
+ // skipped
+ cover(41);
+ for (i = 0; i < segLen - 2; ++i) {
+ if (str->getChar() == EOF) {
+ error(getPos(), "Error in JPX PLT marker segment");
+ return gFalse;
+ }
+ }
+ break;
+ case 0x64: // COM - comment
+ // skipped
+ cover(42);
+ for (i = 0; i < segLen - 2; ++i) {
+ if (str->getChar() == EOF) {
+ error(getPos(), "Error in JPX COM marker segment");
+ return gFalse;
+ }
+ }
+ break;
+ case 0x93: // SOD - start of data
+ cover(43);
+ haveSOD = gTrue;
+ break;
+ default:
+ cover(44);
+ error(getPos(), "Unknown marker segment %02x in JPX tile-part stream",
+ segType);
+ for (i = 0; i < segLen - 2; ++i) {
+ if (str->getChar() == EOF) {
+ break;
+ }
+ }
+ break;
+ }
+ } while (!haveSOD);
+
+ //----- initialize the tile, precincts, and code-blocks
+ if (tilePartIdx == 0) {
+ tile = &img.tiles[tileIdx];
+ i = tileIdx / img.nXTiles;
+ j = tileIdx % img.nXTiles;
+ if ((tile->x0 = img.xTileOffset + j * img.xTileSize) < img.xOffset) {
+ tile->x0 = img.xOffset;
+ }
+ if ((tile->y0 = img.yTileOffset + i * img.yTileSize) < img.yOffset) {
+ tile->y0 = img.yOffset;
+ }
+ if ((tile->x1 = img.xTileOffset + (j + 1) * img.xTileSize) > img.xSize) {
+ tile->x1 = img.xSize;
+ }
+ if ((tile->y1 = img.yTileOffset + (i + 1) * img.yTileSize) > img.ySize) {
+ tile->y1 = img.ySize;
+ }
+ tile->comp = 0;
+ tile->res = 0;
+ tile->precinct = 0;
+ tile->layer = 0;
+ tile->maxNDecompLevels = 0;
+ for (comp = 0; comp < img.nComps; ++comp) {
+ tileComp = &tile->tileComps[comp];
+ if (tileComp->nDecompLevels > tile->maxNDecompLevels) {
+ tile->maxNDecompLevels = tileComp->nDecompLevels;
+ }
+ tileComp->x0 = jpxCeilDiv(tile->x0, tileComp->hSep);
+ tileComp->y0 = jpxCeilDiv(tile->y0, tileComp->hSep);
+ tileComp->x1 = jpxCeilDiv(tile->x1, tileComp->hSep);
+ tileComp->y1 = jpxCeilDiv(tile->y1, tileComp->hSep);
+ tileComp->cbW = 1 << tileComp->codeBlockW;
+ tileComp->cbH = 1 << tileComp->codeBlockH;
+ tileComp->data = (int *)gmallocn((tileComp->x1 - tileComp->x0) *
+ (tileComp->y1 - tileComp->y0),
+ sizeof(int));
+ if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) {
+ n = tileComp->x1 - tileComp->x0;
+ } else {
+ n = tileComp->y1 - tileComp->y0;
+ }
+ tileComp->buf = (int *)gmallocn(n + 8, sizeof(int));
+ for (r = 0; r <= tileComp->nDecompLevels; ++r) {
+ resLevel = &tileComp->resLevels[r];
+ k = r == 0 ? tileComp->nDecompLevels
+ : tileComp->nDecompLevels - r + 1;
+ resLevel->x0 = jpxCeilDivPow2(tileComp->x0, k);
+ resLevel->y0 = jpxCeilDivPow2(tileComp->y0, k);
+ resLevel->x1 = jpxCeilDivPow2(tileComp->x1, k);
+ resLevel->y1 = jpxCeilDivPow2(tileComp->y1, k);
+ if (r == 0) {
+ resLevel->bx0[0] = resLevel->x0;
+ resLevel->by0[0] = resLevel->y0;
+ resLevel->bx1[0] = resLevel->x1;
+ resLevel->by1[0] = resLevel->y1;
+ } else {
+ resLevel->bx0[0] = jpxCeilDivPow2(tileComp->x0 - (1 << (k-1)), k);
+ resLevel->by0[0] = resLevel->y0;
+ resLevel->bx1[0] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k);
+ resLevel->by1[0] = resLevel->y1;
+ resLevel->bx0[1] = resLevel->x0;
+ resLevel->by0[1] = jpxCeilDivPow2(tileComp->y0 - (1 << (k-1)), k);
+ resLevel->bx1[1] = resLevel->x1;
+ resLevel->by1[1] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k);
+ resLevel->bx0[2] = jpxCeilDivPow2(tileComp->x0 - (1 << (k-1)), k);
+ resLevel->by0[2] = jpxCeilDivPow2(tileComp->y0 - (1 << (k-1)), k);
+ resLevel->bx1[2] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k);
+ resLevel->by1[2] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k);
+ }
+ resLevel->precincts = (JPXPrecinct *)gmallocn(1, sizeof(JPXPrecinct));
+ for (pre = 0; pre < 1; ++pre) {
+ precinct = &resLevel->precincts[pre];
+ precinct->x0 = resLevel->x0;
+ precinct->y0 = resLevel->y0;
+ precinct->x1 = resLevel->x1;
+ precinct->y1 = resLevel->y1;
+ nSBs = r == 0 ? 1 : 3;
+ precinct->subbands =
+ (JPXSubband *)gmallocn(nSBs, sizeof(JPXSubband));
+ for (sb = 0; sb < nSBs; ++sb) {
+ subband = &precinct->subbands[sb];
+ subband->x0 = resLevel->bx0[sb];
+ subband->y0 = resLevel->by0[sb];
+ subband->x1 = resLevel->bx1[sb];
+ subband->y1 = resLevel->by1[sb];
+ subband->nXCBs = jpxCeilDivPow2(subband->x1,
+ tileComp->codeBlockW)
+ - jpxFloorDivPow2(subband->x0,
+ tileComp->codeBlockW);
+ subband->nYCBs = jpxCeilDivPow2(subband->y1,
+ tileComp->codeBlockH)
+ - jpxFloorDivPow2(subband->y0,
+ tileComp->codeBlockH);
+ n = subband->nXCBs > subband->nYCBs ? subband->nXCBs
+ : subband->nYCBs;
+ for (subband->maxTTLevel = 0, --n;
+ n;
+ ++subband->maxTTLevel, n >>= 1) ;
+ n = 0;
+ for (level = subband->maxTTLevel; level >= 0; --level) {
+ nx = jpxCeilDivPow2(subband->nXCBs, level);
+ ny = jpxCeilDivPow2(subband->nYCBs, level);
+ n += nx * ny;
+ }
+ subband->inclusion =
+ (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode));
+ subband->zeroBitPlane =
+ (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode));
+ for (k = 0; k < n; ++k) {
+ subband->inclusion[k].finished = gFalse;
+ subband->inclusion[k].val = 0;
+ subband->zeroBitPlane[k].finished = gFalse;
+ subband->zeroBitPlane[k].val = 0;
+ }
+ subband->cbs = (JPXCodeBlock *)gmallocn(subband->nXCBs *
+ subband->nYCBs,
+ sizeof(JPXCodeBlock));
+ sbx0 = jpxFloorDivPow2(subband->x0, tileComp->codeBlockW);
+ sby0 = jpxFloorDivPow2(subband->y0, tileComp->codeBlockH);
+ cb = subband->cbs;
+ for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
+ for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
+ cb->x0 = (sbx0 + cbX) << tileComp->codeBlockW;
+ cb->x1 = cb->x0 + tileComp->cbW;
+ if (subband->x0 > cb->x0) {
+ cb->x0 = subband->x0;
+ }
+ if (subband->x1 < cb->x1) {
+ cb->x1 = subband->x1;
+ }
+ cb->y0 = (sby0 + cbY) << tileComp->codeBlockH;
+ cb->y1 = cb->y0 + tileComp->cbH;
+ if (subband->y0 > cb->y0) {
+ cb->y0 = subband->y0;
+ }
+ if (subband->y1 < cb->y1) {
+ cb->y1 = subband->y1;
+ }
+ cb->seen = gFalse;
+ cb->lBlock = 3;
+ cb->nextPass = jpxPassCleanup;
+ cb->nZeroBitPlanes = 0;
+ cb->coeffs =
+ (JPXCoeff *)gmallocn((1 << (tileComp->codeBlockW
+ + tileComp->codeBlockH)),
+ sizeof(JPXCoeff));
+ for (cbi = 0;
+ cbi < (Guint)(1 << (tileComp->codeBlockW
+ + tileComp->codeBlockH));
+ ++cbi) {
+ cb->coeffs[cbi].flags = 0;
+ cb->coeffs[cbi].len = 0;
+ cb->coeffs[cbi].mag = 0;
+ }
+ cb->arithDecoder = NULL;
+ cb->stats = NULL;
+ ++cb;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return readTilePartData(tileIdx, tilePartLen, tilePartToEOC);
+}
+
+GBool JPXStream::readTilePartData(Guint tileIdx,
+ Guint tilePartLen, GBool tilePartToEOC) {
+ JPXTile *tile;
+ JPXTileComp *tileComp;
+ JPXResLevel *resLevel;
+ JPXPrecinct *precinct;
+ JPXSubband *subband;
+ JPXCodeBlock *cb;
+ Guint ttVal;
+ Guint bits, cbX, cbY, nx, ny, i, j, n, sb;
+ int level;
+
+ tile = &img.tiles[tileIdx];
+
+ // read all packets from this tile-part
+ while (1) {
+ if (tilePartToEOC) {
+ //~ peek for an EOC marker
+ cover(93);
+ } else if (tilePartLen == 0) {
+ break;
+ }
+
+ tileComp = &tile->tileComps[tile->comp];
+ resLevel = &tileComp->resLevels[tile->res];
+ precinct = &resLevel->precincts[tile->precinct];
+
+ //----- packet header
+
+ // setup
+ startBitBuf(tilePartLen);
+
+ // zero-length flag
+ if (!readBits(1, &bits)) {
+ goto err;
+ }
+ if (!bits) {
+ // packet is empty -- clear all code-block inclusion flags
+ cover(45);
+ for (sb = 0; sb < (Guint)(tile->res == 0 ? 1 : 3); ++sb) {
+ subband = &precinct->subbands[sb];
+ for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
+ for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
+ cb = &subband->cbs[cbY * subband->nXCBs + cbX];
+ cb->included = gFalse;
+ }
+ }
+ }
+ } else {
+
+ for (sb = 0; sb < (Guint)(tile->res == 0 ? 1 : 3); ++sb) {
+ subband = &precinct->subbands[sb];
+ for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
+ for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
+ cb = &subband->cbs[cbY * subband->nXCBs + cbX];
+
+ // skip code-blocks with no coefficients
+ if (cb->x0 >= cb->x1 || cb->y0 >= cb->y1) {
+ cover(46);
+ cb->included = gFalse;
+ continue;
+ }
+
+ // code-block inclusion
+ if (cb->seen) {
+ cover(47);
+ if (!readBits(1, &cb->included)) {
+ goto err;
+ }
+ } else {
+ cover(48);
+ ttVal = 0;
+ i = 0;
+ for (level = subband->maxTTLevel; level >= 0; --level) {
+ nx = jpxCeilDivPow2(subband->nXCBs, level);
+ ny = jpxCeilDivPow2(subband->nYCBs, level);
+ j = i + (cbY >> level) * nx + (cbX >> level);
+ if (!subband->inclusion[j].finished &&
+ !subband->inclusion[j].val) {
+ subband->inclusion[j].val = ttVal;
+ } else {
+ ttVal = subband->inclusion[j].val;
+ }
+ while (!subband->inclusion[j].finished &&
+ ttVal <= tile->layer) {
+ if (!readBits(1, &bits)) {
+ goto err;
+ }
+ if (bits == 1) {
+ subband->inclusion[j].finished = gTrue;
+ } else {
+ ++ttVal;
+ }
+ }
+ subband->inclusion[j].val = ttVal;
+ if (ttVal > tile->layer) {
+ break;
+ }
+ i += nx * ny;
+ }
+ cb->included = level < 0;
+ }
+
+ if (cb->included) {
+ cover(49);
+
+ // zero bit-plane count
+ if (!cb->seen) {
+ cover(50);
+ ttVal = 0;
+ i = 0;
+ for (level = subband->maxTTLevel; level >= 0; --level) {
+ nx = jpxCeilDivPow2(subband->nXCBs, level);
+ ny = jpxCeilDivPow2(subband->nYCBs, level);
+ j = i + (cbY >> level) * nx + (cbX >> level);
+ if (!subband->zeroBitPlane[j].finished &&
+ !subband->zeroBitPlane[j].val) {
+ subband->zeroBitPlane[j].val = ttVal;
+ } else {
+ ttVal = subband->zeroBitPlane[j].val;
+ }
+ while (!subband->zeroBitPlane[j].finished) {
+ if (!readBits(1, &bits)) {
+ goto err;
+ }
+ if (bits == 1) {
+ subband->zeroBitPlane[j].finished = gTrue;
+ } else {
+ ++ttVal;
+ }
+ }
+ subband->zeroBitPlane[j].val = ttVal;
+ i += nx * ny;
+ }
+ cb->nZeroBitPlanes = ttVal;
+ }
+
+ // number of coding passes
+ if (!readBits(1, &bits)) {
+ goto err;
+ }
+ if (bits == 0) {
+ cover(51);
+ cb->nCodingPasses = 1;
+ } else {
+ if (!readBits(1, &bits)) {
+ goto err;
+ }
+ if (bits == 0) {
+ cover(52);
+ cb->nCodingPasses = 2;
+ } else {
+ cover(53);
+ if (!readBits(2, &bits)) {
+ goto err;
+ }
+ if (bits < 3) {
+ cover(54);
+ cb->nCodingPasses = 3 + bits;
+ } else {
+ cover(55);
+ if (!readBits(5, &bits)) {
+ goto err;
+ }
+ if (bits < 31) {
+ cover(56);
+ cb->nCodingPasses = 6 + bits;
+ } else {
+ cover(57);
+ if (!readBits(7, &bits)) {
+ goto err;
+ }
+ cb->nCodingPasses = 37 + bits;
+ }
+ }
+ }
+ }
+
+ // update Lblock
+ while (1) {
+ if (!readBits(1, &bits)) {
+ goto err;
+ }
+ if (!bits) {
+ break;
+ }
+ ++cb->lBlock;
+ }
+
+ // length of compressed data
+ //~ deal with multiple codeword segments
+ for (n = cb->lBlock, i = cb->nCodingPasses >> 1;
+ i;
+ ++n, i >>= 1) ;
+ if (!readBits(n, &cb->dataLen)) {
+ goto err;
+ }
+ }
+ }
+ }
+ }
+ }
+ tilePartLen = finishBitBuf();
+
+ //----- packet data
+
+ for (sb = 0; sb < (Guint)(tile->res == 0 ? 1 : 3); ++sb) {
+ subband = &precinct->subbands[sb];
+ for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
+ for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
+ cb = &subband->cbs[cbY * subband->nXCBs + cbX];
+ if (cb->included) {
+ if (!readCodeBlockData(tileComp, resLevel, precinct, subband,
+ tile->res, sb, cb)) {
+ return gFalse;
+ }
+ tilePartLen -= cb->dataLen;
+ cb->seen = gTrue;
+ }
+ }
+ }
+ }
+
+ //----- next packet
+
+ switch (tile->progOrder) {
+ case 0: // layer, resolution level, component, precinct
+ cover(58);
+ if (++tile->comp == img.nComps) {
+ tile->comp = 0;
+ if (++tile->res == tile->maxNDecompLevels + 1) {
+ tile->res = 0;
+ if (++tile->layer == tile->nLayers) {
+ tile->layer = 0;
+ }
+ }
+ }
+ break;
+ case 1: // resolution level, layer, component, precinct
+ cover(59);
+ if (++tile->comp == img.nComps) {
+ tile->comp = 0;
+ if (++tile->layer == tile->nLayers) {
+ tile->layer = 0;
+ if (++tile->res == tile->maxNDecompLevels + 1) {
+ tile->res = 0;
+ }
+ }
+ }
+ break;
+ case 2: // resolution level, precinct, component, layer
+ //~ this isn't correct -- see B.12.1.3
+ cover(60);
+ if (++tile->layer == tile->nLayers) {
+ tile->layer = 0;
+ if (++tile->comp == img.nComps) {
+ tile->comp = 0;
+ if (++tile->res == tile->maxNDecompLevels + 1) {
+ tile->res = 0;
+ }
+ }
+ }
+ break;
+ case 3: // precinct, component, resolution level, layer
+ //~ this isn't correct -- see B.12.1.4
+ cover(61);
+ if (++tile->layer == tile->nLayers) {
+ tile->layer = 0;
+ if (++tile->res == tile->maxNDecompLevels + 1) {
+ tile->res = 0;
+ if (++tile->comp == img.nComps) {
+ tile->comp = 0;
+ }
+ }
+ }
+ break;
+ case 4: // component, precinct, resolution level, layer
+ //~ this isn't correct -- see B.12.1.5
+ cover(62);
+ if (++tile->layer == tile->nLayers) {
+ tile->layer = 0;
+ if (++tile->res == tile->maxNDecompLevels + 1) {
+ tile->res = 0;
+ if (++tile->comp == img.nComps) {
+ tile->comp = 0;
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ return gTrue;
+
+ err:
+ error(getPos(), "Error in JPX stream");
+ return gFalse;
+}
+
+GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp,
+ JPXResLevel * /*resLevel*/,
+ JPXPrecinct * /*precinct*/,
+ JPXSubband * /*subband*/,
+ Guint res, Guint sb,
+ JPXCodeBlock *cb) {
+ JPXCoeff *coeff0, *coeff1, *coeff;
+ Guint horiz, vert, diag, all, cx, xorBit;
+ int horizSign, vertSign;
+ Guint i, x, y0, y1, y2;
+
+ if (cb->arithDecoder) {
+ cover(63);
+ cb->arithDecoder->restart(cb->dataLen);
+ } else {
+ cover(64);
+ cb->arithDecoder = new JArithmeticDecoder();
+ cb->arithDecoder->setStream(str, cb->dataLen);
+ cb->arithDecoder->start();
+ cb->stats = new JArithmeticDecoderStats(jpxNContexts);
+ cb->stats->setEntry(jpxContextSigProp, 4, 0);
+ cb->stats->setEntry(jpxContextRunLength, 3, 0);
+ cb->stats->setEntry(jpxContextUniform, 46, 0);
+ }
+
+ for (i = 0; i < cb->nCodingPasses; ++i) {
+ switch (cb->nextPass) {
+
+ //----- significance propagation pass
+ case jpxPassSigProp:
+ cover(65);
+ for (y0 = cb->y0, coeff0 = cb->coeffs;
+ y0 < cb->y1;
+ y0 += 4, coeff0 += 4 << tileComp->codeBlockW) {
+ for (x = cb->x0, coeff1 = coeff0;
+ x < cb->x1;
+ ++x, ++coeff1) {
+ for (y1 = 0, coeff = coeff1;
+ y1 < 4 && y0+y1 < cb->y1;
+ ++y1, coeff += tileComp->cbW) {
+ if (!(coeff->flags & jpxCoeffSignificant)) {
+ horiz = vert = diag = 0;
+ horizSign = vertSign = 2;
+ if (x > cb->x0) {
+ if (coeff[-1].flags & jpxCoeffSignificant) {
+ ++horiz;
+ horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1;
+ }
+ if (y0+y1 > cb->y0) {
+ diag += (coeff[-(int)tileComp->cbW - 1].flags
+ >> jpxCoeffSignificantB) & 1;
+ }
+ if (y0+y1 < cb->y1 - 1) {
+ diag += (coeff[tileComp->cbW - 1].flags
+ >> jpxCoeffSignificantB) & 1;
+ }
+ }
+ if (x < cb->x1 - 1) {
+ if (coeff[1].flags & jpxCoeffSignificant) {
+ ++horiz;
+ horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1;
+ }
+ if (y0+y1 > cb->y0) {
+ diag += (coeff[-(int)tileComp->cbW + 1].flags
+ >> jpxCoeffSignificantB) & 1;
+ }
+ if (y0+y1 < cb->y1 - 1) {
+ diag += (coeff[tileComp->cbW + 1].flags
+ >> jpxCoeffSignificantB) & 1;
+ }
+ }
+ if (y0+y1 > cb->y0) {
+ if (coeff[-(int)tileComp->cbW].flags & jpxCoeffSignificant) {
+ ++vert;
+ vertSign += (coeff[-(int)tileComp->cbW].flags & jpxCoeffSign)
+ ? -1 : 1;
+ }
+ }
+ if (y0+y1 < cb->y1 - 1) {
+ if (coeff[tileComp->cbW].flags & jpxCoeffSignificant) {
+ ++vert;
+ vertSign += (coeff[tileComp->cbW].flags & jpxCoeffSign)
+ ? -1 : 1;
+ }
+ }
+ cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb];
+ if (cx != 0) {
+ if (cb->arithDecoder->decodeBit(cx, cb->stats)) {
+ coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef;
+ coeff->mag = (coeff->mag << 1) | 1;
+ cx = signContext[horizSign][vertSign][0];
+ xorBit = signContext[horizSign][vertSign][1];
+ if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
+ coeff->flags |= jpxCoeffSign;
+ }
+ }
+ ++coeff->len;
+ coeff->flags |= jpxCoeffTouched;
+ }
+ }
+ }
+ }
+ }
+ ++cb->nextPass;
+ break;
+
+ //----- magnitude refinement pass
+ case jpxPassMagRef:
+ cover(66);
+ for (y0 = cb->y0, coeff0 = cb->coeffs;
+ y0 < cb->y1;
+ y0 += 4, coeff0 += 4 << tileComp->codeBlockW) {
+ for (x = cb->x0, coeff1 = coeff0;
+ x < cb->x1;
+ ++x, ++coeff1) {
+ for (y1 = 0, coeff = coeff1;
+ y1 < 4 && y0+y1 < cb->y1;
+ ++y1, coeff += tileComp->cbW) {
+ if ((coeff->flags & jpxCoeffSignificant) &&
+ !(coeff->flags & jpxCoeffTouched)) {
+ if (coeff->flags & jpxCoeffFirstMagRef) {
+ all = 0;
+ if (x > cb->x0) {
+ all += (coeff[-1].flags >> jpxCoeffSignificantB) & 1;
+ if (y0+y1 > cb->y0) {
+ all += (coeff[-(int)tileComp->cbW - 1].flags
+ >> jpxCoeffSignificantB) & 1;
+ }
+ if (y0+y1 < cb->y1 - 1) {
+ all += (coeff[tileComp->cbW - 1].flags
+ >> jpxCoeffSignificantB) & 1;
+ }
+ }
+ if (x < cb->x1 - 1) {
+ all += (coeff[1].flags >> jpxCoeffSignificantB) & 1;
+ if (y0+y1 > cb->y0) {
+ all += (coeff[-(int)tileComp->cbW + 1].flags
+ >> jpxCoeffSignificantB) & 1;
+ }
+ if (y0+y1 < cb->y1 - 1) {
+ all += (coeff[tileComp->cbW + 1].flags
+ >> jpxCoeffSignificantB) & 1;
+ }
+ }
+ if (y0+y1 > cb->y0) {
+ all += (coeff[-(int)tileComp->cbW].flags
+ >> jpxCoeffSignificantB) & 1;
+ }
+ if (y0+y1 < cb->y1 - 1) {
+ all += (coeff[tileComp->cbW].flags
+ >> jpxCoeffSignificantB) & 1;
+ }
+ cx = all ? 15 : 14;
+ } else {
+ cx = 16;
+ }
+ coeff->mag = (coeff->mag << 1) |
+ cb->arithDecoder->decodeBit(cx, cb->stats);
+ ++coeff->len;
+ coeff->flags |= jpxCoeffTouched;
+ coeff->flags &= ~jpxCoeffFirstMagRef;
+ }
+ }
+ }
+ }
+ ++cb->nextPass;
+ break;
+
+ //----- cleanup pass
+ case jpxPassCleanup:
+ cover(67);
+ for (y0 = cb->y0, coeff0 = cb->coeffs;
+ y0 < cb->y1;
+ y0 += 4, coeff0 += 4 << tileComp->codeBlockW) {
+ for (x = cb->x0, coeff1 = coeff0;
+ x < cb->x1;
+ ++x, ++coeff1) {
+ y1 = 0;
+ if (y0 + 3 < cb->y1 &&
+ !(coeff1->flags & jpxCoeffTouched) &&
+ !(coeff1[tileComp->cbW].flags & jpxCoeffTouched) &&
+ !(coeff1[2 * tileComp->cbW].flags & jpxCoeffTouched) &&
+ !(coeff1[3 * tileComp->cbW].flags & jpxCoeffTouched) &&
+ (x == cb->x0 || y0 == cb->y0 ||
+ !(coeff1[-(int)tileComp->cbW - 1].flags
+ & jpxCoeffSignificant)) &&
+ (y0 == cb->y0 ||
+ !(coeff1[-(int)tileComp->cbW].flags
+ & jpxCoeffSignificant)) &&
+ (x == cb->x1 - 1 || y0 == cb->y0 ||
+ !(coeff1[-(int)tileComp->cbW + 1].flags
+ & jpxCoeffSignificant)) &&
+ (x == cb->x0 ||
+ (!(coeff1[-1].flags & jpxCoeffSignificant) &&
+ !(coeff1[tileComp->cbW - 1].flags
+ & jpxCoeffSignificant) &&
+ !(coeff1[2 * tileComp->cbW - 1].flags
+ & jpxCoeffSignificant) &&
+ !(coeff1[3 * tileComp->cbW - 1].flags
+ & jpxCoeffSignificant))) &&
+ (x == cb->x1 - 1 ||
+ (!(coeff1[1].flags & jpxCoeffSignificant) &&
+ !(coeff1[tileComp->cbW + 1].flags
+ & jpxCoeffSignificant) &&
+ !(coeff1[2 * tileComp->cbW + 1].flags
+ & jpxCoeffSignificant) &&
+ !(coeff1[3 * tileComp->cbW + 1].flags
+ & jpxCoeffSignificant))) &&
+ (x == cb->x0 || y0+4 == cb->y1 ||
+ !(coeff1[4 * tileComp->cbW - 1].flags & jpxCoeffSignificant)) &&
+ (y0+4 == cb->y1 ||
+ !(coeff1[4 * tileComp->cbW].flags & jpxCoeffSignificant)) &&
+ (x == cb->x1 - 1 || y0+4 == cb->y1 ||
+ !(coeff1[4 * tileComp->cbW + 1].flags
+ & jpxCoeffSignificant))) {
+ if (cb->arithDecoder->decodeBit(jpxContextRunLength, cb->stats)) {
+ y1 = cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats);
+ y1 = (y1 << 1) |
+ cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats);
+ for (y2 = 0, coeff = coeff1;
+ y2 < y1;
+ ++y2, coeff += tileComp->cbW) {
+ ++coeff->len;
+ }
+ coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef;
+ coeff->mag = (coeff->mag << 1) | 1;
+ ++coeff->len;
+ cx = signContext[2][2][0];
+ xorBit = signContext[2][2][1];
+ if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
+ coeff->flags |= jpxCoeffSign;
+ }
+ ++y1;
+ } else {
+ for (y1 = 0, coeff = coeff1;
+ y1 < 4;
+ ++y1, coeff += tileComp->cbW) {
+ ++coeff->len;
+ }
+ y1 = 4;
+ }
+ }
+ for (coeff = &coeff1[y1 << tileComp->codeBlockW];
+ y1 < 4 && y0 + y1 < cb->y1;
+ ++y1, coeff += tileComp->cbW) {
+ if (!(coeff->flags & jpxCoeffTouched)) {
+ horiz = vert = diag = 0;
+ horizSign = vertSign = 2;
+ if (x > cb->x0) {
+ if (coeff[-1].flags & jpxCoeffSignificant) {
+ ++horiz;
+ horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1;
+ }
+ if (y0+y1 > cb->y0) {
+ diag += (coeff[-(int)tileComp->cbW - 1].flags
+ >> jpxCoeffSignificantB) & 1;
+ }
+ if (y0+y1 < cb->y1 - 1) {
+ diag += (coeff[tileComp->cbW - 1].flags
+ >> jpxCoeffSignificantB) & 1;
+ }
+ }
+ if (x < cb->x1 - 1) {
+ if (coeff[1].flags & jpxCoeffSignificant) {
+ ++horiz;
+ horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1;
+ }
+ if (y0+y1 > cb->y0) {
+ diag += (coeff[-(int)tileComp->cbW + 1].flags
+ >> jpxCoeffSignificantB) & 1;
+ }
+ if (y0+y1 < cb->y1 - 1) {
+ diag += (coeff[tileComp->cbW + 1].flags
+ >> jpxCoeffSignificantB) & 1;
+ }
+ }
+ if (y0+y1 > cb->y0) {
+ if (coeff[-(int)tileComp->cbW].flags & jpxCoeffSignificant) {
+ ++vert;
+ vertSign += (coeff[-(int)tileComp->cbW].flags & jpxCoeffSign)
+ ? -1 : 1;
+ }
+ }
+ if (y0+y1 < cb->y1 - 1) {
+ if (coeff[tileComp->cbW].flags & jpxCoeffSignificant) {
+ ++vert;
+ vertSign += (coeff[tileComp->cbW].flags & jpxCoeffSign)
+ ? -1 : 1;
+ }
+ }
+ cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb];
+ if (cb->arithDecoder->decodeBit(cx, cb->stats)) {
+ coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef;
+ coeff->mag = (coeff->mag << 1) | 1;
+ cx = signContext[horizSign][vertSign][0];
+ xorBit = signContext[horizSign][vertSign][1];
+ if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) {
+ coeff->flags |= jpxCoeffSign;
+ }
+ }
+ ++coeff->len;
+ } else {
+ coeff->flags &= ~jpxCoeffTouched;
+ }
+ }
+ }
+ }
+ cb->nextPass = jpxPassSigProp;
+ break;
+ }
+ }
+
+ cb->arithDecoder->cleanup();
+ return gTrue;
+}
+
+// Inverse quantization, and wavelet transform (IDWT). This also does
+// the initial shift to convert to fixed point format.
+void JPXStream::inverseTransform(JPXTileComp *tileComp) {
+ JPXResLevel *resLevel;
+ JPXPrecinct *precinct;
+ JPXSubband *subband;
+ JPXCodeBlock *cb;
+ JPXCoeff *coeff0, *coeff;
+ Guint qStyle, guard, eps, shift;
+ int shift2;
+ double mu;
+ int val;
+ int *dataPtr;
+ Guint nx0, ny0, nx1, ny1;
+ Guint r, cbX, cbY, x, y;
+
+ cover(68);
+
+ //----- (NL)LL subband (resolution level 0)
+
+ resLevel = &tileComp->resLevels[0];
+ precinct = &resLevel->precincts[0];
+ subband = &precinct->subbands[0];
+
+ // i-quant parameters
+ qStyle = tileComp->quantStyle & 0x1f;
+ guard = (tileComp->quantStyle >> 5) & 7;
+ if (qStyle == 0) {
+ cover(69);
+ eps = (tileComp->quantSteps[0] >> 3) & 0x1f;
+ shift = guard + eps - 1;
+ mu = 0; // make gcc happy
+ } else {
+ cover(70);
+ shift = guard - 1 + tileComp->prec;
+ mu = (double)(0x800 + (tileComp->quantSteps[0] & 0x7ff)) / 2048.0;
+ }
+ if (tileComp->transform == 0) {
+ cover(71);
+ shift += fracBits;
+ }
+
+ // copy (NL)LL into the upper-left corner of the data array, doing
+ // the fixed point adjustment and dequantization along the way
+ cb = subband->cbs;
+ for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
+ for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
+ for (y = cb->y0, coeff0 = cb->coeffs;
+ y < cb->y1;
+ ++y, coeff0 += tileComp->cbW) {
+ dataPtr = &tileComp->data[(y - subband->y0)
+ * (tileComp->x1 - tileComp->x0)
+ + (cb->x0 - subband->x0)];
+ for (x = cb->x0, coeff = coeff0; x < cb->x1; ++x, ++coeff) {
+ val = (int)coeff->mag;
+ if (val != 0) {
+ shift2 = shift - (cb->nZeroBitPlanes + coeff->len);
+ if (shift2 > 0) {
+ cover(94);
+ val = (val << shift2) + (1 << (shift2 - 1));
+ } else {
+ cover(95);
+ val >>= -shift2;
+ }
+ if (qStyle == 0) {
+ cover(96);
+ if (tileComp->transform == 0) {
+ cover(97);
+ val &= -1 << fracBits;
+ }
+ } else {
+ cover(98);
+ val = (int)((double)val * mu);
+ }
+ if (coeff->flags & jpxCoeffSign) {
+ cover(99);
+ val = -val;
+ }
+ }
+ *dataPtr++ = val;
+ }
+ }
+ ++cb;
+ }
+ }
+
+ //----- IDWT for each level
+
+ for (r = 1; r <= tileComp->nDecompLevels; ++r) {
+ resLevel = &tileComp->resLevels[r];
+
+ // (n)LL is already in the upper-left corner of the
+ // tile-component data array -- interleave with (n)HL/LH/HH
+ // and inverse transform to get (n-1)LL, which will be stored
+ // in the upper-left corner of the tile-component data array
+ if (r == tileComp->nDecompLevels) {
+ cover(72);
+ nx0 = tileComp->x0;
+ ny0 = tileComp->y0;
+ nx1 = tileComp->x1;
+ ny1 = tileComp->y1;
+ } else {
+ cover(73);
+ nx0 = tileComp->resLevels[r+1].x0;
+ ny0 = tileComp->resLevels[r+1].y0;
+ nx1 = tileComp->resLevels[r+1].x1;
+ ny1 = tileComp->resLevels[r+1].y1;
+ }
+ inverseTransformLevel(tileComp, r, resLevel, nx0, ny0, nx1, ny1);
+ }
+}
+
+// Do one level of the inverse transform:
+// - take (n)LL from the tile-component data array
+// - take (n)HL/LH/HH from <resLevel>
+// - leave the resulting (n-1)LL in the tile-component data array
+void JPXStream::inverseTransformLevel(JPXTileComp *tileComp,
+ Guint r, JPXResLevel *resLevel,
+ Guint nx0, Guint ny0,
+ Guint nx1, Guint ny1) {
+ JPXPrecinct *precinct;
+ JPXSubband *subband;
+ JPXCodeBlock *cb;
+ JPXCoeff *coeff0, *coeff;
+ Guint qStyle, guard, eps, shift, t;
+ int shift2;
+ double mu;
+ int val;
+ int *dataPtr;
+ Guint xo, yo;
+ Guint x, y, sb, cbX, cbY;
+ int xx, yy;
+
+ //----- interleave
+
+ // spread out LL
+ for (yy = resLevel->y1 - 1; yy >= (int)resLevel->y0; --yy) {
+ for (xx = resLevel->x1 - 1; xx >= (int)resLevel->x0; --xx) {
+ tileComp->data[(2 * yy - ny0) * (tileComp->x1 - tileComp->x0)
+ + (2 * xx - nx0)] =
+ tileComp->data[(yy - resLevel->y0) * (tileComp->x1 - tileComp->x0)
+ + (xx - resLevel->x0)];
+ }
+ }
+
+ // i-quant parameters
+ qStyle = tileComp->quantStyle & 0x1f;
+ guard = (tileComp->quantStyle >> 5) & 7;
+
+ // interleave HL/LH/HH
+ precinct = &resLevel->precincts[0];
+ for (sb = 0; sb < 3; ++sb) {
+
+ // i-quant parameters
+ if (qStyle == 0) {
+ cover(100);
+ eps = (tileComp->quantSteps[3*r - 2 + sb] >> 3) & 0x1f;
+ shift = guard + eps - 1;
+ mu = 0; // make gcc happy
+ } else {
+ cover(101);
+ shift = guard + tileComp->prec;
+ if (sb == 2) {
+ cover(102);
+ ++shift;
+ }
+ t = tileComp->quantSteps[qStyle == 1 ? 0 : (3*r - 2 + sb)];
+ mu = (double)(0x800 + (t & 0x7ff)) / 2048.0;
+ }
+ if (tileComp->transform == 0) {
+ cover(103);
+ shift += fracBits;
+ }
+
+ // copy the subband coefficients into the data array, doing the
+ // fixed point adjustment and dequantization along the way
+ xo = (sb & 1) ? 0 : 1;
+ yo = (sb > 0) ? 1 : 0;
+ subband = &precinct->subbands[sb];
+ cb = subband->cbs;
+ for (cbY = 0; cbY < subband->nYCBs; ++cbY) {
+ for (cbX = 0; cbX < subband->nXCBs; ++cbX) {
+ for (y = cb->y0, coeff0 = cb->coeffs;
+ y < cb->y1;
+ ++y, coeff0 += tileComp->cbW) {
+ dataPtr = &tileComp->data[(2 * y + yo - ny0)
+ * (tileComp->x1 - tileComp->x0)
+ + (2 * cb->x0 + xo - nx0)];
+ for (x = cb->x0, coeff = coeff0; x < cb->x1; ++x, ++coeff) {
+ val = (int)coeff->mag;
+ if (val != 0) {
+ shift2 = shift - (cb->nZeroBitPlanes + coeff->len);
+ if (shift2 > 0) {
+ cover(74);
+ val = (val << shift2) + (1 << (shift2 - 1));
+ } else {
+ cover(75);
+ val >>= -shift2;
+ }
+ if (qStyle == 0) {
+ cover(76);
+ if (tileComp->transform == 0) {
+ val &= -1 << fracBits;
+ }
+ } else {
+ cover(77);
+ val = (int)((double)val * mu);
+ }
+ if (coeff->flags & jpxCoeffSign) {
+ cover(78);
+ val = -val;
+ }
+ }
+ *dataPtr = val;
+ dataPtr += 2;
+ }
+ }
+ ++cb;
+ }
+ }
+ }
+
+ //----- horizontal (row) transforms
+ dataPtr = tileComp->data;
+ for (y = 0; y < ny1 - ny0; ++y) {
+ inverseTransform1D(tileComp, dataPtr, 1, nx0, nx1);
+ dataPtr += tileComp->x1 - tileComp->x0;
+ }
+
+ //----- vertical (column) transforms
+ dataPtr = tileComp->data;
+ for (x = 0; x < nx1 - nx0; ++x) {
+ inverseTransform1D(tileComp, dataPtr,
+ tileComp->x1 - tileComp->x0, ny0, ny1);
+ ++dataPtr;
+ }
+}
+
+void JPXStream::inverseTransform1D(JPXTileComp *tileComp,
+ int *data, Guint stride,
+ Guint i0, Guint i1) {
+ int *buf;
+ Guint offset, end, i;
+
+ //----- special case for length = 1
+ if (i1 - i0 == 1) {
+ cover(79);
+ if (i0 & 1) {
+ cover(104);
+ *data >>= 1;
+ }
+
+ } else {
+ cover(80);
+
+ // choose an offset: this makes even buf[] indexes correspond to
+ // odd values of i, and vice versa
+ offset = 3 + (i0 & 1);
+ end = offset + i1 - i0;
+
+ //----- gather
+ buf = tileComp->buf;
+ for (i = 0; i < i1 - i0; ++i) {
+ buf[offset + i] = data[i * stride];
+ }
+
+ //----- extend right
+ buf[end] = buf[end - 2];
+ if (i1 - i0 == 2) {
+ cover(81);
+ buf[end+1] = buf[offset + 1];
+ buf[end+2] = buf[offset];
+ buf[end+3] = buf[offset + 1];
+ } else {
+ cover(82);
+ buf[end+1] = buf[end - 3];
+ if (i1 - i0 == 3) {
+ cover(105);
+ buf[end+2] = buf[offset + 1];
+ buf[end+3] = buf[offset + 2];
+ } else {
+ cover(106);
+ buf[end+2] = buf[end - 4];
+ if (i1 - i0 == 4) {
+ cover(107);
+ buf[end+3] = buf[offset + 1];
+ } else {
+ cover(108);
+ buf[end+3] = buf[end - 5];
+ }
+ }
+ }
+
+ //----- extend left
+ buf[offset - 1] = buf[offset + 1];
+ buf[offset - 2] = buf[offset + 2];
+ buf[offset - 3] = buf[offset + 3];
+ if (offset == 4) {
+ cover(83);
+ buf[0] = buf[offset + 4];
+ }
+
+ //----- 9-7 irreversible filter
+
+ if (tileComp->transform == 0) {
+ cover(84);
+ // step 1 (even)
+ for (i = 1; i <= end + 2; i += 2) {
+ buf[i] = (int)(idwtKappa * buf[i]);
+ }
+ // step 2 (odd)
+ for (i = 0; i <= end + 3; i += 2) {
+ buf[i] = (int)(idwtIKappa * buf[i]);
+ }
+ // step 3 (even)
+ for (i = 1; i <= end + 2; i += 2) {
+ buf[i] = (int)(buf[i] - idwtDelta * (buf[i-1] + buf[i+1]));
+ }
+ // step 4 (odd)
+ for (i = 2; i <= end + 1; i += 2) {
+ buf[i] = (int)(buf[i] - idwtGamma * (buf[i-1] + buf[i+1]));
+ }
+ // step 5 (even)
+ for (i = 3; i <= end; i += 2) {
+ buf[i] = (int)(buf[i] - idwtBeta * (buf[i-1] + buf[i+1]));
+ }
+ // step 6 (odd)
+ for (i = 4; i <= end - 1; i += 2) {
+ buf[i] = (int)(buf[i] - idwtAlpha * (buf[i-1] + buf[i+1]));
+ }
+
+ //----- 5-3 reversible filter
+
+ } else {
+ cover(85);
+ // step 1 (even)
+ for (i = 3; i <= end; i += 2) {
+ buf[i] -= (buf[i-1] + buf[i+1] + 2) >> 2;
+ }
+ // step 2 (odd)
+ for (i = 4; i < end; i += 2) {
+ buf[i] += (buf[i-1] + buf[i+1]) >> 1;
+ }
+ }
+
+ //----- scatter
+ for (i = 0; i < i1 - i0; ++i) {
+ data[i * stride] = buf[offset + i];
+ }
+ }
+}
+
+// Inverse multi-component transform and DC level shift. This also
+// converts fixed point samples back to integers.
+GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) {
+ JPXTileComp *tileComp;
+ int coeff, d0, d1, d2, t, minVal, maxVal, zeroVal;
+ int *dataPtr;
+ Guint j, comp, x, y;
+
+ //----- inverse multi-component transform
+
+ if (tile->multiComp == 1) {
+ cover(86);
+ if (img.nComps < 3 ||
+ tile->tileComps[0].hSep != tile->tileComps[1].hSep ||
+ tile->tileComps[0].vSep != tile->tileComps[1].vSep ||
+ tile->tileComps[1].hSep != tile->tileComps[2].hSep ||
+ tile->tileComps[1].vSep != tile->tileComps[2].vSep) {
+ return gFalse;
+ }
+
+ // inverse irreversible multiple component transform
+ if (tile->tileComps[0].transform == 0) {
+ cover(87);
+ j = 0;
+ for (y = 0; y < tile->tileComps[0].y1 - tile->tileComps[0].y0; ++y) {
+ for (x = 0; x < tile->tileComps[0].x1 - tile->tileComps[0].x0; ++x) {
+ d0 = tile->tileComps[0].data[j];
+ d1 = tile->tileComps[1].data[j];
+ d2 = tile->tileComps[2].data[j];
+ tile->tileComps[0].data[j] = (int)(d0 + 1.402 * d2 + 0.5);
+ tile->tileComps[1].data[j] =
+ (int)(d0 - 0.34413 * d1 - 0.71414 * d2 + 0.5);
+ tile->tileComps[2].data[j] = (int)(d0 + 1.772 * d1 + 0.5);
+ ++j;
+ }
+ }
+
+ // inverse reversible multiple component transform
+ } else {
+ cover(88);
+ j = 0;
+ for (y = 0; y < tile->tileComps[0].y1 - tile->tileComps[0].y0; ++y) {
+ for (x = 0; x < tile->tileComps[0].x1 - tile->tileComps[0].x0; ++x) {
+ d0 = tile->tileComps[0].data[j];
+ d1 = tile->tileComps[1].data[j];
+ d2 = tile->tileComps[2].data[j];
+ tile->tileComps[1].data[j] = t = d0 - ((d2 + d1) >> 2);
+ tile->tileComps[0].data[j] = d2 + t;
+ tile->tileComps[2].data[j] = d1 + t;
+ ++j;
+ }
+ }
+ }
+ }
+
+ //----- DC level shift
+ for (comp = 0; comp < img.nComps; ++comp) {
+ tileComp = &tile->tileComps[comp];
+
+ // signed: clip
+ if (tileComp->sgned) {
+ cover(89);
+ minVal = -(1 << (tileComp->prec - 1));
+ maxVal = (1 << (tileComp->prec - 1)) - 1;
+ dataPtr = tileComp->data;
+ for (y = 0; y < tileComp->y1 - tileComp->y0; ++y) {
+ for (x = 0; x < tileComp->x1 - tileComp->x0; ++x) {
+ coeff = *dataPtr;
+ if (tileComp->transform == 0) {
+ cover(109);
+ coeff >>= fracBits;
+ }
+ if (coeff < minVal) {
+ cover(110);
+ coeff = minVal;
+ } else if (coeff > maxVal) {
+ cover(111);
+ coeff = maxVal;
+ }
+ *dataPtr++ = coeff;
+ }
+ }
+
+ // unsigned: inverse DC level shift and clip
+ } else {
+ cover(90);
+ maxVal = (1 << tileComp->prec) - 1;
+ zeroVal = 1 << (tileComp->prec - 1);
+ dataPtr = tileComp->data;
+ for (y = 0; y < tileComp->y1 - tileComp->y0; ++y) {
+ for (x = 0; x < tileComp->x1 - tileComp->x0; ++x) {
+ coeff = *dataPtr;
+ if (tileComp->transform == 0) {
+ cover(112);
+ coeff >>= fracBits;
+ }
+ coeff += zeroVal;
+ if (coeff < 0) {
+ cover(113);
+ coeff = 0;
+ } else if (coeff > maxVal) {
+ cover(114);
+ coeff = maxVal;
+ }
+ *dataPtr++ = coeff;
+ }
+ }
+ }
+ }
+
+ return gTrue;
+}
+
+GBool JPXStream::readBoxHdr(Guint *boxType, Guint *boxLen, Guint *dataLen) {
+ Guint len, lenH;
+
+ if (!readULong(&len) ||
+ !readULong(boxType)) {
+ return gFalse;
+ }
+ if (len == 1) {
+ if (!readULong(&lenH) || !readULong(&len)) {
+ return gFalse;
+ }
+ if (lenH) {
+ error(getPos(), "JPX stream contains a box larger than 2^32 bytes");
+ return gFalse;
+ }
+ *boxLen = len;
+ *dataLen = len - 16;
+ } else if (len == 0) {
+ *boxLen = 0;
+ *dataLen = 0;
+ } else {
+ *boxLen = len;
+ *dataLen = len - 8;
+ }
+ return gTrue;
+}
+
+int JPXStream::readMarkerHdr(int *segType, Guint *segLen) {
+ int c;
+
+ do {
+ do {
+ if ((c = str->getChar()) == EOF) {
+ return gFalse;
+ }
+ } while (c != 0xff);
+ do {
+ if ((c = str->getChar()) == EOF) {
+ return gFalse;
+ }
+ } while (c == 0xff);
+ } while (c == 0x00);
+ *segType = c;
+ if ((c >= 0x30 && c <= 0x3f) ||
+ c == 0x4f || c == 0x92 || c == 0x93 || c == 0xd9) {
+ *segLen = 0;
+ return gTrue;
+ }
+ return readUWord(segLen);
+}
+
+GBool JPXStream::readUByte(Guint *x) {
+ int c0;
+
+ if ((c0 = str->getChar()) == EOF) {
+ return gFalse;
+ }
+ *x = (Guint)c0;
+ return gTrue;
+}
+
+GBool JPXStream::readByte(int *x) {
+ int c0;
+
+ if ((c0 = str->getChar()) == EOF) {
+ return gFalse;
+ }
+ *x = c0;
+ if (c0 & 0x80) {
+ *x |= -1 - 0xff;
+ }
+ return gTrue;
+}
+
+GBool JPXStream::readUWord(Guint *x) {
+ int c0, c1;
+
+ if ((c0 = str->getChar()) == EOF ||
+ (c1 = str->getChar()) == EOF) {
+ return gFalse;
+ }
+ *x = (Guint)((c0 << 8) | c1);
+ return gTrue;
+}
+
+GBool JPXStream::readULong(Guint *x) {
+ int c0, c1, c2, c3;
+
+ if ((c0 = str->getChar()) == EOF ||
+ (c1 = str->getChar()) == EOF ||
+ (c2 = str->getChar()) == EOF ||
+ (c3 = str->getChar()) == EOF) {
+ return gFalse;
+ }
+ *x = (Guint)((c0 << 24) | (c1 << 16) | (c2 << 8) | c3);
+ return gTrue;
+}
+
+GBool JPXStream::readNBytes(int nBytes, GBool signd, int *x) {
+ int y, c, i;
+
+ y = 0;
+ for (i = 0; i < nBytes; ++i) {
+ if ((c = str->getChar()) == EOF) {
+ return gFalse;
+ }
+ y = (y << 8) + c;
+ }
+ if (signd) {
+ if (y & (1 << (8 * nBytes - 1))) {
+ y |= -1 << (8 * nBytes);
+ }
+ }
+ *x = y;
+ return gTrue;
+}
+
+GBool JPXStream::readBits(int nBits, Guint *x) {
+ int c;
+
+ while (bitBufLen < nBits) {
+ if (byteCount == 0 || (c = str->getChar()) == EOF) {
+ return gFalse;
+ }
+ --byteCount;
+ if (bitBufSkip) {
+ bitBuf = (bitBuf << 7) | (c & 0x7f);
+ bitBufLen += 7;
+ } else {
+ bitBuf = (bitBuf << 8) | (c & 0xff);
+ bitBufLen += 8;
+ }
+ bitBufSkip = c == 0xff;
+ }
+ *x = (bitBuf >> (bitBufLen - nBits)) & ((1 << nBits) - 1);
+ bitBufLen -= nBits;
+ return gTrue;
+}
+
+void JPXStream::startBitBuf(Guint byteCountA) {
+ bitBufLen = 0;
+ bitBufSkip = gFalse;
+ byteCount = byteCountA;
+}
+
+Guint JPXStream::finishBitBuf() {
+ if (bitBufSkip) {
+ str->getChar();
+ --byteCount;
+ }
+ return byteCount;
+}
diff --git a/kpdf/xpdf/xpdf/JPXStream.h b/kpdf/xpdf/xpdf/JPXStream.h
new file mode 100644
index 00000000..e96e7d38
--- /dev/null
+++ b/kpdf/xpdf/xpdf/JPXStream.h
@@ -0,0 +1,351 @@
+//========================================================================
+//
+// JPXStream.h
+//
+// Copyright 2002-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef JPXSTREAM_H
+#define JPXSTREAM_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "Object.h"
+#include "Stream.h"
+
+class JArithmeticDecoder;
+class JArithmeticDecoderStats;
+
+//------------------------------------------------------------------------
+
+enum JPXColorSpaceType {
+ jpxCSBiLevel = 0,
+ jpxCSYCbCr1 = 1,
+ jpxCSYCbCr2 = 3,
+ jpxCSYCBCr3 = 4,
+ jpxCSPhotoYCC = 9,
+ jpxCSCMY = 11,
+ jpxCSCMYK = 12,
+ jpxCSYCCK = 13,
+ jpxCSCIELab = 14,
+ jpxCSsRGB = 16,
+ jpxCSGrayscale = 17,
+ jpxCSBiLevel2 = 18,
+ jpxCSCIEJab = 19,
+ jpxCSCISesRGB = 20,
+ jpxCSROMMRGB = 21,
+ jpxCSsRGBYCbCr = 22,
+ jpxCSYPbPr1125 = 23,
+ jpxCSYPbPr1250 = 24
+};
+
+struct JPXColorSpecCIELab {
+ Guint rl, ol, ra, oa, rb, ob, il;
+};
+
+struct JPXColorSpecEnumerated {
+ JPXColorSpaceType type; // color space type
+ union {
+ JPXColorSpecCIELab cieLab;
+ };
+};
+
+struct JPXColorSpec {
+ Guint meth; // method
+ int prec; // precedence
+ union {
+ JPXColorSpecEnumerated enumerated;
+ };
+};
+
+//------------------------------------------------------------------------
+
+struct JPXPalette {
+ Guint nEntries; // number of entries in the palette
+ Guint nComps; // number of components in each entry
+ Guint *bpc; // bits per component, for each component
+ int *c; // color data:
+ // c[i*nComps+j] = entry i, component j
+};
+
+//------------------------------------------------------------------------
+
+struct JPXCompMap {
+ Guint nChannels; // number of channels
+ Guint *comp; // codestream components mapped to each channel
+ Guint *type; // 0 for direct use, 1 for palette mapping
+ Guint *pComp; // palette components to use
+};
+
+//------------------------------------------------------------------------
+
+struct JPXChannelDefn {
+ Guint nChannels; // number of channels
+ Guint *idx; // channel indexes
+ Guint *type; // channel types
+ Guint *assoc; // channel associations
+};
+
+//------------------------------------------------------------------------
+
+struct JPXTagTreeNode {
+ GBool finished; // true if this node is finished
+ Guint val; // current value
+};
+
+//------------------------------------------------------------------------
+
+struct JPXCoeff {
+ Gushort flags; // flag bits
+ Gushort len; // number of significant bits in mag
+ Guint mag; // magnitude value
+};
+
+// coefficient flags
+#define jpxCoeffSignificantB 0
+#define jpxCoeffTouchedB 1
+#define jpxCoeffFirstMagRefB 2
+#define jpxCoeffSignB 7
+#define jpxCoeffSignificant (1 << jpxCoeffSignificantB)
+#define jpxCoeffTouched (1 << jpxCoeffTouchedB)
+#define jpxCoeffFirstMagRef (1 << jpxCoeffFirstMagRefB)
+#define jpxCoeffSign (1 << jpxCoeffSignB)
+
+//------------------------------------------------------------------------
+
+struct JPXCodeBlock {
+ //----- size
+ Guint x0, y0, x1, y1; // bounds
+
+ //----- persistent state
+ GBool seen; // true if this code-block has already
+ // been seen
+ Guint lBlock; // base number of bits used for pkt data length
+ Guint nextPass; // next coding pass
+
+ //---- info from first packet
+ Guint nZeroBitPlanes; // number of zero bit planes
+
+ //----- info for the current packet
+ Guint included; // code-block inclusion in this packet:
+ // 0=not included, 1=included
+ Guint nCodingPasses; // number of coding passes in this pkt
+ Guint dataLen; // pkt data length
+
+ //----- coefficient data
+ JPXCoeff *coeffs; // the coefficients
+ JArithmeticDecoder // arithmetic decoder
+ *arithDecoder;
+ JArithmeticDecoderStats // arithmetic decoder stats
+ *stats;
+};
+
+//------------------------------------------------------------------------
+
+struct JPXSubband {
+ //----- computed
+ Guint x0, y0, x1, y1; // bounds
+ Guint nXCBs, nYCBs; // number of code-blocks in the x and y
+ // directions
+
+ //----- tag trees
+ Guint maxTTLevel; // max tag tree level
+ JPXTagTreeNode *inclusion; // inclusion tag tree for each subband
+ JPXTagTreeNode *zeroBitPlane; // zero-bit plane tag tree for each
+ // subband
+
+ //----- children
+ JPXCodeBlock *cbs; // the code-blocks (len = nXCBs * nYCBs)
+};
+
+//------------------------------------------------------------------------
+
+struct JPXPrecinct {
+ //----- computed
+ Guint x0, y0, x1, y1; // bounds of the precinct
+
+ //----- children
+ JPXSubband *subbands; // the subbands
+};
+
+//------------------------------------------------------------------------
+
+struct JPXResLevel {
+ //----- from the COD and COC segments (main and tile)
+ Guint precinctWidth; // log2(precinct width)
+ Guint precinctHeight; // log2(precinct height)
+
+ //----- computed
+ Guint x0, y0, x1, y1; // bounds of the tile-comp (for this res level)
+ Guint bx0[3], by0[3], // subband bounds
+ bx1[3], by1[3];
+
+ //---- children
+ JPXPrecinct *precincts; // the precincts
+};
+
+//------------------------------------------------------------------------
+
+struct JPXTileComp {
+ //----- from the SIZ segment
+ GBool sgned; // 1 for signed, 0 for unsigned
+ Guint prec; // precision, in bits
+ Guint hSep; // horizontal separation of samples
+ Guint vSep; // vertical separation of samples
+
+ //----- from the COD and COC segments (main and tile)
+ Guint style; // coding style parameter (Scod / Scoc)
+ Guint nDecompLevels; // number of decomposition levels
+ Guint codeBlockW; // log2(code-block width)
+ Guint codeBlockH; // log2(code-block height)
+ Guint codeBlockStyle; // code-block style
+ Guint transform; // wavelet transformation
+
+ //----- from the QCD and QCC segments (main and tile)
+ Guint quantStyle; // quantization style
+ Guint *quantSteps; // quantization step size for each subband
+ Guint nQuantSteps; // number of entries in quantSteps
+
+ //----- computed
+ Guint x0, y0, x1, y1; // bounds of the tile-comp, in ref coords
+ Guint cbW; // code-block width
+ Guint cbH; // code-block height
+
+ //----- image data
+ int *data; // the decoded image data
+ int *buf; // intermediate buffer for the inverse
+ // transform
+
+ //----- children
+ JPXResLevel *resLevels; // the resolution levels
+ // (len = nDecompLevels + 1)
+};
+
+//------------------------------------------------------------------------
+
+struct JPXTile {
+ //----- from the COD segments (main and tile)
+ Guint progOrder; // progression order
+ Guint nLayers; // number of layers
+ Guint multiComp; // multiple component transformation
+
+ //----- computed
+ Guint x0, y0, x1, y1; // bounds of the tile, in ref coords
+ Guint maxNDecompLevels; // max number of decomposition levels used
+ // in any component in this tile
+
+ //----- progression order loop counters
+ Guint comp; // component
+ Guint res; // resolution level
+ Guint precinct; // precinct
+ Guint layer; // layer
+
+ //----- children
+ JPXTileComp *tileComps; // the tile-components (len = JPXImage.nComps)
+};
+
+//------------------------------------------------------------------------
+
+struct JPXImage {
+ //----- from the SIZ segment
+ Guint xSize, ySize; // size of reference grid
+ Guint xOffset, yOffset; // image offset
+ Guint xTileSize, yTileSize; // size of tiles
+ Guint xTileOffset, // offset of first tile
+ yTileOffset;
+ Guint nComps; // number of components
+
+ //----- computed
+ Guint nXTiles; // number of tiles in x direction
+ Guint nYTiles; // number of tiles in y direction
+
+ //----- children
+ JPXTile *tiles; // the tiles (len = nXTiles * nYTiles)
+};
+
+//------------------------------------------------------------------------
+
+class JPXStream: public FilterStream {
+public:
+
+ JPXStream(Stream *strA);
+ virtual ~JPXStream();
+ virtual StreamKind getKind() { return strJPX; }
+ virtual void reset();
+ virtual void close();
+ virtual int getChar();
+ virtual int lookChar();
+ virtual GString *getPSFilter(int psLevel, char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+ virtual void getImageParams(int *bitsPerComponent,
+ StreamColorSpaceMode *csMode);
+
+private:
+
+ void fillReadBuf();
+ void getImageParams2(int *bitsPerComponent, StreamColorSpaceMode *csMode);
+ GBool readBoxes();
+ GBool readColorSpecBox(Guint dataLen);
+ GBool readCodestream(Guint len);
+ GBool readTilePart();
+ GBool readTilePartData(Guint tileIdx,
+ Guint tilePartLen, GBool tilePartToEOC);
+ GBool readCodeBlockData(JPXTileComp *tileComp,
+ JPXResLevel *resLevel,
+ JPXPrecinct *precinct,
+ JPXSubband *subband,
+ Guint res, Guint sb,
+ JPXCodeBlock *cb);
+ void inverseTransform(JPXTileComp *tileComp);
+ void inverseTransformLevel(JPXTileComp *tileComp,
+ Guint r, JPXResLevel *resLevel,
+ Guint nx0, Guint ny0,
+ Guint nx1, Guint ny1);
+ void inverseTransform1D(JPXTileComp *tileComp,
+ int *data, Guint stride,
+ Guint i0, Guint i1);
+ GBool inverseMultiCompAndDC(JPXTile *tile);
+ GBool readBoxHdr(Guint *boxType, Guint *boxLen, Guint *dataLen);
+ int readMarkerHdr(int *segType, Guint *segLen);
+ GBool readUByte(Guint *x);
+ GBool readByte(int *x);
+ GBool readUWord(Guint *x);
+ GBool readULong(Guint *x);
+ GBool readNBytes(int nBytes, GBool signd, int *x);
+ GBool readBits(int nBits, Guint *x);
+ void startBitBuf(Guint byteCountA);
+ Guint finishBitBuf();
+
+ Guint nComps; // number of components
+ Guint *bpc; // bits per component, for each component
+ Guint width, height; // image size
+ GBool haveImgHdr; // set if a JP2/JPX image header has been
+ // found
+ JPXColorSpec cs; // color specification
+ GBool haveCS; // set if a color spec has been found
+ JPXPalette palette; // the palette
+ GBool havePalette; // set if a palette has been found
+ JPXCompMap compMap; // the component mapping
+ GBool haveCompMap; // set if a component mapping has been found
+ JPXChannelDefn channelDefn; // channel definition
+ GBool haveChannelDefn; // set if a channel defn has been found
+
+ JPXImage img; // JPEG2000 decoder data
+ Guint bitBuf; // buffer for bit reads
+ int bitBufLen; // number of bits in bitBuf
+ GBool bitBufSkip; // true if next bit should be skipped
+ // (for bit stuffing)
+ Guint byteCount; // number of available bytes left
+
+ Guint curX, curY, curComp; // current position for lookChar/getChar
+ Guint readBuf; // read buffer
+ Guint readBufLen; // number of valid bits in readBuf
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/Lexer.cc b/kpdf/xpdf/xpdf/Lexer.cc
new file mode 100644
index 00000000..1ef37175
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Lexer.cc
@@ -0,0 +1,521 @@
+//========================================================================
+//
+// Lexer.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <ctype.h>
+#include "Lexer.h"
+#include "Error.h"
+#include "XRef.h"
+
+//------------------------------------------------------------------------
+
+// A '1' in this array means the character is white space. A '1' or
+// '2' means the character ends a name or command.
+static char specialChars[256] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
+ 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx
+};
+
+//------------------------------------------------------------------------
+// Lexer
+//------------------------------------------------------------------------
+
+Lexer::Lexer(XRef *xrefA, Stream *str) {
+ Object obj;
+
+ xref = xrefA;
+
+ curStr.initStream(str);
+ streams = new Array(xref);
+ streams->add(curStr.copy(&obj));
+ strPtr = 0;
+ freeArray = gTrue;
+ curStr.streamReset();
+}
+
+Lexer::Lexer(XRef *xrefA, Object *obj) {
+ Object obj2;
+
+ xref = xrefA;
+
+ if (obj->isStream()) {
+ streams = new Array(xref);
+ freeArray = gTrue;
+ streams->add(obj->copy(&obj2));
+ } else {
+ streams = obj->getArray();
+ freeArray = gFalse;
+ }
+ strPtr = 0;
+ if (streams->getLength() > 0) {
+ streams->get(strPtr, &curStr);
+ curStr.streamReset();
+ }
+}
+
+Lexer::~Lexer() {
+ if (!curStr.isNone()) {
+ curStr.streamClose();
+ curStr.free();
+ }
+ if (freeArray) {
+ delete streams;
+ }
+}
+
+int Lexer::getChar() {
+ int c;
+
+ c = EOF;
+ while (!curStr.isNone() && (c = curStr.streamGetChar()) == EOF) {
+ curStr.streamClose();
+ curStr.free();
+ ++strPtr;
+ if (strPtr < streams->getLength()) {
+ streams->get(strPtr, &curStr);
+ curStr.streamReset();
+ }
+ }
+ return c;
+}
+
+int Lexer::lookChar() {
+ if (curStr.isNone()) {
+ return EOF;
+ }
+ return curStr.streamLookChar();
+}
+
+Object *Lexer::getObj(Object *obj, int objNum) {
+ char *p;
+ int c, c2;
+ GBool comment, neg, done;
+ int numParen;
+ int xi;
+ double xf, scale;
+ GString *s;
+ int n, m;
+
+ // skip whitespace and comments
+ comment = gFalse;
+ while (1) {
+ if ((c = getChar()) == EOF) {
+ return obj->initEOF();
+ }
+ if (comment) {
+ if (c == '\r' || c == '\n')
+ comment = gFalse;
+ } else if (c == '%') {
+ comment = gTrue;
+ } else if (specialChars[c] != 1) {
+ break;
+ }
+ }
+
+ // start reading token
+ switch (c) {
+
+ // number
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case '-': case '.':
+ neg = gFalse;
+ xi = 0;
+ if (c == '-') {
+ neg = gTrue;
+ } else if (c == '.') {
+ goto doReal;
+ } else {
+ xi = c - '0';
+ }
+ while (1) {
+ c = lookChar();
+ if (isdigit(c)) {
+ getChar();
+ xi = xi * 10 + (c - '0');
+ } else if (c == '.') {
+ getChar();
+ goto doReal;
+ } else {
+ break;
+ }
+ }
+ if (neg)
+ xi = -xi;
+ obj->initInt(xi);
+ break;
+ doReal:
+ xf = xi;
+ scale = 0.1;
+ while (1) {
+ c = lookChar();
+ if (c == '-') {
+ // ignore minus signs in the middle of numbers to match
+ // Adobe's behavior
+ error(getPos(), "Badly formatted number");
+ getChar();
+ continue;
+ }
+ if (!isdigit(c)) {
+ break;
+ }
+ getChar();
+ xf = xf + scale * (c - '0');
+ scale *= 0.1;
+ }
+ if (neg)
+ xf = -xf;
+ obj->initReal(xf);
+ break;
+
+ // string
+ case '(':
+ p = tokBuf;
+ n = 0;
+ numParen = 1;
+ done = gFalse;
+ s = NULL;
+ do {
+ c2 = EOF;
+ switch (c = getChar()) {
+
+ case EOF:
+#if 0
+ // This breaks some PDF files, e.g., ones from Photoshop.
+ case '\r':
+ case '\n':
+#endif
+ error(getPos(), "Unterminated string");
+ done = gTrue;
+ break;
+
+ case '(':
+ ++numParen;
+ c2 = c;
+ break;
+
+ case ')':
+ if (--numParen == 0) {
+ done = gTrue;
+ } else {
+ c2 = c;
+ }
+ break;
+
+ case '\\':
+ switch (c = getChar()) {
+ case 'n':
+ c2 = '\n';
+ break;
+ case 'r':
+ c2 = '\r';
+ break;
+ case 't':
+ c2 = '\t';
+ break;
+ case 'b':
+ c2 = '\b';
+ break;
+ case 'f':
+ c2 = '\f';
+ break;
+ case '\\':
+ case '(':
+ case ')':
+ c2 = c;
+ break;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ c2 = c - '0';
+ c = lookChar();
+ if (c >= '0' && c <= '7') {
+ getChar();
+ c2 = (c2 << 3) + (c - '0');
+ c = lookChar();
+ if (c >= '0' && c <= '7') {
+ getChar();
+ c2 = (c2 << 3) + (c - '0');
+ }
+ }
+ break;
+ case '\r':
+ c = lookChar();
+ if (c == '\n') {
+ getChar();
+ }
+ break;
+ case '\n':
+ break;
+ case EOF:
+ error(getPos(), "Unterminated string");
+ done = gTrue;
+ break;
+ default:
+ c2 = c;
+ break;
+ }
+ break;
+
+ default:
+ c2 = c;
+ break;
+ }
+
+ if (c2 != EOF) {
+ if (n == tokBufSize) {
+ if (!s)
+ s = new GString(tokBuf, tokBufSize);
+ else
+ s->append(tokBuf, tokBufSize);
+ p = tokBuf;
+ n = 0;
+
+ // we are growing see if the document is not malformed and we are growing too much
+ if (objNum > 0 && xref != NULL)
+ {
+ int newObjNum = xref->getNumEntry(curStr.streamGetPos());
+ if (newObjNum != objNum)
+ {
+ error(getPos(), "Unterminated string");
+ done = gTrue;
+ delete s;
+ n = -2;
+ }
+ }
+ }
+ *p++ = (char)c2;
+ ++n;
+ }
+ } while (!done);
+ if (n >= 0) {
+ if (!s)
+ s = new GString(tokBuf, n);
+ else
+ s->append(tokBuf, n);
+ obj->initString(s);
+ } else {
+ obj->initEOF();
+ }
+ break;
+
+ // name
+ case '/':
+ p = tokBuf;
+ n = 0;
+ s = NULL;
+ while ((c = lookChar()) != EOF && !specialChars[c]) {
+ getChar();
+ if (c == '#') {
+ c2 = lookChar();
+ if (c2 >= '0' && c2 <= '9') {
+ c = c2 - '0';
+ } else if (c2 >= 'A' && c2 <= 'F') {
+ c = c2 - 'A' + 10;
+ } else if (c2 >= 'a' && c2 <= 'f') {
+ c = c2 - 'a' + 10;
+ } else {
+ goto notEscChar;
+ }
+ getChar();
+ c <<= 4;
+ c2 = getChar();
+ if (c2 >= '0' && c2 <= '9') {
+ c += c2 - '0';
+ } else if (c2 >= 'A' && c2 <= 'F') {
+ c += c2 - 'A' + 10;
+ } else if (c2 >= 'a' && c2 <= 'f') {
+ c += c2 - 'a' + 10;
+ } else {
+ error(getPos(), "Illegal digit in hex char in name");
+ }
+ }
+ notEscChar:
+ if (n == tokBufSize) {
+ if (!s)
+ s = new GString(tokBuf, tokBufSize);
+ else
+ {
+ // the spec says 127 is the maximum, we are already at 256 so bail out
+ error(getPos(), "Name token too long");
+ break;
+ }
+ p = tokBuf;
+ n = 0;
+ }
+ *p++ = c;
+ ++n;
+ }
+ *p = '\0';
+ if (s) {
+ s->append(tokBuf, n);
+ obj->initName(s->getCString());
+ delete s;
+ } else obj->initName(tokBuf);
+ break;
+
+ // array punctuation
+ case '[':
+ case ']':
+ tokBuf[0] = c;
+ tokBuf[1] = '\0';
+ obj->initCmd(tokBuf);
+ break;
+
+ // hex string or dict punctuation
+ case '<':
+ c = lookChar();
+
+ // dict punctuation
+ if (c == '<') {
+ getChar();
+ tokBuf[0] = tokBuf[1] = '<';
+ tokBuf[2] = '\0';
+ obj->initCmd(tokBuf);
+
+ // hex string
+ } else {
+ p = tokBuf;
+ m = n = 0;
+ c2 = 0;
+ s = NULL;
+ while (1) {
+ c = getChar();
+ if (c == '>') {
+ break;
+ } else if (c == EOF) {
+ error(getPos(), "Unterminated hex string");
+ break;
+ } else if (specialChars[c] != 1) {
+ c2 = c2 << 4;
+ if (c >= '0' && c <= '9')
+ c2 += c - '0';
+ else if (c >= 'A' && c <= 'F')
+ c2 += c - 'A' + 10;
+ else if (c >= 'a' && c <= 'f')
+ c2 += c - 'a' + 10;
+ else
+ error(getPos(), "Illegal character <%02x> in hex string", c);
+ if (++m == 2) {
+ if (n == tokBufSize) {
+ if (!s)
+ s = new GString(tokBuf, tokBufSize);
+ else
+ s->append(tokBuf, tokBufSize);
+ p = tokBuf;
+ n = 0;
+ }
+ *p++ = (char)c2;
+ ++n;
+ c2 = 0;
+ m = 0;
+ }
+ }
+ }
+ if (!s)
+ s = new GString(tokBuf, n);
+ else
+ s->append(tokBuf, n);
+ if (m == 1)
+ s->append((char)(c2 << 4));
+ obj->initString(s);
+ }
+ break;
+
+ // dict punctuation
+ case '>':
+ c = lookChar();
+ if (c == '>') {
+ getChar();
+ tokBuf[0] = tokBuf[1] = '>';
+ tokBuf[2] = '\0';
+ obj->initCmd(tokBuf);
+ } else {
+ error(getPos(), "Illegal character '>'");
+ obj->initError();
+ }
+ break;
+
+ // error
+ case ')':
+ case '{':
+ case '}':
+ error(getPos(), "Illegal character '%c'", c);
+ obj->initError();
+ break;
+
+ // command
+ default:
+ p = tokBuf;
+ *p++ = c;
+ n = 1;
+ while ((c = lookChar()) != EOF && !specialChars[c]) {
+ getChar();
+ if (++n == tokBufSize) {
+ error(getPos(), "Command token too long");
+ break;
+ }
+ *p++ = c;
+ }
+ *p = '\0';
+ if (tokBuf[0] == 't' && !strcmp(tokBuf, "true")) {
+ obj->initBool(gTrue);
+ } else if (tokBuf[0] == 'f' && !strcmp(tokBuf, "false")) {
+ obj->initBool(gFalse);
+ } else if (tokBuf[0] == 'n' && !strcmp(tokBuf, "null")) {
+ obj->initNull();
+ } else {
+ obj->initCmd(tokBuf);
+ }
+ break;
+ }
+
+ return obj;
+}
+
+void Lexer::skipToNextLine() {
+ int c;
+
+ while (1) {
+ c = getChar();
+ if (c == EOF || c == '\n') {
+ return;
+ }
+ if (c == '\r') {
+ if ((c = lookChar()) == '\n') {
+ getChar();
+ }
+ return;
+ }
+ }
+}
+
+GBool Lexer::isSpace(int c) {
+ return c >= 0 && c <= 0xff && specialChars[c] == 1;
+}
diff --git a/kpdf/xpdf/xpdf/Lexer.h b/kpdf/xpdf/xpdf/Lexer.h
new file mode 100644
index 00000000..3333be9f
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Lexer.h
@@ -0,0 +1,82 @@
+//========================================================================
+//
+// Lexer.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef LEXER_H
+#define LEXER_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "Object.h"
+#include "Stream.h"
+
+class XRef;
+
+#define tokBufSize 128 // size of token buffer
+
+//------------------------------------------------------------------------
+// Lexer
+//------------------------------------------------------------------------
+
+class Lexer {
+public:
+
+ // Construct a lexer for a single stream. Deletes the stream when
+ // lexer is deleted.
+ Lexer(XRef *xrefA, Stream *str);
+
+ // Construct a lexer for a stream or array of streams (assumes obj
+ // is either a stream or array of streams).
+ Lexer(XRef *xrefA, Object *obj);
+
+ // Destructor.
+ ~Lexer();
+
+ // Get the next object from the input stream.
+ Object *getObj(Object *obj, int objNum = -1);
+
+ // Skip to the beginning of the next line in the input stream.
+ void skipToNextLine();
+
+ // Skip over one character.
+ void skipChar() { getChar(); }
+
+ // Get stream.
+ Stream *getStream()
+ { return curStr.isNone() ? (Stream *)NULL : curStr.getStream(); }
+
+ // Get current position in file. This is only used for error
+ // messages, so it returns an int instead of a Guint.
+ int getPos()
+ { return curStr.isNone() ? -1 : (int)curStr.streamGetPos(); }
+
+ // Set position in file.
+ void setPos(Guint pos, int dir = 0)
+ { if (!curStr.isNone()) curStr.streamSetPos(pos, dir); }
+
+ // Returns true if <c> is a whitespace character.
+ static GBool isSpace(int c);
+
+private:
+
+ int getChar();
+ int lookChar();
+
+ Array *streams; // array of input streams
+ int strPtr; // index of current stream
+ Object curStr; // current stream
+ GBool freeArray; // should lexer free the streams array?
+ char tokBuf[tokBufSize]; // temporary token buffer
+
+ XRef *xref;
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/Link.cc b/kpdf/xpdf/xpdf/Link.cc
new file mode 100644
index 00000000..ae2de537
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Link.cc
@@ -0,0 +1,784 @@
+//========================================================================
+//
+// Link.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stddef.h>
+#include <string.h>
+#include "gmem.h"
+#include "GString.h"
+#include "Error.h"
+#include "Object.h"
+#include "Array.h"
+#include "Dict.h"
+#include "Link.h"
+
+//------------------------------------------------------------------------
+// LinkAction
+//------------------------------------------------------------------------
+
+LinkAction *LinkAction::parseDest(Object *obj) {
+ LinkAction *action;
+
+ action = new LinkGoTo(obj);
+ if (!action->isOk()) {
+ delete action;
+ return NULL;
+ }
+ return action;
+}
+
+LinkAction *LinkAction::parseAction(Object *obj, GString *baseURI) {
+ LinkAction *action;
+ Object obj2, obj3, obj4;
+
+ if (!obj->isDict()) {
+ error(-1, "Bad annotation action");
+ return NULL;
+ }
+
+ obj->dictLookup("S", &obj2);
+
+ // GoTo action
+ if (obj2.isName("GoTo")) {
+ obj->dictLookup("D", &obj3);
+ action = new LinkGoTo(&obj3);
+ obj3.free();
+
+ // GoToR action
+ } else if (obj2.isName("GoToR")) {
+ obj->dictLookup("F", &obj3);
+ obj->dictLookup("D", &obj4);
+ action = new LinkGoToR(&obj3, &obj4);
+ obj3.free();
+ obj4.free();
+
+ // Launch action
+ } else if (obj2.isName("Launch")) {
+ action = new LinkLaunch(obj);
+
+ // URI action
+ } else if (obj2.isName("URI")) {
+ obj->dictLookup("URI", &obj3);
+ action = new LinkURI(&obj3, baseURI);
+ obj3.free();
+
+ // Named action
+ } else if (obj2.isName("Named")) {
+ obj->dictLookup("N", &obj3);
+ action = new LinkNamed(&obj3);
+ obj3.free();
+
+ // Movie action
+ } else if (obj2.isName("Movie")) {
+ obj->dictLookupNF("Annot", &obj3);
+ obj->dictLookup("T", &obj4);
+ action = new LinkMovie(&obj3, &obj4);
+ obj3.free();
+ obj4.free();
+
+ // unknown action
+ } else if (obj2.isName()) {
+ action = new LinkUnknown(obj2.getName());
+
+ // action is missing or wrong type
+ } else {
+ error(-1, "Bad annotation action");
+ action = NULL;
+ }
+
+ obj2.free();
+
+ if (action && !action->isOk()) {
+ delete action;
+ return NULL;
+ }
+ return action;
+}
+
+GString *LinkAction::getFileSpecName(Object *fileSpecObj) {
+ GString *name;
+ Object obj1;
+
+ name = NULL;
+
+ // string
+ if (fileSpecObj->isString()) {
+ name = fileSpecObj->getString()->copy();
+
+ // dictionary
+ } else if (fileSpecObj->isDict()) {
+#ifdef WIN32
+ if (!fileSpecObj->dictLookup("DOS", &obj1)->isString()) {
+#else
+ if (!fileSpecObj->dictLookup("Unix", &obj1)->isString()) {
+#endif
+ obj1.free();
+ fileSpecObj->dictLookup("F", &obj1);
+ }
+ if (obj1.isString()) {
+ name = obj1.getString()->copy();
+ } else {
+ error(-1, "Illegal file spec in link");
+ }
+ obj1.free();
+
+ // error
+ } else {
+ error(-1, "Illegal file spec in link");
+ }
+
+ // system-dependent path manipulation
+ if (name) {
+#ifdef WIN32
+ int i, j;
+
+ // "//...." --> "\...."
+ // "/x/...." --> "x:\...."
+ // "/server/share/...." --> "\\server\share\...."
+ // convert escaped slashes to slashes and unescaped slashes to backslashes
+ i = 0;
+ if (name->getChar(0) == '/') {
+ if (name->getLength() >= 2 && name->getChar(1) == '/') {
+ name->del(0);
+ i = 0;
+ } else if (name->getLength() >= 2 &&
+ ((name->getChar(1) >= 'a' && name->getChar(1) <= 'z') ||
+ (name->getChar(1) >= 'A' && name->getChar(1) <= 'Z')) &&
+ (name->getLength() == 2 || name->getChar(2) == '/')) {
+ name->setChar(0, name->getChar(1));
+ name->setChar(1, ':');
+ i = 2;
+ } else {
+ for (j = 2; j < name->getLength(); ++j) {
+ if (name->getChar(j-1) != '\\' &&
+ name->getChar(j) == '/') {
+ break;
+ }
+ }
+ if (j < name->getLength()) {
+ name->setChar(0, '\\');
+ name->insert(0, '\\');
+ i = 2;
+ }
+ }
+ }
+ for (; i < name->getLength(); ++i) {
+ if (name->getChar(i) == '/') {
+ name->setChar(i, '\\');
+ } else if (name->getChar(i) == '\\' &&
+ i+1 < name->getLength() &&
+ name->getChar(i+1) == '/') {
+ name->del(i);
+ }
+ }
+#else
+ // no manipulation needed for Unix
+#endif
+ }
+
+ return name;
+}
+
+//------------------------------------------------------------------------
+// LinkDest
+//------------------------------------------------------------------------
+
+LinkDest::LinkDest(Array *a) {
+ Object obj1, obj2;
+
+ // initialize fields
+ left = bottom = right = top = zoom = 0;
+ ok = gFalse;
+
+ // get page
+ if (a->getLength() < 2) {
+ error(-1, "Annotation destination array is too short");
+ return;
+ }
+ a->getNF(0, &obj1);
+ if (obj1.isInt()) {
+ pageNum = obj1.getInt() + 1;
+ pageIsRef = gFalse;
+ } else if (obj1.isRef()) {
+ pageRef.num = obj1.getRefNum();
+ pageRef.gen = obj1.getRefGen();
+ pageIsRef = gTrue;
+ } else {
+ error(-1, "Bad annotation destination");
+ goto err2;
+ }
+ obj1.free();
+
+ // get destination type
+ a->get(1, &obj1);
+
+ // XYZ link
+ if (obj1.isName("XYZ")) {
+ kind = destXYZ;
+ if (a->getLength() < 3) {
+ changeLeft = gFalse;
+ } else {
+ a->get(2, &obj2);
+ if (obj2.isNull()) {
+ changeLeft = gFalse;
+ } else if (obj2.isNum()) {
+ changeLeft = gTrue;
+ left = obj2.getNum();
+ } else {
+ error(-1, "Bad annotation destination position");
+ goto err1;
+ }
+ obj2.free();
+ }
+ if (a->getLength() < 4) {
+ changeTop = gFalse;
+ } else {
+ a->get(3, &obj2);
+ if (obj2.isNull()) {
+ changeTop = gFalse;
+ } else if (obj2.isNum()) {
+ changeTop = gTrue;
+ top = obj2.getNum();
+ } else {
+ error(-1, "Bad annotation destination position");
+ goto err1;
+ }
+ obj2.free();
+ }
+ if (a->getLength() < 5) {
+ changeZoom = gFalse;
+ } else {
+ a->get(4, &obj2);
+ if (obj2.isNull()) {
+ changeZoom = gFalse;
+ } else if (obj2.isNum()) {
+ changeZoom = gTrue;
+ zoom = obj2.getNum();
+ } else {
+ error(-1, "Bad annotation destination position");
+ goto err1;
+ }
+ obj2.free();
+ }
+
+ // Fit link
+ } else if (obj1.isName("Fit")) {
+ if (a->getLength() < 2) {
+ error(-1, "Annotation destination array is too short");
+ goto err2;
+ }
+ kind = destFit;
+
+ // FitH link
+ } else if (obj1.isName("FitH")) {
+ if (a->getLength() < 3) {
+ error(-1, "Annotation destination array is too short");
+ goto err2;
+ }
+ kind = destFitH;
+ if (!a->get(2, &obj2)->isNum()) {
+ error(-1, "Bad annotation destination position");
+ kind = destFit;
+ }
+ top = obj2.getNum();
+ obj2.free();
+
+ // FitV link
+ } else if (obj1.isName("FitV")) {
+ if (a->getLength() < 3) {
+ error(-1, "Annotation destination array is too short");
+ goto err2;
+ }
+ kind = destFitV;
+ if (!a->get(2, &obj2)->isNum()) {
+ error(-1, "Bad annotation destination position");
+ kind = destFit;
+ }
+ left = obj2.getNum();
+ obj2.free();
+
+ // FitR link
+ } else if (obj1.isName("FitR")) {
+ if (a->getLength() < 6) {
+ error(-1, "Annotation destination array is too short");
+ goto err2;
+ }
+ kind = destFitR;
+ if (!a->get(2, &obj2)->isNum()) {
+ error(-1, "Bad annotation destination position");
+ kind = destFit;
+ }
+ left = obj2.getNum();
+ obj2.free();
+ if (!a->get(3, &obj2)->isNum()) {
+ error(-1, "Bad annotation destination position");
+ kind = destFit;
+ }
+ bottom = obj2.getNum();
+ obj2.free();
+ if (!a->get(4, &obj2)->isNum()) {
+ error(-1, "Bad annotation destination position");
+ kind = destFit;
+ }
+ right = obj2.getNum();
+ obj2.free();
+ if (!a->get(5, &obj2)->isNum()) {
+ error(-1, "Bad annotation destination position");
+ kind = destFit;
+ }
+ top = obj2.getNum();
+ obj2.free();
+
+ // FitB link
+ } else if (obj1.isName("FitB")) {
+ if (a->getLength() < 2) {
+ error(-1, "Annotation destination array is too short");
+ goto err2;
+ }
+ kind = destFitB;
+
+ // FitBH link
+ } else if (obj1.isName("FitBH")) {
+ if (a->getLength() < 3) {
+ error(-1, "Annotation destination array is too short");
+ goto err2;
+ }
+ kind = destFitBH;
+ if (!a->get(2, &obj2)->isNum()) {
+ error(-1, "Bad annotation destination position");
+ kind = destFit;
+ }
+ top = obj2.getNum();
+ obj2.free();
+
+ // FitBV link
+ } else if (obj1.isName("FitBV")) {
+ if (a->getLength() < 3) {
+ error(-1, "Annotation destination array is too short");
+ goto err2;
+ }
+ kind = destFitBV;
+ if (!a->get(2, &obj2)->isNum()) {
+ error(-1, "Bad annotation destination position");
+ kind = destFit;
+ }
+ left = obj2.getNum();
+ obj2.free();
+
+ // unknown link kind
+ } else {
+ error(-1, "Unknown annotation destination type");
+ goto err2;
+ }
+
+ obj1.free();
+ ok = gTrue;
+ return;
+
+ err1:
+ obj2.free();
+ err2:
+ obj1.free();
+}
+
+LinkDest::LinkDest(LinkDest *dest) {
+ kind = dest->kind;
+ pageIsRef = dest->pageIsRef;
+ if (pageIsRef)
+ pageRef = dest->pageRef;
+ else
+ pageNum = dest->pageNum;
+ left = dest->left;
+ bottom = dest->bottom;
+ right = dest->right;
+ top = dest->top;
+ zoom = dest->zoom;
+ changeLeft = dest->changeLeft;
+ changeTop = dest->changeTop;
+ changeZoom = dest->changeZoom;
+ ok = gTrue;
+}
+
+//------------------------------------------------------------------------
+// LinkGoTo
+//------------------------------------------------------------------------
+
+LinkGoTo::LinkGoTo(Object *destObj) {
+ dest = NULL;
+ namedDest = NULL;
+
+ // named destination
+ if (destObj->isName()) {
+ namedDest = new GString(destObj->getName());
+ } else if (destObj->isString()) {
+ namedDest = destObj->getString()->copy();
+
+ // destination dictionary
+ } else if (destObj->isArray()) {
+ dest = new LinkDest(destObj->getArray());
+ if (!dest->isOk()) {
+ delete dest;
+ dest = NULL;
+ }
+
+ // error
+ } else {
+ error(-1, "Illegal annotation destination");
+ }
+}
+
+LinkGoTo::~LinkGoTo() {
+ if (dest)
+ delete dest;
+ if (namedDest)
+ delete namedDest;
+}
+
+//------------------------------------------------------------------------
+// LinkGoToR
+//------------------------------------------------------------------------
+
+LinkGoToR::LinkGoToR(Object *fileSpecObj, Object *destObj) {
+ dest = NULL;
+ namedDest = NULL;
+
+ // get file name
+ fileName = getFileSpecName(fileSpecObj);
+
+ // named destination
+ if (destObj->isName()) {
+ namedDest = new GString(destObj->getName());
+ } else if (destObj->isString()) {
+ namedDest = destObj->getString()->copy();
+
+ // destination dictionary
+ } else if (destObj->isArray()) {
+ dest = new LinkDest(destObj->getArray());
+ if (!dest->isOk()) {
+ delete dest;
+ dest = NULL;
+ }
+
+ // error
+ } else {
+ error(-1, "Illegal annotation destination");
+ }
+}
+
+LinkGoToR::~LinkGoToR() {
+ if (fileName)
+ delete fileName;
+ if (dest)
+ delete dest;
+ if (namedDest)
+ delete namedDest;
+}
+
+
+//------------------------------------------------------------------------
+// LinkLaunch
+//------------------------------------------------------------------------
+
+LinkLaunch::LinkLaunch(Object *actionObj) {
+ Object obj1, obj2;
+
+ fileName = NULL;
+ params = NULL;
+
+ if (actionObj->isDict()) {
+ if (!actionObj->dictLookup("F", &obj1)->isNull()) {
+ fileName = getFileSpecName(&obj1);
+ } else {
+ obj1.free();
+#ifdef WIN32
+ if (actionObj->dictLookup("Win", &obj1)->isDict()) {
+ obj1.dictLookup("F", &obj2);
+ fileName = getFileSpecName(&obj2);
+ obj2.free();
+ if (obj1.dictLookup("P", &obj2)->isString()) {
+ params = obj2.getString()->copy();
+ }
+ obj2.free();
+ } else {
+ error(-1, "Bad launch-type link action");
+ }
+#else
+ //~ This hasn't been defined by Adobe yet, so assume it looks
+ //~ just like the Win dictionary until they say otherwise.
+ if (actionObj->dictLookup("Unix", &obj1)->isDict()) {
+ obj1.dictLookup("F", &obj2);
+ fileName = getFileSpecName(&obj2);
+ obj2.free();
+ if (obj1.dictLookup("P", &obj2)->isString()) {
+ params = obj2.getString()->copy();
+ }
+ obj2.free();
+ } else {
+ error(-1, "Bad launch-type link action");
+ }
+#endif
+ }
+ obj1.free();
+ }
+}
+
+LinkLaunch::~LinkLaunch() {
+ if (fileName)
+ delete fileName;
+ if (params)
+ delete params;
+}
+
+//------------------------------------------------------------------------
+// LinkURI
+//------------------------------------------------------------------------
+
+LinkURI::LinkURI(Object *uriObj, GString *baseURI) {
+ GString *uri2;
+ int n;
+ char c;
+
+ uri = NULL;
+ if (uriObj->isString()) {
+ uri2 = uriObj->getString()->copy();
+ if (baseURI && baseURI->getLength() > 0) {
+ n = strcspn(uri2->getCString(), "/:");
+ if (n == uri2->getLength() || uri2->getChar(n) == '/') {
+ uri = baseURI->copy();
+ c = uri->getChar(uri->getLength() - 1);
+ if (c == '/' || c == '?') {
+ if (uri2->getChar(0) == '/') {
+ uri2->del(0);
+ }
+ } else {
+ if (uri2->getChar(0) != '/') {
+ uri->append('/');
+ }
+ }
+ uri->append(uri2);
+ delete uri2;
+ } else {
+ uri = uri2;
+ }
+ } else {
+ uri = uri2;
+ }
+ } else {
+ error(-1, "Illegal URI-type link");
+ }
+}
+
+LinkURI::~LinkURI() {
+ if (uri)
+ delete uri;
+}
+
+//------------------------------------------------------------------------
+// LinkNamed
+//------------------------------------------------------------------------
+
+LinkNamed::LinkNamed(Object *nameObj) {
+ name = NULL;
+ if (nameObj->isName()) {
+ name = new GString(nameObj->getName());
+ }
+}
+
+LinkNamed::~LinkNamed() {
+ if (name) {
+ delete name;
+ }
+}
+
+//------------------------------------------------------------------------
+// LinkMovie
+//------------------------------------------------------------------------
+
+LinkMovie::LinkMovie(Object *annotObj, Object *titleObj) {
+ annotRef.num = -1;
+ title = NULL;
+ if (annotObj->isRef()) {
+ annotRef = annotObj->getRef();
+ } else if (titleObj->isString()) {
+ title = titleObj->getString()->copy();
+ } else {
+ error(-1, "Movie action is missing both the Annot and T keys");
+ }
+}
+
+LinkMovie::~LinkMovie() {
+ if (title) {
+ delete title;
+ }
+}
+
+//------------------------------------------------------------------------
+// LinkUnknown
+//------------------------------------------------------------------------
+
+LinkUnknown::LinkUnknown(char *actionA) {
+ action = new GString(actionA);
+}
+
+LinkUnknown::~LinkUnknown() {
+ delete action;
+}
+
+//------------------------------------------------------------------------
+// Link
+//------------------------------------------------------------------------
+
+Link::Link(Dict *dict, GString *baseURI) {
+ Object obj1, obj2;
+ double t;
+
+ action = NULL;
+ ok = gFalse;
+
+ // get rectangle
+ if (!dict->lookup("Rect", &obj1)->isArray()) {
+ error(-1, "Annotation rectangle is wrong type");
+ goto err2;
+ }
+ if (!obj1.arrayGet(0, &obj2)->isNum()) {
+ error(-1, "Bad annotation rectangle");
+ goto err1;
+ }
+ x1 = obj2.getNum();
+ obj2.free();
+ if (!obj1.arrayGet(1, &obj2)->isNum()) {
+ error(-1, "Bad annotation rectangle");
+ goto err1;
+ }
+ y1 = obj2.getNum();
+ obj2.free();
+ if (!obj1.arrayGet(2, &obj2)->isNum()) {
+ error(-1, "Bad annotation rectangle");
+ goto err1;
+ }
+ x2 = obj2.getNum();
+ obj2.free();
+ if (!obj1.arrayGet(3, &obj2)->isNum()) {
+ error(-1, "Bad annotation rectangle");
+ goto err1;
+ }
+ y2 = obj2.getNum();
+ obj2.free();
+ obj1.free();
+ if (x1 > x2) {
+ t = x1;
+ x1 = x2;
+ x2 = t;
+ }
+ if (y1 > y2) {
+ t = y1;
+ y1 = y2;
+ y2 = t;
+ }
+
+ // look for destination
+ if (!dict->lookup("Dest", &obj1)->isNull()) {
+ action = LinkAction::parseDest(&obj1);
+
+ // look for action
+ } else {
+ obj1.free();
+ if (dict->lookup("A", &obj1)->isDict()) {
+ action = LinkAction::parseAction(&obj1, baseURI);
+ }
+ }
+ obj1.free();
+
+ // check for bad action
+ if (action) {
+ ok = gTrue;
+ }
+
+ return;
+
+ err1:
+ obj2.free();
+ err2:
+ obj1.free();
+}
+
+Link::~Link() {
+ if (action) {
+ delete action;
+ }
+}
+
+//------------------------------------------------------------------------
+// Links
+//------------------------------------------------------------------------
+
+Links::Links(Object *annots, GString *baseURI) {
+ Link *link;
+ Object obj1, obj2;
+ int size;
+ int i;
+
+ links = NULL;
+ size = 0;
+ numLinks = 0;
+
+ if (annots->isArray()) {
+ for (i = 0; i < annots->arrayGetLength(); ++i) {
+ if (annots->arrayGet(i, &obj1)->isDict()) {
+ if (obj1.dictLookup("Subtype", &obj2)->isName("Link")) {
+ link = new Link(obj1.getDict(), baseURI);
+ if (link->isOk()) {
+ if (numLinks >= size) {
+ size += 16;
+ links = (Link **)greallocn(links, size, sizeof(Link *));
+ }
+ links[numLinks++] = link;
+ } else {
+ delete link;
+ }
+ }
+ obj2.free();
+ }
+ obj1.free();
+ }
+ }
+}
+
+Links::~Links() {
+ int i;
+
+ for (i = 0; i < numLinks; ++i)
+ delete links[i];
+ gfree(links);
+}
+
+LinkAction *Links::find(double x, double y) {
+ int i;
+
+ for (i = numLinks - 1; i >= 0; --i) {
+ if (links[i]->inRect(x, y)) {
+ return links[i]->getAction();
+ }
+ }
+ return NULL;
+}
+
+GBool Links::onLink(double x, double y) {
+ int i;
+
+ for (i = 0; i < numLinks; ++i) {
+ if (links[i]->inRect(x, y))
+ return gTrue;
+ }
+ return gFalse;
+}
diff --git a/kpdf/xpdf/xpdf/Link.h b/kpdf/xpdf/xpdf/Link.h
new file mode 100644
index 00000000..698f2c85
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Link.h
@@ -0,0 +1,369 @@
+//========================================================================
+//
+// Link.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef LINK_H
+#define LINK_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "Object.h"
+
+class GString;
+class Array;
+class Dict;
+
+//------------------------------------------------------------------------
+// LinkAction
+//------------------------------------------------------------------------
+
+enum LinkActionKind {
+ actionGoTo, // go to destination
+ actionGoToR, // go to destination in new file
+ actionLaunch, // launch app (or open document)
+ actionURI, // URI
+ actionNamed, // named action
+ actionMovie, // movie action
+ actionUnknown // anything else
+};
+
+class LinkAction {
+public:
+
+ // Destructor.
+ virtual ~LinkAction() {}
+
+ // Was the LinkAction created successfully?
+ virtual GBool isOk() = 0;
+
+ // Check link action type.
+ virtual LinkActionKind getKind() = 0;
+
+ // Parse a destination (old-style action) name, string, or array.
+ static LinkAction *parseDest(Object *obj);
+
+ // Parse an action dictionary.
+ static LinkAction *parseAction(Object *obj, GString *baseURI = NULL);
+
+ // Extract a file name from a file specification (string or
+ // dictionary).
+ static GString *getFileSpecName(Object *fileSpecObj);
+};
+
+//------------------------------------------------------------------------
+// LinkDest
+//------------------------------------------------------------------------
+
+enum LinkDestKind {
+ destXYZ,
+ destFit,
+ destFitH,
+ destFitV,
+ destFitR,
+ destFitB,
+ destFitBH,
+ destFitBV
+};
+
+class LinkDest {
+public:
+
+ // Build a LinkDest from the array.
+ LinkDest(Array *a);
+
+ // Copy a LinkDest.
+ LinkDest *copy() { return new LinkDest(this); }
+
+ // Was the LinkDest created successfully?
+ GBool isOk() { return ok; }
+
+ // Accessors.
+ LinkDestKind getKind() { return kind; }
+ GBool isPageRef() { return pageIsRef; }
+ int getPageNum() { return pageNum; }
+ Ref getPageRef() { return pageRef; }
+ double getLeft() { return left; }
+ double getBottom() { return bottom; }
+ double getRight() { return right; }
+ double getTop() { return top; }
+ double getZoom() { return zoom; }
+ GBool getChangeLeft() { return changeLeft; }
+ GBool getChangeTop() { return changeTop; }
+ GBool getChangeZoom() { return changeZoom; }
+
+private:
+
+ LinkDestKind kind; // destination type
+ GBool pageIsRef; // is the page a reference or number?
+ union {
+ Ref pageRef; // reference to page
+ int pageNum; // one-relative page number
+ };
+ double left, bottom; // position
+ double right, top;
+ double zoom; // zoom factor
+ GBool changeLeft, changeTop; // for destXYZ links, which position
+ GBool changeZoom; // components to change
+ GBool ok; // set if created successfully
+
+ LinkDest(LinkDest *dest);
+};
+
+//------------------------------------------------------------------------
+// LinkGoTo
+//------------------------------------------------------------------------
+
+class LinkGoTo: public LinkAction {
+public:
+
+ // Build a LinkGoTo from a destination (dictionary, name, or string).
+ LinkGoTo(Object *destObj);
+
+ // Destructor.
+ virtual ~LinkGoTo();
+
+ // Was the LinkGoTo created successfully?
+ virtual GBool isOk() { return dest || namedDest; }
+
+ // Accessors.
+ virtual LinkActionKind getKind() { return actionGoTo; }
+ LinkDest *getDest() { return dest; }
+ GString *getNamedDest() { return namedDest; }
+
+private:
+
+ LinkDest *dest; // regular destination (NULL for remote
+ // link with bad destination)
+ GString *namedDest; // named destination (only one of dest and
+ // and namedDest may be non-NULL)
+};
+
+//------------------------------------------------------------------------
+// LinkGoToR
+//------------------------------------------------------------------------
+
+class LinkGoToR: public LinkAction {
+public:
+
+ // Build a LinkGoToR from a file spec (dictionary) and destination
+ // (dictionary, name, or string).
+ LinkGoToR(Object *fileSpecObj, Object *destObj);
+
+ // Destructor.
+ virtual ~LinkGoToR();
+
+ // Was the LinkGoToR created successfully?
+ virtual GBool isOk() { return fileName && (dest || namedDest); }
+
+ // Accessors.
+ virtual LinkActionKind getKind() { return actionGoToR; }
+ GString *getFileName() { return fileName; }
+ LinkDest *getDest() { return dest; }
+ GString *getNamedDest() { return namedDest; }
+
+private:
+
+ GString *fileName; // file name
+ LinkDest *dest; // regular destination (NULL for remote
+ // link with bad destination)
+ GString *namedDest; // named destination (only one of dest and
+ // and namedDest may be non-NULL)
+};
+
+//------------------------------------------------------------------------
+// LinkLaunch
+//------------------------------------------------------------------------
+
+class LinkLaunch: public LinkAction {
+public:
+
+ // Build a LinkLaunch from an action dictionary.
+ LinkLaunch(Object *actionObj);
+
+ // Destructor.
+ virtual ~LinkLaunch();
+
+ // Was the LinkLaunch created successfully?
+ virtual GBool isOk() { return fileName != NULL; }
+
+ // Accessors.
+ virtual LinkActionKind getKind() { return actionLaunch; }
+ GString *getFileName() { return fileName; }
+ GString *getParams() { return params; }
+
+private:
+
+ GString *fileName; // file name
+ GString *params; // parameters
+};
+
+//------------------------------------------------------------------------
+// LinkURI
+//------------------------------------------------------------------------
+
+class LinkURI: public LinkAction {
+public:
+
+ // Build a LinkURI given the URI (string) and base URI.
+ LinkURI(Object *uriObj, GString *baseURI);
+
+ // Destructor.
+ virtual ~LinkURI();
+
+ // Was the LinkURI created successfully?
+ virtual GBool isOk() { return uri != NULL; }
+
+ // Accessors.
+ virtual LinkActionKind getKind() { return actionURI; }
+ GString *getURI() { return uri; }
+
+private:
+
+ GString *uri; // the URI
+};
+
+//------------------------------------------------------------------------
+// LinkNamed
+//------------------------------------------------------------------------
+
+class LinkNamed: public LinkAction {
+public:
+
+ // Build a LinkNamed given the action name.
+ LinkNamed(Object *nameObj);
+
+ virtual ~LinkNamed();
+
+ virtual GBool isOk() { return name != NULL; }
+
+ virtual LinkActionKind getKind() { return actionNamed; }
+ GString *getName() { return name; }
+
+private:
+
+ GString *name;
+};
+
+//------------------------------------------------------------------------
+// LinkMovie
+//------------------------------------------------------------------------
+
+class LinkMovie: public LinkAction {
+public:
+
+ LinkMovie(Object *annotObj, Object *titleObj);
+
+ virtual ~LinkMovie();
+
+ virtual GBool isOk() { return annotRef.num >= 0 || title != NULL; }
+
+ virtual LinkActionKind getKind() { return actionMovie; }
+ GBool hasAnnotRef() { return annotRef.num >= 0; }
+ Ref *getAnnotRef() { return &annotRef; }
+ GString *getTitle() { return title; }
+
+private:
+
+ Ref annotRef;
+ GString *title;
+};
+
+//------------------------------------------------------------------------
+// LinkUnknown
+//------------------------------------------------------------------------
+
+class LinkUnknown: public LinkAction {
+public:
+
+ // Build a LinkUnknown with the specified action type.
+ LinkUnknown(char *actionA);
+
+ // Destructor.
+ virtual ~LinkUnknown();
+
+ // Was the LinkUnknown create successfully?
+ virtual GBool isOk() { return action != NULL; }
+
+ // Accessors.
+ virtual LinkActionKind getKind() { return actionUnknown; }
+ GString *getAction() { return action; }
+
+private:
+
+ GString *action; // action subtype
+};
+
+//------------------------------------------------------------------------
+// Link
+//------------------------------------------------------------------------
+
+class Link {
+public:
+
+ // Construct a link, given its dictionary.
+ Link(Dict *dict, GString *baseURI);
+
+ // Destructor.
+ ~Link();
+
+ // Was the link created successfully?
+ GBool isOk() { return ok; }
+
+ // Check if point is inside the link rectangle.
+ GBool inRect(double x, double y)
+ { return x1 <= x && x <= x2 && y1 <= y && y <= y2; }
+
+ // Get action.
+ LinkAction *getAction() { return action; }
+
+ // Get the link rectangle.
+ void getRect(double *xa1, double *ya1, double *xa2, double *ya2)
+ { *xa1 = x1; *ya1 = y1; *xa2 = x2; *ya2 = y2; }
+
+private:
+
+ double x1, y1; // lower left corner
+ double x2, y2; // upper right corner
+ LinkAction *action; // action
+ GBool ok; // is link valid?
+};
+
+//------------------------------------------------------------------------
+// Links
+//------------------------------------------------------------------------
+
+class Links {
+public:
+
+ // Extract links from array of annotations.
+ Links(Object *annots, GString *baseURI);
+
+ // Destructor.
+ ~Links();
+
+ // Iterate through list of links.
+ int getNumLinks() { return numLinks; }
+ Link *getLink(int i) { return links[i]; }
+
+ // If point <x>,<y> is in a link, return the associated action;
+ // else return NULL.
+ LinkAction *find(double x, double y);
+
+ // Return true if <x>,<y> is in a link.
+ GBool onLink(double x, double y);
+
+private:
+
+ Link **links;
+ int numLinks;
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/Makefile.am b/kpdf/xpdf/xpdf/Makefile.am
new file mode 100644
index 00000000..4c0593ad
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Makefile.am
@@ -0,0 +1,19 @@
+INCLUDES = -I$(srcdir)/.. -I$(srcdir)/../fofi -I$(srcdir)/../splash -I$(srcdir)/../goo $(LIBFREETYPE_CFLAGS) $(XFT_CFLAGS) $(all_includes)
+
+libxpdf_la_LDFLAGS = $(all_libraries)
+libxpdf_la_LIBADD = $(LIB_X11) $(LIBFREETYPE_LIBS) $(LIBPAPER_LIBS) $(XFT_LIBS) $(LIBJPEG) ../goo/libgoo.la ../fofi/libfofi.la ../splash/libsplash.la
+libxpdf_la_SOURCES = Annot.cc Array.cc BuiltinFont.cc BuiltinFontTables.cc \
+ Catalog.cc CharCodeToUnicode.cc CMap.cc Decrypt.cc Dict.cc \
+ FontEncodingTables.cc Function.cc Gfx.cc \
+ GfxFont.cc GfxState.cc GlobalParams.cc JArithmeticDecoder.cc \
+ JBIG2Stream.cc Lexer.cc Link.cc NameToCharCode.cc Object.cc Outline.cc \
+ OutputDev.cc PDFDoc.cc PDFDocEncoding.cc PreScanOutputDev.cc PSTokenizer.cc \
+ Page.cc Parser.cc PSOutputDev.cc SecurityHandler.cc SplashOutputDev.cc Stream.cc JPXStream.cc \
+ TextOutputDev.cc UnicodeMap.cc UnicodeTypeTable.cc XRef.cc
+
+noinst_LTLIBRARIES = libxpdf.la
+
+# This fixes crash in Bug 109015 which i assume is a compiler bug
+# as adding some correctly placed printf in SplashOutputDev::convertPath() makes this
+# option unneeded
+KDE_CXXFLAGS=$(NOREGMOVE)
diff --git a/kpdf/xpdf/xpdf/NameToCharCode.cc b/kpdf/xpdf/xpdf/NameToCharCode.cc
new file mode 100644
index 00000000..7ebf4e16
--- /dev/null
+++ b/kpdf/xpdf/xpdf/NameToCharCode.cc
@@ -0,0 +1,116 @@
+//========================================================================
+//
+// NameToCharCode.cc
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <string.h>
+#include "gmem.h"
+#include "NameToCharCode.h"
+
+//------------------------------------------------------------------------
+
+struct NameToCharCodeEntry {
+ char *name;
+ CharCode c;
+};
+
+//------------------------------------------------------------------------
+
+NameToCharCode::NameToCharCode() {
+ int i;
+
+ size = 31;
+ len = 0;
+ tab = (NameToCharCodeEntry *)gmallocn(size, sizeof(NameToCharCodeEntry));
+ for (i = 0; i < size; ++i) {
+ tab[i].name = NULL;
+ }
+}
+
+NameToCharCode::~NameToCharCode() {
+ int i;
+
+ for (i = 0; i < size; ++i) {
+ if (tab[i].name) {
+ gfree(tab[i].name);
+ }
+ }
+ gfree(tab);
+}
+
+void NameToCharCode::add(char *name, CharCode c) {
+ NameToCharCodeEntry *oldTab;
+ int h, i, oldSize;
+
+ // expand the table if necessary
+ if (len >= size / 2) {
+ oldSize = size;
+ oldTab = tab;
+ size = 2*size + 1;
+ tab = (NameToCharCodeEntry *)gmallocn(size, sizeof(NameToCharCodeEntry));
+ for (h = 0; h < size; ++h) {
+ tab[h].name = NULL;
+ }
+ for (i = 0; i < oldSize; ++i) {
+ if (oldTab[i].name) {
+ h = hash(oldTab[i].name);
+ while (tab[h].name) {
+ if (++h == size) {
+ h = 0;
+ }
+ }
+ tab[h] = oldTab[i];
+ }
+ }
+ gfree(oldTab);
+ }
+
+ // add the new name
+ h = hash(name);
+ while (tab[h].name && strcmp(tab[h].name, name)) {
+ if (++h == size) {
+ h = 0;
+ }
+ }
+ if (!tab[h].name) {
+ tab[h].name = copyString(name);
+ }
+ tab[h].c = c;
+
+ ++len;
+}
+
+CharCode NameToCharCode::lookup(char *name) {
+ int h;
+
+ h = hash(name);
+ while (tab[h].name) {
+ if (!strcmp(tab[h].name, name)) {
+ return tab[h].c;
+ }
+ if (++h == size) {
+ h = 0;
+ }
+ }
+ return 0;
+}
+
+int NameToCharCode::hash(char *name) {
+ char *p;
+ unsigned int h;
+
+ h = 0;
+ for (p = name; *p; ++p) {
+ h = 17 * h + (int)(*p & 0xff);
+ }
+ return (int)(h % size);
+}
diff --git a/kpdf/xpdf/xpdf/NameToCharCode.h b/kpdf/xpdf/xpdf/NameToCharCode.h
new file mode 100644
index 00000000..65453c3a
--- /dev/null
+++ b/kpdf/xpdf/xpdf/NameToCharCode.h
@@ -0,0 +1,42 @@
+//========================================================================
+//
+// NameToCharCode.h
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef NAMETOCHARCODE_H
+#define NAMETOCHARCODE_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "CharTypes.h"
+
+struct NameToCharCodeEntry;
+
+//------------------------------------------------------------------------
+
+class NameToCharCode {
+public:
+
+ NameToCharCode();
+ ~NameToCharCode();
+
+ void add(char *name, CharCode c);
+ CharCode lookup(char *name);
+
+private:
+
+ int hash(char *name);
+
+ NameToCharCodeEntry *tab;
+ int size;
+ int len;
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/NameToUnicodeTable.h b/kpdf/xpdf/xpdf/NameToUnicodeTable.h
new file mode 100644
index 00000000..c5ecba49
--- /dev/null
+++ b/kpdf/xpdf/xpdf/NameToUnicodeTable.h
@@ -0,0 +1,1097 @@
+//========================================================================
+//
+// NameToUnicodeTable.h
+//
+// Copyright 2001-2004 Glyph & Cog, LLC
+//
+//========================================================================
+
+static struct {
+ Unicode u;
+ char *name;
+} nameToUnicodeTab[] = {
+ {0x0021, "!"},
+ {0x0023, "#"},
+ {0x0024, "$"},
+ {0x0025, "%"},
+ {0x0026, "&"},
+ {0x0027, "'"},
+ {0x0028, "("},
+ {0x0029, ")"},
+ {0x002a, "*"},
+ {0x002b, "+"},
+ {0x002c, ","},
+ {0x002d, "-"},
+ {0x002e, "."},
+ {0x002f, "/"},
+ {0x0030, "0"},
+ {0x0031, "1"},
+ {0x0032, "2"},
+ {0x0033, "3"},
+ {0x0034, "4"},
+ {0x0035, "5"},
+ {0x0036, "6"},
+ {0x0037, "7"},
+ {0x0038, "8"},
+ {0x0039, "9"},
+ {0x003a, ":"},
+ {0x003b, ";"},
+ {0x003c, "<"},
+ {0x003d, "="},
+ {0x003e, ">"},
+ {0x003f, "?"},
+ {0x0040, "@"},
+ {0x0041, "A"},
+ {0x00c6, "AE"},
+ {0x01fc, "AEacute"},
+ {0xf7e6, "AEsmall"},
+ {0x00c1, "Aacute"},
+ {0xf7e1, "Aacutesmall"},
+ {0x0102, "Abreve"},
+ {0x00c2, "Acircumflex"},
+ {0xf7e2, "Acircumflexsmall"},
+ {0xf6c9, "Acute"},
+ {0xf7b4, "Acutesmall"},
+ {0x00c4, "Adieresis"},
+ {0xf7e4, "Adieresissmall"},
+ {0x00c0, "Agrave"},
+ {0xf7e0, "Agravesmall"},
+ {0x0391, "Alpha"},
+ {0x0386, "Alphatonos"},
+ {0x0100, "Amacron"},
+ {0x0104, "Aogonek"},
+ {0x00c5, "Aring"},
+ {0x01fa, "Aringacute"},
+ {0xf7e5, "Aringsmall"},
+ {0xf761, "Asmall"},
+ {0x00c3, "Atilde"},
+ {0xf7e3, "Atildesmall"},
+ {0x0042, "B"},
+ {0x0392, "Beta"},
+ {0xf6f4, "Brevesmall"},
+ {0xf762, "Bsmall"},
+ {0x0043, "C"},
+ {0x0106, "Cacute"},
+ {0xf6ca, "Caron"},
+ {0xf6f5, "Caronsmall"},
+ {0x010c, "Ccaron"},
+ {0x00c7, "Ccedilla"},
+ {0xf7e7, "Ccedillasmall"},
+ {0x0108, "Ccircumflex"},
+ {0x010a, "Cdotaccent"},
+ {0xf7b8, "Cedillasmall"},
+ {0x03a7, "Chi"},
+ {0xf6f6, "Circumflexsmall"},
+ {0xf763, "Csmall"},
+ {0x0044, "D"},
+ {0x010e, "Dcaron"},
+ {0x0110, "Dcroat"},
+ {0x2206, "Delta"},
+ {0xf6cb, "Dieresis"},
+ {0xf6cc, "DieresisAcute"},
+ {0xf6cd, "DieresisGrave"},
+ {0xf7a8, "Dieresissmall"},
+ {0xf6f7, "Dotaccentsmall"},
+ {0xf764, "Dsmall"},
+ {0x0045, "E"},
+ {0x00c9, "Eacute"},
+ {0xf7e9, "Eacutesmall"},
+ {0x0114, "Ebreve"},
+ {0x011a, "Ecaron"},
+ {0x00ca, "Ecircumflex"},
+ {0xf7ea, "Ecircumflexsmall"},
+ {0x00cb, "Edieresis"},
+ {0xf7eb, "Edieresissmall"},
+ {0x0116, "Edotaccent"},
+ {0x00c8, "Egrave"},
+ {0xf7e8, "Egravesmall"},
+ {0x0112, "Emacron"},
+ {0x014a, "Eng"},
+ {0x0118, "Eogonek"},
+ {0x0395, "Epsilon"},
+ {0x0388, "Epsilontonos"},
+ {0xf765, "Esmall"},
+ {0x0397, "Eta"},
+ {0x0389, "Etatonos"},
+ {0x00d0, "Eth"},
+ {0xf7f0, "Ethsmall"},
+ {0x20ac, "Euro"},
+ {0x0046, "F"},
+ {0xf766, "Fsmall"},
+ {0x0047, "G"},
+ {0x0393, "Gamma"},
+ {0x011e, "Gbreve"},
+ {0x01e6, "Gcaron"},
+ {0x011c, "Gcircumflex"},
+ {0x0122, "Gcommaaccent"},
+ {0x0120, "Gdotaccent"},
+ {0xf6ce, "Grave"},
+ {0xf760, "Gravesmall"},
+ {0xf767, "Gsmall"},
+ {0x0048, "H"},
+ {0x25cf, "H18533"},
+ {0x25aa, "H18543"},
+ {0x25ab, "H18551"},
+ {0x25a1, "H22073"},
+ {0x0126, "Hbar"},
+ {0x0124, "Hcircumflex"},
+ {0xf768, "Hsmall"},
+ {0xf6cf, "Hungarumlaut"},
+ {0xf6f8, "Hungarumlautsmall"},
+ {0x0049, "I"},
+ {0x0132, "IJ"},
+ {0x00cd, "Iacute"},
+ {0xf7ed, "Iacutesmall"},
+ {0x012c, "Ibreve"},
+ {0x00ce, "Icircumflex"},
+ {0xf7ee, "Icircumflexsmall"},
+ {0x00cf, "Idieresis"},
+ {0xf7ef, "Idieresissmall"},
+ {0x0130, "Idotaccent"},
+ {0x2111, "Ifraktur"},
+ {0x00cc, "Igrave"},
+ {0xf7ec, "Igravesmall"},
+ {0x012a, "Imacron"},
+ {0x012e, "Iogonek"},
+ {0x0399, "Iota"},
+ {0x03aa, "Iotadieresis"},
+ {0x038a, "Iotatonos"},
+ {0xf769, "Ismall"},
+ {0x0128, "Itilde"},
+ {0x004a, "J"},
+ {0x0134, "Jcircumflex"},
+ {0xf76a, "Jsmall"},
+ {0x004b, "K"},
+ {0x039a, "Kappa"},
+ {0x0136, "Kcommaaccent"},
+ {0xf76b, "Ksmall"},
+ {0x004c, "L"},
+ {0xf6bf, "LL"},
+ {0x0139, "Lacute"},
+ {0x039b, "Lambda"},
+ {0x013d, "Lcaron"},
+ {0x013b, "Lcommaaccent"},
+ {0x013f, "Ldot"},
+ {0x0141, "Lslash"},
+ {0xf6f9, "Lslashsmall"},
+ {0xf76c, "Lsmall"},
+ {0x004d, "M"},
+ {0xf6d0, "Macron"},
+ {0xf7af, "Macronsmall"},
+ {0xf76d, "Msmall"},
+ {0x039c, "Mu"},
+ {0x004e, "N"},
+ {0x0143, "Nacute"},
+ {0x0147, "Ncaron"},
+ {0x0145, "Ncommaaccent"},
+ {0xf76e, "Nsmall"},
+ {0x00d1, "Ntilde"},
+ {0xf7f1, "Ntildesmall"},
+ {0x039d, "Nu"},
+ {0x004f, "O"},
+ {0x0152, "OE"},
+ {0xf6fa, "OEsmall"},
+ {0x00d3, "Oacute"},
+ {0xf7f3, "Oacutesmall"},
+ {0x014e, "Obreve"},
+ {0x00d4, "Ocircumflex"},
+ {0xf7f4, "Ocircumflexsmall"},
+ {0x00d6, "Odieresis"},
+ {0xf7f6, "Odieresissmall"},
+ {0xf6fb, "Ogoneksmall"},
+ {0x00d2, "Ograve"},
+ {0xf7f2, "Ogravesmall"},
+ {0x01a0, "Ohorn"},
+ {0x0150, "Ohungarumlaut"},
+ {0x014c, "Omacron"},
+ {0x2126, "Omega"},
+ {0x038f, "Omegatonos"},
+ {0x039f, "Omicron"},
+ {0x038c, "Omicrontonos"},
+ {0x00d8, "Oslash"},
+ {0x01fe, "Oslashacute"},
+ {0xf7f8, "Oslashsmall"},
+ {0xf76f, "Osmall"},
+ {0x00d5, "Otilde"},
+ {0xf7f5, "Otildesmall"},
+ {0x0050, "P"},
+ {0x03a6, "Phi"},
+ {0x03a0, "Pi"},
+ {0x03a8, "Psi"},
+ {0xf770, "Psmall"},
+ {0x0051, "Q"},
+ {0xf771, "Qsmall"},
+ {0x0052, "R"},
+ {0x0154, "Racute"},
+ {0x0158, "Rcaron"},
+ {0x0156, "Rcommaaccent"},
+ {0x211c, "Rfraktur"},
+ {0x03a1, "Rho"},
+ {0xf6fc, "Ringsmall"},
+ {0xf772, "Rsmall"},
+ {0x0053, "S"},
+ {0x250c, "SF010000"},
+ {0x2514, "SF020000"},
+ {0x2510, "SF030000"},
+ {0x2518, "SF040000"},
+ {0x253c, "SF050000"},
+ {0x252c, "SF060000"},
+ {0x2534, "SF070000"},
+ {0x251c, "SF080000"},
+ {0x2524, "SF090000"},
+ {0x2500, "SF100000"},
+ {0x2502, "SF110000"},
+ {0x2561, "SF190000"},
+ {0x2562, "SF200000"},
+ {0x2556, "SF210000"},
+ {0x2555, "SF220000"},
+ {0x2563, "SF230000"},
+ {0x2551, "SF240000"},
+ {0x2557, "SF250000"},
+ {0x255d, "SF260000"},
+ {0x255c, "SF270000"},
+ {0x255b, "SF280000"},
+ {0x255e, "SF360000"},
+ {0x255f, "SF370000"},
+ {0x255a, "SF380000"},
+ {0x2554, "SF390000"},
+ {0x2569, "SF400000"},
+ {0x2566, "SF410000"},
+ {0x2560, "SF420000"},
+ {0x2550, "SF430000"},
+ {0x256c, "SF440000"},
+ {0x2567, "SF450000"},
+ {0x2568, "SF460000"},
+ {0x2564, "SF470000"},
+ {0x2565, "SF480000"},
+ {0x2559, "SF490000"},
+ {0x2558, "SF500000"},
+ {0x2552, "SF510000"},
+ {0x2553, "SF520000"},
+ {0x256b, "SF530000"},
+ {0x256a, "SF540000"},
+ {0x015a, "Sacute"},
+ {0x0160, "Scaron"},
+ {0xf6fd, "Scaronsmall"},
+ {0x015e, "Scedilla"},
+ {0x015c, "Scircumflex"},
+ {0x0218, "Scommaaccent"},
+ {0x03a3, "Sigma"},
+ {0xf773, "Ssmall"},
+ {0x0054, "T"},
+ {0x03a4, "Tau"},
+ {0x0166, "Tbar"},
+ {0x0164, "Tcaron"},
+ {0x0162, "Tcommaaccent"},
+ {0x0398, "Theta"},
+ {0x00de, "Thorn"},
+ {0xf7fe, "Thornsmall"},
+ {0xf6fe, "Tildesmall"},
+ {0xf774, "Tsmall"},
+ {0x0055, "U"},
+ {0x00da, "Uacute"},
+ {0xf7fa, "Uacutesmall"},
+ {0x016c, "Ubreve"},
+ {0x00db, "Ucircumflex"},
+ {0xf7fb, "Ucircumflexsmall"},
+ {0x00dc, "Udieresis"},
+ {0xf7fc, "Udieresissmall"},
+ {0x00d9, "Ugrave"},
+ {0xf7f9, "Ugravesmall"},
+ {0x01af, "Uhorn"},
+ {0x0170, "Uhungarumlaut"},
+ {0x016a, "Umacron"},
+ {0x0172, "Uogonek"},
+ {0x03a5, "Upsilon"},
+ {0x03d2, "Upsilon1"},
+ {0x03ab, "Upsilondieresis"},
+ {0x038e, "Upsilontonos"},
+ {0x016e, "Uring"},
+ {0xf775, "Usmall"},
+ {0x0168, "Utilde"},
+ {0x0056, "V"},
+ {0xf776, "Vsmall"},
+ {0x0057, "W"},
+ {0x1e82, "Wacute"},
+ {0x0174, "Wcircumflex"},
+ {0x1e84, "Wdieresis"},
+ {0x1e80, "Wgrave"},
+ {0xf777, "Wsmall"},
+ {0x0058, "X"},
+ {0x039e, "Xi"},
+ {0xf778, "Xsmall"},
+ {0x0059, "Y"},
+ {0x00dd, "Yacute"},
+ {0xf7fd, "Yacutesmall"},
+ {0x0176, "Ycircumflex"},
+ {0x0178, "Ydieresis"},
+ {0xf7ff, "Ydieresissmall"},
+ {0x1ef2, "Ygrave"},
+ {0xf779, "Ysmall"},
+ {0x005a, "Z"},
+ {0x0179, "Zacute"},
+ {0x017d, "Zcaron"},
+ {0xf6ff, "Zcaronsmall"},
+ {0x017b, "Zdotaccent"},
+ {0x0396, "Zeta"},
+ {0xf77a, "Zsmall"},
+ {0x0022, "\""},
+ {0x005c, "\\"},
+ {0x005d, "]"},
+ {0x005e, "^"},
+ {0x005f, "_"},
+ {0x0060, "`"},
+ {0x0061, "a"},
+ {0x00e1, "aacute"},
+ {0x0103, "abreve"},
+ {0x00e2, "acircumflex"},
+ {0x00b4, "acute"},
+ {0x0301, "acutecomb"},
+ {0x00e4, "adieresis"},
+ {0x00e6, "ae"},
+ {0x01fd, "aeacute"},
+ {0x2015, "afii00208"},
+ {0x0410, "afii10017"},
+ {0x0411, "afii10018"},
+ {0x0412, "afii10019"},
+ {0x0413, "afii10020"},
+ {0x0414, "afii10021"},
+ {0x0415, "afii10022"},
+ {0x0401, "afii10023"},
+ {0x0416, "afii10024"},
+ {0x0417, "afii10025"},
+ {0x0418, "afii10026"},
+ {0x0419, "afii10027"},
+ {0x041a, "afii10028"},
+ {0x041b, "afii10029"},
+ {0x041c, "afii10030"},
+ {0x041d, "afii10031"},
+ {0x041e, "afii10032"},
+ {0x041f, "afii10033"},
+ {0x0420, "afii10034"},
+ {0x0421, "afii10035"},
+ {0x0422, "afii10036"},
+ {0x0423, "afii10037"},
+ {0x0424, "afii10038"},
+ {0x0425, "afii10039"},
+ {0x0426, "afii10040"},
+ {0x0427, "afii10041"},
+ {0x0428, "afii10042"},
+ {0x0429, "afii10043"},
+ {0x042a, "afii10044"},
+ {0x042b, "afii10045"},
+ {0x042c, "afii10046"},
+ {0x042d, "afii10047"},
+ {0x042e, "afii10048"},
+ {0x042f, "afii10049"},
+ {0x0490, "afii10050"},
+ {0x0402, "afii10051"},
+ {0x0403, "afii10052"},
+ {0x0404, "afii10053"},
+ {0x0405, "afii10054"},
+ {0x0406, "afii10055"},
+ {0x0407, "afii10056"},
+ {0x0408, "afii10057"},
+ {0x0409, "afii10058"},
+ {0x040a, "afii10059"},
+ {0x040b, "afii10060"},
+ {0x040c, "afii10061"},
+ {0x040e, "afii10062"},
+ {0xf6c4, "afii10063"},
+ {0xf6c5, "afii10064"},
+ {0x0430, "afii10065"},
+ {0x0431, "afii10066"},
+ {0x0432, "afii10067"},
+ {0x0433, "afii10068"},
+ {0x0434, "afii10069"},
+ {0x0435, "afii10070"},
+ {0x0451, "afii10071"},
+ {0x0436, "afii10072"},
+ {0x0437, "afii10073"},
+ {0x0438, "afii10074"},
+ {0x0439, "afii10075"},
+ {0x043a, "afii10076"},
+ {0x043b, "afii10077"},
+ {0x043c, "afii10078"},
+ {0x043d, "afii10079"},
+ {0x043e, "afii10080"},
+ {0x043f, "afii10081"},
+ {0x0440, "afii10082"},
+ {0x0441, "afii10083"},
+ {0x0442, "afii10084"},
+ {0x0443, "afii10085"},
+ {0x0444, "afii10086"},
+ {0x0445, "afii10087"},
+ {0x0446, "afii10088"},
+ {0x0447, "afii10089"},
+ {0x0448, "afii10090"},
+ {0x0449, "afii10091"},
+ {0x044a, "afii10092"},
+ {0x044b, "afii10093"},
+ {0x044c, "afii10094"},
+ {0x044d, "afii10095"},
+ {0x044e, "afii10096"},
+ {0x044f, "afii10097"},
+ {0x0491, "afii10098"},
+ {0x0452, "afii10099"},
+ {0x0453, "afii10100"},
+ {0x0454, "afii10101"},
+ {0x0455, "afii10102"},
+ {0x0456, "afii10103"},
+ {0x0457, "afii10104"},
+ {0x0458, "afii10105"},
+ {0x0459, "afii10106"},
+ {0x045a, "afii10107"},
+ {0x045b, "afii10108"},
+ {0x045c, "afii10109"},
+ {0x045e, "afii10110"},
+ {0x040f, "afii10145"},
+ {0x0462, "afii10146"},
+ {0x0472, "afii10147"},
+ {0x0474, "afii10148"},
+ {0xf6c6, "afii10192"},
+ {0x045f, "afii10193"},
+ {0x0463, "afii10194"},
+ {0x0473, "afii10195"},
+ {0x0475, "afii10196"},
+ {0xf6c7, "afii10831"},
+ {0xf6c8, "afii10832"},
+ {0x04d9, "afii10846"},
+ {0x200e, "afii299"},
+ {0x200f, "afii300"},
+ {0x200d, "afii301"},
+ {0x066a, "afii57381"},
+ {0x060c, "afii57388"},
+ {0x0660, "afii57392"},
+ {0x0661, "afii57393"},
+ {0x0662, "afii57394"},
+ {0x0663, "afii57395"},
+ {0x0664, "afii57396"},
+ {0x0665, "afii57397"},
+ {0x0666, "afii57398"},
+ {0x0667, "afii57399"},
+ {0x0668, "afii57400"},
+ {0x0669, "afii57401"},
+ {0x061b, "afii57403"},
+ {0x061f, "afii57407"},
+ {0x0621, "afii57409"},
+ {0x0622, "afii57410"},
+ {0x0623, "afii57411"},
+ {0x0624, "afii57412"},
+ {0x0625, "afii57413"},
+ {0x0626, "afii57414"},
+ {0x0627, "afii57415"},
+ {0x0628, "afii57416"},
+ {0x0629, "afii57417"},
+ {0x062a, "afii57418"},
+ {0x062b, "afii57419"},
+ {0x062c, "afii57420"},
+ {0x062d, "afii57421"},
+ {0x062e, "afii57422"},
+ {0x062f, "afii57423"},
+ {0x0630, "afii57424"},
+ {0x0631, "afii57425"},
+ {0x0632, "afii57426"},
+ {0x0633, "afii57427"},
+ {0x0634, "afii57428"},
+ {0x0635, "afii57429"},
+ {0x0636, "afii57430"},
+ {0x0637, "afii57431"},
+ {0x0638, "afii57432"},
+ {0x0639, "afii57433"},
+ {0x063a, "afii57434"},
+ {0x0640, "afii57440"},
+ {0x0641, "afii57441"},
+ {0x0642, "afii57442"},
+ {0x0643, "afii57443"},
+ {0x0644, "afii57444"},
+ {0x0645, "afii57445"},
+ {0x0646, "afii57446"},
+ {0x0648, "afii57448"},
+ {0x0649, "afii57449"},
+ {0x064a, "afii57450"},
+ {0x064b, "afii57451"},
+ {0x064c, "afii57452"},
+ {0x064d, "afii57453"},
+ {0x064e, "afii57454"},
+ {0x064f, "afii57455"},
+ {0x0650, "afii57456"},
+ {0x0651, "afii57457"},
+ {0x0652, "afii57458"},
+ {0x0647, "afii57470"},
+ {0x06a4, "afii57505"},
+ {0x067e, "afii57506"},
+ {0x0686, "afii57507"},
+ {0x0698, "afii57508"},
+ {0x06af, "afii57509"},
+ {0x0679, "afii57511"},
+ {0x0688, "afii57512"},
+ {0x0691, "afii57513"},
+ {0x06ba, "afii57514"},
+ {0x06d2, "afii57519"},
+ {0x06d5, "afii57534"},
+ {0x20aa, "afii57636"},
+ {0x05be, "afii57645"},
+ {0x05c3, "afii57658"},
+ {0x05d0, "afii57664"},
+ {0x05d1, "afii57665"},
+ {0x05d2, "afii57666"},
+ {0x05d3, "afii57667"},
+ {0x05d4, "afii57668"},
+ {0x05d5, "afii57669"},
+ {0x05d6, "afii57670"},
+ {0x05d7, "afii57671"},
+ {0x05d8, "afii57672"},
+ {0x05d9, "afii57673"},
+ {0x05da, "afii57674"},
+ {0x05db, "afii57675"},
+ {0x05dc, "afii57676"},
+ {0x05dd, "afii57677"},
+ {0x05de, "afii57678"},
+ {0x05df, "afii57679"},
+ {0x05e0, "afii57680"},
+ {0x05e1, "afii57681"},
+ {0x05e2, "afii57682"},
+ {0x05e3, "afii57683"},
+ {0x05e4, "afii57684"},
+ {0x05e5, "afii57685"},
+ {0x05e6, "afii57686"},
+ {0x05e7, "afii57687"},
+ {0x05e8, "afii57688"},
+ {0x05e9, "afii57689"},
+ {0x05ea, "afii57690"},
+ {0xfb2a, "afii57694"},
+ {0xfb2b, "afii57695"},
+ {0xfb4b, "afii57700"},
+ {0xfb1f, "afii57705"},
+ {0x05f0, "afii57716"},
+ {0x05f1, "afii57717"},
+ {0x05f2, "afii57718"},
+ {0xfb35, "afii57723"},
+ {0x05b4, "afii57793"},
+ {0x05b5, "afii57794"},
+ {0x05b6, "afii57795"},
+ {0x05bb, "afii57796"},
+ {0x05b8, "afii57797"},
+ {0x05b7, "afii57798"},
+ {0x05b0, "afii57799"},
+ {0x05b2, "afii57800"},
+ {0x05b1, "afii57801"},
+ {0x05b3, "afii57802"},
+ {0x05c2, "afii57803"},
+ {0x05c1, "afii57804"},
+ {0x05b9, "afii57806"},
+ {0x05bc, "afii57807"},
+ {0x05bd, "afii57839"},
+ {0x05bf, "afii57841"},
+ {0x05c0, "afii57842"},
+ {0x02bc, "afii57929"},
+ {0x2105, "afii61248"},
+ {0x2113, "afii61289"},
+ {0x2116, "afii61352"},
+ {0x202c, "afii61573"},
+ {0x202d, "afii61574"},
+ {0x202e, "afii61575"},
+ {0x200c, "afii61664"},
+ {0x066d, "afii63167"},
+ {0x02bd, "afii64937"},
+ {0x00e0, "agrave"},
+ {0x2135, "aleph"},
+ {0x03b1, "alpha"},
+ {0x03ac, "alphatonos"},
+ {0x0101, "amacron"},
+ {0x0026, "ampersand"},
+ {0xf726, "ampersandsmall"},
+ {0x2220, "angle"},
+ {0x2329, "angleleft"},
+ {0x232a, "angleright"},
+ {0x0387, "anoteleia"},
+ {0x0105, "aogonek"},
+ {0x2248, "approxequal"},
+ {0x00e5, "aring"},
+ {0x01fb, "aringacute"},
+ {0x2194, "arrowboth"},
+ {0x21d4, "arrowdblboth"},
+ {0x21d3, "arrowdbldown"},
+ {0x21d0, "arrowdblleft"},
+ {0x21d2, "arrowdblright"},
+ {0x21d1, "arrowdblup"},
+ {0x2193, "arrowdown"},
+ {0xf8e7, "arrowhorizex"},
+ {0x2190, "arrowleft"},
+ {0x2192, "arrowright"},
+ {0x2191, "arrowup"},
+ {0x2195, "arrowupdn"},
+ {0x21a8, "arrowupdnbse"},
+ {0xf8e6, "arrowvertex"},
+ {0x005e, "asciicircum"},
+ {0x007e, "asciitilde"},
+ {0x002a, "asterisk"},
+ {0x2217, "asteriskmath"},
+ {0xf6e9, "asuperior"},
+ {0x0040, "at"},
+ {0x00e3, "atilde"},
+ {0x0062, "b"},
+ {0x005c, "backslash"},
+ {0x007c, "bar"},
+ {0x03b2, "beta"},
+ {0x2588, "block"},
+ {0xf8f4, "braceex"},
+ {0x007b, "braceleft"},
+ {0xf8f3, "braceleftbt"},
+ {0xf8f2, "braceleftmid"},
+ {0xf8f1, "bracelefttp"},
+ {0x007d, "braceright"},
+ {0xf8fe, "bracerightbt"},
+ {0xf8fd, "bracerightmid"},
+ {0xf8fc, "bracerighttp"},
+ {0x005b, "bracketleft"},
+ {0xf8f0, "bracketleftbt"},
+ {0xf8ef, "bracketleftex"},
+ {0xf8ee, "bracketlefttp"},
+ {0x005d, "bracketright"},
+ {0xf8fb, "bracketrightbt"},
+ {0xf8fa, "bracketrightex"},
+ {0xf8f9, "bracketrighttp"},
+ {0x02d8, "breve"},
+ {0x00a6, "brokenbar"},
+ {0xf6ea, "bsuperior"},
+ {0x2022, "bullet"},
+ {0x0063, "c"},
+ {0x0107, "cacute"},
+ {0x02c7, "caron"},
+ {0x21b5, "carriagereturn"},
+ {0x010d, "ccaron"},
+ {0x00e7, "ccedilla"},
+ {0x0109, "ccircumflex"},
+ {0x010b, "cdotaccent"},
+ {0x00b8, "cedilla"},
+ {0x00a2, "cent"},
+ {0xf6df, "centinferior"},
+ {0xf7a2, "centoldstyle"},
+ {0xf6e0, "centsuperior"},
+ {0x03c7, "chi"},
+ {0x25cb, "circle"},
+ {0x2297, "circlemultiply"},
+ {0x2295, "circleplus"},
+ {0x02c6, "circumflex"},
+ {0x2663, "club"},
+ {0x003a, "colon"},
+ {0x20a1, "colonmonetary"},
+ {0x002c, "comma"},
+ {0xf6c3, "commaaccent"},
+ {0xf6e1, "commainferior"},
+ {0xf6e2, "commasuperior"},
+ {0x2245, "congruent"},
+ {0x00a9, "copyright"},
+ {0x00a9, "copyrightsans"},
+ {0x00a9, "copyrightserif"},
+ {0x00a4, "currency"},
+ {0xf6d1, "cyrBreve"},
+ {0xf6d2, "cyrFlex"},
+ {0xf6d4, "cyrbreve"},
+ {0xf6d5, "cyrflex"},
+ {0x0064, "d"},
+ {0x2020, "dagger"},
+ {0x2021, "daggerdbl"},
+ {0xf6d3, "dblGrave"},
+ {0xf6d6, "dblgrave"},
+ {0x010f, "dcaron"},
+ {0x0111, "dcroat"},
+ {0x00b0, "degree"},
+ {0x03b4, "delta"},
+ {0x2666, "diamond"},
+ {0x00a8, "dieresis"},
+ {0xf6d7, "dieresisacute"},
+ {0xf6d8, "dieresisgrave"},
+ {0x0385, "dieresistonos"},
+ {0x00f7, "divide"},
+ {0x2593, "dkshade"},
+ {0x2584, "dnblock"},
+ {0x0024, "dollar"},
+ {0xf6e3, "dollarinferior"},
+ {0xf724, "dollaroldstyle"},
+ {0xf6e4, "dollarsuperior"},
+ {0x20ab, "dong"},
+ {0x02d9, "dotaccent"},
+ {0x0323, "dotbelowcomb"},
+ {0x0131, "dotlessi"},
+ {0xf6be, "dotlessj"},
+ {0x22c5, "dotmath"},
+ {0xf6eb, "dsuperior"},
+ {0x0065, "e"},
+ {0x00e9, "eacute"},
+ {0x0115, "ebreve"},
+ {0x011b, "ecaron"},
+ {0x00ea, "ecircumflex"},
+ {0x00eb, "edieresis"},
+ {0x0117, "edotaccent"},
+ {0x00e8, "egrave"},
+ {0x0038, "eight"},
+ {0x2088, "eightinferior"},
+ {0xf738, "eightoldstyle"},
+ {0x2078, "eightsuperior"},
+ {0x2208, "element"},
+ {0x2026, "ellipsis"},
+ {0x0113, "emacron"},
+ {0x2014, "emdash"},
+ {0x2205, "emptyset"},
+ {0x2013, "endash"},
+ {0x014b, "eng"},
+ {0x0119, "eogonek"},
+ {0x03b5, "epsilon"},
+ {0x03ad, "epsilontonos"},
+ {0x003d, "equal"},
+ {0x2261, "equivalence"},
+ {0x212e, "estimated"},
+ {0xf6ec, "esuperior"},
+ {0x03b7, "eta"},
+ {0x03ae, "etatonos"},
+ {0x00f0, "eth"},
+ {0x0021, "exclam"},
+ {0x203c, "exclamdbl"},
+ {0x00a1, "exclamdown"},
+ {0xf7a1, "exclamdownsmall"},
+ {0x0021, "exclamleft"},
+ {0xf721, "exclamsmall"},
+ {0x2203, "existential"},
+ {0x0066, "f"},
+ {0x2640, "female"},
+ {0xfb00, "ff"},
+ {0xfb03, "ffi"},
+ {0xfb04, "ffl"},
+ {0xfb01, "fi"},
+ {0x2012, "figuredash"},
+ {0x25a0, "filledbox"},
+ {0x25ac, "filledrect"},
+ {0x0035, "five"},
+ {0x215d, "fiveeighths"},
+ {0x2085, "fiveinferior"},
+ {0xf735, "fiveoldstyle"},
+ {0x2075, "fivesuperior"},
+ {0xfb02, "fl"},
+ {0x0192, "florin"},
+ {0x0034, "four"},
+ {0x2084, "fourinferior"},
+ {0xf734, "fouroldstyle"},
+ {0x2074, "foursuperior"},
+ {0x2044, "fraction"},
+ {0x20a3, "franc"},
+ {0x0067, "g"},
+ {0x03b3, "gamma"},
+ {0x011f, "gbreve"},
+ {0x01e7, "gcaron"},
+ {0x011d, "gcircumflex"},
+ {0x0123, "gcommaaccent"},
+ {0x0121, "gdotaccent"},
+ {0x00df, "germandbls"},
+ {0x2207, "gradient"},
+ {0x0060, "grave"},
+ {0x0300, "gravecomb"},
+ {0x003e, "greater"},
+ {0x2265, "greaterequal"},
+ {0x00ab, "guillemotleft"},
+ {0x00bb, "guillemotright"},
+ {0x2039, "guilsinglleft"},
+ {0x203a, "guilsinglright"},
+ {0x0068, "h"},
+ {0x0127, "hbar"},
+ {0x0125, "hcircumflex"},
+ {0x2665, "heart"},
+ {0x0309, "hookabovecomb"},
+ {0x2302, "house"},
+ {0x02dd, "hungarumlaut"},
+ {0x002d, "hyphen"},
+ {0xf6e5, "hypheninferior"},
+ {0xf6e6, "hyphensuperior"},
+ {0x0069, "i"},
+ {0x00ed, "iacute"},
+ {0x012d, "ibreve"},
+ {0x00ee, "icircumflex"},
+ {0x00ef, "idieresis"},
+ {0x00ec, "igrave"},
+ {0x0133, "ij"},
+ {0x012b, "imacron"},
+ {0x221e, "infinity"},
+ {0x222b, "integral"},
+ {0x2321, "integralbt"},
+ {0xf8f5, "integralex"},
+ {0x2320, "integraltp"},
+ {0x2229, "intersection"},
+ {0x25d8, "invbullet"},
+ {0x25d9, "invcircle"},
+ {0x263b, "invsmileface"},
+ {0x012f, "iogonek"},
+ {0x03b9, "iota"},
+ {0x03ca, "iotadieresis"},
+ {0x0390, "iotadieresistonos"},
+ {0x03af, "iotatonos"},
+ {0xf6ed, "isuperior"},
+ {0x0129, "itilde"},
+ {0x006a, "j"},
+ {0x0135, "jcircumflex"},
+ {0x006b, "k"},
+ {0x03ba, "kappa"},
+ {0x0137, "kcommaaccent"},
+ {0x0138, "kgreenlandic"},
+ {0x006c, "l"},
+ {0x013a, "lacute"},
+ {0x03bb, "lambda"},
+ {0x013e, "lcaron"},
+ {0x013c, "lcommaaccent"},
+ {0x0140, "ldot"},
+ {0x003c, "less"},
+ {0x2264, "lessequal"},
+ {0x258c, "lfblock"},
+ {0x20a4, "lira"},
+ {0xf6c0, "ll"},
+ {0x2227, "logicaland"},
+ {0x00ac, "logicalnot"},
+ {0x2228, "logicalor"},
+ {0x017f, "longs"},
+ {0x25ca, "lozenge"},
+ {0x0142, "lslash"},
+ {0xf6ee, "lsuperior"},
+ {0x2591, "ltshade"},
+ {0x006d, "m"},
+ {0x00af, "macron"},
+ {0x2642, "male"},
+ {0x2212, "minus"},
+ {0x2032, "minute"},
+ {0xf6ef, "msuperior"},
+ {0x00b5, "mu"},
+ {0x00d7, "multiply"},
+ {0x266a, "musicalnote"},
+ {0x266b, "musicalnotedbl"},
+ {0x006e, "n"},
+ {0x0144, "nacute"},
+ {0x0149, "napostrophe"},
+ {0x00a0, "nbspace"},
+ {0x0148, "ncaron"},
+ {0x0146, "ncommaaccent"},
+ {0x0039, "nine"},
+ {0x2089, "nineinferior"},
+ {0xf739, "nineoldstyle"},
+ {0x2079, "ninesuperior"},
+ {0x00a0, "nonbreakingspace"},
+ {0x2209, "notelement"},
+ {0x2260, "notequal"},
+ {0x2284, "notsubset"},
+ {0x207f, "nsuperior"},
+ {0x00f1, "ntilde"},
+ {0x03bd, "nu"},
+ {0x0023, "numbersign"},
+ {0x006f, "o"},
+ {0x00f3, "oacute"},
+ {0x014f, "obreve"},
+ {0x00f4, "ocircumflex"},
+ {0x00f6, "odieresis"},
+ {0x0153, "oe"},
+ {0x02db, "ogonek"},
+ {0x00f2, "ograve"},
+ {0x01a1, "ohorn"},
+ {0x0151, "ohungarumlaut"},
+ {0x014d, "omacron"},
+ {0x03c9, "omega"},
+ {0x03d6, "omega1"},
+ {0x03ce, "omegatonos"},
+ {0x03bf, "omicron"},
+ {0x03cc, "omicrontonos"},
+ {0x0031, "one"},
+ {0x2024, "onedotenleader"},
+ {0x215b, "oneeighth"},
+ {0xf6dc, "onefitted"},
+ {0x00bd, "onehalf"},
+ {0x2081, "oneinferior"},
+ {0xf731, "oneoldstyle"},
+ {0x00bc, "onequarter"},
+ {0x00b9, "onesuperior"},
+ {0x2153, "onethird"},
+ {0x25e6, "openbullet"},
+ {0x00aa, "ordfeminine"},
+ {0x00ba, "ordmasculine"},
+ {0x221f, "orthogonal"},
+ {0x00f8, "oslash"},
+ {0x01ff, "oslashacute"},
+ {0xf6f0, "osuperior"},
+ {0x00f5, "otilde"},
+ {0x0070, "p"},
+ {0x00b6, "paragraph"},
+ {0x0028, "parenleft"},
+ {0xf8ed, "parenleftbt"},
+ {0xf8ec, "parenleftex"},
+ {0x208d, "parenleftinferior"},
+ {0x207d, "parenleftsuperior"},
+ {0xf8eb, "parenlefttp"},
+ {0x0029, "parenright"},
+ {0xf8f8, "parenrightbt"},
+ {0xf8f7, "parenrightex"},
+ {0x208e, "parenrightinferior"},
+ {0x207e, "parenrightsuperior"},
+ {0xf8f6, "parenrighttp"},
+ {0x2202, "partialdiff"},
+ {0x0025, "percent"},
+ {0x002e, "period"},
+ {0x00b7, "periodcentered"},
+ {0xf6e7, "periodinferior"},
+ {0xf6e8, "periodsuperior"},
+ {0x22a5, "perpendicular"},
+ {0x2030, "perthousand"},
+ {0x20a7, "peseta"},
+ {0x03c6, "phi"},
+ {0x03d5, "phi1"},
+ {0x03c0, "pi"},
+ {0x002b, "plus"},
+ {0x00b1, "plusminus"},
+ {0x211e, "prescription"},
+ {0x220f, "product"},
+ {0x2282, "propersubset"},
+ {0x2283, "propersuperset"},
+ {0x221d, "proportional"},
+ {0x03c8, "psi"},
+ {0x0071, "q"},
+ {0x003f, "question"},
+ {0x00bf, "questiondown"},
+ {0xf7bf, "questiondownsmall"},
+ {0xf73f, "questionsmall"},
+ {0x0022, "quotedbl"},
+ {0x201e, "quotedblbase"},
+ {0x201c, "quotedblleft"},
+ {0x201d, "quotedblright"},
+ {0x2018, "quoteleft"},
+ {0x201b, "quotereversed"},
+ {0x2019, "quoteright"},
+ {0x201a, "quotesinglbase"},
+ {0x0027, "quotesingle"},
+ {0x0072, "r"},
+ {0x0155, "racute"},
+ {0x221a, "radical"},
+ {0xf8e5, "radicalex"},
+ {0x0159, "rcaron"},
+ {0x0157, "rcommaaccent"},
+ {0x2286, "reflexsubset"},
+ {0x2287, "reflexsuperset"},
+ {0x00ae, "registered"},
+ {0x00ae, "registersans"},
+ {0x00ae, "registerserif"},
+ {0x2310, "revlogicalnot"},
+ {0x03c1, "rho"},
+ {0x02da, "ring"},
+ {0xf6f1, "rsuperior"},
+ {0x2590, "rtblock"},
+ {0xf6dd, "rupiah"},
+ {0x0073, "s"},
+ {0x015b, "sacute"},
+ {0x0161, "scaron"},
+ {0x015f, "scedilla"},
+ {0x015d, "scircumflex"},
+ {0x0219, "scommaaccent"},
+ {0x2033, "second"},
+ {0x00a7, "section"},
+ {0x003b, "semicolon"},
+ {0x0037, "seven"},
+ {0x215e, "seveneighths"},
+ {0x2087, "seveninferior"},
+ {0xf737, "sevenoldstyle"},
+ {0x2077, "sevensuperior"},
+ {0x2592, "shade"},
+ {0x03c3, "sigma"},
+ {0x03c2, "sigma1"},
+ {0x223c, "similar"},
+ {0x0036, "six"},
+ {0x2086, "sixinferior"},
+ {0xf736, "sixoldstyle"},
+ {0x2076, "sixsuperior"},
+ {0x002f, "slash"},
+ {0x263a, "smileface"},
+ {0x0020, "space"},
+ {0x2660, "spade"},
+ {0xf6f2, "ssuperior"},
+ {0x00a3, "sterling"},
+ {0x220b, "suchthat"},
+ {0x2211, "summation"},
+ {0x263c, "sun"},
+ {0x0074, "t"},
+ {0x03c4, "tau"},
+ {0x0167, "tbar"},
+ {0x0165, "tcaron"},
+ {0x0163, "tcommaaccent"},
+ {0x2234, "therefore"},
+ {0x03b8, "theta"},
+ {0x03d1, "theta1"},
+ {0x00fe, "thorn"},
+ {0x0033, "three"},
+ {0x215c, "threeeighths"},
+ {0x2083, "threeinferior"},
+ {0xf733, "threeoldstyle"},
+ {0x00be, "threequarters"},
+ {0xf6de, "threequartersemdash"},
+ {0x00b3, "threesuperior"},
+ {0x02dc, "tilde"},
+ {0x0303, "tildecomb"},
+ {0x0384, "tonos"},
+ {0x2122, "trademark"},
+ {0x2122, "trademarksans"},
+ {0x2122, "trademarkserif"},
+ {0x25bc, "triagdn"},
+ {0x25c4, "triaglf"},
+ {0x25ba, "triagrt"},
+ {0x25b2, "triagup"},
+ {0xf6f3, "tsuperior"},
+ {0x0032, "two"},
+ {0x2025, "twodotenleader"},
+ {0x2082, "twoinferior"},
+ {0xf732, "twooldstyle"},
+ {0x00b2, "twosuperior"},
+ {0x2154, "twothirds"},
+ {0x0075, "u"},
+ {0x00fa, "uacute"},
+ {0x016d, "ubreve"},
+ {0x00fb, "ucircumflex"},
+ {0x00fc, "udieresis"},
+ {0x00f9, "ugrave"},
+ {0x01b0, "uhorn"},
+ {0x0171, "uhungarumlaut"},
+ {0x016b, "umacron"},
+ {0x005f, "underscore"},
+ {0x2017, "underscoredbl"},
+ {0x222a, "union"},
+ {0x2200, "universal"},
+ {0x0173, "uogonek"},
+ {0x2580, "upblock"},
+ {0x03c5, "upsilon"},
+ {0x03cb, "upsilondieresis"},
+ {0x03b0, "upsilondieresistonos"},
+ {0x03cd, "upsilontonos"},
+ {0x016f, "uring"},
+ {0x0169, "utilde"},
+ {0x0076, "v"},
+ {0x0077, "w"},
+ {0x1e83, "wacute"},
+ {0x0175, "wcircumflex"},
+ {0x1e85, "wdieresis"},
+ {0x2118, "weierstrass"},
+ {0x1e81, "wgrave"},
+ {0x0078, "x"},
+ {0x03be, "xi"},
+ {0x0079, "y"},
+ {0x00fd, "yacute"},
+ {0x0177, "ycircumflex"},
+ {0x00ff, "ydieresis"},
+ {0x00a5, "yen"},
+ {0x1ef3, "ygrave"},
+ {0x007a, "z"},
+ {0x017a, "zacute"},
+ {0x017e, "zcaron"},
+ {0x017c, "zdotaccent"},
+ {0x0030, "zero"},
+ {0x2080, "zeroinferior"},
+ {0xf730, "zerooldstyle"},
+ {0x2070, "zerosuperior"},
+ {0x03b6, "zeta"},
+ {0x007b, "{"},
+ {0x007c, "|"},
+ {0x007d, "}"},
+ {0x007e, "~"},
+ { 0, NULL }
+};
diff --git a/kpdf/xpdf/xpdf/Object.cc b/kpdf/xpdf/xpdf/Object.cc
new file mode 100644
index 00000000..f0a3a092
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Object.cc
@@ -0,0 +1,233 @@
+//========================================================================
+//
+// Object.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stddef.h>
+#include "Object.h"
+#include "Array.h"
+#include "Dict.h"
+#include "Error.h"
+#include "Stream.h"
+#include "XRef.h"
+
+//------------------------------------------------------------------------
+// Object
+//------------------------------------------------------------------------
+
+char *objTypeNames[numObjTypes] = {
+ "boolean",
+ "integer",
+ "real",
+ "string",
+ "name",
+ "null",
+ "array",
+ "dictionary",
+ "stream",
+ "ref",
+ "cmd",
+ "error",
+ "eof",
+ "none"
+};
+
+#ifdef DEBUG_MEM
+int Object::numAlloc[numObjTypes] =
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+#endif
+
+Object *Object::initArray(XRef *xref) {
+ initObj(objArray);
+ array = new Array(xref);
+ return this;
+}
+
+Object *Object::initDict(XRef *xref) {
+ initObj(objDict);
+ dict = new Dict(xref);
+ return this;
+}
+
+Object *Object::initDict(Dict *dictA) {
+ initObj(objDict);
+ dict = dictA;
+ dict->incRef();
+ return this;
+}
+
+Object *Object::initStream(Stream *streamA) {
+ initObj(objStream);
+ stream = streamA;
+ return this;
+}
+
+Object *Object::copy(Object *obj) {
+ *obj = *this;
+ switch (type) {
+ case objString:
+ obj->string = string->copy();
+ break;
+ case objName:
+ obj->name = copyString(name);
+ break;
+ case objArray:
+ array->incRef();
+ break;
+ case objDict:
+ dict->incRef();
+ break;
+ case objStream:
+ stream->incRef();
+ break;
+ case objCmd:
+ obj->cmd = copyString(cmd);
+ break;
+ default:
+ break;
+ }
+#ifdef DEBUG_MEM
+ ++numAlloc[type];
+#endif
+ return obj;
+}
+
+Object *Object::fetch(XRef *xref, Object *obj) {
+ return (type == objRef && xref) ?
+ xref->fetch(ref.num, ref.gen, obj) : copy(obj);
+}
+
+void Object::free() {
+ switch (type) {
+ case objString:
+ delete string;
+ break;
+ case objName:
+ gfree(name);
+ break;
+ case objArray:
+ if (!array->decRef()) {
+ delete array;
+ }
+ break;
+ case objDict:
+ if (!dict->decRef()) {
+ delete dict;
+ }
+ break;
+ case objStream:
+ if (!stream->decRef()) {
+ delete stream;
+ }
+ break;
+ case objCmd:
+ gfree(cmd);
+ break;
+ default:
+ break;
+ }
+#ifdef DEBUG_MEM
+ --numAlloc[type];
+#endif
+ type = objNone;
+}
+
+char *Object::getTypeName() {
+ return objTypeNames[type];
+}
+
+void Object::print(FILE *f) {
+ Object obj;
+ int i;
+
+ switch (type) {
+ case objBool:
+ fprintf(f, "%s", booln ? "true" : "false");
+ break;
+ case objInt:
+ fprintf(f, "%d", intg);
+ break;
+ case objReal:
+ fprintf(f, "%g", real);
+ break;
+ case objString:
+ fprintf(f, "(");
+ fwrite(string->getCString(), 1, string->getLength(), f);
+ fprintf(f, ")");
+ break;
+ case objName:
+ fprintf(f, "/%s", name);
+ break;
+ case objNull:
+ fprintf(f, "null");
+ break;
+ case objArray:
+ fprintf(f, "[");
+ for (i = 0; i < arrayGetLength(); ++i) {
+ if (i > 0)
+ fprintf(f, " ");
+ arrayGetNF(i, &obj);
+ obj.print(f);
+ obj.free();
+ }
+ fprintf(f, "]");
+ break;
+ case objDict:
+ fprintf(f, "<<");
+ for (i = 0; i < dictGetLength(); ++i) {
+ fprintf(f, " /%s ", dictGetKey(i));
+ dictGetValNF(i, &obj);
+ obj.print(f);
+ obj.free();
+ }
+ fprintf(f, " >>");
+ break;
+ case objStream:
+ fprintf(f, "<stream>");
+ break;
+ case objRef:
+ fprintf(f, "%d %d R", ref.num, ref.gen);
+ break;
+ case objCmd:
+ fprintf(f, "%s", cmd);
+ break;
+ case objError:
+ fprintf(f, "<error>");
+ break;
+ case objEOF:
+ fprintf(f, "<EOF>");
+ break;
+ case objNone:
+ fprintf(f, "<none>");
+ break;
+ }
+}
+
+void Object::memCheck(FILE *f) {
+#ifdef DEBUG_MEM
+ int i;
+ int t;
+
+ t = 0;
+ for (i = 0; i < numObjTypes; ++i)
+ t += numAlloc[i];
+ if (t > 0) {
+ fprintf(f, "Allocated objects:\n");
+ for (i = 0; i < numObjTypes; ++i) {
+ if (numAlloc[i] > 0)
+ fprintf(f, " %-20s: %6d\n", objTypeNames[i], numAlloc[i]);
+ }
+ }
+#else
+ (void)f;
+#endif
+}
diff --git a/kpdf/xpdf/xpdf/Object.h b/kpdf/xpdf/xpdf/Object.h
new file mode 100644
index 00000000..8b1807c5
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Object.h
@@ -0,0 +1,303 @@
+//========================================================================
+//
+// Object.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef OBJECT_H
+#define OBJECT_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include "gtypes.h"
+#include "gmem.h"
+#include "GString.h"
+
+class XRef;
+class Array;
+class Dict;
+class Stream;
+
+//------------------------------------------------------------------------
+// Ref
+//------------------------------------------------------------------------
+
+struct Ref {
+ int num; // object number
+ int gen; // generation number
+};
+
+//------------------------------------------------------------------------
+// object types
+//------------------------------------------------------------------------
+
+enum ObjType {
+ // simple objects
+ objBool, // boolean
+ objInt, // integer
+ objReal, // real
+ objString, // string
+ objName, // name
+ objNull, // null
+
+ // complex objects
+ objArray, // array
+ objDict, // dictionary
+ objStream, // stream
+ objRef, // indirect reference
+
+ // special objects
+ objCmd, // command name
+ objError, // error return from Lexer
+ objEOF, // end of file return from Lexer
+ objNone // uninitialized object
+};
+
+#define numObjTypes 14 // total number of object types
+
+//------------------------------------------------------------------------
+// Object
+//------------------------------------------------------------------------
+
+#ifdef DEBUG_MEM
+#define initObj(t) ++numAlloc[type = t]
+#else
+#define initObj(t) type = t
+#endif
+
+class Object {
+public:
+
+ // Default constructor.
+ Object():
+ type(objNone) {}
+
+ // Initialize an object.
+ Object *initBool(GBool boolnA)
+ { initObj(objBool); booln = boolnA; return this; }
+ Object *initInt(int intgA)
+ { initObj(objInt); intg = intgA; return this; }
+ Object *initReal(double realA)
+ { initObj(objReal); real = realA; return this; }
+ Object *initString(GString *stringA)
+ { initObj(objString); string = stringA; return this; }
+ Object *initName(char *nameA)
+ { initObj(objName); name = copyString(nameA); return this; }
+ Object *initNull()
+ { initObj(objNull); return this; }
+ Object *initArray(XRef *xref);
+ Object *initDict(XRef *xref);
+ Object *initDict(Dict *dictA);
+ Object *initStream(Stream *streamA);
+ Object *initRef(int numA, int genA)
+ { initObj(objRef); ref.num = numA; ref.gen = genA; return this; }
+ Object *initCmd(char *cmdA)
+ { initObj(objCmd); cmd = copyString(cmdA); return this; }
+ Object *initError()
+ { initObj(objError); return this; }
+ Object *initEOF()
+ { initObj(objEOF); return this; }
+
+ // Copy an object.
+ Object *copy(Object *obj);
+
+ // If object is a Ref, fetch and return the referenced object.
+ // Otherwise, return a copy of the object.
+ Object *fetch(XRef *xref, Object *obj);
+
+ // Free object contents.
+ void free();
+
+ // Type checking.
+ ObjType getType() { return type; }
+ GBool isBool() { return type == objBool; }
+ GBool isInt() { return type == objInt; }
+ GBool isReal() { return type == objReal; }
+ GBool isNum() { return type == objInt || type == objReal; }
+ GBool isString() { return type == objString; }
+ GBool isName() { return type == objName; }
+ GBool isNull() { return type == objNull; }
+ GBool isArray() { return type == objArray; }
+ GBool isDict() { return type == objDict; }
+ GBool isStream() { return type == objStream; }
+ GBool isRef() { return type == objRef; }
+ GBool isCmd() { return type == objCmd; }
+ GBool isError() { return type == objError; }
+ GBool isEOF() { return type == objEOF; }
+ GBool isNone() { return type == objNone; }
+
+ // Special type checking.
+ GBool isName(char *nameA)
+ { return type == objName && !strcmp(name, nameA); }
+ GBool isDict(char *dictType);
+ GBool isStream(char *dictType);
+ GBool isCmd(char *cmdA)
+ { return type == objCmd && !strcmp(cmd, cmdA); }
+
+ // Accessors. NB: these assume object is of correct type.
+ GBool getBool() { return booln; }
+ int getInt() { return intg; }
+ double getReal() { return real; }
+ double getNum() { return type == objInt ? (double)intg : real; }
+ GString *getString() { return string; }
+ char *getName() { return name; }
+ Array *getArray() { return array; }
+ Dict *getDict() { return dict; }
+ Stream *getStream() { return stream; }
+ Ref getRef() { return ref; }
+ int getRefNum() { return ref.num; }
+ int getRefGen() { return ref.gen; }
+ char *getCmd() { return cmd; }
+
+ // Array accessors.
+ int arrayGetLength();
+ void arrayAdd(Object *elem);
+ Object *arrayGet(int i, Object *obj);
+ Object *arrayGetNF(int i, Object *obj);
+
+ // Dict accessors.
+ int dictGetLength();
+ void dictAdd(char *key, Object *val);
+ GBool dictIs(char *dictType);
+ Object *dictLookup(char *key, Object *obj);
+ Object *dictLookupNF(char *key, Object *obj);
+ char *dictGetKey(int i);
+ Object *dictGetVal(int i, Object *obj);
+ Object *dictGetValNF(int i, Object *obj);
+
+ // Stream accessors.
+ GBool streamIs(char *dictType);
+ void streamReset();
+ void streamClose();
+ int streamGetChar();
+ int streamLookChar();
+ char *streamGetLine(char *buf, int size);
+ Guint streamGetPos();
+ void streamSetPos(Guint pos, int dir = 0);
+ Dict *streamGetDict();
+
+ // Output.
+ char *getTypeName();
+ void print(FILE *f = stdout);
+
+ // Memory testing.
+ static void memCheck(FILE *f);
+
+private:
+
+ ObjType type; // object type
+ union { // value for each type:
+ GBool booln; // boolean
+ int intg; // integer
+ double real; // real
+ GString *string; // string
+ char *name; // name
+ Array *array; // array
+ Dict *dict; // dictionary
+ Stream *stream; // stream
+ Ref ref; // indirect reference
+ char *cmd; // command
+ };
+
+#ifdef DEBUG_MEM
+ static int // number of each type of object
+ numAlloc[numObjTypes]; // currently allocated
+#endif
+};
+
+//------------------------------------------------------------------------
+// Array accessors.
+//------------------------------------------------------------------------
+
+#include "Array.h"
+
+inline int Object::arrayGetLength()
+ { return array->getLength(); }
+
+inline void Object::arrayAdd(Object *elem)
+ { array->add(elem); }
+
+inline Object *Object::arrayGet(int i, Object *obj)
+ { return array->get(i, obj); }
+
+inline Object *Object::arrayGetNF(int i, Object *obj)
+ { return array->getNF(i, obj); }
+
+//------------------------------------------------------------------------
+// Dict accessors.
+//------------------------------------------------------------------------
+
+#include "Dict.h"
+
+inline int Object::dictGetLength()
+ { return dict->getLength(); }
+
+inline void Object::dictAdd(char *key, Object *val)
+ { dict->add(key, val); }
+
+inline GBool Object::dictIs(char *dictType)
+ { return dict->is(dictType); }
+
+inline GBool Object::isDict(char *dictType)
+ { return type == objDict && dictIs(dictType); }
+
+inline Object *Object::dictLookup(char *key, Object *obj)
+ { return dict->lookup(key, obj); }
+
+inline Object *Object::dictLookupNF(char *key, Object *obj)
+ { return dict->lookupNF(key, obj); }
+
+inline char *Object::dictGetKey(int i)
+ { return dict->getKey(i); }
+
+inline Object *Object::dictGetVal(int i, Object *obj)
+ { return dict->getVal(i, obj); }
+
+inline Object *Object::dictGetValNF(int i, Object *obj)
+ { return dict->getValNF(i, obj); }
+
+//------------------------------------------------------------------------
+// Stream accessors.
+//------------------------------------------------------------------------
+
+#include "Stream.h"
+
+inline GBool Object::streamIs(char *dictType)
+ { return stream->getDict()->is(dictType); }
+
+inline GBool Object::isStream(char *dictType)
+ { return type == objStream && streamIs(dictType); }
+
+inline void Object::streamReset()
+ { stream->reset(); }
+
+inline void Object::streamClose()
+ { stream->close(); }
+
+inline int Object::streamGetChar()
+ { return stream->getChar(); }
+
+inline int Object::streamLookChar()
+ { return stream->lookChar(); }
+
+inline char *Object::streamGetLine(char *buf, int size)
+ { return stream->getLine(buf, size); }
+
+inline Guint Object::streamGetPos()
+ { return stream->getPos(); }
+
+inline void Object::streamSetPos(Guint pos, int dir)
+ { stream->setPos(pos, dir); }
+
+inline Dict *Object::streamGetDict()
+ { return stream->getDict(); }
+
+#endif
diff --git a/kpdf/xpdf/xpdf/Outline.cc b/kpdf/xpdf/xpdf/Outline.cc
new file mode 100644
index 00000000..39e89a3c
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Outline.cc
@@ -0,0 +1,151 @@
+//========================================================================
+//
+// Outline.cc
+//
+// Copyright 2002-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "gmem.h"
+#include "GString.h"
+#include "GList.h"
+#include "Link.h"
+#include "PDFDocEncoding.h"
+#include "Outline.h"
+
+//------------------------------------------------------------------------
+
+Outline::Outline(Object *outlineObj, XRef *xref) {
+ Object first, last;
+
+ items = NULL;
+ if (!outlineObj->isDict()) {
+ return;
+ }
+ items = OutlineItem::readItemList(outlineObj->dictLookupNF("First", &first),
+ outlineObj->dictLookupNF("Last", &last),
+ xref);
+ first.free();
+ last.free();
+}
+
+Outline::~Outline() {
+ if (items) {
+ deleteGList(items, OutlineItem);
+ }
+}
+
+//------------------------------------------------------------------------
+
+OutlineItem::OutlineItem(Dict *dict, XRef *xrefA) {
+ Object obj1;
+ GString *s;
+ int i;
+
+ xref = xrefA;
+ title = NULL;
+ action = NULL;
+ kids = NULL;
+
+ if (dict->lookup("Title", &obj1)->isString()) {
+ s = obj1.getString();
+ if ((s->getChar(0) & 0xff) == 0xfe &&
+ (s->getChar(1) & 0xff) == 0xff) {
+ titleLen = (s->getLength() - 2) / 2;
+ title = (Unicode *)gmallocn(titleLen, sizeof(Unicode));
+ for (i = 0; i < titleLen; ++i) {
+ title[i] = ((s->getChar(2 + 2*i) & 0xff) << 8) |
+ (s->getChar(3 + 2*i) & 0xff);
+ }
+ } else {
+ titleLen = s->getLength();
+ title = (Unicode *)gmallocn(titleLen, sizeof(Unicode));
+ for (i = 0; i < titleLen; ++i) {
+ title[i] = pdfDocEncoding[s->getChar(i) & 0xff];
+ }
+ }
+ } else {
+ titleLen = 0;
+ }
+ obj1.free();
+
+ if (!dict->lookup("Dest", &obj1)->isNull()) {
+ action = LinkAction::parseDest(&obj1);
+ } else {
+ obj1.free();
+ if (!dict->lookup("A", &obj1)->isNull()) {
+ action = LinkAction::parseAction(&obj1);
+ }
+ }
+ obj1.free();
+
+ dict->lookupNF("First", &firstRef);
+ dict->lookupNF("Last", &lastRef);
+ dict->lookupNF("Next", &nextRef);
+
+ startsOpen = gFalse;
+ if (dict->lookup("Count", &obj1)->isInt()) {
+ if (obj1.getInt() > 0) {
+ startsOpen = gTrue;
+ }
+ }
+ obj1.free();
+}
+
+OutlineItem::~OutlineItem() {
+ close();
+ if (title) {
+ gfree(title);
+ }
+ if (action) {
+ delete action;
+ }
+ firstRef.free();
+ lastRef.free();
+ nextRef.free();
+}
+
+GList *OutlineItem::readItemList(Object *firstItemRef, Object *lastItemRef,
+ XRef *xrefA) {
+ GList *items;
+ OutlineItem *item;
+ Object obj;
+ Object *p;
+
+ items = new GList();
+ p = firstItemRef;
+ while (p->isRef()) {
+ if (!p->fetch(xrefA, &obj)->isDict()) {
+ obj.free();
+ break;
+ }
+ item = new OutlineItem(obj.getDict(), xrefA);
+ obj.free();
+ items->append(item);
+ if (p->getRef().num == lastItemRef->getRef().num &&
+ p->getRef().gen == lastItemRef->getRef().gen) {
+ break;
+ }
+ p = &item->nextRef;
+ }
+ return items;
+}
+
+void OutlineItem::open() {
+ if (!kids) {
+ kids = readItemList(&firstRef, &lastRef, xref);
+ }
+}
+
+void OutlineItem::close() {
+ if (kids) {
+ deleteGList(kids, OutlineItem);
+ kids = NULL;
+ }
+}
diff --git a/kpdf/xpdf/xpdf/Outline.h b/kpdf/xpdf/xpdf/Outline.h
new file mode 100644
index 00000000..f38f8d16
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Outline.h
@@ -0,0 +1,76 @@
+//========================================================================
+//
+// Outline.h
+//
+// Copyright 2002-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef OUTLINE_H
+#define OUTLINE_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "Object.h"
+#include "CharTypes.h"
+
+class GString;
+class GList;
+class XRef;
+class LinkAction;
+
+//------------------------------------------------------------------------
+
+class Outline {
+public:
+
+ Outline(Object *outlineObj, XRef *xref);
+ ~Outline();
+
+ GList *getItems() { return items; }
+
+private:
+
+ GList *items; // NULL if document has no outline
+ // [OutlineItem]
+};
+
+//------------------------------------------------------------------------
+
+class OutlineItem {
+public:
+
+ OutlineItem(Dict *dict, XRef *xrefA);
+ ~OutlineItem();
+
+ static GList *readItemList(Object *firstItemRef, Object *lastItemRef,
+ XRef *xrefA);
+
+ void open();
+ void close();
+
+ Unicode *getTitle() { return title; }
+ int getTitleLength() { return titleLen; }
+ LinkAction *getAction() { return action; }
+ GBool isOpen() { return startsOpen; }
+ GBool hasKids() { return firstRef.isRef(); }
+ GList *getKids() { return kids; }
+
+private:
+
+ XRef *xref;
+ Unicode *title;
+ int titleLen;
+ LinkAction *action;
+ Object firstRef;
+ Object lastRef;
+ Object nextRef;
+ GBool startsOpen;
+ GList *kids; // NULL unless this item is open [OutlineItem]
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/OutputDev.cc b/kpdf/xpdf/xpdf/OutputDev.cc
new file mode 100644
index 00000000..3ba19973
--- /dev/null
+++ b/kpdf/xpdf/xpdf/OutputDev.cc
@@ -0,0 +1,131 @@
+//========================================================================
+//
+// OutputDev.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stddef.h>
+#include "Object.h"
+#include "Stream.h"
+#include "GfxState.h"
+#include "OutputDev.h"
+
+//------------------------------------------------------------------------
+// OutputDev
+//------------------------------------------------------------------------
+
+void OutputDev::setDefaultCTM(double *ctm) {
+ int i;
+ double det;
+
+ for (i = 0; i < 6; ++i) {
+ defCTM[i] = ctm[i];
+ }
+ det = 1 / (defCTM[0] * defCTM[3] - defCTM[1] * defCTM[2]);
+ defICTM[0] = defCTM[3] * det;
+ defICTM[1] = -defCTM[1] * det;
+ defICTM[2] = -defCTM[2] * det;
+ defICTM[3] = defCTM[0] * det;
+ defICTM[4] = (defCTM[2] * defCTM[5] - defCTM[3] * defCTM[4]) * det;
+ defICTM[5] = (defCTM[1] * defCTM[4] - defCTM[0] * defCTM[5]) * det;
+}
+
+void OutputDev::cvtDevToUser(double dx, double dy, double *ux, double *uy) {
+ *ux = defICTM[0] * dx + defICTM[2] * dy + defICTM[4];
+ *uy = defICTM[1] * dx + defICTM[3] * dy + defICTM[5];
+}
+
+void OutputDev::cvtUserToDev(double ux, double uy, int *dx, int *dy) {
+ *dx = (int)(defCTM[0] * ux + defCTM[2] * uy + defCTM[4] + 0.5);
+ *dy = (int)(defCTM[1] * ux + defCTM[3] * uy + defCTM[5] + 0.5);
+}
+
+void OutputDev::updateAll(GfxState *state) {
+ updateLineDash(state);
+ updateFlatness(state);
+ updateLineJoin(state);
+ updateLineCap(state);
+ updateMiterLimit(state);
+ updateLineWidth(state);
+ updateStrokeAdjust(state);
+ updateFillColorSpace(state);
+ updateFillColor(state);
+ updateStrokeColorSpace(state);
+ updateStrokeColor(state);
+ updateBlendMode(state);
+ updateFillOpacity(state);
+ updateStrokeOpacity(state);
+ updateFillOverprint(state);
+ updateStrokeOverprint(state);
+ updateTransfer(state);
+ updateFont(state);
+}
+
+GBool OutputDev::beginType3Char(GfxState * /*state*/, double /*x*/, double /*y*/,
+ double /*dx*/, double /*dy*/,
+ CharCode /*code*/, Unicode * /*u*/, int /*uLen*/) {
+ return gFalse;
+}
+
+void OutputDev::drawImageMask(GfxState * /*state*/, Object * /*ref*/, Stream *str,
+ int width, int height, GBool /*invert*/,
+ GBool inlineImg) {
+ int i, j;
+
+ if (inlineImg) {
+ str->reset();
+ j = height * ((width + 7) / 8);
+ for (i = 0; i < j; ++i)
+ str->getChar();
+ str->close();
+ }
+}
+
+void OutputDev::drawImage(GfxState * /*state*/, Object * /*ref*/, Stream *str,
+ int width, int height, GfxImageColorMap *colorMap,
+ int * /*maskColors*/, GBool inlineImg) {
+ int i, j;
+
+ if (inlineImg) {
+ str->reset();
+ j = height * ((width * colorMap->getNumPixelComps() *
+ colorMap->getBits() + 7) / 8);
+ for (i = 0; i < j; ++i)
+ str->getChar();
+ str->close();
+ }
+}
+
+void OutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ Stream * /*maskStr*/,
+ int /*maskWidth*/, int /*maskHeight*/,
+ GBool /*maskInvert*/) {
+ drawImage(state, ref, str, width, height, colorMap, NULL, gFalse);
+}
+
+void OutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ Stream * /*maskStr*/,
+ int /*maskWidth*/, int /*maskHeight*/,
+ GfxImageColorMap * /*maskColorMap*/) {
+ drawImage(state, ref, str, width, height, colorMap, NULL, gFalse);
+}
+
+#if OPI_SUPPORT
+void OutputDev::opiBegin(GfxState *state, Dict *opiDict) {
+}
+
+void OutputDev::opiEnd(GfxState *state, Dict *opiDict) {
+}
+#endif
diff --git a/kpdf/xpdf/xpdf/OutputDev.h b/kpdf/xpdf/xpdf/OutputDev.h
new file mode 100644
index 00000000..a4ee37b1
--- /dev/null
+++ b/kpdf/xpdf/xpdf/OutputDev.h
@@ -0,0 +1,250 @@
+//========================================================================
+//
+// OutputDev.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef OUTPUTDEV_H
+#define OUTPUTDEV_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "CharTypes.h"
+
+class GString;
+class GfxState;
+struct GfxColor;
+class GfxColorSpace;
+class GfxImageColorMap;
+class GfxFunctionShading;
+class GfxAxialShading;
+class GfxRadialShading;
+class Stream;
+class Links;
+class Link;
+class Catalog;
+class Page;
+class Function;
+
+//------------------------------------------------------------------------
+// OutputDev
+//------------------------------------------------------------------------
+
+class OutputDev {
+public:
+
+ // Constructor.
+ OutputDev() {}
+
+ // Destructor.
+ virtual ~OutputDev() {}
+
+ //----- get info about output device
+
+ // Does this device use upside-down coordinates?
+ // (Upside-down means (0,0) is the top left corner of the page.)
+ virtual GBool upsideDown() = 0;
+
+ // Does this device use drawChar() or drawString()?
+ virtual GBool useDrawChar() = 0;
+
+ // Does this device use tilingPatternFill()? If this returns false,
+ // tiling pattern fills will be reduced to a series of other drawing
+ // operations.
+ virtual GBool useTilingPatternFill() { return gFalse; }
+
+ // Does this device use functionShadedFill(), axialShadedFill(), and
+ // radialShadedFill()? If this returns false, these shaded fills
+ // will be reduced to a series of other drawing operations.
+ virtual GBool useShadedFills() { return gFalse; }
+
+ // Does this device use drawForm()? If this returns false,
+ // form-type XObjects will be interpreted (i.e., unrolled).
+ virtual GBool useDrawForm() { return gFalse; }
+
+ // Does this device use beginType3Char/endType3Char? Otherwise,
+ // text in Type 3 fonts will be drawn with drawChar/drawString.
+ virtual GBool interpretType3Chars() = 0;
+
+ // Does this device need non-text content?
+ virtual GBool needNonText() { return gTrue; }
+
+ //----- initialization and control
+
+ // Set default transform matrix.
+ virtual void setDefaultCTM(double *ctm);
+
+ // Check to see if a page slice should be displayed. If this
+ // returns false, the page display is aborted. Typically, an
+ // OutputDev will use some alternate means to display the page
+ // before returning false.
+ virtual GBool checkPageSlice(Page * /*page*/, double /*hDPI*/, double /*vDPI*/,
+ int /*rotate*/, GBool /*useMediaBox*/, GBool /*crop*/,
+ int /*sliceX*/, int /*sliceY*/, int /*sliceW*/, int /*sliceH*/,
+ GBool /*printing*/, Catalog * /*catalog*/,
+ GBool (* /*abortCheckCbk*/)(void *data) = NULL,
+ void * /*abortCheckCbkData*/ = NULL)
+ { return gTrue; }
+
+ // Start a page.
+ virtual void startPage(int /*pageNum*/, GfxState * /*state*/) {}
+
+ // End a page.
+ virtual void endPage() {}
+
+ // Dump page contents to display.
+ virtual void dump() {}
+
+ //----- coordinate conversion
+
+ // Convert between device and user coordinates.
+ virtual void cvtDevToUser(double dx, double dy, double *ux, double *uy);
+ virtual void cvtUserToDev(double ux, double uy, int *dx, int *dy);
+
+ double *getDefCTM() { return defCTM; }
+ double *getDefICTM() { return defICTM; }
+
+ //----- save/restore graphics state
+ virtual void saveState(GfxState * /*state*/) {}
+ virtual void restoreState(GfxState * /*state*/) {}
+
+ //----- update graphics state
+ virtual void updateAll(GfxState *state);
+ virtual void updateCTM(GfxState * /*state*/, double /*m11*/, double /*m12*/,
+ double /*m21*/, double /*m22*/, double /*m31*/, double /*m32*/) {}
+ virtual void updateLineDash(GfxState * /*state*/) {}
+ virtual void updateFlatness(GfxState * /*state*/) {}
+ virtual void updateLineJoin(GfxState * /*state*/) {}
+ virtual void updateLineCap(GfxState * /*state*/) {}
+ virtual void updateMiterLimit(GfxState * /*state*/) {}
+ virtual void updateLineWidth(GfxState * /*state*/) {}
+ virtual void updateStrokeAdjust(GfxState * /*state*/) {}
+ virtual void updateFillColorSpace(GfxState * /*state*/) {}
+ virtual void updateStrokeColorSpace(GfxState * /*state*/) {}
+ virtual void updateFillColor(GfxState * /*state*/) {}
+ virtual void updateStrokeColor(GfxState * /*state*/) {}
+ virtual void updateBlendMode(GfxState * /*state*/) {}
+ virtual void updateFillOpacity(GfxState * /*state*/) {}
+ virtual void updateStrokeOpacity(GfxState * /*state*/) {}
+ virtual void updateFillOverprint(GfxState * /*state*/) {}
+ virtual void updateStrokeOverprint(GfxState * /*state*/) {}
+ virtual void updateTransfer(GfxState * /*state*/) {}
+
+ //----- update text state
+ virtual void updateFont(GfxState * /*state*/) {}
+ virtual void updateTextMat(GfxState * /*state*/) {}
+ virtual void updateCharSpace(GfxState * /*state*/) {}
+ virtual void updateRender(GfxState * /*state*/) {}
+ virtual void updateRise(GfxState * /*state*/) {}
+ virtual void updateWordSpace(GfxState * /*state*/) {}
+ virtual void updateHorizScaling(GfxState * /*state*/) {}
+ virtual void updateTextPos(GfxState * /*state*/) {}
+ virtual void updateTextShift(GfxState * /*state*/, double /*shift*/) {}
+
+ //----- path painting
+ virtual void stroke(GfxState * /*state*/) {}
+ virtual void fill(GfxState * /*state*/) {}
+ virtual void eoFill(GfxState * /*state*/) {}
+ virtual void tilingPatternFill(GfxState * /*state*/, Object * /*str*/,
+ int /*paintType*/, Dict * /*resDict*/,
+ double * /*mat*/, double * /*bbox*/,
+ int /*x0*/, int /*y0*/, int /*x1*/, int /*y1*/,
+ double /*xStep*/, double /*yStep*/) {}
+ virtual GBool functionShadedFill(GfxState * /*state*/,
+ GfxFunctionShading * /*shading*/)
+ { return gFalse; }
+ virtual GBool axialShadedFill(GfxState * /*state*/, GfxAxialShading * /*shading*/)
+ { return gFalse; }
+ virtual GBool radialShadedFill(GfxState * /*state*/, GfxRadialShading * /*shading*/)
+ { return gFalse; }
+
+ //----- path clipping
+ virtual void clip(GfxState * /*state*/) {}
+ virtual void eoClip(GfxState * /*state*/) {}
+ virtual void clipToStrokePath(GfxState * /*state*/) {}
+
+ //----- text drawing
+ virtual void beginStringOp(GfxState * /*state*/) {}
+ virtual void endStringOp(GfxState * /*state*/) {}
+ virtual void beginString(GfxState * /*state*/, GString * /*s*/) {}
+ virtual void endString(GfxState * /*state*/) {}
+ virtual void drawChar(GfxState * /*state*/, double /*x*/, double /*y*/,
+ double /*dx*/, double /*dy*/,
+ double /*originX*/, double /*originY*/,
+ CharCode /*code*/, int /*nBytes*/, Unicode * /*u*/, int /*uLen*/) {}
+ virtual void drawString(GfxState * /*state*/, GString * /*s*/) {}
+ virtual GBool beginType3Char(GfxState *state, double x, double y,
+ double dx, double dy,
+ CharCode code, Unicode *u, int uLen);
+ virtual void endType3Char(GfxState * /*state*/) {}
+ virtual void endTextObject(GfxState * /*state*/) {}
+
+ //----- image drawing
+ virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool inlineImg);
+ virtual void drawImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GfxImageColorMap *colorMap,
+ int *maskColors, GBool inlineImg);
+ virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ Stream *maskStr, int maskWidth, int maskHeight,
+ GBool maskInvert);
+ virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ Stream *maskStr,
+ int maskWidth, int maskHeight,
+ GfxImageColorMap *maskColorMap);
+
+#if OPI_SUPPORT
+ //----- OPI functions
+ virtual void opiBegin(GfxState *state, Dict *opiDict);
+ virtual void opiEnd(GfxState *state, Dict *opiDict);
+#endif
+
+ //----- Type 3 font operators
+ virtual void type3D0(GfxState * /*state*/, double /*wx*/, double /*wy*/) {}
+ virtual void type3D1(GfxState * /*state*/, double /*wx*/, double /*wy*/,
+ double /*llx*/, double /*lly*/, double /*urx*/, double /*ury*/) {}
+
+ //----- form XObjects
+ virtual void drawForm(Ref /*id*/) {}
+
+ //----- PostScript XObjects
+ virtual void psXObject(Stream * /*psStream*/, Stream * /*level1Stream*/) {}
+
+ //----- transparency groups and soft masks
+ virtual void beginTransparencyGroup(GfxState * /*state*/, double * /*bbox*/,
+ GfxColorSpace * /*blendingColorSpace*/,
+ GBool /*isolated*/, GBool /*knockout*/,
+ GBool /*forSoftMask*/) {}
+ virtual void endTransparencyGroup(GfxState * /*state*/) {}
+ virtual void paintTransparencyGroup(GfxState * /*state*/, double * /*bbox*/) {}
+ virtual void setSoftMask(GfxState * /*state*/, double * /*bbox*/, GBool /*alpha*/,
+ Function * /*transferFunc*/, GfxColor * /*backdropColor*/) {}
+ virtual void clearSoftMask(GfxState * /*state*/) {}
+
+ //----- links
+ virtual void processLink(Link * /*link*/, Catalog * /*catalog*/) {}
+
+#if 1 //~tmp: turn off anti-aliasing temporarily
+ virtual GBool getVectorAntialias() { return gFalse; }
+ virtual void setVectorAntialias(GBool /*vaa*/) {}
+#endif
+
+private:
+
+ double defCTM[6]; // default coordinate transform matrix
+ double defICTM[6]; // inverse of default CTM
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/PDFDoc.cc b/kpdf/xpdf/xpdf/PDFDoc.cc
new file mode 100644
index 00000000..dc24d97e
--- /dev/null
+++ b/kpdf/xpdf/xpdf/PDFDoc.cc
@@ -0,0 +1,433 @@
+//========================================================================
+//
+// PDFDoc.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#ifdef WIN32
+# include <windows.h>
+#endif
+#include "GString.h"
+#include "config.h"
+#include "GlobalParams.h"
+#include "Page.h"
+#include "Catalog.h"
+#include "Stream.h"
+#include "XRef.h"
+#include "Link.h"
+#include "OutputDev.h"
+#include "Error.h"
+#include "ErrorCodes.h"
+#include "Lexer.h"
+#include "Parser.h"
+#include "SecurityHandler.h"
+#ifndef DISABLE_OUTLINE
+#include "Outline.h"
+#endif
+#include "PDFDoc.h"
+
+//------------------------------------------------------------------------
+
+#define headerSearchSize 1024 // read this many bytes at beginning of
+ // file to look for '%PDF'
+
+//------------------------------------------------------------------------
+// PDFDoc
+//------------------------------------------------------------------------
+
+PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword,
+ GString *userPassword, void *guiDataA) {
+ Object obj;
+ GString *fileName1, *fileName2;
+
+ ok = gFalse;
+ errCode = errNone;
+
+ guiData = guiDataA;
+
+ file = NULL;
+ str = NULL;
+ xref = NULL;
+ catalog = NULL;
+#ifndef DISABLE_OUTLINE
+ outline = NULL;
+#endif
+
+ fileName = fileNameA;
+ fileName1 = fileName;
+
+
+ // try to open file
+ fileName2 = NULL;
+#ifdef VMS
+ if (!(file = fopen(fileName1->getCString(), "rb", "ctx=stm"))) {
+ error(-1, "Couldn't open file '%s'", fileName1->getCString());
+ errCode = errOpenFile;
+ return;
+ }
+#else
+ if (!(file = fopen(fileName1->getCString(), "rb"))) {
+ fileName2 = fileName->copy();
+ fileName2->lowerCase();
+ if (!(file = fopen(fileName2->getCString(), "rb"))) {
+ fileName2->upperCase();
+ if (!(file = fopen(fileName2->getCString(), "rb"))) {
+ error(-1, "Couldn't open file '%s'", fileName->getCString());
+ delete fileName2;
+ errCode = errOpenFile;
+ return;
+ }
+ }
+ delete fileName2;
+ }
+#endif
+
+ // create stream
+ obj.initNull();
+ str = new FileStream(file, 0, gFalse, 0, &obj);
+
+ ok = setup(ownerPassword, userPassword);
+}
+
+#ifdef WIN32
+PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword,
+ GString *userPassword, void *guiDataA) {
+ OSVERSIONINFO version;
+ wchar_t fileName2[_MAX_PATH + 1];
+ Object obj;
+ int i;
+
+ ok = gFalse;
+ errCode = errNone;
+
+ guiData = guiDataA;
+
+ file = NULL;
+ str = NULL;
+ xref = NULL;
+ catalog = NULL;
+#ifndef DISABLE_OUTLINE
+ outline = NULL;
+#endif
+
+ //~ file name should be stored in Unicode (?)
+ fileName = new GString();
+ for (i = 0; i < fileNameLen; ++i) {
+ fileName->append((char)fileNameA[i]);
+ }
+
+ // zero-terminate the file name string
+ for (i = 0; i < fileNameLen && i < _MAX_PATH; ++i) {
+ fileName2[i] = fileNameA[i];
+ }
+ fileName2[i] = 0;
+
+ // try to open file
+ // NB: _wfopen is only available in NT
+ version.dwOSVersionInfoSize = sizeof(version);
+ GetVersionEx(&version);
+ if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
+ file = _wfopen(fileName2, L"rb");
+ } else {
+ file = fopen(fileName->getCString(), "rb");
+ }
+ if (!file) {
+ error(-1, "Couldn't open file '%s'", fileName->getCString());
+ errCode = errOpenFile;
+ return;
+ }
+
+ // create stream
+ obj.initNull();
+ str = new FileStream(file, 0, gFalse, 0, &obj);
+
+ ok = setup(ownerPassword, userPassword);
+}
+#endif
+
+PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword,
+ GString *userPassword, void *guiDataA) {
+ ok = gFalse;
+ errCode = errNone;
+ guiData = guiDataA;
+ if (strA->getFileName()) {
+ fileName = strA->getFileName()->copy();
+ } else {
+ fileName = NULL;
+ }
+ file = NULL;
+ str = strA;
+ xref = NULL;
+ catalog = NULL;
+#ifndef DISABLE_OUTLINE
+ outline = NULL;
+#endif
+ ok = setup(ownerPassword, userPassword);
+}
+
+GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) {
+ str->reset();
+
+ char *eof = new char[1025];
+ int pos = str->getPos();
+ str->setPos(1024, -1);
+ int i, ch;
+ for (i = 0; i < 1024; i++)
+ {
+ ch = str->getChar();
+ if (ch == EOF)
+ break;
+ eof[i] = ch;
+ }
+ eof[i] = '\0';
+
+ bool found = false;
+ for (i = i - 5; i >= 0; i--) {
+ if (strncmp (&eof[i], "%%EOF", 5) == 0) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ {
+ error(-1, "Document does not have ending %%EOF");
+ errCode = errDamaged;
+ delete[] eof;
+ return gFalse;
+ }
+ delete[] eof;
+
+ str->setPos(pos);
+
+ // check header
+ checkHeader();
+
+ // read xref table
+ xref = new XRef(str);
+ if (!xref->isOk()) {
+ error(-1, "Couldn't read xref table");
+ errCode = xref->getErrorCode();
+ return gFalse;
+ }
+
+ // check for encryption
+ if (!checkEncryption(ownerPassword, userPassword)) {
+ errCode = errEncrypted;
+ return gFalse;
+ }
+
+ // read catalog
+ catalog = new Catalog(xref);
+ if (!catalog->isOk()) {
+ error(-1, "Couldn't read page catalog");
+ errCode = errBadCatalog;
+ return gFalse;
+ }
+
+#ifndef DISABLE_OUTLINE
+ // read outline
+ outline = new Outline(catalog->getOutline(), xref);
+#endif
+
+ // done
+ return gTrue;
+}
+
+PDFDoc::~PDFDoc() {
+#ifndef DISABLE_OUTLINE
+ if (outline) {
+ delete outline;
+ }
+#endif
+ if (catalog) {
+ delete catalog;
+ }
+ if (xref) {
+ delete xref;
+ }
+ if (str) {
+ delete str;
+ }
+ if (file) {
+ fclose(file);
+ }
+ if (fileName) {
+ delete fileName;
+ }
+}
+
+// Check for a PDF header on this stream. Skip past some garbage
+// if necessary.
+void PDFDoc::checkHeader() {
+ char hdrBuf[headerSearchSize+1];
+ char *p;
+ int i;
+
+ pdfVersion = 0;
+ for (i = 0; i < headerSearchSize; ++i) {
+ hdrBuf[i] = str->getChar();
+ }
+ hdrBuf[headerSearchSize] = '\0';
+ for (i = 0; i < headerSearchSize - 5; ++i) {
+ if (!strncmp(&hdrBuf[i], "%PDF-", 5)) {
+ break;
+ }
+ }
+ if (i >= headerSearchSize - 5) {
+ error(-1, "May not be a PDF file (continuing anyway)");
+ return;
+ }
+ str->moveStart(i);
+ if (!(p = strtok(&hdrBuf[i+5], " \t\n\r"))) {
+ error(-1, "May not be a PDF file (continuing anyway)");
+ return;
+ }
+ pdfVersion = atof(p);
+ if (!(hdrBuf[i+5] >= '0' && hdrBuf[i+5] <= '9') ||
+ pdfVersion > supportedPDFVersionNum + 0.0001) {
+ error(-1, "PDF version %s -- xpdf supports version %s"
+ " (continuing anyway)", p, supportedPDFVersionStr);
+ }
+}
+
+GBool PDFDoc::checkEncryption(GString *ownerPassword, GString *userPassword) {
+ Object encrypt;
+ GBool encrypted;
+ SecurityHandler *secHdlr;
+ GBool ret;
+
+ xref->getTrailerDict()->dictLookup("Encrypt", &encrypt);
+ if ((encrypted = encrypt.isDict())) {
+ if ((secHdlr = SecurityHandler::make(this, &encrypt))) {
+ if (secHdlr->checkEncryption(ownerPassword, userPassword)) {
+ // authorization succeeded
+ xref->setEncryption(secHdlr->getPermissionFlags(),
+ secHdlr->getOwnerPasswordOk(),
+ secHdlr->getFileKey(),
+ secHdlr->getFileKeyLength(),
+ secHdlr->getEncVersion(),
+ secHdlr->getEncAlgorithm());
+ ret = gTrue;
+ } else {
+ // authorization failed
+ ret = gFalse;
+ }
+ delete secHdlr;
+ } else {
+ // couldn't find the matching security handler
+ ret = gFalse;
+ }
+ } else {
+ // document is not encrypted
+ ret = gTrue;
+ }
+ encrypt.free();
+ return ret;
+}
+
+void PDFDoc::displayPage(OutputDev *out, int page,
+ double hDPI, double vDPI, int rotate,
+ GBool useMediaBox, GBool crop, GBool printing,
+ GBool (*abortCheckCbk)(void *data),
+ void *abortCheckCbkData) {
+ if (globalParams->getPrintCommands()) {
+ printf("***** page %d *****\n", page);
+ }
+ catalog->getPage(page)->display(out, hDPI, vDPI,
+ rotate, useMediaBox, crop, printing, catalog,
+ abortCheckCbk, abortCheckCbkData);
+}
+
+void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage,
+ double hDPI, double vDPI, int rotate,
+ GBool useMediaBox, GBool crop, GBool printing,
+ GBool (*abortCheckCbk)(void *data),
+ void *abortCheckCbkData) {
+ int page;
+
+ for (page = firstPage; page <= lastPage; ++page) {
+ displayPage(out, page, hDPI, vDPI, rotate, useMediaBox, crop, printing,
+ abortCheckCbk, abortCheckCbkData);
+ }
+}
+
+void PDFDoc::displayPageSlice(OutputDev *out, int page,
+ double hDPI, double vDPI, int rotate,
+ GBool useMediaBox, GBool crop, GBool printing,
+ int sliceX, int sliceY, int sliceW, int sliceH,
+ GBool (*abortCheckCbk)(void *data),
+ void *abortCheckCbkData) {
+ catalog->getPage(page)->displaySlice(out, hDPI, vDPI,
+ rotate, useMediaBox, crop,
+ sliceX, sliceY, sliceW, sliceH,
+ printing, catalog,
+ abortCheckCbk, abortCheckCbkData);
+}
+
+Links *PDFDoc::getLinks(int page) {
+ return catalog->getPage(page)->getLinks(catalog);
+}
+
+void PDFDoc::processLinks(OutputDev *out, int page) {
+ catalog->getPage(page)->processLinks(out, catalog);
+}
+
+GBool PDFDoc::isLinearized() {
+ Parser *parser;
+ Object obj1, obj2, obj3, obj4, obj5;
+ GBool lin;
+
+ lin = gFalse;
+ obj1.initNull();
+ parser = new Parser(xref,
+ new Lexer(xref,
+ str->makeSubStream(str->getStart(), gFalse, 0, &obj1)),
+ gTrue);
+ parser->getObj(&obj1);
+ parser->getObj(&obj2);
+ parser->getObj(&obj3);
+ parser->getObj(&obj4);
+ if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") &&
+ obj4.isDict()) {
+ obj4.dictLookup("Linearized", &obj5);
+ if (obj5.isNum() && obj5.getNum() > 0) {
+ lin = gTrue;
+ }
+ obj5.free();
+ }
+ obj4.free();
+ obj3.free();
+ obj2.free();
+ obj1.free();
+ delete parser;
+ return lin;
+}
+
+GBool PDFDoc::saveAs(GString *name) {
+ FILE *f;
+ int c;
+
+ if (!(f = fopen(name->getCString(), "wb"))) {
+ error(-1, "Couldn't open file '%s'", name->getCString());
+ return gFalse;
+ }
+ str->reset();
+ while ((c = str->getChar()) != EOF) {
+ fputc(c, f);
+ }
+ str->close();
+ fclose(f);
+ return gTrue;
+}
diff --git a/kpdf/xpdf/xpdf/PDFDoc.h b/kpdf/xpdf/xpdf/PDFDoc.h
new file mode 100644
index 00000000..208b61ef
--- /dev/null
+++ b/kpdf/xpdf/xpdf/PDFDoc.h
@@ -0,0 +1,183 @@
+//========================================================================
+//
+// PDFDoc.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef PDFDOC_H
+#define PDFDOC_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include <stdio.h>
+#include "XRef.h"
+#include "Catalog.h"
+#include "Page.h"
+
+class GString;
+class BaseStream;
+class OutputDev;
+class Links;
+class LinkAction;
+class LinkDest;
+class Outline;
+
+//------------------------------------------------------------------------
+// PDFDoc
+//------------------------------------------------------------------------
+
+class PDFDoc {
+public:
+
+ PDFDoc(GString *fileNameA, GString *ownerPassword = NULL,
+ GString *userPassword = NULL, void *guiDataA = NULL);
+#ifdef WIN32
+ PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword = NULL,
+ GString *userPassword = NULL, void *guiDataA = NULL);
+#endif
+ PDFDoc(BaseStream *strA, GString *ownerPassword = NULL,
+ GString *userPassword = NULL, void *guiDataA = NULL);
+ ~PDFDoc();
+
+ // Was PDF document successfully opened?
+ GBool isOk() { return ok; }
+
+ // Get the error code (if isOk() returns false).
+ int getErrorCode() { return errCode; }
+
+ // Get file name.
+ GString *getFileName() { return fileName; }
+
+ // Get the xref table.
+ XRef *getXRef() { return xref; }
+
+ // Get catalog.
+ Catalog *getCatalog() { return catalog; }
+
+ // Get base stream.
+ BaseStream *getBaseStream() { return str; }
+
+ // Get page parameters.
+ double getPageMediaWidth(int page)
+ { return catalog->getPage(page)->getMediaWidth(); }
+ double getPageMediaHeight(int page)
+ { return catalog->getPage(page)->getMediaHeight(); }
+ double getPageCropWidth(int page)
+ { return catalog->getPage(page)->getCropWidth(); }
+ double getPageCropHeight(int page)
+ { return catalog->getPage(page)->getCropHeight(); }
+ int getPageRotate(int page)
+ { return catalog->getPage(page)->getRotate(); }
+
+ // Get number of pages.
+ int getNumPages() { return catalog->getNumPages(); }
+
+ // Return the contents of the metadata stream, or NULL if there is
+ // no metadata.
+ GString *readMetadata() { return catalog->readMetadata(); }
+
+ // Return the structure tree root object.
+ Object *getStructTreeRoot() { return catalog->getStructTreeRoot(); }
+
+ // Display a page.
+ void displayPage(OutputDev *out, int page,
+ double hDPI, double vDPI, int rotate,
+ GBool useMediaBox, GBool crop, GBool printing,
+ GBool (*abortCheckCbk)(void *data) = NULL,
+ void *abortCheckCbkData = NULL);
+
+ // Display a range of pages.
+ void displayPages(OutputDev *out, int firstPage, int lastPage,
+ double hDPI, double vDPI, int rotate,
+ GBool useMediaBox, GBool crop, GBool printing,
+ GBool (*abortCheckCbk)(void *data) = NULL,
+ void *abortCheckCbkData = NULL);
+
+ // Display part of a page.
+ void displayPageSlice(OutputDev *out, int page,
+ double hDPI, double vDPI, int rotate,
+ GBool useMediaBox, GBool crop, GBool printing,
+ int sliceX, int sliceY, int sliceW, int sliceH,
+ GBool (*abortCheckCbk)(void *data) = NULL,
+ void *abortCheckCbkData = NULL);
+
+ // Find a page, given its object ID. Returns page number, or 0 if
+ // not found.
+ int findPage(int num, int gen) { return catalog->findPage(num, gen); }
+
+ // Returns the links for the current page, transferring ownership to
+ // the caller.
+ Links *getLinks(int page);
+
+ // Find a named destination. Returns the link destination, or
+ // NULL if <name> is not a destination.
+ LinkDest *findDest(GString *name)
+ { return catalog->findDest(name); }
+
+ // Process the links for a page.
+ void processLinks(OutputDev *out, int page);
+
+#ifndef DISABLE_OUTLINE
+ // Return the outline object.
+ Outline *getOutline() { return outline; }
+#endif
+
+ // Is the file encrypted?
+ GBool isEncrypted() { return xref->isEncrypted(); }
+
+ // Check various permissions.
+ GBool okToPrint(GBool ignoreOwnerPW = gFalse)
+ { return xref->okToPrint(ignoreOwnerPW); }
+ GBool okToChange(GBool ignoreOwnerPW = gFalse)
+ { return xref->okToChange(ignoreOwnerPW); }
+ GBool okToCopy(GBool ignoreOwnerPW = gFalse)
+ { return xref->okToCopy(ignoreOwnerPW); }
+ GBool okToAddNotes(GBool ignoreOwnerPW = gFalse)
+ { return xref->okToAddNotes(ignoreOwnerPW); }
+
+ // Is this document linearized?
+ GBool isLinearized();
+
+ // Return the document's Info dictionary (if any).
+ Object *getDocInfo(Object *obj) { return xref->getDocInfo(obj); }
+ Object *getDocInfoNF(Object *obj) { return xref->getDocInfoNF(obj); }
+
+ // Return the PDF version specified by the file.
+ double getPDFVersion() { return pdfVersion; }
+
+ // Save this file with another name.
+ GBool saveAs(GString *name);
+
+ // Return a pointer to the GUI (XPDFCore or WinPDFCore object).
+ void *getGUIData() { return guiData; }
+
+
+private:
+
+ GBool setup(GString *ownerPassword, GString *userPassword);
+ void checkHeader();
+ GBool checkEncryption(GString *ownerPassword, GString *userPassword);
+
+ GString *fileName;
+ FILE *file;
+ BaseStream *str;
+ void *guiData;
+ double pdfVersion;
+ XRef *xref;
+ Catalog *catalog;
+#ifndef DISABLE_OUTLINE
+ Outline *outline;
+#endif
+
+
+ GBool ok;
+ int errCode;
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/PDFDocEncoding.cc b/kpdf/xpdf/xpdf/PDFDocEncoding.cc
new file mode 100644
index 00000000..89dc3828
--- /dev/null
+++ b/kpdf/xpdf/xpdf/PDFDocEncoding.cc
@@ -0,0 +1,44 @@
+//========================================================================
+//
+// PDFDocEncoding.h
+//
+// Copyright 2002-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include "PDFDocEncoding.h"
+
+Unicode pdfDocEncoding[256] = {
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 00
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 10
+ 0x02d8, 0x02c7, 0x02c6, 0x02d9, 0x02dd, 0x02db, 0x02da, 0x02dc,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, // 20
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, // 30
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, // 40
+ 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
+ 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, // 50
+ 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, // 60
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, // 70
+ 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x0000,
+ 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x0192, 0x2044, // 80
+ 0x2039, 0x203a, 0x2212, 0x2030, 0x201e, 0x201c, 0x201d, 0x2018,
+ 0x2019, 0x201a, 0x2122, 0xfb01, 0xfb02, 0x0141, 0x0152, 0x0160, // 90
+ 0x0178, 0x017d, 0x0131, 0x0142, 0x0153, 0x0161, 0x017e, 0x0000,
+ 0x20ac, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, // a0
+ 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x0000, 0x00ae, 0x00af,
+ 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, // b0
+ 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
+ 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, // c0
+ 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf,
+ 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, // d0
+ 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df,
+ 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, // e0
+ 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+ 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, // f0
+ 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
+};
diff --git a/kpdf/xpdf/xpdf/PDFDocEncoding.h b/kpdf/xpdf/xpdf/PDFDocEncoding.h
new file mode 100644
index 00000000..3259d3e1
--- /dev/null
+++ b/kpdf/xpdf/xpdf/PDFDocEncoding.h
@@ -0,0 +1,16 @@
+//========================================================================
+//
+// PDFDocEncoding.h
+//
+// Copyright 2002-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef PDFDOCENCODING_H
+#define PDFDOCENCODING_H
+
+#include "CharTypes.h"
+
+extern Unicode pdfDocEncoding[256];
+
+#endif
diff --git a/kpdf/xpdf/xpdf/PSOutputDev.cc b/kpdf/xpdf/xpdf/PSOutputDev.cc
new file mode 100644
index 00000000..d35739a5
--- /dev/null
+++ b/kpdf/xpdf/xpdf/PSOutputDev.cc
@@ -0,0 +1,6307 @@
+//========================================================================
+//
+// PSOutputDev.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+#include <locale.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <math.h>
+#include "GString.h"
+#include "GList.h"
+#include "config.h"
+#include "GlobalParams.h"
+#include "Object.h"
+#include "Error.h"
+#include "Function.h"
+#include "Gfx.h"
+#include "GfxState.h"
+#include "GfxFont.h"
+#include "UnicodeMap.h"
+#include "FoFiType1C.h"
+#include "FoFiTrueType.h"
+#include "Catalog.h"
+#include "Page.h"
+#include "Stream.h"
+#include "Annot.h"
+#include "XRef.h"
+#include "PreScanOutputDev.h"
+#if HAVE_SPLASH
+# include "Splash.h"
+# include "SplashBitmap.h"
+# include "SplashOutputDev.h"
+#endif
+#include "PSOutputDev.h"
+
+#ifdef MACOS
+// needed for setting type/creator of MacOS files
+#include "ICSupport.h"
+#endif
+
+// the MSVC math.h doesn't define this
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+//------------------------------------------------------------------------
+
+// Resolution at which pages with transparency will be rasterized.
+#define splashDPI 300
+
+//------------------------------------------------------------------------
+// PostScript prolog and setup
+//------------------------------------------------------------------------
+
+// The '~' escapes mark prolog code that is emitted only in certain
+// levels:
+//
+// ~[123][sn]
+// ^ ^----- s=psLevel*Sep, n=psLevel*
+// +----- 1=psLevel1*, 2=psLevel2*, 3=psLevel3*
+
+static char *prolog[] = {
+ "/xpdf 75 dict def xpdf begin",
+ "% PDF special state",
+ "/pdfDictSize 15 def",
+ "~1sn",
+ "/pdfStates 64 array def",
+ " 0 1 63 {",
+ " pdfStates exch pdfDictSize dict",
+ " dup /pdfStateIdx 3 index put",
+ " put",
+ " } for",
+ "~123sn",
+ "/pdfSetup {",
+ " 3 1 roll 2 array astore",
+ " /setpagedevice where {",
+ " pop 3 dict begin",
+ " /PageSize exch def",
+ " /ImagingBBox null def",
+ " /Policies 1 dict dup begin /PageSize 3 def end def",
+ " { /Duplex true def } if",
+ " currentdict end setpagedevice",
+ " } {",
+ " pop pop",
+ " } ifelse",
+ "} def",
+ "~1sn",
+ "/pdfOpNames [",
+ " /pdfFill /pdfStroke /pdfLastFill /pdfLastStroke",
+ " /pdfTextMat /pdfFontSize /pdfCharSpacing /pdfTextRender",
+ " /pdfTextRise /pdfWordSpacing /pdfHorizScaling /pdfTextClipPath",
+ "] def",
+ "~123sn",
+ "/pdfStartPage {",
+ "~1sn",
+ " pdfStates 0 get begin",
+ "~23sn",
+ " pdfDictSize dict begin",
+ "~23n",
+ " /pdfFillCS [] def",
+ " /pdfFillXform {} def",
+ " /pdfStrokeCS [] def",
+ " /pdfStrokeXform {} def",
+ "~1n",
+ " /pdfFill 0 def",
+ " /pdfStroke 0 def",
+ "~1s",
+ " /pdfFill [0 0 0 1] def",
+ " /pdfStroke [0 0 0 1] def",
+ "~23sn",
+ " /pdfFill [0] def",
+ " /pdfStroke [0] def",
+ " /pdfFillOP false def",
+ " /pdfStrokeOP false def",
+ "~123sn",
+ " /pdfLastFill false def",
+ " /pdfLastStroke false def",
+ " /pdfTextMat [1 0 0 1 0 0] def",
+ " /pdfFontSize 0 def",
+ " /pdfCharSpacing 0 def",
+ " /pdfTextRender 0 def",
+ " /pdfTextRise 0 def",
+ " /pdfWordSpacing 0 def",
+ " /pdfHorizScaling 1 def",
+ " /pdfTextClipPath [] def",
+ "} def",
+ "/pdfEndPage { end } def",
+ "~23s",
+ "% separation convention operators",
+ "/findcmykcustomcolor where {",
+ " pop",
+ "}{",
+ " /findcmykcustomcolor { 5 array astore } def",
+ "} ifelse",
+ "/setcustomcolor where {",
+ " pop",
+ "}{",
+ " /setcustomcolor {",
+ " exch",
+ " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
+ " 0 4 getinterval cvx",
+ " [ exch /dup load exch { mul exch dup } /forall load",
+ " /pop load dup ] cvx",
+ " ] setcolorspace setcolor",
+ " } def",
+ "} ifelse",
+ "/customcolorimage where {",
+ " pop",
+ "}{",
+ " /customcolorimage {",
+ " gsave",
+ " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
+ " 0 4 getinterval",
+ " [ exch /dup load exch { mul exch dup } /forall load",
+ " /pop load dup ] cvx",
+ " ] setcolorspace",
+ " 10 dict begin",
+ " /ImageType 1 def",
+ " /DataSource exch def",
+ " /ImageMatrix exch def",
+ " /BitsPerComponent exch def",
+ " /Height exch def",
+ " /Width exch def",
+ " /Decode [1 0] def",
+ " currentdict end",
+ " image",
+ " grestore",
+ " } def",
+ "} ifelse",
+ "~123sn",
+ "% PDF color state",
+ "~1n",
+ "/g { dup /pdfFill exch def setgray",
+ " /pdfLastFill true def /pdfLastStroke false def } def",
+ "/G { dup /pdfStroke exch def setgray",
+ " /pdfLastStroke true def /pdfLastFill false def } def",
+ "/fCol {",
+ " pdfLastFill not {",
+ " pdfFill setgray",
+ " /pdfLastFill true def /pdfLastStroke false def",
+ " } if",
+ "} def",
+ "/sCol {",
+ " pdfLastStroke not {",
+ " pdfStroke setgray",
+ " /pdfLastStroke true def /pdfLastFill false def",
+ " } if",
+ "} def",
+ "~1s",
+ "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor",
+ " /pdfLastFill true def /pdfLastStroke false def } def",
+ "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor",
+ " /pdfLastStroke true def /pdfLastFill false def } def",
+ "/fCol {",
+ " pdfLastFill not {",
+ " pdfFill aload pop setcmykcolor",
+ " /pdfLastFill true def /pdfLastStroke false def",
+ " } if",
+ "} def",
+ "/sCol {",
+ " pdfLastStroke not {",
+ " pdfStroke aload pop setcmykcolor",
+ " /pdfLastStroke true def /pdfLastFill false def",
+ " } if",
+ "} def",
+ "~23n",
+ "/cs { /pdfFillXform exch def dup /pdfFillCS exch def",
+ " setcolorspace } def",
+ "/CS { /pdfStrokeXform exch def dup /pdfStrokeCS exch def",
+ " setcolorspace } def",
+ "/sc { pdfLastFill not { pdfFillCS setcolorspace } if",
+ " dup /pdfFill exch def aload pop pdfFillXform setcolor",
+ " /pdfLastFill true def /pdfLastStroke false def } def",
+ "/SC { pdfLastStroke not { pdfStrokeCS setcolorspace } if",
+ " dup /pdfStroke exch def aload pop pdfStrokeXform setcolor",
+ " /pdfLastStroke true def /pdfLastFill false def } def",
+ "/op { /pdfFillOP exch def",
+ " pdfLastFill { pdfFillOP setoverprint } if } def",
+ "/OP { /pdfStrokeOP exch def",
+ " pdfLastStroke { pdfStrokeOP setoverprint } if } def",
+ "/fCol {",
+ " pdfLastFill not {",
+ " pdfFillCS setcolorspace",
+ " pdfFill aload pop pdfFillXform setcolor",
+ " pdfFillOP setoverprint",
+ " /pdfLastFill true def /pdfLastStroke false def",
+ " } if",
+ "} def",
+ "/sCol {",
+ " pdfLastStroke not {",
+ " pdfStrokeCS setcolorspace",
+ " pdfStroke aload pop pdfStrokeXform setcolor",
+ " pdfStrokeOP setoverprint",
+ " /pdfLastStroke true def /pdfLastFill false def",
+ " } if",
+ "} def",
+ "~23s",
+ "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor",
+ " /pdfLastFill true def /pdfLastStroke false def } def",
+ "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor",
+ " /pdfLastStroke true def /pdfLastFill false def } def",
+ "/ck { 6 copy 6 array astore /pdfFill exch def",
+ " findcmykcustomcolor exch setcustomcolor",
+ " /pdfLastFill true def /pdfLastStroke false def } def",
+ "/CK { 6 copy 6 array astore /pdfStroke exch def",
+ " findcmykcustomcolor exch setcustomcolor",
+ " /pdfLastStroke true def /pdfLastFill false def } def",
+ "/op { /pdfFillOP exch def",
+ " pdfLastFill { pdfFillOP setoverprint } if } def",
+ "/OP { /pdfStrokeOP exch def",
+ " pdfLastStroke { pdfStrokeOP setoverprint } if } def",
+ "/fCol {",
+ " pdfLastFill not {",
+ " pdfFill aload length 4 eq {",
+ " setcmykcolor",
+ " }{",
+ " findcmykcustomcolor exch setcustomcolor",
+ " } ifelse",
+ " pdfFillOP setoverprint",
+ " /pdfLastFill true def /pdfLastStroke false def",
+ " } if",
+ "} def",
+ "/sCol {",
+ " pdfLastStroke not {",
+ " pdfStroke aload length 4 eq {",
+ " setcmykcolor",
+ " }{",
+ " findcmykcustomcolor exch setcustomcolor",
+ " } ifelse",
+ " pdfStrokeOP setoverprint",
+ " /pdfLastStroke true def /pdfLastFill false def",
+ " } if",
+ "} def",
+ "~123sn",
+ "% build a font",
+ "/pdfMakeFont {",
+ " 4 3 roll findfont",
+ " 4 2 roll matrix scale makefont",
+ " dup length dict begin",
+ " { 1 index /FID ne { def } { pop pop } ifelse } forall",
+ " /Encoding exch def",
+ " currentdict",
+ " end",
+ " definefont pop",
+ "} def",
+ "/pdfMakeFont16 {",
+ " exch findfont",
+ " dup length dict begin",
+ " { 1 index /FID ne { def } { pop pop } ifelse } forall",
+ " /WMode exch def",
+ " currentdict",
+ " end",
+ " definefont pop",
+ "} def",
+ "~3sn",
+ "/pdfMakeFont16L3 {",
+ " 1 index /CIDFont resourcestatus {",
+ " pop pop 1 index /CIDFont findresource /CIDFontType known",
+ " } {",
+ " false",
+ " } ifelse",
+ " {",
+ " 0 eq { /Identity-H } { /Identity-V } ifelse",
+ " exch 1 array astore composefont pop",
+ " } {",
+ " pdfMakeFont16",
+ " } ifelse",
+ "} def",
+ "~123sn",
+ "% graphics state operators",
+ "~1sn",
+ "/q {",
+ " gsave",
+ " pdfOpNames length 1 sub -1 0 { pdfOpNames exch get load } for",
+ " pdfStates pdfStateIdx 1 add get begin",
+ " pdfOpNames { exch def } forall",
+ "} def",
+ "/Q { end grestore } def",
+ "~23sn",
+ "/q { gsave pdfDictSize dict begin } def",
+ "/Q {",
+ " end grestore",
+ " /pdfLastFill where {",
+ " pop",
+ " pdfLastFill {",
+ " pdfFillOP setoverprint",
+ " } {",
+ " pdfStrokeOP setoverprint",
+ " } ifelse",
+ " } if",
+ "} def",
+ "~123sn",
+ "/cm { concat } def",
+ "/d { setdash } def",
+ "/i { setflat } def",
+ "/j { setlinejoin } def",
+ "/J { setlinecap } def",
+ "/M { setmiterlimit } def",
+ "/w { setlinewidth } def",
+ "% path segment operators",
+ "/m { moveto } def",
+ "/l { lineto } def",
+ "/c { curveto } def",
+ "/re { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto",
+ " neg 0 rlineto closepath } def",
+ "/h { closepath } def",
+ "% path painting operators",
+ "/S { sCol stroke } def",
+ "/Sf { fCol stroke } def",
+ "/f { fCol fill } def",
+ "/f* { fCol eofill } def",
+ "% clipping operators",
+ "/W { clip newpath } def",
+ "/W* { eoclip newpath } def",
+ "/Ws { strokepath clip newpath } def",
+ "% text state operators",
+ "/Tc { /pdfCharSpacing exch def } def",
+ "/Tf { dup /pdfFontSize exch def",
+ " dup pdfHorizScaling mul exch matrix scale",
+ " pdfTextMat matrix concatmatrix dup 4 0 put dup 5 0 put",
+ " exch findfont exch makefont setfont } def",
+ "/Tr { /pdfTextRender exch def } def",
+ "/Ts { /pdfTextRise exch def } def",
+ "/Tw { /pdfWordSpacing exch def } def",
+ "/Tz { /pdfHorizScaling exch def } def",
+ "% text positioning operators",
+ "/Td { pdfTextMat transform moveto } def",
+ "/Tm { /pdfTextMat exch def } def",
+ "% text string operators",
+ "/cshow where {",
+ " pop",
+ " /cshow2 {",
+ " dup {",
+ " pop pop",
+ " 1 string dup 0 3 index put 3 index exec",
+ " } exch cshow",
+ " pop pop",
+ " } def",
+ "}{",
+ " /cshow2 {",
+ " currentfont /FontType get 0 eq {",
+ " 0 2 2 index length 1 sub {",
+ " 2 copy get exch 1 add 2 index exch get",
+ " 2 copy exch 256 mul add",
+ " 2 string dup 0 6 5 roll put dup 1 5 4 roll put",
+ " 3 index exec",
+ " } for",
+ " } {",
+ " dup {",
+ " 1 string dup 0 3 index put 3 index exec",
+ " } forall",
+ " } ifelse",
+ " pop pop",
+ " } def",
+ "} ifelse",
+ "/awcp {", // awidthcharpath
+ " exch {",
+ " false charpath",
+ " 5 index 5 index rmoveto",
+ " 6 index eq { 7 index 7 index rmoveto } if",
+ " } exch cshow2",
+ " 6 {pop} repeat",
+ "} def",
+ "/Tj {",
+ " fCol", // because stringwidth has to draw Type 3 chars
+ " 1 index stringwidth pdfTextMat idtransform pop",
+ " sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse",
+ " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
+ " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
+ " pdfTextMat dtransform",
+ " 6 5 roll Tj1",
+ "} def",
+ "/Tj16 {",
+ " fCol", // because stringwidth has to draw Type 3 chars
+ " 2 index stringwidth pdfTextMat idtransform pop",
+ " sub exch div",
+ " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
+ " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
+ " pdfTextMat dtransform",
+ " 6 5 roll Tj1",
+ "} def",
+ "/Tj16V {",
+ " fCol", // because stringwidth has to draw Type 3 chars
+ " 2 index stringwidth pdfTextMat idtransform exch pop",
+ " sub exch div",
+ " 0 pdfWordSpacing pdfTextMat dtransform 32",
+ " 4 3 roll pdfCharSpacing add 0 exch",
+ " pdfTextMat dtransform",
+ " 6 5 roll Tj1",
+ "} def",
+ "/Tj1 {",
+ " 0 pdfTextRise pdfTextMat dtransform rmoveto",
+ " currentpoint 8 2 roll",
+ " pdfTextRender 1 and 0 eq {",
+ " 6 copy awidthshow",
+ " } if",
+ " pdfTextRender 3 and dup 1 eq exch 2 eq or {",
+ " 7 index 7 index moveto",
+ " 6 copy",
+ " currentfont /FontType get 3 eq { fCol } { sCol } ifelse",
+ " false awcp currentpoint stroke moveto",
+ " } if",
+ " pdfTextRender 4 and 0 ne {",
+ " 8 6 roll moveto",
+ " false awcp",
+ " /pdfTextClipPath [ pdfTextClipPath aload pop",
+ " {/moveto cvx}",
+ " {/lineto cvx}",
+ " {/curveto cvx}",
+ " {/closepath cvx}",
+ " pathforall ] def",
+ " currentpoint newpath moveto",
+ " } {",
+ " 8 {pop} repeat",
+ " } ifelse",
+ " 0 pdfTextRise neg pdfTextMat dtransform rmoveto",
+ "} def",
+ "/TJm { pdfFontSize 0.001 mul mul neg 0",
+ " pdfTextMat dtransform rmoveto } def",
+ "/TJmV { pdfFontSize 0.001 mul mul neg 0 exch",
+ " pdfTextMat dtransform rmoveto } def",
+ "/Tclip { pdfTextClipPath cvx exec clip newpath",
+ " /pdfTextClipPath [] def } def",
+ "~1ns",
+ "% Level 1 image operators",
+ "~1n",
+ "/pdfIm1 {",
+ " /pdfImBuf1 4 index string def",
+ " { currentfile pdfImBuf1 readhexstring pop } image",
+ "} def",
+ "~1s",
+ "/pdfIm1Sep {",
+ " /pdfImBuf1 4 index string def",
+ " /pdfImBuf2 4 index string def",
+ " /pdfImBuf3 4 index string def",
+ " /pdfImBuf4 4 index string def",
+ " { currentfile pdfImBuf1 readhexstring pop }",
+ " { currentfile pdfImBuf2 readhexstring pop }",
+ " { currentfile pdfImBuf3 readhexstring pop }",
+ " { currentfile pdfImBuf4 readhexstring pop }",
+ " true 4 colorimage",
+ "} def",
+ "~1ns",
+ "/pdfImM1 {",
+ " fCol /pdfImBuf1 4 index 7 add 8 idiv string def",
+ " { currentfile pdfImBuf1 readhexstring pop } imagemask",
+ "} def",
+ "/pdfImM1a {",
+ " { 2 copy get exch 1 add exch } imagemask",
+ " pop pop",
+ "} def",
+ "~23sn",
+ "% Level 2 image operators",
+ "/pdfImBuf 100 string def",
+ "/pdfIm {",
+ " image",
+ " { currentfile pdfImBuf readline",
+ " not { pop exit } if",
+ " (%-EOD-) eq { exit } if } loop",
+ "} def",
+ "~23s",
+ "/pdfImSep {",
+ " findcmykcustomcolor exch",
+ " dup /Width get /pdfImBuf1 exch string def",
+ " dup /Decode get aload pop 1 index sub /pdfImDecodeRange exch def",
+ " /pdfImDecodeLow exch def",
+ " begin Width Height BitsPerComponent ImageMatrix DataSource end",
+ " /pdfImData exch def",
+ " { pdfImData pdfImBuf1 readstring pop",
+ " 0 1 2 index length 1 sub {",
+ " 1 index exch 2 copy get",
+ " pdfImDecodeRange mul 255 div pdfImDecodeLow add round cvi",
+ " 255 exch sub put",
+ " } for }",
+ " 6 5 roll customcolorimage",
+ " { currentfile pdfImBuf readline",
+ " not { pop exit } if",
+ " (%-EOD-) eq { exit } if } loop",
+ "} def",
+ "~23sn",
+ "/pdfImM {",
+ " fCol imagemask",
+ " { currentfile pdfImBuf readline",
+ " not { pop exit } if",
+ " (%-EOD-) eq { exit } if } loop",
+ "} def",
+ "/pr { 2 index 2 index 3 2 roll putinterval 4 add } def",
+ "/pdfImClip {",
+ " gsave",
+ " 0 2 4 index length 1 sub {",
+ " dup 4 index exch 2 copy",
+ " get 5 index div put",
+ " 1 add 3 index exch 2 copy",
+ " get 3 index div put",
+ " } for",
+ " pop pop rectclip",
+ "} def",
+ "/pdfImClipEnd { grestore } def",
+ "~23sn",
+ "% shading operators",
+ "/colordelta {",
+ " false 0 1 3 index length 1 sub {",
+ " dup 4 index exch get 3 index 3 2 roll get sub abs 0.004 gt {",
+ " pop true",
+ " } if",
+ " } for",
+ " exch pop exch pop",
+ "} def",
+ "/funcCol { func n array astore } def",
+ "/funcSH {",
+ " dup 0 eq {",
+ " true",
+ " } {",
+ " dup 6 eq {",
+ " false",
+ " } {",
+ " 4 index 4 index funcCol dup",
+ " 6 index 4 index funcCol dup",
+ " 3 1 roll colordelta 3 1 roll",
+ " 5 index 5 index funcCol dup",
+ " 3 1 roll colordelta 3 1 roll",
+ " 6 index 8 index funcCol dup",
+ " 3 1 roll colordelta 3 1 roll",
+ " colordelta or or or",
+ " } ifelse",
+ " } ifelse",
+ " {",
+ " 1 add",
+ " 4 index 3 index add 0.5 mul exch 4 index 3 index add 0.5 mul exch",
+ " 6 index 6 index 4 index 4 index 4 index funcSH",
+ " 2 index 6 index 6 index 4 index 4 index funcSH",
+ " 6 index 2 index 4 index 6 index 4 index funcSH",
+ " 5 3 roll 3 2 roll funcSH pop pop",
+ " } {",
+ " pop 3 index 2 index add 0.5 mul 3 index 2 index add 0.5 mul",
+ "~23n",
+ " funcCol sc",
+ "~23s",
+ " funcCol aload pop k",
+ "~23sn",
+ " dup 4 index exch mat transform m",
+ " 3 index 3 index mat transform l",
+ " 1 index 3 index mat transform l",
+ " mat transform l pop pop h f*",
+ " } ifelse",
+ "} def",
+ "/axialCol {",
+ " dup 0 lt {",
+ " pop t0",
+ " } {",
+ " dup 1 gt {",
+ " pop t1",
+ " } {",
+ " dt mul t0 add",
+ " } ifelse",
+ " } ifelse",
+ " func n array astore",
+ "} def",
+ "/axialSH {",
+ " dup 0 eq {",
+ " true",
+ " } {",
+ " dup 8 eq {",
+ " false",
+ " } {",
+ " 2 index axialCol 2 index axialCol colordelta",
+ " } ifelse",
+ " } ifelse",
+ " {",
+ " 1 add 3 1 roll 2 copy add 0.5 mul",
+ " dup 4 3 roll exch 4 index axialSH",
+ " exch 3 2 roll axialSH",
+ " } {",
+ " pop 2 copy add 0.5 mul",
+ "~23n",
+ " axialCol sc",
+ "~23s",
+ " axialCol aload pop k",
+ "~23sn",
+ " exch dup dx mul x0 add exch dy mul y0 add",
+ " 3 2 roll dup dx mul x0 add exch dy mul y0 add",
+ " dx abs dy abs ge {",
+ " 2 copy yMin sub dy mul dx div add yMin m",
+ " yMax sub dy mul dx div add yMax l",
+ " 2 copy yMax sub dy mul dx div add yMax l",
+ " yMin sub dy mul dx div add yMin l",
+ " h f*",
+ " } {",
+ " exch 2 copy xMin sub dx mul dy div add xMin exch m",
+ " xMax sub dx mul dy div add xMax exch l",
+ " exch 2 copy xMax sub dx mul dy div add xMax exch l",
+ " xMin sub dx mul dy div add xMin exch l",
+ " h f*",
+ " } ifelse",
+ " } ifelse",
+ "} def",
+ "/radialCol {",
+ " dup t0 lt {",
+ " pop t0",
+ " } {",
+ " dup t1 gt {",
+ " pop t1",
+ " } if",
+ " } ifelse",
+ " func n array astore",
+ "} def",
+ "/radialSH {",
+ " dup 0 eq {",
+ " true",
+ " } {",
+ " dup 8 eq {",
+ " false",
+ " } {",
+ " 2 index dt mul t0 add radialCol",
+ " 2 index dt mul t0 add radialCol colordelta",
+ " } ifelse",
+ " } ifelse",
+ " {",
+ " 1 add 3 1 roll 2 copy add 0.5 mul",
+ " dup 4 3 roll exch 4 index radialSH",
+ " exch 3 2 roll radialSH",
+ " } {",
+ " pop 2 copy add 0.5 mul dt mul t0 add",
+ "~23n",
+ " radialCol sc",
+ "~23s",
+ " radialCol aload pop k",
+ "~23sn",
+ " encl {",
+ " exch dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
+ " 0 360 arc h",
+ " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
+ " 360 0 arcn h f",
+ " } {",
+ " 2 copy",
+ " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
+ " a1 a2 arcn",
+ " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
+ " a2 a1 arcn h",
+ " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
+ " a1 a2 arc",
+ " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add",
+ " a2 a1 arc h f",
+ " } ifelse",
+ " } ifelse",
+ "} def",
+ "~123sn",
+ "end",
+ NULL
+};
+
+static char *cmapProlog[] = {
+ "/CIDInit /ProcSet findresource begin",
+ "10 dict begin",
+ " begincmap",
+ " /CMapType 1 def",
+ " /CMapName /Identity-H def",
+ " /CIDSystemInfo 3 dict dup begin",
+ " /Registry (Adobe) def",
+ " /Ordering (Identity) def",
+ " /Supplement 0 def",
+ " end def",
+ " 1 begincodespacerange",
+ " <0000> <ffff>",
+ " endcodespacerange",
+ " 0 usefont",
+ " 1 begincidrange",
+ " <0000> <ffff> 0",
+ " endcidrange",
+ " endcmap",
+ " currentdict CMapName exch /CMap defineresource pop",
+ "end",
+ "10 dict begin",
+ " begincmap",
+ " /CMapType 1 def",
+ " /CMapName /Identity-V def",
+ " /CIDSystemInfo 3 dict dup begin",
+ " /Registry (Adobe) def",
+ " /Ordering (Identity) def",
+ " /Supplement 0 def",
+ " end def",
+ " /WMode 1 def",
+ " 1 begincodespacerange",
+ " <0000> <ffff>",
+ " endcodespacerange",
+ " 0 usefont",
+ " 1 begincidrange",
+ " <0000> <ffff> 0",
+ " endcidrange",
+ " endcmap",
+ " currentdict CMapName exch /CMap defineresource pop",
+ "end",
+ "end",
+ NULL
+};
+
+//------------------------------------------------------------------------
+// Fonts
+//------------------------------------------------------------------------
+
+struct PSSubstFont {
+ char *psName; // PostScript name
+ double mWidth; // width of 'm' character
+};
+
+static char *psFonts[] = {
+ "Courier",
+ "Courier-Bold",
+ "Courier-Oblique",
+ "Courier-BoldOblique",
+ "Helvetica",
+ "Helvetica-Bold",
+ "Helvetica-Oblique",
+ "Helvetica-BoldOblique",
+ "Symbol",
+ "Times-Roman",
+ "Times-Bold",
+ "Times-Italic",
+ "Times-BoldItalic",
+ "ZapfDingbats",
+ NULL
+};
+
+static PSSubstFont psSubstFonts[] = {
+ {"Helvetica", 0.833},
+ {"Helvetica-Oblique", 0.833},
+ {"Helvetica-Bold", 0.889},
+ {"Helvetica-BoldOblique", 0.889},
+ {"Times-Roman", 0.788},
+ {"Times-Italic", 0.722},
+ {"Times-Bold", 0.833},
+ {"Times-BoldItalic", 0.778},
+ {"Courier", 0.600},
+ {"Courier-Oblique", 0.600},
+ {"Courier-Bold", 0.600},
+ {"Courier-BoldOblique", 0.600}
+};
+
+// Info for 8-bit fonts
+struct PSFont8Info {
+ Ref fontID;
+ Gushort *codeToGID; // code-to-GID mapping for TrueType fonts
+};
+
+// Encoding info for substitute 16-bit font
+struct PSFont16Enc {
+ Ref fontID;
+ GString *enc;
+};
+
+//------------------------------------------------------------------------
+// process colors
+//------------------------------------------------------------------------
+
+#define psProcessCyan 1
+#define psProcessMagenta 2
+#define psProcessYellow 4
+#define psProcessBlack 8
+#define psProcessCMYK 15
+
+//------------------------------------------------------------------------
+// PSOutCustomColor
+//------------------------------------------------------------------------
+
+class PSOutCustomColor {
+public:
+
+ PSOutCustomColor(double cA, double mA,
+ double yA, double kA, GString *nameA);
+ ~PSOutCustomColor();
+
+ double c, m, y, k;
+ GString *name;
+ PSOutCustomColor *next;
+};
+
+PSOutCustomColor::PSOutCustomColor(double cA, double mA,
+ double yA, double kA, GString *nameA) {
+ c = cA;
+ m = mA;
+ y = yA;
+ k = kA;
+ name = nameA;
+ next = NULL;
+}
+
+PSOutCustomColor::~PSOutCustomColor() {
+ delete name;
+}
+
+//------------------------------------------------------------------------
+
+struct PSOutImgClipRect {
+ int x0, x1, y0, y1;
+};
+
+//------------------------------------------------------------------------
+// DeviceNRecoder
+//------------------------------------------------------------------------
+
+class DeviceNRecoder: public FilterStream {
+public:
+
+ DeviceNRecoder(Stream *strA, int widthA, int heightA,
+ GfxImageColorMap *colorMapA);
+ virtual ~DeviceNRecoder();
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ virtual int getChar()
+ { return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx++]; }
+ virtual int lookChar()
+ { return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx]; }
+ virtual GString *getPSFilter(int /*psLevel*/, char * /*indent*/) { return NULL; }
+ virtual GBool isBinary(GBool /*last*/ = gTrue) { return gTrue; }
+ virtual GBool isEncoder() { return gTrue; }
+
+private:
+
+ GBool fillBuf();
+
+ int width, height;
+ GfxImageColorMap *colorMap;
+ Function *func;
+ ImageStream *imgStr;
+ int buf[gfxColorMaxComps];
+ int pixelIdx;
+ int bufIdx;
+ int bufSize;
+};
+
+DeviceNRecoder::DeviceNRecoder(Stream *strA, int widthA, int heightA,
+ GfxImageColorMap *colorMapA):
+ FilterStream(strA) {
+ width = widthA;
+ height = heightA;
+ colorMap = colorMapA;
+ imgStr = NULL;
+ pixelIdx = 0;
+ bufIdx = gfxColorMaxComps;
+ bufSize = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
+ getAlt()->getNComps();
+ func = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
+ getTintTransformFunc();
+}
+
+DeviceNRecoder::~DeviceNRecoder() {
+ if (imgStr) {
+ delete imgStr;
+ }
+}
+
+void DeviceNRecoder::reset() {
+ imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
+ colorMap->getBits());
+ imgStr->reset();
+}
+
+GBool DeviceNRecoder::fillBuf() {
+ Guchar pixBuf[gfxColorMaxComps];
+ GfxColor color;
+ double x[gfxColorMaxComps], y[gfxColorMaxComps];
+ int i;
+
+ if (pixelIdx >= width * height) {
+ return gFalse;
+ }
+ imgStr->getPixel(pixBuf);
+ colorMap->getColor(pixBuf, &color);
+ for (i = 0;
+ i < ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->getNComps();
+ ++i) {
+ x[i] = colToDbl(color.c[i]);
+ }
+ func->transform(x, y);
+ for (i = 0; i < bufSize; ++i) {
+ buf[i] = (int)(y[i] * 255 + 0.5);
+ }
+ bufIdx = 0;
+ ++pixelIdx;
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
+// PSOutputDev
+//------------------------------------------------------------------------
+
+extern "C" {
+typedef void (*SignalFunc)(int);
+}
+
+static void outputToFile(void *stream, char *data, int len) {
+ fwrite(data, 1, len, (FILE *)stream);
+}
+
+PSOutputDev::PSOutputDev(char *fileName, char *pstitle, XRef *xrefA, Catalog *catalog,
+ int firstPage, int lastPage, PSOutMode modeA,
+ int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
+ GBool forceRasterizeA,
+ GBool manualCtrlA) {
+ FILE *f;
+ PSFileType fileTypeA;
+
+ underlayCbk = NULL;
+ underlayCbkData = NULL;
+ overlayCbk = NULL;
+ overlayCbkData = NULL;
+
+ fontIDs = NULL;
+ fontFileIDs = NULL;
+ fontFileNames = NULL;
+ font8Info = NULL;
+ font16Enc = NULL;
+ imgIDs = NULL;
+ formIDs = NULL;
+ xobjStack = NULL;
+ embFontList = NULL;
+ customColors = NULL;
+ haveTextClip = gFalse;
+ t3String = NULL;
+
+ forceRasterize = forceRasterizeA;
+
+ // open file or pipe
+ if (!strcmp(fileName, "-")) {
+ fileTypeA = psStdout;
+ f = stdout;
+ } else if (fileName[0] == '|') {
+ fileTypeA = psPipe;
+#ifdef HAVE_POPEN
+#ifndef WIN32
+ signal(SIGPIPE, (SignalFunc)SIG_IGN);
+#endif
+ if (!(f = popen(fileName + 1, "w"))) {
+ error(-1, "Couldn't run print command '%s'", fileName);
+ ok = gFalse;
+ return;
+ }
+#else
+ error(-1, "Print commands are not supported ('%s')", fileName);
+ ok = gFalse;
+ return;
+#endif
+ } else {
+ fileTypeA = psFile;
+ if (!(f = fopen(fileName, "w"))) {
+ error(-1, "Couldn't open PostScript file '%s'", fileName);
+ ok = gFalse;
+ return;
+ }
+ }
+
+ init(outputToFile, f, fileTypeA, pstitle,
+ xrefA, catalog, firstPage, lastPage, modeA,
+ imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA);
+}
+
+void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
+ PSFileType fileTypeA, char *pstitle, XRef *xrefA, Catalog *catalog,
+ int firstPage, int lastPage, PSOutMode modeA,
+ int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
+ GBool manualCtrlA) {
+ Page *page;
+ PDFRectangle *box;
+
+ // initialize
+ setlocale(LC_NUMERIC,"POSIX");
+ ok = gTrue;
+ outputFunc = outputFuncA;
+ outputStream = outputStreamA;
+ fileType = fileTypeA;
+ xref = xrefA;
+ level = globalParams->getPSLevel();
+ mode = modeA;
+ paperWidth = globalParams->getPSPaperWidth();
+ paperHeight = globalParams->getPSPaperHeight();
+ imgLLX = imgLLXA;
+ imgLLY = imgLLYA;
+ imgURX = imgURXA;
+ imgURY = imgURYA;
+ if (imgLLX == 0 && imgURX == 0 && imgLLY == 0 && imgURY == 0) {
+ globalParams->getPSImageableArea(&imgLLX, &imgLLY, &imgURX, &imgURY);
+ }
+ if (paperWidth < 0 || paperHeight < 0) {
+ // this check is needed in case the document has zero pages
+ if (firstPage > 0 && firstPage <= catalog->getNumPages()) {
+ page = catalog->getPage(firstPage);
+ paperWidth = (int)ceil(page->getMediaWidth());
+ paperHeight = (int)ceil(page->getMediaHeight());
+ } else {
+ paperWidth = 1;
+ paperHeight = 1;
+ }
+ imgLLX = imgLLY = 0;
+ imgURX = paperWidth;
+ imgURY = paperHeight;
+ }
+ preload = globalParams->getPSPreload();
+ manualCtrl = manualCtrlA;
+ if (mode == psModeForm) {
+ lastPage = firstPage;
+ }
+ processColors = 0;
+ inType3Char = gFalse;
+
+#if OPI_SUPPORT
+ // initialize OPI nesting levels
+ opi13Nest = 0;
+ opi20Nest = 0;
+#endif
+
+ tx0 = ty0 = -1;
+ xScale0 = yScale0 = 0;
+ rotate0 = -1;
+ clipLLX0 = clipLLY0 = 0;
+ clipURX0 = clipURY0 = -1;
+
+ // initialize fontIDs, fontFileIDs, and fontFileNames lists
+ fontIDSize = 64;
+ fontIDLen = 0;
+ fontIDs = (Ref *)gmallocn(fontIDSize, sizeof(Ref));
+ fontFileIDSize = 64;
+ fontFileIDLen = 0;
+ fontFileIDs = (Ref *)gmallocn(fontFileIDSize, sizeof(Ref));
+ fontFileNameSize = 64;
+ fontFileNameLen = 0;
+ fontFileNames = (GString **)gmallocn(fontFileNameSize, sizeof(GString *));
+ psFileNames = (GString **)gmallocn(fontFileNameSize, sizeof(GString *));
+ nextTrueTypeNum = 0;
+ font8InfoLen = 0;
+ font8InfoSize = 0;
+ font16EncLen = 0;
+ font16EncSize = 0;
+ imgIDLen = 0;
+ imgIDSize = 0;
+ formIDLen = 0;
+ formIDSize = 0;
+
+ xobjStack = new GList();
+ numSaves = 0;
+ numTilingPatterns = 0;
+ nextFunc = 0;
+
+ // initialize embedded font resource comment list
+ embFontList = new GString();
+
+ if (!manualCtrl) {
+ // this check is needed in case the document has zero pages
+ if (firstPage > 0 && firstPage <= catalog->getNumPages()) {
+ writeHeader(firstPage, lastPage,
+ catalog->getPage(firstPage)->getMediaBox(),
+ catalog->getPage(firstPage)->getCropBox(),
+ catalog->getPage(firstPage)->getRotate(), pstitle);
+ } else {
+ box = new PDFRectangle(0, 0, 1, 1);
+ writeHeader(firstPage, lastPage, box, box, 0, pstitle);
+ delete box;
+ }
+ if (mode != psModeForm) {
+ writePS("%%BeginProlog\n");
+ }
+ writeXpdfProcset();
+ if (mode != psModeForm) {
+ writePS("%%EndProlog\n");
+ writePS("%%BeginSetup\n");
+ }
+ writeDocSetup(catalog, firstPage, lastPage);
+ if (mode != psModeForm) {
+ writePS("%%EndSetup\n");
+ }
+ }
+
+ // initialize sequential page number
+ seqPage = 1;
+}
+
+PSOutputDev::~PSOutputDev() {
+ PSOutCustomColor *cc;
+ int i;
+
+ if (ok) {
+ if (!manualCtrl) {
+ writePS("%%Trailer\n");
+ writeTrailer();
+ if (mode != psModeForm) {
+ writePS("%%EOF\n");
+ }
+ }
+ if (fileType == psFile) {
+#ifdef MACOS
+ ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle);
+#endif
+ fclose((FILE *)outputStream);
+ }
+#ifdef HAVE_POPEN
+ else if (fileType == psPipe) {
+ pclose((FILE *)outputStream);
+#ifndef WIN32
+ signal(SIGPIPE, (SignalFunc)SIG_DFL);
+#endif
+ }
+#endif
+ }
+ if (embFontList) {
+ delete embFontList;
+ }
+ if (fontIDs) {
+ gfree(fontIDs);
+ }
+ if (fontFileIDs) {
+ gfree(fontFileIDs);
+ }
+ if (fontFileNames) {
+ for (i = 0; i < fontFileNameLen; ++i) {
+ delete fontFileNames[i];
+ }
+ gfree(fontFileNames);
+ }
+ if (font8Info) {
+ for (i = 0; i < font8InfoLen; ++i) {
+ gfree(font8Info[i].codeToGID);
+ }
+ gfree(font8Info);
+ }
+ if (psFileNames) {
+ for (i = 0; i < fontFileNameLen; ++i) {
+ if (psFileNames[i])
+ delete psFileNames[i];
+ }
+ gfree(psFileNames);
+ }
+ if (font16Enc) {
+ for (i = 0; i < font16EncLen; ++i) {
+ delete font16Enc[i].enc;
+ }
+ gfree(font16Enc);
+ }
+ gfree(imgIDs);
+ gfree(formIDs);
+ if (xobjStack) {
+ delete xobjStack;
+ }
+ while (customColors) {
+ cc = customColors;
+ customColors = cc->next;
+ delete cc;
+ }
+}
+
+void PSOutputDev::writeHeader(int firstPage, int lastPage,
+ PDFRectangle *mediaBox, PDFRectangle *cropBox,
+ int pageRotate, char *pstitle) {
+ Object info, obj1;
+ double x1, y1, x2, y2;
+
+ switch (mode) {
+ case psModePS:
+ writePS("%!PS-Adobe-3.0\n");
+ break;
+ case psModeEPS:
+ writePS("%!PS-Adobe-3.0 EPSF-3.0\n");
+ break;
+ case psModeForm:
+ writePS("%!PS-Adobe-3.0 Resource-Form\n");
+ break;
+ }
+
+ xref->getDocInfo(&info);
+ if (info.isDict() && info.dictLookup("Creator", &obj1)->isString()) {
+ writePS("%%Creator: ");
+ writePSTextLine(obj1.getString());
+ }
+ obj1.free();
+ info.free();
+ if(pstitle) {
+ writePSFmt("%%Title: {0:s}\n", pstitle);
+ }
+ writePSFmt("%%LanguageLevel: {0:d}\n",
+ (level == psLevel1 || level == psLevel1Sep) ? 1 :
+ (level == psLevel2 || level == psLevel2Sep) ? 2 : 3);
+ if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) {
+ writePS("%%DocumentProcessColors: (atend)\n");
+ writePS("%%DocumentCustomColors: (atend)\n");
+ }
+ writePS("%%DocumentSuppliedResources: (atend)\n");
+
+ switch (mode) {
+ case psModePS:
+ writePSFmt("%%DocumentMedia: plain {0:d} {1:d} 0 () ()\n",
+ paperWidth, paperHeight);
+ writePSFmt("%%BoundingBox: 0 0 {0:d} {1:d}\n", paperWidth, paperHeight);
+ writePSFmt("%%Pages: {0:d}\n", lastPage - firstPage + 1);
+ writePS("%%EndComments\n");
+ writePS("%%BeginDefaults\n");
+ writePS("%%PageMedia: plain\n");
+ writePS("%%EndDefaults\n");
+ break;
+ case psModeEPS:
+ epsX1 = cropBox->x1;
+ epsY1 = cropBox->y1;
+ epsX2 = cropBox->x2;
+ epsY2 = cropBox->y2;
+ if (pageRotate == 0 || pageRotate == 180) {
+ x1 = epsX1;
+ y1 = epsY1;
+ x2 = epsX2;
+ y2 = epsY2;
+ } else { // pageRotate == 90 || pageRotate == 270
+ x1 = 0;
+ y1 = 0;
+ x2 = epsY2 - epsY1;
+ y2 = epsX2 - epsX1;
+ }
+ writePSFmt("%%BoundingBox: {0:d} {1:d} {2:d} {3:d}\n",
+ (int)floor(x1), (int)floor(y1), (int)ceil(x2), (int)ceil(y2));
+ if (floor(x1) != ceil(x1) || floor(y1) != ceil(y1) ||
+ floor(x2) != ceil(x2) || floor(y2) != ceil(y2)) {
+ writePSFmt("%%HiResBoundingBox: {0:.4g} {1:.4g} {2:.4g} {3:.4g}\n",
+ x1, y1, x2, y2);
+ }
+ writePS("%%EndComments\n");
+ break;
+ case psModeForm:
+ writePS("%%EndComments\n");
+ writePS("32 dict dup begin\n");
+ writePSFmt("/BBox [{0:d} {1:d} {2:d} {3:d}] def\n",
+ (int)floor(mediaBox->x1), (int)floor(mediaBox->y1),
+ (int)ceil(mediaBox->x2), (int)ceil(mediaBox->y2));
+ writePS("/FormType 1 def\n");
+ writePS("/Matrix [1 0 0 1 0 0] def\n");
+ break;
+ }
+}
+
+void PSOutputDev::writeXpdfProcset() {
+ GBool lev1, lev2, lev3, sep, nonSep;
+ char **p;
+ char *q;
+
+ writePSFmt("%%BeginResource: procset xpdf {0:s} 0\n", xpdfVersion);
+ writePSFmt("%%Copyright: {0:s}\n", xpdfCopyright);
+ lev1 = lev2 = lev3 = sep = nonSep = gTrue;
+ for (p = prolog; *p; ++p) {
+ if ((*p)[0] == '~') {
+ lev1 = lev2 = lev3 = sep = nonSep = gFalse;
+ for (q = *p + 1; *q; ++q) {
+ switch (*q) {
+ case '1': lev1 = gTrue; break;
+ case '2': lev2 = gTrue; break;
+ case '3': lev3 = gTrue; break;
+ case 's': sep = gTrue; break;
+ case 'n': nonSep = gTrue; break;
+ }
+ }
+ } else if ((level == psLevel1 && lev1 && nonSep) ||
+ (level == psLevel1Sep && lev1 && sep) ||
+ (level == psLevel2 && lev2 && nonSep) ||
+ (level == psLevel2Sep && lev2 && sep) ||
+ (level == psLevel3 && lev3 && nonSep) ||
+ (level == psLevel3Sep && lev3 && sep)) {
+ writePSFmt("{0:s}\n", *p);
+ }
+ }
+ writePS("%%EndResource\n");
+
+ if (level >= psLevel3) {
+ for (p = cmapProlog; *p; ++p) {
+ writePSFmt("{0:s}\n", *p);
+ }
+ }
+}
+
+void PSOutputDev::writeDocSetup(Catalog *catalog,
+ int firstPage, int lastPage) {
+ Page *page;
+ Dict *resDict;
+ Annots *annots;
+ Object obj1, obj2;
+ int pg, i;
+
+ if (mode == psModeForm) {
+ // swap the form and xpdf dicts
+ writePS("xpdf end begin dup begin\n");
+ } else {
+ writePS("xpdf begin\n");
+ }
+ for (pg = firstPage; pg <= lastPage; ++pg) {
+ page = catalog->getPage(pg);
+ if ((resDict = page->getResourceDict())) {
+ setupResources(resDict);
+ }
+ annots = new Annots(xref, catalog, page->getAnnots(&obj1));
+ obj1.free();
+ for (i = 0; i < annots->getNumAnnots(); ++i) {
+ if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) {
+ obj1.streamGetDict()->lookup("Resources", &obj2);
+ if (obj2.isDict()) {
+ setupResources(obj2.getDict());
+ }
+ obj2.free();
+ }
+ obj1.free();
+ }
+ delete annots;
+ }
+ if (mode != psModeForm) {
+ if (mode != psModeEPS && !manualCtrl) {
+ writePSFmt("{0:d} {1:d} {2:s} pdfSetup\n",
+ paperWidth, paperHeight,
+ globalParams->getPSDuplex() ? "true" : "false");
+ }
+#if OPI_SUPPORT
+ if (globalParams->getPSOPI()) {
+ writePS("/opiMatrix matrix currentmatrix def\n");
+ }
+#endif
+ }
+}
+
+void PSOutputDev::writePageTrailer() {
+ if (mode != psModeForm) {
+ writePS("pdfEndPage\n");
+ }
+}
+
+void PSOutputDev::writeTrailer() {
+ PSOutCustomColor *cc;
+
+ if (mode == psModeForm) {
+ writePS("/Foo exch /Form defineresource pop\n");
+ } else {
+ writePS("end\n");
+ writePS("%%DocumentSuppliedResources:\n");
+ writePS(embFontList->getCString());
+ if (level == psLevel1Sep || level == psLevel2Sep ||
+ level == psLevel3Sep) {
+ writePS("%%DocumentProcessColors:");
+ if (processColors & psProcessCyan) {
+ writePS(" Cyan");
+ }
+ if (processColors & psProcessMagenta) {
+ writePS(" Magenta");
+ }
+ if (processColors & psProcessYellow) {
+ writePS(" Yellow");
+ }
+ if (processColors & psProcessBlack) {
+ writePS(" Black");
+ }
+ writePS("\n");
+ writePS("%%DocumentCustomColors:");
+ for (cc = customColors; cc; cc = cc->next) {
+ writePSFmt(" ({0:s})", cc->name->getCString());
+ }
+ writePS("\n");
+ writePS("%%CMYKCustomColor:\n");
+ for (cc = customColors; cc; cc = cc->next) {
+ writePSFmt("%%+ {0:.4g} {1:.4g} {2:.4g} {3:.4g} ({4:t})\n",
+ cc->c, cc->m, cc->y, cc->k, cc->name);
+ }
+ }
+ }
+}
+
+void PSOutputDev::setupResources(Dict *resDict) {
+ Object xObjDict, xObjRef, xObj, patDict, patRef, pat, resObj;
+ Ref ref0, ref1;
+ GBool skip;
+ int i, j;
+
+ setupFonts(resDict);
+ setupImages(resDict);
+ setupForms(resDict);
+
+ //----- recursively scan XObjects
+ resDict->lookup("XObject", &xObjDict);
+ if (xObjDict.isDict()) {
+ for (i = 0; i < xObjDict.dictGetLength(); ++i) {
+
+ // avoid infinite recursion on XObjects
+ skip = gFalse;
+ if ((xObjDict.dictGetValNF(i, &xObjRef)->isRef())) {
+ ref0 = xObjRef.getRef();
+ for (j = 0; j < xobjStack->getLength(); ++j) {
+ ref1 = *(Ref *)xobjStack->get(j);
+ if (ref1.num == ref0.num && ref1.gen == ref0.gen) {
+ skip = gTrue;
+ break;
+ }
+ }
+ if (!skip) {
+ xobjStack->append(&ref0);
+ }
+ }
+ if (!skip) {
+
+ // process the XObject's resource dictionary
+ xObjDict.dictGetVal(i, &xObj);
+ if (xObj.isStream()) {
+ xObj.streamGetDict()->lookup("Resources", &resObj);
+ if (resObj.isDict()) {
+ setupResources(resObj.getDict());
+ }
+ resObj.free();
+ }
+ xObj.free();
+ }
+
+ if (xObjRef.isRef() && !skip) {
+ xobjStack->del(xobjStack->getLength() - 1);
+ }
+ xObjRef.free();
+ }
+ }
+ xObjDict.free();
+
+ //----- recursively scan Patterns
+ resDict->lookup("Pattern", &patDict);
+ if (patDict.isDict()) {
+ inType3Char = gTrue;
+ for (i = 0; i < patDict.dictGetLength(); ++i) {
+
+ // avoid infinite recursion on Patterns
+ skip = gFalse;
+ if ((patDict.dictGetValNF(i, &patRef)->isRef())) {
+ ref0 = patRef.getRef();
+ for (j = 0; j < xobjStack->getLength(); ++j) {
+ ref1 = *(Ref *)xobjStack->get(j);
+ if (ref1.num == ref0.num && ref1.gen == ref0.gen) {
+ skip = gTrue;
+ break;
+ }
+ }
+ if (!skip) {
+ xobjStack->append(&ref0);
+ }
+ }
+ if (!skip) {
+
+ // process the Pattern's resource dictionary
+ patDict.dictGetVal(i, &pat);
+ if (pat.isStream()) {
+ pat.streamGetDict()->lookup("Resources", &resObj);
+ if (resObj.isDict()) {
+ setupResources(resObj.getDict());
+ }
+ resObj.free();
+ }
+ pat.free();
+ }
+
+ if (patRef.isRef() && !skip) {
+ xobjStack->del(xobjStack->getLength() - 1);
+ }
+ patRef.free();
+ }
+ inType3Char = gFalse;
+ }
+ patDict.free();
+}
+
+void PSOutputDev::setupFonts(Dict *resDict) {
+ Object obj1, obj2;
+ Ref r;
+ GfxFontDict *gfxFontDict;
+ GfxFont *font;
+ int i;
+
+ if (forceRasterize) return;
+
+ gfxFontDict = NULL;
+ resDict->lookupNF("Font", &obj1);
+ if (obj1.isRef()) {
+ obj1.fetch(xref, &obj2);
+ if (obj2.isDict()) {
+ r = obj1.getRef();
+ gfxFontDict = new GfxFontDict(xref, &r, obj2.getDict());
+ }
+ obj2.free();
+ } else if (obj1.isDict()) {
+ gfxFontDict = new GfxFontDict(xref, NULL, obj1.getDict());
+ }
+ if (gfxFontDict) {
+ for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
+ if ((font = gfxFontDict->getFont(i))) {
+ setupFont(font, resDict);
+ }
+ }
+ delete gfxFontDict;
+ }
+ obj1.free();
+}
+
+void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
+ Ref fontFileID;
+ GString *name;
+ PSFontParam *fontParam;
+ GString *psName;
+ char buf[16];
+ GBool subst;
+ UnicodeMap *uMap;
+ char *charName;
+ double xs, ys;
+ int code;
+ double w1, w2;
+ double *fm;
+ int i, j;
+ DisplayFontParam *dfp;
+
+ // check if font is already set up
+ for (i = 0; i < fontIDLen; ++i) {
+ if (fontIDs[i].num == font->getID()->num &&
+ fontIDs[i].gen == font->getID()->gen) {
+ return;
+ }
+ }
+
+ // add entry to fontIDs list
+ if (fontIDLen >= fontIDSize) {
+ fontIDSize += 64;
+ fontIDs = (Ref *)greallocn(fontIDs, fontIDSize, sizeof(Ref));
+ }
+ fontIDs[fontIDLen++] = *font->getID();
+
+ xs = ys = 1;
+ subst = gFalse;
+
+ // check for resident 8-bit font
+ if (font->getName() &&
+ (fontParam = globalParams->getPSFont(font->getName()))) {
+ psName = new GString(fontParam->psFontName->getCString());
+
+ // check for embedded Type 1 font
+ } else if (globalParams->getPSEmbedType1() &&
+ font->getType() == fontType1 &&
+ font->getEmbeddedFontID(&fontFileID)) {
+ psName = filterPSName(font->getEmbeddedFontName());
+ setupEmbeddedType1Font(&fontFileID, psName);
+
+ // check for embedded Type 1C font
+ } else if (globalParams->getPSEmbedType1() &&
+ font->getType() == fontType1C &&
+ font->getEmbeddedFontID(&fontFileID)) {
+ // use the PDF font name because the embedded font name might
+ // not include the subset prefix
+ psName = filterPSName(font->getOrigName());
+ setupEmbeddedType1CFont(font, &fontFileID, psName);
+
+ // check for embedded OpenType - Type 1C font
+ } else if (globalParams->getPSEmbedType1() &&
+ font->getType() == fontType1COT &&
+ font->getEmbeddedFontID(&fontFileID)) {
+ // use the PDF font name because the embedded font name might
+ // not include the subset prefix
+ psName = filterPSName(font->getOrigName());
+ setupEmbeddedOpenTypeT1CFont(font, &fontFileID, psName);
+
+ // check for external Type 1 font file
+ } else if (globalParams->getPSEmbedType1() &&
+ font->getType() == fontType1 &&
+ font->getExtFontFile()) {
+ // this assumes that the PS font name matches the PDF font name
+ psName = font->getName()->copy();
+ setupExternalType1Font(font->getExtFontFile(), psName);
+
+ // check for embedded TrueType font
+ } else if (globalParams->getPSEmbedTrueType() &&
+ (font->getType() == fontTrueType ||
+ font->getType() == fontTrueTypeOT) &&
+ font->getEmbeddedFontID(&fontFileID)) {
+ psName = filterPSName(font->getEmbeddedFontName());
+ setupEmbeddedTrueTypeFont(font, &fontFileID, psName);
+
+ // check for external TrueType font file
+ } else if (globalParams->getPSEmbedTrueType() &&
+ font->getType() == fontTrueType &&
+ font->getExtFontFile()) {
+ psName = setupExternalTrueTypeFont(font);
+
+ // check for embedded CID PostScript font
+ } else if (globalParams->getPSEmbedCIDPostScript() &&
+ font->getType() == fontCIDType0C &&
+ font->getEmbeddedFontID(&fontFileID)) {
+ psName = filterPSName(font->getEmbeddedFontName());
+ setupEmbeddedCIDType0Font(font, &fontFileID, psName);
+
+ // check for embedded CID TrueType font
+ } else if (globalParams->getPSEmbedCIDTrueType() &&
+ (font->getType() == fontCIDType2 ||
+ font->getType() == fontCIDType2OT) &&
+ font->getEmbeddedFontID(&fontFileID)) {
+ psName = filterPSName(font->getEmbeddedFontName());
+ //~ should check to see if font actually uses vertical mode
+ setupEmbeddedCIDTrueTypeFont(font, &fontFileID, psName, gTrue);
+
+ // check for embedded OpenType - CID CFF font
+ } else if (globalParams->getPSEmbedCIDPostScript() &&
+ font->getType() == fontCIDType0COT &&
+ font->getEmbeddedFontID(&fontFileID)) {
+ psName = filterPSName(font->getEmbeddedFontName());
+ setupEmbeddedOpenTypeCFFFont(font, &fontFileID, psName);
+
+ // check for Type 3 font
+ } else if (font->getType() == fontType3) {
+ psName = GString::format("T3_{0:d}_{1:d}",
+ font->getID()->num, font->getID()->gen);
+ setupType3Font(font, psName, parentResDict);
+ // check for external CID TrueType font file
+ } else if (globalParams->getPSEmbedCIDTrueType() &&
+ font->getType() == fontCIDType2 &&
+ font->getExtFontFile()) {
+ psName = setupExternalCIDTrueTypeFont(font, font->getExtFontFile());
+ // do 8-bit font substitution
+ } else if (!font->isCIDFont()) {
+ subst = gTrue;
+ name = font->getName();
+ psName = NULL;
+ if (name) {
+ for (i = 0; psFonts[i]; ++i) {
+ if (name->cmp(psFonts[i]) == 0) {
+ psName = new GString(psFonts[i]);
+ break;
+ }
+ }
+ }
+ if (!psName) {
+ if (font->isFixedWidth()) {
+ i = 8;
+ } else if (font->isSerif()) {
+ i = 4;
+ } else {
+ i = 0;
+ }
+ if (font->isBold()) {
+ i += 2;
+ }
+ if (font->isItalic()) {
+ i += 1;
+ }
+ psName = new GString(psSubstFonts[i].psName);
+ for (code = 0; code < 256; ++code) {
+ if ((charName = ((Gfx8BitFont *)font)->getCharName(code)) &&
+ charName[0] == 'm' && charName[1] == '\0') {
+ break;
+ }
+ }
+ if (code < 256) {
+ w1 = ((Gfx8BitFont *)font)->getWidth(code);
+ } else {
+ w1 = 0;
+ }
+ w2 = psSubstFonts[i].mWidth;
+ xs = w1 / w2;
+ if (xs < 0.1) {
+ xs = 1;
+ }
+ if (font->getType() == fontType3) {
+ // This is a hack which makes it possible to substitute for some
+ // Type 3 fonts. The problem is that it's impossible to know what
+ // the base coordinate system used in the font is without actually
+ // rendering the font.
+ ys = xs;
+ fm = font->getFontMatrix();
+ if (fm[0] != 0) {
+ ys *= fm[3] / fm[0];
+ }
+ } else {
+ ys = 1;
+ }
+ }
+
+ // do 16-bit font substitution
+ } else if ((fontParam = globalParams->
+ getPSFont16(font->getName(),
+ ((GfxCIDFont *)font)->getCollection(),
+ font->getWMode()))) {
+ subst = gTrue;
+ psName = fontParam->psFontName->copy();
+ if (font16EncLen >= font16EncSize) {
+ font16EncSize += 16;
+ font16Enc = (PSFont16Enc *)greallocn(font16Enc,
+ font16EncSize, sizeof(PSFont16Enc));
+ }
+ font16Enc[font16EncLen].fontID = *font->getID();
+ font16Enc[font16EncLen].enc = fontParam->encoding->copy();
+ if ((uMap = globalParams->getUnicodeMap(font16Enc[font16EncLen].enc))) {
+ uMap->decRefCnt();
+ ++font16EncLen;
+ } else {
+ error(-1, "Couldn't find Unicode map for 16-bit font encoding '%s'",
+ font16Enc[font16EncLen].enc->getCString());
+ }
+
+ // try the display font for embedding
+ } else if (globalParams->getPSEmbedCIDTrueType() &&
+ ((GfxCIDFont *)font)->getCollection() &&
+ (dfp = globalParams->
+ getDisplayCIDFont(font->getName(),
+ ((GfxCIDFont *)font)->getCollection())) &&
+ dfp->kind == displayFontTT) {
+ psName = setupExternalCIDTrueTypeFont(font, dfp->tt.fileName, dfp->tt.faceIndex);
+
+ // give up - can't do anything with this font
+ } else {
+ error(-1, "Couldn't find a font to substitute for '%s' ('%s' character collection)",
+ font->getName() ? font->getName()->getCString() : "(unnamed)",
+ ((GfxCIDFont *)font)->getCollection()
+ ? ((GfxCIDFont *)font)->getCollection()->getCString()
+ : "(unknown)");
+ return;
+ }
+
+ // generate PostScript code to set up the font
+ if (font->isCIDFont()) {
+ if (level == psLevel3 || level == psLevel3Sep) {
+ writePSFmt("/F{0:d}_{1:d} /{2:t} {3:d} pdfMakeFont16L3\n",
+ font->getID()->num, font->getID()->gen, psName,
+ font->getWMode());
+ } else {
+ writePSFmt("/F{0:d}_{1:d} /{2:t} {3:d} pdfMakeFont16\n",
+ font->getID()->num, font->getID()->gen, psName,
+ font->getWMode());
+ }
+ } else {
+ writePSFmt("/F{0:d}_{1:d} /{2:t} {3:.4g} {4:.4g}\n",
+ font->getID()->num, font->getID()->gen, psName, xs, ys);
+ for (i = 0; i < 256; i += 8) {
+ writePS((char *)((i == 0) ? "[ " : " "));
+ for (j = 0; j < 8; ++j) {
+ if (font->getType() == fontTrueType &&
+ !subst &&
+ !((Gfx8BitFont *)font)->getHasEncoding()) {
+ sprintf(buf, "c%02x", i+j);
+ charName = buf;
+ } else {
+ charName = ((Gfx8BitFont *)font)->getCharName(i+j);
+ // this is a kludge for broken PDF files that encode char 32
+ // as .notdef
+ if (i+j == 32 && charName && !strcmp(charName, ".notdef")) {
+ charName = "space";
+ }
+ }
+ writePS("/");
+ writePSName(charName ? charName : (char *)".notdef");
+ // the empty name is legal in PDF and PostScript, but PostScript
+ // uses a double-slash (//...) for "immediately evaluated names",
+ // so we need to add a space character here
+ if (charName && !charName[0]) {
+ writePS(" ");
+ }
+ }
+ writePS((i == 256-8) ? (char *)"]\n" : (char *)"\n");
+ }
+ writePS("pdfMakeFont\n");
+ }
+
+ delete psName;
+}
+
+void PSOutputDev::setupEmbeddedType1Font(Ref *id, GString *psName) {
+ static char hexChar[17] = "0123456789abcdef";
+ Object refObj, strObj, obj1, obj2, obj3;
+ Dict *dict;
+ int length1, length2, length3;
+ int c;
+ int start[4];
+ GBool binMode;
+ int i;
+
+ // check if font is already embedded
+ for (i = 0; i < fontFileIDLen; ++i) {
+ if (fontFileIDs[i].num == id->num &&
+ fontFileIDs[i].gen == id->gen)
+ return;
+ }
+
+ // add entry to fontFileIDs list
+ if (fontFileIDLen >= fontFileIDSize) {
+ fontFileIDSize += 64;
+ fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
+ }
+ fontFileIDs[fontFileIDLen++] = *id;
+
+ // get the font stream and info
+ refObj.initRef(id->num, id->gen);
+ refObj.fetch(xref, &strObj);
+ refObj.free();
+ if (!strObj.isStream()) {
+ error(-1, "Embedded font file object is not a stream");
+ goto err1;
+ }
+ if (!(dict = strObj.streamGetDict())) {
+ error(-1, "Embedded font stream is missing its dictionary");
+ goto err1;
+ }
+ dict->lookup("Length1", &obj1);
+ dict->lookup("Length2", &obj2);
+ dict->lookup("Length3", &obj3);
+ if (!obj1.isInt() || !obj2.isInt() || !obj3.isInt()) {
+ error(-1, "Missing length fields in embedded font stream dictionary");
+ obj1.free();
+ obj2.free();
+ obj3.free();
+ goto err1;
+ }
+ length1 = obj1.getInt();
+ length2 = obj2.getInt();
+ length3 = obj3.getInt();
+ obj1.free();
+ obj2.free();
+ obj3.free();
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // copy ASCII portion of font
+ strObj.streamReset();
+ for (i = 0; i < length1 && (c = strObj.streamGetChar()) != EOF; ++i) {
+ writePSChar(c);
+ }
+
+ // figure out if encrypted portion is binary or ASCII
+ binMode = gFalse;
+ for (i = 0; i < 4; ++i) {
+ start[i] = strObj.streamGetChar();
+ if (start[i] == EOF) {
+ error(-1, "Unexpected end of file in embedded font stream");
+ goto err1;
+ }
+ if (!((start[i] >= '0' && start[i] <= '9') ||
+ (start[i] >= 'A' && start[i] <= 'F') ||
+ (start[i] >= 'a' && start[i] <= 'f')))
+ binMode = gTrue;
+ }
+
+ // convert binary data to ASCII
+ if (binMode) {
+ for (i = 0; i < 4; ++i) {
+ writePSChar(hexChar[(start[i] >> 4) & 0x0f]);
+ writePSChar(hexChar[start[i] & 0x0f]);
+ }
+#if 0 // this causes trouble for various PostScript printers
+ // if Length2 is incorrect (too small), font data gets chopped, so
+ // we take a few extra characters from the trailer just in case
+ length2 += length3 >= 8 ? 8 : length3;
+#endif
+ while (i < length2) {
+ if ((c = strObj.streamGetChar()) == EOF) {
+ break;
+ }
+ writePSChar(hexChar[(c >> 4) & 0x0f]);
+ writePSChar(hexChar[c & 0x0f]);
+ if (++i % 32 == 0) {
+ writePSChar('\n');
+ }
+ }
+ if (i % 32 > 0) {
+ writePSChar('\n');
+ }
+
+ // already in ASCII format -- just copy it
+ } else {
+ for (i = 0; i < 4; ++i) {
+ writePSChar(start[i]);
+ }
+ for (i = 4; i < length2; ++i) {
+ if ((c = strObj.streamGetChar()) == EOF) {
+ break;
+ }
+ writePSChar(c);
+ }
+ }
+
+ // write padding and "cleartomark"
+ for (i = 0; i < 8; ++i) {
+ writePS("00000000000000000000000000000000"
+ "00000000000000000000000000000000\n");
+ }
+ writePS("cleartomark\n");
+
+ // ending comment
+ writePS("%%EndResource\n");
+
+ err1:
+ strObj.streamClose();
+ strObj.free();
+}
+
+//~ This doesn't handle .pfb files or binary eexec data (which only
+//~ happens in pfb files?).
+void PSOutputDev::setupExternalType1Font(GString *fileName, GString *psName) {
+ FILE *fontFile;
+ int c;
+ int i;
+
+ // check if font is already embedded
+ for (i = 0; i < fontFileNameLen; ++i) {
+ if (!fontFileNames[i]->cmp(fileName)) {
+ return;
+ }
+ }
+
+ // add entry to fontFileNames list
+ if (fontFileNameLen >= fontFileNameSize) {
+ fontFileNameSize += 64;
+ fontFileNames = (GString **)greallocn(fontFileNames,
+ fontFileNameSize, sizeof(GString *));
+ psFileNames = (GString **)greallocn(psFileNames,
+ fontFileNameSize, sizeof(GString *));
+ }
+ fontFileNames[fontFileNameLen] = fileName->copy();
+ psFileNames[fontFileNameLen] = psName->copy();
+ fontFileNameLen++;
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // copy the font file
+ if (!(fontFile = fopen(fileName->getCString(), "rb"))) {
+ error(-1, "Couldn't open external font file");
+ return;
+ }
+ while ((c = fgetc(fontFile)) != EOF) {
+ writePSChar(c);
+ }
+ fclose(fontFile);
+
+ // ending comment
+ writePS("%%EndResource\n");
+}
+
+void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id,
+ GString *psName) {
+ char *fontBuf;
+ int fontLen;
+ FoFiType1C *ffT1C;
+ int i;
+
+ // check if font is already embedded
+ for (i = 0; i < fontFileIDLen; ++i) {
+ if (fontFileIDs[i].num == id->num &&
+ fontFileIDs[i].gen == id->gen)
+ return;
+ }
+
+ // add entry to fontFileIDs list
+ if (fontFileIDLen >= fontFileIDSize) {
+ fontFileIDSize += 64;
+ fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
+ }
+ fontFileIDs[fontFileIDLen++] = *id;
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // convert it to a Type 1 font
+ fontBuf = font->readEmbFontFile(xref, &fontLen);
+ if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
+ ffT1C->convertToType1(psName->getCString(), NULL, gTrue,
+ outputFunc, outputStream);
+ delete ffT1C;
+ }
+ gfree(fontBuf);
+
+ // ending comment
+ writePS("%%EndResource\n");
+}
+
+void PSOutputDev::setupEmbeddedOpenTypeT1CFont(GfxFont *font, Ref *id,
+ GString *psName) {
+ char *fontBuf;
+ int fontLen;
+ FoFiTrueType *ffTT;
+ int i;
+
+ // check if font is already embedded
+ for (i = 0; i < fontFileIDLen; ++i) {
+ if (fontFileIDs[i].num == id->num &&
+ fontFileIDs[i].gen == id->gen)
+ return;
+ }
+
+ // add entry to fontFileIDs list
+ if (fontFileIDLen >= fontFileIDSize) {
+ fontFileIDSize += 64;
+ fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
+ }
+ fontFileIDs[fontFileIDLen++] = *id;
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // convert it to a Type 1 font
+ fontBuf = font->readEmbFontFile(xref, &fontLen);
+ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
+ if (ffTT->isOpenTypeCFF()) {
+ ffTT->convertToType1(psName->getCString(), NULL, gTrue,
+ outputFunc, outputStream);
+ }
+ delete ffTT;
+ }
+ gfree(fontBuf);
+
+ // ending comment
+ writePS("%%EndResource\n");
+}
+
+void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id,
+ GString *psName) {
+ char *fontBuf;
+ int fontLen;
+ FoFiTrueType *ffTT;
+ Gushort *codeToGID;
+ int i;
+
+ // check if font is already embedded
+ for (i = 0; i < fontFileIDLen; ++i) {
+ if (fontFileIDs[i].num == id->num &&
+ fontFileIDs[i].gen == id->gen) {
+ psName->appendf("_{0:d}", nextTrueTypeNum++);
+ break;
+ }
+ }
+
+ // add entry to fontFileIDs list
+ if (i == fontFileIDLen) {
+ if (fontFileIDLen >= fontFileIDSize) {
+ fontFileIDSize += 64;
+ fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
+ }
+ fontFileIDs[fontFileIDLen++] = *id;
+ }
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // convert it to a Type 42 font
+ fontBuf = font->readEmbFontFile(xref, &fontLen);
+ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
+ codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT);
+ ffTT->convertToType42(psName->getCString(),
+ ((Gfx8BitFont *)font)->getHasEncoding()
+ ? ((Gfx8BitFont *)font)->getEncoding()
+ : (char **)NULL,
+ codeToGID, outputFunc, outputStream);
+ if (codeToGID) {
+ if (font8InfoLen >= font8InfoSize) {
+ font8InfoSize += 16;
+ font8Info = (PSFont8Info *)greallocn(font8Info,
+ font8InfoSize,
+ sizeof(PSFont8Info));
+ }
+ font8Info[font8InfoLen].fontID = *font->getID();
+ font8Info[font8InfoLen].codeToGID = codeToGID;
+ ++font8InfoLen;
+ }
+ delete ffTT;
+ }
+ gfree(fontBuf);
+
+ // ending comment
+ writePS("%%EndResource\n");
+}
+
+GString *PSOutputDev::setupExternalTrueTypeFont(GfxFont *font) {
+ GString *fileName;
+ char *fontBuf;
+ int fontLen;
+ FoFiTrueType *ffTT;
+ Gushort *codeToGID;
+ GString *psName;
+ int i;
+
+ // check if font is already embedded
+ fileName = font->getExtFontFile();
+ for (i = 0; i < fontFileNameLen; ++i) {
+ if (!fontFileNames[i]->cmp(fileName)) {
+ return psFileNames[i]->copy();
+ }
+ }
+
+ psName = filterPSName(font->getName());
+ // add entry to fontFileNames list
+ if (i == fontFileNameLen) {
+ if (fontFileNameLen >= fontFileNameSize) {
+ fontFileNameSize += 64;
+ fontFileNames =
+ (GString **)greallocn(fontFileNames,
+ fontFileNameSize, sizeof(GString *));
+ psFileNames =
+ (GString **)greallocn(psFileNames,
+ fontFileNameSize, sizeof(GString *));
+ }
+ fontFileNames[fontFileNameLen] = fileName->copy();
+ psFileNames[fontFileNameLen] = psName->copy();
+ fontFileNameLen++;
+ }
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // convert it to a Type 42 font
+ fontBuf = font->readExtFontFile(&fontLen);
+ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
+ codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT);
+ ffTT->convertToType42(psName->getCString(),
+ ((Gfx8BitFont *)font)->getHasEncoding()
+ ? ((Gfx8BitFont *)font)->getEncoding()
+ : (char **)NULL,
+ codeToGID, outputFunc, outputStream);
+ if (codeToGID) {
+ if (font8InfoLen >= font8InfoSize) {
+ font8InfoSize += 16;
+ font8Info = (PSFont8Info *)greallocn(font8Info,
+ font8InfoSize,
+ sizeof(PSFont8Info));
+ }
+ font8Info[font8InfoLen].fontID = *font->getID();
+ font8Info[font8InfoLen].codeToGID = codeToGID;
+ ++font8InfoLen;
+ }
+ delete ffTT;
+ }
+ gfree(fontBuf);
+
+ // ending comment
+ writePS("%%EndResource\n");
+ return psName;
+}
+
+GString *PSOutputDev::setupExternalCIDTrueTypeFont(GfxFont *font, GString *fileName, int faceIndex) {
+ FoFiTrueType *ffTT;
+ Gushort *codeToGID;
+ GString *psName;
+ int i;
+ GString *myFileName;
+
+ myFileName = fileName->copy();
+ if (faceIndex > 0) {
+ char tmp[32];
+ sprintf(tmp, ",%d", faceIndex);
+ myFileName->append(tmp);
+ }
+ // check if font is already embedded
+ for (i = 0; i < fontFileNameLen; ++i) {
+ if (!fontFileNames[i]->cmp(myFileName)) {
+ delete myFileName;
+ return psFileNames[i]->copy();
+ }
+ }
+
+ psName = filterPSName(font->getName());
+ // add entry to fontFileNames list
+ if (i == fontFileNameLen) {
+ if (fontFileNameLen >= fontFileNameSize) {
+ fontFileNameSize += 64;
+ fontFileNames =
+ (GString **)grealloc(fontFileNames,
+ fontFileNameSize * sizeof(GString *));
+ psFileNames =
+ (GString **)grealloc(psFileNames,
+ fontFileNameSize * sizeof(GString *));
+ }
+ }
+ fontFileNames[fontFileNameLen] = myFileName;
+ psFileNames[fontFileNameLen] = psName->copy();
+ fontFileNameLen++;
+
+ // beginning comment
+ writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // convert it to a CID type2 font
+ if ((ffTT = FoFiTrueType::load(fileName->getCString(), faceIndex))) {
+ int n = ((GfxCIDFont *)font)->getCIDToGIDLen();
+ if (n) {
+ codeToGID = (Gushort *)gmalloc(n * sizeof(Gushort));
+ memcpy(codeToGID, ((GfxCIDFont *)font)->getCIDToGID(), n * sizeof(Gushort));
+ } else {
+ codeToGID = ((GfxCIDFont *)font)->getCodeToGIDMap(ffTT, &n);
+ }
+ if (globalParams->getPSLevel() >= psLevel3) {
+ // Level 3: use a CID font
+ ffTT->convertToCIDType2(psName->getCString(),
+ codeToGID, n, gTrue,
+ outputFunc, outputStream);
+ } else {
+ // otherwise: use a non-CID composite font
+ ffTT->convertToType0(psName->getCString(),
+ codeToGID, n, gTrue,
+ outputFunc, outputStream);
+ }
+ gfree(codeToGID);
+ delete ffTT;
+ }
+
+ // ending comment
+ writePS("%%EndResource\n");
+ return psName;
+}
+
+void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id,
+ GString *psName) {
+ char *fontBuf;
+ int fontLen;
+ FoFiType1C *ffT1C;
+ int i;
+
+ // check if font is already embedded
+ for (i = 0; i < fontFileIDLen; ++i) {
+ if (fontFileIDs[i].num == id->num &&
+ fontFileIDs[i].gen == id->gen)
+ return;
+ }
+
+ // add entry to fontFileIDs list
+ if (fontFileIDLen >= fontFileIDSize) {
+ fontFileIDSize += 64;
+ fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
+ }
+ fontFileIDs[fontFileIDLen++] = *id;
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // convert it to a Type 0 font
+ fontBuf = font->readEmbFontFile(xref, &fontLen);
+ if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) {
+ if (globalParams->getPSLevel() >= psLevel3) {
+ // Level 3: use a CID font
+ ffT1C->convertToCIDType0(psName->getCString(), outputFunc, outputStream);
+ } else {
+ // otherwise: use a non-CID composite font
+ ffT1C->convertToType0(psName->getCString(), outputFunc, outputStream);
+ }
+ delete ffT1C;
+ }
+ gfree(fontBuf);
+
+ // ending comment
+ writePS("%%EndResource\n");
+}
+
+void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id,
+ GString *psName,
+ GBool needVerticalMetrics) {
+ char *fontBuf;
+ int fontLen;
+ FoFiTrueType *ffTT;
+ int i;
+
+ // check if font is already embedded
+ for (i = 0; i < fontFileIDLen; ++i) {
+ if (fontFileIDs[i].num == id->num &&
+ fontFileIDs[i].gen == id->gen) {
+ psName->appendf("_{0:d}", nextTrueTypeNum++);
+ break;
+ }
+ }
+
+ // add entry to fontFileIDs list
+ if (fontFileIDLen >= fontFileIDSize) {
+ fontFileIDSize += 64;
+ fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
+ }
+ fontFileIDs[fontFileIDLen++] = *id;
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // convert it to a Type 0 font
+ fontBuf = font->readEmbFontFile(xref, &fontLen);
+ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
+ if (globalParams->getPSLevel() >= psLevel3) {
+ // Level 3: use a CID font
+ ffTT->convertToCIDType2(psName->getCString(),
+ ((GfxCIDFont *)font)->getCIDToGID(),
+ ((GfxCIDFont *)font)->getCIDToGIDLen(),
+ needVerticalMetrics,
+ outputFunc, outputStream);
+ } else {
+ // otherwise: use a non-CID composite font
+ ffTT->convertToType0(psName->getCString(),
+ ((GfxCIDFont *)font)->getCIDToGID(),
+ ((GfxCIDFont *)font)->getCIDToGIDLen(),
+ needVerticalMetrics,
+ outputFunc, outputStream);
+ }
+ delete ffTT;
+ }
+ gfree(fontBuf);
+
+ // ending comment
+ writePS("%%EndResource\n");
+}
+
+void PSOutputDev::setupEmbeddedOpenTypeCFFFont(GfxFont *font, Ref *id,
+ GString *psName) {
+ char *fontBuf;
+ int fontLen;
+ FoFiTrueType *ffTT;
+ int i;
+
+ // check if font is already embedded
+ for (i = 0; i < fontFileIDLen; ++i) {
+ if (fontFileIDs[i].num == id->num &&
+ fontFileIDs[i].gen == id->gen)
+ return;
+ }
+
+ // add entry to fontFileIDs list
+ if (fontFileIDLen >= fontFileIDSize) {
+ fontFileIDSize += 64;
+ fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref));
+ }
+ fontFileIDs[fontFileIDLen++] = *id;
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // convert it to a Type 0 font
+ fontBuf = font->readEmbFontFile(xref, &fontLen);
+ if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) {
+ if (ffTT->isOpenTypeCFF()) {
+ if (globalParams->getPSLevel() >= psLevel3) {
+ // Level 3: use a CID font
+ ffTT->convertToCIDType0(psName->getCString(),
+ outputFunc, outputStream);
+ } else {
+ // otherwise: use a non-CID composite font
+ ffTT->convertToType0(psName->getCString(), outputFunc, outputStream);
+ }
+ }
+ delete ffTT;
+ }
+ gfree(fontBuf);
+
+ // ending comment
+ writePS("%%EndResource\n");
+}
+
+void PSOutputDev::setupType3Font(GfxFont *font, GString *psName,
+ Dict *parentResDict) {
+ Dict *resDict;
+ Dict *charProcs;
+ Object charProc;
+ Gfx *gfx;
+ PDFRectangle box;
+ double *m;
+ GString *buf;
+ int i;
+
+ // set up resources used by font
+ if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
+ inType3Char = gTrue;
+ setupResources(resDict);
+ inType3Char = gFalse;
+ } else {
+ resDict = parentResDict;
+ }
+
+ // beginning comment
+ writePSFmt("%%BeginResource: font {0:t}\n", psName);
+ embFontList->append("%%+ font ");
+ embFontList->append(psName->getCString());
+ embFontList->append("\n");
+
+ // font dictionary
+ writePS("8 dict begin\n");
+ writePS("/FontType 3 def\n");
+ m = font->getFontMatrix();
+ writePSFmt("/FontMatrix [{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g}] def\n",
+ m[0], m[1], m[2], m[3], m[4], m[5]);
+ m = font->getFontBBox();
+ writePSFmt("/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] def\n",
+ m[0], m[1], m[2], m[3]);
+ writePS("/Encoding 256 array def\n");
+ writePS(" 0 1 255 { Encoding exch /.notdef put } for\n");
+ writePS("/BuildGlyph {\n");
+ writePS(" exch /CharProcs get exch\n");
+ writePS(" 2 copy known not { pop /.notdef } if\n");
+ writePS(" get exec\n");
+ writePS("} bind def\n");
+ writePS("/BuildChar {\n");
+ writePS(" 1 index /Encoding get exch get\n");
+ writePS(" 1 index /BuildGlyph get exec\n");
+ writePS("} bind def\n");
+ if ((charProcs = ((Gfx8BitFont *)font)->getCharProcs())) {
+ writePSFmt("/CharProcs {0:d} dict def\n", charProcs->getLength());
+ writePS("CharProcs begin\n");
+ box.x1 = m[0];
+ box.y1 = m[1];
+ box.x2 = m[2];
+ box.y2 = m[3];
+ gfx = new Gfx(xref, this, resDict, &box, NULL);
+ inType3Char = gTrue;
+ for (i = 0; i < charProcs->getLength(); ++i) {
+ t3Cacheable = gFalse;
+ t3NeedsRestore = gFalse;
+ writePS("/");
+ writePSName(charProcs->getKey(i));
+ writePS(" {\n");
+ gfx->display(charProcs->getVal(i, &charProc));
+ charProc.free();
+ if (t3String) {
+ if (t3Cacheable) {
+ buf = GString::format("{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g} setcachedevice\n",
+ t3WX, t3WY, t3LLX, t3LLY, t3URX, t3URY);
+ } else {
+ buf = GString::format("{0:.4g} {1:.4g} setcharwidth\n", t3WX, t3WY);
+ }
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ (*outputFunc)(outputStream, t3String->getCString(),
+ t3String->getLength());
+ delete t3String;
+ t3String = NULL;
+ }
+ if (t3NeedsRestore) {
+ (*outputFunc)(outputStream, "Q\n", 2);
+ }
+ writePS("} def\n");
+ }
+ inType3Char = gFalse;
+ delete gfx;
+ writePS("end\n");
+ }
+ writePS("currentdict end\n");
+ writePSFmt("/{0:t} exch definefont pop\n", psName);
+
+ // ending comment
+ writePS("%%EndResource\n");
+}
+
+void PSOutputDev::setupImages(Dict *resDict) {
+ Object xObjDict, xObj, xObjRef, subtypeObj;
+ int i;
+
+ if (!(mode == psModeForm || inType3Char || preload)) {
+ return;
+ }
+
+ resDict->lookup("XObject", &xObjDict);
+ if (xObjDict.isDict()) {
+ for (i = 0; i < xObjDict.dictGetLength(); ++i) {
+ xObjDict.dictGetValNF(i, &xObjRef);
+ xObjDict.dictGetVal(i, &xObj);
+ if (xObj.isStream()) {
+ xObj.streamGetDict()->lookup("Subtype", &subtypeObj);
+ if (subtypeObj.isName("Image")) {
+ if (xObjRef.isRef()) {
+ setupImage(xObjRef.getRef(), xObj.getStream());
+ } else {
+ error(-1, "Image in resource dict is not an indirect reference");
+ }
+ }
+ subtypeObj.free();
+ }
+ xObj.free();
+ xObjRef.free();
+ }
+ }
+ xObjDict.free();
+}
+
+void PSOutputDev::setupImage(Ref id, Stream *str) {
+ GBool useRLE, useCompressed, useASCIIHex;
+ GString *s;
+ int c;
+ int size, line, col, i;
+
+ // check if image is already setup
+ for (i = 0; i < imgIDLen; ++i) {
+ if (imgIDs[i].num == id.num && imgIDs[i].gen == id.gen) {
+ return;
+ }
+ }
+
+ // add entry to imgIDs list
+ if (imgIDLen >= imgIDSize) {
+ if (imgIDSize == 0) {
+ imgIDSize = 64;
+ } else {
+ imgIDSize *= 2;
+ }
+ imgIDs = (Ref *)greallocn(imgIDs, imgIDSize, sizeof(Ref));
+ }
+ imgIDs[imgIDLen++] = id;
+
+ // filters
+ //~ this does not correctly handle the DeviceN color space
+ //~ -- need to use DeviceNRecoder
+ if (level < psLevel2) {
+ useRLE = gFalse;
+ useCompressed = gFalse;
+ useASCIIHex = gTrue;
+ } else {
+ s = str->getPSFilter(level < psLevel3 ? 2 : 3, "");
+ if (s) {
+ useRLE = gFalse;
+ useCompressed = gTrue;
+ delete s;
+ } else {
+ useRLE = gTrue;
+ useCompressed = gFalse;
+ }
+ useASCIIHex = level == psLevel1 || level == psLevel1Sep ||
+ globalParams->getPSASCIIHex();
+ }
+ if (useCompressed) {
+ str = str->getUndecodedStream();
+ }
+ if (useRLE) {
+ str = new RunLengthEncoder(str);
+ }
+ if (useASCIIHex) {
+ str = new ASCIIHexEncoder(str);
+ } else {
+ str = new ASCII85Encoder(str);
+ }
+
+ // compute image data size
+ str->reset();
+ col = size = 0;
+ do {
+ do {
+ c = str->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
+ break;
+ }
+ if (c == 'z') {
+ ++col;
+ } else {
+ ++col;
+ for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) {
+ do {
+ c = str->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
+ break;
+ }
+ ++col;
+ }
+ }
+ if (col > 225) {
+ ++size;
+ col = 0;
+ }
+ } while (c != (useASCIIHex ? '>' : '~') && c != EOF);
+ // add one entry for the final line of data; add another entry
+ // because the RunLengthDecode filter may read past the end
+ ++size;
+ if (useRLE) {
+ ++size;
+ }
+ writePSFmt("{0:d} array dup /ImData_{1:d}_{2:d} exch def\n",
+ size, id.num, id.gen);
+ str->close();
+
+ // write the data into the array
+ str->reset();
+ line = col = 0;
+ writePS((char *)(useASCIIHex ? "dup 0 <" : "dup 0 <~"));
+ do {
+ do {
+ c = str->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
+ break;
+ }
+ if (c == 'z') {
+ writePSChar(c);
+ ++col;
+ } else {
+ writePSChar(c);
+ ++col;
+ for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) {
+ do {
+ c = str->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
+ break;
+ }
+ writePSChar(c);
+ ++col;
+ }
+ }
+ // each line is: "dup nnnnn <~...data...~> put<eol>"
+ // so max data length = 255 - 20 = 235
+ // chunks are 1 or 4 bytes each, so we have to stop at 232
+ // but make it 225 just to be safe
+ if (col > 225) {
+ writePS((char *)(useASCIIHex ? "> put\n" : "~> put\n"));
+ ++line;
+ writePSFmt((char *)(useASCIIHex ? "dup {0:d} <" : "dup {0:d} <~"), line);
+ col = 0;
+ }
+ } while (c != (useASCIIHex ? '>' : '~') && c != EOF);
+ writePS((char *)(useASCIIHex ? "> put\n" : "~> put\n"));
+ if (useRLE) {
+ ++line;
+ writePSFmt("{0:d} <> put\n", line);
+ } else {
+ writePS("pop\n");
+ }
+ str->close();
+
+ delete str;
+}
+
+void PSOutputDev::setupForms(Dict *resDict) {
+ Object xObjDict, xObj, xObjRef, subtypeObj;
+ int i;
+
+ if (!preload) {
+ return;
+ }
+
+ resDict->lookup("XObject", &xObjDict);
+ if (xObjDict.isDict()) {
+ for (i = 0; i < xObjDict.dictGetLength(); ++i) {
+ xObjDict.dictGetValNF(i, &xObjRef);
+ xObjDict.dictGetVal(i, &xObj);
+ if (xObj.isStream()) {
+ xObj.streamGetDict()->lookup("Subtype", &subtypeObj);
+ if (subtypeObj.isName("Form")) {
+ if (xObjRef.isRef()) {
+ setupForm(xObjRef.getRef(), &xObj);
+ } else {
+ error(-1, "Form in resource dict is not an indirect reference");
+ }
+ }
+ subtypeObj.free();
+ }
+ xObj.free();
+ xObjRef.free();
+ }
+ }
+ xObjDict.free();
+}
+
+void PSOutputDev::setupForm(Ref id, Object *strObj) {
+ Dict *dict, *resDict;
+ Object matrixObj, bboxObj, resObj, obj1;
+ double m[6], bbox[4];
+ PDFRectangle box;
+ Gfx *gfx;
+ int i;
+
+ // check if form is already defined
+ for (i = 0; i < formIDLen; ++i) {
+ if (formIDs[i].num == id.num && formIDs[i].gen == id.gen) {
+ return;
+ }
+ }
+
+ // add entry to formIDs list
+ if (formIDLen >= formIDSize) {
+ if (formIDSize == 0) {
+ formIDSize = 64;
+ } else {
+ formIDSize *= 2;
+ }
+ formIDs = (Ref *)greallocn(formIDs, formIDSize, sizeof(Ref));
+ }
+ formIDs[formIDLen++] = id;
+
+ dict = strObj->streamGetDict();
+
+ // get bounding box
+ dict->lookup("BBox", &bboxObj);
+ if (!bboxObj.isArray()) {
+ bboxObj.free();
+ error(-1, "Bad form bounding box");
+ return;
+ }
+ for (i = 0; i < 4; ++i) {
+ bboxObj.arrayGet(i, &obj1);
+ bbox[i] = obj1.getNum();
+ obj1.free();
+ }
+ bboxObj.free();
+
+ // get matrix
+ dict->lookup("Matrix", &matrixObj);
+ if (matrixObj.isArray()) {
+ for (i = 0; i < 6; ++i) {
+ matrixObj.arrayGet(i, &obj1);
+ m[i] = obj1.getNum();
+ obj1.free();
+ }
+ } else {
+ m[0] = 1; m[1] = 0;
+ m[2] = 0; m[3] = 1;
+ m[4] = 0; m[5] = 0;
+ }
+ matrixObj.free();
+
+ // get resources
+ dict->lookup("Resources", &resObj);
+ resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
+
+ writePSFmt("/f_{0:d}_{1:d} {{\n", id.num, id.gen);
+ writePS("q\n");
+ writePSFmt("[{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g}] cm\n",
+ m[0], m[1], m[2], m[3], m[4], m[5]);
+
+ box.x1 = bbox[0];
+ box.y1 = bbox[1];
+ box.x2 = bbox[2];
+ box.y2 = bbox[3];
+ gfx = new Gfx(xref, this, resDict, &box, &box);
+ gfx->display(strObj);
+ delete gfx;
+
+ writePS("Q\n");
+ writePS("} def\n");
+
+ resObj.free();
+}
+
+GBool PSOutputDev::checkPageSlice(Page *page, double /*hDPI*/, double /*vDPI*/,
+ int rotateA, GBool useMediaBox, GBool crop,
+ int sliceX, int sliceY,
+ int sliceW, int sliceH,
+ GBool printing, Catalog *catalog,
+ GBool (*abortCheckCbk)(void *data),
+ void *abortCheckCbkData) {
+#if HAVE_SPLASH
+ PreScanOutputDev *scan;
+ GBool rasterize;
+ SplashOutputDev *splashOut;
+ SplashColor paperColor;
+ PDFRectangle box;
+ GfxState *state;
+ SplashBitmap *bitmap;
+ Stream *str0, *str;
+ Object obj;
+ Guchar *p;
+ Guchar col[4];
+ double m0, m1, m2, m3, m4, m5;
+ int c, w, h, x, y, comp, i;
+
+ if (!forceRasterize) {
+ scan = new PreScanOutputDev();
+ page->displaySlice(scan, 72, 72, rotateA, useMediaBox, crop,
+ sliceX, sliceY, sliceW, sliceH,
+ printing, catalog, abortCheckCbk, abortCheckCbkData);
+ rasterize = scan->usesTransparency();
+ delete scan;
+ } else {
+ rasterize = true;
+ }
+ if (!rasterize) {
+ return gTrue;
+ }
+
+ // rasterize the page
+ if (level == psLevel1) {
+ paperColor[0] = 0xff;
+ splashOut = new SplashOutputDev(splashModeMono8, 1, gFalse,
+ paperColor, gTrue, gFalse);
+#if SPLASH_CMYK
+ } else if (level == psLevel1Sep) {
+ paperColor[0] = paperColor[1] = paperColor[2] = paperColor[3] = 0;
+ splashOut = new SplashOutputDev(splashModeCMYK8, 1, gFalse,
+ paperColor, gTrue, gFalse);
+#endif
+ } else {
+ paperColor[0] = paperColor[1] = paperColor[2] = 0xff;
+ splashOut = new SplashOutputDev(splashModeRGB8, 1, gFalse,
+ paperColor, gTrue, gFalse);
+ }
+ splashOut->startDoc(xref);
+ page->displaySlice(splashOut, splashDPI, splashDPI, rotateA,
+ useMediaBox, crop,
+ sliceX, sliceY, sliceW, sliceH,
+ printing, catalog, abortCheckCbk, abortCheckCbkData);
+
+ // start the PS page
+ page->makeBox(splashDPI, splashDPI, rotateA, useMediaBox, gFalse,
+ sliceX, sliceY, sliceW, sliceH, &box, &crop);
+ rotateA += page->getRotate();
+ if (rotateA >= 360) {
+ rotateA -= 360;
+ } else if (rotateA < 0) {
+ rotateA += 360;
+ }
+ state = new GfxState(splashDPI, splashDPI, &box, rotateA, gFalse);
+ startPage(page->getNum(), state);
+ delete state;
+ switch (rotateA) {
+ case 0:
+ default: // this should never happen
+ m0 = box.x2 - box.x1;
+ m1 = 0;
+ m2 = 0;
+ m3 = box.y2 - box.y1;
+ m4 = box.x1;
+ m5 = box.y1;
+ break;
+ case 90:
+ m0 = 0;
+ m1 = box.y2 - box.y1;
+ m2 = -(box.x2 - box.x1);
+ m3 = 0;
+ m4 = box.x2;
+ m5 = box.y1;
+ break;
+ case 180:
+ m0 = -(box.x2 - box.x1);
+ m1 = 0;
+ m2 = 0;
+ m3 = -(box.y2 - box.y1);
+ m4 = box.x2;
+ m5 = box.y2;
+ break;
+ case 270:
+ m0 = 0;
+ m1 = -(box.y2 - box.y1);
+ m2 = box.x2 - box.x1;
+ m3 = 0;
+ m4 = box.x1;
+ m5 = box.y2;
+ break;
+ }
+
+ //~ need to add the process colors
+
+ // draw the rasterized image
+ bitmap = splashOut->getBitmap();
+ w = bitmap->getWidth();
+ h = bitmap->getHeight();
+ writePS("gsave\n");
+ writePSFmt("[{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g}] concat\n",
+ m0, m1, m2, m3, m4, m5);
+ switch (level) {
+ case psLevel1:
+ writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1\n",
+ w, h, w, -h, h);
+ p = bitmap->getDataPtr();
+ i = 0;
+ for (y = 0; y < h; ++y) {
+ for (x = 0; x < w; ++x) {
+ writePSFmt("{0:02x}", *p++);
+ if (++i == 32) {
+ writePSChar('\n');
+ i = 0;
+ }
+ }
+ }
+ if (i != 0) {
+ writePSChar('\n');
+ }
+ break;
+ case psLevel1Sep:
+ writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1Sep\n",
+ w, h, w, -h, h);
+ p = bitmap->getDataPtr();
+ i = 0;
+ col[0] = col[1] = col[2] = col[3] = 0;
+ for (y = 0; y < h; ++y) {
+ for (comp = 0; comp < 4; ++comp) {
+ for (x = 0; x < w; ++x) {
+ writePSFmt("{0:02x}", p[4*x + comp]);
+ col[comp] |= p[4*x + comp];
+ if (++i == 32) {
+ writePSChar('\n');
+ i = 0;
+ }
+ }
+ }
+ p += bitmap->getRowSize();
+ }
+ if (i != 0) {
+ writePSChar('\n');
+ }
+ if (col[0]) {
+ processColors |= psProcessCyan;
+ }
+ if (col[1]) {
+ processColors |= psProcessMagenta;
+ }
+ if (col[2]) {
+ processColors |= psProcessYellow;
+ }
+ if (col[3]) {
+ processColors |= psProcessBlack;
+ }
+ break;
+ case psLevel2:
+ case psLevel2Sep:
+ case psLevel3:
+ case psLevel3Sep:
+ writePS("/DeviceRGB setcolorspace\n");
+ writePS("<<\n /ImageType 1\n");
+ writePSFmt(" /Width {0:d}\n", bitmap->getWidth());
+ writePSFmt(" /Height {0:d}\n", bitmap->getHeight());
+ writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n", w, -h, h);
+ writePS(" /BitsPerComponent 8\n");
+ writePS(" /Decode [0 1 0 1 0 1]\n");
+ writePS(" /DataSource currentfile\n");
+ if (globalParams->getPSASCIIHex()) {
+ writePS(" /ASCIIHexDecode filter\n");
+ } else {
+ writePS(" /ASCII85Decode filter\n");
+ }
+ writePS(" /RunLengthDecode filter\n");
+ writePS(">>\n");
+ writePS("image\n");
+ obj.initNull();
+ str0 = new MemStream((char *)bitmap->getDataPtr(), 0, w * h * 3, &obj);
+ str = new RunLengthEncoder(str0);
+ if (globalParams->getPSASCIIHex()) {
+ str = new ASCIIHexEncoder(str);
+ } else {
+ str = new ASCII85Encoder(str);
+ }
+ str->reset();
+ while ((c = str->getChar()) != EOF) {
+ writePSChar(c);
+ }
+ str->close();
+ delete str;
+ delete str0;
+ processColors |= psProcessCMYK;
+ break;
+ }
+ delete splashOut;
+ writePS("grestore\n");
+
+ // finish the PS page
+ endPage();
+
+ return gFalse;
+#else
+ return gTrue;
+#endif
+}
+
+void PSOutputDev::startPage(int pageNum, GfxState *state) {
+ int x1, y1, x2, y2, width, height;
+ int imgWidth, imgHeight, imgWidth2, imgHeight2;
+ GBool landscape;
+
+
+ if (mode == psModePS) {
+ writePSFmt("%%Page: {0:d} {1:d}\n", pageNum, seqPage);
+ writePS("%%BeginPageSetup\n");
+ }
+
+ // underlays
+ if (underlayCbk) {
+ (*underlayCbk)(this, underlayCbkData);
+ }
+ if (overlayCbk) {
+ saveState(NULL);
+ }
+
+ switch (mode) {
+
+ case psModePS:
+ // rotate, translate, and scale page
+ imgWidth = imgURX - imgLLX;
+ imgHeight = imgURY - imgLLY;
+ x1 = (int)floor(state->getX1());
+ y1 = (int)floor(state->getY1());
+ x2 = (int)ceil(state->getX2());
+ y2 = (int)ceil(state->getY2());
+ width = x2 - x1;
+ height = y2 - y1;
+ tx = ty = 0;
+ // rotation and portrait/landscape mode
+ if (rotate0 >= 0) {
+ rotate = (360 - rotate0) % 360;
+ landscape = gFalse;
+ } else {
+ rotate = (360 - state->getRotate()) % 360;
+ if (rotate == 0 || rotate == 180) {
+ if (width > height && width > imgWidth) {
+ rotate += 90;
+ landscape = gTrue;
+ } else {
+ landscape = gFalse;
+ }
+ } else { // rotate == 90 || rotate == 270
+ if (height > width && height > imgWidth) {
+ rotate = 270 - rotate;
+ landscape = gTrue;
+ } else {
+ landscape = gFalse;
+ }
+ }
+ }
+ writePSFmt("%%PageOrientation: {0:s}\n",
+ landscape ? "Landscape" : "Portrait");
+ writePS("pdfStartPage\n");
+ if (rotate == 0) {
+ imgWidth2 = imgWidth;
+ imgHeight2 = imgHeight;
+ } else if (rotate == 90) {
+ writePS("90 rotate\n");
+ ty = -imgWidth;
+ imgWidth2 = imgHeight;
+ imgHeight2 = imgWidth;
+ } else if (rotate == 180) {
+ writePS("180 rotate\n");
+ imgWidth2 = imgWidth;
+ imgHeight2 = imgHeight;
+ tx = -imgWidth;
+ ty = -imgHeight;
+ } else { // rotate == 270
+ writePS("270 rotate\n");
+ tx = -imgHeight;
+ imgWidth2 = imgHeight;
+ imgHeight2 = imgWidth;
+ }
+ // shrink or expand
+ if (xScale0 > 0 && yScale0 > 0) {
+ xScale = xScale0;
+ yScale = yScale0;
+ } else if ((globalParams->getPSShrinkLarger() &&
+ (width > imgWidth2 || height > imgHeight2)) ||
+ (globalParams->getPSExpandSmaller() &&
+ (width < imgWidth2 && height < imgHeight2))) {
+ xScale = (double)imgWidth2 / (double)width;
+ yScale = (double)imgHeight2 / (double)height;
+ if (yScale < xScale) {
+ xScale = yScale;
+ } else {
+ yScale = xScale;
+ }
+ } else {
+ xScale = yScale = 1;
+ }
+ // deal with odd bounding boxes or clipping
+ if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) {
+ tx -= xScale * clipLLX0;
+ ty -= yScale * clipLLY0;
+ } else {
+ tx -= xScale * x1;
+ ty -= yScale * y1;
+ }
+ // center
+ if (tx0 >= 0 && ty0 >= 0) {
+ tx += rotate == 0 ? tx0 : ty0;
+ ty += rotate == 0 ? ty0 : -tx0;
+ } else if (globalParams->getPSCenter()) {
+ if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) {
+ tx += (imgWidth2 - xScale * (clipURX0 - clipLLX0)) / 2;
+ ty += (imgHeight2 - yScale * (clipURY0 - clipLLY0)) / 2;
+ } else {
+ tx += (imgWidth2 - xScale * width) / 2;
+ ty += (imgHeight2 - yScale * height) / 2;
+ }
+ }
+ tx += rotate == 0 ? imgLLX : imgLLY;
+ ty += rotate == 0 ? imgLLY : -imgLLX;
+ if (tx != 0 || ty != 0) {
+ writePSFmt("{0:.4g} {1:.4g} translate\n", tx, ty);
+ }
+ if (xScale != 1 || yScale != 1) {
+ writePSFmt("{0:.4f} {1:.4f} scale\n", xScale, yScale);
+ }
+ if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) {
+ writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} re W\n",
+ clipLLX0, clipLLY0, clipURX0 - clipLLX0, clipURY0 - clipLLY0);
+ } else {
+ writePSFmt("{0:d} {1:d} {2:d} {3:d} re W\n", x1, y1, x2 - x1, y2 - y1);
+ }
+
+ writePS("%%EndPageSetup\n");
+ ++seqPage;
+ break;
+
+ case psModeEPS:
+ writePS("pdfStartPage\n");
+ tx = ty = 0;
+ rotate = (360 - state->getRotate()) % 360;
+ if (rotate == 0) {
+ } else if (rotate == 90) {
+ writePS("90 rotate\n");
+ tx = -epsX1;
+ ty = -epsY2;
+ } else if (rotate == 180) {
+ writePS("180 rotate\n");
+ tx = -(epsX1 + epsX2);
+ ty = -(epsY1 + epsY2);
+ } else { // rotate == 270
+ writePS("270 rotate\n");
+ tx = -epsX2;
+ ty = -epsY1;
+ }
+ if (tx != 0 || ty != 0) {
+ writePSFmt("{0:.4g} {1:.4g} translate\n", tx, ty);
+ }
+ xScale = yScale = 1;
+ break;
+
+ case psModeForm:
+ writePS("/PaintProc {\n");
+ writePS("begin xpdf begin\n");
+ writePS("pdfStartPage\n");
+ tx = ty = 0;
+ xScale = yScale = 1;
+ rotate = 0;
+ break;
+ }
+}
+
+void PSOutputDev::endPage() {
+ if (overlayCbk) {
+ restoreState(NULL);
+ (*overlayCbk)(this, overlayCbkData);
+ }
+
+
+ if (mode == psModeForm) {
+ writePS("pdfEndPage\n");
+ writePS("end end\n");
+ writePS("} def\n");
+ writePS("end end\n");
+ } else {
+ if (!manualCtrl) {
+ writePS("showpage\n");
+ }
+ writePS("%%PageTrailer\n");
+ writePageTrailer();
+ }
+}
+
+void PSOutputDev::saveState(GfxState * /*state*/) {
+ writePS("q\n");
+ ++numSaves;
+}
+
+void PSOutputDev::restoreState(GfxState * /*state*/) {
+ writePS("Q\n");
+ --numSaves;
+}
+
+void PSOutputDev::updateCTM(GfxState * /*state*/, double m11, double m12,
+ double m21, double m22, double m31, double m32) {
+ writePSFmt("[{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g}] cm\n",
+ m11, m12, m21, m22, m31, m32);
+}
+
+void PSOutputDev::updateLineDash(GfxState *state) {
+ double *dash;
+ double start;
+ int length, i;
+
+ state->getLineDash(&dash, &length, &start);
+ writePS("[");
+ for (i = 0; i < length; ++i) {
+ writePSFmt("{0:.4g}{1:w}",
+ dash[i] < 0 ? 0 : dash[i],
+ (i == length-1) ? 0 : 1);
+ }
+ writePSFmt("] {0:.4g} d\n", start);
+}
+
+void PSOutputDev::updateFlatness(GfxState *state) {
+ writePSFmt("{0:d} i\n", state->getFlatness());
+}
+
+void PSOutputDev::updateLineJoin(GfxState *state) {
+ writePSFmt("{0:d} j\n", state->getLineJoin());
+}
+
+void PSOutputDev::updateLineCap(GfxState *state) {
+ writePSFmt("{0:d} J\n", state->getLineCap());
+}
+
+void PSOutputDev::updateMiterLimit(GfxState *state) {
+ writePSFmt("{0:.4g} M\n", state->getMiterLimit());
+}
+
+void PSOutputDev::updateLineWidth(GfxState *state) {
+ writePSFmt("{0:.4g} w\n", state->getLineWidth());
+}
+
+void PSOutputDev::updateFillColorSpace(GfxState *state) {
+ switch (level) {
+ case psLevel1:
+ case psLevel1Sep:
+ break;
+ case psLevel2:
+ case psLevel3:
+ if (state->getFillColorSpace()->getMode() != csPattern) {
+ dumpColorSpaceL2(state->getFillColorSpace(), gTrue, gFalse, gFalse);
+ writePS(" cs\n");
+ }
+ break;
+ case psLevel2Sep:
+ case psLevel3Sep:
+ break;
+ }
+}
+
+void PSOutputDev::updateStrokeColorSpace(GfxState *state) {
+ switch (level) {
+ case psLevel1:
+ case psLevel1Sep:
+ break;
+ case psLevel2:
+ case psLevel3:
+ if (state->getStrokeColorSpace()->getMode() != csPattern) {
+ dumpColorSpaceL2(state->getStrokeColorSpace(), gTrue, gFalse, gFalse);
+ writePS(" CS\n");
+ }
+ break;
+ case psLevel2Sep:
+ case psLevel3Sep:
+ break;
+ }
+}
+
+void PSOutputDev::updateFillColor(GfxState *state) {
+ GfxColor color;
+ GfxColor *colorPtr;
+ GfxGray gray;
+ GfxCMYK cmyk;
+ GfxSeparationColorSpace *sepCS;
+ double c, m, y, k;
+ int i;
+
+ switch (level) {
+ case psLevel1:
+ state->getFillGray(&gray);
+ writePSFmt("{0:.4g} g\n", colToDbl(gray));
+ break;
+ case psLevel1Sep:
+ state->getFillCMYK(&cmyk);
+ c = colToDbl(cmyk.c);
+ m = colToDbl(cmyk.m);
+ y = colToDbl(cmyk.y);
+ k = colToDbl(cmyk.k);
+ writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} k\n", c, m, y, k);
+ addProcessColor(c, m, y, k);
+ break;
+ case psLevel2:
+ case psLevel3:
+ if (state->getFillColorSpace()->getMode() != csPattern) {
+ colorPtr = state->getFillColor();
+ writePS("[");
+ for (i = 0; i < state->getFillColorSpace()->getNComps(); ++i) {
+ if (i > 0) {
+ writePS(" ");
+ }
+ writePSFmt("{0:.4g}", colToDbl(colorPtr->c[i]));
+ }
+ writePS("] sc\n");
+ }
+ break;
+ case psLevel2Sep:
+ case psLevel3Sep:
+ if (state->getFillColorSpace()->getMode() == csSeparation) {
+ sepCS = (GfxSeparationColorSpace *)state->getFillColorSpace();
+ color.c[0] = gfxColorComp1;
+ sepCS->getCMYK(&color, &cmyk);
+ writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} ({5:t}) ck\n",
+ colToDbl(state->getFillColor()->c[0]),
+ colToDbl(cmyk.c), colToDbl(cmyk.m),
+ colToDbl(cmyk.y), colToDbl(cmyk.k),
+ sepCS->getName());
+ addCustomColor(sepCS);
+ } else {
+ state->getFillCMYK(&cmyk);
+ c = colToDbl(cmyk.c);
+ m = colToDbl(cmyk.m);
+ y = colToDbl(cmyk.y);
+ k = colToDbl(cmyk.k);
+ writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} k\n", c, m, y, k);
+ addProcessColor(c, m, y, k);
+ }
+ break;
+ }
+ t3Cacheable = gFalse;
+}
+
+void PSOutputDev::updateStrokeColor(GfxState *state) {
+ GfxColor color;
+ GfxColor *colorPtr;
+ GfxGray gray;
+ GfxCMYK cmyk;
+ GfxSeparationColorSpace *sepCS;
+ double c, m, y, k;
+ int i;
+
+ switch (level) {
+ case psLevel1:
+ state->getStrokeGray(&gray);
+ writePSFmt("{0:.4g} G\n", colToDbl(gray));
+ break;
+ case psLevel1Sep:
+ state->getStrokeCMYK(&cmyk);
+ c = colToDbl(cmyk.c);
+ m = colToDbl(cmyk.m);
+ y = colToDbl(cmyk.y);
+ k = colToDbl(cmyk.k);
+ writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} K\n", c, m, y, k);
+ addProcessColor(c, m, y, k);
+ break;
+ case psLevel2:
+ case psLevel3:
+ if (state->getStrokeColorSpace()->getMode() != csPattern) {
+ colorPtr = state->getStrokeColor();
+ writePS("[");
+ for (i = 0; i < state->getStrokeColorSpace()->getNComps(); ++i) {
+ if (i > 0) {
+ writePS(" ");
+ }
+ writePSFmt("{0:.4g}", colToDbl(colorPtr->c[i]));
+ }
+ writePS("] SC\n");
+ }
+ break;
+ case psLevel2Sep:
+ case psLevel3Sep:
+ if (state->getStrokeColorSpace()->getMode() == csSeparation) {
+ sepCS = (GfxSeparationColorSpace *)state->getStrokeColorSpace();
+ color.c[0] = gfxColorComp1;
+ sepCS->getCMYK(&color, &cmyk);
+ writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} ({5:t}) CK\n",
+ colToDbl(state->getStrokeColor()->c[0]),
+ colToDbl(cmyk.c), colToDbl(cmyk.m),
+ colToDbl(cmyk.y), colToDbl(cmyk.k),
+ sepCS->getName());
+ addCustomColor(sepCS);
+ } else {
+ state->getStrokeCMYK(&cmyk);
+ c = colToDbl(cmyk.c);
+ m = colToDbl(cmyk.m);
+ y = colToDbl(cmyk.y);
+ k = colToDbl(cmyk.k);
+ writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} K\n", c, m, y, k);
+ addProcessColor(c, m, y, k);
+ }
+ break;
+ }
+ t3Cacheable = gFalse;
+}
+
+void PSOutputDev::addProcessColor(double c, double m, double y, double k) {
+ if (c > 0) {
+ processColors |= psProcessCyan;
+ }
+ if (m > 0) {
+ processColors |= psProcessMagenta;
+ }
+ if (y > 0) {
+ processColors |= psProcessYellow;
+ }
+ if (k > 0) {
+ processColors |= psProcessBlack;
+ }
+}
+
+void PSOutputDev::addCustomColor(GfxSeparationColorSpace *sepCS) {
+ PSOutCustomColor *cc;
+ GfxColor color;
+ GfxCMYK cmyk;
+
+ for (cc = customColors; cc; cc = cc->next) {
+ if (!cc->name->cmp(sepCS->getName())) {
+ return;
+ }
+ }
+ color.c[0] = gfxColorComp1;
+ sepCS->getCMYK(&color, &cmyk);
+ cc = new PSOutCustomColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
+ colToDbl(cmyk.y), colToDbl(cmyk.k),
+ sepCS->getName()->copy());
+ cc->next = customColors;
+ customColors = cc;
+}
+
+void PSOutputDev::updateFillOverprint(GfxState *state) {
+ if (level >= psLevel2) {
+ writePSFmt("{0:s} op\n", state->getFillOverprint() ? "true" : "false");
+ }
+}
+
+void PSOutputDev::updateStrokeOverprint(GfxState *state) {
+ if (level >= psLevel2) {
+ writePSFmt("{0:s} OP\n", state->getStrokeOverprint() ? "true" : "false");
+ }
+}
+
+void PSOutputDev::updateTransfer(GfxState *state) {
+ Function **funcs;
+ int i;
+
+ funcs = state->getTransfer();
+ if (funcs[0] && funcs[1] && funcs[2] && funcs[3]) {
+ if (level >= psLevel2) {
+ for (i = 0; i < 4; ++i) {
+ cvtFunction(funcs[i]);
+ }
+ writePS("setcolortransfer\n");
+ } else {
+ cvtFunction(funcs[3]);
+ writePS("settransfer\n");
+ }
+ } else if (funcs[0]) {
+ cvtFunction(funcs[0]);
+ writePS("settransfer\n");
+ } else {
+ writePS("{} settransfer\n");
+ }
+}
+
+void PSOutputDev::updateFont(GfxState *state) {
+ if (state->getFont()) {
+ writePSFmt("/F{0:d}_{1:d} {2:.4g} Tf\n",
+ state->getFont()->getID()->num, state->getFont()->getID()->gen,
+ fabs(state->getFontSize()) < 0.00001 ? 0.00001
+ : state->getFontSize());
+ }
+}
+
+void PSOutputDev::updateTextMat(GfxState *state) {
+ double *mat;
+
+ mat = state->getTextMat();
+ if (fabs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.00001) {
+ // avoid a singular (or close-to-singular) matrix
+ writePSFmt("[0.00001 0 0 0.00001 {0:.4g} {1:.4g}] Tm\n", mat[4], mat[5]);
+ } else {
+ writePSFmt("[{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g}] Tm\n",
+ mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
+ }
+}
+
+void PSOutputDev::updateCharSpace(GfxState *state) {
+ writePSFmt("{0:.4g} Tc\n", state->getCharSpace());
+}
+
+void PSOutputDev::updateRender(GfxState *state) {
+ int rm;
+
+ rm = state->getRender();
+ writePSFmt("{0:d} Tr\n", rm);
+ rm &= 3;
+ if (rm != 0 && rm != 3) {
+ t3Cacheable = gFalse;
+ }
+}
+
+void PSOutputDev::updateRise(GfxState *state) {
+ writePSFmt("{0:.4g} Ts\n", state->getRise());
+}
+
+void PSOutputDev::updateWordSpace(GfxState *state) {
+ writePSFmt("{0:.4g} Tw\n", state->getWordSpace());
+}
+
+void PSOutputDev::updateHorizScaling(GfxState *state) {
+ double h;
+
+ h = state->getHorizScaling();
+ if (fabs(h) < 0.01) {
+ h = 0.01;
+ }
+ writePSFmt("{0:.4g} Tz\n", h);
+}
+
+void PSOutputDev::updateTextPos(GfxState *state) {
+ writePSFmt("{0:.4g} {1:.4g} Td\n", state->getLineX(), state->getLineY());
+}
+
+void PSOutputDev::updateTextShift(GfxState *state, double shift) {
+ if (state->getFont()->getWMode()) {
+ writePSFmt("{0:.4g} TJmV\n", shift);
+ } else {
+ writePSFmt("{0:.4g} TJm\n", shift);
+ }
+}
+
+void PSOutputDev::stroke(GfxState *state) {
+ doPath(state->getPath());
+ if (t3String) {
+ // if we're construct a cacheable Type 3 glyph, we need to do
+ // everything in the fill color
+ writePS("Sf\n");
+ } else {
+ writePS("S\n");
+ }
+}
+
+void PSOutputDev::fill(GfxState *state) {
+ doPath(state->getPath());
+ writePS("f\n");
+}
+
+void PSOutputDev::eoFill(GfxState *state) {
+ doPath(state->getPath());
+ writePS("f*\n");
+}
+
+void PSOutputDev::tilingPatternFill(GfxState * /*state*/, Object *str,
+ int paintType, Dict *resDict,
+ double *mat, double *bbox,
+ int x0, int y0, int x1, int y1,
+ double xStep, double yStep) {
+ PDFRectangle box;
+ Gfx *gfx;
+
+ // define a Type 3 font
+ writePS("8 dict begin\n");
+ writePS("/FontType 3 def\n");
+ writePS("/FontMatrix [1 0 0 1 0 0] def\n");
+ writePSFmt("/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] def\n",
+ bbox[0], bbox[1], bbox[2], bbox[3]);
+ writePS("/Encoding 256 array def\n");
+ writePS(" 0 1 255 { Encoding exch /.notdef put } for\n");
+ writePS(" Encoding 120 /x put\n");
+ writePS("/BuildGlyph {\n");
+ writePS(" exch /CharProcs get exch\n");
+ writePS(" 2 copy known not { pop /.notdef } if\n");
+ writePS(" get exec\n");
+ writePS("} bind def\n");
+ writePS("/BuildChar {\n");
+ writePS(" 1 index /Encoding get exch get\n");
+ writePS(" 1 index /BuildGlyph get exec\n");
+ writePS("} bind def\n");
+ writePS("/CharProcs 1 dict def\n");
+ writePS("CharProcs begin\n");
+ box.x1 = bbox[0];
+ box.y1 = bbox[1];
+ box.x2 = bbox[2];
+ box.y2 = bbox[3];
+ gfx = new Gfx(xref, this, resDict, &box, NULL);
+ writePS("/x {\n");
+ if (paintType == 2) {
+ writePSFmt("{0:.4g} 0 {1:.4g} {2:.4g} {3:.4g} {4:.4g} setcachedevice\n",
+ xStep, bbox[0], bbox[1], bbox[2], bbox[3]);
+ } else {
+ if (x1 - 1 <= x0) {
+ writePS("1 0 setcharwidth\n");
+ } else {
+ writePSFmt("{0:.4g} 0 setcharwidth\n", xStep);
+ }
+ }
+ inType3Char = gTrue;
+ ++numTilingPatterns;
+ gfx->display(str);
+ --numTilingPatterns;
+ inType3Char = gFalse;
+ writePS("} def\n");
+ delete gfx;
+ writePS("end\n");
+ writePS("currentdict end\n");
+ writePSFmt("/xpdfTile{0:d} exch definefont pop\n", numTilingPatterns);
+
+ // draw the tiles
+ writePSFmt("/xpdfTile{0:d} findfont setfont\n", numTilingPatterns);
+ writePSFmt("gsave [{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g}] concat\n",
+ mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
+ writePSFmt("{0:d} 1 {1:d} {{ {2:.4g} exch {3:.4g} mul m {4:d} 1 {5:d} {{ pop (x) show }} for }} for\n",
+ y0, y1 - 1, x0 * xStep, yStep, x0, x1 - 1);
+ writePS("grestore\n");
+}
+
+GBool PSOutputDev::functionShadedFill(GfxState * /*state*/,
+ GfxFunctionShading *shading) {
+ double x0, y0, x1, y1;
+ double *mat;
+ int i;
+
+ if (level == psLevel2Sep || level == psLevel3Sep) {
+ if (shading->getColorSpace()->getMode() != csDeviceCMYK) {
+ return gFalse;
+ }
+ processColors |= psProcessCMYK;
+ }
+
+ shading->getDomain(&x0, &y0, &x1, &y1);
+ mat = shading->getMatrix();
+ writePSFmt("/mat [{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g}] def\n",
+ mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]);
+ writePSFmt("/n {0:d} def\n", shading->getColorSpace()->getNComps());
+ if (shading->getNFuncs() == 1) {
+ writePS("/func ");
+ cvtFunction(shading->getFunc(0));
+ writePS("def\n");
+ } else {
+ writePS("/func {\n");
+ for (i = 0; i < shading->getNFuncs(); ++i) {
+ if (i < shading->getNFuncs() - 1) {
+ writePS("2 copy\n");
+ }
+ cvtFunction(shading->getFunc(i));
+ writePS("exec\n");
+ if (i < shading->getNFuncs() - 1) {
+ writePS("3 1 roll\n");
+ }
+ }
+ writePS("} def\n");
+ }
+ writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} 0 funcSH\n", x0, y0, x1, y1);
+
+ return gTrue;
+}
+
+GBool PSOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading) {
+ double xMin, yMin, xMax, yMax;
+ double x0, y0, x1, y1, dx, dy, mul;
+ double tMin, tMax, t, t0, t1;
+ int i;
+
+ if (level == psLevel2Sep || level == psLevel3Sep) {
+ if (shading->getColorSpace()->getMode() != csDeviceCMYK) {
+ return gFalse;
+ }
+ processColors |= psProcessCMYK;
+ }
+
+ // get the clip region bbox
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+
+ // compute min and max t values, based on the four corners of the
+ // clip region bbox
+ shading->getCoords(&x0, &y0, &x1, &y1);
+ dx = x1 - x0;
+ dy = y1 - y0;
+ if (fabs(dx) < 0.01 && fabs(dy) < 0.01) {
+ return gTrue;
+ } else {
+ mul = 1 / (dx * dx + dy * dy);
+ tMin = tMax = ((xMin - x0) * dx + (yMin - y0) * dy) * mul;
+ t = ((xMin - x0) * dx + (yMax - y0) * dy) * mul;
+ if (t < tMin) {
+ tMin = t;
+ } else if (t > tMax) {
+ tMax = t;
+ }
+ t = ((xMax - x0) * dx + (yMin - y0) * dy) * mul;
+ if (t < tMin) {
+ tMin = t;
+ } else if (t > tMax) {
+ tMax = t;
+ }
+ t = ((xMax - x0) * dx + (yMax - y0) * dy) * mul;
+ if (t < tMin) {
+ tMin = t;
+ } else if (t > tMax) {
+ tMax = t;
+ }
+ if (tMin < 0 && !shading->getExtend0()) {
+ tMin = 0;
+ }
+ if (tMax > 1 && !shading->getExtend1()) {
+ tMax = 1;
+ }
+ }
+
+ // get the function domain
+ t0 = shading->getDomain0();
+ t1 = shading->getDomain1();
+
+ // generate the PS code
+ writePSFmt("/t0 {0:.4g} def\n", t0);
+ writePSFmt("/t1 {0:.4g} def\n", t1);
+ writePSFmt("/dt {0:.4g} def\n", t1 - t0);
+ writePSFmt("/x0 {0:.4g} def\n", x0);
+ writePSFmt("/y0 {0:.4g} def\n", y0);
+ writePSFmt("/dx {0:.4g} def\n", x1 - x0);
+ writePSFmt("/x1 {0:.4g} def\n", x1);
+ writePSFmt("/y1 {0:.4g} def\n", y1);
+ writePSFmt("/dy {0:.4g} def\n", y1 - y0);
+ writePSFmt("/xMin {0:.4g} def\n", xMin);
+ writePSFmt("/yMin {0:.4g} def\n", yMin);
+ writePSFmt("/xMax {0:.4g} def\n", xMax);
+ writePSFmt("/yMax {0:.4g} def\n", yMax);
+ writePSFmt("/n {0:d} def\n", shading->getColorSpace()->getNComps());
+ if (shading->getNFuncs() == 1) {
+ writePS("/func ");
+ cvtFunction(shading->getFunc(0));
+ writePS("def\n");
+ } else {
+ writePS("/func {\n");
+ for (i = 0; i < shading->getNFuncs(); ++i) {
+ if (i < shading->getNFuncs() - 1) {
+ writePS("dup\n");
+ }
+ cvtFunction(shading->getFunc(i));
+ writePS("exec\n");
+ if (i < shading->getNFuncs() - 1) {
+ writePS("exch\n");
+ }
+ }
+ writePS("} def\n");
+ }
+ writePSFmt("{0:.4g} {1:.4g} 0 axialSH\n", tMin, tMax);
+
+ return gTrue;
+}
+
+GBool PSOutputDev::radialShadedFill(GfxState *state,
+ GfxRadialShading *shading) {
+ double xMin, yMin, xMax, yMax;
+ double x0, y0, r0, x1, y1, r1, t0, t1;
+ double xa, ya, ra;
+ double sz, xz, yz, sMin, sMax, sa, ta;
+ double theta, alpha, a1, a2;
+ GBool enclosed;
+ int i;
+
+ if (level == psLevel2Sep || level == psLevel3Sep) {
+ if (shading->getColorSpace()->getMode() != csDeviceCMYK) {
+ return gFalse;
+ }
+ processColors |= psProcessCMYK;
+ }
+
+ // get the shading info
+ shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1);
+ t0 = shading->getDomain0();
+ t1 = shading->getDomain1();
+
+ // Compute the point at which r(s) = 0; check for the enclosed
+ // circles case; and compute the angles for the tangent lines.
+ if (r0 == r1) {
+ enclosed = x0 == x1 && y0 == y1;
+ theta = 0;
+ sz = 0; // make gcc happy
+ } else {
+ sz = -r0 / (r1 - r0);
+ xz = x0 + sz * (x1 - x0);
+ yz = y0 + sz * (y1 - y0);
+ enclosed = (xz - x0) * (xz - x0) + (yz - y0) * (yz - y0) <= r0 * r0;
+ theta = asin(r0 / sqrt((x0 - xz) * (x0 - xz) + (y0 - yz) * (y0 - yz)));
+ if (r0 > r1) {
+ theta = -theta;
+ }
+ }
+ if (enclosed) {
+ a1 = 0;
+ a2 = 360;
+ } else {
+ alpha = atan2(y1 - y0, x1 - x0);
+ a1 = (180 / M_PI) * (alpha + theta) + 90;
+ a2 = (180 / M_PI) * (alpha - theta) - 90;
+ while (a2 < a1) {
+ a2 += 360;
+ }
+ }
+
+ // compute the (possibly extended) s range
+ state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
+ if (enclosed) {
+ sMin = 0;
+ sMax = 1;
+ } else {
+ sMin = 1;
+ sMax = 0;
+ // solve for x(s) + r(s) = xMin
+ if ((x1 + r1) - (x0 + r0) != 0) {
+ sa = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0));
+ if (sa < sMin) {
+ sMin = sa;
+ } else if (sa > sMax) {
+ sMax = sa;
+ }
+ }
+ // solve for x(s) - r(s) = xMax
+ if ((x1 - r1) - (x0 - r0) != 0) {
+ sa = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0));
+ if (sa < sMin) {
+ sMin = sa;
+ } else if (sa > sMax) {
+ sMax = sa;
+ }
+ }
+ // solve for y(s) + r(s) = yMin
+ if ((y1 + r1) - (y0 + r0) != 0) {
+ sa = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0));
+ if (sa < sMin) {
+ sMin = sa;
+ } else if (sa > sMax) {
+ sMax = sa;
+ }
+ }
+ // solve for y(s) - r(s) = yMax
+ if ((y1 - r1) - (y0 - r0) != 0) {
+ sa = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0));
+ if (sa < sMin) {
+ sMin = sa;
+ } else if (sa > sMax) {
+ sMax = sa;
+ }
+ }
+ // check against sz
+ if (r0 < r1) {
+ if (sMin < sz) {
+ sMin = sz;
+ }
+ } else if (r0 > r1) {
+ if (sMax > sz) {
+ sMax = sz;
+ }
+ }
+ // check the 'extend' flags
+ if (!shading->getExtend0() && sMin < 0) {
+ sMin = 0;
+ }
+ if (!shading->getExtend1() && sMax > 1) {
+ sMax = 1;
+ }
+ }
+
+ // generate the PS code
+ writePSFmt("/x0 {0:.4g} def\n", x0);
+ writePSFmt("/x1 {0:.4g} def\n", x1);
+ writePSFmt("/dx {0:.4g} def\n", x1 - x0);
+ writePSFmt("/y0 {0:.4g} def\n", y0);
+ writePSFmt("/y1 {0:.4g} def\n", y1);
+ writePSFmt("/dy {0:.4g} def\n", y1 - y0);
+ writePSFmt("/r0 {0:.4g} def\n", r0);
+ writePSFmt("/r1 {0:.4g} def\n", r1);
+ writePSFmt("/dr {0:.4g} def\n", r1 - r0);
+ writePSFmt("/t0 {0:.4g} def\n", t0);
+ writePSFmt("/t1 {0:.4g} def\n", t1);
+ writePSFmt("/dt {0:.4g} def\n", t1 - t0);
+ writePSFmt("/n {0:d} def\n", shading->getColorSpace()->getNComps());
+ writePSFmt("/encl {0:s} def\n", enclosed ? "true" : "false");
+ writePSFmt("/a1 {0:.4g} def\n", a1);
+ writePSFmt("/a2 {0:.4g} def\n", a2);
+ if (shading->getNFuncs() == 1) {
+ writePS("/func ");
+ cvtFunction(shading->getFunc(0));
+ writePS("def\n");
+ } else {
+ writePS("/func {\n");
+ for (i = 0; i < shading->getNFuncs(); ++i) {
+ if (i < shading->getNFuncs() - 1) {
+ writePS("dup\n");
+ }
+ cvtFunction(shading->getFunc(i));
+ writePS("exec\n");
+ if (i < shading->getNFuncs() - 1) {
+ writePS("exch\n");
+ }
+ }
+ writePS("} def\n");
+ }
+ writePSFmt("{0:.4g} {1:.4g} 0 radialSH\n", sMin, sMax);
+
+ // extend the 'enclosed' case
+ if (enclosed) {
+ // extend the smaller circle
+ if ((shading->getExtend0() && r0 <= r1) ||
+ (shading->getExtend1() && r1 < r0)) {
+ if (r0 <= r1) {
+ ta = t0;
+ ra = r0;
+ xa = x0;
+ ya = y0;
+ } else {
+ ta = t1;
+ ra = r1;
+ xa = x1;
+ ya = y1;
+ }
+ if (level == psLevel2Sep || level == psLevel3Sep) {
+ writePSFmt("{0:.4g} radialCol aload pop k\n", ta);
+ } else {
+ writePSFmt("{0:.4g} radialCol sc\n", ta);
+ }
+ writePSFmt("{0:.4g} {1:.4g} {2:.4g} 0 360 arc h f*\n", xa, ya, ra);
+ }
+
+ // extend the larger circle
+ if ((shading->getExtend0() && r0 > r1) ||
+ (shading->getExtend1() && r1 >= r0)) {
+ if (r0 > r1) {
+ ta = t0;
+ ra = r0;
+ xa = x0;
+ ya = y0;
+ } else {
+ ta = t1;
+ ra = r1;
+ xa = x1;
+ ya = y1;
+ }
+ if (level == psLevel2Sep || level == psLevel3Sep) {
+ writePSFmt("{0:.4g} radialCol aload pop k\n", ta);
+ } else {
+ writePSFmt("{0:.4g} radialCol sc\n", ta);
+ }
+ writePSFmt("{0:.4g} {1:.4g} {2:.4g} 0 360 arc h\n", xa, ya, ra);
+ writePSFmt("{0:.4g} {1:.4g} m {2:.4g} {3:.4g} l {4:.4g} {5:.4g} l {6:.4g} {7:.4g} l h f*\n",
+ xMin, yMin, xMin, yMax, xMax, yMax, xMax, yMin);
+ }
+ }
+
+ return gTrue;
+}
+
+void PSOutputDev::clip(GfxState *state) {
+ doPath(state->getPath());
+ writePS("W\n");
+}
+
+void PSOutputDev::eoClip(GfxState *state) {
+ doPath(state->getPath());
+ writePS("W*\n");
+}
+
+void PSOutputDev::clipToStrokePath(GfxState *state) {
+ doPath(state->getPath());
+ writePS("Ws\n");
+}
+
+void PSOutputDev::doPath(GfxPath *path) {
+ GfxSubpath *subpath;
+ double x0, y0, x1, y1, x2, y2, x3, y3, x4, y4;
+ int n, m, i, j;
+
+ n = path->getNumSubpaths();
+
+ if (n == 1 && path->getSubpath(0)->getNumPoints() == 5) {
+ subpath = path->getSubpath(0);
+ x0 = subpath->getX(0);
+ y0 = subpath->getY(0);
+ x4 = subpath->getX(4);
+ y4 = subpath->getY(4);
+ if (x4 == x0 && y4 == y0) {
+ x1 = subpath->getX(1);
+ y1 = subpath->getY(1);
+ x2 = subpath->getX(2);
+ y2 = subpath->getY(2);
+ x3 = subpath->getX(3);
+ y3 = subpath->getY(3);
+ if (x0 == x1 && x2 == x3 && y0 == y3 && y1 == y2) {
+ writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} re\n",
+ x0 < x2 ? x0 : x2, y0 < y1 ? y0 : y1,
+ fabs(x2 - x0), fabs(y1 - y0));
+ return;
+ } else if (x0 == x3 && x1 == x2 && y0 == y1 && y2 == y3) {
+ writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} re\n",
+ x0 < x1 ? x0 : x1, y0 < y2 ? y0 : y2,
+ fabs(x1 - x0), fabs(y2 - y0));
+ return;
+ }
+ }
+ }
+
+ for (i = 0; i < n; ++i) {
+ subpath = path->getSubpath(i);
+ m = subpath->getNumPoints();
+ writePSFmt("{0:.4g} {1:.4g} m\n", subpath->getX(0), subpath->getY(0));
+ j = 1;
+ while (j < m) {
+ if (subpath->getCurve(j)) {
+ writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g} c\n",
+ subpath->getX(j), subpath->getY(j),
+ subpath->getX(j+1), subpath->getY(j+1),
+ subpath->getX(j+2), subpath->getY(j+2));
+ j += 3;
+ } else {
+ writePSFmt("{0:.4g} {1:.4g} l\n", subpath->getX(j), subpath->getY(j));
+ ++j;
+ }
+ }
+ if (subpath->isClosed()) {
+ writePS("h\n");
+ }
+ }
+}
+
+void PSOutputDev::drawString(GfxState *state, GString *s) {
+ GfxFont *font;
+ int wMode;
+ Gushort *codeToGID;
+ GString *s2;
+ double dx, dy, dx2, dy2, originX, originY;
+ char *p;
+ UnicodeMap *uMap;
+ CharCode code;
+ Unicode u[8];
+ char buf[8];
+ int len, nChars, uLen, n, m, i, j;
+
+ // check for invisible text -- this is used by Acrobat Capture
+ if (state->getRender() == 3) {
+ return;
+ }
+
+ // ignore empty strings
+ if (s->getLength() == 0) {
+ return;
+ }
+
+ // get the font
+ if (!(font = state->getFont())) {
+ return;
+ }
+ wMode = font->getWMode();
+
+ // check for a subtitute 16-bit font
+ uMap = NULL;
+ codeToGID = NULL;
+ if (font->isCIDFont()) {
+ for (i = 0; i < font16EncLen; ++i) {
+ if (font->getID()->num == font16Enc[i].fontID.num &&
+ font->getID()->gen == font16Enc[i].fontID.gen) {
+ uMap = globalParams->getUnicodeMap(font16Enc[i].enc);
+ break;
+ }
+ }
+
+ // check for a code-to-GID map
+ } else {
+ for (i = 0; i < font8InfoLen; ++i) {
+ if (font->getID()->num == font8Info[i].fontID.num &&
+ font->getID()->gen == font8Info[i].fontID.gen) {
+ codeToGID = font8Info[i].codeToGID;
+ break;
+ }
+ }
+ }
+
+ // compute width of chars in string, ignoring char spacing and word
+ // spacing -- the Tj operator will adjust for the metrics of the
+ // font that's actually used
+ dx = dy = 0;
+ nChars = 0;
+ p = s->getCString();
+ len = s->getLength();
+ s2 = new GString();
+ while (len > 0) {
+ n = font->getNextChar(p, len, &code,
+ u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
+ &dx2, &dy2, &originX, &originY);
+ if (font->isCIDFont()) {
+ if (uMap) {
+ for (i = 0; i < uLen; ++i) {
+ m = uMap->mapUnicode(u[i], buf, (int)sizeof(buf));
+ for (j = 0; j < m; ++j) {
+ s2->append(buf[j]);
+ }
+ }
+ //~ this really needs to get the number of chars in the target
+ //~ encoding - which may be more than the number of Unicode
+ //~ chars
+ nChars += uLen;
+ } else {
+ s2->append((char)((code >> 8) & 0xff));
+ s2->append((char)(code & 0xff));
+ ++nChars;
+ }
+ } else {
+ if (!codeToGID || codeToGID[code]) {
+ s2->append((char)code);
+ }
+ }
+ dx += dx2;
+ dy += dy2;
+ p += n;
+ len -= n;
+ }
+ dx *= state->getFontSize() * state->getHorizScaling();
+ dy *= state->getFontSize();
+ if (uMap) {
+ uMap->decRefCnt();
+ }
+
+ if (s2->getLength() > 0) {
+ writePSString(s2);
+ if (font->isCIDFont()) {
+ if (wMode) {
+ writePSFmt(" {0:d} {1:.4g} Tj16V\n", nChars, dy);
+ } else {
+ writePSFmt(" {0:d} {1:.4g} Tj16\n", nChars, dx);
+ }
+ } else {
+ writePSFmt(" {0:.4g} Tj\n", dx);
+ }
+ }
+ delete s2;
+
+ if (state->getRender() & 4) {
+ haveTextClip = gTrue;
+ }
+}
+
+void PSOutputDev::endTextObject(GfxState * /*state*/) {
+ if (haveTextClip) {
+ writePS("Tclip\n");
+ haveTextClip = gFalse;
+ }
+}
+
+void PSOutputDev::drawImageMask(GfxState * /*state*/, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool inlineImg) {
+ int len;
+
+ len = height * ((width + 7) / 8);
+ switch (level) {
+ case psLevel1:
+ case psLevel1Sep:
+ doImageL1(ref, NULL, invert, inlineImg, str, width, height, len);
+ break;
+ case psLevel2:
+ case psLevel2Sep:
+ doImageL2(ref, NULL, invert, inlineImg, str, width, height, len,
+ NULL, NULL, 0, 0, gFalse);
+ break;
+ case psLevel3:
+ case psLevel3Sep:
+ doImageL3(ref, NULL, invert, inlineImg, str, width, height, len,
+ NULL, NULL, 0, 0, gFalse);
+ break;
+ }
+}
+
+void PSOutputDev::drawImage(GfxState * /*state*/, Object *ref, Stream *str,
+ int width, int height, GfxImageColorMap *colorMap,
+ int *maskColors, GBool inlineImg) {
+ int len;
+
+ len = height * ((width * colorMap->getNumPixelComps() *
+ colorMap->getBits() + 7) / 8);
+ switch (level) {
+ case psLevel1:
+ doImageL1(ref, colorMap, gFalse, inlineImg, str, width, height, len);
+ break;
+ case psLevel1Sep:
+ //~ handle indexed, separation, ... color spaces
+ doImageL1Sep(colorMap, gFalse, inlineImg, str, width, height, len);
+ break;
+ case psLevel2:
+ case psLevel2Sep:
+ doImageL2(ref, colorMap, gFalse, inlineImg, str,
+ width, height, len, maskColors, NULL, 0, 0, gFalse);
+ break;
+ case psLevel3:
+ case psLevel3Sep:
+ doImageL3(ref, colorMap, gFalse, inlineImg, str,
+ width, height, len, maskColors, NULL, 0, 0, gFalse);
+ break;
+ }
+ t3Cacheable = gFalse;
+}
+
+void PSOutputDev::drawMaskedImage(GfxState * /*state*/, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ Stream *maskStr,
+ int maskWidth, int maskHeight,
+ GBool maskInvert) {
+ int len;
+
+ len = height * ((width * colorMap->getNumPixelComps() *
+ colorMap->getBits() + 7) / 8);
+ switch (level) {
+ case psLevel1:
+ doImageL1(ref, colorMap, gFalse, gFalse, str, width, height, len);
+ break;
+ case psLevel1Sep:
+ //~ handle indexed, separation, ... color spaces
+ doImageL1Sep(colorMap, gFalse, gFalse, str, width, height, len);
+ break;
+ case psLevel2:
+ case psLevel2Sep:
+ doImageL2(ref, colorMap, gFalse, gFalse, str, width, height, len,
+ NULL, maskStr, maskWidth, maskHeight, maskInvert);
+ break;
+ case psLevel3:
+ case psLevel3Sep:
+ doImageL3(ref, colorMap, gFalse, gFalse, str, width, height, len,
+ NULL, maskStr, maskWidth, maskHeight, maskInvert);
+ break;
+ }
+ t3Cacheable = gFalse;
+}
+
+void PSOutputDev::doImageL1(Object *ref, GfxImageColorMap *colorMap,
+ GBool invert, GBool inlineImg,
+ Stream *str, int width, int height, int len) {
+ ImageStream *imgStr;
+ Guchar pixBuf[gfxColorMaxComps];
+ GfxGray gray;
+ int col, x, y, c, i;
+
+ if ((inType3Char || preload) && !colorMap) {
+ if (inlineImg) {
+ // create an array
+ str = new FixedLengthEncoder(str, len);
+ str = new ASCIIHexEncoder(str);
+ str->reset();
+ col = 0;
+ writePS("[<");
+ do {
+ do {
+ c = str->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == '>' || c == EOF) {
+ break;
+ }
+ writePSChar(c);
+ ++col;
+ // each line is: "<...data...><eol>"
+ // so max data length = 255 - 4 = 251
+ // but make it 240 just to be safe
+ // chunks are 2 bytes each, so we need to stop on an even col number
+ if (col == 240) {
+ writePS(">\n<");
+ col = 0;
+ }
+ } while (c != '>' && c != EOF);
+ writePS(">]\n");
+ writePS("0\n");
+ str->close();
+ delete str;
+ } else {
+ // set up to use the array already created by setupImages()
+ writePSFmt("ImData_{0:d}_{1:d} 0\n", ref->getRefNum(), ref->getRefGen());
+ }
+ }
+
+ // image/imagemask command
+ if ((inType3Char || preload) && !colorMap) {
+ writePSFmt("{0:d} {1:d} {2:s} [{3:d} 0 0 {4:d} 0 {5:d}] pdfImM1a\n",
+ width, height, invert ? "true" : "false",
+ width, -height, height);
+ } else if (colorMap) {
+ writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1\n",
+ width, height,
+ width, -height, height);
+ } else {
+ writePSFmt("{0:d} {1:d} {2:s} [{3:d} 0 0 {4:d} 0 {5:d}] pdfImM1\n",
+ width, height, invert ? "true" : "false",
+ width, -height, height);
+ }
+
+ // image data
+ if (!((inType3Char || preload) && !colorMap)) {
+
+ if (colorMap) {
+
+ // set up to process the data stream
+ imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
+ colorMap->getBits());
+ imgStr->reset();
+
+ // process the data stream
+ i = 0;
+ for (y = 0; y < height; ++y) {
+
+ // write the line
+ for (x = 0; x < width; ++x) {
+ imgStr->getPixel(pixBuf);
+ colorMap->getGray(pixBuf, &gray);
+ writePSFmt("{0:02x}", colToByte(gray));
+ if (++i == 32) {
+ writePSChar('\n');
+ i = 0;
+ }
+ }
+ }
+ if (i != 0) {
+ writePSChar('\n');
+ }
+ str->close();
+ delete imgStr;
+
+ // imagemask
+ } else {
+ str->reset();
+ i = 0;
+ for (y = 0; y < height; ++y) {
+ for (x = 0; x < width; x += 8) {
+ writePSFmt("{0:02x}", str->getChar() & 0xff);
+ if (++i == 32) {
+ writePSChar('\n');
+ i = 0;
+ }
+ }
+ }
+ if (i != 0) {
+ writePSChar('\n');
+ }
+ str->close();
+ }
+ }
+}
+
+void PSOutputDev::doImageL1Sep(GfxImageColorMap *colorMap,
+ GBool /*invert*/, GBool /*inlineImg*/,
+ Stream *str, int width, int height, int /*len*/) {
+ ImageStream *imgStr;
+ Guchar *lineBuf;
+ Guchar pixBuf[gfxColorMaxComps];
+ GfxCMYK cmyk;
+ int x, y, i, comp;
+
+ // width, height, matrix, bits per component
+ writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1Sep\n",
+ width, height,
+ width, -height, height);
+
+ // allocate a line buffer
+ lineBuf = (Guchar *)gmalloc(4 * width);
+
+ // set up to process the data stream
+ imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(),
+ colorMap->getBits());
+ imgStr->reset();
+
+ // process the data stream
+ i = 0;
+ for (y = 0; y < height; ++y) {
+
+ // read the line
+ for (x = 0; x < width; ++x) {
+ imgStr->getPixel(pixBuf);
+ colorMap->getCMYK(pixBuf, &cmyk);
+ lineBuf[4*x+0] = colToByte(cmyk.c);
+ lineBuf[4*x+1] = colToByte(cmyk.m);
+ lineBuf[4*x+2] = colToByte(cmyk.y);
+ lineBuf[4*x+3] = colToByte(cmyk.k);
+ addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
+ colToDbl(cmyk.y), colToDbl(cmyk.k));
+ }
+
+ // write one line of each color component
+ for (comp = 0; comp < 4; ++comp) {
+ for (x = 0; x < width; ++x) {
+ writePSFmt("{0:02x}", lineBuf[4*x + comp]);
+ if (++i == 32) {
+ writePSChar('\n');
+ i = 0;
+ }
+ }
+ }
+ }
+
+ if (i != 0) {
+ writePSChar('\n');
+ }
+
+ str->close();
+ delete imgStr;
+ gfree(lineBuf);
+}
+
+void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
+ GBool invert, GBool inlineImg,
+ Stream *str, int width, int height, int len,
+ int *maskColors, Stream *maskStr,
+ int maskWidth, int maskHeight, GBool maskInvert) {
+ Stream *str2;
+ ImageStream *imgStr;
+ Guchar *line;
+ PSOutImgClipRect *rects0, *rects1, *rectsTmp, *rectsOut;
+ int rects0Len, rects1Len, rectsSize, rectsOutLen, rectsOutSize;
+ GBool emitRect, addRect, extendRect;
+ GString *s;
+ int n, numComps;
+ GBool useRLE, useASCII, useASCIIHex, useCompressed;
+ GfxSeparationColorSpace *sepCS;
+ GfxColor color;
+ GfxCMYK cmyk;
+ int c;
+ int col, i, j, x0, x1, y, maskXor;
+
+ // color key masking
+ if (maskColors && colorMap && !inlineImg) {
+ // can't read the stream twice for inline images -- but masking
+ // isn't allowed with inline images anyway
+ numComps = colorMap->getNumPixelComps();
+ imgStr = new ImageStream(str, width, numComps, colorMap->getBits());
+ imgStr->reset();
+ rects0Len = rects1Len = rectsOutLen = 0;
+ rectsSize = rectsOutSize = 64;
+ rects0 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
+ rects1 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
+ rectsOut = (PSOutImgClipRect *)gmallocn(rectsOutSize,
+ sizeof(PSOutImgClipRect));
+ for (y = 0; y < height; ++y) {
+ if (!(line = imgStr->getLine())) {
+ break;
+ }
+ i = 0;
+ rects1Len = 0;
+ for (x0 = 0; x0 < width; ++x0) {
+ for (j = 0; j < numComps; ++j) {
+ if (line[x0*numComps+j] < maskColors[2*j] ||
+ line[x0*numComps+j] > maskColors[2*j+1]) {
+ break;
+ }
+ }
+ if (j < numComps) {
+ break;
+ }
+ }
+ for (x1 = x0; x1 < width; ++x1) {
+ for (j = 0; j < numComps; ++j) {
+ if (line[x1*numComps+j] < maskColors[2*j] ||
+ line[x1*numComps+j] > maskColors[2*j+1]) {
+ break;
+ }
+ }
+ if (j == numComps) {
+ break;
+ }
+ }
+ while (x0 < width || i < rects0Len) {
+ emitRect = addRect = extendRect = gFalse;
+ if (x0 >= width) {
+ emitRect = gTrue;
+ } else if (i >= rects0Len) {
+ addRect = gTrue;
+ } else if (rects0[i].x0 < x0) {
+ emitRect = gTrue;
+ } else if (x0 < rects0[i].x0) {
+ addRect = gTrue;
+ } else if (rects0[i].x1 == x1) {
+ extendRect = gTrue;
+ } else {
+ emitRect = addRect = gTrue;
+ }
+ if (emitRect) {
+ if (rectsOutLen == rectsOutSize) {
+ rectsOutSize *= 2;
+ rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize,
+ sizeof(PSOutImgClipRect));
+ }
+ rectsOut[rectsOutLen].x0 = rects0[i].x0;
+ rectsOut[rectsOutLen].x1 = rects0[i].x1;
+ rectsOut[rectsOutLen].y0 = height - y - 1;
+ rectsOut[rectsOutLen].y1 = height - rects0[i].y0 - 1;
+ ++rectsOutLen;
+ ++i;
+ }
+ if (addRect || extendRect) {
+ if (rects1Len == rectsSize) {
+ rectsSize *= 2;
+ rects0 = (PSOutImgClipRect *)greallocn(rects0, rectsSize,
+ sizeof(PSOutImgClipRect));
+ rects1 = (PSOutImgClipRect *)greallocn(rects1, rectsSize,
+ sizeof(PSOutImgClipRect));
+ }
+ rects1[rects1Len].x0 = x0;
+ rects1[rects1Len].x1 = x1;
+ if (addRect) {
+ rects1[rects1Len].y0 = y;
+ }
+ if (extendRect) {
+ rects1[rects1Len].y0 = rects0[i].y0;
+ ++i;
+ }
+ ++rects1Len;
+ for (x0 = x1; x0 < width; ++x0) {
+ for (j = 0; j < numComps; ++j) {
+ if (line[x0*numComps+j] < maskColors[2*j] ||
+ line[x0*numComps+j] > maskColors[2*j+1]) {
+ break;
+ }
+ }
+ if (j < numComps) {
+ break;
+ }
+ }
+ for (x1 = x0; x1 < width; ++x1) {
+ for (j = 0; j < numComps; ++j) {
+ if (line[x1*numComps+j] < maskColors[2*j] ||
+ line[x1*numComps+j] > maskColors[2*j+1]) {
+ break;
+ }
+ }
+ if (j == numComps) {
+ break;
+ }
+ }
+ }
+ }
+ rectsTmp = rects0;
+ rects0 = rects1;
+ rects1 = rectsTmp;
+ i = rects0Len;
+ rects0Len = rects1Len;
+ rects1Len = i;
+ }
+ for (i = 0; i < rects0Len; ++i) {
+ if (rectsOutLen == rectsOutSize) {
+ rectsOutSize *= 2;
+ rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize,
+ sizeof(PSOutImgClipRect));
+ }
+ rectsOut[rectsOutLen].x0 = rects0[i].x0;
+ rectsOut[rectsOutLen].x1 = rects0[i].x1;
+ rectsOut[rectsOutLen].y0 = height - y - 1;
+ rectsOut[rectsOutLen].y1 = height - rects0[i].y0 - 1;
+ ++rectsOutLen;
+ }
+ writePSFmt("{0:d} array 0\n", rectsOutLen * 4);
+ for (i = 0; i < rectsOutLen; ++i) {
+ writePSFmt("[{0:d} {1:d} {2:d} {3:d}] pr\n",
+ rectsOut[i].x0, rectsOut[i].y0,
+ rectsOut[i].x1 - rectsOut[i].x0,
+ rectsOut[i].y1 - rectsOut[i].y0);
+ }
+ writePSFmt("pop {0:d} {1:d} pdfImClip\n", width, height);
+ gfree(rectsOut);
+ gfree(rects0);
+ gfree(rects1);
+ delete imgStr;
+ str->close();
+
+ // explicit masking
+ } else if (maskStr) {
+ imgStr = new ImageStream(maskStr, maskWidth, 1, 1);
+ imgStr->reset();
+ rects0Len = rects1Len = rectsOutLen = 0;
+ rectsSize = rectsOutSize = 64;
+ rects0 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
+ rects1 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect));
+ rectsOut = (PSOutImgClipRect *)gmallocn(rectsOutSize,
+ sizeof(PSOutImgClipRect));
+ maskXor = maskInvert ? 1 : 0;
+ for (y = 0; y < maskHeight; ++y) {
+ if (!(line = imgStr->getLine())) {
+ break;
+ }
+ i = 0;
+ rects1Len = 0;
+ for (x0 = 0; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ;
+ for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ;
+ while (x0 < maskWidth || i < rects0Len) {
+ emitRect = addRect = extendRect = gFalse;
+ if (x0 >= maskWidth) {
+ emitRect = gTrue;
+ } else if (i >= rects0Len) {
+ addRect = gTrue;
+ } else if (rects0[i].x0 < x0) {
+ emitRect = gTrue;
+ } else if (x0 < rects0[i].x0) {
+ addRect = gTrue;
+ } else if (rects0[i].x1 == x1) {
+ extendRect = gTrue;
+ } else {
+ emitRect = addRect = gTrue;
+ }
+ if (emitRect) {
+ if (rectsOutLen == rectsOutSize) {
+ rectsOutSize *= 2;
+ rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize,
+ sizeof(PSOutImgClipRect));
+ }
+ rectsOut[rectsOutLen].x0 = rects0[i].x0;
+ rectsOut[rectsOutLen].x1 = rects0[i].x1;
+ rectsOut[rectsOutLen].y0 = maskHeight - y - 1;
+ rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1;
+ ++rectsOutLen;
+ ++i;
+ }
+ if (addRect || extendRect) {
+ if (rects1Len == rectsSize) {
+ rectsSize *= 2;
+ rects0 = (PSOutImgClipRect *)greallocn(rects0, rectsSize,
+ sizeof(PSOutImgClipRect));
+ rects1 = (PSOutImgClipRect *)greallocn(rects1, rectsSize,
+ sizeof(PSOutImgClipRect));
+ }
+ rects1[rects1Len].x0 = x0;
+ rects1[rects1Len].x1 = x1;
+ if (addRect) {
+ rects1[rects1Len].y0 = y;
+ }
+ if (extendRect) {
+ rects1[rects1Len].y0 = rects0[i].y0;
+ ++i;
+ }
+ ++rects1Len;
+ for (x0 = x1; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ;
+ for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ;
+ }
+ }
+ rectsTmp = rects0;
+ rects0 = rects1;
+ rects1 = rectsTmp;
+ i = rects0Len;
+ rects0Len = rects1Len;
+ rects1Len = i;
+ }
+ for (i = 0; i < rects0Len; ++i) {
+ if (rectsOutLen == rectsOutSize) {
+ rectsOutSize *= 2;
+ rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize,
+ sizeof(PSOutImgClipRect));
+ }
+ rectsOut[rectsOutLen].x0 = rects0[i].x0;
+ rectsOut[rectsOutLen].x1 = rects0[i].x1;
+ rectsOut[rectsOutLen].y0 = maskHeight - y - 1;
+ rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1;
+ ++rectsOutLen;
+ }
+ writePSFmt("{0:d} array 0\n", rectsOutLen * 4);
+ for (i = 0; i < rectsOutLen; ++i) {
+ writePSFmt("[{0:d} {1:d} {2:d} {3:d}] pr\n",
+ rectsOut[i].x0, rectsOut[i].y0,
+ rectsOut[i].x1 - rectsOut[i].x0,
+ rectsOut[i].y1 - rectsOut[i].y0);
+ }
+ writePSFmt("pop {0:d} {1:d} pdfImClip\n", maskWidth, maskHeight);
+ gfree(rectsOut);
+ gfree(rects0);
+ gfree(rects1);
+ delete imgStr;
+ maskStr->close();
+ }
+
+ // color space
+ if (colorMap) {
+ dumpColorSpaceL2(colorMap->getColorSpace(), gFalse, gTrue, gFalse);
+ writePS(" setcolorspace\n");
+ }
+
+ useASCIIHex = globalParams->getPSASCIIHex();
+
+ // set up the image data
+ if (mode == psModeForm || inType3Char || preload) {
+ if (inlineImg) {
+ // create an array
+ str2 = new FixedLengthEncoder(str, len);
+ str2 = new RunLengthEncoder(str2);
+ if (useASCIIHex) {
+ str2 = new ASCIIHexEncoder(str2);
+ } else {
+ str2 = new ASCII85Encoder(str2);
+ }
+ str2->reset();
+ col = 0;
+ writePS((char *)(useASCIIHex ? "[<" : "[<~"));
+ do {
+ do {
+ c = str2->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
+ break;
+ }
+ if (c == 'z') {
+ writePSChar(c);
+ ++col;
+ } else {
+ writePSChar(c);
+ ++col;
+ for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) {
+ do {
+ c = str2->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
+ break;
+ }
+ writePSChar(c);
+ ++col;
+ }
+ }
+ // each line is: "<~...data...~><eol>"
+ // so max data length = 255 - 6 = 249
+ // chunks are 1 or 5 bytes each, so we have to stop at 245
+ // but make it 240 just to be safe
+ if (col > 240) {
+ writePS((char *)(useASCIIHex ? ">\n<" : "~>\n<~"));
+ col = 0;
+ }
+ } while (c != (useASCIIHex ? '>' : '~') && c != EOF);
+ writePS((char *)(useASCIIHex ? ">\n" : "~>\n"));
+ // add an extra entry because the RunLengthDecode filter may
+ // read past the end
+ writePS("<>]\n");
+ writePS("0\n");
+ str2->close();
+ delete str2;
+ } else {
+ // set up to use the array already created by setupImages()
+ writePSFmt("ImData_{0:d}_{1:d} 0\n", ref->getRefNum(), ref->getRefGen());
+ }
+ }
+
+ // image dictionary
+ writePS("<<\n /ImageType 1\n");
+
+ // width, height, matrix, bits per component
+ writePSFmt(" /Width {0:d}\n", width);
+ writePSFmt(" /Height {0:d}\n", height);
+ writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n",
+ width, -height, height);
+ if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
+ writePS(" /BitsPerComponent 8\n");
+ } else {
+ writePSFmt(" /BitsPerComponent {0:d}\n",
+ colorMap ? colorMap->getBits() : 1);
+ }
+
+ // decode
+ if (colorMap) {
+ writePS(" /Decode [");
+ if ((level == psLevel2Sep || level == psLevel3Sep) &&
+ colorMap->getColorSpace()->getMode() == csSeparation) {
+ // this matches up with the code in the pdfImSep operator
+ n = (1 << colorMap->getBits()) - 1;
+ writePSFmt("{0:.4g} {1:.4g}", colorMap->getDecodeLow(0) * n,
+ colorMap->getDecodeHigh(0) * n);
+ } else if (colorMap->getColorSpace()->getMode() == csDeviceN) {
+ numComps = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
+ getAlt()->getNComps();
+ for (i = 0; i < numComps; ++i) {
+ if (i > 0) {
+ writePS(" ");
+ }
+ writePS("0 1");
+ }
+ } else {
+ numComps = colorMap->getNumPixelComps();
+ for (i = 0; i < numComps; ++i) {
+ if (i > 0) {
+ writePS(" ");
+ }
+ writePSFmt("{0:.4g} {1:.4g}",
+ colorMap->getDecodeLow(i), colorMap->getDecodeHigh(i));
+ }
+ }
+ writePS("]\n");
+ } else {
+ writePSFmt(" /Decode [{0:d} {1:d}]\n", invert ? 1 : 0, invert ? 0 : 1);
+ }
+
+ // data source
+ if (mode == psModeForm || inType3Char || preload) {
+ writePS(" /DataSource { 2 copy get exch 1 add exch }\n");
+ } else {
+ writePS(" /DataSource currentfile\n");
+ }
+
+ // filters
+ s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
+ " ");
+ if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
+ inlineImg || !s) {
+ useRLE = gTrue;
+ useASCII = !(mode == psModeForm || inType3Char || preload);
+ useCompressed = gFalse;
+ } else {
+ useRLE = gFalse;
+ useASCII = str->isBinary() &&
+ !(mode == psModeForm || inType3Char || preload);
+ useCompressed = gTrue;
+ }
+ if (useASCII) {
+ writePSFmt(" /ASCII{0:s}Decode filter\n",
+ useASCIIHex ? "Hex" : "85");
+ }
+ if (useRLE) {
+ writePS(" /RunLengthDecode filter\n");
+ }
+ if (useCompressed) {
+ writePS(s->getCString());
+ }
+ if (s) {
+ delete s;
+ }
+
+ if (mode == psModeForm || inType3Char || preload) {
+
+ // end of image dictionary
+ writePSFmt(">>\n{0:s}\n", colorMap ? "image" : "imagemask");
+
+ // get rid of the array and index
+ writePS("pop pop\n");
+
+ } else {
+
+ // cut off inline image streams at appropriate length
+ if (inlineImg) {
+ str = new FixedLengthEncoder(str, len);
+ } else if (useCompressed) {
+ str = str->getUndecodedStream();
+ }
+
+ // recode DeviceN data
+ if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
+ str = new DeviceNRecoder(str, width, height, colorMap);
+ }
+
+ // add RunLengthEncode and ASCIIHex/85 encode filters
+ if (useRLE) {
+ str = new RunLengthEncoder(str);
+ }
+ if (useASCII) {
+ if (useASCIIHex) {
+ str = new ASCIIHexEncoder(str);
+ } else {
+ str = new ASCII85Encoder(str);
+ }
+ }
+
+ // end of image dictionary
+ writePS(">>\n");
+#if OPI_SUPPORT
+ if (opi13Nest) {
+ if (inlineImg) {
+ // this can't happen -- OPI dictionaries are in XObjects
+ error(-1, "Internal: OPI in inline image");
+ n = 0;
+ } else {
+ // need to read the stream to count characters -- the length
+ // is data-dependent (because of ASCII and RLE filters)
+ str->reset();
+ n = 0;
+ while ((c = str->getChar()) != EOF) {
+ ++n;
+ }
+ str->close();
+ }
+ // +6/7 for "pdfIm\n" / "pdfImM\n"
+ // +8 for newline + trailer
+ n += colorMap ? 14 : 15;
+ writePSFmt("%%BeginData: {0:d} Hex Bytes\n", n);
+ }
+#endif
+ if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap &&
+ colorMap->getColorSpace()->getMode() == csSeparation) {
+ color.c[0] = gfxColorComp1;
+ sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace();
+ sepCS->getCMYK(&color, &cmyk);
+ writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} ({4:t}) pdfImSep\n",
+ colToDbl(cmyk.c), colToDbl(cmyk.m),
+ colToDbl(cmyk.y), colToDbl(cmyk.k),
+ sepCS->getName());
+ } else {
+ writePSFmt("{0:s}\n", colorMap ? "pdfIm" : "pdfImM");
+ }
+
+ // copy the stream data
+ str->reset();
+ while ((c = str->getChar()) != EOF) {
+ writePSChar(c);
+ }
+ str->close();
+
+ // add newline and trailer to the end
+ writePSChar('\n');
+ writePS("%-EOD-\n");
+#if OPI_SUPPORT
+ if (opi13Nest) {
+ writePS("%%EndData\n");
+ }
+#endif
+
+ // delete encoders
+ if (useRLE || useASCII || inlineImg) {
+ delete str;
+ }
+ }
+
+ if ((maskColors && colorMap && !inlineImg) || maskStr) {
+ writePS("pdfImClipEnd\n");
+ }
+}
+
+//~ this doesn't currently support OPI
+void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap,
+ GBool invert, GBool inlineImg,
+ Stream *str, int width, int height, int len,
+ int *maskColors, Stream *maskStr,
+ int maskWidth, int maskHeight, GBool maskInvert) {
+ Stream *str2;
+ GString *s;
+ int n, numComps;
+ GBool useRLE, useASCII, useASCIIHex, useCompressed;
+ GBool maskUseRLE, maskUseASCII, maskUseCompressed;
+ GfxSeparationColorSpace *sepCS;
+ GfxColor color;
+ GfxCMYK cmyk;
+ int c;
+ int col, i;
+
+ useASCIIHex = globalParams->getPSASCIIHex();
+ useRLE = useASCII = useCompressed = gFalse; // make gcc happy
+ maskUseRLE = maskUseASCII = maskUseCompressed = gFalse; // make gcc happy
+
+ // color space
+ if (colorMap) {
+ dumpColorSpaceL2(colorMap->getColorSpace(), gFalse, gTrue, gFalse);
+ writePS(" setcolorspace\n");
+ }
+
+ // set up the image data
+ if (mode == psModeForm || inType3Char || preload) {
+ if (inlineImg) {
+ // create an array
+ str2 = new FixedLengthEncoder(str, len);
+ str2 = new RunLengthEncoder(str2);
+ if (useASCIIHex) {
+ str2 = new ASCIIHexEncoder(str2);
+ } else {
+ str2 = new ASCII85Encoder(str2);
+ }
+ str2->reset();
+ col = 0;
+ writePS((char *)(useASCIIHex ? "[<" : "[<~"));
+ do {
+ do {
+ c = str2->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
+ break;
+ }
+ if (c == 'z') {
+ writePSChar(c);
+ ++col;
+ } else {
+ writePSChar(c);
+ ++col;
+ for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) {
+ do {
+ c = str2->getChar();
+ } while (c == '\n' || c == '\r');
+ if (c == (useASCIIHex ? '>' : '~') || c == EOF) {
+ break;
+ }
+ writePSChar(c);
+ ++col;
+ }
+ }
+ // each line is: "<~...data...~><eol>"
+ // so max data length = 255 - 6 = 249
+ // chunks are 1 or 5 bytes each, so we have to stop at 245
+ // but make it 240 just to be safe
+ if (col > 240) {
+ writePS((char *)(useASCIIHex ? ">\n<" : "~>\n<~"));
+ col = 0;
+ }
+ } while (c != (useASCIIHex ? '>' : '~') && c != EOF);
+ writePS((char *)(useASCIIHex ? ">\n" : "~>\n"));
+ // add an extra entry because the RunLengthDecode filter may
+ // read past the end
+ writePS("<>]\n");
+ writePS("0\n");
+ str2->close();
+ delete str2;
+ } else {
+ // set up to use the array already created by setupImages()
+ writePSFmt("ImData_{0:d}_{1:d} 0\n", ref->getRefNum(), ref->getRefGen());
+ }
+ }
+
+ // explicit masking
+ if (maskStr) {
+ writePS("<<\n /ImageType 3\n");
+ writePS(" /InterleaveType 3\n");
+ writePS(" /DataDict\n");
+ }
+
+ // image (data) dictionary
+ writePSFmt("<<\n /ImageType {0:d}\n", (maskColors && colorMap) ? 4 : 1);
+
+ // color key masking
+ if (maskColors && colorMap) {
+ writePS(" /MaskColor [\n");
+ numComps = colorMap->getNumPixelComps();
+ for (i = 0; i < 2 * numComps; i += 2) {
+ writePSFmt(" {0:d} {1:d}\n", maskColors[i], maskColors[i+1]);
+ }
+ writePS(" ]\n");
+ }
+
+ // width, height, matrix, bits per component
+ writePSFmt(" /Width {0:d}\n", width);
+ writePSFmt(" /Height {0:d}\n", height);
+ writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n",
+ width, -height, height);
+ if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
+ writePS(" /BitsPerComponent 8\n");
+ } else {
+ writePSFmt(" /BitsPerComponent {0:d}\n",
+ colorMap ? colorMap->getBits() : 1);
+ }
+
+ // decode
+ if (colorMap) {
+ writePS(" /Decode [");
+ if ((level == psLevel2Sep || level == psLevel3Sep) &&
+ colorMap->getColorSpace()->getMode() == csSeparation) {
+ // this matches up with the code in the pdfImSep operator
+ n = (1 << colorMap->getBits()) - 1;
+ writePSFmt("{0:.4g} {1:.4g}", colorMap->getDecodeLow(0) * n,
+ colorMap->getDecodeHigh(0) * n);
+ } else if (colorMap->getColorSpace()->getMode() == csDeviceN) {
+ numComps = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->
+ getAlt()->getNComps();
+ for (i = 0; i < numComps; ++i) {
+ if (i > 0) {
+ writePS(" ");
+ }
+ writePS("0 1");
+ }
+ } else {
+ numComps = colorMap->getNumPixelComps();
+ for (i = 0; i < numComps; ++i) {
+ if (i > 0) {
+ writePS(" ");
+ }
+ writePSFmt("{0:.4g} {1:.4g}", colorMap->getDecodeLow(i),
+ colorMap->getDecodeHigh(i));
+ }
+ }
+ writePS("]\n");
+ } else {
+ writePSFmt(" /Decode [{0:d} {1:d}]\n", invert ? 1 : 0, invert ? 0 : 1);
+ }
+
+ // data source
+ if (mode == psModeForm || inType3Char || preload) {
+ writePS(" /DataSource { 2 copy get exch 1 add exch }\n");
+ } else {
+ writePS(" /DataSource currentfile\n");
+ }
+
+ // filters
+ s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
+ " ");
+ if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) ||
+ inlineImg || !s) {
+ useRLE = gTrue;
+ useASCII = !(mode == psModeForm || inType3Char || preload);
+ useCompressed = gFalse;
+ } else {
+ useRLE = gFalse;
+ useASCII = str->isBinary() &&
+ !(mode == psModeForm || inType3Char || preload);
+ useCompressed = gTrue;
+ }
+ if (useASCII) {
+ writePSFmt(" /ASCII{0:s}Decode filter\n",
+ useASCIIHex ? "Hex" : "85");
+ }
+ if (useRLE) {
+ writePS(" /RunLengthDecode filter\n");
+ }
+ if (useCompressed) {
+ writePS(s->getCString());
+ }
+ if (s) {
+ delete s;
+ }
+
+ // end of image (data) dictionary
+ writePS(">>\n");
+
+ // explicit masking
+ if (maskStr) {
+ writePS(" /MaskDict\n");
+ writePS("<<\n");
+ writePS(" /ImageType 1\n");
+ writePSFmt(" /Width {0:d}\n", maskWidth);
+ writePSFmt(" /Height {0:d}\n", maskHeight);
+ writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n",
+ maskWidth, -maskHeight, maskHeight);
+ writePS(" /BitsPerComponent 1\n");
+ writePSFmt(" /Decode [{0:d} {1:d}]\n",
+ maskInvert ? 1 : 0, maskInvert ? 0 : 1);
+
+ // mask data source
+ writePS(" /DataSource currentfile\n");
+ s = maskStr->getPSFilter(3, " ");
+ if (!s) {
+ maskUseRLE = gTrue;
+ maskUseASCII = gTrue;
+ maskUseCompressed = gFalse;
+ } else {
+ maskUseRLE = gFalse;
+ maskUseASCII = maskStr->isBinary();
+ maskUseCompressed = gTrue;
+ }
+ if (maskUseASCII) {
+ writePSFmt(" /ASCII{0:s}Decode filter\n",
+ useASCIIHex ? "Hex" : "85");
+ }
+ if (maskUseRLE) {
+ writePS(" /RunLengthDecode filter\n");
+ }
+ if (maskUseCompressed) {
+ writePS(s->getCString());
+ }
+ if (s) {
+ delete s;
+ }
+
+ writePS(">>\n");
+ writePS(">>\n");
+ }
+
+ if (mode == psModeForm || inType3Char || preload) {
+
+ // image command
+ writePSFmt("{0:s}\n", colorMap ? "image" : "imagemask");
+
+ } else {
+
+ if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap &&
+ colorMap->getColorSpace()->getMode() == csSeparation) {
+ color.c[0] = gfxColorComp1;
+ sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace();
+ sepCS->getCMYK(&color, &cmyk);
+ writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} ({4:t}) pdfImSep\n",
+ colToDbl(cmyk.c), colToDbl(cmyk.m),
+ colToDbl(cmyk.y), colToDbl(cmyk.k),
+ sepCS->getName());
+ } else {
+ writePSFmt("{0:s}\n", colorMap ? "pdfIm" : "pdfImM");
+ }
+
+ }
+
+ // explicit masking
+ if (maskStr) {
+
+ if (maskUseCompressed) {
+ maskStr = maskStr->getUndecodedStream();
+ }
+
+ // add RunLengthEncode and ASCIIHex/85 encode filters
+ if (maskUseRLE) {
+ maskStr = new RunLengthEncoder(maskStr);
+ }
+ if (maskUseASCII) {
+ if (useASCIIHex) {
+ maskStr = new ASCIIHexEncoder(maskStr);
+ } else {
+ maskStr = new ASCII85Encoder(maskStr);
+ }
+ }
+
+ // copy the stream data
+ maskStr->reset();
+ while ((c = maskStr->getChar()) != EOF) {
+ writePSChar(c);
+ }
+ maskStr->close();
+ writePSChar('\n');
+
+ // delete encoders
+ if (maskUseRLE || maskUseASCII) {
+ delete maskStr;
+ }
+ }
+
+ // get rid of the array and index
+ if (mode == psModeForm || inType3Char || preload) {
+ writePS("pop pop\n");
+
+ // image data
+ } else {
+
+ // cut off inline image streams at appropriate length
+ if (inlineImg) {
+ str = new FixedLengthEncoder(str, len);
+ } else if (useCompressed) {
+ str = str->getUndecodedStream();
+ }
+
+ // recode DeviceN data
+ if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) {
+ str = new DeviceNRecoder(str, width, height, colorMap);
+ }
+
+ // add RunLengthEncode and ASCIIHex/85 encode filters
+ if (useRLE) {
+ str = new RunLengthEncoder(str);
+ }
+ if (useASCII) {
+ if (useASCIIHex) {
+ str = new ASCIIHexEncoder(str);
+ } else {
+ str = new ASCII85Encoder(str);
+ }
+ }
+
+ // copy the stream data
+ str->reset();
+ while ((c = str->getChar()) != EOF) {
+ writePSChar(c);
+ }
+ str->close();
+
+ // add newline and trailer to the end
+ writePSChar('\n');
+ writePS("%-EOD-\n");
+
+ // delete encoders
+ if (useRLE || useASCII || inlineImg) {
+ delete str;
+ }
+ }
+}
+
+void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace,
+ GBool genXform, GBool updateColors,
+ GBool map01) {
+ GfxCalGrayColorSpace *calGrayCS;
+ GfxCalRGBColorSpace *calRGBCS;
+ GfxLabColorSpace *labCS;
+ GfxIndexedColorSpace *indexedCS;
+ GfxSeparationColorSpace *separationCS;
+ GfxDeviceNColorSpace *deviceNCS;
+ GfxColorSpace *baseCS;
+ Guchar *lookup, *p;
+ double x[gfxColorMaxComps], y[gfxColorMaxComps];
+ double low[gfxColorMaxComps], range[gfxColorMaxComps];
+ GfxColor color;
+ GfxCMYK cmyk;
+ Function *func;
+ int n, numComps, numAltComps;
+ int byte;
+ int i, j, k;
+
+ switch (colorSpace->getMode()) {
+
+ case csDeviceGray:
+ writePS("/DeviceGray");
+ if (genXform) {
+ writePS(" {}");
+ }
+ if (updateColors) {
+ processColors |= psProcessBlack;
+ }
+ break;
+
+ case csCalGray:
+ calGrayCS = (GfxCalGrayColorSpace *)colorSpace;
+ writePS("[/CIEBasedA <<\n");
+ writePSFmt(" /DecodeA {{{0:.4g} exp}} bind\n", calGrayCS->getGamma());
+ writePSFmt(" /MatrixA [{0:.4g} {1:.4g} {2:.4g}]\n",
+ calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
+ calGrayCS->getWhiteZ());
+ writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n",
+ calGrayCS->getWhiteX(), calGrayCS->getWhiteY(),
+ calGrayCS->getWhiteZ());
+ writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n",
+ calGrayCS->getBlackX(), calGrayCS->getBlackY(),
+ calGrayCS->getBlackZ());
+ writePS(">>]");
+ if (genXform) {
+ writePS(" {}");
+ }
+ if (updateColors) {
+ processColors |= psProcessBlack;
+ }
+ break;
+
+ case csDeviceRGB:
+ writePS("/DeviceRGB");
+ if (genXform) {
+ writePS(" {}");
+ }
+ if (updateColors) {
+ processColors |= psProcessCMYK;
+ }
+ break;
+
+ case csCalRGB:
+ calRGBCS = (GfxCalRGBColorSpace *)colorSpace;
+ writePS("[/CIEBasedABC <<\n");
+ writePSFmt(" /DecodeABC [{{{0:.4g} exp}} bind {{{1:.4g} exp}} bind {{{2:.4g} exp}} bind]\n",
+ calRGBCS->getGammaR(), calRGBCS->getGammaG(),
+ calRGBCS->getGammaB());
+ writePSFmt(" /MatrixABC [{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g} {6:.4g} {7:.4g} {8:.4g}]\n",
+ calRGBCS->getMatrix()[0], calRGBCS->getMatrix()[1],
+ calRGBCS->getMatrix()[2], calRGBCS->getMatrix()[3],
+ calRGBCS->getMatrix()[4], calRGBCS->getMatrix()[5],
+ calRGBCS->getMatrix()[6], calRGBCS->getMatrix()[7],
+ calRGBCS->getMatrix()[8]);
+ writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n",
+ calRGBCS->getWhiteX(), calRGBCS->getWhiteY(),
+ calRGBCS->getWhiteZ());
+ writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n",
+ calRGBCS->getBlackX(), calRGBCS->getBlackY(),
+ calRGBCS->getBlackZ());
+ writePS(">>]");
+ if (genXform) {
+ writePS(" {}");
+ }
+ if (updateColors) {
+ processColors |= psProcessCMYK;
+ }
+ break;
+
+ case csDeviceCMYK:
+ writePS("/DeviceCMYK");
+ if (genXform) {
+ writePS(" {}");
+ }
+ if (updateColors) {
+ processColors |= psProcessCMYK;
+ }
+ break;
+
+ case csLab:
+ labCS = (GfxLabColorSpace *)colorSpace;
+ writePS("[/CIEBasedABC <<\n");
+ if (map01) {
+ writePS(" /RangeABC [0 1 0 1 0 1]\n");
+ writePSFmt(" /DecodeABC [{{100 mul 16 add 116 div}} bind {{{0:.4g} mul {1:.4g} add}} bind {{{2:.4g} mul {3:.4g} add}} bind]\n",
+ (labCS->getAMax() - labCS->getAMin()) / 500.0,
+ labCS->getAMin() / 500.0,
+ (labCS->getBMax() - labCS->getBMin()) / 200.0,
+ labCS->getBMin() / 200.0);
+ } else {
+ writePSFmt(" /RangeABC [0 100 {0:.4g} {1:.4g} {2:.4g} {3:.4g}]\n",
+ labCS->getAMin(), labCS->getAMax(),
+ labCS->getBMin(), labCS->getBMax());
+ writePS(" /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]\n");
+ }
+ writePS(" /MatrixABC [1 1 1 1 0 0 0 0 -1]\n");
+ writePS(" /DecodeLMN\n");
+ writePS(" [{dup 6 29 div ge {dup dup mul mul}\n");
+ writePSFmt(" {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind\n",
+ labCS->getWhiteX());
+ writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
+ writePSFmt(" {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind\n",
+ labCS->getWhiteY());
+ writePS(" {dup 6 29 div ge {dup dup mul mul}\n");
+ writePSFmt(" {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind]\n",
+ labCS->getWhiteZ());
+ writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n",
+ labCS->getWhiteX(), labCS->getWhiteY(), labCS->getWhiteZ());
+ writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n",
+ labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ());
+ writePS(">>]");
+ if (genXform) {
+ writePS(" {}");
+ }
+ if (updateColors) {
+ processColors |= psProcessCMYK;
+ }
+ break;
+
+ case csICCBased:
+ // there is no transform function to the alternate color space, so
+ // we can use it directly
+ dumpColorSpaceL2(((GfxICCBasedColorSpace *)colorSpace)->getAlt(),
+ genXform, updateColors, gFalse);
+ break;
+
+ case csIndexed:
+ indexedCS = (GfxIndexedColorSpace *)colorSpace;
+ baseCS = indexedCS->getBase();
+ writePS("[/Indexed ");
+ dumpColorSpaceL2(baseCS, gFalse, gFalse, gTrue);
+ n = indexedCS->getIndexHigh();
+ numComps = baseCS->getNComps();
+ lookup = indexedCS->getLookup();
+ writePSFmt(" {0:d} <\n", n);
+ if (baseCS->getMode() == csDeviceN) {
+ func = ((GfxDeviceNColorSpace *)baseCS)->getTintTransformFunc();
+ baseCS->getDefaultRanges(low, range, indexedCS->getIndexHigh());
+ if (((GfxDeviceNColorSpace *)baseCS)->getAlt()->getMode() == csLab) {
+ labCS = (GfxLabColorSpace *)((GfxDeviceNColorSpace *)baseCS)->getAlt();
+ } else {
+ labCS = NULL;
+ }
+ numAltComps = ((GfxDeviceNColorSpace *)baseCS)->getAlt()->getNComps();
+ p = lookup;
+ for (i = 0; i <= n; i += 8) {
+ writePS(" ");
+ for (j = i; j < i+8 && j <= n; ++j) {
+ for (k = 0; k < numComps; ++k) {
+ x[k] = low[k] + (*p++ / 255.0) * range[k];
+ }
+ func->transform(x, y);
+ if (labCS) {
+ y[0] /= 100.0;
+ y[1] = (y[1] - labCS->getAMin()) /
+ (labCS->getAMax() - labCS->getAMin());
+ y[2] = (y[2] - labCS->getBMin()) /
+ (labCS->getBMax() - labCS->getBMin());
+ }
+ for (k = 0; k < numAltComps; ++k) {
+ byte = (int)(y[k] * 255 + 0.5);
+ if (byte < 0) {
+ byte = 0;
+ } else if (byte > 255) {
+ byte = 255;
+ }
+ writePSFmt("{0:02x}", byte);
+ }
+ if (updateColors) {
+ color.c[0] = dblToCol(j);
+ indexedCS->getCMYK(&color, &cmyk);
+ addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
+ colToDbl(cmyk.y), colToDbl(cmyk.k));
+ }
+ }
+ writePS("\n");
+ }
+ } else {
+ for (i = 0; i <= n; i += 8) {
+ writePS(" ");
+ for (j = i; j < i+8 && j <= n; ++j) {
+ for (k = 0; k < numComps; ++k) {
+ writePSFmt("{0:02x}", lookup[j * numComps + k]);
+ }
+ if (updateColors) {
+ color.c[0] = dblToCol(j);
+ indexedCS->getCMYK(&color, &cmyk);
+ addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m),
+ colToDbl(cmyk.y), colToDbl(cmyk.k));
+ }
+ }
+ writePS("\n");
+ }
+ }
+ writePS(">]");
+ if (genXform) {
+ writePS(" {}");
+ }
+ break;
+
+ case csSeparation:
+ separationCS = (GfxSeparationColorSpace *)colorSpace;
+ writePS("[/Separation ");
+ writePSString(separationCS->getName());
+ writePS(" ");
+ dumpColorSpaceL2(separationCS->getAlt(), gFalse, gFalse, gFalse);
+ writePS("\n");
+ cvtFunction(separationCS->getFunc());
+ writePS("]");
+ if (genXform) {
+ writePS(" {}");
+ }
+ if (updateColors) {
+ addCustomColor(separationCS);
+ }
+ break;
+
+ case csDeviceN:
+ // DeviceN color spaces are a Level 3 PostScript feature.
+ deviceNCS = (GfxDeviceNColorSpace *)colorSpace;
+ dumpColorSpaceL2(deviceNCS->getAlt(), gFalse, updateColors, map01);
+ if (genXform) {
+ writePS(" ");
+ cvtFunction(deviceNCS->getTintTransformFunc());
+ }
+ break;
+
+ case csPattern:
+ //~ unimplemented
+ break;
+ }
+}
+
+#if OPI_SUPPORT
+void PSOutputDev::opiBegin(GfxState *state, Dict *opiDict) {
+ Object dict;
+
+ if (globalParams->getPSOPI()) {
+ opiDict->lookup("2.0", &dict);
+ if (dict.isDict()) {
+ opiBegin20(state, dict.getDict());
+ dict.free();
+ } else {
+ dict.free();
+ opiDict->lookup("1.3", &dict);
+ if (dict.isDict()) {
+ opiBegin13(state, dict.getDict());
+ }
+ dict.free();
+ }
+ }
+}
+
+void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) {
+ Object obj1, obj2, obj3, obj4;
+ double width, height, left, right, top, bottom;
+ int w, h;
+ int i;
+
+ writePS("%%BeginOPI: 2.0\n");
+ writePS("%%Distilled\n");
+
+ dict->lookup("F", &obj1);
+ if (getFileSpec(&obj1, &obj2)) {
+ writePSFmt("%%ImageFileName: {0:t}\n", obj2.getString());
+ obj2.free();
+ }
+ obj1.free();
+
+ dict->lookup("MainImage", &obj1);
+ if (obj1.isString()) {
+ writePSFmt("%%MainImage: {0:t}\n", obj1.getString());
+ }
+ obj1.free();
+
+ //~ ignoring 'Tags' entry
+ //~ need to use writePSString() and deal with >255-char lines
+
+ dict->lookup("Size", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+ obj1.arrayGet(0, &obj2);
+ width = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ height = obj2.getNum();
+ obj2.free();
+ writePSFmt("%%ImageDimensions: {0:.4g} {1:.4g}\n", width, height);
+ }
+ obj1.free();
+
+ dict->lookup("CropRect", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 4) {
+ obj1.arrayGet(0, &obj2);
+ left = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ top = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2, &obj2);
+ right = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(3, &obj2);
+ bottom = obj2.getNum();
+ obj2.free();
+ writePSFmt("%%ImageCropRect: {0:.4g} {1:.4g} {2:.4g} {3:.4g}\n",
+ left, top, right, bottom);
+ }
+ obj1.free();
+
+ dict->lookup("Overprint", &obj1);
+ if (obj1.isBool()) {
+ writePSFmt("%%ImageOverprint: {0:s}\n", obj1.getBool() ? "true" : "false");
+ }
+ obj1.free();
+
+ dict->lookup("Inks", &obj1);
+ if (obj1.isName()) {
+ writePSFmt("%%ImageInks: {0:s}\n", obj1.getName());
+ } else if (obj1.isArray() && obj1.arrayGetLength() >= 1) {
+ obj1.arrayGet(0, &obj2);
+ if (obj2.isName()) {
+ writePSFmt("%%ImageInks: {0:s} {1:d}",
+ obj2.getName(), (obj1.arrayGetLength() - 1) / 2);
+ for (i = 1; i+1 < obj1.arrayGetLength(); i += 2) {
+ obj1.arrayGet(i, &obj3);
+ obj1.arrayGet(i+1, &obj4);
+ if (obj3.isString() && obj4.isNum()) {
+ writePS(" ");
+ writePSString(obj3.getString());
+ writePSFmt(" {0:.4g}", obj4.getNum());
+ }
+ obj3.free();
+ obj4.free();
+ }
+ writePS("\n");
+ }
+ obj2.free();
+ }
+ obj1.free();
+
+ writePS("gsave\n");
+
+ writePS("%%BeginIncludedImage\n");
+
+ dict->lookup("IncludedImageDimensions", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+ obj1.arrayGet(0, &obj2);
+ w = obj2.getInt();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ h = obj2.getInt();
+ obj2.free();
+ writePSFmt("%%IncludedImageDimensions: {0:d} {1:d}\n", w, h);
+ }
+ obj1.free();
+
+ dict->lookup("IncludedImageQuality", &obj1);
+ if (obj1.isNum()) {
+ writePSFmt("%%IncludedImageQuality: {0:.4g}\n", obj1.getNum());
+ }
+ obj1.free();
+
+ ++opi20Nest;
+}
+
+void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) {
+ Object obj1, obj2;
+ int left, right, top, bottom, samples, bits, width, height;
+ double c, m, y, k;
+ double llx, lly, ulx, uly, urx, ury, lrx, lry;
+ double tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry;
+ double horiz, vert;
+ int i, j;
+
+ writePS("save\n");
+ writePS("/opiMatrix2 matrix currentmatrix def\n");
+ writePS("opiMatrix setmatrix\n");
+
+ dict->lookup("F", &obj1);
+ if (getFileSpec(&obj1, &obj2)) {
+ writePSFmt("%ALDImageFileName: {0:t}\n", obj2.getString());
+ obj2.free();
+ }
+ obj1.free();
+
+ dict->lookup("CropRect", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 4) {
+ obj1.arrayGet(0, &obj2);
+ left = obj2.getInt();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ top = obj2.getInt();
+ obj2.free();
+ obj1.arrayGet(2, &obj2);
+ right = obj2.getInt();
+ obj2.free();
+ obj1.arrayGet(3, &obj2);
+ bottom = obj2.getInt();
+ obj2.free();
+ writePSFmt("%ALDImageCropRect: {0:d} {1:d} {2:d} {3:d}\n",
+ left, top, right, bottom);
+ }
+ obj1.free();
+
+ dict->lookup("Color", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 5) {
+ obj1.arrayGet(0, &obj2);
+ c = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ m = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2, &obj2);
+ y = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(3, &obj2);
+ k = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(4, &obj2);
+ if (obj2.isString()) {
+ writePSFmt("%ALDImageColor: {0:.4g} {1:.4g} {2:.4g} {3:.4g} ",
+ c, m, y, k);
+ writePSString(obj2.getString());
+ writePS("\n");
+ }
+ obj2.free();
+ }
+ obj1.free();
+
+ dict->lookup("ColorType", &obj1);
+ if (obj1.isName()) {
+ writePSFmt("%ALDImageColorType: {0:s}\n", obj1.getName());
+ }
+ obj1.free();
+
+ //~ ignores 'Comments' entry
+ //~ need to handle multiple lines
+
+ dict->lookup("CropFixed", &obj1);
+ if (obj1.isArray()) {
+ obj1.arrayGet(0, &obj2);
+ ulx = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ uly = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2, &obj2);
+ lrx = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(3, &obj2);
+ lry = obj2.getNum();
+ obj2.free();
+ writePSFmt("%ALDImageCropFixed: {0:.4g} {1:.4g} {2:.4g} {3:.4g}\n",
+ ulx, uly, lrx, lry);
+ }
+ obj1.free();
+
+ dict->lookup("GrayMap", &obj1);
+ if (obj1.isArray()) {
+ writePS("%ALDImageGrayMap:");
+ for (i = 0; i < obj1.arrayGetLength(); i += 16) {
+ if (i > 0) {
+ writePS("\n%%+");
+ }
+ for (j = 0; j < 16 && i+j < obj1.arrayGetLength(); ++j) {
+ obj1.arrayGet(i+j, &obj2);
+ writePSFmt(" {0:d}", obj2.getInt());
+ obj2.free();
+ }
+ }
+ writePS("\n");
+ }
+ obj1.free();
+
+ dict->lookup("ID", &obj1);
+ if (obj1.isString()) {
+ writePSFmt("%ALDImageID: {0:t}\n", obj1.getString());
+ }
+ obj1.free();
+
+ dict->lookup("ImageType", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+ obj1.arrayGet(0, &obj2);
+ samples = obj2.getInt();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ bits = obj2.getInt();
+ obj2.free();
+ writePSFmt("%ALDImageType: {0:d} {1:d}\n", samples, bits);
+ }
+ obj1.free();
+
+ dict->lookup("Overprint", &obj1);
+ if (obj1.isBool()) {
+ writePSFmt("%ALDImageOverprint: {0:s}\n",
+ obj1.getBool() ? "true" : "false");
+ }
+ obj1.free();
+
+ dict->lookup("Position", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 8) {
+ obj1.arrayGet(0, &obj2);
+ llx = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ lly = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2, &obj2);
+ ulx = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(3, &obj2);
+ uly = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(4, &obj2);
+ urx = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(5, &obj2);
+ ury = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(6, &obj2);
+ lrx = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(7, &obj2);
+ lry = obj2.getNum();
+ obj2.free();
+ opiTransform(state, llx, lly, &tllx, &tlly);
+ opiTransform(state, ulx, uly, &tulx, &tuly);
+ opiTransform(state, urx, ury, &turx, &tury);
+ opiTransform(state, lrx, lry, &tlrx, &tlry);
+ writePSFmt("%ALDImagePosition: {0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g} {6:.4g} {7:.4g}\n",
+ tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry);
+ obj2.free();
+ }
+ obj1.free();
+
+ dict->lookup("Resolution", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+ obj1.arrayGet(0, &obj2);
+ horiz = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ vert = obj2.getNum();
+ obj2.free();
+ writePSFmt("%ALDImageResoution: {0:.4g} {1:.4g}\n", horiz, vert);
+ obj2.free();
+ }
+ obj1.free();
+
+ dict->lookup("Size", &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 2) {
+ obj1.arrayGet(0, &obj2);
+ width = obj2.getInt();
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ height = obj2.getInt();
+ obj2.free();
+ writePSFmt("%ALDImageDimensions: {0:d} {1:d}\n", width, height);
+ }
+ obj1.free();
+
+ //~ ignoring 'Tags' entry
+ //~ need to use writePSString() and deal with >255-char lines
+
+ dict->lookup("Tint", &obj1);
+ if (obj1.isNum()) {
+ writePSFmt("%ALDImageTint: {0:.4g}\n", obj1.getNum());
+ }
+ obj1.free();
+
+ dict->lookup("Transparency", &obj1);
+ if (obj1.isBool()) {
+ writePSFmt("%ALDImageTransparency: {0:s}\n",
+ obj1.getBool() ? "true" : "false");
+ }
+ obj1.free();
+
+ writePS("%%BeginObject: image\n");
+ writePS("opiMatrix2 setmatrix\n");
+ ++opi13Nest;
+}
+
+// Convert PDF user space coordinates to PostScript default user space
+// coordinates. This has to account for both the PDF CTM and the
+// PSOutputDev page-fitting transform.
+void PSOutputDev::opiTransform(GfxState *state, double x0, double y0,
+ double *x1, double *y1) {
+ double t;
+
+ state->transform(x0, y0, x1, y1);
+ *x1 += tx;
+ *y1 += ty;
+ if (rotate == 90) {
+ t = *x1;
+ *x1 = -*y1;
+ *y1 = t;
+ } else if (rotate == 180) {
+ *x1 = -*x1;
+ *y1 = -*y1;
+ } else if (rotate == 270) {
+ t = *x1;
+ *x1 = *y1;
+ *y1 = -t;
+ }
+ *x1 *= xScale;
+ *y1 *= yScale;
+}
+
+void PSOutputDev::opiEnd(GfxState *state, Dict *opiDict) {
+ Object dict;
+
+ if (globalParams->getPSOPI()) {
+ opiDict->lookup("2.0", &dict);
+ if (dict.isDict()) {
+ writePS("%%EndIncludedImage\n");
+ writePS("%%EndOPI\n");
+ writePS("grestore\n");
+ --opi20Nest;
+ dict.free();
+ } else {
+ dict.free();
+ opiDict->lookup("1.3", &dict);
+ if (dict.isDict()) {
+ writePS("%%EndObject\n");
+ writePS("restore\n");
+ --opi13Nest;
+ }
+ dict.free();
+ }
+ }
+}
+
+GBool PSOutputDev::getFileSpec(Object *fileSpec, Object *fileName) {
+ if (fileSpec->isString()) {
+ fileSpec->copy(fileName);
+ return gTrue;
+ }
+ if (fileSpec->isDict()) {
+ fileSpec->dictLookup("DOS", fileName);
+ if (fileName->isString()) {
+ return gTrue;
+ }
+ fileName->free();
+ fileSpec->dictLookup("Mac", fileName);
+ if (fileName->isString()) {
+ return gTrue;
+ }
+ fileName->free();
+ fileSpec->dictLookup("Unix", fileName);
+ if (fileName->isString()) {
+ return gTrue;
+ }
+ fileName->free();
+ fileSpec->dictLookup("F", fileName);
+ if (fileName->isString()) {
+ return gTrue;
+ }
+ fileName->free();
+ }
+ return gFalse;
+}
+#endif // OPI_SUPPORT
+
+void PSOutputDev::type3D0(GfxState * /*state*/, double wx, double wy) {
+ writePSFmt("{0:.4g} {1:.4g} setcharwidth\n", wx, wy);
+ writePS("q\n");
+ t3NeedsRestore = gTrue;
+}
+
+void PSOutputDev::type3D1(GfxState * /*state*/, double wx, double wy,
+ double llx, double lly, double urx, double ury) {
+ t3WX = wx;
+ t3WY = wy;
+ t3LLX = llx;
+ t3LLY = lly;
+ t3URX = urx;
+ t3URY = ury;
+ t3String = new GString();
+ writePS("q\n");
+ t3Cacheable = gTrue;
+ t3NeedsRestore = gTrue;
+}
+
+void PSOutputDev::drawForm(Ref id) {
+ writePSFmt("f_{0:d}_{1:d}\n", id.num, id.gen);
+}
+
+void PSOutputDev::psXObject(Stream *psStream, Stream *level1Stream) {
+ Stream *str;
+ int c;
+
+ if ((level == psLevel1 || level == psLevel1Sep) && level1Stream) {
+ str = level1Stream;
+ } else {
+ str = psStream;
+ }
+ str->reset();
+ while ((c = str->getChar()) != EOF) {
+ writePSChar(c);
+ }
+ str->close();
+}
+
+//~ can nextFunc be reset to 0 -- maybe at the start of each page?
+//~ or maybe at the start of each color space / pattern?
+void PSOutputDev::cvtFunction(Function *func) {
+ SampledFunction *func0;
+ ExponentialFunction *func2;
+ StitchingFunction *func3;
+ PostScriptFunction *func4;
+ int thisFunc, m, n, nSamples, i, j, k;
+
+ switch (func->getType()) {
+
+ case -1: // identity
+ writePS("{}\n");
+ break;
+
+ case 0: // sampled
+ func0 = (SampledFunction *)func;
+ thisFunc = nextFunc++;
+ m = func0->getInputSize();
+ n = func0->getOutputSize();
+ nSamples = n;
+ for (i = 0; i < m; ++i) {
+ nSamples *= func0->getSampleSize(i);
+ }
+ writePSFmt("/xpdfSamples{0:d} [\n", thisFunc);
+ for (i = 0; i < nSamples; ++i) {
+ writePSFmt("{0:.4g}\n", func0->getSamples()[i]);
+ }
+ writePS("] def\n");
+ writePSFmt("{{ {0:d} array {1:d} array {2:d} 2 roll\n", 2*m, m, m+2);
+ // [e01] [efrac] x0 x1 ... xm-1
+ for (i = m-1; i >= 0; --i) {
+ // [e01] [efrac] x0 x1 ... xi
+ writePSFmt("{0:.4g} sub {1:.4g} mul {2:.4g} add\n",
+ func0->getDomainMin(i),
+ (func0->getEncodeMax(i) - func0->getEncodeMin(i)) /
+ (func0->getDomainMax(i) - func0->getDomainMin(i)),
+ func0->getEncodeMin(i));
+ // [e01] [efrac] x0 x1 ... xi-1 xi'
+ writePSFmt("dup 0 lt {{ pop 0 }} {{ dup {0:d} gt {{ pop {1:d} }} if }} ifelse\n",
+ func0->getSampleSize(i) - 1, func0->getSampleSize(i) - 1);
+ // [e01] [efrac] x0 x1 ... xi-1 xi'
+ writePS("dup floor cvi exch dup ceiling cvi exch 2 index sub\n");
+ // [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi') xi'-floor(xi')
+ writePSFmt("{0:d} index {1:d} 3 2 roll put\n", i+3, i);
+ // [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi')
+ writePSFmt("{0:d} index {1:d} 3 2 roll put\n", i+3, 2*i+1);
+ // [e01] [efrac] x0 x1 ... xi-1 floor(xi')
+ writePSFmt("{0:d} index {1:d} 3 2 roll put\n", i+2, 2*i);
+ // [e01] [efrac] x0 x1 ... xi-1
+ }
+ // [e01] [efrac]
+ for (i = 0; i < n; ++i) {
+ // [e01] [efrac] y(0) ... y(i-1)
+ for (j = 0; j < (1<<m); ++j) {
+ // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(j-1)
+ writePSFmt("xpdfSamples{0:d}\n", thisFunc);
+ k = m - 1;
+ writePSFmt("{0:d} index {1:d} get\n", i+j+2, 2 * k + ((j >> k) & 1));
+ for (k = m - 2; k >= 0; --k) {
+ writePSFmt("{0:d} mul {1:d} index {2:d} get add\n",
+ func0->getSampleSize(k),
+ i + j + 3,
+ 2 * k + ((j >> k) & 1));
+ }
+ if (n > 1) {
+ writePSFmt("{0:d} mul {1:d} add ", n, i);
+ }
+ writePS("get\n");
+ }
+ // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^m-1)
+ for (j = 0; j < m; ++j) {
+ // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^(m-j)-1)
+ for (k = 0; k < (1 << (m - j)); k += 2) {
+ // [e01] [efrac] y(0) ... y(i-1) <k/2 s' values> <2^(m-j)-k s values>
+ writePSFmt("{0:d} index {1:d} get dup\n",
+ i + k/2 + (1 << (m-j)) - k, j);
+ writePS("3 2 roll mul exch 1 exch sub 3 2 roll mul add\n");
+ writePSFmt("{0:d} 1 roll\n", k/2 + (1 << m-j) - k - 1);
+ }
+ // [e01] [efrac] s'(0) s'(1) ... s(2^(m-j-1)-1)
+ }
+ // [e01] [efrac] y(0) ... y(i-1) s
+ writePSFmt("{0:.4g} mul {1:.4g} add\n",
+ func0->getDecodeMax(i) - func0->getDecodeMin(i),
+ func0->getDecodeMin(i));
+ writePSFmt("dup {0:.4g} lt {{ pop {1:.4g} }} {{ dup {2:.4g} gt {{ pop {3:.4g} }} if }} ifelse\n",
+ func0->getRangeMin(i), func0->getRangeMin(i),
+ func0->getRangeMax(i), func0->getRangeMax(i));
+ // [e01] [efrac] y(0) ... y(i-1) y(i)
+ }
+ // [e01] [efrac] y(0) ... y(n-1)
+ writePSFmt("{0:d} {1:d} roll pop pop }}\n", n+2, n);
+ break;
+
+ case 2: // exponential
+ func2 = (ExponentialFunction *)func;
+ n = func2->getOutputSize();
+ writePSFmt("{{ dup {0:.4g} lt {{ pop {1:.4g} }} {{ dup {2:.4g} gt {{ pop {3:.4g} }} if }} ifelse\n",
+ func2->getDomainMin(0), func2->getDomainMin(0),
+ func2->getDomainMax(0), func2->getDomainMax(0));
+ // x
+ for (i = 0; i < n; ++i) {
+ // x y(0) .. y(i-1)
+ writePSFmt("{0:d} index {1:.4g} exp {2:.4g} mul {3:.4g} add\n",
+ i, func2->getE(), func2->getC1()[i] - func2->getC0()[i],
+ func2->getC0()[i]);
+ if (func2->getHasRange()) {
+ writePSFmt("dup {0:.4g} lt {{ pop {1:.4g} }} {{ dup {2:.4g} gt {{ pop {3:.4g} }} if }} ifelse\n",
+ func2->getRangeMin(i), func2->getRangeMin(i),
+ func2->getRangeMax(i), func2->getRangeMax(i));
+ }
+ }
+ // x y(0) .. y(n-1)
+ writePSFmt("{0:d} {1:d} roll pop }}\n", n+1, n);
+ break;
+
+ case 3: // stitching
+ func3 = (StitchingFunction *)func;
+ thisFunc = nextFunc++;
+ for (i = 0; i < func3->getNumFuncs(); ++i) {
+ cvtFunction(func3->getFunc(i));
+ writePSFmt("/xpdfFunc{0:d}_{1:d} exch def\n", thisFunc, i);
+ }
+ writePSFmt("{{ dup {0:.4g} lt {{ pop {1:.4g} }} {{ dup {2:.4g} gt {{ pop {3:.4g} }} if }} ifelse\n",
+ func3->getDomainMin(0), func3->getDomainMin(0),
+ func3->getDomainMax(0), func3->getDomainMax(0));
+ for (i = 0; i < func3->getNumFuncs() - 1; ++i) {
+ writePSFmt("dup {0:.4g} lt {{ {1:.4g} sub {2:.4g} mul {3:.4g} add xpdfFunc{4:d}_{5:d} }} {{\n",
+ func3->getBounds()[i+1],
+ func3->getBounds()[i],
+ func3->getScale()[i],
+ func3->getEncode()[2*i],
+ thisFunc, i);
+ }
+ writePSFmt("{0:.4g} sub {1:.4g} mul {2:.4g} add xpdfFunc{3:d}_{4:d}\n",
+ func3->getBounds()[i],
+ func3->getScale()[i],
+ func3->getEncode()[2*i],
+ thisFunc, i);
+ for (i = 0; i < func3->getNumFuncs() - 1; ++i) {
+ writePS("} ifelse\n");
+ }
+ writePS("}\n");
+ break;
+
+ case 4: // PostScript
+ func4 = (PostScriptFunction *)func;
+ writePS(func4->getCodeString()->getCString());
+ writePS("\n");
+ break;
+ }
+}
+
+void PSOutputDev::writePSChar(char c) {
+ if (t3String) {
+ t3String->append(c);
+ } else {
+ (*outputFunc)(outputStream, &c, 1);
+ }
+}
+
+void PSOutputDev::writePS(char *s) {
+ if (t3String) {
+ t3String->append(s);
+ } else {
+ (*outputFunc)(outputStream, s, strlen(s));
+ }
+}
+
+void PSOutputDev::writePSFmt(const char *fmt, ...) {
+ va_list args;
+ GString *buf;
+
+ va_start(args, fmt);
+ if (t3String) {
+ t3String->appendfv((char *)fmt, args);
+ } else {
+ buf = GString::formatv((char *)fmt, args);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ va_end(args);
+}
+
+void PSOutputDev::writePSString(GString *s) {
+ Guchar *p;
+ int n, line;
+ char buf[8];
+
+ writePSChar('(');
+ line = 1;
+ for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
+ if (line >= 64) {
+ writePSChar('\\');
+ writePSChar('\n');
+ line = 0;
+ }
+ if (*p == '(' || *p == ')' || *p == '\\') {
+ writePSChar('\\');
+ writePSChar((char)*p);
+ line += 2;
+ } else if (*p < 0x20 || *p >= 0x80) {
+ sprintf(buf, "\\%03o", *p);
+ writePS(buf);
+ line += 4;
+ } else {
+ writePSChar((char)*p);
+ ++line;
+ }
+ }
+ writePSChar(')');
+}
+
+void PSOutputDev::writePSName(char *s) {
+ char *p;
+ char c;
+
+ p = s;
+ while ((c = *p++)) {
+ if (c <= (char)0x20 || c >= (char)0x7f ||
+ c == '(' || c == ')' || c == '<' || c == '>' ||
+ c == '[' || c == ']' || c == '{' || c == '}' ||
+ c == '/' || c == '%') {
+ writePSFmt("#{0:02x}", c & 0xff);
+ } else {
+ writePSChar(c);
+ }
+ }
+}
+
+GString *PSOutputDev::filterPSName(GString *name) {
+ GString *name2;
+ char buf[8];
+ int i;
+ char c;
+
+ name2 = new GString();
+
+ // ghostscript chokes on names that begin with out-of-limits
+ // numbers, e.g., 1e4foo is handled correctly (as a name), but
+ // 1e999foo generates a limitcheck error
+ c = name->getChar(0);
+ if (c >= '0' && c <= '9') {
+ name2->append('f');
+ }
+
+ for (i = 0; i < name->getLength(); ++i) {
+ c = name->getChar(i);
+ if (c <= (char)0x20 || c >= (char)0x7f ||
+ c == '(' || c == ')' || c == '<' || c == '>' ||
+ c == '[' || c == ']' || c == '{' || c == '}' ||
+ c == '/' || c == '%') {
+ sprintf(buf, "#%02x", c & 0xff);
+ name2->append(buf);
+ } else {
+ name2->append(c);
+ }
+ }
+ return name2;
+}
+
+// Write a DSC-compliant <textline>.
+void PSOutputDev::writePSTextLine(GString *s) {
+ int i, j, step;
+ int c;
+
+ // - DSC comments must be printable ASCII; control chars and
+ // backslashes have to be escaped (we do cheap Unicode-to-ASCII
+ // conversion by simply ignoring the high byte)
+ // - lines are limited to 255 chars (we limit to 200 here to allow
+ // for the keyword, which was emitted by the caller)
+ // - lines that start with a left paren are treated as <text>
+ // instead of <textline>, so we escape a leading paren
+ if (s->getLength() >= 2 &&
+ (s->getChar(0) & 0xff) == 0xfe &&
+ (s->getChar(1) & 0xff) == 0xff) {
+ i = 3;
+ step = 2;
+ } else {
+ i = 0;
+ step = 1;
+ }
+ for (j = 0; i < s->getLength() && j < 200; i += step) {
+ c = s->getChar(i) & 0xff;
+ if (c == '\\') {
+ writePS("\\\\");
+ j += 2;
+ } else if (c < 0x20 || c > 0x7e || (j == 0 && c == '(')) {
+ writePSFmt("\\{0:03o}", c);
+ j += 4;
+ } else {
+ writePSChar(c);
+ ++j;
+ }
+ }
+ writePS("\n");
+}
diff --git a/kpdf/xpdf/xpdf/PSOutputDev.h b/kpdf/xpdf/xpdf/PSOutputDev.h
new file mode 100644
index 00000000..36c0e8b6
--- /dev/null
+++ b/kpdf/xpdf/xpdf/PSOutputDev.h
@@ -0,0 +1,391 @@
+//========================================================================
+//
+// PSOutputDev.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef PSOUTPUTDEV_H
+#define PSOUTPUTDEV_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include <stddef.h>
+#include "config.h"
+#include "Object.h"
+#include "GlobalParams.h"
+#include "OutputDev.h"
+
+class Function;
+class GfxPath;
+class GfxFont;
+class GfxColorSpace;
+class GfxSeparationColorSpace;
+class PDFRectangle;
+struct PSFont8Info;
+struct PSFont16Enc;
+class PSOutCustomColor;
+
+//------------------------------------------------------------------------
+// PSOutputDev
+//------------------------------------------------------------------------
+
+enum PSOutMode {
+ psModePS,
+ psModeEPS,
+ psModeForm
+};
+
+enum PSFileType {
+ psFile, // write to file
+ psPipe, // write to pipe
+ psStdout, // write to stdout
+ psGeneric // write to a generic stream
+};
+
+typedef void (*PSOutputFunc)(void *stream, char *data, int len);
+
+class PSOutputDev: public OutputDev {
+public:
+
+ // Open a PostScript output file, and write the prolog.
+ PSOutputDev(char *fileName, char *pstitle, XRef *xrefA, Catalog *catalog,
+ int firstPage, int lastPage, PSOutMode modeA,
+ int imgLLXA = 0, int imgLLYA = 0,
+ int imgURXA = 0, int imgURYA = 0,
+ GBool forceRasterize = gFalse,
+ GBool manualCtrlA = gFalse);
+
+ // Destructor -- writes the trailer and closes the file.
+ virtual ~PSOutputDev();
+
+ // Check if file was successfully created.
+ virtual GBool isOk() { return ok; }
+
+ //---- get info about output device
+
+ // Does this device use upside-down coordinates?
+ // (Upside-down means (0,0) is the top left corner of the page.)
+ virtual GBool upsideDown() { return gFalse; }
+
+ // Does this device use drawChar() or drawString()?
+ virtual GBool useDrawChar() { return gFalse; }
+
+ // Does this device use tilingPatternFill()? If this returns false,
+ // tiling pattern fills will be reduced to a series of other drawing
+ // operations.
+ virtual GBool useTilingPatternFill() { return gTrue; }
+
+ // Does this device use functionShadedFill(), axialShadedFill(), and
+ // radialShadedFill()? If this returns false, these shaded fills
+ // will be reduced to a series of other drawing operations.
+ virtual GBool useShadedFills()
+ { return level >= psLevel2; }
+
+ // Does this device use drawForm()? If this returns false,
+ // form-type XObjects will be interpreted (i.e., unrolled).
+ virtual GBool useDrawForm() { return preload; }
+
+ // Does this device use beginType3Char/endType3Char? Otherwise,
+ // text in Type 3 fonts will be drawn with drawChar/drawString.
+ virtual GBool interpretType3Chars() { return gFalse; }
+
+ //----- header/trailer (used only if manualCtrl is true)
+
+ // Write the document-level header.
+ void writeHeader(int firstPage, int lastPage,
+ PDFRectangle *mediaBox, PDFRectangle *cropBox,
+ int pageRotate, char *pstitle);
+
+ // Write the Xpdf procset.
+ void writeXpdfProcset();
+
+ // Write the document-level setup.
+ void writeDocSetup(Catalog *catalog, int firstPage, int lastPage);
+
+ // Write the trailer for the current page.
+ void writePageTrailer();
+
+ // Write the document trailer.
+ void writeTrailer();
+
+ //----- initialization and control
+
+ // Check to see if a page slice should be displayed. If this
+ // returns false, the page display is aborted. Typically, an
+ // OutputDev will use some alternate means to display the page
+ // before returning false.
+ virtual GBool checkPageSlice(Page *page, double hDPI, double vDPI,
+ int rotate, GBool useMediaBox, GBool crop,
+ int sliceX, int sliceY, int sliceW, int sliceH,
+ GBool printing, Catalog *catalog,
+ GBool (*abortCheckCbk)(void *data) = NULL,
+ void *abortCheckCbkData = NULL);
+
+ // Start a page.
+ virtual void startPage(int pageNum, GfxState *state);
+
+ // End a page.
+ virtual void endPage();
+
+ //----- save/restore graphics state
+ virtual void saveState(GfxState *state);
+ virtual void restoreState(GfxState *state);
+
+ //----- update graphics state
+ virtual void updateCTM(GfxState *state, double m11, double m12,
+ double m21, double m22, double m31, double m32);
+ virtual void updateLineDash(GfxState *state);
+ virtual void updateFlatness(GfxState *state);
+ virtual void updateLineJoin(GfxState *state);
+ virtual void updateLineCap(GfxState *state);
+ virtual void updateMiterLimit(GfxState *state);
+ virtual void updateLineWidth(GfxState *state);
+ virtual void updateFillColorSpace(GfxState *state);
+ virtual void updateStrokeColorSpace(GfxState *state);
+ virtual void updateFillColor(GfxState *state);
+ virtual void updateStrokeColor(GfxState *state);
+ virtual void updateFillOverprint(GfxState *state);
+ virtual void updateStrokeOverprint(GfxState *state);
+ virtual void updateTransfer(GfxState *state);
+
+ //----- update text state
+ virtual void updateFont(GfxState *state);
+ virtual void updateTextMat(GfxState *state);
+ virtual void updateCharSpace(GfxState *state);
+ virtual void updateRender(GfxState *state);
+ virtual void updateRise(GfxState *state);
+ virtual void updateWordSpace(GfxState *state);
+ virtual void updateHorizScaling(GfxState *state);
+ virtual void updateTextPos(GfxState *state);
+ virtual void updateTextShift(GfxState *state, double shift);
+
+ //----- path painting
+ virtual void stroke(GfxState *state);
+ virtual void fill(GfxState *state);
+ virtual void eoFill(GfxState *state);
+ virtual void tilingPatternFill(GfxState *state, Object *str,
+ int paintType, Dict *resDict,
+ double *mat, double *bbox,
+ int x0, int y0, int x1, int y1,
+ double xStep, double yStep);
+ virtual GBool functionShadedFill(GfxState *state,
+ GfxFunctionShading *shading);
+ virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading);
+ virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading);
+
+ //----- path clipping
+ virtual void clip(GfxState *state);
+ virtual void eoClip(GfxState *state);
+ virtual void clipToStrokePath(GfxState *state);
+
+ //----- text drawing
+ virtual void drawString(GfxState *state, GString *s);
+ virtual void endTextObject(GfxState *state);
+
+ //----- image drawing
+ virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool inlineImg);
+ virtual void drawImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GfxImageColorMap *colorMap,
+ int *maskColors, GBool inlineImg);
+ virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ Stream *maskStr, int maskWidth, int maskHeight,
+ GBool maskInvert);
+
+#if OPI_SUPPORT
+ //----- OPI functions
+ virtual void opiBegin(GfxState *state, Dict *opiDict);
+ virtual void opiEnd(GfxState *state, Dict *opiDict);
+#endif
+
+ //----- Type 3 font operators
+ virtual void type3D0(GfxState *state, double wx, double wy);
+ virtual void type3D1(GfxState *state, double wx, double wy,
+ double llx, double lly, double urx, double ury);
+
+ //----- form XObjects
+ virtual void drawForm(Ref ref);
+
+ //----- PostScript XObjects
+ virtual void psXObject(Stream *psStream, Stream *level1Stream);
+
+ //----- miscellaneous
+ void setOffset(double x, double y)
+ { tx0 = x; ty0 = y; }
+ void setScale(double x, double y)
+ { xScale0 = x; yScale0 = y; }
+ void setRotate(int rotateA)
+ { rotate0 = rotateA; }
+ void setClip(double llx, double lly, double urx, double ury)
+ { clipLLX0 = llx; clipLLY0 = lly; clipURX0 = urx; clipURY0 = ury; }
+ void setUnderlayCbk(void (*cbk)(PSOutputDev *psOut, void *data),
+ void *data)
+ { underlayCbk = cbk; underlayCbkData = data; }
+ void setOverlayCbk(void (*cbk)(PSOutputDev *psOut, void *data),
+ void *data)
+ { overlayCbk = cbk; overlayCbkData = data; }
+
+private:
+
+ void init(PSOutputFunc outputFuncA, void *outputStreamA,
+ PSFileType fileTypeA, char *pstitle, XRef *xrefA, Catalog *catalog,
+ int firstPage, int lastPage, PSOutMode modeA,
+ int imgLLXA, int imgLLYA, int imgURXA, int imgURYA,
+ GBool manualCtrlA);
+ void setupResources(Dict *resDict);
+ void setupFonts(Dict *resDict);
+ void setupFont(GfxFont *font, Dict *parentResDict);
+ void setupEmbeddedType1Font(Ref *id, GString *psName);
+ void setupExternalType1Font(GString *fileName, GString *psName);
+ void setupEmbeddedType1CFont(GfxFont *font, Ref *id, GString *psName);
+ void setupEmbeddedOpenTypeT1CFont(GfxFont *font, Ref *id, GString *psName);
+ void setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, GString *psName);
+ GString *setupExternalTrueTypeFont(GfxFont *font);
+ void setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, GString *psName);
+ void setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, GString *psName,
+ GBool needVerticalMetrics);
+ void setupEmbeddedOpenTypeCFFFont(GfxFont *font, Ref *id, GString *psName);
+ GString *setupExternalCIDTrueTypeFont(GfxFont *font, GString *fileName, int faceIndex=0);
+ void setupType3Font(GfxFont *font, GString *psName, Dict *parentResDict);
+ void setupImages(Dict *resDict);
+ void setupImage(Ref id, Stream *str);
+ void setupForms(Dict *resDict);
+ void setupForm(Ref id, Object *strObj);
+ void addProcessColor(double c, double m, double y, double k);
+ void addCustomColor(GfxSeparationColorSpace *sepCS);
+ void doPath(GfxPath *path);
+ void doImageL1(Object *ref, GfxImageColorMap *colorMap,
+ GBool invert, GBool inlineImg,
+ Stream *str, int width, int height, int len);
+ void doImageL1Sep(GfxImageColorMap *colorMap,
+ GBool invert, GBool inlineImg,
+ Stream *str, int width, int height, int len);
+ void doImageL2(Object *ref, GfxImageColorMap *colorMap,
+ GBool invert, GBool inlineImg,
+ Stream *str, int width, int height, int len,
+ int *maskColors, Stream *maskStr,
+ int maskWidth, int maskHeight, GBool maskInvert);
+ void doImageL3(Object *ref, GfxImageColorMap *colorMap,
+ GBool invert, GBool inlineImg,
+ Stream *str, int width, int height, int len,
+ int *maskColors, Stream *maskStr,
+ int maskWidth, int maskHeight, GBool maskInvert);
+ void dumpColorSpaceL2(GfxColorSpace *colorSpace,
+ GBool genXform, GBool updateColors,
+ GBool map01);
+#if OPI_SUPPORT
+ void opiBegin20(GfxState *state, Dict *dict);
+ void opiBegin13(GfxState *state, Dict *dict);
+ void opiTransform(GfxState *state, double x0, double y0,
+ double *x1, double *y1);
+ GBool getFileSpec(Object *fileSpec, Object *fileName);
+#endif
+ void cvtFunction(Function *func);
+ void writePSChar(char c);
+ void writePS(char *s);
+ void writePSFmt(const char *fmt, ...);
+ void writePSString(GString *s);
+ void writePSName(char *s);
+ GString *filterPSName(GString *name);
+ void writePSTextLine(GString *s);
+
+ PSLevel level; // PostScript level (1, 2, separation)
+ PSOutMode mode; // PostScript mode (PS, EPS, form)
+ int paperWidth; // width of paper, in pts
+ int paperHeight; // height of paper, in pts
+ int imgLLX, imgLLY, // imageable area, in pts
+ imgURX, imgURY;
+ GBool preload; // load all images into memory, and
+ // predefine forms
+
+ PSOutputFunc outputFunc;
+ void *outputStream;
+ PSFileType fileType; // file / pipe / stdout
+ GBool manualCtrl;
+ int seqPage; // current sequential page number
+ void (*underlayCbk)(PSOutputDev *psOut, void *data);
+ void *underlayCbkData;
+ void (*overlayCbk)(PSOutputDev *psOut, void *data);
+ void *overlayCbkData;
+
+ XRef *xref; // the xref table for this PDF file
+
+ Ref *fontIDs; // list of object IDs of all used fonts
+ int fontIDLen; // number of entries in fontIDs array
+ int fontIDSize; // size of fontIDs array
+ Ref *fontFileIDs; // list of object IDs of all embedded fonts
+ int fontFileIDLen; // number of entries in fontFileIDs array
+ int fontFileIDSize; // size of fontFileIDs array
+ GString **fontFileNames; // list of names of all embedded external fonts
+ GString **psFileNames; // list of names of all embedded external ps names
+ int fontFileNameLen; // number of entries in fontFileNames array
+ int fontFileNameSize; // size of fontFileNames array
+ int nextTrueTypeNum; // next unique number to append to a TrueType
+ // font name
+ PSFont8Info *font8Info; // info for 8-bit fonts
+ int font8InfoLen; // number of entries in font8Info array
+ int font8InfoSize; // size of font8Info array
+ PSFont16Enc *font16Enc; // encodings for substitute 16-bit fonts
+ int font16EncLen; // number of entries in font16Enc array
+ int font16EncSize; // size of font16Enc array
+ Ref *imgIDs; // list of image IDs for in-memory images
+ int imgIDLen; // number of entries in imgIDs array
+ int imgIDSize; // size of imgIDs array
+ Ref *formIDs; // list of IDs for predefined forms
+ int formIDLen; // number of entries in formIDs array
+ int formIDSize; // size of formIDs array
+ GList *xobjStack; // stack of XObject dicts currently being
+ // processed
+ int numSaves; // current number of gsaves
+ int numTilingPatterns; // current number of nested tiling patterns
+ int nextFunc; // next unique number to use for a function
+
+ double tx0, ty0; // global translation
+ double xScale0, yScale0; // global scaling
+ int rotate0; // rotation angle (0, 90, 180, 270)
+ double clipLLX0, clipLLY0,
+ clipURX0, clipURY0;
+ double tx, ty; // global translation for current page
+ double xScale, yScale; // global scaling for current page
+ int rotate; // rotation angle for current page
+ double epsX1, epsY1, // EPS bounding box (unrotated)
+ epsX2, epsY2;
+
+ GString *embFontList; // resource comments for embedded fonts
+
+ int processColors; // used process colors
+ PSOutCustomColor // used custom colors
+ *customColors;
+
+ GBool haveTextClip; // set if text has been drawn with a
+ // clipping render mode
+
+ GBool inType3Char; // inside a Type 3 CharProc
+ GString *t3String; // Type 3 content string
+ double t3WX, t3WY, // Type 3 character parameters
+ t3LLX, t3LLY, t3URX, t3URY;
+ GBool t3Cacheable; // cleared if char is not cacheable
+ GBool t3NeedsRestore; // set if a 'q' operator was issued
+ GBool forceRasterize; // forces the page to be rasterized
+
+#if OPI_SUPPORT
+ int opi13Nest; // nesting level of OPI 1.3 objects
+ int opi20Nest; // nesting level of OPI 2.0 objects
+#endif
+
+ GBool ok; // set up ok?
+
+
+ friend class WinPDFPrinter;
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/PSTokenizer.cc b/kpdf/xpdf/xpdf/PSTokenizer.cc
new file mode 100644
index 00000000..a959cc73
--- /dev/null
+++ b/kpdf/xpdf/xpdf/PSTokenizer.cc
@@ -0,0 +1,135 @@
+//========================================================================
+//
+// PSTokenizer.cc
+//
+// Copyright 2002-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "PSTokenizer.h"
+
+//------------------------------------------------------------------------
+
+// A '1' in this array means the character is white space. A '1' or
+// '2' means the character ends a name or command.
+static char PSTokenizer_specialChars[256] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x
+ 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx
+};
+
+//------------------------------------------------------------------------
+
+PSTokenizer::PSTokenizer(int (*getCharFuncA)(void *), void *dataA) {
+ getCharFunc = getCharFuncA;
+ data = dataA;
+ charBuf = -1;
+}
+
+PSTokenizer::~PSTokenizer() {
+}
+
+GBool PSTokenizer::getToken(char *buf, int size, int *length) {
+ GBool comment, backslash;
+ int c;
+ int i;
+
+ // skip whitespace and comments
+ comment = gFalse;
+ while (1) {
+ if ((c = getChar()) == EOF) {
+ buf[0] = '\0';
+ *length = 0;
+ return gFalse;
+ }
+ if (comment) {
+ if (c == '\x0a' || c == '\x0d') {
+ comment = gFalse;
+ }
+ } else if (c == '%') {
+ comment = gTrue;
+ } else if (PSTokenizer_specialChars[c] != 1) {
+ break;
+ }
+ }
+
+ // read a token
+ i = 0;
+ buf[i++] = c;
+ if (c == '(') {
+ backslash = gFalse;
+ while ((c = lookChar()) != EOF) {
+ if (i < size - 1) {
+ buf[i++] = c;
+ }
+ getChar();
+ if (c == '\\') {
+ backslash = gTrue;
+ } else if (!backslash && c == ')') {
+ break;
+ } else {
+ backslash = gFalse;
+ }
+ }
+ } else if (c == '<') {
+ while ((c = lookChar()) != EOF) {
+ getChar();
+ if (i < size - 1 && PSTokenizer_specialChars[c] != 1) {
+ buf[i++] = c;
+ }
+ if (c == '>') {
+ break;
+ }
+ }
+ } else if (c != '[' && c != ']') {
+ while ((c = lookChar()) != EOF && !PSTokenizer_specialChars[c]) {
+ getChar();
+ if (i < size - 1) {
+ buf[i++] = c;
+ }
+ }
+ }
+ buf[i] = '\0';
+ *length = i;
+
+ return gTrue;
+}
+
+int PSTokenizer::lookChar() {
+ if (charBuf < 0) {
+ charBuf = (*getCharFunc)(data);
+ }
+ return charBuf;
+}
+
+int PSTokenizer::getChar() {
+ int c;
+
+ if (charBuf < 0) {
+ charBuf = (*getCharFunc)(data);
+ }
+ c = charBuf;
+ charBuf = -1;
+ return c;
+}
diff --git a/kpdf/xpdf/xpdf/PSTokenizer.h b/kpdf/xpdf/xpdf/PSTokenizer.h
new file mode 100644
index 00000000..4d5ee97f
--- /dev/null
+++ b/kpdf/xpdf/xpdf/PSTokenizer.h
@@ -0,0 +1,41 @@
+//========================================================================
+//
+// PSTokenizer.h
+//
+// Copyright 2002-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef PSTOKENIZER_H
+#define PSTOKENIZER_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+
+//------------------------------------------------------------------------
+
+class PSTokenizer {
+public:
+
+ PSTokenizer(int (*getCharFuncA)(void *), void *dataA);
+ ~PSTokenizer();
+
+ // Get the next PostScript token. Returns false at end-of-stream.
+ GBool getToken(char *buf, int size, int *length);
+
+private:
+
+ int lookChar();
+ int getChar();
+
+ int (*getCharFunc)(void *);
+ void *data;
+ int charBuf;
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/Page.cc b/kpdf/xpdf/xpdf/Page.cc
new file mode 100644
index 00000000..cfeab88b
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Page.cc
@@ -0,0 +1,558 @@
+//========================================================================
+//
+// Page.cc
+//
+// Copyright 1996-2007 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stddef.h>
+#include "GlobalParams.h"
+#include "Object.h"
+#include "Array.h"
+#include "Dict.h"
+#include "XRef.h"
+#include "Link.h"
+#include "OutputDev.h"
+#ifndef PDF_PARSER_ONLY
+#include "Gfx.h"
+#include "GfxState.h"
+#include "Annot.h"
+#endif
+#include "Error.h"
+#include "Catalog.h"
+#include "Page.h"
+
+//------------------------------------------------------------------------
+// PDFRectangle
+//------------------------------------------------------------------------
+
+void PDFRectangle::clipTo(PDFRectangle *rect) {
+ if (x1 < rect->x1) {
+ x1 = rect->x1;
+ } else if (x1 > rect->x2) {
+ x1 = rect->x2;
+ }
+ if (x2 < rect->x1) {
+ x2 = rect->x1;
+ } else if (x2 > rect->x2) {
+ x2 = rect->x2;
+ }
+ if (y1 < rect->y1) {
+ y1 = rect->y1;
+ } else if (y1 > rect->y2) {
+ y1 = rect->y2;
+ }
+ if (y2 < rect->y1) {
+ y2 = rect->y1;
+ } else if (y2 > rect->y2) {
+ y2 = rect->y2;
+ }
+}
+
+//------------------------------------------------------------------------
+// PageAttrs
+//------------------------------------------------------------------------
+
+PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) {
+ Object obj1;
+
+ // get old/default values
+ if (attrs) {
+ mediaBox = attrs->mediaBox;
+ cropBox = attrs->cropBox;
+ haveCropBox = attrs->haveCropBox;
+ rotate = attrs->rotate;
+ attrs->resources.copy(&resources);
+ } else {
+ // set default MediaBox to 8.5" x 11" -- this shouldn't be necessary
+ // but some (non-compliant) PDF files don't specify a MediaBox
+ mediaBox.x1 = 0;
+ mediaBox.y1 = 0;
+ mediaBox.x2 = 612;
+ mediaBox.y2 = 792;
+ cropBox.x1 = cropBox.y1 = cropBox.x2 = cropBox.y2 = 0;
+ haveCropBox = gFalse;
+ rotate = 0;
+ resources.initNull();
+ }
+
+ // media box
+ readBox(dict, "MediaBox", &mediaBox);
+
+ // crop box
+ if (readBox(dict, "CropBox", &cropBox)) {
+ haveCropBox = gTrue;
+ }
+ if (!haveCropBox) {
+ cropBox = mediaBox;
+ }
+ else
+ {
+ // cropBox can not be bigger than mediaBox
+ if (cropBox.x2 - cropBox.x1 > mediaBox.x2 - mediaBox.x1)
+ {
+ cropBox.x1 = mediaBox.x1;
+ cropBox.x2 = mediaBox.x2;
+ }
+ if (cropBox.y2 - cropBox.y1 > mediaBox.y2 - mediaBox.y1)
+ {
+ cropBox.y1 = mediaBox.y1;
+ cropBox.y2 = mediaBox.y2;
+ }
+ }
+
+ // other boxes
+ bleedBox = cropBox;
+ readBox(dict, "BleedBox", &bleedBox);
+ trimBox = cropBox;
+ readBox(dict, "TrimBox", &trimBox);
+ artBox = cropBox;
+ readBox(dict, "ArtBox", &artBox);
+
+ // clip all other boxes to the media box
+ cropBox.clipTo(&mediaBox);
+ bleedBox.clipTo(&mediaBox);
+ trimBox.clipTo(&mediaBox);
+ artBox.clipTo(&mediaBox);
+
+ // rotate
+ dict->lookup("Rotate", &obj1);
+ if (obj1.isInt()) {
+ rotate = obj1.getInt();
+ }
+ obj1.free();
+ while (rotate < 0) {
+ rotate += 360;
+ }
+ while (rotate >= 360) {
+ rotate -= 360;
+ }
+
+ // misc attributes
+ dict->lookup("LastModified", &lastModified);
+ dict->lookup("BoxColorInfo", &boxColorInfo);
+ dict->lookup("Group", &group);
+ dict->lookup("Metadata", &metadata);
+ dict->lookup("PieceInfo", &pieceInfo);
+ dict->lookup("SeparationInfo", &separationInfo);
+
+ // resource dictionary
+ dict->lookup("Resources", &obj1);
+ if (obj1.isDict()) {
+ resources.free();
+ obj1.copy(&resources);
+ }
+ obj1.free();
+}
+
+PageAttrs::~PageAttrs() {
+ lastModified.free();
+ boxColorInfo.free();
+ group.free();
+ metadata.free();
+ pieceInfo.free();
+ separationInfo.free();
+ resources.free();
+}
+
+GBool PageAttrs::readBox(Dict *dict, char *key, PDFRectangle *box) {
+ PDFRectangle tmp;
+ double t;
+ Object obj1, obj2;
+ GBool ok;
+
+ dict->lookup(key, &obj1);
+ if (obj1.isArray() && obj1.arrayGetLength() == 4) {
+ ok = gTrue;
+ obj1.arrayGet(0, &obj2);
+ if (obj2.isNum()) {
+ tmp.x1 = obj2.getNum();
+ } else {
+ ok = gFalse;
+ }
+ obj2.free();
+ obj1.arrayGet(1, &obj2);
+ if (obj2.isNum()) {
+ tmp.y1 = obj2.getNum();
+ } else {
+ ok = gFalse;
+ }
+ obj2.free();
+ obj1.arrayGet(2, &obj2);
+ if (obj2.isNum()) {
+ tmp.x2 = obj2.getNum();
+ } else {
+ ok = gFalse;
+ }
+ obj2.free();
+ obj1.arrayGet(3, &obj2);
+ if (obj2.isNum()) {
+ tmp.y2 = obj2.getNum();
+ } else {
+ ok = gFalse;
+ }
+ obj2.free();
+ if (ok) {
+ if (tmp.x1 > tmp.x2) {
+ t = tmp.x1; tmp.x1 = tmp.x2; tmp.x2 = t;
+ }
+ if (tmp.y1 > tmp.y2) {
+ t = tmp.y1; tmp.y1 = tmp.y2; tmp.y2 = t;
+ }
+ *box = tmp;
+ }
+ } else {
+ ok = gFalse;
+ }
+ obj1.free();
+ return ok;
+}
+
+//------------------------------------------------------------------------
+// PageTransition
+//------------------------------------------------------------------------
+
+PageTransition::PageTransition(Dict *dict)
+ : type(Replace),
+ duration(1),
+ alignment(Horizontal),
+ direction(Inward),
+ angle(0),
+ scale(1.0),
+ rectangular(false)
+{
+ Object dictObj;
+ Object obj;
+
+ dict->lookup("Trans", &dictObj);
+ if (dictObj.isDict()) {
+ Dict *transDict = dictObj.getDict();
+
+ if (transDict->lookup("S", &obj)->isName()) {
+ const char *s = obj.getName();
+ if (strcmp("R", s) == 0)
+ type = Replace;
+ else if (strcmp("Split", s) == 0)
+ type = Split;
+ else if (strcmp("Blinds", s) == 0)
+ type = Blinds;
+ else if (strcmp("Box", s) == 0)
+ type = Box;
+ else if (strcmp("Wipe", s) == 0)
+ type = Wipe;
+ else if (strcmp("Dissolve", s) == 0)
+ type = Dissolve;
+ else if (strcmp("Glitter", s) == 0)
+ type = Glitter;
+ else if (strcmp("Fly", s) == 0)
+ type = Fly;
+ else if (strcmp("Push", s) == 0)
+ type = Push;
+ else if (strcmp("Cover", s) == 0)
+ type = Cover;
+ else if (strcmp("Uncover", s) == 0)
+ type = Push;
+ else if (strcmp("Fade", s) == 0)
+ type = Cover;
+ }
+ obj.free();
+
+ if (transDict->lookup("D", &obj)->isInt()) {
+ duration = obj.getInt();
+ }
+ obj.free();
+
+ if (transDict->lookup("Dm", &obj)->isName()) {
+ const char *dm = obj.getName();
+ if ( strcmp( "H", dm ) == 0 )
+ alignment = Horizontal;
+ else if ( strcmp( "V", dm ) == 0 )
+ alignment = Vertical;
+ }
+ obj.free();
+
+ if (transDict->lookup("M", &obj)->isName()) {
+ const char *m = obj.getName();
+ if ( strcmp( "I", m ) == 0 )
+ direction = Inward;
+ else if ( strcmp( "O", m ) == 0 )
+ direction = Outward;
+ }
+ obj.free();
+
+ if (transDict->lookup("Di", &obj)->isInt()) {
+ angle = obj.getInt();
+ }
+ obj.free();
+
+ if (transDict->lookup("Di", &obj)->isName()) {
+ if ( strcmp( "None", obj.getName() ) == 0 )
+ angle = 0;
+ }
+ obj.free();
+
+ if (transDict->lookup("SS", &obj)->isReal()) {
+ scale = obj.getReal();
+ }
+ obj.free();
+
+ if (transDict->lookup("B", &obj)->isBool()) {
+ rectangular = obj.getBool();
+ }
+ obj.free();
+ }
+ dictObj.free();
+}
+
+PageTransition::~PageTransition() {
+}
+
+//------------------------------------------------------------------------
+// Page
+//------------------------------------------------------------------------
+
+Page::Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA) {
+ ok = gTrue;
+ xref = xrefA;
+ num = numA;
+
+ // get attributes
+ attrs = attrsA;
+
+ // get transition
+ transition = new PageTransition( pageDict );
+
+ // annotations
+ pageDict->lookupNF("Annots", &annots);
+ if (!(annots.isRef() || annots.isArray() || annots.isNull())) {
+ error(-1, "Page annotations object (page %d) is wrong type (%s)",
+ num, annots.getTypeName());
+ annots.free();
+ goto err2;
+ }
+
+ // contents
+ pageDict->lookupNF("Contents", &contents);
+ if (!(contents.isRef() || contents.isArray() ||
+ contents.isNull())) {
+ error(-1, "Page contents object (page %d) is wrong type (%s)",
+ num, contents.getTypeName());
+ contents.free();
+ goto err1;
+ }
+
+ return;
+
+ err2:
+ annots.initNull();
+ err1:
+ contents.initNull();
+ ok = gFalse;
+}
+
+Page::~Page() {
+ delete attrs;
+ delete transition;
+ annots.free();
+ contents.free();
+}
+
+Links *Page::getLinks(Catalog *catalog) {
+ Links *links;
+ Object obj;
+
+ links = new Links(getAnnots(&obj), catalog->getBaseURI());
+ obj.free();
+ return links;
+}
+
+void Page::display(OutputDev *out, double hDPI, double vDPI,
+ int rotate, GBool useMediaBox, GBool crop,
+ GBool printing, Catalog *catalog,
+ GBool (*abortCheckCbk)(void *data),
+ void *abortCheckCbkData) {
+ displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop,
+ -1, -1, -1, -1, printing, catalog,
+ abortCheckCbk, abortCheckCbkData);
+}
+
+void Page::displaySlice(OutputDev *out, double hDPI, double vDPI,
+ int rotate, GBool useMediaBox, GBool crop,
+ int sliceX, int sliceY, int sliceW, int sliceH,
+ GBool printing, Catalog *catalog,
+ GBool (*abortCheckCbk)(void *data),
+ void *abortCheckCbkData) {
+#ifndef PDF_PARSER_ONLY
+ PDFRectangle *mediaBox, *cropBox;
+ PDFRectangle box;
+ Gfx *gfx;
+ Object obj;
+ Annots *annotList;
+ Dict *acroForm;
+ int i;
+
+ if (!out->checkPageSlice(this, hDPI, vDPI, rotate, useMediaBox, crop,
+ sliceX, sliceY, sliceW, sliceH,
+ printing, catalog,
+ abortCheckCbk, abortCheckCbkData)) {
+ return;
+ }
+
+ rotate += getRotate();
+ if (rotate >= 360) {
+ rotate -= 360;
+ } else if (rotate < 0) {
+ rotate += 360;
+ }
+
+ makeBox(hDPI, vDPI, rotate, useMediaBox, out->upsideDown(),
+ sliceX, sliceY, sliceW, sliceH, &box, &crop);
+ cropBox = getCropBox();
+
+ if (globalParams->getPrintCommands()) {
+ mediaBox = getMediaBox();
+ printf("***** MediaBox = ll:%g,%g ur:%g,%g\n",
+ mediaBox->x1, mediaBox->y1, mediaBox->x2, mediaBox->y2);
+ printf("***** CropBox = ll:%g,%g ur:%g,%g\n",
+ cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2);
+ printf("***** Rotate = %d\n", attrs->getRotate());
+ }
+
+ gfx = new Gfx(xref, out, num, attrs->getResourceDict(),
+ hDPI, vDPI, &box, crop ? cropBox : (PDFRectangle *)NULL,
+ rotate, abortCheckCbk, abortCheckCbkData);
+ contents.fetch(xref, &obj);
+ if (!obj.isNull()) {
+ gfx->saveState();
+ gfx->display(&obj);
+ gfx->restoreState();
+ }
+ obj.free();
+
+ // draw annotations
+ annotList = new Annots(xref, catalog, getAnnots(&obj));
+ obj.free();
+ acroForm = catalog->getAcroForm()->isDict() ?
+ catalog->getAcroForm()->getDict() : NULL;
+ if (acroForm) {
+ if (acroForm->lookup("NeedAppearances", &obj)) {
+ if (obj.isBool() && obj.getBool()) {
+ annotList->generateAppearances(acroForm);
+ }
+ }
+ obj.free();
+ }
+ if (annotList->getNumAnnots() > 0) {
+ if (globalParams->getPrintCommands()) {
+ printf("***** Annotations\n");
+ }
+ for (i = 0; i < annotList->getNumAnnots(); ++i) {
+ annotList->getAnnot(i)->draw(gfx, printing);
+ }
+ out->dump();
+ }
+ delete annotList;
+
+ delete gfx;
+#endif
+}
+
+void Page::makeBox(double hDPI, double vDPI, int rotate,
+ GBool useMediaBox, GBool upsideDown,
+ double sliceX, double sliceY, double sliceW, double sliceH,
+ PDFRectangle *box, GBool *crop) {
+ PDFRectangle *mediaBox, *cropBox, *baseBox;
+ double kx, ky;
+
+ mediaBox = getMediaBox();
+ cropBox = getCropBox();
+ if (sliceW >= 0 && sliceH >= 0) {
+ baseBox = useMediaBox ? mediaBox : cropBox;
+ kx = 72.0 / hDPI;
+ ky = 72.0 / vDPI;
+ if (rotate == 90) {
+ if (upsideDown) {
+ box->x1 = baseBox->x1 + ky * sliceY;
+ box->x2 = baseBox->x1 + ky * (sliceY + sliceH);
+ } else {
+ box->x1 = baseBox->x2 - ky * (sliceY + sliceH);
+ box->x2 = baseBox->x2 - ky * sliceY;
+ }
+ box->y1 = baseBox->y1 + kx * sliceX;
+ box->y2 = baseBox->y1 + kx * (sliceX + sliceW);
+ } else if (rotate == 180) {
+ box->x1 = baseBox->x2 - kx * (sliceX + sliceW);
+ box->x2 = baseBox->x2 - kx * sliceX;
+ if (upsideDown) {
+ box->y1 = baseBox->y1 + ky * sliceY;
+ box->y2 = baseBox->y1 + ky * (sliceY + sliceH);
+ } else {
+ box->y1 = baseBox->y2 - ky * (sliceY + sliceH);
+ box->y2 = baseBox->y2 - ky * sliceY;
+ }
+ } else if (rotate == 270) {
+ if (upsideDown) {
+ box->x1 = baseBox->x2 - ky * (sliceY + sliceH);
+ box->x2 = baseBox->x2 - ky * sliceY;
+ } else {
+ box->x1 = baseBox->x1 + ky * sliceY;
+ box->x2 = baseBox->x1 + ky * (sliceY + sliceH);
+ }
+ box->y1 = baseBox->y2 - kx * (sliceX + sliceW);
+ box->y2 = baseBox->y2 - kx * sliceX;
+ } else {
+ box->x1 = baseBox->x1 + kx * sliceX;
+ box->x2 = baseBox->x1 + kx * (sliceX + sliceW);
+ if (upsideDown) {
+ box->y1 = baseBox->y2 - ky * (sliceY + sliceH);
+ box->y2 = baseBox->y2 - ky * sliceY;
+ } else {
+ box->y1 = baseBox->y1 + ky * sliceY;
+ box->y2 = baseBox->y1 + ky * (sliceY + sliceH);
+ }
+ }
+ } else if (useMediaBox) {
+ *box = *mediaBox;
+ } else {
+ *box = *cropBox;
+ *crop = gFalse;
+ }
+}
+
+void Page::processLinks(OutputDev *out, Catalog *catalog) {
+ Links *links;
+ int i;
+
+ links = getLinks(catalog);
+ for (i = 0; i < links->getNumLinks(); ++i) {
+ out->processLink(links->getLink(i), catalog);
+ }
+ delete links;
+}
+
+void Page::getDefaultCTM(double *ctm, double hDPI, double vDPI,
+ int rotate, GBool useMediaBox, GBool upsideDown) {
+ GfxState *state;
+ int i;
+
+ rotate += getRotate();
+ if (rotate >= 360) {
+ rotate -= 360;
+ } else if (rotate < 0) {
+ rotate += 360;
+ }
+ state = new GfxState(hDPI, vDPI,
+ useMediaBox ? getMediaBox() : getCropBox(),
+ rotate, upsideDown);
+ for (i = 0; i < 6; ++i) {
+ ctm[i] = state->getCTM()[i];
+ }
+ delete state;
+}
diff --git a/kpdf/xpdf/xpdf/Page.h b/kpdf/xpdf/xpdf/Page.h
new file mode 100644
index 00000000..111554c7
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Page.h
@@ -0,0 +1,259 @@
+//========================================================================
+//
+// Page.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef PAGE_H
+#define PAGE_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "Object.h"
+
+class Dict;
+class XRef;
+class OutputDev;
+class Links;
+class Catalog;
+
+//------------------------------------------------------------------------
+
+class PDFRectangle {
+public:
+ double x1, y1, x2, y2;
+
+ PDFRectangle() { x1 = y1 = x2 = y2 = 0; }
+ PDFRectangle(double x1A, double y1A, double x2A, double y2A)
+ { x1 = x1A; y1 = y1A; x2 = x2A; y2 = y2A; }
+ GBool isValid() { return x1 != 0 || y1 != 0 || x2 != 0 || y2 != 0; }
+ void clipTo(PDFRectangle *rect);
+};
+
+//------------------------------------------------------------------------
+// PageAttrs
+//------------------------------------------------------------------------
+
+class PageAttrs {
+public:
+
+ // Construct a new PageAttrs object by merging a dictionary
+ // (of type Pages or Page) into another PageAttrs object. If
+ // <attrs> is NULL, uses defaults.
+ PageAttrs(PageAttrs *attrs, Dict *dict);
+
+ // Destructor.
+ ~PageAttrs();
+
+ // Accessors.
+ PDFRectangle *getMediaBox() { return &mediaBox; }
+ PDFRectangle *getCropBox() { return &cropBox; }
+ GBool isCropped() { return haveCropBox; }
+ PDFRectangle *getBleedBox() { return &bleedBox; }
+ PDFRectangle *getTrimBox() { return &trimBox; }
+ PDFRectangle *getArtBox() { return &artBox; }
+ int getRotate() { return rotate; }
+ GString *getLastModified()
+ { return lastModified.isString()
+ ? lastModified.getString() : (GString *)NULL; }
+ Dict *getBoxColorInfo()
+ { return boxColorInfo.isDict() ? boxColorInfo.getDict() : (Dict *)NULL; }
+ Dict *getGroup()
+ { return group.isDict() ? group.getDict() : (Dict *)NULL; }
+ Stream *getMetadata()
+ { return metadata.isStream() ? metadata.getStream() : (Stream *)NULL; }
+ Dict *getPieceInfo()
+ { return pieceInfo.isDict() ? pieceInfo.getDict() : (Dict *)NULL; }
+ Dict *getSeparationInfo()
+ { return separationInfo.isDict()
+ ? separationInfo.getDict() : (Dict *)NULL; }
+ Dict *getResourceDict()
+ { return resources.isDict() ? resources.getDict() : (Dict *)NULL; }
+
+private:
+
+ GBool readBox(Dict *dict, char *key, PDFRectangle *box);
+
+ PDFRectangle mediaBox;
+ PDFRectangle cropBox;
+ GBool haveCropBox;
+ PDFRectangle bleedBox;
+ PDFRectangle trimBox;
+ PDFRectangle artBox;
+ int rotate;
+ Object lastModified;
+ Object boxColorInfo;
+ Object group;
+ Object metadata;
+ Object pieceInfo;
+ Object separationInfo;
+ Object resources;
+};
+
+//------------------------------------------------------------------------
+// PageTransition
+//------------------------------------------------------------------------
+class PageTransition {
+public:
+ enum Type {
+ Replace,
+ Split,
+ Blinds,
+ Box,
+ Wipe,
+ Dissolve,
+ Glitter,
+ Fly,
+ Push,
+ Cover,
+ Uncover,
+ Fade
+ };
+
+ enum Alignment {
+ Horizontal,
+ Vertical
+ };
+
+ enum Direction {
+ Inward,
+ Outward
+ };
+
+ // Construct a new PageTransition object from a page dictionary.
+ PageTransition( Dict *dict );
+
+ // Destructor
+ ~PageTransition();
+
+ // Get type of the transition.
+ Type getType() const { return type; }
+
+ // Get duration of the transition in seconds.
+ int getDuration() const { return duration; }
+
+ // Get dimension in which the transition effect
+ // occurs.
+ Alignment getAlignment() const { return alignment; }
+
+ // Get direction of motion of the transition effect.
+ Direction getDirection() const { return direction; }
+
+ // Get direction in which the transition effect moves.
+ int getAngle() const { return angle; }
+
+ // Get starting or ending scale.
+ double getScale() const { return scale; }
+
+ // Returns true if the area to be flown is rectangular and
+ // opaque.
+ GBool isRectangular() const { return rectangular; }
+private:
+ Type type;
+ int duration;
+ Alignment alignment;
+ Direction direction;
+ int angle;
+ double scale;
+ GBool rectangular;
+};
+
+//------------------------------------------------------------------------
+// Page
+//------------------------------------------------------------------------
+
+class Page {
+public:
+
+ // Constructor.
+ Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA);
+
+ // Destructor.
+ ~Page();
+
+ // Is page valid?
+ GBool isOk() { return ok; }
+
+ // Get page parameters.
+ int getNum() { return num; }
+ PDFRectangle *getMediaBox() { return attrs->getMediaBox(); }
+ PDFRectangle *getCropBox() { return attrs->getCropBox(); }
+ GBool isCropped() { return attrs->isCropped(); }
+ double getMediaWidth()
+ { return attrs->getMediaBox()->x2 - attrs->getMediaBox()->x1; }
+ double getMediaHeight()
+ { return attrs->getMediaBox()->y2 - attrs->getMediaBox()->y1; }
+ double getCropWidth()
+ { return attrs->getCropBox()->x2 - attrs->getCropBox()->x1; }
+ double getCropHeight()
+ { return attrs->getCropBox()->y2 - attrs->getCropBox()->y1; }
+ PDFRectangle *getBleedBox() { return attrs->getBleedBox(); }
+ PDFRectangle *getTrimBox() { return attrs->getTrimBox(); }
+ PDFRectangle *getArtBox() { return attrs->getArtBox(); }
+ int getRotate() { return attrs->getRotate(); }
+ GString *getLastModified() { return attrs->getLastModified(); }
+ Dict *getBoxColorInfo() { return attrs->getBoxColorInfo(); }
+ Dict *getGroup() { return attrs->getGroup(); }
+ Stream *getMetadata() { return attrs->getMetadata(); }
+ Dict *getPieceInfo() { return attrs->getPieceInfo(); }
+ Dict *getSeparationInfo() { return attrs->getSeparationInfo(); }
+
+ // Get resource dictionary.
+ Dict *getResourceDict() { return attrs->getResourceDict(); }
+
+ // Get annotations array.
+ Object *getAnnots(Object *obj) { return annots.fetch(xref, obj); }
+
+ // Return a list of links.
+ Links *getLinks(Catalog *catalog);
+
+ // Get contents.
+ Object *getContents(Object *obj) { return contents.fetch(xref, obj); }
+
+ // Get transition information.
+ PageTransition *getTransition() const { return transition; }
+
+ // Display a page.
+ void display(OutputDev *out, double hDPI, double vDPI,
+ int rotate, GBool useMediaBox, GBool crop,
+ GBool printing, Catalog *catalog,
+ GBool (*abortCheckCbk)(void *data) = NULL,
+ void *abortCheckCbkData = NULL);
+
+ // Display part of a page.
+ void displaySlice(OutputDev *out, double hDPI, double vDPI,
+ int rotate, GBool useMediaBox, GBool crop,
+ int sliceX, int sliceY, int sliceW, int sliceH,
+ GBool printing, Catalog *catalog,
+ GBool (*abortCheckCbk)(void *data) = NULL,
+ void *abortCheckCbkData = NULL);
+
+ void makeBox(double hDPI, double vDPI, int rotate,
+ GBool useMediaBox, GBool upsideDown,
+ double sliceX, double sliceY, double sliceW, double sliceH,
+ PDFRectangle *box, GBool *crop);
+
+ void processLinks(OutputDev *out, Catalog *catalog);
+
+ // Get the page's default CTM.
+ void getDefaultCTM(double *ctm, double hDPI, double vDPI,
+ int rotate, GBool useMediaBox, GBool upsideDown);
+
+private:
+
+ XRef *xref; // the xref table for this PDF file
+ int num; // page number
+ PageAttrs *attrs; // page attributes
+ PageTransition *transition; // page transition
+ Object annots; // annotations array
+ Object contents; // page contents
+ GBool ok; // true if page is valid
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/Parser.cc b/kpdf/xpdf/xpdf/Parser.cc
new file mode 100644
index 00000000..65a43d94
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Parser.cc
@@ -0,0 +1,227 @@
+//========================================================================
+//
+// Parser.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stddef.h>
+#include "Object.h"
+#include "Array.h"
+#include "Dict.h"
+#include "Decrypt.h"
+#include "Parser.h"
+#include "XRef.h"
+#include "Error.h"
+
+Parser::Parser(XRef *xrefA, Lexer *lexerA, GBool allowStreamsA) {
+ xref = xrefA;
+ lexer = lexerA;
+ inlineImg = 0;
+ allowStreams = allowStreamsA;
+ lexer->getObj(&buf1);
+ lexer->getObj(&buf2);
+}
+
+Parser::~Parser() {
+ buf1.free();
+ buf2.free();
+ delete lexer;
+}
+
+Object *Parser::getObj(Object *obj, Guchar *fileKey,
+ CryptAlgorithm encAlgorithm, int keyLength,
+ int objNum, int objGen) {
+ char *key;
+ Stream *str;
+ Object obj2;
+ int num;
+ DecryptStream *decrypt;
+ GString *s, *s2;
+ int c;
+
+ // refill buffer after inline image data
+ if (inlineImg == 2) {
+ buf1.free();
+ buf2.free();
+ lexer->getObj(&buf1);
+ lexer->getObj(&buf2);
+ inlineImg = 0;
+ }
+
+ // array
+ if (buf1.isCmd("[")) {
+ shift();
+ obj->initArray(xref);
+ while (!buf1.isCmd("]") && !buf1.isEOF())
+ obj->arrayAdd(getObj(&obj2, fileKey, encAlgorithm, keyLength,
+ objNum, objGen));
+ if (buf1.isEOF())
+ error(getPos(), "End of file inside array");
+ shift();
+
+ // dictionary or stream
+ } else if (buf1.isCmd("<<")) {
+ shift(objNum);
+ obj->initDict(xref);
+ while (!buf1.isCmd(">>") && !buf1.isEOF()) {
+ if (!buf1.isName()) {
+ error(getPos(), "Dictionary key must be a name object");
+ shift();
+ } else {
+ key = copyString(buf1.getName());
+ shift();
+ if (buf1.isEOF() || buf1.isError()) {
+ gfree(key);
+ break;
+ }
+ obj->dictAdd(key, getObj(&obj2, fileKey, encAlgorithm, keyLength,
+ objNum, objGen));
+ }
+ }
+ if (buf1.isEOF())
+ error(getPos(), "End of file inside dictionary");
+ // stream objects are not allowed inside content streams or
+ // object streams
+ if (allowStreams && buf2.isCmd("stream")) {
+ if ((str = makeStream(obj, fileKey, encAlgorithm, keyLength,
+ objNum, objGen))) {
+ obj->initStream(str);
+ } else {
+ obj->free();
+ obj->initError();
+ }
+ } else {
+ shift();
+ }
+
+ // indirect reference or integer
+ } else if (buf1.isInt()) {
+ num = buf1.getInt();
+ shift();
+ if (buf1.isInt() && buf2.isCmd("R")) {
+ obj->initRef(num, buf1.getInt());
+ shift();
+ shift();
+ } else {
+ obj->initInt(num);
+ }
+
+ // string
+ } else if (buf1.isString() && fileKey) {
+ s = buf1.getString();
+ s2 = new GString();
+ obj2.initNull();
+ decrypt = new DecryptStream(new MemStream(s->getCString(), 0,
+ s->getLength(), &obj2),
+ fileKey, encAlgorithm, keyLength,
+ objNum, objGen);
+ decrypt->reset();
+ while ((c = decrypt->getChar()) != EOF) {
+ s2->append((char)c);
+ }
+ delete decrypt;
+ obj->initString(s2);
+ shift();
+
+ // simple object
+ } else {
+ buf1.copy(obj);
+ shift();
+ }
+
+ return obj;
+}
+
+Stream *Parser::makeStream(Object *dict, Guchar *fileKey,
+ CryptAlgorithm encAlgorithm, int keyLength,
+ int objNum, int objGen) {
+ Object obj;
+ BaseStream *baseStr;
+ Stream *str;
+ Guint pos, endPos, length;
+
+ // get stream start position
+ lexer->skipToNextLine();
+ pos = lexer->getPos();
+
+ // get length
+ dict->dictLookup("Length", &obj);
+ if (obj.isInt()) {
+ length = (Guint)obj.getInt();
+ obj.free();
+ } else {
+ error(getPos(), "Bad 'Length' attribute in stream");
+ obj.free();
+ return NULL;
+ }
+
+ // check for length in damaged file
+ if (xref && xref->getStreamEnd(pos, &endPos)) {
+ length = endPos - pos;
+ }
+
+ // in badly damaged PDF files, we can run off the end of the input
+ // stream immediately after the "stream" token
+ if (!lexer->getStream()) {
+ return NULL;
+ }
+ baseStr = lexer->getStream()->getBaseStream();
+
+ // skip over stream data
+ lexer->setPos(pos + length);
+
+ // refill token buffers and check for 'endstream'
+ shift(); // kill '>>'
+ shift(); // kill 'stream'
+ if (buf1.isCmd("endstream")) {
+ shift();
+ } else {
+ error(getPos(), "Missing 'endstream'");
+ // kludge for broken PDF files: just add 5k to the length, and
+ // hope its enough
+ length += 5000;
+ }
+
+ // make base stream
+ str = baseStr->makeSubStream(pos, gTrue, length, dict);
+
+ // handle decryption
+ if (fileKey) {
+ str = new DecryptStream(str, fileKey, encAlgorithm, keyLength,
+ objNum, objGen);
+ }
+
+ // get filters
+ str = str->addFilters(dict);
+
+ return str;
+}
+
+void Parser::shift(int objNum) {
+ if (inlineImg > 0) {
+ if (inlineImg < 2) {
+ ++inlineImg;
+ } else {
+ // in a damaged content stream, if 'ID' shows up in the middle
+ // of a dictionary, we need to reset
+ inlineImg = 0;
+ }
+ } else if (buf2.isCmd("ID")) {
+ lexer->skipChar(); // skip char after 'ID' command
+ inlineImg = 1;
+ }
+ buf1.free();
+ buf1 = buf2;
+ if (inlineImg > 0) // don't buffer inline image data
+ buf2.initNull();
+ else
+ lexer->getObj(&buf2, objNum);
+}
diff --git a/kpdf/xpdf/xpdf/Parser.h b/kpdf/xpdf/xpdf/Parser.h
new file mode 100644
index 00000000..1cca9954
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Parser.h
@@ -0,0 +1,59 @@
+//========================================================================
+//
+// Parser.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef PARSER_H
+#define PARSER_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "Lexer.h"
+
+//------------------------------------------------------------------------
+// Parser
+//------------------------------------------------------------------------
+
+class Parser {
+public:
+
+ // Constructor.
+ Parser(XRef *xrefA, Lexer *lexerA, GBool allowStreamsA);
+
+ // Destructor.
+ ~Parser();
+
+ // Get the next object from the input stream.
+ Object *getObj(Object *obj, Guchar *fileKey = NULL,
+ CryptAlgorithm encAlgorithm = cryptRC4, int keyLength = 0,
+ int objNum = 0, int objGen = 0);
+
+ // Get stream.
+ Stream *getStream() { return lexer->getStream(); }
+
+ // Get current position in file.
+ int getPos() { return lexer->getPos(); }
+
+private:
+
+ XRef *xref; // the xref table for this PDF file
+ Lexer *lexer; // input stream
+ GBool allowStreams; // parse stream objects?
+ Object buf1, buf2; // next two tokens
+ int inlineImg; // set when inline image data is encountered
+
+ Stream *makeStream(Object *dict, Guchar *fileKey,
+ CryptAlgorithm encAlgorithm, int keyLength,
+ int objNum, int objGen);
+ void shift(int objNum = -1);
+};
+
+#endif
+
diff --git a/kpdf/xpdf/xpdf/PreScanOutputDev.cc b/kpdf/xpdf/xpdf/PreScanOutputDev.cc
new file mode 100644
index 00000000..52ffeb7f
--- /dev/null
+++ b/kpdf/xpdf/xpdf/PreScanOutputDev.cc
@@ -0,0 +1,257 @@
+//========================================================================
+//
+// PreScanOutputDev.cc
+//
+// Copyright 2005 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <math.h>
+#include "GlobalParams.h"
+#include "GfxFont.h"
+#include "Link.h"
+#include "PreScanOutputDev.h"
+
+//------------------------------------------------------------------------
+// PreScanOutputDev
+//------------------------------------------------------------------------
+
+PreScanOutputDev::PreScanOutputDev() {
+ clearStats();
+}
+
+PreScanOutputDev::~PreScanOutputDev() {
+}
+
+void PreScanOutputDev::startPage(int /*pageNum*/, GfxState * /*state*/) {
+}
+
+void PreScanOutputDev::endPage() {
+}
+
+void PreScanOutputDev::stroke(GfxState *state) {
+ double *dash;
+ int dashLen;
+ double dashStart;
+
+ check(state->getStrokeColorSpace(), state->getStrokeColor(),
+ state->getStrokeOpacity(), state->getBlendMode());
+ state->getLineDash(&dash, &dashLen, &dashStart);
+ if (dashLen != 0) {
+ gdi = gFalse;
+ }
+}
+
+void PreScanOutputDev::fill(GfxState *state) {
+ check(state->getFillColorSpace(), state->getFillColor(),
+ state->getFillOpacity(), state->getBlendMode());
+}
+
+void PreScanOutputDev::eoFill(GfxState *state) {
+ check(state->getFillColorSpace(), state->getFillColor(),
+ state->getFillOpacity(), state->getBlendMode());
+}
+
+void PreScanOutputDev::clip(GfxState * /*state*/) {
+ //~ check for a rectangle "near" the edge of the page;
+ //~ else set gdi to false
+}
+
+void PreScanOutputDev::eoClip(GfxState * /*state*/) {
+ //~ see clip()
+}
+
+void PreScanOutputDev::beginStringOp(GfxState *state) {
+ int render;
+ GfxFont *font;
+ double m11, m12, m21, m22;
+ Ref embRef;
+ DisplayFontParam *dfp;
+ GBool simpleTTF;
+
+ render = state->getRender();
+ if (!(render & 1)) {
+ check(state->getFillColorSpace(), state->getFillColor(),
+ state->getFillOpacity(), state->getBlendMode());
+ }
+ if ((render & 3) == 1 || (render & 3) == 2) {
+ check(state->getStrokeColorSpace(), state->getStrokeColor(),
+ state->getStrokeOpacity(), state->getBlendMode());
+ }
+
+ font = state->getFont();
+ state->getFontTransMat(&m11, &m12, &m21, &m22);
+ simpleTTF = fabs(m11 + m22) < 0.01 &&
+ m11 > 0 &&
+ fabs(m12) < 0.01 &&
+ fabs(m21) < 0.01 &&
+ fabs(state->getHorizScaling() - 1) < 0.001 &&
+ (font->getType() == fontTrueType ||
+ font->getType() == fontTrueTypeOT) &&
+ (font->getEmbeddedFontID(&embRef) ||
+ font->getExtFontFile() ||
+ (font->getName() &&
+ (dfp = globalParams->getDisplayFont(font->getName())) &&
+ dfp->kind == displayFontTT));
+ if (simpleTTF) {
+ //~ need to create a FoFiTrueType object, and check for a Unicode cmap
+ }
+ if (state->getRender() != 0 || !simpleTTF) {
+ gdi = gFalse;
+ }
+}
+
+void PreScanOutputDev::endStringOp(GfxState * /*state*/) {
+}
+
+GBool PreScanOutputDev::beginType3Char(GfxState * /*state*/, double /*x*/, double /*y*/,
+ double /*dx*/, double /*dy*/,
+ CharCode /*code*/, Unicode * /*u*/, int /*uLen*/) {
+ // return false so all Type 3 chars get rendered (no caching)
+ return gFalse;
+}
+
+void PreScanOutputDev::endType3Char(GfxState * /*state*/) {
+}
+
+void PreScanOutputDev::drawImageMask(GfxState *state, Object * /*ref*/, Stream *str,
+ int width, int height, GBool /*invert*/,
+ GBool inlineImg) {
+ int i, j;
+
+ check(state->getFillColorSpace(), state->getFillColor(),
+ state->getFillOpacity(), state->getBlendMode());
+ gdi = gFalse;
+
+ if (inlineImg) {
+ str->reset();
+ j = height * ((width + 7) / 8);
+ for (i = 0; i < j; ++i)
+ str->getChar();
+ str->close();
+ }
+}
+
+void PreScanOutputDev::drawImage(GfxState *state, Object * /*ref*/, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ int * /*maskColors*/, GBool inlineImg) {
+ GfxColorSpace *colorSpace;
+ int i, j;
+
+ colorSpace = colorMap->getColorSpace();
+ if (colorSpace->getMode() == csIndexed) {
+ colorSpace = ((GfxIndexedColorSpace *)colorSpace)->getBase();
+ }
+ if (colorSpace->getMode() != csDeviceGray &&
+ colorSpace->getMode() != csCalGray) {
+ gray = gFalse;
+ }
+ mono = gFalse;
+ if (state->getBlendMode() != gfxBlendNormal) {
+ transparency = gTrue;
+ }
+ gdi = gFalse;
+
+ if (inlineImg) {
+ str->reset();
+ j = height * ((width * colorMap->getNumPixelComps() *
+ colorMap->getBits() + 7) / 8);
+ for (i = 0; i < j; ++i)
+ str->getChar();
+ str->close();
+ }
+}
+
+void PreScanOutputDev::drawMaskedImage(GfxState *state, Object * /*ref*/,
+ Stream * /*str*/,
+ int /*width*/, int /*height*/,
+ GfxImageColorMap *colorMap,
+ Stream * /*maskStr*/,
+ int /*maskWidth*/, int /*maskHeight*/,
+ GBool /*maskInvert*/) {
+ GfxColorSpace *colorSpace;
+
+ colorSpace = colorMap->getColorSpace();
+ if (colorSpace->getMode() == csIndexed) {
+ colorSpace = ((GfxIndexedColorSpace *)colorSpace)->getBase();
+ }
+ if (colorSpace->getMode() != csDeviceGray &&
+ colorSpace->getMode() != csCalGray) {
+ gray = gFalse;
+ }
+ mono = gFalse;
+ if (state->getBlendMode() != gfxBlendNormal) {
+ transparency = gTrue;
+ }
+ gdi = gFalse;
+}
+
+void PreScanOutputDev::drawSoftMaskedImage(GfxState * /*state*/, Object * /*ref*/,
+ Stream * /*str*/,
+ int /*width*/, int /*height*/,
+ GfxImageColorMap *colorMap,
+ Stream * /*maskStr*/,
+ int /*maskWidth*/, int /*maskHeight*/,
+ GfxImageColorMap * /*maskColorMap*/) {
+ GfxColorSpace *colorSpace;
+
+ colorSpace = colorMap->getColorSpace();
+ if (colorSpace->getMode() == csIndexed) {
+ colorSpace = ((GfxIndexedColorSpace *)colorSpace)->getBase();
+ }
+ if (colorSpace->getMode() != csDeviceGray &&
+ colorSpace->getMode() != csCalGray) {
+ gray = gFalse;
+ }
+ mono = gFalse;
+ transparency = gTrue;
+ gdi = gFalse;
+}
+
+void PreScanOutputDev::beginTransparencyGroup(
+ GfxState * /*state*/, double * /*bbox*/,
+ GfxColorSpace * /*blendingColorSpace*/,
+ GBool /*isolated*/, GBool /*knockout*/,
+ GBool /*forSoftMask*/) {
+ transparency = gTrue;
+ gdi = gFalse;
+}
+
+void PreScanOutputDev::check(GfxColorSpace *colorSpace, GfxColor *color,
+ double opacity, GfxBlendMode blendMode) {
+ GfxRGB rgb;
+
+ if (colorSpace->getMode() == csPattern) {
+ mono = gFalse;
+ gray = gFalse;
+ gdi = gFalse;
+ } else {
+ colorSpace->getRGB(color, &rgb);
+ if (rgb.r != rgb.g || rgb.g != rgb.b || rgb.b != rgb.r) {
+ mono = gFalse;
+ gray = gFalse;
+ } else if (!((rgb.r == 0 && rgb.g == 0 && rgb.b == 0) ||
+ (rgb.r == gfxColorComp1 &&
+ rgb.g == gfxColorComp1 &&
+ rgb.b == gfxColorComp1))) {
+ mono = gFalse;
+ }
+ }
+ if (opacity != 1 || blendMode != gfxBlendNormal) {
+ transparency = gTrue;
+ }
+}
+
+void PreScanOutputDev::clearStats() {
+ mono = gTrue;
+ gray = gTrue;
+ transparency = gFalse;
+ gdi = gTrue;
+}
diff --git a/kpdf/xpdf/xpdf/PreScanOutputDev.h b/kpdf/xpdf/xpdf/PreScanOutputDev.h
new file mode 100644
index 00000000..c825ddfc
--- /dev/null
+++ b/kpdf/xpdf/xpdf/PreScanOutputDev.h
@@ -0,0 +1,130 @@
+//========================================================================
+//
+// PreScanOutputDev.h
+//
+// Copyright 2005 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef PRESCANOUTPUTDEV_H
+#define PRESCANOUTPUTDEV_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "GfxState.h"
+#include "OutputDev.h"
+
+//------------------------------------------------------------------------
+// PreScanOutputDev
+//------------------------------------------------------------------------
+
+class PreScanOutputDev: public OutputDev {
+public:
+
+ // Constructor.
+ PreScanOutputDev();
+
+ // Destructor.
+ virtual ~PreScanOutputDev();
+
+ //----- get info about output device
+
+ // Does this device use upside-down coordinates?
+ // (Upside-down means (0,0) is the top left corner of the page.)
+ virtual GBool upsideDown() { return gTrue; }
+
+ // Does this device use drawChar() or drawString()?
+ virtual GBool useDrawChar() { return gTrue; }
+
+ // Does this device use beginType3Char/endType3Char? Otherwise,
+ // text in Type 3 fonts will be drawn with drawChar/drawString.
+ virtual GBool interpretType3Chars() { return gTrue; }
+
+ //----- initialization and control
+
+ // Start a page.
+ virtual void startPage(int pageNum, GfxState *state);
+
+ // End a page.
+ virtual void endPage();
+
+ //----- path painting
+ virtual void stroke(GfxState *state);
+ virtual void fill(GfxState *state);
+ virtual void eoFill(GfxState *state);
+
+ //----- path clipping
+ virtual void clip(GfxState *state);
+ virtual void eoClip(GfxState *state);
+
+ //----- text drawing
+ virtual void beginStringOp(GfxState *state);
+ virtual void endStringOp(GfxState *state);
+ virtual GBool beginType3Char(GfxState *state, double x, double y,
+ double dx, double dy,
+ CharCode code, Unicode *u, int uLen);
+ virtual void endType3Char(GfxState *state);
+
+ //----- image drawing
+ virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool inlineImg);
+ virtual void drawImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GfxImageColorMap *colorMap,
+ int *maskColors, GBool inlineImg);
+ virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ Stream *maskStr, int maskWidth, int maskHeight,
+ GBool maskInvert);
+ virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ Stream *maskStr,
+ int maskWidth, int maskHeight,
+ GfxImageColorMap *maskColorMap);
+
+ //----- transparency groups and soft masks
+ virtual void beginTransparencyGroup(GfxState *state, double *bbox,
+ GfxColorSpace *blendingColorSpace,
+ GBool isolated, GBool knockout,
+ GBool forSoftMask);
+
+ //----- special access
+
+ // Returns true if the operations performed since the last call to
+ // clearStats() are all monochrome (black or white).
+ GBool isMonochrome() { return mono; }
+
+ // Returns true if the operations performed since the last call to
+ // clearStats() are all gray.
+ GBool isGray() { return gray; }
+
+ // Returns true if the operations performed since the last call to
+ // clearStats() included any transparency.
+ GBool usesTransparency() { return transparency; }
+
+ // Returns true if the operations performed since the last call to
+ // clearStats() are all rasterizable by GDI calls in GDIOutputDev.
+ GBool isAllGDI() { return gdi; }
+
+ // Clear the stats used by the above functions.
+ void clearStats();
+
+private:
+
+ void check(GfxColorSpace *colorSpace, GfxColor *color,
+ double opacity, GfxBlendMode blendMode);
+
+ GBool mono;
+ GBool gray;
+ GBool transparency;
+ GBool gdi;
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/SecurityHandler.cc b/kpdf/xpdf/xpdf/SecurityHandler.cc
new file mode 100644
index 00000000..ea0f9341
--- /dev/null
+++ b/kpdf/xpdf/xpdf/SecurityHandler.cc
@@ -0,0 +1,390 @@
+//========================================================================
+//
+// SecurityHandler.cc
+//
+// Copyright 2004 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include "GString.h"
+#include "PDFDoc.h"
+#include "Decrypt.h"
+#include "Error.h"
+#include "GlobalParams.h"
+#if HAVE_XPDFCORE
+# include "XPDFCore.h"
+#elif HAVE_WINPDFCORE
+# include "WinPDFCore.h"
+#endif
+#ifdef ENABLE_PLUGINS
+# include "XpdfPluginAPI.h"
+#endif
+#include "SecurityHandler.h"
+
+//------------------------------------------------------------------------
+// SecurityHandler
+//------------------------------------------------------------------------
+
+SecurityHandler *SecurityHandler::make(PDFDoc *docA, Object *encryptDictA) {
+ Object filterObj;
+ SecurityHandler *secHdlr;
+#ifdef ENABLE_PLUGINS
+ XpdfSecurityHandler *xsh;
+#endif
+
+ encryptDictA->dictLookup("Filter", &filterObj);
+ if (filterObj.isName("Standard")) {
+ secHdlr = new StandardSecurityHandler(docA, encryptDictA);
+ } else if (filterObj.isName()) {
+#ifdef ENABLE_PLUGINS
+ if ((xsh = globalParams->getSecurityHandler(filterObj.getName()))) {
+ secHdlr = new ExternalSecurityHandler(docA, encryptDictA, xsh);
+ } else {
+#endif
+ error(-1, "Couldn't find the '%s' security handler",
+ filterObj.getName());
+ secHdlr = NULL;
+#ifdef ENABLE_PLUGINS
+ }
+#endif
+ } else {
+ error(-1, "Missing or invalid 'Filter' entry in encryption dictionary");
+ secHdlr = NULL;
+ }
+ filterObj.free();
+ return secHdlr;
+}
+
+SecurityHandler::SecurityHandler(PDFDoc *docA) {
+ doc = docA;
+}
+
+SecurityHandler::~SecurityHandler() {
+}
+
+GBool SecurityHandler::checkEncryption(GString *ownerPassword,
+ GString *userPassword) {
+ void *authData;
+ GBool ok;
+ int i;
+
+ if (ownerPassword || userPassword) {
+ authData = makeAuthData(ownerPassword, userPassword);
+ } else {
+ authData = NULL;
+ }
+ ok = authorize(authData);
+ if (authData) {
+ freeAuthData(authData);
+ }
+ for (i = 0; !ok && i < 3; ++i) {
+ if (!(authData = getAuthData())) {
+ break;
+ }
+ ok = authorize(authData);
+ if (authData) {
+ freeAuthData(authData);
+ }
+ }
+ if (!ok) {
+ error(-1, "Incorrect password");
+ }
+ return ok;
+}
+
+//------------------------------------------------------------------------
+// StandardSecurityHandler
+//------------------------------------------------------------------------
+
+class StandardAuthData {
+public:
+
+ StandardAuthData(GString *ownerPasswordA, GString *userPasswordA) {
+ ownerPassword = ownerPasswordA;
+ userPassword = userPasswordA;
+ }
+
+ ~StandardAuthData() {
+ if (ownerPassword) {
+ delete ownerPassword;
+ }
+ if (userPassword) {
+ delete userPassword;
+ }
+ }
+
+ GString *ownerPassword;
+ GString *userPassword;
+};
+
+StandardSecurityHandler::StandardSecurityHandler(PDFDoc *docA,
+ Object *encryptDictA):
+ SecurityHandler(docA)
+{
+ Object versionObj, revisionObj, lengthObj;
+ Object ownerKeyObj, userKeyObj, permObj, fileIDObj;
+ Object fileIDObj1;
+ Object cryptFiltersObj, streamFilterObj, stringFilterObj;
+ Object cryptFilterObj, cfmObj, cfLengthObj;
+ Object encryptMetadataObj;
+
+ ok = gFalse;
+ fileID = NULL;
+ ownerKey = NULL;
+ userKey = NULL;
+
+ encryptDictA->dictLookup("V", &versionObj);
+ encryptDictA->dictLookup("R", &revisionObj);
+ encryptDictA->dictLookup("Length", &lengthObj);
+ encryptDictA->dictLookup("O", &ownerKeyObj);
+ encryptDictA->dictLookup("U", &userKeyObj);
+ encryptDictA->dictLookup("P", &permObj);
+ doc->getXRef()->getTrailerDict()->dictLookup("ID", &fileIDObj);
+ if (versionObj.isInt() &&
+ revisionObj.isInt() &&
+ ownerKeyObj.isString() && ownerKeyObj.getString()->getLength() == 32 &&
+ userKeyObj.isString() && userKeyObj.getString()->getLength() == 32 &&
+ permObj.isInt()) {
+ encVersion = versionObj.getInt();
+ encRevision = revisionObj.getInt();
+ encAlgorithm = cryptRC4;
+ // revision 2 forces a 40-bit key - some buggy PDF generators
+ // set the Length value incorrectly
+ if (encRevision == 2 || !lengthObj.isInt()) {
+ fileKeyLength = 5;
+ } else {
+ fileKeyLength = lengthObj.getInt() / 8;
+ }
+ encryptMetadata = gTrue;
+ //~ this currently only handles a subset of crypt filter functionality
+ if (encVersion == 4 && encRevision == 4) {
+ encryptDictA->dictLookup("CF", &cryptFiltersObj);
+ encryptDictA->dictLookup("StmF", &streamFilterObj);
+ encryptDictA->dictLookup("StrF", &stringFilterObj);
+ if (cryptFiltersObj.isDict() &&
+ streamFilterObj.isName() &&
+ stringFilterObj.isName() &&
+ !strcmp(streamFilterObj.getName(), stringFilterObj.getName())) {
+ if (cryptFiltersObj.dictLookup(streamFilterObj.getName(),
+ &cryptFilterObj)->isDict()) {
+ cryptFilterObj.dictLookup("CFM", &cfmObj);
+ if (cfmObj.isName("V2")) {
+ encVersion = 2;
+ encRevision = 3;
+ if (cryptFilterObj.dictLookup("Length", &cfLengthObj)->isInt()) {
+ //~ according to the spec, this should be cfLengthObj / 8
+ fileKeyLength = cfLengthObj.getInt();
+ }
+ cfLengthObj.free();
+ } else if (cfmObj.isName("AESV2")) {
+ encVersion = 2;
+ encRevision = 3;
+ encAlgorithm = cryptAES;
+ if (cryptFilterObj.dictLookup("Length", &cfLengthObj)->isInt()) {
+ //~ according to the spec, this should be cfLengthObj / 8
+ fileKeyLength = cfLengthObj.getInt();
+ }
+ cfLengthObj.free();
+ }
+ cfmObj.free();
+ }
+ cryptFilterObj.free();
+ }
+ stringFilterObj.free();
+ streamFilterObj.free();
+ cryptFiltersObj.free();
+ if (encryptDictA->dictLookup("EncryptMetadata",
+ &encryptMetadataObj)->isBool()) {
+ encryptMetadata = encryptMetadataObj.getBool();
+ }
+ encryptMetadataObj.free();
+ }
+ permFlags = permObj.getInt();
+ ownerKey = ownerKeyObj.getString()->copy();
+ userKey = userKeyObj.getString()->copy();
+ if (encVersion >= 1 && encVersion <= 2 &&
+ encRevision >= 2 && encRevision <= 3) {
+ if (fileIDObj.isArray()) {
+ if (fileIDObj.arrayGet(0, &fileIDObj1)->isString()) {
+ fileID = fileIDObj1.getString()->copy();
+ } else {
+ fileID = new GString();
+ }
+ fileIDObj1.free();
+ } else {
+ fileID = new GString();
+ }
+ ok = gTrue;
+ } else {
+ error(-1, "Unsupported version/revision (%d/%d) of Standard security handler",
+ encVersion, encRevision);
+ }
+ } else {
+ error(-1, "Weird encryption info");
+ }
+ if (fileKeyLength > 16) {
+ fileKeyLength = 16;
+ }
+ fileIDObj.free();
+ permObj.free();
+ userKeyObj.free();
+ ownerKeyObj.free();
+ lengthObj.free();
+ revisionObj.free();
+ versionObj.free();
+}
+
+StandardSecurityHandler::~StandardSecurityHandler() {
+ if (fileID) {
+ delete fileID;
+ }
+ if (ownerKey) {
+ delete ownerKey;
+ }
+ if (userKey) {
+ delete userKey;
+ }
+}
+
+void *StandardSecurityHandler::makeAuthData(GString *ownerPassword,
+ GString *userPassword) {
+ return new StandardAuthData(ownerPassword ? ownerPassword->copy()
+ : (GString *)NULL,
+ userPassword ? userPassword->copy()
+ : (GString *)NULL);
+}
+
+void *StandardSecurityHandler::getAuthData() {
+#if HAVE_XPDFCORE
+ XPDFCore *core;
+ GString *password;
+
+ if (!(core = (XPDFCore *)doc->getGUIData()) ||
+ !(password = core->getPassword())) {
+ return NULL;
+ }
+ return new StandardAuthData(password, password->copy());
+#elif HAVE_WINPDFCORE
+ WinPDFCore *core;
+ GString *password;
+
+ if (!(core = (WinPDFCore *)doc->getGUIData()) ||
+ !(password = core->getPassword())) {
+ return NULL;
+ }
+ return new StandardAuthData(password, password->copy());
+#else
+ return NULL;
+#endif
+}
+
+void StandardSecurityHandler::freeAuthData(void *authData) {
+ delete (StandardAuthData *)authData;
+}
+
+GBool StandardSecurityHandler::authorize(void *authData) {
+ GString *ownerPassword, *userPassword;
+
+ if (!ok) {
+ return gFalse;
+ }
+ if (authData) {
+ ownerPassword = ((StandardAuthData *)authData)->ownerPassword;
+ userPassword = ((StandardAuthData *)authData)->userPassword;
+ } else {
+ ownerPassword = NULL;
+ userPassword = NULL;
+ }
+ if (!Decrypt::makeFileKey(encVersion, encRevision, fileKeyLength,
+ ownerKey, userKey, permFlags, fileID,
+ ownerPassword, userPassword, fileKey,
+ encryptMetadata, &ownerPasswordOk)) {
+ return gFalse;
+ }
+ return gTrue;
+}
+
+#ifdef ENABLE_PLUGINS
+
+//------------------------------------------------------------------------
+// ExternalSecurityHandler
+//------------------------------------------------------------------------
+
+ExternalSecurityHandler::ExternalSecurityHandler(PDFDoc *docA,
+ Object *encryptDictA,
+ XpdfSecurityHandler *xshA):
+ SecurityHandler(docA)
+{
+ encryptDictA->copy(&encryptDict);
+ xsh = xshA;
+ encAlgorithm = cryptRC4; //~ this should be obtained via getKey
+ ok = gFalse;
+
+ if (!(*xsh->newDoc)(xsh->handlerData, (XpdfDoc)docA,
+ (XpdfObject)encryptDictA, &docData)) {
+ return;
+ }
+
+ ok = gTrue;
+}
+
+ExternalSecurityHandler::~ExternalSecurityHandler() {
+ (*xsh->freeDoc)(xsh->handlerData, docData);
+ encryptDict.free();
+}
+
+void *ExternalSecurityHandler::makeAuthData(GString *ownerPassword,
+ GString *userPassword) {
+ char *opw, *upw;
+ void *authData;
+
+ opw = ownerPassword ? ownerPassword->getCString() : (char *)NULL;
+ upw = userPassword ? userPassword->getCString() : (char *)NULL;
+ if (!(*xsh->makeAuthData)(xsh->handlerData, docData, opw, upw, &authData)) {
+ return NULL;
+ }
+ return authData;
+}
+
+void *ExternalSecurityHandler::getAuthData() {
+ void *authData;
+
+ if (!(*xsh->getAuthData)(xsh->handlerData, docData, &authData)) {
+ return NULL;
+ }
+ return authData;
+}
+
+void ExternalSecurityHandler::freeAuthData(void *authData) {
+ (*xsh->freeAuthData)(xsh->handlerData, docData, authData);
+}
+
+GBool ExternalSecurityHandler::authorize(void *authData) {
+ char *key;
+ int length;
+
+ if (!ok) {
+ return gFalse;
+ }
+ permFlags = (*xsh->authorize)(xsh->handlerData, docData, authData);
+ if (!(permFlags & xpdfPermissionOpen)) {
+ return gFalse;
+ }
+ if (!(*xsh->getKey)(xsh->handlerData, docData, &key, &length, &encVersion)) {
+ return gFalse;
+ }
+ if ((fileKeyLength = length) > 16) {
+ fileKeyLength = 16;
+ }
+ memcpy(fileKey, key, fileKeyLength);
+ (*xsh->freeKey)(xsh->handlerData, docData, key, length);
+ return gTrue;
+}
+
+#endif // ENABLE_PLUGINS
diff --git a/kpdf/xpdf/xpdf/SecurityHandler.h b/kpdf/xpdf/xpdf/SecurityHandler.h
new file mode 100644
index 00000000..a27868c2
--- /dev/null
+++ b/kpdf/xpdf/xpdf/SecurityHandler.h
@@ -0,0 +1,160 @@
+//========================================================================
+//
+// SecurityHandler.h
+//
+// Copyright 2004 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef SECURITYHANDLER_H
+#define SECURITYHANDLER_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "Object.h"
+
+class GString;
+class PDFDoc;
+struct XpdfSecurityHandler;
+
+//------------------------------------------------------------------------
+// SecurityHandler
+//------------------------------------------------------------------------
+
+class SecurityHandler {
+public:
+
+ static SecurityHandler *make(PDFDoc *docA, Object *encryptDictA);
+
+ SecurityHandler(PDFDoc *docA);
+ virtual ~SecurityHandler();
+
+ // Check the document's encryption. If the document is encrypted,
+ // this will first try <ownerPassword> and <userPassword> (in
+ // "batch" mode), and if those fail, it will attempt to request a
+ // password from the user. This is the high-level function that
+ // calls the lower level functions for the specific security handler
+ // (requesting a password three times, etc.). Returns true if the
+ // document can be opened (if it's unencrypted, or if a correct
+ // password is obtained); false otherwise (encrypted and no correct
+ // password).
+ GBool checkEncryption(GString *ownerPassword,
+ GString *userPassword);
+
+ // Create authorization data for the specified owner and user
+ // passwords. If the security handler doesn't support "batch" mode,
+ // this function should return NULL.
+ virtual void *makeAuthData(GString *ownerPassword,
+ GString *userPassword) = 0;
+
+ // Construct authorization data, typically by prompting the user for
+ // a password. Returns an authorization data object, or NULL to
+ // cancel.
+ virtual void *getAuthData() = 0;
+
+ // Free the authorization data returned by makeAuthData or
+ // getAuthData.
+ virtual void freeAuthData(void *authData) = 0;
+
+ // Attempt to authorize the document, using the supplied
+ // authorization data (which may be NULL). Returns true if
+ // successful (i.e., if at least the right to open the document was
+ // granted).
+ virtual GBool authorize(void *authData) = 0;
+
+ // Return the various authorization parameters. These are only
+ // valid after authorize has returned true.
+ virtual int getPermissionFlags() = 0;
+ virtual GBool getOwnerPasswordOk() = 0;
+ virtual Guchar *getFileKey() = 0;
+ virtual int getFileKeyLength() = 0;
+ virtual int getEncVersion() = 0;
+ virtual CryptAlgorithm getEncAlgorithm() = 0;
+
+protected:
+
+ PDFDoc *doc;
+};
+
+//------------------------------------------------------------------------
+// StandardSecurityHandler
+//------------------------------------------------------------------------
+
+class StandardSecurityHandler: public SecurityHandler {
+public:
+
+ StandardSecurityHandler(PDFDoc *docA, Object *encryptDictA);
+ virtual ~StandardSecurityHandler();
+
+ virtual void *makeAuthData(GString *ownerPassword,
+ GString *userPassword);
+ virtual void *getAuthData();
+ virtual void freeAuthData(void *authData);
+ virtual GBool authorize(void *authData);
+ virtual int getPermissionFlags() { return permFlags; }
+ virtual GBool getOwnerPasswordOk() { return ownerPasswordOk; }
+ virtual Guchar *getFileKey() { return fileKey; }
+ virtual int getFileKeyLength() { return fileKeyLength; }
+ virtual int getEncVersion() { return encVersion; }
+ virtual CryptAlgorithm getEncAlgorithm() { return encAlgorithm; }
+
+private:
+
+ int permFlags;
+ GBool ownerPasswordOk;
+ Guchar fileKey[16];
+ int fileKeyLength;
+ int encVersion;
+ int encRevision;
+ CryptAlgorithm encAlgorithm;
+ GBool encryptMetadata;
+
+ GString *ownerKey, *userKey;
+ GString *fileID;
+ GBool ok;
+};
+
+#ifdef ENABLE_PLUGINS
+//------------------------------------------------------------------------
+// ExternalSecurityHandler
+//------------------------------------------------------------------------
+
+class ExternalSecurityHandler: public SecurityHandler {
+public:
+
+ ExternalSecurityHandler(PDFDoc *docA, Object *encryptDictA,
+ XpdfSecurityHandler *xshA);
+ virtual ~ExternalSecurityHandler();
+
+ virtual void *makeAuthData(GString *ownerPassword,
+ GString *userPassword);
+ virtual void *getAuthData();
+ virtual void freeAuthData(void *authData);
+ virtual GBool authorize(void *authData);
+ virtual int getPermissionFlags() { return permFlags; }
+ virtual GBool getOwnerPasswordOk() { return gFalse; }
+ virtual Guchar *getFileKey() { return fileKey; }
+ virtual int getFileKeyLength() { return fileKeyLength; }
+ virtual int getEncVersion() { return encVersion; }
+ virtual CryptAlgorithm getEncAlgorithm() { return encAlgorithm; }
+
+private:
+
+ Object encryptDict;
+ XpdfSecurityHandler *xsh;
+ void *docData;
+ int permFlags;
+ Guchar fileKey[16];
+ int fileKeyLength;
+ int encVersion;
+ CryptAlgorithm encAlgorithm;
+ GBool ok;
+};
+#endif // ENABLE_PLUGINS
+
+#endif
diff --git a/kpdf/xpdf/xpdf/SplashOutputDev.cc b/kpdf/xpdf/xpdf/SplashOutputDev.cc
new file mode 100644
index 00000000..fe235fb8
--- /dev/null
+++ b/kpdf/xpdf/xpdf/SplashOutputDev.cc
@@ -0,0 +1,2851 @@
+//========================================================================
+//
+// SplashOutputDev.cc
+//
+// Copyright 2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <string.h>
+#include <math.h>
+#include "gfile.h"
+#include "GlobalParams.h"
+#include "Error.h"
+#include "Object.h"
+#include "GfxFont.h"
+#include "Link.h"
+#include "CharCodeToUnicode.h"
+#include "FontEncodingTables.h"
+#include "FoFiTrueType.h"
+#include "SplashBitmap.h"
+#include "SplashGlyphBitmap.h"
+#include "SplashPattern.h"
+#include "SplashScreen.h"
+#include "SplashPath.h"
+#include "SplashState.h"
+#include "SplashErrorCodes.h"
+#include "SplashFontEngine.h"
+#include "SplashFont.h"
+#include "SplashFontFile.h"
+#include "SplashFontFileID.h"
+#include "Splash.h"
+#include "SplashOutputDev.h"
+
+#ifdef VMS
+#if (__VMS_VER < 70000000)
+extern "C" int unlink(char *filename);
+#endif
+#endif
+
+//------------------------------------------------------------------------
+
+// Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result.
+static inline Guchar div255(int x) {
+ return (Guchar)((x + (x >> 8) + 0x80) >> 8);
+}
+
+//------------------------------------------------------------------------
+// Blend functions
+//------------------------------------------------------------------------
+
+static void splashOutBlendMultiply(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+ int i;
+
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ blend[i] = (dest[i] * src[i]) / 255;
+ }
+}
+
+static void splashOutBlendScreen(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+ int i;
+
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ blend[i] = dest[i] + src[i] - (dest[i] * src[i]) / 255;
+ }
+}
+
+static void splashOutBlendOverlay(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+ int i;
+
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ blend[i] = dest[i] < 0x80
+ ? (src[i] * 2 * dest[i]) / 255
+ : 255 - 2 * ((255 - src[i]) * (255 - dest[i])) / 255;
+ }
+}
+
+static void splashOutBlendDarken(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+ int i;
+
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ blend[i] = dest[i] < src[i] ? dest[i] : src[i];
+ }
+}
+
+static void splashOutBlendLighten(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+ int i;
+
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ blend[i] = dest[i] > src[i] ? dest[i] : src[i];
+ }
+}
+
+static void splashOutBlendColorDodge(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend,
+ SplashColorMode cm) {
+ int i, x;
+
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ if (src[i] == 255) {
+ blend[i] = 255;
+ } else {
+ x = (dest[i] * 255) / (255 - src[i]);
+ blend[i] = x <= 255 ? x : 255;
+ }
+ }
+}
+
+static void splashOutBlendColorBurn(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+ int i, x;
+
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ if (src[i] == 0) {
+ blend[i] = 0;
+ } else {
+ x = ((255 - dest[i]) * 255) / src[i];
+ blend[i] = x <= 255 ? 255 - x : 0;
+ }
+ }
+}
+
+static void splashOutBlendHardLight(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+ int i;
+
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ blend[i] = src[i] < 0x80
+ ? (dest[i] * 2 * src[i]) / 255
+ : 255 - 2 * ((255 - dest[i]) * (255 - src[i])) / 255;
+ }
+}
+
+static void splashOutBlendSoftLight(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+ int i, x;
+
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ if (src[i] < 0x80) {
+ blend[i] = dest[i] - (255 - 2 * src[i]) * dest[i] * (255 - dest[i]) /
+ (255 * 255);
+ } else {
+ if (dest[i] < 0x40) {
+ x = (((((16 * dest[i] - 12 * 255) * dest[i]) / 255)
+ + 4 * 255) * dest[i]) / 255;
+ } else {
+ x = (int)sqrt(255.0 * dest[i]);
+ }
+ blend[i] = dest[i] + (2 * src[i] - 255) * (x - dest[i]) / 255;
+ }
+ }
+}
+
+static void splashOutBlendDifference(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend,
+ SplashColorMode cm) {
+ int i;
+
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ blend[i] = dest[i] < src[i] ? src[i] - dest[i] : dest[i] - src[i];
+ }
+}
+
+static void splashOutBlendExclusion(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+ int i;
+
+ for (i = 0; i < splashColorModeNComps[cm]; ++i) {
+ blend[i] = dest[i] + src[i] - (2 * dest[i] * src[i]) / 255;
+ }
+}
+
+static void cvtRGBToHSV(Guchar r, Guchar g, Guchar b, int *h, int *s, int *v) {
+ int cmax, cmid, cmin, x;
+
+ if (r >= g) {
+ if (g >= b) { x = 0; cmax = r; cmid = g; cmin = b; }
+ else if (b >= r) { x = 4; cmax = b; cmid = r; cmin = g; }
+ else { x = 5; cmax = r; cmid = b; cmin = g; }
+ } else {
+ if (r >= b) { x = 1; cmax = g; cmid = r; cmin = b; }
+ else if (g >= b) { x = 2; cmax = g; cmid = b; cmin = r; }
+ else { x = 3; cmax = b; cmid = g; cmin = r; }
+ }
+ if (cmax == cmin) {
+ *h = *s = 0;
+ } else {
+ *h = x * 60;
+ if (x & 1) {
+ *h += ((cmax - cmid) * 60) / (cmax - cmin);
+ } else {
+ *h += ((cmid - cmin) * 60) / (cmax - cmin);
+ }
+ *s = (255 * (cmax - cmin)) / cmax;
+ }
+ *v = cmax;
+}
+
+static void cvtHSVToRGB(int h, int s, int v, Guchar *r, Guchar *g, Guchar *b) {
+ int x, f, cmax, cmid, cmin;
+
+ if (s == 0) {
+ *r = *g = *b = v;
+ } else {
+ x = h / 60;
+ f = h % 60;
+ cmax = v;
+ if (x & 1) {
+ cmid = div255(v * 255 - ((s * f) / 60));
+ } else {
+ cmid = div255(v * (255 - ((s * (60 - f)) / 60)));
+ }
+ cmin = div255(v * (255 - s));
+ switch (x) {
+ case 0: *r = cmax; *g = cmid; *b = cmin; break;
+ case 1: *g = cmax; *r = cmid; *b = cmin; break;
+ case 2: *g = cmax; *b = cmid; *r = cmin; break;
+ case 3: *b = cmax; *g = cmid; *r = cmin; break;
+ case 4: *b = cmax; *r = cmid; *g = cmin; break;
+ case 5: *r = cmax; *b = cmid; *g = cmin; break;
+ }
+ }
+}
+
+static void splashOutBlendHue(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+ int hs, ss, vs, hd, sd, vd;
+#if SPLASH_CMYK
+ Guchar r, g, b;
+#endif
+
+ switch (cm) {
+ case splashModeMono1:
+ case splashModeMono8:
+ blend[0] = dest[0];
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs);
+ cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd);
+ cvtHSVToRGB(hs, sd, vd, &blend[0], &blend[1], &blend[2]);
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ //~ (0xff - ...) should be clipped
+ cvtRGBToHSV(0xff - (src[0] + src[3]),
+ 0xff - (src[1] + src[3]),
+ 0xff - (src[2] + src[3]), &hs, &ss, &vs);
+ cvtRGBToHSV(0xff - (dest[0] + dest[3]),
+ 0xff - (dest[1] + dest[3]),
+ 0xff - (dest[2] + dest[3]), &hd, &sd, &vd);
+ cvtHSVToRGB(hs, sd, vd, &r, &g, &b);
+ //~ should do black generation
+ blend[0] = 0xff - r;
+ blend[1] = 0xff - g;
+ blend[2] = 0xff - b;
+ blend[3] = 0;
+ break;
+#endif
+ }
+}
+
+static void splashOutBlendSaturation(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend,
+ SplashColorMode cm) {
+ int hs, ss, vs, hd, sd, vd;
+#if SPLASH_CMYK
+ Guchar r, g, b;
+#endif
+
+ switch (cm) {
+ case splashModeMono1:
+ case splashModeMono8:
+ blend[0] = dest[0];
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs);
+ cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd);
+ cvtHSVToRGB(hd, ss, vd, &blend[0], &blend[1], &blend[2]);
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ //~ (0xff - ...) should be clipped
+ cvtRGBToHSV(0xff - (src[0] + src[3]),
+ 0xff - (src[1] + src[3]),
+ 0xff - (src[2] + src[3]), &hs, &ss, &vs);
+ cvtRGBToHSV(0xff - (dest[0] + dest[3]),
+ 0xff - (dest[1] + dest[3]),
+ 0xff - (dest[2] + dest[3]), &hd, &sd, &vd);
+ cvtHSVToRGB(hd, ss, vd, &r, &g, &b);
+ //~ should do black generation
+ blend[0] = 0xff - r;
+ blend[1] = 0xff - g;
+ blend[2] = 0xff - b;
+ blend[3] = 0;
+ break;
+#endif
+ }
+}
+
+static void splashOutBlendColor(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend, SplashColorMode cm) {
+ int hs, ss, vs, hd, sd, vd;
+#if SPLASH_CMYK
+ Guchar r, g, b;
+#endif
+
+ switch (cm) {
+ case splashModeMono1:
+ case splashModeMono8:
+ blend[0] = dest[0];
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs);
+ cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd);
+ cvtHSVToRGB(hs, ss, vd, &blend[0], &blend[1], &blend[2]);
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ //~ (0xff - ...) should be clipped
+ cvtRGBToHSV(0xff - (src[0] + src[3]),
+ 0xff - (src[1] + src[3]),
+ 0xff - (src[2] + src[3]), &hs, &ss, &vs);
+ cvtRGBToHSV(0xff - (dest[0] + dest[3]),
+ 0xff - (dest[1] + dest[3]),
+ 0xff - (dest[2] + dest[3]), &hd, &sd, &vd);
+ cvtHSVToRGB(hs, ss, vd, &r, &g, &b);
+ //~ should do black generation
+ blend[0] = 0xff - r;
+ blend[1] = 0xff - g;
+ blend[2] = 0xff - b;
+ blend[3] = 0;
+ break;
+#endif
+ }
+}
+
+static void splashOutBlendLuminosity(SplashColorPtr src, SplashColorPtr dest,
+ SplashColorPtr blend,
+ SplashColorMode cm) {
+ int hs, ss, vs, hd, sd, vd;
+#if SPLASH_CMYK
+ Guchar r, g, b;
+#endif
+
+ switch (cm) {
+ case splashModeMono1:
+ case splashModeMono8:
+ blend[0] = dest[0];
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs);
+ cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd);
+ cvtHSVToRGB(hd, sd, vs, &blend[0], &blend[1], &blend[2]);
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ //~ (0xff - ...) should be clipped
+ cvtRGBToHSV(0xff - (src[0] + src[3]),
+ 0xff - (src[1] + src[3]),
+ 0xff - (src[2] + src[3]), &hs, &ss, &vs);
+ cvtRGBToHSV(0xff - (dest[0] + dest[3]),
+ 0xff - (dest[1] + dest[3]),
+ 0xff - (dest[2] + dest[3]), &hd, &sd, &vd);
+ cvtHSVToRGB(hd, sd, vs, &r, &g, &b);
+ //~ should do black generation
+ blend[0] = 0xff - r;
+ blend[1] = 0xff - g;
+ blend[2] = 0xff - b;
+ blend[3] = 0;
+ break;
+#endif
+ }
+}
+
+// NB: This must match the GfxBlendMode enum defined in GfxState.h.
+SplashBlendFunc splashOutBlendFuncs[] = {
+ NULL,
+ &splashOutBlendMultiply,
+ &splashOutBlendScreen,
+ &splashOutBlendOverlay,
+ &splashOutBlendDarken,
+ &splashOutBlendLighten,
+ &splashOutBlendColorDodge,
+ &splashOutBlendColorBurn,
+ &splashOutBlendHardLight,
+ &splashOutBlendSoftLight,
+ &splashOutBlendDifference,
+ &splashOutBlendExclusion,
+ &splashOutBlendHue,
+ &splashOutBlendSaturation,
+ &splashOutBlendColor,
+ &splashOutBlendLuminosity
+};
+
+//------------------------------------------------------------------------
+// Font substitutions
+//------------------------------------------------------------------------
+
+struct SplashOutFontSubst {
+ char *name;
+ double mWidth;
+};
+
+// index: {symbolic:12, fixed:8, serif:4, sans-serif:0} + bold*2 + italic
+static SplashOutFontSubst splashOutSubstFonts[16] = {
+ {"Helvetica", 0.833},
+ {"Helvetica-Oblique", 0.833},
+ {"Helvetica-Bold", 0.889},
+ {"Helvetica-BoldOblique", 0.889},
+ {"Times-Roman", 0.788},
+ {"Times-Italic", 0.722},
+ {"Times-Bold", 0.833},
+ {"Times-BoldItalic", 0.778},
+ {"Courier", 0.600},
+ {"Courier-Oblique", 0.600},
+ {"Courier-Bold", 0.600},
+ {"Courier-BoldOblique", 0.600},
+ {"Symbol", 0.576},
+ {"Symbol", 0.576},
+ {"Symbol", 0.576},
+ {"Symbol", 0.576}
+};
+
+//------------------------------------------------------------------------
+// SplashOutFontFileID
+//------------------------------------------------------------------------
+
+class SplashOutFontFileID: public SplashFontFileID {
+public:
+
+ SplashOutFontFileID(Ref *rA) { r = *rA; substIdx = -1; }
+
+ ~SplashOutFontFileID() {}
+
+ GBool matches(SplashFontFileID *id) {
+ return ((SplashOutFontFileID *)id)->r.num == r.num &&
+ ((SplashOutFontFileID *)id)->r.gen == r.gen;
+ }
+
+ void setSubstIdx(int substIdxA) { substIdx = substIdxA; }
+ int getSubstIdx() { return substIdx; }
+
+private:
+
+ Ref r;
+ int substIdx;
+};
+
+//------------------------------------------------------------------------
+// T3FontCache
+//------------------------------------------------------------------------
+
+struct T3FontCacheTag {
+ Gushort code;
+ Gushort mru; // valid bit (0x8000) and MRU index
+};
+
+class T3FontCache {
+public:
+
+ T3FontCache(Ref *fontID, double m11A, double m12A,
+ double m21A, double m22A,
+ int glyphXA, int glyphYA, int glyphWA, int glyphHA,
+ GBool aa, GBool validBBoxA);
+ ~T3FontCache();
+ GBool matches(Ref *idA, double m11A, double m12A,
+ double m21A, double m22A)
+ { return fontID.num == idA->num && fontID.gen == idA->gen &&
+ m11 == m11A && m12 == m12A && m21 == m21A && m22 == m22A; }
+
+ Ref fontID; // PDF font ID
+ double m11, m12, m21, m22; // transform matrix
+ int glyphX, glyphY; // pixel offset of glyph bitmaps
+ int glyphW, glyphH; // size of glyph bitmaps, in pixels
+ GBool validBBox; // false if the bbox was [0 0 0 0]
+ int glyphSize; // size of glyph bitmaps, in bytes
+ int cacheSets; // number of sets in cache
+ int cacheAssoc; // cache associativity (glyphs per set)
+ Guchar *cacheData; // glyph pixmap cache
+ T3FontCacheTag *cacheTags; // cache tags, i.e., char codes
+};
+
+T3FontCache::T3FontCache(Ref *fontIDA, double m11A, double m12A,
+ double m21A, double m22A,
+ int glyphXA, int glyphYA, int glyphWA, int glyphHA,
+ GBool validBBoxA, GBool aa) {
+ int i;
+
+ fontID = *fontIDA;
+ m11 = m11A;
+ m12 = m12A;
+ m21 = m21A;
+ m22 = m22A;
+ glyphX = glyphXA;
+ glyphY = glyphYA;
+ glyphW = glyphWA;
+ glyphH = glyphHA;
+ validBBox = validBBoxA;
+ if (aa) {
+ glyphSize = glyphW * glyphH;
+ } else {
+ glyphSize = ((glyphW + 7) >> 3) * glyphH;
+ }
+ cacheAssoc = 8;
+ if (glyphSize <= 256) {
+ cacheSets = 8;
+ } else if (glyphSize <= 512) {
+ cacheSets = 4;
+ } else if (glyphSize <= 1024) {
+ cacheSets = 2;
+ } else {
+ cacheSets = 1;
+ }
+ cacheData = (Guchar *)gmallocn_checkoverflow(cacheSets * cacheAssoc, glyphSize);
+ if (cacheData != NULL)
+ {
+ cacheTags = (T3FontCacheTag *)gmallocn(cacheSets * cacheAssoc,
+ sizeof(T3FontCacheTag));
+ for (i = 0; i < cacheSets * cacheAssoc; ++i) {
+ cacheTags[i].mru = i & (cacheAssoc - 1);
+ }
+ }
+ else
+ {
+ cacheTags = NULL;
+ }
+}
+
+T3FontCache::~T3FontCache() {
+ gfree(cacheData);
+ gfree(cacheTags);
+}
+
+struct T3GlyphStack {
+ Gushort code; // character code
+
+ //----- cache info
+ T3FontCache *cache; // font cache for the current font
+ T3FontCacheTag *cacheTag; // pointer to cache tag for the glyph
+ Guchar *cacheData; // pointer to cache data for the glyph
+
+ //----- saved state
+ SplashBitmap *origBitmap;
+ Splash *origSplash;
+ double origCTM4, origCTM5;
+
+ T3GlyphStack *next; // next object on stack
+};
+
+//------------------------------------------------------------------------
+// SplashTransparencyGroup
+//------------------------------------------------------------------------
+
+struct SplashTransparencyGroup {
+ int tx, ty; // translation coordinates
+ SplashBitmap *tBitmap; // bitmap for transparency group
+ GfxColorSpace *blendingColorSpace;
+ GBool isolated;
+
+ //----- saved state
+ SplashBitmap *origBitmap;
+ Splash *origSplash;
+
+ SplashTransparencyGroup *next;
+};
+
+//------------------------------------------------------------------------
+// SplashOutputDev
+//------------------------------------------------------------------------
+
+SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA,
+ int bitmapRowPadA,
+ GBool reverseVideoA,
+ SplashColorPtr paperColorA,
+ GBool bitmapTopDownA,
+ GBool allowAntialiasA) {
+ colorMode = colorModeA;
+ bitmapRowPad = bitmapRowPadA;
+ bitmapTopDown = bitmapTopDownA;
+ allowAntialias = allowAntialiasA;
+ vectorAntialias = allowAntialias &&
+ globalParams->getVectorAntialias() &&
+ colorMode != splashModeMono1;
+ setupScreenParams(72.0, 72.0);
+ reverseVideo = reverseVideoA;
+ splashColorCopy(paperColor, paperColorA);
+
+ xref = NULL;
+
+ bitmap = new SplashBitmap(1, 1, bitmapRowPad, colorMode,
+ colorMode != splashModeMono1, bitmapTopDown);
+ splash = new Splash(bitmap, vectorAntialias, &screenParams);
+ splash->clear(paperColor, 0);
+
+ fontEngine = NULL;
+
+ nT3Fonts = 0;
+ t3GlyphStack = NULL;
+
+ font = NULL;
+ needFontUpdate = gFalse;
+ textClipPath = NULL;
+
+ transpGroupStack = NULL;
+}
+
+void SplashOutputDev::setupScreenParams(double hDPI, double vDPI) {
+ screenParams.size = globalParams->getScreenSize();
+ screenParams.dotRadius = globalParams->getScreenDotRadius();
+ screenParams.gamma = (SplashCoord)globalParams->getScreenGamma();
+ screenParams.blackThreshold =
+ (SplashCoord)globalParams->getScreenBlackThreshold();
+ screenParams.whiteThreshold =
+ (SplashCoord)globalParams->getScreenWhiteThreshold();
+ switch (globalParams->getScreenType()) {
+ case screenDispersed:
+ screenParams.type = splashScreenDispersed;
+ if (screenParams.size < 0) {
+ screenParams.size = 4;
+ }
+ break;
+ case screenClustered:
+ screenParams.type = splashScreenClustered;
+ if (screenParams.size < 0) {
+ screenParams.size = 10;
+ }
+ break;
+ case screenStochasticClustered:
+ screenParams.type = splashScreenStochasticClustered;
+ if (screenParams.size < 0) {
+ screenParams.size = 100;
+ }
+ if (screenParams.dotRadius < 0) {
+ screenParams.dotRadius = 2;
+ }
+ break;
+ case screenUnset:
+ default:
+ // use clustered dithering for resolution >= 300 dpi
+ // (compare to 299.9 to avoid floating point issues)
+ if (hDPI > 299.9 && vDPI > 299.9) {
+ screenParams.type = splashScreenStochasticClustered;
+ if (screenParams.size < 0) {
+ screenParams.size = 100;
+ }
+ if (screenParams.dotRadius < 0) {
+ screenParams.dotRadius = 2;
+ }
+ } else {
+ screenParams.type = splashScreenDispersed;
+ if (screenParams.size < 0) {
+ screenParams.size = 4;
+ }
+ }
+ }
+}
+
+SplashOutputDev::~SplashOutputDev() {
+ int i;
+
+ for (i = 0; i < nT3Fonts; ++i) {
+ delete t3FontCache[i];
+ }
+ if (fontEngine) {
+ delete fontEngine;
+ }
+ if (splash) {
+ delete splash;
+ }
+ if (bitmap) {
+ delete bitmap;
+ }
+}
+
+void SplashOutputDev::startDoc(XRef *xrefA) {
+ int i;
+
+ xref = xrefA;
+ if (fontEngine) {
+ delete fontEngine;
+ }
+ fontEngine = new SplashFontEngine(
+#if HAVE_T1LIB_H
+ globalParams->getEnableT1lib(),
+#endif
+#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
+ globalParams->getEnableFreeType(),
+#endif
+ allowAntialias &&
+ globalParams->getAntialias() &&
+ colorMode != splashModeMono1);
+ for (i = 0; i < nT3Fonts; ++i) {
+ delete t3FontCache[i];
+ }
+ nT3Fonts = 0;
+}
+
+void SplashOutputDev::startPage(int /*pageNum*/, GfxState *state) {
+ int w, h;
+ double *ctm;
+ SplashCoord mat[6];
+ SplashColor color;
+
+ if (state) {
+ setupScreenParams(state->getHDPI(), state->getVDPI());
+ w = (int)(state->getPageWidth() + 0.5);
+ if (w <= 0) {
+ w = 1;
+ }
+ h = (int)(state->getPageHeight() + 0.5);
+ if (h <= 0) {
+ h = 1;
+ }
+ } else {
+ w = h = 1;
+ }
+ if (splash) {
+ delete splash;
+ }
+ if (!bitmap || w != bitmap->getWidth() || h != bitmap->getHeight()) {
+ if (bitmap) {
+ delete bitmap;
+ }
+ bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode,
+ colorMode != splashModeMono1, bitmapTopDown);
+ }
+ splash = new Splash(bitmap, vectorAntialias, &screenParams);
+ if (state) {
+ ctm = state->getCTM();
+ mat[0] = (SplashCoord)ctm[0];
+ mat[1] = (SplashCoord)ctm[1];
+ mat[2] = (SplashCoord)ctm[2];
+ mat[3] = (SplashCoord)ctm[3];
+ mat[4] = (SplashCoord)ctm[4];
+ mat[5] = (SplashCoord)ctm[5];
+ splash->setMatrix(mat);
+ }
+ switch (colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ color[0] = 0;
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ color[0] = color[1] = color[2] = 0;
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ color[0] = color[1] = color[2] = color[3] = 0;
+ break;
+#endif
+ }
+ splash->setStrokePattern(new SplashSolidColor(color));
+ splash->setFillPattern(new SplashSolidColor(color));
+ splash->setLineCap(splashLineCapButt);
+ splash->setLineJoin(splashLineJoinMiter);
+ splash->setLineDash(NULL, 0, 0);
+ splash->setMiterLimit(10);
+ splash->setFlatness(1);
+ // the SA parameter supposedly defaults to false, but Acrobat
+ // apparently hardwires it to true
+ splash->setStrokeAdjust(globalParams->getStrokeAdjust());
+ splash->clear(paperColor, 0);
+}
+
+void SplashOutputDev::endPage() {
+ if (colorMode != splashModeMono1) {
+ splash->compositeBackground(paperColor);
+ }
+}
+
+void SplashOutputDev::saveState(GfxState * /*state*/) {
+ splash->saveState();
+}
+
+void SplashOutputDev::restoreState(GfxState * /*state*/) {
+ splash->restoreState();
+ needFontUpdate = gTrue;
+}
+
+void SplashOutputDev::updateAll(GfxState *state) {
+ updateLineDash(state);
+ updateLineJoin(state);
+ updateLineCap(state);
+ updateLineWidth(state);
+ updateFlatness(state);
+ updateMiterLimit(state);
+ updateStrokeAdjust(state);
+ updateFillColor(state);
+ updateStrokeColor(state);
+ needFontUpdate = gTrue;
+}
+
+void SplashOutputDev::updateCTM(GfxState *state, double /*m11*/, double /*m12*/,
+ double /*m21*/, double /*m22*/,
+ double /*m31*/, double /*m32*/) {
+ double *ctm;
+ SplashCoord mat[6];
+
+ ctm = state->getCTM();
+ mat[0] = (SplashCoord)ctm[0];
+ mat[1] = (SplashCoord)ctm[1];
+ mat[2] = (SplashCoord)ctm[2];
+ mat[3] = (SplashCoord)ctm[3];
+ mat[4] = (SplashCoord)ctm[4];
+ mat[5] = (SplashCoord)ctm[5];
+ splash->setMatrix(mat);
+}
+
+void SplashOutputDev::updateLineDash(GfxState *state) {
+ double *dashPattern;
+ int dashLength;
+ double dashStart;
+ SplashCoord dash[20];
+ int i;
+
+ state->getLineDash(&dashPattern, &dashLength, &dashStart);
+ if (dashLength > 20) {
+ dashLength = 20;
+ }
+ for (i = 0; i < dashLength; ++i) {
+ dash[i] = (SplashCoord)dashPattern[i];
+ if (dash[i] < 0) {
+ dash[i] = 0;
+ }
+ }
+ splash->setLineDash(dash, dashLength, (SplashCoord)dashStart);
+}
+
+void SplashOutputDev::updateFlatness(GfxState *state) {
+ splash->setFlatness(state->getFlatness());
+}
+
+void SplashOutputDev::updateLineJoin(GfxState *state) {
+ splash->setLineJoin(state->getLineJoin());
+}
+
+void SplashOutputDev::updateLineCap(GfxState *state) {
+ splash->setLineCap(state->getLineCap());
+}
+
+void SplashOutputDev::updateMiterLimit(GfxState *state) {
+ splash->setMiterLimit(state->getMiterLimit());
+}
+
+void SplashOutputDev::updateLineWidth(GfxState *state) {
+ splash->setLineWidth(state->getLineWidth());
+}
+
+void SplashOutputDev::updateStrokeAdjust(GfxState * /*state*/) {
+#if 0 // the SA parameter supposedly defaults to false, but Acrobat
+ // apparently hardwires it to true
+ splash->setStrokeAdjust(state->getStrokeAdjust());
+#endif
+}
+
+void SplashOutputDev::updateFillColor(GfxState *state) {
+ GfxGray gray;
+ GfxRGB rgb;
+#if SPLASH_CMYK
+ GfxCMYK cmyk;
+#endif
+
+ state->getFillGray(&gray);
+ state->getFillRGB(&rgb);
+#if SPLASH_CMYK
+ state->getFillCMYK(&cmyk);
+ splash->setFillPattern(getColor(gray, &rgb, &cmyk));
+#else
+ splash->setFillPattern(getColor(gray, &rgb));
+#endif
+}
+
+void SplashOutputDev::updateStrokeColor(GfxState *state) {
+ GfxGray gray;
+ GfxRGB rgb;
+#if SPLASH_CMYK
+ GfxCMYK cmyk;
+#endif
+
+ state->getStrokeGray(&gray);
+ state->getStrokeRGB(&rgb);
+#if SPLASH_CMYK
+ state->getStrokeCMYK(&cmyk);
+ splash->setStrokePattern(getColor(gray, &rgb, &cmyk));
+#else
+ splash->setStrokePattern(getColor(gray, &rgb));
+#endif
+}
+
+#if SPLASH_CMYK
+SplashPattern *SplashOutputDev::getColor(GfxGray gray, GfxRGB *rgb,
+ GfxCMYK *cmyk) {
+#else
+SplashPattern *SplashOutputDev::getColor(GfxGray gray, GfxRGB *rgb) {
+#endif
+ SplashPattern *pattern;
+ SplashColor color;
+ GfxColorComp r, g, b;
+
+ if (reverseVideo) {
+ gray = gfxColorComp1 - gray;
+ r = gfxColorComp1 - rgb->r;
+ g = gfxColorComp1 - rgb->g;
+ b = gfxColorComp1 - rgb->b;
+ } else {
+ r = rgb->r;
+ g = rgb->g;
+ b = rgb->b;
+ }
+
+ pattern = NULL; // make gcc happy
+ switch (colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ color[0] = colToByte(gray);
+ pattern = new SplashSolidColor(color);
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ color[0] = colToByte(r);
+ color[1] = colToByte(g);
+ color[2] = colToByte(b);
+ pattern = new SplashSolidColor(color);
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ color[0] = colToByte(cmyk->c);
+ color[1] = colToByte(cmyk->m);
+ color[2] = colToByte(cmyk->y);
+ color[3] = colToByte(cmyk->k);
+ pattern = new SplashSolidColor(color);
+ break;
+#endif
+ }
+
+ return pattern;
+}
+
+void SplashOutputDev::updateBlendMode(GfxState *state) {
+ splash->setBlendFunc(splashOutBlendFuncs[state->getBlendMode()]);
+}
+
+void SplashOutputDev::updateFillOpacity(GfxState *state) {
+ splash->setFillAlpha((SplashCoord)state->getFillOpacity());
+}
+
+void SplashOutputDev::updateStrokeOpacity(GfxState *state) {
+ splash->setStrokeAlpha((SplashCoord)state->getStrokeOpacity());
+}
+
+void SplashOutputDev::updateFont(GfxState * /*state*/) {
+ needFontUpdate = gTrue;
+}
+
+void SplashOutputDev::doUpdateFont(GfxState *state) {
+ GfxFont *gfxFont;
+ GfxFontType fontType;
+ SplashOutFontFileID *id;
+ SplashFontFile *fontFile;
+ SplashFontSrc *fontsrc = NULL;
+ FoFiTrueType *ff;
+ Ref embRef;
+ Object refObj, strObj;
+ GString *fileName, *substName;
+ char *tmpBuf;
+ int tmpBufLen;
+ Gushort *codeToGID;
+ DisplayFontParam *dfp;
+ CharCodeToUnicode *ctu;
+ double *textMat;
+ double m11, m12, m21, m22, w1, w2, fontSize;
+ SplashCoord mat[4];
+ char *name;
+ Unicode uBuf[8];
+ int substIdx, n, code, cmap;
+ int faceIndex = 0;
+
+ needFontUpdate = gFalse;
+ font = NULL;
+ fileName = NULL;
+ tmpBuf = NULL;
+ substIdx = -1;
+ dfp = NULL;
+
+ if (!(gfxFont = state->getFont())) {
+ goto err1;
+ }
+ fontType = gfxFont->getType();
+ if (fontType == fontType3) {
+ goto err1;
+ }
+
+ // check the font file cache
+ id = new SplashOutFontFileID(gfxFont->getID());
+ if ((fontFile = fontEngine->getFontFile(id))) {
+ delete id;
+
+ } else {
+
+ // if there is an embedded font, write it to disk
+ if (gfxFont->getEmbeddedFontID(&embRef)) {
+ tmpBuf = gfxFont->readEmbFontFile(xref, &tmpBufLen);
+ if (! tmpBuf)
+ goto err2;
+
+ // if there is an external font file, use it
+ } else if (!(fileName = gfxFont->getExtFontFile())) {
+
+ // look for a display font mapping or a substitute font
+ if (gfxFont->isCIDFont()) {
+ if (((GfxCIDFont *)gfxFont)->getCollection()) {
+ dfp = globalParams->
+ getDisplayCIDFont(gfxFont->getName(),
+ ((GfxCIDFont *)gfxFont)->getCollection());
+ }
+ } else {
+ if (gfxFont->getName()) {
+ dfp = globalParams->getDisplayFont(gfxFont->getName());
+ }
+ if (!dfp) {
+ // 8-bit font substitution
+ if (gfxFont->isFixedWidth()) {
+ substIdx = 8;
+ } else if (gfxFont->isSerif()) {
+ substIdx = 4;
+ } else {
+ substIdx = 0;
+ }
+ if (gfxFont->isBold()) {
+ substIdx += 2;
+ }
+ if (gfxFont->isItalic()) {
+ substIdx += 1;
+ }
+ substName = new GString(splashOutSubstFonts[substIdx].name);
+ dfp = globalParams->getDisplayFont(substName);
+ delete substName;
+ id->setSubstIdx(substIdx);
+ }
+ }
+ if (!dfp) {
+ error(-1, "Couldn't find a font for '%s'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
+ goto err2;
+ }
+ switch (dfp->kind) {
+ case displayFontT1:
+ fileName = dfp->t1.fileName;
+ fontType = gfxFont->isCIDFont() ? fontCIDType0 : fontType1;
+ break;
+ case displayFontTT:
+ fileName = dfp->tt.fileName;
+ fontType = gfxFont->isCIDFont() ? fontCIDType2 : fontTrueType;
+ faceIndex = dfp->tt.faceIndex;
+ break;
+ }
+ }
+
+ fontsrc = new SplashFontSrc;
+ if (fileName)
+ fontsrc->setFile(fileName, gFalse);
+ else
+ fontsrc->setBuf(tmpBuf, tmpBufLen, gTrue);
+
+ // load the font file
+ switch (fontType) {
+ case fontType1:
+ if (!(fontFile = fontEngine->loadType1Font(
+ id,
+ fontsrc,
+ ((Gfx8BitFont *)gfxFont)->getEncoding()))) {
+ error(-1, "Couldn't create a font for '%s'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
+ goto err2;
+ }
+ break;
+ case fontType1C:
+ if (!(fontFile = fontEngine->loadType1CFont(
+ id,
+ fontsrc,
+ ((Gfx8BitFont *)gfxFont)->getEncoding()))) {
+ error(-1, "Couldn't create a font for '%s'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
+ goto err2;
+ }
+ break;
+ case fontType1COT:
+ if (!(fontFile = fontEngine->loadOpenTypeT1CFont(
+ id,
+ fontsrc,
+ ((Gfx8BitFont *)gfxFont)->getEncoding()))) {
+ error(-1, "Couldn't create a font for '%s'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
+ goto err2;
+ }
+ break;
+ case fontTrueType:
+ case fontTrueTypeOT:
+ if (fileName)
+ ff = FoFiTrueType::load(fileName->getCString());
+ else
+ ff = FoFiTrueType::make(tmpBuf, tmpBufLen);
+ if (ff) {
+ codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff);
+ n = 256;
+ delete ff;
+ } else {
+ codeToGID = NULL;
+ n = 0;
+ }
+ if (!(fontFile = fontEngine->loadTrueTypeFont(
+ id,
+ fontsrc,
+ codeToGID, n))) {
+ error(-1, "Couldn't create a font for '%s'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
+ goto err2;
+ }
+ break;
+ case fontCIDType0:
+ case fontCIDType0C:
+ if (!(fontFile = fontEngine->loadCIDFont(
+ id,
+ fontsrc))) {
+ error(-1, "Couldn't create a font for '%s'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
+ goto err2;
+ }
+ break;
+ case fontCIDType0COT:
+ if (!(fontFile = fontEngine->loadOpenTypeCFFFont(
+ id,
+ fontsrc))) {
+ error(-1, "Couldn't create a font for '%s'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
+ goto err2;
+ }
+ break;
+ case fontCIDType2:
+ case fontCIDType2OT:
+ codeToGID = NULL;
+ n = 0;
+ if (dfp) {
+ // create a CID-to-GID mapping, via Unicode
+ if ((ctu = ((GfxCIDFont *)gfxFont)->getToUnicode())) {
+ if (fileName)
+ ff = FoFiTrueType::load(fileName->getCString());
+ else
+ ff = FoFiTrueType::make(tmpBuf, tmpBufLen);
+ if (ff) {
+ // look for a Unicode cmap
+ for (cmap = 0; cmap < ff->getNumCmaps(); ++cmap) {
+ if ((ff->getCmapPlatform(cmap) == 3 &&
+ ff->getCmapEncoding(cmap) == 1) ||
+ ff->getCmapPlatform(cmap) == 0) {
+ break;
+ }
+ }
+ if (cmap < ff->getNumCmaps()) {
+ // map CID -> Unicode -> GID
+ n = ctu->getLength();
+ codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort));
+ for (code = 0; code < n; ++code) {
+ if (ctu->mapToUnicode(code, uBuf, 8) > 0) {
+ codeToGID[code] = ff->mapCodeToGID(cmap, uBuf[0]);
+ } else {
+ codeToGID[code] = 0;
+ }
+ }
+ }
+ delete ff;
+ }
+ ctu->decRefCnt();
+ } else {
+ error(-1, "Couldn't find a mapping to Unicode for font '%s'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
+ }
+ } else {
+ if (((GfxCIDFont *)gfxFont)->getCIDToGID()) {
+ n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
+ codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort));
+ memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(),
+ n * sizeof(Gushort));
+ }
+ }
+ if (!(fontFile = fontEngine->loadTrueTypeFont(
+ id,
+ fontsrc,
+ codeToGID, n, faceIndex))) {
+ error(-1, "Couldn't create a font for '%s'",
+ gfxFont->getName() ? gfxFont->getName()->getCString()
+ : "(unnamed)");
+ goto err2;
+ }
+ break;
+ default:
+ // this shouldn't happen
+ goto err2;
+ }
+ }
+
+ // get the font matrix
+ textMat = state->getTextMat();
+ fontSize = state->getFontSize();
+ m11 = textMat[0] * fontSize * state->getHorizScaling();
+ m12 = textMat[1] * fontSize * state->getHorizScaling();
+ m21 = textMat[2] * fontSize;
+ m22 = textMat[3] * fontSize;
+
+ // for substituted fonts: adjust the font matrix -- compare the
+ // width of 'm' in the original font and the substituted font
+ substIdx = ((SplashOutFontFileID *)fontFile->getID())->getSubstIdx();
+ if (substIdx >= 0) {
+ for (code = 0; code < 256; ++code) {
+ if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) &&
+ name[0] == 'm' && name[1] == '\0') {
+ break;
+ }
+ }
+ if (code < 256) {
+ w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code);
+ w2 = splashOutSubstFonts[substIdx].mWidth;
+ if (!gfxFont->isSymbolic()) {
+ // if real font is substantially narrower than substituted
+ // font, reduce the font size accordingly
+ if (w1 > 0.01 && w1 < 0.9 * w2) {
+ w1 /= w2;
+ m11 *= w1;
+ m21 *= w1;
+ }
+ }
+ }
+ }
+
+ // create the scaled font
+ mat[0] = m11; mat[1] = m12;
+ mat[2] = m21; mat[3] = m22;
+ font = fontEngine->getFont(fontFile, mat, splash->getMatrix());
+
+ if (fontsrc && !fontsrc->isFile)
+ fontsrc->unref();
+
+ return;
+
+ err2:
+ delete id;
+ err1:
+ if (fontsrc && !fontsrc->isFile)
+ fontsrc->unref();
+ return;
+}
+
+void SplashOutputDev::stroke(GfxState *state) {
+ SplashPath *path;
+
+ if (state->getStrokeColorSpace()->isNonMarking()) {
+ return;
+ }
+ path = convertPath(state, state->getPath());
+ splash->stroke(path);
+ delete path;
+}
+
+void SplashOutputDev::fill(GfxState *state) {
+ SplashPath *path;
+
+ if (state->getFillColorSpace()->isNonMarking()) {
+ return;
+ }
+ path = convertPath(state, state->getPath());
+ splash->fill(path, gFalse);
+ delete path;
+}
+
+void SplashOutputDev::eoFill(GfxState *state) {
+ SplashPath *path;
+
+ if (state->getFillColorSpace()->isNonMarking()) {
+ return;
+ }
+ path = convertPath(state, state->getPath());
+ splash->fill(path, gTrue);
+ delete path;
+}
+
+void SplashOutputDev::clip(GfxState *state) {
+ SplashPath *path;
+
+ path = convertPath(state, state->getPath());
+ splash->clipToPath(path, gFalse);
+ delete path;
+}
+
+void SplashOutputDev::eoClip(GfxState *state) {
+ SplashPath *path;
+
+ path = convertPath(state, state->getPath());
+ splash->clipToPath(path, gTrue);
+ delete path;
+}
+
+void SplashOutputDev::clipToStrokePath(GfxState *state) {
+ SplashPath *path, *path2;
+
+ path = convertPath(state, state->getPath());
+ path2 = splash->makeStrokePath(path);
+ delete path;
+ splash->clipToPath(path2, gFalse);
+ delete path2;
+}
+
+SplashPath *SplashOutputDev::convertPath(GfxState * /*state*/, GfxPath *path) {
+ SplashPath *sPath;
+ GfxSubpath *subpath;
+ int i, j;
+
+ sPath = new SplashPath();
+ for (i = 0; i < path->getNumSubpaths(); ++i) {
+ subpath = path->getSubpath(i);
+ if (subpath->getNumPoints() > 0) {
+ sPath->moveTo((SplashCoord)subpath->getX(0),
+ (SplashCoord)subpath->getY(0));
+ j = 1;
+ while (j < subpath->getNumPoints()) {
+ if (subpath->getCurve(j)) {
+ sPath->curveTo((SplashCoord)subpath->getX(j),
+ (SplashCoord)subpath->getY(j),
+ (SplashCoord)subpath->getX(j+1),
+ (SplashCoord)subpath->getY(j+1),
+ (SplashCoord)subpath->getX(j+2),
+ (SplashCoord)subpath->getY(j+2));
+ j += 3;
+ } else {
+ sPath->lineTo((SplashCoord)subpath->getX(j),
+ (SplashCoord)subpath->getY(j));
+ ++j;
+ }
+ }
+ if (subpath->isClosed()) {
+ sPath->close();
+ }
+ }
+ }
+ return sPath;
+}
+
+void SplashOutputDev::drawChar(GfxState *state, double x, double y,
+ double /*dx*/, double /*dy*/,
+ double originX, double originY,
+ CharCode code, int /*nBytes*/,
+ Unicode * /*u*/, int /*uLen*/) {
+ SplashPath *path;
+ int render;
+
+ // check for invisible text -- this is used by Acrobat Capture
+ render = state->getRender();
+ if (render == 3) {
+ return;
+ }
+
+ if (needFontUpdate) {
+ doUpdateFont(state);
+ }
+ if (!font) {
+ return;
+ }
+
+ x -= originX;
+ y -= originY;
+
+ // fill
+ if (!(render & 1)) {
+ if (!state->getFillColorSpace()->isNonMarking()) {
+ splash->fillChar((SplashCoord)x, (SplashCoord)y, code, font);
+ }
+ }
+
+ // stroke
+ if ((render & 3) == 1 || (render & 3) == 2) {
+ if (!state->getStrokeColorSpace()->isNonMarking()) {
+ if ((path = font->getGlyphPath(code))) {
+ path->offset((SplashCoord)x, (SplashCoord)y);
+ splash->stroke(path);
+ delete path;
+ }
+ }
+ }
+
+ // clip
+ if (render & 4) {
+ if ((path = font->getGlyphPath(code))) {
+ path->offset((SplashCoord)x, (SplashCoord)y);
+ if (textClipPath) {
+ textClipPath->append(path);
+ delete path;
+ } else {
+ textClipPath = path;
+ }
+ }
+ }
+}
+
+GBool SplashOutputDev::beginType3Char(GfxState *state, double /*x*/, double /*y*/,
+ double /*dx*/, double /*dy*/,
+ CharCode code, Unicode * /*u*/, int /*uLen*/) {
+ GfxFont *gfxFont;
+ Ref *fontID;
+ double *ctm, *bbox;
+ T3FontCache *t3Font;
+ T3GlyphStack *t3gs;
+ GBool validBBox;
+ double x1, y1, xMin, yMin, xMax, yMax, xt, yt;
+ int i, j;
+
+ if (!(gfxFont = state->getFont())) {
+ return gFalse;
+ }
+ fontID = gfxFont->getID();
+ ctm = state->getCTM();
+ state->transform(0, 0, &xt, &yt);
+
+ // is it the first (MRU) font in the cache?
+ if (!(nT3Fonts > 0 &&
+ t3FontCache[0]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3]))) {
+
+ // is the font elsewhere in the cache?
+ for (i = 1; i < nT3Fonts; ++i) {
+ if (t3FontCache[i]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3])) {
+ t3Font = t3FontCache[i];
+ for (j = i; j > 0; --j) {
+ t3FontCache[j] = t3FontCache[j - 1];
+ }
+ t3FontCache[0] = t3Font;
+ break;
+ }
+ }
+ if (i >= nT3Fonts) {
+
+ // create new entry in the font cache
+ if (nT3Fonts == splashOutT3FontCacheSize) {
+ delete t3FontCache[nT3Fonts - 1];
+ --nT3Fonts;
+ }
+ for (j = nT3Fonts; j > 0; --j) {
+ t3FontCache[j] = t3FontCache[j - 1];
+ }
+ ++nT3Fonts;
+ bbox = gfxFont->getFontBBox();
+ if (bbox[0] == 0 && bbox[1] == 0 && bbox[2] == 0 && bbox[3] == 0) {
+ // unspecified bounding box -- just take a guess
+ xMin = xt - 5;
+ xMax = xMin + 30;
+ yMax = yt + 15;
+ yMin = yMax - 45;
+ validBBox = gFalse;
+ } else {
+ state->transform(bbox[0], bbox[1], &x1, &y1);
+ xMin = xMax = x1;
+ yMin = yMax = y1;
+ state->transform(bbox[0], bbox[3], &x1, &y1);
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+ state->transform(bbox[2], bbox[1], &x1, &y1);
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+ state->transform(bbox[2], bbox[3], &x1, &y1);
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+ validBBox = gTrue;
+ }
+ t3FontCache[0] = new T3FontCache(fontID, ctm[0], ctm[1], ctm[2], ctm[3],
+ (int)floor(xMin - xt),
+ (int)floor(yMin - yt),
+ (int)ceil(xMax) - (int)floor(xMin) + 3,
+ (int)ceil(yMax) - (int)floor(yMin) + 3,
+ validBBox,
+ colorMode != splashModeMono1);
+ }
+ }
+ t3Font = t3FontCache[0];
+
+ // is the glyph in the cache?
+ i = (code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc;
+ for (j = 0; j < t3Font->cacheAssoc; ++j) {
+ if (t3Font->cacheTags != NULL) {
+ if ((t3Font->cacheTags[i+j].mru & 0x8000) &&
+ t3Font->cacheTags[i+j].code == code) {
+ drawType3Glyph(t3Font, &t3Font->cacheTags[i+j],
+ t3Font->cacheData + (i+j) * t3Font->glyphSize);
+ return gTrue;
+ }
+ }
+ }
+
+ // push a new Type 3 glyph record
+ t3gs = new T3GlyphStack();
+ t3gs->next = t3GlyphStack;
+ t3GlyphStack = t3gs;
+ t3GlyphStack->code = code;
+ t3GlyphStack->cache = t3Font;
+ t3GlyphStack->cacheTag = NULL;
+ t3GlyphStack->cacheData = NULL;
+
+ return gFalse;
+}
+
+void SplashOutputDev::endType3Char(GfxState *state) {
+ T3GlyphStack *t3gs;
+ double *ctm;
+
+ if (t3GlyphStack->cacheTag) {
+ memcpy(t3GlyphStack->cacheData, bitmap->getDataPtr(),
+ t3GlyphStack->cache->glyphSize);
+ delete bitmap;
+ delete splash;
+ bitmap = t3GlyphStack->origBitmap;
+ splash = t3GlyphStack->origSplash;
+ ctm = state->getCTM();
+ state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3],
+ t3GlyphStack->origCTM4, t3GlyphStack->origCTM5);
+ updateCTM(state, 0, 0, 0, 0, 0, 0);
+ drawType3Glyph(t3GlyphStack->cache,
+ t3GlyphStack->cacheTag, t3GlyphStack->cacheData);
+ }
+ t3gs = t3GlyphStack;
+ t3GlyphStack = t3gs->next;
+ delete t3gs;
+}
+
+void SplashOutputDev::type3D0(GfxState * /*state*/, double /*wx*/, double /*wy*/) {
+}
+
+void SplashOutputDev::type3D1(GfxState *state, double /*wx*/, double /*wy*/,
+ double llx, double lly, double urx, double ury) {
+ double *ctm;
+ T3FontCache *t3Font;
+ SplashColor color;
+ double xt, yt, xMin, xMax, yMin, yMax, x1, y1;
+ int i, j;
+
+ t3Font = t3GlyphStack->cache;
+
+ // check for a valid bbox
+ state->transform(0, 0, &xt, &yt);
+ state->transform(llx, lly, &x1, &y1);
+ xMin = xMax = x1;
+ yMin = yMax = y1;
+ state->transform(llx, ury, &x1, &y1);
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+ state->transform(urx, lly, &x1, &y1);
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+ state->transform(urx, ury, &x1, &y1);
+ if (x1 < xMin) {
+ xMin = x1;
+ } else if (x1 > xMax) {
+ xMax = x1;
+ }
+ if (y1 < yMin) {
+ yMin = y1;
+ } else if (y1 > yMax) {
+ yMax = y1;
+ }
+ if (xMin - xt < t3Font->glyphX ||
+ yMin - yt < t3Font->glyphY ||
+ xMax - xt > t3Font->glyphX + t3Font->glyphW ||
+ yMax - yt > t3Font->glyphY + t3Font->glyphH) {
+ if (t3Font->validBBox) {
+ error(-1, "Bad bounding box in Type 3 glyph");
+ }
+ return;
+ }
+
+ // allocate a cache entry
+ i = (t3GlyphStack->code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc;
+ for (j = 0; j < t3Font->cacheAssoc; ++j) {
+ if ((t3Font->cacheTags[i+j].mru & 0x7fff) == t3Font->cacheAssoc - 1) {
+ t3Font->cacheTags[i+j].mru = 0x8000;
+ t3Font->cacheTags[i+j].code = t3GlyphStack->code;
+ t3GlyphStack->cacheTag = &t3Font->cacheTags[i+j];
+ t3GlyphStack->cacheData = t3Font->cacheData + (i+j) * t3Font->glyphSize;
+ } else {
+ ++t3Font->cacheTags[i+j].mru;
+ }
+ }
+
+ // save state
+ t3GlyphStack->origBitmap = bitmap;
+ t3GlyphStack->origSplash = splash;
+ ctm = state->getCTM();
+ t3GlyphStack->origCTM4 = ctm[4];
+ t3GlyphStack->origCTM5 = ctm[5];
+
+ // create the temporary bitmap
+ if (colorMode == splashModeMono1) {
+ bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, 1,
+ splashModeMono1, gFalse);
+ splash = new Splash(bitmap, gFalse,
+ t3GlyphStack->origSplash->getScreen());
+ color[0] = 0;
+ splash->clear(color);
+ color[0] = 1;
+ } else {
+ bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, 1,
+ splashModeMono8, gFalse);
+ splash = new Splash(bitmap, vectorAntialias,
+ t3GlyphStack->origSplash->getScreen());
+ color[0] = 0x00;
+ splash->clear(color);
+ color[0] = 0xff;
+ }
+ splash->setFillPattern(new SplashSolidColor(color));
+ splash->setStrokePattern(new SplashSolidColor(color));
+ //~ this should copy other state from t3GlyphStack->origSplash?
+ state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3],
+ -t3Font->glyphX, -t3Font->glyphY);
+ updateCTM(state, 0, 0, 0, 0, 0, 0);
+}
+
+void SplashOutputDev::drawType3Glyph(T3FontCache *t3Font,
+ T3FontCacheTag * /*tag*/, Guchar *data) {
+ SplashGlyphBitmap glyph;
+
+ glyph.x = -t3Font->glyphX;
+ glyph.y = -t3Font->glyphY;
+ glyph.w = t3Font->glyphW;
+ glyph.h = t3Font->glyphH;
+ glyph.aa = colorMode != splashModeMono1;
+ glyph.data = data;
+ glyph.freeData = gFalse;
+ splash->fillGlyph(0, 0, &glyph);
+}
+
+void SplashOutputDev::endTextObject(GfxState * /*state*/) {
+ if (textClipPath) {
+ splash->clipToPath(textClipPath, gFalse);
+ delete textClipPath;
+ textClipPath = NULL;
+ }
+}
+
+struct SplashOutImageMaskData {
+ ImageStream *imgStr;
+ GBool invert;
+ int width, height, y;
+};
+
+GBool SplashOutputDev::imageMaskSrc(void *data, SplashColorPtr line) {
+ SplashOutImageMaskData *imgMaskData = (SplashOutImageMaskData *)data;
+ Guchar *p;
+ SplashColorPtr q;
+ int x;
+
+ if (imgMaskData->y == imgMaskData->height) {
+ return gFalse;
+ }
+ for (x = 0, p = imgMaskData->imgStr->getLine(), q = line;
+ x < imgMaskData->width;
+ ++x) {
+ *q++ = *p++ ^ imgMaskData->invert;
+ }
+ ++imgMaskData->y;
+ return gTrue;
+}
+
+void SplashOutputDev::drawImageMask(GfxState *state, Object * /*ref*/, Stream *str,
+ int width, int height, GBool invert,
+ GBool inlineImg) {
+ double *ctm;
+ SplashCoord mat[6];
+ SplashOutImageMaskData imgMaskData;
+
+ if (state->getFillColorSpace()->isNonMarking()) {
+ return;
+ }
+
+ ctm = state->getCTM();
+ mat[0] = ctm[0];
+ mat[1] = ctm[1];
+ mat[2] = -ctm[2];
+ mat[3] = -ctm[3];
+ mat[4] = ctm[2] + ctm[4];
+ mat[5] = ctm[3] + ctm[5];
+
+ imgMaskData.imgStr = new ImageStream(str, width, 1, 1);
+ imgMaskData.imgStr->reset();
+ imgMaskData.invert = invert ? 0 : 1;
+ imgMaskData.width = width;
+ imgMaskData.height = height;
+ imgMaskData.y = 0;
+
+ splash->fillImageMask(&imageMaskSrc, &imgMaskData, width, height, mat,
+ t3GlyphStack != NULL);
+ if (inlineImg) {
+ while (imgMaskData.y < height) {
+ imgMaskData.imgStr->getLine();
+ ++imgMaskData.y;
+ }
+ }
+
+ delete imgMaskData.imgStr;
+ str->close();
+}
+
+struct SplashOutImageData {
+ ImageStream *imgStr;
+ GfxImageColorMap *colorMap;
+ SplashColorPtr lookup;
+ int *maskColors;
+ SplashColorMode colorMode;
+ int width, height, y;
+};
+
+GBool SplashOutputDev::imageSrc(void *data, SplashColorPtr colorLine,
+ Guchar * /*alphaLine*/) {
+ SplashOutImageData *imgData = (SplashOutImageData *)data;
+ Guchar *p;
+ SplashColorPtr q, col;
+ GfxRGB rgb;
+ GfxGray gray;
+#if SPLASH_CMYK
+ GfxCMYK cmyk;
+#endif
+ int nComps, x;
+
+ if (imgData->y == imgData->height) {
+ return gFalse;
+ }
+
+ nComps = imgData->colorMap->getNumPixelComps();
+
+ if (imgData->lookup) {
+ switch (imgData->colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
+ x < imgData->width;
+ ++x, ++p) {
+ *q++ = imgData->lookup[*p];
+ }
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
+ x < imgData->width;
+ ++x, ++p) {
+ col = &imgData->lookup[3 * *p];
+ *q++ = col[0];
+ *q++ = col[1];
+ *q++ = col[2];
+ }
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
+ x < imgData->width;
+ ++x, ++p) {
+ col = &imgData->lookup[4 * *p];
+ *q++ = col[0];
+ *q++ = col[1];
+ *q++ = col[2];
+ *q++ = col[3];
+ }
+ break;
+#endif
+ }
+ } else {
+ switch (imgData->colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
+ x < imgData->width;
+ ++x, p += nComps) {
+ imgData->colorMap->getGray(p, &gray);
+ *q++ = colToByte(gray);
+ }
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
+ x < imgData->width;
+ ++x, p += nComps) {
+ imgData->colorMap->getRGB(p, &rgb);
+ *q++ = colToByte(rgb.r);
+ *q++ = colToByte(rgb.g);
+ *q++ = colToByte(rgb.b);
+ }
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ for (x = 0, p = imgData->imgStr->getLine(), q = colorLine;
+ x < imgData->width;
+ ++x, p += nComps) {
+ imgData->colorMap->getCMYK(p, &cmyk);
+ *q++ = colToByte(cmyk.c);
+ *q++ = colToByte(cmyk.m);
+ *q++ = colToByte(cmyk.y);
+ *q++ = colToByte(cmyk.k);
+ }
+ break;
+#endif
+ }
+ }
+
+ ++imgData->y;
+ return gTrue;
+}
+
+GBool SplashOutputDev::alphaImageSrc(void *data, SplashColorPtr colorLine,
+ Guchar *alphaLine) {
+ SplashOutImageData *imgData = (SplashOutImageData *)data;
+ Guchar *p, *aq;
+ SplashColorPtr q, col;
+ GfxRGB rgb;
+ GfxGray gray;
+#if SPLASH_CMYK
+ GfxCMYK cmyk;
+#endif
+ Guchar alpha;
+ int nComps, x, i;
+
+ if (imgData->y == imgData->height) {
+ return gFalse;
+ }
+
+ nComps = imgData->colorMap->getNumPixelComps();
+
+ for (x = 0, p = imgData->imgStr->getLine(), q = colorLine, aq = alphaLine;
+ x < imgData->width;
+ ++x, p += nComps) {
+ alpha = 0;
+ for (i = 0; i < nComps; ++i) {
+ if (p[i] < imgData->maskColors[2*i] ||
+ p[i] > imgData->maskColors[2*i+1]) {
+ alpha = 0xff;
+ break;
+ }
+ }
+ if (imgData->lookup) {
+ switch (imgData->colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ *q++ = imgData->lookup[*p];
+ *aq++ = alpha;
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ col = &imgData->lookup[3 * *p];
+ *q++ = col[0];
+ *q++ = col[1];
+ *q++ = col[2];
+ *aq++ = alpha;
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ col = &imgData->lookup[4 * *p];
+ *q++ = col[0];
+ *q++ = col[1];
+ *q++ = col[2];
+ *q++ = col[3];
+ *aq++ = alpha;
+ break;
+#endif
+ }
+ } else {
+ switch (imgData->colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ imgData->colorMap->getGray(p, &gray);
+ *q++ = colToByte(gray);
+ *aq++ = alpha;
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ imgData->colorMap->getRGB(p, &rgb);
+ *q++ = colToByte(rgb.r);
+ *q++ = colToByte(rgb.g);
+ *q++ = colToByte(rgb.b);
+ *aq++ = alpha;
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ imgData->colorMap->getCMYK(p, &cmyk);
+ *q++ = colToByte(cmyk.c);
+ *q++ = colToByte(cmyk.m);
+ *q++ = colToByte(cmyk.y);
+ *q++ = colToByte(cmyk.k);
+ *aq++ = alpha;
+ break;
+#endif
+ }
+ }
+ }
+
+ ++imgData->y;
+ return gTrue;
+}
+
+void SplashOutputDev::drawImage(GfxState *state, Object * /*ref*/, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ int *maskColors, GBool inlineImg) {
+ double *ctm;
+ SplashCoord mat[6];
+ SplashOutImageData imgData;
+ SplashColorMode srcMode;
+ SplashImageSource src;
+ GfxGray gray;
+ GfxRGB rgb;
+#if SPLASH_CMYK
+ GfxCMYK cmyk;
+#endif
+ Guchar pix;
+ int n, i;
+
+ ctm = state->getCTM();
+ mat[0] = ctm[0];
+ mat[1] = ctm[1];
+ mat[2] = -ctm[2];
+ mat[3] = -ctm[3];
+ mat[4] = ctm[2] + ctm[4];
+ mat[5] = ctm[3] + ctm[5];
+
+ imgData.imgStr = new ImageStream(str, width,
+ colorMap->getNumPixelComps(),
+ colorMap->getBits());
+ imgData.imgStr->reset();
+ imgData.colorMap = colorMap;
+ imgData.maskColors = maskColors;
+ imgData.colorMode = colorMode;
+ imgData.width = width;
+ imgData.height = height;
+ imgData.y = 0;
+
+ // special case for one-channel (monochrome/gray/separation) images:
+ // build a lookup table here
+ imgData.lookup = NULL;
+ if (colorMap->getNumPixelComps() == 1) {
+ n = 1 << colorMap->getBits();
+ switch (colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ imgData.lookup = (SplashColorPtr)gmalloc(n);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getGray(&pix, &gray);
+ imgData.lookup[i] = colToByte(gray);
+ }
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ imgData.lookup = (SplashColorPtr)gmalloc(3 * n);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getRGB(&pix, &rgb);
+ imgData.lookup[3*i] = colToByte(rgb.r);
+ imgData.lookup[3*i+1] = colToByte(rgb.g);
+ imgData.lookup[3*i+2] = colToByte(rgb.b);
+ }
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ imgData.lookup = (SplashColorPtr)gmalloc(4 * n);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getCMYK(&pix, &cmyk);
+ imgData.lookup[4*i] = colToByte(cmyk.c);
+ imgData.lookup[4*i+1] = colToByte(cmyk.m);
+ imgData.lookup[4*i+2] = colToByte(cmyk.y);
+ imgData.lookup[4*i+3] = colToByte(cmyk.k);
+ }
+ break;
+#endif
+ break;
+ }
+ }
+
+ if (colorMode == splashModeMono1) {
+ srcMode = splashModeMono8;
+ } else {
+ srcMode = colorMode;
+ }
+ src = maskColors ? &alphaImageSrc : &imageSrc;
+ splash->drawImage(src, &imgData, srcMode, maskColors ? gTrue : gFalse,
+ width, height, mat);
+ if (inlineImg) {
+ while (imgData.y < height) {
+ imgData.imgStr->getLine();
+ ++imgData.y;
+ }
+ }
+
+ gfree(imgData.lookup);
+ delete imgData.imgStr;
+ str->close();
+}
+
+struct SplashOutMaskedImageData {
+ ImageStream *imgStr;
+ GfxImageColorMap *colorMap;
+ SplashBitmap *mask;
+ SplashColorPtr lookup;
+ SplashColorMode colorMode;
+ int width, height, y;
+};
+
+GBool SplashOutputDev::maskedImageSrc(void *data, SplashColorPtr colorLine,
+ Guchar *alphaLine) {
+ SplashOutMaskedImageData *imgData = (SplashOutMaskedImageData *)data;
+ Guchar *p, *aq;
+ SplashColor maskColor;
+ SplashColorPtr q, col;
+ GfxRGB rgb;
+ GfxGray gray;
+#if SPLASH_CMYK
+ GfxCMYK cmyk;
+#endif
+ Guchar alpha;
+ int nComps, x;
+
+ if (imgData->y == imgData->height) {
+ return gFalse;
+ }
+
+ nComps = imgData->colorMap->getNumPixelComps();
+
+ for (x = 0, p = imgData->imgStr->getLine(), q = colorLine, aq = alphaLine;
+ x < imgData->width;
+ ++x, p += nComps) {
+ imgData->mask->getPixel(x, imgData->y, maskColor);
+ alpha = maskColor[0] ? 0xff : 0x00;
+ if (imgData->lookup) {
+ switch (imgData->colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ *q++ = imgData->lookup[*p];
+ *aq++ = alpha;
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ col = &imgData->lookup[3 * *p];
+ *q++ = col[0];
+ *q++ = col[1];
+ *q++ = col[2];
+ *aq++ = alpha;
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ col = &imgData->lookup[4 * *p];
+ *q++ = col[0];
+ *q++ = col[1];
+ *q++ = col[2];
+ *q++ = col[3];
+ *aq++ = alpha;
+ break;
+#endif
+ }
+ } else {
+ switch (imgData->colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ imgData->colorMap->getGray(p, &gray);
+ *q++ = colToByte(gray);
+ *aq++ = alpha;
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ imgData->colorMap->getRGB(p, &rgb);
+ *q++ = colToByte(rgb.r);
+ *q++ = colToByte(rgb.g);
+ *q++ = colToByte(rgb.b);
+ *aq++ = alpha;
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ imgData->colorMap->getCMYK(p, &cmyk);
+ *q++ = colToByte(cmyk.c);
+ *q++ = colToByte(cmyk.m);
+ *q++ = colToByte(cmyk.y);
+ *q++ = colToByte(cmyk.k);
+ *aq++ = alpha;
+ break;
+#endif
+ }
+ }
+ }
+
+ ++imgData->y;
+ return gTrue;
+}
+
+void SplashOutputDev::drawMaskedImage(GfxState *state, Object *ref,
+ Stream *str, int width, int height,
+ GfxImageColorMap *colorMap,
+ Stream *maskStr, int maskWidth,
+ int maskHeight, GBool maskInvert) {
+ GfxImageColorMap *maskColorMap;
+ Object maskDecode, decodeLow, decodeHigh;
+ double *ctm;
+ SplashCoord mat[6];
+ SplashOutMaskedImageData imgData;
+ SplashOutImageMaskData imgMaskData;
+ SplashColorMode srcMode;
+ SplashBitmap *maskBitmap;
+ Splash *maskSplash;
+ SplashColor maskColor;
+ GfxGray gray;
+ GfxRGB rgb;
+#if SPLASH_CMYK
+ GfxCMYK cmyk;
+#endif
+ Guchar pix;
+ int n, i;
+
+ // If the mask is higher resolution than the image, use
+ // drawSoftMaskedImage() instead.
+ if (maskWidth > width || maskHeight > height) {
+ decodeLow.initInt(maskInvert ? 0 : 1);
+ decodeHigh.initInt(maskInvert ? 1 : 0);
+ maskDecode.initArray(xref);
+ maskDecode.arrayAdd(&decodeLow);
+ maskDecode.arrayAdd(&decodeHigh);
+ maskColorMap = new GfxImageColorMap(1, &maskDecode,
+ new GfxDeviceGrayColorSpace());
+ maskDecode.free();
+ drawSoftMaskedImage(state, ref, str, width, height, colorMap,
+ maskStr, maskWidth, maskHeight, maskColorMap);
+ delete maskColorMap;
+
+ } else {
+
+ //----- scale the mask image to the same size as the source image
+
+ mat[0] = (SplashCoord)width;
+ mat[1] = 0;
+ mat[2] = 0;
+ mat[3] = (SplashCoord)height;
+ mat[4] = 0;
+ mat[5] = 0;
+ imgMaskData.imgStr = new ImageStream(maskStr, maskWidth, 1, 1);
+ imgMaskData.imgStr->reset();
+ imgMaskData.invert = maskInvert ? 0 : 1;
+ imgMaskData.width = maskWidth;
+ imgMaskData.height = maskHeight;
+ imgMaskData.y = 0;
+ maskBitmap = new SplashBitmap(width, height, 1, splashModeMono1, gFalse);
+ maskSplash = new Splash(maskBitmap, gFalse);
+ maskColor[0] = 0;
+ maskSplash->clear(maskColor);
+ maskColor[0] = 0xff;
+ maskSplash->setFillPattern(new SplashSolidColor(maskColor));
+ maskSplash->fillImageMask(&imageMaskSrc, &imgMaskData,
+ maskWidth, maskHeight, mat, gFalse);
+ delete imgMaskData.imgStr;
+ maskStr->close();
+ delete maskSplash;
+
+ //----- draw the source image
+
+ ctm = state->getCTM();
+ mat[0] = ctm[0];
+ mat[1] = ctm[1];
+ mat[2] = -ctm[2];
+ mat[3] = -ctm[3];
+ mat[4] = ctm[2] + ctm[4];
+ mat[5] = ctm[3] + ctm[5];
+
+ imgData.imgStr = new ImageStream(str, width,
+ colorMap->getNumPixelComps(),
+ colorMap->getBits());
+ imgData.imgStr->reset();
+ imgData.colorMap = colorMap;
+ imgData.mask = maskBitmap;
+ imgData.colorMode = colorMode;
+ imgData.width = width;
+ imgData.height = height;
+ imgData.y = 0;
+
+ // special case for one-channel (monochrome/gray/separation) images:
+ // build a lookup table here
+ imgData.lookup = NULL;
+ if (colorMap->getNumPixelComps() == 1) {
+ n = 1 << colorMap->getBits();
+ switch (colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ imgData.lookup = (SplashColorPtr)gmalloc(n);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getGray(&pix, &gray);
+ imgData.lookup[i] = colToByte(gray);
+ }
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ imgData.lookup = (SplashColorPtr)gmalloc(3 * n);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getRGB(&pix, &rgb);
+ imgData.lookup[3*i] = colToByte(rgb.r);
+ imgData.lookup[3*i+1] = colToByte(rgb.g);
+ imgData.lookup[3*i+2] = colToByte(rgb.b);
+ }
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ imgData.lookup = (SplashColorPtr)gmalloc(4 * n);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getCMYK(&pix, &cmyk);
+ imgData.lookup[4*i] = colToByte(cmyk.c);
+ imgData.lookup[4*i+1] = colToByte(cmyk.m);
+ imgData.lookup[4*i+2] = colToByte(cmyk.y);
+ imgData.lookup[4*i+3] = colToByte(cmyk.k);
+ }
+ break;
+#endif
+ }
+ }
+
+ if (colorMode == splashModeMono1) {
+ srcMode = splashModeMono8;
+ } else {
+ srcMode = colorMode;
+ }
+ splash->drawImage(&maskedImageSrc, &imgData, srcMode, gTrue,
+ width, height, mat);
+
+ delete maskBitmap;
+ gfree(imgData.lookup);
+ delete imgData.imgStr;
+ str->close();
+ }
+}
+
+void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object * /*ref*/,
+ Stream *str, int width, int height,
+ GfxImageColorMap *colorMap,
+ Stream *maskStr,
+ int maskWidth, int maskHeight,
+ GfxImageColorMap *maskColorMap) {
+ double *ctm;
+ SplashCoord mat[6];
+ SplashOutImageData imgData;
+ SplashOutImageData imgMaskData;
+ SplashColorMode srcMode;
+ SplashBitmap *maskBitmap;
+ Splash *maskSplash;
+ SplashColor maskColor;
+ GfxGray gray;
+ GfxRGB rgb;
+#if SPLASH_CMYK
+ GfxCMYK cmyk;
+#endif
+ Guchar pix;
+ int n, i;
+
+ ctm = state->getCTM();
+ mat[0] = ctm[0];
+ mat[1] = ctm[1];
+ mat[2] = -ctm[2];
+ mat[3] = -ctm[3];
+ mat[4] = ctm[2] + ctm[4];
+ mat[5] = ctm[3] + ctm[5];
+
+ //----- set up the soft mask
+
+ imgMaskData.imgStr = new ImageStream(maskStr, maskWidth,
+ maskColorMap->getNumPixelComps(),
+ maskColorMap->getBits());
+ imgMaskData.imgStr->reset();
+ imgMaskData.colorMap = maskColorMap;
+ imgMaskData.maskColors = NULL;
+ imgMaskData.colorMode = splashModeMono8;
+ imgMaskData.width = maskWidth;
+ imgMaskData.height = maskHeight;
+ imgMaskData.y = 0;
+ n = 1 << maskColorMap->getBits();
+ imgMaskData.lookup = (SplashColorPtr)gmalloc(n);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ maskColorMap->getGray(&pix, &gray);
+ imgMaskData.lookup[i] = colToByte(gray);
+ }
+ maskBitmap = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(),
+ 1, splashModeMono8, gFalse);
+ maskSplash = new Splash(maskBitmap, vectorAntialias);
+ maskColor[0] = 0;
+ maskSplash->clear(maskColor);
+ maskSplash->drawImage(&imageSrc, &imgMaskData, splashModeMono8, gFalse,
+ maskWidth, maskHeight, mat);
+ delete imgMaskData.imgStr;
+ maskStr->close();
+ gfree(imgMaskData.lookup);
+ delete maskSplash;
+ splash->setSoftMask(maskBitmap);
+
+ //----- draw the source image
+
+ imgData.imgStr = new ImageStream(str, width,
+ colorMap->getNumPixelComps(),
+ colorMap->getBits());
+ imgData.imgStr->reset();
+ imgData.colorMap = colorMap;
+ imgData.maskColors = NULL;
+ imgData.colorMode = colorMode;
+ imgData.width = width;
+ imgData.height = height;
+ imgData.y = 0;
+
+ // special case for one-channel (monochrome/gray/separation) images:
+ // build a lookup table here
+ imgData.lookup = NULL;
+ if (colorMap->getNumPixelComps() == 1) {
+ n = 1 << colorMap->getBits();
+ switch (colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ imgData.lookup = (SplashColorPtr)gmalloc(n);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getGray(&pix, &gray);
+ imgData.lookup[i] = colToByte(gray);
+ }
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ imgData.lookup = (SplashColorPtr)gmalloc(3 * n);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getRGB(&pix, &rgb);
+ imgData.lookup[3*i] = colToByte(rgb.r);
+ imgData.lookup[3*i+1] = colToByte(rgb.g);
+ imgData.lookup[3*i+2] = colToByte(rgb.b);
+ }
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ imgData.lookup = (SplashColorPtr)gmalloc(4 * n);
+ for (i = 0; i < n; ++i) {
+ pix = (Guchar)i;
+ colorMap->getCMYK(&pix, &cmyk);
+ imgData.lookup[4*i] = colToByte(cmyk.c);
+ imgData.lookup[4*i+1] = colToByte(cmyk.m);
+ imgData.lookup[4*i+2] = colToByte(cmyk.y);
+ imgData.lookup[4*i+3] = colToByte(cmyk.k);
+ }
+ break;
+#endif
+ }
+ }
+
+ if (colorMode == splashModeMono1) {
+ srcMode = splashModeMono8;
+ } else {
+ srcMode = colorMode;
+ }
+ splash->drawImage(&imageSrc, &imgData, srcMode, gFalse, width, height, mat);
+
+ splash->setSoftMask(NULL);
+ gfree(imgData.lookup);
+ delete imgData.imgStr;
+ str->close();
+}
+
+void SplashOutputDev::beginTransparencyGroup(GfxState *state, double *bbox,
+ GfxColorSpace *blendingColorSpace,
+ GBool isolated, GBool /*knockout*/,
+ GBool /*forSoftMask*/) {
+ SplashTransparencyGroup *transpGroup;
+ SplashColor color;
+ double xMin, yMin, xMax, yMax, x, y;
+ int tx, ty, w, h;
+
+ // transform the bbox
+ state->transform(bbox[0], bbox[1], &x, &y);
+ xMin = xMax = x;
+ yMin = yMax = y;
+ state->transform(bbox[0], bbox[3], &x, &y);
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ state->transform(bbox[2], bbox[1], &x, &y);
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ state->transform(bbox[2], bbox[3], &x, &y);
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ tx = (int)floor(xMin);
+ if (tx < 0) {
+ tx = 0;
+ } else if (tx > bitmap->getWidth()) {
+ tx = bitmap->getWidth();
+ }
+ ty = (int)floor(yMin);
+ if (ty < 0) {
+ ty = 0;
+ } else if (ty > bitmap->getHeight()) {
+ ty = bitmap->getHeight();
+ }
+ w = (int)ceil(xMax) - tx + 1;
+ if (tx + w > bitmap->getWidth()) {
+ w = bitmap->getWidth() - tx;
+ }
+ if (w < 1) {
+ w = 1;
+ }
+ h = (int)ceil(yMax) - ty + 1;
+ if (ty + h > bitmap->getHeight()) {
+ h = bitmap->getHeight() - ty;
+ }
+ if (h < 1) {
+ h = 1;
+ }
+
+ // push a new stack entry
+ transpGroup = new SplashTransparencyGroup();
+ transpGroup->tx = tx;
+ transpGroup->ty = ty;
+ transpGroup->blendingColorSpace = blendingColorSpace;
+ transpGroup->isolated = isolated;
+ transpGroup->next = transpGroupStack;
+ transpGroupStack = transpGroup;
+
+ // save state
+ transpGroup->origBitmap = bitmap;
+ transpGroup->origSplash = splash;
+
+ //~ this ignores the blendingColorSpace arg
+
+ // create the temporary bitmap
+ bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode, gTrue,
+ bitmapTopDown);
+ splash = new Splash(bitmap, vectorAntialias,
+ transpGroup->origSplash->getScreen());
+ if (isolated) {
+ switch (colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ color[0] = 0;
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ color[0] = color[1] = color[2] = 0;
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ color[0] = color[1] = color[2] = color[3] = 0;
+ break;
+#endif
+ default:
+ // make gcc happy
+ break;
+ }
+ splash->clear(color, 0);
+ } else {
+ splash->blitTransparent(transpGroup->origBitmap, tx, ty, 0, 0, w, h);
+ splash->setInNonIsolatedGroup(transpGroup->origBitmap, tx, ty);
+ }
+ transpGroup->tBitmap = bitmap;
+ state->shiftCTM(-tx, -ty);
+ updateCTM(state, 0, 0, 0, 0, 0, 0);
+}
+
+void SplashOutputDev::endTransparencyGroup(GfxState *state) {
+ double *ctm;
+
+ // restore state
+ delete splash;
+ bitmap = transpGroupStack->origBitmap;
+ splash = transpGroupStack->origSplash;
+ ctm = state->getCTM();
+ state->shiftCTM(transpGroupStack->tx, transpGroupStack->ty);
+ updateCTM(state, 0, 0, 0, 0, 0, 0);
+}
+
+void SplashOutputDev::paintTransparencyGroup(GfxState * /*state*/, double * /*bbox*/) {
+ SplashBitmap *tBitmap;
+ SplashTransparencyGroup *transpGroup;
+ GBool isolated;
+ int tx, ty;
+
+ tx = transpGroupStack->tx;
+ ty = transpGroupStack->ty;
+ tBitmap = transpGroupStack->tBitmap;
+ isolated = transpGroupStack->isolated;
+
+ // paint the transparency group onto the parent bitmap
+ // - the clip path was set in the parent's state)
+ splash->composite(tBitmap, 0, 0, tx, ty,
+ tBitmap->getWidth(), tBitmap->getHeight(),
+ gFalse, !isolated);
+
+ // pop the stack
+ transpGroup = transpGroupStack;
+ transpGroupStack = transpGroup->next;
+ delete transpGroup;
+
+ delete tBitmap;
+}
+
+void SplashOutputDev::setSoftMask(GfxState * /*state*/, double * /*bbox*/,
+ GBool alpha, Function *transferFunc,
+ GfxColor *backdropColor) {
+ SplashBitmap *softMask, *tBitmap;
+ Splash *tSplash;
+ SplashTransparencyGroup *transpGroup;
+ SplashColor color;
+ SplashColorPtr p;
+ GfxGray gray;
+ GfxRGB rgb;
+#if SPLASH_CMYK
+ GfxCMYK cmyk;
+#endif
+ double lum, lum2;
+ int tx, ty, x, y;
+
+ tx = transpGroupStack->tx;
+ ty = transpGroupStack->ty;
+ tBitmap = transpGroupStack->tBitmap;
+
+ // composite with backdrop color
+ if (!alpha && colorMode != splashModeMono1) {
+ //~ need to correctly handle the case where no blending color
+ //~ space is given
+ tSplash = new Splash(tBitmap, vectorAntialias,
+ transpGroupStack->origSplash->getScreen());
+ if (transpGroupStack->blendingColorSpace) {
+ switch (colorMode) {
+ case splashModeMono1:
+ // transparency is not supported in mono1 mode
+ break;
+ case splashModeMono8:
+ transpGroupStack->blendingColorSpace->getGray(backdropColor, &gray);
+ color[0] = colToByte(gray);
+ tSplash->compositeBackground(color);
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ transpGroupStack->blendingColorSpace->getRGB(backdropColor, &rgb);
+ color[0] = colToByte(rgb.r);
+ color[1] = colToByte(rgb.g);
+ color[2] = colToByte(rgb.b);
+ tSplash->compositeBackground(color);
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ transpGroupStack->blendingColorSpace->getCMYK(backdropColor, &cmyk);
+ color[0] = colToByte(cmyk.c);
+ color[1] = colToByte(cmyk.m);
+ color[2] = colToByte(cmyk.y);
+ color[3] = colToByte(cmyk.k);
+ tSplash->compositeBackground(color);
+ break;
+#endif
+ }
+ delete tSplash;
+ }
+ }
+
+ softMask = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(),
+ 1, splashModeMono8, gFalse);
+ memset(softMask->getDataPtr(), 0,
+ softMask->getRowSize() * softMask->getHeight());
+ p = softMask->getDataPtr() + ty * softMask->getRowSize() + tx;
+ int xMax = tBitmap->getWidth();
+ int yMax = tBitmap->getHeight();
+ if (xMax + tx > bitmap->getWidth()) xMax = bitmap->getWidth() - tx;
+ if (yMax + ty > bitmap->getHeight()) yMax = bitmap->getHeight() - ty;
+ for (y = 0; y < yMax; ++y) {
+ for (x = 0; x < xMax; ++x) {
+ tBitmap->getPixel(x, y, color);
+ if (alpha) {
+ //~ unimplemented
+ } else {
+ // convert to luminosity
+ switch (colorMode) {
+ case splashModeMono1:
+ case splashModeMono8:
+ lum = color[0] / 255.0;
+ break;
+ case splashModeRGB8:
+ case splashModeBGR8:
+ lum = (0.3 / 255.0) * color[0] +
+ (0.59 / 255.0) * color[1] +
+ (0.11 / 255.0) * color[2];
+ break;
+#if SPLASH_CMYK
+ case splashModeCMYK8:
+ lum = (1 - color[3] / 255.0)
+ - (0.3 / 255.0) * color[0]
+ - (0.59 / 255.0) * color[1]
+ - (0.11 / 255.0) * color[2];
+ if (lum < 0) {
+ lum = 0;
+ }
+ break;
+#endif
+ }
+ if (transferFunc) {
+ transferFunc->transform(&lum, &lum2);
+ } else {
+ lum2 = lum;
+ }
+ p[x] = (int)(lum2 * 255.0 + 0.5);
+ }
+ }
+ p += softMask->getRowSize();
+ }
+ splash->setSoftMask(softMask);
+
+ // pop the stack
+ transpGroup = transpGroupStack;
+ transpGroupStack = transpGroup->next;
+ delete transpGroup;
+
+ delete tBitmap;
+}
+
+void SplashOutputDev::clearSoftMask(GfxState * /*state*/) {
+ splash->setSoftMask(NULL);
+}
+
+void SplashOutputDev::setPaperColor(SplashColorPtr paperColorA) {
+ splashColorCopy(paperColor, paperColorA);
+}
+
+int SplashOutputDev::getBitmapWidth() {
+ return bitmap->getWidth();
+}
+
+int SplashOutputDev::getBitmapHeight() {
+ return bitmap->getHeight();
+}
+
+SplashBitmap *SplashOutputDev::takeBitmap() {
+ SplashBitmap *ret;
+
+ ret = bitmap;
+ bitmap = new SplashBitmap(1, 1, bitmapRowPad, colorMode,
+ colorMode != splashModeMono1, bitmapTopDown);
+ return ret;
+}
+
+void SplashOutputDev::getModRegion(int *xMin, int *yMin,
+ int *xMax, int *yMax) {
+ splash->getModRegion(xMin, yMin, xMax, yMax);
+}
+
+void SplashOutputDev::clearModRegion() {
+ splash->clearModRegion();
+}
+
+void SplashOutputDev::setFillColor(int r, int g, int b) {
+ GfxRGB rgb;
+ GfxGray gray;
+#if SPLASH_CMYK
+ GfxCMYK cmyk;
+#endif
+
+ rgb.r = byteToCol(r);
+ rgb.g = byteToCol(g);
+ rgb.b = byteToCol(b);
+ gray = (GfxColorComp)(0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b + 0.5);
+ if (gray > gfxColorComp1) {
+ gray = gfxColorComp1;
+ }
+#if SPLASH_CMYK
+ cmyk.c = gfxColorComp1 - rgb.r;
+ cmyk.m = gfxColorComp1 - rgb.g;
+ cmyk.y = gfxColorComp1 - rgb.b;
+ cmyk.k = 0;
+ splash->setFillPattern(getColor(gray, &rgb, &cmyk));
+#else
+ splash->setFillPattern(getColor(gray, &rgb));
+#endif
+}
+
+SplashFont *SplashOutputDev::getFont(GString *name, double *textMatA) {
+ DisplayFontParam *dfp;
+ Ref ref;
+ SplashOutFontFileID *id;
+ SplashFontFile *fontFile;
+ SplashFont *fontObj;
+ FoFiTrueType *ff;
+ Gushort *codeToGID;
+ Unicode u;
+ SplashCoord textMat[4];
+ int cmap, i;
+
+ for (i = 0; i < 16; ++i) {
+ if (!name->cmp(splashOutSubstFonts[i].name)) {
+ break;
+ }
+ }
+ if (i == 16) {
+ return NULL;
+ }
+ ref.num = i;
+ ref.gen = -1;
+ id = new SplashOutFontFileID(&ref);
+
+ // check the font file cache
+ if ((fontFile = fontEngine->getFontFile(id))) {
+ delete id;
+
+ // load the font file
+ } else {
+ dfp = globalParams->getDisplayFont(name);
+ if (dfp && dfp->kind == displayFontT1) {
+ SplashFontSrc *fontsrc = new SplashFontSrc;
+ fontsrc->setFile(dfp->t1.fileName, gFalse);
+ fontFile = fontEngine->loadType1Font(id, fontsrc, winAnsiEncoding);
+ } else if (dfp && dfp->kind == displayFontTT) {
+ if (!(ff = FoFiTrueType::load(dfp->tt.fileName->getCString()))) {
+ return NULL;
+ }
+ for (cmap = 0; cmap < ff->getNumCmaps(); ++cmap) {
+ if ((ff->getCmapPlatform(cmap) == 3 &&
+ ff->getCmapEncoding(cmap) == 1) ||
+ ff->getCmapPlatform(cmap) == 0) {
+ break;
+ }
+ }
+ if (cmap == ff->getNumCmaps()) {
+ delete ff;
+ return NULL;
+ }
+ codeToGID = (Gushort *)gmallocn(256, sizeof(Gushort));
+ for (i = 0; i < 256; ++i) {
+ codeToGID[i] = 0;
+ if (winAnsiEncoding[i] &&
+ (u = globalParams->mapNameToUnicode(winAnsiEncoding[i]))) {
+ codeToGID[i] = ff->mapCodeToGID(cmap, u);
+ }
+ }
+ delete ff;
+ SplashFontSrc *fontsrc = new SplashFontSrc;
+ fontsrc->setFile(dfp->tt.fileName->getCString(), gFalse);
+ fontFile = fontEngine->loadTrueTypeFont(id, fontsrc, codeToGID, 256);
+ } else {
+ return NULL;
+ }
+ }
+
+ // create the scaled font
+ textMat[0] = (SplashCoord)textMatA[0];
+ textMat[1] = (SplashCoord)textMatA[1];
+ textMat[2] = (SplashCoord)textMatA[2];
+ textMat[3] = (SplashCoord)textMatA[3];
+ fontObj = fontEngine->getFont(fontFile, textMat, splash->getMatrix());
+
+ return fontObj;
+}
+
+#if 1 //~tmp: turn off anti-aliasing temporarily
+GBool SplashOutputDev::getVectorAntialias() {
+ return splash->getVectorAntialias();
+}
+
+void SplashOutputDev::setVectorAntialias(GBool vaa) {
+ splash->setVectorAntialias(vaa);
+}
+#endif
diff --git a/kpdf/xpdf/xpdf/SplashOutputDev.h b/kpdf/xpdf/xpdf/SplashOutputDev.h
new file mode 100644
index 00000000..96f270ab
--- /dev/null
+++ b/kpdf/xpdf/xpdf/SplashOutputDev.h
@@ -0,0 +1,247 @@
+//========================================================================
+//
+// SplashOutputDev.h
+//
+// Copyright 2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef SPLASHOUTPUTDEV_H
+#define SPLASHOUTPUTDEV_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "SplashTypes.h"
+#include "config.h"
+#include "OutputDev.h"
+#include "GfxState.h"
+
+class Gfx8BitFont;
+class SplashBitmap;
+class Splash;
+class SplashPath;
+class SplashPattern;
+class SplashFontEngine;
+class SplashFont;
+class T3FontCache;
+struct T3FontCacheTag;
+struct T3GlyphStack;
+struct SplashTransparencyGroup;
+
+//------------------------------------------------------------------------
+
+// number of Type 3 fonts to cache
+#define splashOutT3FontCacheSize 8
+
+//------------------------------------------------------------------------
+// SplashOutputDev
+//------------------------------------------------------------------------
+
+class SplashOutputDev: public OutputDev {
+public:
+
+ // Constructor.
+ SplashOutputDev(SplashColorMode colorModeA, int bitmapRowPadA,
+ GBool reverseVideoA, SplashColorPtr paperColorA,
+ GBool bitmapTopDownA = gTrue,
+ GBool allowAntialiasA = gTrue);
+
+ // Destructor.
+ virtual ~SplashOutputDev();
+
+ //----- get info about output device
+
+ // Does this device use upside-down coordinates?
+ // (Upside-down means (0,0) is the top left corner of the page.)
+ virtual GBool upsideDown() { return gTrue; }
+
+ // Does this device use drawChar() or drawString()?
+ virtual GBool useDrawChar() { return gTrue; }
+
+ // Does this device use beginType3Char/endType3Char? Otherwise,
+ // text in Type 3 fonts will be drawn with drawChar/drawString.
+ virtual GBool interpretType3Chars() { return gTrue; }
+
+ //----- initialization and control
+
+ // Start a page.
+ virtual void startPage(int pageNum, GfxState *state);
+
+ // End a page.
+ virtual void endPage();
+
+ //----- save/restore graphics state
+ virtual void saveState(GfxState *state);
+ virtual void restoreState(GfxState *state);
+
+ //----- update graphics state
+ virtual void updateAll(GfxState *state);
+ virtual void updateCTM(GfxState *state, double m11, double m12,
+ double m21, double m22, double m31, double m32);
+ virtual void updateLineDash(GfxState *state);
+ virtual void updateFlatness(GfxState *state);
+ virtual void updateLineJoin(GfxState *state);
+ virtual void updateLineCap(GfxState *state);
+ virtual void updateMiterLimit(GfxState *state);
+ virtual void updateLineWidth(GfxState *state);
+ virtual void updateStrokeAdjust(GfxState *state);
+ virtual void updateFillColor(GfxState *state);
+ virtual void updateStrokeColor(GfxState *state);
+ virtual void updateBlendMode(GfxState *state);
+ virtual void updateFillOpacity(GfxState *state);
+ virtual void updateStrokeOpacity(GfxState *state);
+
+ //----- update text state
+ virtual void updateFont(GfxState *state);
+
+ //----- path painting
+ virtual void stroke(GfxState *state);
+ virtual void fill(GfxState *state);
+ virtual void eoFill(GfxState *state);
+
+ //----- path clipping
+ virtual void clip(GfxState *state);
+ virtual void eoClip(GfxState *state);
+ virtual void clipToStrokePath(GfxState *state);
+
+ //----- text drawing
+ virtual void drawChar(GfxState *state, double x, double y,
+ double dx, double dy,
+ double originX, double originY,
+ CharCode code, int nBytes, Unicode *u, int uLen);
+ virtual GBool beginType3Char(GfxState *state, double x, double y,
+ double dx, double dy,
+ CharCode code, Unicode *u, int uLen);
+ virtual void endType3Char(GfxState *state);
+ virtual void endTextObject(GfxState *state);
+
+ //----- image drawing
+ virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GBool invert,
+ GBool inlineImg);
+ virtual void drawImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height, GfxImageColorMap *colorMap,
+ int *maskColors, GBool inlineImg);
+ virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ Stream *maskStr, int maskWidth, int maskHeight,
+ GBool maskInvert);
+ virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str,
+ int width, int height,
+ GfxImageColorMap *colorMap,
+ Stream *maskStr,
+ int maskWidth, int maskHeight,
+ GfxImageColorMap *maskColorMap);
+
+ //----- Type 3 font operators
+ virtual void type3D0(GfxState *state, double wx, double wy);
+ virtual void type3D1(GfxState *state, double wx, double wy,
+ double llx, double lly, double urx, double ury);
+
+ //----- transparency groups and soft masks
+ virtual void beginTransparencyGroup(GfxState *state, double *bbox,
+ GfxColorSpace *blendingColorSpace,
+ GBool isolated, GBool knockout,
+ GBool forSoftMask);
+ virtual void endTransparencyGroup(GfxState *state);
+ virtual void paintTransparencyGroup(GfxState *state, double *bbox);
+ virtual void setSoftMask(GfxState *state, double *bbox, GBool alpha,
+ Function *transferFunc, GfxColor *backdropColor);
+ virtual void clearSoftMask(GfxState *state);
+
+ //----- special access
+
+ // Called to indicate that a new PDF document has been loaded.
+ void startDoc(XRef *xrefA);
+
+ void setPaperColor(SplashColorPtr paperColorA);
+
+ GBool isReverseVideo() { return reverseVideo; }
+ void setReverseVideo(GBool reverseVideoA) { reverseVideo = reverseVideoA; }
+
+ // Get the bitmap and its size.
+ SplashBitmap *getBitmap() { return bitmap; }
+ int getBitmapWidth();
+ int getBitmapHeight();
+
+ // Returns the last rasterized bitmap, transferring ownership to the
+ // caller.
+ SplashBitmap *takeBitmap();
+
+ // Get the Splash object.
+ Splash *getSplash() { return splash; }
+
+ // Get the modified region.
+ void getModRegion(int *xMin, int *yMin, int *xMax, int *yMax);
+
+ // Clear the modified region.
+ void clearModRegion();
+
+ // Set the Splash fill color.
+ void setFillColor(int r, int g, int b);
+
+ // Get a font object for a Base-14 font, using the Latin-1 encoding.
+ SplashFont *getFont(GString *name, double *textMatA);
+
+ SplashFont *getCurrentFont() { return font; }
+
+#if 1 //~tmp: turn off anti-aliasing temporarily
+ virtual GBool getVectorAntialias();
+ virtual void setVectorAntialias(GBool vaa);
+#endif
+
+private:
+
+ void setupScreenParams(double hDPI, double vDPI);
+#if SPLASH_CMYK
+ SplashPattern *getColor(GfxGray gray, GfxRGB *rgb, GfxCMYK *cmyk);
+#else
+ SplashPattern *getColor(GfxGray gray, GfxRGB *rgb);
+#endif
+ SplashPath *convertPath(GfxState *state, GfxPath *path);
+ void doUpdateFont(GfxState *state);
+ void drawType3Glyph(T3FontCache *t3Font,
+ T3FontCacheTag *tag, Guchar *data);
+ static GBool imageMaskSrc(void *data, SplashColorPtr line);
+ static GBool imageSrc(void *data, SplashColorPtr colorLine,
+ Guchar *alphaLine);
+ static GBool alphaImageSrc(void *data, SplashColorPtr line,
+ Guchar *alphaLine);
+ static GBool maskedImageSrc(void *data, SplashColorPtr line,
+ Guchar *alphaLine);
+
+ SplashColorMode colorMode;
+ int bitmapRowPad;
+ GBool bitmapTopDown;
+ GBool allowAntialias;
+ GBool vectorAntialias;
+ GBool reverseVideo; // reverse video mode
+ SplashColor paperColor; // paper color
+ SplashScreenParams screenParams;
+
+ XRef *xref; // xref table for current document
+
+ SplashBitmap *bitmap;
+ Splash *splash;
+ SplashFontEngine *fontEngine;
+
+ T3FontCache * // Type 3 font cache
+ t3FontCache[splashOutT3FontCacheSize];
+ int nT3Fonts; // number of valid entries in t3FontCache
+ T3GlyphStack *t3GlyphStack; // Type 3 glyph context stack
+
+ SplashFont *font; // current font
+ GBool needFontUpdate; // set when the font needs to be updated
+ SplashPath *textClipPath; // clipping path built with text object
+
+ SplashTransparencyGroup * // transparency group stack
+ transpGroupStack;
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/Stream-CCITT.h b/kpdf/xpdf/xpdf/Stream-CCITT.h
new file mode 100644
index 00000000..a9b1d1ed
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Stream-CCITT.h
@@ -0,0 +1,462 @@
+#ifndef STREAM_CCITT_H
+#define STREAM_CCITT_H
+//========================================================================
+//
+// Stream-CCITT.h
+//
+// Tables for CCITT Fax decoding.
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+struct CCITTCode {
+ short bits;
+ short n;
+};
+
+#define ccittEOL -2
+
+//------------------------------------------------------------------------
+// 2D codes
+//------------------------------------------------------------------------
+
+#define twoDimPass 0
+#define twoDimHoriz 1
+#define twoDimVert0 2
+#define twoDimVertR1 3
+#define twoDimVertL1 4
+#define twoDimVertR2 5
+#define twoDimVertL2 6
+#define twoDimVertR3 7
+#define twoDimVertL3 8
+
+// 1-7 bit codes
+static CCITTCode twoDimTab1[128] = {
+ {-1, -1}, {-1, -1}, // 000000x
+ {7, twoDimVertL3}, // 0000010
+ {7, twoDimVertR3}, // 0000011
+ {6, twoDimVertL2}, {6, twoDimVertL2}, // 000010x
+ {6, twoDimVertR2}, {6, twoDimVertR2}, // 000011x
+ {4, twoDimPass}, {4, twoDimPass}, // 0001xxx
+ {4, twoDimPass}, {4, twoDimPass},
+ {4, twoDimPass}, {4, twoDimPass},
+ {4, twoDimPass}, {4, twoDimPass},
+ {3, twoDimHoriz}, {3, twoDimHoriz}, // 001xxxx
+ {3, twoDimHoriz}, {3, twoDimHoriz},
+ {3, twoDimHoriz}, {3, twoDimHoriz},
+ {3, twoDimHoriz}, {3, twoDimHoriz},
+ {3, twoDimHoriz}, {3, twoDimHoriz},
+ {3, twoDimHoriz}, {3, twoDimHoriz},
+ {3, twoDimHoriz}, {3, twoDimHoriz},
+ {3, twoDimHoriz}, {3, twoDimHoriz},
+ {3, twoDimVertL1}, {3, twoDimVertL1}, // 010xxxx
+ {3, twoDimVertL1}, {3, twoDimVertL1},
+ {3, twoDimVertL1}, {3, twoDimVertL1},
+ {3, twoDimVertL1}, {3, twoDimVertL1},
+ {3, twoDimVertL1}, {3, twoDimVertL1},
+ {3, twoDimVertL1}, {3, twoDimVertL1},
+ {3, twoDimVertL1}, {3, twoDimVertL1},
+ {3, twoDimVertL1}, {3, twoDimVertL1},
+ {3, twoDimVertR1}, {3, twoDimVertR1}, // 011xxxx
+ {3, twoDimVertR1}, {3, twoDimVertR1},
+ {3, twoDimVertR1}, {3, twoDimVertR1},
+ {3, twoDimVertR1}, {3, twoDimVertR1},
+ {3, twoDimVertR1}, {3, twoDimVertR1},
+ {3, twoDimVertR1}, {3, twoDimVertR1},
+ {3, twoDimVertR1}, {3, twoDimVertR1},
+ {3, twoDimVertR1}, {3, twoDimVertR1},
+ {1, twoDimVert0}, {1, twoDimVert0}, // 1xxxxxx
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0},
+ {1, twoDimVert0}, {1, twoDimVert0}
+};
+
+//------------------------------------------------------------------------
+// white run lengths
+//------------------------------------------------------------------------
+
+// 11-12 bit codes (upper 7 bits are 0)
+static CCITTCode whiteTab1[32] = {
+ {-1, -1}, // 00000
+ {12, ccittEOL}, // 00001
+ {-1, -1}, {-1, -1}, // 0001x
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 001xx
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 010xx
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 011xx
+ {11, 1792}, {11, 1792}, // 1000x
+ {12, 1984}, // 10010
+ {12, 2048}, // 10011
+ {12, 2112}, // 10100
+ {12, 2176}, // 10101
+ {12, 2240}, // 10110
+ {12, 2304}, // 10111
+ {11, 1856}, {11, 1856}, // 1100x
+ {11, 1920}, {11, 1920}, // 1101x
+ {12, 2368}, // 11100
+ {12, 2432}, // 11101
+ {12, 2496}, // 11110
+ {12, 2560} // 11111
+};
+
+// 1-9 bit codes
+static CCITTCode whiteTab2[512] = {
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 0000000xx
+ {8, 29}, {8, 29}, // 00000010x
+ {8, 30}, {8, 30}, // 00000011x
+ {8, 45}, {8, 45}, // 00000100x
+ {8, 46}, {8, 46}, // 00000101x
+ {7, 22}, {7, 22}, {7, 22}, {7, 22}, // 0000011xx
+ {7, 23}, {7, 23}, {7, 23}, {7, 23}, // 0000100xx
+ {8, 47}, {8, 47}, // 00001010x
+ {8, 48}, {8, 48}, // 00001011x
+ {6, 13}, {6, 13}, {6, 13}, {6, 13}, // 000011xxx
+ {6, 13}, {6, 13}, {6, 13}, {6, 13},
+ {7, 20}, {7, 20}, {7, 20}, {7, 20}, // 0001000xx
+ {8, 33}, {8, 33}, // 00010010x
+ {8, 34}, {8, 34}, // 00010011x
+ {8, 35}, {8, 35}, // 00010100x
+ {8, 36}, {8, 36}, // 00010101x
+ {8, 37}, {8, 37}, // 00010110x
+ {8, 38}, {8, 38}, // 00010111x
+ {7, 19}, {7, 19}, {7, 19}, {7, 19}, // 0001100xx
+ {8, 31}, {8, 31}, // 00011010x
+ {8, 32}, {8, 32}, // 00011011x
+ {6, 1}, {6, 1}, {6, 1}, {6, 1}, // 000111xxx
+ {6, 1}, {6, 1}, {6, 1}, {6, 1},
+ {6, 12}, {6, 12}, {6, 12}, {6, 12}, // 001000xxx
+ {6, 12}, {6, 12}, {6, 12}, {6, 12},
+ {8, 53}, {8, 53}, // 00100100x
+ {8, 54}, {8, 54}, // 00100101x
+ {7, 26}, {7, 26}, {7, 26}, {7, 26}, // 0010011xx
+ {8, 39}, {8, 39}, // 00101000x
+ {8, 40}, {8, 40}, // 00101001x
+ {8, 41}, {8, 41}, // 00101010x
+ {8, 42}, {8, 42}, // 00101011x
+ {8, 43}, {8, 43}, // 00101100x
+ {8, 44}, {8, 44}, // 00101101x
+ {7, 21}, {7, 21}, {7, 21}, {7, 21}, // 0010111xx
+ {7, 28}, {7, 28}, {7, 28}, {7, 28}, // 0011000xx
+ {8, 61}, {8, 61}, // 00110010x
+ {8, 62}, {8, 62}, // 00110011x
+ {8, 63}, {8, 63}, // 00110100x
+ {8, 0}, {8, 0}, // 00110101x
+ {8, 320}, {8, 320}, // 00110110x
+ {8, 384}, {8, 384}, // 00110111x
+ {5, 10}, {5, 10}, {5, 10}, {5, 10}, // 00111xxxx
+ {5, 10}, {5, 10}, {5, 10}, {5, 10},
+ {5, 10}, {5, 10}, {5, 10}, {5, 10},
+ {5, 10}, {5, 10}, {5, 10}, {5, 10},
+ {5, 11}, {5, 11}, {5, 11}, {5, 11}, // 01000xxxx
+ {5, 11}, {5, 11}, {5, 11}, {5, 11},
+ {5, 11}, {5, 11}, {5, 11}, {5, 11},
+ {5, 11}, {5, 11}, {5, 11}, {5, 11},
+ {7, 27}, {7, 27}, {7, 27}, {7, 27}, // 0100100xx
+ {8, 59}, {8, 59}, // 01001010x
+ {8, 60}, {8, 60}, // 01001011x
+ {9, 1472}, // 010011000
+ {9, 1536}, // 010011001
+ {9, 1600}, // 010011010
+ {9, 1728}, // 010011011
+ {7, 18}, {7, 18}, {7, 18}, {7, 18}, // 0100111xx
+ {7, 24}, {7, 24}, {7, 24}, {7, 24}, // 0101000xx
+ {8, 49}, {8, 49}, // 01010010x
+ {8, 50}, {8, 50}, // 01010011x
+ {8, 51}, {8, 51}, // 01010100x
+ {8, 52}, {8, 52}, // 01010101x
+ {7, 25}, {7, 25}, {7, 25}, {7, 25}, // 0101011xx
+ {8, 55}, {8, 55}, // 01011000x
+ {8, 56}, {8, 56}, // 01011001x
+ {8, 57}, {8, 57}, // 01011010x
+ {8, 58}, {8, 58}, // 01011011x
+ {6, 192}, {6, 192}, {6, 192}, {6, 192}, // 010111xxx
+ {6, 192}, {6, 192}, {6, 192}, {6, 192},
+ {6, 1664}, {6, 1664}, {6, 1664}, {6, 1664}, // 011000xxx
+ {6, 1664}, {6, 1664}, {6, 1664}, {6, 1664},
+ {8, 448}, {8, 448}, // 01100100x
+ {8, 512}, {8, 512}, // 01100101x
+ {9, 704}, // 011001100
+ {9, 768}, // 011001101
+ {8, 640}, {8, 640}, // 01100111x
+ {8, 576}, {8, 576}, // 01101000x
+ {9, 832}, // 011010010
+ {9, 896}, // 011010011
+ {9, 960}, // 011010100
+ {9, 1024}, // 011010101
+ {9, 1088}, // 011010110
+ {9, 1152}, // 011010111
+ {9, 1216}, // 011011000
+ {9, 1280}, // 011011001
+ {9, 1344}, // 011011010
+ {9, 1408}, // 011011011
+ {7, 256}, {7, 256}, {7, 256}, {7, 256}, // 0110111xx
+ {4, 2}, {4, 2}, {4, 2}, {4, 2}, // 0111xxxxx
+ {4, 2}, {4, 2}, {4, 2}, {4, 2},
+ {4, 2}, {4, 2}, {4, 2}, {4, 2},
+ {4, 2}, {4, 2}, {4, 2}, {4, 2},
+ {4, 2}, {4, 2}, {4, 2}, {4, 2},
+ {4, 2}, {4, 2}, {4, 2}, {4, 2},
+ {4, 2}, {4, 2}, {4, 2}, {4, 2},
+ {4, 2}, {4, 2}, {4, 2}, {4, 2},
+ {4, 3}, {4, 3}, {4, 3}, {4, 3}, // 1000xxxxx
+ {4, 3}, {4, 3}, {4, 3}, {4, 3},
+ {4, 3}, {4, 3}, {4, 3}, {4, 3},
+ {4, 3}, {4, 3}, {4, 3}, {4, 3},
+ {4, 3}, {4, 3}, {4, 3}, {4, 3},
+ {4, 3}, {4, 3}, {4, 3}, {4, 3},
+ {4, 3}, {4, 3}, {4, 3}, {4, 3},
+ {4, 3}, {4, 3}, {4, 3}, {4, 3},
+ {5, 128}, {5, 128}, {5, 128}, {5, 128}, // 10010xxxx
+ {5, 128}, {5, 128}, {5, 128}, {5, 128},
+ {5, 128}, {5, 128}, {5, 128}, {5, 128},
+ {5, 128}, {5, 128}, {5, 128}, {5, 128},
+ {5, 8}, {5, 8}, {5, 8}, {5, 8}, // 10011xxxx
+ {5, 8}, {5, 8}, {5, 8}, {5, 8},
+ {5, 8}, {5, 8}, {5, 8}, {5, 8},
+ {5, 8}, {5, 8}, {5, 8}, {5, 8},
+ {5, 9}, {5, 9}, {5, 9}, {5, 9}, // 10100xxxx
+ {5, 9}, {5, 9}, {5, 9}, {5, 9},
+ {5, 9}, {5, 9}, {5, 9}, {5, 9},
+ {5, 9}, {5, 9}, {5, 9}, {5, 9},
+ {6, 16}, {6, 16}, {6, 16}, {6, 16}, // 101010xxx
+ {6, 16}, {6, 16}, {6, 16}, {6, 16},
+ {6, 17}, {6, 17}, {6, 17}, {6, 17}, // 101011xxx
+ {6, 17}, {6, 17}, {6, 17}, {6, 17},
+ {4, 4}, {4, 4}, {4, 4}, {4, 4}, // 1011xxxxx
+ {4, 4}, {4, 4}, {4, 4}, {4, 4},
+ {4, 4}, {4, 4}, {4, 4}, {4, 4},
+ {4, 4}, {4, 4}, {4, 4}, {4, 4},
+ {4, 4}, {4, 4}, {4, 4}, {4, 4},
+ {4, 4}, {4, 4}, {4, 4}, {4, 4},
+ {4, 4}, {4, 4}, {4, 4}, {4, 4},
+ {4, 4}, {4, 4}, {4, 4}, {4, 4},
+ {4, 5}, {4, 5}, {4, 5}, {4, 5}, // 1100xxxxx
+ {4, 5}, {4, 5}, {4, 5}, {4, 5},
+ {4, 5}, {4, 5}, {4, 5}, {4, 5},
+ {4, 5}, {4, 5}, {4, 5}, {4, 5},
+ {4, 5}, {4, 5}, {4, 5}, {4, 5},
+ {4, 5}, {4, 5}, {4, 5}, {4, 5},
+ {4, 5}, {4, 5}, {4, 5}, {4, 5},
+ {4, 5}, {4, 5}, {4, 5}, {4, 5},
+ {6, 14}, {6, 14}, {6, 14}, {6, 14}, // 110100xxx
+ {6, 14}, {6, 14}, {6, 14}, {6, 14},
+ {6, 15}, {6, 15}, {6, 15}, {6, 15}, // 110101xxx
+ {6, 15}, {6, 15}, {6, 15}, {6, 15},
+ {5, 64}, {5, 64}, {5, 64}, {5, 64}, // 11011xxxx
+ {5, 64}, {5, 64}, {5, 64}, {5, 64},
+ {5, 64}, {5, 64}, {5, 64}, {5, 64},
+ {5, 64}, {5, 64}, {5, 64}, {5, 64},
+ {4, 6}, {4, 6}, {4, 6}, {4, 6}, // 1110xxxxx
+ {4, 6}, {4, 6}, {4, 6}, {4, 6},
+ {4, 6}, {4, 6}, {4, 6}, {4, 6},
+ {4, 6}, {4, 6}, {4, 6}, {4, 6},
+ {4, 6}, {4, 6}, {4, 6}, {4, 6},
+ {4, 6}, {4, 6}, {4, 6}, {4, 6},
+ {4, 6}, {4, 6}, {4, 6}, {4, 6},
+ {4, 6}, {4, 6}, {4, 6}, {4, 6},
+ {4, 7}, {4, 7}, {4, 7}, {4, 7}, // 1111xxxxx
+ {4, 7}, {4, 7}, {4, 7}, {4, 7},
+ {4, 7}, {4, 7}, {4, 7}, {4, 7},
+ {4, 7}, {4, 7}, {4, 7}, {4, 7},
+ {4, 7}, {4, 7}, {4, 7}, {4, 7},
+ {4, 7}, {4, 7}, {4, 7}, {4, 7},
+ {4, 7}, {4, 7}, {4, 7}, {4, 7},
+ {4, 7}, {4, 7}, {4, 7}, {4, 7}
+};
+
+//------------------------------------------------------------------------
+// black run lengths
+//------------------------------------------------------------------------
+
+// 10-13 bit codes (upper 6 bits are 0)
+static CCITTCode blackTab1[128] = {
+ {-1, -1}, {-1, -1}, // 000000000000x
+ {12, ccittEOL}, {12, ccittEOL}, // 000000000001x
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000001xx
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000010xx
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000011xx
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000100xx
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000101xx
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000110xx
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000111xx
+ {11, 1792}, {11, 1792}, {11, 1792}, {11, 1792}, // 00000001000xx
+ {12, 1984}, {12, 1984}, // 000000010010x
+ {12, 2048}, {12, 2048}, // 000000010011x
+ {12, 2112}, {12, 2112}, // 000000010100x
+ {12, 2176}, {12, 2176}, // 000000010101x
+ {12, 2240}, {12, 2240}, // 000000010110x
+ {12, 2304}, {12, 2304}, // 000000010111x
+ {11, 1856}, {11, 1856}, {11, 1856}, {11, 1856}, // 00000001100xx
+ {11, 1920}, {11, 1920}, {11, 1920}, {11, 1920}, // 00000001101xx
+ {12, 2368}, {12, 2368}, // 000000011100x
+ {12, 2432}, {12, 2432}, // 000000011101x
+ {12, 2496}, {12, 2496}, // 000000011110x
+ {12, 2560}, {12, 2560}, // 000000011111x
+ {10, 18}, {10, 18}, {10, 18}, {10, 18}, // 0000001000xxx
+ {10, 18}, {10, 18}, {10, 18}, {10, 18},
+ {12, 52}, {12, 52}, // 000000100100x
+ {13, 640}, // 0000001001010
+ {13, 704}, // 0000001001011
+ {13, 768}, // 0000001001100
+ {13, 832}, // 0000001001101
+ {12, 55}, {12, 55}, // 000000100111x
+ {12, 56}, {12, 56}, // 000000101000x
+ {13, 1280}, // 0000001010010
+ {13, 1344}, // 0000001010011
+ {13, 1408}, // 0000001010100
+ {13, 1472}, // 0000001010101
+ {12, 59}, {12, 59}, // 000000101011x
+ {12, 60}, {12, 60}, // 000000101100x
+ {13, 1536}, // 0000001011010
+ {13, 1600}, // 0000001011011
+ {11, 24}, {11, 24}, {11, 24}, {11, 24}, // 00000010111xx
+ {11, 25}, {11, 25}, {11, 25}, {11, 25}, // 00000011000xx
+ {13, 1664}, // 0000001100100
+ {13, 1728}, // 0000001100101
+ {12, 320}, {12, 320}, // 000000110011x
+ {12, 384}, {12, 384}, // 000000110100x
+ {12, 448}, {12, 448}, // 000000110101x
+ {13, 512}, // 0000001101100
+ {13, 576}, // 0000001101101
+ {12, 53}, {12, 53}, // 000000110111x
+ {12, 54}, {12, 54}, // 000000111000x
+ {13, 896}, // 0000001110010
+ {13, 960}, // 0000001110011
+ {13, 1024}, // 0000001110100
+ {13, 1088}, // 0000001110101
+ {13, 1152}, // 0000001110110
+ {13, 1216}, // 0000001110111
+ {10, 64}, {10, 64}, {10, 64}, {10, 64}, // 0000001111xxx
+ {10, 64}, {10, 64}, {10, 64}, {10, 64}
+};
+
+// 7-12 bit codes (upper 4 bits are 0)
+static CCITTCode blackTab2[192] = {
+ {8, 13}, {8, 13}, {8, 13}, {8, 13}, // 00000100xxxx
+ {8, 13}, {8, 13}, {8, 13}, {8, 13},
+ {8, 13}, {8, 13}, {8, 13}, {8, 13},
+ {8, 13}, {8, 13}, {8, 13}, {8, 13},
+ {11, 23}, {11, 23}, // 00000101000x
+ {12, 50}, // 000001010010
+ {12, 51}, // 000001010011
+ {12, 44}, // 000001010100
+ {12, 45}, // 000001010101
+ {12, 46}, // 000001010110
+ {12, 47}, // 000001010111
+ {12, 57}, // 000001011000
+ {12, 58}, // 000001011001
+ {12, 61}, // 000001011010
+ {12, 256}, // 000001011011
+ {10, 16}, {10, 16}, {10, 16}, {10, 16}, // 0000010111xx
+ {10, 17}, {10, 17}, {10, 17}, {10, 17}, // 0000011000xx
+ {12, 48}, // 000001100100
+ {12, 49}, // 000001100101
+ {12, 62}, // 000001100110
+ {12, 63}, // 000001100111
+ {12, 30}, // 000001101000
+ {12, 31}, // 000001101001
+ {12, 32}, // 000001101010
+ {12, 33}, // 000001101011
+ {12, 40}, // 000001101100
+ {12, 41}, // 000001101101
+ {11, 22}, {11, 22}, // 00000110111x
+ {8, 14}, {8, 14}, {8, 14}, {8, 14}, // 00000111xxxx
+ {8, 14}, {8, 14}, {8, 14}, {8, 14},
+ {8, 14}, {8, 14}, {8, 14}, {8, 14},
+ {8, 14}, {8, 14}, {8, 14}, {8, 14},
+ {7, 10}, {7, 10}, {7, 10}, {7, 10}, // 0000100xxxxx
+ {7, 10}, {7, 10}, {7, 10}, {7, 10},
+ {7, 10}, {7, 10}, {7, 10}, {7, 10},
+ {7, 10}, {7, 10}, {7, 10}, {7, 10},
+ {7, 10}, {7, 10}, {7, 10}, {7, 10},
+ {7, 10}, {7, 10}, {7, 10}, {7, 10},
+ {7, 10}, {7, 10}, {7, 10}, {7, 10},
+ {7, 10}, {7, 10}, {7, 10}, {7, 10},
+ {7, 11}, {7, 11}, {7, 11}, {7, 11}, // 0000101xxxxx
+ {7, 11}, {7, 11}, {7, 11}, {7, 11},
+ {7, 11}, {7, 11}, {7, 11}, {7, 11},
+ {7, 11}, {7, 11}, {7, 11}, {7, 11},
+ {7, 11}, {7, 11}, {7, 11}, {7, 11},
+ {7, 11}, {7, 11}, {7, 11}, {7, 11},
+ {7, 11}, {7, 11}, {7, 11}, {7, 11},
+ {7, 11}, {7, 11}, {7, 11}, {7, 11},
+ {9, 15}, {9, 15}, {9, 15}, {9, 15}, // 000011000xxx
+ {9, 15}, {9, 15}, {9, 15}, {9, 15},
+ {12, 128}, // 000011001000
+ {12, 192}, // 000011001001
+ {12, 26}, // 000011001010
+ {12, 27}, // 000011001011
+ {12, 28}, // 000011001100
+ {12, 29}, // 000011001101
+ {11, 19}, {11, 19}, // 00001100111x
+ {11, 20}, {11, 20}, // 00001101000x
+ {12, 34}, // 000011010010
+ {12, 35}, // 000011010011
+ {12, 36}, // 000011010100
+ {12, 37}, // 000011010101
+ {12, 38}, // 000011010110
+ {12, 39}, // 000011010111
+ {11, 21}, {11, 21}, // 00001101100x
+ {12, 42}, // 000011011010
+ {12, 43}, // 000011011011
+ {10, 0}, {10, 0}, {10, 0}, {10, 0}, // 0000110111xx
+ {7, 12}, {7, 12}, {7, 12}, {7, 12}, // 0000111xxxxx
+ {7, 12}, {7, 12}, {7, 12}, {7, 12},
+ {7, 12}, {7, 12}, {7, 12}, {7, 12},
+ {7, 12}, {7, 12}, {7, 12}, {7, 12},
+ {7, 12}, {7, 12}, {7, 12}, {7, 12},
+ {7, 12}, {7, 12}, {7, 12}, {7, 12},
+ {7, 12}, {7, 12}, {7, 12}, {7, 12},
+ {7, 12}, {7, 12}, {7, 12}, {7, 12}
+};
+
+// 2-6 bit codes
+static CCITTCode blackTab3[64] = {
+ {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 0000xx
+ {6, 9}, // 000100
+ {6, 8}, // 000101
+ {5, 7}, {5, 7}, // 00011x
+ {4, 6}, {4, 6}, {4, 6}, {4, 6}, // 0010xx
+ {4, 5}, {4, 5}, {4, 5}, {4, 5}, // 0011xx
+ {3, 1}, {3, 1}, {3, 1}, {3, 1}, // 010xxx
+ {3, 1}, {3, 1}, {3, 1}, {3, 1},
+ {3, 4}, {3, 4}, {3, 4}, {3, 4}, // 011xxx
+ {3, 4}, {3, 4}, {3, 4}, {3, 4},
+ {2, 3}, {2, 3}, {2, 3}, {2, 3}, // 10xxxx
+ {2, 3}, {2, 3}, {2, 3}, {2, 3},
+ {2, 3}, {2, 3}, {2, 3}, {2, 3},
+ {2, 3}, {2, 3}, {2, 3}, {2, 3},
+ {2, 2}, {2, 2}, {2, 2}, {2, 2}, // 11xxxx
+ {2, 2}, {2, 2}, {2, 2}, {2, 2},
+ {2, 2}, {2, 2}, {2, 2}, {2, 2},
+ {2, 2}, {2, 2}, {2, 2}, {2, 2}
+};
+#endif
diff --git a/kpdf/xpdf/xpdf/Stream.cc b/kpdf/xpdf/xpdf/Stream.cc
new file mode 100644
index 00000000..ab630241
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Stream.cc
@@ -0,0 +1,4697 @@
+//========================================================================
+//
+// Stream.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <limits.h>
+#ifndef WIN32
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <ctype.h>
+#include "gmem.h"
+#include "gfile.h"
+#include "config.h"
+#include "Error.h"
+#include "Object.h"
+#include "Lexer.h"
+#include "GfxState.h"
+#include "Stream.h"
+#include "JBIG2Stream.h"
+#include "JPXStream.h"
+#include "Stream-CCITT.h"
+
+#ifdef __DJGPP__
+static GBool setDJSYSFLAGS = gFalse;
+#endif
+
+#ifdef VMS
+#ifdef __GNUC__
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+#endif
+#endif
+
+//------------------------------------------------------------------------
+// Stream (base class)
+//------------------------------------------------------------------------
+
+Stream::Stream() {
+ ref = 1;
+}
+
+Stream::~Stream() {
+}
+
+void Stream::close() {
+}
+
+int Stream::getRawChar() {
+ error(-1, "Internal: called getRawChar() on non-predictor stream");
+ return EOF;
+}
+
+char *Stream::getLine(char *buf, int size) {
+ int i;
+ int c;
+
+ if (lookChar() == EOF)
+ return NULL;
+ for (i = 0; i < size - 1; ++i) {
+ c = getChar();
+ if (c == EOF || c == '\n')
+ break;
+ if (c == '\r') {
+ if ((c = lookChar()) == '\n')
+ getChar();
+ break;
+ }
+ buf[i] = c;
+ }
+ buf[i] = '\0';
+ return buf;
+}
+
+GString *Stream::getPSFilter(int /*psLevel*/, char * /*indent*/) {
+ return new GString();
+}
+
+Stream *Stream::addFilters(Object *dict) {
+ Object obj, obj2;
+ Object params, params2;
+ Stream *str;
+ int i;
+
+ str = this;
+ dict->dictLookup("Filter", &obj);
+ if (obj.isNull()) {
+ obj.free();
+ dict->dictLookup("F", &obj);
+ }
+ dict->dictLookup("DecodeParms", &params);
+ if (params.isNull()) {
+ params.free();
+ dict->dictLookup("DP", &params);
+ }
+ if (obj.isName()) {
+ str = makeFilter(obj.getName(), str, &params);
+ } else if (obj.isArray()) {
+ for (i = 0; i < obj.arrayGetLength(); ++i) {
+ obj.arrayGet(i, &obj2);
+ if (params.isArray())
+ params.arrayGet(i, &params2);
+ else
+ params2.initNull();
+ if (obj2.isName()) {
+ str = makeFilter(obj2.getName(), str, &params2);
+ } else {
+ error(getPos(), "Bad filter name");
+ str = new EOFStream(str);
+ }
+ obj2.free();
+ params2.free();
+ }
+ } else if (!obj.isNull()) {
+ error(getPos(), "Bad 'Filter' attribute in stream");
+ }
+ obj.free();
+ params.free();
+
+ return str;
+}
+
+Stream *Stream::makeFilter(char *name, Stream *str, Object *params) {
+ int pred; // parameters
+ int colors;
+ int bits;
+ int early;
+ int encoding;
+ GBool endOfLine, byteAlign, endOfBlock, black;
+ int columns, rows;
+ int colorXform;
+ Object globals, obj;
+
+ if (!strcmp(name, "ASCIIHexDecode") || !strcmp(name, "AHx")) {
+ str = new ASCIIHexStream(str);
+ } else if (!strcmp(name, "ASCII85Decode") || !strcmp(name, "A85")) {
+ str = new ASCII85Stream(str);
+ } else if (!strcmp(name, "LZWDecode") || !strcmp(name, "LZW")) {
+ pred = 1;
+ columns = 1;
+ colors = 1;
+ bits = 8;
+ early = 1;
+ if (params->isDict()) {
+ params->dictLookup("Predictor", &obj);
+ if (obj.isInt())
+ pred = obj.getInt();
+ obj.free();
+ params->dictLookup("Columns", &obj);
+ if (obj.isInt())
+ columns = obj.getInt();
+ obj.free();
+ params->dictLookup("Colors", &obj);
+ if (obj.isInt())
+ colors = obj.getInt();
+ obj.free();
+ params->dictLookup("BitsPerComponent", &obj);
+ if (obj.isInt())
+ bits = obj.getInt();
+ obj.free();
+ params->dictLookup("EarlyChange", &obj);
+ if (obj.isInt())
+ early = obj.getInt();
+ obj.free();
+ }
+ str = new LZWStream(str, pred, columns, colors, bits, early);
+ } else if (!strcmp(name, "RunLengthDecode") || !strcmp(name, "RL")) {
+ str = new RunLengthStream(str);
+ } else if (!strcmp(name, "CCITTFaxDecode") || !strcmp(name, "CCF")) {
+ encoding = 0;
+ endOfLine = gFalse;
+ byteAlign = gFalse;
+ columns = 1728;
+ rows = 0;
+ endOfBlock = gTrue;
+ black = gFalse;
+ if (params->isDict()) {
+ params->dictLookup("K", &obj);
+ if (obj.isInt()) {
+ encoding = obj.getInt();
+ }
+ obj.free();
+ params->dictLookup("EndOfLine", &obj);
+ if (obj.isBool()) {
+ endOfLine = obj.getBool();
+ }
+ obj.free();
+ params->dictLookup("EncodedByteAlign", &obj);
+ if (obj.isBool()) {
+ byteAlign = obj.getBool();
+ }
+ obj.free();
+ params->dictLookup("Columns", &obj);
+ if (obj.isInt()) {
+ columns = obj.getInt();
+ }
+ obj.free();
+ params->dictLookup("Rows", &obj);
+ if (obj.isInt()) {
+ rows = obj.getInt();
+ }
+ obj.free();
+ params->dictLookup("EndOfBlock", &obj);
+ if (obj.isBool()) {
+ endOfBlock = obj.getBool();
+ }
+ obj.free();
+ params->dictLookup("BlackIs1", &obj);
+ if (obj.isBool()) {
+ black = obj.getBool();
+ }
+ obj.free();
+ }
+ str = new CCITTFaxStream(str, encoding, endOfLine, byteAlign,
+ columns, rows, endOfBlock, black);
+ } else if (!strcmp(name, "DCTDecode") || !strcmp(name, "DCT")) {
+ colorXform = -1;
+ if (params->isDict()) {
+ if (params->dictLookup("ColorTransform", &obj)->isInt()) {
+ colorXform = obj.getInt();
+ }
+ obj.free();
+ }
+ str = new DCTStream(str, colorXform);
+ } else if (!strcmp(name, "FlateDecode") || !strcmp(name, "Fl")) {
+ pred = 1;
+ columns = 1;
+ colors = 1;
+ bits = 8;
+ if (params->isDict()) {
+ params->dictLookup("Predictor", &obj);
+ if (obj.isInt())
+ pred = obj.getInt();
+ obj.free();
+ params->dictLookup("Columns", &obj);
+ if (obj.isInt())
+ columns = obj.getInt();
+ obj.free();
+ params->dictLookup("Colors", &obj);
+ if (obj.isInt())
+ colors = obj.getInt();
+ obj.free();
+ params->dictLookup("BitsPerComponent", &obj);
+ if (obj.isInt())
+ bits = obj.getInt();
+ obj.free();
+ }
+ str = new FlateStream(str, pred, columns, colors, bits);
+ } else if (!strcmp(name, "JBIG2Decode")) {
+ if (params->isDict()) {
+ params->dictLookup("JBIG2Globals", &globals);
+ }
+ str = new JBIG2Stream(str, &globals);
+ globals.free();
+ } else if (!strcmp(name, "JPXDecode")) {
+ str = new JPXStream(str);
+ } else {
+ error(getPos(), "Unknown filter '%s'", name);
+ str = new EOFStream(str);
+ }
+ return str;
+}
+
+//------------------------------------------------------------------------
+// BaseStream
+//------------------------------------------------------------------------
+
+BaseStream::BaseStream(Object *dictA) {
+ dict = *dictA;
+}
+
+BaseStream::~BaseStream() {
+ dict.free();
+}
+
+//------------------------------------------------------------------------
+// FilterStream
+//------------------------------------------------------------------------
+
+FilterStream::FilterStream(Stream *strA) {
+ str = strA;
+}
+
+FilterStream::~FilterStream() {
+}
+
+void FilterStream::close() {
+ str->close();
+}
+
+void FilterStream::setPos(Guint /*pos*/, int /*dir*/) {
+ error(-1, "Internal: called setPos() on FilterStream");
+}
+
+//------------------------------------------------------------------------
+// ImageStream
+//------------------------------------------------------------------------
+
+ImageStream::ImageStream(Stream *strA, int widthA, int nCompsA, int nBitsA) {
+ int imgLineSize;
+
+ str = strA;
+ width = widthA;
+ nComps = nCompsA;
+ nBits = nBitsA;
+
+ nVals = width * nComps;
+ if (nBits == 1) {
+ imgLineSize = (nVals + 7) & ~7;
+ } else {
+ imgLineSize = nVals;
+ }
+ imgLine = (Guchar *)gmallocn(imgLineSize, sizeof(Guchar));
+ imgIdx = nVals;
+}
+
+ImageStream::~ImageStream() {
+ gfree(imgLine);
+}
+
+void ImageStream::reset() {
+ str->reset();
+}
+
+GBool ImageStream::getPixel(Guchar *pix) {
+ int i;
+
+ if (imgIdx >= nVals) {
+ getLine();
+ imgIdx = 0;
+ }
+ for (i = 0; i < nComps; ++i) {
+ pix[i] = imgLine[imgIdx++];
+ }
+ return gTrue;
+}
+
+Guchar *ImageStream::getLine() {
+ Gulong buf, bitMask;
+ int bits;
+ int c;
+ int i;
+
+ if (nBits == 1) {
+ for (i = 0; i < nVals; i += 8) {
+ c = str->getChar();
+ imgLine[i+0] = (Guchar)((c >> 7) & 1);
+ imgLine[i+1] = (Guchar)((c >> 6) & 1);
+ imgLine[i+2] = (Guchar)((c >> 5) & 1);
+ imgLine[i+3] = (Guchar)((c >> 4) & 1);
+ imgLine[i+4] = (Guchar)((c >> 3) & 1);
+ imgLine[i+5] = (Guchar)((c >> 2) & 1);
+ imgLine[i+6] = (Guchar)((c >> 1) & 1);
+ imgLine[i+7] = (Guchar)(c & 1);
+ }
+ } else if (nBits == 8) {
+ for (i = 0; i < nVals; ++i) {
+ imgLine[i] = str->getChar();
+ }
+ } else {
+ bitMask = (1 << nBits) - 1;
+ buf = 0;
+ bits = 0;
+ for (i = 0; i < nVals; ++i) {
+ if (bits < nBits) {
+ buf = (buf << 8) | (str->getChar() & 0xff);
+ bits += 8;
+ }
+ imgLine[i] = (Guchar)((buf >> (bits - nBits)) & bitMask);
+ bits -= nBits;
+ }
+ }
+ return imgLine;
+}
+
+void ImageStream::skipLine() {
+ int n, i;
+
+ n = (nVals * nBits + 7) >> 3;
+ for (i = 0; i < n; ++i) {
+ str->getChar();
+ }
+}
+
+//------------------------------------------------------------------------
+// StreamPredictor
+//------------------------------------------------------------------------
+
+StreamPredictor::StreamPredictor(Stream *strA, int predictorA,
+ int widthA, int nCompsA, int nBitsA) {
+ str = strA;
+ predictor = predictorA;
+ width = widthA;
+ nComps = nCompsA;
+ nBits = nBitsA;
+ predLine = NULL;
+ ok = gFalse;
+
+ nVals = width * nComps;
+ if (width <= 0 || nComps <= 0 || nBits <= 0 ||
+ nComps > gfxColorMaxComps || nBits > 16 ||
+ width >= INT_MAX / nComps ||
+ nVals >= (INT_MAX - 7) / nBits) {
+ return;
+ }
+ pixBytes = (nComps * nBits + 7) >> 3;
+ rowBytes = ((nVals * nBits + 7) >> 3) + pixBytes;
+ if (rowBytes <= 0) {
+ return;
+ }
+ predLine = (Guchar *)gmalloc(rowBytes);
+ memset(predLine, 0, rowBytes);
+ predIdx = rowBytes;
+
+ ok = gTrue;
+}
+
+StreamPredictor::~StreamPredictor() {
+ gfree(predLine);
+}
+
+int StreamPredictor::lookChar() {
+ if (predIdx >= rowBytes) {
+ if (!getNextLine()) {
+ return EOF;
+ }
+ }
+ return predLine[predIdx];
+}
+
+int StreamPredictor::getChar() {
+ if (predIdx >= rowBytes) {
+ if (!getNextLine()) {
+ return EOF;
+ }
+ }
+ return predLine[predIdx++];
+}
+
+GBool StreamPredictor::getNextLine() {
+ int curPred;
+ Guchar upLeftBuf[gfxColorMaxComps * 2 + 1];
+ int left, up, upLeft, p, pa, pb, pc;
+ int c;
+ Gulong inBuf, outBuf, bitMask;
+ int inBits, outBits;
+ int i, j, k, kk;
+
+ // get PNG optimum predictor number
+ if (predictor >= 10) {
+ if ((curPred = str->getRawChar()) == EOF) {
+ return gFalse;
+ }
+ curPred += 10;
+ } else {
+ curPred = predictor;
+ }
+
+ // read the raw line, apply PNG (byte) predictor
+ memset(upLeftBuf, 0, pixBytes + 1);
+ for (i = pixBytes; i < rowBytes; ++i) {
+ for (j = pixBytes; j > 0; --j) {
+ upLeftBuf[j] = upLeftBuf[j-1];
+ }
+ upLeftBuf[0] = predLine[i];
+ if ((c = str->getRawChar()) == EOF) {
+ if (i > pixBytes) {
+ // this ought to return false, but some (broken) PDF files
+ // contain truncated image data, and Adobe apparently reads the
+ // last partial line
+ break;
+ }
+ return gFalse;
+ }
+ switch (curPred) {
+ case 11: // PNG sub
+ predLine[i] = predLine[i - pixBytes] + (Guchar)c;
+ break;
+ case 12: // PNG up
+ predLine[i] = predLine[i] + (Guchar)c;
+ break;
+ case 13: // PNG average
+ predLine[i] = ((predLine[i - pixBytes] + predLine[i]) >> 1) +
+ (Guchar)c;
+ break;
+ case 14: // PNG Paeth
+ left = predLine[i - pixBytes];
+ up = predLine[i];
+ upLeft = upLeftBuf[pixBytes];
+ p = left + up - upLeft;
+ if ((pa = p - left) < 0)
+ pa = -pa;
+ if ((pb = p - up) < 0)
+ pb = -pb;
+ if ((pc = p - upLeft) < 0)
+ pc = -pc;
+ if (pa <= pb && pa <= pc)
+ predLine[i] = left + (Guchar)c;
+ else if (pb <= pc)
+ predLine[i] = up + (Guchar)c;
+ else
+ predLine[i] = upLeft + (Guchar)c;
+ break;
+ case 10: // PNG none
+ default: // no predictor or TIFF predictor
+ predLine[i] = (Guchar)c;
+ break;
+ }
+ }
+
+ // apply TIFF (component) predictor
+ if (predictor == 2) {
+ if (nBits == 1) {
+ inBuf = predLine[pixBytes - 1];
+ for (i = pixBytes; i < rowBytes; i += 8) {
+ // 1-bit add is just xor
+ inBuf = (inBuf << 8) | predLine[i];
+ predLine[i] ^= inBuf >> nComps;
+ }
+ } else if (nBits == 8) {
+ for (i = pixBytes; i < rowBytes; ++i) {
+ predLine[i] += predLine[i - nComps];
+ }
+ } else {
+ memset(upLeftBuf, 0, nComps + 1);
+ bitMask = (1 << nBits) - 1;
+ inBuf = outBuf = 0;
+ inBits = outBits = 0;
+ j = k = pixBytes;
+ for (i = 0; i < width; ++i) {
+ for (kk = 0; kk < nComps; ++kk) {
+ if (inBits < nBits) {
+ inBuf = (inBuf << 8) | (predLine[j++] & 0xff);
+ inBits += 8;
+ }
+ upLeftBuf[kk] = (Guchar)((upLeftBuf[kk] +
+ (inBuf >> (inBits - nBits))) & bitMask);
+ inBits -= nBits;
+ outBuf = (outBuf << nBits) | upLeftBuf[kk];
+ outBits += nBits;
+ if (outBits >= 8) {
+ predLine[k++] = (Guchar)(outBuf >> (outBits - 8));
+ outBits -= 8;
+ }
+ }
+ }
+ if (outBits > 0) {
+ predLine[k++] = (Guchar)((outBuf << (8 - outBits)) +
+ (inBuf & ((1 << (8 - outBits)) - 1)));
+ }
+ }
+ }
+
+ // reset to start of line
+ predIdx = pixBytes;
+
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
+// FileStream
+//------------------------------------------------------------------------
+
+FileStream::FileStream(FILE *fA, Guint startA, GBool limitedA,
+ Guint lengthA, Object *dictA):
+ BaseStream(dictA) {
+ f = fA;
+ start = startA;
+ limited = limitedA;
+ length = lengthA;
+ bufPtr = bufEnd = buf;
+ bufPos = start;
+ savePos = 0;
+ saved = gFalse;
+}
+
+FileStream::~FileStream() {
+ close();
+}
+
+Stream *FileStream::makeSubStream(Guint startA, GBool limitedA,
+ Guint lengthA, Object *dictA) {
+ return new FileStream(f, startA, limitedA, lengthA, dictA);
+}
+
+void FileStream::reset() {
+#if HAVE_FSEEKO
+ savePos = (Guint)ftello(f);
+ fseeko(f, start, SEEK_SET);
+#elif HAVE_FSEEK64
+ savePos = (Guint)ftell64(f);
+ fseek64(f, start, SEEK_SET);
+#else
+ savePos = (Guint)ftell(f);
+ fseek(f, start, SEEK_SET);
+#endif
+ saved = gTrue;
+ bufPtr = bufEnd = buf;
+ bufPos = start;
+}
+
+void FileStream::close() {
+ if (saved) {
+#if HAVE_FSEEKO
+ fseeko(f, savePos, SEEK_SET);
+#elif HAVE_FSEEK64
+ fseek64(f, savePos, SEEK_SET);
+#else
+ fseek(f, savePos, SEEK_SET);
+#endif
+ saved = gFalse;
+ }
+}
+
+GBool FileStream::fillBuf() {
+ int n;
+
+ bufPos += bufEnd - buf;
+ bufPtr = bufEnd = buf;
+ if (limited && bufPos >= start + length) {
+ return gFalse;
+ }
+ if (limited && bufPos + fileStreamBufSize > start + length) {
+ n = start + length - bufPos;
+ } else {
+ n = fileStreamBufSize;
+ }
+ n = fread(buf, 1, n, f);
+ bufEnd = buf + n;
+ if (bufPtr >= bufEnd) {
+ return gFalse;
+ }
+ return gTrue;
+}
+
+void FileStream::setPos(Guint pos, int dir) {
+ Guint size;
+
+ if (dir >= 0) {
+#if HAVE_FSEEKO
+ fseeko(f, pos, SEEK_SET);
+#elif HAVE_FSEEK64
+ fseek64(f, pos, SEEK_SET);
+#else
+ fseek(f, pos, SEEK_SET);
+#endif
+ bufPos = pos;
+ } else {
+#if HAVE_FSEEKO
+ fseeko(f, 0, SEEK_END);
+ size = (Guint)ftello(f);
+#elif HAVE_FSEEK64
+ fseek64(f, 0, SEEK_END);
+ size = (Guint)ftell64(f);
+#else
+ fseek(f, 0, SEEK_END);
+ size = (Guint)ftell(f);
+#endif
+ if (pos > size)
+ pos = (Guint)size;
+#ifdef __CYGWIN32__
+ //~ work around a bug in cygwin's implementation of fseek
+ rewind(f);
+#endif
+#if HAVE_FSEEKO
+ fseeko(f, -(int)pos, SEEK_END);
+ bufPos = (Guint)ftello(f);
+#elif HAVE_FSEEK64
+ fseek64(f, -(int)pos, SEEK_END);
+ bufPos = (Guint)ftell64(f);
+#else
+ fseek(f, -(int)pos, SEEK_END);
+ bufPos = (Guint)ftell(f);
+#endif
+ }
+ bufPtr = bufEnd = buf;
+}
+
+void FileStream::moveStart(int delta) {
+ start += delta;
+ bufPtr = bufEnd = buf;
+ bufPos = start;
+}
+
+//------------------------------------------------------------------------
+// MemStream
+//------------------------------------------------------------------------
+
+MemStream::MemStream(char *bufA, Guint startA, Guint lengthA, Object *dictA):
+ BaseStream(dictA) {
+ buf = bufA;
+ start = startA;
+ length = lengthA;
+ bufEnd = buf + start + length;
+ bufPtr = buf + start;
+ needFree = gFalse;
+}
+
+MemStream::~MemStream() {
+ if (needFree) {
+ gfree(buf);
+ }
+}
+
+Stream *MemStream::makeSubStream(Guint startA, GBool limited,
+ Guint lengthA, Object *dictA) {
+ MemStream *subStr;
+ Guint newLength;
+
+ if (!limited || startA + lengthA > start + length) {
+ newLength = start + length - startA;
+ } else {
+ newLength = lengthA;
+ }
+ subStr = new MemStream(buf, startA, newLength, dictA);
+ return subStr;
+}
+
+void MemStream::reset() {
+ bufPtr = buf + start;
+}
+
+void MemStream::close() {
+}
+
+void MemStream::setPos(Guint pos, int dir) {
+ Guint i;
+
+ if (dir >= 0) {
+ i = pos;
+ } else {
+ i = start + length - pos;
+ }
+ if (i < start) {
+ i = start;
+ } else if (i > start + length) {
+ i = start + length;
+ }
+ bufPtr = buf + i;
+}
+
+void MemStream::moveStart(int delta) {
+ start += delta;
+ length -= delta;
+ bufPtr = buf + start;
+}
+
+//------------------------------------------------------------------------
+// EmbedStream
+//------------------------------------------------------------------------
+
+EmbedStream::EmbedStream(Stream *strA, Object *dictA,
+ GBool limitedA, Guint lengthA):
+ BaseStream(dictA) {
+ str = strA;
+ limited = limitedA;
+ length = lengthA;
+}
+
+EmbedStream::~EmbedStream() {
+}
+
+Stream *EmbedStream::makeSubStream(Guint /*start*/, GBool /*limitedA*/,
+ Guint /*lengthA*/, Object * /*dictA*/) {
+ error(-1, "Internal: called makeSubStream() on EmbedStream");
+ return NULL;
+}
+
+int EmbedStream::getChar() {
+ if (limited && !length) {
+ return EOF;
+ }
+ --length;
+ return str->getChar();
+}
+
+int EmbedStream::lookChar() {
+ if (limited && !length) {
+ return EOF;
+ }
+ return str->lookChar();
+}
+
+void EmbedStream::setPos(Guint /*pos*/, int /*dir*/) {
+ error(-1, "Internal: called setPos() on EmbedStream");
+}
+
+Guint EmbedStream::getStart() {
+ error(-1, "Internal: called getStart() on EmbedStream");
+ return 0;
+}
+
+void EmbedStream::moveStart(int /*delta*/) {
+ error(-1, "Internal: called moveStart() on EmbedStream");
+}
+
+//------------------------------------------------------------------------
+// ASCIIHexStream
+//------------------------------------------------------------------------
+
+ASCIIHexStream::ASCIIHexStream(Stream *strA):
+ FilterStream(strA) {
+ buf = EOF;
+ eof = gFalse;
+}
+
+ASCIIHexStream::~ASCIIHexStream() {
+ delete str;
+}
+
+void ASCIIHexStream::reset() {
+ str->reset();
+ buf = EOF;
+ eof = gFalse;
+}
+
+int ASCIIHexStream::lookChar() {
+ int c1, c2, x;
+
+ if (buf != EOF)
+ return buf;
+ if (eof) {
+ buf = EOF;
+ return EOF;
+ }
+ do {
+ c1 = str->getChar();
+ } while (isspace(c1));
+ if (c1 == '>') {
+ eof = gTrue;
+ buf = EOF;
+ return buf;
+ }
+ do {
+ c2 = str->getChar();
+ } while (isspace(c2));
+ if (c2 == '>') {
+ eof = gTrue;
+ c2 = '0';
+ }
+ if (c1 >= '0' && c1 <= '9') {
+ x = (c1 - '0') << 4;
+ } else if (c1 >= 'A' && c1 <= 'F') {
+ x = (c1 - 'A' + 10) << 4;
+ } else if (c1 >= 'a' && c1 <= 'f') {
+ x = (c1 - 'a' + 10) << 4;
+ } else if (c1 == EOF) {
+ eof = gTrue;
+ x = 0;
+ } else {
+ error(getPos(), "Illegal character <%02x> in ASCIIHex stream", c1);
+ x = 0;
+ }
+ if (c2 >= '0' && c2 <= '9') {
+ x += c2 - '0';
+ } else if (c2 >= 'A' && c2 <= 'F') {
+ x += c2 - 'A' + 10;
+ } else if (c2 >= 'a' && c2 <= 'f') {
+ x += c2 - 'a' + 10;
+ } else if (c2 == EOF) {
+ eof = gTrue;
+ x = 0;
+ } else {
+ error(getPos(), "Illegal character <%02x> in ASCIIHex stream", c2);
+ }
+ buf = x & 0xff;
+ return buf;
+}
+
+GString *ASCIIHexStream::getPSFilter(int psLevel, char *indent) {
+ GString *s;
+
+ if (psLevel < 2) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
+ return NULL;
+ }
+ s->append(indent)->append("/ASCIIHexDecode filter\n");
+ return s;
+}
+
+GBool ASCIIHexStream::isBinary(GBool /*last*/) {
+ return str->isBinary(gFalse);
+}
+
+//------------------------------------------------------------------------
+// ASCII85Stream
+//------------------------------------------------------------------------
+
+ASCII85Stream::ASCII85Stream(Stream *strA):
+ FilterStream(strA) {
+ index = n = 0;
+ eof = gFalse;
+}
+
+ASCII85Stream::~ASCII85Stream() {
+ delete str;
+}
+
+void ASCII85Stream::reset() {
+ str->reset();
+ index = n = 0;
+ eof = gFalse;
+}
+
+int ASCII85Stream::lookChar() {
+ int k;
+ Gulong t;
+
+ if (index >= n) {
+ if (eof)
+ return EOF;
+ index = 0;
+ do {
+ c[0] = str->getChar();
+ } while (Lexer::isSpace(c[0]));
+ if (c[0] == '~' || c[0] == EOF) {
+ eof = gTrue;
+ n = 0;
+ return EOF;
+ } else if (c[0] == 'z') {
+ b[0] = b[1] = b[2] = b[3] = 0;
+ n = 4;
+ } else {
+ for (k = 1; k < 5; ++k) {
+ do {
+ c[k] = str->getChar();
+ } while (Lexer::isSpace(c[k]));
+ if (c[k] == '~' || c[k] == EOF)
+ break;
+ }
+ n = k - 1;
+ if (k < 5 && (c[k] == '~' || c[k] == EOF)) {
+ for (++k; k < 5; ++k)
+ c[k] = 0x21 + 84;
+ eof = gTrue;
+ }
+ t = 0;
+ for (k = 0; k < 5; ++k)
+ t = t * 85 + (c[k] - 0x21);
+ for (k = 3; k >= 0; --k) {
+ b[k] = (int)(t & 0xff);
+ t >>= 8;
+ }
+ }
+ }
+ return b[index];
+}
+
+GString *ASCII85Stream::getPSFilter(int psLevel, char *indent) {
+ GString *s;
+
+ if (psLevel < 2) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
+ return NULL;
+ }
+ s->append(indent)->append("/ASCII85Decode filter\n");
+ return s;
+}
+
+GBool ASCII85Stream::isBinary(GBool /*last*/) {
+ return str->isBinary(gFalse);
+}
+
+//------------------------------------------------------------------------
+// LZWStream
+//------------------------------------------------------------------------
+
+LZWStream::LZWStream(Stream *strA, int predictor, int columns, int colors,
+ int bits, int earlyA):
+ FilterStream(strA) {
+ if (predictor != 1) {
+ pred = new StreamPredictor(this, predictor, columns, colors, bits);
+ if (!pred->isOk()) {
+ delete pred;
+ pred = NULL;
+ }
+ } else {
+ pred = NULL;
+ }
+ early = earlyA;
+ eof = gFalse;
+ inputBits = 0;
+ clearTable();
+}
+
+LZWStream::~LZWStream() {
+ if (pred) {
+ delete pred;
+ }
+ delete str;
+}
+
+int LZWStream::getChar() {
+ if (pred) {
+ return pred->getChar();
+ }
+ if (eof) {
+ return EOF;
+ }
+ if (seqIndex >= seqLength) {
+ if (!processNextCode()) {
+ return EOF;
+ }
+ }
+ return seqBuf[seqIndex++];
+}
+
+int LZWStream::lookChar() {
+ if (pred) {
+ return pred->lookChar();
+ }
+ if (eof) {
+ return EOF;
+ }
+ if (seqIndex >= seqLength) {
+ if (!processNextCode()) {
+ return EOF;
+ }
+ }
+ return seqBuf[seqIndex];
+}
+
+int LZWStream::getRawChar() {
+ if (eof) {
+ return EOF;
+ }
+ if (seqIndex >= seqLength) {
+ if (!processNextCode()) {
+ return EOF;
+ }
+ }
+ return seqBuf[seqIndex++];
+}
+
+void LZWStream::reset() {
+ str->reset();
+ eof = gFalse;
+ inputBits = 0;
+ clearTable();
+}
+
+GBool LZWStream::processNextCode() {
+ int code;
+ int nextLength;
+ int i, j;
+
+ // check for EOF
+ if (eof) {
+ return gFalse;
+ }
+
+ // check for eod and clear-table codes
+ start:
+ code = getCode();
+ if (code == EOF || code == 257) {
+ eof = gTrue;
+ return gFalse;
+ }
+ if (code == 256) {
+ clearTable();
+ goto start;
+ }
+ if (nextCode >= 4097) {
+ error(getPos(), "Bad LZW stream - expected clear-table code");
+ clearTable();
+ }
+
+ // process the next code
+ nextLength = seqLength + 1;
+ if (code < 256) {
+ seqBuf[0] = code;
+ seqLength = 1;
+ } else if (code < nextCode) {
+ seqLength = table[code].length;
+ for (i = seqLength - 1, j = code; i > 0; --i) {
+ seqBuf[i] = table[j].tail;
+ j = table[j].head;
+ }
+ seqBuf[0] = j;
+ } else if (code == nextCode) {
+ seqBuf[seqLength] = newChar;
+ ++seqLength;
+ } else {
+ error(getPos(), "Bad LZW stream - unexpected code");
+ eof = gTrue;
+ return gFalse;
+ }
+ newChar = seqBuf[0];
+ if (first) {
+ first = gFalse;
+ } else {
+ table[nextCode].length = nextLength;
+ table[nextCode].head = prevCode;
+ table[nextCode].tail = newChar;
+ ++nextCode;
+ if (nextCode + early == 512)
+ nextBits = 10;
+ else if (nextCode + early == 1024)
+ nextBits = 11;
+ else if (nextCode + early == 2048)
+ nextBits = 12;
+ }
+ prevCode = code;
+
+ // reset buffer
+ seqIndex = 0;
+
+ return gTrue;
+}
+
+void LZWStream::clearTable() {
+ nextCode = 258;
+ nextBits = 9;
+ seqIndex = seqLength = 0;
+ first = gTrue;
+}
+
+int LZWStream::getCode() {
+ int c;
+ int code;
+
+ while (inputBits < nextBits) {
+ if ((c = str->getChar()) == EOF)
+ return EOF;
+ inputBuf = (inputBuf << 8) | (c & 0xff);
+ inputBits += 8;
+ }
+ code = (inputBuf >> (inputBits - nextBits)) & ((1 << nextBits) - 1);
+ inputBits -= nextBits;
+ return code;
+}
+
+GString *LZWStream::getPSFilter(int psLevel, char *indent) {
+ GString *s;
+
+ if (psLevel < 2 || pred) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
+ return NULL;
+ }
+ s->append(indent)->append("<< ");
+ if (!early) {
+ s->append("/EarlyChange 0 ");
+ }
+ s->append(">> /LZWDecode filter\n");
+ return s;
+}
+
+GBool LZWStream::isBinary(GBool /*last*/) {
+ return str->isBinary(gTrue);
+}
+
+//------------------------------------------------------------------------
+// RunLengthStream
+//------------------------------------------------------------------------
+
+RunLengthStream::RunLengthStream(Stream *strA):
+ FilterStream(strA) {
+ bufPtr = bufEnd = buf;
+ eof = gFalse;
+}
+
+RunLengthStream::~RunLengthStream() {
+ delete str;
+}
+
+void RunLengthStream::reset() {
+ str->reset();
+ bufPtr = bufEnd = buf;
+ eof = gFalse;
+}
+
+GString *RunLengthStream::getPSFilter(int psLevel, char *indent) {
+ GString *s;
+
+ if (psLevel < 2) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
+ return NULL;
+ }
+ s->append(indent)->append("/RunLengthDecode filter\n");
+ return s;
+}
+
+GBool RunLengthStream::isBinary(GBool /*last*/) {
+ return str->isBinary(gTrue);
+}
+
+GBool RunLengthStream::fillBuf() {
+ int c;
+ int n, i;
+
+ if (eof)
+ return gFalse;
+ c = str->getChar();
+ if (c == 0x80 || c == EOF) {
+ eof = gTrue;
+ return gFalse;
+ }
+ if (c < 0x80) {
+ n = c + 1;
+ for (i = 0; i < n; ++i)
+ buf[i] = (char)str->getChar();
+ } else {
+ n = 0x101 - c;
+ c = str->getChar();
+ for (i = 0; i < n; ++i)
+ buf[i] = (char)c;
+ }
+ bufPtr = buf;
+ bufEnd = buf + n;
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
+// CCITTFaxStream
+//------------------------------------------------------------------------
+
+CCITTFaxStream::CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA,
+ GBool byteAlignA, int columnsA, int rowsA,
+ GBool endOfBlockA, GBool blackA):
+ FilterStream(strA) {
+ encoding = encodingA;
+ endOfLine = endOfLineA;
+ byteAlign = byteAlignA;
+ columns = columnsA;
+ if (columns < 1) {
+ columns = 1;
+ } else if (columns > INT_MAX - 2) {
+ columns = INT_MAX - 2;
+ }
+ rows = rowsA;
+ endOfBlock = endOfBlockA;
+ black = blackA;
+ // 0 <= codingLine[0] < codingLine[1] < ... < codingLine[n] = columns
+ // ---> max codingLine size = columns + 1
+ // refLine has one extra guard entry at the end
+ // ---> max refLine size = columns + 2
+ codingLine = (int *)gmallocn_checkoverflow(columns + 1, sizeof(int));
+ refLine = (int *)gmallocn_checkoverflow(columns + 2, sizeof(int));
+
+ if (codingLine != NULL && refLine != NULL) {
+ eof = gFalse;
+ codingLine[0] = columns;
+ } else {
+ eof = gTrue;
+ }
+ row = 0;
+ nextLine2D = encoding < 0;
+ inputBits = 0;
+ a0i = 0;
+ outputBits = 0;
+
+ buf = EOF;
+}
+
+CCITTFaxStream::~CCITTFaxStream() {
+ delete str;
+ gfree(refLine);
+ gfree(codingLine);
+}
+
+void CCITTFaxStream::reset() {
+ short code1;
+
+ str->reset();
+
+ if (codingLine != NULL && refLine != NULL) {
+ eof = gFalse;
+ codingLine[0] = columns;
+ } else {
+ eof = gTrue;
+ }
+ row = 0;
+ nextLine2D = encoding < 0;
+ inputBits = 0;
+ a0i = 0;
+ outputBits = 0;
+ buf = EOF;
+
+ // skip any initial zero bits and end-of-line marker, and get the 2D
+ // encoding tag
+ while ((code1 = lookBits(12)) == 0) {
+ eatBits(1);
+ }
+ if (code1 == 0x001) {
+ eatBits(12);
+ }
+ if (encoding > 0) {
+ nextLine2D = !lookBits(1);
+ eatBits(1);
+ }
+}
+
+inline void CCITTFaxStream::addPixels(int a1, int blackPixels) {
+ if (a1 > codingLine[a0i]) {
+ if (a1 > columns) {
+ error(getPos(), "CCITTFax row is wrong length (%d)", a1);
+ err = gTrue;
+ a1 = columns;
+ }
+ if ((a0i & 1) ^ blackPixels) {
+ ++a0i;
+ }
+ codingLine[a0i] = a1;
+ }
+}
+
+inline void CCITTFaxStream::addPixelsNeg(int a1, int blackPixels) {
+ if (a1 > codingLine[a0i]) {
+ if (a1 > columns) {
+ error(getPos(), "CCITTFax row is wrong length (%d)", a1);
+ err = gTrue;
+ a1 = columns;
+ }
+ if ((a0i & 1) ^ blackPixels) {
+ ++a0i;
+ }
+ codingLine[a0i] = a1;
+ } else if (a1 < codingLine[a0i]) {
+ if (a1 < 0) {
+ error(getPos(), "Invalid CCITTFax code");
+ err = gTrue;
+ a1 = 0;
+ }
+ while (a0i > 0 && a1 <= codingLine[a0i - 1]) {
+ --a0i;
+ }
+ codingLine[a0i] = a1;
+ }
+}
+
+int CCITTFaxStream::lookChar() {
+ short code1, code2, code3;
+ int b1i, blackPixels, i, bits;
+ GBool gotEOL;
+
+ if (buf != EOF) {
+ return buf;
+ }
+
+ // read the next row
+ if (outputBits == 0) {
+
+ // if at eof just return EOF
+ if (eof) {
+ return EOF;
+ }
+
+ err = gFalse;
+
+ // 2-D encoding
+ if (nextLine2D) {
+ for (i = 0; codingLine[i] < columns; ++i) {
+ refLine[i] = codingLine[i];
+ }
+ refLine[i++] = columns;
+ refLine[i] = columns;
+ codingLine[0] = 0;
+ a0i = 0;
+ b1i = 0;
+ blackPixels = 0;
+ // invariant:
+ // refLine[b1i-1] <= codingLine[a0i] < refLine[b1i] < refLine[b1i+1]
+ // <= columns
+ // exception at left edge:
+ // codingLine[a0i = 0] = refLine[b1i = 0] = 0 is possible
+ // exception at right edge:
+ // refLine[b1i] = refLine[b1i+1] = columns is possible
+ while (codingLine[a0i] < columns) {
+ code1 = getTwoDimCode();
+ switch (code1) {
+ case twoDimPass:
+ addPixels(refLine[b1i + 1], blackPixels);
+ if (refLine[b1i + 1] < columns) {
+ b1i += 2;
+ }
+ break;
+ case twoDimHoriz:
+ code1 = code2 = 0;
+ if (blackPixels) {
+ do {
+ code1 += code3 = getBlackCode();
+ } while (code3 >= 64);
+ do {
+ code2 += code3 = getWhiteCode();
+ } while (code3 >= 64);
+ } else {
+ do {
+ code1 += code3 = getWhiteCode();
+ } while (code3 >= 64);
+ do {
+ code2 += code3 = getBlackCode();
+ } while (code3 >= 64);
+ }
+ addPixels(codingLine[a0i] + code1, blackPixels);
+ if (codingLine[a0i] < columns) {
+ addPixels(codingLine[a0i] + code2, blackPixels ^ 1);
+ }
+ while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) {
+ b1i += 2;
+ }
+ break;
+ case twoDimVertR3:
+ addPixels(refLine[b1i] + 3, blackPixels);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < columns) {
+ ++b1i;
+ while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) {
+ b1i += 2;
+ }
+ }
+ break;
+ case twoDimVertR2:
+ addPixels(refLine[b1i] + 2, blackPixels);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < columns) {
+ ++b1i;
+ while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) {
+ b1i += 2;
+ }
+ }
+ break;
+ case twoDimVertR1:
+ addPixels(refLine[b1i] + 1, blackPixels);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < columns) {
+ ++b1i;
+ while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) {
+ b1i += 2;
+ }
+ }
+ break;
+ case twoDimVert0:
+ addPixels(refLine[b1i], blackPixels);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < columns) {
+ ++b1i;
+ while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) {
+ b1i += 2;
+ }
+ }
+ break;
+ case twoDimVertL3:
+ addPixelsNeg(refLine[b1i] - 3, blackPixels);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < columns) {
+ if (b1i > 0) {
+ --b1i;
+ } else {
+ ++b1i;
+ }
+ while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) {
+ b1i += 2;
+ }
+ }
+ break;
+ case twoDimVertL2:
+ addPixelsNeg(refLine[b1i] - 2, blackPixels);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < columns) {
+ if (b1i > 0) {
+ --b1i;
+ } else {
+ ++b1i;
+ }
+ while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) {
+ b1i += 2;
+ }
+ }
+ break;
+ case twoDimVertL1:
+ addPixelsNeg(refLine[b1i] - 1, blackPixels);
+ blackPixels ^= 1;
+ if (codingLine[a0i] < columns) {
+ if (b1i > 0) {
+ --b1i;
+ } else {
+ ++b1i;
+ }
+ while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) {
+ b1i += 2;
+ }
+ }
+ break;
+ case EOF:
+ addPixels(columns, 0);
+ eof = gTrue;
+ break;
+ default:
+ error(getPos(), "Bad 2D code %04x in CCITTFax stream", code1);
+ addPixels(columns, 0);
+ err = gTrue;
+ break;
+ }
+ }
+
+ // 1-D encoding
+ } else {
+ codingLine[0] = 0;
+ a0i = 0;
+ blackPixels = 0;
+ while (codingLine[a0i] < columns) {
+ code1 = 0;
+ if (blackPixels) {
+ do {
+ code1 += code3 = getBlackCode();
+ } while (code3 >= 64);
+ } else {
+ do {
+ code1 += code3 = getWhiteCode();
+ } while (code3 >= 64);
+ }
+ addPixels(codingLine[a0i] + code1, blackPixels);
+ blackPixels ^= 1;
+ }
+ }
+
+ // byte-align the row
+ if (byteAlign) {
+ inputBits &= ~7;
+ }
+
+ // check for end-of-line marker, skipping over any extra zero bits
+ gotEOL = gFalse;
+ if (!endOfBlock && row == rows - 1) {
+ eof = gTrue;
+ } else {
+ code1 = lookBits(12);
+ while (code1 == 0) {
+ eatBits(1);
+ code1 = lookBits(12);
+ }
+ if (code1 == 0x001) {
+ eatBits(12);
+ gotEOL = gTrue;
+ } else if (code1 == EOF) {
+ eof = gTrue;
+ }
+ }
+
+ // get 2D encoding tag
+ if (!eof && encoding > 0) {
+ nextLine2D = !lookBits(1);
+ eatBits(1);
+ }
+
+ // check for end-of-block marker
+ if (endOfBlock && gotEOL) {
+ code1 = lookBits(12);
+ if (code1 == 0x001) {
+ eatBits(12);
+ if (encoding > 0) {
+ lookBits(1);
+ eatBits(1);
+ }
+ if (encoding >= 0) {
+ for (i = 0; i < 4; ++i) {
+ code1 = lookBits(12);
+ if (code1 != 0x001) {
+ error(getPos(), "Bad RTC code in CCITTFax stream");
+ }
+ eatBits(12);
+ if (encoding > 0) {
+ lookBits(1);
+ eatBits(1);
+ }
+ }
+ }
+ eof = gTrue;
+ }
+
+ // look for an end-of-line marker after an error -- we only do
+ // this if we know the stream contains end-of-line markers because
+ // the "just plow on" technique tends to work better otherwise
+ } else if (err && endOfLine) {
+ while (1) {
+ code1 = lookBits(13);
+ if (code1 == EOF) {
+ eof = gTrue;
+ return EOF;
+ }
+ if ((code1 >> 1) == 0x001) {
+ break;
+ }
+ eatBits(1);
+ }
+ eatBits(12);
+ if (encoding > 0) {
+ eatBits(1);
+ nextLine2D = !(code1 & 1);
+ }
+ }
+
+ // set up for output
+ if (codingLine[0] > 0) {
+ outputBits = codingLine[a0i = 0];
+ } else {
+ outputBits = codingLine[a0i = 1];
+ }
+
+ ++row;
+ }
+
+ // get a byte
+ if (outputBits >= 8) {
+ buf = (a0i & 1) ? 0x00 : 0xff;
+ outputBits -= 8;
+ if (outputBits == 0 && codingLine[a0i] < columns) {
+ ++a0i;
+ outputBits = codingLine[a0i] - codingLine[a0i - 1];
+ }
+ } else {
+ bits = 8;
+ buf = 0;
+ do {
+ if (outputBits > bits) {
+ buf <<= bits;
+ if (!(a0i & 1)) {
+ buf |= 0xff >> (8 - bits);
+ }
+ outputBits -= bits;
+ bits = 0;
+ } else {
+ buf <<= outputBits;
+ if (!(a0i & 1)) {
+ buf |= 0xff >> (8 - outputBits);
+ }
+ bits -= outputBits;
+ outputBits = 0;
+ if (codingLine[a0i] < columns) {
+ ++a0i;
+ outputBits = codingLine[a0i] - codingLine[a0i - 1];
+ } else if (bits > 0) {
+ buf <<= bits;
+ bits = 0;
+ }
+ }
+ } while (bits);
+ }
+ if (black) {
+ buf ^= 0xff;
+ }
+ return buf;
+}
+
+short CCITTFaxStream::getTwoDimCode() {
+ short code;
+ CCITTCode *p;
+ int n;
+
+ code = 0; // make gcc happy
+ if (endOfBlock) {
+ code = lookBits(7);
+ p = &twoDimTab1[code];
+ if (p->bits > 0) {
+ eatBits(p->bits);
+ return p->n;
+ }
+ } else {
+ for (n = 1; n <= 7; ++n) {
+ code = lookBits(n);
+ if (n < 7) {
+ code <<= 7 - n;
+ }
+ p = &twoDimTab1[code];
+ if (p->bits == n) {
+ eatBits(n);
+ return p->n;
+ }
+ }
+ }
+ error(getPos(), "Bad two dim code (%04x) in CCITTFax stream", code);
+ return EOF;
+}
+
+short CCITTFaxStream::getWhiteCode() {
+ short code;
+ CCITTCode *p;
+ int n;
+
+ code = 0; // make gcc happy
+ if (endOfBlock) {
+ code = lookBits(12);
+ if (code == EOF) {
+ return 1;
+ }
+ if ((code >> 5) == 0) {
+ p = &whiteTab1[code];
+ } else {
+ p = &whiteTab2[code >> 3];
+ }
+ if (p->bits > 0) {
+ eatBits(p->bits);
+ return p->n;
+ }
+ } else {
+ for (n = 1; n <= 9; ++n) {
+ code = lookBits(n);
+ if (code == EOF) {
+ return 1;
+ }
+ if (n < 9) {
+ code <<= 9 - n;
+ }
+ p = &whiteTab2[code];
+ if (p->bits == n) {
+ eatBits(n);
+ return p->n;
+ }
+ }
+ for (n = 11; n <= 12; ++n) {
+ code = lookBits(n);
+ if (code == EOF) {
+ return 1;
+ }
+ if (n < 12) {
+ code <<= 12 - n;
+ }
+ p = &whiteTab1[code];
+ if (p->bits == n) {
+ eatBits(n);
+ return p->n;
+ }
+ }
+ }
+ error(getPos(), "Bad white code (%04x) in CCITTFax stream", code);
+ // eat a bit and return a positive number so that the caller doesn't
+ // go into an infinite loop
+ eatBits(1);
+ return 1;
+}
+
+short CCITTFaxStream::getBlackCode() {
+ short code;
+ CCITTCode *p;
+ int n;
+
+ code = 0; // make gcc happy
+ if (endOfBlock) {
+ code = lookBits(13);
+ if (code == EOF) {
+ return 1;
+ }
+ if ((code >> 7) == 0) {
+ p = &blackTab1[code];
+ } else if ((code >> 9) == 0 && (code >> 7) != 0) {
+ p = &blackTab2[(code >> 1) - 64];
+ } else {
+ p = &blackTab3[code >> 7];
+ }
+ if (p->bits > 0) {
+ eatBits(p->bits);
+ return p->n;
+ }
+ } else {
+ for (n = 2; n <= 6; ++n) {
+ code = lookBits(n);
+ if (code == EOF) {
+ return 1;
+ }
+ if (n < 6) {
+ code <<= 6 - n;
+ }
+ p = &blackTab3[code];
+ if (p->bits == n) {
+ eatBits(n);
+ return p->n;
+ }
+ }
+ for (n = 7; n <= 12; ++n) {
+ code = lookBits(n);
+ if (code == EOF) {
+ return 1;
+ }
+ if (n < 12) {
+ code <<= 12 - n;
+ }
+ if (code >= 64) {
+ p = &blackTab2[code - 64];
+ if (p->bits == n) {
+ eatBits(n);
+ return p->n;
+ }
+ }
+ }
+ for (n = 10; n <= 13; ++n) {
+ code = lookBits(n);
+ if (code == EOF) {
+ return 1;
+ }
+ if (n < 13) {
+ code <<= 13 - n;
+ }
+ p = &blackTab1[code];
+ if (p->bits == n) {
+ eatBits(n);
+ return p->n;
+ }
+ }
+ }
+ error(getPos(), "Bad black code (%04x) in CCITTFax stream", code);
+ // eat a bit and return a positive number so that the caller doesn't
+ // go into an infinite loop
+ eatBits(1);
+ return 1;
+}
+
+short CCITTFaxStream::lookBits(int n) {
+ int c;
+
+ while (inputBits < n) {
+ if ((c = str->getChar()) == EOF) {
+ if (inputBits == 0) {
+ return EOF;
+ }
+ // near the end of the stream, the caller may ask for more bits
+ // than are available, but there may still be a valid code in
+ // however many bits are available -- we need to return correct
+ // data in this case
+ return (inputBuf << (n - inputBits)) & (0xffff >> (16 - n));
+ }
+ inputBuf = (inputBuf << 8) + c;
+ inputBits += 8;
+ }
+ return (inputBuf >> (inputBits - n)) & (0xffff >> (16 - n));
+}
+
+GString *CCITTFaxStream::getPSFilter(int psLevel, char *indent) {
+ GString *s;
+ char s1[50];
+
+ if (psLevel < 2) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
+ return NULL;
+ }
+ s->append(indent)->append("<< ");
+ if (encoding != 0) {
+ sprintf(s1, "/K %d ", encoding);
+ s->append(s1);
+ }
+ if (endOfLine) {
+ s->append("/EndOfLine true ");
+ }
+ if (byteAlign) {
+ s->append("/EncodedByteAlign true ");
+ }
+ sprintf(s1, "/Columns %d ", columns);
+ s->append(s1);
+ if (rows != 0) {
+ sprintf(s1, "/Rows %d ", rows);
+ s->append(s1);
+ }
+ if (!endOfBlock) {
+ s->append("/EndOfBlock false ");
+ }
+ if (black) {
+ s->append("/BlackIs1 true ");
+ }
+ s->append(">> /CCITTFaxDecode filter\n");
+ return s;
+}
+
+GBool CCITTFaxStream::isBinary(GBool /*last*/) {
+ return str->isBinary(gTrue);
+}
+
+//------------------------------------------------------------------------
+// DCTStream
+//------------------------------------------------------------------------
+
+// IDCT constants (20.12 fixed point format)
+#define dctCos1 4017 // cos(pi/16)
+#define dctSin1 799 // sin(pi/16)
+#define dctCos3 3406 // cos(3*pi/16)
+#define dctSin3 2276 // sin(3*pi/16)
+#define dctCos6 1567 // cos(6*pi/16)
+#define dctSin6 3784 // sin(6*pi/16)
+#define dctSqrt2 5793 // sqrt(2)
+#define dctSqrt1d2 2896 // sqrt(2) / 2
+
+// color conversion parameters (16.16 fixed point format)
+#define dctCrToR 91881 // 1.4020
+#define dctCbToG -22553 // -0.3441363
+#define dctCrToG -46802 // -0.71413636
+#define dctCbToB 116130 // 1.772
+
+// clip [-256,511] --> [0,255]
+#define dctClipOffset 256
+static Guchar dctClip[768];
+static int dctClipInit = 0;
+
+// zig zag decode map
+static int dctZigZag[64] = {
+ 0,
+ 1, 8,
+ 16, 9, 2,
+ 3, 10, 17, 24,
+ 32, 25, 18, 11, 4,
+ 5, 12, 19, 26, 33, 40,
+ 48, 41, 34, 27, 20, 13, 6,
+ 7, 14, 21, 28, 35, 42, 49, 56,
+ 57, 50, 43, 36, 29, 22, 15,
+ 23, 30, 37, 44, 51, 58,
+ 59, 52, 45, 38, 31,
+ 39, 46, 53, 60,
+ 61, 54, 47,
+ 55, 62,
+ 63
+};
+
+DCTStream::DCTStream(Stream *strA, GBool colorXformA):
+ FilterStream(strA) {
+ int i, j;
+
+ colorXform = colorXformA;
+ progressive = interleaved = gFalse;
+ width = height = 0;
+ mcuWidth = mcuHeight = 0;
+ numComps = 0;
+ comp = 0;
+ x = y = dy = 0;
+ for (i = 0; i < 4; ++i) {
+ for (j = 0; j < 32; ++j) {
+ rowBuf[i][j] = NULL;
+ }
+ frameBuf[i] = NULL;
+ }
+
+ if (!dctClipInit) {
+ for (i = -256; i < 0; ++i)
+ dctClip[dctClipOffset + i] = 0;
+ for (i = 0; i < 256; ++i)
+ dctClip[dctClipOffset + i] = i;
+ for (i = 256; i < 512; ++i)
+ dctClip[dctClipOffset + i] = 255;
+ dctClipInit = 1;
+ }
+}
+
+DCTStream::~DCTStream() {
+ close();
+ delete str;
+}
+
+void DCTStream::reset() {
+ int i, j;
+
+ str->reset();
+
+ progressive = interleaved = gFalse;
+ width = height = 0;
+ numComps = 0;
+ numQuantTables = 0;
+ numDCHuffTables = 0;
+ numACHuffTables = 0;
+ gotJFIFMarker = gFalse;
+ gotAdobeMarker = gFalse;
+ restartInterval = 0;
+
+ if (!readHeader()) {
+ y = height;
+ return;
+ }
+
+ // compute MCU size
+ if (numComps == 1) {
+ compInfo[0].hSample = compInfo[0].vSample = 1;
+ }
+ mcuWidth = compInfo[0].hSample;
+ mcuHeight = compInfo[0].vSample;
+ for (i = 1; i < numComps; ++i) {
+ if (compInfo[i].hSample > mcuWidth) {
+ mcuWidth = compInfo[i].hSample;
+ }
+ if (compInfo[i].vSample > mcuHeight) {
+ mcuHeight = compInfo[i].vSample;
+ }
+ }
+ mcuWidth *= 8;
+ mcuHeight *= 8;
+
+ // figure out color transform
+ if (colorXform == -1) {
+ if (numComps == 3) {
+ if (gotJFIFMarker) {
+ colorXform = 1;
+ } else if (compInfo[0].id == 82 && compInfo[1].id == 71 &&
+ compInfo[2].id == 66) { // ASCII "RGB"
+ colorXform = 0;
+ } else {
+ colorXform = 1;
+ }
+ } else {
+ colorXform = 0;
+ }
+ }
+
+ if (progressive || !interleaved) {
+
+ // allocate a buffer for the whole image
+ bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth;
+ bufHeight = ((height + mcuHeight - 1) / mcuHeight) * mcuHeight;
+ if (bufWidth <= 0 || bufHeight <= 0 ||
+ bufWidth > INT_MAX / bufWidth / (int)sizeof(int)) {
+ error(getPos(), "Invalid image size in DCT stream");
+ y = height;
+ return;
+ }
+ for (i = 0; i < numComps; ++i) {
+ frameBuf[i] = (int *)gmallocn(bufWidth * bufHeight, sizeof(int));
+ memset(frameBuf[i], 0, bufWidth * bufHeight * sizeof(int));
+ }
+
+ // read the image data
+ do {
+ restartMarker = 0xd0;
+ restart();
+ readScan();
+ } while (readHeader());
+
+ // decode
+ decodeImage();
+
+ // initialize counters
+ comp = 0;
+ x = 0;
+ y = 0;
+
+ } else {
+
+ // allocate a buffer for one row of MCUs
+ bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth;
+ for (i = 0; i < numComps; ++i) {
+ for (j = 0; j < mcuHeight; ++j) {
+ rowBuf[i][j] = (Guchar *)gmallocn(bufWidth, sizeof(Guchar));
+ }
+ }
+
+ // initialize counters
+ comp = 0;
+ x = 0;
+ y = 0;
+ dy = mcuHeight;
+
+ restartMarker = 0xd0;
+ restart();
+ }
+}
+
+void DCTStream::close() {
+ int i, j;
+
+ for (i = 0; i < 4; ++i) {
+ for (j = 0; j < 32; ++j) {
+ gfree(rowBuf[i][j]);
+ rowBuf[i][j] = NULL;
+ }
+ gfree(frameBuf[i]);
+ frameBuf[i] = NULL;
+ }
+ FilterStream::close();
+}
+
+int DCTStream::getChar() {
+ int c;
+
+ if (y >= height) {
+ return EOF;
+ }
+ if (progressive || !interleaved) {
+ c = frameBuf[comp][y * bufWidth + x];
+ if (++comp == numComps) {
+ comp = 0;
+ if (++x == width) {
+ x = 0;
+ ++y;
+ }
+ }
+ } else {
+ if (dy >= mcuHeight) {
+ if (!readMCURow()) {
+ y = height;
+ return EOF;
+ }
+ comp = 0;
+ x = 0;
+ dy = 0;
+ }
+ c = rowBuf[comp][dy][x];
+ if (++comp == numComps) {
+ comp = 0;
+ if (++x == width) {
+ x = 0;
+ ++y;
+ ++dy;
+ if (y == height) {
+ readTrailer();
+ }
+ }
+ }
+ }
+ return c;
+}
+
+int DCTStream::lookChar() {
+ if (y >= height) {
+ return EOF;
+ }
+ if (progressive || !interleaved) {
+ return frameBuf[comp][y * bufWidth + x];
+ } else {
+ if (dy >= mcuHeight) {
+ if (!readMCURow()) {
+ y = height;
+ return EOF;
+ }
+ comp = 0;
+ x = 0;
+ dy = 0;
+ }
+ return rowBuf[comp][dy][x];
+ }
+}
+
+void DCTStream::restart() {
+ int i;
+
+ inputBits = 0;
+ restartCtr = restartInterval;
+ for (i = 0; i < numComps; ++i) {
+ compInfo[i].prevDC = 0;
+ }
+ eobRun = 0;
+}
+
+// Read one row of MCUs from a sequential JPEG stream.
+GBool DCTStream::readMCURow() {
+ int data1[64];
+ Guchar data2[64];
+ Guchar *p1, *p2;
+ int pY, pCb, pCr, pR, pG, pB;
+ int h, v, horiz, vert, hSub, vSub;
+ int x1, x2, y2, x3, y3, x4, y4, x5, y5, cc, i;
+ int c;
+
+ for (x1 = 0; x1 < width; x1 += mcuWidth) {
+
+ // deal with restart marker
+ if (restartInterval > 0 && restartCtr == 0) {
+ c = readMarker();
+ if (c != restartMarker) {
+ error(getPos(), "Bad DCT data: incorrect restart marker");
+ return gFalse;
+ }
+ if (++restartMarker == 0xd8)
+ restartMarker = 0xd0;
+ restart();
+ }
+
+ // read one MCU
+ for (cc = 0; cc < numComps; ++cc) {
+ h = compInfo[cc].hSample;
+ v = compInfo[cc].vSample;
+ horiz = mcuWidth / h;
+ vert = mcuHeight / v;
+ hSub = horiz / 8;
+ vSub = vert / 8;
+ for (y2 = 0; y2 < mcuHeight; y2 += vert) {
+ for (x2 = 0; x2 < mcuWidth; x2 += horiz) {
+ if (!readDataUnit(&dcHuffTables[scanInfo.dcHuffTable[cc]],
+ &acHuffTables[scanInfo.acHuffTable[cc]],
+ &compInfo[cc].prevDC,
+ data1)) {
+ return gFalse;
+ }
+ transformDataUnit(quantTables[compInfo[cc].quantTable],
+ data1, data2);
+ if (hSub == 1 && vSub == 1) {
+ for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) {
+ p1 = &rowBuf[cc][y2+y3][x1+x2];
+ p1[0] = data2[i];
+ p1[1] = data2[i+1];
+ p1[2] = data2[i+2];
+ p1[3] = data2[i+3];
+ p1[4] = data2[i+4];
+ p1[5] = data2[i+5];
+ p1[6] = data2[i+6];
+ p1[7] = data2[i+7];
+ }
+ } else if (hSub == 2 && vSub == 2) {
+ for (y3 = 0, i = 0; y3 < 16; y3 += 2, i += 8) {
+ p1 = &rowBuf[cc][y2+y3][x1+x2];
+ p2 = &rowBuf[cc][y2+y3+1][x1+x2];
+ p1[0] = p1[1] = p2[0] = p2[1] = data2[i];
+ p1[2] = p1[3] = p2[2] = p2[3] = data2[i+1];
+ p1[4] = p1[5] = p2[4] = p2[5] = data2[i+2];
+ p1[6] = p1[7] = p2[6] = p2[7] = data2[i+3];
+ p1[8] = p1[9] = p2[8] = p2[9] = data2[i+4];
+ p1[10] = p1[11] = p2[10] = p2[11] = data2[i+5];
+ p1[12] = p1[13] = p2[12] = p2[13] = data2[i+6];
+ p1[14] = p1[15] = p2[14] = p2[15] = data2[i+7];
+ }
+ } else {
+ i = 0;
+ for (y3 = 0, y4 = 0; y3 < 8; ++y3, y4 += vSub) {
+ for (x3 = 0, x4 = 0; x3 < 8; ++x3, x4 += hSub) {
+ for (y5 = 0; y5 < vSub; ++y5)
+ for (x5 = 0; x5 < hSub; ++x5)
+ rowBuf[cc][y2+y4+y5][x1+x2+x4+x5] = data2[i];
+ ++i;
+ }
+ }
+ }
+ }
+ }
+ }
+ --restartCtr;
+
+ // color space conversion
+ if (colorXform) {
+ // convert YCbCr to RGB
+ if (numComps == 3) {
+ for (y2 = 0; y2 < mcuHeight; ++y2) {
+ for (x2 = 0; x2 < mcuWidth; ++x2) {
+ pY = rowBuf[0][y2][x1+x2];
+ pCb = rowBuf[1][y2][x1+x2] - 128;
+ pCr = rowBuf[2][y2][x1+x2] - 128;
+ pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16;
+ rowBuf[0][y2][x1+x2] = dctClip[dctClipOffset + pR];
+ pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + 32768) >> 16;
+ rowBuf[1][y2][x1+x2] = dctClip[dctClipOffset + pG];
+ pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16;
+ rowBuf[2][y2][x1+x2] = dctClip[dctClipOffset + pB];
+ }
+ }
+ // convert YCbCrK to CMYK (K is passed through unchanged)
+ } else if (numComps == 4) {
+ for (y2 = 0; y2 < mcuHeight; ++y2) {
+ for (x2 = 0; x2 < mcuWidth; ++x2) {
+ pY = rowBuf[0][y2][x1+x2];
+ pCb = rowBuf[1][y2][x1+x2] - 128;
+ pCr = rowBuf[2][y2][x1+x2] - 128;
+ pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16;
+ rowBuf[0][y2][x1+x2] = 255 - dctClip[dctClipOffset + pR];
+ pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + 32768) >> 16;
+ rowBuf[1][y2][x1+x2] = 255 - dctClip[dctClipOffset + pG];
+ pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16;
+ rowBuf[2][y2][x1+x2] = 255 - dctClip[dctClipOffset + pB];
+ }
+ }
+ }
+ }
+ }
+ return gTrue;
+}
+
+// Read one scan from a progressive or non-interleaved JPEG stream.
+void DCTStream::readScan() {
+ int data[64];
+ int x1, y1, dx1, dy1, x2, y2, y3, cc, i;
+ int h, v, horiz, vert, vSub;
+ int *p1;
+ int c;
+
+ if (scanInfo.numComps == 1) {
+ for (cc = 0; cc < numComps; ++cc) {
+ if (scanInfo.comp[cc]) {
+ break;
+ }
+ }
+ dx1 = mcuWidth / compInfo[cc].hSample;
+ dy1 = mcuHeight / compInfo[cc].vSample;
+ } else {
+ dx1 = mcuWidth;
+ dy1 = mcuHeight;
+ }
+
+ for (y1 = 0; y1 < height; y1 += dy1) {
+ for (x1 = 0; x1 < width; x1 += dx1) {
+
+ // deal with restart marker
+ if (restartInterval > 0 && restartCtr == 0) {
+ c = readMarker();
+ if (c != restartMarker) {
+ error(getPos(), "Bad DCT data: incorrect restart marker");
+ return;
+ }
+ if (++restartMarker == 0xd8) {
+ restartMarker = 0xd0;
+ }
+ restart();
+ }
+
+ // read one MCU
+ for (cc = 0; cc < numComps; ++cc) {
+ if (!scanInfo.comp[cc]) {
+ continue;
+ }
+
+ h = compInfo[cc].hSample;
+ v = compInfo[cc].vSample;
+ horiz = mcuWidth / h;
+ vert = mcuHeight / v;
+ vSub = vert / 8;
+ for (y2 = 0; y2 < dy1; y2 += vert) {
+ for (x2 = 0; x2 < dx1; x2 += horiz) {
+
+ // pull out the current values
+ p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)];
+ for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) {
+ data[i] = p1[0];
+ data[i+1] = p1[1];
+ data[i+2] = p1[2];
+ data[i+3] = p1[3];
+ data[i+4] = p1[4];
+ data[i+5] = p1[5];
+ data[i+6] = p1[6];
+ data[i+7] = p1[7];
+ p1 += bufWidth * vSub;
+ }
+
+ // read one data unit
+ if (progressive) {
+ if (!readProgressiveDataUnit(
+ &dcHuffTables[scanInfo.dcHuffTable[cc]],
+ &acHuffTables[scanInfo.acHuffTable[cc]],
+ &compInfo[cc].prevDC,
+ data)) {
+ return;
+ }
+ } else {
+ if (!readDataUnit(&dcHuffTables[scanInfo.dcHuffTable[cc]],
+ &acHuffTables[scanInfo.acHuffTable[cc]],
+ &compInfo[cc].prevDC,
+ data)) {
+ return;
+ }
+ }
+
+ // add the data unit into frameBuf
+ p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)];
+ for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) {
+ p1[0] = data[i];
+ p1[1] = data[i+1];
+ p1[2] = data[i+2];
+ p1[3] = data[i+3];
+ p1[4] = data[i+4];
+ p1[5] = data[i+5];
+ p1[6] = data[i+6];
+ p1[7] = data[i+7];
+ p1 += bufWidth * vSub;
+ }
+ }
+ }
+ }
+ --restartCtr;
+ }
+ }
+}
+
+// Read one data unit from a sequential JPEG stream.
+GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable,
+ DCTHuffTable *acHuffTable,
+ int *prevDC, int data[64]) {
+ int run, size, amp;
+ int c;
+ int i, j;
+
+ if ((size = readHuffSym(dcHuffTable)) == 9999) {
+ return gFalse;
+ }
+ if (size > 0) {
+ if ((amp = readAmp(size)) == 9999) {
+ return gFalse;
+ }
+ } else {
+ amp = 0;
+ }
+ data[0] = *prevDC += amp;
+ for (i = 1; i < 64; ++i) {
+ data[i] = 0;
+ }
+ i = 1;
+ while (i < 64) {
+ run = 0;
+ while ((c = readHuffSym(acHuffTable)) == 0xf0 && run < 0x30) {
+ run += 0x10;
+ }
+ if (c == 9999) {
+ return gFalse;
+ }
+ if (c == 0x00) {
+ break;
+ } else {
+ run += (c >> 4) & 0x0f;
+ size = c & 0x0f;
+ amp = readAmp(size);
+ if (amp == 9999) {
+ return gFalse;
+ }
+ i += run;
+ if (i < 64) {
+ j = dctZigZag[i++];
+ data[j] = amp;
+ }
+ }
+ }
+ return gTrue;
+}
+
+// Read one data unit from a sequential JPEG stream.
+GBool DCTStream::readProgressiveDataUnit(DCTHuffTable *dcHuffTable,
+ DCTHuffTable *acHuffTable,
+ int *prevDC, int data[64]) {
+ int run, size, amp, bit, c;
+ int i, j, k;
+
+ // get the DC coefficient
+ i = scanInfo.firstCoeff;
+ if (i == 0) {
+ if (scanInfo.ah == 0) {
+ if ((size = readHuffSym(dcHuffTable)) == 9999) {
+ return gFalse;
+ }
+ if (size > 0) {
+ if ((amp = readAmp(size)) == 9999) {
+ return gFalse;
+ }
+ } else {
+ amp = 0;
+ }
+ data[0] += (*prevDC += amp) << scanInfo.al;
+ } else {
+ if ((bit = readBit()) == 9999) {
+ return gFalse;
+ }
+ data[0] += bit << scanInfo.al;
+ }
+ ++i;
+ }
+ if (scanInfo.lastCoeff == 0) {
+ return gTrue;
+ }
+
+ // check for an EOB run
+ if (eobRun > 0) {
+ while (i <= scanInfo.lastCoeff) {
+ j = dctZigZag[i++];
+ if (data[j] != 0) {
+ if ((bit = readBit()) == EOF) {
+ return gFalse;
+ }
+ if (bit) {
+ data[j] += 1 << scanInfo.al;
+ }
+ }
+ }
+ --eobRun;
+ return gTrue;
+ }
+
+ // read the AC coefficients
+ while (i <= scanInfo.lastCoeff) {
+ if ((c = readHuffSym(acHuffTable)) == 9999) {
+ return gFalse;
+ }
+
+ // ZRL
+ if (c == 0xf0) {
+ k = 0;
+ while (k < 16) {
+ j = dctZigZag[i++];
+ if (data[j] == 0) {
+ ++k;
+ } else {
+ if ((bit = readBit()) == EOF) {
+ return gFalse;
+ }
+ if (bit) {
+ data[j] += 1 << scanInfo.al;
+ }
+ }
+ }
+
+ // EOB run
+ } else if ((c & 0x0f) == 0x00) {
+ j = c >> 4;
+ eobRun = 0;
+ for (k = 0; k < j; ++k) {
+ if ((bit = readBit()) == EOF) {
+ return gFalse;
+ }
+ eobRun = (eobRun << 1) | bit;
+ }
+ eobRun += 1 << j;
+ while (i <= scanInfo.lastCoeff) {
+ j = dctZigZag[i++];
+ if (data[j] != 0) {
+ if ((bit = readBit()) == EOF) {
+ return gFalse;
+ }
+ if (bit) {
+ data[j] += 1 << scanInfo.al;
+ }
+ }
+ }
+ --eobRun;
+ break;
+
+ // zero run and one AC coefficient
+ } else {
+ run = (c >> 4) & 0x0f;
+ size = c & 0x0f;
+ if ((amp = readAmp(size)) == 9999) {
+ return gFalse;
+ }
+ k = 0;
+ do {
+ j = dctZigZag[i++];
+ while (data[j] != 0) {
+ if ((bit = readBit()) == EOF) {
+ return gFalse;
+ }
+ if (bit) {
+ data[j] += 1 << scanInfo.al;
+ }
+ j = dctZigZag[i++];
+ }
+ ++k;
+ } while (k <= run);
+ data[j] = amp << scanInfo.al;
+ }
+ }
+
+ return gTrue;
+}
+
+// Decode a progressive JPEG image.
+void DCTStream::decodeImage() {
+ int dataIn[64];
+ Guchar dataOut[64];
+ Gushort *quantTable;
+ int pY, pCb, pCr, pR, pG, pB;
+ int x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, cc, i;
+ int h, v, horiz, vert, hSub, vSub;
+ int *p0, *p1, *p2;
+
+ for (y1 = 0; y1 < bufHeight; y1 += mcuHeight) {
+ for (x1 = 0; x1 < bufWidth; x1 += mcuWidth) {
+ for (cc = 0; cc < numComps; ++cc) {
+ quantTable = quantTables[compInfo[cc].quantTable];
+ h = compInfo[cc].hSample;
+ v = compInfo[cc].vSample;
+ horiz = mcuWidth / h;
+ vert = mcuHeight / v;
+ hSub = horiz / 8;
+ vSub = vert / 8;
+ for (y2 = 0; y2 < mcuHeight; y2 += vert) {
+ for (x2 = 0; x2 < mcuWidth; x2 += horiz) {
+
+ // pull out the coded data unit
+ p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)];
+ for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) {
+ dataIn[i] = p1[0];
+ dataIn[i+1] = p1[1];
+ dataIn[i+2] = p1[2];
+ dataIn[i+3] = p1[3];
+ dataIn[i+4] = p1[4];
+ dataIn[i+5] = p1[5];
+ dataIn[i+6] = p1[6];
+ dataIn[i+7] = p1[7];
+ p1 += bufWidth * vSub;
+ }
+
+ // transform
+ transformDataUnit(quantTable, dataIn, dataOut);
+
+ // store back into frameBuf, doing replication for
+ // subsampled components
+ p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)];
+ if (hSub == 1 && vSub == 1) {
+ for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) {
+ p1[0] = dataOut[i] & 0xff;
+ p1[1] = dataOut[i+1] & 0xff;
+ p1[2] = dataOut[i+2] & 0xff;
+ p1[3] = dataOut[i+3] & 0xff;
+ p1[4] = dataOut[i+4] & 0xff;
+ p1[5] = dataOut[i+5] & 0xff;
+ p1[6] = dataOut[i+6] & 0xff;
+ p1[7] = dataOut[i+7] & 0xff;
+ p1 += bufWidth;
+ }
+ } else if (hSub == 2 && vSub == 2) {
+ p2 = p1 + bufWidth;
+ for (y3 = 0, i = 0; y3 < 16; y3 += 2, i += 8) {
+ p1[0] = p1[1] = p2[0] = p2[1] = dataOut[i] & 0xff;
+ p1[2] = p1[3] = p2[2] = p2[3] = dataOut[i+1] & 0xff;
+ p1[4] = p1[5] = p2[4] = p2[5] = dataOut[i+2] & 0xff;
+ p1[6] = p1[7] = p2[6] = p2[7] = dataOut[i+3] & 0xff;
+ p1[8] = p1[9] = p2[8] = p2[9] = dataOut[i+4] & 0xff;
+ p1[10] = p1[11] = p2[10] = p2[11] = dataOut[i+5] & 0xff;
+ p1[12] = p1[13] = p2[12] = p2[13] = dataOut[i+6] & 0xff;
+ p1[14] = p1[15] = p2[14] = p2[15] = dataOut[i+7] & 0xff;
+ p1 += bufWidth * 2;
+ p2 += bufWidth * 2;
+ }
+ } else {
+ i = 0;
+ for (y3 = 0, y4 = 0; y3 < 8; ++y3, y4 += vSub) {
+ for (x3 = 0, x4 = 0; x3 < 8; ++x3, x4 += hSub) {
+ p2 = p1 + x4;
+ for (y5 = 0; y5 < vSub; ++y5) {
+ for (x5 = 0; x5 < hSub; ++x5) {
+ p2[x5] = dataOut[i] & 0xff;
+ }
+ p2 += bufWidth;
+ }
+ ++i;
+ }
+ p1 += bufWidth * vSub;
+ }
+ }
+ }
+ }
+ }
+
+ // color space conversion
+ if (colorXform) {
+ // convert YCbCr to RGB
+ if (numComps == 3) {
+ for (y2 = 0; y2 < mcuHeight; ++y2) {
+ p0 = &frameBuf[0][(y1+y2) * bufWidth + x1];
+ p1 = &frameBuf[1][(y1+y2) * bufWidth + x1];
+ p2 = &frameBuf[2][(y1+y2) * bufWidth + x1];
+ for (x2 = 0; x2 < mcuWidth; ++x2) {
+ pY = *p0;
+ pCb = *p1 - 128;
+ pCr = *p2 - 128;
+ pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16;
+ *p0++ = dctClip[dctClipOffset + pR];
+ pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr +
+ 32768) >> 16;
+ *p1++ = dctClip[dctClipOffset + pG];
+ pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16;
+ *p2++ = dctClip[dctClipOffset + pB];
+ }
+ }
+ // convert YCbCrK to CMYK (K is passed through unchanged)
+ } else if (numComps == 4) {
+ for (y2 = 0; y2 < mcuHeight; ++y2) {
+ p0 = &frameBuf[0][(y1+y2) * bufWidth + x1];
+ p1 = &frameBuf[1][(y1+y2) * bufWidth + x1];
+ p2 = &frameBuf[2][(y1+y2) * bufWidth + x1];
+ for (x2 = 0; x2 < mcuWidth; ++x2) {
+ pY = *p0;
+ pCb = *p1 - 128;
+ pCr = *p2 - 128;
+ pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16;
+ *p0++ = 255 - dctClip[dctClipOffset + pR];
+ pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr +
+ 32768) >> 16;
+ *p1++ = 255 - dctClip[dctClipOffset + pG];
+ pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16;
+ *p2++ = 255 - dctClip[dctClipOffset + pB];
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+// Transform one data unit -- this performs the dequantization and
+// IDCT steps. This IDCT algorithm is taken from:
+// Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz,
+// "Practical Fast 1-D DCT Algorithms with 11 Multiplications",
+// IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989,
+// 988-991.
+// The stage numbers mentioned in the comments refer to Figure 1 in this
+// paper.
+void DCTStream::transformDataUnit(Gushort *quantTable,
+ int dataIn[64], Guchar dataOut[64]) {
+ int v0, v1, v2, v3, v4, v5, v6, v7, t;
+ int *p;
+ int i;
+
+ // dequant
+ for (i = 0; i < 64; ++i) {
+ dataIn[i] *= quantTable[i];
+ }
+
+ // inverse DCT on rows
+ for (i = 0; i < 64; i += 8) {
+ p = dataIn + i;
+
+ // check for all-zero AC coefficients
+ if (p[1] == 0 && p[2] == 0 && p[3] == 0 &&
+ p[4] == 0 && p[5] == 0 && p[6] == 0 && p[7] == 0) {
+ t = (dctSqrt2 * p[0] + 512) >> 10;
+ p[0] = t;
+ p[1] = t;
+ p[2] = t;
+ p[3] = t;
+ p[4] = t;
+ p[5] = t;
+ p[6] = t;
+ p[7] = t;
+ continue;
+ }
+
+ // stage 4
+ v0 = (dctSqrt2 * p[0] + 128) >> 8;
+ v1 = (dctSqrt2 * p[4] + 128) >> 8;
+ v2 = p[2];
+ v3 = p[6];
+ v4 = (dctSqrt1d2 * (p[1] - p[7]) + 128) >> 8;
+ v7 = (dctSqrt1d2 * (p[1] + p[7]) + 128) >> 8;
+ v5 = p[3] << 4;
+ v6 = p[5] << 4;
+
+ // stage 3
+ t = (v0 - v1+ 1) >> 1;
+ v0 = (v0 + v1 + 1) >> 1;
+ v1 = t;
+ t = (v2 * dctSin6 + v3 * dctCos6 + 128) >> 8;
+ v2 = (v2 * dctCos6 - v3 * dctSin6 + 128) >> 8;
+ v3 = t;
+ t = (v4 - v6 + 1) >> 1;
+ v4 = (v4 + v6 + 1) >> 1;
+ v6 = t;
+ t = (v7 + v5 + 1) >> 1;
+ v5 = (v7 - v5 + 1) >> 1;
+ v7 = t;
+
+ // stage 2
+ t = (v0 - v3 + 1) >> 1;
+ v0 = (v0 + v3 + 1) >> 1;
+ v3 = t;
+ t = (v1 - v2 + 1) >> 1;
+ v1 = (v1 + v2 + 1) >> 1;
+ v2 = t;
+ t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
+ v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
+ v7 = t;
+ t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
+ v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
+ v6 = t;
+
+ // stage 1
+ p[0] = v0 + v7;
+ p[7] = v0 - v7;
+ p[1] = v1 + v6;
+ p[6] = v1 - v6;
+ p[2] = v2 + v5;
+ p[5] = v2 - v5;
+ p[3] = v3 + v4;
+ p[4] = v3 - v4;
+ }
+
+ // inverse DCT on columns
+ for (i = 0; i < 8; ++i) {
+ p = dataIn + i;
+
+ // check for all-zero AC coefficients
+ if (p[1*8] == 0 && p[2*8] == 0 && p[3*8] == 0 &&
+ p[4*8] == 0 && p[5*8] == 0 && p[6*8] == 0 && p[7*8] == 0) {
+ t = (dctSqrt2 * dataIn[i+0] + 8192) >> 14;
+ p[0*8] = t;
+ p[1*8] = t;
+ p[2*8] = t;
+ p[3*8] = t;
+ p[4*8] = t;
+ p[5*8] = t;
+ p[6*8] = t;
+ p[7*8] = t;
+ continue;
+ }
+
+ // stage 4
+ v0 = (dctSqrt2 * p[0*8] + 2048) >> 12;
+ v1 = (dctSqrt2 * p[4*8] + 2048) >> 12;
+ v2 = p[2*8];
+ v3 = p[6*8];
+ v4 = (dctSqrt1d2 * (p[1*8] - p[7*8]) + 2048) >> 12;
+ v7 = (dctSqrt1d2 * (p[1*8] + p[7*8]) + 2048) >> 12;
+ v5 = p[3*8];
+ v6 = p[5*8];
+
+ // stage 3
+ t = (v0 - v1 + 1) >> 1;
+ v0 = (v0 + v1 + 1) >> 1;
+ v1 = t;
+ t = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12;
+ v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12;
+ v3 = t;
+ t = (v4 - v6 + 1) >> 1;
+ v4 = (v4 + v6 + 1) >> 1;
+ v6 = t;
+ t = (v7 + v5 + 1) >> 1;
+ v5 = (v7 - v5 + 1) >> 1;
+ v7 = t;
+
+ // stage 2
+ t = (v0 - v3 + 1) >> 1;
+ v0 = (v0 + v3 + 1) >> 1;
+ v3 = t;
+ t = (v1 - v2 + 1) >> 1;
+ v1 = (v1 + v2 + 1) >> 1;
+ v2 = t;
+ t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12;
+ v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12;
+ v7 = t;
+ t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12;
+ v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12;
+ v6 = t;
+
+ // stage 1
+ p[0*8] = v0 + v7;
+ p[7*8] = v0 - v7;
+ p[1*8] = v1 + v6;
+ p[6*8] = v1 - v6;
+ p[2*8] = v2 + v5;
+ p[5*8] = v2 - v5;
+ p[3*8] = v3 + v4;
+ p[4*8] = v3 - v4;
+ }
+
+ // convert to 8-bit integers
+ for (i = 0; i < 64; ++i) {
+ dataOut[i] = dctClip[dctClipOffset + 128 + ((dataIn[i] + 8) >> 4)];
+ }
+}
+
+int DCTStream::readHuffSym(DCTHuffTable *table) {
+ Gushort code;
+ int bit;
+ int codeBits;
+
+ code = 0;
+ codeBits = 0;
+ do {
+ // add a bit to the code
+ if ((bit = readBit()) == EOF)
+ return 9999;
+ code = (code << 1) + bit;
+ ++codeBits;
+
+ // look up code
+ if (code - table->firstCode[codeBits] < table->numCodes[codeBits]) {
+ code -= table->firstCode[codeBits];
+ return table->sym[table->firstSym[codeBits] + code];
+ }
+ } while (codeBits < 16);
+
+ error(getPos(), "Bad Huffman code in DCT stream");
+ return 9999;
+}
+
+int DCTStream::readAmp(int size) {
+ int amp, bit;
+ int bits;
+
+ amp = 0;
+ for (bits = 0; bits < size; ++bits) {
+ if ((bit = readBit()) == EOF)
+ return 9999;
+ amp = (amp << 1) + bit;
+ }
+ if (amp < (1 << (size - 1)))
+ amp -= (1 << size) - 1;
+ return amp;
+}
+
+int DCTStream::readBit() {
+ int bit;
+ int c, c2;
+
+ if (inputBits == 0) {
+ if ((c = str->getChar()) == EOF)
+ return EOF;
+ if (c == 0xff) {
+ do {
+ c2 = str->getChar();
+ } while (c2 == 0xff);
+ if (c2 != 0x00) {
+ error(getPos(), "Bad DCT data: missing 00 after ff");
+ return EOF;
+ }
+ }
+ inputBuf = c;
+ inputBits = 8;
+ }
+ bit = (inputBuf >> (inputBits - 1)) & 1;
+ --inputBits;
+ return bit;
+}
+
+GBool DCTStream::readHeader() {
+ GBool doScan;
+ int n;
+ int c = 0;
+ int i;
+
+ // read headers
+ doScan = gFalse;
+ while (!doScan) {
+ c = readMarker();
+ switch (c) {
+ case 0xc0: // SOF0 (sequential)
+ case 0xc1: // SOF1 (extended sequential)
+ if (!readBaselineSOF()) {
+ return gFalse;
+ }
+ break;
+ case 0xc2: // SOF2 (progressive)
+ if (!readProgressiveSOF()) {
+ return gFalse;
+ }
+ break;
+ case 0xc4: // DHT
+ if (!readHuffmanTables()) {
+ return gFalse;
+ }
+ break;
+ case 0xd8: // SOI
+ break;
+ case 0xd9: // EOI
+ return gFalse;
+ case 0xda: // SOS
+ if (!readScanInfo()) {
+ return gFalse;
+ }
+ doScan = gTrue;
+ break;
+ case 0xdb: // DQT
+ if (!readQuantTables()) {
+ return gFalse;
+ }
+ break;
+ case 0xdd: // DRI
+ if (!readRestartInterval()) {
+ return gFalse;
+ }
+ break;
+ case 0xe0: // APP0
+ if (!readJFIFMarker()) {
+ return gFalse;
+ }
+ break;
+ case 0xee: // APP14
+ if (!readAdobeMarker()) {
+ return gFalse;
+ }
+ break;
+ case EOF:
+ error(getPos(), "Bad DCT header");
+ return gFalse;
+ default:
+ // skip APPn / COM / etc.
+ if (c >= 0xe0) {
+ n = read16() - 2;
+ for (i = 0; i < n; ++i) {
+ str->getChar();
+ }
+ } else {
+ error(getPos(), "Unknown DCT marker <%02x>", c);
+ return gFalse;
+ }
+ break;
+ }
+ }
+
+ return gTrue;
+}
+
+GBool DCTStream::readBaselineSOF() {
+ int length;
+ int prec;
+ int i;
+ int c;
+
+ length = read16();
+ prec = str->getChar();
+ height = read16();
+ width = read16();
+ numComps = str->getChar();
+ if (numComps <= 0 || numComps > 4) {
+ error(getPos(), "Bad number of components in DCT stream");
+ numComps = 0;
+ return gFalse;
+ }
+ if (prec != 8) {
+ error(getPos(), "Bad DCT precision %d", prec);
+ return gFalse;
+ }
+ for (i = 0; i < numComps; ++i) {
+ compInfo[i].id = str->getChar();
+ c = str->getChar();
+ compInfo[i].hSample = (c >> 4) & 0x0f;
+ compInfo[i].vSample = c & 0x0f;
+ compInfo[i].quantTable = str->getChar();
+ }
+ progressive = gFalse;
+ return gTrue;
+}
+
+GBool DCTStream::readProgressiveSOF() {
+ int length;
+ int prec;
+ int i;
+ int c;
+
+ length = read16();
+ prec = str->getChar();
+ height = read16();
+ width = read16();
+ numComps = str->getChar();
+ if (numComps <= 0 || numComps > 4) {
+ error(getPos(), "Bad number of components in DCT stream");
+ numComps = 0;
+ return gFalse;
+ }
+ if (prec != 8) {
+ error(getPos(), "Bad DCT precision %d", prec);
+ return gFalse;
+ }
+ for (i = 0; i < numComps; ++i) {
+ compInfo[i].id = str->getChar();
+ c = str->getChar();
+ compInfo[i].hSample = (c >> 4) & 0x0f;
+ compInfo[i].vSample = c & 0x0f;
+ compInfo[i].quantTable = str->getChar();
+ }
+ progressive = gTrue;
+ return gTrue;
+}
+
+GBool DCTStream::readScanInfo() {
+ int length;
+ int id, c;
+ int i, j;
+
+ length = read16() - 2;
+ scanInfo.numComps = str->getChar();
+ if (scanInfo.numComps <= 0 || scanInfo.numComps > 4) {
+ error(getPos(), "Bad number of components in DCT stream");
+ scanInfo.numComps = 0;
+ return gFalse;
+ }
+ --length;
+ if (length != 2 * scanInfo.numComps + 3) {
+ error(getPos(), "Bad DCT scan info block");
+ return gFalse;
+ }
+ interleaved = scanInfo.numComps == numComps;
+ for (j = 0; j < numComps; ++j) {
+ scanInfo.comp[j] = gFalse;
+ }
+ for (i = 0; i < scanInfo.numComps; ++i) {
+ id = str->getChar();
+ // some (broken) DCT streams reuse ID numbers, but at least they
+ // keep the components in order, so we check compInfo[i] first to
+ // work around the problem
+ if (id == compInfo[i].id) {
+ j = i;
+ } else {
+ for (j = 0; j < numComps; ++j) {
+ if (id == compInfo[j].id) {
+ break;
+ }
+ }
+ if (j == numComps) {
+ error(getPos(), "Bad DCT component ID in scan info block");
+ return gFalse;
+ }
+ }
+ scanInfo.comp[j] = gTrue;
+ c = str->getChar();
+ scanInfo.dcHuffTable[j] = (c >> 4) & 0x0f;
+ scanInfo.acHuffTable[j] = c & 0x0f;
+ }
+ scanInfo.firstCoeff = str->getChar();
+ scanInfo.lastCoeff = str->getChar();
+ if (scanInfo.firstCoeff < 0 || scanInfo.lastCoeff > 63 ||
+ scanInfo.firstCoeff > scanInfo.lastCoeff) {
+ error(getPos(), "Bad DCT coefficient numbers in scan info block");
+ return gFalse;
+ }
+ c = str->getChar();
+ scanInfo.ah = (c >> 4) & 0x0f;
+ scanInfo.al = c & 0x0f;
+ return gTrue;
+}
+
+GBool DCTStream::readQuantTables() {
+ int length, prec, i, index;
+
+ length = read16() - 2;
+ while (length > 0) {
+ index = str->getChar();
+ prec = (index >> 4) & 0x0f;
+ index &= 0x0f;
+ if (prec > 1 || index >= 4) {
+ error(getPos(), "Bad DCT quantization table");
+ return gFalse;
+ }
+ if (index == numQuantTables) {
+ numQuantTables = index + 1;
+ }
+ for (i = 0; i < 64; ++i) {
+ if (prec) {
+ quantTables[index][dctZigZag[i]] = read16();
+ } else {
+ quantTables[index][dctZigZag[i]] = str->getChar();
+ }
+ }
+ if (prec) {
+ length -= 129;
+ } else {
+ length -= 65;
+ }
+ }
+ return gTrue;
+}
+
+GBool DCTStream::readHuffmanTables() {
+ DCTHuffTable *tbl;
+ int length;
+ int index;
+ Gushort code;
+ Guchar sym;
+ int i;
+ int c;
+
+ length = read16() - 2;
+ while (length > 0) {
+ index = str->getChar();
+ --length;
+ if ((index & 0x0f) >= 4) {
+ error(getPos(), "Bad DCT Huffman table");
+ return gFalse;
+ }
+ if (index & 0x10) {
+ index &= 0x0f;
+ if (index >= numACHuffTables)
+ numACHuffTables = index+1;
+ tbl = &acHuffTables[index];
+ } else {
+ index &= 0x0f;
+ if (index >= numDCHuffTables)
+ numDCHuffTables = index+1;
+ tbl = &dcHuffTables[index];
+ }
+ sym = 0;
+ code = 0;
+ for (i = 1; i <= 16; ++i) {
+ c = str->getChar();
+ tbl->firstSym[i] = sym;
+ tbl->firstCode[i] = code;
+ tbl->numCodes[i] = c;
+ sym += c;
+ code = (code + c) << 1;
+ }
+ length -= 16;
+ for (i = 0; i < sym; ++i)
+ tbl->sym[i] = str->getChar();
+ length -= sym;
+ }
+ return gTrue;
+}
+
+GBool DCTStream::readRestartInterval() {
+ int length;
+
+ length = read16();
+ if (length != 4) {
+ error(getPos(), "Bad DCT restart interval");
+ return gFalse;
+ }
+ restartInterval = read16();
+ return gTrue;
+}
+
+GBool DCTStream::readJFIFMarker() {
+ int length, i;
+ char buf[5];
+ int c;
+
+ length = read16();
+ length -= 2;
+ if (length >= 5) {
+ for (i = 0; i < 5; ++i) {
+ if ((c = str->getChar()) == EOF) {
+ error(getPos(), "Bad DCT APP0 marker");
+ return gFalse;
+ }
+ buf[i] = c;
+ }
+ length -= 5;
+ if (!memcmp(buf, "JFIF\0", 5)) {
+ gotJFIFMarker = gTrue;
+ }
+ }
+ while (length > 0) {
+ if (str->getChar() == EOF) {
+ error(getPos(), "Bad DCT APP0 marker");
+ return gFalse;
+ }
+ --length;
+ }
+ return gTrue;
+}
+
+GBool DCTStream::readAdobeMarker() {
+ int length, i;
+ char buf[12];
+ int c;
+
+ length = read16();
+ if (length < 14) {
+ goto err;
+ }
+ for (i = 0; i < 12; ++i) {
+ if ((c = str->getChar()) == EOF) {
+ goto err;
+ }
+ buf[i] = c;
+ }
+ if (strncmp(buf, "Adobe", 5)) {
+ goto err;
+ }
+ colorXform = buf[11];
+ gotAdobeMarker = gTrue;
+ for (i = 14; i < length; ++i) {
+ if (str->getChar() == EOF) {
+ goto err;
+ }
+ }
+ return gTrue;
+
+ err:
+ error(getPos(), "Bad DCT Adobe APP14 marker");
+ return gFalse;
+}
+
+GBool DCTStream::readTrailer() {
+ int c;
+
+ c = readMarker();
+ if (c != 0xd9) { // EOI
+ error(getPos(), "Bad DCT trailer");
+ return gFalse;
+ }
+ return gTrue;
+}
+
+int DCTStream::readMarker() {
+ int c;
+
+ do {
+ do {
+ c = str->getChar();
+ } while (c != 0xff && c != EOF);
+ do {
+ c = str->getChar();
+ } while (c == 0xff);
+ } while (c == 0x00);
+ return c;
+}
+
+int DCTStream::read16() {
+ int c1, c2;
+
+ if ((c1 = str->getChar()) == EOF)
+ return EOF;
+ if ((c2 = str->getChar()) == EOF)
+ return EOF;
+ return (c1 << 8) + c2;
+}
+
+GString *DCTStream::getPSFilter(int psLevel, char *indent) {
+ GString *s;
+
+ if (psLevel < 2) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
+ return NULL;
+ }
+ s->append(indent)->append("<< >> /DCTDecode filter\n");
+ return s;
+}
+
+GBool DCTStream::isBinary(GBool /*last*/) {
+ return str->isBinary(gTrue);
+}
+
+//------------------------------------------------------------------------
+// FlateStream
+//------------------------------------------------------------------------
+
+int FlateStream::codeLenCodeMap[flateMaxCodeLenCodes] = {
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
+};
+
+FlateDecode FlateStream::lengthDecode[flateMaxLitCodes-257] = {
+ {0, 3},
+ {0, 4},
+ {0, 5},
+ {0, 6},
+ {0, 7},
+ {0, 8},
+ {0, 9},
+ {0, 10},
+ {1, 11},
+ {1, 13},
+ {1, 15},
+ {1, 17},
+ {2, 19},
+ {2, 23},
+ {2, 27},
+ {2, 31},
+ {3, 35},
+ {3, 43},
+ {3, 51},
+ {3, 59},
+ {4, 67},
+ {4, 83},
+ {4, 99},
+ {4, 115},
+ {5, 131},
+ {5, 163},
+ {5, 195},
+ {5, 227},
+ {0, 258},
+ {0, 258},
+ {0, 258}
+};
+
+FlateDecode FlateStream::distDecode[flateMaxDistCodes] = {
+ { 0, 1},
+ { 0, 2},
+ { 0, 3},
+ { 0, 4},
+ { 1, 5},
+ { 1, 7},
+ { 2, 9},
+ { 2, 13},
+ { 3, 17},
+ { 3, 25},
+ { 4, 33},
+ { 4, 49},
+ { 5, 65},
+ { 5, 97},
+ { 6, 129},
+ { 6, 193},
+ { 7, 257},
+ { 7, 385},
+ { 8, 513},
+ { 8, 769},
+ { 9, 1025},
+ { 9, 1537},
+ {10, 2049},
+ {10, 3073},
+ {11, 4097},
+ {11, 6145},
+ {12, 8193},
+ {12, 12289},
+ {13, 16385},
+ {13, 24577}
+};
+
+static FlateCode flateFixedLitCodeTabCodes[512] = {
+ {7, 0x0100},
+ {8, 0x0050},
+ {8, 0x0010},
+ {8, 0x0118},
+ {7, 0x0110},
+ {8, 0x0070},
+ {8, 0x0030},
+ {9, 0x00c0},
+ {7, 0x0108},
+ {8, 0x0060},
+ {8, 0x0020},
+ {9, 0x00a0},
+ {8, 0x0000},
+ {8, 0x0080},
+ {8, 0x0040},
+ {9, 0x00e0},
+ {7, 0x0104},
+ {8, 0x0058},
+ {8, 0x0018},
+ {9, 0x0090},
+ {7, 0x0114},
+ {8, 0x0078},
+ {8, 0x0038},
+ {9, 0x00d0},
+ {7, 0x010c},
+ {8, 0x0068},
+ {8, 0x0028},
+ {9, 0x00b0},
+ {8, 0x0008},
+ {8, 0x0088},
+ {8, 0x0048},
+ {9, 0x00f0},
+ {7, 0x0102},
+ {8, 0x0054},
+ {8, 0x0014},
+ {8, 0x011c},
+ {7, 0x0112},
+ {8, 0x0074},
+ {8, 0x0034},
+ {9, 0x00c8},
+ {7, 0x010a},
+ {8, 0x0064},
+ {8, 0x0024},
+ {9, 0x00a8},
+ {8, 0x0004},
+ {8, 0x0084},
+ {8, 0x0044},
+ {9, 0x00e8},
+ {7, 0x0106},
+ {8, 0x005c},
+ {8, 0x001c},
+ {9, 0x0098},
+ {7, 0x0116},
+ {8, 0x007c},
+ {8, 0x003c},
+ {9, 0x00d8},
+ {7, 0x010e},
+ {8, 0x006c},
+ {8, 0x002c},
+ {9, 0x00b8},
+ {8, 0x000c},
+ {8, 0x008c},
+ {8, 0x004c},
+ {9, 0x00f8},
+ {7, 0x0101},
+ {8, 0x0052},
+ {8, 0x0012},
+ {8, 0x011a},
+ {7, 0x0111},
+ {8, 0x0072},
+ {8, 0x0032},
+ {9, 0x00c4},
+ {7, 0x0109},
+ {8, 0x0062},
+ {8, 0x0022},
+ {9, 0x00a4},
+ {8, 0x0002},
+ {8, 0x0082},
+ {8, 0x0042},
+ {9, 0x00e4},
+ {7, 0x0105},
+ {8, 0x005a},
+ {8, 0x001a},
+ {9, 0x0094},
+ {7, 0x0115},
+ {8, 0x007a},
+ {8, 0x003a},
+ {9, 0x00d4},
+ {7, 0x010d},
+ {8, 0x006a},
+ {8, 0x002a},
+ {9, 0x00b4},
+ {8, 0x000a},
+ {8, 0x008a},
+ {8, 0x004a},
+ {9, 0x00f4},
+ {7, 0x0103},
+ {8, 0x0056},
+ {8, 0x0016},
+ {8, 0x011e},
+ {7, 0x0113},
+ {8, 0x0076},
+ {8, 0x0036},
+ {9, 0x00cc},
+ {7, 0x010b},
+ {8, 0x0066},
+ {8, 0x0026},
+ {9, 0x00ac},
+ {8, 0x0006},
+ {8, 0x0086},
+ {8, 0x0046},
+ {9, 0x00ec},
+ {7, 0x0107},
+ {8, 0x005e},
+ {8, 0x001e},
+ {9, 0x009c},
+ {7, 0x0117},
+ {8, 0x007e},
+ {8, 0x003e},
+ {9, 0x00dc},
+ {7, 0x010f},
+ {8, 0x006e},
+ {8, 0x002e},
+ {9, 0x00bc},
+ {8, 0x000e},
+ {8, 0x008e},
+ {8, 0x004e},
+ {9, 0x00fc},
+ {7, 0x0100},
+ {8, 0x0051},
+ {8, 0x0011},
+ {8, 0x0119},
+ {7, 0x0110},
+ {8, 0x0071},
+ {8, 0x0031},
+ {9, 0x00c2},
+ {7, 0x0108},
+ {8, 0x0061},
+ {8, 0x0021},
+ {9, 0x00a2},
+ {8, 0x0001},
+ {8, 0x0081},
+ {8, 0x0041},
+ {9, 0x00e2},
+ {7, 0x0104},
+ {8, 0x0059},
+ {8, 0x0019},
+ {9, 0x0092},
+ {7, 0x0114},
+ {8, 0x0079},
+ {8, 0x0039},
+ {9, 0x00d2},
+ {7, 0x010c},
+ {8, 0x0069},
+ {8, 0x0029},
+ {9, 0x00b2},
+ {8, 0x0009},
+ {8, 0x0089},
+ {8, 0x0049},
+ {9, 0x00f2},
+ {7, 0x0102},
+ {8, 0x0055},
+ {8, 0x0015},
+ {8, 0x011d},
+ {7, 0x0112},
+ {8, 0x0075},
+ {8, 0x0035},
+ {9, 0x00ca},
+ {7, 0x010a},
+ {8, 0x0065},
+ {8, 0x0025},
+ {9, 0x00aa},
+ {8, 0x0005},
+ {8, 0x0085},
+ {8, 0x0045},
+ {9, 0x00ea},
+ {7, 0x0106},
+ {8, 0x005d},
+ {8, 0x001d},
+ {9, 0x009a},
+ {7, 0x0116},
+ {8, 0x007d},
+ {8, 0x003d},
+ {9, 0x00da},
+ {7, 0x010e},
+ {8, 0x006d},
+ {8, 0x002d},
+ {9, 0x00ba},
+ {8, 0x000d},
+ {8, 0x008d},
+ {8, 0x004d},
+ {9, 0x00fa},
+ {7, 0x0101},
+ {8, 0x0053},
+ {8, 0x0013},
+ {8, 0x011b},
+ {7, 0x0111},
+ {8, 0x0073},
+ {8, 0x0033},
+ {9, 0x00c6},
+ {7, 0x0109},
+ {8, 0x0063},
+ {8, 0x0023},
+ {9, 0x00a6},
+ {8, 0x0003},
+ {8, 0x0083},
+ {8, 0x0043},
+ {9, 0x00e6},
+ {7, 0x0105},
+ {8, 0x005b},
+ {8, 0x001b},
+ {9, 0x0096},
+ {7, 0x0115},
+ {8, 0x007b},
+ {8, 0x003b},
+ {9, 0x00d6},
+ {7, 0x010d},
+ {8, 0x006b},
+ {8, 0x002b},
+ {9, 0x00b6},
+ {8, 0x000b},
+ {8, 0x008b},
+ {8, 0x004b},
+ {9, 0x00f6},
+ {7, 0x0103},
+ {8, 0x0057},
+ {8, 0x0017},
+ {8, 0x011f},
+ {7, 0x0113},
+ {8, 0x0077},
+ {8, 0x0037},
+ {9, 0x00ce},
+ {7, 0x010b},
+ {8, 0x0067},
+ {8, 0x0027},
+ {9, 0x00ae},
+ {8, 0x0007},
+ {8, 0x0087},
+ {8, 0x0047},
+ {9, 0x00ee},
+ {7, 0x0107},
+ {8, 0x005f},
+ {8, 0x001f},
+ {9, 0x009e},
+ {7, 0x0117},
+ {8, 0x007f},
+ {8, 0x003f},
+ {9, 0x00de},
+ {7, 0x010f},
+ {8, 0x006f},
+ {8, 0x002f},
+ {9, 0x00be},
+ {8, 0x000f},
+ {8, 0x008f},
+ {8, 0x004f},
+ {9, 0x00fe},
+ {7, 0x0100},
+ {8, 0x0050},
+ {8, 0x0010},
+ {8, 0x0118},
+ {7, 0x0110},
+ {8, 0x0070},
+ {8, 0x0030},
+ {9, 0x00c1},
+ {7, 0x0108},
+ {8, 0x0060},
+ {8, 0x0020},
+ {9, 0x00a1},
+ {8, 0x0000},
+ {8, 0x0080},
+ {8, 0x0040},
+ {9, 0x00e1},
+ {7, 0x0104},
+ {8, 0x0058},
+ {8, 0x0018},
+ {9, 0x0091},
+ {7, 0x0114},
+ {8, 0x0078},
+ {8, 0x0038},
+ {9, 0x00d1},
+ {7, 0x010c},
+ {8, 0x0068},
+ {8, 0x0028},
+ {9, 0x00b1},
+ {8, 0x0008},
+ {8, 0x0088},
+ {8, 0x0048},
+ {9, 0x00f1},
+ {7, 0x0102},
+ {8, 0x0054},
+ {8, 0x0014},
+ {8, 0x011c},
+ {7, 0x0112},
+ {8, 0x0074},
+ {8, 0x0034},
+ {9, 0x00c9},
+ {7, 0x010a},
+ {8, 0x0064},
+ {8, 0x0024},
+ {9, 0x00a9},
+ {8, 0x0004},
+ {8, 0x0084},
+ {8, 0x0044},
+ {9, 0x00e9},
+ {7, 0x0106},
+ {8, 0x005c},
+ {8, 0x001c},
+ {9, 0x0099},
+ {7, 0x0116},
+ {8, 0x007c},
+ {8, 0x003c},
+ {9, 0x00d9},
+ {7, 0x010e},
+ {8, 0x006c},
+ {8, 0x002c},
+ {9, 0x00b9},
+ {8, 0x000c},
+ {8, 0x008c},
+ {8, 0x004c},
+ {9, 0x00f9},
+ {7, 0x0101},
+ {8, 0x0052},
+ {8, 0x0012},
+ {8, 0x011a},
+ {7, 0x0111},
+ {8, 0x0072},
+ {8, 0x0032},
+ {9, 0x00c5},
+ {7, 0x0109},
+ {8, 0x0062},
+ {8, 0x0022},
+ {9, 0x00a5},
+ {8, 0x0002},
+ {8, 0x0082},
+ {8, 0x0042},
+ {9, 0x00e5},
+ {7, 0x0105},
+ {8, 0x005a},
+ {8, 0x001a},
+ {9, 0x0095},
+ {7, 0x0115},
+ {8, 0x007a},
+ {8, 0x003a},
+ {9, 0x00d5},
+ {7, 0x010d},
+ {8, 0x006a},
+ {8, 0x002a},
+ {9, 0x00b5},
+ {8, 0x000a},
+ {8, 0x008a},
+ {8, 0x004a},
+ {9, 0x00f5},
+ {7, 0x0103},
+ {8, 0x0056},
+ {8, 0x0016},
+ {8, 0x011e},
+ {7, 0x0113},
+ {8, 0x0076},
+ {8, 0x0036},
+ {9, 0x00cd},
+ {7, 0x010b},
+ {8, 0x0066},
+ {8, 0x0026},
+ {9, 0x00ad},
+ {8, 0x0006},
+ {8, 0x0086},
+ {8, 0x0046},
+ {9, 0x00ed},
+ {7, 0x0107},
+ {8, 0x005e},
+ {8, 0x001e},
+ {9, 0x009d},
+ {7, 0x0117},
+ {8, 0x007e},
+ {8, 0x003e},
+ {9, 0x00dd},
+ {7, 0x010f},
+ {8, 0x006e},
+ {8, 0x002e},
+ {9, 0x00bd},
+ {8, 0x000e},
+ {8, 0x008e},
+ {8, 0x004e},
+ {9, 0x00fd},
+ {7, 0x0100},
+ {8, 0x0051},
+ {8, 0x0011},
+ {8, 0x0119},
+ {7, 0x0110},
+ {8, 0x0071},
+ {8, 0x0031},
+ {9, 0x00c3},
+ {7, 0x0108},
+ {8, 0x0061},
+ {8, 0x0021},
+ {9, 0x00a3},
+ {8, 0x0001},
+ {8, 0x0081},
+ {8, 0x0041},
+ {9, 0x00e3},
+ {7, 0x0104},
+ {8, 0x0059},
+ {8, 0x0019},
+ {9, 0x0093},
+ {7, 0x0114},
+ {8, 0x0079},
+ {8, 0x0039},
+ {9, 0x00d3},
+ {7, 0x010c},
+ {8, 0x0069},
+ {8, 0x0029},
+ {9, 0x00b3},
+ {8, 0x0009},
+ {8, 0x0089},
+ {8, 0x0049},
+ {9, 0x00f3},
+ {7, 0x0102},
+ {8, 0x0055},
+ {8, 0x0015},
+ {8, 0x011d},
+ {7, 0x0112},
+ {8, 0x0075},
+ {8, 0x0035},
+ {9, 0x00cb},
+ {7, 0x010a},
+ {8, 0x0065},
+ {8, 0x0025},
+ {9, 0x00ab},
+ {8, 0x0005},
+ {8, 0x0085},
+ {8, 0x0045},
+ {9, 0x00eb},
+ {7, 0x0106},
+ {8, 0x005d},
+ {8, 0x001d},
+ {9, 0x009b},
+ {7, 0x0116},
+ {8, 0x007d},
+ {8, 0x003d},
+ {9, 0x00db},
+ {7, 0x010e},
+ {8, 0x006d},
+ {8, 0x002d},
+ {9, 0x00bb},
+ {8, 0x000d},
+ {8, 0x008d},
+ {8, 0x004d},
+ {9, 0x00fb},
+ {7, 0x0101},
+ {8, 0x0053},
+ {8, 0x0013},
+ {8, 0x011b},
+ {7, 0x0111},
+ {8, 0x0073},
+ {8, 0x0033},
+ {9, 0x00c7},
+ {7, 0x0109},
+ {8, 0x0063},
+ {8, 0x0023},
+ {9, 0x00a7},
+ {8, 0x0003},
+ {8, 0x0083},
+ {8, 0x0043},
+ {9, 0x00e7},
+ {7, 0x0105},
+ {8, 0x005b},
+ {8, 0x001b},
+ {9, 0x0097},
+ {7, 0x0115},
+ {8, 0x007b},
+ {8, 0x003b},
+ {9, 0x00d7},
+ {7, 0x010d},
+ {8, 0x006b},
+ {8, 0x002b},
+ {9, 0x00b7},
+ {8, 0x000b},
+ {8, 0x008b},
+ {8, 0x004b},
+ {9, 0x00f7},
+ {7, 0x0103},
+ {8, 0x0057},
+ {8, 0x0017},
+ {8, 0x011f},
+ {7, 0x0113},
+ {8, 0x0077},
+ {8, 0x0037},
+ {9, 0x00cf},
+ {7, 0x010b},
+ {8, 0x0067},
+ {8, 0x0027},
+ {9, 0x00af},
+ {8, 0x0007},
+ {8, 0x0087},
+ {8, 0x0047},
+ {9, 0x00ef},
+ {7, 0x0107},
+ {8, 0x005f},
+ {8, 0x001f},
+ {9, 0x009f},
+ {7, 0x0117},
+ {8, 0x007f},
+ {8, 0x003f},
+ {9, 0x00df},
+ {7, 0x010f},
+ {8, 0x006f},
+ {8, 0x002f},
+ {9, 0x00bf},
+ {8, 0x000f},
+ {8, 0x008f},
+ {8, 0x004f},
+ {9, 0x00ff}
+};
+
+FlateHuffmanTab FlateStream::fixedLitCodeTab = {
+ flateFixedLitCodeTabCodes, 9
+};
+
+static FlateCode flateFixedDistCodeTabCodes[32] = {
+ {5, 0x0000},
+ {5, 0x0010},
+ {5, 0x0008},
+ {5, 0x0018},
+ {5, 0x0004},
+ {5, 0x0014},
+ {5, 0x000c},
+ {5, 0x001c},
+ {5, 0x0002},
+ {5, 0x0012},
+ {5, 0x000a},
+ {5, 0x001a},
+ {5, 0x0006},
+ {5, 0x0016},
+ {5, 0x000e},
+ {0, 0x0000},
+ {5, 0x0001},
+ {5, 0x0011},
+ {5, 0x0009},
+ {5, 0x0019},
+ {5, 0x0005},
+ {5, 0x0015},
+ {5, 0x000d},
+ {5, 0x001d},
+ {5, 0x0003},
+ {5, 0x0013},
+ {5, 0x000b},
+ {5, 0x001b},
+ {5, 0x0007},
+ {5, 0x0017},
+ {5, 0x000f},
+ {0, 0x0000}
+};
+
+FlateHuffmanTab FlateStream::fixedDistCodeTab = {
+ flateFixedDistCodeTabCodes, 5
+};
+
+FlateStream::FlateStream(Stream *strA, int predictor, int columns,
+ int colors, int bits):
+ FilterStream(strA) {
+ if (predictor != 1) {
+ pred = new StreamPredictor(this, predictor, columns, colors, bits);
+ if (!pred->isOk()) {
+ delete pred;
+ pred = NULL;
+ }
+ } else {
+ pred = NULL;
+ }
+ litCodeTab.codes = NULL;
+ distCodeTab.codes = NULL;
+ memset(buf, 0, flateWindow);
+}
+
+FlateStream::~FlateStream() {
+ if (litCodeTab.codes != fixedLitCodeTab.codes) {
+ gfree(litCodeTab.codes);
+ }
+ if (distCodeTab.codes != fixedDistCodeTab.codes) {
+ gfree(distCodeTab.codes);
+ }
+ if (pred) {
+ delete pred;
+ }
+ delete str;
+}
+
+void FlateStream::reset() {
+ int cmf, flg;
+
+ index = 0;
+ remain = 0;
+ codeBuf = 0;
+ codeSize = 0;
+ compressedBlock = gFalse;
+ endOfBlock = gTrue;
+ eof = gTrue;
+
+ str->reset();
+
+ // read header
+ //~ need to look at window size?
+ endOfBlock = eof = gTrue;
+ cmf = str->getChar();
+ flg = str->getChar();
+ if (cmf == EOF || flg == EOF)
+ return;
+ if ((cmf & 0x0f) != 0x08) {
+ error(getPos(), "Unknown compression method in flate stream");
+ return;
+ }
+ if ((((cmf << 8) + flg) % 31) != 0) {
+ error(getPos(), "Bad FCHECK in flate stream");
+ return;
+ }
+ if (flg & 0x20) {
+ error(getPos(), "FDICT bit set in flate stream");
+ return;
+ }
+
+ eof = gFalse;
+}
+
+int FlateStream::getChar() {
+ int c;
+
+ if (pred) {
+ return pred->getChar();
+ }
+ while (remain == 0) {
+ if (endOfBlock && eof)
+ return EOF;
+ readSome();
+ }
+ c = buf[index];
+ index = (index + 1) & flateMask;
+ --remain;
+ return c;
+}
+
+int FlateStream::lookChar() {
+ int c;
+
+ if (pred) {
+ return pred->lookChar();
+ }
+ while (remain == 0) {
+ if (endOfBlock && eof)
+ return EOF;
+ readSome();
+ }
+ c = buf[index];
+ return c;
+}
+
+int FlateStream::getRawChar() {
+ int c;
+
+ while (remain == 0) {
+ if (endOfBlock && eof)
+ return EOF;
+ readSome();
+ }
+ c = buf[index];
+ index = (index + 1) & flateMask;
+ --remain;
+ return c;
+}
+
+GString *FlateStream::getPSFilter(int psLevel, char *indent) {
+ GString *s;
+
+ if (psLevel < 3 || pred) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
+ return NULL;
+ }
+ s->append(indent)->append("<< >> /FlateDecode filter\n");
+ return s;
+}
+
+GBool FlateStream::isBinary(GBool /*last*/) {
+ return str->isBinary(gTrue);
+}
+
+void FlateStream::readSome() {
+ int code1, code2;
+ int len, dist;
+ int i, j, k;
+ int c;
+
+ if (endOfBlock) {
+ if (!startBlock())
+ return;
+ }
+
+ if (compressedBlock) {
+ if ((code1 = getHuffmanCodeWord(&litCodeTab)) == EOF)
+ goto err;
+ if (code1 < 256) {
+ buf[index] = code1;
+ remain = 1;
+ } else if (code1 == 256) {
+ endOfBlock = gTrue;
+ remain = 0;
+ } else {
+ code1 -= 257;
+ code2 = lengthDecode[code1].bits;
+ if (code2 > 0 && (code2 = getCodeWord(code2)) == EOF)
+ goto err;
+ len = lengthDecode[code1].first + code2;
+ if ((code1 = getHuffmanCodeWord(&distCodeTab)) == EOF)
+ goto err;
+ code2 = distDecode[code1].bits;
+ if (code2 > 0 && (code2 = getCodeWord(code2)) == EOF)
+ goto err;
+ dist = distDecode[code1].first + code2;
+ i = index;
+ j = (index - dist) & flateMask;
+ for (k = 0; k < len; ++k) {
+ buf[i] = buf[j];
+ i = (i + 1) & flateMask;
+ j = (j + 1) & flateMask;
+ }
+ remain = len;
+ }
+
+ } else {
+ len = (blockLen < flateWindow) ? blockLen : flateWindow;
+ for (i = 0, j = index; i < len; ++i, j = (j + 1) & flateMask) {
+ if ((c = str->getChar()) == EOF) {
+ endOfBlock = eof = gTrue;
+ break;
+ }
+ buf[j] = c & 0xff;
+ }
+ remain = i;
+ blockLen -= len;
+ if (blockLen == 0)
+ endOfBlock = gTrue;
+ }
+
+ return;
+
+err:
+ error(getPos(), "Unexpected end of file in flate stream");
+ endOfBlock = eof = gTrue;
+ remain = 0;
+}
+
+GBool FlateStream::startBlock() {
+ int blockHdr;
+ int c;
+ int check;
+
+ // free the code tables from the previous block
+ if (litCodeTab.codes != fixedLitCodeTab.codes) {
+ gfree(litCodeTab.codes);
+ }
+ litCodeTab.codes = NULL;
+ if (distCodeTab.codes != fixedDistCodeTab.codes) {
+ gfree(distCodeTab.codes);
+ }
+ distCodeTab.codes = NULL;
+
+ // read block header
+ blockHdr = getCodeWord(3);
+ if (blockHdr & 1)
+ eof = gTrue;
+ blockHdr >>= 1;
+
+ // uncompressed block
+ if (blockHdr == 0) {
+ compressedBlock = gFalse;
+ if ((c = str->getChar()) == EOF)
+ goto err;
+ blockLen = c & 0xff;
+ if ((c = str->getChar()) == EOF)
+ goto err;
+ blockLen |= (c & 0xff) << 8;
+ if ((c = str->getChar()) == EOF)
+ goto err;
+ check = c & 0xff;
+ if ((c = str->getChar()) == EOF)
+ goto err;
+ check |= (c & 0xff) << 8;
+ if (check != (~blockLen & 0xffff))
+ error(getPos(), "Bad uncompressed block length in flate stream");
+ codeBuf = 0;
+ codeSize = 0;
+
+ // compressed block with fixed codes
+ } else if (blockHdr == 1) {
+ compressedBlock = gTrue;
+ loadFixedCodes();
+
+ // compressed block with dynamic codes
+ } else if (blockHdr == 2) {
+ compressedBlock = gTrue;
+ if (!readDynamicCodes()) {
+ goto err;
+ }
+
+ // unknown block type
+ } else {
+ goto err;
+ }
+
+ endOfBlock = gFalse;
+ return gTrue;
+
+err:
+ error(getPos(), "Bad block header in flate stream");
+ endOfBlock = eof = gTrue;
+ return gFalse;
+}
+
+void FlateStream::loadFixedCodes() {
+ litCodeTab.codes = fixedLitCodeTab.codes;
+ litCodeTab.maxLen = fixedLitCodeTab.maxLen;
+ distCodeTab.codes = fixedDistCodeTab.codes;
+ distCodeTab.maxLen = fixedDistCodeTab.maxLen;
+}
+
+GBool FlateStream::readDynamicCodes() {
+ int numCodeLenCodes;
+ int numLitCodes;
+ int numDistCodes;
+ int codeLenCodeLengths[flateMaxCodeLenCodes];
+ FlateHuffmanTab codeLenCodeTab;
+ int len, repeat, code;
+ int i;
+
+ codeLenCodeTab.codes = NULL;
+
+ // read lengths
+ if ((numLitCodes = getCodeWord(5)) == EOF) {
+ goto err;
+ }
+ numLitCodes += 257;
+ if ((numDistCodes = getCodeWord(5)) == EOF) {
+ goto err;
+ }
+ numDistCodes += 1;
+ if ((numCodeLenCodes = getCodeWord(4)) == EOF) {
+ goto err;
+ }
+ numCodeLenCodes += 4;
+ if (numLitCodes > flateMaxLitCodes ||
+ numDistCodes > flateMaxDistCodes ||
+ numCodeLenCodes > flateMaxCodeLenCodes) {
+ goto err;
+ }
+
+ // build the code length code table
+ for (i = 0; i < flateMaxCodeLenCodes; ++i) {
+ codeLenCodeLengths[i] = 0;
+ }
+ for (i = 0; i < numCodeLenCodes; ++i) {
+ if ((codeLenCodeLengths[codeLenCodeMap[i]] = getCodeWord(3)) == -1) {
+ goto err;
+ }
+ }
+ compHuffmanCodes(codeLenCodeLengths, flateMaxCodeLenCodes, &codeLenCodeTab);
+
+ // build the literal and distance code tables
+ len = 0;
+ repeat = 0;
+ i = 0;
+ while (i < numLitCodes + numDistCodes) {
+ if ((code = getHuffmanCodeWord(&codeLenCodeTab)) == EOF) {
+ goto err;
+ }
+ if (code == 16) {
+ if ((repeat = getCodeWord(2)) == EOF) {
+ goto err;
+ }
+ repeat += 3;
+ if (i + repeat > numLitCodes + numDistCodes) {
+ goto err;
+ }
+ for (; repeat > 0; --repeat) {
+ codeLengths[i++] = len;
+ }
+ } else if (code == 17) {
+ if ((repeat = getCodeWord(3)) == EOF) {
+ goto err;
+ }
+ repeat += 3;
+ if (i + repeat > numLitCodes + numDistCodes) {
+ goto err;
+ }
+ len = 0;
+ for (; repeat > 0; --repeat) {
+ codeLengths[i++] = 0;
+ }
+ } else if (code == 18) {
+ if ((repeat = getCodeWord(7)) == EOF) {
+ goto err;
+ }
+ repeat += 11;
+ if (i + repeat > numLitCodes + numDistCodes) {
+ goto err;
+ }
+ len = 0;
+ for (; repeat > 0; --repeat) {
+ codeLengths[i++] = 0;
+ }
+ } else {
+ codeLengths[i++] = len = code;
+ }
+ }
+ compHuffmanCodes(codeLengths, numLitCodes, &litCodeTab);
+ compHuffmanCodes(codeLengths + numLitCodes, numDistCodes, &distCodeTab);
+
+ gfree(codeLenCodeTab.codes);
+ return gTrue;
+
+err:
+ error(getPos(), "Bad dynamic code table in flate stream");
+ gfree(codeLenCodeTab.codes);
+ return gFalse;
+}
+
+// Convert an array <lengths> of <n> lengths, in value order, into a
+// Huffman code lookup table.
+void FlateStream::compHuffmanCodes(int *lengths, int n, FlateHuffmanTab *tab) {
+ int tabSize, len, code, code2, skip, val, i, t;
+
+ // find max code length
+ tab->maxLen = 0;
+ for (val = 0; val < n; ++val) {
+ if (lengths[val] > tab->maxLen) {
+ tab->maxLen = lengths[val];
+ }
+ }
+
+ // allocate the table
+ tabSize = 1 << tab->maxLen;
+ tab->codes = (FlateCode *)gmallocn(tabSize, sizeof(FlateCode));
+
+ // clear the table
+ for (i = 0; i < tabSize; ++i) {
+ tab->codes[i].len = 0;
+ tab->codes[i].val = 0;
+ }
+
+ // build the table
+ for (len = 1, code = 0, skip = 2;
+ len <= tab->maxLen;
+ ++len, code <<= 1, skip <<= 1) {
+ for (val = 0; val < n; ++val) {
+ if (lengths[val] == len) {
+
+ // bit-reverse the code
+ code2 = 0;
+ t = code;
+ for (i = 0; i < len; ++i) {
+ code2 = (code2 << 1) | (t & 1);
+ t >>= 1;
+ }
+
+ // fill in the table entries
+ for (i = code2; i < tabSize; i += skip) {
+ tab->codes[i].len = (Gushort)len;
+ tab->codes[i].val = (Gushort)val;
+ }
+
+ ++code;
+ }
+ }
+ }
+}
+
+int FlateStream::getHuffmanCodeWord(FlateHuffmanTab *tab) {
+ FlateCode *code;
+ int c;
+
+ while (codeSize < tab->maxLen) {
+ if ((c = str->getChar()) == EOF) {
+ break;
+ }
+ codeBuf |= (c & 0xff) << codeSize;
+ codeSize += 8;
+ }
+ code = &tab->codes[codeBuf & ((1 << tab->maxLen) - 1)];
+ if (codeSize == 0 || codeSize < code->len || code->len == 0) {
+ return EOF;
+ }
+ codeBuf >>= code->len;
+ codeSize -= code->len;
+ return (int)code->val;
+}
+
+int FlateStream::getCodeWord(int bits) {
+ int c;
+
+ while (codeSize < bits) {
+ if ((c = str->getChar()) == EOF)
+ return EOF;
+ codeBuf |= (c & 0xff) << codeSize;
+ codeSize += 8;
+ }
+ c = codeBuf & ((1 << bits) - 1);
+ codeBuf >>= bits;
+ codeSize -= bits;
+ return c;
+}
+
+//------------------------------------------------------------------------
+// EOFStream
+//------------------------------------------------------------------------
+
+EOFStream::EOFStream(Stream *strA):
+ FilterStream(strA) {
+}
+
+EOFStream::~EOFStream() {
+ delete str;
+}
+
+//------------------------------------------------------------------------
+// FixedLengthEncoder
+//------------------------------------------------------------------------
+
+FixedLengthEncoder::FixedLengthEncoder(Stream *strA, int lengthA):
+ FilterStream(strA) {
+ length = lengthA;
+ count = 0;
+}
+
+FixedLengthEncoder::~FixedLengthEncoder() {
+ if (str->isEncoder())
+ delete str;
+}
+
+void FixedLengthEncoder::reset() {
+ str->reset();
+ count = 0;
+}
+
+int FixedLengthEncoder::getChar() {
+ if (length >= 0 && count >= length)
+ return EOF;
+ ++count;
+ return str->getChar();
+}
+
+int FixedLengthEncoder::lookChar() {
+ if (length >= 0 && count >= length)
+ return EOF;
+ return str->getChar();
+}
+
+GBool FixedLengthEncoder::isBinary(GBool /*last*/) {
+ return str->isBinary(gTrue);
+}
+
+//------------------------------------------------------------------------
+// ASCIIHexEncoder
+//------------------------------------------------------------------------
+
+ASCIIHexEncoder::ASCIIHexEncoder(Stream *strA):
+ FilterStream(strA) {
+ bufPtr = bufEnd = buf;
+ lineLen = 0;
+ eof = gFalse;
+}
+
+ASCIIHexEncoder::~ASCIIHexEncoder() {
+ if (str->isEncoder()) {
+ delete str;
+ }
+}
+
+void ASCIIHexEncoder::reset() {
+ str->reset();
+ bufPtr = bufEnd = buf;
+ lineLen = 0;
+ eof = gFalse;
+}
+
+GBool ASCIIHexEncoder::fillBuf() {
+ static char *hex = "0123456789abcdef";
+ int c;
+
+ if (eof) {
+ return gFalse;
+ }
+ bufPtr = bufEnd = buf;
+ if ((c = str->getChar()) == EOF) {
+ *bufEnd++ = '>';
+ eof = gTrue;
+ } else {
+ if (lineLen >= 64) {
+ *bufEnd++ = '\n';
+ lineLen = 0;
+ }
+ *bufEnd++ = hex[(c >> 4) & 0x0f];
+ *bufEnd++ = hex[c & 0x0f];
+ lineLen += 2;
+ }
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
+// ASCII85Encoder
+//------------------------------------------------------------------------
+
+ASCII85Encoder::ASCII85Encoder(Stream *strA):
+ FilterStream(strA) {
+ bufPtr = bufEnd = buf;
+ lineLen = 0;
+ eof = gFalse;
+}
+
+ASCII85Encoder::~ASCII85Encoder() {
+ if (str->isEncoder())
+ delete str;
+}
+
+void ASCII85Encoder::reset() {
+ str->reset();
+ bufPtr = bufEnd = buf;
+ lineLen = 0;
+ eof = gFalse;
+}
+
+GBool ASCII85Encoder::fillBuf() {
+ Guint t;
+ char buf1[5];
+ int c0, c1, c2, c3;
+ int n, i;
+
+ if (eof) {
+ return gFalse;
+ }
+ c0 = str->getChar();
+ c1 = str->getChar();
+ c2 = str->getChar();
+ c3 = str->getChar();
+ bufPtr = bufEnd = buf;
+ if (c3 == EOF) {
+ if (c0 == EOF) {
+ n = 0;
+ t = 0;
+ } else {
+ if (c1 == EOF) {
+ n = 1;
+ t = c0 << 24;
+ } else if (c2 == EOF) {
+ n = 2;
+ t = (c0 << 24) | (c1 << 16);
+ } else {
+ n = 3;
+ t = (c0 << 24) | (c1 << 16) | (c2 << 8);
+ }
+ for (i = 4; i >= 0; --i) {
+ buf1[i] = (char)(t % 85 + 0x21);
+ t /= 85;
+ }
+ for (i = 0; i <= n; ++i) {
+ *bufEnd++ = buf1[i];
+ if (++lineLen == 65) {
+ *bufEnd++ = '\n';
+ lineLen = 0;
+ }
+ }
+ }
+ *bufEnd++ = '~';
+ *bufEnd++ = '>';
+ eof = gTrue;
+ } else {
+ t = (c0 << 24) | (c1 << 16) | (c2 << 8) | c3;
+ if (t == 0) {
+ *bufEnd++ = 'z';
+ if (++lineLen == 65) {
+ *bufEnd++ = '\n';
+ lineLen = 0;
+ }
+ } else {
+ for (i = 4; i >= 0; --i) {
+ buf1[i] = (char)(t % 85 + 0x21);
+ t /= 85;
+ }
+ for (i = 0; i <= 4; ++i) {
+ *bufEnd++ = buf1[i];
+ if (++lineLen == 65) {
+ *bufEnd++ = '\n';
+ lineLen = 0;
+ }
+ }
+ }
+ }
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
+// RunLengthEncoder
+//------------------------------------------------------------------------
+
+RunLengthEncoder::RunLengthEncoder(Stream *strA):
+ FilterStream(strA) {
+ bufPtr = bufEnd = nextEnd = buf;
+ eof = gFalse;
+}
+
+RunLengthEncoder::~RunLengthEncoder() {
+ if (str->isEncoder())
+ delete str;
+}
+
+void RunLengthEncoder::reset() {
+ str->reset();
+ bufPtr = bufEnd = nextEnd = buf;
+ eof = gFalse;
+}
+
+//
+// When fillBuf finishes, buf[] looks like this:
+// +-----+--------------+-----------------+--
+// + tag | ... data ... | next 0, 1, or 2 |
+// +-----+--------------+-----------------+--
+// ^ ^ ^
+// bufPtr bufEnd nextEnd
+//
+GBool RunLengthEncoder::fillBuf() {
+ int c, c1, c2;
+ int n;
+
+ // already hit EOF?
+ if (eof)
+ return gFalse;
+
+ // grab two bytes
+ if (nextEnd < bufEnd + 1) {
+ if ((c1 = str->getChar()) == EOF) {
+ eof = gTrue;
+ return gFalse;
+ }
+ } else {
+ c1 = bufEnd[0] & 0xff;
+ }
+ if (nextEnd < bufEnd + 2) {
+ if ((c2 = str->getChar()) == EOF) {
+ eof = gTrue;
+ buf[0] = 0;
+ buf[1] = c1;
+ bufPtr = buf;
+ bufEnd = &buf[2];
+ return gTrue;
+ }
+ } else {
+ c2 = bufEnd[1] & 0xff;
+ }
+
+ // check for repeat
+ c = 0; // make gcc happy
+ if (c1 == c2) {
+ n = 2;
+ while (n < 128 && (c = str->getChar()) == c1)
+ ++n;
+ buf[0] = (char)(257 - n);
+ buf[1] = c1;
+ bufEnd = &buf[2];
+ if (c == EOF) {
+ eof = gTrue;
+ } else if (n < 128) {
+ buf[2] = c;
+ nextEnd = &buf[3];
+ } else {
+ nextEnd = bufEnd;
+ }
+
+ // get up to 128 chars
+ } else {
+ buf[1] = c1;
+ buf[2] = c2;
+ n = 2;
+ while (n < 128) {
+ if ((c = str->getChar()) == EOF) {
+ eof = gTrue;
+ break;
+ }
+ ++n;
+ buf[n] = c;
+ if (buf[n] == buf[n-1])
+ break;
+ }
+ if (buf[n] == buf[n-1]) {
+ buf[0] = (char)(n-2-1);
+ bufEnd = &buf[n-1];
+ nextEnd = &buf[n+1];
+ } else {
+ buf[0] = (char)(n-1);
+ bufEnd = nextEnd = &buf[n+1];
+ }
+ }
+ bufPtr = buf;
+ return gTrue;
+}
diff --git a/kpdf/xpdf/xpdf/Stream.h b/kpdf/xpdf/xpdf/Stream.h
new file mode 100644
index 00000000..b2f71de7
--- /dev/null
+++ b/kpdf/xpdf/xpdf/Stream.h
@@ -0,0 +1,860 @@
+//========================================================================
+//
+// Stream.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef STREAM_H
+#define STREAM_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include <stdio.h>
+#include "gtypes.h"
+#include "Object.h"
+
+class BaseStream;
+
+//------------------------------------------------------------------------
+
+enum StreamKind {
+ strFile,
+ strASCIIHex,
+ strASCII85,
+ strLZW,
+ strRunLength,
+ strCCITTFax,
+ strDCT,
+ strFlate,
+ strJBIG2,
+ strJPX,
+ strWeird // internal-use stream types
+};
+
+enum StreamColorSpaceMode {
+ streamCSNone,
+ streamCSDeviceGray,
+ streamCSDeviceRGB,
+ streamCSDeviceCMYK
+};
+
+//------------------------------------------------------------------------
+
+// This is in Stream.h instead of Decrypt.h to avoid really annoying
+// include file dependency loops.
+enum CryptAlgorithm {
+ cryptRC4,
+ cryptAES
+};
+
+//------------------------------------------------------------------------
+// Stream (base class)
+//------------------------------------------------------------------------
+
+class Stream {
+public:
+
+ // Constructor.
+ Stream();
+
+ // Destructor.
+ virtual ~Stream();
+
+ // Reference counting.
+ int incRef() { return ++ref; }
+ int decRef() { return --ref; }
+
+ // Get kind of stream.
+ virtual StreamKind getKind() = 0;
+
+ // Reset stream to beginning.
+ virtual void reset() = 0;
+
+ // Close down the stream.
+ virtual void close();
+
+ // Get next char from stream.
+ virtual int getChar() = 0;
+
+ // Peek at next char in stream.
+ virtual int lookChar() = 0;
+
+ // Get next char from stream without using the predictor.
+ // This is only used by StreamPredictor.
+ virtual int getRawChar();
+
+ // Get next line from stream.
+ virtual char *getLine(char *buf, int size);
+
+ // Get current position in file.
+ virtual int getPos() = 0;
+
+ // Go to a position in the stream. If <dir> is negative, the
+ // position is from the end of the file; otherwise the position is
+ // from the start of the file.
+ virtual void setPos(Guint pos, int dir = 0) = 0;
+
+ // Get PostScript command for the filter(s).
+ virtual GString *getPSFilter(int psLevel, char *indent);
+
+ // Does this stream type potentially contain non-printable chars?
+ virtual GBool isBinary(GBool last = gTrue) = 0;
+
+ // Get the BaseStream of this stream.
+ virtual BaseStream *getBaseStream() = 0;
+
+ // Get the stream after the last decoder (this may be a BaseStream
+ // or a DecryptStream).
+ virtual Stream *getUndecodedStream() = 0;
+
+ // Get the dictionary associated with this stream.
+ virtual Dict *getDict() = 0;
+
+ // Is this an encoding filter?
+ virtual GBool isEncoder() { return gFalse; }
+
+ // Get image parameters which are defined by the stream contents.
+ virtual void getImageParams(int * /*bitsPerComponent*/,
+ StreamColorSpaceMode * /*csMode*/) {}
+
+ // Return the next stream in the "stack".
+ virtual Stream *getNextStream() { return NULL; }
+
+ // Add filters to this stream according to the parameters in <dict>.
+ // Returns the new stream.
+ Stream *addFilters(Object *dict);
+
+private:
+
+ Stream *makeFilter(char *name, Stream *str, Object *params);
+
+ int ref; // reference count
+};
+
+//------------------------------------------------------------------------
+// BaseStream
+//
+// This is the base class for all streams that read directly from a file.
+//------------------------------------------------------------------------
+
+class BaseStream: public Stream {
+public:
+
+ BaseStream(Object *dictA);
+ virtual ~BaseStream();
+ virtual Stream *makeSubStream(Guint start, GBool limited,
+ Guint length, Object *dict) = 0;
+ virtual void setPos(Guint pos, int dir = 0) = 0;
+ virtual GBool isBinary(GBool last = gTrue) { return last; }
+ virtual BaseStream *getBaseStream() { return this; }
+ virtual Stream *getUndecodedStream() { return this; }
+ virtual Dict *getDict() { return dict.getDict(); }
+ virtual GString *getFileName() { return NULL; }
+
+ // Get/set position of first byte of stream within the file.
+ virtual Guint getStart() = 0;
+ virtual void moveStart(int delta) = 0;
+
+private:
+
+ Object dict;
+};
+
+//------------------------------------------------------------------------
+// FilterStream
+//
+// This is the base class for all streams that filter another stream.
+//------------------------------------------------------------------------
+
+class FilterStream: public Stream {
+public:
+
+ FilterStream(Stream *strA);
+ virtual ~FilterStream();
+ virtual void close();
+ virtual int getPos() { return str->getPos(); }
+ virtual void setPos(Guint pos, int dir = 0);
+ virtual BaseStream *getBaseStream() { return str->getBaseStream(); }
+ virtual Stream *getUndecodedStream() { return str->getUndecodedStream(); }
+ virtual Dict *getDict() { return str->getDict(); }
+ virtual Stream *getNextStream() { return str; }
+
+protected:
+
+ Stream *str;
+};
+
+//------------------------------------------------------------------------
+// ImageStream
+//------------------------------------------------------------------------
+
+class ImageStream {
+public:
+
+ // Create an image stream object for an image with the specified
+ // parameters. Note that these are the actual image parameters,
+ // which may be different from the predictor parameters.
+ ImageStream(Stream *strA, int widthA, int nCompsA, int nBitsA);
+
+ ~ImageStream();
+
+ // Reset the stream.
+ void reset();
+
+ // Gets the next pixel from the stream. <pix> should be able to hold
+ // at least nComps elements. Returns false at end of file.
+ GBool getPixel(Guchar *pix);
+
+ // Returns a pointer to the next line of pixels. Returns NULL at
+ // end of file.
+ Guchar *getLine();
+
+ // Skip an entire line from the image.
+ void skipLine();
+
+private:
+
+ Stream *str; // base stream
+ int width; // pixels per line
+ int nComps; // components per pixel
+ int nBits; // bits per component
+ int nVals; // components per line
+ Guchar *imgLine; // line buffer
+ int imgIdx; // current index in imgLine
+};
+
+//------------------------------------------------------------------------
+// StreamPredictor
+//------------------------------------------------------------------------
+
+class StreamPredictor {
+public:
+
+ // Create a predictor object. Note that the parameters are for the
+ // predictor, and may not match the actual image parameters.
+ StreamPredictor(Stream *strA, int predictorA,
+ int widthA, int nCompsA, int nBitsA);
+
+ ~StreamPredictor();
+
+ GBool isOk() { return ok; }
+
+ int lookChar();
+ int getChar();
+
+private:
+
+ GBool getNextLine();
+
+ Stream *str; // base stream
+ int predictor; // predictor
+ int width; // pixels per line
+ int nComps; // components per pixel
+ int nBits; // bits per component
+ int nVals; // components per line
+ int pixBytes; // bytes per pixel
+ int rowBytes; // bytes per line
+ Guchar *predLine; // line buffer
+ int predIdx; // current index in predLine
+ GBool ok;
+};
+
+//------------------------------------------------------------------------
+// FileStream
+//------------------------------------------------------------------------
+
+#define fileStreamBufSize 256
+
+class FileStream: public BaseStream {
+public:
+
+ FileStream(FILE *fA, Guint startA, GBool limitedA,
+ Guint lengthA, Object *dictA);
+ virtual ~FileStream();
+ virtual Stream *makeSubStream(Guint startA, GBool limitedA,
+ Guint lengthA, Object *dictA);
+ virtual StreamKind getKind() { return strFile; }
+ virtual void reset();
+ virtual void close();
+ virtual int getChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
+ virtual int lookChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
+ virtual int getPos() { return bufPos + (bufPtr - buf); }
+ virtual void setPos(Guint pos, int dir = 0);
+ virtual Guint getStart() { return start; }
+ virtual void moveStart(int delta);
+
+private:
+
+ GBool fillBuf();
+
+ FILE *f;
+ Guint start;
+ GBool limited;
+ Guint length;
+ char buf[fileStreamBufSize];
+ char *bufPtr;
+ char *bufEnd;
+ Guint bufPos;
+ int savePos;
+ GBool saved;
+};
+
+//------------------------------------------------------------------------
+// MemStream
+//------------------------------------------------------------------------
+
+class MemStream: public BaseStream {
+public:
+
+ MemStream(char *bufA, Guint startA, Guint lengthA, Object *dictA);
+ virtual ~MemStream();
+ virtual Stream *makeSubStream(Guint start, GBool limited,
+ Guint lengthA, Object *dictA);
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ virtual void close();
+ virtual int getChar()
+ { return (bufPtr < bufEnd) ? (*bufPtr++ & 0xff) : EOF; }
+ virtual int lookChar()
+ { return (bufPtr < bufEnd) ? (*bufPtr & 0xff) : EOF; }
+ virtual int getPos() { return (int)(bufPtr - buf); }
+ virtual void setPos(Guint pos, int dir = 0);
+ virtual Guint getStart() { return start; }
+ virtual void moveStart(int delta);
+
+private:
+
+ char *buf;
+ Guint start;
+ Guint length;
+ char *bufEnd;
+ char *bufPtr;
+ GBool needFree;
+};
+
+//------------------------------------------------------------------------
+// EmbedStream
+//
+// This is a special stream type used for embedded streams (inline
+// images). It reads directly from the base stream -- after the
+// EmbedStream is deleted, reads from the base stream will proceed where
+// the BaseStream left off. Note that this is very different behavior
+// that creating a new FileStream (using makeSubStream).
+//------------------------------------------------------------------------
+
+class EmbedStream: public BaseStream {
+public:
+
+ EmbedStream(Stream *strA, Object *dictA, GBool limitedA, Guint lengthA);
+ virtual ~EmbedStream();
+ virtual Stream *makeSubStream(Guint start, GBool limitedA,
+ Guint lengthA, Object *dictA);
+ virtual StreamKind getKind() { return str->getKind(); }
+ virtual void reset() {}
+ virtual int getChar();
+ virtual int lookChar();
+ virtual int getPos() { return str->getPos(); }
+ virtual void setPos(Guint pos, int dir = 0);
+ virtual Guint getStart();
+ virtual void moveStart(int delta);
+
+private:
+
+ Stream *str;
+ GBool limited;
+ Guint length;
+};
+
+//------------------------------------------------------------------------
+// ASCIIHexStream
+//------------------------------------------------------------------------
+
+class ASCIIHexStream: public FilterStream {
+public:
+
+ ASCIIHexStream(Stream *strA);
+ virtual ~ASCIIHexStream();
+ virtual StreamKind getKind() { return strASCIIHex; }
+ virtual void reset();
+ virtual int getChar()
+ { int c = lookChar(); buf = EOF; return c; }
+ virtual int lookChar();
+ virtual GString *getPSFilter(int psLevel, char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+
+private:
+
+ int buf;
+ GBool eof;
+};
+
+//------------------------------------------------------------------------
+// ASCII85Stream
+//------------------------------------------------------------------------
+
+class ASCII85Stream: public FilterStream {
+public:
+
+ ASCII85Stream(Stream *strA);
+ virtual ~ASCII85Stream();
+ virtual StreamKind getKind() { return strASCII85; }
+ virtual void reset();
+ virtual int getChar()
+ { int ch = lookChar(); ++index; return ch; }
+ virtual int lookChar();
+ virtual GString *getPSFilter(int psLevel, char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+
+private:
+
+ int c[5];
+ int b[4];
+ int index, n;
+ GBool eof;
+};
+
+//------------------------------------------------------------------------
+// LZWStream
+//------------------------------------------------------------------------
+
+class LZWStream: public FilterStream {
+public:
+
+ LZWStream(Stream *strA, int predictor, int columns, int colors,
+ int bits, int earlyA);
+ virtual ~LZWStream();
+ virtual StreamKind getKind() { return strLZW; }
+ virtual void reset();
+ virtual int getChar();
+ virtual int lookChar();
+ virtual int getRawChar();
+ virtual GString *getPSFilter(int psLevel, char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+
+private:
+
+ StreamPredictor *pred; // predictor
+ int early; // early parameter
+ GBool eof; // true if at eof
+ int inputBuf; // input buffer
+ int inputBits; // number of bits in input buffer
+ struct { // decoding table
+ int length;
+ int head;
+ Guchar tail;
+ } table[4097];
+ int nextCode; // next code to be used
+ int nextBits; // number of bits in next code word
+ int prevCode; // previous code used in stream
+ int newChar; // next char to be added to table
+ Guchar seqBuf[4097]; // buffer for current sequence
+ int seqLength; // length of current sequence
+ int seqIndex; // index into current sequence
+ GBool first; // first code after a table clear
+
+ GBool processNextCode();
+ void clearTable();
+ int getCode();
+};
+
+//------------------------------------------------------------------------
+// RunLengthStream
+//------------------------------------------------------------------------
+
+class RunLengthStream: public FilterStream {
+public:
+
+ RunLengthStream(Stream *strA);
+ virtual ~RunLengthStream();
+ virtual StreamKind getKind() { return strRunLength; }
+ virtual void reset();
+ virtual int getChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
+ virtual int lookChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
+ virtual GString *getPSFilter(int psLevel, char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+
+private:
+
+ char buf[128]; // buffer
+ char *bufPtr; // next char to read
+ char *bufEnd; // end of buffer
+ GBool eof;
+
+ GBool fillBuf();
+};
+
+//------------------------------------------------------------------------
+// CCITTFaxStream
+//------------------------------------------------------------------------
+
+struct CCITTCodeTable;
+
+class CCITTFaxStream: public FilterStream {
+public:
+
+ CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA,
+ GBool byteAlignA, int columnsA, int rowsA,
+ GBool endOfBlockA, GBool blackA);
+ virtual ~CCITTFaxStream();
+ virtual StreamKind getKind() { return strCCITTFax; }
+ virtual void reset();
+ virtual int getChar()
+ { int c = lookChar(); buf = EOF; return c; }
+ virtual int lookChar();
+ virtual GString *getPSFilter(int psLevel, char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+
+private:
+
+ int encoding; // 'K' parameter
+ GBool endOfLine; // 'EndOfLine' parameter
+ GBool byteAlign; // 'EncodedByteAlign' parameter
+ int columns; // 'Columns' parameter
+ int rows; // 'Rows' parameter
+ GBool endOfBlock; // 'EndOfBlock' parameter
+ GBool black; // 'BlackIs1' parameter
+ GBool eof; // true if at eof
+ GBool nextLine2D; // true if next line uses 2D encoding
+ int row; // current row
+ int inputBuf; // input buffer
+ int inputBits; // number of bits in input buffer
+ int *codingLine; // coding line changing elements
+ int *refLine; // reference line changing elements
+ int a0i; // index into codingLine
+ GBool err; // error on current line
+ int outputBits; // remaining ouput bits
+ int buf; // character buffer
+
+ void addPixels(int a1, int black);
+ void addPixelsNeg(int a1, int black);
+ short getTwoDimCode();
+ short getWhiteCode();
+ short getBlackCode();
+ short lookBits(int n);
+ void eatBits(int n) { if ((inputBits -= n) < 0) inputBits = 0; }
+};
+
+//------------------------------------------------------------------------
+// DCTStream
+//------------------------------------------------------------------------
+
+// DCT component info
+struct DCTCompInfo {
+ int id; // component ID
+ int hSample, vSample; // horiz/vert sampling resolutions
+ int quantTable; // quantization table number
+ int prevDC; // DC coefficient accumulator
+};
+
+struct DCTScanInfo {
+ GBool comp[4]; // comp[i] is set if component i is
+ // included in this scan
+ int numComps; // number of components in the scan
+ int dcHuffTable[4]; // DC Huffman table numbers
+ int acHuffTable[4]; // AC Huffman table numbers
+ int firstCoeff, lastCoeff; // first and last DCT coefficient
+ int ah, al; // successive approximation parameters
+};
+
+// DCT Huffman decoding table
+struct DCTHuffTable {
+ Guchar firstSym[17]; // first symbol for this bit length
+ Gushort firstCode[17]; // first code for this bit length
+ Gushort numCodes[17]; // number of codes of this bit length
+ Guchar sym[256]; // symbols
+};
+
+class DCTStream: public FilterStream {
+public:
+
+ DCTStream(Stream *strA, int colorXformA);
+ virtual ~DCTStream();
+ virtual StreamKind getKind() { return strDCT; }
+ virtual void reset();
+ virtual void close();
+ virtual int getChar();
+ virtual int lookChar();
+ virtual GString *getPSFilter(int psLevel, char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+ Stream *getRawStream() { return str; }
+
+private:
+
+ GBool progressive; // set if in progressive mode
+ GBool interleaved; // set if in interleaved mode
+ int width, height; // image size
+ int mcuWidth, mcuHeight; // size of min coding unit, in data units
+ int bufWidth, bufHeight; // frameBuf size
+ DCTCompInfo compInfo[4]; // info for each component
+ DCTScanInfo scanInfo; // info for the current scan
+ int numComps; // number of components in image
+ int colorXform; // color transform: -1 = unspecified
+ // 0 = none
+ // 1 = YUV/YUVK -> RGB/CMYK
+ GBool gotJFIFMarker; // set if APP0 JFIF marker was present
+ GBool gotAdobeMarker; // set if APP14 Adobe marker was present
+ int restartInterval; // restart interval, in MCUs
+ Gushort quantTables[4][64]; // quantization tables
+ int numQuantTables; // number of quantization tables
+ DCTHuffTable dcHuffTables[4]; // DC Huffman tables
+ DCTHuffTable acHuffTables[4]; // AC Huffman tables
+ int numDCHuffTables; // number of DC Huffman tables
+ int numACHuffTables; // number of AC Huffman tables
+ Guchar *rowBuf[4][32]; // buffer for one MCU (non-progressive mode)
+ int *frameBuf[4]; // buffer for frame (progressive mode)
+ int comp, x, y, dy; // current position within image/MCU
+ int restartCtr; // MCUs left until restart
+ int restartMarker; // next restart marker
+ int eobRun; // number of EOBs left in the current run
+ int inputBuf; // input buffer for variable length codes
+ int inputBits; // number of valid bits in input buffer
+
+ void restart();
+ GBool readMCURow();
+ void readScan();
+ GBool readDataUnit(DCTHuffTable *dcHuffTable,
+ DCTHuffTable *acHuffTable,
+ int *prevDC, int data[64]);
+ GBool readProgressiveDataUnit(DCTHuffTable *dcHuffTable,
+ DCTHuffTable *acHuffTable,
+ int *prevDC, int data[64]);
+ void decodeImage();
+ void transformDataUnit(Gushort *quantTable,
+ int dataIn[64], Guchar dataOut[64]);
+ int readHuffSym(DCTHuffTable *table);
+ int readAmp(int size);
+ int readBit();
+ GBool readHeader();
+ GBool readBaselineSOF();
+ GBool readProgressiveSOF();
+ GBool readScanInfo();
+ GBool readQuantTables();
+ GBool readHuffmanTables();
+ GBool readRestartInterval();
+ GBool readJFIFMarker();
+ GBool readAdobeMarker();
+ GBool readTrailer();
+ int readMarker();
+ int read16();
+};
+
+//------------------------------------------------------------------------
+// FlateStream
+//------------------------------------------------------------------------
+
+#define flateWindow 32768 // buffer size
+#define flateMask (flateWindow-1)
+#define flateMaxHuffman 15 // max Huffman code length
+#define flateMaxCodeLenCodes 19 // max # code length codes
+#define flateMaxLitCodes 288 // max # literal codes
+#define flateMaxDistCodes 30 // max # distance codes
+
+// Huffman code table entry
+struct FlateCode {
+ Gushort len; // code length, in bits
+ Gushort val; // value represented by this code
+};
+
+struct FlateHuffmanTab {
+ FlateCode *codes;
+ int maxLen;
+};
+
+// Decoding info for length and distance code words
+struct FlateDecode {
+ int bits; // # extra bits
+ int first; // first length/distance
+};
+
+class FlateStream: public FilterStream {
+public:
+
+ FlateStream(Stream *strA, int predictor, int columns,
+ int colors, int bits);
+ virtual ~FlateStream();
+ virtual StreamKind getKind() { return strFlate; }
+ virtual void reset();
+ virtual int getChar();
+ virtual int lookChar();
+ virtual int getRawChar();
+ virtual GString *getPSFilter(int psLevel, char *indent);
+ virtual GBool isBinary(GBool last = gTrue);
+
+private:
+
+ StreamPredictor *pred; // predictor
+ Guchar buf[flateWindow]; // output data buffer
+ int index; // current index into output buffer
+ int remain; // number valid bytes in output buffer
+ int codeBuf; // input buffer
+ int codeSize; // number of bits in input buffer
+ int // literal and distance code lengths
+ codeLengths[flateMaxLitCodes + flateMaxDistCodes];
+ FlateHuffmanTab litCodeTab; // literal code table
+ FlateHuffmanTab distCodeTab; // distance code table
+ GBool compressedBlock; // set if reading a compressed block
+ int blockLen; // remaining length of uncompressed block
+ GBool endOfBlock; // set when end of block is reached
+ GBool eof; // set when end of stream is reached
+
+ static int // code length code reordering
+ codeLenCodeMap[flateMaxCodeLenCodes];
+ static FlateDecode // length decoding info
+ lengthDecode[flateMaxLitCodes-257];
+ static FlateDecode // distance decoding info
+ distDecode[flateMaxDistCodes];
+ static FlateHuffmanTab // fixed literal code table
+ fixedLitCodeTab;
+ static FlateHuffmanTab // fixed distance code table
+ fixedDistCodeTab;
+
+ void readSome();
+ GBool startBlock();
+ void loadFixedCodes();
+ GBool readDynamicCodes();
+ void compHuffmanCodes(int *lengths, int n, FlateHuffmanTab *tab);
+ int getHuffmanCodeWord(FlateHuffmanTab *tab);
+ int getCodeWord(int bits);
+};
+
+//------------------------------------------------------------------------
+// EOFStream
+//------------------------------------------------------------------------
+
+class EOFStream: public FilterStream {
+public:
+
+ EOFStream(Stream *strA);
+ virtual ~EOFStream();
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset() {}
+ virtual int getChar() { return EOF; }
+ virtual int lookChar() { return EOF; }
+ virtual GString *getPSFilter(int /*psLevel*/, char * /*indent*/) { return NULL; }
+ virtual GBool isBinary(GBool /*last*/ = gTrue) { return gFalse; }
+};
+
+//------------------------------------------------------------------------
+// FixedLengthEncoder
+//------------------------------------------------------------------------
+
+class FixedLengthEncoder: public FilterStream {
+public:
+
+ FixedLengthEncoder(Stream *strA, int lengthA);
+ ~FixedLengthEncoder();
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ virtual int getChar();
+ virtual int lookChar();
+ virtual GString *getPSFilter(int /*psLevel*/, char * /*indent*/) { return NULL; }
+ virtual GBool isBinary(GBool last = gTrue);
+ virtual GBool isEncoder() { return gTrue; }
+
+private:
+
+ int length;
+ int count;
+};
+
+//------------------------------------------------------------------------
+// ASCIIHexEncoder
+//------------------------------------------------------------------------
+
+class ASCIIHexEncoder: public FilterStream {
+public:
+
+ ASCIIHexEncoder(Stream *strA);
+ virtual ~ASCIIHexEncoder();
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ virtual int getChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
+ virtual int lookChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
+ virtual GString *getPSFilter(int /*psLevel*/, char * /*indent*/) { return NULL; }
+ virtual GBool isBinary(GBool /*last*/ = gTrue) { return gFalse; }
+ virtual GBool isEncoder() { return gTrue; }
+
+private:
+
+ char buf[4];
+ char *bufPtr;
+ char *bufEnd;
+ int lineLen;
+ GBool eof;
+
+ GBool fillBuf();
+};
+
+//------------------------------------------------------------------------
+// ASCII85Encoder
+//------------------------------------------------------------------------
+
+class ASCII85Encoder: public FilterStream {
+public:
+
+ ASCII85Encoder(Stream *strA);
+ virtual ~ASCII85Encoder();
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ virtual int getChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
+ virtual int lookChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
+ virtual GString *getPSFilter(int /*psLevel*/, char * /*indent*/) { return NULL; }
+ virtual GBool isBinary(GBool /*last*/ = gTrue) { return gFalse; }
+ virtual GBool isEncoder() { return gTrue; }
+
+private:
+
+ char buf[8];
+ char *bufPtr;
+ char *bufEnd;
+ int lineLen;
+ GBool eof;
+
+ GBool fillBuf();
+};
+
+//------------------------------------------------------------------------
+// RunLengthEncoder
+//------------------------------------------------------------------------
+
+class RunLengthEncoder: public FilterStream {
+public:
+
+ RunLengthEncoder(Stream *strA);
+ virtual ~RunLengthEncoder();
+ virtual StreamKind getKind() { return strWeird; }
+ virtual void reset();
+ virtual int getChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
+ virtual int lookChar()
+ { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
+ virtual GString *getPSFilter(int /*psLevel*/, char * /*indent*/) { return NULL; }
+ virtual GBool isBinary(GBool /*last*/ = gTrue) { return gTrue; }
+ virtual GBool isEncoder() { return gTrue; }
+
+private:
+
+ char buf[131];
+ char *bufPtr;
+ char *bufEnd;
+ char *nextEnd;
+ GBool eof;
+
+ GBool fillBuf();
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/TextOutputDev.cc b/kpdf/xpdf/xpdf/TextOutputDev.cc
new file mode 100644
index 00000000..d2bfaf63
--- /dev/null
+++ b/kpdf/xpdf/xpdf/TextOutputDev.cc
@@ -0,0 +1,4090 @@
+//========================================================================
+//
+// TextOutputDev.cc
+//
+// Copyright 1997-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <math.h>
+#include <ctype.h>
+#ifdef WIN32
+#include <fcntl.h> // for O_BINARY
+#include <io.h> // for setmode
+#endif
+#include "gmem.h"
+#include "GString.h"
+#include "GList.h"
+#include "config.h"
+#include "Error.h"
+#include "GlobalParams.h"
+#include "UnicodeMap.h"
+#include "UnicodeTypeTable.h"
+#include "GfxState.h"
+#include "Link.h"
+#include "TextOutputDev.h"
+
+#ifdef MACOS
+// needed for setting type/creator of MacOS files
+#include "ICSupport.h"
+#endif
+
+//------------------------------------------------------------------------
+// parameters
+//------------------------------------------------------------------------
+
+// Each bucket in a text pool includes baselines within a range of
+// this many points.
+#define textPoolStep 4
+
+// Inter-character space width which will cause addChar to start a new
+// word.
+#define minWordBreakSpace 0.1
+
+// Negative inter-character space width, i.e., overlap, which will
+// cause addChar to start a new word.
+#define minDupBreakOverlap 0.2
+
+// Max distance between baselines of two lines within a block, as a
+// fraction of the font size.
+#define maxLineSpacingDelta 1.5
+
+// Max difference in primary font sizes on two lines in the same
+// block. Delta1 is used when examining new lines above and below the
+// current block; delta2 is used when examining text that overlaps the
+// current block; delta3 is used when examining text to the left and
+// right of the current block.
+#define maxBlockFontSizeDelta1 0.05
+#define maxBlockFontSizeDelta2 0.6
+#define maxBlockFontSizeDelta3 0.2
+
+// Max difference in font sizes inside a word.
+#define maxWordFontSizeDelta 0.05
+
+// Maximum distance between baselines of two words on the same line,
+// e.g., distance between subscript or superscript and the primary
+// baseline, as a fraction of the font size.
+#define maxIntraLineDelta 0.5
+
+// Minimum inter-word spacing, as a fraction of the font size. (Only
+// used for raw ordering.)
+#define minWordSpacing 0.15
+
+// Maximum inter-word spacing, as a fraction of the font size.
+#define maxWordSpacing 1.5
+
+// Maximum horizontal spacing which will allow a word to be pulled
+// into a block.
+#define minColSpacing1 0.3
+
+// Minimum spacing between columns, as a fraction of the font size.
+#define minColSpacing2 1.0
+
+// Maximum vertical spacing between blocks within a flow, as a
+// multiple of the font size.
+#define maxBlockSpacing 2.5
+
+// Minimum spacing between characters within a word, as a fraction of
+// the font size.
+#define minCharSpacing -0.2
+
+// Maximum spacing between characters within a word, as a fraction of
+// the font size, when there is no obvious extra-wide character
+// spacing.
+#define maxCharSpacing 0.03
+
+// When extra-wide character spacing is detected, the inter-character
+// space threshold is set to the minimum inter-character space
+// multiplied by this constant.
+#define maxWideCharSpacingMul 1.3
+
+// Upper limit on spacing between characters in a word.
+#define maxWideCharSpacing 0.4
+
+// Max difference in primary,secondary coordinates (as a fraction of
+// the font size) allowed for duplicated text (fake boldface, drop
+// shadows) which is to be discarded.
+#define dupMaxPriDelta 0.1
+#define dupMaxSecDelta 0.2
+
+// Max width of underlines (in points).
+#define maxUnderlineWidth 3
+
+// Min distance between baseline and underline (in points).
+//~ this should be font-size-dependent
+#define minUnderlineGap -2
+
+// Max distance between baseline and underline (in points).
+//~ this should be font-size-dependent
+#define maxUnderlineGap 4
+
+// Max horizontal distance between edge of word and start of underline
+// (in points).
+//~ this should be font-size-dependent
+#define underlineSlack 1
+
+// Max distance between edge of text and edge of link border
+#define hyperlinkSlack 2
+
+//------------------------------------------------------------------------
+// TextUnderline
+//------------------------------------------------------------------------
+
+class TextUnderline {
+public:
+
+ TextUnderline(double x0A, double y0A, double x1A, double y1A)
+ { x0 = x0A; y0 = y0A; x1 = x1A; y1 = y1A; horiz = y0 == y1; }
+ ~TextUnderline() {}
+
+ double x0, y0, x1, y1;
+ GBool horiz;
+};
+
+//------------------------------------------------------------------------
+// TextLink
+//------------------------------------------------------------------------
+
+class TextLink {
+public:
+
+ TextLink(int xMinA, int yMinA, int xMaxA, int yMaxA, Link *linkA)
+ { xMin = xMinA; yMin = yMinA; xMax = xMaxA; yMax = yMaxA; link = linkA; }
+ ~TextLink() {}
+
+ int xMin, yMin, xMax, yMax;
+ Link *link;
+};
+
+//------------------------------------------------------------------------
+// TextFontInfo
+//------------------------------------------------------------------------
+
+TextFontInfo::TextFontInfo(GfxState *state) {
+ gfxFont = state->getFont();
+#if TEXTOUT_WORD_LIST
+ fontName = (gfxFont && gfxFont->getOrigName())
+ ? gfxFont->getOrigName()->copy()
+ : (GString *)NULL;
+ flags = gfxFont ? gfxFont->getFlags() : 0;
+#endif
+}
+
+TextFontInfo::~TextFontInfo() {
+#if TEXTOUT_WORD_LIST
+ if (fontName) {
+ delete fontName;
+ }
+#endif
+}
+
+GBool TextFontInfo::matches(GfxState *state) {
+ return state->getFont() == gfxFont;
+}
+
+//------------------------------------------------------------------------
+// TextWord
+//------------------------------------------------------------------------
+
+TextWord::TextWord(GfxState *state, int rotA, double x0, double y0,
+ int charPosA, TextFontInfo *fontA, double fontSizeA) {
+ GfxFont *gfxFont;
+ double x, y, ascent, descent;
+
+ rot = rotA;
+ charPos = charPosA;
+ charLen = 0;
+ font = fontA;
+ fontSize = fontSizeA;
+ state->transform(x0, y0, &x, &y);
+ if ((gfxFont = font->gfxFont)) {
+ ascent = gfxFont->getAscent() * fontSize;
+ descent = gfxFont->getDescent() * fontSize;
+ } else {
+ // this means that the PDF file draws text without a current font,
+ // which should never happen
+ ascent = 0.95 * fontSize;
+ descent = -0.35 * fontSize;
+ }
+ switch (rot) {
+ case 0:
+ yMin = y - ascent;
+ yMax = y - descent;
+ if (yMin == yMax) {
+ // this is a sanity check for a case that shouldn't happen -- but
+ // if it does happen, we want to avoid dividing by zero later
+ yMin = y;
+ yMax = y + 1;
+ }
+ base = y;
+ break;
+ case 1:
+ xMin = x + descent;
+ xMax = x + ascent;
+ if (xMin == xMax) {
+ // this is a sanity check for a case that shouldn't happen -- but
+ // if it does happen, we want to avoid dividing by zero later
+ xMin = x;
+ xMax = x + 1;
+ }
+ base = x;
+ break;
+ case 2:
+ yMin = y + descent;
+ yMax = y + ascent;
+ if (yMin == yMax) {
+ // this is a sanity check for a case that shouldn't happen -- but
+ // if it does happen, we want to avoid dividing by zero later
+ yMin = y;
+ yMax = y + 1;
+ }
+ base = y;
+ break;
+ case 3:
+ xMin = x - ascent;
+ xMax = x - descent;
+ if (xMin == xMax) {
+ // this is a sanity check for a case that shouldn't happen -- but
+ // if it does happen, we want to avoid dividing by zero later
+ xMin = x;
+ xMax = x + 1;
+ }
+ base = x;
+ break;
+ }
+ text = NULL;
+ edge = NULL;
+ len = size = 0;
+ spaceAfter = gFalse;
+ next = NULL;
+
+#if TEXTOUT_WORD_LIST
+ GfxRGB rgb;
+
+ if ((state->getRender() & 3) == 1) {
+ state->getStrokeRGB(&rgb);
+ } else {
+ state->getFillRGB(&rgb);
+ }
+ colorR = colToDbl(rgb.r);
+ colorG = colToDbl(rgb.g);
+ colorB = colToDbl(rgb.b);
+#endif
+
+ underlined = gFalse;
+ link = NULL;
+}
+
+TextWord::~TextWord() {
+ gfree(text);
+ gfree(edge);
+}
+
+void TextWord::addChar(GfxState * /*state*/, double x, double y,
+ double dx, double dy, Unicode u) {
+ if (len == size) {
+ size += 16;
+ text = (Unicode *)greallocn(text, size, sizeof(Unicode));
+ edge = (double *)greallocn(edge, size + 1, sizeof(double));
+ }
+ text[len] = u;
+ switch (rot) {
+ case 0:
+ if (len == 0) {
+ xMin = x;
+ }
+ edge[len] = x;
+ xMax = edge[len+1] = x + dx;
+ break;
+ case 1:
+ if (len == 0) {
+ yMin = y;
+ }
+ edge[len] = y;
+ yMax = edge[len+1] = y + dy;
+ break;
+ case 2:
+ if (len == 0) {
+ xMax = x;
+ }
+ edge[len] = x;
+ xMin = edge[len+1] = x + dx;
+ break;
+ case 3:
+ if (len == 0) {
+ yMax = y;
+ }
+ edge[len] = y;
+ yMin = edge[len+1] = y + dy;
+ break;
+ }
+ ++len;
+}
+
+void TextWord::merge(TextWord *word) {
+ int i;
+
+ if (word->xMin < xMin) {
+ xMin = word->xMin;
+ }
+ if (word->yMin < yMin) {
+ yMin = word->yMin;
+ }
+ if (word->xMax > xMax) {
+ xMax = word->xMax;
+ }
+ if (word->yMax > yMax) {
+ yMax = word->yMax;
+ }
+ if (len + word->len > size) {
+ size = len + word->len;
+ text = (Unicode *)greallocn(text, size, sizeof(Unicode));
+ edge = (double *)greallocn(edge, size + 1, sizeof(double));
+ }
+ for (i = 0; i < word->len; ++i) {
+ text[len + i] = word->text[i];
+ edge[len + i] = word->edge[i];
+ }
+ edge[len + word->len] = word->edge[word->len];
+ len += word->len;
+ charLen += word->charLen;
+}
+
+inline int TextWord::primaryCmp(TextWord *word) {
+ double cmp;
+
+ cmp = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ cmp = xMin - word->xMin;
+ break;
+ case 1:
+ cmp = yMin - word->yMin;
+ break;
+ case 2:
+ cmp = word->xMax - xMax;
+ break;
+ case 3:
+ cmp = word->yMax - yMax;
+ break;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+double TextWord::primaryDelta(TextWord *word) {
+ double delta;
+
+ delta = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ delta = word->xMin - xMax;
+ break;
+ case 1:
+ delta = word->yMin - yMax;
+ break;
+ case 2:
+ delta = xMin - word->xMax;
+ break;
+ case 3:
+ delta = yMin - word->yMax;
+ break;
+ }
+ return delta;
+}
+
+int TextWord::cmpYX(const void *p1, const void *p2) {
+ TextWord *word1 = *(TextWord **)p1;
+ TextWord *word2 = *(TextWord **)p2;
+ double cmp;
+
+ cmp = word1->yMin - word2->yMin;
+ if (cmp == 0) {
+ cmp = word1->xMin - word2->xMin;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+#if TEXTOUT_WORD_LIST
+
+GString *TextWord::getText() {
+ GString *s;
+ UnicodeMap *uMap;
+ char buf[8];
+ int n, i;
+
+ s = new GString();
+ if (!(uMap = globalParams->getTextEncoding())) {
+ return s;
+ }
+ for (i = 0; i < len; ++i) {
+ n = uMap->mapUnicode(text[i], buf, sizeof(buf));
+ s->append(buf, n);
+ }
+ uMap->decRefCnt();
+ return s;
+}
+
+void TextWord::getCharBBox(int charIdx, double *xMinA, double *yMinA,
+ double *xMaxA, double *yMaxA) {
+ if (charIdx < 0 || charIdx >= len) {
+ return;
+ }
+ switch (rot) {
+ case 0:
+ *xMinA = edge[charIdx];
+ *xMaxA = edge[charIdx + 1];
+ *yMinA = yMin;
+ *yMaxA = yMax;
+ break;
+ case 1:
+ *xMinA = xMin;
+ *xMaxA = xMax;
+ *yMinA = edge[charIdx];
+ *yMaxA = edge[charIdx + 1];
+ break;
+ case 2:
+ *xMinA = edge[charIdx + 1];
+ *xMaxA = edge[charIdx];
+ *yMinA = yMin;
+ *yMaxA = yMax;
+ break;
+ case 3:
+ *xMinA = xMin;
+ *xMaxA = xMax;
+ *yMinA = edge[charIdx + 1];
+ *yMaxA = edge[charIdx];
+ break;
+ }
+}
+
+#endif // TEXTOUT_WORD_LIST
+
+//------------------------------------------------------------------------
+// TextPool
+//------------------------------------------------------------------------
+
+TextPool::TextPool() {
+ minBaseIdx = 0;
+ maxBaseIdx = -1;
+ pool = NULL;
+ cursor = NULL;
+ cursorBaseIdx = -1;
+}
+
+TextPool::~TextPool() {
+ int baseIdx;
+ TextWord *word, *word2;
+
+ for (baseIdx = minBaseIdx; baseIdx <= maxBaseIdx; ++baseIdx) {
+ for (word = pool[baseIdx - minBaseIdx]; word; word = word2) {
+ word2 = word->next;
+ delete word;
+ }
+ }
+ gfree(pool);
+}
+
+int TextPool::getBaseIdx(double base) {
+ int baseIdx;
+
+ baseIdx = (int)(base / textPoolStep);
+ if (baseIdx < minBaseIdx) {
+ return minBaseIdx;
+ }
+ if (baseIdx > maxBaseIdx) {
+ return maxBaseIdx;
+ }
+ return baseIdx;
+}
+
+void TextPool::addWord(TextWord *word) {
+ TextWord **newPool;
+ int wordBaseIdx, newMinBaseIdx, newMaxBaseIdx, baseIdx;
+ TextWord *w0, *w1;
+
+ // expand the array if needed
+ wordBaseIdx = (int)(word->base / textPoolStep);
+ if (minBaseIdx > maxBaseIdx) {
+ minBaseIdx = wordBaseIdx - 128;
+ maxBaseIdx = wordBaseIdx + 128;
+ pool = (TextWord **)gmallocn(maxBaseIdx - minBaseIdx + 1,
+ sizeof(TextWord *));
+ for (baseIdx = minBaseIdx; baseIdx <= maxBaseIdx; ++baseIdx) {
+ pool[baseIdx - minBaseIdx] = NULL;
+ }
+ } else if (wordBaseIdx < minBaseIdx) {
+ newMinBaseIdx = wordBaseIdx - 128;
+ newPool = (TextWord **)gmallocn(maxBaseIdx - newMinBaseIdx + 1,
+ sizeof(TextWord *));
+ for (baseIdx = newMinBaseIdx; baseIdx < minBaseIdx; ++baseIdx) {
+ newPool[baseIdx - newMinBaseIdx] = NULL;
+ }
+ memcpy(&newPool[minBaseIdx - newMinBaseIdx], pool,
+ (maxBaseIdx - minBaseIdx + 1) * sizeof(TextWord *));
+ gfree(pool);
+ pool = newPool;
+ minBaseIdx = newMinBaseIdx;
+ } else if (wordBaseIdx > maxBaseIdx) {
+ newMaxBaseIdx = wordBaseIdx + 128;
+ pool = (TextWord **)greallocn(pool, newMaxBaseIdx - minBaseIdx + 1,
+ sizeof(TextWord *));
+ for (baseIdx = maxBaseIdx + 1; baseIdx <= newMaxBaseIdx; ++baseIdx) {
+ pool[baseIdx - minBaseIdx] = NULL;
+ }
+ maxBaseIdx = newMaxBaseIdx;
+ }
+
+ // insert the new word
+ if (cursor && wordBaseIdx == cursorBaseIdx &&
+ word->primaryCmp(cursor) > 0) {
+ w0 = cursor;
+ w1 = cursor->next;
+ } else {
+ w0 = NULL;
+ w1 = pool[wordBaseIdx - minBaseIdx];
+ }
+ for (; w1 && word->primaryCmp(w1) > 0; w0 = w1, w1 = w1->next) ;
+ word->next = w1;
+ if (w0) {
+ w0->next = word;
+ } else {
+ pool[wordBaseIdx - minBaseIdx] = word;
+ }
+ cursor = word;
+ cursorBaseIdx = wordBaseIdx;
+}
+
+//------------------------------------------------------------------------
+// TextLine
+//------------------------------------------------------------------------
+
+TextLine::TextLine(TextBlock *blkA, int rotA, double baseA) {
+ blk = blkA;
+ rot = rotA;
+ xMin = yMin = 0;
+ xMax = yMax = -1;
+ base = baseA;
+ words = lastWord = NULL;
+ text = NULL;
+ edge = NULL;
+ col = NULL;
+ len = 0;
+ convertedLen = 0;
+ hyphenated = gFalse;
+ next = NULL;
+}
+
+TextLine::~TextLine() {
+ TextWord *word;
+
+ while (words) {
+ word = words;
+ words = words->next;
+ delete word;
+ }
+ gfree(text);
+ gfree(edge);
+ gfree(col);
+}
+
+void TextLine::addWord(TextWord *word) {
+ if (lastWord) {
+ lastWord->next = word;
+ } else {
+ words = word;
+ }
+ lastWord = word;
+
+ if (xMin > xMax) {
+ xMin = word->xMin;
+ xMax = word->xMax;
+ yMin = word->yMin;
+ yMax = word->yMax;
+ } else {
+ if (word->xMin < xMin) {
+ xMin = word->xMin;
+ }
+ if (word->xMax > xMax) {
+ xMax = word->xMax;
+ }
+ if (word->yMin < yMin) {
+ yMin = word->yMin;
+ }
+ if (word->yMax > yMax) {
+ yMax = word->yMax;
+ }
+ }
+}
+
+double TextLine::primaryDelta(TextLine *line) {
+ double delta;
+
+ delta = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ delta = line->xMin - xMax;
+ break;
+ case 1:
+ delta = line->yMin - yMax;
+ break;
+ case 2:
+ delta = xMin - line->xMax;
+ break;
+ case 3:
+ delta = yMin - line->yMax;
+ break;
+ }
+ return delta;
+}
+
+int TextLine::primaryCmp(TextLine *line) {
+ double cmp;
+
+ cmp = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ cmp = xMin - line->xMin;
+ break;
+ case 1:
+ cmp = yMin - line->yMin;
+ break;
+ case 2:
+ cmp = line->xMax - xMax;
+ break;
+ case 3:
+ cmp = line->yMax - yMax;
+ break;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+int TextLine::secondaryCmp(TextLine *line) {
+ double cmp;
+
+ cmp = (rot == 0 || rot == 3) ? base - line->base : line->base - base;
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+int TextLine::cmpYX(TextLine *line) {
+ int cmp;
+
+ if ((cmp = secondaryCmp(line))) {
+ return cmp;
+ }
+ return primaryCmp(line);
+}
+
+int TextLine::cmpXY(const void *p1, const void *p2) {
+ TextLine *line1 = *(TextLine **)p1;
+ TextLine *line2 = *(TextLine **)p2;
+ int cmp;
+
+ if ((cmp = line1->primaryCmp(line2))) {
+ return cmp;
+ }
+ return line1->secondaryCmp(line2);
+}
+
+void TextLine::coalesce(UnicodeMap *uMap) {
+ TextWord *word0, *word1;
+ double space, delta, minSpace;
+ GBool isUnicode;
+ char buf[8];
+ int i, j;
+
+ if (words->next) {
+
+ // compute the inter-word space threshold
+ if (words->len > 1 || words->next->len > 1) {
+ minSpace = 0;
+ } else {
+ minSpace = words->primaryDelta(words->next);
+ for (word0 = words->next, word1 = word0->next;
+ word1 && minSpace > 0;
+ word0 = word1, word1 = word0->next) {
+ if (word1->len > 1) {
+ minSpace = 0;
+ }
+ delta = word0->primaryDelta(word1);
+ if (delta < minSpace) {
+ minSpace = delta;
+ }
+ }
+ }
+ if (minSpace <= 0) {
+ space = maxCharSpacing * words->fontSize;
+ } else {
+ space = maxWideCharSpacingMul * minSpace;
+ if (space > maxWideCharSpacing * words->fontSize) {
+ space = maxWideCharSpacing * words->fontSize;
+ }
+ }
+
+ // merge words
+ word0 = words;
+ word1 = words->next;
+ while (word1) {
+ if (word0->primaryDelta(word1) >= space) {
+ word0->spaceAfter = gTrue;
+ word0 = word1;
+ word1 = word1->next;
+ } else if (word0->font == word1->font &&
+ word0->underlined == word1->underlined &&
+ fabs(word0->fontSize - word1->fontSize) <
+ maxWordFontSizeDelta * words->fontSize &&
+ word1->charPos == word0->charPos + word0->charLen) {
+ word0->merge(word1);
+ word0->next = word1->next;
+ delete word1;
+ word1 = word0->next;
+ } else {
+ word0 = word1;
+ word1 = word1->next;
+ }
+ }
+ }
+
+ // build the line text
+ isUnicode = uMap ? uMap->isUnicode() : gFalse;
+ len = 0;
+ for (word1 = words; word1; word1 = word1->next) {
+ len += word1->len;
+ if (word1->spaceAfter) {
+ ++len;
+ }
+ }
+ text = (Unicode *)gmallocn(len, sizeof(Unicode));
+ edge = (double *)gmallocn(len + 1, sizeof(double));
+ i = 0;
+ for (word1 = words; word1; word1 = word1->next) {
+ for (j = 0; j < word1->len; ++j) {
+ text[i] = word1->text[j];
+ edge[i] = word1->edge[j];
+ ++i;
+ }
+ edge[i] = word1->edge[word1->len];
+ if (word1->spaceAfter) {
+ text[i] = (Unicode)0x0020;
+ ++i;
+ }
+ }
+
+ // compute convertedLen and set up the col array
+ col = (int *)gmallocn(len + 1, sizeof(int));
+ convertedLen = 0;
+ for (i = 0; i < len; ++i) {
+ col[i] = convertedLen;
+ if (isUnicode) {
+ ++convertedLen;
+ } else if (uMap) {
+ convertedLen += uMap->mapUnicode(text[i], buf, sizeof(buf));
+ }
+ }
+ col[len] = convertedLen;
+
+ // check for hyphen at end of line
+ //~ need to check for other chars used as hyphens
+ hyphenated = text[len - 1] == (Unicode)'-';
+}
+
+//------------------------------------------------------------------------
+// TextLineFrag
+//------------------------------------------------------------------------
+
+class TextLineFrag {
+public:
+
+ TextLine *line; // the line object
+ int start, len; // offset and length of this fragment
+ // (in Unicode chars)
+ double xMin, xMax; // bounding box coordinates
+ double yMin, yMax;
+ double base; // baseline virtual coordinate
+ int col; // first column
+
+ void init(TextLine *lineA, int startA, int lenA);
+ void computeCoords(GBool oneRot);
+
+ static int cmpYXPrimaryRot(const void *p1, const void *p2);
+ static int cmpYXLineRot(const void *p1, const void *p2);
+ static int cmpXYLineRot(const void *p1, const void *p2);
+ static int cmpXYColumnPrimaryRot(const void *p1, const void *p2);
+ static int cmpXYColumnLineRot(const void *p1, const void *p2);
+};
+
+void TextLineFrag::init(TextLine *lineA, int startA, int lenA) {
+ line = lineA;
+ start = startA;
+ len = lenA;
+ col = line->col[start];
+}
+
+void TextLineFrag::computeCoords(GBool oneRot) {
+ TextBlock *blk;
+ double d0, d1, d2, d3, d4;
+
+ if (oneRot) {
+
+ switch (line->rot) {
+ case 0:
+ xMin = line->edge[start];
+ xMax = line->edge[start + len];
+ yMin = line->yMin;
+ yMax = line->yMax;
+ break;
+ case 1:
+ xMin = line->xMin;
+ xMax = line->xMax;
+ yMin = line->edge[start];
+ yMax = line->edge[start + len];
+ break;
+ case 2:
+ xMin = line->edge[start + len];
+ xMax = line->edge[start];
+ yMin = line->yMin;
+ yMax = line->yMax;
+ break;
+ case 3:
+ xMin = line->xMin;
+ xMax = line->xMax;
+ yMin = line->edge[start + len];
+ yMax = line->edge[start];
+ break;
+ }
+ base = line->base;
+
+ } else {
+
+ if (line->rot == 0 && line->blk->page->primaryRot == 0) {
+
+ xMin = line->edge[start];
+ xMax = line->edge[start + len];
+ yMin = line->yMin;
+ yMax = line->yMax;
+ base = line->base;
+
+ } else {
+
+ blk = line->blk;
+ d0 = line->edge[start];
+ d1 = line->edge[start + len];
+ d2 = d3 = d4 = 0; // make gcc happy
+
+ switch (line->rot) {
+ case 0:
+ d2 = line->yMin;
+ d3 = line->yMax;
+ d4 = line->base;
+ d0 = (d0 - blk->xMin) / (blk->xMax - blk->xMin);
+ d1 = (d1 - blk->xMin) / (blk->xMax - blk->xMin);
+ d2 = (d2 - blk->yMin) / (blk->yMax - blk->yMin);
+ d3 = (d3 - blk->yMin) / (blk->yMax - blk->yMin);
+ d4 = (d4 - blk->yMin) / (blk->yMax - blk->yMin);
+ break;
+ case 1:
+ d2 = line->xMax;
+ d3 = line->xMin;
+ d4 = line->base;
+ d0 = (d0 - blk->yMin) / (blk->yMax - blk->yMin);
+ d1 = (d1 - blk->yMin) / (blk->yMax - blk->yMin);
+ d2 = (blk->xMax - d2) / (blk->xMax - blk->xMin);
+ d3 = (blk->xMax - d3) / (blk->xMax - blk->xMin);
+ d4 = (blk->xMax - d4) / (blk->xMax - blk->xMin);
+ break;
+ case 2:
+ d2 = line->yMax;
+ d3 = line->yMin;
+ d4 = line->base;
+ d0 = (blk->xMax - d0) / (blk->xMax - blk->xMin);
+ d1 = (blk->xMax - d1) / (blk->xMax - blk->xMin);
+ d2 = (blk->yMax - d2) / (blk->yMax - blk->yMin);
+ d3 = (blk->yMax - d3) / (blk->yMax - blk->yMin);
+ d4 = (blk->yMax - d4) / (blk->yMax - blk->yMin);
+ break;
+ case 3:
+ d2 = line->xMin;
+ d3 = line->xMax;
+ d4 = line->base;
+ d0 = (blk->yMax - d0) / (blk->yMax - blk->yMin);
+ d1 = (blk->yMax - d1) / (blk->yMax - blk->yMin);
+ d2 = (d2 - blk->xMin) / (blk->xMax - blk->xMin);
+ d3 = (d3 - blk->xMin) / (blk->xMax - blk->xMin);
+ d4 = (d4 - blk->xMin) / (blk->xMax - blk->xMin);
+ break;
+ }
+
+ switch (line->blk->page->primaryRot) {
+ case 0:
+ xMin = blk->xMin + d0 * (blk->xMax - blk->xMin);
+ xMax = blk->xMin + d1 * (blk->xMax - blk->xMin);
+ yMin = blk->yMin + d2 * (blk->yMax - blk->yMin);
+ yMax = blk->yMin + d3 * (blk->yMax - blk->yMin);
+ base = blk->yMin + base * (blk->yMax - blk->yMin);
+ break;
+ case 1:
+ xMin = blk->xMax - d3 * (blk->xMax - blk->xMin);
+ xMax = blk->xMax - d2 * (blk->xMax - blk->xMin);
+ yMin = blk->yMin + d0 * (blk->yMax - blk->yMin);
+ yMax = blk->yMin + d1 * (blk->yMax - blk->yMin);
+ base = blk->xMax - d4 * (blk->xMax - blk->xMin);
+ break;
+ case 2:
+ xMin = blk->xMax - d1 * (blk->xMax - blk->xMin);
+ xMax = blk->xMax - d0 * (blk->xMax - blk->xMin);
+ yMin = blk->yMax - d3 * (blk->yMax - blk->yMin);
+ yMax = blk->yMax - d2 * (blk->yMax - blk->yMin);
+ base = blk->yMax - d4 * (blk->yMax - blk->yMin);
+ break;
+ case 3:
+ xMin = blk->xMin + d2 * (blk->xMax - blk->xMin);
+ xMax = blk->xMin + d3 * (blk->xMax - blk->xMin);
+ yMin = blk->yMax - d1 * (blk->yMax - blk->yMin);
+ yMax = blk->yMax - d0 * (blk->yMax - blk->yMin);
+ base = blk->xMin + d4 * (blk->xMax - blk->xMin);
+ break;
+ }
+
+ }
+ }
+}
+
+int TextLineFrag::cmpYXPrimaryRot(const void *p1, const void *p2) {
+ TextLineFrag *frag1 = (TextLineFrag *)p1;
+ TextLineFrag *frag2 = (TextLineFrag *)p2;
+ double cmp;
+
+ cmp = 0; // make gcc happy
+ switch (frag1->line->blk->page->primaryRot) {
+ case 0:
+ if (fabs(cmp = frag1->yMin - frag2->yMin) < 0.01) {
+ cmp = frag1->xMin - frag2->xMin;
+ }
+ break;
+ case 1:
+ if (fabs(cmp = frag2->xMax - frag1->xMax) < 0.01) {
+ cmp = frag1->yMin - frag2->yMin;
+ }
+ break;
+ case 2:
+ if (fabs(cmp = frag2->yMin - frag1->yMin) < 0.01) {
+ cmp = frag2->xMax - frag1->xMax;
+ }
+ break;
+ case 3:
+ if (fabs(cmp = frag1->xMax - frag2->xMax) < 0.01) {
+ cmp = frag2->yMax - frag1->yMax;
+ }
+ break;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+int TextLineFrag::cmpYXLineRot(const void *p1, const void *p2) {
+ TextLineFrag *frag1 = (TextLineFrag *)p1;
+ TextLineFrag *frag2 = (TextLineFrag *)p2;
+ double cmp;
+
+ cmp = 0; // make gcc happy
+ switch (frag1->line->rot) {
+ case 0:
+ if ((cmp = frag1->yMin - frag2->yMin) == 0) {
+ cmp = frag1->xMin - frag2->xMin;
+ }
+ break;
+ case 1:
+ if ((cmp = frag2->xMax - frag1->xMax) == 0) {
+ cmp = frag1->yMin - frag2->yMin;
+ }
+ break;
+ case 2:
+ if ((cmp = frag2->yMin - frag1->yMin) == 0) {
+ cmp = frag2->xMax - frag1->xMax;
+ }
+ break;
+ case 3:
+ if ((cmp = frag1->xMax - frag2->xMax) == 0) {
+ cmp = frag2->yMax - frag1->yMax;
+ }
+ break;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+int TextLineFrag::cmpXYLineRot(const void *p1, const void *p2) {
+ TextLineFrag *frag1 = (TextLineFrag *)p1;
+ TextLineFrag *frag2 = (TextLineFrag *)p2;
+ double cmp;
+
+ cmp = 0; // make gcc happy
+ switch (frag1->line->rot) {
+ case 0:
+ if ((cmp = frag1->xMin - frag2->xMin) == 0) {
+ cmp = frag1->yMin - frag2->yMin;
+ }
+ break;
+ case 1:
+ if ((cmp = frag1->yMin - frag2->yMin) == 0) {
+ cmp = frag2->xMax - frag1->xMax;
+ }
+ break;
+ case 2:
+ if ((cmp = frag2->xMax - frag1->xMax) == 0) {
+ cmp = frag2->yMin - frag1->yMin;
+ }
+ break;
+ case 3:
+ if ((cmp = frag2->yMax - frag1->yMax) == 0) {
+ cmp = frag1->xMax - frag2->xMax;
+ }
+ break;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+int TextLineFrag::cmpXYColumnPrimaryRot(const void *p1, const void *p2) {
+ TextLineFrag *frag1 = (TextLineFrag *)p1;
+ TextLineFrag *frag2 = (TextLineFrag *)p2;
+ double cmp;
+
+ // if columns overlap, compare y values
+ if (frag1->col < frag2->col + (frag2->line->col[frag2->start + frag2->len] -
+ frag2->line->col[frag2->start]) &&
+ frag2->col < frag1->col + (frag1->line->col[frag1->start + frag1->len] -
+ frag1->line->col[frag1->start])) {
+ cmp = 0; // make gcc happy
+ switch (frag1->line->blk->page->primaryRot) {
+ case 0: cmp = frag1->yMin - frag2->yMin; break;
+ case 1: cmp = frag2->xMax - frag1->xMax; break;
+ case 2: cmp = frag2->yMin - frag1->yMin; break;
+ case 3: cmp = frag1->xMax - frag2->xMax; break;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+ }
+
+ // otherwise, compare starting column
+ return frag1->col - frag2->col;
+}
+
+int TextLineFrag::cmpXYColumnLineRot(const void *p1, const void *p2) {
+ TextLineFrag *frag1 = (TextLineFrag *)p1;
+ TextLineFrag *frag2 = (TextLineFrag *)p2;
+ double cmp;
+
+ // if columns overlap, compare y values
+ if (frag1->col < frag2->col + (frag2->line->col[frag2->start + frag2->len] -
+ frag2->line->col[frag2->start]) &&
+ frag2->col < frag1->col + (frag1->line->col[frag1->start + frag1->len] -
+ frag1->line->col[frag1->start])) {
+ cmp = 0; // make gcc happy
+ switch (frag1->line->rot) {
+ case 0: cmp = frag1->yMin - frag2->yMin; break;
+ case 1: cmp = frag2->xMax - frag1->xMax; break;
+ case 2: cmp = frag2->yMin - frag1->yMin; break;
+ case 3: cmp = frag1->xMax - frag2->xMax; break;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+ }
+
+ // otherwise, compare starting column
+ return frag1->col - frag2->col;
+}
+
+//------------------------------------------------------------------------
+// TextBlock
+//------------------------------------------------------------------------
+
+TextBlock::TextBlock(TextPage *pageA, int rotA) {
+ page = pageA;
+ rot = rotA;
+ xMin = yMin = 0;
+ xMax = yMax = -1;
+ priMin = 0;
+ priMax = page->pageWidth;
+ pool = new TextPool();
+ lines = NULL;
+ curLine = NULL;
+ next = NULL;
+ stackNext = NULL;
+}
+
+TextBlock::~TextBlock() {
+ TextLine *line;
+
+ delete pool;
+ while (lines) {
+ line = lines;
+ lines = lines->next;
+ delete line;
+ }
+}
+
+void TextBlock::addWord(TextWord *word) {
+ pool->addWord(word);
+ if (xMin > xMax) {
+ xMin = word->xMin;
+ xMax = word->xMax;
+ yMin = word->yMin;
+ yMax = word->yMax;
+ } else {
+ if (word->xMin < xMin) {
+ xMin = word->xMin;
+ }
+ if (word->xMax > xMax) {
+ xMax = word->xMax;
+ }
+ if (word->yMin < yMin) {
+ yMin = word->yMin;
+ }
+ if (word->yMax > yMax) {
+ yMax = word->yMax;
+ }
+ }
+}
+
+void TextBlock::coalesce(UnicodeMap *uMap) {
+ TextWord *word0, *word1, *word2, *bestWord0, *bestWord1, *lastWord;
+ TextLine *line, *line0, *line1;
+ int poolMinBaseIdx, startBaseIdx, minBaseIdx, maxBaseIdx;
+ int baseIdx, bestWordBaseIdx, idx0, idx1;
+ double minBase, maxBase;
+ double fontSize, delta, priDelta, secDelta;
+ TextLine **lineArray;
+ GBool found;
+ int col1, col2;
+ int i, j, k;
+
+ // discard duplicated text (fake boldface, drop shadows)
+ for (idx0 = pool->minBaseIdx; idx0 <= pool->maxBaseIdx; ++idx0) {
+ word0 = pool->getPool(idx0);
+ while (word0) {
+ priDelta = dupMaxPriDelta * word0->fontSize;
+ secDelta = dupMaxSecDelta * word0->fontSize;
+ if (rot == 0 || rot == 3) {
+ maxBaseIdx = pool->getBaseIdx(word0->base + secDelta);
+ } else {
+ maxBaseIdx = pool->getBaseIdx(word0->base - secDelta);
+ }
+ found = gFalse;
+ word1 = word2 = NULL; // make gcc happy
+ for (idx1 = idx0; idx1 <= maxBaseIdx; ++idx1) {
+ if (idx1 == idx0) {
+ word1 = word0;
+ word2 = word0->next;
+ } else {
+ word1 = NULL;
+ word2 = pool->getPool(idx1);
+ }
+ for (; word2; word1 = word2, word2 = word2->next) {
+ if (word2->len == word0->len &&
+ !memcmp(word2->text, word0->text,
+ word0->len * sizeof(Unicode))) {
+ switch (rot) {
+ case 0:
+ case 2:
+ found = fabs(word0->xMin - word2->xMin) < priDelta &&
+ fabs(word0->xMax - word2->xMax) < priDelta &&
+ fabs(word0->yMin - word2->yMin) < secDelta &&
+ fabs(word0->yMax - word2->yMax) < secDelta;
+ break;
+ case 1:
+ case 3:
+ found = fabs(word0->xMin - word2->xMin) < secDelta &&
+ fabs(word0->xMax - word2->xMax) < secDelta &&
+ fabs(word0->yMin - word2->yMin) < priDelta &&
+ fabs(word0->yMax - word2->yMax) < priDelta;
+ break;
+ }
+ }
+ if (found) {
+ break;
+ }
+ }
+ if (found) {
+ break;
+ }
+ }
+ if (found) {
+ if (word1) {
+ word1->next = word2->next;
+ } else {
+ pool->setPool(idx1, word2->next);
+ }
+ delete word2;
+ } else {
+ word0 = word0->next;
+ }
+ }
+ }
+
+ // build the lines
+ curLine = NULL;
+ poolMinBaseIdx = pool->minBaseIdx;
+ charCount = 0;
+ nLines = 0;
+ while (1) {
+
+ // find the first non-empty line in the pool
+ for (;
+ poolMinBaseIdx <= pool->maxBaseIdx && !pool->getPool(poolMinBaseIdx);
+ ++poolMinBaseIdx) ;
+ if (poolMinBaseIdx > pool->maxBaseIdx) {
+ break;
+ }
+
+ // look for the left-most word in the first four lines of the
+ // pool -- this avoids starting with a superscript word
+ startBaseIdx = poolMinBaseIdx;
+ for (baseIdx = poolMinBaseIdx + 1;
+ baseIdx < poolMinBaseIdx + 4 && baseIdx <= pool->maxBaseIdx;
+ ++baseIdx) {
+ if (!pool->getPool(baseIdx)) {
+ continue;
+ }
+ if (pool->getPool(baseIdx)->primaryCmp(pool->getPool(startBaseIdx))
+ < 0) {
+ startBaseIdx = baseIdx;
+ }
+ }
+
+ // create a new line
+ word0 = pool->getPool(startBaseIdx);
+ pool->setPool(startBaseIdx, word0->next);
+ word0->next = NULL;
+ line = new TextLine(this, word0->rot, word0->base);
+ line->addWord(word0);
+ lastWord = word0;
+
+ // compute the search range
+ fontSize = word0->fontSize;
+ minBase = word0->base - maxIntraLineDelta * fontSize;
+ maxBase = word0->base + maxIntraLineDelta * fontSize;
+ minBaseIdx = pool->getBaseIdx(minBase);
+ maxBaseIdx = pool->getBaseIdx(maxBase);
+
+ // find the rest of the words in this line
+ while (1) {
+
+ // find the left-most word whose baseline is in the range for
+ // this line
+ bestWordBaseIdx = 0;
+ bestWord0 = bestWord1 = NULL;
+ for (baseIdx = minBaseIdx; baseIdx <= maxBaseIdx; ++baseIdx) {
+ for (word0 = NULL, word1 = pool->getPool(baseIdx);
+ word1;
+ word0 = word1, word1 = word1->next) {
+ if (word1->base >= minBase &&
+ word1->base <= maxBase &&
+ (delta = lastWord->primaryDelta(word1)) >=
+ minCharSpacing * fontSize) {
+ if (delta < maxWordSpacing * fontSize &&
+ (!bestWord1 || word1->primaryCmp(bestWord1) < 0)) {
+ bestWordBaseIdx = baseIdx;
+ bestWord0 = word0;
+ bestWord1 = word1;
+ }
+ break;
+ }
+ }
+ }
+ if (!bestWord1) {
+ break;
+ }
+
+ // remove it from the pool, and add it to the line
+ if (bestWord0) {
+ bestWord0->next = bestWord1->next;
+ } else {
+ pool->setPool(bestWordBaseIdx, bestWord1->next);
+ }
+ bestWord1->next = NULL;
+ line->addWord(bestWord1);
+ lastWord = bestWord1;
+ }
+
+ // add the line
+ if (curLine && line->cmpYX(curLine) > 0) {
+ line0 = curLine;
+ line1 = curLine->next;
+ } else {
+ line0 = NULL;
+ line1 = lines;
+ }
+ for (;
+ line1 && line->cmpYX(line1) > 0;
+ line0 = line1, line1 = line1->next) ;
+ if (line0) {
+ line0->next = line;
+ } else {
+ lines = line;
+ }
+ line->next = line1;
+ curLine = line;
+ line->coalesce(uMap);
+ charCount += line->len;
+ ++nLines;
+ }
+
+ // sort lines into xy order for column assignment
+ lineArray = (TextLine **)gmallocn(nLines, sizeof(TextLine *));
+ for (line = lines, i = 0; line; line = line->next, ++i) {
+ lineArray[i] = line;
+ }
+ qsort(lineArray, nLines, sizeof(TextLine *), &TextLine::cmpXY);
+
+ // column assignment
+ nColumns = 0;
+ for (i = 0; i < nLines; ++i) {
+ line0 = lineArray[i];
+ col1 = 0;
+ for (j = 0; j < i; ++j) {
+ line1 = lineArray[j];
+ if (line1->primaryDelta(line0) >= 0) {
+ col2 = line1->col[line1->len] + 1;
+ } else {
+ k = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ for (k = 0;
+ k < line1->len &&
+ line0->xMin >= 0.5 * (line1->edge[k] + line1->edge[k+1]);
+ ++k) ;
+ break;
+ case 1:
+ for (k = 0;
+ k < line1->len &&
+ line0->yMin >= 0.5 * (line1->edge[k] + line1->edge[k+1]);
+ ++k) ;
+ break;
+ case 2:
+ for (k = 0;
+ k < line1->len &&
+ line0->xMax <= 0.5 * (line1->edge[k] + line1->edge[k+1]);
+ ++k) ;
+ break;
+ case 3:
+ for (k = 0;
+ k < line1->len &&
+ line0->yMax <= 0.5 * (line1->edge[k] + line1->edge[k+1]);
+ ++k) ;
+ break;
+ }
+ col2 = line1->col[k];
+ }
+ if (col2 > col1) {
+ col1 = col2;
+ }
+ }
+ for (k = 0; k <= line0->len; ++k) {
+ line0->col[k] += col1;
+ }
+ if (line0->col[line0->len] > nColumns) {
+ nColumns = line0->col[line0->len];
+ }
+ }
+ gfree(lineArray);
+}
+
+void TextBlock::updatePriMinMax(TextBlock *blk) {
+ double newPriMin, newPriMax;
+ GBool gotPriMin, gotPriMax;
+
+ gotPriMin = gotPriMax = gFalse;
+ newPriMin = newPriMax = 0; // make gcc happy
+ switch (page->primaryRot) {
+ case 0:
+ case 2:
+ if (blk->yMin < yMax && blk->yMax > yMin) {
+ if (blk->xMin < xMin) {
+ newPriMin = blk->xMax;
+ gotPriMin = gTrue;
+ }
+ if (blk->xMax > xMax) {
+ newPriMax = blk->xMin;
+ gotPriMax = gTrue;
+ }
+ }
+ break;
+ case 1:
+ case 3:
+ if (blk->xMin < xMax && blk->xMax > xMin) {
+ if (blk->yMin < yMin) {
+ newPriMin = blk->yMax;
+ gotPriMin = gTrue;
+ }
+ if (blk->yMax > yMax) {
+ newPriMax = blk->yMin;
+ gotPriMax = gTrue;
+ }
+ }
+ break;
+ }
+ if (gotPriMin) {
+ if (newPriMin > xMin) {
+ newPriMin = xMin;
+ }
+ if (newPriMin > priMin) {
+ priMin = newPriMin;
+ }
+ }
+ if (gotPriMax) {
+ if (newPriMax < xMax) {
+ newPriMax = xMax;
+ }
+ if (newPriMax < priMax) {
+ priMax = newPriMax;
+ }
+ }
+}
+
+int TextBlock::cmpXYPrimaryRot(const void *p1, const void *p2) {
+ TextBlock *blk1 = *(TextBlock **)p1;
+ TextBlock *blk2 = *(TextBlock **)p2;
+ double cmp;
+
+ cmp = 0; // make gcc happy
+ switch (blk1->page->primaryRot) {
+ case 0:
+ if ((cmp = blk1->xMin - blk2->xMin) == 0) {
+ cmp = blk1->yMin - blk2->yMin;
+ }
+ break;
+ case 1:
+ if ((cmp = blk1->yMin - blk2->yMin) == 0) {
+ cmp = blk2->xMax - blk1->xMax;
+ }
+ break;
+ case 2:
+ if ((cmp = blk2->xMax - blk1->xMax) == 0) {
+ cmp = blk2->yMin - blk1->yMin;
+ }
+ break;
+ case 3:
+ if ((cmp = blk2->yMax - blk1->yMax) == 0) {
+ cmp = blk1->xMax - blk2->xMax;
+ }
+ break;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+int TextBlock::cmpYXPrimaryRot(const void *p1, const void *p2) {
+ TextBlock *blk1 = *(TextBlock **)p1;
+ TextBlock *blk2 = *(TextBlock **)p2;
+ double cmp;
+
+ cmp = 0; // make gcc happy
+ switch (blk1->page->primaryRot) {
+ case 0:
+ if ((cmp = blk1->yMin - blk2->yMin) == 0) {
+ cmp = blk1->xMin - blk2->xMin;
+ }
+ break;
+ case 1:
+ if ((cmp = blk2->xMax - blk1->xMax) == 0) {
+ cmp = blk1->yMin - blk2->yMin;
+ }
+ break;
+ case 2:
+ if ((cmp = blk2->yMin - blk1->yMin) == 0) {
+ cmp = blk2->xMax - blk1->xMax;
+ }
+ break;
+ case 3:
+ if ((cmp = blk1->xMax - blk2->xMax) == 0) {
+ cmp = blk2->yMax - blk1->yMax;
+ }
+ break;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+int TextBlock::primaryCmp(TextBlock *blk) {
+ double cmp;
+
+ cmp = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ cmp = xMin - blk->xMin;
+ break;
+ case 1:
+ cmp = yMin - blk->yMin;
+ break;
+ case 2:
+ cmp = blk->xMax - xMax;
+ break;
+ case 3:
+ cmp = blk->yMax - yMax;
+ break;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+double TextBlock::secondaryDelta(TextBlock *blk) {
+ double delta;
+
+ delta = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ delta = blk->yMin - yMax;
+ break;
+ case 1:
+ delta = xMin - blk->xMax;
+ break;
+ case 2:
+ delta = yMin - blk->yMax;
+ break;
+ case 3:
+ delta = blk->xMin - xMax;
+ break;
+ }
+ return delta;
+}
+
+GBool TextBlock::isBelow(TextBlock *blk) {
+ GBool below;
+
+ below = gFalse; // make gcc happy
+ switch (page->primaryRot) {
+ case 0:
+ below = xMin >= blk->priMin && xMax <= blk->priMax &&
+ yMin > blk->yMin;
+ break;
+ case 1:
+ below = yMin >= blk->priMin && yMax <= blk->priMax &&
+ xMax < blk->xMax;
+ break;
+ case 2:
+ below = xMin >= blk->priMin && xMax <= blk->priMax &&
+ yMax < blk->yMax;
+ break;
+ case 3:
+ below = yMin >= blk->priMin && yMax <= blk->priMax &&
+ xMin > blk->xMin;
+ break;
+ }
+
+ return below;
+}
+
+//------------------------------------------------------------------------
+// TextFlow
+//------------------------------------------------------------------------
+
+TextFlow::TextFlow(TextPage *pageA, TextBlock *blk) {
+ page = pageA;
+ xMin = blk->xMin;
+ xMax = blk->xMax;
+ yMin = blk->yMin;
+ yMax = blk->yMax;
+ priMin = blk->priMin;
+ priMax = blk->priMax;
+ blocks = lastBlk = blk;
+ next = NULL;
+}
+
+TextFlow::~TextFlow() {
+ TextBlock *blk;
+
+ while (blocks) {
+ blk = blocks;
+ blocks = blocks->next;
+ delete blk;
+ }
+}
+
+void TextFlow::addBlock(TextBlock *blk) {
+ if (lastBlk) {
+ lastBlk->next = blk;
+ } else {
+ blocks = blk;
+ }
+ lastBlk = blk;
+ if (blk->xMin < xMin) {
+ xMin = blk->xMin;
+ }
+ if (blk->xMax > xMax) {
+ xMax = blk->xMax;
+ }
+ if (blk->yMin < yMin) {
+ yMin = blk->yMin;
+ }
+ if (blk->yMax > yMax) {
+ yMax = blk->yMax;
+ }
+}
+
+GBool TextFlow::blockFits(TextBlock *blk, TextBlock * /*prevBlk*/) {
+ GBool fits;
+
+ // lower blocks must use smaller fonts
+ if (blk->lines->words->fontSize > lastBlk->lines->words->fontSize) {
+ return gFalse;
+ }
+
+ fits = gFalse; // make gcc happy
+ switch (page->primaryRot) {
+ case 0:
+ fits = blk->xMin >= priMin && blk->xMax <= priMax;
+ break;
+ case 1:
+ fits = blk->yMin >= priMin && blk->yMax <= priMax;
+ break;
+ case 2:
+ fits = blk->xMin >= priMin && blk->xMax <= priMax;
+ break;
+ case 3:
+ fits = blk->yMin >= priMin && blk->yMax <= priMax;
+ break;
+ }
+ return fits;
+}
+
+#if TEXTOUT_WORD_LIST
+
+//------------------------------------------------------------------------
+// TextWordList
+//------------------------------------------------------------------------
+
+TextWordList::TextWordList(TextPage *text, GBool physLayout) {
+ TextFlow *flow;
+ TextBlock *blk;
+ TextLine *line;
+ TextWord *word;
+ TextWord **wordArray;
+ int nWords, i;
+
+ words = new GList();
+
+ if (text->rawOrder) {
+ for (word = text->rawWords; word; word = word->next) {
+ words->append(word);
+ }
+
+ } else if (physLayout) {
+ // this is inefficient, but it's also the least useful of these
+ // three cases
+ nWords = 0;
+ for (flow = text->flows; flow; flow = flow->next) {
+ for (blk = flow->blocks; blk; blk = blk->next) {
+ for (line = blk->lines; line; line = line->next) {
+ for (word = line->words; word; word = word->next) {
+ ++nWords;
+ }
+ }
+ }
+ }
+ wordArray = (TextWord **)gmallocn(nWords, sizeof(TextWord *));
+ i = 0;
+ for (flow = text->flows; flow; flow = flow->next) {
+ for (blk = flow->blocks; blk; blk = blk->next) {
+ for (line = blk->lines; line; line = line->next) {
+ for (word = line->words; word; word = word->next) {
+ wordArray[i++] = word;
+ }
+ }
+ }
+ }
+ qsort(wordArray, nWords, sizeof(TextWord *), &TextWord::cmpYX);
+ for (i = 0; i < nWords; ++i) {
+ words->append(wordArray[i]);
+ }
+ gfree(wordArray);
+
+ } else {
+ for (flow = text->flows; flow; flow = flow->next) {
+ for (blk = flow->blocks; blk; blk = blk->next) {
+ for (line = blk->lines; line; line = line->next) {
+ for (word = line->words; word; word = word->next) {
+ words->append(word);
+ }
+ }
+ }
+ }
+ }
+}
+
+TextWordList::~TextWordList() {
+ delete words;
+}
+
+int TextWordList::getLength() {
+ return words->getLength();
+}
+
+TextWord *TextWordList::get(int idx) {
+ if (idx < 0 || idx >= words->getLength()) {
+ return NULL;
+ }
+ return (TextWord *)words->get(idx);
+}
+
+#endif // TEXTOUT_WORD_LIST
+
+//------------------------------------------------------------------------
+// TextPage
+//------------------------------------------------------------------------
+
+TextPage::TextPage(GBool rawOrderA) {
+ int rot;
+
+ rawOrder = rawOrderA;
+ curWord = NULL;
+ charPos = 0;
+ curFont = NULL;
+ curFontSize = 0;
+ nest = 0;
+ nTinyChars = 0;
+ lastCharOverlap = gFalse;
+ if (!rawOrder) {
+ for (rot = 0; rot < 4; ++rot) {
+ pools[rot] = new TextPool();
+ }
+ }
+ flows = NULL;
+ blocks = NULL;
+ rawWords = NULL;
+ rawLastWord = NULL;
+ fonts = new GList();
+ lastFindXMin = lastFindYMin = 0;
+ haveLastFind = gFalse;
+ underlines = new GList();
+ links = new GList();
+}
+
+TextPage::~TextPage() {
+ int rot;
+
+ clear();
+ if (!rawOrder) {
+ for (rot = 0; rot < 4; ++rot) {
+ delete pools[rot];
+ }
+ }
+ delete fonts;
+ deleteGList(underlines, TextUnderline);
+ deleteGList(links, TextLink);
+}
+
+void TextPage::startPage(GfxState *state) {
+ clear();
+ if (state) {
+ pageWidth = state->getPageWidth();
+ pageHeight = state->getPageHeight();
+ } else {
+ pageWidth = pageHeight = 0;
+ }
+}
+
+void TextPage::endPage() {
+ if (curWord) {
+ endWord();
+ }
+}
+
+void TextPage::clear() {
+ int rot;
+ TextFlow *flow;
+ TextWord *word;
+
+ if (curWord) {
+ delete curWord;
+ curWord = NULL;
+ }
+ if (rawOrder) {
+ while (rawWords) {
+ word = rawWords;
+ rawWords = rawWords->next;
+ delete word;
+ }
+ } else {
+ for (rot = 0; rot < 4; ++rot) {
+ delete pools[rot];
+ }
+ while (flows) {
+ flow = flows;
+ flows = flows->next;
+ delete flow;
+ }
+ gfree(blocks);
+ }
+ deleteGList(fonts, TextFontInfo);
+
+ curWord = NULL;
+ charPos = 0;
+ curFont = NULL;
+ curFontSize = 0;
+ nest = 0;
+ nTinyChars = 0;
+ if (!rawOrder) {
+ for (rot = 0; rot < 4; ++rot) {
+ pools[rot] = new TextPool();
+ }
+ }
+ flows = NULL;
+ blocks = NULL;
+ rawWords = NULL;
+ rawLastWord = NULL;
+ fonts = new GList();
+}
+
+void TextPage::updateFont(GfxState *state) {
+ GfxFont *gfxFont;
+ double *fm;
+ char *name;
+ int code, mCode, letterCode, anyCode;
+ double w;
+ int i;
+
+ // get the font info object
+ curFont = NULL;
+ for (i = 0; i < fonts->getLength(); ++i) {
+ curFont = (TextFontInfo *)fonts->get(i);
+ if (curFont->matches(state)) {
+ break;
+ }
+ curFont = NULL;
+ }
+ if (!curFont) {
+ curFont = new TextFontInfo(state);
+ fonts->append(curFont);
+ }
+
+ // adjust the font size
+ gfxFont = state->getFont();
+ curFontSize = state->getTransformedFontSize();
+ if (gfxFont && gfxFont->getType() == fontType3) {
+ // This is a hack which makes it possible to deal with some Type 3
+ // fonts. The problem is that it's impossible to know what the
+ // base coordinate system used in the font is without actually
+ // rendering the font. This code tries to guess by looking at the
+ // width of the character 'm' (which breaks if the font is a
+ // subset that doesn't contain 'm').
+ mCode = letterCode = anyCode = -1;
+ for (code = 0; code < 256; ++code) {
+ name = ((Gfx8BitFont *)gfxFont)->getCharName(code);
+ if (name && name[0] == 'm' && name[1] == '\0') {
+ mCode = code;
+ }
+ if (letterCode < 0 && name && name[1] == '\0' &&
+ ((name[0] >= 'A' && name[0] <= 'Z') ||
+ (name[0] >= 'a' && name[0] <= 'z'))) {
+ letterCode = code;
+ }
+ if (anyCode < 0 && name &&
+ ((Gfx8BitFont *)gfxFont)->getWidth(code) > 0) {
+ anyCode = code;
+ }
+ }
+ if (mCode >= 0 &&
+ (w = ((Gfx8BitFont *)gfxFont)->getWidth(mCode)) > 0) {
+ // 0.6 is a generic average 'm' width -- yes, this is a hack
+ curFontSize *= w / 0.6;
+ } else if (letterCode >= 0 &&
+ (w = ((Gfx8BitFont *)gfxFont)->getWidth(letterCode)) > 0) {
+ // even more of a hack: 0.5 is a generic letter width
+ curFontSize *= w / 0.5;
+ } else if (anyCode >= 0 &&
+ (w = ((Gfx8BitFont *)gfxFont)->getWidth(anyCode)) > 0) {
+ // better than nothing: 0.5 is a generic character width
+ curFontSize *= w / 0.5;
+ }
+ fm = gfxFont->getFontMatrix();
+ if (fm[0] != 0) {
+ curFontSize *= fabs(fm[3] / fm[0]);
+ }
+ }
+}
+
+void TextPage::beginWord(GfxState *state, double x0, double y0) {
+ double *fontm;
+ double m[4], m2[4];
+ int rot;
+
+ // This check is needed because Type 3 characters can contain
+ // text-drawing operations (when TextPage is being used via
+ // {X,Win}SplashOutputDev rather than TextOutputDev).
+ if (curWord) {
+ ++nest;
+ return;
+ }
+
+ // compute the rotation
+ state->getFontTransMat(&m[0], &m[1], &m[2], &m[3]);
+ if (state->getFont()->getType() == fontType3) {
+ fontm = state->getFont()->getFontMatrix();
+ m2[0] = fontm[0] * m[0] + fontm[1] * m[2];
+ m2[1] = fontm[0] * m[1] + fontm[1] * m[3];
+ m2[2] = fontm[2] * m[0] + fontm[3] * m[2];
+ m2[3] = fontm[2] * m[1] + fontm[3] * m[3];
+ m[0] = m2[0];
+ m[1] = m2[1];
+ m[2] = m2[2];
+ m[3] = m2[3];
+ }
+ if (fabs(m[0] * m[3]) > fabs(m[1] * m[2])) {
+ rot = (m[3] < 0) ? 0 : 2;
+ } else {
+ rot = (m[2] > 0) ? 1 : 3;
+ }
+
+ curWord = new TextWord(state, rot, x0, y0, charPos, curFont, curFontSize);
+}
+
+void TextPage::addChar(GfxState *state, double x, double y,
+ double dx, double dy,
+ CharCode c, int nBytes, Unicode *u, int uLen) {
+ double x1, y1, w1, h1, dx2, dy2, base, sp, delta;
+ GBool overlap;
+ int i;
+
+ // subtract char and word spacing from the dx,dy values
+ sp = state->getCharSpace();
+ if (c == (CharCode)0x20) {
+ sp += state->getWordSpace();
+ }
+ state->textTransformDelta(sp * state->getHorizScaling(), 0, &dx2, &dy2);
+ dx -= dx2;
+ dy -= dy2;
+ state->transformDelta(dx, dy, &w1, &h1);
+
+ // throw away chars that aren't inside the page bounds
+ // (and also do a sanity check on the character size)
+ state->transform(x, y, &x1, &y1);
+ if (x1 + w1 < 0 || x1 > pageWidth ||
+ y1 + h1 < 0 || y1 > pageHeight ||
+ w1 > pageWidth || h1 > pageHeight) {
+ charPos += nBytes;
+ return;
+ }
+
+ // check the tiny chars limit
+ if (!globalParams->getTextKeepTinyChars() &&
+ fabs(w1) < 3 && fabs(h1) < 3) {
+ if (++nTinyChars > 50000) {
+ charPos += nBytes;
+ return;
+ }
+ }
+
+ // break words at space character
+ if (uLen == 1 && u[0] == (Unicode)0x20) {
+ if (curWord) {
+ ++curWord->charLen;
+ }
+ charPos += nBytes;
+ endWord();
+ return;
+ }
+
+ // start a new word if:
+ // (1) this character doesn't fall in the right place relative to
+ // the end of the previous word (this places upper and lower
+ // constraints on the position deltas along both the primary
+ // and secondary axes), or
+ // (2) this character overlaps the previous one (duplicated text), or
+ // (3) the previous character was an overlap (we want each duplicated
+ // character to be in a word by itself at this stage),
+ // (4) the font size has changed
+ if (curWord && curWord->len > 0) {
+ base = sp = delta = 0; // make gcc happy
+ switch (curWord->rot) {
+ case 0:
+ base = y1;
+ sp = x1 - curWord->xMax;
+ delta = x1 - curWord->edge[curWord->len - 1];
+ break;
+ case 1:
+ base = x1;
+ sp = y1 - curWord->yMax;
+ delta = y1 - curWord->edge[curWord->len - 1];
+ break;
+ case 2:
+ base = y1;
+ sp = curWord->xMin - x1;
+ delta = curWord->edge[curWord->len - 1] - x1;
+ break;
+ case 3:
+ base = x1;
+ sp = curWord->yMin - y1;
+ delta = curWord->edge[curWord->len - 1] - y1;
+ break;
+ }
+ overlap = fabs(delta) < dupMaxPriDelta * curWord->fontSize &&
+ fabs(base - curWord->base) < dupMaxSecDelta * curWord->fontSize;
+ if (overlap || lastCharOverlap ||
+ sp < -minDupBreakOverlap * curWord->fontSize ||
+ sp > minWordBreakSpace * curWord->fontSize ||
+ fabs(base - curWord->base) > 0.5 ||
+ curFontSize != curWord->fontSize) {
+ endWord();
+ }
+ lastCharOverlap = overlap;
+ } else {
+ lastCharOverlap = gFalse;
+ }
+
+ if (uLen != 0) {
+ // start a new word if needed
+ if (!curWord) {
+ beginWord(state, x, y);
+ }
+
+ // page rotation and/or transform matrices can cause text to be
+ // drawn in reverse order -- in this case, swap the begin/end
+ // coordinates and break text into individual chars
+ if ((curWord->rot == 0 && w1 < 0) ||
+ (curWord->rot == 1 && h1 < 0) ||
+ (curWord->rot == 2 && w1 > 0) ||
+ (curWord->rot == 3 && h1 > 0)) {
+ endWord();
+ beginWord(state, x + dx, y + dy);
+ x1 += w1;
+ y1 += h1;
+ w1 = -w1;
+ h1 = -h1;
+ }
+
+ // add the characters to the current word
+ w1 /= uLen;
+ h1 /= uLen;
+ for (i = 0; i < uLen; ++i) {
+ curWord->addChar(state, x1 + i*w1, y1 + i*h1, w1, h1, u[i]);
+ }
+ }
+ if (curWord) {
+ curWord->charLen += nBytes;
+ }
+ charPos += nBytes;
+}
+
+void TextPage::endWord() {
+ // This check is needed because Type 3 characters can contain
+ // text-drawing operations (when TextPage is being used via
+ // {X,Win}SplashOutputDev rather than TextOutputDev).
+ if (nest > 0) {
+ --nest;
+ return;
+ }
+
+ if (curWord) {
+ addWord(curWord);
+ curWord = NULL;
+ }
+}
+
+void TextPage::addWord(TextWord *word) {
+ // throw away zero-length words -- they don't have valid xMin/xMax
+ // values, and they're useless anyway
+ if (word->len == 0) {
+ delete word;
+ return;
+ }
+
+ if (rawOrder) {
+ if (rawLastWord) {
+ rawLastWord->next = word;
+ } else {
+ rawWords = word;
+ }
+ rawLastWord = word;
+ } else {
+ pools[word->rot]->addWord(word);
+ }
+}
+
+void TextPage::addUnderline(double x0, double y0, double x1, double y1) {
+ underlines->append(new TextUnderline(x0, y0, x1, y1));
+}
+
+void TextPage::addLink(int xMin, int yMin, int xMax, int yMax, Link *link) {
+ links->append(new TextLink(xMin, yMin, xMax, yMax, link));
+}
+
+void TextPage::coalesce(GBool /*physLayout*/, GBool doHTML) {
+ UnicodeMap *uMap;
+ TextPool *pool;
+ TextWord *word0, *word1, *word2;
+ TextLine *line;
+ TextBlock *blkList, *blkStack, *blk, *lastBlk, *blk0, *blk1;
+ TextBlock **blkArray;
+ TextFlow *flow, *lastFlow;
+ TextUnderline *underline;
+ TextLink *link;
+ int rot, poolMinBaseIdx, baseIdx, startBaseIdx, endBaseIdx;
+ double minBase, maxBase, newMinBase, newMaxBase;
+ double fontSize, colSpace1, colSpace2, lineSpace, intraLineSpace, blkSpace;
+ GBool found;
+ int count[4];
+ int lrCount;
+ int firstBlkIdx, nBlocksLeft;
+ int col1, col2;
+ int i, j, n;
+
+ if (rawOrder) {
+ primaryRot = 0;
+ primaryLR = gTrue;
+ return;
+ }
+
+ uMap = globalParams->getTextEncoding();
+ blkList = NULL;
+ lastBlk = NULL;
+ nBlocks = 0;
+ primaryRot = -1;
+
+#if 0 // for debugging
+ printf("*** initial words ***\n");
+ for (rot = 0; rot < 4; ++rot) {
+ pool = pools[rot];
+ for (baseIdx = pool->minBaseIdx; baseIdx <= pool->maxBaseIdx; ++baseIdx) {
+ for (word0 = pool->getPool(baseIdx); word0; word0 = word0->next) {
+ printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f rot=%d link=%p '",
+ word0->xMin, word0->xMax, word0->yMin, word0->yMax,
+ word0->base, word0->fontSize, rot*90, word0->link);
+ for (i = 0; i < word0->len; ++i) {
+ fputc(word0->text[i] & 0xff, stdout);
+ }
+ printf("'\n");
+ }
+ }
+ }
+ printf("\n");
+#endif
+
+#if 0 //~ for debugging
+ for (i = 0; i < underlines->getLength(); ++i) {
+ underline = (TextUnderline *)underlines->get(i);
+ printf("underline: x=%g..%g y=%g..%g horiz=%d\n",
+ underline->x0, underline->x1, underline->y0, underline->y1,
+ underline->horiz);
+ }
+#endif
+
+ if (doHTML) {
+
+ //----- handle underlining
+ for (i = 0; i < underlines->getLength(); ++i) {
+ underline = (TextUnderline *)underlines->get(i);
+ if (underline->horiz) {
+ // rot = 0
+ if (pools[0]->minBaseIdx <= pools[0]->maxBaseIdx) {
+ startBaseIdx = pools[0]->getBaseIdx(underline->y0 + minUnderlineGap);
+ endBaseIdx = pools[0]->getBaseIdx(underline->y0 + maxUnderlineGap);
+ for (j = startBaseIdx; j <= endBaseIdx; ++j) {
+ for (word0 = pools[0]->getPool(j); word0; word0 = word0->next) {
+ //~ need to check the y value against the word baseline
+ if (underline->x0 < word0->xMin + underlineSlack &&
+ word0->xMax - underlineSlack < underline->x1) {
+ word0->underlined = gTrue;
+ }
+ }
+ }
+ }
+
+ // rot = 2
+ if (pools[2]->minBaseIdx <= pools[2]->maxBaseIdx) {
+ startBaseIdx = pools[2]->getBaseIdx(underline->y0 - maxUnderlineGap);
+ endBaseIdx = pools[2]->getBaseIdx(underline->y0 - minUnderlineGap);
+ for (j = startBaseIdx; j <= endBaseIdx; ++j) {
+ for (word0 = pools[2]->getPool(j); word0; word0 = word0->next) {
+ if (underline->x0 < word0->xMin + underlineSlack &&
+ word0->xMax - underlineSlack < underline->x1) {
+ word0->underlined = gTrue;
+ }
+ }
+ }
+ }
+ } else {
+ // rot = 1
+ if (pools[1]->minBaseIdx <= pools[1]->maxBaseIdx) {
+ startBaseIdx = pools[1]->getBaseIdx(underline->x0 - maxUnderlineGap);
+ endBaseIdx = pools[1]->getBaseIdx(underline->x0 - minUnderlineGap);
+ for (j = startBaseIdx; j <= endBaseIdx; ++j) {
+ for (word0 = pools[1]->getPool(j); word0; word0 = word0->next) {
+ if (underline->y0 < word0->yMin + underlineSlack &&
+ word0->yMax - underlineSlack < underline->y1) {
+ word0->underlined = gTrue;
+ }
+ }
+ }
+ }
+
+ // rot = 3
+ if (pools[3]->minBaseIdx <= pools[3]->maxBaseIdx) {
+ startBaseIdx = pools[3]->getBaseIdx(underline->x0 + minUnderlineGap);
+ endBaseIdx = pools[3]->getBaseIdx(underline->x0 + maxUnderlineGap);
+ for (j = startBaseIdx; j <= endBaseIdx; ++j) {
+ for (word0 = pools[3]->getPool(j); word0; word0 = word0->next) {
+ if (underline->y0 < word0->yMin + underlineSlack &&
+ word0->yMax - underlineSlack < underline->y1) {
+ word0->underlined = gTrue;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //----- handle links
+ for (i = 0; i < links->getLength(); ++i) {
+ link = (TextLink *)links->get(i);
+
+ // rot = 0
+ if (pools[0]->minBaseIdx <= pools[0]->maxBaseIdx) {
+ startBaseIdx = pools[0]->getBaseIdx(link->yMin);
+ endBaseIdx = pools[0]->getBaseIdx(link->yMax);
+ for (j = startBaseIdx; j <= endBaseIdx; ++j) {
+ for (word0 = pools[0]->getPool(j); word0; word0 = word0->next) {
+ if (link->xMin < word0->xMin + hyperlinkSlack &&
+ word0->xMax - hyperlinkSlack < link->xMax &&
+ link->yMin < word0->yMin + hyperlinkSlack &&
+ word0->yMax - hyperlinkSlack < link->yMax) {
+ word0->link = link->link;
+ }
+ }
+ }
+ }
+
+ // rot = 2
+ if (pools[2]->minBaseIdx <= pools[2]->maxBaseIdx) {
+ startBaseIdx = pools[2]->getBaseIdx(link->yMin);
+ endBaseIdx = pools[2]->getBaseIdx(link->yMax);
+ for (j = startBaseIdx; j <= endBaseIdx; ++j) {
+ for (word0 = pools[2]->getPool(j); word0; word0 = word0->next) {
+ if (link->xMin < word0->xMin + hyperlinkSlack &&
+ word0->xMax - hyperlinkSlack < link->xMax &&
+ link->yMin < word0->yMin + hyperlinkSlack &&
+ word0->yMax - hyperlinkSlack < link->yMax) {
+ word0->link = link->link;
+ }
+ }
+ }
+ }
+
+ // rot = 1
+ if (pools[1]->minBaseIdx <= pools[1]->maxBaseIdx) {
+ startBaseIdx = pools[1]->getBaseIdx(link->xMin);
+ endBaseIdx = pools[1]->getBaseIdx(link->xMax);
+ for (j = startBaseIdx; j <= endBaseIdx; ++j) {
+ for (word0 = pools[1]->getPool(j); word0; word0 = word0->next) {
+ if (link->yMin < word0->yMin + hyperlinkSlack &&
+ word0->yMax - hyperlinkSlack < link->yMax &&
+ link->xMin < word0->xMin + hyperlinkSlack &&
+ word0->xMax - hyperlinkSlack < link->xMax) {
+ word0->link = link->link;
+ }
+ }
+ }
+ }
+
+ // rot = 3
+ if (pools[3]->minBaseIdx <= pools[3]->maxBaseIdx) {
+ startBaseIdx = pools[3]->getBaseIdx(link->xMin);
+ endBaseIdx = pools[3]->getBaseIdx(link->xMax);
+ for (j = startBaseIdx; j <= endBaseIdx; ++j) {
+ for (word0 = pools[3]->getPool(j); word0; word0 = word0->next) {
+ if (link->yMin < word0->yMin + hyperlinkSlack &&
+ word0->yMax - hyperlinkSlack < link->yMax &&
+ link->xMin < word0->xMin + hyperlinkSlack &&
+ word0->xMax - hyperlinkSlack < link->xMax) {
+ word0->link = link->link;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //----- assemble the blocks
+
+ //~ add an outer loop for writing mode (vertical text)
+
+ // build blocks for each rotation value
+ for (rot = 0; rot < 4; ++rot) {
+ pool = pools[rot];
+ poolMinBaseIdx = pool->minBaseIdx;
+ count[rot] = 0;
+
+ // add blocks until no more words are left
+ while (1) {
+
+ // find the first non-empty line in the pool
+ for (;
+ poolMinBaseIdx <= pool->maxBaseIdx &&
+ !pool->getPool(poolMinBaseIdx);
+ ++poolMinBaseIdx) ;
+ if (poolMinBaseIdx > pool->maxBaseIdx) {
+ break;
+ }
+
+ // look for the left-most word in the first four lines of the
+ // pool -- this avoids starting with a superscript word
+ startBaseIdx = poolMinBaseIdx;
+ for (baseIdx = poolMinBaseIdx + 1;
+ baseIdx < poolMinBaseIdx + 4 && baseIdx <= pool->maxBaseIdx;
+ ++baseIdx) {
+ if (!pool->getPool(baseIdx)) {
+ continue;
+ }
+ if (pool->getPool(baseIdx)->primaryCmp(pool->getPool(startBaseIdx))
+ < 0) {
+ startBaseIdx = baseIdx;
+ }
+ }
+
+ // create a new block
+ word0 = pool->getPool(startBaseIdx);
+ pool->setPool(startBaseIdx, word0->next);
+ word0->next = NULL;
+ blk = new TextBlock(this, rot);
+ blk->addWord(word0);
+
+ fontSize = word0->fontSize;
+ minBase = maxBase = word0->base;
+ colSpace1 = minColSpacing1 * fontSize;
+ colSpace2 = minColSpacing2 * fontSize;
+ lineSpace = maxLineSpacingDelta * fontSize;
+ intraLineSpace = maxIntraLineDelta * fontSize;
+
+ // add words to the block
+ do {
+ found = gFalse;
+
+ // look for words on the line above the current top edge of
+ // the block
+ newMinBase = minBase;
+ for (baseIdx = pool->getBaseIdx(minBase);
+ baseIdx >= pool->getBaseIdx(minBase - lineSpace);
+ --baseIdx) {
+ word0 = NULL;
+ word1 = pool->getPool(baseIdx);
+ while (word1) {
+ if (word1->base < minBase &&
+ word1->base >= minBase - lineSpace &&
+ ((rot == 0 || rot == 2)
+ ? (word1->xMin < blk->xMax && word1->xMax > blk->xMin)
+ : (word1->yMin < blk->yMax && word1->yMax > blk->yMin)) &&
+ fabs(word1->fontSize - fontSize) <
+ maxBlockFontSizeDelta1 * fontSize) {
+ word2 = word1;
+ if (word0) {
+ word0->next = word1->next;
+ } else {
+ pool->setPool(baseIdx, word1->next);
+ }
+ word1 = word1->next;
+ word2->next = NULL;
+ blk->addWord(word2);
+ found = gTrue;
+ newMinBase = word2->base;
+ } else {
+ word0 = word1;
+ word1 = word1->next;
+ }
+ }
+ }
+ minBase = newMinBase;
+
+ // look for words on the line below the current bottom edge of
+ // the block
+ newMaxBase = maxBase;
+ for (baseIdx = pool->getBaseIdx(maxBase);
+ baseIdx <= pool->getBaseIdx(maxBase + lineSpace);
+ ++baseIdx) {
+ word0 = NULL;
+ word1 = pool->getPool(baseIdx);
+ while (word1) {
+ if (word1->base > maxBase &&
+ word1->base <= maxBase + lineSpace &&
+ ((rot == 0 || rot == 2)
+ ? (word1->xMin < blk->xMax && word1->xMax > blk->xMin)
+ : (word1->yMin < blk->yMax && word1->yMax > blk->yMin)) &&
+ fabs(word1->fontSize - fontSize) <
+ maxBlockFontSizeDelta1 * fontSize) {
+ word2 = word1;
+ if (word0) {
+ word0->next = word1->next;
+ } else {
+ pool->setPool(baseIdx, word1->next);
+ }
+ word1 = word1->next;
+ word2->next = NULL;
+ blk->addWord(word2);
+ found = gTrue;
+ newMaxBase = word2->base;
+ } else {
+ word0 = word1;
+ word1 = word1->next;
+ }
+ }
+ }
+ maxBase = newMaxBase;
+
+ // look for words that are on lines already in the block, and
+ // that overlap the block horizontally
+ for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace);
+ baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace);
+ ++baseIdx) {
+ word0 = NULL;
+ word1 = pool->getPool(baseIdx);
+ while (word1) {
+ if (word1->base >= minBase - intraLineSpace &&
+ word1->base <= maxBase + intraLineSpace &&
+ ((rot == 0 || rot == 2)
+ ? (word1->xMin < blk->xMax + colSpace1 &&
+ word1->xMax > blk->xMin - colSpace1)
+ : (word1->yMin < blk->yMax + colSpace1 &&
+ word1->yMax > blk->yMin - colSpace1)) &&
+ fabs(word1->fontSize - fontSize) <
+ maxBlockFontSizeDelta2 * fontSize) {
+ word2 = word1;
+ if (word0) {
+ word0->next = word1->next;
+ } else {
+ pool->setPool(baseIdx, word1->next);
+ }
+ word1 = word1->next;
+ word2->next = NULL;
+ blk->addWord(word2);
+ found = gTrue;
+ } else {
+ word0 = word1;
+ word1 = word1->next;
+ }
+ }
+ }
+
+ // only check for outlying words (the next two chunks of code)
+ // if we didn't find anything else
+ if (found) {
+ continue;
+ }
+
+ // scan down the left side of the block, looking for words
+ // that are near (but not overlapping) the block; if there are
+ // three or fewer, add them to the block
+ n = 0;
+ for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace);
+ baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace);
+ ++baseIdx) {
+ word1 = pool->getPool(baseIdx);
+ while (word1) {
+ if (word1->base >= minBase - intraLineSpace &&
+ word1->base <= maxBase + intraLineSpace &&
+ ((rot == 0 || rot == 2)
+ ? (word1->xMax <= blk->xMin &&
+ word1->xMax > blk->xMin - colSpace2)
+ : (word1->yMax <= blk->yMin &&
+ word1->yMax > blk->yMin - colSpace2)) &&
+ fabs(word1->fontSize - fontSize) <
+ maxBlockFontSizeDelta3 * fontSize) {
+ ++n;
+ break;
+ }
+ word1 = word1->next;
+ }
+ }
+ if (n > 0 && n <= 3) {
+ for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace);
+ baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace);
+ ++baseIdx) {
+ word0 = NULL;
+ word1 = pool->getPool(baseIdx);
+ while (word1) {
+ if (word1->base >= minBase - intraLineSpace &&
+ word1->base <= maxBase + intraLineSpace &&
+ ((rot == 0 || rot == 2)
+ ? (word1->xMax <= blk->xMin &&
+ word1->xMax > blk->xMin - colSpace2)
+ : (word1->yMax <= blk->yMin &&
+ word1->yMax > blk->yMin - colSpace2)) &&
+ fabs(word1->fontSize - fontSize) <
+ maxBlockFontSizeDelta3 * fontSize) {
+ word2 = word1;
+ if (word0) {
+ word0->next = word1->next;
+ } else {
+ pool->setPool(baseIdx, word1->next);
+ }
+ word1 = word1->next;
+ word2->next = NULL;
+ blk->addWord(word2);
+ if (word2->base < minBase) {
+ minBase = word2->base;
+ } else if (word2->base > maxBase) {
+ maxBase = word2->base;
+ }
+ found = gTrue;
+ break;
+ } else {
+ word0 = word1;
+ word1 = word1->next;
+ }
+ }
+ }
+ }
+
+ // scan down the right side of the block, looking for words
+ // that are near (but not overlapping) the block; if there are
+ // three or fewer, add them to the block
+ n = 0;
+ for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace);
+ baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace);
+ ++baseIdx) {
+ word1 = pool->getPool(baseIdx);
+ while (word1) {
+ if (word1->base >= minBase - intraLineSpace &&
+ word1->base <= maxBase + intraLineSpace &&
+ ((rot == 0 || rot == 2)
+ ? (word1->xMin >= blk->xMax &&
+ word1->xMin < blk->xMax + colSpace2)
+ : (word1->yMin >= blk->yMax &&
+ word1->yMin < blk->yMax + colSpace2)) &&
+ fabs(word1->fontSize - fontSize) <
+ maxBlockFontSizeDelta3 * fontSize) {
+ ++n;
+ break;
+ }
+ word1 = word1->next;
+ }
+ }
+ if (n > 0 && n <= 3) {
+ for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace);
+ baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace);
+ ++baseIdx) {
+ word0 = NULL;
+ word1 = pool->getPool(baseIdx);
+ while (word1) {
+ if (word1->base >= minBase - intraLineSpace &&
+ word1->base <= maxBase + intraLineSpace &&
+ ((rot == 0 || rot == 2)
+ ? (word1->xMin >= blk->xMax &&
+ word1->xMin < blk->xMax + colSpace2)
+ : (word1->yMin >= blk->yMax &&
+ word1->yMin < blk->yMax + colSpace2)) &&
+ fabs(word1->fontSize - fontSize) <
+ maxBlockFontSizeDelta3 * fontSize) {
+ word2 = word1;
+ if (word0) {
+ word0->next = word1->next;
+ } else {
+ pool->setPool(baseIdx, word1->next);
+ }
+ word1 = word1->next;
+ word2->next = NULL;
+ blk->addWord(word2);
+ if (word2->base < minBase) {
+ minBase = word2->base;
+ } else if (word2->base > maxBase) {
+ maxBase = word2->base;
+ }
+ found = gTrue;
+ break;
+ } else {
+ word0 = word1;
+ word1 = word1->next;
+ }
+ }
+ }
+ }
+
+ } while (found);
+
+ //~ need to compute the primary writing mode (horiz/vert) in
+ //~ addition to primary rotation
+
+ // coalesce the block, and add it to the list
+ blk->coalesce(uMap);
+ if (lastBlk) {
+ lastBlk->next = blk;
+ } else {
+ blkList = blk;
+ }
+ lastBlk = blk;
+ count[rot] += blk->charCount;
+ if (primaryRot < 0 || count[rot] > count[primaryRot]) {
+ primaryRot = rot;
+ }
+ ++nBlocks;
+ }
+ }
+
+#if 0 // for debugging
+ printf("*** rotation ***\n");
+ for (rot = 0; rot < 4; ++rot) {
+ printf(" %d: %6d\n", rot, count[rot]);
+ }
+ printf(" primary rot = %d\n", primaryRot);
+ printf("\n");
+#endif
+
+#if 0 // for debugging
+ printf("*** blocks ***\n");
+ for (blk = blkList; blk; blk = blk->next) {
+ printf("block: rot=%d x=%.2f..%.2f y=%.2f..%.2f\n",
+ blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax);
+ for (line = blk->lines; line; line = line->next) {
+ printf(" line: x=%.2f..%.2f y=%.2f..%.2f base=%.2f\n",
+ line->xMin, line->xMax, line->yMin, line->yMax, line->base);
+ for (word0 = line->words; word0; word0 = word0->next) {
+ printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '",
+ word0->xMin, word0->xMax, word0->yMin, word0->yMax,
+ word0->base, word0->fontSize, word0->spaceAfter);
+ for (i = 0; i < word0->len; ++i) {
+ fputc(word0->text[i] & 0xff, stdout);
+ }
+ printf("'\n");
+ }
+ }
+ }
+ printf("\n");
+#endif
+
+ // determine the primary direction
+ lrCount = 0;
+ for (blk = blkList; blk; blk = blk->next) {
+ for (line = blk->lines; line; line = line->next) {
+ for (word0 = line->words; word0; word0 = word0->next) {
+ for (i = 0; i < word0->len; ++i) {
+ if (unicodeTypeL(word0->text[i])) {
+ ++lrCount;
+ } else if (unicodeTypeR(word0->text[i])) {
+ --lrCount;
+ }
+ }
+ }
+ }
+ }
+ primaryLR = lrCount >= 0;
+
+#if 0 // for debugging
+ printf("*** direction ***\n");
+ printf("lrCount = %d\n", lrCount);
+ printf("primaryLR = %d\n", primaryLR);
+#endif
+
+ //----- column assignment
+
+ // sort blocks into xy order for column assignment
+ blocks = (TextBlock **)gmallocn(nBlocks, sizeof(TextBlock *));
+ for (blk = blkList, i = 0; blk; blk = blk->next, ++i) {
+ blocks[i] = blk;
+ }
+ qsort(blocks, nBlocks, sizeof(TextBlock *), &TextBlock::cmpXYPrimaryRot);
+
+ // column assignment
+ for (i = 0; i < nBlocks; ++i) {
+ blk0 = blocks[i];
+ col1 = 0;
+ for (j = 0; j < i; ++j) {
+ blk1 = blocks[j];
+ col2 = 0; // make gcc happy
+ switch (primaryRot) {
+ case 0:
+ if (blk0->xMin > blk1->xMax) {
+ col2 = blk1->col + blk1->nColumns + 3;
+ } else if (blk1->xMax == blk1->xMin) {
+ col2 = blk1->col;
+ } else {
+ col2 = blk1->col + (int)(((blk0->xMin - blk1->xMin) /
+ (blk1->xMax - blk1->xMin)) *
+ blk1->nColumns);
+ }
+ break;
+ case 1:
+ if (blk0->yMin > blk1->yMax) {
+ col2 = blk1->col + blk1->nColumns + 3;
+ } else if (blk1->yMax == blk1->yMin) {
+ col2 = blk1->col;
+ } else {
+ col2 = blk1->col + (int)(((blk0->yMin - blk1->yMin) /
+ (blk1->yMax - blk1->yMin)) *
+ blk1->nColumns);
+ }
+ break;
+ case 2:
+ if (blk0->xMax < blk1->xMin) {
+ col2 = blk1->col + blk1->nColumns + 3;
+ } else if (blk1->xMin == blk1->xMax) {
+ col2 = blk1->col;
+ } else {
+ col2 = blk1->col + (int)(((blk0->xMax - blk1->xMax) /
+ (blk1->xMin - blk1->xMax)) *
+ blk1->nColumns);
+ }
+ break;
+ case 3:
+ if (blk0->yMax < blk1->yMin) {
+ col2 = blk1->col + blk1->nColumns + 3;
+ } else if (blk1->yMin == blk1->yMax) {
+ col2 = blk1->col;
+ } else {
+ col2 = blk1->col + (int)(((blk0->yMax - blk1->yMax) /
+ (blk1->yMin - blk1->yMax)) *
+ blk1->nColumns);
+ }
+ break;
+ }
+ if (col2 > col1) {
+ col1 = col2;
+ }
+ }
+ blk0->col = col1;
+ for (line = blk0->lines; line; line = line->next) {
+ for (j = 0; j <= line->len; ++j) {
+ line->col[j] += col1;
+ }
+ }
+ }
+
+#if 0 // for debugging
+ printf("*** blocks, after column assignment ***\n");
+ for (blk = blkList; blk; blk = blk->next) {
+ printf("block: rot=%d x=%.2f..%.2f y=%.2f..%.2f col=%d nCols=%d\n",
+ blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax, blk->col,
+ blk->nColumns);
+ for (line = blk->lines; line; line = line->next) {
+ printf(" line:\n");
+ for (word0 = line->words; word0; word0 = word0->next) {
+ printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '",
+ word0->xMin, word0->xMax, word0->yMin, word0->yMax,
+ word0->base, word0->fontSize, word0->spaceAfter);
+ for (i = 0; i < word0->len; ++i) {
+ fputc(word0->text[i] & 0xff, stdout);
+ }
+ printf("'\n");
+ }
+ }
+ }
+ printf("\n");
+#endif
+
+ //----- reading order sort
+
+ // sort blocks into yx order (in preparation for reading order sort)
+ qsort(blocks, nBlocks, sizeof(TextBlock *), &TextBlock::cmpYXPrimaryRot);
+
+ // compute space on left and right sides of each block
+ for (i = 0; i < nBlocks; ++i) {
+ blk0 = blocks[i];
+ for (j = 0; j < nBlocks; ++j) {
+ blk1 = blocks[j];
+ if (blk1 != blk0) {
+ blk0->updatePriMinMax(blk1);
+ }
+ }
+ }
+
+#if 0 // for debugging
+ printf("*** blocks, after yx sort ***\n");
+ for (i = 0; i < nBlocks; ++i) {
+ blk = blocks[i];
+ printf("block: rot=%d x=%.2f..%.2f y=%.2f..%.2f space=%.2f..%.2f\n",
+ blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax,
+ blk->priMin, blk->priMax);
+ for (line = blk->lines; line; line = line->next) {
+ printf(" line:\n");
+ for (word0 = line->words; word0; word0 = word0->next) {
+ printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '",
+ word0->xMin, word0->xMax, word0->yMin, word0->yMax,
+ word0->base, word0->fontSize, word0->spaceAfter);
+ for (j = 0; j < word0->len; ++j) {
+ fputc(word0->text[j] & 0xff, stdout);
+ }
+ printf("'\n");
+ }
+ }
+ }
+ printf("\n");
+#endif
+
+ // build the flows
+ //~ this needs to be adjusted for writing mode (vertical text)
+ //~ this also needs to account for right-to-left column ordering
+ blkArray = (TextBlock **)gmallocn(nBlocks, sizeof(TextBlock *));
+ memcpy(blkArray, blocks, nBlocks * sizeof(TextBlock *));
+ flows = lastFlow = NULL;
+ firstBlkIdx = 0;
+ nBlocksLeft = nBlocks;
+ while (nBlocksLeft > 0) {
+
+ // find the upper-left-most block
+ for (; !blkArray[firstBlkIdx]; ++firstBlkIdx) ;
+ i = firstBlkIdx;
+ blk = blkArray[i];
+ for (j = firstBlkIdx + 1; j < nBlocks; ++j) {
+ blk1 = blkArray[j];
+ if (blk1) {
+ if (blk && blk->secondaryDelta(blk1) > 0) {
+ break;
+ }
+ if (blk1->primaryCmp(blk) < 0) {
+ i = j;
+ blk = blk1;
+ }
+ }
+ }
+ blkArray[i] = NULL;
+ --nBlocksLeft;
+ blk->next = NULL;
+
+ // create a new flow, starting with the upper-left-most block
+ flow = new TextFlow(this, blk);
+ if (lastFlow) {
+ lastFlow->next = flow;
+ } else {
+ flows = flow;
+ }
+ lastFlow = flow;
+ fontSize = blk->lines->words->fontSize;
+
+ // push the upper-left-most block on the stack
+ blk->stackNext = NULL;
+ blkStack = blk;
+
+ // find the other blocks in this flow
+ while (blkStack) {
+
+ // find the upper-left-most block under (but within
+ // maxBlockSpacing of) the top block on the stack
+ blkSpace = maxBlockSpacing * blkStack->lines->words->fontSize;
+ blk = NULL;
+ i = -1;
+ for (j = firstBlkIdx; j < nBlocks; ++j) {
+ blk1 = blkArray[j];
+ if (blk1) {
+ if (blkStack->secondaryDelta(blk1) > blkSpace) {
+ break;
+ }
+ if (blk && blk->secondaryDelta(blk1) > 0) {
+ break;
+ }
+ if (blk1->isBelow(blkStack) &&
+ (!blk || blk1->primaryCmp(blk) < 0)) {
+ i = j;
+ blk = blk1;
+ }
+ }
+ }
+
+ // if a suitable block was found, add it to the flow and push it
+ // onto the stack
+ if (blk && flow->blockFits(blk, blkStack)) {
+ blkArray[i] = NULL;
+ --nBlocksLeft;
+ blk->next = NULL;
+ flow->addBlock(blk);
+ fontSize = blk->lines->words->fontSize;
+ blk->stackNext = blkStack;
+ blkStack = blk;
+
+ // otherwise (if there is no block under the top block or the
+ // block is not suitable), pop the stack
+ } else {
+ blkStack = blkStack->stackNext;
+ }
+ }
+ }
+ gfree(blkArray);
+
+#if 0 // for debugging
+ printf("*** flows ***\n");
+ for (flow = flows; flow; flow = flow->next) {
+ printf("flow: x=%.2f..%.2f y=%.2f..%.2f pri:%.2f..%.2f\n",
+ flow->xMin, flow->xMax, flow->yMin, flow->yMax,
+ flow->priMin, flow->priMax);
+ for (blk = flow->blocks; blk; blk = blk->next) {
+ printf(" block: rot=%d x=%.2f..%.2f y=%.2f..%.2f pri=%.2f..%.2f\n",
+ blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax,
+ blk->priMin, blk->priMax);
+ for (line = blk->lines; line; line = line->next) {
+ printf(" line:\n");
+ for (word0 = line->words; word0; word0 = word0->next) {
+ printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '",
+ word0->xMin, word0->xMax, word0->yMin, word0->yMax,
+ word0->base, word0->fontSize, word0->spaceAfter);
+ for (i = 0; i < word0->len; ++i) {
+ fputc(word0->text[i] & 0xff, stdout);
+ }
+ printf("'\n");
+ }
+ }
+ }
+ }
+ printf("\n");
+#endif
+
+ if (uMap) {
+ uMap->decRefCnt();
+ }
+}
+
+GBool TextPage::findText(Unicode *s, int len,
+ GBool startAtTop, GBool stopAtBottom,
+ GBool startAtLast, GBool stopAtLast,
+ GBool caseSensitive, GBool backward,
+ double *xMin, double *yMin,
+ double *xMax, double *yMax) {
+ TextBlock *blk;
+ TextLine *line;
+ Unicode *s2, *txt;
+ Unicode *p;
+ int txtSize, m, i, j, k;
+ double xStart, yStart, xStop, yStop;
+ double xMin0, yMin0, xMax0, yMax0;
+ double xMin1, yMin1, xMax1, yMax1;
+ GBool found;
+
+ //~ needs to handle right-to-left text
+
+ if (rawOrder) {
+ return gFalse;
+ }
+
+ // convert the search string to uppercase
+ if (!caseSensitive) {
+ s2 = (Unicode *)gmallocn(len, sizeof(Unicode));
+ for (i = 0; i < len; ++i) {
+ s2[i] = unicodeToUpper(s[i]);
+ }
+ } else {
+ s2 = s;
+ }
+
+ txt = NULL;
+ txtSize = 0;
+
+ xStart = yStart = xStop = yStop = 0;
+ if (startAtLast && haveLastFind) {
+ xStart = lastFindXMin;
+ yStart = lastFindYMin;
+ } else if (!startAtTop) {
+ xStart = *xMin;
+ yStart = *yMin;
+ }
+ if (stopAtLast && haveLastFind) {
+ xStop = lastFindXMin;
+ yStop = lastFindYMin;
+ } else if (!stopAtBottom) {
+ xStop = *xMax;
+ yStop = *yMax;
+ }
+
+ found = gFalse;
+ xMin0 = xMax0 = yMin0 = yMax0 = 0; // make gcc happy
+ xMin1 = xMax1 = yMin1 = yMax1 = 0; // make gcc happy
+
+ for (i = backward ? nBlocks - 1 : 0;
+ backward ? i >= 0 : i < nBlocks;
+ i += backward ? -1 : 1) {
+ blk = blocks[i];
+
+ // check: is the block above the top limit?
+ if (!startAtTop && (backward ? blk->yMin > yStart : blk->yMax < yStart)) {
+ continue;
+ }
+
+ // check: is the block below the bottom limit?
+ if (!stopAtBottom && (backward ? blk->yMax < yStop : blk->yMin > yStop)) {
+ break;
+ }
+
+ for (line = blk->lines; line; line = line->next) {
+
+ // check: is the line above the top limit?
+ if (!startAtTop &&
+ (backward ? line->yMin > yStart : line->yMin < yStart)) {
+ continue;
+ }
+
+ // check: is the line below the bottom limit?
+ if (!stopAtBottom &&
+ (backward ? line->yMin < yStop : line->yMin > yStop)) {
+ continue;
+ }
+
+ // convert the line to uppercase
+ m = line->len;
+ if (!caseSensitive) {
+ if (m > txtSize) {
+ txt = (Unicode *)greallocn(txt, m, sizeof(Unicode));
+ txtSize = m;
+ }
+ for (k = 0; k < m; ++k) {
+ txt[k] = unicodeToUpper(line->text[k]);
+ }
+ } else {
+ txt = line->text;
+ }
+
+ // search each position in this line
+ j = backward ? m - len : 0;
+ p = txt + j;
+ while (backward ? j >= 0 : j <= m - len) {
+
+ // compare the strings
+ for (k = 0; k < len; ++k) {
+ if (p[k] != s2[k]) {
+ break;
+ }
+ }
+
+ // found it
+ if (k == len) {
+ switch (line->rot) {
+ case 0:
+ xMin1 = line->edge[j];
+ xMax1 = line->edge[j + len];
+ yMin1 = line->yMin;
+ yMax1 = line->yMax;
+ break;
+ case 1:
+ xMin1 = line->xMin;
+ xMax1 = line->xMax;
+ yMin1 = line->edge[j];
+ yMax1 = line->edge[j + len];
+ break;
+ case 2:
+ xMin1 = line->edge[j + len];
+ xMax1 = line->edge[j];
+ yMin1 = line->yMin;
+ yMax1 = line->yMax;
+ break;
+ case 3:
+ xMin1 = line->xMin;
+ xMax1 = line->xMax;
+ yMin1 = line->edge[j + len];
+ yMax1 = line->edge[j];
+ break;
+ }
+ if (backward) {
+ if ((startAtTop ||
+ yMin1 < yStart || (yMin1 == yStart && xMin1 < xStart)) &&
+ (stopAtBottom ||
+ yMin1 > yStop || (yMin1 == yStop && xMin1 > xStop))) {
+ if (!found ||
+ yMin1 > yMin0 || (yMin1 == yMin0 && xMin1 > xMin0)) {
+ xMin0 = xMin1;
+ xMax0 = xMax1;
+ yMin0 = yMin1;
+ yMax0 = yMax1;
+ found = gTrue;
+ }
+ }
+ } else {
+ if ((startAtTop ||
+ yMin1 > yStart || (yMin1 == yStart && xMin1 > xStart)) &&
+ (stopAtBottom ||
+ yMin1 < yStop || (yMin1 == yStop && xMin1 < xStop))) {
+ if (!found ||
+ yMin1 < yMin0 || (yMin1 == yMin0 && xMin1 < xMin0)) {
+ xMin0 = xMin1;
+ xMax0 = xMax1;
+ yMin0 = yMin1;
+ yMax0 = yMax1;
+ found = gTrue;
+ }
+ }
+ }
+ }
+ if (backward) {
+ --j;
+ --p;
+ } else {
+ ++j;
+ ++p;
+ }
+ }
+ }
+ }
+
+ if (!caseSensitive) {
+ gfree(s2);
+ gfree(txt);
+ }
+
+ if (found) {
+ *xMin = xMin0;
+ *xMax = xMax0;
+ *yMin = yMin0;
+ *yMax = yMax0;
+ lastFindXMin = xMin0;
+ lastFindYMin = yMin0;
+ haveLastFind = gTrue;
+ return gTrue;
+ }
+
+ return gFalse;
+}
+
+GString *TextPage::getText(double xMin, double yMin,
+ double xMax, double yMax) {
+ GString *s;
+ UnicodeMap *uMap;
+ GBool isUnicode;
+ TextBlock *blk;
+ TextLine *line;
+ TextLineFrag *frags;
+ int nFrags, fragsSize;
+ TextLineFrag *frag;
+ char space[8], eol[16];
+ int spaceLen, eolLen;
+ int lastRot;
+ double x, y, delta;
+ int col, idx0, idx1, i, j;
+ GBool multiLine, oneRot;
+
+ s = new GString();
+
+ if (rawOrder) {
+ return s;
+ }
+
+ // get the output encoding
+ if (!(uMap = globalParams->getTextEncoding())) {
+ return s;
+ }
+ isUnicode = uMap->isUnicode();
+ spaceLen = uMap->mapUnicode(0x20, space, sizeof(space));
+ eolLen = 0; // make gcc happy
+ switch (globalParams->getTextEOL()) {
+ case eolUnix:
+ eolLen = uMap->mapUnicode(0x0a, eol, sizeof(eol));
+ break;
+ case eolDOS:
+ eolLen = uMap->mapUnicode(0x0d, eol, sizeof(eol));
+ eolLen += uMap->mapUnicode(0x0a, eol + eolLen, sizeof(eol) - eolLen);
+ break;
+ case eolMac:
+ eolLen = uMap->mapUnicode(0x0d, eol, sizeof(eol));
+ break;
+ }
+
+ //~ writing mode (horiz/vert)
+
+ // collect the line fragments that are in the rectangle
+ fragsSize = 256;
+ frags = (TextLineFrag *)gmallocn(fragsSize, sizeof(TextLineFrag));
+ nFrags = 0;
+ lastRot = -1;
+ oneRot = gTrue;
+ for (i = 0; i < nBlocks; ++i) {
+ blk = blocks[i];
+ if (xMin < blk->xMax && blk->xMin < xMax &&
+ yMin < blk->yMax && blk->yMin < yMax) {
+ for (line = blk->lines; line; line = line->next) {
+ if (xMin < line->xMax && line->xMin < xMax &&
+ yMin < line->yMax && line->yMin < yMax) {
+ idx0 = idx1 = -1;
+ switch (line->rot) {
+ case 0:
+ y = 0.5 * (line->yMin + line->yMax);
+ if (yMin < y && y < yMax) {
+ j = 0;
+ while (j < line->len) {
+ if (0.5 * (line->edge[j] + line->edge[j+1]) > xMin) {
+ idx0 = j;
+ break;
+ }
+ ++j;
+ }
+ j = line->len - 1;
+ while (j >= 0) {
+ if (0.5 * (line->edge[j] + line->edge[j+1]) < xMax) {
+ idx1 = j;
+ break;
+ }
+ --j;
+ }
+ }
+ break;
+ case 1:
+ x = 0.5 * (line->xMin + line->xMax);
+ if (xMin < x && x < xMax) {
+ j = 0;
+ while (j < line->len) {
+ if (0.5 * (line->edge[j] + line->edge[j+1]) > yMin) {
+ idx0 = j;
+ break;
+ }
+ ++j;
+ }
+ j = line->len - 1;
+ while (j >= 0) {
+ if (0.5 * (line->edge[j] + line->edge[j+1]) < yMax) {
+ idx1 = j;
+ break;
+ }
+ --j;
+ }
+ }
+ break;
+ case 2:
+ y = 0.5 * (line->yMin + line->yMax);
+ if (yMin < y && y < yMax) {
+ j = 0;
+ while (j < line->len) {
+ if (0.5 * (line->edge[j] + line->edge[j+1]) < xMax) {
+ idx0 = j;
+ break;
+ }
+ ++j;
+ }
+ j = line->len - 1;
+ while (j >= 0) {
+ if (0.5 * (line->edge[j] + line->edge[j+1]) > xMin) {
+ idx1 = j;
+ break;
+ }
+ --j;
+ }
+ }
+ break;
+ case 3:
+ x = 0.5 * (line->xMin + line->xMax);
+ if (xMin < x && x < xMax) {
+ j = 0;
+ while (j < line->len) {
+ if (0.5 * (line->edge[j] + line->edge[j+1]) < yMax) {
+ idx0 = j;
+ break;
+ }
+ ++j;
+ }
+ j = line->len - 1;
+ while (j >= 0) {
+ if (0.5 * (line->edge[j] + line->edge[j+1]) > yMin) {
+ idx1 = j;
+ break;
+ }
+ --j;
+ }
+ }
+ break;
+ }
+ if (idx0 >= 0 && idx1 >= 0) {
+ if (nFrags == fragsSize) {
+ fragsSize *= 2;
+ frags = (TextLineFrag *)
+ greallocn(frags, fragsSize, sizeof(TextLineFrag));
+ }
+ frags[nFrags].init(line, idx0, idx1 - idx0 + 1);
+ ++nFrags;
+ if (lastRot >= 0 && line->rot != lastRot) {
+ oneRot = gFalse;
+ }
+ lastRot = line->rot;
+ }
+ }
+ }
+ }
+ }
+
+ // sort the fragments and generate the string
+ if (nFrags > 0) {
+
+ for (i = 0; i < nFrags; ++i) {
+ frags[i].computeCoords(oneRot);
+ }
+ assignColumns(frags, nFrags, oneRot);
+
+ // if all lines in the region have the same rotation, use it;
+ // otherwise, use the page's primary rotation
+ if (oneRot) {
+ qsort(frags, nFrags, sizeof(TextLineFrag),
+ &TextLineFrag::cmpYXLineRot);
+ } else {
+ qsort(frags, nFrags, sizeof(TextLineFrag),
+ &TextLineFrag::cmpYXPrimaryRot);
+ }
+ i = 0;
+ while (i < nFrags) {
+ delta = maxIntraLineDelta * frags[i].line->words->fontSize;
+ for (j = i+1;
+ j < nFrags && fabs(frags[j].base - frags[i].base) < delta;
+ ++j) ;
+ qsort(frags + i, j - i, sizeof(TextLineFrag),
+ oneRot ? &TextLineFrag::cmpXYColumnLineRot
+ : &TextLineFrag::cmpXYColumnPrimaryRot);
+ i = j;
+ }
+
+ col = 0;
+ multiLine = gFalse;
+ for (i = 0; i < nFrags; ++i) {
+ frag = &frags[i];
+
+ // insert a return
+ if (frag->col < col ||
+ (i > 0 && fabs(frag->base - frags[i-1].base) >
+ maxIntraLineDelta * frags[i-1].line->words->fontSize)) {
+ s->append(eol, eolLen);
+ col = 0;
+ multiLine = gTrue;
+ }
+
+ // column alignment
+ for (; col < frag->col; ++col) {
+ s->append(space, spaceLen);
+ }
+
+ // get the fragment text
+ col += dumpFragment(frag->line->text + frag->start, frag->len, uMap, s);
+ }
+
+ if (multiLine) {
+ s->append(eol, eolLen);
+ }
+ }
+
+ gfree(frags);
+ uMap->decRefCnt();
+
+ return s;
+}
+
+GBool TextPage::findCharRange(int pos, int length,
+ double *xMin, double *yMin,
+ double *xMax, double *yMax) {
+ TextBlock *blk;
+ TextLine *line;
+ TextWord *word;
+ double xMin0, xMax0, yMin0, yMax0;
+ double xMin1, xMax1, yMin1, yMax1;
+ GBool first;
+ int i, j0, j1;
+
+ if (rawOrder) {
+ return gFalse;
+ }
+
+ //~ this doesn't correctly handle:
+ //~ - ranges split across multiple lines (the highlighted region
+ //~ is the bounding box of all the parts of the range)
+ //~ - cases where characters don't convert one-to-one into Unicode
+ first = gTrue;
+ xMin0 = xMax0 = yMin0 = yMax0 = 0; // make gcc happy
+ xMin1 = xMax1 = yMin1 = yMax1 = 0; // make gcc happy
+ for (i = 0; i < nBlocks; ++i) {
+ blk = blocks[i];
+ for (line = blk->lines; line; line = line->next) {
+ for (word = line->words; word; word = word->next) {
+ if (pos < word->charPos + word->charLen &&
+ word->charPos < pos + length) {
+ j0 = pos - word->charPos;
+ if (j0 < 0) {
+ j0 = 0;
+ }
+ j1 = pos + length - 1 - word->charPos;
+ if (j1 >= word->len) {
+ j1 = word->len - 1;
+ }
+ switch (line->rot) {
+ case 0:
+ xMin1 = word->edge[j0];
+ xMax1 = word->edge[j1 + 1];
+ yMin1 = word->yMin;
+ yMax1 = word->yMax;
+ break;
+ case 1:
+ xMin1 = word->xMin;
+ xMax1 = word->xMax;
+ yMin1 = word->edge[j0];
+ yMax1 = word->edge[j1 + 1];
+ break;
+ case 2:
+ xMin1 = word->edge[j1 + 1];
+ xMax1 = word->edge[j0];
+ yMin1 = word->yMin;
+ yMax1 = word->yMax;
+ break;
+ case 3:
+ xMin1 = word->xMin;
+ xMax1 = word->xMax;
+ yMin1 = word->edge[j1 + 1];
+ yMax1 = word->edge[j0];
+ break;
+ }
+ if (first || xMin1 < xMin0) {
+ xMin0 = xMin1;
+ }
+ if (first || xMax1 > xMax0) {
+ xMax0 = xMax1;
+ }
+ if (first || yMin1 < yMin0) {
+ yMin0 = yMin1;
+ }
+ if (first || yMax1 > yMax0) {
+ yMax0 = yMax1;
+ }
+ first = gFalse;
+ }
+ }
+ }
+ }
+ if (!first) {
+ *xMin = xMin0;
+ *xMax = xMax0;
+ *yMin = yMin0;
+ *yMax = yMax0;
+ return gTrue;
+ }
+ return gFalse;
+}
+
+void TextPage::dump(void *outputStream, TextOutputFunc outputFunc,
+ GBool physLayout) {
+ UnicodeMap *uMap;
+ TextFlow *flow;
+ TextBlock *blk;
+ TextLine *line;
+ TextLineFrag *frags;
+ TextWord *word;
+ int nFrags, fragsSize;
+ TextLineFrag *frag;
+ char space[8], eol[16], eop[8];
+ int spaceLen, eolLen, eopLen;
+ GBool pageBreaks;
+ GString *s;
+ double delta;
+ int col, i, j, d, n;
+
+ // get the output encoding
+ if (!(uMap = globalParams->getTextEncoding())) {
+ return;
+ }
+ spaceLen = uMap->mapUnicode(0x20, space, sizeof(space));
+ eolLen = 0; // make gcc happy
+ switch (globalParams->getTextEOL()) {
+ case eolUnix:
+ eolLen = uMap->mapUnicode(0x0a, eol, sizeof(eol));
+ break;
+ case eolDOS:
+ eolLen = uMap->mapUnicode(0x0d, eol, sizeof(eol));
+ eolLen += uMap->mapUnicode(0x0a, eol + eolLen, sizeof(eol) - eolLen);
+ break;
+ case eolMac:
+ eolLen = uMap->mapUnicode(0x0d, eol, sizeof(eol));
+ break;
+ }
+ eopLen = uMap->mapUnicode(0x0c, eop, sizeof(eop));
+ pageBreaks = globalParams->getTextPageBreaks();
+
+ //~ writing mode (horiz/vert)
+
+ // output the page in raw (content stream) order
+ if (rawOrder) {
+
+ for (word = rawWords; word; word = word->next) {
+ s = new GString();
+ dumpFragment(word->text, word->len, uMap, s);
+ (*outputFunc)(outputStream, s->getCString(), s->getLength());
+ delete s;
+ if (word->next &&
+ fabs(word->next->base - word->base) <
+ maxIntraLineDelta * word->fontSize) {
+ if (word->next->xMin > word->xMax + minWordSpacing * word->fontSize) {
+ (*outputFunc)(outputStream, space, spaceLen);
+ }
+ } else {
+ (*outputFunc)(outputStream, eol, eolLen);
+ }
+ }
+
+ // output the page, maintaining the original physical layout
+ } else if (physLayout) {
+
+ // collect the line fragments for the page and sort them
+ fragsSize = 256;
+ frags = (TextLineFrag *)gmallocn(fragsSize, sizeof(TextLineFrag));
+ nFrags = 0;
+ for (i = 0; i < nBlocks; ++i) {
+ blk = blocks[i];
+ for (line = blk->lines; line; line = line->next) {
+ if (nFrags == fragsSize) {
+ fragsSize *= 2;
+ frags = (TextLineFrag *)greallocn(frags,
+ fragsSize, sizeof(TextLineFrag));
+ }
+ frags[nFrags].init(line, 0, line->len);
+ frags[nFrags].computeCoords(gTrue);
+ ++nFrags;
+ }
+ }
+ qsort(frags, nFrags, sizeof(TextLineFrag), &TextLineFrag::cmpYXPrimaryRot);
+ i = 0;
+ while (i < nFrags) {
+ delta = maxIntraLineDelta * frags[i].line->words->fontSize;
+ for (j = i+1;
+ j < nFrags && fabs(frags[j].base - frags[i].base) < delta;
+ ++j) ;
+ qsort(frags + i, j - i, sizeof(TextLineFrag),
+ &TextLineFrag::cmpXYColumnPrimaryRot);
+ i = j;
+ }
+
+#if 0 // for debugging
+ printf("*** line fragments ***\n");
+ for (i = 0; i < nFrags; ++i) {
+ frag = &frags[i];
+ printf("frag: x=%.2f..%.2f y=%.2f..%.2f base=%.2f '",
+ frag->xMin, frag->xMax, frag->yMin, frag->yMax, frag->base);
+ for (n = 0; n < frag->len; ++n) {
+ fputc(frag->line->text[frag->start + n] & 0xff, stdout);
+ }
+ printf("'\n");
+ }
+ printf("\n");
+#endif
+
+ // generate output
+ col = 0;
+ for (i = 0; i < nFrags; ++i) {
+ frag = &frags[i];
+
+ // column alignment
+ for (; col < frag->col; ++col) {
+ (*outputFunc)(outputStream, space, spaceLen);
+ }
+
+ // print the line
+ s = new GString();
+ col += dumpFragment(frag->line->text + frag->start, frag->len, uMap, s);
+ (*outputFunc)(outputStream, s->getCString(), s->getLength());
+ delete s;
+
+ // print one or more returns if necessary
+ if (i == nFrags - 1 ||
+ frags[i+1].col < col ||
+ fabs(frags[i+1].base - frag->base) >
+ maxIntraLineDelta * frag->line->words->fontSize) {
+ if (i < nFrags - 1) {
+ d = (int)((frags[i+1].base - frag->base) /
+ frag->line->words->fontSize);
+ if (d < 1) {
+ d = 1;
+ } else if (d > 5) {
+ d = 5;
+ }
+ } else {
+ d = 1;
+ }
+ for (; d > 0; --d) {
+ (*outputFunc)(outputStream, eol, eolLen);
+ }
+ col = 0;
+ }
+ }
+
+ gfree(frags);
+
+ // output the page, "undoing" the layout
+ } else {
+ for (flow = flows; flow; flow = flow->next) {
+ for (blk = flow->blocks; blk; blk = blk->next) {
+ for (line = blk->lines; line; line = line->next) {
+ n = line->len;
+ if (line->hyphenated && (line->next || blk->next)) {
+ --n;
+ }
+ s = new GString();
+ dumpFragment(line->text, n, uMap, s);
+ (*outputFunc)(outputStream, s->getCString(), s->getLength());
+ delete s;
+ if (!line->hyphenated) {
+ if (line->next) {
+ (*outputFunc)(outputStream, space, spaceLen);
+ } else if (blk->next) {
+ //~ this is a bit of a kludge - we should really do a more
+ //~ intelligent determination of paragraphs
+ if (blk->next->lines->words->fontSize ==
+ blk->lines->words->fontSize) {
+ (*outputFunc)(outputStream, space, spaceLen);
+ } else {
+ (*outputFunc)(outputStream, eol, eolLen);
+ }
+ }
+ }
+ }
+ }
+ (*outputFunc)(outputStream, eol, eolLen);
+ (*outputFunc)(outputStream, eol, eolLen);
+ }
+ }
+
+ // end of page
+ if (pageBreaks) {
+ (*outputFunc)(outputStream, eop, eopLen);
+ }
+
+ uMap->decRefCnt();
+}
+
+void TextPage::assignColumns(TextLineFrag *frags, int nFrags, GBool oneRot) {
+ TextLineFrag *frag0, *frag1;
+ int rot, col1, col2, i, j, k;
+
+ // all text in the region has the same rotation -- recompute the
+ // column numbers based only on the text in the region
+ if (oneRot) {
+ qsort(frags, nFrags, sizeof(TextLineFrag), &TextLineFrag::cmpXYLineRot);
+ rot = frags[0].line->rot;
+ for (i = 0; i < nFrags; ++i) {
+ frag0 = &frags[i];
+ col1 = 0;
+ for (j = 0; j < i; ++j) {
+ frag1 = &frags[j];
+ col2 = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ if (frag0->xMin >= frag1->xMax) {
+ col2 = frag1->col + (frag1->line->col[frag1->start + frag1->len] -
+ frag1->line->col[frag1->start]) + 1;
+ } else {
+ for (k = frag1->start;
+ k < frag1->start + frag1->len &&
+ frag0->xMin >= 0.5 * (frag1->line->edge[k] +
+ frag1->line->edge[k+1]);
+ ++k) ;
+ col2 = frag1->col +
+ frag1->line->col[k] - frag1->line->col[frag1->start];
+ }
+ break;
+ case 1:
+ if (frag0->yMin >= frag1->yMax) {
+ col2 = frag1->col + (frag1->line->col[frag1->start + frag1->len] -
+ frag1->line->col[frag1->start]) + 1;
+ } else {
+ for (k = frag1->start;
+ k < frag1->start + frag1->len &&
+ frag0->yMin >= 0.5 * (frag1->line->edge[k] +
+ frag1->line->edge[k+1]);
+ ++k) ;
+ col2 = frag1->col +
+ frag1->line->col[k] - frag1->line->col[frag1->start];
+ }
+ break;
+ case 2:
+ if (frag0->xMax <= frag1->xMin) {
+ col2 = frag1->col + (frag1->line->col[frag1->start + frag1->len] -
+ frag1->line->col[frag1->start]) + 1;
+ } else {
+ for (k = frag1->start;
+ k < frag1->start + frag1->len &&
+ frag0->xMax <= 0.5 * (frag1->line->edge[k] +
+ frag1->line->edge[k+1]);
+ ++k) ;
+ col2 = frag1->col +
+ frag1->line->col[k] - frag1->line->col[frag1->start];
+ }
+ break;
+ case 3:
+ if (frag0->yMax <= frag1->yMin) {
+ col2 = frag1->col + (frag1->line->col[frag1->start + frag1->len] -
+ frag1->line->col[frag1->start]) + 1;
+ } else {
+ for (k = frag1->start;
+ k < frag1->start + frag1->len &&
+ frag0->yMax <= 0.5 * (frag1->line->edge[k] +
+ frag1->line->edge[k+1]);
+ ++k) ;
+ col2 = frag1->col +
+ frag1->line->col[k] - frag1->line->col[frag1->start];
+ }
+ break;
+ }
+ if (col2 > col1) {
+ col1 = col2;
+ }
+ }
+ frag0->col = col1;
+ }
+
+ // the region includes text at different rotations -- use the
+ // globally assigned column numbers, offset by the minimum column
+ // number (i.e., shift everything over to column 0)
+ } else {
+ col1 = frags[0].col;
+ for (i = 1; i < nFrags; ++i) {
+ if (frags[i].col < col1) {
+ col1 = frags[i].col;
+ }
+ }
+ for (i = 0; i < nFrags; ++i) {
+ frags[i].col -= col1;
+ }
+ }
+}
+
+int TextPage::dumpFragment(Unicode *text, int len, UnicodeMap *uMap,
+ GString *s) {
+ char lre[8], rle[8], popdf[8], buf[8];
+ int lreLen, rleLen, popdfLen, n;
+ int nCols, i, j, k;
+
+ nCols = 0;
+
+ if (uMap->isUnicode()) {
+
+ lreLen = uMap->mapUnicode(0x202a, lre, sizeof(lre));
+ rleLen = uMap->mapUnicode(0x202b, rle, sizeof(rle));
+ popdfLen = uMap->mapUnicode(0x202c, popdf, sizeof(popdf));
+
+ if (primaryLR) {
+
+ i = 0;
+ while (i < len) {
+ // output a left-to-right section
+ for (j = i; j < len && !unicodeTypeR(text[j]); ++j) ;
+ for (k = i; k < j; ++k) {
+ n = uMap->mapUnicode(text[k], buf, sizeof(buf));
+ s->append(buf, n);
+ ++nCols;
+ }
+ i = j;
+ // output a right-to-left section
+ for (j = i; j < len && !unicodeTypeL(text[j]); ++j) ;
+ if (j > i) {
+ s->append(rle, rleLen);
+ for (k = j - 1; k >= i; --k) {
+ n = uMap->mapUnicode(text[k], buf, sizeof(buf));
+ s->append(buf, n);
+ ++nCols;
+ }
+ s->append(popdf, popdfLen);
+ i = j;
+ }
+ }
+
+ } else {
+
+ s->append(rle, rleLen);
+ i = len - 1;
+ while (i >= 0) {
+ // output a right-to-left section
+ for (j = i; j >= 0 && !unicodeTypeL(text[j]); --j) ;
+ for (k = i; k > j; --k) {
+ n = uMap->mapUnicode(text[k], buf, sizeof(buf));
+ s->append(buf, n);
+ ++nCols;
+ }
+ i = j;
+ // output a left-to-right section
+ for (j = i; j >= 0 && !unicodeTypeR(text[j]); --j) ;
+ if (j < i) {
+ s->append(lre, lreLen);
+ for (k = j + 1; k <= i; ++k) {
+ n = uMap->mapUnicode(text[k], buf, sizeof(buf));
+ s->append(buf, n);
+ ++nCols;
+ }
+ s->append(popdf, popdfLen);
+ i = j;
+ }
+ }
+ s->append(popdf, popdfLen);
+
+ }
+
+ } else {
+ for (i = 0; i < len; ++i) {
+ n = uMap->mapUnicode(text[i], buf, sizeof(buf));
+ s->append(buf, n);
+ nCols += n;
+ }
+ }
+
+ return nCols;
+}
+
+#if TEXTOUT_WORD_LIST
+TextWordList *TextPage::makeWordList(GBool physLayout) {
+ return new TextWordList(this, physLayout);
+}
+#endif
+
+//------------------------------------------------------------------------
+// TextOutputDev
+//------------------------------------------------------------------------
+
+static void TextOutputDev_outputToFile(void *stream, char *text, int len) {
+ fwrite(text, 1, len, (FILE *)stream);
+}
+
+TextOutputDev::TextOutputDev(char *fileName, GBool physLayoutA,
+ GBool rawOrderA, GBool append) {
+ text = NULL;
+ physLayout = physLayoutA;
+ rawOrder = rawOrderA;
+ doHTML = gFalse;
+ ok = gTrue;
+
+ // open file
+ needClose = gFalse;
+ if (fileName) {
+ if (!strcmp(fileName, "-")) {
+ outputStream = stdout;
+#ifdef WIN32
+ // keep DOS from munging the end-of-line characters
+ setmode(fileno(stdout), O_BINARY);
+#endif
+ } else if ((outputStream = fopen(fileName, append ? "ab" : "wb"))) {
+ needClose = gTrue;
+ } else {
+ error(-1, "Couldn't open text file '%s'", fileName);
+ ok = gFalse;
+ return;
+ }
+ outputFunc = &TextOutputDev_outputToFile;
+ } else {
+ outputStream = NULL;
+ }
+
+ // set up text object
+ text = new TextPage(rawOrderA);
+}
+
+TextOutputDev::TextOutputDev(TextOutputFunc func, void *stream,
+ GBool physLayoutA, GBool rawOrderA) {
+ outputFunc = func;
+ outputStream = stream;
+ needClose = gFalse;
+ physLayout = physLayoutA;
+ rawOrder = rawOrderA;
+ doHTML = gFalse;
+ text = new TextPage(rawOrderA);
+ ok = gTrue;
+}
+
+TextOutputDev::~TextOutputDev() {
+ if (needClose) {
+#ifdef MACOS
+ ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle);
+#endif
+ fclose((FILE *)outputStream);
+ }
+ if (text) {
+ delete text;
+ }
+}
+
+void TextOutputDev::startPage(int /*pageNum*/, GfxState *state) {
+ text->startPage(state);
+}
+
+void TextOutputDev::endPage() {
+ text->endPage();
+ text->coalesce(physLayout, doHTML);
+ if (outputStream) {
+ text->dump(outputStream, outputFunc, physLayout);
+ }
+}
+
+void TextOutputDev::updateFont(GfxState *state) {
+ text->updateFont(state);
+}
+
+void TextOutputDev::beginString(GfxState * /*state*/, GString * /*s*/) {
+}
+
+void TextOutputDev::endString(GfxState * /*state*/) {
+}
+
+void TextOutputDev::drawChar(GfxState *state, double x, double y,
+ double dx, double dy,
+ double /*originX*/, double /*originY*/,
+ CharCode c, int nBytes, Unicode *u, int uLen) {
+ text->addChar(state, x, y, dx, dy, c, nBytes, u, uLen);
+}
+
+void TextOutputDev::stroke(GfxState *state) {
+ GfxPath *path;
+ GfxSubpath *subpath;
+ double x[2], y[2];
+
+ if (!doHTML) {
+ return;
+ }
+ path = state->getPath();
+ if (path->getNumSubpaths() != 1) {
+ return;
+ }
+ subpath = path->getSubpath(0);
+ if (subpath->getNumPoints() != 2) {
+ return;
+ }
+ state->transform(subpath->getX(0), subpath->getY(0), &x[0], &y[0]);
+ state->transform(subpath->getX(1), subpath->getY(1), &x[1], &y[1]);
+
+ // look for a vertical or horizontal line
+ if (x[0] == x[1] || y[0] == y[1]) {
+ text->addUnderline(x[0], y[0], x[1], y[1]);
+ }
+}
+
+void TextOutputDev::fill(GfxState *state) {
+ GfxPath *path;
+ GfxSubpath *subpath;
+ double x[5], y[5];
+ double rx0, ry0, rx1, ry1, t;
+ int i;
+
+ if (!doHTML) {
+ return;
+ }
+ path = state->getPath();
+ if (path->getNumSubpaths() != 1) {
+ return;
+ }
+ subpath = path->getSubpath(0);
+ if (subpath->getNumPoints() != 5) {
+ return;
+ }
+ for (i = 0; i < 5; ++i) {
+ if (subpath->getCurve(i)) {
+ return;
+ }
+ state->transform(subpath->getX(i), subpath->getY(i), &x[i], &y[i]);
+ }
+
+ // look for a rectangle
+ if (x[0] == x[1] && y[1] == y[2] && x[2] == x[3] && y[3] == y[4] &&
+ x[0] == x[4] && y[0] == y[4]) {
+ rx0 = x[0];
+ ry0 = y[0];
+ rx1 = x[2];
+ ry1 = y[1];
+ } else if (y[0] == y[1] && x[1] == x[2] && y[2] == y[3] && x[3] == x[4] &&
+ x[0] == x[4] && y[0] == y[4]) {
+ rx0 = x[0];
+ ry0 = y[0];
+ rx1 = x[1];
+ ry1 = y[2];
+ } else {
+ return;
+ }
+ if (rx1 < rx0) {
+ t = rx0;
+ rx0 = rx1;
+ rx1 = t;
+ }
+ if (ry1 < ry0) {
+ t = ry0;
+ ry0 = ry1;
+ ry1 = t;
+ }
+
+ // skinny horizontal rectangle
+ if (ry1 - ry0 < rx1 - rx0) {
+ if (ry1 - ry0 < maxUnderlineWidth) {
+ ry0 = 0.5 * (ry0 + ry1);
+ text->addUnderline(rx0, ry0, rx1, ry0);
+ }
+
+ // skinny vertical rectangle
+ } else {
+ if (rx1 - rx0 < maxUnderlineWidth) {
+ rx0 = 0.5 * (rx0 + rx1);
+ text->addUnderline(rx0, ry0, rx0, ry1);
+ }
+ }
+}
+
+void TextOutputDev::eoFill(GfxState *state) {
+ if (!doHTML) {
+ return;
+ }
+ fill(state);
+}
+
+void TextOutputDev::processLink(Link *link, Catalog * /*catalog*/) {
+ double x1, y1, x2, y2;
+ int xMin, yMin, xMax, yMax, x, y;
+
+ if (!doHTML) {
+ return;
+ }
+ link->getRect(&x1, &y1, &x2, &y2);
+ cvtUserToDev(x1, y1, &x, &y);
+ xMin = xMax = x;
+ yMin = yMax = y;
+ cvtUserToDev(x1, y2, &x, &y);
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ cvtUserToDev(x2, y1, &x, &y);
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ cvtUserToDev(x2, y2, &x, &y);
+ if (x < xMin) {
+ xMin = x;
+ } else if (x > xMax) {
+ xMax = x;
+ }
+ if (y < yMin) {
+ yMin = y;
+ } else if (y > yMax) {
+ yMax = y;
+ }
+ text->addLink(xMin, yMin, xMax, yMax, link);
+}
+
+GBool TextOutputDev::findText(Unicode *s, int len,
+ GBool startAtTop, GBool stopAtBottom,
+ GBool startAtLast, GBool stopAtLast,
+ GBool caseSensitive, GBool backward,
+ double *xMin, double *yMin,
+ double *xMax, double *yMax) {
+ return text->findText(s, len, startAtTop, stopAtBottom,
+ startAtLast, stopAtLast, caseSensitive, backward,
+ xMin, yMin, xMax, yMax);
+}
+
+GString *TextOutputDev::getText(double xMin, double yMin,
+ double xMax, double yMax) {
+ return text->getText(xMin, yMin, xMax, yMax);
+}
+
+GBool TextOutputDev::findCharRange(int pos, int length,
+ double *xMin, double *yMin,
+ double *xMax, double *yMax) {
+ return text->findCharRange(pos, length, xMin, yMin, xMax, yMax);
+}
+
+#if TEXTOUT_WORD_LIST
+TextWordList *TextOutputDev::makeWordList() {
+ return text->makeWordList(physLayout);
+}
+#endif
+
+TextPage *TextOutputDev::takeText() {
+ TextPage *ret;
+
+ ret = text;
+ text = new TextPage(rawOrder);
+ return ret;
+}
diff --git a/kpdf/xpdf/xpdf/TextOutputDev.h b/kpdf/xpdf/xpdf/TextOutputDev.h
new file mode 100644
index 00000000..3a424bb1
--- /dev/null
+++ b/kpdf/xpdf/xpdf/TextOutputDev.h
@@ -0,0 +1,661 @@
+//========================================================================
+//
+// TextOutputDev.h
+//
+// Copyright 1997-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef TEXTOUTPUTDEV_H
+#define TEXTOUTPUTDEV_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include <stdio.h>
+#include "gtypes.h"
+#include "GfxFont.h"
+#include "OutputDev.h"
+
+class GString;
+class GList;
+class GfxFont;
+class GfxState;
+class UnicodeMap;
+class Link;
+
+class TextWord;
+class TextPool;
+class TextLine;
+class TextLineFrag;
+class TextBlock;
+class TextFlow;
+class TextWordList;
+class TextPage;
+
+//------------------------------------------------------------------------
+
+typedef void (*TextOutputFunc)(void *stream, char *text, int len);
+
+//------------------------------------------------------------------------
+// TextFontInfo
+//------------------------------------------------------------------------
+
+class TextFontInfo {
+public:
+
+ TextFontInfo(GfxState *state);
+ ~TextFontInfo();
+
+ GBool matches(GfxState *state);
+
+#if TEXTOUT_WORD_LIST
+ // Get the font name (which may be NULL).
+ GString *getFontName() { return fontName; }
+
+ // Get font descriptor flags.
+ GBool isFixedWidth() { return flags & fontFixedWidth; }
+ GBool isSerif() { return flags & fontSerif; }
+ GBool isSymbolic() { return flags & fontSymbolic; }
+ GBool isItalic() { return flags & fontItalic; }
+ GBool isBold() { return flags & fontBold; }
+#endif
+
+private:
+
+ GfxFont *gfxFont;
+#if TEXTOUT_WORD_LIST
+ GString *fontName;
+ int flags;
+#endif
+
+ friend class TextWord;
+ friend class TextPage;
+};
+
+//------------------------------------------------------------------------
+// TextWord
+//------------------------------------------------------------------------
+
+class TextWord {
+public:
+
+ // Constructor.
+ TextWord(GfxState *state, int rotA, double x0, double y0,
+ int charPosA, TextFontInfo *fontA, double fontSize);
+
+ // Destructor.
+ ~TextWord();
+
+ // Add a character to the word.
+ void addChar(GfxState *state, double x, double y,
+ double dx, double dy, Unicode u);
+
+ // Merge <word> onto the end of <this>.
+ void merge(TextWord *word);
+
+ // Compares <this> to <word>, returning -1 (<), 0 (=), or +1 (>),
+ // based on a primary-axis comparison, e.g., x ordering if rot=0.
+ int primaryCmp(TextWord *word);
+
+ // Return the distance along the primary axis between <this> and
+ // <word>.
+ double primaryDelta(TextWord *word);
+
+ static int cmpYX(const void *p1, const void *p2);
+
+ // Get the TextFontInfo object associated with this word.
+ TextFontInfo *getFontInfo() { return font; }
+
+ // Get the next TextWord on the linked list.
+ TextWord *getNext() { return next; }
+
+#if TEXTOUT_WORD_LIST
+ int getLength() { return len; }
+ Unicode getChar(int idx) { return text[idx]; }
+ GString *getText();
+ GString *getFontName() { return font->fontName; }
+ void getColor(double *r, double *g, double *b)
+ { *r = colorR; *g = colorG; *b = colorB; }
+ void getBBox(double *xMinA, double *yMinA, double *xMaxA, double *yMaxA)
+ { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; }
+ void getCharBBox(int charIdx, double *xMinA, double *yMinA,
+ double *xMaxA, double *yMaxA);
+ double getFontSize() { return fontSize; }
+ int getRotation() { return rot; }
+ int getCharPos() { return charPos; }
+ int getCharLen() { return charLen; }
+ GBool getSpaceAfter() { return spaceAfter; }
+#endif
+
+ GBool isUnderlined() { return underlined; }
+ Link *getLink() { return link; }
+
+private:
+
+ int rot; // rotation, multiple of 90 degrees
+ // (0, 1, 2, or 3)
+ double xMin, xMax; // bounding box x coordinates
+ double yMin, yMax; // bounding box y coordinates
+ double base; // baseline x or y coordinate
+ Unicode *text; // the text
+ double *edge; // "near" edge x or y coord of each char
+ // (plus one extra entry for the last char)
+ int len; // length of text and edge arrays
+ int size; // size of text and edge arrays
+ int charPos; // character position (within content stream)
+ int charLen; // number of content stream characters in
+ // this word
+ TextFontInfo *font; // font information
+ double fontSize; // font size
+ GBool spaceAfter; // set if there is a space between this
+ // word and the next word on the line
+ TextWord *next; // next word in line
+
+#if TEXTOUT_WORD_LIST
+ double colorR, // word color
+ colorG,
+ colorB;
+#endif
+
+ GBool underlined;
+ Link *link;
+
+ friend class TextPool;
+ friend class TextLine;
+ friend class TextBlock;
+ friend class TextFlow;
+ friend class TextWordList;
+ friend class TextPage;
+};
+
+//------------------------------------------------------------------------
+// TextPool
+//------------------------------------------------------------------------
+
+class TextPool {
+public:
+
+ TextPool();
+ ~TextPool();
+
+ TextWord *getPool(int baseIdx) { return pool[baseIdx - minBaseIdx]; }
+ void setPool(int baseIdx, TextWord *p) { pool[baseIdx - minBaseIdx] = p; }
+
+ int getBaseIdx(double base);
+
+ void addWord(TextWord *word);
+
+private:
+
+ int minBaseIdx; // min baseline bucket index
+ int maxBaseIdx; // max baseline bucket index
+ TextWord **pool; // array of linked lists, one for each
+ // baseline value (multiple of 4 pts)
+ TextWord *cursor; // pointer to last-accessed word
+ int cursorBaseIdx; // baseline bucket index of last-accessed word
+
+ friend class TextBlock;
+ friend class TextPage;
+};
+
+//------------------------------------------------------------------------
+// TextLine
+//------------------------------------------------------------------------
+
+class TextLine {
+public:
+
+ TextLine(TextBlock *blkA, int rotA, double baseA);
+ ~TextLine();
+
+ void addWord(TextWord *word);
+
+ // Return the distance along the primary axis between <this> and
+ // <line>.
+ double primaryDelta(TextLine *line);
+
+ // Compares <this> to <line>, returning -1 (<), 0 (=), or +1 (>),
+ // based on a primary-axis comparison, e.g., x ordering if rot=0.
+ int primaryCmp(TextLine *line);
+
+ // Compares <this> to <line>, returning -1 (<), 0 (=), or +1 (>),
+ // based on a secondary-axis comparison of the baselines, e.g., y
+ // ordering if rot=0.
+ int secondaryCmp(TextLine *line);
+
+ int cmpYX(TextLine *line);
+
+ static int cmpXY(const void *p1, const void *p2);
+
+ void coalesce(UnicodeMap *uMap);
+
+ // Get the head of the linked list of TextWords.
+ TextWord *getWords() { return words; }
+
+ // Get the next TextLine on the linked list.
+ TextLine *getNext() { return next; }
+
+ // Returns true if the last char of the line is a hyphen.
+ GBool isHyphenated() { return hyphenated; }
+
+private:
+
+ TextBlock *blk; // parent block
+ int rot; // text rotation
+ double xMin, xMax; // bounding box x coordinates
+ double yMin, yMax; // bounding box y coordinates
+ double base; // baseline x or y coordinate
+ TextWord *words; // words in this line
+ TextWord *lastWord; // last word in this line
+ Unicode *text; // Unicode text of the line, including
+ // spaces between words
+ double *edge; // "near" edge x or y coord of each char
+ // (plus one extra entry for the last char)
+ int *col; // starting column number of each Unicode char
+ int len; // number of Unicode chars
+ int convertedLen; // total number of converted characters
+ GBool hyphenated; // set if last char is a hyphen
+ TextLine *next; // next line in block
+
+ friend class TextLineFrag;
+ friend class TextBlock;
+ friend class TextFlow;
+ friend class TextWordList;
+ friend class TextPage;
+};
+
+//------------------------------------------------------------------------
+// TextBlock
+//------------------------------------------------------------------------
+
+class TextBlock {
+public:
+
+ TextBlock(TextPage *pageA, int rotA);
+ ~TextBlock();
+
+ void addWord(TextWord *word);
+
+ void coalesce(UnicodeMap *uMap);
+
+ // Update this block's priMin and priMax values, looking at <blk>.
+ void updatePriMinMax(TextBlock *blk);
+
+ static int cmpXYPrimaryRot(const void *p1, const void *p2);
+
+ static int cmpYXPrimaryRot(const void *p1, const void *p2);
+
+ int primaryCmp(TextBlock *blk);
+
+ double secondaryDelta(TextBlock *blk);
+
+ // Returns true if <this> is below <blk>, relative to the page's
+ // primary rotation.
+ GBool isBelow(TextBlock *blk);
+
+ // Get the head of the linked list of TextLines.
+ TextLine *getLines() { return lines; }
+
+ // Get the next TextBlock on the linked list.
+ TextBlock *getNext() { return next; }
+
+private:
+
+ TextPage *page; // the parent page
+ int rot; // text rotation
+ double xMin, xMax; // bounding box x coordinates
+ double yMin, yMax; // bounding box y coordinates
+ double priMin, priMax; // whitespace bounding box along primary axis
+
+ TextPool *pool; // pool of words (used only until lines
+ // are built)
+ TextLine *lines; // linked list of lines
+ TextLine *curLine; // most recently added line
+ int nLines; // number of lines
+ int charCount; // number of characters in the block
+ int col; // starting column
+ int nColumns; // number of columns in the block
+
+ TextBlock *next;
+ TextBlock *stackNext;
+
+ friend class TextLine;
+ friend class TextLineFrag;
+ friend class TextFlow;
+ friend class TextWordList;
+ friend class TextPage;
+};
+
+//------------------------------------------------------------------------
+// TextFlow
+//------------------------------------------------------------------------
+
+class TextFlow {
+public:
+
+ TextFlow(TextPage *pageA, TextBlock *blk);
+ ~TextFlow();
+
+ // Add a block to the end of this flow.
+ void addBlock(TextBlock *blk);
+
+ // Returns true if <blk> fits below <prevBlk> in the flow, i.e., (1)
+ // it uses a font no larger than the last block added to the flow,
+ // and (2) it fits within the flow's [priMin, priMax] along the
+ // primary axis.
+ GBool blockFits(TextBlock *blk, TextBlock *prevBlk);
+
+ // Get the head of the linked list of TextBlocks.
+ TextBlock *getBlocks() { return blocks; }
+
+ // Get the next TextFlow on the linked list.
+ TextFlow *getNext() { return next; }
+
+private:
+
+ TextPage *page; // the parent page
+ double xMin, xMax; // bounding box x coordinates
+ double yMin, yMax; // bounding box y coordinates
+ double priMin, priMax; // whitespace bounding box along primary axis
+ TextBlock *blocks; // blocks in flow
+ TextBlock *lastBlk; // last block in this flow
+ TextFlow *next;
+
+ friend class TextWordList;
+ friend class TextPage;
+};
+
+#if TEXTOUT_WORD_LIST
+
+//------------------------------------------------------------------------
+// TextWordList
+//------------------------------------------------------------------------
+
+class TextWordList {
+public:
+
+ // Build a flat word list, in content stream order (if
+ // text->rawOrder is true), physical layout order (if <physLayout>
+ // is true and text->rawOrder is false), or reading order (if both
+ // flags are false).
+ TextWordList(TextPage *text, GBool physLayout);
+
+ ~TextWordList();
+
+ // Return the number of words on the list.
+ int getLength();
+
+ // Return the <idx>th word from the list.
+ TextWord *get(int idx);
+
+private:
+
+ GList *words; // [TextWord]
+};
+
+#endif // TEXTOUT_WORD_LIST
+
+//------------------------------------------------------------------------
+// TextPage
+//------------------------------------------------------------------------
+
+class TextPage {
+public:
+
+ // Constructor.
+ TextPage(GBool rawOrderA);
+
+ // Destructor.
+ ~TextPage();
+
+ // Start a new page.
+ void startPage(GfxState *state);
+
+ // End the current page.
+ void endPage();
+
+ // Update the current font.
+ void updateFont(GfxState *state);
+
+ // Begin a new word.
+ void beginWord(GfxState *state, double x0, double y0);
+
+ // Add a character to the current word.
+ void addChar(GfxState *state, double x, double y,
+ double dx, double dy,
+ CharCode c, int nBytes, Unicode *u, int uLen);
+
+ // End the current word, sorting it into the list of words.
+ void endWord();
+
+ // Add a word, sorting it into the list of words.
+ void addWord(TextWord *word);
+
+ // Add a (potential) underline.
+ void addUnderline(double x0, double y0, double x1, double y1);
+
+ // Add a hyperlink.
+ void addLink(int xMin, int yMin, int xMax, int yMax, Link *link);
+
+ // Coalesce strings that look like parts of the same line.
+ void coalesce(GBool physLayout, GBool doHTML);
+
+ // Find a string. If <startAtTop> is true, starts looking at the
+ // top of the page; else if <startAtLast> is true, starts looking
+ // immediately after the last find result; else starts looking at
+ // <xMin>,<yMin>. If <stopAtBottom> is true, stops looking at the
+ // bottom of the page; else if <stopAtLast> is true, stops looking
+ // just before the last find result; else stops looking at
+ // <xMax>,<yMax>.
+ GBool findText(Unicode *s, int len,
+ GBool startAtTop, GBool stopAtBottom,
+ GBool startAtLast, GBool stopAtLast,
+ GBool caseSensitive, GBool backward,
+ double *xMin, double *yMin,
+ double *xMax, double *yMax);
+
+ // Get the text which is inside the specified rectangle.
+ GString *getText(double xMin, double yMin,
+ double xMax, double yMax);
+
+ // Find a string by character position and length. If found, sets
+ // the text bounding rectangle and returns true; otherwise returns
+ // false.
+ GBool findCharRange(int pos, int length,
+ double *xMin, double *yMin,
+ double *xMax, double *yMax);
+
+ // Dump contents of page to a file.
+ void dump(void *outputStream, TextOutputFunc outputFunc,
+ GBool physLayout);
+
+ // Get the head of the linked list of TextFlows.
+ TextFlow *getFlows() { return flows; }
+
+#if TEXTOUT_WORD_LIST
+ // Build a flat word list, in content stream order (if
+ // this->rawOrder is true), physical layout order (if <physLayout>
+ // is true and this->rawOrder is false), or reading order (if both
+ // flags are false).
+ TextWordList *makeWordList(GBool physLayout);
+#endif
+
+private:
+
+ void clear();
+ void assignColumns(TextLineFrag *frags, int nFrags, int rot);
+ int dumpFragment(Unicode *text, int len, UnicodeMap *uMap, GString *s);
+
+ GBool rawOrder; // keep text in content stream order
+
+ double pageWidth, pageHeight; // width and height of current page
+ TextWord *curWord; // currently active string
+ int charPos; // next character position (within content
+ // stream)
+ TextFontInfo *curFont; // current font
+ double curFontSize; // current font size
+ int nest; // current nesting level (for Type 3 fonts)
+ int nTinyChars; // number of "tiny" chars seen so far
+ GBool lastCharOverlap; // set if the last added char overlapped the
+ // previous char
+
+ TextPool *pools[4]; // a "pool" of TextWords for each rotation
+ TextFlow *flows; // linked list of flows
+ TextBlock **blocks; // array of blocks, in yx order
+ int nBlocks; // number of blocks
+ int primaryRot; // primary rotation
+ GBool primaryLR; // primary direction (true means L-to-R,
+ // false means R-to-L)
+ TextWord *rawWords; // list of words, in raw order (only if
+ // rawOrder is set)
+ TextWord *rawLastWord; // last word on rawWords list
+
+ GList *fonts; // all font info objects used on this
+ // page [TextFontInfo]
+
+ double lastFindXMin, // coordinates of the last "find" result
+ lastFindYMin;
+ GBool haveLastFind;
+
+ GList *underlines; // [TextUnderline]
+ GList *links; // [TextLink]
+
+ friend class TextLine;
+ friend class TextLineFrag;
+ friend class TextBlock;
+ friend class TextFlow;
+ friend class TextWordList;
+};
+
+//------------------------------------------------------------------------
+// TextOutputDev
+//------------------------------------------------------------------------
+
+class TextOutputDev: public OutputDev {
+public:
+
+ // Open a text output file. If <fileName> is NULL, no file is
+ // written (this is useful, e.g., for searching text). If
+ // <physLayoutA> is true, the original physical layout of the text
+ // is maintained. If <rawOrder> is true, the text is kept in
+ // content stream order.
+ TextOutputDev(char *fileName, GBool physLayoutA,
+ GBool rawOrderA, GBool append);
+
+ // Create a TextOutputDev which will write to a generic stream. If
+ // <physLayoutA> is true, the original physical layout of the text
+ // is maintained. If <rawOrder> is true, the text is kept in
+ // content stream order.
+ TextOutputDev(TextOutputFunc func, void *stream,
+ GBool physLayoutA, GBool rawOrderA);
+
+ // Destructor.
+ virtual ~TextOutputDev();
+
+ // Check if file was successfully created.
+ virtual GBool isOk() { return ok; }
+
+ //---- get info about output device
+
+ // Does this device use upside-down coordinates?
+ // (Upside-down means (0,0) is the top left corner of the page.)
+ virtual GBool upsideDown() { return gTrue; }
+
+ // Does this device use drawChar() or drawString()?
+ virtual GBool useDrawChar() { return gTrue; }
+
+ // Does this device use beginType3Char/endType3Char? Otherwise,
+ // text in Type 3 fonts will be drawn with drawChar/drawString.
+ virtual GBool interpretType3Chars() { return gFalse; }
+
+ // Does this device need non-text content?
+ virtual GBool needNonText() { return gFalse; }
+
+ //----- initialization and control
+
+ // Start a page.
+ virtual void startPage(int pageNum, GfxState *state);
+
+ // End a page.
+ virtual void endPage();
+
+ //----- update text state
+ virtual void updateFont(GfxState *state);
+
+ //----- text drawing
+ virtual void beginString(GfxState *state, GString *s);
+ virtual void endString(GfxState *state);
+ virtual void drawChar(GfxState *state, double x, double y,
+ double dx, double dy,
+ double originX, double originY,
+ CharCode c, int nBytes, Unicode *u, int uLen);
+
+ //----- path painting
+ virtual void stroke(GfxState *state);
+ virtual void fill(GfxState *state);
+ virtual void eoFill(GfxState *state);
+
+ //----- link borders
+ virtual void processLink(Link *link, Catalog *catalog);
+
+ //----- special access
+
+ // Find a string. If <startAtTop> is true, starts looking at the
+ // top of the page; else if <startAtLast> is true, starts looking
+ // immediately after the last find result; else starts looking at
+ // <xMin>,<yMin>. If <stopAtBottom> is true, stops looking at the
+ // bottom of the page; else if <stopAtLast> is true, stops looking
+ // just before the last find result; else stops looking at
+ // <xMax>,<yMax>.
+ GBool findText(Unicode *s, int len,
+ GBool startAtTop, GBool stopAtBottom,
+ GBool startAtLast, GBool stopAtLast,
+ GBool caseSensitive, GBool backward,
+ double *xMin, double *yMin,
+ double *xMax, double *yMax);
+
+ // Get the text which is inside the specified rectangle.
+ GString *getText(double xMin, double yMin,
+ double xMax, double yMax);
+
+ // Find a string by character position and length. If found, sets
+ // the text bounding rectangle and returns true; otherwise returns
+ // false.
+ GBool findCharRange(int pos, int length,
+ double *xMin, double *yMin,
+ double *xMax, double *yMax);
+
+#if TEXTOUT_WORD_LIST
+ // Build a flat word list, in content stream order (if
+ // this->rawOrder is true), physical layout order (if
+ // this->physLayout is true and this->rawOrder is false), or reading
+ // order (if both flags are false).
+ TextWordList *makeWordList();
+#endif
+
+ // Returns the TextPage object for the last rasterized page,
+ // transferring ownership to the caller.
+ TextPage *takeText();
+
+ // Turn extra processing for HTML conversion on or off.
+ void enableHTMLExtras(GBool doHTMLA) { doHTML = doHTMLA; }
+
+private:
+
+ TextOutputFunc outputFunc; // output function
+ void *outputStream; // output stream
+ GBool needClose; // need to close the output file?
+ // (only if outputStream is a FILE*)
+ TextPage *text; // text for the current page
+ GBool physLayout; // maintain original physical layout when
+ // dumping text
+ GBool rawOrder; // keep text in content stream order
+ GBool doHTML; // extra processing for HTML conversion
+ GBool ok; // set up ok?
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/UTF8.h b/kpdf/xpdf/xpdf/UTF8.h
new file mode 100644
index 00000000..8536dbf9
--- /dev/null
+++ b/kpdf/xpdf/xpdf/UTF8.h
@@ -0,0 +1,56 @@
+//========================================================================
+//
+// UTF8.h
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+static int mapUTF8(Unicode u, char *buf, int bufSize) {
+ if (u <= 0x0000007f) {
+ if (bufSize < 1) {
+ return 0;
+ }
+ buf[0] = (char)u;
+ return 1;
+ } else if (u <= 0x000007ff) {
+ if (bufSize < 2) {
+ return 0;
+ }
+ buf[0] = (char)(0xc0 + (u >> 6));
+ buf[1] = (char)(0x80 + (u & 0x3f));
+ return 2;
+ } else if (u <= 0x0000ffff) {
+ if (bufSize < 3) {
+ return 0;
+ }
+ buf[0] = (char)(0xe0 + (u >> 12));
+ buf[1] = (char)(0x80 + ((u >> 6) & 0x3f));
+ buf[2] = (char)(0x80 + (u & 0x3f));
+ return 3;
+ } else if (u <= 0x0010ffff) {
+ if (bufSize < 4) {
+ return 0;
+ }
+ buf[0] = (char)(0xf0 + (u >> 18));
+ buf[1] = (char)(0x80 + ((u >> 12) & 0x3f));
+ buf[2] = (char)(0x80 + ((u >> 6) & 0x3f));
+ buf[3] = (char)(0x80 + (u & 0x3f));
+ return 4;
+ } else {
+ return 0;
+ }
+}
+
+static int mapUCS2(Unicode u, char *buf, int bufSize) {
+ if (u <= 0xffff) {
+ if (bufSize < 2) {
+ return 0;
+ }
+ buf[0] = (char)((u >> 8) & 0xff);
+ buf[1] = (char)(u & 0xff);
+ return 2;
+ } else {
+ return 0;
+ }
+}
diff --git a/kpdf/xpdf/xpdf/UnicodeMap.cc b/kpdf/xpdf/xpdf/UnicodeMap.cc
new file mode 100644
index 00000000..2b8cb1f7
--- /dev/null
+++ b/kpdf/xpdf/xpdf/UnicodeMap.cc
@@ -0,0 +1,293 @@
+//========================================================================
+//
+// UnicodeMap.cc
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include "gmem.h"
+#include "gfile.h"
+#include "GString.h"
+#include "GList.h"
+#include "Error.h"
+#include "GlobalParams.h"
+#include "UnicodeMap.h"
+
+//------------------------------------------------------------------------
+
+#define maxExtCode 16
+
+struct UnicodeMapExt {
+ Unicode u; // Unicode char
+ char code[maxExtCode];
+ Guint nBytes;
+};
+
+//------------------------------------------------------------------------
+
+UnicodeMap *UnicodeMap::parse(GString *encodingNameA) {
+ FILE *f;
+ UnicodeMap *map;
+ UnicodeMapRange *range;
+ UnicodeMapExt *eMap;
+ int size, eMapsSize;
+ char buf[256];
+ int line, nBytes, i, x;
+ char *tok1, *tok2, *tok3;
+
+ if (!(f = globalParams->getUnicodeMapFile(encodingNameA))) {
+ error(-1, "Couldn't find unicodeMap file for the '%s' encoding",
+ encodingNameA->getCString());
+ return NULL;
+ }
+
+ map = new UnicodeMap(encodingNameA->copy());
+
+ size = 8;
+ map->ranges = (UnicodeMapRange *)gmallocn(size, sizeof(UnicodeMapRange));
+ eMapsSize = 0;
+
+ line = 1;
+ while (getLine(buf, sizeof(buf), f)) {
+ if ((tok1 = strtok(buf, " \t\r\n")) &&
+ (tok2 = strtok(NULL, " \t\r\n"))) {
+ if (!(tok3 = strtok(NULL, " \t\r\n"))) {
+ tok3 = tok2;
+ tok2 = tok1;
+ }
+ nBytes = strlen(tok3) / 2;
+ if (nBytes <= 4) {
+ if (map->len == size) {
+ size *= 2;
+ map->ranges = (UnicodeMapRange *)
+ greallocn(map->ranges, size, sizeof(UnicodeMapRange));
+ }
+ range = &map->ranges[map->len];
+ sscanf(tok1, "%x", &range->start);
+ sscanf(tok2, "%x", &range->end);
+ sscanf(tok3, "%x", &range->code);
+ range->nBytes = nBytes;
+ ++map->len;
+ } else if (tok2 == tok1) {
+ if (map->eMapsLen == eMapsSize) {
+ eMapsSize += 16;
+ map->eMaps = (UnicodeMapExt *)
+ greallocn(map->eMaps, eMapsSize, sizeof(UnicodeMapExt));
+ }
+ eMap = &map->eMaps[map->eMapsLen];
+ sscanf(tok1, "%x", &eMap->u);
+ for (i = 0; i < nBytes; ++i) {
+ sscanf(tok3 + i*2, "%2x", &x);
+ eMap->code[i] = (char)x;
+ }
+ eMap->nBytes = nBytes;
+ ++map->eMapsLen;
+ } else {
+ error(-1, "Bad line (%d) in unicodeMap file for the '%s' encoding",
+ line, encodingNameA->getCString());
+ }
+ } else {
+ error(-1, "Bad line (%d) in unicodeMap file for the '%s' encoding",
+ line, encodingNameA->getCString());
+ }
+ ++line;
+ }
+
+ fclose(f);
+
+ return map;
+}
+
+UnicodeMap::UnicodeMap(GString *encodingNameA) {
+ encodingName = encodingNameA;
+ unicodeOut = gFalse;
+ kind = unicodeMapUser;
+ ranges = NULL;
+ len = 0;
+ eMaps = NULL;
+ eMapsLen = 0;
+ refCnt = 1;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+}
+
+UnicodeMap::UnicodeMap(char *encodingNameA, GBool unicodeOutA,
+ UnicodeMapRange *rangesA, int lenA) {
+ encodingName = new GString(encodingNameA);
+ unicodeOut = unicodeOutA;
+ kind = unicodeMapResident;
+ ranges = rangesA;
+ len = lenA;
+ eMaps = NULL;
+ eMapsLen = 0;
+ refCnt = 1;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+}
+
+UnicodeMap::UnicodeMap(char *encodingNameA, GBool unicodeOutA,
+ UnicodeMapFunc funcA) {
+ encodingName = new GString(encodingNameA);
+ unicodeOut = unicodeOutA;
+ kind = unicodeMapFunc;
+ func = funcA;
+ eMaps = NULL;
+ eMapsLen = 0;
+ refCnt = 1;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
+}
+
+UnicodeMap::~UnicodeMap() {
+ delete encodingName;
+ if (kind == unicodeMapUser && ranges) {
+ gfree(ranges);
+ }
+ if (eMaps) {
+ gfree(eMaps);
+ }
+#if MULTITHREADED
+ gDestroyMutex(&mutex);
+#endif
+}
+
+void UnicodeMap::incRefCnt() {
+#if MULTITHREADED
+ gLockMutex(&mutex);
+#endif
+ ++refCnt;
+#if MULTITHREADED
+ gUnlockMutex(&mutex);
+#endif
+}
+
+void UnicodeMap::decRefCnt() {
+ GBool done;
+
+#if MULTITHREADED
+ gLockMutex(&mutex);
+#endif
+ done = --refCnt == 0;
+#if MULTITHREADED
+ gUnlockMutex(&mutex);
+#endif
+ if (done) {
+ delete this;
+ }
+}
+
+GBool UnicodeMap::match(GString *encodingNameA) {
+ return !encodingName->cmp(encodingNameA);
+}
+
+int UnicodeMap::mapUnicode(Unicode u, char *buf, int bufSize) {
+ int a, b, m, n, i, j;
+ Guint code;
+
+ if (kind == unicodeMapFunc) {
+ return (*func)(u, buf, bufSize);
+ }
+
+ a = 0;
+ b = len;
+ if (u >= ranges[a].start) {
+ // invariant: ranges[a].start <= u < ranges[b].start
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ if (u >= ranges[m].start) {
+ a = m;
+ } else if (u < ranges[m].start) {
+ b = m;
+ }
+ }
+ if (u <= ranges[a].end) {
+ n = ranges[a].nBytes;
+ if (n > bufSize) {
+ return 0;
+ }
+ code = ranges[a].code + (u - ranges[a].start);
+ for (i = n - 1; i >= 0; --i) {
+ buf[i] = (char)(code & 0xff);
+ code >>= 8;
+ }
+ return n;
+ }
+ }
+
+ for (i = 0; i < eMapsLen; ++i) {
+ if (eMaps[i].u == u) {
+ n = eMaps[i].nBytes;
+ for (j = 0; j < n; ++j) {
+ buf[j] = eMaps[i].code[j];
+ }
+ return n;
+ }
+ }
+
+ return 0;
+}
+
+//------------------------------------------------------------------------
+
+UnicodeMapCache::UnicodeMapCache() {
+ int i;
+
+ for (i = 0; i < unicodeMapCacheSize; ++i) {
+ cache[i] = NULL;
+ }
+}
+
+UnicodeMapCache::~UnicodeMapCache() {
+ int i;
+
+ for (i = 0; i < unicodeMapCacheSize; ++i) {
+ if (cache[i]) {
+ cache[i]->decRefCnt();
+ }
+ }
+}
+
+UnicodeMap *UnicodeMapCache::getUnicodeMap(GString *encodingName) {
+ UnicodeMap *map;
+ int i, j;
+
+ if (cache[0] && cache[0]->match(encodingName)) {
+ cache[0]->incRefCnt();
+ return cache[0];
+ }
+ for (i = 1; i < unicodeMapCacheSize; ++i) {
+ if (cache[i] && cache[i]->match(encodingName)) {
+ map = cache[i];
+ for (j = i; j >= 1; --j) {
+ cache[j] = cache[j - 1];
+ }
+ cache[0] = map;
+ map->incRefCnt();
+ return map;
+ }
+ }
+ if ((map = UnicodeMap::parse(encodingName))) {
+ if (cache[unicodeMapCacheSize - 1]) {
+ cache[unicodeMapCacheSize - 1]->decRefCnt();
+ }
+ for (j = unicodeMapCacheSize - 1; j >= 1; --j) {
+ cache[j] = cache[j - 1];
+ }
+ cache[0] = map;
+ map->incRefCnt();
+ return map;
+ }
+ return NULL;
+}
diff --git a/kpdf/xpdf/xpdf/UnicodeMap.h b/kpdf/xpdf/xpdf/UnicodeMap.h
new file mode 100644
index 00000000..0f86101e
--- /dev/null
+++ b/kpdf/xpdf/xpdf/UnicodeMap.h
@@ -0,0 +1,123 @@
+//========================================================================
+//
+// UnicodeMap.h
+//
+// Mapping from Unicode to an encoding.
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef UNICODEMAP_H
+#define UNICODEMAP_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "CharTypes.h"
+
+#if MULTITHREADED
+#include "GMutex.h"
+#endif
+
+class GString;
+
+//------------------------------------------------------------------------
+
+enum UnicodeMapKind {
+ unicodeMapUser, // read from a file
+ unicodeMapResident, // static list of ranges
+ unicodeMapFunc // function pointer
+};
+
+typedef int (*UnicodeMapFunc)(Unicode u, char *buf, int bufSize);
+
+struct UnicodeMapRange {
+ Unicode start, end; // range of Unicode chars
+ Guint code, nBytes; // first output code
+};
+
+struct UnicodeMapExt;
+
+//------------------------------------------------------------------------
+
+class UnicodeMap {
+public:
+
+ // Create the UnicodeMap specified by <encodingName>. Sets the
+ // initial reference count to 1. Returns NULL on failure.
+ static UnicodeMap *parse(GString *encodingNameA);
+
+ // Create a resident UnicodeMap.
+ UnicodeMap(char *encodingNameA, GBool unicodeOutA,
+ UnicodeMapRange *rangesA, int lenA);
+
+ // Create a resident UnicodeMap that uses a function instead of a
+ // list of ranges.
+ UnicodeMap(char *encodingNameA, GBool unicodeOutA,
+ UnicodeMapFunc funcA);
+
+ ~UnicodeMap();
+
+ void incRefCnt();
+ void decRefCnt();
+
+ GString *getEncodingName() { return encodingName; }
+
+ GBool isUnicode() { return unicodeOut; }
+
+ // Return true if this UnicodeMap matches the specified
+ // <encodingNameA>.
+ GBool match(GString *encodingNameA);
+
+ // Map Unicode to the target encoding. Fills in <buf> with the
+ // output and returns the number of bytes used. Output will be
+ // truncated at <bufSize> bytes. No string terminator is written.
+ // Returns 0 if no mapping is found.
+ int mapUnicode(Unicode u, char *buf, int bufSize);
+
+private:
+
+ UnicodeMap(GString *encodingNameA);
+
+ GString *encodingName;
+ UnicodeMapKind kind;
+ GBool unicodeOut;
+ union {
+ UnicodeMapRange *ranges; // (user, resident)
+ UnicodeMapFunc func; // (func)
+ };
+ int len; // (user, resident)
+ UnicodeMapExt *eMaps; // (user)
+ int eMapsLen; // (user)
+ int refCnt;
+#if MULTITHREADED
+ GMutex mutex;
+#endif
+};
+
+//------------------------------------------------------------------------
+
+#define unicodeMapCacheSize 4
+
+class UnicodeMapCache {
+public:
+
+ UnicodeMapCache();
+ ~UnicodeMapCache();
+
+ // Get the UnicodeMap for <encodingName>. Increments its reference
+ // count; there will be one reference for the cache plus one for the
+ // caller of this function. Returns NULL on failure.
+ UnicodeMap *getUnicodeMap(GString *encodingName);
+
+private:
+
+ UnicodeMap *cache[unicodeMapCacheSize];
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/UnicodeMapTables.h b/kpdf/xpdf/xpdf/UnicodeMapTables.h
new file mode 100644
index 00000000..9c510346
--- /dev/null
+++ b/kpdf/xpdf/xpdf/UnicodeMapTables.h
@@ -0,0 +1,361 @@
+//========================================================================
+//
+// UnicodeMapTables.h
+//
+// Copyright 2001-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+static UnicodeMapRange latin1UnicodeMapRanges[] = {
+ { 0x000a, 0x000a, 0x0a, 1 },
+ { 0x000c, 0x000d, 0x0c, 1 },
+ { 0x0020, 0x007e, 0x20, 1 },
+ { 0x00a0, 0x00a0, 0x20, 1 },
+ { 0x00a1, 0x00ac, 0xa1, 1 },
+ { 0x00ae, 0x00ff, 0xae, 1 },
+ { 0x010c, 0x010c, 0x43, 1 },
+ { 0x010d, 0x010d, 0x63, 1 },
+ { 0x0131, 0x0131, 0x69, 1 },
+ { 0x0141, 0x0141, 0x4c, 1 },
+ { 0x0142, 0x0142, 0x6c, 1 },
+ { 0x0152, 0x0152, 0x4f45, 2 },
+ { 0x0153, 0x0153, 0x6f65, 2 },
+ { 0x0160, 0x0160, 0x53, 1 },
+ { 0x0161, 0x0161, 0x73, 1 },
+ { 0x0178, 0x0178, 0x59, 1 },
+ { 0x017d, 0x017d, 0x5a, 1 },
+ { 0x017e, 0x017e, 0x7a, 1 },
+ { 0x02c6, 0x02c6, 0x5e, 1 },
+ { 0x02da, 0x02da, 0xb0, 1 },
+ { 0x02dc, 0x02dc, 0x7e, 1 },
+ { 0x2013, 0x2013, 0xad, 1 },
+ { 0x2014, 0x2014, 0x2d2d, 2 },
+ { 0x2018, 0x2018, 0x60, 1 },
+ { 0x2019, 0x2019, 0x27, 1 },
+ { 0x201a, 0x201a, 0x2c, 1 },
+ { 0x201c, 0x201c, 0x22, 1 },
+ { 0x201d, 0x201d, 0x22, 1 },
+ { 0x201e, 0x201e, 0x2c2c, 2 },
+ { 0x2022, 0x2022, 0xb7, 1 },
+ { 0x2026, 0x2026, 0x2e2e2e, 3 },
+ { 0x2039, 0x2039, 0x3c, 1 },
+ { 0x203a, 0x203a, 0x3e, 1 },
+ { 0x2044, 0x2044, 0x2f, 1 },
+ { 0x2122, 0x2122, 0x544d, 2 },
+ { 0x2212, 0x2212, 0x2d, 1 },
+ { 0xf6f9, 0xf6f9, 0x4c, 1 },
+ { 0xf6fa, 0xf6fa, 0x4f45, 2 },
+ { 0xf6fc, 0xf6fc, 0xb0, 1 },
+ { 0xf6fd, 0xf6fd, 0x53, 1 },
+ { 0xf6fe, 0xf6fe, 0x7e, 1 },
+ { 0xf6ff, 0xf6ff, 0x5a, 1 },
+ { 0xf721, 0xf721, 0x21, 1 },
+ { 0xf724, 0xf724, 0x24, 1 },
+ { 0xf726, 0xf726, 0x26, 1 },
+ { 0xf730, 0xf739, 0x30, 1 },
+ { 0xf73f, 0xf73f, 0x3f, 1 },
+ { 0xf761, 0xf77a, 0x41, 1 },
+ { 0xf7a1, 0xf7a2, 0xa1, 1 },
+ { 0xf7bf, 0xf7bf, 0xbf, 1 },
+ { 0xf7e0, 0xf7f6, 0xc0, 1 },
+ { 0xf7f8, 0xf7fe, 0xd8, 1 },
+ { 0xf7ff, 0xf7ff, 0x59, 1 },
+ { 0xfb00, 0xfb00, 0x6666, 2 },
+ { 0xfb01, 0xfb01, 0x6669, 2 },
+ { 0xfb02, 0xfb02, 0x666c, 2 },
+ { 0xfb03, 0xfb03, 0x666669, 3 },
+ { 0xfb04, 0xfb04, 0x66666c, 3 }
+};
+#define latin1UnicodeMapLen (sizeof(latin1UnicodeMapRanges) / sizeof(UnicodeMapRange))
+
+static UnicodeMapRange ascii7UnicodeMapRanges[] = {
+ { 0x000a, 0x000a, 0x0a, 1 },
+ { 0x000c, 0x000d, 0x0c, 1 },
+ { 0x0020, 0x005f, 0x20, 1 },
+ { 0x0061, 0x007e, 0x61, 1 },
+ { 0x00a6, 0x00a6, 0x7c, 1 },
+ { 0x00a9, 0x00a9, 0x286329, 3 },
+ { 0x00ae, 0x00ae, 0x285229, 3 },
+ { 0x00b7, 0x00b7, 0x2a, 1 },
+ { 0x00bc, 0x00bc, 0x312f34, 3 },
+ { 0x00bd, 0x00bd, 0x312f32, 3 },
+ { 0x00be, 0x00be, 0x332f34, 3 },
+ { 0x00c0, 0x00c0, 0x41, 1 },
+ { 0x00c1, 0x00c1, 0x41, 1 },
+ { 0x00c2, 0x00c2, 0x41, 1 },
+ { 0x00c3, 0x00c3, 0x41, 1 },
+ { 0x00c4, 0x00c4, 0x41, 1 },
+ { 0x00c5, 0x00c5, 0x41, 1 },
+ { 0x00c6, 0x00c6, 0x4145, 2 },
+ { 0x00c7, 0x00c7, 0x43, 1 },
+ { 0x00c8, 0x00c8, 0x45, 1 },
+ { 0x00c9, 0x00c9, 0x45, 1 },
+ { 0x00ca, 0x00ca, 0x45, 1 },
+ { 0x00cb, 0x00cb, 0x45, 1 },
+ { 0x00cc, 0x00cc, 0x49, 1 },
+ { 0x00cd, 0x00cd, 0x49, 1 },
+ { 0x00ce, 0x00ce, 0x49, 1 },
+ { 0x00cf, 0x00cf, 0x49, 1 },
+ { 0x00d1, 0x00d2, 0x4e, 1 },
+ { 0x00d3, 0x00d3, 0x4f, 1 },
+ { 0x00d4, 0x00d4, 0x4f, 1 },
+ { 0x00d5, 0x00d5, 0x4f, 1 },
+ { 0x00d6, 0x00d6, 0x4f, 1 },
+ { 0x00d7, 0x00d7, 0x78, 1 },
+ { 0x00d8, 0x00d8, 0x4f, 1 },
+ { 0x00d9, 0x00d9, 0x55, 1 },
+ { 0x00da, 0x00da, 0x55, 1 },
+ { 0x00db, 0x00db, 0x55, 1 },
+ { 0x00dc, 0x00dc, 0x55, 1 },
+ { 0x00dd, 0x00dd, 0x59, 1 },
+ { 0x00e0, 0x00e0, 0x61, 1 },
+ { 0x00e1, 0x00e1, 0x61, 1 },
+ { 0x00e2, 0x00e2, 0x61, 1 },
+ { 0x00e3, 0x00e3, 0x61, 1 },
+ { 0x00e4, 0x00e4, 0x61, 1 },
+ { 0x00e5, 0x00e5, 0x61, 1 },
+ { 0x00e6, 0x00e6, 0x6165, 2 },
+ { 0x00e7, 0x00e7, 0x63, 1 },
+ { 0x00e8, 0x00e8, 0x65, 1 },
+ { 0x00e9, 0x00e9, 0x65, 1 },
+ { 0x00ea, 0x00ea, 0x65, 1 },
+ { 0x00eb, 0x00eb, 0x65, 1 },
+ { 0x00ec, 0x00ec, 0x69, 1 },
+ { 0x00ed, 0x00ed, 0x69, 1 },
+ { 0x00ee, 0x00ee, 0x69, 1 },
+ { 0x00ef, 0x00ef, 0x69, 1 },
+ { 0x00f1, 0x00f2, 0x6e, 1 },
+ { 0x00f3, 0x00f3, 0x6f, 1 },
+ { 0x00f4, 0x00f4, 0x6f, 1 },
+ { 0x00f5, 0x00f5, 0x6f, 1 },
+ { 0x00f6, 0x00f6, 0x6f, 1 },
+ { 0x00f7, 0x00f7, 0x2f, 1 },
+ { 0x00f8, 0x00f8, 0x6f, 1 },
+ { 0x00f9, 0x00f9, 0x75, 1 },
+ { 0x00fa, 0x00fa, 0x75, 1 },
+ { 0x00fb, 0x00fb, 0x75, 1 },
+ { 0x00fc, 0x00fc, 0x75, 1 },
+ { 0x00fd, 0x00fd, 0x79, 1 },
+ { 0x00ff, 0x00ff, 0x79, 1 },
+ { 0x0131, 0x0131, 0x69, 1 },
+ { 0x0141, 0x0141, 0x4c, 1 },
+ { 0x0152, 0x0152, 0x4f45, 2 },
+ { 0x0153, 0x0153, 0x6f65, 2 },
+ { 0x0160, 0x0160, 0x53, 1 },
+ { 0x0178, 0x0178, 0x59, 1 },
+ { 0x017d, 0x017d, 0x5a, 1 },
+ { 0x2013, 0x2013, 0x2d, 1 },
+ { 0x2014, 0x2014, 0x2d2d, 2 },
+ { 0x2018, 0x2018, 0x60, 1 },
+ { 0x2019, 0x2019, 0x27, 1 },
+ { 0x201c, 0x201c, 0x22, 1 },
+ { 0x201d, 0x201d, 0x22, 1 },
+ { 0x2022, 0x2022, 0x2a, 1 },
+ { 0x2026, 0x2026, 0x2e2e2e, 3 },
+ { 0x2122, 0x2122, 0x544d, 2 },
+ { 0x2212, 0x2212, 0x2d, 1 },
+ { 0xf6f9, 0xf6f9, 0x4c, 1 },
+ { 0xf6fa, 0xf6fa, 0x4f45, 2 },
+ { 0xf6fd, 0xf6fd, 0x53, 1 },
+ { 0xf6fe, 0xf6fe, 0x7e, 1 },
+ { 0xf6ff, 0xf6ff, 0x5a, 1 },
+ { 0xf721, 0xf721, 0x21, 1 },
+ { 0xf724, 0xf724, 0x24, 1 },
+ { 0xf726, 0xf726, 0x26, 1 },
+ { 0xf730, 0xf739, 0x30, 1 },
+ { 0xf73f, 0xf73f, 0x3f, 1 },
+ { 0xf761, 0xf77a, 0x41, 1 },
+ { 0xf7e0, 0xf7e0, 0x41, 1 },
+ { 0xf7e1, 0xf7e1, 0x41, 1 },
+ { 0xf7e2, 0xf7e2, 0x41, 1 },
+ { 0xf7e3, 0xf7e3, 0x41, 1 },
+ { 0xf7e4, 0xf7e4, 0x41, 1 },
+ { 0xf7e5, 0xf7e5, 0x41, 1 },
+ { 0xf7e6, 0xf7e6, 0x4145, 2 },
+ { 0xf7e7, 0xf7e7, 0x43, 1 },
+ { 0xf7e8, 0xf7e8, 0x45, 1 },
+ { 0xf7e9, 0xf7e9, 0x45, 1 },
+ { 0xf7ea, 0xf7ea, 0x45, 1 },
+ { 0xf7eb, 0xf7eb, 0x45, 1 },
+ { 0xf7ec, 0xf7ec, 0x49, 1 },
+ { 0xf7ed, 0xf7ed, 0x49, 1 },
+ { 0xf7ee, 0xf7ee, 0x49, 1 },
+ { 0xf7ef, 0xf7ef, 0x49, 1 },
+ { 0xf7f1, 0xf7f2, 0x4e, 1 },
+ { 0xf7f3, 0xf7f3, 0x4f, 1 },
+ { 0xf7f4, 0xf7f4, 0x4f, 1 },
+ { 0xf7f5, 0xf7f5, 0x4f, 1 },
+ { 0xf7f6, 0xf7f6, 0x4f, 1 },
+ { 0xf7f8, 0xf7f8, 0x4f, 1 },
+ { 0xf7f9, 0xf7f9, 0x55, 1 },
+ { 0xf7fa, 0xf7fa, 0x55, 1 },
+ { 0xf7fb, 0xf7fb, 0x55, 1 },
+ { 0xf7fc, 0xf7fc, 0x55, 1 },
+ { 0xf7fd, 0xf7fd, 0x59, 1 },
+ { 0xf7ff, 0xf7ff, 0x59, 1 },
+ { 0xfb00, 0xfb00, 0x6666, 2 },
+ { 0xfb01, 0xfb01, 0x6669, 2 },
+ { 0xfb02, 0xfb02, 0x666c, 2 },
+ { 0xfb03, 0xfb03, 0x666669, 3 },
+ { 0xfb04, 0xfb04, 0x66666c, 3 }
+};
+#define ascii7UnicodeMapLen (sizeof(ascii7UnicodeMapRanges) / sizeof(UnicodeMapRange))
+
+static UnicodeMapRange symbolUnicodeMapRanges[] = {
+ { 0x0020, 0x0021, 0x20, 1 },
+ { 0x0023, 0x0023, 0x23, 1 },
+ { 0x0025, 0x0026, 0x25, 1 },
+ { 0x0028, 0x0029, 0x28, 1 },
+ { 0x002b, 0x002c, 0x2b, 1 },
+ { 0x002e, 0x003f, 0x2e, 1 },
+ { 0x005b, 0x005b, 0x5b, 1 },
+ { 0x005d, 0x005d, 0x5d, 1 },
+ { 0x005f, 0x005f, 0x5f, 1 },
+ { 0x007b, 0x007d, 0x7b, 1 },
+ { 0x00ac, 0x00ac, 0xd8, 1 },
+ { 0x00b0, 0x00b1, 0xb0, 1 },
+ { 0x00b5, 0x00b5, 0x6d, 1 },
+ { 0x00d7, 0x00d7, 0xb4, 1 },
+ { 0x00f7, 0x00f7, 0xb8, 1 },
+ { 0x0192, 0x0192, 0xa6, 1 },
+ { 0x0391, 0x0392, 0x41, 1 },
+ { 0x0393, 0x0393, 0x47, 1 },
+ { 0x0395, 0x0395, 0x45, 1 },
+ { 0x0396, 0x0396, 0x5a, 1 },
+ { 0x0397, 0x0397, 0x48, 1 },
+ { 0x0398, 0x0398, 0x51, 1 },
+ { 0x0399, 0x0399, 0x49, 1 },
+ { 0x039a, 0x039d, 0x4b, 1 },
+ { 0x039e, 0x039e, 0x58, 1 },
+ { 0x039f, 0x03a0, 0x4f, 1 },
+ { 0x03a1, 0x03a1, 0x52, 1 },
+ { 0x03a3, 0x03a5, 0x53, 1 },
+ { 0x03a6, 0x03a6, 0x46, 1 },
+ { 0x03a7, 0x03a7, 0x43, 1 },
+ { 0x03a8, 0x03a8, 0x59, 1 },
+ { 0x03b1, 0x03b2, 0x61, 1 },
+ { 0x03b3, 0x03b3, 0x67, 1 },
+ { 0x03b4, 0x03b5, 0x64, 1 },
+ { 0x03b6, 0x03b6, 0x7a, 1 },
+ { 0x03b7, 0x03b7, 0x68, 1 },
+ { 0x03b8, 0x03b8, 0x71, 1 },
+ { 0x03b9, 0x03b9, 0x69, 1 },
+ { 0x03ba, 0x03bb, 0x6b, 1 },
+ { 0x03bd, 0x03bd, 0x6e, 1 },
+ { 0x03be, 0x03be, 0x78, 1 },
+ { 0x03bf, 0x03c0, 0x6f, 1 },
+ { 0x03c1, 0x03c1, 0x72, 1 },
+ { 0x03c2, 0x03c2, 0x56, 1 },
+ { 0x03c3, 0x03c5, 0x73, 1 },
+ { 0x03c6, 0x03c6, 0x66, 1 },
+ { 0x03c7, 0x03c7, 0x63, 1 },
+ { 0x03c8, 0x03c8, 0x79, 1 },
+ { 0x03c9, 0x03c9, 0x77, 1 },
+ { 0x03d1, 0x03d1, 0x4a, 1 },
+ { 0x03d2, 0x03d2, 0xa1, 1 },
+ { 0x03d5, 0x03d5, 0x6a, 1 },
+ { 0x03d6, 0x03d6, 0x76, 1 },
+ { 0x2022, 0x2022, 0xb7, 1 },
+ { 0x2026, 0x2026, 0xbc, 1 },
+ { 0x2032, 0x2032, 0xa2, 1 },
+ { 0x2033, 0x2033, 0xb2, 1 },
+ { 0x2044, 0x2044, 0xa4, 1 },
+ { 0x2111, 0x2111, 0xc1, 1 },
+ { 0x2118, 0x2118, 0xc3, 1 },
+ { 0x211c, 0x211c, 0xc2, 1 },
+ { 0x2126, 0x2126, 0x57, 1 },
+ { 0x2135, 0x2135, 0xc0, 1 },
+ { 0x2190, 0x2193, 0xac, 1 },
+ { 0x2194, 0x2194, 0xab, 1 },
+ { 0x21b5, 0x21b5, 0xbf, 1 },
+ { 0x21d0, 0x21d3, 0xdc, 1 },
+ { 0x21d4, 0x21d4, 0xdb, 1 },
+ { 0x2200, 0x2200, 0x22, 1 },
+ { 0x2202, 0x2202, 0xb6, 1 },
+ { 0x2203, 0x2203, 0x24, 1 },
+ { 0x2205, 0x2205, 0xc6, 1 },
+ { 0x2206, 0x2206, 0x44, 1 },
+ { 0x2207, 0x2207, 0xd1, 1 },
+ { 0x2208, 0x2209, 0xce, 1 },
+ { 0x220b, 0x220b, 0x27, 1 },
+ { 0x220f, 0x220f, 0xd5, 1 },
+ { 0x2211, 0x2211, 0xe5, 1 },
+ { 0x2212, 0x2212, 0x2d, 1 },
+ { 0x2217, 0x2217, 0x2a, 1 },
+ { 0x221a, 0x221a, 0xd6, 1 },
+ { 0x221d, 0x221d, 0xb5, 1 },
+ { 0x221e, 0x221e, 0xa5, 1 },
+ { 0x2220, 0x2220, 0xd0, 1 },
+ { 0x2227, 0x2228, 0xd9, 1 },
+ { 0x2229, 0x222a, 0xc7, 1 },
+ { 0x222b, 0x222b, 0xf2, 1 },
+ { 0x2234, 0x2234, 0x5c, 1 },
+ { 0x223c, 0x223c, 0x7e, 1 },
+ { 0x2245, 0x2245, 0x40, 1 },
+ { 0x2248, 0x2248, 0xbb, 1 },
+ { 0x2260, 0x2261, 0xb9, 1 },
+ { 0x2264, 0x2264, 0xa3, 1 },
+ { 0x2265, 0x2265, 0xb3, 1 },
+ { 0x2282, 0x2282, 0xcc, 1 },
+ { 0x2283, 0x2283, 0xc9, 1 },
+ { 0x2284, 0x2284, 0xcb, 1 },
+ { 0x2286, 0x2286, 0xcd, 1 },
+ { 0x2287, 0x2287, 0xca, 1 },
+ { 0x2295, 0x2295, 0xc5, 1 },
+ { 0x2297, 0x2297, 0xc4, 1 },
+ { 0x22a5, 0x22a5, 0x5e, 1 },
+ { 0x22c5, 0x22c5, 0xd7, 1 },
+ { 0x2320, 0x2320, 0xf3, 1 },
+ { 0x2321, 0x2321, 0xf5, 1 },
+ { 0x2329, 0x2329, 0xe1, 1 },
+ { 0x232a, 0x232a, 0xf1, 1 },
+ { 0x25ca, 0x25ca, 0xe0, 1 },
+ { 0x2660, 0x2660, 0xaa, 1 },
+ { 0x2663, 0x2663, 0xa7, 1 },
+ { 0x2665, 0x2665, 0xa9, 1 },
+ { 0x2666, 0x2666, 0xa8, 1 },
+ { 0xf6d9, 0xf6d9, 0xd3, 1 },
+ { 0xf6da, 0xf6da, 0xd2, 1 },
+ { 0xf6db, 0xf6db, 0xd4, 1 },
+ { 0xf8e5, 0xf8e5, 0x60, 1 },
+ { 0xf8e6, 0xf8e7, 0xbd, 1 },
+ { 0xf8e8, 0xf8ea, 0xe2, 1 },
+ { 0xf8eb, 0xf8f4, 0xe6, 1 },
+ { 0xf8f5, 0xf8f5, 0xf4, 1 },
+ { 0xf8f6, 0xf8fe, 0xf6, 1 }
+};
+#define symbolUnicodeMapLen (sizeof(symbolUnicodeMapRanges) / sizeof(UnicodeMapRange))
+
+static UnicodeMapRange zapfDingbatsUnicodeMapRanges[] = {
+ { 0x0020, 0x0020, 0x20, 1 },
+ { 0x2192, 0x2192, 0xd5, 1 },
+ { 0x2194, 0x2195, 0xd6, 1 },
+ { 0x2460, 0x2469, 0xac, 1 },
+ { 0x25a0, 0x25a0, 0x6e, 1 },
+ { 0x25b2, 0x25b2, 0x73, 1 },
+ { 0x25bc, 0x25bc, 0x74, 1 },
+ { 0x25c6, 0x25c6, 0x75, 1 },
+ { 0x25cf, 0x25cf, 0x6c, 1 },
+ { 0x25d7, 0x25d7, 0x77, 1 },
+ { 0x2605, 0x2605, 0x48, 1 },
+ { 0x260e, 0x260e, 0x25, 1 },
+ { 0x261b, 0x261b, 0x2a, 1 },
+ { 0x261e, 0x261e, 0x2b, 1 },
+ { 0x2660, 0x2660, 0xab, 1 },
+ { 0x2663, 0x2663, 0xa8, 1 },
+ { 0x2665, 0x2665, 0xaa, 1 },
+ { 0x2666, 0x2666, 0xa9, 1 },
+ { 0x2701, 0x2704, 0x21, 1 },
+ { 0x2706, 0x2709, 0x26, 1 },
+ { 0x270c, 0x2727, 0x2c, 1 },
+ { 0x2729, 0x274b, 0x49, 1 },
+ { 0x274d, 0x274d, 0x6d, 1 },
+ { 0x274f, 0x2752, 0x6f, 1 },
+ { 0x2756, 0x2756, 0x76, 1 },
+ { 0x2758, 0x275e, 0x78, 1 },
+ { 0x2761, 0x2767, 0xa1, 1 },
+ { 0x2776, 0x2794, 0xb6, 1 },
+ { 0x2798, 0x27af, 0xd8, 1 },
+ { 0x27b1, 0x27be, 0xf1, 1 }
+};
+#define zapfDingbatsUnicodeMapLen (sizeof(zapfDingbatsUnicodeMapRanges) / sizeof(UnicodeMapRange))
diff --git a/kpdf/xpdf/xpdf/UnicodeTypeTable.cc b/kpdf/xpdf/xpdf/UnicodeTypeTable.cc
new file mode 100644
index 00000000..b8960403
--- /dev/null
+++ b/kpdf/xpdf/xpdf/UnicodeTypeTable.cc
@@ -0,0 +1,949 @@
+//========================================================================
+//
+// UnicodeTypeTable.cc
+//
+// Copyright 2004 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <stdlib.h>
+#include "CharTypes.h"
+#include "UnicodeTypeTable.h"
+
+struct UnicodeMapTableEntry {
+ char *vector;
+ char type;
+};
+
+struct UnicodeCaseTableVector {
+ Unicode codes[256];
+};
+
+static UnicodeMapTableEntry typeTable[256] = {
+ { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLNNNNNNNNNNLNNNNLNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLL", 'X' },
+ { NULL, 'L' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLNNNNNNNNNNNNNNLLNNNNNNNNNNNNNNLLLLLNNNNNNNNNLNNNNNNNNNNNNNNNNN", 'X' },
+ { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLNNNNNNNNNNNLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLL", 'X' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNRNRNNRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR", 'X' },
+ { "RRRRNNNNNNNNNRNNNNNNNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNRRRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNRNNNNNNNRRNNNNNNNRRNNNNNNNNNNRRRRRR", 'X' },
+ { "RRRRRRRRRRRRRRNNRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNNNNNNNNNNNNNNNNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNRNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' },
+ { NULL, 'N' },
+ { "NNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNNNNNLLLLNLLLNNNNLLLLLLLLLLLLLNNLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNLLLLLLLLNLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLNNLLLLLLLNNNNN", 'X' },
+ { "NNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNNNNNLLLLNLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLNNNNNNNNNNNNNNNN", 'X' },
+ { "NNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLNLNNNLLLLLLLLLNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNLLLLL", 'X' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNLLLLNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNLLLLLLLNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLNNNNNNNNNNNNLLLLLLLNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLNNNNNNNNNLLLLLLLLLLNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLNLNLNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNLNNNNNLNNLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNLNNNNNNLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' },
+ { "LLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNLLLLLLLLNLLNNNNNNNNNNNLLLLLLLNLNLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNN", 'X' },
+ { "NNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLNNNNNLLLLLLNLLLLLLNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLNNNLLLLLLLLLLLNNNLLLLLLLLLLLLNNNNLLLLLLLLLLLLLNNNLLLLLLLLLLLLLNNN", 'X' },
+ { "NNNNNNNNNNNNNNLRNNNNNNNNNNNNNNNNNNNNNNNNNNLRNLRNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLNNNNNNNNNNNNNLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' },
+ { "NNLNNNNLNNLLLLLLLLLLNLNNNLLLLLNNNNNNLNLNLNLLLLNLLLNLLLLLLLNNLLLLNNNNNLLLLLNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' },
+ { NULL, 'N' },
+ { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' },
+ { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNN", 'X' },
+ { NULL, 'N' },
+ { NULL, 'N' },
+ { NULL, 'N' },
+ { NULL, 'L' },
+ { NULL, 'N' },
+ { NULL, 'N' },
+ { NULL, 'N' },
+ { NULL, 'N' },
+ { NULL, 'N' },
+ { NULL, 'N' },
+ { NULL, 'N' },
+ { "NNNNNLLLNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLNNNNNNNLLLLLNNLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLL", 'X' },
+ { NULL, 'L' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNLLLLLLLLLLLLNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN", 'X' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { NULL, 'L' },
+ { "LLLLLLLLLLLLLLLLLLLLLLLLRRRRRRNRRRRRRRRRRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR", 'X' },
+ { NULL, 'R' },
+ { "RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNN", 'X' },
+ { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNN", 'X' },
+ { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLL", 'X' }
+};
+
+static UnicodeCaseTableVector caseTable00 = {{
+ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
+ 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f,
+ 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
+ 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f,
+ 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
+ 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
+ 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
+ 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
+ 0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
+ 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
+ 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
+ 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
+ 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f,
+ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
+ 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
+ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
+ 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
+ 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7,
+ 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af,
+ 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x03bc, 0x00b6, 0x00b7,
+ 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
+ 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
+ 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+ 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00d7,
+ 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00df,
+ 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
+ 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef,
+ 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7,
+ 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff
+}};
+static UnicodeCaseTableVector caseTable01 = {{
+ 0x0101, 0x0101, 0x0103, 0x0103, 0x0105, 0x0105, 0x0107, 0x0107,
+ 0x0109, 0x0109, 0x010b, 0x010b, 0x010d, 0x010d, 0x010f, 0x010f,
+ 0x0111, 0x0111, 0x0113, 0x0113, 0x0115, 0x0115, 0x0117, 0x0117,
+ 0x0119, 0x0119, 0x011b, 0x011b, 0x011d, 0x011d, 0x011f, 0x011f,
+ 0x0121, 0x0121, 0x0123, 0x0123, 0x0125, 0x0125, 0x0127, 0x0127,
+ 0x0129, 0x0129, 0x012b, 0x012b, 0x012d, 0x012d, 0x012f, 0x012f,
+ 0x0130, 0x0131, 0x0133, 0x0133, 0x0135, 0x0135, 0x0137, 0x0137,
+ 0x0138, 0x013a, 0x013a, 0x013c, 0x013c, 0x013e, 0x013e, 0x0140,
+ 0x0140, 0x0142, 0x0142, 0x0144, 0x0144, 0x0146, 0x0146, 0x0148,
+ 0x0148, 0x0149, 0x014b, 0x014b, 0x014d, 0x014d, 0x014f, 0x014f,
+ 0x0151, 0x0151, 0x0153, 0x0153, 0x0155, 0x0155, 0x0157, 0x0157,
+ 0x0159, 0x0159, 0x015b, 0x015b, 0x015d, 0x015d, 0x015f, 0x015f,
+ 0x0161, 0x0161, 0x0163, 0x0163, 0x0165, 0x0165, 0x0167, 0x0167,
+ 0x0169, 0x0169, 0x016b, 0x016b, 0x016d, 0x016d, 0x016f, 0x016f,
+ 0x0171, 0x0171, 0x0173, 0x0173, 0x0175, 0x0175, 0x0177, 0x0177,
+ 0x00ff, 0x017a, 0x017a, 0x017c, 0x017c, 0x017e, 0x017e, 0x0073,
+ 0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188,
+ 0x0188, 0x0256, 0x0257, 0x018c, 0x018c, 0x018d, 0x01dd, 0x0259,
+ 0x025b, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268,
+ 0x0199, 0x0199, 0x019a, 0x019b, 0x026f, 0x0272, 0x019e, 0x0275,
+ 0x01a1, 0x01a1, 0x01a3, 0x01a3, 0x01a5, 0x01a5, 0x0280, 0x01a8,
+ 0x01a8, 0x0283, 0x01aa, 0x01ab, 0x01ad, 0x01ad, 0x0288, 0x01b0,
+ 0x01b0, 0x028a, 0x028b, 0x01b4, 0x01b4, 0x01b6, 0x01b6, 0x0292,
+ 0x01b9, 0x01b9, 0x01ba, 0x01bb, 0x01bd, 0x01bd, 0x01be, 0x01bf,
+ 0x01c0, 0x01c1, 0x01c2, 0x01c3, 0x01c6, 0x01c6, 0x01c6, 0x01c9,
+ 0x01c9, 0x01c9, 0x01cc, 0x01cc, 0x01cc, 0x01ce, 0x01ce, 0x01d0,
+ 0x01d0, 0x01d2, 0x01d2, 0x01d4, 0x01d4, 0x01d6, 0x01d6, 0x01d8,
+ 0x01d8, 0x01da, 0x01da, 0x01dc, 0x01dc, 0x01dd, 0x01df, 0x01df,
+ 0x01e1, 0x01e1, 0x01e3, 0x01e3, 0x01e5, 0x01e5, 0x01e7, 0x01e7,
+ 0x01e9, 0x01e9, 0x01eb, 0x01eb, 0x01ed, 0x01ed, 0x01ef, 0x01ef,
+ 0x01f0, 0x01f3, 0x01f3, 0x01f3, 0x01f5, 0x01f5, 0x0195, 0x01bf,
+ 0x01f9, 0x01f9, 0x01fb, 0x01fb, 0x01fd, 0x01fd, 0x01ff, 0x01ff
+}};
+static UnicodeCaseTableVector caseTable02 = {{
+ 0x0201, 0x0201, 0x0203, 0x0203, 0x0205, 0x0205, 0x0207, 0x0207,
+ 0x0209, 0x0209, 0x020b, 0x020b, 0x020d, 0x020d, 0x020f, 0x020f,
+ 0x0211, 0x0211, 0x0213, 0x0213, 0x0215, 0x0215, 0x0217, 0x0217,
+ 0x0219, 0x0219, 0x021b, 0x021b, 0x021d, 0x021d, 0x021f, 0x021f,
+ 0x019e, 0x0221, 0x0223, 0x0223, 0x0225, 0x0225, 0x0227, 0x0227,
+ 0x0229, 0x0229, 0x022b, 0x022b, 0x022d, 0x022d, 0x022f, 0x022f,
+ 0x0231, 0x0231, 0x0233, 0x0233, 0x0234, 0x0235, 0x0236, 0x0237,
+ 0x0238, 0x0239, 0x023a, 0x023b, 0x023c, 0x023d, 0x023e, 0x023f,
+ 0x0240, 0x0241, 0x0242, 0x0243, 0x0244, 0x0245, 0x0246, 0x0247,
+ 0x0248, 0x0249, 0x024a, 0x024b, 0x024c, 0x024d, 0x024e, 0x024f,
+ 0x0250, 0x0251, 0x0252, 0x0253, 0x0254, 0x0255, 0x0256, 0x0257,
+ 0x0258, 0x0259, 0x025a, 0x025b, 0x025c, 0x025d, 0x025e, 0x025f,
+ 0x0260, 0x0261, 0x0262, 0x0263, 0x0264, 0x0265, 0x0266, 0x0267,
+ 0x0268, 0x0269, 0x026a, 0x026b, 0x026c, 0x026d, 0x026e, 0x026f,
+ 0x0270, 0x0271, 0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277,
+ 0x0278, 0x0279, 0x027a, 0x027b, 0x027c, 0x027d, 0x027e, 0x027f,
+ 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0286, 0x0287,
+ 0x0288, 0x0289, 0x028a, 0x028b, 0x028c, 0x028d, 0x028e, 0x028f,
+ 0x0290, 0x0291, 0x0292, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297,
+ 0x0298, 0x0299, 0x029a, 0x029b, 0x029c, 0x029d, 0x029e, 0x029f,
+ 0x02a0, 0x02a1, 0x02a2, 0x02a3, 0x02a4, 0x02a5, 0x02a6, 0x02a7,
+ 0x02a8, 0x02a9, 0x02aa, 0x02ab, 0x02ac, 0x02ad, 0x02ae, 0x02af,
+ 0x02b0, 0x02b1, 0x02b2, 0x02b3, 0x02b4, 0x02b5, 0x02b6, 0x02b7,
+ 0x02b8, 0x02b9, 0x02ba, 0x02bb, 0x02bc, 0x02bd, 0x02be, 0x02bf,
+ 0x02c0, 0x02c1, 0x02c2, 0x02c3, 0x02c4, 0x02c5, 0x02c6, 0x02c7,
+ 0x02c8, 0x02c9, 0x02ca, 0x02cb, 0x02cc, 0x02cd, 0x02ce, 0x02cf,
+ 0x02d0, 0x02d1, 0x02d2, 0x02d3, 0x02d4, 0x02d5, 0x02d6, 0x02d7,
+ 0x02d8, 0x02d9, 0x02da, 0x02db, 0x02dc, 0x02dd, 0x02de, 0x02df,
+ 0x02e0, 0x02e1, 0x02e2, 0x02e3, 0x02e4, 0x02e5, 0x02e6, 0x02e7,
+ 0x02e8, 0x02e9, 0x02ea, 0x02eb, 0x02ec, 0x02ed, 0x02ee, 0x02ef,
+ 0x02f0, 0x02f1, 0x02f2, 0x02f3, 0x02f4, 0x02f5, 0x02f6, 0x02f7,
+ 0x02f8, 0x02f9, 0x02fa, 0x02fb, 0x02fc, 0x02fd, 0x02fe, 0x02ff
+}};
+static UnicodeCaseTableVector caseTable03 = {{
+ 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307,
+ 0x0308, 0x0309, 0x030a, 0x030b, 0x030c, 0x030d, 0x030e, 0x030f,
+ 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317,
+ 0x0318, 0x0319, 0x031a, 0x031b, 0x031c, 0x031d, 0x031e, 0x031f,
+ 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327,
+ 0x0328, 0x0329, 0x032a, 0x032b, 0x032c, 0x032d, 0x032e, 0x032f,
+ 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337,
+ 0x0338, 0x0339, 0x033a, 0x033b, 0x033c, 0x033d, 0x033e, 0x033f,
+ 0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x03b9, 0x0346, 0x0347,
+ 0x0348, 0x0349, 0x034a, 0x034b, 0x034c, 0x034d, 0x034e, 0x034f,
+ 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357,
+ 0x0358, 0x0359, 0x035a, 0x035b, 0x035c, 0x035d, 0x035e, 0x035f,
+ 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367,
+ 0x0368, 0x0369, 0x036a, 0x036b, 0x036c, 0x036d, 0x036e, 0x036f,
+ 0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377,
+ 0x0378, 0x0379, 0x037a, 0x037b, 0x037c, 0x037d, 0x037e, 0x037f,
+ 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x03ac, 0x0387,
+ 0x03ad, 0x03ae, 0x03af, 0x038b, 0x03cc, 0x038d, 0x03cd, 0x03ce,
+ 0x0390, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7,
+ 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
+ 0x03c0, 0x03c1, 0x03a2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7,
+ 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03ac, 0x03ad, 0x03ae, 0x03af,
+ 0x03b0, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7,
+ 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf,
+ 0x03c0, 0x03c1, 0x03c3, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7,
+ 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03cc, 0x03cd, 0x03ce, 0x03cf,
+ 0x03b2, 0x03b8, 0x03d2, 0x03d3, 0x03d4, 0x03c6, 0x03c0, 0x03d7,
+ 0x03d9, 0x03d9, 0x03db, 0x03db, 0x03dd, 0x03dd, 0x03df, 0x03df,
+ 0x03e1, 0x03e1, 0x03e3, 0x03e3, 0x03e5, 0x03e5, 0x03e7, 0x03e7,
+ 0x03e9, 0x03e9, 0x03eb, 0x03eb, 0x03ed, 0x03ed, 0x03ef, 0x03ef,
+ 0x03ba, 0x03c1, 0x03f2, 0x03f3, 0x03b8, 0x03b5, 0x03f6, 0x03f8,
+ 0x03f8, 0x03f2, 0x03fb, 0x03fb, 0x03fc, 0x03fd, 0x03fe, 0x03ff
+}};
+static UnicodeCaseTableVector caseTable04 = {{
+ 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457,
+ 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x045d, 0x045e, 0x045f,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f,
+ 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
+ 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f,
+ 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
+ 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f,
+ 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457,
+ 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x045d, 0x045e, 0x045f,
+ 0x0461, 0x0461, 0x0463, 0x0463, 0x0465, 0x0465, 0x0467, 0x0467,
+ 0x0469, 0x0469, 0x046b, 0x046b, 0x046d, 0x046d, 0x046f, 0x046f,
+ 0x0471, 0x0471, 0x0473, 0x0473, 0x0475, 0x0475, 0x0477, 0x0477,
+ 0x0479, 0x0479, 0x047b, 0x047b, 0x047d, 0x047d, 0x047f, 0x047f,
+ 0x0481, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487,
+ 0x0488, 0x0489, 0x048b, 0x048b, 0x048d, 0x048d, 0x048f, 0x048f,
+ 0x0491, 0x0491, 0x0493, 0x0493, 0x0495, 0x0495, 0x0497, 0x0497,
+ 0x0499, 0x0499, 0x049b, 0x049b, 0x049d, 0x049d, 0x049f, 0x049f,
+ 0x04a1, 0x04a1, 0x04a3, 0x04a3, 0x04a5, 0x04a5, 0x04a7, 0x04a7,
+ 0x04a9, 0x04a9, 0x04ab, 0x04ab, 0x04ad, 0x04ad, 0x04af, 0x04af,
+ 0x04b1, 0x04b1, 0x04b3, 0x04b3, 0x04b5, 0x04b5, 0x04b7, 0x04b7,
+ 0x04b9, 0x04b9, 0x04bb, 0x04bb, 0x04bd, 0x04bd, 0x04bf, 0x04bf,
+ 0x04c0, 0x04c2, 0x04c2, 0x04c4, 0x04c4, 0x04c6, 0x04c6, 0x04c8,
+ 0x04c8, 0x04ca, 0x04ca, 0x04cc, 0x04cc, 0x04ce, 0x04ce, 0x04cf,
+ 0x04d1, 0x04d1, 0x04d3, 0x04d3, 0x04d5, 0x04d5, 0x04d7, 0x04d7,
+ 0x04d9, 0x04d9, 0x04db, 0x04db, 0x04dd, 0x04dd, 0x04df, 0x04df,
+ 0x04e1, 0x04e1, 0x04e3, 0x04e3, 0x04e5, 0x04e5, 0x04e7, 0x04e7,
+ 0x04e9, 0x04e9, 0x04eb, 0x04eb, 0x04ed, 0x04ed, 0x04ef, 0x04ef,
+ 0x04f1, 0x04f1, 0x04f3, 0x04f3, 0x04f5, 0x04f5, 0x04f6, 0x04f7,
+ 0x04f9, 0x04f9, 0x04fa, 0x04fb, 0x04fc, 0x04fd, 0x04fe, 0x04ff
+}};
+static UnicodeCaseTableVector caseTable05 = {{
+ 0x0501, 0x0501, 0x0503, 0x0503, 0x0505, 0x0505, 0x0507, 0x0507,
+ 0x0509, 0x0509, 0x050b, 0x050b, 0x050d, 0x050d, 0x050f, 0x050f,
+ 0x0510, 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0516, 0x0517,
+ 0x0518, 0x0519, 0x051a, 0x051b, 0x051c, 0x051d, 0x051e, 0x051f,
+ 0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527,
+ 0x0528, 0x0529, 0x052a, 0x052b, 0x052c, 0x052d, 0x052e, 0x052f,
+ 0x0530, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567,
+ 0x0568, 0x0569, 0x056a, 0x056b, 0x056c, 0x056d, 0x056e, 0x056f,
+ 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577,
+ 0x0578, 0x0579, 0x057a, 0x057b, 0x057c, 0x057d, 0x057e, 0x057f,
+ 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0557,
+ 0x0558, 0x0559, 0x055a, 0x055b, 0x055c, 0x055d, 0x055e, 0x055f,
+ 0x0560, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567,
+ 0x0568, 0x0569, 0x056a, 0x056b, 0x056c, 0x056d, 0x056e, 0x056f,
+ 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577,
+ 0x0578, 0x0579, 0x057a, 0x057b, 0x057c, 0x057d, 0x057e, 0x057f,
+ 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0587,
+ 0x0588, 0x0589, 0x058a, 0x058b, 0x058c, 0x058d, 0x058e, 0x058f,
+ 0x0590, 0x0591, 0x0592, 0x0593, 0x0594, 0x0595, 0x0596, 0x0597,
+ 0x0598, 0x0599, 0x059a, 0x059b, 0x059c, 0x059d, 0x059e, 0x059f,
+ 0x05a0, 0x05a1, 0x05a2, 0x05a3, 0x05a4, 0x05a5, 0x05a6, 0x05a7,
+ 0x05a8, 0x05a9, 0x05aa, 0x05ab, 0x05ac, 0x05ad, 0x05ae, 0x05af,
+ 0x05b0, 0x05b1, 0x05b2, 0x05b3, 0x05b4, 0x05b5, 0x05b6, 0x05b7,
+ 0x05b8, 0x05b9, 0x05ba, 0x05bb, 0x05bc, 0x05bd, 0x05be, 0x05bf,
+ 0x05c0, 0x05c1, 0x05c2, 0x05c3, 0x05c4, 0x05c5, 0x05c6, 0x05c7,
+ 0x05c8, 0x05c9, 0x05ca, 0x05cb, 0x05cc, 0x05cd, 0x05ce, 0x05cf,
+ 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7,
+ 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df,
+ 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7,
+ 0x05e8, 0x05e9, 0x05ea, 0x05eb, 0x05ec, 0x05ed, 0x05ee, 0x05ef,
+ 0x05f0, 0x05f1, 0x05f2, 0x05f3, 0x05f4, 0x05f5, 0x05f6, 0x05f7,
+ 0x05f8, 0x05f9, 0x05fa, 0x05fb, 0x05fc, 0x05fd, 0x05fe, 0x05ff
+}};
+static UnicodeCaseTableVector caseTable1e = {{
+ 0x1e01, 0x1e01, 0x1e03, 0x1e03, 0x1e05, 0x1e05, 0x1e07, 0x1e07,
+ 0x1e09, 0x1e09, 0x1e0b, 0x1e0b, 0x1e0d, 0x1e0d, 0x1e0f, 0x1e0f,
+ 0x1e11, 0x1e11, 0x1e13, 0x1e13, 0x1e15, 0x1e15, 0x1e17, 0x1e17,
+ 0x1e19, 0x1e19, 0x1e1b, 0x1e1b, 0x1e1d, 0x1e1d, 0x1e1f, 0x1e1f,
+ 0x1e21, 0x1e21, 0x1e23, 0x1e23, 0x1e25, 0x1e25, 0x1e27, 0x1e27,
+ 0x1e29, 0x1e29, 0x1e2b, 0x1e2b, 0x1e2d, 0x1e2d, 0x1e2f, 0x1e2f,
+ 0x1e31, 0x1e31, 0x1e33, 0x1e33, 0x1e35, 0x1e35, 0x1e37, 0x1e37,
+ 0x1e39, 0x1e39, 0x1e3b, 0x1e3b, 0x1e3d, 0x1e3d, 0x1e3f, 0x1e3f,
+ 0x1e41, 0x1e41, 0x1e43, 0x1e43, 0x1e45, 0x1e45, 0x1e47, 0x1e47,
+ 0x1e49, 0x1e49, 0x1e4b, 0x1e4b, 0x1e4d, 0x1e4d, 0x1e4f, 0x1e4f,
+ 0x1e51, 0x1e51, 0x1e53, 0x1e53, 0x1e55, 0x1e55, 0x1e57, 0x1e57,
+ 0x1e59, 0x1e59, 0x1e5b, 0x1e5b, 0x1e5d, 0x1e5d, 0x1e5f, 0x1e5f,
+ 0x1e61, 0x1e61, 0x1e63, 0x1e63, 0x1e65, 0x1e65, 0x1e67, 0x1e67,
+ 0x1e69, 0x1e69, 0x1e6b, 0x1e6b, 0x1e6d, 0x1e6d, 0x1e6f, 0x1e6f,
+ 0x1e71, 0x1e71, 0x1e73, 0x1e73, 0x1e75, 0x1e75, 0x1e77, 0x1e77,
+ 0x1e79, 0x1e79, 0x1e7b, 0x1e7b, 0x1e7d, 0x1e7d, 0x1e7f, 0x1e7f,
+ 0x1e81, 0x1e81, 0x1e83, 0x1e83, 0x1e85, 0x1e85, 0x1e87, 0x1e87,
+ 0x1e89, 0x1e89, 0x1e8b, 0x1e8b, 0x1e8d, 0x1e8d, 0x1e8f, 0x1e8f,
+ 0x1e91, 0x1e91, 0x1e93, 0x1e93, 0x1e95, 0x1e95, 0x1e96, 0x1e97,
+ 0x1e98, 0x1e99, 0x1e9a, 0x1e61, 0x1e9c, 0x1e9d, 0x1e9e, 0x1e9f,
+ 0x1ea1, 0x1ea1, 0x1ea3, 0x1ea3, 0x1ea5, 0x1ea5, 0x1ea7, 0x1ea7,
+ 0x1ea9, 0x1ea9, 0x1eab, 0x1eab, 0x1ead, 0x1ead, 0x1eaf, 0x1eaf,
+ 0x1eb1, 0x1eb1, 0x1eb3, 0x1eb3, 0x1eb5, 0x1eb5, 0x1eb7, 0x1eb7,
+ 0x1eb9, 0x1eb9, 0x1ebb, 0x1ebb, 0x1ebd, 0x1ebd, 0x1ebf, 0x1ebf,
+ 0x1ec1, 0x1ec1, 0x1ec3, 0x1ec3, 0x1ec5, 0x1ec5, 0x1ec7, 0x1ec7,
+ 0x1ec9, 0x1ec9, 0x1ecb, 0x1ecb, 0x1ecd, 0x1ecd, 0x1ecf, 0x1ecf,
+ 0x1ed1, 0x1ed1, 0x1ed3, 0x1ed3, 0x1ed5, 0x1ed5, 0x1ed7, 0x1ed7,
+ 0x1ed9, 0x1ed9, 0x1edb, 0x1edb, 0x1edd, 0x1edd, 0x1edf, 0x1edf,
+ 0x1ee1, 0x1ee1, 0x1ee3, 0x1ee3, 0x1ee5, 0x1ee5, 0x1ee7, 0x1ee7,
+ 0x1ee9, 0x1ee9, 0x1eeb, 0x1eeb, 0x1eed, 0x1eed, 0x1eef, 0x1eef,
+ 0x1ef1, 0x1ef1, 0x1ef3, 0x1ef3, 0x1ef5, 0x1ef5, 0x1ef7, 0x1ef7,
+ 0x1ef9, 0x1ef9, 0x1efa, 0x1efb, 0x1efc, 0x1efd, 0x1efe, 0x1eff
+}};
+static UnicodeCaseTableVector caseTable1f = {{
+ 0x1f00, 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07,
+ 0x1f00, 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07,
+ 0x1f10, 0x1f11, 0x1f12, 0x1f13, 0x1f14, 0x1f15, 0x1f16, 0x1f17,
+ 0x1f10, 0x1f11, 0x1f12, 0x1f13, 0x1f14, 0x1f15, 0x1f1e, 0x1f1f,
+ 0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25, 0x1f26, 0x1f27,
+ 0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25, 0x1f26, 0x1f27,
+ 0x1f30, 0x1f31, 0x1f32, 0x1f33, 0x1f34, 0x1f35, 0x1f36, 0x1f37,
+ 0x1f30, 0x1f31, 0x1f32, 0x1f33, 0x1f34, 0x1f35, 0x1f36, 0x1f37,
+ 0x1f40, 0x1f41, 0x1f42, 0x1f43, 0x1f44, 0x1f45, 0x1f46, 0x1f47,
+ 0x1f40, 0x1f41, 0x1f42, 0x1f43, 0x1f44, 0x1f45, 0x1f4e, 0x1f4f,
+ 0x1f50, 0x1f51, 0x1f52, 0x1f53, 0x1f54, 0x1f55, 0x1f56, 0x1f57,
+ 0x1f58, 0x1f51, 0x1f5a, 0x1f53, 0x1f5c, 0x1f55, 0x1f5e, 0x1f57,
+ 0x1f60, 0x1f61, 0x1f62, 0x1f63, 0x1f64, 0x1f65, 0x1f66, 0x1f67,
+ 0x1f60, 0x1f61, 0x1f62, 0x1f63, 0x1f64, 0x1f65, 0x1f66, 0x1f67,
+ 0x1f70, 0x1f71, 0x1f72, 0x1f73, 0x1f74, 0x1f75, 0x1f76, 0x1f77,
+ 0x1f78, 0x1f79, 0x1f7a, 0x1f7b, 0x1f7c, 0x1f7d, 0x1f7e, 0x1f7f,
+ 0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87,
+ 0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87,
+ 0x1f90, 0x1f91, 0x1f92, 0x1f93, 0x1f94, 0x1f95, 0x1f96, 0x1f97,
+ 0x1f90, 0x1f91, 0x1f92, 0x1f93, 0x1f94, 0x1f95, 0x1f96, 0x1f97,
+ 0x1fa0, 0x1fa1, 0x1fa2, 0x1fa3, 0x1fa4, 0x1fa5, 0x1fa6, 0x1fa7,
+ 0x1fa0, 0x1fa1, 0x1fa2, 0x1fa3, 0x1fa4, 0x1fa5, 0x1fa6, 0x1fa7,
+ 0x1fb0, 0x1fb1, 0x1fb2, 0x1fb3, 0x1fb4, 0x1fb5, 0x1fb6, 0x1fb7,
+ 0x1fb0, 0x1fb1, 0x1f70, 0x1f71, 0x1fb3, 0x1fbd, 0x03b9, 0x1fbf,
+ 0x1fc0, 0x1fc1, 0x1fc2, 0x1fc3, 0x1fc4, 0x1fc5, 0x1fc6, 0x1fc7,
+ 0x1f72, 0x1f73, 0x1f74, 0x1f75, 0x1fc3, 0x1fcd, 0x1fce, 0x1fcf,
+ 0x1fd0, 0x1fd1, 0x1fd2, 0x1fd3, 0x1fd4, 0x1fd5, 0x1fd6, 0x1fd7,
+ 0x1fd0, 0x1fd1, 0x1f76, 0x1f77, 0x1fdc, 0x1fdd, 0x1fde, 0x1fdf,
+ 0x1fe0, 0x1fe1, 0x1fe2, 0x1fe3, 0x1fe4, 0x1fe5, 0x1fe6, 0x1fe7,
+ 0x1fe0, 0x1fe1, 0x1f7a, 0x1f7b, 0x1fe5, 0x1fed, 0x1fee, 0x1fef,
+ 0x1ff0, 0x1ff1, 0x1ff2, 0x1ff3, 0x1ff4, 0x1ff5, 0x1ff6, 0x1ff7,
+ 0x1f78, 0x1f79, 0x1f7c, 0x1f7d, 0x1ff3, 0x1ffd, 0x1ffe, 0x1fff
+}};
+static UnicodeCaseTableVector caseTable21 = {{
+ 0x2100, 0x2101, 0x2102, 0x2103, 0x2104, 0x2105, 0x2106, 0x2107,
+ 0x2108, 0x2109, 0x210a, 0x210b, 0x210c, 0x210d, 0x210e, 0x210f,
+ 0x2110, 0x2111, 0x2112, 0x2113, 0x2114, 0x2115, 0x2116, 0x2117,
+ 0x2118, 0x2119, 0x211a, 0x211b, 0x211c, 0x211d, 0x211e, 0x211f,
+ 0x2120, 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x03c9, 0x2127,
+ 0x2128, 0x2129, 0x006b, 0x00e5, 0x212c, 0x212d, 0x212e, 0x212f,
+ 0x2130, 0x2131, 0x2132, 0x2133, 0x2134, 0x2135, 0x2136, 0x2137,
+ 0x2138, 0x2139, 0x213a, 0x213b, 0x213c, 0x213d, 0x213e, 0x213f,
+ 0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147,
+ 0x2148, 0x2149, 0x214a, 0x214b, 0x214c, 0x214d, 0x214e, 0x214f,
+ 0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157,
+ 0x2158, 0x2159, 0x215a, 0x215b, 0x215c, 0x215d, 0x215e, 0x215f,
+ 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177,
+ 0x2178, 0x2179, 0x217a, 0x217b, 0x217c, 0x217d, 0x217e, 0x217f,
+ 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177,
+ 0x2178, 0x2179, 0x217a, 0x217b, 0x217c, 0x217d, 0x217e, 0x217f,
+ 0x2180, 0x2181, 0x2182, 0x2183, 0x2184, 0x2185, 0x2186, 0x2187,
+ 0x2188, 0x2189, 0x218a, 0x218b, 0x218c, 0x218d, 0x218e, 0x218f,
+ 0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x2196, 0x2197,
+ 0x2198, 0x2199, 0x219a, 0x219b, 0x219c, 0x219d, 0x219e, 0x219f,
+ 0x21a0, 0x21a1, 0x21a2, 0x21a3, 0x21a4, 0x21a5, 0x21a6, 0x21a7,
+ 0x21a8, 0x21a9, 0x21aa, 0x21ab, 0x21ac, 0x21ad, 0x21ae, 0x21af,
+ 0x21b0, 0x21b1, 0x21b2, 0x21b3, 0x21b4, 0x21b5, 0x21b6, 0x21b7,
+ 0x21b8, 0x21b9, 0x21ba, 0x21bb, 0x21bc, 0x21bd, 0x21be, 0x21bf,
+ 0x21c0, 0x21c1, 0x21c2, 0x21c3, 0x21c4, 0x21c5, 0x21c6, 0x21c7,
+ 0x21c8, 0x21c9, 0x21ca, 0x21cb, 0x21cc, 0x21cd, 0x21ce, 0x21cf,
+ 0x21d0, 0x21d1, 0x21d2, 0x21d3, 0x21d4, 0x21d5, 0x21d6, 0x21d7,
+ 0x21d8, 0x21d9, 0x21da, 0x21db, 0x21dc, 0x21dd, 0x21de, 0x21df,
+ 0x21e0, 0x21e1, 0x21e2, 0x21e3, 0x21e4, 0x21e5, 0x21e6, 0x21e7,
+ 0x21e8, 0x21e9, 0x21ea, 0x21eb, 0x21ec, 0x21ed, 0x21ee, 0x21ef,
+ 0x21f0, 0x21f1, 0x21f2, 0x21f3, 0x21f4, 0x21f5, 0x21f6, 0x21f7,
+ 0x21f8, 0x21f9, 0x21fa, 0x21fb, 0x21fc, 0x21fd, 0x21fe, 0x21ff
+}};
+static UnicodeCaseTableVector caseTable24 = {{
+ 0x2400, 0x2401, 0x2402, 0x2403, 0x2404, 0x2405, 0x2406, 0x2407,
+ 0x2408, 0x2409, 0x240a, 0x240b, 0x240c, 0x240d, 0x240e, 0x240f,
+ 0x2410, 0x2411, 0x2412, 0x2413, 0x2414, 0x2415, 0x2416, 0x2417,
+ 0x2418, 0x2419, 0x241a, 0x241b, 0x241c, 0x241d, 0x241e, 0x241f,
+ 0x2420, 0x2421, 0x2422, 0x2423, 0x2424, 0x2425, 0x2426, 0x2427,
+ 0x2428, 0x2429, 0x242a, 0x242b, 0x242c, 0x242d, 0x242e, 0x242f,
+ 0x2430, 0x2431, 0x2432, 0x2433, 0x2434, 0x2435, 0x2436, 0x2437,
+ 0x2438, 0x2439, 0x243a, 0x243b, 0x243c, 0x243d, 0x243e, 0x243f,
+ 0x2440, 0x2441, 0x2442, 0x2443, 0x2444, 0x2445, 0x2446, 0x2447,
+ 0x2448, 0x2449, 0x244a, 0x244b, 0x244c, 0x244d, 0x244e, 0x244f,
+ 0x2450, 0x2451, 0x2452, 0x2453, 0x2454, 0x2455, 0x2456, 0x2457,
+ 0x2458, 0x2459, 0x245a, 0x245b, 0x245c, 0x245d, 0x245e, 0x245f,
+ 0x2460, 0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466, 0x2467,
+ 0x2468, 0x2469, 0x246a, 0x246b, 0x246c, 0x246d, 0x246e, 0x246f,
+ 0x2470, 0x2471, 0x2472, 0x2473, 0x2474, 0x2475, 0x2476, 0x2477,
+ 0x2478, 0x2479, 0x247a, 0x247b, 0x247c, 0x247d, 0x247e, 0x247f,
+ 0x2480, 0x2481, 0x2482, 0x2483, 0x2484, 0x2485, 0x2486, 0x2487,
+ 0x2488, 0x2489, 0x248a, 0x248b, 0x248c, 0x248d, 0x248e, 0x248f,
+ 0x2490, 0x2491, 0x2492, 0x2493, 0x2494, 0x2495, 0x2496, 0x2497,
+ 0x2498, 0x2499, 0x249a, 0x249b, 0x249c, 0x249d, 0x249e, 0x249f,
+ 0x24a0, 0x24a1, 0x24a2, 0x24a3, 0x24a4, 0x24a5, 0x24a6, 0x24a7,
+ 0x24a8, 0x24a9, 0x24aa, 0x24ab, 0x24ac, 0x24ad, 0x24ae, 0x24af,
+ 0x24b0, 0x24b1, 0x24b2, 0x24b3, 0x24b4, 0x24b5, 0x24d0, 0x24d1,
+ 0x24d2, 0x24d3, 0x24d4, 0x24d5, 0x24d6, 0x24d7, 0x24d8, 0x24d9,
+ 0x24da, 0x24db, 0x24dc, 0x24dd, 0x24de, 0x24df, 0x24e0, 0x24e1,
+ 0x24e2, 0x24e3, 0x24e4, 0x24e5, 0x24e6, 0x24e7, 0x24e8, 0x24e9,
+ 0x24d0, 0x24d1, 0x24d2, 0x24d3, 0x24d4, 0x24d5, 0x24d6, 0x24d7,
+ 0x24d8, 0x24d9, 0x24da, 0x24db, 0x24dc, 0x24dd, 0x24de, 0x24df,
+ 0x24e0, 0x24e1, 0x24e2, 0x24e3, 0x24e4, 0x24e5, 0x24e6, 0x24e7,
+ 0x24e8, 0x24e9, 0x24ea, 0x24eb, 0x24ec, 0x24ed, 0x24ee, 0x24ef,
+ 0x24f0, 0x24f1, 0x24f2, 0x24f3, 0x24f4, 0x24f5, 0x24f6, 0x24f7,
+ 0x24f8, 0x24f9, 0x24fa, 0x24fb, 0x24fc, 0x24fd, 0x24fe, 0x24ff
+}};
+static UnicodeCaseTableVector caseTableff = {{
+ 0xff00, 0xff01, 0xff02, 0xff03, 0xff04, 0xff05, 0xff06, 0xff07,
+ 0xff08, 0xff09, 0xff0a, 0xff0b, 0xff0c, 0xff0d, 0xff0e, 0xff0f,
+ 0xff10, 0xff11, 0xff12, 0xff13, 0xff14, 0xff15, 0xff16, 0xff17,
+ 0xff18, 0xff19, 0xff1a, 0xff1b, 0xff1c, 0xff1d, 0xff1e, 0xff1f,
+ 0xff20, 0xff41, 0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47,
+ 0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f,
+ 0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, 0xff56, 0xff57,
+ 0xff58, 0xff59, 0xff5a, 0xff3b, 0xff3c, 0xff3d, 0xff3e, 0xff3f,
+ 0xff40, 0xff41, 0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47,
+ 0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f,
+ 0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, 0xff56, 0xff57,
+ 0xff58, 0xff59, 0xff5a, 0xff5b, 0xff5c, 0xff5d, 0xff5e, 0xff5f,
+ 0xff60, 0xff61, 0xff62, 0xff63, 0xff64, 0xff65, 0xff66, 0xff67,
+ 0xff68, 0xff69, 0xff6a, 0xff6b, 0xff6c, 0xff6d, 0xff6e, 0xff6f,
+ 0xff70, 0xff71, 0xff72, 0xff73, 0xff74, 0xff75, 0xff76, 0xff77,
+ 0xff78, 0xff79, 0xff7a, 0xff7b, 0xff7c, 0xff7d, 0xff7e, 0xff7f,
+ 0xff80, 0xff81, 0xff82, 0xff83, 0xff84, 0xff85, 0xff86, 0xff87,
+ 0xff88, 0xff89, 0xff8a, 0xff8b, 0xff8c, 0xff8d, 0xff8e, 0xff8f,
+ 0xff90, 0xff91, 0xff92, 0xff93, 0xff94, 0xff95, 0xff96, 0xff97,
+ 0xff98, 0xff99, 0xff9a, 0xff9b, 0xff9c, 0xff9d, 0xff9e, 0xff9f,
+ 0xffa0, 0xffa1, 0xffa2, 0xffa3, 0xffa4, 0xffa5, 0xffa6, 0xffa7,
+ 0xffa8, 0xffa9, 0xffaa, 0xffab, 0xffac, 0xffad, 0xffae, 0xffaf,
+ 0xffb0, 0xffb1, 0xffb2, 0xffb3, 0xffb4, 0xffb5, 0xffb6, 0xffb7,
+ 0xffb8, 0xffb9, 0xffba, 0xffbb, 0xffbc, 0xffbd, 0xffbe, 0xffbf,
+ 0xffc0, 0xffc1, 0xffc2, 0xffc3, 0xffc4, 0xffc5, 0xffc6, 0xffc7,
+ 0xffc8, 0xffc9, 0xffca, 0xffcb, 0xffcc, 0xffcd, 0xffce, 0xffcf,
+ 0xffd0, 0xffd1, 0xffd2, 0xffd3, 0xffd4, 0xffd5, 0xffd6, 0xffd7,
+ 0xffd8, 0xffd9, 0xffda, 0xffdb, 0xffdc, 0xffdd, 0xffde, 0xffdf,
+ 0xffe0, 0xffe1, 0xffe2, 0xffe3, 0xffe4, 0xffe5, 0xffe6, 0xffe7,
+ 0xffe8, 0xffe9, 0xffea, 0xffeb, 0xffec, 0xffed, 0xffee, 0xffef,
+ 0xfff0, 0xfff1, 0xfff2, 0xfff3, 0xfff4, 0xfff5, 0xfff6, 0xfff7,
+ 0xfff8, 0xfff9, 0xfffa, 0xfffb, 0xfffc, 0xfffd, 0xfffe, 0xffff
+}};
+static UnicodeCaseTableVector *caseTable[256] = {
+ &caseTable00,
+ &caseTable01,
+ &caseTable02,
+ &caseTable03,
+ &caseTable04,
+ &caseTable05,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &caseTable1e,
+ &caseTable1f,
+ NULL,
+ &caseTable21,
+ NULL,
+ NULL,
+ &caseTable24,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &caseTableff
+};
+
+static inline char getType(Unicode c) {
+ int i;
+ char type;
+
+ if (c > 0xffff) {
+ type = 'X';
+ } else {
+ i = (c >> 8) & 0xff;
+ if ((type = typeTable[i].type) == 'X') {
+ type = typeTable[i].vector[c & 0xff];
+ }
+ }
+ return type;
+}
+
+GBool unicodeTypeL(Unicode c) {
+ return getType(c) == 'L';
+}
+
+GBool unicodeTypeR(Unicode c) {
+ return getType(c) == 'R';
+}
+
+Unicode unicodeToUpper(Unicode c) {
+ int i;
+
+ if (c > 0xffff) {
+ return c;
+ }
+ i = (c >> 8) & 0xff;
+ if (caseTable[i]) {
+ return caseTable[i]->codes[c & 0xff];
+ }
+ return c;
+}
+
diff --git a/kpdf/xpdf/xpdf/UnicodeTypeTable.h b/kpdf/xpdf/xpdf/UnicodeTypeTable.h
new file mode 100644
index 00000000..7103dbdd
--- /dev/null
+++ b/kpdf/xpdf/xpdf/UnicodeTypeTable.h
@@ -0,0 +1,20 @@
+//========================================================================
+//
+// UnicodeTypeTable.h
+//
+// Copyright 2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef UNICODETYPETABLE_H
+#define UNICODETYPETABLE_H
+
+#include "gtypes.h"
+
+extern GBool unicodeTypeL(Unicode c);
+
+extern GBool unicodeTypeR(Unicode c);
+
+extern Unicode unicodeToUpper(Unicode c);
+
+#endif
diff --git a/kpdf/xpdf/xpdf/XRef.cc b/kpdf/xpdf/xpdf/XRef.cc
new file mode 100644
index 00000000..d12d812f
--- /dev/null
+++ b/kpdf/xpdf/xpdf/XRef.cc
@@ -0,0 +1,917 @@
+//========================================================================
+//
+// XRef.cc
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <ctype.h>
+#include "gmem.h"
+#include "Object.h"
+#include "Stream.h"
+#include "Lexer.h"
+#include "Parser.h"
+#include "Dict.h"
+#include "Error.h"
+#include "ErrorCodes.h"
+#include "XRef.h"
+
+//------------------------------------------------------------------------
+
+#define xrefSearchSize 1024 // read this many bytes at end of file
+ // to look for 'startxref'
+
+//------------------------------------------------------------------------
+// Permission bits
+//------------------------------------------------------------------------
+
+#define permPrint (1<<2)
+#define permChange (1<<3)
+#define permCopy (1<<4)
+#define permNotes (1<<5)
+#define defPermFlags 0xfffc
+
+//------------------------------------------------------------------------
+// ObjectStream
+//------------------------------------------------------------------------
+
+class ObjectStream {
+public:
+
+ // Create an object stream, using object number <objStrNum>,
+ // generation 0.
+ ObjectStream(XRef *xref, int objStrNumA);
+
+ ~ObjectStream();
+
+ // Return the object number of this object stream.
+ int getObjStrNum() { return objStrNum; }
+
+ // Get the <objIdx>th object from this stream, which should be
+ // object number <objNum>, generation 0.
+ Object *getObject(int objIdx, int objNum, Object *obj);
+
+private:
+
+ int objStrNum; // object number of the object stream
+ int nObjects; // number of objects in the stream
+ Object *objs; // the objects (length = nObjects)
+ int *objNums; // the object numbers (length = nObjects)
+};
+
+ObjectStream::ObjectStream(XRef *xref, int objStrNumA) {
+ Stream *str;
+ Parser *parser;
+ int *offsets;
+ Object objStr, obj1, obj2;
+ int first, i;
+
+ objStrNum = objStrNumA;
+ nObjects = 0;
+ objs = NULL;
+ objNums = NULL;
+
+ if (!xref->fetch(objStrNum, 0, &objStr)->isStream()) {
+ goto err1;
+ }
+
+ if (!objStr.streamGetDict()->lookup("N", &obj1)->isInt()) {
+ obj1.free();
+ goto err1;
+ }
+ nObjects = obj1.getInt();
+ obj1.free();
+ if (nObjects <= 0) {
+ goto err1;
+ }
+
+ if (!objStr.streamGetDict()->lookup("First", &obj1)->isInt()) {
+ obj1.free();
+ goto err1;
+ }
+ first = obj1.getInt();
+ obj1.free();
+ if (first < 0) {
+ goto err1;
+ }
+
+ objs = new Object[nObjects];
+ objNums = (int *)gmallocn(nObjects, sizeof(int));
+ offsets = (int *)gmallocn(nObjects, sizeof(int));
+
+ // parse the header: object numbers and offsets
+ objStr.streamReset();
+ obj1.initNull();
+ str = new EmbedStream(objStr.getStream(), &obj1, gTrue, first);
+ parser = new Parser(xref, new Lexer(xref, str), gFalse);
+ for (i = 0; i < nObjects; ++i) {
+ parser->getObj(&obj1);
+ parser->getObj(&obj2);
+ if (!obj1.isInt() || !obj2.isInt()) {
+ obj1.free();
+ obj2.free();
+ delete parser;
+ gfree(offsets);
+ goto err1;
+ }
+ objNums[i] = obj1.getInt();
+ offsets[i] = obj2.getInt();
+ obj1.free();
+ obj2.free();
+ if (objNums[i] < 0 || offsets[i] < 0 ||
+ (i > 0 && offsets[i] < offsets[i-1])) {
+ delete parser;
+ gfree(offsets);
+ goto err1;
+ }
+ }
+ while (str->getChar() != EOF) ;
+ delete parser;
+
+ // skip to the first object - this shouldn't be necessary because
+ // the First key is supposed to be equal to offsets[0], but just in
+ // case...
+ for (i = first; i < offsets[0]; ++i) {
+ objStr.getStream()->getChar();
+ }
+
+ // parse the objects
+ for (i = 0; i < nObjects; ++i) {
+ obj1.initNull();
+ if (i == nObjects - 1) {
+ str = new EmbedStream(objStr.getStream(), &obj1, gFalse, 0);
+ } else {
+ str = new EmbedStream(objStr.getStream(), &obj1, gTrue,
+ offsets[i+1] - offsets[i]);
+ }
+ parser = new Parser(xref, new Lexer(xref, str), gFalse);
+ parser->getObj(&objs[i]);
+ while (str->getChar() != EOF) ;
+ delete parser;
+ }
+
+ gfree(offsets);
+
+ err1:
+ objStr.free();
+ return;
+}
+
+ObjectStream::~ObjectStream() {
+ int i;
+
+ if (objs) {
+ for (i = 0; i < nObjects; ++i) {
+ objs[i].free();
+ }
+ delete[] objs;
+ }
+ gfree(objNums);
+}
+
+Object *ObjectStream::getObject(int objIdx, int objNum, Object *obj) {
+ if (objIdx < 0 || objIdx >= nObjects || objNum != objNums[objIdx]) {
+ return obj->initNull();
+ }
+ return objs[objIdx].copy(obj);
+}
+
+//------------------------------------------------------------------------
+// XRef
+//------------------------------------------------------------------------
+
+XRef::XRef(BaseStream *strA) {
+ Guint pos;
+ Object obj;
+
+ ok = gTrue;
+ errCode = errNone;
+ size = 0;
+ entries = NULL;
+ streamEnds = NULL;
+ streamEndsLen = 0;
+ objStr = NULL;
+
+ encrypted = gFalse;
+ permFlags = defPermFlags;
+ ownerPasswordOk = gFalse;
+
+ // read the trailer
+ str = strA;
+ start = str->getStart();
+ pos = getStartXref();
+
+ // if there was a problem with the 'startxref' position, try to
+ // reconstruct the xref table
+ if (pos == 0) {
+ if (!(ok = constructXRef())) {
+ errCode = errDamaged;
+ return;
+ }
+
+ // read the xref table
+ } else {
+ while (readXRef(&pos)) ;
+
+ // if there was a problem with the xref table,
+ // try to reconstruct it
+ if (!ok) {
+ if (!(ok = constructXRef())) {
+ errCode = errDamaged;
+ return;
+ }
+ }
+ }
+
+ // get the root dictionary (catalog) object
+ trailerDict.dictLookupNF("Root", &obj);
+ if (obj.isRef()) {
+ rootNum = obj.getRefNum();
+ rootGen = obj.getRefGen();
+ obj.free();
+ } else {
+ obj.free();
+ if (!(ok = constructXRef())) {
+ errCode = errDamaged;
+ return;
+ }
+ }
+
+ // now set the trailer dictionary's xref pointer so we can fetch
+ // indirect objects from it
+ trailerDict.getDict()->setXRef(this);
+}
+
+XRef::~XRef() {
+ gfree(entries);
+ trailerDict.free();
+ if (streamEnds) {
+ gfree(streamEnds);
+ }
+ if (objStr) {
+ delete objStr;
+ }
+}
+
+// Read the 'startxref' position.
+Guint XRef::getStartXref() {
+ char buf[xrefSearchSize+1];
+ char *p;
+ int c, n, i;
+
+ // read last xrefSearchSize bytes
+ str->setPos(xrefSearchSize, -1);
+ for (n = 0; n < xrefSearchSize; ++n) {
+ if ((c = str->getChar()) == EOF) {
+ break;
+ }
+ buf[n] = c;
+ }
+ buf[n] = '\0';
+
+ // find startxref
+ for (i = n - 9; i >= 0; --i) {
+ if (!strncmp(&buf[i], "startxref", 9)) {
+ break;
+ }
+ }
+ if (i < 0) {
+ return 0;
+ }
+ for (p = &buf[i+9]; isspace(*p); ++p) ;
+ lastXRefPos = strToUnsigned(p);
+
+ return lastXRefPos;
+}
+
+// Read one xref table section. Also reads the associated trailer
+// dictionary, and returns the prev pointer (if any).
+GBool XRef::readXRef(Guint *pos) {
+ Parser *parser;
+ Object obj;
+ GBool more;
+
+ // start up a parser, parse one token
+ obj.initNull();
+ parser = new Parser(NULL,
+ new Lexer(NULL,
+ str->makeSubStream(start + *pos, gFalse, 0, &obj)),
+ gTrue);
+ parser->getObj(&obj);
+
+ // parse an old-style xref table
+ if (obj.isCmd("xref")) {
+ obj.free();
+ more = readXRefTable(parser, pos);
+
+ // parse an xref stream
+ } else if (obj.isInt()) {
+ obj.free();
+ if (!parser->getObj(&obj)->isInt()) {
+ goto err1;
+ }
+ obj.free();
+ if (!parser->getObj(&obj)->isCmd("obj")) {
+ goto err1;
+ }
+ obj.free();
+ if (!parser->getObj(&obj)->isStream()) {
+ goto err1;
+ }
+ more = readXRefStream(obj.getStream(), pos);
+ obj.free();
+
+ } else {
+ goto err1;
+ }
+
+ delete parser;
+ return more;
+
+ err1:
+ obj.free();
+ delete parser;
+ ok = gFalse;
+ return gFalse;
+}
+
+GBool XRef::readXRefTable(Parser *parser, Guint *pos) {
+ XRefEntry entry;
+ GBool more;
+ Object obj, obj2;
+ Guint pos2;
+ int first, n, newSize, i;
+
+ while (1) {
+ parser->getObj(&obj);
+ if (obj.isCmd("trailer")) {
+ obj.free();
+ break;
+ }
+ if (!obj.isInt()) {
+ goto err1;
+ }
+ first = obj.getInt();
+ obj.free();
+ if (!parser->getObj(&obj)->isInt()) {
+ goto err1;
+ }
+ n = obj.getInt();
+ obj.free();
+ if (first < 0 || n < 0 || first + n < 0) {
+ goto err1;
+ }
+ if (first + n > size) {
+ for (newSize = size ? 2 * size : 1024;
+ first + n > newSize && newSize > 0;
+ newSize <<= 1) ;
+ if (newSize < 0) {
+ goto err1;
+ }
+ entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry));
+ for (i = size; i < newSize; ++i) {
+ entries[i].offset = 0xffffffff;
+ entries[i].type = xrefEntryFree;
+ }
+ size = newSize;
+ }
+ for (i = first; i < first + n; ++i) {
+ if (!parser->getObj(&obj)->isInt()) {
+ goto err1;
+ }
+ entry.offset = (Guint)obj.getInt();
+ obj.free();
+ if (!parser->getObj(&obj)->isInt()) {
+ goto err1;
+ }
+ entry.gen = obj.getInt();
+ obj.free();
+ parser->getObj(&obj);
+ if (obj.isCmd("n")) {
+ entry.type = xrefEntryUncompressed;
+ } else if (obj.isCmd("f")) {
+ entry.type = xrefEntryFree;
+ } else {
+ goto err1;
+ }
+ obj.free();
+ if (entries[i].offset == 0xffffffff) {
+ entries[i] = entry;
+ // PDF files of patents from the IBM Intellectual Property
+ // Network have a bug: the xref table claims to start at 1
+ // instead of 0.
+ if (i == 1 && first == 1 &&
+ entries[1].offset == 0 && entries[1].gen == 65535 &&
+ entries[1].type == xrefEntryFree) {
+ i = first = 0;
+ entries[0] = entries[1];
+ entries[1].offset = 0xffffffff;
+ }
+ }
+ }
+ }
+
+ // read the trailer dictionary
+ if (!parser->getObj(&obj)->isDict()) {
+ goto err1;
+ }
+
+ // get the 'Prev' pointer
+ obj.getDict()->lookupNF("Prev", &obj2);
+ if (obj2.isInt()) {
+ *pos = (Guint)obj2.getInt();
+ more = gTrue;
+ } else if (obj2.isRef()) {
+ // certain buggy PDF generators generate "/Prev NNN 0 R" instead
+ // of "/Prev NNN"
+ *pos = (Guint)obj2.getRefNum();
+ more = gTrue;
+ } else {
+ more = gFalse;
+ }
+ obj2.free();
+
+ // save the first trailer dictionary
+ if (trailerDict.isNone()) {
+ obj.copy(&trailerDict);
+ }
+
+ // check for an 'XRefStm' key
+ if (obj.getDict()->lookup("XRefStm", &obj2)->isInt()) {
+ pos2 = (Guint)obj2.getInt();
+ readXRef(&pos2);
+ if (!ok) {
+ obj2.free();
+ goto err1;
+ }
+ }
+ obj2.free();
+
+ obj.free();
+ return more;
+
+ err1:
+ obj.free();
+ ok = gFalse;
+ return gFalse;
+}
+
+GBool XRef::readXRefStream(Stream *xrefStr, Guint *pos) {
+ Dict *dict;
+ int w[3];
+ GBool more;
+ Object obj, obj2, idx;
+ int newSize, first, n, i;
+
+ dict = xrefStr->getDict();
+
+ if (!dict->lookupNF("Size", &obj)->isInt()) {
+ goto err1;
+ }
+ newSize = obj.getInt();
+ obj.free();
+ if (newSize < 0) {
+ goto err1;
+ }
+ if (newSize > size) {
+ entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry));
+ for (i = size; i < newSize; ++i) {
+ entries[i].offset = 0xffffffff;
+ entries[i].type = xrefEntryFree;
+ }
+ size = newSize;
+ }
+
+ if (!dict->lookupNF("W", &obj)->isArray() ||
+ obj.arrayGetLength() < 3) {
+ goto err1;
+ }
+ for (i = 0; i < 3; ++i) {
+ if (!obj.arrayGet(i, &obj2)->isInt()) {
+ obj2.free();
+ goto err1;
+ }
+ w[i] = obj2.getInt();
+ obj2.free();
+ if (w[i] < 0 || w[i] > 4) {
+ goto err1;
+ }
+ }
+ obj.free();
+
+ xrefStr->reset();
+ dict->lookupNF("Index", &idx);
+ if (idx.isArray()) {
+ for (i = 0; i+1 < idx.arrayGetLength(); i += 2) {
+ if (!idx.arrayGet(i, &obj)->isInt()) {
+ idx.free();
+ goto err1;
+ }
+ first = obj.getInt();
+ obj.free();
+ if (!idx.arrayGet(i+1, &obj)->isInt()) {
+ idx.free();
+ goto err1;
+ }
+ n = obj.getInt();
+ obj.free();
+ if (first < 0 || n < 0 ||
+ !readXRefStreamSection(xrefStr, w, first, n)) {
+ idx.free();
+ goto err0;
+ }
+ }
+ } else {
+ if (!readXRefStreamSection(xrefStr, w, 0, newSize)) {
+ idx.free();
+ goto err0;
+ }
+ }
+ idx.free();
+
+ dict->lookupNF("Prev", &obj);
+ if (obj.isInt()) {
+ *pos = (Guint)obj.getInt();
+ more = gTrue;
+ } else {
+ more = gFalse;
+ }
+ obj.free();
+ if (trailerDict.isNone()) {
+ trailerDict.initDict(dict);
+ }
+
+ return more;
+
+ err1:
+ obj.free();
+ err0:
+ ok = gFalse;
+ return gFalse;
+}
+
+GBool XRef::readXRefStreamSection(Stream *xrefStr, int *w, int first, int n) {
+ Guint offset;
+ int type, gen, c, newSize, i, j;
+
+ if (first + n < 0) {
+ return gFalse;
+ }
+ if (first + n > size) {
+ for (newSize = size ? 2 * size : 1024;
+ first + n > newSize && newSize > 0;
+ newSize <<= 1) ;
+ if (newSize < 0) {
+ return gFalse;
+ }
+ entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry));
+ for (i = size; i < newSize; ++i) {
+ entries[i].offset = 0xffffffff;
+ entries[i].type = xrefEntryFree;
+ }
+ size = newSize;
+ }
+ for (i = first; i < first + n; ++i) {
+ if (w[0] == 0) {
+ type = 1;
+ } else {
+ for (type = 0, j = 0; j < w[0]; ++j) {
+ if ((c = xrefStr->getChar()) == EOF) {
+ return gFalse;
+ }
+ type = (type << 8) + c;
+ }
+ }
+ for (offset = 0, j = 0; j < w[1]; ++j) {
+ if ((c = xrefStr->getChar()) == EOF) {
+ return gFalse;
+ }
+ offset = (offset << 8) + c;
+ }
+ for (gen = 0, j = 0; j < w[2]; ++j) {
+ if ((c = xrefStr->getChar()) == EOF) {
+ return gFalse;
+ }
+ gen = (gen << 8) + c;
+ }
+ if (entries[i].offset == 0xffffffff) {
+ switch (type) {
+ case 0:
+ entries[i].offset = offset;
+ entries[i].gen = gen;
+ entries[i].type = xrefEntryFree;
+ break;
+ case 1:
+ entries[i].offset = offset;
+ entries[i].gen = gen;
+ entries[i].type = xrefEntryUncompressed;
+ break;
+ case 2:
+ entries[i].offset = offset;
+ entries[i].gen = gen;
+ entries[i].type = xrefEntryCompressed;
+ break;
+ default:
+ return gFalse;
+ }
+ }
+ }
+
+ return gTrue;
+}
+
+// Attempt to construct an xref table for a damaged file.
+GBool XRef::constructXRef() {
+ Parser *parser;
+ Object newTrailerDict, obj;
+ char buf[256];
+ Guint pos;
+ int num, gen;
+ int newSize;
+ int streamEndsSize;
+ char *p;
+ int i;
+ GBool gotRoot;
+
+ gfree(entries);
+ size = 0;
+ entries = NULL;
+
+ error(-1, "PDF file is damaged - attempting to reconstruct xref table...");
+ gotRoot = gFalse;
+ streamEndsLen = streamEndsSize = 0;
+
+ str->reset();
+ while (1) {
+ pos = str->getPos();
+ if (!str->getLine(buf, 256)) {
+ break;
+ }
+ p = buf;
+
+ // skip whitespace
+ while (*p && Lexer::isSpace(*p & 0xff)) ++p;
+
+ // got trailer dictionary
+ if (!strncmp(p, "trailer", 7)) {
+ obj.initNull();
+ parser = new Parser(NULL,
+ new Lexer(NULL,
+ str->makeSubStream(pos + 7, gFalse, 0, &obj)),
+ gFalse);
+ parser->getObj(&newTrailerDict);
+ if (newTrailerDict.isDict()) {
+ newTrailerDict.dictLookupNF("Root", &obj);
+ if (obj.isRef()) {
+ rootNum = obj.getRefNum();
+ rootGen = obj.getRefGen();
+ if (!trailerDict.isNone()) {
+ trailerDict.free();
+ }
+ newTrailerDict.copy(&trailerDict);
+ gotRoot = gTrue;
+ }
+ obj.free();
+ }
+ newTrailerDict.free();
+ delete parser;
+
+ // look for object
+ } else if (isdigit(*p)) {
+ num = atoi(p);
+ if (num > 0) {
+ do {
+ ++p;
+ } while (*p && isdigit(*p));
+ if (isspace(*p)) {
+ do {
+ ++p;
+ } while (*p && isspace(*p));
+ if (isdigit(*p)) {
+ gen = atoi(p);
+ do {
+ ++p;
+ } while (*p && isdigit(*p));
+ if (isspace(*p)) {
+ do {
+ ++p;
+ } while (*p && isspace(*p));
+ if (!strncmp(p, "obj", 3)) {
+ if (num >= size) {
+ newSize = (num + 1 + 255) & ~255;
+ if (newSize < 0) {
+ error(-1, "Bad object number");
+ return gFalse;
+ }
+ entries = (XRefEntry *)
+ greallocn(entries, newSize, sizeof(XRefEntry));
+ for (i = size; i < newSize; ++i) {
+ entries[i].offset = 0xffffffff;
+ entries[i].type = xrefEntryFree;
+ }
+ size = newSize;
+ }
+ if (entries[num].type == xrefEntryFree ||
+ gen >= entries[num].gen) {
+ entries[num].offset = pos - start;
+ entries[num].gen = gen;
+ entries[num].type = xrefEntryUncompressed;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ } else if (!strncmp(p, "endstream", 9)) {
+ if (streamEndsLen == streamEndsSize) {
+ streamEndsSize += 64;
+ streamEnds = (Guint *)greallocn(streamEnds,
+ streamEndsSize, sizeof(int));
+ }
+ streamEnds[streamEndsLen++] = pos;
+ }
+ }
+
+ if (gotRoot)
+ return gTrue;
+
+ error(-1, "Couldn't find trailer dictionary");
+ return gFalse;
+}
+
+void XRef::setEncryption(int permFlagsA, GBool ownerPasswordOkA,
+ Guchar *fileKeyA, int keyLengthA, int encVersionA,
+ CryptAlgorithm encAlgorithmA) {
+ int i;
+
+ encrypted = gTrue;
+ permFlags = permFlagsA;
+ ownerPasswordOk = ownerPasswordOkA;
+ if (keyLengthA <= 16) {
+ keyLength = keyLengthA;
+ } else {
+ keyLength = 16;
+ }
+ for (i = 0; i < keyLength; ++i) {
+ fileKey[i] = fileKeyA[i];
+ }
+ encVersion = encVersionA;
+ encAlgorithm = encAlgorithmA;
+}
+
+GBool XRef::okToPrint(GBool ignoreOwnerPW) {
+ return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permPrint);
+}
+
+GBool XRef::okToChange(GBool ignoreOwnerPW) {
+ return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permChange);
+}
+
+GBool XRef::okToCopy(GBool ignoreOwnerPW) {
+ return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permCopy);
+}
+
+GBool XRef::okToAddNotes(GBool ignoreOwnerPW) {
+ return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permNotes);
+}
+
+Object *XRef::fetch(int num, int gen, Object *obj) {
+ XRefEntry *e;
+ Parser *parser;
+ Object obj1, obj2, obj3;
+
+ // check for bogus ref - this can happen in corrupted PDF files
+ if (num < 0 || num >= size) {
+ goto err;
+ }
+
+ e = &entries[num];
+ switch (e->type) {
+
+ case xrefEntryUncompressed:
+ if (e->gen != gen) {
+ goto err;
+ }
+ obj1.initNull();
+ parser = new Parser(this,
+ new Lexer(this,
+ str->makeSubStream(start + e->offset, gFalse, 0, &obj1)),
+ gTrue);
+ parser->getObj(&obj1);
+ parser->getObj(&obj2);
+ parser->getObj(&obj3);
+ if (!obj1.isInt() || obj1.getInt() != num ||
+ !obj2.isInt() || obj2.getInt() != gen ||
+ !obj3.isCmd("obj")) {
+ obj1.free();
+ obj2.free();
+ obj3.free();
+ delete parser;
+ goto err;
+ }
+ parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL,
+ encAlgorithm, keyLength, num, gen);
+ obj1.free();
+ obj2.free();
+ obj3.free();
+ delete parser;
+ break;
+
+ case xrefEntryCompressed:
+ if (gen != 0) {
+ goto err;
+ }
+ if (!objStr || objStr->getObjStrNum() != (int)e->offset) {
+ if (objStr) {
+ delete objStr;
+ }
+ objStr = new ObjectStream(this, e->offset);
+ }
+ objStr->getObject(e->gen, num, obj);
+ break;
+
+ default:
+ goto err;
+ }
+
+ return obj;
+
+ err:
+ return obj->initNull();
+}
+
+Object *XRef::getDocInfo(Object *obj) {
+ return trailerDict.dictLookup("Info", obj);
+}
+
+// Added for the pdftex project.
+Object *XRef::getDocInfoNF(Object *obj) {
+ return trailerDict.dictLookupNF("Info", obj);
+}
+
+GBool XRef::getStreamEnd(Guint streamStart, Guint *streamEnd) {
+ int a, b, m;
+
+ if (streamEndsLen == 0 ||
+ streamStart > streamEnds[streamEndsLen - 1]) {
+ return gFalse;
+ }
+
+ a = -1;
+ b = streamEndsLen - 1;
+ // invariant: streamEnds[a] < streamStart <= streamEnds[b]
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ if (streamStart <= streamEnds[m]) {
+ b = m;
+ } else {
+ a = m;
+ }
+ }
+ *streamEnd = streamEnds[b];
+ return gTrue;
+}
+
+int XRef::getNumEntry(Guint offset) const
+{
+ if (size > 0)
+ {
+ int res = 0;
+ Guint resOffset = entries[0].offset;
+ XRefEntry e;
+ for (int i = 1; i < size; ++i)
+ {
+ e = entries[i];
+ if (e.offset < offset && e.offset >= resOffset)
+ {
+ res = i;
+ resOffset = e.offset;
+ }
+ }
+ return res;
+ }
+ else return -1;
+}
+
+Guint XRef::strToUnsigned(char *s) {
+ Guint x;
+ char *p;
+ int i;
+
+ x = 0;
+ for (p = s, i = 0; *p && isdigit(*p) && i < 10; ++p, ++i) {
+ x = 10 * x + (*p - '0');
+ }
+ return x;
+}
diff --git a/kpdf/xpdf/xpdf/XRef.h b/kpdf/xpdf/xpdf/XRef.h
new file mode 100644
index 00000000..68a0e9c5
--- /dev/null
+++ b/kpdf/xpdf/xpdf/XRef.h
@@ -0,0 +1,136 @@
+//========================================================================
+//
+// XRef.h
+//
+// Copyright 1996-2003 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef XREF_H
+#define XREF_H
+
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
+#pragma interface
+#endif
+
+#include "gtypes.h"
+#include "Object.h"
+
+class Dict;
+class Stream;
+class Parser;
+class ObjectStream;
+
+//------------------------------------------------------------------------
+// XRef
+//------------------------------------------------------------------------
+
+enum XRefEntryType {
+ xrefEntryFree,
+ xrefEntryUncompressed,
+ xrefEntryCompressed
+};
+
+struct XRefEntry {
+ Guint offset;
+ int gen;
+ XRefEntryType type;
+};
+
+class XRef {
+public:
+
+ // Constructor. Read xref table from stream.
+ XRef(BaseStream *strA);
+
+ // Destructor.
+ ~XRef();
+
+ // Is xref table valid?
+ GBool isOk() { return ok; }
+
+ // Get the error code (if isOk() returns false).
+ int getErrorCode() { return errCode; }
+
+ // Set the encryption parameters.
+ void setEncryption(int permFlagsA, GBool ownerPasswordOkA,
+ Guchar *fileKeyA, int keyLengthA, int encVersionA,
+ CryptAlgorithm encAlgorithmA);
+
+ // Is the file encrypted?
+ GBool isEncrypted() { return encrypted; }
+
+ // Check various permissions.
+ GBool okToPrint(GBool ignoreOwnerPW = gFalse);
+ GBool okToChange(GBool ignoreOwnerPW = gFalse);
+ GBool okToCopy(GBool ignoreOwnerPW = gFalse);
+ GBool okToAddNotes(GBool ignoreOwnerPW = gFalse);
+
+ // Get catalog object.
+ Object *getCatalog(Object *obj) { return fetch(rootNum, rootGen, obj); }
+
+ // Fetch an indirect reference.
+ Object *fetch(int num, int gen, Object *obj);
+
+ // Return the document's Info dictionary (if any).
+ Object *getDocInfo(Object *obj);
+ Object *getDocInfoNF(Object *obj);
+
+ // Return the number of objects in the xref table.
+ int getNumObjects() { return size; }
+
+ // Return the offset of the last xref table.
+ Guint getLastXRefPos() { return lastXRefPos; }
+
+ // Return the catalog object reference.
+ int getRootNum() { return rootNum; }
+ int getRootGen() { return rootGen; }
+
+ // Get end position for a stream in a damaged file.
+ // Returns false if unknown or file is not damaged.
+ GBool getStreamEnd(Guint streamStart, Guint *streamEnd);
+
+ // Retuns the entry that belongs to the offset
+ int getNumEntry(Guint offset) const;
+
+ // Direct access.
+ int getSize() { return size; }
+ XRefEntry *getEntry(int i) { return &entries[i]; }
+ Object *getTrailerDict() { return &trailerDict; }
+
+private:
+
+ BaseStream *str; // input stream
+ Guint start; // offset in file (to allow for garbage
+ // at beginning of file)
+ XRefEntry *entries; // xref entries
+ int size; // size of <entries> array
+ int rootNum, rootGen; // catalog dict
+ GBool ok; // true if xref table is valid
+ int errCode; // error code (if <ok> is false)
+ Object trailerDict; // trailer dictionary
+ Guint lastXRefPos; // offset of last xref table
+ Guint *streamEnds; // 'endstream' positions - only used in
+ // damaged files
+ int streamEndsLen; // number of valid entries in streamEnds
+ ObjectStream *objStr; // cached object stream
+ GBool encrypted; // true if file is encrypted
+ int permFlags; // permission bits
+ GBool ownerPasswordOk; // true if owner password is correct
+ Guchar fileKey[16]; // file decryption key
+ int keyLength; // length of key, in bytes
+ int encVersion; // encryption version
+ CryptAlgorithm encAlgorithm; // encryption algorithm
+
+ Guint getStartXref();
+ GBool readXRef(Guint *pos);
+ GBool readXRefTable(Parser *parser, Guint *pos);
+ GBool readXRefStreamSection(Stream *xrefStr, int *w, int first, int n);
+ GBool readXRefStream(Stream *xrefStr, Guint *pos);
+ GBool constructXRef();
+ Guint strToUnsigned(char *s);
+};
+
+#endif
diff --git a/kpdf/xpdf/xpdf/xpdf_config.h b/kpdf/xpdf/xpdf/xpdf_config.h
new file mode 100644
index 00000000..81d4dd07
--- /dev/null
+++ b/kpdf/xpdf/xpdf/xpdf_config.h
@@ -0,0 +1,112 @@
+//========================================================================
+//
+// config.h
+//
+// Copyright 1996-2007 Glyph & Cog, LLC
+//
+//========================================================================
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+//------------------------------------------------------------------------
+// version
+//------------------------------------------------------------------------
+
+// xpdf version
+#define xpdfVersion "3.02"
+#define xpdfVersionNum 3.02
+#define xpdfMajorVersion 3
+#define xpdfMinorVersion 2
+#define xpdfUpdateVersion 0
+#define xpdfMajorVersionStr "3"
+#define xpdfMinorVersionStr "2"
+#define xpdfUpdateVersionStr "0"
+
+// supported PDF version
+#define supportedPDFVersionStr "1.7"
+#define supportedPDFVersionNum 1.7
+
+// copyright notice
+#define xpdfCopyright "Copyright 1996-2007 Glyph & Cog, LLC"
+
+// Windows resource file stuff
+#define winxpdfVersion "WinXpdf 3.02"
+#define xpdfCopyrightAmp "Copyright 1996-2007 Glyph && Cog, LLC"
+
+//------------------------------------------------------------------------
+// paper size
+//------------------------------------------------------------------------
+
+// default paper size (in points) for PostScript output
+#ifdef A4_PAPER
+#define defPaperWidth 595 // ISO A4 (210x297 mm)
+#define defPaperHeight 842
+#else
+#define defPaperWidth 612 // American letter (8.5x11")
+#define defPaperHeight 792
+#endif
+
+//------------------------------------------------------------------------
+// config file (xpdfrc) path
+//------------------------------------------------------------------------
+
+// user config file name, relative to the user's home directory
+#if defined(VMS) || (defined(WIN32) && !defined(__CYGWIN32__))
+#define xpdfUserConfigFile "xpdfrc"
+#else
+#define xpdfUserConfigFile ".xpdfrc"
+#endif
+
+// system config file name (set via the configure script)
+#ifdef SYSTEM_XPDFRC
+#define xpdfSysConfigFile SYSTEM_XPDFRC
+#else
+// under Windows, we get the directory with the executable and then
+// append this file name
+#define xpdfSysConfigFile "xpdfrc"
+#endif
+
+//------------------------------------------------------------------------
+// X-related constants
+//------------------------------------------------------------------------
+
+// default maximum size of color cube to allocate
+#define defaultRGBCube 5
+
+// number of fonts (combined t1lib, FreeType, X server) to cache
+#define xOutFontCacheSize 64
+
+// number of Type 3 fonts to cache
+#define xOutT3FontCacheSize 8
+
+//------------------------------------------------------------------------
+// popen
+//------------------------------------------------------------------------
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+#define popen _popen
+#define pclose _pclose
+#endif
+
+#if defined(VMS) || defined(VMCMS) || defined(DOS) || defined(OS2) || defined(__EMX__) || defined(WIN32) || defined(__DJGPP__) || defined(MACOS)
+#define POPEN_READ_MODE "rb"
+#else
+#define POPEN_READ_MODE "r"
+#endif
+
+//------------------------------------------------------------------------
+// Win32 stuff
+//------------------------------------------------------------------------
+
+#ifdef CDECL
+#undef CDECL
+#endif
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+#define CDECL __cdecl
+#else
+#define CDECL
+#endif
+
+#endif
diff --git a/kpovmodeler/AUTHORS b/kpovmodeler/AUTHORS
new file mode 100644
index 00000000..5afc7760
--- /dev/null
+++ b/kpovmodeler/AUTHORS
@@ -0,0 +1,13 @@
+Maintainer, framework, everything:
+Andreas Zehender <zehender@kde.org>
+
+Textures:
+Luis Passos Carvalho <lpassos@oninetspeed.pt>
+
+Povray 3.5 Objects:
+Leon Pennington <leon@leonscape.co.uk>
+
+Some graphical objects:
+Philippe Van Hecke <lephiloux@tiscalinet.be>
+Leonardo Skorianez <lsk@if.ufrj.br>
+
diff --git a/kpovmodeler/BUGS b/kpovmodeler/BUGS
new file mode 100644
index 00000000..7cecd8b3
--- /dev/null
+++ b/kpovmodeler/BUGS
@@ -0,0 +1,5 @@
+Known bugs in kpovmodeler in version 0.2
+--------
+
+None at the moment
+
diff --git a/kpovmodeler/COPYING b/kpovmodeler/COPYING
new file mode 100644
index 00000000..54754ab4
--- /dev/null
+++ b/kpovmodeler/COPYING
@@ -0,0 +1,341 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/kpovmodeler/ChangeLog b/kpovmodeler/ChangeLog
new file mode 100644
index 00000000..9ad06f1f
--- /dev/null
+++ b/kpovmodeler/ChangeLog
@@ -0,0 +1,83 @@
+Version 0.0.1:
+ - Development release
+ - Framework is finished
+ - Some basic objects and textures
+
+Version 0.1
+ - First release for the public
+ - Most textures are supported
+ - All simple objects are supported
+ - Rendering the scene with povray inside the program
+ - Textures can be previewed inside the dialog view
+ - The camera supports now focal blur and all complex projections
+ - The camera view can render all projections except the omnimax projection
+
+Version 0.1.1
+ - Bugfix release
+ - Fixed bugs:
+ - A bug that causes the program to crash during rendering
+ - A bug that causes the program to hang during auto scroll
+ - "Revert file" now works
+
+Version 0.2
+ - Ported to Qt 3.0 / KDE 3.0, moved to the kdegraphics package
+ - Dock widgets
+ - Qt OpenGL extension removed
+ - Key navigation in the tree view
+ - Compressed document format
+ - Fixed bugs:
+ - Validation check for the depth edit in the pattern edit
+ - Texture preview didn't serialize all needed declares
+ - "File close" follows the style guide
+
+Version 1.0
+ - View layouts
+ - User documentation
+
+Version 1.1
+ - Plugin framework (work in progress)
+ - Object and texture library (work in progress)
+ - new --no-dri command line option and configuration dialog to
+ disable direct rendering
+ - First characters of comments are used as description in the tree view
+ - The user is asked if pending changes should be saved before rendering
+ - Nicer render speed values
+ - Empty line before comments in povray output
+ - Control point selection in the properties view for bicubic patch,
+ sor, lathe and prism
+ - Export flag for graphical objects and the camera
+ - Removed the glut dependency
+ - Added Heightfield Viewstructure
+ - Light object gained, parallel, circular and orient options
+ - Dispersion options added to interior
+ - Added Noise generator options to global settings and patterns
+ - New warp types added
+ - Added accuracy setting to normals
+ - Added new finish options
+ - New objects:
+ - Isosurface
+ - Sphere sweep
+ - Projected through
+ - Radiosity
+ - Global photons
+ - Photons
+ - Light groups
+ - Interior textures
+ - Mesh
+
+Version 1.1.1
+ - Added graphical editing to Mesh object
+ - Updated Media too handle new methods and options
+ - Added new patterns cells, additional crackle options, julia,
+ additional mandel options, and slope
+ - Added keywords no_image, no_reflection, and double_illuminate to
+ graphical objects
+ - Added uv mapping and uv vectors
+
+Version 1.1.2
+ - Added local and global detail levels too:
+ Sphere, Cylinder, Cone, Torus, Disc, Blob Sphere, Blob Cylinder, Lathe,
+ SOR, Prism, SQE, Sphere sweep and Heightfield.
+
+Version 1.2
+ - The user is asked if pending changes should be saved before saving or exporting
diff --git a/kpovmodeler/INSTALL b/kpovmodeler/INSTALL
new file mode 100644
index 00000000..02a4a074
--- /dev/null
+++ b/kpovmodeler/INSTALL
@@ -0,0 +1,167 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes a while. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 4. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made.
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
+
diff --git a/kpovmodeler/Makefile.am b/kpovmodeler/Makefile.am
new file mode 100644
index 00000000..4e1f3ef9
--- /dev/null
+++ b/kpovmodeler/Makefile.am
@@ -0,0 +1,251 @@
+
+INCLUDES = $(LIBFREETYPE_CFLAGS) $(all_includes)
+
+SUBDIRS = pics examples
+
+KDE_OPTIONS = nofinal
+
+####
+# common lib
+
+lib_LTLIBRARIES = libkpovmodeler.la
+libkpovmodeler_la_SOURCES = pmpart.cpp pmfactory.cpp \
+ pmview.cpp pmshell.cpp pmobjectdrag.cpp \
+ pmtreeview.cpp pmmessage.cpp pmtreeviewitem.cpp \
+ pmerrordialog.cpp pminsertpopup.cpp pminserterrordialog.cpp \
+ pmglview.cpp pmrendermanager.cpp pmobjectselect.cpp \
+ pmrendermodesdialog.cpp pmpovrayrenderwidget.cpp pmpovraywidget.cpp \
+ pmpovrayoutputwidget.cpp pmsettingsdialog.cpp \
+ pmcolorsettings.cpp pmgridsettings.cpp pmlayoutsettings.cpp \
+ pmobjectlibrarysettings.cpp pmobjectsettings.cpp pmpluginsettings.cpp \
+ pmpovraysettings.cpp pmpreviewsettings.cpp pmopenglsettings.cpp \
+ pmdockwidget.cpp pmdockwidget_private.cpp pmviewlayoutmanager.cpp \
+ pmviewbase.cpp pmviewfactory.cpp pmunknownview.cpp pmdragwidget.cpp \
+ \
+ pmprototypemanager.cpp \
+ pmobject.cpp pmcompositeobject.cpp \
+ pmgraphicalobject.cpp pmsolidobject.cpp \
+ pmscene.cpp pmglobalsettings.cpp pmskysphere.cpp pmrainbow.cpp \
+ pmfog.cpp pmbox.cpp pmsphere.cpp pmblob.cpp pmblobsphere.cpp \
+ pmblobcylinder.cpp pmtext.cpp pmjuliafractal.cpp \
+ pmcylinder.cpp pmcone.cpp pmtorus.cpp pmplane.cpp pmpolynom.cpp \
+ pmdisc.cpp pmbicubicpatch.cpp pmtriangle.cpp \
+ pmlathe.cpp pmprism.cpp pmsor.cpp pmsqe.cpp pmheightfield.cpp \
+ pmheightfieldroam.cpp pmcomment.cpp pmraw.cpp pmnamedobject.cpp \
+ pmtranslate.cpp pmscale.cpp pmrotate.cpp pmpovraymatrix.cpp \
+ pmcsg.cpp pmcamera.cpp pmboundedby.cpp pmclippedby.cpp \
+ pmlight.cpp pmlookslike.cpp pmprojectedthrough.cpp\
+ pmtexturebase.cpp pmtexture.cpp pmpigment.cpp \
+ pmsolidcolor.cpp pmlistpattern.cpp pmquickcolor.cpp \
+ pmpattern.cpp pmblendmapmodifiers.cpp pmtexturemap.cpp \
+ pmnormal.cpp pmslope.cpp pmwarp.cpp pmfinish.cpp \
+ pminterior.cpp pmmedia.cpp pmmaterial.cpp pmmaterialmap.cpp \
+ pmdensity.cpp pmimagemap.cpp pmbumpmap.cpp \
+ \
+ pmisosurface.cpp pmradiosity.cpp pmglobalphotons.cpp \
+ pmphotons.cpp pmlightgroup.cpp pminteriortexture.cpp \
+ pmspheresweep.cpp pmmesh.cpp pmdetailobject.cpp \
+ \
+ pmdeclare.cpp pmobjectlink.cpp \
+ pmrecursiveobjectiterator.cpp \
+ \
+ pmaddcommand.cpp pmcommandmanager.cpp pmdatachangecommand.cpp \
+ pmdeletecommand.cpp pmmovecommand.cpp \
+ \
+ pmdialogview.cpp pmdialogeditbase.cpp pmgraphicalobjectedit.cpp \
+ pmnamedobjectedit.cpp pmsolidobjectedit.cpp pmskysphereedit.cpp \
+ pmglobalsettingsedit.cpp pmrainbowedit.cpp pmfogedit.cpp \
+ pmboxedit.cpp pmsphereedit.cpp pmblobedit.cpp pmblobsphereedit.cpp \
+ pmblobcylinderedit.cpp pmtextedit.cpp pmjuliafractaledit.cpp \
+ pmcylinderedit.cpp pmconeedit.cpp pmtorusedit.cpp pmplaneedit.cpp \
+ pmpolynomedit.cpp pmheightfieldedit.cpp \
+ pmlatheedit.cpp pmprismedit.cpp pmsoredit.cpp pmsqeedit.cpp \
+ pmdiscedit.cpp pmbicubicpatchedit.cpp pmtriangleedit.cpp \
+ pmcommentedit.cpp pmrawedit.cpp \
+ pmrotateedit.cpp pmscaleedit.cpp pmtranslateedit.cpp \
+ pmpovraymatrixedit.cpp \
+ pmcsgedit.cpp pmcameraedit.cpp pmlightedit.cpp pmboundedbyedit.cpp \
+ pmclippedbyedit.cpp \
+ pmlineedits.cpp pmvectorlistedit.cpp pmcoloredit.cpp pmlinkedit.cpp \
+ pmvectoredit.cpp pmpalettevalueedit.cpp pmformulalabel.cpp \
+ pmtexturebaseedit.cpp pmtextureedit.cpp pmpigmentedit.cpp \
+ pmsolidcoloredit.cpp pmlistpatternedit.cpp pmquickcoloredit.cpp \
+ pmpatternedit.cpp pmblendmapmodifiersedit.cpp pmimagemapedit.cpp \
+ pmtexturemapedit.cpp pmbumpmapedit.cpp pmmaterialmapedit.cpp \
+ pmnormaledit.cpp pmslopeedit.cpp pmfinishedit.cpp pmwarpedit.cpp \
+ pminterioredit.cpp pmmediaedit.cpp pmmaterialedit.cpp \
+ pmdensityedit.cpp pmdeclareedit.cpp pmobjectlinkedit.cpp \
+ \
+ pmisosurfaceedit.cpp pmradiosityedit.cpp pmglobalphotonsedit.cpp \
+ pmphotonsedit.cpp pmlightgroupedit.cpp pminteriortextureedit.cpp \
+ pmspheresweepedit.cpp pmmeshedit.cpp pmdetailobjectedit.cpp \
+ \
+ pmcontrolpoint.cpp pm3dcontrolpoint.cpp pm2dcontrolpoint.cpp \
+ pmsorcontrolpoint.cpp pmtranslatecontrolpoint.cpp \
+ pmrotatecontrolpoint.cpp pmscalecontrolpoint.cpp \
+ pmvectorcontrolpoint.cpp pmdistancecontrolpoint.cpp \
+ pmplanenormalcontrolpoint.cpp \
+ \
+ pmmemento.cpp pmmapmemento.cpp pmsplinememento.cpp pmprismmemento.cpp \
+ pmpalettevaluememento.cpp \
+ \
+ pmiomanager.cpp pmpovrayformat.cpp pmpovray31format.cpp pmpovray35format.cpp \
+ pmpovray31serialization.cpp pmpovray35serialization.cpp \
+ pmscanner.cpp pmparser.cpp pmxmlparser.cpp pmpovrayparser.cpp \
+ pmserializer.cpp pmoutputdevice.cpp pmxmlhelper.cpp \
+ pmfiledialog.cpp \
+ \
+ pmpalettevalue.cpp \
+ pmvector.cpp pmmath.cpp pmmatrix.cpp pmviewstructure.cpp pmline.cpp \
+ pmcolor.cpp pmpoint.cpp pmsymboltable.cpp pmactions.cpp \
+ pmsplinesegment.cpp pmsorsegment.cpp pmpolynomexponents.cpp \
+ pmvariant.cpp pmmetaobject.cpp pmenumproperty.cpp pmface.cpp \
+ \
+ pmrendermode.cpp pmresourcelocator.cpp pmtruetypecache.cpp \
+ pmdocumentationmap.cpp pminsertrulesystem.cpp pmlibrarymanager.cpp \
+ pmlibraryhandle.cpp pmlibraryhandleedit.cpp pmlibraryobject.cpp \
+ pmlibraryentrypreview.cpp\
+ pmlibrarybrowser.cpp pmlibraryiconview.cpp pmlibraryobjectsearch.cpp \
+ pmpluginmanager.cpp \
+ pmpartiface.skel
+
+libkpovmodeler_la_LDFLAGS = $(all_libraries) -version-info 0:0:0 -no-undefined $(LIBFREETYPE_RPATH)
+libkpovmodeler_la_LIBADD = $(LIBFREETYPE_LIBS) $(LIB_KPARTS) $(GLLIB) -lXmu -lXi
+METASOURCES = AUTO
+
+noinst_HEADERS = pmpart.h pmfactory.h pmview.h pmshell.h pmobjectdrag.h \
+ pmtreeview.h pmtreeviewitem.h pmmessage.h \
+ pmerrordialog.h pminsertpopup.h pminserterrordialog.h \
+ pmglview.h pmrendermanager.h pmobjectselect.h \
+ pmrendermodesdialog.h pmpovrayrenderwidget.h pmpovraywidget.h \
+ pmpovrayoutputwidget.h pmsettingsdialog.h \
+ pmcolorsettings.h pmgridsettings.h pmlayoutsettings.h \
+ pmobjectlibrarysettings.h pmobjectsettings.h pmpluginsettings.h \
+ pmpovraysettings.h pmpreviewsettings.h pmopenglsettings.h \
+ pmdockwidget.h pmdockwidget_private.h pmviewlayoutmanager.h \
+ pmviewbase.h pmviewfactory.h pmunknownview.h pmdragwidget.h \
+ \
+ pmprototypemanager.h pmallobjects.h \
+ pmobject.h pmcompositeobject.h \
+ pmgraphicalobject.h pmsolidobject.h \
+ pmscene.h pmglobalsettings.h pmskysphere.h pmrainbow.h \
+ pmfog.h pmbox.h pmsphere.h pmblob.h pmblobsphere.h \
+ pmblobcylinder.h pmtext.h pmjuliafractal.h \
+ pmcylinder.h pmcone.h pmtorus.h pmplane.h pmpolynom.h \
+ pmdisc.h pmbicubicpatch.h pmtriangle.h \
+ pmlathe.h pmprism.h pmsor.h pmsqe.h pmheightfield.h \
+ pmheightfieldroam.h pmcomment.h pmraw.h pmnamedobject.h \
+ pmtranslate.h pmscale.h pmrotate.h pmpovraymatrix.h \
+ pmcsg.h pmcamera.h pmboundedby.h pmclippedby.h \
+ pmlight.h pmlookslike.h pmprojectedthrough.h\
+ pmtexturebase.h pmtexture.h pmpigment.h \
+ pmsolidcolor.h pmlistpattern.h pmquickcolor.h pmmaterialmap.h \
+ pmpattern.h pmblendmapmodifiers.h pmtexturemap.h pmnormal.h \
+ pmslope.h pmfinish.h pmwarp.h pminterior.h pmmedia.h pmmaterial.h \
+ pmdensity.h pmimagemap.h pmbumpmap.h pmdeclare.h pmobjectlink.h \
+ pmrecursiveobjectiterator.h \
+ \
+ pmisosurface.h pmradiosity.h pmglobalphotons.h \
+ pmphotons.h pmlightgroup.h pminteriortexture.h \
+ pmspheresweep.h pmmesh.h pmdetailobject.h \
+ \
+ pmcommand.h pmaddcommand.h pmcommandmanager.h pmdatachangecommand.h \
+ pmallcommands.h pmdeletecommand.h pmmovecommand.h \
+ \
+ pmdialogview.h pmdialogeditbase.h pmgraphicalobjectedit.h \
+ pmnamedobjectedit.h pmsolidobjectedit.h pmskysphereedit.h \
+ pmglobalsettingsedit.h pmrainbowedit.h pmfogedit.h \
+ pmboxedit.h pmsphereedit.h pmblobedit.h pmblobsphereedit.h \
+ pmblobcylinderedit.h pmtextedit.h pmjuliafractaledit.h \
+ pmcylinderedit.h pmconeedit.h pmtorusedit.h pmplaneedit.h \
+ pmpolynomedit.h pmheightfieldedit.h \
+ pmdiscedit.h pmbicubicpatchedit.h pmtriangleedit.h \
+ pmlatheedit.h pmprismedit.h pmsoredit.h pmsqeedit.h \
+ pmcommentedit.h pmrawedit.h \
+ pmrotateedit.h pmscaleedit.h pmtranslateedit.h \
+ pmpovraymatrixedit.h \
+ pmcsgedit.h pmcameraedit.h pmlightedit.h pmboundedbyedit.h \
+ pmclippedbyedit.h \
+ pmlineedits.h pmvectorlistedit.h pmcoloredit.h pmlinkedit.h \
+ pmvectoredit.h pmpalettevalueedit.h pmformulalabel.h \
+ pmtexturebaseedit.h pmtextureedit.h pmpigmentedit.h \
+ pmsolidcoloredit.h pmlistpatternedit.h pmquickcoloredit.h \
+ pmpatternedit.h pmblendmapmodifiersedit.h pmimagemapedit.h \
+ pmtexturemapedit.h pmbumpmapedit.h pmmaterialmapedit.h \
+ pmnormaledit.h pmslopeedit.h pmfinishedit.h pmwarpedit.h \
+ pminterioredit.h pmmediaedit.h pmmaterialedit.h pmdensityedit.h \
+ pmdeclareedit.h pmobjectlinkedit.h \
+ \
+ pmisosurfaceedit.h pmradiosityedit.h pmglobalphotonsedit.h \
+ pmphotonsedit.h pmlightgroupedit.h pminteriortextureedit.h \
+ pmspheresweepedit.h pmmeshedit.h pmdetailobjectedit.h \
+ \
+ pmcontrolpoint.h pm3dcontrolpoint.h pm2dcontrolpoint.h \
+ pmsorcontrolpoint.h pmtranslatecontrolpoint.h \
+ pmrotatecontrolpoint.h pmscalecontrolpoint.h \
+ pmvectorcontrolpoint.h pmdistancecontrolpoint.h \
+ pmplanenormalcontrolpoint.h \
+ \
+ pmmemento.h pmmapmemento.h pmsplinememento.h pmprismmemento.h \
+ pmpalettevaluememento.h \
+ \
+ pmiomanager.h pmpovrayformat.h pmpovray31format.h pmpovray35format.h \
+ pmpovray31serialization.h pmpovray35serialization.h \
+ pmtokens.h pmscanner.h \
+ pmparser.h pmxmlparser.h pmpovrayparser.h \
+ pmserializer.h pmoutputdevice.h pmxmlhelper.h \
+ pmfiledialog.h \
+ \
+ pmerrorflags.h pmpalettevalue.h \
+ pmvector.h pmmath.h pmmatrix.h pmviewstructure.h pmline.h \
+ pmcolor.h pmpoint.h pmvalue.h pmsymboltable.h pmactions.h \
+ pmobjectaction.h pmsplinesegment.h pmsorsegment.h pmpolynomexponents.h \
+ pmface.h \
+ \
+ pmrendermode.h pmglobals.h pmdefaults.h pmresourcelocator.h \
+ pmtruetypecache.h pmdocumentationmap.h pminsertrulesystem.h \
+ pmlibrarymanager.h pmlibraryhandle.h pmlibraryhandleedit.h \
+ pmlibraryobject.h pmlibrarybrowser.h pmlibraryiconview.h \
+ pmlibraryentrypreview.h\
+ pmlibraryobjectsearch.h \
+ pmpluginmanager.h \
+ \
+ version.h pmdocumentformat.h pmdebug.h pmpartiface.h
+
+####
+# the part
+
+kde_module_LTLIBRARIES = libkpovmodelerpart.la
+
+libkpovmodelerpart_la_SOURCES = dummy.cpp
+libkpovmodelerpart_la_LIBADD = libkpovmodeler.la
+libkpovmodelerpart_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+
+####
+# the executable
+
+bin_PROGRAMS = kpovmodeler
+
+kpovmodeler_SOURCES = main.cpp
+kpovmodeler_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+kpovmodeler_LDADD = libkpovmodeler.la
+
+dummy.cpp:
+ echo > dummy.cpp
+
+rcdir = $(kde_datadir)/kpovmodeler
+rc_DATA = kpovmodelershell.rc kpovmodelerui.rc kpovmodelerbrowser.rc \
+ povraydocmap.xml baseinsertrules.xml questionmark.png
+
+
+EXTRA_DIST = kpovmodeler.desktop
+
+
+# make messages.po. Move this one to ../po/ and "make merge" in po
+# the -x is for skipping messages already translated in kdelibs
+messages: rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/kpovmodeler.pot
+
+KDE_ICON = kpovmodeler_doc kpovmodeler
+
+xdg_apps_DATA = kpovmodeler.desktop
diff --git a/kpovmodeler/README b/kpovmodeler/README
new file mode 100644
index 00000000..209fde03
--- /dev/null
+++ b/kpovmodeler/README
@@ -0,0 +1,3 @@
+KPovModeler: A graphical editor for povray scenes
+
+See http://www.kpovmodeler.org
diff --git a/kpovmodeler/REQUIREMENTS b/kpovmodeler/REQUIREMENTS
new file mode 100644
index 00000000..17987faa
--- /dev/null
+++ b/kpovmodeler/REQUIREMENTS
@@ -0,0 +1,19 @@
+Requirements for KPovModeler 1.0
+--------------------------------
+
+The program requires:
+
+- KDE-3.0 with header files
+
+- Qt-3.0.2 with header files
+
+- Freetype2 (Text view structures will be disabled otherwise)
+
+- OpenGL, glut, glu, glx libraries and header files
+
+- The Qt OpenGL extension is _NOT_ required any more!
+
+If you still have problems compiling the application,
+visit http://www.kpovmodeler.org/install.html
+or contact the KPovModeler developers
+http://www.kpovmodeler.org/contact.html
diff --git a/kpovmodeler/StyleConvention b/kpovmodeler/StyleConvention
new file mode 100644
index 00000000..eddc404f
--- /dev/null
+++ b/kpovmodeler/StyleConvention
@@ -0,0 +1,225 @@
+ Coding Style Convention
+ -------------------------
+
+This document describes the coding style convention
+used in KPovModeler.
+
+Author: Andreas Zehender <zehender@kde.org>
+Date: 16 June 2001
+
+If you edit existing files or create new ones, please follow this convention.
+This ensures that the code is consistent and clear.
+
+1) Indentation
+--------------
+
+- Use 3 spaces as basic offset. Do not use tabs for indentation.
+- Do not indent access keywords (public, protected, private) as
+ well as signal/slot keywords.
+- Do not indent braces.
+- Put braces in separate lines.
+- Indent case statements.
+
+Example:
+class abcd
+{
+public:
+ void someMethod( );
+};
+
+void abcd::someMethod( )
+{
+ if( 1 == 2 )
+ {
+ }
+ else
+ {
+ switch( x )
+ {
+ case 1:
+ y = 2;
+ break;
+ default:
+ y = -2;
+ }
+ }
+}
+
+
+2) Spacing
+----------
+
+Use many spaces.
+Use it
+- before and after brackets
+- before and after operators
+- after commas
+
+Examples:
+
+a = someMethod( ); // Notice the space between the brackets!
+b = anotherMethod( ( a + b ) / 2, 3 ) || 23456;
+if( ( a == 2 ) && !b )
+
+
+3) Type Modifiers (Pointers and References)
+-------------------------------------------
+
+Put type modifiers behind the type, not before the variable name.
+
+Example:
+
+const QString& type;
+PMObject* obj;
+
+
+4) Names
+--------
+
+Variables:
+----------
+Member variables begin with "m_".
+Static variables begin with "s_".
+Member pointers begin with "m_p".
+
+All variables begin with a lower case (member variables after the "m_").
+Use upper case character to separate different words.
+
+Examples:
+
+class abcd
+{
+ int m_firstMember;
+ char* m_pFirstMember;
+ static const char* s_pAStaticPointerToConstCharThatMeansItIsAString;
+};
+
+void abcd::efgh( )
+{
+ int aLocalVariable;
+}
+
+Classes:
+--------
+All classes start with "PM" and a upper case character.
+
+Methods:
+--------
+All methods start with a lower case character.
+
+Set methods begin with "set".
+Get methods do NOT begin with "get".
+
+Examples:
+
+int PMSPhere::centre( ) const;
+void PMSphere::setCentre( );
+
+5) KDoc Comments
+----------------
+
+Use KDoc comments to document classes.
+
+Don't add a description if you just overload a virtual function
+that doesn't add some functionality.
+
+Example:
+
+/** Returns the internal object name (not i18n'ed) */
+virtual PMObject::className( ) const;
+
+/** */
+virtual PMSphere::className( ) const;
+
+KDoc will then generate the following output:
+
+<documentation>
+PMObject* newObject ( )
+
+[const virtual]
+
+Reimplemented from PMObject.
+</documentation>
+
+
+6) Long Lines
+--------------
+Try to use only 80 characters per line.
+
+
+7) Sample .emacs File
+---------------------
+
+Here is a sample .emacs file. It is a mix of several files, so some
+things are set multiple times. But it works :-)
+
+<.emacs>
+(defconst my-c-style
+ '((c-tab-always-indent . t)
+ (c-comment-only-line-offset . 0)
+ (c-hanging-braces-alist . ((substatement-open after)
+ (brace-list-open)))
+ (c-hanging-colons-alist . ((member-init-intro before)
+ (inher-intro)
+ (case-label after)
+ (label after)
+ (access-label after)))
+ (c-cleanup-list . (scope-operator
+ empty-defun-braces
+ defun-close-semi))
+ (c-offsets-alist . ((arglist-close . c-lineup-arglist)
+ (substatement-open . 0)
+ (case-label . +)
+ (block-open . 0)
+ (knr-argdecl-intro . -)
+ (inline-open . 0)))
+ (c-echo-syntactic-information-p . t)
+ )
+ "My C Programming Style")
+
+;; Customizations for all of c-mode, c++-mode, and objc-mode
+(defun my-c-mode-common-hook ()
+ ;; add my personal style and set it for the current buffer
+ (c-add-style "PERSONAL" my-c-style t)
+ ;; offset customizations not in my-c-style
+ (c-set-offset 'member-init-intro '++)
+ ;; other customizations
+ (setq tab-width 8
+ ;; this will make sure spaces are used instead of tabs
+ indent-tabs-mode nil)
+ (setq c-basic-offset 3)
+ ;; we like auto-newline and hungry-delete
+ (c-toggle-hungry-state 1)
+ ;; keybindings for C, C++, and Objective-C. We can put these in
+ ;; c-mode-map because c++-mode-map and objc-mode-map inherit it
+ (define-key c-mode-map [f9] 'compile)
+ (define-key c-mode-map [return] 'newline-and-indent)
+ (define-key c++-mode-map [f9] 'compile)
+ (define-key c++-mode-map [return] 'newline-and-indent)
+ (define-key java-mode-map [f9] 'compile)
+ (define-key java-mode-map [return] 'newline-and-indent)
+ (load-library "vc")
+
+ ;;for QT
+ (setq c-C++-access-key "\\<\\(signals\\|public\\|protected\\|private
+ \\|public slots\\|protected slots\\|private slots\\)\\>[ \t]*:")
+ ;; modify the colour of slots to match public, private, etc ...
+ (font-lock-add-keywords 'c++-mode
+ '(("\\<\\(slots\\|signals\\)\\>" . font-lock-type-face)))
+ ;; make new font for rest of qt keywords
+ (make-face 'qt-keywords-face)
+ (set-face-foreground 'qt-keywords-face "green")
+ ;; qt keywords
+ (font-lock-add-keywords 'c++-mode
+ '(("\\<Q_OBJECT\\>" . 'qt-keywords-face)))
+ (font-lock-add-keywords 'c++-mode
+ '(("\\<SIGNAL\\|SLOT\\>" . 'qt-keywords-face)))
+ (font-lock-add-keywords 'c++-mode
+ '(("\\<Q[A-Z][A-Za-z]*" . 'qt-keywords-face)))
+ )
+
+(setq auto-mode-alist
+ (append '(("\\.h$" . c++-mode)) auto-mode-alist))
+
+</.emacs>
+
diff --git a/kpovmodeler/TODO b/kpovmodeler/TODO
new file mode 100644
index 00000000..565d19d1
--- /dev/null
+++ b/kpovmodeler/TODO
@@ -0,0 +1,52 @@
+TODO/Wishlist for kpovmodeler
+-----------------------------
+
+Tree View
+---------
+- Leave insert errors at their original position
+- Add an option to the configuration whether transformations and maybe
+ a simple pigment should be added to new graphical objects
+
+Object Properties View
+----------------------
+
+Graphical View
+--------------
+- Zoom to object short cut
+- Invert mouse wheel option
+- Remove GLUT dependency
+- Do hidden views use CPU time?
+- Heightfield wire frame
+
+Povray Render Window
+--------------------
+
+Includes
+--------
+- Finish the library
+ * Maintain the object index in PMLibraryHandle and library_index.html
+ * Eliminate crashes when modifying a library object
+ * Implement delete in the library object preview tree
+- Build an example objects library
+
+Povray Export
+-------------
+
+General
+-------
+- All not implemented objects
+- New POV-Ray 3.5 objects and textures
+- BREP modeling with the patch object (triangles and polygons, extrusion etc.)
+- Umlauts in the truetype text object
+- Scene templates
+- Add some basic render modes to a new scenes
+- Sync the recent files list between multiple windows
+- Multiplication of objects with simple transformations
+
+Long Term
+---------
+- Support for animations
+- Shaded views, csg results
+- The whole povray syntax (macros, includes, ...)
+- Support for povray variants (megapov, pvmpov)
+- Support for more renderers
diff --git a/kpovmodeler/baseinsertrules.xml b/kpovmodeler/baseinsertrules.xml
new file mode 100644
index 00000000..24aa7dd5
--- /dev/null
+++ b/kpovmodeler/baseinsertrules.xml
@@ -0,0 +1,1039 @@
+<!DOCTYPE insertrules SYSTEM "pminsertrules.dtd">
+<insertrules format="1.0">
+
+ <definegroup name="Transformations">
+ <class name="Translate"/>
+ <class name="Scale"/>
+ <class name="Rotate"/>
+ <class name="PovrayMatrix"/>
+ </definegroup>
+
+ <definegroup name="Textures">
+ <class name="Pigment"/>
+ <class name="Normal"/>
+ <class name="Finish"/>
+ <class name="Texture"/>
+ <class name="InteriorTexture"/>
+ <class name="Interior"/>
+ <class name="Material"/>
+ </definegroup>
+
+ <definegroup name="ObjectModifier">
+ <group name="Transformations"/>
+ <group name="Textures"/>
+ <class name="BoundedBy"/>
+ <class name="ClippedBy"/>
+ <class name="Photons"/>
+ </definegroup>
+
+ <targetclass name="Blob">
+ <definegroup name="ObjectModifier">
+ <group name="Transformations"/>
+ <group name="Textures"/>
+ </definegroup>
+ <definegroup name="BlobComponents">
+ <class name="BlobCylinder"/>
+ <class name="BlobSphere"/>
+ </definegroup>
+
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ <rule>
+ <group name="ObjectModifier"/>
+ <not><before><group name="BlobComponents"/></before></not>
+ </rule>
+ <rule>
+ <group name="BlobComponents"/>
+ <not><after><group name="ObjectModifier"/></after></not>
+ </rule>
+ </targetclass>
+
+ <targetclass name="BlobCylinder">
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ <group name="Transformations"/>
+ <class name="Texture"/>
+ <class name="InteriorTexture"/>
+ <class name="Pigment"/>
+ <class name="Normal"/>
+ <class name="Finish"/>
+ </rule>
+ </targetclass>
+ <targetclass name="BlobSphere">
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ <group name="Transformations"/>
+ <class name="Texture"/>
+ <class name="InteriorTexture"/>
+ <class name="Pigment"/>
+ <class name="Normal"/>
+ <class name="Finish"/>
+ </rule>
+ </targetclass>
+
+ <targetclass name="BoundedBy">
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ <class name="SolidObject"/>
+ </rule>
+ </targetclass>
+
+ <targetclass name="Camera">
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ <group name="Transformations"/>
+ <class name="Normal"/>
+ </rule>
+ </targetclass>
+
+ <targetclass name="ClippedBy">
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ <class name="SolidObject"/>
+ </rule>
+ </targetclass>
+
+ <targetclass name="CSG">
+ <definegroup name="CSGObjects">
+ <class name="GraphicalObject"/>
+ <class name="Light"/>
+ </definegroup>
+
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ <rule>
+ <group name="ObjectModifier"/>
+ <not><before><group name="CSGObjects"/></before></not>
+ </rule>
+ <rule>
+ <group name="CSGObjects"/>
+ <not><after><group name="ObjectModifier"/></after></not>
+ </rule>
+ </targetclass>
+
+ <targetclass name="LightGroup">
+ <definegroup name="LightGroupObjects">
+ <class name="GraphicalObject"/>
+ <class name="Light"/>
+ </definegroup>
+
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ <rule>
+ <group name="ObjectModifier"/>
+ <not><before><group name="LightGroupObjects"/></before></not>
+ </rule>
+ <rule>
+ <group name="LightGroupObjects"/>
+ <not><after><group name="ObjectModifier"/></after></not>
+ </rule>
+ </targetclass>
+
+ <targetclass name="Mesh">
+ <definegroup name="MeshObjects">
+ <class name="Triangle"/>
+ </definegroup>
+
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ <rule>
+ <group name="ObjectModifier"/>
+ <not><before><group name="MeshObjects"/></before></not>
+ </rule>
+ <rule>
+ <group name="MeshObjects"/>
+ <not><after><group name="ObjectModifier"/></after></not>
+ </rule>
+ </targetclass>
+
+ <targetclass name="Triangle">
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ <rule>
+ <group name="ObjectModifier"/>
+ <not><parent><class name="Mesh"/></parent></not>
+ </rule>
+ </targetclass>
+
+ <targetclass name="Declare">
+ <rule>
+ <class name="GraphicalObject"/>
+ <class name="Light"/>
+ <class name="TextureBase"/>
+ <equal>
+ <property name="numberOfChildren"/>
+ <const value="0"/>
+ </equal>
+ </rule>
+ <rule>
+ <class name="Texture"/>
+ <contains><class name="Texture"/></contains>
+ </rule>
+ <rule>
+ <class name="InteriorTexture"/>
+ <contains><class name="InteriorTexture"/></contains>
+ </rule>
+ </targetclass>
+
+ <targetclass name="Density">
+ <definegroup name="ListPattern">
+ <class name="ColorList"/>
+ <class name="DensityList"/>
+ </definegroup>
+ <definegroup name="Map">
+ <class name="ColorMap"/>
+ <class name="DensityMap"/>
+ </definegroup>
+ <definegroup name="Sum">
+ <class name="Pattern"/>
+ <group name="Map"/>
+ <class name="Warp"/>
+ <class name="SolidColor"/>
+ <group name="ListPattern"/>
+ </definegroup>
+
+ <rule>
+ <class name="SolidColor"/>
+ <class name="ColorList"/>
+ <class name="DensityList"/>
+ <not><contains><group name="Sum"/></contains></not>
+ </rule>
+ <rule>
+ <class name="Pattern"/>
+ <and>
+ <not>
+ <contains>
+ <class name="Pattern"/>
+ <group name="ListPattern"/>
+ </contains>
+ </not>
+ <not><after><group name="Map"/></after></not>
+ <not><after><class name="Warp"/></after></not>
+ <not><after><class name="BlendMapModifiers"/></after></not>
+ <not><after><group name="Transformations"/></after></not>
+ </and>
+ </rule>
+ <rule>
+ <class name="Warp"/>
+ <after><class name="Pattern"/></after>
+ </rule>
+ <rule>
+ <group name="Map"/>
+ <and>
+ <not>
+ <contains>
+ <group name="Map"/>
+ <group name="ListPattern"/>
+ <class name="SolidColor"/>
+ </contains>
+ </not>
+ <not><before><class name="Pattern"/></before></not>
+ </and>
+ </rule>
+ <rule>
+ <class name="QuickColor"/>
+ <group name="Transformations"/>
+ <not><before><class name="Pattern"/></before></not>
+ </rule>
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ </targetclass>
+
+ <targetclass name="Finish">
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ </targetclass>
+
+ <targetclass name="Fog">
+ <rule>
+ <group name="Transformations"/>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ </targetclass>
+
+ <targetclass name="GraphicalObject">
+ <exception class="CSG"/>
+ <exception class="Mesh"/>
+ <rule>
+ <group name="ObjectModifier"/>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ </targetclass>
+
+ <targetclass name="Interior">
+ <rule>
+ <class name="Media"/>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ </targetclass>
+
+ <targetclass name="Light">
+ <rule>
+ <group name="Transformations"/>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ <rule>
+ <class name="LooksLike"/>
+ <not><contains><class name="LooksLike"/></contains></not>
+ </rule>
+ <rule>
+ <class name="ProjectedThrough"/>
+ <not><contains><class name="ProjectedThrough"/></contains></not>
+ </rule>
+ <rule>
+ <class name="Photons"/>
+ <not><contains><class name="Photons"/></contains></not>
+ </rule>
+ </targetclass>
+
+ <targetclass name="ColorList">
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ <rule>
+ <class name="SolidColor"/>
+ <or>
+ <and>
+ <equal><property name="listType"/><const value="Hexagon"/></equal>
+ <less><count><class name="SolidColor"/></count><const value="3"/></less>
+ </and>
+ <and>
+ <not><equal><property name="listType"/><const value="Hexagon"/></equal></not>
+ <less><count><class name="SolidColor"/></count><const value="2"/></less>
+ </and>
+ </or>
+ </rule>
+ </targetclass>
+
+ <targetclass name="DensityList">
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ <rule>
+ <class name="Density"/>
+ <or>
+ <and>
+ <equal><property name="listType"/><const value="Hexagon"/></equal>
+ <less><count><class name="Density"/></count><const value="3"/></less>
+ </and>
+ <and>
+ <not><equal><property name="listType"/><const value="Hexagon"/></equal></not>
+ <less><count><class name="Density"/></count><const value="2"/></less>
+ </and>
+ </or>
+ </rule>
+ </targetclass>
+
+ <targetclass name="NormalList">
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ <rule>
+ <class name="Normal"/>
+ <and>
+ <equal><property name="depth"/><const value="0.0"/></equal>
+ <or>
+ <and>
+ <equal><property name="listType"/><const value="Hexagon"/></equal>
+ <less><count><class name="Normal"/></count><const value="3"/></less>
+ </and>
+ <and>
+ <not><equal><property name="listType"/><const value="Hexagon"/></equal></not>
+ <less><count><class name="Normal"/></count><const value="2"/></less>
+ </and>
+ </or>
+ </and>
+ </rule>
+ </targetclass>
+
+ <targetclass name="PigmentList">
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ <rule>
+ <class name="Pigment"/>
+ <or>
+ <and>
+ <equal><property name="listType"/><const value="Hexagon"/></equal>
+ <less><count><class name="Pigment"/></count><const value="3"/></less>
+ </and>
+ <and>
+ <not><equal><property name="listType"/><const value="Hexagon"/></equal></not>
+ <less><count><class name="Pigment"/></count><const value="2"/></less>
+ </and>
+ </or>
+ </rule>
+ </targetclass>
+
+ <targetclass name="TextureList">
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ <rule>
+ <class name="Texture"/>
+ <or>
+ <and>
+ <equal><property name="listType"/><const value="Hexagon"/></equal>
+ <less><count><class name="Texture"/></count><const value="3"/></less>
+ </and>
+ <and>
+ <not><equal><property name="listType"/><const value="Hexagon"/></equal></not>
+ <less><count><class name="Texture"/></count><const value="2"/></less>
+ </and>
+ </or>
+ </rule>
+ </targetclass>
+
+ <targetclass name="LooksLike">
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ <rule>
+ <class name="GraphicalObject"/>
+ <not>
+ <contains>
+ <class name="GraphicalObject"/>
+ </contains>
+ </not>
+ </rule>
+ </targetclass>
+
+ <targetclass name="ProjectedThrough">
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ <rule>
+ <class name="GraphicalObject"/>
+ <not>
+ <contains>
+ <class name="GraphicalObject"/>
+ </contains>
+ </not>
+ </rule>
+ </targetclass>
+
+ <targetclass name="ProjectedThrough">
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ <rule>
+ <class name="GraphicalObject"/>
+ <not>
+ <contains>
+ <class name="GraphicalObject"/>
+ </contains>
+ </not>
+ </rule>
+ </targetclass>
+
+ <targetclass name="Material">
+ <rule>
+ <group name="Textures"/>
+ <group name="Transformations"/>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ </targetclass>
+
+ <targetclass name="MaterialMap">
+ <rule>
+ <class name="Comment"/>
+ <class name="Texture"/>
+ </rule>
+ </targetclass>
+
+ <targetclass name="Media">
+ <rule>
+ <class name="Density"/>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ </targetclass>
+
+ <targetclass name="Normal">
+ <rule>
+ <class name="BumpMap"/>
+ <not>
+ <contains>
+ <class name="BumpMap"/>
+ <class name="NormalList"/>
+ <class name="Pattern"/>
+ <class name="NormalMap"/>
+ <class name="SlopeMap"/>
+ <class name="Warp"/>
+ <class name="BlendMapModifiers"/>
+ </contains>
+ </not>
+ </rule>
+ <rule>
+ <class name="NormalList"/>
+ <not>
+ <contains>
+ <class name="BumpMap"/>
+ <class name="NormalList"/>
+ <class name="Pattern"/>
+ <class name="NormalMap"/>
+ <class name="SlopeMap"/>
+ <class name="Warp"/>
+ </contains>
+ </not>
+ </rule>
+ <rule>
+ <class name="Pattern"/>
+ <and>
+ <not>
+ <contains>
+ <class name="BumpMap"/>
+ <class name="NormalList"/>
+ <class name="Pattern"/>
+ </contains>
+ </not>
+ <not><after><class name="NormalMap"/></after></not>
+ <not><after><class name="SlopeMap"/></after></not>
+ <not><after><class name="Warp"/></after></not>
+ <not><after><class name="BlendMapModifiers"/></after></not>
+ <not><after><group name="Transformations"/></after></not>
+ </and>
+ </rule>
+ <rule>
+ <class name="Warp"/>
+ <after><class name="Pattern"/></after>
+ </rule>
+ <rule>
+ <class name="NormalMap"/>
+ <and>
+ <not>
+ <contains>
+ <class name="BumpMap"/>
+ <class name="NormalMap"/>
+ <class name="NormalList"/>
+ </contains>
+ </not>
+ <not><after><class name="SlopeMap"/></after></not>
+ <not><after><class name="BlendMapModifiers"/></after></not>
+ <not><before><class name="Pattern"/></before></not>
+ </and>
+ </rule>
+ <rule>
+ <class name="SlopeMap"/>
+ <and>
+ <not>
+ <contains>
+ <class name="BumpMap"/>
+ <class name="SlopeMap"/>
+ <class name="NormalList"/>
+ </contains>
+ </not>
+ <not><after><class name="BlendMapModifiers"/></after></not>
+ <not><after><group name="Transformations"/></after></not>
+ <not><before><class name="Pattern"/></before></not>
+ </and>
+ </rule>
+ <rule>
+ <class name="BlendMapModifiers"/>
+ <and>
+ <not><contains><class name="BlendMapModifiers"/></contains></not>
+ <or>
+ <not>
+ <contains>
+ <class name="BumpMap"/>
+ <class name="NormalMap"/>
+ <class name="SlopeMap"/>
+ </contains>
+ </not>
+ <after><class name="NormalMap"/></after>
+ <after><class name="SlopeMap"/></after>
+ </or>
+ <not><before><class name="Pattern"/></before></not>
+ <not><after><group name="Transformations"/></after></not>
+ </and>
+ </rule>
+ <rule>
+ <group name="Transformations"/>
+ <not><before><class name="Pattern"/></before></not>
+ </rule>
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ </targetclass>
+
+ <targetclass name="Pigment">
+ <definegroup name="Color">
+ <class name="SolidColor"/>
+ <class name="ImageMap"/>
+ </definegroup>
+ <definegroup name="ListPattern">
+ <class name="ColorList"/>
+ <class name="PigmentList"/>
+ </definegroup>
+ <definegroup name="Map">
+ <class name="ColorMap"/>
+ <class name="PigmentMap"/>
+ </definegroup>
+ <definegroup name="Sum">
+ <class name="Pattern"/>
+ <group name="Map"/>
+ <class name="Warp"/>
+ <group name="Color"/>
+ <group name="ListPattern"/>
+ </definegroup>
+
+ <rule>
+ <group name="Color"/>
+ <group name="ListPattern"/>
+ <not><contains><group name="Sum"/></contains></not>
+ </rule>
+ <rule>
+ <class name="Pattern"/>
+ <and>
+ <not>
+ <contains>
+ <group name="Color"/>
+ <class name="Pattern"/>
+ <group name="ListPattern"/>
+ </contains>
+ </not>
+ <not><after><group name="Map"/></after></not>
+ <not><after><class name="Warp"/></after></not>
+ <not><after><class name="BlendMapModifiers"/></after></not>
+ <not><after><group name="Transformations"/></after></not>
+ </and>
+ </rule>
+ <rule>
+ <class name="Warp"/>
+ <after><class name="Pattern"/></after>
+ </rule>
+ <rule>
+ <group name="Map"/>
+ <and>
+ <not>
+ <contains>
+ <group name="Map"/>
+ <group name="ListPattern"/>
+ <group name="Color"/>
+ </contains>
+ </not>
+ <not><before><class name="Pattern"/></before></not>
+ </and>
+ </rule>
+ <rule>
+ <class name="BlendMapModifiers"/>
+ <and>
+ <not>
+ <contains>
+ <class name="BlendMapModifiers"/>
+ <group name="Color"/>
+ </contains>
+ </not>
+ <not><before><group name="Map"/></before></not>
+ <not><before><class name="Pattern"/></before></not>
+ </and>
+ </rule>
+ <rule>
+ <class name="QuickColor"/>
+ <group name="Transformations"/>
+ <not><before><class name="Pattern"/></before></not>
+ </rule>
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ </targetclass>
+
+ <targetclass name="Rainbow">
+ <rule>
+ <class name="ColorMap"/>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ </targetclass>
+
+ <targetclass name="Scene">
+ <rule>
+ <class name="GraphicalObject"/>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ <class name="Declare"/>
+ <class name="Camera"/>
+ <class name="Light"/>
+ <class name="SkySphere"/>
+ <class name="Rainbow"/>
+ <class name="Fog"/>
+ <class name="Media"/>
+ </rule>
+ <rule>
+ <class name="GlobalSettings"/>
+ <not><contains><class name="GlobalSettings"/></contains></not>
+ </rule>
+ </targetclass>
+
+ <targetclass name="GlobalSettings">
+ <rule>
+ <class name="Radiosity"/>
+ <not><contains><class name="Radiosity"/></contains></not>
+ </rule>
+ <rule>
+ <class name="GlobalPhotons"/>
+ <not><contains><class name="GlobalPhotons"/></contains></not>
+ </rule>
+ </targetclass>
+
+ <targetclass name="SkySphere">
+ <rule>
+ <class name="Pigment"/>
+ <group name="Transformations"/>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ </targetclass>
+
+ <targetclass name="Texture">
+ <definegroup name="SumMap">
+ <class name="Pattern"/>
+ <class name="TextureMap"/>
+ <class name="Warp"/>
+ </definegroup>
+ <definegroup name="SumPigment">
+ <class name="Pigment"/>
+ <class name="Normal"/>
+ <class name="Finish"/>
+ </definegroup>
+
+ <rule>
+ <class name="MaterialMap"/>
+ <not>
+ <contains>
+ <class name="TextureList"/>
+ <group name="SumMap"/>
+ <group name="SumPigment"/>
+ </contains>
+ </not>
+ </rule>
+ <rule>
+ <class name="Pigment"/>
+ <not>
+ <contains>
+ <class name="TextureList"/>
+ <group name="SumMap"/>
+ <class name="Pigment"/>
+ <class name="MaterialMap"/>
+ </contains>
+ </not>
+ </rule>
+ <rule>
+ <class name="Normal"/>
+ <not>
+ <contains>
+ <class name="TextureList"/>
+ <group name="SumMap"/>
+ <class name="Normal"/>
+ <class name="MaterialMap"/>
+ </contains>
+ </not>
+ </rule>
+ <rule>
+ <class name="Finish"/>
+ <not>
+ <contains>
+ <class name="TextureList"/>
+ <group name="SumMap"/>
+ <class name="Finish"/>
+ <class name="MaterialMap"/>
+ </contains>
+ </not>
+ </rule>
+ <rule>
+ <class name="Pattern"/>
+ <and>
+ <not>
+ <contains>
+ <class name="Pattern"/>
+ <class name="TextureList"/>
+ <group name="SumPigment"/>
+ <class name="MaterialMap"/>
+ </contains>
+ </not>
+ <not><after><class name="TextureMap"/></after></not>
+ <not><after><class name="Warp"/></after></not>
+ <not><after><class name="BlendMapModifiers"/></after></not>
+ <not><after><group name="Transformations"/></after></not>
+ </and>
+ </rule>
+ <rule>
+ <class name="TextureMap"/>
+ <and>
+ <not>
+ <contains>
+ <class name="TextureMap"/>
+ <class name="TextureList"/>
+ <group name="SumPigment"/>
+ <class name="MaterialMap"/>
+ </contains>
+ </not>
+ <not><before><class name="Pattern"/></before></not>
+ <not><after><class name="BlendMapModifiers"/></after></not>
+ </and>
+ </rule>
+ <rule>
+ <class name="TextureList"/>
+ <not>
+ <contains>
+ <class name="TextureList"/>
+ <group name="SumMap"/>
+ <group name="SumPigment"/>
+ <class name="MaterialMap"/>
+ </contains>
+ </not>
+ </rule>
+ <rule>
+ <class name="Warp"/>
+ <after><class name="Pattern"/></after>
+ </rule>
+ <rule>
+ <group name="Transformations"/>
+ <not><before><class name="Pattern"/></before></not>
+ </rule>
+ <rule>
+ <class name="BlendMapModifiers"/>
+ <and>
+ <not>
+ <contains>
+ <class name="MaterialMap"/>
+ <class name="BlendMapModifiers"/>
+ </contains>
+ </not>
+ <not><before><class name="TextureMap"/></before></not>
+ <not><before><class name="Pattern"/></before></not>
+ <not><after><group name="Transformations"/></after></not>
+ </and>
+ </rule>
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ </targetclass>
+
+ <targetclass name="InteriorTexture">
+ <definegroup name="SumMap">
+ <class name="Pattern"/>
+ <class name="TextureMap"/>
+ <class name="Warp"/>
+ </definegroup>
+ <definegroup name="SumPigment">
+ <class name="Pigment"/>
+ <class name="Normal"/>
+ <class name="Finish"/>
+ </definegroup>
+
+ <rule>
+ <class name="MaterialMap"/>
+ <not>
+ <contains>
+ <class name="TextureList"/>
+ <group name="SumMap"/>
+ <group name="SumPigment"/>
+ </contains>
+ </not>
+ </rule>
+ <rule>
+ <class name="Pigment"/>
+ <not>
+ <contains>
+ <class name="TextureList"/>
+ <group name="SumMap"/>
+ <class name="Pigment"/>
+ <class name="MaterialMap"/>
+ </contains>
+ </not>
+ </rule>
+ <rule>
+ <class name="Normal"/>
+ <not>
+ <contains>
+ <class name="TextureList"/>
+ <group name="SumMap"/>
+ <class name="Normal"/>
+ <class name="MaterialMap"/>
+ </contains>
+ </not>
+ </rule>
+ <rule>
+ <class name="Finish"/>
+ <not>
+ <contains>
+ <class name="TextureList"/>
+ <group name="SumMap"/>
+ <class name="Finish"/>
+ <class name="MaterialMap"/>
+ </contains>
+ </not>
+ </rule>
+ <rule>
+ <class name="Pattern"/>
+ <and>
+ <not>
+ <contains>
+ <class name="Pattern"/>
+ <class name="TextureList"/>
+ <group name="SumPigment"/>
+ <class name="MaterialMap"/>
+ </contains>
+ </not>
+ <not><after><class name="TextureMap"/></after></not>
+ <not><after><class name="Warp"/></after></not>
+ <not><after><class name="BlendMapModifiers"/></after></not>
+ <not><after><group name="Transformations"/></after></not>
+ </and>
+ </rule>
+ <rule>
+ <class name="TextureMap"/>
+ <and>
+ <not>
+ <contains>
+ <class name="TextureMap"/>
+ <class name="TextureList"/>
+ <group name="SumPigment"/>
+ <class name="MaterialMap"/>
+ </contains>
+ </not>
+ <not><before><class name="Pattern"/></before></not>
+ <not><after><class name="BlendMapModifiers"/></after></not>
+ </and>
+ </rule>
+ <rule>
+ <class name="TextureList"/>
+ <not>
+ <contains>
+ <class name="TextureList"/>
+ <group name="SumMap"/>
+ <group name="SumPigment"/>
+ <class name="MaterialMap"/>
+ </contains>
+ </not>
+ </rule>
+ <rule>
+ <class name="Warp"/>
+ <after><class name="Pattern"/></after>
+ </rule>
+ <rule>
+ <group name="Transformations"/>
+ <not><before><class name="Pattern"/></before></not>
+ </rule>
+ <rule>
+ <class name="BlendMapModifiers"/>
+ <and>
+ <not>
+ <contains>
+ <class name="MaterialMap"/>
+ <class name="BlendMapModifiers"/>
+ </contains>
+ </not>
+ <not><before><class name="TextureMap"/></before></not>
+ <not><before><class name="Pattern"/></before></not>
+ <not><after><group name="Transformations"/></after></not>
+ </and>
+ </rule>
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ </targetclass>
+
+ <targetclass name="TextureMap">
+ <rule>
+ <class name="Texture"/>
+ <equal><property name="hasLinkedObject"/><const value="false"/></equal>
+ </rule>
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ </targetclass>
+
+ <targetclass name="PigmentMap">
+ <rule>
+ <class name="Pigment"/>
+ <equal><property name="hasLinkedObject"/><const value="false"/></equal>
+ </rule>
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ </targetclass>
+
+ <targetclass name="ColorMap">
+ <rule>
+ <class name="SolidColor"/>
+ <equal><property name="hasLinkedObject"/><const value="false"/></equal>
+ </rule>
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ </targetclass>
+
+ <targetclass name="NormalMap">
+ <rule>
+ <class name="Normal"/>
+ <equal><property name="hasLinkedObject"/><const value="false"/></equal>
+ </rule>
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ </targetclass>
+
+ <targetclass name="SlopeMap">
+ <rule>
+ <class name="Slope"/>
+ <equal><property name="hasLinkedObject"/><const value="false"/></equal>
+ </rule>
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ </targetclass>
+
+ <targetclass name="DensityMap">
+ <rule>
+ <class name="Density"/>
+ <equal><property name="hasLinkedObject"/><const value="false"/></equal>
+ </rule>
+ <rule>
+ <class name="Comment"/>
+ <class name="Raw"/>
+ </rule>
+ </targetclass>
+</insertrules>
diff --git a/kpovmodeler/configure.in.bot b/kpovmodeler/configure.in.bot
new file mode 100644
index 00000000..da816798
--- /dev/null
+++ b/kpovmodeler/configure.in.bot
@@ -0,0 +1,37 @@
+if test "$KPOVMODELER_OPENGL" = "no"; then
+ if test "$have_gl_headers" = "no"; then
+ echo ""
+ echo "You are missing"
+ if test "$ac_cv_header_GL_gl_h" = "no"; then
+ echo " - OpenGL (mesa)"
+ fi
+ if test "$ac_cv_header_GL_glu_h" = "no"; then
+ echo " - GLU"
+ fi
+ if test "$ac_cv_header_GL_glx_h" = "no"; then
+ echo " - GLX"
+ fi
+ echo "KPovModeler will not be compiled."
+ echo "You can download them from"
+ echo "http://mesa3d.sf.net"
+ echo ""
+ else
+ echo ""
+ echo "Your system fails at linking a small OpenGL application!"
+ echo "KPovModeler will not be compiled."
+ echo "Check, if OpenGL and GLU are installed correctly on your system."
+ echo "For more details about this problem, look at config.log after"
+ echo "the line \"checking for GL\"."
+ echo ""
+ fi
+ all_tests=bad
+fi
+
+if test -z "$LIBFREETYPE_LIBS"; then
+ echo ""
+ echo "You're missing freetype2. KPovModeler will not display true type texts."
+ echo "You can download it from"
+ echo "http://www.freetype.org"
+ echo ""
+ all_tests=bad
+fi
diff --git a/kpovmodeler/configure.in.in b/kpovmodeler/configure.in.in
new file mode 100644
index 00000000..34ae508f
--- /dev/null
+++ b/kpovmodeler/configure.in.in
@@ -0,0 +1,60 @@
+have_gl_headers=yes
+can_link_gl=yes
+KPOVMODELER_OPENGL=yes;
+
+KDE_CHECK_HEADERS(GL/gl.h GL/glu.h GL/glx.h)
+if test "$ac_cv_header_GL_gl_h" = "no"; then
+ have_gl_headers=no;
+fi
+if test "$ac_cv_header_GL_glu_h" = "no"; then
+ have_gl_headers=no;
+fi
+if test "$ac_cv_header_GL_glx_h" = "no"; then
+ have_gl_headers=no;
+fi
+
+if test "$have_gl_headers" = "yes"; then
+ AC_HAVE_GL( can_link_gl=yes, can_link_gl=no )
+fi
+
+if test "$have_gl_headers" = "no"; then
+ KPOVMODELER_OPENGL=no;
+fi
+if test "$can_link_gl" = "no"; then
+ KPOVMODELER_OPENGL=no;
+fi
+
+if test "$KPOVMODELER_OPENGL" = "no"; then
+ DO_NOT_COMPILE="$DO_NOT_COMPILE kpovmodeler"
+fi
+
+
+KDE_FIND_PATH(freetype-config, FREETYPE_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin])
+
+if test -n "$FREETYPE_CONFIG"; then
+ vers=`$FREETYPE_CONFIG --version 2>/dev/null | sed -e 's/libfreetype //' | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'`
+ if test -n "$vers" && test "$vers" -ge 5000000
+ then
+ LIBFREETYPE_LIBS="`$FREETYPE_CONFIG --libs`"
+ LIBFREETYPE_RPATH=
+ for args in $LIBFREETYPE_LIBS; do
+ case $args in
+ -L*)
+ LIBFREETYPE_RPATH="$LIBFREETYPE_RPATH $args"
+ ;;
+ esac
+ done
+ LIBFREETYPE_RPATH=`echo $LIBFREETYPE_RPATH | sed -e "s/-L/-R/g"`
+ LIBFREETYPE_CFLAGS="`$FREETYPE_CONFIG --cflags`"
+
+ AC_DEFINE_UNQUOTED(HAVE_FREETYPE, 1, [Defines if your system has the libfreetype library])
+ AC_MSG_RESULT([libraries $LIBFREETYPE_LIBS, headers $LIBFREETYPE_CFLAGS])
+ else
+ AC_MSG_WARN([You need at least libfreetype 5.0])
+ fi
+fi
+
+
+AC_SUBST(LIBFREETYPE_LIBS)
+AC_SUBST(LIBFREETYPE_CFLAGS)
+AC_SUBST(LIBFREETYPE_RPATH)
diff --git a/kpovmodeler/cr16-mime-kpovmodeler_doc.png b/kpovmodeler/cr16-mime-kpovmodeler_doc.png
new file mode 100644
index 00000000..7ece4cce
--- /dev/null
+++ b/kpovmodeler/cr16-mime-kpovmodeler_doc.png
Binary files differ
diff --git a/kpovmodeler/cr32-mime-kpovmodeler_doc.png b/kpovmodeler/cr32-mime-kpovmodeler_doc.png
new file mode 100644
index 00000000..32f0d2a5
--- /dev/null
+++ b/kpovmodeler/cr32-mime-kpovmodeler_doc.png
Binary files differ
diff --git a/kpovmodeler/cr48-mime-kpovmodeler_doc.png b/kpovmodeler/cr48-mime-kpovmodeler_doc.png
new file mode 100644
index 00000000..ec8bf13e
--- /dev/null
+++ b/kpovmodeler/cr48-mime-kpovmodeler_doc.png
Binary files differ
diff --git a/kpovmodeler/examples/Makefile.am b/kpovmodeler/examples/Makefile.am
new file mode 100644
index 00000000..4ad27f9a
--- /dev/null
+++ b/kpovmodeler/examples/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = scenes includes \ No newline at end of file
diff --git a/kpovmodeler/examples/includes/Makefile.am b/kpovmodeler/examples/includes/Makefile.am
new file mode 100644
index 00000000..9d7b21f2
--- /dev/null
+++ b/kpovmodeler/examples/includes/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = inlined original \ No newline at end of file
diff --git a/kpovmodeler/examples/includes/inlined/Makefile.am b/kpovmodeler/examples/includes/inlined/Makefile.am
new file mode 100644
index 00000000..f798eb8b
--- /dev/null
+++ b/kpovmodeler/examples/includes/inlined/Makefile.am
@@ -0,0 +1,4 @@
+exdir = $(kde_datadir)/kpovmodeler/examples/includes/inlined
+ex_DATA = chars.kpm finish.kpm glass.kpm golds.kpm metals.kpm shapes.kpm \
+ shapes2.kpm shapesq.kpm skies.kpm stars.kpm stones1.kpm stones2.kpm \
+ textures.kpm woods.kpm \ No newline at end of file
diff --git a/kpovmodeler/examples/includes/inlined/chars.kpm b/kpovmodeler/examples/includes/inlined/chars.kpm
new file mode 100644
index 00000000..606e7db0
--- /dev/null
+++ b/kpovmodeler/examples/includes/inlined/chars.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/inlined/finish.kpm b/kpovmodeler/examples/includes/inlined/finish.kpm
new file mode 100644
index 00000000..d7131c4d
--- /dev/null
+++ b/kpovmodeler/examples/includes/inlined/finish.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/inlined/glass.kpm b/kpovmodeler/examples/includes/inlined/glass.kpm
new file mode 100644
index 00000000..329b68e1
--- /dev/null
+++ b/kpovmodeler/examples/includes/inlined/glass.kpm
@@ -0,0 +1,141 @@
+<!DOCTYPE KPOVMODELER>
+<scene minorFormat="0" majorFormat="1" visibility_level="10" >
+ <extra_data>
+ <rendermode sampling_method="0" width="640" subsection="0" antialiasing="0" end_column="640" start_row="1" radiosity="0" height="480" alpha="0" start_column="1" end_row="480" aa_depth="2" aa_jitter="0" aa_jitter_amount="1" aa_threshold="0.3" quality="9" description="Default" />
+ </extra_data>
+ <comment>
+Persistence of Vision Raytracer Version 3.1
+Glass finishes and textures
+</comment>
+ <comment>Changes in ver. 3.1 moved refraction and ior to the interior statment.
+Use I_Glass in conjunction with each of the finish statments below.</comment>
+ <comment>Glass Interior</comment>
+ <declare id="I_Glass" >
+ <interior enable_fade_power="0" fade_power="0" fade_distance="0" caustics="0" ior="1.5" enable_ior="1" enable_fade_distance="0" enable_caustics="0" name="" />
+ </declare>
+ <comment>Glass Finishes</comment>
+ <declare id="F_Glass1" >
+ <finish enable_brilliance="0" enable_metallic="0" enable_exponent="0" enable_diffuse="1" metallic="1" enable_reflection="1" irid_turbulence="0" irid="0" crand="0" brilliance="1" enable_roughness="1" enable_specular="1" enable_ambient="1" irid_amount="0" reflection_exponent="1" roughness="0.001" enable_phong_size="0" enable_phong="0" irid_thickness="0" phong="0" ambient="0 0 0 0 0" reflection="0.1 0.1 0.1 0.1 0.1" diffuse="0" name="" specular="1" phongsize="40" enable_crand="0" />
+ </declare>
+ <declare id="F_Glass2" >
+ <finish enable_brilliance="0" enable_metallic="0" enable_exponent="0" enable_diffuse="1" metallic="1" enable_reflection="1" irid_turbulence="0" irid="0" crand="0" brilliance="1" enable_roughness="0" enable_specular="0" enable_ambient="1" irid_amount="0" reflection_exponent="1" roughness="0.05" enable_phong_size="1" enable_phong="1" irid_thickness="0" phong="0.3" ambient="0 0 0 0 0" reflection="0.5 0.5 0.5 0.5 0.5" diffuse="0" name="" specular="0" phongsize="60" enable_crand="0" />
+ </declare>
+ <declare id="F_Glass3" >
+ <finish enable_brilliance="0" enable_metallic="0" enable_exponent="0" enable_diffuse="1" metallic="1" enable_reflection="1" irid_turbulence="0" irid="0" crand="0" brilliance="1" enable_roughness="1" enable_specular="1" enable_ambient="1" irid_amount="0" reflection_exponent="1" roughness="0.003" enable_phong_size="1" enable_phong="1" irid_thickness="0" phong="1" ambient="0.1 0.1 0.1 0.1 0.1" reflection="0.1 0.1 0.1 0.1 0.1" diffuse="0.1" name="" specular="0.8" phongsize="400" enable_crand="0" />
+ </declare>
+ <declare id="F_Glass4" >
+ <finish enable_brilliance="0" enable_metallic="0" enable_exponent="0" enable_diffuse="1" metallic="1" enable_reflection="1" irid_turbulence="0" irid="0" crand="0" brilliance="1" enable_roughness="1" enable_specular="1" enable_ambient="1" irid_amount="0" reflection_exponent="1" roughness="0.001" enable_phong_size="0" enable_phong="0" irid_thickness="0" phong="0" ambient="0.1 0.1 0.1 0.1 0.1" reflection="0.25 0.25 0.25 0.25 0.25" diffuse="0.1" name="" specular="1" phongsize="40" enable_crand="0" />
+ </declare>
+ <comment>Glass Textures</comment>
+ <comment>Simple clear glass</comment>
+ <declare id="T_Glass1" >
+ <texture name="" >
+ <pigment name="" >
+ <solidcolor color="1 1 1 0.7 0" />
+ </pigment>
+ <finish enable_brilliance="0" enable_metallic="0" enable_exponent="0" enable_diffuse="1" metallic="1" enable_reflection="1" irid_turbulence="0" irid="0" crand="0" brilliance="1" enable_roughness="1" enable_specular="1" enable_ambient="1" irid_amount="0" reflection_exponent="1" roughness="0.001" enable_phong_size="0" enable_phong="0" irid_thickness="0" phong="0" ambient="0 0 0 0 0" reflection="0.1 0.1 0.1 0.1 0.1" diffuse="0" name="" specular="1" phongsize="40" enable_crand="0" />
+ </texture>
+ </declare>
+ <comment>More like an acrylic plastic</comment>
+ <declare id="T_Glass2" >
+ <texture name="" >
+ <pigment name="" >
+ <solidcolor color="1 1 1 1 0" />
+ </pigment>
+ <finish enable_brilliance="0" enable_metallic="0" enable_exponent="0" enable_diffuse="1" metallic="1" enable_reflection="1" irid_turbulence="0" irid="0" crand="0" brilliance="1" enable_roughness="0" enable_specular="0" enable_ambient="1" irid_amount="0" reflection_exponent="1" roughness="0.05" enable_phong_size="1" enable_phong="1" irid_thickness="0" phong="0.3" ambient="0 0 0 0 0" reflection="0.5 0.5 0.5 0.5 0.5" diffuse="0" name="" specular="0" phongsize="60" enable_crand="0" />
+ </texture>
+ </declare>
+ <comment>An excellent lead crystal glass!</comment>
+ <declare id="T_Glass3" >
+ <texture name="" >
+ <pigment name="" >
+ <solidcolor color="0.98 0.98 0.98 0.9 0" />
+ </pigment>
+ <finish enable_brilliance="0" enable_metallic="0" enable_exponent="0" enable_diffuse="1" metallic="1" enable_reflection="1" irid_turbulence="0" irid="0" crand="0" brilliance="1" enable_roughness="1" enable_specular="1" enable_ambient="1" irid_amount="0" reflection_exponent="1" roughness="0.003" enable_phong_size="1" enable_phong="1" irid_thickness="0" phong="1" ambient="0.1 0.1 0.1 0.1 0.1" reflection="0.1 0.1 0.1 0.1 0.1" diffuse="0.1" name="" specular="0.8" phongsize="400" enable_crand="0" />
+ </texture>
+ </declare>
+ <declare id="T_Glass4" >
+ <texture name="" >
+ <pigment name="" >
+ <solidcolor color="0.98 1 0.99 0.75 0" />
+ </pigment>
+ <finish enable_brilliance="0" enable_metallic="0" enable_exponent="0" enable_diffuse="1" metallic="1" enable_reflection="1" irid_turbulence="0" irid="0" crand="0" brilliance="1" enable_roughness="1" enable_specular="1" enable_ambient="1" irid_amount="0" reflection_exponent="1" roughness="0.001" enable_phong_size="0" enable_phong="0" irid_thickness="0" phong="0" ambient="0.1 0.1 0.1 0.1 0.1" reflection="0.25 0.25 0.25 0.25 0.25" diffuse="0.1" name="" specular="1" phongsize="40" enable_crand="0" />
+ </texture>
+ </declare>
+ <declare id="T_Old_Glass" >
+ <texture name="" >
+ <finish enable_brilliance="0" enable_metallic="0" enable_exponent="0" enable_diffuse="1" metallic="1" enable_reflection="1" irid_turbulence="0" irid="0" crand="0" brilliance="1" enable_roughness="1" enable_specular="1" enable_ambient="1" irid_amount="0" reflection_exponent="1" roughness="0.001" enable_phong_size="0" enable_phong="0" irid_thickness="0" phong="0" ambient="0.1 0.1 0.1 0.1 0.1" reflection="0.25 0.25 0.25 0.25 0.25" diffuse="0.1" name="" specular="1" phongsize="40" enable_crand="0" />
+ <pigment name="" >
+ <solidcolor color="0.8 0.9 0.85 0.85 0" />
+ </pigment>
+ </texture>
+ </declare>
+ <declare id="T_Winebottle_Glass" >
+ <texture name="" >
+ <finish enable_brilliance="0" enable_metallic="0" enable_exponent="0" enable_diffuse="1" metallic="1" enable_reflection="1" irid_turbulence="0" irid="0" crand="0" brilliance="1" enable_roughness="1" enable_specular="1" enable_ambient="1" irid_amount="0" reflection_exponent="1" roughness="0.001" enable_phong_size="0" enable_phong="0" irid_thickness="0" phong="0" ambient="0.1 0.1 0.1 0.1 0.1" reflection="0.25 0.25 0.25 0.25 0.25" diffuse="0.1" name="" specular="1" phongsize="40" enable_crand="0" />
+ <pigment name="" >
+ <solidcolor color="0.4 0.72 0.4 0.6 0" />
+ </pigment>
+ </texture>
+ </declare>
+ <declare id="T_Beerbottle_Glass" >
+ <texture name="" >
+ <finish enable_brilliance="0" enable_metallic="0" enable_exponent="0" enable_diffuse="1" metallic="1" enable_reflection="1" irid_turbulence="0" irid="0" crand="0" brilliance="1" enable_roughness="1" enable_specular="1" enable_ambient="1" irid_amount="0" reflection_exponent="1" roughness="0.001" enable_phong_size="0" enable_phong="0" irid_thickness="0" phong="0" ambient="0.1 0.1 0.1 0.1 0.1" reflection="0.25 0.25 0.25 0.25 0.25" diffuse="0.1" name="" specular="1" phongsize="40" enable_crand="0" />
+ <pigment name="" >
+ <solidcolor color="0.7 0.5 0.1 0.6 0" />
+ </pigment>
+ </texture>
+ </declare>
+ <comment>A few color variations on Norm's glass
+Ruby glass</comment>
+ <declare id="T_Ruby_Glass" >
+ <texture name="" >
+ <finish enable_brilliance="0" enable_metallic="0" enable_exponent="0" enable_diffuse="1" metallic="1" enable_reflection="1" irid_turbulence="0" irid="0" crand="0" brilliance="1" enable_roughness="1" enable_specular="1" enable_ambient="1" irid_amount="0" reflection_exponent="1" roughness="0.001" enable_phong_size="0" enable_phong="0" irid_thickness="0" phong="0" ambient="0.1 0.1 0.1 0.1 0.1" reflection="0.25 0.25 0.25 0.25 0.25" diffuse="0.1" name="" specular="1" phongsize="40" enable_crand="0" />
+ <pigment name="" >
+ <solidcolor color="0.9 0.1 0.2 0.8 0" />
+ </pigment>
+ </texture>
+ </declare>
+ <declare id="T_Green_Glass" >
+ <texture name="" >
+ <pigment name="" >
+ <solidcolor color="0.8 1 0.95 0.9 0" />
+ </pigment>
+ <finish enable_brilliance="0" enable_metallic="0" enable_exponent="0" enable_diffuse="1" metallic="1" enable_reflection="1" irid_turbulence="0" irid="0" crand="0" brilliance="1" enable_roughness="1" enable_specular="1" enable_ambient="1" irid_amount="0" reflection_exponent="1" roughness="0.003" enable_phong_size="1" enable_phong="1" irid_thickness="0" phong="1" ambient="0.1 0.1 0.1 0.1 0.1" reflection="0.1 0.1 0.1 0.1 0.1" diffuse="0.1" name="" specular="0.8" phongsize="400" enable_crand="0" />
+ </texture>
+ </declare>
+ <declare id="T_Dark_Green_Glass" >
+ <texture name="" >
+ <finish enable_brilliance="0" enable_metallic="0" enable_exponent="0" enable_diffuse="1" metallic="1" enable_reflection="1" irid_turbulence="0" irid="0" crand="0" brilliance="1" enable_roughness="1" enable_specular="1" enable_ambient="1" irid_amount="0" reflection_exponent="1" roughness="0.001" enable_phong_size="0" enable_phong="0" irid_thickness="0" phong="0" ambient="0.1 0.1 0.1 0.1 0.1" reflection="0.25 0.25 0.25 0.25 0.25" diffuse="0.1" name="" specular="1" phongsize="40" enable_crand="0" />
+ <pigment name="" >
+ <solidcolor color="0.1 0.7 0.8 0.8 0" />
+ </pigment>
+ </texture>
+ </declare>
+ <declare id="T_Yellow_Glass" >
+ <texture name="" >
+ <finish enable_brilliance="0" enable_metallic="0" enable_exponent="0" enable_diffuse="1" metallic="1" enable_reflection="1" irid_turbulence="0" irid="0" crand="0" brilliance="1" enable_roughness="1" enable_specular="1" enable_ambient="1" irid_amount="0" reflection_exponent="1" roughness="0.001" enable_phong_size="0" enable_phong="0" irid_thickness="0" phong="0" ambient="0.1 0.1 0.1 0.1 0.1" reflection="0.25 0.25 0.25 0.25 0.25" diffuse="0.1" name="" specular="1" phongsize="40" enable_crand="0" />
+ <pigment name="" >
+ <solidcolor color="0.8 0.8 0.2 0.8 0" />
+ </pigment>
+ </texture>
+ </declare>
+ <comment>Orange/Amber glass</comment>
+ <declare id="T_Orange_Glass" >
+ <texture name="" >
+ <finish enable_brilliance="0" enable_metallic="0" enable_exponent="0" enable_diffuse="1" metallic="1" enable_reflection="1" irid_turbulence="0" irid="0" crand="0" brilliance="1" enable_roughness="1" enable_specular="1" enable_ambient="1" irid_amount="0" reflection_exponent="1" roughness="0.001" enable_phong_size="0" enable_phong="0" irid_thickness="0" phong="0" ambient="0.1 0.1 0.1 0.1 0.1" reflection="0.25 0.25 0.25 0.25 0.25" diffuse="0.1" name="" specular="1" phongsize="40" enable_crand="0" />
+ <pigment name="" >
+ <solidcolor color="1 0.5 0 0.8 0" />
+ </pigment>
+ </texture>
+ </declare>
+ <comment>Vicks bottle, glass</comment>
+ <declare id="T_Vicksbottle_Glass" >
+ <texture name="" >
+ <finish enable_brilliance="0" enable_metallic="0" enable_exponent="0" enable_diffuse="1" metallic="1" enable_reflection="1" irid_turbulence="0" irid="0" crand="0" brilliance="1" enable_roughness="1" enable_specular="1" enable_ambient="1" irid_amount="0" reflection_exponent="1" roughness="0.001" enable_phong_size="0" enable_phong="0" irid_thickness="0" phong="0" ambient="0.1 0.1 0.1 0.1 0.1" reflection="0.25 0.25 0.25 0.25 0.25" diffuse="0.1" name="" specular="1" phongsize="40" enable_crand="0" />
+ <pigment name="" >
+ <solidcolor color="0.1 0.15 0.5 0.9 0" />
+ </pigment>
+ </texture>
+ </declare>
+</scene>
diff --git a/kpovmodeler/examples/includes/inlined/golds.kpm b/kpovmodeler/examples/includes/inlined/golds.kpm
new file mode 100644
index 00000000..91feeca0
--- /dev/null
+++ b/kpovmodeler/examples/includes/inlined/golds.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/inlined/metals.kpm b/kpovmodeler/examples/includes/inlined/metals.kpm
new file mode 100644
index 00000000..80f7f432
--- /dev/null
+++ b/kpovmodeler/examples/includes/inlined/metals.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/inlined/shapes.kpm b/kpovmodeler/examples/includes/inlined/shapes.kpm
new file mode 100644
index 00000000..0390613d
--- /dev/null
+++ b/kpovmodeler/examples/includes/inlined/shapes.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/inlined/shapes2.kpm b/kpovmodeler/examples/includes/inlined/shapes2.kpm
new file mode 100644
index 00000000..72421aef
--- /dev/null
+++ b/kpovmodeler/examples/includes/inlined/shapes2.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/inlined/shapesq.kpm b/kpovmodeler/examples/includes/inlined/shapesq.kpm
new file mode 100644
index 00000000..3aa691b6
--- /dev/null
+++ b/kpovmodeler/examples/includes/inlined/shapesq.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/inlined/skies.kpm b/kpovmodeler/examples/includes/inlined/skies.kpm
new file mode 100644
index 00000000..9c4ff952
--- /dev/null
+++ b/kpovmodeler/examples/includes/inlined/skies.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/inlined/stars.kpm b/kpovmodeler/examples/includes/inlined/stars.kpm
new file mode 100644
index 00000000..9ec844a6
--- /dev/null
+++ b/kpovmodeler/examples/includes/inlined/stars.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/inlined/stones1.kpm b/kpovmodeler/examples/includes/inlined/stones1.kpm
new file mode 100644
index 00000000..67ddadfe
--- /dev/null
+++ b/kpovmodeler/examples/includes/inlined/stones1.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/inlined/stones2.kpm b/kpovmodeler/examples/includes/inlined/stones2.kpm
new file mode 100644
index 00000000..955052e5
--- /dev/null
+++ b/kpovmodeler/examples/includes/inlined/stones2.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/inlined/textures.kpm b/kpovmodeler/examples/includes/inlined/textures.kpm
new file mode 100644
index 00000000..4f5d3dc9
--- /dev/null
+++ b/kpovmodeler/examples/includes/inlined/textures.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/inlined/woods.kpm b/kpovmodeler/examples/includes/inlined/woods.kpm
new file mode 100644
index 00000000..f5b12879
--- /dev/null
+++ b/kpovmodeler/examples/includes/inlined/woods.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/original/Makefile.am b/kpovmodeler/examples/includes/original/Makefile.am
new file mode 100644
index 00000000..544ecd09
--- /dev/null
+++ b/kpovmodeler/examples/includes/original/Makefile.am
@@ -0,0 +1,4 @@
+exdir = $(kde_datadir)/kpovmodeler/examples/includes/original
+ex_DATA = chars.kpm finish.kpm glass.kpm golds.kpm metals.kpm shapes.kpm \
+ shapes2.kpm shapesq.kpm skies.kpm stars.kpm stones1.kpm stones2.kpm \
+ textures.kpm woods.kpm \ No newline at end of file
diff --git a/kpovmodeler/examples/includes/original/chars.kpm b/kpovmodeler/examples/includes/original/chars.kpm
new file mode 100644
index 00000000..1f16af27
--- /dev/null
+++ b/kpovmodeler/examples/includes/original/chars.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/original/finish.kpm b/kpovmodeler/examples/includes/original/finish.kpm
new file mode 100644
index 00000000..57964af6
--- /dev/null
+++ b/kpovmodeler/examples/includes/original/finish.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/original/glass.kpm b/kpovmodeler/examples/includes/original/glass.kpm
new file mode 100644
index 00000000..9750c57a
--- /dev/null
+++ b/kpovmodeler/examples/includes/original/glass.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/original/golds.kpm b/kpovmodeler/examples/includes/original/golds.kpm
new file mode 100644
index 00000000..d11b632b
--- /dev/null
+++ b/kpovmodeler/examples/includes/original/golds.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/original/metals.kpm b/kpovmodeler/examples/includes/original/metals.kpm
new file mode 100644
index 00000000..c5634789
--- /dev/null
+++ b/kpovmodeler/examples/includes/original/metals.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/original/shapes.kpm b/kpovmodeler/examples/includes/original/shapes.kpm
new file mode 100644
index 00000000..e587d44b
--- /dev/null
+++ b/kpovmodeler/examples/includes/original/shapes.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/original/shapes2.kpm b/kpovmodeler/examples/includes/original/shapes2.kpm
new file mode 100644
index 00000000..206f375a
--- /dev/null
+++ b/kpovmodeler/examples/includes/original/shapes2.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/original/shapesq.kpm b/kpovmodeler/examples/includes/original/shapesq.kpm
new file mode 100644
index 00000000..416d190e
--- /dev/null
+++ b/kpovmodeler/examples/includes/original/shapesq.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/original/skies.kpm b/kpovmodeler/examples/includes/original/skies.kpm
new file mode 100644
index 00000000..e5c65c04
--- /dev/null
+++ b/kpovmodeler/examples/includes/original/skies.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/original/stars.kpm b/kpovmodeler/examples/includes/original/stars.kpm
new file mode 100644
index 00000000..b17cb306
--- /dev/null
+++ b/kpovmodeler/examples/includes/original/stars.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/original/stones1.kpm b/kpovmodeler/examples/includes/original/stones1.kpm
new file mode 100644
index 00000000..0753b49e
--- /dev/null
+++ b/kpovmodeler/examples/includes/original/stones1.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/original/stones2.kpm b/kpovmodeler/examples/includes/original/stones2.kpm
new file mode 100644
index 00000000..16438514
--- /dev/null
+++ b/kpovmodeler/examples/includes/original/stones2.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/original/textures.kpm b/kpovmodeler/examples/includes/original/textures.kpm
new file mode 100644
index 00000000..ae6cca1f
--- /dev/null
+++ b/kpovmodeler/examples/includes/original/textures.kpm
Binary files differ
diff --git a/kpovmodeler/examples/includes/original/woods.kpm b/kpovmodeler/examples/includes/original/woods.kpm
new file mode 100644
index 00000000..4cdca2ec
--- /dev/null
+++ b/kpovmodeler/examples/includes/original/woods.kpm
Binary files differ
diff --git a/kpovmodeler/examples/scenes/Makefile.am b/kpovmodeler/examples/scenes/Makefile.am
new file mode 100644
index 00000000..090e2230
--- /dev/null
+++ b/kpovmodeler/examples/scenes/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = advanced csg interior lights objects \ No newline at end of file
diff --git a/kpovmodeler/examples/scenes/advanced/Makefile.am b/kpovmodeler/examples/scenes/advanced/Makefile.am
new file mode 100644
index 00000000..42f8c53c
--- /dev/null
+++ b/kpovmodeler/examples/scenes/advanced/Makefile.am
@@ -0,0 +1,2 @@
+exdir = $(kde_datadir)/kpovmodeler/examples/scenes/advanced
+ex_DATA = ants.kpm bee.kpm ink.kpm table.kpm \ No newline at end of file
diff --git a/kpovmodeler/examples/scenes/advanced/ants.kpm b/kpovmodeler/examples/scenes/advanced/ants.kpm
new file mode 100644
index 00000000..c84bd68d
--- /dev/null
+++ b/kpovmodeler/examples/scenes/advanced/ants.kpm
Binary files differ
diff --git a/kpovmodeler/examples/scenes/advanced/bee.kpm b/kpovmodeler/examples/scenes/advanced/bee.kpm
new file mode 100644
index 00000000..9f594df3
--- /dev/null
+++ b/kpovmodeler/examples/scenes/advanced/bee.kpm
Binary files differ
diff --git a/kpovmodeler/examples/scenes/advanced/ink.kpm b/kpovmodeler/examples/scenes/advanced/ink.kpm
new file mode 100644
index 00000000..036ef168
--- /dev/null
+++ b/kpovmodeler/examples/scenes/advanced/ink.kpm
Binary files differ
diff --git a/kpovmodeler/examples/scenes/advanced/table.kpm b/kpovmodeler/examples/scenes/advanced/table.kpm
new file mode 100644
index 00000000..1fdddccd
--- /dev/null
+++ b/kpovmodeler/examples/scenes/advanced/table.kpm
Binary files differ
diff --git a/kpovmodeler/examples/scenes/csg/Makefile.am b/kpovmodeler/examples/scenes/csg/Makefile.am
new file mode 100644
index 00000000..c63d4ae8
--- /dev/null
+++ b/kpovmodeler/examples/scenes/csg/Makefile.am
@@ -0,0 +1,2 @@
+exdir = $(kde_datadir)/kpovmodeler/examples/scenes/csg
+ex_DATA = cheese.kpm emptybox.kpm heightfield.kpm \ No newline at end of file
diff --git a/kpovmodeler/examples/scenes/csg/cheese.kpm b/kpovmodeler/examples/scenes/csg/cheese.kpm
new file mode 100644
index 00000000..215ec50d
--- /dev/null
+++ b/kpovmodeler/examples/scenes/csg/cheese.kpm
Binary files differ
diff --git a/kpovmodeler/examples/scenes/csg/emptybox.kpm b/kpovmodeler/examples/scenes/csg/emptybox.kpm
new file mode 100644
index 00000000..e917ba21
--- /dev/null
+++ b/kpovmodeler/examples/scenes/csg/emptybox.kpm
Binary files differ
diff --git a/kpovmodeler/examples/scenes/csg/heightfield.kpm b/kpovmodeler/examples/scenes/csg/heightfield.kpm
new file mode 100644
index 00000000..051b25ea
--- /dev/null
+++ b/kpovmodeler/examples/scenes/csg/heightfield.kpm
Binary files differ
diff --git a/kpovmodeler/examples/scenes/interior/Makefile.am b/kpovmodeler/examples/scenes/interior/Makefile.am
new file mode 100644
index 00000000..7d8e4e22
--- /dev/null
+++ b/kpovmodeler/examples/scenes/interior/Makefile.am
@@ -0,0 +1,2 @@
+exdir = $(kde_datadir)/kpovmodeler/examples/scenes/interior
+ex_DATA = cubes.kpm media1.kpm media2.kpm media3.kpm spheres.kpm \ No newline at end of file
diff --git a/kpovmodeler/examples/scenes/interior/cubes.kpm b/kpovmodeler/examples/scenes/interior/cubes.kpm
new file mode 100644
index 00000000..30f516c9
--- /dev/null
+++ b/kpovmodeler/examples/scenes/interior/cubes.kpm
Binary files differ
diff --git a/kpovmodeler/examples/scenes/interior/media1.kpm b/kpovmodeler/examples/scenes/interior/media1.kpm
new file mode 100644
index 00000000..94938e69
--- /dev/null
+++ b/kpovmodeler/examples/scenes/interior/media1.kpm
Binary files differ
diff --git a/kpovmodeler/examples/scenes/interior/media2.kpm b/kpovmodeler/examples/scenes/interior/media2.kpm
new file mode 100644
index 00000000..bae2c746
--- /dev/null
+++ b/kpovmodeler/examples/scenes/interior/media2.kpm
Binary files differ
diff --git a/kpovmodeler/examples/scenes/interior/media3.kpm b/kpovmodeler/examples/scenes/interior/media3.kpm
new file mode 100644
index 00000000..b9215dfa
--- /dev/null
+++ b/kpovmodeler/examples/scenes/interior/media3.kpm
Binary files differ
diff --git a/kpovmodeler/examples/scenes/interior/spheres.kpm b/kpovmodeler/examples/scenes/interior/spheres.kpm
new file mode 100644
index 00000000..059bee3b
--- /dev/null
+++ b/kpovmodeler/examples/scenes/interior/spheres.kpm
Binary files differ
diff --git a/kpovmodeler/examples/scenes/lights/Makefile.am b/kpovmodeler/examples/scenes/lights/Makefile.am
new file mode 100644
index 00000000..9b1f5ad5
--- /dev/null
+++ b/kpovmodeler/examples/scenes/lights/Makefile.am
@@ -0,0 +1,2 @@
+exdir = $(kde_datadir)/kpovmodeler/examples/scenes/lights
+ex_DATA = arealight.kpm arealight2.kpm spotlight.kpm \ No newline at end of file
diff --git a/kpovmodeler/examples/scenes/lights/arealight.kpm b/kpovmodeler/examples/scenes/lights/arealight.kpm
new file mode 100644
index 00000000..d02a893d
--- /dev/null
+++ b/kpovmodeler/examples/scenes/lights/arealight.kpm
Binary files differ
diff --git a/kpovmodeler/examples/scenes/lights/arealight2.kpm b/kpovmodeler/examples/scenes/lights/arealight2.kpm
new file mode 100644
index 00000000..21d2e772
--- /dev/null
+++ b/kpovmodeler/examples/scenes/lights/arealight2.kpm
Binary files differ
diff --git a/kpovmodeler/examples/scenes/lights/spotlight.kpm b/kpovmodeler/examples/scenes/lights/spotlight.kpm
new file mode 100644
index 00000000..925fb7c3
--- /dev/null
+++ b/kpovmodeler/examples/scenes/lights/spotlight.kpm
Binary files differ
diff --git a/kpovmodeler/examples/scenes/objects/Makefile.am b/kpovmodeler/examples/scenes/objects/Makefile.am
new file mode 100644
index 00000000..bfa14dce
--- /dev/null
+++ b/kpovmodeler/examples/scenes/objects/Makefile.am
@@ -0,0 +1,3 @@
+exdir = $(kde_datadir)/kpovmodeler/examples/scenes/objects
+ex_DATA = allobjects.kpm fractals.kpm lathe.kpm prism.kpm sor.kpm \
+ superellipsoid.kpm text.kpm \ No newline at end of file
diff --git a/kpovmodeler/examples/scenes/objects/allobjects.kpm b/kpovmodeler/examples/scenes/objects/allobjects.kpm
new file mode 100644
index 00000000..10136a71
--- /dev/null
+++ b/kpovmodeler/examples/scenes/objects/allobjects.kpm
Binary files differ
diff --git a/kpovmodeler/examples/scenes/objects/fractals.kpm b/kpovmodeler/examples/scenes/objects/fractals.kpm
new file mode 100644
index 00000000..a0e83171
--- /dev/null
+++ b/kpovmodeler/examples/scenes/objects/fractals.kpm
Binary files differ
diff --git a/kpovmodeler/examples/scenes/objects/lathe.kpm b/kpovmodeler/examples/scenes/objects/lathe.kpm
new file mode 100644
index 00000000..64e8691a
--- /dev/null
+++ b/kpovmodeler/examples/scenes/objects/lathe.kpm
Binary files differ
diff --git a/kpovmodeler/examples/scenes/objects/prism.kpm b/kpovmodeler/examples/scenes/objects/prism.kpm
new file mode 100644
index 00000000..c6b5cd19
--- /dev/null
+++ b/kpovmodeler/examples/scenes/objects/prism.kpm
Binary files differ
diff --git a/kpovmodeler/examples/scenes/objects/sor.kpm b/kpovmodeler/examples/scenes/objects/sor.kpm
new file mode 100644
index 00000000..cddea81e
--- /dev/null
+++ b/kpovmodeler/examples/scenes/objects/sor.kpm
Binary files differ
diff --git a/kpovmodeler/examples/scenes/objects/superellipsoid.kpm b/kpovmodeler/examples/scenes/objects/superellipsoid.kpm
new file mode 100644
index 00000000..35810e6e
--- /dev/null
+++ b/kpovmodeler/examples/scenes/objects/superellipsoid.kpm
Binary files differ
diff --git a/kpovmodeler/examples/scenes/objects/text.kpm b/kpovmodeler/examples/scenes/objects/text.kpm
new file mode 100644
index 00000000..f7c84beb
--- /dev/null
+++ b/kpovmodeler/examples/scenes/objects/text.kpm
Binary files differ
diff --git a/kpovmodeler/hi16-app-kpovmodeler.png b/kpovmodeler/hi16-app-kpovmodeler.png
new file mode 100644
index 00000000..a6f1b945
--- /dev/null
+++ b/kpovmodeler/hi16-app-kpovmodeler.png
Binary files differ
diff --git a/kpovmodeler/hi22-app-kpovmodeler.png b/kpovmodeler/hi22-app-kpovmodeler.png
new file mode 100644
index 00000000..218417bd
--- /dev/null
+++ b/kpovmodeler/hi22-app-kpovmodeler.png
Binary files differ
diff --git a/kpovmodeler/hi32-app-kpovmodeler.png b/kpovmodeler/hi32-app-kpovmodeler.png
new file mode 100644
index 00000000..07ffa8bb
--- /dev/null
+++ b/kpovmodeler/hi32-app-kpovmodeler.png
Binary files differ
diff --git a/kpovmodeler/hi48-app-kpovmodeler.png b/kpovmodeler/hi48-app-kpovmodeler.png
new file mode 100644
index 00000000..904a39cf
--- /dev/null
+++ b/kpovmodeler/hi48-app-kpovmodeler.png
Binary files differ
diff --git a/kpovmodeler/kdoc.rules b/kpovmodeler/kdoc.rules
new file mode 100644
index 00000000..6b5d40a6
--- /dev/null
+++ b/kpovmodeler/kdoc.rules
@@ -0,0 +1,10 @@
+# These are the rules used by makekdedoc to generate the kpovmodeler
+# documentation with KDOC.
+#
+# $Id$
+
+kde_MODULES = kpovmodeler
+
+kpovmodeler_FILES = *.h
+kpovmodeler_LIBS = -lkdeui -lkparts -lkdecore -ldcop -lkfile -lkio -lqt -p
+kpovmodeler_PATH = . \ No newline at end of file
diff --git a/kpovmodeler/kpovmodeler.desktop b/kpovmodeler/kpovmodeler.desktop
new file mode 100644
index 00000000..49e0844c
--- /dev/null
+++ b/kpovmodeler/kpovmodeler.desktop
@@ -0,0 +1,59 @@
+[Desktop Entry]
+DocPath=kpovmodeler/index.html
+Exec=kpovmodeler -caption "%c" %i %m %f
+Icon=kpovmodeler
+MimeType=application/x-kpovmodeler;
+Name=KPovModeler
+Name[eo]=KPovModelilo
+Name[es]=Modelador Povray
+Name[he]=מעצב Povray
+Name[nb]=KPov-modellerer
+Name[ne]=केडीई पोभ मोडेलर
+Name[nn]=KPov-modellering
+Name[sv]=Kpovmodeler
+GenericName=Povray Modeler
+GenericName[ca]=Modelador Povray
+GenericName[cs]=Modelář Povray
+GenericName[cy]=Modelydd Povray
+GenericName[da]=Povray-modellering
+GenericName[de]=Povray-Modellierer
+GenericName[en_GB]=Povray Modeller
+GenericName[eo]=Povray-modelilo
+GenericName[es]=Modelador Povray
+GenericName[et]=Povray modelleerija
+GenericName[eu]=Povray modelatzailea
+GenericName[fa]=سازندۀ مدل Povray
+GenericName[fi]=Povray-mallintaja
+GenericName[fr]=Modeleur Povray
+GenericName[gl]=Modelador Povray
+GenericName[he]=מעצב Povray
+GenericName[hu]=Povray-modellező
+GenericName[is]=Povray hönnuður
+GenericName[it]=Modellatore per Povray
+GenericName[ja]=Povray モデラー
+GenericName[kk]=Povray үлгілеу
+GenericName[km]=កម្មវិធី​ធ្វើ​ម៉ូដែល Povray
+GenericName[ms]=Pemodel Povray
+GenericName[nb]=Povray-modellerer
+GenericName[nds]=Povray-Modellmaker
+GenericName[ne]=पोभ्रे मोडेलर
+GenericName[nn]=Povray-modellering
+GenericName[pl]=Modeler Povray
+GenericName[pt]=Modelador de Povray
+GenericName[pt_BR]=Modelador Povray
+GenericName[ro]=Modelator Povray
+GenericName[ru]=Редактор Povray
+GenericName[sl]=Modelirnik Povray
+GenericName[sr]=Моделар за Povray
+GenericName[sr@Latn]=Modelar za Povray
+GenericName[sv]=Modellering med Povray
+GenericName[ta]=பாவ்ரே மாடுல்லர்
+GenericName[tr]=Povray Modelleyici
+GenericName[zh_CN]=Povray 建模器
+GenericName[zh_HK]=Povray 建模器
+Path=
+ServiceTypes=KParts/ReadOnlyPart,KParts/ReadWritePart,Browser/View,KPovModeler/Document
+Terminal=false
+Type=Application
+X-KDE-Library=libkpovmodelerpart
+Categories=Qt;KDE;Graphics;
diff --git a/kpovmodeler/kpovmodelerbrowser.rc b/kpovmodeler/kpovmodelerbrowser.rc
new file mode 100644
index 00000000..9640121f
--- /dev/null
+++ b/kpovmodeler/kpovmodelerbrowser.rc
@@ -0,0 +1,21 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="KPovModelerPart" version="1">
+<MenuBar>
+ <Menu name="edit"><text>&amp;Edit</text>
+ <Action name="edit_cut"/>
+ <Action name="edit_copy"/>
+ <Action name="edit_paste"/>
+ <Action name="edit_delete"/>
+ </Menu>
+</MenuBar>
+
+<ToolBar name="mainToolBar">
+ <Action name="edit_undo"/>
+ <Action name="edit_redo"/>
+ <Separator/>
+ <Action name="edit_cut"/>
+ <Action name="edit_copy"/>
+ <Action name="edit_paste"/>
+ <Action name="edit_delete"/>
+</ToolBar>
+</kpartgui>
diff --git a/kpovmodeler/kpovmodelershell.rc b/kpovmodeler/kpovmodelershell.rc
new file mode 100644
index 00000000..cea9e017
--- /dev/null
+++ b/kpovmodeler/kpovmodelershell.rc
@@ -0,0 +1,58 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="KPovModelerShell" version="7">
+<MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <DefineGroup name="file_export_actions" append="save_merge"/>
+ <DefineGroup name="file_import_actions" append="open_merge"/>
+ </Menu>
+ <Menu name="edit"><text>&amp;Edit</text>
+ <MergeLocal/>
+ </Menu>
+ <Menu name="insert"><text>&amp;Insert</text>
+ <MergeLocal/>
+ </Menu>
+ <Menu name="view"><text>&amp;View</text>
+ <Action name="view_new_treeview"/>
+ <Action name="view_new_dialogview"/>
+ <Action name="view_new_librarybrowser"/>
+ <DefineGroup name="view_new_views_merge"/>
+ <Separator/>
+ <Action name="view_new_topview"/>
+ <Action name="view_new_bottomview"/>
+ <Action name="view_new_leftview"/>
+ <Action name="view_new_rightview"/>
+ <Action name="view_new_frontview"/>
+ <Action name="view_new_backview"/>
+ <Action name="view_new_cameraview"/>
+ <Separator/>
+ <Action name="view_layouts_menu"/>
+ <Action name="save_view_layout"/>
+ <Separator/>
+ <MergeLocal/>
+ </Menu>
+ <Menu name="settings"><text>&amp;Settings</text>
+ <Action name="options_show_path" append="show_merge"/>
+ </Menu>
+ <Merge/>
+</MenuBar>
+
+<ToolBar name="mainToolBar" noMerge="1"><text>Main Toolbar</text>
+ <Action name="file_new"/>
+ <Action name="file_open"/>
+ <Action name="file_save"/>
+ <Action name="file_print"/>
+ <Action name="file_print_preview"/>
+ <Action name="file_mail"/>
+ <Separator/>
+ <Merge/>
+</ToolBar>
+
+<ToolBar name="libraryToolbar" noMerge="1"><text>Library Toolbar</text>
+ <Action name="library_up"/>
+ <Action name="library_object_new"/>
+ <Action name="library_object_edit"/>
+ <Action name="library_object_delete"/>
+</ToolBar>
+
+</kpartgui>
+
diff --git a/kpovmodeler/kpovmodelerui.rc b/kpovmodeler/kpovmodelerui.rc
new file mode 100644
index 00000000..007257b6
--- /dev/null
+++ b/kpovmodeler/kpovmodelerui.rc
@@ -0,0 +1,303 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="KPovModelerPart" version="14">
+
+<MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="file_export" group="file_export_actions"/>
+ <Action name="file_import" group="file_import_actions"/>
+ </Menu>
+ <Menu name="edit"><text>&amp;Edit</text>
+ <Action name="edit_undo"/>
+ <Action name="edit_redo"/>
+ <Separator/>
+ <Action name="edit_cut"/>
+ <Action name="edit_copy"/>
+ <Action name="edit_paste"/>
+ <Action name="edit_delete"/>
+ </Menu>
+ <Menu name="insert"><text context="Insert menu">&amp;Insert</text>
+ <Action name="new_globalsettings"/>
+ <Action name="new_radiosity"/>
+ <Action name="new_globalphotons"/>
+ <Separator/>
+ <Action name="new_declare"/>
+ <Separator/>
+ <Action name="new_clippedby"/>
+ <Action name="new_boundedby"/>
+ <Separator/>
+ <Action name="new_light"/>
+ <Action name="new_lightgroup"/>
+ <Action name="new_lookslike"/>
+ <Action name="new_projectedthrough"/>
+ <Action name="new_camera"/>
+ <Separator/>
+ <Action name="new_comment"/>
+ <Action name="new_raw"/>
+ <Separator/>
+ <Menu name="finite_solid_objects"><text>Finite Solid Primitives</text>
+ <Action name="new_box"/>
+ <Action name="new_sphere"/>
+ <Action name="new_cylinder"/>
+ <Action name="new_cone"/>
+ <Action name="new_torus"/>
+ <Action name="new_superquadricellipsoid"/>
+ <Action name="new_heightfield"/>
+ <Action name="new_text"/>
+ <Action name="new_juliafractal"/>
+ <Action name="new_isosurface"/>
+ <Separator/>
+ <Action name="new_blob"/>
+ <Action name="new_blobsphere"/>
+ <Action name="new_blobcylinder"/>
+ <Separator/>
+ <Action name="new_lathe"/>
+ <Action name="new_prism"/>
+ <Action name="new_surfaceofrevolution"/>
+ <Action name="new_spheresweep"/>
+ <Separator/>
+ <Action name="new_objectlink"/>
+ </Menu>
+ <Menu name="finite_patch_objects"><text>Finite Patch Primitives</text>
+ <Action name="new_disc"/>
+ <Action name="new_bicubicpatch"/>
+ <Action name="new_triangle"/>
+ <Action name="new_mesh"/>
+ </Menu>
+ <Menu name="infinite_solid_objects"><text>Infinite Solid Primitives</text>
+ <Action name="new_plane"/>
+ <Action name="new_polynom"/>
+ </Menu>
+ <Menu name="csg_objects"><text>Constructive Solid Geometry</text>
+ <Action name="new_union"/>
+ <Action name="new_intersection"/>
+ <Action name="new_difference"/>
+ <Action name="new_merge"/>
+ </Menu>
+ <Separator/>
+ <Menu name="material_objects"><text>Material</text>
+ <Action name="new_material"/>
+ </Menu>
+ <Menu name="interior_objects"><text>Interior</text>
+ <Action name="new_interior"/>
+ <Action name="new_media"/>
+ <Action name="new_density"/>
+ <Action name="new_densitylist"/>
+ <Action name="new_densitymap"/>
+ </Menu>
+ <Menu name="texture_objects"><text>Textures</text>
+ <Action name="new_pattern"/>
+ <Action name="new_blendmapmodifiers"/>
+ <Action name="new_warp"/>
+ <Separator/>
+ <Action name="new_texture"/>
+ <Action name="new_interiortexture"/>
+ <Action name="new_texturelist"/>
+ <Action name="new_texturemap"/>
+ <Action name="new_materialmap"/>
+ <Action name="new_pigment"/>
+ <Action name="new_pigmentlist"/>
+ <Action name="new_pigmentmap"/>
+ <Action name="new_imagemap"/>
+ <Action name="new_solidcolor"/>
+ <Action name="new_colorlist"/>
+ <Action name="new_colormap"/>
+ <Action name="new_normal"/>
+ <Action name="new_normallist"/>
+ <Action name="new_normalmap"/>
+ <Action name="new_bumpmap"/>
+ <Action name="new_slope"/>
+ <Action name="new_slopemap"/>
+ <Action name="new_finish"/>
+ <Separator/>
+ <Action name="new_quickcolor"/>
+ </Menu>
+ <Menu name="photons_objects"><text>Photons</text>
+ <Action name="new_photons"/>
+ </Menu>
+ <Menu name="atmospheric_objects"><text>Atmospheric Effects</text>
+ <Action name="new_skysphere"/>
+ <Action name="new_rainbow"/>
+ <Action name="new_fog"/>
+ </Menu>
+ <Separator/>
+ <Menu name="transformation_objects"><text>Transformations</text>
+ <Action name="new_scale"/>
+ <Action name="new_rotate"/>
+ <Action name="new_translate"/>
+ <Action name="new_povraymatrix"/>
+ </Menu>
+ </Menu>
+ <Menu name="view"><text>&amp;View</text>
+ <Action name="view_render_settings"/>
+ <Action name="view_render"/>
+ <Action name="view_render_window"/>
+ <Separator/>
+ <Action name="global_detail_level"/>
+ </Menu>
+</MenuBar>
+
+<Menu name="viewPopup">
+ <Action name="view_redisplay"/>
+ <Separator/>
+ <Action name="view_pos_x"/>
+ <Action name="view_neg_x"/>
+ <Action name="view_pos_y"/>
+ <Action name="view_neg_y"/>
+ <Action name="view_pos_z"/>
+ <Action name="view_neg_z"/>
+ <Action name="view_cameras_menu"/>
+ <Separator/>
+ <Action name="view_translate"/>
+ <Action name="view_scale"/>
+ <Separator/>
+ <Action name="cp_snaptogrid"/>
+ <ActionList name="cp_commands"/>
+ <Separator/>
+ <Action name="view_control_points_menu"/>
+</Menu>
+
+<Menu name="treeViewPopup">
+ <Action name="edit_cut"/>
+ <Action name="edit_copy"/>
+ <Action name="edit_paste"/>
+ <Action name="edit_delete"/>
+</Menu>
+
+<ToolBar name="mainToolBar"><text>Main Toolbar</text>
+ <Action name="edit_undo"/>
+ <Action name="edit_redo"/>
+ <Separator/>
+ <Action name="edit_cut"/>
+ <Action name="edit_copy"/>
+ <Action name="edit_paste"/>
+ <Action name="edit_delete"/>
+</ToolBar>
+
+<ToolBar name="newSolidObjectsBar"><text>Finite Solid Primitives</text>
+ <Action name="new_box"/>
+ <Action name="new_sphere"/>
+ <Action name="new_cylinder"/>
+ <Action name="new_cone"/>
+ <Action name="new_torus"/>
+ <Action name="new_superquadricellipsoid"/>
+ <Action name="new_heightfield"/>
+ <Action name="new_text"/>
+ <Action name="new_juliafractal"/>
+ <Action name="new_isosurface"/>
+ <Separator/>
+ <Action name="new_blob"/>
+ <Action name="new_blobsphere"/>
+ <Action name="new_blobcylinder"/>
+ <Separator/>
+ <Action name="new_lathe"/>
+ <Action name="new_prism"/>
+ <Action name="new_surfaceofrevolution"/>
+ <Action name="new_spheresweep"/>
+ <Separator/>
+ <Action name="new_objectlink"/>
+</ToolBar>
+
+<ToolBar name="newCSGObjectsBar"><text>Constructive Solid Geometry</text>
+ <Action name="new_union"/>
+ <Action name="new_intersection"/>
+ <Action name="new_difference"/>
+ <Action name="new_merge"/>
+</ToolBar>
+
+<ToolBar name="newInfiniteAndPatchObjectsBar"><text>Infinite and Patch Primitives</text>
+ <Action name="new_plane"/>
+ <Action name="new_polynom"/>
+ <Separator/>
+ <Action name="new_disc"/>
+ <Action name="new_bicubicpatch"/>
+ <Action name="new_triangle"/>
+ <Action name="new_mesh"/>
+</ToolBar>
+
+<ToolBar name="newAtmosphericEffectsBar"><text>Atmospheric Effects</text>
+ <Action name="new_skysphere"/>
+ <Action name="new_rainbow"/>
+ <Action name="new_fog"/>
+</ToolBar>
+
+<ToolBar name="newMiscObjectsBar"><text>Misc Objects</text>
+ <Action name="new_declare"/>
+ <Separator/>
+ <Action name="new_clippedby"/>
+ <Action name="new_boundedby"/>
+ <Separator/>
+ <Action name="new_light"/>
+ <Action name="new_lightgroup"/>
+ <Action name="new_lookslike"/>
+ <Action name="new_projectedthrough"/>
+ <Separator/>
+ <Action name="new_camera"/>
+ <Separator/>
+ <Action name="new_globalsettings"/>
+ <Action name="new_radiosity"/>
+ <Action name="new_globalphotons"/>
+ <Separator/>
+ <Action name="new_comment"/>
+ <Action name="new_raw"/>
+</ToolBar>
+
+<ToolBar name="newTransformationsBar"><text>Transformations</text>
+ <Action name="new_scale"/>
+ <Action name="new_rotate"/>
+ <Action name="new_translate"/>
+ <Action name="new_povraymatrix"/>
+</ToolBar>
+
+<ToolBar name="newTexturesBar"><text>Textures</text>
+ <Action name="new_material"/>
+ <Separator/>
+ <Action name="new_interior"/>
+ <Action name="new_media"/>
+ <Action name="new_density"/>
+ <Action name="new_densitylist"/>
+ <Action name="new_densitymap"/>
+ <Separator/>
+ <Action name="new_pattern"/>
+ <Action name="new_blendmapmodifiers"/>
+ <Action name="new_warp"/>
+ <Separator/>
+ <Action name="new_texture"/>
+ <Action name="new_interiortexture"/>
+ <Action name="new_texturelist"/>
+ <Action name="new_texturemap"/>
+ <Action name="new_materialmap"/>
+ <Action name="new_pigment"/>
+ <Action name="new_pigmentlist"/>
+ <Action name="new_pigmentmap"/>
+ <Action name="new_imagemap"/>
+ <Action name="new_solidcolor"/>
+ <Action name="new_colorlist"/>
+ <Action name="new_colormap"/>
+ <Action name="new_normal"/>
+ <Action name="new_normallist"/>
+ <Action name="new_normalmap"/>
+ <Action name="new_bumpmap"/>
+ <Action name="new_slope"/>
+ <Action name="new_slopemap"/>
+ <Action name="new_finish"/>
+ <Separator/>
+ <Action name="new_quickcolor"/>
+ <Separator/>
+ <Action name="new_photons"/>
+</ToolBar>
+
+<ToolBar name="renderBar"><text>Povray Rendering</text>
+ <Action name="view_render_combo"/>
+ <Action name="view_render_settings"/>
+ <Action name="view_render"/>
+</ToolBar>
+
+<ToolBar name="graphicalViewsBar"><text>Graphical View</text>
+ <Action name="view_visibility_label"/>
+ <Action name="view_visibility_level"/>
+ <Separator/>
+ <Action name="global_detail_label"/>
+ <Action name="global_detail_level"/>
+</ToolBar>
+
+</kpartgui>
diff --git a/kpovmodeler/main.cpp b/kpovmodeler/main.cpp
new file mode 100644
index 00000000..8bdabf8e
--- /dev/null
+++ b/kpovmodeler/main.cpp
@@ -0,0 +1,69 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include <klocale.h>
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <kapplication.h>
+
+#include "pmshell.h"
+#include "pmfactory.h"
+#include "pmrendermanager.h"
+#include "version.h"
+
+
+static KCmdLineOptions options[] =
+{
+ { "+[file]", I18N_NOOP( "File to open" ), 0 },
+ { "no-opengl", I18N_NOOP( "Disables OpenGL rendering" ), 0 },
+ { "no-dri", I18N_NOOP( "Disables direct rendering" ), 0 },
+ KCmdLineLastOption
+};
+
+int main( int argc, char* argv[] )
+{
+ PMShell* shell = 0;
+
+ KCmdLineArgs::init( argc, argv, PMFactory::aboutData( ) );
+ KCmdLineArgs::addCmdLineOptions( options );
+
+ KApplication app;
+
+ KCmdLineArgs* args = KCmdLineArgs::parsedArgs( );
+
+ if( !args->isSet( "-opengl" ) )
+ PMRenderManager::disableOpenGL( );
+ if( !args->isSet( "-dri" ) )
+ PMGLView::enableDirectRendering( false );
+
+ if( args->count( ) > 0 )
+ {
+ for( int i = 0 ; i < args->count( ) ; i++ )
+ {
+ shell = new PMShell( args->url( i ) );
+ shell->show( );
+ }
+ }
+ else
+ {
+ shell = new PMShell;
+ shell->show( );
+ }
+ args->clear();
+ return app.exec( );
+}
diff --git a/kpovmodeler/pics/Makefile.am b/kpovmodeler/pics/Makefile.am
new file mode 100644
index 00000000..ff33151e
--- /dev/null
+++ b/kpovmodeler/pics/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = locolor crystalsvg
diff --git a/kpovmodeler/pics/crystalsvg/Makefile.am b/kpovmodeler/pics/crystalsvg/Makefile.am
new file mode 100644
index 00000000..66481ab6
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/Makefile.am
@@ -0,0 +1,2 @@
+pmtoolbardir = $(kde_datadir)/kpovmodeler/icons
+pmtoolbar_ICON = AUTO
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmaddpoint.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmaddpoint.png
new file mode 100644
index 00000000..b3c7cab4
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmaddpoint.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmaddpointabove.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmaddpointabove.png
new file mode 100644
index 00000000..4310c761
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmaddpointabove.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmaddsubprism.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmaddsubprism.png
new file mode 100644
index 00000000..ff5bca2b
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmaddsubprism.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmbicubicpatch.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmbicubicpatch.png
new file mode 100644
index 00000000..3b7baaa0
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmbicubicpatch.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmblendmapmodifiers.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmblendmapmodifiers.png
new file mode 100644
index 00000000..334867dc
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmblendmapmodifiers.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmblob.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmblob.png
new file mode 100644
index 00000000..28c7f9c4
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmblob.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmblobcylinder.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmblobcylinder.png
new file mode 100644
index 00000000..3b788ebf
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmblobcylinder.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmblobsphere.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmblobsphere.png
new file mode 100644
index 00000000..9e9e9c04
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmblobsphere.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmboundedby.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmboundedby.png
new file mode 100644
index 00000000..288769d8
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmboundedby.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmbox.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmbox.png
new file mode 100644
index 00000000..48a81471
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmbox.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmbumpmap.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmbumpmap.png
new file mode 100644
index 00000000..5221c2a9
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmbumpmap.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmcamera.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmcamera.png
new file mode 100644
index 00000000..264a4e9f
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmcamera.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmclippedby.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmclippedby.png
new file mode 100644
index 00000000..b281ac84
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmclippedby.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmcolorlist.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmcolorlist.png
new file mode 100644
index 00000000..cc3e406d
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmcolorlist.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmcolormap.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmcolormap.png
new file mode 100644
index 00000000..ed68e5e5
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmcolormap.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmcolormapdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmcolormapdeclare.png
new file mode 100644
index 00000000..3371c27a
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmcolormapdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmcomment.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmcomment.png
new file mode 100644
index 00000000..78b0a3f0
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmcomment.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmcone.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmcone.png
new file mode 100644
index 00000000..0dd88efd
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmcone.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmcylinder.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmcylinder.png
new file mode 100644
index 00000000..753453b2
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmcylinder.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmdeclare.png
new file mode 100644
index 00000000..36c277d5
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmdensity.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmdensity.png
new file mode 100644
index 00000000..98b91daa
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmdensity.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmdensitydeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmdensitydeclare.png
new file mode 100644
index 00000000..87f96d9e
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmdensitydeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmdensitylist.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmdensitylist.png
new file mode 100644
index 00000000..a783751e
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmdensitylist.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmdensitymap.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmdensitymap.png
new file mode 100644
index 00000000..dc277d2c
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmdensitymap.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmdensitymapdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmdensitymapdeclare.png
new file mode 100644
index 00000000..f22f525e
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmdensitymapdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmdialogview.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmdialogview.png
new file mode 100644
index 00000000..e48cb253
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmdialogview.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmdifference.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmdifference.png
new file mode 100644
index 00000000..d2551828
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmdifference.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmdisc.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmdisc.png
new file mode 100644
index 00000000..c39115c4
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmdisc.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmdrag.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmdrag.png
new file mode 100644
index 00000000..65aba8ba
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmdrag.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmfinish.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmfinish.png
new file mode 100644
index 00000000..d014f144
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmfinish.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmfinishdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmfinishdeclare.png
new file mode 100644
index 00000000..b0e77f59
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmfinishdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmfog.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmfog.png
new file mode 100644
index 00000000..5d7acae0
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmfog.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmfogdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmfogdeclare.png
new file mode 100644
index 00000000..0db954dc
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmfogdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmglobalphotons.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmglobalphotons.png
new file mode 100644
index 00000000..1e6d4144
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmglobalphotons.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmglobalsettings.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmglobalsettings.png
new file mode 100644
index 00000000..9732e0ba
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmglobalsettings.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmglview.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmglview.png
new file mode 100644
index 00000000..7b69cea1
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmglview.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmheightfield.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmheightfield.png
new file mode 100644
index 00000000..f40f3f50
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmheightfield.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmimagemap.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmimagemap.png
new file mode 100644
index 00000000..01d8d9da
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmimagemap.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pminserterrors.png b/kpovmodeler/pics/crystalsvg/cr16-action-pminserterrors.png
new file mode 100644
index 00000000..a8edc396
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pminserterrors.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pminsertfirstchild.png b/kpovmodeler/pics/crystalsvg/cr16-action-pminsertfirstchild.png
new file mode 100644
index 00000000..5ee47f17
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pminsertfirstchild.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pminsertlastchild.png b/kpovmodeler/pics/crystalsvg/cr16-action-pminsertlastchild.png
new file mode 100644
index 00000000..cc7193f7
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pminsertlastchild.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pminsertsibling.png b/kpovmodeler/pics/crystalsvg/cr16-action-pminsertsibling.png
new file mode 100644
index 00000000..a0bca16f
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pminsertsibling.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pminterior.png b/kpovmodeler/pics/crystalsvg/cr16-action-pminterior.png
new file mode 100644
index 00000000..76a003df
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pminterior.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pminteriordeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pminteriordeclare.png
new file mode 100644
index 00000000..18781544
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pminteriordeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pminteriortexture.png b/kpovmodeler/pics/crystalsvg/cr16-action-pminteriortexture.png
new file mode 100644
index 00000000..0de1c19b
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pminteriortexture.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pminteriortexturedeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pminteriortexturedeclare.png
new file mode 100644
index 00000000..801ecda9
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pminteriortexturedeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmintersection.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmintersection.png
new file mode 100644
index 00000000..954eae50
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmintersection.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmisosurface.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmisosurface.png
new file mode 100644
index 00000000..59dbdc05
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmisosurface.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmjuliafractal.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmjuliafractal.png
new file mode 100644
index 00000000..66b6cad0
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmjuliafractal.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmlathe.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmlathe.png
new file mode 100644
index 00000000..bd316870
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmlathe.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmlight.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmlight.png
new file mode 100644
index 00000000..e6e0d098
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmlight.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmlightgroup.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmlightgroup.png
new file mode 100644
index 00000000..105ca083
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmlightgroup.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmlistpattern.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmlistpattern.png
new file mode 100644
index 00000000..cd68aa2a
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmlistpattern.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmlookslike.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmlookslike.png
new file mode 100644
index 00000000..3b511673
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmlookslike.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmmaterial.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmmaterial.png
new file mode 100644
index 00000000..af492025
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmmaterial.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmmaterialdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmmaterialdeclare.png
new file mode 100644
index 00000000..aa9ba10b
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmmaterialdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmmaterialmap.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmmaterialmap.png
new file mode 100644
index 00000000..f46a9fb2
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmmaterialmap.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmmatrix.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmmatrix.png
new file mode 100644
index 00000000..32f4f298
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmmatrix.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmmedia.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmmedia.png
new file mode 100644
index 00000000..4b72046c
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmmedia.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmmediadeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmmediadeclare.png
new file mode 100644
index 00000000..e43b3948
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmmediadeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmmerge.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmmerge.png
new file mode 100644
index 00000000..04e71ed2
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmmerge.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmmesh.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmmesh.png
new file mode 100644
index 00000000..3ab5de1a
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmmesh.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmnormal.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmnormal.png
new file mode 100644
index 00000000..99979725
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmnormal.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmnormaldeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmnormaldeclare.png
new file mode 100644
index 00000000..e148abc3
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmnormaldeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmnormallist.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmnormallist.png
new file mode 100644
index 00000000..4f4fea88
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmnormallist.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmnormalmap.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmnormalmap.png
new file mode 100644
index 00000000..6d12407b
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmnormalmap.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmnormalmapdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmnormalmapdeclare.png
new file mode 100644
index 00000000..09c6d28e
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmnormalmapdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmobjectdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmobjectdeclare.png
new file mode 100644
index 00000000..cd562250
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmobjectdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmobjectlink.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmobjectlink.png
new file mode 100644
index 00000000..479664f6
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmobjectlink.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmpattern.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmpattern.png
new file mode 100644
index 00000000..5032bb8d
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmpattern.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmphotons.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmphotons.png
new file mode 100644
index 00000000..b2f64977
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmphotons.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmpigment.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmpigment.png
new file mode 100644
index 00000000..e1c49853
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmpigment.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentdeclare.png
new file mode 100644
index 00000000..15af344d
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentlist.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentlist.png
new file mode 100644
index 00000000..26aa2908
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentlist.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentmap.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentmap.png
new file mode 100644
index 00000000..32e1c4e6
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentmap.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentmapdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentmapdeclare.png
new file mode 100644
index 00000000..2ff2d59d
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmpigmentmapdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmplane.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmplane.png
new file mode 100644
index 00000000..8e6590b0
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmplane.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmpolynom.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmpolynom.png
new file mode 100644
index 00000000..fcaf1a15
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmpolynom.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmprism.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmprism.png
new file mode 100644
index 00000000..b58f5aa8
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmprism.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmprojectedthrough.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmprojectedthrough.png
new file mode 100644
index 00000000..94b4aa4e
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmprojectedthrough.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmquickcolor.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmquickcolor.png
new file mode 100644
index 00000000..41afd2a3
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmquickcolor.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmradiosity.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmradiosity.png
new file mode 100644
index 00000000..0428f202
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmradiosity.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmrainbow.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmrainbow.png
new file mode 100644
index 00000000..271405db
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmrainbow.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmrainbowdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmrainbowdeclare.png
new file mode 100644
index 00000000..9232255c
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmrainbowdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmraw.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmraw.png
new file mode 100644
index 00000000..cb0ce235
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmraw.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmremovepoint.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmremovepoint.png
new file mode 100644
index 00000000..0be182fb
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmremovepoint.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmrender.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmrender.png
new file mode 100644
index 00000000..901a283d
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmrender.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmrenderpreview.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmrenderpreview.png
new file mode 100644
index 00000000..c14b2c38
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmrenderpreview.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmrendersettings.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmrendersettings.png
new file mode 100644
index 00000000..9a63e1a2
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmrendersettings.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmrotate.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmrotate.png
new file mode 100644
index 00000000..744f927c
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmrotate.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmscale.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmscale.png
new file mode 100644
index 00000000..ca553a0f
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmscale.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmscene.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmscene.png
new file mode 100644
index 00000000..8a4c4bd1
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmscene.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmskysphere.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmskysphere.png
new file mode 100644
index 00000000..bbfd050a
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmskysphere.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmskyspheredeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmskyspheredeclare.png
new file mode 100644
index 00000000..16cd5bb3
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmskyspheredeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmslope.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmslope.png
new file mode 100644
index 00000000..e665a1bd
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmslope.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmslopemap.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmslopemap.png
new file mode 100644
index 00000000..a757fc90
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmslopemap.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmslopemapdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmslopemapdeclare.png
new file mode 100644
index 00000000..fe7e9969
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmslopemapdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmsolidcolor.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmsolidcolor.png
new file mode 100644
index 00000000..b2f4eda7
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmsolidcolor.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmsor.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmsor.png
new file mode 100644
index 00000000..8a652ed7
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmsor.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmsphere.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmsphere.png
new file mode 100644
index 00000000..a8a38679
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmsphere.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmspheresweep.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmspheresweep.png
new file mode 100644
index 00000000..19cced4c
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmspheresweep.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmsqe.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmsqe.png
new file mode 100644
index 00000000..ea2e2a14
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmsqe.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmtext.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmtext.png
new file mode 100644
index 00000000..4b339926
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmtext.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmtexture.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmtexture.png
new file mode 100644
index 00000000..c90031ca
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmtexture.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmtexturedeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmtexturedeclare.png
new file mode 100644
index 00000000..75a77847
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmtexturedeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmtexturelist.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmtexturelist.png
new file mode 100644
index 00000000..85881a7d
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmtexturelist.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmtexturemap.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmtexturemap.png
new file mode 100644
index 00000000..171bf68d
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmtexturemap.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmtexturemapdeclare.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmtexturemapdeclare.png
new file mode 100644
index 00000000..ab2edae6
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmtexturemapdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmtorus.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmtorus.png
new file mode 100644
index 00000000..82f78511
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmtorus.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmtranslate.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmtranslate.png
new file mode 100644
index 00000000..2d16dea2
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmtranslate.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmtreeview.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmtreeview.png
new file mode 100644
index 00000000..b78f646d
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmtreeview.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmtriangle.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmtriangle.png
new file mode 100644
index 00000000..9592e253
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmtriangle.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmunion.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmunion.png
new file mode 100644
index 00000000..1407fe3a
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmunion.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr16-action-pmwarp.png b/kpovmodeler/pics/crystalsvg/cr16-action-pmwarp.png
new file mode 100644
index 00000000..c0f294cd
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr16-action-pmwarp.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmbicubicpatch.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmbicubicpatch.png
new file mode 100644
index 00000000..4dedf979
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmbicubicpatch.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmblendmapmodifiers.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmblendmapmodifiers.png
new file mode 100644
index 00000000..15fc5700
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmblendmapmodifiers.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmblob.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmblob.png
new file mode 100644
index 00000000..a165af80
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmblob.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmblobcylinder.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmblobcylinder.png
new file mode 100644
index 00000000..5dc230f9
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmblobcylinder.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmblobsphere.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmblobsphere.png
new file mode 100644
index 00000000..a43cf351
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmblobsphere.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmboundedby.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmboundedby.png
new file mode 100644
index 00000000..a8748990
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmboundedby.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmbox.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmbox.png
new file mode 100644
index 00000000..1bbdac7c
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmbox.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmbumpmap.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmbumpmap.png
new file mode 100644
index 00000000..2371d104
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmbumpmap.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmcamera.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmcamera.png
new file mode 100644
index 00000000..51e3079a
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmcamera.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmclippedby.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmclippedby.png
new file mode 100644
index 00000000..e7653cb1
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmclippedby.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmcolorlist.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmcolorlist.png
new file mode 100644
index 00000000..b94946d3
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmcolorlist.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmcolormap.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmcolormap.png
new file mode 100644
index 00000000..775db294
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmcolormap.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmcolormapdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmcolormapdeclare.png
new file mode 100644
index 00000000..d4033601
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmcolormapdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmcomment.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmcomment.png
new file mode 100644
index 00000000..348ed6fa
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmcomment.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmcone.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmcone.png
new file mode 100644
index 00000000..8cb55a7a
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmcone.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigurecolors.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigurecolors.png
new file mode 100644
index 00000000..5775bb49
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigurecolors.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguredialogview.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguredialogview.png
new file mode 100644
index 00000000..5951a63b
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguredialogview.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguregraphicalview.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguregraphicalview.png
new file mode 100644
index 00000000..87ce6705
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguregraphicalview.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguregrid.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguregrid.png
new file mode 100644
index 00000000..f378b405
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguregrid.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureobjectlibrary.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureobjectlibrary.png
new file mode 100644
index 00000000..83a72f37
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureobjectlibrary.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureobjects.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureobjects.png
new file mode 100644
index 00000000..16fc0bdf
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureobjects.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureopengl.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureopengl.png
new file mode 100644
index 00000000..03c1efca
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureopengl.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigurepovray.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigurepovray.png
new file mode 100644
index 00000000..de26c9ca
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigurepovray.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguretexturepreview.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguretexturepreview.png
new file mode 100644
index 00000000..6cd4ee02
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfiguretexturepreview.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureviewlayout.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureviewlayout.png
new file mode 100644
index 00000000..502eb876
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmconfigureviewlayout.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmcylinder.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmcylinder.png
new file mode 100644
index 00000000..7fe73163
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmcylinder.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmdeclare.png
new file mode 100644
index 00000000..840d56eb
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmdensity.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmdensity.png
new file mode 100644
index 00000000..057210fb
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmdensity.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmdensitydeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmdensitydeclare.png
new file mode 100644
index 00000000..c38fe00c
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmdensitydeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmdensitylist.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmdensitylist.png
new file mode 100644
index 00000000..3c260d9e
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmdensitylist.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmdensitymap.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmdensitymap.png
new file mode 100644
index 00000000..3aabb850
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmdensitymap.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmdensitymapdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmdensitymapdeclare.png
new file mode 100644
index 00000000..2fc8e38b
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmdensitymapdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmdifference.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmdifference.png
new file mode 100644
index 00000000..0ac4238e
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmdifference.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmdisc.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmdisc.png
new file mode 100644
index 00000000..536cc8a0
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmdisc.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmdrag.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmdrag.png
new file mode 100644
index 00000000..5a5c703d
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmdrag.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmfinish.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmfinish.png
new file mode 100644
index 00000000..070f16d1
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmfinish.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmfinishdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmfinishdeclare.png
new file mode 100644
index 00000000..8d8359c5
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmfinishdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmfog.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmfog.png
new file mode 100644
index 00000000..23a5e5ee
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmfog.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmfogdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmfogdeclare.png
new file mode 100644
index 00000000..df4460d1
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmfogdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmglobalphotons.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmglobalphotons.png
new file mode 100644
index 00000000..b97c1337
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmglobalphotons.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmglobalsettings.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmglobalsettings.png
new file mode 100644
index 00000000..c87764bc
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmglobalsettings.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmheightfield.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmheightfield.png
new file mode 100644
index 00000000..64b767b4
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmheightfield.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmimagemap.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmimagemap.png
new file mode 100644
index 00000000..a93604e5
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmimagemap.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pminserterrors.png b/kpovmodeler/pics/crystalsvg/cr22-action-pminserterrors.png
new file mode 100644
index 00000000..fab5a4eb
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pminserterrors.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pminterior.png b/kpovmodeler/pics/crystalsvg/cr22-action-pminterior.png
new file mode 100644
index 00000000..d3c3a66f
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pminterior.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pminteriordeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pminteriordeclare.png
new file mode 100644
index 00000000..20c5880e
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pminteriordeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pminteriortexture.png b/kpovmodeler/pics/crystalsvg/cr22-action-pminteriortexture.png
new file mode 100644
index 00000000..bf6b6d00
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pminteriortexture.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pminteriortexturedeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pminteriortexturedeclare.png
new file mode 100644
index 00000000..2566437f
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pminteriortexturedeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmintersection.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmintersection.png
new file mode 100644
index 00000000..edc287ff
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmintersection.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmisosurface.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmisosurface.png
new file mode 100644
index 00000000..cbbad58f
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmisosurface.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmjuliafractal.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmjuliafractal.png
new file mode 100644
index 00000000..ce90ba06
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmjuliafractal.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmlathe.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmlathe.png
new file mode 100644
index 00000000..572ca904
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmlathe.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmlight.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmlight.png
new file mode 100644
index 00000000..ebb36242
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmlight.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmlightgroup.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmlightgroup.png
new file mode 100644
index 00000000..49e1aee6
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmlightgroup.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmlistpattern.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmlistpattern.png
new file mode 100644
index 00000000..76fa8d8b
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmlistpattern.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmlookslike.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmlookslike.png
new file mode 100644
index 00000000..d70ce958
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmlookslike.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmmaterial.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmmaterial.png
new file mode 100644
index 00000000..9cb8498d
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmmaterial.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmmaterialdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmmaterialdeclare.png
new file mode 100644
index 00000000..317b793b
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmmaterialdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmmaterialmap.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmmaterialmap.png
new file mode 100644
index 00000000..d352f4c1
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmmaterialmap.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmmatrix.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmmatrix.png
new file mode 100644
index 00000000..3b9524e5
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmmatrix.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmmedia.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmmedia.png
new file mode 100644
index 00000000..dcb93a22
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmmedia.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmmediadeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmmediadeclare.png
new file mode 100644
index 00000000..e09b71c9
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmmediadeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmmerge.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmmerge.png
new file mode 100644
index 00000000..ce93f989
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmmerge.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmmesh.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmmesh.png
new file mode 100644
index 00000000..74ffa376
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmmesh.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmnormal.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmnormal.png
new file mode 100644
index 00000000..c2838b98
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmnormal.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmnormaldeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmnormaldeclare.png
new file mode 100644
index 00000000..ce3841d8
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmnormaldeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmnormallist.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmnormallist.png
new file mode 100644
index 00000000..ec5d3695
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmnormallist.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmnormalmap.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmnormalmap.png
new file mode 100644
index 00000000..435b0b74
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmnormalmap.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmnormalmapdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmnormalmapdeclare.png
new file mode 100644
index 00000000..2cabff95
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmnormalmapdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmobjectdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmobjectdeclare.png
new file mode 100644
index 00000000..b1d2947f
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmobjectdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmobjectlink.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmobjectlink.png
new file mode 100644
index 00000000..f6e2a32f
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmobjectlink.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmpattern.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmpattern.png
new file mode 100644
index 00000000..f2620041
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmpattern.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmphotons.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmphotons.png
new file mode 100644
index 00000000..4e2f161e
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmphotons.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmpigment.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmpigment.png
new file mode 100644
index 00000000..6a2103d0
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmpigment.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentdeclare.png
new file mode 100644
index 00000000..5b0e22e7
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentlist.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentlist.png
new file mode 100644
index 00000000..568beead
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentlist.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentmap.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentmap.png
new file mode 100644
index 00000000..36466942
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentmap.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentmapdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentmapdeclare.png
new file mode 100644
index 00000000..8bbee2e9
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmpigmentmapdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmplane.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmplane.png
new file mode 100644
index 00000000..f5430a72
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmplane.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmpolynom.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmpolynom.png
new file mode 100644
index 00000000..67e4b46c
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmpolynom.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmprism.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmprism.png
new file mode 100644
index 00000000..ca3dd0b5
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmprism.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmprojectedthrough.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmprojectedthrough.png
new file mode 100644
index 00000000..4f7712e6
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmprojectedthrough.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmquickcolor.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmquickcolor.png
new file mode 100644
index 00000000..4a2c7c25
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmquickcolor.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmradiosity.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmradiosity.png
new file mode 100644
index 00000000..59f923cf
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmradiosity.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmrainbow.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmrainbow.png
new file mode 100644
index 00000000..3e0b1021
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmrainbow.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmrainbowdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmrainbowdeclare.png
new file mode 100644
index 00000000..f92ab03e
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmrainbowdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmraw.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmraw.png
new file mode 100644
index 00000000..d8270f7c
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmraw.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmrender.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmrender.png
new file mode 100644
index 00000000..6aa2b69f
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmrender.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmrenderpreview.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmrenderpreview.png
new file mode 100644
index 00000000..0227ab0c
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmrenderpreview.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmrendersettings.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmrendersettings.png
new file mode 100644
index 00000000..cb6b2e9a
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmrendersettings.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmrotate.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmrotate.png
new file mode 100644
index 00000000..22a5af44
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmrotate.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmscale.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmscale.png
new file mode 100644
index 00000000..e7820f60
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmscale.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmscene.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmscene.png
new file mode 100644
index 00000000..47c9dc56
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmscene.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmskysphere.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmskysphere.png
new file mode 100644
index 00000000..cad5cdf5
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmskysphere.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmskyspheredeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmskyspheredeclare.png
new file mode 100644
index 00000000..4aaafa28
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmskyspheredeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmslope.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmslope.png
new file mode 100644
index 00000000..42abb1b4
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmslope.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmslopemap.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmslopemap.png
new file mode 100644
index 00000000..4efbb6ef
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmslopemap.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmslopemapdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmslopemapdeclare.png
new file mode 100644
index 00000000..19307196
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmslopemapdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmsolidcolor.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmsolidcolor.png
new file mode 100644
index 00000000..e8cbfc51
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmsolidcolor.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmsor.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmsor.png
new file mode 100644
index 00000000..1a9bdf7a
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmsor.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmsphere.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmsphere.png
new file mode 100644
index 00000000..bb9b6f2d
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmsphere.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmspheresweep.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmspheresweep.png
new file mode 100644
index 00000000..fe94fb83
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmspheresweep.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmsqe.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmsqe.png
new file mode 100644
index 00000000..a3d9152d
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmsqe.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmtext.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmtext.png
new file mode 100644
index 00000000..25fc94c3
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmtext.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmtexture.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmtexture.png
new file mode 100644
index 00000000..a2f13e15
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmtexture.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmtexturedeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmtexturedeclare.png
new file mode 100644
index 00000000..e40843f0
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmtexturedeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmtexturelist.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmtexturelist.png
new file mode 100644
index 00000000..e497f164
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmtexturelist.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmtexturemap.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmtexturemap.png
new file mode 100644
index 00000000..282acdf6
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmtexturemap.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmtexturemapdeclare.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmtexturemapdeclare.png
new file mode 100644
index 00000000..2f046f10
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmtexturemapdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmtorus.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmtorus.png
new file mode 100644
index 00000000..ab187e64
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmtorus.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmtranslate.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmtranslate.png
new file mode 100644
index 00000000..3234c8fe
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmtranslate.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmtriangle.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmtriangle.png
new file mode 100644
index 00000000..4cae6980
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmtriangle.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmunion.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmunion.png
new file mode 100644
index 00000000..aacb8776
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmunion.png
Binary files differ
diff --git a/kpovmodeler/pics/crystalsvg/cr22-action-pmwarp.png b/kpovmodeler/pics/crystalsvg/cr22-action-pmwarp.png
new file mode 100644
index 00000000..e98e139c
--- /dev/null
+++ b/kpovmodeler/pics/crystalsvg/cr22-action-pmwarp.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/Makefile.am b/kpovmodeler/pics/locolor/Makefile.am
new file mode 100644
index 00000000..66481ab6
--- /dev/null
+++ b/kpovmodeler/pics/locolor/Makefile.am
@@ -0,0 +1,2 @@
+pmtoolbardir = $(kde_datadir)/kpovmodeler/icons
+pmtoolbar_ICON = AUTO
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmaddpoint.png b/kpovmodeler/pics/locolor/lo16-action-pmaddpoint.png
new file mode 100644
index 00000000..b3c7cab4
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmaddpoint.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmaddpointabove.png b/kpovmodeler/pics/locolor/lo16-action-pmaddpointabove.png
new file mode 100644
index 00000000..4310c761
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmaddpointabove.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmaddsubprism.png b/kpovmodeler/pics/locolor/lo16-action-pmaddsubprism.png
new file mode 100644
index 00000000..c292daab
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmaddsubprism.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmbicubicpatch.png b/kpovmodeler/pics/locolor/lo16-action-pmbicubicpatch.png
new file mode 100644
index 00000000..dd3752c9
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmbicubicpatch.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmblendmapmodifiers.png b/kpovmodeler/pics/locolor/lo16-action-pmblendmapmodifiers.png
new file mode 100644
index 00000000..c95808c9
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmblendmapmodifiers.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmblob.png b/kpovmodeler/pics/locolor/lo16-action-pmblob.png
new file mode 100644
index 00000000..f5dfe034
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmblob.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmblobcylinder.png b/kpovmodeler/pics/locolor/lo16-action-pmblobcylinder.png
new file mode 100644
index 00000000..a320ec3a
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmblobcylinder.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmblobsphere.png b/kpovmodeler/pics/locolor/lo16-action-pmblobsphere.png
new file mode 100644
index 00000000..f45f5433
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmblobsphere.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmboundedby.png b/kpovmodeler/pics/locolor/lo16-action-pmboundedby.png
new file mode 100644
index 00000000..4d167b4d
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmboundedby.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmbox.png b/kpovmodeler/pics/locolor/lo16-action-pmbox.png
new file mode 100644
index 00000000..6e8665d4
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmbox.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmbumpmap.png b/kpovmodeler/pics/locolor/lo16-action-pmbumpmap.png
new file mode 100644
index 00000000..17df5809
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmbumpmap.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmcamera.png b/kpovmodeler/pics/locolor/lo16-action-pmcamera.png
new file mode 100644
index 00000000..264a4e9f
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmcamera.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmclippedby.png b/kpovmodeler/pics/locolor/lo16-action-pmclippedby.png
new file mode 100644
index 00000000..98394ece
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmclippedby.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmcomment.png b/kpovmodeler/pics/locolor/lo16-action-pmcomment.png
new file mode 100644
index 00000000..78b0a3f0
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmcomment.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmcone.png b/kpovmodeler/pics/locolor/lo16-action-pmcone.png
new file mode 100644
index 00000000..dc369725
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmcone.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmcylinder.png b/kpovmodeler/pics/locolor/lo16-action-pmcylinder.png
new file mode 100644
index 00000000..7147b4ca
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmcylinder.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmdeclare.png b/kpovmodeler/pics/locolor/lo16-action-pmdeclare.png
new file mode 100644
index 00000000..e56be4e9
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmdensity.png b/kpovmodeler/pics/locolor/lo16-action-pmdensity.png
new file mode 100644
index 00000000..58fe3d6f
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmdensity.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmdensitydeclare.png b/kpovmodeler/pics/locolor/lo16-action-pmdensitydeclare.png
new file mode 100644
index 00000000..9b826d4a
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmdensitydeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmdensitylist.png b/kpovmodeler/pics/locolor/lo16-action-pmdensitylist.png
new file mode 100644
index 00000000..d4d9170b
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmdensitylist.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmdensitymap.png b/kpovmodeler/pics/locolor/lo16-action-pmdensitymap.png
new file mode 100644
index 00000000..69f9fda7
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmdensitymap.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmdensitymapdeclare.png b/kpovmodeler/pics/locolor/lo16-action-pmdensitymapdeclare.png
new file mode 100644
index 00000000..0b26c273
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmdensitymapdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmdifference.png b/kpovmodeler/pics/locolor/lo16-action-pmdifference.png
new file mode 100644
index 00000000..d2551828
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmdifference.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmdisc.png b/kpovmodeler/pics/locolor/lo16-action-pmdisc.png
new file mode 100644
index 00000000..095adf32
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmdisc.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmdrag.png b/kpovmodeler/pics/locolor/lo16-action-pmdrag.png
new file mode 100644
index 00000000..65aba8ba
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmdrag.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmfog.png b/kpovmodeler/pics/locolor/lo16-action-pmfog.png
new file mode 100644
index 00000000..89346120
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmfog.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmfogdeclare.png b/kpovmodeler/pics/locolor/lo16-action-pmfogdeclare.png
new file mode 100644
index 00000000..944720cb
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmfogdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmglobalsettings.png b/kpovmodeler/pics/locolor/lo16-action-pmglobalsettings.png
new file mode 100644
index 00000000..b8951994
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmglobalsettings.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmheightfield.png b/kpovmodeler/pics/locolor/lo16-action-pmheightfield.png
new file mode 100644
index 00000000..5f4b7871
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmheightfield.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmimagemap.png b/kpovmodeler/pics/locolor/lo16-action-pmimagemap.png
new file mode 100644
index 00000000..2ece117d
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmimagemap.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pminserterrors.png b/kpovmodeler/pics/locolor/lo16-action-pminserterrors.png
new file mode 100644
index 00000000..a8edc396
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pminserterrors.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pminsertfirstchild.png b/kpovmodeler/pics/locolor/lo16-action-pminsertfirstchild.png
new file mode 100644
index 00000000..5ee47f17
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pminsertfirstchild.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pminsertlastchild.png b/kpovmodeler/pics/locolor/lo16-action-pminsertlastchild.png
new file mode 100644
index 00000000..cc7193f7
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pminsertlastchild.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pminsertsibling.png b/kpovmodeler/pics/locolor/lo16-action-pminsertsibling.png
new file mode 100644
index 00000000..a0bca16f
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pminsertsibling.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmintersection.png b/kpovmodeler/pics/locolor/lo16-action-pmintersection.png
new file mode 100644
index 00000000..954eae50
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmintersection.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmjuliafractal.png b/kpovmodeler/pics/locolor/lo16-action-pmjuliafractal.png
new file mode 100644
index 00000000..4b88db07
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmjuliafractal.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmlathe.png b/kpovmodeler/pics/locolor/lo16-action-pmlathe.png
new file mode 100644
index 00000000..181e4446
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmlathe.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmlight.png b/kpovmodeler/pics/locolor/lo16-action-pmlight.png
new file mode 100644
index 00000000..ec9c456d
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmlight.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmlistpattern.png b/kpovmodeler/pics/locolor/lo16-action-pmlistpattern.png
new file mode 100644
index 00000000..6a85bc72
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmlistpattern.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmlookslike.png b/kpovmodeler/pics/locolor/lo16-action-pmlookslike.png
new file mode 100644
index 00000000..6f7a439f
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmlookslike.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmmaterialmap.png b/kpovmodeler/pics/locolor/lo16-action-pmmaterialmap.png
new file mode 100644
index 00000000..c964f8a4
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmmaterialmap.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmmatrix.png b/kpovmodeler/pics/locolor/lo16-action-pmmatrix.png
new file mode 100644
index 00000000..096bad00
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmmatrix.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmmerge.png b/kpovmodeler/pics/locolor/lo16-action-pmmerge.png
new file mode 100644
index 00000000..04e71ed2
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmmerge.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmobjectdeclare.png b/kpovmodeler/pics/locolor/lo16-action-pmobjectdeclare.png
new file mode 100644
index 00000000..cd562250
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmobjectdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmobjectlink.png b/kpovmodeler/pics/locolor/lo16-action-pmobjectlink.png
new file mode 100644
index 00000000..479664f6
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmobjectlink.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmpigment.png b/kpovmodeler/pics/locolor/lo16-action-pmpigment.png
new file mode 100644
index 00000000..0f59413c
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmpigment.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmpigmentdeclare.png b/kpovmodeler/pics/locolor/lo16-action-pmpigmentdeclare.png
new file mode 100644
index 00000000..efdada03
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmpigmentdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmplane.png b/kpovmodeler/pics/locolor/lo16-action-pmplane.png
new file mode 100644
index 00000000..7b2029d9
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmplane.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmpolynom.png b/kpovmodeler/pics/locolor/lo16-action-pmpolynom.png
new file mode 100644
index 00000000..d2858866
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmpolynom.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmprism.png b/kpovmodeler/pics/locolor/lo16-action-pmprism.png
new file mode 100644
index 00000000..ce96f3e5
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmprism.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmquickcolor.png b/kpovmodeler/pics/locolor/lo16-action-pmquickcolor.png
new file mode 100644
index 00000000..109131d8
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmquickcolor.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmrainbow.png b/kpovmodeler/pics/locolor/lo16-action-pmrainbow.png
new file mode 100644
index 00000000..ddd11480
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmrainbow.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmrainbowdeclare.png b/kpovmodeler/pics/locolor/lo16-action-pmrainbowdeclare.png
new file mode 100644
index 00000000..47906a3a
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmrainbowdeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmraw.png b/kpovmodeler/pics/locolor/lo16-action-pmraw.png
new file mode 100644
index 00000000..cb0ce235
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmraw.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmremovepoint.png b/kpovmodeler/pics/locolor/lo16-action-pmremovepoint.png
new file mode 100644
index 00000000..0be182fb
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmremovepoint.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmrender.png b/kpovmodeler/pics/locolor/lo16-action-pmrender.png
new file mode 100644
index 00000000..a2fc7d79
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmrender.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmrenderpreview.png b/kpovmodeler/pics/locolor/lo16-action-pmrenderpreview.png
new file mode 100644
index 00000000..feb2f7b1
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmrenderpreview.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmrendersettings.png b/kpovmodeler/pics/locolor/lo16-action-pmrendersettings.png
new file mode 100644
index 00000000..f19b0eea
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmrendersettings.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmrotate.png b/kpovmodeler/pics/locolor/lo16-action-pmrotate.png
new file mode 100644
index 00000000..744f927c
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmrotate.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmscale.png b/kpovmodeler/pics/locolor/lo16-action-pmscale.png
new file mode 100644
index 00000000..ca553a0f
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmscale.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmscene.png b/kpovmodeler/pics/locolor/lo16-action-pmscene.png
new file mode 100644
index 00000000..61dfa78a
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmscene.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmskysphere.png b/kpovmodeler/pics/locolor/lo16-action-pmskysphere.png
new file mode 100644
index 00000000..aaf0f47a
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmskysphere.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmskyspheredeclare.png b/kpovmodeler/pics/locolor/lo16-action-pmskyspheredeclare.png
new file mode 100644
index 00000000..b9d719ff
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmskyspheredeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmsolidcolor.png b/kpovmodeler/pics/locolor/lo16-action-pmsolidcolor.png
new file mode 100644
index 00000000..38840359
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmsolidcolor.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmsor.png b/kpovmodeler/pics/locolor/lo16-action-pmsor.png
new file mode 100644
index 00000000..c38eb6ae
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmsor.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmsphere.png b/kpovmodeler/pics/locolor/lo16-action-pmsphere.png
new file mode 100644
index 00000000..a7ea2461
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmsphere.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmsqr.png b/kpovmodeler/pics/locolor/lo16-action-pmsqr.png
new file mode 100644
index 00000000..cfaa5aff
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmsqr.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmtext.png b/kpovmodeler/pics/locolor/lo16-action-pmtext.png
new file mode 100644
index 00000000..04987349
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmtext.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmtexture.png b/kpovmodeler/pics/locolor/lo16-action-pmtexture.png
new file mode 100644
index 00000000..d84fcd66
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmtexture.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmtexturedeclare.png b/kpovmodeler/pics/locolor/lo16-action-pmtexturedeclare.png
new file mode 100644
index 00000000..8984df92
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmtexturedeclare.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmtorus.png b/kpovmodeler/pics/locolor/lo16-action-pmtorus.png
new file mode 100644
index 00000000..a09660ab
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmtorus.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmtranslate.png b/kpovmodeler/pics/locolor/lo16-action-pmtranslate.png
new file mode 100644
index 00000000..2d16dea2
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmtranslate.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmtriangle.png b/kpovmodeler/pics/locolor/lo16-action-pmtriangle.png
new file mode 100644
index 00000000..dfe6ed44
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmtriangle.png
Binary files differ
diff --git a/kpovmodeler/pics/locolor/lo16-action-pmunion.png b/kpovmodeler/pics/locolor/lo16-action-pmunion.png
new file mode 100644
index 00000000..1407fe3a
--- /dev/null
+++ b/kpovmodeler/pics/locolor/lo16-action-pmunion.png
Binary files differ
diff --git a/kpovmodeler/pm2dcontrolpoint.cpp b/kpovmodeler/pm2dcontrolpoint.cpp
new file mode 100644
index 00000000..66e7a85a
--- /dev/null
+++ b/kpovmodeler/pm2dcontrolpoint.cpp
@@ -0,0 +1,207 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pm2dcontrolpoint.h"
+#include "pmmath.h"
+#include <math.h>
+
+PM2DControlPoint::PM2DControlPoint( const PMVector& point,
+ PM2DControlPoint::CPType type, int id,
+ const QString& description )
+ : PMControlPoint( id, description )
+{
+ m_point = point;
+ m_type = type;
+ m_thirdCoordinate = 0;
+ m_scale = 1.0;
+ m_pBasePoint = 0;
+ m_pLatheLink = 0;
+}
+
+void PM2DControlPoint::graphicalChangeStarted( )
+{
+ QPtrListIterator<PM2DControlPoint> it( m_linkedPoints );
+ for( ; *it; ++it )
+ if( !( *it )->selected( ) )
+ ( *it )->graphicalChangeStarted( );
+
+ m_original2DPoint = m_point;
+ m_originalPoint = to3D( m_point );
+}
+
+void PM2DControlPoint::graphicalChange( const PMVector& startPoint,
+ const PMVector& /*viewNormal*/,
+ const PMVector& endPoint )
+{
+ if( m_pBasePoint && m_pBasePoint->selected( ) )
+ return;
+
+ m_point = to2D( m_originalPoint + endPoint - startPoint );
+
+ if( m_pLatheLink && m_pLatheLink->selected( ) )
+ {
+ PM2DControlPoint* ll = m_pLatheLink;
+ PMVector op = ll->to2D( ll->m_originalPoint + endPoint - startPoint );
+
+ m_point = to2D( m_originalPoint + endPoint - startPoint );
+ if( ( m_point - m_original2DPoint ).abs( ) <
+ ( op - ll->m_original2DPoint ).abs( ) )
+ m_point = op;
+ }
+
+ QPtrListIterator<PM2DControlPoint> it( m_linkedPoints );
+ for( ; *it; ++it )
+ {
+ ( *it )->m_point = m_point + ( *it )->m_original2DPoint
+ - m_original2DPoint;
+ ( *it )->setChanged( );
+ }
+}
+
+void PM2DControlPoint::setBasePoint( PM2DControlPoint* p )
+{
+ if( p != m_pBasePoint )
+ {
+ if( m_pBasePoint )
+ m_pBasePoint->removeLinkedPoint( this );
+ m_pBasePoint = p;
+ if( m_pBasePoint )
+ m_pBasePoint->addLinkedPoint( this );
+ }
+}
+
+void PM2DControlPoint::snapToGrid( )
+{
+ int i;
+ double d = moveGrid( );
+ bool diff = false;
+ PMVector change( 2 );
+
+ if( m_pBasePoint && m_pBasePoint->selected( ) )
+ {
+ m_point -= m_pBasePoint->m_point;
+ diff = true;
+ }
+
+ if( !approxZero( d ) )
+ {
+ for( i = 0; i < 2; i++ )
+ {
+ change[i] = -m_point[i];
+ m_point[i] = rint( m_point[i] / d ) * d;
+ change[i] += m_point[i];
+ }
+ }
+
+ if( diff )
+ m_point += m_pBasePoint->m_point;
+
+ QPtrListIterator<PM2DControlPoint> it( m_linkedPoints );
+ for( ; *it; ++it )
+ {
+ ( *it )->m_point += change;
+ ( *it )->setChanged( );
+ }
+
+ setChanged( );
+}
+
+PMVector PM2DControlPoint::to2D( const PMVector& v ) const
+{
+ PMVector result( 2 );
+ switch( m_type )
+ {
+ case PM2DXY:
+ result[0] = v[0];
+ result[1] = v[1];
+ break;
+ case PM2DXZ:
+ result[0] = v[0];
+ result[1] = v[2];
+ break;
+ case PM2DYZ:
+ result[0] = v[1];
+ result[1] = v[2];
+ break;
+ case PM2DYX:
+ result[0] = v[1];
+ result[1] = v[0];
+ break;
+ case PM2DZX:
+ result[0] = v[2];
+ result[1] = v[0];
+ break;
+ case PM2DZY:
+ result[0] = v[2];
+ result[1] = v[1];
+ break;
+ }
+ if( !approxZero( m_scale ) )
+ result /= m_scale;
+ return result;
+}
+
+PMVector PM2DControlPoint::to3D( const PMVector& v ) const
+{
+ PMVector vec( v * m_scale );
+ PMVector result( 3 );
+ switch( m_type )
+ {
+ case PM2DXY:
+ result[0] = vec[0];
+ result[1] = vec[1];
+ result[2] = m_thirdCoordinate;
+ break;
+ case PM2DXZ:
+ result[0] = vec[0];
+ result[1] = m_thirdCoordinate;
+ result[2] = vec[1];
+ break;
+ case PM2DYZ:
+ result[0] = m_thirdCoordinate;
+ result[1] = vec[0];
+ result[2] = vec[1];
+ break;
+ case PM2DYX:
+ result[1] = vec[0];
+ result[0] = vec[1];
+ result[2] = m_thirdCoordinate;
+ break;
+ case PM2DZX:
+ result[2] = vec[0];
+ result[0] = vec[1];
+ result[1] = m_thirdCoordinate;
+ break;
+ case PM2DZY:
+ result[2] = vec[0];
+ result[1] = vec[1];
+ result[0] = m_thirdCoordinate;
+ break;
+ }
+ return result;
+}
+
+void PM2DControlPoint::addLinkedPoint( PM2DControlPoint* p )
+{
+ if( !m_linkedPoints.containsRef( p ) )
+ m_linkedPoints.append( p );
+}
+
+void PM2DControlPoint::removeLinkedPoint( PM2DControlPoint* p )
+{
+ m_linkedPoints.removeRef( p );
+}
diff --git a/kpovmodeler/pm2dcontrolpoint.h b/kpovmodeler/pm2dcontrolpoint.h
new file mode 100644
index 00000000..f949570b
--- /dev/null
+++ b/kpovmodeler/pm2dcontrolpoint.h
@@ -0,0 +1,135 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PM2DCONTROLPOINT_H
+#define PM2DCONTROLPOINT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include "pmcontrolpoint.h"
+#include <qptrlist.h>
+
+/**
+ * Class for free moveable control points
+ */
+class PM2DControlPoint : public PMControlPoint
+{
+public:
+ /**
+ * Type enum
+ */
+ enum CPType { PM2DXY, PM2DYX, PM2DXZ, PM2DZX, PM2DYZ, PM2DZY };
+ /**
+ * Creates a PM2DControlPoint with id. Point has to be a 2D vector.
+ */
+ PM2DControlPoint( const PMVector& point, CPType type,
+ int id, const QString& description );
+ /**
+ * Deletes the PM2DControlPoint
+ */
+ virtual ~PM2DControlPoint( ) { };
+
+ /** */
+ virtual PMVector position( ) const { return to3D( m_point ); }
+ /**
+ * Sets the 2d coordinates of the control point
+ */
+ void setPoint( const PMVector& newPoint ) { m_point = newPoint; }
+ /**
+ * 2d coordinates of the control point
+ */
+ PMVector point( ) const { return m_point; }
+ /** */
+ virtual void snapToGrid( );
+ /**
+ * Returns the third coordinate
+ */
+ double thirdCoordinate( ) const { return m_thirdCoordinate; }
+ /**
+ * Sets the third coordinate
+ */
+ void setThirdCoordinate( double d ) { m_thirdCoordinate = d; }
+ /**
+ * Returns the 2d scale
+ */
+ double scale( ) const { return m_scale; }
+ /**
+ * Sets the scale
+ */
+ void setScale( double s ) { m_scale = s; }
+
+ /**
+ * Sets the base point.
+ *
+ * If a base point is set, an extra line is shown between
+ * the base point and this control point.
+ */
+ void setBasePoint( PM2DControlPoint* p );
+ /**
+ * Returns the base point
+ */
+ PM2DControlPoint* basePoint( ) const { return m_pBasePoint; }
+ /**
+ * This method is used by the lathe object to link
+ * the control points in the xy and xz plane. These points are
+ * synchronized if both are selected.
+ */
+ void setLatheLink( PM2DControlPoint* p ) { m_pLatheLink = p; }
+ /**
+ * Returns the linked control point for lathe points
+ */
+ PM2DControlPoint* latheLink( ) const { return m_pLatheLink; }
+
+ /** */
+ virtual bool hasExtraLine( ) const { return m_pBasePoint; }
+ /** */
+ virtual PMVector extraLineStart( ) const { return position( ); }
+ /** */
+ virtual PMVector extraLineEnd( ) const
+ {
+ if( m_pBasePoint )
+ return m_pBasePoint->position( );
+ return PMVector( 0, 0, 0 );
+ }
+
+protected:
+ /** */
+ virtual void graphicalChangeStarted( );
+ /** */
+ virtual void graphicalChange( const PMVector& startPoint,
+ const PMVector& viewNormal,
+ const PMVector& endPoint );
+private:
+ PMVector to2D( const PMVector& v ) const;
+ PMVector to3D( const PMVector& v ) const;
+ void addLinkedPoint( PM2DControlPoint* p );
+ void removeLinkedPoint( PM2DControlPoint* p );
+
+ PMVector m_point, m_originalPoint, m_original2DPoint;
+ CPType m_type;
+ double m_thirdCoordinate;
+ double m_scale;
+ PM2DControlPoint* m_pBasePoint;
+ QPtrList<PM2DControlPoint> m_linkedPoints;
+ PM2DControlPoint* m_pLatheLink;
+};
+
+#endif
diff --git a/kpovmodeler/pm3dcontrolpoint.cpp b/kpovmodeler/pm3dcontrolpoint.cpp
new file mode 100644
index 00000000..7bd4e10e
--- /dev/null
+++ b/kpovmodeler/pm3dcontrolpoint.cpp
@@ -0,0 +1,49 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pm3dcontrolpoint.h"
+#include "pmmath.h"
+#include <math.h>
+
+PM3DControlPoint::PM3DControlPoint( const PMVector& point, int id,
+ const QString& description )
+ : PMControlPoint( id, description )
+{
+ m_point = point;
+}
+
+void PM3DControlPoint::graphicalChangeStarted( )
+{
+ m_originalPoint = m_point;
+}
+
+void PM3DControlPoint::graphicalChange( const PMVector& startPoint,
+ const PMVector& /*viewNormal*/,
+ const PMVector& endPoint )
+{
+ m_point = m_originalPoint + endPoint - startPoint;
+}
+
+void PM3DControlPoint::snapToGrid( )
+{
+ int i;
+ double d = moveGrid( );
+ if( !approxZero( d ) )
+ for( i = 0; i < 3; i++ )
+ m_point[i] = rint( m_point[i] / d ) * d;
+ setChanged( );
+}
diff --git a/kpovmodeler/pm3dcontrolpoint.h b/kpovmodeler/pm3dcontrolpoint.h
new file mode 100644
index 00000000..765c4e43
--- /dev/null
+++ b/kpovmodeler/pm3dcontrolpoint.h
@@ -0,0 +1,68 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PM3DCONTROLPOINT_H
+#define PM3DCONTROLPOINT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include "pmcontrolpoint.h"
+
+/**
+ * Class for free moveable control points
+ */
+class PM3DControlPoint : public PMControlPoint
+{
+public:
+ /**
+ * Creates a PM3DControlPoint with id.
+ */
+ PM3DControlPoint( const PMVector& point, int id, const QString& description );
+ /**
+ * Deletes the PM3DControlPoint
+ */
+ virtual ~PM3DControlPoint( ) { };
+
+ /** */
+ virtual PMVector position( ) const { return m_point; }
+ /**
+ * Sets the 3d coordinates of the control point
+ */
+ void setPoint( const PMVector& newPoint ) { m_point = newPoint; }
+ /**
+ * 3d coordinates of the control point
+ */
+ PMVector point( ) const { return m_point; }
+ /** */
+ virtual void snapToGrid( );
+
+protected:
+ /** */
+ virtual void graphicalChangeStarted( );
+ /** */
+ virtual void graphicalChange( const PMVector& startPoint,
+ const PMVector& viewNormal,
+ const PMVector& endPoint );
+private:
+ PMVector m_point, m_originalPoint;
+};
+
+#endif
diff --git a/kpovmodeler/pmactions.cpp b/kpovmodeler/pmactions.cpp
new file mode 100644
index 00000000..b84e42da
--- /dev/null
+++ b/kpovmodeler/pmactions.cpp
@@ -0,0 +1,254 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmactions.h"
+
+#include <qcombobox.h>
+#include <qwhatsthis.h>
+#include <qspinbox.h>
+#include <qlabel.h>
+#include <qstyle.h>
+#include <qpainter.h>
+#include <ktoolbar.h>
+#include <ktoolbarbutton.h>
+
+#include "pmdebug.h"
+
+// Fixed widths are calculated wrong in a toolbar.
+// Fixed sizeHint for the combo box to return
+// at least the minimum size
+class PMComboBox : public QComboBox
+{
+public:
+ PMComboBox( QWidget* parent, const char* name = 0 )
+ : QComboBox( parent, name )
+ {
+ }
+
+ virtual QSize minimumSizeHint( ) const
+ {
+ QSize s = QComboBox::minimumSizeHint( );
+ return s.expandedTo( minimumSize( ) );
+ }
+ virtual QSize sizeHint( ) const
+ {
+ QSize s = QComboBox::sizeHint( );
+ return s.expandedTo( minimumSize( ) );
+ }
+};
+
+PMComboAction::PMComboAction( const QString& text, int accel, const QObject* receiver, const char* member,
+ QObject* parent, const char* name )
+ : KAction( text, accel, parent, name )
+{
+ m_receiver = receiver;
+ m_member = member;
+ m_minWidth = 0;
+ m_maxWidth = 0;
+}
+
+PMComboAction::~PMComboAction( )
+{
+}
+
+int PMComboAction::plug( QWidget* w, int index )
+{
+ if( !w->inherits( "KToolBar" ) )
+ return -1;
+
+ KToolBar* toolBar = ( KToolBar* ) w;
+
+ int id = KAction::getToolButtonID( );
+
+ QComboBox* comboBox = new PMComboBox( toolBar );
+ if( m_minWidth > 0 )
+ comboBox->setMinimumWidth( m_minWidth );
+ if( m_maxWidth > 0 )
+ comboBox->setMaximumWidth( m_maxWidth );
+
+ toolBar->insertWidget( id, m_minWidth > 0 ? m_minWidth : 300,
+ comboBox, index );
+ connect( comboBox, SIGNAL( activated( int ) ), m_receiver, m_member );
+
+ addContainer( toolBar, id );
+
+ connect( toolBar, SIGNAL( destroyed( ) ), this, SLOT( slotDestroyed( ) ) );
+
+ //toolBar->setItemAutoSized( id, true );
+
+ m_combo = comboBox;
+
+ emit plugged( );
+
+ QWhatsThis::add( comboBox, whatsThis( ) );
+
+ return containerCount( ) - 1;
+}
+
+void PMComboAction::unplug( QWidget *w )
+{
+ if( !w->inherits( "KToolBar" ) )
+ return;
+
+ KToolBar *toolBar = ( KToolBar* ) w;
+
+ int idx = findContainer( w );
+
+ toolBar->removeItem( itemId( idx ) );
+
+ removeContainer( idx );
+ m_combo = 0L;
+}
+
+
+// Use a toolbutton instead of a label so it is styled correctly.
+// copied from konq_actions.cc
+class PMToolBarLabel : public QToolButton
+{
+public:
+ PMToolBarLabel( const QString& text, QWidget* parent = 0, const char* name = 0 )
+ : QToolButton( parent, name )
+ {
+ setText( text );
+ }
+protected:
+ QSize sizeHint( ) const
+ {
+ int w = fontMetrics( ).width( text( ) );
+ int h = fontMetrics( ).height( );
+ return QSize( w, h );
+ }
+ void drawButton( QPainter* p )
+ {
+#if ( QT_VERSION >= 300 )
+ // Draw the background
+ style( ).drawComplexControl( QStyle::CC_ToolButton, p, this, rect( ), colorGroup( ),
+ QStyle::Style_Enabled, QStyle::SC_ToolButton );
+ // Draw the label
+ style( ).drawControl( QStyle::CE_ToolButtonLabel, p, this, rect( ), colorGroup( ),
+ QStyle::Style_Enabled );
+#else
+ p->drawText( rect( ), Qt::AlignVCenter | Qt::AlignLeft, text( ) );
+#endif
+ }
+};
+
+PMLabelAction::PMLabelAction( const QString &text, QObject *parent, const char *name )
+ : KAction( text, 0, parent, name )
+{
+ m_button = 0;
+}
+
+int PMLabelAction::plug( QWidget *widget, int index )
+{
+ //do not call the previous implementation here
+
+ if( widget->inherits( "KToolBar" ) )
+ {
+ KToolBar* tb = ( KToolBar* ) widget;
+
+ int id = KAction::getToolButtonID( );
+
+ m_button = new PMToolBarLabel( text( ), widget );
+ tb->insertWidget( id, m_button->width( ), m_button, index );
+
+ addContainer( tb, id );
+
+ connect( tb, SIGNAL( destroyed( ) ), this, SLOT( slotDestroyed( ) ) );
+
+ return containerCount( ) - 1;
+ }
+
+ return -1;
+}
+
+void PMLabelAction::unplug( QWidget *widget )
+{
+ if( widget->inherits( "KToolBar" ) )
+ {
+ KToolBar* bar = ( KToolBar* ) widget;
+
+ int idx = findContainer( bar );
+
+ if( idx != -1 )
+ {
+ bar->removeItem( itemId( idx ) );
+ removeContainer( idx );
+ }
+
+ m_button = 0;
+ return;
+ }
+}
+
+
+PMSpinBoxAction::PMSpinBoxAction( const QString& text, int accel, const QObject* receiver, const char* member,
+ QObject* parent, const char* name )
+ : KAction( text, accel, parent, name )
+{
+ m_receiver = receiver;
+ m_member = member;
+}
+
+PMSpinBoxAction::~PMSpinBoxAction( )
+{
+}
+
+int PMSpinBoxAction::plug( QWidget* w, int index )
+{
+ if( !w->inherits( "KToolBar" ) )
+ return -1;
+
+ KToolBar* toolBar = ( KToolBar* ) w;
+
+ int id = KAction::getToolButtonID( );
+
+ QSpinBox* spinBox = new QSpinBox( -1000, 1000, 1, w );
+ toolBar->insertWidget( id, 70, spinBox, index );
+
+ connect( spinBox, SIGNAL( valueChanged( int ) ), m_receiver, m_member );
+
+ addContainer( toolBar, id );
+
+ connect( toolBar, SIGNAL( destroyed( ) ), this, SLOT( slotDestroyed( ) ) );
+ //toolBar->setItemAutoSized( id, false );
+
+ m_spinBox = spinBox;
+
+ emit plugged( );
+
+ QWhatsThis::add( spinBox, whatsThis( ) );
+
+ return containerCount( ) - 1;
+}
+
+void PMSpinBoxAction::unplug( QWidget *w )
+{
+ if( !w->inherits( "KToolBar" ) )
+ return;
+
+ KToolBar *toolBar = (KToolBar *)w;
+
+ int idx = findContainer( w );
+
+ toolBar->removeItem( itemId( idx ) );
+
+ removeContainer( idx );
+ m_spinBox = 0L;
+}
+
+#include "pmactions.moc"
diff --git a/kpovmodeler/pmactions.h b/kpovmodeler/pmactions.h
new file mode 100644
index 00000000..f4f8e9e4
--- /dev/null
+++ b/kpovmodeler/pmactions.h
@@ -0,0 +1,106 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMACTIONS_H
+#define PMACTIONS_H
+
+#include <qguardedptr.h>
+#include <kaction.h>
+
+class QComboBox;
+class QSpinBox;
+class QLabel;
+class QToolButton;
+
+/**
+ * Combobox action for the toolbar.
+ *
+ * Copied from konq_actions.h, author: Simon Hausmann <hausmann@kde.org>
+ */
+class PMComboAction : public KAction
+{
+ Q_OBJECT
+public:
+ PMComboAction( const QString& text, int accel, const QObject* receiver, const char* member, QObject* parent, const char* name );
+ ~PMComboAction( );
+
+ virtual int plug( QWidget* w, int index = -1 );
+
+ virtual void unplug( QWidget* w );
+
+ QGuardedPtr<QComboBox> combo( ) { return m_combo; }
+
+ void setMaximumWidth( int w ) { m_maxWidth = w; }
+ void setMinimumWidth( int w ) { m_minWidth = w; }
+
+signals:
+ void plugged( );
+
+private:
+ QGuardedPtr<QComboBox> m_combo;
+ const QObject* m_receiver;
+ const char* m_member;
+ int m_minWidth, m_maxWidth;
+};
+
+/**
+ * Label action for the toolbar.
+ *
+ * Copied from konq_actions.h, author: Simon Hausmann <hausmann@kde.org>
+ */
+class PMLabelAction : public KAction
+{
+ Q_OBJECT
+public:
+ PMLabelAction( const QString &text, QObject *parent = 0, const char *name = 0 );
+
+ virtual int plug( QWidget *widget, int index = -1 );
+ virtual void unplug( QWidget *widget );
+ QToolButton* button( ) { return m_button; }
+
+private:
+ QToolButton* m_button;
+};
+
+/**
+ * Spinbox action for the toolbar.
+ */
+class PMSpinBoxAction : public KAction
+{
+ Q_OBJECT
+public:
+ PMSpinBoxAction( const QString& text, int accel, const QObject* receiver, const char* member, QObject* parent, const char* name );
+ ~PMSpinBoxAction( );
+
+ virtual int plug( QWidget* w, int index = -1 );
+ virtual void unplug( QWidget* w );
+
+ QGuardedPtr<QSpinBox> spinBox( ) { return m_spinBox; }
+
+signals:
+ void plugged( );
+
+private:
+ QGuardedPtr<QSpinBox> m_spinBox;
+ const QObject* m_receiver;
+ const char* m_member;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmaddcommand.cpp b/kpovmodeler/pmaddcommand.cpp
new file mode 100644
index 00000000..b8d4ea49
--- /dev/null
+++ b/kpovmodeler/pmaddcommand.cpp
@@ -0,0 +1,233 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmaddcommand.h"
+#include "pmcommandmanager.h"
+#include "pmpart.h"
+#include "pmdeclare.h"
+#include "pmerrorflags.h"
+#include "pmrecursiveobjectiterator.h"
+#include "pmmemento.h"
+
+#include <klocale.h>
+
+PMAddCommand::PMAddCommand( PMObject* obj, PMObject* parent, PMObject* after )
+ : PMCommand( i18n( "Add New %1" ).arg( obj->description( ) ) )
+{
+ m_objects.append( obj );
+ m_pParent = parent;
+ m_pAfter = after;
+ m_executed = false;
+ m_firstExecution = true;
+ m_linksCreated = false;
+ m_pParentChangeMemento = 0;
+}
+
+PMAddCommand::PMAddCommand( const PMObjectList& list, PMObject* parent,
+ PMObject* after )
+ : PMCommand( i18n( "Add Objects" ) )
+{
+ m_objects = list;
+ m_pParent = parent;
+ m_pAfter = after;
+ m_executed = false;
+ m_firstExecution = true;
+ m_linksCreated = false;
+ m_pParentChangeMemento = 0;
+}
+
+PMAddCommand::~PMAddCommand( )
+{
+ if( !m_executed )
+ {
+ m_objects.setAutoDelete( true );
+ m_objects.clear( );
+ }
+
+ m_insertErrors.setAutoDelete( true );
+ m_insertErrors.clear( );
+}
+
+void PMAddCommand::execute( PMCommandManager* theManager )
+{
+ if( !m_executed )
+ {
+ PMObjectListIterator it( m_objects );
+ PMObject* prev = m_pAfter;
+ PMObjectList errors;
+ PMObject* current;
+ bool error = false;
+
+ if( m_firstExecution )
+ if( m_pParent->dataChangeOnInsertRemove( ) )
+ m_pParent->createMemento( );
+
+ for( ; it.current( ); ++it )
+ {
+ current = it.current( );
+ if( !prev )
+ {
+ if( m_pParent->canInsert( current, 0 ) )
+ {
+ m_pParent->insertChild( current, 0 );
+ prev = current;
+ theManager->cmdObjectChanged( current, PMCAdd );
+ }
+ else
+ error = true;
+ }
+ else
+ {
+ if( m_pParent->canInsert( current, prev ) )
+ {
+ m_pParent->insertChildAfter( current, prev );
+ prev = current;
+ theManager->cmdObjectChanged( current, PMCAdd );
+ }
+ else
+ error = true;
+ }
+
+ if( error )
+ {
+ errors.append( current );
+ theManager->cmdObjectChanged( current, PMCAdd | PMCInsertError );
+ if( current->isA( "Declare" ) )
+ {
+ // the object, that couldn't be inserted was a declare,
+ // remove all links
+ PMObjectListIterator links =
+ ( ( PMDeclare* ) current )->linkedObjects( );
+ for( ; links.current( ); ++links )
+ {
+ PMObject* l = links.current( );
+ if( l->parent( ) )
+ l->parent( )->takeChild( l );
+ else
+ m_objects.removeRef( l );
+ m_insertErrors.append( l );
+ }
+ }
+ if( current->linkedObject( ) )
+ current->linkedObject( )->removeLinkedObject( current );
+ error = false;
+ }
+ }
+
+ if( m_pParent->mementoCreated( ) )
+ m_pParentChangeMemento = m_pParent->takeMemento( );
+
+ if( m_pParentChangeMemento )
+ {
+ PMObjectChangeListIterator c = m_pParentChangeMemento->changedObjects( );
+ for( ; c.current( ); ++c )
+ theManager->cmdObjectChanged( c.current( )->object( ),
+ c.current( )->mode( ) );
+ }
+
+ if( m_linksCreated )
+ {
+ PMObjectListIterator rit( m_links );
+ for( ; rit.current( ); ++rit )
+ rit.current( )->linkedObject( )->addLinkedObject( rit.current( ) );
+ PMObjectListIterator dit( m_linkedDeclares );
+ for( ; dit.current( ); ++dit )
+ theManager->cmdObjectChanged( dit.current( ), PMCData );
+ }
+
+ PMObjectListIterator errorit( errors );
+ for( ; errorit.current( ); ++errorit )
+ {
+ m_objects.removeRef( errorit.current( ) );
+ m_insertErrors.append( errorit.current( ) );
+
+ PMRecursiveObjectIterator lit( errorit.current( ) );
+ for( ; lit.current( ); ++lit )
+ if( lit.current( )->linkedObject( ) )
+ lit.current( )->linkedObject( )->removeLinkedObject( lit.current( ) );
+ }
+
+ m_executed = true;
+ m_firstExecution = false;
+ }
+}
+
+void PMAddCommand::undo( PMCommandManager* theManager )
+{
+ if( m_executed )
+ {
+ PMObjectListIterator it( m_objects );
+ PMObject* obj;
+ PMDeclare* decl;
+
+ if( !m_linksCreated )
+ {
+ for( ; it.current( ); ++it )
+ {
+ PMRecursiveObjectIterator lit( it.current( ) );
+ for( ; lit.current( ); ++lit )
+ {
+ decl = lit.current( )->linkedObject( );
+ if( decl )
+ {
+ m_links.append( lit.current( ) );
+ if( !m_linkedDeclares.containsRef( decl ) )
+ m_linkedDeclares.append( decl );
+ }
+ }
+ }
+ m_linksCreated = true;
+ }
+
+ PMObjectListIterator rit( m_links );
+ for( ; rit.current( ); ++rit )
+ rit.current( )->linkedObject( )->removeLinkedObject( rit.current( ) );
+
+ for( it.toLast( ) ; it.current( ); --it )
+ {
+ obj = it.current( );
+ // signal has to be emitted before the item is removed
+ theManager->cmdObjectChanged( obj, PMCRemove );
+
+ if( obj->parent( ) )
+ obj->parent( )->takeChild( obj );
+ }
+
+ if( m_pParentChangeMemento )
+ {
+ m_pParent->restoreMemento( m_pParentChangeMemento );
+ PMObjectChangeListIterator c = m_pParentChangeMemento->changedObjects( );
+ for( ; c.current( ); ++c )
+ {
+ theManager->cmdObjectChanged( c.current( )->object( ),
+ c.current( )->mode( ) );
+ }
+ }
+
+ PMObjectListIterator dit( m_linkedDeclares );
+ for( ; dit.current( ); ++dit )
+ theManager->cmdObjectChanged( dit.current( ), PMCData );
+
+ m_executed = false;
+ }
+}
+
+int PMAddCommand::errorFlags( PMPart* )
+{
+ return PMENone;
+}
diff --git a/kpovmodeler/pmaddcommand.h b/kpovmodeler/pmaddcommand.h
new file mode 100644
index 00000000..97793d03
--- /dev/null
+++ b/kpovmodeler/pmaddcommand.h
@@ -0,0 +1,87 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMADDCOMMAND_H
+#define PMADDCOMMAND_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmcommand.h"
+#include "pmobject.h"
+
+class PMMemento;
+
+/**
+ * Command class for adding a new PMObject
+ */
+class PMAddCommand : public PMCommand
+{
+public:
+ /**
+ * Command that adds a new PMObject.
+ *
+ * The object obj will be inserted as child of parent after
+ * the object after.
+ *
+ * If after is 0, the object becomes the first child.
+ */
+ PMAddCommand( PMObject* obj, PMObject* parent, PMObject* after );
+
+ /**
+ * Command that adds a list of new PMObjects.
+ *
+ * The object in the list will be inserted as children of parent after
+ * the object after.
+ *
+ * If after is 0, the objects will be inserted as first children.
+ */
+ PMAddCommand( const PMObjectList& list, PMObject* parent, PMObject* after );
+ /**
+ * Deletes the command. The inserted object will be deleted, if
+ the command was not executed (or undo-ed) */
+ virtual ~PMAddCommand( );
+
+ /** */
+ virtual int errorFlags( PMPart* );
+
+protected:
+ /**
+ * Executes the command and stores undo information
+ */
+ virtual void execute( PMCommandManager* theManager );
+ /**
+ * Undo the command
+ */
+ virtual void undo( PMCommandManager* theManager );
+
+private:
+ PMObject* m_pParent;
+ PMObjectList m_objects;
+ PMObject* m_pAfter;
+ bool m_executed, m_firstExecution;
+ PMObjectList m_insertErrors;
+ PMObjectList m_links;
+ PMObjectList m_linkedDeclares;
+ bool m_linksCreated;
+ PMMemento* m_pParentChangeMemento;
+};
+
+#endif
diff --git a/kpovmodeler/pmallcommands.h b/kpovmodeler/pmallcommands.h
new file mode 100644
index 00000000..014b5a04
--- /dev/null
+++ b/kpovmodeler/pmallcommands.h
@@ -0,0 +1,27 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMALLCOMMANDS_H
+#define PMALLCOMMANDS_H
+
+#include "pmaddcommand.h"
+#include "pmdeletecommand.h"
+#include "pmmovecommand.h"
+
+#endif
diff --git a/kpovmodeler/pmalledits.h b/kpovmodeler/pmalledits.h
new file mode 100644
index 00000000..e1ee4a5a
--- /dev/null
+++ b/kpovmodeler/pmalledits.h
@@ -0,0 +1,25 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMALLEDITS_H
+#define PMALLEDITS_H
+
+#include "pmboxedit.h"
+
+#endif
diff --git a/kpovmodeler/pmallobjects.h b/kpovmodeler/pmallobjects.h
new file mode 100644
index 00000000..3a02107c
--- /dev/null
+++ b/kpovmodeler/pmallobjects.h
@@ -0,0 +1,106 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMALLOBJECTS_H
+#define PMALLOBJECTS_H
+
+#include "pmscene.h"
+#include "pmglobalsettings.h"
+
+#include "pmbox.h"
+#include "pmsphere.h"
+#include "pmcylinder.h"
+#include "pmcone.h"
+#include "pmtorus.h"
+#include "pmlathe.h"
+#include "pmprism.h"
+#include "pmsor.h"
+#include "pmsqe.h"
+#include "pmheightfield.h"
+#include "pmtext.h"
+#include "pmjuliafractal.h"
+
+#include "pmblob.h"
+#include "pmblobsphere.h"
+#include "pmblobcylinder.h"
+
+#include "pmplane.h"
+#include "pmpolynom.h"
+
+#include "pmdeclare.h"
+#include "pmobjectlink.h"
+
+#include "pmcsg.h"
+
+#include "pmdisc.h"
+#include "pmbicubicpatch.h"
+#include "pmtriangle.h"
+
+#include "pmboundedby.h"
+#include "pmclippedby.h"
+
+#include "pmcamera.h"
+
+#include "pmtranslate.h"
+#include "pmscale.h"
+#include "pmrotate.h"
+#include "pmpovraymatrix.h"
+
+#include "pmlight.h"
+#include "pmlookslike.h"
+#include "pmprojectedthrough.h"
+
+#include "pmtexture.h"
+#include "pmpigment.h"
+#include "pmsolidcolor.h"
+#include "pmlistpattern.h"
+#include "pmquickcolor.h"
+#include "pmnormal.h"
+#include "pmfinish.h"
+#include "pmpattern.h"
+#include "pmblendmapmodifiers.h"
+#include "pmimagemap.h"
+#include "pmbumpmap.h"
+#include "pmtexturemap.h"
+#include "pmmaterialmap.h"
+#include "pmwarp.h"
+#include "pmslope.h"
+#include "pmdensity.h"
+
+#include "pmskysphere.h"
+#include "pmrainbow.h"
+#include "pmfog.h"
+#include "pminterior.h"
+#include "pmmedia.h"
+#include "pmmaterial.h"
+
+#include "pmcomment.h"
+#include "pmraw.h"
+
+// POV-Ray 3.5 objects
+#include "pmisosurface.h"
+#include "pmradiosity.h"
+#include "pmglobalphotons.h"
+#include "pmphotons.h"
+#include "pmlightgroup.h"
+#include "pminteriortexture.h"
+#include "pmspheresweep.h"
+#include "pmmesh.h"
+
+#endif
diff --git a/kpovmodeler/pmbicubicpatch.cpp b/kpovmodeler/pmbicubicpatch.cpp
new file mode 100644
index 00000000..cbc633a9
--- /dev/null
+++ b/kpovmodeler/pmbicubicpatch.cpp
@@ -0,0 +1,544 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmbicubicpatch.h"
+
+#include "pmxmlhelper.h"
+#include "pmbicubicpatchedit.h"
+#include "pmmemento.h"
+#include "pmviewstructure.h"
+#include "pm3dcontrolpoint.h"
+#include "pmmath.h"
+
+#include <klocale.h>
+
+const double c_defaultPatchSize = 6.0;
+const int c_defaultPatchType = 0;
+const int c_defaultPatchUSteps = 3;
+const int c_defaultPatchVSteps = 3;
+const double c_defaultPatchFlatness = 0;
+const PMVector c_defaultUVVector0 = PMVector( 0.0, 0.0 );
+const PMVector c_defaultUVVector1 = PMVector( 1.0, 0.0 );
+const PMVector c_defaultUVVector2 = PMVector( 1.0, 1.0 );
+const PMVector c_defaultUVVector3 = PMVector( 0.0, 1.0 );
+
+PMDefinePropertyClass( PMBicubicPatch, PMBicubicPatchProperty );
+
+class PMPointProperty : public PMPropertyBase
+{
+public:
+ PMPointProperty( )
+ : PMPropertyBase( "controlPoints", PMVariant::Vector )
+ {
+ m_index = 0;
+ }
+ virtual int dimensions( ) const { return 1; }
+ virtual void setIndex( int /*dimension*/, int index )
+ {
+ if( index < 0 || index > 15 )
+ kdError( PMArea ) << "Illegal index in PMBicubicPatch::PointProperty::setIndex" << endl;
+ else
+ m_index = index;
+ }
+ virtual int size( PMObject* /*object*/, int /*dimension*/ ) const
+ {
+ return 16;
+ }
+protected:
+ virtual bool setProtected( PMObject* obj, const PMVariant& v )
+ {
+ PMBicubicPatch* p = ( PMBicubicPatch* ) obj;
+ p->setControlPoint( m_index, v.vectorData( ) );
+ return true;
+ }
+ virtual PMVariant getProtected( const PMObject* obj )
+ {
+ const PMBicubicPatch* p = ( const PMBicubicPatch* ) obj;
+ return PMVariant( p->controlPoint( m_index ) );
+ }
+
+private:
+ int m_index;
+};
+
+class PMUVVectorProperty : public PMPropertyBase
+{
+public:
+ PMUVVectorProperty( )
+ : PMPropertyBase( "uvVectors", PMVariant::Vector )
+ {
+ m_index = 0;
+ }
+ virtual int dimensions( ) const { return 1; }
+ virtual void setIndex( int /*dimension*/, int index )
+ {
+ if( index < 0 || index > 3 )
+ kdError( PMArea ) << "Illegal index in PMBicubicPatch::UVVectorProperty::setIndex" << endl;
+ else
+ m_index = index;
+ }
+ virtual int size( PMObject* /*object*/, int /*dimension*/ ) const
+ {
+ return 3;
+ }
+protected:
+ virtual bool setProtected( PMObject* obj, const PMVariant& v )
+ {
+ PMBicubicPatch* p = ( PMBicubicPatch* ) obj;
+ p->setUVVector( m_index, v.vectorData( ) );
+ return true;
+ }
+ virtual PMVariant getProtected( const PMObject* obj )
+ {
+ const PMBicubicPatch* p = ( const PMBicubicPatch* ) obj;
+ return PMVariant( p->uvVector( m_index ) );
+ }
+
+private:
+ int m_index;
+};
+
+PMMetaObject* PMBicubicPatch::s_pMetaObject = 0;
+PMObject* createNewBicubicPatch( PMPart* part )
+{
+ return new PMBicubicPatch( part );
+}
+
+PMBicubicPatch::PMBicubicPatch( PMPart* part )
+ : Base( part )
+{
+ int x, z;
+ double o = -c_defaultPatchSize / 2.0, s = c_defaultPatchSize / 3.0;
+ m_patchType = c_defaultPatchType;
+ m_numUSteps = c_defaultPatchUSteps;
+ m_numVSteps = c_defaultPatchVSteps;
+ m_flatness = c_defaultPatchFlatness;
+ for( x = 0; x < 4; x++ )
+ for( z = 0; z < 4; z++ )
+ m_point[x+z*4] = PMVector( o + s * x, 0, o + s * z );
+ m_vsUSteps = 0;
+ m_vsVSteps = 0;
+ m_uvEnabled = false;
+ m_uvVectors[0] = c_defaultUVVector0;
+ m_uvVectors[1] = c_defaultUVVector1;
+ m_uvVectors[2] = c_defaultUVVector2;
+ m_uvVectors[3] = c_defaultUVVector3;
+}
+
+PMBicubicPatch::PMBicubicPatch( const PMBicubicPatch& p )
+ : Base( p )
+{
+ int i;
+ m_patchType = p.m_patchType;
+ m_numUSteps = p.m_numUSteps;
+ m_numVSteps = p.m_numVSteps;
+ m_flatness = p.m_flatness;
+ for( i = 0; i < 16; i++ )
+ m_point[i] = p.m_point[i];
+ m_vsUSteps = 0;
+ m_vsVSteps = 0;
+ m_uvEnabled = p.m_uvEnabled;
+ for( i = 0; i < 4; ++i )
+ m_uvVectors[i] = p.m_uvVectors[i];
+}
+
+PMBicubicPatch::~PMBicubicPatch( )
+{
+}
+
+QString PMBicubicPatch::description( ) const
+{
+ return i18n( "bicubic patch" );
+}
+
+void PMBicubicPatch::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ int i;
+
+ e.setAttribute( "type", m_patchType );
+ e.setAttribute( "flatness", m_flatness );
+ e.setAttribute( "uSteps", m_numUSteps );
+ e.setAttribute( "vSteps", m_numVSteps );
+ e.setAttribute( "uvEnabled", m_uvEnabled );
+
+ for( i = 0; i < 16; i++ )
+ e.setAttribute( QString( "cp%1" ).arg( i ), m_point[i].serializeXML( ) );
+
+ for( i = 0; i < 4; ++i )
+ e.setAttribute( QString( "uv%1" ).arg( i ), m_uvVectors[i].serializeXML( ) );
+
+ Base::serialize( e, doc );
+}
+
+void PMBicubicPatch::readAttributes( const PMXMLHelper& h )
+{
+ int u, v;
+ double o = -c_defaultPatchSize / 2.0, s = c_defaultPatchSize / 3.0;
+
+ m_patchType = h.intAttribute( "type", c_defaultPatchType );
+ m_flatness = h.doubleAttribute( "flatness", c_defaultPatchFlatness );
+ m_numUSteps = h.intAttribute( "uSteps", c_defaultPatchUSteps );
+ m_numVSteps = h.intAttribute( "vSteps", c_defaultPatchVSteps );
+ m_uvEnabled = h.boolAttribute( "uvEnabled", m_uvEnabled );
+
+ for( v = 0; v < 4; v++ )
+ for( u = 0; u < 4; u++ )
+ m_point[u+v*4] = h.vectorAttribute( QString( "cp%1" ).arg( u+v*4 ),
+ PMVector( o + s * u, 0, o + s * v ) );
+
+ m_uvVectors[0] = h.vectorAttribute( "uv0", c_defaultUVVector0 );
+ m_uvVectors[1] = h.vectorAttribute( "uv1", c_defaultUVVector1 );
+ m_uvVectors[2] = h.vectorAttribute( "uv2", c_defaultUVVector2 );
+ m_uvVectors[3] = h.vectorAttribute( "uv3", c_defaultUVVector3 );
+
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMBicubicPatch::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "BicubicPatch", Base::metaObject( ),
+ createNewBicubicPatch );
+ s_pMetaObject->addProperty(
+ new PMBicubicPatchProperty( "patchType", &PMBicubicPatch::setPatchType,
+ &PMBicubicPatch::patchType ) );
+ s_pMetaObject->addProperty(
+ new PMBicubicPatchProperty( "uSteps", &PMBicubicPatch::setUSteps,
+ &PMBicubicPatch::uSteps ) );
+ s_pMetaObject->addProperty(
+ new PMBicubicPatchProperty( "vSteps", &PMBicubicPatch::setVSteps,
+ &PMBicubicPatch::vSteps ) );
+ s_pMetaObject->addProperty(
+ new PMBicubicPatchProperty( "flatness", &PMBicubicPatch::setFlatness,
+ &PMBicubicPatch::flatness ) );
+ s_pMetaObject->addProperty(
+ new PMBicubicPatchProperty( "uvEnabled", &PMBicubicPatch::enableUV,
+ &PMBicubicPatch::isUVEnabled ) );
+ s_pMetaObject->addProperty( new PMPointProperty( ) );
+ s_pMetaObject->addProperty( new PMUVVectorProperty( ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMBicubicPatch::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMBicubicPatch::setPatchType( int patchType )
+{
+ if( ( patchType == 0 ) || ( patchType == 1 ) )
+ {
+ if( patchType != m_patchType )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMTypeID, m_patchType );
+ m_patchType = patchType;
+ }
+ }
+ else
+ kdError( PMArea ) << "Wrong type in PMBicubicPatch::setPatchType( )\n";
+}
+
+void PMBicubicPatch::setFlatness( double flatness )
+{
+ if( flatness >= 0.0 )
+ {
+ if( flatness != m_flatness )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFlatnessID, m_flatness );
+ m_flatness = flatness;
+ }
+ }
+ else
+ kdError( PMArea ) << "Flatness has to be >= 0 in PMBicubicPatch::setFlatness( )\n";
+}
+
+void PMBicubicPatch::setUSteps( int steps )
+{
+ if( steps >= 0 )
+ {
+ if( steps != m_numUSteps )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMUStepsID, m_numUSteps );
+ m_numUSteps = steps;
+ setViewStructureChanged( );
+ }
+ }
+ else
+ kdError( PMArea ) << "uSteps has to be >= 0 in PMBicubicPatch::setUSteps( )\n";
+}
+
+void PMBicubicPatch::setVSteps( int steps )
+{
+ if( steps >= 0 )
+ {
+ if( steps != m_numVSteps )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMVStepsID, m_numVSteps );
+ m_numVSteps = steps;
+ setViewStructureChanged( );
+ }
+ }
+ else
+ kdError( PMArea ) << "vSteps has to be >= 0 in PMBicubicPatch::setVSteps( )\n";
+}
+
+void PMBicubicPatch::setControlPoint( int i, const PMVector& p )
+{
+ if( ( i >= 0 ) && ( i <= 15 ) )
+ {
+ if( p != m_point[i] )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMCP0ID + i, m_point[i] );
+ m_point[i] = p;
+ setViewStructureChanged( );
+ }
+ }
+ else
+ kdError( PMArea ) << "Wrong index in PMBicubicPatch::setControlPoint( )\n";
+}
+
+PMVector PMBicubicPatch::controlPoint( int i ) const
+{
+ if( ( i >= 0 ) && ( i <= 15 ) )
+ return m_point[i];
+ else
+ kdError( PMArea ) << "Wrong index in PMBicubicPatch::controlPoint( )\n";
+ return PMVector( 0, 0, 0 );
+}
+
+void PMBicubicPatch::enableUV( bool yes )
+{
+ if( yes != m_uvEnabled )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMUVEnabledID, m_uvEnabled );
+ m_uvEnabled = yes;
+ }
+}
+
+void PMBicubicPatch::setUVVector( int i, const PMVector& v )
+{
+ if ( i >= 0 && i < 4 )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMUV0ID + i, m_uvVectors[i] );
+ m_uvVectors[i] = v;
+ m_uvVectors[i].resize( 2 );
+ }
+ else
+ kdError( PMArea ) << "Wrong index in PMBicubicPatch::setUVVector\n";
+}
+
+PMVector PMBicubicPatch::uvVector( int i ) const
+{
+ if( i >= 0 && i < 4 )
+ return m_uvVectors[i];
+ else
+ kdError( PMArea ) << "Wrong index in PMBicubicPatch::uvVector\n";
+ return PMVector( 0.0, 0.0 );
+}
+
+PMDialogEditBase* PMBicubicPatch::editWidget( QWidget* parent ) const
+{
+ return new PMBicubicPatchEdit( parent );
+}
+
+void PMBicubicPatch::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMTypeID:
+ setPatchType( data->intData( ) );
+ break;
+ case PMFlatnessID:
+ setFlatness( data->doubleData( ) );
+ break;
+ case PMUStepsID:
+ setUSteps( data->intData( ) );
+ break;
+ case PMVStepsID:
+ setVSteps( data->intData( ) );
+ break;
+ case PMUVEnabledID:
+ enableUV( data->boolData( ) );
+ break;
+ default:
+ if( ( data->valueID( ) >= PMCP0ID ) && ( data->valueID( ) <= PMCP15ID ) )
+ setControlPoint( data->valueID( ) - PMCP0ID, data->vectorData( ) );
+ else if ( data->valueID( ) >= PMUV0ID && data->valueID( ) <= PMUV3ID )
+ setUVVector( data->valueID( ) - PMUV0ID, data->vectorData( ) );
+ else
+ kdError( PMArea ) << "Wrong ID in PMBicubicPatch::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
+void PMBicubicPatch::createViewStructure( )
+{
+ int u, v, i, j;
+ int uSteps = m_numUSteps, vSteps = m_numVSteps;
+ if( uSteps > 5 ) uSteps = 5;
+ if( vSteps > 5 ) vSteps = 5;
+ if( uSteps < 0 ) uSteps = 0;
+ if( vSteps < 0 ) vSteps = 0;
+
+ // bugfix: Swap u and v
+ int segmentsU = pmpot( 2, vSteps );
+ int segmentsV = pmpot( 2, uSteps );
+
+ int np = ( segmentsU + 1 ) * ( segmentsV + 1 );
+ int nl = segmentsU * ( segmentsV + 1 ) + ( segmentsU + 1 ) * segmentsV;
+
+ int offset = 0;
+
+ if( !m_pViewStructure )
+ {
+ m_pViewStructure = new PMViewStructure( np, nl );
+ m_vsUSteps = uSteps + 1;
+ }
+ else
+ {
+ if( m_pViewStructure->points( ).size( ) != ( unsigned ) np )
+ m_pViewStructure->points( ).resize( np );
+ if( m_pViewStructure->lines( ).size( ) != ( unsigned ) nl )
+ m_pViewStructure->lines( ).resize( nl );
+ }
+
+ if( ( m_vsUSteps != uSteps ) || ( m_vsVSteps != vSteps ) )
+ {
+ PMLineArray& lines = m_pViewStructure->lines( );
+ int poffset = 0;
+ for( v = 0; v < ( segmentsV + 1 ); v++ )
+ {
+ for( u = 0; u < segmentsU; u++ )
+ {
+ lines[offset + u] = PMLine( poffset, poffset + 1 );
+ poffset++;
+ }
+ poffset++;
+ offset += segmentsU;
+ }
+ poffset = 0;
+ for( v = 0; v < segmentsV; v++ )
+ {
+ for( u = 0; u < ( segmentsU + 1 ); u++ )
+ {
+ lines[offset + u] = PMLine( poffset, poffset + segmentsU + 1 );
+ poffset++;
+ }
+ offset += segmentsU + 1;
+ }
+ m_vsUSteps = uSteps;
+ m_vsVSteps = vSteps;
+ }
+
+ PMPointArray& points = m_pViewStructure->points( );
+
+ offset = 0;
+ double incU = 1.0 / segmentsU;
+ double incV = 1.0 / segmentsV;
+
+ PMVector* hp[4];
+ for( v = 0; v < 4; v++ )
+ hp[v] = new PMVector[segmentsU+1];
+
+ PMVector tp[4];
+
+ double cu, cv;
+
+ // points in u direction
+ for( v = 0; v < 4; v++ )
+ {
+ for( u = 1; u < segmentsU; u++ )
+ {
+ cu = u * incU;
+
+ for( i = 0; i < 4; i++ )
+ tp[i] = m_point[v*4+i];
+ for( i = 3; i > 0; i-- )
+ for( j = 0; j < i; j++ )
+ tp[j] = tp[j] * ( 1 - cu ) + tp[j+1] * cu;
+ hp[v][u] = tp[0];
+ }
+ hp[v][0] = m_point[v*4];
+ hp[v][segmentsU] = m_point[v*4+3];
+ }
+
+ for( v = 0; v <= segmentsV; v++ )
+ {
+ cv = v * incV;
+ for( u = 0; u <= segmentsU; u++ )
+ {
+ for( i = 0; i < 4; i++ )
+ tp[i] = hp[i][u];
+ for( i = 3; i > 0; i-- )
+ for( j = 0; j < i; j++ )
+ tp[j] = tp[j] * ( 1 - cv ) + tp[j+1] * cv;
+ points[offset] = tp[0];
+ offset++;
+ }
+ }
+
+ for( v = 0; v < 4; v++ )
+ delete[] hp[v];
+}
+
+void PMBicubicPatch::controlPoints( PMControlPointList& list )
+{
+ int u, v;
+ for( v = 0; v < 4; v++ )
+ for( u = 0; u < 4; u++ )
+ list.append( new PM3DControlPoint( m_point[u+v*4], u+v*4,
+ i18n( "Point (%1, %2)" ).arg( u ).arg( v ) ) );
+}
+
+void PMBicubicPatch::controlPointsChanged( PMControlPointList& list )
+{
+ PMControlPoint* p;
+
+ for( p = list.first( ); p; p = list.next( ) )
+ {
+ if( p->changed( ) )
+ {
+ setControlPoint( p->id( ), p->position( ) );
+ }
+ }
+}
diff --git a/kpovmodeler/pmbicubicpatch.h b/kpovmodeler/pmbicubicpatch.h
new file mode 100644
index 00000000..c7ca6b3b
--- /dev/null
+++ b/kpovmodeler/pmbicubicpatch.h
@@ -0,0 +1,188 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMBICUBICPATCH_H
+#define PMBICUBICPATCH_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmgraphicalobject.h"
+#include "pmvector.h"
+
+class PMViewStructure;
+
+/**
+ * Class for povray bicubic patches (bezier patches).
+ */
+
+class PMBicubicPatch : public PMGraphicalObject
+{
+ typedef PMGraphicalObject Base;
+public:
+ /**
+ * Creates an empty PMBicubicPatch
+ */
+ PMBicubicPatch( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMBicubicPatch( const PMBicubicPatch& p );
+ /**
+ * deletes the PMBicubicPatch
+ */
+ virtual ~PMBicubicPatch( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMBicubicPatch( *this ); }
+ /** */
+ virtual QString description( ) const;
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMBicubicPatchEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmbicubicpatch" ); }
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /** */
+ virtual void controlPoints( PMControlPointList& list );
+ /** */
+ virtual void controlPointsChanged( PMControlPointList& list );
+ /** */
+ virtual bool multipleSelectControlPoints( ) const { return true; }
+
+ /**
+ * Sets the type. Type must be 0 or 1
+ */
+ void setPatchType( int type );
+ /**
+ * Returns the type
+ */
+ int patchType( ) const { return m_patchType; }
+ /**
+ * Sets the number of u steps
+ */
+ void setUSteps( int steps );
+ /**
+ * Returns the number of u steps
+ */
+ int uSteps( ) const { return m_numUSteps; }
+ /**
+ * Sets the number of v steps
+ */
+ void setVSteps( int steps );
+ /**
+ * Returns the number of v steps
+ */
+ int vSteps( ) const { return m_numVSteps; }
+ /**
+ * Sets the flatness
+ */
+ void setFlatness( double f );
+ /**
+ * Returns the flatness
+ */
+ double flatness( ) const { return m_flatness; }
+
+ /**
+ * Sets the ith patch control point
+ */
+ void setControlPoint( int i, const PMVector& p );
+ /**
+ * Returns the ith patch control point
+ */
+ PMVector controlPoint( int i ) const;
+
+ /**
+ * Sets the uv vectors flag
+ */
+ void enableUV( bool yes );
+ /**
+ * Returns the uv vectors flag
+ */
+ bool isUVEnabled( ) const { return m_uvEnabled; }
+ /**
+ * Sets the ith uv vector
+ */
+ void setUVVector( int i, const PMVector& v );
+ /**
+ * Returns the ith uv vector
+ */
+ PMVector uvVector( int i ) const;
+
+protected:
+ /** */
+ virtual bool isDefault( ) { return false; }
+ /** */
+ virtual void createViewStructure( );
+ /** */
+ virtual PMViewStructure* defaultViewStructure( ) const { return 0; }
+
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMBicubicPatchMementoID { PMTypeID, PMFlatnessID, PMUStepsID,
+ PMVStepsID,
+ PMCP0ID, PMCP1ID, PMCP2ID, PMCP3ID,
+ PMCP4ID, PMCP5ID, PMCP6ID, PMCP7ID,
+ PMCP8ID, PMCP9ID, PMCP10ID, PMCP11ID,
+ PMCP12ID, PMCP13ID, PMCP14ID, PMCP15ID,
+ PMUVEnabledID,
+ PMUV0ID, PMUV1ID, PMUV2ID, PMUV3ID };
+
+ /**
+ * The patch type
+ */
+ int m_patchType;
+ /**
+ * Number of subdivisions
+ */
+ int m_numUSteps, m_numVSteps;
+ /**
+ * Flatness of the patch
+ */
+ double m_flatness;
+ /**
+ * The control points
+ */
+ PMVector m_point[16];
+ int m_vsUSteps, m_vsVSteps;
+ bool m_uvEnabled;
+ PMVector m_uvVectors[4];
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmbicubicpatchedit.cpp b/kpovmodeler/pmbicubicpatchedit.cpp
new file mode 100644
index 00000000..6ead96ae
--- /dev/null
+++ b/kpovmodeler/pmbicubicpatchedit.cpp
@@ -0,0 +1,218 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmbicubicpatchedit.h"
+#include "pmbicubicpatch.h"
+#include "pmvectoredit.h"
+#include "pmlineedits.h"
+#include "pmvectorlistedit.h"
+#include "pmpart.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcombobox.h>
+#include <qcheckbox.h>
+#include <klocale.h>
+
+PMBicubicPatchEdit::PMBicubicPatchEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMBicubicPatchEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* layout;
+
+ m_pType = new QComboBox( false, this );
+ m_pType->insertItem( i18n( "Normal (type 0)" ) );
+ m_pType->insertItem( i18n( "Preprocessed (type 1)" ) );
+ layout = new QHBoxLayout( topLayout( ) );
+ layout->addWidget( new QLabel( i18n( "Type:" ), this ) );
+ layout->addWidget( m_pType );
+ layout->addStretch( 1 );
+
+ m_pUSteps = new PMIntEdit( this );
+ m_pUSteps->setValidation( true, 0, false, 0 );
+ layout = new QHBoxLayout( topLayout( ) );
+ layout->addWidget( new QLabel( i18n( "Steps:" ) + " u", this ) );
+ layout->addWidget( m_pUSteps );
+ m_pVSteps = new PMIntEdit( this );
+ m_pVSteps->setValidation( true, 0, false, 0 );
+ layout->addWidget( new QLabel( "v", this ) );
+ layout->addWidget( m_pVSteps );
+
+ m_pFlatness = new PMFloatEdit( this );
+ m_pFlatness->setValidation( true, 0.0, false, 0.0 );
+ layout = new QHBoxLayout( topLayout( ) );
+ layout->addWidget( new QLabel( i18n( "Flatness:" ), this ) );
+ layout->addWidget( m_pFlatness );
+ layout->addStretch( 1 );
+
+ topLayout( )->addWidget( new QLabel( i18n( "Points:" ), this ) );
+
+ m_pPoints = new PMVectorListEdit( "x", "y", "z", this );
+ m_pPoints->setSize( 16 );
+ topLayout( )->addWidget( m_pPoints );
+
+ m_pUVEnabled = new QCheckBox( i18n( "UV vectors" ), this );
+ topLayout( )->addWidget( m_pUVEnabled );
+ m_pUVVectors = new PMVectorListEdit( "u", "v", this );
+ m_pUVVectors->setSize( 4 );
+ topLayout( )->addWidget( m_pUVVectors );
+
+ connect( m_pType, SIGNAL( highlighted( int ) ), SLOT( slotTypeSelected( int ) ) );
+ connect( m_pUSteps, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pVSteps, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pFlatness, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pPoints, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pPoints, SIGNAL( selectionChanged( ) ),
+ SLOT( slotSelectionChanged( ) ) );
+ connect( m_pUVEnabled, SIGNAL( clicked( ) ), SLOT( slotUVEnabledClicked( ) ) );
+ connect( m_pUVVectors, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMBicubicPatchEdit::displayObject( PMObject* o )
+{
+ int i;
+ if( o->isA( "BicubicPatch" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMBicubicPatch* ) o;
+
+ m_pType->setCurrentItem( m_pDisplayedObject->patchType( ) );
+ m_pType->setEnabled( !readOnly );
+ m_pUSteps->setValue( m_pDisplayedObject->uSteps( ) );
+ m_pUSteps->setReadOnly( readOnly );
+ m_pVSteps->setValue( m_pDisplayedObject->vSteps( ) );
+ m_pVSteps->setReadOnly( readOnly );
+ m_pFlatness->setValue( m_pDisplayedObject->flatness( ) );
+ m_pFlatness->setReadOnly( readOnly );
+
+ for( i = 0; i < 16; i++ )
+ m_pPoints->setVector( i, m_pDisplayedObject->controlPoint( i ) );
+ m_pPoints->setReadOnly( readOnly );
+ updateControlPointSelection( );
+
+ m_pUVEnabled->setChecked( m_pDisplayedObject->isUVEnabled( ) );
+ m_pUVEnabled->setEnabled( !readOnly );
+ for( i = 0; i < 4; ++i )
+ m_pUVVectors->setVector( i, m_pDisplayedObject->uvVector( i ) );
+ m_pUVVectors->setReadOnly( readOnly );
+ slotUVEnabledClicked( );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMBicubicPatchEdit: Can't display object\n";
+}
+
+void PMBicubicPatchEdit::updateControlPointSelection( )
+{
+ PMControlPointList cp = part( )->activeControlPoints( );
+ PMControlPointListIterator it( cp );
+ int s = 0, e = 0;
+
+ m_pPoints->blockSelectionUpdates( true );
+ bool sb = m_pPoints->signalsBlocked( );
+ m_pPoints->blockSignals( true );
+
+ m_pPoints->clearSelection( );
+ while( s < 16 )
+ {
+ if( ( *it )->selected( ) )
+ {
+ for( e = s; e < 16 && ( *it )->selected( ); e++ )
+ ++it;
+ m_pPoints->select( s, e - 1 );
+ s = e;
+ }
+ else
+ {
+ s++;
+ ++it;
+ }
+ }
+
+ m_pPoints->blockSignals( sb );
+ m_pPoints->blockSelectionUpdates( false );
+}
+
+void PMBicubicPatchEdit::saveContents( )
+{
+ int i;
+
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setPatchType( m_pType->currentItem( ) );
+ m_pDisplayedObject->setUSteps( m_pUSteps->value( ) );
+ m_pDisplayedObject->setVSteps( m_pVSteps->value( ) );
+ m_pDisplayedObject->setFlatness( m_pFlatness->value( ) );
+ for( i = 0; i < 16; i++ )
+ m_pDisplayedObject->setControlPoint( i, m_pPoints->vector( i ) );
+ m_pDisplayedObject->enableUV( m_pUVEnabled->isChecked( ) );
+ for( i = 0; i < 4; ++i )
+ m_pDisplayedObject->setUVVector( i, m_pUVVectors->vector( i ) );
+ }
+}
+
+bool PMBicubicPatchEdit::isDataValid( )
+{
+ bool ok = false;
+ if( m_pUSteps->isDataValid( ) )
+ if( m_pVSteps->isDataValid( ) )
+ if( m_pFlatness->isDataValid( ) )
+ ok = true;
+ if( ok )
+ ok = m_pPoints->isDataValid( );
+ if( ok && m_pUVEnabled->isChecked( ) )
+ ok = m_pUVVectors->isDataValid( );
+ if( ok )
+ return Base::isDataValid( );
+ return false;
+}
+
+void PMBicubicPatchEdit::slotTypeSelected( int )
+{
+ emit dataChanged( );
+}
+
+void PMBicubicPatchEdit::slotSelectionChanged( )
+{
+ PMControlPointList cp = part( )->activeControlPoints( );
+ PMControlPointListIterator it( cp );
+ int i;
+ for( i = 0; i < 16; i++, ++it )
+ ( *it )->setSelected( m_pPoints->isSelected( i ) );
+ emit controlPointSelectionChanged( );
+}
+
+void PMBicubicPatchEdit::slotUVEnabledClicked( )
+{
+ if( m_pUVEnabled->isChecked( ) )
+ m_pUVVectors->show( );
+ else
+ m_pUVVectors->hide( );
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+#include "pmbicubicpatchedit.moc"
diff --git a/kpovmodeler/pmbicubicpatchedit.h b/kpovmodeler/pmbicubicpatchedit.h
new file mode 100644
index 00000000..41d173c1
--- /dev/null
+++ b/kpovmodeler/pmbicubicpatchedit.h
@@ -0,0 +1,80 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMBICUBICPATCHEDIT_H
+#define PMBICUBICPATCHEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmgraphicalobjectedit.h"
+
+class PMBicubicPatch;
+class PMIntEdit;
+class PMFloatEdit;
+class PMVectorListEdit;
+class QComboBox;
+class QCheckBox;
+
+/**
+ * Dialog edit class for @ref PMBicubicPatch
+ */
+class PMBicubicPatchEdit : public PMGraphicalObjectEdit
+{
+ Q_OBJECT
+ typedef PMGraphicalObjectEdit Base;
+public:
+ /**
+ * Creates a PMBicubicPatchEdit with parent and name
+ */
+ PMBicubicPatchEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+ /** */
+ virtual void updateControlPointSelection( );
+
+ /** */
+ virtual bool isDataValid( );
+
+protected slots:
+ void slotTypeSelected( int i );
+ void slotSelectionChanged( );
+ void slotUVEnabledClicked( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ QComboBox* m_pType;
+ PMIntEdit* m_pUSteps;
+ PMIntEdit* m_pVSteps;
+ PMFloatEdit* m_pFlatness;
+ PMVectorListEdit* m_pPoints;
+ QCheckBox* m_pUVEnabled;
+ PMVectorListEdit* m_pUVVectors;
+
+ PMBicubicPatch* m_pDisplayedObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmblendmapmodifiers.cpp b/kpovmodeler/pmblendmapmodifiers.cpp
new file mode 100644
index 00000000..0259fb90
--- /dev/null
+++ b/kpovmodeler/pmblendmapmodifiers.cpp
@@ -0,0 +1,284 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#include "pmblendmapmodifiers.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pmblendmapmodifiersedit.h"
+#include "pmvector.h"
+#include "pmenumproperty.h"
+
+#include <klocale.h>
+
+PMDefinePropertyClass( PMBlendMapModifiers, PMBlendMapModifiersProperty );
+PMDefineEnumPropertyClass( PMBlendMapModifiers,
+ PMBlendMapModifiers::PMWaveFormType,
+ PMWaveFormProperty );
+
+PMMetaObject* PMBlendMapModifiers::s_pMetaObject = 0;
+PMObject* createBlendMapModifiers( PMPart* part )
+{
+ return new PMBlendMapModifiers( part );
+}
+
+const double frequencyDefault = 1.0;
+const double phaseDefault = 0.0;
+const PMBlendMapModifiers::PMWaveFormType waveFormTypeDefault = PMBlendMapModifiers::RampWave;
+const double waveFormExponentDefault = 1.0;
+
+
+PMBlendMapModifiers::PMBlendMapModifiers( PMPart* part )
+ : Base( part )
+{
+ m_enableFrequency = false;
+ m_frequency = frequencyDefault;
+ m_enablePhase = false;
+ m_phase = phaseDefault;
+ m_enableWaveForm = false;
+ m_waveFormType = waveFormTypeDefault;
+ m_waveFormExponent = waveFormExponentDefault;
+}
+
+PMBlendMapModifiers::~PMBlendMapModifiers( )
+{
+}
+
+PMMetaObject* PMBlendMapModifiers::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "BlendMapModifiers", Base::metaObject( ),
+ createBlendMapModifiers );
+ s_pMetaObject->addProperty(
+ new PMBlendMapModifiersProperty( "frequencyEnabled", &PMBlendMapModifiers::enableFrequency,
+ &PMBlendMapModifiers::isFrequencyEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMBlendMapModifiersProperty( "frequency", &PMBlendMapModifiers::setFrequency,
+ &PMBlendMapModifiers::frequency ) );
+ s_pMetaObject->addProperty(
+ new PMBlendMapModifiersProperty( "phaseEnabled", &PMBlendMapModifiers::enablePhase,
+ &PMBlendMapModifiers::isPhaseEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMBlendMapModifiersProperty( "phase", &PMBlendMapModifiers::setPhase,
+ &PMBlendMapModifiers::phase ) );
+ s_pMetaObject->addProperty(
+ new PMBlendMapModifiersProperty( "waveFormEnabled", &PMBlendMapModifiers::enableWaveForm,
+ &PMBlendMapModifiers::isWaveFormEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMBlendMapModifiersProperty( "waveFormExponent", &PMBlendMapModifiers::setWaveFormExponent,
+ &PMBlendMapModifiers::waveFormExponent ) );
+
+ PMWaveFormProperty* p = new PMWaveFormProperty(
+ "waveForm", &PMBlendMapModifiers::setWaveFormType,
+ &PMBlendMapModifiers::waveFormType );
+ p->addEnumValue( QString( "RampWave" ), RampWave );
+ p->addEnumValue( QString( "TriangleWave" ), TriangleWave );
+ p->addEnumValue( QString( "SineWave" ), SineWave );
+ p->addEnumValue( QString( "ScallopWave" ), ScallopWave );
+ p->addEnumValue( QString( "CubicWave" ), CubicWave );
+ p->addEnumValue( QString( "PolyWave" ), PolyWave );
+ s_pMetaObject->addProperty( p );
+ }
+ return s_pMetaObject;
+}
+
+void PMBlendMapModifiers::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMBlendMapModifiers::description( ) const
+{
+ return i18n( "blend map modifiers" );
+}
+
+void PMBlendMapModifiers::serialize( QDomElement& e, QDomDocument& ) const
+{
+ e.setAttribute( "frequency", m_frequency );
+ e.setAttribute( "phase", m_phase );
+ e.setAttribute( "enable_frequency", m_enableFrequency );
+ e.setAttribute( "enable_phase", m_enablePhase );
+ e.setAttribute( "wave_exponent", m_waveFormExponent );
+ e.setAttribute( "enable_wave", m_enableWaveForm );
+ switch( m_waveFormType )
+ {
+ case RampWave:
+ e.setAttribute( "waveform_type", "ramp" );
+ break;
+ case TriangleWave:
+ e.setAttribute( "waveform_type", "triangle" );
+ break;
+ case SineWave:
+ e.setAttribute( "waveform_type", "sine" );
+ break;
+ case ScallopWave:
+ e.setAttribute( "waveform_type", "scallop" );
+ break;
+ case CubicWave:
+ e.setAttribute( "waveform_type", "cubic" );
+ break;
+ case PolyWave:
+ e.setAttribute( "waveform_type", "poly" );
+ break;
+ }
+}
+
+void PMBlendMapModifiers::readAttributes( const PMXMLHelper& h )
+{
+ QString str = h.stringAttribute( "waveform_type", "ramp" );
+
+ if( str == "ramp" )
+ m_waveFormType = RampWave;
+ else if( str == "triangle" )
+ m_waveFormType = TriangleWave;
+ else if( str == "sine" )
+ m_waveFormType = SineWave;
+ else if( str == "scallop" )
+ m_waveFormType = ScallopWave;
+ else if( str == "cubic" )
+ m_waveFormType = CubicWave;
+ else if( str == "poly" )
+ m_waveFormType = PolyWave;
+ m_frequency = h.doubleAttribute( "frequency", frequencyDefault );
+ m_enableFrequency = h.boolAttribute( "enable_frequency", false );
+ m_phase = h.doubleAttribute( "phase", phaseDefault );
+ m_enablePhase = h.boolAttribute( "enable_phase", false );
+ m_enableWaveForm = h.boolAttribute( "enable_wave", false );
+ m_waveFormExponent = h.doubleAttribute( "wave_exponent", waveFormExponentDefault );
+}
+
+void PMBlendMapModifiers::setFrequency( double c )
+{
+ if( c != m_frequency )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFrequencyID, m_frequency );
+ m_frequency = c;
+ }
+}
+
+void PMBlendMapModifiers::enableFrequency( bool c )
+{
+ if( c != m_enableFrequency )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableFrequencyID, m_enableFrequency );
+ m_enableFrequency = c;
+ }
+}
+
+void PMBlendMapModifiers::setPhase( double c )
+{
+ if( c != m_phase )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMPhaseID, m_phase );
+ m_phase = c;
+ }
+}
+
+void PMBlendMapModifiers::enablePhase( bool c )
+{
+ if( c != m_enablePhase )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnablePhaseID, m_enablePhase );
+ m_enablePhase = c;
+ }
+}
+
+void PMBlendMapModifiers::enableWaveForm( bool c )
+{
+ if( c != m_enableWaveForm )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableWaveFormID, m_enableWaveForm );
+ m_enableWaveForm = c;
+ }
+}
+
+void PMBlendMapModifiers::setWaveFormExponent( double c )
+{
+ if( c != m_waveFormExponent )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMWaveFormExponentID, m_waveFormExponent );
+ m_waveFormExponent = c;
+ }
+}
+
+void PMBlendMapModifiers::setWaveFormType( PMWaveFormType c )
+{
+ if( c != m_waveFormType )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMWaveFormTypeID, m_waveFormType );
+ m_waveFormType = c;
+ }
+}
+
+PMDialogEditBase* PMBlendMapModifiers::editWidget( QWidget* parent ) const
+{
+ return new PMBlendMapModifiersEdit( parent );
+}
+
+void PMBlendMapModifiers::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMFrequencyID:
+ setFrequency( data->doubleData( ) );
+ break;
+ case PMEnableFrequencyID:
+ enableFrequency( data->boolData( ) );
+ break;
+ case PMPhaseID:
+ setPhase( data->doubleData( ) );
+ break;
+ case PMEnablePhaseID:
+ enablePhase( data->boolData( ) );
+ break;
+ case PMWaveFormTypeID:
+ setWaveFormType( ( PMWaveFormType )data->intData( ) );
+ break;
+ case PMEnableWaveFormID:
+ enableWaveForm( data->boolData( ) );
+ break;
+ case PMWaveFormExponentID:
+ setWaveFormExponent( data->doubleData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMBlendMapModifiers::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmblendmapmodifiers.h b/kpovmodeler/pmblendmapmodifiers.h
new file mode 100644
index 00000000..1fa45528
--- /dev/null
+++ b/kpovmodeler/pmblendmapmodifiers.h
@@ -0,0 +1,129 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMBLENDMAPMODIFIERS_H
+#define PMBLENDMAPMODIFIERS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebase.h"
+#include "pmcolor.h"
+#include "pmvector.h"
+
+/**
+ * Class for povray blendmapmodifierss
+ */
+class PMBlendMapModifiers : public PMObject
+{
+ typedef PMObject Base;
+public:
+ /**
+ * The type of the wave form
+ */
+ enum PMWaveFormType { RampWave, TriangleWave, SineWave, ScallopWave,
+ CubicWave, PolyWave };
+
+ /**
+ * Creates an PMBlendMapModifiers
+ */
+ PMBlendMapModifiers( PMPart* part );
+ /**
+ * Deletes the object
+ */
+ virtual ~PMBlendMapModifiers( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMBlendMapModifiers( *this ); }
+
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMBlendMapModifiersEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmblendmapmodifiers" ); }
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+
+ /** */
+ bool isFrequencyEnabled( ) const { return m_enableFrequency; }
+ /** */
+ double frequency( ) const { return m_frequency; }
+ /** */
+ bool isPhaseEnabled( ) const { return m_enablePhase; }
+ /** */
+ double phase( ) const { return m_phase; }
+ /** */
+ bool isWaveFormEnabled( ) const { return m_enableWaveForm; }
+ /** */
+ PMWaveFormType waveFormType( ) const { return m_waveFormType; }
+ /** */
+ double waveFormExponent( ) const { return m_waveFormExponent; }
+
+ /** */
+ void enableFrequency( bool c );
+ /** */
+ void setFrequency( double c );
+ /** */
+ void enablePhase( bool c );
+ /** */
+ void setPhase( double c );
+ /** */
+ void enableWaveForm( bool c );
+ /** */
+ void setWaveFormType( PMWaveFormType c );
+ /** */
+ void setWaveFormExponent( double c );
+
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMBlendMapModifiersMementoID { PMEnableFrequencyID, PMFrequencyID,
+ PMEnablePhaseID, PMPhaseID, PMEnableWaveFormID,
+ PMWaveFormTypeID, PMWaveFormExponentID };
+
+ bool m_enableFrequency;
+ double m_frequency;
+ bool m_enablePhase;
+ double m_phase;
+ bool m_enableWaveForm;
+ PMWaveFormType m_waveFormType;
+ double m_waveFormExponent;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmblendmapmodifiersedit.cpp b/kpovmodeler/pmblendmapmodifiersedit.cpp
new file mode 100644
index 00000000..8e8ff150
--- /dev/null
+++ b/kpovmodeler/pmblendmapmodifiersedit.cpp
@@ -0,0 +1,261 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+ copyright : (C) 2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmblendmapmodifiersedit.h"
+#include "pmblendmapmodifiers.h"
+#include "pmvectoredit.h"
+#include "pmlineedits.h"
+#include "pmvector.h"
+
+#include <qwidget.h>
+#include <qlayout.h>
+#include <qcombobox.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+#include <qpushbutton.h>
+#include <ktabctl.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdialog.h>
+#include <kfiledialog.h>
+
+PMBlendMapModifiersEdit::PMBlendMapModifiersEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMBlendMapModifiersEdit::createTopWidgets( )
+{
+ QHBoxLayout* hl;
+
+ Base::createTopWidgets( );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ m_pEnableFrequencyEdit = new QCheckBox( i18n( "Frequency:" ), this );
+ m_pFrequencyEdit = new PMFloatEdit( this );
+ hl->addWidget( m_pEnableFrequencyEdit );
+ hl->addWidget( m_pFrequencyEdit );
+ hl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ m_pEnablePhaseEdit = new QCheckBox( i18n( "Phase:" ), this );
+ m_pPhaseEdit = new PMFloatEdit( this );
+ hl->addWidget( m_pEnablePhaseEdit );
+ hl->addWidget( m_pPhaseEdit );
+ hl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ m_pEnableWaveFormEdit = new QCheckBox( i18n( "Wave form:" ), this );
+ m_pWaveTypeCombo = new QComboBox( this );
+ m_pWaveTypeCombo->insertItem( i18n( "Ramp" ) );
+ m_pWaveTypeCombo->insertItem( i18n( "Triangle" ) );
+ m_pWaveTypeCombo->insertItem( i18n( "Sine" ) );
+ m_pWaveTypeCombo->insertItem( i18n( "Scallop" ) );
+ m_pWaveTypeCombo->insertItem( i18n( "Cubic" ) );
+ m_pWaveTypeCombo->insertItem( i18n( "Poly" ) );
+ hl->addWidget( m_pEnableWaveFormEdit );
+ hl->addWidget( m_pWaveTypeCombo );
+ hl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ m_pWaveExponentLabel = new QLabel( i18n( "Exponent:" ), this );
+ m_pWaveExponentEdit = new PMFloatEdit( this );
+ hl->addWidget( m_pWaveExponentLabel );
+ hl->addWidget( m_pWaveExponentEdit );
+ hl->addStretch( 1 );
+
+ connect( m_pEnableFrequencyEdit, SIGNAL( clicked( ) ), SLOT( slotFrequencyClicked( ) ) );
+ connect( m_pFrequencyEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pEnablePhaseEdit, SIGNAL( clicked( ) ), SLOT( slotPhaseClicked( ) ) );
+ connect( m_pPhaseEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pEnableWaveFormEdit, SIGNAL( clicked( ) ), SLOT( slotWaveFormClicked( ) ) );
+ connect( m_pWaveExponentEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pWaveTypeCombo, SIGNAL( activated( int ) ), SLOT( slotTypeComboChanged( int ) ) );
+}
+
+void PMBlendMapModifiersEdit::displayObject( PMObject* o )
+{
+ QString str;
+
+ if( o->isA( "BlendMapModifiers" ) )
+ {
+ m_pDisplayedObject = ( PMBlendMapModifiers* ) o;
+
+ m_pEnableFrequencyEdit->setChecked( m_pDisplayedObject->isFrequencyEnabled( ) );
+ m_pEnablePhaseEdit->setChecked( m_pDisplayedObject->isPhaseEnabled( ) );
+ m_pEnableWaveFormEdit->setChecked( m_pDisplayedObject->isWaveFormEnabled( ) );
+
+ m_pFrequencyEdit->setValue( m_pDisplayedObject->frequency( ) );
+ m_pPhaseEdit->setValue( m_pDisplayedObject->phase( ) );
+ m_pWaveExponentEdit->setValue( m_pDisplayedObject->waveFormExponent( ) );
+
+ switch( m_pDisplayedObject->waveFormType( ) )
+ {
+ case PMBlendMapModifiers::RampWave:
+ m_pWaveTypeCombo->setCurrentItem( 0 );
+ break;
+ case PMBlendMapModifiers::TriangleWave:
+ m_pWaveTypeCombo->setCurrentItem( 1 );
+ break;
+ case PMBlendMapModifiers::SineWave:
+ m_pWaveTypeCombo->setCurrentItem( 2 );
+ break;
+ case PMBlendMapModifiers::ScallopWave:
+ m_pWaveTypeCombo->setCurrentItem( 3 );
+ break;
+ case PMBlendMapModifiers::CubicWave:
+ m_pWaveTypeCombo->setCurrentItem( 4 );
+ break;
+ case PMBlendMapModifiers::PolyWave:
+ m_pWaveTypeCombo->setCurrentItem( 5 );
+ break;
+ }
+
+ slotFrequencyClicked( );
+ slotPhaseClicked( );
+ slotWaveFormClicked( );
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMBlendMapModifiersEdit: Can't display object\n";
+}
+
+void PMBlendMapModifiersEdit::setBlendMapModifiersType( int i )
+{
+ m_pWaveTypeCombo->setCurrentItem( i );
+ slotTypeComboChanged( i );
+}
+
+void PMBlendMapModifiersEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+
+ m_pDisplayedObject->enableFrequency( m_pEnableFrequencyEdit->isChecked( ) );
+ m_pDisplayedObject->enablePhase( m_pEnablePhaseEdit->isChecked( ) );
+ m_pDisplayedObject->enableWaveForm( m_pEnableWaveFormEdit->isChecked( ) );
+
+ if( m_pEnableFrequencyEdit->isChecked( ) )
+ m_pDisplayedObject->setFrequency( m_pFrequencyEdit->value( ) );
+
+ if( m_pEnablePhaseEdit->isChecked( ) )
+ m_pDisplayedObject->setPhase( m_pPhaseEdit->value( ) );
+
+ if( m_pEnableWaveFormEdit->isChecked( ) )
+ {
+ switch( m_pWaveTypeCombo->currentItem( ) )
+ {
+ case 0: /* Ramp Wave */
+ m_pDisplayedObject->setWaveFormType( PMBlendMapModifiers::RampWave );
+ break;
+ case 1: /* Triangle Wave */
+ m_pDisplayedObject->setWaveFormType( PMBlendMapModifiers::TriangleWave );
+ break;
+ case 2: /* Sine Wave */
+ m_pDisplayedObject->setWaveFormType( PMBlendMapModifiers::SineWave );
+ break;
+ case 3: /* Scallop Wave */
+ m_pDisplayedObject->setWaveFormType( PMBlendMapModifiers::ScallopWave );
+ break;
+ case 4: /* Cubic Wave */
+ m_pDisplayedObject->setWaveFormType( PMBlendMapModifiers::CubicWave );
+ break;
+ case 5: /* Poly Wave */
+ m_pDisplayedObject->setWaveFormType( PMBlendMapModifiers::PolyWave );
+ m_pDisplayedObject->setWaveFormExponent( m_pWaveExponentEdit->value( ) );
+ break;
+ }
+ }
+ }
+}
+
+bool PMBlendMapModifiersEdit::isDataValid( )
+{
+ if( !m_pFrequencyEdit->isDataValid( ) ) return false;
+ if( !m_pPhaseEdit->isDataValid( ) ) return false;
+
+ switch( m_pWaveTypeCombo->currentItem( ) )
+ {
+ case 5: /* Poly Wave */
+ if( !m_pWaveExponentEdit->isDataValid( ) ) return false;
+ break;
+ }
+
+ return Base::isDataValid( );
+}
+
+void PMBlendMapModifiersEdit::slotTypeComboChanged( int c )
+{
+ switch( c )
+ {
+ case 5: /* Poly Wave */
+ m_pWaveExponentLabel->show( );
+ m_pWaveExponentEdit->show( );
+ break;
+ default:
+ m_pWaveExponentLabel->hide( );
+ m_pWaveExponentEdit->hide( );
+ break;
+ }
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+void PMBlendMapModifiersEdit::slotFrequencyClicked( )
+{
+ if( m_pEnableFrequencyEdit->isChecked( ) )
+ m_pFrequencyEdit->setEnabled( true );
+ else
+ m_pFrequencyEdit->setEnabled( false );
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+void PMBlendMapModifiersEdit::slotPhaseClicked( )
+{
+ if(m_pEnablePhaseEdit->isChecked( ) )
+ m_pPhaseEdit->setEnabled( true );
+ else
+ m_pPhaseEdit->setEnabled( false );
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+void PMBlendMapModifiersEdit::slotWaveFormClicked( )
+{
+ if(m_pEnableWaveFormEdit->isChecked( ) )
+ {
+ m_pWaveTypeCombo->setEnabled( true );
+ slotTypeComboChanged( m_pWaveTypeCombo->currentItem( ) );
+ }
+ else
+ {
+ m_pWaveTypeCombo->setEnabled( false );
+ m_pWaveExponentLabel->hide( );
+ m_pWaveExponentEdit->hide( );
+ }
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+#include "pmblendmapmodifiersedit.moc"
diff --git a/kpovmodeler/pmblendmapmodifiersedit.h b/kpovmodeler/pmblendmapmodifiersedit.h
new file mode 100644
index 00000000..eb4e40b5
--- /dev/null
+++ b/kpovmodeler/pmblendmapmodifiersedit.h
@@ -0,0 +1,100 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMBLENDMAPMODIFIERSEDIT_H
+#define PMBLENDMAPMODIFIERSEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdialogeditbase.h"
+
+class PMBlendMapModifiers;
+class PMVectorEdit;
+class QComboBox;
+class PMFloatEdit;
+class PMIntEdit;
+class QLabel;
+class QCheckBox;
+class QWidget;
+class QLineEdit;
+class QPushButton;
+
+/**
+ * Dialog edit class for @ref PMBlendMapModifiers.
+ */
+class PMBlendMapModifiersEdit : public PMDialogEditBase
+{
+ Q_OBJECT
+ typedef PMDialogEditBase Base;
+public:
+ /**
+ * Creates a PMBlendMapModifiersEdit with parent and name
+ */
+ PMBlendMapModifiersEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+protected slots:
+ /**
+ * Slot called whenever a new Wave Form type is selected.
+ */
+ void slotTypeComboChanged( int c );
+ /**
+ * Slot called when frequency is activated/deactivated.
+ */
+ void slotFrequencyClicked( );
+ /**
+ * Slot called when phase is activated/deactivated.
+ */
+ void slotPhaseClicked( );
+ /**
+ * Slot called when wave form is activated/deactivated.
+ */
+ void slotWaveFormClicked( );
+
+private:
+ /**
+ * Set's the combo box and enables/disables widgets.
+ */
+ void setBlendMapModifiersType( int i );
+ PMBlendMapModifiers* m_pDisplayedObject;
+
+ QComboBox* m_pWaveTypeCombo;
+ PMFloatEdit* m_pFrequencyEdit;
+ PMFloatEdit* m_pPhaseEdit;
+ PMFloatEdit* m_pWaveExponentEdit;
+ QLabel* m_pWaveExponentLabel;
+ QCheckBox* m_pEnableFrequencyEdit;
+ QCheckBox* m_pEnablePhaseEdit;
+ QCheckBox* m_pEnableWaveFormEdit;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmblob.cpp b/kpovmodeler/pmblob.cpp
new file mode 100644
index 00000000..800c3b5a
--- /dev/null
+++ b/kpovmodeler/pmblob.cpp
@@ -0,0 +1,175 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmblob.h"
+
+#include "pmxmlhelper.h"
+#include "pmblobedit.h"
+#include "pmmemento.h"
+
+#include <klocale.h>
+
+const double c_defaultThreshold = 0.5;
+bool c_defaultSturm = false;
+bool c_defaultHierarchy = false;
+
+PMDefinePropertyClass( PMBlob, PMBlobProperty );
+
+PMMetaObject* PMBlob::s_pMetaObject = 0;
+PMObject* createNewBlob( PMPart* part )
+{
+ return new PMBlob( part );
+}
+
+PMBlob::PMBlob( PMPart* part )
+ : Base( part )
+{
+ m_threshold = c_defaultThreshold;
+ m_sturm = c_defaultSturm;
+ m_hierarchy = c_defaultHierarchy;
+}
+
+PMBlob::PMBlob( const PMBlob& b )
+ : Base( b )
+{
+ m_threshold = b.m_threshold;
+ m_sturm = b.m_sturm;
+ m_hierarchy = b.m_hierarchy;
+}
+
+PMBlob::~PMBlob( )
+{
+}
+
+QString PMBlob::description( ) const
+{
+ return i18n( "blob" );
+}
+
+void PMBlob::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "threshold", m_threshold );
+ e.setAttribute( "sturm", m_sturm );
+ e.setAttribute( "hierarchy", m_hierarchy );
+ Base::serialize( e, doc );
+}
+
+void PMBlob::readAttributes( const PMXMLHelper& h )
+{
+ m_threshold = h.doubleAttribute( "threshold", c_defaultThreshold );
+ m_sturm = h.boolAttribute( "sturm", c_defaultSturm );
+ m_hierarchy = h.boolAttribute( "hierarchy", c_defaultHierarchy );
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMBlob::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Blob", Base::metaObject( ),
+ createNewBlob );
+ s_pMetaObject->addProperty(
+ new PMBlobProperty( "threshold", &PMBlob::setThreshold, &PMBlob::threshold ) );
+ s_pMetaObject->addProperty(
+ new PMBlobProperty( "hierarchy", &PMBlob::setHierarchy, &PMBlob::hierarchy ) );
+ s_pMetaObject->addProperty(
+ new PMBlobProperty( "sturm", &PMBlob::setSturm, &PMBlob::sturm ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMBlob::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMBlob::setThreshold( double t )
+{
+ if( t <= 0.0 )
+ {
+ kdError( PMArea ) << "Threshold is not positive in PMBlob::setThreshold\n";
+ t = 1.0;
+ }
+
+ if( t != m_threshold )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMThresholdID, m_threshold );
+ m_threshold = t;
+ }
+}
+
+void PMBlob::setSturm( bool s )
+{
+ if( s != m_sturm )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSturmID, m_sturm );
+ m_sturm = s;
+ }
+}
+
+void PMBlob::setHierarchy( bool h )
+{
+ if( h != m_hierarchy )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMHierarchyID, m_hierarchy );
+ m_hierarchy = h;
+ }
+}
+
+PMDialogEditBase* PMBlob::editWidget( QWidget* parent ) const
+{
+ return new PMBlobEdit( parent );
+}
+
+void PMBlob::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMThresholdID:
+ setThreshold( data->doubleData( ) );
+ break;
+ case PMSturmID:
+ setSturm( data->boolData( ) );
+ break;
+ case PMHierarchyID:
+ setHierarchy( data->boolData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMBlob::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmblob.h b/kpovmodeler/pmblob.h
new file mode 100644
index 00000000..986cec8c
--- /dev/null
+++ b/kpovmodeler/pmblob.h
@@ -0,0 +1,113 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMBLOB_H
+#define PMBLOB_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobject.h"
+
+/**
+ * Class for povray blobs.
+ */
+
+class PMBlob : public PMSolidObject
+{
+ typedef PMSolidObject Base;
+public:
+ /**
+ * Creates an empty PMBlob
+ */
+ PMBlob( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMBlob( const PMBlob& b );
+ /**
+ * deletes the PMBlob
+ */
+ virtual ~PMBlob( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMBlob( *this ); }
+ /** */
+ virtual QString description( ) const;
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMBlobEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmblob" ); }
+
+ /**
+ * Returns the threshold
+ */
+ double threshold( ) const { return m_threshold; }
+ /**
+ * Sets the threshold
+ */
+ void setThreshold( double t );
+ /**
+ * Returns the hierarchy flag
+ */
+ bool hierarchy( ) const { return m_hierarchy; }
+ /**
+ * Sets the hierarchy flag
+ */
+ void setHierarchy( bool h );
+ /**
+ * Returns the sturm flag
+ */
+ bool sturm( ) const { return m_sturm; }
+ /**
+ * Sets the sturm flag
+ */
+ void setSturm( bool s );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMBlobMementoID { PMThresholdID, PMHierarchyID, PMSturmID };
+ double m_threshold;
+ bool m_hierarchy;
+ bool m_sturm;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmblobcylinder.cpp b/kpovmodeler/pmblobcylinder.cpp
new file mode 100644
index 00000000..687ce132
--- /dev/null
+++ b/kpovmodeler/pmblobcylinder.cpp
@@ -0,0 +1,468 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmblobcylinder.h"
+
+#include "pmxmlhelper.h"
+#include "pmboxedit.h"
+#include "pmmemento.h"
+#include "pm3dcontrolpoint.h"
+#include "pmdefaults.h"
+#include "pmdistancecontrolpoint.h"
+#include "pmblobcylinderedit.h"
+
+#include <klocale.h>
+
+PMDefinePropertyClass( PMBlobCylinder, PMBlobCylinderProperty );
+
+PMMetaObject* PMBlobCylinder::s_pMetaObject = 0;
+PMObject* createNewBlobCylinder( PMPart* part )
+{
+ return new PMBlobCylinder( part );
+}
+
+const double c_defaultRadius = 0.5;
+const PMVector c_defaultEnd1 = PMVector ( 0, 0.5, 0 );
+const PMVector c_defaultEnd2 = PMVector ( 0, -0.5, 0 );
+const double c_defaultStrength = 1.0;
+
+/** default cylinder structure */
+PMViewStructure* PMBlobCylinder::s_pDefaultViewStructure = 0;
+int PMBlobCylinder::s_vStep = c_defaultBlobCylinderVSteps;
+int PMBlobCylinder::s_uStep = c_defaultBlobCylinderUSteps;
+int PMBlobCylinder::s_parameterKey = 0;
+
+
+PMBlobCylinder::PMBlobCylinder( PMPart* part )
+ : Base( part )
+{
+ m_end1 = c_defaultEnd1;
+ m_end2 = c_defaultEnd2;
+ m_radius = c_defaultRadius;
+ m_strength = c_defaultStrength;
+}
+
+PMBlobCylinder::PMBlobCylinder( const PMBlobCylinder& c )
+ : Base( c )
+{
+ m_end1 = c.m_end1;
+ m_end2 = c.m_end2;
+ m_radius = c.m_radius;
+ m_strength = c.m_strength;
+}
+
+PMBlobCylinder::~PMBlobCylinder( )
+{
+}
+
+QString PMBlobCylinder::description( ) const
+{
+ return i18n( "blob cylinder" );
+}
+
+void PMBlobCylinder::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "end_a", m_end1.serializeXML( ) );
+ e.setAttribute( "end_b", m_end2.serializeXML( ) );
+ e.setAttribute( "radius", m_radius );
+ e.setAttribute( "strength", m_strength );
+ Base::serialize( e, doc );
+}
+
+void PMBlobCylinder::readAttributes( const PMXMLHelper& h )
+{
+ m_end1 = h.vectorAttribute( "end_a", c_defaultEnd1 );
+ m_end2 = h.vectorAttribute( "end_b", c_defaultEnd2 );
+ m_radius = h.doubleAttribute( "radius", c_defaultRadius );
+ m_strength = h.doubleAttribute( "strength", c_defaultStrength );
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMBlobCylinder::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "BlobCylinder", Base::metaObject( ),
+ createNewBlobCylinder );
+ s_pMetaObject->addProperty(
+ new PMBlobCylinderProperty( "end1", &PMBlobCylinder::setEnd1,
+ &PMBlobCylinder::end1 ) );
+ s_pMetaObject->addProperty(
+ new PMBlobCylinderProperty( "end2", &PMBlobCylinder::setEnd2,
+ &PMBlobCylinder::end2 ) );
+ s_pMetaObject->addProperty(
+ new PMBlobCylinderProperty( "radius", &PMBlobCylinder::setRadius,
+ &PMBlobCylinder::radius ) );
+ s_pMetaObject->addProperty(
+ new PMBlobCylinderProperty( "strength", &PMBlobCylinder::setStrength,
+ &PMBlobCylinder::strength ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMBlobCylinder::setEnd1( const PMVector& p )
+{
+ if( p != m_end1 )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnd1ID, m_end1 );
+ m_end1 = p;
+ m_end1.resize( 3 );
+ setViewStructureChanged( );
+ }
+}
+
+void PMBlobCylinder::setEnd2( const PMVector& p )
+{
+ if( p != m_end2 )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnd2ID, m_end2 );
+ m_end2 = p;
+ m_end2.resize( 3 );
+ setViewStructureChanged( );
+ }
+}
+
+void PMBlobCylinder::setRadius( double radius )
+{
+ if( m_radius != radius )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMRadiusID, m_radius );
+ m_radius = radius;
+ setViewStructureChanged( );
+ }
+}
+
+void PMBlobCylinder::setStrength( double s )
+{
+ if( s != m_strength )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMStrengthID, m_strength );
+ m_strength = s;
+ }
+}
+
+PMDialogEditBase* PMBlobCylinder::editWidget( QWidget* parent ) const
+{
+ return new PMBlobCylinderEdit( parent );
+}
+
+void PMBlobCylinder::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMEnd1ID:
+ setEnd1( data->vectorData( ) );
+ break;
+ case PMEnd2ID:
+ setEnd2( data->vectorData( ) );
+ break;
+ case PMRadiusID:
+ setRadius( data->doubleData( ) );
+ break;
+ case PMStrengthID:
+ setStrength( data->doubleData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMBlobCylinder::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
+bool PMBlobCylinder::isDefault( )
+{
+ if( ( m_end1 == c_defaultEnd1 ) && ( m_end2 == c_defaultEnd2 )
+ && ( m_radius == c_defaultRadius )
+ && globalDetail( ) )
+ return true;
+ return false;
+}
+
+void PMBlobCylinder::createViewStructure( )
+{
+ if( !m_pViewStructure )
+ {
+ m_pViewStructure = new PMViewStructure( defaultViewStructure ( ) );
+ m_pViewStructure->points( ).detach( );
+ }
+
+ int uStep = (int)( ( (float)s_uStep / 2 ) * ( displayDetail( ) + 1 ) );
+ int vStep = (int)( ( (float)s_vStep / 2 ) * ( displayDetail( ) + 1 ) );
+ unsigned ptsSize = vStep * uStep * 2 + 2;
+ unsigned lineSize = vStep * uStep * 4 + vStep;
+
+ if( ptsSize != m_pViewStructure->points( ).size( ) )
+ m_pViewStructure->points( ).resize( ptsSize );
+
+ createPoints( m_pViewStructure->points( ), m_end1, m_end2, m_radius, uStep, vStep );
+
+ if( lineSize != m_pViewStructure->lines( ).size( ) )
+ {
+ m_pViewStructure->lines( ).detach( );
+ m_pViewStructure->lines( ).resize( lineSize );
+ createLines( m_pViewStructure->lines( ), uStep, vStep );
+ }
+}
+
+PMViewStructure* PMBlobCylinder::defaultViewStructure( ) const
+{
+ if( !s_pDefaultViewStructure || s_pDefaultViewStructure->parameterKey( ) != viewStructureParameterKey( ) )
+ {
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ int uStep = (int)( ( (float)s_uStep / 2 ) * ( displayDetail( ) + 1 ) );
+ int vStep = (int)( ( (float)s_vStep / 2 ) * ( displayDetail( ) + 1 ) );
+
+ s_pDefaultViewStructure =
+ new PMViewStructure( vStep * uStep * 2 + 2,
+ vStep * uStep * 4 + vStep );
+
+ createPoints( s_pDefaultViewStructure->points( ), c_defaultEnd1,
+ c_defaultEnd2, c_defaultRadius, uStep, vStep );
+
+ createLines( s_pDefaultViewStructure->lines( ), uStep, vStep );
+ }
+ return s_pDefaultViewStructure;
+}
+
+void PMBlobCylinder::createLines( PMLineArray& lines, int uStep, int vStep )
+{
+ int u, v;
+ int offset = 0;
+
+ // horizontal lines
+ for( u = 0; u < ( uStep * 2 ); u++ )
+ {
+ for( v = 0; v < ( vStep - 1 ); v++ )
+ lines[offset + v] =
+ PMLine( u * vStep + v + 1, u * vStep + v + 2 );
+ lines[offset + vStep - 1] =
+ PMLine( u * vStep + 1, u * vStep + vStep );
+
+ offset += vStep;
+ }
+
+ // vertical lines
+ // lines at the "north pole"
+ for( v = 0; v < vStep; v++ )
+ lines[offset + v] = PMLine( 0, v + 1 );
+ offset += vStep;
+
+ for( v = 0; v < vStep; v++ )
+ {
+ for( u = 0; u < ( 2 * uStep - 1 ); u++ )
+ {
+ lines[offset + u] =
+ PMLine( u * vStep + v + 1, ( u + 1 ) * vStep + v + 1 );
+ }
+ offset += ( 2 * uStep - 1 );
+ }
+ // lines at the "south pole"
+ for( v = 0; v < vStep; v++ )
+ lines[offset + v] = PMLine( ( 2 * uStep - 1 ) * vStep + v + 1,
+ 2 * uStep * vStep + 1 );
+ // offset += vStep;
+}
+
+void PMBlobCylinder::createPoints( PMPointArray& points, const PMVector& end1,
+ const PMVector& end2, double radius, int uStep, int vStep )
+{
+ double uRadStep = M_PI / uStep / 2.0;
+ double vRadStep = 2 * M_PI / vStep;
+ double du = uRadStep;
+
+ if( radius < 0 )
+ radius = -radius;
+
+ PMVector pointAt = end2 - end1;
+ double pl = pointAt.abs( );
+ if( approxZero( pl ) )
+ pointAt = PMVector( 0.0, 0.0, 1.0 );
+ else
+ pointAt /= pl;
+
+ PMMatrix rotation = PMMatrix::rotation( pointAt, vRadStep );
+ PMVector ortho = pointAt.orthogonal( );
+ ortho /= ortho.abs( );
+
+ points[0] = PMPoint( end1 - pointAt * radius );
+ points[vStep * uStep * 2 + 1] = PMPoint( end2 + pointAt * radius );
+
+ int u, v;
+ for( u = 0; u < uStep; u++ )
+ {
+ PMVector end = ortho * radius * sin( du );
+ PMVector pv = pointAt * radius * cos( du );
+ PMVector e1 = end1 - pv;
+ PMVector e2 = end2 + pv;
+
+ for( v = 0; v < vStep; v++ )
+ {
+ points[u * vStep + v + 1] = PMPoint( e1 + end );
+ points[vStep * uStep * 2 - ( u + 1 ) * vStep + v + 1]
+ = PMPoint( e2 + end );
+ end = rotation * end;
+ }
+ du += uRadStep;
+ }
+}
+
+void PMBlobCylinder::controlPoints( PMControlPointList & list )
+{
+ PMVector center, angle1, angle2;
+ center = m_end1 - m_end2;
+ double pl = center.abs( );
+ if( approxZero( pl ) )
+ center = PMVector( 0.0, 1.0, 0.0 );
+ else
+ center /= pl;
+
+ angle1 = center.orthogonal( );
+ angle2 = PMVector::cross( center, angle1 );
+
+ PM3DControlPoint* pb = new PM3DControlPoint( m_end1, PMEnd1ID, i18n( "End 1" ) );
+ list.append( pb );
+ list.append( new PM3DControlPoint( m_end2, PMEnd2ID, i18n( "End 2" ) ) );
+ list.append( new PMDistanceControlPoint( pb, angle1, m_radius, PMRadiusID, i18n( "Radius (1)" ) ) );
+ list.append( new PMDistanceControlPoint( pb, angle2, m_radius, PMRadiusID, i18n( "Radius (2)" ) ) );
+}
+
+
+void PMBlobCylinder::controlPointsChanged( PMControlPointList & list )
+{
+ PMControlPoint* p;
+ bool pointChanged = false;
+ bool radiusChanged = false;
+
+ for( p = list.first( ); p; p = list.next( ) )
+ {
+ if( p->changed( ) )
+ {
+ switch( p->id( ) )
+ {
+ case PMEnd1ID:
+ setEnd1( ( ( PM3DControlPoint *) p)->point( ) );
+ pointChanged = true;
+ break;
+ case PMEnd2ID:
+ setEnd2( ( ( PM3DControlPoint *) p)->point( ) );
+ pointChanged = true;
+ break;
+ case PMRadiusID:
+ setRadius( ( ( PMDistanceControlPoint *) p)->distance( ) );
+ radiusChanged = true;
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMBlobCylinder::controlPointsChanged\n";
+ break;
+ }
+ }
+ }
+
+ if( pointChanged )
+ {
+ PMVector center, angle1, angle2;
+ bool firstPoint = true;
+
+ center = m_end1 - m_end2;
+ double pl = center.abs( );
+ if( approxZero( pl ) )
+ center = PMVector( 0.0, 1.0, 0.0 );
+ else
+ center /= pl;
+
+ angle1 = center.orthogonal( );
+ angle2 = PMVector::cross( center, angle1 );
+
+ for( p = list.first( ); p; p = list.next( ) )
+ if( p->id( ) == PMRadiusID )
+ {
+ if( firstPoint )
+ {
+ ( ( PMDistanceControlPoint *) p)->setDirection( angle1 );
+ firstPoint = false;
+ }
+ else
+ ( ( PMDistanceControlPoint *) p)->setDirection( angle2 );
+ }
+ }
+
+ if( radiusChanged )
+ for( p = list.first( ); p; p = list.next( ) )
+ if( p->id( ) == PMRadiusID )
+ ( ( PMDistanceControlPoint *) p)->setDistance( m_radius );
+}
+
+void PMBlobCylinder::setUSteps( int u )
+{
+ if( u >= 2 )
+ {
+ s_uStep = u;
+ if( s_pDefaultViewStructure )
+ {
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ }
+ }
+ else
+ kdDebug( PMArea ) << "PMBlobCylinder::setUSteps: U must be greater than 1\n";
+ s_parameterKey++;
+}
+
+void PMBlobCylinder::setVSteps( int v )
+{
+ if( v >= 4 )
+ {
+ s_vStep = v;
+ if( s_pDefaultViewStructure )
+ {
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ }
+ }
+ else
+ kdDebug( PMArea ) << "PMBlobCylinder::setVSteps: V must be greater than 3\n";
+ s_parameterKey++;
+}
+
+void PMBlobCylinder::cleanUp( ) const
+{
+ if( s_pDefaultViewStructure )
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
diff --git a/kpovmodeler/pmblobcylinder.h b/kpovmodeler/pmblobcylinder.h
new file mode 100644
index 00000000..80986cfe
--- /dev/null
+++ b/kpovmodeler/pmblobcylinder.h
@@ -0,0 +1,181 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMBLOBCYLINDER_H
+#define PMBLOBCYLINDER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdetailobject.h"
+#include "pmvector.h"
+#include "pmviewstructure.h"
+
+/**
+ * Class for povray blob cylinder
+ */
+
+class PMBlobCylinder : public PMDetailObject
+{
+ typedef PMDetailObject Base;
+public:
+ /**
+ * Creates a cylinder
+ */
+ PMBlobCylinder( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMBlobCylinder( const PMBlobCylinder& c );
+
+ /**
+ * Deletes the cylinder
+ */
+ virtual ~PMBlobCylinder( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMBlobCylinder( *this ); }
+
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMBlobCylinderEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmblobcylinder" ); }
+
+ /**
+ * Return the end_1
+ */
+ PMVector end1( ) const { return m_end1; }
+ /**
+ * Sets end_1
+ */
+ void setEnd1( const PMVector& p );
+ /**
+ * Return the end_2
+ */
+ PMVector end2( ) const { return m_end2; }
+ /**
+ * Sets end_2
+ */
+ void setEnd2( const PMVector& p );
+ /**
+ * return the radius of the cylinder
+ */
+ double radius( ) const { return m_radius; }
+ /**
+ * Sets the radius of the cylinder
+ */
+ void setRadius( double radius );
+ /**
+ * Returns the strength
+ */
+ double strength( ) const { return m_strength; }
+ /**
+ * Sets the strength
+ */
+ void setStrength( double s );
+
+ /**
+ * Sets the number of latitutes
+ */
+ static void setUSteps( int u );
+ /**
+ * Sets the number of longitudes
+ */
+ static void setVSteps( int v );
+ /**
+ * Returns the number or latitutes
+ */
+ static int uSteps( ) { return s_uStep; }
+ /**
+ * Returns the number or longitudes
+ */
+ static int vSteps( ) { return s_vStep; }
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /** */
+ virtual void controlPoints( PMControlPointList& list );
+ /** */
+ virtual void controlPointsChanged( PMControlPointList& list );
+ /** */
+ virtual bool hasDisplayDetail( ) const { return true; }
+ /** */
+ virtual void cleanUp( ) const;
+
+protected:
+ /** */
+ virtual bool isDefault( );
+ /** */
+ virtual void createViewStructure( );
+ /** */
+ virtual PMViewStructure *defaultViewStructure( ) const;
+ /** */
+ virtual int viewStructureParameterKey( ) const { return s_parameterKey + globalDetailKey(); }
+
+private:
+ /**
+ * Creates the lines for the view structure
+ */
+ static void createLines( PMLineArray& lines, int uStep, int vStep );
+ /**
+ * Creates the points for the view structure
+ */
+ static void createPoints( PMPointArray& points, const PMVector& end1,
+ const PMVector& end2, double radius, int uStep, int vStep );
+
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMBlobCylinderMementoID { PMEnd1ID, PMEnd2ID, PMRadiusID, PMStrengthID };
+ /**
+ * ends of cylinder
+ */
+ PMVector m_end1, m_end2;
+ /**
+ * radius of cylinder
+ */
+ double m_radius;
+ double m_strength;
+ /**
+ * The default view structure. It can be shared between cylinders
+ */
+ static PMViewStructure* s_pDefaultViewStructure;
+ static int s_vStep;
+ static int s_uStep;
+ static int s_parameterKey;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmblobcylinderedit.cpp b/kpovmodeler/pmblobcylinderedit.cpp
new file mode 100644
index 00000000..9313b8af
--- /dev/null
+++ b/kpovmodeler/pmblobcylinderedit.cpp
@@ -0,0 +1,114 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmblobcylinderedit.h"
+#include "pmblobcylinder.h"
+#include "pmvectoredit.h"
+#include "pmlineedits.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <klocale.h>
+#include <qcheckbox.h>
+
+PMBlobCylinderEdit::PMBlobCylinderEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMBlobCylinderEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* layout;
+ QGridLayout* gl;
+
+ m_pEnd1 = new PMVectorEdit( "x", "y", "z", this );
+ m_pEnd2 = new PMVectorEdit( "x", "y", "z", this );
+ m_pRadius = new PMFloatEdit( this );
+ m_pStrength = new PMFloatEdit( this );
+
+ gl = new QGridLayout( topLayout( ), 2, 2 );
+ gl->addWidget( new QLabel( i18n( "End 1:" ), this ), 0, 0 );
+ gl->addWidget( m_pEnd1, 0, 1 );
+ gl->addWidget( new QLabel( i18n( "End 2:" ), this ), 1, 0 );
+ gl->addWidget( m_pEnd2, 1, 1 );
+
+ layout = new QHBoxLayout( topLayout( ) );
+ gl = new QGridLayout( layout, 2, 2 );
+ gl->addWidget( new QLabel( i18n( "Radius:" ), this ), 0, 0 );
+ gl->addWidget( m_pRadius, 0, 1 );
+ gl->addWidget( new QLabel( i18n( "Strength:" ), this ), 1, 0 );
+ gl->addWidget( m_pStrength, 1, 1 );
+ layout->addStretch( 1 );
+
+ connect( m_pEnd1, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pEnd2, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pRadius, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pStrength, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMBlobCylinderEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "BlobCylinder" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMBlobCylinder* ) o;
+
+ m_pEnd1->setVector( m_pDisplayedObject->end1( ) );
+ m_pEnd2->setVector( m_pDisplayedObject->end2( ) );
+ m_pRadius->setValue( m_pDisplayedObject->radius( ) );
+ m_pStrength->setValue( m_pDisplayedObject->strength( ) );
+
+ m_pEnd1->setReadOnly( readOnly );
+ m_pEnd2->setReadOnly( readOnly );
+ m_pRadius->setReadOnly( readOnly );
+ m_pStrength->setReadOnly( readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMBlobCylinderEdit: Can't display object\n";
+}
+
+void PMBlobCylinderEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setEnd1( m_pEnd1->vector( ) );
+ m_pDisplayedObject->setEnd2( m_pEnd2->vector( ) );
+ m_pDisplayedObject->setRadius( m_pRadius->value( ) );
+ m_pDisplayedObject->setStrength( m_pStrength->value( ) );
+ }
+}
+
+bool PMBlobCylinderEdit::isDataValid( )
+{
+ if( m_pEnd1->isDataValid( ) )
+ if( m_pEnd2->isDataValid( ) )
+ if( m_pRadius->isDataValid( ) )
+ if( m_pStrength->isDataValid( ) )
+ return Base::isDataValid( );
+ return false;
+}
+
+#include "pmblobcylinderedit.moc"
+
+
diff --git a/kpovmodeler/pmblobcylinderedit.h b/kpovmodeler/pmblobcylinderedit.h
new file mode 100644
index 00000000..d156e412
--- /dev/null
+++ b/kpovmodeler/pmblobcylinderedit.h
@@ -0,0 +1,61 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMBLOBCYLINDEREDIT_H
+#define PMBLOBCYLINDEREDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdetailobjectedit.h"
+
+class PMVectorEdit;
+class PMFloatEdit;
+class PMBlobCylinder;
+
+class PMBlobCylinderEdit : public PMDetailObjectEdit
+{
+ Q_OBJECT
+ typedef PMDetailObjectEdit Base;
+public:
+ /**
+ * Creates a PMBlobCylinderEdit with parent and name
+ */
+ PMBlobCylinderEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMBlobCylinder* m_pDisplayedObject;
+ PMVectorEdit* m_pEnd1;
+ PMVectorEdit* m_pEnd2;
+ PMFloatEdit* m_pRadius;
+ PMFloatEdit* m_pStrength;
+};
+#endif
diff --git a/kpovmodeler/pmblobedit.cpp b/kpovmodeler/pmblobedit.cpp
new file mode 100644
index 00000000..80ebd510
--- /dev/null
+++ b/kpovmodeler/pmblobedit.cpp
@@ -0,0 +1,96 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmblobedit.h"
+#include "pmblob.h"
+#include "pmlineedits.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <klocale.h>
+
+PMBlobEdit::PMBlobEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMBlobEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "Threshold:" ), this ) );
+ m_pThreshold = new PMFloatEdit( this );
+ hl->addWidget( m_pThreshold );
+ m_pThreshold->setValidation( true, 0.0, false, 0 );
+ m_pThreshold->setValidationOperator( PMFloatEdit::OpGreater,
+ PMFloatEdit::OpLess );
+ hl->addStretch( 1 );
+
+ m_pSturm = new QCheckBox( i18n( "Sturm" ), this );
+ topLayout( )->addWidget( m_pSturm );
+ m_pHierarchy = new QCheckBox( i18n( "Hierarchy" ), this );
+ topLayout( )->addWidget( m_pHierarchy );
+
+ connect( m_pThreshold, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pHierarchy, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pSturm, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMBlobEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Blob" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMBlob* ) o;
+
+ m_pThreshold->setValue( m_pDisplayedObject->threshold( ) );
+ m_pSturm->setChecked( m_pDisplayedObject->sturm( ) );
+ m_pHierarchy->setChecked( m_pDisplayedObject->hierarchy( ) );
+
+ m_pThreshold->setReadOnly( readOnly );
+ m_pSturm->setEnabled( !readOnly );
+ m_pHierarchy->setEnabled( !readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMBlobEdit: Can't display object\n";
+}
+
+void PMBlobEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setThreshold( m_pThreshold->value( ) );
+ m_pDisplayedObject->setSturm( m_pSturm->isChecked( ) );
+ m_pDisplayedObject->setHierarchy( m_pHierarchy->isChecked( ) );
+ }
+}
+
+bool PMBlobEdit::isDataValid( )
+{
+ if( m_pThreshold->isDataValid( ) )
+ return Base::isDataValid( );
+ return false;
+}
+
+#include "pmblobedit.moc"
diff --git a/kpovmodeler/pmblobedit.h b/kpovmodeler/pmblobedit.h
new file mode 100644
index 00000000..df07ba30
--- /dev/null
+++ b/kpovmodeler/pmblobedit.h
@@ -0,0 +1,65 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMBLOBEDIT_H
+#define PMBLOBEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobjectedit.h"
+
+class PMBlob;
+class PMFloatEdit;
+class QCheckBox;
+
+/**
+ * Dialog edit class for @ref PMBlob
+ */
+class PMBlobEdit : public PMSolidObjectEdit
+{
+ Q_OBJECT
+ typedef PMSolidObjectEdit Base;
+public:
+ /**
+ * Creates a PMBlobEdit with parent and name
+ */
+ PMBlobEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMBlob* m_pDisplayedObject;
+ PMFloatEdit* m_pThreshold;
+ QCheckBox* m_pSturm;
+ QCheckBox* m_pHierarchy;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmblobsphere.cpp b/kpovmodeler/pmblobsphere.cpp
new file mode 100644
index 00000000..6ca96769
--- /dev/null
+++ b/kpovmodeler/pmblobsphere.cpp
@@ -0,0 +1,391 @@
+/*
+**************************************************************************
+ description
+ -------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmblobsphere.h"
+
+#include "pmxmlhelper.h"
+#include "pmblobsphereedit.h"
+#include "pmmemento.h"
+#include "pm3dcontrolpoint.h"
+#include "pmdistancecontrolpoint.h"
+#include "pmdefaults.h"
+
+#include <klocale.h>
+
+PMDefinePropertyClass( PMBlobSphere, PMBlobSphereProperty );
+
+PMMetaObject* PMBlobSphere::s_pMetaObject = 0;
+PMObject* createNewBlobSphere( PMPart* part )
+{
+ return new PMBlobSphere( part );
+}
+
+/** default param for the sphere */
+const double c_defaultRadius = 0.5;
+const PMVector c_defaultCentre = PMVector( 0, 0, 0 );
+const double c_defaultStrength = 1.0;
+
+/** default sphere structure */
+PMViewStructure* PMBlobSphere::s_pDefaultViewStructure = 0;
+
+int PMBlobSphere::s_vStep = c_defaultBlobSphereVSteps;
+int PMBlobSphere::s_uStep = c_defaultBlobSphereUSteps;
+int PMBlobSphere::s_parameterKey = 0;
+
+PMBlobSphere::PMBlobSphere( PMPart* part )
+ : Base( part )
+{
+ m_radius = c_defaultRadius;
+ m_centre = c_defaultCentre;
+ m_strength = c_defaultStrength;
+}
+
+PMBlobSphere::PMBlobSphere( const PMBlobSphere& s )
+ : Base( s )
+{
+ m_radius = s.m_radius;
+ m_centre = s.m_centre;
+ m_strength = s.m_strength;
+}
+
+PMBlobSphere::~PMBlobSphere( )
+{
+}
+
+
+QString PMBlobSphere::description( ) const
+{
+ return i18n( "blob sphere" );
+}
+
+PMMetaObject* PMBlobSphere::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "BlobSphere", Base::metaObject( ),
+ createNewBlobSphere );
+ s_pMetaObject->addProperty(
+ new PMBlobSphereProperty( "center", &PMBlobSphere::setCentre,
+ &PMBlobSphere::centre ) );
+ s_pMetaObject->addProperty(
+ new PMBlobSphereProperty( "radius", &PMBlobSphere::setRadius,
+ &PMBlobSphere::radius ) );
+ s_pMetaObject->addProperty(
+ new PMBlobSphereProperty( "strength", &PMBlobSphere::setStrength,
+ &PMBlobSphere::strength ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMBlobSphere::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "centre", m_centre.serializeXML( ) );
+ e.setAttribute( "radius", m_radius );
+ e.setAttribute( "strength", m_strength );
+ Base::serialize( e, doc );
+}
+
+void PMBlobSphere::readAttributes( const PMXMLHelper& h )
+{
+ m_centre = h.vectorAttribute( "centre", c_defaultCentre );
+ m_radius = h.doubleAttribute( "radius", c_defaultRadius );
+ m_strength = h.doubleAttribute( "strength", c_defaultStrength );
+ Base::readAttributes( h );
+}
+
+PMDialogEditBase* PMBlobSphere::editWidget( QWidget* parent ) const
+{
+ return new PMBlobSphereEdit( parent );
+}
+
+void PMBlobSphere::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMRadiusID:
+ setRadius( data->doubleData( ) );
+ break;
+ case PMCentreID:
+ setCentre( data->vectorData( ) );
+ break;
+ case PMStrengthID:
+ setStrength( data->doubleData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PBlobSphere::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+
+}
+
+void PMBlobSphere::controlPoints( PMControlPointList& list )
+{
+ PM3DControlPoint* p = new PM3DControlPoint( m_centre, PMCentreID,
+ i18n( "Center" ) );
+ list.append( p );
+ list.append( new PMDistanceControlPoint( p, PMVector( 1.0, 0.0, 0.0 ),
+ m_radius, PMRadiusID,
+ i18n( "Radius (x)" ) ) );
+ list.append( new PMDistanceControlPoint( p, PMVector( 0.0, 1.0, 0.0 ),
+ m_radius, PMRadiusID,
+ i18n( "Radius (y)" ) ) );
+ list.append( new PMDistanceControlPoint( p, PMVector( 0.0, 0.0, 1.0 ),
+ m_radius, PMRadiusID,
+ i18n( "Radius (z)" ) ) );
+}
+
+void PMBlobSphere::controlPointsChanged( PMControlPointList& list )
+{
+ PMControlPoint* p;
+ bool radiusChanged = false;
+
+ for( p = list.first( ); p; p = list.next( ) )
+ {
+ if( p->changed( ) )
+ {
+ switch( p->id( ) )
+ {
+ case PMCentreID:
+ setCentre( ( ( PM3DControlPoint* ) p )->point( ) );
+ break;
+ case PMRadiusID:
+ setRadius( ( ( PMDistanceControlPoint* ) p )->distance( ) );
+ radiusChanged = true;
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMBlobSphere::controlPointsChanged\n";
+ break;
+ }
+ }
+ }
+
+ if( radiusChanged )
+ for( p = list.first( ); p; p = list.next( ) )
+ if( p->id( ) == PMRadiusID )
+ ( ( PMDistanceControlPoint* ) p )->setDistance( m_radius );
+}
+
+bool PMBlobSphere::isDefault( )
+{
+ if( ( m_radius == c_defaultRadius ) && ( m_centre == c_defaultCentre ) && globalDetail( ) )
+ return true;
+ return false;
+}
+
+void PMBlobSphere::createViewStructure( )
+{
+ if( !m_pViewStructure )
+ {
+ m_pViewStructure = new PMViewStructure( defaultViewStructure( ) );
+ m_pViewStructure->points( ).detach( );
+ }
+
+ int uStep = (int)( ( (float)s_uStep / 2 ) * ( displayDetail( ) + 1 ) );
+ int vStep = (int)( ( (float)s_vStep / 2 ) * ( displayDetail( ) + 1 ) );
+ unsigned ptsSize = vStep * ( uStep - 1 ) + 2;
+ unsigned lineSize = vStep * ( uStep - 1 ) * 2 + vStep;
+
+ if( ptsSize != m_pViewStructure->points( ).size( ) )
+ m_pViewStructure->points( ).resize( ptsSize );
+
+ createPoints( m_pViewStructure->points( ), m_centre, m_radius, uStep, vStep );
+
+ if( lineSize != m_pViewStructure->lines( ).size( ) )
+ {
+ m_pViewStructure->lines( ).detach( );
+ m_pViewStructure->lines( ).resize( lineSize );
+ createLines( m_pViewStructure->lines( ), uStep, vStep );
+ }
+}
+
+PMViewStructure* PMBlobSphere::defaultViewStructure( ) const
+{
+ if( !s_pDefaultViewStructure || s_pDefaultViewStructure->parameterKey( ) != viewStructureParameterKey( ) )
+ {
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ int uStep = (int)( ( (float)s_uStep / 2 ) * ( globalDetailLevel( ) + 1 ) );
+ int vStep = (int)( ( (float)s_vStep / 2 ) * ( globalDetailLevel( ) + 1 ) );
+
+ s_pDefaultViewStructure =
+ new PMViewStructure( vStep * ( uStep - 1 ) + 2,
+ vStep * ( uStep - 1 ) * 2 + vStep );
+
+ createPoints( s_pDefaultViewStructure->points( ), c_defaultCentre,
+ c_defaultRadius, uStep, vStep );
+
+ createLines( s_pDefaultViewStructure->lines( ), uStep, vStep );
+ }
+ return s_pDefaultViewStructure;
+}
+
+void PMBlobSphere::createLines( PMLineArray& lines, int uStep, int vStep )
+{
+ int u, v;
+ int offset = 0;
+
+ // horizontal lines
+ for( u = 0; u < ( uStep - 1 ); u++ )
+ {
+ for( v = 0; v < ( vStep - 1 ); v++ )
+ lines[offset + v] =
+ PMLine( u * vStep + v + 1, u * vStep + v + 2 );
+ lines[offset + vStep - 1] =
+ PMLine( u * vStep + 1, u * vStep + vStep );
+
+ offset += vStep;
+ }
+
+ // vertical lines
+ // lines at the "north pole"
+ for( v = 0; v < vStep; v++ )
+ lines[offset + v] = PMLine( 0, v + 1 );
+ offset += vStep;
+
+ for( v = 0; v < vStep; v++ )
+ {
+ for( u = 0; u < ( uStep - 2 ); u++ )
+ {
+ lines[offset + u] =
+ PMLine( u * vStep + v + 1, ( u + 1 ) * vStep + v + 1 );
+ }
+ offset += ( uStep - 2 );
+ }
+ // lines at the "south pole"
+ for( v = 0; v < vStep; v++ )
+ lines[offset + v] = PMLine( ( uStep - 2 ) * vStep + v + 1,
+ ( uStep - 1 ) * vStep + 1 );
+ // offset += vStep;
+}
+
+void PMBlobSphere::createPoints( PMPointArray& points, const PMVector& centre,
+ double radius, int uStep, int vStep )
+{
+ double l_UradStep = M_PI / uStep;
+ double l_VradStep = ( 2.0 * M_PI ) / vStep;
+ double l_u = l_UradStep;
+ int u, v;
+
+ points[0] = PMPoint( centre + PMVector( 0, radius, 0 ) );
+ points[vStep * ( uStep - 1 ) + 1] =
+ PMPoint( centre - PMVector( 0, radius, 0 ) );
+
+ for( u = 0; u < ( uStep - 1 ); u++ )
+ {
+ double l_v = 0.0;
+ double l_rcosu = radius * sin( l_u );
+ double y = ( radius * cos( l_u ) ) + centre[1];
+ for( v = 0; v < vStep ; v++ )
+ {
+
+ double x = ( l_rcosu * cos( l_v ) ) + centre[0];
+ double z = ( l_rcosu * sin( l_v ) ) + centre[2];
+
+ points[u * vStep + v + 1] = PMPoint( x, y, z );
+ l_v = l_v + l_VradStep;
+ }
+ l_u = l_u + l_UradStep;
+ }
+}
+
+void PMBlobSphere::setRadius( double radius )
+{
+ if( m_radius != radius )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMRadiusID, m_radius );
+ m_radius = radius;
+ setViewStructureChanged( );
+ }
+}
+
+void PMBlobSphere::setCentre( const PMVector& centre )
+{
+ if( m_centre != centre )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMCentreID, m_centre );
+ m_centre = centre;
+ setViewStructureChanged( );
+ }
+}
+
+void PMBlobSphere::setStrength( double s )
+{
+ if( m_strength != s )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMStrengthID, m_strength );
+ m_strength = s;
+ }
+}
+
+void PMBlobSphere::setUSteps( int u )
+{
+ if( u >= 2 )
+ {
+ s_uStep = u;
+ if( s_pDefaultViewStructure )
+ {
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ }
+ }
+ else
+ kdDebug( PMArea ) << "PMBlobSphere::setUSteps: U must be greater than 1\n";
+ s_parameterKey++;
+}
+
+void PMBlobSphere::setVSteps( int v )
+{
+ if( v >= 4 )
+ {
+ s_vStep = v;
+ if( s_pDefaultViewStructure )
+ {
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ }
+ }
+ else
+ kdDebug( PMArea ) << "PMBlobSphere::setVSteps: V must be greater than 3\n";
+ s_parameterKey++;
+}
+
+void PMBlobSphere::cleanUp( ) const
+{
+ if( s_pDefaultViewStructure )
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
diff --git a/kpovmodeler/pmblobsphere.h b/kpovmodeler/pmblobsphere.h
new file mode 100644
index 00000000..bb75b856
--- /dev/null
+++ b/kpovmodeler/pmblobsphere.h
@@ -0,0 +1,168 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ -------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMBLOBSPHERE_H
+#define PMBLOBSPHERE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdetailobject.h"
+#include "pmvector.h"
+#include "pmviewstructure.h"
+
+/**
+ * Class for povray sphere.
+ */
+class PMBlobSphere : public PMDetailObject
+{
+ typedef PMDetailObject Base;
+
+public:
+ /**
+ * Create an empty BlobSphere
+ */
+ PMBlobSphere( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMBlobSphere( const PMBlobSphere& s );
+ /**
+ * Delete the PMBlobSphere
+ */
+ virtual ~PMBlobSphere( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMBlobSphere( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMBlobSphereEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmblobsphere" ); }
+
+ /**
+ * Returns the centre of the sphere
+ */
+ PMVector centre( ) const { return m_centre; }
+ /**
+ * Set the centre of the sphere
+ */
+ void setCentre( const PMVector& centre );
+ /**
+ * returns the radius of the sphere
+ */
+ double radius( ) const { return m_radius; }
+ /**
+ * Sets the radius of the sphere
+ */
+ void setRadius( double radius );
+ /**
+ * Returns the components strength
+ */
+ double strength( ) const { return m_strength; }
+ /**
+ * Sets the strength
+ */
+ void setStrength( double s );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /** */
+ virtual void controlPoints( PMControlPointList& list );
+ /** */
+ virtual void controlPointsChanged( PMControlPointList& list );
+ /** */
+ virtual bool hasDisplayDetail( ) const { return true; }
+
+ /**
+ * Sets the number of latitutes
+ */
+ static void setUSteps( int u );
+ /**
+ * Sets the number of longitudes
+ */
+ static void setVSteps( int v );
+ /**
+ * Returns the number or latitutes
+ */
+ static int uSteps( ) { return s_uStep; }
+ /**
+ * Returns the number or longitudes
+ */
+ static int vSteps( ) { return s_vStep; }
+ /** */
+ virtual void cleanUp( ) const;
+
+protected:
+ /** */
+ virtual bool isDefault( );
+ /** */
+ virtual void createViewStructure( );
+ /** */
+ virtual PMViewStructure* defaultViewStructure( ) const;
+ /** */
+ virtual int viewStructureParameterKey( ) const { return s_parameterKey + globalDetailKey(); }
+
+private:
+ /**
+ * Creates the lines for the view structure
+ */
+ static void createLines( PMLineArray& lines, int uStep, int vStep );
+ /**
+ * Creates the points for the view structure
+ */
+ static void createPoints( PMPointArray& points, const PMVector& centre,
+ double radius, int uStep, int vStep );
+
+ enum PMBlobSphereMementoID { PMRadiusID, PMCentreID, PMStrengthID };
+ /**
+ * Radius of the sphere
+ */
+ double m_radius;
+ /**
+ * centre of the sphere
+ */
+ PMVector m_centre;
+ double m_strength;
+
+ static PMViewStructure* s_pDefaultViewStructure;
+ static int s_vStep;
+ static int s_uStep;
+ static int s_parameterKey;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmblobsphereedit.cpp b/kpovmodeler/pmblobsphereedit.cpp
new file mode 100644
index 00000000..26291248
--- /dev/null
+++ b/kpovmodeler/pmblobsphereedit.cpp
@@ -0,0 +1,102 @@
+/*
+**************************************************************************
+ description
+ -------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmblobsphereedit.h"
+#include "pmblobsphere.h"
+#include "pmvectoredit.h"
+#include "pmlineedits.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <klocale.h>
+
+PMBlobSphereEdit::PMBlobSphereEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMBlobSphereEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* layout;
+
+ m_pCentre = new PMVectorEdit( "x", "y", "z", this );
+ m_pRadius = new PMFloatEdit( this );
+ m_pStrength = new PMFloatEdit( this );
+
+ layout = new QHBoxLayout( topLayout( ) );
+ layout->addWidget( new QLabel( i18n( "Center:" ), this ) );
+ layout->addWidget( m_pCentre );
+
+ layout = new QHBoxLayout( topLayout( ) );
+ QGridLayout* gl = new QGridLayout( layout, 2, 2 );
+ gl->addWidget( new QLabel( i18n( "Radius:" ), this ), 0, 0 );
+ gl->addWidget( m_pRadius, 0, 1 );
+ gl->addWidget( new QLabel( i18n( "Strength:" ), this ), 1, 0 );
+ gl->addWidget( m_pStrength, 1, 1 );
+ layout->addStretch( 1 );
+
+ connect( m_pCentre, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pRadius, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pStrength, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMBlobSphereEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "BlobSphere" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMBlobSphere* ) o;
+
+ m_pCentre->setVector( m_pDisplayedObject->centre( ) );
+ m_pRadius->setValue( m_pDisplayedObject->radius( ) );
+ m_pStrength->setValue( m_pDisplayedObject->strength( ) );
+
+ m_pCentre->setReadOnly( readOnly );
+ m_pRadius->setReadOnly( readOnly );
+ m_pStrength->setReadOnly( readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMBlobSphereEdit: Can't display object\n";
+}
+
+void PMBlobSphereEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setCentre( m_pCentre->vector( ) );
+ m_pDisplayedObject->setRadius( m_pRadius->value( ) );
+ m_pDisplayedObject->setStrength( m_pStrength->value( ) );
+ }
+}
+
+bool PMBlobSphereEdit::isDataValid( )
+{
+ if( m_pCentre->isDataValid( ) )
+ if( m_pRadius->isDataValid( ) )
+ if( m_pStrength->isDataValid( ) )
+ return Base::isDataValid( );
+ return false;
+}
+
+
+#include "pmblobsphereedit.moc"
diff --git a/kpovmodeler/pmblobsphereedit.h b/kpovmodeler/pmblobsphereedit.h
new file mode 100644
index 00000000..08f0f1d4
--- /dev/null
+++ b/kpovmodeler/pmblobsphereedit.h
@@ -0,0 +1,63 @@
+/*
+**************************************************************************
+ description
+ -------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMBLOBSPHEREEDIT_H
+#define PMBLOBSPHEREEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdetailobjectedit.h"
+
+class PMBlobSphere;
+class PMVectorEdit;
+class PMFloatEdit ;
+
+/**
+ * Dialog edit class for @ref PMBlobSphere
+ */
+class PMBlobSphereEdit : public PMDetailObjectEdit
+{
+ Q_OBJECT
+ typedef PMDetailObjectEdit Base;
+public:
+ /**
+ * Creates a PMBlobSphereEdit with parent and name
+ */
+ PMBlobSphereEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMBlobSphere* m_pDisplayedObject;
+ PMVectorEdit* m_pCentre;
+ PMFloatEdit* m_pRadius;
+ PMFloatEdit* m_pStrength;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmboundedby.cpp b/kpovmodeler/pmboundedby.cpp
new file mode 100644
index 00000000..127a05f8
--- /dev/null
+++ b/kpovmodeler/pmboundedby.cpp
@@ -0,0 +1,114 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmboundedby.h"
+#include "pmboundedbyedit.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+
+#include <klocale.h>
+
+PMDefinePropertyClass( PMBoundedBy, PMBoundedByProperty );
+
+PMMetaObject* PMBoundedBy::s_pMetaObject = 0;
+PMObject* createNewBoundedBy( PMPart* part )
+{
+ return new PMBoundedBy( part );
+}
+
+PMBoundedBy::PMBoundedBy( PMPart* part )
+ : Base( part )
+{
+}
+
+PMBoundedBy::~PMBoundedBy( )
+{
+}
+
+PMMetaObject* PMBoundedBy::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "BoundedBy", Base::metaObject( ),
+ createNewBoundedBy );
+ s_pMetaObject->addProperty(
+ new PMBoundedByProperty( "clippedBy", 0, &PMBoundedBy::clippedBy ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMBoundedBy::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMBoundedBy::description( ) const
+{
+ return i18n( "bounded by" );
+}
+
+bool PMBoundedBy::clippedBy( ) const
+{
+ bool cb = true;
+ PMObject* o = firstChild( );
+
+ for( ; o && cb; o = o->nextSibling( ) )
+ if( o->type( ) != "Comment" )
+ cb = false;
+
+ return cb;
+}
+
+void PMBoundedBy::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ // no extra data at the moment
+ Base::serialize( e, doc );
+}
+
+void PMBoundedBy::readAttributes( const PMXMLHelper& h )
+{
+ // no extra data at the moment
+ Base::readAttributes( h );
+}
+
+PMDialogEditBase* PMBoundedBy::editWidget( QWidget* parent ) const
+{
+ return new PMBoundedByEdit( parent );
+}
+
+void PMBoundedBy::childRemoved( PMObject* o )
+{
+ Base::childRemoved( o );
+
+ // add a dummy change
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMClippedByID, true );
+}
+
+void PMBoundedBy::childAdded( PMObject* o )
+{
+ Base::childAdded( o );
+
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMClippedByID, true );
+}
diff --git a/kpovmodeler/pmboundedby.h b/kpovmodeler/pmboundedby.h
new file mode 100644
index 00000000..22ac3fb4
--- /dev/null
+++ b/kpovmodeler/pmboundedby.h
@@ -0,0 +1,89 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMBOUNDEDBY_H
+#define PMBOUNDEDBY_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmcompositeobject.h"
+
+/**
+ * class for bounded_by povray statements
+ */
+
+class PMBoundedBy : public PMCompositeObject
+{
+ typedef PMCompositeObject Base;
+public:
+ /**
+ * Creates an empty PMBoundedBy
+ */
+ PMBoundedBy( PMPart* part );
+ /**
+ * Deletes the object
+ */
+ ~PMBoundedBy( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMBoundedBy( *this ); }
+
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual bool dataChangeOnInsertRemove( ) const { return true; }
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMBoundedByEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmboundedby" ); }
+
+ /** */
+ virtual void childRemoved( PMObject* );
+ /** */
+ virtual void childAdded( PMObject* );
+
+ /**
+ * Returns true if the object contains no child objects (exmbumcept comments)
+ */
+ bool clippedBy( ) const;
+
+private:
+ enum PMBoundedByMementoID { PMClippedByID };
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmboundedbyedit.cpp b/kpovmodeler/pmboundedbyedit.cpp
new file mode 100644
index 00000000..2bf1409e
--- /dev/null
+++ b/kpovmodeler/pmboundedbyedit.cpp
@@ -0,0 +1,65 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmboundedbyedit.h"
+#include "pmboundedby.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <klocale.h>
+
+PMBoundedByEdit::PMBoundedByEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMBoundedByEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ m_pChildLabel = new QLabel( i18n( "No child objects" ), this );
+ topLayout( )->addWidget( m_pChildLabel );
+ m_pClippedByLabel = new QLabel( i18n( "(= clipped by)" ), this );
+ topLayout( )->addWidget( m_pClippedByLabel );
+}
+
+void PMBoundedByEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "BoundedBy" ) )
+ {
+ m_pDisplayedObject = ( PMBoundedBy* ) o;
+
+ if( m_pDisplayedObject->clippedBy( ) )
+ {
+ m_pChildLabel->show( );
+ m_pClippedByLabel->show( );
+ }
+ else
+ {
+ m_pChildLabel->hide( );
+ m_pClippedByLabel->hide( );
+ }
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMBoundedByEdit: Can't display object\n";
+}
+
+#include "pmboundedbyedit.moc"
diff --git a/kpovmodeler/pmboundedbyedit.h b/kpovmodeler/pmboundedbyedit.h
new file mode 100644
index 00000000..f4d24a41
--- /dev/null
+++ b/kpovmodeler/pmboundedbyedit.h
@@ -0,0 +1,59 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMBOUNDEDBYEDIT_H
+#define PMBOUNDEDBYEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdialogeditbase.h"
+
+class PMBoundedBy;
+class QLabel;
+
+/**
+ * Dialog edit class for @ref PMBoundedBy
+ */
+class PMBoundedByEdit : public PMDialogEditBase
+{
+ Q_OBJECT
+ typedef PMDialogEditBase Base;
+public:
+ /**
+ * Creates a PMBoundedByEdit with parent and name
+ */
+ PMBoundedByEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+protected:
+ /** */
+ virtual void createTopWidgets( );
+
+private:
+ PMBoundedBy* m_pDisplayedObject;
+ QLabel* m_pChildLabel;
+ QLabel* m_pClippedByLabel;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmbox.cpp b/kpovmodeler/pmbox.cpp
new file mode 100644
index 00000000..045389bb
--- /dev/null
+++ b/kpovmodeler/pmbox.cpp
@@ -0,0 +1,276 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmbox.h"
+
+#include "pmxmlhelper.h"
+#include "pmboxedit.h"
+#include "pmmemento.h"
+#include "pmviewstructure.h"
+#include "pm3dcontrolpoint.h"
+
+#include <klocale.h>
+
+const double defaultBoxSize = 0.5;
+const PMVector corner1Default = PMVector( -defaultBoxSize, -defaultBoxSize, -defaultBoxSize );
+const PMVector corner2Default = PMVector( defaultBoxSize, defaultBoxSize, defaultBoxSize );
+
+PMDefinePropertyClass( PMBox, PMBoxProperty );
+
+PMViewStructure* PMBox::s_pDefaultViewStructure = 0;
+PMMetaObject* PMBox::s_pMetaObject = 0;
+PMObject* createNewBox( PMPart* part )
+{
+ return new PMBox( part );
+}
+
+PMBox::PMBox( PMPart* part )
+ : Base( part )
+{
+ m_corner1 = corner1Default;
+ m_corner2 = corner2Default;
+}
+
+PMBox::PMBox( const PMBox& b )
+ : Base( b )
+{
+ m_corner1 = b.m_corner1;
+ m_corner2 = b.m_corner2;
+}
+
+PMBox::~PMBox( )
+{
+}
+
+QString PMBox::description( ) const
+{
+ return i18n( "box" );
+}
+
+void PMBox::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "corner_a", m_corner1.serializeXML( ) );
+ e.setAttribute( "corner_b", m_corner2.serializeXML( ) );
+ Base::serialize( e, doc );
+}
+
+void PMBox::readAttributes( const PMXMLHelper& h )
+{
+ m_corner1 = h.vectorAttribute( "corner_a", corner1Default );
+ m_corner2 = h.vectorAttribute( "corner_b", corner2Default );
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMBox::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Box", Base::metaObject( ),
+ createNewBox );
+ s_pMetaObject->addProperty(
+ new PMBoxProperty( "corner1", &PMBox::setCorner1, &PMBox::corner1 ) );
+ s_pMetaObject->addProperty(
+ new PMBoxProperty( "corner2", &PMBox::setCorner2, &PMBox::corner2 ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMBox::setCorner1( const PMVector& p )
+{
+ if( p != m_corner1 )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMCorner1ID, m_corner1 );
+ m_corner1 = p;
+ m_corner1.resize( 3 );
+ setViewStructureChanged( );
+ }
+}
+
+void PMBox::setCorner2( const PMVector& p )
+{
+ if( p != m_corner2 )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMCorner2ID, m_corner2 );
+ m_corner2 = p;
+ m_corner2.resize( 3 );
+ setViewStructureChanged( );
+ }
+}
+
+PMDialogEditBase* PMBox::editWidget( QWidget* parent ) const
+{
+ return new PMBoxEdit( parent );
+}
+
+void PMBox::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMCorner1ID:
+ setCorner1( data->vectorData( ) );
+ break;
+ case PMCorner2ID:
+ setCorner2( data->vectorData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMBox::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
+
+bool PMBox::isDefault( )
+{
+ if( ( m_corner1 == corner1Default ) && ( m_corner2 == corner2Default ) )
+ return true;
+ return false;
+}
+
+void PMBox::createViewStructure( )
+{
+ if( !m_pViewStructure )
+ {
+ m_pViewStructure = new PMViewStructure( defaultViewStructure( ) );
+ m_pViewStructure->points( ).detach( );
+ }
+
+ PMPointArray& points = m_pViewStructure->points( );
+
+ points[0][0] = m_corner1[0];
+ points[0][1] = m_corner1[1];
+ points[0][2] = m_corner1[2];
+
+ points[1][0] = m_corner2[0];
+ points[1][1] = m_corner1[1];
+ points[1][2] = m_corner1[2];
+
+ points[2][0] = m_corner2[0];
+ points[2][1] = m_corner1[1];
+ points[2][2] = m_corner2[2];
+
+ points[3][0] = m_corner1[0];
+ points[3][1] = m_corner1[1];
+ points[3][2] = m_corner2[2];
+
+ points[4][0] = m_corner1[0];
+ points[4][1] = m_corner2[1];
+ points[4][2] = m_corner1[2];
+
+ points[5][0] = m_corner2[0];
+ points[5][1] = m_corner2[1];
+ points[5][2] = m_corner1[2];
+
+ points[6][0] = m_corner2[0];
+ points[6][1] = m_corner2[1];
+ points[6][2] = m_corner2[2];
+
+ points[7][0] = m_corner1[0];
+ points[7][1] = m_corner2[1];
+ points[7][2] = m_corner2[2];
+}
+
+PMViewStructure* PMBox::defaultViewStructure( ) const
+{
+ if( !s_pDefaultViewStructure )
+ {
+ s_pDefaultViewStructure = new PMViewStructure( 8, 12 );
+ PMPointArray& points = s_pDefaultViewStructure->points( );
+ PMLineArray& lines = s_pDefaultViewStructure->lines( );
+
+ points[0] = PMPoint( -defaultBoxSize, -defaultBoxSize, -defaultBoxSize );
+ points[1] = PMPoint( defaultBoxSize, -defaultBoxSize, -defaultBoxSize );
+ points[2] = PMPoint( defaultBoxSize, -defaultBoxSize, defaultBoxSize );
+ points[3] = PMPoint( -defaultBoxSize, -defaultBoxSize, defaultBoxSize );
+ points[4] = PMPoint( -defaultBoxSize, defaultBoxSize, -defaultBoxSize );
+ points[5] = PMPoint( defaultBoxSize, defaultBoxSize, -defaultBoxSize );
+ points[6] = PMPoint( defaultBoxSize, defaultBoxSize, defaultBoxSize );
+ points[7] = PMPoint( -defaultBoxSize, defaultBoxSize, defaultBoxSize );
+
+ lines[ 0] = PMLine( 0, 1 );
+ lines[ 1] = PMLine( 0, 3 );
+ lines[ 2] = PMLine( 0, 4 );
+ lines[ 3] = PMLine( 1, 2 );
+ lines[ 4] = PMLine( 1, 5 );
+ lines[ 5] = PMLine( 2, 3 );
+ lines[ 6] = PMLine( 2, 6 );
+ lines[ 7] = PMLine( 3, 7 );
+ lines[ 8] = PMLine( 4, 5 );
+ lines[ 9] = PMLine( 4, 7 );
+ lines[10] = PMLine( 5, 6 );
+ lines[11] = PMLine( 6, 7 );
+ }
+ return s_pDefaultViewStructure;
+}
+
+void PMBox::controlPoints( PMControlPointList& list )
+{
+ list.append( new PM3DControlPoint( m_corner1, PMCorner1ID,
+ i18n( "Corner 1" ) ) );
+ list.append( new PM3DControlPoint( m_corner2, PMCorner2ID,
+ i18n( "Corner 2" ) ) );
+}
+
+void PMBox::controlPointsChanged( PMControlPointList& list )
+{
+ PMControlPoint* p;
+
+ for( p = list.first( ); p; p = list.next( ) )
+ {
+ if( p->changed( ) )
+ {
+ switch( p->id( ) )
+ {
+ case PMCorner1ID:
+ setCorner1( ( ( PM3DControlPoint* ) p )->point( ) );
+ break;
+ case PMCorner2ID:
+ setCorner2( ( ( PM3DControlPoint* ) p )->point( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMBox::controlPointsChanged\n";
+ break;
+ }
+ }
+ }
+}
+
+void PMBox::cleanUp( ) const
+{
+ if( s_pDefaultViewStructure )
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
diff --git a/kpovmodeler/pmbox.h b/kpovmodeler/pmbox.h
new file mode 100644
index 00000000..d6627ffe
--- /dev/null
+++ b/kpovmodeler/pmbox.h
@@ -0,0 +1,123 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMBOX_H
+#define PMBOX_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobject.h"
+#include "pmvector.h"
+
+class PMViewStructure;
+
+/**
+ * Class for povray boxes.
+ */
+
+class PMBox : public PMSolidObject
+{
+ typedef PMSolidObject Base;
+public:
+ /**
+ * Creates an empty PMBox
+ */
+ PMBox( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMBox( const PMBox& b );
+ /**
+ * deletes the PMBox
+ */
+ virtual ~PMBox( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMBox( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMBoxEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmbox" ); }
+
+ /**
+ * Returns Corner_1
+ */
+ PMVector corner1( ) const { return m_corner1; }
+ /**
+ * Sets Corner_1
+ */
+ void setCorner1( const PMVector& p );
+ /**
+ * Returns Corner_2
+ */
+ PMVector corner2( ) const { return m_corner2; }
+ /**
+ * Sets Corner_2
+ */
+ void setCorner2( const PMVector& p );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /** */
+ virtual void controlPoints( PMControlPointList& list );
+ /** */
+ virtual void controlPointsChanged( PMControlPointList& list );
+ /** */
+ virtual void cleanUp( ) const;
+
+protected:
+ /** */
+ virtual bool isDefault( );
+ /** */
+ virtual void createViewStructure( );
+ /** */
+ virtual PMViewStructure* defaultViewStructure( ) const;
+
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMBoxMementoID { PMCorner1ID, PMCorner2ID };
+ PMVector m_corner1, m_corner2;
+
+ /**
+ * The default view structure. It can be shared between boxes
+ */
+ static PMViewStructure* s_pDefaultViewStructure;
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmboxedit.cpp b/kpovmodeler/pmboxedit.cpp
new file mode 100644
index 00000000..2db1eb79
--- /dev/null
+++ b/kpovmodeler/pmboxedit.cpp
@@ -0,0 +1,86 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmboxedit.h"
+#include "pmbox.h"
+#include "pmvectoredit.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <klocale.h>
+
+PMBoxEdit::PMBoxEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMBoxEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ m_pCorner1 = new PMVectorEdit( "x", "y", "z", this );
+ m_pCorner2 = new PMVectorEdit( "x", "y", "z", this );
+
+ QGridLayout* gl = new QGridLayout( topLayout( ), 2, 2 );
+ gl->addWidget( new QLabel( i18n( "Corner 1:" ), this ), 0, 0 );
+ gl->addWidget( m_pCorner1, 0, 1 );
+ gl->addWidget( new QLabel( i18n( "Corner 2:" ), this ), 1, 0 );
+ gl->addWidget( m_pCorner2, 1, 1 );
+
+ connect( m_pCorner1, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pCorner2, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMBoxEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Box" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMBox* ) o;
+
+ m_pCorner1->setVector( m_pDisplayedObject->corner1( ) );
+ m_pCorner2->setVector( m_pDisplayedObject->corner2( ) );
+
+ m_pCorner1->setReadOnly( readOnly );
+ m_pCorner2->setReadOnly( readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMBoxEdit: Can't display object\n";
+}
+
+void PMBoxEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setCorner1( m_pCorner1->vector( ) );
+ m_pDisplayedObject->setCorner2( m_pCorner2->vector( ) );
+ }
+}
+
+bool PMBoxEdit::isDataValid( )
+{
+ if( m_pCorner1->isDataValid( ) )
+ if( m_pCorner2->isDataValid( ) )
+ return Base::isDataValid( );
+ return false;
+}
+#include "pmboxedit.moc"
diff --git a/kpovmodeler/pmboxedit.h b/kpovmodeler/pmboxedit.h
new file mode 100644
index 00000000..4f87ceac
--- /dev/null
+++ b/kpovmodeler/pmboxedit.h
@@ -0,0 +1,63 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMBOXEDIT_H
+#define PMBOXEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobjectedit.h"
+
+class PMBox;
+class PMVectorEdit;
+
+/**
+ * Dialog edit class for @ref PMBox
+ */
+class PMBoxEdit : public PMSolidObjectEdit
+{
+ Q_OBJECT
+ typedef PMSolidObjectEdit Base;
+public:
+ /**
+ * Creates a PMBoxEdit with parent and name
+ */
+ PMBoxEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMBox* m_pDisplayedObject;
+ PMVectorEdit* m_pCorner1;
+ PMVectorEdit* m_pCorner2;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmbumpmap.cpp b/kpovmodeler/pmbumpmap.cpp
new file mode 100644
index 00000000..e9549bd9
--- /dev/null
+++ b/kpovmodeler/pmbumpmap.cpp
@@ -0,0 +1,384 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Passos Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmbumpmapedit.h"
+#include "pmbumpmap.h"
+#include "pmpalettevalue.h"
+#include "pmpalettevaluememento.h"
+
+#include "pmxmlhelper.h"
+#include "pmcompositeobject.h"
+#include "pmmemento.h"
+#include "pmenumproperty.h"
+
+#include <klocale.h>
+
+const PMBumpMap::PMBitmapType bitmapTypeDefault = PMBumpMap::BitmapSys;
+const char *const bitmapFileDefault = 0;
+const bool enableFilterAllDefault = false;
+const bool enableTransmitAllDefault = false;
+const double filterAllDefault = 0.0;
+const double transmitAllDefault = 0.0;
+const bool onceDefault = false;
+const PMBumpMap::PMMapType mapTypeDefault = PMBumpMap::MapPlanar;
+const PMBumpMap::PMInterpolateType interpolateTypeDefault = PMBumpMap::InterpolateNone;
+const bool useIndexDefault = false;
+const double bumpSizeDefault = 0.0;
+
+PMDefinePropertyClass( PMBumpMap, PMBumpMapProperty );
+PMDefineEnumPropertyClass( PMBumpMap, PMBumpMap::PMBitmapType,
+ PMBitmapTypeProperty );
+PMDefineEnumPropertyClass( PMBumpMap, PMBumpMap::PMInterpolateType,
+ PMInterpolateTypeProperty );
+PMDefineEnumPropertyClass( PMBumpMap, PMBumpMap::PMMapType,
+ PMMapTypeProperty );
+
+PMMetaObject* PMBumpMap::s_pMetaObject = 0;
+PMObject* createNewBumpMap( PMPart* part )
+{
+ return new PMBumpMap( part );
+}
+
+PMBumpMap::PMBumpMap( PMPart* part )
+ : Base( part )
+{
+ m_bitmapType = bitmapTypeDefault;
+ m_bitmapFile = bitmapFileDefault;
+ m_once = onceDefault;
+ m_mapType = mapTypeDefault;
+ m_interpolateType = interpolateTypeDefault;
+ m_useIndex = useIndexDefault;
+ m_bumpSize = bumpSizeDefault;
+}
+
+PMBumpMap::PMBumpMap( const PMBumpMap& m )
+ : Base( m )
+{
+ m_bitmapType = m.m_bitmapType;
+ m_bitmapFile = m.m_bitmapFile;
+ m_once = m.m_once;
+ m_mapType = m.m_mapType;
+ m_interpolateType = m.m_interpolateType;
+ m_useIndex = m.m_useIndex;
+ m_bumpSize = m.m_bumpSize;
+}
+
+PMBumpMap::~PMBumpMap( )
+{
+}
+
+void PMBumpMap::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ switch( m_bitmapType )
+ {
+ case BitmapGif:
+ e.setAttribute( "bitmap_type", "gif" );
+ break;
+ case BitmapTga:
+ e.setAttribute( "bitmap_type", "tga" );
+ break;
+ case BitmapIff:
+ e.setAttribute( "bitmap_type", "iff" );
+ break;
+ case BitmapPpm:
+ e.setAttribute( "bitmap_type", "ppm" );
+ break;
+ case BitmapPgm:
+ e.setAttribute( "bitmap_type", "pgm" );
+ break;
+ case BitmapPng:
+ e.setAttribute( "bitmap_type", "png" );
+ break;
+ case BitmapJpeg:
+ e.setAttribute( "bitmap_type", "jpeg" );
+ break;
+ case BitmapTiff:
+ e.setAttribute( "bitmap_type", "tiff" );
+ break;
+ case BitmapSys:
+ e.setAttribute( "bitmap_type", "sys" );
+ break;
+ }
+ e.setAttribute( "file_name", m_bitmapFile );
+ e.setAttribute( "once", m_once );
+ switch( m_mapType )
+ {
+ case MapPlanar:
+ e.setAttribute( "map_type", "planar" );
+ break;
+ case MapSpherical:
+ e.setAttribute( "map_type", "spherical" );
+ break;
+ case MapCylindrical:
+ e.setAttribute( "map_type", "cylindrical" );
+ break;
+ case MapToroidal:
+ e.setAttribute( "map_type", "toroidal" );
+ break;
+ }
+ switch( m_interpolateType )
+ {
+ case InterpolateNone:
+ e.setAttribute( "interpolate", "none" );
+ break;
+ case InterpolateBilinear:
+ e.setAttribute( "interpolate", "bilinear" );
+ break;
+ case InterpolateNormalized:
+ e.setAttribute( "interpolate", "normalized" );
+ break;
+ }
+ e.setAttribute( "use_index", m_useIndex );
+ e.setAttribute( "bump_size", m_bumpSize );
+
+ Base::serialize( e, doc );
+}
+
+void PMBumpMap::readAttributes( const PMXMLHelper& h )
+{
+ QString str;
+
+ str = h.stringAttribute( "bitmap_type", "sys" );
+ if( str == "gif" )
+ m_bitmapType = BitmapGif;
+ else if( str == "tga" )
+ m_bitmapType = BitmapTga;
+ else if( str == "iff" )
+ m_bitmapType = BitmapIff;
+ else if( str == "ppm" )
+ m_bitmapType = BitmapPpm;
+ else if( str == "pgm" )
+ m_bitmapType = BitmapPgm;
+ else if( str == "png" )
+ m_bitmapType = BitmapPng;
+ else if( str == "jpeg" )
+ m_bitmapType = BitmapJpeg;
+ else if( str == "tiff" )
+ m_bitmapType = BitmapTiff;
+ else if( str == "sys" )
+ m_bitmapType = BitmapSys;
+
+ m_bitmapFile = h.stringAttribute( "file_name", bitmapFileDefault );
+ m_once = h.boolAttribute( "once", onceDefault );
+
+ str = h.stringAttribute( "map_type", "planar" );
+ if( str == "planar" )
+ m_mapType = MapPlanar;
+ else if( str == "spherical" )
+ m_mapType = MapSpherical;
+ else if( str == "cylindrical" )
+ m_mapType = MapCylindrical;
+ else if( str == "toroidal" )
+ m_mapType = MapToroidal;
+
+ str = h.stringAttribute( "interpolate", "none" );
+ if( str == "none" )
+ m_interpolateType = InterpolateNone;
+ else if( str == "bilinear" )
+ m_interpolateType = InterpolateBilinear;
+ else if( str == "normalized" )
+ m_interpolateType = InterpolateNormalized;
+
+ m_useIndex = h.boolAttribute( "use_index", useIndexDefault );
+ m_bumpSize = h.doubleAttribute( "bump_size", bumpSizeDefault );
+
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMBumpMap::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "BumpMap", Base::metaObject( ),
+ createNewBumpMap );
+
+ PMBitmapTypeProperty* bp = new PMBitmapTypeProperty(
+ "bitmapType", &PMBumpMap::setBitmapType,
+ &PMBumpMap::bitmapType );
+ bp->addEnumValue( "Gif", BitmapGif );
+ bp->addEnumValue( "Tga", BitmapTga );
+ bp->addEnumValue( "Iff", BitmapIff );
+ bp->addEnumValue( "Ppm", BitmapPpm );
+ bp->addEnumValue( "Pgm", BitmapPgm );
+ bp->addEnumValue( "Png", BitmapPng );
+ bp->addEnumValue( "Jpeg", BitmapJpeg );
+ bp->addEnumValue( "Tiff", BitmapTiff );
+ bp->addEnumValue( "Sys", BitmapSys );
+ s_pMetaObject->addProperty( bp );
+
+ PMInterpolateTypeProperty* ip = new PMInterpolateTypeProperty(
+ "interpolateType", &PMBumpMap::setInterpolateType,
+ &PMBumpMap::interpolateType );
+ ip->addEnumValue( "None", InterpolateNone );
+ ip->addEnumValue( "Bilinear", InterpolateBilinear );
+ ip->addEnumValue( "Normalized", InterpolateNormalized );
+ s_pMetaObject->addProperty( ip );
+
+ PMMapTypeProperty* mp = new PMMapTypeProperty(
+ "mapType", &PMBumpMap::setMapType, &PMBumpMap::mapType );
+ mp->addEnumValue( "Planar", MapPlanar );
+ mp->addEnumValue( "Spherical", MapSpherical );
+ mp->addEnumValue( "Cylindrical", MapCylindrical );
+ mp->addEnumValue( "Toroidal", MapToroidal );
+ s_pMetaObject->addProperty( mp );
+
+ s_pMetaObject->addProperty(
+ new PMBumpMapProperty( "bitmapFile", &PMBumpMap::setBitmapFileName,
+ &PMBumpMap::bitmapFile ) );
+ s_pMetaObject->addProperty(
+ new PMBumpMapProperty( "useIndex", &PMBumpMap::enableUseIndex,
+ &PMBumpMap::isUseIndexEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMBumpMapProperty( "once", &PMBumpMap::enableOnce,
+ &PMBumpMap::isOnceEnabled ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMBumpMap::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+
+QString PMBumpMap::description( ) const
+{
+ return i18n( "bump map" );
+}
+
+void PMBumpMap::setBitmapType( PMBitmapType c )
+{
+ if( c != m_bitmapType )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMBitmapTypeID, m_bitmapType );
+ m_bitmapType = c;
+ }
+}
+
+void PMBumpMap::setBitmapFileName( const QString& c )
+{
+ if( c != m_bitmapFile )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMBitmapFileID, m_bitmapFile );
+ m_bitmapFile = c;
+ }
+}
+
+void PMBumpMap::enableUseIndex( bool c )
+{
+ if( c != m_useIndex )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMUseIndexID, m_useIndex );
+ m_useIndex = c;
+ }
+}
+
+void PMBumpMap::setMapType( PMMapType c )
+{
+ if( c != m_mapType )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMMapTypeID, m_mapType );
+ m_mapType = c;
+ }
+}
+
+void PMBumpMap::setInterpolateType( PMInterpolateType c )
+{
+ if( c != m_interpolateType )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMInterpolateID, m_interpolateType );
+ m_interpolateType = c;
+ }
+}
+
+void PMBumpMap::enableOnce( bool c )
+{
+ if( c != m_once )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMOnceID, m_once );
+ m_once = c;
+ }
+}
+
+void PMBumpMap::setBumpSize( double c )
+{
+ if( c != m_bumpSize )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMBumpSizeID, m_bumpSize );
+ m_bumpSize = c;
+ }
+}
+
+PMDialogEditBase* PMBumpMap::editWidget( QWidget* parent ) const
+{
+ return new PMBumpMapEdit( parent );
+}
+
+void PMBumpMap::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMBitmapTypeID:
+ setBitmapType( ( PMBitmapType )data->intData( ) );
+ break;
+ case PMBitmapFileID:
+ setBitmapFileName( data->stringData( ) );
+ break;
+ case PMOnceID:
+ enableOnce( data->boolData( ) );
+ break;
+ case PMMapTypeID:
+ setMapType( ( PMMapType )data->intData( ) );
+ break;
+ case PMInterpolateID:
+ setInterpolateType( ( PMInterpolateType )data->intData( ) );
+ break;
+ case PMUseIndexID:
+ enableUseIndex( data->boolData( ) );
+ break;
+ case PMBumpSizeID:
+ setBumpSize( data->doubleData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMBumpMap::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmbumpmap.h b/kpovmodeler/pmbumpmap.h
new file mode 100644
index 00000000..69bf53a3
--- /dev/null
+++ b/kpovmodeler/pmbumpmap.h
@@ -0,0 +1,172 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Passos Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMBUMPMAP_H
+#define PMBUMPMAP_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmnamedobject.h"
+#include "pmpalettevalue.h"
+
+/**
+ * Class for povray bumpmaps.
+ */
+
+class PMBumpMap : public PMNamedObject
+{
+ typedef PMNamedObject Base;
+public:
+ /**
+ * The bitmap type
+ */
+ enum PMBitmapType { BitmapGif, BitmapTga, BitmapIff, BitmapPpm,
+ BitmapPgm, BitmapPng, BitmapJpeg, BitmapTiff,
+ BitmapSys };
+ /**
+ * The interpolate method
+ */
+ enum PMInterpolateType { InterpolateNone, InterpolateBilinear,
+ InterpolateNormalized };
+ /**
+ * The mapping method
+ */
+ enum PMMapType { MapPlanar, MapSpherical, MapCylindrical,
+ MapToroidal };
+
+
+ /**
+ * Creates a PMBumpMap
+ */
+ PMBumpMap( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMBumpMap( const PMBumpMap& m );
+ /**
+ * deletes the PMBumpMap
+ */
+ virtual ~PMBumpMap( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMBumpMap( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmbumpmap" ); }
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMBumpMapEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+
+ /**
+ * Gets the bitmap type
+ */
+ PMBitmapType bitmapType( ) const { return m_bitmapType; }
+ /**
+ * Gets the bitmap file name
+ */
+ QString bitmapFile( ) const { return m_bitmapFile; }
+ /**
+ * Returns true if use_index is enabled
+ */
+ bool isUseIndexEnabled( ) const { return m_useIndex; }
+ /**
+ * Returns the bump size
+ */
+ double bumpSize( ) const { return m_bumpSize; }
+ /**
+ * Returns true if once is enabled
+ */
+ bool isOnceEnabled( ) const { return m_once; }
+ /**
+ * Gets the bitmap file type
+ */
+ PMMapType mapType( ) const { return m_mapType; }
+ /**
+ * Gets the interpolate method type
+ */
+ PMInterpolateType interpolateType( ) const { return m_interpolateType; }
+
+
+ /**
+ * Sets the bumpmap type
+ */
+ void setBitmapType( PMBitmapType c );
+ /**
+ * Sets the bitmap file name*/
+ void setBitmapFileName( const QString& c );
+ /**
+ * Sets if use_index is enabled
+ */
+ void enableUseIndex( bool c );
+ /**
+ * Set the bump size
+ */
+ void setBumpSize( double c );
+ /**
+ * Sets if the bitmap should be mapped once
+ */
+ void enableOnce( bool c );
+ /**
+ * Sets the mapping method
+ */
+ void setMapType( const PMMapType c );
+ /**
+ * Sets the interpolating method
+ */
+ void setInterpolateType( PMInterpolateType c );
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMBumpMapMementoID { PMBitmapTypeID, PMBitmapFileID,
+ PMOnceID, PMMapTypeID, PMInterpolateID,
+ PMUseIndexID, PMBumpSizeID };
+ /**
+ * BumpMap type
+ */
+ PMBitmapType m_bitmapType;
+ QString m_bitmapFile;
+ bool m_once;
+ PMMapType m_mapType;
+ PMInterpolateType m_interpolateType;
+ bool m_useIndex;
+ double m_bumpSize;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmbumpmapedit.cpp b/kpovmodeler/pmbumpmapedit.cpp
new file mode 100644
index 00000000..d792cec2
--- /dev/null
+++ b/kpovmodeler/pmbumpmapedit.cpp
@@ -0,0 +1,319 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Passos Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmbumpmapedit.h"
+#include "pmbumpmap.h"
+#include "pmvectoredit.h"
+#include "pmlineedits.h"
+#include "pmpalettevalueedit.h"
+#include "pmvector.h"
+
+#include <qwidget.h>
+#include <qlayout.h>
+#include <qcombobox.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+#include <qpushbutton.h>
+#include <qtooltip.h>
+#include <ktabctl.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdialog.h>
+#include <kfiledialog.h>
+#include <kiconloader.h>
+
+PMBumpMapEdit::PMBumpMapEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMBumpMapEdit::createTopWidgets( )
+{
+ QLabel* lbl;
+ QHBoxLayout* hl;
+
+ Base::createTopWidgets( );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ lbl = new QLabel( i18n( "File type:" ), this );
+ m_pImageFileTypeEdit = new QComboBox( this );
+ m_pImageFileTypeEdit->insertItem( "gif" );
+ m_pImageFileTypeEdit->insertItem( "tga" );
+ m_pImageFileTypeEdit->insertItem( "iff" );
+ m_pImageFileTypeEdit->insertItem( "ppm" );
+ m_pImageFileTypeEdit->insertItem( "pgm" );
+ m_pImageFileTypeEdit->insertItem( "png" );
+ m_pImageFileTypeEdit->insertItem( "jpeg" );
+ m_pImageFileTypeEdit->insertItem( "tiff" );
+ m_pImageFileTypeEdit->insertItem( "sys" );
+ hl->addWidget( lbl );
+ hl->addWidget( m_pImageFileTypeEdit );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ lbl = new QLabel( i18n( "File name:" ), this );
+ m_pImageFileNameEdit = new QLineEdit( this );
+ m_pImageFileNameBrowse = new QPushButton( this );
+ m_pImageFileNameBrowse->setPixmap( SmallIcon( "fileopen" ) );
+ hl->addWidget( lbl );
+ hl->addWidget( m_pImageFileNameEdit );
+ hl->addWidget( m_pImageFileNameBrowse );
+ hl->addStretch( 1 );
+
+ m_pOnceEdit = new QCheckBox( i18n( "Once" ), this );
+ topLayout( )->addWidget( m_pOnceEdit );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ lbl = new QLabel( i18n( "Interpolate:" ), this );
+ m_pInterpolateTypeEdit = new QComboBox( this );
+ m_pInterpolateTypeEdit->insertItem( i18n( "None" ) );
+ m_pInterpolateTypeEdit->insertItem( i18n( "Bilinear" ) );
+ m_pInterpolateTypeEdit->insertItem( i18n( "Normalized" ) );
+ hl->addWidget( lbl );
+ hl->addWidget( m_pInterpolateTypeEdit );
+ hl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ lbl = new QLabel( i18n( "Map type:" ), this );
+ m_pMapTypeEdit = new QComboBox( this );
+ m_pMapTypeEdit->insertItem( i18n( "Planar" ) );
+ m_pMapTypeEdit->insertItem( i18n( "Spherical" ) );
+ m_pMapTypeEdit->insertItem( i18n( "Cylindrical" ) );
+ m_pMapTypeEdit->insertItem( i18n( "Toroidal" ) );
+ hl->addWidget( lbl );
+ hl->addWidget( m_pMapTypeEdit );
+ hl->addStretch( 1 );
+
+ m_pUseIndexEdit = new QCheckBox( i18n( "Use index" ), this );
+ topLayout( )->addWidget( m_pUseIndexEdit );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ lbl = new QLabel( i18n( "Bump size:" ), this );
+ m_pBumpSizeEdit = new PMFloatEdit( this );
+ hl->addWidget( lbl );
+ hl->addWidget( m_pBumpSizeEdit );
+ hl->addStretch( 1 );
+
+ connect( m_pImageFileTypeEdit, SIGNAL( activated( int ) ), SLOT( slotImageFileTypeChanged( int ) ) );
+ connect( m_pMapTypeEdit, SIGNAL( activated( int ) ), SLOT( slotMapTypeChanged( int ) ) );
+ connect( m_pInterpolateTypeEdit, SIGNAL( activated( int ) ), SLOT( slotInterpolateTypeChanged( int ) ) );
+ connect( m_pImageFileNameBrowse, SIGNAL( clicked( ) ), SLOT( slotImageFileBrowseClicked( ) ) );
+ connect( m_pImageFileNameEdit, SIGNAL( textChanged( const QString& ) ), SLOT( slotImageFileNameChanged( const QString& ) ) );
+ connect( m_pOnceEdit, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pUseIndexEdit, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pBumpSizeEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMBumpMapEdit::displayObject( PMObject* o )
+{
+ bool readOnly;
+
+ if( o->isA( "BumpMap" ) )
+ {
+ m_pDisplayedObject = ( PMBumpMap* ) o;
+ readOnly = m_pDisplayedObject->isReadOnly( );
+
+ switch( m_pDisplayedObject->bitmapType( ) )
+ {
+ case PMBumpMap::BitmapGif:
+ m_pImageFileTypeEdit->setCurrentItem( 0 );
+ break;
+ case PMBumpMap::BitmapTga:
+ m_pImageFileTypeEdit->setCurrentItem( 1 );
+ break;
+ case PMBumpMap::BitmapIff:
+ m_pImageFileTypeEdit->setCurrentItem( 2 );
+ break;
+ case PMBumpMap::BitmapPpm:
+ m_pImageFileTypeEdit->setCurrentItem( 3 );
+ break;
+ case PMBumpMap::BitmapPgm:
+ m_pImageFileTypeEdit->setCurrentItem( 4 );
+ break;
+ case PMBumpMap::BitmapPng:
+ m_pImageFileTypeEdit->setCurrentItem( 5 );
+ break;
+ case PMBumpMap::BitmapJpeg:
+ m_pImageFileTypeEdit->setCurrentItem( 6 );
+ break;
+ case PMBumpMap::BitmapTiff:
+ m_pImageFileTypeEdit->setCurrentItem( 7 );
+ break;
+ case PMBumpMap::BitmapSys:
+ m_pImageFileTypeEdit->setCurrentItem( 8 );
+ break;
+ }
+ m_pImageFileTypeEdit->setEnabled( !readOnly );
+
+ switch( m_pDisplayedObject->interpolateType( ) )
+ {
+ case PMBumpMap::InterpolateNone:
+ m_pInterpolateTypeEdit->setCurrentItem( 0 );
+ break;
+ case PMBumpMap::InterpolateBilinear:
+ m_pInterpolateTypeEdit->setCurrentItem( 1);
+ break;
+ case PMBumpMap::InterpolateNormalized:
+ m_pInterpolateTypeEdit->setCurrentItem( 2 );
+ break;
+ }
+ m_pInterpolateTypeEdit->setEnabled( !readOnly );
+
+ switch( m_pDisplayedObject->mapType( ) )
+ {
+ case PMBumpMap::MapPlanar:
+ m_pMapTypeEdit->setCurrentItem( 0 );
+ break;
+ case PMBumpMap::MapSpherical:
+ m_pMapTypeEdit->setCurrentItem( 1 );
+ break;
+ case PMBumpMap::MapCylindrical:
+ m_pMapTypeEdit->setCurrentItem( 2 );
+ break;
+ case PMBumpMap::MapToroidal:
+ m_pMapTypeEdit->setCurrentItem( 3 );
+ break;
+ }
+ m_pMapTypeEdit->setEnabled( !readOnly );
+
+ m_pImageFileNameEdit->setText( m_pDisplayedObject->bitmapFile( ) );
+ m_pImageFileNameEdit->setEnabled( !readOnly );
+ m_pOnceEdit->setChecked( m_pDisplayedObject->isOnceEnabled( ) );
+ m_pOnceEdit->setEnabled( !readOnly );
+ m_pUseIndexEdit->setChecked( m_pDisplayedObject->isUseIndexEnabled( ) );
+ m_pUseIndexEdit->setEnabled( !readOnly );
+ m_pBumpSizeEdit->setValue( m_pDisplayedObject->bumpSize( ) );
+ m_pBumpSizeEdit->setReadOnly( readOnly );
+
+ Base::displayObject( o );
+ }
+
+}
+
+void PMBumpMapEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ switch( m_pImageFileTypeEdit->currentItem( ) )
+ {
+ case 0:
+ m_pDisplayedObject->setBitmapType( PMBumpMap::BitmapGif );
+ break;
+ case 1:
+ m_pDisplayedObject->setBitmapType( PMBumpMap::BitmapTga );
+ break;
+ case 2:
+ m_pDisplayedObject->setBitmapType( PMBumpMap::BitmapIff );
+ break;
+ case 3:
+ m_pDisplayedObject->setBitmapType( PMBumpMap::BitmapPpm );
+ break;
+ case 4:
+ m_pDisplayedObject->setBitmapType( PMBumpMap::BitmapPgm );
+ break;
+ case 5:
+ m_pDisplayedObject->setBitmapType( PMBumpMap::BitmapPng );
+ break;
+ case 6:
+ m_pDisplayedObject->setBitmapType( PMBumpMap::BitmapJpeg );
+ break;
+ case 7:
+ m_pDisplayedObject->setBitmapType( PMBumpMap::BitmapTiff );
+ break;
+ case 8:
+ m_pDisplayedObject->setBitmapType( PMBumpMap::BitmapSys );
+ break;
+ }
+
+ switch( m_pInterpolateTypeEdit->currentItem( ) )
+ {
+ case 0:
+ m_pDisplayedObject->setInterpolateType( PMBumpMap::InterpolateNone );
+ break;
+ case 1:
+ m_pDisplayedObject->setInterpolateType( PMBumpMap::InterpolateBilinear );
+ break;
+ case 2:
+ m_pDisplayedObject->setInterpolateType( PMBumpMap::InterpolateNormalized );
+ break;
+ }
+
+ switch( m_pMapTypeEdit->currentItem( ) )
+ {
+ case 0:
+ m_pDisplayedObject->setMapType( PMBumpMap::MapPlanar );
+ break;
+ case 1:
+ m_pDisplayedObject->setMapType( PMBumpMap::MapSpherical );
+ break;
+ case 2:
+ m_pDisplayedObject->setMapType( PMBumpMap::MapCylindrical );
+ break;
+ case 3:
+ m_pDisplayedObject->setMapType( PMBumpMap::MapToroidal );
+ break;
+ }
+
+ m_pDisplayedObject->setBitmapFileName( m_pImageFileNameEdit->text( ) );
+ m_pDisplayedObject->enableOnce( m_pOnceEdit->isChecked( ) );
+ m_pDisplayedObject->enableUseIndex( m_pUseIndexEdit->isChecked( ) );
+ m_pDisplayedObject->setBumpSize( m_pBumpSizeEdit->value( ) );
+ }
+}
+
+bool PMBumpMapEdit::isDataValid( )
+{
+ if( !m_pBumpSizeEdit->isDataValid( ) ) return false;
+
+ return Base::isDataValid( );
+}
+
+void PMBumpMapEdit::slotInterpolateTypeChanged( const int /*a*/ )
+{
+ emit dataChanged( );
+}
+
+void PMBumpMapEdit::slotImageFileTypeChanged( const int /*a*/ )
+{
+ emit dataChanged( );
+}
+
+void PMBumpMapEdit::slotMapTypeChanged( const int /*a*/ )
+{
+ emit dataChanged( );
+}
+
+void PMBumpMapEdit::slotImageFileNameChanged( const QString& /*a*/ )
+{
+ emit dataChanged( );
+}
+
+void PMBumpMapEdit::slotImageFileBrowseClicked( )
+{
+ QString str = KFileDialog::getOpenFileName( QString::null, QString::null );
+
+ if( !str.isEmpty() )
+ {
+ m_pImageFileNameEdit->setText( str );
+ emit dataChanged( );
+ }
+}
+
+#include "pmbumpmapedit.moc"
diff --git a/kpovmodeler/pmbumpmapedit.h b/kpovmodeler/pmbumpmapedit.h
new file mode 100644
index 00000000..cceb2b84
--- /dev/null
+++ b/kpovmodeler/pmbumpmapedit.h
@@ -0,0 +1,86 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Passos Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMBUMPMAPEDIT_H
+#define PMBUMPMAPEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmpalettevalueedit.h"
+#include "pmdialogeditbase.h"
+
+class PMBumpMap;
+class PMPaletteValue;
+class PMVectorEdit;
+class QComboBox;
+class PMFloatEdit;
+class PMIntEdit;
+class QLabel;
+class QCheckBox;
+class QWidget;
+class QLineEdit;
+class QPushButton;
+
+/**
+ * Dialog edit class for @ref PMBumpMap.
+ */
+class PMBumpMapEdit : public PMDialogEditBase
+{
+ Q_OBJECT
+ typedef PMDialogEditBase Base;
+public:
+ /**
+ * Creates a PMBumpMapEdit with parent and name
+ */
+ PMBumpMapEdit( QWidget* parent, const char* name = 0 );
+ /** */
+ virtual void displayObject( PMObject* o );
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+private slots:
+ /** */
+ void slotImageFileTypeChanged( int a );
+ /** */
+ void slotMapTypeChanged( int a );
+ /** */
+ void slotInterpolateTypeChanged( int a );
+ /** */
+ void slotImageFileNameChanged( const QString& a );
+ /** */
+ void slotImageFileBrowseClicked( );
+private:
+ PMBumpMap* m_pDisplayedObject;
+ QComboBox* m_pImageFileTypeEdit;
+ QLineEdit* m_pImageFileNameEdit;
+ QPushButton* m_pImageFileNameBrowse;
+ QCheckBox* m_pOnceEdit;
+ QComboBox* m_pMapTypeEdit;
+ QComboBox* m_pInterpolateTypeEdit;
+ QCheckBox* m_pUseIndexEdit;
+ PMFloatEdit* m_pBumpSizeEdit;
+};
+
+#endif
diff --git a/kpovmodeler/pmcamera.cpp b/kpovmodeler/pmcamera.cpp
new file mode 100644
index 00000000..b224f340
--- /dev/null
+++ b/kpovmodeler/pmcamera.cpp
@@ -0,0 +1,769 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmcamera.h"
+
+#include "pmxmlhelper.h"
+#include "pmcameraedit.h"
+#include "pmmemento.h"
+#include "pmviewstructure.h"
+#include "pm3dcontrolpoint.h"
+#include "pmvectorcontrolpoint.h"
+#include "pmenumproperty.h"
+
+#include <klocale.h>
+
+PMDefinePropertyClass( PMCamera, PMCameraProperty );
+PMDefineEnumPropertyClass( PMCamera, PMCamera::CameraType,
+ PMCameraTypeProperty );
+
+PMViewStructure* PMCamera::s_pDefaultViewStructure = 0;
+PMMetaObject* PMCamera::s_pMetaObject = 0;
+PMObject* createNewCamera( PMPart* part )
+{
+ return new PMCamera( part );
+}
+
+const PMVector locationDefault = PMVector( 0.0, 0.0, 0.0 );
+const PMVector lookAtDefault = PMVector( 0.0, 0.0, 1.0 );
+const PMVector directionDefault = PMVector( 0.0, 0.0, 1.0 );
+const PMVector upDefault = PMVector( 0.0, 1.0, 0.0 );
+const PMVector rightDefault = PMVector( 4.0/3.0, 0.0, 0.0 );
+const PMVector skyDefault = PMVector( 0.0, 1.0, 0.0 );
+//const double aspectDefault = 1.0;
+const bool angleEnabledDefault = false;
+const double angleDefault = 90.0;
+const PMCamera::CameraType cameraTypeDefault = PMCamera::Perspective;
+const int cylinderTypeDefault = 1;
+const bool focalBlurDefault = false;
+const double apertureDefault = 0.4;
+const int blurSamplesDefault = 10;
+const PMVector focalPointDefault = PMVector( 0.0, 0.0, 0.0 );
+const double confidenceDefault = 0.9;
+const double varianceDefault = 0.008;
+const bool c_defaultExport = true;
+
+PMCamera::PMCamera( PMPart* part )
+ : Base( part )
+{
+ m_location = locationDefault;
+ m_lookAt = lookAtDefault;
+ m_direction = directionDefault;
+
+ m_up = upDefault;
+ m_right = rightDefault;
+
+ m_sky = skyDefault;
+ m_angle = angleDefault;
+ m_angleEnabled = angleEnabledDefault;
+
+ m_cameraType = cameraTypeDefault;
+ m_cylinderType = cylinderTypeDefault;
+
+ m_focalBlurEnabled = focalBlurDefault;
+ m_aperture = apertureDefault;
+ m_blurSamples = blurSamplesDefault;
+ m_focalPoint = focalPointDefault;
+ m_confidence = confidenceDefault;
+ m_variance = varianceDefault;
+ m_export = c_defaultExport;
+}
+
+PMCamera::PMCamera( const PMCamera& c )
+ : Base( c )
+{
+ m_location = c.m_location;
+ m_lookAt = c.m_lookAt;
+ m_direction = c.m_direction;
+
+ m_up = c.m_up;
+ m_right = c.m_right;
+
+ m_sky = c.m_sky;
+ m_angle = c.m_angle;
+ m_angleEnabled = c.m_angleEnabled;
+
+ m_cameraType = c.m_cameraType;
+ m_cylinderType = c.m_cylinderType;
+
+ m_focalBlurEnabled = c.m_focalBlurEnabled;
+ m_aperture = c.m_aperture;
+ m_blurSamples = c.m_blurSamples;
+ m_focalPoint = c.m_focalPoint;
+ m_confidence = c.m_confidence;
+ m_variance = c.m_variance;
+ m_export = c.m_export;
+}
+
+PMCamera::~PMCamera( )
+{
+}
+
+QString PMCamera::description( ) const
+{
+ return i18n( "camera" );
+}
+
+void PMCamera::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "camera_type", cameraTypeToString( m_cameraType ) );
+ e.setAttribute( "cylinder_type", m_cylinderType );
+ e.setAttribute( "location", m_location.serializeXML( ) );
+ e.setAttribute( "sky", m_sky.serializeXML( ) );
+ e.setAttribute( "direction", m_direction.serializeXML( ) );
+ e.setAttribute( "right", m_right.serializeXML( ) );
+ e.setAttribute( "up", m_up.serializeXML( ) );
+ e.setAttribute( "look_at", m_lookAt.serializeXML( ) );
+ e.setAttribute( "angle_enabled", m_angleEnabled );
+ e.setAttribute( "angle", m_angle );
+ e.setAttribute( "focal_blur", m_focalBlurEnabled );
+ e.setAttribute( "aperture", m_aperture );
+ e.setAttribute( "blur_samples", m_blurSamples );
+ e.setAttribute( "focal_point", m_focalPoint.serializeXML( ) );
+ e.setAttribute( "confidence", m_confidence );
+ e.setAttribute( "variance", m_variance );
+ e.setAttribute( "export", m_export );
+
+ Base::serialize( e, doc );
+}
+
+void PMCamera::readAttributes( const PMXMLHelper& h )
+{
+ m_cameraType = stringToCameraType( h.stringAttribute( "camera_type",
+ "perspective" ) );
+ m_cylinderType = h.intAttribute( "cylinder_type", cylinderTypeDefault );
+ m_location = h.vectorAttribute( "location", locationDefault );
+ m_sky = h.vectorAttribute( "sky", skyDefault );
+ m_direction = h.vectorAttribute( "direction", directionDefault );
+ m_right = h.vectorAttribute( "right", rightDefault );
+ m_up = h.vectorAttribute( "up", upDefault );
+ m_lookAt = h.vectorAttribute( "look_at", lookAtDefault );
+ m_angleEnabled = h.boolAttribute( "angle_enabled", angleEnabledDefault );
+ m_angle = h.doubleAttribute( "angle", angleDefault );
+ m_focalBlurEnabled = h.boolAttribute( "focal_blur", focalBlurDefault );
+ m_aperture = h.doubleAttribute( "aperture", apertureDefault );
+ m_blurSamples = h.intAttribute( "blur_samples", blurSamplesDefault );
+ m_focalPoint = h.vectorAttribute( "focal_point", focalPointDefault );
+ m_confidence = h.doubleAttribute( "confidence", confidenceDefault );
+ m_variance = h.doubleAttribute( "variance", varianceDefault );
+ m_export = h.boolAttribute( "export", c_defaultExport );
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMCamera::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Camera", Base::metaObject( ),
+ createNewCamera );
+ s_pMetaObject->addProperty(
+ new PMCameraProperty( "location", &PMCamera::setLocation,
+ &PMCamera::location ) );
+ s_pMetaObject->addProperty(
+ new PMCameraProperty( "lookAt", &PMCamera::setLookAt,
+ &PMCamera::lookAt ) );
+ s_pMetaObject->addProperty(
+ new PMCameraProperty( "up", &PMCamera::setUp,
+ &PMCamera::up ) );
+ s_pMetaObject->addProperty(
+ new PMCameraProperty( "right", &PMCamera::setRight,
+ &PMCamera::right ) );
+ s_pMetaObject->addProperty(
+ new PMCameraProperty( "direction", &PMCamera::setDirection,
+ &PMCamera::direction ) );
+ s_pMetaObject->addProperty(
+ new PMCameraProperty( "sky", &PMCamera::setSky,
+ &PMCamera::sky ) );
+ s_pMetaObject->addProperty(
+ new PMCameraProperty( "aspect", 0, &PMCamera::aspect ) );
+
+ s_pMetaObject->addProperty(
+ new PMCameraProperty( "angleEnabled", &PMCamera::enableAngle,
+ &PMCamera::isAngleEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMCameraProperty( "angle", &PMCamera::setAngle,
+ &PMCamera::angle ) );
+
+ PMCameraTypeProperty* p = new PMCameraTypeProperty(
+ "cameraType", &PMCamera::setCameraType,
+ &PMCamera::cameraType );
+ p->addEnumValue( "Perspective", Perspective );
+ p->addEnumValue( "Orthographic", Orthographic );
+ p->addEnumValue( "FishEye", FishEye );
+ p->addEnumValue( "UltraWideAngle", UltraWideAngle );
+ p->addEnumValue( "Omnimax", Omnimax );
+ p->addEnumValue( "Panoramic", Panoramic );
+ p->addEnumValue( "Cylinder", Cylinder );
+ s_pMetaObject->addProperty( p );
+
+ s_pMetaObject->addProperty(
+ new PMCameraProperty( "cylinderType", &PMCamera::setCylinderType,
+ &PMCamera::cylinderType ) );
+ s_pMetaObject->addProperty(
+ new PMCameraProperty( "focalBlurEnabled", &PMCamera::enableFocalBlur,
+ &PMCamera::isFocalBlurEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMCameraProperty( "aperture", &PMCamera::setAperture,
+ &PMCamera::aperture ) );
+ s_pMetaObject->addProperty(
+ new PMCameraProperty( "blurSamples", &PMCamera::setBlurSamples,
+ &PMCamera::blurSamples ) );
+ s_pMetaObject->addProperty(
+ new PMCameraProperty( "focalPoint", &PMCamera::setFocalPoint,
+ &PMCamera::focalPoint ) );
+ s_pMetaObject->addProperty(
+ new PMCameraProperty( "confidence", &PMCamera::setConfidence,
+ &PMCamera::confidence ) );
+ s_pMetaObject->addProperty(
+ new PMCameraProperty( "variance", &PMCamera::setVariance,
+ &PMCamera::variance ) );
+ s_pMetaObject->addProperty(
+ new PMCameraProperty( "export", &PMCamera::setExportPovray,
+ &PMCamera::exportPovray ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMCamera::setLocation( const PMVector& p )
+{
+ if( p != m_location )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMLocationID, m_location );
+ m_location = p;
+ m_location.resize( 3 );
+ setViewStructureChanged( );
+ }
+}
+
+void PMCamera::setLookAt( const PMVector& p )
+{
+ if( p != m_lookAt )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMLookAtID, m_lookAt );
+ m_lookAt = p;
+ m_lookAt.resize( 3 );
+ setViewStructureChanged( );
+ }
+}
+
+void PMCamera::setUp( const PMVector& v )
+{
+ if( v != m_up )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMUpID, m_up );
+ m_up = v;
+ m_up.resize( 3 );
+ setViewStructureChanged( );
+ }
+}
+
+void PMCamera::setRight( const PMVector& v )
+{
+ if( v != m_right )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMRightID, m_right );
+ m_right = v;
+ m_right.resize( 3 );
+ setViewStructureChanged( );
+ }
+}
+
+void PMCamera::setDirection( const PMVector& v )
+{
+ if( v != m_direction )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMDirectionID, m_direction );
+ m_direction = v;
+ m_direction.resize( 3 );
+ setViewStructureChanged( );
+ }
+}
+
+void PMCamera::setSky( const PMVector& v )
+{
+ if( v != m_sky )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSkyID, m_sky );
+ m_sky = v;
+ m_sky.resize( 3 );
+ setViewStructureChanged( );
+ }
+}
+
+double PMCamera::aspect( ) const
+{
+ double d = m_up.abs( );
+ if( approxZero( d ) )
+ return 1.0;
+ return m_right.abs( ) / d;
+}
+
+void PMCamera::enableAngle( bool yes )
+{
+ if( yes != m_angleEnabled )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAngleEnabledID, m_angleEnabled );
+ m_angleEnabled = yes;
+ setViewStructureChanged( );
+ }
+}
+
+void PMCamera::setAngle( double a )
+{
+ if( a != m_angle )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAngleID, m_angle );
+ m_angle = a;
+ setViewStructureChanged( );
+ }
+}
+
+void PMCamera::setCameraType( PMCamera::CameraType t )
+{
+ if( t != m_cameraType )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMCameraTypeID, m_cameraType );
+ m_cameraType = t;
+ setViewStructureChanged( );
+ }
+}
+
+void PMCamera::setCylinderType( int t )
+{
+ if( ( t < 1 ) || ( t > 4 ) )
+ kdError( PMArea ) << "Invalid type in PMCylinder::setCylinderType\n";
+ else if( t != m_cylinderType )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMCylinderTypeID, m_cylinderType );
+ m_cylinderType = t;
+ setViewStructureChanged( );
+ }
+}
+
+void PMCamera::enableFocalBlur( bool yes )
+{
+ if( yes != m_focalBlurEnabled )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFocalBlurID, m_focalBlurEnabled );
+ m_focalBlurEnabled = yes;
+ }
+}
+
+void PMCamera::setAperture( double a )
+{
+ if( a < 0 )
+ kdError( PMArea ) << "Aperture < 0 in PMCylinder::setAperture\n";
+ else if( a != m_aperture )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMApertureID, m_aperture );
+ m_aperture = a;
+ }
+}
+
+void PMCamera::setBlurSamples( int s )
+{
+ if( s < 0 )
+ kdError( PMArea ) << "Samples < 0 in PMCylinder::setBlutSamples\n";
+ else if( s != m_blurSamples )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMBlurSamplesID, m_blurSamples );
+ m_blurSamples = s;
+ }
+}
+
+void PMCamera::setFocalPoint( const PMVector& v )
+{
+ if( v != m_focalPoint )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFocalPointID, m_focalPoint );
+ m_focalPoint = v;
+ }
+}
+
+void PMCamera::setConfidence( double c )
+{
+ if( ( c < 0.0 ) || ( c > 1.0 ) )
+ kdError( PMArea ) << "Confidence not in [0.0 1.0] in PMCylinder::setConfidence\n";
+ else if( c != m_confidence )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMConfidenceID, m_confidence );
+ m_confidence = c;
+ }
+}
+
+void PMCamera::setVariance( double v )
+{
+ if( v < 0 )
+ kdError( PMArea ) << "Variance < 0 in PMCylinder::setVariance\n";
+ else if( v != m_variance )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMVarianceID, m_variance );
+ m_variance = v;
+ }
+}
+
+void PMCamera::setExportPovray( bool ex )
+{
+ if( m_export != ex )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMExportID, m_export );
+ m_export = ex;
+ }
+}
+
+PMDialogEditBase* PMCamera::editWidget( QWidget* parent ) const
+{
+ return new PMCameraEdit( parent );
+}
+
+void PMCamera::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMLocationID:
+ setLocation( data->vectorData( ) );
+ break;
+ case PMLookAtID:
+ setLookAt( data->vectorData( ) );
+ break;
+ case PMUpID:
+ setUp( data->vectorData( ) );
+ break;
+ case PMRightID:
+ setRight( data->vectorData( ) );
+ break;
+ case PMDirectionID:
+ setDirection( data->vectorData( ) );
+ break;
+ case PMSkyID:
+ setSky( data->vectorData( ) );
+ break;
+ case PMAngleEnabledID:
+ enableAngle( data->boolData( ) );
+ break;
+ case PMAngleID:
+ setAngle( data->doubleData( ) );
+ break;
+ case PMCameraTypeID:
+ setCameraType( ( CameraType ) data->intData( ) );
+ break;
+ case PMCylinderTypeID:
+ setCylinderType( data->intData( ) );
+ break;
+ case PMFocalBlurID:
+ enableFocalBlur( data->boolData( ) );
+ break;
+ case PMBlurSamplesID:
+ setBlurSamples( data->intData( ) );
+ break;
+ case PMFocalPointID:
+ setFocalPoint( data->vectorData( ) );
+ break;
+ case PMConfidenceID:
+ setConfidence( data->doubleData( ) );
+ break;
+ case PMVarianceID:
+ setVariance( data->doubleData( ) );
+ break;
+ case PMApertureID:
+ setAperture( data->doubleData( ) );
+ break;
+ case PMExportID:
+ setExportPovray( data->boolData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMCamera::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
+void PMCamera::createViewStructure( )
+{
+ PMVector newUp, newRight, newDirection, tmp;
+ double upLen, rightLen;
+
+ if( !m_pViewStructure )
+ {
+ m_pViewStructure = new PMViewStructure( defaultViewStructure( ) );
+ m_pViewStructure->points( ).detach( );
+ }
+
+ PMPointArray& points = m_pViewStructure->points( );
+ calculateLookAtAngle( newRight, newUp, newDirection );
+
+ points[0] = m_lookAt;
+ points[1] = m_location;
+
+ upLen = newUp.abs( );
+ rightLen = newRight.abs( );
+ if( rightLen > upLen )
+ {
+ newUp /= rightLen;
+ newRight /= rightLen;
+ newDirection /= rightLen;
+ }
+ else
+ {
+ newUp /= upLen;
+ newRight /= upLen;
+ newDirection /= upLen;
+ }
+
+ newRight /= 2.0;
+ newUp /= 2.0;
+ tmp = m_location + newDirection;
+ points[2] = tmp - newRight + newUp;
+ points[3] = tmp - newRight - newUp;
+ points[4] = tmp + newRight - newUp;
+ points[5] = tmp + newRight + newUp;
+// points[6] = m_location + m_sky;
+}
+
+PMViewStructure* PMCamera::defaultViewStructure( ) const
+{
+ if( !s_pDefaultViewStructure )
+ {
+ s_pDefaultViewStructure = new PMViewStructure( 6, 9 );
+ PMLineArray& lines = s_pDefaultViewStructure->lines( );
+
+ lines[0] = PMLine( 0, 1 );
+ lines[1] = PMLine( 1, 2 );
+ lines[2] = PMLine( 1, 3 );
+ lines[3] = PMLine( 1, 4 );
+ lines[4] = PMLine( 1, 5 );
+ lines[5] = PMLine( 2, 3 );
+ lines[6] = PMLine( 2, 5 );
+ lines[7] = PMLine( 3, 4 );
+ lines[8] = PMLine( 4, 5 );
+// lines[9] = PMLine( 1, 6 );
+ }
+ return s_pDefaultViewStructure;
+}
+
+void PMCamera::controlPoints( PMControlPointList& list )
+{
+ PMControlPoint* p;
+ p = new PM3DControlPoint( m_location, PMLocationID, i18n( "Location" ) );
+ list.append( p );
+ list.append( new PM3DControlPoint( m_lookAt, PMLookAtID, i18n( "Look at" ) ) );
+}
+
+void PMCamera::controlPointsChanged( PMControlPointList& list )
+{
+ PMControlPoint* p;
+
+ for( p = list.first( ); p; p = list.next( ) )
+ {
+ if( p->changed( ) )
+ {
+ switch( p->id( ) )
+ {
+ case PMLocationID:
+ setLocation( ( ( PM3DControlPoint* ) p )->point( ) );
+ break;
+ case PMLookAtID:
+ setLookAt( ( ( PM3DControlPoint* ) p )->point( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMCamera::controlPointsChanged\n";
+ break;
+ }
+ }
+ }
+}
+
+void PMCamera::calculateLookAtAngle( PMVector& right, PMVector& up, PMVector& direction )
+{
+ PMVector tmpVector;
+ double directionLen, upLen, rightLen, handedness, angle;
+
+ angle = m_angle;
+ if( m_cameraType == Perspective )
+ {
+ if( angle < 0.0 )
+ angle = angleDefault;
+ if( angle >= 180.0 )
+ angle = angleDefault;
+ }
+ else
+ angle = 90.0;
+
+ directionLen = m_direction.abs( );
+ upLen = m_up.abs( );
+ rightLen = m_right.abs( );
+
+ // for safety: if vector is null vector, use the default one
+ if( approxZero( directionLen ) )
+ {
+ direction = directionDefault;
+ directionLen = direction.abs( );
+ }
+ else
+ direction = m_direction;
+
+ if( approxZero( upLen ) )
+ {
+ up = upDefault;
+ upLen = up.abs( );
+ }
+ else
+ up = m_up;
+
+ if( approxZero( rightLen ) )
+ {
+ right = rightDefault;
+ rightLen = right.abs( );
+ }
+ else
+ right = m_right;
+
+ if( m_angleEnabled )
+ {
+ // calculate angle
+ direction /= directionLen;
+ directionLen = 0.5 * rightLen / tan( angle * M_PI / 360.0 );
+ direction *= directionLen;
+ }
+
+ // calculate handedness
+ tmpVector = PMVector::cross( up, direction );
+ handedness = PMVector::dot( tmpVector, right );
+
+ direction = m_lookAt - m_location;
+ if( approxZero( direction.abs( ) ) )
+ {
+ // Camera location and look_at point are the same
+ direction = directionDefault;
+ }
+
+ // normalize new direction
+ direction /= direction.abs( );
+
+ tmpVector = right;
+ right = PMVector::cross( m_sky, direction );
+
+ if( approxZero( right.abs( ) ) )
+ right = tmpVector;
+
+ right /= right.abs( );
+ up = PMVector::cross( direction, right );
+ direction *= directionLen;
+
+ if( handedness > 0.0 )
+ right *= rightLen;
+ else
+ right *= -rightLen;
+ up *= upLen;
+}
+
+QString PMCamera::cameraTypeToString( PMCamera::CameraType t )
+{
+ QString str( "perspective" );
+ switch( t )
+ {
+ case Perspective:
+ break;
+ case Orthographic:
+ str = "orthographic";
+ break;
+ case FishEye:
+ str = "fisheye";
+ break;
+ case UltraWideAngle:
+ str = "ultra_wide_angle";
+ break;
+ case Omnimax:
+ str = "omnimax";
+ break;
+ case Panoramic:
+ str = "panoramic";
+ break;
+ case Cylinder:
+ str = "cylinder";
+ break;
+ }
+ return str;
+}
+
+PMCamera::CameraType PMCamera::stringToCameraType( const QString& str )
+{
+ CameraType t = Perspective;
+
+ if( str == "perspective" )
+ t = Perspective;
+ else if( str == "orthographic" )
+ t = Orthographic;
+ else if( str == "fisheye" )
+ t = FishEye;
+ else if( str == "ultra_wide_angle" )
+ t = UltraWideAngle;
+ else if( str == "omnimax" )
+ t = Omnimax;
+ else if( str == "panoramic" )
+ t = Panoramic;
+ else if( str == "cylinder" )
+ t = Cylinder;
+ else
+ kdDebug( PMArea ) << "Unknown camera type\n";
+
+ return t;
+}
+
+void PMCamera::cleanUp( ) const
+{
+ if( s_pDefaultViewStructure )
+ {
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ }
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+
+ Base::cleanUp( );
+}
diff --git a/kpovmodeler/pmcamera.h b/kpovmodeler/pmcamera.h
new file mode 100644
index 00000000..9f09ee58
--- /dev/null
+++ b/kpovmodeler/pmcamera.h
@@ -0,0 +1,292 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMCAMERA_H
+#define PMCAMERA_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmnamedobject.h"
+#include "pmvector.h"
+
+class PMViewStructure;
+
+/**
+ * Class for povray cameras
+ */
+
+class PMCamera : public PMNamedObject
+{
+ typedef PMNamedObject Base;
+public:
+ /**
+ * Type of the camera
+ */
+ enum CameraType { Perspective, Orthographic, FishEye, UltraWideAngle,
+ Omnimax, Panoramic, Cylinder };
+ /**
+ * Creates a default povray camera
+ */
+ PMCamera( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMCamera( const PMCamera& c );
+ /**
+ * deletes the camera
+ */
+ virtual ~PMCamera( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMCamera( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMCameraEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmcamera" ); }
+
+ /**
+ * Returns the location
+ */
+ PMVector location( ) const { return m_location; }
+ /**
+ * Sets the location
+ */
+ void setLocation( const PMVector& p );
+
+ /**
+ * Returns the look_at point
+ */
+ PMVector lookAt( ) const { return m_lookAt; }
+ /**
+ * Sets the look_at point
+ */
+ void setLookAt( const PMVector& p );
+
+ /**
+ * Returns the up vector
+ */
+ PMVector up( ) const { return m_up; }
+ /**
+ * Sets the up vector
+ */
+ void setUp( const PMVector& v );
+
+ /**
+ * Returns the right vector
+ */
+ PMVector right( ) const { return m_right; }
+ /**
+ * Sets the right vector
+ */
+ void setRight( const PMVector& v );
+
+ /**
+ * Returns the direction vector
+ */
+ PMVector direction( ) const { return m_direction; }
+ /**
+ * Sets the direction vector
+ */
+ void setDirection( const PMVector& v );
+
+ /**
+ * Returns the sky vector
+ */
+ PMVector sky( ) const { return m_sky; }
+ /**
+ * Sets the sky vector
+ */
+ void setSky( const PMVector& v );
+
+ /**
+ * Returns the aspect ratio
+ */
+ double aspect( ) const;
+
+ /**
+ * Returns true if angle is enabled
+ */
+ bool isAngleEnabled( ) const { return m_angleEnabled; }
+ /**
+ * Enables/Disables the use of angle
+ */
+ void enableAngle( bool yes );
+
+ /**
+ * Returns the angle
+ */
+ double angle( ) const { return m_angle; }
+ /**
+ * Sets the angle
+ */
+ void setAngle( double a );
+
+ /**
+ * Returns the camera type
+ */
+ CameraType cameraType( ) const { return m_cameraType; }
+ /**
+ * Sets the camera type
+ */
+ void setCameraType( CameraType t );
+
+ /**
+ * Returns the cylinder type
+ */
+ int cylinderType( ) const { return m_cylinderType; }
+ /**
+ * Sets the cylinder type. Valid values are 1-4
+ */
+ void setCylinderType( int t );
+
+ /**
+ * Returns true if focal blur is enabled
+ */
+ bool isFocalBlurEnabled( ) const { return m_focalBlurEnabled; }
+ /**
+ * Enables/Disables the focal blur
+ */
+ void enableFocalBlur( bool yes );
+ /**
+ * Returns the aperture
+ */
+ double aperture( ) const { return m_aperture; }
+ /**
+ * Sets the aperture. Has to be greater or equal 0
+ */
+ void setAperture( double d );
+ /**
+ * Returns the number of blur samples
+ */
+ int blurSamples( ) const { return m_blurSamples; }
+ /**
+ * Sets the number of blur samples
+ */
+ void setBlurSamples( int s );
+ /**
+ * Returns the focal point
+ */
+ PMVector focalPoint( ) const { return m_focalPoint; }
+ /**
+ * Sets the focal point
+ */
+ void setFocalPoint( const PMVector& v );
+ /**
+ * Returns the confidence
+ */
+ double confidence( ) const { return m_confidence;}
+ /**
+ * Sets the confidence
+ */
+ void setConfidence( double c );
+ /**
+ * Returns the variance
+ */
+ double variance( ) const { return m_variance; }
+ /**
+ * Sets the variance
+ */
+ void setVariance( double v );
+
+ /**
+ * Returns the export flag
+ */
+ virtual bool exportPovray( ) const { return m_export; }
+ /**
+ * Sets the export flag
+ */
+ void setExportPovray( bool ex );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /** */
+ virtual void controlPoints( PMControlPointList& list );
+ /** */
+ virtual void controlPointsChanged( PMControlPointList& list );
+
+ /**
+ * Calculates the new right, up and direction vector with the
+ * look_at vector.
+ */
+ void calculateLookAtAngle( PMVector& right, PMVector& up, PMVector& direction );
+
+ /**
+ * Converts the camera type to a string
+ */
+ static QString cameraTypeToString( CameraType t );
+ /**
+ * Converts a string to the camera type
+ */
+ static CameraType stringToCameraType( const QString& s );
+ /** */
+ virtual void cleanUp( ) const;
+
+protected:
+ /** */
+ virtual bool isDefault( ) { return false; }
+ /** */
+ virtual void createViewStructure( );
+ /** */
+ virtual PMViewStructure* defaultViewStructure( ) const;
+
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMCameraMementoID { PMLocationID, PMLookAtID, PMDirectionID,
+ PMUpID, PMRightID, PMAngleID, PMSkyID,
+ PMCameraTypeID, PMCylinderTypeID,
+ PMFocalBlurID, PMBlurSamplesID, PMFocalPointID,
+ PMConfidenceID, PMVarianceID, PMApertureID,
+ PMAngleEnabledID, PMExportID };
+ PMVector m_location, m_lookAt, m_up, m_right, m_direction, m_sky;
+ bool m_angleEnabled;
+ double m_angle;
+ CameraType m_cameraType;
+ int m_cylinderType;
+ bool m_focalBlurEnabled;
+ double m_aperture;
+ int m_blurSamples;
+ PMVector m_focalPoint;
+ double m_confidence, m_variance;
+ bool m_export;
+
+ /**
+ * The default view structure. It can be shared between cameras
+ */
+ static PMViewStructure* s_pDefaultViewStructure;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmcameraedit.cpp b/kpovmodeler/pmcameraedit.cpp
new file mode 100644
index 00000000..676c9f8b
--- /dev/null
+++ b/kpovmodeler/pmcameraedit.cpp
@@ -0,0 +1,439 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmcameraedit.h"
+#include "pmcamera.h"
+#include "pmvectoredit.h"
+#include "pmlineedits.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcombobox.h>
+#include <qcheckbox.h>
+
+#include <klocale.h>
+#include <kmessagebox.h>
+
+
+PMCameraEdit::PMCameraEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMCameraEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QGridLayout* layout;
+ QLabel* label;
+
+ m_pCameraType = new QComboBox( false, this );
+ m_pCameraType->insertItem( i18n( "Perspective" ) );
+ m_pCameraType->insertItem( i18n( "Orthographic" ) );
+ m_pCameraType->insertItem( i18n( "Fish Eye" ) );
+ m_pCameraType->insertItem( i18n( "Ultra Wide Angle" ) );
+ m_pCameraType->insertItem( i18n( "Omnimax" ) );
+ m_pCameraType->insertItem( i18n( "Panoramic" ) );
+ m_pCameraType->insertItem( i18n( "Cylinder" ) );
+
+ m_pCylinderType = new QComboBox( false, this );
+ m_pCylinderType->insertItem( i18n( "1: Vertical, Fixed Viewpoint" ) );
+ m_pCylinderType->insertItem( i18n( "2: Horizontal, Fixed Viewpoint" ) );
+ m_pCylinderType->insertItem( i18n( "3: Vertical, Variable Viewpoint" ) );
+ m_pCylinderType->insertItem( i18n( "4: Horizontal, Variable Viewpoint" ) );
+
+ m_pLocation = new PMVectorEdit( "x", "y", "z", this );
+ m_pSky = new PMVectorEdit( "x", "y", "z", this );
+ m_pDirection = new PMVectorEdit( "x", "y", "z", this );
+ m_pRight = new PMVectorEdit( "x", "y", "z", this );
+ m_pUp = new PMVectorEdit( "x", "y", "z", this );
+ m_pLookAt = new PMVectorEdit( "x", "y", "z", this );
+ m_pAngle = new PMFloatEdit( this );
+ m_pAngle->setValidation( true, 0.0, true, 360.0 );
+
+ QHBoxLayout* hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "Camera type:" ), this ) );
+ hl->addWidget( m_pCameraType );
+ hl = new QHBoxLayout( topLayout( ) );
+ m_pCylinderTypeLabel = new QLabel( i18n( "Cylinder type:" ), this );
+ hl->addWidget( m_pCylinderTypeLabel );
+ hl->addWidget( m_pCylinderType );
+
+ layout = new QGridLayout( topLayout( ), 7, 2 );
+ layout->addWidget( new QLabel( i18n( "Location:" ), this ), 0, 0 );
+ layout->addWidget( m_pLocation, 0, 1 );
+
+ layout->addWidget( new QLabel( i18n( "Sky:" ), this ), 1, 0 );
+ layout->addWidget( m_pSky, 1, 1 );
+
+ layout->addWidget( new QLabel( i18n( "Direction:" ), this ), 2, 0 );
+ layout->addWidget( m_pDirection, 2, 1 );
+
+ layout->addWidget( new QLabel( i18n( "Right:" ), this ), 3, 0 );
+ layout->addWidget( m_pRight, 3, 1 );
+
+ layout->addWidget( new QLabel( i18n( "Up:" ), this ), 4, 0 );
+ layout->addWidget( m_pUp, 4, 1 );
+
+ layout->addWidget( new QLabel( i18n( "Look at:" ), this ), 5, 0 );
+ layout->addWidget( m_pLookAt, 5, 1 );
+
+ m_pEnableAngle = new QCheckBox( i18n( "Angle:" ), this );
+ layout->addWidget( m_pEnableAngle, 6, 0 );
+ layout->addWidget( m_pAngle, 6, 1, AlignLeft );
+
+ m_pFocalBlur = new QCheckBox( i18n( "Focal blur" ), this );
+ topLayout( )->addWidget( m_pFocalBlur );
+
+ m_pAperture = new PMFloatEdit( this );
+ m_pAperture->setValidation( true, 0, false, 0 );
+ m_focalWidgets.append( m_pAperture );
+ m_pBlurSamples = new PMIntEdit( this );
+ m_pBlurSamples->setValidation( true, 0, false, 0 );
+ m_focalWidgets.append( m_pBlurSamples );
+ m_pFocalPoint = new PMVectorEdit( "x", "y", "z", this );
+ m_focalWidgets.append( m_pFocalPoint );
+ m_pConfidence = new PMFloatEdit( this );
+ m_pConfidence->setValidation( true, 0, true, 1 );
+ m_focalWidgets.append( m_pConfidence );
+ m_pVariance = new PMFloatEdit( this );
+ m_pVariance->setValidation( true, 0, false, 0 );
+ m_focalWidgets.append( m_pVariance );
+
+ layout = new QGridLayout( topLayout( ), 5, 2 );
+ label = new QLabel( i18n( "Aperture:" ), this );
+ m_focalWidgets.append( label );
+ layout->addWidget( label, 0, 0 );
+ layout->addWidget( m_pAperture, 0, 1 );
+ label = new QLabel( i18n( "Blur samples:" ), this );
+ m_focalWidgets.append( label );
+ layout->addWidget( label, 1, 0 );
+ layout->addWidget( m_pBlurSamples, 1, 1 );
+ label = new QLabel( i18n( "Focal point:" ), this );
+ m_focalWidgets.append( label );
+ layout->addWidget( label, 2, 0 );
+ layout->addWidget( m_pFocalPoint, 2, 1 );
+ label = new QLabel( i18n( "Confidence:" ), this );
+ m_focalWidgets.append( label );
+ layout->addWidget( label, 3, 0 );
+ layout->addWidget( m_pConfidence, 3, 1 );
+ label = new QLabel( i18n( "Variance:" ), this );
+ m_focalWidgets.append( label );
+ layout->addWidget( label, 4, 0 );
+ layout->addWidget( m_pVariance, 4, 1 );
+
+ m_pExport = new QCheckBox( i18n( "Export to renderer" ), this );
+ topLayout( )->addWidget( m_pExport );
+
+ connect( m_pLocation, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pDirection, SIGNAL( dataChanged( ) ), SLOT( slotDirectionChanged( ) ) );
+ connect( m_pRight, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pRight, SIGNAL( dataChanged( ) ), SLOT( slotRightChanged( ) ) );
+ connect( m_pUp, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pSky, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pLookAt, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pEnableAngle, SIGNAL( toggled( bool ) ),
+ SLOT( slotAngleToggled( bool ) ) );
+ connect( m_pAngle, SIGNAL( dataChanged( ) ), SLOT( slotAngleChanged( ) ) );
+ connect( m_pCameraType, SIGNAL( activated( int ) ),
+ SLOT( slotCameraTypeActivated( int ) ) );
+ connect( m_pCylinderType, SIGNAL( activated( int ) ),
+ SLOT( slotCylinderTypeActivated( int ) ) );
+
+ connect( m_pFocalBlur, SIGNAL( toggled( bool ) ),
+ SLOT( slotFocalBlurToggled( bool ) ) );
+ connect( m_pAperture, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pBlurSamples, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pFocalPoint, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pVariance, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pConfidence, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pExport, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMCameraEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Camera" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMCamera* ) o;
+
+ m_pCameraType->setCurrentItem( m_pDisplayedObject->cameraType( ) );
+ m_pCameraType->setEnabled( !readOnly );
+ slotCameraTypeActivated( m_pDisplayedObject->cameraType( ) );
+ m_pCylinderType->setCurrentItem( m_pDisplayedObject->cylinderType( ) - 1 );
+ m_pCylinderType->setEnabled( !readOnly );
+ m_pLocation->setVector( m_pDisplayedObject->location( ) );
+ m_pLocation->setReadOnly( readOnly );
+ m_pSky->setVector( m_pDisplayedObject->sky( ) );
+ m_pSky->setReadOnly( readOnly );
+ m_pDirection->setVector( m_pDisplayedObject->direction( ) );
+ m_pDirection->setReadOnly( readOnly );
+ m_pRight->setVector( m_pDisplayedObject->right( ) );
+ m_pRight->setReadOnly( readOnly );
+ m_pUp->setVector( m_pDisplayedObject->up( ) );
+ m_pUp->setReadOnly( readOnly );
+ m_pLookAt->setVector( m_pDisplayedObject->lookAt( ) );
+ m_pLookAt->setReadOnly( readOnly );
+
+ m_pEnableAngle->setChecked( m_pDisplayedObject->isAngleEnabled( ) );
+ m_pEnableAngle->setEnabled( !readOnly );
+ m_pAngle->setValue( m_pDisplayedObject->angle( ) );
+ m_pAngle->setReadOnly( readOnly );
+ slotAngleToggled( m_pDisplayedObject->isAngleEnabled( ) );
+ slotRightChanged( );
+ m_pFocalBlur->setChecked( m_pDisplayedObject->isFocalBlurEnabled( ) );
+ slotFocalBlurToggled( m_pDisplayedObject->isFocalBlurEnabled( ) );
+ m_pFocalBlur->setEnabled( !readOnly );
+
+ m_pAperture->setValue( m_pDisplayedObject->aperture( ) );
+ m_pAperture->setReadOnly( readOnly );
+ m_pBlurSamples->setValue( m_pDisplayedObject->blurSamples( ) );
+ m_pBlurSamples->setReadOnly( readOnly );
+ m_pFocalPoint->setVector( m_pDisplayedObject->focalPoint( ) );
+ m_pFocalPoint->setReadOnly( readOnly );
+ m_pConfidence->setValue( m_pDisplayedObject->confidence( ) );
+ m_pConfidence->setReadOnly( readOnly );
+ m_pVariance->setValue( m_pDisplayedObject->variance( ) );
+ m_pVariance->setReadOnly( readOnly );
+
+ m_pExport->setChecked( m_pDisplayedObject->exportPovray( ) );
+ m_pExport->setEnabled( !readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMCameraEdit: Can't display object\n";
+}
+
+void PMCameraEdit::saveContents( )
+{
+ int index;
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ index = m_pCameraType->currentItem( );
+ m_pDisplayedObject->setCameraType( ( PMCamera::CameraType ) index );
+ if( index == 6 )
+ m_pDisplayedObject->setCylinderType( m_pCylinderType->currentItem( ) + 1 );
+ m_pDisplayedObject->setLocation( m_pLocation->vector( ) );
+ m_pDisplayedObject->setDirection( m_pDirection->vector( ) );
+ m_pDisplayedObject->setRight( m_pRight->vector( ) );
+ m_pDisplayedObject->setUp( m_pUp->vector( ) );
+ m_pDisplayedObject->setSky( m_pSky->vector( ) );
+ m_pDisplayedObject->setLookAt( m_pLookAt->vector( ) );
+ m_pDisplayedObject->enableAngle( m_pEnableAngle->isChecked( ) );
+ if( m_pEnableAngle->isChecked( ) )
+ m_pDisplayedObject->setAngle( m_pAngle->value( ) );
+
+ m_pDisplayedObject->enableFocalBlur( m_pFocalBlur->isChecked( ) );
+ if( m_pFocalBlur->isChecked( ) )
+ {
+ m_pDisplayedObject->setAperture( m_pAperture->value( ) );
+ m_pDisplayedObject->setBlurSamples( m_pBlurSamples->value( ) );
+ m_pDisplayedObject->setFocalPoint( m_pFocalPoint->vector( ) );
+ m_pDisplayedObject->setConfidence( m_pConfidence->value( ) );
+ m_pDisplayedObject->setVariance( m_pVariance->value( ) );
+ }
+ m_pDisplayedObject->setExportPovray( m_pExport->isChecked( ) );
+ }
+}
+
+bool PMCameraEdit::isDataValid( )
+{
+ if( !m_pLocation->isDataValid( ) )
+ return false;
+ if( !m_pSky->isDataValid( ) )
+ return false;
+ if( approxZero( m_pSky->vector( ).abs( ) ) )
+ {
+ KMessageBox::error( this, i18n( "The sky vector may not be a null vector." ),
+ i18n( "Error" ) );
+ m_pSky->setFocus( );
+ return false;
+ }
+ if( !m_pDirection->isDataValid( ) )
+ return false;
+ if( approxZero( m_pDirection->vector( ).abs( ) ) )
+ {
+ KMessageBox::error( this, i18n( "The direction vector may not be a null vector." ),
+ i18n( "Error" ) );
+ m_pDirection->setFocus( );
+ return false;
+ }
+ if( !m_pRight->isDataValid( ) )
+ return false;
+ if( approxZero( m_pRight->vector( ).abs( ) ) )
+ {
+ KMessageBox::error( this, i18n( "The right vector may not be a null vector." ),
+ i18n( "Error" ) );
+ m_pRight->setFocus( );
+ return false;
+ }
+ if( !m_pUp->isDataValid( ) )
+ return false;
+ if( approxZero( m_pUp->vector( ).abs( ) ) )
+ {
+ KMessageBox::error( this, i18n( "The up vector may not be a null vector." ),
+ i18n( "Error" ) );
+ m_pDirection->setFocus( );
+ return false;
+ }
+ if( !m_pLookAt->isDataValid( ) )
+ return false;
+ if( m_pEnableAngle->isChecked( ) && !m_pAngle->isDataValid( ) )
+ return false;
+
+ if( ( m_pCameraType->currentItem( ) == 0 ) && m_pEnableAngle->isChecked( ) )
+ {
+ double angle = m_pAngle->value( );
+ if( angle >= 180.0 )
+ {
+ KMessageBox::error( this, i18n( "Angle has to be smaller than 180"
+ " degrees for that camera type." ),
+ i18n( "Error" ) );
+ m_pAngle->setFocus( );
+ return false;
+ }
+ }
+
+ if( m_pFocalBlur->isChecked( ) )
+ {
+ if( !m_pAperture->isDataValid( ) )
+ return false;
+ if( !m_pBlurSamples->isDataValid( ) )
+ return false;
+ if( !m_pFocalPoint->isDataValid( ) )
+ return false;
+ if( !m_pConfidence->isDataValid( ) )
+ return false;
+ if( !m_pVariance->isDataValid( ) )
+ return false;
+ }
+
+ return Base::isDataValid( );
+}
+
+void PMCameraEdit::slotCameraTypeActivated( int index )
+{
+ if( index == 6 )
+ {
+ m_pCylinderType->show( );
+ m_pCylinderTypeLabel->show( );
+ }
+ else
+ {
+ m_pCylinderType->hide( );
+ m_pCylinderTypeLabel->hide( );
+ }
+
+ if( ( index == 1 ) || ( index == 4 ) || ( index == 5 ) )
+ {
+ m_pAngle->hide( );
+ m_pEnableAngle->hide( );
+ }
+ else
+ {
+ m_pAngle->show( );
+ m_pEnableAngle->show( );
+ }
+
+ if( index == 0 )
+ m_pFocalBlur->show( );
+ else
+ m_pFocalBlur->hide( );
+ enableFocalWidgets( m_pFocalBlur->isChecked( ) && ( index == 0 ) );
+ emit sizeChanged( );
+ emit dataChanged( );
+}
+
+void PMCameraEdit::slotCylinderTypeActivated( int )
+{
+ emit dataChanged( );
+}
+
+void PMCameraEdit::slotFocalBlurToggled( bool on )
+{
+ enableFocalWidgets( on && ( m_pCameraType->currentItem( ) == 0 ) );
+ emit dataChanged( );
+}
+
+void PMCameraEdit::slotAngleToggled( bool on )
+{
+ m_pAngle->setEnabled( on );
+ emit dataChanged( );
+}
+
+void PMCameraEdit::slotAngleChanged( )
+{
+ /*
+ if( ( m_pCameraType->currentItem( ) == 0 ) && m_pEnableAngle->isChecked( ) )
+ {
+ // Only change direction's value in perspective and with an enabled angle
+ disconnect( m_pDirection, SIGNAL( dataChanged( ) ), 0, 0 );
+ m_pDirection->setVector( 0.5 * m_pRight->vector( ) / tan( 2 * deg2Rad( m_pAngle->value( ) ) ) );
+ connect( m_pDirection, SIGNAL( dataChanged( ) ), SLOT( slotDirectionChanged( ) ) );
+ }
+ */
+ emit dataChanged( );
+}
+
+void PMCameraEdit::slotDirectionChanged( )
+{
+ calculateCameraAngle( );
+ emit dataChanged( );
+}
+
+void PMCameraEdit::slotRightChanged( )
+{
+ calculateCameraAngle( );
+ emit dataChanged( );
+}
+
+void PMCameraEdit::calculateCameraAngle( )
+{
+ if( ( m_pCameraType->currentItem( ) == 0 ) && !m_pEnableAngle->isChecked( ) )
+ {
+ // Only change angle's value in perspective and with a disabled angle
+ double rl = m_pRight->vector( ).abs( );
+ double dl = m_pDirection->vector( ).abs( );
+ if( ( rl > 0 ) && ( dl > 0 ) )
+ {
+ bool sb = m_pAngle->signalsBlocked( );
+ m_pAngle->blockSignals( true );
+ m_pAngle->setValue( rad2Deg( 2 * atan2( 0.5 * rl, dl ) ) );
+ m_pAngle->blockSignals( sb );
+ }
+ }
+}
+
+void PMCameraEdit::enableFocalWidgets( bool on )
+{
+ QPtrListIterator<QWidget> it( m_focalWidgets );
+
+ for( ; it.current( ); ++it )
+ {
+ if( on )
+ it.current( )->show( );
+ else
+ it.current( )->hide( );
+ }
+ emit sizeChanged( );
+}
+
+#include "pmcameraedit.moc"
diff --git a/kpovmodeler/pmcameraedit.h b/kpovmodeler/pmcameraedit.h
new file mode 100644
index 00000000..7b787683
--- /dev/null
+++ b/kpovmodeler/pmcameraedit.h
@@ -0,0 +1,99 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMCAMERAEDIT_H
+#define PMCAMERAEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmnamedobjectedit.h"
+#include <qptrlist.h>
+
+class PMCamera;
+class PMVectorEdit;
+class PMFloatEdit;
+class PMIntEdit;
+class QComboBox;
+class QLabel;
+class QCheckBox;
+
+/**
+ * Dialog edit class for @ref PMCamera
+ */
+class PMCameraEdit : public PMNamedObjectEdit
+{
+ Q_OBJECT
+ typedef PMNamedObjectEdit Base;
+public:
+ /**
+ * Creates a PMCameraEdit with parent and name
+ */
+ PMCameraEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+protected slots:
+ void slotCameraTypeActivated( int index );
+ void slotCylinderTypeActivated( int index );
+ void slotFocalBlurToggled( bool on );
+ void slotAngleToggled( bool on );
+ void slotAngleChanged( );
+ void slotDirectionChanged( );
+ void slotRightChanged( );
+
+private:
+ void enableFocalWidgets( bool yes );
+ void calculateCameraAngle( );
+
+ PMCamera* m_pDisplayedObject;
+ PMVectorEdit* m_pLocation;
+ PMVectorEdit* m_pDirection;
+ PMVectorEdit* m_pRight;
+ PMVectorEdit* m_pUp;
+ PMVectorEdit* m_pSky;
+ PMVectorEdit* m_pLookAt;
+ QCheckBox* m_pEnableAngle;
+ PMFloatEdit* m_pAngle;
+ QComboBox* m_pCameraType;
+ QComboBox* m_pCylinderType;
+ QLabel* m_pCylinderTypeLabel;
+ QCheckBox* m_pFocalBlur;
+ PMFloatEdit* m_pAperture;
+ PMIntEdit* m_pBlurSamples;
+ PMVectorEdit* m_pFocalPoint;
+ PMFloatEdit* m_pConfidence;
+ PMFloatEdit* m_pVariance;
+ QPtrList<QWidget> m_focalWidgets;
+ QCheckBox* m_pExport;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmclippedby.cpp b/kpovmodeler/pmclippedby.cpp
new file mode 100644
index 00000000..fc00bc51
--- /dev/null
+++ b/kpovmodeler/pmclippedby.cpp
@@ -0,0 +1,114 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmclippedby.h"
+#include "pmclippedbyedit.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+
+#include <klocale.h>
+
+PMDefinePropertyClass( PMClippedBy, PMClippedByProperty );
+
+PMMetaObject* PMClippedBy::s_pMetaObject = 0;
+PMObject* createNewClippedBy( PMPart* part )
+{
+ return new PMClippedBy( part );
+}
+
+PMClippedBy::PMClippedBy( PMPart* part )
+ : Base( part )
+{
+}
+
+PMClippedBy::~PMClippedBy( )
+{
+}
+
+PMMetaObject* PMClippedBy::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "ClippedBy", Base::metaObject( ),
+ createNewClippedBy );
+ s_pMetaObject->addProperty(
+ new PMClippedByProperty( "boundedBy", 0, &PMClippedBy::boundedBy ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMClippedBy::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMClippedBy::description( ) const
+{
+ return i18n( "clipped by" );
+}
+
+bool PMClippedBy::boundedBy( ) const
+{
+ bool cb = true;
+ PMObject* o = firstChild( );
+
+ for( ; o && cb; o = o->nextSibling( ) )
+ if( o->type( ) != "Comment" )
+ cb = false;
+
+ return cb;
+}
+
+void PMClippedBy::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ // no extra data at the moment
+ Base::serialize( e, doc );
+}
+
+void PMClippedBy::readAttributes( const PMXMLHelper& h )
+{
+ // no extra data at the moment
+ Base::readAttributes( h );
+}
+
+PMDialogEditBase* PMClippedBy::editWidget( QWidget* parent ) const
+{
+ return new PMClippedByEdit( parent );
+}
+
+void PMClippedBy::childRemoved( PMObject* o )
+{
+ Base::childRemoved( o );
+
+ // add a dummy change
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMBoundedByID, true );
+}
+
+void PMClippedBy::childAdded( PMObject* o )
+{
+ Base::childAdded( o );
+
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMBoundedByID, true );
+}
diff --git a/kpovmodeler/pmclippedby.h b/kpovmodeler/pmclippedby.h
new file mode 100644
index 00000000..39c5081a
--- /dev/null
+++ b/kpovmodeler/pmclippedby.h
@@ -0,0 +1,88 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMCLIPPEDBY_H
+#define PMCLIPPEDBY_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmcompositeobject.h"
+
+/**
+ * class for clipped_by povray statements
+ */
+
+class PMClippedBy : public PMCompositeObject
+{
+ typedef PMCompositeObject Base;
+public:
+ /**
+ * Creates an empty PMClippedBy
+ */
+ PMClippedBy( PMPart* part );
+ /**
+ * Deletes the object
+ */
+ ~PMClippedBy( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMClippedBy( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual bool dataChangeOnInsertRemove( ) const { return true; }
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMClippedByEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmclippedby" ); }
+
+ /** */
+ virtual void childRemoved( PMObject* );
+ /** */
+ virtual void childAdded( PMObject* );
+
+ /**
+ * Returns true if the object contains no child objects (except comments)
+ */
+ bool boundedBy( ) const;
+
+private:
+ enum PMClippedByMementoID { PMBoundedByID };
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmclippedbyedit.cpp b/kpovmodeler/pmclippedbyedit.cpp
new file mode 100644
index 00000000..18a9d4db
--- /dev/null
+++ b/kpovmodeler/pmclippedbyedit.cpp
@@ -0,0 +1,65 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmclippedbyedit.h"
+#include "pmclippedby.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <klocale.h>
+
+PMClippedByEdit::PMClippedByEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMClippedByEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ m_pChildLabel = new QLabel( i18n( "No child objects" ), this );
+ topLayout( )->addWidget( m_pChildLabel );
+ m_pBoundedByLabel = new QLabel( i18n( "(= bounded by)" ), this );
+ topLayout( )->addWidget( m_pBoundedByLabel );
+}
+
+void PMClippedByEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "ClippedBy" ) )
+ {
+ m_pDisplayedObject = ( PMClippedBy* ) o;
+
+ if( m_pDisplayedObject->boundedBy( ) )
+ {
+ m_pChildLabel->show( );
+ m_pBoundedByLabel->show( );
+ }
+ else
+ {
+ m_pChildLabel->hide( );
+ m_pBoundedByLabel->hide( );
+ }
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMClippedByEdit: Can't display object\n";
+}
+
+#include "pmclippedbyedit.moc"
diff --git a/kpovmodeler/pmclippedbyedit.h b/kpovmodeler/pmclippedbyedit.h
new file mode 100644
index 00000000..3dc0c38f
--- /dev/null
+++ b/kpovmodeler/pmclippedbyedit.h
@@ -0,0 +1,59 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMCLIPPEDBYEDIT_H
+#define PMCLIPPEDBYEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdialogeditbase.h"
+
+class PMClippedBy;
+class QLabel;
+
+/**
+ * Dialog edit class for @ref PMClippedBy
+ */
+class PMClippedByEdit : public PMDialogEditBase
+{
+ Q_OBJECT
+ typedef PMDialogEditBase Base;
+public:
+ /**
+ * Creates a PMClippedByEdit with parent and name
+ */
+ PMClippedByEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+protected:
+ /** */
+ virtual void createTopWidgets( );
+
+private:
+ PMClippedBy* m_pDisplayedObject;
+ QLabel* m_pChildLabel;
+ QLabel* m_pBoundedByLabel;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmcolor.cpp b/kpovmodeler/pmcolor.cpp
new file mode 100644
index 00000000..0eb38b79
--- /dev/null
+++ b/kpovmodeler/pmcolor.cpp
@@ -0,0 +1,196 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmcolor.h"
+#include "pmvector.h"
+#include "pmmath.h"
+
+#include "pmdebug.h"
+
+#include <qtextstream.h>
+#include <qstring.h>
+
+PMColor::PMColor( )
+{
+ int i;
+ for( i = 0; i < 5; i++ )
+ m_colorValue[i] = 0;
+}
+
+PMColor::PMColor( const double red, const double green, const double blue,
+ const double filter, const double transmit )
+{
+ m_colorValue[0] = red;
+ m_colorValue[1] = green;
+ m_colorValue[2] = blue;
+ m_colorValue[3] = filter;
+ m_colorValue[4] = transmit;
+}
+
+PMColor::PMColor( const double red, const double green, const double blue )
+{
+ m_colorValue[0] = red;
+ m_colorValue[1] = green;
+ m_colorValue[2] = blue;
+ m_colorValue[3] = 0;
+ m_colorValue[4] = 0;
+}
+
+PMColor::PMColor( const PMVector& v )
+{
+ int i;
+ if( v.size( ) != 5 )
+ {
+ kdError( PMArea ) << "Vector has wrong size in PMColor::PMColor( const PMVector& v )\n";
+ for( i = 0; i < 5; i++ )
+ m_colorValue[i] = 0;
+ }
+ else
+ {
+ for( i = 0; i < 5; i++ )
+ m_colorValue[i] = v[i];
+ }
+}
+
+PMColor::PMColor( const QColor& c )
+{
+ m_colorValue[0] = c.red( ) / 255.0;
+ m_colorValue[1] = c.green( ) / 255.0;
+ m_colorValue[2] = c.blue( ) / 255.0;
+ m_colorValue[3] = 0.0;
+ m_colorValue[4] = 0.0;
+}
+
+QColor PMColor::toQColor( ) const
+{
+ double r, g, b, max = 0;
+ r = red( );
+ g = green( );
+ b = blue( );
+
+ if( r < 0 ) r = 0;
+ if( g < 0 ) g = 0;
+ if( b < 0 ) b = 0;
+
+ if( r > max )
+ max = r;
+ if( g > max )
+ max = g;
+ if( b > max )
+ max = b;
+ if( max > 1 )
+ {
+ r /= max;
+ g /= max;
+ b /= max;
+ }
+ return QColor( ( int ) ( r * 255 + 0.5 ), ( int ) ( g * 255 + 0.5 ),
+ ( int ) ( b * 255 + 0.5 ) );
+}
+
+QString PMColor::serialize( bool addColorKeyword ) const
+{
+ QString result;
+ QTextStream str( &result, IO_WriteOnly );
+
+ if( addColorKeyword )
+ str << "color ";
+
+ if( approxZero( m_colorValue[4] ) )
+ {
+ if( approxZero( m_colorValue[3] ) )
+ {
+ // rgb
+ str << "rgb <" << m_colorValue[0] << ", " << m_colorValue[1] << ", "
+ << m_colorValue[2] << '>';
+ }
+ else
+ {
+ // rgbf
+ str << "rgbf <" << m_colorValue[0] << ", " << m_colorValue[1] << ", "
+ << m_colorValue[2] << ", " << m_colorValue[3] << '>';
+ }
+ }
+ else
+ {
+ if( approxZero( m_colorValue[3] ) )
+ {
+ // rgbt
+ str << "rgbt <" << m_colorValue[0] << ", " << m_colorValue[1] << ", "
+ << m_colorValue[2] << ", " << m_colorValue[4] << '>';
+ }
+ else
+ {
+ // rgbft
+ str << "rgbft <" << m_colorValue[0] << ", " << m_colorValue[1] << ", "
+ << m_colorValue[2] << ", " << m_colorValue[3]
+ << ", " << m_colorValue[4] << '>';
+ }
+ }
+
+ return result;
+}
+
+QString PMColor::serializeXML( ) const
+{
+ QString result;
+ QTextStream str( &result, IO_WriteOnly );
+ int i;
+
+ for( i = 0; i < 5; i++ )
+ {
+ if( i != 0 )
+ str << ' ';
+ str << m_colorValue[i];
+ }
+
+ return result;
+}
+
+bool PMColor::operator!= ( const PMColor& c ) const
+{
+ return !( *this == c );
+}
+
+bool PMColor::operator== ( const PMColor& c ) const
+{
+ unsigned int i;
+
+ for( i = 0; i < 5; i++ )
+ if( c.m_colorValue[i] != m_colorValue[i] )
+ return false;
+ return true;
+}
+
+bool PMColor::loadXML( const QString& str )
+{
+ QString tmp( str );
+ QTextStream s( &tmp, IO_ReadOnly );
+ QString val;
+ bool ok;
+ int i;
+
+ for( i = 0; i < 5; i++ )
+ {
+ s >> val;
+ m_colorValue[i] = val.toDouble( &ok );
+ if( !ok )
+ return false;
+ }
+ return true;
+}
diff --git a/kpovmodeler/pmcolor.h b/kpovmodeler/pmcolor.h
new file mode 100644
index 00000000..7ae0eeab
--- /dev/null
+++ b/kpovmodeler/pmcolor.h
@@ -0,0 +1,130 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMCOLOR_H
+#define PMCOLOR_H
+
+#include <qstring.h>
+#include <qcolor.h>
+
+class PMVector;
+
+/**
+ * Class for povray colors (red, green, blue, filter and transmit amount)
+ */
+class PMColor
+{
+public:
+ /**
+ * Creates a color with all values set to 0.0
+ */
+ PMColor( );
+ /**
+ * Creates a color
+ */
+ PMColor( const double red, const double green, const double blue,
+ const double filter, const double transmit );
+ /**
+ * Creates a color with filter and transmit set to 0
+ */
+ PMColor( const double red, const double green, const double blue );
+ /**
+ * Creates a color from a @ref PMVector. The vector has to be of size 5
+ */
+ PMColor( const PMVector& v );
+ /**
+ * Creates a color from a @ref QColor object.
+ * filter and transmit are set to 0
+ */
+ PMColor( const QColor& c );
+
+ /**
+ * Sets the red value
+ */
+ void setRed( double d ) { m_colorValue[0] = d; }
+ /**
+ * Returns the red value
+ */
+ double red( ) const { return m_colorValue[0]; }
+ /**
+ * Sets the green value
+ */
+ void setGreen( double d ) { m_colorValue[1] = d; }
+ /**
+ * Returns the green value
+ */
+ double green( ) const { return m_colorValue[1]; }
+ /**
+ * Sets the blue value
+ */
+ void setBlue( double d ) { m_colorValue[2] = d; }
+ /**
+ * Returns the red value
+ */
+ double blue( ) const { return m_colorValue[2]; }
+ /**
+ * Sets the filter value
+ */
+ void setFilter( double d ) { m_colorValue[3] = d; }
+ /**
+ * Returns the filter value
+ */
+ double filter( ) const { return m_colorValue[3]; }
+ /**
+ * Sets the transmit value
+ */
+ void setTransmit( double d ) { m_colorValue[4] = d; }
+ /**
+ * Returns the transmit value
+ */
+ double transmit( ) const { return m_colorValue[4]; }
+
+ /**
+ * Returns the rgb value as QColor
+ */
+ QColor toQColor( ) const;
+
+ /**
+ * Returns a string for serialization
+ */
+ QString serialize( bool addColorKeyword = false ) const;
+ /**
+ * Returns a string for xml output
+ */
+ QString serializeXML( ) const;
+ /**
+ * loads the color data from the xml string
+ */
+ bool loadXML( const QString& str );
+
+ /**
+ * Returns true if the colors are equal*/
+ bool operator== ( const PMColor& p ) const;
+ /**
+ * Returns false if the colors are equal
+ */
+ bool operator!= ( const PMColor& p ) const;
+private:
+ /**
+ * The color values. Index 0 is red, 1 green, 2 blue, 3 filter, 4 transmit
+ */
+ double m_colorValue[5];
+
+};
+
+#endif
diff --git a/kpovmodeler/pmcoloredit.cpp b/kpovmodeler/pmcoloredit.cpp
new file mode 100644
index 00000000..06ac4d0f
--- /dev/null
+++ b/kpovmodeler/pmcoloredit.cpp
@@ -0,0 +1,201 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmcoloredit.h"
+#include "pmlineedits.h"
+#include <kcolorbutton.h>
+#include <klocale.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qcolor.h>
+#include <kdialog.h>
+
+PMColorEdit::PMColorEdit( bool filterAndTransmit, QWidget* parent, const char* name )
+ : QWidget( parent, name )
+{
+ m_bFilterAndTransmit = filterAndTransmit;
+
+ m_edits[0] = new PMFloatEdit( this );
+ m_edits[1] = new PMFloatEdit( this );
+ m_edits[2] = new PMFloatEdit( this );
+ if( filterAndTransmit )
+ {
+ m_edits[3] = new PMFloatEdit( this );
+ m_edits[4] = new PMFloatEdit( this );
+ }
+ else
+ {
+ m_edits[3] = 0;
+ m_edits[4] = 0;
+ }
+ m_pButton = new KColorButton( this );
+
+ QVBoxLayout* topLayout = new QVBoxLayout( this, 0, KDialog::spacingHint( ) );
+ QHBoxLayout* l = new QHBoxLayout( topLayout );
+ l->addWidget( m_pButton );
+ l = new QHBoxLayout( topLayout );
+ l->addWidget( new QLabel( i18n( "red:" ), this ) );
+ l->addWidget( m_edits[0] );
+ l->addWidget( new QLabel( i18n( "green:" ), this ) );
+ l->addWidget( m_edits[1] );
+ l->addWidget( new QLabel( i18n( "blue:" ), this ) );
+ l->addWidget( m_edits[2] );
+ if( filterAndTransmit )
+ {
+ l = new QHBoxLayout( topLayout );
+ l->addWidget( new QLabel( i18n( "filter" ), this ) );
+ l->addWidget( m_edits[3] );
+ l->addWidget( new QLabel( i18n( "transmit" ), this ) );
+ l->addWidget( m_edits[4] );
+ }
+
+ connect( m_edits[0], SIGNAL( dataChanged( ) ), SLOT( slotEditChanged( ) ) );
+ connect( m_edits[1], SIGNAL( dataChanged( ) ), SLOT( slotEditChanged( ) ) );
+ connect( m_edits[2], SIGNAL( dataChanged( ) ), SLOT( slotEditChanged( ) ) );
+ if( filterAndTransmit )
+ {
+ connect( m_edits[3], SIGNAL( dataChanged( ) ), SLOT( slotEditChanged( ) ) );
+ connect( m_edits[4], SIGNAL( dataChanged( ) ), SLOT( slotEditChanged( ) ) );
+ }
+ connect( m_pButton, SIGNAL( changed( const QColor& ) ),
+ SLOT( slotColorChanged( const QColor& ) ) );
+}
+
+void PMColorEdit::setColor( const PMColor& c )
+{
+ bool blocked[5];
+ int i;
+ int num = m_bFilterAndTransmit ? 5 : 3;
+
+ for( i = 0; i < num; i++ )
+ {
+ blocked[i] = m_edits[i]->signalsBlocked( );
+ m_edits[i]->blockSignals( true );
+ }
+
+ m_color = c;
+ m_edits[0]->setValue( c.red( ) );
+ m_edits[1]->setValue( c.green( ) );
+ m_edits[2]->setValue( c.blue( ) );
+ if( m_bFilterAndTransmit )
+ {
+ m_edits[3]->setValue( c.filter( ) );
+ m_edits[4]->setValue( c.transmit( ) );
+ }
+ updateButton( );
+
+ for( i = 0; i < num; i++ )
+ m_edits[i]->blockSignals( blocked[i] );
+}
+
+void PMColorEdit::updateButton( )
+{
+ bool b = m_pButton->signalsBlocked( );
+ m_pButton->blockSignals( true );
+ m_pButton->setColor( m_color.toQColor( ) );
+ m_pButton->blockSignals( b );
+}
+
+bool PMColorEdit::isDataValid( )
+{
+ if( !m_edits[0]->isDataValid( ) )
+ return false;
+ if( !m_edits[1]->isDataValid( ) )
+ return false;
+ if( !m_edits[2]->isDataValid( ) )
+ return false;
+ if( m_bFilterAndTransmit )
+ {
+ if( !m_edits[3]->isDataValid( ) )
+ return false;
+ if( !m_edits[4]->isDataValid( ) )
+ return false;
+ }
+ return true;
+}
+
+void PMColorEdit::setReadOnly( bool yes )
+{
+ m_edits[0]->setReadOnly( yes );
+ m_edits[1]->setReadOnly( yes );
+ m_edits[2]->setReadOnly( yes );
+ if( m_bFilterAndTransmit )
+ {
+ m_edits[3]->setReadOnly( yes );
+ m_edits[4]->setReadOnly( yes );
+ }
+ m_pButton->setEnabled( !yes );
+}
+
+void PMColorEdit::slotColorChanged( const QColor& c )
+{
+ int i;
+ bool blocked[3];
+
+ for( i = 0; i < 3; i++ )
+ {
+ blocked[i] = m_edits[i]->signalsBlocked( );
+ m_edits[i]->blockSignals( true );
+ }
+
+ m_color.setRed( c.red( ) / 255.0 );
+ m_color.setGreen( c.green( ) / 255.0 );
+ m_color.setBlue( c.blue( ) / 255.0 );
+
+ m_edits[0]->setValue( m_color.red( ) );
+ m_edits[1]->setValue( m_color.green( ) );
+ m_edits[2]->setValue( m_color.blue( ) );
+
+ for( i = 0; i < 3; i++ )
+ m_edits[i]->blockSignals( blocked[i] );
+
+ emit dataChanged( );
+}
+
+void PMColorEdit::slotEditChanged( )
+{
+ bool ok;
+
+ m_edits[0]->text( ).toDouble( &ok );
+ if( ok )
+ m_edits[1]->text( ).toDouble( &ok );
+ if( ok )
+ m_edits[2]->text( ).toDouble( &ok );
+ if( m_bFilterAndTransmit )
+ {
+ if( ok )
+ m_edits[3]->text( ).toDouble( &ok );
+ if( ok )
+ m_edits[4]->text( ).toDouble( &ok );
+ }
+
+ if( ok )
+ {
+ m_color.setRed( m_edits[0]->value( ) );
+ m_color.setGreen( m_edits[1]->value( ) );
+ m_color.setBlue( m_edits[2]->value( ) );
+ if( m_bFilterAndTransmit )
+ {
+ m_color.setFilter( m_edits[3]->value( ) );
+ m_color.setTransmit( m_edits[4]->value( ) );
+ }
+ updateButton( );
+ }
+ emit dataChanged( );
+}
+
+#include "pmcoloredit.moc"
diff --git a/kpovmodeler/pmcoloredit.h b/kpovmodeler/pmcoloredit.h
new file mode 100644
index 00000000..4b581a0f
--- /dev/null
+++ b/kpovmodeler/pmcoloredit.h
@@ -0,0 +1,83 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMCOLOREDIT_H
+#define PMCOLOREDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qwidget.h>
+#include "pmcolor.h"
+
+class KColorButton;
+class PMFloatEdit;
+class QColor;
+
+/**
+ * Edit widget for @ref PMColor
+ */
+class PMColorEdit : public QWidget
+{
+ Q_OBJECT
+public:
+ /**
+ * Creates an edit widget for rgbft colors.
+ */
+ PMColorEdit( bool filterAndTransmit, QWidget* parent, const char* name = 0 );
+
+ /**
+ * Sets the displayed color
+ */
+ void setColor( const PMColor& c );
+ /**
+ * Returns the color
+ */
+ PMColor color( ) const { return m_color; }
+
+ /**
+ * Returns true if the input is a valid
+ * color value. Otherwise an error message is shown.
+ */
+ bool isDataValid( );
+
+ /**
+ * Enables or disables read only mode
+ */
+ void setReadOnly( bool yes = true );
+signals:
+ /**
+ * Emitted when the color is changed
+ */
+ void dataChanged( );
+
+protected slots:
+ void slotColorChanged( const QColor& c );
+ void slotEditChanged( );
+private:
+ void updateButton( );
+private:
+ PMFloatEdit* m_edits[5];
+ KColorButton* m_pButton;
+ bool m_bFilterAndTransmit;
+ PMColor m_color;
+};
+
+#endif
diff --git a/kpovmodeler/pmcolorsettings.cpp b/kpovmodeler/pmcolorsettings.cpp
new file mode 100644
index 00000000..d5924d4b
--- /dev/null
+++ b/kpovmodeler/pmcolorsettings.cpp
@@ -0,0 +1,163 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmcolorsettings.h"
+
+#include "pmrendermanager.h"
+#include "pmdefaults.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <kcolorbutton.h>
+#include <klocale.h>
+
+PMColorSettings::PMColorSettings( QWidget* parent, const char* name )
+ : PMSettingsDialogPage( parent, name )
+{
+ QHBoxLayout* hlayout;
+ QVBoxLayout* vlayout;
+ QGridLayout* grid;
+
+ vlayout = new QVBoxLayout( this, 0, KDialog::spacingHint( ) );
+ grid = new QGridLayout( vlayout, 6, 3 );
+
+ grid->addWidget( new QLabel( i18n( "Background:" ), this ), 0, 0 );
+ hlayout = new QHBoxLayout( );
+ grid->addLayout( hlayout, 0, 2 );
+ m_pBackgroundColor = new KColorButton( this );
+ hlayout->addWidget( m_pBackgroundColor );
+ hlayout->addStretch( 1 );
+
+ grid->addWidget( new QLabel( i18n( "Wire frame:" ), this ), 1, 0 );
+ hlayout = new QHBoxLayout( );
+ grid->addLayout( hlayout, 1, 2 );
+ m_pGraphicalObjectsColor[0] = new KColorButton( this );
+ hlayout->addWidget( m_pGraphicalObjectsColor[0] );
+ hlayout->addWidget( new QLabel( i18n( "Selected:" ), this ) );
+ m_pGraphicalObjectsColor[1] = new KColorButton( this );
+ hlayout->addWidget( m_pGraphicalObjectsColor[1] );
+ hlayout->addStretch( 1 );
+
+ grid->addWidget( new QLabel( i18n( "Control points:" ), this ), 2, 0 );
+ hlayout = new QHBoxLayout( );
+ grid->addLayout( hlayout, 2, 2 );
+ m_pControlPointsColor[0] = new KColorButton( this );
+ hlayout->addWidget( m_pControlPointsColor[0] );
+ hlayout->addWidget( new QLabel( i18n( "Selected:" ), this ) );
+ m_pControlPointsColor[1] = new KColorButton( this );
+ hlayout->addWidget( m_pControlPointsColor[1] );
+ hlayout->addStretch( 1 );
+
+ grid->addWidget( new QLabel( i18n( "Axes:" ), this ), 3, 0 );
+ hlayout = new QHBoxLayout( );
+ grid->addLayout( hlayout, 3, 2 );
+ grid->addWidget( new QLabel( "x", this ), 3, 1 );
+ m_pAxesColor[0] = new KColorButton( this );
+ hlayout->addWidget( m_pAxesColor[0] );
+ hlayout->addWidget( new QLabel( "y", this ) );
+ m_pAxesColor[1] = new KColorButton( this );
+ hlayout->addWidget( m_pAxesColor[1] );
+ hlayout->addWidget( new QLabel( "z", this ) );
+ m_pAxesColor[2] = new KColorButton( this );
+ hlayout->addWidget( m_pAxesColor[2] );
+ hlayout->addStretch( 1 );
+
+ grid->addWidget( new QLabel( i18n( "Field of view:" ), this ), 4, 0 );
+ hlayout = new QHBoxLayout( );
+ grid->addLayout( hlayout, 4, 2 );
+ m_pFieldOfViewColor = new KColorButton( this );
+ hlayout->addWidget( m_pFieldOfViewColor );
+ hlayout->addStretch( 1 );
+}
+
+void PMColorSettings::displaySettings( )
+{
+ PMRenderManager* rm = PMRenderManager::theManager( );
+ m_pBackgroundColor->setColor( rm->backgroundColor( ) );
+ m_pGraphicalObjectsColor[0]->setColor( rm->graphicalObjectColor( 0 ) );
+ m_pGraphicalObjectsColor[1]->setColor( rm->graphicalObjectColor( 1 ) );
+ m_pControlPointsColor[0]->setColor( rm->controlPointColor( 0 ) );
+ m_pControlPointsColor[1]->setColor( rm->controlPointColor( 1 ) );
+ m_pAxesColor[0]->setColor( rm->axesColor( 0 ) );
+ m_pAxesColor[1]->setColor( rm->axesColor( 1 ) );
+ m_pAxesColor[2]->setColor( rm->axesColor( 2 ) );
+ m_pFieldOfViewColor->setColor( rm->fieldOfViewColor( ) );
+}
+
+void PMColorSettings::displayDefaults( )
+{
+ m_pBackgroundColor->setColor( c_defaultBackgroundColor );
+ m_pGraphicalObjectsColor[0]->setColor( c_defaultGraphicalObjectColor0 );
+ m_pGraphicalObjectsColor[1]->setColor( c_defaultGraphicalObjectColor1 );
+ m_pControlPointsColor[0]->setColor( c_defaultControlPointColor0 );
+ m_pControlPointsColor[1]->setColor( c_defaultControlPointColor1 );
+ m_pAxesColor[0]->setColor( c_defaultAxesColorX );
+ m_pAxesColor[1]->setColor( c_defaultAxesColorY );
+ m_pAxesColor[2]->setColor( c_defaultAxesColorZ );
+ m_pFieldOfViewColor->setColor( c_defaultFieldOfViewColor );
+}
+
+bool PMColorSettings::validateData( )
+{
+ return true;
+}
+
+void PMColorSettings::applySettings( )
+{
+ bool repaint = false;
+ int i;
+
+ PMRenderManager* rm = PMRenderManager::theManager( );
+ if( rm->backgroundColor( ) != m_pBackgroundColor->color( ) )
+ {
+ rm->setBackgroundColor( m_pBackgroundColor->color( ) );
+ repaint = true;
+ }
+ for( i = 0; i < 2; i++ )
+ {
+ if( rm->graphicalObjectColor( i ) != m_pGraphicalObjectsColor[i]->color( ) )
+ {
+ rm->setGraphicalObjectColor( i, m_pGraphicalObjectsColor[i]->color( ) );
+ repaint = true;
+ }
+ }
+ for( i = 0; i < 2; i++ )
+ {
+ if( rm->controlPointColor( i ) != m_pControlPointsColor[i]->color( ) )
+ {
+ rm->setControlPointColor( i, m_pControlPointsColor[i]->color( ) );
+ repaint = true;
+ }
+ }
+ for( i = 0; i < 3; i++ )
+ {
+ if( rm->axesColor( i ) != m_pAxesColor[i]->color( ) )
+ {
+ rm->setAxesColor( i, m_pAxesColor[i]->color( ) );
+ repaint = true;
+ }
+ }
+ if( rm->fieldOfViewColor( ) != m_pFieldOfViewColor->color( ) )
+ {
+ rm->setFieldOfViewColor( m_pFieldOfViewColor->color( ) );
+ repaint = true;
+ }
+ if( repaint )
+ emit repaintViews( );
+}
+
+#include "pmcolorsettings.moc"
diff --git a/kpovmodeler/pmcolorsettings.h b/kpovmodeler/pmcolorsettings.h
new file mode 100644
index 00000000..9ad628e0
--- /dev/null
+++ b/kpovmodeler/pmcolorsettings.h
@@ -0,0 +1,58 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMCOLORSETTINGS_H
+#define PMCOLORSETTINGS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsettingsdialog.h"
+
+class KColorButton;
+
+/**
+ * Colors configuration dialog page
+ */
+class PMColorSettings : public PMSettingsDialogPage
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ PMColorSettings( QWidget* parent, const char* name = 0 );
+ /** */
+ virtual void displaySettings( );
+ /** */
+ virtual bool validateData( );
+ /** */
+ virtual void applySettings( );
+ /** */
+ virtual void displayDefaults( );
+
+private:
+ KColorButton* m_pBackgroundColor;
+ KColorButton* m_pGraphicalObjectsColor[2];
+ KColorButton* m_pControlPointsColor[2];
+ KColorButton* m_pAxesColor[3];
+ KColorButton* m_pFieldOfViewColor;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmcommand.h b/kpovmodeler/pmcommand.h
new file mode 100644
index 00000000..9bdca16f
--- /dev/null
+++ b/kpovmodeler/pmcommand.h
@@ -0,0 +1,146 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMCOMMAND_H
+#define PMCOMMAND_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qstring.h>
+#include <qptrlist.h>
+
+#include "pmmessage.h"
+#include "pmerrorflags.h"
+
+class PMCommandManager;
+class PMObject;
+class PMPart;
+
+/**
+ * Constants for object changes
+ *
+ * PMCAdd: An object was added
+ *
+ * PMCRemove: An object was removed. A signal with this constant has
+ * to be emitted _before_ the object is removed.
+ *
+ * PMCChildren: Some children are added or removed. Do not use. Use PMCAdd and
+ * PMCRemove for all childrens.
+ *
+ * PMCData: Data (for dialog views) is changed
+ *
+ * PMCDescription: The name or pixmap of the object has changed. Always
+ * together with PMCData.
+ *
+ * PMCViewStructure: The rendering has changed
+ *
+ * PMCNewSelection: The object was selected and all other deleselected.
+ * If the changed object is 0, all objects are deselected!
+ *
+ * PMCSelected: The object was selected.
+ *
+ * PMCDeselected: The object was deselected.
+ *
+ * PMCNewControlPoints: The list of control points has changed.
+ *
+ * PMCControlPointSelection: The control point selection has changed.
+ *
+ * PMCInsertError: The added object couldn't be inserted and was appended
+ * to the insert errors. Always together with PMCAdd.
+ *
+ * PMCNothing: Nothing was changed
+ */
+enum PMChange
+{
+ PMCNothing = 0, PMCAdd = 1, PMCRemove = 2, PMCChildren = 4,
+ PMCData = 8, PMCDescription = 16, PMCViewStructure = 32,
+ PMCGraphicalChange = 64,
+ PMCNewSelection = 128, PMCSelected = 256,
+ PMCDeselected = 512,
+ PMCNewControlPoints = 1024, PMCControlPointSelection = 2048,
+ PMCInsertError = 4096
+};
+
+/**
+ * Base class for all commands, that support undo/redo.
+ */
+class PMCommand
+{
+ friend class PMCommandManager; // only PMCommandManager can execute commands
+public:
+ /**
+ * Creates an empty command object.
+ */
+ PMCommand( ) { }
+ /**
+ * Creates a command with command text text
+ */
+ PMCommand( const QString &text )
+ { m_text = text; }
+ /**
+ * Deletes the command.
+ */
+ virtual ~PMCommand( ) { }
+
+ /**
+ * Command text shown in the undo/redo menues
+ */
+ QString text( ) const { return m_text; }
+ /**
+ * Sets the command text
+ */
+ void setText( const QString& s ) { m_text = s; }
+
+ /**
+ * Checks if the command is valid and sets the error message
+ *
+ * Returns a bitwise combination of @ref PMErrorFlags flags
+ */
+ virtual int errorFlags( PMPart* ) { return PMENone; }
+ /**
+ * Returns the error message
+ */
+ PMMessageList messages( ) { return m_errors; }
+
+protected:
+ /**
+ * Executes the command and stores undo information.
+ */
+ virtual void execute( PMCommandManager* theManager ) = 0;
+ /**
+ * Undoes the command
+ */
+ virtual void undo( PMCommandManager* theManager ) = 0;
+ /**
+ * The error messages
+ */
+ PMMessageList m_errors;
+
+private:
+ /**
+ * The command text.
+ */
+ QString m_text;
+};
+
+typedef QPtrList<PMCommand> PMCommandList;
+
+#endif
diff --git a/kpovmodeler/pmcommandmanager.cpp b/kpovmodeler/pmcommandmanager.cpp
new file mode 100644
index 00000000..333468e3
--- /dev/null
+++ b/kpovmodeler/pmcommandmanager.cpp
@@ -0,0 +1,99 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmcommandmanager.h"
+#include "pmpart.h"
+
+PMCommandManager::PMCommandManager( PMPart* thePart )
+{
+ m_commands.setAutoDelete( true );
+ m_redoCommands.setAutoDelete( true );
+ m_maxUndoRedo = 50;
+ m_pPart = thePart;
+}
+
+PMCommandManager::~PMCommandManager( )
+{
+ m_commands.clear( );
+ m_redoCommands.clear( );
+}
+
+void PMCommandManager::execute( PMCommand* cmd )
+{
+ // some commands (like control point commands) can be executed
+ // multiple times.
+ cmd->execute( this );
+
+ if( m_commands.last( ) != cmd )
+ m_commands.append( cmd );
+ while( m_commands.count( ) > m_maxUndoRedo )
+ m_commands.removeFirst( );
+ m_redoCommands.clear( );
+
+ emit updateUndoRedo( cmd->text( ), QString::null );
+}
+
+void PMCommandManager::undo( )
+{
+ if( !m_commands.isEmpty( ) )
+ {
+ PMCommand* last = m_commands.last( );
+ last->undo( this );
+
+ m_redoCommands.append( m_commands.take( ) );
+
+ if( m_commands.isEmpty( ) )
+ emit updateUndoRedo( QString::null, last->text( ) );
+ else
+ emit updateUndoRedo( m_commands.last( )->text( ), last->text( ) );
+ }
+}
+
+void PMCommandManager::redo( )
+{
+ if( !m_redoCommands.isEmpty( ) )
+ {
+ PMCommand* last = m_redoCommands.last( );
+ last->execute( this );
+
+ m_commands.append( m_redoCommands.take( ) );
+
+ if( m_redoCommands.isEmpty( ) )
+ emit updateUndoRedo( last->text( ), QString::null );
+ else
+ emit updateUndoRedo( last->text( ), m_redoCommands.last( )->text( ) );
+ }
+}
+
+void PMCommandManager::clear( )
+{
+ m_redoCommands.clear( );
+ m_commands.clear( );
+ emit updateUndoRedo( QString::null, QString::null );
+}
+
+void PMCommandManager::cmdObjectChanged( PMObject* obj, const int mode )
+{
+ emit objectChanged( obj, mode, this );
+}
+
+void PMCommandManager::cmdIDChanged( PMObject* obj, const QString& oldID )
+{
+ emit idChanged( obj, oldID );
+}
+#include "pmcommandmanager.moc"
diff --git a/kpovmodeler/pmcommandmanager.h b/kpovmodeler/pmcommandmanager.h
new file mode 100644
index 00000000..2ef2fbbc
--- /dev/null
+++ b/kpovmodeler/pmcommandmanager.h
@@ -0,0 +1,118 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMCOMMANDMANAGER_H
+#define PMCOMMANDMANAGER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmcommand.h"
+#include <qptrstack.h>
+#include <qobject.h>
+
+class PMPart;
+
+/**
+ * Manager for PMCommand objects.
+ *
+ * The class PMCommandManager stores stacks of commands for undo/redo
+ * operations.
+ */
+class PMCommandManager : public QObject
+{
+ Q_OBJECT
+public:
+ /**
+ * Creates a new PMCommandManager
+ */
+ PMCommandManager( PMPart* thepart );
+ /**
+ * Deletes the command manager. All commands are deleted as well.
+ */
+ ~PMCommandManager( );
+ /**
+ * Adds the @ref PMCommand to the command stack.
+ * All commands in the m_redoCommands stack are deleted.
+ */
+ void execute( PMCommand* cmd );
+ /**
+ * Moves the last command to the m_redoCommands stack.
+ */
+ void undo( );
+ /**
+ * Moves the last redo command to the command stack.
+ */
+ void redo( );
+ /**
+ * Deletes the commands
+ */
+ void clear( );
+ /**
+ * Returns the maximal number of items that can be undone/redone.
+ */
+ unsigned int maxUndoRedo( ) const { return m_maxUndoRedo; }
+ /**
+ * Sets the maximal number of items that can be undone/redone.
+ */
+ void setMaxUndoRedo( unsigned int n ) { m_maxUndoRedo = n; }
+ /**
+ * Called by an executed command. Will emit objectChanged( )
+ */
+ void cmdObjectChanged( PMObject* obj, const int mode );
+ /**
+ * Called by an executed command. Will emit idChanged( )
+ */
+ void cmdIDChanged( PMObject* obj, const QString& oldID );
+ /**
+ * Returns a pointer to the part. For commands that need to access the
+ * part directly.
+ */
+ PMPart* part( ) const { return m_pPart; }
+signals:
+ /**
+ * emmited, when the undo and redo command texts change
+ */
+ void updateUndoRedo( const QString& undo, const QString& redo );
+ /**
+ * Signal that is emitted when an object is changed.
+ * Mode is a bit combination of @ref PMChange constants.
+ */
+ void objectChanged( PMObject* obj, const int mode, QObject* sender );
+ /**
+ * Signal that is emitted when the id of the object is changed
+ */
+ void idChanged( PMObject* obj, const QString& oldID );
+private:
+ /**
+ * The executed commands.
+ */
+ PMCommandList m_commands;
+ /**
+ * The undone commands.
+ */
+ PMCommandList m_redoCommands;
+ // the maximal number of items that can be undone/redone.
+ unsigned int m_maxUndoRedo;
+ PMObject* m_pLastChangedObject;
+ PMPart* m_pPart;
+};
+
+#endif
diff --git a/kpovmodeler/pmcomment.cpp b/kpovmodeler/pmcomment.cpp
new file mode 100644
index 00000000..e4783ae5
--- /dev/null
+++ b/kpovmodeler/pmcomment.cpp
@@ -0,0 +1,174 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmcomment.h"
+#include "pmxmlhelper.h"
+
+#include "pmcommentedit.h"
+#include "pmmemento.h"
+
+#include <qtextstream.h>
+#include <klocale.h>
+
+PMDefinePropertyClass( PMComment, PMCommentProperty );
+
+PMMetaObject* PMComment::s_pMetaObject = 0;
+PMObject* createNewComment( PMPart* part )
+{
+ return new PMComment( part );
+}
+
+const unsigned int c_maxDescriptionLength = 25;
+
+PMComment::PMComment( PMPart* part )
+ : Base( part )
+{
+}
+
+PMComment::PMComment( PMPart* part, const QString& t )
+ : Base( part )
+{
+ m_text = t;
+}
+
+PMComment::PMComment( const PMComment& c )
+ : Base( c )
+{
+ m_text = c.m_text;
+}
+
+PMComment::~PMComment( )
+{
+}
+
+QString PMComment::description( ) const
+{
+ if( !m_text.isEmpty( ) )
+ {
+ QString copy = m_text;
+ QTextStream str( &copy, IO_ReadOnly );
+ QString tmp, desc;
+ bool stop = false;
+ bool truncated = false;
+
+ while( !str.atEnd( ) && !stop )
+ {
+ str >> tmp;
+ if( desc.length( ) + tmp.length( ) + 1 <= c_maxDescriptionLength )
+ {
+ if( !desc.isEmpty( ) )
+ desc += " ";
+ desc += tmp;
+ }
+ else
+ {
+ if( desc.isEmpty( ) )
+ {
+ desc = tmp.left( c_maxDescriptionLength );
+ if( tmp.length( ) > c_maxDescriptionLength )
+ truncated = true;
+ }
+ else
+ truncated = true;
+ stop = true;
+ }
+ }
+ if( truncated )
+ desc += "...";
+ return desc;
+ }
+ return i18n( "comment" );
+}
+
+void PMComment::setText( const QString& text )
+{
+ if( text != m_text )
+ {
+ if( m_pMemento )
+ {
+ m_pMemento->addData( s_pMetaObject, PMTextID, m_text );
+ m_pMemento->setDescriptionChanged( );
+ }
+ m_text = text;
+ }
+}
+
+PMMetaObject* PMComment::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Comment", Base::metaObject( ),
+ createNewComment );
+ s_pMetaObject->addProperty(
+ new PMCommentProperty( "text", &PMComment::setText, &PMComment::text ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMComment::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMComment::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ QDomText t = doc.createTextNode( m_text );
+ e.appendChild( t );
+}
+
+void PMComment::readAttributes( const PMXMLHelper& h )
+{
+ QDomNode e = h.element( ).firstChild( );
+ if( e.isText( ) )
+ m_text = e.toText( ).data( );
+}
+
+PMDialogEditBase* PMComment::editWidget( QWidget* parent ) const
+{
+ return new PMCommentEdit( parent );
+}
+
+void PMComment::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMTextID:
+ setText( data->stringData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMComment::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
diff --git a/kpovmodeler/pmcomment.h b/kpovmodeler/pmcomment.h
new file mode 100644
index 00000000..82c62fa8
--- /dev/null
+++ b/kpovmodeler/pmcomment.h
@@ -0,0 +1,92 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMCOMMENT_H
+#define PMCOMMENT_H
+
+#include "pmobject.h"
+#include <qstring.h>
+
+
+/**
+ * Class for povray comments
+ */
+
+class PMComment : public PMObject
+{
+ typedef PMObject Base;
+public:
+ /**
+ * Creates an enpty comment
+ */
+ PMComment( PMPart* part );
+ /**
+ * Creates a comment with text t
+ */
+ PMComment( PMPart* part, const QString& t );
+ /**
+ * Copy constructor
+ */
+ PMComment( const PMComment& c );
+ /**
+ * Deletes the comment
+ */
+ ~PMComment( );
+
+ /**
+ * Sets the comment text
+ */
+ void setText( const QString& text );
+ /**
+ * Returns the comment text
+ */
+ QString text( ) const { return m_text; }
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMComment( *this ); }
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /** */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmcomment" ); }
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMCommentMementoID { PMTextID };
+ QString m_text;
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmcommentedit.cpp b/kpovmodeler/pmcommentedit.cpp
new file mode 100644
index 00000000..6fa5ba9e
--- /dev/null
+++ b/kpovmodeler/pmcommentedit.cpp
@@ -0,0 +1,75 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmcommentedit.h"
+#include "pmcomment.h"
+
+#include <qlayout.h>
+#include <qmultilineedit.h>
+#include <kglobalsettings.h>
+
+PMCommentEdit::PMCommentEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMCommentEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ m_pEdit = new QMultiLineEdit( this );
+#if ( QT_VERSION >= 300 )
+ m_pEdit->setTextFormat( Qt::PlainText );
+ m_pEdit->setWordWrap( QTextEdit::NoWrap );
+#endif
+ m_pEdit->setFont( KGlobalSettings::fixedFont( ) );
+ topLayout( )->addWidget( m_pEdit, 2 );
+
+ connect( m_pEdit, SIGNAL( textChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMCommentEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Comment" ) )
+ {
+ m_pDisplayedObject = ( PMComment* ) o;
+ m_pEdit->setText( m_pDisplayedObject->text( ) );
+
+ m_pEdit->setReadOnly( o->isReadOnly( ) );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMCommentEdit: Can't display object\n";
+}
+
+void PMCommentEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setText( m_pEdit->text( ) );
+ }
+}
+
+bool PMCommentEdit::isDataValid( )
+{
+ return Base::isDataValid( );
+}
+#include "pmcommentedit.moc"
diff --git a/kpovmodeler/pmcommentedit.h b/kpovmodeler/pmcommentedit.h
new file mode 100644
index 00000000..b3dc1d25
--- /dev/null
+++ b/kpovmodeler/pmcommentedit.h
@@ -0,0 +1,62 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMCOMMENTEDIT_H
+#define PMCOMMENTEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdialogeditbase.h"
+
+class PMComment;
+class QMultiLineEdit;
+
+/**
+ * Dialog edit class for @ref PMComment.
+ */
+class PMCommentEdit : public PMDialogEditBase
+{
+ Q_OBJECT
+ typedef PMDialogEditBase Base;
+public:
+ /**
+ * Creates a PMCommentEdit with parent and name
+ */
+ PMCommentEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMComment* m_pDisplayedObject;
+ QMultiLineEdit* m_pEdit;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmcompositeobject.cpp b/kpovmodeler/pmcompositeobject.cpp
new file mode 100644
index 00000000..c1ab704d
--- /dev/null
+++ b/kpovmodeler/pmcompositeobject.cpp
@@ -0,0 +1,396 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmcompositeobject.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pmviewstructure.h"
+
+#include <qdom.h>
+
+PMMetaObject* PMCompositeObject::s_pMetaObject = 0;
+
+PMCompositeObject::PMCompositeObject( PMPart* part )
+ : Base( part )
+{
+ m_pFirstChild = 0;
+ m_pLastChild = 0;
+ m_selectedChildren = 0;
+ m_bViewStructureChanged = true;
+ m_pViewStructure = 0;
+}
+
+PMCompositeObject::PMCompositeObject( const PMCompositeObject& c )
+ : Base( c )
+{
+ m_pFirstChild = 0;
+ m_pLastChild = 0;
+ m_selectedChildren = 0;
+ m_bViewStructureChanged = true;
+ m_pViewStructure = 0;
+
+ PMObject* o = c.m_pFirstChild;
+ for( ; o; o = o->nextSibling( ) )
+ appendChild( o->copy( ) );
+}
+
+PMCompositeObject::~PMCompositeObject( )
+{
+ PMObject* tmp;
+ PMObject* next;
+
+ tmp = m_pFirstChild;
+
+ while( tmp )
+ {
+ next = tmp->m_pNextSibling;
+ delete tmp;
+ tmp = next;
+ }
+
+ if( m_pViewStructure )
+ delete m_pViewStructure;
+}
+
+PMMetaObject* PMCompositeObject::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ s_pMetaObject = new PMMetaObject( "CompositeObject", Base::metaObject( ) );
+ return s_pMetaObject;
+}
+
+void PMCompositeObject::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+PMObject* PMCompositeObject::childAt( uint index ) const
+{
+ PMObject* tmp;
+ uint i = 0;
+
+ for( tmp = m_pFirstChild; tmp && ( i < index ); tmp = tmp->nextSibling( ) )
+ i++;
+ return tmp;
+}
+
+int PMCompositeObject::findChild( PMObject* o )
+{
+ if( o->parent( ) != this )
+ return -1;
+
+ PMObject* tmp;
+ int index = 0;
+
+ for( tmp = m_pFirstChild; tmp; tmp = tmp->nextSibling( ) )
+ {
+ if( tmp == o )
+ return index;
+ else
+ index++;
+ }
+ return -1;
+}
+
+bool PMCompositeObject::insertChild( PMObject* o, int i )
+{
+ if( i < 0 )
+ return appendChild( o );
+ else
+ {
+ if( i == 0 )
+ {
+ if( canInsert( o, 0 ) )
+ {
+ o->m_pNextSibling = m_pFirstChild;
+ o->m_pPrevSibling = 0;
+ if( m_pFirstChild )
+ m_pFirstChild->m_pPrevSibling = o;
+ m_pFirstChild = o;
+ if( !m_pLastChild )
+ m_pLastChild = o;
+ o->m_pParent = this;
+ }
+ else
+ return false;
+ }
+ else
+ {
+ PMObject* tmp = childAt( ( uint ) ( i - 1 ) );
+ if( !tmp )
+ {
+ kdError( PMArea ) << "Index too big" << "\n";
+ return false;
+ }
+
+ if( canInsert( o, tmp ) )
+ {
+ o->m_pPrevSibling = tmp;
+ o->m_pNextSibling = tmp->m_pNextSibling;
+ if( tmp->m_pNextSibling )
+ tmp->m_pNextSibling->m_pPrevSibling = o;
+ else
+ m_pLastChild = o;
+ tmp->m_pNextSibling = o;
+ o->m_pParent = this;
+ }
+ else
+ return false;
+ }
+ childAdded( o );
+ return true;
+ }
+ return false;
+}
+
+bool PMCompositeObject::appendChild( PMObject* o )
+{
+ if( canInsert( o, m_pLastChild ) )
+ {
+ o->m_pParent = this;
+ o->m_pPrevSibling = m_pLastChild;
+ o->m_pNextSibling = 0;
+ if( m_pLastChild )
+ m_pLastChild->m_pNextSibling = o;
+ else
+ m_pFirstChild = o;
+ m_pLastChild = o;
+
+ childAdded( o );
+ return true;
+ }
+ return false;
+}
+
+bool PMCompositeObject::insertChildAfter( PMObject* obj, PMObject* after )
+{
+ if( canInsert( obj, after ) )
+ {
+ if( after->m_pParent == this )
+ {
+ obj->m_pParent = this;
+ obj->m_pPrevSibling = after;
+ obj->m_pNextSibling = after->m_pNextSibling;
+ if( after->m_pNextSibling )
+ after->m_pNextSibling->m_pPrevSibling = obj;
+ else
+ m_pLastChild = obj;
+ after->m_pNextSibling = obj;
+
+ childAdded( obj );
+ return true;
+ }
+ else
+ {
+ kdError( PMArea ) << "Object after is no child" << "\n";
+ return false;
+ }
+ }
+ return false;
+}
+
+bool PMCompositeObject::insertChildBefore( PMObject* obj, PMObject* before )
+{
+ if( before )
+ {
+ if( canInsert( obj, before->m_pPrevSibling ) )
+ {
+ if( before->m_pParent == this )
+ {
+ obj->m_pParent = this;
+ obj->m_pPrevSibling = before->m_pPrevSibling;
+ obj->m_pNextSibling = before;
+ if( before->m_pPrevSibling )
+ before->m_pPrevSibling->m_pNextSibling = obj;
+ else
+ m_pFirstChild = obj;
+ before->m_pPrevSibling = obj;
+
+ childAdded( obj );
+ return true;
+ }
+ else
+ {
+ kdError( PMArea ) << "Object before is no child" << "\n";
+ return false;
+ }
+ }
+ }
+ return false;
+}
+
+bool PMCompositeObject::takeChild( PMObject* o )
+{
+ if( ( PMObject* ) this == o->m_pParent )
+ {
+ // deselect the object and all child objects of o
+ if( o->isSelected( ) )
+ o->setSelected( false );
+ else if( o->selectedChildren( ) > 0 )
+ o->deselectChildren( );
+
+ // remove it, but do NOT delete it.
+ if( o->m_pPrevSibling )
+ o->m_pPrevSibling->m_pNextSibling = o->m_pNextSibling;
+ else
+ m_pFirstChild = o->m_pNextSibling;
+ if( o->m_pNextSibling )
+ o->m_pNextSibling->m_pPrevSibling = o->m_pPrevSibling;
+ else
+ m_pLastChild = o->m_pPrevSibling;
+
+ o->m_pParent = 0;
+ o->m_pPrevSibling = 0;
+ o->m_pNextSibling = 0;
+
+ childRemoved( o );
+ return true;
+ }
+ kdError( PMArea ) << "o is no child" << "\n";
+ return false;
+}
+
+bool PMCompositeObject::takeChild( uint i )
+{
+ PMObject* tmp = childAt( i );
+ if( tmp )
+ return takeChild( tmp );
+ kdError( PMArea ) << "Index too big";
+ return false;
+}
+
+void PMCompositeObject::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ PMObject* tmp;
+
+ for( tmp = m_pFirstChild; tmp; tmp = tmp->m_pNextSibling )
+ e.appendChild( tmp->serialize( doc ) );
+}
+
+int PMCompositeObject::countChildren( ) const
+{
+ int num = 0;
+ PMObject* tmp;
+
+ for( tmp = m_pFirstChild; tmp; tmp = tmp->m_pNextSibling )
+ num++;
+ return num;
+}
+
+void PMCompositeObject::adjustSelectedChildren( int num )
+{
+ m_selectedChildren += num;
+ if( m_selectedChildren < 0 )
+ {
+ kdError( PMArea ) << "num too big in PMCompositeObject::adjustSelectedChildren( )\n";
+ m_selectedChildren = 0;
+ }
+ if( m_pParent )
+ m_pParent->adjustSelectedChildren( num );
+}
+
+void PMCompositeObject::deselectChildren( )
+{
+ PMObject* tmp;
+ if( m_selectedChildren > 0 )
+ {
+ tmp = m_pFirstChild;
+ while( tmp && ( m_selectedChildren > 0 ) )
+ {
+ if( tmp->isSelected( ) )
+ tmp->setSelected( false );
+ else if( tmp->selectedChildren( ) > 0 )
+ tmp->deselectChildren( );
+
+ tmp = tmp->m_pNextSibling;
+ }
+ }
+}
+
+
+PMViewStructure* PMCompositeObject::viewStructure( )
+{
+ if( m_pViewStructure )
+ {
+ if( m_pViewStructure->parameterKey( ) != viewStructureParameterKey( ) )
+ {
+ // the default view structure or the parameters (detail level)
+ // have changed
+ m_bViewStructureChanged = true;
+ delete m_pViewStructure;
+ m_pViewStructure = 0;
+ }
+ }
+
+ if( m_bViewStructureChanged )
+ {
+ PMViewStructure* dvs = defaultViewStructure( );
+ if( dvs )
+ if( dvs->parameterKey( ) == -1 ) // newly created view structure
+ dvs->setParameterKey( viewStructureParameterKey( ) );
+
+ if( isDefault( ) )
+ {
+ if( dvs )
+ {
+ if( m_pViewStructure )
+ {
+ if( *m_pViewStructure != *dvs )
+ {
+ delete m_pViewStructure;
+ m_pViewStructure = new PMViewStructure( dvs );
+ }
+ }
+ else
+ m_pViewStructure = new PMViewStructure( dvs );
+ }
+
+ if( !m_pViewStructure )
+ kdError( PMArea ) << "isDefault( ) returned true, but no default view structure is provided\n";
+ }
+ else
+ {
+ if( dvs )
+ {
+ if( m_pViewStructure && ( *m_pViewStructure == *dvs ) )
+ {
+ delete m_pViewStructure;
+ m_pViewStructure = 0;
+ }
+ }
+ createViewStructure( );
+ if( m_pViewStructure )
+ m_pViewStructure->setParameterKey( viewStructureParameterKey( ) );
+ }
+ m_bViewStructureChanged = false;
+ }
+ return m_pViewStructure;
+}
+
+void PMCompositeObject::setViewStructureChanged( )
+{
+ m_bViewStructureChanged = true;
+ if( m_pMemento )
+ m_pMemento->setViewStructureChanged( );
+}
+
diff --git a/kpovmodeler/pmcompositeobject.h b/kpovmodeler/pmcompositeobject.h
new file mode 100644
index 00000000..c2e2da58
--- /dev/null
+++ b/kpovmodeler/pmcompositeobject.h
@@ -0,0 +1,198 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMCOMPOBJECT_H
+#define PMCOMPOBJECT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmobject.h"
+
+/**
+ * Base class for all povray objects that can have child objects.
+ *
+ * Used pattern: Composite
+ */
+class PMCompositeObject : public PMObject
+{
+ typedef PMObject Base;
+public:
+ /**
+ * Creates an empty PMCompositeObject
+ */
+ PMCompositeObject( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMCompositeObject( const PMCompositeObject& o );
+ /**
+ * Deletes the object and all children.
+ */
+ virtual ~PMCompositeObject( );
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /**
+ * Returns a pointer to the first child.
+ */
+ virtual PMObject* firstChild( ) const { return m_pFirstChild; }
+ /**
+ * Returns a pointer to the last child.
+ */
+ virtual PMObject* lastChild( ) const { return m_pLastChild; }
+ /**
+ * Returns a pointer to the child object at position index,
+ * or null if the index is out of range.
+ */
+ virtual PMObject* childAt( uint index ) const;
+
+ /**
+ * Returns true if the object contains the child object o
+ */
+ virtual bool containsChild( PMObject* o ) const
+ { return ( ( PMObject* )this == o->parent( ) ); }
+ /**
+ * Returns the index of the object or -1 if not found
+ */
+ virtual int findChild( PMObject* o );
+
+ /**
+ * Inserts the object as child at index i.
+ * If i is -1, the object is appended.
+ * Returns true if successful.
+ */
+ virtual bool insertChild( PMObject* o, int i );
+ /**
+ * Inserts the object as child after the child object after
+ */
+ virtual bool insertChildAfter( PMObject* object, PMObject* after );
+ /**
+ * Inserts the object as child before the child object before
+ */
+ virtual bool insertChildBefore( PMObject* object, PMObject* before );
+ /**
+ * Appends the object as child. Returns true if successful.
+ */
+ virtual bool appendChild( PMObject* );
+ /**
+ * Returns the number of children.
+ */
+ virtual int countChildren( ) const;
+ /**
+ * Removes a child object. Does not delete it!
+ * Returns true if successful.*/
+ virtual bool takeChild( PMObject* o );
+ /**
+ * Removes a child object at index i. Does not delete it!
+ */
+ virtual bool takeChild( uint i );
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+
+ /**
+ * Returns the number of selected child items. All selected items in
+ * any depth are counted
+ */
+ virtual int selectedChildren( ) const { return m_selectedChildren; }
+ /**
+ * Deselects recursively all child objects
+ */
+ virtual void deselectChildren( );
+
+ /**
+ * Returns the view structure of the object.
+ *
+ * If the view structure has changed since the last call, the
+ * structure is created or updated, or the default view structure
+ * is used.
+ *
+ * If the default view structure can't be used, this function calls
+ * createViewStructure, which has to create a non default view structure.
+ */
+ virtual PMViewStructure* viewStructure( );
+protected:
+ /**
+ * Adds num to the number of selected objects in this object and all
+ * parent objects. num can be negative.
+ */
+ virtual void adjustSelectedChildren( int num );
+
+ /**
+ * Returns the default view structure for the object. This view
+ * structure can be shared between all objects of this type.
+ *
+ * Only the data can be shared, NOT the pointer!!!
+ *
+ * The default view structure has to be created when this function
+ * is called first.
+ */
+ virtual PMViewStructure* defaultViewStructure( ) const { return 0; }
+ /**
+ * Returns a key that represents the view structure parameter.
+ *
+ * Each time a view structure parameter is changed (=detail level),
+ * this key has to be incremented.
+ */
+ virtual int viewStructureParameterKey( ) const { return 0; }
+
+ /**
+ * Returns true if the objects attributes are default and the default
+ * view structure can be used
+ */
+ virtual bool isDefault( ) { return false; }
+ /**
+ * The object has to create or update a non default view structure
+ */
+ virtual void createViewStructure( ) { };
+ /**
+ * Calls setViewStructureChanged( ) for the memento (if one has been created)
+ * and marks the current view structure as outdated.
+ */
+ void setViewStructureChanged( );
+ /**
+ * The view structure.
+ */
+ PMViewStructure* m_pViewStructure;
+private:
+ /**
+ * Pointer to the first child
+ */
+ PMObject* m_pFirstChild;
+ /**
+ * Pointer to the last child
+ */
+ PMObject* m_pLastChild;
+ /**
+ * number of selected child items.
+ */
+ int m_selectedChildren;
+ /**
+ * The modify flag for the view structure
+ */
+ bool m_bViewStructureChanged;
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmcone.cpp b/kpovmodeler/pmcone.cpp
new file mode 100644
index 00000000..2772eda5
--- /dev/null
+++ b/kpovmodeler/pmcone.cpp
@@ -0,0 +1,451 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Leonardo Skorianez
+ email : lsk@if.ufrj.br
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmcone.h"
+
+#include "pmxmlhelper.h"
+#include "pmboxedit.h"
+#include "pmmemento.h"
+#include "pm3dcontrolpoint.h"
+#include "pmdefaults.h"
+#include "pmdistancecontrolpoint.h"
+#include "pmconeedit.h"
+
+#include <klocale.h>
+
+
+const double defaultConeRadius1 = 0.0;
+const double defaultConeRadius2 = 0.5;
+const double defaultHalfConeSize = 0.5;
+const PMVector defaultEnd1 = PMVector ( 0, defaultHalfConeSize, 0 );
+const PMVector defaultEnd2 = PMVector ( 0, -defaultHalfConeSize, 0 );
+const bool defaultOpen = false;
+
+/** default cone structure */
+PMViewStructure* PMCone::s_pDefaultViewStructure = 0;
+int PMCone::s_numSteps = c_defaultConeSteps;
+int PMCone::s_parameterKey = 0;
+
+PMDefinePropertyClass( PMCone, PMConeProperty );
+
+PMMetaObject* PMCone::s_pMetaObject = 0;
+PMObject* createNewCone( PMPart* part )
+{
+ return new PMCone( part );
+}
+
+PMCone::PMCone( PMPart* part )
+ :Base( part )
+{
+ m_end1 = defaultEnd1;
+ m_end2 = defaultEnd2;
+ m_radius1 = defaultConeRadius1;
+ m_radius2 = defaultConeRadius2;
+ m_open = defaultOpen;
+}
+
+PMCone::PMCone( const PMCone& c )
+ : Base( c )
+{
+ m_end1 = c.m_end1;
+ m_end2 = c.m_end2;
+ m_radius1 = c.m_radius1;
+ m_radius2 = c.m_radius2;
+ m_open = c.m_open;
+}
+
+PMCone::~PMCone( )
+{
+}
+
+QString PMCone::description( ) const
+{
+ return i18n( "cone" );
+}
+
+void PMCone::serialize( QDomElement & e, QDomDocument & doc ) const
+{
+ e.setAttribute( "end_a", m_end1.serializeXML( ) );
+ e.setAttribute( "end_b", m_end2.serializeXML( ) );
+ e.setAttribute( "radius_a", m_radius1 );
+ e.setAttribute( "radius_b", m_radius2 );
+ e.setAttribute( "open", m_open );
+ Base::serialize( e, doc );
+}
+
+void PMCone::readAttributes( const PMXMLHelper & h )
+{
+ m_end1 = h.vectorAttribute( "end_a", defaultEnd1 );
+ m_end2 = h.vectorAttribute( "end_b", defaultEnd2 );
+ m_radius1 = h.doubleAttribute( "radius_a", defaultConeRadius1 );
+ m_radius2 = h.doubleAttribute( "radius_b", defaultConeRadius2 );
+ m_open = h.boolAttribute( "open", defaultOpen );
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMCone::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Cone", Base::metaObject( ),
+ createNewCone );
+ s_pMetaObject->addProperty(
+ new PMConeProperty( "end1", &PMCone::setEnd1, &PMCone::end1 ) );
+ s_pMetaObject->addProperty(
+ new PMConeProperty( "end2", &PMCone::setEnd2, &PMCone::end2 ) );
+ s_pMetaObject->addProperty(
+ new PMConeProperty( "radius1", &PMCone::setRadius1, &PMCone::radius1 ) );
+ s_pMetaObject->addProperty(
+ new PMConeProperty( "radius2", &PMCone::setRadius2, &PMCone::radius2 ) );
+ s_pMetaObject->addProperty(
+ new PMConeProperty( "open", &PMCone::setOpen, &PMCone::open ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMCone::setEnd1( const PMVector & p )
+{
+ if( p != m_end1 )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnd1ID, m_end1 );
+ m_end1 = p;
+ m_end1.resize( 3 );
+ setViewStructureChanged( );
+ }
+}
+
+void PMCone::setEnd2( const PMVector & p )
+{
+ if( p != m_end2 )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnd2ID, m_end2 );
+ m_end2 = p;
+ m_end2.resize( 3 );
+ setViewStructureChanged( );
+ }
+}
+
+void PMCone::setRadius1( double radius )
+{
+ if( m_radius1 != radius )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMRadius1ID, m_radius1 );
+ m_radius1 = radius;
+ setViewStructureChanged( );
+ }
+}
+
+void PMCone::setRadius2( double radius )
+{
+ if( m_radius2 != radius )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMRadius2ID, m_radius2 );
+ m_radius2 = radius;
+ setViewStructureChanged( );
+ }
+}
+
+void PMCone::setOpen( bool op )
+{
+ if( op != m_open )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMOpenID, m_open );
+ m_open = op;
+ }
+}
+
+PMDialogEditBase* PMCone::editWidget( QWidget * parent ) const
+{
+ return new PMConeEdit( parent );
+}
+
+void PMCone::restoreMemento( PMMemento * s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMEnd1ID:
+ setEnd1( data->vectorData( ) );
+ break;
+ case PMEnd2ID:
+ setEnd2( data->vectorData( ) );
+ break;
+ case PMRadius1ID:
+ setRadius1( data->doubleData( ) );
+ break;
+ case PMRadius2ID:
+ setRadius2( data->doubleData( ) );
+ break;
+ case PMOpenID:
+ setOpen( data->boolData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMCone::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento (s);
+}
+
+bool PMCone::isDefault( )
+{
+ if( ( m_end1 == defaultEnd1 ) && ( m_radius1 == defaultConeRadius1 )
+ && ( m_end2 == defaultEnd2 ) && ( m_radius2 == defaultConeRadius2 ) && ( m_open == defaultOpen )
+ && globalDetail( ) )
+ return true;
+ return false;
+}
+
+void PMCone::createViewStructure( )
+{
+ if( !m_pViewStructure )
+ {
+ m_pViewStructure = new PMViewStructure(defaultViewStructure ( ) );
+ m_pViewStructure->points( ).detach( );
+ }
+
+ int steps = (int)( ( (float)s_numSteps / 2 ) * ( displayDetail( ) + 1 ) );
+ unsigned ptsSize = steps * 2;
+ unsigned lineSize = steps * 3;
+
+ if( ptsSize != m_pViewStructure->points( ).size( ) )
+ m_pViewStructure->points( ).resize( ptsSize );
+
+ createPoints( m_pViewStructure->points( ), m_end1, m_end2, m_radius1, m_radius2, steps );
+
+ if( lineSize != m_pViewStructure->lines( ).size( ) )
+ {
+ m_pViewStructure->lines( ).detach( );
+ m_pViewStructure->lines( ).resize( lineSize );
+ createLines( m_pViewStructure->lines( ), steps );
+ }
+}
+
+PMViewStructure* PMCone::defaultViewStructure( ) const
+{
+ if( !s_pDefaultViewStructure || s_pDefaultViewStructure->parameterKey( ) != viewStructureParameterKey( ) )
+ {
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ int steps = (int)( ( (float)s_numSteps / 2 ) * ( globalDetailLevel( ) + 1 ) );
+ s_pDefaultViewStructure = new PMViewStructure( steps * 2, steps * 3 );
+
+ createPoints( s_pDefaultViewStructure->points( ), defaultEnd1,
+ defaultEnd2,defaultConeRadius1,defaultConeRadius2, steps );
+
+ createLines( s_pDefaultViewStructure->lines( ), steps );
+ }
+ return s_pDefaultViewStructure;
+}
+
+void PMCone::createLines( PMLineArray& lines, int steps )
+{
+ int i;
+ for( i = 0; i < ( steps - 1 ); i++ )
+ {
+ lines[i] = PMLine( i, i + 1 );
+ lines[i + steps] = PMLine( i + steps, i + steps+ 1 );
+ }
+ lines[steps - 1] = PMLine( steps - 1, 0 );
+ lines[steps * 2 - 1] = PMLine( steps * 2 - 1, steps );
+
+ for( i = 0; i < steps; i++ )
+ {
+ lines[i + 2 * steps] = PMLine( i, i + steps );
+ }
+}
+
+void PMCone::createPoints( PMPointArray& points, const PMVector& end1,
+ const PMVector& end2, double radius1, double radius2, int steps )
+{
+
+ double angle = ( 2.0 * M_PI ) / (double) steps;
+
+ PMVector pointAt = end2 - end1;
+ double pl = pointAt.abs( );
+ if( approxZero( pl ) )
+ pointAt = PMVector( 0.0, 1.0, 0.0 );
+ else
+ pointAt /= pl;
+
+ PMMatrix rotation = PMMatrix::rotation( pointAt, angle );
+ PMVector endPoint1 = pointAt.orthogonal( );
+ endPoint1 *= radius1;
+ PMVector endPoint2 = pointAt.orthogonal( );
+ endPoint2 *= radius2;
+
+ int i;
+ for( i = 0; i < steps; i++ )
+ {
+ points[i] = PMPoint( endPoint1 + end1 );
+ points[i + steps] = PMPoint( endPoint2 + end2 );
+ endPoint1 = rotation * endPoint1;
+ endPoint2 = rotation * endPoint2;
+ }
+}
+
+void PMCone::controlPoints( PMControlPointList & list )
+{
+ PMVector center, angle1, angle2;
+ center = m_end1 - m_end2;
+ double pl = center.abs( );
+ if( approxZero( pl ) )
+ center = PMVector( 0.0, 1.0, 0.0 );
+ else
+ center /= pl;
+
+ angle1 = center.orthogonal( );
+ angle2 = PMVector::cross( center, angle1 );
+
+ PM3DControlPoint* pb1 = new PM3DControlPoint( m_end1, PMEnd1ID, i18n( "End 1" ) );
+ list.append( pb1 );
+ PM3DControlPoint* pb2 = new PM3DControlPoint( m_end2, PMEnd2ID, i18n( "End 2" ) );
+ list.append( pb2 );
+
+ list.append( new PMDistanceControlPoint( pb1, angle1, m_radius1, PMRadius1ID, i18n( "Radius 1 (1)" ) ) );
+ list.append( new PMDistanceControlPoint( pb1, angle2, m_radius1, PMRadius1ID, i18n( "Radius 1 (2)" ) ) );
+ list.append( new PMDistanceControlPoint( pb2, angle1, m_radius2, PMRadius2ID, i18n( "Radius 2 (1)" ) ) );
+ list.append( new PMDistanceControlPoint( pb2, angle2, m_radius2, PMRadius2ID, i18n( "Radius 2 (2)" ) ) );
+}
+
+void PMCone::controlPointsChanged( PMControlPointList & list )
+{
+ PMControlPoint* p;
+ bool pointChanged = false;
+ bool radiusChanged = false;
+
+ for( p = list.first( ); p; p = list.next( ) )
+ {
+ if( p->changed( ) )
+ {
+ switch( p->id( ) )
+ {
+ case PMEnd1ID:
+ setEnd1( ( ( PM3DControlPoint *) p)->point( ) );
+ pointChanged = true;
+ break;
+ case PMEnd2ID:
+ setEnd2( ( ( PM3DControlPoint *) p)->point( ) );
+ pointChanged = true;
+ break;
+ case PMRadius1ID:
+ setRadius1( ( ( PMDistanceControlPoint *) p)->distance( ) );
+ radiusChanged = true;
+ break;
+ case PMRadius2ID:
+ setRadius2( ( ( PMDistanceControlPoint *) p)->distance( ) );
+ radiusChanged = true;
+ break;
+ default:
+ kdError (PMArea) << "Wrong ID in PMCone::controlPointsChanged\n";
+ break;
+ }
+ }
+ }
+
+ if( pointChanged )
+ {
+ PMVector center, angle1, angle2;
+ bool firstPoint1 = true;
+ bool firstPoint2 = true;
+
+ center = m_end1 - m_end2;
+ double pl = center.abs( );
+ if( approxZero( pl ) )
+ center = PMVector( 0.0, 1.0, 0.0 );
+ else
+ center /= pl;
+
+ angle1 = center.orthogonal( );
+ angle2 = PMVector::cross( center, angle1 );
+
+ for( p = list.first( ); p; p = list.next( ) )
+ {
+ if( p->id( ) == PMRadius1ID )
+ {
+ if( firstPoint1 )
+ {
+ ( ( PMDistanceControlPoint *) p)->setDirection( angle1 );
+ firstPoint1 = false;
+ }
+ else
+ ( ( PMDistanceControlPoint *) p)->setDirection( angle2 );
+ }else if( p->id( ) == PMRadius2ID )
+ {
+ if( firstPoint2 )
+ {
+ ( ( PMDistanceControlPoint *) p)->setDirection( angle1 );
+ firstPoint2 = false;
+ }
+ else
+ ( ( PMDistanceControlPoint *) p)->setDirection( angle2 );
+ }
+ }
+ }
+
+ if( radiusChanged )
+ for( p = list.first( ); p; p = list.next( ) )
+ if( p->id( ) == PMRadius1ID )
+ ( ( PMDistanceControlPoint *) p)->setDistance( m_radius1 );
+ else if( p->id( ) == PMRadius2ID )
+ ( ( PMDistanceControlPoint *) p)->setDistance( m_radius2 );
+}
+
+void PMCone::setSteps( int s )
+{
+ if( s >= 4 )
+ {
+ s_numSteps = s;
+ if( s_pDefaultViewStructure )
+ {
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ }
+ }
+ else
+ kdDebug( PMArea ) << "PMCone::setSteps: S must be greater than 4\n";
+ s_parameterKey++;
+}
+
+void PMCone::cleanUp( ) const
+{
+ if( s_pDefaultViewStructure )
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
diff --git a/kpovmodeler/pmcone.h b/kpovmodeler/pmcone.h
new file mode 100644
index 00000000..445846f3
--- /dev/null
+++ b/kpovmodeler/pmcone.h
@@ -0,0 +1,188 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Leonardo Skorianez
+ email : lsk@if.ufrj.br
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMCONE_H
+#define PMCONE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobject.h"
+#include "pmvector.h"
+#include "pmviewstructure.h"
+
+class PMViewStructure;
+
+/**
+ * Class for Povray Cone
+ *
+ */
+
+class PMCone : public PMSolidObject
+{
+ typedef PMSolidObject Base;
+public:
+ /**
+ * Create a Cone
+ */
+ PMCone( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMCone( const PMCone& c );
+
+ /**
+ * delete the Cone
+ */
+ virtual ~PMCone( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMCone( *this ); }
+
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMConeEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmcone" ); }
+
+ /**
+ * Return the end_1
+ */
+ PMVector end1( ) const { return m_end1; }
+ /**
+ * Sets end_1
+ */
+ void setEnd1( const PMVector & p );
+ /**
+ * Return the end_2
+ */
+ PMVector end2( ) const { return m_end2; }
+ /**
+ * Sets end_2
+ */
+ void setEnd2( const PMVector & p );
+ /**
+ * return the first radius of the cone
+ */
+ double radius1( ) const { return m_radius1; }
+ /**
+ * Sets the first radius of the cone
+ */
+ void setRadius1( double radius );
+ /**
+ * return the second radius of the cone
+ */
+ double radius2( ) const { return m_radius2; }
+ /**
+ * Sets the second radius of the cone
+ */
+ void setRadius2( double radius );
+ /**
+ * Return open = 1 or close = 0
+ */
+ bool open( ) const { return m_open; }
+ /**
+ * Sets open cylinder
+ */
+ void setOpen( bool op );
+
+ /**
+ * Returns the number of lines for rendering
+ */
+ static int steps( ) { return s_numSteps; }
+ /**
+ * Sets the number of lines for rendering
+ */
+ static void setSteps( int s );
+
+ /** */
+ virtual void restoreMemento( PMMemento * s );
+ /** */
+ virtual void controlPoints( PMControlPointList & list );
+ /** */
+ virtual void controlPointsChanged( PMControlPointList & list );
+ /** */
+ virtual bool hasDisplayDetail( ) const { return true; }
+ /** */
+ virtual void cleanUp( ) const;
+
+protected:
+ /** */
+ virtual bool isDefault( );
+ /** */
+ virtual void createViewStructure( );
+ /** */
+ virtual PMViewStructure* defaultViewStructure( ) const;
+ /** */
+ virtual int viewStructureParameterKey( ) const { return s_parameterKey + globalDetailKey(); }
+
+private:
+ /**
+ * Creates the lines for the view structure
+ */
+ static void createLines( PMLineArray& lines, int steps );
+ /**
+ * Creates the points for the view structure
+ */
+ static void createPoints( PMPointArray& points, const PMVector& end1,
+ const PMVector& end2, double radius1, double radius2, int steps );
+
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMConeMementoID { PMEnd1ID, PMEnd2ID, PMRadius1ID, PMRadius2ID, PMOpenID };
+ /**
+ * ends of cone
+ */
+ PMVector m_end1, m_end2;
+ /**
+ * radius of cone
+ */
+ double m_radius1,m_radius2;
+ /**
+ * open
+ */
+ bool m_open;
+ /**
+ * The default view structure. It can be shared between cones
+ */
+ static PMViewStructure* s_pDefaultViewStructure;
+ static int s_numSteps;
+ static int s_parameterKey;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmconeedit.cpp b/kpovmodeler/pmconeedit.cpp
new file mode 100644
index 00000000..2dbcfc7c
--- /dev/null
+++ b/kpovmodeler/pmconeedit.cpp
@@ -0,0 +1,119 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Leonardo Skorianez
+ email : lsk@if.ufrj.br
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmconeedit.h"
+#include "pmcone.h"
+#include "pmvectoredit.h"
+#include "pmlineedits.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <klocale.h>
+#include <qcheckbox.h>
+
+PMConeEdit::PMConeEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMConeEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* layout;
+ QGridLayout* gl;
+
+ m_pEnd1 = new PMVectorEdit( "x", "y", "z", this );
+ m_pEnd2 = new PMVectorEdit( "x", "y", "z", this );
+ m_pRadius1 = new PMFloatEdit( this );
+ m_pRadius2 = new PMFloatEdit( this );
+ m_pOpen = new QCheckBox( i18n( "type of the object", "Open" ), this );
+
+ gl = new QGridLayout( topLayout( ), 2, 2 );
+ gl->addWidget( new QLabel( i18n( "End 1:" ), this ), 0, 0 );
+ gl->addWidget( m_pEnd1, 0, 1 );
+ gl->addWidget( new QLabel( i18n( "End 2:" ), this ), 1, 0 );
+ gl->addWidget( m_pEnd2, 1, 1 );
+
+ layout = new QHBoxLayout( topLayout( ) );
+ gl = new QGridLayout( layout, 2, 2 );
+ gl->addWidget( new QLabel( i18n( "Radius 1:" ), this ), 0, 0 );
+ gl->addWidget( m_pRadius1, 0, 1 );
+ gl->addWidget( new QLabel( i18n( "Radius 2:" ), this ), 1, 0 );
+ gl->addWidget( m_pRadius2, 1, 1 );
+ layout->addStretch( 1 );
+
+ topLayout( )->addWidget( m_pOpen );
+
+ connect( m_pEnd1, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pEnd2, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pRadius1, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pRadius2, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pOpen, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMConeEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Cone" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMCone* ) o;
+
+ m_pEnd1->setVector( m_pDisplayedObject->end1( ) );
+ m_pEnd2->setVector( m_pDisplayedObject->end2( ) );
+ m_pRadius1->setValue( m_pDisplayedObject->radius1( ) );
+ m_pRadius2->setValue( m_pDisplayedObject->radius2( ) );
+ m_pOpen->setChecked( m_pDisplayedObject->open( ) );
+
+ m_pEnd1->setReadOnly( readOnly );
+ m_pEnd2->setReadOnly( readOnly );
+ m_pRadius1->setReadOnly( readOnly );
+ m_pRadius2->setReadOnly( readOnly );
+ m_pOpen->setEnabled( !readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMConeEdit: Can't display object\n";
+}
+
+void PMConeEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setEnd1( m_pEnd1->vector( ) );
+ m_pDisplayedObject->setEnd2( m_pEnd2->vector( ) );
+ m_pDisplayedObject->setRadius1( m_pRadius1->value( ) );
+ m_pDisplayedObject->setRadius2( m_pRadius2->value( ) );
+ m_pDisplayedObject->setOpen( m_pOpen->isChecked( ) );
+ }
+}
+
+bool PMConeEdit::isDataValid( )
+{
+ if( m_pEnd1->isDataValid( ) )
+ if( m_pEnd2->isDataValid( ) )
+ if( m_pRadius1->isDataValid( ) )
+ if( m_pRadius2->isDataValid( ) )
+ return Base::isDataValid( );
+ return false;
+}
+
+#include "pmconeedit.moc"
diff --git a/kpovmodeler/pmconeedit.h b/kpovmodeler/pmconeedit.h
new file mode 100644
index 00000000..f39f95c6
--- /dev/null
+++ b/kpovmodeler/pmconeedit.h
@@ -0,0 +1,64 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Leonardo Skorinaez
+ email : lsk@if.ufrj.br
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMCONEEDIT_H
+#define PMCONEEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobjectedit.h"
+
+class QCheckBox;
+
+class PMVectorEdit;
+class PMFloatEdit;
+class PMCone;
+
+class PMConeEdit : public PMSolidObjectEdit
+{
+ Q_OBJECT
+ typedef PMSolidObjectEdit Base;
+public:
+ /**
+ * Creates a PMConeEdit with parent and name
+ */
+ PMConeEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMCone* m_pDisplayedObject;
+ PMVectorEdit* m_pEnd1;
+ PMVectorEdit* m_pEnd2;
+ PMFloatEdit* m_pRadius1;
+ PMFloatEdit* m_pRadius2;
+ QCheckBox* m_pOpen;
+};
+#endif
diff --git a/kpovmodeler/pmcontrolpoint.cpp b/kpovmodeler/pmcontrolpoint.cpp
new file mode 100644
index 00000000..8617ae27
--- /dev/null
+++ b/kpovmodeler/pmcontrolpoint.cpp
@@ -0,0 +1,99 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmcontrolpoint.h"
+#include "pmdefaults.h"
+#include "pmdebug.h"
+
+#include <kconfig.h>
+
+double PMControlPoint::s_moveGrid = c_defaultMoveGrid;
+double PMControlPoint::s_scaleGrid = c_defaultScaleGrid;
+double PMControlPoint::s_rotateGrid = c_defaultRotateGrid;
+
+PMControlPoint::PMControlPoint( int id, const QString& description )
+{
+ m_id = id;
+ m_bChanged = false;
+ m_description = description;
+ m_bSelected = false;
+}
+
+PMControlPoint::~PMControlPoint( )
+{
+}
+
+void PMControlPoint::startChange( const PMVector& s, const PMVector& n )
+{
+ m_startPoint = s;
+ m_normalVector = n;
+ graphicalChangeStarted( );
+}
+
+void PMControlPoint::change( const PMVector& endPoint )
+{
+ m_bChanged = true;
+ graphicalChange( m_startPoint, m_normalVector, endPoint );
+}
+
+bool PMControlPoint::changed( )
+{
+ bool h = m_bChanged;
+ m_bChanged = false;
+
+ return h;
+}
+
+void PMControlPoint::setMoveGrid( double d )
+{
+ if( d > 0 )
+ s_moveGrid = d;
+ else
+ kdError( PMArea ) << "Grid has to be greater than 0\n";
+}
+
+void PMControlPoint::setScaleGrid( double d )
+{
+ if( d > 0 )
+ s_scaleGrid = d;
+ else
+ kdError( PMArea ) << "Grid has to be greater than 0\n";
+}
+
+void PMControlPoint::setRotateGrid( double d )
+{
+ if( d > 0 )
+ s_rotateGrid = d;
+ else
+ kdError( PMArea ) << "Grid has to be greater than 0\n";
+}
+
+void PMControlPoint::saveConfig( KConfig* cfg )
+{
+ cfg->setGroup( "Grid" );
+ cfg->writeEntry( "MoveGrid", s_moveGrid );
+ cfg->writeEntry( "RotateGrid", s_rotateGrid );
+ cfg->writeEntry( "ScaleGrid", s_scaleGrid );
+}
+
+void PMControlPoint::restoreConfig( KConfig* cfg )
+{
+ cfg->setGroup( "Grid" );
+ s_moveGrid = cfg->readDoubleNumEntry( "MoveGrid", c_defaultMoveGrid );
+ s_rotateGrid = cfg->readDoubleNumEntry( "RotateGrid", c_defaultRotateGrid );
+ s_scaleGrid = cfg->readDoubleNumEntry( "ScaleGrid", c_defaultScaleGrid );
+}
diff --git a/kpovmodeler/pmcontrolpoint.h b/kpovmodeler/pmcontrolpoint.h
new file mode 100644
index 00000000..8d3e9e66
--- /dev/null
+++ b/kpovmodeler/pmcontrolpoint.h
@@ -0,0 +1,190 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMCONTROLPOINT_H
+#define PMCONTROLPOINT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmvector.h"
+#include <qptrlist.h>
+#include <qstring.h>
+
+class KConfig;
+
+/**
+ * Interface between the graphical views and the PMObject.
+ *
+ * PMControlPoint is the interface between graphical view and PMObjects that
+ * can be changed graphically with the mouse. A @ref PMObject has a
+ * PMControlPoint for each changeable attribute.
+ *
+ * There is one subclass for each change behavior like 3dpoint, normal vector,
+ * radius, rotation ...
+ *
+ * Each control point has an id to be indentified by the PMObject. The id has
+ * to be unique within a PMObject.
+ */
+
+class PMControlPoint
+{
+public:
+ /**
+ * Creates a PMControlPoint with an id and a description.
+ */
+ PMControlPoint( int id, const QString& description );
+ /**
+ * Deletes the PMControlPoint
+ */
+ virtual ~PMControlPoint( );
+
+ /**
+ * Starts a graphical change at 3d cursor position startPoint. viewNormal
+ * is the normal vector of the view
+ */
+ void startChange( const PMVector& startPoint, const PMVector& viewNormal );
+ /**
+ * Graphical change with 3d end cursor position endPoint
+ */
+ void change( const PMVector& endPoint );
+ /**
+ * Snaps the control point to the grid
+ */
+ virtual void snapToGrid( ) = 0;
+
+ /**
+ * 3d coordinates of the control point for rendering*/
+ virtual PMVector position( ) const { return PMVector( ); }
+ /**
+ * Returns true if the point should be displayed (rendered)
+ */
+ virtual bool display( ) const { return true; }
+ /**
+ * Returns the id of the control point
+ */
+ int id( ) const { return m_id; }
+ /**
+ * Type of the control point
+ *
+ * CPPoint: The control point is displayed as point, the mouse cursor
+ * has to be over the control point to be active (e.g. 3DControlPoint)
+ *
+ * CPCross: The control point is displayed as cross, the control point
+ * can be changed with the mouse in the whole view (e.g. Translation)
+ */
+ enum PMCPDisplayType { CPPoint = 0, CPCross = 1 };
+ /**
+ * Returns the type of the control point (see @ref PMCPDisplayType)
+ */
+ virtual PMCPDisplayType displayType( ) const { return CPPoint; };
+ /**
+ * Returns the description
+ */
+ QString description( ) const { return m_description; }
+ /**
+ * Selects/deselects the control point
+ */
+ void setSelected( bool yes ) { m_bSelected = yes; }
+ /**
+ * Returns true if the control point is selected
+ */
+ bool selected( ) const { return m_bSelected; }
+
+ /**
+ * Returns true, if the control point was changed and sets the
+ * changed flag to false.
+ */
+ bool changed( );
+
+ /**
+ * Returns true if an extra line should be displayed in addition to
+ * the view structure
+ */
+ virtual bool hasExtraLine( ) const { return false; }
+ /**
+ * Returns the start point of the extra line
+ */
+ virtual PMVector extraLineStart( ) const { return PMVector( 0, 0, 0 ); }
+ /**
+ * Returns the end point of the extra line
+ */
+ virtual PMVector extraLineEnd( ) const { return PMVector( 0, 0, 0 ); }
+
+ /**
+ * Returns the grid distance for 3d points, vectors and movements
+ */
+ static double moveGrid( ) { return s_moveGrid; }
+ /**
+ * Sets the grid distance
+ */
+ static void setMoveGrid( double d );
+ /**
+ * Returns the grid distance rotations
+ */
+ static double rotateGrid( ) { return s_rotateGrid; }
+ /**
+ * Sets the grid distance
+ */
+ static void setRotateGrid( double d );
+ /**
+ * Returns the grid distance for scales
+ */
+ static double scaleGrid( ) { return s_scaleGrid; }
+ /**
+ * Sets the grid distance
+ */
+ static void setScaleGrid( double d );
+
+ static void saveConfig( KConfig* cfg );
+ static void restoreConfig( KConfig* cfg );
+
+protected:
+ /**
+ * Called when a graphical change was started
+ */
+ virtual void graphicalChangeStarted( ) = 0;
+ /**
+ * Called when the control point was changed
+ */
+ virtual void graphicalChange( const PMVector& startPoint,
+ const PMVector& viewNormal,
+ const PMVector& endPoint ) = 0;
+ /**
+ * Sets the changed flag
+ */
+ void setChanged( ) { m_bChanged = true; }
+private:
+ int m_id;
+ PMVector m_startPoint;
+ PMVector m_normalVector;
+ bool m_bChanged;
+ bool m_bSelected;
+ QString m_description;
+
+ static double s_moveGrid;
+ static double s_rotateGrid;
+ static double s_scaleGrid;
+};
+
+typedef QPtrList<PMControlPoint> PMControlPointList;
+typedef QPtrListIterator<PMControlPoint> PMControlPointListIterator;
+
+#endif
diff --git a/kpovmodeler/pmcsg.cpp b/kpovmodeler/pmcsg.cpp
new file mode 100644
index 00000000..3af76740
--- /dev/null
+++ b/kpovmodeler/pmcsg.cpp
@@ -0,0 +1,200 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmcsg.h"
+
+#include <klocale.h>
+#include "pmxmlhelper.h"
+#include "pmcsgedit.h"
+#include "pmmemento.h"
+#include "pmenumproperty.h"
+
+PMDefineEnumPropertyClass( PMCSG, PMCSG::PMCSGType, PMCSGTypeProperty );
+
+PMMetaObject* PMCSG::s_pMetaObject = 0;
+PMObject* createNewCSG( PMPart* part )
+{
+ return new PMCSG( part );
+}
+
+PMCSG::PMCSG( PMPart* part )
+ : Base( part )
+{
+ m_type = CSGUnion;
+}
+
+PMCSG::PMCSG( PMPart* part, const PMCSGType t )
+ : Base( part )
+{
+ m_type = t;
+}
+
+PMCSG::PMCSG( const PMCSG& c )
+ : Base( c )
+{
+ m_type = c.m_type;
+}
+
+PMCSG::~PMCSG( )
+{
+}
+
+QString PMCSG::description( ) const
+{
+ switch( m_type )
+ {
+ case CSGUnion:
+ return i18n( "union" );
+ break;
+ case CSGIntersection:
+ return i18n( "intersection" );
+ break;
+ case CSGDifference:
+ return i18n( "difference" );
+ break;
+ case CSGMerge:
+ return i18n( "merge" );
+ break;
+ }
+ return QString( "" );
+}
+
+QString PMCSG::pixmap( ) const
+{
+ switch( m_type )
+ {
+ case CSGUnion:
+ return QString( "pmunion" );
+ break;
+ case CSGIntersection:
+ return QString( "pmintersection" );
+ break;
+ case CSGDifference:
+ return QString( "pmdifference" );
+ break;
+ case CSGMerge:
+ return QString( "pmmerge" );
+ break;
+ }
+ return QString( "" );
+}
+
+void PMCSG::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ switch( m_type )
+ {
+ case CSGUnion:
+ e.setAttribute( "csgtype", "union" );
+ break;
+ case CSGIntersection:
+ e.setAttribute( "csgtype", "intersection" );
+ break;
+ case CSGDifference:
+ e.setAttribute( "csgtype", "difference" );
+ break;
+ case CSGMerge:
+ e.setAttribute( "csgtype", "merge" );
+ break;
+ }
+
+ Base::serialize( e, doc );
+}
+
+void PMCSG::readAttributes( const PMXMLHelper& h )
+{
+ QString str = h.stringAttribute( "csgtype", "union" );
+ if( str == "union" )
+ m_type = CSGUnion;
+ else if( str == "intersection" )
+ m_type = CSGIntersection;
+ else if( str == "difference" )
+ m_type = CSGDifference;
+ else
+ m_type = CSGMerge;
+
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMCSG::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "CSG", Base::metaObject( ),
+ createNewCSG );
+ PMCSGTypeProperty* p = new PMCSGTypeProperty( "csgType", &PMCSG::setCSGType, &PMCSG::csgType );
+ p->addEnumValue( "union", CSGUnion );
+ p->addEnumValue( "intersection", CSGIntersection );
+ p->addEnumValue( "difference", CSGDifference );
+ p->addEnumValue( "merge", CSGMerge );
+ s_pMetaObject->addProperty( p );
+ }
+ return s_pMetaObject;
+}
+
+void PMCSG::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMCSG::setCSGType( const PMCSGType t )
+{
+ if( t != m_type )
+ {
+ if( m_pMemento )
+ {
+ m_pMemento->addData( s_pMetaObject, PMTypeID, ( int ) m_type );
+ m_pMemento->setDescriptionChanged( );
+ }
+ m_type = t;
+ }
+}
+
+PMDialogEditBase* PMCSG::editWidget( QWidget* parent ) const
+{
+ return new PMCSGEdit( parent );
+}
+
+void PMCSG::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMTypeID:
+ setCSGType( ( PMCSGType ) data->intData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMCSG::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
diff --git a/kpovmodeler/pmcsg.h b/kpovmodeler/pmcsg.h
new file mode 100644
index 00000000..e8ce741e
--- /dev/null
+++ b/kpovmodeler/pmcsg.h
@@ -0,0 +1,105 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMCSG_H
+#define PMCSG_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobject.h"
+
+/**
+ * Class for povray csg objects.
+ */
+
+class PMCSG : public PMSolidObject
+{
+ typedef PMSolidObject Base;
+public:
+ /**
+ * The type of the csg object
+ */
+ enum PMCSGType { CSGUnion, CSGIntersection, CSGDifference, CSGMerge };
+ /**
+ * Creates an empty PMCSG union
+ */
+ PMCSG( PMPart* part );
+ /**
+ * Creates an empty PMCSG object with type t
+ */
+ PMCSG( PMPart* part, const PMCSGType t );
+ /**
+ * Copy constructor
+ */
+ PMCSG( const PMCSG& c );
+
+ /**
+ * deletes the PMCSG object
+ */
+ virtual ~PMCSG( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMCSG( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMCSGEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const;
+
+ /**
+ * Returns the type of the csg
+ */
+ PMCSGType csgType( ) const { return m_type; }
+ /**
+ * Sets the type of the csg
+ */
+ void setCSGType( const PMCSGType t );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMCSGMementoID { PMTypeID };
+ PMCSGType m_type;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmcsgedit.cpp b/kpovmodeler/pmcsgedit.cpp
new file mode 100644
index 00000000..9a6e0a39
--- /dev/null
+++ b/kpovmodeler/pmcsgedit.cpp
@@ -0,0 +1,118 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmcsgedit.h"
+#include "pmcsg.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcombobox.h>
+#include <klocale.h>
+
+PMCSGEdit::PMCSGEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMCSGEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* layout;
+ m_pTypeCombo = new QComboBox( false, this );
+ m_pTypeCombo->insertItem( i18n( "Union" ) );
+ m_pTypeCombo->insertItem( i18n( "Intersection" ) );
+ m_pTypeCombo->insertItem( i18n( "Difference" ) );
+ m_pTypeCombo->insertItem( i18n( "Merge" ) );
+
+ layout = new QHBoxLayout( topLayout( ) );
+ layout->addWidget( new QLabel( i18n( "Type:" ), this ) );
+ layout->addWidget( m_pTypeCombo );
+ layout->addStretch( 1 );
+
+ connect( m_pTypeCombo, SIGNAL( activated( int ) ), SLOT( slotTypeSelected( int ) ) );
+}
+
+void PMCSGEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "CSG" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMCSG* ) o;
+
+ switch( m_pDisplayedObject->csgType( ) )
+ {
+ case PMCSG::CSGUnion:
+ m_pTypeCombo->setCurrentItem( 0 );
+ break;
+ case PMCSG::CSGIntersection:
+ m_pTypeCombo->setCurrentItem( 1 );
+ break;
+ case PMCSG::CSGDifference:
+ m_pTypeCombo->setCurrentItem( 2 );
+ break;
+ case PMCSG::CSGMerge:
+ m_pTypeCombo->setCurrentItem( 3 );
+ break;
+ }
+
+ m_pTypeCombo->setEnabled( !readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMCSGEdit: Can't display object\n";
+}
+
+void PMCSGEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ switch( m_pTypeCombo->currentItem( ) )
+ {
+ case 0:
+ m_pDisplayedObject->setCSGType( PMCSG::CSGUnion );
+ break;
+ case 1:
+ m_pDisplayedObject->setCSGType( PMCSG::CSGIntersection );
+ break;
+ case 2:
+ m_pDisplayedObject->setCSGType( PMCSG::CSGDifference );
+ break;
+ case 3:
+ m_pDisplayedObject->setCSGType( PMCSG::CSGMerge );
+ break;
+ default:
+ m_pDisplayedObject->setCSGType( PMCSG::CSGUnion );
+ break;
+ }
+ }
+}
+
+bool PMCSGEdit::isDataValid( )
+{
+ return Base::isDataValid( );
+}
+
+void PMCSGEdit::slotTypeSelected( int )
+{
+ emit dataChanged( );
+}
+#include "pmcsgedit.moc"
diff --git a/kpovmodeler/pmcsgedit.h b/kpovmodeler/pmcsgedit.h
new file mode 100644
index 00000000..8aeaddc6
--- /dev/null
+++ b/kpovmodeler/pmcsgedit.h
@@ -0,0 +1,63 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMCSGEDIT_H
+#define PMCSGEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobjectedit.h"
+
+class PMCSG;
+class QComboBox;
+
+/**
+ * Dialog edit class for @ref PMCSG
+ */
+class PMCSGEdit : public PMSolidObjectEdit
+{
+ Q_OBJECT
+ typedef PMSolidObjectEdit Base;
+public:
+ /**
+ * Creates a PMCSGEdit with parent and name
+ */
+ PMCSGEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+protected slots:
+ void slotTypeSelected( int index );
+private:
+ PMCSG* m_pDisplayedObject;
+ QComboBox* m_pTypeCombo;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmcylinder.cpp b/kpovmodeler/pmcylinder.cpp
new file mode 100644
index 00000000..1a119004
--- /dev/null
+++ b/kpovmodeler/pmcylinder.cpp
@@ -0,0 +1,407 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Leonardo Skorianez
+ email : lsk@if.ufrj.br
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmcylinder.h"
+
+#include "pmxmlhelper.h"
+#include "pmboxedit.h"
+#include "pmmemento.h"
+#include "pm3dcontrolpoint.h"
+#include "pmdefaults.h"
+
+#include <klocale.h>
+
+#include "pmdistancecontrolpoint.h"
+
+#include "pmcylinderedit.h"
+
+const double defaultCylRadius = 0.5;
+const double defaultHalfCylSize = 0.5;
+const PMVector defaultEnd1 = PMVector ( 0, defaultHalfCylSize, 0 );
+const PMVector defaultEnd2 = PMVector ( 0, -defaultHalfCylSize, 0 );
+const bool defaultOpen = false;
+
+/** default cylinder structure */
+PMViewStructure* PMCylinder::s_pDefaultViewStructure = 0;
+int PMCylinder::s_numSteps = c_defaultCylinderSteps;
+int PMCylinder::s_parameterKey = 0;
+
+PMDefinePropertyClass( PMCylinder, PMCylinderProperty );
+
+PMMetaObject* PMCylinder::s_pMetaObject = 0;
+PMObject* createNewCylinder( PMPart* part )
+{
+ return new PMCylinder( part );
+}
+
+
+PMCylinder::PMCylinder( PMPart* part )
+ : Base( part )
+{
+ m_end1 = defaultEnd1;
+ m_end2 = defaultEnd2;
+ m_radius = defaultCylRadius;
+ m_open = defaultOpen;
+}
+
+PMCylinder::PMCylinder( const PMCylinder& c )
+ : Base( c )
+{
+ m_end1 = c.m_end1;
+ m_end2 = c.m_end2;
+ m_radius = c.m_radius;
+ m_open = c.m_open;
+}
+
+PMCylinder::~PMCylinder( )
+{
+}
+
+QString PMCylinder::description( ) const
+{
+ return i18n( "cylinder" );
+}
+
+void PMCylinder::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "end_a", m_end1.serializeXML( ) );
+ e.setAttribute( "end_b", m_end2.serializeXML( ) );
+ e.setAttribute( "radius", m_radius );
+ e.setAttribute( "open", m_open );
+ Base::serialize( e, doc );
+}
+
+void PMCylinder::readAttributes( const PMXMLHelper& h )
+{
+ m_end1 = h.vectorAttribute( "end_a", defaultEnd1 );
+ m_end2 = h.vectorAttribute( "end_b", defaultEnd2 );
+ m_radius = h.doubleAttribute( "radius", defaultCylRadius );
+ m_open = h.boolAttribute( "open", defaultOpen );
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMCylinder::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Cylinder", Base::metaObject( ),
+ createNewCylinder );
+ s_pMetaObject->addProperty(
+ new PMCylinderProperty( "end1", &PMCylinder::setEnd1, &PMCylinder::end1 ) );
+ s_pMetaObject->addProperty(
+ new PMCylinderProperty( "end2", &PMCylinder::setEnd2, &PMCylinder::end2 ) );
+ s_pMetaObject->addProperty(
+ new PMCylinderProperty( "radius", &PMCylinder::setRadius, &PMCylinder::radius ) );
+ s_pMetaObject->addProperty(
+ new PMCylinderProperty( "open", &PMCylinder::setOpen, &PMCylinder::open ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMCylinder::setEnd1( const PMVector& p )
+{
+ if( p != m_end1 )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnd1ID, m_end1 );
+ m_end1 = p;
+ m_end1.resize( 3 );
+ setViewStructureChanged( );
+ }
+}
+
+void PMCylinder::setEnd2( const PMVector& p )
+{
+ if( p != m_end2 )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnd2ID, m_end2 );
+ m_end2 = p;
+ m_end2.resize( 3 );
+ setViewStructureChanged( );
+ }
+}
+
+void PMCylinder::setRadius( double radius )
+{
+ if( m_radius != radius )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMRadiusID, m_radius );
+ m_radius = radius;
+ setViewStructureChanged( );
+ }
+}
+
+void PMCylinder::setOpen( bool op )
+{
+ if( op != m_open )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMOpenID, m_open );
+ m_open = op;
+ }
+}
+
+PMDialogEditBase* PMCylinder::editWidget( QWidget* parent ) const
+{
+ return new PMCylinderEdit( parent );
+}
+
+void PMCylinder::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMEnd1ID:
+ setEnd1( data->vectorData( ) );
+ break;
+ case PMEnd2ID:
+ setEnd2( data->vectorData( ) );
+ break;
+ case PMRadiusID:
+ setRadius( data->doubleData( ) );
+ break;
+ case PMOpenID:
+ setOpen( data->boolData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMCylinder::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
+bool PMCylinder::isDefault( )
+{
+ if( ( m_end1 == defaultEnd1 ) && ( m_end2 == defaultEnd2 )
+ && ( m_radius == defaultCylRadius ) && ( m_open == defaultOpen )
+ && globalDetail( ) )
+ return true;
+ return false;
+}
+
+void PMCylinder::createViewStructure( )
+{
+ if( !m_pViewStructure )
+ {
+ m_pViewStructure = new PMViewStructure( defaultViewStructure ( ) );
+ m_pViewStructure->points( ).detach( );
+ }
+
+ int steps = (int)( ( (float)s_numSteps / 2 ) * ( displayDetail( ) + 1 ) );
+ unsigned ptsSize = steps * 2;
+ unsigned lineSize = steps * 3;
+
+ if( ptsSize != m_pViewStructure->points( ).size( ) )
+ m_pViewStructure->points( ).resize( ptsSize );
+
+ createPoints( m_pViewStructure->points( ), m_end1, m_end2, m_radius, steps );
+
+ if( ( lineSize ) != m_pViewStructure->lines( ).size( ) )
+ {
+ m_pViewStructure->lines( ).detach( );
+ m_pViewStructure->lines( ).resize( lineSize );
+ createLines( m_pViewStructure->lines( ), steps );
+ }
+}
+
+PMViewStructure* PMCylinder::defaultViewStructure( ) const
+{
+ if( !s_pDefaultViewStructure || s_pDefaultViewStructure->parameterKey( ) != viewStructureParameterKey( ) )
+ {
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ int steps = (int)( ( (float)s_numSteps / 2 ) * ( globalDetailLevel( ) + 1 ) );
+ s_pDefaultViewStructure = new PMViewStructure( steps * 2, steps * 3 );
+
+ createPoints( s_pDefaultViewStructure->points( ), defaultEnd1,
+ defaultEnd2, defaultCylRadius, steps );
+
+ createLines( s_pDefaultViewStructure->lines( ), steps );
+ }
+ return s_pDefaultViewStructure;
+}
+
+void PMCylinder::createLines( PMLineArray& lines, int steps )
+{
+ int i;
+ for( i = 0; i < ( steps - 1 ); i++ )
+ {
+ lines[i] = PMLine( i, i + 1 );
+ lines[i + steps] = PMLine( i + steps, i + steps + 1 );
+ }
+ lines[steps - 1] = PMLine( steps - 1, 0 );
+ lines[steps * 2 - 1] = PMLine( steps * 2 - 1, steps );
+
+ for( i = 0; i < steps; i++ )
+ {
+ lines[i + 2 * steps] = PMLine( i, i + steps );
+ }
+}
+
+void PMCylinder::createPoints( PMPointArray& points, const PMVector& end1,
+ const PMVector& end2, double radius, int steps )
+{
+ double angle = ( 2.0 * M_PI ) / ( double ) steps;
+
+ PMVector pointAt = end2 - end1;
+ double pl = pointAt.abs( );
+ if( approxZero( pl ) )
+ pointAt = PMVector( 0.0, 0.0, 1.0 );
+ else
+ pointAt /= pl;
+
+ PMMatrix rotation = PMMatrix::rotation( pointAt, angle );
+ PMVector endPoint = pointAt.orthogonal( );
+ endPoint *= radius;
+
+ int i;
+ for( i = 0; i < steps; i++ )
+ {
+ points[i] = PMPoint( endPoint + end1 );
+ points[i + steps] = PMPoint( endPoint + end2 );
+ endPoint = rotation * endPoint;
+ }
+}
+
+void PMCylinder::controlPoints( PMControlPointList & list )
+{
+ PMVector center, angle1, angle2;
+ center = m_end1 - m_end2;
+ double pl = center.abs( );
+ if( approxZero( pl ) )
+ center = PMVector( 0.0, 1.0, 0.0 );
+ else
+ center /= pl;
+
+ angle1 = center.orthogonal( );
+ angle2 = PMVector::cross( center, angle1 );
+
+ PM3DControlPoint* pb = new PM3DControlPoint( m_end1, PMEnd1ID, i18n( "End 1" ) );
+ list.append( pb );
+ list.append( new PM3DControlPoint( m_end2, PMEnd2ID, i18n( "End 2" ) ) );
+ list.append( new PMDistanceControlPoint( pb, angle1, m_radius, PMRadiusID, i18n( "Radius (1)" ) ) );
+ list.append( new PMDistanceControlPoint( pb, angle2, m_radius, PMRadiusID, i18n( "Radius (2)" ) ) );
+}
+
+
+void PMCylinder::controlPointsChanged( PMControlPointList & list )
+{
+ PMControlPoint* p;
+ bool pointChanged = false;
+ bool radiusChanged = false;
+
+ for( p = list.first( ); p; p = list.next( ) )
+ {
+ if( p->changed( ) )
+ {
+ switch( p->id( ) )
+ {
+ case PMEnd1ID:
+ setEnd1( ( ( PM3DControlPoint *) p)->point( ) );
+ pointChanged = true;
+ break;
+ case PMEnd2ID:
+ setEnd2( ( ( PM3DControlPoint *) p)->point( ) );
+ pointChanged = true;
+ break;
+ case PMRadiusID:
+ setRadius( ( ( PMDistanceControlPoint *) p)->distance( ) );
+ radiusChanged = true;
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMCylinder::controlPointsChanged\n";
+ break;
+ }
+ }
+ }
+
+ if( pointChanged )
+ {
+ PMVector center, angle1, angle2;
+ bool firstPoint = true;
+
+ center = m_end1 - m_end2;
+ double pl = center.abs( );
+ if( approxZero( pl ) )
+ center = PMVector( 0.0, 1.0, 0.0 );
+ else
+ center /= pl;
+
+ angle1 = center.orthogonal( );
+ angle2 = PMVector::cross( center, angle1 );
+
+ for( p = list.first( ); p; p = list.next( ) )
+ if( p->id( ) == PMRadiusID )
+ {
+ if( firstPoint )
+ {
+ ( ( PMDistanceControlPoint *) p)->setDirection( angle1 );
+ firstPoint = false;
+ }
+ else
+ ( ( PMDistanceControlPoint *) p)->setDirection( angle2 );
+ }
+ }
+
+ if( radiusChanged )
+ for( p = list.first( ); p; p = list.next( ) )
+ if( p->id( ) == PMRadiusID )
+ ( ( PMDistanceControlPoint *) p)->setDistance( m_radius );
+}
+
+void PMCylinder::setSteps( int s )
+{
+ if( s >= 4 )
+ {
+ s_numSteps = s;
+ if( s_pDefaultViewStructure )
+ {
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ }
+ }
+ else
+ kdDebug( PMArea ) << "PMCylinder::setSteps: S must be greater than 3\n";
+ s_parameterKey++;
+}
+
+void PMCylinder::cleanUp( ) const
+{
+ if( s_pDefaultViewStructure )
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
diff --git a/kpovmodeler/pmcylinder.h b/kpovmodeler/pmcylinder.h
new file mode 100644
index 00000000..ba98ae40
--- /dev/null
+++ b/kpovmodeler/pmcylinder.h
@@ -0,0 +1,176 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Leonardo Skorianez
+ email : lsk@if.ufrj.br
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMCYLINDER_H
+#define PMCYLINDER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobject.h"
+#include "pmvector.h"
+#include "pmviewstructure.h"
+
+/**
+ * Class for povray cylinder
+ */
+
+class PMCylinder : public PMSolidObject
+{
+ typedef PMSolidObject Base;
+public:
+ /**
+ * Creates a cylinder
+ */
+ PMCylinder( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMCylinder( const PMCylinder& c );
+
+ /**
+ * Deletes the cylinder
+ */
+ virtual ~PMCylinder( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMCylinder( *this ); }
+
+ /** */
+ virtual QString description( ) const;
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMCylinderEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmcylinder" ); }
+
+ /**
+ * Return the end_1
+ */
+ PMVector end1( ) const { return m_end1; }
+ /**
+ * Sets end_1
+ */
+ void setEnd1( const PMVector& p );
+ /**
+ * Return the end_2
+ */
+ PMVector end2( ) const { return m_end2; }
+ /**
+ * Sets end_2
+ */
+ void setEnd2( const PMVector& p );
+ /**
+ * return the radius of the cylinder
+ */
+ double radius( ) const { return m_radius; }
+ /**
+ * Sets the radius of the cylinder
+ */
+ void setRadius( double radius );
+ /**
+ * Return open = 1 or close = 0
+ */
+ bool open( ) const { return m_open; }
+ /**
+ * Sets open cylinder
+ */
+ void setOpen( bool op );
+
+ /**
+ * Returns the number of lines for rendering
+ */
+ static int steps( ) { return s_numSteps; }
+ /**
+ * Sets the number of lines for rendering
+ */
+ static void setSteps( int s );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /** */
+ virtual void controlPoints( PMControlPointList& list );
+ /** */
+ virtual void controlPointsChanged( PMControlPointList& list );
+ /** */
+ virtual bool hasDisplayDetail( ) const { return true; }
+ /** */
+ virtual void cleanUp( ) const;
+
+protected:
+ /** */
+ virtual bool isDefault( );
+ /** */
+ virtual void createViewStructure( );
+ /** */
+ virtual PMViewStructure* defaultViewStructure( ) const;
+ /** */
+ virtual int viewStructureParameterKey( ) const { return s_parameterKey + globalDetailKey(); }
+
+private:
+ /**
+ * Creates the lines for the view structure
+ */
+ static void createLines( PMLineArray& lines, int steps );
+ /**
+ * Creates the points for the view structure
+ */
+ static void createPoints( PMPointArray& points, const PMVector& end1,
+ const PMVector& end2, double radius, int steps );
+
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMCylinderMementoID { PMEnd1ID, PMEnd2ID, PMRadiusID, PMOpenID };
+ /**
+ * ends of cylinder
+ */
+ PMVector m_end1, m_end2;
+ /**
+ * radius of cylinder
+ */
+ double m_radius;
+ /**
+ * open
+ */
+ bool m_open;
+ /**
+ * The default view structure. It can be shared between cylinders
+ */
+ static PMViewStructure* s_pDefaultViewStructure;
+ static int s_numSteps;
+ static int s_parameterKey;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmcylinderedit.cpp b/kpovmodeler/pmcylinderedit.cpp
new file mode 100644
index 00000000..623b2b4f
--- /dev/null
+++ b/kpovmodeler/pmcylinderedit.cpp
@@ -0,0 +1,113 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Leonardo Skorianez
+ email : skoriane@nce.ufrj.br
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmcylinderedit.h"
+#include "pmcylinder.h"
+#include "pmvectoredit.h"
+#include "pmlineedits.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <klocale.h>
+#include <qcheckbox.h>
+
+PMCylinderEdit::PMCylinderEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMCylinderEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* layout;
+ QGridLayout* gl;
+
+ m_pEnd1 = new PMVectorEdit( "x", "y", "z", this );
+ m_pEnd2 = new PMVectorEdit( "x", "y", "z", this );
+ m_pRadius = new PMFloatEdit( this );
+ m_pOpen = new QCheckBox( i18n( "type of the object", "Open" ), this );
+
+ gl = new QGridLayout( topLayout( ), 2, 2 );
+ gl->addWidget( new QLabel( i18n( "End 1:" ), this ), 0, 0 );
+ gl->addWidget( m_pEnd1, 0, 1 );
+ gl->addWidget( new QLabel( i18n( "End 2:" ), this ), 1, 0 );
+ gl->addWidget( m_pEnd2, 1, 1 );
+
+ layout = new QHBoxLayout( topLayout( ) );
+ layout->addWidget( new QLabel( i18n( "Radius:" ), this ) );
+ layout->addWidget( m_pRadius );
+ layout->addStretch( 1 );
+
+ layout = new QHBoxLayout( topLayout( ) );
+ layout->addWidget( m_pOpen );
+
+ connect( m_pEnd1, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pEnd2, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pRadius, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pOpen, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMCylinderEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Cylinder" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMCylinder* ) o;
+
+ m_pEnd1->setVector( m_pDisplayedObject->end1( ) );
+ m_pEnd2->setVector( m_pDisplayedObject->end2( ) );
+ m_pRadius->setValue( m_pDisplayedObject->radius( ) );
+ m_pOpen->setChecked( m_pDisplayedObject->open( ) );
+
+ m_pEnd1->setReadOnly( readOnly );
+ m_pEnd2->setReadOnly( readOnly );
+ m_pRadius->setReadOnly( readOnly );
+ m_pOpen->setEnabled( !readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMCylinderEdit: Can't display object\n";
+}
+
+void PMCylinderEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setEnd1( m_pEnd1->vector( ) );
+ m_pDisplayedObject->setEnd2( m_pEnd2->vector( ) );
+ m_pDisplayedObject->setRadius( m_pRadius->value( ) );
+ m_pDisplayedObject->setOpen( m_pOpen->isChecked( ) );
+ }
+}
+
+bool PMCylinderEdit::isDataValid( )
+{
+ if( m_pEnd1->isDataValid( ) )
+ if( m_pEnd2->isDataValid( ) )
+ if( m_pRadius->isDataValid( ) )
+ return Base::isDataValid( );
+ return false;
+}
+
+#include "pmcylinderedit.moc"
+
+
diff --git a/kpovmodeler/pmcylinderedit.h b/kpovmodeler/pmcylinderedit.h
new file mode 100644
index 00000000..aec05df5
--- /dev/null
+++ b/kpovmodeler/pmcylinderedit.h
@@ -0,0 +1,63 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Leonardo Skorinaez
+ email : skoriane@nce.ufrj.br
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMCYLINDEREDIT_H
+#define PMCYLINDEREDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobjectedit.h"
+
+class PMVectorEdit;
+class PMFloatEdit;
+class PMCylinder;
+class QCheckBox;
+
+class PMCylinderEdit : public PMSolidObjectEdit
+{
+ Q_OBJECT
+ typedef PMSolidObjectEdit Base;
+public:
+ /**
+ * Creates a PMCylinderEdit with parent and name
+ */
+ PMCylinderEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMCylinder* m_pDisplayedObject;
+ PMVectorEdit* m_pEnd1;
+ PMVectorEdit* m_pEnd2;
+ PMFloatEdit* m_pRadius;
+ QCheckBox* m_pOpen;
+
+};
+#endif
diff --git a/kpovmodeler/pmdatachangecommand.cpp b/kpovmodeler/pmdatachangecommand.cpp
new file mode 100644
index 00000000..0793986e
--- /dev/null
+++ b/kpovmodeler/pmdatachangecommand.cpp
@@ -0,0 +1,111 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmdatachangecommand.h"
+#include "pmcommandmanager.h"
+#include "pmmemento.h"
+#include "pmobject.h"
+#include <klocale.h>
+
+PMDataChangeCommand::PMDataChangeCommand( PMMemento* memento )
+ : PMCommand( )
+{
+ QString text = memento->originator( )->name( );
+ if( text.isEmpty( ) )
+ text = memento->originator( )->description( );
+ setText( i18n( "Change %1" ).arg( text ) );
+
+ // the data is already changed when the command is created
+ m_executed = true;
+ m_unexecuted = false;
+ m_pOldState = memento;
+ m_pNewState = 0;
+}
+
+PMDataChangeCommand::~PMDataChangeCommand( )
+{
+ if( m_pOldState )
+ delete m_pOldState;
+ if( m_pNewState )
+ delete m_pNewState;
+}
+
+void PMDataChangeCommand::execute( PMCommandManager* theManager )
+{
+ PMObject* obj = m_pOldState->originator( );
+ if( !m_executed )
+ {
+ // if the command is not executed
+ // restore the memento
+ if( m_pNewState )
+ {
+ if( m_pNewState->containsChanges( ) )
+ {
+ obj->restoreMemento( m_pNewState );
+
+ if( m_pOldState->idChanged( ) )
+ theManager->cmdIDChanged( obj, m_pOldState->oldID( ) );
+ signalChanges( theManager, m_pNewState );
+ }
+ }
+ m_executed = true;
+ }
+ else if( !m_unexecuted )
+ {
+ // the data can be changed multiple times
+ // if the command was never unexecuted, emit the signal
+ // ( the data was already changed, so this is not necessary here )
+ if( m_pOldState->idChanged( ) )
+ theManager->cmdIDChanged( obj, m_pOldState->oldID( ) );
+ signalChanges( theManager, m_pOldState );
+ }
+}
+
+void PMDataChangeCommand::undo( PMCommandManager* theManager )
+{
+ if( m_executed )
+ {
+ if( m_pOldState->containsChanges( ) )
+ {
+ PMObject* obj = m_pOldState->originator( );
+ if( !m_pNewState )
+ obj->createMemento( );
+
+ obj->restoreMemento( m_pOldState );
+
+ if( !m_pNewState )
+ m_pNewState = obj->takeMemento( );
+
+ if( m_pNewState->idChanged( ) )
+ theManager->cmdIDChanged( obj, m_pNewState->oldID( ) );
+ signalChanges( theManager, m_pOldState );
+ }
+ m_executed = false;
+ m_unexecuted = true;
+ }
+}
+
+void PMDataChangeCommand::signalChanges( PMCommandManager* theManager,
+ PMMemento* memento )
+{
+ PMObjectChangeListIterator it( memento->changedObjects( ) );
+
+ for( ; it.current( ); ++it )
+ theManager->cmdObjectChanged( it.current( )->object( ),
+ it.current( )->mode( ) );
+}
diff --git a/kpovmodeler/pmdatachangecommand.h b/kpovmodeler/pmdatachangecommand.h
new file mode 100644
index 00000000..878e0f4f
--- /dev/null
+++ b/kpovmodeler/pmdatachangecommand.h
@@ -0,0 +1,68 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMDATACHANGECOMMAND_H
+#define PMDATACHANGECOMMAND_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmcommand.h"
+
+class PMMemento;
+
+/**
+ * Command that stores undo information for object changes
+ *
+ * Let an object create a @ref PMMemento, change the objects data, take the
+ * memento and create a PMDataChangeCommand with this memento.
+ *
+ * Then execute the command. The object will not be changed again!
+ */
+class PMDataChangeCommand : public PMCommand
+{
+public:
+ /**
+ * Creates a PMDataChangeCommand for the memento
+ */
+ PMDataChangeCommand( PMMemento* memento );
+ /**
+ * Deletes the command. The memento will be deleted.
+ */
+ virtual ~PMDataChangeCommand( );
+protected:
+ /**
+ * Executes the command
+ */
+ virtual void execute( PMCommandManager* theManager );
+ /**
+ * Undo the command
+ */
+ virtual void undo( PMCommandManager* theManager );
+
+private:
+ void signalChanges( PMCommandManager* theManager, PMMemento* memento );
+ PMMemento* m_pNewState;
+ PMMemento* m_pOldState;
+ bool m_executed;
+ bool m_unexecuted;
+};
+
+#endif
diff --git a/kpovmodeler/pmdebug.h b/kpovmodeler/pmdebug.h
new file mode 100644
index 00000000..692bcd60
--- /dev/null
+++ b/kpovmodeler/pmdebug.h
@@ -0,0 +1,26 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMDEBUG_H
+#define PMDEBUG_H
+
+#define PMArea 0 // no area for debug messages yet
+
+#include <kdebug.h>
+
+#endif
diff --git a/kpovmodeler/pmdeclare.cpp b/kpovmodeler/pmdeclare.cpp
new file mode 100644
index 00000000..2b698f0e
--- /dev/null
+++ b/kpovmodeler/pmdeclare.cpp
@@ -0,0 +1,238 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmdeclare.h"
+#include "pmdeclareedit.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pmprototypemanager.h"
+#include "pmpart.h"
+
+#include <qvaluelist.h>
+#include <klocale.h>
+
+PMDefinePropertyClass( PMDeclare, PMDeclareProperty );
+
+PMMetaObject* PMDeclare::s_pMetaObject;
+PMObject* createNewDeclare( PMPart* part )
+{
+ return new PMDeclare( part );
+}
+
+PMDeclare::PMDeclare( PMPart* part )
+ : Base( part )
+{
+ m_pDeclareType = 0;
+}
+
+PMDeclare::PMDeclare( const PMDeclare& d )
+ : Base( d )
+{
+ m_id = d.m_id; // CAUTION! Duplication of the id which has to be unique
+ m_pDeclareType = 0; // will be set automatically in the
+ // base constuctor when the children are copied
+}
+
+PMMetaObject* PMDeclare::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Declare", Base::metaObject( ),
+ createNewDeclare );
+ s_pMetaObject->addProperty(
+ new PMDeclareProperty( "id", &PMDeclare::setID, &PMDeclare::id ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMDeclare::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+PMDeclare::~PMDeclare( )
+{
+}
+
+QString PMDeclare::description( ) const
+{
+ PMPart* pPart = part( );
+ QString d = i18n( "declaration" );
+
+ if( m_pDeclareType && pPart )
+ {
+ const QValueList<PMDeclareDescription>& descriptions
+ = pPart->prototypeManager( )->declarationTypes( );
+ QValueList<PMDeclareDescription>::const_iterator it;
+ bool found = false;
+ for( it = descriptions.begin( ); it != descriptions.end( ) && !found; ++it )
+ {
+ if( ( *it ).type == m_pDeclareType )
+ {
+ d = ( *it ).description;
+ found = true;
+ }
+ }
+ }
+ return d;
+}
+
+QString PMDeclare::pixmap( ) const
+{
+ PMPart* pPart = part( );
+ QString d = "pmdeclare";
+
+ if( m_pDeclareType && pPart )
+ {
+ const QValueList<PMDeclareDescription>& descriptions
+ = pPart->prototypeManager( )->declarationTypes( );
+ QValueList<PMDeclareDescription>::const_iterator it;
+ bool found = false;
+ for( it = descriptions.begin( ); it != descriptions.end( ) && !found; ++it )
+ {
+ if( ( *it ).type == m_pDeclareType )
+ {
+ d = ( *it ).pixmap;
+ found = true;
+ }
+ }
+ }
+ return d;
+}
+
+void PMDeclare::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "id", m_id );
+ Base::serialize( e, doc );
+}
+
+void PMDeclare::readAttributes( const PMXMLHelper& h )
+{
+ m_id = h.stringAttribute( "id", "object" );
+ Base::readAttributes( h );
+}
+
+PMDialogEditBase* PMDeclare::editWidget( QWidget* parent ) const
+{
+ return new PMDeclareEdit( parent );
+}
+
+void PMDeclare::setID( const QString& newID )
+{
+ if( newID != m_id )
+ {
+ if( m_pMemento )
+ {
+ m_pMemento->addIDChange( s_pMetaObject, PMIDID, m_id );
+ m_pMemento->setDescriptionChanged( );
+ }
+
+ m_id = newID;
+ }
+}
+
+QString PMDeclare::declareType( ) const
+{
+ if( !m_pDeclareType )
+ return QString( "None" );
+ return m_pDeclareType->className( );
+}
+
+void PMDeclare::setDeclareType( PMMetaObject* t )
+{
+ if( m_pDeclareType != t )
+ {
+ if( m_pMemento )
+ m_pMemento->setDescriptionChanged( );
+
+ m_pDeclareType = t;
+ }
+}
+
+void PMDeclare::updateDeclareType( )
+{
+ PMPart* pPart = part( );
+ if( !pPart )
+ return;
+
+ PMMetaObject* type = 0;
+ PMObject* o = firstChild( );
+ PMPrototypeManager* m = pPart->prototypeManager( );
+ if( o )
+ {
+ if( o->isA( "GraphicalObject" ) )
+ type = m->metaObject( "GraphicalObject" );
+ else
+ type = o->metaObject( );
+ }
+ setDeclareType( type );
+}
+
+void PMDeclare::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMIDID:
+ setID( data->stringData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMDeclare::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
+void PMDeclare::addLinkedObject( PMObject* o )
+{
+ m_linkedObjects.append( o );
+}
+
+void PMDeclare::removeLinkedObject( PMObject* o )
+{
+ m_linkedObjects.removeRef( o );
+}
+
+void PMDeclare::childAdded( PMObject* o )
+{
+ if( !m_pDeclareType )
+ updateDeclareType( );
+
+ Base::childAdded( o );
+}
+
+void PMDeclare::childRemoved( PMObject* o )
+{
+ if( !firstChild( ) )
+ setDeclareType( 0 );
+
+ Base::childRemoved( o );
+}
diff --git a/kpovmodeler/pmdeclare.h b/kpovmodeler/pmdeclare.h
new file mode 100644
index 00000000..d466e60e
--- /dev/null
+++ b/kpovmodeler/pmdeclare.h
@@ -0,0 +1,147 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMDECLARE_H
+#define PMDECLARE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmcompositeobject.h"
+#include "pmsymboltable.h"
+
+/**
+ * Class for all povray declares
+ */
+class PMDeclare : public PMCompositeObject
+{
+ typedef PMCompositeObject Base;
+public:
+ /**
+ * Constructor
+ */
+ PMDeclare( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMDeclare( const PMDeclare& d );
+ /**
+ * Deletes the object
+ */
+ ~PMDeclare( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMDeclare( *this ); }
+
+ /** */
+ virtual QString description( ) const;
+ /** */
+ virtual QString pixmap( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual bool dataChangeOnInsertRemove( ) const { return true; }
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMDeclareEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the id of the declare
+ */
+ virtual QString name( ) const { return m_id; }
+ /**
+ * Returns the id of the declare
+ */
+ QString id( ) const { return m_id; }
+ /**
+ * Returns the declare type
+ */
+ QString declareType( ) const;
+
+ /**
+ * Sets the id of the object.
+ */
+ void setID( const QString& id );
+ /** */
+ virtual bool canHaveName( ) const { return true; }
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /**
+ * Returns an iterator to the list of objects, that are linked to that
+ * declare
+ */
+ PMObjectListIterator linkedObjects( ) const
+ {
+ return PMObjectListIterator( m_linkedObjects );
+ }
+ /**
+ * Adds the object to the list of linked objects
+ */
+ void addLinkedObject( PMObject* o );
+ /**
+ * Removes the object from the list of linked objects
+ */
+ void removeLinkedObject( PMObject* o );
+
+ /** */
+ virtual void childAdded( PMObject* o );
+ /** */
+ virtual void childRemoved( PMObject* o );
+
+private:
+ /**
+ * Sets the declare type
+ */
+ void setDeclareType( PMMetaObject* o );
+ /**
+ * Recalculates the declaration type
+ */
+ void updateDeclareType( );
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMDeclareMementoID { PMIDID };
+
+ /**
+ * id of the declare
+ */
+ QString m_id;
+ /**
+ * The linked objects
+ */
+ PMObjectList m_linkedObjects;
+ /**
+ * The declare type
+ */
+ PMMetaObject* m_pDeclareType;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmdeclareedit.cpp b/kpovmodeler/pmdeclareedit.cpp
new file mode 100644
index 00000000..5f9e9c67
--- /dev/null
+++ b/kpovmodeler/pmdeclareedit.cpp
@@ -0,0 +1,206 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmdeclareedit.h"
+#include "pmdeclare.h"
+#include "pmpart.h"
+#include "pmsymboltable.h"
+#include "pmscanner.h"
+#include "pmobjectselect.h"
+
+#include <qlayout.h>
+#include <qlineedit.h>
+#include <qlabel.h>
+#include <qtextstream.h>
+#include <qpushbutton.h>
+#include <qlistbox.h>
+
+#include <klocale.h>
+#include <kmessagebox.h>
+
+PMDeclareEdit::PMDeclareEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+ m_pSelectedObject = 0;
+}
+
+void PMDeclareEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* layout = new QHBoxLayout( topLayout( ) );
+ m_pNameEdit = new QLineEdit( this );
+ m_pNameEdit->setMaxLength( 40 );
+ QLabel* label = new QLabel( i18n( "Identifier:" ), this );
+
+ layout->addWidget( label );
+ layout->addWidget( m_pNameEdit );
+
+ connect( m_pNameEdit, SIGNAL( textChanged( const QString& ) ),
+ SLOT( slotNameChanged( const QString& ) ) );
+}
+
+void PMDeclareEdit::createBottomWidgets( )
+{
+ QLabel* l = new QLabel( i18n( "Linked objects:" ), this );
+ topLayout( )->addWidget( l );
+
+ m_pLinkedObjects = new QListBox( this );
+ m_pLinkedObjects->setMinimumHeight( 100 );
+ connect( m_pLinkedObjects, SIGNAL( highlighted( QListBoxItem* ) ),
+ SLOT( slotItemSelected( QListBoxItem* ) ) );
+ topLayout( )->addWidget( m_pLinkedObjects, 1 );
+
+ QHBoxLayout* layout = new QHBoxLayout( topLayout( ) );
+ m_pSelectButton = new QPushButton( i18n( "Select..." ), this );
+ m_pSelectButton->setEnabled( false );
+
+ connect( m_pSelectButton, SIGNAL( clicked( ) ), SLOT( slotSelect( ) ) );
+ layout->addStretch( );
+ layout->addWidget( m_pSelectButton );
+
+ Base::createBottomWidgets( );
+}
+
+void PMDeclareEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Declare" ) )
+ {
+ m_pDisplayedObject = ( PMDeclare* ) o;
+ m_pNameEdit->setText( QString( m_pDisplayedObject->id( ) ) );
+
+ m_pNameEdit->setReadOnly( m_pDisplayedObject->isReadOnly( ) );
+
+ PMObjectListIterator it( m_pDisplayedObject->linkedObjects( ) );
+ m_pLinkedObjects->clear( );
+
+ for( ; it.current( ); ++it )
+ m_pLinkedObjects->insertItem(
+ new PMListBoxObject( it.current( ) ) );
+
+ m_pSelectButton->setEnabled( false );
+ m_pSelectedObject = 0;
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMDeclareEdit: Can't display object\n";
+}
+
+void PMDeclareEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setID( m_pNameEdit->text( ) );
+ }
+}
+
+bool PMDeclareEdit::isDataValid( )
+{
+ if( !Base::isDataValid( ) )
+ return false;
+
+ QString text = m_pNameEdit->text( );
+ if( text.length( ) == 0 )
+ {
+ KMessageBox::error( this, i18n( "Please enter an identifier!" ),
+ i18n( "Error" ) );
+ return false;
+ }
+
+ if( text == m_pDisplayedObject->id( ) )
+ return true;
+
+ QTextStream str( &text, IO_ReadOnly );
+ QChar c;
+ int ac;
+ bool ok = true;
+ int i = 0;
+ while( !str.atEnd( ) && ok )
+ {
+ str >> c;
+ ac = c.latin1( );
+ // QChar::category can't be used because umlauts are not allowed
+ if( i == 0 )
+ ok = ( ( ( ac >= 'a' ) && ( ac <= 'z' ) ) ||
+ ( ( ac >= 'A' ) && ( ac <= 'Z' ) ) ||
+ ( ac == '_' ) );
+ else
+ ok = ( ( ( ac >= 'a' ) && ( ac <= 'z' ) ) ||
+ ( ( ac >= 'A' ) && ( ac <= 'Z' ) ) ||
+ ( ( ac >= '0' ) && ( ac <= '9' ) ) ||
+ ( ac == '_' ) );
+ i++;
+ }
+ if( !ok )
+ {
+ KMessageBox::error( this, i18n( "An identifier may consist of letters,"
+ " digits and the underscore character"
+ " ('_').\n"
+ "The first character must be a letter"
+ " or the underscore character!" ),
+ i18n( "Error" ) );
+ return false;
+ }
+ // valid identifer!
+
+ PMReservedWordDict* dict = PMScanner::reservedWords( );
+ if( dict->find( text.latin1( ) ) != -1 )
+ {
+ KMessageBox::error( this, i18n( "You can't use a povray reserved word"
+ " as an identifier!" ), i18n( "Error" ) );
+ return false;
+ }
+ dict = PMScanner::directives( );
+ if( dict->find( text.latin1( ) ) != -1 )
+ {
+ KMessageBox::error( this, i18n( "You can't use a povray directive"
+ " as an identifier!" ), i18n( "Error" ) );
+ return false;
+ }
+
+ // no reserved word
+ PMSymbolTable* st = part( )->symbolTable( );
+ if( st->find( text ) )
+ {
+ KMessageBox::error( this, i18n( "Please enter a unique identifier!" ),
+ i18n( "Error" ) );
+ return false;
+ }
+ return true;
+}
+
+void PMDeclareEdit::slotNameChanged( const QString& )
+{
+ emit dataChanged( );
+}
+
+void PMDeclareEdit::slotItemSelected( QListBoxItem* item )
+{
+ m_pSelectedObject = ( ( PMListBoxObject* ) item )->object( );
+ m_pSelectButton->setEnabled( true );
+}
+
+void PMDeclareEdit::slotSelect( )
+{
+ if( m_pSelectedObject )
+ part( )->slotObjectChanged( m_pSelectedObject, PMCNewSelection, this );
+}
+#include "pmdeclareedit.moc"
diff --git a/kpovmodeler/pmdeclareedit.h b/kpovmodeler/pmdeclareedit.h
new file mode 100644
index 00000000..9ee2fc83
--- /dev/null
+++ b/kpovmodeler/pmdeclareedit.h
@@ -0,0 +1,74 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMDECLAREEDIT_H
+#define PMDECLAREEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdialogeditbase.h"
+
+class PMDeclare;
+class QLineEdit;
+class QListBox;
+class QPushButton;
+class QListBoxItem;
+
+/**
+ * Dialog edit class for @ref PMDeclare.
+ */
+class PMDeclareEdit : public PMDialogEditBase
+{
+ Q_OBJECT
+ typedef PMDialogEditBase Base;
+public:
+ /**
+ * Creates a PMDeclareEdit with parent and name
+ */
+ PMDeclareEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void createBottomWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private slots:
+ void slotNameChanged( const QString& );
+ void slotItemSelected( QListBoxItem* );
+ void slotSelect( );
+private:
+ PMDeclare* m_pDisplayedObject;
+ QLineEdit* m_pNameEdit;
+ QListBox* m_pLinkedObjects;
+ QPushButton* m_pSelectButton;
+ PMObject* m_pSelectedObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmdefaults.h b/kpovmodeler/pmdefaults.h
new file mode 100644
index 00000000..32c9675c
--- /dev/null
+++ b/kpovmodeler/pmdefaults.h
@@ -0,0 +1,131 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMDEFAULTS_H
+#define PMDEFAULTS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qcolor.h>
+#include <math.h>
+
+// PMRenderManager
+const QColor c_defaultGraphicalObjectColor0 = QColor( 148, 148, 148 );
+const QColor c_defaultGraphicalObjectColor1 = QColor( 255, 255, 128 );
+const QColor c_defaultTextureColor0 = QColor( 64, 192, 64 );
+const QColor c_defaultTextureColor1 = QColor( 192, 255, 128 );
+const QColor c_defaultAxesColorX = QColor( 255, 0, 0 );
+const QColor c_defaultAxesColorY = QColor( 0, 255, 0 );
+const QColor c_defaultAxesColorZ = QColor( 0, 0, 255 );
+const QColor c_defaultControlPointColor0 = QColor( 255, 255, 148 );
+const QColor c_defaultControlPointColor1 = QColor( 92, 255, 92 );
+const QColor c_defaultBackgroundColor = QColor( 0, 0, 0 );
+const QColor c_defaultFieldOfViewColor = QColor( 128, 128, 255 );
+const bool c_defaultHighDetailCameraView = true;
+
+// PMGLView
+const int c_defaultGridDistance = 50;
+const QColor c_defaultGridColor = QColor( 40, 120, 40 );
+
+// PovrayRenderWidget
+const QString c_defaultPovrayCommand = QString( "povray" );
+
+// PMDetailObject
+const int c_defaultDetailObjectGlobalDetailLevel = 1;
+
+// PMSphere
+const int c_defaultSphereUSteps = 8;
+const int c_defaultSphereVSteps = 16;
+
+// PMBlobSphere
+const int c_defaultBlobSphereUSteps = 8;
+const int c_defaultBlobSphereVSteps = 16;
+
+// PMBlobCylinder
+const int c_defaultBlobCylinderUSteps = 4;
+const int c_defaultBlobCylinderVSteps = 16;
+
+// PMCylinder
+const int c_defaultCylinderSteps = 16;
+
+// PMCone
+const int c_defaultConeSteps = 16;
+
+// PMTorus
+const int c_defaultTorusVSteps = 16;
+const int c_defaultTorusUSteps = 9;
+
+// PMPlane
+const double c_defaultPlaneSize = 2.0;
+
+// PMDisc
+const int c_defaultDiscSteps = 16;
+
+// PMText
+const int c_defaultTextSteps = 3;
+
+// PMLathe
+const int c_defaultLatheRSteps = 16;
+const int c_defaultLatheSSteps = 4;
+
+// PMPrism
+const int c_defaultPrismSSteps = 4;
+
+// PMSurfaceOfRevolution
+const int c_defaultSurfaceOfRevolutionRSteps = 16;
+const int c_defaultSurfaceOfRevolutionSSteps = 4;
+
+// PMSuperquadricEllipsoid
+const int c_defaultSuperquadricEllipsoidUSteps = 3;
+const int c_defaultSuperquadricEllipsoidVSteps = 3;
+
+// PMSphereSweep
+const int c_defaultSphereSweepRSteps = 8;
+const int c_defaultSphereSweepSSteps = 4;
+
+// PMHeightField
+const int c_defaultHeightFieldVariance = 16;
+
+// PMDialogEditBase, texture preview
+const int c_defaultTPSize = 160;
+const bool c_defaultTPShowSphere = true;
+const bool c_defaultTPShowCylinder = false;
+const bool c_defaultTPShowBox = true;
+const bool c_defaultTPAA = false;
+const int c_defaultTPAADepth = 2;
+const double c_defaultTPAAThreshold = 0.3;
+const bool c_defaultTPShowFloor = true;
+const bool c_defaultTPShowWall = true;
+const QColor c_defaultTPWallColor1 = QColor( 255, 255, 255 );
+const QColor c_defaultTPWallColor2 = QColor( 0, 0, 0 );
+const QColor c_defaultTPFloorColor1 = QColor( 192, 0, 0 );
+const QColor c_defaultTPFloorColor2 = QColor( 255, 255, 255 );
+const double c_defaultTPGamma = 1.5;
+
+// PM3DControlPoint
+const double c_defaultMoveGrid = 0.1;
+const double c_defaultScaleGrid = 0.1;
+const double c_defaultRotateGrid = 1.0;
+
+// PMShell
+const bool c_defaultTreeViewTabbed = false;
+const bool c_defaultTreeViewRight = false;
+const bool c_defaultTreeViewBelow = false;
+
+#endif
diff --git a/kpovmodeler/pmdeletecommand.cpp b/kpovmodeler/pmdeletecommand.cpp
new file mode 100644
index 00000000..fa5ff47b
--- /dev/null
+++ b/kpovmodeler/pmdeletecommand.cpp
@@ -0,0 +1,281 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmdeletecommand.h"
+#include "pmcommandmanager.h"
+#include "pmdeclare.h"
+#include "pmrecursiveobjectiterator.h"
+#include "pmmemento.h"
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <qptrdict.h>
+
+PMDeleteCommand::PMDeleteCommand( PMObject* obj )
+ : PMCommand( i18n( "Delete %1" ).arg( obj->name( ) ) )
+{
+ // the scene can not be deleted!
+ if( obj->parent( ) )
+ m_infoList.append( new PMDeleteInfo( obj ) );
+ else
+ {
+ // object has no parent!
+ // top level objects can't be moved, move all child items
+ PMObject* tmp;
+ for( tmp = obj->firstChild( ); tmp; tmp = tmp->nextSibling( ) )
+ m_infoList.append( new PMDeleteInfo( tmp ) );
+ }
+ m_executed = false;
+ m_firstExecution = true;
+ m_linksCreated = false;
+}
+
+PMDeleteCommand::PMDeleteCommand( const PMObjectList& list )
+ : PMCommand( i18n( "Delete Objects" ) )
+{
+ PMObjectListIterator it( list );
+ PMObject* obj;
+
+ for( ; it.current( ); ++it )
+ {
+ obj = it.current( );
+
+ if( obj->parent( ) )
+ m_infoList.append( new PMDeleteInfo( obj ) );
+ else
+ {
+ // object has no parent!
+ // top level objects can't be moved, move all child items
+ PMObject* tmp;
+ for( tmp = obj->firstChild( ); tmp; tmp = tmp->nextSibling( ) )
+ m_infoList.append( new PMDeleteInfo( tmp ) );
+ }
+ }
+
+ m_infoList.setAutoDelete( true );
+ m_executed = false;
+ m_firstExecution = true;
+ m_linksCreated = false;
+}
+
+PMDeleteCommand::~PMDeleteCommand( )
+{
+ if( m_executed )
+ {
+ PMDeleteInfoListIterator it( m_infoList );
+ for( ; it.current( ); ++it )
+ delete ( it.current( )->deletedObject( ) );
+ }
+
+ m_infoList.clear( );
+}
+
+void PMDeleteCommand::execute( PMCommandManager* theManager )
+{
+ if( !m_executed )
+ {
+ PMDeleteInfoListIterator it( m_infoList );
+ PMDeleteInfo* info = 0;
+ PMObject* parent;
+
+ if( !m_linksCreated )
+ {
+ PMDeclare* decl;
+ for( ; it.current( ); ++it )
+ {
+ PMRecursiveObjectIterator oit( it.current( )->deletedObject( ) );
+ for( ; oit.current( ); ++oit )
+ {
+ decl = oit.current( )->linkedObject( );
+ if( decl )
+ {
+ m_links.append( oit.current( ) );
+ if( !m_linkedDeclares.containsRef( decl ) )
+ m_linkedDeclares.append( decl );
+ }
+ }
+ }
+ m_linksCreated = true;
+ }
+
+ PMObjectListIterator lit( m_links );
+ for( ; lit.current( ); ++lit )
+ lit.current( )->linkedObject( )->removeLinkedObject( lit.current( ) );
+
+ for( it.toLast( ); it.current( ); --it )
+ {
+ info = it.current( );
+ parent = info->parent( );
+ // signal has to be emitted before the item is removed
+ theManager->cmdObjectChanged( info->deletedObject( ), PMCRemove );
+ if( m_firstExecution )
+ if( parent->dataChangeOnInsertRemove( )
+ && !parent->mementoCreated( ) )
+ parent->createMemento( );
+ parent->takeChild( info->deletedObject( ) );
+ }
+
+ if( m_firstExecution )
+ {
+ for( it.toLast( ); it.current( ); --it )
+ {
+ parent = it.current( )->parent( );
+ if( parent->mementoCreated( ) )
+ m_dataChanges.append( parent->takeMemento( ) );
+ }
+ }
+
+ QPtrListIterator<PMMemento> mit( m_dataChanges );
+ for( ; mit.current( ); ++mit )
+ {
+ PMObjectChangeListIterator change = mit.current( )->changedObjects( );
+ for( ; change.current( ); ++change )
+ theManager->cmdObjectChanged( change.current( )->object( ),
+ change.current( )->mode( ) );
+ }
+
+ PMObjectListIterator dit( m_linkedDeclares );
+ for( ; dit.current( ); ++dit )
+ theManager->cmdObjectChanged( dit.current( ), PMCData );
+
+ m_executed = true;
+ m_firstExecution = false;
+ }
+}
+
+void PMDeleteCommand::undo( PMCommandManager* theManager )
+{
+ if( m_executed )
+ {
+ PMDeleteInfoListIterator it( m_infoList );
+ for( ; it.current( ); ++it )
+ {
+ if( it.current( )->prevSibling( ) )
+ it.current( )->parent( )
+ ->insertChildAfter( it.current( )->deletedObject( ),
+ it.current( )->prevSibling( ) );
+ else
+ it.current( )->parent( )
+ ->insertChild( it.current( )->deletedObject( ), 0 );
+ theManager->cmdObjectChanged( it.current( )->deletedObject( ), PMCAdd );
+ }
+
+ PMObjectListIterator lit( m_links );
+ for( ; lit.current( ); ++lit )
+ lit.current( )->linkedObject( )->addLinkedObject( lit.current( ) );
+ PMObjectListIterator dit( m_linkedDeclares );
+ for( ; dit.current( ); ++dit )
+ theManager->cmdObjectChanged( dit.current( ), PMCData );
+
+ QPtrListIterator<PMMemento> mit( m_dataChanges );
+ for( ; mit.current( ); ++mit )
+ {
+ mit.current( )->originator( )->restoreMemento( mit.current( ) );
+ PMObjectChangeListIterator change = mit.current( )->changedObjects( );
+ for( ; change.current( ); ++change )
+ theManager->cmdObjectChanged( change.current( )->object( ),
+ change.current( )->mode( ) );
+ }
+
+ m_executed = false;
+ }
+}
+
+int PMDeleteCommand::errorFlags( PMPart* )
+{
+ PMDeleteInfo* info;
+ PMDeclare* decl = 0;
+ PMObject* obj;
+ bool insideSelection;
+ bool ok = true;
+ bool error = false;
+
+ // dictionary of deleted objects
+ QPtrDict<bool> m_deletedObjects( 1009 );
+ m_deletedObjects.setAutoDelete( true );
+ PMDeleteInfoListIterator it( m_infoList );
+ for( ; it.current( ); ++it )
+ m_deletedObjects.insert( it.current( )->deletedObject( ),
+ new bool( true ) );
+
+ // declares can only be deleted, if all linked
+ // objects are deleted as well
+
+ info = m_infoList.last( );
+
+ while( info )
+ {
+ ok = true;
+ if( info->deletedObject( )->isA( "Declare" ) )
+ {
+ decl = ( PMDeclare* ) ( info->deletedObject( ) );
+ PMObjectListIterator links = decl->linkedObjects( );
+
+ for( ; links.current( ) && ok; ++links )
+ {
+ insideSelection = false;
+ for( obj = links.current( ); obj && !insideSelection;
+ obj = obj->parent( ) )
+ {
+ if( m_deletedObjects.find( obj ) )
+ insideSelection = true;
+ }
+
+ if( insideSelection )
+ {
+ bool stop = false;
+ for( obj = links.current( ); obj && !stop; obj = obj->parent( ) )
+ {
+ if( m_deletedObjects.find( obj ) )
+ stop = true;
+ else
+ m_deletedObjects.insert( obj, new bool( true ) );
+ }
+ }
+ else
+ ok = false;
+ }
+ }
+
+ if( !ok )
+ {
+ m_errors.prepend( i18n( "The declare \"%1\" can't be removed "
+ "because of some remaining links." )
+ .arg( decl->id( ) ) );
+
+ PMDeleteInfo* tmp = info;
+ info = m_infoList.prev( );
+ m_deletedObjects.remove( decl );
+ m_infoList.removeRef( tmp );
+
+ error = true;
+ }
+ else
+ info = m_infoList.prev( );
+ }
+
+ if( error )
+ {
+ if( m_infoList.count( ) == 0 )
+ return PMEError | PMEFatal;
+ else
+ return PMEError;
+ }
+
+ return PMENone;
+}
diff --git a/kpovmodeler/pmdeletecommand.h b/kpovmodeler/pmdeletecommand.h
new file mode 100644
index 00000000..ff67c0bc
--- /dev/null
+++ b/kpovmodeler/pmdeletecommand.h
@@ -0,0 +1,126 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMDELETECOMMAND_H
+#define PMDELETECOMMAND_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmcommand.h"
+#include <qstring.h>
+
+#include "pmobject.h"
+
+class PMMemento;
+
+/**
+ * Class that stores undo information for the @ref PMDeleteCommand
+ */
+class PMDeleteInfo
+{
+public:
+ /**
+ * Creates undo information for the object deletedObject.
+ * The object has to have a parent!
+ */
+ PMDeleteInfo( PMObject* deletedObject )
+ {
+ m_pDeletedObject = deletedObject;
+ m_pParent = deletedObject->parent( );
+ m_pPrevSibling = deletedObject->prevSibling( );
+ m_insertError = false;
+ }
+ /**
+ * Deletes the object. The object deletedObject will not be deleted!
+ */
+ ~PMDeleteInfo( ) { };
+ /**
+ * Returns a pointer to the deleted object
+ */
+ PMObject* deletedObject( ) const { return m_pDeletedObject; }
+ /**
+ * Returns a pointer to the parent of the deleted object
+ */
+ PMObject* parent( ) const { return m_pParent; }
+ /**
+ * Returns the previous sibling of the deleted object
+ */
+ PMObject* prevSibling( ) const { return m_pPrevSibling; }
+ /**
+ * Returns true if this object could not be inserted in a move command
+ */
+ bool insertError( ) const { return m_insertError; }
+ /**
+ * Sets the insert error flag
+ */
+ void setInsertError( ) { m_insertError = true; }
+private:
+ PMObject* m_pDeletedObject;
+ PMObject* m_pParent;
+ PMObject* m_pPrevSibling;
+ bool m_insertError;
+};
+
+typedef QPtrList<PMDeleteInfo> PMDeleteInfoList;
+typedef QPtrListIterator<PMDeleteInfo> PMDeleteInfoListIterator;
+
+/**
+ * Command class for removing PMObjects
+ */
+class PMDeleteCommand : public PMCommand
+{
+public:
+ /**
+ * Delete Command that removes the object obj.
+ */
+ PMDeleteCommand( PMObject* obj );
+ /**
+ * Command that deletes a list of PMObjects. The list has to be sorted!
+ */
+ PMDeleteCommand( const PMObjectList& list );
+ /**
+ * Deletes the command. The deleted object will be deleted, if removed
+ */
+ virtual ~PMDeleteCommand( );
+
+ /** */
+ virtual int errorFlags( PMPart* );
+
+protected:
+ /**
+ * Executes the command and stores undo information
+ */
+ virtual void execute( PMCommandManager* theManager );
+ /**
+ * Undo the command
+ */
+ virtual void undo( PMCommandManager* theManager );
+
+private:
+ PMDeleteInfoList m_infoList;
+ bool m_executed, m_firstExecution;
+ PMObjectList m_links;
+ PMObjectList m_linkedDeclares;
+ bool m_linksCreated;
+ QPtrList<PMMemento> m_dataChanges;
+};
+
+#endif
diff --git a/kpovmodeler/pmdensity.cpp b/kpovmodeler/pmdensity.cpp
new file mode 100644
index 00000000..1cc1d638
--- /dev/null
+++ b/kpovmodeler/pmdensity.cpp
@@ -0,0 +1,76 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.tp
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmdensity.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pmdensityedit.h"
+
+#include <klocale.h>
+
+PMMetaObject* PMDensity::s_pMetaObject = 0;
+PMObject* createNewDensity( PMPart* part )
+{
+ return new PMDensity( part );
+}
+
+PMDensity::PMDensity( PMPart* part )
+ : Base( part )
+{
+}
+
+PMDensity::PMDensity( const PMDensity& d )
+ : Base( d )
+{
+}
+
+PMDensity::~PMDensity( )
+{
+}
+
+PMMetaObject* PMDensity::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Density", Base::metaObject( ),
+ createNewDensity );
+ }
+ return s_pMetaObject;
+}
+
+void PMDensity::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMDensity::description( ) const
+{
+ return i18n( "density" );
+}
+
+
+PMDialogEditBase* PMDensity::editWidget( QWidget* parent ) const
+{
+ return new PMDensityEdit( parent );
+}
+
diff --git a/kpovmodeler/pmdensity.h b/kpovmodeler/pmdensity.h
new file mode 100644
index 00000000..72a76bb7
--- /dev/null
+++ b/kpovmodeler/pmdensity.h
@@ -0,0 +1,76 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMDENSITY_H
+#define PMDENSITY_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebase.h"
+
+/**
+ * Class for povray densities
+ */
+class PMDensity : public PMTextureBase
+{
+ typedef PMTextureBase Base;
+public:
+ /**
+ * Creates an PMDensity
+ */
+ PMDensity( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMDensity( const PMDensity& d );
+ /**
+ * Deletes the object
+ */
+ virtual ~PMDensity( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMDensity( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /**
+ * Returns a new @ref PMDensityEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmdensity" ); }
+
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+// enum PMDensityMementoID { };
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmdensityedit.cpp b/kpovmodeler/pmdensityedit.cpp
new file mode 100644
index 00000000..9c7ff732
--- /dev/null
+++ b/kpovmodeler/pmdensityedit.cpp
@@ -0,0 +1,44 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmdensityedit.h"
+#include "pmdensity.h"
+#include "pmlinkedit.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <klocale.h>
+
+
+PMDensityEdit::PMDensityEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMDensityEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Density" ) )
+ {
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMDensityEdit: Can't display object\n";
+}
+
+#include "pmdensityedit.moc"
diff --git a/kpovmodeler/pmdensityedit.h b/kpovmodeler/pmdensityedit.h
new file mode 100644
index 00000000..093a750c
--- /dev/null
+++ b/kpovmodeler/pmdensityedit.h
@@ -0,0 +1,58 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMDENSITYEDIT_H
+#define PMDENSITYEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebaseedit.h"
+
+class PMDensity;
+
+/**
+ * Dialog edit class for @ref PMDensity
+ */
+class PMDensityEdit : public PMTextureBaseEdit
+{
+ Q_OBJECT
+ typedef PMTextureBaseEdit Base;
+public:
+ /**
+ * Creates a PMDensityEdit with parent and name
+ */
+ PMDensityEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+protected:
+ /** */
+// virtual void createTopWidgets( );
+ /** */
+// virtual void saveContents( );
+
+private:
+ PMDensity* m_pDisplayedObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmdetailobject.cpp b/kpovmodeler/pmdetailobject.cpp
new file mode 100644
index 00000000..eae526cb
--- /dev/null
+++ b/kpovmodeler/pmdetailobject.cpp
@@ -0,0 +1,151 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2004 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+#include "pmdetailobject.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pmdefaults.h"
+
+/** Default local detail value*/
+const bool c_defaulGlobalDetail = true;
+const int c_defaultLocalDetailLevel = 1;
+
+/** Static global detail */
+int PMDetailObject::s_globalDetailLevel = c_defaultDetailObjectGlobalDetailLevel;
+int PMDetailObject::s_globalDetailKey = 0;
+
+PMMetaObject* PMDetailObject::s_pMetaObject = 0;
+
+PMDefinePropertyClass( PMDetailObject, PMDetailObjectProperty );
+
+PMDetailObject::PMDetailObject( PMPart *part ) : Base( part )
+{
+ m_globalDetail = c_defaulGlobalDetail;
+ m_localDetailLevel = c_defaultLocalDetailLevel;
+}
+
+PMDetailObject::PMDetailObject( const PMDetailObject& o ) : Base( o )
+{
+ m_globalDetail = o.m_globalDetail;
+ m_localDetailLevel = o.m_localDetailLevel;
+}
+
+PMDetailObject::~PMDetailObject()
+{
+}
+
+PMMetaObject* PMDetailObject::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "DetailObject", Base::metaObject( ) );
+ s_pMetaObject->addProperty(
+ new PMDetailObjectProperty( "globalDetail", &PMDetailObject::setGlobalDetail, &PMDetailObject::globalDetail ) );
+ s_pMetaObject->addProperty(
+ new PMDetailObjectProperty( "localDetailLevel", &PMDetailObject::setLocalDetailLevel, &PMDetailObject::localDetailLevel ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMDetailObject::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMDetailObject::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "global_detail", m_globalDetail );
+ e.setAttribute( "local_detail_level", m_localDetailLevel );
+ Base::serialize( e, doc );
+}
+
+void PMDetailObject::readAttributes( const PMXMLHelper& h )
+{
+ m_globalDetail = h.boolAttribute( "global_detail", c_defaulGlobalDetail );
+ m_localDetailLevel = h.intAttribute( "local_detail_level", c_defaultLocalDetailLevel );
+ Base::readAttributes( h );
+}
+
+int PMDetailObject::displayDetail( ) const
+{
+ if( m_globalDetail )
+ return s_globalDetailLevel;
+ else
+ return m_localDetailLevel;
+}
+
+void PMDetailObject::setGlobalDetail( bool yes )
+{
+ if( m_globalDetail != yes )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMGlobalDetailID, m_globalDetail );
+ m_globalDetail = yes;
+ setViewStructureChanged( );
+ }
+}
+
+void PMDetailObject::setLocalDetailLevel( int level )
+{
+ if( m_localDetailLevel != level )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMLocalDetailLevelID, m_localDetailLevel );
+ m_localDetailLevel = level;
+ setViewStructureChanged( );
+ }
+}
+
+void PMDetailObject::setGlobalDetailLevel( int level )
+{
+ if( s_globalDetailLevel != level )
+ {
+ ++s_globalDetailKey;
+ s_globalDetailLevel = level;
+ }
+}
+
+void PMDetailObject::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMGlobalDetailID:
+ setGlobalDetail( data->boolData( ) );
+ break;
+ case PMLocalDetailLevelID:
+ setLocalDetailLevel( data->intData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMDetailObject::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmdetailobject.h b/kpovmodeler/pmdetailobject.h
new file mode 100644
index 00000000..7994cdff
--- /dev/null
+++ b/kpovmodeler/pmdetailobject.h
@@ -0,0 +1,115 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2004 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#ifndef PMDETAILOBJECT_H
+#define PMDETAILOBJECT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmnamedobject.h"
+
+class PMDetailObject : public PMNamedObject
+{
+ typedef PMNamedObject Base;
+public:
+ /**
+ * Creates an empty PMDetailObject
+ */
+ PMDetailObject( PMPart* part );
+ /**
+ * Copy constrctor
+ */
+ PMDetailObject( const PMDetailObject& o );
+ /**
+ * Deletes the object
+ */
+ virtual ~PMDetailObject();
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns true if the object has detail settings
+ */
+ virtual bool hasDisplayDetail( ) const { return false; }
+
+ /**
+ * Returns the current display detail
+ */
+ int displayDetail( ) const;
+
+ /**
+ * Sets the global detail flag
+ */
+ void setGlobalDetail( bool yes );
+ /**
+ * Returns the global detail flag
+ */
+ bool globalDetail( ) const { return m_globalDetail; }
+
+ /**
+ * Sets the local detail level
+ */
+ void setLocalDetailLevel( int level );
+ /**
+ * Returns the local detail level
+ */
+ int localDetailLevel( ) const { return m_localDetailLevel; }
+
+ /**
+ * Sets the global detail level
+ */
+ static void setGlobalDetailLevel( int level );
+ /**
+ * Returns the global detail level
+ */
+ static int globalDetailLevel( ) { return s_globalDetailLevel; }
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+
+protected:
+ /**
+ * Global parameter key
+ */
+ static int globalDetailKey( ) { return s_globalDetailKey; }
+
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMNamedObjectMementoID { PMGlobalDetailID, PMLocalDetailLevelID };
+
+ bool m_globalDetail;
+ int m_localDetailLevel;
+
+ static int s_globalDetailKey;
+ static int s_globalDetailLevel;
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmdetailobjectedit.cpp b/kpovmodeler/pmdetailobjectedit.cpp
new file mode 100644
index 00000000..d42c668c
--- /dev/null
+++ b/kpovmodeler/pmdetailobjectedit.cpp
@@ -0,0 +1,122 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2004 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+#include "pmdetailobjectedit.h"
+#include "pmdetailobject.h"
+
+#include <qlayout.h>
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qcombobox.h>
+#include <klocale.h>
+
+PMDetailObjectEdit::PMDetailObjectEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMDetailObjectEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* layout = new QHBoxLayout( topLayout( ) );
+ m_pGlobalDetail = new QCheckBox( i18n( "Global detail" ), this );
+ m_pLocalDetailLevelLabel = new QLabel( i18n( "Detail level:" ), this );
+ m_pLocalDetailLevel = new QComboBox( this );
+ m_pLocalDetailLevel->insertItem( i18n( "Very Low" ) );
+ m_pLocalDetailLevel->insertItem( i18n( "Low" ) );
+ m_pLocalDetailLevel->insertItem( i18n( "Medium" ) );
+ m_pLocalDetailLevel->insertItem( i18n( "High" ) );
+ m_pLocalDetailLevel->insertItem( i18n( "Very High" ) );
+
+ layout->addWidget( m_pGlobalDetail );
+ layout->addWidget( m_pLocalDetailLevelLabel );
+ layout->addWidget( m_pLocalDetailLevel );
+ layout->addStretch( );
+
+ connect( m_pGlobalDetail, SIGNAL( clicked( ) ), SLOT( slotGlobalDetailClicked( ) ) );
+ connect( m_pLocalDetailLevel, SIGNAL( activated( int ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMDetailObjectEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "DetailObject" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMDetailObject* ) o;
+
+ if( !m_pDisplayedObject->hasDisplayDetail( ) )
+ {
+ m_pGlobalDetail->hide( );
+ m_pLocalDetailLevelLabel->hide( );
+ m_pLocalDetailLevel->hide( );
+ }
+
+ if( m_pDisplayedObject->globalDetail( ) )
+ {
+ m_pGlobalDetail->setChecked( true );
+ m_pLocalDetailLevelLabel->setEnabled( false );
+ m_pLocalDetailLevel->setEnabled( false );
+ }
+ else
+ {
+ m_pGlobalDetail->setChecked( false );
+ m_pLocalDetailLevelLabel->setEnabled( !readOnly );
+ m_pLocalDetailLevel->setEnabled( !readOnly );
+ }
+ m_pGlobalDetail->setEnabled( !readOnly );
+
+ m_pLocalDetailLevel->setCurrentItem( m_pDisplayedObject->localDetailLevel( ) - 1 );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMNamedObjectEdit: Can't display object\n";
+}
+
+void PMDetailObjectEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setGlobalDetail( m_pGlobalDetail->isChecked( ) );
+ m_pDisplayedObject->setLocalDetailLevel( m_pLocalDetailLevel->currentItem( ) + 1 );
+ }
+}
+
+bool PMDetailObjectEdit::isDataValid( )
+{
+ return Base::isDataValid( );
+}
+
+void PMDetailObjectEdit::slotGlobalDetailClicked( )
+{
+ if( m_pGlobalDetail->isChecked( ) )
+ {
+ m_pLocalDetailLevelLabel->setEnabled( false );
+ m_pLocalDetailLevel->setEnabled( false );
+ }
+ else
+ {
+ bool readOnly = m_pDisplayedObject->isReadOnly( );
+ m_pLocalDetailLevelLabel->setEnabled( !readOnly );
+ m_pLocalDetailLevel->setEnabled( !readOnly );
+ }
+ emit dataChanged( );
+}
+
+#include "pmdetailobjectedit.moc"
diff --git a/kpovmodeler/pmdetailobjectedit.h b/kpovmodeler/pmdetailobjectedit.h
new file mode 100644
index 00000000..7a585034
--- /dev/null
+++ b/kpovmodeler/pmdetailobjectedit.h
@@ -0,0 +1,68 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2004 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+#ifndef PMDETAILOBJECTEDIT_H
+#define PMDETAILOBJECTEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmnamedobjectedit.h"
+
+class PMDetailObject;
+class QCheckBox;
+class QLabel;
+class QComboBox;
+
+/**
+ * Dialog edit class for @ref PMNamedObject.
+ */
+class PMDetailObjectEdit : public PMNamedObjectEdit
+{
+ Q_OBJECT
+ typedef PMNamedObjectEdit Base;
+public:
+ /**
+ * Creates a PMNamedObjectEdit with parent and name
+ */
+ PMDetailObjectEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private slots:
+ void slotGlobalDetailClicked( );
+
+private:
+ PMDetailObject* m_pDisplayedObject;
+ QCheckBox* m_pGlobalDetail;
+ QLabel* m_pLocalDetailLevelLabel;
+ QComboBox* m_pLocalDetailLevel;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmdialogeditbase.cpp b/kpovmodeler/pmdialogeditbase.cpp
new file mode 100644
index 00000000..9defd762
--- /dev/null
+++ b/kpovmodeler/pmdialogeditbase.cpp
@@ -0,0 +1,558 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmdialogeditbase.h"
+
+#include <qlayout.h>
+#include <qcheckbox.h>
+#include <qpushbutton.h>
+#include <qlabel.h>
+#include <qvbox.h>
+#include <qbuffer.h>
+#include <qptrdict.h>
+#include <kdialog.h>
+#include <kconfig.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+#include "pmpart.h"
+#include "pmdefaults.h"
+#include "pmpovrayrenderwidget.h"
+#include "pmpovrayoutputwidget.h"
+#include "pmpovray31format.h"
+#include "pmserializer.h"
+#include "pmcolor.h"
+#include "pmrecursiveobjectiterator.h"
+#include "pmdeclare.h"
+
+#include "pmdebug.h"
+
+int PMDialogEditBase::s_previewSize = c_defaultTPSize;
+bool PMDialogEditBase::s_showSphere = c_defaultTPShowSphere;
+bool PMDialogEditBase::s_showCylinder = c_defaultTPShowCylinder;
+bool PMDialogEditBase::s_showBox = c_defaultTPShowBox;
+bool PMDialogEditBase::s_previewAA = c_defaultTPAA;
+int PMDialogEditBase::s_previewAADepth = c_defaultTPAADepth;
+double PMDialogEditBase::s_previewAAThreshold = c_defaultTPAAThreshold;
+bool PMDialogEditBase::s_showFloor = c_defaultTPShowFloor;
+bool PMDialogEditBase::s_showWall = c_defaultTPShowWall;
+QColor PMDialogEditBase::s_wallColor1 = c_defaultTPWallColor1;
+QColor PMDialogEditBase::s_wallColor2 = c_defaultTPWallColor2;
+QColor PMDialogEditBase::s_floorColor1 = c_defaultTPFloorColor1;
+QColor PMDialogEditBase::s_floorColor2 = c_defaultTPFloorColor2;
+bool PMDialogEditBase::s_previewLocal = false;
+double PMDialogEditBase::s_previewGamma = c_defaultTPGamma;
+
+
+/** Constants for texture preview */
+const QString c_wallCode = QString(
+ "plane { <0, 0, -1>, -2\n"
+ " pigment { checker %1 %2\n"
+ " scale <0.5, 0.5, 0.5>\n"
+ " translate <0.5, 0, 0>\n"
+ " }\n"
+ "}\n" );
+const QString c_floorCode = QString(
+ "plane { <0, 1, 0>, 0\n"
+ " pigment { checker %1 %2\n"
+ " scale <0.5, 0.5, 0.5>\n"
+ " }\n"
+ "}\n" );
+const QString c_lightCode = QString(
+ "light_source { <-2.5, 3, -1.5>, rgb <1, 1, 1> }\n"
+ "light_source { <3, 3, -3>, rgb <0.6, 0.6, 0.6> shadowless }\n" );
+
+
+const QString c_cameraCode[3] = {
+ QString( "camera { location <-1, 1.25, -2> right <1, 0, 0>\n"
+ " look_at <0.0, 0.5, 0> angle 45 }\n" ),
+ QString( "camera { location <-1, 2, -3> right <1, 0, 0>\n"
+ " look_at <0.0, 1, 0> angle 45 }\n" ),
+ QString( "camera { location <-2, 2.5, -4> right <1, 0, 0>\n"
+ " look_at <0.0, 1.5, 0> angle 45 }\n" )
+};
+const QString c_sphereCode = QString(
+ "sphere { <0, 0.5, 0>, 0.5 translate <0, %1, 0> }\n" );
+const QString c_cylinderCode = QString(
+ "cylinder { <0, 0, 0>, <0, 1, 0>, 0.5 translate <0, %1, 0> }\n" );
+const QString c_boxCode = QString(
+ "box { <-0.5, 0, -0.5>, <0.5, 1, 0.5> translate <0, %1, 0> }\n" );
+const QString c_globalSettingsCode = QString(
+ "global_settings { assumed_gamma %1 }\n" );
+
+PMDialogEditBase::PMDialogEditBase( QWidget* parent, const char* name )
+ : QWidget( parent, name )
+{
+ m_pDisplayedObject = 0;
+ m_pPart = 0;
+
+ m_pTexturePreviewWidget = 0;
+ m_pOutputWidget = 0;
+ m_pRenderWidget = 0;
+ m_pRenderFrame = 0;
+ m_pPreviewLocalBox = 0;
+ m_pPreviewButton = 0;
+ m_pOutputButton = 0;
+}
+
+PMDialogEditBase::~PMDialogEditBase( )
+{
+ if( m_pOutputWidget )
+ delete m_pOutputWidget;
+}
+
+void PMDialogEditBase::createWidgets( )
+{
+ m_pTopLayout = new QBoxLayout( this, QBoxLayout::TopToBottom,
+ KDialog::spacingHint( ) );
+
+ createTopWidgets( );
+ createBottomWidgets( );
+
+ m_pTopLayout->addStretch( );
+ m_pTopLayout->activate( );
+}
+
+void PMDialogEditBase::createBottomWidgets( )
+{
+ m_pTexturePreviewWidget = new QWidget( this );
+ m_pTexturePreviewWidget->hide( );
+ m_pTopLayout->addWidget( m_pTexturePreviewWidget );
+}
+
+bool PMDialogEditBase::saveData( )
+{
+ if( isDataValid( ) )
+ {
+ saveContents( );
+ return true;
+ }
+ return false;
+}
+
+void PMDialogEditBase::saveContents( )
+{
+}
+
+void PMDialogEditBase::displayObject( PMObject* o )
+{
+ bool newObject = ( m_pDisplayedObject != o );
+ m_pDisplayedObject = o;
+ PMObject* global;
+ PMObject* local;
+
+ // Is object a full texture or inside a full texture
+ findTextures( global, local );
+ if( global )
+ {
+ // is the preview widget created?
+ if( !m_pRenderWidget )
+ {
+ QVBoxLayout* vl = new QVBoxLayout( m_pTexturePreviewWidget, 0,
+ KDialog::spacingHint( ) );
+ vl->addSpacing( 10 );
+ QFrame* hline = new QFrame( m_pTexturePreviewWidget );
+ hline->setFrameStyle( QFrame::HLine | QFrame::Plain );
+ hline->setLineWidth( 1 );
+ vl->addWidget( hline );
+ vl->addWidget( new QLabel( i18n( "Texture preview:" ), m_pTexturePreviewWidget ) );
+ m_pRenderFrame = new QVBox( m_pTexturePreviewWidget );
+ m_pRenderFrame->setFrameStyle( QFrame::StyledPanel | QFrame::Sunken );
+ m_pRenderFrame->setLineWidth( 2 );
+ m_pRenderFrame->hide( );
+ vl->addWidget( m_pRenderFrame );
+
+ m_pRenderWidget = new PMPovrayRenderWidget( m_pRenderFrame );
+ connect( m_pRenderWidget, SIGNAL( finished( int ) ),
+ SLOT( slotPreviewFinished( int ) ) );
+ m_pPreviewLocalBox = new QCheckBox( i18n( "local" ), m_pTexturePreviewWidget );
+ m_pPreviewLocalBox->setChecked( s_previewLocal );
+ connect( m_pPreviewLocalBox, SIGNAL( toggled( bool ) ),
+ SLOT( slotPreviewLocal( bool ) ) );
+ vl->addWidget( m_pPreviewLocalBox );
+
+ QHBoxLayout* hl = new QHBoxLayout( vl );
+ m_pPreviewButton = new QPushButton( i18n( "&Preview" ), m_pTexturePreviewWidget );
+ hl->addWidget( m_pPreviewButton );
+ connect( m_pPreviewButton, SIGNAL( clicked( ) ),
+ SLOT( slotTexturePreview( ) ) );
+ m_pOutputButton = new QPushButton( i18n( "Povray Output" ), m_pTexturePreviewWidget );
+ hl->addWidget( m_pOutputButton );
+ connect( m_pOutputButton, SIGNAL( clicked( ) ),
+ SLOT( slotPovrayOutput( ) ) );
+ hl->addStretch( 1 );
+
+ m_pOutputWidget = new PMPovrayOutputWidget( );
+ connect( m_pRenderWidget, SIGNAL( povrayMessage( const QString& ) ),
+ m_pOutputWidget, SLOT( slotText( const QString& ) ) );
+ }
+
+ m_pTexturePreviewWidget->show( );
+ if( newObject )
+ m_pRenderFrame->hide( );
+ m_pPreviewLocalBox->setEnabled( local != global );
+ m_pPreviewButton->setEnabled( true );
+ }
+ else
+ {
+ // is the preview widget created?
+ if( m_pPreviewButton )
+ m_pPreviewButton->setEnabled( false );
+ m_pTexturePreviewWidget->hide( );
+ }
+}
+
+void PMDialogEditBase::setHelp( const QString& anchor )
+{
+ m_helpTopic = anchor;
+}
+
+void PMDialogEditBase::redisplay( )
+{
+ if( m_pDisplayedObject )
+ displayObject( m_pDisplayedObject );
+}
+
+void PMDialogEditBase::setCheckBox( QCheckBox* box, PMThreeState state )
+{
+ switch( state )
+ {
+ case PMTrue:
+ box->setChecked( true );
+ break;
+ case PMFalse:
+ box->setChecked( false );
+ break;
+ case PMUnspecified:
+ box->setNoChange( );
+ break;
+ }
+}
+
+PMThreeState PMDialogEditBase::checkBoxState( QCheckBox* box )
+{
+ PMThreeState st = PMTrue;
+ switch( box->state( ) )
+ {
+ case QCheckBox::On:
+ st = PMTrue;
+ break;
+ case QCheckBox::Off:
+ st = PMFalse;
+ break;
+ case QCheckBox::NoChange:
+ st = PMUnspecified;
+ break;
+ }
+ return st;
+}
+
+void PMDialogEditBase::setPreviewSize( int size )
+{
+ if( ( size >= 10 ) && ( size <= 400 ) )
+ s_previewSize = size;
+}
+
+void PMDialogEditBase::setPreviewAADepth( int d )
+{
+ if( ( d >= 1 ) && ( d <= 9 ) )
+ s_previewAADepth = d;
+}
+
+void PMDialogEditBase::saveConfig( KConfig* cfg )
+{
+ cfg->setGroup( "TexturePreview" );
+ cfg->writeEntry( "Size", s_previewSize );
+ cfg->writeEntry( "showSphere", s_showSphere );
+ cfg->writeEntry( "showCylinder", s_showCylinder );
+ cfg->writeEntry( "showBox", s_showBox );
+ cfg->writeEntry( "AA", s_previewAA );
+ cfg->writeEntry( "AADepth", s_previewAADepth );
+ cfg->writeEntry( "AAThreshold", s_previewAAThreshold );
+ cfg->writeEntry( "showWall", s_showWall );
+ cfg->writeEntry( "showFloor", s_showFloor );
+ cfg->writeEntry( "WallColor1", s_wallColor1 );
+ cfg->writeEntry( "WallColor2", s_wallColor2 );
+ cfg->writeEntry( "FloorColor1", s_floorColor1 );
+ cfg->writeEntry( "FloorColor2", s_floorColor2 );
+ cfg->writeEntry( "Gamma", s_previewGamma );
+}
+
+void PMDialogEditBase::restoreConfig( KConfig* cfg )
+{
+ cfg->setGroup( "TexturePreview" );
+ setPreviewSize( cfg->readNumEntry( "Size", s_previewSize ) );
+ s_showSphere = cfg->readBoolEntry( "showSphere", s_showSphere );
+ s_showCylinder = cfg->readBoolEntry( "showCylinder", s_showCylinder );
+ s_showBox = cfg->readBoolEntry( "showBox", s_showBox );
+ s_previewAA = cfg->readBoolEntry( "AA", s_previewAA );
+ setPreviewAADepth( cfg->readNumEntry( "AADepth", s_previewAADepth ) );
+ s_previewAAThreshold = cfg->readDoubleNumEntry( "AAThreshold", s_previewAAThreshold );
+ s_showWall = cfg->readBoolEntry( "showWall", s_showWall );
+ s_showFloor = cfg->readBoolEntry( "showFloor", s_showFloor );
+ s_wallColor1 = cfg->readColorEntry( "WallColor1", &s_wallColor1 );
+ s_wallColor2 = cfg->readColorEntry( "WallColor2", &s_wallColor2 );
+ s_floorColor1 = cfg->readColorEntry( "FloorColor1", &s_floorColor1 );
+ s_floorColor2 = cfg->readColorEntry( "FloorColor2", &s_floorColor2 );
+ s_previewGamma = cfg->readDoubleNumEntry( "Gamma", s_previewGamma );
+}
+
+void PMDialogEditBase::findTextures( PMObject*& global, PMObject*& local ) const
+{
+ PMObject* o;
+ global = 0;
+ local = 0;
+
+ for( o = m_pDisplayedObject; o; o = o->parent( ) )
+ {
+ if( o->type( ) == "Material" || o->type( ) == "Interior" ||
+ o->type( ) == "Texture" || o->type( ) == "Pigment" ||
+ o->type( ) == "InteriorTexture" )
+ {
+ if( !local )
+ local = o;
+ global = o;
+ }
+ else if( o->type( ) == "Declare" )
+ {
+ PMDeclare* d = ( PMDeclare* ) o;
+ if( d->declareType( ) == "Interior" ||
+ d->declareType( ) == "Pigment" ||
+ d->declareType( ) == "Material" )
+ {
+ if( !local || ( local == global ) )
+ local = o;
+ global = o;
+ }
+ else if( d->declareType( ) == "Texture" ||
+ d->declareType( ) == "InteriorTexture" )
+ {
+ if( o->countChildren( ) > 1 )
+ {
+ if( !local )
+ local = o;
+ }
+ else
+ if( !local || ( local == global ) )
+ local = o;
+ global = o;
+ }
+ }
+ }
+}
+
+void PMDialogEditBase::slotTexturePreview( )
+{
+ PMObject* o;
+ PMObject* local = 0;
+ PMObject* global = 0;
+
+ if( !m_pRenderWidget )
+ return;
+
+ findTextures( global, local );
+ if( local )
+ {
+ emit aboutToRender( );
+
+ if( global == local )
+ o = global;
+ else
+ {
+ if( m_pPreviewLocalBox->isChecked( ) )
+ o = local;
+ else
+ o = global;
+ }
+
+ // ensure at least one object will be rendered.
+ if( !( s_showSphere || s_showCylinder || s_showBox ) )
+ s_showSphere = true;
+
+ int numObjects = 0;
+ QByteArray scene;
+ QBuffer buffer( scene );
+ buffer.open( IO_WriteOnly );
+ QTextStream str( &buffer );
+ PMPovray31Format format;
+ PMSerializer* dev = format.newSerializer( &buffer );
+ PMRenderMode mode;
+ PMObjectList neededDeclares, objectsToCheck;
+ QPtrDict<PMObject> objectsToSerialize( 101 );
+ PMObject* link;
+
+ // find needed declares
+ objectsToCheck.append( o );
+ do
+ {
+ PMObjectListIterator it( objectsToCheck );
+ for( ; it.current( ); ++it )
+ {
+ PMRecursiveObjectIterator rit( it.current( ) );
+ for( ; rit.current( ); ++rit )
+ {
+ link = rit.current( )->linkedObject( );
+ if( link )
+ if( !neededDeclares.containsRef( link ) )
+ if( !objectsToSerialize.find( link ) )
+ neededDeclares.append( link );
+ }
+ objectsToSerialize.insert( it.current( ), it.current( ) );
+ }
+
+ objectsToCheck = neededDeclares;
+ neededDeclares.clear( );
+ }
+ while( objectsToCheck.count( ) > 0 );
+
+ // serialize all needed declares in the right order
+ int numDeclares = objectsToSerialize.count( );
+ if( numDeclares > 0 )
+ {
+ PMObject* otr = o;
+
+ // find the scene
+ while( otr->parent( ) ) otr = otr->parent( );
+
+ for( otr = otr->firstChild( ); otr && ( numDeclares > 0 );
+ otr = otr->nextSibling( ) )
+ {
+ if( otr->type( ) == "Declare" )
+ {
+ if( objectsToSerialize.find( otr ) )
+ {
+ dev->serialize( otr );
+ numDeclares--;
+ }
+ }
+ }
+ str << "\n\n";
+ }
+ // if the previewed texture is a declare, serialize it
+ if( o->type( ) == "Declare" )
+ dev->serialize( o );
+
+ // build the preview scene
+ str << "union {\n";
+ if( s_showBox )
+ {
+ str << c_boxCode.arg( numObjects );
+ numObjects++;
+ }
+ if( s_showCylinder )
+ {
+ str << c_cylinderCode.arg( numObjects );
+ numObjects++;
+ }
+ if( s_showSphere )
+ {
+ str << c_sphereCode.arg( numObjects );
+ numObjects++;
+ }
+
+ // serialize the texture
+ if( o->type( ) == "Declare" )
+ {
+ PMDeclare* dec = ( PMDeclare* ) o;
+ if( dec->declareType( ) == "Interior" )
+ str << "interior { ";
+ else if( dec->declareType( ) == "Texture" )
+ str << "texture { ";
+ else if( dec->declareType( ) == "Pigment" )
+ str << "pigment { ";
+ else if( dec->declareType( ) == "InteriorTexture" )
+ str << "interior_texture { ";
+ else if( dec->declareType( ) == "Material" )
+ str << "material { ";
+ else
+ kdError( PMArea ) << "Unhandled declare type in "
+ "PMDialogEditBase::slotTexturePreview\n";
+
+ str << dec->id( );
+ str << " }\n";
+ }
+ else
+ dev->serialize( o );
+ str << "}\n";
+
+ PMColor c1, c2;
+ if( s_showWall )
+ {
+ c1 = PMColor( s_wallColor1 );
+ c2 = PMColor( s_wallColor2 );
+ str << c_wallCode.arg( c1.serialize( true ) ).arg( c2.serialize( true ) );
+ }
+ if( s_showFloor )
+ {
+ c1 = PMColor( s_floorColor1 );
+ c2 = PMColor( s_floorColor2 );
+ str << c_floorCode.arg( c1.serialize( true ) ).arg( c2.serialize( true ) );
+ }
+
+ str << c_lightCode;
+ str << c_cameraCode[numObjects-1];
+ str << c_globalSettingsCode.arg( s_previewGamma );
+
+ // Set the render mode
+ mode.setHeight( s_previewSize );
+ mode.setWidth( s_previewSize );
+ mode.setAntialiasing( s_previewAA );
+ mode.setAntialiasingThreshold( s_previewAAThreshold );
+ mode.setAntialiasingDepth( s_previewAADepth );
+
+ m_pRenderFrame->show( );
+ m_pRenderFrame->setFixedSize( s_previewSize + m_pRenderFrame->frameWidth( ) * 2,
+ s_previewSize + m_pRenderFrame->frameWidth( ) * 2 );
+ m_pRenderFrame->updateGeometry( );
+ m_pTexturePreviewWidget->layout( )->activate( );
+ emit sizeChanged( );
+ m_pOutputWidget->slotClear( );
+ m_pRenderWidget->render( scene, mode, m_pPart->url( ) );
+
+ delete dev;
+ }
+}
+
+void PMDialogEditBase::slotPreviewLocal( bool on )
+{
+ s_previewLocal = on;
+}
+
+void PMDialogEditBase::slotPreviewFinished( int exitStatus )
+{
+ if( exitStatus != 0 )
+ {
+ KMessageBox::error( this, i18n( "Povray exited abnormally with "
+ "exit code %1.\n"
+ "See the povray output for details." )
+ .arg( exitStatus ) );
+ }
+ else if( m_pRenderWidget->povrayOutput( ).contains( "ERROR" ) )
+ {
+ KMessageBox::error( this, i18n( "There were errors while rendering.\n"
+ "See the povray output for details." ) );
+ }
+}
+
+void PMDialogEditBase::slotPovrayOutput( )
+{
+ if( m_pOutputWidget )
+ m_pOutputWidget->show( );
+}
+
+#include "pmdialogeditbase.moc"
diff --git a/kpovmodeler/pmdialogeditbase.h b/kpovmodeler/pmdialogeditbase.h
new file mode 100644
index 00000000..547946f5
--- /dev/null
+++ b/kpovmodeler/pmdialogeditbase.h
@@ -0,0 +1,356 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMDIALOGEDITBASE_H
+#define PMDIALOGEDITBASE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qwidget.h>
+#include <qstring.h>
+
+#include "pmobject.h"
+
+class QBoxLayout;
+class QCheckBox;
+class QLayout;
+class QPushButton;
+class QVBox;
+class KConfig;
+class PMPart;
+class PMPovrayRenderWidget;
+class PMPovrayOutputWidget;
+
+/**
+ * Base class for all widgets for editing object attributes.
+ *
+ * Ensures a consistent layout for all widgets. Widgets should not
+ * created within the constructor, but with the functions @ref createTopWidgets
+ * and @ref createBottomWidgets.
+ *
+ * Each subclass uses the functionality of the base class. For example all
+ * widgets for solid objects have the same base class that shows attributes
+ * of solid objects. Subclasses like the widget for the box object add their
+ * object specific controls.
+ */
+class PMDialogEditBase : public QWidget
+{
+ Q_OBJECT
+public:
+ /**
+ * Creates a new PMDialogEditBase widget objectType is
+ * @ref PMObject->description( ).
+ *
+ * No widgets are created within the constructor! You have to call
+ * @ref createWidgets after creating a new edit widget.
+ */
+ PMDialogEditBase( QWidget* parent, const char* name = 0 );
+ /**
+ * Destructor
+ */
+ virtual ~PMDialogEditBase( );
+
+ /**
+ * Creates child widgets.
+ *
+ * This function is necessary because virtual functions do not work
+ * properly inside the constructor.
+ *
+ * Calls @ref createTopWidgets and @ref createBottomWidgets
+ */
+ void createWidgets( );
+
+ /**
+ * Displays the object o.
+ * Always call displayObject( ) of the base class after displaying the
+ * objects data
+ */
+ virtual void displayObject( PMObject* o );
+
+ /**
+ * returns a pointer to the displayed object
+ */
+ PMObject* displayedObject( ) const { return m_pDisplayedObject; }
+
+ /**
+ * Function that is called, when the "Apply" button is pressed.
+ *
+ * Returns true if successful
+ */
+ bool saveData( );
+
+ /**
+ * Called, when the contents have to be checked.
+ *
+ * Display an error message and return false, if the data is invalid.
+ * Otherwise return isDataValid( ) of the base class.
+ */
+ virtual bool isDataValid( ) { return true; }
+
+ /**
+ * Returns the help topic
+ */
+ const QString& helpTopic( ) { return m_helpTopic; }
+
+ /**
+ * Discards changes and redisplays the object
+ */
+ void redisplay( );
+
+ /**
+ * Called when the control point selection has changed
+ */
+ virtual void updateControlPointSelection( ) { };
+
+ /**
+ * Sets the check box to state s
+ */
+ static void setCheckBox( QCheckBox* box, PMThreeState s );
+ /**
+ * Gets the state of the checkbox
+ */
+ static PMThreeState checkBoxState( QCheckBox* box );
+
+ /**
+ * Sets the part
+ */
+ void setPart( PMPart* p ) { m_pPart = p; }
+ /**
+ * Returns the part
+ */
+ PMPart* part( ) const { return m_pPart; }
+
+ /**
+ * Returns the size of the texture preview widget
+ */
+ static int previewSize( ) { return s_previewSize; }
+ /**
+ * Sets the texture preview size
+ */
+ static void setPreviewSize( int size );
+ /**
+ * Returns true if a sphere should be renderend
+ */
+ static bool previewShowSphere( ) { return s_showSphere; }
+ /**
+ * Enable/disable the sphere in the texture preview widget
+ */
+ static void previewShowSphere( bool show ) { s_showSphere = show; }
+ /**
+ * Returns true if a cylinder should be renderend
+ */
+ static bool previewShowCylinder( ) { return s_showCylinder; }
+ /**
+ * Enable/disable the cylinder in the texture preview widget
+ */
+ static void previewShowCylinder( bool show ) { s_showCylinder = show; }
+ /**
+ * Returns true if a box should be renderend
+ */
+ static bool previewShowBox( ) { return s_showBox; }
+ /**
+ * Enable/disable the box in the texture preview widget
+ */
+ static void previewShowBox( bool show ) { s_showBox = show; }
+
+ /**
+ * Returns true if AA is enabled
+ */
+ static bool isPreviewAAEnabled( ) { return s_previewAA; }
+ /**
+ * Enables/disables AA
+ */
+ static void setPreviewAAEnabled( bool enable ) { s_previewAA = enable; }
+ /**
+ * Returns the AA depth
+ */
+ static int previewAADepth( ) { return s_previewAADepth; }
+ /**
+ * Sets the AA depth
+ */
+ static void setPreviewAADepth( int d );
+ /**
+ * Returns the AA threshold
+ */
+ static double previewAAThreshold( ) { return s_previewAAThreshold; }
+ /**
+ * Sets the AA threshold
+ */
+ static void setPreviewAAThreshold( double t ) { s_previewAAThreshold = t; }
+
+ /**
+ * Returns true if the floor should be rendered
+ */
+ static bool previewShowFloor( ) { return s_showFloor; }
+ /**
+ * Enables/disables the floor
+ */
+ static void previewShowFloor( bool show ) { s_showFloor = show; }
+ /**
+ * Returns true if the wall should be rendered
+ */
+ static bool previewShowWall( ) { return s_showWall; }
+ /**
+ * Enables/disables the wall
+ */
+ static void previewShowWall( bool show ) { s_showWall = show; }
+ /**
+ * Returns the first wall color
+ */
+ static QColor previewWallColor1( ) { return s_wallColor1; }
+ /**
+ * Sets the first wall color
+ */
+ static void setPreviewWallColor1( const QColor& c ) { s_wallColor1 = c; }
+ /**
+ * Returns the second wall color
+ */
+ static QColor previewWallColor2( ) { return s_wallColor2; }
+ /**
+ * Sets the second wall color
+ */
+ static void setPreviewWallColor2( const QColor& c ) { s_wallColor2 = c; }
+ /**
+ * Returns the first floor color
+ */
+ static QColor previewFloorColor1( ) { return s_floorColor1; }
+ /**
+ * Sets the first floor color
+ */
+ static void setPreviewFloorColor1( const QColor& c ) { s_floorColor1 = c; }
+ /**
+ * Returns the second floor color
+ */
+ static QColor previewFloorColor2( ) { return s_floorColor2; }
+ /**
+ * Sets the second floor color
+ */
+ static void setPreviewFloorColor2( const QColor& c ) { s_floorColor2 = c; }
+ /**
+ * Returns the local flag for texture preview
+ */
+ static bool previewLocal( ) { return s_previewLocal; }
+ /**
+ * Sets the local flag
+ */
+ static void setPreviewLocal( bool l ) { s_previewLocal = l; }
+ /**
+ * Returns the gamma value for the texture preview
+ */
+ static double previewGamma( ) { return s_previewGamma; }
+ /**
+ * Sets the gamma value for the texture preview
+ */
+ static void setPreviewGamma( double g ) { s_previewGamma = g; }
+
+ static void saveConfig( KConfig* cfg );
+ static void restoreConfig( KConfig* cfg );
+protected:
+ /**
+ * Sets the help topic
+ * @param anchor Defined anchor in your docbook sources
+ */
+ void setHelp( const QString& anchor );
+
+ /**
+ * Create widgets here, that should be placed on top of the widgets
+ * of the sub class.
+ *
+ * First call the function of the base class, then create and append
+ * the widgets to the top layout.
+ */
+ virtual void createTopWidgets( ) { };
+
+ /**
+ * Create widgets here, that should be placed under the widgets
+ * of the sub class.
+ *
+ * First create and append the widgets to the top layout, then
+ * call the function of the base class
+ */
+ virtual void createBottomWidgets( );
+
+ /**
+ * Save here the class specific data and call saveContents( )
+ * of the base class
+ */
+ virtual void saveContents( );
+
+ /**
+ * Returns a pointer to the top layout
+ */
+ QBoxLayout* topLayout( ) const { return m_pTopLayout; }
+
+protected slots:
+ void slotTexturePreview( );
+ void slotPreviewLocal( bool on );
+ void slotPreviewFinished( int exitStatus );
+ void slotPovrayOutput( );
+
+signals:
+ /**
+ * Emit this, if data has changed
+ */
+ void dataChanged( );
+ /**
+ * Emit this, if the size of the widget has changed
+ */
+ void sizeChanged( );
+ /**
+ * Emit this, if the control point selection has changed
+ */
+ void controlPointSelectionChanged( );
+ /**
+ * Emit this signal, before the displayed object or texture is rendered
+ */
+ void aboutToRender( );
+private:
+ void findTextures( PMObject*& global, PMObject*& local ) const;
+
+ PMObject* m_pDisplayedObject;
+ QBoxLayout* m_pTopLayout;
+ QString m_helpTopic;
+ PMPart* m_pPart;
+ QWidget* m_pTexturePreviewWidget;
+ PMPovrayRenderWidget* m_pRenderWidget;
+ PMPovrayOutputWidget* m_pOutputWidget;
+ QVBox* m_pRenderFrame;
+ QCheckBox* m_pPreviewLocalBox;
+ QPushButton* m_pPreviewButton;
+ QPushButton* m_pOutputButton;
+
+ static int s_previewSize;
+ static bool s_showSphere;
+ static bool s_showCylinder;
+ static bool s_showBox;
+ static bool s_previewAA;
+ static int s_previewAADepth;
+ static double s_previewAAThreshold;
+ static bool s_showFloor;
+ static bool s_showWall;
+ static QColor s_wallColor1, s_wallColor2;
+ static QColor s_floorColor1, s_floorColor2;
+ static bool s_previewLocal;
+ static double s_previewGamma;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmdialogview.cpp b/kpovmodeler/pmdialogview.cpp
new file mode 100644
index 00000000..f88a0272
--- /dev/null
+++ b/kpovmodeler/pmdialogview.cpp
@@ -0,0 +1,441 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmdialogview.h"
+#include "pmdialogeditbase.h"
+#include "pmallobjects.h"
+#include "pmdebug.h"
+#include "pmfactory.h"
+#include "pmdatachangecommand.h"
+#include "pmpart.h"
+#include "pmdocumentationmap.h"
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdialog.h>
+#include <kprocess.h>
+#include <kiconloader.h>
+#include <krun.h>
+#include <kstdguiitem.h>
+
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qgroupbox.h>
+#include <qscrollview.h>
+#include <qlabel.h>
+
+PMDialogEditContent::PMDialogEditContent( QWidget* parent, const char* name )
+ : QScrollView( parent, name )
+{
+ m_pContents = 0;
+ setVScrollBarMode( AlwaysOff );
+ setHScrollBarMode( AlwaysOff );
+ setFrameStyle( Panel | Sunken );
+ setLineWidth( 1 );
+ setResizePolicy( Manual );
+}
+
+void PMDialogEditContent::setContents( QWidget* wid )
+{
+ if( m_pContents )
+ removeChild( m_pContents );
+
+ m_pContents = wid;
+
+ if( m_pContents )
+ {
+ addChild( m_pContents );
+ calculateSize( );
+ }
+}
+
+void PMDialogEditContent::calculateSize( )
+{
+ int fw = lineWidth( ) * 2;
+ if( m_pContents )
+ {
+ QSize newSize = m_pContents->minimumSizeHint( );
+
+ setVScrollBarMode( AlwaysOff );
+ setHScrollBarMode( AlwaysOff );
+ setMargins( 0, 0, 0, 0 );
+
+ if( width( ) - fw < newSize.width( ) )
+ {
+ setHScrollBarMode( AlwaysOn );
+
+ if( ( height( ) - horizontalScrollBar( )->height( ) - fw )
+ < newSize.height( ) )
+ setVScrollBarMode( AlwaysOn );
+ else
+ newSize.setHeight( height( ) - horizontalScrollBar( )->height( ) - 2 );
+ }
+ else if( height( ) - fw < newSize.height( ) )
+ {
+ setVScrollBarMode( AlwaysOn );
+
+ if( ( width( ) - verticalScrollBar( )->width( ) - fw )
+ < newSize.width( ) )
+ setHScrollBarMode( AlwaysOn );
+ else
+ newSize.setWidth( width( ) - verticalScrollBar( )->width( ) - fw );
+ }
+ else
+ {
+ newSize.setWidth( width( ) - fw );
+ newSize.setHeight( height( ) - fw );
+ }
+
+ resizeContents( newSize.width( ), newSize.height( ) );
+ m_pContents->resize( newSize );
+ }
+}
+
+void PMDialogEditContent::resizeEvent( QResizeEvent* /* ev */ )
+{
+ calculateSize( );
+}
+
+PMDialogView::PMDialogView( PMPart* part, QWidget* parent, const char* name )
+ : PMViewBase( parent, name )
+{
+ m_pDisplayedWidget = 0;
+ m_unsavedData = false;
+ m_pHelper = new PMDialogEditContent( this );
+ m_pHelper->show( );
+ m_pPart = part;
+
+ m_pLayout = new QVBoxLayout( this, KDialog::marginHint( ),
+ KDialog::spacingHint( ) );
+
+ QHBoxLayout* labelLayout = new QHBoxLayout( m_pLayout );
+ m_pPixmapLabel = new QLabel( this );
+ m_pObjectTypeLabel = new QLabel( this );
+ labelLayout->addWidget( m_pPixmapLabel );
+ labelLayout->addWidget( m_pObjectTypeLabel );
+ labelLayout->addStretch( );
+
+ m_pLayout->addWidget( m_pHelper, 2 );
+ m_pLayout->addStretch( );
+
+ QHBoxLayout* buttonLayout = new QHBoxLayout( m_pLayout );
+ m_pHelpButton = new KPushButton( KStdGuiItem::help(), this );
+ buttonLayout->addWidget( m_pHelpButton );
+ connect( m_pHelpButton, SIGNAL( clicked( ) ), this, SLOT( slotHelp( ) ) );
+ m_pHelpButton->setEnabled( false );
+
+ m_pApplyButton = new KPushButton( KStdGuiItem::apply(), this );
+ buttonLayout->addWidget( m_pApplyButton );
+ connect( m_pApplyButton, SIGNAL( clicked( ) ), this, SLOT( slotApply( ) ) );
+ m_pApplyButton->setEnabled( false );
+
+ buttonLayout->addStretch( );
+
+ m_pCancelButton = new KPushButton( KStdGuiItem::cancel(), this );
+ buttonLayout->addWidget( m_pCancelButton );
+ connect( m_pCancelButton, SIGNAL( clicked( ) ), this, SLOT( slotCancel( ) ) );
+ m_pCancelButton->setEnabled( false );
+
+ m_pLayout->activate( );
+
+ connect( part, SIGNAL( refresh( ) ), SLOT( slotRefresh( ) ) );
+ connect( part, SIGNAL( objectChanged( PMObject*, const int, QObject* ) ),
+ SLOT( slotObjectChanged( PMObject*, const int, QObject* ) ) );
+ connect( part, SIGNAL( clear( ) ), SLOT( slotClear( ) ) );
+ connect( part, SIGNAL( aboutToRender( ) ), SLOT( slotAboutToRender( ) ) );
+ connect( part, SIGNAL( aboutToSave( ) ), SLOT( slotAboutToRender( ) ) );
+ connect( this, SIGNAL( objectChanged( PMObject*, const int, QObject* ) ),
+ part, SLOT( slotObjectChanged( PMObject*, const int, QObject* ) ) );
+
+ displayObject( m_pPart->activeObject( ) );
+}
+
+
+
+PMDialogView::~PMDialogView( )
+{
+ emit destroyed( this );
+}
+
+void PMDialogView::slotObjectChanged( PMObject* obj, const int mode, QObject* sender )
+{
+ if( sender == this )
+ return;
+ if( mode & PMCNewSelection )
+ {
+ if( m_pDisplayedWidget )
+ if( m_pDisplayedWidget->displayedObject( ) )
+ if( m_unsavedData )
+ if( shouldSaveData( ) )
+ slotApply( );
+
+ displayObject( obj );
+ }
+ if( mode & ( PMCSelected | PMCDeselected ) )
+ {
+ if( m_pDisplayedWidget )
+ if( m_pDisplayedWidget->displayedObject( ) )
+ if( m_unsavedData )
+ if( shouldSaveData( ) )
+ slotApply( );
+
+ displayObject( 0 );
+ }
+ if( mode & PMCRemove )
+ {
+ if( m_pDisplayedWidget )
+ {
+ if( m_pDisplayedWidget->displayedObject( ) == obj )
+ {
+ displayObject( 0 );
+ }
+ }
+ }
+ if( mode & ( PMCData | PMCDescription ) )
+ {
+ if( m_pDisplayedWidget )
+ {
+ if( m_pDisplayedWidget->displayedObject( ) )
+ {
+ if( m_pDisplayedWidget->displayedObject( ) == obj )
+ {
+ displayObject( obj, mode & PMCDescription );
+ m_unsavedData = false;
+ m_pApplyButton->setEnabled( false );
+ m_pCancelButton->setEnabled( false );
+ }
+ }
+ }
+ }
+ if( mode & PMCControlPointSelection )
+ {
+ if( m_pDisplayedWidget )
+ m_pDisplayedWidget->updateControlPointSelection( );
+ }
+}
+
+bool PMDialogView::shouldSaveData( )
+{
+ return ( KMessageBox::questionYesNo(
+ this, i18n( "This object was modified.\n\nSave changes?" ),
+ i18n( "Unsaved Changes" ), KStdGuiItem::save(), KStdGuiItem::discard() ) == KMessageBox::Yes );
+}
+
+void PMDialogView::slotRefresh( )
+{
+ if( m_pDisplayedWidget )
+ m_pDisplayedWidget->redisplay( );
+}
+
+void PMDialogView::slotClear( )
+{
+ displayObject( 0 );
+}
+
+void PMDialogView::slotApply( )
+{
+ if( m_pDisplayedWidget )
+ {
+ PMObject* obj = m_pDisplayedWidget->displayedObject( );
+ if( obj )
+ {
+ if( m_pDisplayedWidget->isDataValid( ) )
+ {
+ PMDataChangeCommand* cmd;
+
+ obj->createMemento( );
+ m_pDisplayedWidget->saveData( );
+ cmd = new PMDataChangeCommand( obj->takeMemento( ) );
+ m_pPart->executeCommand( cmd );
+
+ m_pApplyButton->setEnabled( false );
+ m_pCancelButton->setEnabled( false );
+ m_unsavedData = false;
+ }
+ }
+ }
+}
+
+void PMDialogView::slotHelp( )
+{
+ if( m_pDisplayedWidget && m_pDisplayedWidget->displayedObject( ) )
+ {
+ QString url = PMDocumentationMap::theMap( )->documentation(
+ m_pDisplayedWidget->displayedObject( )->className( ) );
+ if( !url.isEmpty( ) )
+ {
+ // Instead of calling invokeBrowser run konqueror directly.
+ // invokeBrowser was ignoring html anchors.
+ url = "konqueror " + KProcess::quote(url);
+ KRun::runCommand( url );
+ }
+ }
+}
+
+void PMDialogView::slotCancel( )
+{
+ m_pCancelButton->setEnabled( false );
+ m_pApplyButton->setEnabled( false );
+ m_unsavedData = false;
+
+ if( m_pDisplayedWidget )
+ {
+ bool b = m_pDisplayedWidget->signalsBlocked( );
+ m_pDisplayedWidget->blockSignals( true );
+ m_pDisplayedWidget->redisplay( );
+ m_pDisplayedWidget->blockSignals( b );
+ slotSizeChanged( );
+ }
+}
+
+void PMDialogView::slotDataChanged( )
+{
+// kdDebug( PMArea ) << "PMDialogView::slotDataChanged\n";
+ m_pApplyButton->setEnabled( true ) ;
+ m_pCancelButton->setEnabled( true );
+
+ m_unsavedData = true;
+}
+
+void PMDialogView::slotSizeChanged( )
+{
+ // force recalculating of the layout
+ if( m_pDisplayedWidget )
+ if( m_pDisplayedWidget->layout( ) )
+ m_pDisplayedWidget->layout( )->activate( );
+ m_pHelper->calculateSize( );
+}
+
+void PMDialogView::slotControlPointSelectionChanged( )
+{
+ if( m_pDisplayedWidget && m_pDisplayedWidget->displayedObject( ) )
+ emit objectChanged( m_pDisplayedWidget->displayedObject( ),
+ PMCControlPointSelection, this );
+}
+
+void PMDialogView::displayObject( PMObject* obj, bool updateDescription )
+{
+ PMDialogEditBase* old = 0;
+
+ if( !obj )
+ {
+ if( m_pDisplayedWidget )
+ old = m_pDisplayedWidget;
+
+ m_pDisplayedWidget = new PMDialogEditBase( m_pHelper->viewport( ) );
+ m_pDisplayedWidget->createWidgets( );
+ m_pHelper->setContents( m_pDisplayedWidget );
+ m_pPixmapLabel->setText( "" );
+ m_pObjectTypeLabel->setText( "" );
+ }
+ else
+ {
+ bool newWidget = true;
+ if( m_pDisplayedWidget )
+ {
+ if( m_pDisplayedWidget->displayedObject( ) )
+ {
+ if( obj->type( ) == m_pDisplayedWidget->displayedObject( )->type( ) )
+ {
+ // current widget displays object of the same type
+ // reuse the widget
+ newWidget = false;
+ }
+ }
+ }
+
+ if( newWidget )
+ {
+ // first create the new widget, then delete the old one.
+ if( m_pDisplayedWidget )
+ old = m_pDisplayedWidget;
+ m_pDisplayedWidget = obj->editWidget( m_pHelper->viewport( ) );
+ m_pDisplayedWidget->setPart( m_pPart );
+ m_pDisplayedWidget->createWidgets( );
+ m_pHelper->setContents( m_pDisplayedWidget );
+
+ if( m_pDisplayedWidget )
+ {
+ connect( m_pDisplayedWidget, SIGNAL( dataChanged( ) ),
+ this, SLOT( slotDataChanged( ) ) );
+ connect( m_pDisplayedWidget, SIGNAL( sizeChanged( ) ),
+ this, SLOT( slotSizeChanged( ) ) );
+ connect( m_pDisplayedWidget, SIGNAL( aboutToRender( ) ),
+ this, SLOT( slotAboutToRender( ) ) );
+ connect( m_pDisplayedWidget,
+ SIGNAL( controlPointSelectionChanged( ) ),
+ SLOT( slotControlPointSelectionChanged( ) ) );
+
+ }
+ }
+ }
+
+ if( m_pDisplayedWidget )
+ {
+ bool b = m_pDisplayedWidget->signalsBlocked( );
+ m_pDisplayedWidget->blockSignals( true );
+ m_pDisplayedWidget->displayObject( obj );
+ m_pDisplayedWidget->blockSignals( b );
+
+ m_pHelpButton->setEnabled( !m_pDisplayedWidget->helpTopic( ).isNull() );
+
+ if( !m_pDisplayedWidget->isVisible( ) )
+ m_pDisplayedWidget->show( );
+ if( obj && updateDescription )
+ {
+ m_pPixmapLabel->setPixmap( SmallIcon( obj->pixmap( ), PMFactory::instance( ) ) );
+ m_pObjectTypeLabel->setText( obj->description( ) );
+ }
+ slotSizeChanged( );
+ }
+
+ if( old )
+ delete old;
+
+ m_pApplyButton->setEnabled( false );
+ m_pCancelButton->setEnabled( false );
+ m_pHelpButton->setEnabled( !PMDocumentationMap::theMap( )
+ ->povrayDocumentationPath( ).isEmpty( ) );
+
+ m_unsavedData = false;
+}
+
+void PMDialogView::keyPressEvent( QKeyEvent* ev )
+{
+ if( ( ev->key( ) == Key_Return ) || ( ev->key( ) == Key_Enter ) )
+ slotApply( );
+}
+
+void PMDialogView::slotAboutToRender( )
+{
+ if( m_unsavedData )
+ if( shouldSaveData( ) )
+ slotApply( );
+}
+
+QString PMDialogView::description( ) const
+{
+ return i18n( "Object Properties" );
+}
+
+QString PMDialogViewFactory::description( ) const
+{
+ return i18n( "Object Properties" );
+}
+
+#include "pmdialogview.moc"
diff --git a/kpovmodeler/pmdialogview.h b/kpovmodeler/pmdialogview.h
new file mode 100644
index 00000000..aef224eb
--- /dev/null
+++ b/kpovmodeler/pmdialogview.h
@@ -0,0 +1,163 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMDIALOGEDITVIEW_H
+#define PMDIALOGEDITVIEW_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qwidget.h>
+#include <qscrollview.h>
+#include <kpushbutton.h>
+
+#include "pmviewbase.h"
+#include "pmviewfactory.h"
+
+class PMDialogEditBase;
+class PMObject;
+class PMPart;
+class QGroupBox;
+class QBoxLayout;
+class QLabel;
+
+/**
+ * Helper class for @ref PMDialogView
+ */
+class PMDialogEditContent : public QScrollView
+{
+ Q_OBJECT
+public:
+ PMDialogEditContent( QWidget* parent, const char* name = 0 );
+ void setContents( QWidget* wid );
+ void calculateSize( );
+protected:
+ void resizeEvent( QResizeEvent* );
+private:
+ QWidget* m_pContents;
+};
+
+/**
+ * View to display and modify attributes of objects.
+ *
+ * This class creates the corresponding widget
+ * (subclass of @ref PMDialogEditBase) for the active object and
+ * displays it.
+ */
+class PMDialogView : public PMViewBase
+{
+ Q_OBJECT
+public:
+ /**
+ * Creates a new PMDialogView widget
+ */
+ PMDialogView( PMPart* part, QWidget* parent, const char* name = 0 );
+ /**
+ * Deletes the widget
+ */
+ ~PMDialogView( );
+
+ /** */
+ virtual QString viewType( ) const { return QString( "dialogview" ); }
+ /** */
+ virtual QString description( ) const;
+
+public slots:
+ /**
+ * Called when an object is changed.
+ * Mode is a bit combination of @ref PMChange constants
+ */
+ void slotObjectChanged( PMObject* obj, const int mode, QObject* sender );
+ /**
+ * Called before the scene is rendered
+ */
+ void slotAboutToRender( );
+ /**
+ * Called when the whole documents contents have changed
+ */
+ void slotRefresh( );
+ /**
+ * Clears all data
+ */
+ void slotClear( );
+signals:
+ /**
+ * Signal that is emitted when an object is changed.
+ * Mode is a bit combination of @ref PMChange constants.
+ */
+ void objectChanged( PMObject* obj, const int mode, QObject* sender );
+ /**
+ * Emitted in the destructor
+ */
+ void destroyed( PMDialogView* v );
+
+protected:
+ virtual void keyPressEvent( QKeyEvent* );
+
+private slots:
+ void slotApply( );
+ void slotHelp( );
+ void slotCancel( );
+ void slotDataChanged( );
+ void slotSizeChanged( );
+ void slotControlPointSelectionChanged( );
+
+private:
+ /**
+ * Asks the user to save unsaved data in the displayed widget
+ */
+ bool shouldSaveData( );
+ /**
+ * Displays the object
+ */
+ void displayObject( PMObject* obj, bool updateDescription = true );
+
+ PMDialogEditBase* m_pDisplayedWidget;
+ QBoxLayout* m_pLayout;
+
+ KPushButton* m_pApplyButton;
+ KPushButton* m_pCancelButton;
+ KPushButton* m_pHelpButton;
+
+ QLabel* m_pPixmapLabel;
+ QLabel* m_pObjectTypeLabel;
+
+ PMDialogEditContent* m_pHelper;
+
+ bool m_unsavedData;
+ PMPart* m_pPart;
+};
+
+/**
+ * Factory class for dialog views
+ */
+class PMDialogViewFactory : public PMViewTypeFactory
+{
+public:
+ PMDialogViewFactory( ) { }
+ virtual QString viewType( ) const { return QString( "dialogview" ); }
+ virtual QString description( ) const;
+ virtual QString iconName( ) const { return QString( "pmdialogview" ); }
+ virtual PMViewBase* newInstance( QWidget* parent, PMPart* part ) const
+ {
+ return new PMDialogView( part, parent );
+ }
+};
+
+#endif
diff --git a/kpovmodeler/pmdisc.cpp b/kpovmodeler/pmdisc.cpp
new file mode 100644
index 00000000..d276e541
--- /dev/null
+++ b/kpovmodeler/pmdisc.cpp
@@ -0,0 +1,440 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Leonardo Skorianez
+ email : lsk@if.ufrj.br
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmdisc.h"
+
+#include "pmxmlhelper.h"
+#include "pmboxedit.h"
+#include "pmmemento.h"
+#include "pmdistancecontrolpoint.h"
+#include "pmvectorcontrolpoint.h"
+#include "pm3dcontrolpoint.h"
+#include "pmdefaults.h"
+
+#include <klocale.h>
+
+#include "pmdiscedit.h"
+
+const double defaultDiscRadius = 1.0;
+const double defaultDiscHoleRadius = 0.0;
+const PMVector defaultDiscCenter = PMVector ( 0.0, 0.0, 0.0 );
+const PMVector defaultDiscNormal = PMVector ( 0.0, 1.0, 0.0 );
+
+/** default disc structure */
+PMViewStructure* PMDisc::s_pDefaultViewStructure = 0;
+int PMDisc::s_numSteps = c_defaultDiscSteps;
+int PMDisc::s_parameterKey = 0;
+
+PMDefinePropertyClass( PMDisc, PMDiscProperty );
+
+PMMetaObject* PMDisc::s_pMetaObject = 0;
+PMObject* createNewDisc( PMPart* part )
+{
+ return new PMDisc( part );
+}
+
+PMDisc::PMDisc( PMPart* part )
+ : Base( part )
+{
+ m_center = defaultDiscCenter;
+ m_normal = defaultDiscNormal;
+ m_radius = defaultDiscRadius;
+ m_hradius = defaultDiscHoleRadius;
+}
+
+PMDisc::PMDisc( const PMDisc& d )
+ : Base( d )
+{
+ m_center = d.m_center;
+ m_normal = d.m_normal;
+ m_radius = d.m_radius;
+ m_hradius = d.m_hradius;
+}
+
+
+PMDisc::~PMDisc( )
+{
+}
+
+QString PMDisc::description( ) const
+{
+ return i18n( "disc" );
+}
+
+void PMDisc::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "center", m_center.serializeXML( ) );
+ e.setAttribute( "normal", m_normal.serializeXML( ) );
+ e.setAttribute( "radius", m_radius );
+ e.setAttribute( "hole_radius", m_hradius );
+ Base::serialize( e, doc );
+}
+
+void PMDisc::readAttributes( const PMXMLHelper& h )
+{
+ m_center = h.vectorAttribute( "center", defaultDiscCenter );
+ m_normal = h.vectorAttribute( "normal", defaultDiscNormal );
+ m_radius = h.doubleAttribute( "radius", defaultDiscRadius );
+ m_hradius = h.doubleAttribute( "hole_radius", defaultDiscHoleRadius );
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMDisc::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Disc", Base::metaObject( ),
+ createNewDisc );
+ s_pMetaObject->addProperty(
+ new PMDiscProperty( "center", &PMDisc::setCenter, &PMDisc::center ) );
+ s_pMetaObject->addProperty(
+ new PMDiscProperty( "normal", &PMDisc::setNormal, &PMDisc::normal ) );
+ s_pMetaObject->addProperty(
+ new PMDiscProperty( "radius", &PMDisc::setRadius, &PMDisc::radius ) );
+ s_pMetaObject->addProperty(
+ new PMDiscProperty( "holeRadius", &PMDisc::setHoleRadius, &PMDisc::holeRadius ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMDisc::setCenter( const PMVector& c )
+{
+ if( c != m_center )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMCenterID, m_center );
+
+ m_center = c;
+ m_center.resize( 3 );
+
+ setViewStructureChanged( );
+ }
+}
+
+void PMDisc::setNormal( const PMVector& p )
+{
+ if( p != m_normal )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMNormalID, m_normal );
+
+ m_normal = p;
+ m_normal.resize( 3 );
+
+ setViewStructureChanged( );
+ }
+}
+
+void PMDisc::setRadius( double radius )
+{
+ if( m_radius != radius )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMRadiusID, m_radius );
+
+ if( radius <= m_hradius )
+ m_radius = m_hradius;
+ else
+ m_radius = radius;
+
+ setViewStructureChanged( );
+ }
+}
+
+void PMDisc::setHoleRadius( double hradius )
+{
+ if( m_hradius != hradius )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMHRadiusID, m_hradius );
+
+ if( hradius >= m_radius )
+ m_hradius = m_radius;
+ else if( hradius <= 0.0 )
+ m_hradius = 0.0;
+ else
+ m_hradius = hradius;
+
+ setViewStructureChanged( );
+ }
+}
+
+PMDialogEditBase* PMDisc::editWidget( QWidget* parent ) const
+{
+ return new PMDiscEdit( parent );
+}
+
+void PMDisc::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMCenterID:
+ setCenter( data->vectorData( ) );
+ break;
+ case PMNormalID:
+ setNormal( data->vectorData( ) );
+ break;
+ case PMRadiusID:
+ setRadius( data->doubleData( ) );
+ break;
+ case PMHRadiusID:
+ setHoleRadius( data->doubleData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMDisc::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
+bool PMDisc::isDefault( )
+{
+ if( ( m_center == defaultDiscCenter ) && ( m_normal == defaultDiscNormal )
+ && ( m_radius == defaultDiscRadius ) && ( m_hradius == defaultDiscHoleRadius )
+ && globalDetail( ) )
+ return true;
+ return false;
+}
+
+void PMDisc::createViewStructure( )
+{
+ if( !m_pViewStructure )
+ {
+ m_pViewStructure = new PMViewStructure( defaultViewStructure ( ) );
+ m_pViewStructure->points( ).detach( );
+ }
+
+ int steps = (int)( ( (float)s_numSteps / 2 ) * ( displayDetail( ) + 1 ) );
+ unsigned size = steps * 2;
+
+ if( size != m_pViewStructure->points( ).size( ) )
+ {
+ m_pViewStructure->points( ).resize( size );
+ m_pViewStructure->lines( ).detach( );
+ m_pViewStructure->lines( ).resize( size );
+ createLines( m_pViewStructure->lines( ), steps );
+ }
+ createPoints( m_pViewStructure->points( ), m_center, m_normal, m_radius, m_hradius, steps );
+}
+
+PMViewStructure* PMDisc::defaultViewStructure( ) const
+{
+ if( !s_pDefaultViewStructure || s_pDefaultViewStructure->parameterKey( ) != viewStructureParameterKey( ) )
+ {
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ int steps = (int)( ( (float)s_numSteps / 2 ) * ( globalDetailLevel( ) + 1 ) );
+ s_pDefaultViewStructure = new PMViewStructure( steps * 2 , steps * 2 );
+
+ createPoints( s_pDefaultViewStructure->points( ), defaultDiscCenter, defaultDiscNormal,
+ defaultDiscRadius, defaultDiscHoleRadius, steps );
+
+ createLines( s_pDefaultViewStructure->lines( ), steps );
+ }
+ return s_pDefaultViewStructure;
+}
+
+void PMDisc::createLines( PMLineArray& lines, int steps )
+{
+ int i;
+ for( i = 0; i < ( steps - 1) ; i++ )
+ {
+ lines[ i ] = PMLine( i, i + 1 );
+ lines[ i + steps ] = PMLine( i + steps, i + steps + 1 );
+ }
+ lines[ i ] = PMLine( i , 0 );
+ lines[i + steps] = PMLine( i + steps, steps );
+}
+
+void PMDisc::createPoints( PMPointArray& points, const PMVector& center,
+ const PMVector& normal, double radius , double hradius, int steps )
+{
+ PMVector pv = normal;
+ double pl = pv.abs( );
+ if( approxZero( pl ) )
+ pv = PMVector( 0.0 , 1.0 , 0.0 );
+ else
+ pv /= pl;
+
+ double angle = ( 2.0 * M_PI ) / ( double ) steps;
+ PMMatrix rotation = PMMatrix::rotation( pv , angle );
+ PMVector endP = pv.orthogonal( );
+
+ for( int i = 0 ; i < steps ; i++ )
+ {
+ points[ i ] = PMPoint( ( endP * radius ) + center );
+ points[ i + steps ] = PMPoint( ( endP * hradius ) + center );
+ endP = rotation * endP;
+ }
+}
+
+void setVectorBase( PMVector pn , PMVector& vn , PMVector& v1, PMVector& v2 )
+{
+ double pl = pn.abs( );
+ if( approxZero( pl ) )
+ vn = PMVector( 0.0 , 1.0 , 0.0 );
+ else
+ vn = ( pn / pl );
+
+ v1 = vn.orthogonal( );
+ v2 = PMVector::cross( vn, v1 );
+}
+
+void PMDisc::controlPoints( PMControlPointList & list )
+{
+ PMVector vetN , vet1 , vet2 ;
+ setVectorBase( m_normal , vetN , vet1 , vet2 );
+
+ PM3DControlPoint* pb = new PM3DControlPoint( m_center, PMCenterID, i18n( "Center" ) );
+ list.append( pb );
+
+ PMDistanceControlPoint* d;
+ d = new PMDistanceControlPoint( pb , vet1, m_radius, PMRadiusID, i18n( "Radius (1)" ) );
+ list.append( d );
+ d = new PMDistanceControlPoint( pb , vet2, m_radius, PMRadiusID, i18n( "Radius (2)" ) );
+ list.append( d );
+ d = new PMDistanceControlPoint( pb , vet1, m_hradius, PMHRadiusID, i18n( "Hole Radius (1)" ) );
+ list.append( d );
+ d = new PMDistanceControlPoint( pb , vet2, m_hradius, PMHRadiusID, i18n( "Hole Radius (2)" ) );
+ list.append( d );
+
+ list.append( new PMVectorControlPoint( pb, m_normal, PMNormalID, i18n( "Normal" ) ) );
+}
+
+void PMDisc::controlPointsChanged( PMControlPointList & list )
+{
+ PMControlPoint* p;
+ bool radius1Changed = false;
+ bool radius2Changed = false;
+ bool pointChanged = false;
+ PMVector pt;
+
+ for( p = list.first( ); p; p = list.next( ) )
+ {
+ if( p->changed( ) )
+ {
+ switch( p->id( ) )
+ {
+ case PMCenterID:
+ pt =( (PM3DControlPoint* ) p)->point( ) ;
+ setCenter( pt );
+ pointChanged = true;
+ break;
+ case PMNormalID:
+ setNormal( ( ( (PM3DControlPoint* ) p)->point( ) ) );
+ pointChanged = true;
+ break;
+ case PMRadiusID:
+ setRadius( ( ( PMDistanceControlPoint *) p )->distance( ) );
+ radius1Changed = true;
+ break;
+ case PMHRadiusID:
+ setHoleRadius( ( ( PMDistanceControlPoint *) p )->distance( ) );
+ radius2Changed = true;
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMDisc::controlPointsChanged\n";
+ break;
+ }
+ }
+ }
+
+ if( radius1Changed )
+ for( p = list.first( ); p; p = list.next( ) )
+ if( p->id( ) == PMRadiusID )
+ ( ( PMDistanceControlPoint *) p)->setDistance( m_radius );
+
+ if( radius2Changed )
+ for( p = list.first( ); p; p = list.next( ) )
+ if( p->id( ) == PMHRadiusID )
+ ( ( PMDistanceControlPoint *) p)->setDistance( m_hradius );
+
+ if( pointChanged )
+ {
+ PMVector vetN, vet1, vet2;
+ setVectorBase( m_normal , vetN, vet1, vet2 );
+
+ bool firstPoint1 = true;
+ bool firstPoint2 = true;
+
+ for( p = list.first( ); p; p = list.next( ) )
+ {
+ if( p->id( ) == PMRadiusID )
+ {
+ if( firstPoint1 )
+ {
+ ( ( PMDistanceControlPoint *) p)->setDirection( vet1 );
+ firstPoint1 = false;
+ }
+ else
+ ( ( PMDistanceControlPoint *) p)->setDirection( vet2 );
+ }
+ if( p->id( ) == PMHRadiusID )
+ {
+ if( firstPoint2 )
+ {
+ ( ( PMDistanceControlPoint *) p)->setDirection( vet1 );
+ firstPoint2 = false;
+ }
+ else
+ ( ( PMDistanceControlPoint *) p)->setDirection( vet2 );
+ }
+ }
+ }
+}
+
+void PMDisc::setSteps( int s )
+{
+ if( s >= 4 )
+ {
+ s_numSteps = s;
+ if( s_pDefaultViewStructure )
+ {
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ }
+ }
+ else
+ kdDebug( PMArea ) << "PMDisc::setSteps: S must be greater than 3\n";
+ s_parameterKey++;
+}
+
+void PMDisc::cleanUp( ) const
+{
+ if( s_pDefaultViewStructure )
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
diff --git a/kpovmodeler/pmdisc.h b/kpovmodeler/pmdisc.h
new file mode 100644
index 00000000..35cb0081
--- /dev/null
+++ b/kpovmodeler/pmdisc.h
@@ -0,0 +1,180 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Leonardo Skorianez
+ email : lsk@if.ufrj.br
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMDISC_H
+#define PMDISC_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmgraphicalobject.h"
+#include "pmvector.h"
+#include "pmviewstructure.h"
+
+/**
+ * Class for povray disc
+ */
+
+class PMDisc : public PMGraphicalObject
+{
+ typedef PMGraphicalObject Base;
+public:
+ /**
+ * Creates a disc
+ */
+ PMDisc( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMDisc( const PMDisc& d );
+
+ /**
+ * Deletes the disc
+ */
+ virtual ~PMDisc( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMDisc( *this ); }
+
+ /** */
+ virtual QString description( ) const;
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMDiscEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmdisc" ); }
+
+ /**
+ * Return the center
+ */
+ PMVector center( ) const { return m_center; }
+ /**
+ * Sets center
+ */
+ void setCenter( const PMVector& c );
+ /**
+ * Return the normal
+ */
+ PMVector normal( ) const { return m_normal; }
+ /**
+ * Sets normal
+ */
+ void setNormal( const PMVector& p );
+ /**
+ * Return the radius
+ */
+ double radius( ) const { return m_radius; }
+ /**
+ * Sets the radius
+ */
+ void setRadius( double radius );
+ /**
+ * Return the hole radius
+ */
+ double holeRadius( ) const { return m_hradius; }
+ /**
+ * Sets the hole radius
+ */
+ void setHoleRadius( double hradius );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /** */
+ virtual void controlPoints( PMControlPointList& list );
+ /** */
+ virtual void controlPointsChanged( PMControlPointList& list );
+ /** */
+ virtual bool hasDisplayDetail( ) const { return true; }
+
+ /**
+ * Returns the number of lines for rendering
+ */
+ static int steps( ) { return s_numSteps; }
+ /**
+ * Sets the number of lines for rendering
+ */
+ static void setSteps( int s );
+ /** */
+ virtual void cleanUp( ) const;
+
+protected:
+ /** */
+ virtual bool isDefault( );
+ /** */
+ virtual void createViewStructure( );
+ /** */
+ virtual PMViewStructure* defaultViewStructure( ) const;
+ /** */
+ virtual int viewStructureParameterKey( ) const { return s_parameterKey+ globalDetailKey(); }
+
+private:
+ /**
+ * Creates the lines for the view structure
+ */
+ static void createLines( PMLineArray& lines, int steps );
+ /**
+ * Creates the points for the view structure
+ */
+ static void createPoints( PMPointArray& points, const PMVector& center,
+ const PMVector& normal, double radius , double hradius, int steps );
+
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMPlaneMementoID { PMCenterID, PMNormalID, PMRadiusID, PMHRadiusID };
+ /**
+ * center of disc
+ */
+ PMVector m_center;
+ /**
+ * normal of disc
+ */
+ PMVector m_normal;
+ /**
+ * radius of disc
+ */
+ double m_radius;
+ /**
+ * hole radius of disc
+ */
+ double m_hradius;
+ /**
+ * The default view structure. It can be shared between planes
+ */
+ static PMViewStructure* s_pDefaultViewStructure;
+ static int s_numSteps;
+ static int s_parameterKey;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmdiscedit.cpp b/kpovmodeler/pmdiscedit.cpp
new file mode 100644
index 00000000..109c3d66
--- /dev/null
+++ b/kpovmodeler/pmdiscedit.cpp
@@ -0,0 +1,147 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Leonardo Skorianez
+ email : lsk@if.ufrj.br
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmdiscedit.h"
+#include "pmdisc.h"
+#include "pmvectoredit.h"
+#include "pmlineedits.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+PMDiscEdit::PMDiscEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMDiscEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* layout;
+ QGridLayout* gl;
+
+ m_pCenter = new PMVectorEdit( "x", "y", "z", this );
+ m_pNormal = new PMVectorEdit( "x", "y", "z", this );
+ m_pHRadius = new PMFloatEdit( this );
+ m_pHRadius->setValidation( true, 0.0, false, 0.0 );
+ m_pRadius = new PMFloatEdit( this );
+ m_pRadius->setValidation( true, 0.0, false, 0.0 );
+
+ gl = new QGridLayout( topLayout( ), 2, 2 );
+ gl->addWidget( new QLabel( i18n( "Center:" ), this ), 0, 0 );
+ gl->addWidget( m_pCenter, 0, 1 );
+ gl->addWidget( new QLabel( i18n( "Normal:" ), this ), 1, 0 );
+ gl->addWidget( m_pNormal, 1, 1 );
+
+ layout = new QHBoxLayout( topLayout( ) );
+ gl = new QGridLayout( layout, 2, 2 );
+ gl->addWidget( new QLabel( i18n( "Radius:" ), this ), 0, 0 );
+ gl->addWidget( m_pRadius, 0, 1 );
+ gl->addWidget( new QLabel( i18n( "Hole radius:" ), this ), 1, 0 );
+ gl->addWidget( m_pHRadius, 1, 1 );
+ layout->addStretch( 1 );
+
+ QPushButton* nb = new QPushButton( i18n( "Normalize" ), this );
+ layout = new QHBoxLayout( topLayout( ) );
+ layout->addWidget( nb );
+ layout->addStretch( 1 );
+
+ connect( m_pCenter, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pNormal, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pRadius, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pHRadius, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( nb, SIGNAL( clicked( ) ), SLOT( slotNormalize( ) ) );
+}
+
+void PMDiscEdit::slotNormalize( )
+{
+ PMVector normal = m_pNormal->vector( );
+ double l = normal.abs( );
+ if( !approxZero( l ) )
+ m_pNormal->setVector( normal / l );
+}
+
+
+void PMDiscEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Disc" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMDisc* ) o;
+
+ m_pCenter->setVector( m_pDisplayedObject->center( ) );
+ m_pNormal->setVector( m_pDisplayedObject->normal( ) );
+ m_pRadius->setValue( m_pDisplayedObject->radius( ) );
+ m_pHRadius->setValue( m_pDisplayedObject->holeRadius( ) );
+
+ m_pCenter->setReadOnly( readOnly );
+ m_pNormal->setReadOnly( readOnly );
+ m_pRadius->setReadOnly( readOnly );
+ m_pHRadius->setReadOnly( readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMDiscEdit: Can't display object\n";
+}
+
+void PMDiscEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setCenter( m_pCenter->vector( ) );
+ m_pDisplayedObject->setNormal( m_pNormal->vector( ) );
+ m_pDisplayedObject->setRadius( m_pRadius->value( ) );
+ m_pDisplayedObject->setHoleRadius( m_pHRadius->value( ) );
+ }
+}
+
+bool PMDiscEdit::isDataValid( )
+{
+ if( m_pNormal->isDataValid( ) )
+ {
+ if( approxZero( m_pNormal->vector( ).abs( ) ) )
+ {
+ KMessageBox::error( this, i18n( "The normal vector may not be a "
+ "null vector." ),
+ i18n( "Error" ) );
+ return false;
+ }
+ if( m_pCenter->isDataValid( ) )
+ if( m_pRadius->isDataValid( ) )
+ if( m_pHRadius->isDataValid( ) )
+ if( m_pRadius->value( ) >= m_pHRadius->value( ) )
+ return Base::isDataValid( );
+ else
+ {
+ KMessageBox::error( this, i18n( "The radius may not be smaller "
+ "than the hole radius." ),
+ i18n( "Error" ) );
+ m_pRadius->setFocus( );
+ }
+ }
+ return false;
+}
+
+#include "pmdiscedit.moc"
diff --git a/kpovmodeler/pmdiscedit.h b/kpovmodeler/pmdiscedit.h
new file mode 100644
index 00000000..bc603ddc
--- /dev/null
+++ b/kpovmodeler/pmdiscedit.h
@@ -0,0 +1,67 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Leonardo Skorinaez
+ email : lsk@if.ufrj.br
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMDISCEDIT_H
+#define PMDISCEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmgraphicalobjectedit.h"
+
+class PMVectorEdit;
+class PMFloatEdit;
+class PMDisc;
+
+class PMDiscEdit : public PMGraphicalObjectEdit
+{
+ Q_OBJECT
+ typedef PMGraphicalObjectEdit Base;
+public:
+ /**
+ * Creates a PMPlaneEdit with parent and name
+ */
+ PMDiscEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+protected slots:
+ /**
+ * Normalizes the vector
+ */
+ void slotNormalize( );
+
+private:
+ PMDisc* m_pDisplayedObject;
+ PMVectorEdit* m_pCenter;
+ PMVectorEdit* m_pNormal;
+ PMFloatEdit* m_pRadius;
+ PMFloatEdit* m_pHRadius;
+};
+#endif
diff --git a/kpovmodeler/pmdistancecontrolpoint.cpp b/kpovmodeler/pmdistancecontrolpoint.cpp
new file mode 100644
index 00000000..dbd8b881
--- /dev/null
+++ b/kpovmodeler/pmdistancecontrolpoint.cpp
@@ -0,0 +1,92 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmdistancecontrolpoint.h"
+#include "pmmath.h"
+#include "pmdebug.h"
+#include <math.h>
+
+
+PMDistanceControlPoint::PMDistanceControlPoint( PMControlPoint* base,
+ const PMVector& direction, double distance,
+ int id, const QString& description,
+ bool showExtraLine )
+ : PMControlPoint( id, description )
+{
+ m_distance = distance;
+ m_pBasePoint = base;
+ m_direction = direction;
+ m_directionLength = direction.abs( );
+ m_extraLine = showExtraLine;
+}
+
+PMDistanceControlPoint::PMDistanceControlPoint( const PMVector& base,
+ const PMVector& direction, double distance,
+ int id, const QString& description,
+ bool showExtraLine )
+ : PMControlPoint( id, description )
+{
+ m_distance = distance;
+ m_constBasePoint = base;
+ m_pBasePoint = 0;
+ m_direction = direction;
+ m_directionLength = direction.abs( );
+ m_extraLine = showExtraLine;
+}
+
+PMVector PMDistanceControlPoint::position( ) const
+{
+ if( m_pBasePoint )
+ return m_pBasePoint->position( ) + m_direction * m_distance;
+ return m_constBasePoint + m_direction * m_distance;
+}
+
+PMVector PMDistanceControlPoint::basePoint( ) const
+{
+ if( m_pBasePoint )
+ return m_pBasePoint->position( );
+ return m_constBasePoint;
+}
+
+void PMDistanceControlPoint::setDirection( const PMVector& direction )
+{
+ m_direction = direction;
+ m_directionLength = direction.abs( );
+}
+
+void PMDistanceControlPoint::graphicalChangeStarted( )
+{
+ m_originalDistance = m_distance;
+}
+
+void PMDistanceControlPoint::graphicalChange( const PMVector& startPoint,
+ const PMVector& /*viewNormal*/,
+ const PMVector& endPoint )
+{
+ if( !approxZero( m_directionLength ) )
+ m_distance = m_originalDistance +
+ PMVector::dot( endPoint - startPoint, m_direction )
+ / ( m_directionLength * m_directionLength );
+}
+
+void PMDistanceControlPoint::snapToGrid( )
+{
+ double d = moveGrid( );
+ if( !approxZero( d ) )
+ m_distance = rint( m_distance / d ) * d;
+ setChanged( );
+}
diff --git a/kpovmodeler/pmdistancecontrolpoint.h b/kpovmodeler/pmdistancecontrolpoint.h
new file mode 100644
index 00000000..f5e28fff
--- /dev/null
+++ b/kpovmodeler/pmdistancecontrolpoint.h
@@ -0,0 +1,110 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMDISTANCECONTROLPOINT_H
+#define PMDISTANCECONTROLPOINT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include "pmcontrolpoint.h"
+
+/**
+ * Class for distance control points
+ */
+class PMDistanceControlPoint : public PMControlPoint
+{
+public:
+ /**
+ * Creates a PMDistanceControlPoint with id.
+ *
+ * The base point of the vector is given by the control point location.
+ */
+ PMDistanceControlPoint( PMControlPoint* location, const PMVector& direction,
+ double distance, int id, const QString& description,
+ bool extraLine = false );
+ /**
+ * Creates a PMDistanceControlPoint with id.
+ *
+ * The base point of the vector is given by the vector p.
+ */
+ PMDistanceControlPoint( const PMVector& location, const PMVector& direction,
+ double distance, int id, const QString& description,
+ bool extraLine = false );
+
+ /**
+ * Deletes the PMDistanceControlPoint
+ */
+ virtual ~PMDistanceControlPoint( ) { };
+
+ /** */
+ virtual PMVector position( ) const;
+
+ /**
+ * Sets the distance
+ */
+ void setDistance( double distance ) { m_distance = distance; }
+ /**
+ * returns the distance
+ */
+ double distance( ) const { return m_distance; }
+ /**
+ * Sets the direction
+ */
+ void setDirection( const PMVector& d );
+ /**
+ * Returns the direction
+ */
+ PMVector direction( ) const { return m_direction; }
+ /**
+ * Returns the base point
+ */
+ PMVector basePoint( ) const;
+
+ /** */
+ virtual bool hasExtraLine( ) const { return m_extraLine; }
+ /**
+ * Returns the start point of the extra line
+ */
+ virtual PMVector extraLineStart( ) const { return basePoint( ); }
+ /**
+ * Returns the end point of the extra line
+ */
+ virtual PMVector extraLineEnd( ) const { return position( ); }
+
+ /** */
+ virtual void snapToGrid( );
+protected:
+ /** */
+ virtual void graphicalChangeStarted( );
+ /** */
+ virtual void graphicalChange( const PMVector& startPoint,
+ const PMVector& viewNormal,
+ const PMVector& endPoint );
+private:
+ double m_distance, m_originalDistance;
+ PMControlPoint* m_pBasePoint;
+ PMVector m_constBasePoint;
+ PMVector m_direction;
+ double m_directionLength;
+ bool m_extraLine;
+};
+
+#endif
diff --git a/kpovmodeler/pmdockwidget.cpp b/kpovmodeler/pmdockwidget.cpp
new file mode 100644
index 00000000..625ea6bc
--- /dev/null
+++ b/kpovmodeler/pmdockwidget.cpp
@@ -0,0 +1,2549 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Max Judin <novaprint@mtu-net.ru>
+ Modified 2002 Andreas Zehender <zehender@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#include "pmdockwidget.h"
+#include "pmdockwidget_private.h"
+
+#include <qapplication.h>
+#include <qlayout.h>
+#include <qpainter.h>
+#include <qobjectlist.h>
+#include <qstrlist.h>
+#include <qcursor.h>
+#include <qwidgetlist.h>
+#include <qtabwidget.h>
+#include <qstyle.h>
+
+#ifndef NO_KDE2
+#include <kconfig.h>
+#include <kglobal.h>
+#include <ktoolbar.h>
+#include <kpopupmenu.h>
+#include <kwin.h>
+#include <kdebug.h>
+#ifdef Q_WS_X11
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#endif
+#else
+#include <qapplication.h>
+#include <qtoolbar.h>
+#include <qpopupmenu.h>
+#endif
+
+#include "pmdebug.h"
+
+#include <kparts/event.h>
+#include <kparts/part.h>
+#include <kaccel.h>
+#include <kparts/plugin.h>
+#include <kstatusbar.h>
+#include <kinstance.h>
+#include <khelpmenu.h>
+#include <kstandarddirs.h>
+#include <qapplication.h>
+#include <kdebug.h>
+#include <kxmlguifactory.h>
+
+#include <assert.h>
+
+#define DOCK_CONFIG_VERSION "0.0.5"
+
+static const char* const close_xpm[]={
+"7 7 2 1",
+"# c black",
+". c None",
+".......",
+"##..##.",
+".####..",
+"..##...",
+".####..",
+"##..##.",
+"......."};
+
+static const char* const todesktop_xpm[]={
+"5 5 2 1",
+"# c black",
+". c None",
+"####.",
+"##...",
+"#.#..",
+"#..#.",
+"....#"};
+
+static const char* const dockback_xpm[]={
+"5 5 2 1",
+"# c black",
+". c None",
+"#....",
+".#..#",
+"..#.#",
+"...##",
+".####"};
+
+static const char* const not_close_xpm[]={
+"5 5 2 1",
+"# c black",
+". c None",
+"#####",
+"#...#",
+"#...#",
+"#...#",
+"#####"};
+
+class PMDockMainWindowPrivate
+{
+public:
+ PMDockMainWindowPrivate()
+ {
+ m_activePart = 0;
+ m_bShellGUIActivated = false;
+ m_helpMenu = 0;
+ }
+ ~PMDockMainWindowPrivate()
+ {
+ }
+
+ QGuardedPtr<Part> m_activePart;
+ bool m_bShellGUIActivated;
+ KHelpMenu *m_helpMenu;
+};
+
+
+/**
+ * A special kind of KMainWindow that is able to have dockwidget child widgets.
+ *
+ * The main widget should be a dockwidget where other dockwidgets can be docked to
+ * the left, right, top, bottom or to the middle.
+ * Furthermore, the PMDockMainWindow has got the KDocManager and some data about the dock states.
+ *
+ * @author Max Judin.
+*/
+PMDockMainWindow::PMDockMainWindow( QWidget* parent, const char *name, WFlags f)
+:KMainWindow( parent, name, f )
+{
+ QString new_name = QString(name) + QString("_DockManager");
+ dockManager = new PMDockManager( this, new_name.latin1() );
+ mainDockWidget = 0L;
+
+ d = new PMDockMainWindowPrivate( );
+ PartBase::setPartObject( this );
+}
+
+PMDockMainWindow::~PMDockMainWindow()
+{
+ delete dockManager;
+ delete d;
+}
+
+// kparts/dockmainwindow stuff
+void PMDockMainWindow::createGUI( Part * part )
+{
+ kdDebug(1000) << QString("DockMainWindow::createGUI for %1").arg(part?part->name():"0L") << endl;
+
+ KXMLGUIFactory *factory = guiFactory();
+
+ setUpdatesEnabled( false );
+
+ QPtrList<Plugin> plugins;
+
+ if ( d->m_activePart )
+ {
+ kdDebug(1000) << QString("deactivating GUI for %1").arg(d->m_activePart->name()) << endl;
+
+ GUIActivateEvent ev( false );
+ QApplication::sendEvent( d->m_activePart, &ev );
+
+ factory->removeClient( d->m_activePart );
+
+ disconnect( d->m_activePart, SIGNAL( setWindowCaption( const QString & ) ),
+ this, SLOT( setCaption( const QString & ) ) );
+ disconnect( d->m_activePart, SIGNAL( setStatusBarText( const QString & ) ),
+ this, SLOT( slotSetStatusBarText( const QString & ) ) );
+ }
+
+ if( !d->m_bShellGUIActivated )
+ {
+ loadPlugins( this, this, KGlobal::instance() );
+ createShellGUI();
+ d->m_bShellGUIActivated = true;
+ }
+
+ if ( part )
+ {
+ // do this before sending the activate event
+ connect( part, SIGNAL( setWindowCaption( const QString & ) ),
+ this, SLOT( setCaption( const QString & ) ) );
+ connect( part, SIGNAL( setStatusBarText( const QString & ) ),
+ this, SLOT( slotSetStatusBarText( const QString & ) ) );
+
+ factory->addClient( part );
+
+ GUIActivateEvent ev( true );
+ QApplication::sendEvent( part, &ev );
+
+ }
+
+ setUpdatesEnabled( true );
+
+ d->m_activePart = part;
+}
+
+void PMDockMainWindow::slotSetStatusBarText( const QString & text )
+{
+ statusBar()->message( text );
+}
+
+void PMDockMainWindow::createShellGUI( bool create )
+{
+ bool bAccelAutoUpdate = accel()->setAutoUpdate( false );
+ assert( d->m_bShellGUIActivated != create );
+ d->m_bShellGUIActivated = create;
+
+ if ( create )
+ {
+ if ( isHelpMenuEnabled() && !d->m_helpMenu )
+ d->m_helpMenu = new KHelpMenu( this, instance()->aboutData(), true, actionCollection() );
+
+ QString f = xmlFile();
+ setXMLFile( locate( "config", "ui/ui_standards.rc", instance() ) );
+ if ( !f.isEmpty() )
+ setXMLFile( f, true );
+ else
+ {
+ QString auto_file( instance()->instanceName() + "ui.rc" );
+ setXMLFile( auto_file, true );
+ }
+
+ GUIActivateEvent ev( true );
+ QApplication::sendEvent( this, &ev );
+
+ guiFactory()->addClient( this );
+
+ }
+ else
+ {
+ GUIActivateEvent ev( false );
+ QApplication::sendEvent( this, &ev );
+
+ guiFactory()->removeClient( this );
+ }
+ accel()->setAutoUpdate( bAccelAutoUpdate );
+}
+// end kparts/dockmainwindow
+
+void PMDockMainWindow::setMainDockWidget( PMDockWidget* mdw )
+{
+ if ( mainDockWidget == mdw ) return;
+ mainDockWidget = mdw;
+}
+
+void PMDockMainWindow::setView( QWidget *view )
+{
+ if ( view->isA("PMDockWidget") ){
+ if ( view->parent() != this ) ((PMDockWidget*)view)->applyToWidget( this );
+ }
+
+#ifndef NO_KDE2
+ KMainWindow::setCentralWidget(view);
+#else
+ QMainWindow::setCentralWidget(view);
+#endif
+}
+
+PMDockWidget* PMDockMainWindow::createDockWidget( const QString& name, const QPixmap &pixmap, QWidget* parent, const QString& strCaption, const QString& strTabPageLabel)
+{
+ return new PMDockWidget( dockManager, name.latin1(), pixmap, parent, strCaption, strTabPageLabel );
+}
+
+void PMDockMainWindow::makeDockVisible( PMDockWidget* dock )
+{
+ if ( dock != 0L)
+ dock->makeDockVisible();
+}
+
+void PMDockMainWindow::makeDockInvisible( PMDockWidget* dock )
+{
+ if ( dock != 0L)
+ dock->undock();
+}
+
+void PMDockMainWindow::makeWidgetDockVisible( QWidget* widget )
+{
+ makeDockVisible( dockManager->findWidgetParentDock(widget) );
+}
+
+void PMDockMainWindow::writeDockConfig(QDomElement &base)
+{
+ dockManager->writeConfig(base);
+}
+
+void PMDockMainWindow::readDockConfig(QDomElement &base)
+{
+ dockManager->readConfig(base);
+}
+
+#ifndef NO_KDE2
+void PMDockMainWindow::writeDockConfig( KConfig* c, QString group )
+{
+ dockManager->writeConfig( c, group );
+}
+
+void PMDockMainWindow::readDockConfig( KConfig* c, QString group )
+{
+ dockManager->readConfig( c, group );
+}
+#endif
+
+void PMDockMainWindow::slotDockWidgetUndocked()
+{
+ QObject* pSender = (QObject*) sender();
+ if (!pSender->inherits("PMDockWidget")) return;
+ PMDockWidget* pDW = (PMDockWidget*) pSender;
+ emit dockWidgetHasUndocked( pDW);
+}
+
+/*************************************************************************/
+PMDockWidgetAbstractHeaderDrag::PMDockWidgetAbstractHeaderDrag( PMDockWidgetAbstractHeader* parent, PMDockWidget* dock, const char* name )
+:QFrame( parent, name )
+{
+ dw = dock;
+ installEventFilter( dock->dockManager() );
+}
+/*************************************************************************/
+PMDockWidgetHeaderDrag::PMDockWidgetHeaderDrag( PMDockWidgetAbstractHeader* parent, PMDockWidget* dock, const char* name )
+:PMDockWidgetAbstractHeaderDrag( parent, dock, name )
+{
+}
+
+void PMDockWidgetHeaderDrag::paintEvent( QPaintEvent* )
+{
+ QPainter paint;
+
+ paint.begin( this );
+
+ style().drawPrimitive (QStyle::PE_DockWindowHandle, &paint, QRect(0,0,width(), height()), colorGroup());
+
+ paint.end();
+}
+/*************************************************************************/
+PMDockWidgetAbstractHeader::PMDockWidgetAbstractHeader( PMDockWidget* parent, const char* name )
+:QFrame( parent, name )
+{
+}
+/*************************************************************************/
+PMDockWidgetHeader::PMDockWidgetHeader( PMDockWidget* parent, const char* name )
+:PMDockWidgetAbstractHeader( parent, name )
+{
+ layout = new QHBoxLayout( this );
+ layout->setResizeMode( QLayout::Minimum );
+
+ drag = new PMDockWidgetHeaderDrag( this, parent );
+
+ closeButton = new PMDockButton_Private( this, "DockCloseButton" );
+ closeButton->setPixmap( const_cast< const char** >(close_xpm) );
+ int buttonWidth = 9, buttonHeight = 9;
+ closeButton->setFixedSize(buttonWidth,buttonHeight);
+ connect( closeButton, SIGNAL(clicked()), parent, SIGNAL(headerCloseButtonClicked()));
+ // MODIFICATION (zehender)
+ // The shell will delete the widget
+ // undock is unnecessary
+ // connect( closeButton, SIGNAL(clicked()), parent, SLOT(undock()));
+
+ stayButton = new PMDockButton_Private( this, "DockStayButton" );
+ stayButton->setToggleButton( true );
+ stayButton->setPixmap( const_cast< const char** >(not_close_xpm) );
+ stayButton->setFixedSize(buttonWidth,buttonHeight);
+ connect( stayButton, SIGNAL(clicked()), this, SLOT(slotStayClicked()));
+ stayButton->hide( );
+
+ dockbackButton = new PMDockButton_Private( this, "DockbackButton" );
+ dockbackButton->setPixmap( const_cast< const char** >(dockback_xpm));
+ dockbackButton->setFixedSize(buttonWidth,buttonHeight);
+ connect( dockbackButton, SIGNAL(clicked()), parent, SIGNAL(headerDockbackButtonClicked()));
+ connect( dockbackButton, SIGNAL(clicked()), parent, SLOT(dockBack()));
+
+ // MODIFICATION (zehender)
+ // Add a button to undock the widget and dock it as top level
+ // widget to the desktop
+ toDesktopButton = new PMDockButton_Private( this, "ToDesktopButton" );
+ toDesktopButton->setPixmap( const_cast< const char** >(todesktop_xpm));
+ toDesktopButton->setFixedSize(buttonWidth,buttonHeight);
+ connect( toDesktopButton, SIGNAL(clicked()), parent, SLOT(toDesktop()));
+
+ layout->addWidget( drag );
+ layout->addWidget( dockbackButton );
+ layout->addWidget( toDesktopButton );
+ layout->addWidget( stayButton );
+ layout->addWidget( closeButton );
+ layout->activate();
+ drag->setFixedHeight( layout->minimumSize().height() );
+}
+
+void PMDockWidgetHeader::setTopLevel( bool isTopLevel )
+{
+ if ( isTopLevel ){
+ PMDockWidget* par = (PMDockWidget*)parent();
+ if( par) {
+ if( par->isDockBackPossible())
+ dockbackButton->show();
+ else
+ dockbackButton->hide();
+ }
+ stayButton->hide();
+ closeButton->hide();
+ toDesktopButton->hide();
+ drag->setEnabled( true );
+ } else {
+ dockbackButton->hide();
+ stayButton->hide();
+ closeButton->show();
+ toDesktopButton->show();
+ }
+ layout->activate();
+ updateGeometry();
+}
+
+void PMDockWidgetHeader::setDragPanel( PMDockWidgetHeaderDrag* nd )
+{
+ if ( !nd ) return;
+
+ delete layout;
+ layout = new QHBoxLayout( this );
+ layout->setResizeMode( QLayout::Minimum );
+
+ delete drag;
+ drag = nd;
+
+ layout->addWidget( drag );
+ layout->addWidget( dockbackButton );
+ layout->addWidget( toDesktopButton );
+ layout->addWidget( stayButton );
+ layout->addWidget( closeButton );
+ layout->activate();
+ drag->setFixedHeight( layout->minimumSize().height() );
+}
+
+void PMDockWidgetHeader::slotStayClicked()
+{
+ setDragEnabled(!stayButton->isOn());
+}
+
+bool PMDockWidgetHeader::dragEnabled() const
+{
+ return drag->isEnabled();
+}
+
+void PMDockWidgetHeader::setDragEnabled(bool b)
+{
+ stayButton->setOn(!b);
+ closeButton->setEnabled(b);
+ drag->setEnabled(b);
+}
+
+#ifndef NO_KDE2
+void PMDockWidgetHeader::saveConfig( KConfig* c )
+{
+ c->writeEntry( QString("%1%2").arg(parent()->name()).arg(":stayButton"), stayButton->isOn() );
+}
+
+void PMDockWidgetHeader::loadConfig( KConfig* c )
+{
+ setDragEnabled( !c->readBoolEntry( QString("%1%2").arg(parent()->name()).arg(":stayButton"), false ) );
+}
+#endif
+
+/*************************************************************************/
+PMDockWidget::PMDockWidget( PMDockManager* dockManager, const char* name, const QPixmap &pixmap, QWidget* parent, const QString& strCaption, const QString& strTabPageLabel, WFlags f)
+: QWidget( parent, name, f )
+ ,formerBrotherDockWidget(0L)
+ ,currentDockPos(DockNone)
+ ,formerDockPos(DockNone)
+ ,pix(new QPixmap(pixmap))
+ ,prevSideDockPosBeforeDrag(DockNone)
+{
+ d = new PMDockWidgetPrivate(); // create private data
+
+ d->_parent = parent;
+
+ layout = new QVBoxLayout( this );
+ layout->setResizeMode( QLayout::Minimum );
+
+ manager = dockManager;
+ manager->childDock->append( this );
+ installEventFilter( manager );
+
+ header = 0L;
+ setHeader( new PMDockWidgetHeader( this, "AutoCreatedDockHeader" ) );
+ if( strCaption == 0L)
+ setCaption( name );
+ else
+ setCaption( strCaption);
+
+ if( strTabPageLabel == " ")
+ setTabPageLabel( caption());
+ else
+ setTabPageLabel( strTabPageLabel);
+
+ eDocking = DockFullDocking;
+ sDocking = DockFullSite;
+
+ isGroup = false;
+ isTabGroup = false;
+
+ setIcon( pixmap);
+ widget = 0L;
+
+ QObject::connect(this, SIGNAL(hasUndocked()), manager->main, SLOT(slotDockWidgetUndocked()) );
+ applyToWidget( parent, QPoint(0,0) );
+}
+
+void PMDockWidget::slotSetCaption( const QString& str )
+{
+ setTabPageLabel( str );
+ setCaption( str );
+}
+
+PMDockWidget::~PMDockWidget()
+{
+ if ( !manager->undockProcess ){
+ d->blockHasUndockedSignal = true;
+ undock();
+ d->blockHasUndockedSignal = false;
+ }
+ emit iMBeingClosed();
+ manager->childDock->remove( this );
+ delete pix;
+ delete d; // destroy private data
+}
+
+void PMDockWidget::setHeader( PMDockWidgetAbstractHeader* h )
+{
+ if ( !h ) return;
+
+ if ( header ){
+ delete header;
+ delete layout;
+ header = h;
+ layout = new QVBoxLayout( this );
+ layout->setResizeMode( QLayout::Minimum );
+ layout->addWidget( header );
+ setWidget( widget );
+ } else {
+ header = h;
+ layout->addWidget( header );
+ }
+}
+
+void PMDockWidget::setEnableDocking( int pos )
+{
+ eDocking = pos;
+ updateHeader();
+}
+
+void PMDockWidget::updateHeader()
+{
+ if ( parent() ){
+ if ( (parent() == manager->main) || isGroup || (eDocking == PMDockWidget::DockNone) ){
+ header->hide();
+ } else {
+ header->setTopLevel( false );
+ header->show();
+ }
+ } else {
+ header->setTopLevel( true );
+ header->show();
+ }
+}
+
+void PMDockWidget::applyToWidget( QWidget* s, const QPoint& p )
+{
+ if ( parent() != s )
+ {
+ hide();
+ reparent(s, 0, QPoint(0,0), false);
+ }
+
+ if ( s && s->inherits("PMDockMainWindow") ){
+ ((PMDockMainWindow*)s)->setView( this );
+ }
+
+ if ( s == manager->main ){
+ setGeometry( QRect(QPoint(0,0), manager->main->geometry().size()) );
+ }
+
+ if ( !s )
+ {
+ move(p);
+
+#ifndef NO_KDE2
+#ifdef Q_WS_X11
+ if (d->transient && d->_parent)
+ XSetTransientForHint( qt_xdisplay(), winId(), d->_parent->winId() );
+
+ KWin::setType( winId(), d->windowType );
+#endif
+#endif
+
+ }
+ updateHeader();
+
+ setIcon(*pix);
+}
+
+void PMDockWidget::show()
+{
+ if ( parent() || manager->main->isVisible() )
+ if ( !parent() ){
+ emit manager->setDockDefaultPos( this );
+ emit setDockDefaultPos();
+ if ( parent() ){
+ makeDockVisible();
+ } else {
+ QWidget::show();
+ }
+ } else {
+ QWidget::show();
+ }
+}
+
+#ifndef NO_KDE2
+
+void PMDockWidget::setDockWindowType (NET::WindowType windowType)
+{
+ d->windowType = windowType;
+ applyToWidget( parentWidget(), QPoint(0,0) );
+}
+
+#endif
+
+void PMDockWidget::setDockWindowTransient (QWidget *parent, bool transientEnabled)
+{
+ d->_parent = parent;
+ d->transient = transientEnabled;
+ applyToWidget( parentWidget(), QPoint(0,0) );
+}
+
+bool PMDockWidget::event( QEvent* pevent )
+{
+ switch ( pevent->type() )
+ {
+ #undef FocusIn
+ case QEvent::FocusIn:
+ if (widget && !d->pendingFocusInEvent) {
+ d->pendingFocusInEvent = true;
+ widget->setFocus();
+ }
+ d->pendingFocusInEvent = false;
+ break;
+ case QEvent::ChildRemoved:
+ if ( widget == ((QChildEvent*)pevent)->child() ) widget = 0L;
+ break;
+ case QEvent::Show:
+ if ( widget ) widget->show();
+ emit manager->change();
+ break;
+ case QEvent::Hide:
+ if ( widget ) widget->hide();
+ emit manager->change();
+ break;
+ case QEvent::CaptionChange:
+ if ( parentWidget() ){
+ if ( parent()->inherits("PMDockSplitter") ){
+ ((PMDockSplitter*)(parent()))->updateName();
+ }
+ if ( parentDockTabGroup() ){
+ setDockTabName( parentDockTabGroup() );
+ parentDockTabGroup()->setTabLabel( this, tabPageLabel() );
+ }
+ }
+ break;
+ case QEvent::Close:
+ // MODIFICATION (zehender)
+ // Top level widget is closed
+ // emit same signal as if the widget is docked and closed with
+ // the header button
+ emit headerCloseButtonClicked( );
+ // emit iMBeingClosed();
+ break;
+ default:
+ break;
+ }
+ #undef KeyPress
+ bool processed = QWidget::event( pevent );
+ if( pevent->type( ) == QEvent::AccelOverride && !processed && !parent( ) ){
+ // MODIFICATION (zehender)
+ // floating widget, post event to main window
+ processed = qApp->sendEvent( manager->dockMainWidget( ), pevent );
+ }
+ return processed;
+}
+
+PMDockWidget* PMDockWidget::manualDock( PMDockWidget* target, DockPosition dockPos, int spliPos, QPoint pos, bool check, int tabIndex )
+{
+ if (this == target)
+ return 0L; // docking to itself not possible
+
+ bool succes = true; // tested flag
+
+ // do not dock into a floating widget
+ if( target && !target->parent( ) )
+ target = 0;
+
+ // check allowed this dock submit this operations
+ if ( !(eDocking & (int)dockPos) ){
+ succes = false;
+ }
+
+ // check allowed target submit this operations
+ if ( target && !(target->dockSite( ) & (int)dockPos) ){
+ succes = false;
+ }
+
+ if ( parent() && !parent()->inherits("PMDockSplitter") && !parentDockTabGroup() ){
+ succes = false;
+ }
+
+ // if docking to a tab group, and position is not center
+ // dock to the parent of the tab group
+ if( target && ( dockPos != PMDockWidget::DockCenter )
+ && ( dockPos != PMDockWidget::DockNone ) )
+ {
+ QWidget* pdt = target->parentDockTabGroup( );
+ if( pdt )
+ return manualDock( ( PMDockWidget* ) ( pdt->parent( ) ),
+ dockPos, spliPos, pos, check, tabIndex );
+ }
+
+ if ( !succes ){
+ // try to make another manualDock
+ PMDockWidget* dock_result = 0L;
+ if ( target && !check ){
+ PMDockWidget::DockPosition another__dockPos = PMDockWidget::DockNone;
+ switch ( dockPos ){
+ case PMDockWidget::DockLeft : another__dockPos = PMDockWidget::DockRight ; break;
+ case PMDockWidget::DockRight : another__dockPos = PMDockWidget::DockLeft ; break;
+ case PMDockWidget::DockTop : another__dockPos = PMDockWidget::DockBottom; break;
+ case PMDockWidget::DockBottom: another__dockPos = PMDockWidget::DockTop ; break;
+ default: break;
+ }
+ dock_result = target->manualDock( this, another__dockPos, spliPos, pos, true, tabIndex );
+ }
+ return dock_result;
+ }
+ // end check block
+
+ d->blockHasUndockedSignal = true;
+ undock();
+ d->blockHasUndockedSignal = false;
+
+ if ( !target ){
+ move( pos );
+ show();
+ emit manager->change();
+ return this;
+ }
+
+ PMDockTabGroup* parentTab = target->parentDockTabGroup();
+ if ( parentTab ){
+ // add to existing TabGroup
+ applyToWidget( parentTab );
+ parentTab->insertTab( this, icon() ? *icon() : QPixmap(),
+ tabPageLabel(), tabIndex );
+ setDockTabName( parentTab );
+ if( !toolTipStr.isEmpty())
+ parentTab->setTabToolTip( this, toolTipStr);
+
+ currentDockPos = PMDockWidget::DockCenter;
+ emit manager->change();
+ return (PMDockWidget*)parentTab->parent();
+ }
+
+ // MODIFICATION (Zehender):
+ // If DockPosition is DockLeft or DockRight, add the widget
+ // left or right of the target, so that a new vertical splitter
+ // (a splitter with horizontal widget layout :-) is created
+ // that spawns the full height of the main view
+
+ if( ( dockPos == PMDockWidget::DockLeft ) ||
+ ( dockPos == PMDockWidget::DockRight ) )
+ {
+ PMDockWidget* newTarget = target;
+ bool found = false;
+ QWidget* wtarget = target;
+ while( wtarget && !found )
+ {
+ if( wtarget->inherits( "PMDockWidget" ) )
+ {
+ PMDockWidget* dw = ( PMDockWidget* ) wtarget;
+ newTarget = dw;
+ QWidget* pw = wtarget->parentWidget( );
+ if( pw )
+ {
+ if( pw->inherits( "PMDockSplitter" ) )
+ {
+ PMDockSplitter* ds = ( PMDockSplitter* ) pw;
+ if( ds->splitterOrientation( ) == Vertical )
+ found = true;
+ }
+ }
+ }
+ wtarget = wtarget->parentWidget( );
+ }
+
+ if( newTarget != target )
+ return manualDock( newTarget, dockPos, spliPos, pos, check, tabIndex );
+ }
+
+ // END MODIFICATION
+
+ // create a new dockwidget that will contain the target and this
+ QWidget* parentDock = target->parentWidget();
+ PMDockWidget* newDock = new PMDockWidget( manager, "tempName", QPixmap(""), parentDock );
+ newDock->currentDockPos = target->currentDockPos;
+
+ if ( dockPos == PMDockWidget::DockCenter ){
+ newDock->isTabGroup = true;
+ } else {
+ newDock->isGroup = true;
+ }
+ newDock->eDocking = (target->eDocking & eDocking) & (~(int)PMDockWidget::DockCenter);
+
+ newDock->applyToWidget( parentDock );
+
+ if ( !parentDock ){
+ // dock to a toplevel dockwidget means newDock is toplevel now
+ newDock->move( target->frameGeometry().topLeft() );
+ newDock->resize( target->geometry().size() );
+ if ( target->isVisibleToTLW() ) newDock->show();
+ }
+
+ // redirect the dockback button to the new dockwidget
+ if( target->formerBrotherDockWidget != 0L) {
+ newDock->formerBrotherDockWidget = target->formerBrotherDockWidget;
+ if( formerBrotherDockWidget != 0L)
+ QObject::connect( newDock->formerBrotherDockWidget, SIGNAL(iMBeingClosed()),
+ newDock, SLOT(loseFormerBrotherDockWidget()) );
+ target->loseFormerBrotherDockWidget();
+ }
+ newDock->formerDockPos = target->formerDockPos;
+
+ if ( dockPos == PMDockWidget::DockCenter )
+ {
+ PMDockTabGroup* tab = new PMDockTabGroup( newDock, "_dock_tab");
+ QObject::connect(tab, SIGNAL(currentChanged(QWidget*)), d, SLOT(slotFocusEmbeddedWidget(QWidget*)));
+ newDock->setWidget( tab );
+
+ target->applyToWidget( tab );
+ applyToWidget( tab );
+
+
+ tab->insertTab( target, target->icon() ? *(target->icon()) : QPixmap(),
+ target->tabPageLabel() );
+ if( !target->toolTipString().isEmpty())
+ tab->setTabToolTip( target, target->toolTipString());
+
+ tab->insertTab( this, icon() ? *icon() : QPixmap(),
+ tabPageLabel(), tabIndex );
+ if( !toolTipString().isEmpty())
+ tab->setTabToolTip( this, toolTipString());
+
+ setDockTabName( tab );
+ tab->show();
+
+ currentDockPos = DockCenter;
+ target->formerDockPos = target->currentDockPos;
+ target->currentDockPos = DockCenter;
+ }
+ else {
+ // if to dock not to the center of the target dockwidget,
+ // dock to newDock
+ PMDockSplitter* panner = 0L;
+ if ( dockPos == PMDockWidget::DockTop || dockPos == PMDockWidget::DockBottom ) panner = new PMDockSplitter( newDock, "_dock_split_", Horizontal, spliPos, manager->splitterHighResolution() );
+ if ( dockPos == PMDockWidget::DockLeft || dockPos == PMDockWidget::DockRight ) panner = new PMDockSplitter( newDock, "_dock_split_", Vertical , spliPos, manager->splitterHighResolution() );
+ newDock->setWidget( panner );
+
+ panner->setOpaqueResize(manager->splitterOpaqueResize());
+ panner->setKeepSize(manager->splitterKeepSize());
+ panner->setFocusPolicy( NoFocus );
+ target->applyToWidget( panner );
+ applyToWidget( panner );
+ target->formerDockPos = target->currentDockPos;
+ if ( dockPos == PMDockWidget::DockRight) {
+ panner->activate( target, this );
+ currentDockPos = PMDockWidget::DockRight;
+ target->currentDockPos = PMDockWidget::DockLeft;
+ }
+ else if( dockPos == PMDockWidget::DockBottom) {
+ panner->activate( target, this );
+ currentDockPos = PMDockWidget::DockBottom;
+ target->currentDockPos = PMDockWidget::DockTop;
+ }
+ else if( dockPos == PMDockWidget::DockTop) {
+ panner->activate( this, target );
+ currentDockPos = PMDockWidget::DockTop;
+ target->currentDockPos = PMDockWidget::DockBottom;
+ }
+ else if( dockPos == PMDockWidget::DockLeft) {
+ panner->activate( this, target );
+ currentDockPos = PMDockWidget::DockLeft;
+ target->currentDockPos = PMDockWidget::DockRight;
+ }
+ target->show();
+ show();
+ panner->show();
+ }
+
+ if ( parentDock ){
+ if ( parentDock->inherits("PMDockSplitter") ){
+ PMDockSplitter* sp = (PMDockSplitter*)parentDock;
+ sp->deactivate();
+ if ( sp->getFirst() == target )
+ sp->activate( newDock, 0L );
+ else
+ sp->activate( 0L, newDock );
+ }
+ }
+
+ newDock->show();
+ emit target->docking( this, dockPos );
+ emit manager->replaceDock( target, newDock );
+ emit manager->change();
+
+ return newDock;
+}
+
+PMDockTabGroup* PMDockWidget::parentDockTabGroup() const
+{
+ if ( !parent() ) return 0L;
+ QWidget* candidate = parentWidget()->parentWidget();
+ if ( candidate && candidate->inherits("PMDockTabGroup") ) return (PMDockTabGroup*)candidate;
+ return 0L;
+}
+
+void PMDockWidget::toDesktop()
+{
+ QPoint p = mapToGlobal( QPoint( -30, -30 ) );
+ if( p.x( ) < 0 )
+ p.setX( 0 );
+ if( p.y( ) < 0 )
+ p.setY( 0 );
+ manualDock( 0, DockDesktop, 50, p );
+}
+
+void PMDockWidget::undock()
+{
+ QWidget* parentW = parentWidget();
+ if ( !parentW ){
+ hide();
+ if (!d->blockHasUndockedSignal)
+ emit hasUndocked();
+ return;
+ }
+
+ formerDockPos = currentDockPos;
+ currentDockPos = PMDockWidget::DockDesktop;
+
+ manager->blockSignals(true);
+ manager->undockProcess = true;
+
+ bool isV = parentW->isVisibleToTLW();
+
+ PMDockTabGroup* parentTab = parentDockTabGroup();
+ if ( parentTab ){
+ d->index = parentTab->indexOf( this); // memorize the page position in the tab widget
+ parentTab->removePage( this );
+ formerBrotherDockWidget = (PMDockWidget*)parentTab->page(0);
+ QObject::connect( formerBrotherDockWidget, SIGNAL(iMBeingClosed()),
+ this, SLOT(loseFormerBrotherDockWidget()) );
+ applyToWidget( 0L );
+ if ( parentTab->count() == 1 ){
+
+ // last subdock widget in the tab control
+ PMDockWidget* lastTab = (PMDockWidget*)parentTab->page(0);
+ parentTab->removePage( lastTab );
+ lastTab->applyToWidget( 0L );
+ lastTab->move( parentTab->mapToGlobal(parentTab->frameGeometry().topLeft()) );
+
+ // PMDockTabGroup always have a parent that is a PMDockWidget
+ PMDockWidget* parentOfTab = (PMDockWidget*)parentTab->parent();
+ delete parentTab; // PMDockTabGroup
+
+ QWidget* parentOfDockWidget = parentOfTab->parentWidget();
+ if ( parentOfDockWidget == 0L ){
+ if ( isV ) lastTab->show();
+ } else {
+ if ( parentOfDockWidget->inherits("PMDockSplitter") ){
+ PMDockSplitter* split = (PMDockSplitter*)parentOfDockWidget;
+ lastTab->applyToWidget( split );
+ split->deactivate();
+ if ( split->getFirst() == parentOfTab ){
+ split->activate( lastTab );
+ if ( ((PMDockWidget*)split->parent())->splitterOrientation == Vertical )
+ emit ((PMDockWidget*)split->getAnother(parentOfTab))->docking( parentOfTab, PMDockWidget::DockLeft );
+ else
+ emit ((PMDockWidget*)split->getAnother(parentOfTab))->docking( parentOfTab, PMDockWidget::DockTop );
+ } else {
+ split->activate( 0L, lastTab );
+ if ( ((PMDockWidget*)split->parent())->splitterOrientation == Vertical )
+ emit ((PMDockWidget*)split->getAnother(parentOfTab))->docking( parentOfTab, PMDockWidget::DockRight );
+ else
+ emit ((PMDockWidget*)split->getAnother(parentOfTab))->docking( parentOfTab, PMDockWidget::DockBottom );
+ }
+ split->show();
+ } else {
+ lastTab->applyToWidget( parentOfDockWidget );
+ }
+ lastTab->show();
+ }
+ manager->blockSignals(false);
+ emit manager->replaceDock( parentOfTab, lastTab );
+ lastTab->currentDockPos = parentOfTab->currentDockPos;
+ emit parentOfTab->iMBeingClosed();
+ manager->blockSignals(true);
+ delete parentOfTab;
+
+ } else {
+ setDockTabName( parentTab );
+ }
+ } else {
+/*********************************************************************************************/
+ if ( parentW->inherits("PMDockSplitter") ){
+ PMDockSplitter* parentSplitterOfDockWidget = (PMDockSplitter*)parentW;
+ d->splitPosInPercent = parentSplitterOfDockWidget->separatorPos();
+
+ PMDockWidget* secondWidget = (PMDockWidget*)parentSplitterOfDockWidget->getAnother( this );
+ PMDockWidget* group = (PMDockWidget*)parentSplitterOfDockWidget->parentWidget();
+ formerBrotherDockWidget = secondWidget;
+ applyToWidget( 0L );
+ group->hide();
+
+ if( formerBrotherDockWidget != 0L)
+ QObject::connect( formerBrotherDockWidget, SIGNAL(iMBeingClosed()),
+ this, SLOT(loseFormerBrotherDockWidget()) );
+
+ if ( !group->parentWidget() ){
+ secondWidget->applyToWidget( 0L, group->frameGeometry().topLeft() );
+ secondWidget->resize( group->width(), group->height() );
+ } else {
+ QWidget* obj = group->parentWidget();
+ secondWidget->applyToWidget( obj );
+ if ( obj->inherits("PMDockSplitter") ){
+ PMDockSplitter* parentOfGroup = (PMDockSplitter*)obj;
+ parentOfGroup->deactivate();
+
+ if ( parentOfGroup->getFirst() == group )
+ parentOfGroup->activate( secondWidget );
+ else
+ parentOfGroup->activate( 0L, secondWidget );
+ }
+ }
+ secondWidget->currentDockPos = group->currentDockPos;
+ secondWidget->formerDockPos = group->formerDockPos;
+ delete parentSplitterOfDockWidget;
+ manager->blockSignals(false);
+ emit manager->replaceDock( group, secondWidget );
+ emit group->iMBeingClosed();
+ manager->blockSignals(true);
+ delete group;
+
+ if ( isV ) secondWidget->show();
+ } else {
+ applyToWidget( 0L );
+ }
+/*********************************************************************************************/
+ }
+ manager->blockSignals(false);
+ if (!d->blockHasUndockedSignal)
+ emit manager->change();
+ manager->undockProcess = false;
+
+ if (!d->blockHasUndockedSignal)
+ emit hasUndocked();
+}
+
+void PMDockWidget::setWidget( QWidget* mw )
+{
+ if ( !mw ) return;
+
+ if ( mw->parent() != this ){
+ mw->reparent(this, 0, QPoint(0,0), false);
+ }
+
+ widget = mw;
+ delete layout;
+
+ layout = new QVBoxLayout( this );
+ layout->setResizeMode( QLayout::Minimum );
+
+ layout->addWidget( header );
+ layout->addWidget( widget,1 );
+}
+
+void PMDockWidget::setDockTabName( PMDockTabGroup* tab )
+{
+ QString listOfName;
+ QString listOfCaption;
+ for ( int i = 0; i < tab->count(); ++i ) {
+ QWidget *w = tab->page( i );
+ listOfCaption.append( w->caption() ).append(",");
+ listOfName.append( w->name() ).append(",");
+ }
+ listOfCaption.remove( listOfCaption.length()-1, 1 );
+ listOfName.remove( listOfName.length()-1, 1 );
+
+ tab->parentWidget()->setName( listOfName.utf8() );
+ tab->parentWidget()->setCaption( listOfCaption );
+
+ tab->parentWidget()->repaint( false ); // PMDockWidget->repaint
+ if ( tab->parentWidget()->parent() )
+ if ( tab->parentWidget()->parent()->inherits("PMDockSplitter") )
+ ((PMDockSplitter*)(tab->parentWidget()->parent()))->updateName();
+}
+
+bool PMDockWidget::mayBeHide() const
+{
+ bool f = (parent() != manager->main);
+ return ( !isGroup && !isTabGroup && f && isVisible() && ( eDocking != (int)PMDockWidget::DockNone ) );
+}
+
+bool PMDockWidget::mayBeShow() const
+{
+ bool f = (parent() != manager->main);
+ return ( !isGroup && !isTabGroup && f && !isVisible() );
+}
+
+void PMDockWidget::changeHideShowState()
+{
+ if ( mayBeHide() ){
+ undock();
+ return;
+ }
+
+ if ( mayBeShow() ){
+ if ( manager->main->inherits("PMDockMainWindow") ){
+ ((PMDockMainWindow*)manager->main)->makeDockVisible(this);
+ } else {
+ makeDockVisible();
+ }
+ }
+}
+
+void PMDockWidget::makeDockVisible()
+{
+ if ( parentDockTabGroup() ){
+ parentDockTabGroup()->showPage( this );
+ }
+ if ( isVisible() ) return;
+
+ QWidget* p = parentWidget();
+ while ( p ){
+ if ( !p->isVisible() )
+ p->show();
+ p = p->parentWidget();
+ }
+ if( parent() == 0L) // is undocked
+ dockBack();
+ show();
+}
+
+void PMDockWidget::loseFormerBrotherDockWidget()
+{
+ if( formerBrotherDockWidget != 0L)
+ QObject::disconnect( formerBrotherDockWidget, SIGNAL(iMBeingClosed()),
+ this, SLOT(loseFormerBrotherDockWidget()) );
+ formerBrotherDockWidget = 0L;
+ repaint();
+}
+
+void PMDockWidget::dockBack()
+{
+ if( formerBrotherDockWidget) {
+ // search all children if it tries to dock back to a child
+ bool found = false;
+ QObjectList* cl = queryList("PMDockWidget");
+ QObjectListIt it( *cl );
+ QObject * obj;
+ while ( !found && (obj=it.current()) != 0 ) {
+ ++it;
+ QWidget* widg = (QWidget*)obj;
+ if( widg == formerBrotherDockWidget)
+ found = true;
+ }
+ delete cl;
+
+ if( !found) {
+ // can dock back to the former brother dockwidget
+ manualDock( formerBrotherDockWidget, formerDockPos, d->splitPosInPercent, QPoint(0,0), false, d->index);
+ formerBrotherDockWidget = 0L;
+ makeDockVisible();
+ return;
+ }
+ }
+
+ // else dockback to the dockmainwindow (default behaviour)
+ manualDock( ((PMDockMainWindow*)manager->main)->getMainDockWidget(), formerDockPos, d->splitPosInPercent, QPoint(0,0), false, d->index);
+ formerBrotherDockWidget = 0L;
+ if (parent())
+ makeDockVisible();
+}
+
+bool PMDockWidget::isDockBackPossible() const
+{
+ if( (formerBrotherDockWidget == 0L) || !(formerBrotherDockWidget->dockSite() & formerDockPos))
+ return false;
+ else
+ return true;
+}
+
+/**************************************************************************************/
+
+class PMDockManager::PMDockManagerPrivate
+{
+public:
+ /**
+ * This rectangle is used to highlight the current dockposition. It stores global screen coordinates.
+ */
+ QRect dragRect;
+
+ /**
+ * This rectangle is used to erase the previously highlighted dockposition. It stores global screen coordinates.
+ */
+ QRect oldDragRect;
+
+ /**
+ * This flag stores the information if dragging is ready to start. Used between mousePress and mouseMove event.
+ */
+ bool readyToDrag;
+
+ /**
+ * This variable stores the offset of the mouse cursor to the upper left edge of the current drag widget.
+ */
+ QPoint dragOffset;
+
+ /**
+ * These flags store information about the splitter behaviour
+ */
+ bool splitterOpaqueResize;
+ bool splitterKeepSize;
+ bool splitterHighResolution;
+};
+
+PMDockManager::PMDockManager( QWidget* mainWindow , const char* name )
+:QObject( mainWindow, name )
+ ,main(mainWindow)
+ ,currentDragWidget(0L)
+ ,currentMoveWidget(0L)
+ ,childDockWidgetList(0L)
+ ,autoCreateDock(0L)
+ ,storeW(0)
+ ,storeH(0)
+ ,draging(false)
+ ,undockProcess(false)
+ ,dropCancel(true)
+{
+ d = new PMDockManagerPrivate;
+ d->splitterOpaqueResize = false;
+ d->splitterKeepSize = false;
+ d->splitterHighResolution = false;
+
+ main->installEventFilter( this );
+
+ undockProcess = false;
+
+ menuData = new QPtrList<MenuDockData>;
+ menuData->setAutoDelete( true );
+ menuData->setAutoDelete( true );
+
+#ifndef NO_KDE2
+ menu = new KPopupMenu();
+#else
+ menu = new QPopupMenu();
+#endif
+
+ connect( menu, SIGNAL(aboutToShow()), SLOT(slotMenuPopup()) );
+ connect( menu, SIGNAL(activated(int)), SLOT(slotMenuActivated(int)) );
+
+ childDock = new QObjectList();
+ childDock->setAutoDelete( false );
+}
+
+PMDockManager::~PMDockManager()
+{
+ delete menuData;
+ delete menu;
+
+ QObjectListIt it( *childDock );
+ PMDockWidget * obj;
+
+ while ( (obj=(PMDockWidget*)it.current()) ) {
+ delete obj;
+ }
+ delete childDock;
+ delete d;
+}
+
+void PMDockManager::activate()
+{
+ QObjectListIt it( *childDock );
+ PMDockWidget * obj;
+
+ while ( (obj=(PMDockWidget*)it.current()) ) {
+ ++it;
+ if ( obj->widget ) obj->widget->show();
+ if ( !obj->parentDockTabGroup() ){
+ obj->show();
+ }
+ }
+ if ( !main->inherits("QDialog") ) main->show();
+}
+
+bool PMDockManager::eventFilter( QObject *obj, QEvent *event )
+{
+/* This doesn't seem to fullfill any sense, other than breaking
+ QMainWindow's layout all over the place
+ The first child of the mainwindow is not necessarily a meaningful
+ content widget but in Qt3's QMainWindow it can easily be a QToolBar.
+ In short: QMainWindow knows how to layout its children, no need to
+ mess that up.
+
+ >>>>>I need this in the PMDockArea at the moment (JoWenn)
+
+ if ( obj == main && event->type() == QEvent::Resize && dynamic_cast<PMDockArea*>(main) && main->children() ){
+#ifndef NO_KDE2
+ kdDebug()<<"PMDockManager::eventFilter(): main is a PMDockArea and there are children"<<endl;
+#endif
+ QWidget* fc = (QWidget*)main->children()->getFirst();
+ if ( fc )
+ fc->setGeometry( QRect(QPoint(0,0), main->geometry().size()) );
+ }
+*/
+
+ if ( obj->inherits("PMDockWidgetAbstractHeaderDrag") ){
+ PMDockWidget* pDockWdgAtCursor = 0L;
+ PMDockWidget* curdw = ((PMDockWidgetAbstractHeaderDrag*)obj)->dockWidget();
+ switch ( event->type() ){
+ case QEvent::MouseButtonDblClick:
+ if (curdw->currentDockPos == PMDockWidget::DockDesktop) curdw->dockBack();
+ else curdw->toDesktop( );
+ break;
+ case QEvent::MouseButtonPress:
+ if ( ((QMouseEvent*)event)->button() == LeftButton ){
+ if ( curdw->eDocking != (int)PMDockWidget::DockNone ){
+ dropCancel = true;
+ curdw->setFocus();
+ qApp->processOneEvent();
+
+ currentDragWidget = curdw;
+ currentMoveWidget = 0L;
+ childDockWidgetList = new QWidgetList();
+ childDockWidgetList->append( curdw );
+ findChildDockWidget( curdw, *childDockWidgetList );
+
+ d->oldDragRect = QRect();
+ d->dragRect = QRect(curdw->geometry());
+ QPoint p = curdw->mapToGlobal(QPoint(0,0));
+ d->dragRect.moveTopLeft(p);
+ drawDragRectangle();
+ d->readyToDrag = true;
+
+ d->dragOffset = QCursor::pos()-currentDragWidget->mapToGlobal(QPoint(0,0));
+ }
+ }
+ break;
+ case QEvent::MouseButtonRelease:
+ if ( ((QMouseEvent*)event)->button() == LeftButton ){
+ if ( draging ){
+ if ( !dropCancel )
+ drop();
+ else
+ cancelDrop();
+ }
+ if (d->readyToDrag) {
+ d->readyToDrag = false;
+ d->oldDragRect = QRect();
+ d->dragRect = QRect(curdw->geometry());
+ QPoint p = curdw->mapToGlobal(QPoint(0,0));
+ d->dragRect.moveTopLeft(p);
+ drawDragRectangle();
+ currentDragWidget = 0L;
+ delete childDockWidgetList;
+ childDockWidgetList = 0L;
+ }
+ draging = false;
+ dropCancel = true;
+ }
+ break;
+ case QEvent::MouseMove:
+ if ( draging ) {
+ pDockWdgAtCursor = findDockWidgetAt( QCursor::pos() );
+ PMDockWidget* oldMoveWidget = currentMoveWidget;
+ if ( currentMoveWidget && pDockWdgAtCursor == currentMoveWidget ) { //move
+ dragMove( currentMoveWidget, currentMoveWidget->mapFromGlobal( QCursor::pos() ) );
+ break;
+ } else {
+ if (dropCancel && curdw) {
+ d->dragRect = QRect(curdw->geometry());
+ QPoint p = curdw->mapToGlobal(QPoint(0,0));
+ d->dragRect.moveTopLeft(p);
+ }else
+ d->dragRect = QRect();
+
+ drawDragRectangle();
+ }
+
+ if ( !pDockWdgAtCursor && (curdw->eDocking & (int)PMDockWidget::DockDesktop) == 0 ){
+ // just moving at the desktop
+ currentMoveWidget = pDockWdgAtCursor;
+ curPos = PMDockWidget::DockDesktop;
+ } else {
+ if ( oldMoveWidget && pDockWdgAtCursor != currentMoveWidget ) { //leave
+ currentMoveWidget = pDockWdgAtCursor;
+ curPos = PMDockWidget::DockDesktop;
+ }
+ }
+
+ if ( oldMoveWidget != pDockWdgAtCursor && pDockWdgAtCursor ) { //enter pDockWdgAtCursor
+ currentMoveWidget = pDockWdgAtCursor;
+ curPos = PMDockWidget::DockDesktop;
+ }
+ } else {
+ if (d->readyToDrag) {
+ d->readyToDrag = false;
+ }
+ if ( (((QMouseEvent*)event)->state() == LeftButton) &&
+ (curdw->eDocking != (int)PMDockWidget::DockNone) ) {
+ startDrag( curdw);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return QObject::eventFilter( obj, event );
+}
+
+PMDockWidget* PMDockManager::findDockWidgetAt( const QPoint& pos )
+{
+ dropCancel = true;
+
+ if (!currentDragWidget)
+ return 0L; // pointer access safety
+
+ if (currentDragWidget->eDocking == (int)PMDockWidget::DockNone ) return 0L;
+
+ QWidget* p = QApplication::widgetAt( pos );
+ if ( !p ) {
+ dropCancel = false;
+ return 0L;
+ }
+#if defined(_OS_WIN32_) || defined(Q_OS_WIN32)
+ p = p->topLevelWidget();
+#endif
+ QWidget* w = 0L;
+ findChildDockWidget( w, p, p->mapFromGlobal(pos) );
+ if ( !w ){
+ if ( !p->inherits("PMDockWidget") ) {
+ return 0L;
+ }
+ w = p;
+ }
+ if ( qt_find_obj_child( w, "PMDockSplitter", "_dock_split_" ) ) return 0L;
+ if ( qt_find_obj_child( w, "PMDockTabGroup", "_dock_tab" ) ) return 0L;
+ if (!childDockWidgetList) return 0L;
+ if ( childDockWidgetList->find(w) != -1 ) return 0L;
+ if ( currentDragWidget->isGroup && ((PMDockWidget*)w)->parentDockTabGroup() ) return 0L;
+
+ PMDockWidget* www = (PMDockWidget*)w;
+ if ( www->dockSite( ) == (int)PMDockWidget::DockNone ) return 0L;
+
+ PMDockWidget::DockPosition curPos = PMDockWidget::DockDesktop;
+ QPoint cpos = www->mapFromGlobal( pos );
+
+ int ww = www->widget->width() / 3;
+ int hh = www->widget->height() / 3;
+
+ if ( cpos.y() <= hh ){
+ curPos = PMDockWidget::DockTop;
+ } else
+ if ( cpos.y() >= 2*hh ){
+ curPos = PMDockWidget::DockBottom;
+ } else
+ if ( cpos.x() <= ww ){
+ curPos = PMDockWidget::DockLeft;
+ } else
+ if ( cpos.x() >= 2*ww ){
+ curPos = PMDockWidget::DockRight;
+ } else
+ curPos = PMDockWidget::DockCenter;
+
+ if ( !(www->dockSite( ) & (int)curPos) ) return 0L;
+ if ( !(currentDragWidget->eDocking & (int)curPos) ) return 0L;
+ if ( www->manager != this ) return 0L;
+
+ dropCancel = false;
+ return www;
+}
+
+void PMDockManager::findChildDockWidget( QWidget*& ww, const QWidget* p, const QPoint& pos )
+{
+ if ( p->children() ) {
+ QWidget *w;
+ QObjectListIt it( *p->children() );
+ it.toLast();
+ while ( it.current() ) {
+ if ( it.current()->isWidgetType() ) {
+ w = (QWidget*)it.current();
+ if ( w->isVisible() && w->geometry().contains(pos) ) {
+ if ( w->inherits("PMDockWidget") ) ww = w;
+ findChildDockWidget( ww, w, w->mapFromParent(pos) );
+ return;
+ }
+ }
+ --it;
+ }
+ }
+ return;
+}
+
+void PMDockManager::findChildDockWidget( const QWidget* p, QWidgetList& list )
+{
+ if ( p->children() ) {
+ QWidget *w;
+ QObjectListIt it( *p->children() );
+ it.toLast();
+ while ( it.current() ) {
+ if ( it.current()->isWidgetType() ) {
+ w = (QWidget*)it.current();
+ if ( w->isVisible() ) {
+ if ( w->inherits("PMDockWidget") ) list.append( w );
+ findChildDockWidget( w, list );
+ }
+ }
+ --it;
+ }
+ }
+ return;
+}
+
+void PMDockManager::findFloatingWidgets( QPtrList<PMDockWidget>& l )
+{
+ QObjectListIt it( *childDock );
+ for( ; it.current( ); ++it )
+ if( it.current( )->inherits( "PMDockWidget" ) &&
+ !it.current( )->parent( ) )
+ l.append( ( PMDockWidget* ) it.current( ) );
+}
+
+void PMDockManager::startDrag( PMDockWidget* w )
+{
+ if(( w->currentDockPos == PMDockWidget::DockLeft) || ( w->currentDockPos == PMDockWidget::DockRight)
+ || ( w->currentDockPos == PMDockWidget::DockTop) || ( w->currentDockPos == PMDockWidget::DockBottom)) {
+ w->prevSideDockPosBeforeDrag = w->currentDockPos;
+
+ if ( w->parentWidget()->inherits("PMDockSplitter") ){
+ PMDockSplitter* parentSplitterOfDockWidget = (PMDockSplitter*)(w->parentWidget());
+ w->d->splitPosInPercent = parentSplitterOfDockWidget->separatorPos();
+ }
+ }
+
+ curPos = PMDockWidget::DockDesktop;
+ draging = true;
+
+ QApplication::setOverrideCursor(QCursor(sizeAllCursor));
+}
+
+void PMDockManager::dragMove( PMDockWidget* dw, QPoint pos )
+{
+ QPoint p = dw->mapToGlobal( dw->widget->pos() );
+ PMDockWidget::DockPosition oldPos = curPos;
+
+ QSize r = dw->widget->size();
+ if ( dw->parentDockTabGroup() ){
+ curPos = PMDockWidget::DockCenter;
+ if ( oldPos != curPos ) {
+ d->dragRect.setRect( p.x()+2, p.y()+2, r.width()-4, r.height()-4 );
+ }
+ return;
+ }
+
+ int w = r.width() / 3;
+ int h = r.height() / 3;
+
+ PMDockMainWindow* mw = ( PMDockMainWindow* ) parent( );
+ QWidget* cw = mw->centralWidget( );
+ QPoint cwp = cw->mapToGlobal( QPoint( 0, 0 ) );
+ int cwh = cw->height( );
+
+ if ( pos.y() <= h )
+ {
+ curPos = PMDockWidget::DockTop;
+ w = r.width();
+ }
+ else if ( pos.y() >= 2*h )
+ {
+ curPos = PMDockWidget::DockBottom;
+ p.setY( p.y() + 2*h );
+ w = r.width();
+ }
+ else if ( pos.x() <= w )
+ {
+ curPos = PMDockWidget::DockLeft;
+ h = r.height();
+ p.setY( cwp.y( ) );
+ h = cwh;
+ }
+ else if ( pos.x() >= 2*w )
+ {
+ curPos = PMDockWidget::DockRight;
+ p.setX( p.x() + 2*w );
+ p.setY( cwp.y( ) );
+ h = cwh;
+ }
+ else
+ {
+ curPos = PMDockWidget::DockCenter;
+ p.setX( p.x() + w );
+ p.setY( p.y() + h );
+ }
+
+ if ( oldPos != curPos ) {
+ d->dragRect.setRect( p.x(), p.y(), w, h );
+ drawDragRectangle();
+ }
+}
+
+
+void PMDockManager::cancelDrop()
+{
+ QApplication::restoreOverrideCursor();
+
+ delete childDockWidgetList;
+ childDockWidgetList = 0L;
+
+ d->dragRect = QRect(); // cancel drawing
+ drawDragRectangle(); // only the old rect will be deleted
+}
+
+
+void PMDockManager::drop()
+{
+ d->dragRect = QRect(); // cancel drawing
+ drawDragRectangle(); // only the old rect will be deleted
+
+ QApplication::restoreOverrideCursor();
+
+ delete childDockWidgetList;
+ childDockWidgetList = 0L;
+
+ if ( dropCancel ) return;
+ if ( !currentMoveWidget && ((currentDragWidget->eDocking & (int)PMDockWidget::DockDesktop) == 0) ) {
+ d->dragRect = QRect(); // cancel drawing
+ drawDragRectangle(); // only the old rect will be deleted
+ return;
+ }
+ if ( !currentMoveWidget && !currentDragWidget->parent() ) {
+ currentDragWidget->move( QCursor::pos() - d->dragOffset );
+ }
+ else {
+ int splitPos = currentDragWidget->d->splitPosInPercent;
+ // do we have to calculate 100%-splitPosInPercent?
+ if( (curPos != currentDragWidget->prevSideDockPosBeforeDrag) && (curPos != PMDockWidget::DockCenter) && (curPos != PMDockWidget::DockDesktop)) {
+ switch( currentDragWidget->prevSideDockPosBeforeDrag) {
+ case PMDockWidget::DockLeft: if(curPos != PMDockWidget::DockTop) splitPos = 100-splitPos; break;
+ case PMDockWidget::DockRight: if(curPos != PMDockWidget::DockBottom) splitPos = 100-splitPos; break;
+ case PMDockWidget::DockTop: if(curPos != PMDockWidget::DockLeft) splitPos = 100-splitPos; break;
+ case PMDockWidget::DockBottom: if(curPos != PMDockWidget::DockRight) splitPos = 100-splitPos; break;
+ default: break;
+ }
+ }
+ currentDragWidget->manualDock( currentMoveWidget, curPos , splitPos, QCursor::pos() - d->dragOffset );
+ currentDragWidget->makeDockVisible();
+ }
+}
+
+
+static QDomElement createStringEntry(QDomDocument &doc, const QString &tagName, const QString &str)
+{
+ QDomElement el = doc.createElement(tagName);
+
+ el.appendChild(doc.createTextNode(str));
+ return el;
+}
+
+
+static QDomElement createBoolEntry(QDomDocument &doc, const QString &tagName, bool b)
+{
+ return createStringEntry(doc, tagName, QString::fromLatin1(b? "true" : "false"));
+}
+
+
+static QDomElement createNumberEntry(QDomDocument &doc, const QString &tagName, int n)
+{
+ return createStringEntry(doc, tagName, QString::number(n));
+}
+
+
+static QDomElement createRectEntry(QDomDocument &doc, const QString &tagName, const QRect &rect)
+{
+ QDomElement el = doc.createElement(tagName);
+
+ QDomElement xel = doc.createElement("x");
+ xel.appendChild(doc.createTextNode(QString::number(rect.x())));
+ el.appendChild(xel);
+ QDomElement yel = doc.createElement("y");
+ yel.appendChild(doc.createTextNode(QString::number(rect.y())));
+ el.appendChild(yel);
+ QDomElement wel = doc.createElement("width");
+ wel.appendChild(doc.createTextNode(QString::number(rect.width())));
+ el.appendChild(wel);
+ QDomElement hel = doc.createElement("height");
+ hel.appendChild(doc.createTextNode(QString::number(rect.height())));
+ el.appendChild(hel);
+
+ return el;
+}
+
+
+static QDomElement createListEntry(QDomDocument &doc, const QString &tagName,
+ const QString &subTagName, const QStrList &list)
+{
+ QDomElement el = doc.createElement(tagName);
+
+ QStrListIterator it(list);
+ for (; it.current(); ++it) {
+ QDomElement subel = doc.createElement(subTagName);
+ subel.appendChild(doc.createTextNode(QString::fromLatin1(it.current())));
+ el.appendChild(subel);
+ }
+
+ return el;
+}
+
+
+static QString stringEntry(QDomElement &base, const QString &tagName)
+{
+ return base.namedItem(tagName).firstChild().toText().data();
+}
+
+
+static bool boolEntry(QDomElement &base, const QString &tagName)
+{
+ return base.namedItem(tagName).firstChild().toText().data() == "true";
+}
+
+
+static int numberEntry(QDomElement &base, const QString &tagName)
+{
+ return stringEntry(base, tagName).toInt();
+}
+
+
+static QRect rectEntry(QDomElement &base, const QString &tagName)
+{
+ QDomElement el = base.namedItem(tagName).toElement();
+
+ int x = numberEntry(el, "x");
+ int y = numberEntry(el, "y");
+ int width = numberEntry(el, "width");
+ int height = numberEntry(el, "height");
+
+ return QRect(x, y, width, height);
+}
+
+
+static QStrList listEntry(QDomElement &base, const QString &tagName, const QString &subTagName)
+{
+ QStrList list;
+
+ QDomElement subel = base.namedItem(tagName).firstChild().toElement();
+ while (!subel.isNull()) {
+ if (subel.tagName() == subTagName)
+ list.append(subel.firstChild().toText().data().latin1());
+ subel = subel.nextSibling().toElement();
+ }
+
+ return list;
+}
+
+
+void PMDockManager::writeConfig(QDomElement &base)
+{
+ // First of all, clear the tree under base
+ while (!base.firstChild().isNull())
+ base.removeChild(base.firstChild());
+ QDomDocument doc = base.ownerDocument();
+
+ QStrList nameList;
+ QString mainWidgetStr;
+
+ // collect widget names
+ QStrList nList;
+ QObjectListIt it(*childDock);
+ PMDockWidget *obj1;
+ while ( (obj1=(PMDockWidget*)it.current()) ) {
+ if ( obj1->parent() == main )
+ mainWidgetStr = QString::fromLatin1(obj1->name());
+ nList.append(obj1->name());
+ ++it;
+ }
+
+ nList.first();
+ while ( nList.current() ) {
+ PMDockWidget *obj = getDockWidgetFromName( nList.current() );
+ if (obj->isGroup && (nameList.find( obj->firstName.latin1() ) == -1
+ || nameList.find(obj->lastName.latin1()) == -1)) {
+ // Skip until children are saved (why?)
+ nList.next();
+ if ( !nList.current() ) nList.first();
+ continue;
+ }
+
+ QDomElement groupEl;
+
+ if (obj->isGroup) {
+ //// Save a group
+ groupEl = doc.createElement("splitGroup");
+
+ groupEl.appendChild(createStringEntry(doc, "firstName", obj->firstName));
+ groupEl.appendChild(createStringEntry(doc, "secondName", obj->lastName));
+ groupEl.appendChild(createNumberEntry(doc, "orientation", (int)obj->splitterOrientation));
+ groupEl.appendChild(createNumberEntry(doc, "separatorPos", ((PMDockSplitter*)obj->widget)->separatorPos()));
+ } else if (obj->isTabGroup) {
+ //// Save a tab group
+ groupEl = doc.createElement("tabGroup");
+
+ QStrList list;
+ for ( int i = 0; i < ((PMDockTabGroup*)obj->widget)->count(); ++i )
+ list.append( ((PMDockTabGroup*)obj->widget)->page( i )->name() );
+ groupEl.appendChild(createListEntry(doc, "tabs", "tab", list));
+ groupEl.appendChild(createNumberEntry(doc, "currentTab", ((PMDockTabGroup*)obj->widget)->currentPageIndex()));
+ } else {
+ //// Save an ordinary dock widget
+ groupEl = doc.createElement("dock");
+ }
+
+ groupEl.appendChild(createStringEntry(doc, "name", QString::fromLatin1(obj->name())));
+ groupEl.appendChild(createBoolEntry(doc, "hasParent", obj->parent()));
+ if ( !obj->parent() ) {
+ groupEl.appendChild(createRectEntry(doc, "geometry", QRect(main->frameGeometry().topLeft(), main->size())));
+ groupEl.appendChild(createBoolEntry(doc, "visible", obj->isVisible()));
+ }
+ if (obj->header && obj->header->inherits("PMDockWidgetHeader")) {
+ PMDockWidgetHeader *h = static_cast<PMDockWidgetHeader*>(obj->header);
+ groupEl.appendChild(createBoolEntry(doc, "dragEnabled", h->dragEnabled()));
+ }
+
+ base.appendChild(groupEl);
+ nameList.append(obj->name());
+ nList.remove();
+ nList.first();
+ }
+
+ if (main->inherits("PMDockMainWindow")) {
+ PMDockMainWindow *dmain = (PMDockMainWindow*)main;
+ QString centralWidgetStr = QString(dmain->centralWidget()? dmain->centralWidget()->name() : "");
+ base.appendChild(createStringEntry(doc, "centralWidget", centralWidgetStr));
+ QString mainDockWidgetStr = QString(dmain->getMainDockWidget()? dmain->getMainDockWidget()->name() : "");
+ base.appendChild(createStringEntry(doc, "mainDockWidget", mainDockWidgetStr));
+ } else {
+ base.appendChild(createStringEntry(doc, "mainWidget", mainWidgetStr));
+ }
+
+ base.appendChild(createRectEntry(doc, "geometry", QRect(main->frameGeometry().topLeft(), main->size())));
+}
+
+
+void PMDockManager::readConfig(QDomElement &base)
+{
+ if (base.namedItem("group").isNull()
+ && base.namedItem("tabgroup").isNull()
+ && base.namedItem("dock").isNull()) {
+ activate();
+ return;
+ }
+
+ autoCreateDock = new QObjectList();
+ autoCreateDock->setAutoDelete( true );
+
+ bool isMainVisible = main->isVisible();
+ main->hide();
+
+ QObjectListIt it(*childDock);
+ PMDockWidget *obj1;
+ while ( (obj1=(PMDockWidget*)it.current()) ) {
+ if ( !obj1->isGroup && !obj1->isTabGroup ) {
+ if ( obj1->parent() )
+ obj1->undock();
+ else
+ obj1->hide();
+ }
+ ++it;
+ }
+
+ QDomElement childEl = base.firstChild().toElement();
+ while (!childEl.isNull() ) {
+ PMDockWidget *obj = 0;
+
+ if (childEl.tagName() == "splitGroup") {
+ // Read a group
+ QString name = stringEntry(childEl, "name");
+ QString firstName = stringEntry(childEl, "firstName");
+ QString secondName = stringEntry(childEl, "secondName");
+ int orientation = numberEntry(childEl, "orientation");
+ int separatorPos = numberEntry(childEl, "separatorPos");
+
+ PMDockWidget *first = getDockWidgetFromName(firstName);
+ PMDockWidget *second = getDockWidgetFromName(secondName);
+ if (first && second) {
+ obj = first->manualDock(second,
+ (orientation == (int)Vertical)? PMDockWidget::DockLeft : PMDockWidget::DockTop,
+ separatorPos);
+ if (obj)
+ obj->setName(name.latin1());
+ }
+ } else if (childEl.tagName() == "tabGroup") {
+ // Read a tab group
+ QString name = stringEntry(childEl, "name");
+ QStrList list = listEntry(childEl, "tabs", "tab");
+
+ PMDockWidget *d1 = getDockWidgetFromName( list.first() );
+ list.next();
+ PMDockWidget *d2 = getDockWidgetFromName( list.current() );
+
+ PMDockWidget *obj = d2->manualDock( d1, PMDockWidget::DockCenter );
+ if (obj) {
+ PMDockTabGroup *tab = (PMDockTabGroup*)obj->widget;
+ list.next();
+ while (list.current() && obj) {
+ PMDockWidget *tabDock = getDockWidgetFromName(list.current());
+ obj = tabDock->manualDock(d1, PMDockWidget::DockCenter);
+ list.next();
+ }
+ if (obj) {
+ obj->setName(name.latin1());
+ tab->showPage(tab->page(numberEntry(childEl, "currentTab")));
+ }
+ }
+ } else if (childEl.tagName() == "dock") {
+ // Read an ordinary dock widget
+ obj = getDockWidgetFromName(stringEntry(childEl, "name"));
+ }
+
+ if (!boolEntry(childEl, "hasParent")) {
+ QRect r = rectEntry(childEl, "geometry");
+ obj = getDockWidgetFromName(stringEntry(childEl, "name"));
+ obj->applyToWidget(0);
+ obj->setGeometry(r);
+ if (boolEntry(childEl, "visible"))
+ obj->QWidget::show();
+ }
+
+ if (obj && obj->header && obj->header->inherits("PMDockWidgetHeader")) {
+ PMDockWidgetHeader *h = static_cast<PMDockWidgetHeader*>(obj->header);
+ h->setDragEnabled(boolEntry(childEl, "dragEnabled"));
+ }
+
+ childEl = childEl.nextSibling().toElement();
+ }
+
+ if (main->inherits("PMDockMainWindow")) {
+ PMDockMainWindow *dmain = (PMDockMainWindow*)main;
+
+ QString mv = stringEntry(base, "centralWidget");
+ if (!mv.isEmpty() && getDockWidgetFromName(mv) ) {
+ PMDockWidget *mvd = getDockWidgetFromName(mv);
+ mvd->applyToWidget(dmain);
+ mvd->show();
+ dmain->setCentralWidget(mvd);
+ }
+ QString md = stringEntry(base, "mainDockWidget");
+ if (!md.isEmpty() && getDockWidgetFromName(md)) {
+ PMDockWidget *mvd = getDockWidgetFromName(md);
+ dmain->setMainDockWidget(mvd);
+ }
+ } else {
+ QString mv = stringEntry(base, "mainWidget");
+ if (!mv.isEmpty() && getDockWidgetFromName(mv)) {
+ PMDockWidget *mvd = getDockWidgetFromName(mv);
+ mvd->applyToWidget(main);
+ mvd->show();
+ }
+ }
+
+ QRect mr = rectEntry(base, "geometry");
+ main->setGeometry(mr);
+ if (isMainVisible)
+ main->show();
+
+ delete autoCreateDock;
+ autoCreateDock = 0;
+}
+
+
+#ifndef NO_KDE2
+void PMDockManager::writeConfig( KConfig* c, QString group )
+{
+ //debug("BEGIN Write Config");
+ if ( !c ) c = KGlobal::config();
+ if ( group.isEmpty() ) group = "dock_setting_default";
+
+ c->setGroup( group );
+ c->writeEntry( "Version", DOCK_CONFIG_VERSION );
+
+ QStrList nameList;
+ QStrList findList;
+ QObjectListIt it( *childDock );
+ PMDockWidget * obj;
+
+ // collect PMDockWidget's name
+ QStrList nList;
+ while ( (obj=(PMDockWidget*)it.current()) ) {
+ ++it;
+ //debug(" +Add subdock %s", obj->name());
+ nList.append( obj->name() );
+ if ( obj->parent() == main )
+ c->writeEntry( "Main:view", obj->name() );
+ }
+
+ nList.first();
+ while ( nList.current() ){
+ //debug(" -Try to save %s", nList.current());
+ obj = getDockWidgetFromName( nList.current() );
+ QString cname = obj->name();
+ if ( obj->header ){
+ obj->header->saveConfig( c );
+ }
+/*************************************************************************************************/
+ if ( obj->isGroup ){
+ if ( findList.find( obj->firstName.latin1() ) != -1 && findList.find( obj->lastName.latin1() ) != -1 ){
+
+ c->writeEntry( cname+":type", "GROUP");
+ if ( !obj->parent() ){
+ c->writeEntry( cname+":parent", "___null___");
+ c->writeEntry( cname+":geometry", QRect(obj->frameGeometry().topLeft(), obj->size()) );
+ c->writeEntry( cname+":visible", obj->isVisible());
+ } else {
+ c->writeEntry( cname+":parent", "yes");
+ }
+ c->writeEntry( cname+":first_name", obj->firstName );
+ c->writeEntry( cname+":last_name", obj->lastName );
+ c->writeEntry( cname+":orientation", (int)obj->splitterOrientation );
+ c->writeEntry( cname+":sepPos", ((PMDockSplitter*)obj->widget)->separatorPos() );
+
+ nameList.append( obj->name() );
+ findList.append( obj->name() );
+ //debug(" Save %s", nList.current());
+ nList.remove();
+ nList.first();
+ } else {
+/*************************************************************************************************/
+ //debug(" Skip %s", nList.current());
+ //if ( findList.find( obj->firstName ) == -1 )
+ // debug(" ? Not found %s", obj->firstName);
+ //if ( findList.find( obj->lastName ) == -1 )
+ // debug(" ? Not found %s", obj->lastName);
+ nList.next();
+ if ( !nList.current() ) nList.first();
+ }
+ } else {
+/*************************************************************************************************/
+ if ( obj->isTabGroup){
+ c->writeEntry( cname+":type", "TAB_GROUP");
+ if ( !obj->parent() ){
+ c->writeEntry( cname+":parent", "___null___");
+ c->writeEntry( cname+":geometry", QRect(obj->frameGeometry().topLeft(), obj->size()) );
+ c->writeEntry( cname+":visible", obj->isVisible());
+ } else {
+ c->writeEntry( cname+":parent", "yes");
+ }
+ QStrList list;
+ for ( int i = 0; i < ((PMDockTabGroup*)obj->widget)->count(); ++i )
+ list.append( ((PMDockTabGroup*)obj->widget)->page( i )->name() );
+ c->writeEntry( cname+":tabNames", list );
+ c->writeEntry( cname+":curTab", ((PMDockTabGroup*)obj->widget)->currentPageIndex() );
+
+ nameList.append( obj->name() );
+ findList.append( obj->name() ); // not really need !!!
+ //debug(" Save %s", nList.current());
+ nList.remove();
+ nList.first();
+ } else {
+/*************************************************************************************************/
+ if ( !obj->parent() ){
+ c->writeEntry( cname+":type", "NULL_DOCK");
+ c->writeEntry( cname+":geometry", QRect(obj->frameGeometry().topLeft(), obj->size()) );
+ c->writeEntry( cname+":visible", obj->isVisible());
+ } else {
+ c->writeEntry( cname+":type", "DOCK");
+ }
+ nameList.append( cname.latin1() );
+ //debug(" Save %s", nList.current());
+ findList.append( obj->name() );
+ nList.remove();
+ nList.first();
+ }
+ }
+ }
+ c->writeEntry( "NameList", nameList );
+
+ c->writeEntry( "Main:Geometry", QRect(main->frameGeometry().topLeft(), main->size()) );
+ c->writeEntry( "Main:visible", main->isVisible()); // curently nou use
+
+ if ( main->inherits("PMDockMainWindow") ){
+ PMDockMainWindow* dmain = (PMDockMainWindow*)main;
+ // for PMDockMainWindow->setView() in readConfig()
+ c->writeEntry( "Main:view", dmain->centralWidget() ? dmain->centralWidget()->name():"" );
+ c->writeEntry( "Main:dock", dmain->getMainDockWidget() ? dmain->getMainDockWidget()->name() :"" );
+ }
+
+ c->sync();
+ //debug("END Write Config");
+}
+#include <qmessagebox.h>
+void PMDockManager::readConfig( KConfig* c, QString group )
+{
+ if ( !c ) c = KGlobal::config();
+ if ( group.isEmpty() ) group = "dock_setting_default";
+
+ c->setGroup( group );
+ QStrList nameList;
+ c->readListEntry( "NameList", nameList );
+ QString ver = c->readEntry( "Version", "0.0.1" );
+ nameList.first();
+ if ( !nameList.current() || ver != DOCK_CONFIG_VERSION ){
+ activate();
+ return;
+ }
+
+ autoCreateDock = new QObjectList();
+ autoCreateDock->setAutoDelete( true );
+
+ bool isMainVisible = main->isVisible();
+ // if (isMainVisible) // CCC
+ //QMessageBox::information(0,"","hallo");
+//COMMENTED4TESTING main->hide();
+
+ QObjectListIt it( *childDock );
+ PMDockWidget * obj;
+
+ while ( (obj=(PMDockWidget*)it.current()) ){
+ ++it;
+ if ( !obj->isGroup && !obj->isTabGroup )
+ {
+ if ( obj->parent() ) obj->undock(); else obj->hide();
+ }
+ }
+
+ nameList.first();
+ while ( nameList.current() ){
+ QString oname = nameList.current();
+ c->setGroup( group );
+ QString type = c->readEntry( oname + ":type" );
+ obj = 0L;
+
+ if ( type == "GROUP" ){
+ PMDockWidget* first = getDockWidgetFromName( c->readEntry( oname + ":first_name" ) );
+ PMDockWidget* last = getDockWidgetFromName( c->readEntry( oname + ":last_name" ) );
+ int sepPos = c->readNumEntry( oname + ":sepPos" );
+
+ Orientation p = (Orientation)c->readNumEntry( oname + ":orientation" );
+ if ( first && last ){
+ obj = first->manualDock( last, ( p == Vertical ) ? PMDockWidget::DockLeft : PMDockWidget::DockTop, sepPos );
+ if (obj){
+ obj->setName( oname.latin1() );
+ }
+ }
+ }
+
+ if ( type == "TAB_GROUP" ){
+ QStrList list;
+ PMDockWidget* tabDockGroup = 0L;
+ c->readListEntry( oname+":tabNames", list );
+ PMDockWidget* d1 = getDockWidgetFromName( list.first() );
+ list.next();
+ PMDockWidget* d2 = getDockWidgetFromName( list.current() );
+ tabDockGroup = d2->manualDock( d1, PMDockWidget::DockCenter );
+ if ( tabDockGroup ){
+ PMDockTabGroup* tab = (PMDockTabGroup*)tabDockGroup->widget;
+ list.next();
+ while ( list.current() && tabDockGroup ){
+ PMDockWidget* tabDock = getDockWidgetFromName( list.current() );
+ tabDockGroup = tabDock->manualDock( d1, PMDockWidget::DockCenter );
+ list.next();
+ }
+ if ( tabDockGroup ){
+ tabDockGroup->setName( oname.latin1() );
+ c->setGroup( group );
+ tab->showPage( tab->page( c->readNumEntry( oname+":curTab" ) ) );
+ }
+ }
+ obj = tabDockGroup;
+ }
+
+ if ( type == "NULL_DOCK" || c->readEntry( oname + ":parent") == "___null___" ){
+ QRect r = c->readRectEntry( oname + ":geometry" );
+ obj = getDockWidgetFromName( oname );
+ obj->applyToWidget( 0L );
+ obj->setGeometry(r);
+
+ c->setGroup( group );
+ if ( c->readBoolEntry( oname + ":visible" ) ){
+ obj->QWidget::show();
+ }
+ }
+
+ if ( type == "DOCK" ){
+ obj = getDockWidgetFromName( oname );
+ }
+
+ if ( obj && obj->header){
+ obj->header->loadConfig( c );
+ }
+ nameList.next();
+ }
+
+ if ( main->inherits("PMDockMainWindow") ){
+ PMDockMainWindow* dmain = (PMDockMainWindow*)main;
+
+ c->setGroup( group );
+ QString mv = c->readEntry( "Main:view" );
+ if ( !mv.isEmpty() && getDockWidgetFromName( mv ) ){
+ PMDockWidget* mvd = getDockWidgetFromName( mv );
+ mvd->applyToWidget( dmain );
+ mvd->show();
+ dmain->setView( mvd );
+ }
+ c->setGroup( group );
+ QString md = c->readEntry( "Main:dock" );
+ if ( !md.isEmpty() && getDockWidgetFromName( md ) ){
+ PMDockWidget* mvd = getDockWidgetFromName( md );
+ dmain->setMainDockWidget( mvd );
+ }
+ } else {
+ c->setGroup( group );
+ QString mv = c->readEntry( "Main:view" );
+ if ( !mv.isEmpty() && getDockWidgetFromName( mv ) ){
+ PMDockWidget* mvd = getDockWidgetFromName( mv );
+ mvd->applyToWidget( main );
+ mvd->show();
+ }
+
+ }
+ // delete all autocreate dock
+ delete autoCreateDock;
+ autoCreateDock = 0L;
+
+ c->setGroup( group );
+ QRect mr = c->readRectEntry("Main:Geometry");
+ main->setGeometry(mr);
+ if ( isMainVisible ) main->show();
+}
+#endif
+
+PMDockWidget* PMDockManager::getDockWidgetFromName( const QString& dockName )
+{
+ QObjectListIt it( *childDock );
+ PMDockWidget * obj;
+ while ( (obj=(PMDockWidget*)it.current()) ) {
+ ++it;
+ if ( QString(obj->name()) == dockName ) return obj;
+ }
+
+ PMDockWidget* autoCreate = 0L;
+ if ( autoCreateDock ){
+ autoCreate = new PMDockWidget( this, dockName.latin1(), QPixmap("") );
+ autoCreateDock->append( autoCreate );
+ }
+ return autoCreate;
+}
+void PMDockManager::setSplitterOpaqueResize(bool b)
+{
+ d->splitterOpaqueResize = b;
+}
+
+bool PMDockManager::splitterOpaqueResize() const
+{
+ return d->splitterOpaqueResize;
+}
+
+void PMDockManager::setSplitterKeepSize(bool b)
+{
+ d->splitterKeepSize = b;
+}
+
+bool PMDockManager::splitterKeepSize() const
+{
+ return d->splitterKeepSize;
+}
+
+void PMDockManager::setSplitterHighResolution(bool b)
+{
+ d->splitterHighResolution = b;
+}
+
+bool PMDockManager::splitterHighResolution() const
+{
+ return d->splitterHighResolution;
+}
+
+void PMDockManager::slotMenuPopup()
+{
+ menu->clear();
+ menuData->clear();
+
+ QObjectListIt it( *childDock );
+ PMDockWidget * obj;
+ int numerator = 0;
+ while ( (obj=(PMDockWidget*)it.current()) ) {
+ ++it;
+ if ( obj->mayBeHide() )
+ {
+ menu->insertItem( obj->icon() ? *(obj->icon()) : QPixmap(), QString("Hide ") + obj->caption(), numerator++ );
+ menuData->append( new MenuDockData( obj, true ) );
+ }
+
+ if ( obj->mayBeShow() )
+ {
+ menu->insertItem( obj->icon() ? *(obj->icon()) : QPixmap(), QString("Show ") + obj->caption(), numerator++ );
+ menuData->append( new MenuDockData( obj, false ) );
+ }
+ }
+}
+
+void PMDockManager::slotMenuActivated( int id )
+{
+ MenuDockData* data = menuData->at( id );
+ data->dock->changeHideShowState();
+}
+
+PMDockWidget* PMDockManager::findWidgetParentDock( QWidget* w ) const
+{
+ QObjectListIt it( *childDock );
+ PMDockWidget * dock;
+ PMDockWidget * found = 0L;
+
+ while ( (dock=(PMDockWidget*)it.current()) ) {
+ ++it;
+ if ( dock->widget == w ){ found = dock; break; }
+ }
+ return found;
+}
+
+void PMDockManager::drawDragRectangle()
+{
+ if (d->oldDragRect == d->dragRect)
+ return;
+
+ int i;
+ QRect oldAndNewDragRect[2];
+ oldAndNewDragRect[0] = d->oldDragRect;
+ oldAndNewDragRect[1] = d->dragRect;
+
+ // 2 calls, one for the old and one for the new drag rectangle
+ for (i = 0; i <= 1; i++) {
+ if (oldAndNewDragRect[i].isEmpty())
+ continue;
+
+ PMDockWidget* pDockWdgAtRect = (PMDockWidget*) QApplication::widgetAt( oldAndNewDragRect[i].topLeft(), true );
+ if (!pDockWdgAtRect)
+ continue;
+
+ bool isOverMainWdg = false;
+ bool unclipped;
+ PMDockMainWindow* pMain = 0L;
+ PMDockWidget* pTLDockWdg = 0L;
+ QWidget* topWdg;
+ if (pDockWdgAtRect->topLevelWidget() == main) {
+ isOverMainWdg = true;
+ topWdg = pMain = (PMDockMainWindow*) main;
+ unclipped = pMain->testWFlags( WPaintUnclipped );
+ pMain->setWFlags( WPaintUnclipped );
+ }
+ else {
+ topWdg = pTLDockWdg = (PMDockWidget*) pDockWdgAtRect->topLevelWidget();
+ unclipped = pTLDockWdg->testWFlags( WPaintUnclipped );
+ pTLDockWdg->setWFlags( WPaintUnclipped );
+ }
+
+ // draw the rectangle unclipped over the main dock window
+ QPainter p;
+ p.begin( topWdg );
+ if ( !unclipped ) {
+ if (isOverMainWdg)
+ pMain->clearWFlags(WPaintUnclipped);
+ else
+ pTLDockWdg->clearWFlags(WPaintUnclipped);
+ }
+ // draw the rectangle
+ p.setRasterOp(Qt::NotXorROP);
+ QRect r = oldAndNewDragRect[i];
+ r.moveTopLeft( r.topLeft() - topWdg->mapToGlobal(QPoint(0,0)) );
+ p.drawRect(r.x(), r.y(), r.width(), r.height());
+ p.end();
+ }
+
+ // memorize the current rectangle for later removing
+ d->oldDragRect = d->dragRect;
+}
+
+
+#ifdef _JOWENN_EXPERIMENTAL_
+
+PMDockArea::PMDockArea( QWidget* parent, const char *name)
+:QWidget( parent, name)
+{
+ QString new_name = QString(name) + QString("_DockManager");
+ dockManager = new PMDockManager( this, new_name.latin1() );
+ mainDockWidget = 0L;
+}
+
+PMDockArea::~PMDockArea()
+{
+ delete dockManager;
+}
+
+PMDockWidget* PMDockArea::createDockWidget( const QString& name, const QPixmap &pixmap, QWidget* parent, const QString& strCaption, const QString& strTabPageLabel)
+{
+ return new PMDockWidget( dockManager, name.latin1(), pixmap, parent, strCaption, strTabPageLabel );
+}
+
+void PMDockArea::makeDockVisible( PMDockWidget* dock )
+{
+ if ( dock != 0L)
+ dock->makeDockVisible();
+}
+
+void PMDockArea::makeDockInvisible( PMDockWidget* dock )
+{
+ if ( dock != 0L)
+ dock->undock();
+}
+
+void PMDockArea::makeWidgetDockVisible( QWidget* widget )
+{
+ makeDockVisible( dockManager->findWidgetParentDock(widget) );
+}
+
+void PMDockArea::writeDockConfig(QDomElement &base)
+{
+ dockManager->writeConfig(base);
+}
+
+void PMDockArea::readDockConfig(QDomElement &base)
+{
+ dockManager->readConfig(base);
+}
+
+void PMDockArea::slotDockWidgetUndocked()
+{
+ QObject* pSender = (QObject*) sender();
+ if (!pSender->inherits("PMDockWidget")) return;
+ PMDockWidget* pDW = (PMDockWidget*) pSender;
+ emit dockWidgetHasUndocked( pDW);
+}
+
+void PMDockArea::resizeEvent(QResizeEvent *rsize)
+{
+ QWidget::resizeEvent(rsize);
+ if (children()){
+#ifndef NO_KDE2
+ kdDebug()<<"PMDockArea::resize"<<endl;
+#endif
+ QObjectList *list=queryList("QWidget",0,false);
+
+ QObjectListIt it( *list ); // iterate over the buttons
+ QObject *obj;
+
+ while ( (obj = it.current()) != 0 ) {
+ // for each found object...
+ ((QWidget*)obj)->setGeometry(QRect(QPoint(0,0),size()));
+ break;
+ }
+ delete list;
+#if 0
+ PMDockSplitter *split;
+// for (unsigned int i=0;i<children()->count();i++)
+ {
+// QPtrList<QObject> list(children());
+// QObject *obj=((QPtrList<QObject*>)children())->at(i);
+ QObject *obj=children()->getFirst();
+ if (split=dynamic_cast<PMDockSplitter*>(obj))
+ {
+ split->setGeometry( QRect(QPoint(0,0), size() ));
+// break;
+ }
+ }
+#endif
+ }
+}
+
+#ifndef NO_KDE2
+void PMDockArea::writeDockConfig( KConfig* c, QString group )
+{
+ dockManager->writeConfig( c, group );
+}
+
+void PMDockArea::readDockConfig( KConfig* c, QString group )
+{
+ dockManager->readConfig( c, group );
+}
+
+void PMDockArea::setMainDockWidget( PMDockWidget* mdw )
+{
+ if ( mainDockWidget == mdw ) return;
+ mainDockWidget = mdw;
+ mdw->applyToWidget(this);
+}
+#endif
+
+
+#endif
+
+void PMDockWidgetAbstractHeader::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+void PMDockWidgetAbstractHeaderDrag::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+void PMDockWidgetHeaderDrag::virtual_hook( int id, void* data )
+{ PMDockWidgetAbstractHeaderDrag::virtual_hook( id, data ); }
+
+void PMDockWidgetHeader::virtual_hook( int id, void* data )
+{ PMDockWidgetAbstractHeader::virtual_hook( id, data ); }
+
+void PMDockTabGroup::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+void PMDockWidget::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+void PMDockManager::virtual_hook( int, void* )
+{ /*BASE::virtual_hook( id, data );*/ }
+
+void PMDockMainWindow::virtual_hook( int id, void* data )
+{ KMainWindow::virtual_hook( id, data ); }
+
+void PMDockArea::virtual_hook( int, void* )
+{ /*KMainWindow::virtual_hook( id, data );*/ }
+
+
+#ifndef NO_INCLUDE_MOCFILES // for Qt-only projects, because tmake doesn't take this name
+#include "pmdockwidget.moc"
+#endif
diff --git a/kpovmodeler/pmdockwidget.h b/kpovmodeler/pmdockwidget.h
new file mode 100644
index 00000000..29f6c34f
--- /dev/null
+++ b/kpovmodeler/pmdockwidget.h
@@ -0,0 +1,1478 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Max Judin <novaprint@mtu-net.ru>
+ Copyright (C) 2000 Falk Brettschneider <falk@kdevelop.org>
+ Modified 2002 Andreas Zehender <zehender@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/*
+ activities:
+ -----------
+ 03/2002 : Copied from kdelibs. Slightly different docking
+ ; behavior by Andreas Zehender <zehender@kde.org>
+ 05/2001 - : useful patches, bugfixes by Christoph Cullmann <crossfire@babylon2k.de>,
+ Joseph Wenninger <jowenn@bigfoot.com> and Falk Brettschneider
+ 03/2001 - 05/2001 : maintained and enhanced by Falk Brettschneider <falk@kdevelop.org>
+ 03/2000 : class documentation added by Falk Brettschneider <gigafalk@yahoo.com>
+ 10/1999 - 03/2000 : programmed by Max Judin <novaprint@mtu-net.ru>
+
+ C++ classes in this file:
+ -------------------------
+ - PMDockWidgetAbstractHeader - minor helper class
+ - PMDockWidgetAbstractHeaderDrag - minor helper class
+ - PMDockWidgetHeaderDrag - drag panel in a dockwidget title bar
+ - PMDockWidgetHeader - dockwidget title bar containing the drag panel
+ - PMDockTabGroup - minor helper class
+ - PMDockWidget - IMPORTANT CLASS: the one and only dockwidget class
+ - PMDockManager - helper class
+ - PMDockMainWindow - IMPORTANT CLASS: a special KMainWindow that can have dockwidgets
+ - PMDockArea - like PMDockMainWindow but inherits just QWidget
+
+ IMPORTANT Note: This file compiles also in Qt-only mode by using the NO_KDE2 precompiler definition!
+*/
+
+/*
+ MODIFICATIONS (zehender)
+ Added kparts ability from kparts/dockmainwindow
+*/
+
+#define _JOWENN_EXPERIMENTAL_
+
+
+#ifndef KDOCKWIDGET_H
+#define KDOCKWIDGET_H
+
+#define _KDOCKWIDGET_2_2_
+
+#include <qpoint.h>
+#include <qptrlist.h>
+#include <qframe.h>
+#include <qdom.h>
+#include <qtabwidget.h>
+
+#ifndef NO_KDE2
+#include <kmainwindow.h>
+#include <netwm_def.h>
+#undef EXPORT_DOCKCLASS
+#define EXPORT_DOCKCLASS
+#else
+#include <qmainwindow.h>
+#include "exportdockclass.h"
+#include "dummykmainwindow.h"
+#endif
+
+#include <kparts/part.h>
+using namespace KParts;
+
+class PMDockSplitter;
+class PMDockManager;
+class PMDockMoveManager;
+class PMDockWidget;
+class PMDockButton_Private;
+class PMDockWidgetPrivate;
+class PMDockArea;
+class PMDockMainWindowPrivate;
+
+class QObjectList;
+class QPopupMenu;
+class QVBoxLayout;
+class QHBoxLayout;
+class QPixmap;
+
+#ifndef NO_KDE2
+class KToolBar;
+class KConfig;
+#else
+class QToolBar;
+#endif
+
+/**
+ * An abstract base clase for all dockwidget headers (and member of the dockwidget class set).
+ * See the class description of @ref PMDockWidgetHeader!
+ * More or less a minor helper class for the dockwidget class set.
+ *
+ * @author Max Judin (documentation: Falk Brettschneider).
+ */
+class PMDockWidgetAbstractHeader : public QFrame
+{
+ Q_OBJECT
+public:
+
+ /**
+ * Constructs this.
+ *
+ * @param parent the parent widget (usually a dockwidget)
+ * @param name the object instance name
+ */
+ PMDockWidgetAbstractHeader( PMDockWidget* parent, const char* name = 0L );
+
+ /**
+ * Destructs this.
+ */
+ virtual ~PMDockWidgetAbstractHeader(){};
+
+ /**
+ * Provides things concerning to switching to toplevel mode. Must be overridden by an inheriting class.
+ */
+ virtual void setTopLevel( bool ){};
+
+#ifndef NO_KDE2
+ /**
+ * Provides saving the current configuration. Must be overridden by an inheriting class.
+ */
+ virtual void saveConfig( KConfig* ){};
+
+ /**
+ * Provides loading the current configuration. Must be overridden by an inheriting class
+ */
+ virtual void loadConfig( KConfig* ){};
+#endif
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class PMDockWidgetAbstractHeaderPrivate;
+ PMDockWidgetAbstractHeaderPrivate *d;
+};
+
+/**
+ * An abstract class for all dockwidget drag-panels of a dockwidgets (and member of the dockwidget class set).
+ * See the class description of @ref PMDockWidgetHeaderDrag!
+ * More or less a minor helper class for the dockwidget class set.
+ *
+ * @author Max Judin (documentation: Falk Brettschneider).
+ */
+class PMDockWidgetAbstractHeaderDrag : public QFrame
+{
+ Q_OBJECT
+public:
+
+ /**
+ * Constructs this.
+ *
+ * @param parent the parent widget (usually a dockwidget header)
+ * @param dock the dockwidget where it belongs to
+ * @param name the object instance name
+ */
+ PMDockWidgetAbstractHeaderDrag( PMDockWidgetAbstractHeader* parent,
+ PMDockWidget* dock, const char* name = 0L );
+
+ /**
+ * Destructs this.
+ */
+ virtual ~PMDockWidgetAbstractHeaderDrag(){};
+
+ /**
+ * @return the dockwidget where this belongs to
+ */
+ PMDockWidget* dockWidget() const { return dw; }
+
+private:
+ /**
+ * the dockwidget where this belongs to
+ */
+ PMDockWidget* dw;
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class PMDockWidgetAbstractHeaderDragPrivate;
+ PMDockWidgetAbstractHeaderDragPrivate *d;
+};
+
+/**
+ * This special widget is the panel one can grip with the mouses (and member of the dockwidget class set).
+ * The widget for dragging, so to speak.
+ * Usually it is located in the @ref PMDockWidgetHeader.
+ * More or less a minor helper class for the dockwidget class set.
+ *
+ * @author Max Judin (documentation: Falk Brettschneider).
+ */
+class PMDockWidgetHeaderDrag : public PMDockWidgetAbstractHeaderDrag
+{
+ Q_OBJECT
+public:
+
+ /**
+ * Constructs this.
+ *
+ * @param parent the parent widget (usually a dockwidget header)
+ * @param dock the dockwidget where it belongs to
+ * @param name the object instance name
+ */
+ PMDockWidgetHeaderDrag( PMDockWidgetAbstractHeader* parent, PMDockWidget* dock,
+ const char* name = 0L );
+
+ /**
+ * Destructs this.
+ */
+ virtual ~PMDockWidgetHeaderDrag(){};
+
+protected:
+
+ /**
+ * Draws the drag panel (a double line)
+ */
+ virtual void paintEvent( QPaintEvent* );
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class PMDockWidgetHeaderDragPrivate;
+ PMDockWidgetHeaderDragPrivate *d;
+};
+
+/**
+ * The header (additional bar) for a @ref PMDockWidget s (and member of the dockwidget class set).
+ * It have got the buttons located there. And it is for recording and reading the button states.
+ * More or less a minor helper class for the dockwidget class set.
+ *
+ * @author Max Judin (documentation: Falk Brettschneider).
+ */
+class PMDockWidgetHeader : public PMDockWidgetAbstractHeader
+{
+ Q_OBJECT
+public:
+
+ /**
+ * Constructs this.
+ *
+ * @param parent the parent widget (usually a dockwidget)
+ * @param name the object instance name
+ */
+ PMDockWidgetHeader( PMDockWidget* parent, const char* name = 0L );
+
+ /**
+ * Destructs this.
+ */
+ virtual ~PMDockWidgetHeader(){};
+
+ /**
+ * Hides the close button and stay button when switching to toplevel or vice versa shows them.
+ *
+ * @param t toplevel or not
+ */
+ virtual void setTopLevel( bool t);
+
+ /**
+ * Sets the drag panel of this header.
+ *
+ * @param nd A pointer to the new drag panel
+ */
+ void setDragPanel( PMDockWidgetHeaderDrag* nd );
+
+ bool dragEnabled() const;
+ void setDragEnabled(bool b);
+
+#ifndef NO_KDE2
+ /**
+ * Saves the current button state to a KDE config container object.
+ *
+ * @param c the configuration safe
+ */
+ virtual void saveConfig( KConfig* c);
+
+ /**
+ * Loads the current button state from a KDE config container object.
+ *
+ * @param c the configuration safe
+ */
+ virtual void loadConfig( KConfig* );
+#endif
+
+protected slots:
+ /**
+ * Sets dragging the dockwidget off when the stay button is pressed down and vice versa.
+ */
+ void slotStayClicked();
+
+protected:
+
+ /**
+ * A layout manager for placing the embedded buttons (close and stay)
+ */
+ QHBoxLayout* layout;
+
+ /**
+ * a little button for closing (undocking and hiding) the dockwidget
+ */
+ PMDockButton_Private* closeButton;
+
+ /**
+ * a little button for undocking the dockwidget and add it as
+ * level widget
+ */
+ PMDockButton_Private* toDesktopButton;
+
+ /**
+ * a little button for enabling/disabling dragging the dockwidget with the mouse
+ */
+ PMDockButton_Private* stayButton;
+
+ /**
+ * a little button for dock back the dockwidget to it's previous dockwidget
+ */
+ PMDockButton_Private* dockbackButton;
+
+ /**
+ * the drag panel (double line)
+ */
+ PMDockWidgetHeaderDrag* drag;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class PMDockWidgetHeaderPrivate;
+ PMDockWidgetHeaderPrivate *d;
+};
+
+/**
+ * It just hides the special implementation of a dockwidget tab groups (and is member of the dockwidget class set).
+ * An abstraction what it is currently.
+ * In general it is like @ref QTabWidget but is more useful for the dockwidget class set.
+ * More or less a minor helper class for the dockwidget class set.
+ *
+ * @author Max Judin (documentation: Falk Brettschneider).
+ */
+class EXPORT_DOCKCLASS PMDockTabGroup : public QTabWidget
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructs this. It just calls the method of the base class.
+ */
+ PMDockTabGroup( QWidget *parent = 0, const char *name = 0 )
+ :QTabWidget( parent, name ){};
+
+ /**
+ * Destructs a PMDockTabGroup.
+ */
+ virtual ~PMDockTabGroup(){};
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class PMDockTabGroupPrivate;
+ PMDockTabGroupPrivate *d;
+};
+
+/**
+ * Floatable widget that can be dragged around with the mouse and
+ * encapsulate the actual widgets (and member of the dockwidget class
+ * set).
+ *
+ * You just grip the double-lined panel, tear it off its parent
+ * widget, drag it somewhere and let it loose. Depending on the
+ * position where you leave it, the dockwidget becomes a toplevel
+ * window on the desktop (floating mode) or docks to a new widget
+ * (dock mode). Note: A PMDockWidget can only be docked to a
+ * PMDockWidget.
+ *
+ * If you want to use this kind of widget, your main application
+ * window has to be a @ref PMDockMainWindow. That is because it has
+ * got several additional dock management features, for instance a
+ * @ref PMDockManager that has an overview over all dockwidgets and and
+ * a dockmovemanager (internal class) that handles the dock process.
+ *
+ * Usually you create an PMDockWidget that covers the actual widget in this way:
+ * <PRE>
+ * ...
+ * PMDockMainWindow* mainWidget;
+ * ...
+ * PMDockWidget* dock = 0L;
+ * dock = mainWidget->createDockWidget( "Any window caption", nicePixmap, 0L, i18n("window caption")); // 0L==no parent
+ * QWidget* actualWidget = new QWidget( dock);
+ * dock->setWidget( actualWidget); // embed it
+ * dock->setToolTipString(i18n("That's me")); // available when appearing as tab page
+ * ...
+ * </PRE>
+ *
+ * See @ref PMDockMainWindow how a dockwidget is docked in.
+ *
+ *
+ * @author Max Judin (documentation: Falk Brettschneider).
+ */
+class EXPORT_DOCKCLASS PMDockWidget: public QWidget
+{
+ Q_OBJECT
+friend class PMDockManager;
+friend class PMDockSplitter;
+friend class PMDockMainWindow;
+friend class PMDockArea;
+
+public:
+ /**
+ * Construct a dockwidget.
+ *
+ * Initially, docking to another and docking to this is allowed for
+ * every @p DockPosition. It is supposed to be no (tab) group. It will
+ * taken under control of its dockmanager.
+ *
+ * @param dockManager The responsible manager (dock helper)
+ * @param name Object instance name
+ * @param pixmap An icon (for instance shown when docked centered)
+ * @param parent Parent widget
+ * @param strCaption Title of the dockwidget window (shown when toplevel)
+ * @param strTabPageLabel The title of the tab page (shown when in tab page mode), if it is "", only the icon will be shown, if it is 0L, the label is set to strCaption
+ */
+ PMDockWidget( PMDockManager* dockManager, const char* name,
+ const QPixmap &pixmap, QWidget* parent = 0L, const QString& strCaption = 0L,
+ const QString& strTabPageLabel = " ", WFlags f = 0);
+
+ /**
+ * Destructs a dockwidget.
+ */
+ virtual ~PMDockWidget();
+
+ /**
+ * The possible positions where a dockwidget can dock to another dockwidget
+ */
+ enum DockPosition
+ {
+ DockNone = 0,
+ DockTop = 0x0001,
+ DockLeft = 0x0002,
+ DockRight = 0x0004,
+ DockBottom = 0x0008,
+ DockCenter = 0x0010,
+ DockDesktop= 0x0020,
+
+ DockCorner = DockTop | DockLeft | DockRight | DockBottom,
+ DockFullSite = DockCorner | DockCenter,
+ DockFullDocking = DockFullSite | DockDesktop
+ };
+
+ /**
+ * This is a key method of this class! Use it to dock dockwidgets to
+ * another dockwidget at the right position within its
+ * @ref PMDockMainWindow or a toplevel dockwidget.
+ *
+ *
+ * If the target is null, it will become a toplevel dockwidget at position pos;
+ * Note: Docking to another dockwidget means exactly:
+ * A new parent dockwidget will be created, that replaces the target dockwidget and contains another single helper widget (tab widget or panner)
+ * which contains both dockwidgets, this and the target dockwidget. So consider parent<->child relationships change completely during such actions.
+ *
+ * @param target The dockwidget to dock to
+ * @param dockPos One of the DockPositions this is going to dock to
+ * @param spliPos The split relation (in percent, or percent*100 in high resolution) between both dockwidgets, target and this
+ * @param pos The dock position, mainly of interest for docking to the desktop (as toplevel dockwidget)
+ * @param check Only for internal use;
+ * @param tabIndex The position index of the tab widget (when in tab page mode), -1 (default) means append
+ * @return result The group dockwidget that replaces the target dockwidget and will be grandparent of target and @p this.
+ */
+ PMDockWidget* manualDock( PMDockWidget* target, DockPosition dockPos, int spliPos = 50, QPoint pos = QPoint(0,0), bool check = false, int tabIndex = -1);
+
+ /**
+ * Specify where it is either possible or impossible for this to dock to another dockwidget.
+ *
+ * @param pos An OR'ed set of @p DockPositions
+ */
+ void setEnableDocking( int pos );
+
+ /**
+ * @return Where it is either possible or impossible for this to dock to another dockwidget (an OR'ed set of DockPositions).
+ */
+ int enableDocking() const { return eDocking; }
+
+ /**
+ * Specify where it is either possible or impossible for another dockwidget to dock to this.
+ *
+ * @param pos An OR'ed set of @p DockPositions
+ */
+ void setDockSite( int pos ){ sDocking = pos;}
+
+ /**
+ * @return There it is either possible or impossible for another dockwidget to dock to this (an OR'ed set of @p DockPositions).
+ */
+ int dockSite() const
+ {
+ // no docking if a floating dock widget
+ if( !parent( ) )
+ return 0;
+ return sDocking;
+ }
+
+ /**
+ * Sets the embedded widget.
+ *
+ * A QLayout takes care about proper resizing, automatically.
+ *
+ * @param w The pointer to the dockwidget's child widget.
+ */
+ void setWidget( QWidget* w);
+
+ /**
+ * Get the embedded widget.
+ *
+ * @return The pointer to the dockwidget's child widget, 0L if there's no such child.
+ */
+ QWidget* getWidget() const { return widget; };
+
+ /**
+ * Sets the header of this dockwidget.
+ *
+ * A @ref QLayout takes care about proper resizing, automatically.
+ * The header contains the drag panel, the close button and the stay button.
+ *
+ * @param ah A base class pointer to the dockwidget header
+ */
+ void setHeader( PMDockWidgetAbstractHeader* ah);
+
+ /**
+ * Normally it simply shows the dockwidget.
+ *
+ * But additionally, if it is docked to a tab widget (@p DockCenter), it is set as the active (visible) tab page.
+ */
+ void makeDockVisible();
+
+ /**
+ * @return If it may be possible to hide this.
+ *
+ * There are reasons that it's impossible:
+ * @li It is a (tab) group.
+ * @li It is already invisible ;-)
+ * @li The parent of this is the @ref PMDockMainWindow.
+ * @li It isn't able to dock to another widget.
+ */
+ bool mayBeHide() const;
+
+ /**
+ * @return If it may be possible to show this.
+ * There are reasons that it's impossible:
+ * @li It is a (tab) group.
+ * @li It is already visible ;-)
+ * @li The parent of this is the @p PMDockMainWindow.
+ */
+ bool mayBeShow() const;
+
+ /**
+ * @return The dockmanager that is responsible for this.
+ */
+ PMDockManager* dockManager() const { return manager; }
+
+ /**
+ * Stores a string for a tooltip.
+ *
+ * That tooltip string has only a meaning when this dockwidget is shown as tab page.
+ * In this case the tooltip is shown when one holds the mouse cursor on the tab page header.
+ * Such tooltip will for instance be useful, if you use only icons there.
+ * Note: Setting an empty string switches the tooltip off.
+ *
+ * @param ttStr A string for the tooltip on the tab.
+ */
+ void setToolTipString(const QString& ttStr) { toolTipStr = ttStr; };
+
+ /**
+ * @return The tooltip string being shown on the appropriate tab page header when in dock-centered mode.
+ */
+ const QString& toolTipString() const { return toolTipStr; };
+
+ /**
+ * @return result @p true, if a dockback is possible, otherwise @p false.
+ */
+ bool isDockBackPossible() const;
+
+ /**
+ * Sets a string that is used for the label of the tab page when in tab page mode
+ * @param label The new tab page label.
+ */
+ void setTabPageLabel( const QString& label) { tabPageTitle = label; };
+
+ /**
+ * @return A string that is used for the label of the tab page when in tab page mode.
+ */
+ const QString& tabPageLabel() const { return tabPageTitle; };
+
+ /**
+ * Catches and processes some @ref QWidget events that are interesting for dockwidgets.
+ */
+ virtual bool event( QEvent * );
+
+ /**
+ * Add dockwidget management actions to @ref QWidget::show.
+ */
+ virtual void show();
+ /**
+ * @return the parent widget of this if it inherits class PMDockTabGroup
+ */
+ PMDockTabGroup* parentDockTabGroup() const;
+
+#ifndef NO_KDE2
+
+ /**
+ * Sets the type of the dock window
+ *
+ * @param windowType is type of dock window
+ */
+ void setDockWindowType (NET::WindowType windowType);
+
+#endif
+
+ /**
+ * Sets the type of the dock window
+ *
+ * @param windowType is type of dock window
+ */
+ void setDockWindowTransient (QWidget *parent, bool transientEnabled);
+
+ // MODIFICATION (lpassos)
+ /**
+ *
+ * Return the current dock position of the widget
+ */
+ DockPosition getDockPosition( ) const { return currentDockPos; }
+public slots:
+ /**
+ * Docks a dockwidget back to the dockwidget that was the neighbor
+ widget before the current dock position.
+ */
+ void dockBack();
+
+ /**
+ * Toggles the visibility state of the dockwidget if it is able to be shown or to be hidden.
+ */
+ void changeHideShowState();
+
+ /**
+ * Undocks this. It means it becomes a toplevel widget framed by the system window manager.
+ * A small panel at the top of this undocked widget gives the possibility to drag it into
+ * another dockwidget by mouse (docking).
+ */
+ void undock();
+
+ // MODIFICATION (zehender)
+ /**
+ * Docks the widget to the desktop (as a toplevel widget)
+ */
+ void toDesktop( );
+
+ /**
+ * Sets the caption and tab label
+ */
+ void slotSetCaption( const QString& );
+
+protected:
+
+ /**
+ * Checks some conditions and shows or hides the dockwidget header (drag panel).
+ * The header is hidden if:
+ * @li the parent widget is the PMDockMainWindow
+ * @li this is a (tab) group dockwidget
+ * @li it is not able to dock to another dockwidget
+ */
+ void updateHeader();
+
+signals:
+ /**
+ * Emitted when another dock widget is docking to this.
+ *
+ * @param dw the dockwidget that is docking to this
+ * @param dp the DockPosition where it wants to dock to
+ */
+ void docking( PMDockWidget* dw, PMDockWidget::DockPosition dp);
+
+ /**
+ * Signals that the dock default position is set.
+ */
+ void setDockDefaultPos();
+
+ /**
+ * Emitted when the close button of the panel (@ref PMDockWidgetHeader) has been clicked.
+ */
+ void headerCloseButtonClicked();
+
+ /**
+ * Emitted when the dockback button of the panel (@ref PMDockWidgetHeader) has been clicked.
+ */
+ void headerDockbackButtonClicked();
+
+ /**
+ * Emitted when the widget processes a close event.
+ */
+ void iMBeingClosed();
+ /**
+ * Emitted when the widget has undocked.
+ */
+ void hasUndocked();
+
+protected slots:
+
+ /**
+ * Does several things here when it has noticed that the former brother widget (closest neighbor) gets lost.
+ * The former brother widget is needed for a possible dockback action, to speak with the Beatles:
+ * "To get back to where you once belonged" ;-)
+ */
+ void loseFormerBrotherDockWidget();
+
+protected:
+ /**
+ * earlier closest neighbor widget, so it's possible to dock back to it.
+ */
+ PMDockWidget* formerBrotherDockWidget;
+ /**
+ * the current dock position.
+ */
+ DockPosition currentDockPos;
+ /**
+ * the former dock position when it really was at another position before.
+ */
+ DockPosition formerDockPos;
+ /**
+ * a string used as tooltip for the tab page header when in dock-centered mode.
+ */
+ QString toolTipStr;
+ /**
+ * a string used as title of the tab page when in tab page mode
+ */
+ QString tabPageTitle;
+
+private:
+ /**
+ * Sets the caption (window title) of the given tab widget.
+ *
+ * @param g the group (tab) widget
+ */
+ void setDockTabName( PMDockTabGroup* g);
+
+ /**
+ * Reparent to s or set this to the PMDockMainWindow's view if s is that dockmainwindow.
+ * If s is O, simply move the widget.
+ *
+ * @param s the target widget to reparent to
+ * @param p the point to move to (if it doesn't reparent)
+ */
+ void applyToWidget( QWidget* s, const QPoint& p = QPoint(0,0) );
+
+ /**
+ * A base class pointer to the header of this dockwidget
+ */
+ PMDockWidgetAbstractHeader* header;
+
+ /**
+ * the embedded widget
+ */
+ QWidget* widget;
+
+ /**
+ * the layout manager that takes care about proper resizing and moving the embedded widget and the header
+ */
+ QVBoxLayout* layout;
+
+ /**
+ * the responsible dockmanager
+ */
+ PMDockManager* manager;
+
+ /**
+ * an icon for the tab widget header
+ */
+ QPixmap* pix;
+
+ /**
+ * Information about the ability for docking to another dockwidget.
+ */
+ int eDocking;
+
+ /**
+ * Information which site of this dockwidget is free for docking of other dockwidgets.
+ */
+ int sDocking;
+
+ /**
+ * Previous side (left,right,top,bottom) where this dockwidget was before a dragging action, none if it wasn't dragged before.
+ */
+ PMDockWidget::DockPosition prevSideDockPosBeforeDrag;
+
+ // GROUP data
+ QString firstName;
+ QString lastName;
+ Orientation splitterOrientation;
+ bool isGroup;
+ bool isTabGroup;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ PMDockWidgetPrivate *d;
+};
+
+/**
+ * The manager that knows all dockwidgets and handles the dock process (and member of the dockwidget class set).
+ * More or less a helper class for the PMDockWidget class set but of interest for some functionality
+ * that can be called within a @ref PMDockMainWindow or a @ref PMDockWidget .
+ *
+ * An important feature is the ability to read or save the current state of all things concerning to
+ * dockwidgets to @ref KConfig .
+ *
+ * The dockmanager is also often used when a certain dockwidget or a child of such dockwidget must be found.
+ *
+ * @author Max Judin (documentation: Falk Brettschneider).
+ */
+class EXPORT_DOCKCLASS PMDockManager: public QObject
+{
+ Q_OBJECT
+friend class PMDockWidget;
+friend class PMDockMainWindow;
+
+public:
+ /**
+ * Constructs a dockmanager. Some initialization happen:
+ * @li It installs an event filter for the main window,
+ * @li a control list for dock objects
+ * @li a control list for menu items concerning to menus provided by the dockmanager
+ * @li Some state variables are set
+ *
+ * @param mainWindow the main window controlled by this
+ * @param name the internal QOject name
+ */
+ PMDockManager( QWidget* mainWindow, const char* name = 0L );
+
+ /**
+ * Destructs a dockmanager.
+ */
+ virtual ~PMDockManager();
+
+#ifndef NO_KDE2
+ /**
+ * Saves the current state of the dockmanager and of all controlled widgets.
+ * State means here to save the geometry, visibility, parents, internal object names, orientation,
+ * separator positions, dockwidget-group information, tab widget states (if it is a tab group) and
+ * last but not least some necessary things for recovering the dockmainwindow state.
+ *
+ * @param c the KDE configuration saver
+ * @param group the name of the section in KConfig
+ */
+ void writeConfig( KConfig* c = 0L, QString group = QString::null );
+
+ /**
+ * Like writeConfig but reads the whole stuff in.
+ *
+ * In order to restore a window configuration
+ * from a config file, it looks up widgets by name
+ * (QObject::name) in the childDock variable of
+ * PMDockManager. This list in turn contains all
+ * PMDockWidgets (according to the PMDockWidget constructor).
+ * So in principle, in order to restore a window layout,
+ * one must first construct all widgets, put each of them in a
+ * PMDockWidget and then call readConfig(). And for all that
+ * to work, each widget must have a unique name.
+ *
+ * @param c the KDE configuration saver
+ * @param group the name of the section in KConfig
+ */
+ void readConfig ( KConfig* c = 0L, QString group = QString::null );
+#endif
+
+ /**
+ * Saves the current dock window layout into a DOM tree below the given element.
+ */
+ void writeConfig(QDomElement &base);
+ /**
+ * Reads the current dock window layout from a DOM tree below the given element.
+ */
+ void readConfig(QDomElement &base);
+
+ /**
+ * Shows all encapsulated widgets of all controlled dockwidgets and shows all dockwidgets which are
+ * parent of a dockwidget tab group.
+ */
+ void activate();
+
+ /**
+ * It's more or less a method that catches several events which are interesting for the dockmanager.
+ * Mainly mouse events during the drag process of a dockwidgets are of interest here.
+ *
+ * @param _ the object that sends the event
+ * @param _ the event
+ * @return the return value of the method call of the base class method
+ */
+ virtual bool eventFilter( QObject *, QEvent * );
+
+ /**
+ * This method finds out what a widgets' dockwidget is. That means the dockmanager has a look at all
+ * dockwidgets it knows and tells you when one of those dockwidgets covers the given widget.
+ *
+ * @param w any widget that is supposed to be encapsulated by one of the controlled dockwidgets
+ * @return the dockwidget that encapsulates that widget, otherwise 0
+ */
+ PMDockWidget* findWidgetParentDock( QWidget* w) const;
+
+ /**
+ * Works like makeDockVisible() but can be called for widgets that covered by a dockwidget.
+ *
+ * @param w the widget that is encapsulated by a dockwidget that turns to visible.
+ */
+ void makeWidgetDockVisible( QWidget* w ){ findWidgetParentDock(w)->makeDockVisible(); }
+
+ /**
+ * @return the popupmenu for showing/hiding dockwidgets
+ */
+ QPopupMenu* dockHideShowMenu() const { return menu; }
+
+ /**
+ * @param dockName an internal QObject name
+ * @return the dockwidget that has got that internal QObject name
+ */
+ PMDockWidget* getDockWidgetFromName( const QString& dockName );
+
+ /**
+ * Enables opaque resizing. Opaque resizing is initially turned off.
+ * Call this method before you create any dock widgets!
+ */
+ void setSplitterOpaqueResize(bool b=true);
+
+ /**
+ * Returns TRUE if opaque resizing is enabled, FALSE otherwise.
+ */
+ bool splitterOpaqueResize() const;
+
+ /**
+ * Try to preserve the widget's size. Works like KeepSize resize mode
+ * of QSplitter. Off by default.
+ * Call this method before you create any dock widgets!
+ */
+ void setSplitterKeepSize(bool b=true);
+
+ /**
+ * Returns TRUE if the KeepSize is enabled, FALSE otherwise.
+ */
+ bool splitterKeepSize() const;
+
+ /**
+ * Operate the splitter with a higher resolution. Off by default.
+ * Call this method before you create any dock widgets!
+ * If high resolution is used all splitter position parameters
+ * are percent*100 instead of percent.
+ */
+ void setSplitterHighResolution(bool b=true);
+
+ /**
+ * Returns TRUE if the splitter uses the high resolution, FALSE otherwise.
+ */
+ bool splitterHighResolution() const;
+
+ /**
+ * Returns the main dock widget
+ */
+ QWidget* dockMainWidget( ) const { return main; }
+
+signals:
+
+ /**
+ * Signals changes of the docking state of a dockwidget. Usually the dock-toolbar will be updated then.
+ */
+ void change();
+
+ /**
+ * Signals a dockwidget is replaced with another one.
+ */
+ void replaceDock( PMDockWidget* oldDock, PMDockWidget* newDock );
+
+ /**
+ * Signals a dockwidget without parent (toplevel) is shown.
+ */
+ void setDockDefaultPos( PMDockWidget* );
+
+private slots:
+
+ /**
+ * Clears the popupmenu for showing/hiding dockwidgets and fills it with the current states of all controlled dockwidgets.
+ */
+ void slotMenuPopup();
+
+ /**
+ * This method assumes a menuitem of the popupmenu for showing/hiding dockwidgets is selected and toggles that state.
+ *
+ * @param id the popupmenu id of the selected menuitem
+ */
+ void slotMenuActivated( int id);
+
+ /* clears the old drawn drag rectangle (oldDragRect) from screen and
+ * draws the new current drag rectangle (dragRect) depending on the current mouse position.
+ * This highlights the dockwidget which is the currently chosen target during a dock action.
+ */
+ void drawDragRectangle();
+
+private:
+
+ /**
+ * A data structure containing data about every dockwidget that is under control.
+ */
+ struct MenuDockData
+ {
+ MenuDockData( PMDockWidget* _dock, bool _hide )
+ {
+ dock = _dock;
+ hide = _hide;
+ };
+ ~MenuDockData(){};
+
+ PMDockWidget* dock;
+ bool hide;
+ };
+
+ /**
+ * Finds the PMDockWidget at the position given as parameter
+ *
+ * @param pos global (desktop) position of the wanted dockwidget
+ * @return the dockwidget at that position
+ */
+ PMDockWidget* findDockWidgetAt( const QPoint& pos );
+
+ /**
+ * Finds the QWidget recursively at the position given as parameter
+ *
+ * @param w a variable where the method puts the QWidget at that position (instead of a return value)
+ * @param p the parent widget where the recursive search should start from
+ * @param pos global (desktop) position of the wanted dockwidget
+ */
+ void findChildDockWidget( QWidget*& w, const QWidget* p, const QPoint& pos );
+ // MODIFICATION (lpassos)
+ // Made findChildDockWidget public
+public:
+ /**
+ * Finds all dockwidgets which are child, grandchild and so on of p.
+ *
+ * @param p the parent widget where the recursive search starts from
+ * @param l the widget list that contains the search result after the return of this method
+ */
+ void findChildDockWidget( const QWidget* p, QWidgetList& l);
+ /**
+ * Returns all floating dock widgets
+ */
+ void findFloatingWidgets( QPtrList<PMDockWidget>& l );
+
+private:
+ /**
+ * Sets a dockwidget in drag mode.
+ */
+ void startDrag( PMDockWidget* );
+
+ /**
+ * Moves a dockwidget that is in drag mode.
+ *
+ * @param d the dockwidget which is dragged
+ * @param pos the new position of the dragged dockwidget
+ */
+ void dragMove( PMDockWidget* d, QPoint pos );
+
+ /**
+ * Aborts the drag mode. Restores the cursor and hides the drag indicator.
+ */
+ void cancelDrop();
+
+ /**
+ * Finishes the drag mode. If the user let it drop on an other dockwidget, it will possibly be docked (if allowed),
+ * if the user drops it outside of the application window it becomes toplevel.
+ */
+ void drop();
+
+// class members
+
+ /**
+ * Usually the PMDockMainWindow but not necessarily.
+ */
+ QWidget* main;
+
+ /**
+ * The dockwidget that is being dragged at the moment
+ */
+ PMDockWidget* currentDragWidget;
+
+ /**
+ * The target dockwidget where the currentDragWidget is dropped
+ */
+ PMDockWidget* currentMoveWidget; // widget where mouse moving
+
+ /**
+ * It is of interest during the dock process. Then it contains all child dockwidgets.
+ */
+ QWidgetList* childDockWidgetList;
+
+ /**
+ * The dockposition where the dockwidget would be docked to, if we dropped it here.
+ */
+ PMDockWidget::DockPosition curPos;
+
+ /**
+ * A QList of all objects that are important for docking.
+ * Some serve as group widgets of dockwidgets, others encapsulate normal widgets.
+ */
+ QObjectList* childDock;
+
+ /**
+ * Contains dockwidgets that are created automatically by the dockmanager. For internal use.
+ */
+ QObjectList* autoCreateDock;
+
+ /**
+ * For storing the width during the dragging of a dockwidget.
+ */
+ int storeW;
+
+ /**
+ * For storing the height during the dragging of a dockwidget.
+ */
+ int storeH;
+
+ /**
+ * State variable if there is a drag process active.
+ */
+ bool draging;
+
+ /**
+ * State variable if there is an undock process active
+ */
+ bool undockProcess;
+
+ /**
+ * The dockmanager sets it to true if the user cancels the drag by moving the cursor
+ * on a invalid drop place
+ */
+ bool dropCancel;
+
+ /**
+ * A popup menu that contains one menuitem for each dockwidget that shows the current visibility state and
+ * to show or hide the appropriate dockwidget.
+ */
+ QPopupMenu* menu;
+
+ /**
+ * An internal list containing data for the menuitems for the visibility popup menu.
+ */
+ QPtrList<MenuDockData> *menuData;
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class PMDockManagerPrivate;
+ PMDockManagerPrivate *d;
+};
+
+/**
+ * A special kind of @ref KMainWindow that is able to have dockwidget child widgets (and member of the dockwidget class set).
+ *
+ * The main widget should be a @ref PMDockWidget where other @ref PMDockWidget can be docked to
+ * the left, right, top, bottom or to the middle.
+ * Note: dock to the middle means to drop on a dockwidget and to unite them to a new widget, a tab control.
+ *
+ * Furthermore, the PMDockMainWindow has got the @ref PMDockManager and some data about the dock states.
+ *
+ * If you've got some dockwidgets, you can dock them to the dockmainwindow to initialize a start scene:
+ * Here an example:
+ * <PRE>
+ * DockApplication::DockApplication( const char* name) : PMDockMainWindow( name)
+ * {
+ * ...
+ * PMDockWidget* mainDock;
+ * mainDock = createDockWidget( "Falk's MainDockWidget", mainPixmap, 0L, "main_dock_widget");
+ * AnyContentsWidget* cw = new AnyContentsWidget( mainDock);
+ * mainDock->setWidget( cw);
+ * // allow others to dock to the 4 sides
+ * mainDock->setDockSite(PMDockWidget::DockCorner);
+ * // forbit docking abilities of mainDock itself
+ * mainDock->setEnableDocking(PMDockWidget::DockNone);
+ * setView( mainDock); // central widget in a KDE mainwindow
+ * setMainDockWidget( mainDock); // master dockwidget
+ * ...
+ * PMDockWidget* dockLeft;
+ * dockLeft = createDockWidget( "Intially left one", anyOtherPixmap, 0L, i18n("The left dockwidget"));
+ * AnotherWidget* aw = new AnotherWidget( dockLeft);
+ * dockLeft->setWidget( aw);
+ * dockLeft->manualDock( mainDock, // dock target
+ * PMDockWidget::DockLeft, // dock site
+ * 20 ); // relation target/this (in percent)
+ * ...
+ * </PRE>
+ *
+ * Docking is fully dynamical at runtime. That means you can always move dockwidgets via drag and drop.
+ *
+ * And last but not least you can use the popupmenu for showing or hiding any controlled dockwidget
+ * of this class and insert it to your main menu bar or anywhere else.
+ *
+ * @author Max Judin (documentation: Falk Brettschneider).
+ */
+class EXPORT_DOCKCLASS PMDockMainWindow : public KMainWindow, virtual public PartBase
+{
+ Q_OBJECT
+
+friend class PMDockManager;
+
+public:
+
+ /**
+ * Constructs a dockmainwindow. It calls its base class constructor and does additional things concerning
+ * to the dock stuff:
+ * @li information about the dock state of this' children gets initialized
+ * @li a dockmanager is created...
+ * @li ...and gets initialized
+ * @li the main dockwidget is set to 0
+ *
+ * @param name object name
+ */
+ PMDockMainWindow( QWidget* parent = 0L, const char *name = 0L, WFlags f = WType_TopLevel | WDestructiveClose );
+
+ /**
+ * Destructs a dockmainwindow.
+ */
+ virtual ~PMDockMainWindow();
+
+ /**
+ * Returns the dockmanager of this. (see @ref PMDockManager)
+ * @return pointer to the wanted dockmanager
+ */
+ PMDockManager* manager() const { return dockManager; }
+
+ /**
+ * Sets a new main dockwidget.
+ * Additionally, the toolbar is re-initialized.
+ *
+ * @param _ dockwidget that become the new main dockwidget
+ */
+ void setMainDockWidget( PMDockWidget* );
+
+ /**
+ * Returns the main dockwidget.
+ *
+ * @return pointer to the main dockwidget
+ */
+ PMDockWidget* getMainDockWidget() const { return mainDockWidget; }
+
+ /**
+ * This is one of the most important methods!
+ * The PMDockMainWindow creates a new dockwidget object here that usually should encapsulate the user's widget.
+ * The new dockwidget is automatically taken under control by the dockmanager of the dockmainwindow.
+ *
+ * @param name QObject name (default dockwidget caption)
+ * @param pixmap window icon (for instance shown when docked as tabwidget entry)
+ * @param parent parent widget for the new dockwidget
+ * @param strCaption window title (shown when toplevel)
+ * @param strTabPageLabel title of the tab page (visible when in tab page mode), if it is "", only the icon will be shown; if it is 0L, the label is set to strCaption
+ * @return a pointer to the new created dockwidget
+ */
+ PMDockWidget* createDockWidget( const QString& name, const QPixmap &pixmap, QWidget* parent = 0L, const QString& strCaption = 0L, const QString& strTabPageLabel = " ");
+
+ /**
+ * Saves the current dock window layout into a DOM tree below the given element.
+ */
+ void writeDockConfig(QDomElement &base);
+ /**
+ * Reads the current dock window layout from a DOM tree below the given element.
+ */
+ void readDockConfig(QDomElement &base);
+
+#ifndef NO_KDE2
+ /**
+ * It writes the current dock state in the given section of KConfig.
+ *
+ * @param c KDE class for saving configurations
+ * @param group name of section to write to
+ */
+ void writeDockConfig( KConfig* c = 0L, QString group = QString::null );
+
+ /**
+ * It reads the current dock state from the given section of KConfig.
+ *
+ * @param c KDE class for saving configurations
+ * @param group name of section to read from
+ */
+ void readDockConfig ( KConfig* c = 0L, QString group = QString::null );
+#endif
+
+ /**
+ * It runs through all dockwidgets which are under control of the dockmanager and calls show() for every
+ * encapsulated widget and show() for the dockwidget itself if it is not in tab mode.
+ * Additionally, if the main dockwidget is not a QDialog, it will be shown.
+ */
+ void activateDock(){ dockManager->activate(); }
+
+ /**
+ * Returns a popup menu that contains entries for all controlled dockwidgets making hiding and showing
+ * them possible.
+ *
+ * @return the wanted popup menu
+ */
+ QPopupMenu* dockHideShowMenu() const { return dockManager->dockHideShowMenu(); }
+
+ /**
+ * This method shows the given dockwidget.
+ * The clue is that it also considers the dockwidget could be a tab page
+ * and must set to be the activate one.
+ *
+ * @param dock the dockwidget that is to be shown
+ */
+ void makeDockVisible( PMDockWidget* dock );
+
+ /**
+ * This method hides the given dockwidget.
+ *
+ * @param dock the dockwidget that is to be shown
+ */
+ void makeDockInvisible( PMDockWidget* dock );
+
+ /**
+ * This is an overloaded member function, provided for convenience.
+ * It differs from the above function only in what argument(s) it accepts.
+ */
+ void makeWidgetDockVisible( QWidget* widget );
+
+ /**
+ * This method calls the base class method.
+ * If the given widget inherits PMDockWidget, applyToWidget(this) is called.
+ *
+ * @param _ any widget that should become the main view
+ */
+ void setView( QWidget* );
+
+signals:
+ /**
+ * Signals a certain dockwidget is undocked now.
+ */
+ void dockWidgetHasUndocked(PMDockWidget*);
+
+protected:
+
+ /**
+ * A pointer to the main dockwidget (where one can manualDock() to
+ */
+ PMDockWidget* mainDockWidget;
+
+ /**
+ * A pointer to the manager for the dock process
+ */
+ PMDockManager* dockManager;
+
+protected slots:
+ /**
+ * Called whenever one of the dockwidgets of this has been undocked.
+ */
+ void slotDockWidgetUndocked();
+
+ // kparts/dockmainwindow stuff
+protected slots:
+
+ /**
+ * Create the GUI (by merging the host's and the active part's)
+ *
+ * Called on startup and whenever the active part changes
+ * For this you need to connect this slot to the
+ * @ref KPartManager::activePartChanged() signal
+ * @param part The active part (set to 0L if no part).
+ */
+ void createGUI( KParts::Part * part );
+
+ /**
+ * Called when the active part wants to change the statusbar message
+ * Reimplement if your dock-mainwindow has a complex statusbar
+ * (with several items)
+ */
+ virtual void slotSetStatusBarText( const QString & );
+
+protected:
+ virtual void createShellGUI( bool create = true );
+ // end kparts/dockmainwindow stuff
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ PMDockMainWindowPrivate *d;
+};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#ifdef _JOWENN_EXPERIMENTAL_
+/* Joseph Wenninger jowenn@kde.org Experimental (Just all KMainWindow references changed to QWidget, otherwise nearly exactly the
+same as PMDockMainWindow*/
+
+class EXPORT_DOCKCLASS PMDockArea : public QWidget
+{
+ Q_OBJECT
+
+friend class PMDockManager;
+
+public:
+
+
+ PMDockArea( QWidget* parent = 0L, const char *name = 0L);
+
+ virtual ~PMDockArea();
+
+ PMDockManager* manager(){ return dockManager; }
+
+
+ void setMainDockWidget( PMDockWidget* );
+ PMDockWidget* getMainDockWidget(){ return mainDockWidget; }
+
+ PMDockWidget* createDockWidget( const QString& name, const QPixmap &pixmap, QWidget* parent = 0L, const QString& strCaption = 0L, const QString& strTabPageLabel = " ");
+
+ void writeDockConfig(QDomElement &base);
+ void readDockConfig(QDomElement &base);
+
+#ifndef NO_KDE2
+ void writeDockConfig( KConfig* c = 0L, QString group = QString::null );
+ void readDockConfig ( KConfig* c = 0L, QString group = QString::null );
+#endif
+
+
+
+ void activateDock(){ dockManager->activate(); }
+ QPopupMenu* dockHideShowMenu(){ return dockManager->dockHideShowMenu(); }
+ void makeDockVisible( PMDockWidget* dock );
+ void makeDockInvisible( PMDockWidget* dock );
+ void makeWidgetDockVisible( QWidget* widget );
+ //void setView( QWidget* );
+
+signals:
+ /**
+ * Signals a certain dockwidget is undocked now.
+ */
+ void dockWidgetHasUndocked(PMDockWidget*);
+
+protected:
+
+ PMDockWidget* mainDockWidget;
+ PMDockManager* dockManager;
+
+protected slots:
+ void slotDockWidgetUndocked();
+
+public:
+ virtual void resizeEvent(QResizeEvent *);
+
+protected:
+ virtual void virtual_hook( int id, void* data );
+private:
+ class PMDockMainWindowPrivate;
+ PMDockMainWindowPrivate *d;
+};
+
+#endif
+
+#endif
+
+
diff --git a/kpovmodeler/pmdockwidget_private.cpp b/kpovmodeler/pmdockwidget_private.cpp
new file mode 100644
index 00000000..cdf21930
--- /dev/null
+++ b/kpovmodeler/pmdockwidget_private.cpp
@@ -0,0 +1,372 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Max Judin <novaprint@mtu-net.ru>
+ Modified 2002 Andreas Zehender <zehender@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#include "pmdockwidget.h"
+#include "pmdockwidget_private.h"
+
+#include <qpainter.h>
+#include <qcursor.h>
+
+PMDockSplitter::PMDockSplitter(QWidget *parent, const char *name, Orientation orient, int pos, bool highResolution)
+: QWidget(parent, name)
+{
+ divider = 0L;
+ child0 = 0L;
+ child1 = 0L;
+ orientation = orient;
+ mOpaqueResize = false;
+ mKeepSize = false;
+ mHighResolution = highResolution;
+ setSeparatorPos( pos, false );
+ initialised = false;
+}
+
+void PMDockSplitter::activate(QWidget *c0, QWidget *c1)
+{
+ if ( c0 ) child0 = c0;
+ if ( c1 ) child1 = c1;
+
+ setupMinMaxSize();
+
+ if (divider) delete divider;
+ divider = new QFrame(this, "pannerdivider");
+ divider->setFrameStyle(QFrame::Panel | QFrame::Raised);
+ divider->setLineWidth(1);
+ divider->raise();
+
+ if (orientation == Horizontal)
+ divider->setCursor(QCursor(sizeVerCursor));
+ else
+ divider->setCursor(QCursor(sizeHorCursor));
+
+ divider->installEventFilter(this);
+
+ initialised= true;
+
+ updateName();
+
+ divider->show();
+ resizeEvent(0);
+}
+
+void PMDockSplitter::setupMinMaxSize()
+{
+ // Set the minimum and maximum sizes
+ int minx, maxx, miny, maxy;
+ if (orientation == Horizontal) {
+ miny = child0->minimumSize().height() + child1->minimumSize().height()+4;
+ maxy = child0->maximumSize().height() + child1->maximumSize().height()+4;
+ minx = (child0->minimumSize().width() > child1->minimumSize().width()) ? child0->minimumSize().width() : child1->minimumSize().width();
+ maxx = (child0->maximumSize().width() > child1->maximumSize().width()) ? child0->maximumSize().width() : child1->maximumSize().width();
+
+ miny = (miny > 4) ? miny : 4;
+ maxy = (maxy < 32000) ? maxy : 32000;
+ minx = (minx > 2) ? minx : 2;
+ maxx = (maxx < 32000) ? maxx : 32000;
+ } else {
+ minx = child0->minimumSize().width() + child1->minimumSize().width()+4;
+ maxx = child0->maximumSize().width() + child1->maximumSize().width()+4;
+ miny = (child0->minimumSize().height() > child1->minimumSize().height()) ? child0->minimumSize().height() : child1->minimumSize().height();
+ maxy = (child0->maximumSize().height() > child1->maximumSize().height()) ? child0->maximumSize().height() : child1->maximumSize().height();
+
+ minx = (minx > 4) ? minx : 4;
+ maxx = (maxx < 32000) ? maxx : 32000;
+ miny = (miny > 2) ? miny : 2;
+ maxy = (maxy < 32000) ? maxy : 32000;
+ }
+ setMinimumSize(minx, miny);
+ setMaximumSize(maxx, maxy);
+}
+
+void PMDockSplitter::deactivate()
+{
+ if (divider) delete divider;
+ divider = 0L;
+ initialised= false;
+}
+
+void PMDockSplitter::setSeparatorPos(int pos, bool do_resize)
+{
+ xpos = pos;
+ if (do_resize)
+ resizeEvent(0);
+}
+
+int PMDockSplitter::separatorPos() const
+{
+ return xpos;
+}
+
+void PMDockSplitter::resizeEvent(QResizeEvent *ev)
+{
+ if (initialised){
+ int factor = (mHighResolution)? 10000:100;
+ // real resize event, recalculate xpos
+ if (ev && mKeepSize && isVisible()) {
+ if (orientation == Horizontal) {
+ if (ev->oldSize().height() != ev->size().height())
+ xpos = factor * checkValue( child0->height()+1 ) / height();
+ } else {
+ if (ev->oldSize().width() != ev->size().width())
+ xpos = factor * checkValue( child0->width()+1 ) / width();
+ }
+ }
+ int position = checkValue( (orientation == Vertical ? width() : height()) * xpos/factor );
+ if (orientation == Horizontal){
+ child0->setGeometry(0, 0, width(), position);
+ child1->setGeometry(0, position+4, width(), height()-position-4);
+ divider->setGeometry(0, position, width(), 4);
+ } else {
+ child0->setGeometry(0, 0, position, height());
+ child1->setGeometry(position+4, 0, width()-position-4, height());
+ divider->setGeometry(position, 0, 4, height());
+ }
+ }
+}
+
+int PMDockSplitter::checkValue( int position ) const
+{
+ if (initialised){
+ if (orientation == Vertical){
+ if (position < (child0->minimumSize().width()))
+ position = child0->minimumSize().width();
+ if ((width()-4-position) < (child1->minimumSize().width()))
+ position = width() - (child1->minimumSize().width()) -4;
+ } else {
+ if (position < (child0->minimumSize().height()))
+ position = (child0->minimumSize().height());
+ if ((height()-4-position) < (child1->minimumSize().height()))
+ position = height() - (child1->minimumSize().height()) -4;
+ }
+ }
+
+ if (position < 0) position = 0;
+
+ if ((orientation == Vertical) && (position > width()))
+ position = width();
+ if ((orientation == Horizontal) && (position > height()))
+ position = height();
+
+ return position;
+}
+
+bool PMDockSplitter::eventFilter(QObject *o, QEvent *e)
+{
+ QMouseEvent *mev;
+ bool handled = false;
+ int factor = (mHighResolution)? 10000:100;
+
+ switch (e->type()) {
+ case QEvent::MouseMove:
+ mev= (QMouseEvent*)e;
+ child0->setUpdatesEnabled(mOpaqueResize);
+ child1->setUpdatesEnabled(mOpaqueResize);
+ if (orientation == Horizontal) {
+ if (!mOpaqueResize) {
+ int position = checkValue( mapFromGlobal(mev->globalPos()).y() );
+ divider->move( 0, position );
+ } else {
+ xpos = factor * checkValue( mapFromGlobal(mev->globalPos()).y() ) / height();
+ resizeEvent(0);
+ divider->repaint(true);
+ }
+ } else {
+ if (!mOpaqueResize) {
+ int position = checkValue( mapFromGlobal(QCursor::pos()).x() );
+ divider->move( position, 0 );
+ } else {
+ xpos = factor * checkValue( mapFromGlobal( mev->globalPos()).x() ) / width();
+ resizeEvent(0);
+ divider->repaint(true);
+ }
+ }
+ handled= true;
+ break;
+ case QEvent::MouseButtonRelease:
+ child0->setUpdatesEnabled(true);
+ child1->setUpdatesEnabled(true);
+ mev= (QMouseEvent*)e;
+ if (orientation == Horizontal){
+ xpos = factor* checkValue( mapFromGlobal(mev->globalPos()).y() ) / height();
+ resizeEvent(0);
+ divider->repaint(true);
+ } else {
+ xpos = factor* checkValue( mapFromGlobal(mev->globalPos()).x() ) / width();
+ resizeEvent(0);
+ divider->repaint(true);
+ }
+ handled= true;
+ break;
+ default:
+ break;
+ }
+ return (handled) ? true : QWidget::eventFilter( o, e );
+}
+
+bool PMDockSplitter::event( QEvent* e )
+{
+ if ( e->type() == QEvent::LayoutHint ){
+ // change children min/max size
+ setupMinMaxSize();
+ setSeparatorPos(xpos);
+ }
+ return QWidget::event(e);
+}
+
+QWidget* PMDockSplitter::getAnother( QWidget* w ) const
+{
+ return ( w == child0 ) ? child1 : child0;
+}
+
+void PMDockSplitter::updateName()
+{
+ if ( !initialised ) return;
+
+ QString new_name = QString( child0->name() ) + "," + child1->name();
+ parentWidget()->setName( new_name.latin1() );
+ parentWidget()->setCaption( child0->caption() + "," + child1->caption() );
+ parentWidget()->repaint( false );
+
+ ((PMDockWidget*)parentWidget())->firstName = child0->name();
+ ((PMDockWidget*)parentWidget())->lastName = child1->name();
+ ((PMDockWidget*)parentWidget())->splitterOrientation = orientation;
+
+ QWidget* p = parentWidget()->parentWidget();
+ if ( p != 0L && p->inherits("PMDockSplitter" ) )
+ ((PMDockSplitter*)p)->updateName();
+}
+
+void PMDockSplitter::setOpaqueResize(bool b)
+{
+ mOpaqueResize = b;
+}
+
+bool PMDockSplitter::opaqueResize() const
+{
+ return mOpaqueResize;
+}
+
+void PMDockSplitter::setKeepSize(bool b)
+{
+ mKeepSize = b;
+}
+
+bool PMDockSplitter::keepSize() const
+{
+ return mKeepSize;
+}
+
+void PMDockSplitter::setHighResolution(bool b)
+{
+ if (mHighResolution) {
+ if (!b) xpos = xpos/100;
+ } else {
+ if (b) xpos = xpos*100;
+ }
+ mHighResolution = b;
+}
+
+bool PMDockSplitter::highResolution() const
+{
+ return mHighResolution;
+}
+
+
+/*************************************************************************/
+PMDockButton_Private::PMDockButton_Private( QWidget *parent, const char * name )
+:QPushButton( parent, name )
+{
+ moveMouse = false;
+ setFocusPolicy( NoFocus );
+}
+
+PMDockButton_Private::~PMDockButton_Private()
+{
+}
+
+void PMDockButton_Private::drawButton( QPainter* p )
+{
+ p->fillRect( 0,0, width(), height(), QBrush(colorGroup().brush(QColorGroup::Background)) );
+ p->drawPixmap( (width() - pixmap()->width()) / 2, (height() - pixmap()->height()) / 2, *pixmap() );
+ if ( moveMouse && !isDown() ){
+ p->setPen( white );
+ p->moveTo( 0, height() - 1 );
+ p->lineTo( 0, 0 );
+ p->lineTo( width() - 1, 0 );
+
+ p->setPen( colorGroup().dark() );
+ p->lineTo( width() - 1, height() - 1 );
+ p->lineTo( 0, height() - 1 );
+ }
+ if ( isOn() || isDown() ){
+ p->setPen( colorGroup().dark() );
+ p->moveTo( 0, height() - 1 );
+ p->lineTo( 0, 0 );
+ p->lineTo( width() - 1, 0 );
+
+ p->setPen( white );
+ p->lineTo( width() - 1, height() - 1 );
+ p->lineTo( 0, height() - 1 );
+ }
+}
+
+void PMDockButton_Private::enterEvent( QEvent * )
+{
+ moveMouse = true;
+ repaint();
+}
+
+void PMDockButton_Private::leaveEvent( QEvent * )
+{
+ moveMouse = false;
+ repaint();
+}
+
+/*************************************************************************/
+PMDockWidgetPrivate::PMDockWidgetPrivate()
+ : QObject()
+ ,index(-1)
+ ,splitPosInPercent(50)
+ ,pendingFocusInEvent(false)
+ ,blockHasUndockedSignal(false)
+{
+#ifndef NO_KDE2
+ windowType = NET::Normal;
+#endif
+
+ _parent = 0L;
+ transient = false;
+}
+
+PMDockWidgetPrivate::~PMDockWidgetPrivate()
+{
+}
+
+void PMDockWidgetPrivate::slotFocusEmbeddedWidget(QWidget* w)
+{
+ if (w) {
+ QWidget* embeddedWdg = ((PMDockWidget*)w)->getWidget();
+ if (embeddedWdg && ((embeddedWdg->focusPolicy() == QWidget::ClickFocus) || (embeddedWdg->focusPolicy() == QWidget::StrongFocus))) {
+ embeddedWdg->setFocus();
+ }
+ }
+}
+
+#ifndef NO_INCLUDE_MOCFILES // for Qt-only projects, because tmake doesn't take this name
+#include "pmdockwidget_private.moc"
+#endif
diff --git a/kpovmodeler/pmdockwidget_private.h b/kpovmodeler/pmdockwidget_private.h
new file mode 100644
index 00000000..353eb390
--- /dev/null
+++ b/kpovmodeler/pmdockwidget_private.h
@@ -0,0 +1,142 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2000 Max Judin <novaprint@mtu-net.ru>
+ Modified 2002 Andreas Zehender <zehender@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/*
+ IMPORTANT Note: This file compiles also in Qt-only mode by using the NO_KDE2 precompiler definition
+*/
+
+#ifndef KDOCKWIDGET_PRIVATE_H
+#define KDOCKWIDGET_PRIVATE_H
+
+#include <qwidget.h>
+#include <qpushbutton.h>
+
+#ifndef NO_KDE2
+#include <netwm_def.h>
+#endif
+
+class QFrame;
+
+/**
+ * Like QSplitter but specially designed for dockwidgets stuff.
+ * @internal
+ *
+ * @author Max Judin.
+*/
+class PMDockSplitter : public QWidget
+{
+ Q_OBJECT
+public:
+ PMDockSplitter(QWidget *parent= 0, const char *name= 0, Orientation orient= Vertical, int pos= 50, bool highResolution=false);
+ virtual ~PMDockSplitter(){};
+
+ void activate(QWidget *c0, QWidget *c1 = 0L);
+ void deactivate();
+
+ int separatorPos() const;
+ void setSeparatorPos(int pos, bool do_resize = true);
+
+ virtual bool eventFilter(QObject *, QEvent *);
+ virtual bool event( QEvent * );
+
+ QWidget* getFirst() const { return child0; }
+ QWidget* getLast() const { return child1; }
+ QWidget* getAnother( QWidget* ) const;
+ void updateName();
+
+ void setOpaqueResize(bool b=true);
+ bool opaqueResize() const;
+
+ void setKeepSize(bool b=true);
+ bool keepSize() const;
+
+ void setHighResolution(bool b=true);
+ bool highResolution() const;
+
+ // MODIFICATION (Zehender)
+ Orientation splitterOrientation( ) const { return orientation; }
+
+protected:
+ int checkValue( int ) const;
+ virtual void resizeEvent(QResizeEvent *);
+
+private:
+ void setupMinMaxSize();
+
+ QWidget *child0, *child1;
+ Orientation orientation;
+ bool initialised;
+ QFrame* divider;
+ int xpos;
+ bool mOpaqueResize, mKeepSize, mHighResolution;
+};
+
+/**
+ * A mini-button usually placed in the dockpanel.
+ * @internal
+ *
+ * @author Max Judin.
+*/
+class PMDockButton_Private : public QPushButton
+{
+ Q_OBJECT
+public:
+ PMDockButton_Private( QWidget *parent=0, const char *name=0 );
+ ~PMDockButton_Private();
+
+protected:
+ virtual void drawButton( QPainter * );
+ virtual void enterEvent( QEvent * );
+ virtual void leaveEvent( QEvent * );
+
+private:
+ bool moveMouse;
+};
+
+/**
+ * additional PMDockWidget stuff (private)
+*/
+class PMDockWidgetPrivate : public QObject
+{
+ Q_OBJECT
+public:
+ PMDockWidgetPrivate();
+ ~PMDockWidgetPrivate();
+
+public slots:
+ /**
+ * Especially used for Tab page docking. Switching the pages requires additional setFocus() for the embedded widget.
+ */
+ void slotFocusEmbeddedWidget(QWidget* w = 0L);
+
+public:
+ int index;
+ int splitPosInPercent;
+ bool pendingFocusInEvent;
+ bool blockHasUndockedSignal;
+
+#ifndef NO_KDE2
+ NET::WindowType windowType;
+#endif
+
+ QWidget *_parent;
+ bool transient;
+};
+
+#endif
diff --git a/kpovmodeler/pmdocumentationmap.cpp b/kpovmodeler/pmdocumentationmap.cpp
new file mode 100644
index 00000000..9c898c4c
--- /dev/null
+++ b/kpovmodeler/pmdocumentationmap.cpp
@@ -0,0 +1,193 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmdocumentationmap.h"
+
+#include <kconfig.h>
+#include <kstandarddirs.h>
+
+#include <qfile.h>
+#include <qdom.h>
+
+#include "pmdebug.h"
+
+PMDocumentationMap* PMDocumentationMap::s_pInstance = 0;
+KStaticDeleter<PMDocumentationMap> PMDocumentationMap::s_staticDeleter;
+
+QString PMDocumentationVersion::documentation( const QString& className ) const
+{
+ if( m_map.contains( className ) )
+ return m_map[className];
+ return m_index;
+}
+
+void PMDocumentationVersion::loadData( QDomElement& e )
+{
+ QString className;
+ QString target;
+
+ m_version = e.attribute( "number", "3.1" );
+ m_index = e.attribute( "index", "index.htm" );
+
+ QDomNode m = e.firstChild( );
+ while( !m.isNull( ) )
+ {
+ if( m.isElement( ) )
+ {
+ QDomElement me = m.toElement( );
+ className = me.attribute( "className", "" );
+ target = me.attribute( "target", "" );
+ if( !className.isEmpty( ) && !target.isEmpty( ) )
+ m_map.insert( className, target );
+ }
+ m = m.nextSibling( );
+ }
+}
+
+PMDocumentationMap::PMDocumentationMap( )
+{
+ m_pCurrentVersion = 0;
+ m_mapLoaded = false;
+}
+
+PMDocumentationMap::~PMDocumentationMap( )
+{
+ m_maps.setAutoDelete( true );
+ m_maps.clear( );
+}
+
+void PMDocumentationMap::saveConfig( KConfig* cfg )
+{
+ cfg->setGroup( "Povray" );
+ cfg->writePathEntry( "DocumentationPath", m_documentationPath );
+ cfg->writeEntry( "DocumentationVersion", m_currentVersion );
+}
+
+void PMDocumentationMap::restoreConfig( KConfig* cfg )
+{
+ cfg->setGroup( "Povray" );
+ m_documentationPath = cfg->readPathEntry( "DocumentationPath" );
+ m_currentVersion = cfg->readEntry( "DocumentationVersion", "3.1" );
+}
+
+void PMDocumentationMap::setDocumentationVersion( const QString& v )
+{
+ m_currentVersion = v;
+ if( m_mapLoaded )
+ findVersion( );
+}
+
+QValueList<QString> PMDocumentationMap::availableVersions( )
+{
+ if( !m_mapLoaded )
+ loadMap( );
+
+ QValueList<QString> result;
+ QPtrListIterator<PMDocumentationVersion> it( m_maps );
+
+ for( ; it.current( ); ++it )
+ result.push_back( it.current( )->version( ) );
+
+ return result;
+}
+
+QString PMDocumentationMap::documentation( const QString& objectName )
+{
+ if( !m_mapLoaded )
+ loadMap( );
+
+ QString url;
+
+ if( !m_documentationPath.isEmpty( ) )
+ if( !m_documentationPath.endsWith( QString( "/" ) ) )
+ m_documentationPath += "/";
+
+ if( !m_documentationPath.isEmpty( ) && m_pCurrentVersion )
+ url = m_documentationPath
+ + m_pCurrentVersion->documentation( objectName );
+
+ return url;
+}
+
+void PMDocumentationMap::loadMap( )
+{
+ if( !m_mapLoaded )
+ {
+ m_mapLoaded = true;
+
+ QString fileName = locate( "data", "kpovmodeler/povraydocmap.xml" );
+ if( fileName.isEmpty( ) )
+ {
+ kdError( PMArea ) << "Povray documentation map not found" << endl;
+ return;
+ }
+
+ QFile file( fileName );
+ if( !file.open( IO_ReadOnly ) )
+ {
+ kdError( PMArea ) << "Could not open the povray documentation map file"
+ << endl;
+ return;
+ }
+
+ QDomDocument doc( "DOCMAP" );
+ doc.setContent( &file );
+
+ QDomElement e = doc.documentElement( );
+ QDomNode c = e.firstChild( );
+
+ QString str;
+
+ while( !c.isNull( ) )
+ {
+ if( c.isElement( ) )
+ {
+ QDomElement ce = c.toElement( );
+ PMDocumentationVersion* v = new PMDocumentationVersion( );
+ m_maps.append( v );
+ v->loadData( ce );
+ }
+ c = c.nextSibling( );
+ }
+
+ findVersion( );
+ }
+}
+
+void PMDocumentationMap::findVersion( )
+{
+ QPtrListIterator< PMDocumentationVersion > it( m_maps );
+ bool found = false;
+
+ m_pCurrentVersion = 0;
+
+ for( ; it.current( ) && !found; ++it )
+ {
+ if( it.current( )->version( ) == m_currentVersion )
+ {
+ found = true;
+ m_pCurrentVersion = it.current( );
+ }
+ }
+}
+
+PMDocumentationMap* PMDocumentationMap::theMap( )
+{
+ if( !s_pInstance )
+ s_staticDeleter.setObject( s_pInstance, new PMDocumentationMap( ) );
+ return s_pInstance;
+}
diff --git a/kpovmodeler/pmdocumentationmap.h b/kpovmodeler/pmdocumentationmap.h
new file mode 100644
index 00000000..3027095c
--- /dev/null
+++ b/kpovmodeler/pmdocumentationmap.h
@@ -0,0 +1,138 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMDOCUMENTATIONMAP_H
+#define PMDOCUMENTATIONMAP_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qstring.h>
+#include <qmap.h>
+#include <qptrlist.h>
+#include <qvaluelist.h>
+#include <kstaticdeleter.h>
+
+class KConfig;
+class QDomElement;
+
+/**
+ * Class used internally by @ref PMDocumentationMap
+ */
+class PMDocumentationVersion
+{
+public:
+ /**
+ * Constructor
+ */
+ PMDocumentationVersion( ) { }
+ /**
+ * Destructor
+ */
+ ~PMDocumentationVersion( ) { }
+
+ QString version( ) const { return m_version; }
+ void setVersion( const QString& str ) { m_version = str; }
+ QString index( ) const { return m_index; }
+ void setIndex( const QString& str ) { m_index = str; }
+
+ QString documentation( const QString& className ) const;
+
+ void loadData( QDomElement& e );
+
+private:
+ QString m_version;
+ QString m_index;
+ QMap< QString, QString > m_map;
+};
+
+/**
+ * Class that maps the class name to the corresponding povray
+ * user documentation file
+ */
+class PMDocumentationMap
+{
+public:
+ /**
+ * Destructor
+ */
+ ~PMDocumentationMap( );
+ /**
+ * Returns the map instance (singleton)
+ */
+ static PMDocumentationMap* theMap( );
+
+ /**
+ * Sets the path to the povray user documentation
+ */
+ void setPovrayDocumentationPath( const QString& s )
+ {
+ m_documentationPath = s;
+ }
+ /**
+ * Returns the path to the povray user documentation
+ */
+ QString povrayDocumentationPath( )
+ {
+ return m_documentationPath;
+ }
+
+ /**
+ * Sets the povray documentation version
+ */
+ void setDocumentationVersion( const QString& str );
+ /**
+ * Returns the povray documentation version
+ */
+ QString documentationVersion( ) const { return m_currentVersion; }
+
+ /**
+ * Returns the list of available documentation versions
+ */
+ QValueList<QString> availableVersions( );
+
+ /**
+ * Returns the povray documentation file for the
+ * given object type
+ */
+ QString documentation( const QString& objectName );
+
+ void saveConfig( KConfig* cfg );
+ void restoreConfig( KConfig* cfg );
+
+private:
+
+ /**
+ * Constructor
+ */
+ PMDocumentationMap( );
+ void loadMap( );
+ void findVersion( );
+
+ QString m_documentationPath;
+ bool m_mapLoaded;
+ QPtrList< PMDocumentationVersion > m_maps;
+ PMDocumentationVersion* m_pCurrentVersion;
+ QString m_currentVersion;
+
+ static PMDocumentationMap* s_pInstance;
+ static KStaticDeleter<PMDocumentationMap> s_staticDeleter;
+};
+
+#endif
diff --git a/kpovmodeler/pmdocumentformat.h b/kpovmodeler/pmdocumentformat.h
new file mode 100644
index 00000000..1551f9e4
--- /dev/null
+++ b/kpovmodeler/pmdocumentformat.h
@@ -0,0 +1,26 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMDOCUMENTFORMAT_H
+#define PMDOCUMENTFORMAT_H
+
+// the current document format number
+// (1.0)
+const int c_majorDocumentFormat = 1;
+const int c_minorDocumentFormat = 0;
+
+#endif
diff --git a/kpovmodeler/pmdragwidget.cpp b/kpovmodeler/pmdragwidget.cpp
new file mode 100644
index 00000000..7b63baf5
--- /dev/null
+++ b/kpovmodeler/pmdragwidget.cpp
@@ -0,0 +1,49 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2004 by Luis Carvalho
+ email : lpassos@oninetspeed.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#include "pmdragwidget.h"
+
+PMDragWidget::PMDragWidget( QWidget* parent, const char* name, WFlags f )
+ : QWidget( parent, name, f )
+{
+ dragging = false;
+}
+
+void PMDragWidget::mousePressEvent( QMouseEvent* )
+{
+ dragging = true;
+}
+
+void PMDragWidget::mouseReleaseEvent( QMouseEvent* )
+{
+ dragging = false;
+}
+
+void PMDragWidget::mouseMoveEvent( QMouseEvent* )
+{
+ if( dragging )
+ {
+ startDrag( );
+ dragging = false;
+ }
+}
+
+void PMDragWidget::startDrag( )
+{
+}
+
+#include "pmdragwidget.moc"
diff --git a/kpovmodeler/pmdragwidget.h b/kpovmodeler/pmdragwidget.h
new file mode 100644
index 00000000..30b15045
--- /dev/null
+++ b/kpovmodeler/pmdragwidget.h
@@ -0,0 +1,51 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2004 by Luis Carvalho
+ email : lpassos@oninetspeed.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#ifndef PMDRAGWIDGET_H
+#define PMDRAGWIDGET_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qwidget.h>
+#include <qstring.h>
+
+/**
+ * This class implements a widget that exposes a signal for drag
+ * and drop.
+ *
+ * It will emit startDrag when it's time to start a drag.
+ */
+class PMDragWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ PMDragWidget( QWidget* parent = 0, const char* name = 0, WFlags f = 0 );
+
+ virtual void startDrag( );
+
+protected:
+ void mousePressEvent( QMouseEvent* );
+ void mouseReleaseEvent( QMouseEvent* );
+ void mouseMoveEvent( QMouseEvent* );
+
+private:
+ bool dragging;
+};
+
+#endif
diff --git a/kpovmodeler/pmenumproperty.cpp b/kpovmodeler/pmenumproperty.cpp
new file mode 100644
index 00000000..72a03788
--- /dev/null
+++ b/kpovmodeler/pmenumproperty.cpp
@@ -0,0 +1,57 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmenumproperty.h"
+
+PMEnumProperty::PMEnumProperty( const char* name, bool readOnly,
+ bool writeOnly )
+ : PMPropertyBase( name, PMVariant::String, readOnly, writeOnly )
+{
+}
+
+void PMEnumProperty::addEnumValue( const QString& str, int value )
+{
+ m_valueMap[value] = str;
+ m_stringMap[str] = value;
+}
+
+QStringList PMEnumProperty::enumValues( ) const
+{
+ QStringList l;
+ PMEnumStringValueMap::const_iterator it;
+ for( it = m_stringMap.begin( ); it != m_stringMap.end( ); ++it )
+ l.append( it.key( ) );
+ return l;
+}
+
+bool PMEnumProperty::setProtected( PMObject* obj, const PMVariant& v )
+{
+ PMEnumStringValueMap::iterator it = m_stringMap.find( v.stringData( ) );
+ if( it == m_stringMap.end( ) )
+ return false;
+ setEnum( obj, it.data( ) );
+ return true;
+}
+
+PMVariant PMEnumProperty::getProtected( const PMObject* obj )
+{
+ int v = getEnum( obj );
+ PMEnumValueStringMap::const_iterator it = m_valueMap.find( v );
+ if( it == m_valueMap.end( ) )
+ return PMVariant( QString::null );
+ return it.data( );
+}
diff --git a/kpovmodeler/pmenumproperty.h b/kpovmodeler/pmenumproperty.h
new file mode 100644
index 00000000..a8d6085e
--- /dev/null
+++ b/kpovmodeler/pmenumproperty.h
@@ -0,0 +1,110 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMENUMPROPERTY_H
+#define PMENUMPROPERTY_H
+
+#include "pmmetaobject.h"
+#include <qmap.h>
+
+typedef QMap<int, QString> PMEnumValueStringMap;
+typedef QMap<QString, int> PMEnumStringValueMap;
+
+/**
+ * Base class for enum properties
+ */
+class PMEnumProperty : public PMPropertyBase
+{
+public:
+ /**
+ * Default constructor
+ */
+ PMEnumProperty( const char* name, bool readOnly = false,
+ bool writeOnly = false );
+
+ /**
+ * Adds the string to the list of enum values and sets the enum flag
+ * to true
+ */
+ void addEnumValue( const QString& str, int value );
+
+ /**
+ * Returns true if the property is an enum
+ */
+ virtual bool isEnum( ) const { return true; }
+ /**
+ * Returns the list of enum values
+ */
+ virtual QStringList enumValues( ) const;
+
+protected:
+ /**
+ * Do not reimplement this method in a sub class
+ */
+ virtual bool setProtected( PMObject* obj, const PMVariant& v );
+ /**
+ * Do not reimplement this method in a sub class
+ */
+ virtual PMVariant getProtected( const PMObject* obj );
+
+ /**
+ * Reimplement this method in sub classes. You can safetly
+ * cast the integer to the enum type
+ */
+ virtual void setEnum( PMObject* obj, int value ) = 0;
+ /**
+ * Reimplement this method in sub classes.
+ */
+ virtual int getEnum( const PMObject* obj ) = 0;
+
+private:
+ PMEnumValueStringMap m_valueMap;
+ PMEnumStringValueMap m_stringMap;
+};
+
+#define PMDefineEnumPropertyClass( ObjectClass, EnumType, PropertyClass ) \
+class PropertyClass : public PMEnumProperty \
+{ \
+public: \
+ typedef void ( ObjectClass::*SetPtr ) ( EnumType ); \
+ typedef EnumType ( ObjectClass::*GetPtr ) ( void ) const; \
+ \
+ PropertyClass( const char* name, SetPtr setFktn, GetPtr getFktn ) \
+ : PMEnumProperty( name, setFktn == 0, getFktn == 0 ) \
+ { \
+ m_setFunktion = setFktn; \
+ m_getFunktion = getFktn; \
+ } \
+protected: \
+ virtual void setEnum( PMObject* obj, int value ) \
+ { \
+ ObjectClass* o = ( ObjectClass* ) obj; \
+ ( o->*m_setFunktion )( ( EnumType ) value ); \
+ } \
+ virtual int getEnum( const PMObject* obj ) \
+ { \
+ const ObjectClass* o = ( const ObjectClass* ) obj; \
+ return ( o->*m_getFunktion )( ); \
+ } \
+private: \
+ SetPtr m_setFunktion; \
+ GetPtr m_getFunktion; \
+}
+// no semicolon, put a semicolon after the macro!
+
+#endif
diff --git a/kpovmodeler/pmerrordialog.cpp b/kpovmodeler/pmerrordialog.cpp
new file mode 100644
index 00000000..721cd302
--- /dev/null
+++ b/kpovmodeler/pmerrordialog.cpp
@@ -0,0 +1,136 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmerrordialog.h"
+#include "pmerrorflags.h"
+
+#include <klocale.h>
+#include <qlabel.h>
+#include <qtextedit.h>
+
+#include <kconfig.h>
+
+
+QSize PMErrorDialog::s_size = QSize( 150, 200 );
+
+PMErrorDialog::PMErrorDialog( const PMMessageList& messages, int errorFlags,
+ QWidget* parent, const char* name )
+ : KDialogBase( parent, name, true, i18n( "Messages" ),
+ Ok | Cancel, Cancel )
+{
+ QVBox* page = makeVBoxMainWidget( );
+ QLabel* text = new QLabel( QString( "" ), ( QWidget* )page );
+
+
+ m_pTextView = new QTextEdit( ( QWidget* )page );
+ m_pTextView->setReadOnly( true );
+
+ m_messageDict.setAutoDelete( true );
+ m_messages.setAutoDelete( true );
+
+ PMMessageList::ConstIterator it;
+ for( it = messages.begin( ); it != messages.end( ); ++it )
+ m_messages.append( new PMMessage( *it ) );
+
+ QPtrListIterator<PMMessage> pit( m_messages );
+ for( ; pit.current( ); ++pit )
+ {
+ PMObject* obj = pit.current( )->linkedObject( );
+ for( ; obj; obj = obj->parent( ) )
+ {
+ QPtrList<PMMessage>* pList = m_messageDict.find( obj );
+ if( !pList )
+ {
+ pList = new QPtrList<PMMessage>;
+ m_messageDict.insert( obj, pList );
+ }
+ pList->append( pit.current( ) );
+ if( !obj->parent( ) )
+ {
+ if( obj->type( ) != "scene" )
+ {
+ kdError( PMArea ) << "A message contains an object that is not inserted in the scene" << endl;
+ pit.current( )->setLinkedObject( 0 );
+ }
+ }
+ }
+ }
+
+ displayMessages( );
+
+ if( errorFlags & PMEWarning )
+ {
+ if( ( errorFlags & PMEError ) || ( errorFlags & PMEFatal ) )
+ text->setText( i18n( "There were warnings and errors:" ) );
+ else
+ text->setText( i18n( "There were warnings:" ) );
+ }
+ else
+ text->setText( i18n( "There were errors:" ) );
+
+ setButtonOKText( KStdGuiItem::ok().text(),
+ i18n( "Proceed" ),
+ i18n( "When clicking <b>Proceed</b>, the program\n"
+ "will try to proceed with the current action." ) );
+ setButtonCancelText( KStdGuiItem::cancel().text(),
+ i18n( "&Cancel" ),
+ i18n( "When clicking <b>Cancel<b>, the program\n"
+ "will cancel the current action." ) );
+
+ if( errorFlags & PMEFatal )
+ showButtonOK( false );
+ else
+ new QLabel( i18n( "Still try to proceed?" ), ( QWidget* )page );
+
+ resize( s_size );
+}
+
+void PMErrorDialog::displayMessages( )
+{
+ QPtrListIterator<PMMessage> pit( m_messages );
+ QString text;
+
+ text = "<qt>\n";
+
+ for( ; pit.current( ); ++pit )
+ text += "<p>" + pit.current( )->text( ) + "</p>\n";
+
+ text += "</qt>";
+
+ m_pTextView->setText( text );
+}
+
+void PMErrorDialog::saveConfig( KConfig* cfg )
+{
+ cfg->setGroup( "Appearance" );
+ cfg->writeEntry( "ErrorDialogSize", s_size );
+}
+
+void PMErrorDialog::restoreConfig( KConfig* cfg )
+{
+ cfg->setGroup( "Appearance" );
+
+ QSize defaultSize( 150, 200 );
+ s_size = cfg->readSizeEntry( "ErrorDialogSize", &defaultSize );
+}
+
+void PMErrorDialog::resizeEvent( QResizeEvent* ev )
+{
+ s_size = ev->size( );
+}
+#include "pmerrordialog.moc"
diff --git a/kpovmodeler/pmerrordialog.h b/kpovmodeler/pmerrordialog.h
new file mode 100644
index 00000000..972d55ab
--- /dev/null
+++ b/kpovmodeler/pmerrordialog.h
@@ -0,0 +1,73 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMERRORDIALOG_H
+#define PMERRORDIALOG_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kdialogbase.h>
+#include <qvaluelist.h>
+#include <qptrdict.h>
+#include <qptrlist.h>
+
+class KConfig;
+class QTextEdit;
+class PMObject;
+
+#include "pmmessage.h"
+
+/**
+ * Dialog that is shown if some errors or warnings occurred during
+ * parsing or execution of commands.
+ */
+class PMErrorDialog : public KDialogBase
+{
+ Q_OBJECT
+public:
+ /**
+ * Creates a modal PMErrorDialog with parent and name.
+ *
+ * messages is the message list. If the list contains a message of type
+ * FatalError, the 'Proceed" button will not be shown.
+ *
+ * PMErrorDialog::exec( ) returns QDialog::Accepted if the command
+ * should be continued.
+ */
+ PMErrorDialog( const PMMessageList& messages, int errorFlags,
+ QWidget* parent = 0, const char* name = 0 );
+
+ static void saveConfig( KConfig* cfg );
+ static void restoreConfig( KConfig* cfg );
+
+protected:
+ virtual void resizeEvent( QResizeEvent* ev );
+
+private:
+ void displayMessages( );
+
+ static QSize s_size;
+ QTextEdit* m_pTextView;
+ QPtrDict< QPtrList<PMMessage> > m_messageDict;
+ QPtrList<PMMessage> m_messages;
+};
+
+#endif
diff --git a/kpovmodeler/pmerrorflags.h b/kpovmodeler/pmerrorflags.h
new file mode 100644
index 00000000..ce604c9b
--- /dev/null
+++ b/kpovmodeler/pmerrorflags.h
@@ -0,0 +1,31 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMERRORFLAGS_H
+#define PMERRORFLAGS_H
+
+/**
+ * Error flags
+ *
+ * These flags are returnd by @ref PMParser::errorFlags( )
+ * and PMCommand::errorFlags( )
+ */
+
+enum PMErrorFlags { PMENone = 0, PMEWarning = 1, PMEError = 2, PMEFatal = 4 };
+
+#endif
diff --git a/kpovmodeler/pmface.cpp b/kpovmodeler/pmface.cpp
new file mode 100644
index 00000000..654a31b0
--- /dev/null
+++ b/kpovmodeler/pmface.cpp
@@ -0,0 +1,119 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2004 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+#include <new>
+#include "pmface.h"
+
+GLuint PMFace::s_dummy = 0;
+
+PMFace::PMFace( const PMFace& face )
+{
+ m_points = new( std::nothrow ) GLuint[ face.m_size ];
+ for( unsigned i = 0; i < face.m_size; ++i )
+ m_points[ i ] = face.m_points[ i ];
+ m_size = face.m_size;
+ m_normal = face.m_normal;
+}
+
+PMFace::PMFace( const GLuint pt1, const GLuint pt2, const GLuint pt3, const PMVector& normal )
+{
+ m_points = new( std::nothrow ) GLuint[ 3 ];
+ m_points[ 0 ] = pt1;
+ m_points[ 1 ] = pt2;
+ m_points[ 2 ] = pt3;
+ m_size = 3;
+ m_normal = normal;
+}
+
+PMFace::PMFace( const GLuint pt1, const GLuint pt2, const GLuint pt3, const GLuint pt4, const PMVector& normal )
+{
+ m_points = new( std::nothrow ) GLuint[ 4 ];
+ m_points[ 0 ] = pt1;
+ m_points[ 1 ] = pt2;
+ m_points[ 2 ] = pt3;
+ m_points[ 3 ] = pt4;
+ m_size = 4;
+ m_normal = normal;
+}
+
+PMFace& PMFace::operator=( const PMFace& face )
+{
+ delete m_points;
+ m_points = new( std::nothrow ) GLuint[ face.m_size ];
+ for( unsigned i = 0; i < face.m_size; ++i )
+ m_points[ i ] = face.m_points[ i ];
+ m_size = face.m_size;
+ m_normal = face.m_normal;
+ return *this;
+}
+
+bool PMFace::operator==( const PMFace& face ) const
+{
+ if( m_size == face.m_size && m_normal == face.m_normal )
+ {
+ for( unsigned i = 0; i < m_size; ++i )
+ {
+ if( m_points[i] != face.m_points[i] )
+ return false;
+ }
+ return true;
+ }
+ else
+ return false;
+}
+
+bool PMFace::operator!=( const PMFace& face ) const
+{
+ return !( *this == face );
+}
+
+bool PMFace::resize( const unsigned int size )
+{
+ if( size != m_size )
+ {
+ GLuint* temp = new( std::nothrow ) GLuint[ size ];
+ if( temp )
+ {
+ for( unsigned i = 0; i < m_size && i < size; ++i )
+ temp[i] = m_points[i];
+
+ for( unsigned i = m_size; i < size; ++i )
+ temp[i] = 0;
+
+ delete [] m_points;
+ m_points = temp;
+ }
+ else
+ return false;
+ }
+ return true;
+}
+
+GLuint& PMFace::operator[] ( int index )
+{
+ if( ( index >= 0 ) && ( index < ( signed ) m_size ) )
+ return m_points[index];
+ kdError( PMArea ) << "Bad index in PMFace operator []\n";
+ return s_dummy;
+}
+
+const GLuint& PMFace::operator[] ( int index ) const
+{
+ if( ( index >= 0 ) && ( index < ( signed ) m_size ) )
+ return m_points[index];
+ kdError( PMArea ) << "Bad index in PMFace operator []\n";
+ return s_dummy;
+}
diff --git a/kpovmodeler/pmface.h b/kpovmodeler/pmface.h
new file mode 100644
index 00000000..46da64bb
--- /dev/null
+++ b/kpovmodeler/pmface.h
@@ -0,0 +1,130 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2004 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+#ifndef PMFACE_H
+#define PMFACE_H
+
+#include <qptrlist.h>
+#include <qvaluevector.h>
+#include <GL/gl.h>
+#include "pmdebug.h"
+#include "pmvector.h"
+
+/**
+ * face to display with index of points. Points must be in clockwise order.
+ *
+ * Face of a @ref PMViewStructure. Only the indices in a @ref PMPointArray
+ * are stored.
+ *
+ * Optimized for OpenGL
+ */
+class PMFace
+{
+public:
+ /**
+ * Default constructor
+ */
+ PMFace( )
+ {
+ m_points = 0;
+ m_size = 0;
+ }
+ /**
+ * Copy Constructor
+ */
+ PMFace( const PMFace& face );
+ /**
+ * Destructor
+ */
+ ~PMFace( ) { delete m_points; }
+ /**
+ * Creates a face with three points.
+ */
+ PMFace( const GLuint pt1, const GLuint pt2, const GLuint pt3, const PMVector& normal = PMVector() );
+ /**
+ * Creates a face with four points.
+ */
+ PMFace( const GLuint pt1, const GLuint pt2, const GLuint pt3, const GLuint pt4, const PMVector& normal = PMVector() );
+
+ /**
+ * Operator assignment
+ */
+ PMFace& operator=( const PMFace& face );
+ /**
+ * Operator equals
+ */
+ bool operator==( const PMFace& face ) const;
+ /**
+ * Operator unequals
+ */
+ bool operator!=( const PMFace& face ) const;
+
+ /**
+ * Resizes the number of points in the face.
+ * @return True if successful
+ */
+ bool resize( const unsigned int size );
+ /**
+ * @return The number of points in the face.
+ */
+ unsigned int size( ) const { return m_size; }
+
+ /**
+ * Returns a reference to a point in the face
+ */
+ GLuint& operator[] ( int index );
+ /**
+ * Returns a const reference to a point in the face
+ */
+ const GLuint& operator[] ( int index ) const;
+
+ /**
+ * Calculates the normal for the face
+ */
+ void setNormal( const PMVector& normal ) { m_normal = normal; }
+ /**
+ * Returns the normal for the face
+ */
+ PMVector normal( ) const { return m_normal; }
+
+private:
+ /**
+ * The face points (indices!)
+ */
+ GLuint* m_points;
+ /**
+ * The number of points in the face
+ */
+ unsigned int m_size;
+ /**
+ * The normal of the face, calculated automatically
+ */
+ PMVector m_normal;
+ static GLuint s_dummy;
+};
+
+typedef QPtrListIterator<PMFace> PMFaceListIterator;
+
+/**
+ * A list of @ref PMFace objects.
+ *
+ * This class stores all faces of a @ref PMViewStructure. Only the indices
+ * in a @ref PMPointArray are stored.
+ */
+typedef QValueVector<PMFace> PMFaceArray;
+
+#endif
diff --git a/kpovmodeler/pmfactory.cpp b/kpovmodeler/pmfactory.cpp
new file mode 100644
index 00000000..4a3631ae
--- /dev/null
+++ b/kpovmodeler/pmfactory.cpp
@@ -0,0 +1,102 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include <klocale.h>
+#include <kinstance.h>
+#include <kaboutdata.h>
+
+#include "pmfactory.h"
+#include "pmpart.h"
+#include "pmdebug.h"
+#include "version.h"
+
+extern "C"
+{
+ void* init_libkpovmodelerpart( )
+ {
+ return new PMFactory( );
+ }
+}
+
+static const char description[] = I18N_NOOP( "Modeler for POV-Ray Scenes" );
+
+KInstance* PMFactory::s_instance = 0L;
+KAboutData* PMFactory::s_aboutData = 0L;
+
+PMFactory::PMFactory( )
+{
+ kdDebug( ) << "PMFactory::PMFactory( )\n";
+}
+
+PMFactory::~PMFactory( )
+{
+ if( s_instance )
+ delete s_instance;
+ if( s_aboutData )
+ delete s_aboutData;
+
+ s_instance = 0L;
+ s_aboutData = 0L;
+}
+
+KParts::Part* PMFactory::createPartObject( QWidget* parentWidget,
+ const char* widgetName,
+ QObject* parent, const char* name,
+ const char* classname,
+ const QStringList& /*args*/ )
+{
+ kdDebug( ) << "PMFactory: Created new part\n";
+
+ bool readwrite = !( ( strcmp( classname, "Browser/View" ) == 0 )
+ || ( strcmp( classname, "KParts::ReadOnlyPart" ) == 0 ) );
+
+ KParts::ReadWritePart *part = new PMPart( parentWidget, widgetName,
+ parent, name, readwrite );
+
+ return part;
+}
+
+KInstance* PMFactory::instance( )
+{
+ if( !s_instance )
+ s_instance = new KInstance( aboutData( ) );
+ return s_instance;
+}
+
+const KAboutData* PMFactory::aboutData( )
+{
+ if( !s_aboutData )
+ {
+ s_aboutData =
+ new KAboutData( "kpovmodeler", I18N_NOOP( "KPovModeler" ),
+ KPOVMODELER_VERSION, description,
+ KAboutData::License_GPL, "(c) 2001-2006, Andreas Zehender" );
+ s_aboutData->addAuthor( "Andreas Zehender", 0,
+ "zehender@kde.org", "http://www.azweb.de" );
+ s_aboutData->addAuthor( "Luis Passos Carvalho", I18N_NOOP( "Textures" ),
+ "lpassos@mail.telepac.pt" );
+ s_aboutData->addAuthor( "Leon Pennington", I18N_NOOP( "POV-Ray 3.5 objects" ),
+ "leon@leonscape.co.uk" );
+ s_aboutData->addAuthor( "Philippe Van Hecke", I18N_NOOP( "Some graphical objects" ),
+ "lephiloux@tiscalinet.be" );
+ s_aboutData->addAuthor( "Leonardo Skorianez", I18N_NOOP( "Some graphical objects" ),
+ "skorianez@bol.com.br" );
+ }
+ return s_aboutData;
+}
+#include "pmfactory.moc"
diff --git a/kpovmodeler/pmfactory.h b/kpovmodeler/pmfactory.h
new file mode 100644
index 00000000..b44c6bd3
--- /dev/null
+++ b/kpovmodeler/pmfactory.h
@@ -0,0 +1,48 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMFACTORY_H
+#define PMFACTORY_H
+
+#include <kparts/factory.h>
+
+class KAboutData;
+class KInstance;
+
+class PMFactory : public KParts::Factory
+{
+ Q_OBJECT
+public:
+ PMFactory( );
+ virtual ~PMFactory( );
+
+ virtual KParts::Part* createPartObject( QWidget* parentWidget,
+ const char* widgetName,
+ QObject* parent, const char* name,
+ const char* classname,
+ const QStringList& args );
+
+ static KInstance* instance( );
+ static const KAboutData* aboutData( );
+private:
+ static KInstance* s_instance;
+ static KAboutData* s_aboutData;
+};
+
+#endif
diff --git a/kpovmodeler/pmfiledialog.cpp b/kpovmodeler/pmfiledialog.cpp
new file mode 100644
index 00000000..68030f8c
--- /dev/null
+++ b/kpovmodeler/pmfiledialog.cpp
@@ -0,0 +1,104 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmfiledialog.h"
+#include "pmpart.h"
+
+#include <kfilefiltercombo.h>
+
+
+PMFileDialog::PMFileDialog( const QString& startDir, const QString& filter, QWidget* parent, const char* name, bool modal )
+ : KFileDialog( startDir, filter, parent, name, modal )
+{
+
+}
+
+QString PMFileDialog::getImportFileName( QWidget* parent, PMPart* part,
+ PMIOFormat*& format )
+{
+ PMIOManager* manager = part->ioManager( );
+ QString filter;
+ QPtrListIterator<PMIOFormat> it( manager->formats( ) );
+ QPtrList<PMIOFormat> formats;
+
+ for( ; it.current( ); ++it )
+ {
+ if( it.current( )->services( ) & PMIOFormat::Import )
+ {
+ QStringList patterns = it.current( )->importPatterns( );
+ QStringList::Iterator pit;
+ for( pit = patterns.begin( ); pit != patterns.end( ); ++pit )
+ {
+ if( !filter.isEmpty( ) )
+ filter += "\n";
+ filter += *pit;
+ formats.append( it.current( ) );
+ }
+ }
+ }
+
+ PMFileDialog dlg( QString::null, filter, parent, "import file dialog", true );
+ dlg.setOperationMode( Opening );
+ dlg.setMode( KFile::File | KFile::LocalOnly );
+ dlg.setCaption( i18n( "Import" ) );
+ dlg.filterWidget->setEditable( false );
+ dlg.exec( );
+
+ format = formats.at( dlg.filterWidget->currentItem( ) );
+
+ return dlg.selectedFile( );
+}
+
+QString PMFileDialog::getExportFileName( QWidget* parent, PMPart* part,
+ PMIOFormat*& format, QString& selectedFilter )
+{
+ PMIOManager* manager = part->ioManager( );
+ QString filter;
+ QPtrListIterator<PMIOFormat> it( manager->formats( ) );
+ QPtrList<PMIOFormat> formats;
+
+ for( ; it.current( ); ++it )
+ {
+ if( it.current( )->services( ) & PMIOFormat::Export )
+ {
+ QStringList patterns = it.current( )->exportPatterns( );
+ QStringList::Iterator pit;
+ for( pit = patterns.begin( ); pit != patterns.end( ); ++pit )
+ {
+ if( !filter.isEmpty( ) )
+ filter += "\n";
+ filter += *pit;
+ formats.append( it.current( ) );
+ }
+ }
+ }
+
+ PMFileDialog dlg( QString::null, filter, parent, "export file dialog", true );
+ dlg.setOperationMode( Saving );
+ dlg.setMode( KFile::File | KFile::LocalOnly );
+ dlg.setCaption( i18n( "Export" ) );
+ dlg.filterWidget->setEditable( false );
+ dlg.exec( );
+
+ format = formats.at( dlg.filterWidget->currentItem( ) );
+ selectedFilter = dlg.currentFilter( );
+
+ return dlg.selectedFile( );
+}
+
+#include "pmfiledialog.moc"
diff --git a/kpovmodeler/pmfiledialog.h b/kpovmodeler/pmfiledialog.h
new file mode 100644
index 00000000..e98a84ab
--- /dev/null
+++ b/kpovmodeler/pmfiledialog.h
@@ -0,0 +1,60 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMFILEDIALOG_H
+#define PMFILEDIALOG_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmiomanager.h"
+#include <kfiledialog.h>
+
+class PMPart;
+
+/**
+ * File dialog used for the import and export action.
+ *
+ * The filters will be set automatically dependent on the
+ * supported file formats
+ * @see PMIOManager
+ */
+class PMFileDialog : public KFileDialog
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor, use the static methods
+ * @ref getImportFileName or @ref getExportFileName instead
+ */
+ PMFileDialog( const QString& startDir, const QString& filter, QWidget* parent, const char* name, bool modal );
+ /**
+ * Opens a modal file dialog and returns a selected file and the chosen
+ * file format.
+ */
+ static QString getImportFileName( QWidget* parent, PMPart* part, PMIOFormat*& format );
+ /**
+ * Opens a modal file dialog and returns a selected file and the chosen
+ * file format and filter.
+ */
+ static QString getExportFileName( QWidget* parent, PMPart* part,
+ PMIOFormat*& format, QString& filter );
+};
+
+#endif
diff --git a/kpovmodeler/pmfinish.cpp b/kpovmodeler/pmfinish.cpp
new file mode 100644
index 00000000..a98b9a2c
--- /dev/null
+++ b/kpovmodeler/pmfinish.cpp
@@ -0,0 +1,765 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmfinish.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pmfinishedit.h"
+
+#include <klocale.h>
+
+const PMColor ambientColorDefault = PMColor( 0.0, 0.0, 0.0, 0.0, 0.0 );
+const double diffuseDefault = 0.6;
+const double brillianceDefault = 1.0;
+const double crandDefault = 0.0;
+const double phongDefault = 0.0;
+const double phongSizeDefault = 40.0;
+const double metallicDefault = 1.0;
+const double specularDefault = 0.0;
+const double roughnessDefault = 0.05;
+const double iridAmountDefault = 0.0;
+const double iridThicknessDefault = 0.0;
+const double iridTurbulenceDefault = 0.0;
+const PMColor reflectionColorDefault = PMColor( 0.0, 0.0, 0.0, 0.0, 0.0 );
+const double reflectionFalloffDefault = 0.0;
+const double reflectionExponentDefault = 1.0;
+const double reflectionMetallicDefault = 1.0;
+
+PMDefinePropertyClass( PMFinish, PMFinishProperty );
+
+PMMetaObject* PMFinish::s_pMetaObject = 0;
+PMObject* createNewFinish( PMPart* part )
+{
+ return new PMFinish( part );
+}
+
+PMFinish::PMFinish( PMPart* part )
+ : Base( part )
+{
+ m_ambientColor = ambientColorDefault;
+ m_diffuse = diffuseDefault;
+ m_brilliance = brillianceDefault;
+ m_crand = crandDefault;
+ m_conserveEnergy = false;
+ m_phong = phongDefault;
+ m_phongSize = phongSizeDefault;
+ m_metallic = metallicDefault;
+ m_specular = specularDefault;
+ m_roughness = roughnessDefault;
+ m_iridAmount = iridAmountDefault;
+ m_iridThickness = iridThicknessDefault;
+ m_iridTurbulence = iridTurbulenceDefault;
+ m_reflectionColor = reflectionColorDefault;
+ m_reflectionMinColor = reflectionColorDefault;
+ m_reflectionFresnel = false;
+ m_reflectionFalloff = reflectionFalloffDefault;
+ m_reflectionExponent = reflectionExponentDefault;
+ m_reflectionMetallic = reflectionMetallicDefault;
+ m_enableAmbient = false;
+ m_enableDiffuse = false;
+ m_enableBrilliance = false;
+ m_enableCrand = false;
+ m_enablePhong = false;
+ m_enablePhongSize = false;
+ m_enableMetallic = false;
+ m_enableSpecular = false;
+ m_enableRoughness = false;
+ m_enableReflection = false;
+ m_enableReflectionMin = false;
+ m_enableRefFalloff = false;
+ m_enableRefExponent = false;
+ m_enableRefMetallic = false;
+ m_irid = false;
+}
+
+PMFinish::PMFinish( const PMFinish& f )
+ : Base( f )
+{
+ m_ambientColor = f.m_ambientColor;
+ m_diffuse = f.m_diffuse;
+ m_brilliance = f.m_brilliance;
+ m_crand = f.m_crand;
+ m_conserveEnergy = f.m_conserveEnergy;
+ m_phong = f.m_phong;
+ m_phongSize = f.m_phongSize;
+ m_metallic = f.m_metallic;
+ m_specular = f.m_specular;
+ m_roughness = f.m_roughness;
+ m_iridAmount = f.m_iridAmount;
+ m_iridThickness = f.m_iridThickness;
+ m_iridTurbulence = f.m_iridTurbulence;
+ m_reflectionColor = f.m_reflectionColor;
+ m_reflectionMinColor = f.m_reflectionMinColor;
+ m_reflectionFresnel = f.m_reflectionFresnel;
+ m_reflectionFalloff = f.m_reflectionFalloff;
+ m_reflectionExponent = f.m_reflectionExponent;
+ m_reflectionMetallic = f.m_reflectionMetallic;
+ m_enableAmbient = f.m_enableAmbient;
+ m_enableDiffuse = f.m_enableDiffuse;
+ m_enableBrilliance = f.m_enableBrilliance;
+ m_enableCrand = f.m_enableCrand;
+ m_enablePhong = f.m_enablePhong;
+ m_enablePhongSize = f.m_enablePhongSize;
+ m_enableMetallic = f.m_enableMetallic;
+ m_enableSpecular = f.m_enableSpecular;
+ m_enableRoughness = f.m_enableRoughness;
+ m_enableReflection = f.m_enableReflection;
+ m_enableReflectionMin = f.m_enableReflectionMin;
+ m_enableRefFalloff = f.m_enableRefFalloff;
+ m_enableRefExponent = f.m_enableRefExponent;
+ m_enableRefMetallic = f.m_enableRefMetallic;
+ m_irid = f.m_irid;
+}
+
+PMFinish::~PMFinish( )
+{
+}
+
+PMMetaObject* PMFinish::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Finish", Base::metaObject( ),
+ createNewFinish );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "ambientColor", &PMFinish::setAmbientColor, &PMFinish::ambientColor ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "phong", &PMFinish::setPhong, &PMFinish::phong ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "diffuse", &PMFinish::setDiffuse, &PMFinish::diffuse ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "brilliance", &PMFinish::setBrilliance, &PMFinish::brilliance ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "crand", &PMFinish::setCrand, &PMFinish::crand ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "conserveEnergy", &PMFinish::setConserveEnergy, &PMFinish::conserveEnergy ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "specular", &PMFinish::setSpecular, &PMFinish::specular ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "roughness", &PMFinish::setRoughness, &PMFinish::roughness ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "metallic", &PMFinish::setMetallic, &PMFinish::metallic ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "irid", &PMFinish::setIrid, &PMFinish::irid ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "iridAmount", &PMFinish::setIridAmount, &PMFinish::iridAmount ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "iridThickness", &PMFinish::setIridThickness, &PMFinish::iridThickness ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "reflectionColor", &PMFinish::setReflectionColor, &PMFinish::reflectionColor ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "reflectionMinColor", &PMFinish::setReflectionMinColor, &PMFinish::reflectionMinColor ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "reflectionFresnel", &PMFinish::setReflectionFresnel, &PMFinish::reflectionFresnel ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "reflectionFalloff", &PMFinish::setReflectionFalloff, &PMFinish::reflectionFalloff ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "reflectionExponent", &PMFinish::setReflectionExponent, &PMFinish::reflectionExponent ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "reflectionMetallic", &PMFinish::setReflectionMetallic, &PMFinish::reflectionMetallic ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "ambientEnabled", &PMFinish::enableAmbient, &PMFinish::isAmbientEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "phongEnabled", &PMFinish::enablePhong, &PMFinish::isPhongEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "phongSizeEnabled", &PMFinish::enablePhongSize, &PMFinish::isPhongSizeEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "diffuseEnabled", &PMFinish::enableDiffuse, &PMFinish::isDiffuseEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "brillianceEnabled", &PMFinish::enableBrilliance, &PMFinish::isBrillianceEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "crandEnabled", &PMFinish::enableCrand, &PMFinish::isCrandEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "specularEnabled", &PMFinish::enableSpecular, &PMFinish::isSpecularEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "roughnessEnabled", &PMFinish::enableRoughness, &PMFinish::isRoughnessEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "metallicEnabled", &PMFinish::enableMetallic, &PMFinish::isMetallicEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "reflectionEnabled", &PMFinish::enableReflection, &PMFinish::isReflectionEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "reflectionMinEnabled", &PMFinish::enableReflectionMin, &PMFinish::isReflectionMinEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "refFalloffEnabled", &PMFinish::enableRefFalloff, &PMFinish::isRefFalloffEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "refExponentEnabled", &PMFinish::enableRefExponent, &PMFinish::isRefExponentEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMFinishProperty( "refMetallicEnabled", &PMFinish::enableRefMetallic, &PMFinish::isRefMetallicEnabled ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMFinish::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMFinish::description( ) const
+{
+ return i18n( "finish" );
+}
+
+void PMFinish::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ Base::serialize( e, doc );
+ e.setAttribute( "enable_ambient", m_enableAmbient );
+ e.setAttribute( "enable_diffuse", m_enableDiffuse );
+ e.setAttribute( "enable_brilliance", m_enableBrilliance );
+ e.setAttribute( "enable_crand", m_enableCrand );
+ e.setAttribute( "enable_phong", m_enablePhong );
+ e.setAttribute( "enable_phong_size", m_enablePhongSize );
+ e.setAttribute( "enable_metallic", m_enableMetallic );
+ e.setAttribute( "enable_specular", m_enableSpecular );
+ e.setAttribute( "enable_roughness", m_enableRoughness );
+ e.setAttribute( "enable_reflection", m_enableReflection );
+ e.setAttribute( "enable_reflection_min", m_enableReflectionMin );
+ e.setAttribute( "enable_reflection_falloff", m_enableRefFalloff );
+ e.setAttribute( "enable_reflection_exponent", m_enableRefExponent );
+ e.setAttribute( "enable_reflection_metallic", m_enableRefMetallic );
+ e.setAttribute( "ambient", m_ambientColor.serializeXML( ) );
+ e.setAttribute( "diffuse", m_diffuse );
+ e.setAttribute( "brilliance", m_brilliance );
+ e.setAttribute( "crand", m_crand );
+ e.setAttribute( "conserve_energy", m_conserveEnergy );
+ e.setAttribute( "phong", m_phong );
+ e.setAttribute( "phongsize", m_phongSize );
+ e.setAttribute( "metallic", m_metallic );
+ e.setAttribute( "specular", m_specular );
+ e.setAttribute( "roughness", m_roughness );
+ e.setAttribute( "irid", m_irid );
+ e.setAttribute( "irid_amount", m_iridAmount );
+ e.setAttribute( "irid_thickness", m_iridThickness );
+ e.setAttribute( "irid_turbulence", m_iridTurbulence );
+ e.setAttribute( "reflection", m_reflectionColor.serializeXML( ) );
+ e.setAttribute( "reflection_min", m_reflectionMinColor.serializeXML( ) );
+ e.setAttribute( "reflection_fresnel", m_reflectionFresnel );
+ e.setAttribute( "reflection_falloff", m_reflectionFalloff );
+ e.setAttribute( "reflection_exponent", m_reflectionExponent );
+ e.setAttribute( "reflection_metallic", m_reflectionMetallic );
+}
+
+void PMFinish::readAttributes( const PMXMLHelper& h )
+{
+ Base::readAttributes( h );
+ m_enableAmbient = h.boolAttribute( "enable_ambient", false );
+ m_enableDiffuse = h.boolAttribute( "enable_diffuse", false );
+ m_enableBrilliance = h.boolAttribute( "enable_brilliance", false );
+ m_enableCrand = h.boolAttribute( "enable_crand", false );
+ m_enablePhong = h.boolAttribute( "enable_phong", false );
+ m_enablePhongSize = h.boolAttribute( "enable_phong_size", false );
+ m_enableMetallic = h.boolAttribute( "enable_metallic", false );
+ m_enableSpecular = h.boolAttribute( "enable_specular", false );
+ m_enableRoughness = h.boolAttribute( "enable_roughness", false );
+ m_enableReflection = h.boolAttribute( "enable_reflection", false );
+ m_enableReflectionMin = h.boolAttribute( "enable_reflection_min", false );
+ m_enableRefFalloff = h.boolAttribute( "enable_reflection_falloff", false );
+ m_enableRefExponent = h.boolAttribute( "enable_reflection_exponent", false );
+ m_enableRefMetallic = h.boolAttribute( "enable_reflection_metallic", false );
+ m_irid = h.boolAttribute( "irid", false );
+ m_ambientColor = h.colorAttribute( "ambient", ambientColorDefault );
+ m_diffuse = h.doubleAttribute( "diffuse", diffuseDefault );
+ m_brilliance = h.doubleAttribute( "brilliance", crandDefault );
+ m_crand = h.doubleAttribute( "crand", crandDefault );
+ m_conserveEnergy = h.boolAttribute( "conserve_energy", false );
+ m_phong = h.doubleAttribute( "phong", phongDefault );
+ m_phongSize = h.doubleAttribute( "phongsize", phongSizeDefault );
+ m_metallic = h.doubleAttribute( "metallic", metallicDefault );
+ m_specular = h.doubleAttribute( "specular", specularDefault );
+ m_roughness = h.doubleAttribute( "roughness", roughnessDefault );
+ m_iridAmount = h.doubleAttribute( "irid_amount", iridAmountDefault );
+ m_iridThickness = h.doubleAttribute( "irid_thickness", iridThicknessDefault );
+ m_iridTurbulence = h.doubleAttribute( "irid_turbulence", iridTurbulenceDefault );
+ m_reflectionColor = h.colorAttribute( "reflection", reflectionColorDefault );
+ m_reflectionMinColor = h.colorAttribute( "reflection_min", reflectionColorDefault );
+ m_reflectionFresnel = h.boolAttribute( "reflection_fresnel", false );
+ m_reflectionFalloff = h.doubleAttribute( "reflection_falloff", reflectionFalloffDefault );
+ m_reflectionExponent = h.doubleAttribute( "reflection_exponent", reflectionExponentDefault );
+ m_reflectionMetallic = h.doubleAttribute( "reflection_metallic", reflectionMetallicDefault );
+}
+
+void PMFinish::setPhong( double c )
+{
+ if( c != m_phong )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMPhongID, m_phong );
+ m_phong = c;
+ }
+}
+
+void PMFinish::setPhongSize( double c )
+{
+ if( c != m_phongSize )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMPhongSizeID, m_phongSize );
+ m_phongSize = c;
+ }
+}
+
+void PMFinish::setMetallic( double c )
+{
+ if( c != m_metallic )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMMetallicID, m_metallic );
+ m_metallic = c;
+ }
+}
+
+void PMFinish::setAmbientColor( const PMColor& c )
+{
+ if( c != m_ambientColor )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAmbientColorID, m_ambientColor );
+ m_ambientColor = c;
+ }
+}
+
+void PMFinish::setDiffuse( double c )
+{
+ if( c != m_diffuse )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMDiffuseID, m_diffuse );
+ m_diffuse = c;
+ }
+}
+
+void PMFinish::setBrilliance( double c )
+{
+ if( c != m_brilliance )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMBrillianceID, m_brilliance );
+ m_brilliance = c;
+ }
+}
+
+void PMFinish::setCrand( double c )
+{
+ if( c != m_crand )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMCrandID, m_crand );
+ m_crand = c;
+ }
+}
+
+void PMFinish::setConserveEnergy( bool c )
+{
+ if( c != m_conserveEnergy )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMConserveEnergyID, m_conserveEnergy );
+ m_conserveEnergy = c;
+ }
+}
+
+void PMFinish::setSpecular( double c )
+{
+ if( c != m_specular )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSpecularID, m_specular );
+ m_specular = c;
+ }
+}
+
+void PMFinish::setRoughness( double c )
+{
+ if( c != m_roughness )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMRoughnessID, m_roughness );
+ m_roughness = c;
+ }
+}
+
+void PMFinish::setIrid( bool c )
+{
+ if( c != m_irid )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMIridID, m_irid );
+ m_irid = c;
+ }
+}
+
+void PMFinish::setReflectionColor( const PMColor& c )
+{
+ if( c != m_reflectionColor )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMReflectionColorID, m_reflectionColor );
+ m_reflectionColor = c;
+ }
+}
+
+void PMFinish::setReflectionMinColor( const PMColor& c )
+{
+ if( c != m_reflectionMinColor )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMReflectionMinColorID, m_reflectionMinColor );
+ m_reflectionMinColor = c;
+ }
+}
+
+void PMFinish::setReflectionFresnel( bool c )
+{
+ if( c != m_reflectionFresnel )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMReflectionFresnelID, m_reflectionFresnel );
+ m_reflectionFresnel = c;
+ }
+}
+
+void PMFinish::setReflectionFalloff( double c )
+{
+ if( c != m_reflectionFalloff )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMReflectionFalloffID, m_reflectionFalloff );
+ m_reflectionFalloff = c;
+ }
+}
+
+void PMFinish::setReflectionExponent( double c )
+{
+ if( c != m_reflectionExponent )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMReflectionExponentID, m_reflectionExponent );
+ m_reflectionExponent = c;
+ }
+}
+
+void PMFinish::setReflectionMetallic( double c )
+{
+ if( c != m_reflectionMetallic )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMReflectionMetallicID, m_reflectionMetallic );
+ m_reflectionMetallic = c;
+ }
+}
+
+void PMFinish::enableAmbient( bool c )
+{
+ if( c != m_enableAmbient )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableAmbientID, m_enableAmbient );
+ m_enableAmbient = c;
+ }
+}
+
+void PMFinish::enableDiffuse( bool c )
+{
+ if( c != m_enableDiffuse )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableDiffuseID, m_enableDiffuse );
+ m_enableDiffuse = c;
+ }
+}
+
+void PMFinish::enablePhong( bool c )
+{
+ if( c != m_enablePhong )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnablePhongID, m_enablePhong );
+ m_enablePhong = c;
+ }
+}
+
+void PMFinish::enablePhongSize( bool c )
+{
+ if( c != m_enablePhongSize )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnablePhongSizeID, m_enablePhongSize );
+ m_enablePhongSize = c;
+ }
+}
+
+void PMFinish::enableBrilliance( bool c )
+{
+ if( c != m_enableBrilliance )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableBrillianceID, m_enableBrilliance );
+ m_enableBrilliance = c;
+ }
+}
+
+void PMFinish::enableCrand( bool c )
+{
+ if( c != m_enableCrand )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableCrandID, m_enableCrand );
+ m_enableCrand = c;
+ }
+}
+
+void PMFinish::enableSpecular( bool c )
+{
+ if( c != m_enableSpecular )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableSpecularID, m_enableSpecular );
+ m_enableSpecular = c;
+ }
+}
+
+void PMFinish::enableRoughness( bool c )
+{
+ if( c != m_enableRoughness )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableRoughnessID, m_enableRoughness );
+ m_enableRoughness = c;
+ }
+}
+
+void PMFinish::enableMetallic( bool c )
+{
+ if( c != m_enableMetallic )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableMetallicID, m_enableMetallic );
+ m_enableMetallic = c;
+ }
+}
+
+void PMFinish::enableReflection( bool c )
+{
+ if( c != m_enableReflection )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableReflectionID, m_enableReflection );
+ m_enableReflection = c;
+ }
+}
+
+void PMFinish::enableReflectionMin( bool c )
+{
+ if( c != m_enableReflectionMin )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableReflectionMinID, m_enableReflectionMin );
+ m_enableReflectionMin = c;
+ }
+}
+
+void PMFinish::enableRefFalloff( bool c )
+{
+ if( c != m_enableRefFalloff )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableRefFalloffID, m_enableRefFalloff );
+ m_enableRefFalloff = c;
+ }
+}
+
+void PMFinish::enableRefExponent( bool c )
+{
+ if( c != m_enableRefExponent )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableRefExponentID, m_enableRefExponent );
+ m_enableRefExponent = c;
+ }
+}
+
+void PMFinish::enableRefMetallic( bool c )
+{
+ if( c != m_enableRefMetallic )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableRefMetallicID, m_enableRefMetallic );
+ m_enableRefMetallic = c;
+ }
+}
+
+void PMFinish::setIridAmount( double c )
+{
+ if( c != m_iridAmount )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMIridAmountID, m_iridAmount );
+ m_iridAmount = c;
+ }
+}
+
+void PMFinish::setIridThickness( double c )
+{
+ if( c != m_iridThickness )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMIridThicknessID, m_iridThickness );
+ m_iridThickness = c;
+ }
+}
+
+void PMFinish::setIridTurbulence( double c )
+{
+ if( c != m_iridTurbulence )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMIridTurbulenceID, m_iridTurbulence );
+ m_iridTurbulence = c;
+ }
+}
+
+PMDialogEditBase* PMFinish::editWidget( QWidget* parent ) const
+{
+ return new PMFinishEdit( parent );
+}
+
+void PMFinish::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMAmbientColorID:
+ setAmbientColor( data->colorData( ) );
+ break;
+ case PMDiffuseID:
+ setDiffuse( data->doubleData( ) );
+ break;
+ case PMBrillianceID:
+ setBrilliance( data->doubleData( ) );
+ break;
+ case PMCrandID:
+ setCrand( data->doubleData( ) );
+ break;
+ case PMConserveEnergyID:
+ setConserveEnergy( data->boolData( ) );
+ case PMPhongID:
+ setPhong( data->doubleData( ) );
+ break;
+ case PMPhongSizeID:
+ setPhongSize( data->doubleData( ) );
+ break;
+ case PMMetallicID:
+ setMetallic( data->doubleData( ) );
+ break;
+ case PMSpecularID:
+ setSpecular( data->doubleData( ) );
+ break;
+ case PMRoughnessID:
+ setRoughness( data->doubleData( ) );
+ break;
+ case PMIridID:
+ setIrid( data->boolData( ) );
+ break;
+ case PMIridAmountID:
+ setIridAmount( data->doubleData( ) );
+ break;
+ case PMIridThicknessID:
+ setIridThickness( data->doubleData( ) );
+ break;
+ case PMIridTurbulenceID:
+ setIridTurbulence( data->doubleData( ) );
+ break;
+ case PMReflectionColorID:
+ setReflectionColor( data->colorData( ) );
+ break;
+ case PMReflectionMinColorID:
+ setReflectionMinColor( data->colorData( ) );
+ break;
+ case PMReflectionFresnelID:
+ setReflectionFresnel( data->boolData( ) );
+ break;
+ case PMReflectionFalloffID:
+ setReflectionFalloff( data->doubleData( ) );
+ break;
+ case PMReflectionExponentID:
+ setReflectionExponent( data->doubleData( ) );
+ break;
+ case PMReflectionMetallicID:
+ setReflectionMetallic( data->doubleData( ) );
+ break;
+ case PMEnableAmbientID:
+ enableAmbient( data->boolData( ) );
+ break;
+ case PMEnablePhongID:
+ enablePhong( data->boolData( ) );
+ break;
+ case PMEnablePhongSizeID:
+ enablePhongSize( data->boolData( ) );
+ break;
+ case PMEnableDiffuseID:
+ enableDiffuse( data->boolData( ) );
+ break;
+ case PMEnableBrillianceID:
+ enableBrilliance( data->boolData( ) );
+ break;
+ case PMEnableCrandID:
+ enableCrand( data->boolData( ) );
+ break;
+ case PMEnableSpecularID:
+ enableSpecular( data->boolData( ) );
+ break;
+ case PMEnableRoughnessID:
+ enableRoughness( data->boolData( ) );
+ break;
+ case PMEnableMetallicID:
+ enableMetallic( data->boolData( ) );
+ break;
+ case PMEnableReflectionID:
+ enableReflection( data->boolData( ) );
+ break;
+ case PMEnableReflectionMinID:
+ enableReflectionMin( data->boolData( ) );
+ break;
+ case PMEnableRefFalloffID:
+ enableRefFalloff( data->boolData( ) );
+ break;
+ case PMEnableRefExponentID:
+ enableRefExponent( data->boolData( ) );
+ break;
+ case PMEnableRefMetallicID:
+ enableRefMetallic( data->boolData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMFinish::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmfinish.h b/kpovmodeler/pmfinish.h
new file mode 100644
index 00000000..072a0f7c
--- /dev/null
+++ b/kpovmodeler/pmfinish.h
@@ -0,0 +1,208 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMFINISH_H
+#define PMFINISH_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebase.h"
+#include "pmcolor.h"
+
+/**
+ * Class for povray finishs
+ */
+class PMFinish : public PMTextureBase
+{
+ typedef PMTextureBase Base;
+public:
+ /**
+ * Creates an PMFinish
+ */
+ PMFinish( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMFinish( const PMFinish& f );
+ /**
+ * Deletes the object
+ */
+ virtual ~PMFinish( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMFinish( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMFinishEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmfinish" ); }
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+
+ PMColor ambientColor( ) const { return m_ambientColor; }
+ double phong( ) const { return m_phong; }
+ double phongSize( ) const { return m_phongSize; }
+ double diffuse( ) const { return m_diffuse; }
+ double brilliance( ) const { return m_brilliance; }
+ double crand( ) const { return m_crand; }
+ bool conserveEnergy( ) const { return m_conserveEnergy; }
+ double specular( ) const { return m_specular; }
+ double roughness( ) const { return m_roughness; }
+ double metallic( ) const { return m_metallic; }
+ bool irid( ) const { return m_irid; }
+ double iridAmount( ) const { return m_iridAmount; }
+ double iridThickness( ) const { return m_iridThickness; }
+ double iridTurbulence( ) const { return m_iridTurbulence; }
+ PMColor reflectionColor( ) const { return m_reflectionColor; }
+ PMColor reflectionMinColor( ) const { return m_reflectionMinColor;}
+ bool reflectionFresnel( ) const { return m_reflectionFresnel; }
+ double reflectionFalloff( ) const { return m_reflectionFalloff; }
+ double reflectionExponent( ) const { return m_reflectionExponent; }
+ double reflectionMetallic( ) const { return m_reflectionMetallic; }
+ bool isAmbientEnabled( ) const { return m_enableAmbient; }
+ bool isPhongEnabled( ) const { return m_enablePhong; }
+ bool isPhongSizeEnabled( ) const { return m_enablePhongSize; }
+ bool isDiffuseEnabled( ) const { return m_enableDiffuse; }
+ bool isBrillianceEnabled( ) const { return m_enableBrilliance; }
+ bool isCrandEnabled( ) const { return m_enableCrand; }
+ bool isSpecularEnabled( ) const { return m_enableSpecular; }
+ bool isRoughnessEnabled( ) const { return m_enableRoughness; }
+ bool isMetallicEnabled( ) const { return m_enableMetallic; }
+ bool isReflectionEnabled( ) const { return m_enableReflection; }
+ bool isReflectionMinEnabled( ) const { return m_enableReflectionMin; }
+ bool isRefFalloffEnabled( ) const { return m_enableRefFalloff; }
+ bool isRefExponentEnabled( ) const { return m_enableRefExponent; }
+ bool isRefMetallicEnabled( ) const { return m_enableRefMetallic; }
+
+ //This is here for povrat31serialization (It won't compile otherwise)
+ bool isExponentEnabled( ) const { return m_enableRefExponent; }
+
+ void setAmbientColor( const PMColor& c );
+ void setPhong( double c );
+ void setPhongSize( double c );
+ void setDiffuse( double c );
+ void setBrilliance( double c );
+ void setCrand( double c );
+ void setConserveEnergy( bool c );
+ void setSpecular( double c );
+ void setRoughness( double c );
+ void setMetallic( double c );
+ void setIrid( bool c );
+ void setIridAmount( double c );
+ void setIridThickness( double c );
+ void setIridTurbulence( double c );
+ void setReflectionColor( const PMColor& c );
+ void setReflectionMinColor( const PMColor& c );
+ void setReflectionFresnel( bool c );
+ void setReflectionFalloff( double c );
+ void setReflectionExponent( double c );
+ void setReflectionMetallic( double c );
+ void enableAmbient( bool c );
+ void enablePhong( bool c );
+ void enablePhongSize( bool c );
+ void enableDiffuse( bool c );
+ void enableBrilliance( bool c );
+ void enableCrand( bool c );
+ void enableSpecular( bool c );
+ void enableRoughness( bool c );
+ void enableMetallic( bool c );
+ void enableReflection( bool c );
+ void enableReflectionMin( bool c );
+ void enableRefFalloff( bool c );
+ void enableRefExponent( bool c );
+ void enableRefMetallic( bool c );
+
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMFinishMementoID { PMAmbientColorID, PMPhongID, PMPhongSizeID,
+ PMMetallicID, PMDiffuseID, PMBrillianceID,
+ PMCrandID, PMConserveEnergyID, PMSpecularID,
+ PMRoughnessID,
+ PMIridID, PMIridAmountID, PMIridThicknessID,
+ PMReflectionColorID, PMReflectionMinColorID,
+ PMReflectionFresnelID, PMReflectionFalloffID,
+ PMReflectionExponentID, PMReflectionMetallicID,
+ PMIridTurbulenceID, PMEnableAmbientID,
+ PMEnablePhongID, PMEnablePhongSizeID,
+ PMEnableMetallicID,
+ PMEnableDiffuseID, PMEnableBrillianceID,
+ PMEnableCrandID, PMEnableSpecularID,
+ PMEnableRoughnessID, PMEnableReflectionID,
+ PMEnableReflectionMinID, PMEnableRefFalloffID,
+ PMEnableRefExponentID, PMEnableRefMetallicID };
+
+ PMColor m_ambientColor;
+ double m_phong;
+ double m_phongSize;
+ double m_diffuse;
+ double m_brilliance;
+ double m_crand;
+ bool m_conserveEnergy;
+ double m_specular;
+ double m_roughness;
+ double m_metallic;
+ bool m_irid;
+ double m_iridAmount;
+ double m_iridThickness;
+ double m_iridTurbulence;
+ PMColor m_reflectionColor;
+ PMColor m_reflectionMinColor;
+ bool m_reflectionFresnel;
+ double m_reflectionFalloff;
+ double m_reflectionExponent;
+ double m_reflectionMetallic;
+
+ bool m_enableAmbient;
+ bool m_enableDiffuse;
+ bool m_enableBrilliance;
+ bool m_enableCrand;
+ bool m_enablePhong;
+ bool m_enablePhongSize;
+ bool m_enableMetallic;
+ bool m_enableSpecular;
+ bool m_enableRoughness;
+ bool m_enableReflection;
+ bool m_enableReflectionMin;
+ bool m_enableRefFalloff;
+ bool m_enableRefExponent;
+ bool m_enableRefMetallic;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmfinishedit.cpp b/kpovmodeler/pmfinishedit.cpp
new file mode 100644
index 00000000..809cbd66
--- /dev/null
+++ b/kpovmodeler/pmfinishedit.cpp
@@ -0,0 +1,474 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmfinishedit.h"
+#include "pmfinish.h"
+#include "pmlineedits.h"
+#include "pmcoloredit.h"
+
+#include <qwidget.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <klocale.h>
+#include <kdialog.h>
+
+
+PMFinishEdit::PMFinishEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMFinishEdit::createTopWidgets( )
+{
+ QHBoxLayout* hl;
+
+ Base::createTopWidgets( );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ QGridLayout* layout = new QGridLayout( hl, 2, 2 );
+ m_pEnableAmbientEdit = new QCheckBox( i18n( "Ambient color" ), this );
+ m_pAmbientColorLabel = new QLabel( i18n( "Color:" ), this );
+ m_pAmbientColorEdit = new PMColorEdit( true, this );
+ layout->addMultiCellWidget( m_pEnableAmbientEdit, 0, 0, 0, 1 );
+ layout->addWidget( m_pAmbientColorLabel, 1, 0, AlignTop );
+ layout->addWidget( m_pAmbientColorEdit, 1, 1 );
+ hl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ layout = new QGridLayout( hl, 4, 2 );
+ m_pEnableDiffuseEdit = new QCheckBox( i18n( "Diffuse:" ), this );
+ m_pDiffuseEdit = new PMFloatEdit( this );
+ layout->addWidget( m_pEnableDiffuseEdit, 0, 0 );
+ layout->addWidget( m_pDiffuseEdit, 0, 1 );
+ m_pEnableBrillianceEdit = new QCheckBox( i18n( "Brilliance:" ), this );
+ m_pBrillianceEdit = new PMFloatEdit( this );
+ layout->addWidget( m_pEnableBrillianceEdit, 1, 0 );
+ layout->addWidget( m_pBrillianceEdit, 1, 1 );
+ m_pEnableCrandEdit = new QCheckBox( i18n( "Crand:" ), this );
+ m_pCrandEdit = new PMFloatEdit( this );
+ layout->addWidget( m_pEnableCrandEdit, 2, 0 );
+ layout->addWidget( m_pCrandEdit, 2, 1 );
+ m_pConserveEnergyEdit = new QCheckBox(
+ i18n( "Conserve energy for reflection" ), this );
+ layout->addMultiCellWidget( m_pConserveEnergyEdit, 3, 3, 0, 1 );
+ hl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ layout = new QGridLayout( hl, 2, 2 );
+ m_pEnablePhongEdit = new QCheckBox( i18n( "Phong:" ), this );
+ m_pPhongEdit = new PMFloatEdit( this );
+ m_pEnablePhongSizeEdit = new QCheckBox( i18n( "Phong size:" ), this );
+ m_pPhongSizeEdit = new PMFloatEdit( this );
+ layout->addWidget( m_pEnablePhongEdit, 0, 0 );
+ layout->addWidget( m_pPhongEdit, 0, 1 );
+ layout->addWidget( m_pEnablePhongSizeEdit, 1, 0 );
+ layout->addWidget( m_pPhongSizeEdit, 1, 1 );
+ hl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ layout = new QGridLayout( hl, 3, 2 );
+ m_pEnableSpecularEdit = new QCheckBox( i18n( "Specular:" ), this );
+ m_pSpecularEdit = new PMFloatEdit( this );
+ layout->addWidget( m_pEnableSpecularEdit, 0, 0 );
+ layout->addWidget( m_pSpecularEdit, 0, 1 );
+ m_pEnableRoughnessEdit = new QCheckBox( i18n( "Roughness:" ), this );
+ m_pRoughnessEdit = new PMFloatEdit( this );
+ layout->addWidget( m_pEnableRoughnessEdit, 1, 0 );
+ layout->addWidget( m_pRoughnessEdit, 1, 1 );
+ m_pEnableMetallicEdit = new QCheckBox( i18n( "Metallic:" ), this );
+ m_pMetallicEdit = new PMFloatEdit( this );
+ layout->addWidget( m_pEnableMetallicEdit, 2, 0 );
+ layout->addWidget( m_pMetallicEdit, 2, 1 );
+ hl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ layout = new QGridLayout( hl, 6, 2 );
+ m_pIridEdit = new QCheckBox( i18n( "Iridiscence" ), this );
+ layout->addMultiCellWidget( m_pIridEdit, 0, 0, 0, 1 );
+ m_pIridAmountLabel = new QLabel( i18n( "Amount:" ), this );
+ m_pIridAmountEdit = new PMFloatEdit( this );
+ layout->addWidget( m_pIridAmountLabel, 1, 0 );
+ layout->addWidget( m_pIridAmountEdit, 1, 1 );
+ m_pIridThicknessLabel = new QLabel( i18n( "Thickness:" ), this );
+ m_pIridThicknessEdit = new PMFloatEdit( this );
+ layout->addWidget( m_pIridThicknessLabel, 2, 0 );
+ layout->addWidget( m_pIridThicknessEdit, 2, 1 );
+ m_pIridTurbulenceEdit = new PMFloatEdit( this );
+ m_pIridTurbulenceLabel = new QLabel( i18n( "Turbulence:" ), this );
+ layout->addWidget( m_pIridTurbulenceLabel, 3, 0 );
+ layout->addWidget( m_pIridTurbulenceEdit, 3, 1 );
+ m_pEnableReflectionEdit = new QCheckBox( i18n( "Reflection" ), this );
+ layout->addMultiCellWidget( m_pEnableReflectionEdit, 4, 4, 0, 1 );
+ hl->addStretch( 1 );
+
+ m_pReflectionWidget = new QWidget( this );
+ QVBoxLayout* vl = new QVBoxLayout( m_pReflectionWidget, 0, KDialog::spacingHint( ) );
+ QGridLayout* gl = new QGridLayout( vl, 2, 2 );
+ m_pEnableReflectionMinEdit = new QCheckBox( i18n( "Minimum:" ),
+ m_pReflectionWidget );
+ m_pReflectionMinColorEdit = new PMColorEdit( false, m_pReflectionWidget );
+ gl->addWidget( m_pEnableReflectionMinEdit, 0, 0, AlignTop );
+ gl->addWidget( m_pReflectionMinColorEdit, 0, 1 );
+ QLabel* label = new QLabel( i18n( "Maximum:" ), m_pReflectionWidget );
+ m_pReflectionColorEdit = new PMColorEdit( false, m_pReflectionWidget );
+ gl->addWidget( label, 1, 0, AlignTop );
+ gl->addWidget( m_pReflectionColorEdit, 1, 1 );
+
+ gl = new QGridLayout( vl, 4, 2 );
+ m_pReflectionFresnelEdit = new QCheckBox( i18n( "Fresnel reflectivity" ),
+ m_pReflectionWidget );
+ gl->addMultiCellWidget( m_pReflectionFresnelEdit, 0, 0, 0, 1 );
+ m_pEnableRefFalloffEdit = new QCheckBox( i18n( "Falloff:" ),
+ m_pReflectionWidget );
+ m_pReflectionFalloffEdit = new PMFloatEdit( m_pReflectionWidget );
+ gl->addWidget( m_pEnableRefFalloffEdit, 1, 0 );
+ gl->addWidget( m_pReflectionFalloffEdit, 1, 1 );
+ m_pEnableRefExponentEdit = new QCheckBox( i18n( "Exponent:" ),
+ m_pReflectionWidget );
+ m_pReflectionExponentEdit = new PMFloatEdit( m_pReflectionWidget );
+ gl->addWidget( m_pEnableRefExponentEdit, 2, 0 );
+ gl->addWidget( m_pReflectionExponentEdit, 2, 1 );
+ m_pEnableRefMetallicEdit = new QCheckBox( i18n( "Metallic:" ),
+ m_pReflectionWidget );
+ m_pReflectionMetallicEdit = new PMFloatEdit( m_pReflectionWidget );
+ gl->addWidget( m_pEnableRefMetallicEdit, 3, 0 );
+ gl->addWidget( m_pReflectionMetallicEdit, 3, 1 );
+ vl->addStretch( 1 );
+ layout->addMultiCellWidget( m_pReflectionWidget, 5, 5, 0, 1 );
+
+
+ connect( m_pAmbientColorEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pDiffuseEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pBrillianceEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pCrandEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pConserveEnergyEdit, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pPhongEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pPhongSizeEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pMetallicEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pSpecularEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pRoughnessEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pIridAmountEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pIridThicknessEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pIridTurbulenceEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pIridEdit, SIGNAL( clicked( ) ), SLOT( slotIridClicked( ) ) );
+ connect( m_pReflectionColorEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pReflectionMinColorEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pReflectionFresnelEdit, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pReflectionFalloffEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pReflectionExponentEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pReflectionMetallicEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+
+ connect( m_pEnableAmbientEdit, SIGNAL( clicked( ) ), SLOT( slotAmbientClicked( ) ) );
+ connect( m_pEnablePhongEdit, SIGNAL( clicked( ) ), SLOT( slotPhongClicked( ) ) );
+ connect( m_pEnablePhongSizeEdit, SIGNAL( clicked( ) ), SLOT( slotPhongSizeClicked( ) ) );
+ connect( m_pEnableDiffuseEdit, SIGNAL( clicked( ) ), SLOT( slotDiffuseClicked( ) ) );
+ connect( m_pEnableBrillianceEdit, SIGNAL( clicked( ) ), SLOT( slotBrillianceClicked( ) ) );
+ connect( m_pEnableCrandEdit, SIGNAL( clicked( ) ), SLOT( slotCrandClicked( ) ) );
+ connect( m_pEnableSpecularEdit, SIGNAL( clicked( ) ), SLOT( slotSpecularClicked( ) ) );
+ connect( m_pEnableRoughnessEdit, SIGNAL( clicked( ) ), SLOT( slotRoughnessClicked( ) ) );
+ connect( m_pEnableMetallicEdit, SIGNAL( clicked( ) ), SLOT( slotMetallicClicked( ) ) );
+ connect( m_pEnableReflectionEdit, SIGNAL( clicked( ) ), SLOT( slotReflectionClicked( ) ) );
+ connect( m_pEnableReflectionMinEdit, SIGNAL( clicked( ) ), SLOT( slotReflectionMinClicked( ) ) );
+ connect( m_pEnableRefFalloffEdit, SIGNAL( clicked( ) ), SLOT( slotRefFalloffClicked( ) ) );
+ connect( m_pEnableRefExponentEdit, SIGNAL( clicked( ) ), SLOT( slotRefExponentClicked( ) ) );
+ connect( m_pEnableRefMetallicEdit, SIGNAL( clicked( ) ), SLOT( slotRefMetallicClicked( ) ) );
+}
+
+void PMFinishEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Finish" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMFinish* ) o;
+
+ m_pAmbientColorEdit->setColor( m_pDisplayedObject->ambientColor( ) );
+ m_pAmbientColorEdit->setReadOnly( readOnly );
+ m_pDiffuseEdit->setValue( m_pDisplayedObject->diffuse( ) );
+ m_pDiffuseEdit->setReadOnly( readOnly );
+ m_pBrillianceEdit->setValue( m_pDisplayedObject->brilliance( ) );
+ m_pBrillianceEdit->setReadOnly( readOnly );
+ m_pCrandEdit->setValue( m_pDisplayedObject->crand( ) );
+ m_pCrandEdit->setReadOnly( readOnly );
+ m_pConserveEnergyEdit->setChecked( m_pDisplayedObject->conserveEnergy( ) );
+ m_pConserveEnergyEdit->setEnabled( !readOnly );
+ m_pPhongEdit->setValue( m_pDisplayedObject->phong( ) );
+ m_pPhongEdit->setReadOnly( readOnly );
+ m_pPhongSizeEdit->setValue( m_pDisplayedObject->phongSize( ) );
+ m_pPhongSizeEdit->setReadOnly( readOnly );
+ m_pMetallicEdit->setValue( m_pDisplayedObject->metallic( ) );
+ m_pMetallicEdit->setReadOnly( readOnly );
+ m_pSpecularEdit->setValue( m_pDisplayedObject->specular( ) );
+ m_pSpecularEdit->setReadOnly( readOnly );
+ m_pRoughnessEdit->setValue( m_pDisplayedObject->roughness( ) );
+ m_pRoughnessEdit->setReadOnly( readOnly );
+ m_pIridEdit->setChecked( m_pDisplayedObject->irid( ) );
+ m_pIridEdit->setEnabled( !readOnly );
+ m_pIridAmountEdit->setValue( m_pDisplayedObject->iridAmount( ) );
+ m_pIridAmountEdit->setReadOnly( readOnly );
+ m_pIridThicknessEdit->setValue( m_pDisplayedObject->iridThickness( ) );
+ m_pIridThicknessEdit->setReadOnly( readOnly );
+ m_pIridTurbulenceEdit->setValue( m_pDisplayedObject->iridTurbulence( ) );
+ m_pIridTurbulenceEdit->setReadOnly( readOnly );
+ m_pReflectionColorEdit->setColor( m_pDisplayedObject->reflectionColor( ) );
+ m_pReflectionColorEdit->setReadOnly( readOnly );
+ m_pReflectionMinColorEdit->setColor( m_pDisplayedObject->reflectionMinColor( ) );
+ m_pReflectionMinColorEdit->setReadOnly( readOnly );
+ m_pReflectionFresnelEdit->setChecked( m_pDisplayedObject->reflectionFresnel( ) );
+ m_pReflectionFresnelEdit->setEnabled( !readOnly );
+ m_pReflectionFalloffEdit->setValue( m_pDisplayedObject->reflectionFalloff( ) );
+ m_pReflectionFalloffEdit->setReadOnly( readOnly );
+ m_pReflectionExponentEdit->setValue( m_pDisplayedObject->reflectionExponent( ) );
+ m_pReflectionExponentEdit->setReadOnly( readOnly );
+ m_pReflectionMetallicEdit->setValue( m_pDisplayedObject->reflectionMetallic( ) );
+ m_pReflectionMetallicEdit->setReadOnly( readOnly );
+ m_pEnableAmbientEdit->setChecked( m_pDisplayedObject->isAmbientEnabled( ) );
+ m_pEnableAmbientEdit->setEnabled( !readOnly );
+ m_pEnablePhongEdit->setChecked( m_pDisplayedObject->isPhongEnabled( ) );
+ m_pEnablePhongEdit->setEnabled( !readOnly );
+ m_pEnablePhongSizeEdit->setChecked( m_pDisplayedObject->isPhongSizeEnabled( ) );
+ m_pEnablePhongSizeEdit->setEnabled( !readOnly );
+ m_pEnableDiffuseEdit->setChecked( m_pDisplayedObject->isDiffuseEnabled( ) );
+ m_pEnableDiffuseEdit->setEnabled( !readOnly );
+ m_pEnableBrillianceEdit->setChecked( m_pDisplayedObject->isBrillianceEnabled( ) );
+ m_pEnableBrillianceEdit->setEnabled( !readOnly );
+ m_pEnableCrandEdit->setChecked( m_pDisplayedObject->isCrandEnabled( ) );
+ m_pEnableCrandEdit->setEnabled( !readOnly );
+ m_pEnableMetallicEdit->setChecked( m_pDisplayedObject->isMetallicEnabled( ) );
+ m_pEnableMetallicEdit->setEnabled( !readOnly );
+ m_pEnableSpecularEdit->setChecked( m_pDisplayedObject->isSpecularEnabled( ) );
+ m_pEnableSpecularEdit->setEnabled( !readOnly );
+ m_pEnableRoughnessEdit->setChecked( m_pDisplayedObject->isRoughnessEnabled( ) );
+ m_pEnableRoughnessEdit->setEnabled( !readOnly );
+ m_pEnableReflectionEdit->setChecked( m_pDisplayedObject->isReflectionEnabled( ) );
+ m_pEnableReflectionEdit->setEnabled( !readOnly );
+ m_pEnableReflectionMinEdit->setChecked( m_pDisplayedObject->isReflectionMinEnabled( ) );
+ m_pEnableReflectionMinEdit->setEnabled( !readOnly );
+ m_pEnableRefFalloffEdit->setChecked( m_pDisplayedObject->isRefFalloffEnabled( ) );
+ m_pEnableRefFalloffEdit->setEnabled( !readOnly );
+ m_pEnableRefExponentEdit->setChecked( m_pDisplayedObject->isRefExponentEnabled( ) );
+ m_pEnableRefExponentEdit->setEnabled( !readOnly );
+ m_pEnableRefMetallicEdit->setChecked( m_pDisplayedObject->isRefMetallicEnabled( ) );
+ m_pEnableRefMetallicEdit->setEnabled( !readOnly );
+ slotIridClicked( );
+ slotAmbientClicked( );
+ slotPhongClicked( );
+ slotPhongSizeClicked( );
+ slotBrillianceClicked( );
+ slotDiffuseClicked( );
+ slotMetallicClicked( );
+ slotCrandClicked( );
+ slotSpecularClicked( );
+ slotRoughnessClicked( );
+ slotReflectionClicked( );
+ slotReflectionMinClicked( );
+ slotRefFalloffClicked( );
+ slotRefExponentClicked( );
+ slotRefMetallicClicked( );
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMFinishEdit: Can't display object\n";
+}
+
+void PMFinishEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setAmbientColor( m_pAmbientColorEdit->color( ) );
+ m_pDisplayedObject->setDiffuse( m_pDiffuseEdit->value( ) );
+ m_pDisplayedObject->setBrilliance( m_pBrillianceEdit->value( ) );
+ m_pDisplayedObject->setCrand( m_pCrandEdit->value( ) );
+ m_pDisplayedObject->setConserveEnergy( m_pConserveEnergyEdit->isChecked( ) );
+ m_pDisplayedObject->setPhong( m_pPhongEdit->value( ) );
+ m_pDisplayedObject->setPhongSize( m_pPhongSizeEdit->value( ) );
+ m_pDisplayedObject->setMetallic( m_pMetallicEdit->value( ) );
+ m_pDisplayedObject->setSpecular( m_pSpecularEdit->value( ) );
+ m_pDisplayedObject->setRoughness( m_pRoughnessEdit->value( ) );
+ m_pDisplayedObject->setIrid( m_pIridEdit->isChecked( ) );
+ m_pDisplayedObject->setIridAmount( m_pIridAmountEdit->value( ) );
+ m_pDisplayedObject->setIridThickness( m_pIridThicknessEdit->value( ) );
+ m_pDisplayedObject->setIridTurbulence( m_pIridTurbulenceEdit->value( ) );
+ m_pDisplayedObject->setReflectionColor( m_pReflectionColorEdit->color( ) );
+ m_pDisplayedObject->setReflectionMinColor( m_pReflectionMinColorEdit->color( ) );
+ m_pDisplayedObject->setReflectionFresnel( m_pReflectionFresnelEdit->isChecked( ) );
+ m_pDisplayedObject->setReflectionFalloff( m_pReflectionFalloffEdit->value( ) );
+ m_pDisplayedObject->setReflectionExponent( m_pReflectionExponentEdit->value( ) );
+ m_pDisplayedObject->setReflectionMetallic( m_pReflectionMetallicEdit->value( ) );
+ m_pDisplayedObject->enableAmbient( m_pEnableAmbientEdit->isChecked( ) );
+ m_pDisplayedObject->enablePhong( m_pEnablePhongEdit->isChecked( ) );
+ m_pDisplayedObject->enablePhongSize( m_pEnablePhongSizeEdit->isChecked( ) );
+ m_pDisplayedObject->enableBrilliance( m_pEnableBrillianceEdit->isChecked( ) );
+ m_pDisplayedObject->enableDiffuse( m_pEnableDiffuseEdit->isChecked( ) );
+ m_pDisplayedObject->enableCrand( m_pEnableCrandEdit->isChecked( ) );
+ m_pDisplayedObject->enableMetallic( m_pEnableMetallicEdit->isChecked( ) );
+ m_pDisplayedObject->enableRoughness( m_pEnableRoughnessEdit->isChecked( ) );
+ m_pDisplayedObject->enableSpecular( m_pEnableSpecularEdit->isChecked( ) );
+ m_pDisplayedObject->enableReflection( m_pEnableReflectionEdit->isChecked( ) );
+ m_pDisplayedObject->enableReflectionMin( m_pEnableReflectionMinEdit->isChecked( ) );
+ m_pDisplayedObject->enableRefFalloff( m_pEnableRefFalloffEdit->isChecked( ) );
+ m_pDisplayedObject->enableRefExponent( m_pEnableRefExponentEdit->isChecked( ) );
+ m_pDisplayedObject->enableRefMetallic( m_pEnableRefMetallicEdit->isChecked( ) );
+ }
+}
+
+bool PMFinishEdit::isDataValid( )
+{
+ if( !m_pDiffuseEdit->isDataValid( ) ) return false;
+ if( !m_pBrillianceEdit->isDataValid( ) ) return false;
+ if( !m_pCrandEdit->isDataValid( ) ) return false;
+ if( !m_pPhongEdit->isDataValid( ) ) return false;
+ if( !m_pPhongSizeEdit->isDataValid( ) ) return false;
+ if( !m_pMetallicEdit->isDataValid( ) ) return false;
+ if( !m_pSpecularEdit->isDataValid( ) ) return false;
+ if( !m_pRoughnessEdit->isDataValid( ) ) return false;
+ if( !m_pIridAmountEdit->isDataValid( ) ) return false;
+ if( !m_pIridThicknessEdit->isDataValid( ) ) return false;
+ if( !m_pIridTurbulenceEdit->isDataValid( ) ) return false;
+ if( !m_pReflectionFalloffEdit->isDataValid( ) ) return false;
+ if( !m_pReflectionExponentEdit->isDataValid( ) ) return false;
+ if( !m_pReflectionMetallicEdit->isDataValid( ) ) return false;
+ return Base::isDataValid( );
+}
+
+void PMFinishEdit::slotIridClicked( )
+{
+ if( m_pIridEdit->isChecked( ) )
+ {
+ m_pIridAmountLabel->show( );
+ m_pIridAmountEdit->show( );
+ m_pIridThicknessLabel->show( );
+ m_pIridThicknessEdit->show( );
+ m_pIridTurbulenceEdit->show( );
+ m_pIridTurbulenceLabel->show( );
+ }
+ else
+ {
+ m_pIridAmountLabel->hide( );
+ m_pIridAmountEdit->hide( );
+ m_pIridThicknessLabel->hide( );
+ m_pIridThicknessEdit->hide( );
+ m_pIridTurbulenceEdit->hide( );
+ m_pIridTurbulenceLabel->hide( );
+ }
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+void PMFinishEdit::slotAmbientClicked( )
+{
+ if( m_pEnableAmbientEdit->isChecked( ) )
+ {
+ m_pAmbientColorEdit->show( );
+ m_pAmbientColorLabel->show( );
+ }
+ else
+ {
+ m_pAmbientColorEdit->hide( );
+ m_pAmbientColorLabel->hide( );
+ }
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+void PMFinishEdit::slotPhongClicked( )
+{
+ m_pPhongEdit->setEnabled( m_pEnablePhongEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+void PMFinishEdit::slotPhongSizeClicked( )
+{
+ m_pPhongSizeEdit->setEnabled( m_pEnablePhongSizeEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+void PMFinishEdit::slotBrillianceClicked( )
+{
+ m_pBrillianceEdit->setEnabled( m_pEnableBrillianceEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+void PMFinishEdit::slotDiffuseClicked( )
+{
+ m_pDiffuseEdit->setEnabled( m_pEnableDiffuseEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+void PMFinishEdit::slotMetallicClicked( )
+{
+ m_pMetallicEdit->setEnabled( m_pEnableMetallicEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+void PMFinishEdit::slotCrandClicked( )
+{
+ m_pCrandEdit->setEnabled( m_pEnableCrandEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+void PMFinishEdit::slotSpecularClicked( )
+{
+ m_pSpecularEdit->setEnabled( m_pEnableSpecularEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+void PMFinishEdit::slotRoughnessClicked( )
+{
+ m_pRoughnessEdit->setEnabled( m_pEnableRoughnessEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+void PMFinishEdit::slotReflectionClicked( )
+{
+ if( m_pEnableReflectionEdit->isChecked( ) )
+ m_pReflectionWidget->show( );
+ else
+ m_pReflectionWidget->hide( );
+
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+void PMFinishEdit::slotReflectionMinClicked( )
+{
+ m_pReflectionMinColorEdit->setEnabled( m_pEnableReflectionMinEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+void PMFinishEdit::slotRefFalloffClicked( )
+{
+ m_pReflectionFalloffEdit->setEnabled( m_pEnableRefFalloffEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+void PMFinishEdit::slotRefExponentClicked( )
+{
+ m_pReflectionExponentEdit->setEnabled( m_pEnableRefExponentEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+void PMFinishEdit::slotRefMetallicClicked( )
+{
+ m_pReflectionMetallicEdit->setEnabled( m_pEnableRefMetallicEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+#include "pmfinishedit.moc"
diff --git a/kpovmodeler/pmfinishedit.h b/kpovmodeler/pmfinishedit.h
new file mode 100644
index 00000000..313b35dc
--- /dev/null
+++ b/kpovmodeler/pmfinishedit.h
@@ -0,0 +1,122 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMFINISHEDIT_H
+#define PMFINISHEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebaseedit.h"
+
+class PMFinish;
+class PMFloatEdit;
+class PMColorEdit;
+class QCheckBox;
+class QLabel;
+class QWidget;
+
+/**
+ * Dialog edit class for @ref PMFinish
+ */
+class PMFinishEdit : public PMTextureBaseEdit
+{
+ Q_OBJECT
+ typedef PMTextureBaseEdit Base;
+public:
+ /**
+ * Creates a PMFinishEdit with parent and name
+ */
+ PMFinishEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+protected slots:
+ void slotIridClicked( );
+ void slotAmbientClicked( );
+ void slotPhongClicked( );
+ void slotPhongSizeClicked( );
+ void slotBrillianceClicked( );
+ void slotDiffuseClicked( );
+ void slotMetallicClicked( );
+ void slotCrandClicked( );
+ void slotSpecularClicked( );
+ void slotRoughnessClicked( );
+ void slotReflectionClicked( );
+ void slotReflectionMinClicked( );
+ void slotRefFalloffClicked( );
+ void slotRefExponentClicked( );
+ void slotRefMetallicClicked( );
+
+private:
+ PMFinish* m_pDisplayedObject;
+ PMColorEdit* m_pAmbientColorEdit;
+ QLabel* m_pAmbientColorLabel;
+ PMFloatEdit* m_pDiffuseEdit;
+ PMFloatEdit* m_pBrillianceEdit;
+ PMFloatEdit* m_pCrandEdit;
+ QCheckBox* m_pConserveEnergyEdit;
+ PMFloatEdit* m_pPhongEdit;
+ PMFloatEdit* m_pPhongSizeEdit;
+ PMFloatEdit* m_pMetallicEdit;
+ PMFloatEdit* m_pSpecularEdit;
+ PMFloatEdit* m_pRoughnessEdit;
+ QCheckBox* m_pIridEdit;
+ PMFloatEdit* m_pIridAmountEdit;
+ PMFloatEdit* m_pIridThicknessEdit;
+ PMFloatEdit* m_pIridTurbulenceEdit;
+ QLabel* m_pIridAmountLabel;
+ QLabel* m_pIridThicknessLabel;
+ QLabel* m_pIridTurbulenceLabel;
+ QCheckBox* m_pEnableAmbientEdit;
+ QCheckBox* m_pEnablePhongEdit;
+ QCheckBox* m_pEnablePhongSizeEdit;
+ QCheckBox* m_pEnableDiffuseEdit;
+ QCheckBox* m_pEnableBrillianceEdit;
+ QCheckBox* m_pEnableCrandEdit;
+ QCheckBox* m_pEnableSpecularEdit;
+ QCheckBox* m_pEnableRoughnessEdit;
+ QCheckBox* m_pEnableMetallicEdit;
+
+ QWidget* m_pReflectionWidget;
+ PMColorEdit* m_pReflectionColorEdit;
+ PMColorEdit* m_pReflectionMinColorEdit;
+ QCheckBox* m_pReflectionFresnelEdit;
+ PMFloatEdit* m_pReflectionFalloffEdit;
+ PMFloatEdit* m_pReflectionExponentEdit;
+ PMFloatEdit* m_pReflectionMetallicEdit;
+ QCheckBox* m_pEnableReflectionEdit;
+ QCheckBox* m_pEnableReflectionMinEdit;
+ QCheckBox* m_pEnableRefFalloffEdit;
+ QCheckBox* m_pEnableRefExponentEdit;
+ QCheckBox* m_pEnableRefMetallicEdit;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmfog.cpp b/kpovmodeler/pmfog.cpp
new file mode 100644
index 00000000..5f2f1581
--- /dev/null
+++ b/kpovmodeler/pmfog.cpp
@@ -0,0 +1,347 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#include "pmfog.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pmfogedit.h"
+#include "pmvector.h"
+
+#include <klocale.h>
+
+const int fogTypeDefault = 1;
+const double distanceDefault = 0.0;
+const PMColor colorDefault = PMColor( 0.0, 0.0, 0.0 );
+const double lambdaDefault = 2.0;
+const double fogOffsetDefault = 0.0;
+const double fogAltDefault = 0.0;
+const PMVector turbulenceDefault = PMVector( 0.0, 0.0, 0.0 );
+const int octavesDefault = 6;
+const double omegaDefault = 0.5;
+const double turbDepthDefault = 0.5;
+const PMVector upDefault = PMVector( 0.0, 1.0, 0.0 );
+
+PMDefinePropertyClass( PMFog, PMFogProperty );
+
+PMMetaObject* PMFog::s_pMetaObject = 0;
+PMObject* createNewFog( PMPart* part )
+{
+ return new PMFog( part );
+}
+
+PMFog::PMFog( PMPart* part )
+ : Base( part )
+{
+ m_fogType = fogTypeDefault;
+ m_distance = distanceDefault;
+ m_color = colorDefault;
+ m_enableTurbulence = false;
+ m_valueVector = turbulenceDefault;
+ m_octaves = octavesDefault;
+ m_omega = omegaDefault;
+ m_depth = turbDepthDefault;
+ m_fogOffset = fogOffsetDefault;
+ m_fogAlt = fogAltDefault;
+ m_up = upDefault;
+ m_lambda = 0;
+}
+
+PMFog::PMFog( const PMFog& f )
+ : Base( f )
+{
+ m_fogType = f.m_fogType;
+ m_distance = f.m_distance;
+ m_color = f.m_color;
+ m_enableTurbulence = f.m_enableTurbulence;
+ m_valueVector = f.m_valueVector;
+ m_octaves = f.m_octaves;
+ m_omega = f.m_omega;
+ m_depth = f.m_depth;
+ m_fogOffset = f.m_fogOffset;
+ m_fogAlt = f.m_fogAlt;
+ m_up = f.m_up;
+ m_lambda = f.m_lambda;
+}
+
+PMFog::~PMFog( )
+{
+}
+
+PMMetaObject* PMFog::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Fog", Base::metaObject( ),
+ createNewFog );
+ s_pMetaObject->addProperty(
+ new PMFogProperty( "fogType", &PMFog::setFogType, &PMFog::fogType ) );
+ s_pMetaObject->addProperty(
+ new PMFogProperty( "distance", &PMFog::setDistance, &PMFog::distance ) );
+ s_pMetaObject->addProperty(
+ new PMFogProperty( "color", &PMFog::setColor, &PMFog::color ) );
+ s_pMetaObject->addProperty(
+ new PMFogProperty( "turbulenceEnabled", &PMFog::enableTurbulence, &PMFog::isTurbulenceEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMFogProperty( "turbulence", &PMFog::setValueVector, &PMFog::valueVector ) );
+ s_pMetaObject->addProperty(
+ new PMFogProperty( "octaves", &PMFog::setOctaves, &PMFog::octaves ) );
+ s_pMetaObject->addProperty(
+ new PMFogProperty( "omega", &PMFog::setOmega, &PMFog::omega ) );
+ s_pMetaObject->addProperty(
+ new PMFogProperty( "lambda", &PMFog::setLambda, &PMFog::lambda ) );
+ s_pMetaObject->addProperty(
+ new PMFogProperty( "depth", &PMFog::setDepth, &PMFog::depth ) );
+ s_pMetaObject->addProperty(
+ new PMFogProperty( "offset", &PMFog::setFogOffset, &PMFog::fogOffset ) );
+ s_pMetaObject->addProperty(
+ new PMFogProperty( "altitude", &PMFog::setFogAlt, &PMFog::fogAlt ) );
+ s_pMetaObject->addProperty(
+ new PMFogProperty( "up", &PMFog::setUp, &PMFog::up ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMFog::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMFog::description( ) const
+{
+ return i18n( "fog" );
+}
+
+void PMFog::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ Base::serialize( e, doc );
+ e.setAttribute( "fog_type", m_fogType );
+ e.setAttribute( "distance", m_distance );
+ e.setAttribute( "color", m_color.serializeXML( ) );
+ e.setAttribute( "enable_turbulence", m_enableTurbulence );
+ e.setAttribute( "value_vector", m_valueVector.serializeXML( ) );
+ e.setAttribute( "octaves", m_octaves );
+ e.setAttribute( "omega", m_omega );
+ e.setAttribute( "lambda", m_lambda );
+ e.setAttribute( "depth", m_depth );
+ e.setAttribute( "fog_offset", m_fogOffset );
+ e.setAttribute( "fog_alt", m_fogAlt );
+ e.setAttribute( "up", m_up.serializeXML( ) );
+}
+
+void PMFog::readAttributes( const PMXMLHelper& h )
+{
+ Base::readAttributes( h );
+ m_fogType = h.intAttribute( "fog_type", fogTypeDefault );
+ m_distance = h.doubleAttribute( "distance", distanceDefault );
+ m_color = h.colorAttribute( "color", colorDefault );
+ m_enableTurbulence = h.boolAttribute( "enable_turbulence", false );
+ m_valueVector = h.vectorAttribute( "value_vector", turbulenceDefault );
+ m_octaves = h.intAttribute( "octaves", octavesDefault );
+ m_omega = h.doubleAttribute( "omega", omegaDefault );
+ m_lambda = h.doubleAttribute( "lambda", lambdaDefault );
+ m_depth = h.doubleAttribute( "depth", turbDepthDefault );
+ m_fogOffset = h.doubleAttribute( "fog_offset", fogOffsetDefault );
+ m_fogAlt = h.doubleAttribute( "fog_alt", fogAltDefault );
+ m_up = h.vectorAttribute( "up", upDefault );
+}
+
+void PMFog::setFogType( int c )
+{
+ if( c != m_fogType )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFogTypeID, m_fogType );
+ m_fogType = c;
+ }
+}
+
+void PMFog::setDistance( double c )
+{
+ if( c != m_distance )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMDistanceID, m_distance );
+ m_distance = c;
+ }
+}
+
+void PMFog::setColor( const PMColor& c )
+{
+ if( c != m_color )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMColorID, m_color );
+ m_color = c;
+ }
+}
+
+void PMFog::enableTurbulence( bool c )
+{
+ if( c != m_enableTurbulence )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableTurbulenceID, m_enableTurbulence );
+ m_enableTurbulence = c;
+ }
+}
+
+void PMFog::setValueVector( const PMVector& c )
+{
+ if( c != m_valueVector )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMValueVectorID, m_valueVector );
+ m_valueVector = c;
+ }
+}
+
+void PMFog::setOctaves( int c )
+{
+ if( c != m_octaves )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMOctavesID, m_octaves );
+ m_octaves = c;
+ }
+}
+
+void PMFog::setOmega( double c )
+{
+ if( c != m_omega )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMOmegaID, m_omega );
+ m_omega = c;
+ }
+}
+
+void PMFog::setLambda( double c )
+{
+ if( c != m_lambda )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMLambdaID, m_lambda );
+ m_lambda = c;
+ }
+}
+
+void PMFog::setDepth( double c )
+{
+ if( c != m_depth )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMDepthID, m_depth );
+ m_depth = c;
+ }
+}
+
+void PMFog::setFogOffset( double c )
+{
+ if( c != m_fogOffset )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFogOffsetID, m_fogOffset );
+ m_fogOffset = c;
+ }
+}
+
+void PMFog::setFogAlt( double c )
+{
+ if( c != m_fogAlt )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFogAltID, m_fogAlt );
+ m_fogAlt = c;
+ }
+}
+
+void PMFog::setUp( const PMVector& c )
+{
+ if( c != m_up )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMUpID, m_up );
+ m_up = c;
+ }
+}
+
+PMDialogEditBase* PMFog::editWidget( QWidget* parent ) const
+{
+ return new PMFogEdit( parent );
+}
+
+void PMFog::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMFogTypeID:
+ setFogType( data->intData( ) );
+ break;
+ case PMDistanceID:
+ setDistance( data->doubleData( ) );
+ break;
+ case PMColorID:
+ setColor( data->colorData( ) );
+ break;
+ case PMEnableTurbulenceID:
+ enableTurbulence( data->boolData( ) );
+ break;
+ case PMValueVectorID:
+ setValueVector( data->vectorData( ) );
+ break;
+ case PMOctavesID:
+ setOctaves( data->intData( ) );
+ break;
+ case PMOmegaID:
+ setOmega( data->doubleData( ) );
+ break;
+ case PMLambdaID:
+ setLambda( data->doubleData( ) );
+ break;
+ case PMDepthID:
+ setDepth( data->doubleData( ) );
+ break;
+ case PMFogOffsetID:
+ setFogOffset( data->doubleData( ) );
+ break;
+ case PMFogAltID:
+ setFogAlt( data->doubleData( ) );
+ break;
+ case PMUpID:
+ setUp( data->vectorData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMFog::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmfog.h b/kpovmodeler/pmfog.h
new file mode 100644
index 00000000..444fa54a
--- /dev/null
+++ b/kpovmodeler/pmfog.h
@@ -0,0 +1,129 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMFOG_H
+#define PMFOG_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebase.h"
+#include "pmcolor.h"
+#include "pmvector.h"
+
+/**
+ * Class for povray fogs
+ */
+class PMFog : public PMTextureBase
+{
+ typedef PMTextureBase Base;
+public:
+ /**
+ * Creates an PMFog
+ */
+ PMFog( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMFog( const PMFog& f );
+ /**
+ * Deletes the object
+ */
+ virtual ~PMFog( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMFog( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMFogEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmfog" ); }
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+
+ int fogType( ) const { return m_fogType; }
+ double distance( ) const { return m_distance; }
+ PMColor color( ) const { return m_color; }
+ bool isTurbulenceEnabled( ) const { return m_enableTurbulence; }
+ PMVector valueVector( ) const { return m_valueVector; }
+ int octaves( ) const { return m_octaves; }
+ double omega( ) const { return m_omega; }
+ double lambda( ) const { return m_lambda; }
+ double depth( ) const { return m_depth; }
+ double fogOffset( ) const { return m_fogOffset; }
+ double fogAlt( ) const { return m_fogAlt; }
+ PMVector up( ) const { return m_up; }
+
+ void setFogType( int c );
+ void setDistance( double c );
+ void setColor( const PMColor& c );
+ void enableTurbulence( bool c );
+ void setValueVector( const PMVector& v );
+ void setOctaves( int c );
+ void setOmega( double c );
+ void setLambda( double c );
+ void setDepth( double c );
+ void setFogOffset( double c );
+ void setFogAlt( double c );
+ void setUp( const PMVector& v );
+
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMFogMementoID { PMFogTypeID, PMDistanceID, PMColorID,
+ PMEnableTurbulenceID, PMValueVectorID,
+ PMOctavesID, PMOmegaID, PMLambdaID,
+ PMDepthID, PMFogOffsetID, PMFogAltID,
+ PMUpID };
+
+ int m_fogType;
+ double m_distance;
+ PMColor m_color;
+ bool m_enableTurbulence;
+ PMVector m_valueVector;
+ int m_octaves;
+ double m_omega;
+ double m_lambda;
+ double m_depth;
+ double m_fogOffset;
+ double m_fogAlt;
+ PMVector m_up;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmfogedit.cpp b/kpovmodeler/pmfogedit.cpp
new file mode 100644
index 00000000..64cb915e
--- /dev/null
+++ b/kpovmodeler/pmfogedit.cpp
@@ -0,0 +1,240 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmfogedit.h"
+#include "pmfog.h"
+#include "pmlineedits.h"
+#include "pmvectoredit.h"
+#include "pmcoloredit.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdialog.h>
+
+PMFogEdit::PMFogEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMFogEdit::createTopWidgets( )
+{
+ QHBoxLayout* hl;
+ QVBoxLayout* vl;
+ QGridLayout* gl;
+ QLabel* lbl;
+
+ Base::createTopWidgets( );
+
+ lbl = new QLabel( i18n( "Fog type:" ), this );
+ m_pFogTypeEdit = new QComboBox( this );
+ m_pFogTypeEdit->insertItem( i18n( "Constant" ) );
+ m_pFogTypeEdit->insertItem( i18n( "Ground" ) );
+ hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( lbl );
+ hl->addWidget( m_pFogTypeEdit );
+ hl->addStretch( 1 );
+
+ lbl = new QLabel( i18n( "Distance:" ), this );
+ m_pDistance = new PMFloatEdit( this );
+ hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( lbl );
+ hl->addWidget( m_pDistance );
+ hl->addStretch( 1 );
+
+ lbl = new QLabel( i18n( "Color:" ), this );
+ m_pColor = new PMColorEdit( false, this );
+ hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( lbl );
+ hl->addWidget( m_pColor );
+ hl->addStretch( 1 );
+
+ m_pTurbulenceCheck = new QCheckBox( i18n( "Turbulence" ), this );
+ topLayout( )->addWidget( m_pTurbulenceCheck );
+
+ m_pTurbulenceWidget = new QWidget( this );
+ vl = new QVBoxLayout( m_pTurbulenceWidget, 0, KDialog::spacingHint( ) );
+ hl = new QHBoxLayout( vl );
+ lbl = new QLabel( i18n( "Value: " ), m_pTurbulenceWidget );
+ m_pTurbulenceVector = new PMVectorEdit( "x", "y", "z", m_pTurbulenceWidget);
+ hl->addWidget( lbl );
+ hl->addWidget( m_pTurbulenceVector );
+ hl->addStretch( 1 );
+ hl = new QHBoxLayout( vl );
+ gl = new QGridLayout( hl, 4, 2 );
+ lbl = new QLabel( i18n( "Octaves:" ), m_pTurbulenceWidget );
+ m_pOctaves = new PMIntEdit( m_pTurbulenceWidget );
+ gl->addWidget( lbl, 0, 0 );
+ gl->addWidget( m_pOctaves, 0, 1 );
+ lbl = new QLabel( i18n( "Omega:" ), m_pTurbulenceWidget );
+ m_pOmega = new PMFloatEdit( m_pTurbulenceWidget );
+ gl->addWidget( lbl, 1, 0 );
+ gl->addWidget( m_pOmega, 1, 1 );
+ lbl = new QLabel( i18n( "Lambda:" ), m_pTurbulenceWidget );
+ m_pLambda = new PMFloatEdit( m_pTurbulenceWidget );
+ gl->addWidget( lbl, 2, 0 );
+ gl->addWidget( m_pLambda, 2, 1 );
+ lbl = new QLabel( i18n( "Depth:" ), m_pTurbulenceWidget );
+ m_pDepth = new PMFloatEdit( m_pTurbulenceWidget );
+ gl->addWidget( lbl, 3, 0 );
+ gl->addWidget( m_pDepth, 3, 1 );
+ hl->addStretch( 1 );
+ topLayout( )->addWidget( m_pTurbulenceWidget );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ gl = new QGridLayout( hl, 2, 2 );
+ m_pFogOffsetLabel = new QLabel( i18n( "Offset: " ), this );
+ m_pFogOffset = new PMFloatEdit( this );
+ m_pFogAltLabel = new QLabel( i18n( "Altitude: " ), this );
+ m_pFogAlt = new PMFloatEdit( this );
+ gl->addWidget( m_pFogOffsetLabel, 0, 0 );
+ gl->addWidget( m_pFogOffset, 0, 1 );
+ gl->addWidget( m_pFogAltLabel, 1, 0 );
+ gl->addWidget( m_pFogAlt, 1, 1 );
+ hl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ m_pUpLabel = new QLabel( i18n( "Up: " ), this );
+ m_pUp = new PMVectorEdit( "x", "y", "z", this );
+ hl->addWidget( m_pUpLabel );
+ hl->addWidget( m_pUp );
+
+ connect( m_pFogTypeEdit, SIGNAL( activated( int ) ), SLOT( slotFogTypeChanged( int ) ) );
+ connect( m_pDistance, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pColor, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pTurbulenceCheck, SIGNAL( clicked( ) ), SLOT( slotTurbulenceClicked( ) ) );
+ connect( m_pTurbulenceVector, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pOctaves, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pOmega, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pLambda, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pDepth, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pFogOffset, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pFogAlt, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pUp, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMFogEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Fog" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMFog* ) o;
+
+ m_pFogTypeEdit->setCurrentItem( m_pDisplayedObject->fogType( ) - 1 );
+ m_pFogTypeEdit->setEnabled( !readOnly );
+ m_pDistance->setValue( m_pDisplayedObject->distance( ) );
+ m_pDistance->setReadOnly( readOnly );
+ m_pColor->setColor( m_pDisplayedObject->color( ) );
+ m_pColor->setReadOnly( readOnly );
+ m_pTurbulenceCheck->setChecked( m_pDisplayedObject->isTurbulenceEnabled( ) );
+ m_pTurbulenceCheck->setEnabled( !readOnly );
+ m_pTurbulenceVector->setVector( m_pDisplayedObject->valueVector( ) );
+ m_pTurbulenceVector->setReadOnly( readOnly );
+ m_pOctaves->setValue( m_pDisplayedObject->octaves( ) );
+ m_pOctaves->setReadOnly( readOnly );
+ m_pOmega->setValue( m_pDisplayedObject->omega( ) );
+ m_pOmega->setReadOnly( readOnly );
+ m_pLambda->setValue( m_pDisplayedObject->lambda( ) );
+ m_pLambda->setReadOnly( readOnly );
+ m_pDepth->setValue( m_pDisplayedObject->depth( ) );
+ m_pDepth->setReadOnly( readOnly );
+ m_pFogOffset->setValue( m_pDisplayedObject->fogOffset( ) );
+ m_pFogOffset->setReadOnly( readOnly );
+ m_pFogAlt->setValue( m_pDisplayedObject->fogAlt( ) );
+ m_pFogAlt->setReadOnly( readOnly );
+ m_pUp->setVector( m_pDisplayedObject->up( ) );
+ m_pUp->setReadOnly( readOnly );
+
+ slotTurbulenceClicked( );
+ slotFogTypeChanged( m_pFogTypeEdit->currentItem( ) );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMFogEdit: Can't display object\n";
+}
+
+void PMFogEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ m_pDisplayedObject->setFogType( m_pFogTypeEdit->currentItem( ) + 1 );
+ m_pDisplayedObject->setDistance( m_pDistance->value( ) );
+ m_pDisplayedObject->setColor( m_pColor->color( ) );
+ m_pDisplayedObject->enableTurbulence( m_pTurbulenceCheck->isChecked( ) );
+ m_pDisplayedObject->setValueVector( m_pTurbulenceVector->vector( ) );
+ m_pDisplayedObject->setOctaves( m_pOctaves->value( ) );
+ m_pDisplayedObject->setOmega( m_pOmega->value( ) );
+ m_pDisplayedObject->setLambda( m_pLambda->value( ) );
+ m_pDisplayedObject->setDepth( m_pDepth->value( ) );
+ m_pDisplayedObject->setFogOffset( m_pFogOffset->value( ) );
+ m_pDisplayedObject->setFogAlt( m_pFogAlt->value( ) );
+ m_pDisplayedObject->setUp( m_pUp->vector( ) );
+ Base::saveContents( );
+ }
+}
+
+bool PMFogEdit::isDataValid( )
+{
+ return Base::isDataValid( );
+}
+
+void PMFogEdit::slotTurbulenceClicked( )
+{
+ if( m_pTurbulenceCheck->isChecked( ) )
+ m_pTurbulenceWidget->show( );
+ else
+ m_pTurbulenceWidget->hide( );
+
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+void PMFogEdit::slotFogTypeChanged( int val )
+{
+ switch( val )
+ {
+ case 0: // Constant Fog
+ m_pFogOffsetLabel->hide( );
+ m_pFogOffset->hide( );
+ m_pFogAltLabel->hide( );
+ m_pFogAlt->hide( );
+ m_pUpLabel->hide( );
+ m_pUp->hide( );
+ break;
+ case 1: // Ground Fog
+ m_pFogOffsetLabel->show( );
+ m_pFogOffset->show( );
+ m_pFogAltLabel->show( );
+ m_pFogAlt->show( );
+ m_pUpLabel->show( );
+ m_pUp->show( );
+ break;
+ default:
+ break;
+ }
+
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+#include "pmfogedit.moc"
diff --git a/kpovmodeler/pmfogedit.h b/kpovmodeler/pmfogedit.h
new file mode 100644
index 00000000..880b578c
--- /dev/null
+++ b/kpovmodeler/pmfogedit.h
@@ -0,0 +1,95 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMFOGEDIT_H
+#define PMFOGEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebaseedit.h"
+
+class PMFog;
+class PMVectorEdit;
+class PMFloatEdit;
+class PMIntEdit;
+class PMColorEdit;
+class QCheckBox;
+class QComboBox;
+class QWidget;
+class QLabel;
+
+/**
+ * Dialog edit class for @ref PMFog
+ */
+class PMFogEdit : public PMTextureBaseEdit
+{
+ Q_OBJECT
+ typedef PMTextureBaseEdit Base;
+public:
+ /**
+ * Creates a PMFogEdit with parent and name
+ */
+ PMFogEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+protected slots:
+ /**
+ * Slot called whenever turbulence is activated/deactivated
+ */
+ void slotTurbulenceClicked( );
+ /**
+ * Slot called whenever a new fog type is selected
+ */
+ void slotFogTypeChanged( int val );
+
+private:
+ PMFog* m_pDisplayedObject;
+
+ QComboBox* m_pFogTypeEdit;
+ PMFloatEdit* m_pDistance;
+ PMColorEdit* m_pColor;
+ QCheckBox* m_pTurbulenceCheck;
+ QWidget* m_pTurbulenceWidget;
+ PMVectorEdit* m_pTurbulenceVector;
+ PMIntEdit* m_pOctaves;
+ PMFloatEdit* m_pOmega;
+ PMFloatEdit* m_pLambda;
+ PMFloatEdit* m_pDepth;
+ QLabel* m_pFogOffsetLabel;
+ PMFloatEdit* m_pFogOffset;
+ QLabel* m_pFogAltLabel;
+ PMFloatEdit* m_pFogAlt;
+ QLabel* m_pUpLabel;
+ PMVectorEdit* m_pUp;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmformulalabel.cpp b/kpovmodeler/pmformulalabel.cpp
new file mode 100644
index 00000000..ac2e98d3
--- /dev/null
+++ b/kpovmodeler/pmformulalabel.cpp
@@ -0,0 +1,190 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmformulalabel.h"
+#include "pmpolynomexponents.h"
+
+#include <qapplication.h>
+#include <qsimplerichtext.h>
+#include <qpainter.h>
+
+const int c_indent = 3;
+const int c_dotSize = 3;
+
+QString PMFormulaLabel::s_xyz[3] =
+{
+ QString( "x" ), QString( "y" ), QString( "z" )
+};
+
+QString PMFormulaLabel::s_digit[10] =
+{
+ QString( "0" ),
+ QString( "1" ),
+ QString( "2" ),
+ QString( "3" ),
+ QString( "4" ),
+ QString( "5" ),
+ QString( "6" ),
+ QString( "7" ),
+ QString( "8" ),
+ QString( "9" )
+};
+
+QString PMFormulaLabel::s_nullString = QString( "= 0" );
+
+PMFormulaLabel::PMFormulaLabel( const PMPolynomExponents& exp, QWidget* parent, const char* name )
+ : QWidget( parent, name )
+{
+ m_exponents[0] = exp.exponent( 0 );
+ m_exponents[1] = exp.exponent( 1 );
+ m_exponents[2] = exp.exponent( 2 );
+
+ calculateSizeHint( );
+}
+
+PMFormulaLabel::PMFormulaLabel( int x, int y, int z, QWidget* parent, const char* name )
+ : QWidget( parent, name )
+{
+ m_exponents[0] = x;
+ m_exponents[1] = y;
+ m_exponents[2] = z;
+
+ calculateSizeHint( );
+}
+
+PMFormulaLabel::~PMFormulaLabel( )
+{
+}
+
+void PMFormulaLabel::drawContents( QPainter* p )
+{
+ QRect cr = rect( );
+ int i;
+ cr.setLeft( cr.left( ) + c_indent );
+
+ int sum = m_exponents[0] + m_exponents[1] + m_exponents[2];
+ if( sum == 0 )
+ p->drawText( cr, Qt::AlignVCenter | Qt::AlignLeft, s_nullString );
+ else
+ {
+ // draw dot
+ int center = ( cr.top( ) + cr.bottom( ) ) / 2;
+ int rad = c_dotSize / 2;
+ p->setBrush( QBrush( colorGroup( ).text( ) ) );
+ p->drawEllipse( cr.left( ), center - rad, c_dotSize, c_dotSize );
+ cr.setLeft( cr.left( ) + c_dotSize + c_indent );
+
+ QFontMetrics m1( font( ) );
+ QFont f2 = exponentFont( );
+ QFontMetrics m2( f2 );
+ int up = m1.height( ) / 2;
+
+ for( i = 0; i < 3; i++ )
+ {
+
+ if( m_exponents[i] > 0 )
+ {
+ p->drawText( cr, Qt::AlignVCenter | Qt::AlignLeft, s_xyz[i] );
+ cr.setLeft( cr.left( ) + m1.width( s_xyz[i] ) );
+ if( m_exponents[i] > 1 )
+ {
+ cr.setBottom( cr.bottom( ) - up );
+ p->setFont( f2 );
+ p->drawText( cr, Qt::AlignVCenter | Qt::AlignLeft,
+ s_digit[m_exponents[i]] );
+ cr.setLeft( cr.left( ) + m2.width( s_digit[m_exponents[i]] ) + 1 );
+ cr.setBottom( cr.bottom( ) + up );
+ p->setFont( font( ) );
+ }
+ }
+ }
+ }
+}
+
+void PMFormulaLabel::paintEvent( QPaintEvent* ev )
+{
+ QPainter paint( this );
+ if( ev->rect( ).intersects( rect( ) ) )
+ {
+ paint.setClipRegion( ev->region( ).intersect( rect( ) ) );
+ drawContents( &paint );
+ }
+}
+
+void PMFormulaLabel::calculateSizeHint( )
+{
+ int sum = m_exponents[0] + m_exponents[1] + m_exponents[2];
+
+ QFontMetrics m1( font( ) );
+ if( sum == 0 )
+ m_sizeHint.setWidth( m1.width( s_nullString ) );
+ else
+ {
+ QFontMetrics m2( exponentFont( ) );
+ int width = c_indent * 3 + c_dotSize;
+ int i;
+ for( i = 0; i < 3; i++ )
+ {
+ if( m_exponents[i] > 0 )
+ {
+ width += m1.width( s_xyz[i] );
+ if( m_exponents[i] > 1 )
+ width += m2.width( s_digit[m_exponents[i]] ) + 1;
+ }
+ }
+ m_sizeHint.setWidth( width );
+ }
+ m_sizeHint.setHeight( m1.height( ) + 7 );
+}
+
+QSize PMFormulaLabel::sizeHint( ) const
+{
+ return minimumSizeHint( );
+}
+
+QSize PMFormulaLabel::minimumSizeHint( ) const
+{
+ return m_sizeHint;
+}
+
+void PMFormulaLabel::fontChange( const QFont& )
+{
+ calculateSizeHint( );
+}
+
+
+QFont PMFormulaLabel::exponentFont( ) const
+{
+ QFont small = font( );
+ int fs = small.pointSize( );
+ if( fs > 0 )
+ {
+ fs = fs * 2 / 3;
+ if( fs == 0 )
+ fs = 1;
+ small.setPointSize( fs );
+ }
+ else
+ {
+ fs = small.pixelSize( );
+ fs = fs * 2 / 3;
+ if( fs == 0 )
+ fs = 1;
+ small.setPixelSize( fs );
+ }
+ return small;
+}
diff --git a/kpovmodeler/pmformulalabel.h b/kpovmodeler/pmformulalabel.h
new file mode 100644
index 00000000..329ba639
--- /dev/null
+++ b/kpovmodeler/pmformulalabel.h
@@ -0,0 +1,69 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMFORMULALABEL_H
+#define PMFORMULALABEL_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qwidget.h>
+
+class PMPolynomExponents;
+
+/**
+ * QLabel with a rich text to display a polynom for the quadric,
+ * cubic, quartic and polynom objects.
+ */
+class PMFormulaLabel : public QWidget
+{
+public:
+ /**
+ * Displays the exponents of the @ref PMPolynomExponents
+ */
+ PMFormulaLabel( const PMPolynomExponents& exp, QWidget* parent, const char* name = 0 );
+ /**
+ * Displays the given exponents
+ */
+ PMFormulaLabel( int x, int y, int z, QWidget* parent, const char* name = 0 );
+ /**
+ * Destructor
+ */
+ ~PMFormulaLabel( );
+ virtual QSize sizeHint( ) const;
+ virtual QSize minimumSizeHint( ) const;
+
+protected:
+ virtual void drawContents( QPainter* p );
+ virtual void paintEvent( QPaintEvent* e );
+ virtual void fontChange( const QFont& oldFont );
+
+private:
+ QFont exponentFont( ) const;
+ void calculateSizeHint( );
+
+ QSize m_sizeHint;
+ int m_exponents[3];
+
+ static QString s_xyz[3];
+ static QString s_digit[10];
+ static QString s_nullString;
+};
+
+#endif
diff --git a/kpovmodeler/pmglobalphotons.cpp b/kpovmodeler/pmglobalphotons.cpp
new file mode 100644
index 00000000..4a24855f
--- /dev/null
+++ b/kpovmodeler/pmglobalphotons.cpp
@@ -0,0 +1,521 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmglobalphotons.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pmenumproperty.h"
+#include "pmglobalphotonsedit.h"
+
+#include <klocale.h>
+
+const double spacingDefault = 0.01;
+const int countDefault = 20000;
+const int gatherMinDefault = 20;
+const int gatherMaxDefault = 100;
+const int mediaMaxStepsDefault = 0;
+const double mediaFactorDefault = 1.0;
+const double jitterDefault = 0.4;
+const int maxTraceLevelDefault = 0;
+const double adcBailoutDefault = 0.01;
+const double autostopDefault = 0.0;
+const double expandIncreaseDefault = 0.2;
+const int expandMinDefault = 40;
+const double radiusGatherDefault = 0.0;
+const double radiusGatherMultiDefault = 1.0;
+const double radiusMediaDefault = 0.0;
+const double radiusMediaMultiDefault = 1.0;
+
+PMDefinePropertyClass( PMGlobalPhotons, PMGlobalPhotonsProperty );
+PMDefineEnumPropertyClass( PMGlobalPhotons, PMGlobalPhotons::PMNumberType, PMNumberProperty );
+
+PMMetaObject* PMGlobalPhotons::s_pMetaObject = 0;
+PMObject* createNewGlobalPhotons( PMPart* part )
+{
+ return new PMGlobalPhotons( part );
+}
+
+PMGlobalPhotons::PMGlobalPhotons( PMPart* part ) : Base( part )
+{
+ m_numberType = Spacing;
+ m_spacing = spacingDefault;
+ m_count = countDefault;
+ m_gatherMin = gatherMinDefault;
+ m_gatherMax = gatherMaxDefault;
+ m_mediaMaxSteps = mediaMaxStepsDefault;
+ m_mediaFactor = mediaFactorDefault;
+ m_jitter = jitterDefault;
+ m_maxTraceLevelGlobal = true;
+ m_maxTraceLevel = maxTraceLevelDefault;
+ m_adcBailoutGlobal = true;
+ m_adcBailout = adcBailoutDefault;
+ m_autostop = autostopDefault;
+ m_expandIncrease = expandIncreaseDefault;
+ m_expandMin = expandMinDefault;
+ m_radiusGather = radiusGatherDefault;
+ m_radiusGatherMulti = radiusGatherMultiDefault;
+ m_radiusMedia = radiusMediaDefault;
+ m_radiusMediaMulti = radiusMediaMultiDefault;
+}
+
+PMGlobalPhotons::PMGlobalPhotons( const PMGlobalPhotons& p )
+ : Base( p )
+{
+ m_numberType = p.m_numberType;
+ m_spacing = p.m_spacing;
+ m_count = p.m_count;
+ m_gatherMin = p.m_gatherMin;
+ m_gatherMax = p.m_gatherMax;
+ m_mediaMaxSteps = p.m_mediaMaxSteps;
+ m_mediaFactor = p.m_mediaFactor;
+ m_jitter = p.m_jitter;
+ m_maxTraceLevelGlobal = p.m_maxTraceLevelGlobal;
+ m_maxTraceLevel = p.m_maxTraceLevel;
+ m_adcBailoutGlobal = p.m_adcBailoutGlobal;
+ m_adcBailout = p.m_adcBailout;
+ m_autostop = p.m_autostop;
+ m_expandIncrease = p.m_expandIncrease;
+ m_expandMin = p.m_expandMin;
+ m_radiusGather = p.m_radiusGather;
+ m_radiusGatherMulti = p.m_radiusGatherMulti;
+ m_radiusMedia = p.m_radiusMedia;
+ m_radiusMediaMulti = p.m_radiusMediaMulti;
+}
+
+PMGlobalPhotons::~PMGlobalPhotons( )
+{
+}
+
+PMMetaObject* PMGlobalPhotons::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "GlobalPhotons", Base::metaObject( ),
+ createNewGlobalPhotons );
+
+ PMNumberProperty* p1 = new PMNumberProperty( "numberType",
+ &PMGlobalPhotons::setNumberType, &PMGlobalPhotons::numberType );
+ p1->addEnumValue( "Spacing", Spacing );
+ p1->addEnumValue( "Count", Count );
+ s_pMetaObject->addProperty( p1 );
+
+ s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "spacing",
+ &PMGlobalPhotons::setSpacing, &PMGlobalPhotons::spacing ) );
+ s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "count",
+ &PMGlobalPhotons::setCount, &PMGlobalPhotons::count ) );
+ s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "gatherMin",
+ &PMGlobalPhotons::setGatherMin, &PMGlobalPhotons::gatherMin ) );
+ s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "gatherMax",
+ &PMGlobalPhotons::setGatherMax, &PMGlobalPhotons::gatherMax ) );
+ s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "mediaMaxSteps",
+ &PMGlobalPhotons::setMediaMaxSteps, &PMGlobalPhotons::mediaMaxSteps ) );
+ s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "mediaFactor",
+ &PMGlobalPhotons::setMediaFactor, &PMGlobalPhotons::mediaFactor ) );
+ s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "jitter",
+ &PMGlobalPhotons::setJitter, &PMGlobalPhotons::jitter ) );
+ s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "maxTraceLevelGlobal",
+ &PMGlobalPhotons::setMaxTraceLevelGlobal, &PMGlobalPhotons::maxTraceLevelGlobal ) );
+ s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "maxTraceLevel",
+ &PMGlobalPhotons::setMaxTraceLevel, &PMGlobalPhotons::maxTraceLevel ) );
+ s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "adcBailoutGlobal",
+ &PMGlobalPhotons::setAdcBailoutGlobal, &PMGlobalPhotons::adcBailoutGlobal ) );
+ s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "adcBailout",
+ &PMGlobalPhotons::setAdcBailout, &PMGlobalPhotons::adcBailout ) );
+ s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "autostop",
+ &PMGlobalPhotons::setAutostop, &PMGlobalPhotons::autostop ) );
+ s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "expandIncrease",
+ &PMGlobalPhotons::setExpandIncrease, &PMGlobalPhotons::expandIncrease ) );
+ s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "expandMin",
+ &PMGlobalPhotons::setExpandMin, &PMGlobalPhotons::expandMin ) );
+ s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "radiusGather",
+ &PMGlobalPhotons::setRadiusGather, &PMGlobalPhotons::radiusGather ) );
+ s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "radiusGatherMulti",
+ &PMGlobalPhotons::setRadiusGatherMulti, &PMGlobalPhotons::radiusGatherMulti ) );
+ s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "radiusMedia",
+ &PMGlobalPhotons::setRadiusMedia, &PMGlobalPhotons::radiusMedia ) );
+ s_pMetaObject->addProperty( new PMGlobalPhotonsProperty( "radiusMediaMulti",
+ &PMGlobalPhotons::setRadiusMediaMulti, &PMGlobalPhotons::radiusMediaMulti ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMGlobalPhotons::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMGlobalPhotons::description( ) const
+{
+ return i18n( "global photons" );
+}
+
+void PMGlobalPhotons::serialize( QDomElement& e, QDomDocument& ) const
+{
+ if( m_numberType == Spacing )
+ {
+ e.setAttribute( "number_type", "spacing" );
+ e.setAttribute( "spacing", m_spacing );
+ }
+ else
+ {
+ e.setAttribute( "number_type", "count" );
+ e.setAttribute( "count", m_count );
+ }
+
+ e.setAttribute( "gather_min", m_gatherMin );
+ e.setAttribute( "gather_max", m_gatherMax );
+ e.setAttribute( "media_max_steps", m_mediaMaxSteps );
+ e.setAttribute( "media_factor", m_mediaFactor );
+ e.setAttribute( "jitter", m_jitter );
+ e.setAttribute( "max_trace_level_global", m_maxTraceLevelGlobal );
+ e.setAttribute( "max_trace_level", m_maxTraceLevel );
+ e.setAttribute( "adc_bailout_global", m_adcBailoutGlobal );
+ e.setAttribute( "adc_bailout", m_adcBailout );
+ e.setAttribute( "autostop", m_autostop );
+ e.setAttribute( "expand_increase", m_expandIncrease );
+ e.setAttribute( "expand_min", m_expandMin );
+ e.setAttribute( "radius_gather", m_radiusGather );
+ e.setAttribute( "radius_gather_multi", m_radiusGatherMulti );
+ e.setAttribute( "radius_media", m_radiusMedia );
+ e.setAttribute( "radius_media_multi", m_radiusMediaMulti );
+}
+
+void PMGlobalPhotons::readAttributes( const PMXMLHelper& h )
+{
+ QString str;
+
+ str = h.stringAttribute( "number_type", "spacing" );
+ if( str == "count" )
+ m_numberType = Count;
+ else
+ m_numberType = Spacing;
+
+ m_spacing = h.doubleAttribute( "spacing", spacingDefault );
+ m_count = h.intAttribute( "count", countDefault );
+ m_gatherMin = h.intAttribute( "gather_min", gatherMinDefault );
+ m_gatherMax = h.intAttribute( "gather_max", gatherMaxDefault );
+ m_mediaMaxSteps = h.intAttribute( "media_max_steps", mediaMaxStepsDefault );
+ m_mediaFactor = h.doubleAttribute( "media_factor", mediaFactorDefault );
+ m_jitter = h.doubleAttribute( "jitter", jitterDefault );
+ m_maxTraceLevelGlobal = h.boolAttribute( "max_trace_level_global", true );
+ m_maxTraceLevel = h.intAttribute( "max_trace_level", maxTraceLevelDefault );
+ m_adcBailoutGlobal = h.boolAttribute( "adc_bailout_global", true );
+ m_adcBailout = h.doubleAttribute( "adc_bailout", adcBailoutDefault );
+ m_autostop = h.doubleAttribute( "autostop", autostopDefault );
+ m_expandIncrease = h.doubleAttribute( "expand_increase", expandIncreaseDefault );
+ m_expandMin = h.intAttribute( "expand_min", expandMinDefault );
+ m_radiusGather = h.doubleAttribute( "radius_gather", radiusGatherDefault );
+ m_radiusGatherMulti = h.doubleAttribute( "radius_gather_multi",
+ radiusGatherMultiDefault );
+
+ m_radiusMedia = h.doubleAttribute( "radius_media", radiusMediaDefault );
+ m_radiusMediaMulti = h.doubleAttribute( "radius_media_multi",
+ radiusMediaMultiDefault );
+}
+
+void PMGlobalPhotons::setNumberType( PMNumberType nt )
+{
+ if( nt != m_numberType )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMNumberTypeID, m_numberType );
+ m_numberType = nt;
+ }
+}
+
+void PMGlobalPhotons::setSpacing( double s )
+{
+ if( s != m_spacing )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSpacingID, m_spacing );
+ m_spacing = s;
+ }
+}
+
+void PMGlobalPhotons::setCount( int c )
+{
+ if( c != m_count )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMCountID, m_count );
+ m_count = c;
+ }
+}
+
+void PMGlobalPhotons::setGatherMin( int gm )
+{
+ if( gm > m_gatherMax )
+ {
+ kdError( PMArea ) << "Gather Minimum > Gather Maximum in PMGlobalPhotons::setGatherMin\n";
+ gm = m_gatherMax;
+ }
+
+ if( gm != m_gatherMin )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMGatherMinID, m_gatherMin );
+ m_gatherMin = gm;
+ }
+}
+
+void PMGlobalPhotons::setGatherMax( int gm )
+{
+ if( gm < m_gatherMin )
+ {
+ kdError( PMArea ) << "Gather Maximum < Gather Minimum in PMGlobalPhotons::setGatherMax\n";
+ gm = m_gatherMin;
+ }
+
+ if( gm != m_gatherMax )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMGatherMaxID, m_gatherMax );
+ m_gatherMax = gm;
+ }
+}
+
+void PMGlobalPhotons::setMediaMaxSteps( int mms )
+{
+ if( mms != m_mediaMaxSteps )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMMediaMaxStepsID, m_mediaMaxSteps );
+ m_mediaMaxSteps = mms;
+ }
+}
+
+void PMGlobalPhotons::setMediaFactor( double mf )
+{
+ if( mf != m_mediaFactor )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMMediaFactorID, m_mediaFactor );
+ m_mediaFactor = mf;
+ }
+}
+
+void PMGlobalPhotons::setJitter( double j )
+{
+ if( j != m_jitter )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMJitterID, m_jitter );
+ m_jitter = j;
+ }
+}
+
+void PMGlobalPhotons::setMaxTraceLevelGlobal( bool mtlg )
+{
+ if( mtlg != m_maxTraceLevelGlobal )
+ {
+ if( m_pMemento )
+ m_pMemento->addData(
+ s_pMetaObject, PMMaxTraceLevelGlobalID, m_maxTraceLevelGlobal );
+ m_maxTraceLevelGlobal = mtlg;
+ }
+}
+
+void PMGlobalPhotons::setMaxTraceLevel( int mtl )
+{
+ if( mtl != m_maxTraceLevel )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMMaxTraceLevelID, m_maxTraceLevel );
+ m_maxTraceLevel = mtl;
+ }
+}
+
+void PMGlobalPhotons::setAdcBailoutGlobal( bool abg )
+{
+ if( abg != m_adcBailoutGlobal )
+ {
+ if( m_pMemento )
+ m_pMemento->addData(
+ s_pMetaObject, PMAdcBailoutGlobalID, m_adcBailoutGlobal );
+ m_adcBailoutGlobal = abg;
+ }
+}
+
+void PMGlobalPhotons::setAdcBailout( double ab )
+{
+ if( ab != m_adcBailout )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAdcBailoutID, m_adcBailout );
+ m_adcBailout = ab;
+ }
+}
+
+void PMGlobalPhotons::setAutostop( double a )
+{
+ if( a != m_autostop )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAutostopID, m_autostop );
+ m_autostop = a;
+ }
+}
+
+void PMGlobalPhotons::setExpandIncrease( double ei )
+{
+ if( ei != m_expandIncrease )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMExpandIncreaseID, m_expandIncrease );
+ m_expandIncrease = ei;
+ }
+}
+
+void PMGlobalPhotons::setExpandMin( int em )
+{
+ if(em != m_expandMin )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMExpandMinID, m_expandMin );
+ m_expandMin = em;
+ }
+}
+
+void PMGlobalPhotons::setRadiusGather( double rg )
+{
+ if ( rg != m_radiusGather )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMRadiusGatherID, m_radiusGather );
+ m_radiusGather = rg;
+ }
+}
+
+void PMGlobalPhotons::setRadiusGatherMulti( double rgm )
+{
+ if ( rgm != m_radiusGatherMulti )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMRadiusGatherID, m_radiusGatherMulti );
+ m_radiusGatherMulti = rgm;
+ }
+}
+
+void PMGlobalPhotons::setRadiusMedia( double rm )
+{
+ if ( rm != m_radiusMedia )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMRadiusGatherID, m_radiusMedia );
+ m_radiusMedia = rm;
+ }
+}
+
+void PMGlobalPhotons::setRadiusMediaMulti( double rmm )
+{
+ if ( rmm != m_radiusMediaMulti )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMRadiusGatherID, m_radiusMediaMulti );
+ m_radiusMediaMulti = rmm;
+ }
+}
+
+PMDialogEditBase* PMGlobalPhotons::editWidget( QWidget* parent ) const
+{
+ return new PMGlobalPhotonsEdit( parent );
+}
+
+void PMGlobalPhotons::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMNumberTypeID:
+ setNumberType( ( PMNumberType ) ( data->intData( ) ) );
+ break;
+ case PMSpacingID:
+ setSpacing( data->doubleData( ) );
+ break;
+ case PMCountID:
+ setCount( data->intData( ) );
+ break;
+ case PMGatherMinID:
+ setGatherMin( data->intData( ) );
+ break;
+ case PMGatherMaxID:
+ setGatherMax( data->intData( ) );
+ break;
+ case PMMediaMaxStepsID:
+ setMediaMaxSteps( data->intData( ) );
+ break;
+ case PMMediaFactorID:
+ setMediaFactor( data->doubleData( ) );
+ break;
+ case PMJitterID:
+ setJitter( data->doubleData( ) );
+ break;
+ case PMMaxTraceLevelGlobalID:
+ setMaxTraceLevelGlobal( data->boolData( ) );
+ break;
+ case PMMaxTraceLevelID:
+ setMaxTraceLevel( data->intData( ) );
+ break;
+ case PMAdcBailoutGlobalID:
+ setAdcBailoutGlobal( data->boolData( ) );
+ break;
+ case PMAdcBailoutID:
+ setAdcBailout( data->doubleData( ) );
+ break;
+ case PMAutostopID:
+ setAutostop( data->doubleData( ) );
+ break;
+ case PMExpandIncreaseID:
+ setExpandIncrease( data->doubleData( ) );
+ break;
+ case PMExpandMinID:
+ setExpandMin( data->intData( ) );
+ break;
+ case PMRadiusGatherID:
+ setRadiusGather( data->doubleData( ) );
+ break;
+ case PMRadiusGatherMultiID:
+ setRadiusGatherMulti( data->doubleData( ) );
+ break;
+ case PMRadiusMediaID:
+ setRadiusMedia( data->doubleData( ) );
+ break;
+ case PMRadiusMediaMultiID:
+ setRadiusMediaMulti( data->doubleData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMRadiosity::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmglobalphotons.h b/kpovmodeler/pmglobalphotons.h
new file mode 100644
index 00000000..b56cc6b1
--- /dev/null
+++ b/kpovmodeler/pmglobalphotons.h
@@ -0,0 +1,284 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMGLOBALPHOTONS_H
+#define PMGLOBALPHOTONS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmobject.h"
+
+/**
+ * Class for GlobalPhotons settings.
+ */
+
+class PMGlobalPhotons : public PMObject
+{
+ typedef PMObject Base;
+public:
+ enum PMNumberType { Spacing=0, Count=1 };
+
+ /**
+ * Creates a PMGlobalPhotons
+ */
+ PMGlobalPhotons( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMGlobalPhotons( const PMGlobalPhotons& p );
+ /**
+ * deletes the PMGlobalPhotons
+ */
+ virtual ~PMGlobalPhotons( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMGlobalPhotons( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMGlobalPhotonsEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmglobalphotons" ); }
+
+ /**
+ * Returns the number type
+ */
+ PMNumberType numberType( ) const { return m_numberType; }
+ /**
+ * Sets the number type
+ */
+ void setNumberType( PMNumberType nt );
+
+ /**
+ * Returns the photons spacing value
+ */
+ double spacing( ) const { return m_spacing; }
+ /**
+ * Sets the photons spacing value
+ */
+ void setSpacing( double s );
+
+ /**
+ * Returns the number of photons to shoot
+ */
+ int count( ) const { return m_count; }
+ /**
+ * Sets the number of photons to shoot
+ */
+ void setCount( int c );
+
+ /**
+ * Returns the minimum gather
+ */
+ int gatherMin( ) const { return m_gatherMin; }
+ /**
+ * Sets the minimum gather
+ */
+ void setGatherMin( int gm );
+
+ /**
+ * Returns the maximum gather
+ */
+ int gatherMax( ) const { return m_gatherMax; }
+ /**
+ * Sets the maximum gather
+ */
+ void setGatherMax( int gm );
+
+ /**
+ * Returns the media maximum steps
+ */
+ int mediaMaxSteps( ) const { return m_mediaMaxSteps; }
+ /**
+ * Sets the media maximum steps
+ */
+ void setMediaMaxSteps( int mms );
+
+ /**
+ * Returns the media factor
+ */
+ double mediaFactor( ) const { return m_mediaFactor; }
+ /**
+ * Sets the media factor
+ */
+ void setMediaFactor( double mf );
+
+ /**
+ * Returns jitter amount
+ */
+ double jitter( ) const { return m_jitter; }
+ /**
+ * Sets the jitter amount
+ */
+ void setJitter( double j );
+
+ /**
+ * Returns the maximum trace level global flag
+ */
+ bool maxTraceLevelGlobal( ) const { return m_maxTraceLevelGlobal; }
+ /**
+ * Sets the maximum trace level global flag
+ */
+ void setMaxTraceLevelGlobal( bool mtlg );
+
+ /**
+ * Returns the maximum trace level
+ */
+ int maxTraceLevel( ) const { return m_maxTraceLevel; }
+ /**
+ * Sets the maximum trace level
+ */
+ void setMaxTraceLevel( int mtl );
+
+ /**
+ * Returns the adc bailout global flag
+ */
+ bool adcBailoutGlobal( ) const { return m_adcBailoutGlobal; }
+ /**
+ * Sets the adc bailout global flag
+ */
+ void setAdcBailoutGlobal( bool abg );
+
+ /**
+ * Returns the adc bailout
+ */
+ double adcBailout( ) const { return m_adcBailout; }
+ /**
+ * Sets the adc bailout
+ */
+ void setAdcBailout( double ab );
+
+ /**
+ * Returns the autostop fraction
+ */
+ double autostop( ) const { return m_autostop; }
+ /**
+ * Sets the autostop fraction
+ */
+ void setAutostop( double a );
+
+ /**
+ * Returns the expand threshold percent increase
+ */
+ double expandIncrease( ) const { return m_expandIncrease; }
+ /**
+ * Sets the expand threshold percent increase
+ */
+ void setExpandIncrease( double ei );
+
+ /**
+ * Returns the expand threshold minimum
+ */
+ int expandMin( ) const { return m_expandMin; }
+ /**
+ * Sets the expand threshold minimum
+ */
+ void setExpandMin( int em );
+
+ /**
+ * Retuens the gather radius
+ */
+ double radiusGather( ) const { return m_radiusGather; }
+ /**
+ * Sets the gather radius
+ */
+ void setRadiusGather( double rg );
+
+ /**
+ * Returns the gather radius multiplier
+ */
+ double radiusGatherMulti( ) const { return m_radiusGatherMulti; }
+ /**
+ * Sets the radius gather multiplier
+ */
+ void setRadiusGatherMulti( double rgm );
+
+ /**
+ * Returns the media gather radius
+ */
+ double radiusMedia( ) const { return m_radiusMedia; }
+ /**
+ * Sets the media gather radius
+ */
+ void setRadiusMedia( double rm );
+
+ /**
+ * Returns the media gather radius multiplier
+ */
+ double radiusMediaMulti( ) const { return m_radiusMediaMulti; }
+ /**
+ * Sets the media gather radius multiplier
+ */
+ void setRadiusMediaMulti( double rmm );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMGlobalPhotonsMementoID
+ { PMNumberTypeID, PMSpacingID, PMCountID, PMGatherMinID, PMGatherMaxID,
+ PMMediaMaxStepsID, PMMediaFactorID, PMJitterID, PMMaxTraceLevelGlobalID,
+ PMMaxTraceLevelID, PMAdcBailoutGlobalID, PMAdcBailoutID, PMAutostopID,
+ PMExpandIncreaseID, PMExpandMinID, PMRadiusGatherID, PMRadiusGatherMultiID,
+ PMRadiusMediaID, PMRadiusMediaMultiID };
+
+ PMNumberType m_numberType;
+ double m_spacing;
+ int m_count;
+ int m_gatherMin;
+ int m_gatherMax;
+ int m_mediaMaxSteps;
+ double m_mediaFactor;
+ double m_jitter;
+ bool m_maxTraceLevelGlobal;
+ int m_maxTraceLevel;
+ bool m_adcBailoutGlobal;
+ double m_adcBailout;
+ double m_autostop;
+ double m_expandIncrease;
+ int m_expandMin;
+ double m_radiusGather;
+ double m_radiusGatherMulti;
+ double m_radiusMedia;
+ double m_radiusMediaMulti;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmglobalphotonsedit.cpp b/kpovmodeler/pmglobalphotonsedit.cpp
new file mode 100644
index 00000000..e241f597
--- /dev/null
+++ b/kpovmodeler/pmglobalphotonsedit.cpp
@@ -0,0 +1,328 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmglobalphotonsedit.h"
+#include "pmglobalphotons.h"
+#include "pmlineedits.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <klocale.h>
+#include <kdialog.h>
+#include <kmessagebox.h>
+
+
+PMGlobalPhotonsEdit::PMGlobalPhotonsEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMGlobalPhotonsEdit::createTopWidgets( )
+{
+ QHBoxLayout* hl;
+ QGridLayout* gl;
+ QLabel* lbl;
+
+ Base::createTopWidgets( );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ lbl = new QLabel( i18n( "Photon numbers" ), this );
+ m_pNumberType = new QComboBox( false, this );
+ m_pNumberType->insertItem( i18n( "Spacing" ) );
+ m_pNumberType->insertItem( i18n( "Count" ) );
+ m_pSpacing = new PMFloatEdit( this );
+ m_pSpacing->setValidation( true, 0, false, 0 );
+ m_pCount = new PMIntEdit( this );
+ m_pCount->setValidation( true, 0, false, 0 );
+ hl->addWidget( lbl );
+ hl->addWidget( m_pNumberType );
+ hl->addWidget( m_pSpacing );
+ hl->addWidget( m_pCount );
+ hl->addStretch( 1 );
+
+ gl = new QGridLayout( topLayout( ), 2, 5 );
+ lbl = new QLabel( i18n( "Gather" ), this );
+ gl->addWidget( lbl, 0, 0 );
+ lbl = new QLabel( i18n( "Min:" ), this );
+ gl->addWidget( lbl, 0, 1 );
+ m_pGatherMin = new PMIntEdit( this );
+ m_pGatherMin->setValidation( true, 0, false, 0 );
+ gl->addWidget( m_pGatherMin, 0, 2 );
+ lbl = new QLabel( i18n( "Max:" ), this );
+ gl->addWidget( lbl, 0, 3 );
+ m_pGatherMax = new PMIntEdit( this );
+ m_pGatherMax->setValidation( true, 0, false, 0 );
+ gl->addWidget( m_pGatherMax, 0, 4 );
+
+ lbl = new QLabel( i18n( "Media" ), this );
+ gl->addWidget( lbl, 1, 0 );
+ lbl = new QLabel( i18n( "Max stop:" ), this );
+ gl->addWidget( lbl, 1, 1 );
+ m_pMediaMaxSteps = new PMIntEdit( this );
+ m_pMediaMaxSteps->setValidation( true, 0, false, 0 );
+ gl->addWidget( m_pMediaMaxSteps, 1, 2 );
+ lbl = new QLabel( i18n( "Factor:" ), this );
+ gl->addWidget( lbl,1, 3 );
+ m_pMediaFactor = new PMFloatEdit( this );
+ m_pMediaFactor->setValidation( true, 0, false, 0 );
+ gl->addWidget( m_pMediaFactor, 1, 4 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ lbl = new QLabel( i18n( "Jitter:" ), this );
+ m_pJitter = new PMFloatEdit( this );
+ m_pJitter->setValidation ( true, 0, false, 0 );
+ hl->addWidget( lbl );
+ hl->addWidget( m_pJitter );
+ hl->addStretch( 1 );
+
+ gl = new QGridLayout( topLayout( ), 2, 3 );
+ lbl = new QLabel( i18n( "Max trace level:" ), this );
+ m_pMaxTraceLevel = new PMIntEdit ( this );
+ m_pMaxTraceLevel->setValidation( true, 0, false, 0 );
+ m_pMaxTraceLevelGlobal = new QCheckBox( i18n( "Use global" ), this );
+ gl->addWidget( lbl, 0, 0 );
+ gl->addWidget( m_pMaxTraceLevel, 0, 1 );
+ gl->addWidget( m_pMaxTraceLevelGlobal, 0, 2 );
+
+ lbl = new QLabel( i18n( "Adc bailout:" ), this );
+ m_pAdcBailout = new PMFloatEdit ( this );
+ m_pAdcBailout->setValidation( true, 0, true, 1 );
+ m_pAdcBailoutGlobal = new QCheckBox( i18n( "Use global" ), this );
+ gl->addWidget( lbl, 1, 0 );
+ gl->addWidget( m_pAdcBailout, 1, 1 );
+ gl->addWidget( m_pAdcBailoutGlobal, 1, 2 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ lbl = new QLabel( i18n( "Autostop:" ), this );
+ m_pAutostop = new PMFloatEdit ( this );
+ m_pAutostop->setValidation( true, 0, true, 1 );
+ hl->addWidget( lbl );
+ hl->addWidget( m_pAutostop );
+ hl->addStretch( 1 );
+
+ gl = new QGridLayout( topLayout( ), 3, 5 );
+ lbl = new QLabel( i18n( "Expand" ), this );
+ gl->addWidget( lbl, 0, 0 );
+ lbl = new QLabel( i18n( "Increase:" ), this );
+ gl->addWidget( lbl, 0, 1 );
+ m_pExpandIncrease = new PMFloatEdit( this );
+ m_pExpandIncrease->setValidation( true, 0, true, 1 );
+ gl->addWidget( m_pExpandIncrease, 0, 2 );
+ lbl = new QLabel( i18n( "Minimum:" ), this );
+ gl->addWidget( lbl, 0, 3 );
+ m_pExpandMin = new PMIntEdit( this );
+ m_pExpandMin->setValidation( true, 0, false, 0 );
+ gl->addWidget( m_pExpandMin, 0, 4 );
+
+ lbl = new QLabel( i18n( "Gather" ), this );
+ gl->addWidget( lbl, 1, 0 );
+ lbl = new QLabel( i18n( "Radius:" ), this );
+ gl->addWidget( lbl, 1, 1 );
+ m_pRadiusGather = new PMFloatEdit( this );
+ m_pRadiusGather->setValidation( true, 0, false, 0 );
+ gl->addWidget( m_pRadiusGather, 1, 2 );
+ lbl = new QLabel( i18n( "Multiplier:" ), this );
+ gl->addWidget( lbl, 1, 3 );
+ m_pRadiusGatherMulti = new PMFloatEdit( this );
+ m_pRadiusGatherMulti->setValidation( true, 0, false, 0 );
+ gl->addWidget( m_pRadiusGatherMulti, 1, 4 );
+
+ lbl = new QLabel( i18n( "Media" ), this );
+ gl->addWidget( lbl, 2, 0 );
+ lbl = new QLabel( i18n( "Radius:" ), this );
+ gl->addWidget( lbl, 2, 1 );
+ m_pRadiusMedia = new PMFloatEdit( this );
+ m_pRadiusMedia->setValidation( true, 0, false, 0 );
+ gl->addWidget( m_pRadiusMedia, 2, 2 );
+ lbl = new QLabel( i18n( "Multiplier:" ), this );
+ gl->addWidget( lbl, 2, 3 );
+ m_pRadiusMediaMulti = new PMFloatEdit( this );
+ m_pRadiusMediaMulti->setValidation( true, 0, false, 0 );
+ gl->addWidget( m_pRadiusMediaMulti, 2, 4 );
+
+ connect( m_pNumberType, SIGNAL( activated( int ) ),
+ SLOT( slotNumberTypeActivated( int ) ) );
+ connect( m_pSpacing, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pCount, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pGatherMin, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pGatherMax, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pMediaMaxSteps, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pMediaFactor, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pJitter, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pMaxTraceLevelGlobal, SIGNAL( clicked( ) ),
+ SLOT( slotMaxTraceLevelGlobalClicked( ) ) );
+ connect( m_pMaxTraceLevel, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pAdcBailoutGlobal, SIGNAL( clicked( ) ),
+ SLOT( slotAdcBailoutGlobalClicked( ) ) );
+ connect( m_pAdcBailout, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pAutostop, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pExpandIncrease, SIGNAL( dataChanged( ) ), SIGNAL ( dataChanged( ) ) );
+ connect( m_pExpandMin, SIGNAL( dataChanged( ) ), SIGNAL ( dataChanged( ) ) );
+ connect( m_pRadiusGather, SIGNAL( dataChanged( ) ), SIGNAL ( dataChanged( ) ) );
+ connect( m_pRadiusGatherMulti, SIGNAL( dataChanged( ) ), SIGNAL ( dataChanged( ) ) );
+ connect( m_pRadiusMedia, SIGNAL( dataChanged( ) ), SIGNAL ( dataChanged( ) ) );
+ connect( m_pRadiusMediaMulti, SIGNAL( dataChanged( ) ), SIGNAL ( dataChanged( ) ) );
+}
+
+void PMGlobalPhotonsEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "GlobalPhotons" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMGlobalPhotons* ) o;
+
+ m_pNumberType->setCurrentItem( m_pDisplayedObject->numberType( ) );
+ m_pNumberType->setEnabled( !readOnly );
+ m_pSpacing->setValue( m_pDisplayedObject->spacing( ) );
+ m_pSpacing->setReadOnly( readOnly );
+ m_pCount->setValue( m_pDisplayedObject->count( ) );
+ m_pCount->setReadOnly( readOnly );
+ m_pGatherMin->setValue( m_pDisplayedObject->gatherMin( ) );
+ m_pGatherMin->setReadOnly( readOnly );
+ m_pGatherMax->setValue( m_pDisplayedObject->gatherMax( ) );
+ m_pGatherMax->setReadOnly( readOnly );
+ m_pMediaMaxSteps->setValue( m_pDisplayedObject->mediaMaxSteps( ) );
+ m_pMediaMaxSteps->setReadOnly( readOnly );
+ m_pMediaFactor->setValue( m_pDisplayedObject->mediaFactor( ) );
+ m_pMediaFactor->setReadOnly( readOnly );
+ m_pJitter->setValue( m_pDisplayedObject->jitter( ) );
+ m_pJitter->setReadOnly( readOnly );
+ m_pMaxTraceLevelGlobal->setChecked( m_pDisplayedObject->maxTraceLevelGlobal( ) );
+ m_pMaxTraceLevelGlobal->setEnabled( !readOnly );
+ m_pMaxTraceLevel->setValue( m_pDisplayedObject->maxTraceLevel( ) );
+ m_pMaxTraceLevel->setReadOnly( readOnly );
+ m_pAdcBailoutGlobal->setChecked( m_pDisplayedObject->adcBailoutGlobal( ) );
+ m_pAdcBailoutGlobal->setEnabled( !readOnly );
+ m_pAdcBailout->setValue( m_pDisplayedObject->adcBailout( ) );
+ m_pAdcBailout->setReadOnly( readOnly );
+ m_pAutostop->setValue( m_pDisplayedObject->autostop( ) );
+ m_pAutostop->setReadOnly( readOnly );
+ m_pExpandIncrease->setValue( m_pDisplayedObject->expandIncrease( ) );
+ m_pExpandIncrease->setReadOnly( readOnly );
+ m_pExpandMin->setValue( m_pDisplayedObject->expandMin( ) );
+ m_pExpandMin->setReadOnly( readOnly );
+ m_pRadiusGather->setValue( m_pDisplayedObject->radiusGather( ) );
+ m_pRadiusGather->setReadOnly( readOnly );
+ m_pRadiusGatherMulti->setValue( m_pDisplayedObject->radiusGatherMulti( ) );
+ m_pRadiusGatherMulti->setReadOnly( readOnly );
+ m_pRadiusMedia->setValue( m_pDisplayedObject->radiusMedia( ) );
+ m_pRadiusMedia->setReadOnly( readOnly );
+ m_pRadiusMediaMulti->setValue( m_pDisplayedObject->radiusMediaMulti( ) );
+ m_pRadiusMediaMulti->setReadOnly( readOnly );
+
+ slotNumberTypeActivated( m_pDisplayedObject->numberType( ) );
+ slotMaxTraceLevelGlobalClicked( );
+ slotAdcBailoutGlobalClicked( );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMGlobalPhotonsEdit: Can't display object\n";
+}
+
+void PMGlobalPhotonsEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setNumberType(
+ ( PMGlobalPhotons::PMNumberType ) m_pNumberType->currentItem( ) );
+ m_pDisplayedObject->setSpacing( m_pSpacing->value( ) );
+ m_pDisplayedObject->setCount( m_pCount->value( ) );
+ m_pDisplayedObject->setGatherMin( m_pGatherMin->value( ) );
+ m_pDisplayedObject->setGatherMax( m_pGatherMax->value( ) );
+ m_pDisplayedObject->setMediaMaxSteps( m_pMediaMaxSteps->value( ) );
+ m_pDisplayedObject->setMediaFactor( m_pMediaFactor->value( ) );
+ m_pDisplayedObject->setJitter( m_pJitter->value( ) );
+ m_pDisplayedObject->setMaxTraceLevelGlobal(
+ m_pMaxTraceLevelGlobal->isChecked( ) );
+ m_pDisplayedObject->setMaxTraceLevel( m_pMaxTraceLevel->value( ) );
+ m_pDisplayedObject->setAdcBailoutGlobal(
+ m_pAdcBailoutGlobal->isChecked( ) );
+ m_pDisplayedObject->setAdcBailout( m_pAdcBailout->value( ) );
+ m_pDisplayedObject->setAutostop( m_pAutostop->value( ) );
+ m_pDisplayedObject->setExpandIncrease( m_pExpandIncrease->value( ) );
+ m_pDisplayedObject->setExpandMin( m_pExpandMin->value( ) );
+ m_pDisplayedObject->setRadiusGather( m_pRadiusGather->value( ) );
+ m_pDisplayedObject->setRadiusGatherMulti( m_pRadiusGatherMulti->value( ) );
+ m_pDisplayedObject->setRadiusMedia( m_pRadiusMedia->value( ) );
+ m_pDisplayedObject->setRadiusMediaMulti( m_pRadiusMediaMulti->value( ) );
+ }
+}
+
+bool PMGlobalPhotonsEdit::isDataValid( )
+{
+ if( !m_pSpacing->isDataValid( ) ) return false;
+ if( !m_pCount->isDataValid( ) ) return false;
+ if( !m_pGatherMin->isDataValid( ) ) return false;
+ if( !m_pGatherMax->isDataValid( ) ) return false;
+ if( !m_pMediaMaxSteps->isDataValid( ) ) return false;
+ if( !m_pMediaFactor->isDataValid( ) ) return false;
+ if( !m_pJitter->isDataValid( ) ) return false;
+ if( !m_pMaxTraceLevel->isDataValid( ) ) return false;
+ if( !m_pAdcBailout->isDataValid( ) ) return false;
+ if( !m_pAutostop->isDataValid( ) ) return false;
+ if( !m_pExpandIncrease->isDataValid( ) ) return false;
+ if( !m_pExpandMin->isDataValid( ) ) return false;
+ if( !m_pRadiusGather->isDataValid( ) ) return false;
+ if( !m_pRadiusGatherMulti->isDataValid( ) ) return false;
+ if( !m_pRadiusMedia->isDataValid( ) ) return false;
+ if( !m_pRadiusMediaMulti->isDataValid( ) ) return false;
+
+ return Base::isDataValid( );
+}
+
+void PMGlobalPhotonsEdit::slotNumberTypeActivated( int index )
+{
+ if( index == 0 )
+ {
+ m_pSpacing->show( );
+ m_pCount->hide( );
+ }
+ else
+ {
+ m_pSpacing->hide( );
+ m_pCount->show( );
+ }
+ emit dataChanged( );
+}
+
+void PMGlobalPhotonsEdit::slotMaxTraceLevelGlobalClicked( )
+{
+ if( m_pMaxTraceLevelGlobal->isChecked( ) )
+ m_pMaxTraceLevel->setEnabled( false );
+ else if ( m_pMaxTraceLevelGlobal->isEnabled( ) )
+ m_pMaxTraceLevel->setEnabled( true );
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+void PMGlobalPhotonsEdit::slotAdcBailoutGlobalClicked( )
+{
+ if( m_pAdcBailoutGlobal->isChecked( ) )
+ m_pAdcBailout->setEnabled( false );
+ else if ( m_pAdcBailoutGlobal->isEnabled( ) )
+ m_pAdcBailout->setEnabled( true );
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+#include "pmglobalphotonsedit.moc"
diff --git a/kpovmodeler/pmglobalphotonsedit.h b/kpovmodeler/pmglobalphotonsedit.h
new file mode 100644
index 00000000..ec06f749
--- /dev/null
+++ b/kpovmodeler/pmglobalphotonsedit.h
@@ -0,0 +1,98 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMGLOBALPHOTONSEDIT_H
+#define PMGLOBALPHOTONSEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdialogeditbase.h"
+
+class PMGlobalPhotons;
+class PMFloatEdit;
+class PMIntEdit;
+class QComboBox;
+class QCheckBox;
+
+/**
+ * Dialog edit class for @ref PMGlobalPhotons.
+ */
+class PMGlobalPhotonsEdit : public PMDialogEditBase
+{
+ Q_OBJECT
+ typedef PMDialogEditBase Base;
+public:
+ /**
+ * Creates a PMGlobalPhotonsEdit with parent and name
+ */
+ PMGlobalPhotonsEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+protected slots:
+ /**
+ * Slot Called whenever NumberType is altered
+ */
+ void slotNumberTypeActivated( int index );
+ /**
+ * slot Called whenever MaxTraceLevelGlobal is Clicked
+ */
+ void slotMaxTraceLevelGlobalClicked( );
+ /**
+ * slot Called whenever AdcBailoutGlobal is Clicked
+ */
+ void slotAdcBailoutGlobalClicked( );
+
+private:
+ PMGlobalPhotons* m_pDisplayedObject;
+
+ QComboBox* m_pNumberType;
+ PMFloatEdit* m_pSpacing;
+ PMIntEdit* m_pCount;
+ PMIntEdit* m_pGatherMin;
+ PMIntEdit* m_pGatherMax;
+ PMIntEdit* m_pMediaMaxSteps;
+ PMFloatEdit* m_pMediaFactor;
+ PMFloatEdit* m_pJitter;
+ QCheckBox* m_pMaxTraceLevelGlobal;
+ PMIntEdit* m_pMaxTraceLevel;
+ QCheckBox* m_pAdcBailoutGlobal;
+ PMFloatEdit* m_pAdcBailout;
+ PMFloatEdit* m_pAutostop;
+ PMFloatEdit* m_pExpandIncrease;
+ PMIntEdit* m_pExpandMin;
+ PMFloatEdit* m_pRadiusGather;
+ PMFloatEdit* m_pRadiusGatherMulti;
+ PMFloatEdit* m_pRadiusMedia;
+ PMFloatEdit* m_pRadiusMediaMulti;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmglobals.h b/kpovmodeler/pmglobals.h
new file mode 100644
index 00000000..0a50b2b6
--- /dev/null
+++ b/kpovmodeler/pmglobals.h
@@ -0,0 +1,29 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMGLOBALS_H
+#define PMGLOBALS_H
+
+#ifdef PMEnableSimpleProfiling
+#include <qdatetime.h>
+extern QTime PMDebugTime;
+#endif
+
+#define PMArea 0 // no area for debug messages yet
+
+
+#endif
diff --git a/kpovmodeler/pmglobalsettings.cpp b/kpovmodeler/pmglobalsettings.cpp
new file mode 100644
index 00000000..a4740378
--- /dev/null
+++ b/kpovmodeler/pmglobalsettings.cpp
@@ -0,0 +1,516 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmglobalsettings.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pmglobalsettingsedit.h"
+#include "pmenumproperty.h"
+
+#include <klocale.h>
+
+const double adcBailoutDefault = 1.0 / 255.0;
+const PMColor ambientLightDefault = PMColor( 1.0, 1.0, 1.0, 0.0, 0.0 );
+const double assumedGammaDefault = 0.0;
+const bool hfGray16Default = false;
+const PMColor iridWaveLengthDefault = PMColor( 0.25, 0.18, 0.14, 0.0, 0.0 );
+const int maxIntersectionsDefault = 0; // ???
+const int maxTraceLevelDefault = 0; // ???
+const int numberWavesDefault = 10;
+const bool radiosityDefault = false;
+const double brightnessDefault = 1.0;
+const int countDefault = 35;
+const double distanceMaximumDefault = 0; // ???
+const double errorBoundDefault = 1.8;
+const double grayThresholdDefault = 0.0;
+const double lowErrorFactorDefault = 0.5;
+const double minimumReuseDefault = 0.015;
+const int nearestCountDefault = 5;
+const int recursionLimitDefault = 2;
+
+PMDefinePropertyClass( PMGlobalSettings, PMGlobalSettingsProperty );
+PMDefineEnumPropertyClass( PMGlobalSettings, PMGlobalSettings::PMNoiseType, PMNoiseProperty );
+
+PMMetaObject* PMGlobalSettings::s_pMetaObject = 0;
+PMObject* createNewGlobalSettings( PMPart* part )
+{
+ return new PMGlobalSettings( part );
+}
+
+PMGlobalSettings::PMGlobalSettings( PMPart* part )
+ : Base( part )
+{
+ m_adcBailout = adcBailoutDefault;
+ m_ambientLight = ambientLightDefault;
+ m_assumedGamma = assumedGammaDefault;
+ m_hfGray16 = hfGray16Default;
+ m_iridWaveLength = iridWaveLengthDefault;
+ m_maxIntersections = maxIntersectionsDefault;
+ m_maxTraceLevel = maxTraceLevelDefault;
+ m_numberWaves = numberWavesDefault;
+ m_noiseGenerator = RangeCorrected;
+ m_radiosityEnabled = radiosityDefault;
+ m_brightness = brightnessDefault;
+ m_count = countDefault;
+ m_distanceMaximum = distanceMaximumDefault;
+ m_errorBound = errorBoundDefault;
+ m_grayThreshold = grayThresholdDefault;
+ m_lowErrorFactor = lowErrorFactorDefault;
+ m_minimumReuse = minimumReuseDefault;
+ m_nearestCount = nearestCountDefault;
+ m_recursionLimit = recursionLimitDefault;
+}
+
+PMGlobalSettings::PMGlobalSettings( const PMGlobalSettings& s )
+ : Base( s )
+{
+ m_adcBailout = s.m_adcBailout;
+ m_ambientLight = s.m_ambientLight;
+ m_assumedGamma = s.m_assumedGamma;
+ m_hfGray16 = s.m_hfGray16;
+ m_iridWaveLength = s.m_iridWaveLength;
+ m_maxIntersections = s.m_maxIntersections;
+ m_maxTraceLevel = s.m_maxTraceLevel;
+ m_numberWaves = s.m_numberWaves;
+ m_noiseGenerator = s.m_noiseGenerator;
+ m_radiosityEnabled = s.m_radiosityEnabled;
+ m_brightness = s.m_brightness;
+ m_count = s.m_count;
+ m_distanceMaximum = s.m_distanceMaximum;
+ m_errorBound = s.m_errorBound;
+ m_grayThreshold = s.m_grayThreshold;
+ m_lowErrorFactor = s.m_lowErrorFactor;
+ m_minimumReuse = s.m_minimumReuse;
+ m_nearestCount = s.m_nearestCount;
+ m_recursionLimit = s.m_recursionLimit;
+}
+
+PMGlobalSettings::~PMGlobalSettings( )
+{
+}
+
+PMMetaObject* PMGlobalSettings::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "GlobalSettings", Base::metaObject( ),
+ createNewGlobalSettings );
+ s_pMetaObject->addProperty(
+ new PMGlobalSettingsProperty( "adcBailout", &PMGlobalSettings::setAdcBailout, &PMGlobalSettings::adcBailout ) );
+ s_pMetaObject->addProperty(
+ new PMGlobalSettingsProperty( "ambientLight", &PMGlobalSettings::setAmbientLight, &PMGlobalSettings::ambientLight ) );
+ s_pMetaObject->addProperty(
+ new PMGlobalSettingsProperty( "assumedGamma", &PMGlobalSettings::setAssumedGamma, &PMGlobalSettings::assumedGamma ) );
+ s_pMetaObject->addProperty(
+ new PMGlobalSettingsProperty( "hfGray16", &PMGlobalSettings::setHfGray16, &PMGlobalSettings::hfGray16 ) );
+ s_pMetaObject->addProperty(
+ new PMGlobalSettingsProperty( "iridWaveLength", &PMGlobalSettings::setIridWaveLength, &PMGlobalSettings::iridWaveLength ) );
+ s_pMetaObject->addProperty(
+ new PMGlobalSettingsProperty( "maxIntersections", &PMGlobalSettings::setMaxIntersections, &PMGlobalSettings::maxIntersections ) );
+ s_pMetaObject->addProperty(
+ new PMGlobalSettingsProperty( "maxTraceLevel", &PMGlobalSettings::setMaxTraceLevel, &PMGlobalSettings::maxTraceLevel ) );
+ s_pMetaObject->addProperty(
+ new PMGlobalSettingsProperty( "numberWaves", &PMGlobalSettings::setNumberWaves, &PMGlobalSettings::numberWaves ) );
+
+ PMNoiseProperty* p = new PMNoiseProperty( "noiseGenerator", &PMGlobalSettings::setNoiseGenerator,
+ &PMGlobalSettings::noiseGenerator );
+ p->addEnumValue( "Original", Original );
+ p->addEnumValue( "RangeCorrected", RangeCorrected );
+ p->addEnumValue( "Perlin", Perlin );
+ s_pMetaObject->addProperty( p );
+
+ s_pMetaObject->addProperty(
+ new PMGlobalSettingsProperty( "radiosity", &PMGlobalSettings::enableRadiosity, &PMGlobalSettings::isRadiosityEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMGlobalSettingsProperty( "brightness", &PMGlobalSettings::setBrightness, &PMGlobalSettings::brightness ) );
+ s_pMetaObject->addProperty(
+ new PMGlobalSettingsProperty( "count", &PMGlobalSettings::setCount, &PMGlobalSettings::count ) );
+ s_pMetaObject->addProperty(
+ new PMGlobalSettingsProperty( "distanceMaximum", &PMGlobalSettings::setDistanceMaximum, &PMGlobalSettings::distanceMaximum ) );
+ s_pMetaObject->addProperty(
+ new PMGlobalSettingsProperty( "errorBound", &PMGlobalSettings::setErrorBound, &PMGlobalSettings::errorBound ) );
+ s_pMetaObject->addProperty(
+ new PMGlobalSettingsProperty( "grayThreshold", &PMGlobalSettings::setGrayThreshold, &PMGlobalSettings::grayThreshold ) );
+ s_pMetaObject->addProperty(
+ new PMGlobalSettingsProperty( "lowErrorFactor", &PMGlobalSettings::setLowErrorFactor, &PMGlobalSettings::lowErrorFactor ) );
+ s_pMetaObject->addProperty(
+ new PMGlobalSettingsProperty( "minimumReuse", &PMGlobalSettings::setMinimumReuse, &PMGlobalSettings::minimumReuse ) );
+ s_pMetaObject->addProperty(
+ new PMGlobalSettingsProperty( "nearestCount", &PMGlobalSettings::setNearestCount, &PMGlobalSettings::nearestCount ) );
+ s_pMetaObject->addProperty(
+ new PMGlobalSettingsProperty( "recursionLimit", &PMGlobalSettings::setRecursionLimit, &PMGlobalSettings::recursionLimit ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMGlobalSettings::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMGlobalSettings::description( ) const
+{
+ return i18n( "global settings" );
+}
+
+void PMGlobalSettings::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "adc_bailout", m_adcBailout );
+ e.setAttribute( "ambient_light", m_ambientLight.serializeXML( ) );
+ e.setAttribute( "assumed_gamma", m_assumedGamma );
+ e.setAttribute( "hf_gray_16", m_hfGray16 );
+ e.setAttribute( "irid_wavelength", m_iridWaveLength.serializeXML( ) );
+ e.setAttribute( "max_intersections", m_maxIntersections );
+ e.setAttribute( "max_trace_level", m_maxTraceLevel );
+ e.setAttribute( "number_of_waves", m_numberWaves );
+ e.setAttribute( "radiosity", m_radiosityEnabled );
+ switch ( m_noiseGenerator )
+ {
+ case Original:
+ e.setAttribute( "noise_generator", "original" );
+ break;
+ case RangeCorrected:
+ e.setAttribute( "noise_generator", "range_corrected" );
+ break;
+ case Perlin:
+ e.setAttribute( "noise_generator", "perlin" );
+ break;
+ }
+ e.setAttribute( "brightness", m_brightness );
+ e.setAttribute( "count", m_count );
+ e.setAttribute( "distance_maximum", m_distanceMaximum );
+ e.setAttribute( "error_bound", m_errorBound );
+ e.setAttribute( "gray_threshold", m_grayThreshold );
+ e.setAttribute( "low_error_factor", m_lowErrorFactor );
+ e.setAttribute( "minimum_reuse", m_minimumReuse );
+ e.setAttribute( "nearest_count", m_nearestCount );
+ e.setAttribute( "recursion_limit", m_recursionLimit );
+
+ Base::serialize( e, doc );
+}
+
+void PMGlobalSettings::readAttributes( const PMXMLHelper& h )
+{
+ QString str;
+
+ m_adcBailout = h.doubleAttribute( "adc_bailout", adcBailoutDefault );
+ m_ambientLight = h.colorAttribute( "ambient_light", ambientLightDefault );
+ m_assumedGamma = h.doubleAttribute( "assumed_gamma", assumedGammaDefault );
+ m_hfGray16 = h.boolAttribute( "hf_gray_16", hfGray16Default );
+ m_iridWaveLength = h.colorAttribute( "irid_wavelength", iridWaveLengthDefault );
+ m_maxIntersections = h.intAttribute( "max_intersections", maxIntersectionsDefault );
+ m_maxTraceLevel = h.intAttribute( "max_trace_level", maxTraceLevelDefault );
+ m_numberWaves = h.intAttribute( "number_of_waves", numberWavesDefault );
+ str = h.stringAttribute( "noise_generator", "range_corrected" );
+ if ( str == "original" )
+ m_noiseGenerator = Original;
+ else if ( str == "perlin" )
+ m_noiseGenerator = Perlin;
+ else
+ m_noiseGenerator = RangeCorrected;
+ m_radiosityEnabled = h.boolAttribute( "radiosity", radiosityDefault );
+ m_brightness = h.doubleAttribute( "brightness", brightnessDefault );
+ m_count = h.intAttribute( "count", countDefault );
+ m_distanceMaximum = h.doubleAttribute( "distance_maximum", distanceMaximumDefault );
+ m_errorBound = h.doubleAttribute( "error_bound", errorBoundDefault );
+ m_grayThreshold = h.doubleAttribute( "gray_threshold", grayThresholdDefault );
+ m_lowErrorFactor = h.doubleAttribute( "low_error_factor", lowErrorFactorDefault );
+ m_minimumReuse = h.doubleAttribute( "minimum_reuse", minimumReuseDefault );
+ m_nearestCount = h.intAttribute( "nearest_count", nearestCountDefault );
+ m_recursionLimit = h.intAttribute( "recursion_limit", recursionLimitDefault );
+
+ Base::readAttributes( h );
+}
+
+void PMGlobalSettings::setAdcBailout( double c )
+{
+ if( c != m_adcBailout )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAdcBailoutID, m_adcBailout );
+ m_adcBailout = c;
+ }
+}
+
+void PMGlobalSettings::setAmbientLight( const PMColor& c )
+{
+ if( c != m_ambientLight )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAmbientLightID, m_ambientLight );
+ m_ambientLight = c;
+ }
+}
+
+void PMGlobalSettings::setAssumedGamma( double c )
+{
+ if( c != m_assumedGamma )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAssumedGammaID, m_assumedGamma );
+ m_assumedGamma = c;
+ }
+}
+
+void PMGlobalSettings::setIridWaveLength( const PMColor& c )
+{
+ if( c != m_iridWaveLength )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMIridWaveLengthID, m_iridWaveLength );
+ m_iridWaveLength = c;
+ }
+}
+
+void PMGlobalSettings::setHfGray16( bool c )
+{
+ if( c != m_hfGray16 )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMHfGray16ID, m_hfGray16 );
+ m_hfGray16 = c;
+ }
+}
+
+void PMGlobalSettings::setMaxIntersections( int c )
+{
+ if( c != m_maxIntersections )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMMaxIntersectionsID, m_maxIntersections );
+ m_maxIntersections = c;
+ }
+}
+
+void PMGlobalSettings::setMaxTraceLevel( int c )
+{
+ if( c != m_maxTraceLevel )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMMaxTraceLevelID, m_maxTraceLevel );
+ m_maxTraceLevel = c;
+ }
+}
+
+void PMGlobalSettings::setNumberWaves( int c )
+{
+ if( c != m_numberWaves )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMNumberWavesID, m_numberWaves );
+ m_numberWaves = c;
+ }
+}
+
+void PMGlobalSettings::setNoiseGenerator( PMNoiseType c )
+{
+ if( c != m_noiseGenerator )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMNoiseGeneratorID, m_noiseGenerator );
+ m_noiseGenerator = c;
+ }
+}
+
+void PMGlobalSettings::enableRadiosity( bool c )
+{
+ if( c != m_radiosityEnabled )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMRadiosityEnabledID, m_radiosityEnabled );
+ m_radiosityEnabled = c;
+ }
+}
+
+void PMGlobalSettings::setBrightness( double c )
+{
+ if( c != m_brightness )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMBrightnessID, m_brightness );
+ m_brightness = c;
+ }
+}
+
+void PMGlobalSettings::setCount( int c )
+{
+ if( c != m_count )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMCountID, m_count );
+ m_count = c;
+ }
+}
+
+void PMGlobalSettings::setDistanceMaximum( double c )
+{
+ if( c != m_distanceMaximum )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMDistanceMaximumID, m_distanceMaximum );
+ m_distanceMaximum = c;
+ }
+}
+
+void PMGlobalSettings::setErrorBound( double c )
+{
+ if( c != m_errorBound )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMErrorBoundID, m_errorBound );
+ m_errorBound = c;
+ }
+}
+
+void PMGlobalSettings::setGrayThreshold( double c )
+{
+ if( c != m_grayThreshold )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMGrayThresholdID, m_grayThreshold );
+ m_grayThreshold = c;
+ }
+}
+
+void PMGlobalSettings::setLowErrorFactor( double c )
+{
+ if( c != m_lowErrorFactor )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMLowErrorFactorID, m_lowErrorFactor );
+ m_lowErrorFactor = c;
+ }
+}
+
+void PMGlobalSettings::setMinimumReuse( double c )
+{
+ if( c != m_minimumReuse )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMMinimumReuseID, m_minimumReuse );
+ m_minimumReuse = c;
+ }
+}
+
+void PMGlobalSettings::setNearestCount( int c )
+{
+ if( c != m_nearestCount )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMNearestCountID, m_nearestCount );
+ m_nearestCount = c;
+ }
+}
+
+void PMGlobalSettings::setRecursionLimit( int c )
+{
+ if( c != m_recursionLimit )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMRecursionLimitID, m_recursionLimit );
+ m_recursionLimit = c;
+ }
+}
+
+PMDialogEditBase* PMGlobalSettings::editWidget( QWidget* parent ) const
+{
+ return new PMGlobalSettingsEdit( parent );
+}
+
+void PMGlobalSettings::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMAdcBailoutID:
+ setAdcBailout( data->doubleData( ) );
+ break;
+ case PMAmbientLightID:
+ setAmbientLight( data->colorData( ) );
+ break;
+ case PMAssumedGammaID:
+ setAssumedGamma( data->doubleData( ) );
+ break;
+ case PMHfGray16ID:
+ setHfGray16( data->boolData( ) );
+ break;
+ case PMIridWaveLengthID:
+ setIridWaveLength( data->colorData( ) );
+ break;
+ case PMMaxIntersectionsID:
+ setMaxIntersections( data->intData( ) );
+ break;
+ case PMMaxTraceLevelID:
+ setMaxTraceLevel( data->intData( ) );
+ break;
+ case PMNumberWavesID:
+ setNumberWaves( data->intData( ) );
+ break;
+ case PMNoiseGeneratorID:
+ setNoiseGenerator( ( PMNoiseType ) ( data->intData( ) ) );
+ break;
+ case PMRadiosityEnabledID:
+ enableRadiosity( data->boolData( ) );
+ break;
+ case PMBrightnessID:
+ setBrightness( data->doubleData( ) );
+ break;
+ case PMCountID:
+ setCount( data->intData( ) );
+ break;
+ case PMDistanceMaximumID:
+ setDistanceMaximum( data->doubleData( ) );
+ break;
+ case PMErrorBoundID:
+ setErrorBound( data->doubleData( ) );
+ break;
+ case PMGrayThresholdID:
+ setGrayThreshold( data->doubleData( ) );
+ break;
+ case PMLowErrorFactorID:
+ setLowErrorFactor( data->doubleData( ) );
+ break;
+ case PMMinimumReuseID:
+ setMinimumReuse( data->doubleData( ) );
+ break;
+ case PMNearestCountID:
+ setNearestCount( data->intData( ) );
+ break;
+ case PMRecursionLimitID:
+ setRecursionLimit( data->intData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMGlobalSettings::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmglobalsettings.h b/kpovmodeler/pmglobalsettings.h
new file mode 100644
index 00000000..e552293e
--- /dev/null
+++ b/kpovmodeler/pmglobalsettings.h
@@ -0,0 +1,268 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMGLOBALSETTINGS_H
+#define PMGLOBALSETTINGS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmcompositeobject.h"
+#include "pmcolor.h"
+
+/**
+ * Class for global settings.
+ */
+
+class PMGlobalSettings : public PMCompositeObject
+{
+ typedef PMCompositeObject Base;
+public:
+ enum PMNoiseType { Original = 0, RangeCorrected = 1, Perlin = 2 };
+
+ /**
+ * Creates a PMGlobalSettings
+ */
+ PMGlobalSettings( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMGlobalSettings( const PMGlobalSettings& s );
+ /**
+ * deletes the PMGlobalSettings
+ */
+ virtual ~PMGlobalSettings( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMGlobalSettings( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMGlobalSettingsEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmglobalsettings" ); }
+
+ /**
+ * Returns the adc bailout
+ */
+ double adcBailout( ) const { return m_adcBailout; }
+ /**
+ * Sets the adc bailout
+ */
+ void setAdcBailout( double c );
+ /**
+ * Returns the ambient color
+ */
+ PMColor ambientLight( ) const { return m_ambientLight; }
+ /**
+ * Sets the ambient color
+ */
+ void setAmbientLight( const PMColor& c );
+ /**
+ * Returns the assumed gamma
+ */
+ double assumedGamma( ) const { return m_assumedGamma; }
+ /**
+ * Sets the assumed gamma
+ */
+ void setAssumedGamma( double c );
+ /**
+ * Returns the hf gray 16
+ */
+ bool hfGray16( ) const { return m_hfGray16; }
+ /**
+ * Sets the hf gray 16
+ */
+ void setHfGray16( bool c );
+ /**
+ * Returns the iridiscence wavelength
+ */
+ PMColor iridWaveLength( ) const { return m_iridWaveLength; }
+ /**
+ * Sets the iridiscence wavelength
+ */
+ void setIridWaveLength( const PMColor& c );
+ /**
+ * Returns the maximum number of intersections
+ */
+ int maxIntersections( ) const { return m_maxIntersections; }
+ /**
+ * Sets the maximum number of intersections
+ */
+ void setMaxIntersections( int c );
+ /**
+ * Returns the maximum trace level
+ */
+ int maxTraceLevel( ) const { return m_maxTraceLevel; }
+ /**
+ * Sets the maximum trace level
+ */
+ void setMaxTraceLevel( int c );
+ /**
+ * Returns the number of waves
+ */
+ int numberWaves( ) const { return m_numberWaves; }
+ /**
+ * Sets the number of waves
+ */
+ void setNumberWaves( int c );
+ /**
+ * Returns the current noise generator
+ */
+ PMNoiseType noiseGenerator( ) const { return m_noiseGenerator; }
+ /**
+ * Sets the noise generator
+ */
+ void setNoiseGenerator( PMNoiseType c );
+ /**
+ * Returns true if radiosity is enabled
+ */
+ bool isRadiosityEnabled( ) const { return m_radiosityEnabled; }
+ /**
+ * Enables/Disables radiosity
+ */
+ void enableRadiosity( bool c );
+ /**
+ * Returns brightness
+ */
+ double brightness( ) const { return m_brightness; }
+ /**
+ * Sets the brightness
+ */
+ void setBrightness( double c );
+ /**
+ * Returns count
+ */
+ int count( ) const { return m_count; }
+ /**
+ * Sets the count
+ */
+ void setCount( int c );
+ /**
+ * Returns maximum distance
+ */
+ double distanceMaximum( ) const { return m_distanceMaximum; }
+ /**
+ * Sets the maximum distance
+ */
+ void setDistanceMaximum( double c );
+ /**
+ * Returns error boundary
+ */
+ double errorBound( ) const { return m_errorBound; }
+ /**
+ * Sets the error boundary
+ */
+ void setErrorBound( double c );
+ /**
+ * Returns gray threshold
+ */
+ double grayThreshold( ) const { return m_grayThreshold; }
+ /**
+ * Sets the gray threshold
+ */
+ void setGrayThreshold( double c );
+ /**
+ * Returns low error factor
+ */
+ double lowErrorFactor( ) const { return m_lowErrorFactor; }
+ /**
+ * Sets the low error factor
+ */
+ void setLowErrorFactor( double c );
+ /**
+ * Returns minimum reuse
+ */
+ double minimumReuse( ) const { return m_minimumReuse; }
+ /**
+ * Sets the minimum reuse
+ */
+ void setMinimumReuse( double c );
+ /**
+ * Returns nearest count
+ */
+ int nearestCount( ) const { return m_nearestCount; }
+ /**
+ * Sets the nearest count
+ */
+ void setNearestCount( int c );
+ /**
+ * Returns recursion limit
+ */
+ int recursionLimit( ) const { return m_recursionLimit; }
+ /**
+ * Sets the recursion limit
+ */
+ void setRecursionLimit( int c );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMGlobalSettingsMementoID { PMAdcBailoutID, PMAmbientLightID, PMAssumedGammaID,
+ PMHfGray16ID, PMIridWaveLengthID, PMMaxIntersectionsID,
+ PMMaxTraceLevelID, PMNumberWavesID, PMNoiseGeneratorID,
+ PMRadiosityEnabledID, PMBrightnessID, PMCountID,
+ PMDistanceMaximumID, PMErrorBoundID, PMGrayThresholdID,
+ PMLowErrorFactorID, PMMinimumReuseID, PMNearestCountID,
+ PMRecursionLimitID };
+
+ double m_adcBailout;
+ PMColor m_ambientLight;
+ double m_assumedGamma;
+ bool m_hfGray16;
+ PMColor m_iridWaveLength;
+ int m_maxIntersections;
+ int m_maxTraceLevel;
+ int m_numberWaves;
+ PMNoiseType m_noiseGenerator;
+ bool m_radiosityEnabled;
+ double m_brightness;
+ int m_count;
+ double m_distanceMaximum;
+ double m_errorBound;
+ double m_grayThreshold;
+ double m_lowErrorFactor;
+ double m_minimumReuse;
+ int m_nearestCount;
+ int m_recursionLimit;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmglobalsettingsedit.cpp b/kpovmodeler/pmglobalsettingsedit.cpp
new file mode 100644
index 00000000..8a297738
--- /dev/null
+++ b/kpovmodeler/pmglobalsettingsedit.cpp
@@ -0,0 +1,317 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmglobalsettingsedit.h"
+#include "pmglobalsettings.h"
+#include "pmlineedits.h"
+#include "pmcoloredit.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <klocale.h>
+#include <kdialog.h>
+#include <kmessagebox.h>
+
+PMGlobalSettingsEdit::PMGlobalSettingsEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMGlobalSettingsEdit::createTopWidgets( )
+{
+ QHBoxLayout* hl;
+ QLabel* lbl;
+
+ Base::createTopWidgets( );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ lbl = new QLabel( i18n( "Adc bailout:" ), this );
+ m_pAdcBailoutEdit = new PMFloatEdit( this );
+ hl->addWidget( lbl );
+ hl->addWidget( m_pAdcBailoutEdit );
+ hl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ lbl = new QLabel( i18n( "Ambient light:" ), this );
+ m_pAmbientLightEdit = new PMColorEdit( false, this );
+ topLayout( )->addWidget( lbl );
+ topLayout( )->addWidget( m_pAmbientLightEdit );
+ hl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ lbl = new QLabel( i18n( "Assumed gamma:" ), this );
+ m_pAssumedGammaEdit = new PMFloatEdit( this );
+ hl->addWidget( lbl );
+ hl->addWidget( m_pAssumedGammaEdit );
+ hl->addStretch( 1 );
+
+ m_pHfGray16Edit = new QCheckBox( i18n( "Hf gray 16" ), this );
+ topLayout( )->addWidget( m_pHfGray16Edit );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ lbl = new QLabel( i18n( "Iridiscence wave length:" ), this );
+ m_pIridWaveLengthEdit = new PMColorEdit( false, this );
+ topLayout( )->addWidget( lbl );
+ topLayout( )->addWidget( m_pIridWaveLengthEdit );
+ hl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ QGridLayout* layout = new QGridLayout( hl, 4, 2 );
+ lbl = new QLabel( i18n( "Maximum intersections:" ), this );
+ m_pMaxIntersectionsEdit = new PMIntEdit( this );
+ layout->addWidget( lbl, 0, 0 );
+ layout->addWidget( m_pMaxIntersectionsEdit, 0, 1 );
+ lbl = new QLabel( i18n( "Maximum trace level:" ), this );
+ m_pMaxTraceLevelEdit = new PMIntEdit( this );
+ layout->addWidget( lbl, 1, 0 );
+ layout->addWidget( m_pMaxTraceLevelEdit, 1, 1 );
+ lbl = new QLabel( i18n( "Number of waves:" ), this );
+ m_pNumberWavesEdit = new PMIntEdit( this );
+ layout->addWidget( lbl, 2, 0 );
+ layout->addWidget( m_pNumberWavesEdit, 2, 1 );
+ lbl = new QLabel( i18n( "Noise generator:" ), this );
+ m_pNoiseGeneratorEdit = new QComboBox( false, this );
+ m_pNoiseGeneratorEdit->insertItem( i18n( "Original" ) );
+ m_pNoiseGeneratorEdit->insertItem( i18n( "Range Corrected" ) );
+ m_pNoiseGeneratorEdit->insertItem( i18n( "Perlin" ) );
+ layout->addWidget( lbl, 3, 0 );
+ layout->addWidget( m_pNoiseGeneratorEdit, 3, 1 );
+ hl->addStretch( 1 );
+
+ m_pRadiosityEdit = new QCheckBox( i18n( "Radiosity (Povray 3.1)" ), this );
+ topLayout( )->addWidget( m_pRadiosityEdit );
+
+ m_pRadiosityWidget = new QWidget( this );
+ hl = new QHBoxLayout( m_pRadiosityWidget, 0, KDialog::spacingHint( ) );
+ layout = new QGridLayout( hl, 7, 2 );
+ lbl = new QLabel( i18n( "Brightness:" ), m_pRadiosityWidget );
+ m_pBrightnessEdit = new PMFloatEdit( m_pRadiosityWidget );
+ layout->addWidget( lbl, 0, 0 );
+ layout->addWidget( m_pBrightnessEdit, 0, 1 );
+ lbl = new QLabel( i18n( "Count:" ), m_pRadiosityWidget );
+ m_pCountEdit = new PMIntEdit( m_pRadiosityWidget );
+ layout->addWidget( lbl, 1, 0 );
+ layout->addWidget( m_pCountEdit, 1, 1 );
+ lbl = new QLabel( i18n( "Maximum distance:" ), m_pRadiosityWidget );
+ m_pDistanceMaximumEdit = new PMFloatEdit( m_pRadiosityWidget );
+ layout->addWidget( lbl, 2, 0 );
+ layout->addWidget( m_pDistanceMaximumEdit, 2, 1 );
+ lbl = new QLabel( i18n( "Error boundary:" ), m_pRadiosityWidget );
+ m_pErrorBoundEdit = new PMFloatEdit( m_pRadiosityWidget );
+ layout->addWidget( lbl, 3, 0 );
+ layout->addWidget( m_pErrorBoundEdit, 3, 1 );
+ lbl = new QLabel( i18n( "Gray threshold:" ), m_pRadiosityWidget );
+ m_pGrayThresholdEdit = new PMFloatEdit( m_pRadiosityWidget );
+ layout->addWidget( lbl, 4, 0 );
+ layout->addWidget( m_pGrayThresholdEdit, 4, 1 );
+ lbl = new QLabel( i18n( "Low error factor:" ), m_pRadiosityWidget );
+ m_pLowErrorFactorEdit = new PMFloatEdit( m_pRadiosityWidget );
+ layout->addWidget( lbl, 5, 0 );
+ layout->addWidget( m_pLowErrorFactorEdit, 5, 1 );
+ lbl = new QLabel( i18n( "Minimum reuse:" ), m_pRadiosityWidget );
+ m_pMinimumReuseEdit = new PMFloatEdit( m_pRadiosityWidget );
+ layout->addWidget( lbl, 6, 0 );
+ layout->addWidget( m_pMinimumReuseEdit, 6, 1 );
+ lbl = new QLabel( i18n( "Nearest count:" ), m_pRadiosityWidget );
+ m_pNearestCountEdit = new PMIntEdit( m_pRadiosityWidget );
+ layout->addWidget( lbl, 7, 0 );
+ layout->addWidget( m_pNearestCountEdit, 7, 1 );
+ lbl = new QLabel( i18n( "Recursion limit:" ), m_pRadiosityWidget );
+ m_pRecursionLimitEdit = new PMIntEdit( m_pRadiosityWidget );
+ layout->addWidget( lbl, 8, 0 );
+ layout->addWidget( m_pRecursionLimitEdit, 8, 1 );
+ hl->addStretch( 1 );
+
+ topLayout( )->addWidget( m_pRadiosityWidget );
+
+ connect( m_pAdcBailoutEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pAmbientLightEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pAssumedGammaEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pHfGray16Edit, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pIridWaveLengthEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pMaxIntersectionsEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pMaxTraceLevelEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pNumberWavesEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pNoiseGeneratorEdit, SIGNAL( activated( int ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pRadiosityEdit, SIGNAL( clicked( ) ), SLOT( slotRadiosityClicked( ) ) );
+ connect( m_pBrightnessEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pCountEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pDistanceMaximumEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pErrorBoundEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pGrayThresholdEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pLowErrorFactorEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pMinimumReuseEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pNearestCountEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pRecursionLimitEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMGlobalSettingsEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "GlobalSettings" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMGlobalSettings* ) o;
+
+ m_pAdcBailoutEdit->setValue( m_pDisplayedObject->adcBailout( ) );
+ m_pAdcBailoutEdit->setReadOnly( readOnly );
+ m_pAmbientLightEdit->setColor( m_pDisplayedObject->ambientLight( ) );
+ m_pAmbientLightEdit->setReadOnly( readOnly );
+ m_pAssumedGammaEdit->setValue( m_pDisplayedObject->assumedGamma( ) );
+ m_pAssumedGammaEdit->setReadOnly( readOnly );
+ m_pHfGray16Edit->setChecked( m_pDisplayedObject->hfGray16( ) );
+ m_pHfGray16Edit->setEnabled( !readOnly );
+ m_pIridWaveLengthEdit->setColor( m_pDisplayedObject->iridWaveLength( ) );
+ m_pIridWaveLengthEdit->setReadOnly( readOnly );
+ m_pMaxIntersectionsEdit->setValue( m_pDisplayedObject->maxIntersections( ) );
+ m_pMaxIntersectionsEdit->setReadOnly( readOnly );
+ m_pMaxTraceLevelEdit->setValue( m_pDisplayedObject->maxTraceLevel( ) );
+ m_pMaxTraceLevelEdit->setReadOnly( readOnly );
+ m_pNumberWavesEdit->setValue( m_pDisplayedObject->numberWaves( ) );
+ m_pNumberWavesEdit->setReadOnly( readOnly );
+ m_pNoiseGeneratorEdit->setCurrentItem( m_pDisplayedObject->noiseGenerator( ) );
+ m_pNoiseGeneratorEdit->setEnabled( !readOnly );
+ m_pRadiosityEdit->setChecked( m_pDisplayedObject->isRadiosityEnabled( ) );
+ m_pRadiosityEdit->setEnabled( !readOnly );
+ m_pBrightnessEdit->setValue( m_pDisplayedObject->brightness( ) );
+ m_pBrightnessEdit->setReadOnly( readOnly );
+ m_pCountEdit->setValue( m_pDisplayedObject->count( ) );
+ m_pCountEdit->setReadOnly( readOnly );
+ m_pDistanceMaximumEdit->setValue( m_pDisplayedObject->distanceMaximum( ) );
+ m_pDistanceMaximumEdit->setReadOnly( readOnly );
+ m_pErrorBoundEdit->setValue( m_pDisplayedObject->errorBound( ) );
+ m_pErrorBoundEdit->setReadOnly( readOnly );
+ m_pGrayThresholdEdit->setValue( m_pDisplayedObject->grayThreshold( ) );
+ m_pGrayThresholdEdit->setReadOnly( readOnly );
+ m_pLowErrorFactorEdit->setValue( m_pDisplayedObject->lowErrorFactor( ) );
+ m_pLowErrorFactorEdit->setReadOnly( readOnly );
+ m_pMinimumReuseEdit->setValue( m_pDisplayedObject->minimumReuse( ) );
+ m_pMinimumReuseEdit->setReadOnly( readOnly );
+ m_pNearestCountEdit->setValue( m_pDisplayedObject->nearestCount( ) );
+ m_pNearestCountEdit->setReadOnly( readOnly );
+ m_pRecursionLimitEdit->setValue( m_pDisplayedObject->recursionLimit( ) );
+ m_pRecursionLimitEdit->setReadOnly( readOnly );
+ slotRadiosityClicked( );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMGlobalSettingsEdit: Can't display object\n";
+}
+
+void PMGlobalSettingsEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setAdcBailout( m_pAdcBailoutEdit->value( ) );
+ m_pDisplayedObject->setAmbientLight( m_pAmbientLightEdit->color( ) );
+ m_pDisplayedObject->setAssumedGamma( m_pAssumedGammaEdit->value( ) );
+ m_pDisplayedObject->setHfGray16( m_pHfGray16Edit->isChecked( ) );
+ m_pDisplayedObject->setIridWaveLength( m_pIridWaveLengthEdit->color( ) );
+ m_pDisplayedObject->setMaxIntersections( m_pMaxIntersectionsEdit->value( ) );
+ m_pDisplayedObject->setMaxTraceLevel( m_pMaxTraceLevelEdit->value( ) );
+ m_pDisplayedObject->setNumberWaves( m_pNumberWavesEdit->value( ) );
+ m_pDisplayedObject->setNoiseGenerator(
+ ( PMGlobalSettings::PMNoiseType ) ( m_pNoiseGeneratorEdit->currentItem( ) ) );
+ m_pDisplayedObject->enableRadiosity( m_pRadiosityEdit->isChecked( ) );
+ m_pDisplayedObject->setBrightness( m_pBrightnessEdit->value( ) );
+ m_pDisplayedObject->setCount( m_pCountEdit->value( ) );
+ m_pDisplayedObject->setDistanceMaximum( m_pDistanceMaximumEdit->value( ) );
+ m_pDisplayedObject->setErrorBound( m_pErrorBoundEdit->value( ) );
+ m_pDisplayedObject->setGrayThreshold( m_pGrayThresholdEdit->value( ) );
+ m_pDisplayedObject->setLowErrorFactor( m_pLowErrorFactorEdit->value( ) );
+ m_pDisplayedObject->setMinimumReuse( m_pMinimumReuseEdit->value( ) );
+ m_pDisplayedObject->setNearestCount( m_pNearestCountEdit->value( ) );
+ m_pDisplayedObject->setRecursionLimit( m_pRecursionLimitEdit->value( ) );
+ }
+}
+
+bool PMGlobalSettingsEdit::isDataValid( )
+{
+ if( !m_pAdcBailoutEdit->isDataValid( ) ) return false;
+ if( !m_pAmbientLightEdit->isDataValid( ) ) return false;
+ if( !m_pAssumedGammaEdit->isDataValid( ) ) return false;
+ if( !m_pIridWaveLengthEdit->isDataValid( ) ) return false;
+ if( !m_pMaxIntersectionsEdit->isDataValid( ) ) return false;
+ if( !m_pMaxTraceLevelEdit->isDataValid( ) ) return false;
+ if( !m_pNumberWavesEdit->isDataValid( ) ) return false;
+ if( !m_pBrightnessEdit->isDataValid( ) ) return false;
+ if( !m_pCountEdit->isDataValid( ) ) return false;
+ if( !m_pDistanceMaximumEdit->isDataValid( ) ) return false;
+ if( !m_pErrorBoundEdit->isDataValid( ) ) return false;
+ if( !m_pGrayThresholdEdit->isDataValid( ) ) return false;
+ if( !m_pLowErrorFactorEdit->isDataValid( ) ) return false;
+ if( !m_pMinimumReuseEdit->isDataValid( ) ) return false;
+ if( !m_pNearestCountEdit->isDataValid( ) ) return false;
+ if( !m_pRecursionLimitEdit->isDataValid( ) ) return false;
+
+ if( m_pMaxIntersectionsEdit->value( ) < 0 )
+ {
+ KMessageBox::error( this, i18n( "Maximum intersections must be a positive value." ),
+ i18n( "Error" ) );
+ m_pMaxIntersectionsEdit->setFocus( );
+ return false;
+ }
+ if( m_pMaxTraceLevelEdit->value( ) < 0 )
+ {
+ KMessageBox::error( this, i18n( "Maximum trace level must be a positive value." ),
+ i18n( "Error" ) );
+ m_pMaxTraceLevelEdit->setFocus( );
+ return false;
+ }
+ if( m_pNumberWavesEdit->value( ) < 0 )
+ {
+ KMessageBox::error( this, i18n( "Number of waves must be a positive value." ),
+ i18n( "Error" ) );
+ m_pNumberWavesEdit->setFocus( );
+ return false;
+ }
+ if( m_pNearestCountEdit->value( ) < 1 || m_pNearestCountEdit->value( ) > 10 )
+ {
+ KMessageBox::error( this, i18n( "Nearest count must be between 1 and 10." ),
+ i18n( "Error" ) );
+ m_pNearestCountEdit->setFocus( );
+ return false;
+ }
+
+ if( m_pRecursionLimitEdit->value( ) < 1 || m_pRecursionLimitEdit->value( ) > 2 )
+ {
+ KMessageBox::error( this, i18n( "Recursion limit must be 1 or 2." ),
+ i18n( "Error" ) );
+ m_pRecursionLimitEdit->setFocus( );
+ return false;
+ }
+
+ return Base::isDataValid( );
+}
+
+void PMGlobalSettingsEdit::slotRadiosityClicked( )
+{
+ if( m_pRadiosityEdit->isChecked( ) )
+ m_pRadiosityWidget->show( );
+ else
+ m_pRadiosityWidget->hide( );
+
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+#include "pmglobalsettingsedit.moc"
diff --git a/kpovmodeler/pmglobalsettingsedit.h b/kpovmodeler/pmglobalsettingsedit.h
new file mode 100644
index 00000000..2a439617
--- /dev/null
+++ b/kpovmodeler/pmglobalsettingsedit.h
@@ -0,0 +1,93 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMGLOBALSETTINGSEDIT_H
+#define PMGLOBALSETTINGSEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdialogeditbase.h"
+
+class PMGlobalSettings;
+class PMColorEdit;
+class PMFloatEdit;
+class PMIntEdit;
+class QCheckBox;
+class QComboBox;
+
+/**
+ * Dialog edit class for @ref PMGlobalSettings.
+ */
+class PMGlobalSettingsEdit : public PMDialogEditBase
+{
+ Q_OBJECT
+ typedef PMDialogEditBase Base;
+public:
+ /**
+ * Creates a PMGlobalSettingsEdit with parent and name
+ */
+ PMGlobalSettingsEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+protected slots:
+ /**
+ * Slot called whenever Radiosity is toggled
+ */
+ void slotRadiosityClicked( );
+
+private:
+ PMGlobalSettings* m_pDisplayedObject;
+
+ PMFloatEdit* m_pAdcBailoutEdit;
+ PMColorEdit* m_pAmbientLightEdit;
+ PMFloatEdit* m_pAssumedGammaEdit;
+ QCheckBox* m_pHfGray16Edit;
+ PMColorEdit* m_pIridWaveLengthEdit;
+ PMIntEdit* m_pMaxIntersectionsEdit;
+ PMIntEdit* m_pMaxTraceLevelEdit;
+ PMIntEdit* m_pNumberWavesEdit;
+ QComboBox* m_pNoiseGeneratorEdit;
+ QCheckBox* m_pRadiosityEdit;
+ QWidget* m_pRadiosityWidget;
+ PMFloatEdit* m_pBrightnessEdit;
+ PMIntEdit* m_pCountEdit;
+ PMFloatEdit* m_pDistanceMaximumEdit;
+ PMFloatEdit* m_pErrorBoundEdit;
+ PMFloatEdit* m_pGrayThresholdEdit;
+ PMFloatEdit* m_pLowErrorFactorEdit;
+ PMFloatEdit* m_pMinimumReuseEdit;
+ PMIntEdit* m_pNearestCountEdit;
+ PMIntEdit* m_pRecursionLimitEdit;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmglview.cpp b/kpovmodeler/pmglview.cpp
new file mode 100644
index 00000000..43102de9
--- /dev/null
+++ b/kpovmodeler/pmglview.cpp
@@ -0,0 +1,1853 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmglview.h"
+#include "pmpart.h"
+#include "pmrendermanager.h"
+#include "pmcamera.h"
+#include "pmscene.h"
+#include "pmdatachangecommand.h"
+#include "pmdebug.h"
+#include "pmdefaults.h"
+
+#include <math.h>
+#include <qpopupmenu.h>
+#include <qpainter.h>
+#include <qapplication.h>
+#include <qcursor.h>
+#include <qcolor.h>
+#include <qglobal.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcombobox.h>
+#include <qdom.h>
+
+#include <kxmlguifactory.h>
+#include <kaction.h>
+#include <kconfig.h>
+#include <kstaticdeleter.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kdialog.h>
+
+#include <GL/glx.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xos.h>
+#include <X11/Xatom.h>
+#include <X11/Xmu/StdCmap.h>
+
+const double c_sizeFactor = log( 2.0 ) / 100.0;
+const int c_mouseChangeDelayPixel = 3;
+const int c_mouseChangeDelayMs = 300;
+const int c_multipleSelectDelayPixel = 3;
+const double c_defaultAutoScrollSpeed = 200; // pixels per second
+const int c_minAutoScrollUpdateTime = 30; //ms
+
+const double keyMoveSpeed = 40.0;
+const double keyScaleFactor = 1.4;
+
+static int glxAttributeList[] = { GLX_LEVEL, 0,
+ GLX_DOUBLEBUFFER,
+ GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ //GLX_ALPHA_SIZE, 1,
+ GLX_DEPTH_SIZE, 1,
+ None };
+
+class PMGLViewStatic
+{
+public:
+ PMGLViewStatic( )
+ {
+ m_colormap = 0;
+ m_context = NULL;
+ m_colormapAllocated = false;
+ m_display = 0;
+ m_visualInfo = 0;
+ }
+ ~PMGLViewStatic( )
+ {
+ if( m_colormapAllocated )
+ XFreeColormap( m_display, m_colormap );
+ if( m_context != NULL )
+ glXDestroyContext( m_display, m_context );
+ if( m_visualInfo )
+ XFree( m_visualInfo );
+ }
+
+ Colormap m_colormap;
+ GLXContext m_context;
+ bool m_colormapAllocated;
+ Display* m_display;
+ XVisualInfo* m_visualInfo;
+};
+
+static PMGLViewStatic* s_pSharedData = 0;
+static KStaticDeleter<PMGLViewStatic> s_staticDeleter;
+bool PMGLView::s_bDirect = true;
+
+
+PMGLView::PMGLView( PMPart* part, PMViewType t,
+ QWidget* parent, const char* name, WFlags f )
+ : PMViewBase( parent, name, f | Qt::WWinOwnDC | Qt::WRepaintNoErase )
+{
+ m_pPart = part;
+ m_type = t;
+ m_bScaleMode = false;
+ m_scaleIntX = 0.0;
+ m_scaleIntY = 0.0;
+ m_bTranslateMode = false;
+ m_bGraphicalChangeMode = false;
+ m_bMousePressed = false;
+ m_bMidMousePressed = false;
+ m_dTransX = 0.0;
+ m_dTransY = 0.0;
+ m_dScale = 30.0;
+ m_bInverseValid = false;
+ m_pActiveObject = part->activeObject( );
+ m_bMementoCreated = false;
+ m_bSelectUnderMouse = false;
+ m_bDeselectUnderMouse = false;
+ m_bMultipleSelectionMode = false;
+ m_bSelectionStarted = false;
+ m_bAutoScroll = false;
+ m_autoScrollSpeed = c_defaultAutoScrollSpeed;
+ m_bAboutToUpdate = false;
+ m_projectionUpToDate = false;
+ m_contextClickPosition = PMVector( 0.0, 0.0 );
+ m_objectActions.setAutoDelete( true );
+
+ m_controlPointsPosition.setAutoDelete( true );
+ m_pUnderMouse = 0;
+
+ setCamera( m_pPart->firstCamera( ) );
+
+ initializeGL( );
+
+ setMouseTracking( true );
+ setFocusPolicy( WheelFocus );
+
+ PMRenderManager* rm = PMRenderManager::theManager( );
+ rm->viewCreated( );
+
+ setMinimumSize( 50, 50 );
+
+ connect( part, SIGNAL( refresh( ) ), SLOT( slotRefresh( ) ) );
+ connect( part, SIGNAL( clear( ) ), SLOT( slotClear( ) ) );
+
+ connect( this, SIGNAL( objectChanged( PMObject*, const int, QObject* ) ),
+ part, SLOT( slotObjectChanged( PMObject*, const int, QObject* ) ) );
+ connect( part, SIGNAL( objectChanged( PMObject*, const int, QObject* ) ),
+ SLOT( slotObjectChanged( PMObject*, const int, QObject* ) ) );
+
+ connect( part, SIGNAL( activeRenderModeChanged( ) ),
+ SLOT( slotActiveRenderModeChanged( ) ) );
+
+ connect( &m_startTimer, SIGNAL( timeout( ) ),
+ SLOT( slotMouseChangeTimer( ) ) );
+ connect( &m_autoScrollTimer, SIGNAL( timeout( ) ),
+ SLOT( slotAutoScroll( ) ) );
+
+ connect( rm, SIGNAL( renderingStarted( PMGLView* ) ),
+ SLOT( slotRenderingStarted( PMGLView* ) ) );
+ connect( rm, SIGNAL( aboutToUpdate( PMGLView* ) ),
+ SLOT( slotAboutToUpdate( PMGLView* ) ) );
+ connect( rm, SIGNAL( renderingFinished( PMGLView* ) ),
+ SLOT( slotRenderingFinished( PMGLView* ) ) );
+ connect( rm, SIGNAL( renderingSettingsChanged( ) ),
+ SLOT( slotRefresh( ) ) );
+
+ connect( this, SIGNAL( controlPointMessage( const QString& ) ),
+ m_pPart, SIGNAL( controlPointMessage( const QString& ) ) );
+
+ updateControlPoints( );
+}
+
+void PMGLView::initializeGL( )
+{
+ Display* display = x11Display( );
+ int screen = x11Screen( );
+ int i;
+
+ if( !s_pSharedData )
+ {
+ s_staticDeleter.setObject( s_pSharedData, new PMGLViewStatic );
+ s_pSharedData->m_display = display;
+
+ if( PMRenderManager::hasOpenGL( ) )
+ {
+ // get an appropriate visual
+ XVisualInfo* vi = glXChooseVisual( display, screen, glxAttributeList );
+ s_pSharedData->m_visualInfo = vi;
+
+ if( vi )
+ {
+ kdDebug( PMArea ) << "PMGLView: XVisual found\n";
+
+ // create a color map (from qgl_x11.cpp)
+ // check if we can use the global colormap
+ // should be the default ?
+ if( vi->visualid ==
+ XVisualIDFromVisual( ( Visual* ) QPaintDevice::x11AppVisual( ) ) )
+ {
+ kdDebug( PMArea ) << "PMGLView: Default colormap used\n";
+ s_pSharedData->m_colormap = QPaintDevice::x11AppColormap();
+ s_pSharedData->m_colormapAllocated = false;
+ }
+
+ if( !s_pSharedData->m_colormap )
+ {
+ const char* v = glXQueryServerString( display, vi->screen,
+ GLX_VERSION );
+ bool mesa_gl = false;
+ if( v )
+ mesa_gl = strstr( v, "Mesa" ) != 0;
+ if( mesa_gl )
+ {
+ XStandardColormap* c;
+ int n;
+ Atom hp_cmaps = XInternAtom( display, "_HP_RGB_SMOOTH_MAP_LIST",
+ TRUE );
+
+ if( hp_cmaps && ( vi->visual->c_class == TrueColor )
+ && ( vi->depth == 8 ) )
+ {
+ if( XGetRGBColormaps( display, RootWindow( display,vi->screen ),
+ &c, &n, hp_cmaps ) )
+ {
+ i = 0;
+ while( ( i < n ) && ( s_pSharedData->m_colormap == 0 ) )
+ {
+ if( c[i].visualid == vi->visual->visualid )
+ {
+ s_pSharedData->m_colormap = c[i].colormap;
+ kdDebug( PMArea ) << "PMGLView: HP_RGB scmap used\n";
+ }
+ i++;
+ }
+ XFree( ( char* ) c );
+ }
+ }
+ }
+ }
+
+#if !defined(Q_OS_SOLARIS)
+ if( !s_pSharedData->m_colormap )
+ {
+ XStandardColormap* c;
+ int n;
+
+ if( XmuLookupStandardColormap( display, vi->screen, vi->visualid,
+ vi->depth, XA_RGB_DEFAULT_MAP,
+ FALSE, TRUE ) )
+ {
+ if( XGetRGBColormaps( display, RootWindow( display, vi->screen ),
+ &c, &n, XA_RGB_DEFAULT_MAP ) )
+ {
+ i = 0;
+ while( ( i < n ) && ( s_pSharedData->m_colormap == 0 ) )
+ {
+ if( c[i].visualid == vi->visualid )
+ {
+ s_pSharedData->m_colormap = c[i].colormap;
+ kdDebug( PMArea ) << "PMGLView: RGB_DEFAULT scmap used\n";
+ }
+ i++;
+ }
+ XFree( ( char* ) c );
+ }
+ }
+ }
+#endif
+
+ if( !s_pSharedData->m_colormap )
+ {
+ // create a new colormap otherwise
+ kdDebug( PMArea ) << "PMGLView: New colormap created\n";
+ s_pSharedData->m_colormap =
+ XCreateColormap( display,
+ RootWindow( display, vi->screen ),
+ vi->visual, AllocNone );
+ s_pSharedData->m_colormapAllocated = true;
+ }
+
+ // create the context
+ // this context is shared between all gl views!
+ s_pSharedData->m_context = glXCreateContext( display, vi, 0, s_bDirect );
+
+ if( s_pSharedData->m_context != NULL )
+ kdDebug( PMArea ) << "PMGLView: glx context created\n";
+
+ }
+ }
+ }
+
+ if( s_pSharedData->m_context != NULL )
+ {
+ XVisualInfo* vi = s_pSharedData->m_visualInfo;
+
+ // create the window
+ XSetWindowAttributes swa;
+ swa.colormap = s_pSharedData->m_colormap;
+ swa.border_pixel = 0;
+ swa.background_pixel = 0;
+
+ Window p;
+ p = RootWindow( display, vi->screen );
+ QWidget* pw = parentWidget( );
+ if( pw )
+ p = pw->winId( );
+
+ Window w = XCreateWindow( display, p, x( ), y( ), width( ),
+ height( ), 0, vi->depth, InputOutput,
+ vi->visual,
+ CWColormap | CWBorderPixel | CWBackPixel,
+ &swa );
+
+ // tell the windowmanager to use the colormap
+ Window* colorMapWindows = 0;
+ Window* newWindows = 0;
+ int num;
+ if( XGetWMColormapWindows( display, topLevelWidget( )->winId( ),
+ &colorMapWindows, &num ) )
+ {
+ // create a new list and append the new window
+ bool replaced = false;
+ newWindows = new Window[num+1];
+
+ for( i = 0; i < num; i++ )
+ {
+ newWindows[i] = colorMapWindows[i];
+ if( newWindows[i] == winId( ) ) // old window
+ {
+ newWindows[i] = w;
+ replaced = true;
+ }
+ }
+ if( !replaced )
+ {
+ newWindows[num] = w;
+ num++;
+ }
+ }
+ else
+ {
+ num = 1;
+ newWindows = new Window[1];
+ newWindows[0] = w;
+ }
+ // tell Qt to use this window
+ create( w );
+
+ XSetWMColormapWindows( display, topLevelWidget( )->winId( ),
+ newWindows, num );
+ delete[] newWindows;
+
+ XFlush( x11Display( ) );
+ }
+ else
+ {
+ QVBoxLayout* topLayout = new QVBoxLayout( this );
+ QLabel* label = new QLabel( i18n( "No OpenGL support" ), this );
+ label->setAlignment( Qt::AlignCenter );
+ topLayout->addWidget( label );
+ }
+
+ //setProjection( );
+}
+
+PMGLView::~PMGLView( )
+{
+ PMRenderManager* rm = PMRenderManager::theManager( );
+ rm->removeView( this );
+ rm->viewDeleted( );
+ emit destroyed( this );
+}
+
+bool PMGLView::isValid( ) const
+{
+ if( s_pSharedData && ( s_pSharedData->m_context != NULL ) )
+ return true;
+ return false;
+}
+
+void PMGLView::makeCurrent( )
+{
+ if( isValid( ) )
+ glXMakeCurrent( x11Display( ), winId( ), s_pSharedData->m_context );
+}
+
+void PMGLView::swapBuffers( )
+{
+ if( isValid( ) )
+ glXSwapBuffers( x11Display( ), winId( ) );
+}
+
+void PMGLView::setScale( double scale )
+{
+ if( m_dScale > 0 )
+ {
+ m_dScale = scale;
+ invalidateProjection( );
+ }
+ else
+ kdError( PMArea ) << "Scale <= 0 in PMGLView::setScale\n";
+}
+
+void PMGLView::setTranslationX( double d )
+{
+ m_dTransX = d;
+ invalidateProjection( );
+}
+
+void PMGLView::setTranslationY( double d )
+{
+ m_dTransY = d;
+ invalidateProjection( );
+}
+
+void PMGLView::resizeEvent( QResizeEvent* )
+{
+ invalidateProjection( );
+}
+
+void PMGLView::paintEvent( QPaintEvent* )
+{
+ repaint( );
+}
+
+void PMGLView::invalidateProjection( bool graphicalChange /*= true*/ )
+{
+ m_viewTransformation = PMMatrix::identity( );
+
+
+ if( m_type != PMViewCamera )
+ {
+ m_viewTransformation = m_viewTransformation * PMMatrix::scale( m_dScale, m_dScale, m_dScale );
+ m_viewTransformation = m_viewTransformation * PMMatrix::translation( m_dTransX, m_dTransY, 0 );
+
+ switch( m_type )
+ {
+ case PMViewPosZ:
+ m_normal = PMVector( 0.0, 0.0, 1.0 );
+ break;
+ case PMViewNegZ:
+ m_viewTransformation = m_viewTransformation * PMMatrix::rotation( 0.0, M_PI, 0.0 );
+ m_normal = PMVector( 0.0, 0.0, -1.0 );
+ break;
+ case PMViewNegY:
+ m_viewTransformation = m_viewTransformation * PMMatrix::rotation( M_PI_2, 0.0, 0.0 );
+ m_normal = PMVector( 0.0, -1.0, 0.0 );
+ break;
+ case PMViewPosY:
+ m_normal = PMVector( 0.0, 1.0, 0.0 );
+ m_viewTransformation = m_viewTransformation * PMMatrix::rotation( -M_PI_2, 0.0, 0.0 );
+ break;
+ case PMViewPosX:
+ m_viewTransformation = m_viewTransformation * PMMatrix::rotation( 0.0, M_PI_2, 0.0 );
+ m_normal = PMVector( 1.0, 0.0, 0.0 );
+ break;
+ case PMViewNegX:
+ m_viewTransformation = m_viewTransformation * PMMatrix::rotation( 0.0, -M_PI_2, 0.0 );
+ m_normal = PMVector( -1.0, 0.0, 0.0 );
+ break;
+ default:
+ break;
+ }
+
+ m_viewTransformation = m_viewTransformation * PMMatrix::scale( 1.0, 1.0, -1.0 );
+
+ if( m_controlPoints.count( ) > 0 )
+ recalculateTransformations( );
+ recalculateControlPointPosition( );
+ }
+ m_projectionUpToDate = false;
+ repaint( graphicalChange );
+}
+
+void PMGLView::enableTranslateMode( bool yes )
+{
+ if( m_type != PMViewCamera )
+ {
+ m_bScaleMode = false;
+ m_bTranslateMode = yes;
+ setCursor( yes ? crossCursor : arrowCursor );
+ }
+}
+
+void PMGLView::enableScaleMode( bool yes )
+{
+ if( m_type != PMViewCamera )
+ {
+ m_bScaleMode = yes;
+ m_bTranslateMode = false;
+ setCursor( yes ? crossCursor : arrowCursor );
+ }
+}
+
+void PMGLView::mousePressEvent( QMouseEvent* e )
+{
+ if( m_bScaleMode || m_bTranslateMode )
+ {
+ if( ( e->button( ) & LeftButton ) && ( e->state( ) == 0 ) )
+ {
+ m_bMousePressed = true;
+ m_mousePos = e->pos( );
+ m_scaleIntX = screenToInternalX( e->x( ) );
+ m_scaleIntY = screenToInternalY( e->y( ) );
+ }
+ }
+ else if( m_type != PMViewCamera )
+ {
+ if( ( e->button( ) & LeftButton ) && m_bInverseValid
+ && m_pActiveObject )
+ {
+ if( m_pUnderMouse )
+ {
+ // check the control point selection
+ if( m_pActiveObject->multipleSelectControlPoints( ) )
+ {
+ if( m_pUnderMouse->selected( ) )
+ {
+ if( e->state( ) & ControlButton )
+ m_bDeselectUnderMouse = true;
+ else
+ m_bSelectUnderMouse = true;
+ }
+ else
+ {
+ if( e->state( ) & ControlButton )
+ selectControlPoint( m_pUnderMouse,
+ !m_pUnderMouse->selected( ), false );
+ else
+ selectControlPoint( m_pUnderMouse, true );
+ }
+ }
+ else
+ selectControlPoint( m_pUnderMouse, true );
+
+ // start the graphical change
+ if( !m_bGraphicalChangeMode )
+ {
+ m_bGraphicalChangeMode = true;
+ m_bMementoCreated = false;
+ m_changeStartPos = e->pos( );
+ m_changeStartTime = QTime::currentTime( );
+ m_currentMousePos = m_changeStartPos;
+ m_startTimer.start( c_mouseChangeDelayMs, true );
+ }
+ }
+ else
+ {
+ if( m_pActiveObject->multipleSelectControlPoints( ) )
+ {
+ // multiple selection mode
+ // start only when the view is rendered
+ if( !PMRenderManager::theManager( )->containsTask( this ) )
+ {
+ m_bMultipleSelectionMode = true;
+ m_bSelectionStarted = false;
+ m_selectionStart = e->pos( );
+ m_selectionEnd = m_selectionStart;
+ }
+ }
+ else
+ selectControlPoint( 0, false );
+ }
+ }
+ }
+
+
+ if( !( m_bGraphicalChangeMode || m_bMousePressed ) )
+ {
+ if( ( e->button( ) == RightButton ) && ( e->state( ) == 0 ) )
+ {
+ m_contextClickPosition = PMVector( screenToInternalX( e->x( ) ),
+ screenToInternalY( e->y( ) ) );
+
+ if( m_pUnderMouse )
+ {
+ // check the control point selection
+ if( m_pActiveObject->multipleSelectControlPoints( ) )
+ {
+ if( !m_pUnderMouse->selected( ) )
+ selectControlPoint( m_pUnderMouse, true );
+ }
+ else
+ selectControlPoint( m_pUnderMouse, true );
+ }
+
+ contextMenu( );
+ }
+ }
+
+ if( e->button( ) == MidButton )
+ {
+ m_bMidMousePressed = true;
+ m_mousePos = e->pos( );
+ }
+}
+
+void PMGLView::mouseReleaseEvent( QMouseEvent* e )
+{
+ m_bMousePressed = false;
+ if( m_bGraphicalChangeMode )
+ {
+ m_startTimer.stop( );
+
+ if( m_bMementoCreated )
+ {
+ PMDataChangeCommand* cmd;
+ cmd = new PMDataChangeCommand( m_pActiveObject->takeMemento( ) );
+ m_pPart->executeCommand( cmd );
+
+ checkUnderMouse( ( int ) screenToInternalX( e->x( ) ),
+ ( int ) screenToInternalY( e->y( ) ) );
+ }
+ else
+ {
+ if( m_pUnderMouse )
+ {
+ if( m_bSelectUnderMouse )
+ selectControlPoint( m_pUnderMouse, true );
+ else if( m_bDeselectUnderMouse )
+ selectControlPoint( m_pUnderMouse, false, false );
+ }
+ }
+ m_bGraphicalChangeMode = false;
+ }
+ else if( m_bMultipleSelectionMode )
+ {
+ if( m_bSelectionStarted )
+ {
+ int sx, sy, ex, ey, w, h;
+ double isx, isy, iex, iey;
+ QPtrListIterator<PMVector> pit( m_controlPointsPosition );
+ PMControlPointListIterator cit( m_controlPoints );
+ PMVector p;
+
+ calculateSelectionBox( sx, sy, ex, ey, w, h );
+ isx = screenToInternalX( sx );
+ iex = screenToInternalX( ex );
+ isy = screenToInternalY( ey );
+ iey = screenToInternalY( sy );
+ restoreSelectionBox( );
+
+ while( pit.current( ) && cit.current( ) )
+ {
+ p = *( pit.current( ) );
+
+ if( ( isx <= p[0] ) && ( iex >= p[0] )
+ && ( isy <= p[1] ) && ( iey >= p[1] ) )
+ selectControlPoint( cit.current( ), true, false );
+ else if( !( e->state( ) & ControlButton ) )
+ selectControlPoint( cit.current( ), false, false );
+
+ ++cit;
+ ++pit;
+ }
+ }
+ else
+ selectControlPoint( 0, false );
+
+ m_bMultipleSelectionMode = false;
+ }
+
+ if( m_bAutoScroll )
+ {
+ m_bAutoScroll = false;
+ m_autoScrollTimer.stop( );
+ }
+
+ if( e->button( ) & QEvent::MidButton )
+ m_bMidMousePressed = false;
+
+ m_bSelectUnderMouse = false;
+ m_bDeselectUnderMouse = false;
+}
+
+void PMGLView::mouseMoveEvent( QMouseEvent* e )
+{
+ if( m_bMousePressed )
+ {
+ if( m_bScaleMode )
+ {
+ int d = e->x( ) - m_mousePos.x( );
+ if( d != 0 )
+ {
+ double s = exp( d * c_sizeFactor );
+ double c = 1.0 / ( m_dScale * s ) - 1.0 / m_dScale;
+ m_dTransX += m_scaleIntX * c;
+ m_dTransY += m_scaleIntY * c;
+ m_dScale *= s;
+ invalidateProjection( );
+ }
+ }
+ else if( m_bTranslateMode )
+ {
+ m_dTransX += ( e->x( ) - m_mousePos.x( ) ) / m_dScale;
+ m_dTransY -= ( e->y( ) - m_mousePos.y( ) ) / m_dScale;
+ invalidateProjection( );
+ }
+ m_mousePos = e->pos( );
+ }
+ else if( m_bMidMousePressed )
+ {
+ m_dTransX += ( e->x( ) - m_mousePos.x( ) ) / m_dScale;
+ m_dTransY -= ( e->y( ) - m_mousePos.y( ) ) / m_dScale;
+ invalidateProjection( );
+
+ m_mousePos = e->pos( );
+ }
+ else if( m_bGraphicalChangeMode )
+ {
+ m_currentMousePos = e->pos( );
+ if( !m_bMementoCreated )
+ {
+ QPoint movement = e->pos( ) - m_changeStartPos;
+ if( ( m_changeStartTime.msecsTo( QTime::currentTime( ) ) > c_mouseChangeDelayMs )
+ || ( movement.manhattanLength( ) > c_mouseChangeDelayPixel ) )
+ {
+ m_startTimer.stop( );
+ startChange( m_changeStartPos );
+ }
+ }
+
+ if( m_bMementoCreated )
+ graphicalChange( e->pos( ) );
+ }
+ else if( m_bMultipleSelectionMode )
+ {
+ if( !m_bSelectionStarted )
+ {
+ m_selectionEnd = e->pos( );
+ startSelection( );
+ }
+ else
+ {
+ restoreSelectionBox( );
+ m_selectionEnd = e->pos( );
+ saveSelectionBox( );
+ paintSelectionBox( );
+ }
+ }
+ else if( !( m_bScaleMode || m_bTranslateMode ) )
+ {
+ checkUnderMouse( ( int ) screenToInternalX( e->x( ) ),
+ ( int ) screenToInternalY( e->y( ) ) );
+ }
+
+ if( m_bMultipleSelectionMode || m_bGraphicalChangeMode )
+ {
+ bool as = m_bAutoScroll;
+
+ if( e->x( ) < 0 )
+ m_autoScrollDirectionX = 1;
+ else if( e->x( ) >= width( ) )
+ m_autoScrollDirectionX = -1;
+ else
+ m_autoScrollDirectionX = 0;
+
+ if( e->y( ) < 0 )
+ m_autoScrollDirectionY = 1;
+ else if( e->y( ) >= height( ) )
+ m_autoScrollDirectionY = -1;
+ else
+ m_autoScrollDirectionY = 0;
+
+ if( ( m_autoScrollDirectionX != 0 ) || ( m_autoScrollDirectionY != 0 ) )
+ m_bAutoScroll = true;
+ else
+ m_bAutoScroll = false;
+
+ if( m_bAutoScroll && !as )
+ {
+ m_lastAutoScrollUpdate = QTime::currentTime( );
+ m_autoScrollTimer.start( c_minAutoScrollUpdateTime, true );
+ }
+ if( !m_bAutoScroll && as )
+ m_autoScrollTimer.stop( );
+ }
+}
+
+void PMGLView::wheelEvent( QWheelEvent* e )
+{
+ if( m_type != PMViewCamera )
+ {
+ double s = exp( e->delta( ) / 4 * c_sizeFactor );
+ double deltaX = screenToInternalX( e->x( ) );
+ double deltaY = screenToInternalY( e->y( ) );
+ double c = 1.0 / ( m_dScale * s ) - 1.0 / m_dScale;
+ m_dTransX += deltaX * c;
+ m_dTransY += deltaY * c;
+ m_dScale *= s;
+ invalidateProjection( );
+ }
+}
+
+void PMGLView::keyPressEvent( QKeyEvent* e )
+{
+ bool accept = true;
+
+ if( e->state( ) == 0 )
+ {
+ if( m_type != PMViewCamera )
+ {
+ if( m_dScale > 0 )
+ {
+ switch( e->key( ) )
+ {
+ case Key_Left:
+ m_dTransX -= keyMoveSpeed / m_dScale;
+ break;
+ case Key_Right:
+ m_dTransX += keyMoveSpeed / m_dScale;
+ break;
+ case Key_Up:
+ m_dTransY += keyMoveSpeed / m_dScale;
+ break;
+ case Key_Down:
+ m_dTransY -= keyMoveSpeed / m_dScale;
+ break;
+ default:
+ accept = false;
+ }
+ }
+ else
+ kdError( PMArea ) << "scale <= 0 in PMGLView::keyPressEvent\n";
+ }
+ }
+ else if( e->state( ) == ControlButton )
+ {
+ if( m_type != PMViewCamera )
+ {
+ switch( e->key( ) )
+ {
+ case Key_Left:
+ case Key_Down:
+ m_dScale /= keyScaleFactor;
+ break;
+ case Key_Right:
+ case Key_Up:
+ m_dScale *= keyScaleFactor;
+ break;
+ default:
+ accept = false;
+ }
+ }
+ }
+ else
+ accept = false;
+
+ if( accept )
+ invalidateProjection( );
+ else
+ e->ignore( );
+}
+
+void PMGLView::slotAutoScroll( )
+{
+ if( m_bAutoScroll )
+ {
+ QTime now = QTime::currentTime( );
+ int msecs = m_lastAutoScrollUpdate.msecsTo( now );
+ int pixels = ( int ) ( m_autoScrollSpeed * msecs / 1000.0 );
+
+ if( pixels < 1 )
+ pixels = 1;
+ if( pixels > ( width( ) * 3 / 4 ) )
+ pixels = width( ) * 3 / 4;
+ if( pixels > ( height( ) * 3 / 4 ) )
+ pixels = height( ) * 3 / 4;
+
+ if( m_bGraphicalChangeMode && !m_bMementoCreated )
+ startChange( m_changeStartPos );
+ if( m_bMultipleSelectionMode )
+ restoreSelectionBox( );
+
+ m_dTransX += pixels * m_autoScrollDirectionX / m_dScale;
+ m_dTransY -= pixels * m_autoScrollDirectionY / m_dScale;
+ invalidateProjection( );
+
+ if( m_bGraphicalChangeMode )
+ if( m_bMultipleSelectionMode )
+ {
+ m_selectionStart += QPoint( pixels * m_autoScrollDirectionX,
+ pixels * m_autoScrollDirectionY );
+
+ saveSelectionBox( );
+ paintSelectionBox( );
+ }
+
+ if( m_bGraphicalChangeMode )
+ graphicalChange( mapFromGlobal( QCursor::pos( ) ) );
+ else
+ repaint( );
+
+ m_lastAutoScrollUpdate = now;
+ }
+}
+
+void PMGLView::slotMouseChangeTimer( )
+{
+ if( !m_bMementoCreated )
+ {
+ if( m_currentMousePos != m_changeStartPos )
+ {
+ startChange( m_changeStartPos );
+ graphicalChange( m_currentMousePos );
+ }
+ }
+}
+
+void PMGLView::startChange( const QPoint& mousePos )
+{
+ m_pActiveObject->createMemento( );
+ m_bMementoCreated = true;
+
+ PMVector p = mousePosition( m_pUnderMouse, mousePos.x( ), mousePos.y( ) );
+ p.transform( m_inversePointsTransformation );
+
+ if( m_pActiveObject->multipleSelectControlPoints( ) )
+ {
+ PMControlPointListIterator it( m_controlPoints );
+ for( ; it.current( ); ++it )
+ if( it.current( )->selected( ) )
+ it.current( )->startChange( p, m_normal );
+ }
+ else
+ m_pUnderMouse->startChange( p, m_normal );
+}
+
+void PMGLView::graphicalChange( const QPoint& mousePos )
+{
+ PMVector p = mousePosition( m_pUnderMouse, mousePos.x( ), mousePos.y( ) );
+ p.transform( m_inversePointsTransformation );
+ if( m_pActiveObject->multipleSelectControlPoints( ) )
+ {
+ PMControlPointListIterator it( m_controlPoints );
+ for( ; it.current( ); ++it )
+ if( it.current( )->selected( ) )
+ it.current( )->change( p );
+ }
+ else
+ m_pUnderMouse->change( p );
+
+ PMObjectList changedObjects;
+ m_pActiveObject->controlPointsChangedList( m_controlPoints, changedObjects );
+
+ if( changedObjects.isEmpty( ) )
+ emit objectChanged( m_pActiveObject, PMCGraphicalChange, this );
+ else
+ {
+ PMObjectListIterator it( changedObjects );
+ for( ; it.current( ); ++it )
+ emit objectChanged( it.current( ), PMCGraphicalChange, this );
+ }
+}
+
+void PMGLView::checkUnderMouse( int x, int y )
+{
+ // is cursor over a control point?
+ // double z;
+ PMVector* v;
+ PMControlPoint* p;
+ PMControlPoint* old = m_pUnderMouse;
+
+ if( m_bInverseValid && ( m_type != PMViewCamera ) )
+ {
+ m_pUnderMouse = 0;
+// z = -1e10;
+
+ v = m_controlPointsPosition.first( );
+ p = m_controlPoints.first( );
+
+ while( p )
+ {
+ if( p->displayType( ) == PMControlPoint::CPCross )
+ {
+ if( !m_pUnderMouse )
+ m_pUnderMouse = p;
+ }
+ else
+ {
+ if( ( fabs( x - (*v)[0] ) < ( controlPointSize / 2.0 + 0.1 ) )
+ && ( fabs( y - (*v)[1] ) < ( controlPointSize / 2.0 + 0.1 ) ) )
+ {
+ if( m_pUnderMouse )
+ {
+ if( p->selected( ) && !m_pUnderMouse->selected( ) )
+ m_pUnderMouse = p;
+ }
+ else
+ m_pUnderMouse = p;
+ }
+ }
+
+ p = m_controlPoints.next( );
+ v = m_controlPointsPosition.next( );
+ }
+ }
+ else
+ m_pUnderMouse = 0;
+
+ setCursor( m_pUnderMouse ? crossCursor : arrowCursor );
+ if( m_pUnderMouse != old )
+ {
+ if( m_pUnderMouse )
+ emit controlPointMessage( m_pUnderMouse->description( ) );
+ else
+ emit controlPointMessage( "" );
+ }
+}
+
+void PMGLView::updateControlPoints( )
+{
+ m_controlPoints.clear( );
+ m_controlPoints = m_pPart->activeControlPoints( );
+
+ if( ( m_controlPoints.count( ) > 0 ) && m_pActiveObject )
+ {
+ m_objectsTransformation = m_pActiveObject->transformedWith( );
+ recalculateTransformations( );
+ }
+
+ if( m_bGraphicalChangeMode )
+ m_bGraphicalChangeMode = false;
+
+ recalculateControlPointPosition( );
+}
+
+void PMGLView::recalculateControlPointPosition( )
+{
+ PMControlPointListIterator it( m_controlPoints );
+ m_controlPointsPosition.clear( );
+ PMVector* v;
+
+ for( ; it.current( ); ++it )
+ {
+ v = new PMVector( m_controlPointsTransformation * it.current( )->position( ) );
+ m_controlPointsPosition.append( v );
+ }
+ if( !m_bGraphicalChangeMode )
+ {
+ m_pUnderMouse = 0;
+ emit controlPointMessage( "" );
+ }
+}
+
+PMVector PMGLView::mousePosition( PMControlPoint* cp, int x, int y )
+{
+ PMVector result;
+ int index;
+ PMVector* p;
+
+ result[0] = screenToInternalX( x );
+ result[1] = screenToInternalY( y );
+ if( cp )
+ {
+ index = m_controlPoints.findRef( cp );
+ if( index >= 0 )
+ {
+ p = m_controlPointsPosition.at( ( uint ) index );
+ if( p )
+ result[2] = p->z( );
+ }
+ }
+ return result;
+}
+
+void PMGLView::recalculateTransformations( )
+{
+ int r, c;
+
+ m_controlPointsTransformation = m_viewTransformation * m_objectsTransformation;
+
+ if( m_controlPointsTransformation.canBuildInverse( ) )
+ {
+ m_inversePointsTransformation = m_controlPointsTransformation.inverse( );
+
+ for( c = 0; c < 4; c++ )
+ for( r = 0; r < 4; r++ )
+ if( fabs( m_inversePointsTransformation[c][r] ) < 1e-8 )
+ m_inversePointsTransformation[c][r] = 0.0;
+
+ m_bInverseValid = true;
+ }
+ else
+ m_bInverseValid = false;
+}
+
+void PMGLView::setType( PMViewType t )
+{
+ if( m_type != t )
+ m_viewTransformation = PMMatrix::identity( );
+ m_type = t;
+ invalidateProjection( );
+
+ emit viewTypeChanged( viewTypeAsString( t ) );
+}
+
+void PMGLView::setCamera( PMCamera* c )
+{
+ m_pCamera = c;
+ invalidateProjection( );
+}
+
+void PMGLView::slotRefresh( )
+{
+ if( m_type == PMViewCamera )
+ if( !m_pCamera )
+ setCamera( m_pPart->firstCamera( ) );
+
+ repaint( );
+}
+
+void PMGLView::slotClear( )
+{
+ m_controlPointsPosition.clear( );
+ m_controlPoints.clear( );
+ m_pUnderMouse = 0;
+ m_pCamera = 0;
+ m_pActiveObject = 0;
+
+ slotStopRendering( );
+}
+
+void PMGLView::slotActiveRenderModeChanged( )
+{
+ if( ( m_type == PMViewCamera ) && m_pCamera )
+ invalidateProjection( );
+}
+
+void PMGLView::slotStopRendering( )
+{
+ PMRenderManager* rm = PMRenderManager::theManager( );
+ rm->removeView( this );
+}
+
+void PMGLView::slotObjectChanged( PMObject* obj, const int mode,
+ QObject* sender )
+{
+ bool redraw = false;
+
+ if( mode & PMCNewSelection )
+ {
+ if( obj )
+ {
+ if( obj != m_pActiveObject )
+ {
+ m_pActiveObject = obj;
+ redraw = true;
+ }
+ }
+ else
+ {
+ m_pActiveObject = 0;
+ redraw = true;
+ }
+ }
+ if( mode & ( PMCSelected | PMCDeselected ) )
+ {
+ m_pActiveObject = 0;
+ redraw = true;
+ }
+ if( mode & ( PMCViewStructure | PMCGraphicalChange ) )
+ {
+ if( m_type == PMGLView::PMViewCamera )
+ {
+ if( obj->type( ) == "Camera" )
+ if( m_pCamera == ( PMCamera* ) obj )
+ invalidateProjection( );
+
+ if( obj->parent( ) )
+ if( obj->parent( )->type( ) == "Camera" )
+ if( m_pCamera == ( PMCamera* ) obj->parent( ) )
+ if( obj->hasTransformationMatrix( ) )
+ invalidateProjection( );
+ }
+
+ redraw = true;
+ }
+ if( mode & PMCNewControlPoints )
+ {
+ updateControlPoints( );
+ m_pActiveObject = m_pPart->activeObject( );
+ redraw = true;
+ }
+ if( mode & PMCControlPointSelection )
+ {
+ redraw = true;
+ }
+ if( mode & PMCDescription )
+ {
+ if( m_type == PMGLView::PMViewCamera && obj && obj == m_pCamera )
+ redraw = true;
+ }
+ if( mode & PMCAdd )
+ {
+ if( m_type == PMGLView::PMViewCamera )
+ {
+ if( obj->type( ) == "Camera" )
+ if( !m_pCamera )
+ setCamera( ( PMCamera* ) obj );
+ if( obj->parent( ) )
+ if( obj->parent( )->type( ) == "Camera" )
+ if( m_pCamera == ( PMCamera* ) obj->parent( ) )
+ if( obj->hasTransformationMatrix( ) )
+ invalidateProjection( );
+ }
+ redraw = true;
+ }
+
+ if( mode & PMCRemove )
+ {
+ if( obj->type( ) == "Camera" )
+ if( m_pCamera == ( PMCamera* ) obj )
+ setCamera( 0 );
+
+ if( m_type == PMGLView::PMViewCamera )
+ if( obj->parent( ) )
+ if( obj->parent( )->type( ) == "Camera" )
+ if( m_pCamera == ( PMCamera* ) obj->parent( ) )
+ if( obj->hasTransformationMatrix( ) )
+ invalidateProjection( );
+
+ redraw = true;
+ }
+
+ if( mode & PMCChildren )
+ redraw = true;
+
+ if( redraw )
+ repaint( sender == this );
+}
+
+void PMGLView::repaint( bool graphicalChange )
+{
+ if( isValid( ) )
+ {
+ PMObject* obj = m_pActiveObject;
+
+ if( obj )
+ obj = topLevelRenderingObject( obj );
+ else
+ {
+ const PMObjectList& selected = m_pPart->selectedObjects( );
+ PMObjectListIterator it( selected );
+ if( it.current( ) )
+ obj = topLevelRenderingObject( it.current( ) );
+
+ if( obj && ( obj->type( ) != "Scene" ) )
+ for( ++it; it.current( ) && obj; ++it )
+ if( topLevelRenderingObject( it.current( ) ) != obj )
+ obj = 0;
+ }
+
+ if( !obj )
+ obj = m_pPart->scene( );
+
+ if( obj )
+ {
+ double aspectRatio = 1.0;
+ PMRenderMode* mode = m_pPart->scene( )->renderModes( )->current( );
+ if( mode )
+ if( mode->height( ) != 0 )
+ aspectRatio = ( double ) mode->width( )
+ / ( double ) mode->height( );
+
+ PMRenderManager* rm = PMRenderManager::theManager( );
+ rm->addView( this, m_pActiveObject, obj,
+ &m_controlPoints, aspectRatio,
+ m_pPart->scene( )->visibilityLevel( ), graphicalChange );
+ }
+ }
+}
+
+PMObject* PMGLView::topLevelRenderingObject( PMObject* o ) const
+{
+ PMObject* obj = o;
+ bool stop = false;
+
+ if( obj )
+ {
+ do
+ {
+ if( !obj )
+ stop = true;
+ else if( obj->isA( "Scene" ) || obj->isA( "Declare" ) )
+ stop = true;
+ else
+ obj = obj->parent( );
+ }
+ while( !stop );
+ }
+ else
+ obj = m_pPart->scene( );
+
+ return obj;
+}
+
+void PMGLView::selectControlPoint( PMControlPoint* cp, bool select, bool deselectOthers )
+{
+ bool selectionChanged = false;
+
+ if( cp )
+ {
+ if( deselectOthers )
+ {
+ PMControlPointListIterator it( m_controlPoints );
+ for( ; it.current( ); ++it )
+ {
+ bool s;
+ if( it.current( ) == cp )
+ s = select;
+ else
+ s = false;
+
+ if( s != it.current( )->selected( ) )
+ {
+ selectionChanged = true;
+ it.current( )->setSelected( s );
+ }
+ }
+ }
+ else
+ {
+ if( select != cp->selected( ) )
+ {
+ selectionChanged = true;
+ cp->setSelected( select );
+ }
+ }
+ }
+ else
+ {
+ PMControlPointListIterator it( m_controlPoints );
+ for( ; it.current( ); ++it )
+ {
+ if( select != it.current( )->selected( ) )
+ {
+ selectionChanged = true;
+ it.current( )->setSelected( select );
+ }
+ }
+ }
+
+ if( selectionChanged )
+ emit objectChanged( m_pActiveObject, PMCControlPointSelection, this );
+}
+
+void PMGLView::startSelection( )
+{
+ if( !m_bSelectionStarted )
+ {
+ saveSelectionBox( );
+ paintSelectionBox( );
+
+ m_bSelectionStarted = true;
+ }
+}
+
+void PMGLView::restoreSelectionBox( )
+{
+ if( !m_bAboutToUpdate )
+ {
+ int sx, sy, ex, ey, w, h;
+ calculateSelectionBox( sx, sy, ex, ey, w, h );
+
+ if( !m_selectionPixmap[0].isNull( ) )
+ bitBlt( this, sx, sy, &( m_selectionPixmap[0] ), 0, 0, w, 1, CopyROP );
+ if( !m_selectionPixmap[1].isNull( ) )
+ bitBlt( this, sx, ey, &( m_selectionPixmap[1] ), 0, 0, w, 1, CopyROP );
+ if( !m_selectionPixmap[2].isNull( ) )
+ bitBlt( this, sx, sy+1, &( m_selectionPixmap[2] ), 0, 0, 1, h-2, CopyROP );
+ if( !m_selectionPixmap[3].isNull( ) )
+ bitBlt( this, ex, sy+1, &( m_selectionPixmap[3] ), 0, 0, 1, h-2, CopyROP );
+ }
+}
+
+void PMGLView::saveSelectionBox( )
+{
+ if( !m_bAboutToUpdate )
+ {
+ int sx, sy, ex, ey, w, h;
+ calculateSelectionBox( sx, sy, ex, ey, w, h );
+
+ m_selectionPixmap[0].resize( w, 1 );
+ if( !m_selectionPixmap[0].isNull( ) )
+ bitBlt( &( m_selectionPixmap[0] ), 0, 0, this, sx, sy, w, 1, CopyROP );
+ m_selectionPixmap[1].resize( w, 1 );
+ if( !m_selectionPixmap[1].isNull( ) )
+ bitBlt( &( m_selectionPixmap[1] ), 0, 0, this, sx, ey, w, 1, CopyROP );
+
+ m_selectionPixmap[2].resize( 1, h-2 );
+ if( !m_selectionPixmap[2].isNull( ) )
+ bitBlt( &( m_selectionPixmap[2] ), 0, 0, this, sx, sy+1, 1, h-2, CopyROP );
+ m_selectionPixmap[3].resize( 1, h-2 );
+ if( !m_selectionPixmap[3].isNull( ) )
+ bitBlt( &( m_selectionPixmap[3] ), 0, 0, this, ex, sy+1, 1, h-2, CopyROP );
+ }
+}
+
+void PMGLView::paintSelectionBox( )
+{
+ if( !m_bAboutToUpdate )
+ {
+ int sx, sy, ex, ey, w, h;
+ calculateSelectionBox( sx, sy, ex, ey, w, h );
+ QPainter p;
+ p.begin( this );
+ p.setPen( PMRenderManager::theManager( )->controlPointColor( 1 ) );
+ p.drawRect( sx, sy, w, h );
+ p.end( );
+ }
+}
+
+void PMGLView::calculateSelectionBox( int& sx, int& sy, int& ex, int& ey,
+ int& w, int& h )
+{
+ if( m_selectionStart.x( ) < m_selectionEnd.x( ) )
+ {
+ sx = m_selectionStart.x( );
+ ex = m_selectionEnd.x( );
+ }
+ else
+ {
+ ex = m_selectionStart.x( );
+ sx = m_selectionEnd.x( );
+ }
+
+ if( m_selectionStart.y( ) < m_selectionEnd.y( ) )
+ {
+ sy = m_selectionStart.y( );
+ ey = m_selectionEnd.y( );
+ }
+ else
+ {
+ ey = m_selectionStart.y( );
+ sy = m_selectionEnd.y( );
+ }
+
+ w = ex - sx + 1;
+ h = ey - sy + 1;
+}
+
+double PMGLView::screenToInternalX( int x ) const
+{
+ return rint( x - width( ) / 2.0 + 0.1 );
+}
+
+double PMGLView::screenToInternalY( int y ) const
+{
+ return rint( height( ) / 2.0 - y - 0.1 );
+}
+
+void PMGLView::slotRenderingStarted( PMGLView* )
+{
+}
+
+void PMGLView::slotAboutToUpdate( PMGLView* view )
+{
+ if( view == this )
+ m_bAboutToUpdate = true;
+}
+
+void PMGLView::slotRenderingFinished( PMGLView* view )
+{
+ if( view == this )
+ {
+ m_bAboutToUpdate = false;
+ if( m_bMultipleSelectionMode )
+ {
+ saveSelectionBox( );
+ paintSelectionBox( );
+ }
+
+ if( m_bAutoScroll )
+ {
+ QTime now = QTime::currentTime( );
+ int msecs = m_lastAutoScrollUpdate.msecsTo( now );
+
+ if( msecs < c_minAutoScrollUpdateTime )
+ m_autoScrollTimer.start( c_minAutoScrollUpdateTime - msecs, true );
+ else
+ m_autoScrollTimer.start( 0, true );
+ }
+ }
+}
+
+QString PMGLView::viewTypeAsString( PMViewType t )
+{
+ QString str;
+
+ switch( t )
+ {
+ case PMViewPosX:
+ str = i18n( "Left" );
+ break;
+ case PMViewNegX:
+ str = i18n( "Right" );
+ break;
+ case PMViewPosY:
+ str = i18n( "Bottom" );
+ break;
+ case PMViewNegY:
+ str = i18n( "Top" );
+ break;
+ case PMViewPosZ:
+ str = i18n( "Front" );
+ break;
+ case PMViewNegZ:
+ str = i18n( "Back" );
+ break;
+ case PMViewCamera:
+ str = i18n( "Camera" );
+ break;
+ }
+ return str;
+}
+
+void PMGLView::saveConfig( KConfig* /*cfg*/ )
+{
+}
+
+void PMGLView::restoreConfig( KConfig* /*cfg*/ )
+{
+}
+
+void PMGLView::contextMenu( )
+{
+ QPopupMenu* m = new QPopupMenu( );
+ m->insertItem( i18n( "Left View" ), this, SLOT( slotSetTypePosX( ) ) );
+ m->insertItem( i18n( "Right View" ), this, SLOT( slotSetTypeNegX( ) ) );
+ m->insertItem( i18n( "Top View" ), this, SLOT( slotSetTypeNegY( ) ) );
+ m->insertItem( i18n( "Bottom View" ), this, SLOT( slotSetTypePosY( ) ) );
+ m->insertItem( i18n( "Front View" ), this, SLOT( slotSetTypePosZ( ) ) );
+ m->insertItem( i18n( "Back View" ), this, SLOT( slotSetTypeNegZ( ) ) );
+
+ QPopupMenu* cm = new QPopupMenu( m );
+ QPtrListIterator<PMCamera> it = m_pPart->cameras( );
+ QString name;
+ if( !it.current( ) )
+ cm->insertItem( i18n( "No Cameras" ) );
+ else
+ {
+ int cnr = 0;
+ for( ; it.current( ); ++it, ++cnr )
+ {
+ name = it.current( )->name( );
+ if( name.isEmpty( ) )
+ name = i18n( "(unnamed)" );
+ cm->insertItem( name, cnr );
+ }
+ }
+ connect( cm, SIGNAL( activated( int ) ), SLOT( slotCameraView( int ) ) );
+
+ m->insertItem( SmallIconSet( "pmcamera" ), i18n( "Camera" ), cm );
+
+ m->insertSeparator( );
+
+ m->insertItem( i18n( "Snap to Grid" ), this, SLOT( slotSnapToGrid( ) ) );
+ m_objectActions.clear( );
+ if( m_pActiveObject )
+ {
+ m_pActiveObject->addObjectActions( m_controlPoints, m_objectActions );
+ if( !m_objectActions.isEmpty( ) )
+ {
+ PMObjectAction* oa = 0;
+ QPtrListIterator<PMObjectAction> ait( m_objectActions );
+
+ for( ; ait.current( ); ++ait )
+ {
+ oa = ait.current( );
+ oa->setMenuID( m->insertItem( oa->description( ) ) );
+ }
+ }
+ }
+ connect( m, SIGNAL( activated( int ) ), SLOT( slotObjectAction( int ) ) );
+
+ m->insertSeparator( );
+
+ QPopupMenu* menu = new QPopupMenu( m );
+ PMControlPointListIterator pit( m_controlPoints );
+
+ if( !pit.current( ) )
+ menu->insertItem( i18n( "No Control Points" ) );
+ else
+ {
+ int cnr = 0;
+ for( ; pit.current( ); ++pit, ++cnr )
+ menu->insertItem( pit.current( )->description( ), cnr );
+ }
+ connect( menu, SIGNAL( activated( int ) ), SLOT( slotControlPoint( int ) ) );
+
+ m->insertItem( i18n( "Control Points" ), menu );
+
+ m->exec( QCursor::pos( ) );
+ delete m;
+}
+
+void PMGLView::slotCameraView( int id )
+{
+ int i;
+ QPtrListIterator<PMCamera> it = m_pPart->cameras( );
+
+ for( i = 0; i < id; i++ )
+ ++it;
+ if( it.current( ) )
+ {
+ setCamera( it.current( ) );
+ setType( PMGLView::PMViewCamera );
+ }
+}
+
+void PMGLView::slotObjectAction( int id )
+{
+ QPtrListIterator<PMObjectAction> it( m_objectActions );
+ PMObjectAction* oa = 0;
+
+ for( ; it.current( ) && !oa; ++it )
+ if( it.current( )->menuID( ) == id )
+ oa = it.current( );
+
+ if( oa && m_pActiveObject )
+ {
+ // otherwise no object action was selected in the context menu
+
+ m_pActiveObject->createMemento( );
+ m_pActiveObject->objectActionCalled( oa, m_controlPoints,
+ m_controlPointsPosition,
+ m_contextClickPosition );
+ PMDataChangeCommand* cmd;
+ cmd = new PMDataChangeCommand( m_pActiveObject->takeMemento( ) );
+ cmd->setText( oa->description( ) );
+ m_pPart->executeCommand( cmd );
+ }
+}
+
+void PMGLView::slotControlPoint( int id )
+{
+ PMControlPoint* p = m_controlPoints.at( id );
+ if( p )
+ {
+ PMControlPointListIterator cit( m_controlPoints );
+ for( ; cit.current( ); ++cit )
+ cit.current( )->setSelected( p == cit.current( ) );
+ emit objectChanged( m_pActiveObject, PMCControlPointSelection, this );
+ }
+}
+
+void PMGLView::slotSnapToGrid( )
+{
+ if( m_pActiveObject )
+ {
+ if( !m_pActiveObject->mementoCreated( ) )
+ m_pActiveObject->createMemento( );
+
+ PMControlPointListIterator it( m_controlPoints );
+ for( ; it.current( ); ++it )
+ if( it.current( )->selected( ) )
+ it.current( )->snapToGrid( );
+
+ m_pActiveObject->controlPointsChanged( m_controlPoints );
+
+ PMDataChangeCommand* cmd;
+ cmd = new PMDataChangeCommand( m_pActiveObject->takeMemento( ) );
+ cmd->setText( i18n( "Snap to Grid" ) );
+ m_pPart->executeCommand( cmd );
+ }
+}
+
+QString PMGLView::description( ) const
+{
+ return viewTypeAsString( m_type );
+}
+
+void PMGLView::restoreViewConfig( PMViewOptions* vo )
+{
+ if( vo && vo->viewType( ) == "glview" )
+ {
+ PMGLViewOptions* o = ( PMGLViewOptions* ) vo;
+ m_type = o->glViewType( );
+ }
+}
+
+void PMGLView::saveViewConfig( PMViewOptions* vo ) const
+{
+ if( vo && vo->viewType( ) == "glview" )
+ {
+ PMGLViewOptions* o = ( PMGLViewOptions* ) vo;
+ o->setGLViewType( m_type );
+ }
+}
+
+void PMGLViewOptions::loadData( QDomElement& e )
+{
+ QString s = e.attribute( "type", "Camera" );
+ if( s == "Camera" ) m_glViewType = PMGLView::PMViewCamera;
+ else if( s == "X" ) m_glViewType = PMGLView::PMViewPosX;
+ else if( s == "Y" ) m_glViewType = PMGLView::PMViewPosY;
+ else if( s == "Z" ) m_glViewType = PMGLView::PMViewPosZ;
+ else if( s == "NegX" ) m_glViewType = PMGLView::PMViewNegX;
+ else if( s == "NegY" ) m_glViewType = PMGLView::PMViewNegY;
+ else if( s == "NegZ" ) m_glViewType = PMGLView::PMViewNegZ;
+}
+
+void PMGLViewOptions::saveData( QDomElement& e )
+{
+ switch( m_glViewType )
+ {
+ case PMGLView::PMViewCamera:
+ e.setAttribute( "type", "Camera" );
+ break;
+ case PMGLView::PMViewPosX:
+ e.setAttribute( "type", "X" );
+ break;
+ case PMGLView::PMViewPosY:
+ e.setAttribute( "type", "Y" );
+ break;
+ case PMGLView::PMViewPosZ:
+ e.setAttribute( "type", "Z" );
+ break;
+ case PMGLView::PMViewNegX:
+ e.setAttribute( "type", "NegX" );
+ break;
+ case PMGLView::PMViewNegY:
+ e.setAttribute( "type", "NegY" );
+ break;
+ case PMGLView::PMViewNegZ:
+ e.setAttribute( "type", "NegZ" );
+ break;
+ default:
+ kdError( PMArea ) << i18n( "Unknown GL view type." )
+ << endl;
+ break;
+ }
+}
+
+QString PMGLViewFactory::description( ) const
+{
+ return i18n( "3D View" );
+}
+
+QString PMGLViewFactory::description( PMViewOptions* vo ) const
+{
+ if( vo && vo->viewType( ) == "glview" )
+ {
+ PMGLViewOptions* o = ( PMGLViewOptions* ) vo;
+ return i18n( "3D View (%1)" ).arg(
+ PMGLView::viewTypeAsString( o->glViewType( ) ) );
+ }
+ return description( );
+}
+
+PMViewOptionsWidget* PMGLViewFactory::newOptionsWidget( QWidget* parent,
+ PMViewOptions* o )
+{
+ return new PMGLViewOptionsWidget( parent, o );
+}
+
+PMViewOptions* PMGLViewFactory::newOptionsInstance( ) const
+{
+ PMGLViewOptions* o = new PMGLViewOptions( );
+ return o;
+}
+
+PMGLViewOptionsWidget::PMGLViewOptionsWidget( QWidget* parent,
+ PMViewOptions* o )
+ : PMViewOptionsWidget( parent )
+{
+ m_pOptions = ( PMGLViewOptions* ) o;
+
+ QHBoxLayout* hl = new QHBoxLayout( this, 0, KDialog::spacingHint( ) );
+ QLabel* l = new QLabel( i18n( "3D view type:" ), this );
+ hl->addWidget( l );
+
+ m_pGLViewType = new QComboBox( false, this );
+ m_pGLViewType->insertItem( i18n( "Top" ) );
+ m_pGLViewType->insertItem( i18n( "Bottom" ) );
+ m_pGLViewType->insertItem( i18n( "Left" ) );
+ m_pGLViewType->insertItem( i18n( "Right" ) );
+ m_pGLViewType->insertItem( i18n( "Front" ) );
+ m_pGLViewType->insertItem( i18n( "Back" ) );
+ m_pGLViewType->insertItem( i18n( "Camera" ) );
+
+ switch( m_pOptions->glViewType( ) )
+ {
+ case PMGLView::PMViewNegY:
+ m_pGLViewType->setCurrentItem( 0 );
+ break;
+ case PMGLView::PMViewPosY:
+ m_pGLViewType->setCurrentItem( 1 );
+ break;
+ case PMGLView::PMViewPosX:
+ m_pGLViewType->setCurrentItem( 2 );
+ break;
+ case PMGLView::PMViewNegX:
+ m_pGLViewType->setCurrentItem( 3 );
+ break;
+ case PMGLView::PMViewPosZ:
+ m_pGLViewType->setCurrentItem( 4 );
+ break;
+ case PMGLView::PMViewNegZ:
+ m_pGLViewType->setCurrentItem( 5 );
+ break;
+ case PMGLView::PMViewCamera:
+ m_pGLViewType->setCurrentItem( 6 );
+ break;
+ }
+
+ connect( m_pGLViewType, SIGNAL( activated( int ) ),
+ SLOT( slotGLViewTypeChanged( int ) ) );
+ hl->addWidget( m_pGLViewType );
+}
+
+void PMGLViewOptionsWidget::slotGLViewTypeChanged( int index )
+{
+ switch( index )
+ {
+ case 0:
+ m_pOptions->setGLViewType( PMGLView::PMViewNegY );
+ break;
+ case 1:
+ m_pOptions->setGLViewType( PMGLView::PMViewPosY );
+ break;
+ case 2:
+ m_pOptions->setGLViewType( PMGLView::PMViewPosX );
+ break;
+ case 3:
+ m_pOptions->setGLViewType( PMGLView::PMViewNegX );
+ break;
+ case 4:
+ m_pOptions->setGLViewType( PMGLView::PMViewPosZ );
+ break;
+ case 5:
+ m_pOptions->setGLViewType( PMGLView::PMViewNegZ );
+ break;
+ case 6:
+ m_pOptions->setGLViewType( PMGLView::PMViewCamera );
+ break;
+ }
+ emit viewTypeDescriptionChanged( );
+}
+
+#include "pmglview.moc"
diff --git a/kpovmodeler/pmglview.h b/kpovmodeler/pmglview.h
new file mode 100644
index 00000000..b33eeb2b
--- /dev/null
+++ b/kpovmodeler/pmglview.h
@@ -0,0 +1,589 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMGLVIEW_H
+#define PMGLVIEW_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qwidget.h>
+#include <qpoint.h>
+#include <qdatetime.h>
+#include <qtimer.h>
+#include <qpixmap.h>
+
+#include "pmviewbase.h"
+#include "pmviewfactory.h"
+#include "pmcontrolpoint.h"
+#include "pmvector.h"
+#include "pmmatrix.h"
+#include "pmobjectaction.h"
+
+const int controlPointSize = 7;
+
+class PMObject;
+class PMPart;
+class PMCamera;
+class KConfig;
+class QComboBox;
+
+/**
+ * Widget for rendering the scene with OpenGL
+ */
+class PMGLView : public PMViewBase
+{
+ Q_OBJECT
+public:
+ /**
+ * Type of the view
+ */
+ enum PMViewType { PMViewPosX, PMViewNegX, PMViewPosY, PMViewNegY,
+ PMViewPosZ, PMViewNegZ, PMViewCamera };
+ /**
+ * Constructor
+ */
+ PMGLView( PMPart* part, PMViewType t,
+ QWidget* parent = 0, const char* name = 0, WFlags f = 0 );
+ /**
+ * Destructor
+ */
+ ~PMGLView( );
+
+ /** */
+ virtual QString viewType( ) const { return QString( "glview" ); }
+ /** */
+ virtual QString description( ) const;
+ /** */
+ virtual void restoreViewConfig( PMViewOptions* );
+ /** */
+ virtual void saveViewConfig( PMViewOptions* ) const;
+
+ /**
+ * Enables/disables translating the view with the mouse
+ */
+ void enableTranslateMode( bool yes = true );
+ /**
+ * Enables/disables scaling the view with the mouse
+ */
+ void enableScaleMode( bool yes = true );
+
+ /**
+ * Returns true if the opengl projection is up to date
+ */
+ bool isProjectionUpToDate( ) const { return m_projectionUpToDate; }
+ /**
+ * Sets the projection up to date flag
+ */
+ void setProjectionUpToDate( bool yes ) { m_projectionUpToDate = yes; }
+
+ /**
+ * Sets the scale
+ */
+ void setScale( double scale );
+ /**
+ * Returns the scale
+ */
+ double scale( ) const { return m_dScale; }
+ /**
+ * Sets the views translation in x direction
+ */
+ void setTranslationX( double d );
+ /**
+ * Returns the views translation in x direction
+ */
+ double translationX( ) const { return m_dTransX; }
+ /**
+ * Sets the views translation in y direction
+ */
+ void setTranslationY( double d );
+ /**
+ * Returns the views translation in y direction
+ */
+ double translationY( ) const { return m_dTransY; }
+
+ /**
+ * Returns the 2D control points position in the view
+ */
+ const QPtrList<PMVector>& controlPointsPosition( ) const
+ {
+ return m_controlPointsPosition;
+ }
+ /**
+ * Returns the last right mouse click position
+ */
+ PMVector contextClickPosition( ) const { return m_contextClickPosition; }
+
+ /**
+ * Returns the view type
+ */
+ PMViewType type( ) const { return m_type; }
+ /**
+ * Sets the view type
+ */
+ void setType( PMViewType t );
+ /**
+ * Sets the camera
+ */
+ void setCamera( PMCamera* c );
+ /**
+ * Returns the camera
+ */
+ PMCamera* camera( ) const { return m_pCamera; }
+
+ /**
+ * Saves the configuration
+ */
+ static void saveConfig( KConfig* cfg );
+ /**
+ * Restores the configuration
+ */
+ static void restoreConfig( KConfig* cfg );
+
+ /**
+ * Returns true if the glx stuff was initialized successfully
+ */
+ bool isValid( ) const;
+ /**
+ * Sets this view as the current rendering view
+ */
+ void makeCurrent( );
+ /**
+ * Swaps the opengl buffers
+ */
+ void swapBuffers( );
+
+ /**
+ * Returns the view type as string
+ */
+ static QString viewTypeAsString( PMViewType t );
+ /**
+ * Sets the direct rendering flag
+ */
+ static void enableDirectRendering( bool yes ) { s_bDirect = yes; }
+ /**
+ * Returns the direct rendering flag
+ */
+ static bool isDirectRenderingEnabled( ) { return s_bDirect; }
+public slots:
+ /**
+ * Sets the view normal vector to the positive x-axes
+ */
+ void slotSetTypePosX( ) { setType( PMViewPosX ); }
+ /**
+ * Sets the view normal vector to the negative x-axes
+ */
+ void slotSetTypeNegX( ) { setType( PMViewNegX ); }
+ /**
+ * Sets the view normal vector to the positive y-axes
+ */
+ void slotSetTypePosY( ) { setType( PMViewPosY ); }
+ /**
+ * Sets the view normal vector to the negative y-axes
+ */
+ void slotSetTypeNegY( ) { setType( PMViewNegY ); }
+ /**
+ * Sets the view normal vector to the positive z-axes
+ */
+ void slotSetTypePosZ( ) { setType( PMViewPosZ ); }
+ /**
+ * Sets the view normal vector to the negative z-axes
+ */
+ void slotSetTypeNegZ( ) { setType( PMViewNegZ ); }
+
+ /**
+ * Called when an object is changed.
+ * @see PMPart::objectChanged( )
+ */
+ void slotObjectChanged( PMObject* obj, const int mode, QObject* sender );
+ /**
+ * Restarts rendering
+ */
+ void slotRefresh( );
+ /**
+ * Clears all data
+ */
+ void slotClear( );
+ /**
+ * Stops rendering
+ */
+ void slotStopRendering( );
+ /**
+ * Repaints the view if it is a camera view
+ */
+ void slotActiveRenderModeChanged( );
+
+ /**
+ * Connected to the render manager
+ */
+ void slotRenderingStarted( PMGLView* view );
+ /**
+ * Connected to the render manager
+ */
+ void slotAboutToUpdate( PMGLView* view );
+ /**
+ * Connected to the render manager
+ */
+ void slotRenderingFinished( PMGLView* view );
+
+protected slots:
+ /**
+ * Sets the view type to camera view
+ */
+ void slotCameraView( int id );
+ /**
+ * Called when an object action was selected in the context menu
+ */
+ void slotObjectAction( int id );
+ /**
+ * Called when a control point was selected in the context menu
+ */
+ void slotControlPoint( int id );
+ /**
+ * Aligns the selected control points to the grid
+ */
+ void slotSnapToGrid( );
+
+ void slotMouseChangeTimer( );
+ void slotAutoScroll( );
+
+signals:
+ /**
+ * Emitted when rendering has to be restarted
+ */
+ void refresh( PMGLView* w );
+ /**
+ * Emitted when an object is changed
+ */
+ void objectChanged( PMObject* obj, const int mode, QObject* sender );
+ /**
+ * Emitted when the mouse is over a control point
+ */
+ void controlPointMessage( const QString& msg );
+ /**
+ * Emitted in the destructor
+ */
+ void destroyed( PMGLView* v );
+ /**
+ * Emitted when the view type changes
+ */
+ void viewTypeChanged( const QString& str );
+
+protected:
+ /**
+ * Initializes the glx stuff
+ */
+ virtual void initializeGL( );
+ /** */
+ virtual void resizeEvent( QResizeEvent* e );
+ /** */
+ virtual void paintEvent( QPaintEvent* e );
+ /** */
+ virtual void mousePressEvent( QMouseEvent* e );
+ /** */
+ virtual void mouseReleaseEvent( QMouseEvent* e );
+ /** */
+ virtual void mouseMoveEvent( QMouseEvent* e );
+ /** */
+ virtual void keyPressEvent( QKeyEvent* e );
+ /**
+ * Event to zoom in / zoom out the viewport by mouse wheel
+ */
+ virtual void wheelEvent( QWheelEvent* e );
+
+private:
+ /**
+ * Updates the control points
+ */
+ void updateControlPoints( );
+ /**
+ * Recalculates the position of the control points on the screen
+ */
+ void recalculateControlPointPosition( );
+ /**
+ * Recalculates m_controlPointsTransformation and
+ * m_inversePointsTransformation
+ */
+ void recalculateTransformations( );
+ /**
+ * Returns the mouse 3D position, when the control point cp is selected
+ *
+ * x and y are the screen coordinates of the mouse.
+ */
+ PMVector mousePosition( PMControlPoint* cp, int x, int y );
+ /**
+ * Checks if a control point is under the mouse
+ */
+ void checkUnderMouse( int x, int y );
+ /**
+ * Repaints the view
+ */
+ void repaint( bool graphicalChange = false );
+ /**
+ * Starts a graphical change
+ */
+ void startChange( const QPoint& mousePos );
+ /**
+ * Graphical Change
+ */
+ void graphicalChange( const QPoint& mousePos );
+ /**
+ * Selects/deselecs the control point. If cp is 0, all control points are
+ * selected/deselected.
+ */
+ void selectControlPoint( PMControlPoint* cp, bool select, bool deselectOthers = true );
+ /**
+ * Invalidates the projection and repaints the view
+ */
+ void invalidateProjection( bool graphicaChange = false );
+
+ /**
+ * Starts multiple selection mode
+ */
+ void startSelection( );
+ /**
+ * Restores the widget under the selection rect
+ */
+ void restoreSelectionBox( );
+ /**
+ * Saves the widget under the selection rect
+ */
+ void saveSelectionBox( );
+ /**
+ * Paints the selection box
+ */
+ void paintSelectionBox( );
+ /**
+ * Calculates the selection box
+ */
+ void calculateSelectionBox( int& sx, int& sy, int& ex, int& ey, int& w, int& h );
+
+ double screenToInternalX( int x ) const;
+ double screenToInternalY( int y ) const;
+
+ /**
+ * Returns the top level object for rendering (a declaration or the scene)
+ */
+ PMObject* topLevelRenderingObject( PMObject* obj ) const;
+ /**
+ * Displays the context menu
+ */
+ void contextMenu( );
+
+ /**
+ * Type of the view (camera, xy, ... )
+ */
+ PMViewType m_type;
+ /**
+ * Pointer to the part
+ */
+ PMPart* m_pPart;
+ /**
+ * True if "scale view" is active
+ */
+ bool m_bScaleMode;
+ double m_scaleIntX, m_scaleIntY;
+ /**
+ * true if "translate view" is active
+ */
+ bool m_bTranslateMode;
+ /**
+ * True if "scale view" or "translate view" is active and the left
+ * mouse button is pressed.
+ */
+ bool m_bMousePressed;
+ /**
+ * MidButton pressed
+ */
+ bool m_bMidMousePressed;
+ /**
+ * True if a graphical change is active
+ */
+ bool m_bGraphicalChangeMode;
+ bool m_bMementoCreated;
+ /**
+ * The old mouse position
+ */
+ QPoint m_mousePos;
+ QPoint m_changeStartPos;
+ QPoint m_currentMousePos;
+ QTimer m_startTimer;
+ QTime m_changeStartTime;
+ bool m_bDeselectUnderMouse;
+ bool m_bSelectUnderMouse;
+
+ /**
+ * Member variables for multiple selection mode
+ */
+ QPixmap m_selectionPixmap[4];
+ QPoint m_selectionStart, m_selectionEnd;
+ bool m_bMultipleSelectionMode;
+ bool m_bSelectionStarted;
+
+ /**
+ * Member variables for autoscroll
+ */
+ bool m_bAutoScroll;
+ double m_autoScrollSpeed;
+ QTimer m_autoScrollTimer;
+ QTime m_lastAutoScrollUpdate;
+ int m_autoScrollDirectionX, m_autoScrollDirectionY;
+ /**
+ * Rendering
+ */
+ bool m_bAboutToUpdate;
+
+ /**
+ * Scale of the view
+ */
+ double m_dScale;
+ /**
+ * X-translation of the view
+ */
+ double m_dTransX;
+ /**
+ * Y-translation of the view
+ */
+ double m_dTransY;
+
+ /**
+ * Control points of the active object
+ */
+ PMControlPointList m_controlPoints;
+ /**
+ * Control point under the mouse
+ */
+ PMControlPoint* m_pUnderMouse;
+ /**
+ * Position of the control points on the screen
+ */
+ QPtrList<PMVector> m_controlPointsPosition;
+ /**
+ * Position of the last right mouse click
+ */
+ PMVector m_contextClickPosition;
+ /**
+ * Transformation of the control points
+ *
+ * Always m_viewTransformation * m_objectsTransformation.
+ */
+ PMMatrix m_controlPointsTransformation;
+ /**
+ * Inverse of m_controlPointsTransformation
+ */
+ PMMatrix m_inversePointsTransformation;
+ /**
+ * True if m_inversePointsTransformation is valid
+ */
+ bool m_bInverseValid;
+ /**
+ * Normal vector of the view
+ */
+ PMVector m_normal;
+ /**
+ * Transformation of the view (scale and translation)
+ */
+ PMMatrix m_viewTransformation;
+ /**
+ * Transformation of the active object
+ */
+ PMMatrix m_objectsTransformation;
+ /**
+ * The camera
+ */
+ PMCamera* m_pCamera;
+ PMObject* m_pActiveObject;
+ /**
+ * true if the opengl projection is up to date
+ */
+ bool m_projectionUpToDate;
+ int m_visibilityLevel;
+ /**
+ * The current object actions
+ */
+ QPtrList<PMObjectAction> m_objectActions;
+ static bool s_bDirect;
+};
+
+/**
+ * Options class for the opengl view
+ */
+class PMGLViewOptions : public PMViewOptions
+{
+public:
+ PMGLViewOptions( )
+ {
+ m_glViewType = PMGLView::PMViewPosX;
+ }
+ PMGLViewOptions( PMGLView::PMViewType t )
+ {
+ m_glViewType = t;
+ }
+ virtual PMViewOptions* copy( ) const { return new PMGLViewOptions( *this ); }
+ virtual QString viewType( ) const { return QString( "glview" ); }
+ PMGLView::PMViewType glViewType( ) const { return m_glViewType; }
+ void setGLViewType( PMGLView::PMViewType t ) { m_glViewType = t; }
+ virtual void loadData( QDomElement& e );
+ virtual void saveData( QDomElement& e );
+
+private:
+ PMGLView::PMViewType m_glViewType;
+};
+
+/**
+ * Factory class for 3d views
+ */
+class PMGLViewFactory : public PMViewTypeFactory
+{
+public:
+ PMGLViewFactory( ) { }
+ virtual QString viewType( ) const { return QString( "glview" ); }
+ virtual QString description( ) const;
+ virtual QString description( PMViewOptions* ) const;
+ virtual QString iconName( ) const { return QString( "pmglview" ); }
+ virtual PMViewBase* newInstance( QWidget* parent, PMPart* part ) const
+ {
+ return new PMGLView( part, PMGLView::PMViewPosX, parent );
+ }
+ virtual PMViewOptions* newOptionsInstance( ) const;
+ virtual PMViewOptionsWidget* newOptionsWidget( QWidget*, PMViewOptions* );
+};
+
+/**
+ * Configuration widget for the view layout settings dialog
+ */
+class PMGLViewOptionsWidget : public PMViewOptionsWidget
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ PMGLViewOptionsWidget( QWidget* parent, PMViewOptions* o );
+
+protected slots:
+ void slotGLViewTypeChanged( int );
+
+private:
+ PMGLViewOptions* m_pOptions;
+ QComboBox* m_pGLViewType;
+};
+
+#endif
diff --git a/kpovmodeler/pmgraphicalobject.cpp b/kpovmodeler/pmgraphicalobject.cpp
new file mode 100644
index 00000000..85f4ad22
--- /dev/null
+++ b/kpovmodeler/pmgraphicalobject.cpp
@@ -0,0 +1,248 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmgraphicalobject.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+
+const bool c_defaultNoShadow = false;
+const bool c_defaultNoImage = false;
+const bool c_defaultNoReflection = false;
+const bool c_defaultDoubleIlluminate = false;
+const int c_defaultVisibilityLevel = 0;
+const bool c_defaultRelativeVisibility = true;
+const bool c_defaultExport = true;
+
+PMDefinePropertyClass( PMGraphicalObject, PMGraphicalObjectProperty );
+
+PMMetaObject* PMGraphicalObject::s_pMetaObject = 0;
+
+PMGraphicalObject::PMGraphicalObject( PMPart* part )
+ : Base( part )
+{
+ m_noShadow = c_defaultNoShadow;
+ m_noImage = c_defaultNoImage;
+ m_noReflection = c_defaultNoReflection;
+ m_doubleIlluminate = c_defaultDoubleIlluminate;
+ m_visibilityLevel = c_defaultVisibilityLevel;
+ m_relativeVisibility = c_defaultRelativeVisibility;
+ m_export = c_defaultExport;
+}
+
+PMGraphicalObject::PMGraphicalObject( const PMGraphicalObject& o )
+ : Base( o )
+{
+ m_noShadow = o.m_noShadow;
+ m_noImage = o.m_noImage;
+ m_noReflection = o.m_noReflection;
+ m_doubleIlluminate = o.m_doubleIlluminate;
+ m_visibilityLevel = o.m_visibilityLevel;
+ m_relativeVisibility = o.m_relativeVisibility;
+ m_export = o.m_export;
+}
+
+PMGraphicalObject::~PMGraphicalObject( )
+{
+}
+
+PMMetaObject* PMGraphicalObject::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "GraphicalObject", Base::metaObject( ) );
+ s_pMetaObject->addProperty(
+ new PMGraphicalObjectProperty( "noShadow", &PMGraphicalObject::setNoShadow,
+ &PMGraphicalObject::noShadow ) );
+ s_pMetaObject->addProperty(
+ new PMGraphicalObjectProperty( "noImage", &PMGraphicalObject::setNoImage,
+ &PMGraphicalObject::noImage ) );
+ s_pMetaObject->addProperty(
+ new PMGraphicalObjectProperty( "noReflection", &PMGraphicalObject::setNoReflection,
+ &PMGraphicalObject::noReflection ) );
+ s_pMetaObject->addProperty(
+ new PMGraphicalObjectProperty( "doubleIlluminate", &PMGraphicalObject::setDoubleIlluminate,
+ &PMGraphicalObject::doubleIlluminate ) );
+ s_pMetaObject->addProperty(
+ new PMGraphicalObjectProperty( "visibilityLevel", &PMGraphicalObject::setVisibilityLevel,
+ &PMGraphicalObject::visibilityLevel ) );
+ s_pMetaObject->addProperty(
+ new PMGraphicalObjectProperty( "relativeVisibilityLevel", &PMGraphicalObject::setVisibilityLevelRelative,
+ &PMGraphicalObject::isVisibilityLevelRelative ) );
+ s_pMetaObject->addProperty(
+ new PMGraphicalObjectProperty( "export", &PMGraphicalObject::setExportPovray,
+ &PMGraphicalObject::exportPovray ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMGraphicalObject::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMGraphicalObject::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "no_shadow", m_noShadow );
+ e.setAttribute( "no_image", m_noImage );
+ e.setAttribute( "no_reflection", m_noReflection );
+ e.setAttribute( "double_illuminate", m_doubleIlluminate );
+ e.setAttribute( "visibility_level", m_visibilityLevel );
+ e.setAttribute( "relative_visibility", m_relativeVisibility );
+ e.setAttribute( "export", m_export );
+ Base::serialize( e, doc );
+}
+
+void PMGraphicalObject::readAttributes( const PMXMLHelper& h )
+{
+ m_noShadow = h.boolAttribute( "no_shadow", c_defaultNoShadow );
+ m_noImage = h.boolAttribute( "no_image", c_defaultNoImage );
+ m_noReflection = h.boolAttribute( "no_reflection", c_defaultNoReflection );
+ m_doubleIlluminate = h.boolAttribute( "double_illuminate",
+ c_defaultDoubleIlluminate );
+ m_visibilityLevel = h.intAttribute( "visibility_level",
+ c_defaultVisibilityLevel );
+ m_relativeVisibility = h.boolAttribute( "relative_visibility",
+ c_defaultRelativeVisibility );
+ m_export = h.boolAttribute( "export", c_defaultExport );
+ Base::readAttributes( h );
+}
+
+void PMGraphicalObject::setNoShadow( bool yes )
+{
+ if( m_noShadow != yes )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMNoShadowID, m_noShadow );
+ m_noShadow = yes;
+ }
+}
+
+void PMGraphicalObject::setNoImage( bool yes )
+{
+ if( m_noImage != yes )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMNoImageID, m_noImage );
+ m_noImage = yes;
+ }
+}
+
+void PMGraphicalObject::setNoReflection( bool yes )
+{
+ if ( m_noReflection != yes )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMNoReflectionID, m_noReflection );
+ m_noReflection = yes;
+ }
+}
+
+void PMGraphicalObject::setDoubleIlluminate( bool yes )
+{
+ if( m_doubleIlluminate != yes )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMDoubleIlluminateID, m_doubleIlluminate );
+ m_doubleIlluminate = yes;
+ }
+}
+
+void PMGraphicalObject::setVisibilityLevel( int level )
+{
+ if( m_visibilityLevel != level )
+ {
+ if( m_pMemento )
+ {
+ m_pMemento->addData( s_pMetaObject, PMVisibilityID,
+ m_visibilityLevel );
+ // do not call PMCompositeObject::setViewStructureChanged because
+ // the view structure has not really changed.
+ // Only the scene has to be rendered.
+ m_pMemento->setViewStructureChanged( );
+ }
+ m_visibilityLevel = level;
+ }
+}
+
+void PMGraphicalObject::setVisibilityLevelRelative( bool relative )
+{
+ if( m_relativeVisibility != relative )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMRelativeVisibilityID,
+ m_relativeVisibility );
+ m_relativeVisibility = relative;
+ }
+}
+
+void PMGraphicalObject::setExportPovray( bool ex )
+{
+ if( m_export != ex )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMExportID, m_export );
+ m_export = ex;
+ }
+}
+
+void PMGraphicalObject::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMNoShadowID:
+ setNoShadow( data->boolData( ) );
+ break;
+ case PMNoImageID:
+ setNoImage( data->boolData( ) );
+ break;
+ case PMNoReflectionID:
+ setNoReflection( data->boolData( ) );
+ break;
+ case PMDoubleIlluminateID:
+ setDoubleIlluminate( data->boolData( ) );
+ break;
+ case PMVisibilityID:
+ setVisibilityLevel( data->intData( ) );
+ break;
+ case PMRelativeVisibilityID:
+ setVisibilityLevelRelative( data->boolData( ) );
+ break;
+ case PMExportID:
+ setExportPovray( data->boolData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMGraphicalObject::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmgraphicalobject.h b/kpovmodeler/pmgraphicalobject.h
new file mode 100644
index 00000000..f07ac46f
--- /dev/null
+++ b/kpovmodeler/pmgraphicalobject.h
@@ -0,0 +1,141 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMGRAPHICALOBJECT_H
+#define PMGRAPHICALOBJECT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdetailobject.h"
+
+
+/**
+ * Class for povray graphical objects
+ *
+ * Objects in povray can be:
+ * Finite Solid Primitives, Finite Patch Primitives, Infinite Solid Primitives and Constructive Solid Geometry
+ */
+class PMGraphicalObject : public PMDetailObject
+{
+ typedef PMDetailObject Base;
+public:
+ /**
+ * Creates an empty PMGraphicalObject
+ */
+ PMGraphicalObject( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMGraphicalObject( const PMGraphicalObject& o );
+ /**
+ * Deletes the object and all children
+ */
+ virtual ~PMGraphicalObject( );
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns the state of the no_shadow flag.
+ */
+ bool noShadow( ) const { return m_noShadow; }
+ /**
+ * Sets the no_shadow flag
+ */
+ void setNoShadow( bool yes );
+ /**
+ * Returns the state of the no_image flag.
+ */
+ bool noImage( ) const { return m_noImage; }
+ /**
+ * Sets the no_image flag
+ */
+ void setNoImage( bool yes );
+ /**
+ * Returns the state of the no_reflection flag
+ */
+ bool noReflection( ) const { return m_noReflection; }
+ /**
+ * Sets the no_reflection flag
+ */
+ void setNoReflection( bool yes );
+ /**
+ * Returns the state of the double_illuminate flag
+ */
+ bool doubleIlluminate( ) const { return m_doubleIlluminate; }
+ /**
+ * Sets the double_illuminate flag
+ */
+ void setDoubleIlluminate( bool yes );
+ /**
+ * Returns the visibility level
+ */
+ int visibilityLevel( ) const { return m_visibilityLevel; }
+ /**
+ * Sets the visibility level
+ */
+ void setVisibilityLevel( int level );
+ /**
+ * Returns true if the visibility level is relative to the objects parent
+ */
+ bool isVisibilityLevelRelative( ) const { return m_relativeVisibility; }
+ /**
+ * Sets the visibility level absolute or relative
+ */
+ void setVisibilityLevelRelative( bool relative );
+ /**
+ * Returns the export flag
+ */
+ virtual bool exportPovray( ) const { return m_export; }
+ /**
+ * Sets the export flag
+ */
+ void setExportPovray( bool ex );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMGraphicalObjectMementoID { PMNoShadowID, PMNoImageID, PMNoReflectionID,
+ PMDoubleIlluminateID, PMVisibilityID,
+ PMRelativeVisibilityID, PMExportID };
+
+ bool m_noShadow;
+ bool m_noImage;
+ bool m_noReflection;
+ bool m_doubleIlluminate;
+ int m_visibilityLevel;
+ bool m_relativeVisibility;
+ bool m_export;
+ static PMMetaObject* s_pMetaObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmgraphicalobjectedit.cpp b/kpovmodeler/pmgraphicalobjectedit.cpp
new file mode 100644
index 00000000..2a06485c
--- /dev/null
+++ b/kpovmodeler/pmgraphicalobjectedit.cpp
@@ -0,0 +1,168 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmgraphicalobjectedit.h"
+#include "pmgraphicalobject.h"
+
+#include <qcheckbox.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qspinbox.h>
+#include <klocale.h>
+
+const int c_minValue = -1000;
+const int c_maxValue = 1000;
+
+PMGraphicalObjectEdit::PMGraphicalObjectEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMGraphicalObjectEdit::createBottomWidgets( )
+{
+ QGridLayout* gl = new QGridLayout( topLayout( ), 2, 2 );
+ m_pNoShadowButton = new QCheckBox( i18n( "No shadow" ), this );
+ gl->addWidget( m_pNoShadowButton, 0, 0 );
+ m_pNoImageButton = new QCheckBox( i18n( "No image" ), this );
+ gl->addWidget( m_pNoImageButton, 0, 1 );
+ m_pNoReflectionButton = new QCheckBox( i18n( "No reflection" ), this );
+ gl->addWidget( m_pNoReflectionButton, 1, 0 );
+ m_pDoubleIlluminateButton = new QCheckBox( i18n( "Double illuminate" ), this );
+ gl->addWidget( m_pDoubleIlluminateButton, 1, 1 );
+ m_pExport = new QCheckBox( i18n( "Export to renderer" ), this );
+ topLayout( )->addWidget( m_pExport );
+
+ QHBoxLayout* hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "Visibility level: " ), this ) );
+ m_pVisibilityLevel = new QSpinBox( c_minValue, c_maxValue, 1, this );
+ hl->addWidget( m_pVisibilityLevel );
+ m_pResultingVisibility = new QLabel( QString( "( )" ), this );
+ hl->addWidget( m_pResultingVisibility );
+ hl->addSpacing( 10 );
+ m_pRelativeVisibility = new QCheckBox( i18n( "Relative" ), this );
+ hl->addWidget( m_pRelativeVisibility );
+ hl->addStretch( 1 );
+
+ connect( m_pNoShadowButton, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pNoImageButton, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pNoReflectionButton, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pDoubleIlluminateButton, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pRelativeVisibility, SIGNAL( clicked( ) ),
+ SLOT( slotRelativeChanged( ) ) );
+ connect( m_pVisibilityLevel, SIGNAL( valueChanged( int ) ),
+ SLOT( slotLevelChanged( int ) ) );
+ connect( m_pExport, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+
+
+ Base::createBottomWidgets( );
+}
+
+void PMGraphicalObjectEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "GraphicalObject" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+
+ m_pDisplayedObject = ( PMGraphicalObject* ) o;
+ m_pNoShadowButton->setChecked( m_pDisplayedObject->noShadow( ) );
+ m_pNoShadowButton->setEnabled( !readOnly );
+ m_pNoImageButton->setChecked( m_pDisplayedObject->noImage( ) );
+ m_pNoImageButton->setEnabled( !readOnly );
+ m_pNoReflectionButton->setChecked( m_pDisplayedObject->noReflection( ) );
+ m_pNoReflectionButton->setEnabled( !readOnly );
+ m_pDoubleIlluminateButton->setChecked( m_pDisplayedObject->doubleIlluminate( ) );
+ m_pDoubleIlluminateButton->setEnabled( !readOnly );
+ bool sb = m_pVisibilityLevel->signalsBlocked( );
+ m_pVisibilityLevel->blockSignals( true );
+ m_pVisibilityLevel->setValue( m_pDisplayedObject->visibilityLevel( ) );
+ m_pVisibilityLevel->setEnabled( !readOnly );
+ m_pVisibilityLevel->blockSignals( sb );
+ sb = m_pRelativeVisibility->signalsBlocked( );
+ m_pRelativeVisibility->blockSignals( true );
+ m_pRelativeVisibility->setChecked( m_pDisplayedObject->isVisibilityLevelRelative( ) );
+ m_pRelativeVisibility->setEnabled( !readOnly );
+ m_pRelativeVisibility->blockSignals( sb );
+ m_pExport->setChecked( m_pDisplayedObject->exportPovray( ) );
+ m_pExport->setEnabled( !readOnly );
+
+ recalculateResultingVisibility( );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMGraphicalObjectEdit: Can't display object\n";
+}
+
+void PMGraphicalObjectEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ m_pDisplayedObject->setNoShadow( m_pNoShadowButton->isChecked( ) );
+ m_pDisplayedObject->setNoImage( m_pNoImageButton->isChecked( ) );
+ m_pDisplayedObject->setNoReflection( m_pNoReflectionButton->isChecked( ) );
+ m_pDisplayedObject->setDoubleIlluminate( m_pDoubleIlluminateButton->isChecked( ) );
+ m_pDisplayedObject->setVisibilityLevel( m_pVisibilityLevel->value( ) );
+ m_pDisplayedObject->setVisibilityLevelRelative( m_pRelativeVisibility->isChecked( ) );
+ m_pDisplayedObject->setExportPovray( m_pExport->isChecked( ) );
+ Base::saveContents( );
+ }
+}
+
+bool PMGraphicalObjectEdit::isDataValid( )
+{
+ return Base::isDataValid( );
+}
+
+void PMGraphicalObjectEdit::slotRelativeChanged( )
+{
+ recalculateResultingVisibility( );
+ emit dataChanged( );
+}
+
+void PMGraphicalObjectEdit::slotLevelChanged( int )
+{
+ recalculateResultingVisibility( );
+ emit dataChanged( );
+}
+
+void PMGraphicalObjectEdit::recalculateResultingVisibility( )
+{
+ PMObject* o = m_pDisplayedObject->parent( );
+ PMGraphicalObject* go = 0;
+ int level = 0;
+ bool absoluteFound = false;
+
+ level = m_pVisibilityLevel->value( );
+ if( !m_pRelativeVisibility->isChecked( ) )
+ absoluteFound = true;
+
+ for( ; o && !absoluteFound; o = o->parent( ) )
+ {
+ if( o->isA( "GraphicalObject" ) )
+ {
+ go = ( PMGraphicalObject* ) o;
+ level += go->visibilityLevel( );
+ if( !go->isVisibilityLevelRelative( ) )
+ absoluteFound = true;
+ }
+ }
+ m_pResultingVisibility->setText( QString( "(%1)" ).arg( level ) );
+}
+
+#include "pmgraphicalobjectedit.moc"
diff --git a/kpovmodeler/pmgraphicalobjectedit.h b/kpovmodeler/pmgraphicalobjectedit.h
new file mode 100644
index 00000000..3b31a794
--- /dev/null
+++ b/kpovmodeler/pmgraphicalobjectedit.h
@@ -0,0 +1,78 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMGRAPHICALOBJECTEDIT_H
+#define PMGRAPHICALOBJECTEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdetailobjectedit.h"
+
+class PMGraphicalObject;
+class QCheckBox;
+class QSpinBox;
+class QLabel;
+
+/**
+ * Dialog edit class for @ref PMGraphicalObject.
+ */
+class PMGraphicalObjectEdit : public PMDetailObjectEdit
+{
+ Q_OBJECT
+ typedef PMDetailObjectEdit Base;
+public:
+ /**
+ * Creates a PMGraphicalObjectEdit with parent and name
+ */
+ PMGraphicalObjectEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createBottomWidgets( );
+ /** */
+ virtual void saveContents( );
+
+protected slots:
+ void slotRelativeChanged( );
+ void slotLevelChanged( int );
+
+private:
+ void recalculateResultingVisibility( );
+
+private:
+ PMGraphicalObject* m_pDisplayedObject;
+ QCheckBox* m_pNoShadowButton;
+ QCheckBox* m_pNoImageButton;
+ QCheckBox* m_pNoReflectionButton;
+ QCheckBox* m_pDoubleIlluminateButton;
+ QSpinBox* m_pVisibilityLevel;
+ QCheckBox* m_pRelativeVisibility;
+ QLabel* m_pResultingVisibility;
+ QCheckBox* m_pExport;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmgridsettings.cpp b/kpovmodeler/pmgridsettings.cpp
new file mode 100644
index 00000000..20973935
--- /dev/null
+++ b/kpovmodeler/pmgridsettings.cpp
@@ -0,0 +1,155 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmgridsettings.h"
+
+#include "pmlineedits.h"
+#include "pmrendermanager.h"
+#include "pmcontrolpoint.h"
+#include "pmdefaults.h"
+
+#include <qlayout.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <kcolorbutton.h>
+#include <klocale.h>
+
+PMGridSettings::PMGridSettings( QWidget* parent, const char* name )
+ : PMSettingsDialogPage( parent, name )
+{
+ QHBoxLayout* hlayout;
+ QVBoxLayout* vlayout;
+ QVBoxLayout* gvl;
+ QGridLayout* grid;
+ QGroupBox* gb;
+
+ vlayout = new QVBoxLayout( this, 0, KDialog::spacingHint( ) );
+ gb = new QGroupBox( i18n( "Displayed Grid" ), this );
+ vlayout->addWidget( gb );
+ gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) );
+ gvl->addSpacing( 10 );
+
+ hlayout = new QHBoxLayout( gvl );
+ hlayout->addWidget( new QLabel( i18n( "Color:" ), gb ) );
+ m_pGridColor = new KColorButton( gb );
+ hlayout->addWidget( m_pGridColor );
+ hlayout->addStretch( 1 );
+
+ hlayout = new QHBoxLayout( gvl );
+ hlayout->addWidget( new QLabel( i18n( "Distance:" ), gb ) );
+ m_pGridDistance = new PMIntEdit( gb );
+ m_pGridDistance->setValidation( true, 20, false, 0 );
+ hlayout->addWidget( m_pGridDistance );
+ hlayout->addStretch( 1 );
+
+ gb = new QGroupBox( i18n( "Control Point Grid" ), this );
+ vlayout->addWidget( gb );
+ gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) );
+ gvl->addSpacing( 10 );
+
+ hlayout = new QHBoxLayout( gvl );
+ grid = new QGridLayout( hlayout, 3, 2 );
+ grid->addWidget( new QLabel( i18n( "2D/3D movement:" ), gb ), 0, 0 );
+ m_pMoveGrid = new PMFloatEdit( gb );
+ m_pMoveGrid->setValidation( true, 0.001, true, 100 );
+ grid->addWidget( m_pMoveGrid, 0, 1 );
+
+ grid->addWidget( new QLabel( i18n( "Scale:" ), gb ), 1, 0 );
+ m_pScaleGrid = new PMFloatEdit( gb );
+ m_pScaleGrid->setValidation( true, 0.001, true, 100 );
+ grid->addWidget( m_pScaleGrid, 1, 1 );
+
+ grid->addWidget( new QLabel( i18n( "Rotation:" ), gb ), 2, 0 );
+ m_pRotateGrid = new PMFloatEdit( gb );
+ m_pRotateGrid->setValidation( true, 0.001, true, 180 );
+ grid->addWidget( m_pRotateGrid, 2, 1 );
+
+ hlayout->addStretch( 1 );
+
+ vlayout->addStretch( 1 );
+}
+
+void PMGridSettings::displaySettings( )
+{
+ PMRenderManager* rm = PMRenderManager::theManager( );
+ m_pGridColor->setColor( rm->gridColor( ) );
+ m_pGridDistance->setValue( rm->gridDistance( ) );
+ m_pMoveGrid->setValue( PMControlPoint::moveGrid( ) );
+ m_pScaleGrid->setValue( PMControlPoint::scaleGrid( ) );
+ m_pRotateGrid->setValue( PMControlPoint::rotateGrid( ) );
+}
+
+void PMGridSettings::displayDefaults( )
+{
+ m_pGridColor->setColor( c_defaultGridColor );
+ m_pGridDistance->setValue( c_defaultGridDistance );
+ m_pMoveGrid->setValue( c_defaultMoveGrid );
+ m_pScaleGrid->setValue( c_defaultScaleGrid );
+ m_pRotateGrid->setValue( c_defaultRotateGrid );
+}
+
+bool PMGridSettings::validateData( )
+{
+ if( !m_pGridDistance->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pGridDistance->setFocus( );
+ return false;
+ }
+ if( !m_pMoveGrid->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pMoveGrid->setFocus( );
+ return false;
+ }
+ if( !m_pScaleGrid->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pScaleGrid->setFocus( );
+ return false;
+ }
+ if( !m_pRotateGrid->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pRotateGrid->setFocus( );
+ return false;
+ }
+ return true;
+}
+
+void PMGridSettings::applySettings( )
+{
+ bool repaint = false;
+ PMRenderManager* rm = PMRenderManager::theManager( );
+ if( rm->gridColor( ) != m_pGridColor->color( ) )
+ {
+ rm->setGridColor( m_pGridColor->color( ) );
+ repaint = true;
+ }
+ if( rm->gridDistance( ) != m_pGridDistance->value( ) )
+ {
+ rm->setGridDistance( m_pGridDistance->value( ) );
+ repaint = true;
+ }
+ PMControlPoint::setMoveGrid( m_pMoveGrid->value( ) );
+ PMControlPoint::setScaleGrid( m_pScaleGrid->value( ) );
+ PMControlPoint::setRotateGrid( m_pRotateGrid->value( ) );
+ if( repaint )
+ emit repaintViews( );
+}
+
+#include "pmgridsettings.moc"
diff --git a/kpovmodeler/pmgridsettings.h b/kpovmodeler/pmgridsettings.h
new file mode 100644
index 00000000..724ade35
--- /dev/null
+++ b/kpovmodeler/pmgridsettings.h
@@ -0,0 +1,60 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMGRIDSETTINGS_H
+#define PMGRIDSETTINGS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsettingsdialog.h"
+
+class KColorButton;
+class PMIntEdit;
+class PMFloatEdit;
+
+/**
+ * Grid configuration dialog page
+ */
+class PMGridSettings : public PMSettingsDialogPage
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ PMGridSettings( QWidget* parent, const char* name = 0 );
+ /** */
+ virtual void displaySettings( );
+ /** */
+ virtual bool validateData( );
+ /** */
+ virtual void applySettings( );
+ /** */
+ virtual void displayDefaults( );
+
+private:
+ PMIntEdit* m_pGridDistance;
+ KColorButton* m_pGridColor;
+ PMFloatEdit* m_pMoveGrid;
+ PMFloatEdit* m_pScaleGrid;
+ PMFloatEdit* m_pRotateGrid;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmheightfield.cpp b/kpovmodeler/pmheightfield.cpp
new file mode 100644
index 00000000..e729282a
--- /dev/null
+++ b/kpovmodeler/pmheightfield.cpp
@@ -0,0 +1,469 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmheightfield.h"
+
+#include "pmxmlhelper.h"
+#include "pmheightfieldedit.h"
+#include "pmheightfieldroam.h"
+#include "pmmemento.h"
+#include "pmviewstructure.h"
+#include "pmenumproperty.h"
+#include "pmdefaults.h"
+
+#include <klocale.h>
+
+const PMHeightField::HeightFieldType c_defaultType = PMHeightField::HFgif;
+const QString c_defaultTypeText = QString( "gif" );
+const QString c_defaultFileName = QString( "" );
+const bool c_defaultHierarchy = true;
+const bool c_defaultSmooth = false;
+const double c_defaultWaterLevel = 0.0;
+
+PMDefinePropertyClass( PMHeightField, PMHeightFieldProperty );
+PMDefineEnumPropertyClass( PMHeightField, PMHeightField::HeightFieldType,
+ PMHeightFieldTypeProperty );
+
+
+int PMHeightField::s_variance = c_defaultHeightFieldVariance;
+int PMHeightField::s_parameterKey = 0;
+
+PMViewStructure* PMHeightField::s_pDefaultViewStructure = 0;
+PMMetaObject* PMHeightField::s_pMetaObject = 0;
+
+PMObject* createNewHeightField( PMPart* part )
+{
+ return new PMHeightField( part );
+}
+
+PMHeightField::PMHeightField( PMPart* part )
+ : Base( part )
+{
+ m_hfType = c_defaultType;
+ m_fileName = c_defaultFileName;
+ m_hierarchy = c_defaultHierarchy;
+ m_smooth = c_defaultSmooth;
+ m_waterLevel = c_defaultWaterLevel;
+
+ m_modMap = true;
+ m_pROAM = 0;
+}
+
+PMHeightField::PMHeightField( const PMHeightField& f )
+ : Base( f )
+{
+ m_hfType = f.m_hfType;
+ m_fileName = f.m_fileName;
+ m_hierarchy = f.m_hierarchy;
+ m_smooth = f.m_smooth;
+ m_waterLevel = f.m_waterLevel;
+
+ m_modMap = true;
+ m_pROAM = 0;
+}
+
+PMHeightField::~PMHeightField( )
+{
+ delete m_pROAM;
+}
+
+QString PMHeightField::description( ) const
+{
+ return i18n( "height field" );
+}
+
+void PMHeightField::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "hf_type", typeToString( m_hfType ) );
+ e.setAttribute( "file_name", m_fileName );
+ e.setAttribute( "hierarchy", m_hierarchy );
+ e.setAttribute( "smooth", m_smooth );
+ e.setAttribute( "water_level", m_waterLevel );
+ Base::serialize( e, doc );
+}
+
+void PMHeightField::readAttributes( const PMXMLHelper& h )
+{
+ m_hfType = stringToType( h.stringAttribute( "hf_type", c_defaultTypeText ) );
+ m_fileName = h.stringAttribute( "file_name", c_defaultFileName );
+ m_hierarchy = h.boolAttribute( "hierarchy", c_defaultHierarchy );
+ m_smooth = h.boolAttribute( "smooth", c_defaultSmooth );
+ m_waterLevel = h.doubleAttribute( "water_level", c_defaultWaterLevel );
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMHeightField::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "HeightField", Base::metaObject( ),
+ createNewHeightField );
+ s_pMetaObject->addProperty(
+ new PMHeightFieldProperty( "fileName", &PMHeightField::setFileName, &PMHeightField::fileName ) );
+ s_pMetaObject->addProperty(
+ new PMHeightFieldProperty( "hierarchy", &PMHeightField::setHierarchy, &PMHeightField::hierarchy ) );
+ s_pMetaObject->addProperty(
+ new PMHeightFieldProperty( "smooth", &PMHeightField::setSmooth, &PMHeightField::smooth ) );
+ s_pMetaObject->addProperty(
+ new PMHeightFieldProperty( "waterLevel", &PMHeightField::setWaterLevel, &PMHeightField::waterLevel ) );
+ PMHeightFieldTypeProperty* p =
+ new PMHeightFieldTypeProperty( "heightFieldType", &PMHeightField::setHeightFieldType,
+ &PMHeightField::heightFieldType );
+ p->addEnumValue( "Gif", HFgif );
+ p->addEnumValue( "Tga", HFtga );
+ p->addEnumValue( "Pot", HFpot );
+ p->addEnumValue( "Png", HFpng );
+ p->addEnumValue( "Pgm", HFpgm );
+ p->addEnumValue( "Ppm", HFppm );
+ p->addEnumValue( "Sys", HFsys );
+ s_pMetaObject->addProperty( p );
+ }
+ return s_pMetaObject;
+}
+
+void PMHeightField::setHeightFieldType( PMHeightField::HeightFieldType t )
+{
+ if( t != m_hfType )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMHeightFieldTypeID, m_hfType );
+ m_hfType = t;
+ }
+}
+
+void PMHeightField::setFileName( const QString& f )
+{
+ if( f != m_fileName )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFileNameID, m_fileName );
+ m_fileName = f;
+ m_modMap = true;
+ setViewStructureChanged( );
+ }
+}
+
+void PMHeightField::setHierarchy( bool h )
+{
+ if( h != m_hierarchy )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMHierarchyID, m_hierarchy );
+ m_hierarchy = h;
+ }
+}
+
+void PMHeightField::setSmooth( bool s )
+{
+ if( s != m_smooth )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSmoothID, m_smooth );
+ m_smooth = s;
+ }
+}
+
+void PMHeightField::setWaterLevel( double wl )
+{
+ if( wl < 0.0 )
+ {
+ kdError( PMArea ) << "Water level < 0.0 in PMHeightField::setWaterLevel\n";
+ wl = 0.0;
+ }
+ if( wl > 1.0 )
+ {
+ kdError( PMArea ) << "Water level > 1.0 in PMHeightField::setWaterLevel\n";
+ wl = 1.0;
+ }
+
+ if( wl != m_waterLevel )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMWaterLevelID, m_waterLevel );
+ m_waterLevel = wl;
+ setViewStructureChanged( );
+ }
+}
+
+PMDialogEditBase* PMHeightField::editWidget( QWidget* parent ) const
+{
+ return new PMHeightFieldEdit( parent );
+}
+
+void PMHeightField::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMHeightFieldTypeID:
+ m_hfType = ( HeightFieldType ) data->intData( );
+ break;
+ case PMFileNameID:
+ m_fileName = data->stringData( );
+ break;
+ case PMHierarchyID:
+ m_hierarchy = data->boolData( );
+ break;
+ case PMSmoothID:
+ m_smooth = data->boolData( );
+ break;
+ case PMWaterLevelID:
+ m_waterLevel = data->doubleData( );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMHeightField::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
+
+bool PMHeightField::isDefault( )
+{
+ return ( m_waterLevel == c_defaultWaterLevel && m_fileName.isEmpty( ) );
+}
+
+void PMHeightField::createViewStructure( )
+{
+ int detail = 65200 - ( ( s_variance * 163 ) * ( displayDetail( ) * displayDetail( ) ) );
+ if ( m_modMap )
+ {
+ m_modMap = false;
+
+ if ( m_pROAM )
+ {
+ delete m_pROAM;
+ m_pROAM = 0;
+ }
+
+ if ( !m_fileName.isEmpty( ) )
+ {
+ m_pROAM = new PMHeightFieldROAM( m_fileName );
+
+ if ( m_pROAM->isFailed( ) )
+ {
+ delete m_pROAM;
+ m_pROAM = 0;
+ }
+ }
+ }
+
+ if ( m_pROAM )
+ {
+ m_pROAM->setDisplayDetail( detail );
+ m_pROAM->setWaterLevel( m_waterLevel );
+ m_pROAM->updateModel( );
+ roamViewStructure( );
+ return;
+ }
+
+ if ( !m_pViewStructure )
+ {
+ m_pViewStructure = new PMViewStructure( defaultViewStructure( ) );
+ m_pViewStructure->points( ).detach( );
+ m_pViewStructure->lines( ).detach( );
+ }
+ else
+ {
+ m_pViewStructure->points( ).resize(
+ defaultViewStructure( )->points( ).size( ) );
+ m_pViewStructure->lines( ).resize(
+ defaultViewStructure( )->lines( ).size( ) );
+ }
+
+ PMPointArray& points = m_pViewStructure->points( );
+
+ points[4][1] = m_waterLevel;
+ points[5][1] = m_waterLevel;
+ points[6][1] = m_waterLevel;
+ points[7][1] = m_waterLevel;
+}
+
+void PMHeightField::roamViewStructure( )
+{
+ if ( !m_pViewStructure )
+ {
+ m_pViewStructure = new PMViewStructure( defaultViewStructure( ) );
+ m_pViewStructure->points( ).detach( );
+ m_pViewStructure->lines( ).detach( );
+ }
+
+ int x, z, i, pts;
+ int size = m_pROAM->size( );
+ int currentLine = defaultViewStructure( )->lines( ).size( );
+ int defPointsNum = defaultViewStructure( )->points( ).size( );
+ double dx, dy, dz;
+ double sizeM1 = size - 1.0;
+
+ m_pViewStructure->points( ).resize( m_pROAM->usedPoints( ) + defPointsNum );
+ m_pViewStructure->lines( ).resize( m_pROAM->numLines( ) + currentLine );
+
+ PMPointArray& points = m_pViewStructure->points( );
+ PMLineArray& lines = m_pViewStructure->lines( );
+
+ points[4][1] = m_waterLevel;
+ points[5][1] = m_waterLevel;
+ points[6][1] = m_waterLevel;
+ points[7][1] = m_waterLevel;
+
+ for ( x = 0; x < size; ++x )
+ {
+ dx = x / sizeM1;
+ for ( z = 0; z < size; ++z )
+ {
+ dz = z / sizeM1;
+ if ( m_pROAM->usedPoint( x, z ) )
+ {
+ pts = m_pROAM->posPoint( x, z ) + defPointsNum;
+ dy = m_pROAM->height( x, z, true ) / 65535.0;
+ points[ pts ] = PMPoint( dx, dy, dz );
+
+ for ( i = 0; m_pROAM->lineExist( x, z, i ) && i < 8; ++i )
+ {
+ lines[ currentLine++ ] =
+ PMLine( pts, m_pROAM->endPoint( x, z, i ) + defPointsNum );
+ }
+ }
+ }
+ }
+}
+
+PMViewStructure* PMHeightField::defaultViewStructure( ) const
+{
+ if( !s_pDefaultViewStructure )
+ {
+ s_pDefaultViewStructure = new PMViewStructure( 12, 16 );
+ PMPointArray& points = s_pDefaultViewStructure->points( );
+ PMLineArray& lines = s_pDefaultViewStructure->lines( );
+
+ points[ 0] = PMPoint( 0.0, 0.0, 0.0 );
+ points[ 1] = PMPoint( 1.0, 0.0, 0.0 );
+ points[ 2] = PMPoint( 1.0, 0.0, 1.0 );
+ points[ 3] = PMPoint( 0.0, 0.0, 1.0 );
+ points[ 4] = PMPoint( 0.0, c_defaultWaterLevel, 0.0 );
+ points[ 5] = PMPoint( 1.0, c_defaultWaterLevel, 0.0 );
+ points[ 6] = PMPoint( 1.0, c_defaultWaterLevel, 1.0 );
+ points[ 7] = PMPoint( 0.0, c_defaultWaterLevel, 1.0 );
+ points[ 8] = PMPoint( 0.0, 1.0, 0.0 );
+ points[ 9] = PMPoint( 1.0, 1.0, 0.0 );
+ points[10] = PMPoint( 1.0, 1.0, 1.0 );
+ points[11] = PMPoint( 0.0, 1.0, 1.0 );
+
+ lines[ 0] = PMLine( 0, 1 );
+ lines[ 1] = PMLine( 1, 2 );
+ lines[ 2] = PMLine( 2, 3 );
+ lines[ 3] = PMLine( 0, 3 );
+
+ lines[ 4] = PMLine( 0, 8 );
+ lines[ 5] = PMLine( 1, 9 );
+ lines[ 6] = PMLine( 2, 10 );
+ lines[ 7] = PMLine( 3, 11 );
+
+ lines[ 8] = PMLine( 4, 5 );
+ lines[ 9] = PMLine( 5, 6 );
+ lines[10] = PMLine( 6, 7 );
+ lines[11] = PMLine( 4, 7 );
+
+ lines[12] = PMLine( 8, 9 );
+ lines[13] = PMLine( 9, 10 );
+ lines[14] = PMLine( 10, 11 );
+ lines[15] = PMLine( 8, 11 );
+ }
+ return s_pDefaultViewStructure;
+}
+
+QString PMHeightField::typeToString( PMHeightField::HeightFieldType t )
+{
+ QString s;
+ switch( t )
+ {
+ case HFgif:
+ s = QString( "gif" );
+ break;
+ case HFtga:
+ s = QString( "tga" );
+ break;
+ case HFpot:
+ s = QString( "pot" );
+ break;
+ case HFpng:
+ s = QString( "png" );
+ break;
+ case HFpgm:
+ s = QString( "pgm" );
+ break;
+ case HFppm:
+ s = QString( "ppm" );
+ break;
+ case HFsys:
+ s = QString( "sys" );
+ break;
+ }
+ return s;
+}
+
+PMHeightField::HeightFieldType PMHeightField::stringToType( const QString &str )
+{
+ HeightFieldType t = HFgif;
+ if( str == "gif" )
+ t = HFgif;
+ else if( str == "tga" )
+ t = HFtga;
+ else if( str == "pot" )
+ t = HFpot;
+ else if( str == "png" )
+ t = HFpng;
+ else if( str == "pgm" )
+ t = HFpgm;
+ else if( str == "ppm" )
+ t = HFppm;
+ else if( str == "sys" )
+ t = HFsys;
+ return t;
+}
+
+void PMHeightField::setVariance( int v )
+{
+ if( v < 52 && v > 0 )
+ s_variance = v;
+ else
+ kdDebug( PMArea ) << "PMHeightField::setVariance: V must be less than 52 & greater than 0\n";
+ s_parameterKey++;
+}
+
+void PMHeightField::cleanUp( ) const
+{
+ if( s_pDefaultViewStructure )
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
diff --git a/kpovmodeler/pmheightfield.h b/kpovmodeler/pmheightfield.h
new file mode 100644
index 00000000..4ab961c8
--- /dev/null
+++ b/kpovmodeler/pmheightfield.h
@@ -0,0 +1,180 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMHEIGHTFIELD_H
+#define PMHEIGHTFIELD_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobject.h"
+
+class PMViewStructure;
+class PMHeightFieldROAM;
+
+/**
+ * Class for povray height fields.
+ */
+
+class PMHeightField : public PMSolidObject
+{
+ typedef PMSolidObject Base;
+public:
+ /**
+ * Height field type
+ */
+ enum HeightFieldType { HFgif, HFtga, HFpot, HFpng, HFpgm, HFppm, HFsys };
+ /**
+ * Creates an empty PMHeightField
+ */
+ PMHeightField( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMHeightField( const PMHeightField& f );
+ /**
+ * deletes the PMHeightField
+ */
+ virtual ~PMHeightField( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMHeightField( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMHeightFieldEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmheightfield" ); }
+
+ /**
+ * Returns the height field type
+ */
+ HeightFieldType heightFieldType( ) const { return m_hfType; }
+ /**
+ * Sets the height field type
+ */
+ void setHeightFieldType( HeightFieldType t );
+ /**
+ * Returns the file name
+ */
+ QString fileName( ) const { return m_fileName; }
+ /**
+ * Sets the file name
+ */
+ void setFileName( const QString& name );
+ /**
+ * Returns the hierarchy flag
+ */
+ bool hierarchy( ) const { return m_hierarchy; }
+ /**
+ * Sets the hierarchy flag
+ */
+ void setHierarchy( bool h );
+ /**
+ * Returns the smooth flag
+ */
+ bool smooth( ) const { return m_smooth; }
+ /**
+ * Sets the smooth flag
+ */
+ void setSmooth( bool s );
+ /**
+ * Returns the water level
+ */
+ double waterLevel( ) const { return m_waterLevel; }
+ /**
+ * Sets the water level
+ */
+ void setWaterLevel( double wl );
+
+ /**
+ * Sets the heightfield variance
+ */
+ static void setVariance( int v );
+ /**
+ * Returns the heightfield variance
+ */
+ static int variance( ) { return s_variance; }
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /** */
+ virtual bool hasDisplayDetail( ) const { return true; }
+ /** */
+ virtual void cleanUp( ) const;
+
+ static QString typeToString( HeightFieldType t );
+ static HeightFieldType stringToType( const QString &str );
+
+protected:
+ /** */
+ virtual bool isDefault( );
+ /** */
+ virtual void createViewStructure( );
+ /** */
+ virtual PMViewStructure* defaultViewStructure( ) const;
+ /** */
+ virtual int viewStructureParameterKey( ) const { return s_parameterKey + globalDetailKey(); }
+
+private:
+ /**
+ * Creates the ROAM view structure
+ */
+ void roamViewStructure( );
+
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMHeightFieldMementoID { PMHeightFieldTypeID, PMFileNameID,
+ PMHierarchyID, PMSmoothID, PMWaterLevelID };
+
+ HeightFieldType m_hfType;
+ QString m_fileName;
+ bool m_hierarchy;
+ bool m_smooth;
+ double m_waterLevel;
+
+ bool m_modMap;
+ PMHeightFieldROAM* m_pROAM;
+
+ /**
+ * The default view structure. It can be shared between height fields
+ */
+ static PMViewStructure* s_pDefaultViewStructure;
+ static int s_variance;
+ static int s_parameterKey;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmheightfieldedit.cpp b/kpovmodeler/pmheightfieldedit.cpp
new file mode 100644
index 00000000..c5a65998
--- /dev/null
+++ b/kpovmodeler/pmheightfieldedit.cpp
@@ -0,0 +1,201 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmheightfieldedit.h"
+#include "pmheightfield.h"
+#include "pmlineedits.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+#include <qslider.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kfiledialog.h>
+
+PMHeightFieldEdit::PMHeightFieldEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMHeightFieldEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "Type:" ), this ) );
+ m_pHeightFieldType = new QComboBox( false, this );
+ hl->addWidget( m_pHeightFieldType );
+ hl->addStretch( 0 );
+ m_pHeightFieldType->insertItem( "gif" );
+ m_pHeightFieldType->insertItem( "tga" );
+ m_pHeightFieldType->insertItem( "pot" );
+ m_pHeightFieldType->insertItem( "png" );
+ m_pHeightFieldType->insertItem( "pgm" );
+ m_pHeightFieldType->insertItem( "ppm" );
+ m_pHeightFieldType->insertItem( "sys" );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "File name:" ), this ) );
+ m_pFileName = new QLineEdit( this );
+ hl->addWidget( m_pFileName );
+ m_pChooseFileName = new QPushButton( this );
+ m_pChooseFileName->setPixmap( SmallIcon( "fileopen" ) );
+ hl->addWidget( m_pChooseFileName );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "Water level:" ), this ) );
+ m_pWaterLevel = new PMFloatEdit( this );
+ m_pWaterLevel->setValidation( true, 0.0, true, 1.0 );
+ hl->addWidget( m_pWaterLevel );
+ hl->addStretch( 1 );
+
+ m_pHierarchy = new QCheckBox( i18n( "Hierarchy" ), this );
+ topLayout( )->addWidget( m_pHierarchy );
+
+ m_pSmooth = new QCheckBox( i18n( "Smooth" ), this );
+ topLayout( )->addWidget( m_pSmooth );
+
+ connect( m_pHeightFieldType, SIGNAL( activated( int ) ),
+ SLOT( slotTypeChanged( int ) ) );
+ connect( m_pFileName, SIGNAL( textChanged( const QString& ) ),
+ SLOT( slotFileNameChanged( const QString& ) ) );
+ connect( m_pChooseFileName, SIGNAL( clicked( ) ),
+ SLOT( slotFileNameClicked( ) ) );
+ connect( m_pWaterLevel, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pHierarchy, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pSmooth, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMHeightFieldEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "HeightField" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMHeightField* ) o;
+
+ switch( m_pDisplayedObject->heightFieldType( ) )
+ {
+ case PMHeightField::HFgif:
+ m_pHeightFieldType->setCurrentItem( 0 );
+ break;
+ case PMHeightField::HFtga:
+ m_pHeightFieldType->setCurrentItem( 1 );
+ break;
+ case PMHeightField::HFpot:
+ m_pHeightFieldType->setCurrentItem( 2 );
+ break;
+ case PMHeightField::HFpng:
+ m_pHeightFieldType->setCurrentItem( 3 );
+ break;
+ case PMHeightField::HFpgm:
+ m_pHeightFieldType->setCurrentItem( 4 );
+ break;
+ case PMHeightField::HFppm:
+ m_pHeightFieldType->setCurrentItem( 5 );
+ break;
+ case PMHeightField::HFsys:
+ m_pHeightFieldType->setCurrentItem( 6 );
+ break;
+ }
+ m_pFileName->setText( m_pDisplayedObject->fileName( ) );
+ m_pWaterLevel->setValue( m_pDisplayedObject->waterLevel( ) );
+ m_pHierarchy->setChecked( m_pDisplayedObject->hierarchy( ) );
+ m_pSmooth->setChecked( m_pDisplayedObject->smooth( ) );
+
+ m_pHeightFieldType->setEnabled( !readOnly );
+ m_pFileName->setReadOnly( readOnly );
+ m_pChooseFileName->setEnabled( !readOnly );
+ m_pHierarchy->setEnabled( !readOnly );
+ m_pSmooth->setEnabled( !readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMHeightFieldEdit: Can't display object\n";
+}
+
+void PMHeightFieldEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ switch( m_pHeightFieldType->currentItem( ) )
+ {
+ case 0:
+ m_pDisplayedObject->setHeightFieldType( PMHeightField::HFgif );
+ break;
+ case 1:
+ m_pDisplayedObject->setHeightFieldType( PMHeightField::HFtga );
+ break;
+ case 2:
+ m_pDisplayedObject->setHeightFieldType( PMHeightField::HFpot );
+ break;
+ case 3:
+ m_pDisplayedObject->setHeightFieldType( PMHeightField::HFpng );
+ break;
+ case 4:
+ m_pDisplayedObject->setHeightFieldType( PMHeightField::HFpgm );
+ break;
+ case 5:
+ m_pDisplayedObject->setHeightFieldType( PMHeightField::HFppm );
+ break;
+ case 6:
+ m_pDisplayedObject->setHeightFieldType( PMHeightField::HFsys );
+ break;
+ }
+ m_pDisplayedObject->setFileName( m_pFileName->text( ) );
+ m_pDisplayedObject->setWaterLevel( m_pWaterLevel->value( ) );
+ m_pDisplayedObject->setHierarchy( m_pHierarchy->isChecked( ) );
+ m_pDisplayedObject->setSmooth( m_pSmooth->isChecked( ) );
+ }
+}
+
+bool PMHeightFieldEdit::isDataValid( )
+{
+ if( m_pWaterLevel->isDataValid( ) )
+ return Base::isDataValid( );
+ return false;
+}
+
+void PMHeightFieldEdit::slotTypeChanged( int )
+{
+ emit dataChanged( );
+}
+
+void PMHeightFieldEdit::slotFileNameChanged( const QString& )
+{
+ emit dataChanged( );
+}
+
+void PMHeightFieldEdit::slotFileNameClicked( )
+{
+ QString str = KFileDialog::getOpenFileName( QString::null, QString::null );
+
+ if( !str.isEmpty() )
+ {
+ m_pFileName->setText( str );
+ emit dataChanged( );
+ }
+}
+
+#include "pmheightfieldedit.moc"
diff --git a/kpovmodeler/pmheightfieldedit.h b/kpovmodeler/pmheightfieldedit.h
new file mode 100644
index 00000000..24ea2e6e
--- /dev/null
+++ b/kpovmodeler/pmheightfieldedit.h
@@ -0,0 +1,87 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMHEIGHTFIELDEDIT_H
+#define PMHEIGHTFIELDEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobjectedit.h"
+
+class PMHeightField;
+class PMFloatEdit;
+class QCheckBox;
+class QComboBox;
+class QLineEdit;
+class QPushButton;
+
+/**
+ * Dialog edit class for @ref PMHeightField
+ */
+class PMHeightFieldEdit : public PMSolidObjectEdit
+{
+ Q_OBJECT
+ typedef PMSolidObjectEdit Base;
+public:
+ /**
+ * Creates a PMHeightFieldEdit with parent and name
+ */
+ PMHeightFieldEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+
+protected slots:
+ /**
+ * Slot called when the height field type is changed
+ */
+ void slotTypeChanged( int t );
+ /**
+ * Slot called when the file name is changed
+ */
+ void slotFileNameChanged( const QString& s );
+ /**
+ * Slot called when the choose file button is pressed
+ */
+ void slotFileNameClicked( );
+
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMHeightField* m_pDisplayedObject;
+ QComboBox* m_pHeightFieldType;
+ QLineEdit* m_pFileName;
+ QPushButton* m_pChooseFileName;
+ QCheckBox* m_pSmooth;
+ QCheckBox* m_pHierarchy;
+ PMFloatEdit* m_pWaterLevel;
+
+};
+
+
+#endif
diff --git a/kpovmodeler/pmheightfieldroam.cpp b/kpovmodeler/pmheightfieldroam.cpp
new file mode 100644
index 00000000..eb2790a5
--- /dev/null
+++ b/kpovmodeler/pmheightfieldroam.cpp
@@ -0,0 +1,422 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+#include "pmheightfieldroam.h"
+
+#include <cstdlib>
+#include <new>
+
+#include <qstring.h>
+#include <qimage.h>
+#include <qcolor.h>
+
+#include <kdebug.h>
+
+PMHeightFieldROAM::PMHeightFieldROAM( const QString &fileName )
+{
+ m_size = 0;
+ m_numLines = m_usedPoints = 0;
+ m_waterLevel = m_displayDetail = 0;
+ m_mapMod = m_levelMod = true;
+ m_fail = false;
+ m_pPoints = 0;
+ m_pTree = 0;
+
+ if ( !imageToData( fileName ) )
+ {
+ if ( m_pPoints )
+ delete [] m_pPoints;
+ if ( m_pTree )
+ delete [] m_pTree;
+ m_pPoints = 0;
+ m_pTree = 0;
+ m_pNextNode = 0;
+ m_size = m_numPoints = m_numNodes = 0;
+ m_fail = true;
+ return;
+ }
+
+ calcLevel( );
+}
+
+PMHeightFieldROAM::~PMHeightFieldROAM( )
+{
+ delete [] m_pPoints;
+ delete [] m_pTree;
+}
+
+void PMHeightFieldROAM::updateModel( )
+{
+ if ( m_fail )
+ return;
+ int z = m_size - 1;
+ if ( m_mapMod )
+ {
+ m_mapMod = false;
+ m_levelMod = false;
+ clearPoints( );
+ clearNodes( true );
+
+ m_pNextNode = m_pTree + 1;
+ m_pNextNode->base = m_pTree;
+ m_pTree->base = m_pNextNode++;
+
+ varNode(m_pTree, z, 0, 0, 0, 0, z, 0);
+ varNode(m_pTree + 1, 0, z, z, z, z, 0, 0);
+
+ sptNode(m_pTree, 0);
+ sptNode(m_pTree + 1, 0);
+
+ pntNode(m_pTree, z, 0, 0, 0, 0, z);
+ pntNode(m_pTree + 1, 0, z, z, z, z, 0);
+ }
+ else if ( m_levelMod )
+ {
+ m_levelMod = false;
+ clearPoints( );
+ clearNodes( );
+
+ sptNode( m_pTree, 0 );
+ sptNode( m_pTree + 1, 0 );
+
+ pntNode( m_pTree, z, 0, 0, 0, 0, z );
+ pntNode( m_pTree + 1, 0, z, z, z, z, 0 );
+ }
+}
+
+void PMHeightFieldROAM::setDisplayDetail( int detail )
+{
+ if ( detail != m_displayDetail )
+ {
+ m_displayDetail = detail;
+ m_levelMod = true;
+ }
+}
+
+void PMHeightFieldROAM::setWaterLevel( double waterLevel )
+{
+ int waterConv = (int)( waterLevel * 65535 );
+ if ( waterConv != m_waterLevel )
+ {
+ m_waterLevel = waterConv;
+ m_levelMod = true;
+ }
+}
+
+double PMHeightFieldROAM::waterLevel( ) const
+{
+ double waterConv = m_waterLevel / 65535.0;
+ return waterConv;
+}
+
+unsigned short PMHeightFieldROAM::height( int x, int y, bool waterLevel ) const
+{
+ unsigned short hgt = m_pPoints[ x + ( y * m_size ) ].hgt;
+ if ( waterLevel )
+ {
+ if ( hgt <= m_waterLevel )
+ return m_waterLevel;
+ else
+ return hgt;
+ }
+ else
+ return hgt;
+}
+
+bool PMHeightFieldROAM::lineExist( int x, int y, int line ) const
+{
+ if ( m_pPoints[ x + ( y * m_size ) ].lines[ line ] ) return true;
+ else return false;
+}
+
+bool PMHeightFieldROAM::imageToData(const QString &fileName)
+{
+ QImage scaledMap;
+ QImage mapFile( fileName );
+
+ if ( mapFile.isNull( ) )
+ return false;
+
+ if ( mapFile.width( ) > 192 || mapFile.height( ) > 192 )
+ {
+ scaledMap = mapFile.scale( 257, 257 );
+ }
+ else if ( mapFile.width( ) > 96 || mapFile.height( ) > 96 )
+ {
+ scaledMap = mapFile.scale( 129, 129 );
+ }
+ else if ( mapFile.width( ) > 48 || mapFile.height( ) > 48)
+ {
+ scaledMap = mapFile.scale( 65, 65 );
+ }
+ else
+ {
+ scaledMap = mapFile.scale( 33, 33 );
+ }
+
+ if ( scaledMap.isNull( ) )
+ return false;
+
+ m_size = scaledMap.width( );
+ if ( !createPoints( ) || !createNodes( ) )
+ return false;
+
+ bool colourIndex;
+
+ if ( mapFile.depth( ) > 8 )
+ colourIndex = false;
+ else
+ {
+ scaledMap = scaledMap.convertDepthWithPalette( 8, mapFile.colorTable( ), 256 );
+ colourIndex = true;
+ }
+
+ for ( int y = 0, y2 = ( m_size - 1 ) ; y < m_size ; ++y, --y2 )
+ {
+ for ( int x = 0 ; x < m_size ; ++x )
+ {
+ if ( colourIndex )
+ setHeight( x, y2, scaledMap.pixelIndex( x, y ) * 256 );
+ else
+ setHeight( x, y2, ( 256 * qRed( scaledMap.pixel( x, y ) ) ) +
+ qGreen( scaledMap.pixel( x, y ) ) );
+ }
+ }
+
+ return true;
+}
+
+void PMHeightFieldROAM::calcLevel( )
+{
+ int i = 0;
+ int j = m_size;
+
+ while( j != 1)
+ {
+ j /= 2;
+ i++;
+ }
+ m_maxLevel = i * 2;
+}
+
+void PMHeightFieldROAM::varNode ( triNodeStructure* current,
+ int x1, int y1,
+ int x2, int y2,
+ int x3, int y3,
+ int level )
+{
+ int xm = (x1 + x3) >> 1;
+ int ym = (y1 + y3) >> 1;
+
+ if ( level >= m_maxLevel )
+ {
+ unsigned short z1 = height( x1, y1 );
+ unsigned short z3 = height( x3, y3 );
+
+ unsigned short zm = ( ( z3 - z1 ) / 2 ) + z1;
+ unsigned short hgt = height( xm, ym );
+
+ current->vari = abs( zm - hgt );
+ return;
+ }
+
+ current->lchd = m_pNextNode++;
+ current->rchd = m_pNextNode++;
+
+ varNode(current->lchd, x3, y3, xm, ym, x2, y2, level + 1);
+ varNode(current->rchd, x2, y2, xm, ym, x1, y1, level + 1);
+
+ current->vari = current->lchd->vari + current->rchd->vari;
+}
+
+void PMHeightFieldROAM::sptNode ( triNodeStructure* current, int level )
+{
+ if ( !current->split )
+ {
+ if ( level >= m_maxLevel ) return;
+
+ if (current->vari > m_displayDetail) split(current);
+ else return;
+ }
+
+ sptNode(current->lchd, level + 1);
+ sptNode(current->rchd, level + 1);
+}
+
+void PMHeightFieldROAM::split( triNodeStructure* current )
+{
+ current->split = true;
+
+ if ( current->base )
+ {
+ if ( current->base->base != current ) split( current->base );
+ }
+
+ triNodeStructure* child;
+
+ //left child
+ child = current->lchd;
+ child->base = current->lnbr;
+ if ( current->lnbr )
+ {
+ if ( current->lnbr->rnbr == current ) current->lnbr->rnbr = child;
+ else current->lnbr->base = child;
+ }
+ child->lnbr = current->rchd;
+
+ //rightchild
+ child = current->rchd;
+ child->base = current->rnbr;
+ if ( current->rnbr )
+ {
+ if ( current->rnbr->lnbr == current ) current->rnbr->lnbr = child;
+ else current->rnbr->base = child;
+ }
+ child->rnbr = current->lchd;
+
+ if ( current->base )
+ {
+ if ( !current->base->split ) split( current->base );
+ current->lchd->rnbr = current->base->rchd;
+ current->rchd->lnbr = current->base->lchd;
+ }
+}
+
+void PMHeightFieldROAM::pntNode( triNodeStructure* current,
+ int x1, int y1,
+ int x2, int y2,
+ int x3, int y3 )
+{
+ if (current->split)
+ {
+ int xm = (x1 + x3) >> 1;
+ int ym = (y1 + y3) >> 1;
+ pntNode( current->lchd, x3, y3, xm, ym, x2, y2 );
+ pntNode( current->rchd, x2, y2, xm, ym, x1, y1 );
+ }
+ else
+ {
+ pointStructure* pts[3];
+ pts[0] = &m_pPoints[ x1 + ( y1 * m_size ) ];
+ pts[1] = &m_pPoints[ x2 + ( y2 * m_size ) ];
+ pts[2] = &m_pPoints[ x3 + ( y3 * m_size ) ];
+
+ if ( m_waterLevel != 0 )
+ {
+ if ( pts[0]->hgt <= m_waterLevel &&
+ pts[1]->hgt <= m_waterLevel &&
+ pts[2]->hgt <= m_waterLevel )
+ return;
+ }
+
+ for ( int i = 0 ; i < 3 ; ++i )
+ {
+ if ( !pts[i]->used )
+ {
+ pts[i]->pos = m_usedPoints++;
+ pts[i]->used = true;
+ }
+ }
+
+ addLine( pts[0], pts[1] );
+ addLine( pts[1], pts[2] );
+ addLine( pts[2], pts[0] );
+ }
+}
+
+void PMHeightFieldROAM::addLine( pointStructure* pts1, pointStructure* pts2 )
+{
+ for ( int i = 0 ; i < 8 ; ++i )
+ {
+ if ( pts1->lines[i] )
+ {
+ if ( pts1->lines[i] == pts2 ) return;
+ }
+ else
+ {
+ for ( int j = 0 ; pts2->lines[j] ; ++j )
+ {
+ if ( pts2->lines[j] == pts1 ) return;
+ }
+ pts1->lines[i] = pts2;
+ m_numLines++;
+ return;
+ }
+ }
+}
+
+bool PMHeightFieldROAM::createPoints( )
+{
+ m_numPoints = m_size * m_size;
+ m_pPoints = new( std::nothrow ) pointStructure[ m_numPoints ];
+ if ( !m_pPoints )
+ return false;
+ else
+ {
+ clearPoints( true );
+ return true;
+ }
+}
+
+void PMHeightFieldROAM::clearPoints( bool all )
+{
+ int i, j;
+ for ( i = 0 ; i < m_numPoints ; ++i )
+ {
+ if ( all )
+ {
+ m_pPoints[i].hgt = 0;
+ m_pPoints[i].pos = 0;
+ }
+ for ( j = 0 ; j < 8 ; ++j )
+ m_pPoints[i].lines[j] = 0;
+ m_pPoints[i].used = false;
+ }
+
+ m_usedPoints = m_numLines = 0;
+}
+
+bool PMHeightFieldROAM::createNodes( )
+{
+ m_numNodes = ( ( m_size - 1 ) * ( 4 * ( m_size - 1 ) ) ) - 2;
+ m_pTree = new( std::nothrow ) triNodeStructure[ m_numNodes ];
+ if ( !m_pTree )
+ return false;
+ else
+ {
+ clearNodes( true );
+ return true;
+ }
+}
+
+void PMHeightFieldROAM::clearNodes( bool all )
+{
+ m_pNextNode = m_pTree;
+ for ( int i = 0; i < m_numNodes; ++i )
+ {
+ if ( all )
+ {
+ m_pNextNode->lchd = 0;
+ m_pNextNode->rchd = 0;
+ m_pNextNode->base = 0;
+ m_pNextNode->lnbr = 0;
+ m_pNextNode->rnbr = 0;
+ m_pNextNode->vari = 0;
+ }
+ m_pNextNode->split = false;
+ m_pNextNode++;
+ }
+}
diff --git a/kpovmodeler/pmheightfieldroam.h b/kpovmodeler/pmheightfieldroam.h
new file mode 100644
index 00000000..e2802c6b
--- /dev/null
+++ b/kpovmodeler/pmheightfieldroam.h
@@ -0,0 +1,283 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+#ifndef PMHEIGHTFIELDROAM_H
+#define PMHEIGHTFIELDROAM_H
+
+class QString;
+
+/**
+ * ROAM display class for @ref PMHeightField
+*/
+class PMHeightFieldROAM
+{
+ int m_size;
+ int m_numPoints;
+ int m_usedPoints;
+ int m_numLines;
+ int m_numNodes;
+ bool m_fail;
+ int m_maxLevel;
+ int m_displayDetail;
+ int m_waterLevel;
+ bool m_mapMod;
+ bool m_levelMod;
+
+ /**
+ * Point Structure holds most of the info
+ */
+ struct pointStructure
+ {
+ unsigned short hgt;
+ pointStructure* lines[ 8 ];
+ int pos;
+ bool used;
+ };
+ /**
+ * The points array
+ */
+ pointStructure* m_pPoints;
+
+ /**
+ * The Triangle Node structure used in the ROAM algorithm
+ */
+ struct triNodeStructure
+ {
+ triNodeStructure* lchd;
+ triNodeStructure* rchd;
+ triNodeStructure* base;
+ triNodeStructure* lnbr;
+ triNodeStructure* rnbr;
+ int vari;
+ bool split;
+ };
+ /**
+ * Tree Root node
+ */
+ triNodeStructure* m_pTree;
+ /**
+ * Next available node
+ */
+ triNodeStructure* m_pNextNode;
+
+ /**
+ * Loads and formats the image to the correct size, creates the points
+ * array. Then fills the points array with the heights and zero's the
+ * rest of the info
+ * @param filename The name of the file to load
+ * @return true if succesful false it it fails
+ */
+ bool imageToData( const QString &fileName );
+
+ /**
+ * Sets the Maximum Level of the tree.
+ */
+ void calcLevel( );
+
+ /**
+ * Generates the Variance for each node.
+ * @param current The current node
+ * @param x1-y1 The position of the first corner
+ * @param x2-y2 The position of the second corner
+ * @param x3-y3 The position of the third corner
+ * @param level The current level within a tree
+ */
+ void varNode( triNodeStructure* current,
+ int x1, int y1,
+ int x2, int y2,
+ int x3, int y3,
+ int level );
+
+ /**
+ * Generates the Split for the Tree.
+ * @param current The current node
+ * @param level The current level within a tree
+ */
+ void sptNode( triNodeStructure* current, int level );
+
+ /**
+ * Request the splitting of a node, checks too see if it can be
+ * Split or if its base neighbour requires splitting.
+ * @param current node to split
+ */
+ void split( triNodeStructure* current );
+
+ /**
+ * Counts up the lines and points in a model, and sets the points
+ * structure ready for returning
+ * @param current The current node
+ * @param x1-y1 The position of the first corner
+ * @param x2-y2 The position of the second corner
+ * @param x3-y3 The position of the third corner
+ */
+ void pntNode( triNodeStructure* current,
+ int x1, int y1,
+ int x2, int y2,
+ int x3, int y3 );
+
+ /**
+ * Adds a line makes sure that this line does not already exist
+ * @param pts1 The start point in the line
+ * @param pts2 The end point of the line
+ */
+ void addLine( pointStructure* pts1, pointStructure* pts2 );
+
+ /**
+ * creates the points array and clears it
+ * @return true if succesful
+ */
+ bool createPoints( );
+ /**
+ * Clears some of the points data for recalculation or all
+ * of it for initialization
+ * @param all true if all the data is to be cleared
+ */
+ void clearPoints( bool all = false );
+
+ /**
+ * creates the nodes array and clears it
+ * @return true if succesful
+ */
+ bool createNodes( );
+ /**
+ * Clears nodes for reuse in splitting recalculation or
+ * all of the data for initialization and variance
+ * @param all true if all the data is to be cleared
+ */
+ void clearNodes( bool all = false );
+
+ /**
+ * Sets the height of a point
+ * @param x the position of the point in X
+ * @param y the position of the point in Y
+ * @param hgt the new height
+ */
+ void setHeight( int x, int y, unsigned short hgt ) const
+ { m_pPoints[ x + ( y * m_size ) ].hgt = hgt; }
+
+public:
+ /**
+ * Constructor for class
+ * @param fileName Source file for the map
+ */
+ PMHeightFieldROAM( const QString &fileName );
+ /**
+ * Class Destructor relases all the memory
+ */
+ ~PMHeightFieldROAM( );
+
+ /**
+ * Returns true if there has been a problem
+ */
+ bool isFailed( ) { return m_fail; }
+
+ /**
+ * Creates the model based on the current map
+ * display detail and water level
+ */
+ void updateModel( );
+
+ /**
+ * Sets the display detail for the model
+ * @param detail The new level of detail
+ */
+ void setDisplayDetail( int detail );
+ /**
+ * Returns the current display detail
+ */
+ int displayDetail( ) const { return m_displayDetail; }
+
+ /**
+ * Sets the water level
+ * @param waterLevel the water level
+ */
+ void setWaterLevel( double m_waterLevel );
+ /**
+ * Returns the current water level
+ */
+ double waterLevel( ) const;
+
+ /**
+ * Return The size of the map in either direction
+ */
+ int size( ) const { return m_size; }
+ /**
+ * Return The total number of points in the model
+ */
+ int numPoints( ) const { return m_numPoints; }
+ /**
+ * Return The number of used points
+ */
+ int usedPoints( ) const { return m_usedPoints; }
+ /**
+ * Return The number of lines
+ */
+ int numLines( ) const { return m_numLines; }
+ /**
+ * Return the number of nodes
+ */
+ int numNodes( ) const { return m_numNodes; }
+
+ /**
+ * Returns a height of a point
+ * @param x the position of the point in X
+ * @param y the position of the point in Y
+ * @param waterLevel whether to return a point offset by water level
+ * @return the height of the point
+ */
+ unsigned short height( int x, int y, bool waterLevel = false ) const;
+
+ /**
+ * Determines if the point is used
+ * @param x The position of the point on the x axis.
+ * @param y The position of the point on the y axis.
+ * @return true if the point is used else false
+ */
+ bool usedPoint( int x, int y ) const
+ { return m_pPoints[ x + ( y * m_size ) ].used; }
+
+ /**
+ * Gets the used postion of a point
+ * @param x The position of the point on the x axis.
+ * @param y The position of the point on the y axis.
+ * @return the used position
+ */
+ int posPoint( int x, int y ) const
+ { return m_pPoints[ x + ( y * m_size ) ].pos; }
+
+ /**
+ * Returns the used position of a point at the end point of a line.
+ * @param x The position of the start point on the x axis.
+ * @param y The position of the start point on the y axis.
+ * @param line The Line Index
+ * @return The used positon of the end point
+ */
+ int endPoint( int x, int y, int line ) const
+ { return m_pPoints[ x + ( y * m_size ) ].lines[ line ]->pos; }
+
+ /**
+ * Returns whether this line exists
+ * @param x The position of the start point on the x axis.
+ * @param y The position of the start point on the y axis.
+ * @param line The Line Index
+ * @return Whether the line exists
+ */
+ bool lineExist( int x, int y, int line ) const;
+
+};
+
+#endif
diff --git a/kpovmodeler/pmimagemap.cpp b/kpovmodeler/pmimagemap.cpp
new file mode 100644
index 00000000..7fcaeb64
--- /dev/null
+++ b/kpovmodeler/pmimagemap.cpp
@@ -0,0 +1,522 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Passos Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmimagemapedit.h"
+#include "pmimagemap.h"
+#include "pmpalettevalue.h"
+#include "pmpalettevaluememento.h"
+
+#include "pmxmlhelper.h"
+#include "pmcompositeobject.h"
+#include "pmmemento.h"
+#include "pmenumproperty.h"
+
+#include <klocale.h>
+
+const PMImageMap::PMBitmapType bitmapTypeDefault = PMImageMap::BitmapSys;
+const char *const bitmapFileDefault = 0;
+const bool enableFilterAllDefault = false;
+const bool enableTransmitAllDefault = false;
+const double filterAllDefault = 0.0;
+const double transmitAllDefault = 0.0;
+const bool onceDefault = false;
+const PMImageMap::PMMapType mapTypeDefault = PMImageMap::MapPlanar;
+const PMImageMap::PMInterpolateType interpolateTypeDefault = PMImageMap::InterpolateNone;
+
+PMDefinePropertyClass( PMImageMap, PMImageMapProperty );
+PMDefineEnumPropertyClass( PMImageMap, PMImageMap::PMBitmapType,
+ PMBitmapTypeProperty );
+PMDefineEnumPropertyClass( PMImageMap, PMImageMap::PMInterpolateType,
+ PMInterpolateTypeProperty );
+PMDefineEnumPropertyClass( PMImageMap, PMImageMap::PMMapType,
+ PMMapTypeProperty );
+
+PMMetaObject* PMImageMap::s_pMetaObject = 0;
+PMObject* createNewImageMap( PMPart* part )
+{
+ return new PMImageMap( part );
+}
+
+PMImageMap::PMImageMap( PMPart* part )
+ : Base( part )
+{
+ m_bitmapType = bitmapTypeDefault;
+ m_bitmapFile = bitmapFileDefault;
+ m_enableFilterAll = enableFilterAllDefault;
+ m_filterAll = filterAllDefault;
+ m_enableTransmitAll = enableTransmitAllDefault;
+ m_transmitAll = transmitAllDefault;
+ m_once = onceDefault;
+ m_mapType = mapTypeDefault;
+ m_interpolateType = interpolateTypeDefault;
+}
+
+PMImageMap::PMImageMap( const PMImageMap& m )
+ : Base( m )
+{
+ m_bitmapType = m.m_bitmapType;
+ m_bitmapFile = m.m_bitmapFile;
+ m_enableFilterAll = m.m_enableFilterAll;
+ m_filterAll = m.m_filterAll;
+ m_enableTransmitAll = m.m_enableTransmitAll;
+ m_transmitAll = m.m_transmitAll;
+ m_once = m.m_once;
+ m_mapType = m.m_mapType;
+ m_interpolateType = m.m_interpolateType;
+ m_filters = m.m_filters;
+ m_transmits = m.m_transmits;
+}
+
+PMImageMap::~PMImageMap( )
+{
+}
+
+void PMImageMap::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ switch( m_bitmapType )
+ {
+ case BitmapGif:
+ e.setAttribute( "bitmap_type", "gif" );
+ break;
+ case BitmapTga:
+ e.setAttribute( "bitmap_type", "tga" );
+ break;
+ case BitmapIff:
+ e.setAttribute( "bitmap_type", "iff" );
+ break;
+ case BitmapPpm:
+ e.setAttribute( "bitmap_type", "ppm" );
+ break;
+ case BitmapPgm:
+ e.setAttribute( "bitmap_type", "pgm" );
+ break;
+ case BitmapPng:
+ e.setAttribute( "bitmap_type", "png" );
+ break;
+ case BitmapJpeg:
+ e.setAttribute( "bitmap_type", "jpeg" );
+ break;
+ case BitmapTiff:
+ e.setAttribute( "bitmap_type", "tiff" );
+ break;
+ case BitmapSys:
+ e.setAttribute( "bitmap_type", "sys" );
+ break;
+ }
+ e.setAttribute( "file_name", m_bitmapFile );
+ e.setAttribute( "enable_filter_all", m_enableFilterAll );
+ e.setAttribute( "filter_all", m_filterAll );
+ e.setAttribute( "enable_transmit_all", m_enableTransmitAll );
+ e.setAttribute( "transmit_all", m_transmitAll );
+ e.setAttribute( "once", m_once );
+
+ QDomElement extra_data = doc.createElement( "extra_data" );
+
+ QDomElement data = doc.createElement( "indexed_filters" );
+ QDomElement p;
+
+ QValueList<PMPaletteValue>::ConstIterator it;
+ for( it = m_filters.begin( ); it != m_filters.end( ); ++it )
+ {
+ p = doc.createElement( "index_filter" );
+ ( *it ).serialize( p, doc );
+ data.appendChild( p );
+ }
+ extra_data.appendChild( data );
+
+ data = doc.createElement( "indexed_transmits" );
+ for( it = m_transmits.begin( ); it != m_transmits.end( ); ++it )
+ {
+ p = doc.createElement( "index_transmit" );
+ ( *it ).serialize( p, doc );
+ data.appendChild( p );
+ }
+ extra_data.appendChild( data );
+
+ e.appendChild( extra_data );
+
+ switch( m_mapType )
+ {
+ case MapPlanar:
+ e.setAttribute( "map_type", "planar" );
+ break;
+ case MapSpherical:
+ e.setAttribute( "map_type", "spherical" );
+ break;
+ case MapCylindrical:
+ e.setAttribute( "map_type", "cylindrical" );
+ break;
+ case MapToroidal:
+ e.setAttribute( "map_type", "toroidal" );
+ break;
+ }
+ switch( m_interpolateType )
+ {
+ case InterpolateNone:
+ e.setAttribute( "interpolate", "none" );
+ break;
+ case InterpolateBilinear:
+ e.setAttribute( "interpolate", "bilinear" );
+ break;
+ case InterpolateNormalized:
+ e.setAttribute( "interpolate", "normalized" );
+ break;
+ }
+ Base::serialize( e, doc );
+}
+
+void PMImageMap::readAttributes( const PMXMLHelper& h )
+{
+ QString str;
+
+ str = h.stringAttribute( "bitmap_type", "sys" );
+ if( str == "gif" )
+ m_bitmapType = BitmapGif;
+ else if( str == "tga" )
+ m_bitmapType = BitmapTga;
+ else if( str == "iff" )
+ m_bitmapType = BitmapIff;
+ else if( str == "ppm" )
+ m_bitmapType = BitmapPpm;
+ else if( str == "pgm" )
+ m_bitmapType = BitmapPgm;
+ else if( str == "png" )
+ m_bitmapType = BitmapPng;
+ else if( str == "jpeg" )
+ m_bitmapType = BitmapJpeg;
+ else if( str == "tiff" )
+ m_bitmapType = BitmapTiff;
+ else if( str == "sys" )
+ m_bitmapType = BitmapSys;
+
+ m_bitmapFile = h.stringAttribute( "file_name", bitmapFileDefault );
+ m_enableFilterAll = h.boolAttribute( "enable_filter_all", enableFilterAllDefault );
+ m_filterAll = h.doubleAttribute( "filter_all", filterAllDefault );
+ m_enableTransmitAll = h.boolAttribute( "enable_transmit_all", enableTransmitAllDefault );
+ m_transmitAll = h.doubleAttribute( "transmit_all", transmitAllDefault );
+ m_once = h.boolAttribute( "once", onceDefault );
+
+ QDomElement e = h.extraData( );
+ if( !e.isNull( ) )
+ {
+ QDomNode c = e.firstChild( );
+ while( !c.isNull( ) )
+ {
+ if( c.isElement( ) )
+ {
+ QDomElement ce = c.toElement( );
+ if( ce.tagName( ) == "indexed_filters" )
+ {
+ m_filters.clear( );
+ QDomNode cd = ce.firstChild( );
+ while( !cd.isNull( ) )
+ {
+ if( cd.isElement( ) )
+ {
+ PMPaletteValue pv;
+ pv.readAttributes( cd.toElement( ) );
+ m_filters.append( pv );
+ }
+ cd = cd.nextSibling( );
+ }
+ }
+ if( ce.tagName( ) == "indexed_transmits" )
+ {
+ m_transmits.clear( );
+ QDomNode cd = ce.firstChild( );
+ while( !cd.isNull( ) )
+ {
+ if( cd.isElement( ) )
+ {
+ PMPaletteValue pv;
+ pv.readAttributes( cd.toElement( ) );
+ m_transmits.append( pv );
+ }
+ cd = cd.nextSibling( );
+ }
+ }
+ }
+ c = c.nextSibling( );
+ }
+ }
+
+ str = h.stringAttribute( "map_type", "planar" );
+ if( str == "planar" )
+ m_mapType = MapPlanar;
+ else if( str == "spherical" )
+ m_mapType = MapSpherical;
+ else if( str == "cylindrical" )
+ m_mapType = MapCylindrical;
+ else if( str == "toroidal" )
+ m_mapType = MapToroidal;
+
+ str = h.stringAttribute( "interpolate", "none" );
+ if( str == "none" )
+ m_interpolateType = InterpolateNone;
+ else if( str == "bilinear" )
+ m_interpolateType = InterpolateBilinear;
+ else if( str == "normalized" )
+ m_interpolateType = InterpolateNormalized;
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMImageMap::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "ImageMap", Base::metaObject( ),
+ createNewImageMap );
+
+ PMBitmapTypeProperty* bp = new PMBitmapTypeProperty(
+ "bitmapType", &PMImageMap::setBitmapType, &PMImageMap::bitmapType );
+ bp->addEnumValue( "Gif", BitmapGif );
+ bp->addEnumValue( "Tga", BitmapTga );
+ bp->addEnumValue( "Iff", BitmapIff );
+ bp->addEnumValue( "Ppm", BitmapPpm );
+ bp->addEnumValue( "Pgm", BitmapPgm );
+ bp->addEnumValue( "Png", BitmapPng );
+ bp->addEnumValue( "Jpeg", BitmapJpeg );
+ bp->addEnumValue( "Tiff", BitmapTiff );
+ bp->addEnumValue( "Sys", BitmapSys );
+ s_pMetaObject->addProperty( bp );
+
+ PMInterpolateTypeProperty* ip = new PMInterpolateTypeProperty(
+ "interpolateType", &PMImageMap::setInterpolateType,
+ &PMImageMap::interpolateType );
+ ip->addEnumValue( "None", InterpolateNone );
+ ip->addEnumValue( "Bilinear", InterpolateBilinear );
+ ip->addEnumValue( "Normalized", InterpolateNormalized );
+ s_pMetaObject->addProperty( ip );
+
+ PMMapTypeProperty* mp = new PMMapTypeProperty(
+ "mapType", &PMImageMap::setMapType, &PMImageMap::mapType );
+ mp->addEnumValue( "Planar", MapPlanar );
+ mp->addEnumValue( "Spherical", MapSpherical );
+ mp->addEnumValue( "Cylindrical", MapCylindrical );
+ mp->addEnumValue( "Toroidal", MapToroidal );
+ s_pMetaObject->addProperty( mp );
+
+ s_pMetaObject->addProperty(
+ new PMImageMapProperty( "bitmapFile", &PMImageMap::setBitmapFileName,
+ &PMImageMap::bitmapFile ) );
+ s_pMetaObject->addProperty(
+ new PMImageMapProperty( "filterAllEnabled", &PMImageMap::enableFilterAll,
+ &PMImageMap::isFilterAllEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMImageMapProperty( "filterAll", &PMImageMap::setFilterAll,
+ &PMImageMap::filterAll ) );
+ s_pMetaObject->addProperty(
+ new PMImageMapProperty( "transmitAllEnabled", &PMImageMap::enableTransmitAll,
+ &PMImageMap::isTransmitAllEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMImageMapProperty( "transmitAll", &PMImageMap::setTransmitAll,
+ &PMImageMap::transmitAll ) );
+ s_pMetaObject->addProperty(
+ new PMImageMapProperty( "once", &PMImageMap::enableOnce, &PMImageMap::isOnceEnabled ) );
+
+ // TODO: filters and transmits properties
+ }
+ return s_pMetaObject;
+}
+
+void PMImageMap::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMImageMap::description( ) const
+{
+ return i18n( "imagemap" );
+}
+
+void PMImageMap::setBitmapType( PMBitmapType c )
+{
+ if( c != m_bitmapType )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMBitmapTypeID, m_bitmapType );
+ m_bitmapType = c;
+ }
+}
+
+void PMImageMap::setBitmapFileName( const QString& c )
+{
+ if( c != m_bitmapFile )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMBitmapFileID, m_bitmapFile );
+ m_bitmapFile = c;
+ }
+}
+
+void PMImageMap::enableFilterAll( bool c )
+{
+ if( c != m_enableFilterAll )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableFilterAllID, m_enableFilterAll );
+ m_enableFilterAll = c;
+ }
+}
+
+void PMImageMap::enableTransmitAll( bool c )
+{
+ if( c != m_enableTransmitAll )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableTransmitAllID, m_enableTransmitAll );
+ m_enableTransmitAll = c;
+ }
+}
+
+void PMImageMap::setFilterAll( double c )
+{
+ if( c != m_filterAll )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFilterAllID, m_filterAll );
+ m_filterAll = c;
+ }
+}
+
+void PMImageMap::setTransmitAll( double c )
+{
+ if( c != m_transmitAll )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFilterAllID, m_transmitAll );
+ m_transmitAll = c;
+ }
+}
+
+void PMImageMap::enableOnce( bool c )
+{
+ if( c != m_once )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMOnceID, m_once );
+ m_once = c;
+ }
+}
+
+void PMImageMap::setMapType( PMMapType c )
+{
+ if( c != m_mapType )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMMapTypeID, m_mapType );
+ m_mapType = c;
+ }
+}
+
+void PMImageMap::setInterpolateType( PMInterpolateType c )
+{
+ if( c != m_interpolateType )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMInterpolateID, m_interpolateType );
+ m_interpolateType = c;
+ }
+}
+
+void PMImageMap::setFilters( const QValueList<PMPaletteValue>& c )
+{
+ if( m_filters != c )
+ {
+ if( m_pMemento )
+ ( ( PMPaletteValueMemento* ) m_pMemento )->setFilterPaletteValues( m_filters );
+ m_filters = c;
+ }
+}
+
+void PMImageMap::setTransmits( const QValueList<PMPaletteValue>& c )
+{
+ if( m_transmits != c )
+ {
+ if( m_pMemento )
+ ( ( PMPaletteValueMemento* ) m_pMemento )->setTransmitPaletteValues( m_transmits );
+ m_transmits = c;
+ }
+}
+
+PMDialogEditBase* PMImageMap::editWidget( QWidget* parent ) const
+{
+ return new PMImageMapEdit( parent );
+}
+
+void PMImageMap::restoreMemento( PMMemento* s )
+{
+ PMPaletteValueMemento* m = ( PMPaletteValueMemento* ) s;
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMBitmapTypeID:
+ setBitmapType( ( PMBitmapType )data->intData( ) );
+ break;
+ case PMBitmapFileID:
+ setBitmapFileName( data->stringData( ) );
+ break;
+ case PMEnableFilterAllID:
+ enableFilterAll( data->boolData( ) );
+ break;
+ case PMEnableTransmitAllID:
+ enableTransmitAll( data->boolData( ) );
+ break;
+ case PMFilterAllID:
+ setFilterAll( data->doubleData( ) );
+ break;
+ case PMTransmitAllID:
+ setTransmitAll( data->doubleData( ) );
+ break;
+ case PMOnceID:
+ enableOnce( data->boolData( ) );
+ break;
+ case PMMapTypeID:
+ setMapType( ( PMMapType )data->intData( ) );
+ break;
+ case PMInterpolateID:
+ setInterpolateType( ( PMInterpolateType )data->intData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMImageMap::restoreMemento\n";
+ break;
+ }
+ }
+ }
+
+ if( m->filterPaletteValuesSaved( ) )
+ setFilters( m->filterPaletteValues( ) );
+
+ if( m->transmitPaletteValuesSaved( ) )
+ setTransmits( m->transmitPaletteValues( ) );
+
+ Base::restoreMemento( s );
+}
+
diff --git a/kpovmodeler/pmimagemap.h b/kpovmodeler/pmimagemap.h
new file mode 100644
index 00000000..3291994d
--- /dev/null
+++ b/kpovmodeler/pmimagemap.h
@@ -0,0 +1,209 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Passos Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMIMAGEMAP_H
+#define PMIMAGEMAP_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmnamedobject.h"
+#include "pmpalettevalue.h"
+
+/**
+ * Class for povray imagemaps.
+ */
+
+class PMImageMap : public PMNamedObject
+{
+ typedef PMNamedObject Base;
+public:
+ /**
+ * The bitmap type
+ */
+ enum PMBitmapType { BitmapGif, BitmapTga, BitmapIff, BitmapPpm,
+ BitmapPgm, BitmapPng, BitmapJpeg, BitmapTiff,
+ BitmapSys };
+ /**
+ * The interpolate method
+ */
+ enum PMInterpolateType { InterpolateNone, InterpolateBilinear,
+ InterpolateNormalized };
+ /**
+ * The mapping method
+ */
+ enum PMMapType { MapPlanar, MapSpherical, MapCylindrical,
+ MapToroidal };
+
+ /**
+ * Creates a PMImageMap
+ */
+ PMImageMap( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMImageMap( const PMImageMap& im );
+ /**
+ * deletes the PMImageMap
+ */
+ virtual ~PMImageMap( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMImageMap( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmimagemap" ); }
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMImageMapEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+
+ /**
+ * Gets the bitmap type
+ */
+ PMBitmapType bitmapType( ) const { return m_bitmapType; }
+ /**
+ * Gets the bitmap file name
+ */
+ QString bitmapFile( ) const { return m_bitmapFile; }
+ /**
+ * Returns true if filter all is enabled
+ */
+ bool isFilterAllEnabled( ) const { return m_enableFilterAll; }
+ /**
+ * Gets the value of filter for all colors
+ */
+ double filterAll( ) const { return m_filterAll; }
+ /**
+ * Returns true if transmit all is enabled
+ */
+ bool isTransmitAllEnabled( ) const { return m_enableTransmitAll; }
+ /**
+ * Gets the value of transmit all for all colors
+ */
+ double transmitAll( ) const { return m_transmitAll; }
+ /**
+ * Returns true if once is enabled
+ */
+ bool isOnceEnabled( ) const { return m_once; }
+ /**
+ * Gets the bitmap file type
+ */
+ PMMapType mapType( ) const { return m_mapType; }
+ /**
+ * Gets the interpolate method type
+ */
+ PMInterpolateType interpolateType( ) const { return m_interpolateType; }
+ /**
+ * Gets the list of indexed filters
+ */
+ QValueList<PMPaletteValue> filters( ) const { return m_filters; }
+ /**
+ * Gets the list of indexed transmits
+ */
+ QValueList<PMPaletteValue> transmits( ) const { return m_transmits; }
+
+ /**
+ * Sets the imagemap type
+ */
+ void setBitmapType( PMBitmapType c );
+ /**
+ * Sets the bitmap file name*/
+ void setBitmapFileName( const QString& c );
+ /**
+ * Enables/Disables Filter All
+ */
+ void enableFilterAll( bool c );
+ /**
+ * Sets the filter all value
+ */
+ void setFilterAll( double c );
+ /**
+ * Enables/Disables Transmit All
+ */
+ void enableTransmitAll( bool c );
+ /**
+ * Sets the transmit all value
+ */
+ void setTransmitAll( double c );
+ /**
+ * Sets if the bitmap should be mapped once
+ */
+ void enableOnce( bool c );
+ /**
+ * Sets the mapping method
+ */
+ void setMapType( const PMMapType c );
+ /**
+ * Sets the interpolating method
+ */
+ void setInterpolateType( PMInterpolateType c );
+ /**
+ * Set the list of indexed filters
+ */
+ void setFilters( const QValueList<PMPaletteValue>& filters );
+ /**
+ * Set the list of indexed transmits
+ */
+ void setTransmits( const QValueList<PMPaletteValue>& transmits );
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMImageMapMementoID { PMBitmapTypeID, PMBitmapFileID,
+ PMEnableFilterAllID,
+ PMEnableTransmitAllID,
+ PMFilterAllID, PMTransmitAllID,
+ PMOnceID, PMMapTypeID,
+ PMInterpolateID };
+ /**
+ * ImageMap type
+ */
+ PMBitmapType m_bitmapType;
+ QString m_bitmapFile;
+ bool m_enableFilterAll;
+ float m_filterAll;
+ bool m_enableTransmitAll;
+ float m_transmitAll;
+ bool m_once;
+ PMMapType m_mapType;
+ PMInterpolateType m_interpolateType;
+ QValueList<PMPaletteValue> m_filters;
+ QValueList<PMPaletteValue> m_transmits;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmimagemapedit.cpp b/kpovmodeler/pmimagemapedit.cpp
new file mode 100644
index 00000000..c43443df
--- /dev/null
+++ b/kpovmodeler/pmimagemapedit.cpp
@@ -0,0 +1,625 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Passos Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmimagemapedit.h"
+#include "pmimagemap.h"
+#include "pmvectoredit.h"
+#include "pmlineedits.h"
+#include "pmpalettevalueedit.h"
+#include "pmvector.h"
+
+#include <qwidget.h>
+#include <qlayout.h>
+#include <qcombobox.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+#include <qpushbutton.h>
+#include <qtooltip.h>
+#include <ktabctl.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdialog.h>
+#include <kfiledialog.h>
+#include <kiconloader.h>
+
+PMImageMapEdit::PMImageMapEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMImageMapEdit::createTopWidgets( )
+{
+ QLabel* lbl;
+ QHBoxLayout* hl;
+
+ Base::createTopWidgets( );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ lbl = new QLabel( i18n( "File type:" ), this );
+ m_pImageFileTypeEdit = new QComboBox( this );
+ m_pImageFileTypeEdit->insertItem( "gif" );
+ m_pImageFileTypeEdit->insertItem( "tga" );
+ m_pImageFileTypeEdit->insertItem( "iff" );
+ m_pImageFileTypeEdit->insertItem( "ppm" );
+ m_pImageFileTypeEdit->insertItem( "pgm" );
+ m_pImageFileTypeEdit->insertItem( "png" );
+ m_pImageFileTypeEdit->insertItem( "jpeg" );
+ m_pImageFileTypeEdit->insertItem( "tiff" );
+ m_pImageFileTypeEdit->insertItem( "sys" );
+ hl->addWidget( lbl );
+ hl->addWidget( m_pImageFileTypeEdit );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ lbl = new QLabel( i18n( "File name:" ), this );
+ m_pImageFileNameEdit = new QLineEdit( this );
+ m_pImageFileNameBrowse = new QPushButton( this );
+ m_pImageFileNameBrowse->setPixmap( SmallIcon( "fileopen" ) );
+ hl->addWidget( lbl );
+ hl->addWidget( m_pImageFileNameEdit );
+ hl->addWidget( m_pImageFileNameBrowse );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ m_pEnableFilterAllEdit = new QCheckBox( i18n( "Filter all" ), this );
+ m_pFilterAllEdit = new PMFloatEdit( this );
+ hl->addWidget( m_pEnableFilterAllEdit );
+ hl->addWidget( m_pFilterAllEdit );
+ hl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ m_pEnableTransmitAllEdit = new QCheckBox( i18n( "Transmit all" ), this );
+ m_pTransmitAllEdit = new PMFloatEdit( this );
+ hl->addWidget( m_pEnableTransmitAllEdit );
+ hl->addWidget( m_pTransmitAllEdit );
+ hl->addStretch( 1 );
+
+ m_pOnceEdit = new QCheckBox( i18n( "Once" ), this );
+ topLayout( )->addWidget( m_pOnceEdit );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ lbl = new QLabel( i18n( "Interpolate:" ), this );
+ m_pInterpolateTypeEdit = new QComboBox( this );
+ m_pInterpolateTypeEdit->insertItem( i18n( "None" ) );
+ m_pInterpolateTypeEdit->insertItem( i18n( "Bilinear" ) );
+ m_pInterpolateTypeEdit->insertItem( i18n( "Normalized" ) );
+ hl->addWidget( lbl );
+ hl->addWidget( m_pInterpolateTypeEdit );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ lbl = new QLabel( i18n( "Map type:" ), this );
+ m_pMapTypeEdit = new QComboBox( this );
+ m_pMapTypeEdit->insertItem( i18n( "Planar" ) );
+ m_pMapTypeEdit->insertItem( i18n( "Spherical" ) );
+ m_pMapTypeEdit->insertItem( i18n( "Cylindrical" ) );
+ m_pMapTypeEdit->insertItem( i18n( "Toroidal" ) );
+ hl->addWidget( lbl );
+ hl->addWidget( m_pMapTypeEdit );
+
+ connect( m_pImageFileTypeEdit, SIGNAL( activated( int ) ), SLOT( slotImageFileTypeChanged( int ) ) );
+ connect( m_pMapTypeEdit, SIGNAL( activated( int ) ), SLOT( slotMapTypeChanged( int ) ) );
+ connect( m_pInterpolateTypeEdit, SIGNAL( activated( int ) ), SLOT( slotInterpolateTypeChanged( int ) ) );
+ connect( m_pImageFileNameBrowse, SIGNAL( clicked( ) ), SLOT( slotImageFileBrowseClicked( ) ) );
+ connect( m_pImageFileNameEdit, SIGNAL( textChanged( const QString& ) ), SLOT( slotImageFileNameChanged( const QString& ) ) );
+ connect( m_pEnableFilterAllEdit, SIGNAL( clicked( ) ), SLOT( slotFilterAllClicked( ) ) );
+ connect( m_pEnableTransmitAllEdit, SIGNAL( clicked( ) ), SLOT( slotTransmitAllClicked( ) ) );
+ connect( m_pFilterAllEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pTransmitAllEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pOnceEdit, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMImageMapEdit::createBottomWidgets( )
+{
+ topLayout( )->addWidget( new QLabel( i18n( "Indexed filters" ), this ) );
+ m_pFiltersWidget = new QWidget( this );
+ topLayout( )->addWidget( m_pFiltersWidget );
+ topLayout( )->addWidget( new QLabel( i18n( "Indexed transmits" ), this ) );
+ m_pTransmitsWidget = new QWidget( this );
+ topLayout( )->addWidget( m_pTransmitsWidget );
+
+
+ Base::createBottomWidgets( );
+}
+
+void PMImageMapEdit::displayObject( PMObject* o )
+{
+ bool readOnly;
+
+ if( o->isA( "ImageMap" ) )
+ {
+ m_pDisplayedObject = ( PMImageMap* ) o;
+ readOnly = m_pDisplayedObject->isReadOnly( );
+
+ switch( m_pDisplayedObject->bitmapType( ) )
+ {
+ case PMImageMap::BitmapGif:
+ m_pImageFileTypeEdit->setCurrentItem( 0 );
+ break;
+ case PMImageMap::BitmapTga:
+ m_pImageFileTypeEdit->setCurrentItem( 1 );
+ break;
+ case PMImageMap::BitmapIff:
+ m_pImageFileTypeEdit->setCurrentItem( 2 );
+ break;
+ case PMImageMap::BitmapPpm:
+ m_pImageFileTypeEdit->setCurrentItem( 3 );
+ break;
+ case PMImageMap::BitmapPgm:
+ m_pImageFileTypeEdit->setCurrentItem( 4 );
+ break;
+ case PMImageMap::BitmapPng:
+ m_pImageFileTypeEdit->setCurrentItem( 5 );
+ break;
+ case PMImageMap::BitmapJpeg:
+ m_pImageFileTypeEdit->setCurrentItem( 6 );
+ break;
+ case PMImageMap::BitmapTiff:
+ m_pImageFileTypeEdit->setCurrentItem( 7 );
+ break;
+ case PMImageMap::BitmapSys:
+ m_pImageFileTypeEdit->setCurrentItem( 8 );
+ break;
+ }
+ m_pImageFileTypeEdit->setEnabled( !readOnly );
+
+ switch( m_pDisplayedObject->interpolateType( ) )
+ {
+ case PMImageMap::InterpolateNone:
+ m_pInterpolateTypeEdit->setCurrentItem( 0 );
+ break;
+ case PMImageMap::InterpolateBilinear:
+ m_pInterpolateTypeEdit->setCurrentItem( 1);
+ break;
+ case PMImageMap::InterpolateNormalized:
+ m_pInterpolateTypeEdit->setCurrentItem( 2 );
+ break;
+ }
+ m_pInterpolateTypeEdit->setEnabled( !readOnly );
+
+ switch( m_pDisplayedObject->mapType( ) )
+ {
+ case PMImageMap::MapPlanar:
+ m_pMapTypeEdit->setCurrentItem( 0 );
+ break;
+ case PMImageMap::MapSpherical:
+ m_pMapTypeEdit->setCurrentItem( 1 );
+ break;
+ case PMImageMap::MapCylindrical:
+ m_pMapTypeEdit->setCurrentItem( 2 );
+ break;
+ case PMImageMap::MapToroidal:
+ m_pMapTypeEdit->setCurrentItem( 3 );
+ break;
+ }
+ m_pMapTypeEdit->setEnabled( !readOnly );
+
+ m_pImageFileNameEdit->setText( m_pDisplayedObject->bitmapFile( ) );
+ m_pImageFileNameEdit->setEnabled( !readOnly );
+ m_pOnceEdit->setChecked( m_pDisplayedObject->isOnceEnabled( ) );
+ m_pOnceEdit->setEnabled( !readOnly );
+ m_pEnableFilterAllEdit->setChecked( m_pDisplayedObject->isFilterAllEnabled( ) );
+ m_pEnableFilterAllEdit->setEnabled( !readOnly );
+ m_pFilterAllEdit->setValue( m_pDisplayedObject->filterAll( ) );
+ m_pFilterAllEdit->setReadOnly( readOnly );
+ m_pEnableTransmitAllEdit->setChecked( m_pDisplayedObject->isTransmitAllEnabled( ) );
+ m_pEnableTransmitAllEdit->setEnabled( !readOnly );
+ m_pTransmitAllEdit->setValue( m_pDisplayedObject->transmitAll( ) );
+ m_pTransmitAllEdit->setReadOnly( readOnly );
+
+ displayPaletteEntries( m_pDisplayedObject->filters( ), m_pDisplayedObject->transmits( ) );
+
+ slotFilterAllClicked( );
+ slotTransmitAllClicked( );
+
+ Base::displayObject( o );
+ }
+
+}
+
+void PMImageMapEdit::displayPaletteEntries( const QValueList<PMPaletteValue>& filters,
+ const QValueList<PMPaletteValue>& transmits )
+{
+ bool readOnly = m_pDisplayedObject->isReadOnly( );
+
+ int nfilters = ( int ) filters.count( );
+ int ntransmits = ( int ) transmits.count( );
+
+ int i;
+ PMPaletteValueEdit* edit;
+ QPushButton* button;
+ QGridLayout* gl;
+ QPixmap addButtonPixmap = SmallIcon( "pmaddpoint" );
+ QPixmap removeButtonPixmap = SmallIcon( "pmremovepoint" );
+
+ // First let's deal with the filter entries...
+ if( m_pFiltersWidget->layout( ) )
+ delete m_pFiltersWidget->layout( );
+
+ m_filterEntries.setAutoDelete( true );
+ m_filterAddButtons.setAutoDelete( true );
+ m_filterRemoveButtons.setAutoDelete( true );
+ m_filterEntries.clear( );
+ m_filterAddButtons.clear( );
+ m_filterRemoveButtons.clear( );
+ m_filterEntries.setAutoDelete( false );
+ m_filterAddButtons.setAutoDelete( false );
+ m_filterRemoveButtons.setAutoDelete( false );
+
+ gl = new QGridLayout( m_pFiltersWidget, nfilters + 1, 3, 0, KDialog::spacingHint( ) );
+
+ button = new QPushButton( m_pFiltersWidget );
+ button->setPixmap( addButtonPixmap );
+ m_filterAddButtons.append( button );
+ connect( button, SIGNAL( clicked( ) ), SLOT( slotAddFilterEntry( ) ) );
+ gl->addWidget( button, 0, 1 );
+ button->show( );
+ button->setEnabled( !readOnly );
+ QToolTip::add( button, i18n( "Add new filter" ) );
+
+ for( i = 0; i < nfilters; i ++ )
+ {
+ edit = new PMPaletteValueEdit( m_pFiltersWidget );
+ m_filterEntries.append( edit );
+ connect( edit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ gl->addWidget( edit, i+1, 0 );
+ edit->setIndex( filters[ i ].index( ) );
+ edit->setValue( filters[ i ].value( ) );
+ edit->show( );
+ edit->setReadOnly( readOnly );
+
+ button = new QPushButton( m_pFiltersWidget );
+ button->setPixmap( addButtonPixmap );
+ m_filterAddButtons.append( button );
+ connect( button, SIGNAL( clicked( ) ), SLOT( slotAddFilterEntry( ) ) );
+ gl->addWidget( button, i+1, 1 );
+ button->show( );
+ button->setEnabled( !readOnly );
+ QToolTip::add( button, i18n( "Add new filter" ) );
+
+ button = new QPushButton( m_pFiltersWidget );
+ button->setPixmap( removeButtonPixmap );
+ m_filterRemoveButtons.append( button );
+ connect( button, SIGNAL( clicked( ) ), SLOT( slotRemoveFilterEntry( ) ) );
+ gl->addWidget( button, i+1, 2 );
+ button->show( );
+ button->setEnabled( !readOnly );
+ QToolTip::add( button, i18n( "Remove filter" ) );
+ }
+
+ // ...next the transmit entries
+ m_transmitEntries.setAutoDelete( true );
+ m_transmitAddButtons.setAutoDelete( true );
+ m_transmitRemoveButtons.setAutoDelete( true );
+ m_transmitEntries.clear( );
+ m_transmitAddButtons.clear( );
+ m_transmitRemoveButtons.clear( );
+ m_transmitEntries.setAutoDelete( false );
+ m_transmitAddButtons.setAutoDelete( false );
+ m_transmitRemoveButtons.setAutoDelete( false );
+
+ // recreate the entry edits
+ if( m_pTransmitsWidget->layout( ) )
+ delete m_pTransmitsWidget->layout( );
+
+ gl = new QGridLayout( m_pTransmitsWidget, ntransmits + 1, 3, 0, KDialog::spacingHint( ) );
+
+ button = new QPushButton( m_pTransmitsWidget );
+ button->setPixmap( addButtonPixmap );
+ m_transmitAddButtons.append( button );
+ connect( button, SIGNAL( clicked( ) ), SLOT( slotAddTransmitEntry( ) ) );
+ gl->addWidget( button, 0, 1 );
+ button->show( );
+ button->setEnabled( !readOnly );
+ QToolTip::add( button, i18n( "Add new transmit" ) );
+
+ for( i = 0; i < ntransmits; i ++ )
+ {
+ edit = new PMPaletteValueEdit( m_pTransmitsWidget );
+ m_transmitEntries.append( edit );
+ connect( edit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ gl->addWidget( edit, i+1, 0 );
+ edit->setIndex( transmits[ i ].index( ) );
+ edit->setValue( transmits[ i ].value( ) );
+ edit->show( );
+ edit->setReadOnly( readOnly );
+
+ button = new QPushButton( m_pTransmitsWidget );
+ button->setPixmap( addButtonPixmap );
+ m_transmitAddButtons.append( button );
+ connect( button, SIGNAL( clicked( ) ), SLOT( slotAddTransmitEntry( ) ) );
+ gl->addWidget( button, i+1, 1 );
+ button->show( );
+ button->setEnabled( !readOnly );
+ QToolTip::add( button, i18n( "Add new transmit" ) );
+
+ button = new QPushButton( m_pTransmitsWidget );
+ button->setPixmap( removeButtonPixmap );
+ m_transmitRemoveButtons.append( button );
+ connect( button, SIGNAL( clicked( ) ), SLOT( slotRemoveTransmitEntry( ) ) );
+ gl->addWidget( button, i+1, 2 );
+ button->show( );
+ button->setEnabled( !readOnly );
+ QToolTip::add( button, i18n( "Remove transmit" ) );
+ }
+}
+
+void PMImageMapEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ switch( m_pImageFileTypeEdit->currentItem( ) )
+ {
+ case 0:
+ m_pDisplayedObject->setBitmapType( PMImageMap::BitmapGif );
+ break;
+ case 1:
+ m_pDisplayedObject->setBitmapType( PMImageMap::BitmapTga );
+ break;
+ case 2:
+ m_pDisplayedObject->setBitmapType( PMImageMap::BitmapIff );
+ break;
+ case 3:
+ m_pDisplayedObject->setBitmapType( PMImageMap::BitmapPpm );
+ break;
+ case 4:
+ m_pDisplayedObject->setBitmapType( PMImageMap::BitmapPgm );
+ break;
+ case 5:
+ m_pDisplayedObject->setBitmapType( PMImageMap::BitmapPng );
+ break;
+ case 6:
+ m_pDisplayedObject->setBitmapType( PMImageMap::BitmapJpeg );
+ break;
+ case 7:
+ m_pDisplayedObject->setBitmapType( PMImageMap::BitmapTiff );
+ break;
+ case 8:
+ m_pDisplayedObject->setBitmapType( PMImageMap::BitmapSys );
+ break;
+ }
+
+ switch( m_pInterpolateTypeEdit->currentItem( ) )
+ {
+ case 0:
+ m_pDisplayedObject->setInterpolateType( PMImageMap::InterpolateNone );
+ break;
+ case 1:
+ m_pDisplayedObject->setInterpolateType( PMImageMap::InterpolateBilinear );
+ break;
+ case 2:
+ m_pDisplayedObject->setInterpolateType( PMImageMap::InterpolateNormalized );
+ break;
+ }
+
+ switch( m_pMapTypeEdit->currentItem( ) )
+ {
+ case 0:
+ m_pDisplayedObject->setMapType( PMImageMap::MapPlanar );
+ break;
+ case 1:
+ m_pDisplayedObject->setMapType( PMImageMap::MapSpherical );
+ break;
+ case 2:
+ m_pDisplayedObject->setMapType( PMImageMap::MapCylindrical );
+ break;
+ case 3:
+ m_pDisplayedObject->setMapType( PMImageMap::MapToroidal );
+ break;
+ }
+
+ m_pDisplayedObject->setFilters( filters( ) );
+ m_pDisplayedObject->setTransmits( transmits( ) );
+
+ m_pDisplayedObject->setBitmapFileName( m_pImageFileNameEdit->text( ) );
+ m_pDisplayedObject->enableFilterAll( m_pEnableFilterAllEdit->isChecked( ) );
+ m_pDisplayedObject->setFilterAll( m_pFilterAllEdit->value( ) );
+ m_pDisplayedObject->enableTransmitAll( m_pEnableTransmitAllEdit->isChecked( ) );
+ m_pDisplayedObject->setTransmitAll( m_pTransmitAllEdit->value( ) );
+ m_pDisplayedObject->enableOnce( m_pOnceEdit->isChecked( ) );
+ }
+}
+
+bool PMImageMapEdit::isDataValid( )
+{
+ if( !m_pFilterAllEdit->isDataValid( ) ) return false;
+ if( !m_pTransmitAllEdit->isDataValid( ) ) return false;
+
+ QPtrListIterator<PMPaletteValueEdit> it_filters( m_filterEntries );
+ for( ; it_filters.current( ); ++it_filters )
+ if( !( it_filters.current( )->isDataValid( ) ) )
+ return false;
+
+ QPtrListIterator<PMPaletteValueEdit> it_transmits( m_transmitEntries );
+ for( ; it_transmits.current( ); ++it_transmits )
+ if( !( it_transmits.current( )->isDataValid( ) ) )
+ return false;
+
+ return Base::isDataValid( );
+}
+
+void PMImageMapEdit::slotInterpolateTypeChanged( const int /*a*/ )
+{
+ emit dataChanged( );
+}
+
+void PMImageMapEdit::slotImageFileTypeChanged( const int /*a*/ )
+{
+ emit dataChanged( );
+}
+
+void PMImageMapEdit::slotMapTypeChanged( const int /*a*/ )
+{
+ emit dataChanged( );
+}
+
+void PMImageMapEdit::slotImageFileNameChanged( const QString& /*a*/ )
+{
+ emit dataChanged( );
+}
+
+void PMImageMapEdit::slotImageFileBrowseClicked( )
+{
+ QString str = KFileDialog::getOpenFileName( QString::null, QString::null );
+
+ if( !str.isEmpty() )
+ {
+ m_pImageFileNameEdit->setText( str );
+ emit dataChanged( );
+ }
+}
+
+void PMImageMapEdit::slotFilterAllClicked( )
+{
+ if( m_pEnableFilterAllEdit->isChecked( ) )
+ m_pFilterAllEdit->setEnabled( true );
+ else
+ m_pFilterAllEdit->setEnabled( false );
+ emit sizeChanged( );
+ emit dataChanged( );
+}
+
+void PMImageMapEdit::slotTransmitAllClicked( )
+{
+ if( m_pEnableTransmitAllEdit->isChecked( ) )
+ m_pTransmitAllEdit->setEnabled( true );
+ else
+ m_pTransmitAllEdit->setEnabled( false );
+ emit sizeChanged( );
+ emit dataChanged( );
+}
+
+QValueList<PMPaletteValue> PMImageMapEdit::filters( )
+{
+ QValueList<PMPaletteValue> entries;
+ QPtrListIterator<PMPaletteValueEdit> it( m_filterEntries );
+
+ for( ; it.current( ); ++it )
+ entries.append( PMPaletteValue( it.current( )->index( ), it.current( )->value( ) ) );
+
+ return entries;
+}
+
+QValueList<PMPaletteValue> PMImageMapEdit::transmits( )
+{
+ QValueList<PMPaletteValue> entries;
+ QPtrListIterator<PMPaletteValueEdit> it( m_transmitEntries );
+
+ for( ; it.current( ); ++it )
+ entries.append( PMPaletteValue( it.current( )->index( ), it.current( )->value( ) ) );
+
+ return entries;
+}
+
+void PMImageMapEdit::slotAddFilterEntry( )
+{
+ QValueList<PMPaletteValue> entriesFilters;
+ QValueListIterator<PMPaletteValue> it;
+ PMPaletteValue newEntry;
+ QPushButton* button = ( QPushButton* ) sender( );
+
+ if( button )
+ {
+ int index = m_filterAddButtons.findRef( button );
+ if( index >= 0 )
+ {
+ entriesFilters = filters( );
+ if( index == 0 )
+ entriesFilters.prepend( newEntry );
+ else
+ {
+ it = entriesFilters.at( index );
+ entriesFilters.insert( it, newEntry );
+ }
+ displayPaletteEntries( entriesFilters, transmits( ) );
+ emit sizeChanged( );
+ emit dataChanged( );
+ }
+ }
+}
+
+void PMImageMapEdit::slotRemoveFilterEntry( )
+{
+ QValueList<PMPaletteValue> entriesFilters;
+ QValueListIterator<PMPaletteValue> it;
+ QPushButton* button = ( QPushButton* ) sender( );
+
+ if( button )
+ {
+ int index = m_filterRemoveButtons.findRef( button );
+ if( index >= 0 )
+ {
+ entriesFilters = filters( );
+ it = entriesFilters.at( index );
+ entriesFilters.remove( it );
+ displayPaletteEntries( entriesFilters, transmits( ) );
+ emit sizeChanged( );
+ emit dataChanged( );
+ }
+ }
+}
+
+void PMImageMapEdit::slotAddTransmitEntry( )
+{
+ QValueList<PMPaletteValue> entriesTransmits;
+ QValueListIterator<PMPaletteValue> it;
+ PMPaletteValue newEntry;
+ QPushButton* button = ( QPushButton* ) sender( );
+
+ if( button )
+ {
+ int index = m_transmitAddButtons.findRef( button );
+ if( index >= 0 )
+ {
+ entriesTransmits = transmits( );
+ if( index == 0 )
+ entriesTransmits.prepend( newEntry );
+ else
+ {
+ it = entriesTransmits.at( index );
+ entriesTransmits.insert( it, newEntry );
+ }
+ displayPaletteEntries( filters( ), entriesTransmits );
+ emit sizeChanged( );
+ emit dataChanged( );
+ }
+ }
+}
+
+void PMImageMapEdit::slotRemoveTransmitEntry( )
+{
+ QValueList<PMPaletteValue> entriesTransmits;
+ QValueListIterator<PMPaletteValue> it;
+ QPushButton* button = ( QPushButton* ) sender( );
+
+ if( button )
+ {
+ int index = m_transmitRemoveButtons.findRef( button );
+ if( index >= 0 )
+ {
+ entriesTransmits = transmits( );
+ it = entriesTransmits.at( index );
+ entriesTransmits.remove( it );
+ displayPaletteEntries( filters( ), entriesTransmits );
+ emit sizeChanged( );
+ emit dataChanged( );
+ }
+ }
+}
+
+#include "pmimagemapedit.moc"
diff --git a/kpovmodeler/pmimagemapedit.h b/kpovmodeler/pmimagemapedit.h
new file mode 100644
index 00000000..86055ea2
--- /dev/null
+++ b/kpovmodeler/pmimagemapedit.h
@@ -0,0 +1,121 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Passos Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMIMAGEMAPEDIT_H
+#define PMIMAGEMAPEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmpalettevalueedit.h"
+#include "pmdialogeditbase.h"
+
+class PMImageMap;
+class PMPaletteValue;
+class PMVectorEdit;
+class QComboBox;
+class PMFloatEdit;
+class PMIntEdit;
+class QLabel;
+class QCheckBox;
+class QWidget;
+class QLineEdit;
+class QPushButton;
+
+/**
+ * Dialog edit class for @ref PMImageMap.
+ */
+class PMImageMapEdit : public PMDialogEditBase
+{
+ Q_OBJECT
+ typedef PMDialogEditBase Base;
+public:
+ /**
+ * Creates a PMImageMapEdit with parent and name
+ */
+ PMImageMapEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void createBottomWidgets( );
+ /** */
+ virtual void saveContents( );
+ /** */
+ QValueList<PMPaletteValue> filters( );
+ /** */
+ QValueList<PMPaletteValue> transmits( );
+ /** */
+ void displayPaletteEntries( const QValueList<PMPaletteValue>& filters,
+ const QValueList<PMPaletteValue>& transmits );
+
+private slots:
+ /** */
+ void slotImageFileTypeChanged( int a );
+ /** */
+ void slotMapTypeChanged( int a );
+ /** */
+ void slotInterpolateTypeChanged( int a );
+ /** */
+ void slotImageFileNameChanged( const QString& a );
+ /** */
+ void slotImageFileBrowseClicked( );
+ /** */
+ void slotFilterAllClicked( );
+ /** */
+ void slotTransmitAllClicked( );
+ /** */
+ void slotAddFilterEntry( );
+ /** */
+ void slotRemoveFilterEntry( );
+ /** */
+ void slotAddTransmitEntry( );
+ /** */
+ void slotRemoveTransmitEntry( );
+private:
+ PMImageMap* m_pDisplayedObject;
+ QComboBox* m_pImageFileTypeEdit;
+ QLineEdit* m_pImageFileNameEdit;
+ QPushButton* m_pImageFileNameBrowse;
+ QCheckBox* m_pOnceEdit;
+ QComboBox* m_pMapTypeEdit;
+ QComboBox* m_pInterpolateTypeEdit;
+ QCheckBox* m_pEnableFilterAllEdit;
+ QCheckBox* m_pEnableTransmitAllEdit;
+ PMFloatEdit* m_pFilterAllEdit;
+ PMFloatEdit* m_pTransmitAllEdit;
+ QWidget* m_pFiltersWidget;
+ QWidget* m_pTransmitsWidget;
+
+ QPtrList<PMPaletteValueEdit> m_filterEntries;
+ QPtrList<QPushButton> m_filterAddButtons;
+ QPtrList<QPushButton> m_filterRemoveButtons;
+ QPtrList<PMPaletteValueEdit> m_transmitEntries;
+ QPtrList<QPushButton> m_transmitAddButtons;
+ QPtrList<QPushButton> m_transmitRemoveButtons;
+};
+
+#endif
diff --git a/kpovmodeler/pminserterrordialog.cpp b/kpovmodeler/pminserterrordialog.cpp
new file mode 100644
index 00000000..766db20a
--- /dev/null
+++ b/kpovmodeler/pminserterrordialog.cpp
@@ -0,0 +1,51 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pminserterrordialog.h"
+#include <klocale.h>
+#include <qlabel.h>
+#include <qlistbox.h>
+#include <qvbox.h>
+
+PMInsertErrorDialog::PMInsertErrorDialog(
+ int numObj, int numErrors,
+ const QStringList& details,
+ QWidget* parent /*= 0*/, const char* name /*= 0*/ )
+ : KDialogBase( parent, name, true, i18n( "Insert Errors" ),
+ Help | Ok | User1, Ok, false, i18n( "Details" ) )
+{
+ QVBox* page = makeVBoxMainWidget( );
+ new QLabel( i18n( "%1 of %2 objects couldn't be inserted." )
+ .arg( numErrors ).arg( numObj ), page );
+
+ m_pDetailsLabel = new QLabel( i18n( "Objects not inserted:" ), page );
+ m_pDetailsLabel->hide( );
+
+ m_pDetails = new QListBox( page );
+ m_pDetails->insertStringList( details, 0 );
+ m_pDetails->setMinimumHeight( 150 );
+ m_pDetails->hide( );
+
+}
+
+void PMInsertErrorDialog::slotUser1( )
+{
+ m_pDetailsLabel->show( );
+ m_pDetails->show( );
+}
+#include "pminserterrordialog.moc"
diff --git a/kpovmodeler/pminserterrordialog.h b/kpovmodeler/pminserterrordialog.h
new file mode 100644
index 00000000..d94be0f6
--- /dev/null
+++ b/kpovmodeler/pminserterrordialog.h
@@ -0,0 +1,54 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMINSERTERRORDIALOG_H
+#define PMINSERTERRORDIALOG_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kdialogbase.h>
+#include <qstringlist.h>
+
+class QListBox;
+class QLabel;
+
+/**
+ * Dialog that is shown if not all objects could be inserted
+ during the execution of a command */
+class PMInsertErrorDialog : public KDialogBase
+{
+ Q_OBJECT
+public:
+ /**
+ * Creates a modal PMInsertErrorDialog with parent and name.
+ */
+ PMInsertErrorDialog( int NumberOfObjects, int NumberOfInsertErrors,
+ const QStringList& details,
+ QWidget* parent = 0, const char* name = 0 );
+protected slots:
+ void slotUser1( );
+
+private:
+ QListBox* m_pDetails;
+ QLabel* m_pDetailsLabel;
+};
+
+#endif
diff --git a/kpovmodeler/pminsertpopup.cpp b/kpovmodeler/pminsertpopup.cpp
new file mode 100644
index 00000000..be6a527d
--- /dev/null
+++ b/kpovmodeler/pminsertpopup.cpp
@@ -0,0 +1,90 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pminsertpopup.h"
+#include <klocale.h>
+#include <kiconloader.h>
+#include <qcursor.h>
+
+PMInsertPopup::PMInsertPopup( QWidget* parent, bool multipleObjects,
+ int items, bool canInsertAllAsFirstChildren,
+ bool canInsertAllAsLastChildren,
+ bool canInsertAllAsSiblings, const char* name )
+ : KPopupMenu( parent, name )
+{
+ QString itemText;
+ if( multipleObjects )
+ {
+ insertTitle( i18n( "Insert Objects As" ) );
+ if( ( items & PMIFirstChild ) == PMIFirstChild )
+ {
+ itemText = i18n( "First Children" );
+ if( !canInsertAllAsFirstChildren )
+ itemText += " (" + i18n( "some" ) + ")";
+ insertItem( SmallIcon( "pminsertfirstchild" ),
+ itemText, PMIFirstChild );
+ }
+ if( ( items & PMILastChild ) == PMILastChild )
+ {
+ itemText = i18n( "Last Children" );
+ if( !canInsertAllAsLastChildren )
+ itemText += " (" + i18n( "some" ) + ")";
+ insertItem( SmallIcon( "pminsertlastchild" ),
+ itemText, PMILastChild );
+ }
+ if( ( items & PMISibling ) == PMISibling )
+ {
+ itemText = i18n( "Siblings" );
+ if( !canInsertAllAsSiblings )
+ itemText += " (" + i18n( "some" ) + ")";
+ insertItem( SmallIcon( "pminsertsibling" ),
+ itemText, PMISibling );
+ }
+ }
+ else
+ {
+ insertTitle( i18n( "Insert Object As" ) );
+ if( ( items & PMIFirstChild ) == PMIFirstChild )
+ insertItem( SmallIcon( "pminsertfirstchild" ),
+ i18n( "First Child" ), PMIFirstChild );
+ if( ( items & PMILastChild ) == PMILastChild )
+ insertItem( SmallIcon( "pminsertlastchild" ),
+ i18n( "Last Child" ), PMILastChild );
+ if( ( items & PMISibling ) == PMISibling )
+ insertItem( SmallIcon( "pminsertsibling" ),
+ i18n( "Sibling" ), PMISibling );
+ }
+}
+
+int PMInsertPopup::choosePlace( QWidget* parent, bool multipleObjects,
+ int items, bool canInsertAllAsFirstChildren,
+ bool canInsertAllAsLastChildren,
+ bool canInsertAllAsSiblings )
+{
+ int result;
+ PMInsertPopup* popup = new PMInsertPopup( parent, multipleObjects, items,
+ canInsertAllAsFirstChildren,
+ canInsertAllAsLastChildren,
+ canInsertAllAsSiblings );
+ result = popup->exec( QCursor::pos( ) );
+ if( result < 0 )
+ result = 0;
+ delete popup;
+
+ return result;
+}
diff --git a/kpovmodeler/pminsertpopup.h b/kpovmodeler/pminsertpopup.h
new file mode 100644
index 00000000..c5e99dac
--- /dev/null
+++ b/kpovmodeler/pminsertpopup.h
@@ -0,0 +1,81 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMINSERTPOPUP_H
+#define PMINSERTPOPUP_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kpopupmenu.h>
+
+/**
+ * Popup menu. Ask the user where to insert new objects
+ */
+class PMInsertPopup : public KPopupMenu
+{
+public:
+ /**
+ * Places where a new object can be inserted
+ */
+ enum { PMIFirstChild = 1, PMILastChild = 2, PMISibling = 4 };
+ /**
+ * Creates a popup menu
+ *
+ * @param parent The parent widget
+ * @param multipleObjects True if more than one object will be inserted
+ * @param items Which items to display. Can be a bitwise combination
+ * of PMIFirstChild, PMILastChild, PMISibling.
+ * @param name Internal name of the popup menu
+ */
+ PMInsertPopup( QWidget* parent, bool multipleObjects,
+ int items = PMIFirstChild | PMILastChild | PMISibling,
+ bool canInsertAllAsFirstChildren = true,
+ bool canInsertAllAsLastChildren = true,
+ bool canInsertAllAsSiblings = true,
+ const char* name = 0 );
+ /**
+ * Deletes the popup menu
+ */
+ ~PMInsertPopup( ) { };
+
+ /**
+ * Popups a PMInsertPopup menu
+ *
+ * @param parent The parent widget
+ * @param multipleObjects True if more than one object will be inserted
+ * @param items Which items to display. Can be a bitwise combination
+ * of PMIFirstChild, PMILastChild, PMISibling.
+ * @param canInsertAllAsChildren If false the text "(some)" will appear
+ * behind the "first Children" and "last Children" items
+ * @param canInsertAllAsSiblings If false the text "(some)" will appear
+ * behind the "Siblings" items
+ *
+ * Returns the selected item or 0 if no item was selected.
+ */
+ static int choosePlace( QWidget* parent, bool multipleObjects,
+ int items = PMIFirstChild | PMILastChild
+ | PMISibling,
+ bool canInsertAllAsFirstChildren = true,
+ bool canInsertAllAsLastChildren = true,
+ bool canInsertAllAsSiblings = true );
+};
+
+#endif
diff --git a/kpovmodeler/pminsertrules.dtd b/kpovmodeler/pminsertrules.dtd
new file mode 100644
index 00000000..a3c2128c
--- /dev/null
+++ b/kpovmodeler/pminsertrules.dtd
@@ -0,0 +1,97 @@
+<!-- Simple dtd for kpovmodeler insert rules
+ Autor: Andreas Zehender <zehender@kde.org> -->
+
+<!-- Validation command for xemacs:
+ nsgmls -sv /usr/doc/jade-1.2.1/pubtext/xml.dcl <file> -->
+
+<!-- The root element. -->
+<!ELEMENT insertrules (definegroup*, targetclass+)>
+<!ATTLIST insertrules
+ format CDATA #REQUIRED
+>
+
+<!-- Groups together a list of classes. Groups can be nested. -->
+<!ELEMENT definegroup ((class | group)+)>
+<!ATTLIST definegroup
+ name CDATA #REQUIRED
+>
+
+<!-- Reference to an object class. -->
+<!ELEMENT class EMPTY>
+<!ATTLIST class
+ name CDATA #REQUIRED
+>
+
+<!-- Reference to a defined group. -->
+<!ELEMENT group EMPTY>
+<!ATTLIST group
+ name CDATA #REQUIRED
+>
+
+<!-- Contains the insert rules for one class
+ (the class where the new object is inserted) -->
+<!ELEMENT targetclass (definegroup*, rule+)>
+<!ATTLIST targetclass
+ name CDATA #REQUIRED
+>
+
+<!-- One rule for the current class.
+ Insert a list of groups and classes (the object classes that can be inserted)
+ and one condition. If the condition is omitted,
+ the classes can allways be inserted. -->
+<!ELEMENT rule ((group | class)+, (and | or | not | before | after | contains
+ | greater | less | equal)?)>
+
+<!-- Simple negation. Insert one condition -->
+<!ELEMENT not (and | or | before | after | contains | greater | less | equal)>
+
+<!-- Logical and. Insert any number of conditions -->
+<!ELEMENT and (and | or | not | before | after | contains | greater | less | equal)+>
+
+<!-- Logical or. Insert any number of conditions -->
+<!ELEMENT or (and | or | not | before | after | contains | greater | less | equal)+>
+
+<!-- Condition. Value is true if the object already contains
+ objects of the given class or group before the insert point. -->
+<!ELEMENT before (class | group)>
+
+<!-- Condition. Value is true if the object already contains
+ objects of the given class or group after the insert point. -->
+<!ELEMENT after (class | group)>
+
+<!-- Condition. Value is true if the two values (child xml tags)
+ are equal. -->
+<!ELEMENT equal ((property | count | const), (property | count | const))>
+
+<!-- Condition. Value is true if the first value (child xml tag)
+ is greater than the second. -->
+<!ELEMENT greater ((property | count | const), (property | count | const))>
+
+<!-- Condition. Value is true if the first value (child xml tag)
+ is less than the second. -->
+<!ELEMENT less ((property | count | const), (property | count | const))>
+
+<!-- Condition. Value is true if the object contains
+ objects of the given classes and groups. -->
+<!ELEMENT contains (group | class)+>
+
+
+<!-- Value. Value is the class property of the object, where the
+ new object should be inserted into. -->
+<!ELEMENT property EMPTY>
+<!ATTLIST property
+ name CDATA #REQUIRED
+>
+
+<!-- Value. Defines a constant (number or string). -->
+<!ELEMENT const EMPTY>
+<!ATTLIST const
+ value CDATA #REQUIRED
+>
+
+<!-- Value. Counts the number of already inserted instances of the given
+ groups or classes. -->
+<!ELEMENT count (group | class)+>
+
+
+
diff --git a/kpovmodeler/pminsertrulesystem.cpp b/kpovmodeler/pminsertrulesystem.cpp
new file mode 100644
index 00000000..0e7b7be2
--- /dev/null
+++ b/kpovmodeler/pminsertrulesystem.cpp
@@ -0,0 +1,1061 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pminsertrulesystem.h"
+#include "pmprototypemanager.h"
+#include "pmpart.h"
+#include "pmvariant.h"
+#include "pmdebug.h"
+
+#include <qfile.h>
+#include <kstandarddirs.h>
+
+bool isCategory( QDomElement& e )
+{
+ return( e.tagName( ) == "class" || e.tagName( ) == "group" );
+}
+
+PMRuleCategory* newCategory( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+{
+ if( e.tagName( ) == "class" )
+ return new PMRuleClass( e );
+ if( e.tagName( ) == "group" )
+ return new PMRuleGroup( e, globalGroups, localGroups );
+ return 0;
+}
+
+PMPrototypeManager* PMRuleClass::s_pPrototypeManager = 0;
+
+PMRuleClass::PMRuleClass( QDomElement& e )
+ : PMRuleCategory( )
+{
+ m_pPrototypeManager = s_pPrototypeManager;
+ m_className = e.attribute( "name" );
+ if( m_className.isEmpty( ) )
+ kdError( PMArea ) << "RuleSystem: Invalid class name" << endl;
+ if( !m_pPrototypeManager->existsClass( m_className ) )
+ kdError( PMArea ) << "RuleSystem: Unknown class: "
+ << m_className << endl;
+}
+
+bool PMRuleClass::matches( const QString& className )
+{
+ return m_pPrototypeManager->isA( className, m_className );
+}
+
+PMRuleGroup::PMRuleGroup( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleCategory( )
+{
+ m_pGroup = 0;
+ QString groupName = e.attribute( "name" );
+ if( groupName.isEmpty( ) )
+ kdError( PMArea ) << "RuleSystem: Invalid group name" << endl;
+ // find group
+ QPtrListIterator<PMRuleDefineGroup> lit( localGroups );
+ for( ; lit.current( ) && !m_pGroup; ++lit )
+ if( lit.current( )->name( ) == groupName )
+ m_pGroup = lit.current( );
+ QPtrListIterator<PMRuleDefineGroup> git( globalGroups );
+ for( ; git.current( ) && !m_pGroup; ++git )
+ if( git.current( )->name( ) == groupName )
+ m_pGroup = git.current( );
+ if( !m_pGroup )
+ kdError( PMArea ) << "RuleSystem: Group not defined: "
+ << groupName << endl;
+}
+
+bool PMRuleGroup::matches( const QString& className )
+{
+ if( m_pGroup )
+ return m_pGroup->matches( className );
+ return false;
+}
+
+PMRuleDefineGroup::PMRuleDefineGroup( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+{
+ m_name = e.attribute( "name" );
+ if( m_name.isEmpty( ) )
+ kdError( PMArea ) << "RuleSystem: Invalid group name" << endl;
+
+ QDomNode m = e.firstChild( );
+ while( !m.isNull( ) )
+ {
+ if( m.isElement( ) )
+ {
+ QDomElement me = m.toElement( );
+ if( isCategory( me ) )
+ m_categories.append( newCategory( me, globalGroups, localGroups ) );
+ }
+ m = m.nextSibling( );
+ }
+}
+
+PMRuleDefineGroup::~PMRuleDefineGroup( )
+{
+ m_categories.setAutoDelete( true );
+ m_categories.clear( );
+}
+
+bool PMRuleDefineGroup::matches( const QString& className )
+{
+ bool m = false;
+ QPtrListIterator<PMRuleCategory> it( m_categories );
+ for( ; it.current( ) && !m; ++it )
+ m = it.current( )->matches( className );
+ return m;
+}
+
+
+bool isValue( QDomElement& e )
+{
+ return( e.tagName( ) == "property" || e.tagName( ) == "const" ||
+ e.tagName( ) == "count" );
+}
+
+bool isCondition( QDomElement& e )
+{
+ return( e.tagName( ) == "not" || e.tagName( ) == "and" ||
+ e.tagName( ) == "or" || e.tagName( ) == "before" ||
+ e.tagName( ) == "after" || e.tagName( ) == "contains" ||
+ e.tagName( ) == "greater" || e.tagName( ) == "less" ||
+ e.tagName( ) == "equal" );
+}
+
+PMRuleValue* newValue( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+{
+ if( e.tagName( ) == "property" )
+ return new PMRuleProperty( e );
+ if( e.tagName( ) == "const" )
+ return new PMRuleConstant( e );
+ if( e.tagName( ) == "count" )
+ return new PMRuleCount( e, globalGroups, localGroups );
+ return 0;
+}
+
+PMRuleCondition* newCondition( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+{
+ if( e.tagName( ) == "not" )
+ return new PMRuleNot( e, globalGroups, localGroups );
+ if( e.tagName( ) == "and" )
+ return new PMRuleAnd( e, globalGroups, localGroups );
+ if( e.tagName( ) == "or" )
+ return new PMRuleOr( e, globalGroups, localGroups );
+ if( e.tagName( ) == "before" )
+ return new PMRuleBefore( e, globalGroups, localGroups );
+ if( e.tagName( ) == "after" )
+ return new PMRuleAfter( e, globalGroups, localGroups );
+ if( e.tagName( ) == "contains" )
+ return new PMRuleContains( e, globalGroups, localGroups );
+ if( e.tagName( ) == "greater" )
+ return new PMRuleGreater( e, globalGroups, localGroups );
+ if( e.tagName( ) == "less" )
+ return new PMRuleLess( e, globalGroups, localGroups );
+ if( e.tagName( ) == "equal" )
+ return new PMRuleEqual( e, globalGroups, localGroups );
+ return 0;
+}
+
+PMRuleBase::~PMRuleBase( )
+{
+ m_children.setAutoDelete( true );
+ m_children.clear( );
+}
+
+void PMRuleBase::countChild( const QString& className, bool afterInsertPoint )
+{
+ countChildProtected( className, afterInsertPoint );
+
+ QPtrListIterator<PMRuleBase> it( m_children );
+ for( ; it.current( ); ++it )
+ it.current( )->countChild( className, afterInsertPoint );
+}
+
+void PMRuleBase::reset( )
+{
+ resetProtected( );
+
+ QPtrListIterator<PMRuleBase> it( m_children );
+ for( ; it.current( ); ++it )
+ it.current( )->reset( );
+}
+
+PMRuleProperty::PMRuleProperty( QDomElement& e )
+ : PMRuleValue( )
+{
+ m_property = e.attribute( "name" );
+ if( m_property.isNull( ) )
+ kdError( PMArea ) << "RuleSystem: Invalid property name" << endl;
+}
+
+PMVariant PMRuleProperty::evaluate( const PMObject* o )
+{
+ PMVariant v = o->property( m_property );
+ if( v.isNull( ) )
+ kdError( PMArea ) << "RuleSystem: Invalid property name: "
+ << m_property << endl;
+ return v;
+}
+
+
+PMRuleConstant::PMRuleConstant( QDomElement& e )
+ : PMRuleValue( )
+{
+ QString v = e.attribute( "value" );
+ if( v.isNull( ) )
+ kdError( PMArea ) << "RuleSystem: Invalid value" << endl;
+
+ m_value = PMVariant( v );
+}
+
+PMVariant PMRuleConstant::evaluate( const PMObject* )
+{
+ return m_value;
+}
+
+bool PMRuleConstant::convertTo( PMVariant::PMVariantDataType type )
+{
+ return m_value.convertTo( type );
+}
+
+
+PMRuleCount::PMRuleCount( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleValue( )
+{
+ m_number = 0;
+ QDomNode m = e.firstChild( );
+ while( !m.isNull( ) )
+ {
+ if( m.isElement( ) )
+ {
+ QDomElement me = m.toElement( );
+ if( isCategory( me ) )
+ m_categories.append( newCategory( me, globalGroups, localGroups ) );
+ }
+ m = m.nextSibling( );
+ }
+}
+
+PMRuleCount::~PMRuleCount( )
+{
+ m_categories.setAutoDelete( true );
+ m_categories.clear( );
+}
+
+PMVariant PMRuleCount::evaluate( const PMObject* )
+{
+ return PMVariant( m_number );
+}
+
+void PMRuleCount::countChildProtected( const QString& className, bool )
+{
+ bool m = false;
+ QPtrListIterator<PMRuleCategory> it( m_categories );
+ for( ; it.current( ) && !m; ++it )
+ m = it.current( )->matches( className );
+ if( m )
+ m_number++;
+}
+
+void PMRuleCount::resetProtected( )
+{
+ m_number = 0;
+}
+
+PMRuleNot::PMRuleNot( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleCondition( )
+{
+ m_pChild = 0;
+ QDomNode m = e.firstChild( );
+ while( !m.isNull( ) && !m_pChild )
+ {
+ if( m.isElement( ) )
+ {
+ QDomElement me = m.toElement( );
+ if( isCondition( me ) )
+ {
+ m_pChild = newCondition( me, globalGroups, localGroups );
+ m_children.append( m_pChild );
+ }
+ }
+ m = m.nextSibling( );
+ }
+}
+
+bool PMRuleNot::evaluate( const PMObject* object )
+{
+ if( m_pChild )
+ return !m_pChild->evaluate( object );
+ return true;
+}
+
+PMRuleAnd::PMRuleAnd( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleCondition( )
+{
+ QDomNode m = e.firstChild( );
+ while( !m.isNull( ) )
+ {
+ if( m.isElement( ) )
+ {
+ QDomElement me = m.toElement( );
+ if( isCondition( me ) )
+ {
+ PMRuleCondition* c = newCondition( me, globalGroups, localGroups );
+ m_children.append( c );
+ m_conditions.append( c );
+ }
+ }
+ m = m.nextSibling( );
+ }
+}
+
+bool PMRuleAnd::evaluate( const PMObject* object )
+{
+ bool b = true;
+ QPtrListIterator<PMRuleCondition> it( m_conditions );
+ for( ; it.current( ) && b; ++it )
+ b = it.current( )->evaluate( object );
+ return b;
+}
+
+PMRuleOr::PMRuleOr( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleCondition( )
+{
+ QDomNode m = e.firstChild( );
+ while( !m.isNull( ) )
+ {
+ if( m.isElement( ) )
+ {
+ QDomElement me = m.toElement( );
+ if( isCondition( me ) )
+ {
+ PMRuleCondition* c = newCondition( me, globalGroups, localGroups );
+ m_children.append( c );
+ m_conditions.append( c );
+ }
+ }
+ m = m.nextSibling( );
+ }
+}
+
+bool PMRuleOr::evaluate( const PMObject* object )
+{
+ bool b = false;
+ QPtrListIterator<PMRuleCondition> it( m_conditions );
+ for( ; it.current( ) && !b; ++it )
+ b = it.current( )->evaluate( object );
+ return b;
+}
+
+PMRuleBefore::PMRuleBefore( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleCondition( )
+{
+ m_contains = false;
+ QDomNode m = e.firstChild( );
+ while( !m.isNull( ) )
+ {
+ if( m.isElement( ) )
+ {
+ QDomElement me = m.toElement( );
+ if( isCategory( me ) )
+ m_categories.append( newCategory( me, globalGroups, localGroups ) );
+ }
+ m = m.nextSibling( );
+ }
+}
+
+PMRuleBefore::~PMRuleBefore( )
+{
+ m_categories.setAutoDelete( true );
+ m_categories.clear( );
+}
+
+bool PMRuleBefore::evaluate( const PMObject* )
+{
+ return m_contains;
+}
+
+void PMRuleBefore::countChildProtected( const QString& className,
+ bool afterInsertPoint )
+{
+ if( afterInsertPoint && !m_contains )
+ {
+ QPtrListIterator<PMRuleCategory> it( m_categories );
+ for( ; it.current( ) && !m_contains; ++it )
+ m_contains = it.current( )->matches( className );
+ }
+}
+
+void PMRuleBefore::resetProtected( )
+{
+ m_contains = false;
+}
+
+PMRuleAfter::PMRuleAfter( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleCondition( )
+{
+ m_contains = false;
+ QDomNode m = e.firstChild( );
+ while( !m.isNull( ) )
+ {
+ if( m.isElement( ) )
+ {
+ QDomElement me = m.toElement( );
+ if( isCategory( me ) )
+ m_categories.append( newCategory( me, globalGroups, localGroups ) );
+ }
+ m = m.nextSibling( );
+ }
+}
+
+PMRuleAfter::~PMRuleAfter( )
+{
+ m_categories.setAutoDelete( true );
+ m_categories.clear( );
+}
+
+bool PMRuleAfter::evaluate( const PMObject* )
+{
+ return m_contains;
+}
+
+void PMRuleAfter::countChildProtected( const QString& className,
+ bool afterInsertPoint )
+{
+ if( !afterInsertPoint && !m_contains )
+ {
+ QPtrListIterator<PMRuleCategory> it( m_categories );
+ for( ; it.current( ) && !m_contains; ++it )
+ m_contains = it.current( )->matches( className );
+ }
+}
+
+void PMRuleAfter::resetProtected( )
+{
+ m_contains = false;
+}
+
+PMRuleContains::PMRuleContains( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleCondition( )
+{
+ m_contains = false;
+ QDomNode m = e.firstChild( );
+ while( !m.isNull( ) )
+ {
+ if( m.isElement( ) )
+ {
+ QDomElement me = m.toElement( );
+ if( isCategory( me ) )
+ m_categories.append( newCategory( me, globalGroups, localGroups ) );
+ }
+ m = m.nextSibling( );
+ }
+}
+
+PMRuleContains::~PMRuleContains( )
+{
+ m_categories.setAutoDelete( true );
+ m_categories.clear( );
+}
+
+bool PMRuleContains::evaluate( const PMObject* )
+{
+ return m_contains;
+}
+
+void PMRuleContains::countChildProtected( const QString& className, bool )
+{
+ if( !m_contains )
+ {
+ QPtrListIterator<PMRuleCategory> it( m_categories );
+ for( ; it.current( ) && !m_contains; ++it )
+ m_contains = it.current( )->matches( className );
+ }
+}
+
+void PMRuleContains::resetProtected( )
+{
+ m_contains = false;
+}
+
+PMRuleCompare::PMRuleCompare( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleCondition( )
+{
+ m_pValue[0] = 0;
+ m_pValue[1] = 0;
+
+ int i = 0;
+ QDomNode m = e.firstChild( );
+ while( !m.isNull( ) && !m_pValue[1] )
+ {
+ if( m.isElement( ) )
+ {
+ QDomElement me = m.toElement( );
+ if( isValue( me ) )
+ {
+ m_pValue[i] = newValue( me, globalGroups, localGroups );
+ m_children.append( m_pValue[i] );
+ i++;
+ }
+ }
+ m = m.nextSibling( );
+ }
+ if( !m_pValue[1] )
+ kdError( PMArea ) << "RuleSystem: Comparison needs two values" << endl;
+}
+
+bool PMRuleCompare::evaluate( const PMObject* object )
+{
+ if( !m_pValue[1] )
+ return false;
+
+ PMVariant v[2];
+ v[0] = m_pValue[0]->evaluate( object );
+ v[1] = m_pValue[1]->evaluate( object );
+
+ if( v[0].isNull( ) || v[1].isNull( ) )
+ return false;
+
+ bool convertError = false;
+
+ if( v[0].dataType( ) != v[1].dataType( ) )
+ {
+ if( m_pValue[1]->type( ) == "Constant" )
+ {
+ if( v[1].convertTo( v[0].dataType( ) ) )
+ ( ( PMRuleConstant* ) m_pValue[1] )->convertTo( v[0].dataType( ) );
+ else
+ convertError = true;
+ }
+ else if( m_pValue[0]->type( ) == "Constant" )
+ {
+ if( v[0].convertTo( v[1].dataType( ) ) )
+ ( ( PMRuleConstant* ) m_pValue[0] )->convertTo( v[1].dataType( ) );
+ else
+ convertError = true;
+ }
+ else
+ convertError = true;
+ }
+ if( convertError )
+ {
+ kdError( PMArea ) << "RuleSystem: Types in comparison must match" << endl;
+ return false;
+ }
+
+ return compare( v[0], v[1] );
+}
+
+PMRuleLess::PMRuleLess( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleCompare( e, globalGroups, localGroups )
+{
+}
+
+bool PMRuleLess::compare( const PMVariant& v1, const PMVariant& v2 )
+{
+ bool c = false;
+
+ switch( v1.dataType( ) )
+ {
+ case PMVariant::Integer:
+ c = v1.intData( ) < v2.intData( );
+ break;
+ case PMVariant::Unsigned:
+ c = v1.unsignedData( ) < v2.unsignedData( );
+ break;
+ case PMVariant::Double:
+ c = v1.doubleData( ) < v2.doubleData( );
+ break;
+ case PMVariant::String:
+ c = v1.stringData( ) < v2.stringData( );
+ break;
+ case PMVariant::Bool:
+ kdError( PMArea ) << "RuleSystem: Less: Can't compare booleans" << endl;
+ break;
+ case PMVariant::ThreeState:
+ kdError( PMArea ) << "RuleSystem: Less: Can't compare ThreeStates" << endl;
+ break;
+ case PMVariant::Vector:
+ kdError( PMArea ) << "RuleSystem: Less: Can't compare vectors" << endl;
+ break;
+ case PMVariant::Color:
+ kdError( PMArea ) << "RuleSystem: Less: Can't compare colors" << endl;
+ break;
+ case PMVariant::ObjectPointer:
+ kdError( PMArea ) << "RuleSystem: Less: Can't compare object pointers" << endl;
+ break;
+ case PMVariant::None:
+ kdError( PMArea ) << "RuleSystem: Less: Value has type none" << endl;
+ break;
+ }
+ return c;
+}
+
+PMRuleGreater::PMRuleGreater( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleCompare( e, globalGroups, localGroups )
+{
+}
+
+bool PMRuleGreater::compare( const PMVariant& v1, const PMVariant& v2 )
+{
+ bool c = false;
+
+ switch( v1.dataType( ) )
+ {
+ case PMVariant::Integer:
+ c = v1.intData( ) > v2.intData( );
+ break;
+ case PMVariant::Unsigned:
+ c = v1.unsignedData( ) > v2.unsignedData( );
+ break;
+ case PMVariant::Double:
+ c = v1.doubleData( ) > v2.doubleData( );
+ break;
+ case PMVariant::String:
+ c = v1.stringData( ) > v2.stringData( );
+ break;
+ case PMVariant::Bool:
+ kdError( PMArea ) << "RuleSystem: Greater: Can't compare booleans" << endl;
+ break;
+ case PMVariant::ThreeState:
+ kdError( PMArea ) << "RuleSystem: Greater: Can't compare ThreeStates" << endl;
+ break;
+ case PMVariant::Vector:
+ kdError( PMArea ) << "RuleSystem: Greater: Can't compare vectors" << endl;
+ break;
+ case PMVariant::Color:
+ kdError( PMArea ) << "RuleSystem: Greater: Can't compare colors" << endl;
+ break;
+ case PMVariant::ObjectPointer:
+ kdError( PMArea ) << "RuleSystem: Greater: Can't compare object pointers" << endl;
+ break;
+ case PMVariant::None:
+ kdError( PMArea ) << "RuleSystem: Greater: Value has type none" << endl;
+ break;
+ }
+ return c;
+}
+
+PMRuleEqual::PMRuleEqual( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleCompare( e, globalGroups, localGroups )
+{
+}
+
+bool PMRuleEqual::compare( const PMVariant& v1, const PMVariant& v2 )
+{
+ bool c = false;
+
+ switch( v1.dataType( ) )
+ {
+ case PMVariant::Integer:
+ c = v1.intData( ) == v2.intData( );
+ break;
+ case PMVariant::Unsigned:
+ c = v1.unsignedData( ) == v2.unsignedData( );
+ break;
+ case PMVariant::Double:
+ c = v1.doubleData( ) == v2.doubleData( );
+ break;
+ case PMVariant::String:
+ c = v1.stringData( ) == v2.stringData( );
+ break;
+ case PMVariant::Bool:
+ c = v1.boolData( ) == v2.boolData( );
+ break;
+ case PMVariant::ThreeState:
+ c = v1.threeStateData( ) == v2.threeStateData( );
+ break;
+ case PMVariant::Vector:
+ kdError( PMArea ) << "RuleSystem: Equal: Can't compare vectors" << endl;
+ break;
+ case PMVariant::Color:
+ kdError( PMArea ) << "RuleSystem: Equal: Can't compare colors" << endl;
+ break;
+ case PMVariant::ObjectPointer:
+ kdError( PMArea ) << "RuleSystem: Equal: Can't compare object pointers" << endl;
+ break;
+ case PMVariant::None:
+ kdError( PMArea ) << "RuleSystem: Equal: Value has type none" << endl;
+ break;
+ }
+ return c;
+}
+
+
+PMRule::PMRule( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups )
+ : PMRuleBase( )
+{
+ m_pCondition = 0;
+
+ QDomNode m = e.firstChild( );
+ while( !m.isNull( ) && !m_pCondition )
+ {
+ if( m.isElement( ) )
+ {
+ QDomElement me = m.toElement( );
+ if( isCategory( me ) )
+ m_categories.append( newCategory( me, globalGroups, localGroups ) );
+ else if( isCondition( me ) )
+ {
+ m_pCondition = newCondition( me, globalGroups, localGroups );
+ m_children.append( m_pCondition );
+ }
+ }
+ m = m.nextSibling( );
+ }
+}
+
+PMRule::~PMRule( )
+{
+ m_categories.setAutoDelete( true );
+ m_categories.clear( );
+}
+
+bool PMRule::matches( const QString& className )
+{
+ bool m = false;
+ QPtrListIterator<PMRuleCategory> it( m_categories );
+ for( ; it.current( ) && !m; ++it )
+ m = it.current( )->matches( className );
+ return m;
+}
+
+bool PMRule::evaluate( const PMObject* parent )
+{
+ if( !m_pCondition )
+ return true;
+ else
+ return m_pCondition->evaluate( parent );
+}
+
+PMRuleTargetClass::PMRuleTargetClass( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups )
+{
+ m_class = e.attribute( "name" );
+ if( m_class.isEmpty( ) )
+ kdError( PMArea ) << "RuleSystem: Invalid class name" << endl;
+
+ appendRules( e, globalGroups );
+}
+
+void PMRuleTargetClass::appendRules( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups )
+{
+ QDomNode m = e.firstChild( );
+ while( !m.isNull( ) )
+ {
+ if( m.isElement( ) )
+ {
+ QDomElement me = m.toElement( );
+ if( me.tagName( ) == "definegroup" )
+ m_groups.append( new PMRuleDefineGroup( me, globalGroups, m_groups ) );
+ if( me.tagName( ) == "rule" )
+ m_rules.append( new PMRule( me, globalGroups, m_groups ) );
+ if( me.tagName( ) == "exception" )
+ m_exceptions.append( me.attribute( "class" ) );
+ }
+ m = m.nextSibling( );
+ }
+}
+
+PMRuleTargetClass::~PMRuleTargetClass( )
+{
+ m_groups.setAutoDelete( true );
+ m_groups.clear( );
+ m_rules.setAutoDelete( true );
+ m_rules.clear( );
+}
+
+PMInsertRuleSystem::PMInsertRuleSystem( PMPart* part )
+{
+ m_pPart = part;
+}
+
+PMInsertRuleSystem::~PMInsertRuleSystem( )
+{
+ m_groups.setAutoDelete( true );
+ m_groups.clear( );
+ m_classRules.setAutoDelete( true );
+ m_classRules.clear( );
+}
+
+void PMInsertRuleSystem::loadRules( const QString& fileName )
+{
+ PMRuleClass::s_pPrototypeManager = m_pPart->prototypeManager( );
+ if( m_loadedFiles.find( fileName ) != m_loadedFiles.end( ) )
+ return;
+ m_loadedFiles.push_back( fileName );
+
+
+ QString ruleFile = locate( "data", QString( "kpovmodeler/" + fileName ) );
+ if( ruleFile.isEmpty( ) )
+ {
+ kdError( PMArea ) << "Rule file 'kpovmodeler/" << fileName
+ << "' not found." << endl;
+ return;
+ }
+
+ QFile file( ruleFile );
+ if( !file.open( IO_ReadOnly ) )
+ {
+ kdError( PMArea ) << "Could not open rule file 'kpovmodeler/" << fileName
+ << "'" << endl;
+ return;
+ }
+
+ QDomDocument doc( "insertrules" );
+ doc.setContent( &file );
+
+ QDomElement e = doc.documentElement( );
+ if( e.attribute( "format" ) != "1.0" )
+ kdError( PMArea ) << "Rule format " << e.attribute( "format" )
+ << " not supported." << endl;
+ else
+ {
+ QDomNode c = e.firstChild( );
+ QPtrList<PMRuleDefineGroup> dummyLocalGroups;
+
+ while( !c.isNull( ) )
+ {
+ if( c.isElement( ) )
+ {
+ QDomElement ce = c.toElement( );
+ if( ce.tagName( ) == "definegroup" )
+ m_groups.append( new PMRuleDefineGroup( ce, m_groups,
+ dummyLocalGroups ) );
+ else if( ce.tagName( ) == "targetclass" )
+ {
+ QString className = ce.attribute( "name" );
+ // find a target class with the same name
+ PMRuleTargetClass* target = 0;
+
+ if( !m_rulesDict.isEmpty( ) )
+ target = m_rulesDict.find( className );
+
+ if( target )
+ target->appendRules( ce, m_groups );
+ else
+ {
+ target = new PMRuleTargetClass( ce, m_groups );
+ m_rulesDict.insert( className, target );
+ m_classRules.append( target );
+ }
+ }
+ }
+ c = c.nextSibling( );
+ }
+ }
+ file.close( );
+
+ PMRuleClass::s_pPrototypeManager = 0;
+}
+
+bool PMInsertRuleSystem::canInsert( const PMObject* parentObject,
+ const QString& className,
+ const PMObject* after,
+ const PMObjectList* objectsBetween )
+{
+ bool possible = false;
+
+ // find rules for target class
+ PMMetaObject* meta = parentObject->metaObject( );
+ for( ; meta && !possible; meta = meta->superClass( ) )
+ {
+ PMRuleTargetClass* tc = m_rulesDict.find( meta->className( ) );
+ if( tc )
+ {
+ // check the exception list
+ QStringList exceptions = tc->exceptions( );
+ bool exceptionFound = false;
+ QStringList::ConstIterator it;
+ for( it = exceptions.begin( );
+ it != exceptions.end( ) && !exceptionFound; ++it )
+ if( parentObject->isA( *it ) )
+ exceptionFound = true;
+
+ if( !exceptionFound )
+ {
+ QPtrListIterator<PMRule> rit = tc->rules( );
+ // find matching rules for class name
+ for( ; rit.current( ) && !possible; ++rit )
+ {
+ PMRule* rule = rit.current( );
+ if( rule->matches( className ) )
+ {
+ // matching rule found
+ // reset the rule
+ rit.current( )->reset( );
+
+ // count already inserted child objects
+ bool afterInsertPoint = false;
+ PMObject* o = parentObject->firstChild( );
+ if( !after )
+ afterInsertPoint = true;
+ for( ; o; o = o->nextSibling( ) )
+ {
+ rule->countChild( o->className( ), afterInsertPoint );
+ if( o == after )
+ afterInsertPoint = true;
+ }
+ if( objectsBetween )
+ {
+ PMObjectListIterator it( *objectsBetween );
+ for( ; it.current( ); ++it )
+ rule->countChild( it.current( )->type( ), false );
+ }
+
+ // evaluate condition value
+ possible = rule->evaluate( parentObject );
+ }
+ }
+ }
+ }
+ }
+
+ return possible;
+}
+
+bool PMInsertRuleSystem::canInsert( const PMObject* parentObject,
+ const PMObject* object,
+ const PMObject* after,
+ const PMObjectList* objectsBetween )
+{
+ return canInsert( parentObject, object->type( ), after, objectsBetween );
+}
+
+int PMInsertRuleSystem::canInsert( const PMObject* parentObject,
+ const PMObjectList& list,
+ const PMObject* after )
+{
+ PMObjectListIterator it( list );
+ QStringList classes;
+ for( ; it.current( ); ++it )
+ classes.append( it.current( )->type( ) );
+ return canInsert( parentObject, classes, after );
+}
+
+int PMInsertRuleSystem::canInsert( const PMObject* parentObject,
+ const QStringList& list,
+ const PMObject* after )
+{
+ if( list.size( ) == 1 )
+ {
+ // more efficient
+ if( canInsert( parentObject, list.first( ), after ) )
+ return 1;
+ else
+ return 0;
+ }
+
+ // find rules for target class
+ QPtrList<PMRuleTargetClass> targetClassList;
+ PMMetaObject* meta = parentObject->metaObject( );
+ for( ; meta; meta = meta->superClass( ) )
+ {
+ PMRuleTargetClass* tc = m_rulesDict.find( meta->className( ) );
+ if( tc )
+ targetClassList.append( tc );
+ }
+ if( targetClassList.isEmpty( ) )
+ return 0; // not rules found
+
+ // count already inserted children
+ QPtrListIterator<PMRuleTargetClass> tit( targetClassList );
+ for( ; tit.current( ); ++tit ) // ... for all target classes
+ {
+ QPtrListIterator<PMRule> rit = tit.current( )->rules( );
+ for( ; rit.current( ); ++rit ) // ... and all rules
+ {
+ rit.current( )->reset( );
+ bool afterInsertPoint = false;
+ PMObject* o = parentObject->firstChild( );
+ if( !after )
+ afterInsertPoint = true;
+ for( ; o; o = o->nextSibling( ) )
+ {
+ rit.current( )->countChild( o->className( ), afterInsertPoint );
+ if( o == after )
+ afterInsertPoint = true;
+ }
+ }
+ }
+
+ int number = 0;
+ QStringList::const_iterator oit;
+
+ for( oit = list.begin( ); oit != list.end( ); ++oit )
+ {
+ bool possible = false;
+ for( tit.toFirst( ); tit.current( ) && !possible; ++tit )
+ {
+ QPtrListIterator<PMRule> rit = tit.current( )->rules( );
+
+ for( ; rit.current( ) && !possible; ++rit )
+ {
+ PMRule* rule = rit.current( );
+ if( rule->matches( *oit ) )
+ possible = rule->evaluate( parentObject );
+ }
+ }
+ if( possible )
+ {
+ // object can be inserted, count it
+ for( ; tit.current( ); ++tit )
+ {
+ QPtrListIterator<PMRule> rit = tit.current( )->rules( );
+ for( ; rit.current( ); ++rit )
+ rit.current( )->countChild( *oit, false );
+ }
+ number++;
+ }
+ }
+
+ return number;
+}
diff --git a/kpovmodeler/pminsertrulesystem.h b/kpovmodeler/pminsertrulesystem.h
new file mode 100644
index 00000000..499cbc8e
--- /dev/null
+++ b/kpovmodeler/pminsertrulesystem.h
@@ -0,0 +1,678 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMINSERTRULESYSTEM_H
+#define PMINSERTRULESYSTEM_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmobject.h"
+
+#include <qstringlist.h>
+#include <qptrlist.h>
+#include <qdict.h>
+#include <qdom.h>
+
+class PMInsertRuleSystem;
+class PMPrototypeManager;
+
+/**
+ * Base class for all object categories (class and group)
+ * for the insert rule system
+ */
+class PMRuleCategory
+{
+public:
+ /**
+ * Default constructor
+ */
+ PMRuleCategory( ) { }
+ /**
+ * Destructor
+ */
+ virtual ~PMRuleCategory( ) { }
+ /**
+ * Returns true if the given class types matches the category.
+ */
+ virtual bool matches( const QString& className ) = 0;
+};
+
+/**
+ * Represents a class for the insert rule system
+ */
+class PMRuleClass : public PMRuleCategory
+{
+public:
+ /**
+ * Workaround to tell a created instance which
+ * prototype manager to use.
+ */
+ static PMPrototypeManager* s_pPrototypeManager;
+ /**
+ * Reads the data from the QDomElement.
+ */
+ PMRuleClass( QDomElement& e );
+ /** */
+ virtual bool matches( const QString& className );
+private:
+ QString m_className;
+ PMPrototypeManager* m_pPrototypeManager;
+};
+
+/**
+ * Groups together multiple classes or groups to form a new
+ * category for the insert rule system.
+ */
+class PMRuleDefineGroup
+{
+public:
+ /**
+ * Reads the data from the QDomElement.
+ */
+ PMRuleDefineGroup( QDomElement& e, QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups );
+ /**
+ * Destructor
+ */
+ virtual ~PMRuleDefineGroup( );
+ /**
+ * Returns true if the given class types matches the category.
+ */
+ virtual bool matches( const QString& className );
+ /**
+ * Returns the group's name
+ */
+ QString name( ) const { return m_name; }
+private:
+ QPtrList<PMRuleCategory> m_categories;
+ QString m_name;
+};
+
+/**
+ * Represents a group for the insert rule system
+ */
+class PMRuleGroup : public PMRuleCategory
+{
+public:
+ /**
+ * Reads the data from the QDomElement.
+ */
+ PMRuleGroup( QDomElement& e, QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups );
+ /** */
+ bool matches( const QString& className );
+private:
+ PMRuleDefineGroup* m_pGroup;
+};
+
+
+/**
+ * Base class for all nodes for the insert rule system
+ */
+class PMRuleBase
+{
+public:
+ /**
+ * Default constructor.
+ */
+ PMRuleBase( ) { }
+ /**
+ * Destructor
+ */
+ virtual ~PMRuleBase( );
+ /**
+ * Returns the node type.
+ */
+ virtual QString type( ) const = 0;
+ /**
+ * Calls countChildProtected for this node and all child nodes
+ */
+ void countChild( const QString& className, bool afterInsertPoint );
+ /**
+ * Calls resetProtected for this node and all child nodes
+ */
+ void reset( );
+ /**
+ * Returns an iterator to all child nodes
+ */
+ QPtrListIterator<PMRuleBase> childIterator( ) const
+ {
+ return QPtrListIterator<PMRuleBase>( m_children );
+ }
+protected:
+ /**
+ * Reimplement this method if the nodes value depends
+ * on already inserted child objects.
+ */
+ virtual void countChildProtected( const QString&, bool ) { }
+ /**
+ * Reset all cached data (like counted child objects) here.
+ */
+ virtual void resetProtected( ) { }
+
+ /**
+ * Add all child nodes to this list.
+ */
+ QPtrList<PMRuleBase> m_children;
+};
+
+/**
+ * Base class for values used by the rule system
+ */
+class PMRuleValue : public PMRuleBase
+{
+public:
+ /**
+ * Default constructor
+ */
+ PMRuleValue( ) : PMRuleBase( ) { }
+ /**
+ * Returns the node's value as variant.
+ *
+ * Reimplement this method in sub classes.
+ */
+ virtual PMVariant evaluate( const PMObject* o ) = 0;
+};
+
+
+/**
+ * Value node for object properties
+ */
+class PMRuleProperty : public PMRuleValue
+{
+public:
+ /**
+ * Reads the data from the QDomElement.
+ */
+ PMRuleProperty( QDomElement& e );
+ /** */
+ virtual QString type( ) const { return QString( "Property" ); }
+ /** */
+ virtual PMVariant evaluate( const PMObject* o );
+private:
+ QString m_property;
+};
+
+
+/**
+ * Simple constant
+ */
+class PMRuleConstant : public PMRuleValue
+{
+public:
+ /**
+ * Reads the data from the QDomElement.
+ */
+ PMRuleConstant( QDomElement& e );
+ /** */
+ virtual QString type( ) const { return QString( "Constant" ); }
+ /** */
+ virtual PMVariant evaluate( const PMObject* );
+ /**
+ * Converts the constant to the given type and returns true if
+ * successful.
+ */
+ bool convertTo( PMVariant::PMVariantDataType type );
+private:
+ PMVariant m_value;
+};
+
+/**
+ * Rule that counts child objects of certaint types
+ */
+class PMRuleCount : public PMRuleValue
+{
+public:
+ /**
+ * Reads the data from the QDomElement.
+ */
+ PMRuleCount( QDomElement& e, QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups );
+ /**
+ * Destructor
+ */
+ virtual ~PMRuleCount( );
+ /** */
+ virtual QString type( ) const { return QString( "Count" ); }
+ /** */
+ virtual PMVariant evaluate( const PMObject* );
+protected:
+ /** */
+ virtual void countChildProtected( const QString& className,
+ bool afterInsertPoint );
+ /**
+ * Reset all cached data (like counted child objects) here.
+ */
+ virtual void resetProtected( );
+private:
+ QPtrList<PMRuleCategory> m_categories;
+ int m_number;
+};
+
+/**
+ * Base class for conditions
+ */
+class PMRuleCondition : public PMRuleBase
+{
+public:
+ /**
+ * Default constructor
+ */
+ PMRuleCondition( ) : PMRuleBase( ) { }
+ /**
+ * Returns the condition's value.
+ *
+ * Reimplement this method in sub classes.
+ */
+ virtual bool evaluate( const PMObject* object ) = 0;
+};
+
+
+/**
+ * Logical negation
+ */
+class PMRuleNot : public PMRuleCondition
+{
+public:
+ /**
+ * Reads the data from the QDomElement.
+ */
+ PMRuleNot( QDomElement& e, QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups );
+ /** */
+ virtual QString type( ) const { return QString( "Not" ); }
+ /** */
+ virtual bool evaluate( const PMObject* object );
+private:
+ PMRuleCondition* m_pChild;
+};
+
+
+/**
+ * Logical and
+ */
+class PMRuleAnd : public PMRuleCondition
+{
+public:
+ /**
+ * Reads the data from the QDomElement.
+ */
+ PMRuleAnd( QDomElement& e, QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups );
+ /** */
+ virtual QString type( ) const { return QString( "And" ); }
+ /** */
+ virtual bool evaluate( const PMObject* object );
+private:
+ QPtrList<PMRuleCondition> m_conditions;
+};
+
+/**
+ * Logical or
+ */
+class PMRuleOr : public PMRuleCondition
+{
+public:
+ /**
+ * Reads the data from the QDomElement.
+ */
+ PMRuleOr( QDomElement& e, QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups );
+ /** */
+ virtual QString type( ) const { return QString( "Or" ); }
+ /** */
+ virtual bool evaluate( const PMObject* object );
+private:
+ QPtrList<PMRuleCondition> m_conditions;
+};
+
+/**
+ * Condition. Value is true if the object already contains
+ * objects of certaint classes before the insert point.
+ */
+class PMRuleBefore : public PMRuleCondition
+{
+public:
+ /**
+ * Reads the data from the QDomElement.
+ */
+ PMRuleBefore( QDomElement& e, QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups );
+ /**
+ * Destructor
+ */
+ virtual ~PMRuleBefore( );
+ /** */
+ virtual QString type( ) const { return QString( "Before" ); }
+ /** */
+ virtual bool evaluate( const PMObject* object );
+protected:
+ /** */
+ virtual void countChildProtected( const QString& className,
+ bool afterInsertPoint );
+ /** */
+ virtual void resetProtected( );
+private:
+ QPtrList<PMRuleCategory> m_categories;
+ bool m_contains;
+};
+
+/**
+ * Condition. Value is true if the object already contains
+ * objects of certaint classes after the insert point.
+ */
+class PMRuleAfter : public PMRuleCondition
+{
+public:
+ /**
+ * Reads the data from the QDomElement.
+ */
+ PMRuleAfter( QDomElement& e, QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups );
+ /**
+ * Destructor
+ */
+ virtual ~PMRuleAfter( );
+ /** */
+ virtual QString type( ) const { return QString( "After" ); }
+ /** */
+ virtual bool evaluate( const PMObject* object );
+protected:
+ /** */
+ virtual void countChildProtected( const QString& className,
+ bool afterInsertPoint );
+ /** */
+ virtual void resetProtected( );
+private:
+ QPtrList<PMRuleCategory> m_categories;
+ bool m_contains;
+};
+
+/**
+ * Condition. Value is true if the object already contains
+ * objects of certaint classes.
+ */
+class PMRuleContains : public PMRuleCondition
+{
+public:
+ /**
+ * Reads the data from the QDomElement.
+ */
+ PMRuleContains( QDomElement& e, QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups );
+ /**
+ * Destructor
+ */
+ virtual ~PMRuleContains( );
+ /** */
+ virtual QString type( ) const { return QString( "Contains" ); }
+ /** */
+ virtual bool evaluate( const PMObject* object );
+protected:
+ /** */
+ virtual void countChildProtected( const QString& className,
+ bool afterInsertPoint );
+ /** */
+ virtual void resetProtected( );
+private:
+ QPtrList<PMRuleCategory> m_categories;
+ bool m_contains;
+};
+
+/**
+ * Base class for comparisons
+ */
+class PMRuleCompare : public PMRuleCondition
+{
+public:
+ /**
+ * Reads the data from the QDomElement.
+ */
+ PMRuleCompare( QDomElement& e, QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups );
+ /** */
+ virtual bool evaluate( const PMObject* object );
+protected:
+ /**
+ * Compares the two variants. The variants have the same type.
+ *
+ * Reimplement this method in sub classes.
+ */
+ virtual bool compare( const PMVariant& v1, const PMVariant& v2 ) = 0;
+private:
+ PMRuleValue* m_pValue[2];
+};
+
+/**
+ * Less than comparison
+ */
+class PMRuleLess : public PMRuleCompare
+{
+public:
+ /**
+ * Reads the data from the QDomElement.
+ */
+ PMRuleLess( QDomElement& e, QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups );
+ /** */
+ virtual QString type( ) const { return QString( "Less" ); }
+protected:
+ /** */
+ virtual bool compare( const PMVariant& v1, const PMVariant& v2 );
+};
+
+/**
+ * Greater than comparison
+ */
+class PMRuleGreater : public PMRuleCompare
+{
+public:
+ /**
+ * Reads the data from the QDomElement.
+ */
+ PMRuleGreater( QDomElement& e, QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups );
+ /** */
+ virtual QString type( ) const { return QString( "Greater" ); }
+protected:
+ /** */
+ virtual bool compare( const PMVariant& v1, const PMVariant& v2 );
+};
+
+/**
+ * Equal comparison
+ */
+class PMRuleEqual : public PMRuleCompare
+{
+public:
+ /**
+ * Reads the data from the QDomElement.
+ */
+ PMRuleEqual( QDomElement& e, QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups );
+ /** */
+ virtual QString type( ) const { return QString( "Equal" ); }
+protected:
+ /** */
+ virtual bool compare( const PMVariant& v1, const PMVariant& v2 );
+};
+
+class PMRule : public PMRuleBase
+{
+public:
+ /**
+ * Reads the data from the QDomElement.
+ */
+ PMRule( QDomElement& e, QPtrList<PMRuleDefineGroup>& globalGroups,
+ QPtrList<PMRuleDefineGroup>& localGroups );
+ /**
+ * Destructor
+ */
+ virtual ~PMRule( );
+ /** */
+ virtual QString type( ) const { return QString( "Rule" ); }
+ /**
+ * Returns true if this rule matches for the given class.
+ */
+ bool matches( const QString& className );
+ /**
+ * Returns the conditions value.
+ */
+ bool evaluate( const PMObject* parent );
+
+private:
+ QPtrList<PMRuleCategory> m_categories;
+ PMRuleCondition* m_pCondition;
+};
+
+/**
+ * Class used internally by the insert rule system
+ *
+ * Stores all rules for one class.
+ */
+class PMRuleTargetClass
+{
+public:
+ /**
+ * Reads the data from the QDomElement.
+ */
+ PMRuleTargetClass( QDomElement& e,
+ QPtrList<PMRuleDefineGroup>& globalGroups );
+ /**
+ * Destructor
+ */
+ ~PMRuleTargetClass( );
+
+ /**
+ * Reads rules and groups from the QDomELement and appends
+ * them to the local ones.
+ */
+ void appendRules( QDomElement& e, QPtrList<PMRuleDefineGroup>& globalGroups );
+ /**
+ * Returns an iterator to the rules
+ */
+ QPtrListIterator<PMRule> rules( ) const
+ {
+ return QPtrListIterator<PMRule>( m_rules );
+ }
+ /**
+ * Returns the class name
+ */
+ QString name( ) const { return m_class; }
+ /**
+ * Returns a list of exceptions for this rule.
+ */
+ QStringList exceptions( ) const { return m_exceptions; }
+private:
+ QPtrList<PMRuleDefineGroup> m_groups;
+ QPtrList<PMRule> m_rules;
+ QString m_class;
+ QStringList m_exceptions;
+};
+
+/**
+ * Rule based system that checks which objects can be inserted as child
+ * into another object.
+ *
+ * The rules are defined in the file "pmbaseinsertrules.xml".
+ * The file "pminsertrules.dtd" is a DTD file that can be used
+ * to validate rule files.
+ *
+ * Plugins can add additional rules to the system.
+ */
+class PMInsertRuleSystem
+{
+public:
+ /**
+ * Constructor
+ */
+ PMInsertRuleSystem( PMPart* part );
+ /**
+ * Destructor
+ */
+ ~PMInsertRuleSystem( );
+
+ /**
+ * Tells the system to load the rules from a file.
+ *
+ * Rules are never loaded twice for the same file. It is save
+ * to call this method twice for the same file.
+ */
+ void loadRules( const QString& fileName );
+
+ /**
+ * Returns true if an object of the given class can be inserted as child
+ * after the object after.
+ *
+ * The parser uses the third parameter for top level objects. These objects
+ * have to be treated as if they are inserted after the object after.
+ */
+ bool canInsert( const PMObject* parentObject, const QString& className,
+ const PMObject* after, const PMObjectList* objectsBetween = 0 );
+
+ /**
+ * Returns true if the object can be inserted as child
+ * after the object after.
+ *
+ * The parser uses the third parameter for top level objects. These objects
+ * have to be treated as if they are inserted after the object after.
+ *
+ * Same as canInsert( parentObject, object->class( ), after, objectsBetween )
+ */
+ bool canInsert( const PMObject* parentObject, const PMObject* object,
+ const PMObject* after, const PMObjectList* objectsBetween = 0 );
+
+ /**
+ * Returns the number of objects that can be inserted at that position
+ */
+ int canInsert( const PMObject* parentObject, const PMObjectList& list,
+ const PMObject* after );
+ /**
+ * Returns the number of objects that can be inserted at that position
+ */
+ int canInsert( const PMObject* parentObject, const QStringList& listOfClasses,
+ const PMObject* after );
+ /**
+ * Returns a pointer to the part
+ */
+ PMPart* part( ) const { return m_pPart; }
+
+private:
+ /**
+ * List of all rules.
+ */
+ QPtrList<PMRuleTargetClass> m_classRules;
+ /**
+ * List of global groups
+ */
+ QPtrList<PMRuleDefineGroup> m_groups;
+ /**
+ * Dictionary that maps from the class name
+ * to a list of rules that match.
+ */
+ QDict<PMRuleTargetClass> m_rulesDict;
+ /**
+ * List of already loaded files
+ */
+ QStringList m_loadedFiles;
+ PMPart* m_pPart;
+};
+
+#endif
diff --git a/kpovmodeler/pminterior.cpp b/kpovmodeler/pminterior.cpp
new file mode 100644
index 00000000..31d7bf5d
--- /dev/null
+++ b/kpovmodeler/pminterior.cpp
@@ -0,0 +1,343 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pminterior.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pminterioredit.h"
+
+#include <klocale.h>
+
+const double iorDefault = 1.0;
+const double causticsDefault = 0.0;
+const double dispersionDefault = 1.0;
+const int dispSamplesDefault = 7;
+const double fadeDistanceDefault = 0.0;
+const double fadePowerDefault = 0.0;
+
+PMDefinePropertyClass( PMInterior, PMInteriorProperty );
+
+PMMetaObject* PMInterior::s_pMetaObject = 0;
+PMObject* createNewInterior( PMPart* part )
+{
+ return new PMInterior( part );
+}
+
+PMInterior::PMInterior( PMPart* part )
+ : Base( part )
+{
+ m_ior = iorDefault;
+ m_caustics = causticsDefault;
+ m_dispersion = dispersionDefault;
+ m_dispSamples = dispSamplesDefault;
+ m_fadeDistance = fadeDistanceDefault;
+ m_fadePower = fadePowerDefault;
+ m_enableIor = false;
+ m_enableCaustics = false;
+ m_enableDispersion = false;
+ m_enableDispSamples = false;
+ m_enableFadeDistance = false;
+ m_enableFadePower = false;
+}
+
+PMInterior::PMInterior( const PMInterior& i )
+ : Base( i )
+{
+ m_ior = i.m_ior;
+ m_caustics = i.m_caustics;
+ m_dispersion = i.m_dispersion;
+ m_dispSamples = i.m_dispSamples;
+ m_fadeDistance = i.m_fadeDistance;
+ m_fadePower = i.m_fadePower;
+ m_enableIor = i.m_enableIor;
+ m_enableCaustics = i.m_enableCaustics;
+ m_enableDispersion = i.m_enableDispersion;
+ m_enableDispSamples = i.m_enableDispSamples;
+ m_enableFadeDistance = i.m_enableFadeDistance;
+ m_enableFadePower = i.m_enableFadePower;
+}
+
+PMInterior::~PMInterior( )
+{
+}
+
+PMMetaObject* PMInterior::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Interior", Base::metaObject( ),
+ createNewInterior );
+ s_pMetaObject->addProperty(
+ new PMInteriorProperty( "ior", &PMInterior::setIor, &PMInterior::ior ) );
+ s_pMetaObject->addProperty(
+ new PMInteriorProperty( "caustics", &PMInterior::setCaustics, &PMInterior::caustics ) );
+ s_pMetaObject->addProperty(
+ new PMInteriorProperty( "dispersion", &PMInterior::setDispersion, &PMInterior::dispersion ) );
+ s_pMetaObject->addProperty(
+ new PMInteriorProperty( "dispSamples", &PMInterior::setDispSamples, &PMInterior::dispSamples ) );
+ s_pMetaObject->addProperty(
+ new PMInteriorProperty( "fadeDistance", &PMInterior::setFadeDistance, &PMInterior::fadeDistance ) );
+ s_pMetaObject->addProperty(
+ new PMInteriorProperty( "fadePower", &PMInterior::setFadePower, &PMInterior::fadePower ) );
+ s_pMetaObject->addProperty(
+ new PMInteriorProperty( "iorEnabled", &PMInterior::enableIor, &PMInterior::isIorEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMInteriorProperty( "causticsEnabled", &PMInterior::enableCaustics, &PMInterior::isCausticsEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMInteriorProperty( "dispersionEnabled", &PMInterior::enableDispersion, &PMInterior::isDispersionEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMInteriorProperty( "dispSamplesEnabled", &PMInterior::enableDispSamples, &PMInterior::isDispSamplesEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMInteriorProperty( "fadeDistanceEnabled", &PMInterior::enableFadeDistance, &PMInterior::isFadeDistanceEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMInteriorProperty( "fadePowerEnabled", &PMInterior::enableFadePower, &PMInterior::isFadePowerEnabled ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMInterior::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMInterior::description( ) const
+{
+ return i18n( "interior" );
+}
+
+void PMInterior::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ Base::serialize( e, doc );
+ e.setAttribute( "enable_ior", m_enableIor );
+ e.setAttribute( "enable_caustics", m_enableCaustics );
+ e.setAttribute( "enable_dispersion", m_enableDispersion );
+ e.setAttribute( "enable_disp_samples", m_enableDispSamples );
+ e.setAttribute( "enable_fade_distance", m_enableFadeDistance );
+ e.setAttribute( "enable_fade_power", m_enableFadePower );
+ e.setAttribute( "ior", m_ior );
+ e.setAttribute( "caustics", m_caustics );
+ e.setAttribute( "dispersion", m_dispersion );
+ e.setAttribute( "disp_samples", m_dispSamples );
+ e.setAttribute( "fade_distance", m_fadeDistance );
+ e.setAttribute( "fade_power", m_fadePower );
+}
+
+void PMInterior::readAttributes( const PMXMLHelper& h )
+{
+ Base::readAttributes( h );
+ m_enableIor = h.boolAttribute( "enable_ior", false );
+ m_enableCaustics = h.boolAttribute( "enable_caustics", false );
+ m_enableDispersion = h.boolAttribute( "enable_dispersion", false );
+ m_enableDispSamples = h.boolAttribute( "enable_disp_samples", false );
+ m_enableFadeDistance = h.boolAttribute( "enable_fade_distance", false );
+ m_enableFadePower = h.boolAttribute( "enable_fade_power", false );
+ m_ior = h.doubleAttribute( "ior", iorDefault );
+ m_caustics = h.doubleAttribute( "caustics", causticsDefault );
+ m_dispersion = h.doubleAttribute( "dispersion", dispersionDefault );
+ m_dispSamples = h.intAttribute( "disp_samples", dispSamplesDefault );
+ m_fadeDistance = h.doubleAttribute( "fade_distance", fadeDistanceDefault );
+ m_fadePower = h.doubleAttribute( "fade_power", fadePowerDefault );
+}
+
+void PMInterior::setIor( double c )
+{
+ if( c != m_ior )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMIorID, m_ior );
+ m_ior = c;
+ }
+}
+
+void PMInterior::setCaustics( double c )
+{
+ if( c != m_caustics )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMCausticsID, m_caustics );
+ m_caustics = c;
+ }
+}
+
+void PMInterior::setDispersion( double c )
+{
+ if ( c != m_dispersion )
+ {
+ if ( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMDispersionID, m_dispersion );
+ m_dispersion = c;
+ }
+}
+
+void PMInterior::setDispSamples( int c )
+{
+ if ( c != m_dispSamples )
+ {
+ if ( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMDispSamplesID, m_dispSamples );
+ m_dispSamples = c;
+ }
+}
+
+void PMInterior::setFadeDistance( double c )
+{
+ if( c != m_fadeDistance )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFadeDistanceID, m_fadeDistance );
+ m_fadeDistance = c;
+ }
+}
+
+void PMInterior::setFadePower( double c )
+{
+ if( c != m_fadePower )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFadePowerID, m_fadePower );
+ m_fadePower = c;
+ }
+}
+
+void PMInterior::enableIor( bool c )
+{
+ if( c != m_enableIor )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableIorID, m_enableIor );
+ m_enableIor = c;
+ }
+}
+
+void PMInterior::enableCaustics( bool c )
+{
+ if( c != m_enableCaustics )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableCausticsID, m_enableCaustics );
+ m_enableCaustics = c;
+ }
+}
+
+void PMInterior::enableDispersion( bool c )
+{
+ if( c != m_enableDispersion )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableDispersionID, m_enableDispersion );
+ m_enableDispersion = c;
+ }
+}
+
+void PMInterior::enableDispSamples( bool c )
+{
+ if( c != m_enableDispSamples )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableDispSamplesID, m_enableDispSamples );
+ m_enableDispSamples = c;
+ }
+}
+
+void PMInterior::enableFadeDistance( bool c )
+{
+ if( c != m_enableFadeDistance )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableFadeDistanceID,
+ m_enableFadeDistance );
+ m_enableFadeDistance = c;
+ }
+}
+
+void PMInterior::enableFadePower( bool c )
+{
+ if( c != m_enableFadePower )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableFadePowerID,
+ m_enableFadePower );
+ m_enableFadePower = c;
+ }
+}
+
+PMDialogEditBase* PMInterior::editWidget( QWidget* parent ) const
+{
+ return new PMInteriorEdit( parent );
+}
+
+void PMInterior::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMIorID:
+ setIor( data->doubleData( ) );
+ break;
+ case PMCausticsID:
+ setCaustics( data->doubleData( ) );
+ break;
+ case PMDispersionID:
+ setDispersion( data->doubleData( ) );
+ break;
+ case PMDispSamplesID:
+ setDispSamples( data->intData( ) );
+ break;
+ case PMFadeDistanceID:
+ setFadeDistance( data->doubleData( ) );
+ break;
+ case PMFadePowerID:
+ setFadePower( data->doubleData( ) );
+ break;
+ case PMEnableIorID:
+ enableIor( data->boolData( ) );
+ break;
+ case PMEnableCausticsID:
+ enableCaustics( data->boolData( ) );
+ break;
+ case PMEnableDispersionID:
+ enableDispersion( data->boolData( ) );
+ break;
+ case PMEnableDispSamplesID:
+ enableDispSamples( data->boolData( ) );
+ case PMEnableFadeDistanceID:
+ enableFadeDistance( data->boolData( ) );
+ break;
+ case PMEnableFadePowerID:
+ enableFadePower( data->boolData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMInterior::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pminterior.h b/kpovmodeler/pminterior.h
new file mode 100644
index 00000000..159b6b64
--- /dev/null
+++ b/kpovmodeler/pminterior.h
@@ -0,0 +1,128 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMINTERIOR_H
+#define PMINTERIOR_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebase.h"
+#include "pmcolor.h"
+
+/**
+ * Class for povray interiors
+ */
+class PMInterior : public PMTextureBase
+{
+ typedef PMTextureBase Base;
+public:
+ /**
+ * Creates an PMInterior
+ */
+ PMInterior( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMInterior( const PMInterior& i );
+ /**
+ * Deletes the object
+ */
+ virtual ~PMInterior( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMInterior( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMInteriorEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /** */
+ virtual QString pixmap( ) const { return QString( "pminterior" ); }
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+
+ double ior( ) const { return m_ior; }
+ double caustics( ) const { return m_caustics; }
+ double dispersion( ) const { return m_dispersion; }
+ int dispSamples( ) const { return m_dispSamples; }
+ double fadeDistance( ) const { return m_fadeDistance; }
+ double fadePower( ) const { return m_fadePower; }
+ bool isIorEnabled( ) const { return m_enableIor; }
+ bool isCausticsEnabled( ) const { return m_enableCaustics; }
+ bool isDispersionEnabled( ) const { return m_enableDispersion; }
+ bool isDispSamplesEnabled( ) const { return m_enableDispSamples; }
+ bool isFadeDistanceEnabled( ) const { return m_enableFadeDistance; }
+ bool isFadePowerEnabled( ) const { return m_enableFadePower; }
+
+ void setIor( double c );
+ void setCaustics( double c );
+ void setDispersion ( double c );
+ void setDispSamples ( int c );
+ void setFadeDistance( double c );
+ void setFadePower( double c );
+ void enableIor( bool c );
+ void enableCaustics( bool c );
+ void enableDispersion( bool c );
+ void enableDispSamples( bool c );
+ void enableFadeDistance( bool c );
+ void enableFadePower( bool c );
+
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMInteriorMementoID { PMIorID, PMCausticsID, PMDispersionID,
+ PMDispSamplesID, PMFadeDistanceID, PMFadePowerID,
+ PMEnableIorID, PMEnableCausticsID,
+ PMEnableDispersionID, PMEnableDispSamplesID,
+ PMEnableFadeDistanceID, PMEnableFadePowerID };
+ double m_ior;
+ double m_caustics;
+ double m_dispersion;
+ int m_dispSamples;
+ double m_fadeDistance;
+ double m_fadePower;
+
+ bool m_enableIor;
+ bool m_enableCaustics;
+ bool m_enableDispersion;
+ bool m_enableDispSamples;
+ bool m_enableFadeDistance;
+ bool m_enableFadePower;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pminterioredit.cpp b/kpovmodeler/pminterioredit.cpp
new file mode 100644
index 00000000..b5df1825
--- /dev/null
+++ b/kpovmodeler/pminterioredit.cpp
@@ -0,0 +1,212 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pminterioredit.h"
+#include "pminterior.h"
+#include "pmlineedits.h"
+#include "pmcoloredit.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <klocale.h>
+
+
+PMInteriorEdit::PMInteriorEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMInteriorEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* hl = new QHBoxLayout( topLayout( ) );
+ QGridLayout* layout = new QGridLayout( hl ,17 ,6);
+ m_pEnableIorEdit = new QCheckBox( i18n( "Refraction:" ), this );
+ m_pIorEdit = new PMFloatEdit( this );
+ layout->addWidget( m_pEnableIorEdit, 0, 0 );
+ layout->addWidget( m_pIorEdit, 0, 1 );
+ m_pEnableCausticsEdit = new QCheckBox( i18n( "Caustics:" ), this );
+ m_pCausticsEdit = new PMFloatEdit( this );
+ layout->addWidget( m_pEnableCausticsEdit, 1, 0 );
+ layout->addWidget( m_pCausticsEdit, 1, 1 );
+ m_pEnableDispersionEdit = new QCheckBox( i18n( "Dispersion:" ), this );
+ m_pDispersionEdit = new PMFloatEdit( this );
+ m_pDispersionEdit->setValidation( true, 0, false, 0 );
+ layout->addWidget( m_pEnableDispersionEdit, 2, 0 );
+ layout->addWidget( m_pDispersionEdit, 2, 1 );
+ m_pEnableDispSamplesEdit = new QCheckBox( i18n( "Dispersion samples:" ), this );
+ m_pDispSamplesEdit = new PMIntEdit( this );
+ m_pDispSamplesEdit->setValidation( true, 2, false, 0 );
+ layout->addWidget( m_pEnableDispSamplesEdit, 3, 0 );
+ layout->addWidget( m_pDispSamplesEdit, 3, 1 );
+ m_pEnableFadeDistanceEdit = new QCheckBox( i18n( "Fade distance:" ), this );
+ m_pFadeDistanceEdit = new PMFloatEdit( this );
+ layout->addWidget( m_pEnableFadeDistanceEdit, 4, 0 );
+ layout->addWidget( m_pFadeDistanceEdit, 4, 1 );
+ m_pEnableFadePowerEdit = new QCheckBox( i18n( "Fade power:" ), this );
+ m_pFadePowerEdit = new PMFloatEdit( this );
+ layout->addWidget( m_pEnableFadePowerEdit, 5, 0 );
+ layout->addWidget( m_pFadePowerEdit, 5, 1 );
+ hl->addStretch( 1 );
+
+ connect( m_pIorEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pCausticsEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pDispersionEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pDispSamplesEdit, SIGNAL( dataChanged( ) ), SIGNAL ( dataChanged( ) ) );
+ connect( m_pFadeDistanceEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pFadePowerEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pEnableIorEdit, SIGNAL( clicked( ) ), SLOT( slotIorClicked( ) ) );
+ connect( m_pEnableCausticsEdit, SIGNAL( clicked( ) ), SLOT( slotCausticsClicked( ) ) );
+ connect( m_pEnableDispersionEdit, SIGNAL( clicked( ) ), SLOT( slotDispersionClicked( ) ) );
+ connect( m_pEnableDispSamplesEdit, SIGNAL( clicked( ) ), SLOT( slotDispSamplesClicked( ) ) );
+ connect( m_pEnableFadeDistanceEdit, SIGNAL( clicked( ) ), SLOT( slotFadeDistanceClicked( ) ) );
+ connect( m_pEnableFadePowerEdit, SIGNAL( clicked( ) ), SLOT( slotFadePowerClicked( ) ) );
+}
+
+void PMInteriorEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Interior" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMInterior* ) o;
+
+ m_pIorEdit->setValue( m_pDisplayedObject->ior( ) );
+ m_pIorEdit->setReadOnly( readOnly );
+ m_pCausticsEdit->setValue( m_pDisplayedObject->caustics( ) );
+ m_pCausticsEdit->setReadOnly( readOnly );
+ m_pDispersionEdit->setValue( m_pDisplayedObject->dispersion( ) );
+ m_pDispersionEdit->setReadOnly( readOnly );
+ m_pDispSamplesEdit->setValue( m_pDisplayedObject->dispSamples( ) );
+ m_pDispSamplesEdit->setReadOnly( readOnly );
+ m_pFadeDistanceEdit->setValue( m_pDisplayedObject->fadeDistance( ) );
+ m_pFadeDistanceEdit->setReadOnly( readOnly );
+ m_pFadePowerEdit->setValue( m_pDisplayedObject->fadePower( ) );
+ m_pFadePowerEdit->setReadOnly( readOnly );
+ m_pEnableIorEdit->setChecked( m_pDisplayedObject->isIorEnabled( ) );
+ m_pEnableIorEdit->setEnabled( !readOnly );
+ m_pEnableCausticsEdit->setChecked( m_pDisplayedObject->isCausticsEnabled( ) );
+ m_pEnableCausticsEdit->setEnabled( !readOnly );
+ m_pEnableDispersionEdit->setChecked( m_pDisplayedObject->isDispersionEnabled( ) );
+ m_pEnableDispersionEdit->setEnabled( !readOnly );
+ m_pEnableDispSamplesEdit->setChecked( m_pDisplayedObject->isDispSamplesEnabled( ) );
+ m_pEnableDispSamplesEdit->setEnabled( !readOnly );
+ m_pEnableFadeDistanceEdit->setChecked( m_pDisplayedObject->isFadeDistanceEnabled( ) );
+ m_pEnableFadeDistanceEdit->setEnabled( !readOnly );
+ m_pEnableFadePowerEdit->setChecked( m_pDisplayedObject->isFadePowerEnabled( ) );
+ m_pEnableFadePowerEdit->setEnabled( !readOnly );
+ slotIorClicked( );
+ slotCausticsClicked( );
+ slotDispersionClicked( );
+ slotDispSamplesClicked( );
+ slotFadeDistanceClicked( );
+ slotFadePowerClicked( );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMInteriorEdit: Can't display object\n";
+}
+
+void PMInteriorEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setIor( m_pIorEdit->value( ) );
+ m_pDisplayedObject->setCaustics( m_pCausticsEdit->value( ) );
+ m_pDisplayedObject->setDispersion( m_pDispersionEdit->value( ) );
+ m_pDisplayedObject->setDispSamples( m_pDispSamplesEdit->value( ) );
+ m_pDisplayedObject->setFadeDistance( m_pFadeDistanceEdit->value( ) );
+ m_pDisplayedObject->setFadePower( m_pFadePowerEdit->value( ) );
+ m_pDisplayedObject->enableIor( m_pEnableIorEdit->isChecked( ) );
+ m_pDisplayedObject->enableCaustics( m_pEnableCausticsEdit->isChecked( ) );
+ m_pDisplayedObject->enableDispersion( m_pEnableDispersionEdit->isChecked( ) );
+ m_pDisplayedObject->enableDispSamples( m_pEnableDispSamplesEdit->isChecked( ) );
+ m_pDisplayedObject->enableFadeDistance( m_pEnableFadeDistanceEdit->isChecked( ) );
+ m_pDisplayedObject->enableFadePower( m_pEnableFadePowerEdit->isChecked( ) );
+ }
+}
+
+bool PMInteriorEdit::isDataValid( )
+{
+ if( !m_pIorEdit->isDataValid( ) ) return false;
+ if( !m_pCausticsEdit->isDataValid( ) ) return false;
+ if( !m_pDispersionEdit->isDataValid( ) ) return false;
+ if( !m_pDispSamplesEdit->isDataValid( ) ) return false;
+ if( !m_pFadeDistanceEdit->isDataValid( ) ) return false;
+ if( !m_pFadePowerEdit->isDataValid( ) ) return false;
+ if( !m_pFadeDistanceEdit->isDataValid( ) ) return false;
+
+ return Base::isDataValid( );
+}
+
+void PMInteriorEdit::slotIorClicked( )
+{
+ if( m_pEnableIorEdit->isChecked( ) )
+ {
+ m_pIorEdit->setEnabled( true );
+ m_pEnableDispersionEdit->setEnabled( true );
+ m_pEnableDispSamplesEdit->setEnabled( true );
+ }
+ else
+ {
+ m_pIorEdit->setEnabled( false );
+ m_pEnableDispersionEdit->setEnabled( false );
+ m_pEnableDispSamplesEdit->setEnabled( false );
+ m_pEnableDispersionEdit->setChecked( false );
+ m_pEnableDispSamplesEdit->setChecked( false );
+ slotDispersionClicked( );
+ slotDispSamplesClicked( );
+ }
+ emit dataChanged( );
+}
+
+void PMInteriorEdit::slotCausticsClicked( )
+{
+ m_pCausticsEdit->setEnabled( m_pEnableCausticsEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+void PMInteriorEdit::slotDispersionClicked( )
+{
+ m_pDispersionEdit->setEnabled( m_pEnableDispersionEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+void PMInteriorEdit::slotDispSamplesClicked( )
+{
+ m_pDispSamplesEdit->setEnabled( m_pEnableDispSamplesEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+void PMInteriorEdit::slotFadeDistanceClicked( )
+{
+ m_pFadeDistanceEdit->setEnabled( m_pEnableFadeDistanceEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+void PMInteriorEdit::slotFadePowerClicked( )
+{
+ m_pFadePowerEdit->setEnabled( m_pEnableFadePowerEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+#include "pminterioredit.moc"
diff --git a/kpovmodeler/pminterioredit.h b/kpovmodeler/pminterioredit.h
new file mode 100644
index 00000000..93564bcb
--- /dev/null
+++ b/kpovmodeler/pminterioredit.h
@@ -0,0 +1,85 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMINTERIOREDIT_H
+#define PMINTERIOREDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebaseedit.h"
+
+class PMInterior;
+class PMIntEdit;
+class PMFloatEdit;
+class PMColorEdit;
+class QCheckBox;
+class QLabel;
+
+/**
+ * Dialog edit class for @ref PMInterior
+ */
+class PMInteriorEdit : public PMTextureBaseEdit
+{
+ Q_OBJECT
+ typedef PMTextureBaseEdit Base;
+public:
+ /**
+ * Creates a PMInteriorEdit with parent and name
+ */
+ PMInteriorEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+protected slots:
+ void slotIorClicked( );
+ void slotCausticsClicked( );
+ void slotDispersionClicked( );
+ void slotDispSamplesClicked( );
+ void slotFadePowerClicked( );
+ void slotFadeDistanceClicked( );
+
+private:
+ PMInterior* m_pDisplayedObject;
+ PMFloatEdit* m_pIorEdit;
+ PMFloatEdit* m_pCausticsEdit;
+ PMFloatEdit* m_pDispersionEdit;
+ PMIntEdit* m_pDispSamplesEdit;
+ PMFloatEdit* m_pFadeDistanceEdit;
+ PMFloatEdit* m_pFadePowerEdit;
+ QCheckBox* m_pEnableIorEdit;
+ QCheckBox* m_pEnableCausticsEdit;
+ QCheckBox* m_pEnableDispersionEdit;
+ QCheckBox* m_pEnableDispSamplesEdit;
+ QCheckBox* m_pEnableFadeDistanceEdit;
+ QCheckBox* m_pEnableFadePowerEdit;
+};
+
+
+#endif
diff --git a/kpovmodeler/pminteriortexture.cpp b/kpovmodeler/pminteriortexture.cpp
new file mode 100644
index 00000000..f379e4b6
--- /dev/null
+++ b/kpovmodeler/pminteriortexture.cpp
@@ -0,0 +1,75 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pminteriortexture.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pminteriortextureedit.h"
+
+#include <klocale.h>
+
+PMMetaObject* PMInteriorTexture::s_pMetaObject = 0;
+PMObject* createNewInteriorTexture( PMPart* part )
+{
+ return new PMInteriorTexture( part );
+}
+
+PMInteriorTexture::PMInteriorTexture( PMPart* part )
+ : Base( part )
+{
+}
+
+PMInteriorTexture::PMInteriorTexture( const PMInteriorTexture& t )
+ : Base( t )
+{
+}
+
+PMInteriorTexture::~PMInteriorTexture( )
+{
+}
+
+PMMetaObject* PMInteriorTexture::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "InteriorTexture", Base::metaObject( ),
+ createNewInteriorTexture );
+ }
+ return s_pMetaObject;
+}
+
+void PMInteriorTexture::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMInteriorTexture::description( ) const
+{
+ return i18n( "interior texture" );
+}
+
+PMDialogEditBase* PMInteriorTexture::editWidget( QWidget* parent ) const
+{
+ return new PMInteriorTextureEdit( parent );
+}
+
diff --git a/kpovmodeler/pminteriortexture.h b/kpovmodeler/pminteriortexture.h
new file mode 100644
index 00000000..8682e69d
--- /dev/null
+++ b/kpovmodeler/pminteriortexture.h
@@ -0,0 +1,71 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMINTERIORTEXTURE_H
+#define PMINTERIORTEXTURE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebase.h"
+
+/**
+ * Class for povray interior textures
+ */
+class PMInteriorTexture : public PMTextureBase
+{
+ typedef PMTextureBase Base;
+public:
+ /**
+ * Creates an PMInteriorTexture
+ */
+ PMInteriorTexture( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMInteriorTexture( const PMInteriorTexture& t );
+ /**
+ * Deletes the object
+ */
+ virtual ~PMInteriorTexture( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMInteriorTexture( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /**
+ * Returns a new @ref PMTextureEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /** */
+ virtual QString pixmap( ) const { return QString( "pminteriortexture" ); }
+
+private:
+ static PMMetaObject* s_pMetaObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pminteriortextureedit.cpp b/kpovmodeler/pminteriortextureedit.cpp
new file mode 100644
index 00000000..47fe6f38
--- /dev/null
+++ b/kpovmodeler/pminteriortextureedit.cpp
@@ -0,0 +1,44 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pminteriortextureedit.h"
+#include "pminteriortexture.h"
+#include "pmlinkedit.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <klocale.h>
+
+
+PMInteriorTextureEdit::PMInteriorTextureEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMInteriorTextureEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "InteriorTexture" ) )
+ {
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMInteriorTextureEdit: Can't display object\n";
+}
+
+#include "pminteriortextureedit.moc"
diff --git a/kpovmodeler/pminteriortextureedit.h b/kpovmodeler/pminteriortextureedit.h
new file mode 100644
index 00000000..1594ef6e
--- /dev/null
+++ b/kpovmodeler/pminteriortextureedit.h
@@ -0,0 +1,58 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMINTERIORTEXTUREEDIT_H
+#define PMINTERIORTEXTUREEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebaseedit.h"
+
+class PMInteriorTexture;
+
+/**
+ * Dialog edit class for @ref PMTexture
+ */
+class PMInteriorTextureEdit : public PMTextureBaseEdit
+{
+ Q_OBJECT
+ typedef PMTextureBaseEdit Base;
+public:
+ /**
+ * Creates a PMTextureEdit with parent and name
+ */
+ PMInteriorTextureEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+protected:
+ /** */
+// virtual void createTopWidgets( );
+ /** */
+// virtual void saveContents( );
+
+private:
+ PMInteriorTexture* m_pDisplayedObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmiomanager.cpp b/kpovmodeler/pmiomanager.cpp
new file mode 100644
index 00000000..72a081d2
--- /dev/null
+++ b/kpovmodeler/pmiomanager.cpp
@@ -0,0 +1,96 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmiomanager.h"
+#include "pmdebug.h"
+#include "pmpovray31format.h"
+#include "pmpovray35format.h"
+
+PMIOFormat::PMIOFormat( )
+{
+}
+
+PMIOFormat::~PMIOFormat( )
+{
+
+}
+
+PMIOManager::PMIOManager( PMPart* part )
+{
+ m_pPart = part;
+ m_formats.setAutoDelete( true );
+
+ addFormat( new PMPovray35Format( ) );
+ //addFormat( new PMPovray31Format( ) );
+}
+
+PMIOManager::~PMIOManager( )
+{
+
+}
+
+void PMIOManager::addFormat( PMIOFormat* format )
+{
+ if( !format )
+ return;
+ if( !m_formats.containsRef( format ) )
+ {
+ if( !m_dict.find( format->name( ) ) )
+ {
+ m_formats.append( format );
+ m_dict.insert( format->name( ), format );
+ }
+ else
+ kdError( PMArea ) << "Format " << format->name( ) << "already registered" << endl;
+ }
+ else
+ kdError( PMArea ) << "Format " << format->name( ) << "already registered" << endl;
+}
+
+void PMIOManager::removeFormat( const QString& name )
+{
+ PMIOFormat* pFormat = format( name );
+ if( pFormat )
+ {
+ m_dict.remove( name );
+ m_formats.removeRef( pFormat );
+ }
+}
+
+PMIOFormat* PMIOManager::format( const QString& name ) const
+{
+ return m_dict.find( name );
+}
+
+PMIOFormat* PMIOManager::formatForMimeType( const QString& mime ) const
+{
+ QPtrListIterator<PMIOFormat> it( m_formats );
+ bool found = false;
+ PMIOFormat* pFormat = 0;
+
+ while( it.current( ) && !found )
+ {
+ pFormat = it.current( );
+ if( pFormat->mimeType( ) == mime )
+ found = true;
+ else
+ ++it;
+ }
+ if( found )
+ return pFormat;
+ return 0;
+}
diff --git a/kpovmodeler/pmiomanager.h b/kpovmodeler/pmiomanager.h
new file mode 100644
index 00000000..ac3b78eb
--- /dev/null
+++ b/kpovmodeler/pmiomanager.h
@@ -0,0 +1,184 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMIOMANAGER
+#define PMIOMANAGER
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qptrlist.h>
+#include <qdict.h>
+
+class PMParser;
+class PMSerializer;
+class PMRenderer;
+class PMPart;
+
+class QIODevice;
+
+/**
+ * Description class for input and output formats.
+ *
+ * A format may provide the following services:
+ *
+ * Import: The class can provide a parser to load and import data
+ *
+ * Export: The class can provide a output device to export and save data
+ *
+ * Renderer: A renderer exists to render the exported data
+ *
+ * The class @ref PMIOManager stores a list of instances
+ * of this class
+ */
+class PMIOFormat
+{
+public:
+ /**
+ * Format type enum
+ */
+ enum Services { Import = 1, Export = 2, Renderer = 4,
+ AllServices = Import | Export | Renderer };
+ /**
+ * Default constructor
+ */
+ PMIOFormat( );
+ /**
+ * Destructor
+ */
+ virtual ~PMIOFormat( );
+
+ /**
+ * Returns an unique name of this format.
+ */
+ virtual QString name( ) const = 0;
+ /**
+ * Returns a translated description of this format
+ */
+ virtual QString description( ) const = 0;
+ /**
+ * Returns the supported services
+ * (a bitwise combination of the Services enum values)
+ */
+ virtual int services( ) const = 0;
+ /**
+ * Returns a parser to parse the io device.
+ *
+ * The caller is responsible to delete the returned parser.
+ */
+ virtual PMParser* newParser( PMPart*, QIODevice* ) const
+ {
+ return 0;
+ };
+ /**
+ * Returns a parser to parse the byte array.
+ *
+ * The caller is responsible to delete the returned parser.
+ */
+ virtual PMParser* newParser( PMPart*, const QByteArray& ) const
+ {
+ return 0;
+ };
+ /**
+ * Returns an output device to export objects or the complete
+ * scene to the given io device.
+ *
+ * The caller is responsible to delete the returned device
+ */
+ virtual PMSerializer* newSerializer( QIODevice* )
+ {
+ return 0;
+ }
+ /**
+ * Returns a new renderer
+ */
+ virtual PMRenderer* newRenderer( PMPart* ) const
+ {
+ return 0;
+ }
+ /**
+ * Returns the mime type for this format
+ */
+ virtual QString mimeType( ) const
+ {
+ return QString::null;
+ }
+ /**
+ * Returns a list of patterns for the import file dialog
+ */
+ virtual QStringList importPatterns( ) const
+ {
+ return QStringList( );
+ }
+ /**
+ * Returns a list of patterns for the export file dialog
+ */
+ virtual QStringList exportPatterns( ) const
+ {
+ return QStringList( );
+ }
+};
+
+/**
+ * Manager class that handles all available input and output formats
+ * as well as renderers for one part
+ */
+class PMIOManager
+{
+public:
+ /**
+ * Creates an io manager for the part
+ */
+ PMIOManager( PMPart* part );
+ /**
+ * Deletes the io manager
+ */
+ ~PMIOManager( );
+
+ /**
+ * Adds a new format
+ */
+ void addFormat( PMIOFormat* format );
+ /**
+ * Removes a format by name
+ */
+ void removeFormat( const QString& name );
+
+ /**
+ * Returns the list of registered io formats
+ */
+ const QPtrList<PMIOFormat>& formats( ) const { return m_formats; }
+ /**
+ * Returns a view type by name
+ */
+ PMIOFormat* format( const QString& name ) const;
+ /**
+ * Returns the first io format that can handle the mime type
+ * or 0 if there is none
+ */
+ PMIOFormat* formatForMimeType( const QString& mime ) const;
+
+private:
+ QPtrList<PMIOFormat> m_formats;
+ QDict<PMIOFormat> m_dict;
+ PMPart* m_pPart;
+};
+
+#endif
diff --git a/kpovmodeler/pmisosurface.cpp b/kpovmodeler/pmisosurface.cpp
new file mode 100644
index 00000000..16e5e247
--- /dev/null
+++ b/kpovmodeler/pmisosurface.cpp
@@ -0,0 +1,419 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmisosurface.h"
+
+#include "pmxmlhelper.h"
+#include "pmisosurfaceedit.h"
+#include "pmmemento.h"
+#include "pmviewstructure.h"
+
+#include <klocale.h>
+
+const PMIsoSurface::ContainedByType c_defaultContainedBy = PMIsoSurface::Box;
+const PMVector c_defaultCorner1 = PMVector( -1, -1, -1 );
+const PMVector c_defaultCorner2 = PMVector( 1, 1, 1 );
+const PMVector c_defaultCenter = PMVector( 0, 0, 0 );
+const double c_defaultRadius = 1;
+
+const double c_defaultThreshold = 0.0;
+const double c_defaultAccuracy = 0.001;
+const double c_defaultMaxGradient = 1.1;
+const bool c_defaultEvaluate = false;
+const double c_defaultEvaluate0 = 5;
+const double c_defaultEvaluate1 = 1.2;
+const double c_defaultEvaluate2 = 0.95;
+const double c_defaultOpen = false;
+const int c_defaultMaxTrace = 1;
+const bool c_defaultAllIntersections = false;
+
+PMDefinePropertyClass( PMIsoSurface, PMIsoSurfaceProperty );
+
+PMViewStructure* PMIsoSurface::s_pDefaultViewStructure = 0;
+PMMetaObject* PMIsoSurface::s_pMetaObject = 0;
+PMObject* createNewIsoSurface( PMPart* part )
+{
+ return new PMIsoSurface( part );
+}
+
+PMIsoSurface::PMIsoSurface( PMPart* part )
+ : Base( part )
+{
+ m_containedBy = c_defaultContainedBy;
+ m_corner1 = c_defaultCorner1;
+ m_corner2 = c_defaultCorner2;
+ m_center = c_defaultCenter;
+ m_radius = c_defaultRadius;
+ m_threshold = c_defaultThreshold;
+ m_accuracy = c_defaultAccuracy;
+ m_maxGradient = c_defaultMaxGradient;
+ m_bEvaluate = c_defaultEvaluate;
+ m_evaluate[0] = c_defaultEvaluate0;
+ m_evaluate[1] = c_defaultEvaluate1;
+ m_evaluate[2] = c_defaultEvaluate2;
+ m_bOpen = c_defaultOpen;
+ m_maxTrace = c_defaultMaxTrace;
+ m_bAllIntersections = c_defaultAllIntersections;
+}
+
+PMIsoSurface::PMIsoSurface( const PMIsoSurface& b )
+ : Base( b )
+{
+ m_function = b.m_function;
+ m_containedBy = b.m_containedBy;
+ m_corner1 = b.m_corner1;
+ m_corner2 = b.m_corner2;
+ m_center = b.m_center;
+ m_radius = b.m_radius;
+ m_threshold = b.m_threshold;
+ m_accuracy = b.m_accuracy;
+ m_maxGradient = m_maxGradient;
+ m_bEvaluate = b.m_bEvaluate;
+ m_evaluate[0] = b.m_evaluate[0];
+ m_evaluate[1] = b.m_evaluate[1];
+ m_evaluate[2] = b.m_evaluate[2];
+ m_bOpen = b.m_bOpen;
+ m_maxTrace = b.m_maxTrace;
+ m_bAllIntersections = b.m_bAllIntersections;
+}
+
+PMIsoSurface::~PMIsoSurface( )
+{
+}
+
+QString PMIsoSurface::description( ) const
+{
+ return i18n( "isosurface" );
+}
+
+void PMIsoSurface::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ QDomText t = doc.createTextNode( m_function );
+ e.appendChild( t );
+
+ if( m_containedBy == Box )
+ e.setAttribute( "contained_by", "box" );
+ else
+ e.setAttribute( "contained_by", "sphere" );
+ e.setAttribute( "corner_a", m_corner1.serializeXML( ) );
+ e.setAttribute( "corner_b", m_corner2.serializeXML( ) );
+ e.setAttribute( "center", m_center.serializeXML( ) );
+ e.setAttribute( "radius", m_radius );
+ e.setAttribute( "threshold", m_threshold );
+ e.setAttribute( "accuracy", m_accuracy );
+ e.setAttribute( "max_gradient", m_maxGradient );
+ e.setAttribute( "evaluate", m_bEvaluate );
+ e.setAttribute( "e0", m_evaluate[0] );
+ e.setAttribute( "e1", m_evaluate[1] );
+ e.setAttribute( "e2", m_evaluate[2] );
+ e.setAttribute( "open", m_bOpen );
+ e.setAttribute( "max_trace", m_maxTrace );
+ e.setAttribute( "all_intersections", m_bAllIntersections );
+ Base::serialize( e, doc );
+}
+
+void PMIsoSurface::readAttributes( const PMXMLHelper& h )
+{
+ QDomNode e = h.element( ).firstChild( );
+ if( e.isText( ) )
+ m_function = e.toText( ).data( );
+
+ QString str = h.stringAttribute( "contained_by", "" );
+ if( str == "sphere" )
+ m_containedBy = Sphere;
+ else
+ m_containedBy = Box;
+
+ m_corner1 = h.vectorAttribute( "corner_a", c_defaultCorner1 );
+ m_corner2 = h.vectorAttribute( "corner_b", c_defaultCorner1 );
+ m_center = h.vectorAttribute( "center", c_defaultCenter );
+ m_radius = h.doubleAttribute( "radius", c_defaultRadius );
+ m_threshold = h.doubleAttribute( "threshold", c_defaultThreshold );
+ m_accuracy = h.doubleAttribute( "accuracy", c_defaultAccuracy );
+ m_maxGradient = h.doubleAttribute( "max_gradient", c_defaultMaxGradient );
+ m_bEvaluate = h.boolAttribute( "evaluate", c_defaultEvaluate );
+ m_evaluate[0] = h.doubleAttribute( "e0", c_defaultEvaluate0 );
+ m_evaluate[1] = h.doubleAttribute( "e1", c_defaultEvaluate1 );
+ m_evaluate[2] = h.doubleAttribute( "e2", c_defaultEvaluate2 );
+ m_bOpen = h.boolAttribute( "open", c_defaultOpen );
+ m_maxTrace = h.intAttribute( "max_trace", c_defaultMaxTrace );
+ m_bAllIntersections = h.boolAttribute( "all_intersections", c_defaultAllIntersections );
+
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMIsoSurface::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "IsoSurface", Base::metaObject( ),
+ createNewIsoSurface );
+ // TODO
+ /*
+ s_pMetaObject->addProperty(
+ new PMIsoSurfaceProperty( "corner1", &PMIsoSurface::setCorner1, &PMIsoSurface::corner1 ) );
+ s_pMetaObject->addProperty(
+ new PMIsoSurfaceProperty( "corner2", &PMIsoSurface::setCorner2, &PMIsoSurface::corner2 ) );
+ */
+ }
+ return s_pMetaObject;
+}
+
+void PMIsoSurface::setFunction( const QString& f )
+{
+ if( f != m_function )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, FunctionID, m_function );
+ m_function = f;
+ }
+}
+
+void PMIsoSurface::setContainedBy( ContainedByType type )
+{
+ if( type != m_containedBy )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, ContainedByID, m_containedBy );
+ m_containedBy = type;
+ }
+}
+
+void PMIsoSurface::setCorner1( const PMVector& p )
+{
+ if( p != m_corner1 )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, Corner1ID, m_corner1 );
+ m_corner1 = p;
+ m_corner1.resize( 3 );
+ //setViewStructureChanged( );
+ }
+}
+
+void PMIsoSurface::setCorner2( const PMVector& p )
+{
+ if( p != m_corner2 )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, Corner2ID, m_corner2 );
+ m_corner2 = p;
+ m_corner2.resize( 3 );
+ //setViewStructureChanged( );
+ }
+}
+
+void PMIsoSurface::setCenter( const PMVector& v )
+{
+ if( v != m_center )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, CenterID, m_center );
+ m_center = v;
+ }
+}
+
+void PMIsoSurface::setRadius( double r )
+{
+ if( r != m_radius )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, RadiusID, m_radius );
+ m_radius = r;
+ }
+}
+void PMIsoSurface::setThreshold( double d )
+{
+ if( d != m_threshold )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, ThresholdID, m_threshold );
+ m_threshold = d;
+ }
+}
+
+void PMIsoSurface::setAccuracy( double d )
+{
+ if( d != m_accuracy )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, AccuracyID, m_accuracy );
+ m_accuracy = d;
+ }
+}
+
+void PMIsoSurface::setMaxGradient( double d )
+{
+ if( d != m_maxGradient )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, MaxGradientID, m_maxGradient );
+ m_maxGradient = d;
+ }
+}
+void PMIsoSurface::setEvaluate( bool yes )
+{
+ if( yes != m_bEvaluate )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, EvaluateID, m_evaluate );
+ m_bEvaluate = yes;
+ }
+}
+
+void PMIsoSurface::setEvaluateValue( int index, double v )
+{
+ if( index < 0 || index > 2 )
+ {
+ kdError( PMArea ) << "Illegal index in PMIsoSurface::setEvaluateValue" << endl;
+ return;
+ }
+
+ if( v != m_evaluate[index] )
+ {
+ if( m_pMemento )
+ {
+ int id = Evaluate0ID;
+ switch( index )
+ {
+ case 0: id = Evaluate0ID; break;
+ case 1: id = Evaluate1ID; break;
+ case 2: id = Evaluate2ID; break;
+ default: break;
+ }
+
+ m_pMemento->addData( s_pMetaObject, id, m_evaluate[index] );
+ }
+ m_evaluate[index] = v;
+ }
+}
+
+void PMIsoSurface::setOpen( bool yes )
+{
+ if( yes != m_bOpen )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, OpenID, m_bOpen );
+ m_bOpen = yes;
+ }
+}
+
+void PMIsoSurface::setMaxTrace( int i )
+{
+ if( i != m_maxTrace )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, MaxTraceID, m_maxTrace );
+ m_maxTrace = i;
+ }
+}
+
+void PMIsoSurface::setAllIntersections( bool yes )
+{
+ if( yes != m_bAllIntersections )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, AllIntersectionsID, m_bAllIntersections );
+ m_bAllIntersections = yes;
+ }
+}
+
+PMDialogEditBase* PMIsoSurface::editWidget( QWidget* parent ) const
+{
+ return new PMIsoSurfaceEdit( parent );
+}
+
+void PMIsoSurface::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case FunctionID:
+ setFunction( data->stringData( ) );
+ break;
+ case ContainedByID:
+ setContainedBy( ( ContainedByType ) data->intData( ) );
+ break;
+ case Corner1ID:
+ setCorner1( data->vectorData( ) );
+ break;
+ case Corner2ID:
+ setCorner2( data->vectorData( ) );
+ break;
+ case CenterID:
+ setCenter( data->vectorData( ) );
+ break;
+ case RadiusID:
+ setRadius( data->doubleData( ) );
+ break;
+ case ThresholdID:
+ setThreshold( data->doubleData( ) );
+ break;
+ case AccuracyID:
+ setAccuracy( data->doubleData( ) );
+ break;
+ case MaxGradientID:
+ setMaxGradient( data->doubleData( ) );
+ break;
+ case EvaluateID:
+ setEvaluate( data->boolData( ) );
+ break;
+ case Evaluate0ID:
+ setEvaluateValue( 0, data->doubleData( ) );
+ break;
+ case Evaluate1ID:
+ setEvaluateValue( 1, data->doubleData( ) );
+ break;
+ case Evaluate2ID:
+ setEvaluateValue( 2, data->doubleData( ) );
+ break;
+ case OpenID:
+ setOpen( data->boolData( ) );
+ break;
+ case MaxTraceID:
+ setMaxTrace( data->intData( ) );
+ break;
+ case AllIntersectionsID:
+ setAllIntersections( data->boolData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMIsoSurface::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
+
+void PMIsoSurface::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
diff --git a/kpovmodeler/pmisosurface.h b/kpovmodeler/pmisosurface.h
new file mode 100644
index 00000000..0646aff3
--- /dev/null
+++ b/kpovmodeler/pmisosurface.h
@@ -0,0 +1,234 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMISOSURFACE_H
+#define PMISOSURFACE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobject.h"
+#include "pmvector.h"
+
+class PMViewStructure;
+
+/**
+ * Class for povray boxes.
+ */
+
+class PMIsoSurface : public PMSolidObject
+{
+ typedef PMSolidObject Base;
+public:
+ /**
+ * Enum for the "contained_by" statement
+ */
+ enum ContainedByType { Box, Sphere };
+ /**
+ * Creates an empty PMIsoSurface
+ */
+ PMIsoSurface( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMIsoSurface( const PMIsoSurface& b );
+ /**
+ * deletes the PMIsoSurface
+ */
+ virtual ~PMIsoSurface( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMIsoSurface( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMIsoSurfaceEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmisosurface" ); }
+
+
+ /**
+ * Sets the isosurface function
+ */
+ void setFunction( const QString& f );
+ /**
+ * Returns the isosurface function
+ */
+ QString function( ) const { return m_function; }
+ /**
+ * Sets the type of the contained_by object
+ */
+ void setContainedBy( ContainedByType type );
+ /**
+ * Returns the type of the contained_by object
+ */
+ ContainedByType containedBy( ) const { return m_containedBy; }
+ /**
+ * Sets the first corner of a contained_by box
+ */
+ void setCorner1( const PMVector& v );
+ /**
+ * Returns the first corner of a contained_by box
+ */
+ PMVector corner1( ) const { return m_corner1; }
+ /**
+ * Sets the second corner of a contained_by box
+ */
+ void setCorner2( const PMVector& v );
+ /**
+ * Returns the second corner of a contained_by box
+ */
+ PMVector corner2( ) const { return m_corner2; }
+ /**
+ * Sets the center of a contained_by sphere
+ */
+ void setCenter( const PMVector& v );
+ /**
+ * Returns the center of a contained_by sphere
+ */
+ PMVector center( ) const { return m_center; }
+ /**
+ * Sets the radius of a contained_by sphere
+ */
+ void setRadius( double r );
+ /**
+ * Returns the radius of a contained_by sphere
+ */
+ double radius( ) const { return m_radius; }
+ /**
+ * Sets the threshold
+ */
+ void setThreshold( double d );
+ /**
+ * Returns the Threshold
+ */
+ double threshold( ) const { return m_threshold; }
+ /**
+ * Sets the accuracy
+ */
+ void setAccuracy( double d );
+ /**
+ * Returns the accuracy
+ */
+ double accuracy( ) const { return m_accuracy; }
+ /**
+ * Sets the maximal gradient
+ */
+ void setMaxGradient( double d );
+ /**
+ * Returns the maximal Gradient
+ */
+ double maxGradient( ) const { return m_maxGradient; }
+ /**
+ * Enables/disables the evaluate statement
+ */
+ void setEvaluate( bool yes );
+ /**
+ * Returns the evaluate flag
+ */
+ bool evaluate( ) const { return m_bEvaluate; }
+ /**
+ * Sets the i-th evaluate value, index is in [0..2]
+ */
+ void setEvaluateValue( int index, double v );
+ /**
+ * Returns the i-th evaluate value
+ */
+ double evaluateValue( int index ) const { return m_evaluate[index]; }
+ /**
+ * Sets the open flag
+ */
+ void setOpen( bool yes );
+ /**
+ * Returns the open flag
+ */
+ bool open( ) const { return m_bOpen; }
+ /**
+ * Sets the maximal number of intersections
+ */
+ void setMaxTrace( int i );
+ /**
+ * Returns the maximal number of intersections
+ */
+ int maxTrace( ) const { return m_maxTrace; }
+ /**
+ * Sets the all intersections flag
+ */
+ void setAllIntersections( bool yes );
+ /**
+ * Returns the all intersections flag
+ */
+ bool allIntersections( ) const { return m_bAllIntersections; }
+
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /** */
+ virtual void cleanUp( ) const;
+
+protected:
+ /** */
+ //virtual bool isDefault( );
+ /** */
+ //virtual void createViewStructure( );
+ /** */
+ //virtual PMViewStructure* defaultViewStructure( ) const;
+
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMIsoSurfaceMementoID { FunctionID, ContainedByID, Corner1ID, Corner2ID,
+ CenterID, RadiusID, ThresholdID, AccuracyID,
+ MaxGradientID, EvaluateID,
+ Evaluate0ID, Evaluate1ID, Evaluate2ID,
+ OpenID, MaxTraceID, AllIntersectionsID };
+
+ QString m_function;
+ ContainedByType m_containedBy;
+ PMVector m_corner1, m_corner2, m_center;
+ double m_radius, m_threshold, m_accuracy, m_maxGradient;
+ bool m_bEvaluate;
+ double m_evaluate[3];
+ bool m_bOpen;
+ int m_maxTrace;
+ bool m_bAllIntersections;
+
+ /**
+ * The default view structure. It can be shared between boxes
+ */
+ static PMViewStructure* s_pDefaultViewStructure;
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmisosurfaceedit.cpp b/kpovmodeler/pmisosurfaceedit.cpp
new file mode 100644
index 00000000..b4eb0216
--- /dev/null
+++ b/kpovmodeler/pmisosurfaceedit.cpp
@@ -0,0 +1,326 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmisosurfaceedit.h"
+#include "pmisosurface.h"
+#include "pmvectoredit.h"
+#include "pmlineedits.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qcombobox.h>
+#include <qcheckbox.h>
+#include <klocale.h>
+
+PMIsoSurfaceEdit::PMIsoSurfaceEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMIsoSurfaceEdit::createTopWidgets( )
+{
+ int i;
+ QGridLayout* gl;
+ QHBoxLayout* hl;
+
+ Base::createTopWidgets( );
+
+ m_pFunction = new QLineEdit( this );
+ m_pContainedBy = new QComboBox( false, this );
+ m_pContainedBy->insertItem( i18n( "Box" ) );
+ m_pContainedBy->insertItem( i18n( "Sphere" ) );
+
+ m_pCorner1 = new PMVectorEdit( "x", "y", "z", this );
+ m_pCorner2 = new PMVectorEdit( "x", "y", "z", this );
+ m_pCenter = new PMVectorEdit( "x", "y", "z", this );
+ m_pRadius = new PMFloatEdit( this );
+ m_pCorner1Label = new QLabel( i18n( "Corner1:" ), this );
+ m_pCorner2Label = new QLabel( i18n( "Corner2:" ), this );
+ m_pCenterLabel = new QLabel( i18n( "Center:" ), this );
+ m_pRadiusLabel = new QLabel( i18n( "Radius:" ), this );
+
+ m_pThreshold = new PMFloatEdit( this );
+ m_pAccuracy = new PMFloatEdit( this );
+ m_pAccuracy->setValidation( true, 1e-8, false, 0 );
+ m_pMaxGradient = new PMFloatEdit( this );
+ m_pMaxGradient->setValidation( true, 1e-8, false, 0 );
+ m_pEvaluate = new QCheckBox( i18n( "Adapt maximum gradient" ), this );
+ for( i = 0; i < 3; i++ )
+ m_pEvaluateValue[i] = new PMFloatEdit( this );
+ m_pMaxTrace = new PMIntEdit( this );
+ m_pMaxTrace->setValidation( true, 1, false, 0 );
+ m_pAllIntersections = new QCheckBox( i18n( "All intersections" ), this );
+ m_pOpen = new QCheckBox( i18n( "type of the object", "Open" ), this );
+
+ gl = new QGridLayout( topLayout( ), 8, 2 );
+ gl->addWidget( new QLabel( i18n( "Function:" ), this ), 0, 0 );
+ gl->addWidget( m_pFunction, 0, 1 );
+ gl->addWidget( new QLabel( i18n( "Container:" ), this ), 1, 0 );
+ gl->addWidget( m_pContainedBy, 1, 1 );
+ gl->addWidget( m_pCorner1Label, 2, 0 );
+ gl->addWidget( m_pCorner1, 2, 1 );
+ gl->addWidget( m_pCorner2Label, 3, 0 );
+ gl->addWidget( m_pCorner2, 3, 1 );
+ gl->addWidget( m_pCenterLabel, 4, 0 );
+ gl->addWidget( m_pCenter, 4, 1 );
+ gl->addWidget( m_pRadiusLabel, 5, 0 );
+ gl->addWidget( m_pRadius, 5, 1 );
+ gl->addWidget( new QLabel( i18n( "Threshold:" ), this ), 6, 0 );
+ gl->addWidget( m_pThreshold, 6, 1 );
+ gl->addWidget( new QLabel( i18n( "Accuracy:" ), this ), 7, 0 );
+ gl->addWidget( m_pAccuracy, 7, 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "Maximum gradient:" ), this ) );
+ hl->addWidget( m_pMaxGradient );
+
+ topLayout( )->addWidget( m_pEvaluate );
+ hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "Values:" ), this ) );
+ for( i = 0; i < 3; i++ )
+ {
+ hl->addWidget( new QLabel( QString( "P%1" ).arg( i ), this ) );
+ hl->addWidget( m_pEvaluateValue[i] );
+ }
+
+ hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "Maximum traces:" ), this ) );
+ hl->addWidget( m_pMaxTrace );
+ topLayout( )->addWidget( m_pAllIntersections );
+ topLayout( )->addWidget( m_pOpen );
+
+ connect( m_pFunction, SIGNAL( textChanged( const QString& ) ),
+ SLOT( textChanged( const QString& ) ) );
+ connect( m_pContainedBy, SIGNAL( activated( int ) ),
+ SLOT( currentChanged( int ) ) );
+ connect( m_pCorner1, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pCorner2, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pCenter, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pRadius, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pThreshold, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pAccuracy, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pMaxGradient, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pEvaluate, SIGNAL( toggled( bool ) ),
+ SLOT( evaluateToggled( bool ) ) );
+ connect( m_pMaxTrace, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ for( i = 0; i < 3; i++ )
+ connect( m_pEvaluateValue[i], SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pOpen, SIGNAL( toggled( bool ) ), SLOT( toggled( bool ) ) );
+ connect( m_pAllIntersections, SIGNAL( toggled( bool ) ),
+ SLOT( allToggled( bool ) ) );
+}
+
+void PMIsoSurfaceEdit::displayObject( PMObject* o )
+{
+ int i;
+
+ if( o->isA( "IsoSurface" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMIsoSurface* ) o;
+
+ m_pFunction->setText( m_pDisplayedObject->function( ) );
+ if( m_pDisplayedObject->containedBy( ) == PMIsoSurface::Box )
+ {
+ m_pContainedBy->setCurrentItem( 0 );
+ m_pCorner1Label->show( );
+ m_pCorner2Label->show( );
+ m_pCorner1->show( );
+ m_pCorner2->show( );
+ m_pCenterLabel->hide( );
+ m_pCenter->hide( );
+ m_pRadiusLabel->hide( );
+ m_pRadius->hide( );
+ }
+ else
+ {
+ m_pContainedBy->setCurrentItem( 1 );
+ m_pCorner1Label->hide( );
+ m_pCorner2Label->hide( );
+ m_pCorner1->hide( );
+ m_pCorner2->hide( );
+ m_pCenterLabel->show( );
+ m_pCenter->show( );
+ m_pRadiusLabel->show( );
+ m_pRadius->show( );
+ }
+
+ m_pCorner1->setVector( m_pDisplayedObject->corner1( ) );
+ m_pCorner2->setVector( m_pDisplayedObject->corner2( ) );
+ m_pCenter->setVector( m_pDisplayedObject->center( ) );
+ m_pRadius->setValue( m_pDisplayedObject->radius( ) );
+ m_pThreshold->setValue( m_pDisplayedObject->threshold( ) );
+ m_pAccuracy->setValue( m_pDisplayedObject->accuracy( ) );
+ m_pMaxGradient->setValue( m_pDisplayedObject->maxGradient( ) );
+ bool ev = m_pDisplayedObject->evaluate( );
+ m_pEvaluate->setChecked( ev );
+
+ for( i = 0; i < 3; i++ )
+ {
+ m_pEvaluateValue[i]->setValue( m_pDisplayedObject->evaluateValue( i ) );
+ m_pEvaluateValue[i]->setEnabled( ev );
+ }
+
+ m_pOpen->setChecked( m_pDisplayedObject->open( ) );
+ m_pMaxTrace->setValue( m_pDisplayedObject->maxTrace( ) );
+ bool all = m_pDisplayedObject->allIntersections( );
+ m_pAllIntersections->setChecked( all );
+ m_pMaxTrace->setEnabled( !all );
+
+ m_pFunction->setReadOnly( readOnly );
+ m_pContainedBy->setEnabled( !readOnly );
+ m_pCorner1->setReadOnly( readOnly );
+ m_pCorner2->setReadOnly( readOnly );
+ m_pCenter->setReadOnly( readOnly );
+ m_pRadius->setReadOnly( readOnly );
+ m_pThreshold->setReadOnly( readOnly );
+ m_pAccuracy->setReadOnly( readOnly );
+ m_pMaxGradient->setReadOnly( readOnly );
+ m_pEvaluate->setEnabled( !readOnly );
+ for( i = 0; i < 3; i++ )
+ m_pEvaluateValue[i]->setReadOnly( readOnly );
+ m_pOpen->setEnabled( !readOnly );
+ m_pMaxTrace->setReadOnly( readOnly );
+ m_pAllIntersections->setEnabled( !readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMIsoSurfaceEdit: Can't display object\n";
+}
+
+void PMIsoSurfaceEdit::saveContents( )
+{
+ int i;
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setFunction( m_pFunction->text( ) );
+ if( m_pContainedBy->currentItem( ) == 0 )
+ {
+ m_pDisplayedObject->setContainedBy( PMIsoSurface::Box );
+ m_pDisplayedObject->setCorner1( m_pCorner1->vector( ) );
+ m_pDisplayedObject->setCorner2( m_pCorner2->vector( ) );
+ }
+ else
+ {
+ m_pDisplayedObject->setContainedBy( PMIsoSurface::Sphere );
+ m_pDisplayedObject->setCenter( m_pCenter->vector( ) );
+ m_pDisplayedObject->setRadius( m_pRadius->value( ) );
+ }
+ m_pDisplayedObject->setThreshold( m_pThreshold->value( ) );
+ m_pDisplayedObject->setAccuracy( m_pAccuracy->value( ) );
+ m_pDisplayedObject->setMaxGradient( m_pMaxGradient->value( ) );
+ m_pDisplayedObject->setEvaluate( m_pEvaluate->isChecked( ) );
+ if( m_pEvaluate->isChecked( ) )
+ for( i = 0; i < 3; i++ )
+ m_pDisplayedObject->setEvaluateValue( i, m_pEvaluateValue[i]->value( ) );
+ m_pDisplayedObject->setOpen( m_pOpen->isChecked( ) );
+ m_pDisplayedObject->setAllIntersections( m_pAllIntersections->isChecked( ) );
+ if( !m_pAllIntersections->isChecked( ) )
+ m_pDisplayedObject->setMaxTrace( m_pMaxTrace->value( ) );
+ }
+}
+
+bool PMIsoSurfaceEdit::isDataValid( )
+{
+ int i;
+
+ if( m_pContainedBy->currentItem( ) == 0 )
+ {
+ if( !m_pCorner1->isDataValid( ) )
+ return false;
+ if( !m_pCorner2->isDataValid( ) )
+ return false;
+ }
+ else
+ {
+ if( !m_pCenter->isDataValid( ) )
+ return false;
+ if( !m_pRadius->isDataValid( ) )
+ return false;
+ }
+ if( !m_pThreshold->isDataValid( ) )
+ return false;
+ if( !m_pAccuracy->isDataValid( ) )
+ return false;
+ if( !m_pMaxGradient->isDataValid( ) )
+ return false;
+ if( m_pEvaluate->isChecked( ) )
+ for( i = 0; i < 3; i++ )
+ if( !m_pEvaluateValue[i]->isDataValid( ) )
+ return false;
+ if( !m_pAllIntersections->isChecked( ) && !m_pMaxTrace->isDataValid( ) )
+ return false;
+ return Base::isDataValid( );
+}
+
+void PMIsoSurfaceEdit::textChanged( const QString& )
+{
+ emit dataChanged( );
+}
+
+void PMIsoSurfaceEdit::currentChanged( int i )
+{
+ if( i == 0 )
+ {
+ m_pCorner1Label->show( );
+ m_pCorner2Label->show( );
+ m_pCorner1->show( );
+ m_pCorner2->show( );
+ m_pCenterLabel->hide( );
+ m_pCenter->hide( );
+ m_pRadiusLabel->hide( );
+ m_pRadius->hide( );
+ }
+ else
+ {
+ m_pCorner1Label->hide( );
+ m_pCorner2Label->hide( );
+ m_pCorner1->hide( );
+ m_pCorner2->hide( );
+ m_pCenterLabel->show( );
+ m_pCenter->show( );
+ m_pRadiusLabel->show( );
+ m_pRadius->show( );
+ }
+ emit dataChanged( );
+}
+
+void PMIsoSurfaceEdit::evaluateToggled( bool yes )
+{
+ int i;
+ for( i = 0; i < 3; i++ )
+ m_pEvaluateValue[i]->setEnabled( yes );
+ emit dataChanged( );
+}
+
+void PMIsoSurfaceEdit::allToggled( bool yes )
+{
+ m_pMaxTrace->setEnabled( !yes );
+ emit dataChanged( );
+}
+
+void PMIsoSurfaceEdit::toggled( bool )
+{
+ emit dataChanged( );
+}
+
+#include "pmisosurfaceedit.moc"
diff --git a/kpovmodeler/pmisosurfaceedit.h b/kpovmodeler/pmisosurfaceedit.h
new file mode 100644
index 00000000..9ee6e872
--- /dev/null
+++ b/kpovmodeler/pmisosurfaceedit.h
@@ -0,0 +1,92 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMISOSURFACEEDIT_H
+#define PMISOSURFACEEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobjectedit.h"
+
+class PMIsoSurface;
+class PMVectorEdit;
+class PMFloatEdit;
+class PMIntEdit;
+class QCheckBox;
+class QComboBox;
+class QLabel;
+class QLineEdit;
+
+/**
+ * Dialog edit class for @ref PMIsoSurface
+ */
+class PMIsoSurfaceEdit : public PMSolidObjectEdit
+{
+ Q_OBJECT
+ typedef PMSolidObjectEdit Base;
+public:
+ /**
+ * Creates a PMIsoSurfaceEdit with parent and name
+ */
+ PMIsoSurfaceEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private slots:
+ void textChanged( const QString& );
+ void currentChanged( int i );
+ void evaluateToggled( bool );
+ void allToggled( bool );
+ void toggled( bool );
+
+private:
+ PMIsoSurface* m_pDisplayedObject;
+ QLineEdit* m_pFunction;
+ QComboBox* m_pContainedBy;
+ PMVectorEdit* m_pCorner1;
+ PMVectorEdit* m_pCorner2;
+ PMVectorEdit* m_pCenter;
+ PMFloatEdit* m_pRadius;
+ QLabel* m_pCorner1Label;
+ QLabel* m_pCorner2Label;
+ QLabel* m_pCenterLabel;
+ QLabel* m_pRadiusLabel;
+ PMFloatEdit* m_pThreshold;
+ PMFloatEdit* m_pAccuracy;
+ PMFloatEdit* m_pMaxGradient;
+ QCheckBox* m_pEvaluate;
+ PMFloatEdit* m_pEvaluateValue[3];
+ QCheckBox* m_pOpen;
+ PMIntEdit* m_pMaxTrace;
+ QCheckBox* m_pAllIntersections;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmjuliafractal.cpp b/kpovmodeler/pmjuliafractal.cpp
new file mode 100644
index 00000000..49ca9de5
--- /dev/null
+++ b/kpovmodeler/pmjuliafractal.cpp
@@ -0,0 +1,449 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmjuliafractal.h"
+
+#include "pmxmlhelper.h"
+#include "pmjuliafractaledit.h"
+#include "pmmemento.h"
+#include "pmviewstructure.h"
+#include "pm3dcontrolpoint.h"
+#include "pmenumproperty.h"
+
+#include <klocale.h>
+
+const PMVector c_defaultJuliaParameter = PMVector( -0.083, 0.0, -0.83, -0.025 );
+const PMVector c_defaultSliceNormal = PMVector( 0.0, 0.0, 0.0, 1.0 );
+const double c_defaultSliceDistance = 0.0;
+const int c_defaultMaxIterations = 20;
+const PMJuliaFractal::AlgebraType c_defaultAlgebraType = PMJuliaFractal::Quaternion;
+const QString c_defaultAlgebraString = "quaternion";
+const PMJuliaFractal::FunctionType c_defaultFunctionType = PMJuliaFractal::FTsqr;
+const QString c_defaultFunctionString = "sqr";
+const PMVector c_defaultExponent = PMVector( 0.0, 0.0 );
+const double c_defaultPrecision = 20.0;
+
+
+PMDefinePropertyClass( PMJuliaFractal, PMJuliaFractalProperty );
+PMDefineEnumPropertyClass( PMJuliaFractal, PMJuliaFractal::AlgebraType,
+ PMAlgebraTypeProperty );
+PMDefineEnumPropertyClass( PMJuliaFractal, PMJuliaFractal::FunctionType,
+ PMFunctionTypeProperty );
+
+PMMetaObject* PMJuliaFractal::s_pMetaObject = 0;
+PMObject* createNewJuliaFractal( PMPart* part )
+{
+ return new PMJuliaFractal( part );
+}
+
+PMJuliaFractal::PMJuliaFractal( PMPart* part )
+ : Base( part )
+{
+ m_juliaParameter = c_defaultJuliaParameter;
+ m_algebraType = c_defaultAlgebraType;
+ m_functionType = c_defaultFunctionType;
+ m_maxIterations = c_defaultMaxIterations;
+ m_precision = c_defaultPrecision;
+ m_sliceNormal = c_defaultSliceNormal;
+ m_sliceDistance = c_defaultSliceDistance;
+ m_exponent = c_defaultExponent;
+}
+
+PMJuliaFractal::PMJuliaFractal( const PMJuliaFractal& f )
+ : Base( f )
+{
+ m_juliaParameter = f.m_juliaParameter;
+ m_algebraType = f.m_algebraType;
+ m_functionType = f.m_functionType;
+ m_maxIterations = f.m_maxIterations;
+ m_precision = f.m_precision;
+ m_sliceNormal = f.m_sliceNormal;
+ m_sliceDistance = f.m_sliceDistance;
+ m_exponent = f.m_exponent;
+}
+
+PMJuliaFractal::~PMJuliaFractal( )
+{
+}
+
+QString PMJuliaFractal::description( ) const
+{
+ return i18n( "julia fractal" );
+}
+
+void PMJuliaFractal::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "julia_parameter", m_juliaParameter.serializeXML( ) );
+ e.setAttribute( "algebra_type", algebraTypeToString( m_algebraType ) );
+ e.setAttribute( "function_type", functionTypeToString( m_functionType ) );
+ e.setAttribute( "max_iterations", m_maxIterations );
+ e.setAttribute( "precision", m_precision );
+ e.setAttribute( "slice_normal", m_sliceNormal.serializeXML( ) );
+ e.setAttribute( "slice_distance", m_sliceDistance );
+ e.setAttribute( "exponent", m_exponent.serializeXML( ) );
+ Base::serialize( e, doc );
+}
+
+void PMJuliaFractal::readAttributes( const PMXMLHelper& h )
+{
+ m_juliaParameter = h.vectorAttribute( "julia_parameter", c_defaultJuliaParameter );
+ m_algebraType = stringToAlgebraType( h.stringAttribute( "algebra_type", c_defaultAlgebraString ) );
+ m_functionType = stringToFunctionType( h.stringAttribute( "function_type", c_defaultFunctionString ) );
+ m_maxIterations = h.intAttribute( "max_iterations", c_defaultMaxIterations );
+ m_precision = h.doubleAttribute( "precision", c_defaultPrecision );
+ m_sliceNormal = h.vectorAttribute( "slice_normal", c_defaultSliceNormal );
+ m_sliceDistance = h.doubleAttribute( "slice_distance", c_defaultSliceDistance );
+ m_exponent = h.vectorAttribute( "exponent", c_defaultExponent );
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMJuliaFractal::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "JuliaFractal", Base::metaObject( ),
+ createNewJuliaFractal );
+ s_pMetaObject->addProperty(
+ new PMJuliaFractalProperty( "juliaParameter", &PMJuliaFractal::setJuliaParameter,
+ &PMJuliaFractal::juliaParameter ) );
+ s_pMetaObject->addProperty(
+ new PMJuliaFractalProperty( "maximumIterations", &PMJuliaFractal::setMaximumIterations,
+ &PMJuliaFractal::maximumIterations ) );
+ s_pMetaObject->addProperty(
+ new PMJuliaFractalProperty( "precision", &PMJuliaFractal::setPrecision,
+ &PMJuliaFractal::precision ) );
+ s_pMetaObject->addProperty(
+ new PMJuliaFractalProperty( "sliceNormal", &PMJuliaFractal::setSliceNormal,
+ &PMJuliaFractal::sliceNormal ) );
+ s_pMetaObject->addProperty(
+ new PMJuliaFractalProperty( "sliceDistance", &PMJuliaFractal::setSliceDistance,
+ &PMJuliaFractal::sliceDistance ) );
+ s_pMetaObject->addProperty(
+ new PMJuliaFractalProperty( "exponent", &PMJuliaFractal::setExponent,
+ &PMJuliaFractal::exponent ) );
+
+ PMAlgebraTypeProperty* ap = new PMAlgebraTypeProperty(
+ "algebraType", &PMJuliaFractal::setAlgebraType, &PMJuliaFractal::algebraType );
+ ap->addEnumValue( "Quaternion", Quaternion );
+ ap->addEnumValue( "Hypercomplex", Hypercomplex );
+ s_pMetaObject->addProperty( ap );
+
+ PMFunctionTypeProperty* fp = new PMFunctionTypeProperty(
+ "functionType", &PMJuliaFractal::setFunctionType, &PMJuliaFractal::functionType );
+ fp->addEnumValue( "sqr", FTsqr );
+ fp->addEnumValue( "cube", FTcube );
+ fp->addEnumValue( "exp", FTexp );
+ fp->addEnumValue( "reciprocal", FTreciprocal );
+ fp->addEnumValue( "sin", FTsin );
+ fp->addEnumValue( "asin", FTasin );
+ fp->addEnumValue( "sinh", FTsinh );
+ fp->addEnumValue( "asinh", FTasinh );
+ fp->addEnumValue( "cos", FTcos );
+ fp->addEnumValue( "acos", FTacos );
+ fp->addEnumValue( "cosh", FTcosh );
+ fp->addEnumValue( "acosh", FTacosh );
+ fp->addEnumValue( "tan", FTtan );
+ fp->addEnumValue( "atan", FTatan );
+ fp->addEnumValue( "tanh", FTtanh );
+ fp->addEnumValue( "atanh", FTatanh );
+ fp->addEnumValue( "log", FTlog );
+ fp->addEnumValue( "pwr", FTpwr );
+ s_pMetaObject->addProperty( fp );
+ }
+ return s_pMetaObject;
+}
+
+void PMJuliaFractal::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMJuliaFractal::setJuliaParameter( const PMVector& p )
+{
+ if( p != m_juliaParameter )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMJuliaParameterID, m_juliaParameter );
+ m_juliaParameter = p;
+ m_juliaParameter.resize( 4 );
+ }
+}
+
+void PMJuliaFractal::setAlgebraType( PMJuliaFractal::AlgebraType t )
+{
+ if( m_algebraType != t )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAlgebraTypeID, m_algebraType );
+ m_algebraType = t;
+ }
+}
+
+void PMJuliaFractal::setFunctionType( PMJuliaFractal::FunctionType t )
+{
+ if( m_functionType != t )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFunctionTypeID, m_functionType );
+ m_functionType = t;
+ }
+}
+
+void PMJuliaFractal::setMaximumIterations( int max )
+{
+ if( max <= 0 )
+ {
+ kdError( PMArea ) << "max <= 0 in PMJuliaFractal::setMaximumIterations\n";
+ max = 20;
+ }
+ if( m_maxIterations != max )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMMaxIterationsID, m_maxIterations );
+ m_maxIterations = max;
+ }
+}
+
+void PMJuliaFractal::setPrecision( double p )
+{
+ if( p < 1.0 )
+ {
+ kdError( PMArea ) << "p < 1.0 in PMJuliaFractal::setPrecision\n";
+ p = 1.0;
+ }
+
+ if( m_precision != p )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMPrecisionID, m_precision );
+ m_precision = p;
+ }
+}
+
+void PMJuliaFractal::setSliceNormal( const PMVector& n )
+{
+ if( m_sliceNormal != n )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSliceNormalID, m_sliceNormal );
+ m_sliceNormal = n;
+ m_sliceNormal.resize( 4 );
+ }
+}
+
+void PMJuliaFractal::setSliceDistance( double d )
+{
+ if( m_sliceDistance != d )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSliceDistanceID, m_sliceDistance );
+ m_sliceDistance = d;
+ }
+}
+
+void PMJuliaFractal::setExponent( const PMVector& e )
+{
+ if( m_exponent != e )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMExponentID, m_exponent );
+ m_exponent = e;
+ m_exponent.resize( 2 );
+ }
+}
+
+PMDialogEditBase* PMJuliaFractal::editWidget( QWidget* parent ) const
+{
+ return new PMJuliaFractalEdit( parent );
+}
+
+void PMJuliaFractal::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMJuliaParameterID:
+ setJuliaParameter( data->vectorData( ) );
+ break;
+ case PMAlgebraTypeID:
+ setAlgebraType( ( AlgebraType ) data->intData( ) );
+ break;
+ case PMFunctionTypeID:
+ setFunctionType( ( FunctionType ) data->intData( ) );
+ break;
+ case PMMaxIterationsID:
+ setMaximumIterations( data->intData( ) );
+ break;
+ case PMPrecisionID:
+ setPrecision( data->doubleData( ) );
+ break;
+ case PMSliceNormalID:
+ setSliceNormal( data->vectorData( ) );
+ break;
+ case PMSliceDistanceID:
+ setSliceDistance( data->doubleData( ) );
+ break;
+ case PMExponentID:
+ setExponent( data->vectorData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMJuliaFractal::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
+QString PMJuliaFractal::functionTypeToString( PMJuliaFractal::FunctionType t )
+{
+ QString result = "sqr";
+ switch( t )
+ {
+ case FTsqr:
+ result = "sqr";
+ break;
+ case FTcube:
+ result = "cube";
+ break;
+ case FTexp:
+ result = "exp";
+ break;
+ case FTreciprocal:
+ result = "reciprocal";
+ break;
+ case FTsin:
+ result = "sin";
+ break;
+ case FTasin:
+ result = "asin";
+ break;
+ case FTsinh:
+ result = "sinh";
+ break;
+ case FTasinh:
+ result = "asinh";
+ break;
+ case FTcos:
+ result = "cos";
+ break;
+ case FTacos:
+ result = "acos";
+ break;
+ case FTcosh:
+ result = "cosh";
+ break;
+ case FTacosh:
+ result = "acosh";
+ break;
+ case FTtan:
+ result = "tan";
+ break;
+ case FTatan:
+ result = "atan";
+ break;
+ case FTtanh:
+ result = "tanh";
+ break;
+ case FTatanh:
+ result = "atanh";
+ break;
+ case FTlog:
+ result = "log";
+ break;
+ case FTpwr:
+ result = "pwr";
+ break;
+ }
+ return result;
+}
+
+PMJuliaFractal::FunctionType PMJuliaFractal::stringToFunctionType( const QString& str )
+{
+ FunctionType t = c_defaultFunctionType;
+
+ if( str == "sqr" )
+ t = FTsqr;
+ else if( str == "cube" )
+ t = FTcube;
+ else if( str == "exp" )
+ t = FTexp;
+ else if( str == "reciprocal" )
+ t = FTreciprocal;
+ else if( str == "sin" )
+ t = FTsin;
+ else if( str == "asin" )
+ t = FTasin;
+ else if( str == "sinh" )
+ t = FTsinh;
+ else if( str == "asinh" )
+ t = FTasinh;
+ else if( str == "cos" )
+ t = FTcos;
+ else if( str == "acos" )
+ t = FTacos;
+ else if( str == "cosh" )
+ t = FTcosh;
+ else if( str == "acosh" )
+ t = FTacosh;
+ else if( str == "tan" )
+ t = FTtan;
+ else if( str == "atan" )
+ t = FTatan;
+ else if( str == "tanh" )
+ t = FTtanh;
+ else if( str == "atanh" )
+ t = FTatanh;
+ else if( str == "log" )
+ t = FTlog;
+ else if( str == "pwr" )
+ t = FTpwr;
+ return t;
+}
+
+QString PMJuliaFractal::algebraTypeToString( PMJuliaFractal::AlgebraType t )
+{
+ QString result;
+ if( t == Quaternion )
+ result = "quaternion";
+ else
+ result = "hypercomplex";
+ return result;
+}
+
+PMJuliaFractal::AlgebraType PMJuliaFractal::stringToAlgebraType( const QString& str )
+{
+ AlgebraType t = c_defaultAlgebraType;
+ if( str == "quaternion" )
+ t = Quaternion;
+ else if( str == "hypercomplex" )
+ t = Hypercomplex;
+ return t;
+}
diff --git a/kpovmodeler/pmjuliafractal.h b/kpovmodeler/pmjuliafractal.h
new file mode 100644
index 00000000..1e93a46c
--- /dev/null
+++ b/kpovmodeler/pmjuliafractal.h
@@ -0,0 +1,174 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMJULIAFRACTAL_H
+#define PMJULIAFRACTAL_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobject.h"
+#include "pmvector.h"
+
+class PMViewStructure;
+
+/**
+ * Class for povray julia fractals.
+ */
+
+class PMJuliaFractal : public PMSolidObject
+{
+ typedef PMSolidObject Base;
+public:
+ enum AlgebraType { Quaternion, Hypercomplex };
+ enum FunctionType { FTsqr, FTcube, FTexp, FTreciprocal, FTsin, FTasin,
+ FTsinh, FTasinh, FTcos, FTacos, FTcosh, FTacosh,
+ FTtan, FTatan, FTtanh, FTatanh, FTlog, FTpwr };
+
+ /**
+ * Creates an empty PMJuliaFractal
+ */
+ PMJuliaFractal( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMJuliaFractal( const PMJuliaFractal& f );
+ /**
+ * deletes the PMJuliaFractal
+ */
+ virtual ~PMJuliaFractal( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMJuliaFractal( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMJuliaFractalEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmjuliafractal" ); }
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+
+ /**
+ * Returns the 4d julia parameter vector
+ */
+ PMVector juliaParameter( ) const { return m_juliaParameter; }
+ /**
+ * Sets the julia parameter vector
+ */
+ void setJuliaParameter( const PMVector& p );
+ /**
+ * Returns the algebra type
+ */
+ AlgebraType algebraType( ) const { return m_algebraType; }
+ /**
+ * Sets the algebra type
+ */
+ void setAlgebraType( AlgebraType t );
+ /**
+ * Returns the function type
+ */
+ FunctionType functionType( ) const { return m_functionType; }
+ /**
+ * Sets the function type
+ */
+ void setFunctionType( FunctionType t );
+ /**
+ * Returns the maximum number of iterations
+ */
+ int maximumIterations( ) const { return m_maxIterations; }
+ /**
+ * Sets the maximum number of iterations
+ */
+ void setMaximumIterations( int m );
+ /**
+ * Returns the precision
+ */
+ double precision( ) const { return m_precision; }
+ /**
+ * Sets the precision
+ */
+ void setPrecision( double p );
+ /**
+ * Returns the slice normal (4D vector)
+ */
+ PMVector sliceNormal( ) const { return m_sliceNormal; }
+ /**
+ * Sets the slice normal (4D vector)
+ */
+ void setSliceNormal( const PMVector& v );
+ /**
+ * Returns the slice distance
+ */
+ double sliceDistance( ) const { return m_sliceDistance; }
+ /**
+ * Sets the slice distance
+ */
+ void setSliceDistance( double d );
+ /**
+ * Returns the exponent for the pow function type (2D vector)
+ */
+ PMVector exponent( ) const { return m_exponent; }
+ /**
+ * Sets the exponent for the pow function type (2D Vector)
+ */
+ void setExponent( const PMVector& p );
+
+ static QString functionTypeToString( FunctionType t );
+ static FunctionType stringToFunctionType( const QString& str );
+ static QString algebraTypeToString( AlgebraType t );
+ static AlgebraType stringToAlgebraType( const QString& str );
+private:
+
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMJuliaFractalMementoID { PMJuliaParameterID, PMAlgebraTypeID,
+ PMFunctionTypeID, PMMaxIterationsID,
+ PMPrecisionID, PMSliceNormalID,
+ PMSliceDistanceID, PMExponentID };
+ PMVector m_juliaParameter;
+ AlgebraType m_algebraType;
+ FunctionType m_functionType;
+ int m_maxIterations;
+ double m_precision;
+ PMVector m_sliceNormal;
+ double m_sliceDistance;
+ PMVector m_exponent;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmjuliafractaledit.cpp b/kpovmodeler/pmjuliafractaledit.cpp
new file mode 100644
index 00000000..43f351c5
--- /dev/null
+++ b/kpovmodeler/pmjuliafractaledit.cpp
@@ -0,0 +1,380 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmjuliafractaledit.h"
+#include "pmjuliafractal.h"
+#include "pmvectoredit.h"
+#include "pmlineedits.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcombobox.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+PMJuliaFractalEdit::PMJuliaFractalEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMJuliaFractalEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* hl;
+ QGridLayout* gl;
+
+ topLayout( )->addWidget( new QLabel( i18n( "Julia parameter:" ), this ) );
+ m_pJuliaParameter = new PMVectorEdit( "", "i", "j", "k", this );
+ topLayout( )->addWidget( m_pJuliaParameter );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "Algebra type:" ), this ) );
+ m_pAlgebraType = new QComboBox( false, this );
+ m_pAlgebraType->insertItem( i18n( "Quaternion" ) );
+ m_pAlgebraType->insertItem( i18n( "Hypercomplex" ) );
+ hl->addWidget( m_pAlgebraType );
+ hl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "Function type:" ), this ) );
+ m_pFunctionType = new QComboBox( false, this );
+ m_pFunctionType->insertItem( "sqr" );
+ m_pFunctionType->insertItem( "cube" );
+ m_pFunctionType->insertItem( "exp" );
+ m_pFunctionType->insertItem( "reciprocal" );
+ m_pFunctionType->insertItem( "sin" );
+ m_pFunctionType->insertItem( "asin" );
+ m_pFunctionType->insertItem( "sinh" );
+ m_pFunctionType->insertItem( "asinh" );
+ m_pFunctionType->insertItem( "cos" );
+ m_pFunctionType->insertItem( "acos" );
+ m_pFunctionType->insertItem( "cosh" );
+ m_pFunctionType->insertItem( "acosh" );
+ m_pFunctionType->insertItem( "tan" );
+ m_pFunctionType->insertItem( "atan" );
+ m_pFunctionType->insertItem( "tanh" );
+ m_pFunctionType->insertItem( "atanh" );
+ m_pFunctionType->insertItem( "log" );
+ m_pFunctionType->insertItem( "pwr" );
+ hl->addWidget( m_pFunctionType );
+ hl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ m_pExponentsLabel = new QLabel( i18n( "Exponent:" ), this );
+ hl->addWidget( m_pExponentsLabel );
+ m_pExponents = new PMVectorEdit( "", "i", this );
+ hl->addWidget( m_pExponents );
+ hl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ gl = new QGridLayout( hl, 2, 2 );
+ gl->addWidget( new QLabel( i18n( "Maximum iterations:" ), this ), 0, 0 );
+ m_pMaxIterations = new PMIntEdit( this );
+ m_pMaxIterations->setValidation( true, 1, false, 0 );
+ gl->addWidget( m_pMaxIterations, 0, 1 );
+ gl->addWidget( new QLabel( i18n( "Precision:" ), this ), 1, 0 );
+ m_pPrecision = new PMFloatEdit( this );
+ m_pPrecision->setValidation( true, 1.0, false, 0.0 );
+ gl->addWidget( m_pPrecision, 1, 1 );
+ hl->addStretch( 1 );
+
+ topLayout( )->addWidget( new QLabel( i18n( "Slice normal:" ), this ) );
+ m_pSliceNormal = new PMVectorEdit( "", "i", "j", "k", this );
+ topLayout( )->addWidget( m_pSliceNormal );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "Slice distance:" ), this ) );
+ m_pSliceDistance = new PMFloatEdit( this );
+ hl->addWidget( m_pSliceDistance );
+ hl->addStretch( 1 );
+
+ connect( m_pJuliaParameter, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pAlgebraType, SIGNAL( activated( int ) ),
+ SLOT( slotAlgebraTypeSelected( int ) ) );
+ connect( m_pFunctionType, SIGNAL( activated( int ) ),
+ SLOT( slotFunctionTypeSelected( int ) ) );
+ connect( m_pExponents, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pMaxIterations, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pPrecision, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pSliceNormal, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pSliceDistance, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMJuliaFractalEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "JuliaFractal" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMJuliaFractal* ) o;
+
+ m_pJuliaParameter->setVector( m_pDisplayedObject->juliaParameter( ) );
+ switch( m_pDisplayedObject->algebraType( ) )
+ {
+ case PMJuliaFractal::Quaternion:
+ m_pAlgebraType->setCurrentItem( 0 );
+ break;
+ case PMJuliaFractal::Hypercomplex:
+ m_pAlgebraType->setCurrentItem( 1 );
+ break;
+ }
+ switch( m_pDisplayedObject->functionType( ) )
+ {
+ case PMJuliaFractal::FTsqr:
+ m_pFunctionType->setCurrentItem( 0 );
+ break;
+ case PMJuliaFractal::FTcube:
+ m_pFunctionType->setCurrentItem( 1 );
+ break;
+ case PMJuliaFractal::FTexp:
+ m_pFunctionType->setCurrentItem( 2 );
+ break;
+ case PMJuliaFractal::FTreciprocal:
+ m_pFunctionType->setCurrentItem( 3 );
+ break;
+ case PMJuliaFractal::FTsin:
+ m_pFunctionType->setCurrentItem( 4 );
+ break;
+ case PMJuliaFractal::FTasin:
+ m_pFunctionType->setCurrentItem( 5 );
+ break;
+ case PMJuliaFractal::FTsinh:
+ m_pFunctionType->setCurrentItem( 6 );
+ break;
+ case PMJuliaFractal::FTasinh:
+ m_pFunctionType->setCurrentItem( 7 );
+ break;
+ case PMJuliaFractal::FTcos:
+ m_pFunctionType->setCurrentItem( 8 );
+ break;
+ case PMJuliaFractal::FTacos:
+ m_pFunctionType->setCurrentItem( 9 );
+ break;
+ case PMJuliaFractal::FTcosh:
+ m_pFunctionType->setCurrentItem( 10 );
+ break;
+ case PMJuliaFractal::FTacosh:
+ m_pFunctionType->setCurrentItem( 11 );
+ break;
+ case PMJuliaFractal::FTtan:
+ m_pFunctionType->setCurrentItem( 12 );
+ break;
+ case PMJuliaFractal::FTatan:
+ m_pFunctionType->setCurrentItem( 13 );
+ break;
+ case PMJuliaFractal::FTtanh:
+ m_pFunctionType->setCurrentItem( 14 );
+ break;
+ case PMJuliaFractal::FTatanh:
+ m_pFunctionType->setCurrentItem( 15 );
+ break;
+ case PMJuliaFractal::FTlog:
+ m_pFunctionType->setCurrentItem( 16 );
+ break;
+ case PMJuliaFractal::FTpwr:
+ m_pFunctionType->setCurrentItem( 17 );
+ break;
+ }
+ m_pExponents->setVector( m_pDisplayedObject->exponent( ) );
+ if( m_pDisplayedObject->functionType( ) == PMJuliaFractal::FTpwr )
+ {
+ m_pExponents->show( );
+ m_pExponentsLabel->show( );
+ }
+ else
+ {
+ m_pExponents->hide( );
+ m_pExponentsLabel->hide( );
+ }
+
+ m_pMaxIterations->setValue( m_pDisplayedObject->maximumIterations( ) );
+ m_pPrecision->setValue( m_pDisplayedObject->precision( ) );
+ m_pSliceNormal->setVector( m_pDisplayedObject->sliceNormal( ) );
+ m_pSliceDistance->setValue( m_pDisplayedObject->sliceDistance( ) );
+
+ m_pJuliaParameter->setReadOnly( readOnly );
+ m_pAlgebraType->setEnabled( !readOnly );
+ m_pFunctionType->setEnabled( !readOnly );
+ m_pExponents->setReadOnly( readOnly );
+ m_pMaxIterations->setReadOnly( readOnly );
+ m_pPrecision->setReadOnly( readOnly );
+ m_pSliceNormal->setReadOnly( readOnly );
+ m_pSliceDistance->setReadOnly( readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMJuliaFractalEdit: Can't display object\n";
+}
+
+void PMJuliaFractalEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ PMVector p( 4 );
+
+ m_pDisplayedObject->setJuliaParameter( m_pJuliaParameter->vector( ) );
+ switch( m_pAlgebraType->currentItem( ) )
+ {
+ case 0:
+ m_pDisplayedObject->setAlgebraType( PMJuliaFractal::Quaternion );
+ break;
+ case 1:
+ m_pDisplayedObject->setAlgebraType( PMJuliaFractal::Hypercomplex );
+ break;
+ default:
+ m_pDisplayedObject->setAlgebraType( PMJuliaFractal::Quaternion );
+ break;
+ }
+ switch( m_pFunctionType->currentItem( ) )
+ {
+ case 0:
+ m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTsqr );
+ break;
+ case 1:
+ m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTcube );
+ break;
+ case 2:
+ m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTexp );
+ break;
+ case 3:
+ m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTreciprocal );
+ break;
+ case 4:
+ m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTsin );
+ break;
+ case 5:
+ m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTasin );
+ break;
+ case 6:
+ m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTsinh );
+ break;
+ case 7:
+ m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTasinh );
+ break;
+ case 8:
+ m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTcos );
+ break;
+ case 9:
+ m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTacos );
+ break;
+ case 10:
+ m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTcosh );
+ break;
+ case 11:
+ m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTacosh );
+ break;
+ case 12:
+ m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTtan );
+ break;
+ case 13:
+ m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTatan );
+ break;
+ case 14:
+ m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTtanh );
+ break;
+ case 15:
+ m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTatanh );
+ break;
+ case 16:
+ m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTlog );
+ break;
+ case 17:
+ m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTpwr );
+ break;
+ default:
+ m_pDisplayedObject->setFunctionType( PMJuliaFractal::FTsqr );
+ break;
+ }
+ if( m_pExponents->isVisible( ) )
+ m_pDisplayedObject->setExponent( m_pExponents->vector( ) );
+ m_pDisplayedObject->setMaximumIterations( m_pMaxIterations->value( ) );
+ m_pDisplayedObject->setPrecision( m_pPrecision->value( ) );
+ m_pDisplayedObject->setSliceNormal( m_pSliceNormal->vector( ) );
+ m_pDisplayedObject->setSliceDistance( m_pSliceDistance->value( ) );
+ }
+}
+
+bool PMJuliaFractalEdit::isDataValid( )
+{
+ if( !m_pJuliaParameter->isDataValid( ) )
+ return false;
+ if( m_pExponents->isVisible( ) )
+ if( !m_pExponents->isDataValid( ) )
+ return false;
+ if( !m_pMaxIterations->isDataValid( ) )
+ return false;
+ if( !m_pPrecision->isDataValid( ) )
+ return false;
+ if( !m_pSliceNormal->isDataValid( ) )
+ return false;
+ PMVector v = m_pSliceNormal->vector( );
+ if( approxZero( v.abs( ) ) )
+ {
+ KMessageBox::error( this, i18n( "The slice normal vector may not be a null vector." ),
+ i18n( "Error" ) );
+ return false;
+ }
+ if( approxZero( v[3] ) )
+ {
+ KMessageBox::error( this, i18n( "The 'k' component of the slice normal vector may not be zero." ),
+ i18n( "Error" ) );
+ return false;
+ }
+
+ if( !m_pSliceDistance->isDataValid( ) )
+ return false;
+
+ if( m_pAlgebraType->currentItem( ) == 0 )
+ {
+ if( m_pFunctionType->currentItem( ) > 1 )
+ {
+ KMessageBox::error( this, i18n( "Only the functions 'sqr' and 'cube' "
+ "are defined in the quaternion algebra." ),
+ i18n( "Error" ) );
+ return false;
+ }
+ }
+
+
+ return Base::isDataValid( );
+}
+
+void PMJuliaFractalEdit::slotAlgebraTypeSelected( int )
+{
+ emit dataChanged( );
+}
+
+void PMJuliaFractalEdit::slotFunctionTypeSelected( int index )
+{
+ if( index == 17 )
+ {
+ m_pExponents->show( );
+ m_pExponentsLabel->show( );
+ }
+ else
+ {
+ m_pExponents->hide( );
+ m_pExponentsLabel->hide( );
+ }
+ emit dataChanged( );
+}
+
+#include "pmjuliafractaledit.moc"
diff --git a/kpovmodeler/pmjuliafractaledit.h b/kpovmodeler/pmjuliafractaledit.h
new file mode 100644
index 00000000..598ea144
--- /dev/null
+++ b/kpovmodeler/pmjuliafractaledit.h
@@ -0,0 +1,79 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMJULIAFRACTALEDIT_H
+#define PMJULIAFRACTALEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobjectedit.h"
+
+class PMJuliaFractal;
+class PMVectorEdit;
+class PMIntEdit;
+class PMFloatEdit;
+class QComboBox;
+class QLabel;
+
+/**
+ * Dialog edit class for @ref PMJuliaFractal
+ */
+class PMJuliaFractalEdit : public PMSolidObjectEdit
+{
+ Q_OBJECT
+ typedef PMSolidObjectEdit Base;
+public:
+ /**
+ * Creates a PMJuliaFractalEdit with parent and name
+ */
+ PMJuliaFractalEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+protected slots:
+ void slotAlgebraTypeSelected( int );
+ void slotFunctionTypeSelected( int );
+
+private:
+ PMJuliaFractal* m_pDisplayedObject;
+ PMVectorEdit* m_pJuliaParameter;
+ QComboBox* m_pAlgebraType;
+ QComboBox* m_pFunctionType;
+ PMVectorEdit* m_pExponents;
+ QLabel* m_pExponentsLabel;
+ PMIntEdit* m_pMaxIterations;
+ PMFloatEdit* m_pPrecision;
+ PMVectorEdit* m_pSliceNormal;
+ PMFloatEdit* m_pSliceDistance;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmlathe.cpp b/kpovmodeler/pmlathe.cpp
new file mode 100644
index 00000000..f6c3c3c3
--- /dev/null
+++ b/kpovmodeler/pmlathe.cpp
@@ -0,0 +1,948 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmlathe.h"
+
+#include "pmxmlhelper.h"
+#include "pmlatheedit.h"
+#include "pmmemento.h"
+#include "pmviewstructure.h"
+#include "pm2dcontrolpoint.h"
+#include "pmsplinememento.h"
+#include "pmsplinesegment.h"
+#include "pmdefaults.h"
+#include "pmenumproperty.h"
+#include "pmobjectaction.h"
+
+#include <klocale.h>
+
+const int defaultNumberOfPoints = 4;
+const PMVector defaultPoint[defaultNumberOfPoints] =
+{
+ PMVector( 0.0, 1.0 ),
+ PMVector( 0.5, 0.7 ),
+ PMVector( 0.5, 0.3 ),
+ PMVector( 0.0, 0.0 )
+};
+
+const bool defaultSturm = false;
+const PMLathe::SplineType defaultSplineType = PMLathe::LinearSpline;
+
+PMDefinePropertyClass( PMLathe, PMLatheProperty );
+PMDefineEnumPropertyClass( PMLathe, PMLathe::SplineType, PMSplineTypeProperty );
+
+PMMetaObject* PMLathe::s_pMetaObject = 0;
+PMObject* createNewLathe( PMPart* part )
+{
+ return new PMLathe( part );
+}
+
+class PMPointProperty : public PMPropertyBase
+{
+public:
+ PMPointProperty( )
+ : PMPropertyBase( "splinePoints", PMVariant::Vector )
+ {
+ m_index = 0;
+ }
+ virtual int dimensions( ) const { return 1; }
+ virtual void setIndex( int /*dimension*/, int index )
+ {
+ m_index = index;
+ }
+ virtual int size( PMObject* object, int /*dimension*/ ) const
+ {
+ return ( ( PMLathe* ) object )->numberOfPoints( );
+ }
+protected:
+ virtual bool setProtected( PMObject* obj, const PMVariant& var )
+ {
+ PMLathe* p = ( PMLathe* ) obj;
+ QValueList<PMVector> list = p->points( );
+ QValueList<PMVector>::Iterator it = list.begin( );
+ int i;
+ PMVector v = var.vectorData( );
+ v.resize( 2 );
+
+ for( i = 0; i < m_index && it != list.end( ); ++i )
+ ++it;
+ // expand the list if necessary
+ for( ; i < m_index; ++i )
+ list.insert( it, v );
+ if( it == list.end( ) )
+ it = list.insert( it, v );
+ else
+ *it = v;
+
+ p->setPoints( list );
+ return true;
+ }
+ virtual PMVariant getProtected( const PMObject* obj )
+ {
+ PMLathe* p = ( PMLathe* ) obj;
+ QValueList<PMVector> list = p->points( );
+ QValueList<PMVector>::ConstIterator it = list.at( m_index );
+
+ if( it == list.end( ) )
+ {
+ kdError( PMArea ) << "Range error in PMLathe::PointProperty::get" << endl;
+ return PMVariant( );
+ }
+
+ return PMVariant( *it );
+ }
+
+private:
+ int m_index;
+};
+
+
+int PMLathe::s_rSteps = c_defaultLatheRSteps;
+int PMLathe::s_sSteps = c_defaultLatheSSteps;
+int PMLathe::s_parameterKey = 0;
+
+PMLathe::PMLathe( PMPart* part )
+ : Base( part )
+{
+ int i;
+
+ for( i = 0; i < defaultNumberOfPoints; ++i )
+ m_points.append( defaultPoint[i] );
+ m_splineType = defaultSplineType;
+ m_sturm = defaultSturm;
+}
+
+PMLathe::PMLathe( const PMLathe& l )
+ : Base( l )
+{
+ m_points = l.m_points;
+ m_splineType = l.m_splineType;
+ m_sturm = l.m_sturm;
+}
+
+PMLathe::~PMLathe( )
+{
+}
+
+QString PMLathe::description( ) const
+{
+ return i18n( "lathe" );
+}
+
+void PMLathe::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ QDomElement data = doc.createElement( "extra_data" );
+ QDomElement p;
+
+ e.setAttribute( "spline_type", m_splineType );
+ e.setAttribute( "sturm", m_sturm );
+
+ QValueList<PMVector>::ConstIterator it;
+ for( it = m_points.begin( ); it != m_points.end( ); ++it )
+ {
+ p = doc.createElement( "point" );
+ p.setAttribute( "vector", ( *it ).serializeXML( ) );
+ data.appendChild( p );
+ }
+
+ e.appendChild( data );
+ Base::serialize( e, doc );
+}
+
+void PMLathe::readAttributes( const PMXMLHelper& h )
+{
+ m_splineType = ( SplineType ) h.intAttribute( "spline_type", defaultSplineType );
+ m_sturm = h.boolAttribute( "sturm", defaultSturm );
+
+ m_points.clear( );
+ PMVector v( 2 );
+
+ QDomElement e = h.extraData( );
+ if( !e.isNull( ) )
+ {
+ QDomNode c = e.firstChild( );
+ while( !c.isNull( ) )
+ {
+ if( c.isElement( ) )
+ {
+ QDomElement ce = c.toElement( );
+ if( ce.tagName( ) == "point" )
+ {
+ QString str = ce.attribute( "vector" );
+ if( !str.isNull( ) )
+ {
+ v.loadXML( str );
+ m_points.append( v );
+ }
+ }
+ }
+ c = c.nextSibling( );
+ }
+ }
+
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMLathe::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Lathe", Base::metaObject( ),
+ createNewLathe );
+ s_pMetaObject->addProperty(
+ new PMLatheProperty( "sturm", &PMLathe::setSturm, &PMLathe::sturm ) );
+ PMSplineTypeProperty* p = new PMSplineTypeProperty(
+ "splineType", &PMLathe::setSplineType, &PMLathe::splineType );
+ p->addEnumValue( "LinearSpline", LinearSpline );
+ p->addEnumValue( "QuadraticSpline", QuadraticSpline );
+ p->addEnumValue( "CubicSpline", CubicSpline );
+ p->addEnumValue( "BezierSpline", BezierSpline );
+ s_pMetaObject->addProperty( p );
+ s_pMetaObject->addProperty( new PMPointProperty( ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMLathe::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMLathe::setSplineType( PMLathe::SplineType t )
+{
+ if( m_splineType != t )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSplineTypeID, ( int ) m_splineType );
+ setViewStructureChanged( );
+ m_splineType = t;
+ }
+}
+
+void PMLathe::setSturm( bool s )
+{
+ if( m_sturm != s )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSturmID, m_sturm );
+ m_sturm = s;
+ }
+}
+
+void PMLathe::setPoints( const QValueList<PMVector>& points )
+{
+ if( m_points != points )
+ {
+ if( m_pMemento )
+ ( ( PMSplineMemento* ) m_pMemento )->setSplinePoints( m_points );
+
+ setViewStructureChanged( );
+ m_points = points;
+ }
+}
+
+PMDialogEditBase* PMLathe::editWidget( QWidget* parent ) const
+{
+ return new PMLatheEdit( parent );
+}
+
+void PMLathe::createMemento( )
+{
+ if( m_pMemento )
+ delete m_pMemento;
+ m_pMemento = new PMSplineMemento( this );
+}
+
+void PMLathe::restoreMemento( PMMemento* s )
+{
+ PMSplineMemento* m = ( PMSplineMemento* ) s;
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMSplineTypeID:
+ setSplineType( ( SplineType ) data->intData( ) );
+ break;
+ case PMSturmID:
+ setSturm( data->boolData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMLathe::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ if( m->splinePointsSaved( ) )
+ setPoints( m->splinePoints( ) );
+
+ Base::restoreMemento( s );
+}
+
+
+void PMLathe::createViewStructure( )
+{
+ if( s_sSteps == 0 )
+ s_sSteps = c_defaultLatheSSteps;
+ if( s_rSteps == 0 )
+ s_rSteps = c_defaultLatheRSteps;
+
+ int rSteps = (int)( ( (float)s_rSteps / 2 ) * ( displayDetail( ) + 1 ) );
+ int sSteps = (int)( ( (float)s_sSteps / 2 ) * ( displayDetail( ) + 1 ) );
+
+ int np = m_points.count( );
+ int ns = 0;
+ int i, j, r, si;
+
+ // calculate number of segments
+ switch( m_splineType )
+ {
+ case LinearSpline:
+ ns = np - 1;
+ break;
+ case QuadraticSpline:
+ ns = np - 2;
+ break;
+ case CubicSpline:
+ ns = np - 3;
+ break;
+ case BezierSpline:
+ ns = np / 4;
+ break;
+ }
+
+ // calculate number of points and lines of the view structure
+ int vsp = 0;
+ if( m_splineType != BezierSpline )
+ vsp = ns * sSteps + 1;
+ else
+ vsp = ns * ( sSteps + 1 );
+
+ int vsl = 0;
+ if( m_splineType != BezierSpline )
+ vsl = ( 2 * vsp - 1 ) * rSteps;
+ else
+ vsl = ns * ( ( 2 * sSteps + 1 ) * rSteps );
+
+ vsp *= rSteps;
+
+ if( m_pViewStructure )
+ {
+ if( m_pViewStructure->points( ).size( ) != ( unsigned ) vsp )
+ m_pViewStructure->points( ).resize( vsp );
+ if( m_pViewStructure->lines( ).size( ) != ( unsigned ) vsl )
+ m_pViewStructure->lines( ).resize( vsl );
+ }
+ else
+ m_pViewStructure = new PMViewStructure( vsp, vsl );
+
+
+ // calculate the spline segments
+ QValueList<PMSplineSegment> segments;
+ QValueList<PMVector>::Iterator it1, it2, it3, it4;
+ it1 = m_points.begin( );
+ it2 = it1; ++it2;
+ it3 = it2; ++it3;
+ it4 = it3; ++it4;
+ PMSplineSegment s;
+
+ for( i = 0; i < ns; ++i )
+ {
+ switch( m_splineType )
+ {
+ case LinearSpline:
+ s.calculateLinear( *it1, *it2 );
+ ++it1;
+ ++it2;
+ break;
+ case QuadraticSpline:
+ s.calculateQuadratic( *it1, *it2, *it3 );
+ ++it1;
+ ++it2;
+ ++it3;
+ break;
+ case CubicSpline:
+ s.calculateCubic( *it1, *it2, *it3, *it4 );
+ ++it1;
+ ++it2;
+ ++it3;
+ ++it4;
+ break;
+ case BezierSpline:
+ s.calculateBezier( *it1, *it2, *it3, *it4 );
+ for( j = 0; j < 4; ++j )
+ {
+ ++it1;
+ ++it2;
+ ++it3;
+ ++it4;
+ }
+ break;
+ }
+ segments.append( s );
+ }
+
+ // create the line array
+ if( m_splineType != BezierSpline )
+ {
+ PMLineArray& lines = m_pViewStructure->lines( );
+ int vl = ns * sSteps;
+ int lb = 0;
+ for( i = 0; i < vl + 1; ++i )
+ {
+ for( j = 0; j < rSteps - 1; ++j )
+ lines[lb+j] = PMLine( lb + j, lb + j + 1 );
+ lines[lb+rSteps-1] = PMLine( lb, lb + rSteps - 1 );
+ lb += rSteps;
+ }
+ int pi = 0;
+ for( i = 0; i < vl; ++i )
+ {
+ for( j = 0; j < rSteps; ++j )
+ {
+ lines[lb] = PMLine( pi, pi + rSteps );
+ ++pi;
+ ++lb;
+ }
+ }
+ }
+ else
+ {
+ PMLineArray& lines = m_pViewStructure->lines( );
+ int lb = 0;
+ int pi = 0;
+
+ for( si = 0; si < ns; ++si )
+ {
+ for( i = 0; i < sSteps + 1; ++i )
+ {
+ for( j = 0; j < rSteps - 1; ++j )
+ lines[lb+j] = PMLine( lb + j, lb + j + 1 );
+ lines[lb+rSteps-1] = PMLine( lb, lb + rSteps - 1 );
+ lb += rSteps;
+ }
+ }
+ for( si = 0; si < ns; ++si )
+ {
+ for( i = 0; i < sSteps; ++i )
+ {
+ for( j = 0; j < rSteps; ++j )
+ {
+ lines[lb] = PMLine( pi, pi + rSteps );
+ ++pi;
+ ++lb;
+ }
+ }
+ pi += rSteps;
+ }
+ }
+ // calculate the points
+ PMVector point2, point3;
+ QValueList<PMSplineSegment>::Iterator sit = segments.begin( );
+ int pi = 0;
+
+ double poffset = 1.0 / sSteps;
+ PMMatrix rot = PMMatrix::rotation( 0.0, M_PI * 2.0 / rSteps, 0.0 );
+ PMPointArray& points = m_pViewStructure->points( );
+
+ if( m_splineType != BezierSpline )
+ {
+ for( i = 0; i < ns; ++i, ++sit )
+ {
+ for( j = 0; j < sSteps; ++j )
+ {
+ point2 = ( *sit ).point( poffset * j );
+ point3[0] = point2[0];
+ point3[1] = point2[1];
+ point3[2] = 0.0;
+
+ for( r = 0; r < rSteps; ++r )
+ {
+ points[pi] = PMPoint( point3 );
+ if( r != rSteps - 1 )
+ point3.transform( rot );
+ ++pi;
+ }
+ }
+ if( i == ns - 1 )
+ {
+ point2 = ( *sit ).point( 1.0 );
+ point3[0] = point2[0];
+ point3[1] = point2[1];
+ point3[2] = 0.0;
+
+ for( r = 0; r < rSteps; ++r )
+ {
+ points[pi] = PMPoint( point3 );
+ if( r != rSteps - 1 )
+ point3.transform( rot );
+ ++pi;
+ }
+ }
+ }
+ }
+ else
+ {
+ for( i = 0; i < ns; ++i, ++sit )
+ {
+ for( j = 0; j < sSteps + 1; ++j )
+ {
+ point2 = ( *sit ).point( poffset * j );
+ point3[0] = point2[0];
+ point3[1] = point2[1];
+ point3[2] = 0.0;
+
+ for( r = 0; r < rSteps; ++r )
+ {
+ points[pi] = PMPoint( point3 );
+ if( r != rSteps - 1 )
+ point3.transform( rot );
+ ++pi;
+ }
+ }
+ }
+ }
+}
+
+void PMLathe::controlPoints( PMControlPointList& list )
+{
+ QValueList<PMVector>::Iterator it;
+ int i, d;
+
+ PM2DControlPoint* cp = 0;
+ QPtrList<PM2DControlPoint> tmp[2];
+
+ for( d = 0; d < 2; ++d )
+ {
+ if( m_splineType != BezierSpline )
+ {
+ PM2DControlPoint* firstPoint = 0;
+ PM2DControlPoint* lastPoint = 0;
+
+ for( it = m_points.begin( ), i = 0; it != m_points.end( ); ++it, ++i )
+ {
+ lastPoint = cp;
+ if( d == 0 )
+ cp = new PM2DControlPoint( *it, PM2DControlPoint::PM2DXY, i,
+ i18n( "Point %1 (xy)" ).arg( i + 1 ) );
+ else
+ cp = new PM2DControlPoint( *it, PM2DControlPoint::PM2DZY, i,
+ i18n( "Point %1 (xy)" ).arg( i + 1 ) );
+
+ if( i == 0 )
+ firstPoint = cp;
+ if( ( i == 1 ) && ( m_splineType != LinearSpline ) )
+ firstPoint->setBasePoint( cp );
+
+ tmp[d].append( cp );
+ }
+ if( m_splineType == CubicSpline )
+ cp->setBasePoint( lastPoint );
+ }
+ else
+ {
+ PM2DControlPoint* helpPoint = 0;
+
+ for( it = m_points.begin( ), i = 0; it != m_points.end( ); ++it, ++i )
+ {
+ int imod4 = i % 4;
+ if( d == 0 )
+ cp = new PM2DControlPoint( *it, PM2DControlPoint::PM2DXY, i,
+ i18n( "Point %1 (xy)" ).arg( i + 1 ) );
+ else
+ cp = new PM2DControlPoint( *it, PM2DControlPoint::PM2DZY, i,
+ i18n( "Point %1 (xy)" ).arg( i + 1 ) );
+ switch( imod4 )
+ {
+ case 0:
+ helpPoint = cp;
+ break;
+ case 1:
+ cp->setBasePoint( helpPoint );
+ break;
+ case 2:
+ helpPoint = cp;
+ break;
+ case 3:
+ helpPoint->setBasePoint( cp );
+ break;
+ default:
+ break;
+ }
+
+ tmp[d].append( cp );
+ }
+ }
+ }
+
+ QPtrListIterator<PM2DControlPoint> cit1( tmp[0] ), cit2( tmp[1] );
+
+ for( ; cit1.current( ) && cit2.current( ); ++cit1, ++cit2 )
+ {
+ ( *cit1 )->setLatheLink( *cit2 );
+ ( *cit2 )->setLatheLink( *cit1 );
+ }
+ for( cit1.toFirst( ); cit1.current( ); ++cit1 )
+ list.append( *cit1 );
+ for( cit2.toFirst( ); cit2.current( ); ++cit2 )
+ list.append( *cit2 );
+}
+
+void PMLathe::controlPointsChanged( PMControlPointList& list )
+{
+ PMControlPointListIterator it1( list ), it2( list );
+ QValueList<PMVector>::Iterator pit = m_points.begin( );
+ PM2DControlPoint* p1;
+ PM2DControlPoint* p2;
+ bool firstChange = true;
+
+ for( it2 += list.count( ) / 2; it2.current( ); ++it1, ++it2, ++pit )
+ {
+ p1 = ( PM2DControlPoint* ) it1.current( );
+ p2 = ( PM2DControlPoint* ) it2.current( );
+
+ if( p1->changed( ) )
+ {
+ if( firstChange )
+ {
+ if( m_pMemento )
+ {
+ PMSplineMemento* m = ( PMSplineMemento* ) m_pMemento;
+ if( !m->splinePointsSaved( ) )
+ m->setSplinePoints( m_points );
+ }
+ firstChange = false;
+ setViewStructureChanged( );
+ }
+ p2->setPoint( p1->point( ) );
+ ( *pit ) = p1->point( );
+ }
+ else if( p2->changed( ) )
+ {
+ if( firstChange )
+ {
+ if( m_pMemento )
+ {
+ PMSplineMemento* m = ( PMSplineMemento* ) m_pMemento;
+ if( !m->splinePointsSaved( ) )
+ m->setSplinePoints( m_points );
+ }
+ firstChange = false;
+ setViewStructureChanged( );
+ }
+ p1->setPoint( p2->point( ) );
+ ( *pit ) = p2->point( );
+ }
+ }
+}
+
+void PMLathe::addObjectActions( const PMControlPointList& /*cp*/,
+ QPtrList<PMObjectAction>& actions )
+{
+ PMObjectAction* a;
+
+ a = new PMObjectAction( s_pMetaObject, PMSplitSegmentID,
+ i18n( "Add Point" ) );
+ actions.append( a );
+
+ a = new PMObjectAction( s_pMetaObject, PMJoinSegmentsID,
+ i18n( "Remove Point" ) );
+ int np = m_points.count( );
+ int minp = 3;
+ switch( m_splineType )
+ {
+ case LinearSpline:
+ minp = 3;
+ break;
+ case QuadraticSpline:
+ minp = 4;
+ break;
+ case CubicSpline:
+ minp = 5;
+ break;
+ case BezierSpline:
+ minp = 8;
+ break;
+ }
+
+ if( np < minp )
+ a->setEnabled( false );
+ actions.append( a );
+}
+
+void PMLathe::objectActionCalled( const PMObjectAction* action,
+ const PMControlPointList& cp,
+ const QPtrList<PMVector>& cpViewPosition,
+ const PMVector& clickPosition )
+{
+ if( action->objectType( ) == s_pMetaObject )
+ {
+ switch( action->actionID( ) )
+ {
+ case PMSplitSegmentID:
+ splitSegment( cp, cpViewPosition, clickPosition );
+ break;
+ case PMJoinSegmentsID:
+ joinSegments( cp, cpViewPosition, clickPosition );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMLathe::objectActionCalled\n";
+ break;
+ }
+ }
+ else
+ Base::objectActionCalled( action, cp, cpViewPosition, clickPosition );
+}
+
+void PMLathe::splitSegment( const PMControlPointList& /*cp*/,
+ const QPtrList<PMVector>& cpViewPosition,
+ const PMVector& clickPosition )
+{
+ // find nearest segment
+ int nump = cpViewPosition.count( ) / 2 - 1;
+ double abs = 0.0, minabs = 1e10;
+ int ns = -1;
+ int i, j;
+ PMVector mid( 3 ), dist( 2 );
+
+ QPtrListIterator<PMVector> it1( cpViewPosition );
+ QPtrListIterator<PMVector> it2( cpViewPosition );
+ ++it2;
+
+ for( j = 0; j < 2; ++j )
+ {
+ for( i = 0; i < nump; ++i )
+ {
+ bool skip = false;
+ switch( m_splineType )
+ {
+ case LinearSpline:
+ case BezierSpline:
+ break;
+ case QuadraticSpline:
+ if( i == 0 )
+ skip = true;
+ break;
+ case CubicSpline:
+ if( ( i == 0 ) || ( i == ( nump - 1 ) ) )
+ skip = true;
+ break;
+ }
+
+ if( !skip )
+ {
+ mid = ( **it1 + **it2 ) / 2.0;
+ dist[0] = mid[0];
+ dist[1] = mid[1];
+ dist -= clickPosition;
+ abs = dist.abs( );
+
+ if( ( minabs > abs ) || ( ns < 0 ) )
+ {
+ minabs = abs;
+ ns = i;
+ }
+ }
+ ++it1;
+ ++it2;
+ }
+ ++it1;
+ ++it2;
+ }
+
+ // add a new segment
+ QValueList<PMVector> newPoints = m_points;
+
+ if( m_splineType == BezierSpline )
+ {
+ ns /= 4;
+ ns *= 4;
+ }
+ QValueList<PMVector>::Iterator it = newPoints.at( ( unsigned ) ns );
+ PMVector p[4];
+ QValueList<PMVector>::Iterator hit = it;
+
+ // calculate the spline segment
+ PMSplineSegment segment;
+ switch( m_splineType )
+ {
+ case LinearSpline:
+ for( i = 0; i < 2; ++i, ++hit )
+ p[i] = *hit;
+ segment.calculateLinear( p[0], p[1] );
+ break;
+ case QuadraticSpline:
+ --hit;
+ for( i = 0; i < 3; ++i, ++hit )
+ p[i] = *hit;
+ segment.calculateQuadratic( p[0], p[1], p[2] );
+ break;
+ case CubicSpline:
+ --hit;
+ for( i = 0; i < 4; ++i, ++hit )
+ p[i] = *hit;
+ segment.calculateCubic( p[0], p[1], p[2], p[3] );
+ break;
+ case BezierSpline:
+ for( i = 0; i < 4; ++i, ++hit )
+ p[i] = *hit;
+ segment.calculateBezier( p[0], p[1], p[2], p[3] );
+ break;
+ }
+
+ mid = segment.point( 0.5 );
+ if( m_splineType != BezierSpline )
+ {
+ ++it;
+ newPoints.insert( it, mid );
+ }
+ else
+ {
+ PMVector end = *it;
+ ++it;
+ *it = end + ( *it - end ) / 2.0;
+ ++it;
+
+ PMVector grad = segment.gradient( 0.5 ) / 4.0;
+
+ newPoints.insert( it, mid - grad );
+ newPoints.insert( it, mid );
+ newPoints.insert( it, mid );
+ newPoints.insert( it, mid + grad );
+
+ ++it;
+ end = *it;
+ --it;
+ *it = end + ( *it - end ) / 2.0;
+ }
+ setPoints( newPoints );
+}
+
+void PMLathe::joinSegments( const PMControlPointList& /*cp*/,
+ const QPtrList<PMVector>& cpViewPosition,
+ const PMVector& clickPosition )
+{
+ // find nearest point
+ int nump = cpViewPosition.count( ) / 2;
+ int minp = 0;
+
+ switch( m_splineType )
+ {
+ case LinearSpline:
+ minp = 3;
+ break;
+ case QuadraticSpline:
+ minp = 4;
+ break;
+ case CubicSpline:
+ minp = 5;
+ break;
+ case BezierSpline:
+ minp = 8;
+ break;
+ }
+
+ if( nump < minp )
+ {
+ kdError( PMArea ) << "Not enough points in PMLathe::joinSegments\n";
+ return;
+ }
+
+ double abs = 0.0, minabs = 1e10;
+ int ns = -1;
+ int i, j;
+ PMVector* p;
+ PMVector dist( 2 );
+
+ QPtrListIterator<PMVector> it1( cpViewPosition );
+
+ for( j = 0; j < 2; ++j )
+ {
+ for( i = 0; i < nump; ++i )
+ {
+ p = *it1;
+ dist[0] = (*p)[0];
+ dist[1] = (*p)[1];
+ dist -= clickPosition;
+ abs = dist.abs( );
+
+ if( ( minabs > abs ) || ( ns < 0 ) )
+ {
+ minabs = abs;
+ ns = i;
+ }
+ ++it1;
+ }
+ }
+
+ // join two segments
+ QValueList<PMVector> newPoints = m_points;
+ QValueList<PMVector>::Iterator it;
+
+ if( m_splineType != BezierSpline )
+ {
+ // never remove the first or last point
+ if( ns == 0 )
+ ++ns;
+ if( ns == ( nump - 1 ) )
+ --ns;
+ it = newPoints.at( ns );
+ newPoints.remove( it );
+ }
+ else
+ {
+ ns = ( ns - 2 ) / 4;
+ if( ns < 0 )
+ ns = 0;
+ if( ns >= ( nump / 4 - 1 ) )
+ ns = nump / 4 - 2;
+
+ it = newPoints.at( ns * 4 + 2 );
+ for( i = 0; i < 4; ++i )
+ it = newPoints.remove( it );
+ }
+ setPoints( newPoints );
+}
+
+void PMLathe::setRSteps( int r )
+{
+ if( r >= 4 )
+ s_rSteps = r;
+ else
+ kdDebug( PMArea ) << "PMLathe::setRSteps: R must be greater than 3\n";
+ ++s_parameterKey;
+}
+
+void PMLathe::setSSteps( int s )
+{
+ if( s >= 1 )
+ s_sSteps = s;
+ else
+ kdDebug( PMArea ) << "PMLathe::setSSteps: S must be greater than 0\n";
+ ++s_parameterKey;
+}
diff --git a/kpovmodeler/pmlathe.h b/kpovmodeler/pmlathe.h
new file mode 100644
index 00000000..99986a6f
--- /dev/null
+++ b/kpovmodeler/pmlathe.h
@@ -0,0 +1,193 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMLATHE_H
+#define PMLATHE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobject.h"
+#include "pmvector.h"
+#include <qptrlist.h>
+#include <qvaluelist.h>
+#include <math.h>
+
+class PMViewStructure;
+
+/**
+ * Class for povray lathe objects.
+ */
+
+class PMLathe : public PMSolidObject
+{
+ typedef PMSolidObject Base;
+public:
+ /**
+ * The spline type
+ */
+ enum SplineType { LinearSpline, QuadraticSpline, CubicSpline, BezierSpline };
+ /**
+ * Creates an empty PMLathe
+ */
+ PMLathe( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMLathe( const PMLathe& l );
+ /**
+ * deletes the PMLathe
+ */
+ virtual ~PMLathe( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMLathe( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMLatheEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmlathe" ); }
+
+ /** */
+ virtual void createMemento( );
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /** */
+ virtual void controlPoints( PMControlPointList& list );
+ /** */
+ virtual void controlPointsChanged( PMControlPointList& list );
+ /** */
+ virtual bool hasDisplayDetail( ) const { return true; }
+ /** */
+ virtual bool multipleSelectControlPoints( ) const { return true; }
+ /** */
+ virtual void addObjectActions( const PMControlPointList&,
+ QPtrList<PMObjectAction>& );
+ /** */
+ virtual void objectActionCalled( const PMObjectAction*,
+ const PMControlPointList&,
+ const QPtrList<PMVector>&,
+ const PMVector& );
+
+ /**
+ * Returns the spline points
+ */
+ QValueList<PMVector> points( ) const { return m_points; }
+ /**
+ * Sets the spline points
+ */
+ void setPoints( const QValueList<PMVector>& points );
+ /**
+ * Returns the number of spline points
+ */
+ int numberOfPoints( ) const { return m_points.size( ); }
+ /**
+ * Returns the spline type
+ */
+ SplineType splineType( ) const { return m_splineType; }
+ /**
+ * Sets the spline type
+ */
+ void setSplineType( SplineType t );
+ /**
+ * Returns the sturm flag
+ */
+ bool sturm( ) const { return m_sturm; }
+ /**
+ * Sets the sturm flag
+ */
+ void setSturm( bool s );
+
+ /**
+ * Sets the number of steps around the y axis
+ */
+ static void setRSteps( int r );
+ /**
+ * Sets the number of subdivisions of one spline segment
+ */
+ static void setSSteps( int v );
+ /**
+ * Returns the number of steps around the y axis
+ */
+ static int rSteps( ) { return s_rSteps; }
+ /**
+ * Returns the number of subdivisions of one spline segment
+ */
+ static int sSteps( ) { return s_sSteps; }
+
+protected:
+ /** */
+ virtual void createViewStructure( );
+ /** */
+ virtual int viewStructureParameterKey( ) const { return s_parameterKey + globalDetailKey( ); }
+
+private:
+ /**
+ * Object action. Adds a spline point
+ */
+ void splitSegment( const PMControlPointList& cp,
+ const QPtrList<PMVector>& cpViewPosition,
+ const PMVector& clickPosition );
+ /**
+ * Object action. Removes a spline point
+ */
+ void joinSegments( const PMControlPointList& cp,
+ const QPtrList<PMVector>& cpViewPosition,
+ const PMVector& clickPosition );
+
+ void stringToValues( const QString& str );
+ QString valuesToString( ) const;
+
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMLatheMementoID { PMSplineTypeID, PMSturmID };
+ /**
+ * IDs for the object actions
+ */
+ enum PMLatheActionID { PMSplitSegmentID, PMJoinSegmentsID };
+ SplineType m_splineType;
+ QValueList<PMVector> m_points;
+ bool m_sturm;
+
+ static int s_rSteps;
+ static int s_sSteps;
+ static int s_parameterKey;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmlatheedit.cpp b/kpovmodeler/pmlatheedit.cpp
new file mode 100644
index 00000000..970cc2f5
--- /dev/null
+++ b/kpovmodeler/pmlatheedit.cpp
@@ -0,0 +1,333 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmlatheedit.h"
+#include "pmlathe.h"
+#include "pmvectoredit.h"
+#include "pmvectorlistedit.h"
+#include "pmpart.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qtooltip.h>
+#include <qcombobox.h>
+#include <qcheckbox.h>
+#include <qpushbutton.h>
+#include <klocale.h>
+#include <kdialog.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+
+PMLatheEdit::PMLatheEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMLatheEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "Spline type:" ), this ) );
+ m_pSplineType = new QComboBox( false, this );
+ m_pSplineType->insertItem( i18n( "Linear Spline" ) );
+ m_pSplineType->insertItem( i18n( "Quadratic Spline" ) );
+ m_pSplineType->insertItem( i18n( "Cubic Spline" ) );
+ m_pSplineType->insertItem( i18n( "Bezier Spline" ) );
+ hl->addWidget( m_pSplineType );
+ hl->addStretch( 1 );
+
+ connect( m_pSplineType, SIGNAL( activated( int ) ),
+ SLOT( slotTypeChanged( int ) ) );
+}
+
+void PMLatheEdit::createBottomWidgets( )
+{
+ topLayout( )->addWidget( new QLabel( i18n( "Spline points:" ), this ) );
+
+ m_pPoints = new PMVectorListEdit( "u", "v", this );
+ connect( m_pPoints, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pPoints, SIGNAL( selectionChanged( ) ),
+ SLOT( slotSelectionChanged( ) ) );
+ QHBoxLayout* hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( m_pPoints, 2 );
+
+ m_pAddAbove = new QPushButton( this );
+ m_pAddAbove->setPixmap( SmallIcon( "pmaddpointabove" ) );
+ m_pAddBelow = new QPushButton( this );
+ m_pAddBelow->setPixmap( SmallIcon( "pmaddpoint" ) );
+ m_pRemove = new QPushButton( this );
+ m_pRemove->setPixmap( SmallIcon( "pmremovepoint" ) );
+ connect( m_pAddAbove, SIGNAL( clicked( ) ), SLOT( slotAddPointAbove( ) ) );
+ connect( m_pAddBelow, SIGNAL( clicked( ) ), SLOT( slotAddPointBelow( ) ) );
+ connect( m_pRemove, SIGNAL( clicked( ) ), SLOT( slotRemovePoint( ) ) );
+
+ QVBoxLayout* bl = new QVBoxLayout( hl );
+ bl->addWidget( m_pAddAbove );
+ bl->addWidget( m_pAddBelow );
+ bl->addWidget( m_pRemove );
+ bl->addStretch( 1 );
+
+ m_pSturm = new QCheckBox( i18n( "Sturm" ), this );
+ topLayout( )->addWidget( m_pSturm );
+ connect( m_pSturm, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+
+ Base::createBottomWidgets( );
+}
+
+void PMLatheEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Lathe" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMLathe* ) o;
+
+ switch( m_pDisplayedObject->splineType( ) )
+ {
+ case PMLathe::LinearSpline:
+ m_pSplineType->setCurrentItem( 0 );
+ break;
+ case PMLathe::QuadraticSpline:
+ m_pSplineType->setCurrentItem( 1 );
+ break;
+ case PMLathe::CubicSpline:
+ m_pSplineType->setCurrentItem( 2 );
+ break;
+ case PMLathe::BezierSpline:
+ m_pSplineType->setCurrentItem( 3 );
+ break;
+ }
+ m_pSplineType->setEnabled( !readOnly );
+ m_pSturm->setChecked( m_pDisplayedObject->sturm( ) );
+ m_pSturm->setEnabled( !readOnly );
+ m_pPoints->setReadOnly( readOnly );
+ m_pPoints->setVectors( m_pDisplayedObject->points( ), true );
+ updateControlPointSelection( );
+ updatePointButtons( );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMLatheEdit: Can't display object\n";
+}
+
+void PMLatheEdit::updateControlPointSelection( )
+{
+ PMControlPointList cp = part( )->activeControlPoints( );
+ PMControlPointListIterator it( cp );
+ int i;
+ int np = cp.count( ) / 2;
+
+ if( np == m_pPoints->size( ) )
+ {
+ m_pPoints->blockSelectionUpdates( true );
+ bool sb = m_pPoints->signalsBlocked( );
+ m_pPoints->blockSignals( true );
+
+ m_pPoints->clearSelection( );
+ for( i = 0; i < np; i++, ++it )
+ if( ( *it )->selected( ) )
+ m_pPoints->select( i );
+ for( i = 0; i < np; i++, ++it )
+ if( ( *it )->selected( ) )
+ m_pPoints->select( i );
+
+ m_pPoints->blockSignals( sb );
+ m_pPoints->blockSelectionUpdates( false );
+ }
+}
+
+void PMLatheEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ m_pDisplayedObject->setPoints( m_pPoints->vectors( ) );
+
+ switch( m_pSplineType->currentItem( ) )
+ {
+ case 0:
+ m_pDisplayedObject->setSplineType( PMLathe::LinearSpline );
+ break;
+ case 1:
+ m_pDisplayedObject->setSplineType( PMLathe::QuadraticSpline );
+ break;
+ case 2:
+ m_pDisplayedObject->setSplineType( PMLathe::CubicSpline );
+ break;
+ case 3:
+ m_pDisplayedObject->setSplineType( PMLathe::BezierSpline );
+ break;
+ }
+ m_pDisplayedObject->setSturm( m_pSturm->isChecked( ) );
+ Base::saveContents( );
+ }
+}
+
+bool PMLatheEdit::isDataValid( )
+{
+ if( !m_pPoints->isDataValid( ) )
+ return false;
+
+ int np = m_pPoints->size( );
+ switch( m_pSplineType->currentItem( ) )
+ {
+ case 0:
+ if( np < 2 )
+ {
+ KMessageBox::error( this, i18n( "Linear splines need at least 2 points." ),
+ i18n( "Error" ) );
+ return false;
+ }
+ break;
+ case 1:
+ if( np < 3 )
+ {
+ KMessageBox::error( this, i18n( "Quadratic splines need at least 3 points." ),
+ i18n( "Error" ) );
+ return false;
+ }
+ break;
+ case 2:
+ if( np < 4 )
+ {
+ KMessageBox::error( this, i18n( "Cubic splines need at least 4 points." ),
+ i18n( "Error" ) );
+ return false;
+ }
+ break;
+ case 3:
+ if( ( np < 4 ) || ( ( np % 4 ) != 0 ) )
+ {
+ KMessageBox::error( this, i18n( "Bezier splines need 4 points for each segment." ),
+ i18n( "Error" ) );
+ return false;
+ }
+ break;
+ }
+
+ return Base::isDataValid( );
+}
+
+void PMLatheEdit::slotTypeChanged( int )
+{
+ emit dataChanged( );
+}
+
+void PMLatheEdit::slotAddPointAbove( )
+{
+ int index = m_pPoints->currentRow( );
+ if( index >= 0 )
+ {
+ QValueList<PMVector> points = m_pPoints->vectors( );
+ QValueListIterator<PMVector> it = points.at( index );
+
+ if( it != points.end( ) )
+ {
+ QValueListIterator<PMVector> it2 = it;
+ it2--;
+ PMVector v;
+ if( it2 == points.end( ) )
+ v = *it;
+ else
+ v = ( *it + *it2 ) / 2;
+
+ points.insert( it, v );
+ m_pPoints->setVectors( points, true );
+ updatePointButtons( );
+ emit dataChanged( );
+ emit sizeChanged( );
+ }
+ }
+}
+
+void PMLatheEdit::slotAddPointBelow( )
+{
+ int index = m_pPoints->currentRow( );
+ if( index >= 0 )
+ {
+ QValueList<PMVector> points = m_pPoints->vectors( );
+ QValueListIterator<PMVector> it = points.at( index );
+
+ if( it != points.end( ) )
+ {
+ QValueListIterator<PMVector> it2 = it;
+ it2++;
+ PMVector v;
+ if( it2 == points.end( ) )
+ v = *it;
+ else
+ v = ( *it + *it2 ) / 2;
+
+ points.insert( it2, v );
+ m_pPoints->setVectors( points, true );
+ m_pPoints->setCurrentCell( index + 1, m_pPoints->currentColumn( ) );
+ updatePointButtons( );
+ emit dataChanged( );
+ emit sizeChanged( );
+ }
+ }
+}
+
+void PMLatheEdit::slotRemovePoint( )
+{
+ int row = m_pPoints->currentRow( );
+
+ if( row >= 0 )
+ {
+ QValueList<PMVector> points = m_pPoints->vectors( );
+ QValueListIterator<PMVector> it = points.at( row );
+
+ if( it != points.end( ) && points.size( ) > 1 )
+ {
+ points.remove( it );
+ m_pPoints->setVectors( points, true );
+ updatePointButtons( );
+ emit dataChanged( );
+ emit sizeChanged( );
+ }
+ }
+}
+
+void PMLatheEdit::slotSelectionChanged( )
+{
+ PMControlPointList cp = part( )->activeControlPoints( );
+ PMControlPointListIterator it( cp );
+ int np = cp.count( ) / 2;
+ int i;
+
+ if( np == m_pPoints->size( ) )
+ {
+ for( i = 0; i < np; i++, ++it )
+ ( *it )->setSelected( m_pPoints->isSelected( i ) );
+ for( i = 0; i < np; i++, ++it )
+ ( *it )->setSelected( m_pPoints->isSelected( i ) );
+ emit controlPointSelectionChanged( );
+ }
+ updatePointButtons( );
+}
+
+void PMLatheEdit::updatePointButtons( )
+{
+ int row = m_pPoints->currentRow( );
+ m_pAddAbove->setEnabled( row >= 0 );
+ m_pAddBelow->setEnabled( row >= 0 );
+ m_pRemove->setEnabled( row >= 0 && m_pPoints->size( ) > 2 );
+}
+
+#include "pmlatheedit.moc"
diff --git a/kpovmodeler/pmlatheedit.h b/kpovmodeler/pmlatheedit.h
new file mode 100644
index 00000000..ad8cf835
--- /dev/null
+++ b/kpovmodeler/pmlatheedit.h
@@ -0,0 +1,89 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMLATHEEDIT_H
+#define PMLATHEEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobjectedit.h"
+#include "pmvectoredit.h"
+#include <qptrlist.h>
+#include <qvaluelist.h>
+
+class PMLathe;
+class PMVectorListEdit;
+class QVBoxLayout;
+class QComboBox;
+class QCheckBox;
+class QPushButton;
+class QLabel;
+
+/**
+ * Dialog edit class for @ref PMLathe
+ */
+class PMLatheEdit : public PMSolidObjectEdit
+{
+ Q_OBJECT
+ typedef PMSolidObjectEdit Base;
+public:
+ /**
+ * Creates a PMLatheEdit with parent and name
+ */
+ PMLatheEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+ /** */
+ virtual void updateControlPointSelection( );
+
+ /** */
+ virtual bool isDataValid( );
+
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void createBottomWidgets( );
+ /** */
+ virtual void saveContents( );
+
+protected slots:
+ void slotTypeChanged( int );
+ void slotAddPointAbove( );
+ void slotAddPointBelow( );
+ void slotRemovePoint( );
+ void slotSelectionChanged( );
+
+private:
+ void updatePointButtons( );
+
+ PMLathe* m_pDisplayedObject;
+ QComboBox* m_pSplineType;
+ QCheckBox* m_pSturm;
+ PMVectorListEdit* m_pPoints;
+ QPushButton* m_pAddAbove;
+ QPushButton* m_pAddBelow;
+ QPushButton* m_pRemove;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmlayoutsettings.cpp b/kpovmodeler/pmlayoutsettings.cpp
new file mode 100644
index 00000000..398e5354
--- /dev/null
+++ b/kpovmodeler/pmlayoutsettings.cpp
@@ -0,0 +1,774 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmlayoutsettings.h"
+
+#include "pmlineedits.h"
+#include "pmviewfactory.h"
+#include "pmdebug.h"
+
+#include <qlayout.h>
+#include <qcombobox.h>
+#include <qlistbox.h>
+#include <qlistview.h>
+#include <qpushbutton.h>
+#include <qlabel.h>
+#include <qgroupbox.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+PMLayoutSettings::PMLayoutSettings( QWidget* parent, const char* name )
+ : PMSettingsDialogPage( parent, name )
+{
+ QHBoxLayout* hlayout;
+ QVBoxLayout* vlayout;
+ QVBoxLayout* gvl;
+ QGridLayout* grid;
+ QGroupBox* gb;
+ QGroupBox* gbe;
+ QHBoxLayout* ghe;
+ QVBoxLayout* gvle;
+
+ vlayout = new QVBoxLayout( this, 0, KDialog::spacingHint( ) );
+
+ hlayout = new QHBoxLayout( vlayout );
+ hlayout->addWidget( new QLabel( i18n( "Default view layout:" ), this ) );
+ m_pDefaultLayout = new QComboBox( this );
+ hlayout->addWidget( m_pDefaultLayout, 1 );
+ hlayout->addStretch( 1 );
+
+ gb = new QGroupBox( i18n( "Available View Layouts" ), this );
+ vlayout->addWidget( gb );
+ gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) );
+ gvl->addSpacing( 10 );
+
+ grid = new QGridLayout( gvl, 3, 2 );
+ m_pViewLayouts = new QListBox( gb );
+ connect( m_pViewLayouts, SIGNAL( highlighted( int ) ),
+ SLOT( slotLayoutSelected( int ) ) );
+ grid->addMultiCellWidget( m_pViewLayouts, 0, 2, 0, 0 );
+ m_pAddLayout = new QPushButton( i18n( "Add" ), gb );
+ connect( m_pAddLayout, SIGNAL( clicked( ) ), SLOT( slotAddLayout( ) ) );
+ grid->addWidget( m_pAddLayout, 0, 1 );
+ m_pRemoveLayout = new QPushButton( i18n( "Remove" ), gb );
+ connect( m_pRemoveLayout, SIGNAL( clicked( ) ), SLOT( slotRemoveLayout( ) ) );
+ grid->addWidget( m_pRemoveLayout, 1, 1 );
+ grid->setRowStretch( 2, 1 );
+
+ gbe = new QGroupBox( i18n( "View Layout" ), gb );
+ gvl->addWidget( gbe );
+ gvle = new QVBoxLayout( gbe, KDialog::marginHint( ), KDialog::spacingHint( ) );
+ gvle->addSpacing( 10 );
+ ghe = new QHBoxLayout( gvle );
+ ghe->addWidget( new QLabel( i18n( "Name:" ), gbe ) );
+ m_pViewLayoutName = new QLineEdit( gbe );
+ connect( m_pViewLayoutName, SIGNAL( textChanged( const QString& ) ),
+ SLOT( slotLayoutNameChanged( const QString& ) ) );
+ ghe->addWidget( m_pViewLayoutName );
+ grid = new QGridLayout( gvle, 4, 2 );
+ m_pViewEntries = new QListView( gbe );
+ m_pViewEntries->setAllColumnsShowFocus( true );
+ m_pViewEntries->addColumn( " " ); // This column is for the view entry number
+ m_pViewEntries->addColumn( i18n( "Type" ) );
+ m_pViewEntries->addColumn( i18n( "Position" ) );
+ m_pViewEntries->setSorting( -1 );
+ m_pViewEntries->setMaximumHeight( 150 );
+ connect( m_pViewEntries, SIGNAL( selectionChanged( QListViewItem* ) ),
+ SLOT( slotViewEntrySelected( QListViewItem* ) ) );
+ grid->addMultiCellWidget( m_pViewEntries, 0, 3, 0, 0 );
+ m_pAddEntry = new QPushButton( i18n( "Add" ), gbe );
+ connect( m_pAddEntry, SIGNAL( clicked( ) ), SLOT( slotAddViewEntryClicked( ) ) );
+ grid->addWidget( m_pAddEntry, 0, 1 );
+ m_pRemoveEntry = new QPushButton( i18n( "Remove" ), gbe );
+ connect( m_pRemoveEntry, SIGNAL( clicked( ) ), SLOT( slotRemoveViewEntryClicked( ) ) );
+ grid->addWidget( m_pRemoveEntry, 1, 1 );
+ /* //TODO
+ m_pMoveUpEntry = new QPushButton( i18n( "Move Up" ), gbe );
+ connect( m_pMoveUpEntry, SIGNAL( clicked( ) ), SLOT( slotMoveUpViewEntryClicked( ) ) );
+ grid->addWidget( m_pMoveUpEntry, 2, 1 );
+ m_pMoveDownEntry = new QPushButton( i18n( "Move Down" ), gbe );
+ connect( m_pMoveDownEntry, SIGNAL( clicked( ) ), SLOT( slotMoveDownViewEntryClicked( ) ) );
+ grid->addWidget( m_pMoveDownEntry, 3, 1 );
+ */
+
+ QHBoxLayout* ghl = new QHBoxLayout( gvle );
+ grid = new QGridLayout( ghl, 7, 4 );
+ grid->addWidget( new QLabel( i18n( "Type:" ), gbe ), 0, 0 );
+ grid->addWidget( new QLabel( i18n( "Dock position:" ), gbe ), 2, 0 );
+ m_pColumnWidthLabel = new QLabel( i18n( "Column width:" ), gbe );
+ grid->addWidget( m_pColumnWidthLabel, 3, 0 );
+ m_pViewHeightLabel = new QLabel( i18n( "View height:" ), gbe );
+ grid->addWidget( m_pViewHeightLabel, 4, 0 );
+ m_pViewTypeEdit = new QComboBox( gbe );
+
+ // insert all view types
+ const QPtrList<PMViewTypeFactory>& types =
+ PMViewFactory::theFactory( )->viewTypes( );
+ QPtrListIterator<PMViewTypeFactory> it( types );
+ for( ; *it; ++it )
+ m_pViewTypeEdit->insertItem( ( *it )->description( ) );
+
+ connect( m_pViewTypeEdit, SIGNAL( activated( int ) ),
+ SLOT( slotViewTypeChanged( int ) ) );
+ grid->addWidget( m_pViewTypeEdit, 0, 1 );
+ m_pDockPositionEdit = new QComboBox( gbe );
+ m_pDockPositionEdit->insertItem( i18n( "New Column" ) );
+ m_pDockPositionEdit->insertItem( i18n( "Below" ) );
+ m_pDockPositionEdit->insertItem( i18n( "Tabbed" ) );
+ m_pDockPositionEdit->insertItem( i18n( "Floating" ) );
+ connect( m_pDockPositionEdit, SIGNAL( activated( int ) ),
+ SLOT( slotDockPositionChanged( int ) ) );
+ grid->addWidget( m_pDockPositionEdit, 2, 1 );
+
+ m_pColumnWidthEdit = new PMIntEdit( gbe );
+ connect( m_pColumnWidthEdit, SIGNAL( textChanged( const QString& ) ),
+ SLOT( slotColumnWidthChanged( const QString& ) ) );
+ grid->addWidget( m_pColumnWidthEdit, 3, 1 );
+
+ m_pViewHeightEdit = new PMIntEdit( gbe );
+ connect( m_pViewHeightEdit, SIGNAL( textChanged( const QString& ) ),
+ SLOT( slotViewHeightChanged( const QString& ) ) );
+ grid->addWidget( m_pViewHeightEdit, 4, 1 );
+
+ m_pFloatingWidthLabel = new QLabel( i18n( "Width:" ), gbe );
+ m_pFloatingHeightLabel = new QLabel( i18n( "Height:" ), gbe );
+ m_pFloatingPosXLabel = new QLabel( i18n( "Position x:" ), gbe );
+ m_pFloatingPosYLabel = new QLabel( QString( "y:" ), gbe );
+ grid->addWidget( m_pFloatingWidthLabel, 5, 0 );
+ grid->addWidget( m_pFloatingHeightLabel, 5, 2 );
+ grid->addWidget( m_pFloatingPosXLabel, 6, 0 );
+ grid->addWidget( m_pFloatingPosYLabel, 6, 2 );
+
+ m_pFloatingWidth = new PMIntEdit( gbe );
+ connect( m_pFloatingWidth, SIGNAL( textChanged( const QString& ) ),
+ SLOT( slotFloatingWidthChanged( const QString& ) ) );
+ m_pFloatingHeight = new PMIntEdit( gbe );
+ connect( m_pFloatingHeight, SIGNAL( textChanged( const QString& ) ),
+ SLOT( slotFloatingHeightChanged( const QString& ) ) );
+ m_pFloatingPosX = new PMIntEdit( gbe );
+ connect( m_pFloatingPosX, SIGNAL( textChanged( const QString& ) ),
+ SLOT( slotFloatingPosXChanged( const QString& ) ) );
+ m_pFloatingPosY = new PMIntEdit( gbe );
+ connect( m_pFloatingPosY, SIGNAL( textChanged( const QString& ) ),
+ SLOT( slotFloatingPosYChanged( const QString& ) ) );
+ grid->addWidget( m_pFloatingWidth, 5, 1 );
+ grid->addWidget( m_pFloatingHeight, 5, 3 );
+ grid->addWidget( m_pFloatingPosX, 6, 1 );
+ grid->addWidget( m_pFloatingPosY, 6, 3 );
+
+ // create a holder widget for custom options widgets
+ m_pCustomOptionsWidget = 0;
+ m_pCustomOptionsHolder = new QWidget( gbe );
+
+ QVBoxLayout* covl = new QVBoxLayout( ghl );
+ covl->addWidget( m_pCustomOptionsHolder );
+ covl->addStretch( 1 );
+
+ ghl->addStretch( 1 );
+
+ vlayout->addStretch( 1 );
+}
+
+void PMLayoutSettings::displaySettings( )
+{
+ PMViewLayoutManager* m = PMViewLayoutManager::theManager( );
+ m_viewLayouts = m->layouts( );
+ m_currentViewLayout = m_viewLayouts.begin( );
+ m_defaultViewLayout = m_viewLayouts.begin( );
+ for( ; ( m_defaultViewLayout != m_viewLayouts.end( ) ) &&
+ ( *m_defaultViewLayout ).name( ) != m->defaultLayout( );
+ ++m_defaultViewLayout );
+ displayLayoutList( );
+ m_pViewLayouts->setCurrentItem( 0 );
+ if( m_pViewLayouts->numRows( ) == 1 )
+ m_pRemoveLayout->setEnabled( false );
+}
+
+void PMLayoutSettings::displayDefaults( )
+{
+}
+
+bool PMLayoutSettings::validateData( )
+{
+ QValueListIterator<PMViewLayout> lit;
+ for( lit = m_viewLayouts.begin( ); lit != m_viewLayouts.end( ); ++lit )
+ {
+ if( ( *lit ).name( ).isEmpty( ) )
+ {
+ emit showMe( );
+ KMessageBox::error( this, i18n( "View layouts may not have empty names." ),
+ i18n( "Error" ) );
+ return false;
+ }
+ QValueListIterator<PMViewLayoutEntry> eit = ( *lit ).begin( );
+ if( eit != ( *lit ).end( ) )
+ {
+ if( ( *eit ).dockPosition( ) != PMDockWidget::DockRight )
+ {
+ emit showMe( );
+ KMessageBox::error( this, i18n( "The docking position of the first view layout entry has to be 'New Column'." ),
+ i18n( "Error" ) );
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+void PMLayoutSettings::applySettings( )
+{
+ QValueListIterator<PMViewLayout> lit;
+ for( lit = m_viewLayouts.begin( ); lit != m_viewLayouts.end( ); ++lit )
+ ( *lit ).normalize( );
+ PMViewLayoutManager::theManager( )->setDefaultLayout( m_pDefaultLayout->currentText( ) );
+ PMViewLayoutManager::theManager( )->setLayouts( m_viewLayouts );
+ PMViewLayoutManager::theManager( )->saveData( );
+}
+
+void PMLayoutSettings::displayLayoutList( )
+{
+ QValueListIterator<PMViewLayout> it;
+
+ m_pViewLayouts->clear( );
+ m_pDefaultLayout->clear( );
+ for( it = m_viewLayouts.begin( ); it != m_viewLayouts.end( ); ++it )
+ {
+ m_pViewLayouts->insertItem( ( *it ).name( ) );
+ m_pDefaultLayout->insertItem( ( *it ).name( ) );
+ if( it == m_defaultViewLayout )
+ m_pDefaultLayout->setCurrentText( ( *it ).name( ) );
+ }
+}
+
+void PMLayoutSettings::slotAddLayout( )
+{
+ QString new_name;
+ int i = 1;
+ QString str;
+
+ new_name = i18n( "Unnamed" );
+ str.setNum( i );
+ while( m_pViewLayouts->findItem( new_name, Qt::ExactMatch ) )
+ {
+ new_name = i18n( "Unnamed" ) + str;
+ i++;
+ str.setNum( i );
+ }
+
+ PMViewLayout l;
+ l.setName( new_name );
+
+ m_currentViewLayout++;
+ m_viewLayouts.insert( m_currentViewLayout, l );
+ displayLayoutList( );
+ m_pViewLayouts->setCurrentItem( m_pViewLayouts->findItem( new_name, Qt::ExactMatch ) );
+ m_pRemoveLayout->setEnabled( true );
+}
+
+void PMLayoutSettings::slotRemoveLayout( )
+{
+ if( m_currentViewLayout == m_defaultViewLayout )
+ {
+ m_defaultViewLayout--;
+ if( m_defaultViewLayout == m_viewLayouts.end( ) )
+ {
+ m_defaultViewLayout++;
+ m_defaultViewLayout++;
+ }
+ }
+ m_viewLayouts.remove( m_currentViewLayout );
+ displayLayoutList( );
+ m_pViewLayouts->setCurrentItem( m_pViewLayouts->firstItem( ) );
+
+ if( m_pViewLayouts->numRows( ) == 1 )
+ m_pRemoveLayout->setEnabled( false );
+}
+
+void PMLayoutSettings::slotLayoutSelected( int index )
+{
+ int i;
+ QString str;
+ bool sb;
+
+ m_currentViewLayout = m_viewLayouts.at( index );
+ m_currentViewEntry = ( *m_currentViewLayout ).begin( );
+
+ sb = m_pViewLayoutName->signalsBlocked( );
+ m_pViewLayoutName->blockSignals( true );
+ m_pViewLayoutName->setText( ( *m_currentViewLayout ).name( ) );
+ m_pViewLayoutName->blockSignals( sb );
+
+ PMViewLayout::iterator it;
+ QListViewItem* previous = NULL;
+ m_pViewEntries->clear( );
+ i = 0;
+ for( it = ( *m_currentViewLayout ).begin( );
+ it != ( *m_currentViewLayout ).end( ); ++it )
+ {
+ i++; str.setNum( i );
+ previous = new QListViewItem( m_pViewEntries, previous, str,
+ ( *it ).viewTypeAsString( ),
+ ( *it ).dockPositionAsString( ) );
+ if( i == 1 )
+ m_pViewEntries->setSelected( previous, true );
+ }
+ if( i == 0 )
+ slotViewEntrySelected( 0 );
+}
+
+void PMLayoutSettings::slotLayoutNameChanged( const QString& text )
+{
+ int n_item = m_pViewLayouts->currentItem( );
+ bool sb = m_pViewLayouts->signalsBlocked( );
+ m_pViewLayouts->blockSignals( true );
+ m_pViewLayouts->removeItem( n_item );
+ m_pViewLayouts->insertItem( text, n_item );
+ m_pViewLayouts->setCurrentItem( n_item );
+ m_pViewLayouts->blockSignals( sb );
+
+ ( *m_currentViewLayout ).setName( text );
+
+ QValueListIterator<PMViewLayout> it;
+ m_pDefaultLayout->clear( );
+ for( it = m_viewLayouts.begin( ); it != m_viewLayouts.end( ); ++it )
+ {
+ m_pDefaultLayout->insertItem( ( *it ).name( ) );
+ if( it == m_defaultViewLayout )
+ m_pDefaultLayout->setCurrentText( ( *it ).name( ) );
+ }
+}
+
+void PMLayoutSettings::slotViewEntrySelected( QListViewItem *item )
+{
+ if( item )
+ {
+ m_pViewTypeEdit->setEnabled( true );
+ m_pDockPositionEdit->setEnabled( true );
+
+ int n_item = item->text( 0 ).toInt( ) - 1;
+
+ m_currentViewEntry = ( *m_currentViewLayout ).at( n_item );
+ QString vt = ( *m_currentViewEntry ).viewType( );
+
+ // find the view type
+ int index = 0;
+ bool found = false;
+ const QPtrList<PMViewTypeFactory>& types =
+ PMViewFactory::theFactory( )->viewTypes( );
+ QPtrListIterator<PMViewTypeFactory> it( types );
+
+ for( ; *it && !found; ++it )
+ {
+ if( ( *it )->viewType( ) == vt )
+ found = true;
+ else
+ index++;
+ }
+
+ if( !found )
+ {
+ kdError( PMArea ) << "Unknown view type in PMLayoutSettings::slotViewEntrySelected" << endl;
+ m_pViewTypeEdit->setCurrentItem( 0 );
+ }
+ else
+ m_pViewTypeEdit->setCurrentItem( index );
+
+ /*
+ switch( ( *m_currentViewEntry ).glViewType( ) )
+ {
+ case PMGLView::PMViewNegY:
+ m_pGLViewTypeEdit->setCurrentItem( 0 );
+ break;
+ case PMGLView::PMViewPosY:
+ m_pGLViewTypeEdit->setCurrentItem( 1 );
+ break;
+ case PMGLView::PMViewPosX:
+ m_pGLViewTypeEdit->setCurrentItem( 2 );
+ break;
+ case PMGLView::PMViewNegX:
+ m_pGLViewTypeEdit->setCurrentItem( 3 );
+ break;
+ case PMGLView::PMViewPosZ:
+ m_pGLViewTypeEdit->setCurrentItem( 4 );
+ break;
+ case PMGLView::PMViewNegZ:
+ m_pGLViewTypeEdit->setCurrentItem( 5 );
+ break;
+ case PMGLView::PMViewCamera:
+ m_pGLViewTypeEdit->setCurrentItem( 6 );
+ break;
+ }
+ */
+ switch( ( *m_currentViewEntry ).dockPosition( ) )
+ {
+ case PMDockWidget::DockRight:
+ m_pDockPositionEdit->setCurrentItem( 0 );
+ m_pColumnWidthLabel->show( );
+ m_pColumnWidthEdit->show( );
+ m_pViewHeightEdit->show( );
+ m_pViewHeightLabel->show( );
+ m_pFloatingWidth->hide( );
+ m_pFloatingHeight->hide( );
+ m_pFloatingPosX->hide( );
+ m_pFloatingPosY->hide( );
+ m_pFloatingWidthLabel->hide( );
+ m_pFloatingHeightLabel->hide( );
+ m_pFloatingPosXLabel->hide( );
+ m_pFloatingPosYLabel->hide( );
+ break;
+ case PMDockWidget::DockBottom:
+ m_pDockPositionEdit->setCurrentItem( 1 );
+ m_pColumnWidthLabel->hide( );
+ m_pColumnWidthEdit->hide( );
+ m_pViewHeightEdit->show( );
+ m_pViewHeightLabel->show( );
+ m_pFloatingWidth->hide( );
+ m_pFloatingHeight->hide( );
+ m_pFloatingPosX->hide( );
+ m_pFloatingPosY->hide( );
+ m_pFloatingWidthLabel->hide( );
+ m_pFloatingHeightLabel->hide( );
+ m_pFloatingPosXLabel->hide( );
+ m_pFloatingPosYLabel->hide( );
+ break;
+ case PMDockWidget::DockCenter:
+ m_pDockPositionEdit->setCurrentItem( 2 );
+ m_pColumnWidthLabel->hide( );
+ m_pColumnWidthEdit->hide( );
+ m_pViewHeightEdit->hide( );
+ m_pViewHeightLabel->hide( );
+ m_pFloatingWidth->hide( );
+ m_pFloatingHeight->hide( );
+ m_pFloatingPosX->hide( );
+ m_pFloatingPosY->hide( );
+ m_pFloatingWidthLabel->hide( );
+ m_pFloatingHeightLabel->hide( );
+ m_pFloatingPosXLabel->hide( );
+ m_pFloatingPosYLabel->hide( );
+ break;
+ default:
+ m_pDockPositionEdit->setCurrentItem( 3 );
+ m_pColumnWidthLabel->hide( );
+ m_pColumnWidthEdit->hide( );
+ m_pViewHeightEdit->hide( );
+ m_pViewHeightLabel->hide( );
+ m_pFloatingWidth->show( );
+ m_pFloatingHeight->show( );
+ m_pFloatingPosX->show( );
+ m_pFloatingPosY->show( );
+ m_pFloatingWidthLabel->show( );
+ m_pFloatingHeightLabel->show( );
+ m_pFloatingPosXLabel->show( );
+ m_pFloatingPosYLabel->show( );
+ break;
+ }
+ m_pColumnWidthEdit->setValue( ( *m_currentViewEntry ).columnWidth( ) );
+ m_pViewHeightEdit->setValue( ( *m_currentViewEntry ).height( ) );
+ m_pFloatingWidth->setValue( ( *m_currentViewEntry ).floatingWidth( ) );
+ m_pFloatingHeight->setValue( ( *m_currentViewEntry ).floatingHeight( ) );
+ m_pFloatingPosX->setValue( ( *m_currentViewEntry ).floatingPositionX( ) );
+ m_pFloatingPosY->setValue( ( *m_currentViewEntry ).floatingPositionY( ) );
+ m_pViewEntries->triggerUpdate( );
+ displayCustomOptions( );
+ }
+ else
+ {
+ m_pViewTypeEdit->setEnabled( false );
+ m_pDockPositionEdit->setEnabled( false );
+ m_pColumnWidthLabel->hide( );
+ m_pColumnWidthEdit->hide( );
+ m_pViewHeightEdit->hide( );
+ m_pViewHeightLabel->hide( );
+ m_pFloatingWidth->hide( );
+ m_pFloatingHeight->hide( );
+ m_pFloatingPosX->hide( );
+ m_pFloatingPosY->hide( );
+ m_pFloatingWidthLabel->hide( );
+ m_pFloatingHeightLabel->hide( );
+ m_pFloatingPosXLabel->hide( );
+ m_pFloatingPosYLabel->hide( );
+ }
+}
+
+void PMLayoutSettings::slotViewTypeChanged( int index )
+{
+ const QPtrList<PMViewTypeFactory>& types =
+ PMViewFactory::theFactory( )->viewTypes( );
+ QPtrListIterator<PMViewTypeFactory> it( types );
+ it += index;
+ const PMViewTypeFactory* factory = *it;
+ PMViewLayoutEntry& ve = ( *m_currentViewEntry );
+
+ if( factory && factory->viewType( ) != ve.viewType( ) )
+ {
+ ve.setViewType( factory->viewType( ) );
+ ve.setCustomOptions( factory->newOptionsInstance( ) );
+
+ QListViewItem* item = m_pViewEntries->currentItem( );
+ if( item )
+ {
+ if( ve.customOptions( ) )
+ item->setText( 1, factory->description( ve.customOptions( ) ) );
+ else
+ item->setText( 1, factory->description( ) );
+ displayCustomOptions( );
+ }
+ }
+}
+
+void PMLayoutSettings::slotDockPositionChanged( int index )
+{
+ switch( index )
+ {
+ case 0:
+ ( *m_currentViewEntry ).setDockPosition( PMDockWidget::DockRight );
+ m_pColumnWidthLabel->show( );
+ m_pColumnWidthEdit->show( );
+ m_pViewHeightEdit->show( );
+ m_pViewHeightLabel->show( );
+ m_pFloatingWidth->hide( );
+ m_pFloatingHeight->hide( );
+ m_pFloatingPosX->hide( );
+ m_pFloatingPosY->hide( );
+ m_pFloatingWidthLabel->hide( );
+ m_pFloatingHeightLabel->hide( );
+ m_pFloatingPosXLabel->hide( );
+ m_pFloatingPosYLabel->hide( );
+ break;
+ case 1:
+ ( *m_currentViewEntry ).setDockPosition( PMDockWidget::DockBottom );
+ m_pColumnWidthLabel->hide( );
+ m_pColumnWidthEdit->hide( );
+ m_pViewHeightEdit->show( );
+ m_pViewHeightLabel->show( );
+ m_pFloatingWidth->hide( );
+ m_pFloatingHeight->hide( );
+ m_pFloatingPosX->hide( );
+ m_pFloatingPosY->hide( );
+ m_pFloatingWidthLabel->hide( );
+ m_pFloatingHeightLabel->hide( );
+ m_pFloatingPosXLabel->hide( );
+ m_pFloatingPosYLabel->hide( );
+ break;
+ case 2:
+ ( *m_currentViewEntry ).setDockPosition( PMDockWidget::DockCenter );
+ m_pColumnWidthLabel->hide( );
+ m_pColumnWidthEdit->hide( );
+ m_pViewHeightEdit->hide( );
+ m_pViewHeightLabel->hide( );
+ m_pFloatingWidth->hide( );
+ m_pFloatingHeight->hide( );
+ m_pFloatingPosX->hide( );
+ m_pFloatingPosY->hide( );
+ m_pFloatingWidthLabel->hide( );
+ m_pFloatingHeightLabel->hide( );
+ m_pFloatingPosXLabel->hide( );
+ m_pFloatingPosYLabel->hide( );
+ break;
+ case 3:
+ ( *m_currentViewEntry ).setDockPosition( PMDockWidget::DockNone );
+ m_pColumnWidthLabel->hide( );
+ m_pColumnWidthEdit->hide( );
+ m_pViewHeightEdit->hide( );
+ m_pViewHeightLabel->hide( );
+ m_pFloatingWidth->show( );
+ m_pFloatingHeight->show( );
+ m_pFloatingPosX->show( );
+ m_pFloatingPosY->show( );
+ m_pFloatingWidthLabel->show( );
+ m_pFloatingHeightLabel->show( );
+ m_pFloatingPosXLabel->show( );
+ m_pFloatingPosYLabel->show( );
+ break;
+ }
+ QListViewItem* item = m_pViewEntries->currentItem( );
+ if( item )
+ item->setText( 2, ( *m_currentViewEntry ).dockPositionAsString( ) );
+}
+
+void PMLayoutSettings::slotViewHeightChanged( const QString& text )
+{
+ ( *m_currentViewEntry ).setHeight( text.toInt( ) );
+}
+
+void PMLayoutSettings::slotColumnWidthChanged( const QString& text )
+{
+ ( *m_currentViewEntry ).setColumnWidth( text.toInt( ) );
+}
+
+void PMLayoutSettings::slotFloatingWidthChanged( const QString& text )
+{
+ ( *m_currentViewEntry ).setFloatingWidth( text.toInt( ) );
+}
+
+void PMLayoutSettings::slotFloatingHeightChanged( const QString& text )
+{
+ ( *m_currentViewEntry ).setFloatingHeight( text.toInt( ) );
+}
+
+void PMLayoutSettings::slotFloatingPosXChanged( const QString& text )
+{
+ ( *m_currentViewEntry ).setFloatingPositionX( text.toInt( ) );
+}
+
+void PMLayoutSettings::slotFloatingPosYChanged( const QString& text )
+{
+ ( *m_currentViewEntry ).setFloatingPositionY( text.toInt( ) );
+}
+
+void PMLayoutSettings::slotAddViewEntryClicked( )
+{
+ PMViewLayoutEntry p;
+ QString str;
+ QListViewItem* temp;
+
+ temp = m_pViewEntries->currentItem( );
+ if( temp )
+ {
+ int n_item = temp->text( 0 ).toInt( );
+ ( *m_currentViewLayout ).addEntry( p, n_item );
+ n_item++;
+ str.setNum( n_item );
+ QListViewItem* a = new QListViewItem( m_pViewEntries, temp,
+ str, p.viewTypeAsString( ),
+ p.dockPositionAsString( ) );
+ m_pViewEntries->setSelected( a, true );
+ temp = a->nextSibling( );
+ while( temp )
+ {
+ n_item++;
+ str.setNum( n_item );
+ temp->setText( 0, str );
+ temp = temp->nextSibling( );
+ }
+ }
+ else
+ {
+ // If there is no selected the list must be empty
+ ( *m_currentViewLayout ).addEntry( p );
+ str.setNum( 1 );
+ QListViewItem* a = new QListViewItem( m_pViewEntries, NULL,
+ str, p.viewTypeAsString( ),
+ p.dockPositionAsString( ) );
+ m_pViewEntries->setSelected( a, true );
+ }
+}
+
+void PMLayoutSettings::slotRemoveViewEntryClicked( )
+{
+ QListViewItem* temp;
+ QString str;
+
+ QListViewItem* current = m_pViewEntries->currentItem( );
+ if( current )
+ {
+ int n_item = current->text( 0 ).toInt( ) - 1;
+ ( *m_currentViewLayout ).removeEntry( n_item );
+
+ // Save the next selected item in temp, since the current item will
+ // be removed.
+ temp = current->nextSibling( );
+ if( !temp )
+ temp = current->itemAbove( );
+ else
+ n_item++;
+
+ delete current;
+
+ if( temp )
+ {
+ str.setNum( n_item );
+ temp->setText( 0, str );
+ m_pViewEntries->setSelected( temp, true );
+ n_item++;
+ temp = temp->nextSibling( );
+ }
+ else
+ slotViewEntrySelected( 0 );
+ while( temp )
+ {
+ str.setNum( n_item );
+ temp->setText( 0, str );
+ n_item++;
+ temp = temp->nextSibling( );
+ }
+ }
+}
+
+void PMLayoutSettings::slotMoveUpViewEntryClicked( )
+{
+}
+
+void PMLayoutSettings::slotMoveDownViewEntryClicked( )
+{
+}
+
+void PMLayoutSettings::displayCustomOptions( )
+{
+ // delete an old widget
+ if( m_pCustomOptionsHolder->layout( ) )
+ delete m_pCustomOptionsHolder->layout( );
+ if( m_pCustomOptionsWidget )
+ {
+ delete m_pCustomOptionsWidget;
+ m_pCustomOptionsWidget = 0;
+ }
+
+ if( m_currentViewLayout != m_viewLayouts.end( ) &&
+ m_currentViewEntry != ( *m_currentViewLayout ).end( ) &&
+ ( *m_currentViewEntry ).customOptions( ) )
+ {
+ PMViewTypeFactory* vf = PMViewFactory::theFactory( )->viewFactory(
+ ( *m_currentViewEntry ).viewType( ) );
+ if( vf )
+ {
+ m_pCustomOptionsWidget =
+ vf->newOptionsWidget( m_pCustomOptionsHolder,
+ ( *m_currentViewEntry ).customOptions( ) );
+ if( m_pCustomOptionsWidget )
+ {
+ connect( m_pCustomOptionsWidget, SIGNAL( viewTypeDescriptionChanged( ) ),
+ SLOT( slotViewTypeDescriptionChanged( ) ) );
+ QHBoxLayout* hl = new QHBoxLayout( m_pCustomOptionsHolder,
+ 0, KDialog::spacingHint( ) );
+ hl->addWidget( m_pCustomOptionsWidget );
+ m_pCustomOptionsWidget->show( );
+ }
+ }
+ }
+}
+
+void PMLayoutSettings::slotViewTypeDescriptionChanged( )
+{
+ PMViewLayoutEntry& ve = *m_currentViewEntry;
+ const PMViewTypeFactory* factory =
+ PMViewFactory::theFactory( )->viewFactory( ve.viewType( ) );
+
+ if( factory )
+ {
+ QListViewItem* item = m_pViewEntries->currentItem( );
+ if( item )
+ {
+ if( ve.customOptions( ) )
+ item->setText( 1, factory->description( ve.customOptions( ) ) );
+ else
+ item->setText( 1, factory->description( ) );
+ }
+ }
+}
+
+#include "pmlayoutsettings.moc"
diff --git a/kpovmodeler/pmlayoutsettings.h b/kpovmodeler/pmlayoutsettings.h
new file mode 100644
index 00000000..4bca52e3
--- /dev/null
+++ b/kpovmodeler/pmlayoutsettings.h
@@ -0,0 +1,174 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMLAYOUTSETTINGS_H
+#define PMLAYOUTSETTINGS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsettingsdialog.h"
+#include "pmviewlayoutmanager.h"
+
+#include <qvaluelist.h>
+
+class PMIntEdit;
+class PMViewOptionsWidget;
+class QComboBox;
+class QListBox;
+class QPushButton;
+class QLabel;
+
+/**
+ * View layout configuration dialog page
+ */
+class PMLayoutSettings : public PMSettingsDialogPage
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ PMLayoutSettings( QWidget* parent, const char* name = 0 );
+ /** */
+ virtual void displaySettings( );
+ /** */
+ virtual bool validateData( );
+ /** */
+ virtual void applySettings( );
+ /** */
+ virtual void displayDefaults( );
+
+protected slots:
+ /**
+ * Called when the browse add layout button is clicked
+ */
+ void slotAddLayout( );
+ /**
+ * Called when the remove layout button is clicked
+ */
+ void slotRemoveLayout( );
+ /**
+ * Called when the selected layout changes
+ */
+ void slotLayoutSelected( int i );
+ /**
+ * Called when the layout name changes
+ */
+ void slotLayoutNameChanged( const QString& text );
+ /**
+ * Called when the selected view entry changes
+ */
+ void slotViewEntrySelected( QListViewItem* text );
+ /**
+ * Called when the view type field changes value
+ */
+ void slotViewTypeChanged( int index );
+ /**
+ * Called when the gl view type field changes value
+ */
+ //void slotGLViewTypeChanged( int index );
+ /**
+ * Called when the dock position field changes value
+ */
+ void slotDockPositionChanged( int index );
+ /**
+ * Called when the view height field changes value
+ */
+ void slotViewHeightChanged( const QString& text );
+ /**
+ * Called when the column width field changes value
+ */
+ void slotColumnWidthChanged( const QString& text );
+ /**
+ * Called when the floating height changes value
+ */
+ void slotFloatingHeightChanged( const QString& text );
+ /**
+ * Called when the floating width changes value
+ */
+ void slotFloatingWidthChanged( const QString& text );
+ /**
+ * Called when the floating position x changes value
+ */
+ void slotFloatingPosXChanged( const QString& text );
+ /**
+ * Called when the floating position y changes value
+ */
+ void slotFloatingPosYChanged( const QString& text );
+ /**
+ * Called when the add view entry button is clicked
+ */
+ void slotAddViewEntryClicked( );
+ /**
+ * Called when the remove view entry button is clicked
+ */
+ void slotRemoveViewEntryClicked( );
+ /**
+ * Called when the move up view entry button is clicked
+ */
+ void slotMoveUpViewEntryClicked( );
+ /**
+ * Called when the move down view entry button is clicked
+ */
+ void slotMoveDownViewEntryClicked( );
+ /**
+ * Called when the view type description has changed
+ */
+ void slotViewTypeDescriptionChanged( );
+
+private:
+ void displayLayoutList( );
+ void displayCustomOptions( );
+
+ QComboBox* m_pDefaultLayout;
+ QListBox* m_pViewLayouts;
+ QPushButton* m_pAddLayout;
+ QPushButton* m_pRemoveLayout;
+ QLineEdit* m_pViewLayoutName;
+ QListView* m_pViewEntries;
+ QPushButton* m_pAddEntry;
+ QPushButton* m_pRemoveEntry;
+ QPushButton* m_pMoveUpEntry;
+ QPushButton* m_pMoveDownEntry;
+ QComboBox* m_pViewTypeEdit;
+ QComboBox* m_pDockPositionEdit;
+ PMIntEdit* m_pColumnWidthEdit;
+ QLabel* m_pColumnWidthLabel;
+ PMIntEdit* m_pViewHeightEdit;
+ QLabel* m_pViewHeightLabel;
+
+ PMIntEdit* m_pFloatingHeight;
+ PMIntEdit* m_pFloatingWidth;
+ QLabel* m_pFloatingHeightLabel;
+ QLabel* m_pFloatingWidthLabel;
+ PMIntEdit* m_pFloatingPosX;
+ PMIntEdit* m_pFloatingPosY;
+ QLabel* m_pFloatingPosXLabel;
+ QLabel* m_pFloatingPosYLabel;
+
+ PMViewOptionsWidget* m_pCustomOptionsWidget;
+ QWidget* m_pCustomOptionsHolder;
+
+ QValueList<PMViewLayout> m_viewLayouts;
+ QValueListIterator<PMViewLayout> m_currentViewLayout;
+ QValueListIterator<PMViewLayout> m_defaultViewLayout;
+ QValueListIterator<PMViewLayoutEntry> m_currentViewEntry;
+};
+
+#endif
diff --git a/kpovmodeler/pmlibrarybrowser.cpp b/kpovmodeler/pmlibrarybrowser.cpp
new file mode 100644
index 00000000..e133f08c
--- /dev/null
+++ b/kpovmodeler/pmlibrarybrowser.cpp
@@ -0,0 +1,304 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmlibrarybrowser.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcombobox.h>
+#include <qsplitter.h>
+#include <qtimer.h>
+#include <qpushbutton.h>
+
+#include <kio/job.h>
+#include <kurl.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kmessagebox.h>
+#include <kdialog.h>
+#include <kdiroperator.h>
+#include <kiconloader.h>
+#include <kinputdialog.h>
+
+#include <stdlib.h>
+
+#include "pmlineedits.h"
+#include "pmdialogeditbase.h"
+#include "pmlibrarymanager.h"
+#include "pmlibraryhandle.h"
+#include "pmlibraryobject.h"
+#include "pmlibraryiconview.h"
+#include "pmlibraryentrypreview.h"
+
+// ************** PMLibraryBrowser **************************
+
+PMLibraryBrowserView::PMLibraryBrowserView( PMPart* /*part*/, QWidget* parent /*= 0*/,
+ const char* name /*=0*/ )
+ : PMViewBase( parent, name )
+{
+ QHBoxLayout* hl = new QHBoxLayout( this );
+ PMLibraryBrowserViewWidget* tv = new PMLibraryBrowserViewWidget( this );
+ hl->addWidget( tv );
+}
+
+QString PMLibraryBrowserView::description( ) const
+{
+ return i18n( "Library View" );
+}
+
+PMLibraryBrowserViewWidget::PMLibraryBrowserViewWidget( QWidget* parent, const char* name )
+ : QWidget( parent, name )
+{
+ setCaption( i18n( "Library Objects" ) );
+
+ QVBoxLayout* vl = new QVBoxLayout( this, KDialog::spacingHint( ) );
+
+ QHBoxLayout* hl = new QHBoxLayout( vl );
+
+ m_pUpButton = new QPushButton( this );
+ m_pUpButton->setPixmap( SmallIcon( "up" ) );
+ m_pNewSubLibraryButton = new QPushButton( this );
+ m_pNewSubLibraryButton->setPixmap( SmallIcon( "folder_new" ) );
+ m_pNewObjectButton = new QPushButton( this );
+ m_pNewObjectButton->setPixmap( SmallIcon( "filenew" ) );
+ m_pDeleteObjectButton = new QPushButton( this );
+ m_pDeleteObjectButton->setPixmap( SmallIcon( "editdelete" ) );
+ QLabel* lbl = new QLabel( i18n( "Library: " ), this );
+ m_pLibraryComboBox = new QComboBox( this );
+ m_pLibraryComboBox->insertStringList( PMLibraryManager::theManager( )->availableLibraries( ) );
+ m_pLibraryComboBox->setDuplicatesEnabled( false );
+ m_pLibraryComboBox->setCurrentItem( 0 );
+ hl->addWidget( m_pUpButton );
+ hl->addWidget( m_pNewSubLibraryButton );
+ hl->addWidget( m_pNewObjectButton );
+ hl->addWidget( m_pDeleteObjectButton );
+ hl->addWidget( lbl );
+ hl->addWidget( m_pLibraryComboBox );
+ hl->addStretch( 1 );
+
+ QSplitter *splitv = new QSplitter( this );
+ m_pLibraryIconView = new PMLibraryIconView( splitv );
+ m_pLibraryIconView->setMinimumSize( PMDialogEditBase::previewSize( )+20, PMDialogEditBase::previewSize( ) );
+ m_pLibraryEntryPreview = new PMLibraryEntryPreview( splitv );
+ vl->addWidget( splitv, 99 );
+
+ // Connect all the objects
+ connect( m_pUpButton, SIGNAL( clicked( ) ), SLOT( slotUpButtonClicked( ) ) );
+ connect( m_pNewSubLibraryButton, SIGNAL( clicked( ) ), SLOT( slotNewSubLibraryClicked( ) ) );
+ connect( m_pNewObjectButton, SIGNAL( clicked( ) ), SLOT( slotNewObjectClicked( ) ) );
+ connect( m_pDeleteObjectButton, SIGNAL( clicked( ) ), SLOT( slotDeleteClicked( ) ) );
+ connect( m_pLibraryComboBox, SIGNAL( highlighted( const QString& ) ),
+ SLOT( slotPathSelected( const QString& ) ) );
+ connect( m_pLibraryIconView, SIGNAL( selectionChanged( QIconViewItem* ) ),
+ SLOT( slotSelectionChanged( QIconViewItem* ) ) );
+ connect( m_pLibraryIconView, SIGNAL( executed( QIconViewItem* ) ),
+ SLOT( slotSelectionExecuted( QIconViewItem* ) ) );
+ connect( m_pLibraryEntryPreview, SIGNAL( objectChanged( ) ), SLOT( slotIconViewRefresh( ) ) );
+
+ // Set the selected library
+ slotPathSelected( m_pLibraryComboBox->currentText( ) );
+}
+
+void PMLibraryBrowserViewWidget::resizeEvent( QResizeEvent* /*ev*/ )
+{
+}
+
+void PMLibraryBrowserViewWidget::slotPathSelected( const QString& str )
+{
+ PMLibraryHandle* h = PMLibraryManager::theManager( )->getLibraryHandle( str );
+ if( h )
+ {
+ m_pLibraryIconView->setLibrary( h );
+ m_pCurrentLibrary = h;
+ // This can never be a sub library
+ m_pUpButton->setEnabled( false );
+ // If the top library is read-only so is everthing below it
+ m_topLibraryReadOnly = m_pCurrentLibrary->isReadOnly( );
+ m_pNewSubLibraryButton->setEnabled( !m_topLibraryReadOnly );
+ m_pNewObjectButton->setEnabled( !m_topLibraryReadOnly );
+ m_pDeleteObjectButton->setEnabled( !m_topLibraryReadOnly );
+ }
+ else
+ {
+ m_pUpButton->setEnabled( false );
+ m_pNewSubLibraryButton->setEnabled( false );
+ m_pNewObjectButton->setEnabled( false );
+ m_pDeleteObjectButton->setEnabled( false );
+ }
+}
+
+void PMLibraryBrowserViewWidget::slotIconViewRefresh( )
+{
+ m_pLibraryIconView->refresh( );
+}
+
+void PMLibraryBrowserViewWidget::slotIconViewSetLibrary( )
+{
+ m_pLibraryIconView->setLibrary( m_pFutureLibrary );
+ m_pCurrentLibrary = m_pFutureLibrary;
+ m_pFutureLibrary = NULL;
+}
+
+void PMLibraryBrowserViewWidget::slotSelectionChanged( QIconViewItem* item )
+{
+ PMLibraryIconViewItem* sel = static_cast<PMLibraryIconViewItem*>( item );
+ m_pLibraryIconView->setCurrentItem( sel );
+ if( sel->isSubLibrary( ) )
+ {
+ if( m_pLibraryEntryPreview->saveIfNeeded( ) )
+ QTimer::singleShot( 100, this, SLOT( slotIconViewRefresh( ) ) );
+ else
+ m_pLibraryEntryPreview->showPreview( sel->path( ), m_topLibraryReadOnly, true );
+ }
+ else
+ {
+ if( m_pLibraryEntryPreview->saveIfNeeded( ) )
+ QTimer::singleShot( 100, this, SLOT( slotIconViewRefresh( ) ) );
+ else
+ m_pLibraryEntryPreview->showPreview( sel->path( ), m_topLibraryReadOnly, false );
+ }
+ m_pLibraryIconView->setFocus();
+}
+
+void PMLibraryBrowserViewWidget::slotSelectionExecuted( QIconViewItem* item )
+{
+ PMLibraryIconViewItem* sel = static_cast<PMLibraryIconViewItem*>( item );
+ m_pLibraryIconView->setCurrentItem( sel );
+ if( sel->isSubLibrary( ) )
+ {
+ // It's a sub library
+ m_pFutureLibrary = new PMLibraryHandle( sel->path( ) );
+ m_pLibraryEntryPreview->clearPreview( );
+ QTimer::singleShot( 100, this, SLOT( slotIconViewSetLibrary( ) ) );
+ m_pUpButton->setEnabled( true );
+ }
+ else
+ {
+ // It's an object
+ if( m_pLibraryEntryPreview->saveIfNeeded( ) )
+ QTimer::singleShot( 100, this, SLOT( slotIconViewRefresh( ) ) );
+ else
+ m_pLibraryEntryPreview->showPreview( sel->path( ), m_topLibraryReadOnly, false );
+ }
+ m_pLibraryIconView->setFocus();
+}
+
+void PMLibraryBrowserViewWidget::slotUpButtonClicked( )
+{
+ QDir pathManipulator( m_pCurrentLibrary->path( ) );
+
+ pathManipulator.cdUp( );
+ m_pFutureLibrary = new PMLibraryHandle( pathManipulator.path( ) );
+ if( !m_pFutureLibrary->isSubLibrary( ) )
+ m_pUpButton->setEnabled( false );
+ QTimer::singleShot( 100, this, SLOT( slotIconViewSetLibrary( ) ) );
+
+ // Release the current Library
+ delete m_pCurrentLibrary;
+}
+
+void PMLibraryBrowserViewWidget::slotDeleteClicked( )
+{
+ PMLibraryIconViewItem* sel = static_cast<PMLibraryIconViewItem*>( m_pLibraryIconView->currentItem( ) );
+ PMLibraryHandle::PMResult rst;
+ if( !sel )
+ return;
+ else if( sel->isSubLibrary( ) )
+ rst = m_pCurrentLibrary->deleteSubLibrary( sel->path( ) );
+ else
+ rst = m_pCurrentLibrary->deleteObject( sel->path( ) );
+
+ switch( rst )
+ {
+ case PMLibraryHandle::Ok:
+ {
+ KIO::Job *job = KIO::del( sel->path() );
+ connect( job, SIGNAL( result( KIO::Job * ) ), SLOT( slotJobResult( KIO::Job * ) ) );
+ }
+ break;
+ case PMLibraryHandle::ReadOnlyLib:
+ KMessageBox::error( this, i18n( "This library is read only." ), i18n( "Error" ) );
+ break;
+ case PMLibraryHandle::NotInLib:
+ KMessageBox::error( this, i18n( "The current library does not contain that item." ), i18n( "Error" ) );
+ break;
+ default:
+ KMessageBox::error( this, i18n( "Could not remove item." ), i18n( "Error" ) );
+ break;
+ }
+}
+
+void PMLibraryBrowserViewWidget::slotNewObjectClicked( )
+{
+ m_pLibraryEntryPreview->saveIfNeeded( );
+
+ switch( m_pCurrentLibrary->createNewObject( ) )
+ {
+ case PMLibraryHandle::Ok:
+ QTimer::singleShot( 100, this, SLOT( slotIconViewRefresh( ) ) );
+ break;
+ case PMLibraryHandle::ReadOnlyLib:
+ KMessageBox::error( this, i18n( "This library is read only." ), i18n( "Error" ) );
+ break;
+ default:
+ KMessageBox::error( this, i18n( "Could not create a new object." ), i18n( "Error" ) );
+ }
+}
+
+void PMLibraryBrowserViewWidget::slotNewSubLibraryClicked( )
+{
+ bool result = false;
+
+ m_pLibraryEntryPreview->saveIfNeeded( );
+ QString subLibraryName = KInputDialog::getText( i18n( "Create Sub-Library" ),
+ i18n( "Enter the sub-library name: " ),
+ i18n( "Unknown" ),
+ &result );
+
+ if( result )
+ {
+ switch( m_pCurrentLibrary->createNewSubLibrary( subLibraryName ) )
+ {
+ case PMLibraryHandle::Ok:
+ m_pLibraryIconView->refresh( );
+ break;
+ case PMLibraryHandle::ExistingDir:
+ KMessageBox::error( this, i18n( "That library already exists." ), i18n( "Error" ) );
+ break;
+ case PMLibraryHandle::ReadOnlyLib:
+ KMessageBox::error( this, i18n( "This library is read only." ), i18n( "Error" ) );
+ break;
+ default:
+ KMessageBox::error( this, i18n( "Could not create a new sub library." ), i18n( "Error" ) );
+ }
+ }
+}
+
+void PMLibraryBrowserViewWidget::slotJobResult( KIO::Job * job )
+{
+ if( job->error( ) )
+ job->showErrorDialog( this );
+ QTimer::singleShot( 100, this, SLOT( slotIconViewRefresh( ) ) );
+}
+
+QString PMLibraryBrowserViewFactory::description( ) const
+{
+ return i18n( "Library View" );
+}
+
+#include "pmlibrarybrowser.moc"
diff --git a/kpovmodeler/pmlibrarybrowser.h b/kpovmodeler/pmlibrarybrowser.h
new file mode 100644
index 00000000..3d5af6ff
--- /dev/null
+++ b/kpovmodeler/pmlibrarybrowser.h
@@ -0,0 +1,119 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#ifndef PMLIBRARYBROWSER_H
+#define PMLIBRARYBROWSER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qwidget.h>
+#include <qdict.h>
+
+#include "pmviewbase.h"
+#include "pmviewfactory.h"
+
+class QComboBox;
+class QIconViewItem;
+class QPushButton;
+class KConfig;
+class KDirOperator;
+class PMLibraryIconView;
+class PMLibraryEntryPreview;
+class PMLibraryHandle;
+class PMPart;
+namespace KIO{ class Job; }
+
+typedef QDict<QString> QStringDict;
+
+/**
+ * Wrapper class for the treeview/dock widget
+ */
+class PMLibraryBrowserView : public PMViewBase
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ PMLibraryBrowserView( PMPart* part, QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual QString viewType( ) const { return QString( "librarybrowserview" ); }
+ /** */
+ virtual QString description( ) const;
+};
+
+/**
+ * This class provides a non-modal dialog to browse the available libraries.
+ */
+class PMLibraryBrowserViewWidget: public QWidget
+{
+ Q_OBJECT
+public:
+ PMLibraryBrowserViewWidget( QWidget *parent, const char* name = NULL );
+
+private slots:
+ void resizeEvent( QResizeEvent* ev );
+ void slotPathSelected( const QString& str );
+ void slotSelectionChanged( QIconViewItem* item );
+ void slotSelectionExecuted( QIconViewItem* item );
+ void slotUpButtonClicked( );
+ void slotDeleteClicked( );
+ void slotNewObjectClicked( );
+ void slotNewSubLibraryClicked( );
+
+ void slotJobResult( KIO::Job * );
+
+ // These slots provide delayed activity on the IconView
+ void slotIconViewRefresh( );
+ void slotIconViewSetLibrary( );
+
+private:
+
+
+ QPushButton* m_pUpButton;
+ QPushButton* m_pNewSubLibraryButton;
+ QPushButton* m_pNewObjectButton;
+ QPushButton* m_pDeleteObjectButton;
+ QComboBox* m_pLibraryComboBox;
+ PMLibraryIconView* m_pLibraryIconView;
+ PMLibraryEntryPreview* m_pLibraryEntryPreview;
+ PMLibraryHandle* m_pCurrentLibrary;
+ PMLibraryHandle* m_pFutureLibrary;
+ bool m_topLibraryReadOnly;
+};
+
+/**
+ * Factory class for the tree view
+ */
+class PMLibraryBrowserViewFactory : public PMViewTypeFactory
+{
+public:
+ PMLibraryBrowserViewFactory( ) { }
+ virtual QString viewType( ) const { return QString( "librarybrowserview" ); }
+ virtual QString description( ) const;
+ virtual QString iconName( ) const { return QString( "pmlibrarybrowserview" ); }
+ virtual PMViewBase* newInstance( QWidget* parent, PMPart* part ) const
+ {
+ return new PMLibraryBrowserView( part, parent );
+ }
+};
+
+#endif
diff --git a/kpovmodeler/pmlibraryentrypreview.cpp b/kpovmodeler/pmlibraryentrypreview.cpp
new file mode 100644
index 00000000..b7232cdd
--- /dev/null
+++ b/kpovmodeler/pmlibraryentrypreview.cpp
@@ -0,0 +1,344 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmlibraryobject.h"
+#include "pmlibraryhandle.h"
+#include "pmlibraryentrypreview.h"
+#include "pmdialogeditbase.h"
+#include "pmpart.h"
+#include "pmtreeview.h"
+#include "pmxmlparser.h"
+#include "pmscene.h"
+#include "pmobjectdrag.h"
+
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qmultilineedit.h>
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qdragobject.h>
+
+#include <kurl.h>
+#include <klocale.h>
+#include <kdialog.h>
+#include <kmessagebox.h>
+#include <kfiledialog.h>
+
+PMLibraryEntryPreview::PMLibraryEntryPreview( QWidget* parent ) :
+ QWidget( parent )
+{
+ setAcceptDrops( true );
+ m_pPart = new PMPart( this, "treeview", NULL, "part", false, true );
+ m_pPart->setReadWrite( false );
+ m_readOnly = true;
+ m_modified = false;
+ m_subLib = false;
+
+ setMaximumSize( 1000, 1000 );
+ QVBoxLayout* vl = new QVBoxLayout( this, KDialog::spacingHint( ) );
+
+ QHBoxLayout* hl = new QHBoxLayout( vl );
+ hl->addStretch( 1 );
+
+ QGridLayout* gl = new QGridLayout( vl, 4, 2 );
+ gl->setColStretch( 1, 1 );
+ QLabel* lbl = new QLabel( i18n( "Name: " ), this );
+ m_pName = new QLineEdit( this );
+ m_pName->setAlignment( Qt::AlignLeft );
+ m_pName->setReadOnly( true );
+ gl->addWidget( lbl, 0, 0 );
+ gl->addWidget( m_pName, 0, 1 );
+
+ lbl = new QLabel( i18n( "Description:" ), this );
+ lbl->setAlignment( Qt::AlignTop );
+ m_pDescription = new QMultiLineEdit( this );
+ m_pDescription->setAlignment( Qt::AlignTop | Qt::AlignLeft |
+ Qt::WordBreak | Qt::DontClip );
+ m_pDescription->setReadOnly( true );
+ gl->addWidget( lbl, 1, 0 );
+ gl->addWidget( m_pDescription, 1, 1 );
+
+ m_pKeywordsLabel = new QLabel( i18n( "Keywords:" ), this );
+ m_pKeywordsLabel->setAlignment( Qt::AlignTop );
+ m_pKeywords = new QMultiLineEdit( this );
+ m_pKeywords->setAlignment( Qt::AlignTop | Qt::AlignLeft |
+ Qt::WordBreak | Qt::DontClip );
+ m_pKeywords->setReadOnly( true );
+ gl->addWidget( m_pKeywordsLabel, 2, 0 );
+ gl->addWidget( m_pKeywords, 2, 1 );
+
+ m_pContentsLabel = new QLabel( i18n( "Contents:" ), this );
+ m_pContentsPreview = new PMTreeView( m_pPart, this );
+ gl->addMultiCellWidget( m_pContentsLabel, 3, 3, 0, 1 );
+ gl->addMultiCellWidget( m_pContentsPreview, 4, 4, 0, 1 );
+ gl->setRowStretch(4, 1);
+
+ hl = new QHBoxLayout( vl );
+ hl->addStretch( 1 );
+ m_pSetPreviewImageButton = new QPushButton( i18n( "Change Preview Image" ), this );
+ m_pSetPreviewImageButton->setEnabled( false );
+ hl->addWidget( m_pSetPreviewImageButton );
+
+ hl = new QHBoxLayout( vl );
+ hl->addStretch( 1 );
+ m_pApplyChanges = new QPushButton( i18n( "&Apply" ), this );
+ m_pApplyChanges->setEnabled( false );
+ hl->addWidget( m_pApplyChanges );
+ m_pCancelChanges = new QPushButton( i18n( "&Cancel" ), this );
+ m_pCancelChanges->setEnabled( false );
+ hl->addWidget( m_pCancelChanges );
+
+ connect( m_pName, SIGNAL( textChanged( const QString& ) ),
+ SLOT( slotTextChanged( const QString& ) ) );
+ connect( m_pDescription, SIGNAL( textChanged( ) ),
+ SLOT( slotTextChanged( ) ) );
+ connect( m_pKeywords, SIGNAL( textChanged( ) ),
+ SLOT( slotTextChanged( ) ) );
+ connect( m_pSetPreviewImageButton, SIGNAL( clicked( ) ),
+ SLOT( slotPreviewClicked( ) ) );
+ connect( m_pPart, SIGNAL( modified( ) ),
+ SLOT( slotTextChanged( ) ) );
+ connect( m_pApplyChanges, SIGNAL( clicked( ) ), SLOT( slotApplyClicked( ) ) );
+ connect( m_pCancelChanges, SIGNAL( clicked( ) ), SLOT( slotCancelClicked( ) ) );
+ vl->addStretch( 1 );
+}
+
+PMLibraryEntryPreview::~PMLibraryEntryPreview( )
+{
+// delete m_pPart;
+}
+
+bool PMLibraryEntryPreview::showPreview( KURL u, bool readOnly, bool subLib )
+{
+ bool result = false;
+
+ if( u.isLocalFile( ) )
+ {
+ result = saveIfNeeded( );
+
+ m_image.reset( );
+
+ m_subLib = subLib;
+ if( subLib )
+ {
+ // Load the new subLib to preview
+ PMLibraryHandle lib( u.path( ) );
+ m_pName->setText( lib.name( ) );
+ m_pDescription->setText( lib.description( ) );
+ m_pKeywords->setText( "" );
+ m_pPart->setReadWrite( true );
+ m_pPart->setScene( new PMScene( m_pPart ) );
+ m_pContentsPreview->slotRefresh( );
+ m_pPart->setReadWrite( false );
+ }
+ else
+ {
+ // Load the new object to preview
+ PMLibraryObject aux( u );
+
+ m_pName->setText( aux.name( ) );
+ m_pDescription->setText( aux.description( ) );
+ m_pKeywords->setText( aux.keywords( ) );
+ if( aux.preview( ) )
+ {
+ m_image = aux.preview( )->copy( );
+ }
+ loadObjects( aux.objects( ) );
+ // Save the preview location
+ }
+ m_pKeywordsLabel->setEnabled( !subLib );
+ m_pKeywords->setEnabled( !subLib );
+ m_pContentsLabel->setEnabled( !subLib );
+ m_pContentsPreview->setEnabled( !subLib );
+ setReadOnly( readOnly );
+ setModified( false );
+ m_currentURL = u;
+ }
+ return result;
+}
+
+void PMLibraryEntryPreview::loadObjects( QByteArray* obj )
+{
+
+ m_pPart->setReadWrite( true );
+ m_pPart->setScene( new PMScene( m_pPart ) );
+ if( obj )
+ {
+ PMXMLParser parser( m_pPart, *obj );
+ m_pPart->insertFromParser( i18n( "Object Load" ), &parser, m_pPart->scene( ) );
+ }
+ m_pPart->setReadWrite( false );
+ m_pContentsPreview->slotRefresh( );
+}
+
+void PMLibraryEntryPreview::clearPreview( )
+{
+ saveIfNeeded( );
+ m_pName->setText( "" );
+ m_pDescription->setText( "" );
+ m_pKeywords->setText( "" );
+ m_image.reset( );
+ m_pPart->setReadWrite( true );
+ m_pPart->setScene( new PMScene( m_pPart ) );
+ m_pContentsPreview->slotRefresh( );
+ m_pPart->setReadWrite( false );
+ setReadOnly( true );
+ setModified( false );
+}
+
+void PMLibraryEntryPreview::setReadOnly( bool b )
+{
+ m_readOnly = b;
+ if( b )
+ {
+ m_pName->setReadOnly( true );
+ m_pDescription->setReadOnly( true );
+ m_pKeywords->setReadOnly( true );
+ m_pSetPreviewImageButton->setEnabled( false );
+ m_pPart->setReadWrite( false );
+ }
+ else
+ {
+ m_pName->setReadOnly( false );
+ m_pDescription->setReadOnly( false );
+ if( m_subLib )
+ {
+ m_pKeywords->setReadOnly( true );
+ m_pSetPreviewImageButton->setEnabled( false );
+ m_pPart->setReadWrite( false );
+ }
+ else
+ {
+ m_pKeywords->setReadOnly( false );
+ m_pSetPreviewImageButton->setEnabled( true );
+ m_pPart->setReadWrite( true );
+ }
+ }
+}
+
+void PMLibraryEntryPreview::slotTextChanged( )
+{
+ setModified( true );
+}
+
+void PMLibraryEntryPreview::slotTextChanged( const QString& /* s */)
+{
+ setModified( true );
+}
+
+void PMLibraryEntryPreview::slotPreviewClicked( )
+{
+ KFileDialog dlg( QString::null, "", NULL, "", false );
+
+ dlg.setFilter( "image/jpeg image/gif image/tiff image/png image/x-bmp" );
+ if( dlg.exec( ) == QDialog::Accepted )
+ {
+ m_image.load( dlg.selectedFile( ) );
+ setModified( true );
+ }
+}
+
+void PMLibraryEntryPreview::slotApplyClicked( )
+{
+ saveIfNeeded( true );
+ emit objectChanged( );
+}
+
+void PMLibraryEntryPreview::slotCancelClicked( )
+{
+ setModified( false );
+ showPreview( m_currentURL, m_readOnly, m_subLib );
+}
+
+bool PMLibraryEntryPreview::saveIfNeeded( bool forceSave )
+{
+ if ( m_modified )
+ {
+ // ask if we must save the changes
+ if( forceSave || KMessageBox::questionYesNo( this,
+ i18n( "The object has been modified and not saved.\nDo you wish to save?" ),
+ i18n( "Warning" ), KStdGuiItem::save(), KStdGuiItem::discard() ) == KMessageBox::Yes )
+ {
+ if( m_subLib )
+ {
+ PMLibraryHandle lib( m_currentURL.path( ) );
+ lib.setName( m_pName->text( ) );
+ lib.setDescription( m_pDescription->text( ) );
+ lib.saveLibraryInfo( );
+ }
+ else
+ {
+ PMLibraryObject objToSave;
+ PMObjectList sortedList;
+ PMObject* tmp;
+
+ // First save the text parameters.
+ objToSave.setName( m_pName->text( ) );
+ objToSave.setDescription( m_pDescription->text( ) );
+ objToSave.setKeywords( m_pKeywords->text( ) );
+
+ // Gather the contents of the part.
+ tmp = m_pPart->scene( )->firstChild( );
+ while( tmp )
+ {
+ sortedList.append( tmp );
+ tmp = tmp->nextSibling();
+ }
+
+ // Add them to the object to save.
+ PMObjectDrag drag( m_pPart, sortedList );
+ objToSave.setObjects( drag.encodedData( "application/x-kpovmodeler" ) );
+
+ // Add the preview image
+ objToSave.setPreview( m_image.copy( ) );
+
+ // Finally save the object to a file.
+ kdDebug( 0 ) << m_currentURL.path( ) << "\n";
+ objToSave.save( m_currentURL.path( ) );
+ }
+ setModified( false );
+ return true;
+ }
+ setModified( false );
+ }
+ return false;
+}
+
+void PMLibraryEntryPreview::dragEnterEvent( QDragEnterEvent* event )
+{
+ event->accept( !m_readOnly && QImageDrag::canDecode( event ) );
+}
+
+void PMLibraryEntryPreview::dropEvent( QDropEvent* event )
+{
+ QImage img;
+ if( QImageDrag::decode( event, img ) )
+ {
+ m_image = img;
+ setModified( true );
+ }
+}
+
+void PMLibraryEntryPreview::setModified( bool modified )
+{
+ m_modified = modified;
+ m_pApplyChanges->setEnabled( modified );
+ m_pCancelChanges->setEnabled( modified );
+}
+
+#include "pmlibraryentrypreview.moc"
diff --git a/kpovmodeler/pmlibraryentrypreview.h b/kpovmodeler/pmlibraryentrypreview.h
new file mode 100644
index 00000000..95077299
--- /dev/null
+++ b/kpovmodeler/pmlibraryentrypreview.h
@@ -0,0 +1,119 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#ifndef PMLIBRARYOBJECTPREVIEW_H
+#define PMLIBRARYOBJECTPREVIEW_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qwidget.h>
+#include <qimage.h>
+
+#include <kurl.h>
+
+class QLabel;
+class QLineEdit;
+class QMultiLineEdit;
+class QPushButton;
+class QFrame;
+class PMPart;
+class PMTreeView;
+
+/**
+ * Preview widget for Library Objects and sub Libs.
+ */
+class PMLibraryEntryPreview: public QWidget
+{
+ Q_OBJECT
+public:
+ /** Constructor */
+ PMLibraryEntryPreview( QWidget *parent );
+ /** Destructor */
+ ~PMLibraryEntryPreview( );
+
+ /**
+ * Called to show the file preview.
+ * @param url The path to the file
+ * @param readOnly Whether the top library is read only
+ * @param subLib Whether this is a sub library to preview
+ * @Return true if the previous file was saved to disk.
+ */
+ bool showPreview( KURL url, bool readOnly, bool subLib );
+ /**
+ * Clears the preview
+ */
+ virtual void clearPreview( );
+
+ /**
+ * Save the object, if needed.
+ * @param forceSave If true don't ask about changes just save them
+ * @Return true if a save was performed.
+ */
+ bool saveIfNeeded( bool forceSave = false );
+
+signals:
+ /** Emitted when the object name has been changed */
+ void objectChanged( );
+
+protected:
+ virtual void dragEnterEvent( QDragEnterEvent* event );
+
+ virtual void dropEvent( QDropEvent* event );
+
+private slots:
+ /** Called when description or keywords are changed */
+ void slotTextChanged( );
+ /** Called when the name is changed */
+ void slotTextChanged( const QString& s );
+ /** Called when the set preview button is clicked */
+ void slotPreviewClicked( );
+ /** Called when the apply button is clicked */
+ void slotApplyClicked( );
+ /** Called when the cancel button is clicked */
+ void slotCancelClicked( );
+
+private:
+ /** Called to load the object tree. */
+ void loadObjects( QByteArray* obj );
+ /** Sets whether the object is read only or not */
+ void setReadOnly( bool b );
+ /** Sets whether the object is modified or not */
+ void setModified( bool modified );
+
+ PMPart* m_pPart;
+ QLineEdit* m_pName;
+ QMultiLineEdit* m_pDescription;
+ QLabel* m_pKeywordsLabel;
+ QMultiLineEdit* m_pKeywords;
+ QLabel* m_pContentsLabel;
+ PMTreeView* m_pContentsPreview;
+ QPushButton* m_pSetPreviewImageButton;
+ QPushButton* m_pApplyChanges;
+ QPushButton* m_pCancelChanges;
+
+ QImage m_image;
+ KURL m_currentURL;
+
+ bool m_modified;
+ bool m_readOnly;
+ bool m_subLib;
+};
+
+#endif
diff --git a/kpovmodeler/pmlibraryhandle.cpp b/kpovmodeler/pmlibraryhandle.cpp
new file mode 100644
index 00000000..7902f789
--- /dev/null
+++ b/kpovmodeler/pmlibraryhandle.cpp
@@ -0,0 +1,395 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Luis Carvalho
+ email : lpassos@oninetspeed.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#include "pmlibraryhandle.h"
+#include "pmlibraryobject.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <qdir.h>
+#include <qfile.h>
+#include <qdom.h>
+#include <qtextstream.h>
+#include <qimage.h>
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+
+#include "pmdebug.h"
+
+PMLibraryHandle::PMLibraryHandle( )
+{
+ setPath( "" );
+ setAuthor( i18n( "Unknown" ) );
+ setName( i18n( "Unknown" ) );
+ m_readOnly = false;
+ m_objects.setAutoDelete( true );
+ m_libraries.setAutoDelete( true );
+}
+
+PMLibraryHandle::PMLibraryHandle( const QString& path )
+{
+ setPath( path );
+ setAuthor( i18n( "Unknown" ) );
+ setName( i18n( "Unknown" ) );
+ m_objects.setAutoDelete( true );
+ m_libraries.setAutoDelete( true );
+ loadLibraryInfo( );
+}
+
+PMLibraryHandle::~PMLibraryHandle( )
+{
+}
+
+void PMLibraryHandle::setName( const QString& name )
+{
+ m_name = name;
+}
+
+void PMLibraryHandle::setPath( const QString& path )
+{
+ m_objects.clear( );
+ m_path = path;
+}
+
+void PMLibraryHandle::setAuthor( const QString& author )
+{
+ m_author = author;
+}
+
+void PMLibraryHandle::setDescription( const QString& description )
+{
+ m_description = description;
+}
+
+void PMLibraryHandle::setReadOnly( const bool rdOnly )
+{
+ m_readOnly = rdOnly;
+}
+
+void PMLibraryHandle::loadLibraryInfo( )
+{
+ // 1. Open the information file (library_index.xml)
+ QFile file( m_path + "/library_index.xml" );
+
+ if( !file.open( IO_ReadOnly ) )
+ {
+ kdError( PMArea ) << "Could not find the library index." << endl;
+ return;
+ }
+
+ // 2. Read the information
+ QDomDocument doc( "KPOVLIBINDEX" );
+ doc.setContent( &file );
+
+ QDomElement e = doc.documentElement( );
+
+ if( e.tagName( ) != "library" )
+ {
+ kdError( PMArea ) << "This doesn't appear to be a library index." << endl;
+ return;
+ }
+
+ // 3. The library entry
+ setName( e.attribute( "name", i18n( "Unknown" ) ) );
+ setAuthor( e.attribute( "author", i18n( "Unknown" ) ) );
+ setDescription( e.attribute( "description", "" ) );
+ if( e.attribute( "readonly", "false" ) == "false" )
+ m_readOnly = false;
+ else
+ m_readOnly = true;
+
+ if( e.attribute( "sublibrary", "false" ) == "false" )
+ m_subLibrary = false;
+ else
+ m_subLibrary = true;
+
+ // 4. The object entries
+ QDomNode n = e.firstChild( );
+ if( !n.isNull( ) )
+ {
+ if( n.isElement( ) )
+ {
+ QDomElement c = n.toElement( );
+ if( c.tagName( ) == "object_list" )
+ {
+ n = n.firstChild( );
+ while( !n.isNull( ) )
+ {
+ c = n.toElement( );
+ if( c.tagName( ) == "object_entry" )
+ {
+ m_objects.insert( c.attribute( "name", i18n( "Unknown" ) ),
+ new QString( c.attribute( "file", "" ) ) );
+ }
+ else if( c.tagName( ) == "library_entry" )
+ {
+ m_libraries.insert( c.attribute( "name", i18n( "Unknown" ) ),
+ new QString( c.attribute( "file", "" ) ) );
+ }
+ n = n.nextSibling( );
+ }
+ }
+ }
+ }
+}
+
+PMLibraryHandle::PMResult PMLibraryHandle::createLibrary( )
+{
+ // Test if the library exists.
+ QDir d( m_path );
+
+ if( !d.exists( ) )
+ {
+ // If it doesn't, create it
+ if( !d.mkdir( m_path ) )
+ {
+ return PMLibraryHandle::CouldNotCreateDir;
+ }
+ }
+ else
+ {
+ return PMLibraryHandle::ExistingDir;
+ }
+
+ return saveLibraryInfo( );
+}
+
+PMLibraryHandle::PMResult PMLibraryHandle::saveLibraryInfo( )
+{
+ // Save the information to the index
+ QFile file( m_path + "/library_index.xml" );
+ if( !file.open( IO_WriteOnly ) )
+ {
+ return PMLibraryHandle::CouldNotCreateInfo;
+ }
+
+ // Create the XML DOM tree
+ QDomDocument doc( "KPOVLIBINDEX" );
+ QDomElement e = doc.createElement( "library" );
+ e.setAttribute( "name", name( ) );
+ e.setAttribute( "author", author( ) );
+ e.setAttribute( "description", description( ) );
+ if( m_readOnly )
+ e.setAttribute( "readonly", "true" );
+ else
+ e.setAttribute( "readonly", "false" );
+
+ if( m_subLibrary )
+ e.setAttribute( "sublibrary", "true" );
+ else
+ e.setAttribute( "sublibrary", "false" );
+
+ // Add the object list to the tree
+ QDomElement l = doc.createElement( "object_list" );
+ for(QDictIterator<QString> it( m_objects ); it.current( ); ++it )
+ {
+ QDomElement n = doc.createElement( "object_entry" );
+ n.setAttribute( "name", it.currentKey( ) );
+ n.setAttribute( "file", *( it.current( ) ) );
+ l.appendChild( n );
+ }
+ for(QDictIterator<QString> it( m_libraries ); it.current( ); ++it )
+ {
+ QDomElement n = doc.createElement( "library_entry" );
+ n.setAttribute( "name", it.currentKey( ) );
+ n.setAttribute( "file", *( it.current( ) ) );
+ l.appendChild( n );
+ }
+ e.appendChild( l );
+ doc.appendChild( e );
+
+ // Save to the file
+ QTextStream str( &file );
+ str.setEncoding( QTextStream::UnicodeUTF8 );
+ str << doc.toString( );
+ file.close( );
+
+ return PMLibraryHandle::Ok;
+}
+
+PMLibraryHandle::PMResult PMLibraryHandle::createNewObject( )
+{
+ /// @todo Need to replace mkdtemp and mkstemps before enabling libs
+ return PMLibraryHandle::CouldNotCreateFile;
+ /*
+ PMLibraryObject aux;
+ QCString s = m_path.latin1( );
+ QString unknownIcon = locate( "data" , "kpovmodeler/questionmark.png" );
+ QImage img;
+ int fh;
+
+ if( m_readOnly )
+ return PMLibraryHandle::ReadOnlyLib;
+
+ aux.setName( i18n( "Empty" ) );
+ aux.setObjects( QByteArray( ) );
+ img.load( unknownIcon, "PNG" );
+ aux.setPreview( img );
+
+ s = s + "/objXXXXXX.kpml";
+ if( ( fh = mkstemps( s.data( ), 5 ) ) < 0 )
+ {
+ // Ooops! Error creating the file.
+ return PMLibraryHandle::CouldNotCreateFile;
+ }
+
+ // Success creating the file
+ close( fh );
+ m_objects.insert( i18n( "Empty" ), new QString( s ) );
+ aux.save( s );
+ saveLibraryInfo( );
+ return PMLibraryHandle::Ok;
+ */
+}
+
+PMLibraryHandle::PMResult PMLibraryHandle::addObject( const QString& path, const QString& name )
+{
+ if( m_readOnly )
+ return PMLibraryHandle::ReadOnlyLib;
+
+ m_objects.insert( name, new QString( path ) );
+ saveLibraryInfo( );
+ return PMLibraryHandle::Ok;
+}
+
+PMLibraryHandle::PMResult PMLibraryHandle::deleteObject( const QString& objectName )
+{
+ if( m_readOnly )
+ return PMLibraryHandle::ReadOnlyLib;
+
+ if( !m_objects.remove( objectName ) )
+ {
+ PMLibraryHandle::EntryIterator itr( m_objects );
+ for( ; itr.current( ); ++itr )
+ {
+ if( *(itr.current( )) == objectName )
+ {
+ m_objects.remove( itr.currentKey( ) );
+ saveLibraryInfo( );
+ return PMLibraryHandle::Ok;
+ }
+ }
+ }
+ return PMLibraryHandle::NotInLib;
+}
+
+PMLibraryHandle::PMResult PMLibraryHandle::createNewSubLibrary( const QString /*subLibName*/ )
+{
+ /// @todo Need to replace mkdtemp and mkstemps before enabling libs
+ return PMLibraryHandle::CouldNotCreateFile;
+ /*
+ char* dirname;
+ QCString s = m_path.latin1( );
+ PMLibraryHandle aux;
+
+ if( m_readOnly )
+ return PMLibraryHandle::ReadOnlyLib;
+
+ if( m_libraries.find( subLibName ) )
+ return PMLibraryHandle::ExistingDir;
+
+ s = s+ "/libXXXXXX";
+ if ( !( dirname = mkdtemp( s.data( ) ) ) )
+ {
+ // Ooops! Error creating the file.
+ return PMLibraryHandle::CouldNotCreateFile;
+ }
+
+ aux.setName( subLibName );
+ aux.setAuthor( author( ) );
+ aux.setPath( dirname );
+ aux.saveLibraryInfo( );
+ m_libraries.insert( subLibName, new QString( dirname ) );
+ saveLibraryInfo( );
+ return PMLibraryHandle::Ok;
+ */
+}
+
+PMLibraryHandle::PMResult PMLibraryHandle::addSubLibrary( const QString& path, const QString& subLibName )
+{
+ if( m_readOnly )
+ return PMLibraryHandle::ReadOnlyLib;
+
+ m_libraries.insert( subLibName, new QString( path ) );
+ saveLibraryInfo( );
+ return PMLibraryHandle::Ok;
+}
+
+PMLibraryHandle::PMResult PMLibraryHandle::deleteSubLibrary( const QString& subLibName )
+{
+ if( m_readOnly )
+ return PMLibraryHandle::ReadOnlyLib;
+
+ if( !m_libraries.remove( subLibName ) )
+ {
+ PMLibraryHandle::EntryIterator itr( m_libraries );
+ for( ; itr.current( ); ++itr )
+ {
+ if( *(itr.current( )) == subLibName )
+ {
+ m_libraries.remove( itr.currentKey( ) );
+ saveLibraryInfo( );
+ return PMLibraryHandle::Ok;
+ }
+ }
+ }
+ return PMLibraryHandle::NotInLib;
+}
+
+PMLibraryHandle::PMResult PMLibraryHandle::changeParentLibrary( const QString& parentPath )
+{
+ if( m_readOnly )
+ return PMLibraryHandle::ReadOnlyLib;
+
+ QString newPath = parentPath + "/" + m_path.section( '/', -1 );
+ PMLibraryHandle::EntryIterator itr( m_libraries );
+ for( ; itr.current( ); ++itr )
+ {
+ PMLibraryHandle lib = PMLibraryHandle( *itr.current( ) );
+ lib.changeParentLibrary( newPath );
+ m_libraries.replace( itr.currentKey( ), new QString( newPath + "/" + lib.path( ) ) );
+ }
+
+ PMLibraryHandle::EntryIterator objItr( m_objects );
+ for( ; objItr.current( ); ++objItr )
+ {
+ QString test = newPath + "/" + objItr.current( )->section( '/', -1 );
+ m_objects.replace( objItr.currentKey( ), new QString( newPath + "/" + objItr.current( )->section( '/', -1 ) ) );
+ }
+
+ saveLibraryInfo( );
+ m_path = newPath;
+ return PMLibraryHandle::Ok;
+}
+
+PMLibraryHandle::EntryIterator* PMLibraryHandle::createObjectIterator( )
+{
+ return new EntryIterator( m_objects );
+}
+
+PMLibraryHandle::EntryIterator* PMLibraryHandle::createSubLibraryIterator( )
+{
+ return new EntryIterator( m_libraries );
+}
+
+void PMLibraryHandle::setSubLibrary( bool isSubLibrary )
+{
+ m_subLibrary = isSubLibrary;
+}
diff --git a/kpovmodeler/pmlibraryhandle.h b/kpovmodeler/pmlibraryhandle.h
new file mode 100644
index 00000000..e906fd11
--- /dev/null
+++ b/kpovmodeler/pmlibraryhandle.h
@@ -0,0 +1,210 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Luis Carvalho
+ email : lpassos@oninetspeed.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#ifndef PMLIBRARYHANDLE_H
+#define PMLIBRARYHANDLE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qstring.h>
+#include <qdict.h>
+
+class QDomElement;
+
+/**
+ * Class that holds all the information about a specific library.
+ * The class can also create the library if it doesn't exists.
+ *
+ * A library is nothing more than a directory in the file system, and
+ * an index file stored in XML format.
+ *
+ * One library can have one or more sub-libraries. Sub-libraries can
+ * only contain the entries of object files and more sub-libraries.
+ *
+ */
+class PMLibraryHandle
+{
+public:
+ enum PMResult { Ok, CouldNotCreateDir, ExistingDir,
+ CouldNotCreateInfo, ReadOnlyLib,
+ CouldNotCreateFile, NotInLib };
+
+ /**
+ * Iterator for the objects in the library
+ */
+ typedef QDictIterator<QString> EntryIterator;
+
+ /**
+ * Constructor for an empty library
+ */
+ PMLibraryHandle( );
+
+ /**
+ * Constructor for a given directory.
+ */
+ PMLibraryHandle( const QString& path );
+
+ /**
+ * Destructor
+ */
+ ~PMLibraryHandle( );
+ /**
+ * Returns the library's name
+ */
+ QString name( ) const { return m_name; }
+
+ /**
+ * Returns the library's path
+ */
+ QString path( ) const { return m_path; }
+
+ /**
+ * Returns the library's author
+ */
+ QString author( ) const { return m_author; }
+
+ /**
+ * Returns the library's description
+ */
+ QString description( ) const { return m_description; }
+
+ /**
+ * Sets the library's name
+ */
+ void setName( const QString& name );
+
+ /**
+ * Sets the library's path
+ */
+ void setPath( const QString& path );
+
+ /**
+ * Sets the library's author
+ */
+ void setAuthor( const QString& author );
+
+ /**
+ * Sets the library's description
+ */
+ void setDescription( const QString& description );
+
+ /**
+ * Sets the library's erad only status
+ */
+ void setReadOnly( const bool rdonly = true );
+
+ /**
+ * Save the library's information file.
+ */
+ PMLibraryHandle::PMResult saveLibraryInfo( );
+
+ /**
+ * Create the library's information file.
+ */
+ PMLibraryHandle::PMResult createLibrary( );
+
+ /**
+ * Append a new object to the library.
+ * Returns PMLibraryHandle::Ok if successful or the reason of failure.
+ */
+ PMLibraryHandle::PMResult createNewObject( );
+ /**
+ * Adds an already existing object to the library
+ * @param path The path for the object
+ * @param name The name of the object
+ * @return PMLibraryHandle::Ok if successful or the reason of failure
+ */
+ PMLibraryHandle::PMResult addObject( const QString& path, const QString& name );
+ /**
+ * Deletes an object out of the library. Only removes the entry from the library
+ * doesn't delete the objects file
+ * @param objectName The name of the object ( or objects path ) to delete
+ * @return PMLibraryHandle::Ok if successul or the reason of failure
+ */
+ PMLibraryHandle::PMResult deleteObject( const QString& objectName );
+
+ /**
+ * Create a new sub library.
+ */
+ PMLibraryHandle::PMResult createNewSubLibrary( const QString subLibName );
+ /**
+ * Adds an already existing sub-library to the library
+ * @param path The path for the sub library
+ * @param subLibName The name of the sub library
+ * @return PMLibraryHandle::Ok if successful or the reason of failure
+ */
+ PMLibraryHandle::PMResult addSubLibrary( const QString& path, const QString& name );
+ /**
+ * Deletes a sub library. Only removes the entry from the library
+ * doesn't delete the objects file
+ * @param subLibName The name of the sub library ( or sub libraries path ) to delete
+ * @return PMLibraryHandle::Ok if successul or the reason of failure
+ */
+ PMLibraryHandle::PMResult deleteSubLibrary( const QString& subLibName );
+
+ /**
+ * Returns true if the library is set read-only
+ */
+ bool isReadOnly( ) const { return m_readOnly; }
+
+ /**
+ * Returns an object iterator. It has to be deleted afterwards.
+ */
+ PMLibraryHandle::EntryIterator* createObjectIterator( );
+
+ /**
+ * Returns a sub-library iterator. It has to be deleted afterwards.
+ */
+ PMLibraryHandle::EntryIterator* createSubLibraryIterator( );
+
+ /**
+ * Returns true if the library is a sub library.
+ */
+ bool isSubLibrary( ) const { return m_subLibrary; }
+
+ /**
+ * Changes the parent library if this is a sub library
+ * @param parentPath The new parent path for this library
+ * @return PMLibraryHandle::Ok if successful or the reason for failure
+ */
+ PMLibraryHandle::PMResult changeParentLibrary( const QString& parentPath );
+
+private:
+
+ /**
+ * Makes the library a sub library.
+ */
+ void setSubLibrary( bool isSubLibrary );
+
+
+ void loadLibraryInfo( );
+
+ QString m_name;
+ QString m_path;
+ QString m_author;
+ QString m_description;
+ bool m_readOnly;
+ bool m_subLibrary;
+
+ QDict<QString> m_objects;
+ QDict<QString> m_libraries;
+};
+
+#endif
diff --git a/kpovmodeler/pmlibraryhandleedit.cpp b/kpovmodeler/pmlibraryhandleedit.cpp
new file mode 100644
index 00000000..8c26682d
--- /dev/null
+++ b/kpovmodeler/pmlibraryhandleedit.cpp
@@ -0,0 +1,131 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Luis Carvalho
+ email : lpassos@oninetspeed.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#include "pmlibraryhandleedit.h"
+
+#include <qpushbutton.h>
+#include <qcheckbox.h>
+#include <qlineedit.h>
+#include <qtextedit.h>
+#include <qvbox.h>
+#include <qlayout.h>
+#include <qlabel.h>
+
+#include <klocale.h>
+#include <kconfig.h>
+#include <kmessagebox.h>
+#include <kfiledialog.h>
+
+#include "pmlineedits.h"
+#include "pmdialogeditbase.h"
+#include "pmlibraryhandle.h"
+
+QSize PMLibraryHandleEdit::s_size = QSize( 600, 400 );
+
+PMLibraryHandleEdit::PMLibraryHandleEdit( PMLibraryHandle* lib, QWidget* parent, const char* name )
+ : KDialogBase( parent, name, true, i18n( "Create Library" ),
+ Ok | Cancel, Ok )
+{
+ m_pLibrary = lib;
+
+ resize( s_size );
+ QWidget* page = new QWidget( this );
+ setMainWidget( page );
+ QVBoxLayout* vl = new QVBoxLayout( page, KDialog::spacingHint( ) );
+
+ QGridLayout* grid = new QGridLayout( vl, 5, 2 );
+ QLabel* lbl = new QLabel( i18n( "Name: " ), page );
+ m_pNameEdit = new QLineEdit( page );
+ grid->addWidget( lbl, 0, 0 );
+ grid->addWidget( m_pNameEdit, 0, 1 );
+
+ lbl = new QLabel( i18n( "Author: " ), page );
+ m_pAuthorEdit = new QLineEdit( page );
+ grid->addWidget( lbl, 1, 0 );
+ grid->addWidget( m_pAuthorEdit, 1, 1 );
+
+ lbl = new QLabel( i18n( "Description: " ), page );
+ m_pDescriptionEdit = new QTextEdit( page );
+ m_pDescriptionEdit->setMaximumHeight( 120 );
+ grid->addWidget( lbl, 2, 0 );
+ grid->addMultiCellWidget( m_pDescriptionEdit, 2, 3, 1, 1 );
+ grid->setRowStretch( 3, 1 );
+
+ m_pReadOnlyEdit = new QCheckBox( i18n( "Allow changes to the library?" ), page );
+ grid->addMultiCellWidget( m_pReadOnlyEdit, 4, 4, 0, 1 );
+
+ // Load the fields with values
+ m_pNameEdit->setText( lib->name( ) );
+ m_pDescriptionEdit->setText( lib->description( ) );
+ m_pAuthorEdit->setText( lib->author( ) );
+ m_pReadOnlyEdit->setChecked( !lib->isReadOnly( ) );
+
+ // Setup the signals
+ connect( m_pNameEdit, SIGNAL( textChanged( const QString& ) ), SLOT( slotEditsChanged( const QString& ) ) );
+ connect( m_pAuthorEdit, SIGNAL( textChanged( const QString& ) ), SLOT( slotEditsChanged( const QString& ) ) );
+ connect( m_pDescriptionEdit, SIGNAL( textChanged( ) ), SLOT( slotDescriptionChanged( ) ) );
+ connect( m_pReadOnlyEdit, SIGNAL( clicked( ) ), SLOT( slotReadOnlyChanged( ) ) );
+
+ // On startup you can only cancel
+ enableButtonOK( false );
+}
+
+void PMLibraryHandleEdit::slotReadOnlyChanged( )
+{
+ enableButtonOK( true );
+}
+
+void PMLibraryHandleEdit::slotEditsChanged( const QString& /*str*/ )
+{
+ enableButtonOK( true );
+}
+
+void PMLibraryHandleEdit::slotDescriptionChanged( )
+{
+ enableButtonOK( true );
+}
+
+void PMLibraryHandleEdit::saveConfig( KConfig* cfg )
+{
+ cfg->setGroup( "Appearance" );
+ cfg->writeEntry( "LibraryHandleEditSize", s_size );
+}
+
+void PMLibraryHandleEdit::restoreConfig( KConfig* cfg )
+{
+ cfg->setGroup( "Appearance" );
+
+ QSize defaultSize( 300, 200 );
+ s_size = cfg->readSizeEntry( "LibraryHandleEditSize", &defaultSize );
+}
+
+void PMLibraryHandleEdit::resizeEvent( QResizeEvent* ev )
+{
+ s_size = ev->size( );
+}
+
+void PMLibraryHandleEdit::slotOk( )
+{
+ m_pLibrary->setName( m_pNameEdit->text( ) );
+ m_pLibrary->setAuthor( m_pAuthorEdit->text( ) );
+ m_pLibrary->setDescription( m_pDescriptionEdit->text( ) );
+ m_pLibrary->setReadOnly( !m_pReadOnlyEdit->isChecked( ) );
+
+ accept( );
+}
+
+#include "pmlibraryhandleedit.moc"
diff --git a/kpovmodeler/pmlibraryhandleedit.h b/kpovmodeler/pmlibraryhandleedit.h
new file mode 100644
index 00000000..d0f53bb2
--- /dev/null
+++ b/kpovmodeler/pmlibraryhandleedit.h
@@ -0,0 +1,66 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Luis Carvalho
+ email : lpassos@oninetspeed.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#ifndef PMLIBRARYHANDLEEDIT_H
+#define PMLIBRARYHANDLEEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kdialogbase.h>
+
+class QLineEdit;
+class QTextEdit;
+class QListBox;
+class QCheckBox;
+class PMLibraryHandle;
+
+/**
+ * This class provides a dialog to edit the definitions of a library.
+ */
+class PMLibraryHandleEdit: public KDialogBase
+{
+ Q_OBJECT
+public:
+ /**
+ * Construct a dialog to edit the properties of lib. The library will be
+ * modified only if Ok is pressed.
+ */
+ PMLibraryHandleEdit( PMLibraryHandle* lib, QWidget *parent = NULL, const char* name = NULL );
+
+ static void saveConfig( KConfig* cfg );
+ static void restoreConfig( KConfig* cfg );
+ static QSize s_size;
+
+private slots:
+ void slotOk( );
+ void slotEditsChanged( const QString& );
+ void slotDescriptionChanged( );
+ void slotReadOnlyChanged( );
+ void resizeEvent( QResizeEvent *ev );
+
+private:
+ PMLibraryHandle* m_pLibrary;
+ QLineEdit* m_pNameEdit;
+ QLineEdit* m_pAuthorEdit;
+ QTextEdit* m_pDescriptionEdit;
+ QCheckBox* m_pReadOnlyEdit;
+};
+
+#endif
diff --git a/kpovmodeler/pmlibraryiconview.cpp b/kpovmodeler/pmlibraryiconview.cpp
new file mode 100644
index 00000000..9a59fcda
--- /dev/null
+++ b/kpovmodeler/pmlibraryiconview.cpp
@@ -0,0 +1,328 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Luis Carvalho
+ email : lpassos@oninetspeed.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#include "pmlibraryiconview.h"
+
+#include <unistd.h>
+
+#include <qstring.h>
+#include <qdir.h>
+
+#include <kurl.h>
+#include <kio/job.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+
+#include <stdlib.h>
+
+#include "pmlibraryhandle.h"
+#include "pmlibraryobject.h"
+#include "pmdebug.h"
+
+const char* PMLibraryIconDrag::format( int i ) const
+{
+ switch( i )
+ {
+ case 0:
+ return "application/x-qiconlist";
+ break;
+ case 1:
+ return "text/sublib-list";
+ break;
+ default:
+ return 0;
+ break;
+ }
+}
+
+QByteArray PMLibraryIconDrag::encodedData( const char* mime ) const
+{
+ QByteArray a;
+ if ( QString( mime ) == "application/x-qiconlist" )
+ a = QIconDrag::encodedData( mime );
+ else if ( QString( mime ) == "text/sublib-list" )
+ {
+ QString s , l;
+ for( unsigned i = 0; i < m_paths.count( ); ++i )
+ {
+ if( m_subLibs[i] )
+ l = "true";
+ else
+ l = "false";
+ s += m_paths[i] + "\r" + l + "\n";
+ }
+ a.resize( s.length( ) );
+ memcpy( a.data( ), s.latin1( ), s.length( ) );
+ }
+ return a;
+}
+
+bool PMLibraryIconDrag::canDecode( QMimeSource* e )
+{
+ return e->provides( "application/x-qiconlist" ) ||
+ e->provides( "text/sublib-list" );
+}
+
+bool PMLibraryIconDrag::decode( QMimeSource* e, QStringList& strList, QValueList<bool>& subLibList )
+{
+ QByteArray a = e->encodedData( "text/sublib-list" );
+ if( a.isEmpty( ) )
+ return false;
+
+ QStringList list = QStringList::split( "\n", QString( a ) );
+ for( unsigned i = 0; i < list.count( ); ++i )
+ {
+ strList.append( list[i].section( "\r", 0, 0 ) );
+ if( list[i].section( "\r", 1, 1 ) == "true" )
+ subLibList.append( true );
+ else
+ subLibList.append( false );
+ }
+ return true;
+}
+
+void PMLibraryIconDrag::append( const QIconDragItem &item, const QRect &pr,
+ const QRect &tr, const QString &path, bool isSubLibrary )
+{
+ QIconDrag::append( item, pr, tr );
+ m_paths << path;
+ m_subLibs.append( isSubLibrary );
+}
+
+PMLibraryIconView::PMLibraryIconView( QWidget* parent, const char* name )
+ : KIconView( parent, name )
+{
+ m_pLibrary = NULL;
+ m_pCurrentLibrary = NULL;
+ setSelectionMode( Single );
+ setMode( Execute );
+}
+
+void PMLibraryIconView::setLibrary( PMLibraryHandle* h )
+{
+ m_pLibrary = h;
+ refresh( );
+}
+
+void PMLibraryIconView::refresh( )
+{
+ // Clear all the icons
+ clear( );
+
+ PMLibraryHandle::EntryIterator* it;
+
+ // Scan all the library objects and load them into the view
+ // First let's add the libraries
+ it = m_pLibrary->createSubLibraryIterator( );
+ for( ; it->current( ); ++(*it) )
+ {
+ QString f_name = *( it->current( ) );
+ PMLibraryHandle h( f_name );
+
+ new PMLibraryIconViewItem( this, h.name( ), f_name, true );
+ }
+ delete it;
+
+ // Then the objects
+ it = m_pLibrary->createObjectIterator( );
+ for( ; it->current( ); ++(*it) )
+ {
+ QString f_name = *( it->current( ) );
+ PMLibraryObject obj( f_name );
+
+ if( obj.preview( ) )
+ new PMLibraryIconViewItem( this, obj.name( ), obj.preview( )->copy( ), f_name, false );
+ else
+ new PMLibraryIconViewItem( this, obj.name( ), f_name, false );
+ }
+ delete it;
+}
+
+void PMLibraryIconView::slotDropped( QDropEvent *e, const QValueList<QIconDragItem> & )
+{
+ e->ignore( );
+}
+
+QDragObject* PMLibraryIconView::dragObject( )
+{
+ if ( !currentItem( ) )
+ return 0;
+
+ QPoint orig = viewportToContents( viewport( )->mapFromGlobal( QCursor::pos( ) ) );
+ PMLibraryIconDrag *drag = new PMLibraryIconDrag( viewport( ) );
+ drag->setPixmap( *currentItem( )->pixmap( ),
+ QPoint( currentItem( )->pixmapRect( ).width( ) / 2,
+ currentItem( )->pixmapRect( ).height( ) / 2 ) );
+
+ for ( PMLibraryIconViewItem *item = (PMLibraryIconViewItem*)firstItem( );
+ item; item = ( PMLibraryIconViewItem* )item->nextItem( ) )
+ {
+ if ( item->isSelected( ) )
+ {
+ QIconDragItem id;
+ id.setData( QCString( item->path( ).latin1( ) ) );
+ drag->append( id,
+ QRect( item->pixmapRect( FALSE ).x( ) - orig.x( ),
+ item->pixmapRect( FALSE ).y( ) - orig.y( ),
+ item->pixmapRect( ).width( ),
+ item->pixmapRect( ).height( ) ),
+ QRect( item->textRect( FALSE ).x( ) - orig.x( ),
+ item->textRect( FALSE ).y( ) - orig.y( ),
+ item->textRect().width( ),
+ item->textRect( ).height( ) ),
+ item->path( ),
+ item->isSubLibrary( ) );
+ }
+ }
+ return drag;
+}
+
+PMLibraryIconViewItem::PMLibraryIconViewItem( QIconView *parent, const QString &text, const QString& path, bool isSubLibrary )
+ : KIconViewItem( parent, text )
+{
+ m_path = path;
+ m_isSubLibrary = isSubLibrary;
+}
+
+PMLibraryIconViewItem::PMLibraryIconViewItem( QIconView *parent, const QString &text, const QImage& image, const QString& path, bool isSubLibrary )
+ : KIconViewItem( parent, text, image )
+{
+ m_path = path;
+ m_isSubLibrary = isSubLibrary;
+}
+
+bool PMLibraryIconViewItem::acceptDrop( const QMimeSource *e ) const
+{
+ if ( m_isSubLibrary && e->provides( "text/sublib-list" ) )
+ return true;
+
+ return false;
+}
+
+void PMLibraryIconViewItem::dropped( QDropEvent *e, const QValueList<QIconDragItem> & )
+{
+ QStringList pathList;
+ QValueList<bool> subLibList;
+ if( m_isSubLibrary && PMLibraryIconDrag::decode( e, pathList, subLibList ) )
+ {
+ PMLibraryIconView* source = static_cast<PMLibraryIconView*>( e->source( )->parentWidget( ) );
+ PMLibraryHandle* parentLib = source->library( );
+ PMLibraryHandle newParentLib = PMLibraryHandle( m_path );
+ if ( parentLib->isReadOnly() || newParentLib.isReadOnly() )
+ {
+ e->ignore();
+ return;
+ }
+
+ for( unsigned i = 0; i < pathList.count( ); ++i )
+ {
+ bool success = true;
+ QString path = pathList[i];
+ if( path != ( m_path +"/" + path.section( '/', -1 ) ) )
+ {
+ if( subLibList[i] )
+ {
+ QString newpath = newPath( path, true );
+ if( parentLib->deleteSubLibrary( path ) == PMLibraryHandle::Ok )
+ {
+ PMLibraryHandle lib = PMLibraryHandle( path );
+ if( newParentLib.addSubLibrary( newpath, lib.name() ) == PMLibraryHandle::Ok )
+ {
+ lib.changeParentLibrary( m_path );
+ KIO::move( path, newpath );
+ }
+ else
+ {
+ success = false;
+ parentLib->addSubLibrary( path, lib.name( ) );
+ }
+ }
+ else
+ success = false;
+ }
+ else
+ {
+ QString newpath = newPath( path, false );
+ if( parentLib->deleteObject( path ) == PMLibraryHandle::Ok )
+ {
+ PMLibraryObject obj = PMLibraryObject( path );
+ if( newParentLib.addObject( newpath, obj.name() ) == PMLibraryHandle::Ok )
+ {
+ KIO::move( path, newpath );
+ }
+ else
+ {
+ success = false;
+ parentLib->addObject( path, obj.name( ) );
+ }
+ }
+ else
+ success = false;
+ }
+
+ if( !success )
+ {
+ KMessageBox::error( 0, i18n( "Error moving \"%1\" to \"%2\"" ).arg( path ).arg( m_path ) );
+ e->ignore( );
+ return;
+ }
+ }
+ }
+ e->acceptAction( );
+ source->refresh( );
+ }
+ else
+ {
+ e->ignore( );
+ }
+}
+
+QString PMLibraryIconViewItem::newPath( const QString oldPath, bool /*subLib*/ )
+{
+ /// @todo Need to replace mkdtemp and mkstemps before enabling libs
+ return oldPath;
+ /*
+ QString path = m_path + "/" + oldPath.section( '/', -1 );
+ if( subLib )
+ {
+ QString test = path + "/library_index.xml";
+ if( QFile::exists( test ) )
+ {
+ QCString s = m_path.latin1();
+ s+= "/libXXXXXX";
+ char* dirname = mkdtemp( s.data() );
+ rmdir( dirname );
+ path = dirname;
+ }
+ }
+ else if( QFile::exists( path ) )
+ {
+ // we need to rename it.
+ QCString s = m_path.latin1();
+ s += "/objXXXXXX.kpml";
+ int fh = mkstemps( s.data( ), 5 );
+ close( fh );
+ unlink( s.data() );
+ path = s;
+ }
+
+ return path;
+ */
+}
+
+#include "pmlibraryiconview.moc"
diff --git a/kpovmodeler/pmlibraryiconview.h b/kpovmodeler/pmlibraryiconview.h
new file mode 100644
index 00000000..a30ef529
--- /dev/null
+++ b/kpovmodeler/pmlibraryiconview.h
@@ -0,0 +1,123 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Luis Carvalho
+ email : lpassos@oninetspeed.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#ifndef PMLIBRARYICONVIEW_H
+#define PMLIBRARYICONVIEW_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kiconview.h>
+
+class PMLibraryHandle;
+
+/**
+ * This class is the drag and drop object for the icon view
+ */
+class PMLibraryIconDrag : public QIconDrag
+{
+ Q_OBJECT
+public:
+ /** Constructor */
+ PMLibraryIconDrag( QWidget * dragSource, const char* name = 0 ) : QIconDrag( dragSource, name ) {}
+
+ /** @return The ith format, or NULL. */
+ const char* format( int i ) const;
+ /** @return The encoded payload of this object, in the specified MIME format. */
+ QByteArray encodedData( const char* mime ) const;
+ /** @return True if the information in e can be decoded */
+ static bool canDecode( QMimeSource* e );
+ /**
+ * Attempts to decode the data in e
+ * @return True if successful otherwise returns false
+ */
+ static bool decode( QMimeSource* e, QStringList& StrList, QValueList<bool>& subLibList );
+ /** Adds a item to the object */
+ void append( const QIconDragItem &item, const QRect &pr, const QRect &tr, const QString &path, bool subLib );
+
+private:
+ QStringList m_paths;
+ QValueList<bool> m_subLibs;
+};
+
+/**
+ * This class provides a view to browse objects, showing their previews.
+ */
+class PMLibraryIconView: public KIconView
+{
+ Q_OBJECT
+public:
+ PMLibraryIconView( QWidget *parent, const char* name = NULL );
+
+ /**
+ * Set the library base path
+ */
+ void setLibrary( PMLibraryHandle* h );
+ /**
+ * Returns the library in view
+ */
+ PMLibraryHandle* library( ) const { return m_pLibrary; }
+
+public slots:
+ /**
+ * refresh the icon view
+ */
+ void refresh( );
+
+ /** called when an Item is dropped onto the view */
+ void slotDropped( QDropEvent *e, const QValueList<QIconDragItem>& );
+
+protected:
+ /** @return a QDragObject for drag and drop */
+ virtual QDragObject* dragObject( );
+
+private:
+ PMLibraryHandle *m_pLibrary;
+ PMLibraryHandle *m_pCurrentLibrary;
+};
+
+/**
+ * This class holds a library object's icon. It also remembers the path
+ * where the file is.
+ */
+class PMLibraryIconViewItem: public KIconViewItem
+{
+public:
+ PMLibraryIconViewItem( QIconView *parent, const QString& text, const QString& path, bool isSubLibrary );
+ PMLibraryIconViewItem( QIconView *parent, const QString& text, const QImage& image, const QString& path, bool isSubLibrary );
+
+ /** Get the path of the entry */
+ QString path( ) const { return m_path; }
+ /** Is the entry a sublib library? */
+ bool isSubLibrary( ) const { return m_isSubLibrary; }
+ /** Reimplement accept drop to take items */
+ virtual bool acceptDrop( const QMimeSource *mime ) const;
+
+protected:
+ /** Tokes a dropped item */
+ void dropped( QDropEvent *evt, const QValueList<QIconDragItem>& );
+ /** Checks for the existance of oldpath and generates a new path as required */
+ QString newPath( const QString oldPath, bool subLib );
+
+private:
+ QString m_path;
+ bool m_isSubLibrary;
+};
+
+#endif
diff --git a/kpovmodeler/pmlibrarymanager.cpp b/kpovmodeler/pmlibrarymanager.cpp
new file mode 100644
index 00000000..2caeb6e3
--- /dev/null
+++ b/kpovmodeler/pmlibrarymanager.cpp
@@ -0,0 +1,121 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Luis Carvalho
+ email : lpassos@oninetspeed.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#include "pmlibrarymanager.h"
+
+#include <kconfig.h>
+#include <kstandarddirs.h>
+#include <kglobal.h>
+
+#include <qfile.h>
+#include <qdir.h>
+
+#include "pmdebug.h"
+
+PMLibraryManager* PMLibraryManager::s_pInstance = 0;
+KStaticDeleter<PMLibraryManager> PMLibraryManager::s_staticDeleter;
+
+PMLibraryHandle* PMLibraryManager::getLibraryHandle( const QString& libraryName )
+{
+ QPtrListIterator<PMLibraryHandle> it( m_libraries );
+
+ for( ; it.current( ); ++it )
+ if( it.current( )->name( ) == libraryName )
+ return it.current( );
+
+ return NULL;
+}
+
+PMLibraryManager::PMLibraryManager( )
+{
+ m_libraries.setAutoDelete( true );
+ scanLibraries( );
+}
+
+PMLibraryManager::~PMLibraryManager( )
+{
+ m_libraries.clear( );
+}
+
+void PMLibraryManager::saveConfig( KConfig* /*cfg*/ )
+{
+}
+
+void PMLibraryManager::restoreConfig( KConfig* /*cfg*/ )
+{
+}
+
+QValueList<QString> PMLibraryManager::availableLibraries( )
+{
+ QValueList<QString> result;
+ QPtrListIterator<PMLibraryHandle> it( m_libraries );
+
+ for( ; it.current( ); ++it )
+ result.push_back( it.current( )->name( ) );
+
+ return result;
+}
+
+PMLibraryManager* PMLibraryManager::theManager( )
+{
+ if( !s_pInstance )
+ s_staticDeleter.setObject( s_pInstance, new PMLibraryManager( ) );
+ return s_pInstance;
+}
+
+void PMLibraryManager::scanLibraries( )
+{
+ QStringList libraryDirectories;
+
+ // Search for sub directories in /usr/share/kpovmodeler/library
+ libraryDirectories = KGlobal::dirs( )->findDirs( "data", "kpovmodeler/library" );
+
+ for( QStringList::Iterator i = libraryDirectories.begin( ); i != libraryDirectories.end( ); ++i )
+ {
+ QDir curDir( *i );
+ curDir.setFilter( QDir::Dirs );
+ QFileInfoListIterator it( *( curDir.entryInfoList( ) ) );
+
+ // For each sub directory
+ QFileInfo* fi;
+ for( ; ( fi = it.current( ) ) != NULL; ++it )
+ {
+ // check for the existance of library_index.xml
+ // If it's there it's a library
+ if( QFile::exists( fi->absFilePath( ) + "/library_index.xml" ) )
+ {
+ // Create the corresponding PMLibraryHandle
+ PMLibraryHandle* h;
+
+ h = new PMLibraryHandle( fi->absFilePath( ) );
+ if( !getLibraryHandle( h->name( ) ) )
+ m_libraries.append( h );
+ else
+ // a library with that name already exists
+ delete h;
+ }
+ }
+ }
+}
+
+void PMLibraryManager::refresh( )
+{
+ // TODO: Manage the list incrementaly so that previouly handed out
+ // PMLibraryHandle pointers are kept valid
+ m_libraries.clear( );
+ scanLibraries( );
+}
diff --git a/kpovmodeler/pmlibrarymanager.h b/kpovmodeler/pmlibrarymanager.h
new file mode 100644
index 00000000..8221ba19
--- /dev/null
+++ b/kpovmodeler/pmlibrarymanager.h
@@ -0,0 +1,97 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Luis Carvalho
+ email : lpassos@oninetspeed.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#ifndef PMLIBRARYMANAGER_H
+#define PMLIBRARYMANAGER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qstring.h>
+#include <qmap.h>
+#include <qptrlist.h>
+#include <qvaluelist.h>
+#include <kstaticdeleter.h>
+
+#include "pmlibraryhandle.h"
+
+class KConfig;
+class QDomElement;
+
+/**
+ * Class that maintains the list of available libraries for kpovmodeler
+ *
+ * This class is a singleton, wich means all libraries will be known to
+ * all instances of the application.
+ *
+ * When the class is initialized, the following steps are taken:
+ * 1. The global kpovmodeler library path is scanned for libraries
+ * 2. The users' kpovmodeler library path is also scanned for libraries
+ *
+ * If more than one library has the same name, only the last one will be
+ * accessible.
+ */
+class PMLibraryManager
+{
+
+public:
+ /**
+ * Destructor
+ */
+ ~PMLibraryManager( );
+ /**
+ * Returns the manager instance (singleton)
+ */
+ static PMLibraryManager* theManager( );
+
+ /**
+ * Returns the list of available libraries
+ */
+ QValueList<QString> availableLibraries( );
+
+ /**
+ * Returns the handle for the indicated library
+ */
+ PMLibraryHandle* getLibraryHandle( const QString& libraryName );
+
+ /**
+ * Refreshes the list of libraries.
+ * WARNING: This function invalidates all previously given PMLibraryHandle pointers
+ */
+ void refresh( );
+
+ void saveConfig( KConfig* cfg );
+ void restoreConfig( KConfig* cfg );
+
+private:
+
+ /**
+ * Constructor
+ */
+ PMLibraryManager( );
+
+ void scanLibraries( );
+
+ QPtrList< PMLibraryHandle > m_libraries;
+
+ static PMLibraryManager* s_pInstance;
+ static KStaticDeleter<PMLibraryManager> s_staticDeleter;
+};
+
+#endif
diff --git a/kpovmodeler/pmlibraryobject.cpp b/kpovmodeler/pmlibraryobject.cpp
new file mode 100644
index 00000000..e84ba9e1
--- /dev/null
+++ b/kpovmodeler/pmlibraryobject.cpp
@@ -0,0 +1,331 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#include "pmlibraryobject.h"
+
+#include <qstring.h>
+#include <qvaluelist.h>
+#include <qdom.h>
+#include <qbuffer.h>
+#include <qimage.h>
+
+#include <karchive.h>
+#include <kurl.h>
+#include <ktar.h>
+#include <kfilterdev.h>
+
+#include <stdlib.h>
+
+#include "pmdebug.h"
+
+PMLibraryObject::PMLibraryObject( )
+{
+ m_previewLoaded = false;
+ m_objectsLoaded = false;
+ m_preview = NULL;
+ m_objects = NULL;
+ m_data = NULL;
+ m_name = QString::null;
+ m_description = QString::null;
+ m_keywords = QString::null;
+}
+
+PMLibraryObject::PMLibraryObject( KURL u )
+{
+ m_previewLoaded = false;
+ m_objectsLoaded = false;
+ m_preview = NULL;
+ m_objects = NULL;
+ m_data = new KTar( u.path( ), "application/x-gzip" );
+ loadLibraryInfo( );
+}
+
+PMLibraryObject::~PMLibraryObject( )
+{
+ delete m_data;
+ if( m_previewLoaded )
+ delete m_preview;
+ if( m_objectsLoaded )
+ delete m_objects;
+}
+
+void PMLibraryObject::loadLibraryInfo( )
+{
+ if( m_data )
+ {
+ m_data->open( IO_ReadOnly );
+ // Position in the root of the file
+ const KArchiveDirectory* root = m_data->directory( );
+ if( !root )
+ return;
+
+ // Find the object info
+ const KArchiveEntry* entry = root->entry( "objectinfo.xml" );
+ if( entry && entry->isFile( ) )
+ {
+ QBuffer buffer( ( ( KArchiveFile* )entry )->data( ) );
+ buffer.open( IO_ReadOnly );
+
+ QDomDocument doc( "OBJECTINFO" );
+ doc.setContent( &buffer );
+
+ QDomElement e = doc.documentElement( );
+ m_name = e.attribute( "name", "empty" );
+
+ QDomNode c = e.firstChild( );
+ while( !c.isNull( ) )
+ {
+ if( c.isElement( ) )
+ {
+ QDomElement ce = c.toElement( );
+ // Description information
+ if( ce.tagName( ) == "description" )
+ {
+ QDomText te = ce.firstChild( ).toText( );
+ m_description = te.nodeValue( );
+ }
+ // Keywords information
+ else if( ce.tagName( ) == "keywords" )
+ {
+ QDomText te = ce.firstChild( ).toText( );
+ m_keywords = te.nodeValue( );
+ }
+ // Extra files list
+ else if( ce.tagName( ) == "file_entries" )
+ {
+ QDomNode entry = ce.firstChild( );
+ while( !entry.isNull( ) )
+ {
+ QDomElement entryElement = entry.toElement( );
+ if( entryElement.tagName( ) == "file" )
+ m_extraFiles.append( entryElement.attribute( "name", "" ) );
+ entry = entry.nextSibling( );
+ }
+ }
+ }
+ c = c.nextSibling( );
+ }
+ }
+ m_data->close( );
+ }
+}
+
+QImage* PMLibraryObject::preview( )
+{
+ if( !m_previewLoaded )
+ {
+ if( m_data )
+ {
+ m_data->open( IO_ReadOnly );
+ // Position in the root of the file
+ const KArchiveDirectory* root = m_data->directory( );
+ if( !root )
+ return NULL;
+
+ // Find the object preview
+ const KArchiveEntry* entry = root->entry( "preview.png" );
+ if( entry && entry->isFile( ) )
+ {
+ QBuffer buffer( ( ( KArchiveFile* )entry )->data( ) );
+ buffer.open( IO_ReadOnly );
+ m_preview = new QImage( buffer.readAll( ) );
+ m_previewLoaded = true;
+ }
+
+ m_data->close( );
+ }
+ }
+ return m_preview;
+}
+
+QByteArray* PMLibraryObject::objects( )
+{
+ if( !m_objectsLoaded )
+ {
+ if( m_data )
+ {
+ m_data->open( IO_ReadOnly );
+ // Position in the root of the file
+ const KArchiveDirectory* root = m_data->directory( );
+ if( !root )
+ return NULL;
+
+ // Find the object info
+ const KArchiveEntry* entry = root->entry( "objectdata.kpm" );
+ if( entry && entry->isFile( ) )
+ {
+ // Transfer the file contents to a QByteArray.
+ // TODO Maybe there is a smarter way of doing this.
+ char buf[256];
+ int nbytes;
+ QIODevice* aux_in = ( ( KArchiveFile* )entry )->device( );
+
+ m_objects = new QByteArray( );
+ QBuffer aux_out( *m_objects );
+
+ aux_in->open( IO_ReadOnly );
+ aux_out.open( IO_WriteOnly );
+ while( !aux_in->atEnd( ) )
+ {
+ nbytes = aux_in->readBlock( buf, 256 );
+ aux_out.writeBlock( buf, nbytes );
+ }
+ delete aux_in;
+ if( m_objects->size( ) != 0 )
+ m_objectsLoaded = true;
+ else
+ {
+ delete m_objects;
+ m_objects = NULL;
+ }
+ }
+ }
+ }
+ return m_objects;
+}
+
+void PMLibraryObject::setName( const QString& str )
+{
+ m_name = str;
+}
+
+void PMLibraryObject::setDescription( const QString& str )
+{
+ m_description = str;
+}
+
+void PMLibraryObject::setKeywords( const QString& str )
+{
+ m_keywords = str;
+}
+
+void PMLibraryObject::setPreview( const QImage& img )
+{
+ if( m_previewLoaded )
+ delete m_preview;
+
+ m_preview = new QImage( img );
+ m_previewLoaded = true;
+}
+
+void PMLibraryObject::setObjects( const QByteArray& obj )
+{
+ if( m_objectsLoaded )
+ delete m_objects;
+
+ m_objects = new QByteArray( obj );
+ m_objects->detach( );
+ m_objectsLoaded = true;
+}
+
+void PMLibraryObject::save( const QString& fileName )
+{
+ // create the library file
+ m_data = new KTar( fileName, "application/x-gzip" );
+ m_data->open( IO_WriteOnly );
+ // save object info
+ saveLibraryInfo( );
+ // save preview
+ savePreview( );
+ // save library objects
+ saveObjects( );
+ m_data->close( );
+}
+
+void PMLibraryObject::saveLibraryInfo( )
+{
+ // Pre-condition for the execution of this method.
+ if( !m_data || !m_data->isOpened( ) )
+ {
+ kdError( PMArea ) << "Trying to save to an unopened data file." << endl;
+ exit( 1 );
+ }
+
+ QBuffer buf;
+
+ // Document type
+ QDomDocument doc( "OBJECTINFO" );
+
+ // The root element for the document has one attribute: name
+ QDomElement root = doc.createElement( "object" );
+ doc.appendChild( root );
+ root.setAttribute( "name", m_name );
+
+ // Inside the root element we add the description node ...
+ QDomElement description = doc.createElement( "description" );
+ root.appendChild( description );
+ description.appendChild( doc.createTextNode( m_description ) );
+
+ // ... and the keywords node ...
+ QDomElement keywords = doc.createElement( "keywords" );
+ root.appendChild( keywords );
+ keywords.appendChild( doc.createTextNode( m_keywords ) );
+
+ // ... and finally the extra files information
+ QDomElement file_list = doc.createElement( "file_list" );
+ root.appendChild( file_list );
+ QStringList::Iterator it = m_extraFiles.begin( );
+ for( ; it != m_extraFiles.end( ); ++it )
+ {
+ QDomElement entry = doc.createElement( "file" );
+ entry.setAttribute( "name", *it );
+ file_list.appendChild( entry );
+ }
+
+ // Write the document to the buffer
+ QByteArray array;
+ QTextStream str( array, IO_WriteOnly );
+ str.setEncoding( QTextStream::UnicodeUTF8 );
+ str << doc.toString( );
+ m_data->writeFile( "objectinfo.xml", "user", "group", array.size( ), array.data( ) );
+}
+
+void PMLibraryObject::savePreview( )
+{
+ // Pre-condition for the execution of this method.
+ if( !m_data || !m_data->isOpened( ) )
+ {
+ kdError( PMArea ) << "Trying to save to an unopened data file." << endl;
+ exit( 1 );
+ }
+
+ QByteArray array;
+ QBuffer iods( array );
+ QImageIO img_io( &iods, "PNG" );
+
+ if( m_previewLoaded )
+ {
+ img_io.setImage( *m_preview );
+ iods.open( IO_WriteOnly );
+ img_io.write( );
+ m_data->writeFile( "preview.png", "user", "group", array.size( ), array.data( ) );
+ }
+}
+
+void PMLibraryObject::saveObjects( )
+{
+ // Pre-condition for the execution of this method.
+ if( !m_data || !m_data->isOpened( ) )
+ {
+ kdError( PMArea ) << "Trying to save to an unopened data file." << endl;
+ exit( 1 );
+ }
+
+ if( m_objectsLoaded )
+ m_data->writeFile( "objectdata.kpm", "user", "group", m_objects->size( ), m_objects->data( ) );
+}
diff --git a/kpovmodeler/pmlibraryobject.h b/kpovmodeler/pmlibraryobject.h
new file mode 100644
index 00000000..e3699c8f
--- /dev/null
+++ b/kpovmodeler/pmlibraryobject.h
@@ -0,0 +1,136 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#ifndef PMLIBRARYOBJECT_H
+#define PMLIBRARYOBJECT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qstring.h>
+#include <qmap.h>
+#include <qvaluelist.h>
+#include <kstaticdeleter.h>
+#include <qstringlist.h>
+
+class KURL;
+class KArchive;
+class KTar;
+class QImage;
+
+/**
+ * This class implements a library object.
+ *
+ * A library object has a name, a textual description, a graphical
+ * preview and the object data, of course. It also contains a collection of
+ * keywords.
+ *
+ * When an instance of PMLibraryObject is created, the objects description is
+ * loaded.
+ *
+ * The graphical preview and the objects data are loaded only if needed.
+ *
+ */
+class PMLibraryObject
+{
+public:
+ /**
+ * Constructor for the library object. Creates an empty library object.
+ */
+ PMLibraryObject( );
+ /**
+ * Constructor for the library object.
+ * Loads the object data from the specified library object file.
+ */
+ PMLibraryObject( KURL u );
+ /**
+ * Destructor
+ */
+ ~PMLibraryObject( );
+
+ /**
+ * Name of the library object.
+ */
+ QString name( ) const { return m_name; }
+ /**
+ * Textual description of the library object.
+ */
+ QString description( ) const { return m_description; }
+ /**
+ * List of keywords for search of the library object.
+ */
+ QString keywords( ) const { return m_keywords; }
+ /**
+ * Graphical Preview.
+ */
+ QImage* preview( );
+ /**
+ * True is the preview has been loaded.
+ */
+ bool isPreviewLoaded( ) const { return m_previewLoaded; }
+ /**
+ * Objects for the scene
+ */
+ QByteArray* objects( );
+ bool areObjectsLoaded( ) const { return m_objectsLoaded; }
+
+ /**
+ * Set the library object name
+ */
+ void setName( const QString& str );
+ /**
+ * Set the library object description
+ */
+ void setDescription( const QString& str );
+ /**
+ * Set the library object keywords
+ */
+ void setKeywords( const QString& str );
+ /**
+ * Set the preview image
+ */
+ void setPreview( const QImage& img );
+ /**
+ * Set the object data
+ */
+ void setObjects( const QByteArray& obj );
+
+ /**
+ * Save the library object to a file
+ */
+ void save( const QString& fileName );
+
+private:
+ void loadLibraryInfo( );
+ void saveLibraryInfo( );
+ void savePreview( );
+ void saveObjects( );
+
+ bool m_previewLoaded;
+ bool m_objectsLoaded;
+ QString m_name;
+ QString m_description;
+ QString m_keywords;
+ KTar* m_data;
+ QImage* m_preview;
+ QByteArray* m_objects;
+ QStringList m_extraFiles;
+};
+
+#endif
diff --git a/kpovmodeler/pmlibraryobjectsearch.cpp b/kpovmodeler/pmlibraryobjectsearch.cpp
new file mode 100644
index 00000000..428da887
--- /dev/null
+++ b/kpovmodeler/pmlibraryobjectsearch.cpp
@@ -0,0 +1,86 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmlibraryobject.h"
+#include "pmlibraryentrypreview.h"
+#include "pmlibraryobjectsearch.h"
+#include "pmdialogeditbase.h"
+
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+#include <qlayout.h>
+#include <qpixmap.h>
+#include <qimage.h>
+#include <qframe.h>
+
+#include <kurl.h>
+#include <klocale.h>
+#include <kdialog.h>
+#include <klistview.h>
+
+PMLibraryObjectSearch::PMLibraryObjectSearch( QWidget* parent ) :
+ QWidget( parent, "" )
+{
+ setMinimumSize( 780, 300 );
+ setMaximumSize( 800, 400 );
+ QVBoxLayout* vl = new QVBoxLayout( this, KDialog::spacingHint( ) );
+
+ // Search parameters
+ QFrame* frame = new QFrame( this );
+ QHBoxLayout* fhl = new QHBoxLayout( frame, KDialog::spacingHint( ) );
+ QGridLayout* grid = new QGridLayout( fhl, 3, 2 );
+ QLabel *lbl = new QLabel( i18n( "Search for:" ), frame );
+ m_pSearch = new QLineEdit( frame );
+ grid->addWidget( lbl, 0, 0 );
+ grid->addWidget( m_pSearch, 0, 1 );
+
+ QVBoxLayout* fvl = new QVBoxLayout( fhl );
+ m_pSearchButton = new QPushButton( i18n( "&Search" ), frame );
+ fvl->addWidget( m_pSearchButton );
+ fvl->addStretch( 1 );
+
+ vl->addWidget( frame );
+
+ // Search results
+ frame = new QFrame( this );
+ QHBoxLayout* hl = new QHBoxLayout( frame, KDialog::spacingHint( ) );
+ m_pFileList = new KListView( frame );
+ m_pFileList->addColumn( i18n( "File" ) );
+ m_pFileList->addColumn( i18n( "Path" ) );
+ m_pFileList->setFullWidth( true );
+ m_pPreview = new PMLibraryEntryPreview( frame );
+ hl->addWidget( m_pFileList, 1 );
+ hl->addWidget( m_pPreview );
+ vl->addWidget( frame );
+
+ // Connect signals and slots
+ connect( m_pSearchButton, SIGNAL( clicked( ) ), SLOT( slotSearchButtonPressed( ) ) );
+}
+
+void PMLibraryObjectSearch::slotSearchButtonPressed( )
+{
+// QStringList::Iterator it( s_libraryPath );
+ // For each of the defined libraries
+ //
+ // Open recursively each library file
+ // Check if any of the strings contains the search words
+ // If it does add to the list
+}
+
+#include "pmlibraryobjectsearch.moc"
diff --git a/kpovmodeler/pmlibraryobjectsearch.h b/kpovmodeler/pmlibraryobjectsearch.h
new file mode 100644
index 00000000..2ef5b07a
--- /dev/null
+++ b/kpovmodeler/pmlibraryobjectsearch.h
@@ -0,0 +1,55 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#ifndef PMLIBRARYOBJECTSEARCH_H
+#define PMLIBRARYOBJECTSEARCH_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qwidget.h>
+
+class QLineEdit;
+class QListBox;
+class QPushButton;
+class PMLibraryEntryPreview;
+class KListView;
+
+/**
+ * Search widget for Library Objects.
+ * It also provides drag. If the user doesn't have a clear idea
+ * where the objects he wants are, this is the dialog to use.
+ */
+class PMLibraryObjectSearch: public QWidget
+{
+ Q_OBJECT
+public:
+ PMLibraryObjectSearch( QWidget *parent );
+
+private slots:
+ void slotSearchButtonPressed( );
+
+private:
+ QLineEdit* m_pSearch;
+ QPushButton* m_pSearchButton;
+ KListView* m_pFileList;
+ PMLibraryEntryPreview* m_pPreview;
+};
+
+#endif
diff --git a/kpovmodeler/pmlight.cpp b/kpovmodeler/pmlight.cpp
new file mode 100644
index 00000000..b715c7ee
--- /dev/null
+++ b/kpovmodeler/pmlight.cpp
@@ -0,0 +1,1064 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmlight.h"
+
+#include "pmxmlhelper.h"
+#include "pmlightedit.h"
+#include "pmmemento.h"
+#include "pmviewstructure.h"
+#include "pm3dcontrolpoint.h"
+#include "pmmath.h"
+#include "pmmatrix.h"
+#include "pmenumproperty.h"
+
+#include <klocale.h>
+
+const PMVector locationDefault = PMVector( 0, 0, 0 );
+const PMColor colorDefault = PMColor( 1.0, 1.0, 1.0 );
+const double radiusDefault = 70.0;
+const double falloffDefault = 70.0;
+const double tightnessDefault = 10;
+const PMVector pointAtDefault = PMVector( 0, 0, 1 );
+const bool parallelDefault = false;
+const PMVector areaAxis1Default = PMVector( 1, 0, 0 );
+const PMVector areaAxis2Default = PMVector( 0, 1, 0 );
+const int areaSize1Default = 3;
+const int areaSize2Default = 3;
+const int adaptiveDefault = 0;
+const bool orientDefault = false;
+const bool jitterDefault = false;
+const int fadePowerDefault = 1;
+const double fadeDistanceDefault = 10.0;
+
+PMViewStructure* PMLight::s_pDefaultPointStructure = 0;
+PMViewStructure* PMLight::s_pDefaultSpotStructure = 0;
+PMViewStructure* PMLight::s_pDefaultCylindricalStructure = 0;
+double PMLight::s_pointLightSize = 0.25;
+int PMLight::s_nCylinderLines = 8;
+int PMLight::s_nSpotLines = 8;
+double PMLight::s_length = 1.0;
+
+PMDefinePropertyClass( PMLight, PMLightProperty );
+PMDefineEnumPropertyClass( PMLight, PMLight::PMLightType, PMTypeProperty );
+PMDefineEnumPropertyClass( PMLight, PMLight::PMAreaType, PMAreaProperty );
+
+PMMetaObject* PMLight::s_pMetaObject = 0;
+PMObject* createNewLight( PMPart* part )
+{
+ return new PMLight( part );
+}
+
+PMLight::PMLight( PMPart* part )
+ : Base( part )
+{
+ m_location = locationDefault;
+ m_color = colorDefault;
+ m_type = PointLight;
+ m_radius = radiusDefault;
+ m_falloff = falloffDefault;
+ m_tightness = tightnessDefault;
+ m_pointAt = pointAtDefault;
+ m_parallel = parallelDefault;
+ m_bAreaLight = false;
+ m_areaType = Rectangular;
+ m_areaAxis1 = areaAxis1Default;
+ m_areaAxis2 = areaAxis2Default;
+ m_areaSize1 = areaSize1Default;
+ m_areaSize2 = areaSize2Default;
+ m_adaptive = adaptiveDefault;
+ m_orient = orientDefault;
+ m_jitter = jitterDefault;
+ m_bFading = false;
+ m_fadeDistance = fadeDistanceDefault;
+ m_fadePower = fadePowerDefault;
+ m_bMediaInteraction = true;
+ m_bMediaAttenuation = true;
+}
+
+PMLight::PMLight( const PMLight& l )
+ : Base( l )
+{
+ m_location = l.m_location;
+ m_color = l.m_color;
+ m_type = l.m_type;
+ m_radius = l.m_radius;
+ m_falloff = l.m_falloff;
+ m_tightness = l.m_tightness;
+ m_pointAt = l.m_pointAt;
+ m_parallel = l.m_parallel;
+ m_bAreaLight = l.m_bAreaLight;
+ m_areaType = l.m_areaType;
+ m_areaAxis1 = l.m_areaAxis1;
+ m_areaAxis2 = l.m_areaAxis2;
+ m_areaSize1 = l.m_areaSize1;
+ m_areaSize2 = l.m_areaSize2;
+ m_adaptive = l.m_adaptive;
+ m_orient = l.m_orient;
+ m_jitter = l.m_jitter;
+ m_bFading = l.m_bFading;
+ m_fadeDistance = l.m_fadeDistance;
+ m_fadePower = l.m_fadePower;
+ m_bMediaInteraction = l.m_bMediaInteraction;
+ m_bMediaAttenuation = l.m_bMediaAttenuation;
+}
+
+PMLight::~PMLight( )
+{
+}
+
+QString PMLight::description( ) const
+{
+ return i18n( "light" );
+}
+
+void PMLight::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "location", m_location.serializeXML( ) );
+ e.setAttribute( "color", m_color.serializeXML( ) );
+
+ switch( m_type )
+ {
+ case SpotLight:
+ e.setAttribute( "lighttype", "spotlight" );
+ break;
+ case CylinderLight:
+ e.setAttribute( "lighttype", "cylinder" );
+ break;
+ case ShadowlessLight:
+ e.setAttribute( "lighttype", "shadowless" );
+ break;
+ case PointLight:
+ e.setAttribute( "lighttype", "point" );
+ break;
+ }
+
+ if( ( m_type == SpotLight ) || ( m_type == CylinderLight ) )
+ {
+ e.setAttribute( "radius", m_radius );
+ e.setAttribute( "falloff", m_falloff );
+ e.setAttribute( "tightness", m_tightness );
+ e.setAttribute( "point_at", m_pointAt.serializeXML( ) );
+ }
+
+ if ( m_parallel )
+ e.setAttribute( "parallel", "1" );
+ else
+ e.setAttribute( "parallel", "0" );
+
+ if( m_bAreaLight )
+ {
+ if ( m_areaType == Rectangular )
+ e.setAttribute( "areatype", "rectangular" );
+ else
+ e.setAttribute( "areatype", "circular" );
+
+ e.setAttribute( "area_light", "1" );
+ e.setAttribute( "area_light_a", m_areaAxis1.serializeXML( ) );
+ e.setAttribute( "area_light_b", m_areaAxis2.serializeXML( ) );
+ e.setAttribute( "area_size_a", m_areaSize1 );
+ e.setAttribute( "area_size_b", m_areaSize2 );
+ e.setAttribute( "adaptive", m_adaptive );
+
+ if( m_orient )
+ e.setAttribute( "orient", "1" );
+ else
+ e.setAttribute( "orient", "0" );
+
+ if( m_jitter )
+ e.setAttribute( "jitter", "1" );
+ else
+ e.setAttribute( "jitter", "0" );
+ }
+ else
+ e.setAttribute( "area_light", "0" );
+
+ if( m_bFading )
+ {
+ e.setAttribute( "fading", "1" );
+ e.setAttribute( "fade_distance" , m_fadeDistance );
+ e.setAttribute( "fade_power", m_fadePower );
+ }
+ else
+ e.setAttribute( "fading", "0" );
+
+ if( m_bMediaInteraction )
+ e.setAttribute( "media_interaction", "1" );
+ else
+ e.setAttribute( "media_interaction", "0" );
+
+ if( m_bMediaAttenuation )
+ e.setAttribute( "media_attenuation", "1" );
+ else
+ e.setAttribute( "media_attenuation", "0" );
+
+ Base::serialize( e, doc );
+}
+
+void PMLight::readAttributes( const PMXMLHelper& h )
+{
+ QString str;
+
+ m_location = h.vectorAttribute( "location", locationDefault );
+ m_color = h.colorAttribute( "color", colorDefault );
+
+ str = h.stringAttribute( "lighttype", "point" );
+ if( str == "point" )
+ m_type = PointLight;
+ else if( str == "spotlight" )
+ m_type = SpotLight;
+ else if( str == "cylinder" )
+ m_type = CylinderLight;
+ else if( str == "shadowless" )
+ m_type = ShadowlessLight;
+ else
+ m_type = PointLight;
+
+ if( ( m_type == SpotLight ) || ( m_type == CylinderLight ) )
+ {
+ m_radius = h.doubleAttribute( "radius", radiusDefault );
+ m_falloff = h.doubleAttribute( "falloff", falloffDefault );
+ m_tightness = h.doubleAttribute( "tightness", tightnessDefault );
+ m_pointAt = h.vectorAttribute( "point_at", pointAtDefault );
+ }
+
+ m_parallel = h.boolAttribute( "parallel", parallelDefault );
+
+ m_bAreaLight = h.boolAttribute( "area_light", false );
+ if( m_bAreaLight )
+ {
+ str = h.stringAttribute( "areatype", "rectangular" );
+ if ( str == "circular" )
+ m_areaType = Circular;
+ else
+ m_areaType = Rectangular;
+
+ m_areaAxis1 = h.vectorAttribute( "area_light_a", areaAxis1Default );
+ m_areaAxis2 = h.vectorAttribute( "area_light_b", areaAxis2Default );
+ m_areaSize1 = h.intAttribute( "area_size_a", areaSize1Default );
+ m_areaSize2 = h.intAttribute( "area_size_b", areaSize2Default );
+ m_adaptive = h.intAttribute( "adaptive", adaptiveDefault );
+ m_orient = h.boolAttribute( "orient", orientDefault );
+ m_jitter = h.boolAttribute( "jitter", jitterDefault );
+ }
+ m_bFading = h.boolAttribute( "fading", false );
+ if( m_bFading )
+ {
+ m_fadeDistance = h.doubleAttribute( "fade_distance", fadeDistanceDefault );
+ m_fadePower = h.intAttribute( "fade_power", m_fadePower );
+ }
+ m_bMediaInteraction = h.boolAttribute( "media_interaction", true );
+ m_bMediaAttenuation = h.boolAttribute( "media_attenuation", true );
+
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMLight::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Light", Base::metaObject( ),
+ createNewLight );
+ PMTypeProperty* p = new PMTypeProperty( "lightType", &PMLight::setLightType,
+ &PMLight::lightType );
+ p->addEnumValue( "PointLight", PointLight );
+ p->addEnumValue( "SpotLight", SpotLight );
+ p->addEnumValue( "CylinderLight", CylinderLight );
+ p->addEnumValue( "ShadowlessLight", ShadowlessLight );
+ s_pMetaObject->addProperty( p );
+
+ s_pMetaObject->addProperty(
+ new PMLightProperty( "location", &PMLight::setLocation, &PMLight::location ) );
+ s_pMetaObject->addProperty(
+ new PMLightProperty( "color", &PMLight::setColor, &PMLight::color ) );
+ s_pMetaObject->addProperty(
+ new PMLightProperty( "radius", &PMLight::setRadius, &PMLight::radius ) );
+ s_pMetaObject->addProperty(
+ new PMLightProperty( "falloff", &PMLight::setFalloff, &PMLight::falloff ) );
+ s_pMetaObject->addProperty(
+ new PMLightProperty( "tightness", &PMLight::setTightness, &PMLight::tightness ) );
+ s_pMetaObject->addProperty(
+ new PMLightProperty( "pointAt", &PMLight::setPointAt, &PMLight::pointAt ) );
+ s_pMetaObject->addProperty(
+ new PMLightProperty( "parallel", &PMLight::setParallel, &PMLight::parallel ) );
+ s_pMetaObject->addProperty(
+ new PMLightProperty( "areaLight", &PMLight::setAreaLight, &PMLight::isAreaLight ) );
+
+ PMAreaProperty* p2 = new PMAreaProperty( "areaType", &PMLight::setAreaType,
+ &PMLight::areaType );
+ p2->addEnumValue( "Rectangular", Rectangular );
+ p2->addEnumValue( "Circular", Circular );
+ s_pMetaObject->addProperty( p2 );
+
+ s_pMetaObject->addProperty(
+ new PMLightProperty( "axis1", &PMLight::setAxis1, &PMLight::axis1 ) );
+ s_pMetaObject->addProperty(
+ new PMLightProperty( "axis2", &PMLight::setAxis2, &PMLight::axis2 ) );
+ s_pMetaObject->addProperty(
+ new PMLightProperty( "adaptive", &PMLight::setAdaptive, &PMLight::adaptive ) );
+ s_pMetaObject->addProperty(
+ new PMLightProperty( "orient", &PMLight::setOrient, &PMLight::orient ) );
+ s_pMetaObject->addProperty(
+ new PMLightProperty( "jitter", &PMLight::setJitter, &PMLight::jitter ) );
+ s_pMetaObject->addProperty(
+ new PMLightProperty( "fading", &PMLight::setFading, &PMLight::fading ) );
+ s_pMetaObject->addProperty(
+ new PMLightProperty( "fadeDistance", &PMLight::setFadeDistance, &PMLight::fadeDistance ) );
+ s_pMetaObject->addProperty(
+ new PMLightProperty( "fadePower", &PMLight::setFadePower, &PMLight::fadePower ) );
+ s_pMetaObject->addProperty(
+ new PMLightProperty( "mediaInteraction", &PMLight::setMediaInteraction,
+ &PMLight::mediaInteraction ) );
+ s_pMetaObject->addProperty(
+ new PMLightProperty( "mediaAttenuation", &PMLight::setMediaAttenuation,
+ &PMLight::mediaAttenuation ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMLight::setLocation( const PMVector& p )
+{
+ if( p != m_location )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMLocationID, m_location );
+ m_location = p;
+ m_location.resize( 3 );
+ setViewStructureChanged( );
+ }
+}
+
+void PMLight::setColor( const PMColor& c )
+{
+ if( c != m_color )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMColorID, m_color );
+ m_color = c;
+ }
+}
+
+void PMLight::setLightType( PMLightType t )
+{
+ if( t != m_type )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMTypeID, m_type );
+ m_type = t;
+ setViewStructureChanged( );
+ }
+}
+
+void PMLight::setRadius( double r )
+{
+ if( !approx( r, m_radius ) )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMRadiusID, m_radius );
+ m_radius = r;
+ setViewStructureChanged( );
+ }
+}
+
+void PMLight::setFalloff( double f )
+{
+ if( !approx( f, m_falloff ) )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFalloffID, m_falloff );
+ m_falloff = f;
+ setViewStructureChanged( );
+ }
+}
+
+void PMLight::setTightness( double t )
+{
+ if( !approx( t, m_tightness ) )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMTightnessID, m_tightness );
+ m_tightness = t;
+ }
+}
+
+void PMLight::setPointAt( const PMVector& v )
+{
+ if( !m_pointAt.approxEqual( v ) )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMPointAtID, m_pointAt );
+ m_pointAt = v;
+ setViewStructureChanged( );
+ }
+}
+
+void PMLight::setParallel( bool p )
+{
+ if ( p != m_parallel )
+ {
+ if ( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMParallelID, m_parallel );
+ m_parallel = p;
+ }
+}
+
+void PMLight::setAreaLight( bool yes )
+{
+ if( yes != m_bAreaLight )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAreaLightID, m_bAreaLight );
+ m_bAreaLight = yes;
+ setViewStructureChanged( );
+ }
+}
+
+void PMLight::setAreaType( PMAreaType at )
+{
+ if ( at != m_areaType )
+ {
+ if ( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAreaTypeID, m_areaType );
+ m_areaType = at;
+ setViewStructureChanged( );
+ }
+}
+
+void PMLight::setAxis1( const PMVector& v )
+{
+ if( !m_areaAxis1.approxEqual( v ) )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAreaAxis1ID, m_areaAxis1 );
+ m_areaAxis1 = v;
+ setViewStructureChanged( );
+ }
+}
+
+void PMLight::setAxis2( const PMVector& v )
+{
+ if( !m_areaAxis2.approxEqual( v ) )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAreaAxis2ID, m_areaAxis2 );
+ m_areaAxis2 = v;
+ setViewStructureChanged( );
+ }
+}
+
+void PMLight::setSize1( int s )
+{
+ if( s != m_areaSize1 )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAreaSize1ID, m_areaSize1 );
+ m_areaSize1 = s;
+ setViewStructureChanged( );
+ }
+}
+
+void PMLight::setSize2( int s )
+{
+ if( s != m_areaSize2 )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAreaSize2ID, m_areaSize2 );
+ m_areaSize2 = s;
+ setViewStructureChanged( );
+ }
+}
+
+void PMLight::setAdaptive( int a )
+{
+ if( a != m_adaptive )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAdaptiveID, m_adaptive );
+ m_adaptive = a;
+ }
+}
+
+void PMLight::setOrient( bool o )
+{
+ if( o != m_orient )
+ {
+ if ( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMOrientID, m_orient );
+ m_orient = o;
+ setViewStructureChanged( );
+ }
+}
+
+void PMLight::setJitter( bool j )
+{
+ if( j != m_jitter )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMJitterID, m_jitter );
+ m_jitter = j;
+ }
+}
+
+void PMLight::setFading( bool y )
+{
+ if( y != m_bFading )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFadingID, m_bFading );
+ m_bFading = y;
+ }
+}
+
+void PMLight::setFadeDistance( double d )
+{
+ if( !approx( d, m_fadeDistance ) )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFadeDistanceID, m_fadeDistance );
+ m_fadeDistance = d;
+ }
+}
+
+void PMLight::setFadePower( int p )
+{
+ if( p != m_fadePower )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFadePowerID, m_fadePower );
+ m_fadePower = p;
+ }
+}
+
+void PMLight::setMediaInteraction( bool y )
+{
+ if( y != m_bMediaInteraction )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMInteractionID, m_bMediaInteraction );
+ m_bMediaInteraction = y;
+ }
+}
+
+void PMLight::setMediaAttenuation( bool y )
+{
+ if( y != m_bMediaAttenuation )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAttenuationID, m_bMediaAttenuation );
+ m_bMediaAttenuation = y;
+ }
+}
+
+PMDialogEditBase* PMLight::editWidget( QWidget* parent ) const
+{
+ return new PMLightEdit( parent );
+}
+
+void PMLight::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMLocationID:
+ setLocation( data->vectorData( ) );
+ break;
+ case PMColorID:
+ setColor( data->colorData( ) );
+ break;
+ case PMTypeID:
+ setLightType( ( PMLightType ) ( data->intData( ) ) );
+ break;
+ case PMRadiusID:
+ setRadius( data->doubleData( ) );
+ break;
+ case PMFalloffID:
+ setFalloff( data->doubleData( ) );
+ break;
+ case PMTightnessID:
+ setTightness( data->doubleData( ) );
+ break;
+ case PMPointAtID:
+ setPointAt( data->vectorData( ) );
+ break;
+ case PMParallelID:
+ setParallel( data->boolData( ) );
+ break;
+ case PMAreaLightID:
+ setAreaLight( data->boolData( ) );
+ break;
+ case PMAreaTypeID:
+ setAreaType( ( PMAreaType ) ( data->intData( ) ) );
+ break;
+ case PMAreaAxis1ID:
+ setAxis1( data->vectorData( ) );
+ break;
+ case PMAreaAxis2ID:
+ setAxis2( data->vectorData( ) );
+ break;
+ case PMAreaSize1ID:
+ setSize1( data->intData( ) );
+ break;
+ case PMAreaSize2ID:
+ setSize2( data->intData( ) );
+ break;
+ case PMAdaptiveID:
+ setAdaptive( data->intData( ) );
+ break;
+ case PMOrientID:
+ setOrient( data->boolData( ) );
+ break;
+ case PMJitterID:
+ setJitter( data->boolData( ) );
+ break;
+ case PMFadingID:
+ setFading( data->boolData( ) );
+ break;
+ case PMFadeDistanceID:
+ setFadeDistance( data->doubleData( ) );
+ break;
+ case PMFadePowerID:
+ setFadePower( data->intData( ) );
+ break;
+ case PMInteractionID:
+ setMediaInteraction( data->boolData( ) );
+ break;
+ case PMAttenuationID:
+ setMediaAttenuation( data->boolData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMLight::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
+void PMLight::createViewStructure( )
+{
+ if( ( m_type == PointLight ) || ( m_type == ShadowlessLight ) )
+ {
+ if( !m_pViewStructure )
+ {
+ m_pViewStructure = new PMViewStructure( defaultPointStructure( ) );
+ m_pViewStructure->points( ).detach( );
+ }
+ else
+ {
+ m_pViewStructure->points( ).resize(
+ defaultPointStructure( )->points( ).size( ) );
+ m_pViewStructure->lines( ) = defaultPointStructure( )->lines( );
+ }
+
+ PMPointArray& points = m_pViewStructure->points( );
+
+ int i;
+ double c = s_pointLightSize / sqrt( 3.0 );
+ for( i = 0; i < 14; i++ )
+ points[i] = PMPoint( m_location );
+
+ points[0][0] += s_pointLightSize;
+ points[1][0] -= s_pointLightSize;
+ points[2][1] += s_pointLightSize;
+ points[3][1] -= s_pointLightSize;
+ points[4][2] += s_pointLightSize;
+ points[5][2] -= s_pointLightSize;
+
+ for( i = 0; i < 4; i++ )
+ {
+ points[6+2*i][0] += c;
+ points[6+2*i][1] += ( i & 1 ? c : -c );
+ points[6+2*i][2] += ( i & 2 ? c : -c );
+ points[7+2*i][0] -= c;
+ points[7+2*i][1] -= ( i & 1 ? c : -c );
+ points[7+2*i][2] -= ( i & 2 ? c : -c );
+ }
+ }
+ else if( m_type == SpotLight )
+ {
+ if( !m_pViewStructure )
+ {
+ m_pViewStructure = new PMViewStructure( defaultSpotStructure( ) );
+ m_pViewStructure->points( ).detach( );
+ }
+ else
+ {
+ m_pViewStructure->points( ).resize(
+ defaultSpotStructure( )->points( ).size( ) );
+ m_pViewStructure->lines( ) = defaultSpotStructure( )->lines( );
+ }
+
+ PMPointArray& points = m_pViewStructure->points( );
+
+ points[0] = PMPoint( m_location );
+
+ PMVector pointAtVector = m_pointAt - m_location;
+ double pl = pointAtVector.abs( );
+ if( approxZero( pl ) )
+ pointAtVector = PMVector( 0.0, 0.0, 1.0 );
+ else
+ pointAtVector /= pl;
+ PMVector endPoint = pointAtVector.orthogonal( );
+ PMMatrix rotation = PMMatrix::rotation( pointAtVector,
+ 2 * M_PI / s_nSpotLines );
+ double length, r1, r2, a1, a2;
+ length = s_length;
+ a1 = m_radius;
+ a2 = m_falloff;
+ if( a1 < 0 ) a1 = 0;
+ if( a2 < 0 ) a2 = 0;
+ if( a1 > a2 ) a1 = a2;
+ if( a1 >= 89.9 ) a1 = 89.9;
+ if( a2 >= 89.9 ) a2 = 89.9;
+ a1 *= M_PI / 180;
+ a2 *= M_PI / 180;
+ r1 = tan( a1 ) * length;
+ r2 = tan( a2 ) * length;
+
+ if( r2 > length )
+ {
+ double d = length / r2;
+ r1 *= d;
+ r2 *= d;
+ length *= d;
+ }
+
+ endPoint *= r2;
+ double r;
+ if( approxZero( r2 ) )
+ r = 1;
+ else
+ r = r1 / r2;
+
+ PMVector circleCenter = m_location + length * pointAtVector;
+ points[1] = PMPoint( circleCenter + endPoint );
+ points[s_nSpotLines + 1] = PMPoint( circleCenter + endPoint * r );
+
+ int i;
+ for( i = 2; i < ( s_nSpotLines + 1 ); i++ )
+ {
+ endPoint = rotation * endPoint;
+ points[i] = PMPoint( circleCenter + endPoint );
+ points[s_nSpotLines + i] = PMPoint( circleCenter + endPoint * r );
+ }
+ points[s_nSpotLines*2+1] = m_pointAt;
+ }
+ else if( m_type == CylinderLight )
+ {
+ if( !m_pViewStructure )
+ {
+ m_pViewStructure = new PMViewStructure( defaultCylindricalStructure( ) );
+ m_pViewStructure->points( ).detach( );
+ }
+ else
+ {
+ m_pViewStructure->points( ).resize(
+ defaultCylindricalStructure( )->points( ).size( ) );
+ m_pViewStructure->lines( ) = defaultCylindricalStructure( )->lines( );
+ }
+
+ PMPointArray& points = m_pViewStructure->points( );
+
+ points[s_nCylinderLines*4] = PMPoint( m_location );
+ points[s_nCylinderLines*4+1] = PMPoint( m_pointAt );
+
+ PMVector pointAtVector = m_pointAt - m_location;
+ double pl = pointAtVector.abs( );
+ if( approxZero( pl ) )
+ pointAtVector = PMVector( 0.0, 0.0, 1.0 );
+ else
+ pointAtVector /= pl;
+ PMVector endPoint = pointAtVector.orthogonal( );
+ PMMatrix rotation = PMMatrix::rotation( pointAtVector,
+ 2 * M_PI / s_nCylinderLines );
+ double r1, r2;
+ r1 = m_radius / 100;
+ r2 = m_falloff / 100;
+ if( r1 < 0 ) r1 = 0;
+ if( r2 < 0 ) r2 = 0;
+ if( r1 > r2 ) r1 = r2;
+
+ endPoint *= r2;
+ double r;
+ if( approxZero( r2 ) )
+ r = 1;
+ else
+ r = r1 / r2;
+
+ PMVector circleCenter = m_location + s_length * pointAtVector;
+ points[0] = PMPoint( circleCenter + endPoint );
+ points[s_nCylinderLines] = PMPoint( m_location + endPoint );
+ points[2*s_nCylinderLines] = PMPoint( circleCenter + endPoint * r );
+ points[3*s_nCylinderLines] = PMPoint( m_location + endPoint * r );
+
+ int i;
+ for( i = 1; i < s_nCylinderLines; i++ )
+ {
+ endPoint = rotation * endPoint;
+ points[i] = PMPoint( circleCenter + endPoint );
+ points[s_nCylinderLines + i] = PMPoint( m_location + endPoint );
+ points[2*s_nCylinderLines + i] = PMPoint( circleCenter + endPoint * r );
+ points[3*s_nCylinderLines + i] = PMPoint( m_location + endPoint * r );
+ }
+ }
+
+ if( m_bAreaLight )
+ {
+ int s1, s2;
+
+ s1 = m_areaSize1;
+ s2 = m_areaSize2;
+ if( s1 < 1 ) s1 = 1;
+ if( s2 < 1 ) s2 = 1;
+
+ if( ( s1 > 1 ) || ( s2 > 1 ) )
+ {
+ int x, y, h;
+ int ps, ls;
+ PMVector bp;
+
+ PMPointArray& points = m_pViewStructure->points( );
+ PMLineArray& lines = m_pViewStructure->lines( );
+ points.detach( );
+ lines.detach( );
+
+ ps = points.size( );
+ ls = lines.size( );
+ points.resize( ps + s1*s2 );
+ lines.resize( ls + s1*(s2-1) + s2*(s1-1) );
+
+ if( s1 == 1 )
+ {
+ bp = m_location - m_areaAxis2/2;
+ for( y = 0; y < s2; y++ )
+ points[ps + y] = PMPoint( bp + m_areaAxis2
+ * ( (double)y/(double)(s2-1) ) );
+ for( y = 0; y < ( s2-1 ); y++ )
+ lines[ls+y] = PMLine( ps + y, ps + y+1 );
+ }
+ else if( s2 == 1 )
+ {
+ bp = m_location - m_areaAxis1/2;
+ for( x = 0; x < s1; x++ )
+ points[ps + x] = PMPoint( bp + m_areaAxis1
+ * ( (double)x/(double)(s1-1) ) );
+ for( x = 0; x < ( s1-1 ); x++ )
+ lines[ls+x] = PMLine( ps + x, ps + x+1 );
+ }
+ else
+ {
+ bp = m_location - m_areaAxis1/2 - m_areaAxis2/2;
+
+ if ( m_areaType == Rectangular || s1 < 2 || s2 < 2 )
+ {
+ for( x = 0; x < s1; x++ )
+ for( y = 0; y < s2; y++ )
+ points[ps + y*s1 + x] =
+ PMPoint( bp + m_areaAxis1 * ( (double)x/(double)(s1-1) )
+ + m_areaAxis2 * ( (double)y/(double)(s2-1) ) );
+ }
+ else
+ {
+ double stepX = ( 2.0 / (double)(s1-1) );
+ double stepY = ( 2.0 / (double)(s2-1) );
+ double doubleX, doubleY, xSqr, scaleFactor;
+
+ for ( x = 0; x < s1; ++x )
+ {
+ doubleX = ( (double)x * stepX ) - 1.0;
+ xSqr = doubleX * doubleX;
+ for ( y = 0; y < s2; ++y )
+ {
+ doubleY = ( (double)y * stepY ) - 1.0;
+
+ if ( doubleX == 0.0 && doubleY == 0.0 )
+ scaleFactor = 1.0;
+ else
+ {
+ if ( fabs( doubleX ) > fabs( doubleY ) )
+ scaleFactor = fabs( doubleX );
+ else
+ scaleFactor = fabs( doubleY );
+ scaleFactor /= sqrt( xSqr + doubleY * doubleY );
+ }
+
+ points[ps + y*s1 + x] =
+ PMPoint( bp + m_areaAxis1 *
+ ( ( ( doubleX * scaleFactor ) / 2.0 ) + 0.5 )
+ + m_areaAxis2 *
+ ( ( ( doubleY * scaleFactor ) / 2.0 ) + 0.5 ) );
+ }
+ }
+ }
+
+ for( x = 0; x < s1; x++ )
+ {
+ for( y = 0; y < (s2-1); y++ )
+ {
+ h = ps + x + s1*y;
+ lines[ls + x*(s2-1) + y] = PMLine( h, h+s1 );
+ }
+ }
+
+ ls += s1*(s2-1);
+ for( y = 0; y < s2; y++ )
+ {
+ for( x = 0; x < (s1-1); x++ )
+ {
+ h = ps + x + s1*y;
+ lines[ls + y*(s1-1) + x] = PMLine( h, h+1 );
+ }
+ }
+ }
+ }
+ }
+}
+
+PMViewStructure* PMLight::defaultPointStructure( ) const
+{
+ if( !s_pDefaultPointStructure )
+ {
+ s_pDefaultPointStructure = new PMViewStructure( 14, 7 );
+// PMPointArray& points = s_pDefaultPointStructure->points( );
+ PMLineArray& lines = s_pDefaultPointStructure->lines( );
+
+ lines[0] = PMLine( 0, 1 );
+ lines[1] = PMLine( 2, 3 );
+ lines[2] = PMLine( 4, 5 );
+ lines[3] = PMLine( 6, 7 );
+ lines[4] = PMLine( 8, 9 );
+ lines[5] = PMLine( 10, 11 );
+ lines[6] = PMLine( 12, 13 );
+ }
+ return s_pDefaultPointStructure;
+}
+
+PMViewStructure* PMLight::defaultSpotStructure( ) const
+{
+ if( !s_pDefaultSpotStructure )
+ {
+ s_pDefaultSpotStructure = new PMViewStructure( s_nSpotLines * 2 + 2, s_nSpotLines * 3 + 1 );
+// PMPointArray& points = s_pDefaultSpotStructure->points( );
+ PMLineArray& lines = s_pDefaultSpotStructure->lines( );
+
+ int i;
+ for( i = 0; i < s_nSpotLines; i++ )
+ {
+ lines[i] = PMLine( 0, i+1 );
+ lines[s_nSpotLines + i] = PMLine( i+1, i+2 );
+ lines[2*s_nSpotLines + i] = PMLine( s_nSpotLines + i+1,
+ s_nSpotLines + i+2 );
+ }
+ // fix for the last line
+ lines[2*s_nSpotLines - 1] = PMLine( 1, s_nSpotLines );
+ lines[3*s_nSpotLines - 1] = PMLine( s_nSpotLines + 1, s_nSpotLines*2 );
+ lines[3*s_nSpotLines] = PMLine( 0, s_nSpotLines*2 + 1 );
+ }
+ return s_pDefaultSpotStructure;
+}
+
+PMViewStructure* PMLight::defaultCylindricalStructure( ) const
+{
+ if( !s_pDefaultCylindricalStructure )
+ {
+ s_pDefaultCylindricalStructure = new PMViewStructure( s_nCylinderLines * 4 + 2, s_nCylinderLines * 5 + 1 );
+// PMPointArray& points = s_pDefaultCylindricalStructure->points( );
+ PMLineArray& lines = s_pDefaultCylindricalStructure->lines( );
+
+ int i;
+ for( i = 0; i < s_nCylinderLines; i++ )
+ {
+ lines[i] = PMLine( i, i+1 );
+ lines[s_nCylinderLines + i] = PMLine( i + s_nCylinderLines,
+ i + s_nCylinderLines + 1 );
+ lines[2*s_nCylinderLines + i] = PMLine( i + 2*s_nCylinderLines,
+ i + 2*s_nCylinderLines + 1 );
+ lines[3*s_nCylinderLines + i] = PMLine( i + 3*s_nCylinderLines,
+ i + 3*s_nCylinderLines + 1 );
+ lines[4*s_nCylinderLines + i] = PMLine( i, i + s_nCylinderLines );
+ }
+ // fix for some lines
+ lines[s_nCylinderLines-1] = PMLine( 0, s_nCylinderLines - 1 );
+ lines[2*s_nCylinderLines-1] = PMLine( s_nCylinderLines,
+ 2*s_nCylinderLines - 1 );
+ lines[3*s_nCylinderLines-1] = PMLine( 2*s_nCylinderLines,
+ 3*s_nCylinderLines - 1 );
+ lines[4*s_nCylinderLines-1] = PMLine( 3*s_nCylinderLines,
+ 4*s_nCylinderLines - 1 );
+ lines[5*s_nCylinderLines] = PMLine( 4*s_nCylinderLines,
+ 4*s_nCylinderLines + 1 );
+ }
+ return s_pDefaultCylindricalStructure;
+}
+
+void PMLight::controlPoints( PMControlPointList& list )
+{
+ list.append( new PM3DControlPoint( m_location, PMLocationID, i18n( "Location" ) ) );
+ if( ( m_type == SpotLight ) || ( m_type == CylinderLight ) )
+ list.append( new PM3DControlPoint( m_pointAt, PMPointAtID, i18n( "Point at" ) ) );
+}
+
+void PMLight::controlPointsChanged( PMControlPointList& list )
+{
+ PMControlPoint* p;
+
+ for( p = list.first( ); p; p = list.next( ) )
+ {
+ if( p->changed( ) )
+ {
+ switch( p->id( ) )
+ {
+ case PMLocationID:
+ setLocation( ( ( PM3DControlPoint* ) p )->point( ) );
+ break;
+ case PMPointAtID:
+ setPointAt( ( ( PM3DControlPoint* ) p )->point( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMLight::controlPointsChanged\n";
+ break;
+ }
+ }
+ }
+}
+
+void PMLight::cleanUp( ) const
+{
+ if( s_pDefaultPointStructure )
+ delete s_pDefaultPointStructure;
+ s_pDefaultPointStructure = 0;
+ if( s_pDefaultSpotStructure )
+ delete s_pDefaultSpotStructure;
+ s_pDefaultSpotStructure = 0;
+ if( s_pDefaultCylindricalStructure )
+ delete s_pDefaultCylindricalStructure;
+ s_pDefaultCylindricalStructure = 0;
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
diff --git a/kpovmodeler/pmlight.h b/kpovmodeler/pmlight.h
new file mode 100644
index 00000000..df40ec0a
--- /dev/null
+++ b/kpovmodeler/pmlight.h
@@ -0,0 +1,372 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMLIGHT_H
+#define PMLIGHT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmnamedobject.h"
+#include "pmvector.h"
+#include "pmcolor.h"
+
+class PMViewStructure;
+
+/**
+ * Class for povray light sources.
+ */
+
+class PMLight : public PMNamedObject
+{
+ typedef PMNamedObject Base;
+public:
+ enum PMLightType { PointLight=0, SpotLight=1, CylinderLight=2, ShadowlessLight=3 };
+ enum PMAreaType { Rectangular=0, Circular=1 };
+ /**
+ * Creates an empty PMLight
+ */
+ PMLight( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMLight( const PMLight& l );
+ /**
+ * deletes the PMLight
+ */
+ virtual ~PMLight( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMLight( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMLightEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmlight" ); }
+
+ /**
+ * Returns the type
+ */
+ PMLightType lightType( ) const { return m_type; }
+ /**
+ * Sets the type
+ */
+ void setLightType( PMLightType t );
+
+ /**
+ * Returns the location
+ */
+ PMVector location( ) const { return m_location; }
+ /**
+ * Sets the location
+ */
+ void setLocation( const PMVector& p );
+
+ /**
+ * Returns the color
+ */
+ PMColor color( ) const { return m_color; }
+ /**
+ * Sets the color
+ */
+ void setColor( const PMColor& c );
+
+ /**
+ * Returns the radius for cylinder and spot lights
+ */
+ double radius( ) const { return m_radius; }
+ /**
+ * Sets the radius for cylinder and spot lights
+ */
+ void setRadius( double r );
+
+ /**
+ * Returns the falloff for cylinder and spot lights
+ */
+ double falloff( ) const { return m_falloff; }
+ /**
+ * Sets the falloff for cylinder and spot lights
+ */
+ void setFalloff( double f );
+
+ /**
+ * Returns the tightness for cylinder and spot lights
+ */
+ double tightness( ) const { return m_tightness; }
+ /**
+ * Sets the tightness for cylinder and spot lights
+ */
+ void setTightness( double r );
+
+ /**
+ * Returns the pointAt point for cylinder and spot lights
+ */
+ PMVector pointAt( ) const { return m_pointAt; }
+ /**
+ * Sets the pointAt for cylinder and spot lights
+ */
+ void setPointAt( const PMVector& p );
+
+ /**
+ * Return true if the light is a parallel light
+ */
+ bool parallel( ) const { return m_parallel; }
+ /**
+ * Sets the parallel light flag
+ */
+ void setParallel( bool p );
+
+ /**
+ * Returns true if the light is a area light
+ */
+ bool isAreaLight( ) const { return m_bAreaLight; }
+ /**
+ * Sets the area light flag
+ */
+ void setAreaLight( bool yes );
+
+ /**
+ * Returns the area light type
+ */
+ PMAreaType areaType( ) const { return m_areaType; }
+ /**
+ * Sets the area light type
+ */
+ void setAreaType( PMAreaType at );
+
+ /**
+ * Returns the axis1 for area lights
+ */
+ PMVector axis1( ) const { return m_areaAxis1; }
+ /**
+ * Sets the axis1 for area lights
+ */
+ void setAxis1( const PMVector& v );
+
+ /**
+ * Returns the axis2 for area lights
+ */
+ PMVector axis2( ) const { return m_areaAxis2; }
+ /**
+ * Sets the axis2 for area lights
+ */
+ void setAxis2( const PMVector& v );
+
+ /**
+ * Returns the size1 for area lights
+ */
+ int size1( ) const { return m_areaSize1; }
+ /**
+ * Sets the size1 for area lights
+ */
+ void setSize1( int s );
+
+ /**
+ * Returns the size2 for area lights
+ */
+ int size2( ) const { return m_areaSize2; }
+ /**
+ * Sets the size2 for area lights
+ */
+ void setSize2( int s );
+
+ /**
+ * Returns the adaptive parameter for area lights
+ */
+ int adaptive( ) const { return m_adaptive; }
+ /**
+ * Sets the adaptive parameter for area lights
+ */
+ void setAdaptive( int s );
+
+ /**
+ * Returns if the area light is orientated
+ */
+ bool orient( ) const { return m_orient; }
+ /**
+ * Sets the orient flag
+ */
+ void setOrient( bool o );
+
+ /**
+ * Returns the jitter parameter for area lights
+ */
+ bool jitter( ) const { return m_jitter; }
+ /**
+ * Sets the jitter parameter for area lights
+ */
+ void setJitter( bool j );
+
+ /**
+ * Returns true if light fading is enabled
+ */
+ bool fading( ) const { return m_bFading; }
+ /**
+ * Enables/Disables light fading
+ */
+ void setFading( bool yes );
+
+ /**
+ * Returns the fading distance
+ */
+ double fadeDistance( ) const { return m_fadeDistance; }
+ /**
+ * Sets the fading distance
+ */
+ void setFadeDistance( double d );
+
+ /**
+ * Returns the fading power
+ */
+ int fadePower( ) const { return m_fadePower; }
+ /**
+ * Sets the fading power
+ */
+ void setFadePower( int p );
+
+ /**
+ * Returns the media interaction flag
+ */
+ bool mediaInteraction( ) const { return m_bMediaInteraction; }
+ /**
+ * Sets the media interaction flag
+ */
+ void setMediaInteraction( bool yes );
+
+ /**
+ * Returns the media attenuation flag
+ */
+ bool mediaAttenuation( ) const { return m_bMediaAttenuation; }
+ /**
+ * Sets the media attenuation flag
+ */
+ void setMediaAttenuation( bool yes );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /** */
+ virtual void controlPoints( PMControlPointList& list );
+ /** */
+ virtual void controlPointsChanged( PMControlPointList& list );
+ /** */
+ virtual void cleanUp( ) const;
+
+protected:
+ /** */
+ virtual bool isDefault( ) { return false; }
+ /** */
+ virtual void createViewStructure( );
+ /** */
+ virtual PMViewStructure* defaultViewStructure( ) const { return 0; }
+
+private:
+ /**
+ * Creates and returns the default view structure for point lights
+ */
+ PMViewStructure* defaultPointStructure( ) const;
+ /**
+ * Creates and returns the default view structure for spot lights
+ */
+ PMViewStructure* defaultSpotStructure( ) const;
+ /**
+ * Creates and returns the default view structure for cylindrical lights
+ */
+ PMViewStructure* defaultCylindricalStructure( ) const;
+
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMLightMementoID
+ { PMLocationID, PMColorID, PMRadiusID, PMFalloffID, PMTightnessID,
+ PMPointAtID, PMParallelID, PMAreaLightID, PMAreaTypeID, PMAreaAxis1ID,
+ PMAreaAxis2ID, PMAreaSize1ID, PMAreaSize2ID, PMAdaptiveID, PMOrientID,
+ PMJitterID, PMTypeID, PMFadingID, PMFadeDistanceID, PMFadePowerID,
+ PMInteractionID, PMAttenuationID };
+
+ PMLightType m_type;
+ PMVector m_location;
+ PMColor m_color;
+ double m_radius;
+ double m_falloff;
+ double m_tightness;
+ PMVector m_pointAt;
+ bool m_parallel;
+ bool m_bAreaLight;
+ PMAreaType m_areaType;
+ PMVector m_areaAxis1, m_areaAxis2;
+ int m_areaSize1, m_areaSize2;
+ int m_adaptive;
+ bool m_orient;
+ bool m_jitter;
+ bool m_bFading;
+ double m_fadeDistance;
+ int m_fadePower;
+ bool m_bMediaInteraction;
+ bool m_bMediaAttenuation;
+
+ /**
+ * The default view structure for point lights
+ */
+ static PMViewStructure* s_pDefaultPointStructure;
+ /**
+ * The default view structure for spot lights
+ */
+ static PMViewStructure* s_pDefaultSpotStructure;
+ /**
+ * The default view structure for cylindrical lights
+ */
+ static PMViewStructure* s_pDefaultCylindricalStructure;
+
+ /**
+ * The size of the point light for 3d views
+ */
+ static double s_pointLightSize;
+ /**
+ * Number of lines around the cylinder
+ */
+ static int s_nCylinderLines;
+ /**
+ * Number of lines around the spot
+ */
+ static int s_nSpotLines;
+ /**
+ * Length of the spot and cylinder
+ */
+ static double s_length;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmlightedit.cpp b/kpovmodeler/pmlightedit.cpp
new file mode 100644
index 00000000..23f5aa9d
--- /dev/null
+++ b/kpovmodeler/pmlightedit.cpp
@@ -0,0 +1,450 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmlightedit.h"
+#include "pmlight.h"
+#include "pmvectoredit.h"
+#include "pmlineedits.h"
+#include "pmcoloredit.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcombobox.h>
+#include <qcheckbox.h>
+
+#include <klocale.h>
+
+PMLightEdit::PMLightEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMLightEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ m_pLocation = new PMVectorEdit( "x", "y", "z", this );
+ m_pColor = new PMColorEdit( false, this );
+ m_pType = new QComboBox( false, this );
+ m_pType->insertItem( i18n( "Point Light" ) );
+ m_pType->insertItem( i18n( "Spot Light" ) );
+ m_pType->insertItem( i18n( "Cylindrical Light" ) );
+ m_pType->insertItem( i18n( "Shadowless Light" ) );
+
+ m_pRadius = new PMFloatEdit( this );
+ m_pRadius->setValidation( false, 0, true, 90 );
+ m_pRadiusLabel = new QLabel( i18n( "Radius:" ), this );
+
+ m_pFalloff = new PMFloatEdit( this );
+ m_pFalloff->setValidation( false, 0, true, 90 );
+ m_pFalloffLabel = new QLabel( i18n( "Falloff:" ), this );
+
+ m_pTightness = new PMFloatEdit( this );
+ m_pTightness->setValidation( false, 0, true, 90 );
+ m_pTightnessLabel = new QLabel( i18n( "Tightness:" ), this );
+
+ m_pPointAt = new PMVectorEdit( "x", "y", "z", this );
+ m_pPointAtLabel = new QLabel( i18n( "Point at:" ), this );
+
+ m_pParallel = new QCheckBox( i18n( "Parallel" ), this );
+
+ m_pAreaLight = new QCheckBox( i18n( "Area light" ), this );
+
+ m_pAreaTypeLabel = new QLabel( i18n ( "Area type:" ), this );
+ m_pAreaType = new QComboBox( false, this );
+ m_pAreaType->insertItem( i18n( "Rectangular" ) );
+ m_pAreaType->insertItem( i18n( "Circular" ) );
+
+ m_pAxis1 = new PMVectorEdit( "x", "y", "z", this );
+ m_pAxis1Label = new QLabel( i18n( "Axis 1:" ), this );
+ m_pAxis2 = new PMVectorEdit( "x", "y", "z", this );
+ m_pAxis2Label = new QLabel( i18n( "Axis 2:" ), this );
+
+ m_pSize1 = new PMIntEdit( this );
+ m_pSize1->setValidation( true, 1, true, 50 );
+ m_pSize1Label = new QLabel( i18n( "Size 1:" ), this );
+ m_pSize2 = new PMIntEdit( this );
+ m_pSize2->setValidation( true, 1, true, 50 );
+ m_pSize2Label = new QLabel( i18n( "Size 2:" ), this );
+
+ m_pAdaptive = new PMIntEdit( this );
+ m_pAdaptive->setValidation( true, 0, false, 0 );
+ m_pAdaptiveLabel = new QLabel( i18n( "Adaptive:" ), this );
+ m_pOrient = new QCheckBox( i18n( "Orient" ), this );
+ m_pJitter = new QCheckBox( i18n( "Jitter" ), this );
+
+ m_pFading = new QCheckBox( i18n( "Fading" ), this );
+
+ m_pFadeDistance = new PMFloatEdit( this );
+ m_pFadeDistance->setValidation( true, 0, false, 0 );
+ m_pFadeDistanceLabel = new QLabel( i18n( "Fade distance:" ), this );
+
+ m_pFadePower = new PMIntEdit( this );
+ m_pFadePower->setValidation( true, 0, false, 0 );
+ m_pFadePowerLabel = new QLabel( i18n( "Fade power:" ), this );
+
+ m_pMediaInteraction = new QCheckBox( i18n( "Media interaction" ), this );
+ m_pMediaAttenuation = new QCheckBox( i18n( "Media attenuation" ), this );
+
+ QHBoxLayout* hl;
+ QGridLayout* gl;
+
+ gl = new QGridLayout( topLayout( ), 3, 2 );
+ gl->addWidget( new QLabel( i18n( "Location:" ), this ), 0, 0 );
+ gl->addWidget( m_pLocation, 0, 1 );
+ gl->addWidget( new QLabel( i18n( "Color:" ), this ), 1, 0, AlignTop );
+ gl->addWidget( m_pColor, 1, 1 );
+ gl->addWidget( new QLabel( i18n( "Type:" ), this ), 2, 0 );
+ hl = new QHBoxLayout( );
+ gl->addLayout( hl, 2, 1 );
+ hl->addWidget( m_pType );
+ hl->addStretch( 1 );
+
+ gl = new QGridLayout( topLayout( ), 4, 2 );
+ gl->addWidget( m_pRadiusLabel, 0, 0 );
+ gl->addWidget( m_pRadius, 0, 1, AlignLeft );
+ gl->addWidget( m_pFalloffLabel, 1, 0 );
+ gl->addWidget( m_pFalloff, 1, 1, AlignLeft );
+ gl->addWidget( m_pTightnessLabel, 2, 0 );
+ gl->addWidget( m_pTightness, 2, 1, AlignLeft );
+ gl->addWidget( m_pPointAtLabel, 3, 0 );
+ gl->addWidget( m_pPointAt, 3, 1 );
+
+ topLayout( )->addWidget( m_pParallel );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ gl = new QGridLayout( hl, 7, 2 );
+ gl->addMultiCellWidget( m_pAreaLight, 0, 0, 0, 1 );
+ gl->addWidget( m_pAreaTypeLabel, 1, 0 );
+ gl->addWidget( m_pAreaType, 1, 1 );
+ gl->addWidget( m_pAxis1Label, 2, 0 );
+ gl->addWidget( m_pAxis1, 2, 1 );
+ gl->addWidget( m_pAxis2Label, 3, 0 );
+ gl->addWidget( m_pAxis2, 3, 1 );
+ gl->addWidget( m_pSize1Label, 4, 0 );
+ gl->addWidget( m_pSize1, 4, 1, AlignLeft );
+ gl->addWidget( m_pSize2Label, 5, 0 );
+ gl->addWidget( m_pSize2, 5, 1, AlignLeft );
+ gl->addWidget( m_pAdaptiveLabel, 6, 0 );
+ gl->addWidget( m_pAdaptive, 6, 1, AlignLeft );
+ hl->addStretch( 1 );
+
+ topLayout( )->addWidget( m_pOrient );
+ topLayout( )->addWidget( m_pJitter );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ gl = new QGridLayout( hl, 3, 2 );
+ gl->addMultiCellWidget( m_pFading, 0, 0, 0, 1 );
+ gl->addWidget( m_pFadeDistanceLabel, 1, 0 );
+ gl->addWidget( m_pFadeDistance, 1, 1 );
+ gl->addWidget( m_pFadePowerLabel, 2, 0 );
+ gl->addWidget( m_pFadePower, 2, 1 );
+ hl->addStretch( 1 );
+
+ topLayout( )->addWidget( m_pMediaInteraction );
+ topLayout( )->addWidget( m_pMediaAttenuation );
+
+ connect( m_pLocation, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pColor, SIGNAL( dataChanged( ) ),
+ SIGNAL( dataChanged( ) ) );
+ connect( m_pType, SIGNAL( activated( int ) ),
+ SLOT( slotTypeActivated( int ) ) );
+ connect( m_pRadius, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pFalloff, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pTightness, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pPointAt, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pParallel, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pAreaLight, SIGNAL( clicked( ) ), SLOT( slotAreaClicked( ) ) );
+ connect( m_pAreaType, SIGNAL( activated ( int ) ), SLOT( slotOrientCheck( ) ) );
+ connect( m_pAxis1, SIGNAL( dataChanged( ) ), SLOT( slotOrientCheck( ) ) );
+ connect( m_pAxis2, SIGNAL( dataChanged( ) ), SLOT( slotOrientCheck( ) ) );
+ connect( m_pSize1, SIGNAL( dataChanged( ) ), SLOT( slotOrientCheck( ) ) );
+ connect( m_pSize2, SIGNAL( dataChanged( ) ), SLOT( slotOrientCheck( ) ) );
+ connect( m_pAdaptive, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pOrient, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pJitter, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pFading, SIGNAL( clicked( ) ), SLOT( slotFadingClicked( ) ) );
+ connect( m_pFadeDistance, SIGNAL( dataChanged( ) ),
+ SIGNAL( dataChanged( ) ) );
+ connect( m_pFadePower, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pMediaInteraction, SIGNAL( clicked( ) ),
+ SIGNAL( dataChanged( ) ) );
+ connect( m_pMediaAttenuation, SIGNAL( clicked( ) ),
+ SIGNAL( dataChanged( ) ) );
+}
+
+void PMLightEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Light" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMLight* ) o;
+
+ m_pLocation->setVector( m_pDisplayedObject->location( ) );
+ m_pLocation->setReadOnly( readOnly );
+ m_pColor->setColor( m_pDisplayedObject->color( ) );
+ m_pColor->setReadOnly( readOnly );
+ m_pType->setCurrentItem( m_pDisplayedObject->lightType( ) );
+ m_pType->setEnabled( !readOnly );
+ slotTypeActivated( m_pDisplayedObject->lightType( ) );
+ m_pRadius->setValue( m_pDisplayedObject->radius( ) );
+ m_pRadius->setReadOnly( readOnly );
+ m_pFalloff->setValue( m_pDisplayedObject->falloff( ) );
+ m_pFalloff->setReadOnly( readOnly );
+ m_pTightness->setValue( m_pDisplayedObject->tightness( ) );
+ m_pTightness->setReadOnly( readOnly );
+ m_pPointAt->setVector( m_pDisplayedObject->pointAt( ) );
+ m_pPointAt->setReadOnly( readOnly );
+ m_pParallel->setChecked( m_pDisplayedObject->parallel( ) );
+ m_pParallel->setEnabled( !readOnly );
+ m_pAreaLight->setChecked( m_pDisplayedObject->isAreaLight( ) );
+ m_pAreaLight->setEnabled( !readOnly );
+ m_pAreaType->setCurrentItem( m_pDisplayedObject->areaType( ) );
+ m_pAreaType->setEnabled( !readOnly );
+ m_pAxis1->setVector( m_pDisplayedObject->axis1( ) );
+ m_pAxis1->setReadOnly( readOnly );
+ m_pAxis2->setVector( m_pDisplayedObject->axis2( ) );
+ m_pAxis2->setReadOnly( readOnly );
+ m_pSize1->setValue( m_pDisplayedObject->size1( ) );
+ m_pSize1->setReadOnly( readOnly );
+ m_pSize2->setValue( m_pDisplayedObject->size2( ) );
+ m_pSize2->setReadOnly( readOnly );
+ m_pAdaptive->setValue( m_pDisplayedObject->adaptive( ) );
+ m_pAdaptive->setReadOnly( readOnly );
+ m_pOrient->setChecked( m_pDisplayedObject->orient( ) );
+ m_pOrient->setEnabled( orientEnabled( readOnly ) );
+ m_pJitter->setChecked( m_pDisplayedObject->jitter( ) );
+ m_pJitter->setEnabled( !readOnly );
+ slotAreaClicked( );
+ m_pFading->setChecked( m_pDisplayedObject->fading( ) );
+ m_pFading->setEnabled( !readOnly );
+ m_pFadeDistance->setValue( m_pDisplayedObject->fadeDistance( ) );
+ m_pFadeDistance->setReadOnly( readOnly );
+ m_pFadePower->setValue( m_pDisplayedObject->fadePower( ) );
+ m_pFadePower->setReadOnly( readOnly );
+ slotFadingClicked( );
+ m_pMediaInteraction->setChecked( m_pDisplayedObject->mediaInteraction( ) );
+ m_pMediaInteraction->setEnabled( !readOnly );
+ m_pMediaAttenuation->setChecked( m_pDisplayedObject->mediaAttenuation( ) );
+ m_pMediaAttenuation->setEnabled( !readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMLightEdit: Can't display object\n";
+}
+
+void PMLightEdit::saveContents( )
+{
+ int index;
+
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setLocation( m_pLocation->vector( ) );
+ m_pDisplayedObject->setColor( m_pColor->color( ) );
+
+ index = m_pType->currentItem( );
+ if( ( index == 1 ) || ( index == 2 ) )
+ {
+ m_pDisplayedObject->setRadius( m_pRadius->value( ) );
+ m_pDisplayedObject->setFalloff( m_pFalloff->value( ) );
+ m_pDisplayedObject->setTightness( m_pTightness->value( ) );
+ m_pDisplayedObject->setPointAt( m_pPointAt->vector( ) );
+ }
+ m_pDisplayedObject->setLightType( ( PMLight::PMLightType ) index );
+
+ m_pDisplayedObject->setParallel( m_pParallel->isChecked( ) );
+
+ if( m_pAreaLight->isChecked( ) )
+ {
+ m_pDisplayedObject->setAreaType(
+ ( PMLight::PMAreaType ) m_pAreaType->currentItem( ) );
+ m_pDisplayedObject->setAxis1( m_pAxis1->vector( ) );
+ m_pDisplayedObject->setAxis2( m_pAxis2->vector( ) );
+ m_pDisplayedObject->setSize1( m_pSize1->value( ) );
+ m_pDisplayedObject->setSize2( m_pSize2->value( ) );
+ m_pDisplayedObject->setAdaptive( m_pAdaptive->value( ) );
+ m_pDisplayedObject->setOrient( m_pOrient->isChecked( ) );
+ m_pDisplayedObject->setJitter( m_pJitter->isChecked( ) );
+ }
+ m_pDisplayedObject->setAreaLight( m_pAreaLight->isChecked( ) );
+
+ if( m_pFading->isChecked( ) )
+ {
+ m_pDisplayedObject->setFadePower( m_pFadePower->value( ) );
+ m_pDisplayedObject->setFadeDistance( m_pFadeDistance->value( ) );
+ }
+ m_pDisplayedObject->setFading( m_pFading->isChecked( ) );
+
+ m_pDisplayedObject->setMediaInteraction( m_pMediaInteraction->isChecked( ) );
+ m_pDisplayedObject->setMediaAttenuation( m_pMediaAttenuation->isChecked( ) );
+ }
+}
+
+bool PMLightEdit::isDataValid( )
+{
+ int index;
+ if( !m_pLocation->isDataValid( ) ) return false;
+ if( !m_pColor->isDataValid( ) ) return false;
+
+ index = m_pType->currentItem( );
+ if( ( index == 1 ) || ( index == 2 ) )
+ {
+ if( !m_pRadius->isDataValid( ) ) return false;
+ if( !m_pFalloff->isDataValid( ) ) return false;
+ if( !m_pTightness->isDataValid( ) ) return false;
+ if( !m_pPointAt->isDataValid( ) ) return false;
+ }
+ if( m_pAreaLight->isChecked( ) )
+ {
+ if( !m_pAxis1->isDataValid( ) ) return false;
+ if( !m_pAxis2->isDataValid( ) ) return false;
+ if( !m_pSize1->isDataValid( ) ) return false;
+ if( !m_pSize2->isDataValid( ) ) return false;
+ if( !m_pAdaptive->isDataValid( ) ) return false;
+ }
+ if( m_pFading->isChecked( ) )
+ {
+ if( !m_pFadeDistance->isDataValid( ) ) return false;
+ if( !m_pFadePower->isDataValid( ) ) return false;
+ }
+
+ return Base::isDataValid( );
+}
+
+void PMLightEdit::slotTypeActivated( int index )
+{
+ if( ( index == 1 ) || ( index == 2 ) )
+ {
+ m_pRadius->show( );
+ m_pRadiusLabel->show( );
+ m_pFalloff->show( );
+ m_pFalloffLabel->show( );
+ m_pTightness->show( );
+ m_pTightnessLabel->show( );
+ m_pPointAt->show( );
+ m_pPointAtLabel->show( );
+ }
+ else
+ {
+ m_pRadius->hide( );
+ m_pRadiusLabel->hide( );
+ m_pFalloff->hide( );
+ m_pFalloffLabel->hide( );
+ m_pTightness->hide( );
+ m_pTightnessLabel->hide( );
+ m_pPointAt->hide( );
+ m_pPointAtLabel->hide( );
+ }
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+void PMLightEdit::slotAreaClicked( )
+{
+ if( m_pAreaLight->isChecked( ) )
+ {
+ m_pAreaTypeLabel->show( );
+ m_pAreaType->show( );
+ m_pAxis1->show( );
+ m_pAxis1Label->show( );
+ m_pAxis2->show( );
+ m_pAxis2Label->show( );
+ m_pSize1->show( );
+ m_pSize1Label->show( );
+ m_pSize2->show( );
+ m_pSize2Label->show( );
+ m_pAdaptive->show( );
+ m_pAdaptiveLabel->show( );
+ m_pOrient->show( );
+ m_pOrient->setEnabled( orientEnabled( !m_pJitter->isEnabled( ) ) );
+ m_pJitter->show( );
+ }
+ else
+ {
+ m_pAreaTypeLabel->hide( );
+ m_pAreaType->hide( );
+ m_pAxis1->hide( );
+ m_pAxis1Label->hide( );
+ m_pAxis2->hide( );
+ m_pAxis2Label->hide( );
+ m_pSize1->hide( );
+ m_pSize1Label->hide( );
+ m_pSize2->hide( );
+ m_pSize2Label->hide( );
+ m_pAdaptive->hide( );
+ m_pAdaptiveLabel->hide( );
+ m_pOrient->hide( );
+ m_pJitter->hide( );
+ }
+
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+void PMLightEdit::slotOrientCheck( )
+{
+ m_pOrient->setEnabled( orientEnabled( !m_pJitter->isEnabled( ) ) );
+ emit dataChanged( );
+}
+
+void PMLightEdit::slotFadingClicked( )
+{
+ if( m_pFading->isChecked( ) )
+ {
+ m_pFadeDistance->show( );
+ m_pFadeDistanceLabel->show( );
+ m_pFadePower->show( );
+ m_pFadePowerLabel->show( );
+ }
+ else
+ {
+ m_pFadeDistance->hide( );
+ m_pFadeDistanceLabel->hide( );
+ m_pFadePower->hide( );
+ m_pFadePowerLabel->hide( );
+ }
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+bool PMLightEdit::orientEnabled( bool readOnly )
+{
+ if ( readOnly )
+ return false;
+
+ if ( m_pAreaLight )
+ {
+ if ( m_pAreaType->currentItem( ) == 1 )
+ {
+ int size1 = m_pSize1->value( );
+ int size2 = m_pSize2->value( );
+ if ( size1 > 1 && size2 > 1 && size1 == size2 )
+ {
+ if ( m_pAxis1->vector( ).abs( ) == m_pAxis2->vector( ).abs( ) )
+ return true;
+ }
+ }
+ }
+ m_pOrient->setChecked( false );
+ return false;
+}
+
+#include "pmlightedit.moc"
diff --git a/kpovmodeler/pmlightedit.h b/kpovmodeler/pmlightedit.h
new file mode 100644
index 00000000..0b9b5ffb
--- /dev/null
+++ b/kpovmodeler/pmlightedit.h
@@ -0,0 +1,115 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMLIGHTEDIT_H
+#define PMLIGHTEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmnamedobjectedit.h"
+
+class PMLight;
+class PMVectorEdit;
+class PMColorEdit;
+class QComboBox;
+class PMFloatEdit;
+class PMIntEdit;
+class QLabel;
+class QCheckBox;
+
+/**
+ * Dialog edit class for @ref PMLight
+ */
+class PMLightEdit : public PMNamedObjectEdit
+{
+ Q_OBJECT
+ typedef PMNamedObjectEdit Base;
+public:
+ /**
+ * Creates a PMLightEdit with parent and name
+ */
+ PMLightEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+public slots:
+ void slotTypeActivated( int index );
+ void slotAreaClicked( );
+ void slotOrientCheck( );
+ void slotFadingClicked( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ /**
+ * Returns true if orient should be enabled
+ */
+ bool orientEnabled( bool readOnly );
+
+ PMLight* m_pDisplayedObject;
+ PMVectorEdit* m_pLocation;
+ PMColorEdit* m_pColor;
+ QComboBox* m_pType;
+
+ PMFloatEdit* m_pRadius;
+ QLabel* m_pRadiusLabel;
+ PMFloatEdit* m_pFalloff;
+ QLabel* m_pFalloffLabel;
+ PMFloatEdit* m_pTightness;
+ QLabel* m_pTightnessLabel;
+
+ PMVectorEdit* m_pPointAt;
+ QLabel* m_pPointAtLabel;
+ QCheckBox* m_pParallel;
+
+ QCheckBox* m_pAreaLight;
+ QLabel* m_pAreaTypeLabel;
+ QComboBox* m_pAreaType;
+ PMVectorEdit* m_pAxis1;
+ PMIntEdit* m_pSize1;
+ PMVectorEdit* m_pAxis2;
+ PMIntEdit* m_pSize2;
+ QLabel* m_pAxis1Label;
+ QLabel* m_pAxis2Label;
+ QLabel* m_pSize1Label;
+ QLabel* m_pSize2Label;
+ PMIntEdit* m_pAdaptive;
+ QLabel* m_pAdaptiveLabel;
+ QCheckBox* m_pOrient;
+ QCheckBox* m_pJitter;
+
+ QCheckBox* m_pFading;
+ PMFloatEdit* m_pFadeDistance;
+ QLabel* m_pFadeDistanceLabel;
+ PMIntEdit* m_pFadePower;
+ QLabel* m_pFadePowerLabel;
+ QCheckBox* m_pMediaInteraction;
+ QCheckBox* m_pMediaAttenuation;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmlightgroup.cpp b/kpovmodeler/pmlightgroup.cpp
new file mode 100644
index 00000000..e53e0e3b
--- /dev/null
+++ b/kpovmodeler/pmlightgroup.cpp
@@ -0,0 +1,134 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmlightgroup.h"
+
+#include <klocale.h>
+#include "pmxmlhelper.h"
+#include "pmlightgroupedit.h"
+#include "pmmemento.h"
+
+PMDefinePropertyClass( PMLightGroup, PMLightGroupProperty );
+
+PMMetaObject* PMLightGroup::s_pMetaObject = 0;
+PMObject* createNewLightGroup( PMPart* part )
+{
+ return new PMLightGroup( part );
+}
+
+PMLightGroup::PMLightGroup( PMPart* part )
+ : Base( part )
+{
+ m_globalLights = false;
+}
+
+PMLightGroup::PMLightGroup( const PMLightGroup& lg )
+ : Base( lg )
+{
+ m_globalLights = lg.m_globalLights;
+}
+
+PMLightGroup::~PMLightGroup( )
+{
+}
+
+QString PMLightGroup::description( ) const
+{
+ return QString( i18n( "light group" ) );
+}
+
+void PMLightGroup::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ if( m_globalLights )
+ e.setAttribute( "global_lights", "1" );
+ else
+ e.setAttribute( "global_lights", "0" );
+
+ Base::serialize( e, doc );
+}
+
+void PMLightGroup::readAttributes( const PMXMLHelper& h )
+{
+ m_globalLights = h.boolAttribute( "global_lights", false );
+
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMLightGroup::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "LightGroup", Base::metaObject( ),
+ createNewLightGroup );
+
+ s_pMetaObject->addProperty( new PMLightGroupProperty( "globalLights",
+ &PMLightGroup::setGlobalLights, &PMLightGroup::globalLights ) );
+
+ }
+ return s_pMetaObject;
+}
+
+void PMLightGroup::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMLightGroup::setGlobalLights( bool gl )
+{
+ if( gl != m_globalLights )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMGlobalLightsID, m_globalLights );
+ m_globalLights = gl;
+ }
+}
+
+PMDialogEditBase* PMLightGroup::editWidget( QWidget* parent ) const
+{
+ return new PMLightGroupEdit( parent );
+}
+
+void PMLightGroup::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMGlobalLightsID:
+ setGlobalLights( data->boolData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMCSG::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
diff --git a/kpovmodeler/pmlightgroup.h b/kpovmodeler/pmlightgroup.h
new file mode 100644
index 00000000..f488eaf2
--- /dev/null
+++ b/kpovmodeler/pmlightgroup.h
@@ -0,0 +1,98 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMLIGHTGROUP_H
+#define PMLIGHTGROUP_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobject.h"
+
+/**
+ * Class for povray light group objects.
+ */
+
+class PMLightGroup : public PMSolidObject
+{
+ typedef PMSolidObject Base;
+public:
+ /**
+ * Creates an empty PMLightGroup object
+ */
+ PMLightGroup( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMLightGroup( const PMLightGroup& lg );
+
+ /**
+ * deletes the PMLightGroup object
+ */
+ virtual ~PMLightGroup( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMLightGroup( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMLightGroupEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmlightgroup" ); }
+
+ /**
+ * Returns the global lights flag
+ */
+ bool globalLights( ) const { return m_globalLights; }
+ /**
+ * Sets the global lights flag
+ */
+ void setGlobalLights( bool gl );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMGlobalLightsMementoID { PMGlobalLightsID };
+
+ bool m_globalLights;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmlightgroupedit.cpp b/kpovmodeler/pmlightgroupedit.cpp
new file mode 100644
index 00000000..18feffbe
--- /dev/null
+++ b/kpovmodeler/pmlightgroupedit.cpp
@@ -0,0 +1,78 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmlightgroupedit.h"
+#include "pmlightgroup.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <klocale.h>
+
+PMLightGroupEdit::PMLightGroupEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMLightGroupEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* layout;
+ m_pGlobalLights = new QCheckBox( i18n( "Global lights" ), this );
+
+ layout = new QHBoxLayout( topLayout( ) );
+ layout->addWidget( m_pGlobalLights );
+ layout->addStretch( 1 );
+
+ connect( m_pGlobalLights, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMLightGroupEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "LightGroup" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMLightGroup* ) o;
+
+ m_pGlobalLights->setChecked( m_pDisplayedObject->globalLights( ) );
+ m_pGlobalLights->setEnabled( !readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMLightGroupEdit: Can't display object\n";
+}
+
+void PMLightGroupEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+
+ m_pDisplayedObject->setGlobalLights( m_pGlobalLights->isChecked( ) );
+ }
+}
+
+bool PMLightGroupEdit::isDataValid( )
+{
+ return Base::isDataValid( );
+}
+
+#include "pmlightgroupedit.moc"
diff --git a/kpovmodeler/pmlightgroupedit.h b/kpovmodeler/pmlightgroupedit.h
new file mode 100644
index 00000000..2701d681
--- /dev/null
+++ b/kpovmodeler/pmlightgroupedit.h
@@ -0,0 +1,64 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMLIGHTGROUPEDIT_H
+#define PMLIGHTGROUPEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobjectedit.h"
+
+class PMLightGroup;
+class QCheckBox;
+
+/**
+ * Dialog edit class for @ref PMLightGroup
+ */
+class PMLightGroupEdit : public PMSolidObjectEdit
+{
+ Q_OBJECT
+ typedef PMSolidObjectEdit Base;
+public:
+ /**
+ * Creates a PMLightGroupEdit with parent and name
+ */
+ PMLightGroupEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+protected slots:
+
+private:
+ PMLightGroup* m_pDisplayedObject;
+
+ QCheckBox* m_pGlobalLights;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmline.cpp b/kpovmodeler/pmline.cpp
new file mode 100644
index 00000000..27ff752d
--- /dev/null
+++ b/kpovmodeler/pmline.cpp
@@ -0,0 +1,22 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmline.h"
+
+
+// nothing to be done here at the moment
diff --git a/kpovmodeler/pmline.h b/kpovmodeler/pmline.h
new file mode 100644
index 00000000..399555ea
--- /dev/null
+++ b/kpovmodeler/pmline.h
@@ -0,0 +1,102 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMLINES_H
+#define PMLINES_H
+
+#include <qptrlist.h>
+#include <GL/gl.h>
+#include "pmdebug.h"
+
+/**
+ * Line to display with index of start and end point.
+ *
+ * Line of a @ref PMViewStructure. Only the indices in a @ref PMPointArray
+ * are stored.
+ *
+ * Optimized for OpenGL
+ */
+class PMLine
+{
+public:
+ /**
+ * Default constructor
+ */
+ PMLine( )
+ {
+ m_start = 0;
+ m_end = 0;
+ }
+ /**
+ * Creates a line with start point si and end point ei. If si is greater
+ * than ei, si and ei are swapped.
+ */
+ PMLine( const GLuint si, const GLuint ei )
+ { m_start = si; m_end = ei; checkPoints( ); }
+
+ /**
+ * Sets the start point.
+ */
+ void setStartPoint( GLuint si ) { m_start = si; checkPoints( ); }
+ /**
+ * Sets the end point.
+ */
+ void setEndPoint( GLuint ei ) { m_end = ei; checkPoints( ); }
+ /**
+ * Returns the start point.
+ */
+ GLuint startPoint( ) const { return m_start; }
+ /**
+ * Returns the end point.
+ */
+ GLuint endPoint( ) const { return m_end; }
+
+private:
+ /**
+ * Swaps the two points.
+ */
+ void swapPoints( ) { GLuint help = m_start; m_start = m_end; m_end = help; }
+ /**
+ * Checks, if si < ei and swaps the two points if necessary
+ */
+ void checkPoints( )
+ {
+ if( m_start == m_end ) kdError( PMArea ) << "Start index = end index in PMLine" << "\n";
+ if( m_start > m_end ) swapPoints( );
+ }
+ /**
+ * The start and end points (indices!)
+ *
+ * THESE MEMBERS HAVE TO BE THE ONLY ONE (for rendering with OpenGl)
+ */
+ GLuint m_start, m_end;
+};
+
+typedef QPtrListIterator<PMLine> PMLineListIterator;
+
+/**
+ * A list of @ref PMLine objects.
+ *
+ * This class stores all lines of a @ref PMViewStructure. A line is
+ * described by a start and end point. Only the indices in a @ref PMPointArray
+ * are stored.
+ */
+typedef QMemArray<PMLine> PMLineArray;
+
+#endif
diff --git a/kpovmodeler/pmlineedits.cpp b/kpovmodeler/pmlineedits.cpp
new file mode 100644
index 00000000..05124d75
--- /dev/null
+++ b/kpovmodeler/pmlineedits.cpp
@@ -0,0 +1,229 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmlineedits.h"
+#include <kmessagebox.h>
+#include <klocale.h>
+
+PMFloatEdit::PMFloatEdit( QWidget* parent, const char* name /*= 0*/ )
+ : QLineEdit( parent, name )
+{
+ m_bCheckLower = false;
+ m_bCheckUpper = false;
+ m_lowerValue = 0;
+ m_upperValue = 0;
+ m_lowerOp = OpGreaterEqual;
+ m_upperOp = OpLessEqual;
+
+ connect( this, SIGNAL( textChanged( const QString& ) ),
+ SLOT( slotEditTextChanged( const QString& ) ) );
+}
+
+void PMFloatEdit::setValidation( bool checkLower, double lowerValue,
+ bool checkUpper, double upperValue )
+{
+ m_bCheckLower = checkLower;
+ m_bCheckUpper = checkUpper;
+ m_lowerValue = lowerValue;
+ m_upperValue = upperValue;
+}
+
+void PMFloatEdit::setValidationOperator( ValidationOp l, ValidationOp u )
+{
+ m_lowerOp = l;
+ m_upperOp = u;
+}
+
+bool PMFloatEdit::isDataValid( )
+{
+ bool ok = true;
+ double d;
+ d = text( ).toDouble( &ok );
+
+ if( ok )
+ {
+ if( m_bCheckLower )
+ ok = ok && ( m_lowerOp == OpGreaterEqual ?
+ d >= m_lowerValue : d > m_lowerValue );
+ if( m_bCheckUpper )
+ ok = ok && ( m_upperOp == OpLessEqual ?
+ d <= m_upperValue : d < m_upperValue );
+ if( !ok )
+ {
+ if( m_bCheckLower && m_bCheckUpper )
+ KMessageBox::error( this, i18n( "Please enter a float value "
+ "between %1 and %2" )
+ .arg( m_lowerValue ).arg( m_upperValue ),
+ i18n( "Error" ) );
+ else if( m_bCheckLower )
+ {
+ if( m_lowerOp == OpGreaterEqual )
+ KMessageBox::error( this, i18n( "Please enter a float value "
+ ">= %1" ).arg( m_lowerValue ),
+ i18n( "Error" ) );
+ else
+ KMessageBox::error( this, i18n( "Please enter a float value "
+ "> %1" ).arg( m_lowerValue ),
+ i18n( "Error" ) );
+ }
+ else
+ {
+ if( m_upperOp == OpLessEqual )
+ KMessageBox::error( this, i18n( "Please enter a float value "
+ "<= %1" ).arg( m_upperValue ),
+ i18n( "Error" ) );
+ else
+ KMessageBox::error( this, i18n( "Please enter a float value "
+ "< %1" ).arg( m_upperValue ),
+ i18n( "Error" ) );
+ }
+ }
+ }
+ else
+ {
+ KMessageBox::error( this, i18n( "Please enter a valid float value!" ),
+ i18n( "Error" ) );
+ }
+
+ if( !ok )
+ {
+ setFocus( );
+ selectAll( );
+ }
+ return ok;
+}
+
+double PMFloatEdit::value( ) const
+{
+ return text( ).toDouble( );
+}
+
+void PMFloatEdit::setValue( double d, int precision )
+{
+ QString str;
+
+ str.setNum( d, 'g', precision );
+ setText( str );
+}
+
+void PMFloatEdit::slotEditTextChanged( const QString& /*t*/ )
+{
+ emit dataChanged( );
+}
+
+
+
+
+
+PMIntEdit::PMIntEdit( QWidget* parent, const char* name /*= 0*/ )
+ : QLineEdit( parent, name )
+{
+ m_bCheckLower = false;
+ m_bCheckUpper = false;
+ m_lowerValue = 0;
+ m_upperValue = 0;
+
+ connect( this, SIGNAL( textChanged( const QString& ) ),
+ SLOT( slotEditTextChanged( const QString& ) ) );
+}
+
+void PMIntEdit::setValidation( bool checkLower, int lowerValue,
+ bool checkUpper, int upperValue )
+{
+ m_bCheckLower = checkLower;
+ m_bCheckUpper = checkUpper;
+ m_lowerValue = lowerValue;
+ m_upperValue = upperValue;
+}
+
+bool PMIntEdit::isDataValid( )
+{
+ bool ok = true;
+ int i;
+ double d;
+
+ i = text( ).toInt( &ok );
+ if( !ok )
+ {
+ d = text( ).toDouble( &ok );
+ if( ok )
+ {
+ i = ( int ) d;
+ QString str;
+ bool b = signalsBlocked( );
+ blockSignals( true );
+ str.setNum( i );
+ setText( str );
+ blockSignals( b );
+ }
+ }
+
+ if( ok )
+ {
+ if( m_bCheckLower )
+ ok = ok && ( i >= m_lowerValue );
+ if( m_bCheckUpper )
+ ok = ok && ( i <= m_upperValue );
+ if( !ok )
+ {
+ if( m_bCheckLower && m_bCheckUpper )
+ KMessageBox::error( this, i18n( "Please enter an integer value "
+ "between %1 and %2" )
+ .arg( m_lowerValue ).arg( m_upperValue ),
+ i18n( "Error" ) );
+ else if( m_bCheckLower )
+ KMessageBox::error( this, i18n( "Please enter an integer value "
+ ">= %1" ).arg( m_lowerValue ),
+ i18n( "Error" ) );
+ else
+ KMessageBox::error( this, i18n( "Please enter an integer value "
+ "<= %1" ).arg( m_upperValue ),
+ i18n( "Error" ) );
+ }
+ }
+ else
+ {
+ KMessageBox::error( this, i18n( "Please enter a valid integer value!" ),
+ i18n( "Error" ) );
+ }
+
+ if( !ok )
+ {
+ setFocus( );
+ selectAll( );
+ }
+ return ok;
+}
+
+int PMIntEdit::value( ) const
+{
+ return text( ).toInt( );
+}
+
+void PMIntEdit::setValue( int i )
+{
+ QString str;
+
+ str.setNum( i );
+ setText( str );
+}
+
+void PMIntEdit::slotEditTextChanged( const QString& /*t*/ )
+{
+ emit dataChanged( );
+}
+#include "pmlineedits.moc"
diff --git a/kpovmodeler/pmlineedits.h b/kpovmodeler/pmlineedits.h
new file mode 100644
index 00000000..9a12c384
--- /dev/null
+++ b/kpovmodeler/pmlineedits.h
@@ -0,0 +1,133 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PM_LINEEDITS_H
+#define PM_LINEEDITS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qlineedit.h>
+
+/**
+ * Lineedit for float input
+ */
+
+class PMFloatEdit : public QLineEdit
+{
+ Q_OBJECT
+public:
+ enum ValidationOp { OpGreater, OpGreaterEqual,
+ OpLess, OpLessEqual };
+ /**
+ * Simple constructor
+ */
+ PMFloatEdit( QWidget* parent, const char* name = 0 );
+ /**
+ * Sets the validation for the lineedit.
+ *
+ * If checkLower is true, the value has to be >= the lowerValue.
+ *
+ * If checkUpper is true, the value has to be <= the upperValue.
+ *
+ * By default no range check is made.
+ */
+ void setValidation( bool checkLower, double lowerValue,
+ bool checkUpper, double upperValue );
+ /**
+ * Sets the validation operators for the lower and upper value.
+ *
+ * Valid values for lower are OpGreater and OpGreaterEqual,
+ * valid values for upper are OpLess and OpLessEqual.
+ */
+ void setValidationOperator( ValidationOp lower, ValidationOp upper );
+ /**
+ * Returns true, if the text is a valid float in the valid range
+ */
+ bool isDataValid( );
+ /**
+ * Returns the float value
+ */
+ double value( ) const;
+ /**
+ * Sets the value
+ */
+ void setValue( double d, int precision = 5 );
+signals:
+ /**
+ * emitted if the text is changed
+ */
+ void dataChanged( );
+public slots:
+ void slotEditTextChanged( const QString& t );
+private:
+ bool m_bCheckLower, m_bCheckUpper;
+ double m_lowerValue, m_upperValue;
+ ValidationOp m_lowerOp, m_upperOp;
+};
+
+
+/**
+ * Lineedit for int input
+ */
+
+class PMIntEdit : public QLineEdit
+{
+ Q_OBJECT
+public:
+ /**
+ * Simple constructor
+ */
+ PMIntEdit( QWidget* parent, const char* name = 0 );
+ /**
+ * Sets the validation for the lineedit.
+ *
+ * If checkLower is true, the value has to be >= the lowerValue.
+ *
+ * If checkUpper is true, the value has to be <= the upperValue.
+ *
+ * By default no range check is made.
+ */
+ void setValidation( bool checkLower, int lowerValue,
+ bool checkUpper, int upperValue );
+ /**
+ * Returns true, if the text is a valid integer in the valid range
+ */
+ bool isDataValid( );
+ /**
+ * Returns the integer value
+ */
+ int value( ) const;
+ /**
+ * Sets the value
+ */
+ void setValue( int i );
+signals:
+ /**
+ * emitted if the text is changed
+ */
+ void dataChanged( );
+public slots:
+ void slotEditTextChanged( const QString& t );
+private:
+ bool m_bCheckLower, m_bCheckUpper;
+ int m_lowerValue, m_upperValue;
+};
+
+#endif
diff --git a/kpovmodeler/pmlinkedit.cpp b/kpovmodeler/pmlinkedit.cpp
new file mode 100644
index 00000000..a878e02e
--- /dev/null
+++ b/kpovmodeler/pmlinkedit.cpp
@@ -0,0 +1,146 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmlinkedit.h"
+#include <qlineedit.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <klocale.h>
+#include <kdialog.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+#include "pmdeclare.h"
+#include "pmobjectselect.h"
+
+PMLinkEdit::PMLinkEdit( const QString& declareType,
+ QWidget* parent, const char* name )
+ : QWidget( parent, name )
+{
+ m_declareTypes.append( declareType );
+ init( );
+}
+
+PMLinkEdit::PMLinkEdit( const QStringList& declareTypes,
+ QWidget* parent, const char* name )
+ : QWidget( parent, name )
+{
+ m_declareTypes = declareTypes;
+ init( );
+}
+
+PMLinkEdit::PMLinkEdit( QWidget* parent, const char* name )
+ : QWidget( parent, name )
+{
+ init( );
+}
+
+void PMLinkEdit::init( )
+{
+ m_pDeclare = 0;
+ m_pDisplayedObject = 0;
+ m_bReadOnly = false;
+
+ QGridLayout* grid = new QGridLayout( this, 2, 2, 0, KDialog::spacingHint( ) );
+
+ grid->addWidget( new QLabel( i18n( "Prototype:" ), this ), 0, 0 );
+ grid->setColStretch( 0, 0 );
+ grid->setColStretch( 1, 1 );
+ m_pIDEdit = new QLineEdit( this );
+ m_pIDEdit->setReadOnly( true );
+ grid->addWidget( m_pIDEdit, 0, 1 );
+
+ QHBoxLayout* layout = new QHBoxLayout( );
+ grid->addLayout( layout, 1, 1 );
+ m_pSelectButton = new QPushButton( i18n( "Select..." ), this );
+ layout->addWidget( m_pSelectButton );
+ m_pClearButton = new KPushButton( KStdGuiItem::clear(), this );
+ layout->addWidget( m_pClearButton );
+
+ connect( m_pSelectButton, SIGNAL( clicked( ) ), SLOT( slotSelectClicked( ) ) );
+ connect( m_pClearButton, SIGNAL( clicked( ) ), SLOT( slotClearClicked( ) ) );
+}
+
+void PMLinkEdit::setDisplayedObject( PMObject* obj )
+{
+ m_pDisplayedObject = obj;
+ m_pDeclare = obj->linkedObject( );
+ if( m_pDeclare )
+ {
+ m_pIDEdit->setText( m_pDeclare->id( ) );
+ if( !m_bReadOnly )
+ m_pClearButton->setEnabled( true );
+ }
+ else
+ {
+ m_pIDEdit->clear( );
+ if( !m_bReadOnly )
+ m_pClearButton->setEnabled( false );
+ }
+}
+
+void PMLinkEdit::setLinkPossibility( const QString& t )
+{
+ m_declareTypes.clear( );
+ m_declareTypes.append( t );
+}
+
+
+void PMLinkEdit::setLinkPossibilities( const QStringList& t )
+{
+ m_declareTypes = t;
+}
+
+void PMLinkEdit::setReadOnly( bool yes )
+{
+ m_bReadOnly = yes;
+ m_pClearButton->setEnabled( !m_bReadOnly && m_pDeclare );
+ m_pSelectButton->setEnabled( !m_bReadOnly );
+}
+
+void PMLinkEdit::slotSelectClicked( )
+{
+ if( m_pDisplayedObject )
+ {
+ PMObject* obj = 0;
+ int result;
+
+ if( m_declareTypes.count( ) == 1 )
+ result = PMObjectSelect::selectDeclare(
+ m_pDisplayedObject, m_declareTypes.first( ), obj, this );
+ else
+ result = PMObjectSelect::selectDeclare(
+ m_pDisplayedObject, m_declareTypes, obj, this );
+
+ if( ( result == QDialog::Accepted ) && obj )
+ {
+ m_pDeclare = ( PMDeclare* ) obj;
+ m_pIDEdit->setText( m_pDeclare->id( ) );
+ m_pClearButton->setEnabled( true );
+ emit dataChanged( );
+ }
+ }
+}
+
+void PMLinkEdit::slotClearClicked( )
+{
+ m_pDeclare = 0;
+ m_pIDEdit->clear( );
+ emit dataChanged( );
+}
+
+#include "pmlinkedit.moc"
diff --git a/kpovmodeler/pmlinkedit.h b/kpovmodeler/pmlinkedit.h
new file mode 100644
index 00000000..f5abe182
--- /dev/null
+++ b/kpovmodeler/pmlinkedit.h
@@ -0,0 +1,105 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMLINKEDIT_H
+#define PMLINKEDIT_H
+
+#include <qwidget.h>
+#include "pmobject.h"
+#include "pmdeclare.h"
+
+#include <qvaluelist.h>
+
+class QString;
+class QLineEdit;
+class QPushButton;
+
+/**
+ * Edit widget for links with a QLineEdit, a select and a clear button.
+ */
+class PMLinkEdit : public QWidget
+{
+ Q_OBJECT
+public:
+ /**
+ * Creates a link edit widget with parent and name.
+ *
+ * Allows the selection of declares of type declareType.
+ */
+ PMLinkEdit( const QString& declareType, QWidget* parent, const char* name = 0 );
+ /**
+ * Creates a link edit widget with parent and name.
+ *
+ * Allows the selection of declares of type declares.
+ */
+ PMLinkEdit( const QStringList& declares, QWidget* parent, const char* name = 0 );
+ /**
+ * Creates a link edit widget with parent and name.
+ */
+ PMLinkEdit( QWidget* parent, const char* name = 0 );
+
+ /**
+ * Sets the displayed object and displays the link
+ */
+ void setDisplayedObject( PMObject* obj );
+ /**
+ * Returns the selected link
+ */
+ PMDeclare* link( ) const { return m_pDeclare; }
+
+ /**
+ * Sets the selection possibilities
+ */
+ void setLinkPossibility( const QString& t );
+ /**
+ * Sets the selection possibilities
+ */
+ void setLinkPossibilities( const QStringList& t );
+
+ /**
+ * Enables or disables read only mode
+ */
+ void setReadOnly( bool yes = true );
+signals:
+ /**
+ * Emitted when the link is changed
+ */
+ void dataChanged( );
+
+public slots:
+ /**
+ * Called when the select button is clicked
+ */
+ void slotSelectClicked( );
+ /**
+ * Called when the clear button is clicked
+ */
+ void slotClearClicked( );
+
+private:
+ void init( );
+ PMDeclare* m_pDeclare;
+ PMObject* m_pDisplayedObject;
+ QStringList m_declareTypes;
+
+ QLineEdit* m_pIDEdit;
+ QPushButton* m_pSelectButton;
+ QPushButton* m_pClearButton;
+ bool m_bReadOnly;
+};
+
+#endif
diff --git a/kpovmodeler/pmlistpattern.cpp b/kpovmodeler/pmlistpattern.cpp
new file mode 100644
index 00000000..299ab4fb
--- /dev/null
+++ b/kpovmodeler/pmlistpattern.cpp
@@ -0,0 +1,469 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmlistpattern.h"
+
+#include "pmxmlhelper.h"
+#include "pmlistpatternedit.h"
+#include "pmcompositeobject.h"
+#include "pmmemento.h"
+#include "pmenumproperty.h"
+
+#include <klocale.h>
+
+PMDefinePropertyClass( PMListPattern, PMListPatternProperty );
+PMDefineEnumPropertyClass( PMListPattern, PMListPattern::PMListType,
+ PMListTypeProperty );
+
+const PMVector brickSizeDefault = PMVector( 8, 6, 4.5 );
+const double mortarDefault = 0.5;
+const double depthDefault = 0;
+
+PMMetaObject* PMListPattern::s_pMetaObject = 0;
+PMMetaObject* PMColorList::s_pMetaObject = 0;
+PMObject* createNewColorList( PMPart* part )
+{
+ return new PMColorList( part );
+}
+PMMetaObject* PMDensityList::s_pMetaObject = 0;
+PMObject* createNewDensityList( PMPart* part )
+{
+ return new PMDensityList( part );
+}
+PMMetaObject* PMNormalList::s_pMetaObject = 0;
+PMObject* createNewNormalList( PMPart* part )
+{
+ return new PMNormalList( part );
+}
+PMMetaObject* PMPigmentList::s_pMetaObject = 0;
+PMObject* createNewPigmentList( PMPart* part )
+{
+ return new PMPigmentList( part );
+}
+PMMetaObject* PMTextureList::s_pMetaObject = 0;
+PMObject* createNewTextureList( PMPart* part )
+{
+ return new PMTextureList( part );
+}
+
+PMListPattern::PMListPattern( PMPart* part )
+ : Base( part )
+{
+ m_listType = ListPatternChecker;
+ m_brickSize = brickSizeDefault;
+ m_mortar = mortarDefault;
+}
+
+PMListPattern::PMListPattern( const PMListPattern& p )
+ : Base( p )
+{
+ m_listType = p.m_listType;
+ m_brickSize = p.m_brickSize;
+ m_mortar = p.m_mortar;
+}
+
+PMListPattern::~PMListPattern( )
+{
+}
+
+void PMListPattern::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ switch( m_listType )
+ {
+ case ListPatternBrick:
+ e.setAttribute( "listtype", "brick" );
+ break;
+ case ListPatternChecker:
+ e.setAttribute( "listtype", "checker" );
+ break;
+ case ListPatternHexagon:
+ e.setAttribute( "listtype", "hexagon" );
+ break;
+ };
+ e.setAttribute( "bricksize", m_brickSize.serializeXML( ) );
+ e.setAttribute( "mortar", m_mortar );
+ Base::serialize( e, doc );
+}
+
+void PMListPattern::readAttributes( const PMXMLHelper& h )
+{
+ QString str = h.stringAttribute( "listtype", "checker" );
+ if( str == "checker" )
+ m_listType = ListPatternChecker;
+ else if( str == "brick" )
+ m_listType = ListPatternBrick;
+ else
+ m_listType = ListPatternHexagon;
+ m_brickSize = h.vectorAttribute( "bricksize", brickSizeDefault );
+ m_mortar = h.doubleAttribute( "mortar", mortarDefault );
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMListPattern::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "ListPattern", Base::metaObject( ) );
+
+ PMListTypeProperty* p = new PMListTypeProperty(
+ "listType", &PMListPattern::setListType,
+ &PMListPattern::listType );
+ p->addEnumValue( QString( "Checker" ), ListPatternChecker );
+ p->addEnumValue( QString( "Brick" ), ListPatternBrick );
+ p->addEnumValue( QString( "Hexagon" ), ListPatternHexagon );
+ s_pMetaObject->addProperty( p );
+
+ s_pMetaObject->addProperty(
+ new PMListPatternProperty( "brickSize", &PMListPattern::setBrickSize,
+ &PMListPattern::brickSize ) );
+ s_pMetaObject->addProperty(
+ new PMListPatternProperty( "mortar", &PMListPattern::setMortar,
+ &PMListPattern::mortar ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMListPattern::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMListPattern::setListType( PMListType l )
+{
+ if( l != m_listType )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMListTypeID, m_listType );
+ m_listType = l;
+ }
+}
+
+void PMListPattern::setBrickSize( const PMVector& n )
+{
+ if( n != m_brickSize )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMBrickSizeID, m_brickSize );
+ m_brickSize = n;
+ }
+}
+
+void PMListPattern::setMortar( double n )
+{
+ if( n != m_mortar )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMMortarID, m_mortar );
+ m_mortar = n;
+ }
+}
+
+PMDialogEditBase* PMListPattern::editWidget( QWidget* parent ) const
+{
+ return new PMListPatternEdit( parent );
+}
+
+void PMListPattern::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMListTypeID:
+ setListType( ( PMListType ) data->intData( ) );
+ break;
+ case PMBrickSizeID:
+ setBrickSize( data->vectorData( ) );
+ break;
+ case PMMortarID:
+ setMortar( data->doubleData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMListPattern::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
+
+PMTextureList::PMTextureList( PMPart* part )
+ : Base( part )
+{
+}
+
+PMTextureList::PMTextureList( const PMTextureList& l )
+ : Base( l )
+{
+}
+
+PMTextureList::~PMTextureList( )
+{
+}
+
+PMMetaObject* PMTextureList::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "TextureList", Base::metaObject( ),
+ createNewTextureList );
+ }
+ return s_pMetaObject;
+}
+
+void PMTextureList::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMTextureList::description( ) const
+{
+ return i18n( "texture list" );
+}
+
+PMPigmentList::PMPigmentList( PMPart* part )
+ : Base( part )
+{
+}
+
+PMPigmentList::PMPigmentList( const PMPigmentList& l )
+ : Base( l )
+{
+}
+
+PMPigmentList::~PMPigmentList( )
+{
+}
+
+PMMetaObject* PMPigmentList::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "PigmentList", Base::metaObject( ),
+ createNewPigmentList );
+ }
+ return s_pMetaObject;
+}
+
+void PMPigmentList::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMPigmentList::description( ) const
+{
+ return i18n( "pigment list" );
+}
+
+PMColorList::PMColorList( PMPart* part )
+ : Base( part )
+{
+}
+
+PMColorList::PMColorList( const PMColorList& l )
+ : Base( l )
+{
+}
+
+PMColorList::~PMColorList( )
+{
+}
+
+PMMetaObject* PMColorList::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "ColorList", Base::metaObject( ),
+ createNewColorList );
+ }
+ return s_pMetaObject;
+}
+
+void PMColorList::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMColorList::description( ) const
+{
+ return i18n( "color list" );
+}
+
+PMDensityList::PMDensityList( PMPart* part )
+ : Base( part )
+{
+}
+
+PMDensityList::PMDensityList( const PMDensityList& l )
+ : Base( l )
+{
+}
+
+PMDensityList::~PMDensityList( )
+{
+}
+
+PMMetaObject* PMDensityList::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "DensityList", Base::metaObject( ),
+ createNewDensityList );
+ }
+ return s_pMetaObject;
+}
+
+void PMDensityList::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMDensityList::description( ) const
+{
+ return i18n( "density list" );
+}
+
+PMDefinePropertyClass( PMNormalList, PMNormalListProperty );
+
+PMNormalList::PMNormalList( PMPart* part )
+ : Base( part )
+{
+ m_depth = depthDefault;
+}
+
+PMNormalList::PMNormalList( const PMNormalList& l )
+ : Base( l )
+{
+ m_depth = depthDefault;
+}
+
+PMNormalList::~PMNormalList( )
+{
+}
+
+PMMetaObject* PMNormalList::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "NormalList", Base::metaObject( ),
+ createNewNormalList );
+ s_pMetaObject->addProperty(
+ new PMNormalListProperty( "depth", &PMNormalList::setDepth,
+ &PMNormalList::depth ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMNormalList::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMNormalList::description( ) const
+{
+ return i18n( "normal list" );
+}
+
+void PMNormalList::setDepth( double d )
+{
+ if( d != m_depth )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMDepthID, m_depth );
+ m_depth = d;
+ }
+}
+
+void PMNormalList::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMDepthID:
+ setDepth( data->doubleData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMNormalList::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
+void PMNormalList::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "depth", m_depth );
+ Base::serialize( e, doc );
+}
+
+void PMNormalList::readAttributes( const PMXMLHelper& h )
+{
+ m_depth = h.doubleAttribute( "depth", depthDefault );
+ Base::readAttributes( h );
+}
+
+PMDialogEditBase* PMNormalList::editWidget( QWidget* parent ) const
+{
+ return new PMListPatternEdit( parent );
+}
+
diff --git a/kpovmodeler/pmlistpattern.h b/kpovmodeler/pmlistpattern.h
new file mode 100644
index 00000000..f646d8ab
--- /dev/null
+++ b/kpovmodeler/pmlistpattern.h
@@ -0,0 +1,351 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001-2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMLISTPATTERN_H
+#define PMLISTPATTERN_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmcompositeobject.h"
+#include "pmvector.h"
+
+/**
+ * Base class for povray lists.
+ */
+
+class PMListPattern : public PMCompositeObject
+{
+ typedef PMCompositeObject Base;
+public:
+ /**
+ * The type of the pigment list
+ */
+ enum PMListType { ListPatternChecker, ListPatternBrick, ListPatternHexagon };
+ /**
+ * Creates a PMListPattern
+ */
+ PMListPattern( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMListPattern( const PMListPattern& p );
+ /**
+ * deletes the PMListPattern
+ */
+ virtual ~PMListPattern( );
+
+ /**
+ * Returns the list pattern object type
+ */
+ virtual QString listObjectType( ) const = 0;
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMListPatternEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+
+ /**
+ * Returns the color list type
+ */
+ PMListType listType( ) const { return m_listType; }
+ /**
+ * Returns the brick size
+ */
+ PMVector brickSize( ) const { return m_brickSize; }
+ /**
+ * Returns the mortar size
+ */
+ double mortar( ) const { return m_mortar; }
+
+ /**
+ * Sets the list type
+ */
+ void setListType( PMListType l );
+ /**
+ * Sets the brick size
+ */
+ void setBrickSize( const PMVector& n );
+ /**
+ * Sets the mortar size
+ */
+ void setMortar( double n );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMListPatternMementoID { PMListTypeID, PMBrickSizeID, PMMortarID };
+ /**
+ * List type
+ */
+ PMListType m_listType;
+ /**
+ * Brick Size
+ */
+ PMVector m_brickSize;
+ /**
+ * Mortar Size
+ */
+ double m_mortar;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+/**
+ * Class for texture lists
+ */
+
+class PMTextureList : public PMListPattern
+{
+public:
+ typedef PMListPattern Base;
+ /**
+ * Creates a texture list
+ */
+ PMTextureList( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMTextureList( const PMTextureList& l );
+ /**
+ * Deletes the texture list
+ */
+ virtual ~PMTextureList( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMTextureList( *this ); }
+ /** */
+ virtual QString description( ) const;
+ /** */
+ virtual QString listObjectType( ) const { return QString( "Texture" ); }
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmtexturelist" ); }
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+/**
+ * Class for pigment lists
+ */
+
+class PMPigmentList : public PMListPattern
+{
+public:
+ typedef PMListPattern Base;
+ /**
+ * Creates a pigment list
+ */
+ PMPigmentList( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMPigmentList( const PMPigmentList& l );
+ /**
+ * Deletes the pigment list
+ */
+ virtual ~PMPigmentList( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMPigmentList( *this ); }
+ /** */
+ virtual QString description( ) const;
+ /** */
+ virtual QString listObjectType( ) const { return QString( "Pigment" ); }
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmpigmentlist" ); }
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+/**
+ * Class for color lists
+ */
+
+class PMColorList : public PMListPattern
+{
+public:
+ typedef PMListPattern Base;
+ /**
+ * Creates a color list
+ */
+ PMColorList( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMColorList( const PMColorList& l );
+ /**
+ * Deletes the color list
+ */
+ virtual ~PMColorList( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMColorList( *this ); }
+ /** */
+ virtual QString description( ) const;
+ /** */
+ virtual QString listObjectType( ) const { return QString( "SolidColor" ); }
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmcolorlist" ); }
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+/**
+ * Class for density lists
+ */
+
+class PMDensityList : public PMListPattern
+{
+public:
+ typedef PMListPattern Base;
+ /**
+ * Creates a density list
+ */
+ PMDensityList( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMDensityList( const PMDensityList& l );
+ /**
+ * Deletes the density list
+ */
+ virtual ~PMDensityList( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMDensityList( *this ); }
+ /** */
+ virtual QString description( ) const;
+ /** */
+ virtual QString listObjectType( ) const { return QString( "Density" ); }
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmdensitylist" ); }
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+/**
+ * Class for normal lists
+ */
+
+class PMNormalList : public PMListPattern
+{
+public:
+ typedef PMListPattern Base;
+ /**
+ * Creates a normal list
+ */
+ PMNormalList( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMNormalList( const PMNormalList& l );
+ /**
+ * Deletes the normal list
+ */
+ virtual ~PMNormalList( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMNormalList( *this ); }
+ /** */
+ virtual QString description( ) const;
+ /** */
+ virtual QString listObjectType( ) const { return QString( "Normal" ); }
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /**
+ * Returns a new @ref PMListPatternEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmnormallist" ); }
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+
+ /**
+ * Returns the normal's depth
+ */
+ double depth( ) const { return m_depth; }
+ /**
+ * Sets the normal's depth
+ */
+ void setDepth( double d );
+
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMNormalListMementoID { PMDepthID };
+ /**
+ * Normal Depth
+ */
+ double m_depth;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmlistpatternedit.cpp b/kpovmodeler/pmlistpatternedit.cpp
new file mode 100644
index 00000000..f9eb3cf7
--- /dev/null
+++ b/kpovmodeler/pmlistpatternedit.cpp
@@ -0,0 +1,225 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmlistpatternedit.h"
+#include "pmlistpattern.h"
+#include "pmvectoredit.h"
+#include "pmvector.h"
+
+#include <qwidget.h>
+#include <qlayout.h>
+#include <qcombobox.h>
+#include <qlabel.h>
+#include "pmlineedits.h"
+#include <ktabctl.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+
+PMListPatternEdit::PMListPatternEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMListPatternEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QVBoxLayout* vlayout = new QVBoxLayout( topLayout( ) );
+
+ /* Field for Pattern List type */
+ QHBoxLayout* layout = new QHBoxLayout( vlayout );
+ QLabel* label = new QLabel( i18n( "Type:" ), this );
+ m_pTypeCombo = new QComboBox( false, this );
+ m_pTypeCombo->insertItem( i18n( "Checkers" ) );
+ m_pTypeCombo->insertItem( i18n( "Brick" ) );
+ m_pTypeCombo->insertItem( i18n( "Hexagon" ) );
+ layout->addWidget( label, 0, AlignTop );
+ layout->addWidget( m_pTypeCombo );
+ layout->addStretch( 1 );
+
+ /* The depth field */
+ layout = new QHBoxLayout( vlayout );
+ m_pDepthLabel = new QLabel( i18n( "Depth:" ), this );
+ m_pDepth = new PMFloatEdit( this );
+ layout->addWidget( m_pDepthLabel );
+ layout->addWidget( m_pDepth );
+ layout->addStretch( 1 );
+
+ /* The brick information */
+ QHBoxLayout* bricklayout = new QHBoxLayout( vlayout );
+ m_pBrickSizeLabel = new QLabel( i18n( "Brick size:" ), this );
+ m_pBrickSize = new PMVectorEdit( "x", "y", "z", this );
+ bricklayout->addWidget( m_pBrickSizeLabel );
+ bricklayout->addWidget( m_pBrickSize );
+ layout = new QHBoxLayout( vlayout );
+ m_pMortarLabel = new QLabel( i18n( "Mortar:" ), this );
+ m_pMortar = new PMFloatEdit( this );
+ layout->addWidget( m_pMortarLabel );
+ layout->addWidget( m_pMortar );
+ layout->addStretch( 1 );
+
+ /* connect all signals to slots/signals */
+ connect( m_pBrickSize, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pTypeCombo, SIGNAL( activated( int ) ), SLOT( slotComboChanged( int ) ) );
+ connect( m_pMortar, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pDepth, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMListPatternEdit::displayObject( PMObject* o )
+{
+ QString str;
+
+ if( o->isA( "ListPattern" ) )
+ {
+ m_pDisplayedObject = ( PMListPattern* ) o;
+
+ switch( m_pDisplayedObject->listType( ) )
+ {
+ case PMListPattern::ListPatternChecker:
+ m_pTypeCombo->setCurrentItem( 0 );
+ m_pBrickSizeLabel->hide( );
+ m_pBrickSize->hide( );
+ m_pMortarLabel->hide( );
+ m_pMortar->hide( );
+ break;
+ case PMListPattern::ListPatternBrick:
+ m_pTypeCombo->setCurrentItem( 1 );
+ m_pBrickSizeLabel->show( );
+ m_pBrickSize->show( );
+ m_pMortarLabel->show( );
+ m_pMortar->show( );
+ break;
+ case PMListPattern::ListPatternHexagon:
+ m_pTypeCombo->setCurrentItem( 2 );
+ m_pBrickSizeLabel->hide( );
+ m_pBrickSize->hide( );
+ m_pMortarLabel->hide( );
+ m_pMortar->hide( );
+ break;
+ }
+ m_pMortar->setValue( m_pDisplayedObject->mortar( ) );
+ m_pBrickSize->setVector( m_pDisplayedObject->brickSize( ) );
+ if( o->type( ) == "NormalList" )
+ {
+ m_pDepth->setValue( ( ( PMNormalList* )o )->depth( ) );
+ m_pDepth->show( );
+ m_pDepthLabel->show( );
+ emit sizeChanged( );
+ }
+ else
+ {
+ m_pDepth->hide( );
+ m_pDepthLabel->hide( );
+ emit sizeChanged( );
+ }
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMListPatternEdit: Can't display object\n";
+}
+
+void PMListPatternEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ switch( m_pTypeCombo->currentItem( ) )
+ {
+ case 0:
+ m_pDisplayedObject->setListType( PMListPattern::ListPatternChecker );
+ break;
+ case 1:
+ m_pDisplayedObject->setListType( PMListPattern::ListPatternBrick );
+ m_pDisplayedObject->setMortar( m_pMortar->value( ) );
+ m_pDisplayedObject->setBrickSize( m_pBrickSize->vector( ) );
+ break;
+ case 2:
+ m_pDisplayedObject->setListType( PMListPattern::ListPatternHexagon );
+ break;
+ }
+ if( m_pDisplayedObject->type( ) == "NormalList" )
+ ( ( PMNormalList* )m_pDisplayedObject )->setDepth( m_pDepth->value( ) );
+ }
+}
+
+bool PMListPatternEdit::isDataValid( )
+{
+ int children = 0;
+ PMObject* o;
+
+ if( !m_pBrickSize->isDataValid( ) )
+ return false;
+ if( !m_pMortar->isDataValid( ) )
+ return false;
+
+ // count child objects
+ for( o = m_pDisplayedObject->firstChild( ); o; o = o->nextSibling( ) )
+ if( o->type( ) == m_pDisplayedObject->listObjectType( ) )
+ children++;
+
+ switch( m_pTypeCombo->currentItem( ) )
+ {
+ case 0:
+ case 1:
+ if( children > 2 )
+ {
+ KMessageBox::error( this, i18n( "You can have at most two child"
+ " items for that list type!" ),
+ i18n( "Error" ) );
+ return false;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return Base::isDataValid( );
+}
+
+void PMListPatternEdit::slotComboChanged( int c )
+{
+ switch( c )
+ {
+ case 0:
+ m_pBrickSizeLabel->hide( );
+ m_pBrickSize->hide( );
+ m_pMortarLabel->hide( );
+ m_pMortar->hide( );
+ break;
+ case 1:
+ m_pBrickSizeLabel->show( );
+ m_pBrickSize->show( );
+ m_pMortarLabel->show( );
+ m_pMortar->show( );
+ break;
+ case 2:
+ m_pBrickSizeLabel->hide( );
+ m_pBrickSize->hide( );
+ m_pMortarLabel->hide( );
+ m_pMortar->hide( );
+ break;
+ default:
+ break;
+ }
+ emit sizeChanged( );
+ emit dataChanged( );
+}
+
+#include "pmlistpatternedit.moc"
diff --git a/kpovmodeler/pmlistpatternedit.h b/kpovmodeler/pmlistpatternedit.h
new file mode 100644
index 00000000..8ebd5e5b
--- /dev/null
+++ b/kpovmodeler/pmlistpatternedit.h
@@ -0,0 +1,78 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMLISTPATTERNEDIT_H
+#define PMLISTPATTERNEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdialogeditbase.h"
+
+class PMListPattern;
+class PMVectorEdit;
+class QComboBox;
+class PMFloatEdit;
+class QLabel;
+
+/**
+ * Dialog edit class for @ref PMListPattern.
+ */
+class PMListPatternEdit : public PMDialogEditBase
+{
+ Q_OBJECT
+ typedef PMDialogEditBase Base;
+public:
+ /**
+ * Creates a PMListPatternEdit with parent and name
+ */
+ PMListPatternEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+protected slots:
+ /**
+ * This slot is called when the list type is changed
+ */
+ void slotComboChanged( int c );
+
+private:
+ PMListPattern* m_pDisplayedObject;
+ QComboBox* m_pTypeCombo;
+ PMFloatEdit* m_pMortar;
+ PMVectorEdit* m_pBrickSize;
+ QLabel* m_pBrickSizeLabel;
+ QLabel* m_pMortarLabel;
+
+ QLabel* m_pDepthLabel;
+ PMFloatEdit* m_pDepth;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmlookslike.cpp b/kpovmodeler/pmlookslike.cpp
new file mode 100644
index 00000000..7e810605
--- /dev/null
+++ b/kpovmodeler/pmlookslike.cpp
@@ -0,0 +1,92 @@
+/*
+**************************************************************************
+ description
+ -------------------
+ and : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmlookslike.h"
+
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pmnamedobjectedit.h"
+
+#include <klocale.h>
+
+PMMetaObject* PMLooksLike::s_pMetaObject = 0;
+PMObject* createNewLooksLike( PMPart* part )
+{
+ return new PMLooksLike( part );
+}
+
+PMLooksLike::PMLooksLike( PMPart* part )
+ : Base( part )
+{
+}
+
+PMLooksLike::PMLooksLike( const PMLooksLike& l )
+ : Base( l )
+{
+}
+
+PMLooksLike::~PMLooksLike( )
+{
+}
+
+
+QString PMLooksLike::description( ) const
+{
+ return i18n( "looks like" );
+}
+
+PMMetaObject* PMLooksLike::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "LooksLike", Base::metaObject( ),
+ createNewLooksLike );
+ // no properties
+ }
+ return s_pMetaObject;
+}
+
+void PMLooksLike::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMLooksLike::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ Base::serialize( e, doc );
+}
+
+void PMLooksLike::readAttributes( const PMXMLHelper& h )
+{
+ Base::readAttributes( h );
+}
+
+PMDialogEditBase* PMLooksLike::editWidget( QWidget* parent ) const
+{
+ return new PMNamedObjectEdit( parent );
+}
+
+void PMLooksLike::restoreMemento( PMMemento* s )
+{
+ Base::restoreMemento( s );
+}
+
diff --git a/kpovmodeler/pmlookslike.h b/kpovmodeler/pmlookslike.h
new file mode 100644
index 00000000..971519e0
--- /dev/null
+++ b/kpovmodeler/pmlookslike.h
@@ -0,0 +1,82 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ -------------------
+ and : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMLOOKSLIKE_H
+#define PMLOOKSLIKE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmnamedobject.h"
+
+/**
+ * Class for povray looks_like statements.
+ */
+class PMLooksLike : public PMNamedObject
+{
+ typedef PMNamedObject Base;
+
+public:
+ /**
+ * Constructor
+ */
+ PMLooksLike( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMLooksLike( const PMLooksLike& l );
+ /**
+ * Deletes the PMLooksLike
+ */
+ virtual ~PMLooksLike( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMLooksLike( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMLooksLikeEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmlookslike" ); }
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+
+private:
+ static PMMetaObject* s_pMetaObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmmapmemento.cpp b/kpovmodeler/pmmapmemento.cpp
new file mode 100644
index 00000000..5b4e9aaa
--- /dev/null
+++ b/kpovmodeler/pmmapmemento.cpp
@@ -0,0 +1,51 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmmapmemento.h"
+
+PMMapMemento::PMMapMemento( PMObject* originator )
+ : PMMemento( originator )
+{
+ m_bMapValuesSaved = false;
+ m_bRemovedValuesSaved = false;
+}
+
+PMMapMemento::~PMMapMemento( )
+{
+}
+
+void PMMapMemento::setMapValues( const QValueList<double>& v )
+{
+ if( !m_bMapValuesSaved )
+ {
+ m_mapValues = v;
+ m_bMapValuesSaved = true;
+ addChange( PMCData );
+ }
+}
+
+void PMMapMemento::setRemovedValues( const QValueList<double>& v )
+{
+ if( !m_bRemovedValuesSaved )
+ {
+ m_removedValues = v;
+ m_bRemovedValuesSaved = true;
+ addChange( PMCData );
+ }
+}
+
+
diff --git a/kpovmodeler/pmmapmemento.h b/kpovmodeler/pmmapmemento.h
new file mode 100644
index 00000000..e2f1fa0a
--- /dev/null
+++ b/kpovmodeler/pmmapmemento.h
@@ -0,0 +1,81 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMMAPMEMENTO_H
+#define PMMAPMEMENTO_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmmemento.h"
+#include <qvaluelist.h>
+
+
+/**
+ * Memento for @ref PMTextureMapBase
+ */
+class PMMapMemento : public PMMemento
+{
+public:
+ /**
+ * Creates a memento for the object originator
+ */
+ PMMapMemento( PMObject* originator );
+ /**
+ * Deletes the memento
+ */
+ virtual ~PMMapMemento( );
+
+ /**
+ * Saves the map values
+ */
+ void setMapValues( const QValueList<double>& v );
+ /**
+ * Returns the map values
+ */
+ QValueList<double> mapValues( ) const { return m_mapValues; }
+ /**
+ * Returns true if the map values were saved
+ */
+ bool mapValuesSaved( ) const { return m_bMapValuesSaved; }
+
+ /**
+ * Saves the removed values
+ */
+ void setRemovedValues( const QValueList<double>& v );
+ /**
+ * Returns the removed values
+ */
+ QValueList<double> removedValues( ) const { return m_removedValues; }
+ /**
+ * Returns true if the removed values were saved
+ */
+ bool removedValuesSaved( ) const { return m_bRemovedValuesSaved; }
+
+private:
+ /**
+ * The stored values
+ */
+ QValueList<double> m_mapValues;
+ QValueList<double> m_removedValues;
+ bool m_bMapValuesSaved, m_bRemovedValuesSaved;
+};
+
+#endif
diff --git a/kpovmodeler/pmmaterial.cpp b/kpovmodeler/pmmaterial.cpp
new file mode 100644
index 00000000..d50f0ed1
--- /dev/null
+++ b/kpovmodeler/pmmaterial.cpp
@@ -0,0 +1,75 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmmaterial.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pmmaterialedit.h"
+
+#include <klocale.h>
+
+PMMetaObject* PMMaterial::s_pMetaObject = 0;
+PMObject* createNewMaterial( PMPart* part )
+{
+ return new PMMaterial( part );
+}
+
+PMMaterial::PMMaterial( PMPart* part )
+ : Base( part )
+{
+}
+
+PMMaterial::PMMaterial( const PMMaterial& m )
+ : Base( m )
+{
+}
+
+PMMaterial::~PMMaterial( )
+{
+}
+
+PMMetaObject* PMMaterial::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Material", Base::metaObject( ),
+ createNewMaterial );
+ }
+ return s_pMetaObject;
+}
+
+void PMMaterial::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMMaterial::description( ) const
+{
+ return i18n( "material" );
+}
+
+PMDialogEditBase* PMMaterial::editWidget( QWidget* parent ) const
+{
+ return new PMMaterialEdit( parent );
+}
+
diff --git a/kpovmodeler/pmmaterial.h b/kpovmodeler/pmmaterial.h
new file mode 100644
index 00000000..40891f1e
--- /dev/null
+++ b/kpovmodeler/pmmaterial.h
@@ -0,0 +1,75 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMMATERIAL_H
+#define PMMATERIAL_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebase.h"
+
+/**
+ * Class for povray materials
+ */
+class PMMaterial : public PMTextureBase
+{
+ typedef PMTextureBase Base;
+public:
+ /**
+ * Creates an PMMaterial
+ */
+ PMMaterial( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMMaterial( const PMMaterial& m );
+ /**
+ * Deletes the object
+ */
+ virtual ~PMMaterial( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMMaterial( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /**
+ * Returns a new @ref PMMaterialEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmmaterial" ); }
+
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+// enum PMMaterialMementoID { };
+ static PMMetaObject* s_pMetaObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmmaterialedit.cpp b/kpovmodeler/pmmaterialedit.cpp
new file mode 100644
index 00000000..ba63f579
--- /dev/null
+++ b/kpovmodeler/pmmaterialedit.cpp
@@ -0,0 +1,44 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmmaterialedit.h"
+#include "pmmaterial.h"
+#include "pmlinkedit.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <klocale.h>
+
+
+PMMaterialEdit::PMMaterialEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMMaterialEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Material" ) )
+ {
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMMaterialEdit: Can't display object\n";
+}
+
+#include "pmmaterialedit.moc"
diff --git a/kpovmodeler/pmmaterialedit.h b/kpovmodeler/pmmaterialedit.h
new file mode 100644
index 00000000..d273a72e
--- /dev/null
+++ b/kpovmodeler/pmmaterialedit.h
@@ -0,0 +1,58 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMMATERIALEDIT_H
+#define PMMATERIALEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebaseedit.h"
+
+class PMMaterial;
+
+/**
+ * Dialog edit class for @ref PMMaterial
+ */
+class PMMaterialEdit : public PMTextureBaseEdit
+{
+ Q_OBJECT
+ typedef PMTextureBaseEdit Base;
+public:
+ /**
+ * Creates a PMMaterialEdit with parent and name
+ */
+ PMMaterialEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+protected:
+ /** */
+// virtual void createTopWidgets( );
+ /** */
+// virtual void saveContents( );
+
+private:
+ PMMaterial* m_pDisplayedObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmmaterialmap.cpp b/kpovmodeler/pmmaterialmap.cpp
new file mode 100644
index 00000000..c70d85c9
--- /dev/null
+++ b/kpovmodeler/pmmaterialmap.cpp
@@ -0,0 +1,338 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Passos Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmmaterialmapedit.h"
+#include "pmmaterialmap.h"
+
+#include "pmxmlhelper.h"
+#include "pmcompositeobject.h"
+#include "pmmemento.h"
+#include "pmenumproperty.h"
+
+#include <klocale.h>
+
+const PMMaterialMap::PMBitmapType bitmapTypeDefault = PMMaterialMap::BitmapSys;
+const char *const bitmapFileDefault = 0;
+const bool enableFilterAllDefault = false;
+const bool enableTransmitAllDefault = false;
+const double filterAllDefault = 0.0;
+const double transmitAllDefault = 0.0;
+const bool onceDefault = false;
+const PMMaterialMap::PMMapType mapTypeDefault = PMMaterialMap::MapPlanar;
+const PMMaterialMap::PMInterpolateType interpolateTypeDefault = PMMaterialMap::InterpolateNone;
+
+PMDefinePropertyClass( PMMaterialMap, PMMaterialMapProperty );
+PMDefineEnumPropertyClass( PMMaterialMap, PMMaterialMap::PMBitmapType,
+ PMBitmapTypeProperty );
+PMDefineEnumPropertyClass( PMMaterialMap, PMMaterialMap::PMInterpolateType,
+ PMInterpolateTypeProperty );
+PMDefineEnumPropertyClass( PMMaterialMap, PMMaterialMap::PMMapType,
+ PMMapTypeProperty );
+
+PMMetaObject* PMMaterialMap::s_pMetaObject = 0;
+PMObject* createNewMaterialMap( PMPart* part )
+{
+ return new PMMaterialMap( part );
+}
+
+PMMaterialMap::PMMaterialMap( PMPart* part )
+ : Base( part )
+{
+ m_bitmapType = bitmapTypeDefault;
+ m_bitmapFile = bitmapFileDefault;
+ m_once = onceDefault;
+ m_mapType = mapTypeDefault;
+ m_interpolateType = interpolateTypeDefault;
+}
+
+PMMaterialMap::PMMaterialMap( const PMMaterialMap& m )
+ : Base( m )
+{
+ m_bitmapType = m.m_bitmapType;
+ m_bitmapFile = m.m_bitmapFile;
+ m_once = m.m_once;
+ m_mapType = m.m_mapType;
+ m_interpolateType = m.m_interpolateType;
+}
+
+PMMaterialMap::~PMMaterialMap( )
+{
+}
+
+void PMMaterialMap::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ switch( m_bitmapType )
+ {
+ case BitmapGif:
+ e.setAttribute( "bitmap_type", "gif" );
+ break;
+ case BitmapTga:
+ e.setAttribute( "bitmap_type", "tga" );
+ break;
+ case BitmapIff:
+ e.setAttribute( "bitmap_type", "iff" );
+ break;
+ case BitmapPpm:
+ e.setAttribute( "bitmap_type", "ppm" );
+ break;
+ case BitmapPgm:
+ e.setAttribute( "bitmap_type", "pgm" );
+ break;
+ case BitmapPng:
+ e.setAttribute( "bitmap_type", "png" );
+ break;
+ case BitmapJpeg:
+ e.setAttribute( "bitmap_type", "jpeg" );
+ break;
+ case BitmapTiff:
+ e.setAttribute( "bitmap_type", "tiff" );
+ break;
+ case BitmapSys:
+ e.setAttribute( "bitmap_type", "sys" );
+ break;
+ }
+ e.setAttribute( "file_name", m_bitmapFile );
+ e.setAttribute( "once", m_once );
+ switch( m_mapType )
+ {
+ case MapPlanar:
+ e.setAttribute( "map_type", "planar" );
+ break;
+ case MapSpherical:
+ e.setAttribute( "map_type", "spherical" );
+ break;
+ case MapCylindrical:
+ e.setAttribute( "map_type", "cylindrical" );
+ break;
+ case MapToroidal:
+ e.setAttribute( "map_type", "toroidal" );
+ break;
+ }
+ switch( m_interpolateType )
+ {
+ case InterpolateNone:
+ e.setAttribute( "interpolate", "none" );
+ break;
+ case InterpolateBilinear:
+ e.setAttribute( "interpolate", "bilinear" );
+ break;
+ case InterpolateNormalized:
+ e.setAttribute( "interpolate", "normalized" );
+ break;
+ }
+ Base::serialize( e, doc );
+}
+
+void PMMaterialMap::readAttributes( const PMXMLHelper& h )
+{
+ QString str;
+
+ str = h.stringAttribute( "bitmap_type", "sys" );
+ if( str == "gif" )
+ m_bitmapType = BitmapGif;
+ else if( str == "tga" )
+ m_bitmapType = BitmapTga;
+ else if( str == "iff" )
+ m_bitmapType = BitmapIff;
+ else if( str == "ppm" )
+ m_bitmapType = BitmapPpm;
+ else if( str == "pgm" )
+ m_bitmapType = BitmapPgm;
+ else if( str == "png" )
+ m_bitmapType = BitmapPng;
+ else if( str == "jpeg" )
+ m_bitmapType = BitmapJpeg;
+ else if( str == "tiff" )
+ m_bitmapType = BitmapTiff;
+ else if( str == "sys" )
+ m_bitmapType = BitmapSys;
+
+ m_bitmapFile = h.stringAttribute( "file_name", bitmapFileDefault );
+ m_once = h.boolAttribute( "once", onceDefault );
+
+ str = h.stringAttribute( "map_type", "planar" );
+ if( str == "planar" )
+ m_mapType = MapPlanar;
+ else if( str == "spherical" )
+ m_mapType = MapSpherical;
+ else if( str == "cylindrical" )
+ m_mapType = MapCylindrical;
+ else if( str == "toroidal" )
+ m_mapType = MapToroidal;
+
+ str = h.stringAttribute( "interpolate", "none" );
+ if( str == "none" )
+ m_interpolateType = InterpolateNone;
+ else if( str == "bilinear" )
+ m_interpolateType = InterpolateBilinear;
+ else if( str == "normalized" )
+ m_interpolateType = InterpolateNormalized;
+
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMMaterialMap::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "MaterialMap", Base::metaObject( ),
+ createNewMaterialMap );
+
+ PMBitmapTypeProperty* bp = new PMBitmapTypeProperty(
+ "bitmapType", &PMMaterialMap::setBitmapType, &PMMaterialMap::bitmapType );
+ bp->addEnumValue( "Gif", BitmapGif );
+ bp->addEnumValue( "Tga", BitmapTga );
+ bp->addEnumValue( "Iff", BitmapIff );
+ bp->addEnumValue( "Ppm", BitmapPpm );
+ bp->addEnumValue( "Pgm", BitmapPgm );
+ bp->addEnumValue( "Png", BitmapPng );
+ bp->addEnumValue( "Jpeg", BitmapJpeg );
+ bp->addEnumValue( "Tiff", BitmapTiff );
+ bp->addEnumValue( "Sys", BitmapSys );
+ s_pMetaObject->addProperty( bp );
+
+ PMInterpolateTypeProperty* ip = new PMInterpolateTypeProperty(
+ "interpolateType", &PMMaterialMap::setInterpolateType,
+ &PMMaterialMap::interpolateType );
+ ip->addEnumValue( "None", InterpolateNone );
+ ip->addEnumValue( "Bilinear", InterpolateBilinear );
+ ip->addEnumValue( "Normalized", InterpolateNormalized );
+ s_pMetaObject->addProperty( ip );
+
+ PMMapTypeProperty* mp = new PMMapTypeProperty(
+ "mapType", &PMMaterialMap::setMapType, &PMMaterialMap::mapType );
+ mp->addEnumValue( "Planar", MapPlanar );
+ mp->addEnumValue( "Spherical", MapSpherical );
+ mp->addEnumValue( "Cylindrical", MapCylindrical );
+ mp->addEnumValue( "Toroidal", MapToroidal );
+ s_pMetaObject->addProperty( mp );
+
+ s_pMetaObject->addProperty(
+ new PMMaterialMapProperty( "bitmapFile", &PMMaterialMap::setBitmapFileName,
+ &PMMaterialMap::bitmapFile ) );
+ s_pMetaObject->addProperty(
+ new PMMaterialMapProperty( "once", &PMMaterialMap::enableOnce, &PMMaterialMap::isOnceEnabled ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMMaterialMap::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMMaterialMap::description( ) const
+{
+ return i18n( "material map" );
+}
+
+void PMMaterialMap::setBitmapType( PMBitmapType c )
+{
+ if( c != m_bitmapType )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMBitmapTypeID, m_bitmapType );
+ m_bitmapType = c;
+ }
+}
+
+void PMMaterialMap::setBitmapFileName( const QString& c )
+{
+ if( c != m_bitmapFile )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMBitmapFileID, m_bitmapFile );
+ m_bitmapFile = c;
+ }
+}
+
+void PMMaterialMap::setMapType( PMMapType c )
+{
+ if( c != m_mapType )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMMapTypeID, m_mapType );
+ m_mapType = c;
+ }
+}
+
+void PMMaterialMap::setInterpolateType( PMInterpolateType c )
+{
+ if( c != m_interpolateType )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMInterpolateID, m_interpolateType );
+ m_interpolateType = c;
+ }
+}
+
+void PMMaterialMap::enableOnce( bool c )
+{
+ if( c != m_once )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMOnceID, m_once );
+ m_once = c;
+ }
+}
+
+PMDialogEditBase* PMMaterialMap::editWidget( QWidget* parent ) const
+{
+ return new PMMaterialMapEdit( parent );
+}
+
+void PMMaterialMap::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMBitmapTypeID:
+ setBitmapType( ( PMBitmapType )data->intData( ) );
+ break;
+ case PMBitmapFileID:
+ setBitmapFileName( data->stringData( ) );
+ break;
+ case PMOnceID:
+ enableOnce( data->boolData( ) );
+ break;
+ case PMMapTypeID:
+ setMapType( ( PMMapType )data->intData( ) );
+ break;
+ case PMInterpolateID:
+ setInterpolateType( ( PMInterpolateType )data->intData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMMaterialMap::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmmaterialmap.h b/kpovmodeler/pmmaterialmap.h
new file mode 100644
index 00000000..c6713e9f
--- /dev/null
+++ b/kpovmodeler/pmmaterialmap.h
@@ -0,0 +1,153 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Passos Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMMATERIALMAP_H
+#define PMMATERIALMAP_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmnamedobject.h"
+#include "pmpalettevalue.h"
+
+/**
+ * Class for povray material maps.
+ */
+
+class PMMaterialMap : public PMNamedObject
+{
+ typedef PMNamedObject Base;
+public:
+ /**
+ * The bitmap type
+ */
+ enum PMBitmapType { BitmapGif, BitmapTga, BitmapIff, BitmapPpm,
+ BitmapPgm, BitmapPng, BitmapJpeg, BitmapTiff,
+ BitmapSys };
+ /**
+ * The interpolate method
+ */
+ enum PMInterpolateType { InterpolateNone, InterpolateBilinear,
+ InterpolateNormalized };
+ /**
+ * The mapping method
+ */
+ enum PMMapType { MapPlanar, MapSpherical, MapCylindrical,
+ MapToroidal };
+
+
+ /**
+ * Creates a PMMaterialMap
+ */
+ PMMaterialMap( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMMaterialMap( const PMMaterialMap& m );
+ /**
+ * deletes the PMMaterialMap
+ */
+ virtual ~PMMaterialMap( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMMaterialMap( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmmaterialmap" ); }
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMMaterialMapEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+
+ /**
+ * Gets the bitmap type
+ */
+ PMBitmapType bitmapType( ) const { return m_bitmapType; }
+ /**
+ * Gets the bitmap file name
+ */
+ QString bitmapFile( ) const { return m_bitmapFile; }
+ /**
+ * Returns true if once is enabled
+ */
+ bool isOnceEnabled( ) const { return m_once; }
+ /**
+ * Gets the bitmap file type
+ */
+ PMMapType mapType( ) const { return m_mapType; }
+ /**
+ * Gets the interpolate method type
+ */
+ PMInterpolateType interpolateType( ) const { return m_interpolateType; }
+
+
+ /**
+ * Sets the bumpmap type
+ */
+ void setBitmapType( PMBitmapType c );
+ /**
+ * Sets the bitmap file name*/
+ void setBitmapFileName( const QString& c );
+ /**
+ * Sets if the bitmap should be mapped once
+ */
+ void enableOnce( bool c );
+ /**
+ * Sets the mapping method
+ */
+ void setMapType( const PMMapType c );
+ /**
+ * Sets the interpolating method
+ */
+ void setInterpolateType( PMInterpolateType c );
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMMaterialMapMementoID { PMBitmapTypeID, PMBitmapFileID,
+ PMOnceID, PMMapTypeID, PMInterpolateID };
+ /**
+ * MaterialMap type
+ */
+ PMBitmapType m_bitmapType;
+ QString m_bitmapFile;
+ bool m_once;
+ PMMapType m_mapType;
+ PMInterpolateType m_interpolateType;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmmaterialmapedit.cpp b/kpovmodeler/pmmaterialmapedit.cpp
new file mode 100644
index 00000000..d50e3d7b
--- /dev/null
+++ b/kpovmodeler/pmmaterialmapedit.cpp
@@ -0,0 +1,299 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Passos Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmmaterialmapedit.h"
+#include "pmmaterialmap.h"
+#include "pmvectoredit.h"
+#include "pmlineedits.h"
+#include "pmpalettevalueedit.h"
+#include "pmvector.h"
+
+#include <qwidget.h>
+#include <qlayout.h>
+#include <qcombobox.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+#include <qpushbutton.h>
+#include <qtooltip.h>
+#include <ktabctl.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdialog.h>
+#include <kfiledialog.h>
+#include <kiconloader.h>
+
+PMMaterialMapEdit::PMMaterialMapEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMMaterialMapEdit::createTopWidgets( )
+{
+ QLabel* lbl;
+ QHBoxLayout* hl;
+
+ Base::createTopWidgets( );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ lbl = new QLabel( i18n( "File type:" ), this );
+ m_pImageFileTypeEdit = new QComboBox( this );
+ m_pImageFileTypeEdit->insertItem( "gif" );
+ m_pImageFileTypeEdit->insertItem( "tga" );
+ m_pImageFileTypeEdit->insertItem( "iff" );
+ m_pImageFileTypeEdit->insertItem( "ppm" );
+ m_pImageFileTypeEdit->insertItem( "pgm" );
+ m_pImageFileTypeEdit->insertItem( "png" );
+ m_pImageFileTypeEdit->insertItem( "jpeg" );
+ m_pImageFileTypeEdit->insertItem( "tiff" );
+ m_pImageFileTypeEdit->insertItem( "sys" );
+ hl->addWidget( lbl );
+ hl->addWidget( m_pImageFileTypeEdit );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ lbl = new QLabel( i18n( "File name:" ), this );
+ m_pImageFileNameEdit = new QLineEdit( this );
+ m_pImageFileNameBrowse = new QPushButton( this );
+ m_pImageFileNameBrowse->setPixmap( SmallIcon( "fileopen" ) );
+ hl->addWidget( lbl );
+ hl->addWidget( m_pImageFileNameEdit );
+ hl->addWidget( m_pImageFileNameBrowse );
+ hl->addStretch( 1 );
+
+ m_pOnceEdit = new QCheckBox( i18n( "Once" ), this );
+ topLayout( )->addWidget( m_pOnceEdit );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ lbl = new QLabel( i18n( "Interpolate:" ), this );
+ m_pInterpolateTypeEdit = new QComboBox( this );
+ m_pInterpolateTypeEdit->insertItem( i18n( "None" ) );
+ m_pInterpolateTypeEdit->insertItem( i18n( "Bilinear" ) );
+ m_pInterpolateTypeEdit->insertItem( i18n( "Normalized" ) );
+ hl->addWidget( lbl );
+ hl->addWidget( m_pInterpolateTypeEdit );
+ hl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ lbl = new QLabel( i18n( "Map type:" ), this );
+ m_pMapTypeEdit = new QComboBox( this );
+ m_pMapTypeEdit->insertItem( i18n( "Planar" ) );
+ m_pMapTypeEdit->insertItem( i18n( "Spherical" ) );
+ m_pMapTypeEdit->insertItem( i18n( "Cylindrical" ) );
+ m_pMapTypeEdit->insertItem( i18n( "Toroidal" ) );
+ hl->addWidget( lbl );
+ hl->addWidget( m_pMapTypeEdit );
+ hl->addStretch( 1 );
+
+ connect( m_pImageFileTypeEdit, SIGNAL( activated( int ) ), SLOT( slotImageFileTypeChanged( int ) ) );
+ connect( m_pMapTypeEdit, SIGNAL( activated( int ) ), SLOT( slotMapTypeChanged( int ) ) );
+ connect( m_pInterpolateTypeEdit, SIGNAL( activated( int ) ), SLOT( slotInterpolateTypeChanged( int ) ) );
+ connect( m_pImageFileNameBrowse, SIGNAL( clicked( ) ), SLOT( slotImageFileBrowseClicked( ) ) );
+ connect( m_pImageFileNameEdit, SIGNAL( textChanged( const QString& ) ), SLOT( slotImageFileNameChanged( const QString& ) ) );
+ connect( m_pOnceEdit, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMMaterialMapEdit::displayObject( PMObject* o )
+{
+ bool readOnly;
+
+ if( o->isA( "MaterialMap" ) )
+ {
+ m_pDisplayedObject = ( PMMaterialMap* ) o;
+ readOnly = m_pDisplayedObject->isReadOnly( );
+
+ switch( m_pDisplayedObject->bitmapType( ) )
+ {
+ case PMMaterialMap::BitmapGif:
+ m_pImageFileTypeEdit->setCurrentItem( 0 );
+ break;
+ case PMMaterialMap::BitmapTga:
+ m_pImageFileTypeEdit->setCurrentItem( 1 );
+ break;
+ case PMMaterialMap::BitmapIff:
+ m_pImageFileTypeEdit->setCurrentItem( 2 );
+ break;
+ case PMMaterialMap::BitmapPpm:
+ m_pImageFileTypeEdit->setCurrentItem( 3 );
+ break;
+ case PMMaterialMap::BitmapPgm:
+ m_pImageFileTypeEdit->setCurrentItem( 4 );
+ break;
+ case PMMaterialMap::BitmapPng:
+ m_pImageFileTypeEdit->setCurrentItem( 5 );
+ break;
+ case PMMaterialMap::BitmapJpeg:
+ m_pImageFileTypeEdit->setCurrentItem( 6 );
+ break;
+ case PMMaterialMap::BitmapTiff:
+ m_pImageFileTypeEdit->setCurrentItem( 7 );
+ break;
+ case PMMaterialMap::BitmapSys:
+ m_pImageFileTypeEdit->setCurrentItem( 8 );
+ break;
+ }
+ m_pImageFileTypeEdit->setEnabled( !readOnly );
+
+ switch( m_pDisplayedObject->interpolateType( ) )
+ {
+ case PMMaterialMap::InterpolateNone:
+ m_pInterpolateTypeEdit->setCurrentItem( 0 );
+ break;
+ case PMMaterialMap::InterpolateBilinear:
+ m_pInterpolateTypeEdit->setCurrentItem( 1);
+ break;
+ case PMMaterialMap::InterpolateNormalized:
+ m_pInterpolateTypeEdit->setCurrentItem( 2 );
+ break;
+ }
+ m_pInterpolateTypeEdit->setEnabled( !readOnly );
+
+ switch( m_pDisplayedObject->mapType( ) )
+ {
+ case PMMaterialMap::MapPlanar:
+ m_pMapTypeEdit->setCurrentItem( 0 );
+ break;
+ case PMMaterialMap::MapSpherical:
+ m_pMapTypeEdit->setCurrentItem( 1 );
+ break;
+ case PMMaterialMap::MapCylindrical:
+ m_pMapTypeEdit->setCurrentItem( 2 );
+ break;
+ case PMMaterialMap::MapToroidal:
+ m_pMapTypeEdit->setCurrentItem( 3 );
+ break;
+ }
+ m_pMapTypeEdit->setEnabled( !readOnly );
+
+ m_pImageFileNameEdit->setText( m_pDisplayedObject->bitmapFile( ) );
+ m_pImageFileNameEdit->setEnabled( !readOnly );
+ m_pOnceEdit->setChecked( m_pDisplayedObject->isOnceEnabled( ) );
+ m_pOnceEdit->setEnabled( !readOnly );
+
+ Base::displayObject( o );
+ }
+
+}
+
+void PMMaterialMapEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ switch( m_pImageFileTypeEdit->currentItem( ) )
+ {
+ case 0:
+ m_pDisplayedObject->setBitmapType( PMMaterialMap::BitmapGif );
+ break;
+ case 1:
+ m_pDisplayedObject->setBitmapType( PMMaterialMap::BitmapTga );
+ break;
+ case 2:
+ m_pDisplayedObject->setBitmapType( PMMaterialMap::BitmapIff );
+ break;
+ case 3:
+ m_pDisplayedObject->setBitmapType( PMMaterialMap::BitmapPpm );
+ break;
+ case 4:
+ m_pDisplayedObject->setBitmapType( PMMaterialMap::BitmapPgm );
+ break;
+ case 5:
+ m_pDisplayedObject->setBitmapType( PMMaterialMap::BitmapPng );
+ break;
+ case 6:
+ m_pDisplayedObject->setBitmapType( PMMaterialMap::BitmapJpeg );
+ break;
+ case 7:
+ m_pDisplayedObject->setBitmapType( PMMaterialMap::BitmapTiff );
+ break;
+ case 8:
+ m_pDisplayedObject->setBitmapType( PMMaterialMap::BitmapSys );
+ break;
+ }
+
+ switch( m_pInterpolateTypeEdit->currentItem( ) )
+ {
+ case 0:
+ m_pDisplayedObject->setInterpolateType( PMMaterialMap::InterpolateNone );
+ break;
+ case 1:
+ m_pDisplayedObject->setInterpolateType( PMMaterialMap::InterpolateBilinear );
+ break;
+ case 2:
+ m_pDisplayedObject->setInterpolateType( PMMaterialMap::InterpolateNormalized );
+ break;
+ }
+
+ switch( m_pMapTypeEdit->currentItem( ) )
+ {
+ case 0:
+ m_pDisplayedObject->setMapType( PMMaterialMap::MapPlanar );
+ break;
+ case 1:
+ m_pDisplayedObject->setMapType( PMMaterialMap::MapSpherical );
+ break;
+ case 2:
+ m_pDisplayedObject->setMapType( PMMaterialMap::MapCylindrical );
+ break;
+ case 3:
+ m_pDisplayedObject->setMapType( PMMaterialMap::MapToroidal );
+ break;
+ }
+
+ m_pDisplayedObject->setBitmapFileName( m_pImageFileNameEdit->text( ) );
+ m_pDisplayedObject->enableOnce( m_pOnceEdit->isChecked( ) );
+ }
+}
+
+bool PMMaterialMapEdit::isDataValid( )
+{
+ return Base::isDataValid( );
+}
+
+void PMMaterialMapEdit::slotInterpolateTypeChanged( const int /*a*/ )
+{
+ emit dataChanged( );
+}
+
+void PMMaterialMapEdit::slotImageFileTypeChanged( const int /*a*/ )
+{
+ emit dataChanged( );
+}
+
+void PMMaterialMapEdit::slotMapTypeChanged( const int /*a*/ )
+{
+ emit dataChanged( );
+}
+
+void PMMaterialMapEdit::slotImageFileNameChanged( const QString& /*a*/ )
+{
+ emit dataChanged( );
+}
+
+void PMMaterialMapEdit::slotImageFileBrowseClicked( )
+{
+ QString str = KFileDialog::getOpenFileName( QString::null, QString::null );
+
+ if( !str.isEmpty() )
+ {
+ m_pImageFileNameEdit->setText( str );
+ emit dataChanged( );
+ }
+}
+
+#include "pmmaterialmapedit.moc"
diff --git a/kpovmodeler/pmmaterialmapedit.h b/kpovmodeler/pmmaterialmapedit.h
new file mode 100644
index 00000000..f6ffa7f0
--- /dev/null
+++ b/kpovmodeler/pmmaterialmapedit.h
@@ -0,0 +1,81 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Passos Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMMATERIALMAPEDIT_H
+#define PMMATERIALMAPEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdialogeditbase.h"
+
+class PMMaterialMap;
+class QComboBox;
+class PMFloatEdit;
+class PMIntEdit;
+class QLabel;
+class QCheckBox;
+class QWidget;
+class QLineEdit;
+class QPushButton;
+
+/**
+ * Dialog edit class for @ref PMMaterialMap.
+ */
+class PMMaterialMapEdit : public PMDialogEditBase
+{
+ Q_OBJECT
+ typedef PMDialogEditBase Base;
+public:
+ /**
+ * Creates a PMMaterialMapEdit with parent and name
+ */
+ PMMaterialMapEdit( QWidget* parent, const char* name = 0 );
+ /** */
+ virtual void displayObject( PMObject* o );
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+private slots:
+ /** */
+ void slotImageFileTypeChanged( int a );
+ /** */
+ void slotMapTypeChanged( int a );
+ /** */
+ void slotInterpolateTypeChanged( int a );
+ /** */
+ void slotImageFileNameChanged( const QString& a );
+ /** */
+ void slotImageFileBrowseClicked( );
+private:
+ PMMaterialMap* m_pDisplayedObject;
+ QComboBox* m_pImageFileTypeEdit;
+ QLineEdit* m_pImageFileNameEdit;
+ QPushButton* m_pImageFileNameBrowse;
+ QCheckBox* m_pOnceEdit;
+ QComboBox* m_pMapTypeEdit;
+ QComboBox* m_pInterpolateTypeEdit;
+};
+
+#endif
diff --git a/kpovmodeler/pmmath.cpp b/kpovmodeler/pmmath.cpp
new file mode 100644
index 00000000..8aedab76
--- /dev/null
+++ b/kpovmodeler/pmmath.cpp
@@ -0,0 +1,67 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+// some helper functions
+
+#include "pmmath.h"
+#include <math.h>
+
+bool approx( double v1, double v2, double epsilon )
+{
+ return fabs( v1 - v2 ) < epsilon;
+}
+
+bool approxZero( double v, double epsilon )
+{
+ return fabs( v ) < epsilon;
+}
+
+double rad2Deg( double rad )
+{
+ return rad / M_PI * 180.0;
+}
+
+double deg2Rad( double deg )
+{
+ return deg * M_PI / 180.0;
+}
+
+double pmatan( double s, double c )
+{
+ double a;
+ if( approxZero( c ) )
+ {
+ if( s > 0 )
+ a = M_PI_2;
+ else
+ a = -M_PI_2;
+ }
+ else
+ a = atan2( s, c );
+
+ return a;
+}
+
+int pmpot( int x, int y )
+{
+ int i;
+ int result = 1;
+ for( i = 0; i < y; i++ )
+ result *= x;
+ return result;
+}
diff --git a/kpovmodeler/pmmath.h b/kpovmodeler/pmmath.h
new file mode 100644
index 00000000..520b8b6d
--- /dev/null
+++ b/kpovmodeler/pmmath.h
@@ -0,0 +1,48 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMMATH_H
+#define PMMATH_H
+
+/**
+ * Same as ( fabs( v1 - v2 ) < epsilon )
+ */
+bool approx( double v1, double v2, double epsilon = 1e-6 );
+/**
+ * Same as ( fabs( v ) < epsilon )
+ */
+bool approxZero( double v, double epsilon = 1e-6 );
+/**
+ * Converts rad to deg
+ */
+double rad2Deg( double rad );
+/**
+ * Converts deg to rad
+ */
+double deg2Rad( double deg );
+/**
+ * Returns the atan( s / c ) with all special cases
+ */
+double pmatan( double s, double c );
+/**
+ * Returns x^y. y has to be >= 0
+ */
+int pmpot( int x, int y );
+
+#endif
diff --git a/kpovmodeler/pmmatrix.cpp b/kpovmodeler/pmmatrix.cpp
new file mode 100644
index 00000000..217672e5
--- /dev/null
+++ b/kpovmodeler/pmmatrix.cpp
@@ -0,0 +1,442 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include <math.h>
+
+#include "pmmatrix.h"
+#include "pmvector.h"
+#include "pmdebug.h"
+
+#include <qtextstream.h>
+
+PMMatrix::PMMatrix( )
+{
+ int i;
+
+ for( i = 0; i < 16; i++ )
+ m_elements[i] = 0;
+}
+
+PMMatrix::~PMMatrix( )
+{
+}
+
+PMMatrix& PMMatrix::operator= ( const PMMatrix& m )
+{
+ int i;
+ for( i=0; i<16; i++ )
+ m_elements[i] = m.m_elements[i];
+
+ return *this;
+}
+
+PMMatrix PMMatrix::identity( )
+{
+ PMMatrix newMatrix;
+ int i;
+
+ for( i=0; i<4; i++ )
+ newMatrix[i][i] = 1.0;
+
+ return newMatrix;
+}
+
+PMMatrix PMMatrix::translation( double x, double y, double z )
+{
+ PMMatrix newMatrix;
+ newMatrix[3][0] = x;
+ newMatrix[3][1] = y;
+ newMatrix[3][2] = z;
+ newMatrix[0][0] = 1;
+ newMatrix[1][1] = 1;
+ newMatrix[2][2] = 1;
+ newMatrix[3][3] = 1;
+
+ return newMatrix;
+}
+
+PMMatrix PMMatrix::scale( double x, double y, double z )
+{
+ PMMatrix newMatrix;
+ newMatrix[0][0] = x;
+ newMatrix[1][1] = y;
+ newMatrix[2][2] = z;
+ newMatrix[3][3] = 1;
+
+ return newMatrix;
+}
+
+PMMatrix PMMatrix::rotation( double x, double y, double z )
+{
+ PMMatrix newMatrix;
+ double sinx, siny, sinz, cosx, cosy, cosz;
+ sinx = sin( x );
+ siny = sin( y );
+ sinz = sin( z );
+ cosx = cos( x );
+ cosy = cos( y );
+ cosz = cos( z );
+
+ newMatrix[0][0] = cosz*cosy;
+ newMatrix[1][0] = -sinz*cosx + cosz*siny*sinx;
+ newMatrix[2][0] = sinz*sinx + cosz*siny*cosx;
+ newMatrix[0][1] = sinz*cosy;
+ newMatrix[1][1] = cosz*cosx + sinz*siny*sinx;
+ newMatrix[2][1] = -cosz*sinx + sinz*siny*cosx;
+ newMatrix[0][2] = -siny;
+ newMatrix[1][2] = cosy*sinx;
+ newMatrix[2][2] = cosy*cosx;
+ newMatrix[3][3] = 1;
+
+ return newMatrix;
+}
+
+PMMatrix PMMatrix::rotation( const PMVector& n, double a )
+{
+ PMMatrix result( PMMatrix::identity( ) );
+ double rx, ry;
+
+ if( n.size( ) == 3 )
+ {
+ rx = pmatan( n.y( ), n.z( ) );
+ ry = - pmatan( n.x( ), sqrt( n.y( ) * n.y( ) + n.z( ) * n.z( ) ) );
+
+ result = rotation( -rx, 0.0, 0.0 ) * rotation( 0.0, -ry, 0.0 )
+ * rotation( rx, ry, a );
+
+ }
+ else
+ kdError( PMArea ) << "Wrong size in PMMatrix::rotation( )\n";
+
+ return result;
+}
+
+PMMatrix PMMatrix::viewTransformation( const PMVector& eye,
+ const PMVector& lookAt,
+ const PMVector& up )
+{
+ PMMatrix result;
+ PMVector x, y, z;
+ GLdouble len;
+ int i;
+
+ // create rotation matrix
+ z = eye - lookAt;
+ len = z.abs( );
+ if( !approxZero( len ) )
+ z /= len;
+
+ y = up;
+ x = PMVector::cross( y, z );
+ y = PMVector::cross( z, x );
+
+ // normalize vectors
+ len = x.abs( );
+ if( !approxZero( len ) )
+ x /= len;
+
+ len = y.abs( );
+ if( !approxZero( len ) )
+ y /= len;
+
+ for( i = 0; i < 3; i++ )
+ {
+ result[i][0] = x[i];
+ result[i][1] = y[i];
+ result[i][2] = z[i];
+ result[3][i] = 0.0;
+ result[i][3] = 0.0;
+ }
+ result[3][3] = 1.0;
+
+ // Translate eye to origin
+ return result * translation( -eye[0], -eye[1], -eye[2] );
+}
+
+void PMMatrix::toRotation( double* x, double* y, double* z )
+{
+ PMMatrix& m = *this;
+
+ if( !approx( fabs( m[0][2] ), 1.0 ) )
+ {
+ double cosy;
+ // | m[0][2] | != 1
+ // sin(y) != 1.0, cos(y) != 0.0
+ *y = asin( - m[0][2] );
+ cosy = cos( *y );
+
+ // sign of cosy is important!
+ *x = pmatan( m[1][2] / cosy, m[2][2] / cosy );
+ *z = pmatan( m[0][1] / cosy, m[0][0] / cosy );
+ }
+ else if( m[0][2] < 0 )
+ {
+ // m[0][2] == -1
+ // sin(y) == 1, cos(y) == 0
+ // z and x are dependent of each other, assume z = 0
+
+ double zminusx = pmatan( m[2][1], m[1][1] );
+
+ *y = M_PI_2;
+ *z = 0.0;
+ *x = - zminusx;
+ }
+ else
+ {
+ // m[0][2] == 1
+ // sin(y) == -1, cos(y) == 0
+ // z and x are dependent of each other, assume z = 0
+
+ double zplusx = pmatan( -m[2][1], m[1][1] );
+
+ *y = -M_PI_2;
+ *z = 0.0;
+ *x = zplusx;
+ }
+}
+
+PMMatrix PMMatrix::modelviewMatrix( )
+{
+ PMMatrix result;
+ glGetDoublev( GL_MODELVIEW_MATRIX, result.m_elements );
+ return result;
+}
+
+double PMMatrix::det( ) const
+{
+ PMMatrix tmp( *this );
+ double result = 1.0, help;
+ int i, k, e, row;
+
+ // make a upper triangular matrix
+ for( i=0; i<4; i++ )
+ {
+ row = tmp.notNullElementRow( i );
+ if( row == -1 )
+ return 0;
+ if( row != i )
+ {
+ tmp.exchangeRows( i, row );
+ result = -result;
+ }
+
+ result *= tmp[i][i];
+ for( k=i+1; k<4; k++ )
+ {
+ help = tmp[i][k];
+ for( e=0; e<4; e++ )
+ tmp[e][k] -= tmp[e][i] * help/tmp[i][i];
+ }
+ }
+ return result;
+}
+
+PMMatrix PMMatrix::inverse( ) const
+{
+ PMMatrix result( identity( ) );
+ PMMatrix tmp( *this );
+ int i, k, e, row;
+ double a;
+
+ // uses the Gauss algorithm
+ // row operations to make tmp a identity matrix
+ // result matrix is then the inverse
+ for( i=0; i<4; i++ )
+ {
+ row = tmp.notNullElementRow( i );
+ if( row == -1 )
+ return identity( );
+ if( row != i )
+ {
+ tmp.exchangeRows( i, row );
+ result.exchangeRows( i, row );
+ }
+ // tmp[i][i] != 0
+
+ a = tmp[i][i];
+ for( e=0; e<4; e++ )
+ {
+ result[e][i] /= a;
+ tmp[e][i] /= a;
+ }
+ // tmp[i][i] == 1
+
+ for( k=0; k<4; k++ )
+ {
+ if( k != i )
+ {
+ a = tmp[i][k];
+ for( e=0; e<4; e++ )
+ {
+ result[e][k] -= result[e][i] * a;
+ tmp[e][k] -= tmp[e][i] * a;
+ }
+ }
+ }
+ // tmp[!=i][i] == 0.0
+ }
+ return result;
+}
+
+void PMMatrix::exchangeRows( int r1, int r2 )
+{
+ GLdouble help;
+ int i;
+
+ for( i=0; i<4; i++ )
+ {
+ help = (*this)[i][r1];
+ (*this)[i][r1] = (*this)[i][r2];
+ (*this)[i][r2] = help;
+ }
+}
+
+int PMMatrix::notNullElementRow( const int index ) const
+{
+ int i, result = -1;
+ GLdouble max = 0.0, v;
+
+ // choose the row with abs( ) = max
+ for( i=index; i<4; i++ )
+ {
+ v = fabs((*this)[index][i]);
+ if( v > max )
+ {
+ result = i;
+ max = v;
+ }
+ }
+ return result;
+}
+
+PMMatrix& PMMatrix::operator*= ( const double d )
+{
+ int i;
+ for( i=0; i<16; i++ )
+ m_elements[i] *= d;
+ return *this;
+}
+
+PMMatrix& PMMatrix::operator/= ( const double d )
+{
+ int i;
+ if( approxZero( 0 ) )
+ kdError( PMArea ) << "Division by zero in PMMatrix::operator/=" << "\n";
+ else
+ for( i=0; i<16; i++ )
+ m_elements[i] /= d;
+ return *this;
+}
+
+PMMatrix& PMMatrix::operator*= ( const PMMatrix& m )
+{
+ *this = *this * m;
+ return *this;
+}
+
+PMMatrix operator- ( const PMMatrix& m )
+{
+ PMMatrix result;
+ int r,c;
+
+ for( r=0; r<4; r++ )
+ for( c=0; c<4; c++ )
+ result[c][r] = -m[c][r];
+ return result;
+}
+
+PMMatrix operator* ( const PMMatrix& m1, const PMMatrix& m2 )
+{
+ PMMatrix result;
+ int r, c, i;
+
+ for( r=0; r<4; r++ )
+ for( c=0; c<4; c++ )
+ for( i=0; i<4; i++ )
+ result[c][r] += m1[i][r] * m2[c][i];
+ return result;
+}
+
+PMMatrix operator* ( const PMMatrix& m1, const double d )
+{
+ PMMatrix result( m1 );
+ result *= d;
+ return result;
+}
+
+PMMatrix operator/ ( const PMMatrix& m1, const double d )
+{
+ PMMatrix result( m1 );
+ result /= d ;
+ return result;
+}
+
+PMMatrix operator* ( const double d, const PMMatrix& m1 )
+{
+ PMMatrix result( m1 );
+ result *= d;
+ return result;
+}
+
+#include <stdio.h>
+void PMMatrix::testOutput( )
+{
+ int r, c;
+
+ printf( "\n" );
+ for( r=0; r<4; r++ )
+ {
+ for( c=0; c<4; c++ )
+ printf( "% 20.18f ", (*this)[c][r] );
+ printf( "\n" );
+ }
+}
+
+QString PMMatrix::serializeXML( ) const
+{
+ QString result;
+ QTextStream str( &result, IO_WriteOnly );
+ int i;
+
+ for( i = 0; i < 16; i++ )
+ {
+ if( i > 0 )
+ str << ' ';
+ str << m_elements[i];
+ }
+
+ return result;
+}
+
+bool PMMatrix::loadXML( const QString& str )
+{
+ int i;
+ QString tmp( str );
+ QTextStream s( &tmp, IO_ReadOnly );
+ QString val;
+ bool ok;
+
+ for( i = 0; i < 16; i++ )
+ {
+ s >> val;
+ m_elements[i] = val.toDouble( &ok );
+ if( !ok )
+ return false;
+ }
+ return true;
+}
diff --git a/kpovmodeler/pmmatrix.h b/kpovmodeler/pmmatrix.h
new file mode 100644
index 00000000..62747aea
--- /dev/null
+++ b/kpovmodeler/pmmatrix.h
@@ -0,0 +1,188 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMMATRIX_H
+#define PMMATRIX_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmmath.h"
+#include "math.h"
+
+#include <qstring.h>
+
+#include <GL/gl.h>
+
+class PMVector;
+
+/**
+ * 4x4 matrix for transformations with homogenous coordinates
+ *
+ * Optimized for OpenGL.
+ */
+class PMMatrix
+{
+public:
+ /**
+ * Creates a zero matrix
+ */
+ PMMatrix( );
+ /**
+ * Deletes the matrix
+ */
+ ~PMMatrix( );
+ /**
+ * Assigns m to the matrix
+ */
+ PMMatrix& operator= ( const PMMatrix& m );
+ /**
+ * Creates an identity matrix
+ */
+ static PMMatrix identity( );
+ /**
+ * Creates a matrix for translation.
+ */
+ static PMMatrix translation( double x, double y, double z );
+ /**
+ * Creates a matrix for rotations. Rotation first around the x, then y
+ * and then around the z axis.
+ *
+ * x, y and z in rad
+ */
+ static PMMatrix rotation( double x, double y, double z );
+ /**
+ * Creates a matrix for rotation around the direction n with angle a.
+ *
+ * a in rad.
+ */
+ static PMMatrix rotation( const PMVector& n, double a );
+ /**
+ * Creates a viewing matrix.
+ *
+ * The viewpoint is specified by the parameter eye. The parameter
+ * lookAt specifies any point along the line of sight. The up vector
+ * indicate which direction is up.
+ */
+ static PMMatrix viewTransformation( const PMVector& eye,
+ const PMVector& lookAt,
+ const PMVector& up );
+ /**
+ * Backwards calculate the rotations from the matrix
+ */
+ void toRotation( double* x, double* y, double* z );
+
+ /**
+ * Creates a matrix for scale.
+ */
+ static PMMatrix scale( double x, double y, double z );
+ /**
+ * Returns the current gl modelview matrix
+ */
+ static PMMatrix modelviewMatrix( );
+
+ /**
+ * Returns a pointer to the column (!) at position index.
+ * That means matrix[i][j] is the element at column i and row j*/
+ GLdouble* operator[] ( int index ) { return &( m_elements[index*4] ); }
+ /**
+ * Returns a pointer to the column (!) at position index.
+ * That means matrix[i][j] is the element at column i and row j*/
+ const GLdouble* operator[] ( int index ) const
+ { return &(m_elements[index*4]); }
+ /**
+ * Returns true if an inverse matrix can be calculated
+ */
+ bool canBuildInverse( ) const { return ! approxZero( det( ) ); }
+ /**
+ * Returns the inverse matrix if possible, otherwise a identity matrix
+ */
+ PMMatrix inverse( ) const;
+ /**
+ * Returns the determinant of the matrix
+ */
+ double det( ) const;
+ /**
+ * Multiplies m to the matrix from the right side
+ */
+ PMMatrix& operator*= ( const PMMatrix& m );
+ /**
+ * Multiplies each element with d
+ */
+ PMMatrix& operator*= ( const double d );
+ /**
+ * Divides each element by d
+ */
+ PMMatrix& operator/= ( const double d );
+
+ /**
+ * Returns a matrix with negated elements
+ */
+ friend PMMatrix operator- ( const PMMatrix& m );
+ /**
+ * Multiplies m2 with m1 from the right side (m1*m2)*/
+ friend PMMatrix operator* ( const PMMatrix& m1, const PMMatrix& m2 );
+ /**
+ * Multiplies d to all elements
+ */
+ friend PMMatrix operator* ( const PMMatrix& m, const double d );
+ /**
+ * Multiplies d to all elements
+ */
+ friend PMMatrix operator* ( const GLdouble d, const PMMatrix& m );
+ /**
+ * Divides all elements by d
+ */
+ friend PMMatrix operator/ ( const PMMatrix& m, const double d );
+
+ /**
+ * Only for tests
+ */
+ void testOutput( );
+ /**
+ * Returns a pointer to the data. Can be used in glMultMatrixd
+ */
+ const GLdouble* data( ) const { return m_elements; }
+
+ /**
+ * Returns a string for xml output
+ */
+ QString serializeXML( ) const;
+ /**
+ * loads the vector data from the xml string
+ */
+ bool loadXML( const QString& str );
+private:
+ /**
+ * Exchanges two rows
+ */
+ void exchangeRows( int r1, int r2 );
+ /**
+ * Finds a row with not zero element in column index. Begins to
+ * search in row at position index. Used for det() and inverse()
+ *
+ * Returns -1 if all rows are zero in that column
+ */
+ int notNullElementRow( const int index ) const;
+
+ GLdouble m_elements[16];
+};
+
+#endif
diff --git a/kpovmodeler/pmmedia.cpp b/kpovmodeler/pmmedia.cpp
new file mode 100644
index 00000000..e5229d47
--- /dev/null
+++ b/kpovmodeler/pmmedia.cpp
@@ -0,0 +1,480 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmmedia.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pmmediaedit.h"
+#include "pmcolor.h"
+
+#include <klocale.h>
+
+const int methodDefault = 1;
+const int intervalsDefault = 10;
+const int samplesMinDefault = 1;
+const int samplesMaxDefault = 1;
+const double confidenceDefault = 0.9;
+const double varianceDefault = 0.0078125;
+const double ratioDefault = 0.9;
+const int aaLevelDefault = 4;
+const double aaThresholdDefault = 0.1;
+const PMColor absorptionDefault = PMColor( 0.0, 0.0, 0.0 );
+const PMColor emissionDefault = PMColor( 0.0, 0.0, 0.0 );
+const int scatteringTypeDefault = 0;
+const PMColor scatteringColorDefault = PMColor( 0.0, 0.0, 0.0 );
+const double scatteringEccentricityDefault = 0;
+const double scatteringExtinctionDefault = 1.0;
+
+PMDefinePropertyClass( PMMedia, PMMediaProperty );
+PMMetaObject* PMMedia::s_pMetaObject = 0;
+PMObject* createNewMedia( PMPart* part )
+{
+ return new PMMedia( part );
+}
+
+PMMedia::PMMedia( PMPart* part )
+ : Base( part )
+{
+ m_method = methodDefault;
+ m_intervals = intervalsDefault;
+ m_samplesMin = samplesMinDefault;
+ m_samplesMax = samplesMaxDefault;
+ m_confidence = confidenceDefault;
+ m_variance = varianceDefault;
+ m_ratio = ratioDefault;
+ m_aaLevel = aaLevelDefault;
+ m_aaThreshold = aaThresholdDefault;
+ m_absorption = absorptionDefault;
+ m_emission = emissionDefault;
+ m_scatteringType = scatteringTypeDefault;
+ m_scatteringColor = scatteringColorDefault;
+ m_scatteringEccentricity = scatteringEccentricityDefault;
+ m_scatteringExtinction = scatteringExtinctionDefault;
+ m_enableAbsorption = false;
+ m_enableEmission = false;
+ m_enableScattering = false;
+}
+
+PMMedia::PMMedia( const PMMedia& m )
+ : Base( m )
+{
+ m_method = m.m_method;
+ m_intervals = m.m_intervals;
+ m_samplesMin = m.m_samplesMin;
+ m_samplesMax = m.m_samplesMax;
+ m_aaLevel = m.m_aaLevel;
+ m_confidence = m.m_confidence;
+ m_variance = m.m_variance;
+ m_ratio = m.m_ratio;
+ m_aaThreshold = m.m_aaThreshold;
+ m_absorption = m.m_absorption;
+ m_emission = m.m_emission;
+ m_scatteringType = m.m_scatteringType;
+ m_scatteringColor = m.m_scatteringColor;
+ m_scatteringEccentricity = m.m_scatteringEccentricity;
+ m_scatteringExtinction = m.m_scatteringExtinction;
+ m_enableAbsorption = m.m_enableAbsorption;
+ m_enableEmission = m.m_enableEmission;
+ m_enableScattering = m.m_enableScattering;
+}
+
+PMMedia::~PMMedia( )
+{
+}
+
+PMMetaObject* PMMedia::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Media", Base::metaObject( ),
+ createNewMedia );
+ s_pMetaObject->addProperty(
+ new PMMediaProperty( "method", &PMMedia::setMethod, &PMMedia::method ) );
+ s_pMetaObject->addProperty(
+ new PMMediaProperty( "intervals", &PMMedia::setIntervals, &PMMedia::intervals ) );
+ s_pMetaObject->addProperty(
+ new PMMediaProperty( "samplesMin", &PMMedia::setSamplesMin, &PMMedia::samplesMin ) );
+ s_pMetaObject->addProperty(
+ new PMMediaProperty( "samplesMax", &PMMedia::setSamplesMax, &PMMedia::samplesMax ) );
+ s_pMetaObject->addProperty(
+ new PMMediaProperty( "aaLevel", &PMMedia::setAALevel, &PMMedia::aaLevel ) );
+ s_pMetaObject->addProperty(
+ new PMMediaProperty( "confidence", &PMMedia::setConfidence, &PMMedia::confidence ) );
+ s_pMetaObject->addProperty(
+ new PMMediaProperty( "variance", &PMMedia::setVariance, &PMMedia::variance ) );
+ s_pMetaObject->addProperty(
+ new PMMediaProperty( "ratio", &PMMedia::setRatio, &PMMedia::ratio ) );
+ s_pMetaObject->addProperty(
+ new PMMediaProperty( "aaThreshold", &PMMedia::setAAThreshold, &PMMedia::aaThreshold ) );
+ s_pMetaObject->addProperty(
+ new PMMediaProperty( "absorption", &PMMedia::setAbsorption, &PMMedia::absorption ) );
+ s_pMetaObject->addProperty(
+ new PMMediaProperty( "emission", &PMMedia::setEmission, &PMMedia::emission ) );
+ s_pMetaObject->addProperty(
+ new PMMediaProperty( "scatteringType", &PMMedia::setScatteringType, &PMMedia::scatteringType ) );
+ s_pMetaObject->addProperty(
+ new PMMediaProperty( "scatteringColor", &PMMedia::setScatteringColor, &PMMedia::scatteringColor ) );
+ s_pMetaObject->addProperty(
+ new PMMediaProperty( "scatteringExtinction", &PMMedia::setScatteringExtinction, &PMMedia::scatteringExtinction ) );
+ s_pMetaObject->addProperty(
+ new PMMediaProperty( "scatteringEccentricity", &PMMedia::setScatteringEccentricity, &PMMedia::scatteringEccentricity ) );
+
+ s_pMetaObject->addProperty(
+ new PMMediaProperty( "absorptionEnabled", &PMMedia::enableAbsorption, &PMMedia::isAbsorptionEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMMediaProperty( "emissionEnabled", &PMMedia::enableEmission, &PMMedia::isEmissionEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMMediaProperty( "scatteringEnabled", &PMMedia::enableScattering, &PMMedia::isScatteringEnabled ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMMedia::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMMedia::description( ) const
+{
+ return i18n( "media" );
+}
+
+void PMMedia::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ Base::serialize( e, doc );
+ e.setAttribute( "enable_absorption", m_enableAbsorption );
+ e.setAttribute( "enable_emission", m_enableEmission );
+ e.setAttribute( "enable_scattering", m_enableScattering );
+ e.setAttribute( "method", m_method );
+ e.setAttribute( "intervals", m_intervals );
+ e.setAttribute( "samples_min", m_samplesMin );
+ e.setAttribute( "samples_max", m_samplesMax );
+ e.setAttribute( "aa_level", m_aaLevel );
+ e.setAttribute( "confidence", m_confidence );
+ e.setAttribute( "variance", m_variance );
+ e.setAttribute( "ratio", m_ratio );
+ e.setAttribute( "aa_threshold", m_aaThreshold );
+ e.setAttribute( "absorption", m_absorption.serializeXML( ) );
+ e.setAttribute( "emission", m_emission.serializeXML( ) );
+ e.setAttribute( "scattering_type", m_scatteringType );
+ e.setAttribute( "scattering_color", m_scatteringColor.serializeXML( ) );
+ e.setAttribute( "scattering_eccentricity", m_scatteringEccentricity );
+ e.setAttribute( "scattering_extinction", m_scatteringExtinction );
+}
+
+void PMMedia::readAttributes( const PMXMLHelper& h )
+{
+ Base::readAttributes( h );
+ m_enableAbsorption = h.boolAttribute( "enable_absorption", false );
+ m_enableEmission = h.boolAttribute( "enable_emission", false );
+ m_enableScattering = h.boolAttribute( "enable_scattering", false );
+ m_method = h.intAttribute( "method", methodDefault );
+ m_intervals = h.intAttribute( "intervals", intervalsDefault );
+ m_samplesMin = h.intAttribute( "samples_min", samplesMinDefault );
+ m_samplesMax = h.intAttribute( "samples_max", samplesMaxDefault );
+ m_aaLevel = h.intAttribute( "aa_level", aaLevelDefault );
+ m_confidence = h.doubleAttribute( "confidence", confidenceDefault );
+ m_variance = h.doubleAttribute( "variance", varianceDefault );
+ m_ratio = h.doubleAttribute( "ratio", ratioDefault );
+ m_aaThreshold = h.doubleAttribute( "aa_threshold", aaThresholdDefault );
+ m_absorption = h.colorAttribute( "absorption", absorptionDefault );
+ m_emission = h.colorAttribute( "emission", emissionDefault );
+ m_scatteringType = h.intAttribute( "scattering_type", scatteringTypeDefault );
+ m_scatteringColor = h.colorAttribute( "scattering_color", scatteringColorDefault );
+ m_scatteringEccentricity = h.doubleAttribute( "scattering_eccentricity",
+ scatteringEccentricityDefault );
+ m_scatteringExtinction = h.doubleAttribute( "scattering_extinction",
+ scatteringExtinctionDefault );
+}
+
+void PMMedia::setMethod( int c )
+{
+ if ( c < 1 )
+ {
+ kdError( PMArea ) << "method is < 1 in PMMedia::setMethod\n";
+ c = 1;
+ }
+
+ if ( c > 3 )
+ {
+ kdError( PMArea ) << "method is > 3 in PMMedia::setMethod\n";
+ c = 3;
+ }
+
+ if ( c != m_method )
+ {
+ if ( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMMethodID, m_method );
+ m_method = c;
+ }
+}
+
+void PMMedia::setIntervals( int c )
+{
+ if( c != m_intervals )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMIntervalsID, m_intervals );
+ m_intervals = c;
+ }
+}
+
+void PMMedia::setSamplesMin( int c )
+{
+ if( c != m_samplesMin )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSamplesMinID, m_samplesMin );
+ m_samplesMin = c;
+ }
+}
+
+void PMMedia::setSamplesMax( int c )
+{
+ if( c != m_samplesMax )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSamplesMaxID, m_samplesMax );
+ m_samplesMax = c;
+ }
+}
+
+void PMMedia::setAALevel( int c )
+{
+ if ( c != m_aaLevel )
+ {
+ if ( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAALevelID, m_aaLevel );
+ m_aaLevel = c;
+ }
+}
+
+void PMMedia::setConfidence( double c )
+{
+ if( c != m_confidence )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMConfidenceID, m_confidence );
+ m_confidence = c;
+ }
+}
+
+void PMMedia::setVariance( double c )
+{
+ if( c != m_variance )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMVarianceID, m_variance );
+ m_variance = c;
+ }
+}
+
+void PMMedia::setRatio( double c )
+{
+ if( c != m_ratio )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMRatioID, m_ratio );
+ m_ratio = c;
+ }
+}
+
+void PMMedia::setAAThreshold( double c )
+{
+ if ( c != m_aaThreshold )
+ {
+ if ( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAAThresholdID, m_aaThreshold );
+ m_aaThreshold = c;
+ }
+}
+
+void PMMedia::setAbsorption( const PMColor& c )
+{
+ if( c != m_absorption )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAbsorptionID, m_absorption );
+ m_absorption = c;
+ }
+}
+
+void PMMedia::setEmission( const PMColor& c )
+{
+ if( c != m_emission )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEmissionID, m_emission );
+ m_emission = c;
+ }
+}
+
+void PMMedia::setScatteringType( int c )
+{
+ if( c != m_scatteringType )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMScatteringTypeID, m_scatteringType );
+ m_scatteringType = c;
+ }
+}
+
+void PMMedia::setScatteringColor( const PMColor& c )
+{
+ if( c != m_scatteringColor )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMScatteringColorID, m_scatteringColor );
+ m_scatteringColor = c;
+ }
+}
+
+void PMMedia::setScatteringEccentricity( double c )
+{
+ if( c != m_scatteringEccentricity )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMScatteringEccentricityID, m_scatteringEccentricity );
+ m_scatteringEccentricity = c;
+ }
+}
+
+void PMMedia::setScatteringExtinction( double c )
+{
+ if( c != m_scatteringExtinction )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMScatteringExtinctionID, m_scatteringExtinction );
+ m_scatteringExtinction = c;
+ }
+}
+
+void PMMedia::enableAbsorption( bool c )
+{
+ if( c != m_enableAbsorption )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableAbsorptionID, m_enableAbsorption );
+ m_enableAbsorption = c;
+ }
+}
+
+void PMMedia::enableEmission( bool c )
+{
+ if( c != m_enableEmission )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableEmissionID, m_enableEmission );
+ m_enableEmission = c;
+ }
+}
+
+void PMMedia::enableScattering( bool c )
+{
+ if( c != m_enableScattering )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableScatteringID, m_enableScattering );
+ m_enableScattering = c;
+ }
+}
+
+PMDialogEditBase* PMMedia::editWidget( QWidget* parent ) const
+{
+ return new PMMediaEdit( parent );
+}
+
+void PMMedia::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMEnableAbsorptionID:
+ enableAbsorption( data->boolData( ) );
+ break;
+ case PMEnableEmissionID:
+ enableEmission( data->boolData( ) );
+ break;
+ case PMEnableScatteringID:
+ enableScattering( data->boolData( ) );
+ break;
+ case PMMethodID:
+ setMethod( data->intData( ) );
+ break;
+ case PMIntervalsID:
+ setIntervals( data->intData( ) );
+ break;
+ case PMSamplesMinID:
+ setSamplesMin( data->intData( ) );
+ break;
+ case PMSamplesMaxID:
+ setSamplesMax( data->intData( ) );
+ break;
+ case PMAALevelID:
+ setAALevel( data->intData( ) );
+ break;
+ case PMConfidenceID:
+ setConfidence( data->doubleData( ) );
+ break;
+ case PMVarianceID:
+ setVariance( data->doubleData( ) );
+ break;
+ case PMRatioID:
+ setRatio( data->doubleData( ) );
+ break;
+ case PMAAThresholdID:
+ setAAThreshold( data->doubleData( ) );
+ break;
+ case PMAbsorptionID:
+ setAbsorption( data->colorData( ) );
+ break;
+ case PMEmissionID:
+ setEmission( data->colorData( ) );
+ break;
+ case PMScatteringTypeID:
+ setScatteringType( data->intData( ) );
+ break;
+ case PMScatteringColorID:
+ setScatteringColor( data->colorData( ) );
+ break;
+ case PMScatteringEccentricityID:
+ setScatteringEccentricity( data->doubleData( ) );
+ break;
+ case PMScatteringExtinctionID:
+ setScatteringExtinction( data->doubleData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMMedia::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmmedia.h b/kpovmodeler/pmmedia.h
new file mode 100644
index 00000000..3bf6705b
--- /dev/null
+++ b/kpovmodeler/pmmedia.h
@@ -0,0 +1,149 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMMEDIA_H
+#define PMMEDIA_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebase.h"
+#include "pmcolor.h"
+
+/**
+ * Class for povray medias
+ */
+class PMMedia : public PMTextureBase
+{
+ typedef PMTextureBase Base;
+public:
+ /**
+ * Creates an PMMedia
+ */
+ PMMedia( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMMedia( const PMMedia& m );
+ /**
+ * Deletes the object
+ */
+ virtual ~PMMedia( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMMedia( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMMediaEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmmedia" ); }
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+
+ int method( ) const { return m_method; }
+ int intervals( ) const { return m_intervals; }
+ int samplesMin( ) const { return m_samplesMin; }
+ int samplesMax( ) const { return m_samplesMax; }
+ double confidence( ) const { return m_confidence; }
+ double variance( ) const { return m_variance; }
+ double ratio( ) const { return m_ratio; }
+ int aaLevel( ) const { return m_aaLevel; }
+ double aaThreshold( ) const { return m_aaThreshold; }
+ PMColor absorption( ) const { return m_absorption; }
+ PMColor emission( ) const { return m_emission; }
+ int scatteringType( ) const { return m_scatteringType; }
+ PMColor scatteringColor( ) const { return m_scatteringColor; }
+ double scatteringEccentricity( ) const { return m_scatteringEccentricity; }
+ double scatteringExtinction( ) const { return m_scatteringExtinction; }
+ bool isAbsorptionEnabled( ) const { return m_enableAbsorption; }
+ bool isEmissionEnabled( ) const { return m_enableEmission; }
+ bool isScatteringEnabled( ) const { return m_enableScattering; }
+
+ void setMethod( int c );
+ void setIntervals( int c );
+ void setSamplesMin( int c );
+ void setSamplesMax( int c );
+ void setAALevel( int c );
+ void setConfidence( double c );
+ void setVariance( double c );
+ void setRatio( double c );
+ void setAAThreshold( double c );
+ void setAbsorption( const PMColor& c );
+ void setEmission( const PMColor& c );
+ void setScatteringType( int c );
+ void setScatteringColor( const PMColor& c );
+ void setScatteringEccentricity( double c );
+ void setScatteringExtinction( double c );
+ void enableAbsorption( bool c );
+ void enableEmission( bool c );
+ void enableScattering( bool c );
+
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMMediaMementoID { PMMethodID, PMIntervalsID, PMSamplesMinID, PMSamplesMaxID,
+ PMConfidenceID, PMVarianceID, PMRatioID,
+ PMAALevelID, PMAAThresholdID, PMAbsorptionID, PMEmissionID,
+ PMScatteringTypeID, PMScatteringColorID,
+ PMScatteringEccentricityID, PMScatteringExtinctionID,
+ PMEnableAbsorptionID, PMEnableEmissionID,
+ PMEnableScatteringID };
+
+ int m_method;
+ int m_intervals;
+ int m_samplesMin;
+ int m_samplesMax;
+ double m_confidence;
+ double m_variance;
+ double m_ratio;
+ int m_aaLevel;
+ double m_aaThreshold;
+ PMColor m_absorption;
+ PMColor m_emission;
+ int m_scatteringType;
+ PMColor m_scatteringColor;
+ double m_scatteringEccentricity;
+ double m_scatteringExtinction;
+
+ bool m_enableAbsorption;
+ bool m_enableEmission;
+ bool m_enableScattering;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmmediaedit.cpp b/kpovmodeler/pmmediaedit.cpp
new file mode 100644
index 00000000..2806eff8
--- /dev/null
+++ b/kpovmodeler/pmmediaedit.cpp
@@ -0,0 +1,370 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmmediaedit.h"
+#include "pmmedia.h"
+#include "pmlineedits.h"
+#include "pmcoloredit.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdialog.h>
+
+PMMediaEdit::PMMediaEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMMediaEdit::createTopWidgets( )
+{
+ QHBoxLayout* hl;
+ QGridLayout* gl;
+
+ Base::createTopWidgets( );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "Method:" ), this ) );
+ m_pMethodEdit = new QComboBox( this );
+ m_pMethodEdit->insertItem( i18n( "1 (Monte Carlo)" ) );
+ m_pMethodEdit->insertItem( i18n( "2 (Smooth)" ) );
+ m_pMethodEdit->insertItem( i18n( "3 (Adaptive sampling)" ) );
+ hl->addWidget( m_pMethodEdit );
+ hl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "Intervals:" ), this ) );
+ m_pIntervalsEdit = new PMIntEdit( this );
+ m_pIntervalsEdit->setValidation( true, 1, false, 0 );
+ hl->addWidget( m_pIntervalsEdit );
+ hl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "Samples" ), this ) );
+ hl->addWidget( new QLabel( i18n( "Min:" ), this ) );
+ m_pSamplesMinEdit = new PMIntEdit( this );
+ m_pSamplesMinEdit->setValidation( true, 1, false, 0 );
+ hl->addWidget( m_pSamplesMinEdit );
+ m_pSamplesMaxLabel = new QLabel( i18n( "Max:" ), this );
+ hl->addWidget( m_pSamplesMaxLabel );
+ m_pSamplesMaxEdit = new PMIntEdit( this );
+ hl->addWidget( m_pSamplesMaxEdit );
+ hl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ gl = new QGridLayout( hl, 3, 2 );
+ gl->addWidget( new QLabel( i18n( "Confidence:" ), this ), 0, 0 );
+ m_pConfidenceEdit = new PMFloatEdit( this );
+ m_pConfidenceEdit->setValidation( true, 0, true, 1 );
+ gl->addWidget( m_pConfidenceEdit, 0, 1 );
+ gl->addWidget( new QLabel( i18n( "Variance:" ), this ), 1, 0 );
+ m_pVarianceEdit = new PMFloatEdit( this );
+ gl->addWidget( m_pVarianceEdit, 1, 1 );
+ gl->addWidget( new QLabel( i18n( "Ratio:" ), this ), 2, 0 );
+ m_pRatioEdit = new PMFloatEdit( this );
+ gl->addWidget( m_pRatioEdit, 2, 1 );
+ hl->addStretch( 1 );
+
+ m_pAAWidget = new QWidget( this );
+ hl = new QHBoxLayout( m_pAAWidget, KDialog::spacingHint( ) );
+ hl->addWidget( new QLabel( i18n( "Anti-aliasing" ), m_pAAWidget ) );
+ hl->addWidget( new QLabel( i18n( "Level:" ), m_pAAWidget ) );
+ m_pAALevelEdit = new PMIntEdit( m_pAAWidget );
+ m_pAALevelEdit->setValidation( true, 1, false, 0 );
+ hl->addWidget( m_pAALevelEdit );
+ hl->addWidget( new QLabel( i18n( "Threshold:" ), m_pAAWidget ) );
+ m_pAAThresholdEdit = new PMFloatEdit( m_pAAWidget );
+ m_pAAThresholdEdit->setValidation( true, 0.0, false, 0.0 );
+ hl->addWidget( m_pAAThresholdEdit );
+ hl->addStretch( 1 );
+ topLayout( )->addWidget( m_pAAWidget );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ gl = new QGridLayout( hl, 2, 2 );
+ m_pEnableAbsorptionEdit = new QCheckBox( i18n( "Absorption" ), this );
+ gl->addMultiCellWidget( m_pEnableAbsorptionEdit, 0, 0, 0, 1 );
+ m_pAbsorptionEdit = new PMColorEdit( false, this );
+ m_pAbsorptionLabel = new QLabel( i18n( "Color:" ), this );
+ gl->addWidget( m_pAbsorptionLabel, 1, 0, AlignTop );
+ gl->addWidget( m_pAbsorptionEdit, 1, 1 );
+ hl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ gl = new QGridLayout( hl, 2, 2 );
+ m_pEnableEmissionEdit = new QCheckBox( i18n( "Emission" ), this );
+ gl->addMultiCellWidget( m_pEnableEmissionEdit, 0, 0, 0, 1 );
+ m_pEmissionEdit = new PMColorEdit( false, this );
+ m_pEmissionLabel = new QLabel( i18n( "Color:" ), this );
+ gl->addWidget( m_pEmissionLabel, 1, 0, AlignTop );
+ gl->addWidget( m_pEmissionEdit, 1, 1 );
+ hl->addStretch( 1 );
+
+ m_pEnableScatteringEdit = new QCheckBox( i18n( "Scattering" ), this );
+ topLayout( )->addWidget( m_pEnableScatteringEdit );
+ m_pScatteringWidget = new QWidget( this );
+ QVBoxLayout* vl = new QVBoxLayout( m_pScatteringWidget, KDialog::spacingHint( ) );
+ hl = new QHBoxLayout( vl );
+ hl->addWidget( new QLabel( i18n( "Type:" ), m_pScatteringWidget ) );
+ m_pScatteringTypeEdit = new QComboBox( m_pScatteringWidget );
+ m_pScatteringTypeEdit->insertItem( i18n( "Isotropic" ) );
+ m_pScatteringTypeEdit->insertItem( i18n( "Mie Haze" ) );
+ m_pScatteringTypeEdit->insertItem( i18n( "Mie Murky" ) );
+ m_pScatteringTypeEdit->insertItem( i18n( "Rayleigh" ) );
+ m_pScatteringTypeEdit->insertItem( i18n( "Henyey-Greenstein" ) );
+ hl->addWidget( m_pScatteringTypeEdit );
+ hl->addStretch( 1 );
+ hl = new QHBoxLayout( vl );
+ hl->addWidget( new QLabel( i18n( "Color:" ), m_pScatteringWidget ), 0, AlignTop );
+ m_pScatteringColorEdit = new PMColorEdit( false, m_pScatteringWidget );
+ hl->addWidget( m_pScatteringColorEdit );
+ hl = new QHBoxLayout( vl );
+ gl = new QGridLayout( hl, 2, 2 );
+ m_pScatteringEccentricityLabel = new QLabel( i18n( "Eccentricity:" ), m_pScatteringWidget );
+ gl->addWidget( m_pScatteringEccentricityLabel, 0, 0 );
+ m_pScatteringEccentricityEdit = new PMFloatEdit( m_pScatteringWidget );
+ gl->addWidget( m_pScatteringEccentricityEdit, 0, 1 );
+ gl->addWidget( new QLabel( i18n( "Extinction:" ), m_pScatteringWidget ), 1, 0 );
+ m_pScatteringExtinctionEdit = new PMFloatEdit( m_pScatteringWidget );
+ gl->addWidget( m_pScatteringExtinctionEdit, 1, 1 );
+ hl->addStretch( 1 );
+ topLayout( )->addWidget( m_pScatteringWidget );
+
+ connect( m_pMethodEdit, SIGNAL( activated( int ) ), SLOT( slotMethodChanged( int ) ) );
+ connect( m_pIntervalsEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pSamplesMinEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pSamplesMaxEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pConfidenceEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pVarianceEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pRatioEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pAALevelEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pAAThresholdEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pAbsorptionEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pEmissionEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pEnableAbsorptionEdit, SIGNAL( clicked( ) ), SLOT( slotAbsorptionClicked( ) ) );
+ connect( m_pEnableEmissionEdit, SIGNAL( clicked( ) ), SLOT( slotEmissionClicked( ) ) );
+ connect( m_pEnableScatteringEdit, SIGNAL( clicked( ) ), SLOT( slotScatteringClicked( ) ) );
+ connect( m_pScatteringTypeEdit, SIGNAL( activated( int ) ), SLOT( slotScatteringTypeChanged( int ) ) );
+ connect( m_pScatteringColorEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pScatteringEccentricityEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pScatteringExtinctionEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMMediaEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Media" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMMedia* ) o;
+
+ m_pMethodEdit->setCurrentItem( m_pDisplayedObject->method( ) - 1 );
+ m_pMethodEdit->setEnabled( !readOnly );
+ m_pIntervalsEdit->setValue( m_pDisplayedObject->intervals( ) );
+ m_pIntervalsEdit->setReadOnly( readOnly );
+ m_pSamplesMinEdit->setValue( m_pDisplayedObject->samplesMin( ) );
+ m_pSamplesMinEdit->setReadOnly( readOnly );
+ m_pSamplesMaxEdit->setValue( m_pDisplayedObject->samplesMax( ) );
+ m_pSamplesMaxEdit->setReadOnly( readOnly );
+ m_pConfidenceEdit->setValue( m_pDisplayedObject->confidence( ) );
+ m_pConfidenceEdit->setReadOnly( readOnly );
+ m_pVarianceEdit->setValue( m_pDisplayedObject->variance( ) );
+ m_pVarianceEdit->setReadOnly( readOnly );
+ m_pRatioEdit->setValue( m_pDisplayedObject->ratio( ) );
+ m_pRatioEdit->setReadOnly( readOnly );
+ m_pAALevelEdit->setValue( m_pDisplayedObject->aaLevel( ) );
+ m_pAALevelEdit->setReadOnly( readOnly );
+ m_pAAThresholdEdit->setValue( m_pDisplayedObject->aaThreshold( ) );
+ m_pAAThresholdEdit->setReadOnly( readOnly );
+ m_pAbsorptionEdit->setColor( m_pDisplayedObject->absorption( ) );
+ m_pAbsorptionEdit->setReadOnly( readOnly );
+ m_pEmissionEdit->setColor( m_pDisplayedObject->emission( ) );
+ m_pEmissionEdit->setReadOnly( readOnly );
+ m_pEnableAbsorptionEdit->setChecked( m_pDisplayedObject->isAbsorptionEnabled( ) );
+ m_pEnableAbsorptionEdit->setEnabled( !readOnly );
+ m_pEnableEmissionEdit->setChecked( m_pDisplayedObject->isEmissionEnabled( ) );
+ m_pEnableEmissionEdit->setEnabled( !readOnly );
+ m_pEnableScatteringEdit->setChecked( m_pDisplayedObject->isScatteringEnabled( ) );
+ m_pEnableScatteringEdit->setEnabled( !readOnly );
+ m_pScatteringTypeEdit->setCurrentItem( m_pDisplayedObject->scatteringType( ) - 1 );
+ m_pScatteringTypeEdit->setEnabled( !readOnly );
+ m_pScatteringColorEdit->setColor( m_pDisplayedObject->scatteringColor( ) );
+ m_pScatteringColorEdit->setReadOnly( readOnly );
+ m_pScatteringEccentricityEdit->setValue( m_pDisplayedObject->scatteringEccentricity( ) );
+ m_pScatteringEccentricityEdit->setReadOnly( readOnly );
+ m_pScatteringExtinctionEdit->setValue( m_pDisplayedObject->scatteringExtinction( ) );
+ m_pScatteringExtinctionEdit->setReadOnly( readOnly );
+
+ slotMethodChanged( m_pMethodEdit->currentItem( ) );
+ slotAbsorptionClicked( );
+ slotEmissionClicked( );
+ slotScatteringClicked( );
+ slotScatteringTypeChanged( m_pScatteringTypeEdit->currentItem( ) );
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMMediaEdit: Can't display object\n";
+}
+
+void PMMediaEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setMethod( m_pMethodEdit->currentItem( ) + 1 );
+ m_pDisplayedObject->setIntervals( m_pIntervalsEdit->value( ) );
+ m_pDisplayedObject->setSamplesMin( m_pSamplesMinEdit->value( ) );
+ m_pDisplayedObject->setSamplesMax( m_pSamplesMaxEdit->value( ) );
+ m_pDisplayedObject->setConfidence( m_pConfidenceEdit->value( ) );
+ m_pDisplayedObject->setVariance( m_pVarianceEdit->value( ) );
+ m_pDisplayedObject->setRatio( m_pRatioEdit->value( ) );
+ m_pDisplayedObject->setAALevel( m_pAALevelEdit->value( ) );
+ m_pDisplayedObject->setAAThreshold( m_pAAThresholdEdit->value( ) );
+ m_pDisplayedObject->setAbsorption( m_pAbsorptionEdit->color( ) );
+ m_pDisplayedObject->setEmission( m_pEmissionEdit->color( ) );
+ m_pDisplayedObject->setScatteringType( m_pScatteringTypeEdit->currentItem( ) + 1 );
+ m_pDisplayedObject->setScatteringColor( m_pScatteringColorEdit->color( ) );
+ m_pDisplayedObject->setScatteringEccentricity( m_pScatteringEccentricityEdit->value( ) );
+ m_pDisplayedObject->setScatteringExtinction( m_pScatteringExtinctionEdit->value( ) );
+ m_pDisplayedObject->enableAbsorption( m_pEnableAbsorptionEdit->isChecked( ) );
+ m_pDisplayedObject->enableEmission( m_pEnableEmissionEdit->isChecked( ) );
+ m_pDisplayedObject->enableScattering( m_pEnableScatteringEdit->isChecked( ) );
+ }
+}
+
+bool PMMediaEdit::isDataValid( )
+{
+ if( !m_pIntervalsEdit->isDataValid( ) ) return false;
+ if( !m_pSamplesMinEdit->isDataValid( ) ) return false;
+ if( !m_pSamplesMaxEdit->isDataValid( ) ) return false;
+ if( !m_pConfidenceEdit->isDataValid( ) ) return false;
+ if( !m_pVarianceEdit->isDataValid( ) ) return false;
+ if( !m_pRatioEdit->isDataValid( ) ) return false;
+ if( !m_pAALevelEdit->isDataValid( ) ) return false;
+ if( !m_pAAThresholdEdit->isDataValid( ) ) return false;
+ if( !m_pAbsorptionEdit->isDataValid( ) ) return false;
+ if( !m_pEmissionEdit->isDataValid( ) ) return false;
+ if( !m_pScatteringColorEdit->isDataValid( ) ) return false;
+ if( !m_pScatteringEccentricityEdit->isDataValid( ) ) return false;
+ if( !m_pScatteringExtinctionEdit->isDataValid( ) ) return false;
+ if( m_pMethodEdit->currentItem( ) < 2 &&
+ m_pSamplesMaxEdit->value( ) < m_pSamplesMinEdit->value( ) )
+ {
+ KMessageBox::error( this, i18n( "Maximum number of samples lower than minimum number." ),
+ i18n( "Error" ) );
+ return false;
+ }
+
+ return Base::isDataValid( );
+}
+
+void PMMediaEdit::slotMethodChanged( int c )
+{
+ if ( c == 2 )
+ {
+ m_pAAWidget->show( );
+ m_pSamplesMaxLabel->hide( );
+ m_pSamplesMaxEdit->hide( );
+ }
+ else
+ {
+ m_pAAWidget->hide( );
+ m_pSamplesMaxLabel->show( );
+ m_pSamplesMaxEdit->show( );
+ if ( m_pSamplesMaxEdit->value( ) < m_pSamplesMinEdit->value( ) )
+ m_pSamplesMaxEdit->setValue( m_pSamplesMinEdit->value( ) );
+ }
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+void PMMediaEdit::slotAbsorptionClicked( )
+{
+ if( m_pEnableAbsorptionEdit->isChecked( ) )
+ {
+ m_pAbsorptionEdit->show( );
+ m_pAbsorptionLabel->show( );
+ }
+ else
+ {
+ m_pAbsorptionEdit->hide( );
+ m_pAbsorptionLabel->hide( );
+ }
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+void PMMediaEdit::slotEmissionClicked( )
+{
+ if( m_pEnableEmissionEdit->isChecked( ) )
+ {
+ m_pEmissionEdit->show( );
+ m_pEmissionLabel->show( );
+ }
+ else
+ {
+ m_pEmissionEdit->hide( );
+ m_pEmissionLabel->hide( );
+ }
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+void PMMediaEdit::slotScatteringClicked( )
+{
+ if( m_pEnableScatteringEdit->isChecked( ) )
+ {
+ m_pScatteringWidget->show( );
+ if( m_pScatteringTypeEdit->currentItem( ) == 4 )
+ {
+ m_pScatteringEccentricityLabel->show( );
+ m_pScatteringEccentricityEdit->show( );
+ }
+ else
+ {
+ m_pScatteringEccentricityLabel->hide( );
+ m_pScatteringEccentricityEdit->hide( );
+ }
+ }
+ else
+ m_pScatteringWidget->hide( );
+
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+void PMMediaEdit::slotScatteringTypeChanged( int c )
+{
+ if( c == 4 )
+ {
+ m_pScatteringEccentricityLabel->show( );
+ m_pScatteringEccentricityEdit->show( );
+ }
+ else
+ {
+ m_pScatteringEccentricityLabel->hide( );
+ m_pScatteringEccentricityEdit->hide( );
+ }
+ m_pScatteringWidget->adjustSize( );
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+#include "pmmediaedit.moc"
diff --git a/kpovmodeler/pmmediaedit.h b/kpovmodeler/pmmediaedit.h
new file mode 100644
index 00000000..866e706d
--- /dev/null
+++ b/kpovmodeler/pmmediaedit.h
@@ -0,0 +1,102 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMMEDIAEDIT_H
+#define PMMEDIAEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebaseedit.h"
+
+class PMMedia;
+class PMIntEdit;
+class PMFloatEdit;
+class PMColorEdit;
+class QCheckBox;
+class QLabel;
+class QComboBox;
+
+/**
+ * Dialog edit class for @ref PMMedia
+ */
+class PMMediaEdit : public PMTextureBaseEdit
+{
+ Q_OBJECT
+ typedef PMTextureBaseEdit Base;
+public:
+ /**
+ * Creates a PMMediaEdit with parent and name
+ */
+ PMMediaEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+protected slots:
+ void slotMethodChanged( int c );
+ void slotAbsorptionClicked( );
+ void slotEmissionClicked( );
+ void slotScatteringClicked( );
+ void slotScatteringTypeChanged( int c );
+
+private:
+ PMMedia* m_pDisplayedObject;
+
+ QComboBox* m_pMethodEdit;
+ PMIntEdit* m_pIntervalsEdit;
+ PMIntEdit* m_pSamplesMinEdit;
+ QLabel* m_pSamplesMaxLabel;
+ PMIntEdit* m_pSamplesMaxEdit;
+ PMFloatEdit* m_pConfidenceEdit;
+ PMFloatEdit* m_pVarianceEdit;
+ PMFloatEdit* m_pRatioEdit;
+
+ QWidget* m_pAAWidget;
+ PMIntEdit* m_pAALevelEdit;
+ PMFloatEdit* m_pAAThresholdEdit;
+
+ QCheckBox* m_pEnableAbsorptionEdit;
+ PMColorEdit* m_pAbsorptionEdit;
+ QLabel* m_pAbsorptionLabel;
+
+ QCheckBox* m_pEnableEmissionEdit;
+ PMColorEdit* m_pEmissionEdit;
+ QLabel* m_pEmissionLabel;
+
+ QCheckBox* m_pEnableScatteringEdit;
+ QWidget* m_pScatteringWidget;
+ QComboBox* m_pScatteringTypeEdit;
+ PMColorEdit* m_pScatteringColorEdit;
+ QLabel* m_pScatteringEccentricityLabel;
+ PMFloatEdit* m_pScatteringEccentricityEdit;
+ PMFloatEdit* m_pScatteringExtinctionEdit;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmmemento.cpp b/kpovmodeler/pmmemento.cpp
new file mode 100644
index 00000000..84f52a6e
--- /dev/null
+++ b/kpovmodeler/pmmemento.cpp
@@ -0,0 +1,220 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmmemento.h"
+#include "pmdebug.h"
+
+
+PMMementoData::PMMementoData( PMMetaObject* classType, int vID, int data )
+ : PMVariant( data )
+{
+ m_objectType = classType;
+ m_valueID = vID;
+}
+
+PMMementoData::PMMementoData( PMMetaObject* classType, int vID, unsigned int data )
+ : PMVariant( data )
+{
+ m_objectType = classType;
+ m_valueID = vID;
+}
+
+PMMementoData::PMMementoData( PMMetaObject* classType, int vID, double data )
+ : PMVariant( data )
+{
+ m_objectType = classType;
+ m_valueID = vID;
+}
+
+
+PMMementoData::PMMementoData( PMMetaObject* classType, int vID, bool data )
+ : PMVariant( data )
+{
+ m_objectType = classType;
+ m_valueID = vID;
+}
+
+PMMementoData::PMMementoData( PMMetaObject* classType, int vID, PMThreeState data )
+ : PMVariant( data )
+{
+ m_objectType = classType;
+ m_valueID = vID;
+}
+
+
+PMMementoData::PMMementoData( PMMetaObject* classType, int vID, const QString& data )
+ : PMVariant( data )
+{
+ m_objectType = classType;
+ m_valueID = vID;
+}
+
+PMMementoData::PMMementoData( PMMetaObject* classType, int vID, const PMVector& data )
+ : PMVariant( data )
+{
+ m_objectType = classType;
+ m_valueID = vID;
+}
+
+PMMementoData::PMMementoData( PMMetaObject* classType, int vID, const PMColor& data )
+ : PMVariant( data )
+{
+ m_objectType = classType;
+ m_valueID = vID;
+}
+
+PMMementoData::PMMementoData( PMMetaObject* classType, int vID, PMObject* obj )
+ : PMVariant( obj )
+{
+ m_objectType = classType;
+ m_valueID = vID;
+}
+
+PMMemento::PMMemento( PMObject* originator )
+{
+ m_data.setAutoDelete( true );
+ m_changedObjects.setAutoDelete( true );
+ m_pIDData = 0;
+ m_pOriginatorChange = 0;
+ m_pOriginator = originator;
+}
+
+PMMemento::~PMMemento( )
+{
+ m_data.clear( );
+ m_changedObjects.clear( );
+ // m_pOriginatorChange is in m_changedObjects and is already deleted!
+}
+
+PMMementoData* PMMemento::findData( PMMetaObject* classType, int vID ) const
+{
+ PMMementoDataIterator it( m_data );
+
+ for( ; it.current( ); ++it )
+ {
+ if( ( it.current( )->objectType( ) == classType ) &&
+ ( it.current( )->valueID( ) == vID ) )
+ return it.current( );
+ }
+ return 0;
+}
+
+void PMMemento::addData( PMMementoData* data )
+{
+ m_data.append( data );
+ addChange( PMCData );
+}
+
+void PMMemento::addData( PMMetaObject* classType, int vID, const int data )
+{
+ if( !findData( classType, vID ) )
+ addData( new PMMementoData( classType, vID, data ) );
+}
+
+void PMMemento::addData( PMMetaObject* classType, int vID, const unsigned int data )
+{
+ if( !findData( classType, vID ) )
+ addData( new PMMementoData( classType, vID, data ) );
+}
+
+void PMMemento::addData( PMMetaObject* classType, int vID, const double data )
+{
+ if( !findData( classType, vID ) )
+ addData( new PMMementoData( classType, vID, data ) );
+}
+
+void PMMemento::addData( PMMetaObject* classType, int vID, const bool data )
+{
+ if( !findData( classType, vID ) )
+ addData( new PMMementoData( classType, vID, data ) );
+}
+
+void PMMemento::addData( PMMetaObject* classType, int vID, const PMThreeState data )
+{
+ if( !findData( classType, vID ) )
+ addData( new PMMementoData( classType, vID, data ) );
+}
+
+void PMMemento::addData( PMMetaObject* classType, int vID, const QString& data )
+{
+ if( !findData( classType, vID ) )
+ addData( new PMMementoData( classType, vID, data ) );
+}
+
+void PMMemento::addIDChange( PMMetaObject* classType, int vID, const QString& data )
+{
+ if( !findData( classType, vID ) )
+ {
+ PMMementoData* d = new PMMementoData( classType, vID, data );
+ addData( d );
+ m_pIDData = d;
+ }
+}
+
+void PMMemento::addData( PMMetaObject* classType, int vID, const PMVector& data )
+{
+ if( !findData( classType, vID ) )
+ addData( new PMMementoData( classType, vID, data ) );
+}
+
+void PMMemento::addData( PMMetaObject* classType, int vID, const PMColor& data )
+{
+ if( !findData( classType, vID ) )
+ addData( new PMMementoData( classType, vID, data ) );
+}
+
+void PMMemento::addData( PMMetaObject* classType, int vID, PMObject* obj )
+{
+ if( !findData( classType, vID ) )
+ addData( new PMMementoData( classType, vID, obj ) );
+}
+
+QString PMMemento::oldID( ) const
+{
+ if( m_pIDData )
+ return m_pIDData->stringData( );
+ return QString::null;
+}
+
+void PMMemento::addChangedObject( PMObject* obj, int mode )
+{
+ PMObjectChangeListIterator it( m_changedObjects );
+ PMObjectChange* change = 0;
+
+ while( it.current( ) && !change )
+ {
+ if( it.current( )->object( ) == obj )
+ change = it.current( );
+ else
+ ++it;
+ }
+
+ if( change )
+ change->addMode( mode );
+ else
+ m_changedObjects.append( new PMObjectChange( obj, mode ) );
+}
+
+void PMMemento::addChange( int mode )
+{
+ if( !m_pOriginatorChange )
+ {
+ m_pOriginatorChange = new PMObjectChange( m_pOriginator, PMCData );
+ m_changedObjects.append( m_pOriginatorChange );
+ }
+ m_pOriginatorChange->addMode( mode );
+}
diff --git a/kpovmodeler/pmmemento.h b/kpovmodeler/pmmemento.h
new file mode 100644
index 00000000..a3ea9c98
--- /dev/null
+++ b/kpovmodeler/pmmemento.h
@@ -0,0 +1,318 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMOBJECTMEMENTO_H
+#define PMOBJECTMEMENTO_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmvariant.h"
+#include "pmcommand.h"
+#include "pmmetaobject.h"
+#include <qstring.h>
+#include <qptrlist.h>
+
+/**
+ * Class used by @ref PMObjectMemento to store one value.
+ *
+ * Each piece of data has two IDs: The type of the povray class that stored
+ * the data and a unique ID within this class.
+ *
+ * @see PMMementoDataIterator
+ */
+
+class PMMementoData : public PMVariant
+{
+public:
+ /**
+ * Stores an integer
+ */
+ PMMementoData( PMMetaObject* classType, int vID, int data );
+ /**
+ * Stores an unsigned integer
+ */
+ PMMementoData( PMMetaObject* classType, int vID, unsigned int data );
+ /**
+ * Stores double
+ */
+ PMMementoData( PMMetaObject* classType, int vID, double data );
+ /**
+ * Stores a boolean
+ */
+ PMMementoData( PMMetaObject* classType, int vID, bool data );
+ /**
+ * Stores a @ref PMThreeState
+ */
+ PMMementoData( PMMetaObject* classType, int vID, PMThreeState data );
+ /**
+ * Stores a string
+ */
+ PMMementoData( PMMetaObject* classType, int vID, const QString& data );
+ /**
+ * Stores a @ref PMVector
+ */
+ PMMementoData( PMMetaObject* classType, int vID, const PMVector& data );
+ /**
+ * Stores a @ref PMColor
+ */
+ PMMementoData( PMMetaObject* classType, int vID, const PMColor& data );
+ /**
+ * Stores a pointer to a PMObject
+ */
+ PMMementoData( PMMetaObject* classType, int vID, PMObject* obj );
+
+ /**
+ * Returns the object type of the povray class that stored the data
+ */
+ PMMetaObject* objectType( ) const { return m_objectType; }
+ /**
+ * Returns the ID of the stored value
+ */
+ int valueID( ) const { return m_valueID; }
+
+private:
+ /**
+ * Class that stored the information
+ */
+ PMMetaObject* m_objectType;
+ /**
+ * The unique ID within the m_objectType
+ */
+ int m_valueID;
+};
+
+typedef QPtrList<PMMementoData> PMMementoDataList;
+
+
+/**
+ * Helper class to store information about changed objects in @ref PMMemento
+ */
+class PMObjectChange
+{
+public:
+ /**
+ * Creates change information for the object obj.
+ *
+ * mode is a bitwise combination of @ref PMChange constants.
+ */
+ PMObjectChange( PMObject* obj, int mode )
+ {
+ m_pObject = obj;
+ m_mode = mode;
+ }
+ PMObject* object( ) const { return m_pObject; }
+ int mode( ) const { return m_mode; }
+ void addMode( int mode ) { m_mode |= mode; }
+private:
+ PMObject* m_pObject;
+ int m_mode;
+};
+
+typedef QPtrList<PMObjectChange> PMObjectChangeList;
+typedef QPtrListIterator<PMObjectChange> PMObjectChangeListIterator;
+
+/**
+ * Class that stores the data of povray objects for undo/redo information
+ *
+ * This class should provide enough functionality for most objects. If not,
+ * subclass this class.
+ *
+ * All objects have to use the memento class of its base class or an inherited
+ * one.
+ *
+ * Only the changed attributes of an object are saved.
+ *
+ * See class @ref PMMementoData to see how values are stored.
+ */
+class PMMemento
+{
+ friend class PMMementoDataIterator;
+public:
+ /**
+ * Creates a memento for the object originator
+ */
+ PMMemento( PMObject* originator );
+ /**
+ * Deletes the memento
+ */
+ virtual ~PMMemento( );
+
+ /**
+ * Returns a pointer to the originator
+ */
+ PMObject* originator( ) const { return m_pOriginator; }
+ /**
+ * Returns a pointer to the memento data or 0 if this value is not
+ * stored
+ */
+ PMMementoData* findData( PMMetaObject* classType, int vID ) const;
+ /**
+ * Adds the data object to the list of stored data. The menento may not
+ * contain this information (objType and vID).
+ *
+ * The memento becomes the owner of this object.*/
+ void addData( PMMementoData* data );
+
+ /**
+ * Adds an integer data object. Will be ignored if the memento
+ * already contains this data
+ */
+ void addData( PMMetaObject* classType, int vID, const int data );
+
+ /**
+ * Adds an unsigned data object. Will be ignored if the memento
+ * already contains this data
+ */
+ void addData( PMMetaObject* classType, int vID, const unsigned int data );
+
+ /**
+ * Adds an double data object. Will be ignored if the memento
+ * already contains this data
+ */
+ void addData( PMMetaObject* classType, int vID, const double data );
+
+ /**
+ * Adds an bool data object. Will be ignored if the memento
+ * already contains this data
+ */
+ void addData( PMMetaObject* classType, int vID, const bool data );
+
+ /**
+ * Adds an @ref PMThreeState data object. Will be ignored if the memento
+ * already contains this data
+ */
+ void addData( PMMetaObject* classType, int vID, const PMThreeState data );
+
+ /**
+ * Adds an @ref QString data object. Will be ignored if the memento
+ * already contains this data
+ */
+ void addData( PMMetaObject* classType, int vID, const QString& data );
+
+ /**
+ * Adds an @ref PMVector data object. Will be ignored if the memento
+ * already contains this data
+ */
+ void addData( PMMetaObject* classType, int vID, const PMVector& data );
+
+ /**
+ * Adds an @ref PMColor data object. Will be ignored if the memento
+ * already contains this data
+ */
+ void addData( PMMetaObject* classType, int vID, const PMColor& data );
+
+ /**
+ * Adds an PMObject pointer data object. Will be ignored if the memento
+ * already contains this data
+ */
+ void addData( PMMetaObject* classType, int vID, PMObject* obj );
+
+ /**
+ * Call this to store an id change
+ */
+ void addIDChange( PMMetaObject* classType, int vID, const QString& data );
+
+ /**
+ * Returns true if the memento contains changed data
+ */
+ bool containsChanges( ) const { return ( m_changedObjects.count( ) > 0 ); }
+
+ /**
+ * Call this function, if you stored some data that changed
+ * the view structure of the originator
+ */
+ void setViewStructureChanged( ) { addChange( PMCViewStructure ); }
+ /**
+ * Call this function, if you stored some data that changed
+ * the name or pixmap of the originator
+ */
+ void setDescriptionChanged( ) { addChange( PMCDescription ); }
+
+ /**
+ * Returns true if the id of a @ref PMDeclare was changed
+ */
+ bool idChanged( ) const { return m_pIDData != 0; }
+ /**
+ * Returns the old id
+ */
+ QString oldID( ) const;
+ /**
+ * If one object is changed, other objects can be changed as well.
+ *
+ * For example, if the linked declare of an object link is changed,
+ * the old and new declare are changed as well (Remove the old link,
+ * add the new link).
+ *
+ * This function returns an iterator to the list of all changed objects.
+ * The first object is the originator.
+ */
+ PMObjectChangeListIterator changedObjects( )
+ { return PMObjectChangeListIterator( m_changedObjects ); }
+ /**
+ * Adds the object to the list of changed objects.
+ * Note that the originator is added automatically
+ */
+ void addChangedObject( PMObject* obj, int mode );
+protected:
+ /**
+ * Adds the change to the originator change object
+ */
+ void addChange( int mode );
+private:
+ /**
+ * The stored values
+ */
+ PMMementoDataList m_data;
+ /**
+ * Additional pointer to the memento data for id changes of
+ * @ref PMDeclare objects
+ */
+ PMMementoData* m_pIDData;
+ /**
+ * List of changes
+ */
+ QPtrList<PMObjectChange> m_changedObjects;
+ PMObjectChange* m_pOriginatorChange;
+ PMObject* m_pOriginator;
+};
+
+
+/**
+ * Iterator for memento data
+ */
+class PMMementoDataIterator : public QPtrListIterator<PMMementoData>
+{
+public:
+ PMMementoDataIterator( const PMMemento& m )
+ : QPtrListIterator<PMMementoData>( m.m_data )
+ {
+ }
+ PMMementoDataIterator( const PMMemento* m )
+ : QPtrListIterator<PMMementoData>( m->m_data )
+ {
+ }
+ PMMementoDataIterator( const PMMementoDataList& l )
+ : QPtrListIterator<PMMementoData>( l )
+ {
+ }
+};
+
+#endif
diff --git a/kpovmodeler/pmmesh.cpp b/kpovmodeler/pmmesh.cpp
new file mode 100644
index 00000000..571170a9
--- /dev/null
+++ b/kpovmodeler/pmmesh.cpp
@@ -0,0 +1,557 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmmesh.h"
+
+#include <klocale.h>
+#include "pmxmlhelper.h"
+#include "pmmeshedit.h"
+#include "pmmemento.h"
+#include "pmtriangle.h"
+#include "pm3dcontrolpoint.h"
+#include "pmvectorcontrolpoint.h"
+
+const PMVector insideVectorDefault = PMVector( 0.0, 0.0, 0.0 );
+
+PMDefinePropertyClass( PMMesh, PMMeshProperty );
+
+class PMMeshMemento : public PMMemento
+{
+public:
+ /**
+ * Creates a memento for the object originator
+ */
+ PMMeshMemento( PMObject* originator ) : PMMemento( originator )
+ {
+ m_bTriangleMementosSaved = false;
+ m_triangleMementos.setAutoDelete( true );
+ }
+ /**
+ * Deletes the memento
+ */
+ virtual ~PMMeshMemento( )
+ {
+ m_triangleMementos.clear( );
+ }
+
+ /**
+ * Saves the triangles memento data
+ */
+ void setTriangleMementos( const QPtrList<PMMemento>& list )
+ {
+ if ( !m_bTriangleMementosSaved )
+ {
+ QPtrListIterator<PMMemento> Itr( list );
+ PMMemento* m;
+ while( ( m = Itr.current( ) ) != 0 )
+ {
+ m_triangleMementos.append( m );
+ ++Itr;
+ }
+
+ m_bTriangleMementosSaved = true;
+ addChange( PMCData );
+ }
+ }
+ /**
+ * Returns the triangles memento data
+ */
+ QPtrList<PMMemento> triangleMementos( ) const
+ {
+ if ( !m_bTriangleMementosSaved )
+ kdError( PMArea ) << "Triangles mementos not saved in PMMeshMemento::triangleMementos\n";
+ return m_triangleMementos;
+ }
+ /**
+ * Returns true if the triangle mementos have been saved
+ */
+ bool triangleMementosSaved( ) const { return m_bTriangleMementosSaved; }
+private:
+ QPtrList<PMMemento> m_triangleMementos;
+ bool m_bTriangleMementosSaved;
+};
+
+PMMetaObject* PMMesh::s_pMetaObject = 0;
+PMObject* createNewMesh( PMPart* part )
+{
+ return new PMMesh( part );
+}
+
+PMMesh::PMMesh( PMPart* part )
+ : Base( part )
+{
+ m_hierarchy = true;
+ m_enableInsideVector = false;
+ m_insideVector = insideVectorDefault;
+}
+
+PMMesh::PMMesh( const PMMesh& m )
+ : Base( m )
+{
+ m_hierarchy = m.m_hierarchy;
+ m_enableInsideVector = m.m_enableInsideVector;
+ m_insideVector = m.m_insideVector;
+}
+
+PMMesh::~PMMesh( )
+{
+}
+
+QString PMMesh::description( ) const
+{
+ return i18n( "mesh" );
+}
+
+void PMMesh::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "hierarchy", m_hierarchy );
+ e.setAttribute( "enable_inside_vector", m_enableInsideVector );
+ e.setAttribute( "inside_vector", m_insideVector.serializeXML( ) );
+ Base::serialize( e, doc );
+}
+
+void PMMesh::readAttributes( const PMXMLHelper& h )
+{
+ m_hierarchy = h.boolAttribute( "hierarchy", true );
+ m_enableInsideVector = h.boolAttribute( "enable_inside_vector", false );
+ m_insideVector = h.vectorAttribute( "inside_vector", insideVectorDefault );
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMMesh::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Mesh", Base::metaObject( ), createNewMesh );
+
+ s_pMetaObject->addProperty(
+ new PMMeshProperty( "hierarchy", &PMMesh::setHierarchy, &PMMesh::hierarchy ) );
+ s_pMetaObject->addProperty(
+ new PMMeshProperty( "insideVectorEnabled", &PMMesh::enableInsideVector, &PMMesh::isInsideVectorEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMMeshProperty( "insideVector", &PMMesh::setInsideVector, &PMMesh::insideVector ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMMesh::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMMesh::setHierarchy( bool h )
+{
+ if( h != m_hierarchy )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMHierarchyID, m_hierarchy );
+ m_hierarchy = h;
+ }
+}
+
+void PMMesh::enableInsideVector( bool eiv )
+{
+ if( eiv != m_enableInsideVector )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableInsideVectorID, m_enableInsideVector );
+ m_enableInsideVector = eiv;
+ }
+}
+
+void PMMesh::setInsideVector( const PMVector& iv )
+{
+ if( iv != m_insideVector )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMInsideVectorID, m_insideVector );
+ m_insideVector = iv;
+ }
+}
+
+PMDialogEditBase* PMMesh::editWidget( QWidget* parent ) const
+{
+ return new PMMeshEdit( parent );
+}
+
+void PMMesh::createMemento( )
+{
+ delete m_pMemento;
+ m_pMemento = new PMMeshMemento( this );
+}
+
+void PMMesh::restoreMemento( PMMemento* s )
+{
+ PMMeshMemento* m = ( PMMeshMemento * ) s;
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMHierarchyID:
+ setHierarchy( data->boolData( ) );
+ break;
+ case PMEnableInsideVectorID:
+ enableInsideVector( data->boolData( ) );
+ break;
+ case PMInsideVectorID:
+ setInsideVector( data->vectorData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMMesh::restoreMemento\n";
+ break;
+ }
+ }
+ }
+
+ if ( m->triangleMementosSaved( ) )
+ {
+ int numChildren = countChildren( );
+ PMMemento* tm;
+ QPtrList<PMMemento> list = m->triangleMementos( );
+ QPtrListIterator<PMMemento> Itr( list );
+ for ( int i = 0; i < numChildren && ( tm = Itr.current( ) ) != 0; ++i, ++Itr )
+ childAt( i )->restoreMemento( tm );
+ }
+
+ Base::restoreMemento( s );
+}
+
+void PMMesh::controlPoints( PMControlPointList& list )
+{
+ unsigned numChildren = countChildren();
+ PMTriangle *obj;
+ pointToPoint ptp;
+ bool found;
+ PMVector point, normal;
+ PMControlPoint* listP;
+ PM3DControlPoint* cp;
+ PMVectorControlPoint* vp;
+ int currentPoint = 0;
+ int firstNormal = numChildren * 3;
+ int currentNormal = firstNormal;
+
+ m_pointToPointList.clear( );
+ for ( unsigned i = 0; i < numChildren; ++i )
+ {
+ if ( childAt( i )->isA( "Triangle" ) )
+ {
+
+ obj = ( PMTriangle * ) childAt( i );
+ ptp.object = obj;
+ for ( unsigned j = 0; j < 3; ++j )
+ {
+ found = false;
+ ptp.pointID = j;
+ point = obj->point( j );
+
+ for( listP = list.first( ); listP; listP = list.next( ) )
+ {
+ if ( listP->id( ) < firstNormal && point == listP->position( ) )
+ {
+ found = true;
+ ptp.listID = listP->id( );
+ break;
+ }
+ }
+
+ if ( !found )
+ {
+ cp = new PM3DControlPoint( point, currentPoint,
+ i18n( "Mesh Point " + currentPoint ) );
+ list.append( cp );
+ ptp.listID = currentPoint++;
+ }
+
+ m_pointToPointList.append( ptp );
+
+ if ( obj->isSmoothTriangle( ) )
+ {
+ found = false;
+ ptp.pointID = j + 3;
+ normal = obj->normal( j );
+
+ for ( listP = list.first( ); listP; listP = list.next( ) )
+ {
+ if ( listP->id( ) >= firstNormal )
+ {
+ vp = ( PMVectorControlPoint* ) listP;
+ if ( vp->basePoint( ) == point &&
+ vp->vector( ) == normal )
+ {
+ found = true;
+ ptp.listID = listP->id( );
+ break;
+ }
+ }
+ }
+
+ if ( !found )
+ {
+ vp = new PMVectorControlPoint( point, normal, currentNormal,
+ i18n( "Mesh Normal " + currentNormal ) );
+ list.append( vp );
+ ptp.listID = currentNormal++;
+ }
+
+ m_pointToPointList.append( ptp );
+ }
+
+ }
+ }
+ }
+}
+
+void PMMesh::controlPointsChangedList( PMControlPointList& list, PMObjectList& objList )
+{
+ int numChildren = countChildren( );
+ PMControlPoint* p;
+ QValueList<pointToPoint>::ConstIterator ptpItr = m_pointToPointList.begin( );
+ QPtrList<PMMemento> mementoList;
+ PMTriangle *obj;
+ PMVector p0, p1, p2;
+ PM3DControlPoint* cp0, * cp1, * cp2;
+ bool bp0, bp1, bp2;
+ PMVector n0, n1, n2;
+ PMVectorControlPoint* cn0, * cn1, * cn2;
+ bool bn0, bn1, bn2;
+ PMVector triangleNormal;
+ double d, normalDirection = 1.0;
+ bool found, validNormal, validTriangles = true;
+ int listID, pointID, numCP;
+
+ // have to cache changed values because checking once changes them to false
+ QMemArray<bool> changed( list.count( ) );
+ p = list.first( );
+ for ( int i = 0; p; ++i, p = list.next( ) )
+ changed[i] = p->changed( );
+
+ for ( int i = 0; i < numChildren && validTriangles; ++i )
+ {
+ if ( childAt( i )->isA( "Triangle" ) )
+ {
+ obj = ( PMTriangle* )childAt( i );
+ obj->createMemento( );
+ objList.append( obj );
+ validNormal = false;
+
+ if ( obj->isSmoothTriangle( ) )
+ numCP = 6;
+ else
+ numCP = 3;
+
+ cp0 = cp1 = cp2 = 0;
+ cn0 = cn1 = cn2 = 0;
+
+ bp0 = bp1 = bp2 = bn0 = bn1 = bn2 = false;
+
+ for ( int j = 0; j < numCP; ++j, ++ptpItr )
+ {
+
+ listID = (*ptpItr).listID;
+ pointID = (*ptpItr).pointID;
+ found = false;
+ p = list.first( );
+ for ( int k = 0; p && !found; p = list.next( ), ++k )
+ {
+ if( listID == p->id( ) )
+ {
+ switch( pointID )
+ {
+ case 0:
+ cp0 = ( PM3DControlPoint* ) p;
+ p0 = cp0->point( );
+ bp0 = changed[ k ];
+ break;
+ case 1:
+ cp1 = ( PM3DControlPoint* ) p;
+ p1 = cp1->point( );
+ bp1 = changed[ k ];
+ break;
+ case 2:
+ cp2 = ( PM3DControlPoint* ) p;
+ p2 = cp2->point( );
+ bp2 = changed[ k ];
+ break;
+ case 3:
+ cn0 = ( PMVectorControlPoint* ) p;
+ n0 = cn0->vector( );
+ bn0 = changed[ k ];
+ break;
+ case 4:
+ cn1 = ( PMVectorControlPoint* ) p;
+ n1 = cn1->vector( );
+ bn1 = changed[ k ];
+ break;
+ case 5:
+ cn2 = ( PMVectorControlPoint* ) p;
+ n2 = cn2->vector( );
+ bn2 = changed[ k ];
+ break;
+ default:
+ break;
+ }
+ found = true;
+ }
+ }
+ }
+
+ if ( obj->isSmoothTriangle( ) )
+ {
+ triangleNormal = PMVector::cross( obj->point( 1 ) - obj->point( 0 ),
+ obj->point( 2 ) - obj->point( 0 ) );
+ normalDirection = PMVector::dot( triangleNormal, obj->normal( 0 ) );
+ if( approxZero( normalDirection ) )
+ normalDirection = PMVector::dot( triangleNormal, obj->normal( 1 ) );
+ if( approxZero( normalDirection ) )
+ normalDirection = PMVector::dot( triangleNormal, obj->normal( 2 ) );
+ if( normalDirection < 0 )
+ triangleNormal = -triangleNormal;
+ if( !approxZero( triangleNormal.abs( ) ) )
+ {
+ validNormal = true;
+ triangleNormal /= triangleNormal.abs( );
+ }
+ }
+
+ if ( bp0 )
+ {
+ if ( !( p0.approxEqual( p1 ) || p0.approxEqual( p2 ) ) )
+ obj->setPoint( 0, p0 );
+ else
+ {
+ validTriangles = false;
+ cp0->setPoint( obj->point( 0 ) );
+ break;
+ }
+ }
+
+ if ( bp1 )
+ {
+ if ( !( p1.approxEqual( p0 ) || p1.approxEqual( p2 ) ) )
+ obj->setPoint( 1, p1 );
+ else
+ {
+ validTriangles = false;
+ cp1->setPoint( obj->point( 1 ) );
+ break;
+ }
+ }
+
+ if ( bp2 )
+ {
+ if ( !( p2.approxEqual( p0 ) || p2.approxEqual( p1 ) ) )
+ obj->setPoint( 2, p2 );
+ else
+ {
+ validTriangles = false;
+ cp2->setPoint( obj->point( 2 ) );
+ break;
+ }
+ }
+
+ if ( obj->isSmoothTriangle( ) )
+ {
+ if ( bn0 )
+ {
+ if( validNormal )
+ {
+ d = PMVector::dot( triangleNormal, n0 );
+ if( d > 0 )
+ obj->setNormal( 0, n0 );
+ else
+ {
+ obj->setNormal( 0, n0 - ( d - 1e-5 ) * triangleNormal );
+ cn0->setVector( obj->normal( 0 ) );
+ }
+ }
+ else
+ cn0->setVector( obj->normal( 0 ) );
+ }
+
+ if ( bn1 )
+ {
+ if( validNormal )
+ {
+ d = PMVector::dot( triangleNormal, n1 );
+ if( d > 0 )
+ obj->setNormal( 1, n1 );
+ else
+ {
+ obj->setNormal( 1, n1 - ( d - 1e-5 ) * triangleNormal );
+ cn1->setVector( obj->normal( 1 ) );
+ }
+ }
+ else
+ cn1->setVector( obj->normal( 1 ) );
+ }
+
+ if ( bn2 )
+ {
+ if( validNormal )
+ {
+ d = PMVector::dot( triangleNormal, n2 );
+ if( d > 0 )
+ obj->setNormal( 2, n2 );
+ else
+ {
+ obj->setNormal( 2, n2 - ( d - 1e-5 ) * triangleNormal );
+ cn2->setVector( obj->normal( 2 ) );
+ }
+ }
+ else
+ cn2->setVector( obj->normal( 2 ) );
+ }
+ }
+
+ mementoList.append( obj->takeMemento( ) );
+
+ if ( !validTriangles )
+ {
+ PMMemento *tm;
+ for ( int j = i; j >= 0; --j )
+ {
+ if ( ( tm = mementoList.getLast( ) ) )
+ {
+ childAt( j )->restoreMemento( tm );
+ delete tm;
+ mementoList.removeLast( );
+ }
+ }
+ }
+ }
+ }
+
+ if ( validTriangles )
+ {
+ if ( m_pMemento )
+ ( ( PMMeshMemento * ) m_pMemento )->setTriangleMementos( mementoList );
+ objList.append( this );
+ setViewStructureChanged( );
+ }
+}
diff --git a/kpovmodeler/pmmesh.h b/kpovmodeler/pmmesh.h
new file mode 100644
index 00000000..4045d3ab
--- /dev/null
+++ b/kpovmodeler/pmmesh.h
@@ -0,0 +1,142 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMMESH_H
+#define PMMESH_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobject.h"
+#include "pmvector.h"
+
+class PMTriangle;
+
+/**
+ * Class for povray mesh objects.
+ */
+class PMMesh : public PMSolidObject
+{
+ typedef PMSolidObject Base;
+public:
+ /**
+ * Creates an empty PMMesh object
+ */
+ PMMesh( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMMesh( const PMMesh& m );
+
+ /**
+ * deletes the PMMesh object
+ */
+ virtual ~PMMesh( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMMesh( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMMeshEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmmesh" ); }
+
+ /**
+ * Returns the hierarchy flag
+ */
+ bool hierarchy( ) const { return m_hierarchy; }
+ /**
+ * Sets the type of the csg
+ */
+ void setHierarchy( bool h );
+
+ /**
+ * Returns true if the inside vector is enabled
+ */
+ bool isInsideVectorEnabled( ) const { return m_enableInsideVector; }
+ /**
+ * Sets the inside vector flag
+ */
+ void enableInsideVector( bool eiv );
+
+ /**
+ * Returns the inside vector
+ */
+ PMVector insideVector( ) const { return m_insideVector; }
+ /**
+ * Sets the inside vector
+ */
+ void setInsideVector( const PMVector& iv );
+
+ /** */
+ virtual void createMemento( );
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /** */
+ virtual void controlPoints( PMControlPointList& list );
+ /** */
+ virtual void controlPointsChangedList( PMControlPointList& list, PMObjectList& objList );
+
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMMeshMementoID { PMHierarchyID, PMEnableInsideVectorID,
+ PMInsideVectorID };
+
+ bool m_hierarchy;
+ bool m_enableInsideVector;
+ PMVector m_insideVector;
+
+ static PMMetaObject* s_pMetaObject;
+
+ /**
+ * Point to point structure for changes with control points
+ */
+ struct pointToPoint {
+ PMTriangle *object;
+ int pointID;
+ int listID;
+ };
+
+ /**
+ * List of point to point structures
+ */
+ QValueList<pointToPoint> m_pointToPointList;
+};
+
+#endif
diff --git a/kpovmodeler/pmmeshedit.cpp b/kpovmodeler/pmmeshedit.cpp
new file mode 100644
index 00000000..0b0e2269
--- /dev/null
+++ b/kpovmodeler/pmmeshedit.cpp
@@ -0,0 +1,100 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmmeshedit.h"
+#include "pmmesh.h"
+#include "pmvectoredit.h"
+
+#include <qlayout.h>
+#include <qcheckbox.h>
+
+#include <klocale.h>
+
+PMMeshEdit::PMMeshEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMMeshEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* layout;
+ m_pHierarchy = new QCheckBox( i18n( "Hierarchy" ), this );
+ m_pEnableInsideVector = new QCheckBox( i18n( "Inside vector:" ), this );
+ m_pInsideVector = new PMVectorEdit( "x", "y", "z", this );
+ layout = new QHBoxLayout( topLayout( ) );
+ layout->addWidget( m_pHierarchy );
+ layout->addStretch( 1 );
+ layout = new QHBoxLayout( topLayout( ) );
+ layout->addWidget( m_pEnableInsideVector );
+ layout->addWidget( m_pInsideVector );
+ layout->addStretch( 1 );
+
+ connect( m_pHierarchy, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pEnableInsideVector, SIGNAL( clicked( ) ), SLOT( slotInsideVectorClicked( ) ) );
+ connect( m_pInsideVector, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMMeshEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Mesh" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMMesh* ) o;
+
+ m_pHierarchy->setChecked( m_pDisplayedObject->hierarchy( ) );
+ m_pHierarchy->setEnabled( !readOnly );
+ m_pEnableInsideVector->setChecked( m_pDisplayedObject->isInsideVectorEnabled( ) );
+ m_pEnableInsideVector->setEnabled( !readOnly );
+ m_pInsideVector->setVector( m_pDisplayedObject->insideVector( ) );
+ m_pInsideVector->setReadOnly( readOnly );
+ slotInsideVectorClicked( );
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMMeshEdit: Can't display object\n";
+}
+
+void PMMeshEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setHierarchy( m_pHierarchy->isChecked( ) );
+ m_pDisplayedObject->enableInsideVector( m_pEnableInsideVector->isChecked( ) );
+ m_pDisplayedObject->setInsideVector( m_pInsideVector->vector( ) );
+ }
+}
+
+bool PMMeshEdit::isDataValid( )
+{
+ return Base::isDataValid( );
+}
+
+void PMMeshEdit::slotInsideVectorClicked( )
+{
+ if( m_pEnableInsideVector->isChecked( ) )
+ m_pInsideVector->setEnabled( true );
+ else
+ m_pInsideVector->setEnabled( false );
+ emit dataChanged( );
+}
+
+#include "pmmeshedit.moc"
diff --git a/kpovmodeler/pmmeshedit.h b/kpovmodeler/pmmeshedit.h
new file mode 100644
index 00000000..1a778ac8
--- /dev/null
+++ b/kpovmodeler/pmmeshedit.h
@@ -0,0 +1,67 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMMESHEDIT_H
+#define PMMESHEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobjectedit.h"
+
+class PMMesh;
+class QCheckBox;
+class PMVectorEdit;
+
+/**
+ * Dialog edit class for @ref PMMesh
+ */
+class PMMeshEdit : public PMSolidObjectEdit
+{
+ Q_OBJECT
+ typedef PMSolidObjectEdit Base;
+public:
+ /**
+ * Creates a PMMeshEdit with parent and name
+ */
+ PMMeshEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+protected slots:
+ void slotInsideVectorClicked( );
+private:
+ PMMesh* m_pDisplayedObject;
+
+ QCheckBox* m_pHierarchy;
+ QCheckBox* m_pEnableInsideVector;
+ PMVectorEdit* m_pInsideVector;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmmessage.cpp b/kpovmodeler/pmmessage.cpp
new file mode 100644
index 00000000..5587181f
--- /dev/null
+++ b/kpovmodeler/pmmessage.cpp
@@ -0,0 +1,43 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmmessage.h"
+
+PMMessage::PMMessage( )
+{
+ m_pObject = 0;
+}
+
+PMMessage::PMMessage( const QString& text, PMObject* object )
+{
+ m_sText = text;
+ m_pObject = object;
+}
+
+PMMessage::PMMessage( const PMMessage& m )
+{
+ m_sText = m.m_sText;
+ m_pObject = m.m_pObject;
+}
+
+PMMessage& PMMessage::operator=( const PMMessage& m )
+{
+ m_sText = m.m_sText;
+ m_pObject = m.m_pObject;
+ return *this;
+}
+
diff --git a/kpovmodeler/pmmessage.h b/kpovmodeler/pmmessage.h
new file mode 100644
index 00000000..1247ccb0
--- /dev/null
+++ b/kpovmodeler/pmmessage.h
@@ -0,0 +1,79 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMMESSAGE_H
+#define PMMESSAGE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmobject.h"
+
+#include <qvaluelist.h>
+#include <qstring.h>
+
+/**
+ * Class for messages in the @ref PMErrorDialog
+ */
+class PMMessage
+{
+public:
+ /**
+ * Default constructor
+ */
+ PMMessage( );
+ /**
+ * Creates a message with a text and optionally with
+ * a link to an object
+ */
+ PMMessage( const QString& text, PMObject* object = 0 );
+ /**
+ * Copy constructor
+ */
+ PMMessage( const PMMessage& m );
+ /**
+ * Assignment operator
+ */
+ PMMessage& operator=( const PMMessage& m );
+
+ /**
+ * Returns the message text
+ */
+ QString text( ) const { return m_sText; }
+ /**
+ * Sets the message text
+ */
+ void setText( const QString& text ) { m_sText = text; }
+ /**
+ * Returns the linked object or 0
+ */
+ PMObject* linkedObject( ) const { return m_pObject; }
+ /**
+ * Sets the linked object
+ */
+ void setLinkedObject( PMObject* o ) { m_pObject = o; }
+
+private:
+ QString m_sText;
+ PMObject* m_pObject;
+};
+
+typedef QValueList<PMMessage> PMMessageList;
+
+#endif
diff --git a/kpovmodeler/pmmetaobject.cpp b/kpovmodeler/pmmetaobject.cpp
new file mode 100644
index 00000000..a7e98b9b
--- /dev/null
+++ b/kpovmodeler/pmmetaobject.cpp
@@ -0,0 +1,95 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmmetaobject.h"
+
+PMPropertyBase::PMPropertyBase( const QString& name,
+ PMVariant::PMVariantDataType t,
+ bool readOnly, bool writeOnly )
+{
+ m_name = name;
+ m_type = t;
+ m_pEnumList = 0;
+ m_readOnly = readOnly;
+ m_writeOnly = writeOnly;
+}
+
+PMPropertyBase::PMPropertyBase( const PMPropertyBase& p )
+{
+ m_name = p.m_name;
+ m_type = p.m_type;
+ m_readOnly = p.m_readOnly;
+ m_writeOnly = p.m_writeOnly;
+
+ if( p.m_pEnumList )
+ m_pEnumList = new QStringList( *( p.m_pEnumList ) );
+ else
+ m_pEnumList = 0;
+}
+
+PMPropertyBase::~PMPropertyBase( )
+{
+ delete m_pEnumList;
+}
+
+bool PMPropertyBase::setProperty( PMObject* obj, const PMVariant& v )
+{
+ if( m_readOnly )
+ return false;
+ PMVariant cp = v;
+ if( cp.convertTo( m_type ) )
+ return setProtected( obj, cp );
+ return false;
+}
+
+PMVariant PMPropertyBase::getProperty( const PMObject* obj )
+{
+ if( m_writeOnly )
+ return PMVariant( );
+ return getProtected( obj );
+}
+
+PMMetaObject::PMMetaObject( const QString& className, PMMetaObject* superClass,
+ PMObjectFactoryMethod factory )
+{
+ m_className = className;
+ m_pSuperClass = superClass;
+ m_factory = factory;
+
+ // add the properties of the super class to the dictionary
+ if( m_pSuperClass )
+ m_propertiesDict = superClass->m_propertiesDict;
+}
+
+PMMetaObject::~PMMetaObject( )
+{
+ m_properties.setAutoDelete( true );
+ m_properties.clear( );
+}
+
+void PMMetaObject::addProperty( PMPropertyBase* p )
+{
+ m_properties.append( p );
+ m_propertiesDict.insert( p->name( ), p );
+}
+
+PMObject* PMMetaObject::newObject( PMPart* part ) const
+{
+ if( m_factory )
+ return m_factory( part );
+ return 0;
+}
diff --git a/kpovmodeler/pmmetaobject.h b/kpovmodeler/pmmetaobject.h
new file mode 100644
index 00000000..f8daf2eb
--- /dev/null
+++ b/kpovmodeler/pmmetaobject.h
@@ -0,0 +1,416 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMMETAOBJECT_H
+#define PMMETAOBJECT_H
+
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qptrlist.h>
+#include <qdict.h>
+#include "pmvariant.h"
+
+class PMPart;
+
+/**
+ * Base class for all properties
+ */
+class PMPropertyBase
+{
+public:
+ /**
+ * Default constructor
+ */
+ PMPropertyBase( const QString& name, PMVariant::PMVariantDataType t,
+ bool readOnly = false, bool writeOnly = false );
+ /**
+ * Copy constructor
+ */
+ PMPropertyBase( const PMPropertyBase& p );
+ /**
+ * Destructor
+ */
+ virtual ~PMPropertyBase( );
+
+ /**
+ * Returns the properties name
+ */
+ QString name( ) const { return m_name; }
+ /**
+ * Returns the data type
+ */
+ PMVariant::PMVariantDataType type( ) const { return m_type; }
+
+ /**
+ * Sets the property.
+ *
+ * Returns true if successful.
+ *
+ * Makes a type check and calls @ref setProtected on success.
+ */
+ bool setProperty( PMObject* obj, const PMVariant& );
+
+ /**
+ * Returns the property value
+ */
+ PMVariant getProperty( const PMObject* obj );
+
+ /**
+ * Returns the number of dimensions for array properties
+ * or 0 otherwise
+ */
+ virtual int dimensions( ) const { return 0; }
+ /**
+ * Has to be reimplemented for array properties.
+ *
+ * The first parameter is the dimension, the second the index.
+ */
+ virtual void setIndex( int /*dimension*/, int /*index*/ ) { };
+ /**
+ * Has to be reimplemented for array properties.
+ *
+ * Returns the current size for the object and dimension.
+ */
+ virtual int size( PMObject*, int /*dimension*/ ) const { return 0; }
+
+ /**
+ * Returns true if the property is an enum
+ */
+ virtual bool isEnum( ) const { return false; }
+ /**
+ * Returns the list of enum values
+ */
+ virtual QStringList enumValues( ) const { return QStringList( ); }
+
+ /**
+ * Returns true if the property is read-only. False by default
+ */
+ bool isReadOnly( ) const { return m_readOnly; }
+ /**
+ * Returns true if the property is write-only. False by default
+ */
+ bool isWriteOnly( ) const { return m_writeOnly; }
+
+protected:
+ /**
+ * Reimplement this function to call the correct object method.
+ *
+ * The variant is already converted to the correct type.
+ */
+ virtual bool setProtected( PMObject* obj, const PMVariant& ) = 0;
+
+ /**
+ * Reimplement this function to call the correct object method.
+ */
+ virtual PMVariant getProtected( const PMObject* obj ) = 0;
+
+private:
+ PMVariant::PMVariantDataType m_type;
+ QString m_name;
+ QStringList* m_pEnumList;
+ bool m_readOnly;
+ bool m_writeOnly;
+};
+
+typedef QPtrList<PMPropertyBase> PMPropertyList;
+typedef QDict<PMPropertyBase> PMPropertyDict;
+typedef QDictIterator<PMPropertyBase> PMPropertyIterator;
+
+/**
+ * Macro that defines a property class for a PMObject class
+ *
+ * Example: PMDefinePropertyClass( PMBox, PMProperty ); defines
+ * a class PMProperty that can store pointer to member functions
+ * for PMBox objects.
+ *
+ * Use only in .cpp files.
+ */
+
+#define PMDefinePropertyClass( ObjectClass, PropertyClass ) \
+class PropertyClass : public PMPropertyBase \
+{ \
+public: \
+ typedef void ( ObjectClass::*SetIntPtr ) ( int ); \
+ typedef void ( ObjectClass::*SetUnsignedPtr ) ( unsigned ); \
+ typedef void ( ObjectClass::*SetDoublePtr ) ( double ); \
+ typedef void ( ObjectClass::*SetBoolPtr ) ( bool ); \
+ typedef void ( ObjectClass::*SetThreeStatePtr )( PMThreeState ); \
+ typedef void ( ObjectClass::*SetStringPtr ) ( const QString& ); \
+ typedef void ( ObjectClass::*SetVectorPtr ) ( const PMVector& ); \
+ typedef void ( ObjectClass::*SetColorPtr ) ( const PMColor& ); \
+ typedef void ( ObjectClass::*SetObjectPtr ) ( PMObject* ); \
+ \
+ typedef int ( ObjectClass::*GetIntPtr ) ( void ) const; \
+ typedef unsigned ( ObjectClass::*GetUnsignedPtr ) ( void ) const; \
+ typedef double ( ObjectClass::*GetDoublePtr ) ( void ) const; \
+ typedef bool ( ObjectClass::*GetBoolPtr ) ( void ) const; \
+ typedef PMThreeState ( ObjectClass::*GetThreeStatePtr ) ( void ) const; \
+ typedef QString ( ObjectClass::*GetStringPtr ) ( void ) const; \
+ typedef PMVector ( ObjectClass::*GetVectorPtr ) ( void ) const; \
+ typedef PMColor ( ObjectClass::*GetColorPtr ) ( void ) const; \
+ typedef PMObject* ( ObjectClass::*GetObjectPtr ) ( void ) const; \
+ \
+ PropertyClass( const QString& name, SetIntPtr setFktn, GetIntPtr getFktn ) \
+ : PMPropertyBase( name, PMVariant::Integer, \
+ setFktn == 0, getFktn == 0 ) \
+ { \
+ m_setFunction.setInt = setFktn; \
+ m_getFunction.getInt = getFktn; \
+ } \
+ PropertyClass( const QString& name, SetUnsignedPtr setFktn, GetUnsignedPtr getFktn ) \
+ : PMPropertyBase( name, PMVariant::Unsigned, \
+ setFktn == 0, getFktn == 0 ) \
+ { \
+ m_setFunction.setUnsigned = setFktn; \
+ m_getFunction.getUnsigned = getFktn; \
+ } \
+ PropertyClass( const QString& name, SetDoublePtr setFktn, GetDoublePtr getFktn ) \
+ : PMPropertyBase( name, PMVariant::Double, \
+ setFktn == 0, getFktn == 0 ) \
+ { \
+ m_setFunction.setDouble = setFktn; \
+ m_getFunction.getDouble = getFktn; \
+ } \
+ PropertyClass( const QString& name, SetBoolPtr setFktn, GetBoolPtr getFktn ) \
+ : PMPropertyBase( name, PMVariant::Bool, \
+ setFktn == 0, getFktn == 0 ) \
+ { \
+ m_setFunction.setBool = setFktn; \
+ m_getFunction.getBool = getFktn; \
+ } \
+ PropertyClass( const QString& name, SetThreeStatePtr setFktn, GetThreeStatePtr getFktn ) \
+ : PMPropertyBase( name, PMVariant::ThreeState, \
+ setFktn == 0, getFktn == 0 ) \
+ { \
+ m_setFunction.setThreeState = setFktn; \
+ m_getFunction.getThreeState = getFktn; \
+ } \
+ PropertyClass( const QString& name, SetStringPtr setFktn, GetStringPtr getFktn ) \
+ : PMPropertyBase( name, PMVariant::String, \
+ setFktn == 0, getFktn == 0 ) \
+ { \
+ m_setFunction.setString = setFktn; \
+ m_getFunction.getString = getFktn; \
+ } \
+ PropertyClass( const QString& name, SetVectorPtr setFktn, GetVectorPtr getFktn ) \
+ : PMPropertyBase( name, PMVariant::Vector, \
+ setFktn == 0, getFktn == 0 ) \
+ { \
+ m_setFunction.setVector = setFktn; \
+ m_getFunction.getVector = getFktn; \
+ } \
+ PropertyClass( const QString& name, SetColorPtr setFktn, GetColorPtr getFktn ) \
+ : PMPropertyBase( name, PMVariant::Color, \
+ setFktn == 0, getFktn == 0 ) \
+ { \
+ m_setFunction.setColor = setFktn; \
+ m_getFunction.getColor = getFktn; \
+ } \
+ PropertyClass( const QString& name, SetObjectPtr setFktn, GetObjectPtr getFktn ) \
+ : PMPropertyBase( name, PMVariant::ObjectPointer, \
+ setFktn == 0, getFktn == 0 ) \
+ { \
+ m_setFunction.setObject = setFktn; \
+ m_getFunction.getObject = getFktn; \
+ } \
+ \
+protected: \
+ bool setProtected( PMObject* obj, const PMVariant& v ) \
+ { \
+ ObjectClass* o = ( ObjectClass* ) obj; \
+ switch( type( ) ) \
+ { \
+ case PMVariant::Integer: \
+ ( o->*( m_setFunction.setInt ) )( v.intData( ) ); \
+ break; \
+ case PMVariant::Unsigned: \
+ ( o->*( m_setFunction.setUnsigned ) )( v.unsignedData( ) ); \
+ break; \
+ case PMVariant::Double: \
+ ( o->*( m_setFunction.setDouble ) )( v.doubleData( ) ); \
+ break; \
+ case PMVariant::Bool: \
+ ( o->*( m_setFunction.setBool ) )( v.boolData( ) ); \
+ break; \
+ case PMVariant::ThreeState: \
+ ( o->*( m_setFunction.setThreeState ) )( v.threeStateData( ) ); \
+ break; \
+ case PMVariant::String: \
+ ( o->*( m_setFunction.setString ) )( v.stringData( ) ); \
+ break; \
+ case PMVariant::Vector: \
+ ( o->*( m_setFunction.setVector ) )( v.vectorData( ) ); \
+ break; \
+ case PMVariant::Color: \
+ ( o->*( m_setFunction.setColor ) )( v.colorData( ) ); \
+ break; \
+ case PMVariant::ObjectPointer: \
+ ( o->*( m_setFunction.setObject ) )( v.objectData( ) ); \
+ break; \
+ case PMVariant::None: \
+ break; \
+ } \
+ return true; \
+ } \
+ \
+ PMVariant getProtected( const PMObject* obj ) \
+ { \
+ const ObjectClass* o = ( const ObjectClass* ) obj; \
+ PMVariant result; \
+ \
+ switch( type( ) ) \
+ { \
+ case PMVariant::Integer: \
+ result.setInt( ( o->*( m_getFunction.getInt ) )( ) ); \
+ break; \
+ case PMVariant::Unsigned: \
+ result.setUnsigned( ( o->*( m_getFunction.getUnsigned ) )( ) ); \
+ break; \
+ case PMVariant::Double: \
+ result.setDouble( ( o->*( m_getFunction.getDouble ) )( ) ); \
+ break; \
+ case PMVariant::Bool: \
+ result.setBool( ( o->*( m_getFunction.getBool ) )( ) ); \
+ break; \
+ case PMVariant::ThreeState: \
+ result.setThreeState( ( o->*( m_getFunction.getThreeState ) )( ) ); \
+ break; \
+ case PMVariant::String: \
+ result.setString( ( o->*( m_getFunction.getString ) )( ) ); \
+ break; \
+ case PMVariant::Vector: \
+ result.setVector( ( o->*( m_getFunction.getVector ) )( ) ); \
+ break; \
+ case PMVariant::Color: \
+ result.setColor( ( o->*( m_getFunction.getColor ) )( ) ); \
+ break; \
+ case PMVariant::ObjectPointer: \
+ result.setObject( ( o->*( m_getFunction.getObject ) )( ) ); \
+ break; \
+ case PMVariant::None: \
+ break; \
+ } \
+ return result; \
+ } \
+ \
+private: \
+ union \
+ { \
+ SetIntPtr setInt; \
+ SetUnsignedPtr setUnsigned; \
+ SetDoublePtr setDouble; \
+ SetBoolPtr setBool; \
+ SetThreeStatePtr setThreeState; \
+ SetStringPtr setString; \
+ SetVectorPtr setVector; \
+ SetColorPtr setColor; \
+ SetObjectPtr setObject; \
+ } m_setFunction; \
+ \
+ union \
+ { \
+ GetIntPtr getInt; \
+ GetUnsignedPtr getUnsigned; \
+ GetDoublePtr getDouble; \
+ GetBoolPtr getBool; \
+ GetThreeStatePtr getThreeState; \
+ GetStringPtr getString; \
+ GetVectorPtr getVector; \
+ GetColorPtr getColor; \
+ GetObjectPtr getObject; \
+ } m_getFunction; \
+}
+// no semicolon, put a semicolon after the macro!
+
+
+typedef PMObject* ( *PMObjectFactoryMethod ) ( PMPart* );
+
+/**
+ * Meta information object for the @ref PMObject class.
+ *
+ * Stores information (class name, inheritance hierarchy,
+ * object properties) for each class.
+ */
+class PMMetaObject
+{
+public:
+ /**
+ * Creates a PMMetaObject. The class name has to be the class name
+ * without the PM prefix.
+ *
+ * factoryMethod is a function pointer to a factory method
+ * with signature PMObject* theMethod( PMPart* ) that returns
+ * a new object of that type. factoryMethod may be 0 for
+ * abstract classes.
+ */
+ PMMetaObject( const QString& className, PMMetaObject* superClass = 0,
+ PMObjectFactoryMethod factoryMethod = 0 );
+ /**
+ * Destructor
+ */
+ ~PMMetaObject( );
+
+ /**
+ * Returns the class name
+ */
+ QString className( ) const { return m_className; }
+ /**
+ * Returns the meta object of the super class
+ */
+ PMMetaObject* superClass( ) const { return m_pSuperClass; }
+ /**
+ * Returns a new object instance
+ */
+ PMObject* newObject( PMPart* part ) const;
+ /**
+ * Returns true if the class is an abstract class
+ * (if no factory method was set in the constructor)
+ */
+ bool isAbstract( ) const { return m_factory == 0; }
+
+ /**
+ * Adds a property.
+ *
+ * The meta object becomes the owner of the property object
+ */
+ void addProperty( PMPropertyBase* p );
+ /**
+ * Returns an iterator to the properties
+ */
+ PMPropertyIterator properties( ) const
+ {
+ return PMPropertyIterator( m_propertiesDict );
+ }
+ /**
+ * Returns a property by name or 0 if a property with the name
+ * doesn't exist.
+ */
+ PMPropertyBase* property( const QString& name ) const
+ {
+ return m_propertiesDict.find( name );
+ }
+
+private:
+ QString m_className;
+ PMMetaObject* m_pSuperClass;
+ PMPropertyList m_properties;
+ PMPropertyDict m_propertiesDict;
+ PMObjectFactoryMethod m_factory;
+};
+
+#endif
diff --git a/kpovmodeler/pmmovecommand.cpp b/kpovmodeler/pmmovecommand.cpp
new file mode 100644
index 00000000..1d70f3e0
--- /dev/null
+++ b/kpovmodeler/pmmovecommand.cpp
@@ -0,0 +1,478 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmmovecommand.h"
+#include "pmobject.h"
+#include "pmpart.h"
+#include "pmcommandmanager.h"
+#include "pmdeclare.h"
+#include "pmerrorflags.h"
+#include "pmrecursiveobjectiterator.h"
+#include "pmmemento.h"
+#include "pmdebug.h"
+
+#include <klocale.h>
+#include <qptrdict.h>
+
+PMMoveCommand::PMMoveCommand( PMObject* obj, PMObject* parent, PMObject* after )
+ : PMCommand( i18n( "Move %1" ).arg( obj->description( ) ) )
+{
+ m_pParent = parent;
+ m_pAfter = after;
+
+ if( obj->parent( ) )
+ {
+ m_infoList.append( new PMDeleteInfo( obj ) );
+ }
+ else
+ {
+ // object has no parent!
+ // top level objects can't be moved, move all child items
+ PMObject* tmp;
+ for( tmp = obj->firstChild( ); tmp; tmp = tmp->nextSibling( ) )
+ m_infoList.append( new PMDeleteInfo( tmp ) );
+ }
+
+ m_executed = false;
+ m_firstExecution = true;
+}
+
+PMMoveCommand::PMMoveCommand( const PMObjectList& list, PMObject* parent,
+ PMObject* after )
+ : PMCommand( i18n( "Move Objects" ) )
+{
+ PMObjectListIterator it( list );
+
+ for( ; it.current( ); ++it )
+ {
+ if( it.current( )->parent( ) )
+ m_infoList.append( new PMDeleteInfo( it.current( ) ) );
+ else
+ {
+ // object has no parent!
+ // top level objects can't be moved, move all child items
+ PMObject* tmp;
+ for( tmp = it.current( )->firstChild( ); tmp; tmp = tmp->nextSibling( ) )
+ m_infoList.append( new PMDeleteInfo( tmp ) );
+ }
+ }
+
+ m_pParent = parent;
+ m_pAfter = after;
+ m_executed = false;
+ m_firstExecution = true;
+}
+
+PMMoveCommand::~PMMoveCommand( )
+{
+ if( m_executed )
+ {
+ m_insertErrors.setAutoDelete( true );
+ m_insertErrors.clear( );
+ }
+}
+
+void PMMoveCommand::execute( PMCommandManager* theManager )
+{
+ if( !m_executed )
+ {
+ // remove objects
+ PMDeleteInfoListIterator it( m_infoList );
+ PMObject* prev = m_pAfter;
+ PMObject* obj;
+ bool error = false;
+ PMDeleteInfo* info = 0;
+ PMObject* parent;
+
+ for( it.toLast( ); it.current( ); --it )
+ {
+ info = it.current( );
+ parent = info->parent( );
+ // signal has to be emitted before the item is removed
+ theManager->cmdObjectChanged( info->deletedObject( ), PMCRemove );
+ if( m_firstExecution )
+ if( parent->dataChangeOnInsertRemove( )
+ && !parent->mementoCreated( ) )
+ parent->createMemento( );
+ parent->takeChild( info->deletedObject( ) );
+ }
+
+ // insert at new position
+ if( m_firstExecution )
+ if( m_pParent->dataChangeOnInsertRemove( )
+ && !m_pParent->mementoCreated( ) )
+ m_pParent->createMemento( );
+
+ for( it.toFirst( ); it.current( ); ++it )
+ {
+ if( !it.current( )->insertError( ) )
+ {
+ obj = it.current( )->deletedObject( );
+
+ if( !prev )
+ {
+ if( m_pParent->canInsert( obj, 0 ) )
+ {
+ m_pParent->insertChild( obj, 0 );
+ prev = obj;
+ theManager->cmdObjectChanged( obj, PMCAdd );
+ }
+ else
+ error = true;
+ }
+ else
+ {
+ if( m_pParent->canInsert( obj, prev ) )
+ {
+ m_pParent->insertChildAfter( obj, prev );
+ prev = obj;
+ theManager->cmdObjectChanged( obj, PMCAdd );
+ }
+ else
+ error = true;
+ }
+
+ if( error )
+ {
+ m_insertErrors.append( it.current( )->deletedObject( ) );
+ it.current( )->setInsertError( );
+ theManager->cmdObjectChanged( obj, PMCAdd | PMCInsertError );
+ error = false;
+ }
+ }
+ }
+
+ if( m_firstExecution )
+ {
+ if( m_pParent->mementoCreated( ) )
+ m_dataChanges.append( m_pParent->takeMemento( ) );
+
+ for( it.toLast( ); it.current( ); --it )
+ {
+ info = it.current( );
+ parent = info->parent( );
+
+ if( parent->mementoCreated( ) )
+ m_dataChanges.append( parent->takeMemento( ) );
+ }
+ }
+
+ QPtrListIterator<PMMemento> mit( m_dataChanges );
+ for( ; mit.current( ); ++mit )
+ {
+ PMObjectChangeListIterator change = mit.current( )->changedObjects( );
+ for( ; change.current( ); ++change )
+ theManager->cmdObjectChanged( change.current( )->object( ),
+ change.current( )->mode( ) );
+ }
+
+ m_executed = true;
+ m_firstExecution = true;
+ }
+}
+
+void PMMoveCommand::undo( PMCommandManager* theManager )
+{
+ if( m_executed )
+ {
+ PMDeleteInfoListIterator it( m_infoList );
+ PMObject* obj;
+ for( it.toLast( ) ; it.current( ); --it )
+ {
+ // signal has to be emitted before the item is removed
+ obj = it.current( )->deletedObject( );
+ theManager->cmdObjectChanged( obj, PMCRemove );
+ if( obj->parent( ) )
+ obj->parent( )->takeChild( obj );
+ }
+
+ for( it.toFirst( ); it.current( ); ++it )
+ {
+ obj = it.current( )->deletedObject( );
+ if( it.current( )->prevSibling( ) )
+ it.current( )->parent( )
+ ->insertChildAfter( obj, it.current( )->prevSibling( ) );
+ else
+ it.current( )->parent( )->insertChild( obj, 0 );
+ theManager->cmdObjectChanged( obj, PMCAdd );
+ }
+
+ QPtrListIterator<PMMemento> mit( m_dataChanges );
+ for( ; mit.current( ); ++mit )
+ {
+ mit.current( )->originator( )->restoreMemento( mit.current( ) );
+ PMObjectChangeListIterator change = mit.current( )->changedObjects( );
+ for( ; change.current( ); ++change )
+ theManager->cmdObjectChanged( change.current( )->object( ),
+ change.current( )->mode( ) );
+ }
+
+ m_executed = false;
+ }
+}
+
+int PMMoveCommand::errorFlags( PMPart* )
+{
+ PMDeleteInfo* info;
+ PMDeclare* decl = 0;
+ PMObject* obj;
+ bool insideSelection;
+ bool ok = true;
+ bool declareInsertError = false;
+ bool error = false;
+ bool stop;
+
+ // dictionary of deleted objects
+ QPtrDict<bool> deletedObjects( 1009 );
+ deletedObjects.setAutoDelete( true );
+ QPtrDict<bool> objectsAfterInsertPosition( 1009 );
+ objectsAfterInsertPosition.setAutoDelete( true );
+ QPtrDict<bool> declaresBeforeInsertPosition( 199 );
+ declaresBeforeInsertPosition.setAutoDelete( true );
+
+
+ PMDeleteInfoListIterator it( m_infoList );
+ for( ; it.current( ); ++it )
+ deletedObjects.insert( it.current( )->deletedObject( ),
+ new bool( true ) );
+
+ // declares can only be moved, if all linked
+ // objects are moved as well or the insert position is before the first
+ // linked object and all declares can be inserted
+
+ info = m_infoList.last( );
+
+ while( info )
+ {
+ ok = true;
+ declareInsertError = false;
+
+ if( info->deletedObject( )->isA( "Declare" ) )
+ {
+ decl = ( PMDeclare* ) ( info->deletedObject( ) );
+
+ if( !m_pParent->canInsert( decl, m_pAfter ) )
+ {
+ declareInsertError = true;
+ ok = false;
+ }
+ else
+ {
+ PMObjectListIterator links = decl->linkedObjects( );
+
+ for( ; links.current( ) && ok; ++links )
+ {
+ insideSelection = false;
+ for( obj = links.current( ); obj && !insideSelection;
+ obj = obj->parent( ) )
+ {
+ if( deletedObjects.find( obj ) )
+ insideSelection = true;
+ }
+
+ if( insideSelection )
+ {
+ bool stop = false;
+ for( obj = links.current( ); obj && !stop; obj = obj->parent( ) )
+ {
+ if( deletedObjects.find( obj ) )
+ stop = true;
+ else
+ deletedObjects.insert( obj, new bool( true ) );
+ }
+ }
+ else
+ {
+ // link will not be moved
+ // check, if after insert position
+ // declares can only be inserted as childs of the scene
+
+ if( m_pAfter )
+ {
+ // insert point is not the first item
+ // find the top level parent item
+ stop = false;
+ obj = links.current( );
+ do
+ {
+ if( obj->parent( ) )
+ {
+ if( obj->parent( )->type( ) == "Scene" )
+ stop = true;
+ else
+ obj = obj->parent( );
+ }
+ else
+ stop = true; // error
+ }
+ while( !stop );
+
+ PMObject* topParent = obj;
+
+ // check if insert point is before the top level
+ // parent object
+
+ if( !objectsAfterInsertPosition.find( obj ) )
+ {
+ stop = false;
+ obj = obj->prevSibling( );
+ while( obj && !stop )
+ {
+ if( obj == m_pAfter )
+ stop = true;
+ else if( objectsAfterInsertPosition.find( obj ) )
+ stop = true;
+ else
+ obj = obj->prevSibling( );
+ }
+
+ if( stop )
+ objectsAfterInsertPosition.insert( topParent, new bool( true ) );
+ else
+ ok = false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if( !ok )
+ {
+ if( declareInsertError )
+ m_errors.prepend( i18n( "Can't insert the declare \"%1\" at that point." )
+ .arg( decl->id( ) ) );
+ else
+ m_errors.prepend( i18n( "The declare \"%1\" can't be moved behind linked objects." )
+ .arg( decl->id( ) ) );
+
+ PMDeleteInfo* tmp = info;
+ info = m_infoList.prev( );
+ deletedObjects.remove( tmp->deletedObject( ) );
+ m_infoList.removeRef( tmp );
+
+ error = true;
+ }
+ else
+ info = m_infoList.prev( );
+ }
+
+ // check if links are moved before the declare object
+
+ // find all declares bevore the insert position
+ if( m_pParent->type( ) == "Scene" )
+ obj = m_pAfter;
+ else
+ {
+ stop = false;
+ obj = m_pParent;
+ do
+ {
+ if( obj->parent( ) )
+ {
+ if( obj->parent( )->type( ) == "Scene" )
+ stop = true;
+ else
+ obj = obj->parent( );
+ }
+ else
+ stop = true; // error
+ }
+ while( !stop );
+
+ if( obj )
+ obj = obj->prevSibling( );
+ }
+
+ while( obj )
+ {
+ if( obj->isA( "Declare" ) )
+ declaresBeforeInsertPosition.insert( obj, new bool( true ) );
+ obj = obj->prevSibling( );
+ }
+
+ info = m_infoList.first( );
+ while( info )
+ {
+ ok = true;
+ PMRecursiveObjectIterator it( info->deletedObject( ) );
+ PMObject* linked = 0;
+
+ while( it.current( ) && ok )
+ {
+ linked = it.current( )->linkedObject( );
+
+ if( linked )
+ {
+ if( !deletedObjects.find( linked ) )
+ {
+ // Object is linked to a declare and the declare
+ // will not be moved.
+ // Check, if the insert point is after the declare
+
+ if( !declaresBeforeInsertPosition.find( linked ) )
+ ok = false;
+ }
+ }
+
+ if( ok )
+ ++it;
+ }
+
+ if( ok )
+ info = m_infoList.next( );
+ else
+ {
+ if( linked )
+ {
+ obj = info->deletedObject( );
+ QString name = obj->name( );
+ decl = ( PMDeclare* ) linked;
+
+ if( name.isEmpty( ) )
+ name = i18n( "(unnamed)" );
+ m_errors.append( i18n( "The %1 \"%2\" can't be moved because it "
+ "contains a link to the declare \"%3\" "
+ "and the insert point is not after "
+ "the declare." )
+ .arg( obj->description( ) ).arg( name )
+ .arg( decl->id( ) ) );
+ }
+ else
+ kdError( PMArea ) << "linked is 0 in PMMoveCommand::errorFlags\n";
+
+
+ PMDeleteInfo* tmp = info;
+ info = m_infoList.next( );
+ deletedObjects.remove( tmp->deletedObject( ) );
+ m_infoList.removeRef( tmp );
+
+ error = true;
+ }
+ }
+
+ if( error )
+ {
+ if( m_infoList.count( ) == 0 )
+ return PMEError | PMEFatal;
+ else
+ return PMEError;
+ }
+
+ return PMENone;
+}
diff --git a/kpovmodeler/pmmovecommand.h b/kpovmodeler/pmmovecommand.h
new file mode 100644
index 00000000..75250fd2
--- /dev/null
+++ b/kpovmodeler/pmmovecommand.h
@@ -0,0 +1,88 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMMOVECOMMAND_H
+#define PMMOVECOMMAND_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmcommand.h"
+#include "pmdeletecommand.h"
+
+class PMObject;
+class PMMemento;
+
+/**
+ * Command class for moving objects
+ */
+class PMMoveCommand : public PMCommand
+{
+public:
+ /**
+ * Command that moves one PMObject.
+ *
+ * The object obj will be inserted as child of parent after
+ * the object after.
+ *
+ * If after is 0, the object becomes the first child.
+ */
+ PMMoveCommand( PMObject* obj, PMObject* parent, PMObject* after );
+
+ /**
+ * Command that moves a list of new PMObjects.
+ * The objects don't have to be siblings of each other.
+ *
+ * The object in the list will be inserted as children of parent after
+ * the object after.
+ *
+ * If after is 0, the objects will be inserted as first children.
+ */
+ PMMoveCommand( const PMObjectList& list, PMObject* parent, PMObject* after );
+ /**
+ * Deletes the command.
+ */
+ virtual ~PMMoveCommand( );
+
+ /** */
+ virtual int errorFlags( PMPart* );
+
+protected:
+ /**
+ * Executes the command and stores undo information
+ */
+ virtual void execute( PMCommandManager* theManager );
+ /**
+ * Undo the command
+ */
+ virtual void undo( PMCommandManager* theManager );
+
+private:
+ PMObject* m_pParent;
+ PMObject* m_pAfter;
+
+ PMDeleteInfoList m_infoList;
+ PMObjectList m_insertErrors;
+ bool m_executed;
+ bool m_firstExecution;
+ QPtrList<PMMemento> m_dataChanges;
+};
+
+#endif
diff --git a/kpovmodeler/pmnamedobject.cpp b/kpovmodeler/pmnamedobject.cpp
new file mode 100644
index 00000000..d6d6ab09
--- /dev/null
+++ b/kpovmodeler/pmnamedobject.cpp
@@ -0,0 +1,111 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmnamedobject.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+
+PMDefinePropertyClass( PMNamedObject, PMNamedObjectProperty );
+
+PMMetaObject* PMNamedObject::s_pMetaObject = 0;
+
+PMNamedObject::PMNamedObject( PMPart* part )
+ : Base( part )
+{
+}
+
+PMNamedObject::PMNamedObject( const PMNamedObject& o )
+ : Base( o )
+{
+ m_name = o.m_name;
+}
+
+PMNamedObject::~PMNamedObject( )
+{
+}
+
+PMMetaObject* PMNamedObject::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "NamedObject", Base::metaObject( ) );
+ s_pMetaObject->addProperty(
+ new PMNamedObjectProperty( "name", &PMNamedObject::setName, &PMNamedObject::name ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMNamedObject::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMNamedObject::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "name", m_name );
+ Base::serialize( e, doc );
+}
+
+void PMNamedObject::readAttributes( const PMXMLHelper& h )
+{
+ m_name = h.stringAttribute( "name", "" );
+ Base::readAttributes( h );
+}
+
+void PMNamedObject::setName( const QString& newName )
+{
+ if( newName != m_name )
+ {
+ if( m_pMemento )
+ {
+ m_pMemento->addData( s_pMetaObject, PMNameID, m_name );
+ m_pMemento->setDescriptionChanged( );
+ }
+
+ m_name = newName;
+ }
+}
+
+void PMNamedObject::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMNameID:
+ setName( data->stringData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMNamedObject::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmnamedobject.h b/kpovmodeler/pmnamedobject.h
new file mode 100644
index 00000000..d4cdee2c
--- /dev/null
+++ b/kpovmodeler/pmnamedobject.h
@@ -0,0 +1,89 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMNAMEDOBJECT_H
+#define PMNAMEDOBJECT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmcompositeobject.h"
+
+/**
+ * class for all objects with free choose-able names (all objects except
+ * include files, the scene and declares)
+ */
+
+class PMNamedObject : public PMCompositeObject
+{
+ typedef PMCompositeObject Base;
+public:
+ /**
+ * Creates an empty PMNamedObject
+ */
+ PMNamedObject( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMNamedObject( const PMNamedObject& o );
+ /**
+ * Deletes the object
+ */
+ ~PMNamedObject( );
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns the name of the object. This is the name that helps
+ * the user to identify a object (like "south_wall", "floor" ...) */
+ virtual QString name( ) const { return m_name; }
+ /**
+ * Sets the name of the object.
+ */
+ virtual void setName( const QString& newName );
+ /**
+ * Returns true if the object can have a name
+ */
+ virtual bool canHaveName( ) const { return true; }
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMNamedObjectMementoID { PMNameID };
+
+ /**
+ * Name of the object
+ */
+ QString m_name;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmnamedobjectedit.cpp b/kpovmodeler/pmnamedobjectedit.cpp
new file mode 100644
index 00000000..35a6c96c
--- /dev/null
+++ b/kpovmodeler/pmnamedobjectedit.cpp
@@ -0,0 +1,81 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmnamedobjectedit.h"
+#include "pmnamedobject.h"
+
+#include <qlayout.h>
+#include <qlineedit.h>
+#include <qlabel.h>
+#include <klocale.h>
+
+PMNamedObjectEdit::PMNamedObjectEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMNamedObjectEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* layout = new QHBoxLayout( topLayout( ) );
+ m_pNameEdit = new QLineEdit( this );
+ QLabel* label = new QLabel( i18n( "Name:" ), this );
+
+ layout->addWidget( label );
+ layout->addWidget( m_pNameEdit );
+
+ connect( m_pNameEdit, SIGNAL( textChanged( const QString& ) ),
+ SLOT( slotNameChanged( const QString& ) ) );
+}
+
+void PMNamedObjectEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "NamedObject" ) )
+ {
+ m_pDisplayedObject = ( PMNamedObject* ) o;
+ m_pNameEdit->setText( m_pDisplayedObject->name( ) );
+
+ m_pNameEdit->setReadOnly( m_pDisplayedObject->isReadOnly( ) );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMNamedObjectEdit: Can't display object\n";
+}
+
+void PMNamedObjectEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setName( m_pNameEdit->text( ) );
+ }
+}
+
+bool PMNamedObjectEdit::isDataValid( )
+{
+ return Base::isDataValid( );
+}
+
+void PMNamedObjectEdit::slotNameChanged( const QString& )
+{
+ emit dataChanged( );
+}
+#include "pmnamedobjectedit.moc"
diff --git a/kpovmodeler/pmnamedobjectedit.h b/kpovmodeler/pmnamedobjectedit.h
new file mode 100644
index 00000000..8d9dff40
--- /dev/null
+++ b/kpovmodeler/pmnamedobjectedit.h
@@ -0,0 +1,64 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMNAMEDOBJECTEDIT_H
+#define PMNAMEDOBJECTEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdialogeditbase.h"
+
+class PMNamedObject;
+class QLineEdit;
+
+/**
+ * Dialog edit class for @ref PMNamedObject.
+ */
+class PMNamedObjectEdit : public PMDialogEditBase
+{
+ Q_OBJECT
+ typedef PMDialogEditBase Base;
+public:
+ /**
+ * Creates a PMNamedObjectEdit with parent and name
+ */
+ PMNamedObjectEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private slots:
+ void slotNameChanged( const QString& );
+private:
+ PMNamedObject* m_pDisplayedObject;
+ QLineEdit* m_pNameEdit;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmnormal.cpp b/kpovmodeler/pmnormal.cpp
new file mode 100644
index 00000000..77fdddd1
--- /dev/null
+++ b/kpovmodeler/pmnormal.cpp
@@ -0,0 +1,189 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmnormal.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pmnormaledit.h"
+#include "pmlistpattern.h"
+#include "pmpattern.h"
+
+#include <klocale.h>
+
+const double bumpSizeDefault = 0.0;
+const double accuracyDefault = 0.02;
+
+PMDefinePropertyClass( PMNormal, PMNormProperty );
+
+PMMetaObject* PMNormal::s_pMetaObject = 0;
+PMObject* createNewNormal( PMPart* part )
+{
+ return new PMNormal( part );
+}
+
+PMNormal::PMNormal( PMPart* part )
+ : Base( part )
+{
+ m_enableBumpSize = false;
+ m_bumpSize = bumpSizeDefault;
+ m_accuracy = accuracyDefault;
+ m_uvMapping = false;
+}
+
+PMNormal::PMNormal( const PMNormal& n )
+ : Base( n )
+{
+ m_enableBumpSize = n.m_enableBumpSize;
+ m_bumpSize = n.m_bumpSize;
+ m_accuracy = n.m_accuracy;
+ m_uvMapping = n.m_uvMapping;
+}
+
+PMNormal::~PMNormal( )
+{
+}
+
+PMMetaObject* PMNormal::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Normal", Base::metaObject( ),
+ createNewNormal );
+ s_pMetaObject->addProperty(
+ new PMNormProperty( "bumpSize", &PMNormal::setBumpSize, &PMNormal::bumpSize ) );
+ s_pMetaObject->addProperty(
+ new PMNormProperty( "bumpSizeEnabled", &PMNormal::enableBumpSize, &PMNormal::isBumpSizeEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMNormProperty( "accuracy", &PMNormal::setAccuracy, &PMNormal::accuracy ) );
+ s_pMetaObject->addProperty(
+ new PMNormProperty( "uvMapping", &PMNormal::setUVMapping, &PMNormal::uvMapping ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMNormal::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMNormal::description( ) const
+{
+ return i18n( "normal" );
+}
+
+void PMNormal::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ Base::serialize( e, doc );
+ e.setAttribute( "enable_bump_size", m_enableBumpSize );
+ e.setAttribute( "bump_size", m_bumpSize );
+ e.setAttribute( "accuracy", m_accuracy );
+ e.setAttribute( "uv_mapping", m_uvMapping );
+}
+
+void PMNormal::readAttributes( const PMXMLHelper& h )
+{
+ Base::readAttributes( h );
+ m_enableBumpSize = h.boolAttribute( "enable_bump_size", false );
+ m_bumpSize = h.doubleAttribute( "bump_size", bumpSizeDefault );
+ m_accuracy = h.doubleAttribute( "accuracy", accuracyDefault );
+ m_uvMapping = h.boolAttribute( "uv_mapping", false );
+}
+
+PMDialogEditBase* PMNormal::editWidget( QWidget* parent ) const
+{
+ return new PMNormalEdit( parent );
+}
+
+void PMNormal::enableBumpSize( bool c )
+{
+ if( c != m_enableBumpSize )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableBumpSizeID, m_enableBumpSize );
+ m_enableBumpSize = c;
+ }
+}
+
+void PMNormal::setBumpSize( double c )
+{
+ if( c != m_bumpSize )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMBumpSizeID, m_bumpSize );
+ m_bumpSize = c;
+ }
+}
+
+void PMNormal::setAccuracy( double c )
+{
+ if( c!= m_accuracy )
+ {
+ if ( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAccuracyID, m_accuracy );
+ m_accuracy = c;
+ }
+}
+
+void PMNormal::setUVMapping( bool m )
+{
+ if( m != m_uvMapping )
+ {
+ if ( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMUVMappingID, m_uvMapping );
+ m_uvMapping = m;
+ }
+}
+
+void PMNormal::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMEnableBumpSizeID:
+ enableBumpSize( data->boolData( ) );
+ break;
+ case PMBumpSizeID:
+ setBumpSize( data->doubleData( ) );
+ break;
+ case PMAccuracyID:
+ setAccuracy( data->doubleData( ) );
+ break;
+ case PMUVMappingID:
+ setUVMapping( data->boolData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMNormal::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
diff --git a/kpovmodeler/pmnormal.h b/kpovmodeler/pmnormal.h
new file mode 100644
index 00000000..81ec0547
--- /dev/null
+++ b/kpovmodeler/pmnormal.h
@@ -0,0 +1,122 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMNORMAL_H
+#define PMNORMAL_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebase.h"
+
+/**
+ * Class for povray normals
+ */
+class PMNormal : public PMTextureBase
+{
+ typedef PMTextureBase Base;
+public:
+ /**
+ * Creates an PMNormal
+ */
+ PMNormal( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMNormal( const PMNormal& n );
+ /**
+ * Deletes the object
+ */
+ virtual ~PMNormal( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMNormal( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMNormalEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmnormal" ); }
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+
+ /**
+ * Returns true if bump_size is enabled
+ */
+ bool isBumpSizeEnabled( ) const { return m_enableBumpSize; }
+ /**
+ * enables/disables bump_size
+ */
+ void enableBumpSize( bool c );
+ /**
+ * Returns the normal's bump size
+ */
+ double bumpSize( ) const { return m_bumpSize; }
+ /**
+ * Sets the normal's bump size
+ */
+ void setBumpSize( double c );
+ /**
+ * Returns the normal's accuracy
+ */
+ double accuracy( ) const { return m_accuracy; }
+ /**
+ * Sets the normal's accuracy
+ */
+ void setAccuracy( double c );
+ /**
+ * Returns the uv mapping flag
+ */
+ bool uvMapping( ) const { return m_uvMapping; }
+ /**
+ * Sets the uv mapping flag
+ */
+ void setUVMapping( bool m );
+
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMNormalMementoID { PMEnableBumpSizeID, PMBumpSizeID, PMAccuracyID, PMUVMappingID };
+
+ bool m_enableBumpSize;
+ double m_bumpSize;
+ double m_accuracy;
+ bool m_uvMapping;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmnormaledit.cpp b/kpovmodeler/pmnormaledit.cpp
new file mode 100644
index 00000000..161f2b0b
--- /dev/null
+++ b/kpovmodeler/pmnormaledit.cpp
@@ -0,0 +1,118 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmnormaledit.h"
+#include "pmnormal.h"
+#include "pmlinkedit.h"
+#include "pmlineedits.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <klocale.h>
+
+
+PMNormalEdit::PMNormalEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMNormalEdit::createTopWidgets( )
+{
+ QHBoxLayout* hl;
+
+ Base::createTopWidgets( );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ m_pBumpSizeCheck = new QCheckBox( i18n( "Bump size" ), this );
+ m_pBumpSizeEdit = new PMFloatEdit( this );
+ hl->addWidget( m_pBumpSizeCheck );
+ hl->addWidget( m_pBumpSizeEdit );
+ hl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ QLabel* lbl = new QLabel( i18n( "Accuracy" ), this );
+ m_pAccuracy = new PMFloatEdit( this );
+ hl->addWidget( lbl );
+ hl->addWidget( m_pAccuracy );
+ hl->addStretch( 1 );
+
+ m_pUVMapping = new QCheckBox( i18n( "UV mapping" ), this );
+ topLayout( )->addWidget( m_pUVMapping );
+
+ connect( m_pBumpSizeCheck, SIGNAL( clicked( ) ), SLOT( slotBumpSizeClicked( )) );
+ connect( m_pBumpSizeEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( )) );
+ connect( m_pAccuracy, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pUVMapping, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMNormalEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Normal" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMNormal* )o;
+
+ m_pBumpSizeCheck->setChecked( m_pDisplayedObject->isBumpSizeEnabled( ) );
+ m_pBumpSizeCheck->setEnabled( !readOnly );
+ m_pBumpSizeEdit->setValue( m_pDisplayedObject->bumpSize( ) );
+ m_pBumpSizeEdit->setReadOnly( readOnly );
+ slotBumpSizeClicked( );
+ m_pAccuracy->setValue( m_pDisplayedObject->accuracy( ) );
+ m_pAccuracy->setReadOnly( readOnly );
+ m_pUVMapping->setChecked( m_pDisplayedObject->uvMapping() );
+ m_pUVMapping->setEnabled( !readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMNormalEdit: Can't display object\n";
+}
+
+void PMNormalEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->enableBumpSize( m_pBumpSizeCheck->isChecked( ) );
+ m_pDisplayedObject->setBumpSize( m_pBumpSizeEdit->value( ) );
+ m_pDisplayedObject->setAccuracy( m_pAccuracy->value( ) );
+ m_pDisplayedObject->setUVMapping( m_pUVMapping->isChecked() );
+ }
+}
+
+bool PMNormalEdit::isDataValid( )
+{
+ if( !m_pBumpSizeEdit->isDataValid( ) ) return false;
+ if( !m_pAccuracy->isDataValid( ) ) return false;
+
+ return Base::isDataValid( );
+}
+
+void PMNormalEdit::slotBumpSizeClicked( )
+{
+ if( m_pBumpSizeCheck->isChecked( ) )
+ m_pBumpSizeEdit->show( );
+ else
+ m_pBumpSizeEdit->hide( );
+ emit sizeChanged( );
+ emit dataChanged( );
+}
+
+#include "pmnormaledit.moc"
diff --git a/kpovmodeler/pmnormaledit.h b/kpovmodeler/pmnormaledit.h
new file mode 100644
index 00000000..631db778
--- /dev/null
+++ b/kpovmodeler/pmnormaledit.h
@@ -0,0 +1,70 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMNORMALEDIT_H
+#define PMNORMALEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebaseedit.h"
+
+class PMNormal;
+class QCheckBox;
+class PMFloatEdit;
+
+/**
+ * Dialog edit class for @ref PMNormal
+ */
+class PMNormalEdit : public PMTextureBaseEdit
+{
+ Q_OBJECT
+ typedef PMTextureBaseEdit Base;
+public:
+ /**
+ * Creates a PMNormalEdit with parent and name
+ */
+ PMNormalEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+ /** */
+ virtual bool isDataValid( );
+
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+protected slots:
+ void slotBumpSizeClicked( );
+
+private:
+ PMNormal* m_pDisplayedObject;
+
+ QCheckBox* m_pBumpSizeCheck;
+ PMFloatEdit* m_pBumpSizeEdit;
+ PMFloatEdit* m_pAccuracy;
+ QCheckBox* m_pUVMapping;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmobject.cpp b/kpovmodeler/pmobject.cpp
new file mode 100644
index 00000000..d6bb94b3
--- /dev/null
+++ b/kpovmodeler/pmobject.cpp
@@ -0,0 +1,283 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmobject.h"
+#include "pmcontrolpoint.h"
+#include "pmdialogeditbase.h"
+#include "pmmemento.h"
+#include "pmprototypemanager.h"
+#include "pminsertrulesystem.h"
+#include "pmpart.h"
+
+PMDefinePropertyClass( PMObject, PMObjectProperty );
+
+PMMetaObject* PMObject::s_pMetaObject = 0;
+
+PMObject::PMObject( PMPart* part )
+{
+ m_pParent = 0;
+ m_selected = false;
+ m_pPrevSibling = 0;
+ m_pNextSibling = 0;
+ m_pMemento = 0;
+ m_readOnly = false;
+ m_pPart = part;
+
+ if( !m_pPart )
+ kdError( PMArea ) << "PMObject::PMObject: The part may not be null" << endl;
+}
+
+PMObject::PMObject( const PMObject& o )
+{
+ m_pParent = 0;
+ m_selected = false;
+ m_pPrevSibling = 0;
+ m_pNextSibling = 0;
+ m_pMemento = 0;
+ m_readOnly = false;
+ m_pPart = o.m_pPart;
+}
+
+PMObject::~PMObject( )
+{
+}
+
+PMMetaObject* PMObject::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Object", 0 );
+ s_pMetaObject->addProperty(
+ new PMObjectProperty( "readOnly", &PMObject::setReadOnly, &PMObject::isReadOnly ) );
+ s_pMetaObject->addProperty(
+ new PMObjectProperty( "numberOfChildren", 0, &PMObject::countChildren ) );
+ }
+ return s_pMetaObject;
+}
+
+PMObject* PMObject::newObject( ) const
+{
+ return metaObject( )->newObject( m_pPart );
+}
+
+bool PMObject::insertChildAfter( PMObject*, PMObject* )
+{
+ kdError( PMArea ) << "Tried to insert object into a non composite object" << "\n";
+ return false;
+}
+
+bool PMObject::insertChildBefore( PMObject*, PMObject* )
+{
+ kdError( PMArea ) << "Tried to insert object into a non composite object" << "\n";
+ return false;
+}
+
+void PMObject::setSelected( bool s )
+{
+ if( m_selected != s )
+ {
+ if( s )
+ {
+ if( isSelectable( ) )
+ {
+ m_selected = true;
+ if( m_pParent )
+ m_pParent->adjustSelectedChildren( 1 );
+ }
+ }
+ else
+ {
+ m_selected = false;
+ if( m_pParent )
+ m_pParent->adjustSelectedChildren( -1 );
+ }
+ }
+}
+
+bool PMObject::isSelectable( )
+{
+ bool is = true;
+ PMObject* o;
+
+ for( o = m_pParent; o && is; o = o->m_pParent )
+ if( o->isSelected( ) )
+ is = false;
+
+ return is;
+}
+
+bool PMObject::isReadOnly( ) const
+{
+ if( m_readOnly )
+ return true;
+ if( m_pParent )
+ return m_pParent->isReadOnly( );
+ return false;
+}
+
+bool PMObject::takeChild( PMObject* )
+{
+ kdError( PMArea ) << "Tried to remove object out of a non composite object" << "\n";
+ return false;
+}
+
+bool PMObject::takeChild( uint )
+{
+ kdError( PMArea ) << "Tried to remove object out of a non composite object" << "\n";
+ return false;
+}
+
+PMDialogEditBase* PMObject::editWidget( QWidget* parent ) const
+{
+ return new PMDialogEditBase( parent );
+// return 0;
+}
+
+void PMObject::createMemento( )
+{
+ if( m_pMemento )
+ delete m_pMemento;
+ m_pMemento = new PMMemento( this );
+}
+
+PMMemento* PMObject::takeMemento( )
+{
+ PMMemento* tmp = m_pMemento;
+ m_pMemento = 0;
+ return tmp;
+}
+
+void PMObject::restoreMemento( PMMemento* /* s */ )
+{
+ // nothing to be done at the moment
+}
+
+PMMatrix PMObject::transformedWith( ) const
+{
+ PMMatrix result = PMMatrix::identity( );
+ const PMObject* o = this;
+
+ if( o->firstChild( ) )
+ o = o->firstChild( );
+ else if( o->nextSibling( ) )
+ o = o->nextSibling( );
+ else
+ o = o->parent( );
+
+ while( o )
+ {
+ if( o->hasTransformationMatrix( ) )
+ result = o->transformationMatrix( ) * result;
+
+ if( o->nextSibling( ) )
+ o = o->nextSibling( );
+ else
+ o = o->parent( );
+ }
+
+ return result;
+}
+
+QDomElement PMObject::serialize( QDomDocument& doc ) const
+{
+ QDomElement e = doc.createElement( className( ).lower( ) );
+ serialize( e, doc );
+ return e;
+}
+
+void PMObject::readAttributes( const PMXMLHelper& )
+{
+}
+
+void PMObject::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+}
+
+bool PMObject::setProperty( const QString& name, const PMVariant& v )
+{
+ PMPropertyBase* p = metaObject( )->property( name );
+ if( !p )
+ return false;
+ return p->setProperty( this, v );
+}
+
+QStringList PMObject::properties( ) const
+{
+ QStringList lst;
+ PMPropertyIterator it = metaObject( )->properties( );
+
+ for( ; it.current( ); ++it )
+ lst.append( it.current( )->name( ) );
+
+ return lst;
+}
+
+PMVariant PMObject::property( const QString& name ) const
+{
+ PMPropertyBase* p = metaObject( )->property( name );
+ if( !p )
+ return PMVariant( );
+ return p->getProperty( this );
+}
+
+bool PMObject::isA( const QString& className ) const
+{
+ if( !m_pPart )
+ return false;
+ return m_pPart->prototypeManager( )->isA( metaObject( ), className );
+}
+
+QString PMObject::type( ) const
+{
+ return metaObject( )->className( );
+}
+
+bool PMObject::canInsert( const QString& className, const PMObject* after,
+ const PMObjectList* objectsBetween ) const
+{
+ if( !m_pPart )
+ return false;
+ return m_pPart->insertRuleSystem( )->canInsert( this, className, after, objectsBetween );
+}
+
+bool PMObject::canInsert( const PMObject* o, const PMObject* after,
+ const PMObjectList* objectsBetween ) const
+{
+ if( !m_pPart )
+ return false;
+ return m_pPart->insertRuleSystem( )->canInsert( this, o, after, objectsBetween );
+}
+
+int PMObject::canInsert( const PMObjectList& list, const PMObject* after ) const
+{
+ if( !m_pPart )
+ return false;
+ return m_pPart->insertRuleSystem( )->canInsert( this, list, after );
+}
+
+int PMObject::canInsert( const QStringList& classes, const PMObject* after ) const
+{
+ if( !m_pPart )
+ return false;
+ return m_pPart->insertRuleSystem( )->canInsert( this, classes, after );
+}
diff --git a/kpovmodeler/pmobject.h b/kpovmodeler/pmobject.h
new file mode 100644
index 00000000..0c11008b
--- /dev/null
+++ b/kpovmodeler/pmobject.h
@@ -0,0 +1,511 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMOBJECT_H
+#define PMOBJECT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qvaluelist.h>
+#include <qptrlist.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <kdebug.h>
+#include <qdom.h>
+
+#include "pmmatrix.h"
+#include "pmcontrolpoint.h"
+#include "pmmetaobject.h"
+#include "pmdebug.h"
+
+class PMDialogEditBase;
+class PMMemento;
+class PMViewStructure;
+class PMXMLHelper;
+class PMDeclare;
+class PMObjectAction;
+class PMPart;
+
+class PMObject;
+typedef QPtrList<PMObject> PMObjectList;
+typedef QPtrListIterator<PMObject> PMObjectListIterator;
+
+/**
+ * Base class for all povray objects
+ *
+ * Used pattern: Composite
+ *
+ * All list/child functionality is disabled in this class. Objects that
+ * can have children has to be inherited from @ref PMCompositeObject.
+ */
+class PMObject
+{
+ friend class PMCompositeObject;
+public:
+ /**
+ * Creates an empty PMObject without parent.
+ */
+ PMObject( PMPart* part );
+ /**
+ * Copy constructor. All object pointers (parent, siblings) are set to 0!
+ */
+ PMObject( const PMObject& o );
+ /**
+ * Deletes the object and all children.
+ */
+ virtual ~PMObject( );
+
+ /**
+ * Returns a new object of that type
+ */
+ PMObject* newObject( ) const;
+ /**
+ * Returns a deep copy of the object
+ */
+ virtual PMObject* copy( ) const = 0;
+
+ /**
+ * Returns the meta object for the class
+ */
+ virtual PMMetaObject* metaObject( ) const;
+
+ /**
+ * Returns true if the object is of type t or inherits the object
+ * class with type t
+ */
+ bool isA( const QString& className ) const;
+
+ /**
+ * Returns the class name (not i18n'ed, without the PM prefix)
+ */
+ QString type( ) const;
+ /**
+ * same as @ref type( )
+ */
+ QString className( ) const { return type( ); }
+ /**
+ * Returns the class name of the object (povray name).
+ * This is the name that is showed in dialogs and menus.
+ */
+ virtual QString description( ) const = 0;
+ /**
+ * Returns the name of the object. This is the name that helps
+ * the user to identify a object (like "south wall", "floor" ...)
+ */
+ virtual QString name( ) const { return QString::null; }
+ /**
+ * Returns true if the object can have a name
+ */
+ virtual bool canHaveName( ) const { return false; }
+ /**
+ * Returns true if the object should be exported for rendering
+ */
+ virtual bool exportPovray( ) const { return true; }
+
+ /**
+ * Returns a pointer to the parent object.
+ */
+ PMObject* parent( ) const { return m_pParent; }
+ /**
+ * Returns a pointer to the corresponding part
+ */
+ PMPart* part( ) const { return m_pPart; }
+
+ /**
+ * Returns true if an object with type className can be inserted
+ * as child after the object after.
+ *
+ * The parser uses the third parameter for top level objects. These objects
+ * have to be treated as if they are inserted after the object after.
+ */
+ bool canInsert( const QString& className, const PMObject* after,
+ const PMObjectList* objectsBetween = 0 ) const;
+ /**
+ * Returns true if the object o can be inserted as child after the object
+ * after.
+ *
+ * The parser uses the third parameter for top level objects. These objects
+ * have to be treated as if they are inserted after the object after.
+ */
+ bool canInsert( const PMObject* o, const PMObject* after,
+ const PMObjectList* objectsBetween = 0 ) const;
+ /**
+ * Returns the number of objects that can be inserted at that position
+ */
+ int canInsert( const PMObjectList& list, const PMObject* after ) const;
+ /**
+ * Returns the number of objects that can be inserted at that position
+ */
+ int canInsert( const QStringList& classes, const PMObject* after ) const;
+
+ /**
+ * Returns true if an insert or remove operation of children will
+ * change data inside this class
+ */
+ virtual bool dataChangeOnInsertRemove( ) const { return false; }
+
+ /**
+ * Returns a pointer to the first child. Null for this class
+ */
+ virtual PMObject* firstChild( ) const { return 0; }
+ /**
+ * Returns a pointer to the last child. Null for this class
+ */
+ virtual PMObject* lastChild( ) const { return 0; }
+ /**
+ * Returns a pointer to the child object at position index,
+ * or null if the index is out of range.
+ */
+ virtual PMObject* childAt( uint ) const { return 0; }
+ /**
+ * Returns the next sibling of that item
+ */
+ PMObject* nextSibling( ) const { return m_pNextSibling; }
+ /**
+ * Returns the previous sibling of that item
+ */
+ PMObject* prevSibling( ) const { return m_pPrevSibling; }
+
+ /**
+ * Returns true if the object contains the child object o
+ */
+ virtual bool containsChild( PMObject* ) const { return false; }
+ /**
+ * Returns the index of the child or -1 if not found
+ */
+ virtual int findChild( PMObject* ) { return -1; }
+ /**
+ * Inserts the object as child at index index.
+ * If i is -1, the object is appended.
+ * Returns true if successful
+ */
+ virtual bool insertChild( PMObject*, int )
+ {
+ kdError( PMArea ) << "Tried to insert object into a non composite object" << "\n";
+ return false;
+ }
+ /**
+ * Inserts the object as child after the child object after
+ */
+ virtual bool insertChildAfter( PMObject* object, PMObject* after );
+ /**
+ * Inserts the object as child before the child object before
+ */
+ virtual bool insertChildBefore( PMObject* object, PMObject* before );
+ /**
+ * Appends the object as last child. Returns true if successful
+ */
+ virtual bool appendChild( PMObject* )
+ {
+ kdError( PMArea ) << "Tried to insert object into a non composite object" << "\n";
+ return false;
+ }
+ /**
+ * Returns the number of children. 0 in this class
+ */
+ virtual int countChildren( ) const { return 0; }
+ /**
+ * Removes a child object. Does not delete it!
+ * Returns true if successful
+ */
+ virtual bool takeChild( PMObject* );
+ /**
+ * Removes a child object at index i. Does not delete it!
+ * Returns true if successful
+ */
+ virtual bool takeChild( uint );
+
+ /**
+ * Called when a child was removed. For classes that have to be informed
+ * when children are removed
+ */
+ virtual void childRemoved( PMObject* ) { };
+ /**
+ * Called when a child was added. For classes that have to be informed
+ * when children are added
+ */
+ virtual void childAdded( PMObject* ) { };
+
+ /**
+ * Returns true if the object needs auxiliary files.
+ */
+ virtual bool needsAuxiliaryFiles( ) const { return false; }
+ /**
+ * Returns a list of auxiliary files
+ */
+ virtual QStringList auxiliaryFiles( ) const { return QStringList( ); }
+
+ /**
+ * Returns true if the object has a (povray) transformation matrix.
+ * True for transformation objects.
+ */
+ virtual bool hasTransformationMatrix( ) const { return false; }
+ /**
+ * Returns the (povray) transformation of the object, if it has one,
+ * otherwise an identity matrix
+ */
+ virtual PMMatrix transformationMatrix( ) const
+ {
+ kdError( PMArea ) << "This object has no transformation matrix" << "\n";
+ return PMMatrix::identity( );
+ }
+ /**
+ * Returns the matrix, the object is transformed with
+ */
+ PMMatrix transformedWith( ) const;
+
+ /**
+ * Returns the view structure ( see @ref PMViewStructure ) of the object
+ * or 0, if it has none.
+ *
+ * The view structure will be created or updated if necessary.
+ */
+ virtual PMViewStructure* viewStructure( ) { return 0; }
+
+ /**
+ * Creates the control points and appends them to the list.
+ *
+ * The caller becomes the owner of the control points and has
+ * to delete them.
+ *
+ * Control points are the interface between the graphical views and the
+ * PMObject for graphical changes.
+ */
+ virtual void controlPoints( PMControlPointList& ) { }
+ /**
+ * Tells the object that the control points have changed
+ */
+ virtual void controlPointsChanged( PMControlPointList& ) { }
+ /**
+ * Tells the object that the control points have changed
+ *
+ * The object can add objects to the second parameter, if
+ * additional objects were changed during the graphical change,
+ * not only this object.
+ *
+ * If you leave the list empty, only this object was changed.
+ * If you add children or other objects to the list, add this object
+ * to the list, too, if it was changed!
+ *
+ * IMPORTANT: When you change additional objects, make sure that
+ * a memento is created for these objects (@ref mementoCreated,
+ * @ref createMemento) before changing data.
+ *
+ * Calls @ref controlPointsChanged by default.
+ */
+ virtual void controlPointsChangedList( PMControlPointList& list,
+ PMObjectList& /*changedObjects*/ )
+ {
+ controlPointsChanged( list );
+ }
+ /**
+ * Returns true if multiple control points can be selected
+ */
+ virtual bool multipleSelectControlPoints( ) const { return false; }
+
+ /**
+ * Each object can add actions to the context menu of the @ref PMGLView.
+ *
+ * Each time the user opens the context menu, this function is called.
+ * Add all supported actions to this list and call the base class.
+ *
+ * The default implementation adds no action.
+ *
+ * @see PMObjectAction
+ */
+ virtual void addObjectActions( const PMControlPointList&,
+ QPtrList<PMObjectAction>& ) { }
+
+ /**
+ * This member is called when the user selects an object action
+ * in the context menu.
+ *
+ * The arguments are the selected action, the list of control points,
+ * the 3D (!) positions of the control points (screen-x, screen-y and depth)
+ * in the active opengl view and the 2D mouse position.
+ */
+ virtual void objectActionCalled( const PMObjectAction*,
+ const PMControlPointList&,
+ const QPtrList<PMVector>&,
+ const PMVector& ) { };
+
+ /**
+ * Saves the object as kpovmodeler xml code.
+ */
+ QDomElement serialize( QDomDocument& doc ) const;
+ /**
+ * Adds the objects attributes and child objects to the element
+ */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const = 0;
+ /**
+ * Reads the attributes from the QDomElement
+ */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns the list of known properties
+ */
+ QStringList properties( ) const;
+
+ /**
+ * Sets a property and returns true if successful
+ */
+ bool setProperty( const QString&, const PMVariant& v );
+ /**
+ * Returns a property
+ */
+ PMVariant property( const QString& ) const;
+
+ /**
+ * Returns true if the object is selected
+ */
+ bool isSelected( ) { return m_selected; }
+ /**
+ * Sets this object to be selected if s is true and to not be selected
+ if s is false
+ */
+ void setSelected( bool s );
+ /**
+ * Returns true if this item can be selected. An item cannot be selected
+ * if a parent object is selected
+ */
+ bool isSelectable( );
+ /**
+ * Returns the number of selected child items. All selected items in
+ * any depth are counted
+ */
+ virtual int selectedChildren( ) const { return 0; }
+ /**
+ * Deselects recursively all child objects
+ */
+ virtual void deselectChildren( ) { };
+ /**
+ * Returns true if this object is read only
+ */
+ bool isReadOnly( ) const;
+ /**
+ * Makes this object read only, if yes == true. All children will
+ * be read only, too
+ */
+ void setReadOnly( bool yes = true ) { m_readOnly = yes; }
+
+ /**
+ * Creates a new edit widget that can display this object and
+ * returns a pointer to it.
+ *
+ * The widget will be created as a child of parent.
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const = 0;
+ /**
+ * Returns a pointer to the @ref PMDeclare object, that is linked to
+ * that object, or 0, if this object contains no link
+ */
+ virtual PMDeclare* linkedObject( ) const { return 0; }
+
+ /**
+ * Tells the object to create a memento object.
+ *
+ * By default a simple @ref PMMemento will be created.
+ * If the memento doesn't provide enough functionality, subclass the memento
+ * and reimplement this function.
+ *
+ * NOTE: The new memento has to inherit the memento used in the base class!
+ *
+ * If a memento was created, the object saves all changes its
+ * state. The memento is then used for undo/redo.
+ *
+ * First call this function, change attributes and then take the mementos
+ * with @ref takeMemento
+ *
+ * If you want to restore the old state, call @ref restoreMemento with
+ * the memento.
+ */
+ virtual void createMemento( );
+ /**
+ * Returns true if a memento was created
+ */
+ bool mementoCreated( ) const { return m_pMemento != 0; }
+ /**
+ * Takes the memento. The caller is responsible to delete the memento
+ */
+ PMMemento* takeMemento( );
+ /**
+ * Restores the state s
+ */
+ virtual void restoreMemento( PMMemento* s );
+
+ /**
+ * This function is called before the part is unloaded.
+ *
+ * Delete static pointer variables to clean up the memory.
+ *
+ * This method can be called multiple times when there are subclasses.
+ * Set the pointer to 0 after deleting an object!
+ */
+ virtual void cleanUp( ) const;
+
+protected:
+ /**
+ * Adds num to the number of selected objects in this object and all
+ * parent objects. num can be negative.
+ */
+ virtual void adjustSelectedChildren( int /*num*/ ) { };
+ /**
+ * The memento where the old status of the object should be stored
+ */
+ PMMemento* m_pMemento;
+private:
+ /**
+ * Pointer to the parent object. 0 if the object has no parent.
+ */
+ PMObject* m_pParent;
+ /**
+ * Pointer to the prev sibling. 0 if the object has no prev sibling.
+ */
+ PMObject* m_pPrevSibling;
+ /**
+ * Pointer to the next sibling. 0 if the object has no next sibling.
+ */
+ PMObject* m_pNextSibling;
+ /**
+ * true if this object is selected
+ */
+ bool m_selected;
+ /**
+ * true if this object is read only. All children will be read only, too
+ */
+ bool m_readOnly;
+ /**
+ * The meta object
+ */
+ static PMMetaObject* s_pMetaObject;
+ /**
+ * The corresponding part
+ */
+ PMPart* m_pPart;
+};
+
+#endif
diff --git a/kpovmodeler/pmobjectaction.h b/kpovmodeler/pmobjectaction.h
new file mode 100644
index 00000000..e9a843ce
--- /dev/null
+++ b/kpovmodeler/pmobjectaction.h
@@ -0,0 +1,100 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMOBJECTACTION_H
+#define PMOBJECTACTION_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmvector.h"
+#include "pmcontrolpoint.h"
+#include "pmmetaobject.h"
+#include <qptrlist.h>
+#include <qstring.h>
+
+class KAction;
+
+/**
+ * Helper class for object action functions.
+ *
+ * Each object can define actions that are inserted into the context
+ * menu. This class stores informations of one action.
+ *
+ * The actionID has to be unique for each class.
+ *
+ * The member m_action is set later by the framework.
+ */
+class PMObjectAction
+{
+public:
+ /**
+ * Constructor
+ */
+ PMObjectAction( PMMetaObject* objectType, int actionID,
+ const QString& description, bool enabled = true )
+ {
+ m_class = objectType;
+ m_actionID = actionID;
+ m_description = description;
+ m_enabled = enabled;
+ m_menuID = -1;
+ }
+
+ /**
+ * Returns the class type for the action
+ */
+ PMMetaObject* objectType( ) const { return m_class; }
+ /**
+ * Returns the action ID
+ */
+ int actionID( ) const { return m_actionID; }
+ /**
+ * Returns the description
+ */
+ QString description( ) const { return m_description; }
+
+ /**
+ * Returns the enabled flag
+ */
+ bool isEnabled( ) const { return m_enabled; }
+ /**
+ * Sets the enabled flag
+ */
+ void setEnabled( bool enable ) { m_enabled = enable; }
+
+ /**
+ * Returns the menu id
+ */
+ int menuID( ) const { return m_menuID; }
+ /**
+ * Sets the menu id
+ */
+ void setMenuID( int id ) { m_menuID = id; }
+
+private:
+ PMMetaObject* m_class;
+ int m_actionID;
+ QString m_description;
+ bool m_enabled;
+ int m_menuID;
+};
+
+#endif
diff --git a/kpovmodeler/pmobjectdrag.cpp b/kpovmodeler/pmobjectdrag.cpp
new file mode 100644
index 00000000..6bebfc8e
--- /dev/null
+++ b/kpovmodeler/pmobjectdrag.cpp
@@ -0,0 +1,230 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmobjectdrag.h"
+#include "pmobject.h"
+#include "pmpart.h"
+#include "pmpovrayparser.h"
+#include "pmxmlparser.h"
+#include "pmxmlhelper.h"
+#include "pmdocumentformat.h"
+#include "pmiomanager.h"
+#include "pmserializer.h"
+
+#include <qbuffer.h>
+#include <string.h>
+
+const char* const c_kpmDocumentMimeFormat = "application/x-kpovmodeler";
+
+PMObjectDrag::PMObjectDrag( PMPart* part, PMObject* object, QWidget* dragSource,
+ const char* name )
+ : QDragObject( dragSource, name )
+{
+ QByteArray modelerData;
+
+ QTextStream s2( modelerData, IO_WriteOnly );
+ QDomDocument doc( "KPOVMODELER" );
+ QDomElement top = doc.createElement( "objects" );
+ doc.appendChild( top );
+ top.setAttribute( "majorFormat", c_majorDocumentFormat );
+ top.setAttribute( "minorFormat", c_minorDocumentFormat );
+
+ if( object->type( ) == "Scene" )
+ {
+ PMObject* o = object->firstChild( );
+ for( ; o; o = o->nextSibling( ) )
+ {
+ QDomElement e = o->serialize( doc );
+ top.appendChild( e );
+ }
+ }
+ else
+ {
+ QDomElement e = object->serialize( doc );
+ top.appendChild( e );
+ }
+ s2 << doc;
+
+ m_data.push_back( modelerData );
+ m_mimeTypes.push_back( c_kpmDocumentMimeFormat );
+
+ const QPtrList<PMIOFormat>& formats = part->ioManager( )->formats( );
+ QPtrListIterator<PMIOFormat> it( formats );
+ for( ; it.current( ); ++it )
+ {
+ if( it.current( )->services( ) & PMIOFormat::Export )
+ {
+ QByteArray data;
+ QBuffer buffer( data );
+ buffer.open( IO_WriteOnly );
+
+ PMSerializer* ser = it.current( )->newSerializer( &buffer );
+
+ if( ser )
+ {
+ ser->serialize( object );
+ ser->close( );
+ delete ser;
+ buffer.close( );
+
+ m_data.push_back( data );
+ m_mimeTypes.push_back( it.current( )->mimeType( ) );
+
+ kdDebug( PMArea ) << "Added mime type " << it.current( )->mimeType( )
+ << " " << data.size( ) << " bytes" << endl;
+ }
+ else
+ kdError( PMArea ) << "Format claims to support exporting, but doesn't provide a serializer" << endl;
+
+ buffer.close( );
+ }
+ }
+}
+
+PMObjectDrag::PMObjectDrag( PMPart* part, const PMObjectList& objList, QWidget* dragSource,
+ const char* name )
+ : QDragObject( dragSource, name )
+{
+ QByteArray modelerData;
+
+ QTextStream s2( modelerData, IO_WriteOnly );
+ QDomDocument doc( "KPOVMODELER" );
+ QDomElement top = doc.createElement( "objects" );
+ doc.appendChild( top );
+ top.setAttribute( "majorFormat", c_majorDocumentFormat );
+ top.setAttribute( "minorFormat", c_minorDocumentFormat );
+
+ PMObjectListIterator it( objList );
+ for( ; it.current( ); ++it )
+ {
+ if( it.current( )->type( ) == "Scene" )
+ {
+ PMObject* o = it.current( )->firstChild( );
+ for( ; o; o = o->nextSibling( ) )
+ {
+ QDomElement e = o->serialize( doc );
+ top.appendChild( e );
+ }
+ }
+ else
+ {
+ QDomElement e = it.current( )->serialize( doc );
+ top.appendChild( e );
+ }
+ }
+
+ s2 << doc;
+
+ m_data.push_back( modelerData );
+ m_mimeTypes.push_back( c_kpmDocumentMimeFormat );
+
+ const QPtrList<PMIOFormat>& formats = part->ioManager( )->formats( );
+ QPtrListIterator<PMIOFormat> fit( formats );
+ for( ; fit.current( ); ++fit )
+ {
+ if( fit.current( )->services( ) & PMIOFormat::Export )
+ {
+ QByteArray data;
+ QBuffer buffer( data );
+ buffer.open( IO_WriteOnly );
+
+ PMSerializer* ser = fit.current( )->newSerializer( &buffer );
+
+ if( ser )
+ {
+ ser->serializeList( objList );
+ ser->close( );
+ delete ser;
+ buffer.close( );
+
+ m_data.push_back( data );
+ m_mimeTypes.push_back( fit.current( )->mimeType( ) );
+
+ kdDebug( PMArea ) << "Added mime type " << fit.current( )->mimeType( )
+ << " " << data.size( ) << " bytes" << endl;
+ }
+ else
+ kdError( PMArea ) << "Format claims to support exporting, but doesn't provide a serializer" << endl;
+
+ buffer.close( );
+ }
+ }
+}
+
+PMObjectDrag::~PMObjectDrag( )
+{
+}
+
+QByteArray PMObjectDrag::encodedData( const char* format ) const
+{
+ QValueList<QByteArray>::ConstIterator dit;
+ QStringList::ConstIterator sit;
+
+ for( dit = m_data.begin( ), sit = m_mimeTypes.begin( );
+ dit != m_data.end( ) && sit != m_mimeTypes.end( ); ++dit, ++sit )
+ {
+ if( *sit == format )
+ return *dit;
+ }
+
+ QByteArray empty;
+ return empty;
+}
+
+const char* PMObjectDrag::format( int i /*=0*/ ) const
+{
+ if( i >= 0 && i < ( signed ) m_mimeTypes.size( ) )
+ return ( *m_mimeTypes.at( i ) ).latin1( );
+ return 0;
+}
+
+bool PMObjectDrag::canDecode( const QMimeSource* e, PMPart* part )
+{
+ if( e->provides( c_kpmDocumentMimeFormat ) )
+ return true;
+
+ const QPtrList<PMIOFormat>& formats = part->ioManager( )->formats( );
+ QPtrListIterator<PMIOFormat> fit( formats );
+ for( ; fit.current( ); ++fit )
+ if( fit.current( )->services( ) & PMIOFormat::Import &&
+ e->provides( fit.current( )->mimeType( ).latin1( ) ) )
+ return true;
+
+ return false;
+}
+
+PMParser* PMObjectDrag::newParser( const QMimeSource* e, PMPart* part )
+{
+ if( e->provides( c_kpmDocumentMimeFormat ) )
+ return new PMXMLParser( part, e->encodedData( c_kpmDocumentMimeFormat ) );
+
+ const QPtrList<PMIOFormat>& formats = part->ioManager( )->formats( );
+ QPtrListIterator<PMIOFormat> fit( formats );
+ for( ; fit.current( ); ++fit )
+ {
+ PMIOFormat* f = fit.current( );
+ QString str = f->mimeType( );
+ const char* lat = str.latin1( );
+ if( f->services( ) & PMIOFormat::Import && e->provides( lat ) )
+ return f->newParser( part, e->encodedData( lat ) );
+ }
+
+ return 0;
+}
+
+
diff --git a/kpovmodeler/pmobjectdrag.h b/kpovmodeler/pmobjectdrag.h
new file mode 100644
index 00000000..a8f4daf3
--- /dev/null
+++ b/kpovmodeler/pmobjectdrag.h
@@ -0,0 +1,81 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMOBJECTDRAG_H
+#define PMOBJECTDRAG_H
+
+#include <qdragobject.h>
+#include <qstringlist.h>
+
+#include "pmobject.h"
+class PMParser;
+class PMPart;
+
+/**
+ * Supports drag/drop and copy/paste of kpovmodeler objects
+ */
+
+class PMObjectDrag : public QDragObject
+{
+public:
+ /**
+ * Creates a drag object for one object
+ *
+ * The object drag will contain all formats that are supported
+ * by the part.
+ * @see PMIOManager
+ */
+ PMObjectDrag( PMPart* part, PMObject* object, QWidget* dragSource = 0,
+ const char* name = 0 );
+ /**
+ * Creates a drag object for all objects in objList
+ */
+ PMObjectDrag( PMPart* part, const PMObjectList& objList, QWidget* dragSource = 0,
+ const char* name = 0 );
+ /**
+ * Deletes the drag object
+ */
+ ~PMObjectDrag( );
+ /**
+ * Returns the encoded payload of this object, in the
+ * specified MIME format.
+ */
+ virtual QByteArray encodedData( const char* ) const;
+ /**
+ * Returns the ith format, or NULL.
+ */
+ virtual const char* format( int i = 0 ) const;
+ /**
+ * Returns true if the information in e can be decoded
+ */
+ static bool canDecode( const QMimeSource* e, PMPart* part );
+ /**
+ * Returns a pointer to a parser for this drag object or 0, if the data
+ * can't be decoded.
+ *
+ * The caller is responsible to delete the parser.
+ */
+ static PMParser* newParser( const QMimeSource* e, PMPart* part );
+
+private:
+ QValueList<QByteArray> m_data;
+ QStringList m_mimeTypes;
+};
+
+#endif
diff --git a/kpovmodeler/pmobjectlibrarysettings.cpp b/kpovmodeler/pmobjectlibrarysettings.cpp
new file mode 100644
index 00000000..ce80f77c
--- /dev/null
+++ b/kpovmodeler/pmobjectlibrarysettings.cpp
@@ -0,0 +1,189 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@kde.org
+ copyright : (C) 2003 by Luis Carvalho
+ email : lpassos@oninetspeed.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#include "pmobjectlibrarysettings.h"
+
+#include "pmlibrarymanager.h"
+#include "pmlibraryhandle.h"
+#include "pmlibraryhandleedit.h"
+#include "pmdebug.h"
+
+#include <qlayout.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <klocale.h>
+#include <kfiledialog.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+
+PMObjectLibrarySettings::PMObjectLibrarySettings( QWidget* parent, const char* name )
+ : PMSettingsDialogPage( parent, name )
+{
+ QVBoxLayout* vlayout = new QVBoxLayout( this, 0, KDialog::spacingHint( ) );
+
+ QGroupBox* gb = new QGroupBox( i18n( "Libraries" ), this );
+ vlayout->addWidget( gb );
+
+ QHBoxLayout* hlayout = new QHBoxLayout( gb, KDialog::marginHint( ) + 5, KDialog::spacingHint( ) );
+ m_pObjectLibraries = new QListBox( gb );
+ connect( m_pObjectLibraries, SIGNAL( selectionChanged( ) ), SLOT( slotObjectLibraryChanged( ) ) );
+ hlayout->addWidget( m_pObjectLibraries );
+ QVBoxLayout* gvl = new QVBoxLayout( hlayout );
+ m_pCreateObjectLibrary = new QPushButton( i18n( "Create..." ), gb );
+ connect( m_pCreateObjectLibrary, SIGNAL( clicked( ) ), SLOT( slotCreateObjectLibrary( ) ) );
+ gvl->addWidget( m_pCreateObjectLibrary );
+ m_pRemoveObjectLibrary = new QPushButton( i18n( "Remove" ), gb );
+ connect( m_pRemoveObjectLibrary, SIGNAL( clicked( ) ), SLOT( slotRemoveObjectLibrary( ) ) );
+ gvl->addWidget( m_pRemoveObjectLibrary );
+ m_pImportObjectLibrary = new QPushButton( i18n( "Import" ), gb );
+ connect( m_pImportObjectLibrary, SIGNAL( clicked( ) ), SLOT( slotImportObjectLibrary( ) ) );
+ gvl->addWidget( m_pImportObjectLibrary );
+ m_pModifyObjectLibrary = new QPushButton( i18n( "Properties" ), gb );
+ connect( m_pModifyObjectLibrary, SIGNAL( clicked( ) ), SLOT( slotModifyObjectLibrary( ) ) );
+ gvl->addWidget( m_pModifyObjectLibrary );
+ gvl->addStretch( 1 );
+
+ gb = new QGroupBox( i18n( "Library Details" ), this );
+ QGridLayout* grid = new QGridLayout( gb, 4, 2, KDialog::marginHint( ) + 5, KDialog::spacingHint( ) );
+ QLabel* lbl = new QLabel( i18n( "Path" ), gb );
+ grid->addWidget( lbl, 0, 0 );
+ lbl = new QLabel( i18n( "Author" ), gb );
+ grid->addWidget( lbl, 1, 0 );
+ lbl = new QLabel( i18n( "Description" ), gb );
+ grid->addWidget( lbl, 2, 0 );
+ m_pLibraryPath = new QLabel( "", gb );
+ m_pLibraryAuthor = new QLabel( "", gb );
+ m_pLibraryDescription = new QLabel( "", gb );
+ m_pReadOnlyText = new QLabel( "", gb );
+ grid->addWidget( m_pLibraryPath, 0, 1 );
+ grid->addWidget( m_pLibraryAuthor, 1, 1 );
+ grid->addWidget( m_pLibraryDescription, 2, 1 );
+ grid->addMultiCellWidget( m_pReadOnlyText, 3, 3, 0, 1 );
+ grid->setColStretch( 1, 1 );
+ vlayout->addWidget( gb );
+
+ vlayout->addStretch( 1 );
+}
+
+void PMObjectLibrarySettings::displaySettings( )
+{
+ m_pObjectLibraries->clear( );
+ m_pObjectLibraries->insertStringList( PMLibraryManager::theManager( )->availableLibraries( ) );
+}
+
+void PMObjectLibrarySettings::applySettings( )
+{
+}
+
+bool PMObjectLibrarySettings::validateData( )
+{
+ return true;
+}
+
+void PMObjectLibrarySettings::displayDefaults( )
+{
+}
+
+void PMObjectLibrarySettings::slotImportObjectLibrary( )
+{
+ // TODO
+}
+
+void PMObjectLibrarySettings::slotModifyObjectLibrary( )
+{
+ PMLibraryHandle* h = PMLibraryManager::theManager( )->getLibraryHandle( m_pObjectLibraries->currentText( ) );
+ if( h )
+ {
+ PMLibraryHandleEdit h_dlg( h, this );
+
+ if( h_dlg.exec( ) == QDialog::Accepted )
+ {
+ h->saveLibraryInfo( );
+ displaySettings( );
+ for( unsigned i = 0; i < m_pObjectLibraries->count( ); ++i )
+ {
+ if( m_pObjectLibraries->text( i ) == h->name( ) )
+ {
+ m_pObjectLibraries->setSelected( i, true );
+ break;
+ }
+ }
+ slotObjectLibraryChanged( );
+ }
+ }
+}
+
+void PMObjectLibrarySettings::slotRemoveObjectLibrary( )
+{
+ m_pObjectLibraries->removeItem( m_pObjectLibraries->currentItem( ) );
+}
+
+void PMObjectLibrarySettings::slotCreateObjectLibrary( )
+{
+ PMLibraryHandle h;
+ PMLibraryHandleEdit h_dlg( &h, this );
+ QString libfilename;
+
+ if( h_dlg.exec( ) == QDialog::Accepted )
+ {
+ libfilename = h.name( );
+ h.setPath( locateLocal( "appdata", "library/" ) + libfilename.stripWhiteSpace( ) + "/" );
+ // Create the new library
+ switch( h.createLibrary( ) )
+ {
+ case PMLibraryHandle::Ok:
+ PMLibraryManager::theManager( )->refresh( );
+ displaySettings( );
+ break;
+ case PMLibraryHandle::ExistingDir:
+ KMessageBox::error( this, i18n( "The folder already exists." ) );
+ break;
+ case PMLibraryHandle::CouldNotCreateDir:
+ KMessageBox::error( this, i18n( "Could not create the folder." ) );
+ break;
+ default:
+ kdError( PMArea ) << "Unexpected error in slotCreateObjectLibrary." << endl;
+ }
+ }
+}
+
+void PMObjectLibrarySettings::slotObjectLibraryChanged( )
+{
+ PMLibraryHandle* h = PMLibraryManager::theManager( )->getLibraryHandle( m_pObjectLibraries->currentText( ) );
+ if( h )
+ {
+ m_pLibraryPath->setText( h->path( ) );
+ m_pLibraryAuthor->setText( h->author( ) );
+ m_pLibraryDescription->setText( h->description( ) );
+ if( h->isReadOnly( ) )
+ m_pReadOnlyText->setText( i18n( "This library is not modifiable." ) );
+ else
+ m_pReadOnlyText->setText( i18n( "This library is modifiable." ) );
+ }
+ else
+ {
+ m_pLibraryPath->setText( "" );
+ m_pLibraryAuthor->setText( "" );
+ m_pLibraryDescription->setText( "" );
+ m_pReadOnlyText->setText( "" );
+ }
+}
+
+#include "pmobjectlibrarysettings.moc"
diff --git a/kpovmodeler/pmobjectlibrarysettings.h b/kpovmodeler/pmobjectlibrarysettings.h
new file mode 100644
index 00000000..1c4c9ab9
--- /dev/null
+++ b/kpovmodeler/pmobjectlibrarysettings.h
@@ -0,0 +1,78 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@kde.org
+ copyright : (C) 2003 by Luis Carvalho
+ email : lpassos@oninetspeed.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#ifndef PMOBJECTLIBRARYSETTINGS_H
+#define PMOBJECTLIBRARYSETTINGS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsettingsdialog.h"
+
+class QPushButton;
+class QListBox;
+
+/**
+ * Object library configuration dialog page
+ */
+class PMObjectLibrarySettings : public PMSettingsDialogPage
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ PMObjectLibrarySettings( QWidget* parent, const char* name = 0 );
+ /** */
+ virtual void displaySettings( );
+ /** */
+ virtual void applySettings( );
+ /** */
+ virtual bool validateData( );
+ /** */
+ virtual void displayDefaults( );
+protected slots:
+ /** Called when the object library create button is clicked */
+ void slotCreateObjectLibrary( );
+ /** Called when the object library properties button is clicked */
+ void slotModifyObjectLibrary( );
+ /** Called when the object library remove button is clicked */
+ void slotRemoveObjectLibrary( );
+ /** Called when the object library import button is clicked */
+ void slotImportObjectLibrary( );
+ /** Called when the selected library is changed */
+ void slotObjectLibraryChanged( );
+private:
+ int m_objectLibraryIndex;
+ int m_selectionIndex;
+ QListBox* m_pObjectLibraries;
+ QPushButton* m_pCreateObjectLibrary;
+ QPushButton* m_pModifyObjectLibrary;
+ QPushButton* m_pRemoveObjectLibrary;
+ QPushButton* m_pImportObjectLibrary;
+
+ QLabel* m_pLibraryPath;
+ QLabel* m_pLibraryAuthor;
+ QLabel* m_pLibraryDescription;
+ QLabel* m_pReadOnlyText;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmobjectlink.cpp b/kpovmodeler/pmobjectlink.cpp
new file mode 100644
index 00000000..6596471d
--- /dev/null
+++ b/kpovmodeler/pmobjectlink.cpp
@@ -0,0 +1,197 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmobjectlink.h"
+#include "pmdeclare.h"
+#include "pmpart.h"
+#include "pmsymboltable.h"
+#include "pmobjectlinkedit.h"
+#include "pmparser.h"
+
+#include "pmmemento.h"
+#include "pmxmlhelper.h"
+
+#include <klocale.h>
+
+PMDefinePropertyClass( PMObjectLink, PMObjectLinkProperty );
+
+PMMetaObject* PMObjectLink::s_pMetaObject = 0;
+PMObject* createNewObjectLink( PMPart* part )
+{
+ return new PMObjectLink( part );
+}
+
+PMObjectLink::PMObjectLink( PMPart* part )
+ : Base( part )
+{
+ m_pLinkedObject = 0;
+}
+
+PMObjectLink::PMObjectLink( const PMObjectLink& o )
+ : Base( o )
+{
+ m_pLinkedObject = 0;
+ setLinkedObject( o.m_pLinkedObject );
+}
+
+PMObjectLink::~PMObjectLink( )
+{
+}
+
+QString PMObjectLink::description( ) const
+{
+ return i18n( "object link" );
+}
+
+PMMetaObject* PMObjectLink::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "ObjectLink", Base::metaObject( ),
+ createNewObjectLink );
+ s_pMetaObject->addProperty(
+ new PMObjectLinkProperty( "linkedObject", &PMObjectLink::setLinkedObjectProperty,
+ &PMObjectLink::linkedObjectProperty ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMObjectLink::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+bool PMObjectLink::setLinkedObject( PMDeclare* obj )
+{
+ if( obj )
+ {
+ if( obj->declareType( ) == "GraphicalObject" ||
+ obj->declareType( ) == "Light" )
+ {
+ if( m_pLinkedObject != obj )
+ {
+ if( m_pMemento )
+ {
+ m_pMemento->addData( s_pMetaObject, PMLinkedObjectID,
+ m_pLinkedObject );
+ m_pMemento->setViewStructureChanged( );
+ }
+
+ if( m_pLinkedObject )
+ {
+ m_pLinkedObject->removeLinkedObject( this );
+ if( m_pMemento )
+ m_pMemento->addChangedObject( m_pLinkedObject, PMCData );
+ }
+ m_pLinkedObject = obj;
+ m_pLinkedObject->addLinkedObject( this );
+ if( m_pMemento )
+ m_pMemento->addChangedObject( m_pLinkedObject, PMCData );
+ }
+ return true;
+ }
+ else
+ return false;
+ }
+ else
+ {
+ if( m_pLinkedObject != 0 )
+ {
+ if( m_pMemento )
+ {
+ m_pMemento->addData( s_pMetaObject, PMLinkedObjectID,
+ m_pLinkedObject );
+ m_pMemento->addChangedObject( m_pLinkedObject, PMCData );
+ }
+ m_pLinkedObject->removeLinkedObject( this );
+ m_pLinkedObject = 0;
+ }
+ return true;
+ }
+ return false;
+}
+
+void PMObjectLink::setLinkedObjectProperty( PMObject* o )
+{
+ if( o == 0 )
+ setLinkedObject( 0 );
+ else if( o->isA( "Declare" ) )
+ setLinkedObject( ( PMDeclare* ) o );
+}
+
+void PMObjectLink::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ if( m_pLinkedObject )
+ e.setAttribute( "prototype", m_pLinkedObject->id( ) );
+ Base::serialize( e, doc );
+}
+
+void PMObjectLink::readAttributes( const PMXMLHelper& h )
+{
+ QString id = h.stringAttribute( "prototype", "" );
+ if( !id.isEmpty( ) )
+ {
+ PMDeclare* link = h.parser( )->checkLink( id );
+ if( link )
+ {
+ if( link->type( ) == "Declare" )
+ {
+ m_pLinkedObject = ( PMDeclare* ) link;
+ m_pLinkedObject->addLinkedObject( this );
+ }
+ else
+ h.parser( )->printError( i18n( "Declare \"%1\" has wrong type." )
+ .arg( id ) );
+ }
+ }
+ Base::readAttributes( h );
+}
+
+PMDialogEditBase* PMObjectLink::editWidget( QWidget* parent ) const
+{
+ return new PMObjectLinkEdit( parent );
+}
+
+void PMObjectLink::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMLinkedObjectID:
+ setLinkedObject( ( PMDeclare* ) data->objectData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMObjectLink::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmobjectlink.h b/kpovmodeler/pmobjectlink.h
new file mode 100644
index 00000000..54eb4833
--- /dev/null
+++ b/kpovmodeler/pmobjectlink.h
@@ -0,0 +1,99 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMOBJECTLINK_H
+#define PMOBJECTLINK_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobject.h"
+#include "pmdeclare.h"
+
+/**
+ * Class for links of graphical objects.
+ */
+class PMObjectLink : public PMSolidObject
+{
+ typedef PMSolidObject Base;
+public:
+ /**
+ * Creates an empty PMObjectLink
+ */
+ PMObjectLink( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMObjectLink( const PMObjectLink& ol );
+ /**
+ * deletes the PMObjectLink
+ */
+ virtual ~PMObjectLink( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMObjectLink( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual PMDeclare* linkedObject( ) const { return m_pLinkedObject; }
+ /**
+ * Sets the linked object. Returns true if successful
+ */
+ bool setLinkedObject( PMDeclare* o );
+
+ /**
+ * Method used by the properties framework
+ */
+ PMObject* linkedObjectProperty( ) const { return m_pLinkedObject; }
+ /**
+ * Method used by the properties framework
+ */
+ void setLinkedObjectProperty( PMObject* o );
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMObjectLinkEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmobjectlink" ); }
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMObjectLinkMementoID { PMLinkedObjectID };
+ PMDeclare* m_pLinkedObject;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmobjectlinkedit.cpp b/kpovmodeler/pmobjectlinkedit.cpp
new file mode 100644
index 00000000..935f8714
--- /dev/null
+++ b/kpovmodeler/pmobjectlinkedit.cpp
@@ -0,0 +1,74 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmobjectlinkedit.h"
+#include "pmobjectlink.h"
+#include "pmdeclare.h"
+#include "pmobjectselect.h"
+#include "pmlinkedit.h"
+
+#include <qlayout.h>
+
+PMObjectLinkEdit::PMObjectLinkEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMObjectLinkEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ m_pLinkEdit = new PMLinkEdit( this );
+ QStringList l;
+ l.append( "GraphicalObject" );
+ l.append( "Light" );
+ m_pLinkEdit->setLinkPossibilities( l );
+ topLayout( )->addWidget( m_pLinkEdit );
+ connect( m_pLinkEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMObjectLinkEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "ObjectLink" ) )
+ {
+ m_pDisplayedObject = ( PMObjectLink* ) o;
+ m_pLinkEdit->setDisplayedObject( m_pDisplayedObject );
+ m_pLinkEdit->setReadOnly( m_pDisplayedObject->isReadOnly( ) );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMObjectLinkEdit: Can't display object\n";
+}
+
+void PMObjectLinkEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setLinkedObject( m_pLinkEdit->link( ) );
+ }
+}
+
+bool PMObjectLinkEdit::isDataValid( )
+{
+ return Base::isDataValid( );
+}
+
+#include "pmobjectlinkedit.moc"
diff --git a/kpovmodeler/pmobjectlinkedit.h b/kpovmodeler/pmobjectlinkedit.h
new file mode 100644
index 00000000..2f517951
--- /dev/null
+++ b/kpovmodeler/pmobjectlinkedit.h
@@ -0,0 +1,62 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMOBJECTLINKEDIT_H
+#define PMOBJECTLINKEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobjectedit.h"
+
+class PMObjectLink;
+class PMLinkEdit;
+
+/**
+ * Dialog edit class for @ref PMObjectLink.
+ */
+class PMObjectLinkEdit : public PMSolidObjectEdit
+{
+ Q_OBJECT
+ typedef PMSolidObjectEdit Base;
+public:
+ /**
+ * Creates a PMObjectLinkEdit with parent and name
+ */
+ PMObjectLinkEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMObjectLink* m_pDisplayedObject;
+ PMLinkEdit* m_pLinkEdit;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmobjectselect.cpp b/kpovmodeler/pmobjectselect.cpp
new file mode 100644
index 00000000..fb9fa0ce
--- /dev/null
+++ b/kpovmodeler/pmobjectselect.cpp
@@ -0,0 +1,361 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmobjectselect.h"
+#include "pmfactory.h"
+#include <klocale.h>
+#include <kiconloader.h>
+
+PMListBoxObject::PMListBoxObject( QListBox* listbox, PMObject* obj,
+ QListBoxItem* after )
+ : QListBoxPixmap( listbox,
+ SmallIcon( obj->pixmap( ), PMFactory::instance( ) ),
+ checkName( obj->name( ) ), after )
+{
+ m_pObject = obj;
+}
+
+PMListBoxObject::PMListBoxObject( QListBox* listbox, PMObject* obj )
+ : QListBoxPixmap( listbox,
+ SmallIcon( obj->pixmap( ), PMFactory::instance( ) ),
+ checkName( obj->name( ) ) )
+{
+ m_pObject = obj;
+}
+
+PMListBoxObject::PMListBoxObject( PMObject* obj )
+ : QListBoxPixmap( SmallIcon( obj->pixmap( ), PMFactory::instance( ) ),
+ checkName( obj->name( ) ) )
+{
+ m_pObject = obj;
+}
+
+PMListBoxObject::PMListBoxObject( QListBox* listbox, PMObject* obj,
+ const QString& text, QListBoxItem* after )
+ : QListBoxPixmap( listbox,
+ SmallIcon( obj->pixmap( ), PMFactory::instance( ) ),
+ text, after )
+{
+ m_pObject = obj;
+}
+
+PMListBoxObject::PMListBoxObject( QListBox* listbox, PMObject* obj,
+ const QString& text )
+ : QListBoxPixmap( listbox,
+ SmallIcon( obj->pixmap( ), PMFactory::instance( ) ),
+ text )
+{
+ m_pObject = obj;
+}
+
+PMListBoxObject::PMListBoxObject( PMObject* obj, const QString& text )
+ : QListBoxPixmap( SmallIcon( obj->pixmap( ), PMFactory::instance( ) ),
+ text )
+{
+ m_pObject = obj;
+}
+
+QString PMListBoxObject::checkName( const QString& text )
+{
+ if( text.isEmpty( ) )
+ return i18n( "(unnamed)" );
+ return text;
+}
+
+PMListBoxObject::~PMListBoxObject( )
+{
+}
+
+
+QSize PMObjectSelect::s_size = QSize( 200, 300 );
+
+
+PMObjectSelect::PMObjectSelect( QWidget* parent, const char* name, bool modal )
+ : KDialogBase( parent, name, modal, i18n( "Choose Object" ), Ok | Cancel )
+{
+ m_pSelectedObject = 0;
+ m_pListBox = new QListBox( this );
+ setMainWidget( m_pListBox );
+ setInitialSize( s_size );
+
+ connect( m_pListBox, SIGNAL( highlighted( QListBoxItem* ) ),
+ SLOT( slotHighlighted( QListBoxItem* ) ) );
+ connect( m_pListBox, SIGNAL( selected( QListBoxItem* ) ),
+ SLOT( slotSelected( QListBoxItem* ) ) );
+ enableButtonOK( false );
+}
+
+PMObjectSelect::~PMObjectSelect( )
+{
+ s_size = size( );
+}
+
+void PMObjectSelect::addObject( PMObject* obj )
+{
+ m_pListBox->insertItem( new PMListBoxObject( obj ) );
+}
+
+int PMObjectSelect::selectObject( PMObject* link, const QString& t,
+ PMObject* & obj, QWidget* parent )
+{
+ PMObject* last = link;
+ PMObject* scene;
+ bool stop = false;
+ bool found = false;
+
+ do
+ {
+ scene = last->parent( );
+ if( scene )
+ {
+ if( scene->type( ) == "Scene" )
+ {
+ last = last->prevSibling( );
+ stop = true;
+ found = true;
+ }
+ else
+ last = last->parent( );
+ }
+ else
+ stop = true;
+ }
+ while( !stop );
+
+ if( found )
+ {
+ PMObjectSelect s( parent );
+
+ PMObject* o = scene->firstChild( );
+ bool l = false;
+
+ while( o && !l && last )
+ {
+ if( o->type( ) == t )
+ s.m_pListBox->insertItem( new PMListBoxObject( o ) );
+
+ if( o == last )
+ l = true;
+ else
+ o = o->nextSibling( );
+ }
+
+ int result = s.exec( );
+ if( result == Accepted )
+ obj = s.selectedObject( );
+
+ return result;
+ }
+ else
+ kdError( PMArea ) << "PMObjectSelect: Link does not seem to be correctly inserted in the scene.\n";
+ return Rejected;
+}
+
+int PMObjectSelect::selectObject( PMObject* link,
+ const QStringList& t,
+ PMObject* & obj, QWidget* parent )
+{
+ PMObject* last = link;
+ PMObject* scene;
+ bool stop = false;
+ bool found = false;
+
+ do
+ {
+ scene = last->parent( );
+ if( scene )
+ {
+ if( scene->type( ) == "Scene" )
+ {
+ last = last->prevSibling( );
+ stop = true;
+ found = true;
+ }
+ else
+ last = last->parent( );
+ }
+ else
+ stop = true;
+ }
+ while( !stop );
+
+ if( found )
+ {
+ PMObjectSelect s( parent );
+
+ PMObject* o = scene->firstChild( );
+ bool l = false;
+
+ while( o && !l && last )
+ {
+ if( t.findIndex( o->type( ) ) >= 0 )
+ s.m_pListBox->insertItem( new PMListBoxObject( o ) );
+
+ if( o == last )
+ l = true;
+ else
+ o = o->nextSibling( );
+ }
+
+ int result = s.exec( );
+ if( result == Accepted )
+ obj = s.selectedObject( );
+
+ return result;
+ }
+ else
+ kdError( PMArea ) << "PMObjectSelect: Link does not seem to be correctly inserted in the scene.\n";
+ return Rejected;
+}
+
+int PMObjectSelect::selectDeclare( PMObject* link, const QString& declareType,
+ PMObject* & obj, QWidget* parent )
+{
+ PMObject* last = link;
+ PMObject* scene;
+ bool stop = false;
+ bool found = false;
+
+ do
+ {
+ scene = last->parent( );
+ if( scene )
+ {
+ if( scene->type( ) == "Scene" )
+ {
+ last = last->prevSibling( );
+ stop = true;
+ found = true;
+ }
+ else
+ last = last->parent( );
+ }
+ else
+ stop = true;
+ }
+ while( !stop );
+
+ if( found )
+ {
+ PMObjectSelect s( parent );
+
+ PMObject* o = scene->firstChild( );
+ PMDeclare* decl;
+
+ bool l = false;
+
+ while( o && !l && last )
+ {
+ if( o->type( ) == "Declare" )
+ {
+ decl = ( PMDeclare* ) o;
+ if( decl->declareType( ) == declareType )
+ s.m_pListBox->insertItem( new PMListBoxObject( o ) );
+ }
+
+ if( o == last )
+ l = true;
+ else
+ o = o->nextSibling( );
+ }
+
+ int result = s.exec( );
+ if( result == Accepted )
+ obj = s.selectedObject( );
+
+ return result;
+ }
+ else
+ kdError( PMArea ) << "PMObjectSelect: Link does not seem to be correctly inserted in the scene.\n";
+ return Rejected;
+}
+
+int PMObjectSelect::selectDeclare( PMObject* link, const QStringList& declareTypes,
+ PMObject* & obj, QWidget* parent )
+{
+ PMObject* last = link;
+ PMObject* scene;
+ bool stop = false;
+ bool found = false;
+
+ do
+ {
+ scene = last->parent( );
+ if( scene )
+ {
+ if( scene->type( ) == "Scene" )
+ {
+ last = last->prevSibling( );
+ stop = true;
+ found = true;
+ }
+ else
+ last = last->parent( );
+ }
+ else
+ stop = true;
+ }
+ while( !stop );
+
+ if( found )
+ {
+ PMObjectSelect s( parent );
+
+ PMObject* o = scene->firstChild( );
+ PMDeclare* decl;
+
+ bool l = false;
+
+ while( o && !l && last )
+ {
+ if( o->type( ) == "Declare" )
+ {
+ decl = ( PMDeclare* ) o;
+ if( declareTypes.findIndex( decl->declareType( ) ) >= 0 )
+ s.m_pListBox->insertItem( new PMListBoxObject( o ) );
+ }
+
+ if( o == last )
+ l = true;
+ else
+ o = o->nextSibling( );
+ }
+
+ int result = s.exec( );
+ if( result == Accepted )
+ obj = s.selectedObject( );
+
+ return result;
+ }
+ else
+ kdError( PMArea ) << "PMObjectSelect: Link does not seem to be correctly inserted in the scene.\n";
+ return Rejected;
+}
+
+void PMObjectSelect::slotHighlighted( QListBoxItem* lbi )
+{
+ m_pSelectedObject = ( ( PMListBoxObject* ) lbi )->object( );
+ enableButtonOK( true );
+}
+
+void PMObjectSelect::slotSelected( QListBoxItem* lbi )
+{
+ m_pSelectedObject = ( ( PMListBoxObject* ) lbi )->object( );
+ enableButtonOK( true );
+ accept( );
+}
+#include "pmobjectselect.moc"
diff --git a/kpovmodeler/pmobjectselect.h b/kpovmodeler/pmobjectselect.h
new file mode 100644
index 00000000..c69af315
--- /dev/null
+++ b/kpovmodeler/pmobjectselect.h
@@ -0,0 +1,132 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMOBJECTSELECT_H
+#define PMOBJECTSELECT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kdialogbase.h>
+#include <qlistbox.h>
+#include <qsize.h>
+#include <qvaluelist.h>
+#include <qstringlist.h>
+#include "pmobject.h"
+#include "pmdeclare.h"
+
+/**
+ * QListBoxItem for @ref PMObject
+ */
+class PMListBoxObject : public QListBoxPixmap
+{
+public:
+ /**
+ * Constructs a list box item in listbox listbox showing the
+ * object obj. The item gets inserted after the item after
+ */
+ PMListBoxObject( QListBox* listbox, PMObject* obj, QListBoxItem* after );
+ /**
+ * Constructs a list box item in listbox listbox showing the object obj
+ */
+ PMListBoxObject( QListBox* listbox, PMObject* obj );
+ /**
+ * Constructs a list box item showing the object obj
+ */
+ PMListBoxObject( PMObject* obj );
+ /**
+ * Constructs a list box item in listbox listbox showing the
+ * text text. The item gets inserted after the item after
+ */
+ PMListBoxObject( QListBox* listbox, PMObject* obj, const QString& text,
+ QListBoxItem* after );
+ /**
+ * Constructs a list box item in listbox listbox showing the text text
+ */
+ PMListBoxObject( QListBox* listbox, PMObject* obj, const QString& text );
+ /**
+ * Constructs a list box item showing the text text
+ */
+ PMListBoxObject( PMObject* obj, const QString& text );
+ /**
+ * Deletes the item
+ */
+ ~PMListBoxObject( );
+
+ /**
+ * Returns a pointer to the object
+ */
+ PMObject* object( ) const { return m_pObject; }
+private:
+ static QString checkName( const QString& text );
+ PMObject* m_pObject;
+};
+
+/**
+ * A PMObject selection widget
+ */
+class PMObjectSelect : public KDialogBase
+{
+ Q_OBJECT
+public:
+ /**
+ * Creates a selection widget with parent and name
+ */
+ PMObjectSelect( QWidget* parent = 0, const char* name = 0,
+ bool modal = true );
+ /**
+ * Deletes the dialog
+ */
+ ~PMObjectSelect( );
+
+ /**
+ * Appends the object to the list of choosable objects
+ */
+ void addObject( PMObject* obj );
+
+ /**
+ * Returns the currently selected object
+ */
+ PMObject* selectedObject( ) const { return m_pSelectedObject; }
+
+ /**
+ * Create a modal dialog and let the user choose an declare object
+ * of type t.
+ *
+ * Only objects above the object link are listed.
+ */
+ static int selectObject( PMObject* link, const QString& t, PMObject* & obj,
+ QWidget* parent = 0 );
+ static int selectObject( PMObject* link, const QStringList& t,
+ PMObject* & obj, QWidget* parent = 0 );
+ static int selectDeclare( PMObject* link, const QString& declareType,
+ PMObject* & obj, QWidget* parent = 0 );
+ static int selectDeclare( PMObject* link, const QStringList& dt,
+ PMObject* & obj, QWidget* parent = 0 );
+
+protected slots:
+ void slotHighlighted( QListBoxItem* lbi );
+ void slotSelected( QListBoxItem* lbi );
+private:
+ QListBox* m_pListBox;
+ PMObject* m_pSelectedObject;
+ static QSize s_size;
+};
+
+#endif
diff --git a/kpovmodeler/pmobjectsettings.cpp b/kpovmodeler/pmobjectsettings.cpp
new file mode 100644
index 00000000..06aae64e
--- /dev/null
+++ b/kpovmodeler/pmobjectsettings.cpp
@@ -0,0 +1,550 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmobjectsettings.h"
+
+#include "pmlineedits.h"
+#include "pmrendermanager.h"
+#include "pmdefaults.h"
+
+#include "pmsphere.h"
+#include "pmcone.h"
+#include "pmcylinder.h"
+#include "pmtorus.h"
+#include "pmplane.h"
+#include "pmdisc.h"
+#include "pmblobsphere.h"
+#include "pmblobcylinder.h"
+#include "pmlathe.h"
+#include "pmsor.h"
+#include "pmprism.h"
+#include "pmsqe.h"
+#include "pmspheresweep.h"
+#include "pmheightfield.h"
+#include "pmtext.h"
+
+#include <qlayout.h>
+#include <qcheckbox.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <klocale.h>
+
+
+PMObjectSettings::PMObjectSettings( QWidget* parent, const char* name )
+ : PMSettingsDialogPage( parent, name )
+{
+ QHBoxLayout* hlayout;
+ QVBoxLayout* vlayout;
+ QVBoxLayout* gvl;
+ QGridLayout* grid;
+ QGroupBox* gb;
+
+ vlayout = new QVBoxLayout( this, 0, KDialog::spacingHint( ) );
+
+ gb = new QGroupBox( i18n( "Subdivisions" ), this );
+ vlayout->addWidget( gb );
+ gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) );
+ gvl->addSpacing( 10 );
+ grid = new QGridLayout( gvl, 13, 3 );
+
+ grid->addWidget( new QLabel( i18n( "Sphere:" ), gb ), 0, 0 );
+ hlayout = new QHBoxLayout( );
+ grid->addLayout( hlayout, 0, 2 );
+ grid->addWidget( new QLabel( "u", gb ), 0, 1 );
+ m_pSphereUSteps = new PMIntEdit( gb );
+ hlayout->addWidget( m_pSphereUSteps );
+ m_pSphereUSteps->setValidation( true, 2, true, 32 );
+ hlayout->addWidget( new QLabel( "v", gb ) );
+ m_pSphereVSteps = new PMIntEdit( gb );
+ hlayout->addWidget( m_pSphereVSteps );
+ m_pSphereVSteps->setValidation( true, 4, true, 64 );
+ hlayout->addStretch( 1 );
+
+ grid->addWidget( new QLabel( i18n( "Cylinder:" ), gb ), 1, 0 );
+ hlayout = new QHBoxLayout( );
+ grid->addLayout( hlayout, 1, 2 );
+ m_pCylinderSteps = new PMIntEdit( gb );
+ hlayout->addWidget( m_pCylinderSteps );
+ m_pCylinderSteps->setValidation( true, 4, true, 64 );
+ hlayout->addStretch( 1 );
+
+ grid->addWidget( new QLabel( i18n( "Cone:" ), gb ), 2, 0 );
+ hlayout = new QHBoxLayout( );
+ grid->addLayout( hlayout, 2, 2 );
+ m_pConeSteps = new PMIntEdit( gb );
+ hlayout->addWidget( m_pConeSteps );
+ m_pConeSteps->setValidation( true, 4, true, 64 );
+ hlayout->addStretch( 1 );
+
+ grid->addWidget( new QLabel( i18n( "Torus:" ), gb ), 3, 0 );
+ hlayout = new QHBoxLayout( );
+ grid->addLayout( hlayout, 3, 2 );
+ grid->addWidget( new QLabel( "u", gb ), 3, 1 );
+ m_pTorusUSteps = new PMIntEdit( gb );
+ hlayout->addWidget( m_pTorusUSteps );
+ m_pTorusUSteps->setValidation( true, 2, true, 16 );
+ hlayout->addWidget( new QLabel( "v", gb ) );
+ m_pTorusVSteps = new PMIntEdit( gb );
+ hlayout->addWidget( m_pTorusVSteps );
+ m_pTorusVSteps->setValidation( true, 4, true, 64 );
+ hlayout->addStretch( 1 );
+
+ grid->addWidget( new QLabel( i18n( "Disc:" ), gb ), 4, 0 );
+ hlayout = new QHBoxLayout( );
+ grid->addLayout( hlayout, 4, 2 );
+ m_pDiscSteps = new PMIntEdit( gb );
+ hlayout->addWidget( m_pDiscSteps );
+ m_pDiscSteps->setValidation( true, 4, true, 64 );
+ hlayout->addStretch( 1 );
+
+ grid->addWidget( new QLabel( i18n( "Blob sphere:" ), gb ), 5, 0 );
+ hlayout = new QHBoxLayout( );
+ grid->addLayout( hlayout, 5, 2 );
+ grid->addWidget( new QLabel( "u", gb ), 5, 1 );
+ m_pBlobSphereUSteps = new PMIntEdit( gb );
+ hlayout->addWidget( m_pBlobSphereUSteps );
+ m_pBlobSphereUSteps->setValidation( true, 2, true, 32 );
+ hlayout->addWidget( new QLabel( "v", gb ) );
+ m_pBlobSphereVSteps = new PMIntEdit( gb );
+ hlayout->addWidget( m_pBlobSphereVSteps );
+ m_pBlobSphereVSteps->setValidation( true, 4, true, 64 );
+ hlayout->addStretch( 1 );
+
+ grid->addWidget( new QLabel( i18n( "Blob cylinder:" ), gb ), 6, 0 );
+ hlayout = new QHBoxLayout( );
+ grid->addLayout( hlayout, 6, 2 );
+ grid->addWidget( new QLabel( "u", gb ), 6, 1 );
+ m_pBlobCylinderUSteps = new PMIntEdit( gb );
+ hlayout->addWidget( m_pBlobCylinderUSteps );
+ m_pBlobCylinderUSteps->setValidation( true, 2, true, 32 );
+ hlayout->addWidget( new QLabel( "v", gb ) );
+ m_pBlobCylinderVSteps = new PMIntEdit( gb );
+ hlayout->addWidget( m_pBlobCylinderVSteps );
+ m_pBlobCylinderVSteps->setValidation( true, 4, true, 64 );
+ hlayout->addStretch( 1 );
+
+ grid->addWidget( new QLabel( i18n( "Lathe:" ), gb ), 7, 0 );
+ hlayout = new QHBoxLayout( );
+ grid->addLayout( hlayout, 7, 2 );
+ grid->addWidget( new QLabel( "u", gb ), 7, 1 );
+ m_pLatheUSteps = new PMIntEdit( gb );
+ hlayout->addWidget( m_pLatheUSteps );
+ m_pLatheUSteps->setValidation( true, 1, true, 16 );
+ hlayout->addWidget( new QLabel( "v", gb ) );
+ m_pLatheRSteps = new PMIntEdit( gb );
+ hlayout->addWidget( m_pLatheRSteps );
+ m_pLatheRSteps->setValidation( true, 4, true, 64 );
+ hlayout->addStretch( 1 );
+
+ grid->addWidget( new QLabel( i18n( "Surface of revolution:" ), gb ), 8, 0 );
+ hlayout = new QHBoxLayout( );
+ grid->addLayout( hlayout, 8, 2 );
+ grid->addWidget( new QLabel( "u", gb ), 8, 1 );
+ m_pSorUSteps = new PMIntEdit( gb );
+ hlayout->addWidget( m_pSorUSteps );
+ m_pSorUSteps->setValidation( true, 1, true, 16 );
+ hlayout->addWidget( new QLabel( "v", gb ) );
+ m_pSorRSteps = new PMIntEdit( gb );
+ hlayout->addWidget( m_pSorRSteps );
+ m_pSorRSteps->setValidation( true, 4, true, 64 );
+ hlayout->addStretch( 1 );
+
+ grid->addWidget( new QLabel( i18n( "Prism:" ), gb ), 9, 0 );
+ hlayout = new QHBoxLayout( );
+ grid->addLayout( hlayout, 9, 2 );
+ m_pPrismSteps = new PMIntEdit( gb );
+ hlayout->addWidget( m_pPrismSteps );
+ m_pPrismSteps->setValidation( true, 1, true, 16 );
+ hlayout->addStretch( 1 );
+
+ grid->addWidget( new QLabel( i18n( "Superquadric ellipsoid:" ), gb ), 10, 0 );
+ hlayout = new QHBoxLayout( );
+ grid->addLayout( hlayout, 10, 2 );
+ grid->addWidget( new QLabel( "u", gb ), 10, 1 );
+ m_pSqeUSteps = new PMIntEdit( gb );
+ hlayout->addWidget( m_pSqeUSteps );
+ m_pSqeUSteps->setValidation( true, 2, true, 8 );
+ hlayout->addWidget( new QLabel( "v", gb ) );
+ m_pSqeVSteps = new PMIntEdit( gb );
+ hlayout->addWidget( m_pSqeVSteps );
+ m_pSqeVSteps->setValidation( true, 2, true, 8 );
+ hlayout->addStretch( 1 );
+
+ grid->addWidget( new QLabel( i18n( "Sphere sweep:" ), gb ), 11, 0 );
+ hlayout = new QHBoxLayout( );
+ grid->addLayout( hlayout, 11, 2 );
+ grid->addWidget( new QLabel( "r", gb ), 11, 1 );
+ m_pSphereSweepRSteps = new PMIntEdit( gb );
+ hlayout->addWidget( m_pSphereSweepRSteps );
+ m_pSphereSweepRSteps->setValidation( true, 4, true, 64 );
+ hlayout->addWidget( new QLabel( "s", gb ) );
+ m_pSphereSweepSSteps = new PMIntEdit( gb );
+ hlayout->addWidget( m_pSphereSweepSSteps );
+ m_pSphereSweepSSteps->setValidation( true, 1, true, 16 );
+ hlayout->addStretch( 1 );
+
+ grid->addWidget( new QLabel( i18n( "Heightfield:" ), gb ), 12, 0 );
+ hlayout = new QHBoxLayout( );
+ grid->addLayout( hlayout, 12, 2 );
+ m_pHeightFieldVariance = new PMIntEdit( gb );
+ hlayout->addWidget( m_pHeightFieldVariance );
+ m_pHeightFieldVariance->setValidation( true, 1, true, 16 );
+ hlayout->addStretch( 1 );
+
+ gb = new QGroupBox( i18n( "Sizes" ), this );
+ vlayout->addWidget( gb );
+ gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) );
+ gvl->addSpacing( 10 );
+
+ grid = new QGridLayout( gvl, 1, 2 );
+
+ grid->addWidget( new QLabel( i18n( "Plane:" ), gb ), 0, 0 );
+ hlayout = new QHBoxLayout( );
+ grid->addLayout( hlayout, 0, 1 );
+ m_pPlaneSize = new PMFloatEdit( gb );
+ hlayout->addWidget( m_pPlaneSize );
+ m_pPlaneSize->setValidation( true, 0.1, false, 0.0 );
+ hlayout->addStretch( 1 );
+
+ gb = new QGroupBox( i18n( "Camera Views" ), this );
+ vlayout->addWidget( gb );
+ gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) );
+ gvl->addSpacing( 10 );
+
+ m_pHighDetailCameraViews = new QCheckBox( i18n( "High detail for enhanced projections" ), gb );
+ gvl->addWidget( m_pHighDetailCameraViews );
+
+ vlayout->addStretch( 1 );
+}
+
+void PMObjectSettings::displaySettings( )
+{
+ m_pSphereUSteps->setValue( PMSphere::uSteps( ) );
+ m_pSphereVSteps->setValue( PMSphere::vSteps( ) );
+ m_pCylinderSteps->setValue( PMCylinder::steps( ) );
+ m_pConeSteps->setValue( PMCone::steps( ) );
+ m_pTorusUSteps->setValue( PMTorus::uSteps( ) );
+ m_pTorusVSteps->setValue( PMTorus::vSteps( ) );
+ m_pDiscSteps->setValue( PMDisc::steps( ) );
+ m_pBlobSphereUSteps->setValue( PMBlobSphere::uSteps( ) );
+ m_pBlobSphereVSteps->setValue( PMBlobSphere::vSteps( ) );
+ m_pBlobCylinderUSteps->setValue( PMBlobCylinder::uSteps( ) );
+ m_pBlobCylinderVSteps->setValue( PMBlobCylinder::vSteps( ) );
+ m_pPlaneSize->setValue( PMPlane::planeSize( ) );
+ m_pLatheUSteps->setValue( PMLathe::sSteps( ) );
+ m_pLatheRSteps->setValue( PMLathe::rSteps( ) );
+ m_pSorUSteps->setValue( PMSurfaceOfRevolution::sSteps( ) );
+ m_pSorRSteps->setValue( PMSurfaceOfRevolution::rSteps( ) );
+ m_pPrismSteps->setValue( PMPrism::sSteps( ) );
+ m_pSqeUSteps->setValue( PMSuperquadricEllipsoid::uSteps( ) );
+ m_pSqeVSteps->setValue( PMSuperquadricEllipsoid::vSteps( ) );
+ m_pSphereSweepRSteps->setValue( PMSphereSweep::rSteps( ) );
+ m_pSphereSweepSSteps->setValue( PMSphereSweep::sSteps( ) );
+ m_pHeightFieldVariance->setValue( PMHeightField::variance( ) );
+ PMRenderManager* rm = PMRenderManager::theManager( );
+ m_pHighDetailCameraViews->setChecked( rm->highDetailCameraViews( ) );
+}
+
+void PMObjectSettings::displayDefaults( )
+{
+ m_pSphereUSteps->setValue( c_defaultSphereUSteps );
+ m_pSphereVSteps->setValue( c_defaultSphereVSteps );
+ m_pCylinderSteps->setValue( c_defaultCylinderSteps );
+ m_pConeSteps->setValue( c_defaultConeSteps );
+ m_pTorusUSteps->setValue( c_defaultTorusUSteps );
+ m_pTorusVSteps->setValue( c_defaultTorusVSteps );
+ m_pDiscSteps->setValue( c_defaultDiscSteps );
+ m_pBlobSphereUSteps->setValue( c_defaultBlobSphereUSteps );
+ m_pBlobSphereVSteps->setValue( c_defaultBlobSphereVSteps );
+ m_pBlobCylinderUSteps->setValue( c_defaultBlobCylinderUSteps );
+ m_pBlobCylinderVSteps->setValue( c_defaultBlobCylinderVSteps );
+ m_pLatheUSteps->setValue( c_defaultLatheSSteps );
+ m_pLatheRSteps->setValue( c_defaultLatheRSteps );
+ m_pSorUSteps->setValue( c_defaultSurfaceOfRevolutionSSteps );
+ m_pSorRSteps->setValue( c_defaultSurfaceOfRevolutionRSteps );
+ m_pPrismSteps->setValue( c_defaultPrismSSteps );
+ m_pSqeUSteps->setValue( c_defaultSuperquadricEllipsoidUSteps );
+ m_pSqeVSteps->setValue( c_defaultSuperquadricEllipsoidVSteps );
+ m_pSphereSweepRSteps->setValue( c_defaultSphereSweepRSteps );
+ m_pSphereSweepSSteps->setValue( c_defaultSphereSweepSSteps );
+ m_pHeightFieldVariance->setValue( c_defaultHeightFieldVariance );
+ m_pPlaneSize->setValue( c_defaultPlaneSize );
+ m_pHighDetailCameraViews->setChecked( c_defaultHighDetailCameraView );
+}
+
+bool PMObjectSettings::validateData( )
+{
+ if( !m_pSphereUSteps->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pSphereUSteps->setFocus( );
+ return false;
+ }
+ if( !m_pSphereVSteps->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pSphereVSteps->setFocus( );
+ return false;
+ }
+ if( !m_pCylinderSteps->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pCylinderSteps->setFocus( );
+ return false;
+ }
+ if( !m_pConeSteps->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pConeSteps->setFocus( );
+ return false;
+ }
+ if( !m_pTorusUSteps->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pTorusUSteps->setFocus( );
+ return false;
+ }
+ if( !m_pTorusVSteps->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pTorusVSteps->setFocus( );
+ return false;
+ }
+ if( !m_pDiscSteps->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pDiscSteps->setFocus( );
+ return false;
+ }
+ if( !m_pBlobSphereUSteps->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pBlobSphereUSteps->setFocus( );
+ return false;
+ }
+ if( !m_pBlobSphereVSteps->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pBlobSphereVSteps->setFocus( );
+ return false;
+ }
+ if( !m_pBlobCylinderUSteps->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pBlobCylinderUSteps->setFocus( );
+ return false;
+ }
+ if( !m_pBlobCylinderVSteps->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pBlobCylinderVSteps->setFocus( );
+ return false;
+ }
+ if( !m_pLatheUSteps->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pLatheUSteps->setFocus( );
+ return false;
+ }
+ if( !m_pLatheRSteps->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pLatheRSteps->setFocus( );
+ return false;
+ }
+ if( !m_pSorUSteps->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pSorUSteps->setFocus( );
+ return false;
+ }
+ if( !m_pSorRSteps->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pSorRSteps->setFocus( );
+ return false;
+ }
+ if( !m_pPrismSteps->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pPrismSteps->setFocus( );
+ return false;
+ }
+ if( !m_pSqeUSteps->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pSqeUSteps->setFocus( );
+ return false;
+ }
+ if( !m_pSqeVSteps->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pSqeVSteps->setFocus( );
+ return false;
+ }
+ if( !m_pSphereSweepRSteps->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pSphereSweepRSteps->setFocus( );
+ return false;
+ }
+ if( !m_pSphereSweepSSteps->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pSphereSweepSSteps->setFocus( );
+ return false;
+ }
+ if( !m_pHeightFieldVariance->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pHeightFieldVariance->setFocus( );
+ return false;
+ }
+ if( !m_pPlaneSize->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pPlaneSize->setFocus( );
+ return false;
+ }
+ return true;
+}
+
+void PMObjectSettings::applySettings( )
+{
+ bool repaint = false;
+
+ PMRenderManager* rm = PMRenderManager::theManager( );
+ if( rm->highDetailCameraViews( ) != m_pHighDetailCameraViews->isChecked( ) )
+ {
+ rm->setHighDetailCameraViews( m_pHighDetailCameraViews->isChecked( ) );
+ repaint = true;
+ }
+ if( PMSphere::uSteps( ) != m_pSphereUSteps->value( ) )
+ {
+ PMSphere::setUSteps( m_pSphereUSteps->value( ) );
+ repaint = true;
+ }
+ if( PMSphere::vSteps( ) != m_pSphereVSteps->value( ) )
+ {
+ PMSphere::setVSteps( m_pSphereVSteps->value( ) );
+ repaint = true;
+ }
+ if( PMCylinder::steps( ) != m_pCylinderSteps->value( ) )
+ {
+ PMCylinder::setSteps( m_pCylinderSteps->value( ) );
+ repaint = true;
+ }
+ if( PMCone::steps( ) != m_pConeSteps->value( ) )
+ {
+ PMCone::setSteps( m_pConeSteps->value( ) );
+ repaint = true;
+ }
+ if( PMTorus::uSteps( ) != m_pTorusUSteps->value( ) )
+ {
+ PMTorus::setUSteps( m_pTorusUSteps->value( ) );
+ repaint = true;
+ }
+ if( PMTorus::vSteps( ) != m_pTorusVSteps->value( ) )
+ {
+ PMTorus::setVSteps( m_pTorusVSteps->value( ) );
+ repaint = true;
+ }
+ if( PMDisc::steps( ) != m_pDiscSteps->value( ) )
+ {
+ PMDisc::setSteps( m_pDiscSteps->value( ) );
+ repaint = true;
+ }
+ if( PMBlobSphere::uSteps( ) != m_pBlobSphereUSteps->value( ) )
+ {
+ PMBlobSphere::setUSteps( m_pBlobSphereUSteps->value( ) );
+ repaint = true;
+ }
+ if( PMBlobSphere::vSteps( ) != m_pBlobSphereVSteps->value( ) )
+ {
+ PMBlobSphere::setVSteps( m_pBlobSphereVSteps->value( ) );
+ repaint = true;
+ }
+ if( PMBlobCylinder::uSteps( ) != m_pBlobCylinderUSteps->value( ) )
+ {
+ PMBlobCylinder::setUSteps( m_pBlobCylinderUSteps->value( ) );
+ repaint = true;
+ }
+ if( PMBlobCylinder::vSteps( ) != m_pBlobCylinderVSteps->value( ) )
+ {
+ PMBlobCylinder::setVSteps( m_pBlobCylinderVSteps->value( ) );
+ repaint = true;
+ }
+ if( PMPlane::planeSize( ) != m_pPlaneSize->value( ) )
+ {
+ PMPlane::setPlaneSize( m_pPlaneSize->value( ) );
+ repaint = true;
+ }
+ if( PMLathe::sSteps( ) != m_pLatheUSteps->value( ) )
+ {
+ PMLathe::setSSteps( m_pLatheUSteps->value( ) );
+ repaint = true;
+ }
+ if( PMLathe::rSteps( ) != m_pLatheRSteps->value( ) )
+ {
+ PMLathe::setRSteps( m_pLatheRSteps->value( ) );
+ repaint = true;
+ }
+ if( PMSurfaceOfRevolution::sSteps( ) != m_pSorUSteps->value( ) )
+ {
+ PMSurfaceOfRevolution::setSSteps( m_pSorUSteps->value( ) );
+ repaint = true;
+ }
+ if( PMSurfaceOfRevolution::rSteps( ) != m_pSorRSteps->value( ) )
+ {
+ PMSurfaceOfRevolution::setRSteps( m_pSorRSteps->value( ) );
+ repaint = true;
+ }
+ if( PMPrism::sSteps( ) != m_pPrismSteps->value( ) )
+ {
+ PMPrism::setSSteps( m_pPrismSteps->value( ) );
+ repaint = true;
+ }
+ if( PMSuperquadricEllipsoid::uSteps( ) != m_pSqeUSteps->value( ) )
+ {
+ PMSuperquadricEllipsoid::setUSteps( m_pSqeUSteps->value( ) );
+ repaint = true;
+ }
+ if( PMSuperquadricEllipsoid::vSteps( ) != m_pSqeVSteps->value( ) )
+ {
+ PMSuperquadricEllipsoid::setVSteps( m_pSqeVSteps->value( ) );
+ repaint = true;
+ }
+ if( PMSphereSweep::rSteps( ) != m_pSphereSweepRSteps->value( ) )
+ {
+ PMSphereSweep::setRSteps( m_pSphereSweepRSteps->value( ) );
+ repaint = true;
+ }
+ if( PMSphereSweep::sSteps( ) != m_pSphereSweepSSteps->value( ) )
+ {
+ PMSphereSweep::setSSteps( m_pSphereSweepSSteps->value( ) );
+ repaint = true;
+ }
+ if( PMHeightField::variance( ) != m_pHeightFieldVariance->value( ) )
+ {
+ PMHeightField::setVariance( m_pHeightFieldVariance->value( ) );
+ repaint = true;
+ }
+ if( repaint )
+ emit repaintViews( );
+}
+
+#include "pmobjectsettings.moc"
diff --git a/kpovmodeler/pmobjectsettings.h b/kpovmodeler/pmobjectsettings.h
new file mode 100644
index 00000000..716631c0
--- /dev/null
+++ b/kpovmodeler/pmobjectsettings.h
@@ -0,0 +1,78 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMOBJECTSETTINGS_H
+#define PMOBJECTSETTINGS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsettingsdialog.h"
+
+class PMIntEdit;
+class PMFloatEdit;
+class QCheckBox;
+
+/**
+ * Object details configuration dialog page
+ */
+class PMObjectSettings : public PMSettingsDialogPage
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ PMObjectSettings( QWidget* parent, const char* name = 0 );
+ /** */
+ virtual void displaySettings( );
+ /** */
+ virtual bool validateData( );
+ /** */
+ virtual void applySettings( );
+ /** */
+ virtual void displayDefaults( );
+
+private:
+ PMIntEdit* m_pSphereUSteps;
+ PMIntEdit* m_pSphereVSteps;
+ PMIntEdit* m_pCylinderSteps;
+ PMIntEdit* m_pConeSteps;
+ PMIntEdit* m_pTorusUSteps;
+ PMIntEdit* m_pTorusVSteps;
+ PMFloatEdit* m_pPlaneSize;
+ PMIntEdit* m_pDiscSteps;
+ PMIntEdit* m_pBlobSphereUSteps;
+ PMIntEdit* m_pBlobSphereVSteps;
+ PMIntEdit* m_pBlobCylinderUSteps;
+ PMIntEdit* m_pBlobCylinderVSteps;
+ PMIntEdit* m_pLatheUSteps;
+ PMIntEdit* m_pLatheRSteps;
+ PMIntEdit* m_pSorUSteps;
+ PMIntEdit* m_pSorRSteps;
+ PMIntEdit* m_pPrismSteps;
+ PMIntEdit* m_pSqeUSteps;
+ PMIntEdit* m_pSqeVSteps;
+ PMIntEdit* m_pSphereSweepRSteps;
+ PMIntEdit* m_pSphereSweepSSteps;
+ PMIntEdit* m_pHeightFieldVariance;
+ QCheckBox* m_pHighDetailCameraViews;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmopenglsettings.cpp b/kpovmodeler/pmopenglsettings.cpp
new file mode 100644
index 00000000..64f3ac9c
--- /dev/null
+++ b/kpovmodeler/pmopenglsettings.cpp
@@ -0,0 +1,59 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmopenglsettings.h"
+
+#include "pmglview.h"
+#include "pmdefaults.h"
+
+#include <qlayout.h>
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <klocale.h>
+
+PMOpenGLSettings::PMOpenGLSettings( QWidget* parent, const char* name )
+ : PMSettingsDialogPage( parent, name )
+{
+ QVBoxLayout* vlayout = new QVBoxLayout( this, 0, KDialog::spacingHint( ) );
+
+ m_pDirect = new QCheckBox( i18n( "Direct rendering" ), this );
+ vlayout->addWidget( new QLabel( i18n( "Changes take only effect after a restart!" ), this ) );
+ vlayout->addWidget( m_pDirect );
+ vlayout->addStretch( 1 );
+}
+
+void PMOpenGLSettings::displaySettings( )
+{
+ m_pDirect->setChecked( PMGLView::isDirectRenderingEnabled( ) );
+}
+
+void PMOpenGLSettings::displayDefaults( )
+{
+ m_pDirect->setChecked( true );
+}
+
+bool PMOpenGLSettings::validateData( )
+{
+ return true;
+}
+
+void PMOpenGLSettings::applySettings( )
+{
+ PMGLView::enableDirectRendering( m_pDirect->isChecked( ) );
+}
+
+#include "pmopenglsettings.moc"
diff --git a/kpovmodeler/pmopenglsettings.h b/kpovmodeler/pmopenglsettings.h
new file mode 100644
index 00000000..d893a6b0
--- /dev/null
+++ b/kpovmodeler/pmopenglsettings.h
@@ -0,0 +1,54 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMOPENGLSETTINGS_H
+#define PMOPENGLSETTINGS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsettingsdialog.h"
+
+class QCheckBox;
+
+/**
+ * OpenGL configuration dialog page
+ */
+class PMOpenGLSettings : public PMSettingsDialogPage
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ PMOpenGLSettings( QWidget* parent, const char* name = 0 );
+ /** */
+ virtual void displaySettings( );
+ /** */
+ virtual bool validateData( );
+ /** */
+ virtual void applySettings( );
+ /** */
+ virtual void displayDefaults( );
+
+private:
+ QCheckBox* m_pDirect;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmoutputdevice.cpp b/kpovmodeler/pmoutputdevice.cpp
new file mode 100644
index 00000000..5feb8ec2
--- /dev/null
+++ b/kpovmodeler/pmoutputdevice.cpp
@@ -0,0 +1,203 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmoutputdevice.h"
+#include "pmpovrayformat.h"
+#include <qtextstream.h>
+#include <klocale.h>
+
+unsigned int PMOutputDevice::s_indentOffset = 3;
+bool PMOutputDevice::s_bracketBehindType = true;
+
+PMOutputDevice::PMOutputDevice( QIODevice* dev, PMPovrayFormat* format )
+ : PMSerializer( dev ), m_stream( dev )
+{
+ m_pFormat = format;
+ m_indentation = 0;
+ m_lastWasComment = false;
+ m_pendingNewLine = false;
+ m_objectSeparation = false;
+}
+
+PMOutputDevice::~PMOutputDevice( )
+{
+}
+
+QString PMOutputDevice::description( ) const
+{
+ return QString( "POV-Ray" );
+}
+
+void PMOutputDevice::callSerialization( const PMObject* o, const PMMetaObject* mo )
+{
+ if( !mo )
+ return;
+
+ const PMPovraySerializeMethodInfo* info =
+ m_pFormat->serializationMethod( mo->className( ) );
+
+ if( info )
+ info->call( o, mo, this );
+ else
+ {
+ if( mo == o->metaObject( ) )
+ {
+ printError( i18n( "The object \"%1\" doesn't support %2." )
+ .arg( o->description( ) ).arg( description( ) ) );
+ }
+ else
+ {
+ printError( i18n( "The class \"%1\" doesn't support %2." )
+ .arg( o->description( ) ).arg( mo->className( ) ) );
+ }
+ }
+}
+
+void PMOutputDevice::serialize( PMObject* o )
+{
+ callSerialization( o, o->metaObject( ) );
+}
+
+void PMOutputDevice::close( )
+{
+// m_stream << ( char ) 0;
+}
+
+void PMOutputDevice::objectBegin( const QString& type )
+{
+ if( m_pendingNewLine )
+ newLine( );
+ if( m_objectSeparation )
+ newLine( );
+ m_stream << type;
+ if( s_bracketBehindType )
+ m_stream << " ";
+ else
+ newLine( );
+
+ m_stream << "{";
+ m_indentation++;
+ m_indentString.fill( ' ', s_indentOffset * m_indentation );
+ m_pendingNewLine = true;
+ m_objectSeparation = false;
+}
+
+void PMOutputDevice::declareBegin( const QString& id )
+{
+ if( m_pendingNewLine )
+ newLine( );
+ if( m_objectSeparation )
+ newLine( );
+ m_stream << "#declare " << id << " = ";
+
+ m_objectSeparation = false;
+}
+
+void PMOutputDevice::objectEnd( )
+{
+ m_indentation--;
+ m_indentString.fill( ' ', s_indentOffset * m_indentation );
+ newLine( );
+ m_stream << "}";
+ m_pendingNewLine = true;
+ m_objectSeparation = true;
+}
+
+void PMOutputDevice::writeLine( const QString& str )
+{
+ if( m_pendingNewLine )
+ newLine( );
+ m_stream << str;
+ m_pendingNewLine = true;
+ m_objectSeparation = true;
+}
+
+void PMOutputDevice::write( const QString& str )
+{
+ if( m_pendingNewLine )
+ newLine( );
+ m_stream << str;
+ m_objectSeparation = false;
+}
+
+void PMOutputDevice::newLine( )
+{
+ m_lastWasComment = false;
+ m_pendingNewLine = false;
+ m_stream << '\n' << m_indentString;
+}
+
+void PMOutputDevice::writeComment( const QString& text )
+{
+ QString s( text );
+ QTextStream str( &s, IO_ReadOnly );
+
+ bool lwc = m_lastWasComment;
+ if( m_pendingNewLine )
+ newLine( );
+ if( lwc )
+ newLine( );
+ if( m_objectSeparation )
+ newLine( );
+ if( str.atEnd( ) )
+ writeLine( "//" );
+ else
+ while( !str.atEnd( ) )
+ writeLine( QString( "// " ) + str.readLine( ) );
+ m_lastWasComment = true;
+ m_objectSeparation = false;
+}
+
+void PMOutputDevice::writeSemicolon( )
+{
+ // does not change m_pendingNewLine!
+ m_stream << ';';
+}
+
+void PMOutputDevice::writeName( const QString& name )
+{
+ if( !name.isEmpty( ) )
+ writeLine( QString( "//*PMName " ) + name );
+}
+
+QString PMOutputDevice::escapeAndQuoteString( const QString& s )
+{
+ QString result = "\"";
+ QString tmp = s;
+ QTextStream stream( &tmp, IO_ReadOnly );
+ QChar current, last;
+
+ while( !stream.atEnd( ) )
+ {
+ stream >> current ;
+ // not escaped quotation mark
+ if( ( current == '"' ) && ( last != '\\' ) )
+ result += '\\';
+ result += current;
+ // correctly quoted backslash
+ if( ( last == '\\' ) && ( current == '\\' ) )
+ current = QChar( 0 ); // clear the last char
+ last = current;
+ }
+ // backslash at the end
+ if( last == '\\' )
+ result += '\\';
+ result += '"';
+
+ return result;
+}
diff --git a/kpovmodeler/pmoutputdevice.h b/kpovmodeler/pmoutputdevice.h
new file mode 100644
index 00000000..25b3c58b
--- /dev/null
+++ b/kpovmodeler/pmoutputdevice.h
@@ -0,0 +1,159 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMOUTPUTDEVICE_H
+#define PMOUTPUTDEVICE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmserializer.h"
+
+#include <qstring.h>
+
+class QTextStream;
+class PMPovrayFormat;
+
+/**
+ * Output class for povray code.
+ *
+ * The class @ref PMPovrayFormat or a base class has factory methods
+ * to create an instance of this class. The output device uses the
+ * registered serialization methods of this povray format to serialize
+ * objects.
+ *
+ * This class handles the indentation and position of brackets
+ */
+
+class PMOutputDevice : public PMSerializer
+{
+public:
+ /**
+ * Creates an PMOutputDevice that serializes the povray code
+ * to the device
+ */
+ PMOutputDevice( QIODevice* dev, PMPovrayFormat* format );
+ /** */
+ virtual ~PMOutputDevice( );
+
+ /** */
+ virtual QString description( ) const;
+ /** */
+ virtual void serialize( PMObject* o );
+ /** */
+ virtual void close( );
+
+ /**
+ * Writes the povray object type, an open bracket to the text stream
+ * and indents the next lines
+ */
+ void objectBegin( const QString& type );
+ /**
+ * Begins a declare with the identifier id
+ */
+ void declareBegin( const QString& id );
+ /**
+ * Writes an closing bracket to the text stream
+ * and decreases the indentation
+ */
+ void objectEnd( );
+ /**
+ * Writes a single line to the text stream. Don't include
+ * newlines in the string or indentation will not work properly.
+ *
+ * Adds a newline before the string.
+ */
+ void writeLine( const QString& str );
+ /**
+ * Writes the string to the text stream
+ */
+ void write( const QString& str );
+ /**
+ * Writes a new line to the text stream and indents the next line.
+ */
+ void newLine( );
+ /**
+ * Writes a comment string to the text stream
+ */
+ void writeComment( const QString& text );
+ /**
+ * Writes a semicolon after a call to objectEnd( )
+ */
+ void writeSemicolon( );
+ /**
+ * Writes a special name comment to the text stream, if the
+ * name is not empty
+ */
+ void writeName( const QString& name );
+
+ /**
+ * Returns the basic indentation offset
+ */
+ static unsigned int indentationOffset( ) { return s_indentOffset; }
+ /**
+ * Sets the basic indentation offset
+ */
+ static void setIndentationOffset( unsigned int offset )
+ { s_indentOffset = offset; }
+
+ /**
+ * If set to true, the open bracket after an object begin will be
+ * written behind the object type, otherwise in a new line.
+ */
+ static void setBracketBehindType( bool yes ) { s_bracketBehindType = yes; }
+ /**
+ * Returns true if the open bracket after an object begin will be
+ * written behind the object type
+ */
+ static bool bracketBehindType( ) { return s_bracketBehindType; }
+
+ /**
+ * Correctly escapes the string and puts quotation marks at the begin
+ * and end of the string.
+ *
+ * Escapes only not escaped characters. "\"" and "\\" in the string
+ * are not escaped.
+ */
+ static QString escapeAndQuoteString( const QString& s );
+
+ /**
+ * Calls the serialization method for the object o and class
+ * given by the meta object.
+ *
+ * If no method for this class was registered in the corresponding
+ * @ref PMPovrayFormat, an error is added the message list.
+ */
+ void callSerialization( const PMObject* o, const PMMetaObject* mo );
+
+private:
+ static unsigned int s_indentOffset;
+ static bool s_bracketBehindType;
+
+ PMPovrayFormat* m_pFormat;
+ unsigned int m_indentation;
+ QString m_indentString;
+ QTextStream m_stream;
+ bool m_lastWasComment;
+ bool m_pendingNewLine;
+ bool m_objectSeparation;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmpalettevalue.cpp b/kpovmodeler/pmpalettevalue.cpp
new file mode 100644
index 00000000..f2b26fff
--- /dev/null
+++ b/kpovmodeler/pmpalettevalue.cpp
@@ -0,0 +1,81 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmpalettevalue.h"
+
+PMPaletteValue::PMPaletteValue( )
+{
+ m_index = 0;
+ m_value = 0.0;
+}
+
+PMPaletteValue::PMPaletteValue( int idx, double value )
+{
+ m_index = idx;
+ m_value = value;
+}
+
+void PMPaletteValue::setIndex( int idx )
+{
+ m_index = idx;
+}
+
+void PMPaletteValue::setValue( double value )
+{
+ m_value = value;
+}
+
+void PMPaletteValue::serialize( QDomElement& e, QDomDocument& /* doc */ ) const
+{
+ e.setAttribute( "index", m_index );
+ e.setAttribute( "value", m_value );
+}
+
+void PMPaletteValue::readAttributes( const QDomElement& h )
+{
+ QString str;
+ bool ok;
+
+ str = h.attribute( "index" );
+ if( str.isNull( ) )
+ m_index = 0;
+ else
+ {
+ m_index = str.toInt( &ok );
+ if( !ok ) m_index = 0;
+ }
+
+ str = h.attribute( "value" );
+ if( str.isNull( ) )
+ m_value = 0;
+ else
+ {
+ m_value = str.toDouble( &ok );
+ if( !ok ) m_value = 0;
+ }
+}
+
+bool PMPaletteValue::operator==( const PMPaletteValue& p ) const
+{
+ return ( m_index == p.m_index && m_value == p.m_value );
+}
+
+bool PMPaletteValue::operator!=( const PMPaletteValue& p ) const
+{
+ return ( m_index != p.m_index || m_value != p.m_value );
+}
diff --git a/kpovmodeler/pmpalettevalue.h b/kpovmodeler/pmpalettevalue.h
new file mode 100644
index 00000000..05f9712a
--- /dev/null
+++ b/kpovmodeler/pmpalettevalue.h
@@ -0,0 +1,78 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPALETTEVALUE_H
+#define PMPALETTEVALUE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmnamedobject.h"
+
+/**
+ * Class for pallete values used for filter and transmit in image maps.
+ */
+class PMPaletteValue
+{
+public:
+ /** */
+ PMPaletteValue();
+ /** */
+ PMPaletteValue( int idx, double value );
+ /**
+ * Returns the index of the palette entry.
+ */
+ int index( ) const { return m_index; }
+ /**
+ * Returns the value of the palette entry.
+ */
+ double value( ) const { return m_value; }
+ /**
+ * Sets the index of the palette entry.
+ */
+ void setIndex( int idx );
+ /**
+ * Sets the value of the palette entry.
+ */
+ void setValue( double val );
+ /**
+ * Serializes the palette entry into a XML document.
+ */
+ void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /**
+ * Reads the palette entry from a XML document.
+ */
+ void readAttributes( const QDomElement& h );
+
+ /**
+ * Returns true if both values have the same index and value
+ */
+ bool operator== ( const PMPaletteValue& p) const;
+ /**
+ * Returns false if both values have the same index and value
+ */
+ bool operator!= ( const PMPaletteValue& p) const;
+
+private:
+ int m_index;
+ double m_value;
+};
+
+#endif
diff --git a/kpovmodeler/pmpalettevalueedit.cpp b/kpovmodeler/pmpalettevalueedit.cpp
new file mode 100644
index 00000000..ae6ea653
--- /dev/null
+++ b/kpovmodeler/pmpalettevalueedit.cpp
@@ -0,0 +1,99 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Passos Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmpalettevalueedit.h"
+#include "pmpalettevalue.h"
+#include "pmlineedits.h"
+#include "pmdebug.h"
+
+#include <qwidget.h>
+#include <qlayout.h>
+#include <qcombobox.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+#include <qpushbutton.h>
+#include <qtooltip.h>
+#include <ktabctl.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdialog.h>
+#include <kfiledialog.h>
+
+PMPaletteValueEdit::PMPaletteValueEdit( QWidget* parent, const char* name )
+ : QWidget( parent, name )
+{
+ QLabel* lbl;
+ QHBoxLayout* layout;
+
+ m_pIndexEdit = new PMIntEdit( this );
+ m_pValueEdit = new PMFloatEdit( this );
+
+ layout = new QHBoxLayout( this );
+ lbl = new QLabel( i18n( "Index" ), this );
+ layout->addWidget( lbl );
+ layout->addSpacing( KDialog::spacingHint( ) );
+ layout->addWidget( m_pIndexEdit );
+ layout->addSpacing( KDialog::spacingHint( ) );
+ lbl = new QLabel( i18n( "Value" ), this );
+ layout->addWidget( lbl );
+ layout->addSpacing( KDialog::spacingHint( ) );
+ layout->addWidget( m_pValueEdit );
+
+ connect( m_pIndexEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pValueEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMPaletteValueEdit::setIndex( int idx )
+{
+ m_pIndexEdit->setValue( idx );
+}
+
+void PMPaletteValueEdit::setValue( double val )
+{
+ m_pValueEdit->setValue( val );
+}
+
+int PMPaletteValueEdit::index( )
+{
+ return m_pIndexEdit->value( );
+}
+
+double PMPaletteValueEdit::value( )
+{
+ return m_pValueEdit->value( );
+}
+
+void PMPaletteValueEdit::setReadOnly( bool yes )
+{
+ m_pIndexEdit->setReadOnly( yes );
+ m_pValueEdit->setReadOnly( yes );
+}
+
+void PMPaletteValueEdit::setEnabled( bool yes )
+{
+ m_pIndexEdit->setEnabled( yes );
+ m_pValueEdit->setEnabled( yes );
+}
+
+bool PMPaletteValueEdit::isDataValid( )
+{
+ return ( m_pIndexEdit->isDataValid( ) && m_pValueEdit->isDataValid( ) );
+}
+
+#include "pmpalettevalueedit.moc"
diff --git a/kpovmodeler/pmpalettevalueedit.h b/kpovmodeler/pmpalettevalueedit.h
new file mode 100644
index 00000000..c5795cd9
--- /dev/null
+++ b/kpovmodeler/pmpalettevalueedit.h
@@ -0,0 +1,67 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Passos Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPALETTEVALUEEDIT_H
+#define PMPALETTEVALUEEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdialogeditbase.h"
+
+class PMFloatEdit;
+class PMIntEdit;
+
+/**
+ * Dialog edit class for @ref PMPaletteValue.
+ */
+class PMPaletteValueEdit: public QWidget
+{
+ Q_OBJECT
+public:
+ /** */
+ PMPaletteValueEdit( QWidget* parent, const char* name = 0 );
+ /** */
+ void setIndex( int idx );
+ /** */
+ int index( );
+ /** */
+ void setValue( double val );
+ /** */
+ double value( );
+ /**
+ * Returns true is both fields are valid numbers
+ */
+ bool isDataValid( );
+ /** */
+ void setReadOnly( bool yes = true );
+ /** */
+ virtual void setEnabled( bool yes );
+
+signals:
+ /** */
+ void dataChanged( );
+
+private:
+ PMIntEdit* m_pIndexEdit;
+ PMFloatEdit* m_pValueEdit;
+};
+
+#endif
diff --git a/kpovmodeler/pmpalettevaluememento.cpp b/kpovmodeler/pmpalettevaluememento.cpp
new file mode 100644
index 00000000..6db9b922
--- /dev/null
+++ b/kpovmodeler/pmpalettevaluememento.cpp
@@ -0,0 +1,84 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Passos Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#include "pmpalettevaluememento.h"
+#include "pmdebug.h"
+
+PMPaletteValueMemento::PMPaletteValueMemento( PMObject* originator )
+ : PMMemento( originator )
+{
+ m_bFilterPaletteValuesSaved = false;
+ m_bTransmitPaletteValuesSaved = false;
+}
+
+PMPaletteValueMemento::~PMPaletteValueMemento( )
+{
+}
+
+void PMPaletteValueMemento::setFilterPaletteValues( const QValueList<PMPaletteValue>& v )
+{
+ if( !m_bFilterPaletteValuesSaved )
+ {
+ // Direct assignment does not work with Qt 2.3.x
+ // The list will be changed later in a graphical
+ // change because QValueList::detach( ) is called
+ // too late!
+ // Copy the list by hand.
+
+ QValueList<PMPaletteValue>::ConstIterator it = v.begin( );
+ for( ; it != v.end( ); ++it )
+ m_filterPaletteValues.append( *it );
+
+ m_bFilterPaletteValuesSaved = true;
+ addChange( PMCData );
+ }
+}
+
+QValueList<PMPaletteValue> PMPaletteValueMemento::filterPaletteValues( ) const
+{
+ if( !m_bFilterPaletteValuesSaved )
+ kdError( PMArea ) << "Filter palette values not saved in PMPaletteValueMemento::filterPaletteValues\n";
+
+ return m_filterPaletteValues;
+}
+
+void PMPaletteValueMemento::setTransmitPaletteValues( const QValueList<PMPaletteValue>& v )
+{
+ if( !m_bTransmitPaletteValuesSaved )
+ {
+ // Direct assignment does not work with Qt 2.3.x
+ // The list will be changed later in a graphical
+ // change because QValueList::detach( ) is called
+ // too late!
+ // Copy the list by hand.
+
+ QValueList<PMPaletteValue>::ConstIterator it = v.begin( );
+ for( ; it != v.end( ); ++it )
+ m_transmitPaletteValues.append( *it );
+
+ m_bTransmitPaletteValuesSaved = true;
+ addChange( PMCData );
+ }
+}
+
+QValueList<PMPaletteValue> PMPaletteValueMemento::transmitPaletteValues( ) const
+{
+ if( !m_bTransmitPaletteValuesSaved )
+ kdError( PMArea ) << "Transmit palette values not saved in PMPaletteValueMemento::transmitPaletteValues\n";
+
+ return m_transmitPaletteValues;
+}
diff --git a/kpovmodeler/pmpalettevaluememento.h b/kpovmodeler/pmpalettevaluememento.h
new file mode 100644
index 00000000..0ac1242e
--- /dev/null
+++ b/kpovmodeler/pmpalettevaluememento.h
@@ -0,0 +1,85 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Passos Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPALETTEVALUEMEMENTO_H
+#define PMPALETTEVALUEMEMENTO_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmmemento.h"
+#include "pmpalettevalue.h"
+#include <qvaluelist.h>
+
+
+/**
+ * Memento for @ref PMImageMap
+ */
+class PMPaletteValueMemento : public PMMemento
+{
+public:
+ /**
+ * Creates a memento for the object originator
+ */
+ PMPaletteValueMemento( PMObject* originator );
+ /**
+ * Deletes the memento
+ */
+ virtual ~PMPaletteValueMemento( );
+
+ /**
+ * Saves the filter palette values
+ */
+ void setFilterPaletteValues( const QValueList<PMPaletteValue>& v );
+ /**
+ * Returns the filter palette values
+ */
+ QValueList<PMPaletteValue> filterPaletteValues( ) const;
+ /**
+ * Returns true if the filter palette values were saved
+ */
+ bool filterPaletteValuesSaved( ) const { return m_bFilterPaletteValuesSaved; }
+ /**
+ * Saves the transmit palette values
+ */
+ void setTransmitPaletteValues( const QValueList<PMPaletteValue>& v );
+ /**
+ * Returns the transmit palette values
+ */
+ QValueList<PMPaletteValue> transmitPaletteValues( ) const;
+ /**
+ * Returns true if the transmit palette values were saved
+ */
+ bool transmitPaletteValuesSaved( ) const { return m_bTransmitPaletteValuesSaved; }
+
+private:
+ /**
+ * The stored values for filter
+ */
+ QValueList<PMPaletteValue> m_filterPaletteValues;
+ bool m_bFilterPaletteValuesSaved;
+ /**
+ * The stored values for transmit
+ */
+ QValueList<PMPaletteValue> m_transmitPaletteValues;
+ bool m_bTransmitPaletteValuesSaved;
+};
+
+#endif
diff --git a/kpovmodeler/pmparser.cpp b/kpovmodeler/pmparser.cpp
new file mode 100644
index 00000000..7a252c88
--- /dev/null
+++ b/kpovmodeler/pmparser.cpp
@@ -0,0 +1,433 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmparser.h"
+
+#include <qstring.h>
+#include <qbuffer.h>
+#include <klocale.h>
+
+#include "pmpart.h"
+#include "pmdeclare.h"
+#include "pmerrorflags.h"
+#include "pmrecursiveobjectiterator.h"
+#include "pmdebug.h"
+
+unsigned int PMParser::s_maxErrors = 30;
+unsigned int PMParser::s_maxWarnings = 50;
+
+
+PMParser::PMParser( PMPart* part, QIODevice* dev )
+ : m_okDeclares( 101 )
+{
+ m_pPart = part;
+ m_pDevice = dev;
+ m_bDeviceCreated = false;
+
+ init( );
+}
+
+PMParser::PMParser( PMPart* part, const QByteArray& array )
+ : m_okDeclares( 101 )
+{
+ m_pPart = part;
+ QBuffer* buffer = new QBuffer( array );
+ buffer->open( IO_ReadOnly );
+ m_pDevice = buffer;
+ m_bDeviceCreated = true;
+
+ init( );
+}
+
+void PMParser::init( )
+{
+ m_okDeclares.setAutoDelete( true );
+ m_pLocalST.setAutoDelete( true );
+
+ m_lineNum = -1;
+ m_pResultList = 0;
+ m_errors = 0;
+ m_warnings = 0;
+ m_bFatalError = false;
+ m_shownMessages = 0;
+ m_messages.clear( );
+
+ m_pTopParent = 0;
+ m_renamedObjectSymbols.clear( );
+ m_okDeclares.clear( );
+ m_pNextCheckDeclare = 0;
+}
+
+PMParser::~PMParser( )
+{
+ if( m_bDeviceCreated )
+ delete m_pDevice;
+}
+
+void PMParser::printMessage( const PMPMessage messageNum )
+{
+ if( !( m_shownMessages & messageNum ) )
+ {
+ m_shownMessages |= messageNum;
+
+ switch( messageNum )
+ {
+ case PMMClockDefault:
+ printWarning( i18n( "Using the default value of 0.0 for clock" ) );
+ break;
+ case PMMClockDeltaDefault:
+ printWarning( i18n( "Using the default value of 1.0 for clock_delta" ) );
+ break;
+ case PMMSpecialRawComment:
+ m_messages += PMMessage( i18n( "Note: The full povray syntax is not supported yet. "
+ "If you want to add unsupported povray code to the "
+ "scene, you can put this code between the two "
+ "special comments \"//*PMRawBegin\" and "
+ "\"//*PMRawEnd\"." ) );
+ break;
+ }
+ }
+}
+
+void PMParser::printMessage( const QString& type, const QString& msg )
+{
+ if( m_lineNum >= 0 )
+ m_messages += PMMessage( i18n( "Line %1: " ).arg( m_lineNum ) + type + ": " + msg );
+ else
+ m_messages += PMMessage( type + ": " + msg );
+}
+
+void PMParser::printError( const QString& msg )
+{
+ if( m_errors < s_maxErrors )
+ {
+ printMessage( i18n( "Error" ), msg );
+ m_errors++;
+ }
+ else if( m_errors == s_maxErrors )
+ {
+ m_messages += PMMessage( i18n( "Maximum of %1 errors reached." )
+ .arg( s_maxErrors ) );
+ m_errors++;
+ }
+}
+
+void PMParser::printWarning( const QString& msg )
+{
+ if( m_warnings < s_maxWarnings )
+ {
+ printMessage( i18n( "Warning" ), msg );
+ m_warnings++;
+ }
+ else if( m_warnings == s_maxWarnings )
+ {
+ m_messages += PMMessage( i18n( "Maximum of %1 warnings reached." )
+ .arg( s_maxWarnings ) );
+ m_warnings++;
+ }
+}
+
+void PMParser::printExpected( const char c, const char* sValue )
+{
+ printError( i18n( "'%1' expected, found token '%2' instead." )
+ .arg( c ).arg( sValue ) );
+}
+
+void PMParser::printExpected( const QString& str, const char* sValue )
+{
+ printError( i18n( "'%1' expected, found token '%2' instead." )
+ .arg( str ).arg( sValue ) );
+}
+
+void PMParser::printUnexpected( const QString& str )
+{
+ printError( i18n( "Unexpected token '%1'." ).arg( str ) );
+}
+
+void PMParser::printInfo( const QString& msg )
+{
+ printMessage( i18n( "Info" ), msg );
+}
+
+int PMParser::errorFlags( ) const
+{
+ int result = 0;
+ if( errors( ) )
+ result |= PMEError;
+ if( warnings( ) )
+ result |= PMEWarning;
+ if( fatal( ) )
+ result |= PMEFatal;
+ return result;
+}
+
+
+void PMParser::parse( PMObjectList* list, PMObject* parent,
+ PMObject* after )
+{
+ m_pResultList = list;
+ m_pTopParent = parent;
+ m_pAfter = after;
+
+ // find first item, that can be a declare and can be used as link
+ // for parsed objects.
+ if( parent )
+ {
+ if( parent->type( ) == "Scene" )
+ {
+ if( after )
+ m_pNextCheckDeclare = after;
+ else
+ m_pNextCheckDeclare = 0;
+ }
+ else
+ {
+ PMObject* obj = parent;
+ bool stop = false;
+
+ // go to parents, until the parent is the scene
+ // (declares can only be inserted as top level objects)
+ do
+ {
+ if( obj->parent( ) )
+ {
+ if( obj->parent( )->type( ) == "Scene" )
+ stop = true;
+ else
+ obj = obj->parent( );
+ }
+ else
+ {
+ obj = 0;
+ stop = true;
+ }
+ }
+ while( obj && !stop );
+
+ // now obj is the top level parent of the object, where parsed objects
+ // will be inserted
+ if( obj )
+ m_pNextCheckDeclare = obj->prevSibling( );
+ else
+ m_pNextCheckDeclare = 0;
+ }
+ }
+
+ topParse( );
+
+ QPtrListIterator<PMSymbol> it( m_renamedObjectSymbols );
+ for( ; it.current( ); ++it )
+ it.current( )->setRenamedSymbol( 0 );
+ m_renamedObjectSymbols.clear( );
+ m_pLocalST.clear( );
+
+ if( ( errors( ) || warnings( ) ) && m_pResultList->isEmpty( ) )
+ setFatalError( );
+}
+
+bool PMParser::insertChild( PMObject* child, PMObject* parent )
+{
+ bool inserted = false;
+
+ if( parent )
+ {
+ if( parent->canInsert( child, parent->lastChild( ) ) )
+ {
+ parent->appendChild( child );
+ inserted = true;
+ }
+ else
+ {
+ printError( i18n( "Can't insert %1 into %2." )
+ .arg( child->description( ) )
+ .arg( parent->description( ) ) );
+ }
+ }
+ else
+ {
+ if( m_pTopParent )
+ {
+ if( m_pTopParent->canInsert( child, m_pAfter, m_pResultList ) )
+ {
+ m_pResultList->append( child );
+ inserted = true;
+ }
+ else
+ {
+ printError( i18n( "Can't insert %1 into %2." )
+ .arg( child->description( ) )
+ .arg( m_pTopParent->description( ) ) );
+ }
+ }
+ else
+ {
+ // these lines should not be executed
+ // m_pTopParent may not be null
+ m_pResultList->append( child );
+ inserted = true;
+ }
+ }
+
+ if( !inserted )
+ {
+ // insert error
+ // remove all links
+ PMRecursiveObjectIterator rit( child );
+ PMDeclare* decl = 0;
+
+ for( ; rit.current( ); ++rit )
+ {
+ decl = rit.current( )->linkedObject( );
+ if( decl )
+ decl->removeLinkedObject( rit.current( ) );
+ }
+ }
+
+ return inserted;
+}
+
+void PMParser::checkID( PMDeclare* decl )
+{
+ PMSymbolTable* st = m_pPart->symbolTable( );
+ PMSymbol* s = m_pLocalST.find( decl->id( ) );
+ if( !s )
+ s = st->find( decl->id( ) );
+
+ if( s )
+ {
+ PMSymbol* newSym = st->findNewID( s->id( ) + "_", decl );
+ s->setRenamedSymbol( newSym );
+ // Symbol can be inserted multiple times
+ // Faster than searching for s and inserting s
+ // if the list does not contain it.
+ m_renamedObjectSymbols.append( s );
+
+ if( m_pTopParent )
+ m_pLocalST.insert( decl->id( ), newSym ); // paste/drop
+ else
+ st->insert( decl->id( ), newSym ); // load file
+ }
+ else
+ {
+ s = new PMSymbol( decl->id( ), decl );
+ if( m_pTopParent )
+ m_pLocalST.insert( decl->id( ), s ); // paste/drop
+ else
+ st->insert( decl->id( ), s ); // load file
+ m_okDeclares.insert( decl->id( ), new bool( true ) );
+ }
+}
+
+void PMParser::checkID( const QString& id, const PMValue& v )
+{
+ PMSymbolTable* st = m_pPart->symbolTable( );
+ PMSymbol* s = m_pLocalST.find( id );
+
+ if( s )
+ {
+ PMSymbol* newSym = new PMSymbol( st->findNewID( id + "_" ), v );
+ s->setRenamedSymbol( newSym );
+ // Symbol can be inserted multiple times
+ // Faster than searching for s and inserting s
+ // if the list does not contain it.
+ m_renamedObjectSymbols.append( s );
+
+ if( m_pTopParent )
+ m_pLocalST.insert( id, newSym ); // paste/drop
+
+ // values are never inserted into the parts symbol table
+ // else
+ // st->insert( decl->id( ), newSym ); // load file
+ }
+ else
+ {
+ s = new PMSymbol( id, v );
+ if( m_pTopParent )
+ m_pLocalST.insert( id, s ); // paste/drop
+
+ // values are never inserted into the parts symbol table
+ // else
+ // st->insert( decl->id( ), s ); // load file
+
+ m_okDeclares.insert( id, new bool( true ) );
+ }
+}
+
+PMDeclare* PMParser::checkLink( const QString& id )
+{
+ PMSymbolTable* t = m_pPart->symbolTable( );
+ bool ok = false;
+
+ // is object declared?
+ PMSymbol* s = m_pLocalST.find( id );
+ if( !s )
+ s = t->find( id );
+
+ if( !s )
+ printError( i18n( "Undefined object \"%1\"." ).arg( id ) );
+ else if( s->type( ) != PMSymbol::Object )
+ printError( i18n( "Undefined object \"%1\"." ).arg( id ) );
+ else
+ {
+ // the object is declared
+ // is the id already in m_okDeclares
+ bool* lok = m_okDeclares.find( id );
+ if( lok )
+ ok = true;
+ else
+ {
+ // the id is not in m_okDeclares
+ PMObject* obj = s->object( );
+ while( m_pNextCheckDeclare && !ok )
+ {
+ if( m_pNextCheckDeclare->isA( "Declare" ) )
+ {
+ PMDeclare* decl = ( PMDeclare* ) m_pNextCheckDeclare;
+ m_okDeclares.insert( decl->id( ), new bool( true ) );
+ }
+ if( m_pNextCheckDeclare == obj )
+ ok = true;
+
+ m_pNextCheckDeclare = m_pNextCheckDeclare->prevSibling( );
+ }
+ }
+
+ if( !ok )
+ printError( i18n( "Object \"%1\" is undefined at that point." )
+ .arg( id ) );
+ }
+
+ if( ok )
+ {
+ while( s->renamedSymbol( ) )
+ s = s->renamedSymbol( );
+
+ return s->object( );
+ }
+
+ return 0;
+}
+
+PMSymbol* PMParser::getSymbol( const QString& id ) const
+{
+ PMSymbol* s = m_pLocalST.find( id );
+ if( !s )
+ s = m_pPart->symbolTable( )->find( id );
+ return s;
+}
+
diff --git a/kpovmodeler/pmparser.h b/kpovmodeler/pmparser.h
new file mode 100644
index 00000000..48250798
--- /dev/null
+++ b/kpovmodeler/pmparser.h
@@ -0,0 +1,299 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPARSER_H
+#define PMPARSER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kurl.h>
+#include <qcstring.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qvaluelist.h>
+#include <qptrdict.h>
+#include <qptrlist.h>
+
+#include "pmobject.h"
+#include "pmsymboltable.h"
+#include "pmvalue.h"
+#include "pmerrordialog.h"
+
+class QTextStream;
+class QIODevice;
+
+class PMScanner;
+class PMPart;
+class PMSymbolTable;
+
+enum PMPMessage { PMMClockDefault = 1, PMMClockDeltaDefault = 2,
+ PMMSpecialRawComment = 4 };
+
+/**
+ * Base class for kpovmodeler parsers.
+ */
+class PMParser
+{
+public:
+ /**
+ * Parser that parses the device
+ */
+ PMParser( PMPart* part, QIODevice* device );
+ /**
+ * Parser that parses the byte array
+ */
+ PMParser( PMPart* part, const QByteArray& array );
+ /**
+ * Deletes the parser
+ */
+ virtual ~PMParser( );
+
+ /**
+ * Quickly scans the top level objects. Appends all top level object
+ * types to the list.
+ */
+ virtual void quickParse( QStringList& /*list*/ ) { };
+ /**
+ * Returns true, if the parser can quickly scan the top level objects.
+ */
+ virtual bool canQuickParse( ) const { return false; }
+
+ /**
+ * Parses the device.
+ *
+ * Appends all parsed objects to the list.
+ *
+ * parent is the object where the parsed objects will be inserted as
+ * children behind the object after. These parameters are used to check
+ * the consistency of declares and links.
+ *
+ * Set parent and after to 0 if and only if a document is parsed/opened.
+ */
+ void parse( PMObjectList* list, PMObject* parent,
+ PMObject* after );
+
+ /**
+ * Returns the messages of the parser
+ */
+ PMMessageList messages( ) const { return m_messages; }
+ /**
+ * Returns true if there were errors during parsing
+ */
+ bool errors( ) const { return m_errors > 0; }
+ /**
+ * Returns true if there were warnings during parsing
+ */
+ bool warnings( ) const { return m_warnings > 0; }
+ /**
+ * Returns true, if a fatal error occurred or no object could be
+ * successfully parsed and it doesn't make sense to continue
+ */
+ bool fatal( ) const { return m_bFatalError; }
+ /**
+ * Returns a bitwise combination of @ref PMErrorFlags constants
+ */
+ int errorFlags( ) const;
+
+ /**
+ * returns the maximum number of errors
+ */
+ static unsigned maxErrors( ) { return s_maxErrors; }
+ /**
+ * sets the maximum number of errors to m
+ */
+ static void setMaxErrors( unsigned m ) { s_maxErrors = m; }
+ /**
+ * returns the maximum number of warnings
+ */
+ static unsigned maxWarnings( ) { return s_maxWarnings; }
+ /**
+ * sets the maximum number of warnings to m
+ */
+ static void setMaxWarnings( unsigned m ) { s_maxWarnings = m; }
+
+ /**
+ * Adds an error to the message string
+ */
+ void printError( const QString& msg );
+ /**
+ * Adds the error "'<str>' expected, found <token> instead" to the message string
+ */
+ void printExpected( const QString& str, const char* token );
+ /**
+ * Adds the error "'<c>' expected" to the message string
+ */
+ void printExpected( const char c, const char* token );
+ /**
+ * Adds the error "Unexpected token '<str>', found <token> instead" to the message string
+ */
+ void printUnexpected( const QString& str );
+ /**
+ * Adds a warning to the message string
+ */
+ void printWarning( const QString& msg );
+ /**
+ * Adds an info to the message string
+ */
+ void printInfo( const QString& msg );
+ /**
+ * Adds the message to the message string. Type is "error", "warning",
+ * "info" or "scanner error"
+ */
+ void printMessage( const QString& type, const QString& msg );
+ /**
+ * Prints a messages that should only reported once
+ */
+ void printMessage( const PMPMessage messageNum );
+
+ /**
+ * Sets the fatal error flag
+ */
+ void setFatalError( ) { m_bFatalError = true; }
+
+ /**
+ * Sets the current line number
+ */
+ void setCurrentLine( int lineNumber ) { m_lineNum = lineNumber; }
+
+ /**
+ * Returns the declare object with id, if it exists and is declared at
+ * the current parse position, otherwise 0
+ */
+ PMDeclare* checkLink( const QString& id );
+ /**
+ * Checks the id of the declare. If there is already a declare with
+ * the same id, the id of the object is renamed.
+ *
+ * Inserts the object into the symbol table.*/
+ void checkID( PMDeclare* obj );
+ /**
+ * Checks the id of the value declare (constant, vector or color).
+ * If there is already a declare with
+ * the same id, the id of the value is renamed.
+ *
+ * Inserts the object into the symbol table.*/
+ void checkID( const QString& id, const PMValue& v );
+ /**
+ * Returns the symbol with id id or 0 if the id is undeclared
+ */
+ PMSymbol* getSymbol( const QString& id ) const;
+ /**
+ * Tries to insert obj as child of parent. If parent is 0, the object
+ * will be inserted in the list of top level objects.
+ *
+ * Returns true if the object could be inserted.
+ */
+ bool insertChild( PMObject* obj, PMObject* parent );
+
+protected:
+ /**
+ * Top level parse function.
+ *
+ * Overwrite this function in a specific parser.
+ */
+ virtual void topParse( ) = 0;
+
+protected:
+ /**
+ * Pointer to the part
+ */
+ PMPart* m_pPart;
+ /**
+ * parent object where the parsed top level objects
+ * will be inserted _later_ (not from the parser) as children
+ */
+ const PMObject* m_pTopParent;
+ const PMObject* m_pAfter;
+ /**
+ * The list where the parsed objects are stored
+ */
+ PMObjectList* m_pResultList;
+ /**
+ * The QIODevice
+ */
+ QIODevice* m_pDevice;
+ /**
+ * True, if the device was created by the parser
+ */
+ bool m_bDeviceCreated;
+
+private:
+ /**
+ * Initializes the parser
+ */
+ void init( );
+
+ /**
+ * The parser output (errors, warnings...)
+ */
+ PMMessageList m_messages;
+ /**
+ * A dictionary object -> message
+ */
+ QPtrDict< QPtrList<PMMessage> > m_messageDict;
+ /**
+ * Number of warnings during parsing
+ */
+ unsigned int m_warnings;
+ /**
+ * Number of errors during parsing
+ */
+ unsigned int m_errors;
+ /**
+ * Flag for fatal errors
+ */
+ bool m_bFatalError;
+
+ /**
+ * maximum number of errors
+ */
+ static unsigned int s_maxErrors;
+ /**
+ * maximum number of warnings
+ */
+ static unsigned int s_maxWarnings;
+ /**
+ * Already shown warnings or errors, that are reported only once
+ */
+ int m_shownMessages;
+ /**
+ * The current line number
+ */
+ int m_lineNum;
+ /**
+ * List of renamed declares
+ */
+ QPtrList<PMSymbol> m_renamedObjectSymbols;
+ /**
+ * Dictionary of symbol names, that can be linked
+ */
+ QDict<bool> m_okDeclares;
+ PMObject* m_pNextCheckDeclare;
+ /**
+ * Symbol table used during parsing. The symbol table of the part
+ * will not be changed.
+ */
+ PMSymbolTable m_pLocalST;
+};
+
+
+
+#endif
diff --git a/kpovmodeler/pmpart.cpp b/kpovmodeler/pmpart.cpp
new file mode 100644
index 00000000..c87f4719
--- /dev/null
+++ b/kpovmodeler/pmpart.cpp
@@ -0,0 +1,2884 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+// include files for QT
+#include <qapplication.h>
+#include <qdir.h>
+#include <qstrlist.h>
+#include <qclipboard.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qmessagebox.h>
+#include <qcombobox.h>
+#include <qspinbox.h>
+#include <qlabel.h>
+#include <qdatetime.h>
+#include <qstringlist.h>
+
+// include files for KDE
+#include <kiconloader.h>
+#include <kconfig.h>
+#include <kstdaction.h>
+#include <kaction.h>
+#include <kmessagebox.h>
+#include <ktempfile.h>
+#include <kio/netaccess.h>
+#include <kstandarddirs.h>
+#include <kfilterdev.h>
+#include <kfiledialog.h>
+
+// application specific includes
+#include "pmpart.h"
+#include "pmshell.h"
+#include "pmview.h"
+#include "pmglview.h"
+#include "pmallcommands.h"
+#include "pmpovraywidget.h"
+#include "pmpovrayrenderwidget.h"
+
+#include "pmallobjects.h"
+#include "pmcommandmanager.h"
+#include "pmobjectdrag.h"
+#include "pmxmlparser.h"
+#include "pmpovrayparser.h"
+#include "pmerrordialog.h"
+#include "pmsettingsdialog.h"
+#include "pminserterrordialog.h"
+#include "pminsertpopup.h"
+
+#include "pmpovray35format.h"
+#include "pmserializer.h"
+
+#include "pmfactory.h"
+#include "pmdefaults.h"
+#include "pmsymboltable.h"
+
+#include "pmrendermodesdialog.h"
+#include "pmrendermode.h"
+#include "pmpovrayoutputwidget.h"
+#include "pmrendermanager.h"
+#include "pmdialogeditbase.h"
+#include "pmdocumentationmap.h"
+#include "pmlibrarymanager.h"
+#include "pmlibraryhandleedit.h"
+#include "pmlibraryobject.h"
+#include "pmlibrarybrowser.h"
+#include "pmlibraryobjectsearch.h"
+#include "pmscene.h"
+
+#include "pmpluginmanager.h"
+#include "pminsertrulesystem.h"
+#include "pmprototypemanager.h"
+#include "pmiomanager.h"
+
+#include "pmactions.h"
+#include "pmrecursiveobjectiterator.h"
+
+#include "pmerrorflags.h"
+
+#include "pmfiledialog.h"
+
+#ifdef PMEnableSimpleProfiling
+QTime PMDebugTime;
+#endif
+
+//#define KPM_WITH_OBJECT_LIBRARY
+
+PMPart::PMPart( QWidget* parentWidget, const char* widgetName,
+ QObject* parent, const char* name, bool readwrite,
+ PMShell* shell )
+ : DCOPObject( "PMPartIface" ),
+ KParts::ReadWritePart( parent, name ),
+ m_commandManager( this )
+{
+ setPluginLoadingMode( LoadPlugins );
+ setInstance( PMFactory::instance( ), false );
+ m_pExtension = new PMBrowserExtension( this );
+
+ m_pActiveObject = 0;
+ m_canDecode = false;
+ m_pScene = 0;
+ m_pNewSelection = 0;
+ m_sortedListUpToDate = false;
+ m_numAddedObjects = 0;
+ m_numInsertErrors = 0;
+ m_pSymbolTable = 0;
+ m_bCameraListUpToDate = true;
+ m_updateNewObjectActions = false;
+ m_pPovrayWidget = 0;
+ m_pView = 0;
+ m_pShell = shell;
+ m_controlPoints.setAutoDelete( true );
+ m_onlyCopyPaste = true;
+
+ // call inits to invoke all other construction parts
+ setReadWrite( readwrite );
+
+ if( isReadWrite( ) )
+ setXMLFile( "kpovmodelerui.rc" );
+ else
+ setXMLFile( "kpovmodelerbrowser.rc" );
+
+ m_pPrototypeManager = new PMPrototypeManager( this );
+ m_pInsertRuleSystem = new PMInsertRuleSystem( this );
+ m_pIOManager = new PMIOManager( this );
+ m_pInsertRuleSystem->loadRules( "baseinsertrules.xml" );
+
+ initActions( );
+ initDocument( );
+ initView( parentWidget, widgetName );
+
+ restoreConfig( instance( )->config( ) );
+
+ connect( qApp->clipboard( ), SIGNAL( dataChanged( ) ),
+ SLOT( slotClipboardDataChanged( ) ) );
+ slotClipboardDataChanged( );
+ connect( &m_commandManager, SIGNAL( updateUndoRedo( const QString&, const QString& ) ),
+ SLOT( slotUpdateUndoRedo( const QString&, const QString& ) ) );
+ connect( &m_commandManager, SIGNAL( objectChanged( PMObject*, const int, QObject* ) ),
+ SLOT( slotObjectChanged( PMObject*, const int, QObject* ) ) );
+ connect( &m_commandManager, SIGNAL( idChanged( PMObject*, const QString& ) ),
+ SLOT( slotIDChanged( PMObject*, const QString& ) ) );
+
+ PMPluginManager::theManager( )->registerPart( this );
+
+ emit refresh( );
+ slotObjectChanged( m_pScene, PMCNewSelection, this );
+}
+
+PMPart::PMPart( QWidget* /*parentWidget*/, const char* /*widgetName*/,
+ QObject* parent, const char* name, bool readwrite,
+ bool /*onlyCutPaste*/, PMShell* shell )
+ : DCOPObject( "LibraryBrowserIface" ),
+ KParts::ReadWritePart( parent, name ),
+ m_commandManager( this )
+{
+ setPluginLoadingMode( LoadPlugins );
+ setInstance( PMFactory::instance( ), false );
+
+ m_pActiveObject = 0;
+ m_canDecode = false;
+ m_pNewSelection = 0;
+ m_sortedListUpToDate = false;
+ m_numAddedObjects = 0;
+ m_numInsertErrors = 0;
+ m_pSymbolTable = 0;
+ m_bCameraListUpToDate = true;
+ m_updateNewObjectActions = false;
+ m_pPovrayWidget = 0;
+ m_pView = 0;
+ m_pShell = shell;
+ m_pScene = new PMScene( this );
+ m_onlyCopyPaste = true;
+
+ // call inits to invoke all other construction parts
+ setReadWrite( readwrite );
+
+ if( isReadWrite( ) )
+ setXMLFile( "kpovmodelerui.rc" );
+ else
+ setXMLFile( "kpovmodelerbrowser.rc" );
+
+ m_pPrototypeManager = new PMPrototypeManager( this );
+ m_pInsertRuleSystem = new PMInsertRuleSystem( this );
+ m_pIOManager = new PMIOManager( this );
+ m_pInsertRuleSystem->loadRules( "baseinsertrules.xml" );
+ m_pSymbolTable = new PMSymbolTable( );
+
+ initCopyPasteActions( );
+
+ connect( &m_commandManager, SIGNAL( objectChanged( PMObject*, const int, QObject* ) ),
+ SLOT( slotObjectChanged( PMObject*, const int, QObject* ) ) );
+
+ PMPluginManager::theManager( )->registerPart( this );
+
+ emit refresh( );
+}
+
+PMPart::~PMPart( )
+{
+ delete m_pExtension;
+ deleteContents( );
+ delete m_pSymbolTable;
+ delete m_pPovrayWidget;
+ PMPluginManager::theManager( )->removePart( this );
+}
+
+void PMPart::initCopyPasteActions( )
+{
+ // setup edit menu
+ m_pCutAction = KStdAction::cut( this, SLOT( slotEditCut( ) ), actionCollection( ) );
+ m_pCopyAction = KStdAction::copy( this, SLOT( slotEditCopy( ) ), actionCollection( ) );
+ m_pPasteAction = KStdAction::paste( this, SLOT( slotEditPaste( ) ), actionCollection( ) );
+
+ m_pDeleteAction =
+ new KAction( i18n( "Delete" ), "edittrash", Qt::Key_Delete,
+ this, SLOT( slotEditDelete( ) ),
+ actionCollection( ), "edit_delete" );
+
+ m_pCutAction->setEnabled( false );
+ m_pCopyAction->setEnabled( false );
+ m_pPasteAction->setEnabled( false );
+ m_pDeleteAction->setEnabled( false );
+
+}
+
+void PMPart::initActions( )
+{
+ // file menu
+ m_pImportAction = new KAction( i18n( "Import..." ), 0, this,
+ SLOT( slotFileImport( ) ), actionCollection( ),
+ "file_import" );
+ m_pExportAction = new KAction( i18n( "&Export..." ), 0, this,
+ SLOT( slotFileExport( ) ), actionCollection( ),
+ "file_export" );
+
+ initCopyPasteActions( );
+ m_onlyCopyPaste = false;
+
+ m_pRenderComboAction = new PMComboAction( i18n( "Render Modes" ), 0, this, SLOT( slotRenderMode( int ) ),
+ actionCollection( ), "view_render_combo" );
+ m_pRenderComboAction->setMinimumWidth( 250 );
+ connect( m_pRenderComboAction, SIGNAL( plugged( ) ),
+ SLOT( slotRenderModeActionPlugged( ) ) );
+ m_pRenderAction = new KAction( i18n( "Render" ), "pmrender", 0, this, SLOT( slotRender( ) ),
+ actionCollection( ), "view_render" );
+ m_pRenderSettingsAction = new KAction( i18n( "Render Modes..." ), "pmrendersettings", 0, this, SLOT( slotRenderSettings( ) ),
+ actionCollection( ), "view_render_settings" );
+ m_pViewRenderWindowAction = new KAction( i18n( "Render Window" ), 0, this, SLOT( slotViewRenderWindow( ) ),
+ actionCollection( ), "view_render_window" );
+ m_pVisibilityLabelAction = new PMLabelAction( i18n( "Visibility level:" ) + QString( " " ), actionCollection( ), "view_visibility_label" );
+ m_pVisibilityLevelAction = new PMSpinBoxAction( i18n( "Visibility Level" ),
+ 0, this, SLOT( slotVisibilityLevelChanged( int ) ),
+ actionCollection( ), "view_visibility_level" );
+ connect( m_pVisibilityLevelAction, SIGNAL( plugged( ) ),
+ SLOT( slotVisibilityActionPlugged( ) ) );
+
+ m_pGlobalDetailLabelAction = new PMLabelAction( i18n( "Global detail:" ) + QString( " " ), actionCollection( ), "global_detail_label" );
+ m_pGlobalDetailAction = new KSelectAction( i18n("Global Detail Level"), KShortcut(), actionCollection(), "global_detail_level" );
+ QStringList strList;
+ strList.append( i18n( "Very Low" ) );
+ strList.append( i18n( "Low" ) );
+ strList.append( i18n( "Medium" ) );
+ strList.append( i18n( "High" ) );
+ strList.append( i18n( "Very High" ) );
+ m_pGlobalDetailAction->setItems( strList );
+ connect( m_pGlobalDetailAction, SIGNAL( activated( int ) ), SLOT( slotGlobalDetailLevelChanged( int ) ) );
+
+ // new objects
+ if( isReadWrite( ) )
+ {
+ m_pNewGlobalSettingsAction = new KAction( i18n( "Global Settings" ), "pmglobalsettings", 0, this, SLOT( slotNewGlobalSettings( ) ),
+ actionCollection( ), "new_globalsettings" );
+ m_readWriteActions.append( m_pNewGlobalSettingsAction );
+ m_pNewSkySphereAction = new KAction( i18n( "Sky Sphere" ), "pmskysphere", 0, this, SLOT( slotNewSkySphere( ) ),
+ actionCollection( ), "new_skysphere" );
+ m_readWriteActions.append( m_pNewSkySphereAction );
+ m_pNewRainbowAction = new KAction( i18n( "Rainbow" ), "pmrainbow", 0, this, SLOT( slotNewRainbow( ) ),
+ actionCollection( ), "new_rainbow" );
+ m_readWriteActions.append( m_pNewRainbowAction );
+ m_pNewFogAction = new KAction( i18n( "Fog" ), "pmfog", 0, this, SLOT( slotNewFog( ) ),
+ actionCollection( ), "new_fog" );
+ m_readWriteActions.append( m_pNewFogAction );
+ m_pNewInteriorAction = new KAction( i18n( "Interior" ), "pminterior", 0, this, SLOT( slotNewInterior( ) ),
+ actionCollection( ), "new_interior" );
+ m_readWriteActions.append( m_pNewInteriorAction );
+ m_pNewMediaAction = new KAction( i18n( "Media" ), "pmmedia", 0, this, SLOT( slotNewMedia( ) ),
+ actionCollection( ), "new_media" );
+ m_readWriteActions.append( m_pNewMediaAction );
+ m_pNewDensityAction = new KAction( i18n( "Density" ), "pmdensity", 0, this, SLOT( slotNewDensity( ) ),
+ actionCollection( ), "new_density" );
+ m_readWriteActions.append( m_pNewDensityAction );
+ m_pNewMaterialAction = new KAction( i18n( "Material" ), "pmmaterial", 0, this, SLOT( slotNewMaterial( ) ),
+ actionCollection( ), "new_material" );
+ m_readWriteActions.append( m_pNewMaterialAction );
+ m_pNewBoxAction = new KAction( i18n( "Box" ), "pmbox", 0, this, SLOT( slotNewBox( ) ),
+ actionCollection( ), "new_box" );
+ m_readWriteActions.append( m_pNewBoxAction );
+ m_pNewSphereAction = new KAction( i18n( "Sphere" ), "pmsphere", 0, this, SLOT( slotNewSphere( ) ),
+ actionCollection( ), "new_sphere" );
+ m_readWriteActions.append( m_pNewSphereAction );
+ m_pNewCylinderAction = new KAction( i18n( "Cylinder" ), "pmcylinder", 0, this, SLOT( slotNewCylinder( ) ),
+ actionCollection( ), "new_cylinder" );
+ m_readWriteActions.append( m_pNewCylinderAction );
+ m_pNewConeAction = new KAction( i18n( "Cone" ), "pmcone", 0, this, SLOT( slotNewCone( ) ),
+ actionCollection( ), "new_cone" );
+ m_readWriteActions.append( m_pNewConeAction );
+ m_pNewTorusAction = new KAction( i18n( "Torus" ), "pmtorus", 0, this, SLOT( slotNewTorus( ) ),
+ actionCollection( ), "new_torus" );
+ m_readWriteActions.append( m_pNewTorusAction );
+
+ m_pNewLatheAction = new KAction( i18n( "Lathe" ), "pmlathe", 0, this, SLOT( slotNewLathe( ) ),
+ actionCollection( ), "new_lathe" );
+ m_readWriteActions.append( m_pNewLatheAction );
+ m_pNewPrismAction = new KAction( i18n( "Prism" ), "pmprism", 0, this, SLOT( slotNewPrism( ) ),
+ actionCollection( ), "new_prism" );
+ m_readWriteActions.append( m_pNewPrismAction );
+ m_pNewSurfaceOfRevolutionAction = new KAction( i18n( "Surface of Revolution" ), "pmsor", 0, this, SLOT( slotNewSurfaceOfRevolution( ) ),
+ actionCollection( ), "new_surfaceofrevolution" );
+ m_readWriteActions.append( m_pNewSurfaceOfRevolutionAction );
+ m_pNewSuperquadricEllipsoidAction = new KAction( i18n( "Superquadric Ellipsoid" ), "pmsqe", 0, this, SLOT( slotNewSuperquadricEllipsoid( ) ),
+ actionCollection( ), "new_superquadricellipsoid" );
+ m_readWriteActions.append( m_pNewSuperquadricEllipsoidAction );
+
+ m_pNewJuliaFractalAction = new KAction( i18n( "Julia Fractal" ), "pmjuliafractal", 0, this, SLOT( slotNewJuliaFractal( ) ),
+ actionCollection( ), "new_juliafractal" );
+ m_readWriteActions.append( m_pNewJuliaFractalAction );
+ m_pNewHeightFieldAction = new KAction( i18n( "Height Field" ), "pmheightfield", 0, this, SLOT( slotNewHeightField( ) ),
+ actionCollection( ), "new_heightfield" );
+ m_readWriteActions.append( m_pNewHeightFieldAction );
+ m_pNewTextAction = new KAction( i18n( "Text" ), "pmtext", 0, this, SLOT( slotNewText( ) ),
+ actionCollection( ), "new_text" );
+ m_readWriteActions.append( m_pNewTextAction );
+
+ m_pNewBlobAction = new KAction( i18n( "Blob" ), "pmblob", 0, this, SLOT( slotNewBlob( ) ),
+ actionCollection( ), "new_blob" );
+ m_readWriteActions.append( m_pNewBlobAction );
+ m_pNewBlobSphereAction = new KAction( i18n( "Blob Sphere" ), "pmblobsphere", 0, this, SLOT( slotNewBlobSphere( ) ),
+ actionCollection( ), "new_blobsphere" );
+ m_readWriteActions.append( m_pNewBlobSphereAction );
+ m_pNewBlobCylinderAction = new KAction( i18n( "Blob Cylinder" ), "pmblobcylinder", 0, this, SLOT( slotNewBlobCylinder( ) ),
+ actionCollection( ), "new_blobcylinder" );
+ m_readWriteActions.append( m_pNewBlobCylinderAction );
+
+ m_pNewPlaneAction = new KAction( i18n( "Plane" ), "pmplane", 0, this, SLOT( slotNewPlane( ) ),
+ actionCollection( ), "new_plane" );
+ m_readWriteActions.append( m_pNewPlaneAction );
+ m_pNewPolynomAction = new KAction( i18n( "Polynom" ), "pmpolynom", 0, this, SLOT( slotNewPolynom( ) ),
+ actionCollection( ), "new_polynom" );
+ m_readWriteActions.append( m_pNewPolynomAction );
+
+ m_pNewDeclareAction = new KAction( i18n( "Declaration" ), "pmdeclare", 0, this, SLOT( slotNewDeclare( ) ),
+ actionCollection( ), "new_declare" );
+ m_readWriteActions.append( m_pNewDeclareAction );
+ m_pNewObjectLinkAction = new KAction( i18n( "Object Link" ), "pmobjectlink", 0, this, SLOT( slotNewObjectLink( ) ),
+ actionCollection( ), "new_objectlink" );
+ m_readWriteActions.append( m_pNewObjectLinkAction );
+
+ m_pNewUnionAction = new KAction( i18n( "Union" ), "pmunion", 0, this, SLOT( slotNewUnion( ) ),
+ actionCollection( ), "new_union" );
+ m_readWriteActions.append( m_pNewUnionAction );
+ m_pNewIntersectionAction = new KAction( i18n( "Intersection" ), "pmintersection", 0, this, SLOT( slotNewIntersection( ) ),
+ actionCollection( ), "new_intersection" );
+ m_readWriteActions.append( m_pNewIntersectionAction );
+ m_pNewDifferenceAction = new KAction( i18n( "Difference" ), "pmdifference", 0, this, SLOT( slotNewDifference( ) ),
+ actionCollection( ), "new_difference" );
+ m_readWriteActions.append( m_pNewDifferenceAction );
+ m_pNewMergeAction = new KAction( i18n( "Merge" ), "pmmerge", 0, this, SLOT( slotNewMerge( ) ),
+ actionCollection( ), "new_merge" );
+ m_readWriteActions.append( m_pNewMergeAction );
+
+ m_pNewBoundedByAction = new KAction( i18n( "Bounded By" ), "pmboundedby", 0, this, SLOT( slotNewBoundedBy( ) ),
+ actionCollection( ), "new_boundedby" );
+ m_readWriteActions.append( m_pNewBoundedByAction );
+ m_pNewClippedByAction = new KAction( i18n( "Clipped By" ), "pmclippedby", 0, this, SLOT( slotNewClippedBy( ) ),
+ actionCollection( ), "new_clippedby" );
+ m_readWriteActions.append( m_pNewClippedByAction );
+
+ m_pNewLightAction = new KAction( i18n( "Light" ), "pmlight", 0, this, SLOT( slotNewLight( ) ),
+ actionCollection( ), "new_light" );
+ m_readWriteActions.append( m_pNewLightAction );
+ m_pNewLooksLikeAction = new KAction( i18n( "Looks Like" ), "pmlookslike", 0, this, SLOT( slotNewLooksLike( ) ),
+ actionCollection( ), "new_lookslike" );
+ m_readWriteActions.append( m_pNewLooksLikeAction );
+ m_pNewProjectedThroughAction = new KAction( i18n( "Projected Through" ), "pmprojectedthrough", 0, this, SLOT( slotNewProjectedThrough( ) ),
+ actionCollection( ), "new_projectedthrough" );
+ m_readWriteActions.append( m_pNewProjectedThroughAction );
+
+ m_pNewBicubicPatchAction = new KAction( i18n( "Bicubic Patch" ), "pmbicubicpatch", 0, this, SLOT( slotNewBicubicPatch( ) ),
+ actionCollection( ), "new_bicubicpatch" );
+ m_readWriteActions.append( m_pNewBicubicPatchAction );
+ m_pNewDiscAction = new KAction( i18n( "Disc" ), "pmdisc", 0, this, SLOT( slotNewDisc( ) ),
+ actionCollection( ), "new_disc" );
+ m_readWriteActions.append( m_pNewDiscAction );
+ m_pNewTriangleAction = new KAction( i18n( "Triangle" ), "pmtriangle", 0, this, SLOT( slotNewTriangle( ) ),
+ actionCollection( ), "new_triangle" );
+ m_readWriteActions.append( m_pNewTriangleAction );
+
+
+ m_pNewCameraAction = new KAction( i18n( "Camera" ), "pmcamera", 0, this, SLOT( slotNewCamera( ) ),
+ actionCollection( ), "new_camera" );
+ m_readWriteActions.append( m_pNewCameraAction );
+
+ m_pNewTextureAction = new KAction( i18n( "Texture" ), "pmtexture", 0, this, SLOT( slotNewTexture( ) ),
+ actionCollection( ), "new_texture" );
+ m_readWriteActions.append( m_pNewTextureAction );
+
+ m_pNewPigmentAction = new KAction( i18n( "Pigment" ), "pmpigment", 0, this, SLOT( slotNewPigment( ) ),
+ actionCollection( ), "new_pigment" );
+ m_readWriteActions.append( m_pNewPigmentAction );
+ m_pNewNormalAction = new KAction( i18n( "Normal" ), "pmnormal", 0, this, SLOT( slotNewNormal( ) ),
+ actionCollection( ), "new_normal" );
+ m_readWriteActions.append( m_pNewNormalAction );
+ m_pNewSolidColorAction = new KAction( i18n( "Solid Color" ), "pmsolidcolor", 0, this, SLOT( slotNewSolidColor( ) ),
+ actionCollection( ), "new_solidcolor" );
+ m_readWriteActions.append( m_pNewSolidColorAction );
+
+ m_pNewTextureListAction = new KAction( i18n( "Texture List" ), "pmtexturelist", 0, this, SLOT( slotNewTextureList( ) ),
+ actionCollection( ), "new_texturelist" );
+ m_readWriteActions.append( m_pNewTextureListAction );
+ m_pNewColorListAction = new KAction( i18n( "Color List" ), "pmcolorlist", 0, this, SLOT( slotNewColorList( ) ),
+ actionCollection( ), "new_colorlist" );
+ m_readWriteActions.append( m_pNewColorListAction );
+ m_pNewPigmentListAction = new KAction( i18n( "Pigment List" ), "pmpigmentlist", 0, this, SLOT( slotNewPigmentList( ) ),
+ actionCollection( ), "new_pigmentlist" );
+ m_readWriteActions.append( m_pNewPigmentListAction );
+ m_pNewNormalListAction = new KAction( i18n( "Normal List" ), "pmnormallist", 0, this, SLOT( slotNewNormalList( ) ),
+ actionCollection( ), "new_normallist" );
+ m_readWriteActions.append( m_pNewNormalListAction );
+ m_pNewDensityListAction = new KAction( i18n( "Density List" ), "pmdensitylist", 0, this, SLOT( slotNewDensityList( ) ),
+ actionCollection( ), "new_densitylist" );
+ m_readWriteActions.append( m_pNewDensityListAction );
+
+ m_pNewFinishAction = new KAction( i18n( "Finish" ), "pmfinish", 0, this, SLOT( slotNewFinish( ) ),
+ actionCollection( ), "new_finish" );
+ m_readWriteActions.append( m_pNewFinishAction );
+
+ m_pNewPatternAction = new KAction( i18n( "Pattern" ), "pmpattern", 0, this, SLOT( slotNewPattern( ) ),
+ actionCollection( ), "new_pattern" );
+ m_readWriteActions.append( m_pNewPatternAction );
+ m_pNewBlendMapModifiersAction = new KAction( i18n( "Blend Map Modifiers" ), "pmblendmapmodifiers", 0, this, SLOT( slotNewBlendMapModifiers( ) ),
+ actionCollection( ), "new_blendmapmodifiers" );
+ m_readWriteActions.append( m_pNewBlendMapModifiersAction );
+ m_pNewTextureMapAction = new KAction( i18n( "Texture Map" ), "pmtexturemap", 0, this, SLOT( slotNewTextureMap( ) ),
+ actionCollection( ), "new_texturemap" );
+ m_readWriteActions.append( m_pNewTextureMapAction );
+ m_pNewMaterialMapAction = new KAction( i18n( "Material Map" ), "pmmaterialmap", 0, this, SLOT( slotNewMaterialMap( ) ),
+ actionCollection( ), "new_materialmap" );
+ m_readWriteActions.append( m_pNewMaterialMapAction );
+ m_pNewPigmentMapAction = new KAction( i18n( "Pigment Map" ), "pmpigmentmap", 0, this, SLOT( slotNewPigmentMap( ) ),
+ actionCollection( ), "new_pigmentmap" );
+ m_readWriteActions.append( m_pNewPigmentMapAction );
+ m_pNewColorMapAction = new KAction( i18n( "Color Map" ), "pmcolormap", 0, this, SLOT( slotNewColorMap( ) ),
+ actionCollection( ), "new_colormap" );
+ m_readWriteActions.append( m_pNewColorMapAction );
+ m_pNewNormalMapAction = new KAction( i18n( "Normal Map" ), "pmnormalmap", 0, this, SLOT( slotNewNormalMap( ) ),
+ actionCollection( ), "new_normalmap" );
+ m_readWriteActions.append( m_pNewNormalMapAction );
+ m_pNewBumpMapAction = new KAction( i18n( "Bump Map" ), "pmbumpmap", 0, this, SLOT( slotNewBumpMap( ) ),
+ actionCollection( ), "new_bumpmap" );
+ m_readWriteActions.append( m_pNewBumpMapAction );
+ m_pNewSlopeMapAction = new KAction( i18n( "Slope Map" ), "pmslopemap", 0, this, SLOT( slotNewSlopeMap( ) ),
+ actionCollection( ), "new_slopemap" );
+ m_readWriteActions.append( m_pNewSlopeMapAction );
+ m_pNewDensityMapAction = new KAction( i18n( "Density Map" ), "pmdensitymap", 0, this, SLOT( slotNewDensityMap( ) ),
+ actionCollection( ), "new_densitymap" );
+ m_readWriteActions.append( m_pNewDensityMapAction );
+ m_pNewSlopeAction = new KAction( i18n( "Slope" ), "pmslope", 0, this, SLOT( slotNewSlope( ) ),
+ actionCollection( ), "new_slope" );
+ m_readWriteActions.append( m_pNewSlopeAction );
+
+ m_pNewWarpAction = new KAction( i18n( "Warp" ), "pmwarp", 0, this, SLOT( slotNewWarp( ) ),
+ actionCollection( ), "new_warp" );
+ m_readWriteActions.append( m_pNewWarpAction );
+ m_pNewImageMapAction = new KAction( i18n( "Image Map" ), "pmimagemap", 0, this, SLOT( slotNewImageMap( ) ),
+ actionCollection( ), "new_imagemap" );
+ m_readWriteActions.append( m_pNewImageMapAction );
+ m_pNewQuickColorAction = new KAction( i18n( "QuickColor" ), "pmquickcolor", 0, this, SLOT( slotNewQuickColor( ) ),
+ actionCollection( ), "new_quickcolor" );
+ m_readWriteActions.append( m_pNewQuickColorAction );
+
+ m_pNewTranslateAction = new KAction( i18n( "Translate" ), "pmtranslate", 0, this, SLOT( slotNewTranslate( ) ),
+ actionCollection( ), "new_translate" );
+ m_readWriteActions.append( m_pNewTranslateAction );
+ m_pNewScaleAction = new KAction( i18n( "Scale" ), "pmscale", 0, this, SLOT( slotNewScale( ) ),
+ actionCollection( ), "new_scale" );
+ m_readWriteActions.append( m_pNewScaleAction );
+ m_pNewRotateAction = new KAction( i18n( "Rotate" ), "pmrotate", 0, this, SLOT( slotNewRotate( ) ),
+ actionCollection( ), "new_rotate" );
+ m_readWriteActions.append( m_pNewRotateAction );
+ m_pNewMatrixAction = new KAction( i18n( "Matrix" ), "pmmatrix", 0, this, SLOT( slotNewMatrix( ) ),
+ actionCollection( ), "new_povraymatrix" );
+ m_readWriteActions.append( m_pNewMatrixAction );
+
+ m_pNewCommentAction = new KAction( i18n( "Comment" ), "pmcomment", 0, this, SLOT( slotNewComment( ) ),
+ actionCollection( ), "new_comment" );
+ m_readWriteActions.append( m_pNewCommentAction );
+ m_pNewRawAction = new KAction( i18n( "Raw Povray" ), "pmraw", 0, this, SLOT( slotNewRaw( ) ),
+ actionCollection( ), "new_raw" );
+ m_readWriteActions.append( m_pNewRawAction );
+
+ // POV-Ray 3.5 objects
+ m_pNewIsoSurfaceAction = new KAction( i18n( "Iso Surface" ), "pmisosurface", 0, this, SLOT( slotNewIsoSurface( ) ),
+ actionCollection( ), "new_isosurface" );
+ m_readWriteActions.append( m_pNewIsoSurfaceAction );
+ m_pNewRadiosityAction = new KAction( i18n( "Radiosity" ), "pmradiosity", 0, this, SLOT( slotNewRadiosity( ) ),
+ actionCollection( ), "new_radiosity" );
+ m_readWriteActions.append( m_pNewRadiosityAction );
+ m_pNewGlobalPhotonsAction = new KAction( i18n( "Global Photons" ), "pmglobalphotons", 0, this, SLOT( slotNewGlobalPhotons( ) ),
+ actionCollection( ), "new_globalphotons" );
+ m_readWriteActions.append( m_pNewGlobalPhotonsAction );
+ m_pNewPhotonsAction = new KAction( i18n( "Photons" ), "pmphotons", 0, this, SLOT( slotNewPhotons( ) ),
+ actionCollection( ), "new_photons" );
+ m_readWriteActions.append( m_pNewPhotonsAction );
+ m_pNewLightGroupAction = new KAction( i18n( "Light Group" ), "pmlightgroup", 0, this, SLOT( slotNewLightGroup( ) ),
+ actionCollection( ), "new_lightgroup" );
+ m_readWriteActions.append( m_pNewLightGroupAction );
+ m_pNewInteriorTextureAction = new KAction( i18n( "Interior Texture" ), "pminteriortexture", 0, this, SLOT( slotNewInteriorTexture( ) ),
+ actionCollection( ), "new_interiortexture" );
+ m_readWriteActions.append( m_pNewInteriorTextureAction );
+ m_pNewSphereSweepAction = new KAction( i18n( "Sphere Sweep" ), "pmspheresweep", 0, this, SLOT( slotNewSphereSweep( ) ),
+ actionCollection( ), "new_spheresweep" );
+ m_readWriteActions.append( m_pNewSphereSweepAction );
+ m_pNewMeshAction = new KAction( i18n( "Mesh" ), "pmmesh", 0, this, SLOT( slotNewMesh( ) ),
+ actionCollection( ), "new_mesh" );
+ m_readWriteActions.append( m_pNewMeshAction );
+
+#ifdef KPM_WITH_OBJECT_LIBRARY
+ m_pSearchLibraryObjectAction = new KAction( i18n( "Search Object" ), "pmsearchlibrary", 0, this, SLOT( slotSearchLibraryObject( ) ),
+ actionCollection( ), "search_library_object" );
+ m_readWriteActions.append( m_pSearchLibraryObjectAction );
+#endif
+
+ m_pUndoAction = KStdAction::undo( this, SLOT( slotEditUndo( ) ), actionCollection( ) );
+ m_pRedoAction = KStdAction::redo( this, SLOT( slotEditRedo( ) ), actionCollection( ) );
+ m_pUndoAction->setEnabled( false );
+ m_pRedoAction->setEnabled( false );
+ }
+ else
+ {
+ m_pNewGlobalSettingsAction = 0;
+ m_pNewSkySphereAction = 0;
+ m_pNewRainbowAction = 0;
+ m_pNewFogAction = 0;
+
+ m_pNewInteriorAction = 0;
+ m_pNewMediaAction = 0;
+ m_pNewDensityAction = 0;
+ m_pNewMaterialAction = 0;
+ m_pNewBoxAction = 0;
+ m_pNewSphereAction = 0;
+ m_pNewCylinderAction = 0;
+ m_pNewConeAction = 0;
+ m_pNewTorusAction = 0;
+ m_pNewLatheAction = 0;
+ m_pNewPrismAction = 0;
+ m_pNewSurfaceOfRevolutionAction = 0;
+ m_pNewSuperquadricEllipsoidAction = 0;
+ m_pNewJuliaFractalAction = 0;
+ m_pNewHeightFieldAction = 0;
+ m_pNewTextAction = 0;
+
+ m_pNewBlobAction = 0;
+ m_pNewBlobSphereAction = 0;
+ m_pNewBlobCylinderAction = 0;
+
+ m_pNewPlaneAction = 0;
+ m_pNewPolynomAction = 0;
+
+ m_pNewDeclareAction = 0;
+ m_pNewObjectLinkAction = 0;
+
+ m_pNewDiscAction = 0;
+ m_pNewBicubicPatchAction = 0;
+ m_pNewTriangleAction = 0;
+
+ m_pNewUnionAction = 0;
+ m_pNewDifferenceAction = 0;
+ m_pNewIntersectionAction = 0;
+ m_pNewMergeAction = 0;
+
+ m_pNewBoundedByAction = 0;
+ m_pNewClippedByAction = 0;
+
+ m_pNewLightAction = 0;
+ m_pNewLooksLikeAction = 0;
+ m_pNewProjectedThroughAction = 0;
+
+ m_pNewCameraAction = 0;
+
+ m_pNewTextureAction = 0;
+ m_pNewPigmentAction = 0;
+ m_pNewNormalAction = 0;
+ m_pNewSolidColorAction = 0;
+ m_pNewFinishAction = 0;
+ m_pNewTextureListAction = 0;
+ m_pNewColorListAction = 0;
+ m_pNewPigmentListAction = 0;
+ m_pNewNormalListAction = 0;
+ m_pNewDensityListAction = 0;
+
+ m_pNewPatternAction = 0;
+ m_pNewBlendMapModifiersAction = 0;
+ m_pNewTextureMapAction = 0;
+ m_pNewMaterialMapAction = 0;
+ m_pNewPigmentMapAction = 0;
+ m_pNewColorMapAction = 0;
+ m_pNewNormalMapAction = 0;
+ m_pNewBumpMapAction = 0;
+ m_pNewSlopeMapAction = 0;
+ m_pNewDensityMapAction = 0;
+
+ m_pNewWarpAction = 0;
+ m_pNewImageMapAction = 0;
+ m_pNewSlopeAction = 0;
+
+ m_pNewTranslateAction = 0;
+ m_pNewScaleAction = 0;
+ m_pNewRotateAction = 0;
+ m_pNewMatrixAction = 0;
+ m_pNewCommentAction = 0;
+ m_pNewRawAction = 0;
+
+ m_pNewIsoSurfaceAction = 0;
+ m_pNewRadiosityAction = 0;
+ m_pNewGlobalPhotonsAction = 0;
+ m_pNewPhotonsAction = 0;
+ m_pNewLightGroupAction = 0;
+ m_pNewInteriorTextureAction = 0;
+ m_pNewSphereSweepAction = 0;
+ m_pNewMeshAction = 0;
+
+ // POV-Ray
+
+ m_pUndoAction = 0;
+ m_pRedoAction = 0;
+ }
+}
+
+void PMPart::updateNewObjectActions( )
+{
+ if( isReadWrite( ) && !m_onlyCopyPaste )
+ {
+ QPtrListIterator<PMMetaObject> it =
+ m_pPrototypeManager->prototypeIterator( );
+ KAction* action;
+ bool enable;
+ bool readWriteParent = false;
+
+ if( m_pActiveObject )
+ if( m_pActiveObject->parent( ) )
+ if( !m_pActiveObject->parent( )->isReadOnly( ) )
+ readWriteParent = true;
+
+ for( ; it.current( ); ++it )
+ {
+ // get the action object for that type of PMObject
+ // action names are "new_" + povray name
+ // (like new_box, new_sphere ...)
+
+ QString actionName = "new_" + it.current( )->className( ).lower( );
+ action = actionCollection( )->action( actionName.latin1( ) );
+ if( action )
+ {
+ if( m_pActiveObject )
+ {
+ QString insertName = it.current( )->className( );
+ enable = m_pActiveObject->canInsert( insertName, 0 );
+ if( !enable )
+ if( m_pActiveObject->lastChild( ) )
+ enable = m_pActiveObject->canInsert( insertName, m_pActiveObject->lastChild( ) );
+ if( !enable )
+ if( readWriteParent )
+ enable |= m_pActiveObject->parent( )->canInsert( insertName, m_pActiveObject );
+ }
+ else
+ enable = false;
+ action->setEnabled( enable );
+ }
+ }
+ // special treatment for csg actions
+ if( m_pActiveObject )
+ {
+ enable = m_pActiveObject->canInsert( QString( "CSG" ), 0 );
+ if( !enable )
+ if( m_pActiveObject->lastChild( ) )
+ enable = m_pActiveObject->canInsert( QString( "CSG" ), m_pActiveObject->lastChild( ) );
+ if( !enable )
+ if( readWriteParent )
+ enable = m_pActiveObject->parent( )->canInsert( QString( "CSG" ), m_pActiveObject );
+ }
+ else
+ enable = false;
+ m_pNewUnionAction->setEnabled( enable );
+ m_pNewIntersectionAction->setEnabled( enable );
+ m_pNewDifferenceAction->setEnabled( enable );
+ m_pNewMergeAction->setEnabled( enable );
+ }
+ m_updateNewObjectActions = false;
+}
+
+void PMPart::disableReadWriteActions( )
+{
+ QPtrListIterator<KAction> it( m_readWriteActions);
+ for( ; it.current( ); ++it )
+ it.current( )->setEnabled( false );
+}
+
+void PMPart::initDocument( )
+{
+ newDocument( );
+}
+
+void PMPart::initView( QWidget* parent, const char* name )
+{
+ if( !m_pShell )
+ {
+ // a part inside konqueror
+ // simple layout
+ m_pView = new PMView( this, parent, name );
+ m_pView->show( );
+ setWidget( m_pView );
+ }
+ else
+ {
+ // inside a PMShell
+ // the shell will create the view
+ }
+}
+
+void PMPart::saveConfig( KConfig* cfg )
+{
+ if( m_pView )
+ m_pView->saveConfig( cfg );
+ PMErrorDialog::saveConfig( cfg );
+ PMRenderModesDialog::saveConfig( cfg );
+ PMRenderModeDialog::saveConfig( cfg );
+ PMPovrayOutputWidget::saveConfig( cfg );
+ PMRenderManager::theManager( )->saveConfig( cfg );
+ PMGLView::saveConfig( cfg );
+ PMDialogEditBase::saveConfig( cfg );
+ PMControlPoint::saveConfig( cfg );
+ PMPovrayRenderWidget::saveConfig( cfg );
+ PMSettingsDialog::saveConfig( cfg );
+ PMLibraryHandleEdit::saveConfig( cfg );
+ PMDocumentationMap::theMap( )->saveConfig( cfg );
+ PMLibraryManager::theManager( )->saveConfig(cfg );
+
+ cfg->setGroup( "Rendering" );
+ cfg->writeEntry( "SphereUSteps", PMSphere::uSteps( ) );
+ cfg->writeEntry( "SphereVSteps", PMSphere::vSteps( ) );
+ cfg->writeEntry( "CylinderSteps", PMCylinder::steps( ) );
+ cfg->writeEntry( "ConeSteps", PMCone::steps( ) );
+ cfg->writeEntry( "DiscSteps", PMDisc::steps( ) );
+ cfg->writeEntry( "BlobSphereUSteps", PMBlobSphere::uSteps( ) );
+ cfg->writeEntry( "BlobSphereVSteps", PMBlobSphere::vSteps( ) );
+ cfg->writeEntry( "BlobCylinderUSteps", PMBlobCylinder::uSteps( ) );
+ cfg->writeEntry( "BlobCylinderVSteps", PMBlobCylinder::vSteps( ) );
+ cfg->writeEntry( "TorusUSteps", PMTorus::uSteps( ) );
+ cfg->writeEntry( "TorusVSteps", PMTorus::vSteps( ) );
+ cfg->writeEntry( "LatheSSteps", PMLathe::sSteps( ) );
+ cfg->writeEntry( "LatheRSteps", PMLathe::rSteps( ) );
+ cfg->writeEntry( "SorSSteps", PMSurfaceOfRevolution::sSteps( ) );
+ cfg->writeEntry( "SorRSteps", PMSurfaceOfRevolution::rSteps( ) );
+ cfg->writeEntry( "PrismSSteps", PMPrism::sSteps( ) );
+ cfg->writeEntry( "PlaneSize", PMPlane::planeSize( ) );
+ cfg->writeEntry( "SqeUSteps", PMSuperquadricEllipsoid::uSteps( ) );
+ cfg->writeEntry( "SqeVSteps", PMSuperquadricEllipsoid::vSteps( ) );
+ cfg->writeEntry( "SphereSweepRSteps", PMSphereSweep::rSteps( ) );
+ cfg->writeEntry( "SphereSweepSSteps", PMSphereSweep::sSteps( ) );
+ cfg->writeEntry( "HeightFieldVariance", PMHeightField::variance( ) );
+ cfg->writeEntry( "GlobalDetailLevel", PMDetailObject::globalDetailLevel( ) );
+
+ cfg->writeEntry( "DirectRendering", PMGLView::isDirectRenderingEnabled( ) );
+}
+
+void PMPart::restoreConfig( KConfig* cfg )
+{
+ if( m_pView )
+ m_pView->restoreConfig( cfg );
+ PMErrorDialog::restoreConfig( cfg );
+ PMRenderModesDialog::restoreConfig( cfg );
+ PMRenderModeDialog::restoreConfig( cfg );
+ PMPovrayOutputWidget::restoreConfig( cfg );
+ PMRenderManager::theManager( )->restoreConfig( cfg );
+ PMGLView::restoreConfig( cfg );
+ PMDialogEditBase::restoreConfig( cfg );
+ PMControlPoint::restoreConfig( cfg );
+ PMPovrayRenderWidget::restoreConfig( cfg );
+ PMSettingsDialog::restoreConfig( cfg );
+ PMLibraryHandleEdit::restoreConfig( cfg );
+ PMDocumentationMap::theMap( )->restoreConfig( cfg );
+ PMLibraryManager::theManager( )->restoreConfig(cfg );
+
+ cfg->setGroup( "Rendering" );
+ PMSphere::setUSteps( cfg->readNumEntry( "SphereUSteps", c_defaultSphereUSteps ) );
+ PMSphere::setVSteps( cfg->readNumEntry( "SphereVSteps", c_defaultSphereVSteps ) );
+ PMCylinder::setSteps( cfg->readNumEntry( "CylinderSteps", c_defaultCylinderSteps ) );
+ PMCone::setSteps( cfg->readNumEntry( "ConeSteps", c_defaultConeSteps ) );
+ PMTorus::setUSteps( cfg->readNumEntry( "TorusUSteps", c_defaultTorusUSteps ) );
+ PMTorus::setVSteps( cfg->readNumEntry( "TorusVSteps", c_defaultTorusVSteps ) );
+ PMLathe::setSSteps( cfg->readNumEntry( "LatheSSteps", c_defaultLatheSSteps ) );
+ PMLathe::setRSteps( cfg->readNumEntry( "LatheRSteps", c_defaultLatheRSteps ) );
+ PMSurfaceOfRevolution::setSSteps( cfg->readNumEntry( "SorSSteps", c_defaultSurfaceOfRevolutionSSteps ) );
+ PMSurfaceOfRevolution::setRSteps( cfg->readNumEntry( "SorRSteps", c_defaultSurfaceOfRevolutionRSteps ) );
+ PMPrism::setSSteps( cfg->readNumEntry( "PrismSSteps", c_defaultPrismSSteps ) );
+ PMPlane::setPlaneSize( cfg->readDoubleNumEntry( "PlaneSize", c_defaultPlaneSize ) );
+ PMDisc::setSteps( cfg->readNumEntry( "DiscSteps", c_defaultDiscSteps ) );
+ PMBlobSphere::setUSteps( cfg->readNumEntry( "BlobSphereUSteps", c_defaultBlobSphereUSteps ) );
+ PMBlobSphere::setVSteps( cfg->readNumEntry( "BlobSphereVSteps", c_defaultBlobSphereVSteps ) );
+ PMBlobCylinder::setUSteps( cfg->readNumEntry( "BlobCylinderUSteps", c_defaultBlobCylinderUSteps ) );
+ PMBlobCylinder::setVSteps( cfg->readNumEntry( "BlobCylinderVSteps", c_defaultBlobCylinderVSteps ) );
+ PMSuperquadricEllipsoid::setUSteps( cfg->readNumEntry( "SqeUSteps", c_defaultSuperquadricEllipsoidUSteps ) );
+ PMSuperquadricEllipsoid::setVSteps( cfg->readNumEntry( "SqeVSteps", c_defaultSuperquadricEllipsoidVSteps ) );
+ PMSphereSweep::setRSteps( cfg->readNumEntry( "SphereSweepRSteps", c_defaultSphereSweepRSteps ) );
+ PMSphereSweep::setSSteps( cfg->readNumEntry( "SphereSweepSSteps", c_defaultSphereSweepSSteps ) );
+ PMHeightField::setVariance( cfg->readNumEntry( "HeightFieldVariance", c_defaultHeightFieldVariance ) );
+ PMDetailObject::setGlobalDetailLevel( cfg->readNumEntry( "GlobalDetailLevel", c_defaultDetailObjectGlobalDetailLevel ) );
+ m_pGlobalDetailAction->setCurrentItem( PMDetailObject::globalDetailLevel( ) - 1 );
+
+ if( PMGLView::isDirectRenderingEnabled( ) ) // otherwise it was disabled with a command line switch
+ PMGLView::enableDirectRendering( cfg->readBoolEntry( "DirectRendering", true ) );
+}
+
+bool PMPart::openFile( )
+{
+ QIODevice* dev = KFilterDev::deviceForFile( m_file, "application/x-gzip" );
+ bool success = true;
+ PMObjectList list;
+
+ deleteContents( );
+
+ setModified( false );
+
+ if( dev && dev->open( IO_ReadOnly ) )
+ {
+ PMXMLParser parser( this, dev );
+
+ parser.parse( &list, 0, 0 );
+
+ if( parser.errors( ) || parser.warnings( ) )
+ {
+ PMErrorDialog dlg( parser.messages( ), parser.errorFlags( ) );
+ // still try to insert the correct parsed objects?
+ success = ( dlg.exec( ) == QDialog::Accepted );
+ }
+ if( success )
+ {
+ PMObject* obj = list.first( );
+ if( obj )
+ {
+ if( obj->type( ) == "Scene" )
+ m_pScene = ( PMScene* ) obj;
+ else
+ success = false;
+ }
+ else
+ success = false;
+ }
+ }
+ else
+ success = false;
+
+ if( !success )
+ {
+ m_url = KURL( );
+ newDocument( );
+ }
+
+ m_pScene->setReadOnly( !isReadWrite( ) );
+ if( !isReadWrite( ) )
+ disableReadWriteActions( );
+ m_bCameraListUpToDate = false;
+
+ emit refresh( );
+ updateRenderModes( );
+ updateVisibilityLevel( );
+ slotObjectChanged( m_pScene, PMCNewSelection, this );
+
+ if( dev )
+ delete dev;
+
+ return success;
+}
+
+bool PMPart::saveFile( )
+{
+ bool success = false;
+
+ QIODevice* dev = KFilterDev::deviceForFile( m_file, "application/x-gzip" );
+ if( dev && dev->open( IO_WriteOnly ) )
+ {
+ QDomDocument doc( "KPOVMODELER" );
+ QDomElement e = ( ( PMObject* )m_pScene)->serialize( doc );
+ doc.appendChild( e );
+
+ QTextStream str( dev );
+ str << doc;
+ dev->close( );
+ setModified( false );
+ success = true;
+ }
+
+ if( dev )
+ delete dev;
+
+ return success;
+}
+
+bool PMPart::exportPovray( const KURL& url )
+{
+ KTempFile* tempFile = 0;
+ QFile* file = 0;
+ bool ok = true;
+
+ if( !url.isValid( ) )
+ return false;
+
+ if( url.isLocalFile( ) )
+ {
+ // Local file
+ file = new QFile( url.path( ) );
+ if( !file->open( IO_WriteOnly ) )
+ ok = false;
+ }
+ else
+ {
+ // Remote file
+ // provide a temp file
+ tempFile = new KTempFile( );
+ if( tempFile->status( ) != 0 )
+ ok = false;
+ else
+ file = tempFile->file( );
+ }
+
+ if( ok )
+ {
+ PMPovray35Format format;
+ PMSerializer* dev = format.newSerializer( file );
+ dev->serialize( m_pScene );
+ delete dev;
+
+ if( tempFile )
+ {
+ tempFile->close( );
+ ok = KIO::NetAccess::upload( tempFile->name( ), url, (QWidget*) 0 );
+ tempFile->unlink( );
+ file = 0;
+ }
+ else
+ file->close( );
+ }
+
+ delete file;
+ delete tempFile;
+
+ return ok;
+}
+
+QString PMPart::activeObjectName( )
+{
+ QString result = "";
+ PMObject* tmpObj;
+ PMObject* testSib;
+ int idx = 0;
+
+ tmpObj = activeObject( );
+ while( tmpObj != m_pScene && tmpObj )
+ {
+ // count previous siblings of the same type (for array like entries)
+ testSib = tmpObj;
+ while( ( testSib = testSib->prevSibling( ) ) )
+ if( testSib->type( ) == tmpObj->type( ) )
+ idx++;
+
+ // prepend to result
+ if( idx != 0 )
+ result = tmpObj->type( ) + "[" + QString::number( idx ) + "]/" + result;
+ else
+ result = tmpObj->type( ) + "/" + result;
+
+ // go up in the scene
+ tmpObj = tmpObj->parent( );
+ idx = 0;
+ }
+
+ // Make the object name an absolute name
+ result = "/" + result;
+
+ return result;
+}
+
+bool PMPart::setActiveObject( const QString& name )
+{
+ PMObject* tmpObj;
+ PMObject* tmpSibling;
+ int pos, siblingIndex, objIndex, firstBracket, lastBracket;
+ QString objPath;
+ QString pathElem;
+
+ // check if it's a absolute object name
+ if( name[0] == '/' )
+ {
+ tmpObj = m_pScene;
+ objPath = name.mid( 1 ); // clear that first character
+ }
+ else
+ tmpObj = activeObject( );
+
+ // get the first element
+ pos = objPath.find( '/' );
+ if( pos != -1 )
+ {
+ pathElem = objPath.mid( 0, pos );
+ objPath = objPath.mid( pos + 1 );
+ }
+ else
+ {
+ pathElem = objPath;
+ objPath = QString::null;
+ }
+
+ while( !pathElem.isNull( ) )
+ {
+ if( !pathElem.isEmpty( ) )
+ {
+ // Special treatment for brackets
+ firstBracket = pathElem.find( '[' );
+ if( firstBracket != -1 )
+ {
+ lastBracket = pathElem.findRev( ']' );
+ objIndex = pathElem.mid( firstBracket + 1, lastBracket - firstBracket - 1).toInt( );
+ pathElem = pathElem.left( firstBracket );
+ }
+ else
+ objIndex = 0;
+
+ // Iterate the children for this element. We stop when there are no more siblings
+ // or the object is of the correct type and it's index count is also correct
+ siblingIndex = 0;
+ tmpSibling = tmpObj->firstChild( );
+ for( ; tmpSibling && ( tmpSibling->type( ) != pathElem || siblingIndex != objIndex );
+ tmpSibling = tmpSibling->nextSibling( ) )
+ {
+ // Found an object of the type we are looking for
+ if( tmpSibling->type( ) == pathElem )
+ siblingIndex++;
+ }
+ if( tmpSibling )
+ tmpObj = tmpSibling;
+ else
+ // No correct sibling
+ return false;
+
+ }
+
+ // Get the next element
+ pos = objPath.find( '/' );
+ if( pos != -1 )
+ {
+ pathElem = objPath.mid( 0, pos );
+ objPath = objPath.mid( pos + 1 );
+ }
+ else
+ {
+ pathElem = objPath;
+ objPath = QString::null;
+ }
+ }
+ if( tmpObj )
+ {
+ slotObjectChanged( tmpObj, PMCNewSelection, this );
+ return true;
+ }
+ else
+ return false;
+}
+
+QStringList PMPart::getProperties( )
+{
+ PMObject* curObj = activeObject( );
+
+ // Ensure that there is an active object
+ if( !curObj )
+ return QStringList( );
+
+ return curObj->properties( );
+}
+
+bool PMPart::setProperty( const QString& name, const PMVariant& value )
+{
+ PMObject* curObj = activeObject( );
+
+ // Ensure that there is an active object
+ if( !curObj )
+ return false;
+
+ curObj->setProperty( name, value );
+ slotObjectChanged( curObj, PMCNewSelection, this );
+ return true;
+}
+
+bool PMPart::setProperty( const QString& name, const QString& value )
+{
+ PMObject* curObj = activeObject( );
+ PMVariant variant;
+
+ // Ensure that there is an active object
+ if( !curObj )
+ return false;
+
+ variant.fromString( curObj->property( name ).dataType( ), value );
+ curObj->setProperty( name, variant );
+ slotObjectChanged( curObj, PMCNewSelection, this );
+ return true;
+}
+
+const PMVariant PMPart::getProperty( const QString& name )
+{
+ PMObject* curObj = activeObject( );
+
+ // Ensure that there is an active object
+ if( !curObj )
+ return PMVariant( );
+
+ return curObj->property( name );
+}
+
+const QString PMPart::getPropertyStr( const QString& name )
+{
+ PMObject* curObj = activeObject( );
+
+ // Ensure that there is an active object
+ if( !curObj )
+ return PMVariant( ).asString( );
+
+ return curObj->property( name ).asString( );
+}
+
+const PMObjectList& PMPart::selectedObjects( )
+{
+ uint numObjects = m_selectedObjects.count( );
+ uint numOrdered = 0;
+ bool stop = false;
+
+ PMObject* tmp;
+ QPtrStack<PMObject> stack;
+
+ if( !m_sortedListUpToDate )
+ {
+ m_sortedSelectedObjects.clear( );
+
+ if( numObjects == 1 )
+ m_sortedSelectedObjects.append( m_selectedObjects.first( ) );
+ else if( numObjects > 1 )
+ {
+ tmp = m_pScene;
+ do
+ {
+ if( !tmp )
+ {
+ if( !stack.isEmpty( ) )
+ {
+ tmp = stack.pop( );
+ if( tmp == m_pScene )
+ stop = true;
+ else
+ tmp = tmp->nextSibling( );
+ }
+ else
+ stop = true;
+ }
+ else if( tmp->isSelected( ) )
+ {
+ m_sortedSelectedObjects.append( tmp );
+ numOrdered++;
+ tmp = tmp->nextSibling( );
+ }
+ else if( tmp->selectedChildren( ) > 0 )
+ {
+ stack.push( tmp );
+ tmp = tmp->firstChild( );
+ }
+ else
+ {
+ tmp = tmp->nextSibling( );
+ }
+ }
+ while( !stop && ( numOrdered < numObjects ) );
+ }
+ m_sortedListUpToDate = true;
+ }
+
+ return m_sortedSelectedObjects;
+}
+
+int PMPart::whereToInsert( PMObject* obj, const PMObjectList& list )
+{
+ // if you change this function, change
+ // whereToInsert( PMObject* obj, const QStringList& ), too
+
+ int canInsertAsFirstChild = 0;
+ int canInsertAsLastChild = 0;
+ int canInsertAsSibling = 0;
+
+ int insertAs = 0;
+ int insertPossibilities = 0;
+
+ if( !obj->isReadOnly( ) )
+ {
+ canInsertAsFirstChild = obj->canInsert( list, 0 );
+ if( obj->lastChild( ) )
+ canInsertAsLastChild = obj->canInsert( list, obj->lastChild( ) );
+
+ if( canInsertAsFirstChild > 0 )
+ {
+ // some objects can be inserted as child
+ insertAs |= PMInsertPopup::PMIFirstChild;
+ insertPossibilities++;
+ }
+ if( canInsertAsLastChild > 0 )
+ {
+ insertAs |= PMInsertPopup::PMILastChild;
+ insertPossibilities++;
+ }
+ }
+
+ if( obj->parent( ) )
+ {
+ PMObject* p = obj->parent( );
+ if( !p->isReadOnly( ) )
+ {
+ canInsertAsSibling = p->canInsert( list, obj );
+ if( canInsertAsSibling > 0 )
+ {
+ // some objects can be inserted as siblings
+ insertAs |= PMInsertPopup::PMISibling;
+ insertPossibilities++;
+ }
+ }
+ }
+
+ if( insertPossibilities > 1 )
+ {
+ int count = ( int ) list.count( );
+ // more than one possibilities, ask user
+ insertAs = PMInsertPopup::choosePlace(
+ widget( ), count > 1, insertAs,
+ canInsertAsFirstChild == count,
+ canInsertAsLastChild == count,
+ canInsertAsSibling == count );
+ }
+ else if( insertPossibilities == 0 )
+ insertAs = PMInsertPopup::PMIFirstChild;
+ return insertAs;
+}
+
+int PMPart::whereToInsert( PMObject* obj, const QStringList& list )
+{
+ // if you change this function, change
+ // whereToInsert( PMObject* obj, const PMObjectList ), too
+
+ int canInsertAsFirstChild = 0;
+ int canInsertAsLastChild = 0;
+ int canInsertAsSibling = 0;
+
+ int insertAs = 0;
+ int insertPossibilities = 0;
+
+ if( !obj->isReadOnly( ) )
+ {
+ canInsertAsFirstChild = obj->canInsert( list, 0 );
+ if( obj->lastChild( ) )
+ canInsertAsLastChild = obj->canInsert( list, obj->lastChild( ) );
+
+ if( canInsertAsFirstChild > 0 )
+ {
+ // some objects can be inserted as child
+ insertAs |= PMInsertPopup::PMIFirstChild;
+ insertPossibilities++;
+ }
+ if( canInsertAsLastChild > 0 )
+ {
+ insertAs |= PMInsertPopup::PMILastChild;
+ insertPossibilities++;
+ }
+ }
+
+ if( obj->parent( ) )
+ {
+ PMObject* p = obj->parent( );
+ if( !p->isReadOnly( ) )
+ {
+ canInsertAsSibling = p->canInsert( list, obj );
+ if( canInsertAsSibling > 0 )
+ {
+ // some objects can be inserted as siblings
+ insertAs |= PMInsertPopup::PMISibling;
+ insertPossibilities++;
+ }
+ }
+ }
+
+ if( insertPossibilities > 1 )
+ {
+ int count = ( int ) list.count( );
+ // more than one possibilities, ask user
+ insertAs = PMInsertPopup::choosePlace(
+ widget( ), count > 1, insertAs,
+ canInsertAsFirstChild == count,
+ canInsertAsLastChild == count,
+ canInsertAsSibling == count );
+ }
+ else if( insertPossibilities == 0 )
+ insertAs = PMInsertPopup::PMIFirstChild;
+ return insertAs;
+}
+
+int PMPart::whereToInsert( PMObject* obj )
+{
+ int insertAs = 0;
+ int insertPossibilities = 0;
+
+ if( obj->parent( ) )
+ {
+ insertAs |= PMInsertPopup::PMISibling;
+ insertPossibilities++;
+ }
+ if( obj->isA( "CompositeObject" ) )
+ {
+ insertAs |= PMInsertPopup::PMIFirstChild;
+ insertPossibilities++;
+ if( obj->firstChild( ) )
+ {
+ insertAs |= PMInsertPopup::PMILastChild;
+ insertPossibilities++;
+ }
+ }
+ if( insertAs && ( insertPossibilities > 1 ) )
+ insertAs = PMInsertPopup::choosePlace( widget( ), true, insertAs );
+
+ return insertAs;
+}
+
+void PMPart::slotFileImport( )
+{
+ QString fileName;
+ PMIOFormat* selectedFormat = 0;
+
+ fileName = PMFileDialog::getImportFileName( 0, this, selectedFormat );
+
+ if( !fileName.isEmpty( ) && selectedFormat )
+ {
+ QFile file( fileName );
+ if( file.open( IO_ReadOnly ) )
+ {
+ PMParser* newParser = selectedFormat->newParser( this, &file );
+ if( newParser )
+ {
+ if( m_pActiveObject )
+ insertFromParser( i18n( "Import %1" ).arg( selectedFormat->description( ) ),
+ newParser, m_pActiveObject );
+ else
+ insertFromParser( i18n( "Import %1" ).arg( selectedFormat->description( ) ),
+ newParser, m_pScene );
+ delete newParser;
+ }
+ }
+ else
+ {
+ KMessageBox::error( 0, tr( "Couldn't open the selected file\n"
+ "Permission denied!" ) );
+ }
+ }
+}
+
+void PMPart::slotFileExport( )
+{
+ emit aboutToSave( );
+
+ QString fileName, filter;
+ PMIOFormat* selectedFormat = 0;
+
+ fileName = PMFileDialog::getExportFileName( 0, this, selectedFormat, filter );
+
+ if( !fileName.isEmpty( ) && selectedFormat )
+ {
+ QByteArray baData;
+ QBuffer buffer( baData );
+ buffer.open( IO_WriteOnly );
+
+ PMSerializer* newSer = selectedFormat->newSerializer( &buffer );
+ if( newSer )
+ {
+ newSer->serialize( m_pScene );
+ newSer->close( );
+ bool success = !( newSer->warnings( ) || newSer->errors( ) );
+
+ if( !success )
+ {
+ // there were errors, display them
+ PMErrorDialog dlg( newSer->messages( ), newSer->errorFlags( ) );
+ // still try to export?
+ success = ( dlg.exec( ) == QDialog::Accepted );
+ }
+ if( success )
+ {
+ QFileInfo info( fileName );
+ if( info.extension( ).isEmpty( ) )
+ fileName += filter.right( filter.length( ) - 1 ); // remove '*'
+
+ QFile file( fileName );
+ if( file.open( IO_WriteOnly ) )
+ {
+ file.writeBlock( baData );
+ file.close( );
+ }
+ else
+ {
+ KMessageBox::error( 0, tr( "Couldn't export to the selected file\n"
+ "Permission denied!" ) );
+ }
+ }
+
+ delete newSer;
+ }
+ }
+}
+
+void PMPart::slotEditCut( )
+{
+ emit setStatusBarText( i18n( "Cutting selection..." ) );
+
+ const PMObjectList& sortedList = selectedObjects( );
+
+ if( sortedList.count( ) > 0 )
+ {
+ QApplication::clipboard( )->setData( new PMObjectDrag( this, sortedList ) );
+ removeSelection( i18n( "Cut" ) );
+ }
+
+ emit setStatusBarText( "" );
+}
+
+void PMPart::slotEditDelete( )
+{
+ emit setStatusBarText( i18n( "Deleting selection..." ) );
+
+ removeSelection( i18n( "Delete" ) );
+
+ emit setStatusBarText( "" );
+}
+
+void PMPart::slotEditCopy( )
+{
+ emit setStatusBarText( i18n( "Copying selection to clipboard..." ) );
+ const PMObjectList& sortedList = selectedObjects( );
+
+ if( sortedList.count( ) > 0 )
+ QApplication::clipboard( )->setData( new PMObjectDrag( this, sortedList ) );
+
+ emit setStatusBarText( "" );
+}
+
+bool PMPart::dragMoveSelectionTo( PMObject* obj )
+{
+ if( obj == 0 )
+ {
+ return removeSelection( i18n( "Drag" ) );
+ }
+ else
+ {
+ const PMObjectList& sortedList = selectedObjects( );
+ PMMoveCommand* command = 0;
+ int insertAs = whereToInsert( obj, sortedList );
+
+ if( insertAs > 0 )
+ {
+ PMObject* hlp;
+ bool stop;
+
+ switch( insertAs )
+ {
+ case PMInsertPopup::PMIFirstChild:
+ command = new PMMoveCommand( sortedList, obj, 0 );
+ break;
+ case PMInsertPopup::PMILastChild:
+ hlp = obj->lastChild( );
+ stop = false;
+
+ while( hlp && !stop )
+ {
+ if( hlp->isSelected( ) )
+ hlp = hlp->prevSibling( );
+ else
+ stop = true;
+ }
+ command = new PMMoveCommand( sortedList, obj, hlp );
+ break;
+ case PMInsertPopup::PMISibling:
+ command = new PMMoveCommand( sortedList, obj->parent( ), obj );
+ break;
+ }
+ }
+ if( command )
+ {
+ command->setText( i18n( "Drag" ) );
+ return executeCommand( command );
+ }
+ }
+ return false;
+}
+
+bool PMPart::removeSelection( const QString& type )
+{
+ PMDeleteCommand* cmd = 0;
+ const PMObjectList& sortedList = selectedObjects( );
+
+ if( sortedList.count( ) > 0 )
+ {
+ cmd = new PMDeleteCommand( sortedList );
+ cmd->setText( type );
+ return executeCommand( cmd );
+ }
+ return false;
+}
+
+bool PMPart::drop( PMObject* obj, QMimeSource* mime )
+{
+ return pasteOrDrop( i18n( "Drop" ), mime, obj );
+}
+
+void PMPart::slotEditPaste( )
+{
+ emit setStatusBarText( i18n( "Inserting clipboard contents..." ) );
+
+ pasteOrDrop( i18n( "Paste" ), qApp->clipboard( )->data( ),
+ m_pActiveObject );
+
+ emit setStatusBarText( "" );
+}
+
+bool PMPart::pasteOrDrop( const QString& type, QMimeSource* mime, PMObject* obj )
+{
+ bool success = false;
+
+ if( mime && obj)
+ {
+ PMParser* parser = PMObjectDrag::newParser( mime, this );
+
+ if( parser )
+ success = insertFromParser( type, parser, obj );
+ }
+ return success;
+}
+
+bool PMPart::insertFromParser( const QString& type, PMParser* parser,
+ PMObject* obj )
+{
+ PMObjectList list;
+ bool success = true;
+ int insertAs = 0;
+ PMAddCommand* command = 0;
+
+ // try to parse
+ if( parser->canQuickParse( ) )
+ {
+ QStringList types;
+ parser->quickParse( types );
+
+ success = !( parser->warnings( ) || parser->errors( ) );
+
+ if( !success )
+ {
+ // there were errors, display them
+ PMErrorDialog dlg( parser->messages( ), parser->errorFlags( ) );
+ // still try to insert the correct parsed objects?
+ success = ( dlg.exec( ) == QDialog::Accepted );
+ }
+ if( success && ( types.count( ) > 0 ) )
+ insertAs = whereToInsert( obj, types );
+ }
+ else
+ insertAs = whereToInsert( obj );
+
+ if( success && insertAs )
+ {
+ PMObject* parent = 0;
+ PMObject* after = 0;
+
+ switch( insertAs )
+ {
+ case PMInsertPopup::PMIFirstChild:
+ parent = obj;
+ after = 0;
+ break;
+ case PMInsertPopup::PMILastChild:
+ parent = obj;
+ after = obj->lastChild( );
+ break;
+ case PMInsertPopup::PMISibling:
+ parent = obj->parent( );
+ after = obj;
+ break;
+ default:
+ parent = obj;
+ after = 0;
+ break;
+ }
+
+ parser->parse( &list, parent, after );
+ success = !( parser->warnings( ) || parser->errors( ) );
+
+ if( !success )
+ {
+ // there were errors, display them
+ PMErrorDialog dlg( parser->messages( ), parser->errorFlags( ) );
+ // still try to insert the correct parsed objects?
+ success = ( dlg.exec( ) == QDialog::Accepted );
+ }
+
+ if( list.count( ) > 0 )
+ {
+ if( success )
+ {
+ // parsing was successful
+ command = new PMAddCommand( list, parent, after );
+
+ command->setText( type );
+ success = executeCommand( command );
+ }
+ else
+ {
+ // parsed objects will not be inserted
+ // remove all links
+ PMObjectListIterator it( list );
+ PMDeclare* decl = 0;
+
+ for( ; it.current( ); ++it )
+ {
+ PMRecursiveObjectIterator rit( it.current( ) );
+ for( ; rit.current( ); ++rit )
+ {
+ decl = rit.current( )->linkedObject( );
+ if( decl )
+ decl->removeLinkedObject( rit.current( ) );
+ }
+ }
+ }
+ }
+ }
+ if( !command )
+ {
+ // delete all parsed objects
+ list.setAutoDelete( true );
+ list.clear( );
+ }
+
+ return success && insertAs;
+}
+
+void PMPart::slotEditUndo( )
+{
+ emit setStatusBarText( i18n( "Undo last change..." ) );
+ m_pNewSelection = 0;
+ m_updateNewObjectActions = false;
+
+ m_commandManager.undo( );
+
+ if( m_pNewSelection )
+ slotObjectChanged( m_pNewSelection, PMCNewSelection, this );
+ if( !isModified( ) )
+ setModified( true );
+ if( m_updateNewObjectActions )
+ updateNewObjectActions( );
+
+ emit setStatusBarText( "" );
+}
+
+void PMPart::slotEditRedo( )
+{
+ emit setStatusBarText( i18n( "Redo last change..." ) );
+ m_pNewSelection = 0;
+ m_updateNewObjectActions = false;
+
+ m_commandManager.redo( );
+ if( m_pNewSelection )
+ slotObjectChanged( m_pNewSelection, PMCNewSelection, this );
+ if( !isModified( ) )
+ setModified( true );
+ if( m_updateNewObjectActions )
+ updateNewObjectActions( );
+
+ emit setStatusBarText( "" );
+}
+
+bool PMPart::executeCommand( PMCommand* cmd )
+{
+ m_pNewSelection = 0;
+ m_numAddedObjects = 0;
+ m_numInsertErrors = 0;
+ m_insertErrorDetails.clear( );
+ m_updateNewObjectActions = false;
+
+ if( isReadWrite( ) && cmd )
+ {
+ bool execute = true;
+ int flags = cmd->errorFlags( this );
+
+ if( flags )
+ {
+ PMErrorDialog dlg( cmd->messages( ), flags );
+ execute = ( dlg.exec( ) == QDialog::Accepted );
+ }
+
+ if( execute )
+ {
+ m_commandManager.execute( cmd );
+ if( m_pNewSelection )
+ slotObjectChanged( m_pNewSelection, PMCNewSelection, this );
+ if( !isModified( ) )
+ setModified( true );
+
+ if( m_numInsertErrors > 0 )
+ {
+ m_insertErrorDetails.sort( );
+ PMInsertErrorDialog dlg( m_numAddedObjects, m_numInsertErrors,
+ m_insertErrorDetails );
+ dlg.exec( );
+ }
+ if( m_updateNewObjectActions )
+ updateNewObjectActions( );
+
+ return true;
+ }
+ }
+
+ delete cmd;
+ return false;
+}
+
+void PMPart::slotObjectChanged( PMObject* obj, const int m,
+ QObject* sender )
+{
+ int mode = m;
+ bool selectionChanged = false;
+ bool changeControlPoints = false;
+ PMObject* oldActive = m_pActiveObject;
+
+ if( mode & PMCNewSelection )
+ {
+ if( !obj )
+ {
+ clearSelection( );
+ selectionChanged = true;
+ m_pActiveObject = 0;
+ }
+ else
+ {
+ clearSelection( );
+ obj->setSelected( true );
+ m_selectedObjects.append( obj );
+ selectionChanged = true;
+ m_pActiveObject = obj;
+ }
+ }
+ else if( ( mode & PMCSelected ) && !obj->isSelected( ) )
+ {
+ if( obj->isSelectable( ) )
+ {
+ if( obj->selectedChildren( ) > 0 )
+ {
+ QPtrStack<PMObject> stack;
+ PMObject* tmp = obj->firstChild( );
+ bool stop = false;
+
+ do
+ {
+ if( !tmp )
+ {
+ if( !stack.isEmpty( ) )
+ {
+ tmp = stack.pop( );
+ if( tmp == obj )
+ stop = true;
+ else
+ tmp = tmp->nextSibling( );
+ }
+ else
+ stop = true;
+ }
+ else if( tmp->isSelected( ) )
+ {
+ tmp->setSelected( false );
+ m_selectedObjects.removeRef( tmp );
+ emit objectChanged( tmp, PMCDeselected, this );
+ tmp = tmp->nextSibling( );
+ }
+ else if( tmp->selectedChildren( ) > 0 )
+ {
+ stack.push( tmp );
+ tmp = tmp->firstChild( );
+ }
+ else
+ {
+ tmp = tmp->nextSibling( );
+ }
+ }
+ while( !stop );
+ }
+
+ obj->setSelected( true );
+ m_selectedObjects.append( obj );
+ selectionChanged = true;
+ m_sortedListUpToDate = false;
+ m_sortedSelectedObjects.clear( );
+ m_pActiveObject = 0;
+ }
+ else
+ {
+ kdError( PMArea ) << "(PMPart::slotObjectChanged) object is not selectable!" << "\n";
+ mode = mode & ( ~( PMCSelected | PMCNewSelection ) );
+ }
+ }
+ else if( mode & PMCDeselected )
+ {
+ // no problems here
+ m_selectedObjects.removeRef( obj );
+ obj->setSelected( false );
+ m_sortedListUpToDate = false;
+ m_sortedSelectedObjects.clear( );
+ selectionChanged = true;
+ m_pActiveObject = 0;
+ }
+
+ if( mode & PMCRemove )
+ {
+ if( obj->parent( ) )
+ if( obj->parent( ) == m_pActiveObject )
+ m_updateNewObjectActions = true;
+ if( m_pNewSelection == obj )
+ {
+ if( obj->nextSibling( ) )
+ m_pNewSelection = obj->nextSibling( );
+ else if( obj->prevSibling( ) )
+ m_pNewSelection = obj->nextSibling( );
+ else if( obj->parent( ) )
+ m_pNewSelection = obj->parent( );
+ else
+ m_pNewSelection = 0;
+ }
+ if( m_selectedObjects.containsRef( obj ) )
+ {
+ m_selectedObjects.removeRef( obj );
+ if( m_selectedObjects.isEmpty( ) )
+ {
+ if( obj->nextSibling( ) )
+ m_pNewSelection = obj->nextSibling( );
+ else if( obj->prevSibling( ) )
+ m_pNewSelection = obj->prevSibling( );
+ else if( obj->parent( ) )
+ m_pNewSelection = obj->parent( );
+ else
+ m_pNewSelection = 0;
+ }
+ m_sortedListUpToDate = false;
+ m_sortedSelectedObjects.clear( );
+ selectionChanged = true;
+ }
+ if( m_pActiveObject == obj )
+ m_pActiveObject = 0;
+
+ if( obj->isA( "Declare" ) )
+ {
+ PMDeclare* decl = ( PMDeclare* ) obj;
+ m_pSymbolTable->remove( decl->id( ) );
+ }
+
+ if( obj->type( ) == "Camera" )
+ m_cameras.removeRef( ( PMCamera* ) obj );
+ }
+
+ if( mode & PMCAdd )
+ {
+ if( !( mode & PMCInsertError ) )
+ {
+ m_pNewSelection = obj;
+ if( obj->isA( "Declare" ) )
+ {
+ PMDeclare* decl = ( PMDeclare* ) obj;
+ PMSymbol* s = m_pSymbolTable->find( decl->id( ) );
+ if( !s )
+ m_pSymbolTable->insert( decl->id( ),
+ new PMSymbol( decl->id( ), decl ) );
+ }
+ if( obj->type( ) == "Camera" )
+ m_bCameraListUpToDate = false;
+ }
+ if( obj->parent( ) )
+ if( obj->parent( ) == m_pActiveObject )
+ m_updateNewObjectActions = true;
+ m_numAddedObjects++;
+ }
+
+ if( mode & PMCData )
+ {
+ m_updateNewObjectActions = true;
+ }
+
+ if( mode & PMCViewStructure )
+ {
+ changeControlPoints = true;
+ }
+
+ if( mode & PMCInsertError )
+ {
+ m_numInsertErrors++;
+ QString detail;
+ detail = obj->description( ) + QString( " " ) + obj->name( );
+ m_insertErrorDetails.append( detail );
+
+ if( obj->isA( "Declare" ) )
+ {
+ PMDeclare* decl = ( PMDeclare* ) obj;
+ m_pSymbolTable->remove( decl->id( ) );
+ }
+ }
+
+ if( selectionChanged )
+ {
+ m_sortedListUpToDate = false;
+ m_sortedSelectedObjects.clear( );
+
+ int c = m_selectedObjects.count( );
+
+ if( m_pScene->isSelected( ) )
+ c = m_pScene->countChildren( );
+
+ m_pCopyAction->setEnabled( c > 0 );
+
+ if( isReadWrite( ) )
+ {
+ m_pCutAction->setEnabled( c > 0 );
+ m_pDeleteAction->setEnabled( c > 0 );
+ m_pPasteAction->setEnabled( m_pActiveObject && m_canDecode );
+ updateNewObjectActions( );
+ }
+ }
+
+ if( ( oldActive != m_pActiveObject ) || changeControlPoints )
+ {
+ updateControlPoints( oldActive );
+ emit objectChanged( m_pActiveObject, PMCNewControlPoints, this );
+ mode |= ( PMCNewControlPoints | PMCControlPointSelection );
+ }
+
+ emit objectChanged( obj, mode, sender );
+}
+
+void PMPart::slotIDChanged( PMObject* obj, const QString& oldID )
+{
+ if( obj->isA( "Declare" ) )
+ {
+ PMDeclare* d = ( PMDeclare* ) obj;
+ PMSymbol* s = m_pSymbolTable->find( oldID );
+ if( s )
+ {
+ if( s->type( ) == PMSymbol::Object )
+ {
+ if( s->object( ) == obj )
+ {
+ m_pSymbolTable->take( oldID );
+ s->setId( d->id( ) );
+ m_pSymbolTable->insert( s->id( ), s );
+ }
+ else
+ kdError( PMArea ) << "PMPart::slotIDChanged: Symbol "
+ << oldID << " points to wrong object.\n";
+ }
+ else
+ kdError( PMArea ) << "PMPart::slotIDChanged: Symbol "
+ << oldID << " has wrong type.\n";
+ }
+ else
+ kdError( PMArea ) << "PMPart::slotIDChanged: Symbol "
+ << oldID << " not found.\n";
+ }
+}
+
+void PMPart::slotNewObject( PMObject* newObject, int insertAs )
+{
+ PMObjectList list;
+ list.append( newObject );
+ PMCommand* command = 0;
+
+ if( m_pActiveObject )
+ {
+ // If no position was specified ask the user
+ if( insertAs <= 0 )
+ insertAs = whereToInsert( m_pActiveObject, list );
+ // If either through a parameter or by user action a position was selected
+ if( insertAs > 0 )
+ {
+ // insert the object in the position indicated
+ switch( insertAs )
+ {
+ case PMInsertPopup::PMIFirstChild:
+ command = new PMAddCommand( list, m_pActiveObject, 0 );
+ break;
+ case PMInsertPopup::PMILastChild:
+ command = new PMAddCommand( list, m_pActiveObject,
+ m_pActiveObject->lastChild( ) );
+ break;
+ case PMInsertPopup::PMISibling:
+ command = new PMAddCommand( list,
+ m_pActiveObject->parent( ),
+ m_pActiveObject );
+ break;
+ default:
+ command = new PMAddCommand( list, m_pActiveObject, 0 );
+ break;
+ }
+ executeCommand( command );
+ }
+ else
+ {
+ list.clear( );
+ delete newObject;
+ }
+ }
+ else
+ {
+ list.clear( );
+ delete newObject;
+ }
+}
+
+void PMPart::slotNewObject( const QString& type )
+{
+ PMObject* newObject = m_pPrototypeManager->newObject( type );
+ if( newObject )
+ slotNewObject( newObject );
+}
+
+void PMPart::slotNewObject( const QString& type, const QString& pos )
+{
+ PMObject* newObject = m_pPrototypeManager->newObject( type );
+ if( newObject )
+ {
+ if( pos == "FirstChild" )
+ slotNewObject( newObject, PMInsertPopup::PMIFirstChild );
+ else if( pos == "LastChild" )
+ slotNewObject( newObject, PMInsertPopup::PMILastChild );
+ else if( pos == "Sibling" )
+ slotNewObject( newObject, PMInsertPopup::PMISibling );
+ else
+ slotNewObject( newObject );
+ }
+}
+
+QStringList PMPart::getObjectTypes( )
+{
+ QStringList result;
+ QPtrListIterator<PMMetaObject> it = m_pPrototypeManager->prototypeIterator( );
+
+ for( ; it.current( ); ++it )
+ {
+ result.append( it.current( )->className( ) );
+ }
+ return result;
+}
+
+void PMPart::slotNewTransformedObject( PMObject* o )
+{
+ if( o )
+ {
+ if( o->canInsert( QString( "Scale" ), o->lastChild( ) ) )
+ o->appendChild( new PMScale( this ) );
+ if( o->canInsert( QString( "Rotate" ), o->lastChild( ) ) )
+ o->appendChild( new PMRotate( this ) );
+ if( o->canInsert( QString( "Translate" ), o->lastChild( ) ) )
+ o->appendChild( new PMTranslate( this ) );
+ slotNewObject( o );
+ }
+}
+
+void PMPart::slotNewGlobalSettings( )
+{
+ slotNewObject( new PMGlobalSettings( this ) );
+}
+
+void PMPart::slotNewSkySphere( )
+{
+ slotNewObject( new PMSkySphere( this ) );
+}
+
+void PMPart::slotNewRainbow( )
+{
+ slotNewObject( new PMRainbow( this ) );
+}
+
+void PMPart::slotNewFog( )
+{
+ slotNewObject( new PMFog( this ) );
+}
+
+void PMPart::slotNewInterior( )
+{
+ slotNewObject( new PMInterior( this ) );
+}
+
+void PMPart::slotNewMedia( )
+{
+ slotNewObject( new PMMedia( this ) );
+}
+
+void PMPart::slotNewDensity( )
+{
+ slotNewObject( new PMDensity( this ) );
+}
+
+void PMPart::slotNewMaterial( )
+{
+ slotNewObject( new PMMaterial( this ) );
+}
+
+void PMPart::slotNewBox( )
+{
+ slotNewTransformedObject( new PMBox( this ) );
+}
+
+void PMPart::slotNewSphere( )
+{
+ slotNewTransformedObject( new PMSphere( this ) );
+}
+
+void PMPart::slotNewCylinder( )
+{
+ slotNewTransformedObject( new PMCylinder( this ) );
+}
+
+void PMPart::slotNewPlane( )
+{
+ slotNewTransformedObject( new PMPlane( this ) );
+}
+
+void PMPart::slotNewPolynom( )
+{
+ slotNewTransformedObject( new PMPolynom( this ) );
+}
+
+void PMPart::slotNewCone( )
+{
+ slotNewTransformedObject( new PMCone( this ) );
+}
+
+void PMPart::slotNewTorus( )
+{
+ slotNewTransformedObject( new PMTorus( this ) );
+}
+
+void PMPart::slotNewLathe( )
+{
+ slotNewTransformedObject( new PMLathe( this ) );
+}
+
+void PMPart::slotNewPrism( )
+{
+ slotNewTransformedObject( new PMPrism( this ) );
+}
+
+void PMPart::slotNewSurfaceOfRevolution( )
+{
+ slotNewTransformedObject( new PMSurfaceOfRevolution( this ) );
+}
+
+void PMPart::slotNewSuperquadricEllipsoid( )
+{
+ slotNewTransformedObject( new PMSuperquadricEllipsoid( this ) );
+}
+
+void PMPart::slotNewJuliaFractal( )
+{
+ slotNewTransformedObject( new PMJuliaFractal( this ) );
+}
+
+void PMPart::slotNewHeightField( )
+{
+ slotNewTransformedObject( new PMHeightField( this ) );
+}
+
+void PMPart::slotNewText( )
+{
+ slotNewTransformedObject( new PMText( this ) );
+}
+
+void PMPart::slotNewBlob( )
+{
+ slotNewTransformedObject( new PMBlob( this ) );
+}
+
+void PMPart::slotNewBlobSphere( )
+{
+ slotNewObject( new PMBlobSphere( this ) );
+}
+
+void PMPart::slotNewBlobCylinder( )
+{
+ slotNewObject( new PMBlobCylinder( this ) );
+}
+
+void PMPart::slotNewDeclare( )
+{
+ PMDeclare* obj = new PMDeclare( this );
+ m_pSymbolTable->findNewID( i18n( "Declare" ), obj );
+ slotNewObject( obj );
+}
+
+void PMPart::slotNewObjectLink( )
+{
+ slotNewTransformedObject( new PMObjectLink( this ) );
+}
+
+void PMPart::slotNewUnion( )
+{
+ slotNewObject( new PMCSG( this, PMCSG::CSGUnion ) );
+}
+
+void PMPart::slotNewDifference( )
+{
+ slotNewObject( new PMCSG( this, PMCSG::CSGDifference ) );
+}
+
+void PMPart::slotNewIntersection( )
+{
+ slotNewObject( new PMCSG( this, PMCSG::CSGIntersection ) );
+}
+
+void PMPart::slotNewMerge( )
+{
+ slotNewObject( new PMCSG( this, PMCSG::CSGMerge ) );
+}
+
+void PMPart::slotNewBoundedBy( )
+{
+ slotNewObject( new PMBoundedBy( this ) );
+}
+
+void PMPart::slotNewClippedBy( )
+{
+ slotNewObject( new PMClippedBy( this ) );
+}
+
+void PMPart::slotNewLight( )
+{
+ slotNewObject( new PMLight( this ) );
+}
+
+void PMPart::slotNewLooksLike( )
+{
+ slotNewObject( new PMLooksLike( this ) );
+}
+
+void PMPart::slotNewProjectedThrough( )
+{
+ slotNewObject( new PMProjectedThrough( this ) );
+}
+
+void PMPart::slotNewDisc( )
+{
+ slotNewTransformedObject( new PMDisc( this ) );
+}
+
+void PMPart::slotNewBicubicPatch( )
+{
+ slotNewTransformedObject( new PMBicubicPatch( this ) );
+}
+
+void PMPart::slotNewTriangle( )
+{
+ slotNewObject( new PMTriangle( this ) );
+}
+
+void PMPart::slotNewCamera( )
+{
+ PMCamera* c = new PMCamera( this );
+ c->setAngle( 45.0 );
+ c->setLocation( PMVector( 5.0, 5.0, -5.0 ) );
+ c->setLookAt( PMVector( 0.0, 0.0, 0.0 ) );
+
+ slotNewObject( c );
+}
+
+void PMPart::slotNewTexture( )
+{
+ slotNewObject( new PMTexture( this ) );
+}
+
+void PMPart::slotNewPigment( )
+{
+ slotNewObject( new PMPigment( this ) );
+}
+
+void PMPart::slotNewNormal( )
+{
+ slotNewObject( new PMNormal( this ) );
+}
+
+void PMPart::slotNewSolidColor( )
+{
+ slotNewObject( new PMSolidColor( this ) );
+}
+
+void PMPart::slotNewTextureList( )
+{
+ slotNewObject( new PMTextureList( this ) );
+}
+
+void PMPart::slotNewColorList( )
+{
+ slotNewObject( new PMColorList( this ) );
+}
+
+void PMPart::slotNewPigmentList( )
+{
+ slotNewObject( new PMPigmentList( this ) );
+}
+
+void PMPart::slotNewNormalList( )
+{
+ slotNewObject( new PMNormalList( this ) );
+}
+
+void PMPart::slotNewDensityList( )
+{
+ slotNewObject( new PMDensityList( this ) );
+}
+
+void PMPart::slotNewFinish( )
+{
+ slotNewObject( new PMFinish( this ) );
+}
+
+void PMPart::slotNewWarp( )
+{
+ slotNewObject( new PMWarp( this ) );
+}
+
+void PMPart::slotNewImageMap( )
+{
+ slotNewObject( new PMImageMap( this ) );
+}
+
+void PMPart::slotNewPattern( )
+{
+ slotNewObject( new PMPattern( this ) );
+}
+
+void PMPart::slotNewBlendMapModifiers( )
+{
+ slotNewObject( new PMBlendMapModifiers( this ) );
+}
+
+void PMPart::slotNewTextureMap( )
+{
+ slotNewObject( new PMTextureMap( this ) );
+}
+
+void PMPart::slotNewMaterialMap( )
+{
+ slotNewObject( new PMMaterialMap( this ) );
+}
+
+void PMPart::slotNewColorMap( )
+{
+ slotNewObject( new PMColorMap( this ) );
+}
+
+void PMPart::slotNewPigmentMap( )
+{
+ slotNewObject( new PMPigmentMap( this ) );
+}
+
+void PMPart::slotNewNormalMap( )
+{
+ slotNewObject( new PMNormalMap( this ) );
+}
+
+void PMPart::slotNewBumpMap( )
+{
+ slotNewObject( new PMBumpMap( this ) );
+}
+
+void PMPart::slotNewSlopeMap( )
+{
+ slotNewObject( new PMSlopeMap( this ) );
+}
+
+void PMPart::slotNewDensityMap( )
+{
+ slotNewObject( new PMDensityMap( this ) );
+}
+
+void PMPart::slotNewSlope( )
+{
+ slotNewObject( new PMSlope( this ) );
+}
+
+void PMPart::slotNewQuickColor( )
+{
+ slotNewObject( new PMQuickColor( this ) );
+}
+
+void PMPart::slotNewTranslate( )
+{
+ slotNewObject( new PMTranslate( this ) );
+}
+
+void PMPart::slotNewScale( )
+{
+ slotNewObject( new PMScale( this ) );
+}
+
+void PMPart::slotNewRotate( )
+{
+ slotNewObject( new PMRotate( this ) );
+}
+
+void PMPart::slotNewMatrix( )
+{
+ slotNewObject( new PMPovrayMatrix( this ) );
+}
+
+void PMPart::slotNewComment( )
+{
+ slotNewObject( new PMComment( this ) );
+}
+
+void PMPart::slotNewRaw( )
+{
+ slotNewObject( new PMRaw( this ) );
+}
+
+// POV-Ray 3.5 objects
+
+void PMPart::slotNewIsoSurface( )
+{
+ slotNewObject( new PMIsoSurface( this ) );
+}
+
+void PMPart::slotNewRadiosity( )
+{
+ slotNewObject( new PMRadiosity( this ) );
+}
+
+void PMPart::slotNewGlobalPhotons( )
+{
+ slotNewObject( new PMGlobalPhotons( this ) );
+}
+
+void PMPart::slotNewPhotons( )
+{
+ slotNewObject( new PMPhotons( this ) );
+}
+
+void PMPart::slotNewLightGroup( )
+{
+ slotNewObject( new PMLightGroup( this ) );
+}
+
+void PMPart::slotNewInteriorTexture( )
+{
+ slotNewObject( new PMInteriorTexture( this ) );
+}
+
+void PMPart::slotNewSphereSweep( )
+{
+ slotNewObject( new PMSphereSweep( this ) );
+}
+
+void PMPart::slotNewMesh( )
+{
+ slotNewObject( new PMMesh( this ) );
+}
+
+void PMPart::slotSearchLibraryObject( )
+{
+ PMLibraryObjectSearch* aux = new PMLibraryObjectSearch( NULL );
+ aux->show( );
+}
+
+void PMPart::slotClipboardDataChanged( )
+{
+ if( isReadWrite( ) )
+ {
+ m_canDecode = PMObjectDrag::canDecode( qApp->clipboard( )->data( ), this );
+ m_pPasteAction->setEnabled( m_canDecode && m_pActiveObject );
+ }
+ else
+ m_pPasteAction->setEnabled( false );
+}
+
+void PMPart::clearSelection( )
+{
+ PMObjectListIterator it( m_selectedObjects );
+
+ if( it.current( ) )
+ {
+ if( it.current( )->nextSibling( ) )
+ m_pNewSelection = it.current( )->nextSibling( );
+ else if( it.current( )->prevSibling( ) )
+ m_pNewSelection = it.current( )->prevSibling( );
+ else if( it.current( )->parent( ) )
+ m_pNewSelection = it.current( )->parent( );
+
+ for( ; it.current( ); ++it )
+ {
+ it.current( )->setSelected( false );
+ if( m_pNewSelection == it.current( ) )
+ {
+ if( it.current( )->nextSibling( ) )
+ m_pNewSelection = it.current( )->nextSibling( );
+ else if( it.current( )->prevSibling( ) )
+ m_pNewSelection = it.current( )->prevSibling( );
+ else if( it.current( )->parent( ) )
+ m_pNewSelection = it.current( )->parent( );
+ }
+ }
+ }
+
+ m_selectedObjects.clear( );
+ m_sortedListUpToDate = true;
+}
+
+bool PMPart::newDocument( )
+{
+ deleteContents( );
+ setModified( false );
+
+ m_pScene = new PMScene( this );
+
+ PMGlobalSettings* gs = new PMGlobalSettings( this );
+ gs->setAssumedGamma( 1.5 );
+ m_pScene->appendChild( gs );
+
+ PMBox* b = new PMBox( this );
+ m_pScene->appendChild( b );
+ PMPigment* p = new PMPigment( this );
+ b->appendChild( p );
+ PMSolidColor* c = new PMSolidColor( this );
+ c->setColor( PMColor( 0.3, 1.0, 0.3 ) );
+ p->appendChild( c );
+ PMScale* s = new PMScale( this );
+ b->appendChild( s );
+ PMRotate* r = new PMRotate( this );
+ b->appendChild( r );
+ PMTranslate* t = new PMTranslate( this );
+ t->setTranslation( PMVector( 0, 0.5, 0 ) );
+ b->appendChild( t );
+
+ PMLight* l = new PMLight( this );
+ l->setLocation( PMVector( 4.0, 5.0, -5.0 ) );
+ m_pScene->appendChild( l );
+ PMCamera* ca = new PMCamera( this );
+ ca->setAngle( 45.0 );
+ ca->setLocation( PMVector( 5.0, 5.0, -5.0 ) );
+ ca->setLookAt( PMVector( 0.0, 0.0, 0.0 ) );
+ m_pScene->appendChild( ca );
+ m_bCameraListUpToDate = false;
+
+ m_pScene->setReadOnly( !isReadWrite( ) );
+ PMRenderMode* mode = new PMRenderMode( );
+ mode->setDescription( i18n( "Default" ) );
+ m_pScene->renderModes( )->append( mode );
+
+ emit refresh( );
+ updateRenderModes( );
+ updateVisibilityLevel( );
+ slotObjectChanged( m_pScene, PMCNewSelection, this );
+
+ return true;
+}
+
+void PMPart::closeDocument( )
+{
+ m_url = KURL( );
+}
+
+void PMPart::deleteContents( )
+{
+ emit clear( );
+ if( isReadWrite( ) )
+ m_commandManager.clear( );
+ m_selectedObjects.clear( );
+ m_sortedSelectedObjects.clear( );
+ m_sortedListUpToDate = true;
+ m_pActiveObject = 0;
+ m_pNewSelection = 0;
+
+ if( m_pScene )
+ {
+ delete m_pScene;
+ m_pScene = 0;
+ }
+ if( m_pSymbolTable )
+ delete m_pSymbolTable;
+
+ m_pSymbolTable = new PMSymbolTable( );
+ m_cameras.clear( );
+ m_bCameraListUpToDate = true;
+}
+
+void PMPart::slotUpdateUndoRedo( const QString& undo, const QString& redo )
+{
+ if( isReadWrite( ) )
+ {
+ if( m_pUndoAction )
+ {
+ if( undo.isNull( ) )
+ {
+ m_pUndoAction->setText( i18n( "Undo" ) );
+ m_pUndoAction->setEnabled( false );
+ }
+ else
+ {
+ m_pUndoAction->setText( i18n( "Undo" ) + " " + undo );
+ m_pUndoAction->setEnabled( true );
+ }
+ }
+ if( m_pRedoAction )
+ {
+ if( redo.isNull( ) )
+ {
+ m_pRedoAction->setText( i18n( "Redo" ) );
+ m_pRedoAction->setEnabled( false );
+ }
+ else
+ {
+ m_pRedoAction->setText( i18n( "Redo" ) + " " + redo );
+ m_pRedoAction->setEnabled( true );
+ }
+ }
+ }
+}
+
+void PMPart::setScene( PMScene* scene )
+{
+ deleteContents( );
+ m_pScene = scene;
+ emit refresh( );
+ slotObjectChanged( m_pScene, PMCNewSelection, this );
+}
+
+void PMPart::setModified( )
+{
+ KParts::ReadWritePart::setModified( );
+ emit modified( );
+}
+
+void PMPart::setModified( bool m )
+{
+ KParts::ReadWritePart::setModified( m );
+ emit modified( );
+}
+
+PMCamera* PMPart::firstCamera( )
+{
+ if( !m_bCameraListUpToDate )
+ updateCameraList( );
+ return m_cameras.first( );
+}
+
+QPtrListIterator<PMCamera> PMPart::cameras( )
+{
+ if( !m_bCameraListUpToDate )
+ updateCameraList( );
+ return QPtrListIterator<PMCamera>( m_cameras );
+}
+
+void PMPart::updateCameraList( )
+{
+ m_cameras.clear( );
+ PMObject* obj;
+ for( obj = m_pScene->firstChild( ); obj; obj = obj->nextSibling( ) )
+ if( obj->type( ) == "Camera" )
+ m_cameras.append( ( PMCamera* ) obj );
+ m_bCameraListUpToDate = true;
+}
+
+void PMPart::slotRender( )
+{
+ PMRenderMode* m = m_pScene->renderModes( )->current( );
+ if( m )
+ {
+ emit aboutToRender( );
+
+ QByteArray a;
+ QBuffer buffer( a );
+ buffer.open( IO_WriteOnly );
+ PMPovray35Format format;
+ PMSerializer* dev = format.newSerializer( &buffer );
+ dev->serialize( m_pScene );
+ delete dev;
+
+ if( !m_pPovrayWidget )
+ m_pPovrayWidget = new PMPovrayWidget( );
+ if( m_pPovrayWidget->render( a, *m, url( ) ) )
+ {
+ m_pPovrayWidget->show( );
+ m_pPovrayWidget->raise( );
+ }
+ }
+}
+
+void PMPart::slotRenderSettings( )
+{
+ PMRenderModesDialog dlg( m_pScene->renderModes( ), widget( ) );
+ int result = dlg.exec( );
+
+ if( result == QDialog::Accepted )
+ {
+ if( isReadWrite( ) )
+ setModified( true );
+ updateRenderModes( );
+ }
+}
+
+void PMPart::slotViewRenderWindow( )
+{
+ if( !m_pPovrayWidget )
+ m_pPovrayWidget = new PMPovrayWidget( );
+ m_pPovrayWidget->show( );
+ m_pPovrayWidget->raise( );
+}
+
+void PMPart::slotRenderMode( int index )
+{
+ PMRenderModeList* list = m_pScene->renderModes( );
+ list->at( index );
+ emit activeRenderModeChanged( );
+}
+
+void PMPart::updateRenderModes( )
+{
+ if( m_pScene )
+ {
+ PMRenderModeList* list = m_pScene->renderModes( );
+ PMRenderModeListIterator it( *list );
+
+ QComboBox* box = m_pRenderComboAction->combo( );
+ if( box )
+ {
+ bool b = box->signalsBlocked( );
+ box->blockSignals( true );
+ box->clear( );
+
+ for( ; it.current( ); ++it )
+ box->insertItem( it.current( )->description( ) );
+ box->setCurrentItem( list->at( ) );
+ box->updateGeometry( );
+
+ box->blockSignals( b );
+ }
+ emit activeRenderModeChanged( );
+ }
+}
+
+void PMPart::slotRenderModeActionPlugged( )
+{
+ updateRenderModes( );
+// connect( m_pRenderComboAction->combo( ), SIGNAL( activated( int ) ),
+// SLOT( slotRenderMode( int ) ) );
+}
+
+void PMPart::slotVisibilityLevelChanged( int l )
+{
+ if( m_pScene->visibilityLevel( ) != l )
+ {
+ m_pScene->setVisibilityLevel( l );
+ if( isReadWrite( ) )
+ setModified( true );
+ emit objectChanged( m_pScene, PMCViewStructure, this );
+ }
+}
+
+void PMPart::slotVisibilityActionPlugged( )
+{
+ if( m_pVisibilityLevelAction )
+ {
+ QSpinBox* box = m_pVisibilityLevelAction->spinBox( );
+ if( box )
+ {
+ box->setMinValue( -1000 );
+ box->setMaxValue( 1000 );
+ updateVisibilityLevel( );
+ }
+ }
+}
+
+void PMPart::updateVisibilityLevel( )
+{
+ if( m_pVisibilityLevelAction )
+ {
+ QSpinBox* box = m_pVisibilityLevelAction->spinBox( );
+ if( box && m_pScene )
+ {
+ bool sb = box->signalsBlocked( );
+ box->blockSignals( true );
+ box->setValue( m_pScene->visibilityLevel( ) );
+ box->blockSignals( sb );
+ }
+ }
+}
+
+void PMPart::slotGlobalDetailLevelChanged( int level )
+{
+ PMDetailObject::setGlobalDetailLevel( level + 1 );
+ emit objectChanged( m_pScene, PMCViewStructure, this );
+}
+
+void PMPart::updateControlPoints( PMObject* oldActive )
+{
+ PMControlPointList newCPs;
+
+ if( m_pActiveObject )
+ {
+ m_pActiveObject->controlPoints( newCPs );
+
+ if( m_pActiveObject == oldActive )
+ {
+ // check if the control points are the same
+ bool same = true;
+ PMControlPointListIterator oit( m_controlPoints );
+ PMControlPointListIterator nit( newCPs );
+ while( same && oit.current( ) && nit.current( ) )
+ {
+ if( oit.current( )->id( ) != nit.current( )->id( ) )
+ same = false;
+ ++oit;
+ ++nit;
+ }
+ if( oit.current( ) || nit.current( ) )
+ same = false;
+ if( same )
+ {
+ // set the old selection
+ oit.toFirst( );
+ nit.toFirst( );
+ while( oit.current( ) && nit.current( ) )
+ {
+ nit.current( )->setSelected( oit.current( )->selected( ) );
+ ++oit;
+ ++nit;
+ }
+ }
+ }
+ }
+
+ m_controlPoints.clear( );
+ m_controlPoints = newCPs;
+
+}
+
+void PMPart::slotAboutToSave( )
+{
+ emit aboutToSave( );
+}
+
+#include "pmpart.moc"
diff --git a/kpovmodeler/pmpart.h b/kpovmodeler/pmpart.h
new file mode 100644
index 00000000..e0ebcd06
--- /dev/null
+++ b/kpovmodeler/pmpart.h
@@ -0,0 +1,1041 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPART_H
+#define PMPART_H
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kapplication.h>
+#include <kaccel.h>
+#include <kurl.h>
+#include <kparts/part.h>
+#include <kparts/browserextension.h>
+#include <qstringlist.h>
+#include <qptrlist.h>
+#include <qvaluelist.h>
+#include <kglobal.h>
+#include <klocale.h>
+
+#include "pmobject.h"
+#include "pmcommandmanager.h"
+#include "pmpartiface.h"
+
+class PMView;
+class PMShell;
+class PMObjectDrag;
+class PMScene;
+class PMCamera;
+class PMPovrayWidget;
+class PMParser;
+
+class PMBrowserExtension;
+class PMSymbolTable;
+class PMDeclare;
+
+class PMPrototypeManager;
+class PMInsertRuleSystem;
+class PMIOManager;
+
+class QMimeSource;
+class KAction;
+class KSelectAction;
+class PMComboAction;
+class PMSpinBoxAction;
+class PMLabelAction;
+class KProcess;
+
+/**
+ * The part for kpovmodeler (povray document)
+ */
+class PMPart : public KParts::ReadWritePart, virtual public PMPartIface
+{
+ Q_OBJECT
+public:
+ /**
+ * construtor of PMPart, calls all init functions to create the
+ * application.
+ */
+ PMPart( QWidget* parentWidget, const char* widgetName,
+ QObject* parent, const char* name, bool readWrite,
+ PMShell* shell = 0 );
+
+ /**
+ * construtor of PMPart, calls all init functions to create the
+ * application. It does not create the main widget.
+ */
+ PMPart( QWidget* parentWidget, const char* widgetName,
+ QObject* parent, const char* name, bool readWrite,
+ bool onlyCutPaste, PMShell* shell = 0 );
+
+ /**
+ * Destructor
+ */
+ ~PMPart( );
+ /**
+ * deletes the document's contents
+ */
+ void deleteContents( );
+ /**
+ * initializes the document generally
+ */
+ bool newDocument( );
+ /**
+ * closes the actual document
+ */
+ void closeDocument( );
+ /**
+ * Exports the scene as povray code
+ */
+ bool exportPovray( const KURL& url );
+
+ /**
+ * returns the toplevel object
+ */
+ PMScene* scene( ) const { return m_pScene; }
+ /**
+ * Returns a pointer to the shell if there is one
+ */
+ PMShell* shell( ) const { return m_pShell; }
+ /**
+ * saves settings
+ */
+ void saveConfig( KConfig* cfg );
+ /**
+ * loads settings
+ */
+ void restoreConfig( KConfig* cfg );
+
+ /**
+ * Updates the sorted list of selected objects if necessary and
+ * returns a reference to the list.
+ */
+ const PMObjectList& selectedObjects( );
+
+ /**
+ * Executes the command cmd.
+ *
+ * All changes to the document have to be made
+ * with @ref PMCommand objects for undo/redo. Each slot that changes the
+ * document creates a PMCommand object and calls this function.
+ *
+ * If this function returns false, the command was not executed
+ * and the command object was deleted.
+ */
+ bool executeCommand( PMCommand* cmd );
+ /**
+ * Checks, where the objects in list can be inserted, as child
+ * or as sibling of obj and asks the user if there is more than one
+ * possibility
+ *
+ * Returns PMIFirstChild, PMILastChild, PMISibling or 0, if the objects
+ * should not be inserted.*/
+ int whereToInsert( PMObject* obj, const PMObjectList& list );
+ /**
+ * Checks, where the objects in list can be inserted, as child
+ * or as sibling of obj and asks the user if there is more than one
+ * possibility
+ *
+ * Returns PMIFirstChild, PMILastChild, PMISibling or 0, if the objects
+ * should not be inserted.*/
+ int whereToInsert( PMObject* obj, const QStringList& list );
+ /**
+ * Asks the user, where to insert new objects.
+ *
+ * Returns PMIFirstChild, PMILastChild, PMISibling or 0, if the objects
+ * should not be inserted.*/
+ int whereToInsert( PMObject* obj );
+
+ /**
+ * Returns the symbol table of this document
+ */
+ PMSymbolTable* symbolTable( ) const { return m_pSymbolTable; }
+ /**
+ * Returns the first camera
+ */
+ PMCamera* firstCamera( );
+ /**
+ * Returns an iterator to the list of cameras
+ */
+ QPtrListIterator<PMCamera> cameras( );
+ /**
+ * The active object
+ */
+ PMObject* activeObject( ) const { return m_pActiveObject; }
+ /**
+ * The active object's name
+ */
+ virtual QString activeObjectName( );
+ /**
+ * Set the active object
+ */
+ virtual bool setActiveObject( const QString& name );
+ /**
+ * Get the valid properties of the currently active object
+ */
+ virtual QStringList getProperties( );
+ /**
+ * set a property on the active object
+ */
+ virtual bool setProperty( const QString& name, const PMVariant& value );
+ /**
+ * set a property on the active object
+ */
+ virtual bool setProperty( const QString& name, const QString& value );
+ /**
+ * get a property on the active object
+ */
+ virtual const PMVariant getProperty( const QString& name );
+ /**
+ * get a property on the active object
+ */
+ virtual const QString getPropertyStr( const QString& name );
+ /**
+ * List of control points of the active object
+ */
+ PMControlPointList activeControlPoints( ) const { return m_controlPoints; }
+
+ /**
+ * Called when the user moves some objects in the tree view.
+ * If obj is 0, the user moved the objects to another document (remove)
+ *
+ * Returns true if successful.
+ */
+ bool dragMoveSelectionTo( PMObject* obj );
+ /**
+ * Called when the user drags some objects onto the tree view
+ *
+ * Returns true if successful.
+ */
+ bool drop( PMObject* obj, QMimeSource* e );
+ /**
+ * Tries to parse the data and insert the parsed objects
+ * as child or siblings of object obj
+ *
+ * Type is the actions description for the undo/redo menu.
+ */
+ bool insertFromParser( const QString& type, PMParser* parser, PMObject* obj );
+
+ /**
+ * Returns a pointer to the prototype manager
+ */
+ PMPrototypeManager* prototypeManager( ) const { return m_pPrototypeManager; }
+ /**
+ * Returns a pointer to the insert rules system
+ */
+ PMInsertRuleSystem* insertRuleSystem( ) const { return m_pInsertRuleSystem; }
+ /**
+ * Returns a pointer to the IO formats manager for this part
+ */
+ PMIOManager* ioManager( ) const { return m_pIOManager; }
+
+public slots:
+ /**
+ * Opens the import file dialog
+ */
+ void slotFileImport( );
+ /**
+ * Opens the export file dialog
+ */
+ void slotFileExport( );
+
+ /**
+ * puts the marked text/object into the clipboard and removes the objects
+ */
+ void slotEditCut( );
+ /**
+ * removes the selected object
+ */
+ void slotEditDelete( );
+ /**
+ * puts the marked text/object into the clipboard
+ */
+ void slotEditCopy( );
+ /**
+ * paste the clipboard into the document
+ */
+ void slotEditPaste( );
+ /**
+ * undoes the last change
+ */
+ void slotEditUndo( );
+ /**
+ * redoes the last undone command
+ */
+ void slotEditRedo( );
+
+ /**
+ * Called when an object is changed.
+ * Mode is a bit combination of @ref PMChange constants
+ */
+ void slotObjectChanged( PMObject* obj, const int mode, QObject* sender );
+ /**
+ * Called when an id is changed
+ */
+ void slotIDChanged( PMObject* obj, const QString& oldID );
+
+ /**
+ * Inserts a new PMObject of type type
+ */
+ void slotNewObject( const QString& type );
+ /**
+ * Inserts a new PMObject of type type at position pos.
+ * pos can be one of:
+ * FirstChild
+ * LastChild
+ * Sibling
+ */
+ void slotNewObject( const QString& type, const QString& pos );
+ /**
+ * Inserts the new PMObject. The object will be deleted if it can't be
+ * inserted or the user aborts the action
+ */
+ void slotNewObject( PMObject* newObject, int insertAs = 0 );
+
+ /**
+ * List the known object types
+ */
+ virtual QStringList getObjectTypes( );
+
+ /**
+ * Adds transformations to the object and calls slotNewObject
+ * for it
+ */
+ void slotNewTransformedObject( PMObject* o );
+
+ /**
+ * Inserts a new PMGlobalSettings
+ */
+ void slotNewGlobalSettings( );
+ /**
+ * Inserts a new PMSkySphere
+ */
+ void slotNewSkySphere( );
+ /**
+ * Inserts a new PMRainbow
+ */
+ void slotNewRainbow( );
+ /**
+ * Inserts a new PMFog
+ */
+ void slotNewFog( );
+ /**
+ * Inserts a new PMInterior
+ */
+ void slotNewInterior( );
+ /**
+ * Inserts a new PMMedia
+ */
+ void slotNewMedia( );
+ /**
+ * Inserts a new PMDensity
+ */
+ void slotNewDensity( );
+ /**
+ * Inserts a new PMMaterial
+ */
+ void slotNewMaterial( );
+ /**
+ * Inserts a new PMBox
+ */
+ void slotNewBox( );
+ /**
+ * Inserts a new PMSphere
+ */
+ void slotNewSphere( );
+ /**
+ * Inserts a new PMCylinder
+ */
+ void slotNewCylinder( );
+ /**
+ * Inserts a new PMCone
+ */
+ void slotNewCone( );
+ /**
+ * Inserts a new PMTorus
+ */
+ void slotNewTorus( );
+ /**
+ * Inserts a new PMLathe
+ */
+ void slotNewLathe( );
+ /**
+ * Inserts a new PMPrism
+ */
+ void slotNewPrism( );
+ /**
+ * Inserts a new PMSurfaceOfRevolution
+ */
+ void slotNewSurfaceOfRevolution( );
+ /**
+ * Inserts a new PMSuperquadricEllipsoid
+ */
+ void slotNewSuperquadricEllipsoid( );
+ /**
+ * Inserts a new PMJuliaFractal
+ */
+ void slotNewJuliaFractal( );
+ /**
+ * Inserts a new PMHeightField
+ */
+ void slotNewHeightField( );
+ /**
+ * Inserts a new text object
+ */
+ void slotNewText( );
+
+ /**
+ * Inserts a new PMBlob
+ */
+ void slotNewBlob( );
+ /**
+ * Inserts a new PMBlobSphere
+ */
+ void slotNewBlobSphere( );
+ /**
+ * Inserts a new PMBlobCylinder
+ */
+ void slotNewBlobCylinder( );
+
+ /**
+ * Inserts a new PMPlane
+ */
+ void slotNewPlane( );
+ /**
+ * Inserts a new PMPolynom
+ */
+ void slotNewPolynom( );
+ /**
+ * Inserts a new PMDeclare
+ */
+ void slotNewDeclare( );
+ /**
+ * Inserts a new PMObjectLink
+ */
+ void slotNewObjectLink( );
+
+ /**
+ * Inserts a new PMCSG ( union )
+ */
+ void slotNewUnion( );
+ /**
+ * Inserts a new PMCSG ( intersection )
+ */
+ void slotNewIntersection( );
+ /**
+ * Inserts a new PMCSG ( difference )
+ */
+ void slotNewDifference( );
+ /**
+ * Inserts a new PMCSG ( merge )
+ */
+ void slotNewMerge( );
+
+ /**
+ * Inserts a new PMDisc
+ */
+ void slotNewDisc( );
+ /**
+ * Inserts a new PMBicubicPatch
+ */
+ void slotNewBicubicPatch( );
+ /**
+ * Inserts a new PMTriangle
+ */
+ void slotNewTriangle( );
+
+ /**
+ * Inserts a new PMBoundedBy
+ */
+ void slotNewBoundedBy( );
+ /**
+ * Inserts a new PMClippedBy
+ */
+ void slotNewClippedBy( );
+
+ /**
+ * Inserts a new PMLight object
+ */
+ void slotNewLight( );
+ /**
+ * Inserts a new PMLooksLike object
+ */
+ void slotNewLooksLike( );
+ /**
+ * Inserts a new PMProjectedThrough object
+ */
+ void slotNewProjectedThrough( );
+
+ /**
+ * Inserts a new PMCamera
+ */
+ void slotNewCamera( );
+
+ /**
+ * Inserts a new PMTexture
+ */
+ void slotNewTexture( );
+ /**
+ * Inserts a new PMPigment
+ */
+ void slotNewPigment( );
+ /**
+ * Inserts a new PMNormal
+ */
+ void slotNewNormal( );
+ /**
+ * Inserts a new PMSolidColor
+ */
+ void slotNewSolidColor( );
+ /**
+ * Inserts a new PMTextureList
+ */
+ void slotNewTextureList( );
+ /**
+ * Inserts a new PMColorList
+ */
+ void slotNewColorList( );
+ /**
+ * Inserts a new PMPigmentList
+ */
+ void slotNewPigmentList( );
+ /**
+ * Inserts a new PMNormalList
+ */
+ void slotNewNormalList( );
+ /**
+ * Inserts a new PMDensityList
+ */
+ void slotNewDensityList( );
+ /**
+ * Inserts a new PMFinish
+ */
+ void slotNewFinish( );
+ /**
+ * Inserts a new PMPattern
+ */
+ void slotNewPattern( );
+ /**
+ * Inserts a new PMBlendMapModifiers
+ */
+ void slotNewBlendMapModifiers( );
+ /**
+ * Inserts a new PMTextureMap
+ */
+ void slotNewTextureMap( );
+ /**
+ * Inserts a new PMMaterialMap
+ */
+ void slotNewMaterialMap( );
+ /**
+ * Inserts a new PMColorMap
+ */
+ void slotNewColorMap( );
+ /**
+ * Inserts a new PMPigmentMap
+ */
+ void slotNewPigmentMap( );
+ /**
+ * Inserts a new PMNormalMap
+ */
+ void slotNewNormalMap( );
+ /**
+ * Inserts a new PMBumpMap
+ */
+ void slotNewBumpMap( );
+ /**
+ * Inserts a new PMSlopeMap
+ */
+ void slotNewSlopeMap( );
+ /**
+ * Inserts a new PMDensityMap
+ */
+ void slotNewDensityMap( );
+ /**
+ * Inserts a new PMSlope
+ */
+ void slotNewSlope( );
+ /**
+ * Inserts a new PMWarp
+ */
+ void slotNewWarp( );
+ /**
+ * Inserts a new PMImageMap
+ */
+ void slotNewImageMap( );
+ /**
+ * Inserts a new PMQuickColor
+ */
+ void slotNewQuickColor( );
+
+ /**
+ * Inserts a new PMTranslate
+ */
+ void slotNewTranslate( );
+ /**
+ * Inserts a new PMRotate
+ */
+ void slotNewRotate( );
+ /**
+ * Inserts a new PMScale
+ */
+ void slotNewScale( );
+ /**
+ * Inserts a new PMPovrayMatrix
+ */
+ void slotNewMatrix( );
+ /**
+ * Inserts a new PMComment
+ */
+ void slotNewComment( );
+ /**
+ * Inserts a new PMRaw
+ */
+ void slotNewRaw( );
+
+ // POV-Ray 3.5 objects
+ /**
+ * Inserts a new PMIsoSurfate
+ */
+ void slotNewIsoSurface( );
+ /**
+ * Inserts a new PMRadiosity
+ */
+ void slotNewRadiosity( );
+ /**
+ * Inserts a new PMGlobalPhotons
+ */
+ void slotNewGlobalPhotons( );
+ /**
+ * Inserts a new PMPhotons
+ */
+ void slotNewPhotons( );
+ /**
+ * Inserts a new PMLightGroup
+ */
+ void slotNewLightGroup( );
+ /**
+ * Inserts a new PMInteriorTexture
+ */
+ void slotNewInteriorTexture( );
+ /**
+ * Inserts a new PMSphereSweep
+ */
+ void slotNewSphereSweep( );
+ /**
+ * Inserts a new PMMesh
+ */
+ void slotNewMesh( );
+
+
+ /**
+ * Called when the clipboard contents changed
+ */
+ void slotClipboardDataChanged( );
+ /**
+ * updates the undo/redo menu items
+ */
+ void slotUpdateUndoRedo( const QString& undo, const QString& redo );
+
+ /**
+ * Starts rendering with povray
+ */
+ virtual void slotRender( );
+ /**
+ * Opens the render settings
+ */
+ void slotRenderSettings( );
+ /**
+ * Called when a render mode is selected
+ */
+ void slotRenderMode( int index );
+ /**
+ * Called when the render modes combo action is plugged into the toolbar
+ */
+ void slotRenderModeActionPlugged( );
+ /**
+ * Shows the render window
+ */
+ void slotViewRenderWindow( );
+ /**
+ * Called when the visibility level has changed
+ */
+ void slotVisibilityLevelChanged( int );
+ /**
+ * Called when the visibility level action is plugged into the toolbar
+ */
+ void slotVisibilityActionPlugged( );
+ /**
+ * Called when the global detail level has changed
+ */
+ void slotGlobalDetailLevelChanged( int level );
+
+ /**
+ * Opens the search library object dialog
+ */
+ void slotSearchLibraryObject( );
+
+ /** */
+ virtual void setModified( );
+ /** */
+ virtual void setModified( bool modified );
+
+ /** Set the scene object. Must be used with extreme care. */
+ void setScene( PMScene* scene );
+
+ /**
+ * Emits the aboutToSave signal
+ */
+ void slotAboutToSave( );
+
+signals:
+ /**
+ * Signal that is emitted when an object is changed.
+ * Mode is a bit combination of @ref PMChange constants.
+ */
+ void objectChanged( PMObject* obj, const int mode, QObject* sender );
+ /**
+ * Signal that is emitted when the views have to be refreshed.
+ * Usually on newDocument or openDocument
+ */
+ void refresh( );
+ /**
+ * Emitted when all views should delete all data
+ */
+ void clear( );
+ /**
+ * Emitted, when the modified flag changes
+ */
+ void modified( );
+ /**
+ * Emitted when the mouse is over a control point
+ */
+ void controlPointMessage( const QString& msg );
+ /**
+ * Emitted when the active render mode has changed
+ */
+ void activeRenderModeChanged( );
+ /**
+ * Emitted before the scene is rendered.
+ *
+ * Views should ask the user to save pending changes.
+ */
+ void aboutToRender( );
+ /**
+ * Emitted before the scene is saved or exported
+ *
+ * Views should ask the user to save pending changes.
+ */
+ void aboutToSave( );
+
+protected:
+ /**
+ * reimplemented from @ref KParts::ReadOnlyPart
+ */
+ virtual bool openFile( );
+ /**
+ * reimplemented from @ref KParts::ReadOnlyPart
+ */
+ virtual bool saveFile( );
+ /**
+ * Inits all actions
+ */
+ void initActions( );
+ /**
+ * Inits only actions related to copy&paste.
+ * Required by the library browser.
+ */
+ void initCopyPasteActions( );
+
+ /**
+ * creates the widget of the part instance and sets
+ * it as the view
+ */
+ void initView( QWidget* parent, const char* name );
+ /**
+ * initializes the documents contents
+ */
+ void initDocument( );
+ /**
+ * clears the selection
+ */
+ void clearSelection( );
+
+private:
+ /**
+ * Disables all actions, that modify the part
+ */
+ void disableReadWriteActions( );
+ /**
+ * Updates all "new object" actions
+ */
+ void updateNewObjectActions( );
+ /**
+ * Finds a free id of the format <prefix><number>.
+ *
+ * Adds the object to the symbol table.
+ *
+ * Returns the number.
+ */
+ unsigned int findNewID( const QString& prefix, unsigned int firstNumber,
+ PMDeclare* obj );
+ /**
+ * Updates the list of cameras
+ */
+ void updateCameraList( );
+
+ /**
+ * Generic drop/paste function
+ */
+ bool pasteOrDrop( const QString& type, QMimeSource* mime, PMObject* obj );
+ /**
+ * Generic cut/delete/remove function
+ */
+ bool removeSelection( const QString& type );
+ /**
+ * Updates the render mode combo action
+ */
+ void updateRenderModes( );
+ /**
+ * Updates the visibility level action
+ */
+ void updateVisibilityLevel( );
+ /**
+ * Updates the control point list
+ */
+ void updateControlPoints( PMObject* oldActive );
+
+ PMView* m_pView;
+ PMShell* m_pShell;
+ PMBrowserExtension* m_pExtension;
+
+ /**
+ * the selected objects, unsorted!
+ */
+ PMObjectList m_selectedObjects;
+ /**
+ * the selected objects, sorted. This list is only created if necessary.
+ */
+ PMObjectList m_sortedSelectedObjects;
+ /**
+ * true if the list m_sortedSelectedObjects is up to date
+ */
+ bool m_sortedListUpToDate;
+ /**
+ * the active object
+ */
+ PMObject* m_pActiveObject;
+ /**
+ * the new selection after a command was executed
+ */
+ PMObject* m_pNewSelection;
+ /**
+ * List of all cameras
+ */
+ QPtrList<PMCamera> m_cameras;
+ /**
+ * true if the m_cameras list is up to date
+ */
+ bool m_bCameraListUpToDate;
+ /**
+ * true if the clipboard data can be decoded
+ */
+ bool m_canDecode;
+ /**
+ * Commands stack for undo and redo
+ */
+ PMCommandManager m_commandManager;
+ /**
+ * The povray scene, top level object
+ */
+ PMScene* m_pScene;
+ /**
+ * Number of added objects during the last executed command
+ */
+ unsigned int m_numAddedObjects;
+ /**
+ * Number of insert errors during the last executed command
+ */
+ unsigned int m_numInsertErrors;
+ /**
+ * Details of insert errors
+ */
+ QStringList m_insertErrorDetails;
+ /**
+ * The symbol table for this document
+ */
+ PMSymbolTable* m_pSymbolTable;
+ /**
+ * The povray render window
+ */
+ PMPovrayWidget* m_pPovrayWidget;
+ /**
+ * true if the new object actions have to be updated
+ */
+ bool m_updateNewObjectActions;
+ /**
+ * Control points of the active object
+ */
+ PMControlPointList m_controlPoints;
+ /**
+ * true if only copy'n'paste actions are available
+ */
+ bool m_onlyCopyPaste;
+
+ // the actions
+ KAction* m_pImportAction;
+ KAction* m_pExportAction;
+
+ KAction* m_pCutAction;
+ KAction* m_pCopyAction;
+ KAction* m_pPasteAction;
+ KAction* m_pUndoAction;
+ KAction* m_pRedoAction;
+ KAction* m_pDeleteAction;
+
+ KAction* m_pNewGlobalSettingsAction;
+ KAction* m_pNewSkySphereAction;
+ KAction* m_pNewRainbowAction;
+ KAction* m_pNewFogAction;
+ KAction* m_pNewInteriorAction;
+ KAction* m_pNewMediaAction;
+ KAction* m_pNewDensityAction;
+ KAction* m_pNewMaterialAction;
+ KAction* m_pNewBoxAction;
+ KAction* m_pNewSphereAction;
+ KAction* m_pNewCylinderAction;
+ KAction* m_pNewConeAction;
+ KAction* m_pNewTorusAction;
+ KAction* m_pNewLatheAction;
+ KAction* m_pNewPrismAction;
+ KAction* m_pNewSurfaceOfRevolutionAction;
+ KAction* m_pNewSuperquadricEllipsoidAction;
+ KAction* m_pNewJuliaFractalAction;
+ KAction* m_pNewHeightFieldAction;
+ KAction* m_pNewTextAction;
+
+ KAction* m_pNewBlobAction;
+ KAction* m_pNewBlobSphereAction;
+ KAction* m_pNewBlobCylinderAction;
+
+ KAction* m_pNewPlaneAction;
+ KAction* m_pNewPolynomAction;
+
+ KAction* m_pNewDeclareAction;
+ KAction* m_pNewObjectLinkAction;
+
+ KAction* m_pNewUnionAction;
+ KAction* m_pNewDifferenceAction;
+ KAction* m_pNewIntersectionAction;
+ KAction* m_pNewMergeAction;
+
+ KAction* m_pNewBoundedByAction;
+ KAction* m_pNewClippedByAction;
+
+ KAction* m_pNewBicubicPatchAction;
+ KAction* m_pNewDiscAction;
+ KAction* m_pNewTriangleAction;
+
+ KAction* m_pNewLightAction;
+ KAction* m_pNewLooksLikeAction;
+ KAction* m_pNewProjectedThroughAction;
+
+ KAction* m_pNewCameraAction;
+
+ KAction* m_pNewTextureAction;
+ KAction* m_pNewPigmentAction;
+ KAction* m_pNewNormalAction;
+ KAction* m_pNewSolidColorAction;
+ KAction* m_pNewTextureListAction;
+ KAction* m_pNewColorListAction;
+ KAction* m_pNewPigmentListAction;
+ KAction* m_pNewNormalListAction;
+ KAction* m_pNewDensityListAction;
+ KAction* m_pNewFinishAction;
+ KAction* m_pNewPatternAction;
+ KAction* m_pNewBlendMapModifiersAction;
+ KAction* m_pNewTextureMapAction;
+ KAction* m_pNewMaterialMapAction;
+ KAction* m_pNewPigmentMapAction;
+ KAction* m_pNewColorMapAction;
+ KAction* m_pNewNormalMapAction;
+ KAction* m_pNewBumpMapAction;
+ KAction* m_pNewSlopeMapAction;
+ KAction* m_pNewDensityMapAction;
+ KAction* m_pNewSlopeAction;
+ KAction* m_pNewWarpAction;
+ KAction* m_pNewImageMapAction;
+ KAction* m_pNewQuickColorAction;
+
+ KAction* m_pNewTranslateAction;
+ KAction* m_pNewScaleAction;
+ KAction* m_pNewRotateAction;
+ KAction* m_pNewMatrixAction;
+
+ KAction* m_pNewCommentAction;
+ KAction* m_pNewRawAction;
+
+ // POV-Ray 3.5 objects
+ KAction* m_pNewIsoSurfaceAction;
+ KAction* m_pNewRadiosityAction;
+ KAction* m_pNewGlobalPhotonsAction;
+ KAction* m_pNewPhotonsAction;
+ KAction* m_pNewLightGroupAction;
+ KAction* m_pNewInteriorTextureAction;
+ KAction* m_pNewSphereSweepAction;
+ KAction* m_pNewMeshAction;
+
+ KAction* m_pSearchLibraryObjectAction;
+
+ PMComboAction* m_pRenderComboAction;
+ KAction* m_pRenderSettingsAction;
+ KAction* m_pViewRenderWindowAction;
+ KAction* m_pRenderAction;
+ PMSpinBoxAction* m_pVisibilityLevelAction;
+ PMLabelAction* m_pVisibilityLabelAction;
+ KSelectAction* m_pGlobalDetailAction;
+ PMLabelAction* m_pGlobalDetailLabelAction;
+
+ QPtrList<KAction> m_readWriteActions;
+
+ PMPrototypeManager* m_pPrototypeManager;
+ PMInsertRuleSystem* m_pInsertRuleSystem;
+ PMIOManager* m_pIOManager;
+};
+
+class PMBrowserExtension : public KParts::BrowserExtension
+{
+ Q_OBJECT
+ friend class PMPart;
+public:
+ PMBrowserExtension( PMPart* parent )
+ : KParts::BrowserExtension( parent, "PMBrowserExtension" )
+ {
+ KGlobal::locale()->insertCatalogue("kpovmodeler");
+ }
+
+ virtual ~PMBrowserExtension( )
+ {
+ }
+};
+
+#endif
diff --git a/kpovmodeler/pmpartiface.h b/kpovmodeler/pmpartiface.h
new file mode 100644
index 00000000..a1fe495e
--- /dev/null
+++ b/kpovmodeler/pmpartiface.h
@@ -0,0 +1,119 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2004 by Luis Carvalho
+ email : lpassos@oninetspeed.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPARTIFACE_H
+#define PMPARTIFACE_H
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <dcopobject.h>
+
+#include "pmvariant.h"
+
+/**
+ * DCOP Interface for kpovmodeler
+ */
+class PMPartIface : virtual public DCOPObject
+{
+ K_DCOP
+
+k_dcop:
+ /**
+ * deletes the document's contents
+ */
+ virtual void deleteContents( ) = 0;
+ /**
+ * initializes the document generally
+ */
+ virtual bool newDocument( ) = 0;
+ /**
+ * closes the actual document
+ */
+ virtual void closeDocument( ) = 0;
+ /**
+ * Inserts a new PMObject of type type
+ */
+ virtual void slotNewObject( const QString& type, const QString& pos ) = 0;
+ /**
+ * initializes the documents contents
+ */
+ virtual void initDocument( ) = 0;
+ /**
+ * clears the selection
+ */
+ virtual void clearSelection( ) = 0;
+ /**
+ * puts the marked text/object into the clipboard and removes the objects
+ */
+ virtual void slotEditCut( ) = 0;
+ /**
+ * removes the selected object
+ */
+ virtual void slotEditDelete( ) = 0;
+ /**
+ * puts the marked text/object into the clipboard
+ */
+ virtual void slotEditCopy( ) = 0;
+ /**
+ * paste the clipboard into the document
+ */
+ virtual void slotEditPaste( ) = 0;
+ /**
+ * render the current scene
+ */
+ virtual void slotRender( ) = 0;
+ /**
+ * returns the currently selected object
+ */
+ virtual QString activeObjectName( ) = 0;
+ /**
+ * set the current selected object.
+ * returns true if successful or false otherwise
+ */
+ virtual bool setActiveObject( const QString& name ) = 0;
+ /**
+ * Get known properties of the currently active object
+ */
+ virtual QStringList getProperties( ) = 0;
+ /**
+ * set a property on the currently active object
+ */
+ virtual bool setProperty( const QString& property, const PMVariant& value ) = 0;
+ /**
+ * set a property on the currently active object
+ */
+ virtual bool setProperty( const QString& property, const QString& value ) = 0;
+ /**
+ * Get the value of the given property
+ */
+ virtual const PMVariant getProperty( const QString& property ) = 0;
+ /**
+ * Get the value of the given property
+ */
+ virtual const QString getPropertyStr( const QString& property ) = 0;
+ /**
+ * Get a list of known object types.
+ */
+ virtual QStringList getObjectTypes( ) = 0;
+};
+
+#endif
diff --git a/kpovmodeler/pmpattern.cpp b/kpovmodeler/pmpattern.cpp
new file mode 100644
index 00000000..c9377f84
--- /dev/null
+++ b/kpovmodeler/pmpattern.cpp
@@ -0,0 +1,1126 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001-2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmpatternedit.h"
+#include "pmpattern.h"
+
+#include "pmxmlhelper.h"
+#include "pmlistpatternedit.h"
+#include "pmcompositeobject.h"
+#include "pmmemento.h"
+#include "pmenumproperty.h"
+
+#include <klocale.h>
+
+const PMPattern::PMPatternType patternTypeDefault = PMPattern::PatternAgate;
+const double agateTurbulenceDefault = 0.5;
+const PMVector crackleFormDefault = PMVector( -1.0, 1.0, 0.0 );
+const int crackleMetricDefault = 2;
+const double crackleOffsetDefault = 0.0;
+const bool crackleSolidDefault = false;
+const QString densityFileDefault = QString( "" );
+const int densityInterpolateDefault = 0;
+const PMVector gradientDefault = PMVector( 1.0, 1.0, 1.0 );
+const PMVector juliaComplexDefault = PMVector( 0.353, 0.288 );
+const bool fractalMagnetDefault = false;
+const int fractalMagnetTypeDefault = 1;
+const int maxIterationsDefault = 10;
+const int fractalExponentDefault = 2;
+const int fractalExtTypeDefault = 1;
+const double fractalExtFactorDefault = 1.0;
+const int fractalIntTypeDefault = 0;
+const double fractalIntFactorDefault = 1.0;
+const double quiltControl0Default = 1.0;
+const double quiltControl1Default = 1.0;
+const PMVector slopeDirectionDefault = PMVector( 0.0, -1.0, 0.0 );
+const double slopeLoSlopeDefault = 0.0;
+const double slopeHiSlopeDefault = 1.0;
+const bool slopeAltFlagDefault = false;
+const PMVector slopeAltitudeDefault = PMVector( 0.0, 1.0, 0.0 );
+const double slopeLoAltDefault = 0.0;
+const double slopeHiAltDefault = 1.0;
+const int spiralNumberArmsDefault = 0;
+const PMPattern::PMNoiseType noiseGeneratorDefault = PMPattern::GlobalSetting;
+const QString noiseGeneratorDefaultText = QString( "global_setting" );
+const bool turbulenceDefault = false;
+const PMVector valueVectorDefault = PMVector( 0.0, 0.0, 0.0 );
+const int octavesDefault = 6;
+const double omegaDefault = 0.5;
+const double lambdaDefault = 2.0;
+const double depthDefault = 0.0;
+
+PMDefinePropertyClass( PMPattern, PMPatternProperty );
+PMDefineEnumPropertyClass( PMPattern, PMPattern::PMPatternType,
+ PMPatternTypeProperty );
+PMDefineEnumPropertyClass( PMPattern, PMPattern::PMNoiseType,
+ PMNoiseProperty );
+
+PMMetaObject* PMPattern::s_pMetaObject = 0;
+PMObject* createNewPattern( PMPart* part )
+{
+ return new PMPattern( part );
+}
+
+PMPattern::PMPattern( PMPart* part )
+ : Base( part )
+{
+ m_patternType = patternTypeDefault;
+
+ m_agateTurbulence = agateTurbulenceDefault;
+
+ m_crackleForm = crackleFormDefault;
+ m_crackleMetric = crackleMetricDefault;
+ m_crackleOffset = crackleOffsetDefault;
+ m_crackleSolid = crackleSolidDefault;
+
+ m_densityFile = densityFileDefault;
+ m_densityInterpolate = densityInterpolateDefault;
+
+ m_gradient = gradientDefault;
+
+ m_juliaComplex = juliaComplexDefault;
+ m_fractalMagnet = fractalMagnetDefault;
+ m_fractalMagnetType = fractalMagnetTypeDefault;
+ m_maxIterations = maxIterationsDefault;
+ m_fractalExponent = fractalExponentDefault;
+ m_fractalExtType = fractalExtTypeDefault;
+ m_fractalExtFactor = fractalExtFactorDefault;
+ m_fractalIntType = fractalIntTypeDefault;
+ m_fractalIntFactor = fractalIntFactorDefault;
+
+ m_quiltControl0 = quiltControl0Default;
+ m_quiltControl1 = quiltControl1Default;
+
+ m_slopeDirection = slopeDirectionDefault;
+ m_slopeLoSlope = slopeLoSlopeDefault;
+ m_slopeHiSlope = slopeHiSlopeDefault;
+ m_slopeAltFlag = slopeAltFlagDefault;
+ m_slopeAltitude = slopeAltitudeDefault;
+ m_slopeLoAlt = slopeLoAltDefault;
+ m_slopeHiAlt = slopeHiAltDefault;
+
+ m_spiralNumberArms = spiralNumberArmsDefault;
+
+ m_noiseGenerator = noiseGeneratorDefault;
+
+ m_enableTurbulence = turbulenceDefault;
+ m_valueVector = valueVectorDefault;
+ m_octaves = octavesDefault;
+ m_omega = omegaDefault;
+ m_lambda = lambdaDefault;
+
+ m_depth = depthDefault;
+}
+
+PMPattern::PMPattern( const PMPattern& p )
+ : Base( p )
+{
+ m_patternType = p.m_patternType;
+
+ m_agateTurbulence = p.m_agateTurbulence;
+
+ m_crackleForm = p.m_crackleForm;
+ m_crackleMetric = p.m_crackleMetric;
+ m_crackleOffset = p.m_crackleOffset;
+ m_crackleSolid = p.m_crackleSolid;
+
+ m_densityFile = p.m_densityFile;
+ m_densityInterpolate = p.m_densityInterpolate;
+
+ m_gradient = p.m_gradient;
+
+ m_juliaComplex = p.m_juliaComplex;
+ m_fractalMagnet = p.m_fractalMagnet;
+ m_fractalMagnetType = p.m_fractalMagnetType;
+ m_maxIterations = p.m_maxIterations;
+ m_fractalExponent = p.m_fractalExponent;
+ m_fractalExtType = p.m_fractalExtType;
+ m_fractalExtFactor = p.m_fractalExtFactor;
+ m_fractalIntType = p.m_fractalIntType;
+ m_fractalIntFactor = p.m_fractalIntFactor;
+
+ m_quiltControl0 = p.m_quiltControl0;
+ m_quiltControl1 = p.m_quiltControl1;
+
+ m_slopeDirection = p.m_slopeDirection;
+ m_slopeLoSlope = p.m_slopeLoSlope;
+ m_slopeHiSlope = p.m_slopeHiSlope;
+ m_slopeAltFlag = p.m_slopeAltFlag;
+ m_slopeAltitude = p.m_slopeAltitude;
+ m_slopeLoAlt = p.m_slopeLoAlt;
+ m_slopeHiAlt = p.m_slopeHiAlt;
+
+ m_spiralNumberArms = p.m_spiralNumberArms;
+
+ m_noiseGenerator = p.m_noiseGenerator;
+
+ m_enableTurbulence = p.m_enableTurbulence;
+ m_valueVector = p.m_valueVector;
+ m_octaves = p.m_octaves;
+ m_omega = p.m_omega;
+ m_lambda = p.m_lambda;
+
+ m_depth = p.m_depth;
+}
+
+PMPattern::~PMPattern( )
+{
+}
+
+void PMPattern::serialize( QDomElement& e, QDomDocument& ) const
+{
+ switch( m_patternType )
+ {
+ case PatternAgate:
+ e.setAttribute( "patterntype", "agate" );
+ break;
+ case PatternAverage:
+ e.setAttribute( "patterntype", "average" );
+ break;
+ case PatternBoxed:
+ e.setAttribute( "patterntype", "boxed" );
+ break;
+ case PatternBozo:
+ e.setAttribute( "patterntype", "bozo" );
+ break;
+ case PatternBumps:
+ e.setAttribute( "patterntype", "bumps" );
+ break;
+ case PatternCells:
+ e.setAttribute( "patterntype", "cells" );
+ break;
+ case PatternCrackle:
+ e.setAttribute( "patterntype", "crackle" );
+ break;
+ case PatternCylindrical:
+ e.setAttribute( "patterntype", "cylindrical" );
+ break;
+ case PatternDensity:
+ e.setAttribute( "patterntype", "density" );
+ break;
+ case PatternDents:
+ e.setAttribute( "patterntype", "dents" );
+ break;
+ case PatternGradient:
+ e.setAttribute( "patterntype", "gradient" );
+ break;
+ case PatternGranite:
+ e.setAttribute( "patterntype", "granite" );
+ break;
+ case PatternJulia:
+ e.setAttribute( "patterntype", "julia" );
+ break;
+ case PatternLeopard:
+ e.setAttribute( "patterntype", "leopard" );
+ break;
+ case PatternMandel:
+ e.setAttribute( "patterntype", "mandel" );
+ break;
+ case PatternMarble:
+ e.setAttribute( "patterntype", "marble" );
+ break;
+ case PatternOnion:
+ e.setAttribute( "patterntype", "onion" );
+ break;
+ case PatternPlanar:
+ e.setAttribute( "patterntype", "planar" );
+ break;
+ case PatternQuilted:
+ e.setAttribute( "patterntype", "quilted" );
+ break;
+ case PatternRadial:
+ e.setAttribute( "patterntype", "radial" );
+ break;
+ case PatternRipples:
+ e.setAttribute( "patterntype", "ripples" );
+ break;
+ case PatternSlope:
+ e.setAttribute( "patterntype", "slope" );
+ break;
+ case PatternSpherical:
+ e.setAttribute( "patterntype", "spherical" );
+ break;
+ case PatternSpiral1:
+ e.setAttribute( "patterntype", "spiral1" );
+ break;
+ case PatternSpiral2:
+ e.setAttribute( "patterntype", "spiral2" );
+ break;
+ case PatternSpotted:
+ e.setAttribute( "patterntype", "spotted" );
+ break;
+ case PatternWaves:
+ e.setAttribute( "patterntype", "waves" );
+ break;
+ case PatternWood:
+ e.setAttribute( "patterntype", "wood" );
+ break;
+ case PatternWrinkles:
+ e.setAttribute( "patterntype", "wrinkles" );
+ break;
+ }
+
+ e.setAttribute( "agateturbulence", m_agateTurbulence );
+
+ e.setAttribute( "crackleform", m_crackleForm.serializeXML( ) );
+ e.setAttribute( "cracklemetric", m_crackleMetric );
+ e.setAttribute( "crackleoffset", m_crackleOffset );
+ e.setAttribute( "cracklesolid", m_crackleSolid );
+
+ e.setAttribute( "densityinterpolate", m_densityInterpolate );
+ e.setAttribute( "densityfile", m_densityFile );
+
+ e.setAttribute( "gradient", m_gradient.serializeXML( ) );
+
+ e.setAttribute( "juliacomplex", m_juliaComplex.serializeXML( ) );
+ e.setAttribute( "fractalmagnet", m_fractalMagnet );
+ e.setAttribute( "fractalmagnettype", m_fractalMagnetType );
+ e.setAttribute( "maxiterations", m_maxIterations );
+ e.setAttribute( "fractalexponent", m_fractalExponent );
+ e.setAttribute( "fractalexttype", m_fractalExtType );
+ e.setAttribute( "fractalextfactor", m_fractalExtFactor );
+ e.setAttribute( "fractalinttype", m_fractalIntType );
+ e.setAttribute( "fractalintfactor", m_fractalIntFactor );
+
+ e.setAttribute( "quiltcontrol0", m_quiltControl0 );
+ e.setAttribute( "quiltcontrol1", m_quiltControl1 );
+
+ e.setAttribute( "slopedirection", m_slopeDirection.serializeXML( ) );
+ e.setAttribute( "slopeloslope", m_slopeLoSlope );
+ e.setAttribute( "slopehislope", m_slopeHiSlope );
+ e.setAttribute( "slopealtflag", m_slopeAltFlag );
+ e.setAttribute( "slopealtitude", m_slopeAltitude.serializeXML( ) );
+ e.setAttribute( "slopeloalt", m_slopeLoAlt );
+ e.setAttribute( "slopehialt", m_slopeHiAlt );
+
+ e.setAttribute( "spiralnumberarms", m_spiralNumberArms );
+ switch ( m_noiseGenerator )
+ {
+ case GlobalSetting:
+ e.setAttribute( "noise_generator", "global_setting" );
+ break;
+ case Original:
+ e.setAttribute( "noise_generator", "original" );
+ break;
+ case RangeCorrected:
+ e.setAttribute( "noise_generator", "range_corrected" );
+ break;
+ case Perlin:
+ e.setAttribute( "noise_generator", "perlin" );
+ break;
+ }
+
+ e.setAttribute( "enable_turbulence", m_enableTurbulence );
+ e.setAttribute( "turbulence", m_valueVector.serializeXML( ) );
+ e.setAttribute( "octaves", m_octaves );
+ e.setAttribute( "omega", m_omega );
+ e.setAttribute( "lambda", m_lambda );
+
+ e.setAttribute( "depth", m_depth );
+}
+
+void PMPattern::readAttributes( const PMXMLHelper& h )
+{
+ QString str = h.stringAttribute( "patterntype", "agate" );
+
+ if( str == "agate" )
+ m_patternType = PatternAgate;
+ else if( str == "average" )
+ m_patternType = PatternAverage;
+ else if( str == "boxed" )
+ m_patternType = PatternBoxed;
+ else if( str == "bozo" )
+ m_patternType = PatternBozo;
+ else if( str == "bumps" )
+ m_patternType = PatternBumps;
+ else if( str == "cells" )
+ m_patternType = PatternCells;
+ else if( str == "crackle" )
+ m_patternType = PatternCrackle;
+ else if( str == "cylindrical" )
+ m_patternType = PatternCylindrical;
+ else if( str == "density" )
+ m_patternType = PatternDensity;
+ else if( str == "dents" )
+ m_patternType = PatternDents;
+ else if( str == "gradient" )
+ m_patternType = PatternGradient;
+ else if( str == "granite" )
+ m_patternType = PatternGranite;
+ else if( str == "julia" )
+ m_patternType = PatternJulia;
+ else if( str == "leopard" )
+ m_patternType = PatternLeopard;
+ else if( str == "mandel" )
+ m_patternType = PatternMandel;
+ else if( str == "marble" )
+ m_patternType = PatternMarble;
+ else if( str == "onion" )
+ m_patternType = PatternOnion;
+ else if( str == "planar" )
+ m_patternType = PatternPlanar;
+ else if( str == "quilted" )
+ m_patternType = PatternQuilted;
+ else if( str == "radial" )
+ m_patternType = PatternRadial;
+ else if( str == "ripples" )
+ m_patternType = PatternRipples;
+ else if( str == "slope" )
+ m_patternType = PatternSlope;
+ else if( str == "spherical" )
+ m_patternType = PatternSpherical;
+ else if( str == "spiral1" )
+ m_patternType = PatternSpiral1;
+ else if( str == "spiral2" )
+ m_patternType = PatternSpiral2;
+ else if( str == "spotted" )
+ m_patternType = PatternSpotted;
+ else if( str == "waves" )
+ m_patternType = PatternWaves;
+ else if( str == "wood" )
+ m_patternType = PatternWood;
+ else if( str == "wrinkles" )
+ m_patternType = PatternWrinkles;
+
+ m_agateTurbulence = h.doubleAttribute( "agateturbulence", agateTurbulenceDefault );
+
+ m_crackleForm = h.vectorAttribute( "crackleform", crackleFormDefault );
+ m_crackleMetric = h.intAttribute( "cracklemetric", crackleMetricDefault );
+ m_crackleOffset = h.doubleAttribute( "crackleoffset", crackleOffsetDefault );
+ m_crackleSolid = h.boolAttribute( "cracklesolid", crackleSolidDefault );
+
+ m_densityInterpolate = h.intAttribute( "densityinterpolate", densityInterpolateDefault );
+ m_densityFile = h.stringAttribute( "densityfile", densityFileDefault );
+
+ m_gradient = h.vectorAttribute( "gradient", gradientDefault );
+
+ m_juliaComplex = h.vectorAttribute( "juliacomplex", juliaComplexDefault );
+ m_fractalMagnet = h.boolAttribute( "fractalmagnet", fractalMagnetDefault );
+ m_fractalMagnetType = h.intAttribute( "fractalmagnettype", fractalMagnetTypeDefault );
+ m_maxIterations = h.intAttribute( "maxiterations", maxIterationsDefault );
+ m_fractalExponent = h.intAttribute( "fractalexponent", fractalExponentDefault );
+ m_fractalExtType = h.intAttribute( "fractalexttype", fractalExtTypeDefault );
+ m_fractalExtFactor = h.doubleAttribute( "fractalextfactor", fractalExtFactorDefault );
+ m_fractalIntType = h.intAttribute( "fractalinttype", fractalIntTypeDefault );
+ m_fractalIntFactor = h.doubleAttribute( "fractalintfactor", fractalIntFactorDefault );
+
+ m_quiltControl0 = h.doubleAttribute( "quiltcontrol0", quiltControl0Default );
+ m_quiltControl1 = h.doubleAttribute( "quiltcontrol1", quiltControl1Default );
+
+ m_slopeDirection = h.vectorAttribute( "slopedirection", slopeDirectionDefault );
+ m_slopeLoSlope = h.doubleAttribute( "slopeloslope", slopeLoSlopeDefault );
+ m_slopeHiSlope = h.doubleAttribute( "slopehislope", slopeHiSlopeDefault );
+ m_slopeAltFlag = h.boolAttribute( "slopealtflag", slopeAltFlagDefault );
+ m_slopeAltitude = h.vectorAttribute( "slopealtitude", slopeAltitudeDefault );
+ m_slopeLoAlt = h.doubleAttribute( "slopeloalt", slopeLoAltDefault );
+ m_slopeHiAlt = h.doubleAttribute( "slopehialt", slopeHiAltDefault );
+
+ m_spiralNumberArms = h.intAttribute( "spiralnumberarms", spiralNumberArmsDefault );
+
+ str = h.stringAttribute( "noise_generator", noiseGeneratorDefaultText );
+ if ( str == "original" )
+ m_noiseGenerator = Original;
+ else if ( str == "range_corrected" )
+ m_noiseGenerator = RangeCorrected;
+ else if ( str == "perlin" )
+ m_noiseGenerator = Perlin;
+ else
+ m_noiseGenerator = GlobalSetting;
+
+ m_enableTurbulence = h.boolAttribute( "enable_turbulence" , false );
+ m_valueVector = h.vectorAttribute( "turbulence", valueVectorDefault );
+ m_octaves = h.intAttribute( "octaves", octavesDefault );
+ m_omega = h.doubleAttribute( "omega", omegaDefault );
+ m_lambda = h.doubleAttribute( "lambda", lambdaDefault );
+
+ m_depth = h.doubleAttribute( "depth", depthDefault );
+
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMPattern::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Pattern", Base::metaObject( ),
+ createNewPattern );
+ s_pMetaObject->addProperty(
+ new PMPatternProperty( "agateTurbulence", &PMPattern::setAgateTurbulence, &PMPattern::agateTurbulence ) );
+
+ s_pMetaObject->addProperty(
+ new PMPatternProperty( "densityFile", &PMPattern::setDensityFile, &PMPattern::densityFile ) );
+ s_pMetaObject->addProperty(
+ new PMPatternProperty( "densityInterpolate", &PMPattern::setDensityInterpolate, &PMPattern::densityInterpolate ) );
+
+ s_pMetaObject->addProperty(
+ new PMPatternProperty( "gradient", &PMPattern::setGradient, &PMPattern::gradient ) );
+
+ s_pMetaObject->addProperty(
+ new PMPatternProperty( "maxIterations", &PMPattern::setMaxIterations, &PMPattern::maxIterations ) );
+
+ s_pMetaObject->addProperty(
+ new PMPatternProperty( "quiltControl0", &PMPattern::setQuiltControl0, &PMPattern::quiltControl0 ) );
+ s_pMetaObject->addProperty(
+ new PMPatternProperty( "quiltControl1", &PMPattern::setQuiltControl1, &PMPattern::quiltControl1 ) );
+
+ s_pMetaObject->addProperty(
+ new PMPatternProperty( "spiralNumberArms", &PMPattern::setSpiralNumberArms, &PMPattern::spiralNumberArms ) );
+
+ s_pMetaObject->addProperty(
+ new PMPatternProperty( "turbulence", &PMPattern::enableTurbulence, &PMPattern::isTurbulenceEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMPatternProperty( "valueVector", &PMPattern::setValueVector, &PMPattern::valueVector ) );
+ s_pMetaObject->addProperty(
+ new PMPatternProperty( "octaves", &PMPattern::setOctaves, &PMPattern::octaves ) );
+ s_pMetaObject->addProperty(
+ new PMPatternProperty( "omega", &PMPattern::setOmega, &PMPattern::omega ) );
+ s_pMetaObject->addProperty(
+ new PMPatternProperty( "lambda", &PMPattern::setLambda, &PMPattern::lambda ) );
+
+ s_pMetaObject->addProperty(
+ new PMPatternProperty( "depth", &PMPattern::setDepth, &PMPattern::depth ) );
+
+ PMPatternTypeProperty* p = new PMPatternTypeProperty(
+ "patternType", &PMPattern::setPatternType, &PMPattern::patternType );
+ p->addEnumValue( "Agate", PatternAgate );
+ p->addEnumValue( "Average", PatternAverage );
+ p->addEnumValue( "Boxed", PatternBoxed );
+ p->addEnumValue( "Bozo", PatternBozo );
+ p->addEnumValue( "Bumps", PatternBumps );
+ p->addEnumValue( "Cells", PatternCells );
+ p->addEnumValue( "Crackle", PatternCrackle );
+ p->addEnumValue( "Cylindrical", PatternCylindrical );
+ p->addEnumValue( "Density", PatternDensity );
+ p->addEnumValue( "Dents", PatternDents );
+ p->addEnumValue( "Gradient", PatternGradient );
+ p->addEnumValue( "Granite", PatternGranite );
+ p->addEnumValue( "Julia", PatternJulia );
+ p->addEnumValue( "Leopard", PatternLeopard );
+ p->addEnumValue( "Mandel", PatternMandel );
+ p->addEnumValue( "Marble", PatternMarble );
+ p->addEnumValue( "Onion", PatternOnion );
+ p->addEnumValue( "Planar", PatternPlanar );
+ p->addEnumValue( "Quilted", PatternQuilted );
+ p->addEnumValue( "Radial", PatternRadial );
+ p->addEnumValue( "Ripples", PatternRipples );
+ p->addEnumValue( "Slope", PatternSlope );
+ p->addEnumValue( "Spherical", PatternSpherical );
+ p->addEnumValue( "Spiral1", PatternSpiral1 );
+ p->addEnumValue( "Spiral2", PatternSpiral2 );
+ p->addEnumValue( "Spotted", PatternSpotted );
+ p->addEnumValue( "Waves", PatternWaves );
+ p->addEnumValue( "Wood", PatternWood );
+ p->addEnumValue( "Wrinkles", PatternWrinkles );
+ s_pMetaObject->addProperty( p );
+
+ PMNoiseProperty* p2 = new PMNoiseProperty(
+ "noiseGenerator", &PMPattern::setNoiseGenerator, &PMPattern::noiseGenerator );
+ p2->addEnumValue( "GlobalSetting", GlobalSetting );
+ p2->addEnumValue( "Original", Original );
+ p2->addEnumValue( "RangeCorrected", RangeCorrected );
+ p2->addEnumValue( "Perlin", Perlin );
+ s_pMetaObject->addProperty( p2 );
+ }
+ return s_pMetaObject;
+}
+
+void PMPattern::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMPattern::description( ) const
+{
+ return i18n( "pattern" );
+}
+
+void PMPattern::setPatternType( PMPatternType c )
+{
+ if( c != m_patternType )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMPatternTypeID, m_patternType );
+ m_patternType = c;
+ }
+}
+
+void PMPattern::setAgateTurbulence( double c )
+{
+ if( c != m_agateTurbulence )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAgateTurbulenceID, m_agateTurbulence );
+ m_agateTurbulence = c;
+ }
+}
+
+void PMPattern::setCrackleForm( const PMVector& v )
+{
+ if ( v != m_crackleForm )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMCrackleFormID, m_crackleForm );
+ m_crackleForm = v;
+ }
+}
+
+void PMPattern::setCrackleMetric( int c )
+{
+ if ( c < 1 )
+ {
+ kdError( PMArea ) << "new metric is < 1 in PMPattern::setCrackleMetric\n";
+ c = 1;
+ }
+
+ if ( c != m_crackleMetric )
+ {
+ if ( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMCrackleMetricID, m_crackleMetric );
+ m_crackleMetric = c;
+ }
+}
+
+void PMPattern::setCrackleOffset( double c )
+{
+ if ( c != m_crackleOffset )
+ {
+ if ( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMCrackleOffsetID, m_crackleOffset );
+ m_crackleOffset = c;
+ }
+}
+
+void PMPattern::setCrackleSolid( bool c )
+{
+ if ( c != m_crackleSolid )
+ {
+ if ( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMCrackleSolidID, m_crackleSolid );
+ m_crackleSolid = c;
+ }
+}
+
+void PMPattern::setDensityInterpolate( int c )
+{
+ if( c != m_densityInterpolate )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMDensityInterpolateID, m_densityInterpolate );
+ m_densityInterpolate = c;
+ }
+}
+
+void PMPattern::setDensityFile( const QString& s )
+{
+ if( s != m_densityFile )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMDensityFileID, m_densityFile );
+ m_densityFile = s;
+ }
+}
+
+void PMPattern::setGradient( const PMVector& v )
+{
+ if( v != m_gradient )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMGradientID, m_gradient );
+ m_gradient = v;
+ }
+}
+
+void PMPattern::setJuliaComplex( const PMVector& v )
+{
+ if ( v != m_juliaComplex )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMJuliaComplexID, m_juliaComplex );
+ m_juliaComplex = v;
+ }
+}
+
+void PMPattern::setFractalMagnet( bool c )
+{
+ if ( c != m_fractalMagnet )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFractalMagnetID, m_fractalMagnet );
+ m_fractalMagnet = c;
+ }
+}
+
+void PMPattern::setFractalMagnetType( int c )
+{
+ if ( c < 1 )
+ {
+ kdError( PMArea ) << "Magnet type < 1 in PMPattern::setFractalMagnetType\n";
+ c = 1;
+ }
+
+ if ( c > 2 )
+ {
+ kdError( PMArea ) << "Magnet type > 2 in PMPattern::setFractalMagnetType\n";
+ c = 2;
+ }
+
+ if ( c != m_fractalMagnetType )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFractalMagnetTypeID, m_fractalMagnetType );
+ m_fractalMagnetType = c;
+ }
+}
+
+void PMPattern::setMaxIterations( int c )
+{
+ if( c != m_maxIterations )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMMaxIterationsID, m_maxIterations );
+ m_maxIterations = c;
+ }
+}
+
+void PMPattern::setFractalExponent( int c )
+{
+ if ( c < 2 )
+ {
+ kdError( PMArea ) << "Exponent < 2 in PMPattern::setFractalExponent\n";
+ c = 2;
+ }
+
+ if ( c > 33 )
+ {
+ kdError( PMArea ) << "Exponent > 33 in PMPattern::setFractalExponent\n";
+ c = 33;
+ }
+
+ if ( c != m_fractalExponent )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFractalExponentID, m_fractalExponent );
+ m_fractalExponent = c;
+ }
+}
+
+void PMPattern::setFractalExtType( int c )
+{
+ if ( c < 0 )
+ {
+ kdError( PMArea ) << "Exterior Type < 0 in PMPattern::setFractalExtType\n";
+ c = 0;
+ }
+
+ if ( c > 6 )
+ {
+ kdError( PMArea ) << "Exterior Type > 6 in PMPattern::setFractalExtType\n";
+ c = 6;
+ }
+
+ if ( c != m_fractalExtType )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFractalExtTypeID, m_fractalExtType );
+ m_fractalExtType = c;
+ }
+}
+
+void PMPattern::setFractalExtFactor( double c )
+{
+ if ( c != m_fractalExtFactor )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFractalExtFactorID, m_fractalExtFactor );
+ m_fractalExtFactor = c;
+ }
+}
+
+void PMPattern::setFractalIntType( int c )
+{
+ if ( c < 0 )
+ {
+ kdError( PMArea ) << "Interior Type < 0 in PMPattern::setFractalIntType\n";
+ c = 0;
+ }
+
+ if ( c > 6 )
+ {
+ kdError( PMArea ) << "Interior Type > 6 in PMPattern::setFractalIntType\n";
+ c = 6;
+ }
+
+ if ( c != m_fractalIntType )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFractalIntTypeID, m_fractalIntType );
+ m_fractalIntType = c;
+ }
+}
+
+void PMPattern::setFractalIntFactor( double c )
+{
+ if ( c != m_fractalIntFactor )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFractalIntFactorID, m_fractalIntFactor );
+ m_fractalIntFactor = c;
+ }
+}
+
+void PMPattern::setQuiltControl0( double c )
+{
+ if( c != m_quiltControl0 )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMQuiltControl0ID, m_quiltControl0 );
+ m_quiltControl0 = c;
+ }
+}
+
+void PMPattern::setQuiltControl1( double c )
+{
+ if( c != m_quiltControl1 )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMQuiltControl1ID, m_quiltControl1 );
+ m_quiltControl1 = c;
+ }
+}
+
+void PMPattern::setSlopeDirection( const PMVector& v )
+{
+ if ( v != m_slopeDirection )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSlopeDirectionID, m_slopeDirection );
+ m_slopeDirection = v;
+ }
+}
+
+void PMPattern::setSlopeLoSlope( double c )
+{
+ if ( c < 0.0 )
+ {
+ kdError( PMArea ) << "Low slope < 0.0 in PMPattern::setSlopeLoSlope\n";
+ c = 0.0;
+ }
+
+ if ( c > 1.0 )
+ {
+ kdError( PMArea ) << "Low slope > 1.0 in PMPattern::setSlopeLoSlope\n";
+ c = 1.0;
+ }
+
+ if ( c != m_slopeLoSlope )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSlopeLoSlopeID, m_slopeLoSlope );
+ m_slopeLoSlope = c;
+ }
+}
+
+void PMPattern::setSlopeHiSlope( double c )
+{
+ if ( c < 0.0 )
+ {
+ kdError( PMArea ) << "High slope < 0.0 in PMPattern::setSlopeHiSlope\n";
+ c = 0.0;
+ }
+
+ if ( c > 1.0 )
+ {
+ kdError( PMArea ) << "High slope > 1.0 in PMPattern::setSlopeHiSlope\n";
+ c = 1.0;
+ }
+
+ if ( c != m_slopeHiSlope )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSlopeHiSlopeID, m_slopeHiSlope );
+ m_slopeHiSlope = c;
+ }
+}
+
+void PMPattern::setSlopeAltFlag( bool c )
+{
+ if ( c != m_slopeAltFlag )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSlopeAltFlagID, m_slopeAltFlag );
+ m_slopeAltFlag = c;
+ }
+}
+
+void PMPattern::setSlopeAltitude( const PMVector& v )
+{
+ if ( v != m_slopeAltitude )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSlopeAltitudeID, m_slopeAltitude );
+ m_slopeAltitude = v;
+ }
+}
+
+void PMPattern::setSlopeLoAlt( double c )
+{
+ if ( c != m_slopeLoAlt )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSlopeLoAltID, m_slopeLoAlt );
+ m_slopeLoAlt = c;
+ }
+}
+
+void PMPattern::setSlopeHiAlt( double c )
+{
+ if ( c != m_slopeHiAlt )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSlopeHiAltID, m_slopeHiAlt );
+ m_slopeHiAlt = c;
+ }
+}
+
+void PMPattern::setSpiralNumberArms( int c )
+{
+ if( c != m_spiralNumberArms )
+ {
+ if(m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSpiralNumberArmsID, m_spiralNumberArms );
+ m_spiralNumberArms = c;
+ }
+}
+
+void PMPattern::setNoiseGenerator( PMNoiseType c )
+{
+ if( c != m_noiseGenerator )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMNoiseGeneratorID, m_noiseGenerator );
+ m_noiseGenerator = c;
+ }
+}
+
+void PMPattern::enableTurbulence( bool c )
+{
+ if( c != m_enableTurbulence )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableTurbulenceID, m_enableTurbulence );
+ m_enableTurbulence = c;
+ }
+}
+
+void PMPattern::setValueVector( const PMVector& c )
+{
+ if( c != m_valueVector )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMValueVectorID, m_valueVector );
+ m_valueVector = c;
+ }
+}
+
+void PMPattern::setOctaves( const int c )
+{
+ if( c != m_octaves )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMOctavesID, m_octaves );
+ m_octaves = c;
+ }
+}
+
+void PMPattern::setOmega( const double c )
+{
+ if( c != m_omega )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMOmegaID, m_omega );
+ m_omega = c;
+ }
+}
+
+void PMPattern::setLambda( const double c )
+{
+ if( c != m_lambda )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMLambdaID, m_lambda );
+ m_lambda = c;
+ }
+}
+
+void PMPattern::setDepth( const double c )
+{
+ if( c != m_depth )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMDepthID, m_depth );
+ m_depth = c;
+ }
+}
+
+PMDialogEditBase* PMPattern::editWidget( QWidget* parent ) const
+{
+ return new PMPatternEdit( parent );
+}
+
+void PMPattern::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMPatternTypeID:
+ setPatternType( ( PMPatternType )data->intData( ) );
+ break;
+
+ case PMAgateTurbulenceID:
+ setAgateTurbulence( data->doubleData( ) );
+ break;
+
+ case PMCrackleFormID:
+ setCrackleForm( data->vectorData( ) );
+ break;
+ case PMCrackleMetricID:
+ setCrackleMetric( data->intData( ) );
+ break;
+ case PMCrackleOffsetID:
+ setCrackleOffset( data->doubleData( ) );
+ break;
+ case PMCrackleSolidID:
+ setCrackleSolid( data->boolData( ) );
+ break;
+
+ case PMDensityInterpolateID:
+ setDensityInterpolate( data->intData( ) );
+ break;
+ case PMDensityFileID:
+ setDensityFile( data->stringData( ) );
+ break;
+
+ case PMGradientID:
+ setGradient( data->vectorData( ) );
+ break;
+
+ case PMJuliaComplexID:
+ setJuliaComplex( data->vectorData( ) );
+ break;
+ case PMFractalMagnetID:
+ setFractalMagnet( data->boolData( ) );
+ break;
+ case PMFractalMagnetTypeID:
+ setFractalMagnetType( data->intData( ) );
+ break;
+ case PMMaxIterationsID:
+ setMaxIterations( data->intData( ) );
+ break;
+ case PMFractalExponentID:
+ setFractalExponent( data->intData( ) );
+ break;
+ case PMFractalExtTypeID:
+ setFractalExtType( data->intData( ) );
+ break;
+ case PMFractalExtFactorID:
+ setFractalExtFactor( data->doubleData( ) );
+ break;
+ case PMFractalIntTypeID:
+ setFractalIntType( data->intData( ) );
+ break;
+ case PMFractalIntFactorID:
+ setFractalIntFactor( data->doubleData( ) );
+ break;
+
+ case PMQuiltControl0ID:
+ setQuiltControl0( data->doubleData( ) );
+ break;
+ case PMQuiltControl1ID:
+ setQuiltControl1( data->doubleData( ) );
+ break;
+
+ case PMSlopeDirectionID:
+ setSlopeDirection( data->vectorData( ) );
+ break;
+ case PMSlopeLoSlopeID:
+ setSlopeLoSlope( data->doubleData( ) );
+ break;
+ case PMSlopeHiSlopeID:
+ setSlopeHiSlope( data->doubleData( ) );
+ break;
+ case PMSlopeAltFlagID:
+ setSlopeAltFlag( data->boolData( ) );
+ break;
+ case PMSlopeAltitudeID:
+ setSlopeAltitude( data->boolData( ) );
+ break;
+ case PMSlopeLoAltID:
+ setSlopeLoAlt( data->intData( ) );
+ break;
+ case PMSlopeHiAltID:
+ setSlopeHiAlt( data->intData( ) );
+ break;
+
+ case PMSpiralNumberArmsID:
+ setSpiralNumberArms( data->intData( ) );
+ break;
+
+ case PMNoiseGeneratorID:
+ setNoiseGenerator( ( PMNoiseType ) ( data->intData( ) ) );
+ break;
+
+ case PMEnableTurbulenceID:
+ enableTurbulence( data->boolData( ) );
+ break;
+ case PMValueVectorID:
+ setValueVector( data->vectorData( ) );
+ break;
+ case PMOctavesID:
+ setOctaves( data->intData( ) );
+ break;
+ case PMOmegaID:
+ setOmega( data->doubleData( ) );
+ break;
+ case PMLambdaID:
+ setLambda( data->doubleData( ) );
+ break;
+
+ case PMDepthID:
+ setDepth( data->doubleData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMPattern::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
diff --git a/kpovmodeler/pmpattern.h b/kpovmodeler/pmpattern.h
new file mode 100644
index 00000000..69001a41
--- /dev/null
+++ b/kpovmodeler/pmpattern.h
@@ -0,0 +1,449 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001-2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPATTERN_H
+#define PMPATTERN_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmobject.h"
+#include "pmvector.h"
+#include "pmcolor.h"
+
+#include <qvaluelist.h>
+#include <qvaluestack.h>
+
+/**
+ * Class for povray patterns.
+ */
+class PMPattern : public PMObject
+{
+ typedef PMObject Base;
+public:
+ /**
+ * The type of the pattern
+ */
+ enum PMPatternType { PatternAgate, PatternAverage, PatternBoxed,
+ PatternBozo, PatternBumps, PatternCells,
+ PatternCrackle, PatternCylindrical, PatternDensity,
+ PatternDents, PatternGradient, PatternGranite,
+ PatternJulia, PatternLeopard, PatternMandel,
+ PatternMarble, PatternOnion, PatternPlanar,
+ PatternQuilted, PatternRadial, PatternRipples,
+ PatternSlope, PatternSpherical, PatternSpiral1,
+ PatternSpiral2, PatternSpotted, PatternWaves,
+ PatternWood, PatternWrinkles };
+ /**
+ * The noise generators
+ */
+ enum PMNoiseType { GlobalSetting, Original, RangeCorrected, Perlin };
+ /**
+ * Creates a PMPattern
+ */
+ PMPattern( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMPattern( const PMPattern& p );
+ /**
+ * deletes the PMPattern
+ */
+ virtual ~PMPattern( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMPattern( *this ); }
+ /** */
+ virtual QString description( ) const;
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmpattern" ); }
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMPatternEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+
+ /**
+ * Gets the pattern type
+ */
+ PMPatternType patternType( ) const { return m_patternType; }
+ /**
+ * Gets the agate Turbulence*/
+ double agateTurbulence( ) const { return m_agateTurbulence; }
+ /**
+ * Gets the crackle form
+ */
+ PMVector crackleForm( ) const { return m_crackleForm; }
+ /**
+ * Gets the crackle metric
+ */
+ int crackleMetric( ) const { return m_crackleMetric; }
+ /**
+ * Gets the crackle offset
+ */
+ double crackleOffset( ) const { return m_crackleOffset; }
+ /**
+ * Gets the crackle solid flag
+ */
+ bool crackleSolid( ) const { return m_crackleSolid; }
+ /**
+ * Gets the desity file name
+ */
+ QString densityFile( ) const { return m_densityFile; }
+ /**
+ * Gets the density interpolation
+ */
+ int densityInterpolate( ) const { return m_densityInterpolate; }
+ /**
+ * Gets the gradint vector
+ */
+ PMVector gradient( ) const { return m_gradient; }
+ /**
+ * Returns the Complex number for Julia Fractals
+ */
+ PMVector juliaComplex( ) const { return m_juliaComplex; }
+ /**
+ * Returns true if where using tha magnet types of fractals
+ */
+ bool fractalMagnet( ) const { return m_fractalMagnet; }
+ /**
+ * Returns the magnet type of a fractal
+ */
+ int fractalMagnetType( ) const { return m_fractalMagnetType; }
+ /**
+ * Gets the number of Iterations for fractals
+ */
+ int maxIterations( ) const { return m_maxIterations; }
+ /**
+ * Returns the exponent of a fractal
+ */
+ int fractalExponent( ) const { return m_fractalExponent; }
+ /**
+ * Returns the exterior type of a fractal
+ */
+ int fractalExtType( ) const { return m_fractalExtType; }
+ /**
+ * Return the exterior factor of a fractal
+ */
+ double fractalExtFactor( ) const { return m_fractalExtFactor; }
+ /**
+ * Returns the interior type of a fractal
+ */
+ int fractalIntType( ) const { return m_fractalIntType; }
+ /**
+ * Returns the interior factor of a fractal
+ */
+ double fractalIntFactor( ) const { return m_fractalIntFactor; }
+ /**
+ * Gets control0 for Quilt
+ */
+ double quiltControl0( ) const { return m_quiltControl0; }
+ /**
+ * Gets control1 for Quilt
+ */
+ double quiltControl1( ) const { return m_quiltControl1; }
+ /**
+ * Returns the slope direction
+ */
+ PMVector slopeDirection( ) const { return m_slopeDirection; }
+ /**
+ * Returns the low slope value
+ */
+ double slopeLoSlope( ) const { return m_slopeLoSlope; }
+ /**
+ * Returns the high slope value
+ */
+ double slopeHiSlope( ) const { return m_slopeHiSlope; }
+ /**
+ * Returns the slopes altitude flag
+ */
+ bool slopeAltFlag( ) const { return m_slopeAltFlag; }
+ /**
+ * Returns the altitude for the slope
+ */
+ PMVector slopeAltitude( ) const { return m_slopeAltitude; }
+ /**
+ * Returns the low altitude for slope
+ */
+ double slopeLoAltitude( ) const { return m_slopeLoAlt; }
+ /**
+ * Returns the high altitude for slope
+ */
+ double slopeHiAltitude( ) const { return m_slopeHiAlt; }
+ /**
+ * Gets the number of arms in spiral types 1 and 2
+ */
+ int spiralNumberArms( ) const { return m_spiralNumberArms; }
+ /**
+ * Returns the noise generator
+ */
+ PMNoiseType noiseGenerator( ) const { return m_noiseGenerator; };
+ /**
+ * Returns whether turbulence is enabled
+ */
+ bool isTurbulenceEnabled( ) const { return m_enableTurbulence; }
+ /**
+ * Gets the Turbulence vector
+ */
+ PMVector valueVector( ) const { return m_valueVector; }
+ /**
+ * Gets the turbulence octaves
+ */
+ int octaves( ) const { return m_octaves; }
+ /**
+ * Gets the turbulence omega
+ */
+ double omega( ) const { return m_omega; }
+ /**
+ * Gets the turbulence lambda
+ */
+ double lambda( ) const { return m_lambda; }
+ /**
+ * Returns depth (only has meaning inside a normal)
+ */
+ double depth( ) const { return m_depth; }
+
+ /**
+ * Sets the pattern type
+ */
+ void setPatternType( PMPatternType l );
+ /**
+ * Sets agate turbulence
+ */
+ void setAgateTurbulence( double c );
+ /**
+ * Sets the crackle form
+ */
+ void setCrackleForm( const PMVector& v );
+ /**
+ * Sets the crackle metric
+ */
+ void setCrackleMetric( int c );
+ /**
+ * Sets the crackle offset
+ */
+ void setCrackleOffset( double c );
+ /**
+ * Sets the crackle solid flag
+ */
+ void setCrackleSolid( bool c );
+ /**
+ * Sets the Density File Name
+ */
+ void setDensityFile( const QString& v );
+ /**
+ * Sets the density interpolation
+ */
+ void setDensityInterpolate( int c );
+ /**
+ * sets gradient vector
+ */
+ void setGradient( const PMVector& v );
+ /**
+ * Sets the complex number for Julia
+ */
+ void setJuliaComplex( const PMVector& v );
+ /**
+ * Sets if where using magnet types of fractals
+ */
+ void setFractalMagnet( bool c );
+ /**
+ * Sets the magnet type of a fractal
+ */
+ void setFractalMagnetType( int c );
+ /**
+ * Sets the maximum iterations for fractals
+ */
+ void setMaxIterations( int c );
+ /**
+ * Sets the exponent for fractals
+ */
+ void setFractalExponent( int c );
+ /**
+ * Sets the exterior type of fractals
+ */
+ void setFractalExtType( int c );
+ /**
+ * Sets the exterior factor of fractals
+ */
+ void setFractalExtFactor( double c );
+ /**
+ * Sets the interior type of fractals
+ */
+ void setFractalIntType( int c );
+ /**
+ * Sets the interior factor of fractals
+ */
+ void setFractalIntFactor( double c );
+ /**
+ * Sets quilt control 0
+ */
+ void setQuiltControl0( double c );
+ /**
+ * Sets quite control 1
+ */
+ void setQuiltControl1( double c );
+ /**
+ * Sets the slope direction
+ */
+ void setSlopeDirection( const PMVector& v );
+ /**
+ * Sets the low slope value
+ */
+ void setSlopeLoSlope( double c );
+ /**
+ * Sets the high slope value
+ */
+ void setSlopeHiSlope( double c );
+ /**
+ * Sets the slopes altitude flag
+ */
+ void setSlopeAltFlag( bool c );
+ /**
+ * Sets the slopes alititude direction
+ */
+ void setSlopeAltitude( const PMVector& v );
+ /**
+ * Sets the slopes low altitude
+ */
+ void setSlopeLoAlt( double c );
+ /**
+ * Sets the slopes high altitude
+ */
+ void setSlopeHiAlt( double c );
+ /**
+ * Sets the number of spiral arms
+ */
+ void setSpiralNumberArms( int c );
+ /**
+ * Sets noise generator
+ */
+ void setNoiseGenerator( PMNoiseType c );
+ /**
+ * Enables turbulence
+ */
+ void enableTurbulence( bool c );
+ /**
+ * sets the turbulence vector
+ */
+ void setValueVector( const PMVector& v );
+ /**
+ * Sets the turbulence octaves
+ */
+ void setOctaves( int c );
+ /**
+ * Sets the turblence omega
+ */
+ void setOmega( double c );
+ /**
+ * Sets the turbulence Lambda
+ */
+ void setLambda( double c );
+ /**
+ * Sets the depth value (only inside normals)
+ */
+ void setDepth( double c );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMPatternMementoID { PMPatternTypeID, PMAgateTurbulenceID, PMCrackleFormID,
+ PMCrackleMetricID, PMCrackleOffsetID, PMCrackleSolidID,
+ PMDensityFileID, PMDensityInterpolateID, PMGradientID,
+ PMJuliaComplexID, PMFractalMagnetID, PMFractalMagnetTypeID,
+ PMMaxIterationsID, PMFractalExponentID, PMFractalExtTypeID,
+ PMFractalExtFactorID, PMFractalIntTypeID, PMFractalIntFactorID,
+ PMQuiltControl0ID, PMQuiltControl1ID, PMSlopeDirectionID,
+ PMSlopeLoSlopeID, PMSlopeHiSlopeID, PMSlopeAltFlagID,
+ PMSlopeAltitudeID, PMSlopeLoAltID, PMSlopeHiAltID,
+ PMSpiralNumberArmsID, PMNoiseGeneratorID, PMEnableTurbulenceID,
+ PMValueVectorID, PMOctavesID, PMOmegaID, PMLambdaID, PMDepthID };
+ /**
+ * Pattern type
+ */
+ PMPatternType m_patternType;
+
+ // Extra values for Individual Patterns
+ // Agate
+ double m_agateTurbulence;
+ // crackle
+ PMVector m_crackleForm;
+ int m_crackleMetric;
+ double m_crackleOffset;
+ bool m_crackleSolid;
+ // density
+ QString m_densityFile;
+ int m_densityInterpolate;
+ // gradient
+ PMVector m_gradient;
+ // Julia
+ PMVector m_juliaComplex;
+ // Fractal patterns Mandel and Julia
+ bool m_fractalMagnet;
+ int m_fractalMagnetType;
+ int m_maxIterations;
+ int m_fractalExponent;
+ int m_fractalExtType;
+ double m_fractalExtFactor;
+ int m_fractalIntType;
+ double m_fractalIntFactor;
+ // quilt
+ double m_quiltControl0;
+ double m_quiltControl1;
+ // slope
+ PMVector m_slopeDirection;
+ double m_slopeLoSlope;
+ double m_slopeHiSlope;
+ bool m_slopeAltFlag;
+ PMVector m_slopeAltitude;
+ double m_slopeLoAlt;
+ double m_slopeHiAlt;
+ // Spiral
+ int m_spiralNumberArms;
+
+ // noise generator type for Bozo, Bumps, Granite and Wrinkles.
+ PMNoiseType m_noiseGenerator;
+
+ // Turbulence available for all patterns
+ bool m_enableTurbulence;
+ PMVector m_valueVector;
+ int m_octaves;
+ double m_omega;
+ double m_lambda;
+ // depth when used with Normal
+ double m_depth;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmpatternedit.cpp b/kpovmodeler/pmpatternedit.cpp
new file mode 100644
index 00000000..1f9647c2
--- /dev/null
+++ b/kpovmodeler/pmpatternedit.cpp
@@ -0,0 +1,1073 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+ copyright : (C) 2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmpatternedit.h"
+#include "pmpattern.h"
+#include "pmvectoredit.h"
+#include "pmlineedits.h"
+#include "pmvector.h"
+
+#include <qwidget.h>
+#include <qlayout.h>
+#include <qcombobox.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qcheckbox.h>
+#include <qpushbutton.h>
+#include <ktabctl.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdialog.h>
+#include <kfiledialog.h>
+#include <kiconloader.h>
+
+PMPatternEdit::PMPatternEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMPatternEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QGridLayout* layout;
+ QHBoxLayout* hl;
+ QVBoxLayout* vl;
+ QGridLayout* gl;
+
+ layout = new QGridLayout( topLayout( ), 12, 2 );
+ hl = new QHBoxLayout( KDialog::spacingHint( ) );
+ hl->addWidget( new QLabel( i18n( "Type:" ), this ) );
+ m_pTypeCombo = new QComboBox( false, this );
+ m_pTypeCombo->insertItem( i18n( "Agate" ) );
+ m_pTypeCombo->insertItem( i18n( "Average" ) );
+ m_pTypeCombo->insertItem( i18n( "Boxed" ) );
+ m_pTypeCombo->insertItem( i18n( "Bozo" ) );
+ m_pTypeCombo->insertItem( i18n( "Bumps" ) );
+ m_pTypeCombo->insertItem( i18n( "Cells" ) );
+ m_pTypeCombo->insertItem( i18n( "Crackle" ) );
+ m_pTypeCombo->insertItem( i18n( "Cylindrical" ) );
+ m_pTypeCombo->insertItem( i18n( "Density File" ) );
+ m_pTypeCombo->insertItem( i18n( "Dents" ) );
+ m_pTypeCombo->insertItem( i18n( "Gradient" ) );
+ m_pTypeCombo->insertItem( i18n( "Granite" ) );
+ m_pTypeCombo->insertItem( i18n( "Julia" ) );
+ m_pTypeCombo->insertItem( i18n( "Leopard" ) );
+ m_pTypeCombo->insertItem( i18n( "Mandel" ) );
+ m_pTypeCombo->insertItem( i18n( "Marble" ) );
+ m_pTypeCombo->insertItem( i18n( "Onion" ) );
+ m_pTypeCombo->insertItem( i18n( "Planar" ) );
+ m_pTypeCombo->insertItem( i18n( "Quilt" ) );
+ m_pTypeCombo->insertItem( i18n( "Radial" ) );
+ m_pTypeCombo->insertItem( i18n( "Ripples" ) );
+ m_pTypeCombo->insertItem( i18n( "Slope" ) );
+ m_pTypeCombo->insertItem( i18n( "Spherical" ) );
+ m_pTypeCombo->insertItem( i18n( "Spiral1" ) );
+ m_pTypeCombo->insertItem( i18n( "Spiral2" ) );
+ m_pTypeCombo->insertItem( i18n( "Spotted" ) );
+ m_pTypeCombo->insertItem( i18n( "Waves" ) );
+ m_pTypeCombo->insertItem( i18n( "Wood" ) );
+ m_pTypeCombo->insertItem( i18n( "Wrinkles" ) );
+ hl->addWidget( m_pTypeCombo );
+ hl->addStretch( 1 );
+ layout->addMultiCellLayout( hl, 0, 0, 0, 1 );
+
+ m_pAgateTurbulenceLabel = new QLabel( i18n( "Turbulence:" ), this );
+ layout->addWidget( m_pAgateTurbulenceLabel, 1, 0 );
+ m_pAgateTurbulenceEdit = new PMFloatEdit( this );
+ layout->addWidget( m_pAgateTurbulenceEdit, 1, 1, AlignLeft );
+
+ m_pCrackleWidget = new QWidget( this );
+ vl = new QVBoxLayout( m_pCrackleWidget, 0, KDialog::spacingHint( ) );
+ hl = new QHBoxLayout( vl );
+ hl->addWidget( new QLabel( i18n( "Form:" ), m_pCrackleWidget ) );
+ m_pCrackleForm = new PMVectorEdit( "x", "y", "z", m_pCrackleWidget );
+ hl->addWidget( m_pCrackleForm );
+ hl->addStretch( 1 );
+ hl = new QHBoxLayout( vl );
+ gl = new QGridLayout( hl, 3, 2 );
+ gl->addWidget( new QLabel( i18n( "Metric:" ), m_pCrackleWidget ), 0, 0 );
+ m_pCrackleMetric = new PMIntEdit( m_pCrackleWidget );
+ m_pCrackleMetric->setValidation( true, 1, false, 0 );
+ gl->addWidget( m_pCrackleMetric, 0, 1 );
+ gl->addWidget( new QLabel( i18n( "Offset:" ), m_pCrackleWidget ), 1, 0 );
+ m_pCrackleOffset = new PMFloatEdit( m_pCrackleWidget );
+ gl->addWidget( m_pCrackleOffset, 1, 1 );
+ m_pCrackleSolid = new QCheckBox( i18n( "Solid:" ), m_pCrackleWidget );
+ gl->addMultiCellWidget( m_pCrackleSolid, 2, 2, 0, 1 );
+ hl->addStretch( 1 );
+ layout->addMultiCellWidget( m_pCrackleWidget, 2, 2, 0, 1 );
+
+ m_pDensityWidget = new QWidget( this );
+ vl = new QVBoxLayout( m_pDensityWidget, 0, KDialog::spacingHint( ) );
+ hl = new QHBoxLayout( vl );
+ hl->addWidget( new QLabel( i18n( "File:" ), m_pDensityWidget ) );
+ m_pDensityFile = new QLineEdit( m_pDensityWidget );
+ hl->addWidget( m_pDensityFile, 1 );
+ m_pDensityFileBrowse = new QPushButton( m_pDensityWidget );
+ m_pDensityFileBrowse->setPixmap( SmallIcon( "fileopen" ) );
+ hl->addWidget( m_pDensityFileBrowse );
+ hl = new QHBoxLayout( vl );
+ hl->addWidget( new QLabel( i18n( "Interpolation:" ), m_pDensityWidget ) );
+ m_pDensityInterpolate = new QComboBox( false, m_pDensityWidget );
+ m_pDensityInterpolate->insertItem( i18n( "None" ) );
+ m_pDensityInterpolate->insertItem( i18n( "Trilinear" ) );
+ hl->addWidget( m_pDensityInterpolate );
+ hl->addStretch( 1 );
+ layout->addMultiCellWidget( m_pDensityWidget, 3, 3, 0, 1 );
+
+ m_pGradientLabel = new QLabel( i18n( "Gradient:" ), this );
+ layout->addWidget( m_pGradientLabel, 4, 0 );
+ m_pGradientEdit = new PMVectorEdit( "x", "y", "z", this );
+ layout->addWidget( m_pGradientEdit, 4, 1 );
+
+ m_pJuliaComplexLabel = new QLabel( i18n( "Complex number:" ), this );
+ layout->addWidget( m_pJuliaComplexLabel, 5, 0 );
+ m_pJuliaComplex = new PMVectorEdit( "Real", "Imaginary", this );
+ layout->addWidget( m_pJuliaComplex, 5, 1 );
+
+ m_pFractalWidget = new QWidget( this );
+ vl = new QVBoxLayout( m_pFractalWidget, 0, KDialog::spacingHint( ) );
+ hl = new QHBoxLayout( vl );
+ m_pFractalMagnet = new QCheckBox( i18n( "Magnet" ), m_pFractalWidget );
+ hl->addWidget( m_pFractalMagnet );
+ m_pFractalMagnetType = new QComboBox( false, m_pFractalWidget );
+ m_pFractalMagnetType->insertItem( i18n( "Type 1" ) );
+ m_pFractalMagnetType->insertItem( i18n( "Type 2" ) );
+ hl->addWidget( m_pFractalMagnetType );
+ hl->addStretch( 1 );
+ hl = new QHBoxLayout( vl );
+ gl = new QGridLayout( hl, 2, 2 );
+ gl->addWidget( new QLabel( i18n( "Maximum iterations:" ), m_pFractalWidget ), 0, 0 );
+ m_pMaxIterationsEdit = new PMIntEdit( m_pFractalWidget );
+ m_pMaxIterationsEdit->setValidation( true, 1, false, 0 );
+ gl->addWidget( m_pMaxIterationsEdit, 0, 1 );
+ m_pFractalExponentLabel = new QLabel( i18n( "Exponent:" ), m_pFractalWidget );
+ gl->addWidget( m_pFractalExponentLabel, 1, 0 );
+ m_pFractalExponent = new PMIntEdit( m_pFractalWidget );
+ m_pFractalExponent->setValidation( true, 2, true, 33 );
+ gl->addWidget( m_pFractalExponent, 1, 1 );
+ hl->addStretch( 1 );
+ hl = new QHBoxLayout( vl );
+ gl = new QGridLayout( hl, 2, 4 );
+ gl->addWidget( new QLabel( i18n( "Exterior type:" ), m_pFractalWidget ), 0, 0 );
+ m_pFractalExtType = new QComboBox( false, m_pFractalWidget );
+ m_pFractalExtType->insertItem( i18n( "0: Returns Just 1" ) );
+ m_pFractalExtType->insertItem( i18n( "1: Iterations Until Bailout" ) );
+ m_pFractalExtType->insertItem( i18n( "2: Real Part" ) );
+ m_pFractalExtType->insertItem( i18n( "3: Imaginary Part" ) );
+ m_pFractalExtType->insertItem( i18n( "4: Squared Real Part" ) );
+ m_pFractalExtType->insertItem( i18n( "5: Squared Imaginary Part" ) );
+ m_pFractalExtType->insertItem( i18n( "6: Absolute Value" ) );
+ gl->addWidget( m_pFractalExtType, 0, 1 );
+ gl->addWidget( new QLabel( i18n( "Factor:" ), m_pFractalWidget ), 0, 2 );
+ m_pFractalExtFactor = new PMFloatEdit( m_pFractalWidget );
+ gl->addWidget( m_pFractalExtFactor, 0, 3 );
+ gl->addWidget( new QLabel( i18n( "Interior type:" ), m_pFractalWidget ), 1, 0 );
+ m_pFractalIntType = new QComboBox( false, m_pFractalWidget );
+ m_pFractalIntType->insertItem( i18n( "0: Returns Just 1" ) );
+ m_pFractalIntType->insertItem( i18n( "1: Absolute Value Smallest" ) );
+ m_pFractalIntType->insertItem( i18n( "2: Real Part" ) );
+ m_pFractalIntType->insertItem( i18n( "3: Imaginary Part" ) );
+ m_pFractalIntType->insertItem( i18n( "4: Squared Real Part" ) );
+ m_pFractalIntType->insertItem( i18n( "5: Squared Imaginary Part" ) );
+ m_pFractalIntType->insertItem( i18n( "6: Absolute Value Last" ) );
+ gl->addWidget( m_pFractalIntType, 1, 1 );
+ gl->addWidget( new QLabel( i18n( "Factor:" ), m_pFractalWidget ), 1, 2 );
+ m_pFractalIntFactor = new PMFloatEdit( m_pFractalWidget );
+ gl->addWidget( m_pFractalIntFactor, 1, 3 );
+ hl->addStretch( 1 );
+ layout->addMultiCellWidget( m_pFractalWidget, 6, 6, 0, 1 );
+
+ m_pQuiltControlsLabel = new QLabel( i18n( "Quilt controls:" ), this );
+ m_pQuiltControl0Edit = new PMFloatEdit( this );
+ m_pQuiltControl1Edit = new PMFloatEdit( this );
+ hl = new QHBoxLayout( );
+ hl->addWidget( m_pQuiltControl0Edit );
+ hl->addWidget( m_pQuiltControl1Edit );
+ hl->addStretch( 1 );
+ layout->addWidget( m_pQuiltControlsLabel, 7, 0 );
+ layout->addLayout( hl, 7, 1 );
+
+ m_pSlopeWidget = new QWidget( this );
+ vl = new QVBoxLayout( m_pSlopeWidget, 0, KDialog::spacingHint( ) );
+ hl = new QHBoxLayout( vl );
+ hl->addWidget( new QLabel( i18n( "Direction:" ), m_pSlopeWidget ) );
+ m_pSlopeDirection = new PMVectorEdit( "x", "y", "z", m_pSlopeWidget );
+ hl->addWidget( m_pSlopeDirection );
+ hl = new QHBoxLayout( vl );
+ gl = new QGridLayout( hl, 2, 2 );
+ gl->addWidget( new QLabel( i18n( "Low slope:" ), m_pSlopeWidget ), 0, 0 );
+ m_pSlopeLoSlope = new PMFloatEdit( m_pSlopeWidget );
+ m_pSlopeLoSlope->setValidation( true, 0.0, true, 1.0 );
+ gl->addWidget( m_pSlopeLoSlope, 0, 1 );
+ gl->addWidget( new QLabel( i18n( "High slope:" ), m_pSlopeWidget ), 1, 0 );
+ m_pSlopeHiSlope = new PMFloatEdit( m_pSlopeWidget );
+ m_pSlopeHiSlope->setValidation( true, 0.0, true, 1.0 );
+ gl->addWidget( m_pSlopeHiSlope, 1, 1 );
+ hl->addStretch( 1 );
+ hl = new QHBoxLayout( vl );
+ m_pSlopeAltFlag = new QCheckBox( i18n( "Altitiude" ), m_pSlopeWidget );
+ hl->addWidget( m_pSlopeAltFlag );
+ m_pSlopeAltitude = new PMVectorEdit( "x", "y", "z", m_pSlopeWidget );
+ hl->addWidget( m_pSlopeAltitude );
+ hl = new QHBoxLayout( vl );
+ gl = new QGridLayout( hl, 2, 2 );
+ m_pSlopeLoAltLabel = new QLabel( i18n( "Low altitude:" ), m_pSlopeWidget );
+ gl->addWidget( m_pSlopeLoAltLabel, 0, 0 );
+ m_pSlopeLoAlt = new PMFloatEdit( m_pSlopeWidget );
+ gl->addWidget( m_pSlopeLoAlt, 0, 1 );
+ m_pSlopeHiAltLabel = new QLabel( i18n( "High altitude:" ), m_pSlopeWidget );
+ gl->addWidget( m_pSlopeHiAltLabel, 1, 0 );
+ m_pSlopeHiAlt = new PMFloatEdit( m_pSlopeWidget );
+ gl->addWidget( m_pSlopeHiAlt, 1, 1 );
+ hl->addStretch( 1 );
+ layout->addMultiCellWidget( m_pSlopeWidget, 8, 8, 0, 1 );
+
+ m_pSpiralNumberLabel = new QLabel( i18n( "Spiral number:" ), this );
+ m_pSpiralNumberEdit = new PMIntEdit( this );
+ layout->addWidget( m_pSpiralNumberLabel, 9, 0 );
+ layout->addWidget( m_pSpiralNumberEdit, 9, 1, AlignLeft );
+
+ m_pDepthLabel = new QLabel( i18n( "Depth:" ), this );
+ m_pDepthEdit = new PMFloatEdit( this );
+ layout->addWidget( m_pDepthLabel, 10, 0 );
+ layout->addWidget( m_pDepthEdit, 10, 1, AlignLeft );
+
+ m_pNoiseGeneratorLabel = new QLabel( i18n( "Noise generator:" ), this );
+ m_pNoiseGenerator = new QComboBox( false, this );
+ m_pNoiseGenerator->insertItem( i18n( "Use Global Setting" ) );
+ m_pNoiseGenerator->insertItem( i18n( "Original" ) );
+ m_pNoiseGenerator->insertItem( i18n( "Range Corrected" ) );
+ m_pNoiseGenerator->insertItem( i18n( "Perlin" ) );
+ layout->addWidget( m_pNoiseGeneratorLabel, 11, 0 );
+ layout->addWidget( m_pNoiseGenerator, 11, 1 );
+
+ m_pEnableTurbulenceEdit = new QCheckBox( i18n( "Turbulence" ), this );
+ topLayout( )->addWidget( m_pEnableTurbulenceEdit );
+ m_pTurbulenceWidget = new QWidget( this );
+ vl = new QVBoxLayout( m_pTurbulenceWidget, 0, KDialog::spacingHint( ) );
+ hl = new QHBoxLayout( vl );
+ hl->addWidget( new QLabel( i18n( "Value:" ), m_pTurbulenceWidget ) );
+ m_pValueVectorEdit = new PMVectorEdit( "x", "y", "z", m_pTurbulenceWidget );
+ hl->addWidget( m_pValueVectorEdit );
+ hl = new QHBoxLayout( vl );
+ gl = new QGridLayout( hl, 3, 2 );
+ gl->addWidget( new QLabel( i18n( "Octaves:" ), m_pTurbulenceWidget ), 0, 0 );
+ m_pOctavesEdit = new PMIntEdit( m_pTurbulenceWidget );
+ gl->addWidget( m_pOctavesEdit, 0, 1 );
+ gl->addWidget( new QLabel( i18n( "Omega:" ), m_pTurbulenceWidget ), 1, 0 );
+ m_pOmegaEdit = new PMFloatEdit( m_pTurbulenceWidget );
+ gl->addWidget( m_pOmegaEdit, 1, 1 );
+ gl->addWidget( new QLabel( i18n( "Lambda:" ), m_pTurbulenceWidget ), 2, 0 );
+ m_pLambdaEdit = new PMFloatEdit( m_pTurbulenceWidget );
+ gl->addWidget( m_pLambdaEdit, 2, 1 );
+ hl->addStretch( 1 );
+ topLayout( )->addWidget( m_pTurbulenceWidget );
+
+ /* connect all signals to slots/signals */
+ connect( m_pTypeCombo, SIGNAL( activated( int ) ), SLOT( slotComboChanged( int ) ) );
+
+ connect( m_pAgateTurbulenceEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+
+ connect( m_pCrackleForm, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pCrackleMetric, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pCrackleOffset, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pCrackleSolid, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+
+ connect( m_pDensityInterpolate, SIGNAL( activated( int ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pDensityFile, SIGNAL( textChanged( const QString& ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pDensityFileBrowse, SIGNAL( clicked( ) ), SLOT( slotDensityFileBrowseClicked( ) ) );
+
+ connect( m_pGradientEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+
+ connect( m_pJuliaComplex, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pFractalMagnet, SIGNAL( clicked( ) ), SLOT( slotFractalMagnetClicked( ) ) );
+ connect( m_pFractalMagnetType, SIGNAL( activated( int ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pMaxIterationsEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pFractalExponent, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pFractalExtType, SIGNAL( activated( int ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pFractalExtFactor, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pFractalIntType, SIGNAL( activated( int ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pFractalIntFactor, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+
+ connect( m_pQuiltControl0Edit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pQuiltControl1Edit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+
+ connect( m_pSlopeDirection, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pSlopeLoSlope, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pSlopeHiSlope, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pSlopeAltFlag, SIGNAL( clicked( ) ), SLOT( slotSlopeAltFlagClicked( ) ) );
+ connect( m_pSlopeAltitude, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pSlopeLoAlt, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pSlopeHiAlt, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+
+ connect( m_pSpiralNumberEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+
+ connect( m_pNoiseGenerator, SIGNAL( activated( int ) ), SIGNAL( dataChanged( ) ) );
+
+ connect( m_pEnableTurbulenceEdit, SIGNAL( clicked( ) ), SLOT( slotTurbulenceClicked( ) ) );
+ connect( m_pValueVectorEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pOctavesEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pOmegaEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pLambdaEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pDepthEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMPatternEdit::displayObject( PMObject* o )
+{
+ QString str;
+ bool readOnly;
+
+ if( o->isA( "Pattern" ) )
+ {
+ m_pDisplayedObject = ( PMPattern* ) o;
+ readOnly = m_pDisplayedObject->isReadOnly( );
+
+ switch( m_pDisplayedObject->patternType( ) )
+ {
+ case PMPattern::PatternAgate:
+ setPatternType( 0 );
+ break;
+ case PMPattern::PatternAverage:
+ setPatternType( 1 );
+ break;
+ case PMPattern::PatternBoxed:
+ setPatternType( 2 );
+ break;
+ case PMPattern::PatternBozo:
+ setPatternType( 3 );
+ break;
+ case PMPattern::PatternBumps:
+ setPatternType( 4 );
+ break;
+ case PMPattern::PatternCells:
+ setPatternType( 5 );
+ break;
+ case PMPattern::PatternCrackle:
+ setPatternType( 6 );
+ break;
+ case PMPattern::PatternCylindrical:
+ setPatternType( 7 );
+ break;
+ case PMPattern::PatternDensity:
+ setPatternType( 8 );
+ break;
+ case PMPattern::PatternDents:
+ setPatternType( 9 );
+ break;
+ case PMPattern::PatternGradient:
+ setPatternType( 10 );
+ break;
+ case PMPattern::PatternGranite:
+ setPatternType( 11 );
+ break;
+ case PMPattern::PatternJulia:
+ setPatternType( 12 );
+ break;
+ case PMPattern::PatternLeopard:
+ setPatternType( 13 );
+ break;
+ case PMPattern::PatternMandel:
+ setPatternType( 14 );
+ break;
+ case PMPattern::PatternMarble:
+ setPatternType( 15 );
+ break;
+ case PMPattern::PatternOnion:
+ setPatternType( 16 );
+ break;
+ case PMPattern::PatternPlanar:
+ setPatternType( 17 );
+ break;
+ case PMPattern::PatternQuilted:
+ setPatternType( 18 );
+ break;
+ case PMPattern::PatternRadial:
+ setPatternType( 19 );
+ break;
+ case PMPattern::PatternRipples:
+ setPatternType( 20 );
+ break;
+ case PMPattern::PatternSlope:
+ setPatternType( 21 );
+ break;
+ case PMPattern::PatternSpherical:
+ setPatternType( 22 );
+ break;
+ case PMPattern::PatternSpiral1:
+ setPatternType( 23 );
+ break;
+ case PMPattern::PatternSpiral2:
+ setPatternType( 24 );
+ break;
+ case PMPattern::PatternSpotted:
+ setPatternType( 25 );
+ break;
+ case PMPattern::PatternWaves:
+ setPatternType( 26 );
+ break;
+ case PMPattern::PatternWood:
+ setPatternType( 27 );
+ break;
+ case PMPattern::PatternWrinkles:
+ setPatternType( 28 );
+ break;
+ }
+ m_pTypeCombo->setEnabled( !readOnly );
+
+ m_pAgateTurbulenceEdit->setValue( m_pDisplayedObject->agateTurbulence( ) );
+ m_pAgateTurbulenceEdit->setReadOnly( readOnly );
+
+ m_pCrackleForm->setVector( m_pDisplayedObject->crackleForm( ) );
+ m_pCrackleForm->setReadOnly( readOnly );
+ m_pCrackleMetric->setValue( m_pDisplayedObject->crackleMetric( ) );
+ m_pCrackleMetric->setReadOnly( readOnly );
+ m_pCrackleOffset->setValue( m_pDisplayedObject->crackleOffset( ) );
+ m_pCrackleOffset->setReadOnly( readOnly );
+ m_pCrackleSolid->setChecked( m_pDisplayedObject->crackleSolid( ) );
+ m_pCrackleSolid->setEnabled( !readOnly );
+
+ m_pDensityFile->setText( m_pDisplayedObject->densityFile( ) );
+ m_pDensityFile->setEnabled( !readOnly );
+ m_pDensityInterpolate->setCurrentItem( m_pDisplayedObject->densityInterpolate( ) );
+ m_pDensityInterpolate->setEnabled( !readOnly );
+
+ m_pGradientEdit->setVector( m_pDisplayedObject->gradient( ) );
+ m_pGradientEdit->setReadOnly( readOnly );
+
+ m_pJuliaComplex->setVector( m_pDisplayedObject->juliaComplex( ) );
+ m_pJuliaComplex->setReadOnly( readOnly );
+ m_pFractalMagnet->setChecked( m_pDisplayedObject->fractalMagnet( ) );
+ m_pFractalMagnet->setEnabled( !readOnly );
+ m_pFractalMagnetType->setCurrentItem( m_pDisplayedObject->fractalMagnetType( ) - 1 );
+ m_pFractalMagnetType->setEnabled( !readOnly );
+ m_pMaxIterationsEdit->setValue( m_pDisplayedObject->maxIterations( ) );
+ m_pMaxIterationsEdit->setReadOnly( readOnly );
+ m_pFractalExponent->setValue( m_pDisplayedObject->fractalExponent( ) );
+ m_pFractalExponent->setReadOnly( readOnly );
+ m_pFractalExtType->setCurrentItem( m_pDisplayedObject->fractalExtType( ) );
+ m_pFractalExtType->setEnabled( !readOnly );
+ m_pFractalExtFactor->setValue( m_pDisplayedObject->fractalExtFactor( ) );
+ m_pFractalExtFactor->setReadOnly( readOnly );
+ m_pFractalIntType->setCurrentItem( m_pDisplayedObject->fractalIntType( ) );
+ m_pFractalIntType->setEnabled( !readOnly );
+ m_pFractalIntFactor->setValue( m_pDisplayedObject->fractalIntFactor( ) );
+ m_pFractalIntFactor->setReadOnly( readOnly );
+
+ m_pQuiltControl0Edit->setValue( m_pDisplayedObject->quiltControl0( ) );
+ m_pQuiltControl0Edit->setReadOnly( readOnly );
+ m_pQuiltControl1Edit->setValue( m_pDisplayedObject->quiltControl1( ) );
+ m_pQuiltControl1Edit->setReadOnly( readOnly );
+
+ m_pSlopeDirection->setVector( m_pDisplayedObject->slopeDirection( ) );
+ m_pSlopeDirection->setReadOnly( readOnly );
+ m_pSlopeLoSlope->setValue( m_pDisplayedObject->slopeLoSlope( ) );
+ m_pSlopeLoSlope->setReadOnly( readOnly );
+ m_pSlopeHiSlope->setValue( m_pDisplayedObject->slopeHiSlope( ) );
+ m_pSlopeHiSlope->setReadOnly( readOnly );
+ m_pSlopeAltFlag->setChecked( m_pDisplayedObject->slopeAltFlag( ) );
+ m_pSlopeAltFlag->setEnabled( !readOnly );
+ m_pSlopeAltitude->setVector( m_pDisplayedObject->slopeAltitude( ) );
+ m_pSlopeAltitude->setReadOnly( readOnly );
+ m_pSlopeLoAlt->setValue( m_pDisplayedObject->slopeLoAltitude( ) );
+ m_pSlopeLoAlt->setReadOnly( readOnly );
+ m_pSlopeHiAlt->setValue( m_pDisplayedObject->slopeHiAltitude( ) );
+ m_pSlopeHiAlt->setReadOnly( readOnly );
+
+ m_pSpiralNumberEdit->setValue( m_pDisplayedObject->spiralNumberArms( ) );
+ m_pSpiralNumberEdit->setReadOnly( readOnly );
+
+ m_pNoiseGenerator->setCurrentItem( m_pDisplayedObject->noiseGenerator( ) );
+ m_pNoiseGenerator->setEnabled( !readOnly );
+
+ m_pEnableTurbulenceEdit->setChecked( m_pDisplayedObject->isTurbulenceEnabled( ) );
+ m_pEnableTurbulenceEdit->setEnabled( !readOnly );
+ m_pValueVectorEdit->setVector( m_pDisplayedObject->valueVector( ) );
+ m_pValueVectorEdit->setReadOnly( readOnly );
+ m_pOctavesEdit->setValue( m_pDisplayedObject->octaves( ) );
+ m_pOctavesEdit->setReadOnly( readOnly );
+ m_pOmegaEdit->setValue( m_pDisplayedObject->omega( ) );
+ m_pOmegaEdit->setReadOnly( readOnly );
+ m_pLambdaEdit->setValue( m_pDisplayedObject->lambda( ) );
+ m_pLambdaEdit->setReadOnly( readOnly );
+
+ if( o->parent( ) && ( o->parent( )->type( ) == "Normal" ) )
+ {
+ m_pDepthEdit->setValue( m_pDisplayedObject->depth( ) );
+ m_pDepthEdit->setReadOnly( readOnly );
+ m_pDepthEdit->show( );
+ m_pDepthLabel->show( );
+ emit sizeChanged( );
+ }
+ else
+ {
+ m_pDepthEdit->hide( );
+ m_pDepthLabel->hide( );
+ emit sizeChanged( );
+ }
+
+ slotFractalMagnetClicked( );
+ slotSlopeAltFlagClicked( );
+ slotTurbulenceClicked( );
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMPatternEdit: Can't display object\n";
+}
+
+void PMPatternEdit::setPatternType( int i )
+{
+ m_pTypeCombo->setCurrentItem( i );
+ slotComboChanged( i );
+}
+
+void PMPatternEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ switch( m_pTypeCombo->currentItem( ) )
+ {
+ case 0:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternAgate );
+ m_pDisplayedObject->setAgateTurbulence( m_pAgateTurbulenceEdit->value( ) );
+ break;
+ case 1:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternAverage );
+ break;
+ case 2:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternBoxed );
+ break;
+ case 3:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternBozo );
+ m_pDisplayedObject->setNoiseGenerator(
+ ( PMPattern::PMNoiseType ) m_pNoiseGenerator->currentItem( ) );
+ break;
+ case 4:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternBumps );
+ m_pDisplayedObject->setNoiseGenerator(
+ ( PMPattern::PMNoiseType ) m_pNoiseGenerator->currentItem( ) );
+ break;
+ case 5:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternCells );
+ break;
+ case 6:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternCrackle );
+ m_pDisplayedObject->setCrackleForm( m_pCrackleForm->vector( ) );
+ m_pDisplayedObject->setCrackleMetric( m_pCrackleMetric->value( ) );
+ m_pDisplayedObject->setCrackleOffset( m_pCrackleOffset->value( ) );
+ m_pDisplayedObject->setCrackleSolid( m_pCrackleSolid->isChecked( ) );
+ break;
+ case 7:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternCylindrical );
+ break;
+ case 8:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternDensity );
+ m_pDisplayedObject->setDensityFile( m_pDensityFile->text( ) );
+ m_pDisplayedObject->setDensityInterpolate( m_pDensityInterpolate->currentItem( ) );
+ break;
+ case 9:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternDents );
+ break;
+ case 10:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternGradient );
+ m_pDisplayedObject->setGradient( m_pGradientEdit->vector( ) );
+ break;
+ case 11:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternGranite );
+ m_pDisplayedObject->setNoiseGenerator(
+ ( PMPattern::PMNoiseType ) m_pNoiseGenerator->currentItem( ) );
+ break;
+ case 12:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternJulia );
+ m_pDisplayedObject->setJuliaComplex( m_pJuliaComplex->vector( ) );
+ m_pDisplayedObject->setFractalMagnet( m_pFractalMagnet->isChecked( ) );
+ m_pDisplayedObject->setFractalMagnetType( m_pFractalMagnetType->currentItem( ) + 1 );
+ m_pDisplayedObject->setMaxIterations( m_pMaxIterationsEdit->value( ) );
+ m_pDisplayedObject->setFractalExponent( m_pFractalExponent->value( ) );
+ m_pDisplayedObject->setFractalExtType( m_pFractalExtType->currentItem( ) );
+ m_pDisplayedObject->setFractalExtFactor( m_pFractalExtFactor->value( ) );
+ m_pDisplayedObject->setFractalIntType( m_pFractalIntType->currentItem( ) );
+ m_pDisplayedObject->setFractalIntFactor( m_pFractalIntFactor->value( ) );
+ break;
+ case 13:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternLeopard );
+ break;
+ case 14:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternMandel );
+ m_pDisplayedObject->setFractalMagnet( m_pFractalMagnet->isChecked( ) );
+ m_pDisplayedObject->setFractalMagnetType( m_pFractalMagnetType->currentItem( ) + 1 );
+ m_pDisplayedObject->setMaxIterations( m_pMaxIterationsEdit->value( ) );
+ m_pDisplayedObject->setFractalExponent( m_pFractalExponent->value( ) );
+ m_pDisplayedObject->setFractalExtType( m_pFractalExtType->currentItem( ) );
+ m_pDisplayedObject->setFractalExtFactor( m_pFractalExtFactor->value( ) );
+ m_pDisplayedObject->setFractalIntType( m_pFractalIntType->currentItem( ) );
+ m_pDisplayedObject->setFractalIntFactor( m_pFractalIntFactor->value( ) );
+ break;
+ case 15:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternMarble );
+ break;
+ case 16:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternOnion );
+ break;
+ case 17:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternPlanar );
+ break;
+ case 18:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternQuilted );
+ m_pDisplayedObject->setQuiltControl0( m_pQuiltControl0Edit->value( ) );
+ m_pDisplayedObject->setQuiltControl1( m_pQuiltControl1Edit->value( ) );
+ break;
+ case 19:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternRadial );
+ break;
+ case 20:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternRipples );
+ break;
+ case 21:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternSlope );
+ m_pDisplayedObject->setSlopeDirection( m_pSlopeDirection->vector( ) );
+ m_pDisplayedObject->setSlopeLoSlope( m_pSlopeLoSlope->value( ) );
+ m_pDisplayedObject->setSlopeHiSlope( m_pSlopeHiSlope->value( ) );
+ m_pDisplayedObject->setSlopeAltFlag( m_pSlopeAltFlag->isChecked( ) );
+ m_pDisplayedObject->setSlopeAltitude( m_pSlopeAltitude->vector( ) );
+ m_pDisplayedObject->setSlopeLoAlt( m_pSlopeLoAlt->value( ) );
+ m_pDisplayedObject->setSlopeHiAlt( m_pSlopeHiAlt->value( ) );
+ break;
+ case 22:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternSpherical );
+ break;
+ case 23:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternSpiral1 );
+ m_pDisplayedObject->setSpiralNumberArms( m_pSpiralNumberEdit->value( ) );
+ break;
+ case 24:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternSpiral2 );
+ m_pDisplayedObject->setSpiralNumberArms( m_pSpiralNumberEdit->value( ) );
+ break;
+ case 25:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternSpotted );
+ break;
+ case 26:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternWaves );
+ break;
+ case 27:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternWood );
+ break;
+ case 28:
+ m_pDisplayedObject->setPatternType( PMPattern::PatternWrinkles );
+ m_pDisplayedObject->setNoiseGenerator(
+ ( PMPattern::PMNoiseType ) m_pNoiseGenerator->currentItem( ) );
+ break;
+ }
+ m_pDisplayedObject->enableTurbulence( m_pEnableTurbulenceEdit->isChecked( ) );
+ m_pDisplayedObject->setValueVector( m_pValueVectorEdit->vector( ) );
+ m_pDisplayedObject->setOctaves( m_pOctavesEdit->value( ) );
+ m_pDisplayedObject->setOmega( m_pOmegaEdit->value( ) );
+ m_pDisplayedObject->setLambda( m_pLambdaEdit->value( ) );
+
+ if( m_pDisplayedObject->parent( ) &&
+ ( m_pDisplayedObject->parent( )->type( ) == "Normal" ) )
+ m_pDisplayedObject->setDepth( m_pDepthEdit->value( ) );
+ }
+}
+
+bool PMPatternEdit::isDataValid( )
+{
+ switch( m_pTypeCombo->currentItem( ) )
+ {
+ case 0: // Agate
+ if( !m_pAgateTurbulenceEdit->isDataValid( ) )
+ return false;
+ break;
+ case 6: // Crackle
+ if ( !m_pCrackleMetric->isDataValid( ) )
+ return false;
+ break;
+ case 10: // Gradient
+ if( !m_pGradientEdit->isDataValid( ) )
+ return false;
+ break;
+ case 12: // Julia
+ case 14: // Mandel
+ if ( !m_pMaxIterationsEdit->isDataValid( ) )
+ return false;
+ if ( !m_pFractalExponent->isDataValid( ) )
+ return false;
+ break;
+ case 18: // Quilt
+ if( !m_pQuiltControl0Edit->isDataValid( ) )
+ return false;
+ if( !m_pQuiltControl1Edit->isDataValid( ) )
+ return false;
+ break;
+ case 21: // Slope
+ if( !m_pSlopeLoSlope->isDataValid( ) )
+ return false;
+ if( !m_pSlopeHiSlope->isDataValid( ) )
+ return false;
+ break;
+ case 23: // Spiral1
+ case 24: // Spiral2
+ if( !m_pSpiralNumberEdit->isDataValid( ) )
+ return false;
+ break;
+ default:
+ break;
+ }
+ if( m_pEnableTurbulenceEdit->isChecked( ) ) {
+ if( !m_pValueVectorEdit->isDataValid( ) ) return false;
+ if( !m_pOctavesEdit->isDataValid( ) ) return false;
+ if( !m_pOmegaEdit->isDataValid( ) ) return false;
+ if( !m_pLambdaEdit->isDataValid( ) ) return false;
+ }
+ if( m_pDisplayedObject->parent( ) &&
+ m_pDisplayedObject->parent( )->type( ) == "Normal" &&
+ !m_pDepthEdit->isDataValid( ) )
+ return false;
+
+ return Base::isDataValid( );
+}
+
+void PMPatternEdit::slotComboChanged( int c )
+{
+ switch( c )
+ {
+ case 0: /* Agate */
+ m_pAgateTurbulenceEdit->show( );
+ m_pAgateTurbulenceLabel->show( );
+ m_pCrackleWidget->hide( );
+ m_pDensityWidget->hide( );
+ m_pGradientEdit->hide( );
+ m_pGradientLabel->hide( );
+ m_pJuliaComplexLabel->hide( );
+ m_pJuliaComplex->hide( );
+ m_pFractalWidget->hide( );
+ m_pQuiltControlsLabel->hide( );
+ m_pQuiltControl0Edit->hide( );
+ m_pQuiltControl1Edit->hide( );
+ m_pSlopeWidget->hide( );
+ m_pSpiralNumberEdit->hide( );
+ m_pSpiralNumberLabel->hide( );
+ m_pNoiseGeneratorLabel->hide( );
+ m_pNoiseGenerator->hide( );
+ break;
+ case 3: /* Bozo */
+ case 4: /* Bumps */
+ m_pAgateTurbulenceEdit->hide( );
+ m_pAgateTurbulenceLabel->hide( );
+ m_pCrackleWidget->hide( );
+ m_pDensityWidget->hide( );
+ m_pGradientEdit->hide( );
+ m_pGradientLabel->hide( );
+ m_pJuliaComplexLabel->hide( );
+ m_pJuliaComplex->hide( );
+ m_pFractalWidget->hide( );
+ m_pQuiltControlsLabel->hide( );
+ m_pQuiltControl0Edit->hide( );
+ m_pQuiltControl1Edit->hide( );
+ m_pSlopeWidget->hide( );
+ m_pSpiralNumberEdit->hide( );
+ m_pSpiralNumberLabel->hide( );
+ m_pNoiseGeneratorLabel->show( );
+ m_pNoiseGenerator->show( );
+ break;
+ case 6: /* Crackle */
+ m_pAgateTurbulenceEdit->hide( );
+ m_pAgateTurbulenceLabel->hide( );
+ m_pCrackleWidget->show( );
+ m_pDensityWidget->hide( );
+ m_pGradientEdit->hide( );
+ m_pGradientLabel->hide( );
+ m_pJuliaComplexLabel->hide( );
+ m_pJuliaComplex->hide( );
+ m_pFractalWidget->hide( );
+ m_pQuiltControlsLabel->hide( );
+ m_pQuiltControl0Edit->hide( );
+ m_pQuiltControl1Edit->hide( );
+ m_pSlopeWidget->hide( );
+ m_pSpiralNumberEdit->hide( );
+ m_pSpiralNumberLabel->hide( );
+ m_pNoiseGeneratorLabel->hide( );
+ m_pNoiseGenerator->hide( );
+ break;
+ case 8: /* Density File */
+ m_pAgateTurbulenceEdit->hide( );
+ m_pAgateTurbulenceLabel->hide( );
+ m_pCrackleWidget->hide( );
+ m_pDensityWidget->show( );
+ m_pGradientEdit->hide( );
+ m_pGradientLabel->hide( );
+ m_pJuliaComplexLabel->hide( );
+ m_pJuliaComplex->hide( );
+ m_pFractalWidget->hide( );
+ m_pQuiltControlsLabel->hide( );
+ m_pQuiltControl0Edit->hide( );
+ m_pQuiltControl1Edit->hide( );
+ m_pSlopeWidget->hide( );
+ m_pSpiralNumberEdit->hide( );
+ m_pSpiralNumberLabel->hide( );
+ m_pNoiseGeneratorLabel->hide( );
+ m_pNoiseGenerator->hide( );
+ break;
+ case 10: /* Gradient */
+ m_pAgateTurbulenceEdit->hide( );
+ m_pAgateTurbulenceLabel->hide( );
+ m_pCrackleWidget->hide( );
+ m_pDensityWidget->hide( );
+ m_pGradientEdit->show( );
+ m_pGradientLabel->show( );
+ m_pJuliaComplexLabel->hide( );
+ m_pJuliaComplex->hide( );
+ m_pFractalWidget->hide( );
+ m_pQuiltControlsLabel->hide( );
+ m_pQuiltControl0Edit->hide( );
+ m_pQuiltControl1Edit->hide( );
+ m_pSlopeWidget->hide( );
+ m_pSpiralNumberEdit->hide( );
+ m_pSpiralNumberLabel->hide( );
+ m_pNoiseGeneratorLabel->hide( );
+ m_pNoiseGenerator->hide( );
+ break;
+ case 11: /* Granite */
+ m_pAgateTurbulenceEdit->hide( );
+ m_pAgateTurbulenceLabel->hide( );
+ m_pCrackleWidget->hide( );
+ m_pDensityWidget->hide( );
+ m_pGradientEdit->hide( );
+ m_pGradientLabel->hide( );
+ m_pJuliaComplexLabel->hide( );
+ m_pJuliaComplex->hide( );
+ m_pFractalWidget->hide( );
+ m_pQuiltControlsLabel->hide( );
+ m_pQuiltControl0Edit->hide( );
+ m_pQuiltControl1Edit->hide( );
+ m_pSlopeWidget->hide( );
+ m_pSpiralNumberEdit->hide( );
+ m_pSpiralNumberLabel->hide( );
+ m_pNoiseGeneratorLabel->show( );
+ m_pNoiseGenerator->show( );
+ break;
+ case 12: /* Julia */
+ m_pAgateTurbulenceEdit->hide( );
+ m_pAgateTurbulenceLabel->hide( );
+ m_pCrackleWidget->hide( );
+ m_pDensityWidget->hide( );
+ m_pGradientEdit->hide( );
+ m_pGradientLabel->hide( );
+ m_pJuliaComplexLabel->show( );
+ m_pJuliaComplex->show( );
+ m_pFractalWidget->show( );
+ m_pQuiltControlsLabel->hide( );
+ m_pQuiltControl0Edit->hide( );
+ m_pQuiltControl1Edit->hide( );
+ m_pSlopeWidget->hide( );
+ m_pSpiralNumberEdit->hide( );
+ m_pSpiralNumberLabel->hide( );
+ m_pNoiseGeneratorLabel->hide( );
+ m_pNoiseGenerator->hide( );
+ break;
+ case 14: /* Mandel */
+ m_pAgateTurbulenceEdit->hide( );
+ m_pAgateTurbulenceLabel->hide( );
+ m_pCrackleWidget->hide( );
+ m_pDensityWidget->hide( );
+ m_pGradientEdit->hide( );
+ m_pGradientLabel->hide( );
+ m_pJuliaComplexLabel->hide( );
+ m_pJuliaComplex->hide( );
+ m_pFractalWidget->show( );
+ m_pQuiltControlsLabel->hide( );
+ m_pQuiltControl0Edit->hide( );
+ m_pQuiltControl1Edit->hide( );
+ m_pSlopeWidget->hide( );
+ m_pSpiralNumberEdit->hide( );
+ m_pSpiralNumberLabel->hide( );
+ m_pNoiseGeneratorLabel->hide( );
+ m_pNoiseGenerator->hide( );
+ break;
+ case 18: /* Quilted */
+ m_pAgateTurbulenceEdit->hide( );
+ m_pAgateTurbulenceLabel->hide( );
+ m_pCrackleWidget->hide( );
+ m_pDensityWidget->hide( );
+ m_pGradientEdit->hide( );
+ m_pGradientLabel->hide( );
+ m_pJuliaComplexLabel->hide( );
+ m_pJuliaComplex->hide( );
+ m_pFractalWidget->hide( );
+ m_pQuiltControlsLabel->show( );
+ m_pQuiltControl0Edit->show( );
+ m_pQuiltControl1Edit->show( );
+ m_pSlopeWidget->hide( );
+ m_pSpiralNumberEdit->hide( );
+ m_pSpiralNumberLabel->hide( );
+ m_pNoiseGeneratorLabel->hide( );
+ m_pNoiseGenerator->hide( );
+ break;
+ case 21: /* Slope */
+ m_pAgateTurbulenceEdit->hide( );
+ m_pAgateTurbulenceLabel->hide( );
+ m_pCrackleWidget->hide( );
+ m_pDensityWidget->hide( );
+ m_pGradientEdit->hide( );
+ m_pGradientLabel->hide( );
+ m_pJuliaComplexLabel->hide( );
+ m_pJuliaComplex->hide( );
+ m_pFractalWidget->hide( );
+ m_pQuiltControlsLabel->hide( );
+ m_pQuiltControl0Edit->hide( );
+ m_pQuiltControl1Edit->hide( );
+ m_pSlopeWidget->show( );
+ m_pSpiralNumberEdit->hide( );
+ m_pSpiralNumberLabel->hide( );
+ m_pNoiseGeneratorLabel->hide( );
+ m_pNoiseGenerator->hide( );
+ break;
+ case 23: /* Spiral1 */
+ case 24: /* Spiral2 */
+ m_pAgateTurbulenceEdit->hide( );
+ m_pAgateTurbulenceLabel->hide( );
+ m_pCrackleWidget->hide( );
+ m_pDensityWidget->hide( );
+ m_pGradientEdit->hide( );
+ m_pGradientLabel->hide( );
+ m_pJuliaComplexLabel->hide( );
+ m_pJuliaComplex->hide( );
+ m_pFractalWidget->hide( );
+ m_pQuiltControlsLabel->hide( );
+ m_pQuiltControl0Edit->hide( );
+ m_pQuiltControl1Edit->hide( );
+ m_pSlopeWidget->hide( );
+ m_pSpiralNumberEdit->show( );
+ m_pSpiralNumberLabel->show( );
+ m_pNoiseGeneratorLabel->hide( );
+ m_pNoiseGenerator->hide( );
+ break;
+ case 28: /* Wrinkles */
+ m_pAgateTurbulenceEdit->hide( );
+ m_pAgateTurbulenceLabel->hide( );
+ m_pCrackleWidget->hide( );
+ m_pDensityWidget->hide( );
+ m_pGradientEdit->hide( );
+ m_pGradientLabel->hide( );
+ m_pJuliaComplexLabel->hide( );
+ m_pJuliaComplex->hide( );
+ m_pFractalWidget->hide( );
+ m_pQuiltControlsLabel->hide( );
+ m_pQuiltControl0Edit->hide( );
+ m_pQuiltControl1Edit->hide( );
+ m_pSlopeWidget->hide( );
+ m_pSpiralNumberEdit->hide( );
+ m_pSpiralNumberLabel->hide( );
+ m_pNoiseGeneratorLabel->show( );
+ m_pNoiseGenerator->show( );
+ break;
+ default:
+ m_pAgateTurbulenceEdit->hide( );
+ m_pAgateTurbulenceLabel->hide( );
+ m_pCrackleWidget->hide( );
+ m_pDensityWidget->hide( );
+ m_pGradientEdit->hide( );
+ m_pGradientLabel->hide( );
+ m_pJuliaComplexLabel->hide( );
+ m_pJuliaComplex->hide( );
+ m_pFractalWidget->hide( );
+ m_pQuiltControlsLabel->hide( );
+ m_pQuiltControl0Edit->hide( );
+ m_pQuiltControl1Edit->hide( );
+ m_pSlopeWidget->hide( );
+ m_pSpiralNumberEdit->hide( );
+ m_pSpiralNumberLabel->hide( );
+ m_pNoiseGeneratorLabel->hide( );
+ m_pNoiseGenerator->hide( );
+ break;
+ }
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+void PMPatternEdit::slotDensityFileBrowseClicked( )
+{
+ QString str = KFileDialog::getOpenFileName( QString::null, QString::null );
+
+ if( !str.isEmpty() )
+ {
+ m_pDensityFile->setText( str );
+ emit dataChanged( );
+ }
+}
+
+void PMPatternEdit::slotFractalMagnetClicked( )
+{
+ if ( m_pFractalMagnet->isChecked( ) )
+ {
+ m_pFractalMagnetType->show( );
+ m_pFractalExponentLabel->hide( );
+ m_pFractalExponent->hide( );
+ }
+ else
+ {
+ m_pFractalMagnetType->hide( );
+ m_pFractalExponentLabel->show( );
+ m_pFractalExponent->show( );
+ }
+ m_pFractalWidget->adjustSize( );
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+void PMPatternEdit::slotSlopeAltFlagClicked( )
+{
+ if ( m_pSlopeAltFlag->isChecked( ) )
+ {
+ m_pSlopeAltitude->show( );
+ m_pSlopeLoAltLabel->show( );
+ m_pSlopeLoAlt->show( );
+ m_pSlopeHiAltLabel->show( );
+ m_pSlopeHiAlt->show( );
+ }
+ else
+ {
+ m_pSlopeAltitude->hide( );
+ m_pSlopeLoAltLabel->hide( );
+ m_pSlopeLoAlt->hide( );
+ m_pSlopeHiAltLabel->hide( );
+ m_pSlopeHiAlt->hide( );
+ }
+ m_pSlopeWidget->adjustSize( );
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+void PMPatternEdit::slotTurbulenceClicked( )
+{
+ if(m_pEnableTurbulenceEdit->isChecked( ) )
+ m_pTurbulenceWidget->show( );
+ else
+ m_pTurbulenceWidget->hide( );
+
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+#include "pmpatternedit.moc"
diff --git a/kpovmodeler/pmpatternedit.h b/kpovmodeler/pmpatternedit.h
new file mode 100644
index 00000000..9f36ccf4
--- /dev/null
+++ b/kpovmodeler/pmpatternedit.h
@@ -0,0 +1,164 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+ copyright : (C) 2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPATTERNEDIT_H
+#define PMPATTERNEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdialogeditbase.h"
+
+class PMPattern;
+class PMVectorEdit;
+class QComboBox;
+class PMFloatEdit;
+class PMIntEdit;
+class QLabel;
+class QCheckBox;
+class QWidget;
+class QLineEdit;
+class QPushButton;
+
+/**
+ * Dialog edit class for @ref PMPattern.
+ */
+class PMPatternEdit : public PMDialogEditBase
+{
+ Q_OBJECT
+ typedef PMDialogEditBase Base;
+public:
+ /**
+ * Creates a PMPatternEdit with parent and name
+ */
+ PMPatternEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+protected slots:
+ /**
+ * Slot called whenever a new pattern type is selected.
+ */
+ void slotComboChanged( int c );
+ /**
+ * Slot called when the browse button is pressed for selection of the
+ * density file
+ */
+ void slotDensityFileBrowseClicked( );
+ /**
+ * Slot called when fractal magnet clicked
+ */
+ void slotFractalMagnetClicked( );
+ /**
+ * Slot called when the slope altitude flag is clicked
+ */
+ void slotSlopeAltFlagClicked( );
+ /**
+ * Slot called when turbulence is activated/deactivated.
+ */
+ void slotTurbulenceClicked( );
+
+private:
+ /**
+ * Set's the combo box and enables/disables widgets.
+ */
+ void setPatternType( int i );
+ /**
+ * m_noDepth is false is the editor must show the depth field
+ */
+ bool m_noDepth;
+ PMPattern* m_pDisplayedObject;
+ QComboBox* m_pTypeCombo;
+
+ QLabel* m_pAgateTurbulenceLabel;
+ PMFloatEdit* m_pAgateTurbulenceEdit;
+
+ QWidget* m_pCrackleWidget;
+ PMVectorEdit* m_pCrackleForm;
+ PMIntEdit* m_pCrackleMetric;
+ PMFloatEdit* m_pCrackleOffset;
+ QCheckBox* m_pCrackleSolid;
+
+ QWidget* m_pDensityWidget;
+ QComboBox* m_pDensityInterpolate;
+ QLineEdit* m_pDensityFile;
+ QPushButton* m_pDensityFileBrowse;
+
+ QLabel* m_pGradientLabel;
+ PMVectorEdit* m_pGradientEdit;
+
+ QLabel* m_pJuliaComplexLabel;
+ PMVectorEdit* m_pJuliaComplex;
+ QWidget* m_pFractalWidget;
+ QCheckBox* m_pFractalMagnet;
+ QComboBox* m_pFractalMagnetType;
+ PMIntEdit* m_pMaxIterationsEdit;
+ QLabel* m_pFractalExponentLabel;
+ PMIntEdit* m_pFractalExponent;
+ QComboBox* m_pFractalExtType;
+ PMFloatEdit* m_pFractalExtFactor;
+ QComboBox* m_pFractalIntType;
+ PMFloatEdit* m_pFractalIntFactor;
+
+ QLabel* m_pQuiltControlsLabel;
+ PMFloatEdit* m_pQuiltControl0Edit;
+ PMFloatEdit* m_pQuiltControl1Edit;
+
+ QWidget* m_pSlopeWidget;
+ PMVectorEdit* m_pSlopeDirection;
+ PMFloatEdit* m_pSlopeLoSlope;
+ PMFloatEdit* m_pSlopeHiSlope;
+ QCheckBox* m_pSlopeAltFlag;
+ PMVectorEdit* m_pSlopeAltitude;
+ QLabel* m_pSlopeLoAltLabel;
+ PMFloatEdit* m_pSlopeLoAlt;
+ QLabel* m_pSlopeHiAltLabel;
+ PMFloatEdit* m_pSlopeHiAlt;
+
+ QLabel* m_pSpiralNumberLabel;
+ PMIntEdit* m_pSpiralNumberEdit;
+
+ QLabel* m_pNoiseGeneratorLabel;
+ QComboBox* m_pNoiseGenerator;
+
+ QCheckBox* m_pEnableTurbulenceEdit;
+ QWidget* m_pTurbulenceWidget;
+ PMVectorEdit* m_pValueVectorEdit;
+ PMIntEdit* m_pOctavesEdit;
+ PMFloatEdit* m_pOmegaEdit;
+ PMFloatEdit* m_pLambdaEdit;
+
+ QLabel* m_pDepthLabel;
+ PMFloatEdit* m_pDepthEdit;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmphotons.cpp b/kpovmodeler/pmphotons.cpp
new file mode 100644
index 00000000..8297e3be
--- /dev/null
+++ b/kpovmodeler/pmphotons.cpp
@@ -0,0 +1,240 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmphotons.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pmphotonsedit.h"
+
+#include <klocale.h>
+
+const double spacingMultiDefault = 1.0;
+
+PMDefinePropertyClass( PMPhotons, PMPhotonsProperty );
+
+PMMetaObject* PMPhotons::s_pMetaObject = 0;
+PMObject* createNewPhotons( PMPart* part )
+{
+ return new PMPhotons( part );
+}
+
+PMPhotons::PMPhotons( PMPart* part ) : Base( part )
+{
+ m_target = true;
+ m_spacingMulti = spacingMultiDefault;
+ m_refraction = false;
+ m_reflection = false;
+ m_collect = true;
+ m_passThrough = false;
+ m_areaLight = false;
+}
+
+PMPhotons::PMPhotons( const PMPhotons& p )
+ : Base( p )
+{
+ m_target = p.m_target;
+ m_spacingMulti = p.m_spacingMulti;
+ m_refraction = p.m_refraction;
+ m_reflection = p.m_reflection;
+ m_collect = p.m_collect;
+ m_passThrough = p.m_passThrough;
+ m_areaLight = p.m_areaLight;
+}
+
+PMPhotons::~PMPhotons( )
+{
+}
+
+PMMetaObject* PMPhotons::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Photons", Base::metaObject( ),
+ createNewPhotons );
+
+ s_pMetaObject->addProperty( new PMPhotonsProperty( "target",
+ &PMPhotons::setTarget, &PMPhotons::target ) );
+ s_pMetaObject->addProperty( new PMPhotonsProperty( "spacingMulti",
+ &PMPhotons::setSpacingMulti, &PMPhotons::spacingMulti ) );
+ s_pMetaObject->addProperty( new PMPhotonsProperty( "refraction",
+ &PMPhotons::setRefraction, &PMPhotons::refraction ) );
+ s_pMetaObject->addProperty( new PMPhotonsProperty( "reflection",
+ &PMPhotons::setReflection, &PMPhotons::reflection ) );
+ s_pMetaObject->addProperty( new PMPhotonsProperty( "collect",
+ &PMPhotons::setCollect, &PMPhotons::collect ) );
+ s_pMetaObject->addProperty( new PMPhotonsProperty( "passThrough",
+ &PMPhotons::setPassThrough, &PMPhotons::passThrough ) );
+ s_pMetaObject->addProperty( new PMPhotonsProperty( "areaLight",
+ &PMPhotons::setAreaLight, &PMPhotons::areaLight ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMPhotons::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMPhotons::description( ) const
+{
+ return i18n( "photons" );
+}
+
+void PMPhotons::serialize( QDomElement& e, QDomDocument& ) const
+{
+ e.setAttribute( "target", m_target );
+ e.setAttribute( "spacing_multi", m_spacingMulti );
+ e.setAttribute( "refraction", m_refraction );
+ e.setAttribute( "reflection", m_reflection );
+ e.setAttribute( "collect", m_collect );
+ e.setAttribute( "pass_through", m_passThrough );
+ e.setAttribute( "area_light", m_areaLight );
+}
+
+void PMPhotons::readAttributes( const PMXMLHelper& h )
+{
+ m_target = h.boolAttribute( "target", true );
+ m_spacingMulti = h.doubleAttribute( "spacing_multi", spacingMultiDefault );
+ m_refraction = h.boolAttribute( "refraction", false );
+ m_reflection = h.boolAttribute( "reflection", false );
+ m_collect = h.boolAttribute( "collect", true );
+ m_passThrough = h.boolAttribute( "pass_through", false );
+ m_areaLight = h.boolAttribute( "area_light", false );
+}
+
+void PMPhotons::setTarget( bool t )
+{
+ if( t != m_target )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMTargetID, m_target );
+ m_target = t;
+ }
+}
+
+void PMPhotons::setSpacingMulti( double sm )
+{
+ if ( sm != m_spacingMulti )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSpacingMultiID, m_spacingMulti );
+ m_spacingMulti = sm;
+ }
+}
+
+void PMPhotons::setRefraction( bool r )
+{
+ if ( r != m_refraction )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMRefractionID, m_refraction );
+ m_refraction = r;
+ }
+}
+
+void PMPhotons::setReflection( bool r )
+{
+ if ( r != m_reflection )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMReflectionID, m_reflection);
+ m_reflection = r;
+ }
+}
+
+void PMPhotons::setCollect( bool c )
+{
+ if ( c != m_collect )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMCollectID, m_collect );
+ m_collect = c;
+ }
+}
+
+void PMPhotons::setPassThrough( bool pt )
+{
+ if ( pt != m_passThrough )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMPassThroughID, m_passThrough );
+ m_passThrough = pt;
+ }
+}
+
+void PMPhotons::setAreaLight( bool al )
+{
+ if ( al != m_areaLight )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAreaLightID, m_areaLight );
+ m_areaLight = al;
+ }
+}
+
+PMDialogEditBase* PMPhotons::editWidget( QWidget* parent ) const
+{
+ return new PMPhotonsEdit( parent );
+}
+
+void PMPhotons::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMTargetID:
+ setTarget( data->boolData( ) );
+ break;
+ case PMSpacingMultiID:
+ setSpacingMulti( data->doubleData( ) );
+ break;
+ case PMRefractionID:
+ setRefraction( data->boolData( ) );
+ break;
+ case PMReflectionID:
+ setReflection( data->boolData( ) );
+ break;
+ case PMCollectID:
+ setCollect( data->boolData( ) );
+ break;
+ case PMPassThroughID:
+ setPassThrough( data->boolData( ) );
+ break;
+ case PMAreaLightID:
+ setAreaLight( data->boolData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMRadiosity::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmphotons.h b/kpovmodeler/pmphotons.h
new file mode 100644
index 00000000..14ce9f6f
--- /dev/null
+++ b/kpovmodeler/pmphotons.h
@@ -0,0 +1,160 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPHOTONS_H
+#define PMPHOTONS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmobject.h"
+
+/**
+ * Class for Photons settings.
+ */
+
+class PMPhotons : public PMObject
+{
+ typedef PMObject Base;
+public:
+ /**
+ * Creates a PMPhotons
+ */
+ PMPhotons( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMPhotons( const PMPhotons& p );
+ /**
+ * deletes the PMPhotons
+ */
+ virtual ~PMPhotons( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMPhotons( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMPhotonsEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmphotons" ); }
+
+ /**
+ * Returns the target flag
+ */
+ bool target( ) const { return m_target; }
+ /**
+ * Sets the target flag
+ */
+ void setTarget( bool t );
+
+ /**
+ * Returns the spacing multiplier
+ */
+ double spacingMulti( ) const { return m_spacingMulti; }
+ /**
+ * Sets the spacing multipler
+ */
+ void setSpacingMulti( double sm );
+
+ /**
+ * Returns the refraction flag
+ */
+ bool refraction( ) const { return m_refraction; }
+ /**
+ * Sets the refraction flag
+ */
+ void setRefraction( bool r );
+
+ /**
+ * Returns the reflection flag
+ */
+ bool reflection( ) const { return m_reflection; }
+ /**
+ * Sets the reflection flag
+ */
+ void setReflection( bool r );
+
+ /**
+ * Returns the collect flag
+ */
+ bool collect( ) const { return m_collect; }
+ /**
+ * Sets the collect flag
+ */
+ void setCollect( bool c );
+
+ /**
+ * Returns the pass through flag
+ */
+ bool passThrough( ) const { return m_passThrough; }
+ /**
+ * Sets the pass through flag
+ */
+ void setPassThrough( bool pt );
+
+ /**
+ * Returns the area light flag
+ */
+ bool areaLight( ) const { return m_areaLight; }
+ /**
+ * Sets the area light flag
+ */
+ void setAreaLight( bool al );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMPhotonsMementoID{ PMTargetID, PMSpacingMultiID, PMRefractionID,
+ PMReflectionID, PMCollectID, PMPassThroughID,
+ PMAreaLightID };
+
+ bool m_target;
+ double m_spacingMulti;
+ bool m_refraction;
+ bool m_reflection;
+ bool m_collect;
+ bool m_passThrough;
+ bool m_areaLight;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmphotonsedit.cpp b/kpovmodeler/pmphotonsedit.cpp
new file mode 100644
index 00000000..21f5d106
--- /dev/null
+++ b/kpovmodeler/pmphotonsedit.cpp
@@ -0,0 +1,160 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmphotonsedit.h"
+#include "pmphotons.h"
+#include "pmlineedits.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <klocale.h>
+#include <kdialog.h>
+#include <kmessagebox.h>
+
+
+PMPhotonsEdit::PMPhotonsEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMPhotonsEdit::createTopWidgets( )
+{
+ QGridLayout* gl;
+ QHBoxLayout* hl;
+
+ Base::createTopWidgets( );
+
+ m_pLayoutWidget = new QWidget( this );
+ m_pTarget = new QCheckBox( i18n( "Target" ), m_pLayoutWidget );
+ m_pSpacingMultiLabel = new QLabel( i18n( "Spacing multiplier:" ), m_pLayoutWidget );
+ m_pSpacingMulti = new PMFloatEdit( m_pLayoutWidget );
+ m_pSpacingMulti->setValidation( true, 0, false, 0 );
+
+ m_pRefraction = new QCheckBox( i18n( "Refraction" ), this );
+ m_pReflection = new QCheckBox( i18n( "Reflection" ), this );
+ m_pCollect = new QCheckBox( i18n( "Collect" ), this );
+ m_pPassThrough = new QCheckBox( i18n( "Pass through" ), this );
+ m_pAreaLight = new QCheckBox( i18n( "Area light" ), this );
+
+ hl = new QHBoxLayout( m_pLayoutWidget, 0, KDialog::spacingHint( ) );
+ gl = new QGridLayout( hl, 2, 2 );
+ gl->addMultiCellWidget( m_pTarget, 0, 0, 0, 1 );
+ gl->addWidget( m_pSpacingMultiLabel, 1, 0 );
+ gl->addWidget( m_pSpacingMulti, 1, 1 );
+ hl->addStretch( 1 );
+ topLayout( )->addWidget( m_pLayoutWidget );
+
+ gl = new QGridLayout( topLayout( ), 2, 2 );
+ gl->addWidget( m_pRefraction, 0, 0 );
+ gl->addWidget( m_pReflection, 0, 1 );
+ gl->addWidget( m_pCollect, 1, 0 );
+ gl->addWidget( m_pPassThrough, 1, 1 );
+ gl->addWidget( m_pAreaLight, 1, 0 );
+
+ connect( m_pTarget, SIGNAL( clicked( ) ), SLOT( slotTargetClicked( ) ) );
+ connect( m_pSpacingMulti, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pRefraction, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pReflection, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pCollect, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pPassThrough, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pAreaLight, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMPhotonsEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Photons" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMPhotons* ) o;
+
+ if ( o->parent( ) && ( o->parent( )->isA( "Light" ) ) )
+ {
+ m_pLayoutWidget->hide( );
+ m_pCollect->hide( );
+ m_pPassThrough->hide( );
+ m_pAreaLight->show( );
+ }
+ else
+ {
+ m_pLayoutWidget->show( );
+ m_pCollect->show( );
+ m_pPassThrough->show( );
+ m_pAreaLight->hide( );
+ }
+
+ m_pTarget->setChecked( m_pDisplayedObject->target( ) );
+ m_pTarget->setEnabled( !readOnly );
+ m_pSpacingMulti->setValue( m_pDisplayedObject->spacingMulti( ) );
+ m_pSpacingMulti->setReadOnly( readOnly );
+ m_pRefraction->setChecked( m_pDisplayedObject->refraction( ) );
+ m_pRefraction->setEnabled( !readOnly );
+ m_pReflection->setChecked( m_pDisplayedObject->reflection( ) );
+ m_pReflection->setEnabled( !readOnly );
+ m_pCollect->setChecked( m_pDisplayedObject->collect( ) );
+ m_pCollect->setEnabled( !readOnly );
+ m_pPassThrough->setChecked( m_pDisplayedObject->passThrough( ) );
+ m_pPassThrough->setEnabled( !readOnly );
+ m_pAreaLight->setChecked( m_pDisplayedObject->areaLight( ) );
+ m_pAreaLight->setEnabled( !readOnly );
+
+ slotTargetClicked( );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMPhotonsEdit: Can't display object\n";
+}
+
+void PMPhotonsEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setTarget( m_pTarget->isChecked( ) );
+ m_pDisplayedObject->setSpacingMulti( m_pSpacingMulti->value( ) );
+ m_pDisplayedObject->setRefraction( m_pRefraction->isChecked( ) );
+ m_pDisplayedObject->setReflection( m_pReflection->isChecked( ) );
+ m_pDisplayedObject->setCollect( m_pCollect->isChecked( ) );
+ m_pDisplayedObject->setPassThrough( m_pPassThrough->isChecked( ) );
+ m_pDisplayedObject->setAreaLight( m_pAreaLight->isChecked( ) );
+ }
+}
+
+bool PMPhotonsEdit::isDataValid( )
+{
+ if( !m_pSpacingMulti->isDataValid( ) ) return false;
+
+ return Base::isDataValid( );
+}
+
+void PMPhotonsEdit::slotTargetClicked( )
+{
+ if ( m_pTarget->isChecked( ) && m_pTarget->isEnabled( ) )
+ {
+ m_pSpacingMulti->setEnabled( true );
+ }
+ else
+ {
+ m_pSpacingMulti->setEnabled( false );
+ }
+ emit dataChanged( );
+}
+
+#include "pmphotonsedit.moc"
diff --git a/kpovmodeler/pmphotonsedit.h b/kpovmodeler/pmphotonsedit.h
new file mode 100644
index 00000000..d40e84cf
--- /dev/null
+++ b/kpovmodeler/pmphotonsedit.h
@@ -0,0 +1,79 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPHOTONSEDIT_H
+#define PMPHOTONSEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdialogeditbase.h"
+
+class PMPhotons;
+class PMFloatEdit;
+class QCheckBox;
+class QLabel;
+
+/**
+ * Dialog edit class for @ref PMPhotons.
+ */
+class PMPhotonsEdit : public PMDialogEditBase
+{
+ Q_OBJECT
+ typedef PMDialogEditBase Base;
+public:
+ /**
+ * Creates a PMPhotonsEdit with parent and name
+ */
+ PMPhotonsEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+protected slots:
+ /**
+ * Slot Called whenever target is clicked
+ */
+ void slotTargetClicked( );
+
+private:
+ PMPhotons* m_pDisplayedObject;
+
+ QWidget* m_pLayoutWidget;
+ QCheckBox* m_pTarget;
+ PMFloatEdit* m_pSpacingMulti;
+ QLabel* m_pSpacingMultiLabel;
+ QCheckBox* m_pRefraction;
+ QCheckBox* m_pReflection;
+ QCheckBox* m_pCollect;
+ QCheckBox* m_pPassThrough;
+ QCheckBox* m_pAreaLight;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmpigment.cpp b/kpovmodeler/pmpigment.cpp
new file mode 100644
index 00000000..39e5a4e3
--- /dev/null
+++ b/kpovmodeler/pmpigment.cpp
@@ -0,0 +1,124 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmpigment.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pmpigmentedit.h"
+
+#include <klocale.h>
+
+PMDefinePropertyClass( PMPigment, PMPigmentProperty );
+
+PMMetaObject* PMPigment::s_pMetaObject = 0;
+PMObject* createNewPigment( PMPart* part )
+{
+ return new PMPigment( part );
+}
+
+PMPigment::PMPigment( PMPart* part ) : Base( part )
+{
+ m_uvMapping = false;
+}
+
+PMPigment::PMPigment( const PMPigment& p ) : Base( p )
+{
+ m_uvMapping = p.m_uvMapping;
+}
+
+PMPigment::~PMPigment( )
+{
+}
+
+PMMetaObject* PMPigment::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Pigment", Base::metaObject( ),
+ createNewPigment );
+ s_pMetaObject->addProperty(
+ new PMPigmentProperty( "uvMapping", &PMPigment::setUVMapping, &PMPigment::uvMapping ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMPigment::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMPigment::description( ) const
+{
+ return i18n( "pigment" );
+}
+
+PMDialogEditBase* PMPigment::editWidget( QWidget* parent ) const
+{
+ return new PMPigmentEdit( parent );
+}
+
+void PMPigment::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "uv_mapping", m_uvMapping );
+ Base::serialize( e, doc );
+}
+
+void PMPigment::readAttributes( const PMXMLHelper& h )
+{
+ m_uvMapping = h.boolAttribute( "uv_mapping", false );
+ Base::readAttributes( h );
+}
+
+void PMPigment::setUVMapping( bool m )
+{
+ if( m != m_uvMapping )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMUVMappingID, m_uvMapping );
+ m_uvMapping = m;
+ }
+}
+
+void PMPigment::restoreMemento( PMMemento *s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMUVMappingID:
+ setUVMapping( data->boolData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMPigment::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmpigment.h b/kpovmodeler/pmpigment.h
new file mode 100644
index 00000000..3f465e0e
--- /dev/null
+++ b/kpovmodeler/pmpigment.h
@@ -0,0 +1,95 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPIGMENT_H
+#define PMPIGMENT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebase.h"
+
+/**
+ * Class for povray pigments
+ */
+class PMPigment : public PMTextureBase
+{
+ typedef PMTextureBase Base;
+public:
+ /**
+ * Creates an PMPigment
+ */
+ PMPigment( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMPigment( const PMPigment& );
+ /**
+ * Deletes the object
+ */
+ virtual ~PMPigment( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMPigment( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMPigmentEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmpigment" ); }
+
+ /**
+ * Returns the uv mapping flag
+ */
+ bool uvMapping() const { return m_uvMapping; }
+ /**
+ * Sets the uv maaping flag
+ */
+ void setUVMapping( bool m );
+
+ /** */
+ virtual void restoreMemento( PMMemento *s );
+
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMPigmentMementoID { PMUVMappingID };
+
+ bool m_uvMapping;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmpigmentedit.cpp b/kpovmodeler/pmpigmentedit.cpp
new file mode 100644
index 00000000..939f18cf
--- /dev/null
+++ b/kpovmodeler/pmpigmentedit.cpp
@@ -0,0 +1,68 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmpigmentedit.h"
+#include "pmpigment.h"
+#include "pmlinkedit.h"
+
+#include <qlayout.h>
+#include <qcheckbox.h>
+#include <klocale.h>
+
+
+PMPigmentEdit::PMPigmentEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMPigmentEdit::createTopWidgets()
+{
+ Base::createTopWidgets();
+ m_pUVMapping = new QCheckBox( i18n( "UV mapping" ), this );
+ topLayout( )->addWidget( m_pUVMapping );
+
+ connect( m_pUVMapping, SIGNAL( clicked() ), SIGNAL( dataChanged() ) );
+}
+
+void PMPigmentEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Pigment" ) )
+ {
+ m_pDisplayedObject = ( PMPigment* ) o;
+ bool readOnly = m_pDisplayedObject->isReadOnly( );
+
+ m_pUVMapping->setChecked( m_pDisplayedObject->uvMapping() );
+ m_pUVMapping->setEnabled( !readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMPigmentEdit: Can't display object\n";
+}
+
+void PMPigmentEdit::saveContents()
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents();
+ m_pDisplayedObject->setUVMapping( m_pUVMapping->isChecked() );
+ }
+}
+
+#include "pmpigmentedit.moc"
diff --git a/kpovmodeler/pmpigmentedit.h b/kpovmodeler/pmpigmentedit.h
new file mode 100644
index 00000000..7a3960a2
--- /dev/null
+++ b/kpovmodeler/pmpigmentedit.h
@@ -0,0 +1,60 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPIGMENTEDIT_H
+#define PMPIGMENTEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebaseedit.h"
+
+class PMPigment;
+class QCheckBox;
+
+/**
+ * Dialog edit class for @ref PMPigment
+ */
+class PMPigmentEdit : public PMTextureBaseEdit
+{
+ Q_OBJECT
+ typedef PMTextureBaseEdit Base;
+public:
+ /**
+ * Creates a PMPigmentEdit with parent and name
+ */
+ PMPigmentEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMPigment* m_pDisplayedObject;
+ QCheckBox* m_pUVMapping;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmplane.cpp b/kpovmodeler/pmplane.cpp
new file mode 100644
index 00000000..171df53f
--- /dev/null
+++ b/kpovmodeler/pmplane.cpp
@@ -0,0 +1,276 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Leonardo Skorianez
+ email : lsk@if.ufrj.br
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmplane.h"
+
+#include "pmxmlhelper.h"
+#include "pmboxedit.h"
+#include "pmmemento.h"
+#include "pmdistancecontrolpoint.h"
+#include "pmplanenormalcontrolpoint.h"
+#include "pmdefaults.h"
+
+#include <klocale.h>
+
+#include "pmplaneedit.h"
+
+const double defaultPlaneDistance = 0;
+const PMVector defaultPlaneNormal = PMVector ( 0.0, 1.0, 0.0 );
+
+/** default plane structure */
+PMViewStructure* PMPlane::s_pDefaultViewStructure = 0;
+double PMPlane::s_planeSize = c_defaultPlaneSize;
+int PMPlane::s_parameterKey = 0;
+
+PMDefinePropertyClass( PMPlane, PMPlaneProperty );
+
+PMMetaObject* PMPlane::s_pMetaObject = 0;
+PMObject* createNewPlane( PMPart* part )
+{
+ return new PMPlane( part );
+}
+
+PMPlane::PMPlane( PMPart* part )
+ : Base( part )
+{
+ m_normal = defaultPlaneNormal;
+ m_distance = defaultPlaneDistance;
+}
+
+PMPlane::PMPlane( const PMPlane& p )
+ : Base( p )
+{
+ m_normal = p.m_normal;
+ m_distance = p.m_distance;
+}
+
+PMPlane::~PMPlane( )
+{
+}
+
+QString PMPlane::description( ) const
+{
+ return i18n( "plane" );
+}
+
+void PMPlane::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "normal", m_normal.serializeXML( ) );
+ e.setAttribute( "distance", m_distance );
+ Base::serialize( e, doc );
+}
+
+void PMPlane::readAttributes( const PMXMLHelper& h )
+{
+ m_normal = h.vectorAttribute( "normal", defaultPlaneNormal );
+ m_distance = h.doubleAttribute( "distance", defaultPlaneDistance );
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMPlane::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Plane", Base::metaObject( ),
+ createNewPlane );
+ s_pMetaObject->addProperty(
+ new PMPlaneProperty( "normal", &PMPlane::setNormal, &PMPlane::normal ) );
+ s_pMetaObject->addProperty(
+ new PMPlaneProperty( "distance", &PMPlane::setDistance, &PMPlane::distance ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMPlane::setNormal( const PMVector& p )
+{
+
+ if( p != m_normal )
+ {
+ if( m_pMemento )
+ {
+ m_pMemento->addData( s_pMetaObject, PMNormalID, m_normal );
+ }
+ m_normal = p;
+ m_normal.resize( 3 );
+
+ setViewStructureChanged( );
+ }
+}
+
+void PMPlane::setDistance( double distance )
+{
+ if( m_distance != distance )
+ {
+ if( m_pMemento )
+ {
+ m_pMemento->addData( s_pMetaObject, PMDistanceID, m_distance );
+ }
+ m_distance = distance;
+
+ setViewStructureChanged( );
+ }
+}
+
+PMDialogEditBase* PMPlane::editWidget( QWidget* parent ) const
+{
+ return new PMPlaneEdit( parent );
+}
+
+void PMPlane::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMNormalID:
+ setNormal( data->vectorData( ) );
+ break;
+ case PMDistanceID:
+ setDistance( data->doubleData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMPlane::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
+bool PMPlane::isDefault( )
+{
+ if( ( m_normal == defaultPlaneNormal ) && ( m_distance == defaultPlaneDistance ) )
+ return true;
+ return false;
+}
+
+void PMPlane::createViewStructure( )
+{
+ if( !m_pViewStructure )
+ {
+ m_pViewStructure = new PMViewStructure( defaultViewStructure ( ) );
+ m_pViewStructure->points( ).detach( );
+ }
+ createPoints( m_pViewStructure->points( ), m_normal, m_distance );
+}
+
+PMViewStructure* PMPlane::defaultViewStructure( ) const
+{
+ if( !s_pDefaultViewStructure )
+ {
+ s_pDefaultViewStructure = new PMViewStructure( 4, 4 );
+ PMLineArray& lines = s_pDefaultViewStructure->lines( );
+
+ createPoints( s_pDefaultViewStructure->points( ), defaultPlaneNormal,defaultPlaneDistance );
+
+ lines[0] = PMLine( 0 , 1 );
+ lines[1] = PMLine( 1 , 2 );
+ lines[2] = PMLine( 2 , 3 );
+ lines[3] = PMLine( 3 , 0 );
+ }
+ return s_pDefaultViewStructure;
+}
+
+void PMPlane::createPoints( PMPointArray& points, const PMVector& normal, double distance )
+{
+ PMVector dir = normal;
+ if( approxZero( dir.abs( ) ) )
+ dir = PMVector( 0.0, 1.0, 0.0 );
+
+ PMVector base = dir * distance;
+ PMMatrix rotation = PMMatrix::rotation( dir, M_PI / 4.0 );
+
+ PMVector endPoint1 = rotation * dir.orthogonal( ) * s_planeSize * sqrt( 2.0 ) * 0.5;
+ PMVector endPoint2 = rotation * ( rotation * endPoint1 );
+
+ points[0] = base + endPoint1;
+ points[1] = base + endPoint2;
+ points[2] = base - endPoint1;
+ points[3] = base - endPoint2;
+}
+
+void PMPlane::controlPoints( PMControlPointList & list )
+{
+ PMDistanceControlPoint* d;
+ d = new PMDistanceControlPoint( PMVector( 0, 0, 0 ), m_normal, m_distance,
+ PMDistanceID, i18n( "Distance" ) );
+ list.append( new PMPlaneNormalControlPoint( d, m_normal, PMNormalID,
+ i18n( "Normal" ) ) );
+ list.append( d );
+}
+
+
+void PMPlane::controlPointsChanged( PMControlPointList & list )
+{
+ PMControlPoint* p;
+
+ for( p = list.first( ); p; p = list.next( ) )
+ {
+ if( p->changed( ) )
+ {
+ switch( p->id( ) )
+ {
+ case PMNormalID:
+ setNormal( ( ( PMPlaneNormalControlPoint *) p)->normal( ) );
+ setDistance( ( ( PMPlaneNormalControlPoint *) p)->distance( ) );
+ break;
+ case PMDistanceID:
+ setDistance( ( ( PMDistanceControlPoint *) p )->distance( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMPlane::controlPointsChanged\n";
+ break;
+ }
+ }
+ }
+}
+
+void PMPlane::setPlaneSize( double size )
+{
+ if( size >= 0.1 )
+ {
+ s_planeSize = size;
+ if( s_pDefaultViewStructure )
+ {
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ }
+ }
+ else
+ kdDebug( PMArea ) << "PMPlane::setPlaneSize: Size must be greater than 0.1\n";
+ s_parameterKey++;
+}
+
+void PMPlane::cleanUp( ) const
+{
+ if( s_pDefaultViewStructure )
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
diff --git a/kpovmodeler/pmplane.h b/kpovmodeler/pmplane.h
new file mode 100644
index 00000000..34829ade
--- /dev/null
+++ b/kpovmodeler/pmplane.h
@@ -0,0 +1,148 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Leonardo Skorianez
+ email : lsk@if.ufrj.br
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPLANE_H
+#define PMPLANE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobject.h"
+#include "pmvector.h"
+#include "pmviewstructure.h"
+
+/**
+ * Class for povray plane
+ */
+
+class PMPlane : public PMSolidObject
+{
+ typedef PMSolidObject Base;
+public:
+ /**
+ * Creates a plane
+ */
+ PMPlane( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMPlane( const PMPlane& p );
+
+ /**
+ * Deletes the plane
+ */
+ virtual ~PMPlane( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMPlane( *this ); }
+
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMPlaneEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmplane" ); }
+
+ /**
+ * Return the normal
+ */
+ PMVector normal( ) const { return m_normal; }
+ /**
+ * Sets normal
+ */
+ void setNormal( const PMVector& p );
+ /**
+ * Return the distance
+ */
+ double distance( ) const { return m_distance; }
+ /**
+ * Sets the distance
+ */
+ void setDistance( double distance );
+
+ /**
+ * Sets the plane size (view structure)
+ */
+ static void setPlaneSize( double size );
+ /**
+ * Returns the plane size (view structure)
+ */
+ static double planeSize( ) { return s_planeSize; };
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /** */
+ virtual void controlPoints( PMControlPointList& list );
+ /** */
+ virtual void controlPointsChanged( PMControlPointList& list );
+ /** */
+ virtual void cleanUp( ) const;
+
+protected:
+ /** */
+ virtual bool isDefault( );
+ /** */
+ virtual void createViewStructure( );
+ /** */
+ virtual PMViewStructure* defaultViewStructure( ) const;
+ /** */
+ virtual int viewStructureParameterKey( ) const { return s_parameterKey; }
+
+private:
+ /**
+ * Creates the points for the view structure
+ */
+ static void createPoints( PMPointArray& points, const PMVector& normal , double distance );
+
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMPlaneMementoID { PMNormalID, PMDistanceID };
+ /**
+ * normal of plane
+ */
+ PMVector m_normal;
+ /**
+ * distance from origin
+ */
+ double m_distance;
+ /**
+ * The default view structure. It can be shared between planes
+ */
+ static PMViewStructure* s_pDefaultViewStructure;
+ static double s_planeSize;
+ static int s_parameterKey;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmplaneedit.cpp b/kpovmodeler/pmplaneedit.cpp
new file mode 100644
index 00000000..62e7e08e
--- /dev/null
+++ b/kpovmodeler/pmplaneedit.cpp
@@ -0,0 +1,124 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Leonardo Skorianez
+ email : lsk@if.ufrj.br
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmplaneedit.h"
+#include "pmplane.h"
+#include "pmvectoredit.h"
+#include "pmlineedits.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qcheckbox.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+PMPlaneEdit::PMPlaneEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMPlaneEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* layout;
+
+ m_pNormal = new PMVectorEdit( "x", "y", "z", this );
+ m_pDistance = new PMFloatEdit( this );
+
+ layout = new QHBoxLayout( topLayout( ) );
+ layout->addWidget( new QLabel( i18n( "Normal:" ), this ) );
+ layout->addWidget( m_pNormal );
+
+ layout = new QHBoxLayout( topLayout( ) );
+ layout->addWidget( new QLabel( i18n( "Distance:" ), this ) );
+ layout->addWidget( m_pDistance );
+ layout->addStretch( 1 );
+
+ QPushButton* nb = new QPushButton( i18n( "Normalize" ), this );
+ layout = new QHBoxLayout( topLayout( ) );
+ layout->addWidget( nb );
+ layout->addStretch( 1 );
+
+ connect( m_pNormal, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pDistance, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( nb, SIGNAL( clicked( ) ), SLOT( slotNormalize( ) ) );
+}
+
+void PMPlaneEdit::slotNormalize( )
+{
+ PMVector normal = m_pNormal->vector( );
+ double distance = m_pDistance->value( );
+ double l = normal.abs( );
+ if( !approxZero( l ) )
+ {
+ m_pNormal->setVector( normal / l );
+ m_pDistance->setValue( distance * l );
+ }
+}
+
+void PMPlaneEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Plane" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMPlane* ) o;
+
+ m_pNormal->setVector( m_pDisplayedObject->normal( ) );
+ m_pDistance->setValue( m_pDisplayedObject->distance( ) );
+
+ m_pNormal->setReadOnly( readOnly );
+ m_pDistance->setReadOnly( readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMPlaneEdit: Can't display object\n";
+}
+
+void PMPlaneEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setNormal( m_pNormal->vector( ) );
+ m_pDisplayedObject->setDistance( m_pDistance->value( ) );
+ }
+}
+
+bool PMPlaneEdit::isDataValid( )
+{
+ if( m_pNormal->isDataValid( ) )
+ {
+ if( approxZero( m_pNormal->vector( ).abs( ) ) )
+ {
+ KMessageBox::error( this, i18n( "The normal vector may not be a "
+ "null vector." ),
+ i18n( "Error" ) );
+ return false;
+
+ }
+ if( m_pDistance->isDataValid( ) )
+ return Base::isDataValid( );
+ }
+ return false;
+}
+
+#include "pmplaneedit.moc"
diff --git a/kpovmodeler/pmplaneedit.h b/kpovmodeler/pmplaneedit.h
new file mode 100644
index 00000000..97a07467
--- /dev/null
+++ b/kpovmodeler/pmplaneedit.h
@@ -0,0 +1,66 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Leonardo Skorinaez
+ email : lsk@if.ufrj.br
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPLANEEDIT_H
+#define PMPLANEEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobjectedit.h"
+
+class PMVectorEdit;
+class PMFloatEdit;
+class PMPlane;
+class QCheckBox;
+
+class PMPlaneEdit : public PMSolidObjectEdit
+{
+ Q_OBJECT
+ typedef PMSolidObjectEdit Base;
+public:
+ /**
+ * Creates a PMPlaneEdit with parent and name
+ */
+ PMPlaneEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+protected slots:
+ /**
+ * Normalizes the vector
+ */
+ void slotNormalize( );
+
+private:
+ PMPlane* m_pDisplayedObject;
+ PMVectorEdit* m_pNormal;
+ PMFloatEdit* m_pDistance;
+};
+#endif
diff --git a/kpovmodeler/pmplanenormalcontrolpoint.cpp b/kpovmodeler/pmplanenormalcontrolpoint.cpp
new file mode 100644
index 00000000..f28c035e
--- /dev/null
+++ b/kpovmodeler/pmplanenormalcontrolpoint.cpp
@@ -0,0 +1,93 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmplanenormalcontrolpoint.h"
+#include "pmdistancecontrolpoint.h"
+#include "pmmath.h"
+#include <math.h>
+
+PMPlaneNormalControlPoint::PMPlaneNormalControlPoint( PMDistanceControlPoint* d,
+ const PMVector& normal, int id,
+ const QString& description )
+ : PMControlPoint( id, description )
+{
+ m_normal = normal;
+ m_pDistancePoint = d;
+}
+
+PMVector PMPlaneNormalControlPoint::position( ) const
+{
+ return m_normal * ( m_pDistancePoint->distance( ) + 1.0 );
+}
+
+PMVector PMPlaneNormalControlPoint::extraLineStart( ) const
+{
+ return m_normal * m_pDistancePoint->distance( );
+}
+
+PMVector PMPlaneNormalControlPoint::extraLineEnd( ) const
+{
+ return position( );
+}
+
+void PMPlaneNormalControlPoint::graphicalChangeStarted( )
+{
+ m_originalNormal = m_normal;
+ m_originalDistance = m_pDistancePoint->distance( );
+}
+
+void PMPlaneNormalControlPoint::graphicalChange( const PMVector& startPoint,
+ const PMVector& /*viewNormal*/,
+ const PMVector& endPoint )
+{
+ PMVector p = m_originalNormal * ( m_originalDistance + 1 )
+ + endPoint - startPoint;
+ double pabs = p.abs( );
+
+ if( !approxZero( pabs ) )
+ {
+ PMVector np = p / pabs;
+ double nd = m_originalNormal.abs( ) * m_originalDistance;
+ PMVector normal = p - np * fabs( nd );
+ double nl = normal.abs( );
+
+ if( !approxZero( nl ) )
+ {
+ if( ( m_originalDistance * ( pabs - fabs( nd ) ) ) < 0 )
+ nd = -nd;
+ nd /= nl;
+ m_pDistancePoint->setDistance( nd );
+ m_pDistancePoint->setDirection( normal );
+ m_normal = normal;
+ }
+ }
+}
+
+double PMPlaneNormalControlPoint::distance( ) const
+{
+ return m_pDistancePoint->distance( );
+}
+
+void PMPlaneNormalControlPoint::snapToGrid( )
+{
+ int i;
+ double d = moveGrid( );
+ if( !approxZero( d ) )
+ for( i = 0; i < 3; i++ )
+ m_normal[i] = rint( m_normal[i] / d ) * d;
+ setChanged( );
+}
diff --git a/kpovmodeler/pmplanenormalcontrolpoint.h b/kpovmodeler/pmplanenormalcontrolpoint.h
new file mode 100644
index 00000000..0faf10b8
--- /dev/null
+++ b/kpovmodeler/pmplanenormalcontrolpoint.h
@@ -0,0 +1,92 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMPLANENORMALCONTROLPOINT_H
+#define PMPLANENORMALCONTROLPOINT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmcontrolpoint.h"
+
+class PMDistanceControlPoint;
+
+/**
+ * Control points for the plane normal
+ */
+class PMPlaneNormalControlPoint : public PMControlPoint
+{
+public:
+ /**
+ * Creates a PMPlaneNormalControlPoint with id.
+ *
+ * If the control point is change, the distance control point
+ * is changed, too!
+ */
+ PMPlaneNormalControlPoint( PMDistanceControlPoint* d, const PMVector& normal,
+ int id, const QString& description );
+ /**
+ * Deletes the PMPlaneNormalControlPoint
+ */
+ virtual ~PMPlaneNormalControlPoint( ) { };
+
+ /** */
+ virtual PMVector position( ) const;
+
+ /**
+ * Sets the normal vector
+ */
+ void setNormal( PMVector newNormal ) { m_normal = newNormal; }
+ /**
+ * Returns the normal vector
+ */
+ PMVector normal( ) const { return m_normal; }
+ /**
+ * Returns the distance
+ */
+ double distance( ) const;
+
+ /** */
+ virtual bool hasExtraLine( ) const { return true; }
+ /**
+ * Returns the start point of the extra line
+ */
+ virtual PMVector extraLineStart( ) const;
+ /**
+ * Returns the end point of the extra line
+ */
+ virtual PMVector extraLineEnd( ) const;
+
+ /** */
+ virtual void snapToGrid( );
+
+protected:
+ /** */
+ virtual void graphicalChangeStarted( );
+ /** */
+ virtual void graphicalChange( const PMVector& startPoint,
+ const PMVector& viewNormal,
+ const PMVector& endPoint );
+private:
+ PMVector m_normal, m_originalNormal;
+ double m_originalDistance;
+ PMDistanceControlPoint* m_pDistancePoint;
+};
+
+#endif
diff --git a/kpovmodeler/pmpluginmanager.cpp b/kpovmodeler/pmpluginmanager.cpp
new file mode 100644
index 00000000..0921f79d
--- /dev/null
+++ b/kpovmodeler/pmpluginmanager.cpp
@@ -0,0 +1,115 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmpluginmanager.h"
+#include "pmpart.h"
+#include "pmshell.h"
+#include "pmfactory.h"
+#include "pmdebug.h"
+
+#include <qmap.h>
+#include <qapplication.h>
+
+#include <kparts/plugin.h>
+#include <kxmlguifactory.h>
+#include <kconfig.h>
+
+PMPluginManager* PMPluginManager::s_pInstance = 0;
+KStaticDeleter<PMPluginManager> PMPluginManager::s_staticDeleter;
+
+using namespace KParts;
+
+// workaround for protected Plugin::pluginInfos
+class PMPluginWorkaround : public Plugin
+{
+public:
+ PMPluginWorkaround( ) : Plugin( 0, 0 ) { };
+ static QValueList<Plugin::PluginInfo> installedPlugins( const KInstance* instance )
+ {
+ return pluginInfos( instance );
+ }
+};
+
+PMPluginManager::PMPluginManager( )
+{
+ // find installed plugins
+ KConfigGroup cfgGroup( PMFactory::instance( )->config( ),
+ "KParts Plugins" );
+ QValueList<Plugin::PluginInfo> plugins
+ = PMPluginWorkaround::installedPlugins( PMFactory::instance( ) );
+ QValueList<Plugin::PluginInfo>::ConstIterator pIt = plugins.begin( );
+ QValueList<Plugin::PluginInfo>::ConstIterator pEnd = plugins.end( );
+
+ for( ; pIt != pEnd; ++pIt )
+ {
+ QDomElement docElem = ( *pIt ).m_document.documentElement( );
+ QString name = docElem.attribute( "name" );
+ QString description = docElem.attribute( "description" );
+ if( !description.isEmpty( ) )
+ description = i18n( description.latin1( ) );
+ bool enabled = cfgGroup.readBoolEntry( name + "Enabled", false );
+ m_plugins.append( new PMPluginInfo( name, description, enabled ) );
+ }
+}
+
+PMPluginManager::~PMPluginManager( )
+{
+ m_plugins.setAutoDelete( true );
+ m_plugins.clear( );
+}
+
+PMPluginManager* PMPluginManager::theManager( )
+{
+ if( !s_pInstance )
+ s_staticDeleter.setObject( s_pInstance, new PMPluginManager( ) );
+ return s_pInstance;
+}
+
+void PMPluginManager::registerPart( PMPart* p )
+{
+ if( !m_parts.containsRef( p ) )
+ {
+ m_parts.append( p );
+ Plugin::loadPlugins( p, p, PMFactory::instance( ), false );
+ }
+}
+
+void PMPluginManager::removePart( PMPart* p )
+{
+ m_parts.removeRef( p );
+}
+
+void PMPluginManager::updatePlugins( )
+{
+ KConfigGroup cfgGroup( PMFactory::instance( )->config( ),
+ "KParts Plugins" );
+ QPtrListIterator<PMPluginInfo> pit( m_plugins );
+ for( ; *pit; ++pit )
+ cfgGroup.writeEntry( ( *pit )->name( ) + "Enabled",
+ ( *pit )->enabled( ) );
+ cfgGroup.sync( );
+
+ QPtrListIterator<PMPart> it( m_parts );
+ for( ; *it; ++it )
+ {
+ Plugin::loadPlugins( *it, *it, PMFactory::instance( ), false );
+ PMShell* shell = ( *it )->shell( );
+ if( shell )
+ shell->updateGUI( );
+ // TODO find a solution to update the gui without using the shell
+ }
+}
diff --git a/kpovmodeler/pmpluginmanager.h b/kpovmodeler/pmpluginmanager.h
new file mode 100644
index 00000000..9424e014
--- /dev/null
+++ b/kpovmodeler/pmpluginmanager.h
@@ -0,0 +1,113 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMPLUGINMANAGER_H
+#define PMPLUGINMANAGER_H
+
+#include <kstaticdeleter.h>
+
+#include <qstring.h>
+#include <qptrlist.h>
+
+class PMPart;
+
+/**
+ * Plugin info for one plugin
+ */
+class PMPluginInfo
+{
+public:
+ /**
+ * Default constructor
+ */
+ PMPluginInfo( const QString& name, const QString& description,
+ bool enabled )
+ {
+ m_name = name;
+ m_description = description;
+ m_enabled = enabled;
+ }
+ /**
+ * Returns the plugin name
+ */
+ QString name( ) const { return m_name; }
+ /**
+ * Returns the plugin description (i18n'ed)
+ */
+ QString description( ) const { return m_description; }
+ /**
+ * Returns true if the plugin is enabled
+ */
+ bool enabled( ) const { return m_enabled; }
+ /**
+ * Enables/disables the plugin
+ */
+ void enable( bool en ) { m_enabled = en; }
+private:
+ QString m_name, m_description;
+ bool m_enabled;
+};
+
+/**
+ * Manager class for plugins.
+ *
+ * Stores a list of available plugins and loads and unloads plugins.
+ */
+class PMPluginManager
+{
+public:
+ /**
+ * Destructor
+ */
+ ~PMPluginManager( );
+ /**
+ * Returns the instance (singleton)
+ */
+ static PMPluginManager* theManager( );
+
+ /**
+ * Registers a part instance and loads the plugins for that part
+ */
+ void registerPart( PMPart* p );
+ /**
+ * Removes a part instance
+ */
+ void removePart( PMPart* p );
+
+ /**
+ * Returns a list of available plugins
+ */
+ QPtrList<PMPluginInfo> plugins( ) const { return m_plugins; }
+ /**
+ * Loads and unloads plugins for all parts when plugins were activated or
+ * deactivated
+ */
+ void updatePlugins( );
+private:
+ /**
+ * Constructor
+ */
+ PMPluginManager( );
+
+ QPtrList<PMPluginInfo> m_plugins;
+ QPtrList<PMPart> m_parts;
+
+ static PMPluginManager* s_pInstance;
+ static KStaticDeleter<PMPluginManager> s_staticDeleter;
+};
+
+#endif
diff --git a/kpovmodeler/pmpluginsettings.cpp b/kpovmodeler/pmpluginsettings.cpp
new file mode 100644
index 00000000..6b6611f2
--- /dev/null
+++ b/kpovmodeler/pmpluginsettings.cpp
@@ -0,0 +1,150 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmpluginsettings.h"
+
+#include "pmpluginmanager.h"
+
+#include <qlayout.h>
+#include <qgroupbox.h>
+#include <qlistview.h>
+#include <qpushbutton.h>
+#include <klocale.h>
+
+class PMPluginListViewItem : public QListViewItem
+{
+public:
+ PMPluginListViewItem( QListView* parent, PMPluginInfo* info )
+ : QListViewItem( parent, info->name( ), info->description( ) )
+ {
+ m_info = info;
+ m_enabled = info->enabled( );
+ setStatus( );
+ }
+ void toggleStatus( )
+ {
+ m_enabled = !m_enabled;
+ setStatus( );
+ }
+ void setStatus( )
+ {
+ if( m_enabled )
+ setText( 2, i18n( "loaded" ) );
+ else
+ setText( 2, i18n( "deactivated" ) );
+ }
+ PMPluginInfo* m_info;
+ bool m_enabled;
+};
+
+PMPluginSettings::PMPluginSettings( QWidget* parent, const char* name )
+ : PMSettingsDialogPage( parent, name )
+{
+ QVBoxLayout* vlayout = new QVBoxLayout( this, 0, KDialog::spacingHint( ) );
+
+ QGroupBox* gb = new QGroupBox( i18n( "Installed Plugins" ), this );
+ vlayout->addWidget( gb );
+
+ QVBoxLayout* gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) );
+ gvl->addSpacing( 10 );
+
+ m_pPluginsList = new QListView( gb );
+ connect( m_pPluginsList, SIGNAL( selectionChanged( ) ),
+ SLOT( slotSelectionChanged( ) ) );
+ m_pPluginsList->addColumn( i18n( "Name" ) );
+ m_pPluginsList->addColumn( i18n( "Description" ) );
+ m_pPluginsList->addColumn( i18n( "Status" ) );
+ gvl->addWidget( m_pPluginsList, 1 );
+
+ QHBoxLayout* hl = new QHBoxLayout( gvl );
+ m_pToggle = new QPushButton( i18n( "Load" ), gb );
+ m_pToggle->setEnabled( false );
+ connect( m_pToggle, SIGNAL( clicked( ) ), SLOT( slotToggle( ) ) );
+ hl->addWidget( m_pToggle );
+ hl->addStretch( 1 );
+
+ vlayout->addStretch( 1 );
+}
+
+void PMPluginSettings::displaySettings( )
+{
+ QPtrList<PMPluginInfo> plugins = PMPluginManager::theManager( )->plugins( );
+ QPtrListIterator<PMPluginInfo> it( plugins );
+
+ m_pPluginsList->clear( );
+ for( ; *it; ++it )
+ new PMPluginListViewItem( m_pPluginsList, *it );
+}
+
+void PMPluginSettings::applySettings( )
+{
+ bool changes = false;
+ PMPluginListViewItem* item =
+ ( PMPluginListViewItem* ) m_pPluginsList->firstChild( );
+ for( ; item; item = ( PMPluginListViewItem* ) item->nextSibling( ) )
+ {
+ if( item->m_enabled != item->m_info->enabled( ) )
+ {
+ item->m_info->enable( item->m_enabled );
+ changes = true;
+ }
+ }
+ if( changes )
+ PMPluginManager::theManager( )->updatePlugins( );
+}
+
+bool PMPluginSettings::validateData( )
+{
+ return true;
+}
+
+void PMPluginSettings::displayDefaults( )
+{
+}
+
+void PMPluginSettings::slotToggle( )
+{
+ PMPluginListViewItem* item =
+ ( PMPluginListViewItem* ) m_pPluginsList->currentItem( );
+ if( item )
+ {
+ item->toggleStatus( );
+
+ if( item->m_enabled )
+ m_pToggle->setText( i18n( "Deactivate" ) );
+ else
+ m_pToggle->setText( i18n( "Load" ) );
+ }
+}
+
+void PMPluginSettings::slotSelectionChanged( )
+{
+ PMPluginListViewItem* item =
+ ( PMPluginListViewItem* ) m_pPluginsList->currentItem( );
+ if( item )
+ {
+ m_pToggle->setEnabled( true );
+ if( item->m_enabled )
+ m_pToggle->setText( i18n( "Deactivate" ) );
+ else
+ m_pToggle->setText( i18n( "Load" ) );
+ }
+ else
+ m_pToggle->setEnabled( false );
+}
+
+#include "pmpluginsettings.moc"
diff --git a/kpovmodeler/pmpluginsettings.h b/kpovmodeler/pmpluginsettings.h
new file mode 100644
index 00000000..1ee9191a
--- /dev/null
+++ b/kpovmodeler/pmpluginsettings.h
@@ -0,0 +1,62 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMPLUGINSETTINGS_H
+#define PMPLUGINSETTINGS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsettingsdialog.h"
+
+class QFrame;
+class QListView;
+class QPushButton;
+
+/**
+ * Plugins configuration dialog page
+ */
+class PMPluginSettings : public PMSettingsDialogPage
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ PMPluginSettings( QWidget* parent, const char* name = 0 );
+ /** */
+ virtual void displaySettings( );
+ /** */
+ virtual void applySettings( );
+ /** */
+ virtual bool validateData( );
+ /** */
+ virtual void displayDefaults( );
+
+protected slots:
+ void slotToggle( );
+ void slotSelectionChanged( );
+
+private:
+ QFrame* m_pPluginOptions;
+ QListView* m_pPluginsList;
+ QPushButton* m_pToggle;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmpoint.cpp b/kpovmodeler/pmpoint.cpp
new file mode 100644
index 00000000..2933030e
--- /dev/null
+++ b/kpovmodeler/pmpoint.cpp
@@ -0,0 +1,98 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmpoint.h"
+#include "pmvector.h"
+#include "pmmatrix.h"
+#include "pmmath.h"
+
+
+PMPoint::PMPoint( )
+{
+ m_coord[0] = 0;
+ m_coord[1] = 0;
+ m_coord[2] = 0;
+}
+
+PMPoint::PMPoint( GLdouble x, GLdouble y, GLdouble z )
+{
+ m_coord[0] = x;
+ m_coord[1] = y;
+ m_coord[2] = z;
+}
+
+PMPoint::PMPoint( const PMVector& v )
+{
+ if( v.size( ) == 3 )
+ {
+ m_coord[0] = v[0];
+ m_coord[1] = v[1];
+ m_coord[2] = v[2];
+ }
+ else
+ {
+ m_coord[0] = 0;
+ m_coord[1] = 0;
+ m_coord[2] = 0;
+ }
+}
+
+PMPoint::PMPoint( const PMPoint& p )
+{
+ m_coord[0] = p.m_coord[0];
+ m_coord[1] = p.m_coord[1];
+ m_coord[2] = p.m_coord[2];
+}
+
+PMPoint& PMPoint::operator= ( const PMPoint& p )
+{
+ m_coord[0] = p.m_coord[0];
+ m_coord[1] = p.m_coord[1];
+ m_coord[2] = p.m_coord[2];
+
+ return *this;
+}
+
+void PMPoint::transform( const PMMatrix& m )
+{
+ (*this) = m * (*this);
+}
+
+PMPoint operator* ( const PMMatrix& m, const PMPoint& p )
+{
+ PMPoint result;
+ int c, i;
+ // for homogenous coordinates
+ double u;
+
+ for( c = 0; c < 3; c++ )
+ {
+ result.m_coord[c] = 0.0;
+ for( i = 0; i < 4; i++ )
+ result.m_coord[c] += m[i][c] * ( i<3 ? p[i] : 1.0 );
+ }
+
+ u = 0.0;
+ for( i = 0; i < 4; i++ )
+ u += m[i][3] * ( i<3 ? p[i] : 1.0 );
+ if( !approxZero( u ) )
+ for( i = 0; i < 3; i++ )
+ result.m_coord[i] /= u;
+
+ return result;
+}
diff --git a/kpovmodeler/pmpoint.h b/kpovmodeler/pmpoint.h
new file mode 100644
index 00000000..729d60c0
--- /dev/null
+++ b/kpovmodeler/pmpoint.h
@@ -0,0 +1,122 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPOINT_H
+#define PMPOINT_H
+
+#include "GL/gl.h"
+#include <qmemarray.h>
+
+class PMVector;
+class PMMatrix;
+
+/**
+ * Class for 3d points.
+ *
+ * Used in @ref PMViewStructure.
+ *
+ * Optimized for rendering with opengl
+ */
+
+class PMPoint
+{
+public:
+ /**
+ * Creates a point with coordinates [0,0,0]
+ */
+ PMPoint( );
+ /**
+ * Creates a point with coordinates [x,y,z]
+ */
+ PMPoint( GLdouble x, GLdouble y, GLdouble z );
+ /**
+ * Creates a point from a vector. The size of the vector has to be 3
+ */
+ PMPoint( const PMVector& v );
+ /**
+ * Copy constructor
+ */
+ PMPoint( const PMPoint& p );
+
+ /**
+ * Returns a reference to a coordinate, 0:x, 1:y, 2:z
+ */
+ GLdouble& operator[] ( int index ) { return m_coord[index];}
+ /**
+ * Returns a reference to a coordinate, 0:x, 1:y, 2:z
+ */
+ const GLdouble& operator[] ( int index ) const { return m_coord[index];}
+
+ /**
+ * Returns the x coordinate
+ */
+ GLdouble x( ) const { return m_coord[0]; }
+ /**
+ * Returns the y coordinate
+ */
+ GLdouble y( ) const { return m_coord[1]; }
+ /**
+ * Returns the z coordinate
+ */
+ GLdouble z( ) const { return m_coord[2]; }
+
+ /**
+ * Sets the x coordinate
+ */
+ void setX( const GLdouble newx ) { m_coord[0] = newx; }
+ /**
+ * Sets the y coordinate
+ */
+ void setY( const GLdouble newy ) { m_coord[1] = newy; }
+ /**
+ * Sets the z coordinate
+ */
+ void setZ( const GLdouble newz ) { m_coord[2] = newz; }
+
+ /**
+ * Transforms the point p with the matrix m
+ * @see transform
+ */
+ friend PMPoint operator* ( const PMMatrix& m, const PMPoint& p );
+ /**
+ * Assigns c to the point
+ */
+ PMPoint& operator= ( const PMPoint& c );
+ /**
+ * Transforms the point with the matrix m. Same as p = m * p
+ *
+ * size must be 3!
+ */
+ void transform( const PMMatrix& m );
+
+private:
+ /**
+ * The coords. THIS MEMBER HAS TO BE THE FIRST AND ONLY ONE
+ * (for rendering with OpenGL)!
+ */
+ GLdouble m_coord[3];
+};
+
+/**
+ * @ref QMemArray of PMPoints
+ */
+typedef QMemArray<PMPoint> PMPointArray;
+
+
+#endif
diff --git a/kpovmodeler/pmpolynom.cpp b/kpovmodeler/pmpolynom.cpp
new file mode 100644
index 00000000..93555a58
--- /dev/null
+++ b/kpovmodeler/pmpolynom.cpp
@@ -0,0 +1,238 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmpolynom.h"
+#include "pmpolynomedit.h"
+
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+
+#include <klocale.h>
+
+const double c_defaultCoefficients[10] =
+{ // Hyperboloid_Y
+ 1.0, 0.0, 0.0,
+ 0.0, -1.0, 0.0,
+ 0.0, 1.0, 0.0,
+ -1.0
+};
+const int c_defaultOrder = 2;
+const bool c_defaultSturm = true;
+const int c_polynomSize[8] = { 0, 0, 10, 20, 35, 56, 84, 120 };
+
+PMDefinePropertyClass( PMPolynom, PMPolynomProperty );
+
+class PMCoefficientProperty : public PMPropertyBase
+{
+public:
+ PMCoefficientProperty( )
+ : PMPropertyBase( "coefficients", PMVariant::Double )
+ {
+ m_index = 0;
+ }
+ virtual int dimensions( ) const { return 1; }
+ virtual void setIndex( int /*dimension*/, int index )
+ {
+ m_index = index;
+ }
+ virtual int size( PMObject* object, int /*dimension*/ ) const
+ {
+ return c_polynomSize[ ( ( PMPolynom* ) object )->polynomOrder( ) ];
+ }
+protected:
+ virtual bool setProtected( PMObject* obj, const PMVariant& var )
+ {
+ PMPolynom* p = ( PMPolynom* ) obj;
+ PMVector v = p->coefficients( );
+ v[m_index] = var.doubleData( );
+ p->setCoefficients( v );
+
+ return true;
+ }
+ virtual PMVariant getProtected( const PMObject* obj )
+ {
+ PMPolynom* p = ( PMPolynom* ) obj;
+ return PMVariant( p->coefficients( )[m_index] );
+ }
+
+private:
+ int m_index;
+};
+
+PMMetaObject* PMPolynom::s_pMetaObject = 0;
+PMObject* createNewPolynom( PMPart* part )
+{
+ return new PMPolynom( part );
+}
+
+PMPolynom::PMPolynom( PMPart* part )
+ : Base( part )
+{
+ int i;
+ m_order = c_defaultOrder;
+ m_coefficients = PMVector( 10 );
+ for( i = 0; i < 10; i++ )
+ m_coefficients[i] = c_defaultCoefficients[i];
+ m_sturm = c_defaultSturm;
+}
+
+PMPolynom::PMPolynom( const PMPolynom& p )
+ : Base( p )
+{
+ m_order = p.m_order;
+ m_coefficients = p.m_coefficients;
+ m_sturm = p.m_sturm;
+}
+
+PMPolynom::~PMPolynom( )
+{
+}
+
+QString PMPolynom::description( ) const
+{
+ if( m_order == 2 )
+ return i18n( "quadric" );
+ else if( m_order == 3 )
+ return i18n( "cubic" );
+ else if( m_order == 4 )
+ return i18n( "quartic" );
+ return i18n( "polynom" );
+}
+
+void PMPolynom::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "order", m_order );
+ e.setAttribute( "coefficients", m_coefficients.serializeXML( ) );
+ e.setAttribute( "sturm", m_sturm );
+ Base::serialize( e, doc );
+}
+
+void PMPolynom::readAttributes( const PMXMLHelper& h )
+{
+ m_order = h.intAttribute( "order", c_defaultOrder );
+ m_coefficients = h.vectorAttribute( "coefficients", m_coefficients );
+ m_sturm = h.boolAttribute( "sturm", c_defaultSturm );
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMPolynom::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Polynom", Base::metaObject( ),
+ createNewPolynom );
+ s_pMetaObject->addProperty(
+ new PMPolynomProperty( "polynomOrder", &PMPolynom::setPolynomOrder,
+ &PMPolynom::polynomOrder ) );
+ s_pMetaObject->addProperty(
+ new PMPolynomProperty( "sturm", &PMPolynom::setSturm,
+ &PMPolynom::sturm ) );
+
+ s_pMetaObject->addProperty( new PMCoefficientProperty( ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMPolynom::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+PMDialogEditBase* PMPolynom::editWidget( QWidget* parent ) const
+{
+ return new PMPolynomEdit( parent );
+}
+
+void PMPolynom::setPolynomOrder( int o )
+{
+ if( ( o < 2 ) || ( o > 7 ) )
+ {
+ kdError( PMArea ) << "Invalid order in PMPolynom::setPolynomOrder\n";
+ o = 2;
+ }
+ if( o != m_order )
+ {
+ if( m_pMemento )
+ {
+ m_pMemento->addData( s_pMetaObject, PMOrderID, m_order );
+ if( ( o <= 4 ) || ( m_order <= 4 ) )
+ m_pMemento->setDescriptionChanged( );
+ }
+ m_order = o;
+ }
+}
+
+void PMPolynom::setCoefficients( const PMVector& c )
+{
+ if( c.size( ) != ( unsigned ) c_polynomSize[m_order] )
+ kdError( PMArea ) << "Wrong vector size in PMPolynom::setCoefficients\n";
+
+ if( c != m_coefficients )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMCoefficientsID, m_coefficients );
+ m_coefficients = c;
+ m_coefficients.resize( c_polynomSize[m_order] );
+ //setViewStructureChanged( );
+ }
+}
+
+void PMPolynom::setSturm( bool s )
+{
+ if( m_sturm != s )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSturmID, m_sturm );
+ m_sturm = s;
+ }
+}
+
+void PMPolynom::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMOrderID:
+ setPolynomOrder( data->intData( ) );
+ break;
+ case PMCoefficientsID:
+ setCoefficients( data->vectorData( ) );
+ break;
+ case PMSturmID:
+ setSturm( data->boolData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMPolynom::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmpolynom.h b/kpovmodeler/pmpolynom.h
new file mode 100644
index 00000000..dc59be67
--- /dev/null
+++ b/kpovmodeler/pmpolynom.h
@@ -0,0 +1,105 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPOLYNOM_H
+#define PMPOLYNOM_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobject.h"
+#include "pmvector.h"
+
+/**
+ * Class for povray polynoms.
+ */
+
+class PMPolynom : public PMSolidObject
+{
+ typedef PMSolidObject Base;
+public:
+ /**
+ * Creates an empty PMPolynom
+ */
+ PMPolynom( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMPolynom( const PMPolynom& p );
+ /**
+ * deletes the PMPolynom
+ */
+ virtual ~PMPolynom( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMPolynom( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmpolynom" ); }
+ /**
+ * Returns a new @ref PMPolynomEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+
+ /** */
+ int polynomOrder( ) const { return m_order; }
+ /**
+ * Sets the polynom order
+ */
+ void setPolynomOrder( int order );
+ /**
+ * Returns the coefficients.
+ */
+ PMVector coefficients( ) const { return m_coefficients; }
+ /**
+ * Sets the coefficients.
+ */
+ void setCoefficients( const PMVector& p );
+ /**
+ * Returns the sturm flag
+ */
+ bool sturm( ) const { return m_sturm; }
+ /**
+ * Sets the sturm flag
+ */
+ void setSturm( bool s );
+private:
+ enum PMPolynomMementoID { PMOrderID, PMCoefficientsID, PMSturmID };
+ int m_order;
+ PMVector m_coefficients;
+ bool m_sturm;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmpolynomedit.cpp b/kpovmodeler/pmpolynomedit.cpp
new file mode 100644
index 00000000..b236a8c6
--- /dev/null
+++ b/kpovmodeler/pmpolynomedit.cpp
@@ -0,0 +1,255 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmpolynomedit.h"
+#include "pmpolynom.h"
+#include "pmpolynomexponents.h"
+#include "pmlineedits.h"
+#include "pmformulalabel.h"
+
+#include <qlayout.h>
+#include <qcheckbox.h>
+#include <qspinbox.h>
+#include <qlabel.h>
+#include <klocale.h>
+#include <kdialog.h>
+
+PMPolynomEdit::PMPolynomEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+ m_currentOrder = 0;
+ m_readOnly = false;
+}
+
+void PMPolynomEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "Order" ), this ) );
+ m_pOrder = new QSpinBox( 2, 7, 1, this );
+ hl->addWidget( m_pOrder );
+ hl->addStretch( 1 );
+ connect( m_pOrder, SIGNAL( valueChanged( int ) ), SLOT( slotOrderChanged( int ) ) );
+
+ topLayout( )->addWidget( new QLabel( i18n( "Formula:" ), this ) );
+ m_pPolyWidget = new QWidget( this );
+ topLayout( )->addWidget( m_pPolyWidget );
+ m_pSturm = new QCheckBox( i18n( "Sturm" ), this );
+ topLayout( )->addWidget( m_pSturm );
+ connect( m_pSturm, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMPolynomEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Polynom" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_readOnly = readOnly;
+ m_pDisplayedObject = ( PMPolynom* ) o;
+
+ displayCoefficients( m_pDisplayedObject->coefficients( ),
+ m_pDisplayedObject->polynomOrder( ),
+ m_pDisplayedObject->polynomOrder( ) );
+
+ m_pSturm->setChecked( m_pDisplayedObject->sturm( ) );
+ m_pSturm->setEnabled( !readOnly );
+ if( m_pDisplayedObject->polynomOrder( ) == 2 )
+ m_pSturm->hide( );
+ else
+ m_pSturm->show( );
+
+ bool sb = m_pOrder->signalsBlocked( );
+ m_pOrder->blockSignals( true );
+ m_pOrder->setValue( m_pDisplayedObject->polynomOrder( ) );
+ m_pOrder->blockSignals( sb );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMPolynomEdit: Can't display object\n";
+}
+
+void PMPolynomEdit::displayCoefficients( const PMVector& co, int cOrder,
+ int dOrder )
+{
+ QValueList<PMPolynomExponents>& polynom
+ = PMPolynomExponents::polynom( dOrder );
+
+ if( dOrder != m_currentOrder )
+ {
+ if( m_currentOrder > 0 )
+ {
+ if( m_pPolyWidget->layout( ) )
+ delete m_pPolyWidget->layout( );
+
+ m_labels.setAutoDelete( true );
+ m_labels.clear( );
+ m_labels.setAutoDelete( false );
+ m_edits.setAutoDelete( true );
+ m_edits.clear( );
+ m_edits.setAutoDelete( false );
+ }
+
+ int nedit = polynom.count( );
+ int nr = ( nedit + 2 ) / 3;
+ int i;
+
+ QGridLayout* gl = new QGridLayout( m_pPolyWidget, nr * 2 - 1, 9, 0 );
+ QLabel* l = 0;
+ PMFloatEdit* edit;
+ PMFormulaLabel* fl;
+
+ QValueList<PMPolynomExponents>::ConstIterator it = polynom.begin( );
+ QString text;
+ int row, col;
+ QString plus( "+" );
+
+ for( i = 0; it != polynom.end( ); i++, ++it )
+ {
+ row = ( i / 3 ) * 2;
+ col = ( i % 3 ) * 3;
+
+ if( i != 0 )
+ {
+ l = new QLabel( plus, m_pPolyWidget );
+ m_labels.append( l );
+ gl->addWidget( l, row, col );
+ l->show( );
+ }
+
+ edit = new PMFloatEdit( m_pPolyWidget );
+ connect( edit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ m_edits.append( edit );
+ gl->addWidget( edit, row, col + 1 );
+ edit->show( );
+ edit->setReadOnly( m_readOnly );
+
+ fl = new PMFormulaLabel( *it, m_pPolyWidget );
+
+ m_labels.append( fl );
+ gl->addWidget( fl, row, col + 2 );
+ fl->show( );
+ }
+ for( i = 0; i < ( nr - 1 ); i++ )
+ gl->addRowSpacing( i * 2 + 1, KDialog::spacingHint( ) );
+
+ emit sizeChanged( );
+ }
+ m_currentOrder = dOrder;
+
+
+ if( dOrder == cOrder )
+ {
+ QPtrListIterator<PMFloatEdit> eit( m_edits );
+ int i;
+ for( i = 0; *eit; ++eit, ++i )
+ ( *eit )->setValue( co[i] );
+ }
+ else if( dOrder > cOrder )
+ {
+ QValueList<PMPolynomExponents>::ConstIterator dit = polynom.begin( );
+ QValueList<PMPolynomExponents>& cpoly
+ = PMPolynomExponents::polynom( cOrder );
+ QValueList<PMPolynomExponents>::ConstIterator cit = cpoly.begin( );
+ QPtrListIterator<PMFloatEdit> eit( m_edits );
+ int i = 0;
+
+ for( ; ( dit != polynom.end( ) ) && ( cit != cpoly.end( ) ); ++dit, ++eit )
+ {
+ if( *dit == *cit )
+ {
+ ( *eit )->setValue( co[i] );
+ i++;
+ cit++;
+ }
+ else
+ ( *eit )->setValue( 0.0 );
+ }
+ if( ( dit != polynom.end( ) ) || ( cit != cpoly.end( ) ) )
+ kdError( PMArea ) << "displayExponents is buggy!\n";
+ }
+ else // dOrder < cOrder
+ {
+ QValueList<PMPolynomExponents>::ConstIterator dit = polynom.begin( );
+ QValueList<PMPolynomExponents>& cpoly
+ = PMPolynomExponents::polynom( cOrder );
+ QValueList<PMPolynomExponents>::ConstIterator cit = cpoly.begin( );
+ QPtrListIterator<PMFloatEdit> eit( m_edits );
+ int i = 0;
+
+ for( ; ( dit != polynom.end( ) ) && ( cit != cpoly.end( ) ); ++cit, ++i )
+ {
+ if( *dit == *cit )
+ {
+ ( *eit )->setValue( co[i] );
+ ++eit;
+ ++dit;
+ }
+ }
+ if( ( dit != polynom.end( ) ) || ( cit != cpoly.end( ) ) )
+ kdError( PMArea ) << "displayExponents is buggy!\n";
+ }
+}
+
+PMVector PMPolynomEdit::coefficients( ) const
+{
+ QPtrListIterator<PMFloatEdit> eit( m_edits );
+ int num = m_edits.count( );
+ PMVector v( num );
+ int i;
+
+ for( i = 0 ; *eit; ++eit, ++i )
+ v[i] = ( *eit )->value( );
+ return v;
+}
+
+void PMPolynomEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ m_pDisplayedObject->setPolynomOrder( m_pOrder->value( ) );
+ m_pDisplayedObject->setCoefficients( coefficients( ) );
+
+ Base::saveContents( );
+
+ m_pDisplayedObject->setSturm( m_pSturm->isChecked( ) );
+ }
+}
+
+bool PMPolynomEdit::isDataValid( )
+{
+ QPtrListIterator<PMFloatEdit> eit( m_edits );
+ for( ; *eit; ++eit )
+ if( !( *eit )->isDataValid( ) )
+ return false;
+ return Base::isDataValid( );
+}
+
+void PMPolynomEdit::slotOrderChanged( int order )
+{
+ if( order == 2 )
+ m_pSturm->hide( );
+ else
+ m_pSturm->show( );
+
+ displayCoefficients( coefficients( ), m_currentOrder, order );
+}
+
+#include "pmpolynomedit.moc"
diff --git a/kpovmodeler/pmpolynomedit.h b/kpovmodeler/pmpolynomedit.h
new file mode 100644
index 00000000..6ffb05b4
--- /dev/null
+++ b/kpovmodeler/pmpolynomedit.h
@@ -0,0 +1,80 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPOLYNOMEDIT_H
+#define PMPOLYNOMEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobjectedit.h"
+#include <qptrlist.h>
+
+class PMPolynom;
+class PMFloatEdit;
+class PMFormulaLabel;
+class QSpinBox;
+class QCheckBox;
+
+/**
+ * Dialog edit class for @ref PMPolynom
+ */
+class PMPolynomEdit : public PMSolidObjectEdit
+{
+ Q_OBJECT
+ typedef PMSolidObjectEdit Base;
+public:
+ /**
+ * Creates a PMPolynomEdit with parent and name
+ */
+ PMPolynomEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+protected slots:
+ void slotOrderChanged( int );
+
+private:
+ void displayCoefficients( const PMVector& co, int cOrder, int dOrder );
+ PMVector coefficients( ) const;
+
+ PMPolynom* m_pDisplayedObject;
+
+ int m_currentOrder;
+
+ QWidget* m_pPolyWidget;
+ QPtrList<QWidget> m_labels;
+ QPtrList<PMFloatEdit> m_edits;
+ QCheckBox* m_pSturm;
+ QSpinBox* m_pOrder;
+ bool m_readOnly;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmpolynomexponents.cpp b/kpovmodeler/pmpolynomexponents.cpp
new file mode 100644
index 00000000..fdda7bdf
--- /dev/null
+++ b/kpovmodeler/pmpolynomexponents.cpp
@@ -0,0 +1,71 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmpolynomexponents.h"
+#include "pmdebug.h"
+
+bool PMPolynomExponents::m_created[6] = { false, false, false,
+ false, false, false };
+QValueList<PMPolynomExponents> PMPolynomExponents::m_lists[6];
+
+PMPolynomExponents operator+ ( const PMPolynomExponents& p1,
+ const PMPolynomExponents& p2 )
+{
+ return PMPolynomExponents( p1.m_exponents[0] + p2.m_exponents[0],
+ p1.m_exponents[1] + p2.m_exponents[1],
+ p1.m_exponents[2] + p2.m_exponents[2] );
+}
+
+QValueList<PMPolynomExponents>& PMPolynomExponents::polynom( int n )
+{
+ if( ( n < 2 ) || ( n > 7 ) )
+ {
+ n = 2;
+ kdError( PMArea ) << "Wrong polynom order in PMPolynomExponents::polynom( )\n";
+ }
+
+ if( !m_created[n-2] )
+ {
+ m_lists[n-2] = recPolynom( PMPolynomExponents( 0, 0, 0 ), 0, n, 0 );
+ m_created[n-2] = true;
+// kdDebug( PMArea ) << "Polynom n: " << n << " size: " << m_lists[n-2].count( ) << endl;
+ }
+
+ return m_lists[n-2];
+}
+
+QValueList<PMPolynomExponents>
+PMPolynomExponents::recPolynom( const PMPolynomExponents& base,
+ int xyz, int n, int rem )
+{
+ QValueList<PMPolynomExponents> res;
+
+ if( n >= 0 )
+ {
+ if( ( ( rem + n ) == 0 ) || ( xyz > 2 ) )
+ res.append( base );
+ else
+ {
+ PMPolynomExponents newBase = base;
+ newBase.setExponent( xyz, n );
+ res += recPolynom( newBase, xyz + 1, rem, 0 );
+ res += recPolynom( base, xyz, n - 1, rem + 1 );
+ }
+ }
+
+ return res;
+}
diff --git a/kpovmodeler/pmpolynomexponents.h b/kpovmodeler/pmpolynomexponents.h
new file mode 100644
index 00000000..6f1812ba
--- /dev/null
+++ b/kpovmodeler/pmpolynomexponents.h
@@ -0,0 +1,129 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPOLYNOMEXPONENTS_H
+#define PMPOLYNOMEXPONENTS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qptrlist.h>
+#include <qvaluelist.h>
+
+/**
+ * Helper class for the @ref PMPolynomBaseEdit widget
+ */
+class PMPolynomExponents
+{
+public:
+ /**
+ * All exponents are initialized with 0
+ */
+ PMPolynomExponents( )
+ {
+ m_exponents[0] = m_exponents[1] = m_exponents[2] = 0;
+ }
+ /**
+ * The exponents are initialized with x, y, z
+ */
+ PMPolynomExponents( int x, int y, int z )
+ {
+ m_exponents[0] = x;
+ m_exponents[1] = y;
+ m_exponents[2] = z;
+ }
+
+ /**
+ * Returns the ith exponent
+ */
+ int exponent( int i ) const { return m_exponents[i]; }
+ /**
+ * Sets the ith exponent
+ */
+ void setExponent( int i, int exp ) { m_exponents[i] = exp; }
+
+ /**
+ * Returns the x exponent
+ */
+ int xExponent( ) const { return m_exponents[0]; }
+ /**
+ * Sets the x exponent
+ */
+ void setXExponent( int exp ) { m_exponents[0] = exp; }
+ /**
+ * Returns the y exponent
+ */
+ int yExponent( ) const { return m_exponents[1]; }
+ /**
+ * Sets the y exponent
+ */
+ void setYExponent( int exp ) { m_exponents[1] = exp; }
+ /**
+ * Returns the z exponent
+ */
+ int zExponent( ) const { return m_exponents[2]; }
+ /**
+ * Sets the z exponent
+ */
+ void setZExponent( int exp ) { m_exponents[2] = exp; }
+
+ bool operator== ( const PMPolynomExponents& e ) const
+ {
+ return ( m_exponents[0] == e.m_exponents[0] ) &&
+ ( m_exponents[1] == e.m_exponents[1] ) &&
+ ( m_exponents[2] == e.m_exponents[2] );
+ }
+ bool operator!= ( const PMPolynomExponents& e ) const
+ {
+ return !( *this == e );
+ }
+ PMPolynomExponents& operator= ( const PMPolynomExponents& p )
+ {
+ m_exponents[0] = p.m_exponents[0];
+ m_exponents[1] = p.m_exponents[1];
+ m_exponents[2] = p.m_exponents[2];
+ return *this;
+ }
+ friend PMPolynomExponents operator+ ( const PMPolynomExponents& p1,
+ const PMPolynomExponents& p2 );
+
+ /**
+ * Returns the sum of the exponents
+ */
+ int sum( ) const { return m_exponents[0] + m_exponents[1] + m_exponents[2]; }
+
+private:
+ int m_exponents[3];
+
+ // static stuff
+public:
+ /**
+ * Returns the exponents for a polynom with order n ( 2 <= n <= 7 )
+ */
+ static QValueList<PMPolynomExponents>& polynom( int n );
+
+private:
+ static QValueList<PMPolynomExponents> //...
+ recPolynom( const PMPolynomExponents& base, int xyz, int n, int rem );
+ static bool m_created[6];
+ static QValueList<PMPolynomExponents> m_lists[6];
+};
+
+#endif
diff --git a/kpovmodeler/pmpovray31format.cpp b/kpovmodeler/pmpovray31format.cpp
new file mode 100644
index 00000000..417dd177
--- /dev/null
+++ b/kpovmodeler/pmpovray31format.cpp
@@ -0,0 +1,153 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmpovray31format.h"
+#include "pmpovray31serialization.h"
+
+#include "pmpovrayparser.h"
+#include "pmoutputdevice.h"
+
+#include <klocale.h>
+
+PMPovray31Format::PMPovray31Format( )
+ : PMPovrayFormat( )
+{
+ registerMethod( "BicubicPatch", PMPov31SerBicubicPatch );
+ registerMethod( "BlendMapModifiers", PMPov31SerBlendMapModifiers );
+ registerMethod( "Blob", PMPov31SerBlob );
+ registerMethod( "BlobCylinder", PMPov31SerBlobCylinder );
+ registerMethod( "BlobSphere", PMPov31SerBlobSphere );
+ registerMethod( "BoundedBy", PMPov31SerBoundedBy );
+ registerMethod( "Box", PMPov31SerBox );
+ registerMethod( "BumpMap", PMPov31SerBumpMap );
+ registerMethod( "Camera", PMPov31SerCamera );
+ registerMethod( "ClippedBy", PMPov31SerClippedBy );
+ registerMethod( "Comment", PMPov31SerComment );
+ registerMethod( "CompositeObject", PMPov31SerCompositeObject );
+ registerMethod( "Cone", PMPov31SerCone );
+ registerMethod( "CSG", PMPov31SerCSG );
+ registerMethod( "Cylinder", PMPov31SerCylinder );
+ registerMethod( "Declare", PMPov31SerDeclare );
+ registerMethod( "Density", PMPov31SerDensity );
+ registerMethod( "Disc", PMPov31SerDisc );
+ registerMethod( "Finish", PMPov31SerFinish );
+ registerMethod( "Fog", PMPov31SerFog );
+ registerMethod( "GlobalSettings", PMPov31SerGlobalSettings );
+ registerMethod( "GraphicalObject", PMPov31SerGraphicalObject );
+ registerMethod( "HeightField", PMPov31SerHeightField );
+ registerMethod( "ImageMap", PMPov31SerImageMap );
+ registerMethod( "Interior", PMPov31SerInterior );
+ registerMethod( "JuliaFractal", PMPov31SerJuliaFractal );
+ registerMethod( "Lathe", PMPov31SerLathe );
+ registerMethod( "Light", PMPov31SerLight );
+ registerMethod( "ListPattern", PMPov31SerListPattern );
+ registerMethod( "TextureList", PMPov31SerTextureList );
+ registerMethod( "PigmentList", PMPov31SerPigmentList );
+ registerMethod( "ColorList", PMPov31SerColorList );
+ registerMethod( "DensityList", PMPov31SerDensityList );
+ registerMethod( "NormalList", PMPov31SerNormalList );
+ registerMethod( "LooksLike", PMPov31SerLooksLike );
+ registerMethod( "Material", PMPov31SerMaterial );
+ registerMethod( "MaterialMap", PMPov31SerMaterialMap );
+ registerMethod( "Media", PMPov31SerMedia );
+ registerMethod( "NamedObject", PMPov31SerNamedObject );
+ registerMethod( "Normal", PMPov31SerNormal );
+ registerMethod( "ObjectLink", PMPov31SerObjectLink );
+ registerMethod( "Pattern", PMPov31SerPattern );
+ registerMethod( "Pigment", PMPov31SerPigment );
+ registerMethod( "Plane", PMPov31SerPlane );
+ registerMethod( "Polynom", PMPov31SerPolynom );
+ registerMethod( "PovrayMatrix", PMPov31SerPovrayMatrix );
+ registerMethod( "Prism", PMPov31SerPrism );
+ registerMethod( "QuickColor", PMPov31SerQuickColor );
+ registerMethod( "Rainbow", PMPov31SerRainbow );
+ registerMethod( "Raw", PMPov31SerRaw );
+ registerMethod( "Rotate", PMPov31SerRotate );
+ registerMethod( "Scale", PMPov31SerScale );
+ registerMethod( "Scene", PMPov31SerScene );
+ registerMethod( "SkySphere", PMPov31SerSkySphere );
+ registerMethod( "Slope", PMPov31SerSlope );
+ registerMethod( "SolidColor", PMPov31SerSolidColor );
+ registerMethod( "SolidObject", PMPov31SerSolidObject );
+ registerMethod( "SurfaceOfRevolution", PMPov31SerSurfaceOfRevolution );
+ registerMethod( "Sphere", PMPov31SerSphere );
+ registerMethod( "SuperquadricEllipsoid", PMPov31SerSuperquadricEllipsoid );
+ registerMethod( "Text", PMPov31SerText );
+ registerMethod( "Texture", PMPov31SerTexture );
+ registerMethod( "TextureBase", PMPov31SerTextureBase );
+ registerMethod( "TextureMapBase", PMPov31SerTextureMapBase );
+ registerMethod( "TextureMap", PMPov31SerTextureMap );
+ registerMethod( "PigmentMap", PMPov31SerPigmentMap );
+ registerMethod( "ColorMap", PMPov31SerColorMap );
+ registerMethod( "NormalMap", PMPov31SerNormalMap );
+ registerMethod( "SlopeMap", PMPov31SerSlopeMap );
+ registerMethod( "DensityMap", PMPov31SerDensityMap );
+ registerMethod( "Torus", PMPov31SerTorus );
+ registerMethod( "Translate", PMPov31SerTranslate );
+ registerMethod( "Triangle", PMPov31SerTriangle );
+ registerMethod( "Warp", PMPov31SerWarp );
+ registerMethod( "DetailObject", PMPov31SerDetailObject );
+}
+
+
+PMPovray31Format::~PMPovray31Format( )
+{
+
+}
+
+PMParser* PMPovray31Format::newParser( PMPart* part, QIODevice* dev ) const
+{
+ return new PMPovrayParser( part, dev );
+}
+
+PMParser* PMPovray31Format::newParser( PMPart* part, const QByteArray& data ) const
+{
+ return new PMPovrayParser( part, data );
+}
+
+PMSerializer* PMPovray31Format::newSerializer( QIODevice* dev )
+{
+ return new PMOutputDevice( dev, this );
+}
+
+PMRenderer* PMPovray31Format::newRenderer( PMPart* ) const
+{
+ // TODO
+ return 0;
+}
+
+QString PMPovray31Format::mimeType( ) const
+{
+ return QString( "text/plain" );
+}
+
+QStringList PMPovray31Format::importPatterns( ) const
+{
+ QStringList result;
+ result.push_back( QString( "*.pov *.inc|" )
+ + i18n( "POV-Ray 3.1 Files (*.pov, *.inc)" ) );
+ return result;
+}
+
+QStringList PMPovray31Format::exportPatterns( ) const
+{
+ QStringList result;
+ result.push_back( QString( "*.pov|" ) + i18n( "POV-Ray 3.1 Files (*.pov)" ) );
+ result.push_back( QString( "*.ini|" ) + i18n( "POV-Ray 3.1 Include Files (*.ini)" ) );
+ return result;
+
+}
diff --git a/kpovmodeler/pmpovray31format.h b/kpovmodeler/pmpovray31format.h
new file mode 100644
index 00000000..a0e3453e
--- /dev/null
+++ b/kpovmodeler/pmpovray31format.h
@@ -0,0 +1,64 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMPOVRAY31_FORMAT_H
+#define PMPOVRAY31_FORMAT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmpovrayformat.h"
+
+/**
+ * Description class for POV-Ray 3.1
+ */
+class PMPovray31Format : public PMPovrayFormat
+{
+public:
+ /**
+ * Default constructor
+ */
+ PMPovray31Format( );
+ /**
+ * Destructor
+ */
+ virtual ~PMPovray31Format( );
+
+ /** */
+ virtual QString name( ) const { return "povray31"; };
+ /** */
+ virtual QString description( ) const { return "POV-Ray 3.1"; }
+ /** */
+ virtual int services( ) const { return AllServices; }
+ /** */
+ virtual PMParser* newParser( PMPart*, QIODevice* ) const;
+ /** */
+ virtual PMParser* newParser( PMPart*, const QByteArray& ) const;
+ /** */
+ virtual PMSerializer* newSerializer( QIODevice* );
+ /** */
+ virtual PMRenderer* newRenderer( PMPart* ) const;
+ /** */
+ virtual QString mimeType( ) const;
+ /** */
+ virtual QStringList importPatterns( ) const;
+ /** */
+ virtual QStringList exportPatterns( ) const;
+};
+
+#endif
diff --git a/kpovmodeler/pmpovray31serialization.cpp b/kpovmodeler/pmpovray31serialization.cpp
new file mode 100644
index 00000000..dd4b7603
--- /dev/null
+++ b/kpovmodeler/pmpovray31serialization.cpp
@@ -0,0 +1,2199 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmpovray31serialization.h"
+#include "pmoutputdevice.h"
+#include "pmallobjects.h"
+
+const double c_defaultPatchFlatness = 0;
+
+void PMPov31SerBicubicPatch( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMBicubicPatch* o = ( PMBicubicPatch* ) object;
+
+ int u, v;
+ QString str, line;
+ dev->objectBegin( "bicubic_patch" );
+
+ dev->writeName( object->name( ) );
+
+ str.setNum( o->patchType( ) );
+ dev->writeLine( "type " + str );
+ if( !approx( o->flatness( ), c_defaultPatchFlatness ) )
+ {
+ str.setNum( o->flatness( ) );
+ dev->writeLine( "flatness " + str );
+ }
+ str.setNum( o->uSteps( ) );
+ dev->writeLine( "u_steps " + str );
+ str.setNum( o->vSteps( ) );
+ dev->writeLine( "v_steps " + str );
+
+ for( v = 0; v < 4; v++ )
+ {
+ line = o->controlPoint( v*4 ).serialize( );
+ for( u = 1; u < 4; u++ )
+ line += QString( ", " ) + o->controlPoint( u+4*v ).serialize( );
+ if( v != 3 )
+ line += ",";
+ dev->writeLine( line );
+ }
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerBlendMapModifiers( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev )
+{
+ PMBlendMapModifiers* o = ( PMBlendMapModifiers* ) object;
+
+ QString str;
+
+ if( o->isFrequencyEnabled( ) )
+ {
+ str.setNum( o->frequency( ) );
+ dev->writeLine( "frequency " + str );
+ }
+
+ if( o->isPhaseEnabled( ) )
+ {
+ str.setNum( o->phase( ) );
+ dev->writeLine( "phase " + str );
+ }
+
+ if( o->isWaveFormEnabled( ) )
+ {
+ switch( o->waveFormType( ) )
+ {
+ case PMBlendMapModifiers::RampWave:
+ dev->writeLine( "ramp_wave" );
+ break;
+ case PMBlendMapModifiers::TriangleWave:
+ dev->writeLine( "triangle_wave" );
+ break;
+ case PMBlendMapModifiers::SineWave:
+ dev->writeLine( "sine_wave" );
+ break;
+ case PMBlendMapModifiers::ScallopWave:
+ dev->writeLine( "scallop_wave" );
+ break;
+ case PMBlendMapModifiers::CubicWave:
+ dev->writeLine( "cubic_wave" );
+ break;
+ case PMBlendMapModifiers::PolyWave:
+ str.setNum( o->waveFormExponent( ) );
+ dev->writeLine( "poly_wave " + str );
+ break;
+ }
+ }
+}
+
+void PMPov31SerBlob( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMBlob* o = ( PMBlob* ) object;
+
+ dev->objectBegin( "blob" );
+
+ dev->writeName( object->name( ) );
+ dev->writeLine( QString( "threshold %1" ).arg( o->threshold( ) ) );
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+
+ if( o->sturm( ) )
+ dev->writeLine( "sturm" );
+ if( o->hierarchy( ) )
+ dev->writeLine( "hierarchy" );
+
+ dev->objectEnd( );
+}
+
+void PMPov31SerBlobCylinder( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMBlobCylinder* o = ( PMBlobCylinder* ) object;
+
+ dev->objectBegin( "cylinder" );
+
+ dev->writeName( object->name( ) );
+ QString str1;
+ str1.setNum( o->radius( ) );
+ dev->writeLine( o->end1( ).serialize( ) + ", " + o->end2( ).serialize( )
+ + ", " + str1 + "," );
+ dev->writeLine( QString( "strength %1" ).arg( o->strength( ) ) );
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerBlobSphere( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMBlobSphere* o = ( PMBlobSphere* ) object;
+
+ dev->objectBegin( "sphere" );
+ dev->writeName( object->name( ) );
+ dev->writeLine( o->centre( ).serialize( ) + QString( ", %1," ).arg( o->radius( ) ) );
+ dev->writeLine( QString( "strength %1" ).arg( o->strength( ) ) );
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerBoundedBy( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMBoundedBy* o = ( PMBoundedBy* ) object;
+
+ dev->objectBegin( "bounded_by" );
+ if( o->clippedBy( ) )
+ dev->writeLine( "clipped_by" );
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerBox( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMBox* o = ( PMBox* ) object;
+
+ dev->objectBegin( "box" );
+
+ dev->writeName( object->name( ) );
+ dev->writeLine( o->corner1( ).serialize( ) + ", " + o->corner2( ).serialize( ) );
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerBumpMap( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev )
+{
+ PMBumpMap* o = ( PMBumpMap* ) object;
+
+ QString str1;
+
+ dev->objectBegin( "bump_map" );
+
+ switch( o->bitmapType( ) )
+ {
+ case PMBumpMap::BitmapGif:
+ dev->writeLine( "gif" );
+ break;
+ case PMBumpMap::BitmapTga:
+ dev->writeLine( "tga" );
+ break;
+ case PMBumpMap::BitmapIff:
+ dev->writeLine( "iff" );
+ break;
+ case PMBumpMap::BitmapPpm:
+ dev->writeLine( "ppm" );
+ break;
+ case PMBumpMap::BitmapPgm:
+ dev->writeLine( "pgm" );
+ break;
+ case PMBumpMap::BitmapPng:
+ dev->writeLine( "png" );
+ break;
+ case PMBumpMap::BitmapJpeg:
+ dev->writeLine( "jpeg" );
+ break;
+ case PMBumpMap::BitmapTiff:
+ dev->writeLine( "tiff" );
+ break;
+ case PMBumpMap::BitmapSys:
+ dev->writeLine( "sys" );
+ break;
+ }
+
+ dev->writeLine( "\"" + o->bitmapFile( ) + "\"" );
+
+ if( o->isOnceEnabled( ) )
+ dev->writeLine( "once" );
+
+ switch( o->mapType( ) )
+ {
+ case PMBumpMap::MapPlanar:
+ dev->writeLine( "map_type 0" );
+ break;
+ case PMBumpMap::MapSpherical:
+ dev->writeLine( "map_type 1" );
+ break;
+ case PMBumpMap::MapCylindrical:
+ dev->writeLine( "map_type 2" );
+ break;
+ case PMBumpMap::MapToroidal:
+ dev->writeLine( "map_type 5" );
+ break;
+ }
+ switch( o->interpolateType( ) )
+ {
+ case PMBumpMap::InterpolateBilinear:
+ dev->writeLine( "interpolate 2" );
+ break;
+ case PMBumpMap::InterpolateNormalized:
+ dev->writeLine( "interpolate 4" );
+ break;
+ default:
+ break;
+ }
+
+ if( o->isUseIndexEnabled( ) )
+ dev->writeLine( "use_index" );
+
+ if( o->bumpSize( ) )
+ {
+ str1.setNum( o->bumpSize( ) );
+ dev->writeLine( "bump_size " + str1 );
+ }
+
+ dev->objectEnd( );
+}
+
+void PMPov31SerCamera( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMCamera* o = ( PMCamera* ) object;
+
+ dev->objectBegin( "camera" );
+ QString str;
+
+ dev->writeName( object->name( ) );
+
+ if( o->cameraType( ) == PMCamera::Cylinder )
+ {
+ str.setNum( o->cylinderType( ) );
+ dev->writeLine( "cylinder " + str );
+ }
+ else
+ dev->writeLine( o->cameraTypeToString( o->cameraType( ) ) );
+
+ dev->writeLine( "location " + o->location( ).serialize( ) );
+ dev->writeLine( "sky " + o->sky( ).serialize( ) );
+ dev->writeLine( "direction " + o->direction( ).serialize( ) );
+ dev->writeLine( "right " + o->right( ).serialize( ) );
+ dev->writeLine( "up " + o->up( ).serialize( ) );
+ dev->writeLine( "look_at " + o->lookAt( ).serialize( ) );
+
+ if( ( o->cameraType( ) != PMCamera::Orthographic ) &&
+ ( o->cameraType( ) != PMCamera::Omnimax ) &&
+ ( o->cameraType( ) != PMCamera::Panoramic ) && o->isAngleEnabled( ) )
+ {
+ str.setNum( o->angle( ) );
+ dev->writeLine( "angle " + str );
+ }
+ if( o->isFocalBlurEnabled( ) && ( o->cameraType( ) == PMCamera::Perspective ) )
+ {
+ str.setNum( o->aperture( ) );
+ dev->writeLine( "aperture " + str );
+ str.setNum( o->blurSamples( ) );
+ dev->writeLine( "blur_samples " + str );
+ dev->writeLine( "focal_point " + o->focalPoint( ).serialize( ) );
+ str.setNum( o->confidence( ) );
+ dev->writeLine( "confidence " + str );
+ str.setNum( o->variance( ) );
+ dev->writeLine( "variance " + str );
+ }
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerClippedBy( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMClippedBy* o = ( PMClippedBy* ) object;
+
+ dev->objectBegin( "clipped_by" );
+ if( o->boundedBy( ) )
+ dev->writeLine( "bounded_by" );
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerComment( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev )
+{
+ PMComment* o = ( PMComment* ) object;
+
+ dev->writeComment( o->text( ) );
+}
+
+void PMPov31SerCompositeObject( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev )
+{
+ PMCompositeObject* o = ( PMCompositeObject* ) object;
+
+ PMObject* tmp;
+
+ for( tmp = o->firstChild( ); tmp; tmp = tmp->nextSibling( ) )
+ if( tmp->exportPovray( ) )
+ dev->serialize( tmp );
+}
+
+void PMPov31SerCone( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMCone* o = ( PMCone* ) object;
+
+ dev->objectBegin( "cone" );
+
+ dev->writeName( object->name( ) );
+ QString str1;
+ str1.setNum( o->radius1( ) );
+ dev->writeLine( o->end1( ).serialize( ) + ", " + str1 + "," );
+ str1.setNum( o->radius2( ) );
+ dev->writeLine( o->end2( ).serialize( ) + ", " + str1 );
+ if( o->open( ) )
+ dev->writeLine( QString( "open" ) );
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerCSG( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMCSG* o = ( PMCSG* ) object;
+
+ switch( o->csgType( ) )
+ {
+ case PMCSG::CSGUnion:
+ dev->objectBegin( "union" );
+ break;
+ case PMCSG::CSGIntersection:
+ dev->objectBegin( "intersection" );
+ break;
+ case PMCSG::CSGDifference:
+ dev->objectBegin( "difference" );
+ break;
+ case PMCSG::CSGMerge:
+ dev->objectBegin( "merge" );
+ break;
+ }
+
+ dev->writeName( object->name( ) );
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerCylinder( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMCylinder* o = ( PMCylinder* ) object;
+
+ dev->objectBegin( "cylinder" );
+
+ dev->writeName( object->name( ) );
+ QString str1;
+ str1.setNum( o->radius( ) );
+ dev->writeLine( o->end1( ).serialize( ) + ", " + o->end2( ).serialize( )
+ + ", " + str1 );
+ if( o->open( ) )
+ dev->writeLine( QString( "open" ) );
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerDeclare( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMDeclare* o = ( PMDeclare* ) object;
+
+ if( o->firstChild( ) )
+ {
+ dev->declareBegin( o->id( ) );
+ dev->callSerialization( object, metaObject->superClass( ) );
+ }
+}
+
+void PMPov31SerDensity( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ bool bObject = true;
+ if( object->parent( ) )
+ if( object->parent( )->type( ) == "DensityMap" )
+ bObject = false;
+
+ if( bObject )
+ dev->objectBegin( "density" );
+ dev->callSerialization( object, metaObject->superClass( ) );
+ if( bObject )
+ dev->objectEnd( );
+}
+
+void PMPov31SerDisc( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMDisc* o = ( PMDisc* ) object;
+
+ dev->objectBegin( "disc" );
+
+ dev->writeName( object->name( ) );
+ QString str1, str2;
+ str1.setNum( o->radius( ) );
+ if( o->radius( ) != 0.0 )
+ {
+ str2.setNum( o->holeRadius( ) );
+ dev->writeLine( o->center( ).serialize( ) + "," + o->normal( ).serialize( ) + ", " + str1 + "," + str2 );
+ }
+ else
+ {
+ dev->writeLine( o->center( ).serialize( ) + "," + o->normal( ).serialize( ) + ", " + str1 );
+ }
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerFinish( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMFinish* o = ( PMFinish* ) object;
+
+ QString str1;
+
+ dev->objectBegin( "finish" );
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+
+ if( o->isAmbientEnabled( ) )
+ dev->writeLine( "ambient " + o->ambientColor( ).serialize( ) );
+ if( o->isDiffuseEnabled( ) )
+ {
+ str1.setNum( o->diffuse( ) );
+ dev->writeLine( "diffuse " + str1 );
+ }
+ if( o->isBrillianceEnabled( ) )
+ {
+ str1.setNum( o->brilliance( ) );
+ dev->writeLine( "brilliance " + str1 );
+ }
+ if( o->isPhongEnabled( ) )
+ {
+ str1.setNum( o->phong( ) );
+ dev->writeLine( "phong " + str1 );
+ }
+ if( o->isPhongSizeEnabled( ) )
+ {
+ str1.setNum( o->phongSize( ) );
+ dev->writeLine( "phong_size " + str1 );
+ }
+ if( o->isMetallicEnabled( ) )
+ {
+ str1.setNum( o->metallic( ) );
+ dev->writeLine( "metallic " + str1 );
+ }
+ if( o->isSpecularEnabled( ) )
+ {
+ str1.setNum( o->specular( ) );
+ dev->writeLine( "specular " + str1 );
+ }
+ if( o->isRoughnessEnabled( ) )
+ {
+ str1.setNum( o->roughness( ) );
+ dev->writeLine( "roughness " + str1 );
+ }
+ if( o->isReflectionEnabled( ) )
+ {
+ dev->writeLine( "reflection " + o->reflectionColor( ).serialize( ) );
+ }
+ if( o->isExponentEnabled( ) )
+ {
+ str1.setNum( o->reflectionExponent( ) );
+ dev->writeLine( "reflection_exponent " + str1 );
+ }
+ if( o->irid( ) )
+ {
+ str1.setNum( o->iridAmount( ) );
+ dev->writeLine( "irid { " + str1 );
+ str1.setNum( o->iridThickness( ) );
+ dev->writeLine( "thickness " + str1 );
+ str1.setNum( o->iridTurbulence( ) );
+ dev->writeLine( "turbulence " + str1 + " } " );
+ }
+ if( o->isCrandEnabled( ) )
+ {
+ str1.setNum( o->crand( ) );
+ dev->writeLine( "crand " + str1 );
+ }
+ dev->objectEnd( );
+}
+
+const int c_defaultFogOctaves = 6;
+const double c_defaultFogLambda = 2.0;
+const double c_defaultFogOmega = 0.5;
+const double c_defaultFogTurbDepth = 0.5;
+
+void PMPov31SerFog( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev )
+{
+ PMFog* o = ( PMFog* ) object;
+
+ QString str;
+
+ dev->objectBegin( "fog" );
+
+ // Serialize the name of this object
+ dev->writeName( object->name( ) );
+
+ // Serialize a possible link
+ if( o->linkedObject( ) )
+ {
+ if( o->linkedObject( )->firstChild( ) )
+ dev->writeLine( o->linkedObject( )->id( ) );
+ else
+ {
+ QString text;
+ text = o->name( );
+ if( text.isEmpty( ) )
+ text = o->description( );
+
+ dev->writeComment( QString( "No prototype for %1" ).arg( text ) );
+ }
+ }
+
+ str.setNum( o->fogType( ) );
+ dev->writeLine( "fog_type " + str );
+
+ str.setNum( o->distance( ) );
+ dev->writeLine( "distance " + str );
+ dev->writeLine( " " + o->color( ).serialize( ) + " " );
+ if( o->isTurbulenceEnabled( ) )
+ {
+ dev->writeLine( "turbulence " + o->valueVector( ).serialize( ) );
+ if( o->octaves( ) != c_defaultFogOctaves )
+ {
+ str.setNum(o->octaves( ));
+ dev->writeLine( "octaves " + str );
+ }
+ if( o->omega( ) != c_defaultFogOmega )
+ {
+ str.setNum(o->omega( ));
+ dev->writeLine( "omega " + str );
+ }
+ if( o->lambda( ) != c_defaultFogLambda )
+ {
+ str.setNum(o->lambda( ));
+ dev->writeLine( "lambda " + str );
+ }
+ if( o->depth( ) != c_defaultFogTurbDepth )
+ {
+ str.setNum(o->depth( ));
+ dev->writeLine( "turb_depth " + str );
+ }
+ }
+ if( o->fogType( ) == 2 )
+ {
+ // Serialize ground fog variables
+ str.setNum( o->fogOffset( ) );
+ dev->writeLine( "fog_offset " + str );
+ str.setNum( o->fogAlt( ) );
+ dev->writeLine( "fog_alt " + str );
+ dev->writeLine( "up " + o->up( ).serialize( ) );
+ }
+ // Serialize the children of this object
+ dev->callSerialization( object, object->metaObject( )->superClass( )->superClass( ) );
+ dev->objectEnd( );
+}
+
+const double c_defaultGlobalSettingsAdcBailout = 1.0 / 255.0;
+const PMColor c_defaultGlobalSettingsAmbientLight = PMColor( 1.0, 1.0, 1.0, 0.0, 0.0 );
+const double c_defaultGlobalSettingsAssumedGamma = 0.0;
+const bool c_defaultGlobalSettingsHfGray16 = false;
+const PMColor c_defaultGlobalSettingsIridWaveLength = PMColor( 0.25, 0.18, 0.14, 0.0, 0.0 );
+const int c_defaultGlobalSettingsMaxIntersections = 0; // ???
+const int c_defaultGlobalSettingsMaxTraceLevel = 0; // ???
+const int c_defaultGlobalSettingsNumberWaves = 10;
+const bool c_defaultGlobalSettingsRadiosity = false;
+const double c_defaultGlobalSettingsBrightness = 1.0;
+const int c_defaultGlobalSettingsCount = 35;
+const double c_defaultGlobalSettingsDistanceMaximum = 0; // ???
+const double c_defaultGlobalSettingsErrorBound = 1.8;
+const double c_defaultGlobalSettingsGrayThreshold = 0.0;
+const double c_defaultGlobalSettingsLowErrorFactor = 0.5;
+const double c_defaultGlobalSettingsMinimumReuse = 0.015;
+const int c_defaultGlobalSettingsNearestCount = 5;
+const int c_defaultGlobalSettingsRecursionLimit = 2;
+
+void PMPov31SerGlobalSettings( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev )
+{
+ PMGlobalSettings* o = ( PMGlobalSettings* ) object;
+
+ QString str1;
+
+ dev->objectBegin( "global_settings" );
+
+ if( o->adcBailout( ) != c_defaultGlobalSettingsAdcBailout )
+ {
+ str1.setNum( o->adcBailout( ) );
+ dev->writeLine( "adc_bailout " + str1 );
+ }
+ if( o->ambientLight( ) != c_defaultGlobalSettingsAmbientLight )
+ dev->writeLine( "ambient_light " + o->ambientLight( ).serialize( ) );
+ if( o->assumedGamma( ) != c_defaultGlobalSettingsAssumedGamma )
+ {
+ str1.setNum( o->assumedGamma( ) );
+ dev->writeLine( "assumed_gamma " + str1 );
+ }
+ if( o->hfGray16( ) != c_defaultGlobalSettingsHfGray16 )
+ {
+ if( o->hfGray16( ) )
+ dev->writeLine( "hf_gray_16 on" );
+ else
+ dev->writeLine( "hf_gray_16 off" );
+ }
+ if( o->iridWaveLength( ) != c_defaultGlobalSettingsIridWaveLength )
+ dev->writeLine( "irid_wavelength " + o->iridWaveLength( ).serialize( ) );
+ if( o->maxTraceLevel( ) != c_defaultGlobalSettingsMaxTraceLevel )
+ {
+ str1.setNum( o->maxTraceLevel( ) );
+ dev->writeLine( "max_trace_level " + str1 );
+ }
+ if( o->maxIntersections( ) != c_defaultGlobalSettingsMaxIntersections )
+ {
+ str1.setNum( o->maxIntersections( ) );
+ dev->writeLine( "max_intersections " + str1 );
+ }
+ if( o->numberWaves( ) != c_defaultGlobalSettingsNumberWaves )
+ {
+ str1.setNum( o->numberWaves( ) );
+ dev->writeLine( "number_of_waves " + str1 );
+ }
+ if( o->isRadiosityEnabled( ) )
+ {
+ dev->objectBegin( "radiosity" );
+ if( o->brightness( ) != c_defaultGlobalSettingsBrightness )
+ {
+ str1.setNum( o->brightness( ) );
+ dev->writeLine( "brightness " + str1 );
+ }
+ if( o->count( ) != c_defaultGlobalSettingsCount )
+ {
+ str1.setNum( o->count( ) );
+ dev->writeLine( "count " + str1 );
+ }
+ if( o->distanceMaximum( ) != c_defaultGlobalSettingsDistanceMaximum )
+ {
+ str1.setNum( o->distanceMaximum( ) );
+ dev->writeLine( "distance_maximum " + str1 );
+ }
+ if( o->errorBound( ) != c_defaultGlobalSettingsErrorBound )
+ {
+ str1.setNum( o->errorBound( ) );
+ dev->writeLine( "error_bound " + str1 );
+ }
+ if( o->grayThreshold( ) != c_defaultGlobalSettingsGrayThreshold )
+ {
+ str1.setNum( o->grayThreshold( ) );
+ dev->writeLine( "gray_threshold " + str1 );
+ }
+ if( o->lowErrorFactor( ) != c_defaultGlobalSettingsLowErrorFactor )
+ {
+ str1.setNum( o->lowErrorFactor( ) );
+ dev->writeLine( "low_error_factor " + str1 );
+ }
+ if( o->minimumReuse( ) != c_defaultGlobalSettingsMinimumReuse )
+ {
+ str1.setNum( o->minimumReuse( ) );
+ dev->writeLine( "minimuo->reuse( ) " + str1 );
+ }
+ if( o->nearestCount( ) != c_defaultGlobalSettingsNearestCount )
+ {
+ str1.setNum( o->nearestCount( ) );
+ dev->writeLine( "nearest_count " + str1 );
+ }
+ if( o->recursionLimit( ) != c_defaultGlobalSettingsRecursionLimit )
+ {
+ str1.setNum( o->recursionLimit( ) );
+ dev->writeLine( "recursion_limit " + str1 );
+ }
+ dev->objectEnd( );
+ }
+ dev->objectEnd( );
+}
+
+void PMPov31SerGraphicalObject( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMGraphicalObject* o = ( PMGraphicalObject* ) object;
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ if( o->noShadow( ) )
+ dev->writeLine( "no_shadow" );
+}
+
+void PMPov31SerHeightField( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMHeightField* o = ( PMHeightField* ) object;
+
+ dev->objectBegin( "height_field" );
+
+ dev->writeName( object->name( ) );
+
+ dev->writeLine( o->typeToString( o->heightFieldType( ) ) + " \"" + o->fileName( ) + "\"" );
+ if( o->waterLevel( ) > 0.0 )
+ dev->writeLine( QString( "water_level %1" ).arg( o->waterLevel( ) ) );
+ if( !o->hierarchy( ) )
+ dev->writeLine( "hierarchy off" );
+ if( o->smooth( ) )
+ dev->writeLine( "smooth" );
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerImageMap( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev )
+{
+ PMImageMap* o = ( PMImageMap* ) object;
+
+ typedef QValueList<PMPaletteValue> PMPaletteValueList;
+ PMPaletteValueList values;
+ PMPaletteValueList::ConstIterator tmpPalette;
+ QString str1, str2;
+
+ dev->objectBegin( "image_map" );
+
+ switch( o->bitmapType( ) )
+ {
+ case PMImageMap::BitmapGif:
+ dev->writeLine( "gif" );
+ break;
+ case PMImageMap::BitmapTga:
+ dev->writeLine( "tga" );
+ break;
+ case PMImageMap::BitmapIff:
+ dev->writeLine( "iff" );
+ break;
+ case PMImageMap::BitmapPpm:
+ dev->writeLine( "ppm" );
+ break;
+ case PMImageMap::BitmapPgm:
+ dev->writeLine( "pgm" );
+ break;
+ case PMImageMap::BitmapPng:
+ dev->writeLine( "png" );
+ break;
+ case PMImageMap::BitmapJpeg:
+ dev->writeLine( "jpeg" );
+ break;
+ case PMImageMap::BitmapTiff:
+ dev->writeLine( "tiff" );
+ break;
+ case PMImageMap::BitmapSys:
+ dev->writeLine( "sys" );
+ break;
+ }
+
+ dev->writeLine( "\"" + o->bitmapFile( ) + "\"" );
+
+ values = o->filters( );
+ for( tmpPalette = values.begin( ); tmpPalette != values.end( ); ++tmpPalette )
+ {
+ str1.setNum( ( *tmpPalette ).index( ) );
+ str2.setNum( ( *tmpPalette ).value( ) );
+ dev->writeLine( "filter " + str1 + ", " + str2 );
+ }
+
+ values = o->transmits( );
+ for( tmpPalette = values.begin( ); tmpPalette != values.end( ); ++tmpPalette )
+ {
+ str1.setNum( ( *tmpPalette ).index( ) );
+ str2.setNum( ( *tmpPalette ).value( ) );
+ dev->writeLine( "transmit " + str1 + ", " + str2 );
+ }
+
+ if( o->isFilterAllEnabled( ) )
+ {
+ str1.setNum( o->filterAll( ) );
+ dev->writeLine( "filter all " + str1 );
+ }
+
+ if( o->isTransmitAllEnabled( ) )
+ {
+ str1.setNum( o->transmitAll( ) );
+ dev->writeLine( "transmit all " + str1 );
+ }
+
+ if( o->isOnceEnabled( ) )
+ dev->writeLine( "once" );
+
+ switch( o->mapType( ) )
+ {
+ case PMImageMap::MapPlanar:
+ dev->writeLine( "map_type 0" );
+ break;
+ case PMImageMap::MapSpherical:
+ dev->writeLine( "map_type 1" );
+ break;
+ case PMImageMap::MapCylindrical:
+ dev->writeLine( "map_type 2" );
+ break;
+ case PMImageMap::MapToroidal:
+ dev->writeLine( "map_type 5" );
+ break;
+ }
+ switch( o->interpolateType( ) )
+ {
+ case PMImageMap::InterpolateBilinear:
+ dev->writeLine( "interpolate 2" );
+ break;
+ case PMImageMap::InterpolateNormalized:
+ dev->writeLine( "interpolate 4" );
+ break;
+ default:
+ break;
+ }
+
+ dev->objectEnd( );
+}
+
+void PMPov31SerInterior( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMInterior* o = ( PMInterior* ) object;
+
+ QString str1;
+
+ dev->objectBegin( "interior" );
+ dev->callSerialization( object, metaObject->superClass( ) );
+
+ if( o->isIorEnabled( ) )
+ {
+ str1.setNum( o->ior( ) );
+ dev->writeLine( "ior " + str1 );
+ }
+ if( o->isCausticsEnabled( ) )
+ {
+ str1.setNum( o->caustics( ) );
+ dev->writeLine( "caustics " + str1 );
+ }
+ if( o->isFadeDistanceEnabled( ) )
+ {
+ str1.setNum( o->fadeDistance( ) );
+ dev->writeLine( "fade_distance " + str1 );
+ }
+ if( o->isFadeDistanceEnabled( ) )
+ {
+ str1.setNum( o->fadeDistance( ) );
+ dev->writeLine( "fade_distance " + str1 );
+ }
+ dev->objectEnd( );
+}
+
+void PMPov31SerJuliaFractal( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMJuliaFractal* o = ( PMJuliaFractal* ) object;
+
+ dev->objectBegin( "julia_fractal" );
+
+ dev->writeName( object->name( ) );
+ dev->writeLine( o->juliaParameter( ).serialize( ) );
+ dev->writeLine( o->algebraTypeToString( o->algebraType( ) ) );
+
+ if( o->functionType( ) == PMJuliaFractal::FTpwr )
+ dev->writeLine( QString( "pwr(%1, %2)" ).arg( o->exponent( )[0] ).
+ arg( o->exponent( )[1] ) );
+ else
+ dev->writeLine( o->functionTypeToString( o->functionType( ) ) );
+
+ dev->writeLine( QString( "max_iteration %1" ).arg( o->maximumIterations( ) ) );
+ dev->writeLine( QString( "precision %1" ).arg( o->precision( ) ) );
+ dev->writeLine( QString( "slice %1, %2" ).arg( o->sliceNormal( ).serialize( ) )
+ .arg( o->sliceDistance( ) ) );
+
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerLathe( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMLathe* o = ( PMLathe* ) object;
+
+ dev->objectBegin( "lathe" );
+
+ dev->writeName( object->name( ) );
+
+ switch( o->splineType( ) )
+ {
+ case PMLathe::LinearSpline:
+ dev->writeLine( "linear_spline" );
+ break;
+ case PMLathe::QuadraticSpline:
+ dev->writeLine( "quadratic_spline" );
+ break;
+ case PMLathe::CubicSpline:
+ dev->writeLine( "cubic_spline" );
+ break;
+ case PMLathe::BezierSpline:
+ dev->writeLine( "bezier_spline" );
+ break;
+ }
+
+ int num = o->points( ).count( );
+ dev->writeLine( QString( "%1," ).arg( num ) );
+
+ bool first = true;
+ QValueList<PMVector> points = o->points( );
+ QValueList<PMVector>::ConstIterator it = points.begin( );
+ for( ; it != points.end( ); ++it )
+ {
+ if( !first )
+ dev->write( ", " );
+ dev->write( ( *it ).serialize( ) );
+ first = false;
+ }
+ dev->writeLine( "" );
+
+ if( o->sturm( ) )
+ dev->writeLine( "sturm" );
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+const double c_defaultLightTightness = 10;
+const int c_defaultLightAdaptive = 0;
+
+void PMPov31SerLight( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMLight* o = ( PMLight* ) object;
+
+ dev->objectBegin( QString( "light_source" ) );
+
+ dev->writeName( object->name( ) );
+ dev->writeLine( o->location( ).serialize( ) + ", " + o->color( ).serialize( ) );
+
+ if( o->lightType( ) == PMLight::SpotLight )
+ dev->writeLine( QString( "spotlight" ) );
+ else if( o->lightType( ) == PMLight::CylinderLight )
+ dev->writeLine( QString( "cylinder" ) );
+ else if( o->lightType( ) == PMLight::ShadowlessLight )
+ dev->writeLine( QString( "shadowless" ) );
+
+ if( ( o->lightType( ) == PMLight::SpotLight ) ||
+ ( o->lightType( ) == PMLight::CylinderLight ) )
+ {
+ dev->writeLine( QString( "radius %1" ).arg( o->radius( ) ) );
+ dev->writeLine( QString( "falloff %1" ).arg( o->falloff( ) ) );
+ if( o->tightness( ) != c_defaultLightTightness )
+ dev->writeLine( QString( "tightness %1" ).arg( o->tightness( ) ) );
+ dev->writeLine( QString( "point_at " ) + o->pointAt( ).serialize( ) );
+ }
+
+ if( o->isAreaLight( ) )
+ {
+ dev->writeLine( QString( "area_light " ) + o->axis1( ).serialize( )
+ + QString( ", " ) + o->axis2( ).serialize( )
+ + QString( ", %1, %2" ).arg( o->size1( ) ).arg( o->size2( ) ) );
+ if( o->adaptive( ) != c_defaultLightAdaptive )
+ dev->writeLine( QString( "adaptive %1" ).arg( o->adaptive( ) ) );
+ if( o->jitter( ) )
+ dev->writeLine( QString( "jitter" ) );
+ }
+
+ if( o->fading( ) )
+ {
+ dev->writeLine( QString( "fade_distance %1" ).arg( o->fadeDistance( ) ) );
+ dev->writeLine( QString( "fade_power %1" ).arg( o->fadePower( ) ) );
+ }
+
+ if( !o->mediaInteraction( ) )
+ dev->writeLine( QString( "media_interaction off" ) );
+ if( !o->mediaAttenuation( ) )
+ dev->writeLine( QString( "media_attenuation off" ) );
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerListPattern( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMListPattern* o = ( PMListPattern* ) object;
+
+ QString str1;
+
+ switch( o->listType( ) )
+ {
+ case PMListPattern::ListPatternBrick:
+ dev->writeLine( "brick" );
+ break;
+ case PMListPattern::ListPatternChecker:
+ dev->writeLine( "checker " );
+ break;
+ case PMListPattern::ListPatternHexagon:
+ dev->writeLine( "hexagon " );
+ break;
+ }
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+
+ if( o->listType( ) == PMListPattern::ListPatternBrick )
+ {
+ dev->writeLine( "brick_size " +
+ o->brickSize( ).serialize( ) );
+ str1.setNum( o->mortar( ) );
+ dev->writeLine( "mortar " + str1 );
+ }
+}
+
+void PMPov31SerTextureList( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ dev->callSerialization( object, metaObject->superClass( ) );
+}
+
+void PMPov31SerPigmentList( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ dev->callSerialization( object, metaObject->superClass( ) );
+}
+
+void PMPov31SerColorList( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ dev->callSerialization( object, metaObject->superClass( ) );
+}
+
+void PMPov31SerDensityList( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ dev->callSerialization( object, metaObject->superClass( ) );
+}
+
+void PMPov31SerNormalList( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev )
+{
+ PMNormalList* o = ( PMNormalList* ) object;
+
+ QString str1;
+
+ switch( o->listType( ) )
+ {
+ case PMNormalList::ListPatternBrick:
+ dev->writeLine( "brick " );
+ break;
+ case PMNormalList::ListPatternChecker:
+ dev->writeLine( "checker " );
+ break;
+ case PMNormalList::ListPatternHexagon:
+ dev->writeLine( "hexagon " );
+ break;
+ }
+ if( o->depth( ) )
+ {
+ str1.setNum( o->depth( ) );
+ dev->writeLine( str1 );
+ }
+ if( o->listType( ) == PMNormalList::ListPatternBrick )
+ {
+ dev->writeLine( "brick_size " +
+ o->brickSize( ).serialize( ) );
+ str1.setNum( o->mortar( ) );
+ dev->writeLine( "mortar " + str1 );
+ }
+}
+
+void PMPov31SerLooksLike( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ dev->objectBegin( "looks_like" );
+ dev->writeName( object->name( ) );
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerMaterial( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ dev->objectBegin( "material" );
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerMaterialMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMMaterialMap* o = ( PMMaterialMap* ) object;
+
+ QString str1;
+
+ dev->objectBegin( "material_map" );
+
+ switch( o->bitmapType( ) )
+ {
+ case PMMaterialMap::BitmapGif:
+ dev->writeLine( "gif" );
+ break;
+ case PMMaterialMap::BitmapTga:
+ dev->writeLine( "tga" );
+ break;
+ case PMMaterialMap::BitmapIff:
+ dev->writeLine( "iff" );
+ break;
+ case PMMaterialMap::BitmapPpm:
+ dev->writeLine( "ppm" );
+ break;
+ case PMMaterialMap::BitmapPgm:
+ dev->writeLine( "pgm" );
+ break;
+ case PMMaterialMap::BitmapPng:
+ dev->writeLine( "png" );
+ break;
+ case PMMaterialMap::BitmapJpeg:
+ dev->writeLine( "jpeg" );
+ break;
+ case PMMaterialMap::BitmapTiff:
+ dev->writeLine( "tiff" );
+ break;
+ case PMMaterialMap::BitmapSys:
+ dev->writeLine( "sys" );
+ break;
+ }
+
+ dev->writeLine( "\"" + o->bitmapFile( ) + "\"" );
+
+ if( o->isOnceEnabled( ) )
+ dev->writeLine( "once" );
+
+ switch( o->mapType( ) )
+ {
+ case PMMaterialMap::MapPlanar:
+ dev->writeLine( "map_type 0" );
+ break;
+ case PMMaterialMap::MapSpherical:
+ dev->writeLine( "map_type 1" );
+ break;
+ case PMMaterialMap::MapCylindrical:
+ dev->writeLine( "map_type 2" );
+ break;
+ case PMMaterialMap::MapToroidal:
+ dev->writeLine( "map_type 5" );
+ break;
+ }
+ switch( o->interpolateType( ) )
+ {
+ case PMMaterialMap::InterpolateBilinear:
+ dev->writeLine( "interpolate 2" );
+ break;
+ case PMMaterialMap::InterpolateNormalized:
+ dev->writeLine( "interpolate 4" );
+ break;
+ default:
+ break;
+ }
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+
+ dev->objectEnd( );
+}
+
+const int c_defaultMediaIntervals = 10;
+const int c_defaultMediaSamplesMin = 1;
+const int c_defaultMediaSamplesMax = 1;
+const double c_defaultMediaConfidence = 0.9;
+const double c_defaultMediaVariance = 0.0078125;
+const double c_defaultMediaRatio = 0.9;
+const double c_defaultMediaScatteringEccentricity = 0;
+const double c_defaultMediaScatteringExtinction = 1.0;
+
+void PMPov31SerMedia( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMMedia* o = ( PMMedia* ) object;
+
+ QString str1;
+ QString str2;
+
+ dev->objectBegin( "media" );
+ dev->callSerialization( object, metaObject->superClass( ) );
+ if( o->intervals( ) != c_defaultMediaIntervals )
+ {
+ str1.setNum( o->intervals( ) );
+ dev->writeLine( "intervals " + str1 );
+ }
+ if( o->samplesMin( ) != c_defaultMediaSamplesMin ||
+ o->samplesMax( ) != c_defaultMediaSamplesMax )
+ {
+ str1.setNum( o->samplesMin( ) );
+ str2.setNum( o->samplesMax( ) );
+ dev->writeLine( "samples " + str1 + "," + str2 );
+ }
+ if( o->confidence( ) != c_defaultMediaConfidence )
+ {
+ str1.setNum( o->confidence( ) );
+ dev->writeLine( "confidence " + str1 );
+ }
+ if( o->variance( ) != c_defaultMediaVariance )
+ {
+ str1.setNum( o->variance( ) );
+ dev->writeLine( "variance " + str1 );
+ }
+ if( o->ratio( ) != c_defaultMediaRatio )
+ {
+ str1.setNum( o->ratio( ) );
+ dev->writeLine( "ratio " + str1 );
+ }
+ if( o->isAbsorptionEnabled( ) )
+ {
+ dev->writeLine( "absorption " + o->absorption( ).serialize( ) );
+ }
+ if( o->isEmissionEnabled( ) )
+ {
+ dev->writeLine( "emission " + o->emission( ).serialize( ) );
+ }
+ if( o->isScatteringEnabled( ) )
+ {
+ dev->objectBegin( "scattering" );
+ str1.setNum( o->scatteringType( ) );
+ dev->writeLine( str1 + ", " + o->scatteringColor( ).serialize( ) );
+ if( o->scatteringType( ) == 5 && o->scatteringEccentricity( )
+ != c_defaultMediaScatteringEccentricity )
+ {
+ str1.setNum( o->scatteringEccentricity( ) );
+ dev->writeLine( "eccentricity " + str1 );
+ }
+ if( o->scatteringExtinction( ) != c_defaultMediaScatteringExtinction )
+ {
+ str1.setNum( o->scatteringExtinction( ) );
+ dev->writeLine( "extinction " + str1 );
+ }
+ dev->objectEnd( );
+ }
+ dev->objectEnd( );
+}
+
+void PMPov31SerNamedObject( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ dev->callSerialization( object, metaObject->superClass( ) );
+}
+
+void PMPov31SerNormal( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMNormal* o = ( PMNormal* ) object;
+
+ QString str1;
+ bool bObject = true;
+
+ if( o->parent( ) )
+ if( o->parent( )->type( ) == "NormalMap" )
+ bObject = false;
+
+ if( bObject )
+ dev->objectBegin( "normal" );
+ dev->callSerialization( object, metaObject->superClass( ) );
+ if( o->isBumpSizeEnabled( ) )
+ {
+ str1.setNum( o->bumpSize( ) );
+ dev->writeLine( "bump_size " + str1 );
+ }
+ if( bObject )
+ dev->objectEnd( );
+}
+
+void PMPov31SerObjectLink( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMObjectLink* o = ( PMObjectLink* ) object;
+
+ bool writeComment = true;
+ if( o->linkedObject( ) )
+ {
+ if( o->linkedObject( )->firstChild( ) )
+ {
+ dev->objectBegin( "object" );
+
+ dev->writeName( object->name( ) );
+ dev->writeLine( o->linkedObject( )->id( ) );
+ dev->callSerialization( object, metaObject->superClass( ) );
+ writeComment = false;
+
+ dev->objectEnd( );
+ }
+ }
+ if( writeComment )
+ {
+ QString text;
+ text = o->name( );
+ if( text.isEmpty( ) )
+ text = o->description( );
+
+ dev->writeComment( QString( "No prototype for %1" ).arg( text ) );
+ }
+}
+
+const int c_defaultPatternOctaves = 6;
+const double c_defaultPatternOmega = 0.5;
+const double c_defaultPatternLambda = 2.0;
+
+void PMPov31SerPattern( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev )
+{
+ PMPattern* o = ( PMPattern* ) object;
+
+ QString str;
+
+ // pattern type
+ switch( o->patternType( ) )
+ {
+ case PMPattern::PatternAgate:
+ dev->writeLine( "agate" );
+ break;
+ case PMPattern::PatternAverage:
+ dev->writeLine( "average" );
+ break;
+ case PMPattern::PatternBoxed:
+ dev->writeLine( "boxed" );
+ break;
+ case PMPattern::PatternBozo:
+ dev->writeLine( "bozo" );
+ break;
+ case PMPattern::PatternBumps:
+ dev->writeLine( "bumps" );
+ break;
+ case PMPattern::PatternCrackle:
+ dev->writeLine( "crackle" );
+ break;
+ case PMPattern::PatternCylindrical:
+ dev->writeLine( "cylindrical" );
+ break;
+ case PMPattern::PatternDensity:
+ dev->writeLine( "density_file df3 \"" + o->densityFile( ) + "\"");
+ break;
+ case PMPattern::PatternDents:
+ dev->writeLine( "dents" );
+ break;
+ case PMPattern::PatternGradient:
+ dev->writeLine( "gradient " + o->gradient( ).serialize( ) );
+ break;
+ case PMPattern::PatternGranite:
+ dev->writeLine( "granite" );
+ break;
+ case PMPattern::PatternLeopard:
+ dev->writeLine( "leopard" );
+ break;
+ case PMPattern::PatternMandel:
+ str.setNum( o->maxIterations( ) );
+ dev->writeLine( "mandel " + str );
+ break;
+ case PMPattern::PatternMarble:
+ dev->writeLine( "marble" );
+ break;
+ case PMPattern::PatternOnion:
+ dev->writeLine( "onion" );
+ break;
+ case PMPattern::PatternPlanar:
+ dev->writeLine( "planar" );
+ break;
+ case PMPattern::PatternQuilted:
+ dev->writeLine( "quilted" );
+ break;
+ case PMPattern::PatternRadial:
+ dev->writeLine( "radial" );
+ break;
+ case PMPattern::PatternRipples:
+ dev->writeLine( "ripples" );
+ break;
+ case PMPattern::PatternSpherical:
+ dev->writeLine( "spherical" );
+ break;
+ case PMPattern::PatternSpiral1:
+ str.setNum( o->spiralNumberArms( ) );
+ dev->writeLine( "spiral1 " + str );
+ break;
+ case PMPattern::PatternSpiral2:
+ str.setNum( o->spiralNumberArms( ) );
+ dev->writeLine( "spiral2 " + str );
+ break;
+ case PMPattern::PatternSpotted:
+ dev->writeLine( "spotted" );
+ break;
+ case PMPattern::PatternWaves:
+ dev->writeLine( "waves" );
+ break;
+ case PMPattern::PatternWood:
+ dev->writeLine( "wood" );
+ break;
+ case PMPattern::PatternWrinkles:
+ dev->writeLine( "wrinkles" );
+ break;
+ default:
+ break;
+ }
+ // depth
+ if( o->parent( ) )
+ {
+ if( o->depth( ) && o->parent( )->type( ) == "Normal" )
+ {
+ str.setNum( o->depth( ) );
+ dev->writeLine( str );
+ }
+ }
+ // modifiers
+ switch( o->patternType( ) )
+ {
+ case PMPattern::PatternAgate:
+ str.setNum( o->agateTurbulence( ) );
+ dev->writeLine( "agate_turb " + str );
+ break;
+ case PMPattern::PatternDensity:
+ str.setNum( o->densityInterpolate( ) );
+ dev->writeLine( "interpolate " + str );
+ break;
+ case PMPattern::PatternQuilted:
+ str.setNum( o->quiltControl0( ) );
+ dev->writeLine( "control0 " + str );
+ str.setNum( o->quiltControl1( ) );
+ dev->writeLine( "control1 " + str );
+ break;
+ default:
+ break;
+ }
+ if( o->isTurbulenceEnabled( ) )
+ {
+ dev->writeLine( "turbulence " + o->valueVector( ).serialize( ) );
+ if( o->octaves( ) != c_defaultPatternOctaves )
+ {
+ str.setNum( o->octaves( ) );
+ dev->writeLine( "octaves " + str );
+ }
+ if( o->omega( ) != c_defaultPatternOmega )
+ {
+ str.setNum( o->omega( ) );
+ dev->writeLine( "omega " + str );
+ }
+ if( o->lambda( ) != c_defaultPatternLambda )
+ {
+ str.setNum( o->lambda( ) );
+ dev->writeLine( "lambda " + str );
+ }
+ }
+}
+
+void PMPov31SerPigment( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMPigment* o = ( PMPigment* ) object;
+
+ bool bObject = true;
+ if( o->parent( ) )
+ if( o->parent( )->type( ) == "PigmentMap" )
+ bObject = false;
+
+ if( bObject )
+ dev->objectBegin( "pigment" );
+ dev->callSerialization( object, metaObject->superClass( ) );
+ if( bObject )
+ dev->objectEnd( );
+}
+
+void PMPov31SerPlane( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMPlane* o = ( PMPlane* ) object;
+
+ dev->objectBegin( "plane" );
+
+ dev->writeName( object->name( ) );
+ QString str1;
+ str1.setNum( o->distance( ) );
+ dev->writeLine( o->normal( ).serialize( ) + ", " + str1 );
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerPolynom( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMPolynom* o = ( PMPolynom* ) object;
+ PMVector coefficients = o->coefficients( );
+
+ if( o->polynomOrder( ) == 2 )
+ dev->objectBegin( "quadric" );
+ else if( o->polynomOrder( ) == 3 )
+ dev->objectBegin( "cubic" );
+ else if( o->polynomOrder( ) == 4 )
+ dev->objectBegin( "quartic" );
+ else
+ dev->objectBegin( "poly" );
+
+ dev->writeName( object->name( ) );
+
+ if( o->polynomOrder( ) == 2 )
+ {
+ dev->writeLine( QString( "<%1, %2, %3>," ).arg( coefficients[0] )
+ .arg( coefficients[4] ).arg( coefficients[7] ) );
+ dev->writeLine( QString( "<%1, %2, %3>," ).arg( coefficients[1] )
+ .arg( coefficients[2] ).arg( coefficients[5] ) );
+ dev->writeLine( QString( "<%1, %2, %3>, %4" ).arg( coefficients[3] )
+ .arg( coefficients[6] ).arg( coefficients[8] )
+ .arg( coefficients[9] ) );
+ }
+ else
+ {
+ if( o->polynomOrder( ) > 4 )
+ dev->writeLine( QString( "%1," ).arg( o->polynomOrder( ) ) );
+
+ int size = coefficients.size( );
+
+ int i;
+ QString hlp;
+
+ dev->write( "<" );
+ for( i = 0; i < size; i++ )
+ {
+ hlp.setNum( coefficients[i] );
+ dev->write( hlp );
+
+ if( i != ( size - 1 ) )
+ {
+ dev->write( ", " );
+ if( ( ( i + 1 ) % 5 ) == 0 )
+ dev->writeLine( "" );
+ }
+ }
+ dev->writeLine( ">" );
+ if( o->sturm( ) )
+ dev->writeLine( "sturm" );
+ }
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerPovrayMatrix( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev )
+{
+ PMPovrayMatrix* o = ( PMPovrayMatrix* ) object;
+
+ dev->writeLine( QString( "matrix < %1, %2, %3," ).arg( o->values( )[0] )
+ .arg( o->values( )[1] ).arg( o->values( )[2] ) );
+ dev->writeLine( QString( " %1, %2, %3," ).arg( o->values( )[3] )
+ .arg( o->values( )[4] ).arg( o->values( )[5] ) );
+ dev->writeLine( QString( " %1, %2, %3," ).arg( o->values( )[6] )
+ .arg( o->values( )[7] ).arg( o->values( )[8] ) );
+ dev->writeLine( QString( " %1, %2, %3 >" ).arg( o->values( )[9] )
+ .arg( o->values( )[10] ).arg( o->values( )[11] ) );
+}
+
+void PMPov31SerPrism( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMPrism* o = ( PMPrism* ) object;
+
+ dev->objectBegin( "prism" );
+
+ dev->writeName( object->name( ) );
+
+ switch( o->splineType( ) )
+ {
+ case PMPrism::LinearSpline:
+ dev->writeLine( "linear_spline" );
+ break;
+ case PMPrism::QuadraticSpline:
+ dev->writeLine( "quadratic_spline" );
+ break;
+ case PMPrism::CubicSpline:
+ dev->writeLine( "cubic_spline" );
+ break;
+ case PMPrism::BezierSpline:
+ dev->writeLine( "bezier_spline" );
+ break;
+ }
+ switch( o->sweepType( ) )
+ {
+ case PMPrism::LinearSweep:
+ dev->writeLine( "linear_sweep" );
+ break;
+ case PMPrism::ConicSweep:
+ dev->writeLine( "conic_sweep" );
+ break;
+ }
+ dev->writeLine( QString( "%1, %2," ).arg( o->height1( ) ).arg( o->height2( ) ) );
+
+ // count number of points
+ QValueList< QValueList<PMVector> > points = o->points( );
+ QValueList< QValueList<PMVector> >::ConstIterator spit = points.begin( );
+ int lines = 0;
+ for( ; spit != points.end( ); ++spit )
+ {
+ if( o->splineType( ) != PMPrism::BezierSpline )
+ lines += ( *spit ).count( ) + 1;
+ else
+ lines += ( *spit ).count( ) / 3 * 4;
+ }
+ dev->writeLine( QString( "%1," ).arg( lines ) );
+
+ for( spit = points.begin( ); spit != points.end( ); ++spit )
+ {
+ bool first = true;
+
+ QValueList<PMVector> fullPoints = o->expandedPoints( *spit );
+ QValueList<PMVector>::ConstIterator it = fullPoints.begin( );
+
+ for( ; it != fullPoints.end( ); ++it )
+ {
+ if( !first )
+ dev->write( ", " );
+ dev->write( ( *it ).serialize( ) );
+ first = false;
+ }
+ QValueList< QValueList<PMVector> >::ConstIterator spit2 = spit;
+ spit2++;
+ if( spit2 != points.end( ) )
+ dev->write( "," );
+ dev->writeLine( "" );
+ }
+
+ if( o->open( ) )
+ dev->writeLine( "open" );
+ if( o->sturm( ) )
+ dev->writeLine( "sturm" );
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerQuickColor( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev )
+{
+ PMQuickColor* o = ( PMQuickColor* ) object;
+
+ dev->writeLine( "quick_color " + o->color( ).serialize( ) );
+}
+
+void PMPov31SerRainbow( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMRainbow* o = ( PMRainbow* ) object;
+
+ QString str1;
+
+ dev->objectBegin( "rainbow" );
+ dev->callSerialization( object, metaObject->superClass( ) );
+
+ if( o->isDirectionEnabled( ) )
+ dev->writeLine( "direction " + o->direction( ).serialize( ) );
+ if( o->isAngleEnabled( ) )
+ {
+ str1.setNum( o->angle( ) );
+ dev->writeLine( "angle " + str1 );
+ }
+ if( o->isWidthEnabled( ) )
+ {
+ str1.setNum( o->width( ) );
+ dev->writeLine( "width " + str1 );
+ }
+ if( o->isDistanceEnabled( ) )
+ {
+ str1.setNum( o->distance( ) );
+ dev->writeLine( "distance " + str1 );
+ }
+ if( o->isJitterEnabled( ) )
+ {
+ str1.setNum( o->jitter( ) );
+ dev->writeLine( "jitter " + str1 );
+ }
+ if( o->isUpEnabled( ) )
+ dev->writeLine( "up " + o->up( ).serialize( ) );
+ if( o->isArcAngleEnabled( ) )
+ {
+ str1.setNum( o->arcAngle( ) );
+ dev->writeLine( "arc_angle " + str1 );
+ }
+ if( o->isFalloffAngleEnabled( ) )
+ {
+ str1.setNum( o->falloffAngle( ) );
+ dev->writeLine( "falloff_angle " + str1 );
+ }
+ dev->objectEnd( );
+}
+
+void PMPov31SerRaw( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev )
+{
+ PMRaw* o = ( PMRaw* ) object;
+
+ dev->writeLine( "//*PMRawBegin" );
+
+ QString tmp = o->code( );
+ QTextStream str( &tmp, IO_ReadOnly );
+ while( !str.atEnd( ) )
+ dev->writeLine( str.readLine( ) );
+
+ dev->writeLine( "//*PMRawEnd" );
+}
+
+void PMPov31SerRotate( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev )
+{
+ PMRotate* o = ( PMRotate* ) object;
+ PMVector rotate = o->rotation( );
+
+ QString vector;
+ QTextStream str( &vector, IO_WriteOnly );
+ int i;
+ bool z[3];
+
+ for( i = 0; i < 3; i++ )
+ z[i] = approxZero( rotate[i] );
+ if( !z[0] && z[1] && z[2] )
+ {
+ str << "x*";
+ i = 0;
+ }
+ else if( z[0] && !z[1] && z[2] )
+ {
+ str << "y*";
+ i = 1;
+ }
+ else if( z[0] && z[1] && !z[2] )
+ {
+ str << "z*";
+ i = 2;
+ }
+
+ if( i < 3 )
+ {
+ if( rotate[i] > 0 )
+ str << rotate[i];
+ else
+ str << "(" << rotate[i] << ")";
+ }
+ else
+ {
+ str << '<';
+ for( i = 0; i < 3; i++ )
+ {
+ if( i > 0 )
+ str << ", ";
+ str << rotate[i];
+ }
+ str << '>';
+ }
+
+ dev->writeLine( "rotate " + vector );
+}
+
+void PMPov31SerScale( const PMObject* object, const PMMetaObject* , PMOutputDevice* dev )
+{
+ PMScale* o = ( PMScale* ) object;
+ PMVector scale = o->scale( );
+
+ if( approx( scale[0], scale[1] ) &&
+ approx( scale[1], scale[2] ) )
+ dev->writeLine( QString( "scale %1" ).arg( scale[0] ) );
+ else
+ dev->writeLine( "scale " + scale.serialize( ) );
+}
+
+void PMPov31SerScene( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ dev->callSerialization( object, metaObject->superClass( ) );
+}
+
+void PMPov31SerSkySphere( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ dev->objectBegin( "sky_sphere" );
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerSlope( const PMObject* object, const PMMetaObject* , PMOutputDevice* dev )
+{
+ PMSlope* o = ( PMSlope* ) object;
+
+ QString str1,str2;
+
+ str1.setNum(o->height( ));
+ str2.setNum(o->slope( ));
+
+ dev->writeLine( "<" + str1 + ", " + str2 + ">" );
+}
+
+void PMPov31SerSolidColor( const PMObject* object, const PMMetaObject* , PMOutputDevice* dev )
+{
+ PMSolidColor* o = ( PMSolidColor* ) object;
+
+ dev->writeLine( o->color( ).serialize( true ) );
+}
+
+void PMPov31SerSolidObject( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMSolidObject* o = ( PMSolidObject* ) object;
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ switch( o->hollow( ) )
+ {
+ case PMTrue:
+ dev->writeLine( "hollow" );
+ break;
+ case PMFalse:
+ dev->writeLine( "hollow false" );
+ break;
+ case PMUnspecified:
+ break;
+ }
+ if( o->inverse( ) )
+ dev->writeLine( "inverse" );
+}
+
+void PMPov31SerSurfaceOfRevolution( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMSurfaceOfRevolution* o = ( PMSurfaceOfRevolution* ) object;
+
+ dev->objectBegin( "sor" );
+
+ dev->writeName( object->name( ) );
+
+ int num = o->points( ).count( );
+ dev->writeLine( QString( "%1," ).arg( num ) );
+
+ bool first = true;
+ QValueList<PMVector> points = o->points( );
+ QValueList<PMVector>::ConstIterator it = points.begin( );
+ for( ; it != points.end( ); ++it )
+ {
+ if( !first )
+ dev->write( ", " );
+ dev->write( ( *it ).serialize( ) );
+ first = false;
+ }
+ dev->writeLine( "" );
+
+ if( o->open( ) )
+ dev->writeLine( "open" );
+ if( o->sturm( ) )
+ dev->writeLine( "sturm" );
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerSphere( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMSphere* o = ( PMSphere* ) object;
+
+ dev->objectBegin( "sphere" );
+ dev->writeName( object->name( ) );
+ QString str;
+ str.setNum( o->radius( ) );
+ dev->writeLine( o->centre( ).serialize( ) + ", " + str );
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerSuperquadricEllipsoid( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMSuperquadricEllipsoid* o = ( PMSuperquadricEllipsoid* ) object;
+
+ dev->objectBegin( "superellipsoid" );
+
+ dev->writeName( object->name( ) );
+ dev->writeLine( QString( "<%1, %2>" ).arg( o->eastWestExponent( ) )
+ .arg( o->northSouthExponent( ) ) );
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerText( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMText* o = ( PMText* ) object;
+
+ dev->objectBegin( "text" );
+
+ dev->writeName( object->name( ) );
+ dev->writeLine( QString( "ttf \"" ) + o->font( ) + "\"" );
+ dev->writeLine( PMOutputDevice::escapeAndQuoteString( o->text( ) ) );
+ dev->writeLine( QString( "%1, " ).arg( o->thickness( ) )
+ + o->offset( ).serialize( ) );
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerTexture( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMTexture* o = ( PMTexture* ) object;
+
+ bool bObject = true;
+ if( o->parent( ) )
+ if( o->parent( )->type( ) == "TextureMap" )
+ bObject = false;
+
+ if( bObject )
+ dev->objectBegin( "texture" );
+ dev->callSerialization( object, metaObject->superClass( ) );
+ if( bObject )
+ dev->objectEnd( );
+}
+
+void PMPov31SerTextureBase( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMTextureBase* o = ( PMTextureBase* ) object;
+
+ dev->writeName( object->name( ) );
+
+ PMDeclare* linkedObject = o->linkedObject( );
+
+ if( linkedObject)
+ {
+ if( linkedObject->firstChild( ) )
+ dev->writeLine( linkedObject->id( ) );
+ else
+ {
+ QString text;
+ text = o->name( );
+ if( text.isEmpty( ) )
+ text = o->description( );
+
+ dev->writeComment( QString( "No prototype for %1" ).arg( text ) );
+ }
+ }
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+}
+
+void PMPov31SerTextureMapBase( const PMObject* object, const PMMetaObject* , PMOutputDevice* dev )
+{
+ PMTextureMapBase* o = ( PMTextureMapBase* ) object;
+
+ QValueList<double> mapValues = o->mapValues( );
+ QValueList<double>::ConstIterator it = mapValues.begin( );
+ PMObject* c = o->firstChild( );
+ double value = 0.0;
+
+ /* Take care of a possible link */
+ if( o->linkedObject( ) )
+ {
+ if( o->linkedObject( )->firstChild( ) )
+ dev->writeLine( o->linkedObject( )->id( ) );
+ else
+ {
+ QString text;
+ text = o->name( );
+ if( text.isEmpty( ) )
+ text = o->description( );
+
+ dev->writeComment( QString( "No prototype for %1" ).arg( text ) );
+ }
+ }
+
+ /* Serialize the map */
+ for( ; c; c = c->nextSibling( ) )
+ {
+ if( c->type( ) == o->mapType( ) )
+ {
+ value = 1.0;
+ if( it != mapValues.end( ) )
+ value = *it;
+ dev->write( QString( "[ %1 " ).arg( value ) );
+ dev->serialize( c );
+ dev->writeLine( "]" );
+ ++it;
+ }
+ }
+}
+
+void PMPov31SerTextureMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ dev->objectBegin( "texture_map" );
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerPigmentMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ dev->objectBegin( "pigment_map" );
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerColorMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ dev->objectBegin( "color_map" );
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerNormalMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ dev->objectBegin( "normal_map" );
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerSlopeMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ dev->objectBegin( "slope_map" );
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerDensityMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ dev->objectBegin( "density_map" );
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerTorus( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMTorus* o = ( PMTorus* ) object;
+
+ dev->objectBegin( "torus" );
+ dev->writeName( object->name( ) );
+ QString strMinor;
+ QString strMajor;
+ strMinor.setNum( o->minorRadius( ) );
+ strMajor.setNum( o->majorRadius( ) );
+
+ dev->writeLine(strMajor + ", " + strMinor);
+ if( o->sturm( ) )
+ dev->writeLine( QString( "sturm" ) );
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov31SerTranslate( const PMObject* object, const PMMetaObject* , PMOutputDevice* dev )
+{
+ PMTranslate* o = ( PMTranslate* ) object;
+
+ QString vector;
+ QTextStream str( &vector, IO_WriteOnly );
+ int i;
+ bool z[3];
+ PMVector move = o->translation( );
+
+ for( i = 0; i < 3; i++ )
+ z[i] = approxZero( move[i] );
+ if( !z[0] && z[1] && z[2] )
+ {
+ str << "x*";
+ i = 0;
+ }
+ else if( z[0] && !z[1] && z[2] )
+ {
+ str << "y*";
+ i = 1;
+ }
+ else if( z[0] && z[1] && !z[2] )
+ {
+ str << "z*";
+ i = 2;
+ }
+
+ if( i < 3 )
+ {
+ if( move[i] > 0 )
+ str << move[i];
+ else
+ str << "(" << move[i] << ")";
+ }
+ else
+ {
+ str << '<';
+ for( i = 0; i < 3; i++ )
+ {
+ if( i > 0 )
+ str << ", ";
+ str << move[i];
+ }
+ str << '>';
+ }
+
+ dev->writeLine( "translate " + vector );
+}
+
+void PMPov31SerTriangle( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMTriangle* o = ( PMTriangle* ) object;
+
+ if( o->isSmoothTriangle( ) )
+ {
+ dev->objectBegin( "smooth_triangle" );
+
+ dev->writeName( object->name( ) );
+ dev->writeLine( o->point( 0 ).serialize( ) + ", " + o->normal( 0 ).serialize( ) + "," );
+ dev->writeLine( o->point( 1 ).serialize( ) + ", " + o->normal( 1 ).serialize( ) + "," );
+ dev->writeLine( o->point( 2 ).serialize( ) + ", " + o->normal( 2 ).serialize( ) );
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+ }
+ else
+ {
+ dev->objectBegin( "triangle" );
+
+ dev->writeName( object->name( ) );
+ dev->writeLine( o->point( 0 ).serialize( ) + ", " + o->point( 1 ).serialize( )
+ + ", " + o->point( 2 ).serialize( ) );
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+ }
+}
+
+
+const PMVector c_warpDirectionDefault = PMVector( 1.0, 0.0, 0.0 );
+const PMVector c_warpOffsetDefault = PMVector( 0.0, 0.0, 0.0 );
+const PMVector c_warpFlipDefault = PMVector( 0.0, 0.0, 0.0 );
+const PMVector c_warpLocationDefault = PMVector( 0.0, 0.0, 0.0 );
+const double c_warpRadiusDefault = 0;
+const double c_warpStrengthDefault = 0;
+const double c_warpFalloffDefault = 0;
+const bool c_warpInverseDefault = false;
+const PMVector c_warpRepeatDefault = PMVector( 0.0, 0.0, 0.0 );
+const PMVector c_warpTurbulenceDefault = PMVector( 0.0, 0.0, 0.0 );
+const PMVector c_warpValueVectorDefault = PMVector( 0.0, 0.0, 0.0 );
+const int c_warpOctavesDefault = 6;
+const double c_warpOmegaDefault = 0.5;
+const double c_warpLambdaDefault = 2.0;
+
+void PMPov31SerWarp( const PMObject* object, const PMMetaObject* , PMOutputDevice* dev )
+{
+ PMWarp* o = ( PMWarp* ) object;
+
+ QString str1;
+
+ dev->objectBegin( "warp" );
+ switch( o->warpType( ) )
+ {
+ case PMWarp::Repeat:
+ dev->writeLine( "repeat" );
+ dev->writeLine( o->direction( ).serialize( ) );
+ dev->writeLine( "offset " + o->offset( ).serialize( ) );
+ dev->writeLine( "flip " + o->flip( ).serialize( ) );
+ break;
+ case PMWarp::BlackHole:
+ dev->writeLine( "black_hole" );
+ dev->writeLine( o->location( ).serialize( ) );
+ str1.setNum(o->radius( ));
+ dev->writeLine( ", " + str1 );
+ if( o->strength( ) != c_warpStrengthDefault )
+ {
+ str1.setNum( o->strength( ));
+ dev->writeLine( "strength " + str1 );
+ }
+ if( o->falloff( ) != c_warpFalloffDefault )
+ {
+ str1.setNum( o->falloff( ));
+ dev->writeLine( "falloff " + str1 );
+ }
+ if( o->inverse( ) != c_warpInverseDefault )
+ {
+ if( o->inverse( ) ) dev->writeLine( "inverse" );
+ }
+ if( o->repeat( ) != c_warpRepeatDefault )
+ {
+ dev->writeLine( "repeat " + o->repeat( ).serialize( ) );
+ }
+ if( o->turbulence( ) != c_warpTurbulenceDefault )
+ {
+ dev->writeLine( "turbulence " + o->turbulence( ).serialize( ) );
+ }
+ break;
+ case PMWarp::Turbulence:
+ dev->writeLine( "turbulence " + o->valueVector( ).serialize( ) );
+ if( o->octaves( ) != c_warpOctavesDefault )
+ {
+ str1.setNum(o->octaves( ));
+ dev->writeLine( "octaves " + str1 );
+ }
+ if( o->omega( ) != c_warpOmegaDefault )
+ {
+ str1.setNum( o->omega( ) );
+ dev->writeLine( "omega " + str1 );
+ }
+ if( o->lambda( ) != c_warpLambdaDefault )
+ {
+ str1.setNum( o->lambda( ) );
+ dev->writeLine( "lambda " + str1 );
+ }
+ break;
+ default:
+ break;
+ }
+ dev->objectEnd( );
+}
+
+void PMPov31SerDetailObject( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ dev->callSerialization( object, metaObject->superClass( ) );
+}
diff --git a/kpovmodeler/pmpovray31serialization.h b/kpovmodeler/pmpovray31serialization.h
new file mode 100644
index 00000000..5c48c0cd
--- /dev/null
+++ b/kpovmodeler/pmpovray31serialization.h
@@ -0,0 +1,103 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMPOVRAY31_SERIALIZATION_H
+#define PMPOVRAY31_SERIALIZATION_H
+
+class PMObject;
+class PMMetaObject;
+class PMOutputDevice;
+
+// serialization methods for POV-Ray 3.1
+
+void PMPov31SerBicubicPatch( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerBlendMapModifiers( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerBlob( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerBlobCylinder( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerBlobSphere( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerBoundedBy( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerBox( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerBumpMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerCamera( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerClippedBy( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerComment( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerCompositeObject( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerCone( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerCSG( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerCylinder( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerDeclare( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerDensity( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerDisc( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerFinish( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerFog( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerGlobalSettings( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerGraphicalObject( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerHeightField( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerImageMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerInterior( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerJuliaFractal( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerLathe( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerLight( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerListPattern( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerTextureList( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerPigmentList( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerColorList( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerDensityList( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerNormalList( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerLooksLike( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerMaterial( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerMaterialMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerMedia( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerNamedObject( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerNormal( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerObjectLink( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerPattern( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerPigment( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerPlane( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerPolynom( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerPovrayMatrix( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerPrism( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerQuickColor( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerRainbow( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerRaw( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerRotate( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerScale( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerScene( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerSkySphere( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerSlope( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerSolidColor( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerSolidObject( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerSurfaceOfRevolution( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerSphere( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerSuperquadricEllipsoid( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerText( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerTexture( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerTextureBase( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerTextureMapBase( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerTextureMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerPigmentMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerColorMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerNormalMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerSlopeMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerDensityMap( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerTorus( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerTranslate( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerTriangle( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerWarp( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov31SerDetailObject( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+
+#endif
diff --git a/kpovmodeler/pmpovray35format.cpp b/kpovmodeler/pmpovray35format.cpp
new file mode 100644
index 00000000..c00b1d65
--- /dev/null
+++ b/kpovmodeler/pmpovray35format.cpp
@@ -0,0 +1,100 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmpovray35format.h"
+#include "pmpovray35serialization.h"
+
+#include "pmpovrayparser.h"
+#include "pmoutputdevice.h"
+
+#include <klocale.h>
+
+PMPovray35Format::PMPovray35Format( )
+ : PMPovray31Format( )
+{
+ registerMethod( "IsoSurface", PMPov35SerIsoSurface );
+ registerMethod( "Light", PMPov35SerLight );
+ registerMethod( "ProjectedThrough", PMPov35SerProjectedThrough );
+ registerMethod( "GlobalSettings", PMPov35SerGlobalSettings );
+ registerMethod( "Radiosity", PMPov35SerRadiosity );
+ registerMethod( "GlobalPhotons", PMPov35SerGlobalPhotons );
+ registerMethod( "Photons", PMPov35SerPhotons );
+ registerMethod( "Interior", PMPov35SerInterior );
+ registerMethod( "LightGroup", PMPov35SerLightGroup );
+ registerMethod( "Pattern", PMPov35SerPattern );
+ registerMethod( "Normal", PMPov35SerNormal );
+ registerMethod( "InteriorTexture", PMPov35SerInteriorTexture );
+ registerMethod( "Warp", PMPov35SerWarp );
+ registerMethod( "SphereSweep", PMPov35SerSphereSweep );
+ registerMethod( "Finish", PMPov35SerFinish );
+ registerMethod( "Mesh", PMPov35SerMesh );
+ registerMethod( "Media", PMPov35SerMedia );
+ registerMethod( "GraphicalObject", PMPov35SerGraphicalObject );
+ registerMethod( "Pigment", PMPov35SerPigment );
+ registerMethod( "Texture", PMPov35SerTexture );
+ registerMethod( "BicubicPatch", PMPov35SerBicubicPatch );
+ registerMethod( "Triangle", PMPov35SerTriangle );
+}
+
+
+PMPovray35Format::~PMPovray35Format( )
+{
+
+}
+
+PMParser* PMPovray35Format::newParser( PMPart* part, QIODevice* dev ) const
+{
+ return new PMPovrayParser( part, dev );
+}
+
+PMParser* PMPovray35Format::newParser( PMPart* part, const QByteArray& data ) const
+{
+ return new PMPovrayParser( part, data );
+}
+
+PMSerializer* PMPovray35Format::newSerializer( QIODevice* dev )
+{
+ return new PMOutputDevice( dev, this );
+}
+
+PMRenderer* PMPovray35Format::newRenderer( PMPart* ) const
+{
+ // TODO
+ return 0;
+}
+
+QString PMPovray35Format::mimeType( ) const
+{
+ return QString( "text/plain" );
+}
+
+QStringList PMPovray35Format::importPatterns( ) const
+{
+ QStringList result;
+ result.push_back( QString( "*.pov *.inc|" )
+ + i18n( "POV-Ray 3.5 Files (*.pov, *.inc)" ) );
+ return result;
+}
+
+QStringList PMPovray35Format::exportPatterns( ) const
+{
+ QStringList result;
+ result.push_back( QString( "*.pov|" ) + i18n( "POV-Ray 3.5 Files (*.pov)" ) );
+ result.push_back( QString( "*.ini|" ) + i18n( "POV-Ray 3.5 Include Files (*.ini)" ) );
+ return result;
+
+}
diff --git a/kpovmodeler/pmpovray35format.h b/kpovmodeler/pmpovray35format.h
new file mode 100644
index 00000000..117d0375
--- /dev/null
+++ b/kpovmodeler/pmpovray35format.h
@@ -0,0 +1,64 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMPOVRAY35_FORMAT_H
+#define PMPOVRAY35_FORMAT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmpovray31format.h"
+
+/**
+ * Description class for POV-Ray 3.5
+ */
+class PMPovray35Format : public PMPovray31Format
+{
+public:
+ /**
+ * Default constructor
+ */
+ PMPovray35Format( );
+ /**
+ * Destructor
+ */
+ virtual ~PMPovray35Format( );
+
+ /** */
+ virtual QString name( ) const { return "povray35"; };
+ /** */
+ virtual QString description( ) const { return "POV-Ray 3.5"; }
+ /** */
+ virtual int services( ) const { return AllServices; }
+ /** */
+ virtual PMParser* newParser( PMPart*, QIODevice* ) const;
+ /** */
+ virtual PMParser* newParser( PMPart*, const QByteArray& ) const;
+ /** */
+ virtual PMSerializer* newSerializer( QIODevice* );
+ /** */
+ virtual PMRenderer* newRenderer( PMPart* ) const;
+ /** */
+ virtual QString mimeType( ) const;
+ /** */
+ virtual QStringList importPatterns( ) const;
+ /** */
+ virtual QStringList exportPatterns( ) const;
+};
+
+#endif
diff --git a/kpovmodeler/pmpovray35serialization.cpp b/kpovmodeler/pmpovray35serialization.cpp
new file mode 100644
index 00000000..2c3a88e0
--- /dev/null
+++ b/kpovmodeler/pmpovray35serialization.cpp
@@ -0,0 +1,1471 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmpovray35serialization.h"
+#include "pmoutputdevice.h"
+
+#include "pmisosurface.h"
+#include "pmlight.h"
+#include "pmprojectedthrough.h"
+#include "pmglobalsettings.h"
+#include "pmradiosity.h"
+#include "pmglobalphotons.h"
+#include "pmphotons.h"
+#include "pminterior.h"
+#include "pmlightgroup.h"
+#include "pmpattern.h"
+#include "pmnormal.h"
+#include "pminteriortexture.h"
+#include "pmwarp.h"
+#include "pmspheresweep.h"
+#include "pmfinish.h"
+#include "pmmesh.h"
+#include "pmmedia.h"
+#include "pmgraphicalobject.h"
+#include "pmpigment.h"
+#include "pmtexture.h"
+#include "pmbicubicpatch.h"
+#include "pmtriangle.h"
+
+const PMIsoSurface::ContainedByType c_defaultIsoContainedBy = PMIsoSurface::Box;
+const PMVector c_defaultIsoCorner1 = PMVector( -1, -1, -1 );
+const PMVector c_defaultIsoCorner2 = PMVector( 1, 1, 1 );
+const PMVector c_defaultIsoCenter = PMVector( 0, 0, 0 );
+const double c_defaultIsoRadius = 1;
+
+const double c_defaultIsoThreshold = 0.0;
+const double c_defaultIsoAccuracy = 0.001;
+const double c_defaultIsoMaxGradient = 1.1;
+const bool c_defaultIsoEvaluate = false;
+const double c_defaultIsoEvaluate0 = 5;
+const double c_defaultIsoEvaluate1 = 1.2;
+const double c_defaultIsoEvaluate2 = 0.95;
+const double c_defaultIsoOpen = false;
+const int c_defaultIsoMaxTrace = 1;
+const bool c_defaultIsoAllIntersections = false;
+
+void PMPov35SerIsoSurface( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMIsoSurface* o = ( PMIsoSurface* ) object;
+ QString str;
+
+ dev->objectBegin( "isosurface" );
+ dev->writeName( object->name( ) );
+
+ if( o->containedBy( ) == PMIsoSurface::Box )
+ {
+ dev->writeLine( QString( "function { " ) + o->function( ) + " }" );
+
+ if( o->corner1( ) != c_defaultIsoCorner1 ||
+ o->corner2( ) != c_defaultIsoCorner2 )
+ {
+ dev->writeLine( QString( "contained_by { box { " ) +
+ o->corner1( ).serialize( ) + ", " +
+ o->corner2( ).serialize( ) + " } }" );
+ }
+ }
+ else
+ {
+ str.setNum( o->radius( ) );
+ dev->writeLine( QString( "contained_by { sphere { " ) +
+ o->center( ).serialize( ) + ", " + str + " } }" );
+ }
+
+ if( !approx( o->threshold( ), c_defaultIsoThreshold ) )
+ {
+ str.setNum( o->threshold( ) );
+ dev->writeLine( "threshold " + str );
+ }
+ if( !approx( o->accuracy( ), c_defaultIsoAccuracy ) )
+ {
+ str.setNum( o->accuracy( ) );
+ dev->writeLine( "accuracy " + str );
+ }
+ if( !approx( o->maxGradient( ), c_defaultIsoMaxGradient ) )
+ {
+ str.setNum( o->maxGradient( ) );
+ dev->writeLine( "max_gradient " + str );
+ }
+ if( o->evaluate( ) )
+ {
+ str = QString( "%1, %2, %3" ).arg( o->evaluateValue( 0 ) )
+ .arg( o->evaluateValue( 1 ) ).arg( o->evaluateValue( 2 ) );
+ dev->writeLine( "evaluate " + str );
+ }
+ if( o->allIntersections( ) )
+ dev->writeLine( "all_intersections" );
+ else
+ {
+ str.setNum( o->maxTrace( ) );
+ dev->writeLine( "max_trace " + str );
+ }
+ if( o->open( ) )
+ dev->writeLine( "open" );
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+const double c_defaultLightTightness = 10;
+const int c_defaultLightAdaptive = 0;
+
+void PMPov35SerLight( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMLight* o = ( PMLight* ) object;
+
+ dev->objectBegin( QString( "light_source" ) );
+
+ dev->writeName( object->name( ) );
+ dev->writeLine( o->location( ).serialize( ) + ", " + o->color( ).serialize( ) );
+
+ if( o->lightType( ) == PMLight::SpotLight )
+ dev->writeLine( QString( "spotlight" ) );
+ else if( o->lightType( ) == PMLight::CylinderLight )
+ dev->writeLine( QString( "cylinder" ) );
+ else if( o->lightType( ) == PMLight::ShadowlessLight )
+ dev->writeLine( QString( "shadowless" ) );
+
+ if( o->parallel( ) )
+ dev->writeLine( QString( "parallel" ) );
+
+ if( ( o->lightType( ) == PMLight::SpotLight ) ||
+ ( o->lightType( ) == PMLight::CylinderLight ) )
+ {
+ dev->writeLine( QString( "radius %1" ).arg( o->radius( ) ) );
+ dev->writeLine( QString( "falloff %1" ).arg( o->falloff( ) ) );
+ if( o->tightness( ) != c_defaultLightTightness )
+ dev->writeLine( QString( "tightness %1" ).arg( o->tightness( ) ) );
+ dev->writeLine( QString( "point_at " ) + o->pointAt( ).serialize( ) );
+ }
+
+ if( o->isAreaLight( ) )
+ {
+ dev->writeLine( QString( "area_light " ) + o->axis1( ).serialize( )
+ + QString( ", " ) + o->axis2( ).serialize( )
+ + QString( ", %1, %2" ).arg( o->size1( ) ).arg( o->size2( ) ) );
+ if( o->adaptive( ) != c_defaultLightAdaptive )
+ dev->writeLine( QString( "adaptive %1" ).arg( o->adaptive( ) ) );
+ if( o->jitter( ) )
+ dev->writeLine( QString( "jitter" ) );
+ if ( o->areaType( ) == PMLight::Circular )
+ dev->writeLine( QString( "circular" ) );
+ if ( o->orient( ) )
+ dev->writeLine( QString( "orient" ) );
+ }
+
+ if( o->fading( ) )
+ {
+ dev->writeLine( QString( "fade_distance %1" ).arg( o->fadeDistance( ) ) );
+ dev->writeLine( QString( "fade_power %1" ).arg( o->fadePower( ) ) );
+ }
+
+ if( !o->mediaInteraction( ) )
+ dev->writeLine( QString( "media_interaction off" ) );
+ if( !o->mediaAttenuation( ) )
+ dev->writeLine( QString( "media_attenuation off" ) );
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov35SerProjectedThrough( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ dev->objectBegin( "projected_through" );
+ dev->writeName( object->name( ) );
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+const double c_defaultGlobalSettingsAdcBailout = 1.0 / 255.0;
+const PMColor c_defaultGlobalSettingsAmbientLight = PMColor( 1.0, 1.0, 1.0, 0.0, 0.0 );
+const double c_defaultGlobalSettingsAssumedGamma = 0.0;
+const bool c_defaultGlobalSettingsHfGray16 = false;
+const PMColor c_defaultGlobalSettingsIridWaveLength = PMColor( 0.25, 0.18, 0.14, 0.0, 0.0 );
+const int c_defaultGlobalSettingsMaxIntersections = 0; // ???
+const int c_defaultGlobalSettingsMaxTraceLevel = 0; // ???
+const int c_defaultGlobalSettingsNumberWaves = 10;
+const bool c_defaultGlobalSettingsRadiosity = false;
+const double c_defaultGlobalSettingsBrightness = 1.0;
+const int c_defaultGlobalSettingsCount = 35;
+const double c_defaultGlobalSettingsDistanceMaximum = 0; // ???
+const double c_defaultGlobalSettingsErrorBound = 1.8;
+const double c_defaultGlobalSettingsGrayThreshold = 0.0;
+const double c_defaultGlobalSettingsLowErrorFactor = 0.5;
+const double c_defaultGlobalSettingsMinimumReuse = 0.015;
+const int c_defaultGlobalSettingsNearestCount = 5;
+const int c_defaultGlobalSettingsRecursionLimit = 2;
+
+void PMPov35SerGlobalSettings( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMGlobalSettings* o = ( PMGlobalSettings* ) object;
+
+ QString str1;
+
+ dev->objectBegin( "global_settings" );
+
+ if( o->adcBailout( ) != c_defaultGlobalSettingsAdcBailout )
+ {
+ str1.setNum( o->adcBailout( ) );
+ dev->writeLine( "adc_bailout " + str1 );
+ }
+ if( o->ambientLight( ) != c_defaultGlobalSettingsAmbientLight )
+ dev->writeLine( "ambient_light " + o->ambientLight( ).serialize( ) );
+ if( o->assumedGamma( ) != c_defaultGlobalSettingsAssumedGamma )
+ {
+ str1.setNum( o->assumedGamma( ) );
+ dev->writeLine( "assumed_gamma " + str1 );
+ }
+ if( o->hfGray16( ) != c_defaultGlobalSettingsHfGray16 )
+ {
+ if( o->hfGray16( ) )
+ dev->writeLine( "hf_gray_16 on" );
+ else
+ dev->writeLine( "hf_gray_16 off" );
+ }
+ if( o->iridWaveLength( ) != c_defaultGlobalSettingsIridWaveLength )
+ dev->writeLine( "irid_wavelength " + o->iridWaveLength( ).serialize( ) );
+ if( o->maxTraceLevel( ) != c_defaultGlobalSettingsMaxTraceLevel )
+ {
+ str1.setNum( o->maxTraceLevel( ) );
+ dev->writeLine( "max_trace_level " + str1 );
+ }
+ if( o->maxIntersections( ) != c_defaultGlobalSettingsMaxIntersections )
+ {
+ str1.setNum( o->maxIntersections( ) );
+ dev->writeLine( "max_intersections " + str1 );
+ }
+ if( o->numberWaves( ) != c_defaultGlobalSettingsNumberWaves )
+ {
+ str1.setNum( o->numberWaves( ) );
+ dev->writeLine( "number_of_waves " + str1 );
+ }
+ if ( o->noiseGenerator( ) == PMGlobalSettings::Original )
+ dev->writeLine( QString( "noise_generator 1" ) );
+ else if ( o->noiseGenerator( ) == PMGlobalSettings::RangeCorrected )
+ dev->writeLine( QString( "noise_generator 2" ) );
+ else
+ dev->writeLine( QString( "noise_generator 3" ) );
+ if( o->isRadiosityEnabled( ) )
+ {
+ dev->objectBegin( "radiosity" );
+ if( o->brightness( ) != c_defaultGlobalSettingsBrightness )
+ {
+ str1.setNum( o->brightness( ) );
+ dev->writeLine( "brightness " + str1 );
+ }
+ if( o->count( ) != c_defaultGlobalSettingsCount )
+ {
+ str1.setNum( o->count( ) );
+ dev->writeLine( "count " + str1 );
+ }
+ if( o->distanceMaximum( ) != c_defaultGlobalSettingsDistanceMaximum )
+ {
+ str1.setNum( o->distanceMaximum( ) );
+ dev->writeLine( "distance_maximum " + str1 );
+ }
+ if( o->errorBound( ) != c_defaultGlobalSettingsErrorBound )
+ {
+ str1.setNum( o->errorBound( ) );
+ dev->writeLine( "error_bound " + str1 );
+ }
+ if( o->grayThreshold( ) != c_defaultGlobalSettingsGrayThreshold )
+ {
+ str1.setNum( o->grayThreshold( ) );
+ dev->writeLine( "gray_threshold " + str1 );
+ }
+ if( o->lowErrorFactor( ) != c_defaultGlobalSettingsLowErrorFactor )
+ {
+ str1.setNum( o->lowErrorFactor( ) );
+ dev->writeLine( "low_error_factor " + str1 );
+ }
+ if( o->minimumReuse( ) != c_defaultGlobalSettingsMinimumReuse )
+ {
+ str1.setNum( o->minimumReuse( ) );
+ dev->writeLine( "minimuo->reuse( ) " + str1 );
+ }
+ if( o->nearestCount( ) != c_defaultGlobalSettingsNearestCount )
+ {
+ str1.setNum( o->nearestCount( ) );
+ dev->writeLine( "nearest_count " + str1 );
+ }
+ if( o->recursionLimit( ) != c_defaultGlobalSettingsRecursionLimit )
+ {
+ str1.setNum( o->recursionLimit( ) );
+ dev->writeLine( "recursion_limit " + str1 );
+ }
+ dev->objectEnd( );
+ }
+ else
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+const double c_defaultRadiosityAdcBailout = 0.01;
+const double c_defaultRadiosityBrightness = 1.0;
+const int c_defaultRadiosityCount = 35;
+const double c_defaultRadiosityErrorBound = 1.8;
+const double c_defaultRadiosityGrayThreshold = 0.0;
+const double c_defaultRadiosityLowErrorFactor = 0.5;
+const double c_defaultRadiosityMaxSample = -1.0;
+const double c_defaultRadiosityMinimumReuse = 0.015;
+const int c_defaultRadiosityNearestCount = 5;
+const double c_defaultRadiosityPretraceStart = 0.08;
+const double c_defaultRadiosityPretraceEnd = 0.04;
+const int c_defaultRadiosityRecursionLimit = 2;
+
+void PMPov35SerRadiosity( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev )
+{
+ PMRadiosity* o = ( PMRadiosity* ) object;
+
+ QString str1;
+
+ dev->objectBegin( "radiosity" );
+
+ if( o->adcBailout( ) != c_defaultRadiosityAdcBailout )
+ {
+ str1.setNum( o->adcBailout( ) );
+ dev->writeLine( "adc_bailout " + str1 );
+ }
+
+ if( !o->alwaysSample( ) )
+ dev->writeLine( "always_sample off" );
+
+ if( o->brightness( ) != c_defaultRadiosityBrightness )
+ {
+ str1.setNum( o->brightness( ) );
+ dev->writeLine( "brightness " + str1 );
+ }
+
+ if( o->count( ) != c_defaultRadiosityCount )
+ {
+ str1.setNum( o->count( ) );
+ dev->writeLine( "count " + str1 );
+ }
+
+ if( o->errorBound( ) != c_defaultRadiosityErrorBound )
+ {
+ str1.setNum( o->errorBound( ) );
+ dev->writeLine( "error_bound " + str1 );
+ }
+
+ if( o->grayThreshold( ) != c_defaultRadiosityGrayThreshold )
+ {
+ str1.setNum( o->grayThreshold( ) );
+ dev->writeLine( "gray_threshold " + str1 );
+ }
+
+ if( o->lowErrorFactor( ) != c_defaultRadiosityLowErrorFactor )
+ {
+ str1.setNum( o->lowErrorFactor( ) );
+ dev->writeLine( "low_error_factor " + str1 );
+ }
+
+ if( o->maxSample( ) != c_defaultRadiosityMaxSample )
+ {
+ str1.setNum( o->maxSample( ) );
+ dev->writeLine( "max_sample " + str1 );
+ }
+
+ if( o->media( ) )
+ dev->writeLine( "media on" );
+
+ if( o->minimumReuse( ) != c_defaultRadiosityMinimumReuse )
+ {
+ str1.setNum( o->minimumReuse( ) );
+ dev->writeLine( "minimum_reuse " + str1 );
+ }
+ if( o->nearestCount( ) != c_defaultRadiosityNearestCount )
+ {
+ str1.setNum( o->nearestCount( ) );
+ dev->writeLine( "nearest_count " + str1 );
+ }
+
+ if( o->normal( ) )
+ dev->writeLine( "normal on" );
+
+ if( o->pretraceStart( ) != c_defaultRadiosityPretraceStart )
+ {
+ str1.setNum( o->pretraceStart( ) );
+ dev->writeLine( "pretrace_start " + str1 );
+ }
+
+ if( o->pretraceEnd( ) != c_defaultRadiosityPretraceEnd )
+ {
+ str1.setNum( o->pretraceEnd( ) );
+ dev->writeLine( "pretrace_end " + str1 );
+ }
+
+ if( o->recursionLimit( ) != c_defaultGlobalSettingsRecursionLimit )
+ {
+ str1.setNum( o->recursionLimit( ) );
+ dev->writeLine( "recursion_limit " + str1 );
+ }
+ dev->objectEnd( );
+}
+
+const int c_defaultGlobalPhotonsGatherMin = 20;
+const int c_defaultGlobalPhotonsGatherMax = 100;
+const int c_defaultGlobalPhotonsMediaMaxSteps = 0;
+const double c_defaultGlobalPhotonsMediaFactor = 1.0;
+const double c_defaultGlobalPhotonsJitter = 0.4;
+const double c_defaultGlobalPhotonsAutostop = 0.0;
+const double c_defaultGlobalPhotonsExpandIncrease = 0.2;
+const int c_defaultGlobalPhotonsExpandMin = 40;
+const double c_defaultGlobalPhotonsRadiusGather = 0.0;
+const double c_defaultGlobalPhotonsRadiusGatherMulti = 1.0;
+const double c_defaultGlobalPhotonsRadiusMedia = 0.0;
+const double c_defaultGlobalPhotonsRadiusMediaMulti = 1.0;
+
+void PMPov35SerGlobalPhotons( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev )
+{
+ PMGlobalPhotons* o = ( PMGlobalPhotons* ) object;
+
+ QString str1, str2;
+
+ dev->objectBegin( "photons" );
+
+ if ( o->numberType( ) == PMGlobalPhotons::Spacing )
+ {
+ str1.setNum( o->spacing( ) );
+ dev->writeLine( "spacing " + str1 );
+ }
+ else
+ {
+ str1.setNum( o->count( ) );
+ dev->writeLine( "count " + str1 );
+ }
+
+ if ( o->gatherMin( ) != c_defaultGlobalPhotonsGatherMin ||
+ o->gatherMax( ) != c_defaultGlobalPhotonsGatherMax )
+ {
+ str1.setNum( o->gatherMin( ) );
+ str2.setNum( o->gatherMax( ) );
+ dev->writeLine( "gather " + str1 + ", " + str2 );
+ }
+
+ if ( o->mediaMaxSteps( ) != c_defaultGlobalPhotonsMediaMaxSteps )
+ {
+ str1.setNum( o->mediaMaxSteps( ) );
+ if ( o->mediaFactor( ) != c_defaultGlobalPhotonsMediaFactor )
+ {
+ str2.setNum( o->mediaFactor( ) );
+ dev->writeLine( "media " + str1 + ", " + str2 );
+ }
+ else
+ dev->writeLine( "media " + str1 );
+ }
+
+ if ( o->jitter( ) != c_defaultGlobalPhotonsJitter )
+ {
+ str1.setNum( o->jitter( ) );
+ dev->writeLine( "jitter " + str1 );
+ }
+
+ if ( !o->maxTraceLevelGlobal( ) )
+ {
+ str1.setNum( o->maxTraceLevel( ) );
+ dev->writeLine( "max_trace_level " + str1 );
+ }
+
+ if ( !o->adcBailoutGlobal( ) )
+ {
+ str1.setNum( o->adcBailout( ) );
+ dev->writeLine( "adc_bailout " + str1 );
+ }
+
+ if ( o->autostop( ) != c_defaultGlobalPhotonsAutostop )
+ {
+ str1.setNum( o->autostop( ) );
+ dev->writeLine( "autostop " + str1 );
+ }
+
+ if ( o->expandIncrease( ) != c_defaultGlobalPhotonsExpandIncrease ||
+ o->expandMin( ) != c_defaultGlobalPhotonsExpandMin )
+ {
+ str1.setNum( o->expandIncrease( ) );
+ str2.setNum( o->expandMin( ) );
+ dev->writeLine( "expand_thresholds " + str1 + ", " + str2 );
+ }
+
+ if ( o->radiusGather( ) != c_defaultGlobalPhotonsRadiusGather ||
+ o->radiusGatherMulti( ) != c_defaultGlobalPhotonsRadiusGatherMulti ||
+ o->radiusMedia( ) != c_defaultGlobalPhotonsRadiusMedia ||
+ o->radiusMediaMulti( ) != c_defaultGlobalPhotonsRadiusMediaMulti )
+ {
+ QString str3, str4;
+ str1.setNum( o->radiusGather( ) );
+ str2.setNum( o->radiusGatherMulti( ) );
+ str3.setNum( o->radiusMedia( ) );
+ str4.setNum( o->radiusMediaMulti( ) );
+ dev->writeLine( "radius " + str1 + ", " + str2 + ", " + str3 + ", " + str4 );
+ }
+ dev->objectEnd( );
+}
+
+const double c_defaultPhotonsSpacingMulti = 1.0;
+
+void PMPov35SerPhotons( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev )
+{
+ PMPhotons* o = ( PMPhotons* ) object;
+
+ QString str1;
+
+ dev->objectBegin( "photons" );
+
+ if( o->parent( ) && ( o->parent( )->type( ) == "Light" ) )
+ {
+ if( o->refraction( ) )
+ dev->writeLine( QString( "refraction on" ) );
+ if( o->reflection( ) )
+ dev->writeLine( QString( "reflection on" ) );
+ if( o->areaLight( ) )
+ dev->writeLine( QString( "area_light" ) );
+ }
+ else
+ {
+ if( o->target( ) )
+ {
+ if( o->spacingMulti( ) != c_defaultPhotonsSpacingMulti )
+ {
+ str1.setNum( o->spacingMulti( ) );
+ dev->writeLine( "target " + str1 );
+ }
+ else
+ dev->writeLine( QString( "target" ) );
+ }
+ if( o->refraction( ) )
+ dev->writeLine( QString( "refraction on" ) );
+ if( o->reflection( ) )
+ dev->writeLine( QString( "reflection on" ) );
+ if( !o->collect( ) )
+ dev->writeLine( QString( "collect off" ) );
+ if( o->passThrough( ) )
+ dev->writeLine( QString( "pass_through" ) );
+ }
+ dev->objectEnd( );
+}
+
+void PMPov35SerInterior( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMInterior* o = ( PMInterior* ) object;
+
+ QString str1;
+
+ dev->objectBegin( "interior" );
+ dev->callSerialization( object, metaObject->superClass( ) );
+
+ if( o->isIorEnabled( ) )
+ {
+ str1.setNum( o->ior( ) );
+ dev->writeLine( "ior " + str1 );
+ }
+ if( o->isCausticsEnabled( ) )
+ {
+ str1.setNum( o->caustics( ) );
+ dev->writeLine( "caustics " + str1 );
+ }
+ if ( o->isDispersionEnabled( ) )
+ {
+ str1.setNum( o->dispersion( ) );
+ dev->writeLine( "dispersion " + str1 );
+ }
+ if ( o->isDispSamplesEnabled( ) )
+ {
+ str1.setNum( o->dispSamples( ) );
+ dev->writeLine( "dispersion_samples " + str1 );
+ }
+ if( o->isFadeDistanceEnabled( ) )
+ {
+ str1.setNum( o->fadeDistance( ) );
+ dev->writeLine( "fade_distance " + str1 );
+ }
+ if( o->isFadePowerEnabled( ) )
+ {
+ str1.setNum( o->fadePower( ) );
+ dev->writeLine( "fade_power " + str1 );
+ }
+ dev->objectEnd( );
+}
+
+void PMPov35SerLightGroup( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMLightGroup* o = ( PMLightGroup* ) object;
+
+ dev->objectBegin( "light_group" );
+
+ dev->writeName( object->name( ) );
+ dev->callSerialization( object, metaObject->superClass( ) );
+
+ if ( o->globalLights( ) )
+ dev->writeLine( "global_lights on" );
+ else
+ dev->writeLine( "global_lights off" );
+
+ dev->objectEnd( );
+}
+
+const PMVector c_defaultPatternCrackleForm = PMVector( -1.0, 1.0, 0.0 );
+const int c_defaultPatternCrackleMetric = 2;
+const double c_defaultPatternCrackleOffset = 0.0;
+const bool c_defaultPatternCrackleSolid = false;
+const int c_defaultPatternFractalExponent = 2;
+const int c_defaultPatternFractalExtType = 1;
+const double c_defaultPatternFractalExtFactor = 1.0;
+const int c_defaultPatternFractalIntType = 0;
+const double c_defaultPatternFractalIntFactor = 1.0;
+const double c_defaultPatternSlopeLoSlope = 0.0;
+const double c_defaultPatternSlopeHiSlope = 1.0;
+const double c_defaultPatternSlopeLoAlt = 0.0;
+const double c_defaultPatternSlopeHiAlt = 1.0;
+const int c_defaultPatternOctaves = 6;
+const double c_defaultPatternOmega = 0.5;
+const double c_defaultPatternLambda = 2.0;
+
+void PMPov35SerPattern( const PMObject* object, const PMMetaObject*, PMOutputDevice* dev )
+{
+ PMPattern* o = ( PMPattern* ) object;
+
+ QString str, str2;
+
+ // pattern type
+ switch( o->patternType( ) )
+ {
+ case PMPattern::PatternAgate:
+ dev->writeLine( "agate" );
+ break;
+ case PMPattern::PatternAverage:
+ dev->writeLine( "average" );
+ break;
+ case PMPattern::PatternBoxed:
+ dev->writeLine( "boxed" );
+ break;
+ case PMPattern::PatternBozo:
+ dev->writeLine( "bozo" );
+ break;
+ case PMPattern::PatternBumps:
+ dev->writeLine( "bumps" );
+ break;
+ case PMPattern::PatternCells:
+ dev->writeLine( "cells" );
+ break;
+ case PMPattern::PatternCrackle:
+ dev->writeLine( "crackle" );
+ break;
+ case PMPattern::PatternCylindrical:
+ dev->writeLine( "cylindrical" );
+ break;
+ case PMPattern::PatternDensity:
+ dev->writeLine( "density_file df3 \"" + o->densityFile( ) + "\"");
+ break;
+ case PMPattern::PatternDents:
+ dev->writeLine( "dents" );
+ break;
+ case PMPattern::PatternGradient:
+ dev->writeLine( "gradient " + o->gradient( ).serialize( ) );
+ break;
+ case PMPattern::PatternGranite:
+ dev->writeLine( "granite" );
+ break;
+ case PMPattern::PatternJulia:
+ if( o->fractalMagnet( ) )
+ {
+ str.setNum( o->fractalMagnetType( ) );
+ str = "magnet " + str + " ";
+ }
+ else
+ str = "";
+
+ str2.setNum( o->maxIterations( ) );
+ str = str + "julia " + o->juliaComplex( ).serialize( ) + ", " + str2;
+ dev->writeLine( str );
+ break;
+ case PMPattern::PatternLeopard:
+ dev->writeLine( "leopard" );
+ break;
+ case PMPattern::PatternMandel:
+ if( o->fractalMagnet( ) )
+ {
+ str.setNum( o->fractalMagnetType( ) );
+ str = "magnet " + str + " ";
+ }
+ else
+ str = "";
+
+ str2.setNum( o->maxIterations( ) );
+ dev->writeLine( str + "mandel " + str2 );
+ break;
+ case PMPattern::PatternMarble:
+ dev->writeLine( "marble" );
+ break;
+ case PMPattern::PatternOnion:
+ dev->writeLine( "onion" );
+ break;
+ case PMPattern::PatternPlanar:
+ dev->writeLine( "planar" );
+ break;
+ case PMPattern::PatternQuilted:
+ dev->writeLine( "quilted" );
+ break;
+ case PMPattern::PatternRadial:
+ dev->writeLine( "radial" );
+ break;
+ case PMPattern::PatternRipples:
+ dev->writeLine( "ripples" );
+ break;
+ case PMPattern::PatternSlope:
+ dev->objectBegin( "slope" );
+ dev->write( o->slopeDirection( ).serialize( ) );
+ if ( o->slopeLoSlope( ) != c_defaultPatternSlopeLoSlope ||
+ o->slopeHiSlope( ) != c_defaultPatternSlopeHiSlope )
+ {
+ str.setNum( o->slopeLoSlope( ) );
+ str2.setNum( o->slopeHiSlope( ) );
+ dev->writeLine( ", " + str + ", " + str2 );
+ }
+ else
+ dev->writeLine( "" );
+
+ if ( o->slopeAltFlag( ) )
+ {
+ dev->write( "altitude " + o->slopeAltitude( ).serialize( ) );
+ if ( o->slopeLoAltitude( ) != c_defaultPatternSlopeLoAlt ||
+ o->slopeHiAltitude( ) != c_defaultPatternSlopeHiAlt )
+ {
+ str.setNum( o->slopeLoAltitude( ) );
+ str2.setNum( o->slopeHiAltitude( ) );
+ dev->writeLine( ", " + str + ", " + str2 );
+ }
+ else
+ dev->writeLine( "" );
+ }
+ dev->objectEnd( );
+ break;
+ case PMPattern::PatternSpherical:
+ dev->writeLine( "spherical" );
+ break;
+ case PMPattern::PatternSpiral1:
+ str.setNum( o->spiralNumberArms( ) );
+ dev->writeLine( "spiral1 " + str );
+ break;
+ case PMPattern::PatternSpiral2:
+ str.setNum( o->spiralNumberArms( ) );
+ dev->writeLine( "spiral2 " + str );
+ break;
+ case PMPattern::PatternSpotted:
+ dev->writeLine( "spotted" );
+ break;
+ case PMPattern::PatternWaves:
+ dev->writeLine( "waves" );
+ break;
+ case PMPattern::PatternWood:
+ dev->writeLine( "wood" );
+ break;
+ case PMPattern::PatternWrinkles:
+ dev->writeLine( "wrinkles" );
+ break;
+ }
+ // depth
+ if( o->parent( ) )
+ {
+ if( o->depth( ) && o->parent( )->type( ) == "Normal" )
+ {
+ str.setNum( o->depth( ) );
+ dev->writeLine( str );
+ }
+ }
+ // modifiers
+ switch( o->patternType( ) )
+ {
+ case PMPattern::PatternAgate:
+ str.setNum( o->agateTurbulence( ) );
+ dev->writeLine( "agate_turb " + str );
+ break;
+ case PMPattern::PatternCrackle:
+ if ( o->crackleForm( ) != c_defaultPatternCrackleForm )
+ dev->writeLine( "form " + o->crackleForm( ).serialize( ) );
+ if ( o->crackleMetric( ) != c_defaultPatternCrackleMetric )
+ {
+ str.setNum( o->crackleMetric( ) );
+ dev->writeLine( "metric " + str );
+ }
+ if ( o->crackleOffset( ) != c_defaultPatternCrackleOffset )
+ {
+ str.setNum( o->crackleOffset( ) );
+ dev->writeLine( "offset " + str );
+ }
+ if ( o->crackleSolid( ) )
+ dev->writeLine( "solid" );
+ break;
+ case PMPattern::PatternDensity:
+ str.setNum( o->densityInterpolate( ) );
+ dev->writeLine( "interpolate " + str );
+ break;
+ case PMPattern::PatternJulia:
+ case PMPattern::PatternMandel:
+ if ( !o->fractalMagnet( ) && o->fractalExponent( ) != c_defaultPatternFractalExponent )
+ {
+ str.setNum( o->fractalExponent( ) );
+ dev->writeLine( "exponent " + str );
+ }
+ if ( o->fractalExtType( ) != c_defaultPatternFractalExtType ||
+ o->fractalExtFactor( ) != c_defaultPatternFractalExtFactor )
+ {
+ str.setNum( o->fractalExtType( ) );
+ str2.setNum( o->fractalExtFactor( ) );
+ dev->writeLine( "exterior " + str + ", " + str2 );
+ }
+ if ( o->fractalIntType( ) != c_defaultPatternFractalIntType ||
+ o->fractalIntFactor( ) != c_defaultPatternFractalIntFactor )
+ {
+ str.setNum( o->fractalIntType( ) );
+ str2.setNum( o->fractalIntFactor( ) );
+ dev->writeLine( "interior " + str + ", " + str2 );
+ }
+ break;
+ case PMPattern::PatternQuilted:
+ str.setNum( o->quiltControl0( ) );
+ dev->writeLine( "control0 " + str );
+ str.setNum( o->quiltControl1( ) );
+ dev->writeLine( "control1 " + str );
+ break;
+ case PMPattern::PatternBozo:
+ case PMPattern::PatternBumps:
+ case PMPattern::PatternGranite:
+ case PMPattern::PatternWrinkles:
+ switch( o->noiseGenerator( ) )
+ {
+ case PMPattern::Original:
+ dev->writeLine( QString( "noise_generator 1" ) );
+ break;
+ case PMPattern::RangeCorrected:
+ dev->writeLine( QString( "noise_generator 2" ) );
+ break;
+ case PMPattern::Perlin:
+ dev->writeLine( QString( "noise_generator 3" ) );
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ if( o->isTurbulenceEnabled( ) )
+ {
+ dev->writeLine( "turbulence " + o->valueVector( ).serialize( ) );
+ if( o->octaves( ) != c_defaultPatternOctaves )
+ {
+ str.setNum( o->octaves( ) );
+ dev->writeLine( "octaves " + str );
+ }
+ if( o->omega( ) != c_defaultPatternOmega )
+ {
+ str.setNum( o->omega( ) );
+ dev->writeLine( "omega " + str );
+ }
+ if( o->lambda( ) != c_defaultPatternLambda )
+ {
+ str.setNum( o->lambda( ) );
+ dev->writeLine( "lambda " + str );
+ }
+ }
+}
+
+const double c_defaultNormalAccuracy = 0.02;
+
+void PMPov35SerNormal( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMNormal* o = ( PMNormal* ) object;
+
+ QString str1;
+ bool bObject = true;
+
+ if( o->parent( ) )
+ {
+ if( o->parent( )->type( ) == "NormalMap" )
+ bObject = false;
+ }
+
+ if( bObject )
+ {
+ dev->objectBegin( "normal" );
+ if ( o->uvMapping() )
+ dev->writeLine( "uv_mapping" );
+ }
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+
+ if( o->isBumpSizeEnabled( ) )
+ {
+ str1.setNum( o->bumpSize( ) );
+ dev->writeLine( "bump_size " + str1 );
+ }
+
+ if( o->accuracy( ) != c_defaultNormalAccuracy )
+ {
+ str1.setNum( o->accuracy( ) );
+ dev->writeLine( "accuracy " + str1 );
+ }
+
+ if( bObject )
+ dev->objectEnd( );
+}
+
+void PMPov35SerInteriorTexture( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ dev->objectBegin( "interior_texture" );
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+const PMVector c_warpDirectionDefault = PMVector( 1.0, 0.0, 0.0 );
+const PMVector c_warpOffsetDefault = PMVector( 0.0, 0.0, 0.0 );
+const PMVector c_warpFlipDefault = PMVector( 0.0, 0.0, 0.0 );
+const PMVector c_warpLocationDefault = PMVector( 0.0, 0.0, 0.0 );
+const double c_warpRadiusDefault = 0;
+const double c_warpStrengthDefault = 0;
+const double c_warpFalloffDefault = 0;
+const bool c_warpInverseDefault = false;
+const PMVector c_warpRepeatDefault = PMVector( 0.0, 0.0, 0.0 );
+const PMVector c_warpTurbulenceDefault = PMVector( 0.0, 0.0, 0.0 );
+const PMVector c_warpValueVectorDefault = PMVector( 0.0, 0.0, 0.0 );
+const int c_warpOctavesDefault = 6;
+const double c_warpOmegaDefault = 0.5;
+const double c_warpLambdaDefault = 2.0;
+const PMVector c_warpOrientationDefault = PMVector( 0.0, 0.0, 1.0 );
+const double c_warpDistExpDefault = 0.0;
+const double c_warpMajorRadiusDefault = 1.0;
+
+void PMPov35SerWarp( const PMObject* object, const PMMetaObject* , PMOutputDevice* dev )
+{
+ PMWarp* o = ( PMWarp* ) object;
+
+ QString str1, str2;
+
+ dev->objectBegin( "warp" );
+ switch( o->warpType( ) )
+ {
+ case PMWarp::Repeat:
+ dev->writeLine( "repeat" );
+ dev->writeLine( o->direction( ).serialize( ) );
+ dev->writeLine( "offset " + o->offset( ).serialize( ) );
+ dev->writeLine( "flip " + o->flip( ).serialize( ) );
+ break;
+ case PMWarp::BlackHole:
+ dev->writeLine( "black_hole" );
+ dev->writeLine( o->location( ).serialize( ) );
+ str1.setNum(o->radius( ));
+ dev->writeLine( ", " + str1 );
+ if( o->strength( ) != c_warpStrengthDefault )
+ {
+ str1.setNum( o->strength( ));
+ dev->writeLine( "strength " + str1 );
+ }
+ if( o->falloff( ) != c_warpFalloffDefault )
+ {
+ str1.setNum( o->falloff( ));
+ dev->writeLine( "falloff " + str1 );
+ }
+ if( o->inverse( ) != c_warpInverseDefault )
+ {
+ if( o->inverse( ) ) dev->writeLine( "inverse" );
+ }
+ if( o->repeat( ) != c_warpRepeatDefault )
+ {
+ dev->writeLine( "repeat " + o->repeat( ).serialize( ) );
+ }
+ if( o->turbulence( ) != c_warpTurbulenceDefault )
+ {
+ dev->writeLine( "turbulence " + o->turbulence( ).serialize( ) );
+ }
+ break;
+ case PMWarp::Turbulence:
+ dev->writeLine( "turbulence " + o->valueVector( ).serialize( ) );
+ if( o->octaves( ) != c_warpOctavesDefault )
+ {
+ str1.setNum(o->octaves( ));
+ dev->writeLine( "octaves " + str1 );
+ }
+ if( o->omega( ) != c_warpOmegaDefault )
+ {
+ str1.setNum( o->omega( ) );
+ dev->writeLine( "omega " + str1 );
+ }
+ if( o->lambda( ) != c_warpLambdaDefault )
+ {
+ str1.setNum( o->lambda( ) );
+ dev->writeLine( "lambda " + str1 );
+ }
+ break;
+ case PMWarp::Cylindrical:
+ dev->writeLine( "cylindrical " + o->orientation( ).serialize( ) );
+ if ( o->distExp( ) != c_warpDistExpDefault )
+ {
+ str1.setNum( o->distExp( ) );
+ dev->writeLine( "dist_exp " + str1 );
+ }
+ break;
+ case PMWarp::Spherical:
+ dev->writeLine( "spherical " + o->orientation( ).serialize( ) );
+ if ( o->distExp( ) != c_warpDistExpDefault )
+ {
+ str1.setNum( o->distExp( ) );
+ dev->writeLine( "dist_exp " + str1 );
+ }
+ break;
+ case PMWarp::Toroidal:
+ dev->writeLine( "torodial " + o->orientation( ).serialize( ) );
+ if ( o->distExp( ) != c_warpDistExpDefault )
+ {
+ str1.setNum( o->distExp( ) );
+ dev->writeLine( "dist_exp " + str1 );
+ }
+ if ( o->majorRadius( ) != c_warpMajorRadiusDefault )
+ {
+ str1.setNum( o->majorRadius( ) );
+ dev->writeLine( "major_radius " + str1 );
+ }
+ break;
+ case PMWarp::Planar:
+ str1 = "planar " + o->orientation( ).serialize( );
+ if ( o->distExp( ) != c_warpDistExpDefault )
+ {
+ str2.setNum( o->distExp( ) );
+ dev->writeLine( str1 + ", " + str2 );
+ }
+ else
+ dev->writeLine( str1 );
+ break;
+ }
+
+ dev->objectEnd( );
+}
+
+const double c_sphereSweepToleranceDefault = 1e-6;
+
+void PMPov35SerSphereSweep( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMSphereSweep* o = ( PMSphereSweep* ) object;
+
+ QString str1;
+ int numSpheres;
+ QValueList<PMVector> points;
+ QValueList<double> radii;
+
+ dev->objectBegin( "sphere_sweep" );
+
+ switch( o->splineType( ) )
+ {
+ case PMSphereSweep::LinearSpline:
+ dev->writeLine( QString( "linear_spline," ) );
+ break;
+ case PMSphereSweep::BSpline:
+ dev->writeLine( QString( "b_spline," ) );
+ break;
+ case PMSphereSweep::CubicSpline:
+ dev->writeLine( QString( "cubic_spline," ) );
+ break;
+ }
+
+ numSpheres = o->numberOfPoints( );
+ str1.setNum( numSpheres );
+ dev->writeLine( str1 + "," );
+ points = o->points( );
+ radii = o->radii( );
+
+ for ( int i = 0; i < numSpheres; ++i )
+ {
+ str1.setNum( radii[i] );
+ dev->writeLine( points[i].serialize( ) + "," + str1 );
+ }
+
+ if ( o->tolerance( ) != c_sphereSweepToleranceDefault )
+ {
+ str1.setNum( o->tolerance( ) );
+ dev->writeLine( "tolerance " + str1 );
+ }
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov35SerFinish( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMFinish* o = ( PMFinish* ) object;
+
+ QString str1;
+
+ dev->objectBegin( "finish" );
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+
+ if( o->isAmbientEnabled( ) )
+ dev->writeLine( "ambient " + o->ambientColor( ).serialize( ) );
+
+ if( o->isDiffuseEnabled( ) )
+ {
+ str1.setNum( o->diffuse( ) );
+ dev->writeLine( "diffuse " + str1 );
+ }
+
+ if( o->isBrillianceEnabled( ) )
+ {
+ str1.setNum( o->brilliance( ) );
+ dev->writeLine( "brilliance " + str1 );
+ }
+
+ if( o->isPhongEnabled( ) )
+ {
+ str1.setNum( o->phong( ) );
+ dev->writeLine( "phong " + str1 );
+ }
+
+ if( o->isPhongSizeEnabled( ) )
+ {
+ str1.setNum( o->phongSize( ) );
+ dev->writeLine( "phong_size " + str1 );
+ }
+
+ if( o->isMetallicEnabled( ) )
+ {
+ str1.setNum( o->metallic( ) );
+ dev->writeLine( "metallic " + str1 );
+ }
+
+ if( o->isSpecularEnabled( ) )
+ {
+ str1.setNum( o->specular( ) );
+ dev->writeLine( "specular " + str1 );
+ }
+
+ if( o->isRoughnessEnabled( ) )
+ {
+ str1.setNum( o->roughness( ) );
+ dev->writeLine( "roughness " + str1 );
+ }
+
+ if( o->isCrandEnabled( ) )
+ {
+ str1.setNum( o->crand( ) );
+ dev->writeLine( "crand " + str1 );
+ }
+
+ if( o->conserveEnergy( ) )
+ dev->writeLine( "conserve_energy" );
+
+ if( o->irid( ) )
+ {
+ str1.setNum( o->iridAmount( ) );
+ dev->writeLine( "irid { " + str1 );
+ str1.setNum( o->iridThickness( ) );
+ dev->writeLine( "thickness " + str1 );
+ str1.setNum( o->iridTurbulence( ) );
+ dev->writeLine( "turbulence " + str1 + " } " );
+ }
+
+ if( o->isReflectionEnabled( ) )
+ {
+ dev->objectBegin( "reflection" );
+
+ if ( o->isReflectionMinEnabled( ) )
+ {
+ dev->writeLine( o->reflectionMinColor( ).serialize( ) + ", " +
+ o->reflectionColor( ).serialize( ) );
+ }
+ else
+ dev->writeLine( o->reflectionColor( ).serialize( ) );
+
+ if ( o->reflectionFresnel( ) )
+ dev->writeLine( "fresnel" );
+
+ if ( o->isRefFalloffEnabled( ) )
+ {
+ str1.setNum( o->reflectionFalloff( ) );
+ dev->writeLine( "falloff " + str1 );
+ }
+
+ if ( o->isRefExponentEnabled( ) )
+ {
+ str1.setNum( o->reflectionExponent( ) );
+ dev->writeLine( "exponent " + str1 );
+ }
+
+ if ( o->isRefMetallicEnabled( ) )
+ {
+ str1.setNum( o->reflectionMetallic( ) );
+ dev->writeLine( "metallic " + str1 );
+ }
+
+ dev->objectEnd( );
+ }
+
+ dev->objectEnd( );
+}
+
+void PMPov35SerMesh( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMMesh* o = ( PMMesh* ) object;
+
+ dev->objectBegin( "mesh" );
+
+ if( o->isInsideVectorEnabled( ) )
+ dev->writeLine( "inside_vector " + o->insideVector( ).serialize( ) );
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+
+ if( !o->hierarchy( ) )
+ dev->writeLine( "hierarchy off" );
+
+ dev->objectEnd( );
+}
+
+const int c_defaultMediaMethod = 1;
+const int c_defaultMediaIntervals = 10;
+const int c_defaultMediaSamplesMin = 1;
+const int c_defaultMediaSamplesMax = 1;
+const double c_defaultMediaConfidence = 0.9;
+const double c_defaultMediaVariance = 0.0078125;
+const double c_defaultMediaRatio = 0.9;
+const int c_defaultMediaAALevel = 4;
+const double c_defaultMediaAAThreshold = 0.1;
+const double c_defaultMediaScatteringEccentricity = 0;
+const double c_defaultMediaScatteringExtinction = 1.0;
+
+void PMPov35SerMedia( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMMedia* o = ( PMMedia* ) object;
+
+ QString str1;
+ QString str2;
+
+ dev->objectBegin( "media" );
+ dev->callSerialization( object, metaObject->superClass( ) );
+
+ if( o->method( ) != c_defaultMediaMethod )
+ {
+ str1.setNum( o->method( ) );
+ dev->writeLine( "method " + str1 );
+ }
+ if( o->intervals( ) != c_defaultMediaIntervals )
+ {
+ str1.setNum( o->intervals( ) );
+ dev->writeLine( "intervals " + str1 );
+ }
+ if( o->samplesMin( ) != c_defaultMediaSamplesMin ||
+ o->samplesMax( ) != c_defaultMediaSamplesMax )
+ {
+ str1.setNum( o->samplesMin( ) );
+ str2.setNum( o->samplesMax( ) );
+ if ( o->method( ) < 3 )
+ dev->writeLine( "samples " + str1 + "," + str2 );
+ else
+ dev->writeLine( "samples " + str1 );
+ }
+ if( o->confidence( ) != c_defaultMediaConfidence )
+ {
+ str1.setNum( o->confidence( ) );
+ dev->writeLine( "confidence " + str1 );
+ }
+ if( o->variance( ) != c_defaultMediaVariance )
+ {
+ str1.setNum( o->variance( ) );
+ dev->writeLine( "variance " + str1 );
+ }
+ if( o->ratio( ) != c_defaultMediaRatio )
+ {
+ str1.setNum( o->ratio( ) );
+ dev->writeLine( "ratio " + str1 );
+ }
+ if ( o->method( ) == 3 )
+ {
+ if ( o->aaLevel( ) != c_defaultMediaAALevel )
+ {
+ str1.setNum( o->aaLevel( ) );
+ dev->writeLine( "aa_level " + str1 );
+ }
+ if ( o->aaThreshold( ) != c_defaultMediaAAThreshold )
+ {
+ str1.setNum( o->aaThreshold( ) );
+ dev->writeLine( "aa_threshold " + str1 );
+ }
+ }
+ if( o->isAbsorptionEnabled( ) )
+ {
+ dev->writeLine( "absorption " + o->absorption( ).serialize( ) );
+ }
+ if( o->isEmissionEnabled( ) )
+ {
+ dev->writeLine( "emission " + o->emission( ).serialize( ) );
+ }
+ if( o->isScatteringEnabled( ) )
+ {
+ dev->objectBegin( "scattering" );
+ str1.setNum( o->scatteringType( ) );
+ dev->writeLine( str1 + ", " + o->scatteringColor( ).serialize( ) );
+ if( o->scatteringType( ) == 5 && o->scatteringEccentricity( )
+ != c_defaultMediaScatteringEccentricity )
+ {
+ str1.setNum( o->scatteringEccentricity( ) );
+ dev->writeLine( "eccentricity " + str1 );
+ }
+ if( o->scatteringExtinction( ) != c_defaultMediaScatteringExtinction )
+ {
+ str1.setNum( o->scatteringExtinction( ) );
+ dev->writeLine( "extinction " + str1 );
+ }
+ dev->objectEnd( );
+ }
+ dev->objectEnd( );
+}
+
+void PMPov35SerGraphicalObject( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMGraphicalObject* o = ( PMGraphicalObject* ) object;
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+
+ if( o->noShadow( ) )
+ dev->writeLine( "no_shadow" );
+
+ if( o->noImage( ) )
+ dev->writeLine( "no_image" );
+
+ if( o->noReflection( ) )
+ dev->writeLine( "no_reflection" );
+
+ if( o->doubleIlluminate( ) )
+ dev->writeLine( "double_illuminate" );
+}
+
+void PMPov35SerPigment( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMPigment* o = ( PMPigment* ) object;
+
+ bool bObject = true;
+ if( o->parent( ) )
+ if( o->parent( )->type( ) == "PigmentMap" )
+ bObject = false;
+
+ if( bObject )
+ {
+ dev->objectBegin( "pigment" );
+ if ( o->uvMapping() )
+ dev->writeLine( "uv_mapping" );
+ }
+ dev->callSerialization( object, metaObject->superClass( ) );
+ if( bObject )
+ dev->objectEnd( );
+}
+
+void PMPov35SerTexture( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMTexture* o = ( PMTexture* ) object;
+
+ bool bObject = true;
+ if( o->parent( ) )
+ if( o->parent( )->type( ) == "TextureMap" )
+ bObject = false;
+
+ if( bObject )
+ {
+ dev->objectBegin( "texture" );
+ if ( o->uvMapping() )
+ dev->writeLine( "uv_mapping" );
+ }
+ dev->callSerialization( object, metaObject->superClass( ) );
+ if( bObject )
+ dev->objectEnd( );
+}
+
+const double c_defaultPatchFlatness = 0;
+
+void PMPov35SerBicubicPatch( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMBicubicPatch* o = ( PMBicubicPatch* ) object;
+
+ int u, v;
+ QString str, line;
+ dev->objectBegin( "bicubic_patch" );
+
+ dev->writeName( object->name( ) );
+
+ str.setNum( o->patchType( ) );
+ dev->writeLine( "type " + str );
+ if( !approx( o->flatness( ), c_defaultPatchFlatness ) )
+ {
+ str.setNum( o->flatness( ) );
+ dev->writeLine( "flatness " + str );
+ }
+ str.setNum( o->uSteps( ) );
+ dev->writeLine( "u_steps " + str );
+ str.setNum( o->vSteps( ) );
+ dev->writeLine( "v_steps " + str );
+
+ if( o->isUVEnabled( ) )
+ {
+ dev->writeLine( "uv_vectors " + o->uvVector( 0 ).serialize( ) +
+ " " + o->uvVector( 1 ).serialize( ) +
+ " " + o->uvVector( 2 ).serialize( ) +
+ " " + o->uvVector( 3 ).serialize( ) );
+ }
+
+ for( v = 0; v < 4; v++ )
+ {
+ line = o->controlPoint( v*4 ).serialize( );
+ for( u = 1; u < 4; u++ )
+ line += QString( ", " ) + o->controlPoint( u+4*v ).serialize( );
+ if( v != 3 )
+ line += ",";
+ dev->writeLine( line );
+ }
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
+
+void PMPov35SerTriangle( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev )
+{
+ PMTriangle* o = ( PMTriangle* ) object;
+
+ if( o->isSmoothTriangle( ) )
+ {
+ dev->objectBegin( "smooth_triangle" );
+
+ dev->writeName( object->name( ) );
+ dev->writeLine( o->point( 0 ).serialize( ) + ", " + o->normal( 0 ).serialize( ) + "," );
+ dev->writeLine( o->point( 1 ).serialize( ) + ", " + o->normal( 1 ).serialize( ) + "," );
+ dev->writeLine( o->point( 2 ).serialize( ) + ", " + o->normal( 2 ).serialize( ) );
+ }
+ else
+ {
+ dev->objectBegin( "triangle" );
+
+ dev->writeName( object->name( ) );
+ dev->writeLine( o->point( 0 ).serialize( ) + ", " + o->point( 1 ).serialize( )
+ + ", " + o->point( 2 ).serialize( ) );
+ }
+
+ if( o->isUVEnabled( ) )
+ {
+ dev->writeLine( "uv_vectors " + o->uvVector( 0 ).serialize( ) +
+ " " + o->uvVector( 1 ).serialize( ) +
+ " " + o->uvVector( 2 ).serialize( ) );
+ }
+
+ dev->callSerialization( object, metaObject->superClass( ) );
+ dev->objectEnd( );
+}
diff --git a/kpovmodeler/pmpovray35serialization.h b/kpovmodeler/pmpovray35serialization.h
new file mode 100644
index 00000000..4e511d55
--- /dev/null
+++ b/kpovmodeler/pmpovray35serialization.h
@@ -0,0 +1,49 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMPOVRAY35_SERIALIZATION_H
+#define PMPOVRAY35_SERIALIZATION_H
+
+class PMObject;
+class PMMetaObject;
+class PMOutputDevice;
+
+// serialization methods for POV-Ray 3.5
+
+void PMPov35SerIsoSurface( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov35SerLight( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov35SerProjectedThrough( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov35SerGlobalSettings( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov35SerRadiosity( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov35SerGlobalPhotons( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov35SerPhotons( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov35SerInterior( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov35SerLightGroup( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov35SerPattern( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov35SerNormal( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov35SerInteriorTexture( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov35SerWarp( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov35SerSphereSweep( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov35SerFinish( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov35SerMesh( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov35SerMedia( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov35SerGraphicalObject( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov35SerPigment( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov35SerTexture( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov35SerBicubicPatch( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+void PMPov35SerTriangle( const PMObject* object, const PMMetaObject* metaObject, PMOutputDevice* dev );
+#endif
diff --git a/kpovmodeler/pmpovrayformat.cpp b/kpovmodeler/pmpovrayformat.cpp
new file mode 100644
index 00000000..a2c48c80
--- /dev/null
+++ b/kpovmodeler/pmpovrayformat.cpp
@@ -0,0 +1,52 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmpovrayformat.h"
+#include "pmdebug.h"
+
+PMPovrayFormat::PMPovrayFormat( )
+{
+ m_methodDict.setAutoDelete( true );
+}
+
+
+PMPovrayFormat::~PMPovrayFormat( )
+{
+
+}
+
+void PMPovrayFormat::registerMethod( const QString& className,
+ PMPovraySerializeMethod method )
+{
+ PMPovraySerializeMethodInfo* info = m_methodDict.find( className );
+ if( info )
+ kdWarning( PMArea ) << "Serialization method for " << className
+ << " shadows old implementation" << endl;
+ info = new PMPovraySerializeMethodInfo( method );
+ m_methodDict.insert( className, info );
+}
+
+void PMPovrayFormat::removeMethod( const QString& className )
+{
+ m_methodDict.remove( className );
+}
+
+const PMPovraySerializeMethodInfo* PMPovrayFormat::serializationMethod(
+ const QString& className )
+{
+ return m_methodDict.find( className );
+}
diff --git a/kpovmodeler/pmpovrayformat.h b/kpovmodeler/pmpovrayformat.h
new file mode 100644
index 00000000..398cae42
--- /dev/null
+++ b/kpovmodeler/pmpovrayformat.h
@@ -0,0 +1,94 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMPOVRAY_FORMAT_H
+#define PMPOVRAY_FORMAT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmiomanager.h"
+#include "pmoutputdevice.h"
+
+typedef void ( *PMPovraySerializeMethod ) ( const PMObject*, const PMMetaObject*,
+ PMOutputDevice* );
+/**
+ * Helper class for @ref PMOutputDevice and @ref PMPovrayFormatBase
+ */
+class PMPovraySerializeMethodInfo
+{
+public:
+ PMPovraySerializeMethodInfo( )
+ {
+ m_method = 0;
+ }
+ PMPovraySerializeMethodInfo( PMPovraySerializeMethod m )
+ {
+ m_method = m;
+ }
+ PMPovraySerializeMethod method( ) const { return m_method; }
+ void call( const PMObject* o, const PMMetaObject* mo, PMOutputDevice* ser ) const
+ {
+ if( m_method )
+ m_method( o, mo, ser );
+ }
+private:
+ PMPovraySerializeMethod m_method;
+};
+
+/**
+ * Base class for all POV-Ray formats which use a PMOutputDevice
+ * for serialization.
+ *
+ * Plugins can register new serialization methods with @ref registerMethod
+ */
+class PMPovrayFormat : public PMIOFormat
+{
+public:
+ /**
+ * Default constructor
+ */
+ PMPovrayFormat( );
+ /**
+ * Destructor
+ */
+ virtual ~PMPovrayFormat( );
+
+ /**
+ * Registers the serialization method for the class className
+ */
+ void registerMethod( const QString& className, PMPovraySerializeMethod method );
+ /**
+ * Removes a registered serialization method
+ */
+ void removeMethod( const QString& className );
+ /**
+ * Returns the serialization methods info for the given object type
+ * or 0 if there is none.
+ */
+ const PMPovraySerializeMethodInfo* serializationMethod(
+ const QString& className );
+
+private:
+ /**
+ * Dict class name -> serialization method
+ */
+ QDict<PMPovraySerializeMethodInfo> m_methodDict;
+};
+
+#endif
diff --git a/kpovmodeler/pmpovraymatrix.cpp b/kpovmodeler/pmpovraymatrix.cpp
new file mode 100644
index 00000000..4100d46a
--- /dev/null
+++ b/kpovmodeler/pmpovraymatrix.cpp
@@ -0,0 +1,152 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmpovraymatrix.h"
+#include "pmpovraymatrixedit.h"
+
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+
+#include <klocale.h>
+
+PMDefinePropertyClass( PMPovrayMatrix, PMPovrayMatrixProperty );
+
+PMMetaObject* PMPovrayMatrix::s_pMetaObject = 0;
+PMObject* createNewPovrayMatrix( PMPart* part )
+{
+ return new PMPovrayMatrix( part );
+}
+
+PMPovrayMatrix::PMPovrayMatrix( PMPart* part )
+ : Base( part )
+{
+ m_values = PMVector( 12 );
+ m_values[0] = 1.0;
+ m_values[4] = 1.0;
+ m_values[8] = 1.0;
+}
+
+PMPovrayMatrix::PMPovrayMatrix( const PMPovrayMatrix& m )
+ : Base( m )
+{
+ m_values = m.m_values;
+}
+
+PMPovrayMatrix::~PMPovrayMatrix( )
+{
+}
+
+QString PMPovrayMatrix::description( ) const
+{
+ return i18n( "matrix" );
+}
+
+void PMPovrayMatrix::serialize( QDomElement& e, QDomDocument& /*doc*/ ) const
+{
+ e.setAttribute( "value", m_values.serializeXML( ) );
+}
+
+void PMPovrayMatrix::readAttributes( const PMXMLHelper& h )
+{
+ PMVector d = PMVector( 12 );
+ d[0] = 1.0;
+ d[4] = 1.0;
+ d[8] = 1.0;
+
+ m_values = h.vectorAttribute( "value", d );
+ m_values.resize( 12 );
+}
+
+PMMetaObject* PMPovrayMatrix::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "PovrayMatrix", Base::metaObject( ),
+ createNewPovrayMatrix );
+ s_pMetaObject->addProperty(
+ new PMPovrayMatrixProperty( "values", &PMPovrayMatrix::setValues, &PMPovrayMatrix::values ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMPovrayMatrix::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMPovrayMatrix::setValues( const PMVector& v )
+{
+ if( v != m_values )
+ {
+ if( m_pMemento )
+ {
+ m_pMemento->addData( s_pMetaObject, PMMatrixID, m_values );
+ m_pMemento->setViewStructureChanged( );
+ }
+ m_values = v;
+ m_values.resize( 12 );
+ }
+}
+
+PMDialogEditBase* PMPovrayMatrix::editWidget( QWidget* parent ) const
+{
+ return new PMPovrayMatrixEdit( parent );
+}
+
+void PMPovrayMatrix::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMMatrixID:
+ setValues( data->vectorData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMPovrayMatrix::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
+PMMatrix PMPovrayMatrix::transformationMatrix( ) const
+{
+ PMMatrix m;
+ int l, c;
+
+ for( l = 0; l < 4; l++ )
+ for( c = 0; c < 3; c++ )
+ m[l][c] = m_values[l*3+c];
+ m[3][3] = 1.0;
+
+ return m;
+}
+
diff --git a/kpovmodeler/pmpovraymatrix.h b/kpovmodeler/pmpovraymatrix.h
new file mode 100644
index 00000000..25a1e03b
--- /dev/null
+++ b/kpovmodeler/pmpovraymatrix.h
@@ -0,0 +1,97 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPOVRAYMATRIX_H
+#define PMPOVRAYMATRIX_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmobject.h"
+
+/**
+ * Class for povray matrix transformations.
+ */
+
+class PMPovrayMatrix : public PMObject
+{
+ typedef PMObject Base;
+public:
+ /**
+ * Creates an identity matrix
+ */
+ PMPovrayMatrix( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMPovrayMatrix( const PMPovrayMatrix& m );
+ /**
+ * deletes the object
+ */
+ virtual ~PMPovrayMatrix( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMPovrayMatrix( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMPovrayMatrixEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmmatrix" ); }
+
+ /**
+ * Returns the matrix values.
+ */
+ PMVector values( ) const { return m_values; }
+ /**
+ * Sets the matrix values. Has to be a vector with size 12.
+ */
+ void setValues( const PMVector& v );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /** */
+ virtual bool hasTransformationMatrix( ) const { return true; }
+ /** */
+ virtual PMMatrix transformationMatrix( ) const;
+
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMMatrixMementoID { PMMatrixID };
+ PMVector m_values;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmpovraymatrixedit.cpp b/kpovmodeler/pmpovraymatrixedit.cpp
new file mode 100644
index 00000000..0d78c226
--- /dev/null
+++ b/kpovmodeler/pmpovraymatrixedit.cpp
@@ -0,0 +1,102 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmpovraymatrixedit.h"
+#include "pmpovraymatrix.h"
+#include "pmlineedits.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <klocale.h>
+
+
+PMPovrayMatrixEdit::PMPovrayMatrixEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMPovrayMatrixEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ int i, r, c;
+ QGridLayout* gl = new QGridLayout( topLayout( ), 4, 4 );
+
+ for( i = 0; i < 12; i++ )
+ {
+ m_pValue[i] = new PMFloatEdit( this );
+ connect( m_pValue[i], SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ }
+
+ for( r = 0; r < 4; r++ )
+ for( c = 0; c < 3; c++ )
+ gl->addWidget( m_pValue[r*3+c], r, c );
+ gl->addWidget( new QLabel( "0.0", this ), 0, 3 );
+ gl->addWidget( new QLabel( "0.0", this ), 1, 3 );
+ gl->addWidget( new QLabel( "0.0", this ), 2, 3 );
+ gl->addWidget( new QLabel( "1.0", this ), 3, 3 );
+}
+
+void PMPovrayMatrixEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "PovrayMatrix" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ int i;
+ m_pDisplayedObject = ( PMPovrayMatrix* ) o;
+ PMVector v = m_pDisplayedObject->values( );
+
+ for( i = 0; i < 12; i++ )
+ {
+ m_pValue[i]->setValue( v[i] );
+ m_pValue[i]->setReadOnly( readOnly );
+ }
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMPovrayMatrixEdit: Can't display object\n";
+}
+
+void PMPovrayMatrixEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ PMVector v( 12 );
+ int i;
+
+ for( i = 0; i < 12; i++ )
+ v[i] = m_pValue[i]->value( );
+ m_pDisplayedObject->setValues( v );
+ }
+}
+
+bool PMPovrayMatrixEdit::isDataValid( )
+{
+ int i;
+
+ for( i = 0; i < 12; i++ )
+ if( !m_pValue[i]->isDataValid( ) )
+ return false;
+
+ return Base::isDataValid( );
+}
+
+#include "pmpovraymatrixedit.moc"
diff --git a/kpovmodeler/pmpovraymatrixedit.h b/kpovmodeler/pmpovraymatrixedit.h
new file mode 100644
index 00000000..2dbd41ae
--- /dev/null
+++ b/kpovmodeler/pmpovraymatrixedit.h
@@ -0,0 +1,62 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPOVRAYMATRIXEDIT_H
+#define PMPOVRAYMATRIXEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdialogeditbase.h"
+
+class PMPovrayMatrix;
+class PMFloatEdit;
+
+/**
+ * Dialog edit class for @ref PMPovrayMatrix
+ */
+class PMPovrayMatrixEdit : public PMDialogEditBase
+{
+ Q_OBJECT
+ typedef PMDialogEditBase Base;
+public:
+ /**
+ * Creates a PMPovrayMatrixEdit with parent and name
+ */
+ PMPovrayMatrixEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMPovrayMatrix* m_pDisplayedObject;
+ PMFloatEdit* m_pValue[12];
+};
+
+
+#endif
diff --git a/kpovmodeler/pmpovrayoutputwidget.cpp b/kpovmodeler/pmpovrayoutputwidget.cpp
new file mode 100644
index 00000000..b0d4ca73
--- /dev/null
+++ b/kpovmodeler/pmpovrayoutputwidget.cpp
@@ -0,0 +1,115 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmpovrayoutputwidget.h"
+
+#include <qtextedit.h>
+#include <qlayout.h>
+
+#include <klocale.h>
+#include <kglobalsettings.h>
+#include <kconfig.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+#include "pmdebug.h"
+
+QSize PMPovrayOutputWidget::s_size = QSize( 400, 400 );
+
+PMPovrayOutputWidget::PMPovrayOutputWidget( QWidget* parent, const char* name )
+ : KDialog( parent, name )
+{
+ QVBoxLayout* topLayout = new QVBoxLayout( this, KDialog::marginHint( ), KDialog::spacingHint( ) );
+
+ m_pTextView = new QTextEdit( this );
+ topLayout->addWidget( m_pTextView, 1 );
+ m_pTextView->setFont( KGlobalSettings::fixedFont( ) );
+ m_pTextView->setTextFormat( Qt::PlainText );
+ m_pTextView->setReadOnly( true );
+
+ QHBoxLayout* buttonLayout = new QHBoxLayout( topLayout );
+ buttonLayout->addStretch( 1 );
+ QPushButton* closeButton = new KPushButton( KStdGuiItem::close(), this );
+ buttonLayout->addWidget( closeButton );
+ closeButton->setDefault( true );
+ connect( closeButton, SIGNAL( clicked( ) ), SLOT( hide( ) ) );
+
+ setCaption( i18n( "Povray Output" ) );
+ resize( s_size );
+
+ m_startOfLastLine = 0;
+}
+
+PMPovrayOutputWidget::~PMPovrayOutputWidget( )
+{
+}
+
+void PMPovrayOutputWidget::slotClear( )
+{
+ m_output = QString::null;
+ m_startOfLastLine = 0;
+ m_pTextView->clear( );
+}
+
+void PMPovrayOutputWidget::slotText( const QString& output )
+{
+ unsigned int i;
+
+ for( i = 0; i < output.length( ); i++ )
+ {
+ QChar c = output[i];
+ if( c == '\r' )
+ m_output.truncate( m_startOfLastLine );
+ else if( c == '\n' )
+ {
+ m_output += c;
+ m_startOfLastLine = m_output.length( );
+ //kdDebug( PMArea ) << m_startOfLastLine << endl;
+ }
+ else if( c.isPrint( ) )
+ m_output += c;
+ }
+
+ m_pTextView->setText( m_output );
+}
+
+void PMPovrayOutputWidget::slotClose( )
+{
+ hide( );
+}
+
+
+void PMPovrayOutputWidget::saveConfig( KConfig* cfg )
+{
+ cfg->setGroup( "Appearance" );
+ cfg->writeEntry( "PovrayOutputWidgetSize", s_size );
+}
+
+void PMPovrayOutputWidget::restoreConfig( KConfig* cfg )
+{
+ cfg->setGroup( "Appearance" );
+
+ QSize defaultSize( 500, 400 );
+ s_size = cfg->readSizeEntry( "PovrayOutputWidgetSize", &defaultSize );
+}
+
+void PMPovrayOutputWidget::resizeEvent( QResizeEvent* ev )
+{
+ s_size = ev->size( );
+}
+
+#include "pmpovrayoutputwidget.moc"
diff --git a/kpovmodeler/pmpovrayoutputwidget.h b/kpovmodeler/pmpovrayoutputwidget.h
new file mode 100644
index 00000000..faac7352
--- /dev/null
+++ b/kpovmodeler/pmpovrayoutputwidget.h
@@ -0,0 +1,77 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMPOVRAYOUTPUTWIDGET_H
+#define PMPOVRAYOUTPUTWIDGET_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include <kdialog.h>
+class QTextEdit;
+class KConfig;
+
+/**
+ * Widget to display the povray text output
+ */
+class PMPovrayOutputWidget : public KDialog
+{
+ Q_OBJECT
+public:
+ /**
+ * Standard constructor
+ */
+ PMPovrayOutputWidget( QWidget* parent = 0, const char* name = 0 );
+ /**
+ * Destructor
+ */
+ ~PMPovrayOutputWidget( );
+
+ static void saveConfig( KConfig* cfg );
+ static void restoreConfig( KConfig* cfg );
+
+public slots:
+ /**
+ * Clears the text
+ */
+ void slotClear( );
+ /**
+ * Adds the text to the output
+ */
+ void slotText( const QString& output );
+
+protected slots:
+ /**
+ * Called when the close button is clicked
+ */
+ void slotClose( );
+
+protected:
+ virtual void resizeEvent( QResizeEvent* ev );
+
+private:
+ QTextEdit* m_pTextView;
+ int m_startOfLastLine;
+ QString m_output;
+ static QSize s_size;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmpovrayparser.cpp b/kpovmodeler/pmpovrayparser.cpp
new file mode 100644
index 00000000..88bd8393
--- /dev/null
+++ b/kpovmodeler/pmpovrayparser.cpp
@@ -0,0 +1,7213 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmpovrayparser.h"
+
+#include <klocale.h>
+#include <qvaluelist.h>
+
+#include "pmpart.h"
+#include "pmscanner.h"
+#include "pmtokens.h"
+
+#include "pmcolor.h"
+#include "pmallobjects.h"
+#include "pmprototypemanager.h"
+#include "pmxmlhelper.h"
+
+
+PMPovrayParser::PMPovrayParser( PMPart* part, QIODevice* dev )
+ : PMParser( part, dev )
+{
+ init( );
+}
+
+PMPovrayParser::PMPovrayParser( PMPart* part, const QByteArray& array )
+ : PMParser( part, array )
+{
+ init( );
+}
+
+PMPovrayParser::~PMPovrayParser( )
+{
+ if( m_pScanner )
+ delete m_pScanner;
+}
+
+void PMPovrayParser::init( )
+{
+ m_pScanner = new PMScanner( m_pDevice );
+ m_consumedTokens = 0;
+ m_skippedComments.setAutoDelete( true );
+ m_bLastPMCommentEmpty = true;
+}
+
+
+void PMPovrayParser::nextToken( )
+{
+ m_token = m_pScanner->nextToken( );
+ m_consumedTokens++;
+ setCurrentLine( m_pScanner->currentLine( ) );
+
+ if( ( m_token == SCANNER_ERROR_TOK ) || ( m_token == COMMENT_TOK )
+ || ( m_token == LINE_COMMENT_TOK ) || ( m_token == PMNAME_TOK ) )
+ {
+ // create the objects (string) only if necessary
+ PMComment* c;
+ int lastCommentLine = -2;
+ QString commentText;
+
+ while( ( m_token == SCANNER_ERROR_TOK ) || ( m_token == COMMENT_TOK )
+ || ( m_token == LINE_COMMENT_TOK ) || ( m_token == PMNAME_TOK ) )
+ {
+ switch( m_token )
+ {
+ case SCANNER_ERROR_TOK:
+ printError( m_pScanner->error( ) );
+ lastCommentLine = -2;
+ break;
+ case LINE_COMMENT_TOK:
+ commentText = m_pScanner->sValue( );
+ if( lastCommentLine == ( m_pScanner->currentLine( ) - 1 ) )
+ {
+ c = m_skippedComments.last( );
+ if( c )
+ c->setText( c->text( ) + '\n' + commentText );
+ else
+ {
+ c = new PMComment( m_pPart, commentText );
+ m_skippedComments.append( c );
+ }
+ }
+ else
+ {
+ c = new PMComment( m_pPart, m_pScanner->sValue( ) );
+ m_skippedComments.append( c );
+ }
+ lastCommentLine = m_pScanner->currentLine( );
+ break;
+ case COMMENT_TOK:
+ c = new PMComment( m_pPart, m_pScanner->sValue( ) );
+ m_skippedComments.append( c );
+ lastCommentLine = -2;
+ break;
+ case PMNAME_TOK:
+ // Special comment
+ m_lastPMComment = m_pScanner->sValue( );
+ m_bLastPMCommentEmpty = false;
+ lastCommentLine = -2;
+ break;
+ default:
+ lastCommentLine = -2;
+ break;
+ }
+
+ m_token = m_pScanner->nextToken( );
+ m_consumedTokens++;
+ }
+ }
+}
+
+bool PMPovrayParser::isTrue( ) const
+{
+ if( ( m_token == ON_TOK ) || ( m_token == TRUE_TOK ) || ( m_token == YES_TOK ) )
+ return true;
+ return false;
+}
+
+bool PMPovrayParser::isFalse( ) const
+{
+ if( ( m_token == OFF_TOK ) || ( m_token == FALSE_TOK ) || ( m_token == NO_TOK ) )
+ return true;
+ return false;
+}
+
+void PMPovrayParser::topParse( )
+{
+ nextToken( );
+
+ do
+ {
+ if( !parseChildObjects( 0 ) )
+ m_token = EOF_TOK;
+ if( m_token != EOF_TOK )
+ {
+ printUnexpected( m_pScanner->sValue( ) );
+ nextToken( );
+ }
+ }
+ while( m_token != EOF_TOK );
+
+ if( errors( ) || warnings( ) )
+ printMessage( PMMSpecialRawComment );
+}
+
+bool PMPovrayParser::parseBool( )
+{
+ if( isFalse( ) )
+ {
+ nextToken( );
+ return false;
+ }
+ if( isTrue( ) )
+ {
+ nextToken( );
+ return true;
+ }
+
+ PMValue v;
+
+ if( parseNumericExpression( v, true ) )
+ {
+ switch( v.type( ) )
+ {
+ case PMVFloat:
+ return v.floatValue( ) > 0.0;
+ break;
+ case PMVVector:
+ return ( v.vector( ) )[0] > 0.0;
+ break;
+ default:
+ printError( i18n( "Boolean expression expected" ) );
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool PMPovrayParser::parseChildObjects( PMCompositeObject* parent,
+ int max /* = -1 */ )
+{
+ PMObject* child = 0;
+ bool finished = false;
+ bool error = false;
+ bool noChild = false;
+ int numParsed = 0;
+
+ do
+ {
+ if( !m_bLastPMCommentEmpty && parent )
+ {
+ if( parent->isA( "NamedObject" ) )
+ ( ( PMNamedObject* ) parent )->setName( m_lastPMComment );
+ m_bLastPMCommentEmpty = true;
+ }
+ if( m_skippedComments.count( ) > 0 )
+ child = m_skippedComments.take( 0 );
+ else
+ {
+ child = 0;
+ noChild = false;
+
+ // some objects
+ switch( m_token )
+ {
+ case UNION_TOK:
+ case DIFFERENCE_TOK:
+ case INTERSECTION_TOK:
+ case MERGE_TOK:
+ child = new PMCSG( m_pPart );
+ error = !parseCSG( ( PMCSG* ) child );
+ break;
+ case BOX_TOK:
+ child = new PMBox( m_pPart );
+ error = !parseBox( ( PMBox* ) child );
+ break;
+ case SPHERE_TOK:
+ if( ( parent && ( parent->type( ) == "Blob" ) )
+ || ( !parent && m_pTopParent
+ && ( m_pTopParent->type( ) == "Blob" ) ) )
+ {
+ child = new PMBlobSphere( m_pPart );
+ error = !parseBlobSphere( ( PMBlobSphere* ) child );
+ }
+ else
+ {
+ child = new PMSphere( m_pPart );
+ error = !parseSphere( ( PMSphere* ) child );
+ }
+ break;
+ case CYLINDER_TOK:
+ if( ( parent && ( parent->type( ) == "Blob" ) )
+ || ( !parent && m_pTopParent
+ && ( m_pTopParent->type( ) == "Blob" ) ) )
+ {
+ child = new PMBlobCylinder( m_pPart );
+ error = !parseBlobCylinder( ( PMBlobCylinder* ) child );
+ }
+ else
+ {
+ child = new PMCylinder( m_pPart );
+ error = !parseCylinder( ( PMCylinder* ) child );
+ }
+ break;
+ case CONE_TOK:
+ child = new PMCone( m_pPart );
+ error = !parseCone( ( PMCone* ) child );
+ break;
+ case TORUS_TOK:
+ child = new PMTorus( m_pPart );
+ error = !parseTorus( ( PMTorus* ) child );
+ break;
+ case BLOB_TOK:
+ child = new PMBlob( m_pPart );
+ error = !parseBlob( ( PMBlob* ) child );
+ break;
+ case COMPONENT_TOK:
+ child = new PMBlobSphere( m_pPart );
+ error = !parseBlobComponent( ( PMBlobSphere* ) child );
+ break;
+ case HEIGHT_FIELD_TOK:
+ child = new PMHeightField( m_pPart );
+ error = !parseHeightField( ( PMHeightField* ) child );
+ break;
+ case TEXT_TOK:
+ child = new PMText( m_pPart );
+ error = !parseText( ( PMText* ) child );
+ break;
+ case JULIA_FRACTAL_TOK:
+ child = new PMJuliaFractal( m_pPart );
+ error = !parseJuliaFractal( ( PMJuliaFractal* ) child );
+ break;
+ case PLANE_TOK:
+ child = new PMPlane( m_pPart );
+ error = !parsePlane( ( PMPlane* ) child );
+ break;
+ case QUADRIC_TOK:
+ case CUBIC_TOK:
+ case QUARTIC_TOK:
+ case POLY_TOK:
+ child = new PMPolynom( m_pPart );
+ error = !parsePolynom( ( PMPolynom* ) child );
+ break;
+ case BICUBIC_PATCH_TOK:
+ child = new PMBicubicPatch( m_pPart );
+ error = !parseBicubicPatch( ( PMBicubicPatch* ) child );
+ break;
+ case DISC_TOK:
+ child = new PMDisc( m_pPart );
+ error = !parseDisc( ( PMDisc* ) child );
+ break;
+ case TRIANGLE_TOK:
+ case SMOOTH_TRIANGLE_TOK:
+ child = new PMTriangle( m_pPart );
+ error = !parseTriangle( ( PMTriangle* ) child );
+ break;
+ case LATHE_TOK:
+ child = new PMLathe( m_pPart );
+ error = !parseLathe( ( PMLathe* ) child );
+ break;
+ case PRISM_TOK:
+ child = new PMPrism( m_pPart );
+ error = !parsePrism( ( PMPrism* ) child );
+ break;
+ case SOR_TOK:
+ child = new PMSurfaceOfRevolution( m_pPart );
+ error = !parseSor( ( PMSurfaceOfRevolution* ) child );
+ break;
+ case SUPERELLIPSOID_TOK:
+ child = new PMSuperquadricEllipsoid( m_pPart );
+ error = !parseSqe( ( PMSuperquadricEllipsoid* ) child );
+ break;
+ case CAMERA_TOK:
+ child = new PMCamera( m_pPart );
+ error = !parseCamera( ( PMCamera* ) child );
+ break;
+ case LIGHT_SOURCE_TOK:
+ child = new PMLight( m_pPart );
+ error = !parseLight( ( PMLight* ) child );
+ break;
+ case LOOKS_LIKE_TOK:
+ child = new PMLooksLike( m_pPart );
+ error = !parseLooksLike( ( PMLooksLike* ) child );
+ break;
+ case PROJECTED_THROUGH_TOK:
+ child = new PMProjectedThrough( m_pPart );
+ error = !parseProjectedThrough( ( PMProjectedThrough* ) child );
+ break;
+ case TEXTURE_TOK:
+ child = new PMTexture( m_pPart );
+ error = !parseTexture( ( PMTexture* ) child );
+ break;
+ case AGATE_TOK:
+ case AVERAGE_TOK:
+ case BOXED_TOK:
+ case BOZO_TOK:
+ case BUMPS_TOK:
+ case CELLS_TOK:
+ case CRACKLE_TOK:
+ case CYLINDRICAL_TOK:
+ case DENTS_TOK:
+ case DENSITY_FILE_TOK:
+ case GRADIENT_TOK:
+ case GRANITE_TOK:
+ case JULIA_TOK:
+ case LEOPARD_TOK:
+ case MAGNET_TOK:
+ case MANDEL_TOK:
+ case MARBLE_TOK:
+ case ONION_TOK:
+ case PLANAR_TOK:
+ case QUILTED_TOK:
+ case RADIAL_TOK:
+ case RIPPLES_TOK:
+ case SLOPE_TOK:
+ case SPHERICAL_TOK:
+ case SPIRAL1_TOK:
+ case SPIRAL2_TOK:
+ case SPOTTED_TOK:
+ case WOOD_TOK:
+ case WAVES_TOK:
+ case WRINKLES_TOK:
+ child = new PMPattern( m_pPart );
+ {
+ bool normal = true;
+ if( parent && ( parent->type( ) != "Normal" ) )
+ normal = false;
+ error = !parsePattern( ( PMPattern* ) child, normal );
+ }
+ break;
+ case TURBULENCE_TOK:
+ // Search for a PMPattern in the object's children
+ child = parent->firstChild( );
+ while( child && !child->isA( "Pattern" ) )
+ child = child->nextSibling( );
+ if( child )
+ {
+ error = !parsePattern( ( PMPattern* ) child );
+ child = 0;
+ noChild = true;
+ }
+ else
+ {
+ printError( i18n( "Found turbulence without a pattern." ) );
+ error = true;
+ }
+ break;
+ case FREQUENCY_TOK:
+ case PHASE_TOK:
+ case RAMP_WAVE_TOK:
+ case TRIANGLE_WAVE_TOK:
+ case SINE_WAVE_TOK:
+ case SCALLOP_WAVE_TOK:
+ case CUBIC_WAVE_TOK:
+ case POLY_WAVE_TOK:
+ // Search for a PMBlendMapModifiers in the object's children
+ child = parent->firstChild( );
+ while( child && !child->isA( "BlendMapModifiers" ) )
+ child = child->nextSibling( );
+ if( child )
+ {
+ error = !parseBlendMapModifiers( ( PMBlendMapModifiers* ) child );
+ child = 0;
+ noChild = 0;
+ }
+ else
+ {
+ child = new PMBlendMapModifiers( m_pPart );
+ error = !parseBlendMapModifiers( ( PMBlendMapModifiers* ) child );
+ }
+ break;
+ case WARP_TOK:
+ child = new PMWarp( m_pPart );
+ error = !parseWarp( ( PMWarp* ) child );
+ break;
+ case PIGMENT_TOK:
+ child = new PMPigment( m_pPart );
+ error = !parsePigment( ( PMPigment* ) child );
+ break;
+ case NORMAL_TOK:
+ child = new PMNormal( m_pPart );
+ error = !parseNormal( ( PMNormal* ) child );
+ break;
+ case NORMAL_MAP_TOK:
+ child = new PMNormalMap( m_pPart );
+ error = !parseNormalMap( ( PMNormalMap* ) child );
+ break;
+ case BUMP_MAP_TOK:
+ child = new PMBumpMap( m_pPart );
+ error = !parseBumpMap( ( PMBumpMap* ) child );
+ break;
+ case SLOPE_MAP_TOK:
+ child = new PMSlopeMap( m_pPart );
+ error = !parseSlopeMap( ( PMSlopeMap* ) child );
+ break;
+ case DENSITY_MAP_TOK:
+ child = new PMDensityMap( m_pPart );
+ error = !parseDensityMap( ( PMDensityMap* ) child );
+ break;
+ case TEXTURE_MAP_TOK:
+ child = new PMTextureMap( m_pPart );
+ error = !parseTextureMap( ( PMTextureMap* ) child );
+ break;
+ case MATERIAL_MAP_TOK:
+ child = new PMMaterialMap( m_pPart );
+ error = !parseMaterialMap( ( PMMaterialMap* ) child );
+ break;
+ case PIGMENT_MAP_TOK:
+ child = new PMPigmentMap( m_pPart );
+ error = !parsePigmentMap( ( PMPigmentMap* ) child );
+ break;
+ case COLOR_MAP_TOK:
+ case COLOUR_MAP_TOK:
+ child = new PMColorMap( m_pPart );
+ error = !parseColorMap( ( PMColorMap* ) child );
+ break;
+ case CHECKER_TOK:
+ case HEXAGON_TOK:
+ case BRICK_TOK:
+ {
+ bool normal = false;
+ double depth = 0.0;
+ int expect = 0;
+ PMListPattern::PMListType type = PMListPattern::ListPatternChecker;
+
+ if( parent && parent->type( ) == "Normal" )
+ normal = true;
+ else if( m_pTopParent && m_pTopParent->type( ) == "Normal" )
+ normal = true;
+
+ switch( m_token )
+ {
+ case CHECKER_TOK:
+ type = PMListPattern::ListPatternChecker;
+ expect = 2;
+ break;
+ case HEXAGON_TOK:
+ type = PMListPattern::ListPatternHexagon;
+ expect = 3;
+ break;
+ case BRICK_TOK:
+ type = PMListPattern::ListPatternBrick;
+ expect = 2;
+ break;
+ }
+ nextToken( );
+
+ if( normal )
+ {
+ child = new PMNormalList( m_pPart );
+ if( parseFloat( depth, true ) )
+ ( ( PMNormalList* ) child )->setDepth( depth );
+
+ if( m_token == NORMAL_TOK )
+ error = !parseNormalList( ( PMNormalList* ) child, expect );
+ }
+ else
+ {
+ switch( m_token )
+ {
+ case COLOR_TOK:
+ case COLOUR_TOK:
+ case RGB_TOK:
+ case RGBT_TOK:
+ case RGBF_TOK:
+ case RGBFT_TOK:
+ case RED_TOK:
+ case GREEN_TOK:
+ case BLUE_TOK:
+ case TRANSMIT_TOK:
+ case FILTER_TOK:
+ case ID_TOK:
+ child = new PMColorList( m_pPart );
+ error = !parseColorList( ( PMColorList* ) child, expect );
+ break;
+ case PIGMENT_TOK:
+ child = new PMPigmentList( m_pPart );
+ error = !parsePigmentList( ( PMPigmentList* ) child, expect );
+ break;
+ case TEXTURE_TOK:
+ child = new PMTextureList( m_pPart );
+ error = !parseTextureList( ( PMTextureList* ) child, expect );
+ break;
+ case NORMAL_TOK:
+ child = new PMNormalList( m_pPart );
+ error = !parseNormalList( ( PMNormalList* ) child, expect );
+ break;
+ case DENSITY_TOK:
+ child = new PMDensityList( m_pPart );
+ error = !parseDensityList( ( PMDensityList* ) child, expect );
+ break;
+ default:
+ printError( i18n( "Invalid list member." ) );
+ error = true;
+ }
+ }
+
+ if( child )
+ {
+ ( ( PMListPattern* ) child )->setListType( type );
+
+ int oldConsumed;
+ double num = 0;
+ PMVector vector;
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ switch( m_token )
+ {
+ case MORTAR_TOK:
+ nextToken( );
+ if( !parseFloat( num ) )
+ return false;
+ ( ( PMListPattern* ) child )->setMortar( num );
+ break;
+ case BRICK_SIZE_TOK:
+ nextToken( );
+ if( !parseVector( vector ) )
+ return false;
+ ( ( PMListPattern* ) child )->setBrickSize( vector );
+ break;
+ default:
+ break;
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+ }
+ break;
+ }
+ case IMAGE_MAP_TOK:
+ child = new PMImageMap( m_pPart );
+ error = !parseImageMap( ( PMImageMap* ) child );
+ break;
+ case FINISH_TOK:
+ child = new PMFinish( m_pPart );
+ error = !parseFinish( ( PMFinish* ) child );
+ break;
+ case INTERIOR_TOK:
+ child = new PMInterior( m_pPart );
+ error = !parseInterior( ( PMInterior* ) child );
+ break;
+ case MEDIA_TOK:
+ child = new PMMedia( m_pPart );
+ error = !parseMedia( ( PMMedia* ) child );
+ break;
+ case DENSITY_TOK:
+ child = new PMDensity( m_pPart );
+ error = !parseDensity( ( PMDensity* ) child );
+ break;
+ case MATERIAL_TOK:
+ child = new PMMaterial( m_pPart );
+ error = !parseMaterial( ( PMMaterial* ) child );
+ break;
+ case SKY_SPHERE_TOK:
+ child = new PMSkySphere( m_pPart );
+ error = !parseSkySphere( ( PMSkySphere* ) child );
+ break;
+ case RAINBOW_TOK:
+ child = new PMRainbow( m_pPart );
+ error = !parseRainbow( ( PMRainbow* ) child );
+ break;
+ case FOG_TOK:
+ child = new PMFog( m_pPart );
+ error = !parseFog( ( PMFog* ) child );
+ break;
+ case GLOBAL_SETTINGS_TOK:
+ child = new PMGlobalSettings( m_pPart );
+ error = !parseGlobalSettings( ( PMGlobalSettings* ) child );
+ break;
+ case SCALE_TOK:
+ child = new PMScale( m_pPart );
+ error = !parseScale( ( PMScale* ) child );
+ break;
+ case ROTATE_TOK:
+ child = new PMRotate( m_pPart );
+ error = !parseRotate( ( PMRotate* ) child );
+ break;
+ case TRANSLATE_TOK:
+ child = new PMTranslate( m_pPart );
+ error = !parseTranslate( ( PMTranslate* ) child );
+ break;
+ case MATRIX_TOK:
+ child = new PMPovrayMatrix( m_pPart );
+ error = !parseMatrix( ( PMPovrayMatrix* ) child );
+ break;
+ case BOUNDED_BY_TOK:
+ if( parent && ( parent->type( ) == "ClippedBy" ) )
+ finished = true;
+ else
+ {
+ child = new PMBoundedBy( m_pPart );
+ error = !parseBoundedBy( ( PMBoundedBy* ) child );
+ }
+ break;
+ case CLIPPED_BY_TOK:
+ if( parent && ( parent->type( ) == "BoundedBy" ) )
+ finished = true;
+ else
+ {
+ child = new PMClippedBy( m_pPart );
+ error = !parseClippedBy( ( PMClippedBy* ) child );
+ }
+ break;
+ case ISOSURFACE_TOK:
+ child = new PMIsoSurface( m_pPart );
+ error = !parseIsoSurface( ( PMIsoSurface* ) child );
+ break;
+ case RADIOSITY_TOK:
+ child = new PMRadiosity( m_pPart );
+ error = !parseRadiosity( ( PMRadiosity* ) child );
+ break;
+ case PHOTONS_TOK:
+ if ( parent && ( parent->type( ) == "GlobalSettings" ) )
+ {
+ child = new PMGlobalPhotons( m_pPart );
+ error = !parseGlobalPhotons( ( PMGlobalPhotons* ) child );
+ }
+ else
+ {
+ child = new PMPhotons( m_pPart );
+ error =!parsePhotons( ( PMPhotons* ) child );
+ }
+ break;
+ case LIGHT_GROUP_TOK:
+ child = new PMLightGroup( m_pPart );
+ error = !parseLightGroup( ( PMLightGroup* ) child );
+ break;
+ case INTERIOR_TEXTURE_TOK:
+ child = new PMInteriorTexture( m_pPart );
+ error = !parseInteriorTexture( ( PMInteriorTexture* ) child );
+ break;
+ case SPHERE_SWEEP_TOK:
+ child = new PMSphereSweep( m_pPart );
+ error = !parseSphereSweep( ( PMSphereSweep* ) child );
+ break;
+ case MESH_TOK:
+ child = new PMMesh( m_pPart );
+ error = !parseMesh( ( PMMesh* ) child );
+ break;
+ case DECLARE_TOK:
+ nextToken( );
+ if( m_token == ID_TOK )
+ {
+ QString id( m_pScanner->sValue( ) );
+ nextToken( );
+
+ if( !parseToken( '=' ) )
+ error = true;
+ else
+ {
+ PMValue v;
+ switch( m_token )
+ {
+ case OBJECT_TOK:
+ // finite solid
+ case BLOB_TOK:
+ case BOX_TOK:
+ case CONE_TOK:
+ case CYLINDER_TOK:
+ case HEIGHT_FIELD_TOK:
+ case JULIA_FRACTAL_TOK:
+ case LATHE_TOK:
+ case PRISM_TOK:
+ case SPHERE_TOK:
+ case SUPERELLIPSOID_TOK:
+ case SOR_TOK:
+ case TEXT_TOK:
+ case TORUS_TOK:
+ case ISOSURFACE_TOK:
+ case SPHERE_SWEEP_TOK:
+ // finite patch
+ case BICUBIC_PATCH_TOK:
+ case DISC_TOK:
+ case MESH_TOK:
+ case POLYGON_TOK:
+ case TRIANGLE_TOK:
+ case SMOOTH_TRIANGLE_TOK:
+ // infinite solid
+ case PLANE_TOK:
+ case QUADRIC_TOK:
+ case CUBIC_TOK:
+ case QUARTIC_TOK:
+ case POLY_TOK:
+ // csg
+ case UNION_TOK:
+ case INTERSECTION_TOK:
+ case DIFFERENCE_TOK:
+ case MERGE_TOK:
+ // textures
+ case TEXTURE_TOK:
+ case INTERIOR_TEXTURE_TOK:
+ case PIGMENT_TOK:
+ case NORMAL_TOK:
+ case FINISH_TOK:
+ case TEXTURE_MAP_TOK:
+ case PIGMENT_MAP_TOK:
+ case COLOR_MAP_TOK:
+ case COLOUR_MAP_TOK:
+ case NORMAL_MAP_TOK:
+ case SLOPE_MAP_TOK:
+ case DENSITY_MAP_TOK:
+ case INTERIOR_TOK:
+ case MEDIA_TOK:
+ case DENSITY_TOK:
+ case MATERIAL_TOK:
+ case SKY_SPHERE_TOK:
+ case RAINBOW_TOK:
+ case FOG_TOK:
+ // misc
+ case LIGHT_SOURCE_TOK:
+ case LIGHT_GROUP_TOK:
+ child = new PMDeclare( m_pPart );
+ error = !parseDeclare( ( PMDeclare* ) child );
+ break;
+ default:
+ // constant, vector or color declare?
+ if( parseNumericExpression( v ) )
+ {
+ checkID( id, v );
+ noChild = true;
+ }
+ else
+ error = true;
+ break;
+ }
+ }
+
+ if( child )
+ if( child->isA( "Declare" ) )
+ ( ( PMDeclare* ) child )->setID( id );
+ if( m_token == ';' )
+ nextToken( );
+ }
+ else
+ printExpected( i18n( "identifier" ), m_pScanner->sValue( ) );
+ break;
+ case OBJECT_TOK:
+ error = !parseObject( parent );
+ noChild = true;
+ break;
+ case RAW_POVRAY_TOK:
+ child = new PMRaw( m_pPart, m_pScanner->sValue( ) );
+ error = false;
+ nextToken( );
+ break;
+ default:
+ finished = true;
+ break;
+ }
+ }
+ if( !finished && !child && !noChild )
+ error = true;
+ if( child )
+ {
+ if( !insertChild( child, parent ) )
+ {
+ delete child;
+ child = 0;
+ }
+ else if( child->isA( "Declare" ) )
+ checkID( ( PMDeclare* ) child );
+ numParsed ++;
+ if( ( max > 0 ) && ( numParsed >= max ) )
+ finished = true;
+ }
+ }
+ while( !finished && !error );
+
+ return finished;
+}
+
+bool PMPovrayParser::parseToken( int t, const QString& tokenName )
+{
+ if( t == ',' )
+ {
+ // do not require commas any more.
+ if( m_token == ',' )
+ nextToken( );
+ return true;
+ }
+ else if( m_token == t )
+ {
+ nextToken( );
+ return true;
+ }
+
+ if( tokenName.isNull() )
+ printExpected( ( char ) t, m_pScanner->sValue( ) );
+ else
+ printExpected( tokenName, m_pScanner->sValue( ) );
+ return false;
+}
+
+bool PMPovrayParser::parseNumericItem( PMValue& v, bool checkForBool /*=false*/ )
+{
+ bool finishColor = false;
+ PMVector cv( 0 );
+ PMVector vec( 0 );
+ PMValue hv;
+ PMSymbol* s;
+ int i;
+
+ switch( m_token )
+ {
+ case X_TOK:
+ v.setVector( PMVector( 1.0, 0.0, 0.0 ) );
+ nextToken( );
+ break;
+ case Y_TOK:
+ v.setVector( PMVector( 0.0, 1.0, 0.0 ) );
+ nextToken( );
+ break;
+ case Z_TOK:
+ v.setVector( PMVector( 0.0, 0.0, 1.0 ) );
+ nextToken( );
+ break;
+ case T_TOK:
+ v.setVector( PMVector( 0.0, 0.0, 0.0, 1.0 ) );
+ nextToken( );
+ break;
+ case U_TOK:
+ v.setVector( PMVector( 1.0, 0.0 ) );
+ nextToken( );
+ break;
+ case V_TOK:
+ v.setVector( PMVector( 0.0, 1.0 ) );
+ nextToken( );
+ break;
+ case PI_TOK:
+ v.setFloat( 3.1415926535897932384626 );
+ nextToken( );
+ break;
+ case CLOCK_TOK:
+ printMessage( PMMClockDefault );
+ v.setFloat( 0.0 );
+ break;
+ case CLOCK_DELTA_TOK:
+ printMessage( PMMClockDeltaDefault );
+ v.setFloat( 1.0 );
+ break;
+ case FLOAT_TOK:
+ v.setFloat( m_pScanner->fValue( ) );
+ nextToken( );
+ break;
+ case INTEGER_TOK:
+ v.setFloat( ( double ) m_pScanner->iValue( ) );
+ nextToken( );
+ break;
+ case ON_TOK:
+ case TRUE_TOK:
+ case YES_TOK:
+ v.setFloat( 1.0 );
+ nextToken( );
+ break;
+ case OFF_TOK:
+ case FALSE_TOK:
+ case NO_TOK:
+ v.setFloat( 0.0 );
+ nextToken( );
+ break;
+ case '(':
+ nextToken( );
+ if( !parseNumericExpression( v ) )
+ return false;
+ if( !parseToken( ')' ) )
+ return false;
+ break;
+ case '-':
+ nextToken( );
+ if( !parseNumericItem( v ) )
+ return false;
+ if( v.type( ) == PMVFloat )
+ v.setFloat( -v.floatValue( ) );
+ else
+ v.setVector( -v.vector( ) );
+ break;
+ case '+':
+ nextToken( );
+ if( !parseNumericItem( v ) )
+ return false;
+ break;
+ case '<':
+ if( !parseVectorLiteral( vec ) )
+ return false;
+ v.setVector( vec );
+ break;
+ case COLOR_TOK:
+ case COLOUR_TOK:
+ nextToken( );
+ case RGB_TOK:
+ case RGBT_TOK:
+ case RGBF_TOK:
+ case RGBFT_TOK:
+ case RED_TOK:
+ case GREEN_TOK:
+ case BLUE_TOK:
+ case TRANSMIT_TOK:
+ case FILTER_TOK:
+ cv.resize( 5 );
+ cv = 0.0;
+ finishColor = true;
+ break;
+ case ID_TOK:
+ s = getSymbol( m_pScanner->sValue( ) );
+ if( s )
+ {
+ nextToken( );
+ if( s->type( ) == PMSymbol::Value )
+ v = s->value( );
+ else
+ {
+ printError( i18n( "Float, color or vector identifier expected." ) );
+ return false;
+ }
+ }
+ else
+ {
+ printError( i18n( "Undefined identifier \"%1\"." )
+ .arg( m_pScanner->sValue( ) ) );
+ nextToken( );
+ }
+ break;
+ default:
+ if( !checkForBool )
+ printUnexpected( m_pScanner->sValue( ) );
+ return false;
+ break;
+ }
+
+ if( !finishColor )
+ {
+ if( m_token == '.' )
+ {
+ int index = -1;
+ nextToken( );
+
+ switch( m_token )
+ {
+ case X_TOK:
+ case RED_TOK:
+ case U_TOK:
+ index = 0;
+ break;
+ case Y_TOK:
+ case GREEN_TOK:
+ case V_TOK:
+ index = 1;
+ break;
+ case Z_TOK:
+ case BLUE_TOK:
+ index = 2;
+ break;
+ case T_TOK:
+ case FILTER_TOK:
+ index = 3;
+ break;
+ case TRANSMIT_TOK:
+ index = 4;
+ break;
+ default:
+ break;
+ }
+ if( index >= 0 )
+ {
+ nextToken( );
+ if( v.type( ) == PMVFloat )
+ {
+ if( index != 0 )
+ index = -1;
+ }
+ else
+ {
+ PMVector vec;
+ if( v.type( ) == PMVVector )
+ vec = v.vector( );
+ else
+ vec = v.color( );
+
+ if( ( ( unsigned ) index ) < vec.size( ) )
+ v.setFloat( vec[index] );
+ else
+ index = -1;
+ }
+ }
+ if( index == -1 )
+ {
+ printError( i18n( "Bad operands for period operator." ) );
+ return false;
+ }
+ }
+ }
+
+ while( finishColor )
+ {
+ switch( m_token )
+ {
+ case RGB_TOK:
+ nextToken( );
+ if( !parseNumericExpression( hv ) )
+ return false;
+ switch( hv.type( ) )
+ {
+ case PMVFloat:
+ cv[0] = hv.floatValue( );
+ cv[1] = hv.floatValue( );
+ cv[2] = hv.floatValue( );
+ break;
+ case PMVVector:
+ vec = hv.vector( );
+ vec.resize( 3 );
+ cv[0] = vec[0];
+ cv[1] = vec[1];
+ cv[2] = vec[2];
+ break;
+ default:
+ printError( i18n( "Float or vector expression expected" ) );
+ break;
+ }
+ break;
+ case RGBT_TOK:
+ nextToken( );
+ if( !parseNumericExpression( hv ) )
+ return false;
+ switch( hv.type( ) )
+ {
+ case PMVFloat:
+ cv[0] = hv.floatValue( );
+ cv[1] = hv.floatValue( );
+ cv[2] = hv.floatValue( );
+ cv[4] = hv.floatValue( );
+ break;
+ case PMVVector:
+ vec = hv.vector( );
+ vec.resize( 4 );
+ cv[0] = vec[0];
+ cv[1] = vec[1];
+ cv[2] = vec[2];
+ cv[4] = vec[3];
+ break;
+ default:
+ printError( i18n( "Float or vector expression expected" ) );
+ break;
+ }
+ break;
+ case RGBF_TOK:
+ nextToken( );
+ if( !parseNumericExpression( hv ) )
+ return false;
+ switch( hv.type( ) )
+ {
+ case PMVFloat:
+ cv[0] = hv.floatValue( );
+ cv[1] = hv.floatValue( );
+ cv[2] = hv.floatValue( );
+ cv[3] = hv.floatValue( );
+ break;
+ case PMVVector:
+ vec = hv.vector( );
+ vec.resize( 4 );
+ cv[0] = vec[0];
+ cv[1] = vec[1];
+ cv[2] = vec[2];
+ cv[3] = vec[3];
+ break;
+ default:
+ printError( i18n( "Float or vector expression expected" ) );
+ break;
+ }
+ break;
+ case RGBFT_TOK:
+ nextToken( );
+ if( !parseNumericExpression( hv ) )
+ return false;
+ switch( hv.type( ) )
+ {
+ case PMVFloat:
+ cv = hv.floatValue( );
+ break;
+ case PMVVector:
+ vec = hv.vector( );
+ vec.resize( 5 );
+ cv = vec;
+ break;
+ default:
+ printError( i18n( "Float or vector expression expected" ) );
+ break;
+ }
+ break;
+ case RED_TOK:
+ nextToken( );
+ parseNumericExpression( hv );
+ if( hv.type( ) != PMVFloat )
+ {
+ printError( i18n( "Float expression expected" ) );
+ break;
+ }
+ cv[0] = hv.floatValue( );
+ break;
+ case GREEN_TOK:
+ nextToken( );
+ parseNumericExpression( hv );
+ if( hv.type( ) != PMVFloat )
+ {
+ printError( i18n( "Float expression expected" ) );
+ break;
+ }
+ cv[1] = hv.floatValue( );
+ break;
+ case BLUE_TOK:
+ nextToken( );
+ parseNumericExpression( hv );
+ if( hv.type( ) != PMVFloat )
+ {
+ printError( i18n( "Float expression expected" ) );
+ break;
+ }
+ cv[2] = hv.floatValue( );
+ break;
+ case FILTER_TOK:
+ case ALPHA_TOK:
+ nextToken( );
+ parseNumericExpression( hv );
+ if( hv.type( ) != PMVFloat )
+ {
+ printError( i18n( "Float expression expected" ) );
+ break;
+ }
+ cv[3] = hv.floatValue( );
+ break;
+ case TRANSMIT_TOK:
+ nextToken( );
+ parseNumericExpression( hv );
+ if( hv.type( ) != PMVFloat )
+ {
+ printError( i18n( "Float expression expected" ) );
+ break;
+ }
+ cv[4] = hv.floatValue( );
+ break;
+ case ID_TOK:
+ if( parseNumericItem( hv ) )
+ {
+ if( hv.type( ) == PMVFloat )
+ {
+ for( i = 0; i < 5; i++ )
+ cv[i] = hv.floatValue( );
+ }
+ else if( hv.type( ) == PMVVector )
+ {
+ cv = hv.vector( );
+ cv.resize( 5 );
+ }
+ else
+ cv = hv.color( );
+ }
+ break;
+ default:
+ finishColor = false;
+ v.setColor( cv );
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool PMPovrayParser::parseVectorLiteral( PMVector& p )
+{
+ PMValue v;
+
+ if( !parseToken( '<' ) )
+ return false;
+ if( !parseNumericExpression( v ) )
+ return false;
+
+ if( v.type( ) != PMVFloat )
+ {
+ printError( i18n( "Float expression expected" ) );
+ return false;
+ }
+
+ p.resize( 1 );
+ p[0] = v.floatValue( );
+
+ while( m_token != '>' )
+ {
+ // many old scenes do not use a comma between values
+ if( m_token == ',' )
+ nextToken( );
+ // parseToken( ',' );
+ if( !parseNumericExpression( v ) )
+ return false;
+
+ if( v.type( ) != PMVFloat )
+ {
+ printError( i18n( "Float expression expected" ) );
+ return false;
+ }
+
+ p.resize( p.size( ) + 1 );
+ p[p.size( ) - 1] = v.floatValue( );
+ }
+
+ /** old code
+ while( m_token == ',' )
+ {
+ nextToken( );
+ if( !parseNumericExpression( v ) )
+ return false;
+
+ if( v.type( ) != PMVFloat )
+ {
+ printError( i18n( "Float expression expected" ) );
+ return false;
+ }
+
+ p.resize( p.size( ) + 1 );
+ p[p.size( ) - 1] = v.floatValue( );
+ }
+ */
+
+ if( !parseToken( '>' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseNumericExpression( PMValue& v, bool checkForBool /*=false*/ )
+{
+ bool end = false;
+ PMValue v2;
+ PMVector hv( 0 );
+
+ if( !parseNumericItem( v, checkForBool ) )
+ return false;
+
+ do
+ {
+ switch( m_token )
+ {
+ case '*':
+ nextToken( );
+ if( !parseNumericItem( v2 ) )
+ break;
+ switch( v.type( ) )
+ {
+ case PMVFloat:
+ switch( v2.type( ) )
+ {
+ case PMVFloat:
+ v.setFloat( v.floatValue( ) * v2.floatValue( ) );
+ break;
+ case PMVVector:
+ v.setVector( v2.vector( ) * v.floatValue( ) );
+ break;
+ case PMVColor:
+ v.setColor( v2.color( ) * v.floatValue( ) );
+ break;
+ }
+ break;
+ case PMVVector:
+ switch( v2.type( ) )
+ {
+ case PMVFloat:
+ v.setVector( v.vector( ) * v2.floatValue( ) );
+ break;
+ case PMVVector:
+ v.setVector( v.vector( ) * v2.vector( ) );
+ break;
+ case PMVColor:
+ if( v.vector( ).size( ) == 5 )
+ v.setColor( v.vector( ) * v2.color( ) );
+ else
+ printError( i18n( "You can't multiply a vector with a color" ) );
+ break;
+ }
+ break;
+ case PMVColor:
+ switch( v2.type( ) )
+ {
+ case PMVFloat:
+ v.setColor( v.color( ) * v2.floatValue( ) );
+ break;
+ case PMVVector:
+ if( v2.vector( ).size( ) == 5 )
+ v.setColor( v2.vector( ) * v.color( ) );
+ else
+ printError( i18n( "You can't multiply a vector with a color" ) );
+ break;
+ case PMVColor:
+ v.setColor( v.color( ) * v2.color( ) );
+ break;
+ }
+ break;
+ }
+ break;
+ case '/':
+ nextToken( );
+ if( !parseNumericItem( v2 ) )
+ break;
+ switch( v.type( ) )
+ {
+ case PMVFloat:
+ switch( v2.type( ) )
+ {
+ case PMVFloat:
+ v.setFloat( v.floatValue( ) / v2.floatValue( ) );
+ break;
+ case PMVVector:
+ hv.resize( v2.vector( ).size( ) );
+ hv = v.floatValue( );
+ v.setVector( hv / v2.vector( ) );
+ break;
+ case PMVColor:
+ hv.resize( 5 );
+ hv = v.floatValue( );
+ v.setColor( hv / v.floatValue( ) );
+ break;
+ }
+ break;
+ case PMVVector:
+ switch( v2.type( ) )
+ {
+ case PMVFloat:
+ v.setVector( v.vector( ) / v2.floatValue( ) );
+ break;
+ case PMVVector:
+ v.setVector( v.vector( ) / v2.vector( ) );
+ break;
+ case PMVColor:
+ if( v.vector( ).size( ) == 5 )
+ v.setColor( v.vector( ) / v2.color( ) );
+ else
+ printError( i18n( "You can't divide a vector by a color" ) );
+ break;
+ }
+ break;
+ case PMVColor:
+ switch( v2.type( ) )
+ {
+ case PMVFloat:
+ v.setColor( v.color( ) / v2.floatValue( ) );
+ break;
+ case PMVVector:
+ if( v2.vector( ).size( ) == 5 )
+ v.setColor( v2.vector( ) / v.color( ) );
+ else
+ printError( i18n( "You can't divide a color by a vector" ) );
+ break;
+ case PMVColor:
+ v.setColor( v.color( ) / v2.color( ) );
+ break;
+ }
+ break;
+ }
+ break;
+ case '+':
+ nextToken( );
+ if( !parseNumericExpression( v2 ) )
+ break;
+ switch( v.type( ) )
+ {
+ case PMVFloat:
+ switch( v2.type( ) )
+ {
+ case PMVFloat:
+ v.setFloat( v.floatValue( ) + v2.floatValue( ) );
+ break;
+ case PMVVector:
+ v.setVector( v2.vector( ) + v.floatValue( ) );
+ break;
+ case PMVColor:
+ v.setColor( v2.color( ) + v.floatValue( ) );
+ break;
+ }
+ break;
+ case PMVVector:
+ switch( v2.type( ) )
+ {
+ case PMVFloat:
+ v.setVector( v.vector( ) + v2.floatValue( ) );
+ break;
+ case PMVVector:
+ v.setVector( v.vector( ) + v2.vector( ) );
+ break;
+ case PMVColor:
+ if( v.vector( ).size( ) == 5 )
+ v.setColor( v.vector( ) + v2.color( ) );
+ else
+ printError( i18n( "You can't add a vector and a color" ) );
+ break;
+ }
+ break;
+ case PMVColor:
+ switch( v2.type( ) )
+ {
+ case PMVFloat:
+ v.setColor( v.color( ) + v2.floatValue( ) );
+ break;
+ case PMVVector:
+ if( v2.vector( ).size( ) == 5 )
+ v.setColor( v2.vector( ) + v.color( ) );
+ else
+ printError( i18n( "You can't add a vector with a color" ) );
+ break;
+ case PMVColor:
+ v.setColor( v.color( ) + v2.color( ) );
+ break;
+ }
+ break;
+ }
+ break;
+ case '-':
+ nextToken( );
+ if( !parseNumericExpression( v2 ) )
+ break;
+ switch( v.type( ) )
+ {
+ case PMVFloat:
+ switch( v2.type( ) )
+ {
+ case PMVFloat:
+ v.setFloat( v.floatValue( ) - v2.floatValue( ) );
+ break;
+ case PMVVector:
+ v.setVector( v2.vector( ) - v.floatValue( ) );
+ break;
+ case PMVColor:
+ v.setColor( v2.color( ) - v.floatValue( ) );
+ break;
+ }
+ break;
+ case PMVVector:
+ switch( v2.type( ) )
+ {
+ case PMVFloat:
+ v.setVector( v.vector( ) - v2.floatValue( ) );
+ break;
+ case PMVVector:
+ v.setVector( v.vector( ) - v2.vector( ) );
+ break;
+ case PMVColor:
+ if( v.vector( ).size( ) == 5 )
+ v.setColor( v.vector( ) - v2.color( ) );
+ else
+ printError( i18n( "You can't subtract a vector and a color" ) );
+ break;
+ }
+ break;
+ case PMVColor:
+ switch( v2.type( ) )
+ {
+ case PMVFloat:
+ v.setColor( v.color( ) - v2.floatValue( ) );
+ break;
+ case PMVVector:
+ if( v2.vector( ).size( ) == 5 )
+ v.setColor( v2.vector( ) - v.color( ) );
+ else
+ printError( i18n( "You can't subtract a vector and a color" ) );
+ break;
+ case PMVColor:
+ v.setColor( v.color( ) - v2.color( ) );
+ break;
+ }
+ break;
+ }
+ break;
+ default:
+ end = true;
+ break;
+ }
+ }
+ while( !end );
+
+ return true;
+}
+
+bool PMPovrayParser::parseVector( PMVector& vector, unsigned int size )
+{
+ PMValue v;
+ unsigned int i;
+
+ if( !parseNumericExpression( v ) )
+ return false;
+
+ switch( v.type( ) )
+ {
+ case PMVFloat:
+ vector.resize( size );
+ for( i = 0; i < size; i++ )
+ vector[i] = v.floatValue( );
+ break;
+ case PMVVector:
+ vector = v.vector( );
+ vector.resize( size );
+ break;
+ default:
+ printError( i18n( "Float or vector expression expected" ) );
+ return false;
+ }
+ return true;
+}
+
+bool PMPovrayParser::parseFloat( double& d, bool suppressError )
+{
+ PMValue v;
+
+ if( !parseNumericExpression( v, suppressError ) )
+ return false;
+
+ switch( v.type( ) )
+ {
+ case PMVFloat:
+ d = v.floatValue( );
+ break;
+ case PMVVector:
+ d = ( v.vector( ) )[0];
+ break;
+ default:
+ printError( i18n( "Float expression expected" ) );
+ return false;
+ }
+ return true;
+}
+
+bool PMPovrayParser::parseInt( int& i )
+{
+ double d;
+
+ if( !parseFloat( d ) )
+ return false;
+
+ i = ( int ) ( d + 0.5 );
+ return true;
+}
+
+bool PMPovrayParser::parseColor( PMColor& c )
+{
+ PMValue v;
+
+ if( !parseNumericExpression( v ) )
+ return false;
+
+ if( v.type( ) == PMVColor )
+ c = PMColor( v.color( ) );
+ else if( v.type( ) == PMVVector )
+ {
+ if( v.vector( ).size( ) == 5 )
+ c = PMColor( v.vector( ) );
+ else
+ {
+ printError( i18n( "Color expression expected" ) );
+ return false;
+ }
+ }
+ else if( v.type( ) == PMVFloat )
+ {
+ double d = v.floatValue( );
+ c = PMColor( d, d, d, d, d );
+ }
+ else
+ {
+ printError( i18n( "Color expression expected" ) );
+ return false;
+ }
+
+ return true;
+}
+
+bool PMPovrayParser::parseObjectModifiers( PMGraphicalObject* o )
+{
+ bool finished = false;
+
+ PMSolidObject* so = 0;
+ if( o->isA( "SolidObject" ) )
+ so = ( PMSolidObject* ) o;
+
+ do
+ {
+ finished = true;
+ switch( m_token )
+ {
+ case NO_SHADOW_TOK:
+ o->setNoShadow( true );
+ nextToken( );
+ finished = false;
+ break;
+ case NO_IMAGE_TOK:
+ o->setNoImage( true );
+ nextToken( );
+ finished = false;
+ break;
+ case NO_REFLECTION_TOK:
+ o->setNoReflection( true );
+ nextToken( );
+ finished = false;
+ break;
+ case DOUBLE_ILLUMINATE_TOK:
+ o->setDoubleIlluminate( true );
+ nextToken( );
+ finished = false;
+ break;
+ default:
+ break;
+ }
+ if( so )
+ {
+ switch( m_token )
+ {
+ case HOLLOW_TOK:
+ so->setHollow( PMTrue );
+ nextToken( );
+ if( isTrue( ) )
+ nextToken( );
+ else if( isFalse( ) )
+ {
+ nextToken( );
+ so->setHollow( PMFalse );
+ }
+ finished = false;
+ break;
+ case INVERSE_TOK:
+ so->setInverse( true );
+ nextToken( );
+ finished = false;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ while( !finished );
+ return true;
+}
+
+bool PMPovrayParser::parseCSG( PMCSG* pNewCSG )
+{
+ int oldConsumed;
+
+ switch( m_token )
+ {
+ case UNION_TOK:
+ pNewCSG->setCSGType( PMCSG::CSGUnion );
+ break;
+ case INTERSECTION_TOK:
+ pNewCSG->setCSGType( PMCSG::CSGIntersection );
+ break;
+ case DIFFERENCE_TOK:
+ pNewCSG->setCSGType( PMCSG::CSGDifference );
+ break;
+ case MERGE_TOK:
+ pNewCSG->setCSGType( PMCSG::CSGMerge );
+ break;
+ default:
+ printUnexpected( m_pScanner->sValue( ) );
+ return false;
+ break;
+ }
+ nextToken( );
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( pNewCSG );
+ parseObjectModifiers( pNewCSG );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseBox( PMBox* pNewBox )
+{
+ PMVector vector;
+
+ int oldConsumed;
+
+ if( !parseToken( BOX_TOK, "box" ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( !parseVector( vector ) )
+ return false;
+ pNewBox->setCorner1( vector );
+
+ if( !parseToken( ',' ) )
+ return false;
+
+ if( !parseVector( vector ) )
+ return false;
+ pNewBox->setCorner2( vector );
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( pNewBox );
+ parseObjectModifiers( pNewBox );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseSphere( PMSphere* pNewSphere )
+{
+ PMVector vector;
+ double radius;
+
+ int oldConsumed;
+
+ if( !parseToken( SPHERE_TOK, "sphere" ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( !parseVector( vector ) )
+ return false;
+ pNewSphere->setCentre( vector );
+
+ if( !parseToken( ',' ) )
+ return false;
+
+ if( !parseFloat( radius ) )
+ return false;
+ pNewSphere->setRadius( radius );
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( pNewSphere );
+ parseObjectModifiers( pNewSphere );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseCylinder( PMCylinder* pNewCyl )
+{
+ PMVector vector;
+ double radius;
+ int oldConsumed;
+
+ if( !parseToken( CYLINDER_TOK, "cylinder" ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( !parseVector( vector ) )
+ return false;
+ pNewCyl->setEnd1( vector );
+
+ if( !parseToken( ',' ) )
+ return false;
+
+ if( !parseVector( vector ) )
+ return false;
+ pNewCyl->setEnd2( vector );
+
+ if( !parseToken( ',' ) )
+ return false;
+
+ if( !parseFloat(radius) )
+ return false;
+ pNewCyl->setRadius( radius );
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( pNewCyl );
+ parseObjectModifiers( pNewCyl );
+ switch( m_token )
+ {
+ case OPEN_TOK:
+ nextToken( );
+ pNewCyl->setOpen( true );
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseCone( PMCone* pNewCone )
+{
+ PMVector vector;
+ double radius;
+ int oldConsumed;
+
+ if( !parseToken( CONE_TOK, "cone" ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( !parseVector( vector ) )
+ return false;
+ pNewCone->setEnd1( vector );
+
+ if( !parseToken( ',' ) )
+ return false;
+ if( !parseFloat( radius ) )
+ return false;
+ pNewCone->setRadius1( radius );
+
+ if( !parseToken( ',' ) )
+ return false;
+ if( !parseVector( vector ) )
+ return false;
+ pNewCone->setEnd2( vector );
+
+ if( !parseToken( ',' ) )
+ return false;
+ if( !parseFloat( radius ) )
+ return false;
+ pNewCone->setRadius2( radius );
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( pNewCone );
+ parseObjectModifiers( pNewCone );
+ switch( m_token )
+ {
+ case OPEN_TOK:
+ nextToken( );
+ pNewCone->setOpen( true );
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+
+}
+
+bool PMPovrayParser::parseTorus( PMTorus* pNewTorus )
+{
+ double radius;
+ int oldConsumed;
+
+ if( !parseToken( TORUS_TOK, "torus" ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( !parseFloat( radius ) )
+ return false;
+ pNewTorus->setMajorRadius( radius );
+ if( !parseToken( ',' ) )
+ return false;
+ if( !parseFloat( radius ) )
+ return false;
+ pNewTorus->setMinorRadius( radius );
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( pNewTorus );
+ parseObjectModifiers( pNewTorus );
+ switch( m_token )
+ {
+ case STURM_TOK:
+ nextToken( );
+ pNewTorus->setSturm( true );
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseBlob( PMBlob* pNewBlob )
+{
+ PMVector vector;
+ double threshold;
+ int oldConsumed;
+
+ if( !parseToken( BLOB_TOK, "blob" ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ pNewBlob->setThreshold( 1.0 );
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+
+ switch( m_token )
+ {
+ case STURM_TOK:
+ nextToken( );
+ pNewBlob->setSturm( true );
+ break;
+ case HIERARCHY_TOK:
+ pNewBlob->setHierarchy( true );
+ nextToken( );
+ if( isTrue( ) )
+ nextToken( );
+ else if( isFalse( ) )
+ {
+ nextToken( );
+ pNewBlob->setHierarchy( false );
+ }
+ break;
+ case THRESHOLD_TOK:
+ nextToken( );
+ if( parseFloat( threshold ) )
+ {
+ if( threshold <= 0 )
+ printError( i18n( "The threshold value has to be positive" ) );
+ else
+ pNewBlob->setThreshold( threshold );
+ }
+ break;
+ }
+
+ parseChildObjects( pNewBlob );
+ parseObjectModifiers( pNewBlob );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseBlobSphere( PMBlobSphere* pNewBlobSphere )
+{
+ PMVector vector;
+ double radius;
+ double strength;
+
+ int oldConsumed;
+
+ if( !parseToken( SPHERE_TOK, "sphere" ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( !parseVector( vector ) )
+ return false;
+ pNewBlobSphere->setCentre( vector );
+
+ if( !parseToken( ',' ) )
+ return false;
+
+ if( !parseFloat( radius ) )
+ return false;
+ pNewBlobSphere->setRadius( radius );
+
+ if( !parseToken( ',' ) )
+ return false;
+
+ if( m_token == STRENGTH_TOK )
+ nextToken( );
+
+ if( !parseFloat( strength ) )
+ return false;
+ pNewBlobSphere->setStrength( strength );
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( pNewBlobSphere );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseBlobComponent( PMBlobSphere* pNewBlobSphere )
+{
+ PMVector vector;
+ double radius;
+ double strength;
+
+ if( !parseToken( COMPONENT_TOK, "component" ) )
+ return false;
+
+ if( !parseFloat( strength ) )
+ return false;
+ pNewBlobSphere->setStrength( strength );
+
+ if( !parseToken( ',' ) )
+ return false;
+
+ if( !parseFloat( radius ) )
+ return false;
+ pNewBlobSphere->setRadius( radius );
+
+ if( !parseToken( ',' ) )
+ return false;
+
+ if( !parseVector( vector ) )
+ return false;
+ pNewBlobSphere->setCentre( vector );
+
+ return true;
+}
+
+bool PMPovrayParser::parseBlobCylinder( PMBlobCylinder* pNewBlobCylinder )
+{
+ PMVector vector;
+ double radius;
+ double strength;
+ int oldConsumed;
+
+ if( !parseToken( CYLINDER_TOK, "cylinder" ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( !parseVector( vector ) )
+ return false;
+ pNewBlobCylinder->setEnd1( vector );
+
+ if( !parseToken( ',' ) )
+ return false;
+
+ if( !parseVector( vector ) )
+ return false;
+ pNewBlobCylinder->setEnd2( vector );
+
+ if( !parseToken( ',' ) )
+ return false;
+
+ if( !parseFloat( radius ) )
+ return false;
+ pNewBlobCylinder->setRadius( radius );
+
+ if( !parseToken( ',' ) )
+ return false;
+
+ if( m_token == STRENGTH_TOK )
+ nextToken( );
+
+ if( !parseFloat( strength ) )
+ return false;
+ pNewBlobCylinder->setStrength( strength );
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( pNewBlobCylinder );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseHeightField( PMHeightField* pNewHeightField )
+{
+ int oldConsumed;
+ double wl;
+
+ if( !parseToken( HEIGHT_FIELD_TOK, "height_field" ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ switch( m_token )
+ {
+ case GIF_TOK:
+ pNewHeightField->setHeightFieldType( PMHeightField::HFgif );
+ nextToken( );
+ break;
+ case TGA_TOK:
+ pNewHeightField->setHeightFieldType( PMHeightField::HFtga );
+ nextToken( );
+ break;
+ case POT_TOK:
+ pNewHeightField->setHeightFieldType( PMHeightField::HFpot );
+ nextToken( );
+ break;
+ case PNG_TOK:
+ pNewHeightField->setHeightFieldType( PMHeightField::HFpng );
+ nextToken( );
+ break;
+ case PGM_TOK:
+ pNewHeightField->setHeightFieldType( PMHeightField::HFpgm );
+ nextToken( );
+ break;
+ case PPM_TOK:
+ pNewHeightField->setHeightFieldType( PMHeightField::HFppm );
+ nextToken( );
+ break;
+ case SYS_TOK:
+ pNewHeightField->setHeightFieldType( PMHeightField::HFsys );
+ nextToken( );
+ break;
+ default:
+ printExpected( i18n( "height field type" ), m_pScanner->sValue( ) );
+ return false;
+ }
+ if( m_token != STRING_TOK )
+ {
+ printExpected( i18n( "height field file" ), m_pScanner->sValue( ) );
+ return false;
+ }
+ else
+ {
+ pNewHeightField->setFileName( m_pScanner->sValue( ) );
+ nextToken( );
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+
+ switch( m_token )
+ {
+ case SMOOTH_TOK:
+ nextToken( );
+ pNewHeightField->setSmooth( true );
+ if( isTrue( ) )
+ nextToken( );
+ else if( isFalse( ) )
+ {
+ nextToken( );
+ pNewHeightField->setSmooth( false );
+ }
+ break;
+ case HIERARCHY_TOK:
+ pNewHeightField->setHierarchy( true );
+ nextToken( );
+ if( isTrue( ) )
+ nextToken( );
+ else if( isFalse( ) )
+ {
+ nextToken( );
+ pNewHeightField->setHierarchy( false );
+ }
+ break;
+ case WATER_LEVEL_TOK:
+ nextToken( );
+ if( parseFloat( wl ) )
+ {
+ if( ( wl < 0.0 ) || ( wl > 1.0 ) )
+ printError( i18n( "The water level has to be between 0 and 1" ) );
+ else
+ pNewHeightField->setWaterLevel( wl );
+ }
+ break;
+ }
+
+ parseChildObjects( pNewHeightField );
+ parseObjectModifiers( pNewHeightField );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseText( PMText* pNewText )
+{
+ int oldConsumed;
+ double thickness;
+ PMVector offset;
+
+ if( !parseToken( TEXT_TOK, "text" ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( !parseToken( TTF_TOK, "ttf" ) )
+ return false;
+
+ if( m_token != STRING_TOK )
+ {
+ printExpected( i18n( "font file name" ), m_pScanner->sValue( ) );
+ return false;
+ }
+ else
+ {
+ pNewText->setFont( m_pScanner->sValue( ) );
+ nextToken( );
+ }
+ if( m_token != STRING_TOK )
+ {
+ printExpected( i18n( "string of text" ), m_pScanner->sValue( ) );
+ return false;
+ }
+ else
+ {
+ pNewText->setText( m_pScanner->sValue( ) );
+ nextToken( );
+ }
+
+ if( !parseFloat( thickness ) )
+ return false;
+ pNewText->setThickness( thickness );
+
+ parseToken( ',' );
+
+ if( parseVector( offset, 2 ) )
+ pNewText->setOffset( offset );
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( pNewText );
+ parseObjectModifiers( pNewText );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseJuliaFractal( PMJuliaFractal* pNewFractal )
+{
+ int oldConsumed;
+ double d;
+ int i;
+ PMVector v( 4 ), v2( 2 );
+
+ if( !parseToken( JULIA_FRACTAL_TOK, "julia_fractal" ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( !parseVector( v, 4 ) )
+ return false;
+ pNewFractal->setJuliaParameter( v );
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+
+ switch( m_token )
+ {
+ case QUATERNION_TOK:
+ pNewFractal->setAlgebraType( PMJuliaFractal::Quaternion );
+ nextToken( );
+ break;
+ case HYPERCOMPLEX_TOK:
+ pNewFractal->setAlgebraType( PMJuliaFractal::Hypercomplex );
+ nextToken( );
+ break;
+ case SQR_TOK:
+ pNewFractal->setFunctionType( PMJuliaFractal::FTsqr );
+ nextToken( );
+ break;
+ case CUBE_TOK:
+ pNewFractal->setFunctionType( PMJuliaFractal::FTcube );
+ nextToken( );
+ break;
+ case EXP_TOK:
+ pNewFractal->setFunctionType( PMJuliaFractal::FTexp );
+ nextToken( );
+ break;
+ case RECIPROCAL_TOK:
+ pNewFractal->setFunctionType( PMJuliaFractal::FTreciprocal );
+ nextToken( );
+ break;
+ case SIN_TOK:
+ pNewFractal->setFunctionType( PMJuliaFractal::FTsin );
+ nextToken( );
+ break;
+ case ASIN_TOK:
+ pNewFractal->setFunctionType( PMJuliaFractal::FTasin );
+ nextToken( );
+ break;
+ case SINH_TOK:
+ pNewFractal->setFunctionType( PMJuliaFractal::FTsinh );
+ nextToken( );
+ break;
+ case ASINH_TOK:
+ pNewFractal->setFunctionType( PMJuliaFractal::FTasinh );
+ nextToken( );
+ break;
+ case COS_TOK:
+ pNewFractal->setFunctionType( PMJuliaFractal::FTcos );
+ nextToken( );
+ break;
+ case ACOS_TOK:
+ pNewFractal->setFunctionType( PMJuliaFractal::FTacos );
+ nextToken( );
+ break;
+ case COSH_TOK:
+ pNewFractal->setFunctionType( PMJuliaFractal::FTcosh );
+ nextToken( );
+ break;
+ case ACOSH_TOK:
+ pNewFractal->setFunctionType( PMJuliaFractal::FTacosh );
+ nextToken( );
+ break;
+ case TAN_TOK:
+ pNewFractal->setFunctionType( PMJuliaFractal::FTtan );
+ nextToken( );
+ break;
+ case ATAN_TOK:
+ pNewFractal->setFunctionType( PMJuliaFractal::FTatan );
+ nextToken( );
+ break;
+ case TANH_TOK:
+ pNewFractal->setFunctionType( PMJuliaFractal::FTtanh );
+ nextToken( );
+ break;
+ case ATANH_TOK:
+ pNewFractal->setFunctionType( PMJuliaFractal::FTatanh );
+ nextToken( );
+ break;
+ case LOG_TOK:
+ pNewFractal->setFunctionType( PMJuliaFractal::FTlog );
+ nextToken( );
+ break;
+ case PWR_TOK:
+ pNewFractal->setFunctionType( PMJuliaFractal::FTpwr );
+ nextToken( );
+ if( !parseToken( '(' ) )
+ return false;
+ if( !parseFloat( v2[0] ) )
+ return false;
+ parseToken( ',' );
+ if( !parseFloat( v2[1] ) )
+ return false;
+ if( !parseToken( ')' ) )
+ return false;
+ pNewFractal->setExponent( v2 );
+ break;
+ case MAX_ITERATION_TOK:
+ nextToken( );
+ if( !parseInt( i ) )
+ return false;
+ if( i <= 0 )
+ {
+ printWarning( i18n( "Maximum iterations are less than 1, fixed" ) );
+ i = 1;
+ }
+ pNewFractal->setMaximumIterations( i );
+ break;
+ case PRECISION_TOK:
+ nextToken( );
+ if( !parseFloat( d ) )
+ return false;
+ if( d < 1.0 )
+ {
+ printWarning( i18n( "Precision is less than 1.0, fixed" ) );
+ d = 1.0;
+ }
+ pNewFractal->setPrecision( d );
+ break;
+ case SLICE_TOK:
+ nextToken( );
+ if( !parseVector( v, 4 ) )
+ return false;
+ pNewFractal->setSliceNormal( v );
+ parseToken( ',' );
+ if( !parseFloat( d ) )
+ return false;
+ pNewFractal->setSliceDistance( d );
+ break;
+ }
+
+ parseChildObjects( pNewFractal );
+ parseObjectModifiers( pNewFractal );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parsePlane( PMPlane* pNewPlane )
+{
+ double dist;
+ PMVector vector;
+ int oldConsumed;
+
+ if( !parseToken( PLANE_TOK, "plane" ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( !parseVector( vector ) )
+ return false;
+ pNewPlane->setNormal( vector );
+
+ if( !parseToken( ',' ) )
+ return false;
+ if( !parseFloat( dist ) )
+ return false;
+ pNewPlane->setDistance( dist );
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( pNewPlane );
+ parseObjectModifiers( pNewPlane );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+const int c_polynomSize[8] = { 0, 0, 10, 20, 35, 56, 84, 120 };
+
+bool PMPovrayParser::parsePolynom( PMPolynom* pNewPoly )
+{
+ PMVector vector;
+ double d;
+ PMVector c;
+ int oldConsumed;
+ int order = 2;
+ int type = m_token;
+
+ pNewPoly->setSturm( false );
+
+ if( ( m_token == QUADRIC_TOK ) || ( m_token == CUBIC_TOK ) ||
+ ( m_token == QUARTIC_TOK ) || ( m_token == POLY_TOK ) )
+ {
+ nextToken( );
+ if( !parseToken( '{' ) )
+ return false;
+ }
+ else
+ printExpected( "poly", m_pScanner->sValue( ) );
+
+ if( type == QUADRIC_TOK )
+ {
+ c = PMVector( 10 );
+ pNewPoly->setPolynomOrder( 2 );
+
+ // parse the quadric coefficients
+ if( !parseVectorLiteral( vector ) )
+ return false;
+ vector.resize( 3 );
+ c[0] = vector[0];
+ c[4] = vector[1];
+ c[7] = vector[2];
+ parseToken( ',' );
+
+ if( !parseVectorLiteral( vector ) )
+ return false;
+ vector.resize( 3 );
+ c[1] = vector[0];
+ c[2] = vector[1];
+ c[5] = vector[2];
+ parseToken( ',' );
+
+ if( !parseVectorLiteral( vector ) )
+ return false;
+ vector.resize( 3 );
+ c[3] = vector[0];
+ c[6] = vector[1];
+ c[8] = vector[2];
+ parseToken( ',' );
+
+ if( !parseFloat( d ) )
+ return false;
+ c[9] = d;
+
+ pNewPoly->setCoefficients( c );
+ }
+ else
+ {
+ if( type == CUBIC_TOK )
+ order = 3;
+ else if( type == QUARTIC_TOK )
+ order = 4;
+ else
+ {
+ if( !parseInt( order ) )
+ return false;
+ if( ( order < 2 ) || ( order > 7 ) )
+ {
+ printError( i18n( "The polynom order has to be between 2 and 7 inclusive" ) );
+ return false;
+ }
+ parseToken( ',' );
+ }
+
+ pNewPoly->setPolynomOrder( order );
+
+ if( !parseVectorLiteral( vector ) )
+ return false;
+
+ if( vector.size( ) != ( unsigned ) c_polynomSize[order] )
+ {
+ printError( i18n( "%1 coefficients are needed for a polynom with order %2" )
+ .arg( c_polynomSize[order] ).arg( order ) );
+ vector.resize( c_polynomSize[order] );
+ }
+ pNewPoly->setCoefficients( vector );
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+
+ if( m_token == STURM_TOK )
+ {
+ pNewPoly->setSturm( true );
+ nextToken( );
+ }
+
+ parseChildObjects( pNewPoly );
+ parseObjectModifiers( pNewPoly );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseBicubicPatch( PMBicubicPatch* pNewPatch )
+{
+ PMVector vector;
+ bool stop = false;
+ int oldConsumed;
+ int type;
+ int steps;
+ double flatness;
+ int i;
+
+ if( !parseToken( BICUBIC_PATCH_TOK, "bicubic_patch" ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ // parse patch items
+ do
+ {
+ switch( m_token )
+ {
+ case TYPE_TOK:
+ nextToken( );
+ if( parseInt( type ) )
+ {
+ if( ( type == 0 ) || ( type == 1 ) )
+ pNewPatch->setPatchType( type );
+ else
+ printError( i18n( "Patch type has to be 0 or 1" ) );
+ }
+ break;
+ case U_STEPS_TOK:
+ nextToken( );
+ if( parseInt( steps ) )
+ pNewPatch->setUSteps( steps );
+ break;
+ case V_STEPS_TOK:
+ nextToken( );
+ if( parseInt( steps ) )
+ pNewPatch->setVSteps( steps );
+ break;
+ case FLATNESS_TOK:
+ nextToken( );
+ if( parseFloat( flatness ) )
+ pNewPatch->setFlatness( flatness );
+ break;
+ case UV_VECTORS_TOK:
+ pNewPatch->enableUV( true );
+ nextToken( );
+ for ( i = 0; i < 4; ++i )
+ {
+ if( parseVector( vector ) )
+ pNewPatch->setUVVector( i, vector );
+ else
+ return false;
+ }
+ break;
+ case ',':
+ nextToken( );
+ stop = true;
+ break;
+ default:
+ stop = true;
+ break;
+ }
+ }
+ while( !stop );
+
+ // parse control points
+ stop = false;
+ for( i = 0; ( i < 16 ) && !stop; i++ )
+ {
+ if( parseVector( vector ) )
+ {
+ pNewPatch->setControlPoint( i, vector );
+ if( i < 15 )
+ if( !parseToken( ',' ) )
+ stop = true;
+ }
+ else
+ stop = true;
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( pNewPatch );
+ parseObjectModifiers( pNewPatch );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseDisc( PMDisc* pNewDisc )
+{
+ double d;
+ PMVector vector;
+ int oldConsumed;
+
+ if( !parseToken( DISC_TOK, "disc" ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( !parseVector( vector ) )
+ return false;
+ pNewDisc->setCenter( vector );
+
+ if( !parseToken( ',' ) )
+ return false;
+ if( !parseVector( vector ) )
+ return false;
+ pNewDisc->setNormal( vector );
+
+ if( !parseToken( ',' ) )
+ return false;
+ if( !parseFloat( d ) )
+ return false;
+ pNewDisc->setRadius( d );
+
+ if( m_token == ',' )
+ {
+ nextToken( );
+ if( !parseFloat( d ) )
+ return false;
+ pNewDisc->setHoleRadius( d );
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( pNewDisc );
+ parseObjectModifiers( pNewDisc );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseTriangle( PMTriangle* pNewTriangle )
+{
+ PMVector vector;
+ int oldConsumed;
+ int i;
+
+ if( m_token == SMOOTH_TRIANGLE_TOK )
+ pNewTriangle->setSmoothTriangle( true );
+ else if( m_token == TRIANGLE_TOK )
+ pNewTriangle->setSmoothTriangle( false );
+ else
+ {
+ printExpected( "triangle", m_pScanner->sValue( ) );
+ return false;
+ }
+ nextToken( );
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ for( i = 0; i < 3; i++ )
+ {
+ if( i != 0 )
+ parseToken( ',' );
+ if( !parseVector( vector ) )
+ return false;
+ pNewTriangle->setPoint( i, vector );
+
+ if( pNewTriangle->isSmoothTriangle( ) )
+ {
+ parseToken( ',' );
+ if( !parseVector( vector ) )
+ return false;
+ pNewTriangle->setNormal( i, vector );
+ }
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( pNewTriangle );
+ parseObjectModifiers( pNewTriangle );
+ if( m_token == UV_VECTORS_TOK )
+ {
+ nextToken( );
+ pNewTriangle->enableUV( true );
+ for ( i = 0; i < 3; ++i )
+ {
+ if( parseVector( vector ) )
+ pNewTriangle->setUVVector( i, vector );
+ else
+ return false;
+ }
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseLathe( PMLathe* pNewLathe )
+{
+ PMVector vector;
+ int oldConsumed;
+ int i;
+ bool stop = false;
+
+ if( !parseToken( LATHE_TOK, "lathe" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ int minp = 2;
+ while( !stop )
+ {
+ switch( m_token )
+ {
+ case LINEAR_SPLINE_TOK:
+ pNewLathe->setSplineType( PMLathe::LinearSpline );
+ nextToken( );
+ minp = 2;
+ break;
+ case QUADRATIC_SPLINE_TOK:
+ pNewLathe->setSplineType( PMLathe::QuadraticSpline );
+ nextToken( );
+ minp = 3;
+ break;
+ case CUBIC_SPLINE_TOK:
+ pNewLathe->setSplineType( PMLathe::CubicSpline );
+ nextToken( );
+ minp = 4;
+ break;
+ case BEZIER_SPLINE_TOK:
+ pNewLathe->setSplineType( PMLathe::BezierSpline );
+ nextToken( );
+ minp = 4;
+ break;
+ default:
+ stop = true;
+ break;
+ }
+ }
+
+ int nump;
+ if( !parseInt( nump ) )
+ return false;
+
+ QValueList<PMVector> points;
+ for( i = 0; i < nump; i++ )
+ {
+ parseToken( ',' );
+ if( !parseVector( vector ) )
+ return false;
+ vector.resize( 2 );
+ points.append( vector );
+ }
+
+ if( nump < minp )
+ printError( i18n( "At least %1 points are needed for that spline type" )
+ .arg( minp ) );
+ else if( ( pNewLathe->splineType( ) == PMLathe::BezierSpline ) &&
+ ( ( nump % 4 ) != 0 ) )
+ printError( i18n( "Bezier splines need 4 points for each segment" ) );
+ else
+ pNewLathe->setPoints( points );
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+
+ if( m_token == STURM_TOK )
+ {
+ pNewLathe->setSturm( true );
+ nextToken( );
+ }
+
+ parseChildObjects( pNewLathe );
+ parseObjectModifiers( pNewLathe );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parsePrism( PMPrism* pNewPrism )
+{
+ PMVector vector;
+ double height;
+ int oldConsumed;
+ int i;
+ bool stop = false;
+
+ if( !parseToken( PRISM_TOK, "prism" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ int minp = 3;
+ while( !stop )
+ {
+ switch( m_token )
+ {
+ case LINEAR_SPLINE_TOK:
+ pNewPrism->setSplineType( PMPrism::LinearSpline );
+ nextToken( );
+ minp = 3;
+ break;
+ case QUADRATIC_SPLINE_TOK:
+ pNewPrism->setSplineType( PMPrism::QuadraticSpline );
+ nextToken( );
+ minp = 4;
+ break;
+ case CUBIC_SPLINE_TOK:
+ pNewPrism->setSplineType( PMPrism::CubicSpline );
+ nextToken( );
+ minp = 5;
+ break;
+ case BEZIER_SPLINE_TOK:
+ pNewPrism->setSplineType( PMPrism::BezierSpline );
+ nextToken( );
+ minp = 4;
+ break;
+ case LINEAR_SWEEP_TOK:
+ pNewPrism->setSweepType( PMPrism::LinearSweep );
+ nextToken( );
+ break;
+ case CONIC_SWEEP_TOK:
+ pNewPrism->setSweepType( PMPrism::ConicSweep );
+ nextToken( );
+ break;
+ default:
+ stop = true;
+ break;
+ }
+ }
+
+ if( !parseFloat( height ) )
+ return false;
+ pNewPrism->setHeight1( height );
+ parseToken( ',' );
+ if( !parseFloat( height ) )
+ return false;
+ pNewPrism->setHeight2( height );
+ parseToken( ',' );
+
+ int nump;
+ if( !parseInt( nump ) )
+ return false;
+
+ QValueList<PMVector> allPoints;
+ for( i = 0; i < nump; i++ )
+ {
+ parseToken( ',' );
+ if( !parseVector( vector ) )
+ return false;
+ vector.resize( 2 );
+ allPoints.append( vector );
+ }
+
+ QValueList< QValueList<PMVector> > points;
+ QValueList<PMVector> subPoints;
+ QValueList<PMVector>::Iterator it = allPoints.begin( );
+ int pnr = 0, pmod4;
+ PMVector ref( 2 ), ref2( 2 );
+ bool error = false;
+ bool last = false;
+
+ switch( pNewPrism->splineType( ) )
+ {
+ case PMPrism::LinearSpline:
+ for( ; ( it != allPoints.end( ) ) && !error; ++it, pnr++ )
+ {
+ if( pnr == 0 )
+ {
+ ref = *it;
+ subPoints.append( *it );
+ }
+ else
+ {
+ if( ref.approxEqual( *it ) )
+ {
+ if( pnr < 3 )
+ {
+ printError( i18n( "Linear splines need at least 4 points." ) );
+ error = true;
+ }
+ else
+ {
+ points.append( subPoints );
+ subPoints.clear( );
+ pnr = -1;
+ }
+ }
+ else
+ subPoints.append( *it );
+ }
+ }
+ if( ( pnr != 0 ) && ( !error ) )
+ {
+ printWarning( i18n( "Linear spline not closed" ) );
+ if( pnr < 3 )
+ {
+ printError( i18n( "Linear splines need at least 4 points." ) );
+ error = true;
+ }
+ else
+ {
+ points.append( subPoints );
+ subPoints.clear( );
+ }
+ }
+ break;
+ case PMPrism::QuadraticSpline:
+ for( ; ( it != allPoints.end( ) ) && !error; ++it, pnr++ )
+ {
+ if( pnr == 0 )
+ subPoints.append( *it );
+ else if( pnr == 1 )
+ {
+ ref = *it;
+ subPoints.append( *it );
+ }
+ else
+ {
+ if( ref.approxEqual( *it ) )
+ {
+ if( pnr < 4 )
+ {
+ printError( i18n( "Quadratic splines need at least 5 points." ) );
+ error = true;
+ }
+ else
+ {
+ points.append( subPoints );
+ subPoints.clear( );
+ pnr = -1;
+ }
+ }
+ else
+ subPoints.append( *it );
+ }
+ }
+ if( ( pnr != 0 ) && ( !error ) )
+ {
+ printError( i18n( "Quadratic spline not closed" ) );
+ error = true;
+ }
+ break;
+ case PMPrism::CubicSpline:
+ for( ; ( it != allPoints.end( ) ) && !error; ++it, pnr++ )
+ {
+ if( pnr == 0 )
+ subPoints.append( *it );
+ else if( pnr == 1 )
+ {
+ ref = *it;
+ subPoints.append( *it );
+ }
+ else if( last )
+ {
+ if( pnr < 5 )
+ {
+ printError( i18n( "Cubic splines need at least 6 points." ) );
+ error = true;
+ }
+ else
+ {
+ subPoints.append( *it );
+ points.append( subPoints );
+ subPoints.clear( );
+ pnr = -1;
+ last = false;
+ }
+ }
+ else
+ {
+ if( ref.approxEqual( *it ) )
+ last = true;
+ else
+ subPoints.append( *it );
+ }
+ }
+ if( ( pnr != 0 ) && ( !error ) )
+ {
+ printError( i18n( "Cubic spline not closed" ) );
+ error = true;
+ }
+ break;
+ case PMPrism::BezierSpline:
+ for( ; ( it != allPoints.end( ) ) && !error; ++it, pnr++ )
+ {
+ pmod4 = pnr % 4;
+
+ if( pnr == 0 )
+ {
+ ref = *it;
+ subPoints.append( *it );
+ }
+ else if( pmod4 == 0 )
+ {
+ if( !ref2.approxEqual( *it ) )
+ {
+ printError( i18n( "Bezier spline not closed" ) );
+ error = true;
+ }
+ }
+ else if( pmod4 == 3 )
+ {
+ if( ref.approxEqual( *it ) )
+ {
+ points.append( subPoints );
+ subPoints.clear( );
+ pnr = -1;
+ }
+ else
+ {
+ subPoints.append( *it );
+ ref2 = *it;
+ }
+ }
+ else
+ subPoints.append( *it );
+ }
+ if( ( pnr != 0 ) && ( !error ) )
+ {
+ printError( i18n( "Bezier spline not closed" ) );
+ error = true;
+ }
+ break;
+ }
+
+ if( !error )
+ pNewPrism->setPoints( points );
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+
+ switch( m_token )
+ {
+ case STURM_TOK:
+ pNewPrism->setSturm( true );
+ nextToken( );
+ break;
+ case OPEN_TOK:
+ pNewPrism->setOpen( true );
+ nextToken( );
+ break;
+ default:
+ break;
+ }
+
+ parseChildObjects( pNewPrism );
+ parseObjectModifiers( pNewPrism );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseSor( PMSurfaceOfRevolution* pNewSor )
+{
+ PMVector vector;
+ int oldConsumed;
+ int i;
+
+ if( !parseToken( SOR_TOK, "sor" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ int nump;
+ if( !parseInt( nump ) )
+ return false;
+
+ QValueList<PMVector> points;
+ for( i = 0; i < nump; i++ )
+ {
+ parseToken( ',' );
+ if( !parseVector( vector ) )
+ return false;
+ vector.resize( 2 );
+ points.append( vector );
+ }
+
+ if( nump < 4 )
+ printError( i18n( "At least 4 points are needed for the surface of revolution" ) );
+ else
+ {
+ QValueList<PMVector>::Iterator it1 = points.begin( );
+ QValueList<PMVector>::Iterator it2 = it1; ++it2;
+ QValueList<PMVector>::Iterator it3 = it2; ++it3;
+ int pnr = 0;
+
+ for( ; it3 != points.end( ); ++it1, ++it2, ++it3, pnr++ )
+ {
+ if( ( pnr == 0 ) || ( pnr == ( nump - 3 ) ) )
+ {
+ if( approxZero( ( *it1 )[1] - ( *it3 )[1], c_sorTolerance ) )
+ {
+ printError( i18n( "The v coordinate of point %1 and %2 must be different; fixed" )
+ .arg( pnr + 1 ).arg( pnr + 3 ) );
+ if( pnr == 0 )
+ ( *it1 )[1] = ( *it3 )[1] - c_sorTolerance;
+ else
+ ( *it3 )[1] = ( *it1 )[1] + c_sorTolerance;
+ }
+ }
+
+ if( pnr != 0 )
+ {
+ if( ( ( *it2 )[1] - ( *it1 )[1] ) < c_sorTolerance )
+ {
+ printError( i18n( "The v coordinates must be strictly increasing; fixed" ) );
+ ( *it2 )[1] = ( *it1 )[1] + c_sorTolerance;
+ }
+ }
+ }
+ pNewSor->setPoints( points );
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+
+ switch( m_token )
+ {
+ case STURM_TOK:
+ pNewSor->setSturm( true );
+ nextToken( );
+ break;
+ case OPEN_TOK:
+ pNewSor->setOpen( true );
+ nextToken( );
+ break;
+ default:
+ break;
+ }
+
+ parseChildObjects( pNewSor );
+ parseObjectModifiers( pNewSor );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseSqe( PMSuperquadricEllipsoid* pNewSqe )
+{
+ PMVector vector;
+ int oldConsumed;
+
+ if( !parseToken( SUPERELLIPSOID_TOK ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( !parseVector( vector ) )
+ return false;
+ vector.resize( 2 );
+
+ if( vector[0] < 0.001 )
+ {
+ printError( i18n( "The east-west exponent must be greater than 0.001" ) );
+ vector[0] = 0.001;
+ }
+ if( vector[1] < 0.001 )
+ {
+ printError( i18n( "The north-south exponent must be greater than 0.001" ) );
+ vector[1] = 0.001;
+ }
+
+ pNewSqe->setEastWestExponent( vector[0] );
+ pNewSqe->setNorthSouthExponent( vector[1] );
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( pNewSqe );
+ parseObjectModifiers( pNewSqe );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseRotate( PMRotate* rotate )
+{
+ PMVector v;
+
+ if( !parseToken( ROTATE_TOK, "rotate" ) )
+ return false;
+ if( !parseVector( v ) )
+ return false;
+
+ rotate->setRotation( v );
+ return true;
+}
+
+bool PMPovrayParser::parseScale( PMScale* scale )
+{
+ PMVector v;
+
+ if( !parseToken( SCALE_TOK, "scale" ) )
+ return false;
+ if( !parseVector( v ) )
+ return false;
+
+ scale->setScale( v );
+ return true;
+}
+
+bool PMPovrayParser::parseTranslate( PMTranslate* translate )
+{
+ PMVector v;
+
+ if( !parseToken( TRANSLATE_TOK, "translate" ) )
+ return false;
+ if( !parseVector( v ) )
+ return false;
+
+ translate->setTranslation( v );
+ return true;
+}
+
+bool PMPovrayParser::parseMatrix( PMPovrayMatrix* matrix )
+{
+ PMVector v;
+
+ if( !parseToken( MATRIX_TOK ), "matrix" )
+ return false;
+ if( !parseVectorLiteral( v ) )
+ return false;
+
+ if( v.size( ) != 12 )
+ {
+ printError( i18n( "Wrong number of matrix values." ) );
+ v.resize( 12 );
+ }
+ matrix->setValues( v );
+ return true;
+}
+
+bool PMPovrayParser::parseBoundedBy( PMBoundedBy* bound )
+{
+ int oldConsumed;
+
+ if( !parseToken( BOUNDED_BY_TOK, "bounded_by" ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+
+ if( m_token == CLIPPED_BY_TOK )
+ nextToken( );
+
+ parseChildObjects( bound );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseClippedBy( PMClippedBy* clipped )
+{
+ int oldConsumed;
+
+ if( !parseToken( CLIPPED_BY_TOK, "clipped_by" ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+
+ if( m_token == BOUNDED_BY_TOK )
+ nextToken( );
+
+ parseChildObjects( clipped );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseCamera( PMCamera* camera )
+{
+ PMVector v;
+ double d;
+ int i;
+
+ int oldConsumed;
+
+ if( !parseToken( CAMERA_TOK, "camera" ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+
+ switch( m_token )
+ {
+ case PERSPECTIVE_TOK:
+ nextToken( );
+ camera->setCameraType( PMCamera::Perspective );
+ break;
+ case ORTHOGRAPHIC_TOK:
+ nextToken( );
+ camera->setCameraType( PMCamera::Orthographic );
+ break;
+ case FISHEYE_TOK:
+ nextToken( );
+ camera->setCameraType( PMCamera::FishEye );
+ break;
+ case ULTRA_WIDE_ANGLE_TOK:
+ nextToken( );
+ camera->setCameraType( PMCamera::UltraWideAngle );
+ break;
+ case OMNIMAX_TOK:
+ nextToken( );
+ camera->setCameraType( PMCamera::Omnimax );
+ break;
+ case PANORAMIC_TOK:
+ nextToken( );
+ camera->setCameraType( PMCamera::Panoramic );
+ break;
+ case CYLINDER_TOK:
+ nextToken( );
+ camera->setCameraType( PMCamera::Cylinder );
+ if( parseInt( i ) )
+ camera->setCylinderType( i );
+ break;
+ case LOCATION_TOK:
+ nextToken( );
+ if( parseVector( v ) )
+ camera->setLocation( v );
+ break;
+ case SKY_TOK:
+ nextToken( );
+ if( parseVector( v ) )
+ camera->setSky( v );
+ break;
+ case UP_TOK:
+ nextToken( );
+ if( parseVector( v ) )
+ camera->setUp( v );
+ break;
+ case RIGHT_TOK:
+ nextToken( );
+ if( parseVector( v ) )
+ camera->setRight( v );
+ break;
+ case DIRECTION_TOK:
+ nextToken( );
+ if( parseVector( v ) )
+ camera->setDirection( v );
+ break;
+ case LOOK_AT_TOK:
+ nextToken( );
+ if( parseVector( v ) )
+ camera->setLookAt( v );
+ break;
+ case ANGLE_TOK:
+ nextToken( );
+ if( parseFloat( d ) )
+ {
+ camera->enableAngle( true );
+ camera->setAngle( d );
+ }
+ break;
+ case BLUR_SAMPLES_TOK:
+ nextToken( );
+ camera->enableFocalBlur( true );
+ if( parseInt( i ) )
+ camera->setBlurSamples( i );
+ break;
+ case APERTURE_TOK:
+ nextToken( );
+ camera->enableFocalBlur( true );
+ if( parseFloat( d ) )
+ camera->setAperture( d );
+ break;
+ case FOCAL_POINT_TOK:
+ nextToken( );
+ if( parseVector( v ) )
+ camera->setFocalPoint( v );
+ break;
+ case CONFIDENCE_TOK:
+ nextToken( );
+ if( parseFloat( d ) )
+ camera->setConfidence( d );
+ break;
+ case VARIANCE_TOK:
+ nextToken( );
+ if( parseFloat( d ) )
+ camera->setVariance( d );
+ break;
+ default:
+ break;
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+ parseChildObjects( camera );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseLight( PMLight* light )
+{
+ PMVector v;
+ PMColor c;
+ double d;
+ int i;
+
+ int oldConsumed;
+
+ if( !parseToken( LIGHT_SOURCE_TOK, "light_source" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+ if( !parseVector( v ) )
+ return false;
+ light->setLocation( v );
+ if( m_token == ',' )
+ nextToken( );
+ if( !parseColor( c ) )
+ return false;
+ light->setColor( c );
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( light );
+
+ switch( m_token )
+ {
+ case SPOTLIGHT_TOK:
+ nextToken( );
+ light->setLightType( PMLight::SpotLight );
+ break;
+ case CYLINDER_TOK:
+ nextToken( );
+ light->setLightType( PMLight::CylinderLight );
+ break;
+ case SHADOWLESS_TOK:
+ nextToken( );
+ light->setLightType( PMLight::ShadowlessLight );
+ break;
+ case RADIUS_TOK:
+ nextToken( );
+ if( parseFloat( d ) )
+ light->setRadius( d );
+ break;
+ case FALLOFF_TOK:
+ nextToken( );
+ if( parseFloat( d ) )
+ light->setFalloff( d );
+ break;
+ case TIGHTNESS_TOK:
+ nextToken( );
+ if( parseFloat( d ) )
+ light->setTightness( d );
+ break;
+ case POINT_AT_TOK:
+ nextToken( );
+ if( parseVector( v ) )
+ light->setPointAt( v );
+ break;
+ case PARALLEL_TOK:
+ nextToken( );
+ light->setParallel( parseBool( ) );
+ break;
+ case AREA_LIGHT_TOK:
+ nextToken( );
+ light->setAreaLight( true );
+ if( parseVector( v ) )
+ light->setAxis1( v );
+ parseToken( ',' );
+ if( parseVector( v ) )
+ light->setAxis2( v );
+ parseToken( ',' );
+ if( parseInt( i ) )
+ light->setSize1( i );
+ parseToken( ',' );
+ if( parseInt( i ) )
+ light->setSize2( i );
+ break;
+ case AREA_CIRCULAR_TOK:
+ nextToken( );
+ light->setAreaType( PMLight::Circular );
+ break;
+ case ADAPTIVE_TOK:
+ nextToken( );
+ if( parseInt( i ) )
+ light->setAdaptive( i );
+ break;
+ case ORIENT_TOK:
+ nextToken( );
+ light->setOrient( parseBool( ) );
+ break;
+ case JITTER_TOK:
+ nextToken( );
+ light->setJitter( parseBool( ) );
+ break;
+ case FADE_POWER_TOK:
+ nextToken( );
+ light->setFading( true );
+ if( parseInt( i ) )
+ light->setFadePower( i );
+ break;
+ case FADE_DISTANCE_TOK:
+ nextToken( );
+ light->setFading( true );
+ if( parseFloat( d ) )
+ light->setFadeDistance( d );
+ break;
+ case MEDIA_INTERACTION_TOK:
+ nextToken( );
+ light->setMediaInteraction( parseBool( ) );
+ break;
+ case MEDIA_ATTENUATION_TOK:
+ nextToken( );
+ light->setMediaAttenuation( parseBool( ) );
+ break;
+ default:
+ break;
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseLooksLike( PMLooksLike* ll )
+{
+ if( !parseToken( LOOKS_LIKE_TOK, "looks_like" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ parseChildObjects( ll );
+
+ if( !parseToken( '}' ) )
+ return false;
+ return true;
+}
+
+bool PMPovrayParser::parseProjectedThrough( PMProjectedThrough* ll )
+{
+ if( !parseToken( PROJECTED_THROUGH_TOK, "projected_through" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ parseChildObjects( ll );
+
+ if( !parseToken( '}' ) )
+ return false;
+ return true;
+}
+
+bool PMPovrayParser::parseTexture( PMTexture* texture, bool parseOuter )
+{
+ int oldConsumed;
+
+ if( parseOuter )
+ {
+ if( !parseToken( TEXTURE_TOK, "texture" ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+ }
+
+ if( m_token == ID_TOK )
+ {
+ QString id( m_pScanner->sValue( ) );
+ PMDeclare* decl = checkLink( id );
+ if( decl )
+ {
+ if( !texture->setLinkedObject( decl ) )
+ printError( i18n( "Wrong declare type" ) );
+ }
+ nextToken( );
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( texture );
+ if( m_token == UV_MAPPING_TOK )
+ {
+ nextToken();
+ texture->setUVMapping( parseBool( ) );
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( parseOuter )
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parsePattern( PMPattern* pattern, bool normal )
+{
+ PMVector vector;
+ double f_number;
+ int i_number;
+ int oldConsumed;
+ bool type;
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ type = false;
+
+ switch( m_token )
+ {
+ case AGATE_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternAgate );
+ type = true;
+ break;
+ case AGATE_TURB_TOK:
+ nextToken( );
+ if( !parseFloat( f_number ) )
+ return false;
+ pattern->setAgateTurbulence( f_number );
+ break;
+ case AVERAGE_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternAverage );
+ type = true;
+ break;
+ case BOXED_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternBoxed );
+ type = true;
+ break;
+ case BOZO_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternBozo );
+ type = true;
+ break;
+ case BUMPS_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternBumps );
+ type = true;
+ break;
+ case CELLS_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternCells );
+ type = true;
+ break;
+ case CRACKLE_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternCrackle );
+ type = true;
+ break;
+ case CYLINDRICAL_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternCylindrical );
+ type = true;
+ break;
+ case DENTS_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternDents );
+ type = true;
+ break;
+ case DENSITY_FILE_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternDensity );
+ type = true;
+ if( !parseToken( DF3_TOK, "df3" ) )
+ return false;
+ if( m_token != STRING_TOK )
+ {
+ printError( i18n( "Expecting a file name." ) );
+ return false;
+ }
+ else
+ {
+ pattern->setDensityFile( m_pScanner->sValue( ) );
+ nextToken( );
+ }
+ if( parseToken( INTERPOLATE_TOK, "interpolate" ) )
+ {
+ if( !parseInt( i_number ) )
+ return false;
+ else
+ pattern->setDensityInterpolate( i_number );
+ }
+ break;
+ case GRADIENT_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternGradient );
+ type = true;
+ if( !parseVector( vector ) )
+ return false;
+ pattern->setGradient( vector );
+ break;
+ case GRANITE_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternGranite );
+ type = true;
+ break;
+ case JULIA_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternJulia );
+ type = true;
+ if( !parseVector( vector ) )
+ return false;
+ pattern->setJuliaComplex( vector );
+ if( !parseInt( i_number ) )
+ return false;
+ pattern->setMaxIterations( i_number );
+ break;
+ case LEOPARD_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternLeopard );
+ type = true;
+ break;
+ case MANDEL_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternMandel );
+ type = true;
+ if( !parseInt( i_number ) )
+ return false;
+ pattern->setMaxIterations( i_number );
+ break;
+ case MARBLE_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternMarble );
+ type = true;
+ break;
+ case ONION_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternOnion );
+ type = true;
+ break;
+ case PLANAR_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternPlanar );
+ type = true;
+ break;
+ case QUILTED_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternQuilted );
+ type = true;
+ break;
+ case CONTROL0_TOK:
+ nextToken( );
+ if( !parseFloat( f_number ) )
+ return false;
+ pattern->setQuiltControl0( f_number );
+ break;
+ case CONTROL1_TOK:
+ nextToken( );
+ if( !parseFloat( f_number ) )
+ return false;
+ pattern->setQuiltControl1( f_number );
+ break;
+ case RADIAL_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternRadial );
+ type = true;
+ break;
+ case RIPPLES_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternRipples );
+ type = true;
+ break;
+ case SLOPE_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternSlope );
+ type = true;
+ if( !parseToken( '{' ) )
+ return false;
+ if( !parseVector( vector ) )
+ return false;
+ pattern->setSlopeDirection( vector );
+ if ( parseToken( ',' ) )
+ {
+ if( !parseFloat( f_number ) )
+ return false;
+ pattern->setSlopeLoSlope( f_number );
+ if ( parseToken( ',' ) )
+ {
+ if ( !parseFloat( f_number ) )
+ return false;
+ pattern->setSlopeHiSlope( f_number );
+ }
+ }
+ if( m_token == ALTITUDE_TOK )
+ {
+ pattern->setSlopeAltFlag( true );
+ nextToken( );
+ if ( !parseVector( vector ) )
+ return false;
+ pattern->setSlopeAltitude( vector );
+ if( parseToken( ',' ) )
+ {
+ if ( !parseFloat( f_number ) )
+ return false;
+ pattern->setSlopeLoAlt( f_number );
+ if ( parseToken( ',' ) )
+ {
+ if( !parseFloat( f_number ) )
+ return false;
+ pattern->setSlopeHiAlt( f_number );
+ }
+ }
+ }
+ if( !parseToken( '}' ) )
+ return false;
+ break;
+ case SPHERICAL_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternSpherical );
+ type = true;
+ break;
+ case SPIRAL1_TOK:
+ case SPIRAL2_TOK:
+ if( m_token == SPIRAL1_TOK )
+ pattern->setPatternType( PMPattern::PatternSpiral1 );
+ else
+ pattern->setPatternType( PMPattern::PatternSpiral2 );
+ type = true;
+ nextToken( );
+ if( !parseInt( i_number ) )
+ return false;
+ pattern->setSpiralNumberArms( i_number );
+ break;
+ case SPOTTED_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternSpotted );
+ type = true;
+ break;
+ case WAVES_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternWaves );
+ type = true;
+ break;
+ case WOOD_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternWood );
+ type = true;
+ break;
+ case WRINKLES_TOK:
+ nextToken( );
+ pattern->setPatternType( PMPattern::PatternWrinkles );
+ type = true;
+ break;
+
+ //crackle parameters
+ case FORM_TOK:
+ nextToken( );
+ if( !parseVector( vector ) )
+ return false;
+ pattern->setCrackleForm( vector );
+ break;
+ case METRIC_TOK:
+ nextToken( );
+ if ( !parseInt( i_number ) )
+ return false;
+ pattern->setCrackleMetric( i_number );
+ break;
+ case OFFSET_TOK:
+ nextToken( );
+ if( !parseFloat( f_number ) )
+ return false;
+ pattern->setCrackleOffset( f_number );
+ break;
+ case SOLID_TOK:
+ nextToken( );
+ pattern->setCrackleSolid( true );
+ break;
+
+ //fractal parameters
+ case MAGNET_TOK:
+ nextToken( );
+ pattern->setFractalMagnet( true );
+ if ( !parseInt( i_number ) )
+ return false;
+ pattern->setFractalMagnetType( i_number );
+ break;
+ case EXPONENT_TOK:
+ nextToken( );
+ if ( !parseInt( i_number ) )
+ return false;
+ pattern->setFractalExponent( i_number );
+ break;
+ case EXTERIOR_TOK:
+ nextToken( );
+ if ( !parseInt( i_number ) )
+ return false;
+ pattern->setFractalExtType( i_number );
+ if ( !parseFloat( f_number ) )
+ return false;
+ pattern->setFractalExtFactor( f_number );
+ break;
+ case INTERIOR_TOK:
+ nextToken( );
+ if ( !parseInt( i_number ) )
+ return false;
+ pattern->setFractalIntType( i_number );
+ if ( !parseFloat( f_number ) )
+ return false;
+ pattern->setFractalIntFactor( f_number );
+ break;
+
+ //turbulence
+ case TURBULENCE_TOK:
+ nextToken( );
+ pattern->enableTurbulence( true );
+ if( !parseVector( vector ) )
+ return false;
+ pattern->setValueVector( vector );
+ break;
+ case OCTAVES_TOK:
+ nextToken( );
+ if( !parseInt( i_number ) )
+ return false;
+ pattern->setOctaves( i_number );
+ break;
+ case OMEGA_TOK:
+ nextToken( );
+ if( !parseFloat( f_number ) )
+ return false;
+ pattern->setOmega( f_number );
+ break;
+ case LAMBDA_TOK:
+ nextToken( );
+ if( !parseFloat( f_number ) )
+ return false;
+ pattern->setLambda( f_number );
+ break;
+
+ case NOISE_GENERATOR_TOK:
+ nextToken( );
+ if( !parseInt( i_number ) )
+ return false;
+ pattern->setNoiseGenerator( ( PMPattern::PMNoiseType ) ( i_number ) );
+ break;
+ default:
+ break;
+ }
+
+ if( type && normal )
+ {
+ // try to parse the normal pattern depth
+ double depth;
+ if( parseFloat( depth, true ) )
+ pattern->setDepth( depth );
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ return true;
+}
+
+bool PMPovrayParser::parseBlendMapModifiers( PMBlendMapModifiers* blend )
+{
+ int oldConsumed;
+ double f_number;
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ switch( m_token )
+ {
+ case FREQUENCY_TOK:
+ nextToken( );
+ if( !parseFloat( f_number ) )
+ return false;
+ blend->enableFrequency( true );
+ blend->setFrequency( f_number );
+ break;
+ case PHASE_TOK:
+ nextToken( );
+ if( !parseFloat( f_number ) )
+ return false;
+ blend->enablePhase( true );
+ blend->setPhase( f_number );
+ break;
+ case RAMP_WAVE_TOK:
+ nextToken( );
+ blend->enableWaveForm( true );
+ blend->setWaveFormType( PMBlendMapModifiers::RampWave );
+ break;
+ case TRIANGLE_WAVE_TOK:
+ nextToken( );
+ blend->enableWaveForm( true );
+ blend->setWaveFormType( PMBlendMapModifiers::TriangleWave );
+ break;
+ case SINE_WAVE_TOK:
+ nextToken( );
+ blend->enableWaveForm( true );
+ blend->setWaveFormType( PMBlendMapModifiers::SineWave );
+ break;
+ case SCALLOP_WAVE_TOK:
+ nextToken( );
+ blend->enableWaveForm( true );
+ blend->setWaveFormType( PMBlendMapModifiers::ScallopWave );
+ break;
+ case CUBIC_WAVE_TOK:
+ nextToken( );
+ blend->enableWaveForm( true );
+ blend->setWaveFormType( PMBlendMapModifiers::CubicWave );
+ break;
+ case POLY_WAVE_TOK:
+ nextToken( );
+ blend->enableWaveForm( true );
+ blend->setWaveFormType( PMBlendMapModifiers::PolyWave );
+ if( parseFloat( f_number, true ) )
+ blend->setWaveFormExponent( f_number );
+ break;
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ return true;
+}
+
+bool PMPovrayParser::parseWarp( PMWarp* warp )
+{
+ int oldConsumed;
+ PMVector vector;
+ double f_number;
+ int i_number;
+ bool parsedFirst;
+ bool mapping;
+
+ if( !parseToken( WARP_TOK, "warp" ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ mapping = false;
+ parsedFirst = false;
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ if( !parsedFirst &&
+ ( m_token != REPEAT_TOK ||
+ m_token != BLACK_HOLE_TOK ||
+ m_token != TURBULENCE_TOK ||
+ m_token != CYLINDRICAL_TOK ||
+ m_token != SPHERICAL_TOK ||
+ m_token != TOROIDAL_TOK ||
+ m_token != PLANAR_TOK ) )
+ {
+ printError( i18n( "Expecting a warp type" ) );
+ return false;
+ }
+ switch( m_token )
+ {
+ case REPEAT_TOK:
+ nextToken( );
+ if( !parsedFirst )
+ {
+ warp->setWarpType( PMWarp::Repeat );
+ if( !parseVector( vector ) )
+ return false;
+ warp->setDirection( vector );
+ parsedFirst = true;
+ }
+ else
+ {
+ if( !parseVector( vector ) )
+ return false;
+ warp->setRepeat( vector );
+ }
+ break;
+ case OFFSET_TOK:
+ nextToken( );
+ if( !parseVector( vector ) )
+ return false;
+ warp->setOffset( vector );
+ break;
+ case FLIP_TOK:
+ nextToken( );
+ if( !parseVector( vector ) )
+ return false;
+ warp->setFlip( vector );
+ break;
+ case BLACK_HOLE_TOK:
+ nextToken( );
+ warp->setWarpType( PMWarp::BlackHole );
+ if( !parseVector( vector ) )
+ return false;
+ warp->setLocation( vector );
+ if( !parseToken( ',' ) )
+ return false;
+ if( !parseFloat( f_number ) )
+ return false;
+ warp->setRadius( f_number );
+ parsedFirst = true;
+ break;
+ case STRENGTH_TOK:
+ nextToken( );
+ if( !parseFloat( f_number ) )
+ return false;
+ warp->setStrength( f_number );
+ break;
+ case FALLOFF_TOK:
+ nextToken( );
+ if( !parseFloat( f_number ) )
+ return false;
+ warp->setFalloff( f_number );
+ break;
+ case INVERSE_TOK:
+ nextToken( );
+ warp->setInverse( true );
+ break;
+ case TURBULENCE_TOK:
+ if( !parsedFirst )
+ {
+ nextToken( );
+ warp->setWarpType( PMWarp::Turbulence );
+ if( !parseVector( vector ) )
+ return false;
+ warp->setValueVector( vector );
+ parsedFirst = true;
+ }
+ else
+ {
+ if( !parseVector( vector ) )
+ return false;
+ warp->setTurbulence( vector );
+ }
+ break;
+ case OCTAVES_TOK:
+ nextToken( );
+ if( !parseInt( i_number ) )
+ return false;
+ warp->setOctaves( i_number );
+ break;
+ case OMEGA_TOK:
+ nextToken( );
+ if( !parseFloat( f_number ) )
+ return false;
+ warp->setOmega( f_number );
+ break;
+ case LAMBDA_TOK:
+ nextToken( );
+ if( !parseFloat( f_number ) )
+ return false;
+ warp->setLambda( f_number );
+ break;
+ case CYLINDRICAL_TOK:
+ warp->setWarpType( PMWarp::Cylindrical );
+ mapping = true;
+ break;
+ case SPHERICAL_TOK:
+ warp->setWarpType( PMWarp::Spherical );
+ mapping = true;
+ break;
+ case TOROIDAL_TOK:
+ warp->setWarpType( PMWarp::Toroidal );
+ mapping = true;
+ break;
+ case PLANAR_TOK:
+ nextToken( );
+ warp->setWarpType( PMWarp::Planar );
+ if( parseVector( vector ) )
+ {
+ warp->setOrientation( vector );
+ if( parseToken( ',' ) )
+ {
+ if( !parseFloat( f_number ) )
+ return false;
+ warp->setDistExp( f_number );
+ }
+ }
+ parsedFirst = true;
+ break;
+ case DIST_EXP_TOK:
+ nextToken( );
+ if( !parseFloat( f_number ) )
+ return false;
+ warp->setDistExp( f_number );
+ break;
+ case MAJOR_RADIUS_TOK:
+ nextToken( );
+ if( !parseFloat( f_number ) )
+ return false;
+ warp->setMajorRadius( f_number );
+ break;
+ default:
+ break;
+ }
+
+ if( mapping)
+ {
+ nextToken( );
+ if( !parseVector( vector ) )
+ return false;
+ warp->setOrientation( vector );
+ parsedFirst = true;
+ mapping = false;
+ }
+
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parsePigment( PMPigment* pigment, bool parseOuter )
+{
+ PMColor c;
+ PMSolidColor* sc;
+ int oldConsumed;
+
+ if( parseOuter )
+ {
+ if( !parseToken( PIGMENT_TOK, "pigment" ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+ }
+
+ if( m_token == ID_TOK )
+ {
+ QString id( m_pScanner->sValue( ) );
+ PMSymbol* s = getSymbol( id );
+ bool skipID = false;
+
+ if( s )
+ if( s->type( ) == PMSymbol::Value )
+ skipID = true;
+
+ if( !skipID )
+ {
+ PMDeclare* decl = checkLink( id );
+ if( decl )
+ {
+ if( !pigment->setLinkedObject( decl ) )
+ printError( i18n( "Wrong declare type" ) );
+ }
+ nextToken( );
+ }
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( pigment );
+
+ switch( m_token )
+ {
+ case '<':
+ case COLOR_TOK:
+ case COLOUR_TOK:
+ case RGB_TOK:
+ case RGBT_TOK:
+ case RGBF_TOK:
+ case RGBFT_TOK:
+ case RED_TOK:
+ case GREEN_TOK:
+ case BLUE_TOK:
+ case TRANSMIT_TOK:
+ case FILTER_TOK:
+ case ID_TOK:
+ if( parseColor( c ) )
+ {
+ sc = new PMSolidColor( m_pPart );
+ sc->setColor( c );
+ if( !insertChild( sc, pigment ) )
+ {
+ delete sc;
+ sc = 0;
+ }
+ }
+ break;
+ case UV_MAPPING_TOK:
+ nextToken();
+ pigment->setUVMapping( parseBool( ) );
+ break;
+ default:
+ break;
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( parseOuter )
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseNormal( PMNormal* normal )
+{
+ double f_number;
+ int oldConsumed;
+
+ if( !parseToken( NORMAL_TOK, "normal" ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( m_token == ID_TOK )
+ {
+ QString id( m_pScanner->sValue( ) );
+ PMDeclare* decl = checkLink( id );
+ if( decl )
+ {
+ if( !normal->setLinkedObject( decl ) )
+ printError( i18n( "Wrong declare type" ) );
+ }
+ nextToken( );
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( normal );
+ switch( m_token )
+ {
+ case BUMP_SIZE_TOK:
+ nextToken( );
+ if( !parseFloat( f_number ) )
+ return false;
+ normal->enableBumpSize( true );
+ normal->setBumpSize( f_number );
+ break;
+ case ACCURACY_TOK:
+ nextToken( );
+ if( !parseFloat( f_number ) )
+ return false;
+ normal->setAccuracy( f_number );
+ break;
+ case UV_MAPPING_TOK:
+ nextToken( );
+ normal->setUVMapping( parseBool( ) );
+ default:
+ break;
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseTextureMap( PMTextureMap* textureMap )
+{
+ int oldConsumed;
+ double f_number1;
+ PMTexture* texture;
+ QValueList<double> mapValues;
+
+ if( !parseToken( TEXTURE_MAP_TOK, "texture_map" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( m_token == ID_TOK )
+ {
+ QString id( m_pScanner->sValue( ) );
+ PMDeclare* decl = checkLink( id );
+ if( decl )
+ {
+ if( !textureMap->setLinkedObject( decl ) )
+ printError( i18n( "Wrong declare type" ) );
+ }
+ nextToken( );
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+
+ if( m_token == '[' )
+ {
+ nextToken( );
+
+ if( !parseFloat( f_number1 ) )
+ return false;
+ mapValues.append( f_number1 );
+ texture = new PMTexture( m_pPart );
+
+ parseTexture( texture, false );
+
+ if( !insertChild( texture, textureMap ) )
+ delete texture;
+
+ if( !parseToken( ']' ) )
+ return false;
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ textureMap->setMapValues( mapValues );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parsePigmentMap( PMPigmentMap* pigmentMap )
+{
+ int oldConsumed;
+ double f_number1;
+ PMPigment* pigment;
+ QValueList<double> mapValues;
+
+ if( !parseToken( PIGMENT_MAP_TOK, "pigment_map" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( m_token == ID_TOK )
+ {
+ QString id( m_pScanner->sValue( ) );
+ PMDeclare* decl = checkLink( id );
+ if( decl )
+ {
+ if( !pigmentMap->setLinkedObject( decl ) )
+ printError( i18n( "Wrong declare type" ) );
+ }
+ nextToken( );
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+
+ if( m_token == '[' )
+ {
+ nextToken( );
+ if( !parseFloat( f_number1 ) )
+ return false;
+ mapValues.append( f_number1 );
+ pigment = new PMPigment( m_pPart );
+
+ parsePigment( pigment, false );
+ if( !insertChild( pigment, pigmentMap ) )
+ delete pigment;
+ if( !parseToken( ']' ) )
+ return false;
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ pigmentMap->setMapValues( mapValues );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseNormalMap( PMNormalMap* normalMap )
+{
+ int oldConsumed;
+ double f_number1;
+ PMNormal* normal;
+ QValueList<double> mapValues;
+
+ if( !parseToken( NORMAL_MAP_TOK, "normal_map" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( m_token == ID_TOK )
+ {
+ QString id( m_pScanner->sValue( ) );
+ PMDeclare* decl = checkLink( id );
+ if( decl )
+ {
+ if( !normalMap->setLinkedObject( decl ) )
+ printError( i18n( "Wrong declare type" ) );
+ }
+ nextToken( );
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+
+ // If we find '}' no need to search for an entry
+ if( m_token != '}' && parseToken( '[' ) )
+ {
+ if( !parseFloat( f_number1 ) )
+ return false;
+ mapValues.append( f_number1 );
+ normal = new PMNormal( m_pPart );
+ if( !parseNormal( normal ) )
+ {
+ delete normal;
+ return false;
+ }
+ if( !insertChild( normal, normalMap ) )
+ delete normal;
+ if( !parseToken( ']' ) )
+ return false;
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ normalMap->setMapValues( mapValues );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseBumpMap( PMBumpMap* bumpMap )
+{
+ int oldConsumed;
+ int i_number;
+ double f_number;
+
+ if( !parseToken( BUMP_MAP_TOK, "bump_map" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ // Parse the bitmap type
+ if( m_token != STRING_TOK )
+ {
+ switch( m_token )
+ {
+ case GIF_TOK:
+ bumpMap->setBitmapType( PMBumpMap::BitmapGif );
+ nextToken( );
+ break;
+ case TGA_TOK:
+ bumpMap->setBitmapType( PMBumpMap::BitmapTga );
+ nextToken( );
+ break;
+ case IFF_TOK:
+ bumpMap->setBitmapType( PMBumpMap::BitmapIff );
+ nextToken( );
+ break;
+ case PPM_TOK:
+ bumpMap->setBitmapType( PMBumpMap::BitmapPpm );
+ nextToken( );
+ break;
+ case PGM_TOK:
+ bumpMap->setBitmapType( PMBumpMap::BitmapPgm );
+ nextToken( );
+ break;
+ case PNG_TOK:
+ bumpMap->setBitmapType( PMBumpMap::BitmapPng );
+ nextToken( );
+ break;
+ case SYS_TOK:
+ bumpMap->setBitmapType( PMBumpMap::BitmapSys );
+ nextToken( );
+ break;
+ default:
+ printError( i18n( "Unknown bitmap type" ) );
+ return false;
+ }
+ }
+
+ // Parse the bitmap file name
+ if( m_token != STRING_TOK )
+ {
+ printError( i18n( "Expecting a file name." ) );
+ return false;
+ }
+ else
+ {
+ bumpMap->setBitmapFileName( m_pScanner->sValue( ) );
+ nextToken( );
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ switch( m_token )
+ {
+ case ONCE_TOK:
+ nextToken( );
+ bumpMap->enableOnce( true );
+ break;
+ case MAP_TYPE_TOK:
+ nextToken( );
+ if( !parseInt( i_number ) )
+ return false;
+ switch( i_number )
+ {
+ case 0:
+ bumpMap->setMapType( PMBumpMap::MapPlanar );
+ break;
+ case 1:
+ bumpMap->setMapType( PMBumpMap::MapSpherical );
+ break;
+ case 2:
+ bumpMap->setMapType( PMBumpMap::MapCylindrical );
+ break;
+ case 5:
+ bumpMap->setMapType( PMBumpMap::MapToroidal );
+ break;
+ }
+ break;
+ case INTERPOLATE_TOK:
+ nextToken( );
+ if( !parseInt( i_number ) )
+ return false;
+ switch( i_number )
+ {
+ case 2:
+ bumpMap->setInterpolateType( PMBumpMap::InterpolateBilinear );
+ break;
+ case 4:
+ bumpMap->setInterpolateType( PMBumpMap::InterpolateNormalized );
+ break;
+ }
+ break;
+ case USE_INDEX_TOK:
+ nextToken( );
+ bumpMap->enableUseIndex( true );
+ break;
+ case BUMP_SIZE_TOK:
+ nextToken( );
+ if( !parseFloat( f_number ) )
+ return false;
+ bumpMap->setBumpSize( f_number );
+ break;
+ default:
+ break;
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseMaterialMap( PMMaterialMap* materialMap )
+{
+ int oldConsumed;
+ int i_number;
+
+ if( !parseToken( MATERIAL_MAP_TOK, "material_map" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ // Parse the bitmap type
+ if( m_token != STRING_TOK )
+ {
+ switch( m_token )
+ {
+ case GIF_TOK:
+ materialMap->setBitmapType( PMMaterialMap::BitmapGif );
+ nextToken( );
+ break;
+ case TGA_TOK:
+ materialMap->setBitmapType( PMMaterialMap::BitmapTga );
+ nextToken( );
+ break;
+ case IFF_TOK:
+ materialMap->setBitmapType( PMMaterialMap::BitmapIff );
+ nextToken( );
+ break;
+ case PPM_TOK:
+ materialMap->setBitmapType( PMMaterialMap::BitmapPpm );
+ nextToken( );
+ break;
+ case PGM_TOK:
+ materialMap->setBitmapType( PMMaterialMap::BitmapPgm );
+ nextToken( );
+ break;
+ case PNG_TOK:
+ materialMap->setBitmapType( PMMaterialMap::BitmapPng );
+ nextToken( );
+ break;
+ case SYS_TOK:
+ materialMap->setBitmapType( PMMaterialMap::BitmapSys );
+ nextToken( );
+ break;
+ default:
+ printError( i18n( "Unknown bitmap type" ) );
+ return false;
+ }
+ }
+
+ // Parse the bitmap file name
+ if( m_token != STRING_TOK )
+ {
+ printError( i18n( "Expecting a file name." ) );
+ return false;
+ }
+ else
+ {
+ materialMap->setBitmapFileName( m_pScanner->sValue( ) );
+ nextToken( );
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( materialMap );
+ switch( m_token )
+ {
+ case ONCE_TOK:
+ nextToken( );
+ materialMap->enableOnce( true );
+ break;
+ case MAP_TYPE_TOK:
+ nextToken( );
+ if( !parseInt( i_number ) )
+ return false;
+ switch( i_number )
+ {
+ case 0:
+ materialMap->setMapType( PMMaterialMap::MapPlanar );
+ break;
+ case 1:
+ materialMap->setMapType( PMMaterialMap::MapSpherical );
+ break;
+ case 2:
+ materialMap->setMapType( PMMaterialMap::MapCylindrical );
+ break;
+ case 5:
+ materialMap->setMapType( PMMaterialMap::MapToroidal );
+ break;
+ }
+ break;
+ case INTERPOLATE_TOK:
+ nextToken( );
+ if( !parseInt( i_number ) )
+ return false;
+ switch( i_number )
+ {
+ case 2:
+ materialMap->setInterpolateType( PMMaterialMap::InterpolateBilinear );
+ break;
+ case 4:
+ materialMap->setInterpolateType( PMMaterialMap::InterpolateNormalized );
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseSlopeMap( PMSlopeMap* slopeMap )
+{
+ int oldConsumed;
+ double f_number1;
+ PMSlope* slope;
+ QValueList<double> mapValues;
+
+ if( !parseToken( SLOPE_MAP_TOK, "slope_map" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( m_token == ID_TOK )
+ {
+ QString id( m_pScanner->sValue( ) );
+ PMDeclare* decl = checkLink( id );
+ if( decl )
+ {
+ if( !slopeMap->setLinkedObject( decl ) )
+ printError( i18n( "Wrong declare type" ) );
+ }
+ nextToken( );
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+
+ // If we find '}' no need to search for an entry
+ if( m_token != '}' && parseToken( '[' ) )
+ {
+ if( !parseFloat( f_number1 ) )
+ return false;
+ mapValues.append( f_number1 );
+ slope = new PMSlope( m_pPart );
+ if( !parseSlope( slope ) )
+ {
+ delete slope;
+ return false;
+ }
+ if( !insertChild( slope, slopeMap ) )
+ delete slope;
+ if( !parseToken( ']' ) )
+ return false;
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ slopeMap->setMapValues( mapValues );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseDensityMap( PMDensityMap* densityMap )
+{
+ int oldConsumed;
+ double f_number1;
+ PMDensity* density;
+ QValueList<double> mapValues;
+
+ if( !parseToken( DENSITY_MAP_TOK, "density_map" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( m_token == ID_TOK )
+ {
+ QString id( m_pScanner->sValue( ) );
+ PMDeclare* decl = checkLink( id );
+ if( decl )
+ {
+ if( !densityMap->setLinkedObject( decl ) )
+ printError( i18n( "Wrong declare type" ) );
+ }
+ nextToken( );
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+
+ // If we find '}' no need to search for an entry
+ if( m_token != '}' && parseToken( '[' ) )
+ {
+ if( !parseFloat( f_number1 ) )
+ return false;
+ mapValues.append( f_number1 );
+ density = new PMDensity( m_pPart );
+ if( !parseDensity( density ) )
+ {
+ delete density;
+ return false;
+ }
+ if( !insertChild( density, densityMap ) )
+ delete density;
+ if( !parseToken( ']' ) )
+ return false;
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ densityMap->setMapValues( mapValues );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseImageMap( PMImageMap* imageMap )
+{
+ int oldConsumed;
+ int i_number;
+ double f_number;
+ PMPaletteValue newPaletteValue;
+ QValueList<PMPaletteValue> l_valuesFilter;
+ QValueList<PMPaletteValue> l_valuesTransmit;
+
+ if( !parseToken( IMAGE_MAP_TOK, "image_map" ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ // Parse the bitmap type
+ if( m_token != STRING_TOK )
+ {
+ switch( m_token )
+ {
+ case GIF_TOK:
+ imageMap->setBitmapType( PMImageMap::BitmapGif );
+ nextToken( );
+ break;
+ case TGA_TOK:
+ imageMap->setBitmapType( PMImageMap::BitmapTga );
+ nextToken( );
+ break;
+ case IFF_TOK:
+ imageMap->setBitmapType( PMImageMap::BitmapIff );
+ nextToken( );
+ break;
+ case PPM_TOK:
+ imageMap->setBitmapType( PMImageMap::BitmapPpm );
+ nextToken( );
+ break;
+ case PGM_TOK:
+ imageMap->setBitmapType( PMImageMap::BitmapPgm );
+ nextToken( );
+ break;
+ case PNG_TOK:
+ imageMap->setBitmapType( PMImageMap::BitmapPng );
+ nextToken( );
+ break;
+ case SYS_TOK:
+ imageMap->setBitmapType( PMImageMap::BitmapSys );
+ nextToken( );
+ break;
+ default:
+ printError( i18n( "Unknown bitmap type" ) );
+ return false;
+ }
+ }
+
+ // Parse the bitmap file name
+ if( m_token != STRING_TOK )
+ {
+ printError( i18n( "Expecting a file name." ) );
+ return false;
+ }
+ else
+ {
+ imageMap->setBitmapFileName( m_pScanner->sValue( ) );
+ nextToken( );
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ switch( m_token )
+ {
+ case TRANSMIT_TOK:
+ nextToken( );
+ if( m_token == ALL_TOK )
+ {
+ nextToken( );
+ if( !parseFloat( f_number ) )
+ return false;
+ imageMap->enableTransmitAll( true );
+ imageMap->setTransmitAll( f_number );
+ }
+ else
+ {
+ if( !parseInt( i_number ) )
+ return false;
+ parseToken( ',' );
+ if( !parseFloat( f_number ) )
+ return false;
+ newPaletteValue.setIndex( i_number );
+ newPaletteValue.setValue( f_number );
+ l_valuesTransmit.append( newPaletteValue );
+ }
+ break;
+ case FILTER_TOK:
+ nextToken( );
+ if( m_token == ALL_TOK )
+ {
+ nextToken( );
+ if( !parseFloat( f_number ) )
+ return false;
+ imageMap->enableFilterAll( true );
+ imageMap->setFilterAll( f_number );
+ }
+ else
+ {
+ if( !parseInt( i_number ) )
+ return false;
+ parseToken( ',' );
+ if( !parseFloat( f_number ) )
+ return false;
+ newPaletteValue.setIndex( i_number );
+ newPaletteValue.setValue( f_number );
+ l_valuesFilter.append( newPaletteValue );
+ }
+ break;
+ case ONCE_TOK:
+ nextToken( );
+ imageMap->enableOnce( true );
+ break;
+ case MAP_TYPE_TOK:
+ nextToken( );
+ if( !parseInt( i_number ) )
+ return false;
+ switch( i_number )
+ {
+ case 0:
+ imageMap->setMapType( PMImageMap::MapPlanar );
+ break;
+ case 1:
+ imageMap->setMapType( PMImageMap::MapSpherical );
+ break;
+ case 2:
+ imageMap->setMapType( PMImageMap::MapCylindrical );
+ break;
+ case 5:
+ imageMap->setMapType( PMImageMap::MapToroidal );
+ break;
+ }
+ break;
+ case INTERPOLATE_TOK:
+ nextToken( );
+ if( !parseInt( i_number ) )
+ return false;
+ switch( i_number )
+ {
+ case 2:
+ imageMap->setInterpolateType( PMImageMap::InterpolateBilinear );
+ break;
+ case 4:
+ imageMap->setInterpolateType( PMImageMap::InterpolateNormalized );
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+ imageMap->setFilters( l_valuesFilter );
+ imageMap->setTransmits( l_valuesTransmit );
+
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parsePigmentList( PMPigmentList* pigmentList, int expectedItems )
+{
+ int oldConsumed;
+ PMPigment* pigment;
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ pigment = new PMPigment( m_pPart );
+ if( !parsePigment( pigment ) )
+ {
+ delete pigment;
+ return false;
+ }
+ if( !insertChild( pigment, pigmentList ) )
+ delete pigment;
+
+ // In the last entry don't expect a comma
+ if( expectedItems-- )
+ if( m_token == ',' )
+ nextToken( );
+ }
+ while( oldConsumed != m_consumedTokens && expectedItems );
+
+ return true;
+}
+
+bool PMPovrayParser::parseColorList( PMColorList* colorList, int expectedItems )
+{
+ int oldConsumed;
+ PMColor color;
+ PMSolidColor* sc;
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ if( !parseColor( color ) )
+ {
+ return false;
+ }
+ sc = new PMSolidColor( m_pPart );
+ sc->setColor( color );
+ if( !insertChild( sc, colorList ) )
+ delete sc;
+
+ // In the last entry don't expect a comma
+ if( expectedItems-- )
+ if( m_token == ',' )
+ nextToken( );
+ }
+ while( oldConsumed != m_consumedTokens && expectedItems );
+
+ return true;
+}
+
+bool PMPovrayParser::parseNormalList( PMNormalList* normalList, int expectedItems )
+{
+ int oldConsumed;
+ PMNormal* normal;
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ normal = new PMNormal( m_pPart );
+ if( !parseNormal( normal ) )
+ {
+ delete normal;
+ return false;
+ }
+ if( !insertChild( normal, normalList ) )
+ delete normal;
+
+ // In the last entry don't expect a comma
+ if( expectedItems-- )
+ if( m_token == ',' )
+ nextToken( );
+ }
+ while( oldConsumed != m_consumedTokens && expectedItems );
+
+ return true;
+}
+
+bool PMPovrayParser::parseTextureList( PMTextureList* textureList, int expectedItems )
+{
+ int oldConsumed;
+ PMTexture* texture;
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ texture = new PMTexture( m_pPart );
+ if( !parseTexture( texture ) )
+ {
+ delete texture;
+ return false;
+ }
+ if( !insertChild( texture, textureList ) )
+ delete texture;
+
+ // In the last entry don't expect a comma
+ if( expectedItems-- )
+ if( m_token == ',' )
+ nextToken( );
+ }
+ while( oldConsumed != m_consumedTokens && expectedItems );
+
+ return true;
+}
+
+bool PMPovrayParser::parseDensityList( PMDensityList* densityList, int expectedItems )
+{
+ int oldConsumed;
+ PMDensity* density;
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ density = new PMDensity( m_pPart );
+ if( !parseDensity( density ) )
+ {
+ delete density;
+ return false;
+ }
+ if( !insertChild( density, densityList ) )
+ delete density;
+
+ // In the last entry don't expect a comma
+ if( expectedItems-- )
+ if( m_token == ',' )
+ nextToken( );
+ }
+ while( oldConsumed != m_consumedTokens && expectedItems );
+
+ return true;
+}
+
+bool PMPovrayParser::parseColorMap( PMColorMap* colorMap )
+{
+ int oldConsumed;
+ double f_number1, f_number2;
+ PMColor color1, color2;
+ PMSolidColor* solidColor;
+ PMSolidColor* lastColor = 0;
+ QValueList<double> mapValues;
+ bool newEntry;
+ bool twoColors;
+
+ if( m_token != COLOR_MAP_TOK && m_token != COLOUR_MAP_TOK )
+ return false;
+ nextToken( );
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( m_token == ID_TOK )
+ {
+ QString id( m_pScanner->sValue( ) );
+ PMDeclare* decl = checkLink( id );
+ if( decl )
+ {
+ if( !colorMap->setLinkedObject( decl ) )
+ printError( i18n( "Wrong declare type" ) );
+ }
+ nextToken( );
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+
+ if( m_token == '[' )
+ {
+ nextToken( );
+ if( !parseFloat( f_number1 ) )
+ return false;
+
+ twoColors = false;
+ if( m_token == ',' )
+ {
+ twoColors = true;
+ nextToken( );
+ }
+ else if( ( m_token == INTEGER_TOK ) || ( m_token == FLOAT_TOK ) )
+ twoColors = true;
+
+ if( twoColors )
+ {
+ // Two colors in the same entry
+
+ if( parseFloat( f_number2 ) )
+ {
+ if( !parseColor( color1 ) )
+ return false;
+ if( !parseColor( color2 ) )
+ return false;
+ // If the first value doesn't pick up from the previous,
+ // or the color is different...
+ newEntry = true;
+ if( lastColor && !mapValues.isEmpty( ) )
+ if( ( mapValues.last( ) == f_number1 ) &&
+ ( lastColor->color( ) == color1 ) )
+ newEntry = false;
+
+ if( newEntry )
+ {
+ // ... add the two colors in two different entries ...
+ mapValues.append( f_number1 );
+ solidColor = new PMSolidColor( m_pPart );
+ solidColor->setColor( color1 );
+ if( !insertChild( solidColor, colorMap ) )
+ delete solidColor;
+ else
+ lastColor = solidColor;
+
+ mapValues.append( f_number2 );
+ solidColor = new PMSolidColor( m_pPart );
+ solidColor->setColor( color2 );
+ if( !insertChild( solidColor, colorMap ) )
+ delete solidColor;
+ else
+ lastColor = solidColor;
+ }
+ else
+ {
+ // ... else just add the last value and color
+ mapValues.append( f_number2 );
+ solidColor = new PMSolidColor( m_pPart );
+ solidColor->setColor( color2 );
+ if( !insertChild( solidColor, colorMap ) )
+ delete solidColor;
+ else
+ lastColor = solidColor;
+ }
+ }
+ }
+ else
+ {
+ // Only one color in the entry
+ if( !parseColor( color1 ) )
+ return false;
+ mapValues.append( f_number1 );
+ solidColor = new PMSolidColor( m_pPart );
+ solidColor->setColor( color1 );
+ if( !insertChild( solidColor, colorMap ) )
+ delete solidColor;
+ else
+ lastColor = solidColor;
+ }
+ if( !parseToken( ']' ) )
+ return false;
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ colorMap->setMapValues( mapValues );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseSkySphere( PMSkySphere* sky )
+{
+ int oldConsumed;
+
+ if( !parseToken( SKY_SPHERE_TOK, "sky_sphere" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( m_token == ID_TOK )
+ {
+ QString id( m_pScanner->sValue( ) );
+ PMDeclare* decl = checkLink( id );
+ if( decl )
+ {
+ if( !sky->setLinkedObject( decl ) )
+ printError( i18n( "Wrong declare type" ) );
+ }
+ nextToken( );
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( sky );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseRainbow( PMRainbow* rainbow )
+{
+ PMVector vector;
+ double f_number;
+ int oldConsumed;
+
+ if( !parseToken( RAINBOW_TOK, "rainbow" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( m_token == ID_TOK )
+ {
+ QString id( m_pScanner->sValue( ) );
+ PMDeclare* decl = checkLink( id );
+ if( decl )
+ {
+ if( !rainbow->setLinkedObject( decl ) )
+ printError( i18n( "Wrong declare type" ) );
+ }
+ nextToken( );
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( rainbow );
+ switch( m_token )
+ {
+ case DIRECTION_TOK:
+ nextToken( );
+ if( parseVector( vector ) )
+ {
+ rainbow->enableDirection( true );
+ rainbow->setDirection( vector );
+ }
+ break;
+ case ANGLE_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ {
+ rainbow->enableAngle( true );
+ rainbow->setAngle( f_number );
+ }
+ break;
+ case WIDTH_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ {
+ rainbow->enableWidth( true );
+ rainbow->setWidth( f_number );
+ }
+ break;
+ case DISTANCE_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ {
+ rainbow->enableDistance( true );
+ rainbow->setDistance( f_number );
+ }
+ break;
+ case JITTER_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ {
+ rainbow->enableJitter( true );
+ rainbow->setJitter( f_number );
+ }
+ break;
+ case UP_TOK:
+ nextToken( );
+ if( parseVector( vector ) )
+ {
+ rainbow->enableUp( true );
+ rainbow->setUp( vector );
+ }
+ break;
+ case ARC_ANGLE_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ {
+ rainbow->enableArcAngle( true );
+ rainbow->setArcAngle( f_number );
+ }
+ break;
+ case FALLOFF_ANGLE_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ {
+ rainbow->enableFalloffAngle( true );
+ rainbow->setFalloffAngle( f_number );
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseFog( PMFog* fog )
+{
+ PMColor color;
+ PMVector vector;
+ double f_number;
+ int i_number;
+ int fog_type;
+ int oldConsumed;
+
+ if( !parseToken( FOG_TOK, "fog" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( m_token == ID_TOK )
+ {
+ QString id( m_pScanner->sValue( ) );
+ PMDeclare* decl = checkLink( id );
+ if( decl )
+ {
+ if( !fog->setLinkedObject( decl ) )
+ printError( i18n( "Wrong declare type" ) );
+ }
+ nextToken( );
+ }
+
+ fog_type = 1;
+ if( parseToken( FOG_TYPE_TOK, "fog_type" ) )
+ {
+ if( !parseInt( i_number ) )
+ return false;
+ fog_type = i_number;
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ switch( m_token )
+ {
+ case DISTANCE_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ fog->setDistance( f_number );
+ break;
+ case '<':
+ case COLOR_TOK:
+ case COLOUR_TOK:
+ case RGB_TOK:
+ case RGBT_TOK:
+ case RGBF_TOK:
+ case RGBFT_TOK:
+ case RED_TOK:
+ case GREEN_TOK:
+ case BLUE_TOK:
+ case TRANSMIT_TOK:
+ case FILTER_TOK:
+ case ID_TOK:
+ if( parseColor( color ) )
+ fog->setColor( color );
+ break;
+ case TURBULENCE_TOK:
+ nextToken( );
+ fog->enableTurbulence( true );
+ if( !parseVector( vector ) )
+ return false;
+ fog->setValueVector( vector );
+ break;
+ case OCTAVES_TOK:
+ nextToken( );
+ if( !parseInt( i_number ) )
+ return false;
+ fog->setOctaves( i_number );
+ break;
+ case OMEGA_TOK:
+ nextToken( );
+ if( !parseFloat( f_number ) )
+ return false;
+ fog->setOmega( f_number );
+ break;
+ case LAMBDA_TOK:
+ nextToken( );
+ if( !parseFloat( f_number ) )
+ return false;
+ fog->setLambda( f_number );
+ break;
+ case TURB_DEPTH_TOK:
+ nextToken( );
+ if( !parseFloat( f_number ) )
+ return false;
+ fog->setDepth( f_number );
+ break;
+ case FOG_OFFSET_TOK:
+ nextToken( );
+ fog_type = 2;
+ if( parseFloat( f_number ) )
+ fog->setFogOffset( f_number );
+ break;
+ case FOG_ALT_TOK:
+ nextToken( );
+ fog_type = 2;
+ if( parseFloat( f_number ) )
+ fog->setFogAlt( f_number );
+ break;
+ case UP_TOK:
+ nextToken( );
+ fog_type = 2;
+ if( !parseVector( vector ) )
+ return false;
+ fog->setUp( vector );
+ break;
+ default:
+ break;
+ }
+ // Only parseChildObjects() if the token is not turbulence, because this
+ // function parses that token.
+ if( m_token != TURBULENCE_TOK )
+ parseChildObjects( fog );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ fog->setFogType( fog_type );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseMedia( PMMedia* media )
+{
+ PMColor color;
+ double f_number;
+ int i_number;
+ int oldConsumed, oldConsumed1;
+
+ if( !parseToken( MEDIA_TOK, "media" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( m_token == ID_TOK )
+ {
+ QString id( m_pScanner->sValue( ) );
+ PMDeclare* decl = checkLink( id );
+ if( decl )
+ {
+ if( !media->setLinkedObject( decl ) )
+ printError( i18n( "Wrong declare type" ) );
+ }
+ nextToken( );
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( media );
+ switch( m_token )
+ {
+ case METHOD_TOK:
+ nextToken( );
+ if( parseInt( i_number ) )
+ media->setMethod( i_number );
+ break;
+ case INTERVALS_TOK:
+ nextToken( );
+ if( parseInt( i_number ) )
+ media->setIntervals( i_number );
+ break;
+ case SAMPLES_TOK:
+ nextToken( );
+ if( parseInt( i_number ) )
+ media->setSamplesMin( i_number );
+ parseToken( ',' );
+ if( parseInt( i_number ) )
+ media->setSamplesMax( i_number );
+ break;
+ case CONFIDENCE_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ media->setConfidence( f_number );
+ break;
+ case VARIANCE_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ media->setVariance( f_number );
+ break;
+ case RATIO_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ media->setRatio( f_number );
+ break;
+ case AA_LEVEL_TOK:
+ nextToken( );
+ if ( parseInt( i_number ) )
+ media->setAALevel( i_number );
+ break;
+ case AA_THRESHOLD_TOK:
+ nextToken( );
+ if ( parseFloat( f_number ) )
+ media->setAAThreshold( f_number );
+ break;
+ case ABSORPTION_TOK:
+ nextToken( );
+ if( parseColor( color ) )
+ {
+ media->enableAbsorption( true );
+ media->setAbsorption( color );
+ }
+ break;
+ case EMISSION_TOK:
+ nextToken( );
+ media->enableEmission( true );
+ if( parseColor( color ) )
+ media->setEmission( color );
+ break;
+ case SCATTERING_TOK:
+ nextToken( );
+ parseToken( '{' );
+ media->enableScattering( true );
+ if( parseInt( i_number ) )
+ media->setScatteringType( i_number );
+ parseToken( ',' );
+ if( parseColor( color ) )
+ media->setScatteringColor( color );
+ do
+ {
+ oldConsumed1 = m_consumedTokens;
+ switch( m_token )
+ {
+ case ECCENTRICITY_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ media->setScatteringEccentricity( f_number );
+ break;
+ case EXTINCTION_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ media->setScatteringExtinction( f_number );
+ break;
+ default:
+ break;
+ }
+ }
+ while( oldConsumed1 != m_consumedTokens );
+ parseToken( '}' );
+ break;
+ default:
+ break;
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseDensity( PMDensity* density )
+{
+ int oldConsumed;
+
+ if( !parseToken( DENSITY_TOK, "density" ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( m_token == ID_TOK )
+ {
+ QString id( m_pScanner->sValue( ) );
+ PMDeclare* decl = checkLink( id );
+ if( decl )
+ {
+ if( !density->setLinkedObject( decl ) )
+ printError( i18n( "Wrong declare type" ) );
+ }
+ nextToken( );
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( density );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseInterior( PMInterior* interior )
+{
+ double f_number;
+ int i_number;
+ int oldConsumed;
+
+ if( !parseToken( INTERIOR_TOK, "interior" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( m_token == ID_TOK )
+ {
+ QString id( m_pScanner->sValue( ) );
+ PMDeclare* decl = checkLink( id );
+ if( decl )
+ {
+ if( !interior->setLinkedObject( decl ) )
+ printError( i18n( "Wrong declare type" ) );
+ }
+ nextToken( );
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( interior );
+ switch( m_token )
+ {
+ case IOR_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ {
+ interior->enableIor( true );
+ interior->setIor( f_number );
+ }
+ break;
+ case CAUSTICS_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ {
+ interior->enableCaustics( true );
+ interior->setCaustics( f_number );
+ }
+ break;
+ case DISPERSION_TOK:
+ nextToken( );
+ if ( parseFloat( f_number ) )
+ {
+ interior->enableDispersion( true );
+ interior->setDispersion( f_number );
+ }
+ break;
+ case DISPERSION_SAMPLES_TOK:
+ nextToken( );
+ if ( parseInt( i_number ) )
+ {
+ interior->enableDispSamples( true );
+ interior->setDispSamples( i_number );
+ }
+ break;
+ case FADE_DISTANCE_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ {
+ interior->enableFadeDistance( true );
+ interior->setFadeDistance( f_number );
+ }
+ break;
+ case FADE_POWER_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ {
+ interior->enableFadePower( true );
+ interior->setFadePower( f_number );
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseMaterial( PMMaterial* material )
+{
+ int oldConsumed;
+
+ if( !parseToken( MATERIAL_TOK, "material" ) )
+ return false;
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( m_token == ID_TOK )
+ {
+ QString id( m_pScanner->sValue( ) );
+ PMDeclare* decl = checkLink( id );
+ if( decl )
+ {
+ if( !material->setLinkedObject( decl ) )
+ printError( i18n( "Wrong declare type" ) );
+ }
+ nextToken( );
+ }
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( material );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseSlope( PMSlope* slope )
+{
+ double f_number;
+
+ if( !parseToken( '<' ) )
+ return false;
+ if( !parseFloat( f_number ) )
+ return false;
+ slope->setHeight( f_number );
+ if( !parseToken( ',' ) )
+ return false;
+ if( !parseFloat( f_number ) )
+ return false;
+ slope->setSlope( f_number );
+ if( !parseToken( '>' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseGlobalSettings( PMGlobalSettings* globalsettings )
+{
+ PMColor color;
+ double f_number;
+ int i_number;
+ int oldConsumed;
+
+ // Initial global settings tokens
+ if( !parseToken( GLOBAL_SETTINGS_TOK, "global_settings" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ // Parse global settings tokens
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( globalsettings );
+
+ switch( m_token )
+ {
+ case ADC_BAILOUT_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ globalsettings->setAdcBailout( f_number );
+ break;
+ case AMBIENT_LIGHT_TOK:
+ nextToken( );
+ if( parseColor( color ) )
+ globalsettings->setAmbientLight( color );
+ break;
+ case ASSUMED_GAMMA_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ globalsettings->setAssumedGamma( f_number );
+ break;
+ case HF_GRAY_16_TOK:
+ nextToken( );
+ switch( m_token )
+ {
+ case ON_TOK:
+ globalsettings->setHfGray16( true );
+ nextToken( );
+ break;
+ case OFF_TOK:
+ globalsettings->setHfGray16( false );
+ nextToken( );
+ break;
+ default:
+ break;
+ }
+ break;
+ case IRID_WAVELENGTH_TOK:
+ nextToken( );
+ if( parseColor( color ) )
+ globalsettings->setIridWaveLength( color );
+ break;
+ case MAX_INTERSECTIONS_TOK:
+ nextToken( );
+ if( parseInt( i_number ) )
+ globalsettings->setMaxIntersections( i_number );
+ break;
+ case MAX_TRACE_LEVEL_TOK:
+ nextToken( );
+ if( parseInt( i_number ) )
+ globalsettings->setMaxTraceLevel( i_number );
+ break;
+ case NUMBER_OF_WAVES_TOK:
+ nextToken( );
+ if( parseInt( i_number ) )
+ globalsettings->setNumberWaves( i_number );
+ break;
+ case NOISE_GENERATOR_TOK:
+ nextToken( );
+ if ( parseInt( i_number ) )
+ globalsettings->setNoiseGenerator(
+ ( PMGlobalSettings::PMNoiseType ) ( i_number - 1 ) );
+ break;
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseFinish( PMFinish* finish )
+{
+ PMColor color;
+ double f_number;
+ int oldConsumed, oldConsumed1;
+
+ // Initial finish tokens "finish {"
+ if( !parseToken( FINISH_TOK, "finish" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ // Parse a possible declare link identifier
+ if( m_token == ID_TOK )
+ {
+ QString id( m_pScanner->sValue( ) );
+ PMDeclare* decl = checkLink( id );
+ if( decl )
+ {
+ if( !finish->setLinkedObject( decl ) )
+ printError( i18n( "Wrong declare type" ) );
+ }
+ nextToken( );
+ }
+
+ // Parse finish tokens
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ switch( m_token )
+ {
+ case AMBIENT_TOK:
+ nextToken( );
+ finish->enableAmbient( true );
+ if( parseColor( color ) )
+ finish->setAmbientColor( color );
+ break;
+ case DIFFUSE_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ {
+ finish->enableDiffuse( true );
+ finish->setDiffuse( f_number );
+ }
+ break;
+ case BRILLIANCE_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ {
+ finish->enableBrilliance( true );
+ finish->setBrilliance( f_number );
+ }
+ break;
+ case PHONG_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ {
+ finish->enablePhong( true );
+ finish->setPhong( f_number );
+ }
+ break;
+ case PHONG_SIZE_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ {
+ finish->enablePhongSize( true );
+ finish->setPhongSize( f_number );
+ }
+ break;
+ case METALLIC_TOK:
+ nextToken( );
+ finish->enableMetallic( true );
+ finish->setMetallic( 1.0 );
+ if( parseFloat( f_number, true ) )
+ finish->setMetallic( f_number );
+ break;
+ case SPECULAR_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ {
+ finish->enableSpecular( true );
+ finish->setSpecular( f_number );
+ }
+ break;
+ case ROUGHNESS_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ {
+ finish->enableRoughness( true );
+ finish->setRoughness( f_number );
+ }
+ break;
+ case CRAND_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ {
+ finish->enableCrand( true );
+ finish->setCrand( f_number );
+ }
+ break;
+ case CONSERVE_ENERGY_TOK:
+ nextToken( );
+ finish->setConserveEnergy( parseBool( ) );
+ break;
+ case REFLECTION_TOK:
+ nextToken( );
+ finish->enableReflection( true );
+ if( !parseToken( '{' ) )
+ {
+ printError( i18n( "Using Old Reflection Syntax" ) );
+ if( parseColor( color ) )
+ finish->setReflectionColor( color );
+ }
+ else if( parseColor( color ) )
+ {
+ if( parseToken( ',' ) )
+ {
+ finish->enableReflectionMin( true );
+ finish->setReflectionMinColor( color );
+ if( parseColor( color ) )
+ finish->setReflectionColor( color );
+ else
+ return false;
+ }
+ else
+ finish->setReflectionColor( color );
+
+ do
+ {
+ oldConsumed1 = m_consumedTokens;
+ switch( m_token )
+ {
+ case FRESNEL_TOK:
+ nextToken( );
+ finish->setReflectionFresnel( parseBool( ) );
+ break;
+ case FALLOFF_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ {
+ finish->enableRefFalloff( true );
+ finish->setReflectionFalloff( f_number );
+ }
+ break;
+ case EXPONENT_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ {
+ finish->enableRefExponent( true );
+ finish->setReflectionExponent( f_number );
+ }
+ break;
+ case METALLIC_TOK:
+ nextToken( );
+ if ( parseFloat( f_number ) )
+ {
+ finish->enableRefMetallic( true );
+ finish->setReflectionMetallic( f_number );
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ while( oldConsumed1 != m_consumedTokens );
+ parseToken( '}' );
+ }
+ else
+ return false;
+ break;
+ case REFLECTION_EXPONENT_TOK:
+ nextToken( );
+ if ( parseFloat( f_number ) )
+ {
+ finish->enableRefExponent( true );
+ finish->setReflectionExponent( f_number );
+ }
+ break;
+ case IRID_TOK:
+ nextToken( );
+ parseToken( '{' );
+ finish->setIrid( true );
+ if( parseFloat( f_number ) )
+ finish->setIridAmount( f_number );
+ do
+ {
+ oldConsumed1 = m_consumedTokens;
+ switch( m_token )
+ {
+ case THICKNESS_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ finish->setIridThickness( f_number );
+ break;
+ case TURBULENCE_TOK:
+ nextToken( );
+ if( parseFloat( f_number ) )
+ finish->setIridTurbulence( f_number );
+ break;
+ default:
+ break;
+ }
+ }
+ while( oldConsumed1 != m_consumedTokens );
+ parseToken( '}' );
+ break;
+ default:
+ break;
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseDeclare( PMDeclare* decl )
+{
+ PMObject* child = 0;
+ PMTexture* texture = 0;
+ bool error = false;
+
+ switch( m_token )
+ {
+ case OBJECT_TOK:
+ error = !parseObject( decl );
+ break;
+ // finite solid
+ case BLOB_TOK:
+ child = new PMBlob( m_pPart );
+ error = !parseBlob( ( PMBlob* ) child );
+ break;
+ case BOX_TOK:
+ child = new PMBox( m_pPart );
+ error = !parseBox( ( PMBox* ) child );
+ break;
+ case CONE_TOK:
+ child = new PMCone( m_pPart );
+ error = !parseCone( ( PMCone* ) child );
+ break;
+ case CYLINDER_TOK:
+ child = new PMCylinder( m_pPart );
+ error = !parseCylinder( ( PMCylinder* ) child );
+ break;
+ case HEIGHT_FIELD_TOK:
+ child = new PMHeightField( m_pPart );
+ error = !parseHeightField( ( PMHeightField* ) child );
+ break;
+ case JULIA_FRACTAL_TOK:
+ child = new PMJuliaFractal( m_pPart );
+ error = !parseJuliaFractal( ( PMJuliaFractal* ) child );
+ break;
+ case LATHE_TOK:
+ child = new PMLathe( m_pPart );
+ error = !parseLathe( ( PMLathe* ) child );
+ break;
+ case PRISM_TOK:
+ child = new PMPrism( m_pPart );
+ error = !parsePrism( ( PMPrism* ) child );
+ break;
+ case SPHERE_TOK:
+ child = new PMSphere( m_pPart );
+ error = !parseSphere( ( PMSphere* ) child );
+ break;
+ case SUPERELLIPSOID_TOK:
+ child = new PMSuperquadricEllipsoid( m_pPart );
+ error = !parseSqe( ( PMSuperquadricEllipsoid* ) child );
+ break;
+ case SOR_TOK:
+ child = new PMSurfaceOfRevolution( m_pPart );
+ error = !parseSor( ( PMSurfaceOfRevolution* ) child );
+ break;
+ case TEXT_TOK:
+ child = new PMText( m_pPart );
+ error = !parseText( ( PMText* ) child );
+ break;
+ case TORUS_TOK:
+ child = new PMTorus( m_pPart );
+ error = !parseTorus( ( PMTorus* ) child );
+ break;
+ // finite patch
+ case BICUBIC_PATCH_TOK:
+ child = new PMBicubicPatch( m_pPart );
+ error = !parseBicubicPatch( ( PMBicubicPatch* ) child );
+ break;
+ case DISC_TOK:
+ child = new PMDisc( m_pPart );
+ error = !parseDisc( ( PMDisc* ) child );
+ break;
+ case TRIANGLE_TOK:
+ case SMOOTH_TRIANGLE_TOK:
+ child = new PMTriangle( m_pPart );
+ error = !parseTriangle( ( PMTriangle* ) child );
+ break;
+ // infinite solid
+ case PLANE_TOK:
+ child = new PMPlane( m_pPart );
+ error = !parsePlane( ( PMPlane* ) child );
+ break;
+ case QUADRIC_TOK:
+ case CUBIC_TOK:
+ case QUARTIC_TOK:
+ case POLY_TOK:
+ child = new PMPolynom( m_pPart );
+ error = !parsePolynom( ( PMPolynom* ) child );
+ break;
+ // csg
+ case UNION_TOK:
+ case DIFFERENCE_TOK:
+ case INTERSECTION_TOK:
+ case MERGE_TOK:
+ child = new PMCSG( m_pPart );
+ error = !parseCSG( ( PMCSG* ) child );
+ break;
+ // textures
+ case TEXTURE_TOK:
+ while( m_token == TEXTURE_TOK )
+ {
+ texture = new PMTexture( m_pPart );
+ if( !parseTexture( texture ) )
+ error = true;
+ if( !insertChild( texture, decl ) )
+ {
+ delete texture;
+ texture = 0;
+ }
+ }
+ break;
+ case PIGMENT_TOK:
+ child = new PMPigment( m_pPart );
+ error = !parsePigment( ( PMPigment* ) child );
+ break;
+ case NORMAL_TOK:
+ child = new PMNormal( m_pPart );
+ error = !parseNormal( ( PMNormal* ) child );
+ break;
+ case FINISH_TOK:
+ child = new PMFinish( m_pPart );
+ error = !parseFinish( ( PMFinish* ) child );
+ break;
+ case TEXTURE_MAP_TOK:
+ child = new PMTextureMap( m_pPart );
+ error = !parseTextureMap( ( PMTextureMap* ) child );
+ break;
+ case PIGMENT_MAP_TOK:
+ child = new PMPigmentMap( m_pPart );
+ error = !parsePigmentMap( ( PMPigmentMap* ) child );
+ break;
+ case COLOR_MAP_TOK:
+ case COLOUR_MAP_TOK:
+ child = new PMColorMap( m_pPart );
+ error = !parseColorMap( ( PMColorMap* ) child );
+ break;
+ case NORMAL_MAP_TOK:
+ child = new PMNormalMap( m_pPart );
+ error = !parseNormalMap( ( PMNormalMap* ) child );
+ break;
+ case SLOPE_MAP_TOK:
+ child = new PMSlopeMap( m_pPart );
+ error = !parseSlopeMap( ( PMSlopeMap* ) child );
+ break;
+ case DENSITY_MAP_TOK:
+ child = new PMDensityMap( m_pPart );
+ error = !parseDensityMap( ( PMDensityMap* ) child );
+ break;
+ case INTERIOR_TOK:
+ child = new PMInterior( m_pPart );
+ error = !parseInterior( ( PMInterior* ) child );
+ break;
+ case MEDIA_TOK:
+ child = new PMMedia( m_pPart );
+ error = !parseMedia( ( PMMedia* ) child );
+ break;
+ case DENSITY_TOK:
+ child = new PMDensity( m_pPart );
+ error = !parseDensity( ( PMDensity* ) child );
+ break;
+ case MATERIAL_TOK:
+ child = new PMMaterial( m_pPart );
+ error = !parseMaterial( ( PMMaterial* ) child );
+ break;
+ case SKY_SPHERE_TOK:
+ child = new PMSkySphere( m_pPart );
+ error = !parseSkySphere( ( PMSkySphere* ) child );
+ break;
+ case RAINBOW_TOK:
+ child = new PMRainbow( m_pPart );
+ error = !parseRainbow( ( PMRainbow* ) child );
+ break;
+ case FOG_TOK:
+ child = new PMFog( m_pPart );
+ error = !parseFog( ( PMFog* ) child );
+ break;
+ // misc
+ case LIGHT_SOURCE_TOK:
+ child = new PMLight( m_pPart );
+ error = !parseLight( ( PMLight* ) child );
+ break;
+ case ISOSURFACE_TOK:
+ child = new PMIsoSurface( m_pPart );
+ error = !parseIsoSurface( ( PMIsoSurface* ) child );
+ break;
+ case PHOTONS_TOK:
+ child = new PMPhotons( m_pPart );
+ error = !parsePhotons( ( PMPhotons* ) child );
+ break;
+ case LIGHT_GROUP_TOK:
+ child = new PMLightGroup( m_pPart );
+ error = !parseLightGroup( ( PMLightGroup* ) child );
+ break;
+ case INTERIOR_TEXTURE_TOK:
+ child = new PMInteriorTexture( m_pPart );
+ error = !parseInteriorTexture( ( PMInteriorTexture* ) child );
+ break;
+ case SPHERE_SWEEP_TOK:
+ child = new PMSphereSweep( m_pPart );
+ error = !parseSphereSweep( ( PMSphereSweep* ) child );
+ break;
+ case MESH_TOK:
+ child = new PMMesh( m_pPart );
+ error = !parseMesh( ( PMMesh* ) child );
+ break;
+ }
+
+ if( child )
+ {
+ if( !insertChild( child, decl ) )
+ {
+ delete child;
+ child = 0;
+ }
+ }
+ return !error;
+}
+
+bool PMPovrayParser::parseObject( PMCompositeObject* parent )
+{
+ PMObject* child;
+ bool error = false;
+ if( !parseToken( OBJECT_TOK, "object" ) )
+ return false;
+
+ if( parseToken( '{' ) )
+ {
+ switch( m_token )
+ {
+ case ID_TOK:
+ child = new PMObjectLink( m_pPart );
+ error = !parseObjectLink( ( PMObjectLink* ) child );
+ if( !insertChild( child, parent ) )
+ delete child;
+ break;
+ default:
+ {
+ PMObject* lastChild = 0;
+ if( parent )
+ lastChild = parent->lastChild( );
+ else
+ lastChild = m_pResultList->last( );
+
+ error = !parseChildObjects( parent, 1 );
+ if( !error )
+ {
+ PMObject* newLast = 0;
+ if( parent )
+ newLast = parent->lastChild( );
+ else
+ newLast = m_pResultList->last( );
+
+ if( newLast && ( newLast != lastChild ) &&
+ newLast->isA( "CompositeObject" ) )
+ {
+ // one child was parsed
+ // append all following objects
+ error = !parseChildObjects( ( PMCompositeObject* ) newLast );
+ }
+ else
+ {
+ printError( i18n( "One graphical object expected" ) );
+ error = true;
+ }
+ }
+ break;
+ }
+ }
+ if( !parseToken( '}' ))
+ error = true;
+ }
+ else
+ error = true;
+ return !error;
+}
+
+bool PMPovrayParser::parseObjectLink( PMObjectLink* link )
+{
+ int oldConsumed;
+
+ if( m_token != ID_TOK )
+ {
+ printExpected( "identifier", m_pScanner->sValue( ) );
+ return false;
+ }
+
+ QString id( m_pScanner->sValue( ) );
+ PMDeclare* decl = checkLink( id );
+ if( decl )
+ {
+ if( !link->setLinkedObject( decl ) )
+ printError( i18n( "Wrong declare type" ) );
+ }
+ nextToken( );
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( link );
+ parseObjectModifiers( link );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ return true;
+}
+
+bool PMPovrayParser::parseIsoSurface( PMIsoSurface* iso )
+{
+ PMVector vector;
+ double f;
+ int i;
+ int oldConsumed;
+
+ if( !parseToken( ISOSURFACE_TOK, "isosurface" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( iso );
+ parseObjectModifiers( iso );
+
+ switch( m_token )
+ {
+ case FUNCTION_TOK:
+ nextToken( );
+ if( m_token != '{' )
+ {
+ printExpected( '{', m_pScanner->sValue( ) );
+ return false;
+ }
+
+ m_pScanner->scanFunction( );
+ nextToken( );
+ if( m_token != FUNCTION_TOK )
+ return false;
+ iso->setFunction( QString( m_pScanner->sValue( ) ).simplifyWhiteSpace( ) );
+
+ nextToken( );
+ parseToken( '}' );
+
+ break;
+ case CONTAINED_BY_TOK:
+ nextToken( );
+
+ if( !parseToken( '{' ) )
+ return false;
+
+ if( m_token == BOX_TOK )
+ {
+ iso->setContainedBy( PMIsoSurface::Box );
+ nextToken( );
+ parseToken( '{' );
+ if( parseVector( vector ) )
+ iso->setCorner1( vector );
+ parseToken( ',' );
+ if( parseVector( vector ) )
+ iso->setCorner2( vector );
+ if( !parseToken( '}' ) )
+ return false;
+ }
+ else if( m_token == SPHERE_TOK )
+ {
+ iso->setContainedBy( PMIsoSurface::Sphere );
+ nextToken( );
+ parseToken( '{' );
+ if( parseVector( vector ) )
+ iso->setCenter( vector );
+ parseToken( ',' );
+ if( parseFloat( f ) )
+ iso->setRadius( f );
+ if( !parseToken( '}' ) )
+ return false;
+ }
+ else
+ {
+ printUnexpected( m_pScanner->sValue( ) );
+ return false;
+ }
+
+ if( !parseToken( '}' ) )
+ return false;
+ break;
+ case THRESHOLD_TOK:
+ nextToken( );
+ if( parseFloat( f ) )
+ iso->setThreshold( f );
+ break;
+ case ACCURACY_TOK:
+ nextToken( );
+ if( parseFloat( f ) )
+ iso->setAccuracy( f );
+ break;
+ case MAX_GRADIENT_TOK:
+ nextToken( );
+ if( parseFloat( f ) )
+ iso->setMaxGradient( f );
+ break;
+ case EVALUATE_TOK:
+ nextToken( );
+ iso->setEvaluate( true );
+ if( parseFloat( f ) )
+ {
+ iso->setEvaluateValue( 0, f );
+ if( parseToken( ',' ) && parseFloat( f ) )
+ {
+ iso->setEvaluateValue( 1, f );
+ if( parseToken( ',' ) && parseFloat( f ) )
+ iso->setEvaluateValue( 2, f );
+ }
+ }
+ break;
+ case OPEN_TOK:
+ nextToken( );
+ iso->setOpen( true );
+ break;
+ case MAX_TRACE_TOK:
+ nextToken( );
+ if( parseInt( i ) )
+ iso->setMaxTrace( i );
+ break;
+ case ALL_INTERSECTIONS_TOK:
+ nextToken( );
+ iso->setAllIntersections( true );
+ break;
+ default:
+ break;
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseRadiosity( PMRadiosity* rad )
+{
+ double f;
+ int i;
+ int oldConsumed;
+
+
+ if( !parseToken( RADIOSITY_TOK, "radiosity" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ switch( m_token )
+ {
+ case ADC_BAILOUT_TOK:
+ nextToken( );
+ if( parseFloat( f ) )
+ rad->setAdcBailout( f );
+ break;
+ case ALWAYS_SAMPLE_TOK:
+ nextToken( );
+ rad->setAlwaysSample( parseBool( ) );
+ break;
+ case BRIGHTNESS_TOK:
+ nextToken( );
+ if( parseFloat( f ) )
+ rad->setBrightness( f );
+ break;
+ case COUNT_TOK:
+ nextToken( );
+ if( parseInt( i ) )
+ rad->setCount( i );
+ break;
+ case ERROR_BOUND_TOK:
+ nextToken( );
+ if( parseFloat( f ) )
+ rad->setErrorBound( f );
+ break;
+ case GRAY_THRESHOLD_TOK:
+ nextToken( );
+ if( parseFloat( f ) )
+ rad->setGrayThreshold( f );
+ break;
+ case LOW_ERROR_FACTOR_TOK:
+ nextToken( );
+ if( parseFloat( f ) )
+ rad->setLowErrorFactor( f );
+ break;
+ case MAX_SAMPLE_TOK:
+ nextToken( );
+ if ( parseFloat( f ) )
+ rad->setMaxSample( f );
+ break;
+ case MEDIA_TOK:
+ nextToken( );
+ rad->setMedia( parseBool( ) );
+ break;
+ case MINIMUM_REUSE_TOK:
+ nextToken( );
+ if( parseFloat( f ) )
+ rad->setMinimumReuse( f );
+ break;
+ case NEAREST_COUNT_TOK:
+ nextToken( );
+ if( parseInt( i ) )
+ rad->setNearestCount( i );
+ break;
+ case NORMAL_TOK:
+ nextToken( );
+ rad->setNormal( parseBool( ) );
+ break;
+ case PRETRACE_START_TOK:
+ nextToken( );
+ if( parseFloat( f ) )
+ rad->setPretraceStart( f );
+ break;
+ case PRETRACE_END_TOK:
+ nextToken( );
+ if( parseFloat( f ) )
+ rad->setPretraceEnd( f );
+ break;
+ case RECURSION_LIMIT_TOK:
+ nextToken( );
+ if( parseInt( i) )
+ rad->setRecursionLimit( i );
+ break;
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseGlobalPhotons( PMGlobalPhotons* gp )
+{
+ double f;
+ int i;
+ int oldConsumed;
+
+
+ if( !parseToken( PHOTONS_TOK, "photons" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ switch( m_token )
+ {
+ case SPACING_TOK:
+ gp->setNumberType( PMGlobalPhotons::Spacing );
+ nextToken( );
+ if ( parseFloat( f ) )
+ gp->setSpacing( f );
+ break;
+ case COUNT_TOK:
+ gp->setNumberType( PMGlobalPhotons::Count );
+ nextToken( );
+ if ( parseInt( i ) )
+ gp->setCount( i );
+ break;
+ case GATHER_TOK:
+ nextToken( );
+ if ( parseInt( i ) )
+ {
+ gp->setGatherMin( i );
+ if ( parseToken( ',' ) && parseInt( i ) )
+ gp->setGatherMax( i );
+ }
+ break;
+ case MEDIA_TOK:
+ nextToken( );
+ if ( parseInt( i ) )
+ {
+ gp->setMediaMaxSteps( i );
+ if ( parseToken( ',' ) && parseFloat( f ) )
+ gp->setMediaFactor( f );
+ }
+ case JITTER_TOK:
+ nextToken( );
+ if ( parseFloat( f ) )
+ gp->setJitter( f );
+ break;
+ case MAX_TRACE_LEVEL_TOK:
+ nextToken( );
+ gp->setMaxTraceLevelGlobal( false );
+ if ( parseInt( i ) )
+ gp->setMaxTraceLevel( i );
+ break;
+ case ADC_BAILOUT_TOK:
+ nextToken( );
+ gp->setAdcBailoutGlobal( false );
+ if ( parseFloat( f ) )
+ gp->setAdcBailout( f );
+ break;
+ case AUTOSTOP_TOK:
+ nextToken( );
+ if ( parseFloat( f ) )
+ gp->setAutostop( f );
+ break;
+ case EXPAND_THRESHOLDS_TOK:
+ nextToken( );
+ if ( parseFloat( f ) )
+ {
+ gp->setExpandIncrease( f );
+ if ( parseToken( ',' ) && parseInt( i ) )
+ gp->setExpandMin( i );
+ }
+ break;
+ case RADIUS_TOK:
+ nextToken( );
+ if ( parseFloat( f ) )
+ {
+ gp->setRadiusGather( f );
+ if ( parseToken( ',' ) && parseFloat( f ) )
+ {
+ gp->setRadiusGatherMulti( f );
+ if ( parseToken( ',' ) && parseFloat( f ) )
+ {
+ gp->setRadiusMedia( f );
+ if ( parseToken( ',' ) && parseFloat( f ) )
+ gp->setRadiusMediaMulti( f );
+ }
+ }
+ }
+ break;
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parsePhotons( PMPhotons* p )
+{
+ double f;
+ int oldConsumed;
+
+ if( !parseToken( PHOTONS_TOK, "photons" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ p->setTarget( false );
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ switch( m_token )
+ {
+ case TARGET_TOK:
+ nextToken( );
+ p->setTarget( true );
+ if ( parseFloat( f ) )
+ p->setSpacingMulti( f );
+ break;
+ case REFRACTION_TOK:
+ nextToken( );
+ p->setRefraction( parseBool( ) );
+ break;
+ case REFLECTION_TOK:
+ nextToken( );
+ p->setReflection( parseBool( ) );
+ break;
+ case COLLECT_TOK:
+ nextToken( );
+ p->setCollect( parseBool( ) );
+ break;
+ case PASS_THROUGH_TOK:
+ nextToken( );
+ p->setPassThrough( parseBool( ) );
+ break;
+ case AREA_LIGHT_TOK:
+ nextToken( );
+ p->setAreaLight( parseBool( ) );
+ break;
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseLightGroup( PMLightGroup* lg )
+{
+ int oldConsumed;
+
+ if ( !parseToken( LIGHT_GROUP_TOK, "light_group" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ if ( m_token == GLOBAL_LIGHTS_TOK )
+ {
+ nextToken( );
+ lg->setGlobalLights( parseBool( ) );
+ }
+ else
+ {
+ parseChildObjects( lg );
+ parseObjectModifiers( lg );
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseInteriorTexture( PMInteriorTexture* it )
+{
+ int oldConsumed;
+
+ if( !parseToken( INTERIOR_TEXTURE_TOK, "interior_texture" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ parseChildObjects( it );
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseSphereSweep( PMSphereSweep* ss )
+{
+ int oldConsumed, numspheres;
+ QValueList<PMVector> points;
+ QValueList<double> radii;
+ PMVector point;
+ double f;
+
+ if( !parseToken( SPHERE_SWEEP_TOK, "sphere_sweep" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ nextToken( );
+ switch ( m_token )
+ {
+ case LINEAR_SPLINE_TOK:
+ ss->setSplineType( PMSphereSweep::LinearSpline );
+ break;
+ case B_SPLINE_TOK:
+ ss->setSplineType( PMSphereSweep::BSpline );
+ break;
+ case CUBIC_SPLINE_TOK:
+ ss->setSplineType( PMSphereSweep::CubicSpline );
+ break;
+ default:
+ return false;
+ }
+
+ if ( !parseInt( numspheres ) )
+ return false;
+
+ for ( int i = 0; i < numspheres; ++i )
+ {
+ if ( !parseVector( point ) )
+ return false;
+ points.append( point );
+ if ( !parseToken( ',' ) )
+ return false;
+ if ( !parseFloat( f ) )
+ return false;
+ radii.append( f );
+ }
+
+ ss->setPoints( points );
+ ss->setRadii( radii );
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ if ( m_token == TOLERANCE_TOK )
+ {
+ nextToken( );
+ if ( !parseFloat( f ) )
+ return false;
+ ss->setTolerance( f );
+ }
+ else
+ {
+ parseObjectModifiers( ss );
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
+
+bool PMPovrayParser::parseMesh( PMMesh* m )
+{
+ int oldConsumed;
+ PMVector vector;
+
+ if( !parseToken( MESH_TOK, "mesh" ) )
+ return false;
+ if( !parseToken( '{' ) )
+ return false;
+
+ do
+ {
+ oldConsumed = m_consumedTokens;
+ if ( m_token == HIERARCHY_TOK )
+ {
+ nextToken( );
+ m->setHierarchy( parseBool( ) );
+ }
+ else if ( m_token == INSIDE_VECTOR_TOK )
+ {
+ nextToken( );
+ if ( !parseVector( vector ) )
+ return false;
+ m->enableInsideVector( true );
+ m->setInsideVector( vector );
+ }
+ else
+ {
+ parseChildObjects( m );
+ parseObjectModifiers( m );
+ }
+ }
+ while( oldConsumed != m_consumedTokens );
+
+ if( !parseToken( '}' ) )
+ return false;
+
+ return true;
+}
diff --git a/kpovmodeler/pmpovrayparser.h b/kpovmodeler/pmpovrayparser.h
new file mode 100644
index 00000000..b41beaf9
--- /dev/null
+++ b/kpovmodeler/pmpovrayparser.h
@@ -0,0 +1,534 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPOVRAYPARSER_H
+#define PMPOVRAYPARSER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmparser.h"
+#include "pmcomment.h"
+#include "pmvector.h"
+
+class PMCompositeObject;
+class PMGraphicalObject;
+class PMBox;
+class PMSphere;
+class PMCylinder;
+class PMCone;
+class PMTorus;
+class PMPlane;
+class PMPolynom;
+class PMDisc;
+class PMBlob;
+class PMBlobCylinder;
+class PMBlobSphere;
+class PMBicubicPatch;
+class PMTriangle;
+class PMCSG;
+class PMHeightField;
+class PMText;
+class PMJuliaFractal;
+class PMLathe;
+class PMPrism;
+class PMSurfaceOfRevolution;
+class PMSuperquadricEllipsoid;
+class PMScale;
+class PMRotate;
+class PMTranslate;
+class PMBoundedBy;
+class PMClippedBy;
+class PMPovrayMatrix;
+class PMCamera;
+class PMLight;
+class PMLooksLike;
+class PMProjectedThrough;
+class PMColor;
+class PMTexture;
+class PMPattern;
+class PMBlendMapModifiers;
+class PMWarp;
+class PMPigment;
+class PMNormal;
+class PMTextureMap;
+class PMPigmentMap;
+class PMColorMap;
+class PMNormalMap;
+class PMBumpMap;
+class PMMaterialMap;
+class PMSlopeMap;
+class PMDensityMap;
+class PMListPattern;
+class PMTextureList;
+class PMPigmentList;
+class PMColorList;
+class PMNormalList;
+class PMDensityList;
+class PMImageMap;
+class PMSlope;
+class PMFinish;
+class PMInterior;
+class PMMedia;
+class PMDensity;
+class PMMaterial;
+class PMSkySphere;
+class PMRainbow;
+class PMFog;
+class PMDeclare;
+class PMObjectLink;
+class PMGlobalSettings;
+
+class PMIsoSurface;
+class PMRadiosity;
+class PMGlobalPhotons;
+class PMPhotons;
+class PMLightGroup;
+class PMInteriorTexture;
+class PMSphereSweep;
+class PMMesh;
+
+/**
+ * Parser that parses povray code.
+ *
+ * All parse functions return false or 0 if an error occurred and the parse
+ * function couldn't recover.
+ */
+class PMPovrayParser : public PMParser
+{
+public:
+ /**
+ * Parser that parses the device
+ */
+ PMPovrayParser( PMPart* part, QIODevice* device );
+ /**
+ * Parser that parses the byte array
+ */
+ PMPovrayParser( PMPart* part, const QByteArray& array );
+ /**
+ * Deletes the parser
+ */
+ virtual ~PMPovrayParser( );
+
+protected:
+ /**
+ * Top level parse function
+ */
+ virtual void topParse( );
+
+private:
+ /**
+ * Initializes the parser
+ */
+ void init( );
+
+ /**
+ * Sets m_token to the next token
+ */
+ void nextToken( );
+
+ /**
+ * Returns true if the current token is ON_TOK, TRUE_TOK or YES_TOK
+ */
+ bool isTrue( ) const;
+ /**
+ * Returns true if the current token is OFF_TOK, FALSE_TOK or NO_TOK
+ */
+ bool isFalse( ) const;
+ /**
+ * Returns true if the next token is no bool value or one of the
+ * ON, TRUE or YES tokens
+ */
+ bool parseBool( );
+
+
+ /**
+ * Looks for child objects, parses them and appends them to the parent
+ * object. If parent is 0, all objects are appended to the result list.
+ *
+ * If max is > 0, then the maximum number of parsed objects is max.
+ *
+ * Returns true if there where no objects or parsing was successful.
+ */
+ bool parseChildObjects( PMCompositeObject* parent, int max = -1 );
+
+
+ /**
+ * Parses the token t.
+ *
+ * If the next token is not t, it appends an error to the messages
+ * and returns false.
+ *
+ * If t is not a single character token, set tokenName to the token
+ * name (like "box", "sphere" ...)
+ */
+ bool parseToken( int t, const QString& tokenName = QString::null );
+
+ /**
+ * Parses an item of a vector, float or color expression
+ */
+ bool parseNumericItem( PMValue& v, bool checkForBool = false );
+ /**
+ * Parse function for a vector literal <x, y, z, ...>
+ */
+ bool parseVectorLiteral( PMVector& v );
+ /**
+ * Parses a vector, float or color expression
+ */
+ bool parseNumericExpression( PMValue& v, bool checkForBool = false );
+
+ /**
+ * parses a vector and float expression and returns a vector
+ * of size s
+ */
+ bool parseVector( PMVector& v, unsigned int s=3 );
+ /**
+ * parses a vector and float expression and returns the
+ * float value or the first coordinate of the vector
+ */
+ bool parseFloat( double& d, bool suppressError = false );
+ /**
+ * parses a float or int value and rounds if necessary
+ */
+ bool parseInt( int& d );
+ /**
+ * parses a color expression
+ */
+ bool parseColor( PMColor& c );
+
+ /**
+ * Parse function for object modifiers
+ */
+ bool parseObjectModifiers( PMGraphicalObject* obj );
+
+ /**
+ * Parse function for cvs objects
+ */
+ bool parseCSG( PMCSG* csg );
+
+ /**
+ * Parse function for box objects
+ */
+ bool parseBox( PMBox* box );
+ /**
+ * Parse function for box objects
+ */
+ bool parseSphere( PMSphere* sphere );
+ /**
+ * Parse function for cylinder objects
+ */
+ bool parseCylinder( PMCylinder* pNewCyl );
+ /**
+ * Parse function for cone objects
+ */
+ bool parseCone( PMCone* pNewCone );
+ /**
+ * Parse function for torus objects
+ */
+ bool parseTorus( PMTorus* pNewTorus );
+
+ /**
+ * Parse function for blob objects
+ */
+ bool parseBlob( PMBlob* pNewBlob );
+ /**
+ * Parse function for blob sphere components
+ */
+ bool parseBlobSphere( PMBlobSphere* pNewBlobSphere );
+ /**
+ * Parse function for blob cylinder components
+ */
+ bool parseBlobCylinder( PMBlobCylinder* pNewBlobCylinder );
+ /**
+ * Parse function for old blob components
+ */
+ bool parseBlobComponent( PMBlobSphere* pNewBlobSphere );
+
+ /**
+ * Parse function for height fields
+ */
+ bool parseHeightField( PMHeightField* pNewHeightField );
+ /**
+ * Parse function for text objects
+ */
+ bool parseText( PMText* pNewText );
+ /**
+ * Parse function for julia fractals
+ */
+ bool parseJuliaFractal( PMJuliaFractal* pNewFractal );
+
+ /**
+ * Parse function for plane objects
+ */
+ bool parsePlane( PMPlane* pNewPlane );
+ /**
+ * Parse function for quadric, cubic, quartic and poly
+ */
+ bool parsePolynom( PMPolynom* pNewPoly );
+ /**
+ * Parse function for bicubic patch objects
+ */
+ bool parseBicubicPatch( PMBicubicPatch* pNewPatch );
+ /**
+ * Parse function for disks
+ */
+ bool parseDisc( PMDisc* pNewDisc );
+ /**
+ * Parse function for triangles
+ */
+ bool parseTriangle( PMTriangle* pNewTriangle );
+
+ /**
+ * Parse function for lathes
+ */
+ bool parseLathe( PMLathe* pNewLathe );
+ /**
+ * Parse function for prisms
+ */
+ bool parsePrism( PMPrism* pNewPrism );
+ /**
+ * Parse function for surface of revolutions
+ */
+ bool parseSor( PMSurfaceOfRevolution* pNewSor );
+ /**
+ * Parse function for superquadric ellipsoid
+ */
+ bool parseSqe( PMSuperquadricEllipsoid* pNewSqe );
+
+ /**
+ * Parse function for scale commands
+ */
+ bool parseScale( PMScale* scale );
+ /**
+ * Parse function for rotate commands
+ */
+ bool parseRotate( PMRotate* rotate );
+ /**
+ * Parse function for translate commands
+ */
+ bool parseTranslate( PMTranslate* translate );
+ /**
+ * Parse function for matrix commands
+ */
+ bool parseMatrix( PMPovrayMatrix* matrix );
+
+ /**
+ * Parse function for bounded_by statements
+ */
+ bool parseBoundedBy( PMBoundedBy* bound );
+ /**
+ * Parse function for clipped_by statements
+ */
+ bool parseClippedBy( PMClippedBy* clipped );
+
+ /**
+ * Parse function for camera objects
+ */
+ bool parseCamera( PMCamera* camera );
+
+ /**
+ * Parse function for light objects
+ */
+ bool parseLight( PMLight* light );
+ /**
+ * Parse function for looks_like statement
+ */
+ bool parseLooksLike( PMLooksLike* ll );
+ /**
+ * Parse function for projected_through statement
+ */
+ bool parseProjectedThrough( PMProjectedThrough* ll );
+
+ /**
+ * Parse function for texture objects. If parseOuter is false, the parser
+ * won't search for the texture{} wrapper. This is useful inside a texture
+ * map.
+ */
+ bool parseTexture( PMTexture* pigment, bool parseOuter = true );
+ /**
+ * Parse function for pattern objects
+ */
+ bool parsePattern( PMPattern* pattern, bool normal = false );
+ /**
+ * Parse function for blend map modifier objects
+ */
+ bool parseBlendMapModifiers( PMBlendMapModifiers* blend );
+ /**
+ * Parse function for warp objects
+ */
+ bool parseWarp( PMWarp* pattern );
+ /**
+ * Parse function for pigment objects
+ */
+ bool parsePigment( PMPigment* pigment, bool parseOuter = true );
+ /**
+ * Parse function for normal objects
+ */
+ bool parseNormal( PMNormal* normal );
+ /**
+ * Parse function for texture map objects
+ */
+ bool parseTextureMap( PMTextureMap* textureMap );
+ /**
+ * Parse function for pigment map objects
+ */
+ bool parsePigmentMap( PMPigmentMap* pigmentMap );
+ /**
+ * Parse function for color map objects
+ */
+ bool parseColorMap( PMColorMap* colorMap );
+ /**
+ * Parse function for normal map objects
+ */
+ bool parseNormalMap( PMNormalMap* normalMap );
+ /**
+ * Parse function for bump map objects
+ */
+ bool parseBumpMap( PMBumpMap* bumpMap );
+ /**
+ * Parse function for material map objects
+ */
+ bool parseMaterialMap( PMMaterialMap* materialMap );
+ /**
+ * Parse function for slope map objects
+ */
+ bool parseSlopeMap( PMSlopeMap* slopeMap );
+ /**
+ * Parse function for density map objects
+ */
+ bool parseDensityMap( PMDensityMap* densityMap );
+ /**
+ * Parse function for image map objects
+ */
+ bool parseImageMap( PMImageMap* imageMap );
+ /**
+ * Parse function for slope objects
+ */
+ bool parseSlope( PMSlope* slope );
+ /**
+ * Parse function for texture list objects
+ */
+ bool parseTextureList( PMTextureList* textureList, int expectedItems );
+ /**
+ * Parse function for pigment list objects
+ */
+ bool parsePigmentList( PMPigmentList* pigmentList, int expectedItems );
+ /**
+ * Parse function for color list objects
+ */
+ bool parseColorList( PMColorList* colorList, int expectedItems );
+ /**
+ * Parse function for normal list objects
+ */
+ bool parseNormalList( PMNormalList* normalList, int expectedItems );
+ /**
+ * Parse function for density list objects
+ */
+ bool parseDensityList( PMDensityList* densityList, int expectedItems );
+ /**
+ * Parse function for finish objects
+ */
+ bool parseFinish( PMFinish* finish );
+ /**
+ * Parse function for interior objects
+ */
+ bool parseInterior( PMInterior* interior );
+ /**
+ * Parse function for media objects
+ */
+ bool parseMedia( PMMedia* media );
+ /**
+ * Parse function for density objects
+ */
+ bool parseDensity( PMDensity* density );
+ /**
+ * Parse function for material objects
+ */
+ bool parseMaterial( PMMaterial* material );
+
+ /**
+ * Parse function for sky sphere objects
+ */
+ bool parseSkySphere( PMSkySphere* sky );
+ /**
+ * Parse function for rainbow objects
+ */
+ bool parseRainbow( PMRainbow* rainbow );
+ /**
+ * Parse function for fog objects
+ */
+ bool parseFog( PMFog* fog );
+
+ /**
+ * Parse function for global settings
+ */
+ bool parseGlobalSettings( PMGlobalSettings* decl );
+ /**
+ * Parse function for declares
+ */
+ bool parseDeclare( PMDeclare* decl );
+ /**
+ * Parse function for object links
+ */
+ bool parseObjectLink( PMObjectLink* link );
+ /**
+ * Parse function for object keywords
+ */
+ bool parseObject( PMCompositeObject* parent );
+
+ // POV-Ray 3.5 objects
+ bool parseIsoSurface( PMIsoSurface* iso );
+ bool parseRadiosity( PMRadiosity* rad );
+ bool parseGlobalPhotons( PMGlobalPhotons* gp );
+ bool parsePhotons( PMPhotons* p );
+ bool parseLightGroup( PMLightGroup* lg );
+ bool parseInteriorTexture( PMInteriorTexture* it );
+ bool parseSphereSweep( PMSphereSweep * ss );
+ bool parseMesh( PMMesh* m );
+
+ /**
+ * The used scanner
+ */
+ PMScanner* m_pScanner;
+ /**
+ * The last scanned token
+ */
+ int m_token;
+
+ /**
+ * Number of consumed tokens.
+ */
+ int m_consumedTokens;
+
+ /**
+ * All comments are skipped during parsing and stored here
+ */
+ QPtrList<PMComment> m_skippedComments;
+ /**
+ * The last skipped comment text with special kpovmodeler tags*/
+ QString m_lastPMComment;
+ /**
+ * true if m_lastPMComment is empty
+ */
+ bool m_bLastPMCommentEmpty;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmpovrayrenderwidget.cpp b/kpovmodeler/pmpovrayrenderwidget.cpp
new file mode 100644
index 00000000..3cd44f20
--- /dev/null
+++ b/kpovmodeler/pmpovrayrenderwidget.cpp
@@ -0,0 +1,437 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmpovrayrenderwidget.h"
+#include "pmdefaults.h"
+#include "pmdebug.h"
+#include "pmdragwidget.h"
+
+#include <kprocess.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kurl.h>
+#include <ktempfile.h>
+#include <qcolor.h>
+#include <qpainter.h>
+#include <qtextstream.h>
+#include <qdragobject.h>
+
+#ifdef KDE_NO_COMPAT
+#undef KDE_NO_COMPAT
+#endif
+
+#include <kapplication.h>
+
+QString PMPovrayRenderWidget::s_povrayCommand = c_defaultPovrayCommand;
+QStringList PMPovrayRenderWidget::s_libraryPaths;
+
+PMPovrayRenderWidget::PMPovrayRenderWidget( QWidget* parent, const char* name )
+ : PMDragWidget( parent, name )
+{
+ m_pProcess = 0;
+ m_bSuspended = false;
+ m_rcvHeader = false;
+ m_skipBytes = 0;
+ m_bPixmapUpToDate = false;
+ m_pTempFile = 0;
+
+ setBackgroundColor( QColor( 0, 0, 0 ) );
+}
+
+PMPovrayRenderWidget::~PMPovrayRenderWidget( )
+{
+ cleanup( );
+}
+
+bool PMPovrayRenderWidget::render( const QByteArray& scene,
+ const PMRenderMode& m,
+ const KURL& documentURL )
+{
+ cleanup( );
+
+ m_povrayOutput = "";
+ m_renderMode = m;
+
+ if( !scene.data( ) )
+ {
+ KMessageBox::sorry( this, i18n( "Can't render an empty scene.\n" ) );
+ return false;
+ }
+
+ // output to tmp file
+ m_pTempFile = new KTempFile( QString::null, ".pov" );
+ QDataStream* dstr = m_pTempFile->dataStream( );
+
+ if( ( m_pTempFile->status( ) != 0 ) || !dstr )
+ {
+ KMessageBox::sorry( this, i18n( "Couldn't write the scene to a temp file.\n" ) );
+ return false;
+ }
+
+ dstr->writeRawBytes( scene.data( ), scene.size( ) );
+ m_pTempFile->close( );
+
+ m_pProcess = new KProcess( );
+ connect( m_pProcess, SIGNAL( receivedStdout( KProcess*, char*, int ) ),
+ SLOT( slotPovrayImage( KProcess*, char*, int ) ) );
+ connect( m_pProcess, SIGNAL( receivedStderr( KProcess*, char*, int ) ),
+ SLOT( slotPovrayMessage( KProcess*, char*, int ) ) );
+ connect( m_pProcess, SIGNAL( processExited( KProcess* ) ),
+ SLOT( slotRenderingFinished( KProcess* ) ) );
+
+ *m_pProcess << s_povrayCommand;
+
+ QStringList::ConstIterator it;
+ QStringList args = m_renderMode.commandLineSwitches( );
+ for( it = args.begin( ); it != args.end( ); ++it )
+ *m_pProcess << *it;
+
+ for( it = s_libraryPaths.begin( ); it != s_libraryPaths.end( ); ++it )
+ {
+ QString path = *it;
+ if( path != QString( "/" ) )
+ if( path.right( 1 ) == QString( "/" ) )
+ path.truncate( path.length( ) - 1 );
+ *m_pProcess << ( QString( "+L" ) + path );
+ }
+ *m_pProcess << QString( "+I" ) + m_pTempFile->name( ) << "+O-" << "+FT"
+ << "+K0.0" << "+KFI1" << "+KFF1" << "+KI0.0" << "+KF0.0"
+ << "+SF1" << "+EF1" << "-KC" << "-D";
+
+#if ( ( KDE_VERSION_MAJOR == 2 ) && ( KDE_VERSION_MINOR >= 9 ) ) || ( KDE_VERSION_MAJOR == 3 )
+ if( !documentURL.isEmpty( ) && documentURL.isLocalFile( ) )
+ m_pProcess->setWorkingDirectory( documentURL.directory( ) );
+#endif
+
+ m_rcvHeader = true;
+ m_rcvHeaderBytes = 0;
+ m_rcvPixels = 0;
+ m_progress = 0;
+ m_numRestBytes = 0;
+ m_line = 0;
+ m_column = 0;
+ m_skipBytes = 0;
+
+ int width = m_renderMode.width( );
+ int height = m_renderMode.height( );
+
+ m_image.create( width, height, 32 );
+ m_image.setAlphaBuffer( m_renderMode.alpha( ) );
+ m_image.fill( qRgb( 0, 0, 0 ) );
+ m_bPixmapUpToDate = false;
+ repaint( );
+
+ if( !m_pProcess->start( KProcess::NotifyOnExit, KProcess::AllOutput ) )
+ {
+ KMessageBox::error( this, i18n( "Couldn't call povray.\n"
+ "Please check your installation "
+ "or set another povray command." ) );
+ delete m_pProcess;
+ m_pProcess = 0;
+ return false;
+ }
+
+ m_bSuspended = false;
+ return true;
+}
+
+void PMPovrayRenderWidget::killRendering( )
+{
+ if( m_pProcess )
+ {
+ if( m_bSuspended )
+ m_pProcess->kill( SIGCONT );
+ m_bSuspended = false;
+ m_pProcess->kill( );
+ }
+}
+
+void PMPovrayRenderWidget::suspendRendering( )
+{
+ if( m_pProcess )
+ {
+ m_bSuspended = true;
+ m_pProcess->kill( SIGSTOP );
+ }
+}
+
+void PMPovrayRenderWidget::resumeRendering( )
+{
+ if( m_pProcess )
+ {
+ m_pProcess->kill( SIGCONT );
+ m_bSuspended = false;
+ }
+}
+
+void PMPovrayRenderWidget::slotPovrayMessage( KProcess*,
+ char* buffer, int buflen )
+{
+ QString str;
+ str.setLatin1( buffer, buflen );
+ m_povrayOutput += str;
+ emit povrayMessage( str );
+}
+
+void PMPovrayRenderWidget::slotPovrayImage( KProcess*, char* buffer, int buflen )
+{
+ int index = 0;
+ int i;
+ int oldLine = m_line;
+
+ if( m_rcvHeader )
+ {
+ // receive targa header
+ while( ( m_rcvHeaderBytes < 18 ) && ( index < buflen ) )
+ {
+ m_header[m_rcvHeaderBytes] = ( unsigned char ) buffer[index];
+ m_rcvHeaderBytes++;
+ index++;
+ }
+
+ if( m_rcvHeaderBytes == 18 )
+ {
+ // complete targa header received
+ m_rcvHeader = false;
+ m_skipBytes = m_header[0]; // id length
+ m_bytespp = m_header[16] / 8;
+ }
+ }
+
+ if( m_skipBytes > 0 )
+ {
+ int skip = buflen - index;
+ if( skip > m_skipBytes )
+ skip = m_skipBytes;
+ m_skipBytes -= skip;
+ index += skip;
+ }
+
+ if( ( m_numRestBytes > 0 ) && ( index < buflen ) )
+ {
+ while( ( m_numRestBytes < m_bytespp ) && ( index < buflen ) )
+ {
+ m_restBytes[m_numRestBytes] = ( unsigned char ) buffer[index];
+ index++;
+ m_numRestBytes++;
+ }
+ if( m_numRestBytes == m_bytespp )
+ {
+ m_numRestBytes = 0;
+
+ if( m_bytespp == 4 )
+ setPixel( m_column, m_line,
+ qRgba( m_restBytes[2], m_restBytes[1],
+ m_restBytes[0], m_restBytes[3] ) );
+ else
+ setPixel( m_column, m_line,
+ qRgb( m_restBytes[2], m_restBytes[1], m_restBytes[0] ) );
+
+ m_column++;
+ m_rcvPixels++;
+ if( m_column == m_renderMode.width( ) )
+ {
+ m_column = 0;
+ m_line++;
+ }
+ }
+ }
+
+ if( index < buflen )
+ {
+ int num = ( buflen - index ) / m_bytespp;
+ for( i = 0; i < num; i++ )
+ {
+ if( m_bytespp == 4 )
+ setPixel( m_column, m_line,
+ qRgba( buffer[index+2], buffer[index+1],
+ buffer[index], buffer[index+3] ) );
+ else
+ setPixel( m_column, m_line,
+ qRgb( buffer[index+2], buffer[index+1],
+ buffer[index] ) );
+ index += m_bytespp;
+
+ m_column++;
+ m_rcvPixels++;
+ if( m_column == m_renderMode.width( ) )
+ {
+ m_column = 0;
+ m_line++;
+ }
+ }
+ }
+
+ if( index < buflen )
+ {
+ m_numRestBytes = buflen - index;
+ for( i = 0; i < m_numRestBytes; i++ )
+ {
+ m_restBytes[i] = buffer[index];
+ index++;
+ }
+ }
+
+ if( m_line != oldLine )
+ {
+ QPainter paint( this );
+ int offset = 0;
+ if( m_renderMode.subSection( ) )
+ {
+ double sr = m_renderMode.startRow( );
+ if( sr < 1 )
+ offset = ( int ) ( m_renderMode.height( ) * sr + 0.5 );
+ else
+ offset += ( int ) sr;
+ }
+ paint.drawImage( 0, offset + oldLine,
+ m_image.copy( 0, offset + oldLine, m_image.width( ), offset + m_line - oldLine ) );
+
+ emit lineFinished( m_line - 1 );
+ }
+
+ int oldProgress = m_progress;
+ int numPixels = 0;
+ if( m_renderMode.subSection( ) )
+ {
+ int sr = 0;
+ if( m_renderMode.startRow( ) < 1 )
+ sr = ( int ) ( m_renderMode.height( ) * m_renderMode.startRow( ) + 0.5 );
+ else
+ sr = ( int ) m_renderMode.startRow( );
+ int er = 0;
+ if( m_renderMode.endRow( ) < 1 )
+ er = ( int ) ( m_renderMode.height( ) * m_renderMode.endRow( ) + 0.5 );
+ else
+ er = ( int ) m_renderMode.endRow( );
+
+ numPixels = m_renderMode.width( ) * ( er - sr );
+ }
+ else
+ numPixels = m_renderMode.width( ) * m_renderMode.height( );
+
+ m_progress = m_rcvPixels * 100 / numPixels;
+
+ if( m_progress != oldProgress )
+ emit progress( m_progress );
+ m_bPixmapUpToDate = false;
+}
+
+void PMPovrayRenderWidget::setPixel( int x, int y, uint c )
+{
+ if( m_renderMode.subSection( ) )
+ {
+ double sr = m_renderMode.startRow( );
+ if( sr < 1 )
+ y += ( int ) ( m_renderMode.height( ) * sr + 0.5 );
+ else
+ y += ( int ) sr;
+ }
+
+ if( x >= 0 && x < m_image.width( ) &&
+ y >= 0 && y < m_image.height( ) )
+ m_image.setPixel( x, y, c );
+}
+
+/**
+void PMPovrayRenderWidget::slotWroteStdin( KProcess* )
+{
+ if( m_pProcess )
+ m_pProcess->closeStdin( );
+ m_data.resize( 0 );
+}
+*/
+
+void PMPovrayRenderWidget::slotRenderingFinished( KProcess* )
+{
+ if( m_pProcess->normalExit( ) )
+ emit( finished( m_pProcess->exitStatus( ) ) );
+ else
+ emit( finished( -1000 ) );
+
+ cleanup( );
+}
+
+void PMPovrayRenderWidget::paintEvent( QPaintEvent* ev )
+{
+ if( !m_bPixmapUpToDate )
+ {
+ if( !m_image.isNull( ) )
+ m_pixmap.convertFromImage( m_image );
+ m_bPixmapUpToDate = true;
+ }
+ bitBlt( this, ev->rect( ).left( ), ev->rect( ).top( ),
+ &m_pixmap, ev->rect( ).left( ), ev->rect( ).top( ),
+ ev->rect( ).width( ), ev->rect( ).height( ), CopyROP );
+}
+
+void PMPovrayRenderWidget::cleanup( )
+{
+ if( m_pProcess )
+ delete m_pProcess;
+ m_pProcess = 0;
+ if( m_pTempFile )
+ {
+ m_pTempFile->unlink( );
+ delete m_pTempFile;
+ }
+ m_pTempFile = 0;
+}
+
+QSize PMPovrayRenderWidget::sizeHint( ) const
+{
+ QSize s;
+ if( m_image.isNull( ) )
+ s = QSize( 200, 200 );
+ else
+ s = m_image.size( );
+
+ return s.expandedTo( minimumSize( ) );
+}
+
+void PMPovrayRenderWidget::saveConfig( KConfig* cfg )
+{
+ cfg->setGroup( "Povray" );
+#if ( ( KDE_VERSION_MAJOR == 3 ) && ( KDE_VERSION_MINOR <= 1 ) )
+ cfg->writeEntry( "PovrayCommand", s_povrayCommand );
+ cfg->writeEntry( "LibraryPaths", s_libraryPaths );
+#else
+ cfg->writePathEntry( "PovrayCommand", s_povrayCommand );
+ cfg->writePathEntry( "LibraryPaths", s_libraryPaths );
+#endif
+}
+
+void PMPovrayRenderWidget::restoreConfig( KConfig* cfg )
+{
+ cfg->setGroup( "Povray" );
+#if ( ( KDE_VERSION_MAJOR == 3 ) && ( KDE_VERSION_MINOR <= 1 ) )
+ s_povrayCommand = cfg->readEntry( "PovrayCommand", s_povrayCommand );
+ s_libraryPaths = cfg->readListEntry( "LibraryPaths" );
+#else
+ s_povrayCommand = cfg->readPathEntry( "PovrayCommand", s_povrayCommand );
+ s_libraryPaths = cfg->readPathListEntry( "LibraryPaths" );
+#endif
+}
+
+void PMPovrayRenderWidget::startDrag( )
+{
+ QImageDrag* d = new QImageDrag( m_image, this );
+ d->dragCopy( );
+}
+
+#include "pmpovrayrenderwidget.moc"
diff --git a/kpovmodeler/pmpovrayrenderwidget.h b/kpovmodeler/pmpovrayrenderwidget.h
new file mode 100644
index 00000000..23e30721
--- /dev/null
+++ b/kpovmodeler/pmpovrayrenderwidget.h
@@ -0,0 +1,177 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMPOVRAYRENDERWIDGET_H
+#define PMPOVRAYRENDERWIDGET_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qwidget.h>
+#include <qcstring.h>
+#include <qimage.h>
+#include <qbuffer.h>
+#include <qstringlist.h>
+
+#include "pmrendermode.h"
+#include "pmdragwidget.h"
+
+class KProcess;
+class KConfig;
+class KURL;
+class KTempFile;
+
+/**
+ * Widget that calls povray to render a scene and
+ * displays the output.
+ */
+class PMPovrayRenderWidget : public PMDragWidget
+{
+ Q_OBJECT
+public:
+ /**
+ * Standard constructor
+ */
+ PMPovrayRenderWidget( QWidget* parent = 0, const char* name = 0 );
+ /**
+ * destructor
+ */
+ virtual ~PMPovrayRenderWidget( );
+
+ /**
+ * Starts rendering for the povray code in the byte array with
+ * render mode m.
+ * @see PMRenderMode
+ */
+ bool render( const QByteArray& scene, const PMRenderMode& m,
+ const KURL& documentURL );
+
+ /**
+ * Returns the povray text output
+ */
+ QString povrayOutput( ) const { return m_povrayOutput; }
+ /**
+ * Returns the rendered image
+ */
+ QImage image( ) const { return m_image; }
+
+ static void saveConfig( KConfig* cfg );
+ static void restoreConfig( KConfig* cfg );
+
+ /**
+ * Returns the povray command
+ */
+ static QString povrayCommand( ) { return s_povrayCommand; }
+ /**
+ * Sets the povray command
+ */
+ static void setPovrayCommand( const QString& c ) { s_povrayCommand = c; }
+ /**
+ * Returns the library paths
+ */
+ static QStringList povrayLibraryPaths( ) { return s_libraryPaths; }
+ /**
+ * Sets the library paths
+ */
+ static void setPovrayLibraryPaths( const QStringList& slist )
+ { s_libraryPaths = slist; }
+ virtual QSize sizeHint( ) const;
+
+ virtual void startDrag( );
+signals:
+ /**
+ * Emitted when rendering has finished
+ */
+ void finished( int exitStatus );
+ /**
+ * Provides progress information
+ */
+ void progress( int percent );
+ /**
+ * Provides progress imformation
+ */
+ void lineFinished( int line );
+ /**
+ * The povray output text
+ */
+ void povrayMessage( const QString& msg );
+
+public slots:
+ /**
+ * Kills rendering
+ */
+ void killRendering( );
+ /**
+ * Suspends rendering
+ */
+ void suspendRendering( );
+ /**
+ * Resumes rendering
+ */
+ void resumeRendering( );
+
+protected slots:
+ /**
+ * Receive povray messages
+ */
+ void slotPovrayMessage( KProcess* proc, char* buffer, int buflen );
+ /**
+ * Receive rendered image
+ */
+ void slotPovrayImage( KProcess* proc, char* buffer, int buflen );
+ /**
+ * Called when output has been written to the povray process
+ */
+ //void slotWroteStdin( KProcess* proc );
+ /**
+ * Called when the process has finished
+ */
+ void slotRenderingFinished( KProcess* proc );
+
+protected:
+ virtual void paintEvent( QPaintEvent* );
+
+private:
+ void setPixel( int x, int y, uint c );
+ void cleanup( );
+
+ KProcess* m_pProcess;
+ bool m_bSuspended;
+ PMRenderMode m_renderMode;
+ QImage m_image;
+ bool m_rcvHeader;
+ unsigned char m_header[18];
+ int m_rcvHeaderBytes;
+ int m_skipBytes;
+ int m_bytespp;
+ int m_rcvPixels;
+ int m_progress;
+ unsigned char m_restBytes[4];
+ int m_numRestBytes;
+ int m_line;
+ int m_column;
+ QPixmap m_pixmap;
+ bool m_bPixmapUpToDate;
+ QString m_povrayOutput;
+ KTempFile* m_pTempFile;
+
+ static QString s_povrayCommand;
+ static QStringList s_libraryPaths;
+};
+
+#endif
diff --git a/kpovmodeler/pmpovraysettings.cpp b/kpovmodeler/pmpovraysettings.cpp
new file mode 100644
index 00000000..0b2824ae
--- /dev/null
+++ b/kpovmodeler/pmpovraysettings.cpp
@@ -0,0 +1,308 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmpovraysettings.h"
+
+#include "pmdocumentationmap.h"
+#include "pmpovrayrenderwidget.h"
+#include "pmdefaults.h"
+#include "pmresourcelocator.h"
+#include "pmtext.h"
+
+#include <qlayout.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+#include <qlistbox.h>
+#include <qcombobox.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <kfiledialog.h>
+
+PMPovraySettings::PMPovraySettings( QWidget* parent, const char* name )
+ : PMSettingsDialogPage( parent, name )
+{
+ m_selectionIndex = 0;
+
+ QHBoxLayout* hlayout;
+ QVBoxLayout* vlayout;
+ QVBoxLayout* gvl;
+ QGroupBox* gb;
+
+ vlayout = new QVBoxLayout( this, 0, KDialog::spacingHint( ) );
+
+ gb = new QGroupBox( i18n( "Povray Command" ), this );
+ gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) );
+ gvl->addSpacing( 10 );
+ hlayout = new QHBoxLayout( gvl );
+ hlayout->addWidget( new QLabel( i18n( "Command:" ), gb ) );
+ m_pPovrayCommand = new QLineEdit( gb );
+ hlayout->addWidget( m_pPovrayCommand );
+ m_pBrowsePovrayCommand = new QPushButton( gb );
+ m_pBrowsePovrayCommand->setPixmap( SmallIcon( "fileopen" ) );
+ connect( m_pBrowsePovrayCommand, SIGNAL( clicked( ) ),
+ SLOT( slotBrowsePovrayCommand( ) ) );
+ hlayout->addWidget( m_pBrowsePovrayCommand );
+ vlayout->addWidget( gb );
+
+ gb = new QGroupBox( i18n( "Povray User Documentation" ), this );
+ gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) );
+ gvl->addSpacing( 10 );
+ hlayout = new QHBoxLayout( gvl );
+ hlayout->addWidget( new QLabel( i18n( "Path:" ), gb ) );
+ m_pDocumentationPath = new QLineEdit( gb );
+ hlayout->addWidget( m_pDocumentationPath );
+ m_pBrowseDocumentationPath = new QPushButton( gb );
+ m_pBrowseDocumentationPath->setPixmap( SmallIcon( "fileopen" ) );
+ connect( m_pBrowseDocumentationPath, SIGNAL( clicked( ) ),
+ SLOT( slotBrowsePovrayDocumentation( ) ) );
+ hlayout->addWidget( m_pBrowseDocumentationPath );
+ vlayout->addWidget( gb );
+ hlayout = new QHBoxLayout( gvl );
+ hlayout->addWidget( new QLabel( i18n( "Version:" ), gb ) );
+ m_pDocumentationVersion = new QComboBox( false, gb );
+ QValueList<QString> versions = PMDocumentationMap::theMap( )->availableVersions( );
+ QValueListIterator<QString> it;
+ for( it = versions.begin( ); it != versions.end( ); ++it )
+ m_pDocumentationVersion->insertItem( *it );
+ hlayout->addWidget( m_pDocumentationVersion );
+ hlayout->addStretch( );
+
+ gb = new QGroupBox( i18n( "Library Paths" ), this );
+ gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) );
+ gvl->addSpacing( 10 );
+ hlayout = new QHBoxLayout( gvl );
+ m_pLibraryPaths = new QListBox( gb );
+ connect( m_pLibraryPaths, SIGNAL( highlighted( int ) ),
+ SLOT( slotPathSelected( int ) ) );
+ hlayout->addWidget( m_pLibraryPaths );
+
+ QVBoxLayout* bl = new QVBoxLayout( hlayout );
+ m_pAddLibraryPath = new QPushButton( i18n( "Add..." ), gb );
+ connect( m_pAddLibraryPath, SIGNAL( clicked( ) ), SLOT( slotAddPath( ) ) );
+ bl->addWidget( m_pAddLibraryPath );
+ m_pRemoveLibraryPath = new QPushButton( i18n( "Remove" ), gb );
+ connect( m_pRemoveLibraryPath, SIGNAL( clicked( ) ),
+ SLOT( slotRemovePath( ) ) );
+ bl->addWidget( m_pRemoveLibraryPath );
+ m_pChangeLibraryPath = new QPushButton( i18n( "Edit..." ), gb );
+ connect( m_pChangeLibraryPath, SIGNAL( clicked( ) ),
+ SLOT( slotEditPath( ) ) );
+ bl->addWidget( m_pChangeLibraryPath );
+ m_pLibraryPathUp = new QPushButton( i18n( "Up" ), gb );
+ connect( m_pLibraryPathUp, SIGNAL( clicked( ) ), SLOT( slotPathUp( ) ) );
+ bl->addWidget( m_pLibraryPathUp );
+ m_pLibraryPathDown = new QPushButton( i18n( "Down" ), gb );
+ connect( m_pLibraryPathDown, SIGNAL( clicked( ) ),
+ SLOT( slotPathDown( ) ) );
+ bl->addWidget( m_pLibraryPathDown );
+ bl->addStretch( 1 );
+ vlayout->addWidget( gb );
+
+ vlayout->addStretch( 1 );
+}
+
+void PMPovraySettings::displaySettings( )
+{
+ m_pPovrayCommand->setText( PMPovrayRenderWidget::povrayCommand( ) );
+ m_pDocumentationPath->setText( PMDocumentationMap::theMap( )->povrayDocumentationPath( ) );
+ int c = m_pDocumentationVersion->count( );
+ QString s = PMDocumentationMap::theMap( )->documentationVersion( );
+ int i;
+ for( i = 0; i < c; i++ )
+ if( m_pDocumentationVersion->text( i ) == s )
+ m_pDocumentationVersion->setCurrentItem( i );
+
+ bool sb = m_pLibraryPaths->signalsBlocked( );
+ m_pLibraryPaths->blockSignals( true );
+ m_pLibraryPaths->clear( );
+ QStringList plist = PMPovrayRenderWidget::povrayLibraryPaths( );
+ QStringList::ConstIterator it = plist.begin( );
+ m_selectionIndex = -1;
+ for( ; it != plist.end( ); ++it )
+ {
+ m_pLibraryPaths->insertItem( *it );
+ m_selectionIndex++;
+ }
+
+ m_pRemoveLibraryPath->setEnabled( false );
+ m_pChangeLibraryPath->setEnabled( false );
+ m_pLibraryPathUp->setEnabled( false );
+ m_pLibraryPathDown->setEnabled( false );
+ m_pLibraryPaths->blockSignals( sb );
+}
+
+void PMPovraySettings::displayDefaults( )
+{
+ m_pPovrayCommand->setText( c_defaultPovrayCommand );
+ m_pDocumentationVersion->setCurrentItem( 0 );
+ m_pDocumentationPath->setText( QString::null );
+ m_pLibraryPaths->clear();
+
+}
+
+bool PMPovraySettings::validateData( )
+{
+ return true;
+}
+
+void PMPovraySettings::applySettings( )
+{
+ PMPovrayRenderWidget::setPovrayCommand( m_pPovrayCommand->text( ) );
+ PMDocumentationMap::theMap( )->setPovrayDocumentationPath(
+ m_pDocumentationPath->text( ) );
+ PMDocumentationMap::theMap( )->setDocumentationVersion(
+ m_pDocumentationVersion->currentText( ) );
+ QStringList plist;
+ int num = ( signed ) m_pLibraryPaths->count( );
+ int i;
+ for( i = 0; i < num; i++ )
+ plist.append( m_pLibraryPaths->text( i ) );
+
+ if( PMPovrayRenderWidget::povrayLibraryPaths( ) != plist )
+ {
+ PMPovrayRenderWidget::setPovrayLibraryPaths( plist );
+ PMResourceLocator::clearCache( );
+ PMText::povrayLibraryPathsChanged( );
+ emit repaintViews( );
+ }
+}
+
+void PMPovraySettings::slotAddPath( )
+{
+ if( m_pLibraryPaths->count( ) >= 20 )
+ KMessageBox::error( this, i18n( "Povray only supports up to 20 library paths." ) );
+ else
+ {
+ QString path = KFileDialog::getExistingDirectory( QString::null, this );
+ if( !path.isEmpty( ) )
+ {
+#if ( QT_VERSION >= 300 )
+ QListBoxItem* item = m_pLibraryPaths->findItem( path, ExactMatch );
+#else
+ QListBoxItem* item = 0;
+#endif
+ if( !item )
+ {
+ m_pLibraryPaths->insertItem( path, m_selectionIndex + 1 );
+ m_pLibraryPaths->setCurrentItem( m_selectionIndex + 1 );
+ }
+ else
+ KMessageBox::error( this, i18n( "The list of library paths already contains this path." ) );
+ }
+ }
+}
+
+void PMPovraySettings::slotRemovePath( )
+{
+ m_pLibraryPaths->removeItem( m_selectionIndex );
+ if( ( unsigned ) m_selectionIndex >= m_pLibraryPaths->count( ) )
+ m_selectionIndex--;
+ m_pLibraryPaths->setCurrentItem( m_selectionIndex );
+}
+
+void PMPovraySettings::slotPathUp( )
+{
+ QListBoxItem* lbi = m_pLibraryPaths->item( m_selectionIndex );
+ if( lbi )
+ {
+ QString text = lbi->text( );
+ m_pLibraryPaths->removeItem( m_selectionIndex );
+ if( m_selectionIndex > 0 )
+ m_selectionIndex--;
+ m_pLibraryPaths->insertItem( text, m_selectionIndex );
+ m_pLibraryPaths->setCurrentItem( m_selectionIndex );
+ }
+}
+
+void PMPovraySettings::slotPathDown( )
+{
+ QListBoxItem* lbi = m_pLibraryPaths->item( m_selectionIndex );
+ if( lbi )
+ {
+ QString text = lbi->text( );
+ m_pLibraryPaths->removeItem( m_selectionIndex );
+ if( ( unsigned ) m_selectionIndex < m_pLibraryPaths->count( ) )
+ m_selectionIndex++;
+ m_pLibraryPaths->insertItem( text, m_selectionIndex );
+ m_pLibraryPaths->setCurrentItem( m_selectionIndex );
+ }
+}
+
+void PMPovraySettings::slotEditPath( )
+{
+ QListBoxItem* lbi = m_pLibraryPaths->item( m_selectionIndex );
+ if( lbi )
+ {
+ QString text = lbi->text( );
+ QString path = KFileDialog::getExistingDirectory( text, this );
+ if( !path.isEmpty( ) )
+ {
+#if ( QT_VERSION >= 300 )
+ QListBoxItem* item = m_pLibraryPaths->findItem( path, ExactMatch );
+#else
+ QListBoxItem* item = 0;
+#endif
+ if( !item )
+ m_pLibraryPaths->changeItem( path, m_selectionIndex );
+ else if( item != lbi )
+ KMessageBox::error( this, i18n( "The list of library paths already contains this path." ) );
+ }
+ }
+}
+
+void PMPovraySettings::slotPathSelected( int index )
+{
+ m_selectionIndex = index;
+ QListBoxItem* lbi = m_pLibraryPaths->item( m_selectionIndex );
+ if( lbi )
+ {
+ m_pRemoveLibraryPath->setEnabled( true );
+ m_pChangeLibraryPath->setEnabled( true );
+ m_pLibraryPathUp->setEnabled( index > 0 );
+ m_pLibraryPathDown->setEnabled( index < ( ( signed ) m_pLibraryPaths->count( ) - 1 ) );
+ }
+ else
+ {
+ m_pRemoveLibraryPath->setEnabled( false );
+ m_pChangeLibraryPath->setEnabled( false );
+ m_pLibraryPathUp->setEnabled( false );
+ m_pLibraryPathDown->setEnabled( false );
+ }
+}
+
+void PMPovraySettings::slotBrowsePovrayCommand( )
+{
+ QString str = KFileDialog::getOpenFileName( QString::null, QString::null );
+
+ if( !str.isEmpty() )
+ {
+ m_pPovrayCommand->setText( str );
+ }
+}
+
+void PMPovraySettings::slotBrowsePovrayDocumentation( )
+{
+ QString str = KFileDialog::getExistingDirectory( );
+
+ if( !str.isEmpty( ) )
+ m_pDocumentationPath->setText( str );
+}
+
+#include "pmpovraysettings.moc"
diff --git a/kpovmodeler/pmpovraysettings.h b/kpovmodeler/pmpovraysettings.h
new file mode 100644
index 00000000..cbe07827
--- /dev/null
+++ b/kpovmodeler/pmpovraysettings.h
@@ -0,0 +1,98 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMPOVRAYSETTINGS_H
+#define PMPOVRAYSETTINGS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsettingsdialog.h"
+
+class QLineEdit;
+class QPushButton;
+class QComboBox;
+class QListBox;
+
+/**
+ * Povray configuration dialog page
+ */
+class PMPovraySettings : public PMSettingsDialogPage
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ PMPovraySettings( QWidget* parent, const char* name = 0 );
+ /** */
+ virtual void displaySettings( );
+ /** */
+ virtual bool validateData( );
+ /** */
+ virtual void applySettings( );
+ /** */
+ virtual void displayDefaults( );
+
+protected slots:
+ void slotAddPath( );
+ /**
+ * Called when the remove button is clicked
+ */
+ void slotRemovePath( );
+ /**
+ * Called when the up button is clicked
+ */
+ void slotPathUp( );
+ /**
+ * Called when the down button is clicked
+ */
+ void slotPathDown( );
+ /**
+ * Called when the edit button is clicked
+ */
+ void slotEditPath( );
+ /**
+ * Called when a path is selected in the list view
+ */
+ void slotPathSelected( int index );
+ /**
+ * Called when the browse button for the povray command is clicked
+ */
+ void slotBrowsePovrayCommand( );
+ /**
+ * Called when the browse button for the povray documentation is clicked
+ */
+ void slotBrowsePovrayDocumentation( );
+
+private:
+ QLineEdit* m_pPovrayCommand;
+ QPushButton* m_pBrowsePovrayCommand;
+ QLineEdit* m_pDocumentationPath;
+ QPushButton* m_pBrowseDocumentationPath;
+ QComboBox* m_pDocumentationVersion;
+ QListBox* m_pLibraryPaths;
+ QPushButton* m_pAddLibraryPath;
+ QPushButton* m_pRemoveLibraryPath;
+ QPushButton* m_pChangeLibraryPath;
+ QPushButton* m_pLibraryPathUp;
+ QPushButton* m_pLibraryPathDown;
+ int m_selectionIndex;
+};
+
+#endif
diff --git a/kpovmodeler/pmpovraywidget.cpp b/kpovmodeler/pmpovraywidget.cpp
new file mode 100644
index 00000000..d50edc7e
--- /dev/null
+++ b/kpovmodeler/pmpovraywidget.cpp
@@ -0,0 +1,411 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmpovraywidget.h"
+#include "pmpovrayrenderwidget.h"
+#include "pmpovrayoutputwidget.h"
+#include "pmshell.h"
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kimageio.h>
+#include <kfiledialog.h>
+#include <ktempfile.h>
+#include <kio/netaccess.h>
+#include <kglobalsettings.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+#include <qlayout.h>
+#include <qprogressbar.h>
+#include <qlabel.h>
+#include <qscrollview.h>
+#include <qtimer.h>
+#include <qapplication.h>
+
+const int timerIntervall = 1000;
+bool PMPovrayWidget::s_imageFormatsRegistered = false;
+
+PMPovrayWidget::PMPovrayWidget( QWidget* parent, const char* name )
+ : KDialog( parent, name )
+{
+ QVBoxLayout* topLayout = new QVBoxLayout( this, KDialog::marginHint( ), KDialog::spacingHint( ) );
+ topLayout->addStretch( );
+
+ QHBoxLayout* renderLayout = new QHBoxLayout( );
+ topLayout->addLayout( renderLayout, 2 );
+ m_pScrollView = new QScrollView( this );
+ m_pScrollView->setBackgroundMode( PaletteBase );
+ renderLayout->addWidget( m_pScrollView, 2 );
+ m_pRenderWidget = new PMPovrayRenderWidget( m_pScrollView->viewport( ) );
+ m_pRenderWidget->setFixedSize( 200, 200 );
+ m_pScrollView->addChild( m_pRenderWidget );
+ topLayout->addStretch( );
+
+ QHBoxLayout* progressLayout = new QHBoxLayout( topLayout );
+ m_pProgressBar = new QProgressBar( this );
+ m_pProgressBar->hide( );
+ progressLayout->addWidget( m_pProgressBar, 1 );
+ m_pProgressLabel = new QLabel( this );
+ progressLayout->addWidget( m_pProgressLabel, 2 );
+
+ QHBoxLayout* buttonLayout = new QHBoxLayout( topLayout );
+ m_pStopButton = new QPushButton( i18n( "Stop" ), this );
+ m_pStopButton->setEnabled( false );
+ buttonLayout->addWidget( m_pStopButton );
+ m_pSuspendButton = new QPushButton( i18n( "Suspend" ), this );
+ m_pSuspendButton->setEnabled( false );
+ buttonLayout->addWidget( m_pSuspendButton );
+ m_pResumeButton = new QPushButton( i18n( "Resume" ), this );
+ m_pResumeButton->setEnabled( false );
+ buttonLayout->addWidget( m_pResumeButton );
+ buttonLayout->addStretch( 1 );
+ m_pPovrayOutputButton = new QPushButton( i18n( "Povray Output" ), this );
+ buttonLayout->addWidget( m_pPovrayOutputButton );
+
+ buttonLayout = new QHBoxLayout( topLayout );
+ m_pSaveButton = new KPushButton( KStdGuiItem::saveAs(), this );
+ m_pSaveButton->setEnabled( false );
+ buttonLayout->addWidget( m_pSaveButton );
+ buttonLayout->addStretch( 1 );
+ QPushButton* closeButton = new KPushButton( KStdGuiItem::close(), this );
+ buttonLayout->addWidget( closeButton );
+
+ connect( m_pRenderWidget, SIGNAL( finished( int ) ),
+ SLOT( slotRenderingFinished( int ) ) );
+ connect( m_pRenderWidget, SIGNAL( progress( int ) ),
+ SLOT( slotProgress( int ) ) );
+ connect( m_pRenderWidget, SIGNAL( lineFinished( int ) ),
+ SLOT( slotLineFinished( int ) ) );
+
+ connect( m_pStopButton, SIGNAL( clicked( ) ), SLOT( slotStop( ) ) );
+ connect( m_pSuspendButton, SIGNAL( clicked( ) ), SLOT( slotSuspend( ) ) );
+ connect( m_pResumeButton, SIGNAL( clicked( ) ), SLOT( slotResume( ) ) );
+ connect( m_pSaveButton, SIGNAL( clicked( ) ), SLOT( slotSave( ) ) );
+ connect( closeButton, SIGNAL( clicked( ) ), SLOT( slotClose( ) ) );
+ connect( m_pPovrayOutputButton, SIGNAL( clicked( ) ),
+ SLOT( slotPovrayOutput( ) ) );
+
+ m_bRunning = false;
+ m_pProgressTimer = new QTimer( this );
+ connect( m_pProgressTimer, SIGNAL( timeout( ) ),
+ SLOT( slotUpdateSpeed( ) ) );
+
+ setCaption( i18n( "Render Window" ) );
+
+ m_height = m_width = 0;
+ m_stopped = false;
+
+ m_pPovrayOutputWidget = new PMPovrayOutputWidget( );
+ connect( m_pRenderWidget, SIGNAL( povrayMessage( const QString& ) ),
+ m_pPovrayOutputWidget, SLOT( slotText( const QString& ) ) );
+}
+
+PMPovrayWidget::~PMPovrayWidget( )
+{
+ delete m_pPovrayOutputWidget;
+}
+
+bool PMPovrayWidget::render( const QByteArray& scene, const PMRenderMode& m,
+ const KURL& documentURL )
+{
+ bool updateSize = ( m_height != m.height( ) ) || ( m_width != m.width( ) );
+ m_height = m.height( );
+ m_width = m.width( );
+ m_bRunning = false;
+ m_pPovrayOutputWidget->slotClear( );
+ m_stopped = false;
+
+ m_pRenderWidget->setFixedSize( m_width, m_height );
+ QSize maxSize( m_width + m_pScrollView->frameWidth( ) * 2,
+ m_height + m_pScrollView->frameWidth( ) * 2 );
+ m_pScrollView->setMaximumSize( maxSize );
+
+ if( updateSize )
+ {
+ int w, h;
+
+ w = maxSize.width( ) + KDialog::spacingHint( ) * 2;
+ h = maxSize.height( ) + m_pSaveButton->sizeHint( ).height( ) * 2
+ + KDialog::spacingHint( ) * 6;
+ if( m_pProgressLabel->sizeHint( ).height( )
+ > m_pProgressBar->sizeHint( ).height( ) )
+ h += m_pProgressLabel->sizeHint( ).height( );
+ else
+ h += m_pProgressBar->sizeHint( ).height( );
+
+ w += 16;
+ h += 16;
+
+#if ( ( KDE_VERSION_MAJOR == 3 ) && ( KDE_VERSION_MINOR <= 1 ) )
+ QWidget* dw = QApplication::desktop( );
+ if( w > dw->width( ) )
+ w = dw->width( );
+ if( h > dw->height( ) )
+ h = dw->height( );
+#else
+ QRect dw = KGlobalSettings::desktopGeometry(this);
+ if( w > dw.width() )
+ w = dw.width();
+ if( h > dw.height() )
+ h = dw.height();
+#endif
+ resize( w, h );
+ }
+
+ if( m_pRenderWidget->render( scene, m, documentURL ) )
+ {
+ m_bRunning = true;
+ m_pProgressBar->setProgress( 0 );
+ m_pProgressBar->show( );
+ m_pProgressLabel->setText( i18n( "running" ) );
+ m_pStopButton->setEnabled( true );
+ m_pSuspendButton->setEnabled( true );
+ m_pResumeButton->setEnabled( false );
+ m_pSaveButton->setEnabled( false );
+
+ m_lastSpeedTime = QTime( );
+ m_pProgressTimer->start( timerIntervall, true );
+ m_speedInfo = false;
+ m_speed = 0;
+ m_line = 0;
+ m_immediateUpdate = false;
+ showSpeed( 0 );
+ }
+
+ return m_bRunning;
+}
+
+void PMPovrayWidget::slotStop( )
+{
+ m_stopped = true;
+ m_pRenderWidget->killRendering( );
+ m_pSaveButton->setEnabled( true );
+}
+
+void PMPovrayWidget::slotSuspend( )
+{
+ m_pRenderWidget->suspendRendering( );
+ m_pSuspendButton->setEnabled( false );
+ m_pResumeButton->setEnabled( true );
+ m_pSaveButton->setEnabled( true );
+
+ m_pProgressTimer->stop( );
+ m_lastSpeedTime = QTime( );
+ m_speedInfo = false;
+ m_immediateUpdate = false;
+ m_pProgressLabel->setText( i18n( "suspended" ) );
+}
+
+void PMPovrayWidget::slotResume( )
+{
+ m_pRenderWidget->resumeRendering( );
+ m_pSuspendButton->setEnabled( true );
+ m_pResumeButton->setEnabled( false );
+ m_pSaveButton->setEnabled( false );
+
+ m_pProgressTimer->start( timerIntervall, true );
+ showSpeed( m_speed );
+}
+
+void PMPovrayWidget::slotClose( )
+{
+ hide( );
+}
+
+void PMPovrayWidget::slotSave( )
+{
+ KTempFile* tempFile = 0;
+ QFile* file = 0;
+ bool ok = true;
+
+ if( !s_imageFormatsRegistered )
+ {
+ KImageIO::registerFormats( );
+ s_imageFormatsRegistered = true;
+ }
+
+ KURL url = KFileDialog::getSaveURL( QString::null, KImageIO::pattern( KImageIO::Writing ) );
+ if( url.isEmpty( ) )
+ return;
+ if( !PMShell::overwriteURL( url ) )
+ return;
+
+ if( !url.isValid( ) )
+ {
+ KMessageBox::error( this, i18n( "Malformed URL" ) );
+ return;
+ }
+
+ QString format = KImageIO::type( url.fileName( ) );
+ if( format.isEmpty( ) )
+ {
+ KMessageBox::error( this, i18n( "Unknown image format.\n"
+ "Please enter a valid suffix." ) );
+ return;
+ }
+
+ if( !KImageIO::canWrite( format ) )
+ {
+ KMessageBox::error( this, i18n( "Format is not supported for writing." ) );
+ return;
+ }
+
+ if( url.isLocalFile( ) )
+ {
+ // Local file
+ file = new QFile( url.path( ) );
+ if( !file->open( IO_WriteOnly ) )
+ ok = false;
+ }
+ else
+ {
+ // Remote file
+ // provide a temp file
+ tempFile = new KTempFile( );
+ if( tempFile->status( ) != 0 )
+ ok = false;
+ else
+ file = tempFile->file( );
+ }
+
+ if( ok )
+ {
+ QImageIO iio( file, format.latin1( ) );
+ iio.setImage( m_pRenderWidget->image( ) );
+ ok = iio.write( );
+
+ if( ok )
+ {
+ if( tempFile )
+ {
+ tempFile->close( );
+ ok = KIO::NetAccess::upload( tempFile->name( ), url );
+ tempFile->unlink( );
+ file = 0;
+ }
+ else
+ file->close( );
+ }
+ else
+ KMessageBox::error( this, i18n( "Couldn't correctly write the image.\n"
+ "Wrong image format?" ) );
+ }
+ else
+ KMessageBox::error( this, i18n( "Couldn't write the image.\n"
+ "Permission denied." ) );
+
+
+ delete file;
+ delete tempFile;
+}
+
+void PMPovrayWidget::slotPovrayOutput( )
+{
+ m_pPovrayOutputWidget->show( );
+}
+
+void PMPovrayWidget::slotRenderingFinished( int returnStatus )
+{
+ kdDebug( PMArea ) << "Povray exited with status " << returnStatus << endl;
+ m_bRunning = false;
+ if( returnStatus == 0 )
+ m_pSaveButton->setEnabled( true );
+ m_pStopButton->setEnabled( false );
+ m_pSuspendButton->setEnabled( false );
+ m_pResumeButton->setEnabled( false );
+ m_pProgressLabel->setText( i18n( "finished" ) );
+ m_pProgressTimer->stop( );
+
+ if( ( returnStatus != 0 ) && !m_stopped )
+ {
+ KMessageBox::error( this, i18n( "Povray exited abnormally.\n"
+ "See the povray output for details." )
+ .arg( returnStatus ) );
+ }
+ else if( m_pRenderWidget->povrayOutput( ).contains( "ERROR" ) )
+ {
+ KMessageBox::error( this, i18n( "There were errors while rendering.\n"
+ "See the povray output for details." ) );
+ }
+}
+
+void PMPovrayWidget::slotProgress( int i )
+{
+ m_pProgressBar->setProgress( i );
+}
+
+void PMPovrayWidget::slotLineFinished( int line )
+{
+ m_speedInfo = true;
+ QTime ct = QTime::currentTime( );
+
+ if( !m_lastSpeedTime.isNull( ) )
+ {
+ int msecs = m_lastSpeedTime.msecsTo( ct );
+ if( msecs < 1 )
+ msecs = 1;
+
+ double g = 1.0 / ( ( double ) msecs / 500.0 + 1.0 );
+ m_speed = g * m_speed +
+ 1000 * ( 1.0 - g ) * m_width * ( line - m_line ) / msecs;
+ }
+
+ if( m_immediateUpdate )
+ {
+ m_immediateUpdate = false;
+ showSpeed( m_speed );
+ m_pProgressTimer->start( timerIntervall, true );
+ m_speedInfo = false;
+ }
+
+ m_lastSpeedTime = ct;
+ m_line = line;
+}
+
+void PMPovrayWidget::slotUpdateSpeed( )
+{
+ if( m_speedInfo )
+ {
+ showSpeed( m_speed );
+ m_pProgressTimer->start( timerIntervall, true );
+ m_speedInfo = false;
+ }
+ else
+ m_immediateUpdate = true;
+}
+
+void PMPovrayWidget::showSpeed( double pps )
+{
+ QString num;
+ if( pps >= 1000000 )
+ {
+ num.setNum( pps / 100000, 'g', 3 );
+ num += 'M';
+ }
+ else if( pps >= 1000 )
+ {
+ num.setNum( pps / 1000, 'g', 3 );
+ num += 'K';
+ }
+ else
+ num.setNum( pps, 'g', 3 );
+
+ m_pProgressLabel->setText( i18n( "running, %1 pixels/second" ).arg( num ) );
+}
+
+#include "pmpovraywidget.moc"
diff --git a/kpovmodeler/pmpovraywidget.h b/kpovmodeler/pmpovraywidget.h
new file mode 100644
index 00000000..26d5bb1e
--- /dev/null
+++ b/kpovmodeler/pmpovraywidget.h
@@ -0,0 +1,103 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMPOVRAYWIDGET_H
+#define PMPOVRAYWIDGET_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kdialog.h>
+#include <qcstring.h>
+#include <qdatetime.h>
+
+class PMPovrayRenderWidget;
+class PMPovrayOutputWidget;
+class PMRenderMode;
+
+class QProgressBar;
+class QPushButton;
+class QLabel;
+class QScrollView;
+class KURL;
+
+/**
+ * Widget with toolbar, statusbar and a @ref PMPovrayRenderWidget
+ */
+class PMPovrayWidget : public KDialog
+{
+ Q_OBJECT
+public:
+ /**
+ * Standard constructor
+ */
+ PMPovrayWidget( QWidget* parent = 0, const char* name = 0 );
+ /**
+ * Destructor
+ */
+ virtual ~PMPovrayWidget( );
+
+ /**
+ * Starts rendering for the povray code in the byte array with
+ * render mode m.
+ * @see PMRenderMode
+ */
+ bool render( const QByteArray& scene, const PMRenderMode& m,
+ const KURL& documentURL );
+
+public slots:
+ void slotStop( );
+ void slotSuspend( );
+ void slotResume( );
+ void slotClose( );
+ void slotSave( );
+ void slotPovrayOutput( );
+
+protected slots:
+ void slotRenderingFinished( int returnStatus );
+ void slotProgress( int i );
+ void slotLineFinished( int line );
+ void slotUpdateSpeed( );
+
+protected:
+ void showSpeed( double pps );
+
+private:
+ PMPovrayRenderWidget* m_pRenderWidget;
+ PMPovrayOutputWidget* m_pPovrayOutputWidget;
+ QPushButton* m_pStopButton;
+ QPushButton* m_pSuspendButton;
+ QPushButton* m_pResumeButton;
+ QPushButton* m_pSaveButton;
+ QPushButton* m_pPovrayOutputButton;
+ QProgressBar* m_pProgressBar;
+ QLabel* m_pProgressLabel;
+ QScrollView* m_pScrollView;
+ int m_height, m_width;
+ bool m_bRunning;
+ QTime m_lastSpeedTime;
+ QTimer* m_pProgressTimer;
+ bool m_speedInfo;
+ bool m_immediateUpdate;
+ float m_speed;
+ int m_line;
+ bool m_stopped;
+ static bool s_imageFormatsRegistered;
+};
+
+#endif
diff --git a/kpovmodeler/pmpreviewsettings.cpp b/kpovmodeler/pmpreviewsettings.cpp
new file mode 100644
index 00000000..1254431e
--- /dev/null
+++ b/kpovmodeler/pmpreviewsettings.cpp
@@ -0,0 +1,207 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmpreviewsettings.h"
+
+#include "pmlineedits.h"
+#include "pmdialogeditbase.h"
+#include "pmdefaults.h"
+
+#include <qlayout.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <kcolorbutton.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+PMPreviewSettings::PMPreviewSettings( QWidget* parent, const char* name )
+ : PMSettingsDialogPage( parent, name )
+{
+ QHBoxLayout* hlayout;
+ QVBoxLayout* vlayout;
+ QVBoxLayout* gvl;
+ QGridLayout* grid;
+ QGroupBox* gb;
+
+ vlayout = new QVBoxLayout( this, 0, KDialog::spacingHint( ) );
+
+ hlayout = new QHBoxLayout( vlayout );
+ grid = new QGridLayout( hlayout, 2, 2 );
+ grid->addWidget( new QLabel( i18n( "Size:" ), this ), 0, 0 );
+ m_pPreviewSize = new PMIntEdit( this );
+ m_pPreviewSize->setValidation( true, 10, true, 400 );
+ grid->addWidget( m_pPreviewSize, 0, 1 );
+
+ grid->addWidget( new QLabel( i18n( "Gamma:" ), this ), 1, 0 );
+ m_pPreviewGamma = new PMFloatEdit( this );
+ grid->addWidget( m_pPreviewGamma, 1, 1 );
+ hlayout->addStretch( 1 );
+
+ gb = new QGroupBox( i18n( "Rendered Objects" ), this );
+ vlayout->addWidget( gb );
+ gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) );
+ gvl->addSpacing( 10 );
+ m_pPreviewSphere = new QCheckBox( i18n( "Sphere" ), gb );
+ gvl->addWidget( m_pPreviewSphere );
+ m_pPreviewCylinder = new QCheckBox( i18n( "Cylinder" ), gb );
+ gvl->addWidget( m_pPreviewCylinder );
+ m_pPreviewBox = new QCheckBox( i18n( "Box" ), gb );
+ gvl->addWidget( m_pPreviewBox );
+
+ gb = new QGroupBox( i18n( "Wall" ), this );
+ vlayout->addWidget( gb );
+ gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) );
+ gvl->addSpacing( 10 );
+ m_pPreviewWall = new QCheckBox( i18n( "Enable wall" ), gb );
+ gvl->addWidget( m_pPreviewWall );
+ hlayout = new QHBoxLayout( gvl );
+ hlayout->addWidget( new QLabel( i18n( "Color 1:" ), gb ) );
+ m_pWallColor1 = new KColorButton( gb );
+ hlayout->addWidget( m_pWallColor1 );
+ hlayout->addWidget( new QLabel( i18n( "Color 2:" ), gb ) );
+ m_pWallColor2 = new KColorButton( gb );
+ hlayout->addWidget( m_pWallColor2 );
+ hlayout->addStretch( 1 );
+
+ gb = new QGroupBox( i18n( "Floor" ), this );
+ vlayout->addWidget( gb );
+ gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) );
+ gvl->addSpacing( 10 );
+ m_pPreviewFloor = new QCheckBox( i18n( "Enable floor" ), gb );
+ gvl->addWidget( m_pPreviewFloor );
+ hlayout = new QHBoxLayout( gvl );
+ hlayout->addWidget( new QLabel( i18n( "Color 1:" ), gb ) );
+ m_pFloorColor1 = new KColorButton( gb );
+ hlayout->addWidget( m_pFloorColor1 );
+ hlayout->addWidget( new QLabel( i18n( "Color 2:" ), gb ) );
+ m_pFloorColor2 = new KColorButton( gb );
+ hlayout->addWidget( m_pFloorColor2 );
+ hlayout->addStretch( 1 );
+
+ gb = new QGroupBox( i18n( "Antialiasing" ), this );
+ vlayout->addWidget( gb );
+ gvl = new QVBoxLayout( gb, KDialog::marginHint( ), KDialog::spacingHint( ) );
+ gvl->addSpacing( 10 );
+ m_pPreviewAA = new QCheckBox( i18n( "Enable antialiasing" ), gb );
+ gvl->addWidget( m_pPreviewAA );
+ hlayout = new QHBoxLayout( gvl );
+ hlayout->addWidget( new QLabel( i18n( "Depth:" ), gb ) );
+ m_pPreviewAALevel = new PMIntEdit( gb );
+ m_pPreviewAALevel->setValidation( true, 1, true, 9 );
+ hlayout->addWidget( m_pPreviewAALevel );
+ hlayout->addWidget( new QLabel( i18n( "Threshold:" ), gb ) );
+ m_pPreviewAAThreshold = new PMFloatEdit( gb );
+ hlayout->addWidget( m_pPreviewAAThreshold );
+ hlayout->addStretch( 1 );
+
+ vlayout->addStretch( 1 );
+}
+
+void PMPreviewSettings::displaySettings( )
+{
+ m_pPreviewSize->setValue( PMDialogEditBase::previewSize( ) );
+ m_pPreviewGamma->setValue( PMDialogEditBase::previewGamma( ) );
+ m_pPreviewSphere->setChecked( PMDialogEditBase::previewShowSphere( ) );
+ m_pPreviewCylinder->setChecked( PMDialogEditBase::previewShowCylinder( ) );
+ m_pPreviewBox->setChecked( PMDialogEditBase::previewShowBox( ) );
+ m_pPreviewAA->setChecked( PMDialogEditBase::isPreviewAAEnabled( ) );
+ m_pPreviewAALevel->setValue( PMDialogEditBase::previewAADepth( ) );
+ m_pPreviewAAThreshold->setValue( PMDialogEditBase::previewAAThreshold( ) );
+ m_pPreviewWall->setChecked( PMDialogEditBase::previewShowWall( ) );
+ m_pPreviewFloor->setChecked( PMDialogEditBase::previewShowFloor( ) );
+ m_pFloorColor1->setColor( PMDialogEditBase::previewFloorColor1( ) );
+ m_pFloorColor2->setColor( PMDialogEditBase::previewFloorColor2( ) );
+ m_pWallColor1->setColor( PMDialogEditBase::previewWallColor1( ) );
+ m_pWallColor2->setColor( PMDialogEditBase::previewWallColor2( ) );
+}
+
+void PMPreviewSettings::displayDefaults( )
+{
+ m_pPreviewSize->setValue( c_defaultTPSize );
+ m_pPreviewGamma->setValue( c_defaultTPGamma );
+ m_pPreviewSphere->setChecked( c_defaultTPShowSphere );
+ m_pPreviewCylinder->setChecked( c_defaultTPShowCylinder );
+ m_pPreviewBox->setChecked( c_defaultTPShowBox );
+ m_pPreviewAA->setChecked( c_defaultTPAA );
+ m_pPreviewAALevel->setValue( c_defaultTPAADepth );
+ m_pPreviewAAThreshold->setValue( c_defaultTPAAThreshold );
+ m_pPreviewWall->setChecked( c_defaultTPShowWall );
+ m_pPreviewFloor->setChecked( c_defaultTPShowFloor );
+ m_pFloorColor1->setColor( c_defaultTPFloorColor1 );
+ m_pFloorColor2->setColor( c_defaultTPFloorColor2 );
+ m_pWallColor1->setColor( c_defaultTPWallColor1 );
+ m_pWallColor2->setColor( c_defaultTPWallColor2 );
+}
+
+bool PMPreviewSettings::validateData( )
+{
+ if( !m_pPreviewSize->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pPreviewSize->setFocus( );
+ return false;
+ }
+ if( !m_pPreviewGamma->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pPreviewGamma->setFocus( );
+ return false;
+ }
+ if( !m_pPreviewAALevel->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pPreviewAALevel->setFocus( );
+ return false;
+ }
+ if( !m_pPreviewAAThreshold->isDataValid( ) )
+ {
+ emit showMe( );
+ m_pPreviewAAThreshold->setFocus( );
+ return false;
+ }
+ if( !( m_pPreviewSphere->isChecked( ) || m_pPreviewCylinder->isChecked( )
+ || m_pPreviewBox->isChecked( ) ) )
+ {
+ emit showMe( );
+ KMessageBox::error( this, i18n( "At least one object has to be selected." ),
+ i18n( "Error" ) );
+
+ return false;
+ }
+ return true;
+}
+
+void PMPreviewSettings::applySettings( )
+{
+ PMDialogEditBase::setPreviewSize( m_pPreviewSize->value( ) );
+ PMDialogEditBase::setPreviewGamma( m_pPreviewGamma->value( ) );
+ PMDialogEditBase::previewShowSphere( m_pPreviewSphere->isChecked( ) );
+ PMDialogEditBase::previewShowCylinder( m_pPreviewCylinder->isChecked( ) );
+ PMDialogEditBase::previewShowBox( m_pPreviewBox->isChecked( ) );
+ PMDialogEditBase::setPreviewAAEnabled( m_pPreviewAA->isChecked( ) );
+ PMDialogEditBase::setPreviewAADepth( m_pPreviewAALevel->value( ) );
+ PMDialogEditBase::setPreviewAAThreshold( m_pPreviewAAThreshold->value( ) );
+ PMDialogEditBase::previewShowFloor( m_pPreviewFloor->isChecked( ) );
+ PMDialogEditBase::previewShowWall( m_pPreviewWall->isChecked( ) );
+ PMDialogEditBase::setPreviewWallColor1( m_pWallColor1->color( ) );
+ PMDialogEditBase::setPreviewWallColor2( m_pWallColor2->color( ) );
+ PMDialogEditBase::setPreviewFloorColor1( m_pFloorColor1->color( ) );
+ PMDialogEditBase::setPreviewFloorColor2( m_pFloorColor2->color( ) );
+}
+
+#include "pmpreviewsettings.moc"
diff --git a/kpovmodeler/pmpreviewsettings.h b/kpovmodeler/pmpreviewsettings.h
new file mode 100644
index 00000000..a0983002
--- /dev/null
+++ b/kpovmodeler/pmpreviewsettings.h
@@ -0,0 +1,69 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMPREVIEWSETTINGS_H
+#define PMPREVIEWSETTINGS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsettingsdialog.h"
+
+class PMIntEdit;
+class PMFloatEdit;
+class QCheckBox;
+class KColorButton;
+
+/**
+ * Texture preview configuration dialog page
+ */
+class PMPreviewSettings : public PMSettingsDialogPage
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ PMPreviewSettings( QWidget* parent, const char* name = 0 );
+ /** */
+ virtual void displaySettings( );
+ /** */
+ virtual bool validateData( );
+ /** */
+ virtual void applySettings( );
+ /** */
+ virtual void displayDefaults( );
+
+private:
+ PMIntEdit* m_pPreviewSize;
+ QCheckBox* m_pPreviewSphere;
+ QCheckBox* m_pPreviewCylinder;
+ QCheckBox* m_pPreviewBox;
+ QCheckBox* m_pPreviewAA;
+ PMIntEdit* m_pPreviewAALevel;
+ PMFloatEdit* m_pPreviewAAThreshold;
+ QCheckBox* m_pPreviewWall;
+ QCheckBox* m_pPreviewFloor;
+ KColorButton* m_pFloorColor1;
+ KColorButton* m_pFloorColor2;
+ KColorButton* m_pWallColor1;
+ KColorButton* m_pWallColor2;
+ PMFloatEdit* m_pPreviewGamma;
+};
+
+#endif
diff --git a/kpovmodeler/pmprism.cpp b/kpovmodeler/pmprism.cpp
new file mode 100644
index 00000000..26fa9035
--- /dev/null
+++ b/kpovmodeler/pmprism.cpp
@@ -0,0 +1,1187 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmprism.h"
+
+#include "pmxmlhelper.h"
+#include "pmprismedit.h"
+#include "pmmemento.h"
+#include "pmviewstructure.h"
+#include "pm2dcontrolpoint.h"
+#include "pmdistancecontrolpoint.h"
+#include "pmprismmemento.h"
+#include "pmsplinesegment.h"
+#include "pmdefaults.h"
+#include "pmenumproperty.h"
+#include "pmobjectaction.h"
+
+#include <klocale.h>
+
+const int defaultNumberOfPoints = 6;
+const PMVector defaultPoint[defaultNumberOfPoints] =
+{
+ PMVector( 0.5, 1.0 ),
+ PMVector( 1.0, 0.0 ),
+ PMVector( 0.5, -1.0 ),
+ PMVector( -0.5, -1.0 ),
+ PMVector( -1.0, 0.0 ),
+ PMVector( -0.5, 1.0 ),
+};
+
+const bool defaultSturm = false;
+const bool defaultOpen = false;
+const PMPrism::SplineType defaultSplineType = PMPrism::LinearSpline;
+const PMPrism::SweepType defaultSweepType = PMPrism::LinearSweep;
+const double defaultHeight1 = 0.0;
+const double defaultHeight2 = 1.0;
+
+int PMPrism::s_sSteps = c_defaultPrismSSteps;
+int PMPrism::s_parameterKey = 0;
+PMMetaObject* PMPrism::s_pMetaObject = 0;
+PMObject* createNewPrism( PMPart* part )
+{
+ return new PMPrism( part );
+}
+
+PMDefinePropertyClass( PMPrism, PMPrismProperty );
+PMDefineEnumPropertyClass( PMPrism, PMPrism::SplineType, PMSplineTypeProperty );
+PMDefineEnumPropertyClass( PMPrism, PMPrism::SweepType, PMSweepTypeProperty );
+
+class PMPointProperty : public PMPropertyBase
+{
+public:
+ PMPointProperty( )
+ : PMPropertyBase( "splinePoints", PMVariant::Vector )
+ {
+ m_index[0] = 0;
+ m_index[1] = 0;
+ }
+ virtual int dimensions( ) const { return 2; }
+ virtual void setIndex( int dimension, int index )
+ {
+ if( dimension == 0 || dimension == 1 )
+ m_index[dimension] = index;
+ }
+ virtual int size( PMObject* object, int dimension ) const
+ {
+ PMPrism* prism = ( PMPrism* ) object;
+ QValueList< QValueList<PMVector> > points = prism->points( );
+ if( dimension == 0 )
+ return points.size( );
+ else
+ {
+ QValueList< QValueList<PMVector> >::ConstIterator it
+ = points.at( m_index[0] );
+ if( it != points.end( ) )
+ return ( *it ).size( );
+ }
+ return 0;
+ }
+protected:
+ virtual bool setProtected( PMObject* obj, const PMVariant& var )
+ {
+ PMPrism* p = ( PMPrism* ) obj;
+ QValueList< QValueList<PMVector> > list = p->points( );
+ QValueList< QValueList<PMVector> >::Iterator sit = list.begin( );
+ int i;
+ PMVector v = var.vectorData( );
+ v.resize( 2 );
+
+ for( i = 0; i < m_index[0] && sit != list.end( ); ++i )
+ ++sit;
+ // expand the list if necessary
+ for( ; i < m_index[0]; ++i )
+ list.insert( sit, QValueList< PMVector >( ) );
+ if( sit == list.end( ) )
+ sit = list.insert( sit, QValueList< PMVector >( ) );
+
+ QValueList<PMVector>::Iterator it = ( *sit ).begin( );
+
+ for( i = 0; i < m_index[1] && it != ( *sit ).end( ); ++i )
+ ++it;
+ // expand the list if necessary
+ for( ; i < m_index[1]; ++i )
+ ( *sit ).insert( it, v );
+ if( it == ( *sit ).end( ) )
+ it = ( *sit ).insert( it, v );
+ else
+ *it = v;
+
+ p->setPoints( list );
+ return true;
+ }
+ virtual PMVariant getProtected( const PMObject* obj )
+ {
+ PMPrism* p = ( PMPrism* ) obj;
+ QValueList< QValueList<PMVector> > list = p->points( );
+ QValueList< QValueList<PMVector> >::ConstIterator sit = list.at( m_index[0] );
+ if( sit == list.end( ) )
+ {
+ kdError( PMArea ) << "Range error in PMPrism::PointProperty::get" << endl;
+ return PMVariant( );
+ }
+
+ QValueList<PMVector>::ConstIterator it = ( *sit ).at( m_index[1] );
+
+ if( it == ( *sit ).end( ) )
+ {
+ kdError( PMArea ) << "Range error in PMPrism::PointProperty::get" << endl;
+ return PMVariant( );
+ }
+
+ return PMVariant( *it );
+ }
+
+private:
+ int m_index[2];
+};
+
+PMPrism::PMPrism( PMPart* part )
+ : Base( part )
+{
+ int i;
+ QValueList<PMVector> p;
+
+ for( i = 0; i < defaultNumberOfPoints; ++i )
+ p.append( defaultPoint[i] );
+ m_points.append( p );
+ m_splineType = defaultSplineType;
+ m_sweepType = defaultSweepType;
+ m_sturm = defaultSturm;
+ m_open = defaultOpen;
+ m_height1 = defaultHeight1;
+ m_height2 = defaultHeight2;
+}
+
+PMPrism::PMPrism( const PMPrism& p )
+ : Base( p )
+{
+ m_splineType = p.m_splineType;
+ m_sweepType = p.m_sweepType;
+ m_points = p.m_points;
+ m_height1 = p.m_height1;
+ m_height2 = p.m_height2;
+ m_open = p.m_open;
+ m_sturm = p.m_sturm;
+}
+
+PMPrism::~PMPrism( )
+{
+}
+
+QString PMPrism::description( ) const
+{
+ return i18n( "prism" );
+}
+
+void PMPrism::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ QDomElement data = doc.createElement( "extra_data" );
+ QDomElement p, p2;
+
+ e.setAttribute( "spline_type", m_splineType );
+ e.setAttribute( "sweep_type", m_sweepType );
+ e.setAttribute( "sturm", m_sturm );
+ e.setAttribute( "open", m_open );
+ e.setAttribute( "height1", m_height1 );
+ e.setAttribute( "height2", m_height2 );
+
+ QValueList< QValueList<PMVector> >::ConstIterator it;
+ QValueList<PMVector>::ConstIterator it2;
+ for( it = m_points.begin( ); it != m_points.end( ); ++it )
+ {
+ p = doc.createElement( "sub_prism" );
+ for( it2 = ( *it ).begin( ); it2 != ( *it ).end( ); ++it2 )
+ {
+ p2 = doc.createElement( "point" );
+ p2.setAttribute( "vector", ( *it2 ).serializeXML( ) );
+ p.appendChild( p2 );
+ }
+ data.appendChild( p );
+ }
+
+ e.appendChild( data );
+ Base::serialize( e, doc );
+}
+
+void PMPrism::readAttributes( const PMXMLHelper& h )
+{
+ m_splineType = ( SplineType ) h.intAttribute( "spline_type", defaultSplineType );
+ m_sweepType = ( SweepType ) h.intAttribute( "sweep_type", defaultSweepType );
+ m_open = h.boolAttribute( "open", defaultOpen );
+ m_sturm = h.boolAttribute( "sturm", defaultSturm );
+ m_height1 = h.doubleAttribute( "height1", defaultHeight1 );
+ m_height2 = h.doubleAttribute( "height2", defaultHeight2 );
+
+ m_points.clear( );
+ QValueList<PMVector> list;
+ PMVector v( 2 );
+
+ QDomElement e = h.extraData( );
+ if( !e.isNull( ) )
+ {
+ QDomNode sp = e.firstChild( );
+ while( !sp.isNull( ) )
+ {
+ if( sp.isElement( ) )
+ {
+ QDomElement spe = sp.toElement( );
+ if( spe.tagName( ) == "sub_prism" )
+ {
+ list.clear( );
+ QDomNode c = spe.firstChild( );
+ while( !c.isNull( ) )
+ {
+ if( c.isElement( ) )
+ {
+ QDomElement ce = c.toElement( );
+ if( ce.tagName( ) == "point" )
+ {
+ QString str = ce.attribute( "vector" );
+ if( !str.isNull( ) )
+ {
+ v.loadXML( str );
+ list.append( v );
+ }
+ }
+ }
+ c = c.nextSibling( );
+ }
+ m_points.append( list );
+ }
+ }
+ sp = sp.nextSibling( );
+ }
+ }
+
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMPrism::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Prism", Base::metaObject( ),
+ createNewPrism );
+ s_pMetaObject->addProperty(
+ new PMPrismProperty( "sturm", &PMPrism::setSturm, &PMPrism::sturm ) );
+ s_pMetaObject->addProperty(
+ new PMPrismProperty( "open", &PMPrism::setOpen, &PMPrism::open ) );
+ s_pMetaObject->addProperty(
+ new PMPrismProperty( "height1", &PMPrism::setHeight1, &PMPrism::height1 ) );
+ s_pMetaObject->addProperty(
+ new PMPrismProperty( "height2", &PMPrism::setHeight2, &PMPrism::height2 ) );
+
+ PMSplineTypeProperty* p = new PMSplineTypeProperty(
+ "splineType", &PMPrism::setSplineType, &PMPrism::splineType );
+ p->addEnumValue( "LinearSpline", LinearSpline );
+ p->addEnumValue( "QuadraticSpline", QuadraticSpline );
+ p->addEnumValue( "CubicSpline", CubicSpline );
+ p->addEnumValue( "BezierSpline", BezierSpline );
+ s_pMetaObject->addProperty( p );
+
+ PMSweepTypeProperty* sp = new PMSweepTypeProperty(
+ "sweepType", &PMPrism::setSweepType, &PMPrism::sweepType );
+ sp->addEnumValue( "LinearSweep", LinearSweep );
+ sp->addEnumValue( "ConicSweep", ConicSweep );
+ s_pMetaObject->addProperty( sp );
+
+ s_pMetaObject->addProperty( new PMPointProperty( ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMPrism::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMPrism::setSplineType( PMPrism::SplineType t )
+{
+ if( m_splineType != t )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSplineTypeID, ( int ) m_splineType );
+ setViewStructureChanged( );
+ m_splineType = t;
+ }
+}
+
+void PMPrism::setSweepType( PMPrism::SweepType t )
+{
+ if( m_sweepType != t )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSweepTypeID, ( int ) m_sweepType );
+ setViewStructureChanged( );
+ m_sweepType = t;
+ }
+}
+
+void PMPrism::setSturm( bool s )
+{
+ if( m_sturm != s )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSturmID, m_sturm );
+ m_sturm = s;
+ }
+}
+
+void PMPrism::setOpen( bool o )
+{
+ if( m_open != o )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMOpenID, m_open );
+ m_open = o;
+ }
+}
+
+void PMPrism::setHeight1( double h )
+{
+ if( m_height1 != h )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMHeight1ID, m_height1 );
+ m_height1 = h;
+ setViewStructureChanged( );
+ }
+}
+
+void PMPrism::setHeight2( double h )
+{
+ if( m_height2 != h )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMHeight2ID, m_height2 );
+ m_height2 = h;
+ setViewStructureChanged( );
+ }
+}
+
+void PMPrism::setPoints( const QValueList< QValueList<PMVector> >& points )
+{
+ if( m_points != points )
+ {
+ if( m_pMemento )
+ ( ( PMPrismMemento* ) m_pMemento )->setPrismPoints( m_points );
+
+ setViewStructureChanged( );
+ m_points = points;
+ }
+}
+
+PMDialogEditBase* PMPrism::editWidget( QWidget* parent ) const
+{
+ return new PMPrismEdit( parent );
+}
+
+void PMPrism::createMemento( )
+{
+ if( m_pMemento )
+ delete m_pMemento;
+ m_pMemento = new PMPrismMemento( this );
+}
+
+void PMPrism::restoreMemento( PMMemento* s )
+{
+ PMPrismMemento* m = ( PMPrismMemento* ) s;
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMSplineTypeID:
+ setSplineType( ( SplineType ) data->intData( ) );
+ break;
+ case PMSweepTypeID:
+ setSweepType( ( SweepType ) data->intData( ) );
+ break;
+ case PMOpenID:
+ setOpen( data->boolData( ) );
+ break;
+ case PMSturmID:
+ setSturm( data->boolData( ) );
+ break;
+ case PMHeight1ID:
+ setHeight1( data->doubleData( ) );
+ break;
+ case PMHeight2ID:
+ setHeight2( data->doubleData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMPrism::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ if( m->prismPointsSaved( ) )
+ setPoints( m->prismPoints( ) );
+
+ Base::restoreMemento( s );
+}
+
+
+void PMPrism::createViewStructure( )
+{
+ if( s_sSteps == 0 )
+ s_sSteps = c_defaultPrismSSteps;
+
+ int sSteps = (int)( ( (float)s_sSteps / 2 ) * ( displayDetail( ) + 1 ) );
+
+ // calculate number of points and lines of the view structure
+ QValueList< QValueList<PMVector> >::ConstIterator spit = m_points.begin( );
+ int np = 0;
+ for( ; spit != m_points.end( ); ++spit )
+ {
+ int snp = ( *spit ).count( );
+ switch( m_splineType )
+ {
+ case LinearSpline:
+ break;
+ case QuadraticSpline:
+ snp -= 1;
+ break;
+ case CubicSpline:
+ snp -= 2;
+ break;
+ case BezierSpline:
+ snp /= 3;
+ break;
+ }
+ np += snp;
+ }
+
+ int nl = 0;
+ nl = np * sSteps * 3;
+ np *= sSteps * 2;
+
+ if( m_pViewStructure )
+ {
+ if( m_pViewStructure->points( ).size( ) != ( unsigned ) np )
+ m_pViewStructure->points( ).resize( np );
+ if( m_pViewStructure->lines( ).size( ) != ( unsigned ) nl )
+ m_pViewStructure->lines( ).resize( nl );
+ }
+ else
+ m_pViewStructure = new PMViewStructure( np, nl );
+
+ PMLineArray& lines = m_pViewStructure->lines( );
+ PMPointArray& points = m_pViewStructure->points( );
+ int lb = 0;
+ int pb = 0;
+
+ for( spit = m_points.begin( ); spit != m_points.end( ); ++spit )
+ {
+ QValueList<PMSplineSegment> segments;
+ QValueList<PMVector> fullPoints = expandedPoints( *spit );
+
+ int ns = fullPoints.count( );
+ int i, j;
+
+ switch( m_splineType )
+ {
+ case LinearSpline:
+ ns -= 1;
+ break;
+ case QuadraticSpline:
+ ns -= 2;
+ break;
+ case CubicSpline:
+ ns -= 3;
+ break;
+ case BezierSpline:
+ ns = ns / 4;
+ break;
+ }
+ QValueList<PMVector>::Iterator it1, it2, it3, it4;
+
+ // create the spline segments
+ it1 = fullPoints.begin( );
+ it2 = it1; ++it2;
+ it3 = it2; ++it3;
+ it4 = it3; ++it4;
+ PMSplineSegment s;
+
+ for( i = 0; i < ns; ++i )
+ {
+ switch( m_splineType )
+ {
+ case LinearSpline:
+ s.calculateLinear( *it1, *it2 );
+ ++it1;
+ ++it2;
+ break;
+ case QuadraticSpline:
+ s.calculateQuadratic( *it1, *it2, *it3 );
+ ++it1;
+ ++it2;
+ ++it3;
+ break;
+ case CubicSpline:
+ s.calculateCubic( *it1, *it2, *it3, *it4 );
+ ++it1;
+ ++it2;
+ ++it3;
+ ++it4;
+ break;
+ case BezierSpline:
+ s.calculateBezier( *it1, *it2, *it3, *it4 );
+ for( j = 0; j < 4; ++j )
+ {
+ ++it1;
+ ++it2;
+ ++it3;
+ ++it4;
+ }
+ break;
+ }
+ segments.append( s );
+ }
+
+ // create the line array
+ int vp = ns * sSteps;
+ for( i = 0; i < vp - 1; ++i )
+ lines[lb+i] = PMLine( pb + i, pb + i + 1 );
+ lines[lb+vp-1] = PMLine( pb, pb + vp - 1 );
+ lb += vp;
+ for( i = 0; i < vp - 1; ++i )
+ lines[lb+i] = PMLine( pb + vp + i, pb + vp + i + 1 );
+ lines[lb+vp-1] = PMLine( pb + vp, pb + vp + vp - 1 );
+ lb += vp;
+ for( i = 0; i < vp; ++i )
+ lines[lb+i] = PMLine( pb + i, pb + vp + i );
+ lb += vp;
+
+ // calculate the points
+ PMVector point2( 2 ), point3;
+ QValueList<PMSplineSegment>::Iterator sit = segments.begin( );
+ int pi = 0;
+ double poffset = 1.0 / sSteps;
+
+ for( i = 0; i < ns; ++i, ++sit )
+ {
+ for( j = 0; j < sSteps; ++j )
+ {
+ point2 = ( *sit ).point( poffset * j );
+ if( m_sweepType == LinearSweep )
+ {
+ point3[0] = point2[0];
+ point3[1] = m_height1;
+ point3[2] = point2[1];
+ points[pb+pi] = PMPoint( point3 );
+ point3[1] = m_height2;
+ points[pb+pi+vp] = PMPoint( point3 );
+ }
+ else
+ {
+ point3[0] = point2[0];
+ point3[1] = 1.0;
+ point3[2] = point2[1];
+ points[pb+pi] = PMPoint( point3 * m_height1 );
+ points[pb+pi+vp] = PMPoint( point3 * m_height2 );
+ }
+ ++pi;
+ }
+ }
+ pb += vp * 2;
+ }
+}
+
+void PMPrism::controlPoints( PMControlPointList& list )
+{
+ QValueList< QValueList<PMVector> >::Iterator it1;
+ QValueList<PMVector>::Iterator it2;
+ int i1, i2;
+
+ list.append( new PMDistanceControlPoint( PMVector( 0.0, 0.0, 0.0 ),
+ PMVector( 0.0, 1.0, 0.0 ),
+ m_height1, PMHeight1ID,
+ i18n( "Height 1" ) ) );
+ list.append( new PMDistanceControlPoint( PMVector( 0.0, 0.0, 0.0 ),
+ PMVector( 0.0, 1.0, 0.0 ),
+ m_height2, PMHeight2ID,
+ i18n( "Height 2" ) ) );
+
+ PM2DControlPoint* cp;
+
+ for( it1 = m_points.begin( ), i1 = 0; it1 != m_points.end( ); ++it1, ++i1 )
+ {
+ if( m_splineType != BezierSpline )
+ {
+ int refb = ( *it1 ).count( ) - 1;
+ if( m_splineType == CubicSpline )
+ --refb;
+ it2 = ( *it1 ).begin( );
+ PM2DControlPoint* firstPoint = 0;
+ PM2DControlPoint* secondPoint = 0;
+
+ for( i2 = 0; it2 != ( *it1 ).end( ); ++it2, ++i2 )
+ {
+ cp = new PM2DControlPoint( *it2, PM2DControlPoint::PM2DXZ, i2,
+ i18n( "Point %1.%2" ).arg( i1 + 1 ).arg( i2 + 1 ) );
+ if( i2 == 0 )
+ firstPoint = cp;
+ else if( i2 == 1 )
+ secondPoint = cp;
+
+ cp->setThirdCoordinate( m_height2 );
+ if( m_sweepType == ConicSweep )
+ cp->setScale( m_height2 );
+ if( ( ( m_splineType == QuadraticSpline )
+ || ( m_splineType == CubicSpline ) )
+ && ( i2 == 1 ) )
+ firstPoint->setBasePoint( cp );
+ if( ( m_splineType == CubicSpline ) && ( i2 == ( refb + 2 ) ) )
+ cp->setBasePoint( secondPoint );
+
+ list.append( cp );
+
+ if( ( m_splineType != BezierSpline ) && ( i2 == refb ) )
+ ++i2;
+ }
+ }
+ else
+ {
+ it2 = ( *it1 ).begin( );
+ PM2DControlPoint* firstPoint = 0;
+ PM2DControlPoint* lastPoint = 0;
+ PM2DControlPoint* startPoint = 0;
+
+ for( i2 = 0; it2 != ( *it1 ).end( ); ++it2, ++i2 )
+ {
+ int i2mod4 = i2 % 4;
+ cp = new PM2DControlPoint( *it2, PM2DControlPoint::PM2DXZ, i2,
+ i18n( "Point %1.%2" ).arg( i1 + 1 ).arg( i2 + 1 ) );
+ if( i2mod4 == 0 )
+ firstPoint = cp;
+ if( i2mod4 == 2 )
+ lastPoint = cp;
+ if( !startPoint )
+ startPoint = cp;
+
+ cp->setThirdCoordinate( m_height2 );
+ if( m_sweepType == ConicSweep )
+ cp->setScale( m_height2 );
+ if( i2mod4 == 1 )
+ cp->setBasePoint( firstPoint );
+ if( ( i2mod4 == 0 ) && lastPoint )
+ lastPoint->setBasePoint( cp );
+
+ list.append( cp );
+
+ if( i2mod4 == 2 )
+ ++i2;
+ }
+ if( lastPoint )
+ lastPoint->setBasePoint( startPoint );
+ }
+ }
+}
+
+void PMPrism::controlPointsChanged( PMControlPointList& list )
+{
+ PMControlPointListIterator it( list );
+ QValueList< QValueList<PMVector> >::Iterator spit = m_points.begin( );
+ QValueList<PMVector>::Iterator pit = ( *spit ).begin( );
+ PM2DControlPoint* p1;
+ PMDistanceControlPoint* dcp;
+ bool firstChange = true;
+ bool h2changed = false;
+
+ // IDs are ignored, quick hack, but should work
+ if( it.current( )->changed( ) )
+ {
+ dcp = ( PMDistanceControlPoint* ) it.current( );
+ setHeight1( dcp->distance( ) );
+ }
+ ++it;
+ if( it.current( )->changed( ) )
+ {
+ dcp = ( PMDistanceControlPoint* ) it.current( );
+ setHeight2( dcp->distance( ) );
+ h2changed = true;
+ }
+ ++it;
+
+ for( ; it.current( ); ++it )
+ {
+ p1 = ( PM2DControlPoint* ) it.current( );
+ if( p1->changed( ) )
+ {
+ if( firstChange )
+ {
+ if( m_pMemento )
+ {
+ PMPrismMemento* m = ( PMPrismMemento* ) m_pMemento;
+ if( !m->prismPointsSaved( ) )
+ m->setPrismPoints( m_points );
+ }
+ firstChange = false;
+ setViewStructureChanged( );
+ }
+ ( *pit ) = p1->point( );
+ }
+ if( h2changed )
+ {
+ p1->setThirdCoordinate( m_height2 );
+ if( m_sweepType == ConicSweep )
+ p1->setScale( m_height2 );
+ }
+
+ ++pit;
+ if( pit == ( *spit ).end( ) )
+ {
+ ++spit;
+ pit = ( *spit ).begin( );
+ }
+ }
+}
+
+void PMPrism::addObjectActions( const PMControlPointList& /*cp*/,
+ QPtrList<PMObjectAction>& actions )
+{
+ PMObjectAction* a;
+
+ a = new PMObjectAction( s_pMetaObject, PMSplitSegmentID,
+ i18n( "Add Point" ) );
+ actions.append( a );
+
+ a = new PMObjectAction( s_pMetaObject, PMJoinSegmentsID,
+ i18n( "Remove Point" ) );
+
+ bool enableJoin = false;
+ QValueList< QValueList<PMVector> >::ConstIterator spit = m_points.begin( );
+
+ int minp = 4;
+ switch( m_splineType )
+ {
+ case LinearSpline:
+ minp = 4;
+ break;
+ case QuadraticSpline:
+ minp = 5;
+ break;
+ case CubicSpline:
+ minp = 6;
+ break;
+ case BezierSpline:
+ minp = 6;
+ break;
+ }
+
+ for( ; ( spit != m_points.end( ) ) && !enableJoin; ++spit )
+ if( ( *spit ).count( ) >= ( unsigned ) minp )
+ enableJoin = true;
+
+ a->setEnabled( enableJoin );
+ actions.append( a );
+}
+
+void PMPrism::objectActionCalled( const PMObjectAction* action,
+ const PMControlPointList& cp,
+ const QPtrList<PMVector>& cpViewPosition,
+ const PMVector& clickPosition )
+{
+ if( action->objectType( ) == s_pMetaObject )
+ {
+ switch( action->actionID( ) )
+ {
+ case PMSplitSegmentID:
+ splitSegment( cp, cpViewPosition, clickPosition );
+ break;
+ case PMJoinSegmentsID:
+ joinSegments( cp, cpViewPosition, clickPosition );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMPrism::objectActionCalled\n";
+ break;
+ }
+ }
+ else
+ Base::objectActionCalled( action, cp, cpViewPosition, clickPosition );
+}
+
+void PMPrism::splitSegment( const PMControlPointList& /*cp*/,
+ const QPtrList<PMVector>& cpViewPosition,
+ const PMVector& clickPosition )
+{
+ // find nearest segment
+ double abs = 0.0, minabs = 1e10;
+ int ns = -1;
+ int nsp = 0;
+ int spnr = 0, pnr = 0;
+ int i;
+ PMVector mid( 3 ), dist( 2 );
+ PMVector firstPoint( 3 );
+
+ QPtrListIterator<PMVector> it1( cpViewPosition );
+ QPtrListIterator<PMVector> it2( cpViewPosition );
+ for( i = 0; i < 2; ++i ) ++it1;
+ for( i = 0; i < 3; ++i ) ++it2;
+
+ QValueList< QValueList<PMVector> >::Iterator spit = m_points.begin( );
+ for( spnr = 0; spit != m_points.end( ); ++spit, ++spnr )
+ {
+ int nump = ( *spit ).count( );
+ bool first = true;
+ for( pnr = 0; pnr < nump; ++pnr )
+ {
+ bool skip = false;
+ switch( m_splineType )
+ {
+ case LinearSpline:
+ case BezierSpline:
+ break;
+ case QuadraticSpline:
+ if( pnr == 0 )
+ skip = true;
+ break;
+ case CubicSpline:
+ if( ( pnr == 0 ) || ( pnr == ( nump - 1 ) ) )
+ skip = true;
+ break;
+ }
+
+ if( !skip )
+ {
+ if( first )
+ {
+ firstPoint = **it1;
+ first = false;
+ }
+
+ if( ( ( m_splineType == CubicSpline ) && ( pnr == ( nump - 2 ) ) )
+ || ( ( m_splineType != CubicSpline ) && ( pnr == ( nump - 1 ) ) ) )
+ mid = ( **it1 + firstPoint ) / 2.0;
+ else
+ mid = ( **it1 + **it2 ) / 2.0;
+
+ dist[0] = mid[0];
+ dist[1] = mid[1];
+ dist -= clickPosition;
+ abs = dist.abs( );
+
+ if( ( minabs > abs ) || ( ns < 0 ) )
+ {
+ minabs = abs;
+ ns = pnr;
+ nsp = spnr;
+ }
+ }
+ ++it1;
+ ++it2;
+ }
+ }
+
+ // add a new segment
+ QValueList< QValueList<PMVector> > newPoints = m_points;
+ spit = newPoints.at( nsp );
+ QValueList<PMVector> newSubPoints = *spit;
+
+ if( m_splineType == BezierSpline )
+ {
+ ns /= 3;
+ ns *= 3;
+ }
+ QValueList<PMVector>::Iterator it = newSubPoints.at( ( unsigned ) ns );
+ PMVector p[4];
+ QValueList<PMVector>::Iterator hit = it, eit = newSubPoints.end( );
+ --eit;
+
+ // calculate the spline segment
+ PMSplineSegment segment;
+ switch( m_splineType )
+ {
+ case LinearSpline:
+ for( i = 0; i < 2; ++i )
+ {
+ p[i] = *hit;
+ ++hit;
+ if( hit == newSubPoints.end( ) )
+ hit = newSubPoints.begin( );
+ }
+ segment.calculateLinear( p[0], p[1] );
+ break;
+ case QuadraticSpline:
+ --hit;
+ for( i = 0; i < 3; ++i )
+ {
+ p[i] = *hit;
+ ++hit;
+ if( hit == newSubPoints.end( ) )
+ {
+ hit = newSubPoints.begin( );
+ ++hit;
+ }
+ }
+ segment.calculateQuadratic( p[0], p[1], p[2] );
+ break;
+ case CubicSpline:
+ --hit;
+ for( i = 0; i < 4; ++i )
+ {
+ if( hit == eit )
+ {
+ hit = newSubPoints.begin( );
+ ++hit;
+ p[i] = *hit;
+ hit = eit;
+ ++i;
+ if( i < 4 )
+ p[i] = *hit;
+ }
+ else
+ p[i] = *hit;
+ ++hit;
+ }
+ segment.calculateCubic( p[0], p[1], p[2], p[3] );
+ break;
+ case BezierSpline:
+ for( i = 0; i < 4; ++i )
+ {
+ p[i] = *hit;
+ ++hit;
+ if( hit == newSubPoints.end( ) )
+ hit = newSubPoints.begin( );
+ }
+ segment.calculateBezier( p[0], p[1], p[2], p[3] );
+ break;
+ }
+
+ mid = segment.point( 0.5 );
+ if( m_splineType != BezierSpline )
+ {
+ ++it;
+ newSubPoints.insert( it, mid );
+ }
+ else
+ {
+ PMVector end = *it;
+ ++it;
+ *it = end + ( *it - end ) / 2.0;
+ ++it;
+
+ PMVector grad = segment.gradient( 0.5 ) / 4.0;
+
+ newSubPoints.insert( it, mid - grad );
+ newSubPoints.insert( it, mid );
+ newSubPoints.insert( it, mid + grad );
+
+ ++it;
+ if( it == newSubPoints.end( ) )
+ end = *newSubPoints.begin( );
+ else
+ end = *it;
+ --it;
+ *it = end + ( *it - end ) / 2.0;
+ }
+ ( *spit ) = newSubPoints;
+ setPoints( newPoints );
+}
+
+void PMPrism::joinSegments( const PMControlPointList& /*cp*/,
+ const QPtrList<PMVector>& cpViewPosition,
+ const PMVector& clickPosition )
+{
+ // find nearest point
+ double abs = 0.0, minabs = 1e10;
+ int ns = -1;
+ int nsp = 0;
+ int spnr = 0, pnr = 0;
+ int i;
+ PMVector dist( 2 );
+
+ QPtrListIterator<PMVector> it1( cpViewPosition );
+ for( i = 0; i < 2; ++i ) ++it1;
+
+ int minp = 0;
+ switch( m_splineType )
+ {
+ case LinearSpline:
+ minp = 4;
+ break;
+ case QuadraticSpline:
+ minp = 5;
+ break;
+ case CubicSpline:
+ minp = 6;
+ break;
+ case BezierSpline:
+ minp = 6;
+ break;
+ }
+
+ QValueList< QValueList<PMVector> >::Iterator spit = m_points.begin( );
+ for( spnr = 0; spit != m_points.end( ); ++spit, ++spnr )
+ {
+ int nump = ( *spit ).count( );
+
+ for( pnr = 0; pnr < nump; ++pnr )
+ {
+ bool skip = false;
+ switch( m_splineType )
+ {
+ case LinearSpline:
+ case BezierSpline:
+ break;
+ case QuadraticSpline:
+ if( pnr == 0 )
+ skip = true;
+ break;
+ case CubicSpline:
+ if( ( pnr == 0 ) || ( pnr == ( nump - 1 ) ) )
+ skip = true;
+ break;
+ }
+ if( nump < minp )
+ skip = true;
+
+ if( !skip )
+ {
+ dist[0] = (**it1)[0];
+ dist[1] = (**it1)[1];
+ dist -= clickPosition;
+ abs = dist.abs( );
+
+ if( ( minabs > abs ) || ( ns < 0 ) )
+ {
+ minabs = abs;
+ ns = pnr;
+ nsp = spnr;
+ }
+ }
+ ++it1;
+ }
+ }
+
+ if( ns < 0 )
+ {
+ kdError( PMArea ) << "Not enough points in PMPrism::joinSegments\n";
+ return;
+ }
+
+ // remove the segment
+ QValueList< QValueList<PMVector> > newPoints = m_points;
+ spit = newPoints.at( nsp );
+ QValueList<PMVector> newSubPoints = *spit;
+ QValueList<PMVector>::Iterator it;
+
+ if( m_splineType != BezierSpline )
+ {
+ it = newSubPoints.at( ( unsigned ) ns );
+ newSubPoints.remove( it );
+ }
+ else
+ {
+ int last = ( newSubPoints.count( ) - 3 ) / 3;
+ ns -= 2;
+ if( ns < 0 )
+ ns = last;
+ else
+ ns /= 3;
+
+ it = newSubPoints.at( ns * 3 + 2 );
+ if( ns != last )
+ {
+ it = newSubPoints.remove( it );
+ it = newSubPoints.remove( it );
+ it = newSubPoints.remove( it );
+ }
+ else
+ {
+ newSubPoints.remove( it );
+ it = newSubPoints.begin( );
+ it = newSubPoints.remove( it );
+ it = newSubPoints.remove( it );
+ PMVector h = *it;
+ it = newSubPoints.remove( it );
+ newSubPoints.insert( newSubPoints.end( ), h );
+ }
+ }
+ ( *spit ) = newSubPoints;
+ setPoints( newPoints );
+}
+
+void PMPrism::setSSteps( int s )
+{
+ if( s >= 1 )
+ s_sSteps = s;
+ else
+ kdDebug( PMArea ) << "PMPrism::setSSteps: S must be greater than 0\n";
+ ++s_parameterKey;
+}
+
+QValueList<PMVector> PMPrism::expandedPoints( const QValueList<PMVector>& p ) const
+{
+ // add the missing points
+ int refa = 0, refb = p.count( );
+ QValueList<PMVector> result = p;
+
+ switch( m_splineType )
+ {
+ case LinearSpline:
+ break;
+ case QuadraticSpline:
+ ++refa;
+ break;
+ case CubicSpline:
+ ++refa;
+ --refb;
+ break;
+ case BezierSpline:
+ refb = refb / 3 * 4;
+ break;
+ }
+ QValueList<PMVector>::Iterator it1, it2, it3;
+ if( m_splineType != BezierSpline )
+ {
+ it1 = result.at( refa );
+ it2 = result.at( refb );
+ result.insert( it2, *it1 );
+ }
+ else
+ {
+ int i;
+ it1 = result.begin( );
+ for( i = 1; it1 != result.end( ); ++it1, ++i )
+ {
+ if( ( i % 3 ) == 0 )
+ {
+ it2 = it1;
+ ++it2;
+ it3 = it2;
+ if( it3 == result.end( ) )
+ it3 = result.begin( );
+ it1 = result.insert( it2, *it3 );
+ }
+ }
+ }
+ return result;
+}
diff --git a/kpovmodeler/pmprism.h b/kpovmodeler/pmprism.h
new file mode 100644
index 00000000..64511ee5
--- /dev/null
+++ b/kpovmodeler/pmprism.h
@@ -0,0 +1,224 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPRISM_H
+#define PMPRISM_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobject.h"
+#include "pmvector.h"
+#include <qptrlist.h>
+#include <qvaluelist.h>
+#include <math.h>
+
+class PMViewStructure;
+
+/**
+ * Class for povray prism objects.
+ */
+
+class PMPrism : public PMSolidObject
+{
+ typedef PMSolidObject Base;
+public:
+ /**
+ * The spline type
+ */
+ enum SplineType { LinearSpline, QuadraticSpline, CubicSpline, BezierSpline };
+ /**
+ * The sweep type
+ */
+ enum SweepType { LinearSweep, ConicSweep };
+ /**
+ * Creates an empty PMPrism
+ */
+ PMPrism( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMPrism( const PMPrism& p );
+ /**
+ * deletes the PMPrism
+ */
+ virtual ~PMPrism( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMPrism( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMPrismEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmprism" ); }
+
+ /** */
+ virtual void createMemento( );
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /** */
+ virtual void controlPoints( PMControlPointList& list );
+ /** */
+ virtual void controlPointsChanged( PMControlPointList& list );
+ /** */
+ virtual bool multipleSelectControlPoints( ) const { return true; }
+ /** */
+ virtual bool hasDisplayDetail( ) const { return true; }
+ /** */
+ virtual void addObjectActions( const PMControlPointList&,
+ QPtrList<PMObjectAction>& );
+ /** */
+ virtual void objectActionCalled( const PMObjectAction*,
+ const PMControlPointList&,
+ const QPtrList<PMVector>&,
+ const PMVector& );
+
+ /**
+ * Returns the spline points
+ */
+ QValueList< QValueList<PMVector> > points( ) const { return m_points; }
+ /**
+ * Sets the spline points
+ */
+ void setPoints( const QValueList< QValueList<PMVector> >& points );
+ /**
+ * Returns the spline type
+ */
+ SplineType splineType( ) const { return m_splineType; }
+ /**
+ * Sets the spline type
+ */
+ void setSplineType( SplineType t );
+ /**
+ * Returns the sweep type
+ */
+ SweepType sweepType( ) const { return m_sweepType; }
+ /**
+ * Sets the sweep type
+ */
+ void setSweepType( SweepType t );
+ /**
+ * Returns the sturm flag
+ */
+ bool sturm( ) const { return m_sturm; }
+ /**
+ * Sets the sturm flag
+ */
+ void setSturm( bool s );
+ /**
+ * Returns the open flag
+ */
+ bool open( ) const { return m_open; }
+ /**
+ * Sets the open flag
+ */
+ void setOpen( bool o );
+ /**
+ * Returns the height 1
+ */
+ double height1( ) const { return m_height1; }
+ /**
+ * Returns the height 2
+ */
+ double height2( ) const { return m_height2; }
+ /**
+ * Sets the height 1
+ */
+ void setHeight1( double h );
+ /**
+ * Sets the height 2
+ */
+ void setHeight2( double h );
+
+ /**
+ * Sets the number of steps around the y axis
+ */
+ static void setSSteps( int s );
+ /**
+ * Returns the number of steps around the y axis
+ */
+ static int sSteps( ) { return s_sSteps; }
+ /**
+ * Returns the points for POV-Ray serialization (contains additional points)
+ */
+ QValueList<PMVector> expandedPoints( const QValueList<PMVector>& p ) const;
+
+protected:
+ /** */
+ virtual void createViewStructure( );
+ /** */
+ virtual int viewStructureParameterKey( ) const { return s_parameterKey + globalDetailKey( ); }
+
+private:
+ /**
+ * Object action. Adds a spline point
+ */
+ void splitSegment( const PMControlPointList& cp,
+ const QPtrList<PMVector>& cpViewPosition,
+ const PMVector& clickPosition );
+ /**
+ * Object action. Removes a spline point
+ */
+ void joinSegments( const PMControlPointList& cp,
+ const QPtrList<PMVector>& cpViewPosition,
+ const PMVector& clickPosition );
+
+ void stringToValues( const QString& str );
+ QString valuesToString( ) const;
+
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMPrismMementoID { PMSplineTypeID, PMSweepTypeID, PMSturmID, PMOpenID,
+ PMHeight1ID, PMHeight2ID };
+ /**
+ * IDs for the object actions
+ */
+ enum PMPrismActionID { PMSplitSegmentID, PMJoinSegmentsID };
+ SplineType m_splineType;
+ SweepType m_sweepType;
+ QValueList< QValueList<PMVector> > m_points;
+ double m_height1, m_height2;
+ bool m_sturm;
+ bool m_open;
+
+ static int s_sSteps;
+ static int s_parameterKey;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmprismedit.cpp b/kpovmodeler/pmprismedit.cpp
new file mode 100644
index 00000000..13ac49b5
--- /dev/null
+++ b/kpovmodeler/pmprismedit.cpp
@@ -0,0 +1,696 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmprismedit.h"
+#include "pmprism.h"
+#include "pmvectoredit.h"
+#include "pmlineedits.h"
+#include "pmvectorlistedit.h"
+#include "pmpart.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qtooltip.h>
+#include <qcombobox.h>
+#include <qcheckbox.h>
+#include <qpushbutton.h>
+#include <klocale.h>
+#include <kdialog.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+
+PMPrismEdit::PMPrismEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+ m_lastSplineType = 0;
+}
+
+PMPrismEdit::~PMPrismEdit( )
+{
+}
+
+void PMPrismEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "Spline type:" ), this ) );
+ m_pSplineType = new QComboBox( false, this );
+ m_pSplineType->insertItem( i18n( "Linear Spline" ) );
+ m_pSplineType->insertItem( i18n( "Quadratic Spline" ) );
+ m_pSplineType->insertItem( i18n( "Cubic Spline" ) );
+ m_pSplineType->insertItem( i18n( "Bezier Spline" ) );
+ hl->addWidget( m_pSplineType );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "Sweep type:" ), this ) );
+ m_pSweepType = new QComboBox( false, this );
+ m_pSweepType->insertItem( i18n( "Linear Sweep" ) );
+ m_pSweepType->insertItem( i18n( "Conic Sweep" ) );
+ hl->addWidget( m_pSweepType );
+
+ connect( m_pSplineType, SIGNAL( activated( int ) ),
+ SLOT( slotTypeChanged( int ) ) );
+ connect( m_pSweepType, SIGNAL( activated( int ) ),
+ SLOT( slotSweepChanged( int ) ) );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ QGridLayout* gl = new QGridLayout( hl, 2, 2 );
+ gl->addWidget( new QLabel( i18n( "Height 1:" ), this ), 0, 0 );
+ m_pHeight1 = new PMFloatEdit( this );
+ gl->addWidget( m_pHeight1, 0, 1 );
+ connect( m_pHeight1, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+
+ gl->addWidget( new QLabel( i18n( "Height 2:" ), this ), 1, 0 );
+ m_pHeight2 = new PMFloatEdit( this );
+ gl->addWidget( m_pHeight2, 1, 1 );
+ connect( m_pHeight2, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ hl->addStretch( 1 );
+}
+
+void PMPrismEdit::createBottomWidgets( )
+{
+ m_pEditWidget = new QWidget( this );
+ topLayout( )->addWidget( m_pEditWidget );
+ m_pOpen = new QCheckBox( i18n( "type of the object", "Open" ), this );
+ topLayout( )->addWidget( m_pOpen );
+ m_pSturm = new QCheckBox( i18n( "Sturm" ), this );
+ topLayout( )->addWidget( m_pSturm );
+ connect( m_pSturm, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pOpen, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+
+ Base::createBottomWidgets( );
+}
+
+void PMPrismEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Prism" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMPrism* ) o;
+
+ switch( m_pDisplayedObject->splineType( ) )
+ {
+ case PMPrism::LinearSpline:
+ m_pSplineType->setCurrentItem( 0 );
+ break;
+ case PMPrism::QuadraticSpline:
+ m_pSplineType->setCurrentItem( 1 );
+ break;
+ case PMPrism::CubicSpline:
+ m_pSplineType->setCurrentItem( 2 );
+ break;
+ case PMPrism::BezierSpline:
+ m_pSplineType->setCurrentItem( 3 );
+ break;
+ }
+ m_pSplineType->setEnabled( !readOnly );
+ switch( m_pDisplayedObject->sweepType( ) )
+ {
+ case PMPrism::LinearSweep:
+ m_pSweepType->setCurrentItem( 0 );
+ break;
+ case PMPrism::ConicSweep:
+ m_pSweepType->setCurrentItem( 1 );
+ break;
+ }
+ m_pHeight1->setValue( m_pDisplayedObject->height1( ) );
+ m_pHeight1->setReadOnly( readOnly );
+ m_pHeight2->setValue( m_pDisplayedObject->height2( ) );
+ m_pHeight2->setReadOnly( readOnly );
+ m_pSweepType->setEnabled( !readOnly );
+ m_pSturm->setChecked( m_pDisplayedObject->sturm( ) );
+ m_pSturm->setEnabled( !readOnly );
+ m_pOpen->setChecked( m_pDisplayedObject->open( ) );
+ m_pOpen->setEnabled( !readOnly );
+ displayPoints( m_pDisplayedObject->points( ) );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMPrismEdit: Can't display object\n";
+}
+
+void PMPrismEdit::displayPoints( const QValueList< QValueList<PMVector> >& sp )
+{
+ bool readOnly = m_pDisplayedObject->isReadOnly( );
+
+ // (re)create the edit widget if necessary
+ createEdits( sp );
+
+ QValueList< QValueList<PMVector> >::ConstIterator spit = sp.begin( );
+ QPtrListIterator< PMVectorListEdit > seit( m_points );
+ QPtrListIterator< QPushButton > sbit1( m_removeButtons );
+
+ // display the points
+ for( ; ( spit != sp.end( ) ) && *seit; ++spit, ++seit, ++sbit1 )
+ {
+ ( *seit )->setVectors( *spit );
+ ( *seit )->setReadOnly( readOnly );
+ ( *sbit1 )->setEnabled( !readOnly && ( *spit ).size( ) > 3 );
+ }
+
+ QPtrListIterator< QPushButton > sbit2( m_addAboveButtons );
+ QPtrListIterator< QPushButton > sbit3( m_addBelowButtons );
+ for( ; *sbit2; ++sbit2 )
+ ( *sbit2 )->setEnabled( !readOnly );
+ for( ; *sbit3; ++sbit3 )
+ ( *sbit3 )->setEnabled( !readOnly );
+
+ QPtrListIterator<QPushButton> bit1( m_subPrismAddButtons );
+ for( ; *bit1; ++bit1 )
+ ( *bit1 )->setEnabled( !readOnly );
+ QPtrListIterator<QPushButton> bit2( m_subPrismRemoveButtons );
+ for( ; *bit2; ++bit2 )
+ ( *bit2 )->setEnabled( !readOnly && sp.size( ) > 1 );
+ updateControlPointSelection( );
+}
+
+void PMPrismEdit::createEdits( const QValueList< QValueList<PMVector> >& sp )
+{
+ int st = m_pSplineType->currentItem( );
+
+ if( sp.size( ) != m_points.count( ) )
+ {
+ deleteEdits( );
+
+ QPixmap addPixmap = SmallIcon( "pmaddpoint" );
+ QPixmap removePixmap = SmallIcon( "pmremovepoint" );
+ QPixmap addPrismPixmap = SmallIcon( "pmaddsubprism" );
+ QVBoxLayout* tvl = new QVBoxLayout( m_pEditWidget,
+ 0, KDialog::spacingHint( ) );
+ QHBoxLayout* hl = 0;
+ QVBoxLayout* vl;
+ QLabel* label = 0;
+ QPushButton* button = 0;
+ PMVectorListEdit* vle;
+ int spnr = 0;
+
+ for( spnr = 0; spnr < ( signed ) sp.size( ); spnr++ )
+ {
+ // create all edits for one sub prism
+ hl = new QHBoxLayout( tvl );
+ label = new QLabel( i18n( "Sub prism %1:" ).arg( spnr + 1 ),
+ m_pEditWidget );
+ hl->addWidget( label );
+ hl->addStretch( 1 );
+ m_labels.append( label );
+ label->show( );
+
+ button = new QPushButton( m_pEditWidget );
+ button->setPixmap( addPrismPixmap );
+ m_subPrismAddButtons.append( button );
+ connect( button, SIGNAL( clicked( ) ), SLOT( slotAddSubPrism( ) ) );
+ hl->addWidget( button );
+ button->show( );
+ QToolTip::add( button, i18n( "Add sub prism" ) );
+
+ button = new QPushButton( m_pEditWidget );
+ button->setPixmap( removePixmap );
+ m_subPrismRemoveButtons.append( button );
+ connect( button, SIGNAL( clicked( ) ), SLOT( slotRemoveSubPrism( ) ) );
+ hl->addWidget( button );
+ button->show( );
+ if( sp.size( ) < 2 )
+ button->setEnabled( false );
+ QToolTip::add( button, i18n( "Remove sub prism" ) );
+
+ hl = new QHBoxLayout( tvl );
+
+ vle = new PMVectorListEdit( "x", "z", m_pEditWidget );
+ m_points.append( vle );
+ connect( vle, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( vle, SIGNAL( selectionChanged( ) ),
+ SLOT( slotSelectionChanged( ) ) );
+ hl->addWidget( vle, 2 );
+ vle->show( );
+
+ vl = new QVBoxLayout( hl );
+
+ button = new QPushButton( m_pEditWidget );
+ button->setPixmap( SmallIcon( "pmaddpointabove" ) );
+ connect( button, SIGNAL( clicked( ) ), SLOT( slotAddPointAbove( ) ) );
+ m_addAboveButtons.append( button );
+ button->show( );
+ vl->addWidget( button );
+ button = new QPushButton( m_pEditWidget );
+ button->setPixmap( SmallIcon( "pmaddpoint" ) );
+ connect( button, SIGNAL( clicked( ) ), SLOT( slotAddPointBelow( ) ) );
+ m_addBelowButtons.append( button );
+ button->show( );
+ vl->addWidget( button );
+ button = new QPushButton( m_pEditWidget );
+ button->setPixmap( SmallIcon( "pmremovepoint" ) );
+ connect( button, SIGNAL( clicked( ) ), SLOT( slotRemovePoint( ) ) );
+ m_removeButtons.append( button );
+ button->show( );
+ vl->addWidget( button );
+
+ vl->addStretch( 1 );
+
+ tvl->addSpacing( KDialog::spacingHint( ) );
+ }
+
+ hl = new QHBoxLayout( tvl );
+ label = new QLabel( i18n( "New sub prism" ), m_pEditWidget );
+ hl->addWidget( label );
+ hl->addStretch( 1 );
+ m_labels.append( label );
+ label->show( );
+
+ button = new QPushButton( m_pEditWidget );
+ button->setPixmap( addPrismPixmap );
+ m_subPrismAddButtons.append( button );
+ connect( button, SIGNAL( clicked( ) ), SLOT( slotAddSubPrism( ) ) );
+ hl->addWidget( button );
+ button->show( );
+ QToolTip::add( button, i18n( "Append sub prism" ) );
+ }
+
+ QPtrListIterator< PMVectorListEdit > vlit( m_points );
+ QValueList< QValueList< PMVector > >::ConstIterator spit;
+ PMVectorListEdit* vle = 0;
+ bool newSize = false;
+
+ for( spit = sp.begin( ); spit != sp.end( ); ++spit, ++vlit )
+ {
+ int lines = ( *spit ).count( );
+
+ vle = *vlit;
+ if( ( vle->size( ) != lines ) /*|| ( st != m_lastSplineType )*/ )
+ {
+ newSize = true;
+ vle->setSize( lines );
+ }
+ }
+ if( newSize )
+ {
+ m_pEditWidget->updateGeometry( );
+ emit sizeChanged( );
+ }
+
+ m_lastSplineType = st;
+}
+
+void PMPrismEdit::deleteEdits( )
+{
+ m_labels.setAutoDelete( true );
+ m_labels.clear( );
+ m_labels.setAutoDelete( false );
+ m_subPrismAddButtons.setAutoDelete( true );
+ m_subPrismAddButtons.clear( );
+ m_subPrismAddButtons.setAutoDelete( false );
+ m_subPrismRemoveButtons.setAutoDelete( true );
+ m_subPrismRemoveButtons.clear( );
+ m_subPrismRemoveButtons.setAutoDelete( false );
+ m_addAboveButtons.setAutoDelete( true );
+ m_addAboveButtons.clear( );
+ m_addAboveButtons.setAutoDelete( false );
+ m_addBelowButtons.setAutoDelete( true );
+ m_addBelowButtons.clear( );
+ m_addBelowButtons.setAutoDelete( false );
+ m_removeButtons.setAutoDelete( true );
+ m_removeButtons.clear( );
+ m_removeButtons.setAutoDelete( false );
+ m_points.setAutoDelete( true );
+ m_points.clear( );
+ m_points.setAutoDelete( false );
+
+ if( m_pEditWidget->layout( ) )
+ delete m_pEditWidget->layout( );
+}
+
+QValueList< QValueList<PMVector> > PMPrismEdit::splinePoints( )
+{
+ QPtrListIterator< PMVectorListEdit > it( m_points );
+ QValueList< QValueList<PMVector> > values;
+
+ for( ; it.current( ); ++it )
+ values.append( ( *it )->vectors( ) );
+
+ return values;
+}
+
+void PMPrismEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ m_pDisplayedObject->setPoints( splinePoints( ) );
+
+ switch( m_pSplineType->currentItem( ) )
+ {
+ case 0:
+ m_pDisplayedObject->setSplineType( PMPrism::LinearSpline );
+ break;
+ case 1:
+ m_pDisplayedObject->setSplineType( PMPrism::QuadraticSpline );
+ break;
+ case 2:
+ m_pDisplayedObject->setSplineType( PMPrism::CubicSpline );
+ break;
+ case 3:
+ m_pDisplayedObject->setSplineType( PMPrism::BezierSpline );
+ break;
+ }
+ switch( m_pSweepType->currentItem( ) )
+ {
+ case 0:
+ m_pDisplayedObject->setSweepType( PMPrism::LinearSweep );
+ break;
+ case 1:
+ m_pDisplayedObject->setSweepType( PMPrism::ConicSweep );
+ break;
+ }
+ m_pDisplayedObject->setSturm( m_pSturm->isChecked( ) );
+ m_pDisplayedObject->setOpen( m_pOpen->isChecked( ) );
+ m_pDisplayedObject->setHeight1( m_pHeight1->value( ) );
+ m_pDisplayedObject->setHeight2( m_pHeight2->value( ) );
+ Base::saveContents( );
+ }
+}
+
+bool PMPrismEdit::isDataValid( )
+{
+ QPtrListIterator< PMVectorListEdit > it( m_points );
+ for( ; it.current( ); ++it )
+ if( !it.current( )->isDataValid( ) )
+ return false;
+
+ for( it.toFirst( ); it.current( ); ++it )
+ {
+ int np = it.current( )->size( );
+ switch( m_pSplineType->currentItem( ) )
+ {
+ case 0:
+ if( np < 3 )
+ {
+ KMessageBox::error( this, i18n( "Linear splines need at least 3 points." ),
+ i18n( "Error" ) );
+ return false;
+ }
+ break;
+ case 1:
+ if( np < 4 )
+ {
+ KMessageBox::error( this, i18n( "Quadratic splines need at least 4 points." ),
+ i18n( "Error" ) );
+ return false;
+ }
+ break;
+ case 2:
+ if( np < 5 )
+ {
+ KMessageBox::error( this, i18n( "Cubic splines need at least 5 points." ),
+ i18n( "Error" ) );
+ return false;
+ }
+ break;
+ case 3:
+ if( ( np < 3 ) || ( ( np % 3 ) != 0 ) )
+ {
+ KMessageBox::error( this, i18n( "Bezier splines need 3 points for each segment." ),
+ i18n( "Error" ) );
+ return false;
+ }
+ break;
+ }
+ }
+
+ return Base::isDataValid( );
+}
+
+void PMPrismEdit::slotTypeChanged( int )
+{
+ displayPoints( splinePoints( ) );
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+void PMPrismEdit::slotSweepChanged( int )
+{
+ emit dataChanged( );
+}
+
+void PMPrismEdit::slotAddPointAbove( )
+{
+ QPushButton* bt = ( QPushButton* ) sender( );
+ if( bt )
+ {
+ int subIndex = m_addAboveButtons.findRef( bt );
+ if( subIndex >= 0 )
+ {
+ PMVectorListEdit* ed = m_points.at( subIndex );
+ int index = ed->currentRow( );
+ if( index >= 0 && index < ed->size( ) )
+ {
+ QValueList<PMVector> points = ed->vectors( );
+ QValueListIterator<PMVector> it = points.at( index );
+
+ PMVector newPoint = *it;
+ if( index != 0 )
+ {
+ --it;
+ newPoint = ( newPoint + *it ) / 2;
+ ++it;
+ }
+ points.insert( it, newPoint );
+
+ ed->setSize( points.size( ) );
+ ed->setVectors( points );
+ if( points.size( ) > 3 )
+ m_removeButtons.at( subIndex )->setEnabled( true );
+
+ emit dataChanged( );
+ emit sizeChanged( );
+ }
+ }
+ }
+}
+
+void PMPrismEdit::slotAddPointBelow( )
+{
+ QPushButton* bt = ( QPushButton* ) sender( );
+ if( bt )
+ {
+ int subIndex = m_addBelowButtons.findRef( bt );
+ if( subIndex >= 0 )
+ {
+ PMVectorListEdit* ed = m_points.at( subIndex );
+ int index = ed->currentRow( );
+ if( index >= 0 && index < ed->size( ) )
+ {
+ QValueList<PMVector> points = ed->vectors( );
+ QValueListIterator<PMVector> it = points.at( index );
+
+ PMVector newPoint = *it;
+ ++it;
+
+ if( it != points.end( ) )
+ newPoint = ( newPoint + *it ) / 2;
+
+ points.insert( it, newPoint );
+
+ ed->setSize( points.size( ) );
+ ed->setVectors( points );
+ ed->setCurrentCell( index + 1, ed->currentColumn( ) );
+ if( points.size( ) > 3 )
+ m_removeButtons.at( subIndex )->setEnabled( true );
+
+ emit dataChanged( );
+ emit sizeChanged( );
+ }
+ }
+ }
+}
+
+void PMPrismEdit::slotRemovePoint( )
+{
+ QPushButton* bt = ( QPushButton* ) sender( );
+ if( bt )
+ {
+ int subIndex = m_removeButtons.findRef( bt );
+ if( subIndex >= 0 )
+ {
+ PMVectorListEdit* ed = m_points.at( subIndex );
+ int index = ed->currentRow( );
+ if( index >= 0 && index < ed->size( ) )
+ {
+ QValueList<PMVector> points = ed->vectors( );
+ QValueListIterator<PMVector> it = points.at( index );
+
+ points.remove( it );
+
+ ed->setSize( points.size( ) );
+ ed->setVectors( points );
+ if( points.size( ) <= 3 )
+ m_removeButtons.at( subIndex )->setEnabled( false );
+
+ emit dataChanged( );
+ emit sizeChanged( );
+ }
+ }
+ }
+}
+
+void PMPrismEdit::slotAddSubPrism( )
+{
+ if( m_pSplineType->currentItem( ) == 3 )
+ {
+ KMessageBox::information( this, i18n( "Sub prisms do not work with "
+ "bezier splines in POV-Ray 3.1." ),
+ i18n( "Warning" ), "subPrismWithBezierSplines" );
+ }
+
+ QPushButton* button = ( QPushButton* ) sender( );
+ if( button )
+ {
+ int index = m_subPrismAddButtons.findRef( button );
+ if( index >= 0 )
+ {
+ QValueList< QValueList<PMVector> > points = splinePoints( );
+ QValueList< QValueList<PMVector> >::Iterator it = points.at( index );
+ QValueList<PMVector> newSubPrism;
+
+ if( it != points.begin( ) )
+ {
+ --it;
+ newSubPrism = *it;
+ ++it;
+
+ // find middle point
+ PMVector mid( 2 );
+ int num = 0;
+ QValueList<PMVector>::Iterator pit = newSubPrism.begin( );
+ for( ; pit != newSubPrism.end( ); ++pit, ++num )
+ mid += *pit;
+ if( num > 0 )
+ mid /= num;
+ for( pit = newSubPrism.begin( ); pit != newSubPrism.end( ); ++pit )
+ *pit = ( *pit - mid ) * 0.8 + mid;
+ }
+ else
+ newSubPrism = *it;
+
+ points.insert( it, newSubPrism );
+ displayPoints( points );
+ emit dataChanged( );
+ emit sizeChanged( );
+ }
+ }
+}
+
+void PMPrismEdit::slotRemoveSubPrism( )
+{
+ QPushButton* button = ( QPushButton* ) sender( );
+ if( button )
+ {
+ int index = m_subPrismRemoveButtons.findRef( button );
+ if( index >= 0 )
+ {
+ QValueList< QValueList<PMVector> > points = splinePoints( );
+ QValueList< QValueList<PMVector> >::Iterator it = points.at( index );
+
+ if( points.count( ) > 1 )
+ {
+ points.remove( it );
+ displayPoints( points );
+ emit dataChanged( );
+ emit sizeChanged( );
+ }
+ }
+ }
+}
+
+void PMPrismEdit::slotSelectionChanged( )
+{
+ PMVectorListEdit* edit = ( PMVectorListEdit* ) sender( );
+ if( edit )
+ {
+ QValueList< QValueList< PMVector > > points = m_pDisplayedObject->points( );
+
+ if( m_points.count( ) == points.size( ) )
+ {
+ int i;
+ bool changed = false;
+ QValueList< QValueList< PMVector > >::Iterator spit;
+ PMControlPointList cp = part( )->activeControlPoints( );
+ PMControlPointListIterator it( cp ); ++it; ++it;
+ QPtrListIterator<PMVectorListEdit> edit( m_points );
+
+ for( spit = points.begin( ); spit != points.end( ) && it.current( );
+ ++spit, ++edit )
+ {
+ int np = ( *spit ).size( );
+
+ if( ( *edit )->size( ) == np )
+ {
+ for( i = 0; i < np && it.current( ); i++, ++it )
+ ( *it )->setSelected( ( *edit )->isSelected( i ) );
+ changed = true;
+ }
+ else
+ for( i = 0; i < np; i++ )
+ ++it;
+ }
+ if( changed )
+ emit controlPointSelectionChanged( );
+ }
+ }
+}
+
+void PMPrismEdit::updateControlPointSelection( )
+{
+ QValueList< QValueList< PMVector > > points = m_pDisplayedObject->points( );
+
+ if( m_points.count( ) == points.size( ) )
+ {
+ QValueList< QValueList< PMVector > >::Iterator spit;
+ PMControlPointList cp = part( )->activeControlPoints( );
+ PMControlPointListIterator it( cp ); ++it; ++it;
+ QPtrListIterator<PMVectorListEdit> edit( m_points );
+
+ for( spit = points.begin( ); spit != points.end( ) && it.current( );
+ ++spit, ++edit )
+ {
+ PMVectorListEdit* vl = *edit;
+ int np = ( *spit ).size( );
+ int i;
+
+ if( vl->size( ) == np )
+ {
+ vl->blockSelectionUpdates( true );
+ bool sb = vl->signalsBlocked( );
+ vl->blockSignals( true );
+
+ vl->clearSelection( );
+ for( i = 0; i < np && it.current( ); i++, ++it )
+ if( ( *it )->selected( ) )
+ vl->select( i );
+
+ vl->blockSignals( sb );
+ vl->blockSelectionUpdates( false );
+ }
+ else
+ for( i = 0; i < np; i++ )
+ ++it;
+ }
+ }
+}
+
+#include "pmprismedit.moc"
diff --git a/kpovmodeler/pmprismedit.h b/kpovmodeler/pmprismedit.h
new file mode 100644
index 00000000..75a65dbd
--- /dev/null
+++ b/kpovmodeler/pmprismedit.h
@@ -0,0 +1,122 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPRISMEDIT_H
+#define PMPRISMEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobjectedit.h"
+#include "pmvectoredit.h"
+#include <qptrlist.h>
+#include <qvaluelist.h>
+
+
+class PMPrism;
+class PMFloatEdit;
+class PMVectorListEdit;
+class QVBoxLayout;
+class QComboBox;
+class QCheckBox;
+class QPushButton;
+class QLabel;
+
+/**
+ * Dialog edit class for @ref PMPrism
+ */
+class PMPrismEdit : public PMSolidObjectEdit
+{
+ Q_OBJECT
+ typedef PMSolidObjectEdit Base;
+public:
+ /**
+ * Creates a PMPrismEdit with parent and name
+ */
+ PMPrismEdit( QWidget* parent, const char* name = 0 );
+ /**
+ * Destructor
+ */
+ virtual ~PMPrismEdit( );
+ /** */
+ virtual void displayObject( PMObject* o );
+ /** */
+ void updateControlPointSelection( );
+
+ /** */
+ virtual bool isDataValid( );
+
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void createBottomWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ /**
+ * Displays the spline points
+ */
+ void displayPoints( const QValueList< QValueList<PMVector> >& list );
+ /**
+ * Returns the spline points from the vector edits
+ */
+ QValueList< QValueList<PMVector> > splinePoints( );
+ /**
+ * Deletes the spline point edits
+ */
+ void deleteEdits( );
+ /**
+ * Creates the edits for the points
+ */
+ void createEdits( const QValueList< QValueList<PMVector> >& points );
+
+protected slots:
+ void slotTypeChanged( int );
+ void slotSweepChanged( int );
+ void slotAddSubPrism( );
+ void slotRemoveSubPrism( );
+ void slotAddPointAbove( );
+ void slotAddPointBelow( );
+ void slotRemovePoint( );
+ void slotSelectionChanged( );
+
+private:
+ PMPrism* m_pDisplayedObject;
+ QPtrList< QLabel > m_labels;
+ QPtrList< QPushButton > m_subPrismAddButtons;
+ QPtrList< QPushButton > m_subPrismRemoveButtons;
+ QPtrList< QPushButton > m_addAboveButtons;
+ QPtrList< QPushButton > m_addBelowButtons;
+ QPtrList< QPushButton > m_removeButtons;
+ QPtrList< PMVectorListEdit> m_points;
+ QWidget* m_pEditWidget;
+ QComboBox* m_pSplineType;
+ QComboBox* m_pSweepType;
+ QCheckBox* m_pSturm;
+ QCheckBox* m_pOpen;
+ PMFloatEdit* m_pHeight1;
+ PMFloatEdit* m_pHeight2;
+ int m_lastSplineType;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmprismmemento.cpp b/kpovmodeler/pmprismmemento.cpp
new file mode 100644
index 00000000..0f50449d
--- /dev/null
+++ b/kpovmodeler/pmprismmemento.cpp
@@ -0,0 +1,55 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmprismmemento.h"
+
+PMPrismMemento::PMPrismMemento( PMObject* originator )
+ : PMMemento( originator )
+{
+ m_bPrismPointsSaved = false;
+}
+
+PMPrismMemento::~PMPrismMemento( )
+{
+}
+
+void PMPrismMemento::setPrismPoints( const QValueList< QValueList<PMVector> >& v )
+{
+ if( !m_bPrismPointsSaved )
+ {
+ // Direct assignment does not work with Qt 2.3.x
+ // The list will be changed later in a graphical
+ // change because QValueList::detach( ) is called
+ // too late!
+ // Copy the list by hand.
+
+ QValueList< QValueList< PMVector > >::ConstIterator sit = v.begin( );
+ for( ; sit != v.end( ); ++sit )
+ {
+ QValueList<PMVector> list;
+ QValueList<PMVector>::ConstIterator it = ( *sit ).begin( );
+ for( ; it != ( *sit ).end( ); ++it )
+ list.append( *it );
+ m_prismPoints.append( list );
+ }
+
+ m_bPrismPointsSaved = true;
+ addChange( PMCData );
+ }
+}
+
+
diff --git a/kpovmodeler/pmprismmemento.h b/kpovmodeler/pmprismmemento.h
new file mode 100644
index 00000000..a45f7fef
--- /dev/null
+++ b/kpovmodeler/pmprismmemento.h
@@ -0,0 +1,71 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPRISMMEMENTO_H
+#define PMPRISMMEMENTO_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmmemento.h"
+#include "pmvector.h"
+#include <qvaluelist.h>
+
+
+/**
+ * Memento for @ref PMPrism
+ */
+class PMPrismMemento : public PMMemento
+{
+public:
+ /**
+ * Creates a memento for the object originator
+ */
+ PMPrismMemento( PMObject* originator );
+ /**
+ * Deletes the memento
+ */
+ virtual ~PMPrismMemento( );
+
+ /**
+ * Saves the prism points
+ */
+ void setPrismPoints( const QValueList< QValueList<PMVector> >& v );
+ /**
+ * Returns the prism points
+ */
+ QValueList< QValueList<PMVector> > prismPoints( ) const
+ {
+ return m_prismPoints;
+ }
+ /**
+ * Returns true if the prism points were saved
+ */
+ bool prismPointsSaved( ) const { return m_bPrismPointsSaved; }
+
+private:
+ /**
+ * The stored points
+ */
+ QValueList< QValueList<PMVector> > m_prismPoints;
+ bool m_bPrismPointsSaved;
+};
+
+#endif
diff --git a/kpovmodeler/pmprojectedthrough.cpp b/kpovmodeler/pmprojectedthrough.cpp
new file mode 100644
index 00000000..46ecc51c
--- /dev/null
+++ b/kpovmodeler/pmprojectedthrough.cpp
@@ -0,0 +1,92 @@
+/*
+**************************************************************************
+ description
+ -------------------
+ and : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#include "pmprojectedthrough.h"
+
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pmnamedobjectedit.h"
+
+#include <klocale.h>
+
+PMMetaObject* PMProjectedThrough::s_pMetaObject = 0;
+PMObject* createNewProjectedThrough( PMPart* part )
+{
+ return new PMProjectedThrough( part );
+}
+
+PMProjectedThrough::PMProjectedThrough( PMPart* part )
+ : Base( part )
+{
+}
+
+PMProjectedThrough::PMProjectedThrough( const PMProjectedThrough& l )
+ : Base( l )
+{
+}
+
+PMProjectedThrough::~PMProjectedThrough( )
+{
+}
+
+
+QString PMProjectedThrough::description( ) const
+{
+ return i18n( "projected through" );
+}
+
+PMMetaObject* PMProjectedThrough::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "ProjectedThrough", Base::metaObject( ),
+ createNewProjectedThrough );
+ // no properties
+ }
+ return s_pMetaObject;
+}
+
+void PMProjectedThrough::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMProjectedThrough::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ Base::serialize( e, doc );
+}
+
+void PMProjectedThrough::readAttributes( const PMXMLHelper& h )
+{
+ Base::readAttributes( h );
+}
+
+PMDialogEditBase* PMProjectedThrough::editWidget( QWidget* parent ) const
+{
+ return new PMNamedObjectEdit( parent );
+}
+
+void PMProjectedThrough::restoreMemento( PMMemento* s )
+{
+ Base::restoreMemento( s );
+}
+
diff --git a/kpovmodeler/pmprojectedthrough.h b/kpovmodeler/pmprojectedthrough.h
new file mode 100644
index 00000000..66b2a7bd
--- /dev/null
+++ b/kpovmodeler/pmprojectedthrough.h
@@ -0,0 +1,82 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ -------------------
+ and : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPROJECTEDTHROUGH_H
+#define PMPROJECTEDTHROUGH_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmnamedobject.h"
+
+/**
+ * Class for povray projected_through statements.
+ */
+class PMProjectedThrough : public PMNamedObject
+{
+ typedef PMNamedObject Base;
+
+public:
+ /**
+ * Constructor
+ */
+ PMProjectedThrough( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMProjectedThrough( const PMProjectedThrough& l );
+ /**
+ * Deletes the PMProjectedThrough
+ */
+ virtual ~PMProjectedThrough( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMProjectedThrough( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMProjectedThroughEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmprojectedthrough" ); }
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+
+private:
+ static PMMetaObject* s_pMetaObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmprototypemanager.cpp b/kpovmodeler/pmprototypemanager.cpp
new file mode 100644
index 00000000..f458e248
--- /dev/null
+++ b/kpovmodeler/pmprototypemanager.cpp
@@ -0,0 +1,243 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmprototypemanager.h"
+#include "pmallobjects.h"
+#include <klocale.h>
+
+PMPrototypeManager::PMPrototypeManager( PMPart* part )
+ : m_metaDict( 43 )
+{
+ m_pPart = part;
+ addPrototype( new PMScene( part ) );
+ addPrototype( new PMGlobalSettings( part ) );
+ addPrototype( new PMBox( part ) );
+ addPrototype( new PMSphere( part ) );
+ addPrototype( new PMCylinder( part ) );
+ addPrototype( new PMCone( part ) );
+ addPrototype( new PMTorus( part ) );
+ addPrototype( new PMLathe( part ) );
+ addPrototype( new PMPrism( part ) );
+
+ addPrototype( new PMSurfaceOfRevolution( part ) );
+ addPrototype( new PMSuperquadricEllipsoid( part ) );
+ addPrototype( new PMHeightField( part ) );
+ addPrototype( new PMText( part ) );
+ addPrototype( new PMJuliaFractal( part ) );
+
+ addPrototype( new PMBlob( part ) );
+ addPrototype( new PMBlobSphere( part ) );
+ addPrototype( new PMBlobCylinder( part ) );
+
+ addPrototype( new PMPlane( part ) );
+ addPrototype( new PMPolynom( part ) );
+
+ addPrototype( new PMCSG( part ) );
+ addPrototype( new PMDeclare( part ) );
+ addPrototype( new PMObjectLink( part ) );
+
+ addPrototype( new PMDisc( part ) );
+ addPrototype( new PMBicubicPatch( part ) );
+ addPrototype( new PMTriangle( part ) );
+
+ addPrototype( new PMBoundedBy( part ) );
+ addPrototype( new PMClippedBy( part ) );
+
+ addPrototype( new PMTranslate( part ) );
+ addPrototype( new PMScale( part ) );
+ addPrototype( new PMRotate( part ) );
+ addPrototype( new PMPovrayMatrix( part ) );
+ addPrototype( new PMComment( part ) );
+ addPrototype( new PMRaw( part ) );
+ addPrototype( new PMCamera( part ) );
+ addPrototype( new PMLight( part ) );
+ addPrototype( new PMLooksLike( part ) );
+ addPrototype( new PMProjectedThrough( part ) );
+
+ addPrototype( new PMTexture( part ) );
+ addPrototype( new PMPigment( part ) );
+ addPrototype( new PMSolidColor( part ) );
+ addPrototype( new PMNormal( part ) );
+ addPrototype( new PMFinish( part ) );
+ addPrototype( new PMPattern( part ) );
+ addPrototype( new PMBlendMapModifiers( part ) );
+ addPrototype( new PMImageMap( part ) );
+ addPrototype( new PMTextureMap( part ) );
+ addPrototype( new PMColorMap( part ) );
+ addPrototype( new PMPigmentMap( part ) );
+ addPrototype( new PMNormalMap( part ) );
+ addPrototype( new PMSlopeMap( part ) );
+ addPrototype( new PMDensityMap( part ) );
+ addPrototype( new PMMaterialMap( part ) );
+ addPrototype( new PMBumpMap( part ) );
+ addPrototype( new PMTextureList( part ) );
+ addPrototype( new PMColorList( part ) );
+ addPrototype( new PMPigmentList( part ) );
+ addPrototype( new PMNormalList( part ) );
+ addPrototype( new PMDensityList( part ) );
+ addPrototype( new PMWarp( part ) );
+ addPrototype( new PMQuickColor( part ) );
+ addPrototype( new PMSlope( part ) );
+ addPrototype( new PMSkySphere( part ) );
+ addPrototype( new PMRainbow( part ) );
+ addPrototype( new PMFog( part ) );
+ addPrototype( new PMInterior( part ) );
+ addPrototype( new PMMedia( part ) );
+ addPrototype( new PMMaterial( part ) );
+ addPrototype( new PMDensity( part ) );
+
+ // POV-Ray 3.5 objects
+ addPrototype( new PMIsoSurface( part ) );
+ addPrototype( new PMRadiosity( part ) );
+ addPrototype( new PMGlobalPhotons( part ) );
+ addPrototype( new PMPhotons( part ) );
+ addPrototype( new PMLightGroup( part ) );
+ addPrototype( new PMInteriorTexture( part ) );
+ addPrototype( new PMSphereSweep( part ) );
+ addPrototype( new PMMesh( part ) );
+
+ addDeclarationType( "GraphicalObject", i18n( "object declaration" ), "pmobjectdeclare" );
+ addDeclarationType( "Light", i18n( "object declaration" ), "pmobjectdeclare" );
+ addDeclarationType( "Texture", i18n( "texture declaration" ), "pmtexturedeclare" );
+ addDeclarationType( "Pigment", i18n( "pigment declaration" ), "pmpigmentdeclare" );
+ addDeclarationType( "Normal", i18n( "normal declaration" ), "pmnormaldeclare" );
+ addDeclarationType( "Finish", i18n( "finish declaration" ), "pmfinishdeclare" );
+ addDeclarationType( "TextureMap", i18n( "texture map declaration" ), "pmtexturemapdeclare" );
+ addDeclarationType( "PigmentMap", i18n( "pigment map declaration" ), "pmpigmentmapdeclare" );
+ addDeclarationType( "ColorMap", i18n( "color map declaration" ), "pmcolormapdeclare" );
+ addDeclarationType( "NormalMap", i18n( "normal map declaration" ), "pmnormaldeclare" );
+ addDeclarationType( "SlopeMap", i18n( "slope map declaration" ), "pmslopemapdeclare" );
+ addDeclarationType( "DensityMap", i18n( "density map declaration" ), "pmdensitydeclare" );
+ addDeclarationType( "Interior", i18n( "interior declaration" ), "pminteriordeclare" );
+ addDeclarationType( "Media", i18n( "media declaration" ), "pmmediadeclare" );
+ addDeclarationType( "SkySphere", i18n( "sky sphere declaration" ), "pmskyspheredeclare" );
+ addDeclarationType( "Rainbow", i18n( "rainbow declaration" ), "pmrainbowdeclare" );
+ addDeclarationType( "Fog", i18n( "fog declaration" ), "pmfogdeclare" );
+ addDeclarationType( "Material", i18n( "material declaration" ), "pmmaterialdeclare" );
+ addDeclarationType( "Density", i18n( "density declaration" ), "pmdensitydeclare" );
+ addDeclarationType( "InteriorTexture", i18n( "texture declaration" ), "pminteriortexturedeclare" );
+}
+
+PMPrototypeManager::~PMPrototypeManager( )
+{
+ /*
+ PMObjectListIterator it( m_prototypes );
+ for( ; it.current( ); ++it )
+ it.current( )->cleanUp( );
+ */
+}
+
+void PMPrototypeManager::addPrototype( PMObject* obj )
+{
+ if( !obj )
+ return;
+
+ PMMetaObject* metaObject = obj->metaObject( );
+ PMMetaObject* m2 = m_metaDict.find( metaObject->className( ) );
+ if( m2 )
+ {
+ kdError( PMArea ) << "PMPrototypeManager: Class '"
+ << metaObject->className( )
+ << "' already registered." << endl;
+ }
+ else
+ {
+ if( metaObject->isAbstract( ) )
+ kdError( PMArea ) << "PMPrototypeManager: The meta object for the prototype "
+ << metaObject->className( )
+ << " doesn't have a factory method" << endl;
+
+ m_prototypes.append( metaObject );
+ m_lowerCaseDict[metaObject->className( ).lower( )] = metaObject->className( );
+
+ // insert the meta object and all super classes into the hash table
+ while( metaObject )
+ {
+ if( m_metaDict.find( metaObject->className( ) ) )
+ metaObject = 0;
+ else
+ {
+ m_metaDict.insert( metaObject->className( ), metaObject );
+ metaObject = metaObject->superClass( );
+ }
+ }
+ }
+ delete obj;
+}
+
+void PMPrototypeManager::addDeclarationType( const QString& className,
+ const QString& description,
+ const QString& pixmap )
+{
+ PMMetaObject* m = metaObject( className );
+ if( !m )
+ kdError( PMArea ) << "PMPrototypeManager::addDeclarationType: Unknown class " << className << endl;
+ else
+ m_declareDescriptions.push_back( PMDeclareDescription( m, description, pixmap ) );
+}
+
+QPtrListIterator<PMMetaObject> PMPrototypeManager::prototypeIterator( ) const
+{
+ return QPtrListIterator<PMMetaObject>( m_prototypes );
+}
+
+const QValueList<PMDeclareDescription>& PMPrototypeManager::declarationTypes( ) const
+{
+ return m_declareDescriptions;
+}
+
+PMObject* PMPrototypeManager::newObject( const QString& name ) const
+{
+ if( name.isEmpty( ) )
+ return 0;
+
+ PMMetaObject* meta = m_metaDict.find( name );
+ if( !meta )
+ return 0;
+ return meta->newObject( m_pPart );
+}
+
+PMMetaObject* PMPrototypeManager::metaObject( const QString& name ) const
+{
+ if( name.isNull( ) )
+ return 0;
+ return m_metaDict.find( name );
+}
+
+bool PMPrototypeManager::isA( const QString& className,
+ const QString& baseClass ) const
+{
+ return isA( metaObject( className ), baseClass );
+}
+
+bool PMPrototypeManager::isA( PMMetaObject* c,
+ const QString& baseClass ) const
+{
+ PMMetaObject* bc = metaObject( baseClass );
+ while( c && c != bc )
+ c = c->superClass( );
+ return( c && ( c == bc ) );
+}
+
+QString PMPrototypeManager::className( const QString& lowercase ) const
+{
+ QMap<QString, QString>::const_iterator it = m_lowerCaseDict.find( lowercase );
+ if( it != m_lowerCaseDict.end( ) )
+ return *it;
+ return QString::null;
+}
diff --git a/kpovmodeler/pmprototypemanager.h b/kpovmodeler/pmprototypemanager.h
new file mode 100644
index 00000000..025b8213
--- /dev/null
+++ b/kpovmodeler/pmprototypemanager.h
@@ -0,0 +1,149 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMPTMANAGER_H
+#define PMPTMANAGER_H
+
+#include "pmobject.h"
+#include <qdict.h>
+#include <qmap.h>
+#include <qvaluelist.h>
+
+class PMPart;
+
+/**
+ * Description class for declarations types, used by @ref PMPrototypeManager
+ * and @ref PMDeclare
+ */
+class PMDeclareDescription
+{
+public:
+ PMDeclareDescription( ) { }
+ PMDeclareDescription( const PMDeclareDescription& d )
+ {
+ type = d.type;
+ description = d.description;
+ pixmap = d.pixmap;
+ }
+ PMDeclareDescription( PMMetaObject* t, const QString& d, const QString& p )
+ {
+ type = t;
+ description = d;
+ pixmap = p;
+ }
+ PMDeclareDescription& operator=( const PMDeclareDescription& d )
+ {
+ type = d.type;
+ description = d.description;
+ pixmap = d.pixmap;
+ return *this;
+ }
+ PMMetaObject* type;
+ QString description;
+ QString pixmap;
+};
+
+/**
+ * Prototype manager for @ref PMObject.
+ *
+ * This class stores class and inheritance information for each
+ * available object type.
+ *
+ * Each @ref PMPart class holds one instance of this class. The
+ * available objects depend on the loaded plugins.
+ *
+ * Patterns: Prototype
+ */
+class PMPrototypeManager
+{
+public:
+ /**
+ * Creates a prototype manager for the part.
+ */
+ PMPrototypeManager( PMPart* part );
+ /**
+ * Deletes the prototype manager
+ */
+ ~PMPrototypeManager( );
+ /**
+ * Adds the object to the list of prototypes. The prototype becomes
+ * the owner of the object and will be delete immediately by the
+ * prototype manager.
+ */
+ void addPrototype( PMObject* obj );
+ /**
+ * Adds a declaration type. Needed information is the class type,
+ * the @ref description( ) and the @ref pixmap( )
+ */
+ void addDeclarationType( const QString& className,
+ const QString& description,
+ const QString& pixmap );
+ /**
+ * Returns an iterator to the list of available objects
+ */
+ QPtrListIterator<PMMetaObject> prototypeIterator( ) const;
+ /**
+ * Returns an iterator to the list of available declaration types
+ */
+ const QValueList<PMDeclareDescription>& declarationTypes( ) const;
+ /**
+ * Returns a new PMObject by class name
+ */
+ PMObject* newObject( const QString& name ) const;
+ /**
+ * Returns the meta object by class name or 0 if this class does
+ * not exist.
+ * @see PMMetaObject
+ */
+ PMMetaObject* metaObject( const QString& name ) const;
+ /**
+ * Returns true if the class exists
+ */
+ bool existsClass( const QString& name ) const
+ {
+ return metaObject( name );
+ }
+ /**
+ * Returns true if the second class is a base class for
+ * the first class
+ */
+ bool isA( const QString& className, const QString& baseClassName ) const;
+ /**
+ * Returns true if the second class is a base class for
+ * the first class
+ */
+ bool isA( PMMetaObject* c, const QString& baseClassName ) const;
+ /**
+ * Returns the real class if only the lower case version is know.
+ * Used by the xml parser
+ */
+ QString className( const QString& lowercase ) const;
+ /**
+ * Returns a pointer to the part
+ */
+ PMPart* part( ) const { return m_pPart; }
+
+private:
+ QPtrList<PMMetaObject> m_prototypes;
+ QDict<PMMetaObject> m_metaDict;
+ QMap<QString, QString> m_lowerCaseDict;
+ QValueList<PMDeclareDescription> m_declareDescriptions;
+ PMPart* m_pPart;
+};
+#endif
diff --git a/kpovmodeler/pmquickcolor.cpp b/kpovmodeler/pmquickcolor.cpp
new file mode 100644
index 00000000..fcf34e85
--- /dev/null
+++ b/kpovmodeler/pmquickcolor.cpp
@@ -0,0 +1,132 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Leonardo Skorianez
+ email : lsk@if.ufrj.br
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmquickcolor.h"
+
+#include "pmxmlhelper.h"
+#include "pmquickcoloredit.h"
+#include "pmmemento.h"
+
+#include <klocale.h>
+
+const PMColor colorDefault = PMColor( 1.0, 1.0, 1.0, 0.0, 0.0 );
+
+PMDefinePropertyClass( PMQuickColor, PMQuickColorProperty );
+
+PMMetaObject* PMQuickColor::s_pMetaObject = 0;
+PMObject* createNewQuickColor( PMPart* part )
+{
+ return new PMQuickColor( part );
+}
+
+PMQuickColor::PMQuickColor( PMPart* part )
+ : Base( part )
+{
+ m_color = colorDefault;
+}
+
+PMQuickColor::PMQuickColor( const PMQuickColor& c )
+ : Base( c )
+{
+ m_color = c.m_color;
+}
+
+PMQuickColor::~PMQuickColor( )
+{
+}
+
+QString PMQuickColor::description( ) const
+{
+ return i18n( "quick color" );
+}
+
+void PMQuickColor::serialize( QDomElement& e, QDomDocument& /*doc*/ ) const
+{
+ e.setAttribute( "quickcolor", m_color.serializeXML( ) );
+}
+
+void PMQuickColor::readAttributes( const PMXMLHelper& h )
+{
+ m_color = h.colorAttribute( "quickcolor", colorDefault );
+}
+
+PMMetaObject* PMQuickColor::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "QuickColor", Base::metaObject( ),
+ createNewQuickColor );
+ s_pMetaObject->addProperty(
+ new PMQuickColorProperty( "color", &PMQuickColor::setColor, &PMQuickColor::color ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMQuickColor::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMQuickColor::setColor( const PMColor& c )
+{
+ if( c != m_color )
+ {
+ if( m_pMemento )
+ {
+ m_pMemento->addData( s_pMetaObject, PMColorID, m_color );
+ m_pMemento->setViewStructureChanged( );
+ }
+ m_color = c;
+ }
+}
+
+PMDialogEditBase* PMQuickColor::editWidget( QWidget* parent ) const
+{
+ return new PMQuickColorEdit( parent );
+}
+
+void PMQuickColor::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMColorID:
+ setColor( data->colorData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMQuickColor::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmquickcolor.h b/kpovmodeler/pmquickcolor.h
new file mode 100644
index 00000000..a1dce42d
--- /dev/null
+++ b/kpovmodeler/pmquickcolor.h
@@ -0,0 +1,100 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Leonardo Skorianez
+ email : lsk2if.ufrj.br
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMQUICKCOLOR_H
+#define PMQUICKCOLOR_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmobject.h"
+#include "pmcolor.h"
+
+/**
+ * Class for quick colors.
+ * Tell POV-Ray what solid color to use for quick renders instead of a paterned pigment.
+ */
+
+class PMQuickColor : public PMObject
+{
+ typedef PMObject Base;
+public:
+ /**
+ * Creates a PMQuickColor
+ */
+ PMQuickColor( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMQuickColor( const PMQuickColor& c );
+ /**
+ * deletes the PMQuickColor
+ */
+ virtual ~PMQuickColor( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMQuickColor( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMQuickColorEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmquickcolor" ); }
+
+ /**
+ * Returns the color
+ */
+ PMColor color( ) const { return m_color; }
+ /**
+ * Sets the color
+ */
+ void setColor( const PMColor& c );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMQuickColorMementoID { PMColorID };
+ PMColor m_color;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmquickcoloredit.cpp b/kpovmodeler/pmquickcoloredit.cpp
new file mode 100644
index 00000000..35c21234
--- /dev/null
+++ b/kpovmodeler/pmquickcoloredit.cpp
@@ -0,0 +1,77 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Leonardo Skorianez
+ email : lsk@if.ufrj.br
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmquickcoloredit.h"
+#include "pmquickcolor.h"
+#include "pmcoloredit.h"
+#include "pmdebug.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <klocale.h>
+
+
+PMQuickColorEdit::PMQuickColorEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMQuickColorEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* layout = new QHBoxLayout( topLayout( ) );
+ m_pColorEdit = new PMColorEdit( false, this );
+ layout->addWidget( new QLabel( i18n( "Color:" ), this ), 0, AlignTop );
+ layout->addWidget( m_pColorEdit );
+
+ connect( m_pColorEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMQuickColorEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "QuickColor" ) )
+ {
+ m_pDisplayedObject = ( PMQuickColor* ) o;
+ m_pColorEdit->setColor( m_pDisplayedObject->color( ) );
+ m_pColorEdit->setReadOnly( m_pDisplayedObject->isReadOnly( ) );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMQuickColorEdit: Can't display object\n";
+}
+
+void PMQuickColorEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setColor( m_pColorEdit->color( ) );
+ }
+}
+
+bool PMQuickColorEdit::isDataValid( )
+{
+ if( !m_pColorEdit->isDataValid( ) )
+ return false;
+ return Base::isDataValid( );
+}
+
+#include "pmquickcoloredit.moc"
diff --git a/kpovmodeler/pmquickcoloredit.h b/kpovmodeler/pmquickcoloredit.h
new file mode 100644
index 00000000..78759a88
--- /dev/null
+++ b/kpovmodeler/pmquickcoloredit.h
@@ -0,0 +1,65 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Leonardo Skorianez
+ email : lsk@if.ufrj.br
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMQUICKCOLOREDIT_H
+#define PMQUICKCOLOREDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kcolordialog.h>
+
+#include "pmdialogeditbase.h"
+
+class PMQuickColor;
+class PMColorEdit;
+
+/**
+ * Dialog edit class for @ref PMQuickColor.
+ */
+class PMQuickColorEdit : public PMDialogEditBase
+{
+ Q_OBJECT
+ typedef PMDialogEditBase Base;
+public:
+ /**
+ * Creates a PMQuickColorEdit with parent and name
+ */
+ PMQuickColorEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMQuickColor* m_pDisplayedObject;
+ PMColorEdit* m_pColorEdit;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmradiosity.cpp b/kpovmodeler/pmradiosity.cpp
new file mode 100644
index 00000000..d5446b25
--- /dev/null
+++ b/kpovmodeler/pmradiosity.cpp
@@ -0,0 +1,428 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmradiosity.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pmradiosityedit.h"
+
+#include <klocale.h>
+
+const double adcBailoutDefault = 0.01;
+const double brightnessDefault = 1.0;
+const int countDefault = 35;
+const double errorBoundDefault = 1.8;
+const double grayThresholdDefault = 0.0;
+const double lowErrorFactorDefault = 0.5;
+const double maxSampleDefault = -1.0;
+const double minimumReuseDefault = 0.015;
+const int nearestCountDefault = 5;
+const double pretraceStartDefault = 0.08;
+const double pretraceEndDefault = 0.04;
+const int recursionLimitDefault = 2;
+
+PMDefinePropertyClass( PMRadiosity, PMRadiosityProperty );
+PMMetaObject* PMRadiosity::s_pMetaObject = 0;
+PMObject* createNewRadiosity( PMPart* part )
+{
+ return new PMRadiosity( part );
+}
+
+PMRadiosity::PMRadiosity( PMPart* part ) : Base( part )
+{
+ m_adcBailout = adcBailoutDefault;
+ m_alwaysSample = true;
+ m_brightness = brightnessDefault;
+ m_count = countDefault;
+ m_errorBound = errorBoundDefault;
+ m_grayThreshold = grayThresholdDefault;
+ m_lowErrorFactor = lowErrorFactorDefault;
+ m_maxSample = maxSampleDefault;
+ m_media = false;
+ m_minimumReuse = minimumReuseDefault;
+ m_nearestCount = nearestCountDefault;
+ m_normal = false;
+ m_pretraceStart = pretraceStartDefault;
+ m_pretraceEnd = pretraceEndDefault;
+ m_recursionLimit = recursionLimitDefault;
+}
+
+PMRadiosity::PMRadiosity( const PMRadiosity& r )
+ : Base( r )
+{
+ m_adcBailout = r.m_adcBailout;
+ m_alwaysSample = r.m_alwaysSample;
+ m_brightness = r.m_brightness;
+ m_count = r.m_count;
+ m_errorBound = r.m_errorBound;
+ m_grayThreshold = r.m_grayThreshold;
+ m_lowErrorFactor = r.m_lowErrorFactor;
+ m_maxSample = r.m_maxSample;
+ m_media = r.m_media;
+ m_minimumReuse = r.m_minimumReuse;
+ m_nearestCount = r.m_nearestCount;
+ m_normal = r.m_normal;
+ m_pretraceStart = r.m_pretraceStart;
+ m_pretraceEnd = r.m_pretraceEnd;
+ m_recursionLimit = r.m_recursionLimit;
+}
+
+PMRadiosity::~PMRadiosity( )
+{
+}
+
+PMMetaObject* PMRadiosity::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Radiosity", Base::metaObject( ),
+ createNewRadiosity );
+ s_pMetaObject->addProperty(
+ new PMRadiosityProperty( "adcBailout", &PMRadiosity::setAdcBailout, &PMRadiosity::adcBailout ) );
+ s_pMetaObject->addProperty(
+ new PMRadiosityProperty( "alwaysSample", &PMRadiosity::setAlwaysSample, &PMRadiosity::alwaysSample ) );
+ s_pMetaObject->addProperty(
+ new PMRadiosityProperty( "brightness", &PMRadiosity::setBrightness, &PMRadiosity::brightness ) );
+ s_pMetaObject->addProperty(
+ new PMRadiosityProperty( "count", &PMRadiosity::setCount, &PMRadiosity::count ) );
+ s_pMetaObject->addProperty(
+ new PMRadiosityProperty( "errorBound", &PMRadiosity::setErrorBound, &PMRadiosity::errorBound ) );
+ s_pMetaObject->addProperty(
+ new PMRadiosityProperty( "grayThreshold", &PMRadiosity::setGrayThreshold, &PMRadiosity::grayThreshold ) );
+ s_pMetaObject->addProperty(
+ new PMRadiosityProperty( "lowErrorFactor", &PMRadiosity::setLowErrorFactor, &PMRadiosity::lowErrorFactor ) );
+ s_pMetaObject->addProperty(
+ new PMRadiosityProperty( "maxSample", &PMRadiosity::setMaxSample, &PMRadiosity::maxSample ) );
+ s_pMetaObject->addProperty(
+ new PMRadiosityProperty( "media", &PMRadiosity::setMedia, &PMRadiosity::media ) );
+ s_pMetaObject->addProperty(
+ new PMRadiosityProperty( "minimumReuse", &PMRadiosity::setMinimumReuse, &PMRadiosity::minimumReuse ) );
+ s_pMetaObject->addProperty(
+ new PMRadiosityProperty( "nearestCount", &PMRadiosity::setNearestCount, &PMRadiosity::nearestCount ) );
+ s_pMetaObject->addProperty(
+ new PMRadiosityProperty( "normal", &PMRadiosity::setNormal, &PMRadiosity::normal ) );
+ s_pMetaObject->addProperty(
+ new PMRadiosityProperty( "pretraceStart", &PMRadiosity::setPretraceStart, &PMRadiosity::pretraceStart ) );
+ s_pMetaObject->addProperty(
+ new PMRadiosityProperty( "pretraceEnd", &PMRadiosity::setPretraceEnd, &PMRadiosity::pretraceEnd ) );
+ s_pMetaObject->addProperty(
+ new PMRadiosityProperty( "recursionLimit", &PMRadiosity::setRecursionLimit, &PMRadiosity::recursionLimit ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMRadiosity::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMRadiosity::description( ) const
+{
+ return i18n( "radiosity" );
+}
+
+void PMRadiosity::serialize( QDomElement& e, QDomDocument& ) const
+{
+ e.setAttribute( "adc_bailout", m_adcBailout );
+
+ if ( m_alwaysSample )
+ e.setAttribute( "always_sample", "1" );
+ else
+ e.setAttribute( "always_sample", "0" );
+
+ e.setAttribute( "brightness", m_brightness );
+ e.setAttribute( "count", m_count );
+ e.setAttribute( "error_bound", m_errorBound );
+ e.setAttribute( "gray_threshold", m_grayThreshold );
+ e.setAttribute( "low_error_factor", m_lowErrorFactor );
+ e.setAttribute( "max_sample", m_maxSample );
+
+ if ( m_media )
+ e.setAttribute( "media", "1" );
+ else
+ e.setAttribute( "media", "0" );
+
+ e.setAttribute( "minimum_reuse", m_minimumReuse );
+ e.setAttribute( "nearest_count", m_nearestCount );
+
+ if ( m_normal )
+ e.setAttribute( "normal", "1" );
+ else
+ e.setAttribute( "normal", "0" );
+
+ e.setAttribute( "pretrace_start", m_pretraceStart );
+ e.setAttribute( "pretrace_end", m_pretraceEnd );
+ e.setAttribute( "recursion_limit", m_recursionLimit );
+}
+
+void PMRadiosity::readAttributes( const PMXMLHelper& h )
+{
+ m_adcBailout = h.doubleAttribute( "adc_bailout", adcBailoutDefault );
+ m_alwaysSample = h.boolAttribute( "always_sample", true );
+ m_brightness = h.doubleAttribute( "brightness", brightnessDefault );
+ m_count = h.intAttribute( "count", countDefault );
+ m_errorBound = h.doubleAttribute( "error_bound", errorBoundDefault );
+ m_grayThreshold = h.doubleAttribute( "gray_threshold", grayThresholdDefault );
+ m_lowErrorFactor = h.doubleAttribute( "low_error_factor", lowErrorFactorDefault );
+ m_maxSample = h.doubleAttribute( "max_sample", maxSampleDefault );
+ m_media = h.boolAttribute( "media", false );
+ m_minimumReuse = h.doubleAttribute( "minimum_reuse", minimumReuseDefault );
+ m_nearestCount = h.intAttribute( "nearest_count", nearestCountDefault );
+ m_normal = h.boolAttribute( "normal", false );
+ m_pretraceStart = h.doubleAttribute( "pretrace_start", pretraceStartDefault );
+ m_pretraceEnd = h.doubleAttribute( "pretrace_end", pretraceEndDefault );
+ m_recursionLimit = h.intAttribute( "recursion_limit", recursionLimitDefault );
+}
+
+void PMRadiosity::setAdcBailout( double ab )
+{
+ if( ab != m_adcBailout )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAdcBailoutID, m_adcBailout );
+ m_adcBailout = ab;
+ }
+}
+
+void PMRadiosity::setAlwaysSample( bool as )
+{
+ if( as != m_alwaysSample )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAlwaysSampleID, m_alwaysSample );
+ m_alwaysSample = as;
+ }
+}
+
+void PMRadiosity::setBrightness( double b )
+{
+ if( b != m_brightness )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMBrightnessID, m_brightness );
+ m_brightness = b;
+ }
+}
+
+void PMRadiosity::setCount( int c )
+{
+ if( c != m_count )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMCountID, m_count );
+ m_count = c;
+ }
+}
+
+void PMRadiosity::setErrorBound( double eb )
+{
+ if( eb != m_errorBound )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMErrorBoundID, m_errorBound );
+ m_errorBound = eb;
+ }
+}
+
+void PMRadiosity::setGrayThreshold( double gt )
+{
+ if( gt != m_grayThreshold )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMGrayThresholdID, m_grayThreshold );
+ m_grayThreshold = gt;
+ }
+}
+
+void PMRadiosity::setLowErrorFactor( double lew )
+{
+ if( lew != m_lowErrorFactor )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMLowErrorFactorID, m_lowErrorFactor );
+ m_lowErrorFactor = lew;
+ }
+}
+
+void PMRadiosity::setMaxSample( double ms )
+{
+ if( ms != m_maxSample )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMMaxSampleID, m_maxSample );
+ m_maxSample = ms;
+ }
+}
+
+void PMRadiosity::setMedia( bool m )
+{
+ if( m != m_media )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMMediaID, m_media );
+ m_media = m;
+ }
+}
+
+void PMRadiosity::setMinimumReuse( double c )
+{
+ if( c != m_minimumReuse )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMMinimumReuseID, m_minimumReuse );
+ m_minimumReuse = c;
+ }
+}
+
+void PMRadiosity::setNearestCount( int c )
+{
+ if( c != m_nearestCount )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMNearestCountID, m_nearestCount );
+ m_nearestCount = c;
+ }
+}
+
+void PMRadiosity::setNormal( bool n )
+{
+ if( n != m_normal )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMNormalID, m_normal );
+ m_normal = n;
+ }
+}
+
+void PMRadiosity::setPretraceStart( double ps )
+{
+ if ( ps < m_pretraceEnd )
+ {
+ kdError( PMArea ) << "Pretrace Start < Pretrace End in PMRadiosity::setPretraceStart\n";
+ ps = m_pretraceEnd;
+ }
+
+ if( ps != m_pretraceStart )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMPretraceStartID, m_pretraceStart );
+ m_pretraceStart = ps;
+ }
+}
+
+void PMRadiosity::setPretraceEnd( double pe )
+{
+ if ( pe > m_pretraceStart )
+ {
+ kdError( PMArea ) << "Pretrace End > Pretrace Start in PMRadiosity::setPretraceEnd\n";
+ pe = m_pretraceStart;
+ }
+
+ if( pe != m_pretraceEnd )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMPretraceEndID, m_pretraceEnd );
+ m_pretraceEnd = pe;
+ }
+}
+
+void PMRadiosity::setRecursionLimit( int c )
+{
+ if( c != m_recursionLimit )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMRecursionLimitID, m_recursionLimit );
+ m_recursionLimit = c;
+ }
+}
+
+PMDialogEditBase* PMRadiosity::editWidget( QWidget* parent ) const
+{
+ return new PMRadiosityEdit( parent );
+}
+
+void PMRadiosity::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMAdcBailoutID:
+ setAdcBailout( data->doubleData( ) );
+ break;
+ case PMAlwaysSampleID:
+ setAlwaysSample( data->boolData( ) );
+ break;
+ case PMBrightnessID:
+ setBrightness( data->doubleData( ) );
+ break;
+ case PMCountID:
+ setCount( data->intData( ) );
+ break;
+ case PMErrorBoundID:
+ setErrorBound( data->doubleData( ) );
+ break;
+ case PMGrayThresholdID:
+ setGrayThreshold( data->doubleData( ) );
+ break;
+ case PMLowErrorFactorID:
+ setLowErrorFactor( data->doubleData( ) );
+ break;
+ case PMMaxSampleID:
+ setMaxSample( data->doubleData( ) );
+ break;
+ case PMMediaID:
+ setMedia( data->boolData( ) );
+ break;
+ case PMMinimumReuseID:
+ setMinimumReuse( data->doubleData( ) );
+ break;
+ case PMNearestCountID:
+ setNearestCount( data->intData( ) );
+ break;
+ case PMNormalID:
+ setNormal( data->boolData( ) );
+ break;
+ case PMPretraceStartID:
+ setPretraceStart( data->doubleData( ) );
+ break;
+ case PMPretraceEndID:
+ setPretraceEnd( data->doubleData( ) );
+ break;
+ case PMRecursionLimitID:
+ setRecursionLimit( data->intData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMRadiosity::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmradiosity.h b/kpovmodeler/pmradiosity.h
new file mode 100644
index 00000000..56a1cbd4
--- /dev/null
+++ b/kpovmodeler/pmradiosity.h
@@ -0,0 +1,241 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMRADIOSITY_H
+#define PMRADIOSITY_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmobject.h"
+
+/**
+ * Class for radiosity settings.
+ */
+
+class PMRadiosity : public PMObject
+{
+ typedef PMObject Base;
+public:
+ /**
+ * Creates a PMRadiosity
+ */
+ PMRadiosity( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMRadiosity( const PMRadiosity& r );
+ /**
+ * deletes the PMRadiosity
+ */
+ virtual ~PMRadiosity( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMRadiosity( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMRadiosityEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmradiosity" ); }
+
+ /**
+ * Returns the adc bailout
+ */
+ double adcBailout( ) const { return m_adcBailout; }
+ /**
+ * Sets the adc bailout
+ */
+ void setAdcBailout( double ab );
+
+ /**
+ * Returns the always sample flag
+ */
+ bool alwaysSample( ) const { return m_alwaysSample; }
+ /**
+ * Sets the always sample flag
+ */
+ void setAlwaysSample( bool as );
+
+ /**
+ * Returns brightness
+ */
+ double brightness( ) const { return m_brightness; }
+ /**
+ * Sets the brightness
+ */
+ void setBrightness( double b );
+
+ /**
+ * Returns count
+ */
+ int count( ) const { return m_count; }
+ /**
+ * Sets the count
+ */
+ void setCount( int c );
+
+ /**
+ * Returns error boundary
+ */
+ double errorBound( ) const { return m_errorBound; }
+ /**
+ * Sets the error boundary
+ */
+ void setErrorBound( double eb );
+
+ /**
+ * Returns gray threshold
+ */
+ double grayThreshold( ) const { return m_grayThreshold; }
+ /**
+ * Sets the gray threshold
+ */
+ void setGrayThreshold( double gt );
+
+ /**
+ * Returns low error factor
+ */
+ double lowErrorFactor( ) const { return m_lowErrorFactor; }
+ /**
+ * Sets the low error factor
+ */
+ void setLowErrorFactor( double lew );
+
+ /**
+ * Returns the maximum sample
+ */
+ double maxSample( ) const { return m_maxSample; }
+ /**
+ * Sets the maximum sample
+ */
+ void setMaxSample( double ms );
+
+ /**
+ * Returns the media flag
+ */
+ bool media( ) const { return m_media; }
+ /**
+ * Sets the media flag
+ */
+ void setMedia( bool m );
+
+ /**
+ * Returns minimum reuse
+ */
+ double minimumReuse( ) const { return m_minimumReuse; }
+ /**
+ * Sets the minimum reuse
+ */
+ void setMinimumReuse( double mr );
+
+ /**
+ * Returns nearest count
+ */
+ int nearestCount( ) const { return m_nearestCount; }
+ /**
+ * Sets the nearest count
+ */
+ void setNearestCount( int nc );
+
+ /**
+ * Returns the normal flag
+ */
+ bool normal( ) const { return m_normal; }
+ /**
+ * Sets the normal flag
+ */
+ void setNormal( bool n );
+
+ /**
+ * Returns the pretrace start
+ */
+ double pretraceStart( ) const { return m_pretraceStart; }
+ /**
+ * Sets the pretrace start
+ */
+ void setPretraceStart( double ps );
+
+ /**
+ * Returns the pretrace end
+ */
+ double pretraceEnd( ) const { return m_pretraceEnd; }
+ /**
+ * Sets the pretrace end
+ */
+ void setPretraceEnd( double pe );
+
+ /**
+ * Returns recursion limit
+ */
+ int recursionLimit( ) const { return m_recursionLimit; }
+ /**
+ * Sets the recursion limit
+ */
+ void setRecursionLimit( int rl );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMRadiosityMementoID { PMAdcBailoutID, PMAlwaysSampleID, PMBrightnessID,
+ PMCountID, PMErrorBoundID, PMGrayThresholdID,
+ PMLowErrorFactorID, PMMaxSampleID, PMMediaID,
+ PMMinimumReuseID, PMNearestCountID, PMNormalID,
+ PMPretraceStartID, PMPretraceEndID, PMRecursionLimitID };
+
+ double m_adcBailout;
+ bool m_alwaysSample;
+ double m_brightness;
+ int m_count;
+ double m_errorBound;
+ double m_grayThreshold;
+ double m_lowErrorFactor;
+ double m_maxSample;
+ bool m_media;
+ double m_minimumReuse;
+ int m_nearestCount;
+ bool m_normal;
+ double m_pretraceStart;
+ double m_pretraceEnd;
+ int m_recursionLimit;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmradiosityedit.cpp b/kpovmodeler/pmradiosityedit.cpp
new file mode 100644
index 00000000..1154214d
--- /dev/null
+++ b/kpovmodeler/pmradiosityedit.cpp
@@ -0,0 +1,233 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmradiosityedit.h"
+#include "pmradiosity.h"
+#include "pmlineedits.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <klocale.h>
+#include <kdialog.h>
+#include <kmessagebox.h>
+
+
+PMRadiosityEdit::PMRadiosityEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMRadiosityEdit::createTopWidgets( )
+{
+ QHBoxLayout* hl;
+ QGridLayout *gl;
+ QLabel* lbl;
+
+ Base::createTopWidgets( );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ gl = new QGridLayout( hl, 15, 2 );
+
+ lbl = new QLabel( i18n( "Adc bailout:" ), this );
+ m_pAdcBailout = new PMFloatEdit( this );
+ m_pAdcBailout->setValidation( true, 0, true, 1 );
+ gl->addWidget( lbl, 0, 0 );
+ gl->addWidget( m_pAdcBailout, 0, 1 );
+
+ m_pAlwaysSample = new QCheckBox( i18n( "Always sample" ), this );
+ gl->addMultiCellWidget( m_pAlwaysSample, 1, 1, 0, 1 );
+
+ lbl = new QLabel( i18n( "Brightness:" ), this );
+ m_pBrightness = new PMFloatEdit( this );
+ m_pBrightness->setValidation( true, 0, false, 0 );
+ gl->addWidget( lbl, 2, 0 );
+ gl->addWidget( m_pBrightness, 2, 1 );
+
+ lbl = new QLabel( i18n( "Count:" ), this );
+ m_pCount = new PMIntEdit( this );
+ m_pCount->setValidation( true, 0, true, 1600 );
+ gl->addWidget( lbl, 3, 0 );
+ gl->addWidget( m_pCount, 3, 1 );
+
+ lbl = new QLabel( i18n( "Error boundary:" ), this );
+ m_pErrorBound = new PMFloatEdit( this );
+ m_pErrorBound->setValidation( true, 0, false, 0 );
+ gl->addWidget( lbl, 4, 0 );
+ gl->addWidget( m_pErrorBound, 4, 1 );
+
+ lbl = new QLabel( i18n( "Gray threshold:" ), this );
+ m_pGrayThreshold = new PMFloatEdit( this );
+ m_pGrayThreshold->setValidation( true, 0, true, 1 );
+ gl->addWidget( lbl, 5, 0 );
+ gl->addWidget( m_pGrayThreshold, 5, 1 );
+
+ lbl = new QLabel( i18n( "Low error factor:" ), this );
+ m_pLowErrorFactor = new PMFloatEdit( this );
+ m_pLowErrorFactor->setValidation( true, 0, true, 1 );
+ gl->addWidget( lbl, 6, 0 );
+ gl->addWidget( m_pLowErrorFactor, 6, 1 );
+
+ lbl = new QLabel( i18n( "Maximum sample:" ), this );
+ m_pMaxSample = new PMFloatEdit( this );
+ m_pMaxSample->setValidation( true, -1, false, 0 );
+ gl->addWidget( lbl, 7, 0 );
+ gl->addWidget( m_pMaxSample, 7, 1 );
+
+ m_pMedia = new QCheckBox( i18n( "Media" ), this );
+ gl->addMultiCellWidget( m_pMedia, 8, 8, 0, 1 );
+
+ lbl = new QLabel( i18n( "Minimum reuse:" ), this );
+ m_pMinimumReuse = new PMFloatEdit( this );
+ m_pMinimumReuse->setValidation( true, 0, true, 1 );
+ gl->addWidget( lbl, 9, 0 );
+ gl->addWidget( m_pMinimumReuse, 9, 1 );
+
+ lbl = new QLabel( i18n( "Nearest count:" ), this );
+ m_pNearestCount = new PMIntEdit( this );
+ m_pNearestCount->setValidation( true, 0, true, 20 );
+ gl->addWidget( lbl, 10, 0 );
+ gl->addWidget( m_pNearestCount, 10, 1 );
+
+ m_pNormal = new QCheckBox( i18n( "Normal" ), this );
+ gl->addMultiCellWidget( m_pNormal, 11, 11, 0, 1 );
+
+ lbl = new QLabel( i18n( "Pretrace start:" ), this );
+ m_pPretraceStart = new PMFloatEdit( this );
+ m_pPretraceStart->setValidation( true, 0, true, 1 );
+ gl->addWidget( lbl, 12, 0 );
+ gl->addWidget( m_pPretraceStart, 12, 1 );
+
+ lbl = new QLabel( i18n( "Pretrace end:" ), this );
+ m_pPretraceEnd = new PMFloatEdit( this );
+ m_pPretraceEnd->setValidation( true, 0, true, 1 );
+ gl->addWidget( lbl, 13, 0 );
+ gl->addWidget( m_pPretraceEnd, 13, 1 );
+
+ lbl = new QLabel( i18n( "Recursion limit:" ), this );
+ m_pRecursionLimit = new PMIntEdit( this );
+ m_pRecursionLimit->setValidation( true, 1, true, 20 );
+ gl->addWidget( lbl, 14, 0 );
+ gl->addWidget( m_pRecursionLimit, 14, 1 );
+
+ hl->addStretch( 1 );
+
+ connect( m_pAdcBailout, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pAlwaysSample, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pBrightness, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pCount, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pErrorBound, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pGrayThreshold, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pLowErrorFactor, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pMaxSample, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pMedia, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pMinimumReuse, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pNearestCount, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pNormal, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pPretraceStart, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pPretraceEnd, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pRecursionLimit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMRadiosityEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Radiosity" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMRadiosity* ) o;
+
+ m_pAdcBailout->setValue( m_pDisplayedObject->adcBailout( ) );
+ m_pAdcBailout->setReadOnly( readOnly );
+ m_pAlwaysSample->setChecked( m_pDisplayedObject->alwaysSample( ) );
+ m_pAlwaysSample->setEnabled( !readOnly );
+ m_pBrightness->setValue( m_pDisplayedObject->brightness( ) );
+ m_pBrightness->setReadOnly( readOnly );
+ m_pCount->setValue( m_pDisplayedObject->count( ) );
+ m_pCount->setReadOnly( readOnly );
+ m_pErrorBound->setValue( m_pDisplayedObject->errorBound( ) );
+ m_pErrorBound->setReadOnly( readOnly );
+ m_pGrayThreshold->setValue( m_pDisplayedObject->grayThreshold( ) );
+ m_pGrayThreshold->setReadOnly( readOnly );
+ m_pLowErrorFactor->setValue( m_pDisplayedObject->lowErrorFactor( ) );
+ m_pLowErrorFactor->setReadOnly( readOnly );
+ m_pMaxSample->setValue( m_pDisplayedObject->maxSample( ) );
+ m_pMaxSample->setReadOnly( readOnly );
+ m_pMedia->setChecked( m_pDisplayedObject->media( ) );
+ m_pMedia->setEnabled( !readOnly );
+ m_pMinimumReuse->setValue( m_pDisplayedObject->minimumReuse( ) );
+ m_pMinimumReuse->setReadOnly( readOnly );
+ m_pNearestCount->setValue( m_pDisplayedObject->nearestCount( ) );
+ m_pNearestCount->setReadOnly( readOnly );
+ m_pNormal->setChecked( m_pDisplayedObject->normal( ) );
+ m_pNormal->setEnabled( !readOnly );
+ m_pPretraceStart->setValue( m_pDisplayedObject->pretraceStart( ) );
+ m_pPretraceStart->setReadOnly( readOnly );
+ m_pPretraceEnd->setValue( m_pDisplayedObject->pretraceEnd( ) );
+ m_pPretraceEnd->setReadOnly( readOnly );
+ m_pRecursionLimit->setValue( m_pDisplayedObject->recursionLimit( ) );
+ m_pRecursionLimit->setReadOnly( readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMRadiosityEdit: Can't display object\n";
+}
+
+void PMRadiosityEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setAdcBailout( m_pAdcBailout->value( ) );
+ m_pDisplayedObject->setAlwaysSample( m_pAlwaysSample->isChecked( ) );
+ m_pDisplayedObject->setBrightness( m_pBrightness->value( ) );
+ m_pDisplayedObject->setCount( m_pCount->value( ) );
+ m_pDisplayedObject->setErrorBound( m_pErrorBound->value( ) );
+ m_pDisplayedObject->setGrayThreshold( m_pGrayThreshold->value( ) );
+ m_pDisplayedObject->setLowErrorFactor( m_pLowErrorFactor->value( ) );
+ m_pDisplayedObject->setMaxSample( m_pMaxSample->value( ) );
+ m_pDisplayedObject->setMedia( m_pMedia->isChecked( ) );
+ m_pDisplayedObject->setMinimumReuse( m_pMinimumReuse->value( ) );
+ m_pDisplayedObject->setNearestCount( m_pNearestCount->value( ) );
+ m_pDisplayedObject->setNormal( m_pNormal->isChecked( ) );
+ m_pDisplayedObject->setPretraceStart( m_pPretraceStart->value( ) );
+ m_pDisplayedObject->setPretraceEnd( m_pPretraceEnd->value( ) );
+ m_pDisplayedObject->setRecursionLimit( m_pRecursionLimit->value( ) );
+ }
+}
+
+bool PMRadiosityEdit::isDataValid( )
+{
+ if( !m_pAdcBailout->isDataValid( ) ) return false;
+ if( !m_pBrightness->isDataValid( ) ) return false;
+ if( !m_pCount->isDataValid( ) ) return false;
+ if( !m_pErrorBound->isDataValid( ) ) return false;
+ if( !m_pGrayThreshold->isDataValid( ) ) return false;
+ if( !m_pLowErrorFactor->isDataValid( ) ) return false;
+ if( !m_pMaxSample->isDataValid( ) ) return false;
+ if( !m_pMinimumReuse->isDataValid( ) ) return false;
+ if( !m_pNearestCount->isDataValid( ) ) return false;
+ if( !m_pPretraceStart->isDataValid( ) ) return false;
+ if( !m_pPretraceEnd->isDataValid( ) ) return false;
+ if( !m_pRecursionLimit->isDataValid( ) ) return false;
+
+ return Base::isDataValid( );
+}
+
+#include "pmradiosityedit.moc"
diff --git a/kpovmodeler/pmradiosityedit.h b/kpovmodeler/pmradiosityedit.h
new file mode 100644
index 00000000..37ee18c7
--- /dev/null
+++ b/kpovmodeler/pmradiosityedit.h
@@ -0,0 +1,81 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Leon Pennington
+ email : leon@leonscape.co.uk
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMRADIOSITYEDIT_H
+#define PMRADIOSITYEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdialogeditbase.h"
+
+class PMRadiosity;
+class PMFloatEdit;
+class PMIntEdit;
+class QCheckBox;
+
+/**
+ * Dialog edit class for @ref PMRadiosity.
+ */
+class PMRadiosityEdit : public PMDialogEditBase
+{
+ Q_OBJECT
+ typedef PMDialogEditBase Base;
+public:
+ /**
+ * Creates a PMRadiosityEdit with parent and name
+ */
+ PMRadiosityEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+protected slots:
+
+private:
+ PMRadiosity* m_pDisplayedObject;
+
+ PMFloatEdit* m_pAdcBailout;
+ QCheckBox* m_pAlwaysSample;
+ PMFloatEdit* m_pBrightness;
+ PMIntEdit* m_pCount;
+ PMFloatEdit* m_pErrorBound;
+ PMFloatEdit* m_pGrayThreshold;
+ PMFloatEdit* m_pLowErrorFactor;
+ PMFloatEdit* m_pMaxSample;
+ QCheckBox* m_pMedia;
+ PMFloatEdit* m_pMinimumReuse;
+ PMIntEdit* m_pNearestCount;
+ QCheckBox* m_pNormal;
+ PMFloatEdit* m_pPretraceStart;
+ PMFloatEdit* m_pPretraceEnd;
+ PMIntEdit* m_pRecursionLimit;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmrainbow.cpp b/kpovmodeler/pmrainbow.cpp
new file mode 100644
index 00000000..5a80e013
--- /dev/null
+++ b/kpovmodeler/pmrainbow.cpp
@@ -0,0 +1,422 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001-2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmrainbow.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pmrainbowedit.h"
+#include "pmvector.h"
+
+#include <klocale.h>
+
+PMMetaObject* PMRainbow::s_pMetaObject = 0;
+PMObject* createNewRainbow( PMPart* part )
+{
+ return new PMRainbow( part );
+}
+
+const PMVector directionDefault = PMVector( 0.0, 0.0, 0.0 );
+const double angleDefault = 0.0;
+const double widthDefault = 0.0;
+const double distanceDefault = 0.0;
+const double jitterDefault = 0.0;
+const PMVector upDefault = PMVector( 0.0, 0.0, 0.0 );
+const double arcAngleDefault = 0.0;
+const double falloffAngleDefault = 0.0;
+
+PMDefinePropertyClass( PMRainbow, PMRainbowProperty );
+
+PMRainbow::PMRainbow( PMPart* part )
+ : Base( part )
+{
+ m_direction = directionDefault;
+ m_angle = angleDefault;
+ m_width = widthDefault;
+ m_distance = distanceDefault;
+ m_jitter = jitterDefault;
+ m_up = upDefault;
+ m_arcAngle = arcAngleDefault;
+ m_falloffAngle = falloffAngleDefault;
+ m_enableDirection = false;
+ m_enableAngle = false;
+ m_enableWidth = false;
+ m_enableDistance = false;
+ m_enableJitter = false;
+ m_enableUp = false;
+ m_enableArcAngle = false;
+ m_enableFalloffAngle = false;
+}
+
+PMRainbow::PMRainbow( const PMRainbow& r )
+ : Base( r )
+{
+ m_direction = r.m_direction;
+ m_angle = r.m_angle;
+ m_width = r.m_width;
+ m_distance = r.m_distance;
+ m_jitter = r.m_jitter;
+ m_up = r.m_up;
+ m_arcAngle = r.m_arcAngle;
+ m_falloffAngle = r.m_falloffAngle;
+ m_enableDirection = r.m_enableDirection;
+ m_enableAngle = r.m_enableAngle;
+ m_enableWidth = r.m_enableWidth;
+ m_enableDistance = r.m_enableDistance;
+ m_enableJitter = r.m_enableJitter;
+ m_enableUp = r.m_enableUp;
+ m_enableArcAngle = r.m_enableArcAngle;
+ m_enableFalloffAngle = r.m_enableFalloffAngle;
+}
+
+PMRainbow::~PMRainbow( )
+{
+}
+
+PMMetaObject* PMRainbow::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Rainbow", Base::metaObject( ),
+ createNewRainbow );
+ s_pMetaObject->addProperty(
+ new PMRainbowProperty( "direction", &PMRainbow::setDirection, &PMRainbow::direction ) );
+ s_pMetaObject->addProperty(
+ new PMRainbowProperty( "angle", &PMRainbow::setAngle, &PMRainbow::angle ) );
+ s_pMetaObject->addProperty(
+ new PMRainbowProperty( "width", &PMRainbow::setWidth, &PMRainbow::width ) );
+ s_pMetaObject->addProperty(
+ new PMRainbowProperty( "distance", &PMRainbow::setDistance, &PMRainbow::distance ) );
+ s_pMetaObject->addProperty(
+ new PMRainbowProperty( "jitter", &PMRainbow::setJitter, &PMRainbow::jitter ) );
+ s_pMetaObject->addProperty(
+ new PMRainbowProperty( "up", &PMRainbow::setUp, &PMRainbow::up ) );
+ s_pMetaObject->addProperty(
+ new PMRainbowProperty( "arcAngle", &PMRainbow::setArcAngle, &PMRainbow::arcAngle ) );
+ s_pMetaObject->addProperty(
+ new PMRainbowProperty( "falloffAngle", &PMRainbow::setFalloffAngle, &PMRainbow::falloffAngle ) );
+ s_pMetaObject->addProperty(
+ new PMRainbowProperty( "directionEnabled", &PMRainbow::enableDirection, &PMRainbow::isDirectionEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMRainbowProperty( "angleEnabled", &PMRainbow::enableAngle, &PMRainbow::isAngleEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMRainbowProperty( "widthEnabled", &PMRainbow::enableWidth, &PMRainbow::isWidthEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMRainbowProperty( "distanceEnabled", &PMRainbow::enableDistance, &PMRainbow::isDistanceEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMRainbowProperty( "jitterEnabled", &PMRainbow::enableJitter, &PMRainbow::isJitterEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMRainbowProperty( "upEnabled", &PMRainbow::enableUp, &PMRainbow::isUpEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMRainbowProperty( "arcAngleEnabled", &PMRainbow::enableArcAngle, &PMRainbow::isArcAngleEnabled ) );
+ s_pMetaObject->addProperty(
+ new PMRainbowProperty( "falloffAngleEnabled", &PMRainbow::enableFalloffAngle, &PMRainbow::isFalloffAngleEnabled ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMRainbow::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMRainbow::description( ) const
+{
+ return i18n( "rainbow" );
+}
+
+void PMRainbow::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ Base::serialize( e, doc );
+ e.setAttribute( "enable_direction", m_enableDirection );
+ e.setAttribute( "enable_angle", m_enableAngle );
+ e.setAttribute( "enable_width", m_enableWidth );
+ e.setAttribute( "enable_distance", m_enableDistance );
+ e.setAttribute( "enable_jitter", m_enableJitter );
+ e.setAttribute( "enable_up", m_enableUp );
+ e.setAttribute( "enable_arc_angle", m_enableArcAngle );
+ e.setAttribute( "enable_falloff_angle", m_enableFalloffAngle );
+ e.setAttribute( "direction", m_direction.serializeXML( ) );
+ e.setAttribute( "angle", m_angle );
+ e.setAttribute( "width", m_width );
+ e.setAttribute( "distance", m_distance );
+ e.setAttribute( "jitter", m_jitter );
+ e.setAttribute( "up", m_up.serializeXML( ) );
+ e.setAttribute( "arc_angle", m_arcAngle );
+ e.setAttribute( "falloff_angle", m_falloffAngle );
+}
+
+void PMRainbow::readAttributes( const PMXMLHelper& h )
+{
+ Base::readAttributes( h );
+ m_enableDirection = h.boolAttribute( "enable_direction", false );
+ m_enableAngle = h.boolAttribute( "enable_angle", false );
+ m_enableWidth = h.boolAttribute( "enable_width", false );
+ m_enableDistance = h.boolAttribute( "enable_distance", false );
+ m_enableJitter = h.boolAttribute( "enable_jitter", false );
+ m_enableUp = h.boolAttribute( "enable_up", false );
+ m_enableArcAngle = h.boolAttribute( "enable_arc_angle", false );
+ m_enableFalloffAngle = h.boolAttribute( "enable_falloff_angle", false );
+ m_direction = h.vectorAttribute( "direction", directionDefault );
+ m_angle = h.doubleAttribute( "angle", angleDefault );
+ m_width = h.doubleAttribute( "width", widthDefault );
+ m_distance = h.doubleAttribute( "distance", distanceDefault );
+ m_jitter = h.doubleAttribute( "jitter", jitterDefault );
+ m_up = h.vectorAttribute( "up", upDefault );
+ m_arcAngle = h.doubleAttribute( "arc_angle", arcAngleDefault );
+ m_falloffAngle = h.doubleAttribute( "falloff_angle", falloffAngleDefault );
+}
+
+void PMRainbow::setDirection( const PMVector& c )
+{
+ if( c != m_direction )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMDirectionID, m_direction );
+ m_direction = c;
+ }
+}
+
+void PMRainbow::setAngle( double c )
+{
+ if( c != m_angle )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMAngleID, m_angle );
+ m_angle = c;
+ }
+}
+
+void PMRainbow::setWidth( double c )
+{
+ if( c != m_width )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMWidthID, m_width );
+ m_width = c;
+ }
+}
+
+void PMRainbow::setDistance( double c )
+{
+ if( c != m_distance )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMDistanceID, m_distance );
+ m_distance = c;
+ }
+}
+
+void PMRainbow::setJitter( double c )
+{
+ if( c != m_jitter )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMJitterID, m_jitter );
+ m_jitter = c;
+ }
+}
+
+void PMRainbow::setUp( const PMVector& c )
+{
+ if( c != m_up )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMUpID, m_up );
+ m_up = c;
+ }
+}
+
+void PMRainbow::setArcAngle( double c )
+{
+ if( c != m_arcAngle )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMArcAngleID, m_arcAngle );
+ m_arcAngle = c;
+ }
+}
+
+void PMRainbow::setFalloffAngle( double c )
+{
+ if( c != m_falloffAngle )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFalloffAngleID, m_falloffAngle );
+ m_falloffAngle = c;
+ }
+}
+
+void PMRainbow::enableDirection( bool c )
+{
+ if( c != m_enableDirection )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableDirectionID, m_enableDirection );
+ m_enableDirection = c;
+ }
+}
+
+void PMRainbow::enableAngle( bool c )
+{
+ if( c != m_enableAngle )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableAngleID, m_enableAngle );
+ m_enableAngle = c;
+ }
+}
+
+void PMRainbow::enableWidth( bool c )
+{
+ if( c != m_enableWidth )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableWidthID, m_enableWidth );
+ m_enableWidth = c;
+ }
+}
+
+void PMRainbow::enableDistance( bool c )
+{
+ if( c != m_enableDistance )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableDistanceID, m_enableDistance );
+ m_enableDistance = c;
+ }
+}
+
+void PMRainbow::enableJitter( bool c )
+{
+ if( c != m_enableJitter )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableJitterID, m_enableJitter );
+ m_enableJitter = c;
+ }
+}
+
+void PMRainbow::enableUp( bool c )
+{
+ if( c != m_enableUp )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableUpID, m_enableUp );
+ m_enableUp = c;
+ }
+}
+
+void PMRainbow::enableArcAngle( bool c )
+{
+ if( c != m_enableArcAngle )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableArcAngleID, m_enableArcAngle );
+ m_enableArcAngle = c;
+ }
+}
+
+void PMRainbow::enableFalloffAngle( bool c )
+{
+ if( c != m_enableFalloffAngle )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEnableFalloffAngleID,
+ m_enableFalloffAngle );
+ m_enableFalloffAngle = c;
+ }
+}
+
+PMDialogEditBase* PMRainbow::editWidget( QWidget* parent ) const
+{
+ return new PMRainbowEdit( parent );
+}
+
+void PMRainbow::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMDirectionID:
+ setDirection( data->vectorData( ) );
+ break;
+ case PMAngleID:
+ setAngle( data->doubleData( ) );
+ break;
+ case PMWidthID:
+ setWidth( data->doubleData( ) );
+ break;
+ case PMDistanceID:
+ setDistance( data->doubleData( ) );
+ break;
+ case PMJitterID:
+ setJitter( data->doubleData( ) );
+ break;
+ case PMUpID:
+ setUp( data->vectorData( ) );
+ break;
+ case PMArcAngleID:
+ setArcAngle( data->doubleData( ) );
+ break;
+ case PMFalloffAngleID:
+ setFalloffAngle( data->doubleData( ) );
+ break;
+ case PMEnableDirectionID:
+ enableDirection( data->boolData( ) );
+ break;
+ case PMEnableAngleID:
+ enableAngle( data->boolData( ) );
+ break;
+ case PMEnableWidthID:
+ enableWidth( data->boolData( ) );
+ break;
+ case PMEnableDistanceID:
+ enableDistance( data->boolData( ) );
+ break;
+ case PMEnableJitterID:
+ enableJitter( data->boolData( ) );
+ break;
+ case PMEnableUpID:
+ enableUp( data->boolData( ) );
+ break;
+ case PMEnableArcAngleID:
+ enableArcAngle( data->boolData( ) );
+ break;
+ case PMEnableFalloffAngleID:
+ enableFalloffAngle( data->boolData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMRainbow::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmrainbow.h b/kpovmodeler/pmrainbow.h
new file mode 100644
index 00000000..0c95c459
--- /dev/null
+++ b/kpovmodeler/pmrainbow.h
@@ -0,0 +1,139 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001-2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMRAINBOW_H
+#define PMRAINBOW_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebase.h"
+
+/**
+ * Class for povray rainbows
+ */
+class PMRainbow : public PMTextureBase
+{
+ typedef PMTextureBase Base;
+public:
+ /**
+ * Creates an PMRainbow
+ */
+ PMRainbow( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMRainbow( const PMRainbow& r );
+ /**
+ * Deletes the object
+ */
+ virtual ~PMRainbow( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMRainbow( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMRainbowEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmrainbow" ); }
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+
+ PMVector direction( ) const { return m_direction; }
+ double angle( ) const { return m_angle; }
+ double width( ) const { return m_width; }
+ double distance( ) const { return m_distance; }
+ double jitter( ) const { return m_jitter; }
+ PMVector up( ) const { return m_up; }
+ double arcAngle( ) const { return m_arcAngle; }
+ double falloffAngle( ) const { return m_falloffAngle; }
+ bool isDirectionEnabled( ) const { return m_enableDirection; }
+ bool isAngleEnabled( ) const { return m_enableAngle; }
+ bool isWidthEnabled( ) const { return m_enableWidth; }
+ bool isDistanceEnabled( ) const { return m_enableDistance; }
+ bool isJitterEnabled( ) const { return m_enableJitter; }
+ bool isUpEnabled( ) const { return m_enableUp; }
+ bool isArcAngleEnabled( ) const { return m_enableArcAngle; }
+ bool isFalloffAngleEnabled( ) const { return m_enableFalloffAngle; }
+
+ void setDirection( const PMVector& c );
+ void setAngle( double c );
+ void setWidth( double c );
+ void setDistance( double c );
+ void setJitter( double c );
+ void setUp( const PMVector& c );
+ void setArcAngle( double c );
+ void setFalloffAngle( double c );
+ void enableDirection( bool c );
+ void enableAngle( bool c );
+ void enableWidth( bool c );
+ void enableDistance( bool c );
+ void enableJitter( bool c );
+ void enableUp( bool c );
+ void enableArcAngle( bool c );
+ void enableFalloffAngle( bool c );
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMRainbowMementoID { PMDirectionID, PMAngleID, PMWidthID,
+ PMDistanceID, PMJitterID, PMUpID, PMArcAngleID,
+ PMFalloffAngleID, PMEnableDirectionID,
+ PMEnableAngleID, PMEnableWidthID,
+ PMEnableDistanceID, PMEnableJitterID, PMEnableUpID,
+ PMEnableArcAngleID, PMEnableFalloffAngleID };
+ PMVector m_direction;
+ double m_angle;
+ double m_width;
+ double m_distance;
+ double m_jitter;
+ PMVector m_up;
+ double m_arcAngle;
+ double m_falloffAngle;
+
+ bool m_enableDirection;
+ bool m_enableAngle;
+ bool m_enableWidth;
+ bool m_enableDistance;
+ bool m_enableJitter;
+ bool m_enableUp;
+ bool m_enableArcAngle;
+ bool m_enableFalloffAngle;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmrainbowedit.cpp b/kpovmodeler/pmrainbowedit.cpp
new file mode 100644
index 00000000..ff359a7e
--- /dev/null
+++ b/kpovmodeler/pmrainbowedit.cpp
@@ -0,0 +1,278 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmrainbowedit.h"
+#include "pmrainbow.h"
+#include "pmlineedits.h"
+#include "pmvectoredit.h"
+#include "pmvector.h"
+#include "pmmath.h"
+
+#include <qlayout.h>
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+
+PMRainbowEdit::PMRainbowEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMRainbowEdit::createTopWidgets( )
+{
+ QHBoxLayout* hl;
+ QGridLayout* gl;
+
+ Base::createTopWidgets( );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ m_pEnableDirectionEdit = new QCheckBox( i18n( "Direction:" ), this );
+ m_pDirectionEdit = new PMVectorEdit( "x", "y", "z", this );
+ hl->addWidget( m_pEnableDirectionEdit );
+ hl->addWidget( m_pDirectionEdit );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ gl = new QGridLayout( hl, 4, 2 );
+ m_pEnableAngleEdit = new QCheckBox( i18n( "Angle:" ), this );
+ m_pAngleEdit = new PMFloatEdit( this );
+ gl->addWidget( m_pEnableAngleEdit, 0, 0 );
+ gl->addWidget( m_pAngleEdit, 0, 1 );
+
+ m_pEnableWidthEdit = new QCheckBox( i18n( "Width:" ), this );
+ m_pWidthEdit = new PMFloatEdit( this );
+ gl->addWidget( m_pEnableWidthEdit, 1, 0 );
+ gl->addWidget( m_pWidthEdit, 1, 1 );
+
+ m_pEnableDistanceEdit = new QCheckBox( i18n( "Distance:" ), this );
+ m_pDistanceEdit = new PMFloatEdit( this );
+ gl->addWidget( m_pEnableDistanceEdit, 2, 0 );
+ gl->addWidget( m_pDistanceEdit, 2, 1 );
+
+ m_pEnableJitterEdit = new QCheckBox( i18n( "Jitter:" ), this );
+ m_pJitterEdit = new PMFloatEdit( this );
+ gl->addWidget( m_pEnableJitterEdit, 3, 0 );
+ gl->addWidget( m_pJitterEdit, 3, 1 );
+ hl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ m_pEnableUpEdit = new QCheckBox( i18n( "Up:" ), this );
+ m_pUpEdit = new PMVectorEdit( "x", "y", "z", this );
+ hl->addWidget( m_pEnableUpEdit );
+ hl->addWidget( m_pUpEdit );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ gl = new QGridLayout( hl, 2, 2 );
+ m_pEnableArcAngleEdit = new QCheckBox( i18n( "Arc angle:" ), this );
+ m_pArcAngleEdit = new PMFloatEdit( this );
+ m_pArcAngleEdit->setValidation( true, 0, true, 360 );
+ gl->addWidget( m_pEnableArcAngleEdit, 0, 0 );
+ gl->addWidget( m_pArcAngleEdit, 0, 1 );
+ m_pEnableFalloffAngleEdit = new QCheckBox( i18n( "Falloff angle:" ), this );
+ m_pFalloffAngleEdit = new PMFloatEdit( this );
+ m_pFalloffAngleEdit->setValidation( true, 0, true, 360 );
+ gl->addWidget( m_pEnableFalloffAngleEdit, 1, 0 );
+ gl->addWidget( m_pFalloffAngleEdit, 1, 1 );
+ hl->addStretch( 1 );
+
+ connect( m_pDirectionEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pAngleEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pWidthEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pDistanceEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pJitterEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pUpEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pArcAngleEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pFalloffAngleEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pEnableDirectionEdit, SIGNAL( clicked( ) ), SLOT( slotDirectionClicked( ) ) );
+ connect( m_pEnableAngleEdit, SIGNAL( clicked( ) ), SLOT( slotAngleClicked( ) ) );
+ connect( m_pEnableWidthEdit, SIGNAL( clicked( ) ), SLOT( slotWidthClicked( ) ) );
+ connect( m_pEnableDistanceEdit, SIGNAL( clicked( ) ), SLOT( slotDistanceClicked( ) ) );
+ connect( m_pEnableJitterEdit, SIGNAL( clicked( ) ), SLOT( slotJitterClicked( ) ) );
+ connect( m_pEnableUpEdit, SIGNAL( clicked( ) ), SLOT( slotUpClicked( ) ) );
+ connect( m_pEnableArcAngleEdit, SIGNAL( clicked( ) ), SLOT( slotArcAngleClicked( ) ) );
+ connect( m_pEnableFalloffAngleEdit, SIGNAL( clicked( ) ), SLOT( slotFalloffAngleClicked( ) ) );
+}
+
+void PMRainbowEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Rainbow" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMRainbow* ) o;
+
+ m_pDirectionEdit->setVector( m_pDisplayedObject->direction( ) );
+ m_pDirectionEdit->setReadOnly( readOnly );
+ m_pAngleEdit->setValue( m_pDisplayedObject->angle( ) );
+ m_pAngleEdit->setReadOnly( readOnly );
+ m_pWidthEdit->setValue( m_pDisplayedObject->width( ) );
+ m_pWidthEdit->setReadOnly( readOnly );
+ m_pDistanceEdit->setValue( m_pDisplayedObject->distance( ) );
+ m_pDistanceEdit->setReadOnly( readOnly );
+ m_pJitterEdit->setValue( m_pDisplayedObject->jitter( ) );
+ m_pJitterEdit->setReadOnly( readOnly );
+ m_pUpEdit->setVector( m_pDisplayedObject->up( ) );
+ m_pUpEdit->setReadOnly( readOnly );
+ m_pArcAngleEdit->setValue( m_pDisplayedObject->arcAngle( ) );
+ m_pArcAngleEdit->setReadOnly( readOnly );
+ m_pFalloffAngleEdit->setValue( m_pDisplayedObject->falloffAngle( ) );
+ m_pFalloffAngleEdit->setReadOnly( readOnly );
+ m_pEnableDirectionEdit->setChecked( m_pDisplayedObject->isDirectionEnabled( ) );
+ m_pEnableDirectionEdit->setEnabled( !readOnly );
+ m_pEnableAngleEdit->setChecked( m_pDisplayedObject->isAngleEnabled( ) );
+ m_pEnableAngleEdit->setEnabled( !readOnly );
+ m_pEnableWidthEdit->setChecked( m_pDisplayedObject->isWidthEnabled( ) );
+ m_pEnableWidthEdit->setEnabled( !readOnly );
+ m_pEnableDistanceEdit->setChecked( m_pDisplayedObject->isDistanceEnabled( ) );
+ m_pEnableDistanceEdit->setEnabled( !readOnly );
+ m_pEnableJitterEdit->setChecked( m_pDisplayedObject->isJitterEnabled( ) );
+ m_pEnableJitterEdit->setEnabled( !readOnly );
+ m_pEnableUpEdit->setChecked( m_pDisplayedObject->isUpEnabled( ) );
+ m_pEnableUpEdit->setEnabled( !readOnly );
+ m_pEnableArcAngleEdit->setChecked( m_pDisplayedObject->isArcAngleEnabled( ) );
+ m_pEnableArcAngleEdit->setEnabled( !readOnly );
+ m_pEnableFalloffAngleEdit->setChecked( m_pDisplayedObject->isFalloffAngleEnabled( ) );
+ m_pEnableFalloffAngleEdit->setEnabled( !readOnly );
+ slotDirectionClicked( );
+ slotAngleClicked( );
+ slotWidthClicked( );
+ slotDistanceClicked( );
+ slotJitterClicked( );
+ slotUpClicked( );
+ slotArcAngleClicked( );
+ slotFalloffAngleClicked( );
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMRainbowEdit: Can't display object\n";
+}
+
+void PMRainbowEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setDirection( m_pDirectionEdit->vector( ) );
+ m_pDisplayedObject->setAngle( m_pAngleEdit->value( ) );
+ m_pDisplayedObject->setWidth( m_pWidthEdit->value( ) );
+ m_pDisplayedObject->setDistance( m_pDistanceEdit->value( ) );
+ m_pDisplayedObject->setJitter( m_pJitterEdit->value( ) );
+ m_pDisplayedObject->setUp( m_pUpEdit->vector( ) );
+ m_pDisplayedObject->setArcAngle( m_pArcAngleEdit->value( ) );
+ m_pDisplayedObject->setFalloffAngle( m_pFalloffAngleEdit->value( ) );
+ m_pDisplayedObject->enableDirection( m_pEnableDirectionEdit->isChecked( ) );
+ m_pDisplayedObject->enableAngle( m_pEnableAngleEdit->isChecked( ) );
+ m_pDisplayedObject->enableWidth( m_pEnableWidthEdit->isChecked( ) );
+ m_pDisplayedObject->enableDistance( m_pEnableDistanceEdit->isChecked( ) );
+ m_pDisplayedObject->enableJitter( m_pEnableJitterEdit->isChecked( ) );
+ m_pDisplayedObject->enableUp( m_pEnableUpEdit->isChecked( ) );
+ m_pDisplayedObject->enableArcAngle( m_pEnableArcAngleEdit->isChecked( ) );
+ m_pDisplayedObject->enableFalloffAngle( m_pEnableFalloffAngleEdit->isChecked( ) );
+ }
+}
+
+bool PMRainbowEdit::isDataValid( )
+{
+ double f_angle;
+
+ if( !m_pDirectionEdit->isDataValid( ) ) return false;
+ if( !m_pAngleEdit->isDataValid( ) ) return false;
+ if( !m_pWidthEdit->isDataValid( ) ) return false;
+ if( !m_pDistanceEdit->isDataValid( ) ) return false;
+ if( !m_pJitterEdit->isDataValid( ) ) return false;
+ if( !m_pUpEdit->isDataValid( ) ) return false;
+ if( !m_pArcAngleEdit->isDataValid( ) ) return false;
+ if( !m_pFalloffAngleEdit->isDataValid( ) ) return false;
+ if( m_pFalloffAngleEdit->value( ) > m_pArcAngleEdit->value( ) )
+ {
+ KMessageBox::error( this, i18n( "Arc angle is smaller than falloff angle in rainbow." ),
+ i18n( "Error" ) );
+ return false;
+ }
+ if( approxZero( fabs( PMVector::dot( m_pDirectionEdit->vector( ), m_pDirectionEdit->vector( ) ) ) ) )
+ {
+ KMessageBox::error( this, i18n( "Direction vector is zero." ),
+ i18n( "Error" ) );
+ return false;
+ }
+ if( approxZero( fabs( PMVector::dot( m_pUpEdit->vector( ), m_pUpEdit->vector( ) ) ) ) )
+ {
+ KMessageBox::error( this, i18n( "Up vector is zero." ),
+ i18n( "Error" ) );
+ return false;
+ }
+ f_angle = fabs( rad2Deg( PMVector::angle( m_pDirectionEdit->vector( ), m_pUpEdit->vector( ) ) ) );
+ if( f_angle == 0.0 || f_angle == 180.0 )
+ {
+ KMessageBox::error( this, i18n( "Direction and up vectors are co-linear." ),
+ i18n( "Error" ) );
+ return false;
+ }
+ return Base::isDataValid( );
+}
+
+void PMRainbowEdit::slotDirectionClicked( )
+{
+ m_pDirectionEdit->setEnabled( m_pEnableDirectionEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+void PMRainbowEdit::slotAngleClicked( )
+{
+ m_pAngleEdit->setEnabled( m_pEnableAngleEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+void PMRainbowEdit::slotWidthClicked( )
+{
+ m_pWidthEdit->setEnabled( m_pEnableWidthEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+void PMRainbowEdit::slotDistanceClicked( )
+{
+ m_pDistanceEdit->setEnabled( m_pEnableDistanceEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+void PMRainbowEdit::slotJitterClicked( )
+{
+ m_pJitterEdit->setEnabled( m_pEnableJitterEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+void PMRainbowEdit::slotUpClicked( )
+{
+ m_pUpEdit->setEnabled( m_pEnableUpEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+void PMRainbowEdit::slotArcAngleClicked( )
+{
+ m_pArcAngleEdit->setEnabled( m_pEnableArcAngleEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+void PMRainbowEdit::slotFalloffAngleClicked( )
+{
+ m_pFalloffAngleEdit->setEnabled( m_pEnableFalloffAngleEdit->isChecked( ) );
+ emit dataChanged( );
+}
+
+#include "pmrainbowedit.moc"
diff --git a/kpovmodeler/pmrainbowedit.h b/kpovmodeler/pmrainbowedit.h
new file mode 100644
index 00000000..c5d4b714
--- /dev/null
+++ b/kpovmodeler/pmrainbowedit.h
@@ -0,0 +1,90 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMRAINBOWEDIT_H
+#define PMRAINBOWEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebaseedit.h"
+
+class PMRainbow;
+class PMFloatEdit;
+class PMVectorEdit;
+class QCheckBox;
+class QLabel;
+
+/**
+ * Dialog edit class for @ref PMRainbow
+ */
+class PMRainbowEdit : public PMTextureBaseEdit
+{
+ Q_OBJECT
+ typedef PMTextureBaseEdit Base;
+public:
+ /**
+ * Creates a PMRainbowEdit with parent and name
+ */
+ PMRainbowEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+protected slots:
+ void slotDirectionClicked( );
+ void slotAngleClicked( );
+ void slotWidthClicked( );
+ void slotDistanceClicked( );
+ void slotJitterClicked( );
+ void slotUpClicked( );
+ void slotArcAngleClicked( );
+ void slotFalloffAngleClicked( );
+
+private:
+ PMRainbow* m_pDisplayedObject;
+ PMVectorEdit* m_pDirectionEdit;
+ PMFloatEdit* m_pAngleEdit;
+ PMFloatEdit* m_pWidthEdit;
+ PMFloatEdit* m_pDistanceEdit;
+ PMFloatEdit* m_pJitterEdit;
+ PMVectorEdit* m_pUpEdit;
+ PMFloatEdit* m_pArcAngleEdit;
+ PMFloatEdit* m_pFalloffAngleEdit;
+ QCheckBox* m_pEnableDirectionEdit;
+ QCheckBox* m_pEnableAngleEdit;
+ QCheckBox* m_pEnableWidthEdit;
+ QCheckBox* m_pEnableDistanceEdit;
+ QCheckBox* m_pEnableJitterEdit;
+ QCheckBox* m_pEnableUpEdit;
+ QCheckBox* m_pEnableArcAngleEdit;
+ QCheckBox* m_pEnableFalloffAngleEdit;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmraw.cpp b/kpovmodeler/pmraw.cpp
new file mode 100644
index 00000000..a2d44784
--- /dev/null
+++ b/kpovmodeler/pmraw.cpp
@@ -0,0 +1,135 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmraw.h"
+#include "pmxmlhelper.h"
+
+#include "pmrawedit.h"
+#include "pmmemento.h"
+
+#include <klocale.h>
+#include <qtextstream.h>
+
+PMDefinePropertyClass( PMRaw, PMRawProperty );
+
+PMMetaObject* PMRaw::s_pMetaObject = 0;
+PMObject* createNewRaw( PMPart* part )
+{
+ return new PMRaw( part );
+}
+
+PMRaw::PMRaw( PMPart* part )
+ : Base( part )
+{
+}
+
+PMRaw::PMRaw( const PMRaw& r )
+ : Base( r )
+{
+ m_code = r.m_code;
+}
+
+PMRaw::PMRaw( PMPart* part, const QString& t )
+ : Base( part )
+{
+ m_code = t;
+}
+
+PMRaw::~PMRaw( )
+{
+}
+
+QString PMRaw::description( ) const
+{
+ return i18n( "raw povray" );
+}
+
+void PMRaw::setCode( const QString& code )
+{
+ if( code != m_code )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMCodeID, m_code );
+ m_code = code;
+ }
+}
+
+PMMetaObject* PMRaw::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Raw", Base::metaObject( ),
+ createNewRaw );
+ s_pMetaObject->addProperty(
+ new PMRawProperty( "code", &PMRaw::setCode, &PMRaw::code ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMRaw::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMRaw::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ QDomText t = doc.createTextNode( m_code );
+ e.appendChild( t );
+}
+
+void PMRaw::readAttributes( const PMXMLHelper& h )
+{
+ QDomNode e = h.element( ).firstChild( );
+ if( e.isText( ) )
+ m_code = e.toText( ).data( );
+}
+
+PMDialogEditBase* PMRaw::editWidget( QWidget* parent ) const
+{
+ return new PMRawEdit( parent );
+}
+
+void PMRaw::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMCodeID:
+ setCode( data->stringData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMRaw::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
diff --git a/kpovmodeler/pmraw.h b/kpovmodeler/pmraw.h
new file mode 100644
index 00000000..2ba888bc
--- /dev/null
+++ b/kpovmodeler/pmraw.h
@@ -0,0 +1,90 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMRAW_H
+#define PMRAW_H
+
+#include "pmnamedobject.h"
+#include <qstring.h>
+
+
+/**
+ * Class for raw povray code
+ */
+class PMRaw : public PMNamedObject
+{
+ typedef PMNamedObject Base;
+public:
+ /**
+ * Creates an empty raw povray object
+ */
+ PMRaw( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMRaw( const PMRaw& r );
+ /**
+ * Creates a raw povray object with text t
+ */
+ PMRaw( PMPart* part, const QString& t );
+ /**
+ * Deletes the raw povray object
+ */
+ ~PMRaw( );
+
+ /**
+ * Sets the povray code
+ */
+ void setCode( const QString& text );
+ /**
+ * Returns the raw povray code
+ */
+ QString code( ) const { return m_code; }
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMRaw( *this ); }
+ /** */
+ virtual QString description( ) const;
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmraw" ); }
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMRawMementoID { PMCodeID };
+ QString m_code;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmrawedit.cpp b/kpovmodeler/pmrawedit.cpp
new file mode 100644
index 00000000..81d752d2
--- /dev/null
+++ b/kpovmodeler/pmrawedit.cpp
@@ -0,0 +1,79 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmrawedit.h"
+#include "pmraw.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qmultilineedit.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+
+PMRawEdit::PMRawEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMRawEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ topLayout( )->addWidget( new QLabel( i18n( "Povray code:" ), this ) );
+ m_pEdit = new QMultiLineEdit( this );
+#if ( QT_VERSION >= 300 )
+ m_pEdit->setTextFormat( Qt::PlainText );
+ m_pEdit->setWordWrap( QTextEdit::NoWrap );
+#endif
+ m_pEdit->setFont( KGlobalSettings::fixedFont( ) );
+ topLayout( )->addWidget( m_pEdit, 2 );
+
+ connect( m_pEdit, SIGNAL( textChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMRawEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Raw" ) )
+ {
+ m_pDisplayedObject = ( PMRaw* ) o;
+ m_pEdit->setText( m_pDisplayedObject->code( ) );
+
+ m_pEdit->setReadOnly( o->isReadOnly( ) );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMRawEdit: Can't display object\n";
+}
+
+void PMRawEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setCode( m_pEdit->text( ) );
+ }
+}
+
+bool PMRawEdit::isDataValid( )
+{
+ return Base::isDataValid( );
+}
+
+#include "pmrawedit.moc"
diff --git a/kpovmodeler/pmrawedit.h b/kpovmodeler/pmrawedit.h
new file mode 100644
index 00000000..911ceb4e
--- /dev/null
+++ b/kpovmodeler/pmrawedit.h
@@ -0,0 +1,62 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMRAWEDIT_H
+#define PMRAWEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmnamedobjectedit.h"
+
+class PMRaw;
+class QMultiLineEdit;
+
+/**
+ * Dialog edit class for @ref PMRaw.
+ */
+class PMRawEdit : public PMNamedObjectEdit
+{
+ Q_OBJECT
+ typedef PMNamedObjectEdit Base;
+public:
+ /**
+ * Creates a PMRawEdit with parent and name
+ */
+ PMRawEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMRaw* m_pDisplayedObject;
+ QMultiLineEdit* m_pEdit;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmrecursiveobjectiterator.cpp b/kpovmodeler/pmrecursiveobjectiterator.cpp
new file mode 100644
index 00000000..eeacfaa6
--- /dev/null
+++ b/kpovmodeler/pmrecursiveobjectiterator.cpp
@@ -0,0 +1,62 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmobject.h"
+#include "pmrecursiveobjectiterator.h"
+
+PMRecursiveObjectIterator::PMRecursiveObjectIterator( PMObject* obj )
+{
+ m_pObject = obj;
+ m_pCurrent = obj;
+}
+
+PMObject* PMRecursiveObjectIterator::operator++( )
+{
+ if( m_pCurrent )
+ {
+ if( m_pCurrent->firstChild( ) )
+ m_pCurrent = m_pCurrent->firstChild( );
+ else if( m_pCurrent == m_pObject )
+ m_pCurrent = 0;
+ else if( m_pCurrent->nextSibling( ) )
+ m_pCurrent = m_pCurrent->nextSibling( );
+ else
+ {
+ bool stop = false;
+ do
+ {
+ m_pCurrent = m_pCurrent->parent( );
+ if( !m_pCurrent )
+ stop = true;
+ else if( m_pCurrent == m_pObject )
+ {
+ // finished
+ stop = true;
+ m_pCurrent = 0;
+ }
+ else if( m_pCurrent->nextSibling( ) )
+ {
+ m_pCurrent = m_pCurrent->nextSibling( );
+ stop = true;
+ }
+ }
+ while( !stop );
+ }
+ }
+
+ return m_pCurrent;
+}
diff --git a/kpovmodeler/pmrecursiveobjectiterator.h b/kpovmodeler/pmrecursiveobjectiterator.h
new file mode 100644
index 00000000..aafeaad3
--- /dev/null
+++ b/kpovmodeler/pmrecursiveobjectiterator.h
@@ -0,0 +1,49 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMRECURSIVEOBJECTITERATOR_H
+#define PMRECURSIVEOBJECTITERATOR_H
+
+class PMObject;
+
+/**
+ * Iterator that
+ */
+class PMRecursiveObjectIterator
+{
+public:
+ /**
+ * Creates an iterator that iterates recursively over the childs
+ * of obj.
+ */
+ PMRecursiveObjectIterator( PMObject* obj );
+ /**
+ * Makes the next object the current one and returns it.
+ */
+ PMObject* operator++( );
+ /**
+ * Returns the current object.
+ */
+ PMObject* current( ) const { return m_pCurrent; }
+
+private:
+ PMObject* m_pObject;
+ PMObject* m_pCurrent;
+};
+
+#endif
diff --git a/kpovmodeler/pmrendermanager.cpp b/kpovmodeler/pmrendermanager.cpp
new file mode 100644
index 00000000..664f0fd9
--- /dev/null
+++ b/kpovmodeler/pmrendermanager.cpp
@@ -0,0 +1,1647 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+// conflicting types for INT32 in qt and glx
+#ifndef QT_CLEAN_NAMESPACE
+#define QT_CLEAN_NAMESPACE
+#endif
+
+#include "pmrendermanager.h"
+#include "pmviewstructure.h"
+#include "pmobject.h"
+#include "pmdeclare.h"
+#include "pmcamera.h"
+#include "pmquickcolor.h"
+#include "pmdefaults.h"
+#include "pmgraphicalobject.h"
+#include "pmmath.h"
+
+#include <qptrstack.h>
+#include <qapplication.h>
+#include <qbitmap.h>
+#include <qimage.h>
+#include <qpainter.h>
+#include <kconfig.h>
+#include <klocale.h>
+
+#include <time.h>
+#include <stdio.h>
+#include <math.h>
+
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <GL/glu.h> // Only needed for gluPerspective
+
+#include "pmglview.h"
+
+const GLdouble dA = 0.75;
+const GLdouble dB = 0.15;
+
+const GLdouble viewVolumeZ = 1e5;
+
+// Size has to be controlPointSize (see pmglview.h)
+const GLubyte PointBitmap[7] = { 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE };
+const GLubyte CrossBitmap[7] = { 0x10, 0x10, 0x10, 0xFE, 0x10, 0x10, 0x10 };
+
+
+const int activeTimeAfterRendering = 2;
+const int maxEventTime = 0;
+const int maxSubdivisions = 32;
+const double subdivisionDistance = 0.05;
+
+
+PMRenderManager* PMRenderManager::s_pManager = 0;
+KStaticDeleter<PMRenderManager> PMRenderManager::s_staticDeleter;
+
+bool PMRenderManager::s_hasOpenGL = true;
+bool PMRenderManager::s_hasOpenGLChecked = false;
+
+PMRenderManager* PMRenderManager::theManager( )
+{
+ if( !s_pManager )
+ s_staticDeleter.setObject( s_pManager, new PMRenderManager( ) );
+ return s_pManager;
+}
+
+PMRenderManager::PMRenderManager( )
+ : QObject( qApp )
+{
+ int i;
+
+ m_bStartTask = false;
+ m_bStopTask = false;
+ m_bTaskIsRunning = false;
+
+ m_graphicalObjectColor[0] = c_defaultGraphicalObjectColor0;
+ m_graphicalObjectColor[1] = c_defaultGraphicalObjectColor1;
+ m_textureColor[0] = c_defaultTextureColor0;
+ m_textureColor[1] = c_defaultTextureColor1;
+ m_axesColor[0] = c_defaultAxesColorX;
+ m_axesColor[1] = c_defaultAxesColorY;
+ m_axesColor[2] = c_defaultAxesColorZ;
+ m_controlPointColor[0] = c_defaultControlPointColor0;
+ m_controlPointColor[1] = c_defaultControlPointColor1;
+ m_backgroundColor = c_defaultBackgroundColor;
+ m_fieldOfViewColor = c_defaultFieldOfViewColor;
+ m_highDetailCameraView = c_defaultHighDetailCameraView;
+ m_nMaxRenderedLines = 1000;
+ m_gridDistance = c_defaultGridDistance;
+ m_gridColor = c_defaultGridColor;
+ m_axesViewStructureCreated = false;
+ m_currentVisibility = 0;
+
+ m_renderTasks.setAutoDelete( true );
+ m_matrixStack.setAutoDelete( true );
+ m_quickColors.setAutoDelete( true );
+
+ m_nViews = 0;
+
+ m_subdivisionViewStructure = PMViewStructure( maxSubdivisions + 1,
+ maxSubdivisions );
+ PMLineArray& lines = m_subdivisionViewStructure.lines( );
+ for( i = 0; i < maxSubdivisions; i++ )
+ lines[i] = PMLine( i, i+1 );
+}
+
+PMRenderManager::~PMRenderManager( )
+{
+ s_pManager = 0;
+}
+
+void PMRenderManager::addView( PMGLView* view, PMObject* active, PMObject* top,
+ PMControlPointList* controlPoints,
+ double aspectRatio, int visibilityLevel,
+ bool graphicalChange )
+{
+ PMRenderTaskListIterator it( m_renderTasks );
+ PMRenderTask* task = 0;
+ bool restart = false;
+ bool first = true;
+
+ for( ; it.current( ) && !task; ++it )
+ {
+ if( it.current( )->view( ) == view )
+ task = it.current( );
+ else
+ first = false;
+ }
+
+ if( task )
+ {
+ if( first )
+ restart = true;
+ else if( graphicalChange )
+ {
+ m_renderTasks.findRef( task );
+ m_renderTasks.take( );
+ m_renderTasks.prepend( task );
+ restart = true;
+ }
+ task->setActiveObject( active );
+ task->setTopLevelObject( top );
+ task->setControlPoints( controlPoints );
+ task->setAspectRatio( aspectRatio );
+ task->setVisibilityLevel( visibilityLevel );
+ }
+ else
+ {
+ task = new PMRenderTask( view, active, top, controlPoints, aspectRatio,
+ visibilityLevel );
+ if( graphicalChange )
+ {
+ m_renderTasks.prepend( task );
+ restart = true;
+ }
+ else
+ {
+ m_renderTasks.append( task );
+ if( m_renderTasks.count( ) == 1 )
+ restart = true;
+ }
+ }
+ if( restart )
+ restartRendering( );
+}
+
+void PMRenderManager::removeView( PMGLView* view )
+{
+ PMRenderTaskListIterator it( m_renderTasks );
+ PMRenderTask* task = 0;
+ bool restart = false;
+
+ for( ; it.current( ) && !task; ++it )
+ if( it.current( )->view( ) == view )
+ task = it.current( );
+
+ if( task )
+ {
+ if( task == m_renderTasks.first( ) )
+ {
+ restart = true;
+ if( m_bTaskIsRunning )
+ emit renderingFinished( task->view( ) );
+ }
+ m_renderTasks.removeRef( task );
+ }
+
+ if( restart )
+ restartRendering( );
+}
+
+bool PMRenderManager::containsTask( PMGLView* view ) const
+{
+ PMRenderTaskListIterator it( m_renderTasks );
+ bool contains = false;
+
+ for( ; it.current( ) && !contains; ++it )
+ if( it.current( )->view( ) == view )
+ contains = true;
+ return contains;
+}
+
+QColor PMRenderManager::controlPointColor( int i ) const
+{
+ if( ( i >= 0 ) && ( i <= 1 ) )
+ return m_controlPointColor[i];
+ return QColor( 0, 0, 0 );
+}
+
+void PMRenderManager::setControlPointColor( int i, const QColor& c )
+{
+ if( ( i >= 0 ) && ( i <= 1 ) )
+ m_controlPointColor[i] = c;
+}
+
+QColor PMRenderManager::graphicalObjectColor( int i ) const
+{
+ if( ( i >= 0 ) && ( i <= 1 ) )
+ return m_graphicalObjectColor[i];
+ return QColor( 0, 0, 0 );
+}
+
+void PMRenderManager::setGraphicalObjectColor( int i, const QColor& c )
+{
+ if( ( i >= 0 ) && ( i <= 1 ) )
+ m_graphicalObjectColor[i] = c;
+}
+
+QColor PMRenderManager::axesColor( int i ) const
+{
+ if( ( i >= 0 ) && ( i <= 2 ) )
+ return m_axesColor[i];
+ return QColor( 0, 0, 0 );
+}
+
+void PMRenderManager::setAxesColor( int i, const QColor& c )
+{
+ if( ( i >= 0 ) && ( i <= 2 ) )
+ m_axesColor[i] = c;
+}
+
+void PMRenderManager::setGridDistance( int d )
+{
+ if( d >= 20 )
+ m_gridDistance = d;
+}
+
+void PMRenderManager::restartRendering( )
+{
+ if( !m_bTaskIsRunning && !m_bStartTask )
+ startTimer( 0 );
+
+ m_bStartTask = true;
+ m_bStopTask = false;
+}
+
+void PMRenderManager::slotStopRendering( )
+{
+ m_bStopTask = true;
+ m_bStartTask = false;
+
+ if( m_bTaskIsRunning )
+ if( m_pCurrentTask )
+ emit renderingFinished( m_pCurrentTask->view( ) );
+ m_renderTasks.clear( );
+}
+
+void PMRenderManager::timerEvent( QTimerEvent* )
+{
+ killTimers( );
+ renderTask( );
+}
+
+void PMRenderManager::renderTask( )
+{
+ m_bTaskIsRunning = true;
+ emit renderingStarted( );
+
+ int r, g, b;
+ bool disableView = false;
+
+ while( m_bStartTask && !m_bStopTask )
+ {
+ m_bStartTask = false;
+
+ // render the views sequential
+ while( m_renderTasks.first( ) && !m_bStopTask && !m_bStartTask )
+ {
+ // reset the member variables for rendering
+ m_pCurrentTask = m_renderTasks.first( );
+ m_pCurrentGlView = m_pCurrentTask->view( );
+ emit renderingStarted( m_pCurrentGlView );
+
+ m_renderedLines = 0;
+ m_selected = false;
+ m_pDeselectObject = 0;
+ m_matrixStack.clear( );
+ m_quickColorObjects.clear( );
+ m_quickColors.clear( );
+ m_currentColor = m_graphicalObjectColor[0];
+ m_specialCameraMode = false;
+ m_currentVisibility = 0;
+ m_visibilityStack.clear( );
+
+ if( m_bStopTask || m_bStartTask )
+ break;
+ m_pCurrentGlView->makeCurrent( );
+
+ m_backgroundColor.rgb( &r, &g, &b );
+ glClearColor( r/255.0, g/255.0, b/255.0, 1.0 );
+ glPointSize( controlPointSize );
+ glEnable( GL_DEPTH_TEST );
+ glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
+
+ glViewport( 0, 0, ( GLint ) m_pCurrentGlView->width( ),
+ ( GLint ) m_pCurrentGlView->height( ) );
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ disableView = false;
+ if( m_pCurrentGlView->type( ) == PMGLView::PMViewCamera )
+ {
+ if( m_pCurrentGlView->camera( ) )
+ {
+ if( m_pCurrentGlView->camera( )->cameraType( )
+ == PMCamera::Omnimax )
+ disableView = true;
+ }
+ else
+ disableView = true;
+ }
+
+ if( !disableView )
+ setProjection( );
+
+ glLoadIdentity( );
+
+ glDisable( GL_DEPTH_TEST );
+ if( m_pCurrentGlView->type( ) == PMGLView::PMViewCamera )
+ renderFieldOfView( );
+ else
+ renderGrid( );
+ renderDescription( );
+ glEnable( GL_DEPTH_TEST );
+
+ if( !disableView )
+ {
+ renderAxes( );
+
+ renderObject( m_pCurrentTask->topLevelObject( ) );
+ if( !m_bStopTask && ! m_bStartTask )
+ renderControlPoints( );
+ }
+
+ if( !m_bStopTask && ! m_bStartTask )
+ {
+ glXWaitX( );
+ emit aboutToUpdate( m_pCurrentGlView );
+ if( m_bStopTask || m_bStartTask )
+ break;
+ glXWaitX( );
+ m_pCurrentGlView->swapBuffers( );
+ glFinish( );
+ glXWaitGL( );
+ emit renderingFinished( m_pCurrentGlView );
+ if( m_bStopTask || m_bStartTask )
+ break;
+ qApp->processEvents( maxEventTime );
+ if( m_bStopTask || m_bStartTask )
+ break;
+ m_renderTasks.removeFirst( );
+ }
+ }
+ }
+
+ emit renderingFinished( );
+
+ m_bStopTask = false;
+ m_bStartTask = false;
+ m_bTaskIsRunning = false;
+}
+
+void PMRenderManager::renderObject( PMObject* objectToRender )
+{
+ bool children = false;
+ PMGraphicalObject* go = 0;
+
+ m_objectToRenderStack.append( objectToRender );
+
+ if( objectToRender->isA( "GraphicalObject" ) )
+ {
+ go = ( PMGraphicalObject* ) objectToRender;
+ m_visibilityStack.push( m_currentVisibility );
+ if( go->isVisibilityLevelRelative( ) )
+ m_currentVisibility += go->visibilityLevel( );
+ else
+ m_currentVisibility = go->visibilityLevel( );
+ }
+
+ if( !m_selected )
+ {
+ if( objectToRender->isSelected( ) )
+ {
+ m_selected = true;
+ m_pDeselectObject = objectToRender;
+ if( objectToRender->hasTransformationMatrix( ) )
+ if( objectToRender->parent( ) )
+ m_pDeselectObject = objectToRender->parent( );
+ }
+ }
+
+ if( ( m_pCurrentGlView->type( ) != PMGLView::PMViewCamera )
+ || ( objectToRender != ( PMObject* ) ( m_pCurrentGlView->camera( ) ) ) )
+ {
+ PMObject* obj = 0;
+
+ children = objectToRender->lastChild( ) || objectToRender->linkedObject( );
+ if( children )
+ {
+ bool stop;
+
+ PMMatrix* matrix;
+ if( m_specialCameraMode )
+ matrix = new PMMatrix( m_viewTransformation );
+ else
+ matrix = new PMMatrix( PMMatrix::modelviewMatrix( ) );
+ m_matrixStack.push( matrix );
+
+ // render the children and the linked object
+ obj = objectToRender->lastChild( );
+ while( obj && !m_bStopTask && !m_bStartTask )
+ {
+ if( !obj->isA( "Declare" ) )
+ renderObject( obj );
+ if( !m_bStopTask && !m_bStartTask )
+ {
+ do
+ {
+ // Do not render declares
+ obj = obj->prevSibling( );
+ if( !obj )
+ stop = true;
+ else
+ stop = !obj->isA( "Declare" );
+ }
+ while( !stop );
+ }
+ }
+ if( !m_bStopTask && !m_bStartTask )
+ {
+ obj = objectToRender->linkedObject( );
+ if( obj )
+ renderObject( obj );
+ }
+ }
+
+
+ if( !m_bStopTask && !m_bStartTask )
+ {
+ // children of the object are rendered
+ // render the object
+
+ if( objectToRender == m_pCurrentTask->activeObject( ) )
+ {
+ if( m_specialCameraMode )
+ m_controlPointTransformation = m_viewTransformation;
+ else
+ m_controlPointTransformation = PMMatrix::modelviewMatrix( );
+ }
+
+ if( objectToRender->type( ) == "QuickColor" )
+ {
+ PMQuickColor* qc = ( PMQuickColor* ) objectToRender;
+ PMObjectListIterator it( m_objectToRenderStack );
+ bool pofound = false;
+ it.toLast( );
+
+ while( it.current( ) && !pofound )
+ {
+ if( it.current( )->isA( "GraphicalObject" ) )
+ pofound = true;
+ else
+ --it;
+ }
+ if( pofound )
+ {
+ if( m_quickColorObjects.top( ) != it.current( ) )
+ {
+ m_quickColorObjects.push( it.current( ) );
+ m_quickColors.push( new QColor( m_currentColor ) );
+ m_currentColor = qc->color( ).toQColor( );
+ }
+ }
+ }
+
+ PMViewStructure* vs = objectToRender->viewStructure( );
+ if( objectToRender->hasTransformationMatrix( ) || vs )
+ {
+ // object has transformation or view structure
+ if( vs )
+ {
+ if( ( m_currentVisibility <= m_pCurrentTask->visibilityLevel( ) )
+ || ( objectToRender == m_pCurrentTask->activeObject( ) ) )
+ {
+ // render the view structure.
+ // call qApp->processEvents( ) each m_nMaxRenderedLines rendered
+ // lines
+ if( m_selected )
+ setGLColor( m_graphicalObjectColor[ 1 ] );
+ else
+ setGLColor( m_currentColor );
+
+ renderViewStructure( *vs );
+ }
+ }
+ else if( objectToRender->hasTransformationMatrix( ) )
+ {
+ if( m_specialCameraMode )
+ m_viewTransformation = m_viewTransformation * objectToRender->transformationMatrix( );
+ else
+ glMultMatrixd( objectToRender->transformationMatrix( ).data( ) );
+ }
+ }
+ // end rendering
+ }
+ }
+ if( !m_bStopTask && !m_bStartTask )
+ {
+ if( children )
+ {
+ PMMatrix* matrix = m_matrixStack.pop( );
+
+ if( matrix )
+ {
+ if( m_specialCameraMode )
+ m_viewTransformation = (*matrix);
+ else
+ glLoadMatrixd( matrix->data( ) );
+ delete matrix;
+ matrix = 0;
+ }
+ }
+ if( m_selected )
+ {
+ if( m_pDeselectObject == objectToRender )
+ {
+ m_selected = false;
+ m_pDeselectObject = 0;
+ }
+ }
+ if( m_quickColorObjects.top( ) == objectToRender )
+ {
+ m_quickColorObjects.pop( );
+ QColor* col = m_quickColors.pop( );
+ if( col )
+ {
+ m_currentColor = *col;
+ delete col;
+ col = 0;
+ }
+ }
+ }
+
+ if( go )
+ m_currentVisibility = m_visibilityStack.pop( );
+
+ m_objectToRenderStack.removeLast( );
+}
+
+void PMRenderManager::renderViewStructure( PMViewStructure& vs )
+{
+ if( m_specialCameraMode )
+ {
+ PMPointArray points = vs.points( );
+ points.detach( );
+ transformProjection( points.data( ), points.size( ),
+ m_pCurrentGlView->camera( ) );
+
+ if( m_highDetailCameraView )
+ {
+ // subdivide line
+ PMLineArray& lines = vs.lines( );
+ PMPointArray& utPoints = vs.points( );
+ int numLines = lines.size( );
+ PMPointArray& sdPoints = m_subdivisionViewStructure.points( );
+ PMLineArray& sdLines = m_subdivisionViewStructure.lines( );
+ int i, li, sd;
+ double distance;
+ PMPoint start, end, dir;
+
+ for( i = 0; ( i < numLines ) && !m_bStopTask && !m_bStartTask; i++ )
+ {
+ // calculate screen distance
+ start = points[lines[i].startPoint( )];
+ end = points[lines[i].endPoint( )];
+ dir[0] = ( end[0] - start[0] ) / m_anglex;
+ dir[1] = ( end[1] - start[1] ) / m_angley;
+ distance = sqrt( dir[0] * dir[0] + dir[1] * dir[1] );
+
+ // calculate number of subdivisions
+ sd = ( int ) ( distance / subdivisionDistance );
+ if( sd > 1 )
+ {
+ // calculate subdivision
+ if( sd > maxSubdivisions )
+ sd = maxSubdivisions;
+
+ sdPoints[0] = start;
+ sdPoints[sd] = end;
+
+ start = utPoints[lines[i].startPoint( )];
+ end = utPoints[lines[i].endPoint( )];
+ dir[0] = ( end[0] - start[0] ) / sd;
+ dir[1] = ( end[1] - start[1] ) / sd;
+ dir[2] = ( end[2] - start[2] ) / sd;
+
+ for( li = 1; li < sd; li++ )
+ {
+ sdPoints[li][0] = start[0] + li * dir[0];
+ sdPoints[li][1] = start[1] + li * dir[1];
+ sdPoints[li][2] = start[2] + li * dir[2];
+ }
+ // transform points (first and last are already transformed)
+ transformProjection( sdPoints.data( ) + 1, sd - 1,
+ m_pCurrentGlView->camera( ) );
+ renderViewStructureSimple( sdPoints, sdLines, sd );
+ }
+ else
+ {
+ sdPoints[0] = start;
+ sdPoints[1] = end;
+ renderViewStructureSimple( sdPoints, sdLines, 1 );
+ }
+ }
+ }
+ else
+ renderViewStructureSimple( points, vs.lines( ) );
+ }
+ else
+ renderViewStructureSimple( vs.points( ), vs.lines( ) );
+}
+
+void PMRenderManager::renderViewStructureSimple( PMPointArray& points,
+ PMLineArray& lines,
+ int numberOfLines )
+{
+ GLuint* linesData = ( GLuint* ) ( lines.data( ) );
+ unsigned int vsLines = 0;
+ unsigned int rl;
+
+ if( numberOfLines < 0 )
+ vsLines = lines.size( );
+ else
+ vsLines = ( unsigned ) numberOfLines;
+
+ glEnableClientState( GL_VERTEX_ARRAY );
+ glVertexPointer( 3, GL_DOUBLE, 0, points.data( ) );
+
+ while( ( vsLines > 0 ) && !m_bStopTask && !m_bStartTask )
+ {
+ rl = m_nMaxRenderedLines - m_renderedLines;
+ if( rl > vsLines )
+ rl = vsLines;
+
+ glDrawElements( GL_LINES, rl * 2,
+ GL_UNSIGNED_INT, linesData );
+
+ m_renderedLines += rl;
+ if( m_renderedLines >= m_nMaxRenderedLines )
+ {
+ m_renderedLines = 0;
+ qApp->processEvents( maxEventTime );
+ if( !m_bStopTask && !m_bStartTask )
+ m_pCurrentGlView->makeCurrent( );
+ }
+
+ vsLines -= rl;
+ linesData = linesData + ( rl * 2 );
+ }
+
+ glDisableClientState( GL_VERTEX_ARRAY );
+}
+
+void PMRenderManager::transformProjection( PMPoint* points, int size,
+ PMCamera* camera )
+{
+ int i;
+ PMPoint* data = points;
+ PMPoint p;
+ double cameraAngle = camera->angle( ) * M_PI / 180.0;
+ double rad, phi, h;
+
+ if( approxZero( cameraAngle ) )
+ cameraAngle = M_PI;
+
+ switch( camera->cameraType( ) )
+ {
+ case PMCamera::Perspective:
+ case PMCamera::Orthographic:
+ break;
+
+ case PMCamera::UltraWideAngle:
+ for( i = 0; i < size; i++ )
+ {
+ p = m_viewTransformation * (*data);
+
+ // reverse povray's calculations
+ p[0] /= m_rightLength;
+ p[1] /= m_upLength;
+ p[2] /= m_directionLength;
+ h = sqrt( p[0] * p[0] + p[1] * p[1] + p[2] * p[2] );
+ if( !approxZero( h ) )
+ {
+ p[0] /= h;
+ p[1] /= h;
+ }
+
+ (*data)[0] = asin( p[0] );
+ (*data)[1] = asin( p[1] );
+ if( p[2] > 0 )
+ {
+ (*data)[0] = M_PI - (*data)[0];
+ (*data)[1] = M_PI - (*data)[1];
+ }
+ (*data)[2] = -h;
+
+ data++;
+ }
+ break;
+
+ case PMCamera::FishEye:
+ for( i = 0; i < size; i++ )
+ {
+ p = m_viewTransformation * (*data);
+
+ // reverse povray's calculations
+ phi = atan2( p[1], p[0] );
+ rad = atan2( sqrt( p[0] * p[0] + p[1] * p[1] ), -p[2] );
+
+ (*data)[0] = rad * cos( phi );
+ (*data)[1] = rad * sin( phi );
+ (*data)[2] = -sqrt( p[0] * p[0] + p[1] * p[1] + p[2] * p[2] );
+
+ data++;
+ }
+ break;
+
+ case PMCamera::Panoramic:
+ for( i = 0; i < size; i++ )
+ {
+ p = m_viewTransformation * (*data);
+
+ // reverse povray's calculations
+ p[0] /= m_rightLength;
+ p[1] /= m_upLength;
+ p[2] /= m_directionLength;
+
+ (*data)[0] = atan2( p[0], -p[2] );
+ (*data)[1] = atan2( p[1], sqrt( p[0] * p[0] + p[2] * p[2] ) );
+ (*data)[2] = -sqrt( p[0] * p[0] + p[1] * p[1] + p[2] * p[2] );
+
+ data++;
+ }
+ break;
+
+ case PMCamera::Cylinder:
+ switch( camera->cylinderType( ) )
+ {
+ case 1:
+ for( i = 0; i < size; i++ )
+ {
+ p = m_viewTransformation * (*data);
+
+ // reverse povray's calculations
+ p[0] /= m_rightLength;
+ p[1] /= m_upLength;
+ p[2] /= m_directionLength;
+
+ h = sqrt( p[0] * p[0] + p[2] * p[2] );
+ if( approxZero( h ) )
+ h = 1e-5;
+
+ (*data)[0] = atan2( p[0], -p[2] ) / cameraAngle;
+ (*data)[1] = p[1] / h;
+ (*data)[2] = -h;
+
+ data++;
+ }
+ break;
+
+ case 2:
+ for( i = 0; i < size; i++ )
+ {
+ p = m_viewTransformation * (*data);
+
+ // reverse povray's calculations
+ p[0] /= m_rightLength;
+ p[1] /= m_upLength;
+ p[2] /= m_directionLength;
+
+ h = sqrt( p[1] * p[1] + p[2] * p[2] );
+ if( approxZero( h ) )
+ h = 1e-5;
+
+ (*data)[0] = p[0] / h;
+ (*data)[1] = atan2( p[1], -p[2] ) / cameraAngle;
+ (*data)[2] = -h;
+
+ data++;
+ }
+ break;
+
+ case 3:
+ for( i = 0; i < size; i++ )
+ {
+ p = m_viewTransformation * (*data);
+
+ // reverse povray's calculations
+ p[0] /= m_rightLength;
+ p[1] /= m_upLength;
+ p[2] /= m_directionLength;
+
+ h = sqrt( p[0] * p[0] + p[2] * p[2] );
+ if( approxZero( h ) )
+ h = 1e-5;
+
+ (*data)[0] = atan2( p[0], -p[2] ) / cameraAngle;
+ (*data)[1] = p[1];
+ (*data)[2] = -h;
+
+ data++;
+ }
+ break;
+
+ case 4:
+ for( i = 0; i < size; i++ )
+ {
+ p = m_viewTransformation * (*data);
+
+ // reverse povray's calculations
+ p[0] /= m_rightLength;
+ p[1] /= m_upLength;
+ p[2] /= m_directionLength;
+
+ h = sqrt( p[1] * p[1] + p[2] * p[2] );
+ if( approxZero( h ) )
+ h = 1e-5;
+
+ (*data)[0] = p[0];
+ (*data)[1] = atan2( p[1], -p[2] ) / cameraAngle;
+ (*data)[2] = -h;
+
+ data++;
+ }
+ break;
+ }
+ break;
+
+ case PMCamera::Omnimax:
+ break;
+
+ }
+}
+
+void PMRenderManager::renderControlPoints( )
+{
+ if( ( m_pCurrentGlView->type( ) == PMGLView::PMViewCamera )
+ && ( m_pCurrentGlView->camera( ) == m_pCurrentTask->activeObject( ) ) )
+ return;
+
+ if( m_specialCameraMode )
+ m_viewTransformation = m_controlPointTransformation;
+ else
+ glLoadMatrixd( m_controlPointTransformation.data( ) );
+
+ PMControlPointList* cplist = m_pCurrentTask->controlPoints( );
+ if( cplist->count( ) > 0 )
+ {
+ PMControlPointListIterator it( *cplist );
+ PMControlPoint* cp;
+ PMPoint v;
+ const GLubyte* bitmap = 0;
+
+ // draw extra control point lines
+ setGLColor( m_graphicalObjectColor[1] );
+ for( it.toFirst( ); it.current( ); ++it )
+ {
+ cp = it.current( );
+ if( cp->hasExtraLine( ) )
+ {
+ PMPoint s = PMPoint( cp->extraLineStart( ) );
+ PMPoint e = PMPoint( cp->extraLineEnd( ) );
+
+ if( m_specialCameraMode )
+ {
+ transformProjection( &s, 1, m_pCurrentGlView->camera( ) );
+ transformProjection( &e, 1, m_pCurrentGlView->camera( ) );
+ }
+
+ glBegin( GL_LINES );
+ glVertex3d( s[0], s[1], s[2] );
+ glVertex3d( e[0], e[1], e[2] );
+ glEnd( );
+ }
+ }
+
+ glDisable( GL_DEPTH_TEST );
+ // draw not selected control points
+ setGLColor( m_controlPointColor[0] );
+ for( it.toFirst( ); it.current( ); ++it )
+ {
+ cp = it.current( );
+
+ if( cp->display( ) )
+ {
+ v = PMPoint( cp->position( ) );
+ if( m_specialCameraMode )
+ transformProjection( &v, 1, m_pCurrentGlView->camera( ) );
+ switch( cp->displayType( ) )
+ {
+ case PMControlPoint::CPPoint:
+ if( !cp->selected( ) )
+ bitmap = PointBitmap;
+ break;
+ case PMControlPoint::CPCross:
+ bitmap = CrossBitmap;
+ break;
+ }
+
+ glRasterPos3d( v[0], v[1], v[2] );
+ if( bitmap )
+ glBitmap( controlPointSize, controlPointSize,
+ controlPointSize/2, controlPointSize/2,
+ 0, 0, bitmap );
+ }
+ }
+ // draw selected control points
+ setGLColor( m_controlPointColor[1] );
+ for( it.toFirst( ); it.current( ); ++it )
+ {
+ cp = it.current( );
+
+ if( cp->selected( ) && cp->display( ) )
+ {
+ v = PMPoint( cp->position( ) );
+ if( m_specialCameraMode )
+ transformProjection( &v, 1, m_pCurrentGlView->camera( ) );
+ if( cp->displayType( ) == PMControlPoint::CPPoint )
+ bitmap = PointBitmap;
+
+ glRasterPos3d( v[0], v[1], v[2] );
+ if( bitmap )
+ glBitmap( controlPointSize, controlPointSize,
+ controlPointSize/2, controlPointSize/2,
+ 0, 0, bitmap );
+ }
+ }
+ }
+}
+
+void PMRenderManager::renderAxes( )
+{
+ int i;
+
+ if( !m_axesViewStructureCreated )
+ {
+ m_axesViewStructure[0] = PMViewStructure( 6, 9 );
+ PMPointArray& points = m_axesViewStructure[0].points( );
+ PMLineArray& lines = m_axesViewStructure[0].lines( );
+
+ lines[0] = PMLine( 0, 1 );
+ lines[1] = PMLine( 1, 2 );
+ lines[2] = PMLine( 1, 3 );
+ lines[3] = PMLine( 1, 4 );
+ lines[4] = PMLine( 1, 5 );
+ lines[5] = PMLine( 2, 3 );
+ lines[6] = PMLine( 3, 4 );
+ lines[7] = PMLine( 4, 5 );
+ lines[8] = PMLine( 5, 2 );
+
+ points[0] = PMPoint( 0.0, 0.0, 0.0 );
+ points[1] = PMPoint( 1.0, 0.0, 0.0 );
+ points[2] = PMPoint( dA, dB, dB );
+ points[3] = PMPoint( dA, -dB, dB );
+ points[4] = PMPoint( dA, -dB, -dB );
+ points[5] = PMPoint( dA, dB, -dB );
+
+ m_axesViewStructure[1] = m_axesViewStructure[0];
+ PMPointArray& points1 = m_axesViewStructure[1].points( );
+ points1.detach( );
+
+ points1[0] = PMPoint( 0.0, 0.0, 0.0 );
+ points1[1] = PMPoint( 0.0, 1.0, 0.0 );
+ points1[2] = PMPoint( dB, dA, dB );
+ points1[3] = PMPoint( -dB, dA, dB );
+ points1[4] = PMPoint( -dB, dA, -dB );
+ points1[5] = PMPoint( dB, dA, -dB );
+
+ m_axesViewStructure[2] = m_axesViewStructure[0];
+ PMPointArray& points2 = m_axesViewStructure[2].points( );
+ points2.detach( );
+
+ points2[0] = PMPoint( 0.0, 0.0, 0.0 );
+ points2[1] = PMPoint( 0.0, 0.0, 1.0 );
+ points2[2] = PMPoint( dB, dB, dA );
+ points2[3] = PMPoint( -dB, dB, dA );
+ points2[4] = PMPoint( -dB, -dB, dA );
+ points2[5] = PMPoint( dB, -dB, dA );
+
+ m_axesViewStructureCreated = true;
+ }
+
+ glEnable( GL_DEPTH_TEST );
+ for( i = 0; i < 3; i++ )
+ {
+ setGLColor( m_axesColor[i] );
+ renderViewStructure( m_axesViewStructure[i] );
+ }
+}
+
+PMMatrix PMRenderManager::viewTransformation( PMCamera* c ) const
+{
+ PMVector location, lookAt, sky;
+ PMMatrix m;
+
+ sky = c->sky( );
+ location = c->location( );
+ lookAt = c->lookAt( );
+
+ if( approxZero( sky.abs( ) ) )
+ sky = PMVector( 0.0, 1.0, 0.0 );
+ if( approxZero( ( location - lookAt ).abs( ) ) )
+ lookAt = location + PMVector( 0.0, 0.0, 1.0 );
+
+ m = c->transformedWith( );
+ if( m.canBuildInverse( ) )
+ return PMMatrix::viewTransformation( location, lookAt, sky ) * m.inverse( );
+ return PMMatrix::viewTransformation( location, lookAt, sky );
+}
+
+void PMRenderManager::setProjection( )
+{
+ PMGLView::PMViewType type = m_pCurrentGlView->type( );
+ PMCamera* camera = m_pCurrentGlView->camera( );
+ int width = m_pCurrentGlView->width( );
+ int height = m_pCurrentGlView->height( );
+
+ if( type == PMGLView::PMViewCamera )
+ {
+ if( camera )
+ setCameraProjection( );
+ }
+ else
+ {
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity( );
+
+ double d = m_pCurrentGlView->scale( );
+
+ // TODO calculating the z clipping plane
+ glOrtho( -width/2, width/2, -height/2, height/2,
+ -viewVolumeZ, viewVolumeZ );
+ glScaled( d, d, d );
+ glTranslated( m_pCurrentGlView->translationX( ),
+ m_pCurrentGlView->translationY( ), 0 );
+
+ switch( type )
+ {
+ case PMGLView::PMViewPosZ:
+ break;
+ case PMGLView::PMViewNegZ:
+ glRotated( 180.0, 0.0, 1.0, 0.0 );
+ break;
+ case PMGLView::PMViewNegY:
+ glRotated( 90.0, 1.0, 0.0, 0.0 );
+ break;
+ case PMGLView::PMViewPosY:
+ glRotated( -90.0, 1.0, 0.0, 0.0 );
+ break;
+ case PMGLView::PMViewPosX:
+ glRotated( 90.0, 0.0, 1.0, 0.0 );
+ break;
+ case PMGLView::PMViewNegX:
+ glRotated( -90.0, 0.0, 1.0, 0.0 );
+ break;
+ default:
+ break;
+ }
+
+ glScaled( 1.0, 1.0, -1.0 );
+
+ glMatrixMode( GL_MODELVIEW );
+ m_pCurrentGlView->setProjectionUpToDate( true );
+ }
+}
+
+void PMRenderManager::setCameraProjection( )
+{
+ PMCamera* camera = m_pCurrentGlView->camera( );
+ int width = m_pCurrentGlView->width( );
+ int height = m_pCurrentGlView->height( );
+ double angle = M_PI / 2.0;
+ double modeAspect, viewAspect, cameraAspect;
+
+ m_viewTransformation = viewTransformation( camera );
+ m_upLength = camera->up( ).abs( );
+ if( approxZero( m_upLength ) )
+ m_upLength = 1.0;
+ m_rightLength = camera->right( ).abs( );
+ if( approxZero( m_rightLength ) )
+ m_rightLength = 1.0;
+ m_directionLength = camera->direction( ).abs( );
+ if( approxZero( m_directionLength ) )
+ m_directionLength = 1.0;
+
+ if( camera->isAngleEnabled( ) )
+ angle = camera->angle( ) * M_PI / 180.0;
+
+ m_anglex = 0.5;
+ m_angley = 0.5;
+ if( ( angle <= 0.0 ) || ( angle > 2 * M_PI ) )
+ angle = M_PI;
+
+ switch( camera->cameraType( ) )
+ {
+ case PMCamera::Perspective:
+ // If angle wasn't specified determine one from right and direction
+ if( !camera->isAngleEnabled( ) )
+ angle = 2 * atan2( 0.5 * m_rightLength, m_directionLength );
+ break;
+ case PMCamera::UltraWideAngle:
+ m_anglex = angle / ( 2.0 * M_PI );
+ m_angley = angle / ( 2.0 * M_PI );
+ m_specialCameraMode = true;
+ break;
+ case PMCamera::FishEye:
+ m_anglex = angle / 2.0;
+ m_angley = angle / 2.0;
+ m_specialCameraMode = true;
+ break;
+ case PMCamera::Panoramic:
+ m_anglex = M_PI / 2.0;
+ m_angley = M_PI / 2.0;
+ m_specialCameraMode = true;
+ break;
+ case PMCamera::Cylinder:
+ m_anglex = 0.5;
+ m_angley = 0.5;
+ m_specialCameraMode = true;
+ break;
+ case PMCamera::Omnimax:
+ m_specialCameraMode = true;
+ break;
+ default:
+ break;
+ }
+
+ modeAspect = m_pCurrentTask->aspectRatio( );
+ if( approxZero( modeAspect ) )
+ modeAspect = 1.0;
+ cameraAspect = camera->aspect( );
+ if( approxZero( cameraAspect ) )
+ cameraAspect = 1.0;
+ viewAspect = ( double ) width / ( double ) height;
+ if( approxZero( viewAspect ) )
+ viewAspect = 1.0;
+
+ if( viewAspect > modeAspect )
+ m_anglex *= viewAspect / modeAspect;
+ else
+ m_angley *= modeAspect / viewAspect;
+
+
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity( );
+
+
+ PMVector up, right, direction;
+ double handedness;
+ PMMatrix m;
+
+ up = camera->up( );
+ right = camera->right( );
+ direction = camera->direction( );
+
+ if( approxZero( m_upLength ) )
+ up = PMVector( 0.0, 1.0, 0.0 );
+ if( approxZero( m_rightLength ) )
+ right = PMVector( 1.0, 0.0, 0.0 );
+ if( approxZero( m_directionLength ) )
+ direction = PMVector( 0.0, 0.0, 1.0 );
+
+ handedness = PMVector::dot( PMVector::cross( up, direction ), right );
+
+ switch( camera->cameraType( ) )
+ {
+ case PMCamera::Perspective:
+ if( ( angle <= 0.0 ) || ( angle >= M_PI ) )
+ angle = M_PI / 2.0;
+
+ // opengl needs the vertical angle
+ if( viewAspect < modeAspect )
+ angle = atan( tan( angle / 2.0 ) / cameraAspect * modeAspect
+ / viewAspect ) * 360.0 / M_PI;
+ else
+ angle = atan( tan( angle / 2.0 ) / cameraAspect )
+ * 360.0 / M_PI;
+
+ gluPerspective( angle, cameraAspect * viewAspect / modeAspect,
+ 0.001, viewVolumeZ );
+
+ if( handedness > 0 )
+ glScaled( -1.0, 1.0, 1.0 );
+
+ glMultMatrixd( m_viewTransformation.data( ) );
+ break;
+
+ case PMCamera::Orthographic:
+ m_anglex = m_rightLength / 2.0;
+ m_angley = m_upLength / 2.0;
+
+ if( viewAspect > modeAspect )
+ m_anglex *= viewAspect / modeAspect;
+ else
+ m_angley *= modeAspect / viewAspect;
+
+ glOrtho( -m_anglex, m_anglex, -m_angley, m_angley,
+ 0, viewVolumeZ );
+
+ if( handedness > 0 )
+ glScaled( -1.0, 1.0, 1.0 );
+
+ glMultMatrixd( m_viewTransformation.data( ) );
+ break;
+
+ case PMCamera::UltraWideAngle:
+ case PMCamera::FishEye:
+ case PMCamera::Panoramic:
+ case PMCamera::Cylinder:
+ case PMCamera::Omnimax:
+ glOrtho( -m_anglex, m_anglex, -m_angley, m_angley,
+ -viewVolumeZ, viewVolumeZ );
+
+ if( handedness > 0 )
+ glScaled( -1.0, 1.0, 1.0 );
+ break;
+ }
+
+ glMatrixMode( GL_MODELVIEW );
+ m_pCurrentGlView->setProjectionUpToDate( true );
+}
+
+void PMRenderManager::renderFieldOfView( )
+{
+ if( m_pCurrentGlView->type( ) == PMGLView::PMViewCamera )
+ {
+ PMCamera* camera = m_pCurrentGlView->camera( );
+
+ if( camera )
+ {
+ int width = m_pCurrentGlView->width( );
+ int height = m_pCurrentGlView->height( );
+ double modeAspect, viewAspect;
+ int d, vx1, vx2, vy1, vy2;
+
+ modeAspect = m_pCurrentTask->aspectRatio( ); //camera->aspect( );
+ if( approxZero( modeAspect ) )
+ modeAspect = 1.0;
+ viewAspect = ( double ) width / ( double ) height;
+
+ if( viewAspect < modeAspect )
+ {
+ vx1 = 0;
+ vx2 = width - 1;
+
+ d = ( int ) ( height - width / modeAspect + 0.5 ) / 2;
+
+ vy1 = d;
+ vy2 = height - d - 1;
+ }
+ else
+ {
+ vy1 = 0;
+ vy2 = height - 1;
+
+ d = ( int ) ( height * modeAspect );
+
+ d = ( width - d ) / 2;
+ vx1 = d;
+ vx2 = width - d - 1;
+ }
+
+ glMatrixMode( GL_PROJECTION );
+ glPushMatrix( );
+ glLoadIdentity( );
+ glOrtho( 0, width, 0, height, -2, 2 );
+ glMatrixMode( GL_MODELVIEW );
+ glPushMatrix( );
+ glLoadIdentity( );
+
+ setGLColor( m_fieldOfViewColor );
+ glDisable( GL_DEPTH_TEST );
+
+ if( camera->cameraType( ) == PMCamera::Omnimax )
+ renderString( i18n( "not supported" ), 5.0,
+ height - qApp->fontMetrics( ).height( ) * 2 - 2 );
+ else if( m_specialCameraMode && !m_highDetailCameraView )
+ renderString( i18n( "approximated" ), 5.0,
+ height - qApp->fontMetrics( ).height( ) * 2 - 2 );
+
+ glBegin( GL_LINE_LOOP );
+
+ glVertex2d( vx1, vy1 );
+ glVertex2d( vx2, vy1 );
+ glVertex2d( vx2, vy2 );
+ glVertex2d( vx1, vy2 );
+
+ glEnd( );
+ glEnable( GL_DEPTH_TEST );
+
+ glMatrixMode( GL_PROJECTION );
+ glPopMatrix( );
+ glMatrixMode( GL_MODELVIEW );
+ glPopMatrix( );
+ }
+ }
+}
+
+void PMRenderManager::renderGrid( )
+{
+ double scale = m_pCurrentGlView->scale( );
+
+ if( scale >= 0 )
+ {
+ // calculate the views grid distance
+ double viewGridDistance = pow( 10.0, ceil( log10( ( double ) m_gridDistance / scale ) ) );
+ int sd = ( int ) ( viewGridDistance * scale + 0.5 );
+ if( ( sd * 0.2 ) > m_gridDistance )
+ viewGridDistance *= 0.2;
+ else if( ( sd * 0.5 ) > m_gridDistance )
+ viewGridDistance *= 0.5;
+
+ // draw the grid
+ double x1, x2, y1, y2, sx, sy;
+ double x, y;
+ int gi;
+ double screenx, screeny;
+ double signx = 1.0, signy = 1.0;
+
+ int height = m_pCurrentGlView->height( );
+ int width = m_pCurrentGlView->width( );
+ double transX = m_pCurrentGlView->translationX( );
+ double transY = m_pCurrentGlView->translationY( );
+ int fontHeight = qApp->fontMetrics( ).height( );
+
+ glMatrixMode( GL_PROJECTION );
+ glPushMatrix( );
+ glLoadIdentity( );
+ glOrtho( -width/2, width/2, -height/2, height/2, -2, 2 );
+
+ glMatrixMode( GL_MODELVIEW );
+ glPushMatrix( );
+ glLoadIdentity( );
+
+ setGLColor( m_gridColor );
+ glDisable( GL_DEPTH_TEST );
+
+ switch( m_pCurrentGlView->type( ) )
+ {
+ case PMGLView::PMViewPosX:
+ signx = -1.0;
+ break;
+ case PMGLView::PMViewPosY:
+ signy = -1.0;
+ break;
+ case PMGLView::PMViewNegZ:
+ signx = -1.0;
+ break;
+ default:
+ break;
+ }
+
+ sx = width / scale;
+ sy = height / scale;
+ x1 = -transX - sx / 2;
+ x2 = -transX + sx / 2;
+ y1 = -transY - sy / 2;
+ y2 = -transY + sy / 2;
+
+ sx = ceil( x1 / viewGridDistance ) * viewGridDistance;
+ gi = 0;
+ x = sx;
+ while( x < x2 )
+ {
+ screenx = ( x + transX ) * scale;
+ glBegin( GL_LINES );
+ glVertex2d( screenx, -height/2 );
+ glVertex2d( screenx, height/2 );
+ glEnd( );
+
+ QString label = QString( "%1" ).arg( x * signx, 0, 'g', 4 );
+ if( approxZero( x ) && label.find( "e-" ) )
+ label = "0";
+
+ renderString( label, screenx + 3, height / 2 - fontHeight - 2 );
+
+ gi++;
+ x = sx + viewGridDistance * gi;
+ }
+
+ sy = ceil( y1 / viewGridDistance ) * viewGridDistance;
+ gi = 0;
+ y = sy;
+ while( y < y2 )
+ {
+ screeny = ( y + transY ) * scale;
+ glBegin( GL_LINES );
+ glVertex2d( -width/2, screeny );
+ glVertex2d( width/2, screeny );
+ glEnd( );
+
+ QString label = QString( "%1" ).arg( y * signy, 0, 'g', 4 );
+ if( approxZero( y ) && label.find( "e-" ) )
+ label = "0";
+
+ renderString( label, -width / 2 + 3, screeny + 2 );
+
+ gi++;
+ y = sy + viewGridDistance * gi;
+ }
+
+
+ setGLColor( axesColor( 0 ) );
+ switch( m_pCurrentGlView->type( ) )
+ {
+ case PMGLView::PMViewPosY:
+ case PMGLView::PMViewPosZ:
+ case PMGLView::PMViewNegY:
+ renderString( "x", width / 2 - qApp->fontMetrics( ).boundingRect( "x" ).width( ) - 4, -3 );
+ break;
+ case PMGLView::PMViewNegZ:
+ renderString( "x", -width / 2 + 3, -3 );
+ break;
+ default:
+ break;
+ }
+ setGLColor( axesColor( 1 ) );
+ switch( m_pCurrentGlView->type( ) )
+ {
+ case PMGLView::PMViewPosX:
+ case PMGLView::PMViewNegX:
+ case PMGLView::PMViewPosZ:
+ case PMGLView::PMViewNegZ:
+ renderString( "y", -3, height / 2 - fontHeight );
+ break;
+ default:
+ break;
+ }
+ setGLColor( axesColor( 2 ) );
+ switch( m_pCurrentGlView->type( ) )
+ {
+ case PMGLView::PMViewPosX:
+ renderString( "z", -width / 2 + 3, -3 );
+ break;
+ case PMGLView::PMViewNegX:
+ renderString( "z", width / 2 - qApp->fontMetrics( ).boundingRect( "z" ).width( ) - 4, -3 );
+ break;
+ case PMGLView::PMViewNegY:
+ renderString( "z", -3, height / 2 - fontHeight );
+ break;
+ case PMGLView::PMViewPosY:
+ renderString( "z", -3, -height / 2 );
+ break;
+ default:
+ break;
+ }
+
+ glEnable( GL_DEPTH_TEST );
+ glMatrixMode( GL_PROJECTION );
+ glPopMatrix( );
+ glMatrixMode( GL_MODELVIEW );
+ glPopMatrix( );
+ }
+}
+
+void PMRenderManager::renderDescription( )
+{
+ int height = m_pCurrentGlView->height( );
+ int width = m_pCurrentGlView->width( );
+ int fontHeight = qApp->fontMetrics( ).height( );
+
+ glMatrixMode( GL_PROJECTION );
+ glPushMatrix( );
+ glLoadIdentity( );
+ glOrtho( 0, width, 0, height, -2, 2 );
+ glMatrixMode( GL_MODELVIEW );
+ glPushMatrix( );
+ glLoadIdentity( );
+
+ setGLColor( m_fieldOfViewColor );
+
+ switch( m_pCurrentGlView->type( ) )
+ {
+ case PMGLView::PMViewPosX:
+ renderString( i18n( "left" ), 5.0, height - fontHeight - 2 );
+ break;
+ case PMGLView::PMViewNegX:
+ renderString( i18n( "right" ), 5.0, height - fontHeight - 2 );
+ break;
+ case PMGLView::PMViewPosY:
+ renderString( i18n( "bottom" ), 5.0, height - fontHeight - 2 );
+ break;
+ case PMGLView::PMViewNegY:
+ renderString( i18n( "top" ), 5.0, height - fontHeight - 2 );
+ break;
+ case PMGLView::PMViewPosZ:
+ renderString( i18n( "front" ), 5.0, height - fontHeight - 2 );
+ break;
+ case PMGLView::PMViewNegZ:
+ renderString( i18n( "back" ), 5.0, height - fontHeight - 2 );
+ break;
+ case PMGLView::PMViewCamera:
+ {
+ PMCamera* c = m_pCurrentGlView->camera( );
+ if( c )
+ {
+ QString name( "-" );
+ if( !c->name( ).isEmpty( ) )
+ name = c->name( );
+ else
+ name = i18n( "(unnamed)" );
+
+ renderString( i18n( "camera" ) + ": " + name,
+ 5.0, height - fontHeight - 2 );
+ }
+ else
+ renderString( i18n( "camera" ), 5.0, height - fontHeight - 2 );
+ break;
+ }
+ }
+
+ glEnable( GL_DEPTH_TEST );
+
+ glMatrixMode( GL_PROJECTION );
+ glPopMatrix( );
+ glMatrixMode( GL_MODELVIEW );
+ glPopMatrix( );
+}
+
+void PMRenderManager::renderString( const QString& str, double x, double y )
+{
+ int width = qApp->fontMetrics( ).boundingRect( str ).width( );
+ int height = qApp->fontMetrics( ).height( );
+
+ // GL wants word aligned bitmap
+ QBitmap bm( ( ( width + 32 ) % 32 ) * 32, height, true );
+
+ QPainter p( &bm );
+ p.setFont( qApp->font( ) );
+ p.drawText( bm.rect( ), Qt::AlignLeft | Qt::AlignBottom, str );
+ p.end();
+
+ // Transform to GL bitmap
+ QImage img = bm.convertToImage( ).mirror( ).convertBitOrder( QImage::BigEndian );
+
+ glRasterPos2d( x, y );
+ glBitmap( img.width( ), img.height( ), 0, 0, 0, 0, img.bits( ) );
+}
+
+void PMRenderManager::setGLColor( const QColor& c )
+{
+ int r, g, b;
+
+ c.rgb( &r, &g, &b );
+ glColor3ub( ( GLubyte ) r, ( GLubyte ) g, ( GLubyte ) b );
+}
+
+void PMRenderManager::slotRenderingSettingsChanged( )
+{
+ emit renderingSettingsChanged( );
+}
+
+void PMRenderManager::saveConfig( KConfig* cfg )
+{
+ cfg->setGroup( "Rendering" );
+ cfg->writeEntry( "BackgroundColor", m_backgroundColor );
+ cfg->writeEntry( "GraphicalObjectColor0", m_graphicalObjectColor[0] );
+ cfg->writeEntry( "GraphicalObjectColor1", m_graphicalObjectColor[1] );
+ cfg->writeEntry( "ControlPointColor0", m_controlPointColor[0] );
+ cfg->writeEntry( "ControlPointColor1", m_controlPointColor[1] );
+ cfg->writeEntry( "AxesColorX", m_axesColor[0] );
+ cfg->writeEntry( "AxesColorY", m_axesColor[1] );
+ cfg->writeEntry( "AxesColorZ", m_axesColor[2] );
+ cfg->writeEntry( "GridColor", m_gridColor );
+ cfg->writeEntry( "GridDistance", m_gridDistance );
+ cfg->writeEntry( "FieldOfViewColor", m_fieldOfViewColor );
+ cfg->writeEntry( "HighDetailCameraViews", m_highDetailCameraView );
+}
+
+void PMRenderManager::restoreConfig( KConfig* cfg )
+{
+ cfg->setGroup( "Rendering" );
+
+ m_backgroundColor = cfg->readColorEntry( "BackgroundColor", &m_backgroundColor );
+ m_graphicalObjectColor[0] = cfg->readColorEntry( "GraphicalObjectColor0", &( m_graphicalObjectColor[0] ) );
+ m_graphicalObjectColor[1] = cfg->readColorEntry( "GraphicalObjectColor1", &( m_graphicalObjectColor[1] ) );
+ m_controlPointColor[0] = cfg->readColorEntry( "ControlPointColor0", &( m_controlPointColor[0] ) );
+ m_controlPointColor[1] = cfg->readColorEntry( "ControlPointColor1", &( m_controlPointColor[1] ) );
+ m_axesColor[0] = cfg->readColorEntry( "AxesColorX", &( m_axesColor[0] ) );
+ m_axesColor[1] = cfg->readColorEntry( "AxesColorY", &( m_axesColor[1] ) );
+ m_axesColor[2] = cfg->readColorEntry( "AxesColorZ", &( m_axesColor[2] ) );
+ m_gridColor = cfg->readColorEntry( "GridColor", &m_gridColor );
+ m_gridDistance = cfg->readNumEntry( "GridDistance", m_gridDistance );
+ m_fieldOfViewColor = cfg->readColorEntry( "FieldOfViewColor", &m_fieldOfViewColor );
+ m_highDetailCameraView = cfg->readBoolEntry( "HighDetailCameraViews", m_highDetailCameraView );
+}
+
+bool PMRenderManager::hasOpenGL( )
+{
+ if( !s_hasOpenGLChecked )
+ {
+ s_hasOpenGL = ( glXQueryExtension( qt_xdisplay( ), 0, 0 ) != 0 );
+ s_hasOpenGLChecked = true;
+ }
+
+ return s_hasOpenGL;
+}
+
+void PMRenderManager::disableOpenGL( )
+{
+ s_hasOpenGLChecked = true;
+ s_hasOpenGL = false;
+}
+
+#include "pmrendermanager.moc"
diff --git a/kpovmodeler/pmrendermanager.h b/kpovmodeler/pmrendermanager.h
new file mode 100644
index 00000000..a29a6589
--- /dev/null
+++ b/kpovmodeler/pmrendermanager.h
@@ -0,0 +1,435 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMRENDERMANAGER_H
+#define PMRENDERMANAGER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmcontrolpoint.h"
+#include "pmmatrix.h"
+#include "pmobject.h"
+#include "pmviewstructure.h"
+
+#include <qobject.h>
+#include <qptrlist.h>
+#include <qcolor.h>
+#include <qptrstack.h>
+#include <qvaluestack.h>
+#include <kstaticdeleter.h>
+#include <GL/gl.h>
+
+class PMGLView;
+class PMCamera;
+class PMPoint;
+class KConfig;
+class QString;
+
+/**
+ * Used internally by PMRenderManager.
+ *
+ * This class stores informations for one render task.
+ */
+class PMRenderTask
+{
+public:
+ PMRenderTask( PMGLView* view, PMObject* active, PMObject* top,
+ PMControlPointList* controlPoints, double aspectRatio,
+ int visibilityLevel )
+ {
+ m_pView = view;
+ m_pActiveObject = active;
+ m_pTopLevelObject = top;
+ m_pControlPoints = controlPoints;
+ m_aspectRatio = aspectRatio;
+ m_visibilityLevel = visibilityLevel;
+ }
+
+ ~PMRenderTask( ) { };
+
+ PMGLView* view( ) const { return m_pView; }
+ PMObject* activeObject( ) const { return m_pActiveObject; }
+ PMObject* topLevelObject( ) const { return m_pTopLevelObject; }
+ PMControlPointList* controlPoints( ) const { return m_pControlPoints; }
+ double aspectRatio( ) const { return m_aspectRatio; }
+ int visibilityLevel( ) const { return m_visibilityLevel; }
+
+ void setView( PMGLView* view ) { m_pView = view; }
+ void setActiveObject( PMObject* obj ) { m_pActiveObject = obj; }
+ void setTopLevelObject( PMObject* obj ) { m_pTopLevelObject = obj; }
+ void setControlPoints( PMControlPointList* list ) { m_pControlPoints = list; }
+ void setAspectRatio( double ar ) { m_aspectRatio = ar; }
+ void setVisibilityLevel( int l ) { m_visibilityLevel = l; }
+
+private:
+ PMGLView* m_pView;
+ PMObject* m_pActiveObject;
+ PMObject* m_pTopLevelObject;
+ PMControlPointList* m_pControlPoints;
+ double m_aspectRatio;
+ int m_visibilityLevel;
+};
+
+typedef QPtrList<PMRenderTask> PMRenderTaskList;
+typedef QPtrListIterator<PMRenderTask> PMRenderTaskListIterator;
+
+/**
+ * Class that controls the background rendering
+ */
+class PMRenderManager : public QObject
+{
+ Q_OBJECT
+public:
+ /**
+ * Returns a pointer to the render manager
+ */
+ static PMRenderManager* theManager( );
+ /**
+ * destructor
+ */
+ ~PMRenderManager( );
+ /**
+ * Adds the @ref PMGLView to the list of views that have to be rendered.
+ *
+ * @param view The view
+ * @param active The active object
+ * @param top The top level object (normally the scene)
+ * @param controlPoints A pointer to the list of control points for the
+ * active object
+ * @param graphicalChange If true the view will be rendered with higher
+ * priority
+ */
+ void addView( PMGLView* view, PMObject* active, PMObject* top,
+ PMControlPointList* controlPoints, double aspectRatio,
+ int visibilityLevel, bool graphicalChange );
+ /**
+ * Removes the view from the list of views that have to be rendered
+ */
+ void removeView( PMGLView* view );
+
+ /**
+ * Call this method if a PMGLView was created
+ */
+ void viewCreated( ) { m_nViews++; }
+ /**
+ * Call this method if a PMGLView was deleted
+ */
+ void viewDeleted( ) { m_nViews--; }
+
+ /**
+ * Returns true if the render manager holds a task for the view
+ */
+ bool containsTask( PMGLView* view ) const;
+
+ /**
+ * Returns the color for the control points
+ */
+ QColor controlPointColor( int i ) const;
+ /**
+ * Sets the control point color
+ */
+ void setControlPointColor( int i, const QColor& c );
+ /**
+ * Returns the color for graphical objects
+ */
+ QColor graphicalObjectColor( int i ) const;
+ /**
+ * Sets the graphical object color
+ */
+ void setGraphicalObjectColor( int i, const QColor& c );
+ /**
+ * Returns the color for the coordinate axes
+ */
+ QColor axesColor( int i ) const;
+ /**
+ * Sets the axes color
+ */
+ void setAxesColor( int i, const QColor& c );
+ /**
+ * Returns the background color
+ */
+ QColor backgroundColor( ) const { return m_backgroundColor; }
+ /**
+ * Sets the background color
+ */
+ void setBackgroundColor( const QColor& c ) { m_backgroundColor = c; }
+ /**
+ * Returns the field of view color.
+ */
+ QColor fieldOfViewColor( ) const { return m_fieldOfViewColor; }
+ /**
+ * Sets the field of view color
+ */
+ void setFieldOfViewColor( const QColor& c ) { m_fieldOfViewColor = c; }
+
+ /**
+ * Sets the grid color
+ */
+ void setGridColor( const QColor& c ) { m_gridColor = c; }
+ /**
+ * Returns the grid color
+ */
+ QColor gridColor( ) { return m_gridColor; }
+ /**
+ * Sets the grid distance
+ */
+ void setGridDistance( int d );
+ /**
+ * Returns the grid distance
+ */
+ int gridDistance( ) { return m_gridDistance; }
+
+ /**
+ * Returns true if the camera views with complex projections
+ * are rendered with high detail
+ */
+ bool highDetailCameraViews( ) const { return m_highDetailCameraView; }
+ /**
+ * Sets the highDetailCameraView flag
+ */
+ void setHighDetailCameraViews( bool yes ) { m_highDetailCameraView = yes; }
+
+ /**
+ * Sets the gl drawing color
+ */
+ static void setGLColor( const QColor& c );
+
+ /**
+ * Saves the configuration
+ */
+ void saveConfig( KConfig* cfg );
+ /**
+ * Restores the configuration
+ */
+ void restoreConfig( KConfig* cfg );
+
+ /**
+ * Returns true if the glx extension is available
+ */
+ static bool hasOpenGL( );
+ /**
+ * Disables OpenGL rendering
+ */
+ static void disableOpenGL( );
+
+public slots:
+ /**
+ * Stops rendering
+ */
+ void slotStopRendering( );
+ /**
+ * Call this when rendering settings have been changed
+ */
+ void slotRenderingSettingsChanged( );
+
+signals:
+ /**
+ * Emitted when rendering starts for the view v
+ */
+ void renderingStarted( PMGLView* v );
+ /**
+ * Emitted just before the view is updated
+ */
+ void aboutToUpdate( PMGLView* v );
+ /**
+ * Emitted when rendering has been finished for the view v
+ */
+ void renderingFinished( PMGLView* v );
+ /**
+ * Emitted when rendering settings (colors ...) have been changed
+ */
+ void renderingSettingsChanged( );
+ /**
+ * Emitted when rendering has started
+ */
+ void renderingStarted( );
+ /**
+ * Emitted when rendering has finished
+ */
+ void renderingFinished( );
+
+protected:
+ virtual void timerEvent( QTimerEvent* );
+
+private:
+ /**
+ * constructor
+ */
+ PMRenderManager( );
+
+ /**
+ * Restarts rendering
+ */
+ void restartRendering( );
+
+ /**
+ * The background task for rendering
+ */
+ void renderTask( );
+ /**
+ * Renders one object
+ */
+ void renderObject( PMObject* obj );
+ /**
+ * Renders the view structure, subdivides the lines in high
+ detail camera views */
+ void renderViewStructure( PMViewStructure& vs );
+ /**
+ * Renders the view structure without subdivisions
+ */
+ void renderViewStructureSimple( PMPointArray& points, PMLineArray& lines,
+ int numberOfLines = -1 );
+ /**
+ * Renders the control points
+ */
+ void renderControlPoints( );
+ /**
+ * Draws the grid
+ */
+ void renderGrid( );
+ /**
+ * Draws the coordinate axis
+ */
+ void renderAxes( );
+ /**
+ * Draws the field of view for camera views
+ */
+ void renderFieldOfView( );
+ /**
+ * Draws the view descriptions
+ */
+ void renderDescription( );
+ /**
+ * Renders the string
+ */
+ void renderString( const QString& str, double x, double y );
+
+ /**
+ * Transforms and renders the view structure for special
+ * camera projection types.
+ */
+ void transformProjection( PMPoint* points, int size, PMCamera* camera );
+ /**
+ * Sets the projection for the current view
+ */
+ void setProjection( );
+ /**
+ * Sets the projection for a camera view
+ */
+ void setCameraProjection( );
+
+ /**
+ * Calculates the view transformation for the camera c
+ */
+ PMMatrix viewTransformation( PMCamera* c ) const;
+
+ /**
+ * List of render tasks. The first has the highest priority
+ */
+ QPtrList<PMRenderTask> m_renderTasks;
+ /**
+ * Flag for background rendering
+ */
+ bool m_bStopTask, m_bStartTask, m_bTaskIsRunning;
+ /**
+ * The color for view structures of graphical objects.
+ *
+ * index 0: normal color, 1: selected
+ */
+ QColor m_graphicalObjectColor[2];
+ /**
+ * The color for view structures of textures
+ */
+ QColor m_textureColor[2];
+ /**
+ * The color for the coordinate axes
+ */
+ QColor m_axesColor[3];
+ /**
+ * The background color
+ */
+ QColor m_backgroundColor;
+ /**
+ * color for control points
+ *
+ * index 0: normal color, 1: selected
+ */
+ QColor m_controlPointColor[2];
+ /**
+ * Color for the field of view box
+ */
+ QColor m_fieldOfViewColor;
+
+ /**
+ * Grid distance and color
+ */
+ int m_gridDistance;
+ QColor m_gridColor;
+ /**
+ * If true, lines are subdivided in camera views with complex
+ * projections
+ */
+ bool m_highDetailCameraView;
+
+ /**
+ * Number of rendered lines between calls of processEvents( )
+ */
+ unsigned int m_nMaxRenderedLines;
+
+ /**
+ * Number of gl views
+ */
+ unsigned int m_nViews;
+ /**
+ * The render manager (singleton pattern)
+ */
+ static PMRenderManager* s_pManager;
+ static KStaticDeleter<PMRenderManager> s_staticDeleter;
+
+ // Member variables to save stack space during rendering
+ PMRenderTask* m_pCurrentTask;
+ PMGLView* m_pCurrentGlView;
+ QPtrStack<PMMatrix> m_matrixStack; // I don't know if the build in gl matrix stack is deep enough
+ bool m_selected;
+ PMObject* m_pDeselectObject;
+ PMObjectList m_objectToRenderStack;
+ QPtrStack<PMObject> m_quickColorObjects;
+ QPtrStack<QColor> m_quickColors;
+ QColor m_currentColor;
+ QValueStack<int> m_visibilityStack;
+ int m_currentVisibility;
+ unsigned int m_renderedLines;
+ PMMatrix m_controlPointTransformation;
+
+ // for transformProjection
+ bool m_specialCameraMode;
+ PMMatrix m_viewTransformation;
+ double m_upLength, m_rightLength, m_directionLength;
+ double m_anglex, m_angley;
+ PMViewStructure m_subdivisionViewStructure;
+
+ PMViewStructure m_axesViewStructure[3];
+ bool m_axesViewStructureCreated;
+
+ static bool s_hasOpenGL;
+ static bool s_hasOpenGLChecked;
+};
+
+#endif
diff --git a/kpovmodeler/pmrendermode.cpp b/kpovmodeler/pmrendermode.cpp
new file mode 100644
index 00000000..1dc32290
--- /dev/null
+++ b/kpovmodeler/pmrendermode.cpp
@@ -0,0 +1,220 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmrendermode.h"
+#include <klocale.h>
+
+#include "pmxmlhelper.h"
+
+
+PMRenderMode::PMRenderMode( )
+{
+ init( );
+}
+
+void PMRenderMode::init( )
+{
+ m_width = 640;
+ m_height = 480;
+
+ m_subSection = false;
+ m_startRow = 1;
+ m_endRow = m_height;
+ m_startColumn = 1;
+ m_endColumn = m_width;
+
+ m_quality = 9;
+
+ m_radiosity = false;
+
+ m_antialiasing = false;
+ m_samplingMethod = AntialiasingNonRecursive;
+ m_antialiasThreshold = 0.3;
+ m_antialiasJitter = false;
+ m_antialiasJitterAmount = 1.0;
+ m_antialiasDepth = 2;
+
+ m_description = i18n( "New mode" );
+
+ m_alpha = false;
+}
+
+PMRenderMode::PMRenderMode( const QDomElement& e )
+{
+ init( );
+
+ PMXMLHelper hlp( e, 0, 0, 0, 0 );
+ m_description = hlp.stringAttribute( "description", m_description );
+ m_height = hlp.intAttribute( "height", m_height );
+ m_width = hlp.intAttribute( "width", m_width );
+ m_subSection = hlp.boolAttribute( "subsection", m_subSection );
+ m_startColumn = hlp.doubleAttribute( "start_column", m_startColumn );
+ m_endColumn = hlp.doubleAttribute( "end_column", m_endColumn );
+ m_startRow = hlp.doubleAttribute( "start_row", m_startRow );
+ m_endRow = hlp.doubleAttribute( "end_row", m_endRow );
+ m_quality = hlp.intAttribute( "quality", m_quality );
+ m_radiosity = hlp.boolAttribute( "radiosity", m_radiosity );
+ m_antialiasing = hlp.boolAttribute( "antialiasing", m_antialiasing );
+ m_samplingMethod = hlp.intAttribute( "sampling_method", m_samplingMethod );
+ m_antialiasThreshold = hlp.doubleAttribute( "aa_threshold", m_antialiasThreshold );
+ m_antialiasJitter = hlp.boolAttribute( "aa_jitter", m_antialiasJitter );
+ m_antialiasJitterAmount = hlp.doubleAttribute( "aa_jitter_amount", m_antialiasJitterAmount );
+ m_antialiasDepth = hlp.intAttribute( "aa_depth", m_antialiasDepth );
+ m_alpha = hlp.boolAttribute( "alpha", m_alpha );
+}
+
+void PMRenderMode::serialize( QDomElement& e ) const
+{
+ e.setAttribute( "description", m_description );
+ e.setAttribute( "height", m_height );
+ e.setAttribute( "width", m_width );
+ e.setAttribute( "subsection", m_subSection );
+ e.setAttribute( "start_row", m_startRow );
+ e.setAttribute( "end_row", m_endRow );
+ e.setAttribute( "start_column", m_startColumn );
+ e.setAttribute( "end_column", m_endColumn );
+ e.setAttribute( "quality", m_quality );
+ e.setAttribute( "radiosity", m_radiosity );
+ e.setAttribute( "antialiasing", m_antialiasing );
+ e.setAttribute( "sampling_method", m_samplingMethod );
+ e.setAttribute( "aa_threshold", m_antialiasThreshold );
+ e.setAttribute( "aa_jitter", m_antialiasJitter );
+ e.setAttribute( "aa_jitter_amount", m_antialiasJitterAmount );
+ e.setAttribute( "aa_depth", m_antialiasDepth );
+ e.setAttribute( "alpha", m_alpha );
+}
+
+void PMRenderMode::setHeight( int height )
+{
+ if( height >= 1 )
+ m_height = height;
+}
+
+void PMRenderMode::setWidth( int width )
+{
+ if( width >= 1 )
+ m_width = width;
+}
+
+void PMRenderMode::setStartRow( double startRow )
+{
+ if( startRow >= 0 )
+ m_startRow = startRow;
+}
+
+void PMRenderMode::setEndRow( double endRow )
+{
+ if( endRow >= 0 )
+ m_endRow = endRow;
+}
+
+void PMRenderMode::setStartColumn( double startColumn )
+{
+ if( startColumn >= 0 )
+ m_startColumn = startColumn;
+}
+
+void PMRenderMode::setEndColumn( double endColumn )
+{
+ if( endColumn >= 0 )
+ m_endColumn = endColumn;
+}
+
+void PMRenderMode::setQuality( int quality )
+{
+ if( ( quality >= 0 ) && ( quality <= 11 ) )
+ m_quality = quality;
+}
+
+void PMRenderMode::setAntialiasingDepth( int depth )
+{
+ if( ( depth >= 1 ) && ( depth <= 9 ) )
+ m_antialiasDepth = depth;
+}
+
+void PMRenderMode::setSamplingMethod( int method )
+{
+ if( ( method == AntialiasingNonRecursive )
+ || ( method == AntialiasingRecursive ) )
+ m_samplingMethod = method;
+ else
+ m_samplingMethod = AntialiasingNonRecursive;
+}
+
+QStringList PMRenderMode::commandLineSwitches( ) const
+{
+ QStringList cl;
+ QString tmp;
+
+ cl.append( QString( "+W%1" ).arg( m_width ) );
+ cl.append( QString( "+H%1" ).arg( m_height ) );
+ if( m_subSection )
+ {
+ if( m_startRow < 1.0 )
+ tmp.sprintf( "+SR%4.2f", m_startRow );
+ else
+ tmp = QString( "+SR%1" ).arg( ( int ) ( m_startRow + 0.5 ) );
+ cl.append( tmp );
+ if( m_endRow < 1.0 )
+ tmp.sprintf( "+ER%4.2f", m_endRow );
+ else
+ tmp = QString( "+ER%1" ).arg( ( int ) ( m_endRow + 0.5 ) );
+ cl.append( tmp );
+
+ if( m_startColumn < 1.0 )
+ tmp.sprintf( "+SC%4.2f", m_startColumn );
+ else
+ tmp = QString( "+SC%1" ).arg( ( int ) ( m_startColumn + 0.5 ) );
+ cl.append( tmp );
+ if( m_endColumn < 1.0 )
+ tmp.sprintf( "+EC%4.2f", m_endColumn );
+ else
+ tmp = QString( "+EC%1" ).arg( ( int ) ( m_endColumn + 0.5 ) );
+ cl.append( tmp );
+ }
+ cl.append( QString( "+Q%1" ).arg( m_quality ) );
+ if( m_radiosity )
+ cl.append( QString( "+QR" ) );
+ else
+ cl.append( QString( "-QR" ) );
+
+ if( m_antialiasing )
+ {
+ cl.append( QString( "+A" ) );
+ cl.append( QString( "+AM%1" ).arg( m_samplingMethod ) );
+ tmp.sprintf( "+A%5.3f", m_antialiasThreshold );
+ cl.append( tmp );
+ if( m_antialiasJitter )
+ {
+ tmp.sprintf( "+J%5.3f", m_antialiasJitterAmount );
+ cl.append( tmp );
+ }
+ else
+ cl.append( QString( "-J" ) );
+ cl.append( QString( "+R%1" ).arg( m_antialiasDepth ) );
+ }
+ else
+ cl.append( QString( "-A" ) );
+
+ if( m_alpha )
+ cl.append( QString( "+UA" ) );
+ else
+ cl.append( QString( "-UA" ) );
+
+ return cl;
+}
+
diff --git a/kpovmodeler/pmrendermode.h b/kpovmodeler/pmrendermode.h
new file mode 100644
index 00000000..a8c891ce
--- /dev/null
+++ b/kpovmodeler/pmrendermode.h
@@ -0,0 +1,128 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMRENDERMODE_H
+#define PMRENDERMODE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qstring.h>
+#include <qptrlist.h>
+#include <qstringlist.h>
+#include <qdom.h>
+
+/**
+ * Class that represents the render options for povray
+ *
+ * See povray documentation, output options.
+ */
+class PMRenderMode
+{
+public:
+ /**
+ * Sampling method for antialiasing. See povray documentation.
+ */
+ enum AASamplingMethod { AntialiasingNonRecursive = 0, AntialiasingRecursive = 1 };
+
+ /**
+ * Default constructor
+ */
+ PMRenderMode( );
+ /**
+ * Reads the attributes from the QDomElement
+ */
+ PMRenderMode( const QDomElement& e );
+
+ void setDescription( const QString& descr ) { m_description = descr; }
+ QString description( ) const { return m_description; }
+
+ void setHeight( int height );
+ int height( ) const { return m_height; }
+ void setWidth( int width );
+ int width( ) const { return m_width; }
+
+ void setSubSection( bool on ) { m_subSection = on; }
+ bool subSection( ) const { return m_subSection; }
+ void setStartRow( double startRow );
+ double startRow( ) const { return m_startRow; }
+ void setEndRow( double endRow );
+ double endRow( ) const { return m_endRow; }
+ void setStartColumn( double startColumn );
+ double startColumn( ) const { return m_startColumn; }
+ void setEndColumn( double endColumn );
+ double endColumn( ) const { return m_endColumn; }
+
+ void setQuality( int quality );
+ int quality( ) const { return m_quality; }
+
+ void setRadiosity( bool on ) { m_radiosity = on; }
+ bool radiosity( ) const { return m_radiosity; }
+
+ void setAntialiasing( bool on ) { m_antialiasing = on; }
+ bool antialiasing( ) const { return m_antialiasing; }
+ void setSamplingMethod( int method );
+ int samplingMethod( ) const { return m_samplingMethod; }
+ void setAntialiasingThreshold( double t ) { m_antialiasThreshold = t; }
+ double antialiasingThreshold( ) const { return m_antialiasThreshold; }
+ void setAntialiasingJitter( bool on ) { m_antialiasJitter = on; }
+ bool antialiasingJitter( ) const { return m_antialiasJitter; }
+ void setAntialiasingJitterAmount( double amount ) { m_antialiasJitterAmount = amount; }
+ double antialiasingJitterAmount( ) const { return m_antialiasJitterAmount; }
+ void setAntialiasingDepth( int depth );
+ int antialiasingDepth( ) const { return m_antialiasDepth; }
+
+ void setAlpha( bool on ) { m_alpha = on; }
+ bool alpha( ) const { return m_alpha; }
+
+
+ /**
+ * Returns the settings as povray command line switches
+ */
+ QStringList commandLineSwitches( ) const;
+ /**
+ * Saves the data
+ */
+ void serialize( QDomElement& e ) const;
+
+private:
+ void init( );
+
+ QString m_description;
+ int m_height, m_width;
+ bool m_subSection;
+ double m_startRow, m_endRow, m_startColumn, m_endColumn;
+
+ int m_quality;
+ bool m_radiosity;
+ bool m_antialiasing;
+ int m_samplingMethod;
+ double m_antialiasThreshold;
+ bool m_antialiasJitter;
+ double m_antialiasJitterAmount;
+ int m_antialiasDepth;
+
+ bool m_alpha;
+};
+
+typedef QPtrList<PMRenderMode> PMRenderModeList;
+typedef QPtrListIterator<PMRenderMode> PMRenderModeListIterator;
+
+#endif
diff --git a/kpovmodeler/pmrendermodesdialog.cpp b/kpovmodeler/pmrendermodesdialog.cpp
new file mode 100644
index 00000000..5c4b4b7b
--- /dev/null
+++ b/kpovmodeler/pmrendermodesdialog.cpp
@@ -0,0 +1,611 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmrendermodesdialog.h"
+
+#include <qlistbox.h>
+#include <qpushbutton.h>
+#include <qcheckbox.h>
+#include <qlineedit.h>
+#include <qtabwidget.h>
+#include <qvbox.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcombobox.h>
+
+#include <klocale.h>
+#include <kconfig.h>
+#include <kmessagebox.h>
+#include <kfiledialog.h>
+
+#include "pmlineedits.h"
+
+QSize PMRenderModesDialog::s_size = QSize( 300, 200 );
+
+PMRenderModesDialog::PMRenderModesDialog( PMRenderModeList* modes, QWidget* parent, const char* name )
+ : KDialogBase( parent, name, true, i18n( "Render Modes" ),
+ Ok | Cancel, Ok )
+{
+ m_selectionIndex = modes->at( );
+ m_pOriginalModes = modes;
+ PMRenderModeListIterator it( *modes );
+ for( ; it.current( ); ++it )
+ m_workingModes.append( new PMRenderMode( *( it.current( ) ) ) );
+ m_workingModes.setAutoDelete( true );
+
+ QVBox* mainPage = makeVBoxMainWidget( );
+ m_pListBox = new QListBox( mainPage );
+ connect( m_pListBox, SIGNAL( highlighted( int ) ), SLOT( slotModeSelected( int ) ) );
+
+ QHBox* buttons = new QHBox( mainPage );
+ buttons->setSpacing( KDialog::spacingHint( ) );
+ m_pAddButton = new QPushButton( i18n( "Add" ), buttons );
+ connect( m_pAddButton, SIGNAL( clicked( ) ), SLOT( slotAdd( ) ) );
+ m_pRemoveButton = new QPushButton( i18n( "Remove" ), buttons );
+ connect( m_pRemoveButton, SIGNAL( clicked( ) ), SLOT( slotRemove( ) ) );
+ m_pEditButton = new QPushButton( i18n( "Edit..." ), buttons );
+ connect( m_pEditButton, SIGNAL( clicked( ) ), SLOT( slotEdit( ) ) );
+ m_pUpButton = new QPushButton( i18n( "Up" ), buttons );
+ connect( m_pUpButton, SIGNAL( clicked( ) ), SLOT( slotUp( ) ) );
+ m_pDownButton = new QPushButton( i18n( "Down" ), buttons );
+ connect( m_pDownButton, SIGNAL( clicked( ) ), SLOT( slotDown( ) ) );
+
+ m_pRemoveButton->setEnabled( false );
+ m_pUpButton->setEnabled( false );
+ m_pDownButton->setEnabled( false );
+
+ enableButtonOK( false );
+
+ resize( s_size );
+ displayList( );
+ connect( m_pListBox, SIGNAL( doubleClicked ( QListBoxItem *) ), this, SLOT(slotEdit( ) ) );
+}
+
+void PMRenderModesDialog::slotChanged( )
+{
+ enableButtonOK( true );
+}
+
+void PMRenderModesDialog::slotModeSelected( int index )
+{
+ m_selectionIndex = index;
+ checkButtons( );
+ slotChanged( );
+}
+
+void PMRenderModesDialog::displayList( )
+{
+ PMRenderModeListIterator it( m_workingModes );
+ bool b = m_pListBox->signalsBlocked( );
+ m_pListBox->blockSignals( true );
+
+ m_pListBox->clear( );
+ for( ; it.current( ); ++it )
+ m_pListBox->insertItem( it.current( )->description( ) );
+ m_pListBox->setSelected( m_selectionIndex, true );
+
+ m_pListBox->blockSignals( b );
+
+ checkButtons( );
+}
+
+void PMRenderModesDialog::checkButtons( )
+{
+ if( m_selectionIndex < 0 )
+ {
+ m_pRemoveButton->setEnabled( false );
+ m_pEditButton->setEnabled( false );
+ m_pUpButton->setEnabled( false );
+ m_pDownButton->setEnabled( false );
+ }
+ else
+ {
+ int num = m_workingModes.count( );
+
+ m_pRemoveButton->setEnabled( true );
+ m_pEditButton->setEnabled( true );
+ m_pUpButton->setEnabled( m_selectionIndex != 0 );
+ m_pDownButton->setEnabled( m_selectionIndex != ( num - 1 ) );
+ }
+}
+
+void PMRenderModesDialog::saveConfig( KConfig* cfg )
+{
+ cfg->setGroup( "Appearance" );
+ cfg->writeEntry( "RenderModesDialogSize", s_size );
+}
+
+void PMRenderModesDialog::restoreConfig( KConfig* cfg )
+{
+ cfg->setGroup( "Appearance" );
+
+ QSize defaultSize( 300, 200 );
+ s_size = cfg->readSizeEntry( "RenderModesDialogSize", &defaultSize );
+}
+
+void PMRenderModesDialog::resizeEvent( QResizeEvent* ev )
+{
+ s_size = ev->size( );
+}
+
+void PMRenderModesDialog::slotAdd( )
+{
+ m_selectionIndex++;
+ if( m_selectionIndex < 0 )
+ m_selectionIndex = 0;
+ m_workingModes.insert( ( uint ) m_selectionIndex, new PMRenderMode( ) );
+
+ displayList( );
+ slotChanged( );
+}
+
+void PMRenderModesDialog::slotRemove( )
+{
+ m_workingModes.remove( ( uint ) m_selectionIndex );
+
+ int num = m_workingModes.count( );
+ if( m_selectionIndex >= num )
+ m_selectionIndex = num - 1;
+
+ displayList( );
+ slotChanged( );
+}
+
+void PMRenderModesDialog::slotUp( )
+{
+ PMRenderMode* mode = m_workingModes.take( ( uint ) m_selectionIndex );
+ m_selectionIndex--;
+ if( m_selectionIndex < 0 )
+ m_selectionIndex = 0;
+ m_workingModes.insert( m_selectionIndex, mode );
+
+ displayList( );
+ slotChanged( );
+}
+
+void PMRenderModesDialog::slotDown( )
+{
+ PMRenderMode* mode = m_workingModes.take( ( uint ) m_selectionIndex );
+ m_selectionIndex++;
+
+ int num = m_workingModes.count( );
+ if( m_selectionIndex > num )
+ m_selectionIndex = num;
+ m_workingModes.insert( m_selectionIndex, mode );
+
+ displayList( );
+ slotChanged( );
+}
+
+void PMRenderModesDialog::slotEdit( )
+{
+ if ( m_selectionIndex==-1 )
+ return;
+ PMRenderModeDialog dlg( m_workingModes.at( m_selectionIndex ) );
+ bool changed = ( dlg.exec( ) == QDialog::Accepted );
+ if( changed )
+ {
+ slotChanged( );
+ displayList( );
+ }
+}
+
+void PMRenderModesDialog::slotOk( )
+{
+ m_pOriginalModes->setAutoDelete( true );
+ m_pOriginalModes->clear( );
+ m_pOriginalModes->setAutoDelete( false );
+ *m_pOriginalModes = m_workingModes;
+ m_pOriginalModes->at( m_selectionIndex );
+
+ m_workingModes.setAutoDelete( false );
+ m_workingModes.clear( );
+
+ accept( );
+}
+
+
+QSize PMRenderModeDialog::s_size = QSize( 300, 200 );
+
+const int numQuality = 9;
+const char* qualityString[numQuality] =
+{
+ I18N_NOOP( "0, 1: Quick colors, full ambient lighting only" ),
+ I18N_NOOP( "2, 3: Show specified diffuse and ambient light" ),
+ I18N_NOOP( "4: Render shadows, but no extended lights" ),
+ I18N_NOOP( "5: Render shadows, including extended lights" ),
+ I18N_NOOP( "6, 7: Compute texture patterns" ),
+ I18N_NOOP( "8: Compute reflected, refracted, and transmitted rays" ),
+ I18N_NOOP( "9: Compute media" ),
+ I18N_NOOP( "10: Compute radiosity but no media" ),
+ I18N_NOOP( "11: Compute radiosity and media" )
+};
+
+const int c_qualityToIndex[12] = { 0, 0, 1, 1, 2, 3, 4, 4, 5, 6, 7, 8 };
+const int c_indexToQuality[numQuality] = { 0, 2, 4, 5, 6, 8, 9, 10, 11 };
+
+PMRenderModeDialog::PMRenderModeDialog( PMRenderMode* mode, QWidget* parent, const char* name )
+ : KDialogBase( parent, name, true, i18n( "Render Modes" ),
+ Ok | Cancel, Ok )
+{
+ m_pMode = mode;
+ int i;
+
+ // main page
+ QWidget* page = new QWidget( this );
+ setMainWidget( page );
+ QVBoxLayout* topLayout = new QVBoxLayout( page, 0, spacingHint( ) );
+
+ QHBoxLayout* descrLayout = new QHBoxLayout( topLayout );
+ QLabel* descrLabel = new QLabel( i18n( "Description:" ), page );
+ descrLayout->addWidget( descrLabel );
+
+ m_pDescriptionEdit = new QLineEdit( page );
+ descrLayout->addWidget( m_pDescriptionEdit );
+
+ m_pTabWidget = new QTabWidget( page );
+ topLayout->addWidget( m_pTabWidget );
+
+ QWidget* tab;
+ QVBoxLayout* tabLayout;
+
+ // size tab
+ tab = new QWidget( );
+ m_pTabWidget->addTab( tab, i18n( "Size" ) );
+ tabLayout = new QVBoxLayout( tab, marginHint( ), spacingHint( ) );
+
+ QHBoxLayout* sizeHelpLayout = new QHBoxLayout( tabLayout );
+ QGridLayout* sizeLayout = new QGridLayout( sizeHelpLayout, 2, 2 );
+ sizeLayout->addWidget( new QLabel( i18n( "Width:" ), tab ), 0, 0 );
+ m_pWidthEdit = new PMIntEdit( tab );
+ m_pWidthEdit->setValidation( true, 1, false, 0 );
+ sizeLayout->addWidget( m_pWidthEdit, 0, 1 );
+ sizeLayout->addWidget( new QLabel( i18n( "Height:" ), tab ), 1, 0 );
+ m_pHeightEdit = new PMIntEdit( tab );
+ m_pHeightEdit->setValidation( true, 1, false, 0 );
+ sizeLayout->addWidget( m_pHeightEdit, 1, 1 );
+ sizeHelpLayout->addStretch( 1 );
+
+ m_pSubsectionBox = new QCheckBox( i18n( "Subsection" ), tab );
+ tabLayout->addWidget( m_pSubsectionBox );
+
+ QHBoxLayout* ssHelpLayout = new QHBoxLayout( tabLayout );
+ QGridLayout* ssLayout = new QGridLayout( ssHelpLayout, 4, 2 );
+ ssLayout->addWidget( new QLabel( i18n( "Start column:" ), tab ), 0, 0 );
+ m_pStartColumnEdit = new PMFloatEdit( tab );
+ m_pStartColumnEdit->setValidation( true, 0.0, false, 0.0 );
+ ssLayout->addWidget( m_pStartColumnEdit, 0, 1 );
+ ssLayout->addWidget( new QLabel( i18n( "End column:" ), tab ), 1, 0 );
+ m_pEndColumnEdit = new PMFloatEdit( tab );
+ m_pEndColumnEdit->setValidation( true, 0.0, false, 0.0 );
+ ssLayout->addWidget( m_pEndColumnEdit, 1, 1 );
+ ssLayout->addWidget( new QLabel( i18n( "Start row:" ), tab ), 2, 0 );
+ m_pStartRowEdit = new PMFloatEdit( tab );
+ m_pStartRowEdit->setValidation( true, 0.0, false, 0.0 );
+ ssLayout->addWidget( m_pStartRowEdit, 2, 1 );
+ ssLayout->addWidget( new QLabel( i18n( "End row:" ), tab ), 3, 0 );
+ m_pEndRowEdit = new PMFloatEdit( tab );
+ m_pEndRowEdit->setValidation( true, 0.0, false, 0.0 );
+ ssLayout->addWidget( m_pEndRowEdit, 3, 1 );
+ ssHelpLayout->addStretch( 1 );
+
+ tabLayout->addStretch( 1 );
+
+ // quality tab
+ tab = new QWidget( );
+ m_pTabWidget->addTab( tab, i18n( "Quality" ) );
+ tabLayout = new QVBoxLayout( tab, marginHint( ), spacingHint( ) );
+
+ QHBoxLayout* quHelpLayout = new QHBoxLayout( tabLayout );
+ quHelpLayout->addWidget( new QLabel( i18n( "Quality:" ), tab ) );
+ m_pQualityCombo = new QComboBox( tab );
+ quHelpLayout->addWidget( m_pQualityCombo );
+ for( i = 0; i < numQuality; i++ )
+ m_pQualityCombo->insertItem( i18n( qualityString[i] ) );
+
+ m_pAntialiasingBox = new QCheckBox( i18n( "Antialiasing" ), tab );
+ tabLayout->addWidget( m_pAntialiasingBox );
+
+ QHBoxLayout* aaHelpLayout = new QHBoxLayout( tabLayout );
+ QGridLayout* aaGridLayout = new QGridLayout( aaHelpLayout, 5, 2 );
+ aaGridLayout->addWidget( new QLabel( i18n( "Method:" ), tab ), 0, 0 );
+ m_pSamplingCombo = new QComboBox( tab );
+ aaGridLayout->addWidget( m_pSamplingCombo, 0, 1 );
+ m_pSamplingCombo->insertItem( i18n( "Non Recursive" ) );
+ m_pSamplingCombo->insertItem( i18n( "Recursive" ) );
+
+ aaGridLayout->addWidget( new QLabel( i18n( "Threshold:" ), tab ), 1, 0 );
+ m_pThresholdEdit = new PMFloatEdit( tab );
+ aaGridLayout->addWidget( m_pThresholdEdit, 1, 1 );
+
+ aaGridLayout->addWidget( new QLabel( i18n( "Depth:" ), tab ), 2, 0 );
+ m_pAntialiasDepthEdit = new PMIntEdit( tab );
+ m_pAntialiasDepthEdit->setValidation( true, 1, true, 9 );
+ aaGridLayout->addWidget( m_pAntialiasDepthEdit, 2, 1 );
+
+ m_pJitterBox = new QCheckBox( i18n( "Jitter" ), tab );
+ aaGridLayout->addMultiCellWidget( m_pJitterBox, 3, 3, 0, 1 );
+
+ aaGridLayout->addWidget( new QLabel( i18n( "Amount:" ), tab ), 4, 0 );
+ m_pJitterAmountEdit = new PMFloatEdit( tab );
+ aaGridLayout->addWidget( m_pJitterAmountEdit, 4, 1 );
+
+ aaHelpLayout->addStretch( 1 );
+
+ m_pRadiosityBox = new QCheckBox( i18n( "Radiosity" ), tab );
+ tabLayout->addWidget( m_pRadiosityBox );
+
+ tabLayout->addStretch( 1 );
+
+ // output options tab
+ tab = new QWidget( );
+ m_pTabWidget->addTab( tab, i18n( "Output" ) );
+ tabLayout = new QVBoxLayout( tab, marginHint( ), spacingHint( ) );
+
+ m_pAlphaBox = new QCheckBox( i18n( "Alpha" ), tab );
+ tabLayout->addWidget( m_pAlphaBox );
+
+ tabLayout->addStretch( 1 );
+
+
+ resize( s_size );
+
+ // display the mode BEFORE the signals are connected!!!
+ displayMode( );
+
+ enableButtonOK( false );
+
+ // connect signals
+ connect( m_pDescriptionEdit, SIGNAL( textChanged( const QString& ) ), SLOT( slotTextChanged( const QString& ) ) );
+ connect( m_pHeightEdit, SIGNAL( dataChanged( ) ), SLOT( slotChanged( ) ) );
+ connect( m_pWidthEdit, SIGNAL( dataChanged( ) ), SLOT( slotChanged( ) ) );
+ connect( m_pSubsectionBox, SIGNAL( toggled( bool ) ), SLOT( slotSubsectionToggled( bool ) ) );
+ connect( m_pStartRowEdit, SIGNAL( dataChanged( ) ), SLOT( slotChanged( ) ) );
+ connect( m_pEndRowEdit, SIGNAL( dataChanged( ) ), SLOT( slotChanged( ) ) );
+ connect( m_pStartColumnEdit, SIGNAL( dataChanged( ) ), SLOT( slotChanged( ) ) );
+ connect( m_pEndColumnEdit, SIGNAL( dataChanged( ) ), SLOT( slotChanged( ) ) );
+ connect( m_pQualityCombo, SIGNAL( activated( int ) ), SLOT( slotActivated( int ) ) );
+ connect( m_pRadiosityBox, SIGNAL( clicked( ) ), SLOT( slotChanged( ) ) );
+ connect( m_pAntialiasingBox, SIGNAL( toggled( bool ) ), SLOT( slotAntialiasingToggled( bool ) ) );
+ connect( m_pSamplingCombo, SIGNAL( activated( int ) ), SLOT( slotActivated( int ) ) );
+ connect( m_pThresholdEdit, SIGNAL( dataChanged( ) ), SLOT( slotChanged( ) ) );
+ connect( m_pJitterBox, SIGNAL( toggled( bool ) ), SLOT( slotJitterToggled( bool ) ) );
+ connect( m_pJitterAmountEdit, SIGNAL( dataChanged( ) ), SLOT( slotChanged( ) ) );
+ connect( m_pAntialiasDepthEdit, SIGNAL( dataChanged( ) ), SLOT( slotChanged( ) ) );
+ connect( m_pAlphaBox, SIGNAL( toggled( bool ) ), SLOT( slotToggled( bool ) ) );
+}
+
+void PMRenderModeDialog::saveConfig( KConfig* cfg )
+{
+ cfg->setGroup( "Appearance" );
+ cfg->writeEntry( "RenderModeDialogSize", s_size );
+}
+
+void PMRenderModeDialog::restoreConfig( KConfig* cfg )
+{
+ cfg->setGroup( "Appearance" );
+
+ QSize defaultSize( 400, 400 );
+ s_size = cfg->readSizeEntry( "RenderModeDialogSize", &defaultSize );
+}
+
+void PMRenderModeDialog::resizeEvent( QResizeEvent* ev )
+{
+ s_size = ev->size( );
+}
+
+bool PMRenderModeDialog::saveChanges( )
+{
+ if( validate( ) )
+ {
+ m_pMode->setDescription( m_pDescriptionEdit->text( ) );
+ m_pMode->setWidth( m_pWidthEdit->value( ) );
+ m_pMode->setHeight( m_pHeightEdit->value( ) );
+ m_pMode->setSubSection( m_pSubsectionBox->isChecked( ) );
+ if( m_pSubsectionBox->isChecked( ) )
+ {
+ m_pMode->setStartRow( m_pStartRowEdit->value( ) );
+ m_pMode->setEndRow( m_pEndRowEdit->value( ) );
+ m_pMode->setStartColumn( m_pStartColumnEdit->value( ) );
+ m_pMode->setEndColumn( m_pEndColumnEdit->value( ) );
+ }
+ m_pMode->setQuality( indexToQuality( m_pQualityCombo->currentItem( ) ) );
+ m_pMode->setRadiosity( m_pRadiosityBox->isChecked( ) );
+ m_pMode->setAntialiasing( m_pAntialiasingBox->isChecked( ) );
+ if( m_pAntialiasingBox->isChecked( ) )
+ {
+ m_pMode->setSamplingMethod( m_pSamplingCombo->currentItem( ) );
+ m_pMode->setAntialiasingThreshold( m_pThresholdEdit->value( ) );
+ m_pMode->setAntialiasingJitter( m_pJitterBox->isChecked( ) );
+ if( m_pJitterBox->isChecked( ) )
+ m_pMode->setAntialiasingJitterAmount( m_pJitterAmountEdit->value( ) );
+ m_pMode->setAntialiasingDepth( m_pAntialiasDepthEdit->value( ) );
+ }
+ m_pMode->setAlpha( m_pAlphaBox->isChecked( ) );
+ return true;
+ }
+ return false;
+}
+
+bool PMRenderModeDialog::validate( )
+{
+ if( m_pDescriptionEdit->text( ).isEmpty( ) )
+ {
+ KMessageBox::error( this, i18n( "Please enter a description for the "
+ "render mode." ), i18n( "Error" ) );
+ m_pDescriptionEdit->selectAll( );
+ return false;
+ }
+
+ // tab 0
+ bool error = true;
+
+ if( m_pHeightEdit->isDataValid( ) )
+ if( m_pWidthEdit->isDataValid( ) )
+ error = false;
+ if( !error && m_pSubsectionBox->isChecked( ) )
+ {
+ error = true;
+ if( m_pStartColumnEdit->isDataValid( ) )
+ if( m_pEndColumnEdit->isDataValid( ) )
+ if( m_pStartRowEdit->isDataValid( ) )
+ if( m_pEndRowEdit->isDataValid( ) )
+ error = false;
+ }
+
+ if( error )
+ {
+ m_pTabWidget->setCurrentPage( 0 );
+ return false;
+ }
+
+ // tab 1
+ if( m_pAntialiasingBox->isChecked( ) )
+ {
+ error = false;
+ if( m_pThresholdEdit->isDataValid( ) )
+ if( m_pAntialiasDepthEdit->isDataValid( ) )
+ error = false;
+
+ if( m_pJitterBox->isChecked( ) && !error )
+ error = !m_pJitterAmountEdit->isDataValid( );
+
+ if( error )
+ {
+ m_pTabWidget->setCurrentPage( 1 );
+ return false;
+ }
+ }
+
+ // tab 2
+
+ return true;
+}
+
+void PMRenderModeDialog::displayMode( )
+{
+ m_pDescriptionEdit->setText( m_pMode->description( ) );
+ m_pHeightEdit->setValue( m_pMode->height( ) );
+ m_pWidthEdit->setValue( m_pMode->width( ) );
+ m_pSubsectionBox->setChecked( m_pMode->subSection( ) );
+ enableSubsection( m_pMode->subSection( ) );
+ m_pStartRowEdit->setValue( m_pMode->startRow( ) );
+ m_pEndRowEdit->setValue( m_pMode->endRow( ) );
+ m_pStartColumnEdit->setValue( m_pMode->startColumn( ) );
+ m_pEndColumnEdit->setValue( m_pMode->endColumn( ) );
+ m_pQualityCombo->setCurrentItem( qualityToIndex( m_pMode->quality( ) ) );
+ m_pRadiosityBox->setChecked( m_pMode->radiosity( ) );
+ m_pAntialiasingBox->setChecked( m_pMode->antialiasing( ) );
+ enableAntialiasing( m_pMode->antialiasing( ) );
+ m_pSamplingCombo->setCurrentItem( m_pMode->samplingMethod( ) );
+ m_pThresholdEdit->setValue( m_pMode->antialiasingThreshold( ) );
+ m_pJitterBox->setChecked( m_pMode->antialiasingJitter( ) );
+ enableJitter( m_pMode->antialiasingJitter( ) && m_pMode->antialiasing( ) );
+ m_pJitterAmountEdit->setValue( m_pMode->antialiasingJitterAmount( ) );
+ m_pAntialiasDepthEdit->setValue( m_pMode->antialiasingDepth( ) );
+ m_pAlphaBox->setChecked( m_pMode->alpha( ) );
+}
+
+void PMRenderModeDialog::enableSubsection( bool yes )
+{
+ m_pStartRowEdit->setEnabled( yes );
+ m_pEndRowEdit->setEnabled( yes );
+ m_pStartColumnEdit->setEnabled( yes );
+ m_pEndColumnEdit->setEnabled( yes );
+}
+
+void PMRenderModeDialog::enableAntialiasing( bool yes )
+{
+ m_pSamplingCombo->setEnabled( yes );
+ m_pThresholdEdit->setEnabled( yes );
+ m_pAntialiasDepthEdit->setEnabled( yes );
+ m_pJitterBox->setEnabled( yes );
+ enableJitter( m_pJitterBox->isChecked( ) );
+}
+
+void PMRenderModeDialog::enableJitter( bool yes )
+{
+ m_pJitterAmountEdit->setEnabled( yes );
+}
+
+int PMRenderModeDialog::qualityToIndex( int quality )
+{
+ if( quality < 0 )
+ quality = 0;
+ if( quality > 11 )
+ quality = 11;
+
+ return c_qualityToIndex[quality];
+}
+
+int PMRenderModeDialog::indexToQuality( int index )
+{
+ if( index < 0 )
+ index = 0;
+ if( index >= numQuality )
+ index = numQuality - 1;
+
+ return c_indexToQuality[index];
+}
+
+void PMRenderModeDialog::slotOk( )
+{
+ if( saveChanges( ) )
+ accept( );
+}
+
+void PMRenderModeDialog::slotChanged( )
+{
+ enableButtonOK( true );
+}
+
+void PMRenderModeDialog::slotTextChanged( const QString& )
+{
+ slotChanged( );
+}
+
+void PMRenderModeDialog::slotActivated( int )
+{
+ slotChanged( );
+}
+
+void PMRenderModeDialog::slotSubsectionToggled( bool on )
+{
+ slotChanged( );
+ enableSubsection( on );
+}
+
+void PMRenderModeDialog::slotAntialiasingToggled( bool on )
+{
+ slotChanged( );
+ enableAntialiasing( on );
+}
+
+void PMRenderModeDialog::slotJitterToggled( bool on )
+{
+ slotChanged( );
+ enableJitter( on );
+}
+
+void PMRenderModeDialog::slotToggled( bool )
+{
+ slotChanged( );
+}
+
+#include "pmrendermodesdialog.moc"
+
diff --git a/kpovmodeler/pmrendermodesdialog.h b/kpovmodeler/pmrendermodesdialog.h
new file mode 100644
index 00000000..a6b6482f
--- /dev/null
+++ b/kpovmodeler/pmrendermodesdialog.h
@@ -0,0 +1,179 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMRENDERMODESDIALOG_H
+#define PMRENDERMODESDIALOG_H
+
+#include "pmrendermode.h"
+#include <kdialogbase.h>
+
+class QCheckBox;
+class QComboBox;
+class QLineEdit;
+class QListBox;
+class QPushButton;
+class QTabWidget;
+class KConfig;
+class PMIntEdit;
+class PMFloatEdit;
+
+/**
+ * Dialog for editing a list of render modes.
+ * @see PMRenderMode
+ */
+class PMRenderModesDialog : public KDialogBase
+{
+ Q_OBJECT
+public:
+ /**
+ * Creates a dialog for the modes list
+ */
+ PMRenderModesDialog( PMRenderModeList* modes, QWidget* parent = 0, const char* name = 0 );
+
+ static void saveConfig( KConfig* cfg );
+ static void restoreConfig( KConfig* cfg );
+
+protected slots:
+ /**
+ * Called when a mode is selected in the list view
+ */
+ void slotModeSelected( int index );
+
+ /**
+ * Called when the add button is klicked
+ */
+ void slotAdd( );
+ /**
+ * Called when the remove button is klicked
+ */
+ void slotRemove( );
+ /**
+ * Called when the up button is klicked
+ */
+ void slotUp( );
+ /**
+ * Called when the down button is klicked
+ */
+ void slotDown( );
+ /**
+ * Called when the edit button is klicked
+ */
+ void slotEdit( );
+ /**
+ * Called when the modes are changed
+ */
+ void slotChanged( );
+ virtual void slotOk( );
+
+protected:
+ virtual void resizeEvent( QResizeEvent* ev );
+
+private:
+ void displayList( );
+ void checkButtons( );
+
+ PMRenderModeList* m_pOriginalModes;
+ PMRenderModeList m_workingModes;
+ int m_selectionIndex;
+
+ QListBox* m_pListBox;
+ QPushButton* m_pAddButton;
+ QPushButton* m_pRemoveButton;
+ QPushButton* m_pUpButton;
+ QPushButton* m_pDownButton;
+ QPushButton* m_pEditButton;
+ static QSize s_size;
+};
+
+/**
+ * Dialog for editing one render mode
+ * @see PMRenderMode
+ */
+class PMRenderModeDialog : public KDialogBase
+{
+ Q_OBJECT
+public:
+ /**
+ * Creates a dialog for the mode
+ */
+ PMRenderModeDialog( PMRenderMode* mode, QWidget* parent = 0, const char* name = 0 );
+
+ static void saveConfig( KConfig* cfg );
+ static void restoreConfig( KConfig* cfg );
+
+protected:
+ virtual void resizeEvent( QResizeEvent* ev );
+
+
+protected slots:
+ virtual void slotOk( );
+ void slotChanged( );
+ void slotTextChanged( const QString& );
+ void slotActivated( int );
+ void slotSubsectionToggled( bool );
+ void slotAntialiasingToggled( bool );
+ void slotJitterToggled( bool );
+ void slotToggled( bool );
+
+private:
+ /**
+ * Saves the current changes. Returns true if successful.
+ */
+ bool saveChanges( );
+ /**
+ * Returns true if the data is valid
+ */
+ bool validate( );
+ /**
+ * Displays the selected mode
+ */
+ void displayMode( );
+
+ void enableSubsection( bool yes );
+ void enableAntialiasing( bool yes );
+ void enableJitter( bool yes );
+ int qualityToIndex( int quality );
+ int indexToQuality( int index );
+
+ PMRenderMode* m_pMode;
+
+ QTabWidget* m_pTabWidget;
+ QLineEdit* m_pDescriptionEdit;
+ PMIntEdit* m_pHeightEdit;
+ PMIntEdit* m_pWidthEdit;
+ QCheckBox* m_pSubsectionBox;
+ PMFloatEdit* m_pStartRowEdit;
+ PMFloatEdit* m_pEndRowEdit;
+ PMFloatEdit* m_pStartColumnEdit;
+ PMFloatEdit* m_pEndColumnEdit;
+ // quality
+ QComboBox* m_pQualityCombo;
+ QCheckBox* m_pRadiosityBox;
+ QCheckBox* m_pAntialiasingBox;
+ QComboBox* m_pSamplingCombo;
+ PMFloatEdit* m_pThresholdEdit;
+ QCheckBox* m_pJitterBox;
+ PMFloatEdit* m_pJitterAmountEdit;
+ PMIntEdit* m_pAntialiasDepthEdit;
+ // output
+ QCheckBox* m_pAlphaBox;
+
+ static QSize s_size;
+};
+
+#endif
diff --git a/kpovmodeler/pmresourcelocator.cpp b/kpovmodeler/pmresourcelocator.cpp
new file mode 100644
index 00000000..7c778b31
--- /dev/null
+++ b/kpovmodeler/pmresourcelocator.cpp
@@ -0,0 +1,103 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmresourcelocator.h"
+#include "pmpovrayrenderwidget.h"
+#include "pmdebug.h"
+
+#include <qfileinfo.h>
+#include <qdir.h>
+
+PMResourceLocator* PMResourceLocator::s_pInstance = 0;
+KStaticDeleter<PMResourceLocator> PMResourceLocator::s_staticDeleter;
+
+PMResourceLocator::PMResourceLocator( )
+ : m_cache( 100, 109, true )
+{
+ m_cache.setAutoDelete( true );
+}
+
+PMResourceLocator::~PMResourceLocator( )
+{
+ m_cache.clear( );
+}
+
+QString PMResourceLocator::findFile( const QString& file )
+{
+ if( !s_pInstance )
+ s_staticDeleter.setObject( s_pInstance, new PMResourceLocator( ) );
+ return s_pInstance->lookUp( file );
+}
+
+void PMResourceLocator::clearCache( )
+{
+ if( s_pInstance )
+ s_pInstance->m_cache.clear( );
+}
+
+QString PMResourceLocator::lookUp( const QString& file )
+{
+ if( file.isEmpty( ) )
+ return QString::null;
+
+ kdDebug( PMArea ) << "LookUp: " << file << endl;
+
+ QString* ps = m_cache.find( file );
+ if( ps )
+ return *ps;
+
+ bool found = false;
+ QString fullPath = QString::null;
+
+ if( file[0] == '/' )
+ {
+ // absolute path, library paths are not used
+ QFileInfo info( file );
+ if( info.exists( ) && info.isReadable( ) && info.isFile( ) )
+ {
+ found = true;
+ fullPath = file;
+ }
+ }
+ else
+ {
+ QStringList plist = PMPovrayRenderWidget::povrayLibraryPaths( );
+ QStringList::ConstIterator it = plist.begin( );
+ for( ; ( it != plist.end( ) ) && !found; ++it )
+ {
+ QDir dir( *it );
+ QFileInfo info( dir, file );
+ if( info.exists( ) && info.isReadable( ) && info.isFile( ) )
+ {
+ found = true;
+ fullPath = info.absFilePath( );
+ }
+ }
+ }
+
+ if( found )
+ {
+ QString* ni = new QString( fullPath );
+ if( !m_cache.insert( file, ni ) )
+ delete ni;
+ kdDebug( PMArea ) << "File \"" << file << "\" found in "
+ << fullPath << endl;
+ }
+
+ return fullPath;
+}
+
diff --git a/kpovmodeler/pmresourcelocator.h b/kpovmodeler/pmresourcelocator.h
new file mode 100644
index 00000000..02e725cb
--- /dev/null
+++ b/kpovmodeler/pmresourcelocator.h
@@ -0,0 +1,65 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMRESOURCELOCATOR_H
+#define PMRESOURCELOCATOR_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qstring.h>
+#include <qcache.h>
+#include <kstaticdeleter.h>
+
+/**
+ * Class to find files in the povray library paths
+ */
+class PMResourceLocator
+{
+public:
+ /**
+ * Destructor
+ */
+ ~PMResourceLocator( );
+ /**
+ * Returns the full path for the file or a null string if the file
+ * was not found. The file can be a relative or absolute path.
+ */
+ static QString findFile( const QString& file );
+ /**
+ * Clears the resource cache. Call this if the library paths are changed
+ */
+ static void clearCache( );
+
+private:
+ /**
+ * Constructor
+ */
+ PMResourceLocator( );
+ /**
+ * File lookup function
+ */
+ QString lookUp( const QString& file );
+ static PMResourceLocator* s_pInstance;
+ static KStaticDeleter<PMResourceLocator> s_staticDeleter;
+
+ QCache<QString> m_cache;
+};
+
+#endif
diff --git a/kpovmodeler/pmrotate.cpp b/kpovmodeler/pmrotate.cpp
new file mode 100644
index 00000000..f3e34040
--- /dev/null
+++ b/kpovmodeler/pmrotate.cpp
@@ -0,0 +1,164 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmrotate.h"
+#include "pmrotateedit.h"
+
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pmrotatecontrolpoint.h"
+
+#include <klocale.h>
+#include <qdom.h>
+
+const PMVector rotateDefault = PMVector( 0, 0, 0 );
+
+PMDefinePropertyClass( PMRotate, PMRotateProperty );
+
+PMMetaObject* PMRotate::s_pMetaObject = 0;
+PMObject* createNewRotate( PMPart* part )
+{
+ return new PMRotate( part );
+}
+
+PMRotate::PMRotate( PMPart* part )
+ : Base( part )
+{
+}
+
+PMRotate::PMRotate( const PMRotate& r )
+ : Base( r )
+{
+ m_rotate = r.m_rotate;
+}
+
+PMRotate::~PMRotate( )
+{
+}
+
+QString PMRotate::description( ) const
+{
+ return i18n( "rotate" );
+}
+
+void PMRotate::serialize( QDomElement& e, QDomDocument& /*doc*/ ) const
+{
+ e.setAttribute( "value", m_rotate.serializeXML( ) );
+}
+
+void PMRotate::readAttributes( const PMXMLHelper& h )
+{
+ m_rotate = h.vectorAttribute( "value", rotateDefault );
+}
+
+PMMetaObject* PMRotate::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Rotate", Base::metaObject( ),
+ createNewRotate );
+ s_pMetaObject->addProperty(
+ new PMRotateProperty( "rotation", &PMRotate::setRotation, &PMRotate::rotation ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMRotate::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMRotate::setRotation( const PMVector& p )
+{
+ if( p != m_rotate )
+ {
+ if( m_pMemento )
+ {
+ m_pMemento->addData( s_pMetaObject, PMRotationID, m_rotate );
+ m_pMemento->setViewStructureChanged( );
+ }
+ m_rotate = p;
+ m_rotate.resize( 3 );
+ }
+}
+
+PMDialogEditBase* PMRotate::editWidget( QWidget* parent ) const
+{
+ return new PMRotateEdit( parent );
+}
+
+void PMRotate::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMRotationID:
+ setRotation( data->vectorData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMRotate::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
+PMMatrix PMRotate::transformationMatrix( ) const
+{
+ return PMMatrix::rotation( deg2Rad( m_rotate[0] ), deg2Rad( m_rotate[1] ),
+ deg2Rad( m_rotate[2] ) );
+}
+
+void PMRotate::controlPoints( PMControlPointList& list )
+{
+ list.append( new PMRotateControlPoint( m_rotate, PMRotationID ) );
+}
+
+void PMRotate::controlPointsChanged( PMControlPointList& list )
+{
+ PMControlPoint* p;
+
+ for( p = list.first( ); p; p = list.next( ) )
+ {
+ if( p->changed( ) )
+ {
+ switch( p->id( ) )
+ {
+ case PMRotationID:
+ setRotation( ( ( PMRotateControlPoint* ) p )->rotation( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMRotate::controlPointsChanged\n";
+ break;
+ }
+ }
+ }
+}
diff --git a/kpovmodeler/pmrotate.h b/kpovmodeler/pmrotate.h
new file mode 100644
index 00000000..0a8a1dbb
--- /dev/null
+++ b/kpovmodeler/pmrotate.h
@@ -0,0 +1,102 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMROTATE_H
+#define PMROTATE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmobject.h"
+#include "pmvector.h"
+
+/**
+ * Class for povray rotate commands.
+ */
+
+class PMRotate : public PMObject
+{
+ typedef PMObject Base;
+public:
+ /**
+ * Creates a rotate < 0, 0, 0 >
+ */
+ PMRotate( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMRotate( const PMRotate& r );
+ /**
+ * deletes the object
+ */
+ virtual ~PMRotate( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMRotate( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMRotateEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmrotate" ); }
+
+ /**
+ * Returns the rotation
+ */
+ PMVector rotation( ) const { return m_rotate; }
+ /**
+ * Sets the rotation
+ */
+ void setRotation( const PMVector& p );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /** */
+ virtual bool hasTransformationMatrix( ) const { return true; }
+ /** */
+ virtual PMMatrix transformationMatrix( ) const;
+ /** */
+ virtual void controlPoints( PMControlPointList& list );
+ /** */
+ virtual void controlPointsChanged( PMControlPointList& list );
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMRotateMementoID { PMRotationID };
+ PMVector m_rotate;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmrotatecontrolpoint.cpp b/kpovmodeler/pmrotatecontrolpoint.cpp
new file mode 100644
index 00000000..b612b4c9
--- /dev/null
+++ b/kpovmodeler/pmrotatecontrolpoint.cpp
@@ -0,0 +1,78 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmrotatecontrolpoint.h"
+#include "pmmath.h"
+#include "pmdebug.h"
+
+#include <klocale.h>
+#include <math.h>
+
+const double precision = 0.1;
+
+PMRotateControlPoint::PMRotateControlPoint( const PMVector& rot, int id )
+ : PMControlPoint( id, i18n( "Rotation" ) )
+{
+ m_rotation = rot;
+}
+
+void PMRotateControlPoint::graphicalChangeStarted( )
+{
+ m_originalRotation = m_rotation;
+ m_originalTransformation =
+ PMMatrix::rotation( deg2Rad( m_rotation.x( ) ),
+ deg2Rad( m_rotation.y( ) ),
+ deg2Rad( m_rotation.z( ) ) );
+}
+
+void PMRotateControlPoint::graphicalChange( const PMVector& startPoint,
+ const PMVector& viewNormal,
+ const PMVector& endPoint )
+{
+ double a, x, y, z;
+
+ a = PMVector::angle( startPoint, endPoint );
+ if( !approxZero( a ) )
+ {
+ PMMatrix m;
+
+ if( !approx( a, M_PI ) )
+ {
+ PMVector n = PMVector::cross( startPoint, endPoint );
+ m = PMMatrix::rotation( n, a )
+ * m_originalTransformation;
+ }
+ else
+ m = PMMatrix::rotation( viewNormal, M_PI )
+ * m_originalTransformation;
+
+ m.toRotation( &x, &y, &z );
+ m_rotation[0] = rint( rad2Deg( x ) / precision ) * precision;
+ m_rotation[1] = rint( rad2Deg( y ) / precision ) * precision;
+ m_rotation[2] = rint( rad2Deg( z ) / precision ) * precision;
+ }
+}
+
+void PMRotateControlPoint::snapToGrid( )
+{
+ int i;
+ double d = rotateGrid( );
+ if( !approxZero( d ) )
+ for( i = 0; i < 3; i++ )
+ m_rotation[i] = rint( m_rotation[i] / d ) * d;
+ setChanged( );
+}
diff --git a/kpovmodeler/pmrotatecontrolpoint.h b/kpovmodeler/pmrotatecontrolpoint.h
new file mode 100644
index 00000000..1918eec4
--- /dev/null
+++ b/kpovmodeler/pmrotatecontrolpoint.h
@@ -0,0 +1,73 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMROTATECONTROLPOINT_H
+#define PMROTATECONTROLPOINT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include "pmcontrolpoint.h"
+#include "pmmatrix.h"
+
+/**
+ * Control points for rotation
+ */
+class PMRotateControlPoint : public PMControlPoint
+{
+public:
+ /**
+ * Creates a PMRotateControlPoint with id.
+ */
+ PMRotateControlPoint( const PMVector& rotation, int id );
+ /**
+ * Deletes the PMRotateControlPoint
+ */
+ virtual ~PMRotateControlPoint( ) { };
+
+ /** */
+ virtual PMVector position( ) const { return PMVector( 0.0, 0.0, 0.0 ); }
+
+ /**
+ * Sets the rotation
+ */
+ void setRotation( const PMVector& rot ) { m_rotation = rot; }
+ /**
+ * Returns the rotation
+ */
+ PMVector rotation( ) const { return m_rotation; }
+
+ /** */
+ virtual PMCPDisplayType displayType( ) const { return CPCross; };
+ /** */
+ virtual void snapToGrid( );
+protected:
+ /** */
+ virtual void graphicalChangeStarted( );
+ /** */
+ virtual void graphicalChange( const PMVector& startPoint,
+ const PMVector& viewNormal,
+ const PMVector& endPoint );
+private:
+ PMVector m_rotation, m_originalRotation;
+ PMMatrix m_originalTransformation;
+};
+
+#endif
diff --git a/kpovmodeler/pmrotateedit.cpp b/kpovmodeler/pmrotateedit.cpp
new file mode 100644
index 00000000..df2c2340
--- /dev/null
+++ b/kpovmodeler/pmrotateedit.cpp
@@ -0,0 +1,74 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmrotateedit.h"
+#include "pmrotate.h"
+#include "pmvectoredit.h"
+
+#include <qlayout.h>
+#include <klocale.h>
+
+
+PMRotateEdit::PMRotateEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMRotateEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ m_pVector = new PMVectorEdit( "x", "y", "z", this );
+ topLayout( )->addWidget( m_pVector );
+
+ connect( m_pVector, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMRotateEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Rotate" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMRotate* ) o;
+
+ m_pVector->setVector( m_pDisplayedObject->rotation( ) );
+ m_pVector->setReadOnly( readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMRotateEdit: Can't display object\n";
+}
+
+void PMRotateEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setRotation( m_pVector->vector( ) );
+ }
+}
+
+bool PMRotateEdit::isDataValid( )
+{
+ if( m_pVector->isDataValid( ) )
+ return Base::isDataValid( );
+ return false;
+}
+#include "pmrotateedit.moc"
diff --git a/kpovmodeler/pmrotateedit.h b/kpovmodeler/pmrotateedit.h
new file mode 100644
index 00000000..89ca56fd
--- /dev/null
+++ b/kpovmodeler/pmrotateedit.h
@@ -0,0 +1,62 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMROTATEEDIT_H
+#define PMROTATEEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdialogeditbase.h"
+
+class PMRotate;
+class PMVectorEdit;
+
+/**
+ * Dialog edit class for @ref PMRotate
+ */
+class PMRotateEdit : public PMDialogEditBase
+{
+ Q_OBJECT
+ typedef PMDialogEditBase Base;
+public:
+ /**
+ * Creates a PMRotateEdit with parent and name
+ */
+ PMRotateEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMRotate* m_pDisplayedObject;
+ PMVectorEdit* m_pVector;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmscale.cpp b/kpovmodeler/pmscale.cpp
new file mode 100644
index 00000000..2be064c2
--- /dev/null
+++ b/kpovmodeler/pmscale.cpp
@@ -0,0 +1,163 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmscale.h"
+#include "pmscaleedit.h"
+#include "pmscalecontrolpoint.h"
+
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+
+#include <klocale.h>
+
+const PMVector scaleDefault = PMVector( 0, 0, 0 );
+
+PMDefinePropertyClass( PMScale, PMScaleProperty );
+
+PMMetaObject* PMScale::s_pMetaObject = 0;
+PMObject* createNewScale( PMPart* part )
+{
+ return new PMScale( part );
+}
+
+PMScale::PMScale( PMPart* part )
+ : Base( part )
+{
+ m_scale = PMVector( 1.0, 1.0, 1.0 );
+}
+
+PMScale::PMScale( const PMScale& s )
+ : Base( s )
+{
+ m_scale = s.m_scale;
+}
+
+PMScale::~PMScale( )
+{
+}
+
+QString PMScale::description( ) const
+{
+ return i18n( "scale" );
+}
+
+void PMScale::serialize( QDomElement& e, QDomDocument& /*d*/ ) const
+{
+ e.setAttribute( "value", m_scale.serializeXML( ) );
+}
+
+void PMScale::readAttributes( const PMXMLHelper& h )
+{
+ m_scale = h.vectorAttribute( "value", scaleDefault );
+}
+
+PMMetaObject* PMScale::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Scale", Base::metaObject( ),
+ createNewScale );
+ s_pMetaObject->addProperty(
+ new PMScaleProperty( "scale", &PMScale::setScale, &PMScale::scale ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMScale::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMScale::setScale( const PMVector& p )
+{
+ if( p != m_scale )
+ {
+ if( m_pMemento )
+ {
+ m_pMemento->addData( s_pMetaObject, PMScaleID, m_scale );
+ m_pMemento->setViewStructureChanged( );
+ }
+ m_scale = p;
+ m_scale.resize( 3 );
+ }
+}
+
+PMDialogEditBase* PMScale::editWidget( QWidget* parent ) const
+{
+ return new PMScaleEdit( parent );
+}
+
+void PMScale::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMScaleID:
+ setScale( data->vectorData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMScale::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
+PMMatrix PMScale::transformationMatrix( ) const
+{
+ return PMMatrix::scale( m_scale[0], m_scale[1], m_scale[2] );
+}
+
+void PMScale::controlPoints( PMControlPointList& list )
+{
+ list.append( new PMScaleControlPoint( m_scale, PMScaleID ) );
+}
+
+void PMScale::controlPointsChanged( PMControlPointList& list )
+{
+ PMControlPoint* p;
+
+ for( p = list.first( ); p; p = list.next( ) )
+ {
+ if( p->changed( ) )
+ {
+ switch( p->id( ) )
+ {
+ case PMScaleID:
+ setScale( ( ( PMScaleControlPoint* ) p )->scale( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMScale::controlPointsChanged\n";
+ break;
+ }
+ }
+ }
+}
diff --git a/kpovmodeler/pmscale.h b/kpovmodeler/pmscale.h
new file mode 100644
index 00000000..bc1a391d
--- /dev/null
+++ b/kpovmodeler/pmscale.h
@@ -0,0 +1,103 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMSCALE_H
+#define PMSCALE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmobject.h"
+#include "pmvector.h"
+
+
+/**
+ * Class for povray scale commands.
+ */
+
+class PMScale : public PMObject
+{
+ typedef PMObject Base;
+public:
+ /**
+ * Creates a scale < 0, 0, 0 >
+ */
+ PMScale( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMScale( const PMScale& s );
+ /**
+ * deletes the object
+ */
+ virtual ~PMScale( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMScale( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMScaleEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmscale" ); }
+
+ /**
+ * Returns the scale
+ */
+ PMVector scale( ) const { return m_scale; }
+ /**
+ * Sets the scale
+ */
+ void setScale( const PMVector& p );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /** */
+ virtual bool hasTransformationMatrix( ) const { return true; }
+ /** */
+ virtual PMMatrix transformationMatrix( ) const;
+ /** */
+ virtual void controlPoints( PMControlPointList& list );
+ /** */
+ virtual void controlPointsChanged( PMControlPointList& list );
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMScaleMementoID { PMScaleID };
+ PMVector m_scale;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmscalecontrolpoint.cpp b/kpovmodeler/pmscalecontrolpoint.cpp
new file mode 100644
index 00000000..c6def808
--- /dev/null
+++ b/kpovmodeler/pmscalecontrolpoint.cpp
@@ -0,0 +1,58 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmscalecontrolpoint.h"
+#include "pmmath.h"
+#include "pmdebug.h"
+
+#include <klocale.h>
+#include <math.h>
+
+const double precision = 0.001;
+
+PMScaleControlPoint::PMScaleControlPoint( const PMVector& scale, int id )
+ : PMControlPoint( id, i18n( "Scale" ) )
+{
+ m_scale = scale;
+}
+
+void PMScaleControlPoint::graphicalChangeStarted( )
+{
+ m_originalScale = m_scale;
+}
+
+void PMScaleControlPoint::graphicalChange( const PMVector& startPoint,
+ const PMVector& /*viewNormal*/,
+ const PMVector& endPoint )
+{
+ int i;
+
+ for( i = 0; i < 3; i++ )
+ if( !approxZero( startPoint[i] ) )
+ m_scale[i] = rint( m_originalScale[i] * endPoint[i] / startPoint[i]
+ / precision ) * precision;
+}
+
+void PMScaleControlPoint::snapToGrid( )
+{
+ int i;
+ double d = scaleGrid( );
+ if( !approxZero( d ) )
+ for( i = 0; i < 3; i++ )
+ m_scale[i] = rint( m_scale[i] / d ) * d;
+ setChanged( );
+}
diff --git a/kpovmodeler/pmscalecontrolpoint.h b/kpovmodeler/pmscalecontrolpoint.h
new file mode 100644
index 00000000..5cb4a091
--- /dev/null
+++ b/kpovmodeler/pmscalecontrolpoint.h
@@ -0,0 +1,71 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMSCALECONTROLPOINT_H
+#define PMSCALECONTROLPOINT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include "pmcontrolpoint.h"
+
+/**
+ * Control points for scale
+ */
+class PMScaleControlPoint : public PMControlPoint
+{
+public:
+ /**
+ * Creates a PMScaleControlPoint with id.
+ */
+ PMScaleControlPoint( const PMVector& scale, int id );
+ /**
+ * Deletes the PMScaleControlPoint
+ */
+ virtual ~PMScaleControlPoint( ) { };
+
+ /** */
+ virtual PMVector position( ) const { return PMVector( 0.0, 0.0, 0.0 ); }
+
+ /**
+ * Sets the scale
+ */
+ void setScale( const PMVector& sc ) { m_scale = sc; }
+ /**
+ * Returns the scale
+ */
+ PMVector scale( ) const { return m_scale; }
+
+ /** */
+ virtual PMCPDisplayType displayType( ) const { return CPCross; };
+ /** */
+ virtual void snapToGrid( );
+protected:
+ /** */
+ virtual void graphicalChangeStarted( );
+ /** */
+ virtual void graphicalChange( const PMVector& startPoint,
+ const PMVector& viewNormal,
+ const PMVector& endPoint );
+private:
+ PMVector m_scale, m_originalScale;
+};
+
+#endif
diff --git a/kpovmodeler/pmscaleedit.cpp b/kpovmodeler/pmscaleedit.cpp
new file mode 100644
index 00000000..1df7b40f
--- /dev/null
+++ b/kpovmodeler/pmscaleedit.cpp
@@ -0,0 +1,74 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmscaleedit.h"
+#include "pmscale.h"
+#include "pmvectoredit.h"
+
+#include <qlayout.h>
+#include <klocale.h>
+
+
+PMScaleEdit::PMScaleEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMScaleEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ m_pVector = new PMVectorEdit( "x", "y", "z", this );
+ topLayout( )->addWidget( m_pVector );
+
+ connect( m_pVector, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMScaleEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Scale" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMScale* ) o;
+
+ m_pVector->setVector( m_pDisplayedObject->scale( ) );
+ m_pVector->setReadOnly( readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMScaleEdit: Can't display object\n";
+}
+
+void PMScaleEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setScale( m_pVector->vector( ) );
+ }
+}
+
+bool PMScaleEdit::isDataValid( )
+{
+ if( m_pVector->isDataValid( ) )
+ return Base::isDataValid( );
+ return false;
+}
+#include "pmscaleedit.moc"
diff --git a/kpovmodeler/pmscaleedit.h b/kpovmodeler/pmscaleedit.h
new file mode 100644
index 00000000..f18989f5
--- /dev/null
+++ b/kpovmodeler/pmscaleedit.h
@@ -0,0 +1,62 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMSCALEEDIT_H
+#define PMSCALEEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdialogeditbase.h"
+
+class PMScale;
+class PMVectorEdit;
+
+/**
+ * Dialog edit class for @ref PMScale
+ */
+class PMScaleEdit : public PMDialogEditBase
+{
+ Q_OBJECT
+ typedef PMDialogEditBase Base;
+public:
+ /**
+ * Creates a PMScaleEdit with parent and name
+ */
+ PMScaleEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMScale* m_pDisplayedObject;
+ PMVectorEdit* m_pVector;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmscanner.cpp b/kpovmodeler/pmscanner.cpp
new file mode 100644
index 00000000..f67b7035
--- /dev/null
+++ b/kpovmodeler/pmscanner.cpp
@@ -0,0 +1,1353 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <klocale.h>
+
+#include "pmdebug.h"
+#include "pmscanner.h"
+#include "pmtokens.h"
+
+
+//#define PMSCAN_DEBUG
+
+PMReservedWordDict::PMReservedWordDict( PMDictMode mode )
+ : QAsciiDict<int>( 353 )
+{
+ switch( mode )
+ {
+ case PMDReservedWords:
+ insert( "aa_level", new int( AA_LEVEL_TOK ) );
+ insert( "aa_threshold", new int( AA_THRESHOLD_TOK ) );
+ insert( "abs", new int( ABS_TOK ) );
+ insert( "absorption", new int( ABSORPTION_TOK ) );
+ insert( "accuracy", new int( ACCURACY_TOK ) );
+ insert( "acos", new int( ACOS_TOK ) );
+ insert( "acosh", new int( ACOSH_TOK ) );
+ insert( "adaptive", new int( ADAPTIVE_TOK ) );
+ insert( "adc_bailout", new int( ADC_BAILOUT_TOK ) );
+ insert( "agate", new int( AGATE_TOK ) );
+ insert( "agate_turb", new int( AGATE_TURB_TOK ) );
+ insert( "all", new int( ALL_TOK ) );
+ insert( "all_intersections", new int( ALL_INTERSECTIONS_TOK ) );
+ insert( "alpha", new int( ALPHA_TOK ) );
+ insert( "altitude", new int( ALTITUDE_TOK ) );
+ insert( "always_sample", new int ( ALWAYS_SAMPLE_TOK ) );
+ insert( "ambient", new int( AMBIENT_TOK ) );
+ insert( "ambient_light", new int( AMBIENT_LIGHT_TOK ) );
+ insert( "angle", new int( ANGLE_TOK ) );
+ insert( "aperture", new int( APERTURE_TOK ) );
+ insert( "arc_angle", new int( ARC_ANGLE_TOK ) );
+ insert( "area_light", new int( AREA_LIGHT_TOK ) );
+ insert( "autostop", new int ( AUTOSTOP_TOK ) );
+ insert( "circular", new int( AREA_CIRCULAR_TOK ) );
+ insert( "asc", new int( ASC_TOK ) );
+ insert( "asin", new int( ASIN_TOK ) );
+ insert( "asinh", new int( ASINH_TOK ) );
+ insert( "assumed_gamma", new int( ASSUMED_GAMMA_TOK ) );
+ insert( "atan", new int( ATAN_TOK ) );
+ insert( "atan2", new int( ATAN2_TOK ) );
+ insert( "atanh", new int( ATANH_TOK ) );
+ insert( "atmosphere", new int( ATMOSPHERE_TOK ) );
+ insert( "atmospheric_attenuation", new int( ATMOSPHERIC_ATTENUATION_TOK ) );
+ insert( "attenuating", new int( ATTENUATING_TOK ) );
+ insert( "average", new int( AVERAGE_TOK ) );
+ insert( "b_spline", new int( B_SPLINE_TOK ) );
+ insert( "background", new int( BACKGROUND_TOK ) );
+ insert( "bezier_spline", new int( BEZIER_SPLINE_TOK ) );
+ insert( "bicubic_patch", new int( BICUBIC_PATCH_TOK ) );
+ insert( "black_hole", new int( BLACK_HOLE_TOK ) );
+ insert( "blob", new int( BLOB_TOK ) );
+ insert( "blue", new int( BLUE_TOK ) );
+ insert( "blur_samples", new int( BLUR_SAMPLES_TOK ) );
+ insert( "bounded_by", new int( BOUNDED_BY_TOK ) );
+ insert( "box", new int( BOX_TOK ) );
+ insert( "boxed", new int( BOXED_TOK ) );
+ insert( "bozo", new int( BOZO_TOK ) );
+ insert( "brick", new int( BRICK_TOK ) );
+ insert( "brick_size", new int( BRICK_SIZE_TOK ) );
+ insert( "brightness", new int( BRIGHTNESS_TOK ) );
+ insert( "brilliance", new int( BRILLIANCE_TOK ) );
+ insert( "bumps", new int( BUMPS_TOK ) );
+ insert( "bumpy1", new int( BUMPY1_TOK ) );
+ insert( "bumpy2", new int( BUMPY2_TOK ) );
+ insert( "bumpy3", new int( BUMPY3_TOK ) );
+ insert( "bump_map", new int( BUMP_MAP_TOK ) );
+ insert( "bump_size", new int( BUMP_SIZE_TOK ) );
+ insert( "camera", new int( CAMERA_TOK ) );
+ insert( "caustics", new int( CAUSTICS_TOK ) );
+ insert( "ceil", new int( CEIL_TOK ) );
+ insert( "checker", new int( CHECKER_TOK ) );
+ insert( "chr", new int( CHR_TOK ) );
+ insert( "cells", new int( CELLS_TOK ) );
+ insert( "clipped_by", new int( CLIPPED_BY_TOK ) );
+ insert( "clock", new int( CLOCK_TOK ) );
+ insert( "clock_delta", new int( CLOCK_DELTA_TOK ) );
+ insert( "collect", new int( COLLECT_TOK ) );
+ insert( "color", new int( COLOR_TOK ) );
+ insert( "color_map", new int( COLOR_MAP_TOK ) );
+ insert( "colour", new int( COLOUR_TOK ) );
+ insert( "colour_map", new int( COLOUR_MAP_TOK ) );
+ insert( "component", new int( COMPONENT_TOK ) );
+ insert( "composite", new int( COMPOSITE_TOK ) );
+ insert( "concat", new int( CONCAT_TOK ) );
+ insert( "cone", new int( CONE_TOK ) );
+ insert( "confidence", new int( CONFIDENCE_TOK ) );
+ insert( "conic_sweep", new int( CONIC_SWEEP_TOK ) );
+ insert( "conserve_energy", new int( CONSERVE_ENERGY_TOK ) );
+ insert( "constant", new int( CONSTANT_TOK ) );
+ insert( "contained_by", new int( CONTAINED_BY_TOK ) );
+ insert( "control0", new int( CONTROL0_TOK ) );
+ insert( "control1", new int( CONTROL1_TOK ) );
+ insert( "cos", new int( COS_TOK ) );
+ insert( "cosh", new int( COSH_TOK ) );
+ insert( "count", new int( COUNT_TOK ) );
+ insert( "crackle", new int( CRACKLE_TOK ) );
+ insert( "crand", new int( CRAND_TOK ) );
+ insert( "cube", new int( CUBE_TOK ) );
+ insert( "cubic", new int( CUBIC_TOK ) );
+ insert( "cubic_spline", new int( CUBIC_SPLINE_TOK ) );
+ insert( "cubic_wave", new int( CUBIC_WAVE_TOK ) );
+ insert( "cylinder", new int( CYLINDER_TOK ) );
+ insert( "cylindrical", new int( CYLINDRICAL_TOK ) );
+ insert( "degrees", new int( DEGREES_TOK ) );
+ insert( "dents", new int( DENTS_TOK ) );
+ insert( "density", new int( DENSITY_TOK ) );
+ insert( "density_file", new int( DENSITY_FILE_TOK ) );
+ insert( "density_map", new int( DENSITY_MAP_TOK ) );
+ insert( "df3", new int( DF3_TOK ) );
+ insert( "difference", new int( DIFFERENCE_TOK ) );
+ insert( "diffuse", new int( DIFFUSE_TOK ) );
+ insert( "direction", new int( DIRECTION_TOK ) );
+ insert( "disc", new int( DISC_TOK ) );
+ insert( "dispersion", new int ( DISPERSION_TOK ) );
+ insert( "dispersion_samples", new int ( DISPERSION_SAMPLES_TOK ) );
+ insert( "dist_exp", new int ( DIST_EXP_TOK ) );
+ insert( "distance", new int( DISTANCE_TOK ) );
+ insert( "distance_maximum", new int( DISTANCE_MAXIMUM_TOK ) );
+ insert( "div", new int( DIV_TOK ) );
+ insert( "double_illuminate", new int( DOUBLE_ILLUMINATE_TOK ) );
+ insert( "dust", new int( DUST_TOK ) );
+ insert( "dust_type", new int( DUST_TYPE_TOK ) );
+ insert( "eccentricity", new int( ECCENTRICITY_TOK ) );
+ insert( "emission", new int( EMISSION_TOK ) );
+ insert( "emitting", new int( EMITTING_TOK ) );
+ insert( "error", new int( ERROR_TOK ) );
+ insert( "error_bound", new int( ERROR_BOUND_TOK ) );
+ insert( "evaluate", new int( EVALUATE_TOK ) );
+ insert( "exp", new int( EXP_TOK ) );
+ insert( "expand_thresholds", new int (EXPAND_THRESHOLDS_TOK) );
+ insert( "exponent", new int( EXPONENT_TOK ) );
+ insert( "exterior", new int( EXTERIOR_TOK ) );
+ insert( "extinction", new int( EXTINCTION_TOK ) );
+ insert( "fade_distance", new int( FADE_DISTANCE_TOK ) );
+ insert( "fade_power", new int( FADE_POWER_TOK ) );
+ insert( "falloff", new int( FALLOFF_TOK ) );
+ insert( "falloff_angle", new int( FALLOFF_ANGLE_TOK ) );
+ insert( "false", new int( FALSE_TOK ) );
+ insert( "file_exists", new int( FILE_EXISTS_TOK ) );
+ insert( "filter", new int( FILTER_TOK ) );
+ insert( "finish", new int( FINISH_TOK ) );
+ insert( "fisheye", new int( FISHEYE_TOK ) );
+ insert( "flatness", new int( FLATNESS_TOK ) );
+ insert( "flip", new int( FLIP_TOK ) );
+ insert( "floor", new int( FLOOR_TOK ) );
+ insert( "focal_point", new int( FOCAL_POINT_TOK ) );
+ insert( "fog", new int( FOG_TOK ) );
+ insert( "fog_alt", new int( FOG_ALT_TOK ) );
+ insert( "fog_offset", new int( FOG_OFFSET_TOK ) );
+ insert( "fog_type", new int( FOG_TYPE_TOK ) );
+ insert( "form", new int( FORM_TOK ) );
+ insert( "fresnel", new int( FRESNEL_TOK ) );
+ insert( "frequency", new int( FREQUENCY_TOK ) );
+ insert( "function", new int( FUNCTION_TOK ) );
+ insert( "gather", new int( GATHER_TOK ) );
+ insert( "gif", new int( GIF_TOK ) );
+ insert( "global_lights", new int ( GLOBAL_LIGHTS_TOK ) );
+ insert( "global_settings", new int( GLOBAL_SETTINGS_TOK ) );
+ insert( "glowing", new int( GLOWING_TOK ) );
+ insert( "gradient", new int( GRADIENT_TOK ) );
+ insert( "granite", new int( GRANITE_TOK ) );
+ insert( "gray_threshold", new int( GRAY_THRESHOLD_TOK ) );
+ insert( "green", new int( GREEN_TOK ) );
+ insert( "halo", new int( HALO_TOK ) );
+ insert( "height_field", new int( HEIGHT_FIELD_TOK ) );
+ insert( "hexagon", new int( HEXAGON_TOK ) );
+ insert( "hf_gray_16", new int( HF_GRAY_16_TOK ) );
+ insert( "hierarchy", new int( HIERARCHY_TOK ) );
+ insert( "hollow", new int( HOLLOW_TOK ) );
+ insert( "hypercomplex", new int( HYPERCOMPLEX_TOK ) );
+ insert( "iff", new int( IFF_TOK ) );
+ insert( "image_map", new int( IMAGE_MAP_TOK ) );
+ insert( "incidence", new int( INCIDENCE_TOK ) );
+ insert( "inside_vector", new int( INSIDE_VECTOR_TOK ) );
+ insert( "int", new int( INT_TOK ) );
+ insert( "interior", new int( INTERIOR_TOK ) );
+ insert( "interior_texture", new int( INTERIOR_TEXTURE_TOK ) );
+ insert( "interpolate", new int( INTERPOLATE_TOK ) );
+ insert( "intersection", new int( INTERSECTION_TOK ) );
+ insert( "intervals", new int( INTERVALS_TOK ) );
+ insert( "inverse", new int( INVERSE_TOK ) );
+ insert( "ior", new int( IOR_TOK ) );
+ insert( "irid", new int( IRID_TOK ) );
+ insert( "irid_wavelength", new int( IRID_WAVELENGTH_TOK ) );
+ insert( "isosurface", new int( ISOSURFACE_TOK ) );
+ insert( "jitter", new int( JITTER_TOK ) );
+ insert( "julia", new int( JULIA_TOK ) );
+ insert( "julia_fractal", new int( JULIA_FRACTAL_TOK ) );
+ insert( "lambda", new int( LAMBDA_TOK ) );
+ insert( "lathe", new int( LATHE_TOK ) );
+ insert( "leopard", new int( LEOPARD_TOK ) );
+ insert( "light_group", new int ( LIGHT_GROUP_TOK ) );
+ insert( "light_source", new int( LIGHT_SOURCE_TOK ) );
+ insert( "linear", new int( LINEAR_TOK ) );
+ insert( "linear_spline", new int( LINEAR_SPLINE_TOK ) );
+ insert( "linear_sweep", new int( LINEAR_SWEEP_TOK ) );
+ insert( "location", new int( LOCATION_TOK ) );
+ insert( "log", new int( LOG_TOK ) );
+ insert( "looks_like", new int( LOOKS_LIKE_TOK ) );
+ insert( "look_at", new int( LOOK_AT_TOK ) );
+ insert( "low_error_factor", new int( LOW_ERROR_FACTOR_TOK ) );
+ insert( "magnet", new int ( MAGNET_TOK ) );
+ insert( "major_radius", new int( MAJOR_RADIUS_TOK ) );
+ insert( "mandel", new int( MANDEL_TOK ) );
+ insert( "map_type", new int( MAP_TYPE_TOK ) );
+ insert( "marble", new int( MARBLE_TOK ) );
+ insert( "material", new int( MATERIAL_TOK ) );
+ insert( "material_map", new int( MATERIAL_MAP_TOK ) );
+ insert( "matrix", new int( MATRIX_TOK ) );
+ insert( "max", new int( MAX_TOK ) );
+ insert( "max_gradient", new int( MAX_GRADIENT_TOK ) );
+ insert( "max_intersections", new int( MAX_INTERSECTIONS_TOK ) );
+ insert( "max_iteration", new int( MAX_ITERATION_TOK ) );
+ insert( "max_sample", new int( MAX_SAMPLE_TOK ) );
+ insert( "max_trace", new int( MAX_TRACE_TOK ) );
+ insert( "max_trace_level", new int( MAX_TRACE_LEVEL_TOK ) );
+ insert( "max_value", new int( MAX_VALUE_TOK ) );
+ insert( "media", new int( MEDIA_TOK ) );
+ insert( "media_attenuation", new int( MEDIA_ATTENUATION_TOK ) );
+ insert( "media_interaction", new int( MEDIA_INTERACTION_TOK ) );
+ insert( "merge", new int( MERGE_TOK ) );
+ insert( "mesh", new int( MESH_TOK ) );
+ insert( "metallic", new int( METALLIC_TOK ) );
+ insert( "method", new int( METHOD_TOK ) );
+ insert( "metric", new int( METRIC_TOK ) );
+ insert( "min", new int( MIN_TOK ) );
+ insert( "minimum_reuse", new int( MINIMUM_REUSE_TOK ) );
+ insert( "mod", new int( MOD_TOK ) );
+ insert( "mortar", new int( MORTAR_TOK ) );
+ insert( "nearest_count", new int( NEAREST_COUNT_TOK ) );
+ insert( "no", new int( NO_TOK ) );
+ insert( "noise_generator", new int( NOISE_GENERATOR_TOK ) );
+ insert( "normal", new int( NORMAL_TOK ) );
+ insert( "normal_map", new int( NORMAL_MAP_TOK ) );
+ insert( "no_image", new int( NO_IMAGE_TOK ) );
+ insert( "no_reflection", new int( NO_REFLECTION_TOK ) );
+ insert( "no_shadow", new int( NO_SHADOW_TOK ) );
+ insert( "number_of_waves", new int( NUMBER_OF_WAVES_TOK ) );
+ insert( "object", new int( OBJECT_TOK ) );
+ insert( "octaves", new int( OCTAVES_TOK ) );
+ insert( "off", new int( OFF_TOK ) );
+ insert( "offset", new int( OFFSET_TOK ) );
+ insert( "omega", new int( OMEGA_TOK ) );
+ insert( "omnimax", new int( OMNIMAX_TOK ) );
+ insert( "on", new int( ON_TOK ) );
+ insert( "once", new int( ONCE_TOK ) );
+ insert( "onion", new int( ONION_TOK ) );
+ insert( "open", new int( OPEN_TOK ) );
+ insert( "orient", new int( ORIENT_TOK ) );
+ insert( "orthographic", new int( ORTHOGRAPHIC_TOK ) );
+ insert( "panoramic", new int( PANORAMIC_TOK ) );
+ insert( "parallel", new int( PARALLEL_TOK ) );
+ insert( "pass_through", new int ( PASS_THROUGH_TOK ) );
+ insert( "pattern1", new int( PATTERN1_TOK ) );
+ insert( "pattern2", new int( PATTERN2_TOK ) );
+ insert( "pattern3", new int( PATTERN3_TOK ) );
+ insert( "perspective", new int( PERSPECTIVE_TOK ) );
+ insert( "pgm", new int( PGM_TOK ) );
+ insert( "phase", new int( PHASE_TOK ) );
+ insert( "phong", new int( PHONG_TOK ) );
+ insert( "phong_size", new int( PHONG_SIZE_TOK ) );
+ insert( "photons", new int ( PHOTONS_TOK ) );
+ insert( "pi", new int( PI_TOK ) );
+ insert( "pigment", new int( PIGMENT_TOK ) );
+ insert( "pigment_map", new int( PIGMENT_MAP_TOK ) );
+ insert( "planar", new int( PLANAR_TOK ) );
+ insert( "plane", new int( PLANE_TOK ) );
+ insert( "png", new int( PNG_TOK ) );
+ insert( "point_at", new int( POINT_AT_TOK ) );
+ insert( "poly", new int( POLY_TOK ) );
+ insert( "poly_wave", new int( POLY_WAVE_TOK ) );
+ insert( "polygon", new int( POLYGON_TOK ) );
+ insert( "pot", new int( POT_TOK ) );
+ insert( "pow", new int( POW_TOK ) );
+ insert( "ppm", new int( PPM_TOK ) );
+ insert( "precision", new int( PRECISION_TOK ) );
+ insert( "pretrace_end", new int( PRETRACE_END_TOK ) );
+ insert( "pretrace_start", new int( PRETRACE_START_TOK ) );
+ insert( "prism", new int( PRISM_TOK ) );
+ insert( "projected_through", new int( PROJECTED_THROUGH_TOK ) );
+ insert( "pwr", new int( PWR_TOK ) );
+ insert( "quadratic_spline", new int( QUADRATIC_SPLINE_TOK ) );
+ insert( "quadric", new int( QUADRIC_TOK ) );
+ insert( "quartic", new int( QUARTIC_TOK ) );
+ insert( "quaternion", new int( QUATERNION_TOK ) );
+ insert( "quick_color", new int( QUICK_COLOR_TOK ) );
+ insert( "quick_colour", new int( QUICK_COLOUR_TOK ) );
+ insert( "quilted", new int( QUILTED_TOK ) );
+ insert( "radial", new int( RADIAL_TOK ) );
+ insert( "radians", new int( RADIANS_TOK ) );
+ insert( "radiosity", new int( RADIOSITY_TOK ) );
+ insert( "radius", new int( RADIUS_TOK ) );
+ insert( "rainbow", new int( RAINBOW_TOK ) );
+ insert( "ramp_wave", new int( RAMP_WAVE_TOK ) );
+ insert( "rand", new int( RAND_TOK ) );
+ insert( "ratio", new int( RATIO_TOK ) );
+ insert( "reciprocal", new int( RECIPROCAL_TOK ) );
+ insert( "recursion_limit", new int( RECURSION_LIMIT_TOK ) );
+ insert( "red", new int( RED_TOK ) );
+ insert( "reflection", new int( REFLECTION_TOK ) );
+ insert( "reflection_exponent", new int( REFLECTION_EXPONENT_TOK ) );
+ insert( "refraction", new int( REFRACTION_TOK ) );
+ insert( "repeat", new int( REPEAT_TOK ) );
+ insert( "rgb", new int( RGB_TOK ) );
+ insert( "rgbf", new int( RGBF_TOK ) );
+ insert( "rgbft", new int( RGBFT_TOK ) );
+ insert( "rgbt", new int( RGBT_TOK ) );
+ insert( "right", new int( RIGHT_TOK ) );
+ insert( "ripples", new int( RIPPLES_TOK ) );
+ insert( "rotate", new int( ROTATE_TOK ) );
+ insert( "roughness", new int( ROUGHNESS_TOK ) );
+ insert( "samples", new int( SAMPLES_TOK ) );
+ insert( "scale", new int( SCALE_TOK ) );
+ insert( "scallop_wave", new int( SCALLOP_WAVE_TOK ) );
+ insert( "scattering", new int( SCATTERING_TOK ) );
+ insert( "seed", new int( SEED_TOK ) );
+ insert( "shadowless", new int( SHADOWLESS_TOK ) );
+ insert( "sin", new int( SIN_TOK ) );
+ insert( "sine_wave", new int( SINE_WAVE_TOK ) );
+ insert( "sinh", new int( SINH_TOK ) );
+ insert( "sky", new int( SKY_TOK ) );
+ insert( "sky_sphere", new int( SKY_SPHERE_TOK ) );
+ insert( "slice", new int( SLICE_TOK ) );
+ insert( "slope", new int( SLOPE_TOK ) );
+ insert( "slope_map", new int( SLOPE_MAP_TOK ) );
+ insert( "smooth", new int( SMOOTH_TOK ) );
+ insert( "smooth_triangle", new int( SMOOTH_TRIANGLE_TOK ) );
+ insert( "solid", new int( SOLID_TOK ) );
+ insert( "sor", new int( SOR_TOK ) );
+ insert( "spacing", new int ( SPACING_TOK ) );
+ insert( "specular", new int( SPECULAR_TOK ) );
+ insert( "sphere", new int( SPHERE_TOK ) );
+ insert( "sphere_sweep", new int ( SPHERE_SWEEP_TOK ) );
+ insert( "spherical", new int( SPHERICAL_TOK ) );
+ insert( "spiral", new int( SPIRAL_TOK ) );
+ insert( "spiral1", new int( SPIRAL1_TOK ) );
+ insert( "spiral2", new int( SPIRAL2_TOK ) );
+ insert( "spotlight", new int( SPOTLIGHT_TOK ) );
+ insert( "spotted", new int( SPOTTED_TOK ) );
+ insert( "sqr", new int( SQR_TOK ) );
+ insert( "sqrt", new int( SQRT_TOK ) );
+ insert( "str", new int( STR_TOK ) );
+ insert( "strcmp", new int( STRCMP_TOK ) );
+ insert( "strength", new int( STRENGTH_TOK ) );
+ insert( "strlen", new int( STRLEN_TOK ) );
+ insert( "strlwr", new int( STRLWR_TOK ) );
+ insert( "strupr", new int( STRUPR_TOK ) );
+ insert( "sturm", new int( STURM_TOK ) );
+ insert( "substr", new int( SUBSTR_TOK ) );
+ insert( "superellipsoid", new int( SUPERELLIPSOID_TOK ) );
+ insert( "sys", new int( SYS_TOK ) );
+ insert( "t", new int( T_TOK ) );
+ insert( "tan", new int( TAN_TOK ) );
+ insert( "tanh", new int( TANH_TOK ) );
+ insert( "target", new int( TARGET_TOK ) );
+ insert( "test_camera_1", new int( TEST_CAMERA_1_TOK ) );
+ insert( "test_camera_2", new int( TEST_CAMERA_2_TOK ) );
+ insert( "test_camera_3", new int( TEST_CAMERA_3_TOK ) );
+ insert( "test_camera_4", new int( TEST_CAMERA_4_TOK ) );
+ insert( "text", new int( TEXT_TOK ) );
+ insert( "texture", new int( TEXTURE_TOK ) );
+ insert( "texture_map", new int( TEXTURE_MAP_TOK ) );
+ insert( "tga", new int( TGA_TOK ) );
+ insert( "thickness", new int( THICKNESS_TOK ) );
+ insert( "threshold", new int( THRESHOLD_TOK ) );
+ insert( "tightness", new int( TIGHTNESS_TOK ) );
+ insert( "tile2", new int( TILE2_TOK ) );
+ insert( "tiles", new int( TILES_TOK ) );
+ insert( "tolerance", new int( TOLERANCE_TOK ) );
+ insert( "toroidal", new int( TOROIDAL_TOK ) );
+ insert( "torus", new int( TORUS_TOK ) );
+ insert( "track", new int( TRACK_TOK ) );
+ insert( "transform", new int( TRANSFORM_TOK ) );
+ insert( "translate", new int( TRANSLATE_TOK ) );
+ insert( "transmit", new int( TRANSMIT_TOK ) );
+ insert( "triangle", new int( TRIANGLE_TOK ) );
+ insert( "triangle_wave", new int( TRIANGLE_WAVE_TOK ) );
+ insert( "true", new int( TRUE_TOK ) );
+ insert( "ttf", new int( TTF_TOK ) );
+ insert( "turbulence", new int( TURBULENCE_TOK ) );
+ insert( "turb_depth", new int( TURB_DEPTH_TOK ) );
+ insert( "type", new int( TYPE_TOK ) );
+ insert( "u", new int( U_TOK ) );
+ insert( "ultra_wide_angle", new int( ULTRA_WIDE_ANGLE_TOK ) );
+ insert( "union", new int( UNION_TOK ) );
+ insert( "up", new int( UP_TOK ) );
+ insert( "use_color", new int( USE_COLOR_TOK ) );
+ insert( "use_colour", new int( USE_COLOUR_TOK ) );
+ insert( "use_index", new int( USE_INDEX_TOK ) );
+ insert( "u_steps", new int( U_STEPS_TOK ) );
+ insert( "uv_mapping", new int( UV_MAPPING_TOK ) );
+ insert( "uv_vectors", new int( UV_VECTORS_TOK ) );
+ insert( "v", new int( V_TOK ) );
+ insert( "val", new int( VAL_TOK ) );
+ insert( "variance", new int( VARIANCE_TOK ) );
+ insert( "vaxis_rotate", new int( VAXIS_ROTATE_TOK ) );
+ insert( "vcross", new int( VCROSS_TOK ) );
+ insert( "vdot", new int( VDOT_TOK ) );
+ insert( "vlength", new int( VLENGTH_TOK ) );
+ insert( "vnormalize", new int( VNORMALIZE_TOK ) );
+ insert( "volume_object", new int( VOLUME_OBJECT_TOK ) );
+ insert( "volume_rendered", new int( VOLUME_RENDERED_TOK ) );
+ insert( "vol_with_light", new int( VOL_WITH_LIGHT_TOK ) );
+ insert( "vrotate", new int( VROTATE_TOK ) );
+ insert( "v_steps", new int( V_STEPS_TOK ) );
+ insert( "warp", new int( WARP_TOK ) );
+ insert( "water_level", new int( WATER_LEVEL_TOK ) );
+ insert( "waves", new int( WAVES_TOK ) );
+ insert( "width", new int( WIDTH_TOK ) );
+ insert( "wood", new int( WOOD_TOK ) );
+ insert( "wrinkles", new int( WRINKLES_TOK ) );
+ insert( "x", new int( X_TOK ) );
+ insert( "y", new int( Y_TOK ) );
+ insert( "yes", new int( YES_TOK ) );
+ insert( "z", new int( Z_TOK ) );
+ break;
+ case PMDDirectives:
+ insert( "break", new int( BREAK_TOK ) );
+ insert( "case", new int( CASE_TOK ) );
+ insert( "debug", new int( DEBUG_TOK ) );
+ insert( "declare", new int( DECLARE_TOK ) );
+ insert( "default", new int( DEFAULT_TOK ) );
+ insert( "else", new int( ELSE_TOK ) );
+ insert( "end", new int( END_TOK ) );
+ insert( "if", new int( IF_TOK ) );
+ insert( "ifdef", new int( IFDEF_TOK ) );
+ insert( "ifndef", new int( IFNDEF_TOK ) );
+ insert( "include", new int( INCLUDE_TOK ) );
+ insert( "range", new int( RANGE_TOK ) );
+ insert( "render", new int( RENDER_TOK ) );
+ insert( "statistics", new int( STATISTICS_TOK ) );
+ insert( "switch", new int( SWITCH_TOK ) );
+ insert( "version", new int( VERSION_TOK ) );
+ insert( "warning", new int( WARNING_TOK ) );
+ insert( "while", new int( WHILE_TOK ) );
+ break;
+ }
+}
+
+PMReservedWordDict::~PMReservedWordDict( )
+{
+}
+
+PMReservedWordDict PMScanner::m_reservedWords( PMReservedWordDict::PMDReservedWords );
+PMReservedWordDict PMScanner::m_directives( PMReservedWordDict::PMDDirectives );
+
+const char* c_commentName = "*PMName ";
+const int c_commentNameLength = 8;
+
+const char* c_commentRawBegin = "*PMRawBegin";
+const int c_commentRawBeginLength = 11;
+
+const char* c_commentRawEnd = "//*PMRawEnd";
+const int c_commentRawEndLength = 11;
+
+
+PMScanner::PMScanner( QIODevice* device )
+{
+ m_svalueAlloc = 256;
+ m_svalue = ( char* ) malloc( m_svalueAlloc );
+ m_svalue[0] = '\0';
+ m_lastAlloc = m_svalue + m_svalueAlloc;
+ m_lastChar = m_svalue;
+
+ m_ivalue = 0;
+ m_fvalue = 0;
+ m_pDevice = device;
+ m_line = 1;
+ m_char = 0;
+ m_indentation = 0;
+ m_rawIndentation = 0;
+ m_bFunctionMode = false;
+
+// m_lineData = "";
+// m_lineDataPos = 100;
+// m_lineDataLength = 0;
+ nextChar( );
+}
+
+PMScanner::~PMScanner( )
+{
+ if( m_svalue )
+ free( m_svalue );
+}
+
+void PMScanner::nextChar( )
+{
+ do
+ {
+ m_char = m_pDevice->getch( );
+ }
+ while( m_char == '\r' );
+}
+
+void PMScanner::clearSValue( )
+{
+ m_svalue[0] = '\0';
+ m_lastChar = m_svalue;
+}
+
+void PMScanner::addChar( char c )
+{
+ *m_lastChar = c;
+ m_lastChar++;
+
+ if( m_lastChar == m_lastAlloc )
+ {
+ m_svalueAlloc += 64;
+ m_svalue = ( char* ) realloc( m_svalue, m_svalueAlloc );
+ m_lastAlloc = m_svalue + m_svalueAlloc;
+ m_lastChar = m_lastAlloc - 64;
+ }
+
+ *m_lastChar = '\0';
+}
+
+bool PMScanner::isseparation( int c )
+{
+ if( c < 0 )
+ return true;
+ if( isspace( c ) )
+ return true;
+ switch( c )
+ {
+ case '{':
+ case '}':
+ case '<':
+ case '>':
+ case '(':
+ case ')':
+ case '[':
+ case ']':
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case ',':
+ case ';':
+ case '=':
+ case '.':
+ return true;
+ break;
+ default:
+ return false;
+ }
+ return false;
+}
+
+
+void PMScanner::scanError( int c )
+{
+ m_token = SCANNER_ERROR_TOK;
+ if( isprint( c ) )
+ m_error = i18n( "Unexpected character '%1' after \"%2\"" )
+ .arg( ( char )c ).arg( m_svalue );
+ else
+ m_error = i18n( "Unexpected character %1 after \"%2\"" )
+ .arg( c, 4, 16 ).arg( m_svalue );
+
+#ifdef PMSCAN_DEBUG
+ kdDebug( PMArea ) << "Line " << m_line << ": Error " << m_error << "\n";
+#endif
+}
+
+
+int PMScanner::nextToken( )
+{
+ int status = START_ST;
+ int cdepth = 0;
+ bool consumed;
+ bool end = false;
+
+ clearSValue( );
+ m_ivalue = 0;
+ m_fvalue = 0;
+// m_error = "";
+
+ if( m_bFunctionMode )
+ {
+ m_bFunctionMode = false;
+ // FIXME: TODO brackets in comments will not be scanned correctly
+ int count = 1;
+
+ while( count > 0 )
+ {
+ if( m_char < 0 )
+ count = 0;
+ else if( m_char == '{' )
+ count++;
+ else if( m_char == '}' )
+ count--;
+ if( count > 0 )
+ {
+ addChar( m_char );
+ nextChar( );
+ }
+ }
+
+ if( m_char != '}' )
+ {
+ m_error = i18n( "Function statement not terminated" );
+#ifdef PMSCAN_DEBUG
+ kdDebug( PMArea ) << "Line " << m_line << ": Error " << m_error << "\n";
+#endif
+ m_token = SCANNER_ERROR_TOK;
+ }
+ else
+ m_token = FUNCTION_TOK;
+ }
+ else while( status != TOKEN_END_ST )
+ {
+ consumed = true;
+ if( m_char < 0 )
+ end = true;
+ switch( status )
+ {
+ case START_ST: //begin
+ if( m_char < 0 )
+ {
+ m_token = EOF_TOK;
+ addChar( 'E' );
+ addChar( 'O' );
+ addChar( 'F' );
+ status = TOKEN_END_ST;
+ consumed = false;
+ break;
+ }
+ if( m_char == '\n' )
+ {
+ m_line ++;
+ m_indentation = 0;
+ break;
+ }
+ if( m_char == ' ' )
+ {
+ m_indentation++;
+ break;
+ }
+ if( m_char == '\t' )
+ {
+ m_indentation += 8 - m_indentation % 8;
+ break;
+ }
+ if( iscntrl( m_char ) )
+ break;
+ if( isspace( m_char ) )
+ break;
+ if( isalpha( m_char ) || ( m_char == '_' ) )
+ {
+ status = ID_ENDST;
+ addChar( m_char );
+ break;
+ }
+ if( isdigit( m_char ) )
+ {
+ status = INTEGER_ENDST;
+ addChar( m_char );
+ break;
+ }
+ switch( m_char )
+ {
+ case '.':
+ status = POINT_ST;
+ addChar( m_char );
+ break;
+ case '#':
+ status = DIRECTIVE1_ST;
+ break;
+ case '"':
+ status = STRING1_ST;
+ break;
+ case '/':
+ status = SLASH_ST;
+ break;
+ default:
+ addChar( m_char );
+ m_token = m_char;
+ status = TOKEN_END_ST;
+
+#ifdef PMSCAN_DEBUG
+ kdDebug( PMArea ) << "Line " << m_line << ": Single char '"
+ << QString( QChar( ( char ) m_char ) ) << "'\n";
+#endif
+ break;
+ }
+ break;
+ case ID_ENDST: // indentifier or reserved word
+ if( isalnum( m_char ) || ( m_char == '_' ) )
+ {
+ addChar( m_char );
+ break;
+ }
+ else if( isseparation( m_char ) )
+ {
+ consumed = false;
+ m_token = m_reservedWords[ m_svalue ];
+ if( m_token < 0 )
+ m_token = ID_TOK;
+
+#ifdef PMSCAN_DEBUG
+ if( m_token == ID_TOK )
+ kdDebug( PMArea ) << "Line " << m_line << ": Indentifier: \""
+ << m_svalue << "\"\n";
+ else
+ kdDebug( PMArea ) << "Line " << m_line << ": Reserved word: \""
+ << m_svalue << "\"\n";
+#endif
+
+
+ status = TOKEN_END_ST;
+ }
+ else
+ {
+ status = TOKEN_END_ST;
+ scanError( m_char );
+ consumed = false;
+ }
+ break;
+ case INTEGER_ENDST:
+ if( isdigit ( m_char ) )
+ {
+ addChar( m_char );
+ break;
+ }
+ else if( m_char == '.' )
+ {
+ status = FLOAT1_ST;
+ addChar( m_char );
+ break;
+ }
+ else if( ( m_char == 'e' ) || ( m_char == 'E' ) )
+ {
+ status = FLOAT_EXP1_ST;
+ addChar( m_char );
+ break;
+ }
+ else if( isseparation( m_char ) )
+ {
+ consumed = false;
+ m_ivalue = atoi( m_svalue );
+#ifdef PMSCAN_DEBUG
+ kdDebug( PMArea ) << "Line " << m_line << ": Integer: "
+ << m_ivalue << "\n";
+#endif
+ m_token = INTEGER_TOK;
+ status = TOKEN_END_ST;
+ }
+ else
+ {
+ status = TOKEN_END_ST;
+ scanError( m_char );
+ consumed = false;
+ }
+ break;
+ case POINT_ST:
+ if( isdigit( m_char ) )
+ {
+ status = FLOAT_ENDST;
+ addChar( m_char );
+ }
+ else
+ {
+ status = TOKEN_END_ST;
+ consumed = false;
+ m_token = '.';
+ }
+ break;
+ case FLOAT1_ST:
+ if( isdigit( m_char ) )
+ {
+ status = FLOAT_ENDST;
+ addChar( m_char );
+ break;
+ }
+ else
+ {
+ scanError( m_char );
+ status = TOKEN_END_ST;
+ consumed = false;
+ }
+ break;
+ case FLOAT_ENDST:
+ if( isdigit ( m_char ) )
+ {
+ addChar( m_char );
+ break;
+ }
+ if( ( m_char == 'e' ) || ( m_char == 'E' ) )
+ {
+ status = FLOAT_EXP1_ST;
+ addChar( m_char );
+ break;
+ }
+ else if( isseparation( m_char ) )
+ {
+ consumed = false;
+ m_fvalue = atof( m_svalue );
+#ifdef PMSCAN_DEBUG
+ kdDebug( PMArea ) << "Line " << m_line << ": Float: "
+ << m_fvalue << "\n";
+#endif
+ m_token = FLOAT_TOK;
+ status = TOKEN_END_ST;
+ }
+ else
+ {
+ scanError( m_char );
+ status = TOKEN_END_ST;
+ consumed = false;
+ }
+ break;
+ case FLOAT_EXP1_ST:
+ if( ( m_char == '-' ) || ( m_char == '+' ) )
+ {
+ status = FLOAT_EXP2_ST;
+ addChar( m_char );
+ break;
+ }
+ if( isdigit( m_char ) )
+ {
+ status = FLOAT_EXP_ENDST;
+ addChar( m_char );
+ break;
+ }
+ else
+ {
+ scanError( m_char );
+ consumed = false;
+ status = TOKEN_END_ST;
+ }
+ break;
+ case FLOAT_EXP2_ST:
+ if( isdigit( m_char ) )
+ {
+ status = FLOAT_EXP_ENDST;
+ addChar( m_char );
+ break;
+ }
+ else
+ {
+ scanError( m_char );
+ consumed = false;
+ status = TOKEN_END_ST;
+ }
+ break;
+ case FLOAT_EXP_ENDST:
+ if( isdigit ( m_char ) )
+ {
+ addChar( m_char );
+ break;
+ }
+ else if( isseparation( m_char ) )
+ {
+ consumed = false;
+ m_fvalue = atof( m_svalue );
+#ifdef PMSCAN_DEBUG
+ kdDebug( PMArea ) << "Line " << m_line << ": Float: "
+ << m_fvalue << "\n";
+#endif
+ m_token = FLOAT_TOK;
+ status = TOKEN_END_ST;
+ }
+ else
+ {
+ scanError( m_char );
+ consumed = false;
+ status = TOKEN_END_ST;
+ }
+ break;
+ case DIRECTIVE1_ST:
+ if( m_char == ' ' )
+ {
+ // special treatment for povray inc files
+ // "# debug" directives
+ break;
+ }
+ else if( isalpha ( m_char ) )
+ {
+ status = DIRECTIVE_ENDST;
+ addChar( m_char );
+ break;
+ }
+ else
+ {
+ scanError( m_char );
+ consumed = false;
+ status = TOKEN_END_ST;
+ }
+ break;
+ case DIRECTIVE_ENDST:
+ if( isalpha( m_char ) )
+ {
+ addChar( m_char );
+ break;
+ }
+ else if( isseparation( m_char ) )
+ {
+ consumed = false;
+#ifdef PMSCAN_DEBUG
+ kdDebug( PMArea ) << "Line " << m_line << ": Directive: \""
+ << m_svalue << "\"\n";
+#endif
+ m_token = m_directives[ m_svalue ];
+ if( m_token < 0 )
+ {
+ m_error = i18n( "Unknown directive" );
+#ifdef PMSCAN_DEBUG
+ kdDebug( PMArea ) << "Line " << m_line << ": Error " << m_error << "\n";
+#endif
+
+ m_token = SCANNER_ERROR_TOK;
+ }
+ status = TOKEN_END_ST;
+ }
+ else
+ {
+ scanError( m_char );
+ consumed = false;
+ status = TOKEN_END_ST;
+ }
+ break;
+ case STRING1_ST:
+ switch( m_char )
+ {
+ case '\n':
+ case '\r':
+ consumed = false;
+ m_error = i18n( "String not terminated" );
+ m_token = SCANNER_ERROR_TOK;
+ status = TOKEN_END_ST;
+#ifdef PMSCAN_DEBUG
+ kdDebug( PMArea ) << "Line " << m_line << ": Error " << m_error << "\n";
+#endif
+ break;
+ case '"':
+#ifdef PMSCAN_DEBUG
+ kdDebug( PMArea ) << "Line " << m_line << ": String: \""
+ << m_svalue << "\"\n";
+#endif
+
+ m_token = STRING_TOK;
+ status = TOKEN_END_ST;
+ break;
+ case '\\':
+ status = STRINGBS_ST;
+ addChar( m_char );
+ break;
+ default:
+ addChar( m_char );
+ break;
+ }
+ break;
+ case STRINGBS_ST:
+ if( ( m_char == '\n' ) || ( m_char == '\r' ) || ( m_char < 0 ) )
+ {
+ consumed = false;
+ m_error = i18n( "String not terminated" );
+#ifdef PMSCAN_DEBUG
+ kdDebug( PMArea ) << "Line " << m_line << ": Error " << m_error << "\n";
+#endif
+ m_token = SCANNER_ERROR_TOK;
+ status = TOKEN_END_ST;
+ break;
+ }
+ else
+ {
+ status = STRING1_ST;
+ addChar( m_char );
+ break;
+ }
+ break;
+ case SLASH_ST:
+ switch( m_char )
+ {
+ case '/':
+ status = LINE_COMMENT_FIRST_ST;
+ break;
+ case '*':
+ status = COMMENT_NEW_LINE_ST;
+ cdepth ++;
+ break;
+ default:
+ consumed = false;
+ m_token = '/';
+ status = TOKEN_END_ST;
+ }
+ break;
+ case LINE_COMMENT_FIRST_ST:
+ // skip the first space char
+ if( ( m_char == '\n' ) || ( m_char == '\r' ) || ( m_char < 0 ) )
+ {
+#ifdef PMSCAN_DEBUG
+ kdDebug( PMArea ) << "Line " << m_line << ": Empty line comment\n";
+#endif
+ consumed = false;
+ m_token = LINE_COMMENT_TOK;
+ status = TOKEN_END_ST;
+ break;
+ }
+ else if( !isspace( m_char ) )
+ addChar( m_char );
+ status = LINE_COMMENT_ST;
+ break;
+ case LINE_COMMENT_ST:
+ if( ( m_char == '\n' ) || ( m_char == '\r' ) || ( m_char < 0 ) )
+ {
+#ifdef PMSCAN_DEBUG
+ kdDebug( PMArea ) << "Line " << m_line << ": Line comment: \""
+ << m_svalue << "\"\n";
+#endif
+ consumed = false;
+ m_token = LINE_COMMENT_TOK;
+ status = TOKEN_END_ST;
+ break;
+ }
+ else
+ {
+ addChar( m_char );
+ int l = m_lastChar - m_svalue;
+ if( l == c_commentNameLength )
+ {
+ if( strcmp( m_svalue, c_commentName ) == 0 )
+ {
+ status = PMNAME_ST;
+ clearSValue( );
+ }
+ }
+ if( l == c_commentRawBeginLength )
+ {
+ if( strcmp( m_svalue, c_commentRawBegin ) == 0 )
+ {
+ status = RAW_POVRAY_FIRST_ST;
+ clearSValue( );
+ }
+ }
+ break;
+ }
+ break;
+ case COMMENT_NEW_LINE_ST:
+ // skip any white spaces at begin of line.
+ if( m_char < 0 )
+ {
+ consumed = false;
+ m_error = i18n( "Comment not terminated" );
+#ifdef PMSCAN_DEBUG
+ kdDebug( PMArea ) << "Line " << m_line << ": Error " << m_error << "\n";
+#endif
+ m_token = SCANNER_ERROR_TOK;
+ status = TOKEN_END_ST;
+ }
+ else if( m_char == '\n' )
+ {
+ addChar( '\n' );
+ m_line ++;
+ }
+ else if( !isspace( m_char ) )
+ {
+ consumed = false;
+ status = C_COMMENT_ST;
+ }
+ break;
+ case C_COMMENT_ST:
+ if( m_char < 0 )
+ {
+ consumed = false;
+ m_error = i18n( "Comment not terminated" );
+#ifdef PMSCAN_DEBUG
+ kdDebug( PMArea ) << "Line " << m_line << ": Error " << m_error << "\n";
+#endif
+ m_token = SCANNER_ERROR_TOK;
+ status = TOKEN_END_ST;
+ }
+ else
+ {
+ switch( m_char )
+ {
+ case '*':
+ status = COMMENT_ST_ST;
+ break;
+ case '/':
+ status = COMMENT_SL_ST;
+ addChar( m_char );
+ break;
+ case '\n':
+ addChar( m_char );
+ m_line ++;
+ status = COMMENT_NEW_LINE_ST;
+ break;
+ default:
+ addChar( m_char );
+ }
+ }
+ break;
+ case COMMENT_ST_ST:
+ if( m_char < 0 )
+ {
+ consumed = false;
+ m_error = i18n( "Comment not terminated" );
+#ifdef PMSCAN_DEBUG
+ kdDebug( PMArea ) << "Line " << m_line << ": Error " << m_error << "\n";
+#endif
+ m_token = SCANNER_ERROR_TOK;
+ status = TOKEN_END_ST;
+ }
+ else
+ {
+ switch( m_char )
+ {
+ case '/':
+ cdepth --;
+ if( cdepth == 0 )
+ {
+#ifdef PMSCAN_DEBUG
+ kdDebug( PMArea ) << "Line " << m_line << ": Comment: \""
+ << m_svalue << "\"\n";
+#endif
+ m_token = COMMENT_TOK;
+ status = TOKEN_END_ST;
+ break;
+ }
+ else
+ {
+ status = C_COMMENT_ST;
+ addChar( '*' );
+ addChar( '/' );
+ break;
+ }
+ case '*':
+ addChar( m_char );
+ break;
+ case '\n':
+ status = C_COMMENT_ST;
+ addChar( '*' );
+ addChar( m_char );
+ m_line ++;
+ break;
+ default:
+ status = C_COMMENT_ST;
+ addChar( '*' );
+ addChar( m_char );
+ break;
+ }
+ }
+ break;
+ case COMMENT_SL_ST:
+ if( m_char < 0 )
+ {
+ consumed = false;
+ m_error = i18n( "Comment not terminated" );
+#ifdef PMSCAN_DEBUG
+ kdDebug( PMArea ) << "Line " << m_line << ": Error " << m_error << "\n";
+#endif
+ m_token = SCANNER_ERROR_TOK;
+ status = TOKEN_END_ST;
+ }
+ else
+ {
+ switch( m_char )
+ {
+ case '/':
+ addChar( m_char );
+ break;
+ case '*':
+ status = C_COMMENT_ST;
+ addChar( m_char );
+ cdepth ++;
+ break;
+ case '\n':
+ status = C_COMMENT_ST;
+ addChar( m_char );
+ m_line ++;
+ break;
+ default:
+ status = C_COMMENT_ST;
+ addChar( m_char );
+ }
+ }
+ break;
+ case PMNAME_ST:
+ if( ( m_char == '\n' ) || ( m_char == '\r' ) || ( m_char < 0 ) )
+ {
+#ifdef PMSCAN_DEBUG
+ kdDebug( PMArea ) << "Line " << m_line << ": PMName: \""
+ << m_svalue << "\"\n";
+#endif
+ consumed = false;
+ m_token = PMNAME_TOK;
+ status = TOKEN_END_ST;
+ break;
+ }
+ else
+ {
+ addChar( m_char );
+ break;
+ }
+ break;
+ case RAW_POVRAY_FIRST_ST: // skip the first line
+ if( m_char < 0 )
+ {
+ consumed = false;
+ m_error = i18n( "Raw povray not terminated" );
+#ifdef PMSCAN_DEBUG
+ kdDebug( PMArea ) << "Line " << m_line << ": Error " << m_error << "\n";
+#endif
+ m_token = SCANNER_ERROR_TOK;
+ status = TOKEN_END_ST;
+ }
+ if( m_char == '\n' )
+ {
+ m_line++;
+ m_rawIndentation = 0;
+ status = RAW_POVRAY_LB_ST;
+ }
+ break;
+ case RAW_POVRAY_LB_ST:
+ switch( m_char )
+ {
+ case '\n':
+ addChar( m_char );
+ m_line++;
+ m_rawIndentation = 0;
+ // status = RAW_POVRAY_LB_ST;
+ break;
+ case ' ':
+ m_rawIndentation++;
+ if( m_rawIndentation >= m_indentation )
+ status = RAW_POVRAY_ST;
+ break;
+ case '\t':
+ m_rawIndentation += 8 - m_rawIndentation % 8;
+ if( m_rawIndentation >= m_indentation )
+ status = RAW_POVRAY_ST;
+ break;
+ default:
+ consumed = false;
+ status = RAW_POVRAY_ST;
+ break;
+ }
+ break;
+ case RAW_POVRAY_ST:
+ if( m_char < 0 )
+ {
+ consumed = false;
+ m_error = i18n( "Raw povray not terminated" );
+#ifdef PMSCAN_DEBUG
+ kdDebug( PMArea ) << "Line " << m_line << ": Error " << m_error << "\n";
+#endif
+ m_token = SCANNER_ERROR_TOK;
+ status = TOKEN_END_ST;
+ }
+ else if( m_char == '\n' )
+ {
+ addChar( m_char );
+ m_line++;
+ m_rawIndentation = 0;
+ status = RAW_POVRAY_LB_ST;
+ }
+ else if( m_char == '/' )
+ {
+ m_rawPovrayEnd = 1;
+ status = RAW_POVRAY_END_ST;
+ }
+ else
+ addChar( m_char );
+ break;
+ case RAW_POVRAY_END_ST:
+ if( m_char < 0 )
+ {
+ consumed = false;
+ m_error = i18n( "Raw povray not terminated" );
+#ifdef PMSCAN_DEBUG
+ kdDebug( PMArea ) << "Line " << m_line << ": Error " << m_error << "\n";
+#endif
+ m_token = SCANNER_ERROR_TOK;
+ status = TOKEN_END_ST;
+ }
+ else if( m_char != c_commentRawEnd[m_rawPovrayEnd] )
+ {
+ status = RAW_POVRAY_ST;
+ int i;
+ for( i = 0; i < m_rawPovrayEnd; i++ )
+ addChar( c_commentRawEnd[i] );
+ consumed = false;
+ }
+ else
+ {
+ m_rawPovrayEnd++;
+ if( m_rawPovrayEnd >= c_commentRawEndLength )
+ {
+ status = RAW_POVRAY_END_END_ST;
+ if( m_lastChar > m_svalue )
+ {
+ if( *( m_lastChar - 1 ) == '\n' )
+ {
+ m_lastChar--;
+ *m_lastChar = 0;
+ }
+ }
+ }
+ }
+ break;
+ case RAW_POVRAY_END_END_ST:
+ if( ( m_char < 0 ) || ( m_char == '\n' ) )
+ {
+ consumed = false;
+ status = TOKEN_END_ST;
+ m_token = RAW_POVRAY_TOK;
+ }
+ break;
+ case TOKEN_END_ST:
+ break;
+ }
+ if( consumed )
+ nextChar( );
+ if( end && ( status != TOKEN_END_ST ) )
+ {
+ status = TOKEN_END_ST;
+ kdError( PMArea ) << "Error in scanner: No TOKEN_END_ST after EOF\n";
+ }
+ }
+
+ return m_token;
+}
+
+void PMScanner::scanFunction( )
+{
+ m_bFunctionMode = true;
+}
diff --git a/kpovmodeler/pmscanner.h b/kpovmodeler/pmscanner.h
new file mode 100644
index 00000000..6a3e8529
--- /dev/null
+++ b/kpovmodeler/pmscanner.h
@@ -0,0 +1,191 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMSCANNER_H
+#define PMSCANNER_H
+
+#include <qiodevice.h>
+#include <qstring.h>
+#include <qasciidict.h>
+
+/**
+ * Dictionary of reserved words for fast lookup
+ *
+ * The class @ref PMScanner has two static dictionaries: one for reserved
+ * words and one for directives. The constructor will insert the items.
+ */
+class PMReservedWordDict : protected QAsciiDict<int>
+{
+public:
+ /**
+ * Mode for constructor.
+ */
+ enum PMDictMode { PMDReservedWords, PMDDirectives };
+ /**
+ * Creates a dictionary for povray reserved words or directives.
+ */
+ PMReservedWordDict( PMDictMode mode );
+ /**
+ * Deletes the dictionary
+ */
+ ~PMReservedWordDict( );
+
+ /**
+ * Returns the token constant for the key if found, otherwise -1
+ */
+ int operator[] ( const char* key ) const { return find( key ); }
+ /**
+ * Returns the token constant for the key if found, otherwise -1
+ */
+ int find( const char* key ) const
+ {
+ int* result = QAsciiDict<int>::find( key );
+ if( result )
+ return *result;
+ return -1;
+ }
+};
+
+
+/**
+ * Scanner that scans povray tokens out of a QIODevice
+ */
+class PMScanner
+{
+public:
+ /**
+ * Creates a scanner that scans the QIODevice device
+ */
+ PMScanner( QIODevice* device );
+ /**
+ * Deletes the scanner
+ */
+ ~PMScanner( );
+
+ /**
+ * Scans the device for the next token. Returns a value of @ref PMToken
+ * ( > 0xFF ) or a single character
+ */
+ int nextToken( );
+ /**
+ * Returns the current token
+ */
+ int currentToken( ) const { return m_token; }
+
+ /**
+ * Returns the integer value of the current token if currentToken
+ * is INTEGER_TOK
+ */
+ int iValue( ) const { return m_ivalue; }
+ /**
+ * Returns the double value of the current token if currentToken
+ * is FLOAT_TOK
+ */
+ double fValue( ) const { return m_fvalue; }
+ /**
+ * Returns the string value of the current token if currentToken
+ * is ID_TOK, COMMENT_TOK, STRING_TOK
+ */
+ const char* sValue( ) const { return m_svalue; }
+ /**
+ * Returns the current line number
+ */
+ int currentLine( ) const { return m_line; }
+ /**
+ * Returns the error string if current token is SCANNER_ERROR_TOK
+ */
+ QString error( ) const { return m_error; }
+ /**
+ * Special parse method for a function statement
+ */
+ void scanFunction( );
+ /**
+ * Returns a pointer to a dictionary with reserved words
+ */
+ static PMReservedWordDict* reservedWords( ) { return &m_reservedWords; }
+ /**
+ * Returns a pointer to a dictionary with directives
+ */
+ static PMReservedWordDict* directives( ) { return &m_directives; }
+private:
+ /**
+ * returns true if c is one of the following characters:
+ * space, tab, newline, '{', '}', '<', '>', '+', '-', '*', '/', ',',
+ * '(', ')', '=', '[', ']', ';'
+ */
+ inline bool isseparation( int c );
+ /**
+ * Called on unexpected character
+ */
+ void scanError( int c );
+ /**
+ * Reads the next character out of the device
+ */
+ inline void nextChar( );
+ /**
+ * Adds the char to m_svalue
+ */
+ inline void addChar( char c );
+ /**
+ * Clears m_svalue
+ */
+ inline void clearSValue( );
+
+ static PMReservedWordDict m_reservedWords;
+ static PMReservedWordDict m_directives;
+
+ /**
+ * States for the state machine of the scanner
+ */
+ enum PMScanStates
+ {
+ START_ST = 0, ID_ENDST, INTEGER_ENDST,
+ FLOAT1_ST, FLOAT_ENDST, FLOAT_EXP1_ST, FLOAT_EXP2_ST, FLOAT_EXP_ENDST,
+ POINT_ST,
+ DIRECTIVE1_ST, DIRECTIVE_ENDST,
+ STRING1_ST, STRINGBS_ST,
+ SLASH_ST, LINE_COMMENT_FIRST_ST, LINE_COMMENT_ST,
+ C_COMMENT_ST, COMMENT_ST_ST, COMMENT_SL_ST, COMMENT_NEW_LINE_ST,
+ PMNAME_ST,
+ RAW_POVRAY_FIRST_ST, RAW_POVRAY_LB_ST, RAW_POVRAY_ST, RAW_POVRAY_END_ST,
+ RAW_POVRAY_END_END_ST,
+ TOKEN_END_ST
+ };
+
+ QIODevice* m_pDevice;
+
+ int m_char;
+ int m_token;
+ int m_ivalue;
+ double m_fvalue;
+ char* m_svalue;
+ char* m_lastChar;
+ char* m_lastAlloc;
+ unsigned int m_svalueAlloc;
+ int m_indentation;
+ int m_rawIndentation;
+ int m_rawPovrayEnd;
+ bool m_bFunctionMode;
+
+ int m_line;
+ QString m_error;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmscene.cpp b/kpovmodeler/pmscene.cpp
new file mode 100644
index 00000000..b8de8eef
--- /dev/null
+++ b/kpovmodeler/pmscene.cpp
@@ -0,0 +1,119 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmscene.h"
+#include <klocale.h>
+#include <qdom.h>
+#include "pmxmlhelper.h"
+#include "pmdocumentformat.h"
+
+const int c_defaultVisibilityLevel = 10;
+PMMetaObject* PMScene::s_pMetaObject = 0;
+PMObject* createNewScene( PMPart* part )
+{
+ return new PMScene( part );
+}
+
+PMScene::PMScene( PMPart* part )
+ : Base( part )
+{
+ m_visibilityLevel = c_defaultVisibilityLevel;
+}
+
+PMScene::PMScene( const PMScene& s )
+ : Base( s )
+{
+ m_visibilityLevel = s.m_visibilityLevel;
+}
+
+PMScene::~PMScene( )
+{
+ m_renderModes.setAutoDelete( true );
+ m_renderModes.clear( );
+}
+
+QString PMScene::description( ) const
+{
+ return i18n( "scene" );
+}
+
+PMMetaObject* PMScene::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Scene", Base::metaObject( ),
+ createNewScene );
+ }
+ return s_pMetaObject;
+}
+
+void PMScene::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMScene::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "majorFormat", c_majorDocumentFormat );
+ e.setAttribute( "minorFormat", c_minorDocumentFormat );
+ e.setAttribute( "visibility_level", m_visibilityLevel );
+ QDomElement data = doc.createElement( "extra_data" );
+ QDomElement rm;
+
+ PMRenderModeListIterator it( m_renderModes );
+ for( ; it.current( ); ++it )
+ {
+ rm = doc.createElement( "rendermode" );
+ it.current( )->serialize( rm );
+ data.appendChild( rm );
+ }
+
+ e.appendChild( data );
+ Base::serialize( e, doc );
+}
+
+void PMScene::readAttributes( const PMXMLHelper& h )
+{
+ m_visibilityLevel = h.intAttribute( "visibility_level", c_defaultVisibilityLevel );
+ QDomElement e = h.extraData( );
+ if( !e.isNull( ) )
+ {
+ QDomNode c = e.firstChild( );
+ while( !c.isNull( ) )
+ {
+ if( c.isElement( ) )
+ {
+ QDomElement ce = c.toElement( );
+ if( ce.tagName( ) == "rendermode" )
+ m_renderModes.append( new PMRenderMode( ce ) );
+ }
+ c = c.nextSibling( );
+ }
+ }
+
+ if( m_renderModes.count( ) > 0 )
+ m_renderModes.at( 0 );
+
+ Base::readAttributes( h );
+}
+
diff --git a/kpovmodeler/pmscene.h b/kpovmodeler/pmscene.h
new file mode 100644
index 00000000..2932c43c
--- /dev/null
+++ b/kpovmodeler/pmscene.h
@@ -0,0 +1,92 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMSCENE_H
+#define PMSCENE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmcompositeobject.h"
+#include "pmrendermode.h"
+
+/**
+ * Class for povray scenes.
+ *
+ * A document has a PMScene object as top level object. A PMScene can't have
+ * a parent
+ */
+class PMScene : public PMCompositeObject
+{
+ typedef PMCompositeObject Base;
+public:
+ /**
+ * Creates an empty PMScene
+ */
+ PMScene( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMScene( const PMScene& s );
+ /**
+ * deletes the scene and all objects
+ */
+ virtual ~PMScene( );
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMScene( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmscene" ); }
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a pointer to the list of render modes
+ * @see PMRenderMode
+ */
+ PMRenderModeList* renderModes( ) { return &m_renderModes; }
+ /**
+ * Returns the scenes visibility level
+ */
+ int visibilityLevel( ) const { return m_visibilityLevel; }
+ /**
+ * Sets the visibility level
+ */
+ void setVisibilityLevel( int l ) { m_visibilityLevel = l; }
+
+private:
+ PMRenderModeList m_renderModes;
+ int m_visibilityLevel;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmserializer.cpp b/kpovmodeler/pmserializer.cpp
new file mode 100644
index 00000000..087631cc
--- /dev/null
+++ b/kpovmodeler/pmserializer.cpp
@@ -0,0 +1,93 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmserializer.h"
+#include "pmerrorflags.h"
+#include "pmdebug.h"
+
+#include <klocale.h>
+
+unsigned int PMSerializer::s_maxErrors = 30;
+unsigned int PMSerializer::s_maxWarnings = 50;
+
+
+PMSerializer::PMSerializer( QIODevice* dev )
+{
+ m_pDev = dev;
+ m_errors = 0;
+ m_warnings = 0;
+ m_bFatalError = false;
+}
+
+PMSerializer::~PMSerializer( )
+{
+
+}
+
+void PMSerializer::serializeList( const PMObjectList& objects )
+{
+ PMObjectListIterator it( objects );
+ for( ; it.current( ); ++it )
+ serialize( it.current( ) );
+}
+
+int PMSerializer::errorFlags( ) const
+{
+ int result = 0;
+ if( errors( ) )
+ result |= PMEError;
+ if( warnings( ) )
+ result |= PMEWarning;
+ if( fatal( ) )
+ result |= PMEFatal;
+ return result;
+}
+
+void PMSerializer::printMessage( const QString& type, const QString& msg )
+{
+ m_messages += PMMessage( type + ": " + msg );
+}
+
+void PMSerializer::printError( const QString& msg )
+{
+ if( m_errors < s_maxErrors )
+ {
+ printMessage( i18n( "Error" ), msg );
+ m_errors++;
+ }
+ else if( m_errors == s_maxErrors )
+ {
+ m_messages += PMMessage( i18n( "Maximum of %1 errors reached." )
+ .arg( s_maxErrors ) );
+ m_errors++;
+ }
+}
+
+void PMSerializer::printWarning( const QString& msg )
+{
+ if( m_warnings < s_maxWarnings )
+ {
+ printMessage( i18n( "Warning" ), msg );
+ m_warnings++;
+ }
+ else if( m_warnings == s_maxWarnings )
+ {
+ m_messages += PMMessage( i18n( "Maximum of %1 warnings reached." )
+ .arg( s_maxWarnings ) );
+ m_warnings++;
+ }
+}
diff --git a/kpovmodeler/pmserializer.h b/kpovmodeler/pmserializer.h
new file mode 100644
index 00000000..73e509d8
--- /dev/null
+++ b/kpovmodeler/pmserializer.h
@@ -0,0 +1,179 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMSERIALIZER_H
+#define PMSERIALIZER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+class QIODevice;
+
+#include "pmobject.h"
+#include "pmerrordialog.h"
+
+#include <qdict.h>
+
+
+/**
+ * Class to serialize an object or a list of objects.
+ *
+ * Normally you don't have to create instances of this type or subclasses,
+ * the class @ref PMIOFormat has factory methods to create them.
+ *
+ * There is one sub class for each format.
+ *
+ * During serialization, errors can occur. These are returned
+ * by the method @ref errors.
+ */
+class PMSerializer
+{
+public:
+ /**
+ * Default constructor
+ *
+ * The serialized data will be written to the io device
+ */
+ PMSerializer( QIODevice* dev );
+ /**
+ * Destructor
+ */
+ virtual ~PMSerializer( );
+ /**
+ * Returns the translated description of the format. Should return
+ * the same string as description( ) of the corresponding
+ * IO format.
+ */
+ virtual QString description( ) const = 0;
+
+ /**
+ * Serializes one object to the device
+ */
+ virtual void serialize( PMObject* o ) = 0;
+ /**
+ * Serializes a list of objects. The default
+ * implementation will call serialize( PMObject* ) for each object.
+ */
+ virtual void serializeList( const PMObjectList& objects );
+ /**
+ * Closes the serializer
+ */
+ virtual void close( ) = 0;
+
+ /**
+ * Returns the messages of the serializer
+ */
+ PMMessageList messages( ) const { return m_messages; }
+ /**
+ * Returns true if there were errors during serializing
+ */
+ bool errors( ) const { return m_errors > 0; }
+ /**
+ * Returns true if there were warnings during serializing
+ */
+ bool warnings( ) const { return m_warnings > 0; }
+ /**
+ * Returns true, if a fatal error occurred
+ * and it doesn't make sense to continue
+ */
+ bool fatal( ) const { return m_bFatalError; }
+ /**
+ * Returns a bitwise combination of @ref PMErrorFlags constants
+ */
+ int errorFlags( ) const;
+
+ /**
+ * Adds an error to the message string
+ */
+ void printError( const QString& msg );
+ /**
+ * Adds a warning to the message string
+ */
+ void printWarning( const QString& msg );
+ /**
+ * Adds an info to the message string
+ */
+ void printInfo( const QString& msg );
+ /**
+ * Adds the message to the message string. Type is "error", "warning",
+ * "info"
+ */
+ void printMessage( const QString& type, const QString& msg );
+
+ /**
+ * Sets the fatal error flag
+ */
+ void setFatalError( ) { m_bFatalError = true; }
+
+ /**
+ * returns the maximum number of errors
+ */
+ static unsigned maxErrors( ) { return s_maxErrors; }
+ /**
+ * sets the maximum number of errors to m
+ */
+ static void setMaxErrors( unsigned m ) { s_maxErrors = m; }
+ /**
+ * returns the maximum number of warnings
+ */
+ static unsigned maxWarnings( ) { return s_maxWarnings; }
+ /**
+ * sets the maximum number of warnings to m
+ */
+ static void setMaxWarnings( unsigned m ) { s_maxWarnings = m; }
+
+protected:
+ /**
+ * The assigned IO device for serialization
+ */
+ QIODevice* m_pDev;
+
+private:
+ /**
+ * The serializer output (errors, warnings...)
+ */
+ PMMessageList m_messages;
+ /**
+ * A dictionary object -> message
+ */
+ QPtrDict< QPtrList<PMMessage> > m_messageDict;
+ /**
+ * Number of warnings during parsing
+ */
+ unsigned int m_warnings;
+ /**
+ * Number of errors during parsing
+ */
+ unsigned int m_errors;
+ /**
+ * Flag for fatal errors
+ */
+ bool m_bFatalError;
+
+ /**
+ * maximum number of errors
+ */
+ static unsigned int s_maxErrors;
+ /**
+ * maximum number of warnings
+ */
+ static unsigned int s_maxWarnings;
+};
+
+#endif
diff --git a/kpovmodeler/pmsettingsdialog.cpp b/kpovmodeler/pmsettingsdialog.cpp
new file mode 100644
index 00000000..898719bc
--- /dev/null
+++ b/kpovmodeler/pmsettingsdialog.cpp
@@ -0,0 +1,263 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@kde.org
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#include "pmsettingsdialog.h"
+
+#include "pmpovraysettings.h"
+#include "pmcolorsettings.h"
+#include "pmgridsettings.h"
+#include "pmobjectsettings.h"
+#include "pmpreviewsettings.h"
+#include "pmlayoutsettings.h"
+#include "pmobjectlibrarysettings.h"
+#include "pmpluginsettings.h"
+#include "pmopenglsettings.h"
+
+#include "pmrendermanager.h"
+#include "pmdebug.h"
+
+#include <qvbox.h>
+#include <qlistview.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kiconloader.h>
+
+//#define KPM_WITH_OBJECT_LIBRARY
+
+PMSettingsDialogPage::PMSettingsDialogPage( QWidget* parent, const char* name )
+ : QWidget( parent, name )
+{
+}
+
+QSize PMSettingsDialog::s_size = QSize( 640, 400 );
+
+PMSettingsDialog::PMSettingsDialog( PMPart* part, QWidget* parent, const char* name )
+ : KDialogBase( TreeList, i18n( "Configure" ), Ok | Apply | Cancel | Default, Ok,
+ parent, name )
+{
+ QStringList sl;
+ QWidget* w = 0;
+ PMSettingsDialogPage* p = 0;
+
+ m_pPart = part;
+
+ setShowIconsInTreeList( true );
+
+ sl.clear( );
+ sl.append( i18n( "Povray" ) );
+ w = addVBoxPage( sl, i18n( "Povray Options" ),
+ SmallIcon( "pmconfigurepovray", 22 ) );
+ p = new PMPovraySettings( w );
+ registerPage( w, p );
+
+ sl.clear( );
+ sl.append( i18n( "Graphical View" ) );
+ sl.append( i18n( "OpenGL" ) );
+ w = addVBoxPage( sl, i18n( "OpenGL Display Settings" ),
+ SmallIcon( "pmconfigureopengl", 22 ) );
+ p = new PMOpenGLSettings( w );
+ registerPage( w, p );
+
+ sl.clear( );
+ sl.append( i18n( "Graphical View" ) );
+ setFolderIcon( sl, SmallIcon( "pmconfiguregraphicalview", 22 ) );
+ sl.append( i18n( "Colors" ) );
+ w = addVBoxPage( sl, i18n( "Color Settings" ),
+ SmallIcon( "pmconfigurecolors", 22 ) );
+ p = new PMColorSettings( w );
+ registerPage( w, p );
+
+ sl.clear( );
+ sl.append( i18n( "Graphical View" ) );
+ sl.append( i18n( "Grid" ) );
+ w = addVBoxPage( sl, i18n( "Grid Settings" ),
+ SmallIcon( "pmconfiguregrid", 22 ) );
+ p = new PMGridSettings( w );
+ registerPage( w, p );
+
+ sl.clear( );
+ sl.append( i18n( "Graphical View" ) );
+ sl.append( i18n( "Objects" ) );
+ w = addVBoxPage( sl, i18n( "Display Settings for Objects" ),
+ SmallIcon( "pmconfigureobjects", 22 ) );
+ p = new PMObjectSettings( w );
+ registerPage( w, p );
+
+ sl.clear( );
+ sl.append( i18n( "Properties View" ) );
+ setFolderIcon( sl, SmallIcon( "pmconfiguredialogview", 22 ) );
+ sl.append( i18n( "Texture Preview" ) );
+ w = addVBoxPage( sl, i18n( "Display Settings for Texture Previews" ),
+ SmallIcon( "pmconfiguretexturepreview", 22 ) );
+ p = new PMPreviewSettings( w );
+ registerPage( w, p );
+
+ sl.clear( );
+ sl.append( i18n( "View Layout" ) );
+ w = addVBoxPage( sl, i18n( "Display Settings for View Layouts" ),
+ SmallIcon( "pmconfigureviewlayout", 22 ) );
+ p = new PMLayoutSettings( w );
+ registerPage( w, p );
+
+#ifdef KPM_WITH_OBJECT_LIBRARY
+ sl.clear( );
+ sl.append( i18n( "Object Libraries" ) );
+ w = addVBoxPage( sl, i18n( "Display Settings for Object Libraries" ),
+ SmallIcon( "pmconfigureobjectlibrary", 22 ) );
+ p = new PMObjectLibrarySettings( w );
+ registerPage( w, p );
+#endif
+
+#ifdef KPM_WITH_PLUGINS
+ sl.clear( );
+ sl.append( i18n( "Plugins" ) );
+ w = addVBoxPage( sl, i18n( "Plugin Settings" ) );
+ p = new PMPluginSettings( w );
+ registerPage( w, p );
+#endif
+
+ displaySettings( );
+
+ resize( s_size );
+}
+
+void PMSettingsDialog::displaySettings( )
+{
+ QValueList<PMRegisteredSettingsPage>::const_iterator it;
+ for( it = m_pages.begin( ); it != m_pages.end( ); ++it )
+ ( *it ).page->displaySettings( );
+}
+
+void PMSettingsDialog::slotCancel( )
+{
+ QDialog::reject( );
+}
+
+void PMSettingsDialog::slotApply( )
+{
+ if( validateData( ) )
+ saveSettings( );
+}
+
+void PMSettingsDialog::slotOk( )
+{
+ if( validateData( ) )
+ {
+ saveSettings( );
+ QDialog::accept( );
+ }
+}
+
+void PMSettingsDialog::slotDefault( )
+{
+ int currentPage = activePageIndex( );
+ PMSettingsDialogPage* page = 0;
+ QValueList<PMRegisteredSettingsPage>::const_iterator it;
+ for( it = m_pages.begin( ); it != m_pages.end( ) && !page; ++it )
+ if( ( *it ).index == currentPage )
+ page = ( *it ).page;
+ if( page )
+ page->displayDefaults( );
+}
+
+bool PMSettingsDialog::validateData( )
+{
+ bool valid = true;
+ QValueList<PMRegisteredSettingsPage>::const_iterator it;
+ for( it = m_pages.begin( ); it != m_pages.end( ) && valid; ++it )
+ valid = ( *it ).page->validateData( );
+ return valid;
+}
+
+void PMSettingsDialog::saveSettings( )
+{
+ m_repaint = false;
+
+ QValueList<PMRegisteredSettingsPage>::const_iterator it;
+ for( it = m_pages.begin( ); it != m_pages.end( ); ++it )
+ ( *it ).page->applySettings( );
+
+ if( m_repaint )
+ {
+ PMRenderManager* rm = PMRenderManager::theManager( );
+ rm->slotRenderingSettingsChanged( );
+ }
+}
+
+void PMSettingsDialog::saveConfig( KConfig* cfg )
+{
+ cfg->setGroup( "Appearance" );
+ cfg->writeEntry( "SettingsDialogSize", s_size );
+}
+
+void PMSettingsDialog::restoreConfig( KConfig* cfg )
+{
+ cfg->setGroup( "Appearance" );
+
+ QSize defaultSize( 640, 400 );
+ s_size = cfg->readSizeEntry( "SettingsDialogSize", &defaultSize );
+}
+
+void PMSettingsDialog::resizeEvent( QResizeEvent* ev )
+{
+ s_size = ev->size( );
+}
+
+void PMSettingsDialog::registerPage( QWidget* topPage,
+ PMSettingsDialogPage* page )
+{
+ int i = pageIndex( topPage );
+ if( i < 0 )
+ kdError( PMArea ) << "PMSettingsDialog: Registered settings page"
+ << " not found" << endl;
+ else
+ {
+ m_pages.push_back( PMRegisteredSettingsPage( topPage, page, i ) );
+ connect( page, SIGNAL( repaintViews( ) ), SLOT( slotRepaint( ) ) );
+ connect( page, SIGNAL( showMe( ) ), SLOT( slotShowPage( ) ) );
+ }
+}
+
+void PMSettingsDialog::slotRepaint( )
+{
+ m_repaint = true;
+}
+
+void PMSettingsDialog::slotShowPage( )
+{
+ const QObject* w = sender( );
+ if( w )
+ {
+ int index = findPage( ( const PMSettingsDialogPage* ) w );
+ if( index >= 0 )
+ showPage( index );
+ }
+}
+
+int PMSettingsDialog::findPage( const PMSettingsDialogPage* p )
+{
+ int index = -1;
+ QValueList<PMRegisteredSettingsPage>::const_iterator it;
+ for( it = m_pages.begin( ); it != m_pages.end( ) && index < 0; ++it )
+ if( ( *it ).page == p )
+ index = ( *it ).index;
+ return index;
+}
+
+#include "pmsettingsdialog.moc"
diff --git a/kpovmodeler/pmsettingsdialog.h b/kpovmodeler/pmsettingsdialog.h
new file mode 100644
index 00000000..09f00973
--- /dev/null
+++ b/kpovmodeler/pmsettingsdialog.h
@@ -0,0 +1,187 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMSETTINGSDIALOG_H
+#define PMSETTINGSDIALOG_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kdialogbase.h>
+#include <qvaluelist.h>
+#include <qvaluevector.h>
+
+class QFrame;
+class QCheckBox;
+class QLineEdit;
+class QListBox;
+class QListView;
+class QButtonGroup;
+class QComboBox;
+class KColorButton;
+class KConfig;
+class PMIntEdit;
+class PMFloatEdit;
+class PMPart;
+class PMViewLayout;
+class PMViewLayoutEntry;
+
+/**
+ * Base class for configuration dialog pages.
+ *
+ * All base classes have to implement the pure virtual
+ * methods @ref displaySettings, @ref displayDefaults, @ref validateData
+ * and @ref applySettings
+ */
+class PMSettingsDialogPage : public QWidget
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor
+ */
+ PMSettingsDialogPage( QWidget* parent, const char* name = 0 );
+ /**
+ * Display the settings here.
+ *
+ * Base classes have to implement this method.
+ */
+ virtual void displaySettings( ) = 0;
+ /**
+ * Validate the changed data here and return true
+ * if the data is valid. Display an error message
+ * and return false otherwise.
+ *
+ * Base classes have to implement this method.
+ */
+ virtual bool validateData( ) = 0;
+ /**
+ * Make the changes permanent here.
+ *
+ * Base classes have to implement this method.
+ */
+ virtual void applySettings( ) = 0;
+ /**
+ * Display the default values.
+ *
+ * Base classes have to implement this method.
+ */
+ virtual void displayDefaults( ) = 0;
+signals:
+ /**
+ * Emit this signal if a parameter was changed
+ * that influences the wire frame rendering.
+ */
+ void repaintViews( );
+ /**
+ * Tells the settings dialog to show this page.
+ */
+ void showMe( );
+};
+
+
+/**
+ * Helper class, used internally by @ref PMSettingsDialog
+ */
+class PMRegisteredSettingsPage
+{
+public:
+ PMRegisteredSettingsPage( )
+ {
+ topPage = 0;
+ page = 0;
+ index = 0;
+ }
+ PMRegisteredSettingsPage( QWidget* top, PMSettingsDialogPage* p,
+ int i )
+ {
+ topPage = top;
+ page = p;
+ index = i;
+ }
+ QWidget* topPage;
+ PMSettingsDialogPage* page;
+ int index;
+};
+
+/**
+ * Configuration dialog
+ */
+class PMSettingsDialog : public KDialogBase
+{
+ Q_OBJECT
+public:
+ /**
+ * Standard constructor
+ */
+ PMSettingsDialog( PMPart* part, QWidget* parent = 0, const char* name = 0 );
+ /**
+ * Registers a new settings page.
+ *
+ * @param topPage The page created with addVBoxPage
+ * @param page The internal settings page
+ */
+ void registerPage( QWidget* topPage, PMSettingsDialogPage* page );
+
+ static void saveConfig( KConfig* cfg );
+ static void restoreConfig( KConfig* cfg );
+
+protected:
+ virtual void resizeEvent( QResizeEvent* ev );
+
+protected slots:
+ /**
+ * Validates the data and makes the changes permanent.
+ */
+ virtual void slotApply( );
+ /**
+ * Validates the data, makes the changes permanent and closes the dialog.
+ */
+ virtual void slotOk( );
+ /**
+ * Displays the default values.
+ */
+ virtual void slotDefault( );
+ /**
+ * Closes the dialog without saving the data.
+ */
+ virtual void slotCancel( );
+
+ /**
+ * Repaints the opengl views
+ */
+ void slotRepaint( );
+ /**
+ * Shows the sender page
+ */
+ void slotShowPage( );
+
+private:
+ void displaySettings( );
+ bool validateData( );
+ void saveSettings( );
+ int findPage( const PMSettingsDialogPage* page );
+ bool m_repaint;
+ QValueList<PMRegisteredSettingsPage> m_pages;
+ PMPart* m_pPart;
+
+ static QSize s_size;
+};
+
+#endif
diff --git a/kpovmodeler/pmshell.cpp b/kpovmodeler/pmshell.cpp
new file mode 100644
index 00000000..52702492
--- /dev/null
+++ b/kpovmodeler/pmshell.cpp
@@ -0,0 +1,676 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include <klocale.h>
+#include <khelpmenu.h>
+#include <kstdaction.h>
+#include <kaction.h>
+#include <kstatusbar.h>
+#include <kfiledialog.h>
+#include <kmessagebox.h>
+#include <kiconloader.h>
+#include <kedittoolbar.h>
+#include <kkeydialog.h>
+#include <kaboutdialog.h>
+#include <kpopupmenu.h>
+#include <qtimer.h>
+
+#include "pmshell.h"
+#include "pmpart.h"
+#include "pmfactory.h"
+#include "pmsettingsdialog.h"
+#include "pmdefaults.h"
+#include "pmdockwidget.h"
+
+#include "pmviewfactory.h"
+#include "pmviewbase.h"
+#include "pmunknownview.h"
+#include "pmviewlayoutmanager.h"
+
+//#define KPM_WITH_OBJECT_LIBRARY
+
+const int c_statusBarInfo = 0;
+const int c_statusBarControlPoints = 1;
+
+PMShell::PMShell( const KURL& url )
+ : PMDockMainWindow( 0, "mainwindow" )
+{
+ setPluginLoadingMode( DoNotLoadPlugins );
+ setInstance( PMFactory::instance( ), false );
+
+ m_pPart = new PMPart( this, "part", this, "part", true, this );
+ m_pPart->setReadWrite( ); // read-write mode
+ m_viewNumber = 0;
+ m_objectsToDelete.setAutoDelete( true );
+
+ if (!initialGeometrySet())
+ resize(800,600);
+
+ setupActions( );
+
+ restoreOptions( );
+
+ setupView( );
+ setXMLFile( "kpovmodelershell.rc" );
+ createGUI( m_pPart );
+
+ //guiFactory( )->addClient( m_pPart );
+ m_pStatusBar = statusBar( );
+ m_pStatusBar->insertItem( " ", c_statusBarInfo, 1 );
+ m_pStatusBar->insertItem( "" , c_statusBarControlPoints );
+
+ KConfig* config = instance( )->config( );
+ config->setGroup( "Appearance" );
+ applyMainWindowSettings( config );
+
+ if( !url.isEmpty( ) )
+ openURL( url );
+
+ setCaption( url.prettyURL( ) );
+ connect( m_pPart, SIGNAL( modified( ) ), SLOT( slotModified( ) ) );
+ connect( m_pPart, SIGNAL( controlPointMessage( const QString& ) ),
+ SLOT( slotControlPointMsg( const QString& ) ) );
+}
+
+PMShell::~PMShell( )
+{
+}
+
+void PMShell::setupActions( )
+{
+// m_helpMenu = new KHelpMenu( this, PMFactory::aboutData( ), true,
+// actionCollection( ) );
+
+ KStdAction::openNew( this, SLOT( slotFileNew( ) ), actionCollection( ) );
+ KStdAction::open( this, SLOT( slotFileOpen( ) ), actionCollection( ) );
+ m_pRecent = KStdAction::openRecent( this, SLOT( slotOpenRecent( const KURL& ) ),
+ actionCollection( ) );
+ KStdAction::save( this, SLOT( slotFileSave( ) ), actionCollection( ) );
+ KStdAction::saveAs( this, SLOT( slotFileSaveAs( ) ), actionCollection( ) );
+
+ KStdAction::revert( this, SLOT( slotFileRevert( ) ), actionCollection( ) );
+ KStdAction::print( this, SLOT( slotFilePrint( ) ), actionCollection( ) );
+
+ KStdAction::close( this, SLOT( slotFileClose( ) ), actionCollection( ) );
+ KStdAction::quit( this, SLOT( close( ) ), actionCollection( ) );
+
+ m_pPathAction = new KToggleAction( i18n( "Show &Path" ), 0, this,
+ SLOT( slotShowPath( ) ), actionCollection( ),
+ "options_show_path" );
+ m_pPathAction->setCheckedState(i18n("Hide &Path"));
+
+ m_pStatusbarAction = KStdAction::showStatusbar( this, SLOT( slotShowStatusbar( ) ),
+ actionCollection( ) );
+
+ KStdAction::saveOptions( this, SLOT( saveOptions( ) ), actionCollection( ) );
+
+ KStdAction::keyBindings( this, SLOT( slotConfigureKeys( ) ),
+ actionCollection( ) );
+ KStdAction::configureToolbars( this, SLOT( slotConfigureToolbars( ) ),
+ actionCollection( ) );
+ KStdAction::preferences( this, SLOT( slotSettings( ) ), actionCollection( ) );
+
+ m_pNewTopViewAction = new KAction( i18n( "New Top View" ), 0, this,
+ SLOT( slotNewTopView( ) ),
+ actionCollection( ), "view_new_topview" );
+ m_pNewBottomViewAction = new KAction( i18n( "New Bottom View" ), 0, this,
+ SLOT( slotNewBottomView( ) ),
+ actionCollection( ), "view_new_bottomview" );
+ m_pNewLeftViewAction = new KAction( i18n( "New Left View" ), 0, this,
+ SLOT( slotNewLeftView( ) ),
+ actionCollection( ), "view_new_leftview" );
+ m_pNewRightViewAction = new KAction( i18n( "New Right View" ), 0, this,
+ SLOT( slotNewRightView( ) ),
+ actionCollection( ), "view_new_rightview" );
+ m_pNewFrontViewAction = new KAction( i18n( "New Front View" ), 0, this,
+ SLOT( slotNewFrontView( ) ),
+ actionCollection( ), "view_new_frontview" );
+ m_pNewBackViewAction = new KAction( i18n( "New Back View" ), 0, this,
+ SLOT( slotNewBackView( ) ),
+ actionCollection( ), "view_new_back_view" );
+ m_pNewCameraViewAction = new KAction( i18n( "New Camera View" ), 0, this,
+ SLOT( slotNewCameraView( ) ),
+ actionCollection( ), "view_new_cameraview" );
+
+ m_pNewTreeViewAction = new KAction( i18n( "New Object Tree" ), 0, this,
+ SLOT( slotNewTreeView( ) ), actionCollection( ),
+ "view_new_treeview" );
+ m_pNewDialogViewAction = new KAction( i18n( "New Properties View" ), 0, this,
+ SLOT( slotNewDialogView( ) ), actionCollection( ),
+ "view_new_dialogview" );
+
+#ifdef KPM_WITH_OBJECT_LIBRARY
+ m_pNewLibraryBrowserAction = new KAction( i18n( "New Library Browser" ), 0, this,
+ SLOT( slotNewLibraryBrowserView( ) ), actionCollection( ),
+ "view_new_librarybrowser" );
+#endif
+
+ // Creating the view layouts menu
+ m_pViewLayoutsAction = new KActionMenu( i18n( "View Layouts" ),
+ actionCollection( ), "view_layouts_menu" );
+ KPopupMenu* menu = m_pViewLayoutsAction->popupMenu( );
+ connect( menu, SIGNAL( aboutToShow( ) ), SLOT( slotViewsMenuAboutToShow( ) ) );
+ PMViewLayoutManager::theManager( )->fillPopupMenu( menu );
+ connect( menu, SIGNAL( activated( int ) ), SLOT( slotSelectedLayout( int ) ) );
+
+ m_pSaveViewLayoutAction = new KAction( i18n( "Save View Layout..." ), 0, this,
+ SLOT( slotSaveViewLayout( ) ),
+ actionCollection( ), "save_view_layout" );
+}
+
+void PMShell::setupView( )
+{
+ PMViewLayoutManager::theManager( )->displayDefaultLayout( this );
+}
+
+
+PMDockWidget* PMShell::createView( const QString& t, PMViewOptions* o,
+ bool initPosition )
+{
+ PMDockWidget* dock = 0;
+ PMViewBase* contents = 0;
+
+ PMViewTypeFactory* factory =
+ PMViewFactory::theFactory( )->viewFactory( t );
+
+ m_viewNumber++;
+ QString name = QString( "View (%1)" ).arg( m_viewNumber );
+
+ if( factory )
+ {
+ QString desc;
+ // Create the appropriate dock widget
+ if( o )
+ desc = factory->description( o );
+ else
+ desc = factory->description( );
+
+ dock = createDockWidget( name, SmallIcon( factory->iconName( ) ), 0L,
+ desc, desc );
+ contents = factory->newInstance( dock, m_pPart );
+ if( o )
+ contents->restoreViewConfig( o );
+ }
+ else
+ {
+ // unknown view type
+ dock = createDockWidget( name, SmallIcon( "unknown" ), 0L,
+ i18n( "Unknown" ), i18n( "Unknown" ) );
+ contents = new PMUnknownView( t, dock );
+ }
+
+ dock->setWidget( contents );
+ connect( dock, SIGNAL( headerCloseButtonClicked( ) ),
+ SLOT( slotDockWidgetClosed( ) ) );
+
+ if( initPosition )
+ {
+ dock->resize( 300, 400 );
+ dock->manualDock( 0, PMDockWidget::DockDesktop, 50,
+ mapToGlobal( QPoint( 50, 50 ) ) );
+ }
+ return dock;
+}
+
+/*
+PMDockWidget* PMShell::createTreeView( )
+{
+ PMDockWidget* dock = 0;
+ m_numTreeViews++;
+ QString name = QString( "Object Tree (%1)" ).arg( m_numTreeViews );
+ dock = createDockWidget( name, SmallIcon( "pmtreeview" ),
+ 0L, i18n( "Object Tree" ), i18n( "Object Tree" ) );
+ dock->setDockSite( PMDockWidget::DockFullSite );
+ PMTreeView* tv = new PMTreeView( m_pPart, dock );
+ dock->setWidget( tv );
+
+ connect( dock, SIGNAL( headerCloseButtonClicked( ) ),
+ SLOT( slotDockWidgetClosed( ) ) );
+
+ return dock;
+}
+
+PMDockWidget* PMShell::createDialogView( )
+{
+ PMDockWidget* dock = 0;
+ m_numDialogViews++;
+ QString name = QString( "Object Properties (%1)" ).arg( m_numDialogViews );
+ dock = createDockWidget( name, SmallIcon( "pmdialogview" ),
+ 0L, i18n( "Object Properties" ), i18n( "Object Properties" ) );
+ dock->setDockSite( PMDockWidget::DockFullSite );
+ PMDialogView* dv = new PMDialogView( m_pPart, dock );
+ dock->setWidget( dv );
+
+ connect( dock, SIGNAL( headerCloseButtonClicked( ) ),
+ SLOT( slotDockWidgetClosed( ) ) );
+
+ return dock;
+}
+
+PMDockWidget* PMShell::create3DView( PMGLView::PMViewType t )
+{
+ PMDockWidget* dock = 0;
+ m_numGLViews++;
+ QString name = QString( "3D View (%1)" ).arg( m_numGLViews );
+ dock = createDockWidget( name, SmallIcon( "pmglview" ),
+ 0L, i18n( "3D View" ), i18n( "3D View" ) );
+ dock->setDockSite( PMDockWidget::DockFullSite );
+ PMGLView* vgl = new PMGLView( m_pPart, t, dock );
+ dock->setWidget( vgl );
+ connect( vgl, SIGNAL( viewTypeChanged( const QString& ) ),
+ dock, SLOT( slotSetCaption( const QString& ) ) );
+ dock->slotSetCaption( PMGLView::viewTypeAsString( t ) );
+
+ connect( dock, SIGNAL( headerCloseButtonClicked( ) ),
+ SLOT( slotDockWidgetClosed( ) ) );
+
+ return dock;
+}
+*/
+
+void PMShell::slotNewGraphicalView( PMGLView::PMViewType t )
+{
+ PMGLViewOptions* o = new PMGLViewOptions( t );
+ createView( "glview", o );
+ delete o;
+}
+
+void PMShell::slotNewTopView( )
+{
+ slotNewGraphicalView( PMGLView::PMViewNegY );
+}
+
+void PMShell::slotNewBottomView( )
+{
+ slotNewGraphicalView( PMGLView::PMViewPosY );
+}
+
+void PMShell::slotNewLeftView( )
+{
+ slotNewGraphicalView( PMGLView::PMViewPosX );
+}
+
+void PMShell::slotNewRightView( )
+{
+ slotNewGraphicalView( PMGLView::PMViewNegX );
+}
+
+void PMShell::slotNewFrontView( )
+{
+ slotNewGraphicalView( PMGLView::PMViewPosZ );
+}
+
+void PMShell::slotNewBackView( )
+{
+ slotNewGraphicalView( PMGLView::PMViewNegZ );
+}
+
+void PMShell::slotNewCameraView( )
+{
+ slotNewGraphicalView( PMGLView::PMViewCamera );
+}
+
+void PMShell::slotNewDialogView( )
+{
+ createView( "dialogview" );
+}
+
+void PMShell::slotNewTreeView( )
+{
+ createView( "treeview" );
+}
+
+void PMShell::slotNewLibraryBrowserView( )
+{
+ createView( "librarybrowserview" );
+}
+
+void PMShell::slotDockWidgetClosed( )
+{
+ const QObject* o = sender( );
+ if( o && o->inherits( "PMDockWidget" ) )
+ {
+ if( m_objectsToDelete.containsRef( o ) == 0 )
+ {
+ m_objectsToDelete.append( o );
+ QTimer::singleShot( 0, this, SLOT( slotDeleteClosedObjects( ) ) );
+ }
+ }
+}
+
+void PMShell::slotDeleteClosedObjects( )
+{
+ m_objectsToDelete.clear( );
+}
+
+void PMShell::openURL( const KURL& url )
+{
+ m_pRecent->addURL( url );
+
+ if( !m_pPart->isModified( ) && m_pPart->url( ).isEmpty( ) )
+ {
+ m_pPart->openURL( url );
+ setCaption( m_pPart->url( ).prettyURL( ) );
+ }
+ else
+ {
+ PMShell *shell = new PMShell( );
+ shell->show( );
+ shell->openURL( url );
+ }
+}
+
+void PMShell::slotOpenRecent( const KURL& url )
+{
+ m_openRecentURL = url;
+ QTimer::singleShot( 0, this, SLOT( slotOpenRecentTimer( ) ) );
+}
+
+void PMShell::slotOpenRecentTimer( )
+{
+ openURL( m_openRecentURL );
+}
+
+void PMShell::slotFileNew( )
+{
+ if( !m_pPart->isModified( ) && m_pPart->url( ).isEmpty( ) )
+ {
+ m_pPart->newDocument( );
+ setCaption( );
+ }
+ else
+ {
+ PMShell *shell = new PMShell( );
+ shell->show( );
+ }
+}
+
+void PMShell::slotFileOpen( )
+{
+ KURL url = KFileDialog::getOpenURL(
+ QString::null, QString( "*.kpm|" ) + i18n( "Povray Modeler Files (*.kpm)" )
+ + "\n*|" + i18n( "All Files" ) );
+
+ if( !url.isEmpty( ) )
+ openURL( url );
+}
+
+void PMShell::slotFileSave( )
+{
+ m_pPart->slotAboutToSave( );
+
+ if( m_pPart->isModified( ) )
+ {
+ if( !m_pPart->url( ).isEmpty( ) &&
+ m_pPart->isReadWrite( ) )
+ m_pPart->saveAs( m_pPart->url( ) );
+ else
+ saveAs( );
+ setCaption( m_pPart->url( ).prettyURL( ) );
+ }
+ else
+ emit statusMsg( i18n( "No changes need to be saved" ) );
+}
+
+void PMShell::slotFileSaveAs( )
+{
+ m_pPart->slotAboutToSave( );
+ saveAs( );
+}
+
+void PMShell::saveAs( )
+{
+ KFileDialog dlg( QString::null,
+ QString( "*.kpm|" ) + i18n( "Povray Modeler Files (*.kpm)" ) +
+ QString( "\n*|" ) + i18n( "All Files" ),
+ 0, "filedialog", true );
+ dlg.setCaption( i18n( "Save As" ) );
+ dlg.setOperationMode( KFileDialog::Saving );
+ dlg.exec( );
+
+ KURL url = dlg.selectedURL( );
+
+ if( !url.isEmpty( ) )
+ {
+ if( dlg.currentFilter( ) == QString( "*.kpm" ) )
+ if( QFileInfo( url.path( ) ).extension( ).isEmpty( ) )
+ url.setPath( url.path( ) + ".kpm" );
+
+ if( overwriteURL( url ) )
+ {
+ m_pRecent->addURL( url );
+ if( m_pPart->saveAs( url ) )
+ setCaption( url.prettyURL( ) );
+ else
+ KMessageBox::sorry( this, i18n( "Couldn't save the file." ) );
+ }
+ }
+}
+
+void PMShell::slotFileRevert( )
+{
+ KURL url = m_pPart->url( );
+
+ if( !url.isEmpty( ) )
+ m_pPart->openURL( url );
+// else
+// slotFileNew( );
+}
+
+void PMShell::slotFilePrint( )
+{
+ //TODO
+ // m_pPart->slotPrint( );
+}
+
+void PMShell::slotFileNewWindow( )
+{
+ PMShell* shell = new PMShell;
+ shell->show( );
+}
+
+void PMShell::slotFileClose( )
+{
+ if( m_pPart->closeURL( ) )
+ {
+ m_pPart->closeDocument( );
+ m_pPart->newDocument( );
+ setCaption( );
+ }
+}
+
+void PMShell::slotShowToolbar( )
+{
+ if( toolBar( )->isVisible ( ) )
+ toolBar( )->hide( );
+ else
+ toolBar( )->show( );
+}
+
+void PMShell::slotShowStatusbar( )
+{
+ if( statusBar( )->isVisible ( ) )
+ statusBar( )->hide( );
+ else
+ statusBar( )->show( );
+}
+
+void PMShell::slotShowPath( )
+{
+ setCaption( m_pPart->url( ).prettyURL( ) );
+}
+
+void PMShell::slotConfigureKeys( )
+{
+ KKeyDialog kd;
+ kd.insert( m_pPart->actionCollection( ) );
+ kd.insert( actionCollection( ) );
+ kd.configure( true );
+ //KKeyDialog::configure( actionCollection( ) );
+}
+
+void PMShell::slotSettings( )
+{
+ PMSettingsDialog dlg( m_pPart );
+ dlg.exec( );
+}
+
+void PMShell::slotConfigureToolbars( )
+{
+ saveMainWindowSettings( KGlobal::config( ), "Appearance" );
+ KEditToolbar dlg( factory( ) );
+ connect( &dlg, SIGNAL( newToolbarConfig( ) ),
+ this, SLOT( slotNewToolbarConfig( ) ) );
+ dlg.exec( );
+}
+
+void PMShell::slotNewToolbarConfig( )
+{
+ createGUI( 0 );
+ createShellGUI( false );
+ createGUI( m_pPart );
+ applyMainWindowSettings( KGlobal::config( ), "Appearance" );
+}
+
+void PMShell::updateGUI( )
+{
+ saveMainWindowSettings( KGlobal::config( ), "Appearance" );
+ createGUI( 0 );
+ createShellGUI( false );
+ createGUI( m_pPart );
+ applyMainWindowSettings( KGlobal::config( ), "Appearance" );
+}
+
+void PMShell::saveOptions( )
+{
+ kdDebug( PMArea ) << "Saving configuration" << endl;
+ KConfig* config = KGlobal::config( );
+
+ // set group
+ config->setGroup( "Appearance" );
+ config->writeEntry( "ShowStatusbar", m_pStatusbarAction->isChecked( ) );
+ saveMainWindowSettings( config );
+ m_pRecent->saveEntries( config );
+
+ if( m_pPart )
+ m_pPart->saveConfig( config );
+
+ config->sync( );
+}
+
+void PMShell::restoreOptions( )
+{
+ KConfig* config = instance( )->config( );
+
+ // set group
+ config->setGroup( "Appearance" );
+
+ bool showStatusbar = config->readBoolEntry( "ShowStatusbar", true );
+
+ m_pStatusbarAction->blockSignals( true );
+ m_pStatusbarAction->setChecked( showStatusbar );
+ m_pStatusbarAction->blockSignals( false );
+
+ if( showStatusbar )
+ statusBar( )->show( );
+ else
+ statusBar( )->hide( );
+
+ m_pRecent->loadEntries( config );
+}
+
+void PMShell::setCaption( const QString& caption )
+{
+ QString tmp;
+
+ if( caption.isEmpty( ) )
+ tmp = i18n( "unknown" );
+ else
+ {
+ if( !m_pPathAction->isChecked( ) )
+ tmp = caption.right( caption.length( ) - caption.findRev( '/' ) - 1 );
+ else
+ tmp = caption;
+ }
+
+ KMainWindow::setCaption( tmp, m_pPart->isModified( ) );
+}
+
+void PMShell::statusMsg( const QString& text )
+{
+ m_pStatusBar->message( text, 5000 );
+}
+
+bool PMShell::queryClose( )
+{
+ saveOptions( );
+ return m_pPart->closeURL( );
+}
+
+void PMShell::showEvent( QShowEvent* ){
+ activateDock( );
+}
+
+void PMShell::slotModified( )
+{
+ setCaption( m_pPart->url( ).prettyURL( ) );
+}
+
+void PMShell::slotControlPointMsg( const QString& msg )
+{
+ if( msg.isEmpty( ) )
+ m_pStatusBar->changeItem( msg, c_statusBarControlPoints );
+ else
+ m_pStatusBar->changeItem( QString( " " ) + msg + QString( " " ),
+ c_statusBarControlPoints );
+}
+
+bool PMShell::overwriteURL( const KURL& u )
+{
+ int query = KMessageBox::Continue;
+
+ if( u.isLocalFile( ) )
+ {
+ QFileInfo info;
+ QString name( u.path( ) );
+ info.setFile( name );
+ if( info.exists( ) )
+ query = KMessageBox::warningContinueCancel( 0, i18n( "A file with this name already exists.\nDo you want to overwrite it?" ), QString::null, i18n("Overwrite") );
+ }
+ return ( query == KMessageBox::Continue );
+}
+
+void PMShell::slotSelectedLayout( int id )
+{
+ QMenuItem* menu = m_pViewLayoutsAction->popupMenu( )->findItem( id );
+ PMViewLayoutManager::theManager( )->displayLayout( menu->text( ), this );
+}
+
+void PMShell::slotSaveViewLayout( )
+{
+ PMSaveViewLayoutDialog dlg( this );
+ dlg.exec( );
+}
+
+void PMShell::slotViewsMenuAboutToShow( )
+{
+ KPopupMenu* menu = m_pViewLayoutsAction->popupMenu( );
+
+ PMViewLayoutManager::theManager( )->fillPopupMenu( menu );
+}
+
+#include "pmshell.moc"
diff --git a/kpovmodeler/pmshell.h b/kpovmodeler/pmshell.h
new file mode 100644
index 00000000..9a0dbb91
--- /dev/null
+++ b/kpovmodeler/pmshell.h
@@ -0,0 +1,172 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMSHELL_H
+#define PMSHELL_H
+
+#include "pmdockwidget.h"
+
+#include "pmpart.h"
+#include "pmglview.h"
+#include "version.h"
+
+#include <qptrlist.h>
+
+//class KHelpMenu;
+class KStatusBar;
+class KListAction;
+class KToggleAction;
+class KSelectAction;
+class KRecentFilesAction;
+class KActionMenu;
+class PMViewOptions;
+
+/**
+ * Main view for KPovModeler
+ */
+class PMShell : public PMDockMainWindow
+{
+ Q_OBJECT
+
+public:
+ /**
+ * Standard constructor
+ */
+ PMShell( const KURL& = KURL( ) );
+ /**
+ * Destructor
+ */
+ virtual ~PMShell( );
+
+ /**
+ * Creates the actions
+ */
+ void setupActions( );
+ /**
+ * Creates the docking views
+ */
+ void setupView( );
+ /**
+ * Updates the gui (menus and toolbars)
+ */
+ void updateGUI( );
+
+ /**
+ * Checks if a file with that name exists and asks if
+ * it should be overwritten.
+ *
+ * Returns true if the files is not a local file, the file does'n exist
+ * or the file should be overwritten.
+ */
+ static bool overwriteURL( const KURL& u );
+
+public slots:
+ void openURL( const KURL& );
+ void slotOpenRecent( const KURL& );
+ void slotOpenRecentTimer( );
+
+ void slotFileNew( );
+ void slotFileOpen( );
+ void slotFileSave( );
+ void slotFileSaveAs( );
+ void slotFileRevert( );
+ void slotFilePrint( );
+ void slotFileNewWindow( );
+ void slotFileClose( );
+
+ void slotShowToolbar( );
+ void slotShowStatusbar( );
+ void slotShowPath( );
+ void slotConfigureKeys( );
+ void slotConfigureToolbars( );
+ void slotSettings( );
+ void slotNewToolbarConfig( );
+
+ void slotNewGraphicalView( PMGLView::PMViewType );
+ void slotNewTopView( );
+ void slotNewBottomView( );
+ void slotNewLeftView( );
+ void slotNewRightView( );
+ void slotNewFrontView( );
+ void slotNewBackView( );
+ void slotNewCameraView( );
+ void slotNewTreeView( );
+ void slotNewDialogView( );
+ void slotNewLibraryBrowserView( );
+
+ void saveOptions( );
+ void restoreOptions( );
+
+ void setCaption( const QString& caption = QString::null );
+ void statusMsg( const QString& text = QString::null );
+ void slotControlPointMsg( const QString& msg = QString::null );
+
+ void slotModified( );
+ void slotDockWidgetClosed( );
+ void slotDeleteClosedObjects( );
+ void slotSelectedLayout( int id );
+ void slotSaveViewLayout( );
+ void slotViewsMenuAboutToShow( );
+
+protected:
+ virtual bool queryClose( );
+ virtual void showEvent( QShowEvent* );
+ void saveAs( );
+
+public:
+ /**
+ * Creates a dock widget of view type t with custom config c.
+ *
+ * If initPosition is true, the widget is docked to the desktop.
+ */
+ PMDockWidget* createView( const QString& t, PMViewOptions* c = 0,
+ bool initPosition = true );
+ //PMDockWidget* createTreeView( );
+ //PMDockWidget* createDialogView( );
+ //PMDockWidget* create3DView( PMGLView::PMViewType );
+
+private:
+ KRecentFilesAction* m_pRecent;
+ KToggleAction* m_pToolbarAction;
+ KToggleAction* m_pStatusbarAction;
+ KToggleAction* m_pPathAction;
+
+ KAction* m_pNewTreeViewAction;
+ KAction* m_pNewDialogViewAction;
+ KAction* m_pNewTopViewAction;
+ KAction* m_pNewBottomViewAction;
+ KAction* m_pNewLeftViewAction;
+ KAction* m_pNewRightViewAction;
+ KAction* m_pNewFrontViewAction;
+ KAction* m_pNewBackViewAction;
+ KAction* m_pNewCameraViewAction;
+ KAction* m_pNewLibraryBrowserAction;
+
+ KActionMenu* m_pViewLayoutsAction;
+ KAction* m_pSaveViewLayoutAction;
+
+ KStatusBar* m_pStatusBar;
+ PMPart* m_pPart;
+ KURL m_openRecentURL;
+
+ QPtrList<QObject> m_objectsToDelete;
+ int m_viewNumber;
+};
+
+#endif
diff --git a/kpovmodeler/pmskysphere.cpp b/kpovmodeler/pmskysphere.cpp
new file mode 100644
index 00000000..735c851b
--- /dev/null
+++ b/kpovmodeler/pmskysphere.cpp
@@ -0,0 +1,76 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmskysphere.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pmskysphereedit.h"
+#include "pmdebug.h"
+
+#include <klocale.h>
+
+PMMetaObject* PMSkySphere::s_pMetaObject = 0;
+PMObject* createNewSkySphere( PMPart* part )
+{
+ return new PMSkySphere( part );
+}
+
+PMSkySphere::PMSkySphere( PMPart* part )
+ : Base( part )
+{
+}
+
+PMSkySphere::PMSkySphere( const PMSkySphere& s )
+ : Base( s )
+{
+}
+
+PMSkySphere::~PMSkySphere( )
+{
+}
+
+PMMetaObject* PMSkySphere::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "SkySphere", Base::metaObject( ),
+ createNewSkySphere );
+ }
+ return s_pMetaObject;
+}
+
+void PMSkySphere::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMSkySphere::description( ) const
+{
+ return i18n( "skysphere" );
+}
+
+PMDialogEditBase* PMSkySphere::editWidget( QWidget* parent ) const
+{
+ return new PMSkySphereEdit( parent );
+}
+
diff --git a/kpovmodeler/pmskysphere.h b/kpovmodeler/pmskysphere.h
new file mode 100644
index 00000000..f3799b75
--- /dev/null
+++ b/kpovmodeler/pmskysphere.h
@@ -0,0 +1,75 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001-2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMSKYSPHERE_H
+#define PMSKYSPHERE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebase.h"
+
+/**
+ * Class for povray skyspheres
+ */
+class PMSkySphere : public PMTextureBase
+{
+ typedef PMTextureBase Base;
+public:
+ /**
+ * Creates an PMSkySphere
+ */
+ PMSkySphere( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMSkySphere( const PMSkySphere& s );
+ /**
+ * Deletes the object
+ */
+ virtual ~PMSkySphere( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMSkySphere( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /**
+ * Returns a new @ref PMSkySphereEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmskysphere" ); }
+
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+// enum PMSkySphereMementoID { };
+ static PMMetaObject* s_pMetaObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmskysphereedit.cpp b/kpovmodeler/pmskysphereedit.cpp
new file mode 100644
index 00000000..0dc05580
--- /dev/null
+++ b/kpovmodeler/pmskysphereedit.cpp
@@ -0,0 +1,44 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmskysphereedit.h"
+#include "pmskysphere.h"
+#include "pmlinkedit.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <klocale.h>
+
+
+PMSkySphereEdit::PMSkySphereEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMSkySphereEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "SkySphere" ) )
+ {
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMSkySphereEdit: Can't display object\n";
+}
+
+#include "pmskysphereedit.moc"
diff --git a/kpovmodeler/pmskysphereedit.h b/kpovmodeler/pmskysphereedit.h
new file mode 100644
index 00000000..10ef2567
--- /dev/null
+++ b/kpovmodeler/pmskysphereedit.h
@@ -0,0 +1,58 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMSKYSPHEREEDIT_H
+#define PMSKYSPHEREEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebaseedit.h"
+
+class PMSkySphere;
+
+/**
+ * Dialog edit class for @ref PMSkySphere
+ */
+class PMSkySphereEdit : public PMTextureBaseEdit
+{
+ Q_OBJECT
+ typedef PMTextureBaseEdit Base;
+public:
+ /**
+ * Creates a PMSkySphereEdit with parent and name
+ */
+ PMSkySphereEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+protected:
+ /** */
+// virtual void createTopWidgets( );
+ /** */
+// virtual void saveContents( );
+
+private:
+ PMSkySphere* m_pDisplayedObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmslope.cpp b/kpovmodeler/pmslope.cpp
new file mode 100644
index 00000000..aa652be9
--- /dev/null
+++ b/kpovmodeler/pmslope.cpp
@@ -0,0 +1,146 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#include "pmxmlhelper.h"
+#include "pmvector.h"
+#include "pmslope.h"
+#include "pmslopeedit.h"
+#include "pmmemento.h"
+
+#include <klocale.h>
+
+const double heightDefault = 0;
+const double slopeDefault = 0;
+
+PMDefinePropertyClass( PMSlope, PMSlopeProperty );
+
+PMMetaObject* PMSlope::s_pMetaObject = 0;
+PMObject* createNewSlope( PMPart* part )
+{
+ return new PMSlope( part );
+}
+
+PMSlope::PMSlope( PMPart* part )
+ : Base( part )
+{
+ m_height = heightDefault;
+ m_slope = slopeDefault;
+}
+
+PMSlope::PMSlope( const PMSlope& s )
+ : Base( s )
+{
+ m_height = s.m_height;
+ m_slope = s.m_slope;
+}
+
+PMSlope::~PMSlope( )
+{
+}
+
+QString PMSlope::description( ) const
+{
+ return i18n( "slope" );
+}
+
+void PMSlope::serialize( QDomElement& e, QDomDocument& /*doc*/ ) const
+{
+ e.setAttribute( "height", m_height );
+ e.setAttribute( "slope", m_slope );
+}
+
+void PMSlope::readAttributes( const PMXMLHelper& h )
+{
+ m_height = h.doubleAttribute( "height", heightDefault );
+ m_slope = h.doubleAttribute( "slope", slopeDefault );
+}
+
+PMMetaObject* PMSlope::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Slope", Base::metaObject( ),
+ createNewSlope );
+ s_pMetaObject->addProperty(
+ new PMSlopeProperty( "height", &PMSlope::setHeight, &PMSlope::height ) );
+ s_pMetaObject->addProperty(
+ new PMSlopeProperty( "slope", &PMSlope::setSlope, &PMSlope::slope ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMSlope::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMSlope::setHeight( const double c )
+{
+ if( c != m_height )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMHeightID, m_height );
+ m_height = c;
+ }
+}
+
+void PMSlope::setSlope( const double c )
+{
+ if( c != m_slope )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSlopeID, m_slope );
+ m_slope = c;
+ }
+}
+
+PMDialogEditBase* PMSlope::editWidget( QWidget* parent ) const
+{
+ return new PMSlopeEdit( parent );
+}
+
+void PMSlope::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMSlopeID:
+ setSlope( data->doubleData( ) );
+ break;
+ case PMHeightID:
+ setHeight( data->doubleData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMSlope::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmslope.h b/kpovmodeler/pmslope.h
new file mode 100644
index 00000000..5f89b5b2
--- /dev/null
+++ b/kpovmodeler/pmslope.h
@@ -0,0 +1,94 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMSLOPE_H
+#define PMSLOPE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmobject.h"
+
+/**
+ * Class for Repeat Slopes
+ */
+
+class PMSlope : public PMObject
+{
+ typedef PMObject Base;
+public:
+ /**
+ * Creates a PMSlope
+ */
+ PMSlope( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMSlope( const PMSlope& s );
+ /**
+ * deletes the PMSlope
+ */
+ virtual ~PMSlope( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMSlope( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMSlopeEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmslope" ); }
+
+ double height( ) const { return m_height; }
+ void setHeight( double c );
+ double slope( ) const { return m_slope; }
+ void setSlope( double c );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMSlopeMementoID { PMHeightID, PMSlopeID };
+
+ double m_height;
+ double m_slope;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmslopeedit.cpp b/kpovmodeler/pmslopeedit.cpp
new file mode 100644
index 00000000..5bfcb88b
--- /dev/null
+++ b/kpovmodeler/pmslopeedit.cpp
@@ -0,0 +1,95 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmslopeedit.h"
+#include "pmslope.h"
+#include "pmvectoredit.h"
+#include "pmlineedits.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcombobox.h>
+#include <qcheckbox.h>
+#include <klocale.h>
+#include <kdialog.h>
+
+
+PMSlopeEdit::PMSlopeEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMSlopeEdit::createTopWidgets( )
+{
+ QHBoxLayout* hl;
+ QGridLayout* gl;
+
+ Base::createTopWidgets( );
+
+ QLabel* label = new QLabel( i18n( "Height:" ), this );
+ m_pHeightEdit = new PMFloatEdit( this );
+ hl = new QHBoxLayout( topLayout( ) );
+ gl = new QGridLayout( hl, 2, 2 );
+ gl->addWidget( label, 0, 0 );
+ gl->addWidget( m_pHeightEdit, 0, 1 );
+ label = new QLabel( i18n( "Slope:" ), this );
+ m_pSlopeEdit = new PMFloatEdit( this );
+ gl->addWidget( label, 1, 0 );
+ gl->addWidget( m_pSlopeEdit, 1, 1 );
+ hl->addStretch( 1 );
+
+ connect( m_pHeightEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pSlopeEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMSlopeEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Slope" ) )
+ {
+ m_pDisplayedObject = ( PMSlope* ) o;
+ m_pHeightEdit->setValue( m_pDisplayedObject->height( ) );
+ m_pHeightEdit->setReadOnly( m_pDisplayedObject->isReadOnly( ) );
+ m_pSlopeEdit->setValue( m_pDisplayedObject->slope( ) );
+ m_pSlopeEdit->setReadOnly( m_pDisplayedObject->isReadOnly( ) );
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMSlopeEdit: Can't display object\n";
+}
+
+void PMSlopeEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setHeight( m_pHeightEdit->value( ) );
+ m_pDisplayedObject->setSlope( m_pSlopeEdit->value( ) );
+ }
+}
+
+bool PMSlopeEdit::isDataValid( )
+{
+ if( !m_pHeightEdit->isDataValid( ) ||
+ !m_pSlopeEdit->isDataValid( ) )
+ return false;
+
+ return Base::isDataValid( );
+}
+
+#include "pmslopeedit.moc"
diff --git a/kpovmodeler/pmslopeedit.h b/kpovmodeler/pmslopeedit.h
new file mode 100644
index 00000000..2c4d2af4
--- /dev/null
+++ b/kpovmodeler/pmslopeedit.h
@@ -0,0 +1,68 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMSLOPEEDIT_H
+#define PMSLOPEEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdialogeditbase.h"
+
+class PMSlope;
+class PMVectorEdit;
+class PMIntEdit;
+class PMFloatEdit;
+class QComboBox;
+class QCheckBox;
+class QLabel;
+
+/**
+ * Dialog edit class for @ref PMSlope.
+ */
+class PMSlopeEdit : public PMDialogEditBase
+{
+ Q_OBJECT
+ typedef PMDialogEditBase Base;
+public:
+ /**
+ * Creates a PMSlopeEdit with parent and name
+ */
+ PMSlopeEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMSlope* m_pDisplayedObject;
+ PMFloatEdit* m_pHeightEdit;
+ PMFloatEdit* m_pSlopeEdit;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmsolidcolor.cpp b/kpovmodeler/pmsolidcolor.cpp
new file mode 100644
index 00000000..c067b12d
--- /dev/null
+++ b/kpovmodeler/pmsolidcolor.cpp
@@ -0,0 +1,127 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmsolidcolor.h"
+
+#include "pmxmlhelper.h"
+#include "pmsolidcoloredit.h"
+#include "pmmemento.h"
+
+#include <klocale.h>
+
+const PMColor colorDefault = PMColor( 0.0, 0.0, 0.0, 0.0, 0.0 );
+
+PMDefinePropertyClass( PMSolidColor, PMSolidColorProperty );
+
+PMMetaObject* PMSolidColor::s_pMetaObject = 0;
+PMObject* createNewSolidColor( PMPart* part )
+{
+ return new PMSolidColor( part );
+}
+
+PMSolidColor::PMSolidColor( PMPart* part )
+ : Base( part )
+{
+ m_color = colorDefault;
+}
+
+PMSolidColor::PMSolidColor( const PMSolidColor& c )
+ : Base( c )
+{
+ m_color = c.m_color;
+}
+
+PMSolidColor::~PMSolidColor( )
+{
+}
+
+QString PMSolidColor::description( ) const
+{
+ return i18n( "solid color" );
+}
+
+void PMSolidColor::serialize( QDomElement& e, QDomDocument& /*doc*/ ) const
+{
+ e.setAttribute( "color", m_color.serializeXML( ) );
+}
+
+void PMSolidColor::readAttributes( const PMXMLHelper& h )
+{
+ m_color = h.colorAttribute( "color", colorDefault );
+}
+
+PMMetaObject* PMSolidColor::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "SolidColor", Base::metaObject( ),
+ createNewSolidColor );
+ s_pMetaObject->addProperty(
+ new PMSolidColorProperty( "color", &PMSolidColor::setColor, &PMSolidColor::color ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMSolidColor::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMSolidColor::setColor( const PMColor& c )
+{
+ if( c != m_color )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMColorID, m_color );
+ m_color = c;
+ }
+}
+
+PMDialogEditBase* PMSolidColor::editWidget( QWidget* parent ) const
+{
+ return new PMSolidColorEdit( parent );
+}
+
+void PMSolidColor::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMColorID:
+ setColor( data->colorData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMSolidColor::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmsolidcolor.h b/kpovmodeler/pmsolidcolor.h
new file mode 100644
index 00000000..7a575758
--- /dev/null
+++ b/kpovmodeler/pmsolidcolor.h
@@ -0,0 +1,97 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMSOLIDCOLOR_H
+#define PMSOLIDCOLOR_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmobject.h"
+#include "pmcolor.h"
+
+/**
+ * Class for solid colors.
+ */
+
+class PMSolidColor : public PMObject
+{
+ typedef PMObject Base;
+public:
+ /**
+ * Creates a PMSolidColor
+ */
+ PMSolidColor( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMSolidColor( const PMSolidColor& s );
+ /**
+ * deletes the PMSolidColor
+ */
+ virtual ~PMSolidColor( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMSolidColor( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMSolidColorEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmsolidcolor" ); }
+
+ /**
+ * Returns the color
+ */
+ PMColor color( ) const { return m_color; }
+ /**
+ * Sets the color
+ */
+ void setColor( const PMColor& c );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMSolidColorMementoID { PMColorID };
+ PMColor m_color;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmsolidcoloredit.cpp b/kpovmodeler/pmsolidcoloredit.cpp
new file mode 100644
index 00000000..49183582
--- /dev/null
+++ b/kpovmodeler/pmsolidcoloredit.cpp
@@ -0,0 +1,79 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmsolidcoloredit.h"
+#include "pmsolidcolor.h"
+#include "pmcoloredit.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <klocale.h>
+
+
+PMSolidColorEdit::PMSolidColorEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMSolidColorEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* layout = new QHBoxLayout( topLayout( ) );
+ m_pColorEdit = new PMColorEdit( true, this );
+ QLabel* label = new QLabel( i18n( "Color:" ), this );
+
+ layout->addWidget( label, 0, AlignTop );
+ layout->addWidget( m_pColorEdit );
+
+ connect( m_pColorEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMSolidColorEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "SolidColor" ) )
+ {
+ m_pDisplayedObject = ( PMSolidColor* ) o;
+ m_pColorEdit->setColor( m_pDisplayedObject->color( ) );
+
+ m_pColorEdit->setReadOnly( m_pDisplayedObject->isReadOnly( ) );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMSolidColorEdit: Can't display object\n";
+}
+
+void PMSolidColorEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setColor( m_pColorEdit->color( ) );
+ }
+}
+
+bool PMSolidColorEdit::isDataValid( )
+{
+ if( !m_pColorEdit->isDataValid( ) )
+ return false;
+ return Base::isDataValid( );
+}
+
+#include "pmsolidcoloredit.moc"
diff --git a/kpovmodeler/pmsolidcoloredit.h b/kpovmodeler/pmsolidcoloredit.h
new file mode 100644
index 00000000..57439f92
--- /dev/null
+++ b/kpovmodeler/pmsolidcoloredit.h
@@ -0,0 +1,62 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMSOLIDCOLOREDIT_H
+#define PMSOLIDCOLOREDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdialogeditbase.h"
+
+class PMSolidColor;
+class PMColorEdit;
+
+/**
+ * Dialog edit class for @ref PMSolidColor.
+ */
+class PMSolidColorEdit : public PMDialogEditBase
+{
+ Q_OBJECT
+ typedef PMDialogEditBase Base;
+public:
+ /**
+ * Creates a PMSolidColorEdit with parent and name
+ */
+ PMSolidColorEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMSolidColor* m_pDisplayedObject;
+ PMColorEdit* m_pColorEdit;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmsolidobject.cpp b/kpovmodeler/pmsolidobject.cpp
new file mode 100644
index 00000000..6907e731
--- /dev/null
+++ b/kpovmodeler/pmsolidobject.cpp
@@ -0,0 +1,140 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmsolidobject.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+
+
+PMDefinePropertyClass( PMSolidObject, PMSolidObjectProperty );
+
+PMMetaObject* PMSolidObject::s_pMetaObject = 0;
+
+PMSolidObject::PMSolidObject( PMPart* part )
+ : Base( part )
+{
+ m_inverse = false;
+ m_hollow = PMUnspecified;
+}
+
+PMSolidObject::PMSolidObject( const PMSolidObject& s )
+ : Base( s )
+{
+ m_inverse = s.m_inverse;
+ m_hollow = s.m_hollow;
+}
+
+PMSolidObject::~PMSolidObject( )
+{
+}
+
+PMMetaObject* PMSolidObject::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "SolidObject", Base::metaObject( ) );
+ s_pMetaObject->addProperty(
+ new PMSolidObjectProperty( "inverse", &PMSolidObject::setInverse, &PMSolidObject::inverse ) );
+ s_pMetaObject->addProperty(
+ new PMSolidObjectProperty( "hollow", &PMSolidObject::setHollow, &PMSolidObject::hollow ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMSolidObject::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMSolidObject::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ switch( m_hollow )
+ {
+ case PMTrue:
+ e.setAttribute( "hollow", "1" );
+ break;
+ case PMFalse:
+ e.setAttribute( "hollow", "0" );
+ break;
+ case PMUnspecified:
+ break;
+ }
+ e.setAttribute( "inverse", m_inverse );
+
+ Base::serialize( e, doc );
+}
+
+void PMSolidObject::readAttributes( const PMXMLHelper& h )
+{
+ m_hollow = h.threeStateAttribute( "hollow" );
+ m_inverse = h.boolAttribute( "inverse", false );
+
+ Base::readAttributes( h );
+}
+
+void PMSolidObject::setHollow( PMThreeState h )
+{
+ if( m_hollow != h )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMHollowID, m_hollow );
+ m_hollow = h;
+ }
+}
+
+void PMSolidObject::setInverse( bool yes )
+{
+ if( m_inverse != yes )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMInverseID, m_inverse );
+ m_inverse = yes;
+ }
+}
+
+void PMSolidObject::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMInverseID:
+ setInverse( data->boolData( ) );
+ break;
+ case PMHollowID:
+ setHollow( data->threeStateData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMSolidObject::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmsolidobject.h b/kpovmodeler/pmsolidobject.h
new file mode 100644
index 00000000..e497c397
--- /dev/null
+++ b/kpovmodeler/pmsolidobject.h
@@ -0,0 +1,94 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMSOLIDOBJECT_H
+#define PMSOLIDOBJECT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmgraphicalobject.h"
+
+
+/**
+ * Class for povray solid objects
+ */
+class PMSolidObject : public PMGraphicalObject
+{
+ typedef PMGraphicalObject Base;
+public:
+ /**
+ * Creates an empty PMSolidObject
+ */
+ PMSolidObject( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMSolidObject( const PMSolidObject& s );
+
+ /**
+ * Deletes the object and all children
+ */
+ virtual ~PMSolidObject( );
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns the state of the hollow flag.
+ * Values can be PMTrue, PMFalse, PMUnspecified.
+ */
+ PMThreeState hollow( ) const { return m_hollow; }
+ /**
+ * Sets the hollow flag. Values can be PMTrue, PMFalse, PMUnspecified.
+ */
+ void setHollow( PMThreeState h );
+
+ /**
+ * Returns the state of the inverse flag.
+ */
+ bool inverse( ) const { return m_inverse; }
+ /**
+ * Sets the inverse flag
+ */
+ void setInverse( bool yes );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMSolidObjectMementoID { PMInverseID, PMHollowID };
+
+ bool m_inverse;
+ PMThreeState m_hollow;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmsolidobjectedit.cpp b/kpovmodeler/pmsolidobjectedit.cpp
new file mode 100644
index 00000000..e6aa3765
--- /dev/null
+++ b/kpovmodeler/pmsolidobjectedit.cpp
@@ -0,0 +1,82 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmsolidobjectedit.h"
+#include "pmsolidobject.h"
+
+#include <qcheckbox.h>
+#include <qlayout.h>
+#include <klocale.h>
+
+PMSolidObjectEdit::PMSolidObjectEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMSolidObjectEdit::createBottomWidgets( )
+{
+ m_pInverseButton = new QCheckBox( i18n( "Inverse" ), this );
+ m_pHollowButton = new QCheckBox( i18n( "Hollow" ), this );
+
+ m_pHollowButton->setTristate( true );
+
+ topLayout( )->addWidget( m_pInverseButton );
+ topLayout( )->addWidget( m_pHollowButton );
+
+ connect( m_pHollowButton, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pInverseButton, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+
+ Base::createBottomWidgets( );
+}
+
+void PMSolidObjectEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "SolidObject" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+
+ m_pDisplayedObject = ( PMSolidObject* ) o;
+ setCheckBox( m_pHollowButton, m_pDisplayedObject->hollow( ) );
+ m_pInverseButton->setChecked( m_pDisplayedObject->inverse( ) );
+
+ m_pHollowButton->setEnabled( !readOnly );
+ m_pInverseButton->setEnabled( !readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMSolidObjectEdit: Can't display object\n";
+}
+
+void PMSolidObjectEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ m_pDisplayedObject->setHollow( checkBoxState( m_pHollowButton ) );
+ m_pDisplayedObject->setInverse( m_pInverseButton->isChecked( ) );
+ Base::saveContents( );
+ }
+}
+
+bool PMSolidObjectEdit::isDataValid( )
+{
+ return Base::isDataValid( );
+}
+
+#include "pmsolidobjectedit.moc"
diff --git a/kpovmodeler/pmsolidobjectedit.h b/kpovmodeler/pmsolidobjectedit.h
new file mode 100644
index 00000000..3da2da6a
--- /dev/null
+++ b/kpovmodeler/pmsolidobjectedit.h
@@ -0,0 +1,63 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMSOLIDOBJECTEDIT_H
+#define PMSOLIDOBJECTEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmgraphicalobjectedit.h"
+
+class PMSolidObject;
+class QCheckBox;
+
+/**
+ * Dialog edit class for @ref PMSolidObject.
+ */
+class PMSolidObjectEdit : public PMGraphicalObjectEdit
+{
+ Q_OBJECT
+ typedef PMGraphicalObjectEdit Base;
+public:
+ /**
+ * Creates a PMSolidObjectEdit with parent and name
+ */
+ PMSolidObjectEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createBottomWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMSolidObject* m_pDisplayedObject;
+ QCheckBox* m_pHollowButton;
+ QCheckBox* m_pInverseButton;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmsor.cpp b/kpovmodeler/pmsor.cpp
new file mode 100644
index 00000000..b7a9f0ef
--- /dev/null
+++ b/kpovmodeler/pmsor.cpp
@@ -0,0 +1,708 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmsor.h"
+
+#include "pmxmlhelper.h"
+#include "pmsoredit.h"
+#include "pmmemento.h"
+#include "pmviewstructure.h"
+#include "pmsorcontrolpoint.h"
+#include "pmsplinememento.h"
+#include "pmsorsegment.h"
+#include "pmdefaults.h"
+#include "pmobjectaction.h"
+
+#include <klocale.h>
+
+const int defaultNumberOfPoints = 4;
+const PMVector defaultPoint[defaultNumberOfPoints] =
+{
+ PMVector( 0.0, 0.0 ),
+ PMVector( 0.5, 0.3 ),
+ PMVector( 0.5, 0.7 ),
+ PMVector( 0.0, 1.0 )
+};
+
+const bool defaultSturm = false;
+const bool defaultOpen = false;
+
+int PMSurfaceOfRevolution::s_rSteps = c_defaultSurfaceOfRevolutionRSteps;
+int PMSurfaceOfRevolution::s_sSteps = c_defaultSurfaceOfRevolutionSSteps;
+int PMSurfaceOfRevolution::s_parameterKey = 0;
+PMMetaObject* PMSurfaceOfRevolution::s_pMetaObject = 0;
+PMObject* createNewSurfaceOfRevolution( PMPart* part )
+{
+ return new PMSurfaceOfRevolution( part );
+}
+
+PMDefinePropertyClass( PMSurfaceOfRevolution, PMSurfaceOfRevolutionProperty );
+
+class PMPointProperty : public PMPropertyBase
+{
+public:
+ PMPointProperty( )
+ : PMPropertyBase( "controlPoints", PMVariant::Vector )
+ {
+ m_index = 0;
+ }
+ virtual int dimensions( ) const { return 1; }
+ virtual void setIndex( int /*dimension*/, int index )
+ {
+ m_index = index;
+ }
+ virtual int size( PMObject* object, int /*dimension*/ ) const
+ {
+ return ( ( PMSurfaceOfRevolution* ) object )->numberOfPoints( );
+ }
+protected:
+ virtual bool setProtected( PMObject* obj, const PMVariant& var )
+ {
+ PMSurfaceOfRevolution* p = ( PMSurfaceOfRevolution* ) obj;
+ QValueList<PMVector> list = p->points( );
+ QValueList<PMVector>::Iterator it = list.begin( );
+ int i;
+ PMVector v = var.vectorData( );
+ v.resize( 2 );
+
+ for( i = 0; i < m_index && it != list.end( ); ++i )
+ ++it;
+ // expand the list if necessary
+ for( ; i < m_index; ++i )
+ list.insert( it, v );
+ if( it == list.end( ) )
+ it = list.insert( it, v );
+ else
+ *it = v;
+
+ p->setPoints( list );
+ return true;
+ }
+ virtual PMVariant getProtected( const PMObject* obj )
+ {
+ PMSurfaceOfRevolution* p = ( PMSurfaceOfRevolution* ) obj;
+ QValueList<PMVector> list = p->points( );
+ QValueList<PMVector>::ConstIterator it = list.at( m_index );
+
+ if( it == list.end( ) )
+ {
+ kdError( PMArea ) << "Range error in PMSurfaceOfRevolution::PointProperty::get" << endl;
+ return PMVariant( );
+ }
+
+ return PMVariant( *it );
+ }
+
+private:
+ int m_index;
+};
+
+PMSurfaceOfRevolution::PMSurfaceOfRevolution( PMPart* part )
+ : Base( part )
+{
+ int i;
+
+ for( i = 0; i < defaultNumberOfPoints; ++i )
+ m_points.append( defaultPoint[i] );
+ m_sturm = defaultSturm;
+ m_open = defaultOpen;
+}
+
+PMSurfaceOfRevolution::PMSurfaceOfRevolution( const PMSurfaceOfRevolution& s )
+ : Base( s )
+{
+ m_points = s.m_points;
+ m_sturm = s.m_sturm;
+ m_open = s.m_open;
+}
+
+PMSurfaceOfRevolution::~PMSurfaceOfRevolution( )
+{
+}
+
+QString PMSurfaceOfRevolution::description( ) const
+{
+ return i18n( "surface of revolution" );
+}
+
+void PMSurfaceOfRevolution::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ QDomElement data = doc.createElement( "extra_data" );
+ QDomElement p;
+
+ e.setAttribute( "sturm", m_sturm );
+ e.setAttribute( "open", m_open );
+
+ QValueList<PMVector>::ConstIterator it;
+ for( it = m_points.begin( ); it != m_points.end( ); ++it )
+ {
+ p = doc.createElement( "point" );
+ p.setAttribute( "vector", ( *it ).serializeXML( ) );
+ data.appendChild( p );
+ }
+
+ e.appendChild( data );
+ Base::serialize( e, doc );
+}
+
+void PMSurfaceOfRevolution::readAttributes( const PMXMLHelper& h )
+{
+ m_sturm = h.boolAttribute( "sturm", defaultSturm );
+ m_open = h.boolAttribute( "open", defaultOpen );
+
+ m_points.clear( );
+ PMVector v( 2 );
+
+ QDomElement e = h.extraData( );
+ if( !e.isNull( ) )
+ {
+ QDomNode c = e.firstChild( );
+ while( !c.isNull( ) )
+ {
+ if( c.isElement( ) )
+ {
+ QDomElement ce = c.toElement( );
+ if( ce.tagName( ) == "point" )
+ {
+ QString str = ce.attribute( "vector" );
+ if( !str.isNull( ) )
+ {
+ v.loadXML( str );
+ m_points.append( v );
+ }
+ }
+ }
+ c = c.nextSibling( );
+ }
+ }
+
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMSurfaceOfRevolution::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "SurfaceOfRevolution", Base::metaObject( ),
+ createNewSurfaceOfRevolution );
+ s_pMetaObject->addProperty(
+ new PMSurfaceOfRevolutionProperty( "sturm", &PMSurfaceOfRevolution::setSturm,
+ &PMSurfaceOfRevolution::sturm ) );
+ s_pMetaObject->addProperty(
+ new PMSurfaceOfRevolutionProperty( "open", &PMSurfaceOfRevolution::setOpen,
+ &PMSurfaceOfRevolution::open ) );
+ s_pMetaObject->addProperty( new PMPointProperty( ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMSurfaceOfRevolution::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMSurfaceOfRevolution::setSturm( bool s )
+{
+ if( m_sturm != s )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSturmID, m_sturm );
+ m_sturm = s;
+ }
+}
+
+void PMSurfaceOfRevolution::setOpen( bool o )
+{
+ if( m_open != o )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMOpenID, m_open );
+ m_open = o;
+ }
+}
+
+void PMSurfaceOfRevolution::setPoints( const QValueList<PMVector>& points )
+{
+ if( m_points != points )
+ {
+ if( m_pMemento )
+ ( ( PMSplineMemento* ) m_pMemento )->setSplinePoints( m_points );
+
+ setViewStructureChanged( );
+ m_points = points;
+ }
+}
+
+PMDialogEditBase* PMSurfaceOfRevolution::editWidget( QWidget* parent ) const
+{
+ return new PMSurfaceOfRevolutionEdit( parent );
+}
+
+void PMSurfaceOfRevolution::createMemento( )
+{
+ if( m_pMemento )
+ delete m_pMemento;
+ m_pMemento = new PMSplineMemento( this );
+}
+
+void PMSurfaceOfRevolution::restoreMemento( PMMemento* s )
+{
+ PMSplineMemento* m = ( PMSplineMemento* ) s;
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMSturmID:
+ setSturm( data->boolData( ) );
+ break;
+ case PMOpenID:
+ setOpen( data->boolData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMSurfaceOfRevolution::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ if( m->splinePointsSaved( ) )
+ setPoints( m->splinePoints( ) );
+
+ Base::restoreMemento( s );
+}
+
+
+void PMSurfaceOfRevolution::createViewStructure( )
+{
+ if( s_sSteps == 0 )
+ s_sSteps = c_defaultSurfaceOfRevolutionSSteps;
+ if( s_rSteps == 0 )
+ s_rSteps = c_defaultSurfaceOfRevolutionRSteps;
+
+ int rSteps = (int)( ( (float)s_rSteps / 2 ) * ( displayDetail( ) + 1 ) );
+ int sSteps = (int)( ( (float)s_sSteps / 2 ) * ( displayDetail( ) + 1 ) );
+
+ int np = m_points.count( );
+ int i, j, r;
+
+ // calculate number of segments
+ int ns = np - 3;
+
+ // calculate number of points and lines of the view structure
+ int vsp = ns * sSteps + 1;
+ int vsl = ( 2 * vsp - 1 ) * rSteps;
+ vsp *= rSteps;
+
+ if( m_pViewStructure )
+ {
+ if( m_pViewStructure->points( ).size( ) != ( unsigned ) vsp )
+ m_pViewStructure->points( ).resize( vsp );
+ if( m_pViewStructure->lines( ).size( ) != ( unsigned ) vsl )
+ m_pViewStructure->lines( ).resize( vsl );
+ }
+ else
+ m_pViewStructure = new PMViewStructure( vsp, vsl );
+
+
+ // calculate the spline segments
+ QValueList<PMSorSegment> segments;
+ QValueList<PMVector>::Iterator it1, it2, it3, it4;
+ it1 = m_points.begin( );
+ it2 = it1; ++it2;
+ it3 = it2; ++it3;
+ it4 = it3; ++it4;
+
+ for( i = 0; i < ns; ++i, ++it1, ++it2, ++it3, ++it4 )
+ segments.append( PMSorSegment( *it1, *it2, *it3, *it4 ) );
+
+ // create the line array
+ PMLineArray& lines = m_pViewStructure->lines( );
+ int vl = ns * sSteps;
+ int lb = 0;
+ for( i = 0; i < vl + 1; ++i )
+ {
+ for( j = 0; j < rSteps - 1; ++j )
+ lines[lb+j] = PMLine( lb + j, lb + j + 1 );
+ lines[lb+rSteps-1] = PMLine( lb, lb + rSteps - 1 );
+ lb += rSteps;
+ }
+ int pi = 0;
+ for( i = 0; i < vl; ++i )
+ {
+ for( j = 0; j < rSteps; ++j )
+ {
+ lines[lb] = PMLine( pi, pi + rSteps );
+ ++pi;
+ ++lb;
+ }
+ }
+
+ // calculate the points
+ PMVector point2, point3;
+ QValueList<PMSorSegment>::Iterator sit = segments.begin( );
+
+ double poffset = 1.0 / sSteps;
+ PMMatrix rot = PMMatrix::rotation( 0.0, M_PI * 2.0 / rSteps, 0.0 );
+ PMPointArray& points = m_pViewStructure->points( );
+ pi = 0;
+
+ for( i = 0; i < ns; ++i, ++sit )
+ {
+ for( j = 0; j < sSteps; ++j )
+ {
+ point2 = ( *sit ).point( poffset * j );
+ point3[0] = point2[0];
+ point3[1] = point2[1];
+ point3[2] = 0.0;
+
+ for( r = 0; r < rSteps; ++r )
+ {
+ points[pi] = PMPoint( point3 );
+ if( r != rSteps - 1 )
+ point3.transform( rot );
+ ++pi;
+ }
+ }
+ if( i == ns - 1 )
+ {
+ point2 = ( *sit ).point( 1.0 );
+ point3[0] = point2[0];
+ point3[1] = point2[1];
+ point3[2] = 0.0;
+
+ for( r = 0; r < rSteps; ++r )
+ {
+ points[pi] = PMPoint( point3 );
+ if( r != rSteps - 1 )
+ point3.transform( rot );
+ ++pi;
+ }
+ }
+ }
+}
+
+void PMSurfaceOfRevolution::controlPoints( PMControlPointList& list )
+{
+ QValueList<PMVector>::Iterator it;
+ QPtrList<PMSorControlPoint> tmp1, tmp2;
+ int i;
+
+ PMSorControlPoint* cp = 0;
+
+ PMSorControlPoint* lastPoint = 0;
+ cp = 0;
+
+ for( it = m_points.begin( ), i = 0; it != m_points.end( ); ++it, ++i )
+ {
+ lastPoint = cp;
+ cp = new PMSorControlPoint( lastPoint, *it, PMSorControlPoint::PM2DXY, i,
+ i18n( "Point %1 (xy)" ).arg( i + 1 ) );
+ tmp1.append( cp );
+ }
+
+ lastPoint = 0;
+ cp = 0;
+
+ for( it = m_points.begin( ), i = 0; it != m_points.end( ); ++it, ++i )
+ {
+ lastPoint = cp;
+ cp = new PMSorControlPoint( lastPoint, *it, PMSorControlPoint::PM2DZY, i,
+ i18n( "Point %1 (yz)" ).arg( i + 1 ) );
+ tmp2.append( cp );
+ }
+
+ QPtrListIterator<PMSorControlPoint> cit1( tmp1 ), cit2( tmp2 );
+
+ for( ; cit1.current( ) && cit2.current( ); ++cit1, ++cit2 )
+ {
+ ( *cit1 )->setSorLink( *cit2 );
+ ( *cit2 )->setSorLink( *cit1 );
+ }
+ for( cit1.toFirst( ); cit1.current( ); ++cit1 )
+ list.append( *cit1 );
+ for( cit2.toFirst( ); cit2.current( ); ++cit2 )
+ list.append( *cit2 );
+}
+
+void PMSurfaceOfRevolution::controlPointsChanged( PMControlPointList& list )
+{
+ PMControlPointListIterator it1( list ), it2( list );
+ QValueList<PMVector>::Iterator pit = m_points.begin( );
+ PMSorControlPoint* p1;
+ PMSorControlPoint* p2;
+ bool firstChange = true;
+ PMVector lastPoint( 2 );
+ int num = list.count( ) / 2;
+ int pnr = 0;
+
+ for( it2 += num; it2.current( ); ++it1, ++it2, ++pit, ++pnr )
+ {
+ p1 = ( PMSorControlPoint* ) it1.current( );
+ p2 = ( PMSorControlPoint* ) it2.current( );
+
+ if( p1->changed( ) )
+ {
+ if( firstChange )
+ {
+ if( m_pMemento )
+ {
+ PMSplineMemento* m = ( PMSplineMemento* ) m_pMemento;
+ if( !m->splinePointsSaved( ) )
+ m->setSplinePoints( m_points );
+ }
+ firstChange = false;
+ setViewStructureChanged( );
+ }
+ p2->setPoint( p1->point( ) );
+ ( *pit ) = p1->point( );
+ }
+ else if( p2->changed( ) )
+ {
+ if( firstChange )
+ {
+ if( m_pMemento )
+ {
+ PMSplineMemento* m = ( PMSplineMemento* ) m_pMemento;
+ if( !m->splinePointsSaved( ) )
+ m->setSplinePoints( m_points );
+ }
+ firstChange = false;
+ setViewStructureChanged( );
+ }
+ p1->setPoint( p2->point( ) );
+ ( *pit ) = p2->point( );
+ }
+
+ if( ( pnr > 1 ) && ( pnr < ( num - 1 ) ) )
+ {
+ if( ( ( *pit )[1] - lastPoint[1] ) < c_sorTolerance )
+ {
+ ( *pit )[1] = lastPoint[1] + c_sorTolerance;
+ p1->setPoint( *pit );
+ p2->setPoint( *pit );
+ }
+ }
+ if( ( pnr == ( num - 1 ) ) || ( pnr == 2 ) )
+ {
+ QValueList<PMVector>::Iterator hit = pit;
+ --hit; --hit;
+
+ if( approxZero( ( *hit )[1] - ( *pit )[1], c_sorTolerance ) )
+ {
+ ( *pit )[1] = ( *hit )[1] + c_sorTolerance;
+ p1->setPoint( *pit );
+ p2->setPoint( *pit );
+ }
+ }
+
+ lastPoint = *pit;
+ }
+}
+
+void PMSurfaceOfRevolution::addObjectActions( const PMControlPointList& /*cp*/,
+ QPtrList<PMObjectAction>& actions )
+{
+ PMObjectAction* a;
+
+ a = new PMObjectAction( s_pMetaObject, PMSplitSegmentID,
+ i18n( "Add Point" ) );
+ actions.append( a );
+
+ a = new PMObjectAction( s_pMetaObject, PMJoinSegmentsID,
+ i18n( "Remove Point" ) );
+ int np = m_points.count( );
+
+ if( np < 5 )
+ a->setEnabled( false );
+ actions.append( a );
+}
+
+void PMSurfaceOfRevolution::objectActionCalled( const PMObjectAction* action,
+ const PMControlPointList& cp,
+ const QPtrList<PMVector>& cpViewPosition,
+ const PMVector& clickPosition )
+{
+ if( action->objectType( ) == s_pMetaObject )
+ {
+ switch( action->actionID( ) )
+ {
+ case PMSplitSegmentID:
+ splitSegment( cp, cpViewPosition, clickPosition );
+ break;
+ case PMJoinSegmentsID:
+ joinSegments( cp, cpViewPosition, clickPosition );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMSurfaceOfRevolution::objectActionCalled\n";
+ break;
+ }
+ }
+ else
+ Base::objectActionCalled( action, cp, cpViewPosition, clickPosition );
+}
+
+void PMSurfaceOfRevolution::splitSegment( const PMControlPointList& /*cp*/,
+ const QPtrList<PMVector>& cpViewPosition,
+ const PMVector& clickPosition )
+{
+ // find nearest segment
+ int nump = cpViewPosition.count( ) / 2 - 1;
+ double abs = 0.0, minabs = 1e10;
+ int ns = -1;
+ int i, j;
+ PMVector mid( 3 ), dist( 2 );
+
+ QPtrListIterator<PMVector> it1( cpViewPosition );
+ QPtrListIterator<PMVector> it2( cpViewPosition );
+ ++it2;
+
+ for( j = 0; j < 2; ++j )
+ {
+ ++it1;
+ ++it2;
+ for( i = 1; i < ( nump - 1 ); ++i )
+ {
+ mid = ( **it1 + **it2 ) / 2.0;
+ dist[0] = mid[0];
+ dist[1] = mid[1];
+ dist -= clickPosition;
+ abs = dist.abs( );
+
+ if( ( minabs > abs ) || ( ns < 0 ) )
+ {
+ minabs = abs;
+ ns = i;
+ }
+ ++it1;
+ ++it2;
+ }
+ ++it1;
+ ++it2;
+ ++it1;
+ ++it2;
+ }
+
+ // add a new segment
+ QValueList<PMVector> newPoints = m_points;
+ QValueList<PMVector>::Iterator it = newPoints.at( ( unsigned ) ns );
+ PMVector p[4];
+ QValueList<PMVector>::Iterator hit = it;
+
+ // calculate the spline segment
+ --hit;
+ for( i = 0; i < 4; ++i, ++hit )
+ p[i] = *hit;
+ PMSorSegment segment( p[0], p[1], p[2], p[3] );
+
+ mid = segment.point( 0.5 );
+ if( mid[0] < 0 )
+ mid[0] = 0;
+ ++it;
+ it = newPoints.insert( it, mid );
+ hit = it;
+ --it;
+
+ for( ; hit != newPoints.end( ); ++it, ++hit )
+ if( ( ( *hit )[1] - ( *it )[1] ) < c_sorTolerance )
+ ( *hit )[1] = ( *it )[1] + c_sorTolerance;
+
+ setPoints( newPoints );
+}
+
+void PMSurfaceOfRevolution::joinSegments( const PMControlPointList& /*cp*/,
+ const QPtrList<PMVector>& cpViewPosition,
+ const PMVector& clickPosition )
+{
+ // find nearest point
+ int nump = cpViewPosition.count( ) / 2;
+
+ if( nump < 5 )
+ {
+ kdError( PMArea ) << "Not enough points in PMSurfaceOfRevolution::joinSegments\n";
+ return;
+ }
+
+ double abs = 0.0, minabs = 1e10;
+ int ns = -1;
+ int i, j;
+ PMVector* p;
+ PMVector dist( 2 );
+
+ QPtrListIterator<PMVector> it1( cpViewPosition );
+
+ for( j = 0; j < 2; ++j )
+ {
+ for( i = 0; i < nump; ++i )
+ {
+ p = *it1;
+ dist[0] = (*p)[0];
+ dist[1] = (*p)[1];
+ dist -= clickPosition;
+ abs = dist.abs( );
+
+ if( ( minabs > abs ) || ( ns < 0 ) )
+ {
+ minabs = abs;
+ ns = i;
+ }
+ ++it1;
+ }
+ }
+
+ // join two segments
+ QValueList<PMVector> newPoints = m_points;
+ QValueList<PMVector>::Iterator it;
+
+ // never remove the first or last point
+ if( ns == 0 )
+ ++ns;
+ if( ns == ( nump - 1 ) )
+ --ns;
+ it = newPoints.at( ns );
+ newPoints.remove( it );
+
+ setPoints( newPoints );
+}
+
+void PMSurfaceOfRevolution::setRSteps( int r )
+{
+ if( r >= 4 )
+ s_rSteps = r;
+ else
+ kdDebug( PMArea ) << "PMSurfaceOfRevolution::setRSteps: R must be greater than 3\n";
+ ++s_parameterKey;
+}
+
+void PMSurfaceOfRevolution::setSSteps( int s )
+{
+ if( s >= 1 )
+ s_sSteps = s;
+ else
+ kdDebug( PMArea ) << "PMSurfaceOfRevolution::setSSteps: S must be greater than 0\n";
+ ++s_parameterKey;
+}
diff --git a/kpovmodeler/pmsor.h b/kpovmodeler/pmsor.h
new file mode 100644
index 00000000..c15b305d
--- /dev/null
+++ b/kpovmodeler/pmsor.h
@@ -0,0 +1,191 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMSOR_H
+#define PMSOR_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobject.h"
+#include "pmvector.h"
+#include "pmsorcontrolpoint.h"
+#include <qptrlist.h>
+#include <qvaluelist.h>
+#include <math.h>
+
+class PMViewStructure;
+
+/**
+ * Class for povray sor objects.
+ */
+
+class PMSurfaceOfRevolution : public PMSolidObject
+{
+ typedef PMSolidObject Base;
+public:
+ /**
+ * Creates an empty PMSurfaceOfRevolution
+ */
+ PMSurfaceOfRevolution( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMSurfaceOfRevolution( const PMSurfaceOfRevolution& s );
+ /**
+ * deletes the PMSurfaceOfRevolution
+ */
+ virtual ~PMSurfaceOfRevolution( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMSurfaceOfRevolution( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMSurfaceOfRevolutionEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmsor" ); }
+
+ /** */
+ virtual void createMemento( );
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /** */
+ virtual void controlPoints( PMControlPointList& list );
+ /** */
+ virtual void controlPointsChanged( PMControlPointList& list );
+ /** */
+ virtual bool multipleSelectControlPoints( ) const { return true; }
+ /** */
+ virtual bool hasDisplayDetail( ) const { return true; }
+ /** */
+ virtual void addObjectActions( const PMControlPointList&,
+ QPtrList<PMObjectAction>& );
+ /** */
+ virtual void objectActionCalled( const PMObjectAction*,
+ const PMControlPointList&,
+ const QPtrList<PMVector>&,
+ const PMVector& );
+
+ /**
+ * Returns the sor points
+ */
+ QValueList<PMVector> points( ) const { return m_points; }
+ /**
+ * Sets the spline points
+ */
+ void setPoints( const QValueList<PMVector>& points );
+ /**
+ * Returns the number of spline points
+ */
+ int numberOfPoints( ) const { return m_points.size( ); }
+ /**
+ * Returns the sturm flag
+ */
+ bool sturm( ) const { return m_sturm; }
+ /**
+ * Sets the sturm flag
+ */
+ void setSturm( bool s );
+ /**
+ * Returns the open flag
+ */
+ bool open( ) const { return m_open; }
+ /**
+ * Sets the open flag
+ */
+ void setOpen( bool o );
+
+ /**
+ * Sets the number of steps around the y axis
+ */
+ static void setRSteps( int r );
+ /**
+ * Sets the number of subdivisions of one spline segment
+ */
+ static void setSSteps( int v );
+ /**
+ * Returns the number of steps around the y axis
+ */
+ static int rSteps( ) { return s_rSteps; }
+ /**
+ * Returns the number of subdivisions of one spline segment
+ */
+ static int sSteps( ) { return s_sSteps; }
+
+protected:
+ /** */
+ virtual void createViewStructure( );
+ /** */
+ virtual int viewStructureParameterKey( ) const { return s_parameterKey + globalDetailKey( ); }
+
+private:
+ /**
+ * Object action. Adds a spline point
+ */
+ void splitSegment( const PMControlPointList& cp,
+ const QPtrList<PMVector>& cpViewPosition,
+ const PMVector& clickPosition );
+ /**
+ * Object action. Removes a spline point
+ */
+ void joinSegments( const PMControlPointList& cp,
+ const QPtrList<PMVector>& cpViewPosition,
+ const PMVector& clickPosition );
+
+ void stringToValues( const QString& str );
+ QString valuesToString( ) const;
+
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMSurfaceOfRevolutionMementoID { PMOpenID, PMSturmID };
+ /**
+ * IDs for the object actions
+ */
+ enum PMSurfaceOfRevolutionActionID { PMSplitSegmentID, PMJoinSegmentsID };
+
+ QValueList<PMVector> m_points;
+ bool m_sturm;
+ bool m_open;
+
+ static int s_rSteps;
+ static int s_sSteps;
+ static int s_parameterKey;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmsorcontrolpoint.cpp b/kpovmodeler/pmsorcontrolpoint.cpp
new file mode 100644
index 00000000..88924d05
--- /dev/null
+++ b/kpovmodeler/pmsorcontrolpoint.cpp
@@ -0,0 +1,228 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmsorcontrolpoint.h"
+#include "pmmath.h"
+#include <math.h>
+
+PMSorControlPoint::PMSorControlPoint( PMSorControlPoint* prev,
+ const PMVector& point,
+ PMSorControlPoint::CPType type, int id,
+ const QString& description )
+ : PMControlPoint( id, description )
+{
+ m_point = point;
+ m_type = type;
+ m_pPrev = prev;
+ if( m_pPrev )
+ m_pPrev->m_pNext = this;
+ m_pNext = 0;
+ m_pSorLink = 0;
+}
+
+void PMSorControlPoint::graphicalChangeStarted( )
+{
+ if( m_pPrev && !m_pPrev->m_pPrev && !m_pPrev->selected( ) )
+ m_pPrev->graphicalChangeStarted( );
+ if( m_pNext && !m_pNext->m_pNext && !m_pNext->selected( ) )
+ m_pNext->graphicalChangeStarted( );
+
+ m_original2DPoint = m_point;
+ m_originalPoint = to3D( m_point );
+}
+
+void PMSorControlPoint::graphicalChange( const PMVector& startPoint,
+ const PMVector& /*viewNormal*/,
+ const PMVector& endPoint )
+{
+ if( !m_pPrev && m_pNext->selected( ) ||
+ !m_pNext && m_pPrev->selected( ) )
+ return;
+
+ m_point = to2D( m_originalPoint + endPoint - startPoint );
+
+ if( m_pSorLink && m_pSorLink->selected( ) )
+ {
+ PMSorControlPoint* ll = m_pSorLink;
+ PMVector op = ll->to2D( ll->m_originalPoint + endPoint - startPoint );
+
+ if( ( m_point - m_original2DPoint ).abs( ) <
+ ( op - ll->m_original2DPoint ).abs( ) )
+ m_point = op;
+ }
+
+ if( m_pPrev && m_pNext )
+ {
+ if( m_pPrev->m_pPrev )
+ if( ( m_point[1] - m_pPrev->m_point[1] ) < c_sorTolerance )
+ m_point[1] = m_pPrev->m_point[1] + c_sorTolerance;
+ if( m_pNext->m_pNext )
+ if( ( m_pNext->m_point[1] - m_point[1] ) < c_sorTolerance )
+ m_point[1] = m_pNext->m_point[1] - c_sorTolerance;
+ }
+ if( m_point[0] < 0.0 )
+ m_point[0] = 0.0;
+
+ if( m_pPrev && !m_pPrev->m_pPrev )
+ {
+ m_pPrev->m_point = m_point + m_pPrev->m_original2DPoint
+ - m_original2DPoint;
+ m_pPrev->setChanged( );
+ }
+ if( m_pNext && !m_pNext->m_pNext )
+ {
+ m_pNext->m_point = m_point + m_pNext->m_original2DPoint
+ - m_original2DPoint;
+ m_pNext->setChanged( );
+ }
+}
+
+void PMSorControlPoint::snapToGrid( )
+{
+ int i;
+ double d = moveGrid( );
+ bool diff = false;
+ PMVector change( 2 );
+ PMSorControlPoint* basePoint = 0;
+ PMSorControlPoint* linkedPoint = 0;
+ if( !m_pPrev )
+ basePoint = m_pNext;
+ if( !m_pNext )
+ basePoint = m_pPrev;
+ if( m_pPrev && !m_pPrev->m_pPrev )
+ linkedPoint = m_pPrev;
+ if( m_pNext && !m_pNext->m_pNext )
+ linkedPoint = m_pNext;
+
+ if( basePoint && basePoint->selected( ) )
+ {
+ m_point -= basePoint->m_point;
+ diff = true;
+ }
+
+ if( !approxZero( d ) )
+ {
+ for( i = 0; i < 2; i++ )
+ {
+ change[i] = -m_point[i];
+ m_point[i] = rint( m_point[i] / d ) * d;
+ change[i] += m_point[i];
+ }
+ }
+
+ if( diff )
+ m_point += basePoint->m_point;
+
+ if( linkedPoint )
+ {
+ linkedPoint->m_point += change;
+ linkedPoint->setChanged( );
+ }
+
+ setChanged( );
+}
+
+PMVector PMSorControlPoint::to2D( const PMVector& v ) const
+{
+ PMVector result( 2 );
+ switch( m_type )
+ {
+ case PM2DXY:
+ result[0] = v[0];
+ result[1] = v[1];
+ break;
+ case PM2DXZ:
+ result[0] = v[0];
+ result[1] = v[2];
+ break;
+ case PM2DYZ:
+ result[0] = v[1];
+ result[1] = v[2];
+ break;
+ case PM2DYX:
+ result[0] = v[1];
+ result[1] = v[0];
+ break;
+ case PM2DZX:
+ result[0] = v[2];
+ result[1] = v[0];
+ break;
+ case PM2DZY:
+ result[0] = v[2];
+ result[1] = v[1];
+ break;
+ }
+ return result;
+}
+
+PMVector PMSorControlPoint::to3D( const PMVector& vec ) const
+{
+ PMVector result( 3 );
+ switch( m_type )
+ {
+ case PM2DXY:
+ result[0] = vec[0];
+ result[1] = vec[1];
+ result[2] = 0.0;
+ break;
+ case PM2DXZ:
+ result[0] = vec[0];
+ result[1] = 0.0;
+ result[2] = vec[1];
+ break;
+ case PM2DYZ:
+ result[0] = 0.0;
+ result[1] = vec[0];
+ result[2] = vec[1];
+ break;
+ case PM2DYX:
+ result[1] = vec[0];
+ result[0] = vec[1];
+ result[2] = 0.0;
+ break;
+ case PM2DZX:
+ result[2] = vec[0];
+ result[0] = vec[1];
+ result[1] = 0.0;
+ break;
+ case PM2DZY:
+ result[2] = vec[0];
+ result[1] = vec[1];
+ result[0] = 0.0;
+ break;
+ }
+ return result;
+}
+
+bool PMSorControlPoint::hasExtraLine( ) const
+{
+ return( !m_pPrev || !m_pNext );
+}
+
+PMVector PMSorControlPoint::extraLineStart( ) const
+{
+ return position( );
+}
+
+PMVector PMSorControlPoint::extraLineEnd( ) const
+{
+ if( !m_pPrev && m_pNext )
+ return m_pNext->position( );
+ if( m_pPrev && !m_pNext )
+ return m_pPrev->position( );
+ return PMVector( 0, 0, 0 );
+}
diff --git a/kpovmodeler/pmsorcontrolpoint.h b/kpovmodeler/pmsorcontrolpoint.h
new file mode 100644
index 00000000..0d9ec283
--- /dev/null
+++ b/kpovmodeler/pmsorcontrolpoint.h
@@ -0,0 +1,99 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMSORCONTROLPOINT_H
+#define PMSORCONTROLPOINT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmcontrolpoint.h"
+
+const double c_sorTolerance = 0.0001;
+
+/**
+ * Class for free moveable control points
+ */
+class PMSorControlPoint : public PMControlPoint
+{
+public:
+ /**
+ * Type enum
+ */
+ enum CPType { PM2DXY, PM2DYX, PM2DXZ, PM2DZX, PM2DYZ, PM2DZY };
+ /**
+ * Creates a PMSorControlPoint with id. Point has to be a 2D vector.
+ */
+ PMSorControlPoint( PMSorControlPoint* prev,
+ const PMVector& point, CPType type,
+ int id, const QString& description );
+ /**
+ * Deletes the PMSorControlPoint
+ */
+ virtual ~PMSorControlPoint( ) { };
+
+ /** */
+ virtual PMVector position( ) const { return to3D( m_point ); }
+ /**
+ * Sets the 2d coordinates of the control point
+ */
+ void setPoint( const PMVector& newPoint ) { m_point = newPoint; }
+ /**
+ * 2d coordinates of the control point
+ */
+ PMVector point( ) const { return m_point; }
+ /**
+ * This method is used by the sor object to link
+ * the control points in the xy and xz plane. These points are
+ * synchronized if both are selected.
+ */
+ void setSorLink( PMSorControlPoint* p ) { m_pSorLink = p; }
+ /**
+ * Returns the linked control point for lathe points
+ */
+ PMSorControlPoint* sorLink( ) const { return m_pSorLink; }
+ /** */
+ virtual void snapToGrid( );
+
+ /** */
+ virtual bool hasExtraLine( ) const;
+ /** */
+ virtual PMVector extraLineStart( ) const;
+ /** */
+ virtual PMVector extraLineEnd( ) const;
+
+protected:
+ /** */
+ virtual void graphicalChangeStarted( );
+ /** */
+ virtual void graphicalChange( const PMVector& startPoint,
+ const PMVector& viewNormal,
+ const PMVector& endPoint );
+private:
+ PMVector to2D( const PMVector& v ) const;
+ PMVector to3D( const PMVector& v ) const;
+
+ PMVector m_point, m_originalPoint, m_original2DPoint;
+ CPType m_type;
+ PMSorControlPoint* m_pPrev;
+ PMSorControlPoint* m_pNext;
+ PMSorControlPoint* m_pSorLink;
+};
+
+#endif
diff --git a/kpovmodeler/pmsoredit.cpp b/kpovmodeler/pmsoredit.cpp
new file mode 100644
index 00000000..b56949e6
--- /dev/null
+++ b/kpovmodeler/pmsoredit.cpp
@@ -0,0 +1,282 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmsoredit.h"
+#include "pmsor.h"
+#include "pmvectorlistedit.h"
+#include "pmpart.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qtooltip.h>
+#include <qcombobox.h>
+#include <qcheckbox.h>
+#include <qpushbutton.h>
+#include <klocale.h>
+#include <kdialog.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+
+PMSurfaceOfRevolutionEdit::PMSurfaceOfRevolutionEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMSurfaceOfRevolutionEdit::createBottomWidgets( )
+{
+ topLayout( )->addWidget( new QLabel( i18n( "Spline points:" ), this ) );
+
+ m_pPoints = new PMVectorListEdit( "u", "v", this );
+ connect( m_pPoints, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pPoints, SIGNAL( selectionChanged( ) ),
+ SLOT( slotSelectionChanged( ) ) );
+ QHBoxLayout* hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( m_pPoints, 2 );
+
+ m_pAddAbove = new QPushButton( this );
+ m_pAddAbove->setPixmap( SmallIcon( "pmaddpointabove" ) );
+ m_pAddBelow = new QPushButton( this );
+ m_pAddBelow->setPixmap( SmallIcon( "pmaddpoint" ) );
+ m_pRemove = new QPushButton( this );
+ m_pRemove->setPixmap( SmallIcon( "pmremovepoint" ) );
+ connect( m_pAddAbove, SIGNAL( clicked( ) ), SLOT( slotAddPointAbove( ) ) );
+ connect( m_pAddBelow, SIGNAL( clicked( ) ), SLOT( slotAddPointBelow( ) ) );
+ connect( m_pRemove, SIGNAL( clicked( ) ), SLOT( slotRemovePoint( ) ) );
+
+ QVBoxLayout* bl = new QVBoxLayout( hl );
+ bl->addWidget( m_pAddAbove );
+ bl->addWidget( m_pAddBelow );
+ bl->addWidget( m_pRemove );
+ bl->addStretch( 1 );
+
+ m_pOpen = new QCheckBox( i18n( "type of the object", "Open" ), this );
+ topLayout( )->addWidget( m_pOpen );
+ connect( m_pOpen, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ m_pSturm = new QCheckBox( i18n( "Sturm" ), this );
+ topLayout( )->addWidget( m_pSturm );
+ connect( m_pSturm, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+
+ Base::createBottomWidgets( );
+}
+
+void PMSurfaceOfRevolutionEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "SurfaceOfRevolution" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMSurfaceOfRevolution* ) o;
+
+ m_pOpen->setChecked( m_pDisplayedObject->open( ) );
+ m_pOpen->setEnabled( !readOnly );
+ m_pSturm->setChecked( m_pDisplayedObject->sturm( ) );
+ m_pSturm->setEnabled( !readOnly );
+ m_pPoints->setVectors( m_pDisplayedObject->points( ), true );
+ updateControlPointSelection( );
+ updatePointButtons( );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMSurfaceOfRevolutionEdit: Can't display object\n";
+}
+
+void PMSurfaceOfRevolutionEdit::updateControlPointSelection( )
+{
+ PMControlPointList cp = part( )->activeControlPoints( );
+ PMControlPointListIterator it( cp );
+ int i;
+ int np = cp.count( ) / 2;
+
+ if( np == m_pPoints->size( ) )
+ {
+ m_pPoints->blockSelectionUpdates( true );
+ bool sb = m_pPoints->signalsBlocked( );
+ m_pPoints->blockSignals( true );
+
+ m_pPoints->clearSelection( );
+ for( i = 0; i < np; i++, ++it )
+ if( ( *it )->selected( ) )
+ m_pPoints->select( i );
+ for( i = 0; i < np; i++, ++it )
+ if( ( *it )->selected( ) )
+ m_pPoints->select( i );
+
+ m_pPoints->blockSignals( sb );
+ m_pPoints->blockSelectionUpdates( false );
+ }
+}
+
+void PMSurfaceOfRevolutionEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ m_pDisplayedObject->setPoints( m_pPoints->vectors( ) );
+ m_pDisplayedObject->setOpen( m_pOpen->isChecked( ) );
+ m_pDisplayedObject->setSturm( m_pSturm->isChecked( ) );
+ Base::saveContents( );
+ }
+}
+
+bool PMSurfaceOfRevolutionEdit::isDataValid( )
+{
+ if( !m_pPoints->isDataValid( ) )
+ return false;
+
+ int np = m_pPoints->size( );
+ if( np < 4 )
+ {
+ KMessageBox::error( this, i18n( "The surface of revolution object needs at least 4 points." ),
+ i18n( "Error" ) );
+ return false;
+ }
+
+ QValueList<PMVector> points = m_pPoints->vectors( );
+ QValueListIterator<PMVector> it1 = points.begin( );
+ QValueListIterator<PMVector> it2 = it1; ++it2;
+ QValueListIterator<PMVector> it3 = it2; ++it3;
+ int pnr;
+
+ for( pnr = 0; it3 != points.end( ); ++it1, ++it2, ++it3, pnr++ )
+ {
+ if( ( pnr == 0 ) || ( pnr == ( np - 3 ) ) )
+ {
+ if( approxZero( ( *it1 )[1] - ( *it3 )[1], c_sorTolerance ) )
+ {
+ m_pPoints->setCurrentCell( pnr, 1 );
+ KMessageBox::error( this, i18n( "The v coordinate of point %1 and %2 must be different." )
+ .arg( pnr + 1 ).arg( pnr + 3 ),
+ i18n( "Error" ) );
+ return false;
+ }
+ }
+
+ if( pnr != 0 )
+ {
+ if( ( ( *it2 )[1] - ( *it1 )[1] ) < c_sorTolerance )
+ {
+ m_pPoints->setCurrentCell( pnr + 1, 1 );
+ KMessageBox::error( this, i18n( "The v coordinates must be strictly increasing." ),
+ i18n( "Error" ) );
+ return false;
+ }
+ }
+ }
+
+ return Base::isDataValid( );
+}
+
+void PMSurfaceOfRevolutionEdit::slotAddPointAbove( )
+{
+ int index = m_pPoints->currentRow( );
+ if( index >= 0 )
+ {
+ QValueList<PMVector> points = m_pPoints->vectors( );
+ QValueListIterator<PMVector> it = points.at( index );
+
+ if( it != points.end( ) )
+ {
+ QValueListIterator<PMVector> it2 = it;
+ it2--;
+ PMVector v;
+ if( it2 == points.end( ) )
+ v = *it;
+ else
+ v = ( *it + *it2 ) / 2;
+
+ points.insert( it, v );
+ m_pPoints->setVectors( points, true );
+ updatePointButtons( );
+ emit dataChanged( );
+ }
+ }
+}
+
+void PMSurfaceOfRevolutionEdit::slotAddPointBelow( )
+{
+ int index = m_pPoints->currentRow( );
+ if( index >= 0 )
+ {
+ QValueList<PMVector> points = m_pPoints->vectors( );
+ QValueListIterator<PMVector> it = points.at( index );
+
+ if( it != points.end( ) )
+ {
+ QValueListIterator<PMVector> it2 = it;
+ it2++;
+ PMVector v;
+ if( it2 == points.end( ) )
+ v = *it;
+ else
+ v = ( *it + *it2 ) / 2;
+
+ points.insert( it2, v );
+ m_pPoints->setVectors( points, true );
+ m_pPoints->setCurrentCell( index + 1, m_pPoints->currentColumn( ) );
+ updatePointButtons( );
+ emit dataChanged( );
+ }
+ }
+}
+
+void PMSurfaceOfRevolutionEdit::slotRemovePoint( )
+{
+ int row = m_pPoints->currentRow( );
+
+ if( row >= 0 )
+ {
+ QValueList<PMVector> points = m_pPoints->vectors( );
+ QValueListIterator<PMVector> it = points.at( row );
+
+ if( it != points.end( ) && points.size( ) > 1 )
+ {
+ points.remove( it );
+ m_pPoints->setVectors( points, true );
+ updatePointButtons( );
+ emit dataChanged( );
+ }
+ }
+}
+
+void PMSurfaceOfRevolutionEdit::slotSelectionChanged( )
+{
+ PMControlPointList cp = part( )->activeControlPoints( );
+ PMControlPointListIterator it( cp );
+ int np = cp.count( ) / 2;
+ int i;
+
+ if( np == m_pPoints->size( ) )
+ {
+ for( i = 0; i < np; i++, ++it )
+ ( *it )->setSelected( m_pPoints->isSelected( i ) );
+ for( i = 0; i < np; i++, ++it )
+ ( *it )->setSelected( m_pPoints->isSelected( i ) );
+ emit controlPointSelectionChanged( );
+ }
+ updatePointButtons( );
+}
+
+void PMSurfaceOfRevolutionEdit::updatePointButtons( )
+{
+ int row = m_pPoints->currentRow( );
+ m_pAddAbove->setEnabled( row >= 0 );
+ m_pAddBelow->setEnabled( row >= 0 );
+ m_pRemove->setEnabled( row >= 0 && m_pPoints->size( ) > 4 );
+}
+
+#include "pmsoredit.moc"
diff --git a/kpovmodeler/pmsoredit.h b/kpovmodeler/pmsoredit.h
new file mode 100644
index 00000000..eb64be67
--- /dev/null
+++ b/kpovmodeler/pmsoredit.h
@@ -0,0 +1,86 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMSOREDIT_H
+#define PMSOREDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobjectedit.h"
+#include "pmvectoredit.h"
+#include <qptrlist.h>
+#include <qvaluelist.h>
+
+class PMSurfaceOfRevolution;
+class QVBoxLayout;
+class QComboBox;
+class QCheckBox;
+class QPushButton;
+class QLabel;
+class PMVectorListEdit;
+
+/**
+ * Dialog edit class for @ref PMSurfaceOfRevolution
+ */
+class PMSurfaceOfRevolutionEdit : public PMSolidObjectEdit
+{
+ Q_OBJECT
+ typedef PMSolidObjectEdit Base;
+public:
+ /**
+ * Creates a PMSurfaceOfRevolutionEdit with parent and name
+ */
+ PMSurfaceOfRevolutionEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+ /** */
+ virtual void updateControlPointSelection( );
+
+ /** */
+ virtual bool isDataValid( );
+
+protected:
+ /** */
+ virtual void createBottomWidgets( );
+ /** */
+ virtual void saveContents( );
+
+protected slots:
+ void slotAddPointAbove( );
+ void slotAddPointBelow( );
+ void slotRemovePoint( );
+ void slotSelectionChanged( );
+
+private:
+ void updatePointButtons( );
+
+ PMSurfaceOfRevolution* m_pDisplayedObject;
+ PMVectorListEdit* m_pPoints;
+ QCheckBox* m_pOpen;
+ QCheckBox* m_pSturm;
+ QPushButton* m_pAddAbove;
+ QPushButton* m_pAddBelow;
+ QPushButton* m_pRemove;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmsorsegment.cpp b/kpovmodeler/pmsorsegment.cpp
new file mode 100644
index 00000000..966beb2b
--- /dev/null
+++ b/kpovmodeler/pmsorsegment.cpp
@@ -0,0 +1,97 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmsorsegment.h"
+#include "pmmath.h"
+#include "pmmatrix.h"
+#include "pmdebug.h"
+#include <math.h>
+
+PMVector PMSorSegment::point( double t ) const
+{
+ t = m_t + t * m_s;
+ double r2 = t * ( t * ( t * m_a + m_b ) + m_c ) + m_d;
+ if( r2 < 0.0 )
+ r2 = 0.0;
+
+ return PMVector( sqrt( r2 ), t );
+}
+
+void PMSorSegment::calculateSor( const PMVector& p0, const PMVector& p1,
+ const PMVector& p2, const PMVector& p3 )
+{
+ double b[4], h;
+ PMMatrix m;
+
+ m_t = p1[1];
+ m_s = p2[1] - p1[1];
+
+ if( approxZero( p2[1] - p0[1] ) || approxZero( p3[1] - p1[1] ) )
+ {
+ kdError( PMArea ) << "Incorrect points in PMSorSegment::calculateSor\n";
+ m_a = m_b = m_c = m_d = 0.0;
+ return;
+ }
+
+ // interpolate the points
+ // see povray documentation
+
+ b[0] = p1[0] * p1[0];
+ b[1] = p2[0] * p2[0];
+ b[2] = 2.0 * p1[0] * ( p2[0] - p0[0] ) / ( p2[1] - p0[1] );
+ b[3] = 2.0 * p2[0] * ( p3[0] - p1[0] ) / ( p3[1] - p1[1] );
+
+ h = p1[1];
+
+ m[0][0] = h * h * h;
+ m[0][1] = h * h;
+ m[0][2] = h;
+ m[0][3] = 1.0;
+
+ m[2][0] = 3.0 * h * h;
+ m[2][1] = 2.0 * h;
+ m[2][2] = 1.0;
+ m[2][3] = 0.0;
+
+ h = p2[1];
+
+ m[1][0] = h * h * h;
+ m[1][1] = h * h;
+ m[1][2] = h;
+ m[1][3] = 1.0;
+
+ m[3][0] = 3.0 * h * h;
+ m[3][1] = 2.0 * h;
+ m[3][2] = 1.0;
+ m[3][3] = 0.0;
+
+ // Calculate the coefficients
+ // x = M^-1 * b;
+
+ m = m.inverse( );
+
+ m_a = b[0] * m[0][0] + b[1] * m[0][1] + b[2] * m[0][2] + b[3] * m[0][3];
+ m_b = b[0] * m[1][0] + b[1] * m[1][1] + b[2] * m[1][2] + b[3] * m[1][3];
+ m_c = b[0] * m[2][0] + b[1] * m[2][1] + b[2] * m[2][2] + b[3] * m[2][3];
+ m_d = b[0] * m[3][0] + b[1] * m[3][1] + b[2] * m[3][2] + b[3] * m[3][3];
+
+ if( approxZero( m_a ) ) m_a = 0.0;
+ if( approxZero( m_b ) ) m_b = 0.0;
+ if( approxZero( m_c ) ) m_c = 0.0;
+ if( approxZero( m_d ) ) m_d = 0.0;
+}
diff --git a/kpovmodeler/pmsorsegment.h b/kpovmodeler/pmsorsegment.h
new file mode 100644
index 00000000..f0c5a2ea
--- /dev/null
+++ b/kpovmodeler/pmsorsegment.h
@@ -0,0 +1,77 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMSORSEGMENT_H
+#define PMSORSEGMENT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmvector.h"
+
+/**
+ * Helper class for sors
+ *
+ * Each instance of this class represents one sor segment. A point
+ * on the segment is given by the equation
+ *
+ * fi(t) = A[i] * t^3 + B[i] * t^2 + C[i] * t + D[i]
+ *
+ * with t ranging from 0 to 1.
+ */
+class PMSorSegment
+{
+public:
+ /**
+ * Standard constructor
+ */
+ PMSorSegment( )
+ {
+ m_a = m_b = m_c = m_d = 0.0;
+ }
+ /**
+ * Constructor that calculates the segment
+ */
+ PMSorSegment( const PMVector& p0, const PMVector& p1,
+ const PMVector& p2, const PMVector& p3 )
+ {
+ calculateSor( p0, p1, p2, p3 );
+ }
+
+ /**
+ * Returns a 2D vector with the point on the sor segment
+ */
+ PMVector point( double t ) const;
+ /**
+ * Returns the gradient on the sor
+ */
+ //PMVector gradient( double t ) const;
+
+ /**
+ * Calculates the sor parameters
+ */
+ void calculateSor( const PMVector& p0, const PMVector& p1,
+ const PMVector& p2, const PMVector& p3 );
+private:
+ double m_a, m_b, m_c, m_d;
+ double m_t, m_s;
+};
+
+#endif
diff --git a/kpovmodeler/pmsphere.cpp b/kpovmodeler/pmsphere.cpp
new file mode 100644
index 00000000..698b5352
--- /dev/null
+++ b/kpovmodeler/pmsphere.cpp
@@ -0,0 +1,411 @@
+/*
+**************************************************************************
+ pmsphere.cpp - description
+ -------------------
+ copyright : (C) 2001 by Philippe Van Hecke
+ email : lephiloux@tiscalinet.be
+ copyright : (C) 2001-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmsphere.h"
+
+#include "pmxmlhelper.h"
+#include "pmsphereedit.h"
+#include "pmmemento.h"
+#include "pm3dcontrolpoint.h"
+#include "pmdistancecontrolpoint.h"
+#include "pmdefaults.h"
+
+#include <klocale.h>
+
+/** default param for the sphere */
+const double c_defaultRadius = 0.5;
+const PMVector c_defaultCentre = PMVector( 0, 0, 0 );
+
+/** default sphere structure */
+PMViewStructure* PMSphere::s_pDefaultViewStructure = 0;
+
+int PMSphere::s_vStep = c_defaultSphereVSteps;
+int PMSphere::s_uStep = c_defaultSphereUSteps;
+int PMSphere::s_parameterKey = 0;
+
+PMDefinePropertyClass( PMSphere, PMSphereProperty );
+
+PMMetaObject* PMSphere::s_pMetaObject = 0;
+PMObject* createNewSphere( PMPart* part )
+{
+ return new PMSphere( part );
+}
+
+PMSphere::PMSphere( PMPart* part )
+ : Base( part )
+{
+ m_radius = c_defaultRadius;
+ m_centre = c_defaultCentre;
+}
+
+PMSphere::PMSphere( const PMSphere& s )
+ : Base( s )
+{
+ m_radius = s.m_radius;
+ m_centre = s.m_centre;
+}
+
+PMSphere::~PMSphere( )
+{
+}
+
+
+QString PMSphere::description( ) const
+{
+ return i18n( "sphere" );
+}
+
+PMMetaObject* PMSphere::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Sphere", Base::metaObject( ),
+ createNewSphere );
+ s_pMetaObject->addProperty(
+ new PMSphereProperty( "radius", &PMSphere::setRadius, &PMSphere::radius ) );
+ s_pMetaObject->addProperty(
+ new PMSphereProperty( "center", &PMSphere::setCentre, &PMSphere::centre ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMSphere::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "centre", m_centre.serializeXML( ) );
+ e.setAttribute( "radius", m_radius );
+ Base::serialize( e, doc );
+}
+
+void PMSphere::readAttributes( const PMXMLHelper& h )
+{
+ m_centre = h.vectorAttribute( "centre", c_defaultCentre );
+ m_radius = h.doubleAttribute( "radius", c_defaultRadius );
+ Base::readAttributes( h );
+}
+
+PMDialogEditBase* PMSphere::editWidget( QWidget* parent ) const
+{
+
+ return new PMSphereEdit( parent );
+}
+
+void PMSphere::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMRadiusID:
+ setRadius( data->doubleData( ) );
+ break;
+ case PMCentreID:
+ setCentre( data->vectorData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PSphere::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+
+}
+
+void PMSphere::controlPoints( PMControlPointList& list )
+{
+ PM3DControlPoint* p = new PM3DControlPoint( m_centre, PMCentreID,
+ i18n( "Center" ) );
+ list.append( p );
+ list.append( new PMDistanceControlPoint( p, PMVector( 1.0, 0.0, 0.0 ),
+ m_radius, PMRadiusID,
+ i18n( "Radius (x)" ) ) );
+ list.append( new PMDistanceControlPoint( p, PMVector( 0.0, 1.0, 0.0 ),
+ m_radius, PMRadiusID,
+ i18n( "Radius (y)" ) ) );
+ list.append( new PMDistanceControlPoint( p, PMVector( 0.0, 0.0, 1.0 ),
+ m_radius, PMRadiusID,
+ i18n( "Radius (z)" ) ) );
+}
+
+void PMSphere::controlPointsChanged( PMControlPointList& list )
+{
+ PMControlPoint* p;
+ bool radiusChanged = false;
+
+ for( p = list.first( ); p; p = list.next( ) )
+ {
+ if( p->changed( ) )
+ {
+ switch( p->id( ) )
+ {
+ case PMCentreID:
+ setCentre( ( ( PM3DControlPoint* ) p )->point( ) );
+ break;
+ case PMRadiusID:
+ setRadius( ( ( PMDistanceControlPoint* ) p )->distance( ) );
+ radiusChanged = true;
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMSphere::controlPointsChanged\n";
+ break;
+ }
+ }
+ }
+
+ if( radiusChanged )
+ for( p = list.first( ); p; p = list.next( ) )
+ if( p->id( ) == PMRadiusID )
+ ( ( PMDistanceControlPoint* ) p )->setDistance( m_radius );
+}
+
+bool PMSphere::isDefault( )
+{
+ if( ( m_radius == c_defaultRadius ) && ( m_centre == c_defaultCentre ) && globalDetail( ) )
+ return true;
+ return false;
+}
+
+void PMSphere::createViewStructure( )
+{
+ if( !m_pViewStructure )
+ {
+ m_pViewStructure = new PMViewStructure( defaultViewStructure( ) );
+ m_pViewStructure->points( ).detach( );
+ }
+
+ int uStep = (int)( ( (float)s_uStep / 2 ) * ( displayDetail( ) + 1 ) );
+ int vStep = (int)( ( (float)s_vStep / 2 ) * ( displayDetail( ) + 1 ) );
+ unsigned ptsSize = vStep * ( uStep - 1 ) + 2;
+ unsigned lineSize = vStep * ( uStep - 1 ) * 2 + vStep;
+ unsigned faceSize = vStep * uStep;
+
+ if( ptsSize != m_pViewStructure->points( ).size( ) )
+ m_pViewStructure->points( ).resize( ptsSize );
+
+ createPoints( m_pViewStructure->points( ), m_centre, m_radius, uStep, vStep );
+
+ if( lineSize != m_pViewStructure->lines( ).size( ) )
+ {
+ m_pViewStructure->lines( ).detach( );
+ m_pViewStructure->lines( ).resize( lineSize );
+ createLines( m_pViewStructure->lines( ), uStep, vStep );
+ }
+
+ if( faceSize != m_pViewStructure->faces( ).size( ) )
+ {
+ m_pViewStructure->faces( ).resize( faceSize );
+ createFaces( m_pViewStructure->faces( ), uStep, vStep );
+ }
+}
+
+PMViewStructure* PMSphere::defaultViewStructure( ) const
+{
+ if( !s_pDefaultViewStructure || s_pDefaultViewStructure->parameterKey( ) != viewStructureParameterKey( ) )
+ {
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ int uStep = (int)( ( (float)s_uStep / 2 ) * ( globalDetailLevel( ) + 1 ) );
+ int vStep = (int)( ( (float)s_vStep / 2 ) * ( globalDetailLevel( ) + 1 ) );
+
+ s_pDefaultViewStructure =
+ new PMViewStructure( vStep * ( uStep - 1 ) + 2,
+ vStep * ( uStep - 1 ) * 2 + vStep,
+ vStep * uStep );
+
+ // points
+ createPoints( s_pDefaultViewStructure->points( ), c_defaultCentre,
+ c_defaultRadius, uStep, vStep );
+ //lines
+ createLines( s_pDefaultViewStructure->lines( ), uStep, vStep );
+
+ //faces
+ createFaces( s_pDefaultViewStructure->faces( ), uStep, vStep );
+ }
+
+ return s_pDefaultViewStructure;
+}
+
+void PMSphere::createFaces( PMFaceArray& faces, int uStep, int vStep )
+{
+ int u, v, offsetPt1, offsetPt2, offsetFace;
+
+ offsetPt1 = vStep * ( uStep - 1 ) + 1;
+ offsetPt2 = vStep * ( uStep - 2 ) + 1;
+ offsetFace = vStep * ( uStep - 1 );
+ for( v = 0; v < vStep - 1; ++v )
+ {
+ faces[v] = PMFace( 0, v + 2, v + 1 );
+ faces[ offsetFace + v ] = PMFace( offsetPt1, v + offsetPt2, v + offsetPt2 + 1 );
+ }
+
+ faces[ vStep - 1 ] = PMFace( 0, 1, vStep );
+ faces[ offsetFace + vStep - 1 ] = PMFace( offsetPt1, vStep + offsetPt2 - 1, offsetPt2 );
+
+ offsetFace = vStep;
+ for( u = 0; u < ( uStep - 2 ); ++u )
+ {
+ offsetPt1 = ( u * vStep ) + 1;
+ offsetPt2 = ( ( u + 1 ) * vStep ) + 1;
+ for( v = 0; v < ( vStep - 1 ); ++v )
+ faces[ offsetFace + v ] = PMFace( v + offsetPt1, v + offsetPt1 + 1, v + offsetPt2 + 1, v + offsetPt2 );
+ faces[ offsetFace + vStep - 1 ] = PMFace( offsetPt1 + vStep - 1, offsetPt1, offsetPt2, offsetPt2 + vStep - 1 );
+ offsetFace += vStep;
+ }
+}
+
+void PMSphere::createLines( PMLineArray& lines, int uStep, int vStep )
+{
+ int u, v;
+ int offset = 0;
+
+ // horizontal lines
+ for( u = 0; u < ( uStep - 1 ); u++ )
+ {
+ for( v = 0; v < ( vStep - 1 ); v++ )
+ lines[offset + v] =
+ PMLine( u * vStep + v + 1, u * vStep + v + 2 );
+ lines[offset + vStep - 1] =
+ PMLine( u * vStep + 1, u * vStep + vStep );
+
+ offset += vStep;
+ }
+
+ // vertical lines
+ // lines at the "north pole"
+ for( v = 0; v < vStep; v++ )
+ lines[offset + v] = PMLine( 0, v + 1 );
+ offset += vStep;
+
+ for( v = 0; v < vStep; v++ )
+ {
+ for( u = 0; u < ( uStep - 2 ); u++ )
+ {
+ lines[offset + u] =
+ PMLine( u * vStep + v + 1, ( u + 1 ) * vStep + v + 1 );
+ }
+ offset += ( uStep - 2 );
+ }
+ // lines at the "south pole"
+ for( v = 0; v < vStep; v++ )
+ lines[offset + v] = PMLine( ( uStep - 2 ) * vStep + v + 1,
+ ( uStep - 1 ) * vStep + 1 );
+ // offset += s_vStep;
+}
+
+void PMSphere::createPoints( PMPointArray& points, const PMVector& centre, double radius,
+ int uStep, int vStep )
+{
+ double l_UradStep = M_PI / uStep;
+ double l_VradStep = ( 2.0 * M_PI ) / vStep;
+ double l_u = l_UradStep;
+ int u, v;
+
+ points[0] = PMPoint( centre + PMVector( 0, radius, 0 ) );
+ points[ vStep * ( uStep - 1 ) + 1] = PMPoint( centre - PMVector( 0, radius, 0 ) );
+
+ for( u = 0; u < ( uStep - 1 ); u++ )
+ {
+ double l_v = 0.0;
+ double l_rcosu = radius * sin( l_u );
+ double y = ( radius * cos( l_u ) ) + centre[1];
+ for( v = 0; v < vStep ; v++ )
+ {
+
+ double x = ( l_rcosu * cos( l_v ) ) + centre[0];
+ double z = ( l_rcosu * sin( l_v ) ) + centre[2];
+
+ points[u * vStep + v + 1] = PMPoint( x, y, z );
+ l_v = l_v + l_VradStep;
+ }
+ l_u = l_u + l_UradStep;
+ }
+}
+
+void PMSphere::setRadius( double radius )
+{
+ if( m_radius != radius )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMRadiusID, m_radius );
+ m_radius = radius;
+ setViewStructureChanged( );
+ }
+}
+
+void PMSphere::setCentre( const PMVector& centre )
+{
+ if( m_centre != centre )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMCentreID, m_centre );
+ m_centre = centre;
+ setViewStructureChanged( );
+ }
+}
+
+void PMSphere::setUSteps( int u )
+{
+ if( u >= 2 )
+ {
+ s_uStep = u;
+ if( s_pDefaultViewStructure )
+ {
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ }
+ }
+ else
+ kdDebug( PMArea ) << "PMSPhere::setUSteps: U must be greater than 1\n";
+ s_parameterKey++;
+}
+
+void PMSphere::setVSteps( int v )
+{
+ if( v >= 4 )
+ {
+ s_vStep = v;
+ if( s_pDefaultViewStructure )
+ {
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ }
+ }
+ else
+ kdDebug( PMArea ) << "PMSphere::setVSteps: V must be greater than 3\n";
+ s_parameterKey++;
+}
+
+void PMSphere::cleanUp( ) const
+{
+ if( s_pDefaultViewStructure )
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
diff --git a/kpovmodeler/pmsphere.h b/kpovmodeler/pmsphere.h
new file mode 100644
index 00000000..876fd103
--- /dev/null
+++ b/kpovmodeler/pmsphere.h
@@ -0,0 +1,165 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ pmsphere.h - description
+ -------------------
+ copyright : (C) 2001 by Philippe Van Hecke
+ email : lephiloux@tiscalinet.be
+ and : (C) 2001-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMSPHERE_H
+#define PMSPHERE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobject.h"
+#include "pmvector.h"
+#include "pmviewstructure.h"
+
+/**
+ * Class for povray sphere.
+ */
+class PMSphere : public PMSolidObject
+{
+ typedef PMSolidObject Base;
+
+public:
+ /**
+ * Create an empty Sphere
+ */
+ PMSphere( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMSphere( const PMSphere& s );
+ /**
+ * Delete the PMSphere
+ */
+ virtual ~PMSphere( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMSphere( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMSphereEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmsphere" ); }
+
+ /**
+ * Returns the centre of the sphere
+ */
+ PMVector centre( ) const { return m_centre; }
+ /**
+ * Set the centre of the sphere
+ */
+ void setCentre( const PMVector& centre );
+ /**
+ * returns the radius of the sphere
+ */
+ double radius( ) const { return m_radius; }
+ /**
+ * Sets the radius of the sphere
+ */
+ void setRadius( double radius );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /** */
+ virtual void controlPoints( PMControlPointList& list );
+ /** */
+ virtual void controlPointsChanged( PMControlPointList& list );
+ /** */
+ virtual bool hasDisplayDetail( ) const { return true; }
+
+ /**
+ * Sets the number of latitutes
+ */
+ static void setUSteps( int u );
+ /**
+ * Sets the number of longitudes
+ */
+ static void setVSteps( int v );
+ /**
+ * Returns the number or latitutes
+ */
+ static int uSteps( ) { return s_uStep; }
+ /**
+ * Returns the number or longitudes
+ */
+ static int vSteps( ) { return s_vStep; }
+ /** */
+ virtual void cleanUp( ) const;
+
+protected:
+ /** */
+ virtual bool isDefault( );
+ /** */
+ virtual void createViewStructure( );
+ /** */
+ virtual PMViewStructure* defaultViewStructure( ) const;
+ /** */
+ virtual int viewStructureParameterKey( ) const { return s_parameterKey + globalDetailKey(); }
+
+private:
+ /**
+ * Creates the faces for the view structure
+ */
+ static void createFaces( PMFaceArray& faces, int uStep, int vStep );
+ /**
+ * Creates the lines for the view structure
+ */
+ static void createLines( PMLineArray& lines, int uStep, int vStep );
+ /**
+ * Creates the points for the view structure
+ */
+ static void createPoints( PMPointArray& points, const PMVector& centre,
+ double radius, int uStep, int vStep );
+
+ enum PMSphereMementoID { PMRadiusID, PMCentreID };
+ /**
+ * Radius of the sphere
+ */
+ double m_radius;
+ /**
+ * centre of the sphere
+ */
+ PMVector m_centre;
+
+ static PMViewStructure* s_pDefaultViewStructure;
+ static int s_vStep;
+ static int s_uStep;
+ static int s_parameterKey;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmsphereedit.cpp b/kpovmodeler/pmsphereedit.cpp
new file mode 100644
index 00000000..cb46d513
--- /dev/null
+++ b/kpovmodeler/pmsphereedit.cpp
@@ -0,0 +1,95 @@
+/*
+**************************************************************************
+
+ pmsphereedit.cpp - description
+ -------------------
+ begin : Wed Jun 6 2001
+ copyright : (C) 2001 by Philippe Van Hecke
+ email : lephiloux@tiscalinet.be
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#include "pmsphereedit.h"
+#include "pmsphere.h"
+#include "pmvectoredit.h"
+#include "pmlineedits.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <klocale.h>
+
+PMSphereEdit::PMSphereEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMSphereEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* layout;
+
+ m_pCentre = new PMVectorEdit( "x", "y", "z", this );
+ m_pRadius = new PMFloatEdit( this );
+
+ layout = new QHBoxLayout( topLayout( ) );
+ layout->addWidget( new QLabel( i18n( "Center:" ), this ) );
+ layout->addWidget( m_pCentre );
+
+ layout = new QHBoxLayout( topLayout( ) );
+ layout->addWidget( new QLabel( i18n( "Radius:" ), this ) );
+ layout->addWidget( m_pRadius );
+ layout->addStretch( 1 );
+
+ connect( m_pCentre, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pRadius, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMSphereEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Sphere" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMSphere* ) o;
+
+ m_pCentre->setVector( m_pDisplayedObject->centre( ) );
+ m_pRadius->setValue( m_pDisplayedObject->radius( ) );
+
+ m_pCentre->setReadOnly( readOnly );
+ m_pRadius->setReadOnly( readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMSphereEdit: Can't display object\n";
+}
+
+void PMSphereEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setCentre( m_pCentre->vector( ) );
+ m_pDisplayedObject->setRadius( m_pRadius->value( ) );
+ }
+}
+
+bool PMSphereEdit::isDataValid( )
+{
+ if( m_pCentre->isDataValid( ) )
+ if( m_pRadius->isDataValid( ) )
+ return Base::isDataValid( );
+ return false;
+}
+
+
+#include "pmsphereedit.moc"
diff --git a/kpovmodeler/pmsphereedit.h b/kpovmodeler/pmsphereedit.h
new file mode 100644
index 00000000..9cd64d86
--- /dev/null
+++ b/kpovmodeler/pmsphereedit.h
@@ -0,0 +1,64 @@
+/*
+**************************************************************************
+
+ pmsphereedit.h - description
+ -------------------
+ begin : Wed Jun 6 2001
+ copyright : (C) 2001 by Philippe Van Hecke
+ email : lephiloux@tiscalinet.be
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#ifndef PMSPHEREEDIT_H
+#define PMSPHEREEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobjectedit.h"
+
+class PMSphere;
+class PMVectorEdit;
+class PMFloatEdit ;
+
+/**
+ * Dialog edit class for @ref PMSphere
+ */
+class PMSphereEdit : public PMSolidObjectEdit
+{
+ Q_OBJECT
+ typedef PMSolidObjectEdit Base;
+public:
+ /**
+ * Creates a PMSphereEdit with parent and name
+ */
+ PMSphereEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMSphere* m_pDisplayedObject;
+ PMVectorEdit* m_pCentre;
+ PMFloatEdit* m_pRadius;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmspheresweep.cpp b/kpovmodeler/pmspheresweep.cpp
new file mode 100644
index 00000000..f65a029e
--- /dev/null
+++ b/kpovmodeler/pmspheresweep.cpp
@@ -0,0 +1,894 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmspheresweep.h"
+
+#include "pmxmlhelper.h"
+#include "pmspheresweepedit.h"
+#include "pmmemento.h"
+#include "pmviewstructure.h"
+#include "pm3dcontrolpoint.h"
+#include "pmdistancecontrolpoint.h"
+#include "pmsplinememento.h"
+#include "pmdefaults.h"
+#include "pmenumproperty.h"
+#include "pmobjectaction.h"
+#include "pmpoint.h"
+#include "pmmatrix.h"
+
+#include <klocale.h>
+
+const int defaultNumberOfPoints = 2;
+const PMVector defaultPoint[defaultNumberOfPoints] =
+{
+ PMVector( 0.0, 1.0, 0.0 ),
+ PMVector( 0.0, 0.0, 0.0 )
+};
+const double defaultRadii[defaultNumberOfPoints] =
+{
+ 0.3, 0.5
+};
+
+const double defaultTolerance = 1e-6;
+const PMSphereSweep::SplineType defaultSplineType = PMSphereSweep::LinearSpline;
+
+PMDefinePropertyClass( PMSphereSweep, PMSphereSweepProperty );
+PMDefineEnumPropertyClass( PMSphereSweep, PMSphereSweep::SplineType, PMSplineTypeProperty );
+
+PMMetaObject* PMSphereSweep::s_pMetaObject = 0;
+PMObject* createNewSphereSweep( PMPart* part )
+{
+ return new PMSphereSweep( part );
+}
+
+int PMSphereSweep::s_rSteps = c_defaultSphereSweepRSteps;
+int PMSphereSweep::s_sSteps = c_defaultSphereSweepSSteps;
+int PMSphereSweep::s_parameterKey = 0;
+
+
+/**
+ * Memento for @ref PMLathe
+ */
+class PMSphereSweepMemento : public PMSplineMemento
+{
+public:
+ /**
+ * Creates a memento for the object originator
+ */
+ PMSphereSweepMemento( PMObject* originator )
+ : PMSplineMemento( originator )
+ {
+ m_bRadiiSaved = false;
+ }
+ /**
+ * Deletes the memento
+ */
+ virtual ~PMSphereSweepMemento( ) { };
+
+ /**
+ * Saves the radii
+ */
+ void setRadii( const QValueList<double>& r )
+ {
+ if( !m_bRadiiSaved )
+ {
+ // Direct assignment does not work with Qt 2.3.x
+ // The list will be changed later in a graphical
+ // change because QValueList::detach( ) is called
+ // too late!
+ // Copy the list by hand.
+
+ QValueList<double>::ConstIterator it = r.begin( );
+ for( ; it != r.end( ); ++it )
+ m_radii.append( *it );
+
+ m_bRadiiSaved = true;
+ addChange( PMCData );
+ }
+ }
+ /**
+ * Returns the radii
+ */
+ QValueList<double> radii( ) const
+ {
+ if( !m_bRadiiSaved )
+ kdError( PMArea ) << "Radii points not saved in PMSphereSweepMemento::radii\n";
+ return m_radii;
+ }
+ /**
+ * Returns true if the spline points were saved
+ */
+ bool radiiSaved( ) const { return m_bRadiiSaved; }
+
+private:
+ /**
+ * The stored radii
+ */
+ QValueList<double> m_radii;
+ bool m_bRadiiSaved;
+};
+
+
+PMSphereSweep::PMSphereSweep( PMPart* part )
+ : Base( part )
+{
+ int i;
+
+ for( i = 0; i < defaultNumberOfPoints; i++ )
+ {
+ m_points.append( defaultPoint[i] );
+ m_radii.append( defaultRadii[i] );
+ }
+ m_splineType = defaultSplineType;
+ m_tolerance = defaultTolerance;
+}
+
+PMSphereSweep::PMSphereSweep( const PMSphereSweep& l )
+ : Base( l )
+{
+ m_points = l.m_points;
+ m_radii = l.m_radii;
+ m_splineType = l.m_splineType;
+ m_tolerance = l.m_tolerance;
+}
+
+PMSphereSweep::~PMSphereSweep( )
+{
+}
+
+QString PMSphereSweep::description( ) const
+{
+ return i18n( "sphere sweep" );
+}
+
+void PMSphereSweep::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ QDomElement data = doc.createElement( "extra_data" );
+ QDomElement p;
+
+ e.setAttribute( "spline_type", m_splineType );
+ e.setAttribute( "tolerance", m_tolerance );
+
+ QValueList<PMVector>::ConstIterator it;
+ QValueList<double>::ConstIterator it2;
+ for( it = m_points.begin( ), it2 = m_radii.begin( );
+ it != m_points.end( ) && it2 != m_radii.end( ); ++it, ++it2 )
+ {
+ p = doc.createElement( "point" );
+ p.setAttribute( "vector", ( *it ).serializeXML( ) );
+ p.setAttribute( "radius", *it2 );
+ data.appendChild( p );
+ }
+
+ e.appendChild( data );
+ Base::serialize( e, doc );
+}
+
+void PMSphereSweep::readAttributes( const PMXMLHelper& h )
+{
+ m_splineType = ( SplineType ) h.intAttribute( "spline_type", defaultSplineType );
+ m_tolerance = h.doubleAttribute( "tolerance", defaultTolerance );
+
+ m_points.clear( );
+ m_radii.clear( );
+ PMVector v( 3 );
+
+ QDomElement e = h.extraData( );
+ if( !e.isNull( ) )
+ {
+ QDomNode c = e.firstChild( );
+ while( !c.isNull( ) )
+ {
+ if( c.isElement( ) )
+ {
+ QDomElement ce = c.toElement( );
+ if( ce.tagName( ) == "point" )
+ {
+ QString str = ce.attribute( "vector" );
+ if( !str.isNull( ) )
+ {
+ v.loadXML( str );
+ m_points.append( v );
+ QString str = ce.attribute( "radius" );
+ m_radii.append( str.toDouble( ) );
+ }
+ }
+ }
+ c = c.nextSibling( );
+ }
+ }
+
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMSphereSweep::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "SphereSweep", Base::metaObject( ),
+ createNewSphereSweep );
+ s_pMetaObject->addProperty(
+ new PMSphereSweepProperty( "tolerance", &PMSphereSweep::setTolerance, &PMSphereSweep::tolerance ) );
+ PMSplineTypeProperty* p = new PMSplineTypeProperty(
+ "splineType", &PMSphereSweep::setSplineType, &PMSphereSweep::splineType );
+ p->addEnumValue( "LinearSpline", LinearSpline );
+ p->addEnumValue( "BSpline", BSpline );
+ p->addEnumValue( "CubicSpline", CubicSpline );
+ s_pMetaObject->addProperty( p );
+ //s_pMetaObject->addProperty( new PMPointProperty( ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMSphereSweep::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMSphereSweep::setSplineType( PMSphereSweep::SplineType t )
+{
+ if( m_splineType != t )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSplineTypeID, ( int ) m_splineType );
+ setViewStructureChanged( );
+ m_splineType = t;
+ }
+}
+
+void PMSphereSweep::setTolerance( double t )
+{
+ if( m_tolerance != t )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMToleranceID, m_tolerance );
+ m_tolerance = t;
+ }
+}
+
+void PMSphereSweep::setPoints( const QValueList<PMVector>& points )
+{
+ if( m_points != points )
+ {
+ if( m_pMemento )
+ ( ( PMSplineMemento* ) m_pMemento )->setSplinePoints( m_points );
+
+ setViewStructureChanged( );
+ m_points = points;
+ }
+}
+
+void PMSphereSweep::setRadii( const QValueList<double>& radii )
+{
+ if( m_radii != radii )
+ {
+ if( m_pMemento )
+ ( ( PMSphereSweepMemento* ) m_pMemento )->setRadii( m_radii );
+
+ setViewStructureChanged( );
+ m_radii = radii;
+ }
+}
+
+PMDialogEditBase* PMSphereSweep::editWidget( QWidget* parent ) const
+{
+ return new PMSphereSweepEdit( parent );
+}
+
+void PMSphereSweep::createMemento( )
+{
+ if( m_pMemento )
+ delete m_pMemento;
+ m_pMemento = new PMSphereSweepMemento( this );
+}
+
+void PMSphereSweep::restoreMemento( PMMemento* s )
+{
+ PMSphereSweepMemento* m = ( PMSphereSweepMemento* ) s;
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMSplineTypeID:
+ setSplineType( ( SplineType ) data->intData( ) );
+ break;
+ case PMToleranceID:
+ setTolerance( data->doubleData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMSphereSweep::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ if( m->splinePointsSaved( ) )
+ setPoints( m->splinePoints( ) );
+ if( m->radiiSaved( ) )
+ setRadii( m->radii( ) );
+
+ Base::restoreMemento( s );
+}
+
+
+void PMSphereSweep::createViewStructure( )
+{
+ int numSegments = 0;
+ int numSpheres = m_points.size( );
+ m_segments.clear( );
+
+ int rSteps = (int)( ( (float)s_rSteps / 2 ) * ( displayDetail( ) + 1 ) );
+ int sSteps = (int)( ( (float)s_sSteps / 2 ) * ( displayDetail( ) + 1 ) );
+
+ switch ( m_splineType )
+ {
+ case LinearSpline:
+ numSegments = numSpheres - 1;
+ setLinear( sSteps );
+ break;
+ case BSpline:
+ numSegments = numSpheres - 3;
+ setCurved( false, sSteps );
+ break;
+ case CubicSpline:
+ numSegments = numSpheres - 3;
+ setCurved( true, sSteps );
+ break;
+ }
+
+ //Calculates sphere points
+ int numPoints = ( ( rSteps * ( rSteps - 2 ) ) + 2 ) *
+ ( numSegments + 1 );
+ //Calculates segments points
+ numPoints += ( rSteps * sSteps ) * numSegments;
+
+ //Calculates sphere lines
+ int numLines = ( rSteps * ( rSteps + rSteps - 3 ) ) *
+ ( numSegments + 1 );
+ //Calculates segments lines
+ numLines += ( ( sSteps * rSteps ) +
+ ( ( sSteps - 1 ) * rSteps ) ) * numSegments;
+
+ if ( !m_pViewStructure )
+ {
+ m_pViewStructure = new PMViewStructure( numPoints, numLines );
+ }
+ else
+ {
+ m_pViewStructure->points( ).resize( numPoints );
+ m_pViewStructure->lines( ).resize( numLines );
+ }
+
+ PMPointArray& points = m_pViewStructure->points( );
+ PMLineArray& lines = m_pViewStructure->lines( );
+ m_nextPoint = m_nextLine = 0;
+
+ PMVector v1, v2;
+ double rotval = M_PI / ( rSteps / 2 );
+
+ createSphere( m_segments[0].points[0], m_segments[0].radii[0], rSteps );
+ for ( int i = 0; i < numSegments; ++i )
+ {
+ for ( int j = 0; j < sSteps; ++ j )
+ {
+ v1 = m_segments[i].points[sSteps] - m_segments[i].points[0];
+ v1 = PMVector::cross( m_segments[i].direction[j], v1.orthogonal( ) );
+ v1 = ( v1 * ( 1 / v1.abs( ) ) ) * m_segments[i].radii[j];
+
+ for ( int k = 0; k < rSteps; ++k )
+ {
+ v2 = PMMatrix::rotation( m_segments[i].direction[j],
+ ( rotval * k ) ) * v1;
+ points[m_nextPoint++] = PMPoint( v2 + m_segments[i].points[j] );
+ if ( k < ( rSteps - 1 ) )
+ lines[m_nextLine++] = PMLine(
+ m_nextPoint - 1, m_nextPoint );
+ else
+ lines[m_nextLine++] = PMLine(
+ m_nextPoint - 1, m_nextPoint - rSteps );
+
+ if ( j < ( sSteps - 1 ) )
+ {
+ lines[m_nextLine++] = PMLine(
+ m_nextPoint - 1, m_nextPoint + ( rSteps - 1 ) );
+ }
+ }
+ }
+ createSphere( m_segments[i].points[sSteps - 1],
+ m_segments[i].radii[sSteps - 1], rSteps );
+ }
+}
+
+void PMSphereSweep::controlPoints( PMControlPointList& list )
+{
+ QValueList<PMVector>::Iterator it;
+ QValueList<double>::Iterator it2;
+ int i, nr;
+
+ for( it = m_points.begin( ), it2 = m_radii.begin( ), nr = 1, i = 0;
+ it != m_points.end( ) && it2 != m_radii.end( ); ++it, ++it2, ++nr )
+ {
+ PM3DControlPoint* p = new PM3DControlPoint( *it, i++,
+ i18n( "Center %1" ).arg( nr ) );
+ list.append( p );
+ list.append( new PMDistanceControlPoint( p, PMVector( 1.0, 0.0, 0.0 ),
+ *it2, i++,
+ i18n( "Radius %1 (x)" ).arg( nr ),
+ true ) );
+ list.append( new PMDistanceControlPoint( p, PMVector( 0.0, 1.0, 0.0 ),
+ *it2, i++,
+ i18n( "Radius %1 (y)" ).arg( nr ),
+ true ) );
+ list.append( new PMDistanceControlPoint( p, PMVector( 0.0, 0.0, 1.0 ),
+ *it2, i++,
+ i18n( "Radius %1 (z)" ).arg( nr ),
+ true ) );
+ }
+}
+
+void PMSphereSweep::controlPointsChanged( PMControlPointList& list )
+{
+ PMControlPointListIterator it1( list );
+ QValueList<PMVector>::Iterator pit = m_points.begin( );
+ QValueList<double>::Iterator rit = m_radii.begin( );
+ int i;
+ PM3DControlPoint* p;
+ PMDistanceControlPoint* r;
+ bool firstChange = true;
+
+ for( ; it1.current( ) && pit != m_points.end( ) && rit != m_radii.end( );
+ ++pit, ++rit )
+ {
+ p = ( PM3DControlPoint* ) it1.current( );
+ if( p->changed( ) )
+ {
+ if( firstChange )
+ {
+ firstChange = false;
+ setViewStructureChanged( );
+ }
+ if( m_pMemento )
+ {
+ PMSphereSweepMemento* m = ( PMSphereSweepMemento* ) m_pMemento;
+ if( !m->splinePointsSaved( ) )
+ m->setSplinePoints( m_points );
+ }
+ ( *pit ) = p->point( );
+ }
+ ++it1;
+
+ for( i = 0; i < 3 && it1.current( ); i++ )
+ {
+ r = ( PMDistanceControlPoint* ) it1.current( );
+ if( r->changed( ) )
+ {
+ if( firstChange )
+ {
+ firstChange = false;
+ setViewStructureChanged( );
+ }
+ if( m_pMemento )
+ {
+ PMSphereSweepMemento* m = ( PMSphereSweepMemento* ) m_pMemento;
+ if( !m->radiiSaved( ) )
+ m->setRadii( m_radii );
+ }
+ ( *rit ) = r->distance( );
+ }
+ ++it1;
+ }
+ }
+
+ for( it1.toFirst( ), rit = m_radii.begin( ); rit != m_radii.end( ); ++rit )
+ {
+ ++it1;
+ for( i = 0; i < 3; ++i, ++it1 )
+ ( ( PMDistanceControlPoint* ) *it1 )->setDistance( *rit );
+ }
+}
+
+void PMSphereSweep::addObjectActions( const PMControlPointList& /*cp*/,
+ QPtrList<PMObjectAction>& actions )
+{
+ PMObjectAction* a;
+
+ a = new PMObjectAction( s_pMetaObject, PMSplitSegmentID,
+ i18n( "Add Sphere" ) );
+ actions.append( a );
+
+ a = new PMObjectAction( s_pMetaObject, PMJoinSegmentsID,
+ i18n( "Remove Sphere" ) );
+ int np = m_points.count( );
+ int minp = 2;
+ switch( m_splineType )
+ {
+ case LinearSpline:
+ minp = 2;
+ break;
+ case BSpline:
+ minp = 4;
+ break;
+ case CubicSpline:
+ minp = 4;
+ break;
+ }
+
+ if( np < minp )
+ a->setEnabled( false );
+ actions.append( a );
+}
+
+void PMSphereSweep::objectActionCalled( const PMObjectAction* action,
+ const PMControlPointList& cp,
+ const QPtrList<PMVector>& cpViewPosition,
+ const PMVector& clickPosition )
+{
+ if( action->objectType( ) == s_pMetaObject )
+ {
+ switch( action->actionID( ) )
+ {
+ case PMSplitSegmentID:
+ splitSegment( cp, cpViewPosition, clickPosition );
+ break;
+ case PMJoinSegmentsID:
+ joinSegments( cp, cpViewPosition, clickPosition );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMSphereSweep::objectActionCalled\n";
+ break;
+ }
+ }
+ else
+ Base::objectActionCalled( action, cp, cpViewPosition, clickPosition );
+}
+
+void PMSphereSweep::splitSegment( const PMControlPointList& /*cp*/,
+ const QPtrList<PMVector>& cpViewPosition,
+ const PMVector& clickPosition )
+{
+ // find nearest segment
+ int nump = cpViewPosition.count( ) / 4 - 1;
+ double abs = 0.0, minabs = 1e10;
+ int ns = -1;
+ int i, j;
+ PMVector mid( 3 ), dist( 2 );
+
+ QPtrListIterator<PMVector> it1( cpViewPosition );
+ QPtrListIterator<PMVector> it2( cpViewPosition );
+ ++it2;
+
+ for( i = 0; i < nump; i++ )
+ {
+ bool skip = false;
+ switch( m_splineType )
+ {
+ case LinearSpline:
+ break;
+ case BSpline:
+ case CubicSpline:
+ if( ( i == 0 ) || ( i == ( nump - 1 ) ) )
+ skip = true;
+ break;
+ }
+
+ if( !skip )
+ {
+ mid = ( **it1 + **it2 ) / 2.0;
+ dist[0] = mid[0];
+ dist[1] = mid[1];
+ dist -= clickPosition;
+ abs = dist.abs( );
+
+ if( ( minabs > abs ) || ( ns < 0 ) )
+ {
+ minabs = abs;
+ ns = i;
+ }
+ }
+ for( j = 0; j < 4; j++ )
+ {
+ ++it1;
+ ++it2;
+ }
+ }
+
+ // add a new segment
+ QValueList<PMVector> newPoints = m_points;
+ QValueList<double> newRadii = m_radii;
+
+ QValueList<PMVector>::Iterator it = newPoints.at( ( unsigned ) ns );
+ QValueList<PMVector>::Iterator hit = it;
+ ++it;
+ mid = ( *it + *hit ) / 2;
+ newPoints.insert( it, mid );
+
+ QValueList<double>::Iterator rit = newRadii.at( ( unsigned ) ns );
+ QValueList<double>::Iterator rhit = rit;
+ ++rit;
+ newRadii.insert( rit, ( *rit + *rhit ) / 2 );
+
+ setPoints( newPoints );
+ setRadii( newRadii );
+}
+
+void PMSphereSweep::joinSegments( const PMControlPointList& /*cp*/,
+ const QPtrList<PMVector>& cpViewPosition,
+ const PMVector& clickPosition )
+{
+ // find nearest point
+ int nump = cpViewPosition.count( ) / 4;
+ int minp = 0;
+
+ switch( m_splineType )
+ {
+ case LinearSpline:
+ minp = 3;
+ break;
+ case BSpline:
+ case CubicSpline:
+ minp = 5;
+ break;
+ }
+
+ if( nump < minp )
+ {
+ kdError( PMArea ) << "Not enough points in PMSphereSweep::joinSegments\n";
+ return;
+ }
+
+ double abs = 0.0, minabs = 1e10;
+ int ns = -1;
+ int i, j;
+ PMVector* p;
+ PMVector dist( 2 );
+
+ QPtrListIterator<PMVector> it1( cpViewPosition );
+
+ for( i = 0; i < nump; i++ )
+ {
+ p = *it1;
+ dist[0] = (*p)[0];
+ dist[1] = (*p)[1];
+ dist -= clickPosition;
+ abs = dist.abs( );
+
+ if( ( minabs > abs ) || ( ns < 0 ) )
+ {
+ minabs = abs;
+ ns = i;
+ }
+ for( j = 0; j < 4; j++ )
+ ++it1;
+ }
+
+ // join two segments
+ QValueList<PMVector> newPoints = m_points;
+ QValueList<PMVector>::Iterator it;
+ QValueList<double> newRadii = m_radii;
+ QValueList<double>::Iterator rit;
+
+ // never remove the first or last point
+ if( ns == 0 )
+ ns++;
+ if( ns == ( nump - 1 ) )
+ ns--;
+ it = newPoints.at( ns );
+ newPoints.remove( it );
+ rit = newRadii.at( ns );
+ newRadii.remove( rit );
+
+ setPoints( newPoints );
+ setRadii( newRadii );
+}
+
+void PMSphereSweep::setRSteps( int r )
+{
+ if( r >= 4 )
+ s_rSteps = r;
+ else
+ kdDebug( PMArea ) << "PMSphereSweep::setRSteps: R must be greater than 3\n";
+ s_parameterKey++;
+}
+
+void PMSphereSweep::setSSteps( int s )
+{
+ if( s >= 1 )
+ s_sSteps = s;
+ else
+ kdDebug( PMArea ) << "PMSphereSweep::setSSteps: S must be greater than 0\n";
+ s_parameterKey++;
+}
+
+void PMSphereSweep::setLinear( int sSteps )
+{
+ int numsegments = ( m_points.size( ) - 1 );
+
+ double raddif;
+ PMVector diff, angle;
+ Segment seg;
+
+ for ( int i = 0; i < numsegments; ++i )
+ {
+ seg.points.clear( );
+ seg.radii.clear( );
+ seg.direction.clear( );
+ diff = ( m_points[i + 1] - m_points[i] ) / ( sSteps - 1.0 );
+ raddif = ( m_radii[i + 1] - m_radii[i] ) / ( sSteps - 1.0 );
+ angle = diff * ( 1 / diff.abs( ) );
+
+ for ( int j = 0; j < sSteps; ++j )
+ {
+ seg.points.append( m_points[i] + ( diff * j ) );
+ seg.radii.append( m_radii[i] + ( raddif * j ) );
+ seg.direction.append( angle );
+ }
+ m_segments.append( seg );
+ }
+}
+
+void PMSphereSweep::setCurved( bool cubic, int sSteps )
+{
+ int numsegments = ( m_points.size( ) - 3 );
+ PMVector centres[4];
+ PMVector vtr;
+ double divs = 1.0 / ( sSteps - 1.0 );
+ double raddif;
+ Segment seg;
+
+ for ( int i = 0; i < numsegments; ++i )
+ {
+ seg.points.clear( );
+ seg.radii.clear( );
+ seg.direction.clear( );
+ raddif = ( m_radii[i + 2] - m_radii[i + 1] ) / ( sSteps - 1.0 );
+ for ( int j = 0; j < 4; ++j )
+ centres[j] = m_points[ i + j ];
+
+ for ( int j = 0; j < sSteps; ++j )
+ {
+ if ( cubic )
+ seg.points.append( catmullRom( centres, ( divs * j ) ) );
+ else
+ seg.points.append( bSpline( centres, ( divs * j ) ) );
+
+ seg.radii.append( m_radii[i + 1] + ( raddif * j ) );
+ }
+
+ seg.direction.append( seg.points[0] - seg.points[1] );
+ for ( int j = 1; j < ( sSteps - 1 ) ; ++ j )
+ {
+ vtr = seg.points[ j - 1 ] - seg.points[j];
+ vtr += seg.points[j] - seg.points[ j + 1 ];
+ seg.direction.append( vtr );
+ }
+ seg.direction.append( seg.points[ sSteps - 2 ] -
+ seg.points[ sSteps - 1 ] );
+
+ m_segments.append( seg );
+ }
+}
+
+PMVector PMSphereSweep::catmullRom( PMVector *v, double t )
+{
+ PMVector rst;
+ double t2 = t * t;
+ double t3 = t * t * t;
+
+ rst.setX( (
+ ( -t3 + 2 * t2 - t ) * v[0].x( ) +
+ ( 3 * t3 -5 * t2 + 2 ) * v[1].x( ) +
+ ( -3 * t3 + 4 * t2 + t ) * v[2].x( ) +
+ ( t3 - t2 ) * v[3].x( )
+ ) / 2
+ );
+ rst.setY( (
+ ( -t3 + 2 * t2 -t ) * v[0].y( ) +
+ ( 3 * t3 -5 * t2 + 2 ) * v[1].y( ) +
+ ( -3 * t3 + 4 * t2 + t ) * v[2].y( ) +
+ ( t3 - t2) * v[3].y( )
+ ) / 2
+ );
+ rst.setZ( (
+ ( -t3 + 2 * t2 - t ) * v[0].z( ) +
+ ( 3 * t3 -5 * t2 + 2 ) * v[1].z( ) +
+ ( -3 * t3 + 4 * t2 + t ) * v[2].z( ) +
+ ( t3 - t2 ) * v[3].z( )
+ ) / 2
+ );
+
+ return rst;
+}
+
+PMVector PMSphereSweep::bSpline( PMVector *v, double t )
+{
+ PMVector rst;
+ double t2 = t * t;
+ double t3 = t * t * t;
+
+ rst.setX( (
+ ( -t3 + 3 * t2 -3 * t + 1 ) * v[0].x( ) +
+ ( 3 * t3 -6 * t2 + 4 ) * v[1].x( ) +
+ ( -3 * t3 + 3 * t2 + 3 * t + 1 ) * v[2].x( ) +
+ ( t3 ) * v[3].x( )
+ ) / 6
+ );
+ rst.setY( (
+ ( -t3 + 3 * t2 -3 * t + 1 ) * v[0].y( ) +
+ ( 3 * t3 -6 * t2 + 4 ) * v[1].y( ) +
+ ( -3 * t3 + 3 * t2 + 3 * t + 1 ) * v[2].y( ) +
+ ( t3 ) * v[3].y( )
+ ) / 6
+ );
+ rst.setZ( (
+ ( -t3 + 3 * t2 -3 * t + 1 ) * v[0].z( ) +
+ ( 3 * t3 -6 * t2 + 4 ) * v[1].z( ) +
+ ( -3 * t3 + 3 * t2 + 3 * t + 1 ) * v[2].z( ) +
+ ( t3 ) * v[3].z( )
+ ) / 6
+ );
+
+ return rst;
+}
+
+void PMSphereSweep::createSphere( PMVector v, double r, int rSteps )
+{
+ PMPointArray& points = m_pViewStructure->points( );
+ PMLineArray& lines = m_pViewStructure->lines( );
+
+ PMVector point = PMVector( 0, 1, 0 ) * r;
+ int pointUp = m_nextPoint++;
+ int pointDown = m_nextPoint++;
+ double rotVal1 = M_PI / ( rSteps - 1 );
+ double rotVal2 = ( M_PI / rSteps ) * 2;
+
+ points[pointUp] = PMPoint ( point + v );
+ points[pointDown] = PMPoint ( ( PMMatrix::rotation( 0, 0, M_PI ) * point ) + v );
+
+
+ for ( int i = 0; i < rSteps; ++i )
+ {
+ lines[ m_nextLine++] = PMLine( pointUp, m_nextPoint );
+ for ( int j = 1; j < ( rSteps - 1 ); ++j )
+ {
+ points[m_nextPoint++] = PMPoint(
+ ( PMMatrix::rotation( ( rotVal1 * j ), ( rotVal2 * i ), 0 ) * point ) + v );
+
+ if ( i < ( rSteps - 1 ) )
+ lines[m_nextLine++] = PMLine( m_nextPoint - 1, m_nextPoint +
+ rSteps - 3 );
+ else
+ lines[m_nextLine++] = PMLine( m_nextPoint - 1, m_nextPoint -
+ ( ( rSteps - 1 ) * ( rSteps - 2 ) ) - 1 );
+
+ if ( j < ( rSteps - 2 ) )
+ lines[m_nextLine++] = PMLine( m_nextPoint - 1, m_nextPoint );
+ else
+ lines[m_nextLine++] = PMLine( m_nextPoint - 1, pointDown );
+ }
+ }
+}
diff --git a/kpovmodeler/pmspheresweep.h b/kpovmodeler/pmspheresweep.h
new file mode 100644
index 00000000..281db0c3
--- /dev/null
+++ b/kpovmodeler/pmspheresweep.h
@@ -0,0 +1,245 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMSPHERESWEEP_H
+#define PMSPHERESWEEP_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobject.h"
+#include "pmvector.h"
+#include <qptrlist.h>
+#include <qvaluelist.h>
+#include <math.h>
+
+class PMViewStructure;
+
+/**
+ * Class for povray sphere sweep objects.
+ */
+
+class PMSphereSweep : public PMSolidObject
+{
+ typedef PMSolidObject Base;
+public:
+ /**
+ * The spline type
+ */
+ enum SplineType { LinearSpline, BSpline, CubicSpline };
+ /**
+ * Creates an empty PMSphereSweep
+ */
+ PMSphereSweep( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMSphereSweep( const PMSphereSweep& l );
+ /**
+ * deletes the PMSphereSweep
+ */
+ virtual ~PMSphereSweep( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMSphereSweep( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMSphereSweepEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmspheresweep" ); }
+
+ /** */
+ virtual void createMemento( );
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /** */
+ virtual void controlPoints( PMControlPointList& list );
+ /** */
+ virtual void controlPointsChanged( PMControlPointList& list );
+ /** */
+ virtual bool hasDisplayDetail( ) const { return true; }
+ /** */
+ virtual void addObjectActions( const PMControlPointList&,
+ QPtrList<PMObjectAction>& );
+ /** */
+ virtual void objectActionCalled( const PMObjectAction*,
+ const PMControlPointList&,
+ const QPtrList<PMVector>&,
+ const PMVector& );
+
+ /**
+ * Returns the spline points
+ */
+ QValueList<PMVector> points( ) const { return m_points; }
+ /**
+ * Sets the spline points
+ */
+ void setPoints( const QValueList<PMVector>& points );
+ /**
+ * Returns the radii
+ */
+ QValueList<double> radii( ) const { return m_radii; }
+ /**
+ * Sets the radii
+ */
+ void setRadii( const QValueList<double>& radii );
+ /**
+ * Returns the number of spline points
+ */
+ int numberOfPoints( ) const { return m_points.size( ); }
+ /**
+ * Returns the spline type
+ */
+ SplineType splineType( ) const { return m_splineType; }
+ /**
+ * Sets the spline type
+ */
+ void setSplineType( SplineType t );
+ /**
+ * Returns the depth tolerance
+ */
+ double tolerance( ) const { return m_tolerance; }
+ /**
+ * Sets the depth tolerance
+ */
+ void setTolerance( double t );
+
+ /**
+ * Sets the number of steps around the y axis
+ */
+ static void setRSteps( int r );
+ /**
+ * Sets the number of subdivisions of one spline segment
+ */
+ static void setSSteps( int v );
+ /**
+ * Returns the number of steps around the y axis
+ */
+ static int rSteps( ) { return s_rSteps; }
+ /**
+ * Returns the number of subdivisions of one spline segment
+ */
+ static int sSteps( ) { return s_sSteps; }
+
+protected:
+ /** */
+ virtual void createViewStructure( );
+ /** */
+ virtual int viewStructureParameterKey( ) const { return s_parameterKey + globalDetailKey( ); }
+
+private:
+ /**
+ * Object action. Adds a spline point
+ */
+ void splitSegment( const PMControlPointList& cp,
+ const QPtrList<PMVector>& cpViewPosition,
+ const PMVector& clickPosition );
+ /**
+ * Object action. Removes a spline point
+ */
+ void joinSegments( const PMControlPointList& cp,
+ const QPtrList<PMVector>& cpViewPosition,
+ const PMVector& clickPosition );
+
+ void stringToValues( const QString& str );
+ QString valuesToString( ) const;
+
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMSphereSweepMementoID { PMSplineTypeID, PMToleranceID };
+ /**
+ * IDs for the object actions
+ */
+ enum PMSphereSweepActionID { PMSplitSegmentID, PMJoinSegmentsID };
+ SplineType m_splineType;
+ QValueList<PMVector> m_points;
+ QValueList<double> m_radii;
+ double m_tolerance;
+
+ static int s_rSteps;
+ static int s_sSteps;
+ static int s_parameterKey;
+
+ static PMMetaObject* s_pMetaObject;
+
+ /**
+ * Segment Structure for holding info for
+ * creating view structure
+ */
+ struct Segment{
+ QValueList<PMVector> points;
+ QValueList<double> radii;
+ QValueList<PMVector> direction;
+ };
+
+ QValueList<Segment> m_segments;
+ int m_nextPoint;
+ int m_nextLine;
+ /**
+ * Sets up the segments for linear spline
+ * @param sSteps the number of subdivisions per segment
+ */
+ void setLinear( int sSteps );
+ /**
+ * Sets up segments for curved splines
+ * @param cubic true for cubic_spline false for b_spline
+ * @param sSteps the number of subdivisions per segment
+ */
+ void setCurved( bool cubic, int sSteps );
+ /**
+ * Returns a point on a Catmull rom spline
+ * @param v Pointer to four control points
+ * @param t position along spline ( 0.0 - 1.0 )
+ */
+ PMVector catmullRom( PMVector *v, double t );
+ /**
+ * Returns a point on a cubic b spline
+ * @param v pointer to four control points
+ * @param t position along spline ( 0.0 - 1.0 )
+ */
+ PMVector bSpline( PMVector *v, double t );
+ /**
+ * Creates a sphere
+ * @param v poisition of sphere
+ * @param r radius of sphere
+ * @param rSteps the number of steps around the y axis
+ */
+ void createSphere( PMVector v, double r, int rSteps );
+
+};
+
+#endif
diff --git a/kpovmodeler/pmspheresweepedit.cpp b/kpovmodeler/pmspheresweepedit.cpp
new file mode 100644
index 00000000..582a0e80
--- /dev/null
+++ b/kpovmodeler/pmspheresweepedit.cpp
@@ -0,0 +1,354 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmspheresweepedit.h"
+#include "pmspheresweep.h"
+#include "pmvectoredit.h"
+#include "pmlineedits.h"
+#include "pmvectorlistedit.h"
+#include "pmpart.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qtooltip.h>
+#include <qcombobox.h>
+#include <qcheckbox.h>
+#include <qpushbutton.h>
+#include <klocale.h>
+#include <kdialog.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+
+PMSphereSweepEdit::PMSphereSweepEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMSphereSweepEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "Spline type:" ), this ) );
+ m_pSplineType = new QComboBox( false, this );
+ m_pSplineType->insertItem( i18n( "Linear Spline" ) );
+ m_pSplineType->insertItem( i18n( "B-Spline" ) );
+ m_pSplineType->insertItem( i18n( "Cubic Spline" ) );
+ hl->addWidget( m_pSplineType );
+ hl->addStretch( 1 );
+
+ connect( m_pSplineType, SIGNAL( activated( int ) ),
+ SLOT( slotTypeChanged( int ) ) );
+}
+
+void PMSphereSweepEdit::createBottomWidgets( )
+{
+ topLayout( )->addWidget( new QLabel( i18n( "Spheres:" ), this ) );
+
+ m_pPoints = new PMVectorListEdit( "x", "y", "z", "r", this );
+ connect( m_pPoints, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pPoints, SIGNAL( selectionChanged( ) ),
+ SLOT( slotSelectionChanged( ) ) );
+ QHBoxLayout* hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( m_pPoints, 2 );
+
+ m_pAddAbove = new QPushButton( this );
+ m_pAddAbove->setPixmap( SmallIcon( "pmaddpointabove" ) );
+ m_pAddBelow = new QPushButton( this );
+ m_pAddBelow->setPixmap( SmallIcon( "pmaddpoint" ) );
+ m_pRemove = new QPushButton( this );
+ m_pRemove->setPixmap( SmallIcon( "pmremovepoint" ) );
+ connect( m_pAddAbove, SIGNAL( clicked( ) ), SLOT( slotAddPointAbove( ) ) );
+ connect( m_pAddBelow, SIGNAL( clicked( ) ), SLOT( slotAddPointBelow( ) ) );
+ connect( m_pRemove, SIGNAL( clicked( ) ), SLOT( slotRemovePoint( ) ) );
+
+ QVBoxLayout* bl = new QVBoxLayout( hl );
+ bl->addWidget( m_pAddAbove );
+ bl->addWidget( m_pAddBelow );
+ bl->addWidget( m_pRemove );
+ bl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "Tolerance" ), this ) );
+ m_pTolerance = new PMFloatEdit( this );
+ m_pTolerance->setValidation( true, 0, false, 0 );
+ hl->addWidget( m_pTolerance );
+ connect( m_pTolerance, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+
+ Base::createBottomWidgets( );
+}
+
+void PMSphereSweepEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "SphereSweep" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMSphereSweep* ) o;
+
+ switch( m_pDisplayedObject->splineType( ) )
+ {
+ case PMSphereSweep::LinearSpline:
+ m_pSplineType->setCurrentItem( 0 );
+ break;
+ case PMSphereSweep::BSpline:
+ m_pSplineType->setCurrentItem( 1 );
+ break;
+ case PMSphereSweep::CubicSpline:
+ m_pSplineType->setCurrentItem( 2 );
+ break;
+ }
+ m_pSplineType->setEnabled( !readOnly );
+ m_pTolerance->setValue( m_pDisplayedObject->tolerance( ) );
+ m_pTolerance->setReadOnly( readOnly );
+ m_pPoints->setReadOnly( readOnly );
+
+ QValueList<PMVector> points = m_pDisplayedObject->points( );
+ QValueList<double> radii = m_pDisplayedObject->radii( );
+ QValueListIterator<PMVector> pit = points.begin( );
+ QValueListIterator<double> rit = radii.begin( );
+ for( ; pit != points.end( ) && rit != radii.end( ); ++pit, ++rit )
+ {
+ ( *pit ).resize( 4 );
+ ( *pit )[3] = *rit;
+ }
+
+ m_pPoints->setVectors( points, true );
+ updateControlPointSelection( );
+ updatePointButtons( );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMSphereSweepEdit: Can't display object\n";
+}
+
+void PMSphereSweepEdit::updateControlPointSelection( )
+{
+ /*
+ PMControlPointList cp = part( )->activeControlPoints( );
+ PMControlPointListIterator it( cp );
+ int i;
+ int np = cp.count( ) / 4;
+
+ if( np == m_pPoints->size( ) )
+ {
+ m_pPoints->blockSelectionUpdates( true );
+ bool sb = m_pPoints->signalsBlocked( );
+ m_pPoints->blockSignals( true );
+
+ m_pPoints->clearSelection( );
+ for( i = 0; i < np; i++, ++it )
+ if( ( *it )->selected( ) )
+ m_pPoints->select( i );
+ for( i = 0; i < np; i++, ++it )
+ if( ( *it )->selected( ) )
+ m_pPoints->select( i );
+
+ m_pPoints->blockSignals( sb );
+ m_pPoints->blockSelectionUpdates( false );
+ }
+ */
+}
+
+void PMSphereSweepEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ QValueList<PMVector> points = m_pPoints->vectors( );
+ QValueList<double> radii;
+ QValueListIterator<PMVector> pit = points.begin( );
+ for( ; pit != points.end( ); ++pit )
+ {
+ radii.append( ( *pit )[3] );
+ ( *pit ).resize( 3 );
+ }
+
+ m_pDisplayedObject->setPoints( points );
+ m_pDisplayedObject->setRadii( radii );
+
+ switch( m_pSplineType->currentItem( ) )
+ {
+ case 0:
+ m_pDisplayedObject->setSplineType( PMSphereSweep::LinearSpline );
+ break;
+ case 1:
+ m_pDisplayedObject->setSplineType( PMSphereSweep::BSpline );
+ break;
+ case 2:
+ m_pDisplayedObject->setSplineType( PMSphereSweep::CubicSpline );
+ break;
+ }
+ m_pDisplayedObject->setTolerance( m_pTolerance->value( ) );
+ Base::saveContents( );
+ }
+}
+
+bool PMSphereSweepEdit::isDataValid( )
+{
+ if( !m_pPoints->isDataValid( ) )
+ return false;
+
+ int np = m_pPoints->size( );
+ switch( m_pSplineType->currentItem( ) )
+ {
+ case 0:
+ if( np < 2 )
+ {
+ KMessageBox::error( this, i18n( "Linear splines need at least 2 points." ),
+ i18n( "Error" ) );
+ return false;
+ }
+ break;
+ case 1:
+ if( np < 4 )
+ {
+ KMessageBox::error( this, i18n( "B-splines need at least 4 points." ),
+ i18n( "Error" ) );
+ return false;
+ }
+ break;
+ case 2:
+ if( np < 4 )
+ {
+ KMessageBox::error( this, i18n( "Cubic splines need at least 4 points." ),
+ i18n( "Error" ) );
+ return false;
+ }
+ break;
+ case 3:
+ if( ( np < 4 ) || ( ( np % 4 ) != 0 ) )
+ {
+ KMessageBox::error( this, i18n( "Bezier splines need 4 points for each segment." ),
+ i18n( "Error" ) );
+ return false;
+ }
+ break;
+ }
+ return Base::isDataValid( );
+}
+
+void PMSphereSweepEdit::slotTypeChanged( int )
+{
+ emit dataChanged( );
+}
+
+void PMSphereSweepEdit::slotAddPointAbove( )
+{
+ int index = m_pPoints->currentRow( );
+ if( index >= 0 )
+ {
+ QValueList<PMVector> points = m_pPoints->vectors( );
+ QValueListIterator<PMVector> it = points.at( index );
+
+ if( it != points.end( ) )
+ {
+ QValueListIterator<PMVector> it2 = it;
+ it2--;
+ PMVector v;
+ if( it2 == points.end( ) )
+ v = *it;
+ else
+ v = ( *it + *it2 ) / 2;
+
+ points.insert( it, v );
+ m_pPoints->setVectors( points, true );
+ updatePointButtons( );
+ emit dataChanged( );
+ emit sizeChanged( );
+ }
+ }
+}
+
+void PMSphereSweepEdit::slotAddPointBelow( )
+{
+ int index = m_pPoints->currentRow( );
+ if( index >= 0 )
+ {
+ QValueList<PMVector> points = m_pPoints->vectors( );
+ QValueListIterator<PMVector> it = points.at( index );
+
+ if( it != points.end( ) )
+ {
+ QValueListIterator<PMVector> it2 = it;
+ it2++;
+ PMVector v;
+ if( it2 == points.end( ) )
+ v = *it;
+ else
+ v = ( *it + *it2 ) / 2;
+
+ points.insert( it2, v );
+ m_pPoints->setVectors( points, true );
+ m_pPoints->setCurrentCell( index + 1, m_pPoints->currentColumn( ) );
+ updatePointButtons( );
+ emit dataChanged( );
+ emit sizeChanged( );
+ }
+ }
+}
+
+void PMSphereSweepEdit::slotRemovePoint( )
+{
+ int row = m_pPoints->currentRow( );
+
+ if( row >= 0 )
+ {
+ QValueList<PMVector> points = m_pPoints->vectors( );
+ QValueListIterator<PMVector> it = points.at( row );
+
+ if( it != points.end( ) && points.size( ) > 1 )
+ {
+ points.remove( it );
+ m_pPoints->setVectors( points, true );
+ updatePointButtons( );
+ emit dataChanged( );
+ emit sizeChanged( );
+ }
+ }
+}
+
+void PMSphereSweepEdit::slotSelectionChanged( )
+{
+ /*
+ PMControlPointList cp = part( )->activeControlPoints( );
+ PMControlPointListIterator it( cp );
+ int np = cp.count( ) / 2;
+ int i;
+
+ if( np == m_pPoints->size( ) )
+ {
+ for( i = 0; i < np; i++, ++it )
+ ( *it )->setSelected( m_pPoints->isSelected( i ) );
+ for( i = 0; i < np; i++, ++it )
+ ( *it )->setSelected( m_pPoints->isSelected( i ) );
+ emit controlPointSelectionChanged( );
+ }
+ */
+ updatePointButtons( );
+}
+
+void PMSphereSweepEdit::updatePointButtons( )
+{
+ int row = m_pPoints->currentRow( );
+ m_pAddAbove->setEnabled( row >= 0 );
+ m_pAddBelow->setEnabled( row >= 0 );
+ m_pRemove->setEnabled( row >= 0 && m_pPoints->size( ) > 2 );
+}
+
+#include "pmspheresweepedit.moc"
diff --git a/kpovmodeler/pmspheresweepedit.h b/kpovmodeler/pmspheresweepedit.h
new file mode 100644
index 00000000..58f89372
--- /dev/null
+++ b/kpovmodeler/pmspheresweepedit.h
@@ -0,0 +1,90 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMSPHERESWEEPEDIT_H
+#define PMSPHERESWEEPEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobjectedit.h"
+#include "pmvectoredit.h"
+#include <qptrlist.h>
+#include <qvaluelist.h>
+
+class PMSphereSweep;
+class PMVectorListEdit;
+class PMFloatEdit;
+class QVBoxLayout;
+class QComboBox;
+class QCheckBox;
+class QPushButton;
+class QLabel;
+
+/**
+ * Dialog edit class for @ref PMSphereSweep
+ */
+class PMSphereSweepEdit : public PMSolidObjectEdit
+{
+ Q_OBJECT
+ typedef PMSolidObjectEdit Base;
+public:
+ /**
+ * Creates a PMSphereSweepEdit with parent and name
+ */
+ PMSphereSweepEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+ /** */
+ virtual void updateControlPointSelection( );
+
+ /** */
+ virtual bool isDataValid( );
+
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void createBottomWidgets( );
+ /** */
+ virtual void saveContents( );
+
+protected slots:
+ void slotTypeChanged( int );
+ void slotAddPointAbove( );
+ void slotAddPointBelow( );
+ void slotRemovePoint( );
+ void slotSelectionChanged( );
+
+private:
+ void updatePointButtons( );
+
+ PMSphereSweep* m_pDisplayedObject;
+ QComboBox* m_pSplineType;
+ PMVectorListEdit* m_pPoints;
+ PMFloatEdit* m_pTolerance;
+ QPushButton* m_pAddAbove;
+ QPushButton* m_pAddBelow;
+ QPushButton* m_pRemove;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmsplinememento.cpp b/kpovmodeler/pmsplinememento.cpp
new file mode 100644
index 00000000..a197f8ea
--- /dev/null
+++ b/kpovmodeler/pmsplinememento.cpp
@@ -0,0 +1,58 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmsplinememento.h"
+#include "pmdebug.h"
+
+PMSplineMemento::PMSplineMemento( PMObject* originator )
+ : PMMemento( originator )
+{
+ m_bSplinePointsSaved = false;
+}
+
+PMSplineMemento::~PMSplineMemento( )
+{
+}
+
+void PMSplineMemento::setSplinePoints( const QValueList<PMVector>& v )
+{
+ if( !m_bSplinePointsSaved )
+ {
+ // Direct assignment does not work with Qt 2.3.x
+ // The list will be changed later in a graphical
+ // change because QValueList::detach( ) is called
+ // too late!
+ // Copy the list by hand.
+
+ QValueList<PMVector>::ConstIterator it = v.begin( );
+ for( ; it != v.end( ); ++it )
+ m_splinePoints.append( *it );
+
+ m_bSplinePointsSaved = true;
+ addChange( PMCData );
+ }
+}
+
+QValueList<PMVector> PMSplineMemento::splinePoints( ) const
+{
+ if( !m_bSplinePointsSaved )
+ kdError( PMArea ) << "Spline points not saved in PMSplineMemento::splinePoints\n";
+
+ return m_splinePoints;
+}
+
+
diff --git a/kpovmodeler/pmsplinememento.h b/kpovmodeler/pmsplinememento.h
new file mode 100644
index 00000000..daa4a70b
--- /dev/null
+++ b/kpovmodeler/pmsplinememento.h
@@ -0,0 +1,68 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMSPLINEMEMENTO_H
+#define PMSPLINEMEMENTO_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmmemento.h"
+#include "pmvector.h"
+#include <qvaluelist.h>
+
+
+/**
+ * Memento for @ref PMLathe
+ */
+class PMSplineMemento : public PMMemento
+{
+public:
+ /**
+ * Creates a memento for the object originator
+ */
+ PMSplineMemento( PMObject* originator );
+ /**
+ * Deletes the memento
+ */
+ virtual ~PMSplineMemento( );
+
+ /**
+ * Saves the spline points
+ */
+ void setSplinePoints( const QValueList<PMVector>& v );
+ /**
+ * Returns the spline points
+ */
+ QValueList<PMVector> splinePoints( ) const;
+ /**
+ * Returns true if the spline points were saved
+ */
+ bool splinePointsSaved( ) const { return m_bSplinePointsSaved; }
+
+private:
+ /**
+ * The stored points
+ */
+ QValueList<PMVector> m_splinePoints;
+ bool m_bSplinePointsSaved;
+};
+
+#endif
diff --git a/kpovmodeler/pmsplinesegment.cpp b/kpovmodeler/pmsplinesegment.cpp
new file mode 100644
index 00000000..dbbc6b18
--- /dev/null
+++ b/kpovmodeler/pmsplinesegment.cpp
@@ -0,0 +1,107 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmsplinesegment.h"
+
+PMVector PMSplineSegment::point( double t ) const
+{
+ double t2 = t * t;
+ double t3 = t2 * t;
+
+ return PMVector( m_a[0]*t3 + m_b[0]*t2 + m_c[0]*t + m_d[0],
+ m_a[1]*t3 + m_b[1]*t2 + m_c[1]*t + m_d[1] );
+}
+
+PMVector PMSplineSegment::gradient( double t ) const
+{
+ double t2 = t * t;
+
+ return PMVector( 3*m_a[0]*t2 + 2*m_b[0]*t + m_c[0],
+ 3*m_a[1]*t2 + 2*m_b[1]*t + m_c[1] );
+}
+
+void PMSplineSegment::calculateLinear( const PMVector& p1, const PMVector& p2 )
+{
+ m_a[0] = 0.0;
+ m_b[0] = 0.0;
+ m_c[0] = -1.0 * p1[0] + 1.0 * p2[0];
+ m_d[0] = 1.0 * p1[0];
+
+ m_a[1] = 0.0;
+ m_b[1] = 0.0;
+ m_c[1] = -1.0 * p1[1] + 1.0 * p2[1];
+ m_d[1] = 1.0 * p1[1];
+}
+
+void PMSplineSegment::calculateQuadratic( const PMVector& p1,
+ const PMVector& p2,
+ const PMVector& p3 )
+{
+ m_a[0] = 0.0;
+ m_b[0] = 0.5 * p1[0] - 1.0 * p2[0] + 0.5 * p3[0];
+ m_c[0] = -0.5 * p1[0] + 0.5 * p3[0];
+ m_d[0] = 1.0 * p2[0];
+
+ m_a[1] = 0.0;
+ m_b[1] = 0.5 * p1[1] - 1.0 * p2[1] + 0.5 * p3[1];
+ m_c[1] = -0.5 * p1[1] + 0.5 * p3[1];
+ m_d[1] = 1.0 * p2[1];
+}
+
+void PMSplineSegment::calculateCubic( const PMVector& p1, const PMVector& p2,
+ const PMVector& p3, const PMVector& p4 )
+{
+ m_a[0] = -0.5 * p1[0] + 1.5 * p2[0] - 1.5 * p3[0] + 0.5 * p4[0];
+ m_b[0] = p1[0] - 2.5 * p2[0] + 2.0 * p3[0] - 0.5 * p4[0];
+ m_c[0] = -0.5 * p1[0] + 0.5 * p3[0];
+ m_d[0] = p2[0];
+
+ m_a[1] = -0.5 * p1[1] + 1.5 * p2[1] - 1.5 * p3[1] + 0.5 * p4[1];
+ m_b[1] = p1[1] - 2.5 * p2[1] + 2.0 * p3[1] - 0.5 * p4[1];
+ m_c[1] = -0.5 * p1[1] + 0.5 * p3[1];
+ m_d[1] = p2[1];
+}
+
+void PMSplineSegment::calculateBezier( const PMVector& p1, const PMVector& p2,
+ const PMVector& p3, const PMVector& p4 )
+{
+ m_a[0] = - p1[0] + 3.0 * p2[0] - 3.0 * p3[0] + p4[0];
+ m_b[0] = 3.0 * p1[0] - 6.0 * p2[0] + 3.0 * p3[0];
+ m_c[0] = -3.0 * p1[0] + 3.0 * p2[0];
+ m_d[0] = p1[0];
+
+ m_a[1] = - p1[1] + 3.0 * p2[1] - 3.0 * p3[1] + p4[1];
+ m_b[1] = 3.0 * p1[1] - 6.0 * p2[1] + 3.0 * p3[1];
+ m_c[1] = -3.0 * p1[1] + 3.0 * p2[1];
+ m_d[1] = p1[1];
+}
+
+void PMSplineSegment::calculateQuadricBezier( const PMVector& p1,
+ const PMVector& p2,
+ const PMVector& p3 )
+{
+ m_a[0] = 0;
+ m_b[0] = p1[0] - 2.0 * p2[0] + p3[0];
+ m_c[0] = -2.0 * p1[0] + 2.0 * p2[0];
+ m_d[0] = p1[0];
+
+ m_a[1] = 0;
+ m_b[1] = p1[1] - 2.0 * p2[1] + p3[1];
+ m_c[1] = -2.0 * p1[1] + 2.0 * p2[1];
+ m_d[1] = p1[1];
+}
diff --git a/kpovmodeler/pmsplinesegment.h b/kpovmodeler/pmsplinesegment.h
new file mode 100644
index 00000000..5e97ff49
--- /dev/null
+++ b/kpovmodeler/pmsplinesegment.h
@@ -0,0 +1,122 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMSPLINESEGMENT_H
+#define PMSPLINESEGMENT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmvector.h"
+#include <qvaluelist.h>
+
+/**
+ * Helper class for splines
+ *
+ * Each instance of this class represents one spline segment. A point
+ * on the segment is given by the equation
+ *
+ * fi(t) = A[i] * t^3 + B[i] * t^2 + C[i] * t + D[i]
+ *
+ * with t ranging from 0 to 1.
+ */
+class PMSplineSegment
+{
+public:
+ /**
+ * Standard constructor
+ */
+ PMSplineSegment( )
+ {
+ m_a[0] = m_b[0] = m_c[0] = m_d[0] = 0.0;
+ m_a[1] = m_b[1] = m_c[1] = m_d[1] = 0.0;
+ }
+ /**
+ * Copy constructor
+ */
+ PMSplineSegment( const PMSplineSegment& s )
+ {
+ int i;
+ for( i = 0; i < 2; i++ )
+ {
+ m_a[i] = s.m_a[i];
+ m_b[i] = s.m_b[i];
+ m_c[i] = s.m_c[i];
+ m_d[i] = s.m_d[i];
+ }
+ }
+ /**
+ * Assigns s to the segment
+ */
+ PMSplineSegment& operator= ( const PMSplineSegment& s )
+ {
+ int i;
+ for( i = 0; i < 2; i++ )
+ {
+ m_a[i] = s.m_a[i];
+ m_b[i] = s.m_b[i];
+ m_c[i] = s.m_c[i];
+ m_d[i] = s.m_d[i];
+ }
+ return *this;
+ }
+
+ /**
+ * Returns a 2D vector with the point on the spline segment
+ */
+ PMVector point( double t ) const;
+ /**
+ * Returns the gradient on the spline
+ */
+ PMVector gradient( double t ) const;
+
+ /**
+ * Calculates the spline parameters for the linear spline type
+ */
+ void calculateLinear( const PMVector& p1, const PMVector& p2 );
+ /**
+ * Calculates the spline parameters for the quadratic spline type
+ */
+ void calculateQuadratic( const PMVector& p1, const PMVector& p2,
+ const PMVector& p3 );
+ /**
+ * Calculates the spline parameters for the cubic spline type
+ */
+ void calculateCubic( const PMVector& p1, const PMVector& p2,
+ const PMVector& p3, const PMVector& p4 );
+ /**
+ * Calculates the spline parameters for the bezier spline type
+ */
+ void calculateBezier( const PMVector& p1, const PMVector& p2,
+ const PMVector& p3, const PMVector& p4 );
+ /**
+ * Calculates the spline parameters for the quadric bezier
+ */
+ void calculateQuadricBezier( const PMVector& p1, const PMVector& p2,
+ const PMVector& p3 );
+
+private:
+ double m_a[2], m_b[2], m_c[2], m_d[2];
+};
+
+typedef QValueList<PMSplineSegment> PMSegmentList;
+typedef QValueList<PMSegmentList> PMSegmentListList;
+
+#endif
diff --git a/kpovmodeler/pmsqe.cpp b/kpovmodeler/pmsqe.cpp
new file mode 100644
index 00000000..051aac72
--- /dev/null
+++ b/kpovmodeler/pmsqe.cpp
@@ -0,0 +1,413 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmsqe.h"
+
+#include "pmxmlhelper.h"
+#include "pmsqeedit.h"
+#include "pmmemento.h"
+#include "pmviewstructure.h"
+#include "pmdefaults.h"
+#include "pmmath.h"
+
+#include <klocale.h>
+
+const double c_defaultEastWestExponent = 1.0;
+const double c_defaultNorthSouthExponent = 1.0;
+
+PMViewStructure* PMSuperquadricEllipsoid::s_pDefaultViewStructure = 0;
+int PMSuperquadricEllipsoid::s_vStep = c_defaultSuperquadricEllipsoidVSteps;
+int PMSuperquadricEllipsoid::s_uStep = c_defaultSuperquadricEllipsoidUSteps;
+int PMSuperquadricEllipsoid::s_parameterKey = 0;
+
+PMDefinePropertyClass( PMSuperquadricEllipsoid, PMSuperquadricEllipsoidProperty );
+
+PMMetaObject* PMSuperquadricEllipsoid::s_pMetaObject = 0;
+PMObject* createNewSuperquadricEllipsoid( PMPart* part )
+{
+ return new PMSuperquadricEllipsoid( part );
+}
+
+PMSuperquadricEllipsoid::PMSuperquadricEllipsoid( PMPart* part )
+ : Base( part )
+{
+ m_eastWestExponent = c_defaultEastWestExponent;
+ m_northSouthExponent = c_defaultNorthSouthExponent;
+}
+
+PMSuperquadricEllipsoid::PMSuperquadricEllipsoid( const PMSuperquadricEllipsoid& s )
+ : Base( s )
+{
+ m_eastWestExponent = s.m_eastWestExponent;
+ m_northSouthExponent = s.m_northSouthExponent;
+}
+
+PMSuperquadricEllipsoid::~PMSuperquadricEllipsoid( )
+{
+}
+
+QString PMSuperquadricEllipsoid::description( ) const
+{
+ return i18n( "superquadric ellipsoid" );
+}
+
+void PMSuperquadricEllipsoid::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "value_e", m_eastWestExponent );
+ e.setAttribute( "value_n", m_northSouthExponent );
+ Base::serialize( e, doc );
+}
+
+void PMSuperquadricEllipsoid::readAttributes( const PMXMLHelper& h )
+{
+ m_eastWestExponent = h.doubleAttribute( "value_e", c_defaultEastWestExponent );
+ m_northSouthExponent = h.doubleAttribute( "value_n", c_defaultNorthSouthExponent );
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMSuperquadricEllipsoid::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "SuperquadricEllipsoid", Base::metaObject( ),
+ createNewSuperquadricEllipsoid );
+ s_pMetaObject->addProperty(
+ new PMSuperquadricEllipsoidProperty( "eastWestExponent",
+ &PMSuperquadricEllipsoid::setEastWestExponent,
+ &PMSuperquadricEllipsoid::eastWestExponent ) );
+ s_pMetaObject->addProperty(
+ new PMSuperquadricEllipsoidProperty( "northSouthExponent",
+ &PMSuperquadricEllipsoid::setNorthSouthExponent,
+ &PMSuperquadricEllipsoid::northSouthExponent ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMSuperquadricEllipsoid::setEastWestExponent( double e )
+{
+ if( e != m_eastWestExponent )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMEastWestExponentID,
+ m_eastWestExponent );
+ if( e < 0.001 )
+ {
+ kdError( PMArea ) << "EastWestExponent < 0.001 in PMSuperquadricEllipsoid::setEastWestExponent\n";
+ e = 0.001;
+ }
+ m_eastWestExponent = e;
+ setViewStructureChanged( );
+ }
+}
+
+void PMSuperquadricEllipsoid::setNorthSouthExponent( double n )
+{
+ if( n != m_northSouthExponent )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMNorthSouthExponentID,
+ m_northSouthExponent );
+ if( n < 0.001 )
+ {
+ kdError( PMArea ) << "NorthSouthExponent < 0.001 in PMSuperquadricEllipsoid::setNorthSouthExponent\n";
+ n = 0.001;
+ }
+
+ m_northSouthExponent = n;
+ setViewStructureChanged( );
+ }
+}
+
+PMDialogEditBase* PMSuperquadricEllipsoid::editWidget( QWidget* parent ) const
+{
+ return new PMSuperquadricEllipsoidEdit( parent );
+}
+
+void PMSuperquadricEllipsoid::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMEastWestExponentID:
+ setEastWestExponent( data->doubleData( ) );
+ break;
+ case PMNorthSouthExponentID:
+ setNorthSouthExponent( data->doubleData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMSuperquadricEllipsoid::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
+
+bool PMSuperquadricEllipsoid::isDefault( )
+{
+ if( ( m_eastWestExponent == c_defaultEastWestExponent ) &&
+ ( m_northSouthExponent == c_defaultNorthSouthExponent )
+ && globalDetail( ) )
+ return true;
+ return false;
+}
+
+void PMSuperquadricEllipsoid::createViewStructure( )
+{
+ if( !m_pViewStructure )
+ {
+ m_pViewStructure = new PMViewStructure( defaultViewStructure( ) );
+ m_pViewStructure->points( ).detach( );
+ }
+
+ int uStep = (int)( ( (float)s_uStep / 2 ) * ( displayDetail( ) + 1 ) );
+ int vStep = (int)( ( (float)s_vStep / 2 ) * ( displayDetail( ) + 1 ) );
+ int uStep2 = uStep * 4;
+ int vStep2 = vStep * 8;
+ unsigned ptsSize = vStep2 * ( uStep2 - 1 ) + 2;
+ unsigned lineSize = vStep2 * ( uStep2 - 1 ) * 2 + vStep2;
+
+ if( ptsSize != m_pViewStructure->points( ).size( ) )
+ m_pViewStructure->points( ).resize( ptsSize );
+
+ createPoints( m_pViewStructure->points( ), m_eastWestExponent,
+ m_northSouthExponent, uStep, vStep );
+
+ if( lineSize != m_pViewStructure->lines( ).size( ) )
+ {
+ m_pViewStructure->lines( ).detach( );
+ m_pViewStructure->lines( ).resize( lineSize );
+ createLines( m_pViewStructure->lines( ), uStep2, vStep2 );
+ }
+}
+
+PMViewStructure* PMSuperquadricEllipsoid::defaultViewStructure( ) const
+{
+ if( !s_pDefaultViewStructure || s_pDefaultViewStructure->parameterKey( ) != viewStructureParameterKey( ) )
+ {
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ int uStep = (int)( ( (float)s_uStep / 2 ) * ( globalDetailLevel( ) + 1 ) );
+ int vStep = (int)( ( (float)s_vStep / 2 ) * ( globalDetailLevel( ) + 1 ) );
+
+ // transform u and v steps to sphere u/v steps
+ int uStep2 = uStep * 4;
+ int vStep2 = vStep * 8;
+
+ s_pDefaultViewStructure =
+ new PMViewStructure( vStep2 * ( uStep2 - 1 ) + 2,
+ vStep2 * ( uStep2 - 1 ) * 2 + vStep2 );
+
+ // points
+ createPoints( s_pDefaultViewStructure->points( ),
+ c_defaultEastWestExponent, c_defaultNorthSouthExponent, uStep, vStep );
+
+ createLines( s_pDefaultViewStructure->lines( ), uStep2, vStep2 );
+ }
+ return s_pDefaultViewStructure;
+}
+
+void PMSuperquadricEllipsoid::createLines( PMLineArray& lines, int uStep, int vStep )
+{
+ int u, v;
+ int offset = 0;
+
+ // horizontal lines
+ for( u = 0; u < ( uStep - 1 ); u++ )
+ {
+ for( v = 0; v < ( vStep - 1 ); v++ )
+ lines[offset + v] =
+ PMLine( u * vStep + v + 1, u * vStep + v + 2 );
+ lines[offset + vStep - 1] =
+ PMLine( u * vStep + 1, u * vStep + vStep );
+
+ offset += vStep;
+ }
+
+ // vertical lines
+ // lines at the "north pole"
+ for( v = 0; v < vStep; v++ )
+ lines[offset + v] = PMLine( 0, v + 1 );
+ offset += vStep;
+
+ for( v = 0; v < vStep; v++ )
+ {
+ for( u = 0; u < ( uStep - 2 ); u++ )
+ {
+ lines[offset + u] =
+ PMLine( u * vStep + v + 1, ( u + 1 ) * vStep + v + 1 );
+ }
+ offset += ( uStep - 2 );
+ }
+ // lines at the "south pole"
+ for( v = 0; v < vStep; v++ )
+ lines[offset + v] = PMLine( ( uStep - 2 ) * vStep + v + 1,
+ ( uStep - 1 ) * vStep + 1 );
+ // offset += vStep;
+}
+
+void PMSuperquadricEllipsoid::createPoints( PMPointArray& points,
+ double e, double n, int uStep, int vStep )
+{
+ int u, v;
+ int zi;
+ int pbase = 0, pref = 0;
+
+ if( e <= 0.001 )
+ e = 0.001;
+ if( n <= 0.001 )
+ n = 0.001;
+
+ double c2_e = 2.0 / e;
+ double c2_n = 2.0 / n;
+ double cn_2 = n / 2.0;
+ double ce_2 = e / 2.0;
+ double cn_e = n / e;
+// double ce_n = e / n;
+ double z = 0.0, c = 0.0, a = 0.0, a2 = 0.0, x = 0.0, y = 0.0;
+ double k = 0.0, k2 = 0.0, du = 0.0, dv = 0.0;
+ PMPoint p;
+
+ points[0] = PMPoint( 0, 0, 1 );
+ pbase++;
+
+ for( zi = 0; zi < 2; zi++ )
+ {
+ for( u = 0; u < uStep; u++ )
+ {
+ du = ( double ) ( u + 1 ) / ( double ) uStep;
+ if( zi == 1 )
+ du = 1.0 - du;
+ k = tan( M_PI / 4.0 * pow( du, n < 1.0 ? n : sqrt( n ) ) );
+ k2 = 1 / ( pow( k, c2_n ) + 1 );
+ z = pow( k2, cn_2 );
+ if( zi == 1 )
+ z *= k;
+ c = pow( 1 - pow( z, c2_n ), cn_e );
+
+ for( v = 0; v < ( vStep + 1 ); v++ )
+ {
+ dv = ( double ) v / ( double ) vStep;
+ a = tan( M_PI / 4.0 * pow( dv, e < 1.0 ? e : sqrt( e ) ) );
+ a2 = 1 + pow( a, c2_e );
+ x = pow( c / a2, ce_2 );
+ y = x * a;
+
+ points[pbase+v] = PMPoint( x, y, z );
+ }
+ // 1/8
+
+ pref = pbase + 2 * vStep;
+ for( v = 0; v < vStep; v++, pref-- )
+ {
+ p = points[pbase+v];
+ x = p[0];
+ p[0] = p[1];
+ p[1] = x;
+ points[pref] = p;
+ }
+ // 1/4
+
+ pref = pbase + 4 * vStep;
+ for( v = 0; v < ( 2 * vStep ); v++, pref-- )
+ {
+ p = points[pbase+v];
+ p[0] = -p[0];
+ points[pref] = p;
+ }
+ // 1/2
+
+ pref = pbase + 8 * vStep - 1;
+ for( v = 1; v < ( 4 * vStep ); v++, pref-- )
+ {
+ p = points[pbase+v];
+ p[1] = -p[1];
+ points[pref] = p;
+ }
+
+ pbase += 8 * vStep;
+ }
+ }
+
+ for( u = 0; u < ( uStep * 2 - 1 ); u++ )
+ {
+ pbase = 1 + u * vStep * 8;
+ pref = 1 + ( uStep * 4 - 2 - u ) * vStep * 8;
+
+ for( v = 0; v < ( vStep * 8 ); v++, pref++ )
+ {
+ p = points[pbase + v];
+ p[2] = -p[2];
+ points[pref] = p;
+ }
+ }
+ points[ vStep * 8 * ( uStep * 4 - 1 ) + 1 ] = PMPoint( 0, 0, -1 );
+}
+
+void PMSuperquadricEllipsoid::setUSteps( int u )
+{
+ if( u >= 2 )
+ {
+ s_uStep = u;
+ if( s_pDefaultViewStructure )
+ {
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ }
+ }
+ else
+ kdDebug( PMArea ) << "PMSuperquadricEllipsoid::setUSteps: U must be greater than 1\n";
+ s_parameterKey++;
+}
+
+void PMSuperquadricEllipsoid::setVSteps( int v )
+{
+ if( v >= 2 )
+ {
+ s_vStep = v;
+ if( s_pDefaultViewStructure )
+ {
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ }
+ }
+ else
+ kdDebug( PMArea ) << "PMSuperquadricEllipsoid::setVSteps: V must be greater than 1\n";
+ s_parameterKey++;
+}
+
+void PMSuperquadricEllipsoid::cleanUp( ) const
+{
+ if( s_pDefaultViewStructure )
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
diff --git a/kpovmodeler/pmsqe.h b/kpovmodeler/pmsqe.h
new file mode 100644
index 00000000..e2d04c60
--- /dev/null
+++ b/kpovmodeler/pmsqe.h
@@ -0,0 +1,155 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMSQE_H
+#define PMSQE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobject.h"
+#include "pmvector.h"
+#include "pmpoint.h"
+#include "pmline.h"
+
+class PMViewStructure;
+
+/**
+ * Class for povray superquadric ellipsoids.
+ */
+
+class PMSuperquadricEllipsoid : public PMSolidObject
+{
+ typedef PMSolidObject Base;
+public:
+ /**
+ * Creates an empty PMSuperquadricEllipsoid
+ */
+ PMSuperquadricEllipsoid( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMSuperquadricEllipsoid( const PMSuperquadricEllipsoid& s );
+ /**
+ * deletes the PMSuperquadricEllipsoid
+ */
+ virtual ~PMSuperquadricEllipsoid( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMSuperquadricEllipsoid( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMSuperquadricEllipsoidEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmsqe" ); }
+
+ /**
+ * Returns the east west exponent
+ */
+ double eastWestExponent( ) const { return m_eastWestExponent; }
+ /**
+ * Sets the east west exponent
+ */
+ void setEastWestExponent( double e );
+ /**
+ * Returns the north south exponent
+ */
+ double northSouthExponent( ) const { return m_northSouthExponent; }
+ /**
+ * Sets the north south exponent
+ */
+ void setNorthSouthExponent( double n );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /** */
+ virtual bool hasDisplayDetail( ) const { return true; }
+
+ /**
+ * Sets the number of latitutes
+ */
+ static void setUSteps( int u );
+ /**
+ * Sets the number of longitudes
+ */
+ static void setVSteps( int v );
+ /**
+ * Returns the number or latitutes
+ */
+ static int uSteps( ) { return s_uStep; }
+ /**
+ * Returns the number or longitudes
+ */
+ static int vSteps( ) { return s_vStep; }
+ /** */
+ virtual void cleanUp( ) const;
+
+protected:
+ /** */
+ virtual bool isDefault( );
+ /** */
+ virtual void createViewStructure( );
+ /** */
+ virtual PMViewStructure* defaultViewStructure( ) const;
+ /** */
+ virtual int viewStructureParameterKey( ) const { return s_parameterKey + globalDetailKey( ); }
+
+private:
+ /**
+ * Creates the lines for the view structure
+ */
+ static void createLines( PMLineArray& lines, int uStep, int vStep );
+ /**
+ * Creates the points for the view structure
+ */
+ static void createPoints( PMPointArray& points, double e, double n, int uStep, int vStep );
+
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMSQEMementoID { PMEastWestExponentID, PMNorthSouthExponentID };
+ double m_eastWestExponent, m_northSouthExponent;
+
+ /**
+ * The default view structure. It can be shared between sqe's
+ */
+ static PMViewStructure* s_pDefaultViewStructure;
+ static int s_vStep;
+ static int s_uStep;
+ static int s_parameterKey;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmsqeedit.cpp b/kpovmodeler/pmsqeedit.cpp
new file mode 100644
index 00000000..488ce2f2
--- /dev/null
+++ b/kpovmodeler/pmsqeedit.cpp
@@ -0,0 +1,93 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmsqeedit.h"
+#include "pmsqe.h"
+#include "pmlineedits.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <klocale.h>
+
+PMSuperquadricEllipsoidEdit::PMSuperquadricEllipsoidEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMSuperquadricEllipsoidEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ m_pValueE = new PMFloatEdit( this );
+ m_pValueE->setValidation( true, 0.01, false, 1.0 );
+ m_pValueN = new PMFloatEdit( this );
+ m_pValueN->setValidation( true, 0.01, false, 1.0 );
+
+ topLayout( )->addWidget( new QLabel( i18n( "Exponents:" ), this ) );
+
+ QHBoxLayout* hl = new QHBoxLayout( topLayout( ) );
+ QGridLayout* gl = new QGridLayout( hl, 2, 2 );
+ gl->addWidget( new QLabel( i18n( "East-west:" ), this ), 0, 0 );
+ gl->addWidget( m_pValueE, 0, 1 );
+ gl->addWidget( new QLabel( i18n( "North-south:" ), this ), 1, 0 );
+ gl->addWidget( m_pValueN, 1, 1 );
+ hl->addStretch( 1 );
+
+ connect( m_pValueE, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pValueN, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMSuperquadricEllipsoidEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "SuperquadricEllipsoid" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMSuperquadricEllipsoid* ) o;
+
+ m_pValueE->setValue( m_pDisplayedObject->eastWestExponent( ) );
+ m_pValueN->setValue( m_pDisplayedObject->northSouthExponent( ) );
+
+ m_pValueE->setReadOnly( readOnly );
+ m_pValueN->setReadOnly( readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMSuperquadricEllipsoidEdit: Can't display object\n";
+}
+
+void PMSuperquadricEllipsoidEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setEastWestExponent( m_pValueE->value( ) );
+ m_pDisplayedObject->setNorthSouthExponent( m_pValueN->value( ) );
+ }
+}
+
+bool PMSuperquadricEllipsoidEdit::isDataValid( )
+{
+ if( m_pValueE->isDataValid( ) )
+ if( m_pValueN->isDataValid( ) )
+ return Base::isDataValid( );
+ return false;
+}
+
+#include "pmsqeedit.moc"
diff --git a/kpovmodeler/pmsqeedit.h b/kpovmodeler/pmsqeedit.h
new file mode 100644
index 00000000..45ae1a2f
--- /dev/null
+++ b/kpovmodeler/pmsqeedit.h
@@ -0,0 +1,63 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMSQEEDIT_H
+#define PMSQEEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobjectedit.h"
+
+class PMSuperquadricEllipsoid;
+class PMFloatEdit;
+
+/**
+ * Dialog edit class for @ref PMSuperquadricEllipsoid
+ */
+class PMSuperquadricEllipsoidEdit : public PMSolidObjectEdit
+{
+ Q_OBJECT
+ typedef PMSolidObjectEdit Base;
+public:
+ /**
+ * Creates a PMSuperquadricEllipsoidEdit with parent and name
+ */
+ PMSuperquadricEllipsoidEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMSuperquadricEllipsoid* m_pDisplayedObject;
+ PMFloatEdit* m_pValueE;
+ PMFloatEdit* m_pValueN;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmsymboltable.cpp b/kpovmodeler/pmsymboltable.cpp
new file mode 100644
index 00000000..bd1aab3b
--- /dev/null
+++ b/kpovmodeler/pmsymboltable.cpp
@@ -0,0 +1,121 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmsymboltable.h"
+#include "pmdeclare.h"
+#include "pmdebug.h"
+
+#include <string.h>
+
+PMSymbol::PMSymbol( const QString& id, PMDeclare* o )
+{
+ setId( id );
+ m_type = Object;
+ m_pObj = o;
+ m_pVal = 0;
+ m_pRenamedSymbol = 0;
+}
+
+PMSymbol::PMSymbol( const QString& id, const PMValue& v )
+{
+ setId( id );
+ m_type = Value;
+ m_pObj = 0;
+ m_pVal = new PMValue( v );
+ m_pRenamedSymbol = 0;
+}
+
+PMSymbol::~PMSymbol( )
+{
+ if( m_pVal )
+ delete m_pVal;
+}
+
+void PMSymbol::setId( const QString& id )
+{
+ m_id = id.left( MaxIDLength );
+}
+
+PMDeclare* PMSymbol::object( ) const
+{
+ if( m_type == Object )
+ return m_pObj;
+ kdError( PMArea ) << "Symbol is not an object\n";
+ return 0;
+}
+
+PMValue PMSymbol::value( ) const
+{
+ if( m_type == Value )
+ return *m_pVal;
+ kdError( PMArea ) << "Symbol is not a value\n";
+ return PMValue( );
+}
+
+
+PMSymbolTable::PMSymbolTable( )
+ : QDict<PMSymbol>( 1009 ), m_lastID( 47 )
+{
+ setAutoDelete( true );
+ m_lastID.setAutoDelete( true );
+}
+
+PMSymbolTable::~PMSymbolTable( )
+{
+ clear( );
+}
+
+QString PMSymbolTable::findNewID( const QString& prefix )
+{
+ PMSymbol* symbol;
+ QString testID;
+ unsigned int number;
+
+ int* lastNumber = m_lastID.find( prefix );
+ if( lastNumber )
+ number = *lastNumber + 1;
+ else
+ number = 0;
+
+ // find next free id
+ do
+ {
+ testID = prefix + QString( "%1" ).arg( number );
+ symbol = find( testID );
+ if( symbol )
+ number++;
+ }
+ while( symbol );
+
+ if( lastNumber )
+ *lastNumber = number;
+ else
+ m_lastID.insert( prefix, new int( number ) );
+
+ return testID;
+}
+
+PMSymbol* PMSymbolTable::findNewID( const QString& prefix, PMDeclare* obj )
+{
+ QString newID = findNewID( prefix );
+ obj->setID( newID );
+
+ PMSymbol* s = new PMSymbol( newID, obj );
+// insert( newID, s );
+
+ return s;
+}
diff --git a/kpovmodeler/pmsymboltable.h b/kpovmodeler/pmsymboltable.h
new file mode 100644
index 00000000..27e88785
--- /dev/null
+++ b/kpovmodeler/pmsymboltable.h
@@ -0,0 +1,128 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMSYMBOLTABLE_H
+#define PMSYMBOLTABLE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmvalue.h"
+class PMObject;
+class PMDeclare;
+
+#include <qdict.h>
+#include <qstring.h>
+
+/**
+ * Entry in a @ref PMSymbolTable. Can be a @ref PMValue or a @ref PMObject
+ */
+
+class PMSymbol
+{
+public:
+ enum PMSymbolType { Value, Object };
+ /**
+ * Creates a entry for an object
+ */
+ PMSymbol( const QString& id, PMDeclare* o );
+ /**
+ * Creates a entry for a value
+ */
+ PMSymbol( const QString& id, const PMValue& v );
+ /**
+ * Destructor
+ */
+ ~PMSymbol( );
+
+ /**
+ * Returns the type of the symbol
+ */
+ PMSymbolType type( ) const { return m_type; }
+ /**
+ * Returns the id of the symbol
+ */
+ QString id( ) const { return m_id; }
+ /**
+ * Sets the id
+ */
+ void setId( const QString& id );
+ /**
+ * Returns the stored object
+ */
+ PMDeclare* object( ) const;
+ /**
+ * Returns the stored value
+ */
+ PMValue value( ) const;
+ /**
+ * The maximum length for povray ids
+ */
+ static const unsigned int MaxIDLength = 40;
+ /**
+ * If the parser parses a declare object with this id, the
+ * new id is renamed. This function returns a pointer to the
+ * renamed symbol.
+ */
+ PMSymbol* renamedSymbol( ) const { return m_pRenamedSymbol; }
+ /**
+ * Sets the renamed declare object to symbol
+ */
+ void setRenamedSymbol( PMSymbol* symbol ) { m_pRenamedSymbol = symbol; }
+
+private:
+ PMSymbolType m_type;
+ PMDeclare* m_pObj;
+ PMSymbol* m_pRenamedSymbol;
+ PMValue* m_pVal;
+ QString m_id;
+};
+
+/**
+ * Symbol table for povray #declare statements
+ */
+class PMSymbolTable : public QDict<PMSymbol>
+{
+public:
+ /**
+ * Constructor
+ */
+ PMSymbolTable( );
+ /**
+ * Destructor
+ */
+ ~PMSymbolTable( );
+ /**
+ * Returns a free id with prefix prefix and a number as suffix
+ */
+ QString findNewID( const QString& prefix );
+ /**
+ * Returns a free id with prefix prefix and a number as suffix and assigns
+ * it to the object.
+ *
+ * Does NOT add the object to the symbol table.
+ *
+ * Returns the new symbol.*/
+ PMSymbol* findNewID( const QString& prefix, PMDeclare* obj );
+private:
+ QDict<int> m_lastID;
+};
+
+#endif
diff --git a/kpovmodeler/pmtext.cpp b/kpovmodeler/pmtext.cpp
new file mode 100644
index 00000000..21191cbc
--- /dev/null
+++ b/kpovmodeler/pmtext.cpp
@@ -0,0 +1,339 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmtext.h"
+
+#include "pmxmlhelper.h"
+#include "pmtextedit.h"
+#include "pmmemento.h"
+#include "pmviewstructure.h"
+#include "pmresourcelocator.h"
+#include "pmtruetypecache.h"
+#include "pmdefaults.h"
+
+#include <klocale.h>
+
+const QString c_defaultFont = QString( "" );
+const QString c_defaultText = QString( "" );
+const double c_defaultThickness = 1.0;
+const PMVector c_defaultOffset = PMVector( 0.0, 0.0 );
+
+int PMText::s_parameterKey = 0;
+int PMText::s_steps = c_defaultTextSteps;
+
+PMDefinePropertyClass( PMText, PMTextProperty );
+
+PMMetaObject* PMText::s_pMetaObject = 0;
+PMObject* createNewText( PMPart* part )
+{
+ return new PMText( part );
+}
+
+PMText::PMText( PMPart* part )
+ : Base( part )
+{
+ m_text = c_defaultText;
+ m_font = c_defaultFont;
+ m_thickness = c_defaultThickness;
+ m_offset = c_defaultOffset;
+}
+
+PMText::PMText( const PMText& t )
+ : Base( t )
+{
+ m_text = t.m_text;
+ m_font = t.m_font;
+ m_thickness = t.m_thickness;
+ m_offset = t.m_offset;
+}
+
+PMText::~PMText( )
+{
+}
+
+QString PMText::description( ) const
+{
+ return i18n( "text" );
+}
+
+void PMText::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "font", m_font );
+ e.setAttribute( "text", m_text );
+ e.setAttribute( "thickness", m_thickness );
+ e.setAttribute( "offset", m_offset.serializeXML( ) );
+ Base::serialize( e, doc );
+}
+
+void PMText::readAttributes( const PMXMLHelper& h )
+{
+ m_font = h.stringAttribute( "font", c_defaultFont );
+ m_text = h.stringAttribute( "text", c_defaultText );
+ m_thickness = h.doubleAttribute( "thickness", c_defaultThickness );
+ m_offset = h.vectorAttribute( "offset", c_defaultOffset );
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMText::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Text", Base::metaObject( ),
+ createNewText );
+ s_pMetaObject->addProperty(
+ new PMTextProperty( "font", &PMText::setFont, &PMText::font ) );
+ s_pMetaObject->addProperty(
+ new PMTextProperty( "text", &PMText::setText, &PMText::text ) );
+ s_pMetaObject->addProperty(
+ new PMTextProperty( "thickness", &PMText::setThickness, &PMText::thickness ) );
+ s_pMetaObject->addProperty(
+ new PMTextProperty( "offset", &PMText::setOffset, &PMText::offset ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMText::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMText::setFont( const QString& f )
+{
+ if( f != m_font )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFontID, m_font );
+ m_font = f;
+ setViewStructureChanged( );
+ }
+}
+
+void PMText::setText( const QString& t )
+{
+ if( t != m_text )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMTextID, m_text );
+ m_text = t;
+ setViewStructureChanged( );
+ }
+}
+
+void PMText::setThickness( double t )
+{
+ if( t != m_thickness )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMThicknessID, m_thickness );
+ m_thickness = t;
+ setViewStructureChanged( );
+ }
+}
+
+void PMText::setOffset( const PMVector& o )
+{
+ if( o != m_offset )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMOffsetID, m_offset );
+ m_offset = o;
+ m_offset.resize( 2 );
+ setViewStructureChanged( );
+ }
+}
+
+PMDialogEditBase* PMText::editWidget( QWidget* parent ) const
+{
+ return new PMTextEdit( parent );
+}
+
+void PMText::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMFontID:
+ setFont( data->stringData( ) );
+ break;
+ case PMTextID:
+ setText( data->stringData( ) );
+ break;
+ case PMThicknessID:
+ setThickness( data->doubleData( ) );
+ break;
+ case PMOffsetID:
+ setOffset( data->vectorData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMText::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
+void PMText::createViewStructure( )
+{
+ // calculate needed points and lines
+ int nlines = 0, npoints = 0;
+
+ QString file = PMResourceLocator::findFile( m_font );
+ PMTrueTypeFont* font = PMTrueTypeCache::font( file );
+
+ if( font && font->isValid( ) )
+ {
+ QTextStream str( &m_text, IO_ReadOnly );
+ QChar c;
+ PMTrueTypeOutline* ol;
+
+ while( !str.atEnd( ) )
+ {
+ str >> c;
+ ol = font->outline( c );
+ if( ol )
+ {
+ npoints += ol->segments( ) * 2 * s_steps;
+ nlines += ol->segments( ) * ( 2 * s_steps + 1 );
+ }
+ }
+ }
+
+ if( !m_pViewStructure )
+ m_pViewStructure = new PMViewStructure( npoints, nlines );
+ else
+ {
+ if( m_pViewStructure->points( ).size( ) != ( unsigned ) npoints )
+ m_pViewStructure->points( ).resize( npoints );
+ if( m_pViewStructure->lines( ).size( ) != ( unsigned ) nlines )
+ m_pViewStructure->lines( ).resize( nlines );
+ }
+
+ if( ( nlines > 0 ) && ( npoints > 0 ) && font )
+ {
+ // create the view structure
+ QTextStream str( &m_text, IO_ReadOnly );
+ QChar c, oldc;
+ PMTrueTypeOutline* ol;
+ double dp = 1.0 / s_steps;
+ int i;
+ int hnpoints = npoints / 2;
+ int pbase = 0;
+ int lbase = 0;
+ PMVector v2( 2 );
+ PMVector v3( 3 );
+ int firstPoint = 0;
+ PMVector coffset( 0.0, 0.0, 0.0 );
+ double kerning = 0;
+
+ PMPointArray& points = m_pViewStructure->points( );
+ PMLineArray& lines = m_pViewStructure->lines( );
+
+ while( !str.atEnd( ) )
+ {
+ // iterate over all characters with valid outline
+
+ str >> c;
+ ol = font->outline( c );
+ if( ol )
+ {
+ // kerning offset
+ kerning = font->kerning( oldc, c );
+ coffset[0] += kerning;
+
+ const PMSegmentListList& out = ol->outline( );
+ PMSegmentListList::ConstIterator oit;
+ for( oit = out.begin( ); oit != out.end( ); ++oit )
+ {
+ // iterate over all contours
+
+ PMSegmentList::ConstIterator sit;
+ PMSegmentList::ConstIterator eit = ( *oit ).end( );
+ eit--;
+
+ firstPoint = pbase;
+ for( sit = ( *oit ).begin( ); sit != ( *oit ).end( ); ++sit )
+ {
+ // iterate over all segments for the current contour
+
+ lines[lbase] = PMLine( pbase, pbase + hnpoints );
+ lbase++;
+
+ for( i = 0; i < s_steps; i++ )
+ {
+ v2 = ( *sit ).point( i * dp );
+ v3[0] = v2[0];
+ v3[1] = v2[1];
+ v3[2] = 0.0;
+ v3 += coffset;
+ points[pbase] = PMPoint( v3 );
+ v3[2] = m_thickness;
+ points[pbase + hnpoints] = PMPoint( v3 );
+
+ if( ( i != ( s_steps - 1 ) ) || ( sit != eit ) )
+ {
+ lines[lbase] = PMLine( pbase, pbase + 1 );
+ lbase++;
+ lines[lbase] = PMLine( pbase + hnpoints,
+ pbase + hnpoints + 1 );
+ lbase++;
+ }
+ else
+ {
+ lines[lbase] = PMLine( firstPoint, pbase );
+ lbase++;
+ lines[lbase] = PMLine( firstPoint + hnpoints,
+ pbase + hnpoints );
+ lbase++;
+ }
+
+ pbase++;
+ }
+ }
+ }
+ coffset[0] -= kerning;
+ coffset[0] += ol->advance( );
+ coffset += m_offset;
+ }
+ oldc = c;
+ }
+ if( ( lbase != nlines ) || ( pbase != hnpoints ) )
+ kdError( PMArea ) << "PMText::createViewStructure is buggy!\n";
+ }
+}
+
+void PMText::setSteps( int s )
+{
+ if( s >= 1 )
+ s_steps = s;
+ else
+ kdDebug( PMArea ) << "PMText::setSteps: S must be greater than 0\n";
+ s_parameterKey++;
+}
diff --git a/kpovmodeler/pmtext.h b/kpovmodeler/pmtext.h
new file mode 100644
index 00000000..3a7350bb
--- /dev/null
+++ b/kpovmodeler/pmtext.h
@@ -0,0 +1,147 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMTEXT_H
+#define PMTEXT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobject.h"
+#include "pmvector.h"
+
+class PMViewStructure;
+
+/**
+ * Class for povray truetype texts.
+ */
+
+class PMText : public PMSolidObject
+{
+ typedef PMSolidObject Base;
+public:
+ /**
+ * Creates an empty PMText
+ */
+ PMText( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMText( const PMText& t );
+ /**
+ * deletes the PMText
+ */
+ virtual ~PMText( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMText( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMTextEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmtext" ); }
+
+ /**
+ * Returns the font file
+ */
+ QString font( ) const { return m_font; }
+ /**
+ * Sets the font file
+ */
+ void setFont( const QString& f );
+ /**
+ * Returns the text
+ */
+ QString text( ) const { return m_text; }
+ /**
+ * Sets the text
+ */
+ void setText( const QString& t );
+ /**
+ * Returns the thickness
+ */
+ double thickness( ) const { return m_thickness; }
+ /**
+ * Sets the thickness
+ */
+ void setThickness( double t );
+ /**
+ * Returns the additional offset (2D vector)
+ */
+ PMVector offset( ) const { return m_offset; }
+ /**
+ * Sets the offset (2D vector)
+ */
+ void setOffset( const PMVector& o );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+
+ /**
+ * Call this if the povray library paths have changed
+ */
+ static void povrayLibraryPathsChanged( ) { s_parameterKey++; }
+ /**
+ * Returns the number of lines for rendering
+ */
+ static int steps( ) { return s_steps; }
+ /**
+ * Sets the number of lines for rendering
+ */
+ static void setSteps( int s );
+
+protected:
+ /** */
+ virtual void createViewStructure( );
+ /** */
+ virtual int viewStructureParameterKey( ) const { return s_parameterKey; }
+
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMTextMementoID { PMFontID, PMTextID, PMThicknessID, PMOffsetID };
+ QString m_font, m_text;
+ double m_thickness;
+ PMVector m_offset;
+
+ static int s_steps;
+ static int s_parameterKey;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmtextedit.cpp b/kpovmodeler/pmtextedit.cpp
new file mode 100644
index 00000000..16f8501d
--- /dev/null
+++ b/kpovmodeler/pmtextedit.cpp
@@ -0,0 +1,138 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmtextedit.h"
+#include "pmtext.h"
+#include "pmvectoredit.h"
+#include "pmlineedits.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qlineedit.h>
+#include <qpushbutton.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kfiledialog.h>
+
+PMTextEdit::PMTextEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMTextEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QHBoxLayout* hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "Font:" ), this ) );
+ m_pFont = new QLineEdit( this );
+ hl->addWidget( m_pFont );
+ m_pChooseFont = new QPushButton( this );
+ m_pChooseFont->setPixmap( SmallIcon( "fileopen" ) );
+ hl->addWidget( m_pChooseFont );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "Text:" ), this ) );
+ m_pText = new QLineEdit( this );
+ hl->addWidget( m_pText );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "Thickness:" ), this ) );
+ m_pThickness = new PMFloatEdit( this );
+ hl->addWidget( m_pThickness );
+ hl->addStretch( 1 );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( new QLabel( i18n( "Offset:" ), this ) );
+ m_pOffset = new PMVectorEdit( "x", "y", this );
+ hl->addWidget( m_pOffset );
+
+ connect( m_pFont, SIGNAL( textChanged( const QString& ) ),
+ SLOT( slotTextChanged( const QString& ) ) );
+ connect( m_pChooseFont, SIGNAL( clicked( ) ),
+ SLOT( slotChooseFont( ) ) );
+ connect( m_pText, SIGNAL( textChanged( const QString& ) ),
+ SLOT( slotTextChanged( const QString& ) ) );
+ connect( m_pThickness, SIGNAL( dataChanged( ) ),
+ SIGNAL( dataChanged( ) ) );
+ connect( m_pOffset, SIGNAL( dataChanged( ) ),
+ SIGNAL( dataChanged( ) ) );
+}
+
+void PMTextEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Text" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMText* ) o;
+
+ m_pFont->setText( m_pDisplayedObject->font( ) );
+ m_pText->setText( m_pDisplayedObject->text( ) );
+ m_pThickness->setValue( m_pDisplayedObject->thickness( ) );
+ m_pOffset->setVector( m_pDisplayedObject->offset( ) );
+
+ m_pFont->setReadOnly( readOnly );
+ m_pChooseFont->setEnabled( !readOnly );
+ m_pText->setReadOnly( readOnly );
+ m_pThickness->setReadOnly( readOnly );
+ m_pOffset->setReadOnly( readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMTextEdit: Can't display object\n";
+}
+
+void PMTextEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setFont( m_pFont->text( ) );
+ m_pDisplayedObject->setText( m_pText->text( ) );
+ m_pDisplayedObject->setThickness( m_pThickness->value( ) );
+ m_pDisplayedObject->setOffset( m_pOffset->vector( ) );
+ }
+}
+
+bool PMTextEdit::isDataValid( )
+{
+ if( m_pThickness->isDataValid( ) )
+ if( m_pOffset->isDataValid( ) )
+ return Base::isDataValid( );
+ return false;
+}
+
+void PMTextEdit::slotTextChanged( const QString& )
+{
+ emit dataChanged( );
+}
+
+void PMTextEdit::slotChooseFont( )
+{
+ QString str = KFileDialog::getOpenFileName( QString::null, QString::null );
+
+ if( !str.isEmpty() )
+ {
+ m_pFont->setText( str );
+ emit dataChanged( );
+ }
+}
+
+#include "pmtextedit.moc"
diff --git a/kpovmodeler/pmtextedit.h b/kpovmodeler/pmtextedit.h
new file mode 100644
index 00000000..3dd11280
--- /dev/null
+++ b/kpovmodeler/pmtextedit.h
@@ -0,0 +1,74 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMTEXTEDIT_H
+#define PMTEXTEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobjectedit.h"
+
+class PMText;
+class PMVectorEdit;
+class PMFloatEdit;
+class QLineEdit;
+class QPushButton;
+
+/**
+ * Dialog edit class for @ref PMText
+ */
+class PMTextEdit : public PMSolidObjectEdit
+{
+ Q_OBJECT
+ typedef PMSolidObjectEdit Base;
+public:
+ /**
+ * Creates a PMTextEdit with parent and name
+ */
+ PMTextEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+
+protected slots:
+ void slotTextChanged( const QString& t );
+ void slotChooseFont( );
+
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMText* m_pDisplayedObject;
+ QLineEdit* m_pFont;
+ QPushButton* m_pChooseFont;
+ QLineEdit* m_pText;
+ PMFloatEdit* m_pThickness;
+ PMVectorEdit* m_pOffset;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmtexture.cpp b/kpovmodeler/pmtexture.cpp
new file mode 100644
index 00000000..4b8a21ff
--- /dev/null
+++ b/kpovmodeler/pmtexture.cpp
@@ -0,0 +1,124 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001-2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmtexture.h"
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pmtextureedit.h"
+
+#include <klocale.h>
+
+PMDefinePropertyClass( PMTexture, PMTextureProperty );
+
+PMMetaObject* PMTexture::s_pMetaObject = 0;
+PMObject* createNewTexture( PMPart* part )
+{
+ return new PMTexture( part );
+}
+
+PMTexture::PMTexture( PMPart* part ) : Base( part )
+{
+ m_uvMapping = false;
+}
+
+PMTexture::PMTexture( const PMTexture& t ) : Base( t )
+{
+ m_uvMapping = t.m_uvMapping;
+}
+
+PMTexture::~PMTexture( )
+{
+}
+
+PMMetaObject* PMTexture::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Texture", Base::metaObject( ),
+ createNewTexture );
+ s_pMetaObject->addProperty(
+ new PMTextureProperty( "uvMapping", &PMTexture::setUVMapping, &PMTexture::uvMapping ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMTexture::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMTexture::description( ) const
+{
+ return i18n( "texture" );
+}
+
+PMDialogEditBase* PMTexture::editWidget( QWidget* parent ) const
+{
+ return new PMTextureEdit( parent );
+}
+
+void PMTexture::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "uv_mapping", m_uvMapping );
+ Base::serialize( e, doc );
+}
+
+void PMTexture::readAttributes( const PMXMLHelper& h )
+{
+ m_uvMapping = h.boolAttribute( "uv_mapping", false );
+ Base::readAttributes( h );
+}
+
+void PMTexture::setUVMapping( bool m )
+{
+ if( m != m_uvMapping )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMUVMappingID, m_uvMapping );
+ m_uvMapping = m;
+ }
+}
+
+void PMTexture::restoreMemento( PMMemento *s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMUVMappingID:
+ setUVMapping( data->boolData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMTexture::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmtexture.h b/kpovmodeler/pmtexture.h
new file mode 100644
index 00000000..b8b176db
--- /dev/null
+++ b/kpovmodeler/pmtexture.h
@@ -0,0 +1,95 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001-2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMTEXTURE_H
+#define PMTEXTURE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebase.h"
+
+/**
+ * Class for povray textures
+ */
+class PMTexture : public PMTextureBase
+{
+ typedef PMTextureBase Base;
+public:
+ /**
+ * Creates an PMTexture
+ */
+ PMTexture( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMTexture( const PMTexture& t );
+ /**
+ * Deletes the object
+ */
+ virtual ~PMTexture( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMTexture( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMTextureEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmtexture" ); }
+
+ /**
+ * Returns the uv mapping flag
+ */
+ bool uvMapping() const { return m_uvMapping; }
+ /**
+ * Sets the uv maaping flag
+ */
+ void setUVMapping( bool m );
+
+ /** */
+ virtual void restoreMemento( PMMemento *s );
+
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMPigmentMementoID { PMUVMappingID };
+
+ bool m_uvMapping;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmtexturebase.cpp b/kpovmodeler/pmtexturebase.cpp
new file mode 100644
index 00000000..82a92418
--- /dev/null
+++ b/kpovmodeler/pmtexturebase.cpp
@@ -0,0 +1,180 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmtexturebase.h"
+#include "pmdeclare.h"
+#include "pmpart.h"
+#include "pmsymboltable.h"
+#include "pmtexturebaseedit.h"
+#include "pmparser.h"
+
+#include "pmmemento.h"
+#include "pmxmlhelper.h"
+
+#include <klocale.h>
+
+PMDefinePropertyClass( PMTextureBase, PMTextureBaseProperty );
+
+PMMetaObject* PMTextureBase::s_pMetaObject = 0;
+
+PMTextureBase::PMTextureBase( PMPart* part )
+ : Base( part )
+{
+ m_pLinkedObject = 0;
+}
+
+PMTextureBase::PMTextureBase( const PMTextureBase& b )
+ : Base( b )
+{
+ m_pLinkedObject = 0;
+ setLinkedObject( b.m_pLinkedObject );
+}
+
+PMTextureBase::~PMTextureBase( )
+{
+}
+
+PMMetaObject* PMTextureBase::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "TextureBase", Base::metaObject( ) );
+ s_pMetaObject->addProperty(
+ new PMTextureBaseProperty( "linkedObject", &PMTextureBase::setLinkedObjectProperty,
+ &PMTextureBase::linkedObjectProperty ) );
+ s_pMetaObject->addProperty(
+ new PMTextureBaseProperty( "hasLinkedObject", 0, &PMTextureBase::hasLinkedObject ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMTextureBase::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+bool PMTextureBase::setLinkedObject( PMDeclare* obj )
+{
+ if( obj )
+ {
+ if( obj->declareType( ) == type( ) )
+ {
+ if( m_pLinkedObject != obj )
+ {
+ if( m_pMemento )
+ {
+ m_pMemento->addData( s_pMetaObject, PMLinkedObjectID,
+ m_pLinkedObject );
+ m_pMemento->setViewStructureChanged( );
+ }
+
+ if( m_pLinkedObject )
+ {
+ m_pLinkedObject->removeLinkedObject( this );
+ if( m_pMemento )
+ m_pMemento->addChangedObject( m_pLinkedObject, PMCData );
+ }
+ m_pLinkedObject = obj;
+ m_pLinkedObject->addLinkedObject( this );
+ if( m_pMemento )
+ m_pMemento->addChangedObject( m_pLinkedObject, PMCData );
+ }
+ return true;
+ }
+ }
+ else
+ {
+ if( m_pLinkedObject != 0 )
+ {
+ if( m_pMemento )
+ {
+ m_pMemento->addData( s_pMetaObject, PMLinkedObjectID,
+ m_pLinkedObject );
+ m_pMemento->addChangedObject( m_pLinkedObject, PMCData );
+ }
+ m_pLinkedObject->removeLinkedObject( this );
+ m_pLinkedObject = 0;
+ }
+ return true;
+ }
+ return false;
+}
+
+void PMTextureBase::setLinkedObjectProperty( PMObject* o )
+{
+ if( o == 0 )
+ setLinkedObject( 0 );
+ else if( o->isA( "Declare" ) )
+ setLinkedObject( ( PMDeclare* ) o );
+}
+
+void PMTextureBase::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ if( m_pLinkedObject )
+ e.setAttribute( "prototype", m_pLinkedObject->id( ) );
+ Base::serialize( e, doc );
+}
+
+void PMTextureBase::readAttributes( const PMXMLHelper& h )
+{
+ QString id = h.stringAttribute( "prototype", "" );
+ if( !id.isEmpty( ) )
+ {
+ PMDeclare* link = h.parser( )->checkLink( id );
+ if( link )
+ {
+ if( link->declareType( ) == type( ) )
+ {
+ m_pLinkedObject = link;
+ m_pLinkedObject->addLinkedObject( this );
+ }
+ else
+ h.parser( )->printError( i18n( "Declare \"%1\" has wrong type." )
+ .arg( id ) );
+ }
+ }
+}
+
+void PMTextureBase::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMLinkedObjectID:
+ setLinkedObject( ( PMDeclare* ) data->objectData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMTextureBase::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmtexturebase.h b/kpovmodeler/pmtexturebase.h
new file mode 100644
index 00000000..2bd687f6
--- /dev/null
+++ b/kpovmodeler/pmtexturebase.h
@@ -0,0 +1,96 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMTEXTUREBASE_H
+#define PMTEXTUREBASE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qvaluelist.h>
+
+#include "pmnamedobject.h"
+#include "pmdeclare.h"
+
+/**
+ * Base class for all textures that can link to declares
+ */
+class PMTextureBase : public PMNamedObject
+{
+ typedef PMNamedObject Base;
+public:
+ /**
+ * Creates an PMTextureBase
+ */
+ PMTextureBase( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMTextureBase( const PMTextureBase& b );
+ /**
+ * Deletes the object
+ */
+ virtual ~PMTextureBase( );
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+
+ /** */
+ virtual PMDeclare* linkedObject( ) const { return m_pLinkedObject; }
+ /**
+ * Sets the linked object. Returns true if successful
+ */
+ bool setLinkedObject( PMDeclare* o );
+ /**
+ * Returns true if a linked object is set. Used by the
+ * insert possibilities framework.
+ */
+ bool hasLinkedObject( ) const { return m_pLinkedObject; }
+
+ /**
+ * Method used by the properties framework
+ */
+ PMObject* linkedObjectProperty( ) const { return m_pLinkedObject; }
+ /**
+ * Method used by the properties framework
+ */
+ void setLinkedObjectProperty( PMObject* o );
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMTextureBaseMementoID { PMLinkedObjectID };
+ PMDeclare* m_pLinkedObject;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmtexturebaseedit.cpp b/kpovmodeler/pmtexturebaseedit.cpp
new file mode 100644
index 00000000..e9b91486
--- /dev/null
+++ b/kpovmodeler/pmtexturebaseedit.cpp
@@ -0,0 +1,72 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmtexturebaseedit.h"
+#include "pmpigment.h"
+#include "pmlinkedit.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <klocale.h>
+
+
+PMTextureBaseEdit::PMTextureBaseEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+
+void PMTextureBaseEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+ m_pLinkEdit = new PMLinkEdit( this );
+ topLayout( )->addWidget( m_pLinkEdit );
+ connect( m_pLinkEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+
+void PMTextureBaseEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "TextureBase" ) )
+ {
+ m_pDisplayedObject = ( PMTextureBase* ) o;
+ m_pLinkEdit->setReadOnly( o->isReadOnly( ) );
+ m_pLinkEdit->setDisplayedObject( o );
+ m_pLinkEdit->setLinkPossibility( m_pDisplayedObject->type( ) );
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMTextureBaseEdit: Can't display object\n";
+}
+
+void PMTextureBaseEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setLinkedObject( m_pLinkEdit->link( ) );
+ }
+}
+
+void PMTextureBaseEdit::enableLinkEdit( bool enable )
+{
+ m_pLinkEdit->setEnabled( enable );
+}
+
+#include "pmtexturebaseedit.moc"
diff --git a/kpovmodeler/pmtexturebaseedit.h b/kpovmodeler/pmtexturebaseedit.h
new file mode 100644
index 00000000..b8d67f56
--- /dev/null
+++ b/kpovmodeler/pmtexturebaseedit.h
@@ -0,0 +1,64 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMTEXTUREBASEEDIT_H
+#define PMTEXTUREBASEEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmnamedobjectedit.h"
+
+class PMTextureBase;
+class PMLinkEdit;
+
+/**
+ * Dialog edit class for @ref PMTextureBase
+ */
+class PMTextureBaseEdit : public PMNamedObjectEdit
+{
+ Q_OBJECT
+ typedef PMNamedObjectEdit Base;
+public:
+ /**
+ * Creates a PMTextureBaseEdit with parent and name
+ */
+ PMTextureBaseEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+ /**
+ * Enables/disables the link edit widget
+ */
+ void enableLinkEdit( bool enable );
+
+private:
+ PMTextureBase* m_pDisplayedObject;
+ PMLinkEdit* m_pLinkEdit;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmtextureedit.cpp b/kpovmodeler/pmtextureedit.cpp
new file mode 100644
index 00000000..8a3d4f9f
--- /dev/null
+++ b/kpovmodeler/pmtextureedit.cpp
@@ -0,0 +1,67 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmtextureedit.h"
+#include "pmtexture.h"
+#include "pmlinkedit.h"
+
+#include <qlayout.h>
+#include <qcheckbox.h>
+#include <klocale.h>
+
+
+PMTextureEdit::PMTextureEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMTextureEdit::createTopWidgets()
+{
+ Base::createTopWidgets();
+ m_pUVMapping = new QCheckBox( i18n( "UV mapping" ), this );
+ topLayout( )->addWidget( m_pUVMapping );
+
+ connect( m_pUVMapping, SIGNAL( clicked() ), SIGNAL( dataChanged() ) );
+}
+
+void PMTextureEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Texture" ) )
+ {
+ m_pDisplayedObject = ( PMTexture* ) o;
+ bool readOnly = m_pDisplayedObject->isReadOnly( );
+ m_pUVMapping->setChecked( m_pDisplayedObject->uvMapping() );
+ m_pUVMapping->setEnabled( !readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMTextureEdit: Can't display object\n";
+}
+
+void PMTextureEdit::saveContents()
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents();
+ m_pDisplayedObject->setUVMapping( m_pUVMapping->isChecked() );
+ }
+}
+
+#include "pmtextureedit.moc"
diff --git a/kpovmodeler/pmtextureedit.h b/kpovmodeler/pmtextureedit.h
new file mode 100644
index 00000000..7b799a5e
--- /dev/null
+++ b/kpovmodeler/pmtextureedit.h
@@ -0,0 +1,60 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMTEXTUREEDIT_H
+#define PMTEXTUREEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebaseedit.h"
+
+class PMTexture;
+class QCheckBox;
+
+/**
+ * Dialog edit class for @ref PMTexture
+ */
+class PMTextureEdit : public PMTextureBaseEdit
+{
+ Q_OBJECT
+ typedef PMTextureBaseEdit Base;
+public:
+ /**
+ * Creates a PMTextureEdit with parent and name
+ */
+ PMTextureEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMTexture* m_pDisplayedObject;
+ QCheckBox* m_pUVMapping;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmtexturemap.cpp b/kpovmodeler/pmtexturemap.cpp
new file mode 100644
index 00000000..fad93c61
--- /dev/null
+++ b/kpovmodeler/pmtexturemap.cpp
@@ -0,0 +1,601 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmtexturemapedit.h"
+#include "pmtexturemap.h"
+
+#include "pmxmlhelper.h"
+#include "pmmapmemento.h"
+
+#include <qtextstream.h>
+#include <klocale.h>
+
+class PMValueProperty : public PMPropertyBase
+{
+public:
+ PMValueProperty( )
+ : PMPropertyBase( "mapValues", PMVariant::Double )
+ {
+ m_index = 0;
+ }
+ virtual int dimensions( ) const { return 1; }
+ virtual void setIndex( int /*dimension*/, int index )
+ {
+ m_index = index;
+ }
+ virtual int size( PMObject* object, int /*dimension*/ ) const
+ {
+ return ( ( PMTextureMapBase* ) object )->mapEntries( );
+ }
+protected:
+ virtual bool setProtected( PMObject* obj, const PMVariant& var )
+ {
+ PMTextureMapBase* m = ( PMTextureMapBase* ) obj;
+ QValueList<double> list = m->mapValues( );
+ QValueList<double>::Iterator it = list.at( m_index );
+
+ if( it == list.end( ) )
+ {
+ kdError( PMArea ) << "Range error in PMTextureMapBase::ValueProperty::set" << endl;
+ return false;
+ }
+
+ *it = var.doubleData( );
+
+ m->setMapValues( list );
+ return true;
+ }
+ virtual PMVariant getProtected( const PMObject* obj )
+ {
+ PMTextureMapBase* m = ( PMTextureMapBase* ) obj;
+ QValueList<double> list = m->mapValues( );
+ QValueList<double>::ConstIterator it = list.at( m_index );
+
+ if( it == list.end( ) )
+ {
+ kdError( PMArea ) << "Range error in PMTextureMapBase::ValueProperty::get" << endl;
+ return PMVariant( );
+ }
+
+ return PMVariant( *it );
+ }
+
+private:
+ int m_index;
+};
+
+
+PMMetaObject* PMTextureMapBase::s_pMetaObject = 0;
+
+PMTextureMapBase::PMTextureMapBase( PMPart* part )
+ : Base( part )
+{
+}
+
+PMTextureMapBase::PMTextureMapBase( const PMTextureMapBase& m )
+ : Base( m )
+{
+}
+
+PMTextureMapBase::~PMTextureMapBase( )
+{
+}
+
+void PMTextureMapBase::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "map_values", valuesToString( ) );
+ Base::serialize( e, doc );
+}
+
+void PMTextureMapBase::readAttributes( const PMXMLHelper& h )
+{
+ stringToValues( h.stringAttribute( "map_values", "" ) );
+ Base::readAttributes( h );
+}
+
+QString PMTextureMapBase::valuesToString( ) const
+{
+ QString str;
+ QValueList<double>::ConstIterator it;
+
+ it = m_mapValues.begin( );
+ if( it != m_mapValues.end( ) )
+ {
+ str.setNum( *it );
+ ++it;
+ for( ; it != m_mapValues.end( ); ++it )
+ str += QString( " %1" ).arg( *it );
+ }
+ return str;
+}
+
+void PMTextureMapBase::stringToValues( const QString& str )
+{
+ m_mapValues.clear( );
+ QString tstr = str;
+ QTextIStream s( &tstr );
+ double d;
+
+ while( !s.atEnd( ) )
+ {
+ s >> d;
+ m_mapValues.append( d );
+ }
+}
+
+PMMetaObject* PMTextureMapBase::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "TextureMapBase", Base::metaObject( ) );
+ s_pMetaObject->addProperty( new PMValueProperty( ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMTextureMapBase::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+PMDialogEditBase* PMTextureMapBase::editWidget( QWidget* parent ) const
+{
+ return new PMTextureMapEdit( parent );
+}
+
+void PMTextureMapBase::restoreMemento( PMMemento* s )
+{
+ PMMapMemento* m = ( PMMapMemento* ) s;
+ if( m->mapValuesSaved( ) )
+ {
+ if( m_pMemento )
+ ( ( PMMapMemento* ) m_pMemento )->setMapValues( m_mapValues );
+ m_mapValues = m->mapValues( );
+ }
+ if( m->removedValuesSaved( ) )
+ {
+ if( m_pMemento )
+ ( ( PMMapMemento* ) m_pMemento )->setRemovedValues( m_removedValues );
+ m_removedValues = m->removedValues( );
+ }
+
+ Base::restoreMemento( s );
+}
+
+void PMTextureMapBase::createMemento( )
+{
+ if( m_pMemento )
+ delete m_pMemento;
+ m_pMemento = new PMMapMemento( this );
+}
+
+QValueList<double>::Iterator PMTextureMapBase::valueForChild( PMObject* obj )
+{
+ PMObject* o = firstChild( );
+ QValueList<double>::Iterator it = m_mapValues.begin( );
+
+ while( o && ( o != obj ) )
+ {
+ if( o->type( ) == mapType( ) )
+ ++it;
+ o = o->nextSibling( );
+ }
+ return it;
+}
+
+double PMTextureMapBase::mapValue( const PMObject* obj ) const
+{
+ PMObject* o = firstChild( );
+ QValueList<double>::ConstIterator it = m_mapValues.begin( );
+
+ while( o && ( o != obj ) )
+ {
+ if( o->type( ) == mapType( ) )
+ ++it;
+ o = o->nextSibling( );
+ }
+ return *it;
+}
+
+void PMTextureMapBase::childAdded( PMObject* ao )
+{
+ if( ( unsigned ) countChildren( ) <= m_mapValues.count( ) )
+ return;
+
+ if( m_pMemento )
+ ( ( PMMapMemento* ) m_pMemento )->setMapValues( m_mapValues );
+ if( m_removedValues.isEmpty( ) )
+ {
+ QValueList<double>::Iterator it = valueForChild( ao );
+ if( it == m_mapValues.end( ) )
+ {
+ --it;
+ if( it == m_mapValues.end( ) )
+ m_mapValues.append( 0.0 );
+ else
+ {
+ double v = *it + 0.1;
+ if( v > 1.0 )
+ v = 1.0;
+ m_mapValues.append( v );
+ }
+ }
+ else if( it == m_mapValues.begin( ) )
+ m_mapValues.prepend( 0.0 );
+ else
+ {
+ double va = *it;
+ double vb = *( --it );
+ m_mapValues.insert( ++it, ( va + vb ) / 2.0 );
+ }
+ }
+ else
+ {
+ if( m_pMemento )
+ ( ( PMMapMemento* ) m_pMemento )->setRemovedValues( m_removedValues );
+
+ QValueList<double>::Iterator it = m_mapValues.begin( );
+ bool stop = false;
+ double v = m_removedValues.last( );
+ m_removedValues.remove( m_removedValues.fromLast( ) );
+
+ while( ( it != m_mapValues.end( ) ) && !stop )
+ {
+ if( ( *it ) > v )
+ stop = true;
+ else
+ ++it;
+ }
+ m_mapValues.insert( it, v );
+ }
+}
+
+bool PMTextureMapBase::takeChild( PMObject* o )
+{
+ if( m_pMemento )
+ {
+ ( ( PMMapMemento* ) m_pMemento )->setMapValues( m_mapValues );
+ ( ( PMMapMemento* ) m_pMemento )->setRemovedValues( m_removedValues );
+ }
+
+ QValueList<double>::Iterator it = valueForChild( o );
+ if( it != m_mapValues.end( ) )
+ {
+ m_removedValues.append( *it );
+ m_mapValues.remove( it );
+ }
+
+ return Base::takeChild( o );
+}
+
+void PMTextureMapBase::setMapValues( const QValueList<double>& v )
+{
+ if( m_pMemento )
+ {
+ ( ( PMMapMemento* ) m_pMemento )->setMapValues( m_mapValues );
+ ( ( PMMapMemento* ) m_pMemento )->setRemovedValues( m_removedValues );
+ }
+ m_removedValues.clear( );
+ m_mapValues = v;
+}
+
+PMObject* PMTextureMapBase::nextMapEntry( PMObject* o )
+{
+ bool stop = false;
+ PMObject* result = o;
+
+ do
+ {
+ if( result == 0 )
+ result = firstChild( );
+ else
+ result = result->nextSibling( );
+
+ if( !result )
+ stop = true;
+ else if( result->type( ) == mapType( ) )
+ stop = true;
+ }
+ while( !stop );
+
+ return result;
+}
+
+
+PMMetaObject* PMTextureMap::s_pMetaObject = 0;
+PMObject* createNewTextureMap( PMPart* part )
+{
+ return new PMTextureMap( part );
+}
+
+PMTextureMap::PMTextureMap( PMPart* part )
+ : Base( part )
+{
+}
+
+PMTextureMap::PMTextureMap( const PMTextureMap& m )
+ : Base( m )
+{
+}
+
+PMTextureMap::~PMTextureMap( )
+{
+}
+
+PMMetaObject* PMTextureMap::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "TextureMap", Base::metaObject( ),
+ createNewTextureMap );
+ }
+ return s_pMetaObject;
+}
+
+void PMTextureMap::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMTextureMap::description( ) const
+{
+ return i18n( "texture map" );
+}
+
+
+PMMetaObject* PMPigmentMap::s_pMetaObject = 0;
+PMObject* createNewPigmentMap( PMPart* part )
+{
+ return new PMPigmentMap( part );
+}
+
+PMPigmentMap::PMPigmentMap( PMPart* part )
+ : Base( part )
+{
+}
+
+PMPigmentMap::PMPigmentMap( const PMPigmentMap& m )
+ : Base( m )
+{
+}
+
+PMPigmentMap::~PMPigmentMap( )
+{
+}
+
+PMMetaObject* PMPigmentMap::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "PigmentMap", Base::metaObject( ),
+ createNewPigmentMap );
+ }
+ return s_pMetaObject;
+}
+
+void PMPigmentMap::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMPigmentMap::description( ) const
+{
+ return i18n( "pigment map" );
+}
+
+
+PMMetaObject* PMColorMap::s_pMetaObject = 0;
+PMObject* createNewColorMap( PMPart* part )
+{
+ return new PMColorMap( part );
+}
+
+PMColorMap::PMColorMap( PMPart* part )
+ : Base( part )
+{
+}
+
+PMColorMap::PMColorMap( const PMColorMap& m )
+ : Base( m )
+{
+}
+
+PMColorMap::~PMColorMap( )
+{
+}
+
+PMMetaObject* PMColorMap::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "ColorMap", Base::metaObject( ),
+ createNewColorMap );
+ }
+ return s_pMetaObject;
+}
+
+void PMColorMap::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMColorMap::description( ) const
+{
+ return i18n( "color map" );
+}
+
+
+PMMetaObject* PMNormalMap::s_pMetaObject = 0;
+PMObject* createNewNormalMap( PMPart* part )
+{
+ return new PMNormalMap( part );
+}
+
+PMNormalMap::PMNormalMap( PMPart* part )
+ : Base( part )
+{
+}
+
+PMNormalMap::PMNormalMap( const PMNormalMap& m )
+ : Base( m )
+{
+}
+
+PMNormalMap::~PMNormalMap( )
+{
+}
+
+PMMetaObject* PMNormalMap::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "NormalMap", Base::metaObject( ),
+ createNewNormalMap );
+ }
+ return s_pMetaObject;
+}
+
+void PMNormalMap::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMNormalMap::description( ) const
+{
+ return i18n( "normal map" );
+}
+
+
+PMMetaObject* PMSlopeMap::s_pMetaObject = 0;
+PMObject* createNewSlopeMap( PMPart* part )
+{
+ return new PMSlopeMap( part );
+}
+
+PMSlopeMap::PMSlopeMap( PMPart* part )
+ : Base( part )
+{
+}
+
+PMSlopeMap::PMSlopeMap( const PMSlopeMap& m )
+ : Base( m )
+{
+}
+
+PMSlopeMap::~PMSlopeMap( )
+{
+}
+
+PMMetaObject* PMSlopeMap::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "SlopeMap", Base::metaObject( ),
+ createNewSlopeMap );
+ }
+ return s_pMetaObject;
+}
+
+void PMSlopeMap::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMSlopeMap::description( ) const
+{
+ return i18n( "slope map" );
+}
+
+
+PMMetaObject* PMDensityMap::s_pMetaObject = 0;
+PMObject* createNewDensityMap( PMPart* part )
+{
+ return new PMDensityMap( part );
+}
+
+PMDensityMap::PMDensityMap( PMPart* part )
+ : Base( part )
+{
+}
+
+PMDensityMap::PMDensityMap( const PMDensityMap& m )
+ : Base( m )
+{
+}
+
+PMDensityMap::~PMDensityMap( )
+{
+}
+
+PMMetaObject* PMDensityMap::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "DensityMap", Base::metaObject( ),
+ createNewDensityMap );
+ }
+ return s_pMetaObject;
+}
+
+void PMDensityMap::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+QString PMDensityMap::description( ) const
+{
+ return i18n( "density map" );
+}
+
+
+
diff --git a/kpovmodeler/pmtexturemap.h b/kpovmodeler/pmtexturemap.h
new file mode 100644
index 00000000..227c7e1f
--- /dev/null
+++ b/kpovmodeler/pmtexturemap.h
@@ -0,0 +1,368 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMTEXTUREMAP_H
+#define PMTEXTUREMAP_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebase.h"
+#include "pmvector.h"
+
+#include <qvaluelist.h>
+
+/**
+ * Base class for color, pigment, texture and normal maps
+ */
+
+class PMTextureMapBase : public PMTextureBase
+{
+ typedef PMTextureBase Base;
+public:
+ /**
+ * Creates a PMTextureMapBase
+ */
+ PMTextureMapBase( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMTextureMapBase( const PMTextureMapBase& b );
+ /**
+ * deletes the PMTextureMapBase
+ */
+ virtual ~PMTextureMapBase( );
+
+ /** */
+ virtual bool dataChangeOnInsertRemove( ) const { return true; }
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void childAdded( PMObject* o );
+ /** */
+ virtual bool takeChild( PMObject* o );
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns the map object type
+ */
+ virtual QString mapType( ) const = 0;
+
+ /**
+ * Returns a new @ref PMTextureMapEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+
+ /** */
+ virtual void createMemento( );
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+
+ /**
+ * Returns the map values
+ */
+ QValueList<double> mapValues( ) const { return m_mapValues; }
+ /**
+ * Sets the map values
+ */
+ void setMapValues( const QValueList<double>& v );
+ /**
+ * Returns the map value for the object o
+ */
+ double mapValue( const PMObject* o ) const;
+ /**
+ * Returns the number of map entries
+ */
+ int mapEntries( ) const { return m_mapValues.size( ); }
+
+private:
+ PMObject* nextMapEntry( PMObject* o );
+ void stringToValues( const QString& str );
+ QString valuesToString( ) const;
+ QValueList<double>::Iterator valueForChild( PMObject* o );
+
+ /**
+ * IDs for @ref PMMementoData
+ */
+ // enum PMTextureMapBaseMementoID { };
+
+ /**
+ * list of map values
+ */
+ QValueList<double> m_mapValues;
+ /**
+ * removed map values
+ */
+ QValueList<double> m_removedValues;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+
+/**
+ * Class for texture maps
+ */
+
+class PMTextureMap : public PMTextureMapBase
+{
+public:
+ typedef PMTextureMapBase Base;
+ /**
+ * Creates a texture map
+ */
+ PMTextureMap( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMTextureMap( const PMTextureMap& m );
+ /**
+ * Deletes the texture map
+ */
+ virtual ~PMTextureMap( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMTextureMap( *this ); }
+ /** */
+ virtual QString description( ) const;
+ /** */
+ virtual QString mapType( ) const { return QString( "Texture" ); }
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmtexturemap" ); }
+
+private:
+ static PMMetaObject* s_pMetaObject;
+};
+
+/**
+ * Class for pigment maps
+ */
+
+class PMPigmentMap : public PMTextureMapBase
+{
+public:
+ typedef PMTextureMapBase Base;
+ /**
+ * Creates a pigment map
+ */
+ PMPigmentMap( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMPigmentMap( const PMPigmentMap& m );
+ /**
+ * Deletes the pigment map
+ */
+ virtual ~PMPigmentMap( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMPigmentMap( *this ); }
+ /** */
+ virtual QString description( ) const;
+ /** */
+ virtual QString mapType( ) const { return QString( "Pigment" ); }
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmpigmentmap" ); }
+
+private:
+ static PMMetaObject* s_pMetaObject;
+};
+
+/**
+ * Class for color maps
+ */
+
+class PMColorMap : public PMTextureMapBase
+{
+public:
+ typedef PMTextureMapBase Base;
+ /**
+ * Creates a color map
+ */
+ PMColorMap( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMColorMap( const PMColorMap& m );
+ /**
+ * Deletes the color map
+ */
+ virtual ~PMColorMap( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMColorMap( *this ); }
+ /** */
+ virtual QString description( ) const;
+ /** */
+ virtual QString mapType( ) const { return QString( "SolidColor" ); }
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmcolormap" ); }
+
+private:
+ static PMMetaObject* s_pMetaObject;
+};
+
+
+/**
+ * Class for normal maps
+ */
+
+class PMNormalMap : public PMTextureMapBase
+{
+public:
+ typedef PMTextureMapBase Base;
+ /**
+ * Creates a normal map
+ */
+ PMNormalMap( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMNormalMap( const PMNormalMap& m );
+ /**
+ * Deletes the normal map
+ */
+ virtual ~PMNormalMap( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMNormalMap( *this ); }
+ /** */
+ virtual QString description( ) const;
+ /** */
+ virtual QString mapType( ) const { return QString( "Normal" ); }
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmnormalmap" ); }
+
+private:
+ static PMMetaObject* s_pMetaObject;
+};
+
+/**
+ * Class for slope maps
+ */
+
+class PMSlopeMap : public PMTextureMapBase
+{
+public:
+ typedef PMTextureMapBase Base;
+ /**
+ * Creates a slope map
+ */
+ PMSlopeMap( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMSlopeMap( const PMSlopeMap& m );
+ /**
+ * Deletes the slope map
+ */
+ virtual ~PMSlopeMap( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMSlopeMap( *this ); }
+ /** */
+ virtual QString description( ) const;
+ /** */
+ virtual QString mapType( ) const { return QString( "Slope" ); }
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmslopemap" ); }
+
+private:
+ static PMMetaObject* s_pMetaObject;
+};
+
+/**
+ * Class for density maps
+ */
+
+class PMDensityMap : public PMTextureMapBase
+{
+public:
+ typedef PMTextureMapBase Base;
+ /**
+ * Creates a density map
+ */
+ PMDensityMap( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMDensityMap( const PMDensityMap& m );
+ /**
+ * Deletes the density map
+ */
+ virtual ~PMDensityMap( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMDensityMap( *this ); }
+ /** */
+ virtual QString description( ) const;
+ /** */
+ virtual QString mapType( ) const { return QString( "Density" ); }
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmdensitymap" ); }
+
+private:
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmtexturemapedit.cpp b/kpovmodeler/pmtexturemapedit.cpp
new file mode 100644
index 00000000..6faf4376
--- /dev/null
+++ b/kpovmodeler/pmtexturemapedit.cpp
@@ -0,0 +1,152 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmtexturemapedit.h"
+#include "pmtexturemap.h"
+#include "pmlineedits.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+
+PMTextureMapEdit::PMTextureMapEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+ m_numValues = 0;
+}
+
+void PMTextureMapEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+ topLayout( )->addWidget( new QLabel( i18n( "Map values:" ), this ) );
+ m_pNoChildLabel = new QLabel( i18n( "(No Child Objects)" ), this );
+ m_pPureLinkLabel = new QLabel( i18n( "(Pure Link)" ), this );
+ topLayout( )->addWidget( m_pNoChildLabel );
+ topLayout( )->addWidget( m_pPureLinkLabel );
+ QHBoxLayout* hl = new QHBoxLayout( topLayout( ) );
+ m_pEditLayout = new QVBoxLayout( hl );
+ hl->addStretch( 1 );
+}
+
+void PMTextureMapEdit::displayObject( PMObject* o )
+{
+ QString str;
+
+ if( o->isA( "TextureMapBase" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMTextureMapBase* ) o;
+ QValueList<double> mv = m_pDisplayedObject->mapValues( );
+ QValueList<double>::Iterator vit = mv.begin( );
+ QPtrListIterator<PMFloatEdit> eit( m_edits );
+ PMFloatEdit* edit;
+
+ m_numValues = 0;
+
+ for( ; vit != mv.end( ); ++vit )
+ {
+ if( eit.current( ) )
+ {
+ eit.current( )->setValue( *vit );
+ eit.current( )->show( );
+ eit.current( )->setReadOnly( readOnly );
+ ++eit;
+ }
+ else
+ {
+ edit = new PMFloatEdit( this );
+ m_pEditLayout->addWidget( edit );
+ m_edits.append( edit );
+ edit->setValue( *vit );
+ edit->setValidation( true, 0.0, true, 1.0 );
+ edit->setReadOnly( readOnly );
+ connect( edit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ }
+ m_numValues++;
+ }
+ for( ; eit.current( ); ++eit )
+ eit.current( )->hide( );
+ if( m_numValues == 0 )
+ {
+ if( o->linkedObject( ) )
+ {
+ m_pPureLinkLabel->show( );
+ m_pNoChildLabel->hide( );
+ }
+ else
+ {
+ m_pPureLinkLabel->hide( );
+ m_pNoChildLabel->show( );
+ }
+ }
+ else
+ {
+ m_pNoChildLabel->hide( );
+ m_pPureLinkLabel->hide( );
+ }
+ }
+ else
+ kdError( PMArea ) << "PMTextureMapEdit: Can't display object\n";
+ Base::displayObject( o );
+ enableLinkEdit( m_numValues == 0 );
+}
+
+void PMTextureMapEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ if( m_numValues > 0 )
+ {
+ QPtrListIterator<PMFloatEdit> it( m_edits );
+ int i = 0;
+ QValueList<double> values;
+
+ for( ; ( i < m_numValues ) && it.current( ); ++i, ++it )
+ values.append( it.current( )->value( ) );
+ m_pDisplayedObject->setMapValues( values );
+ }
+ Base::saveContents( );
+ }
+}
+
+bool PMTextureMapEdit::isDataValid( )
+{
+ QPtrListIterator<PMFloatEdit> it( m_edits );
+ int i = 0;
+ double last = 0.0;
+
+ for( ; ( i < m_numValues ) && it.current( ); ++i, ++it )
+ {
+ if( !it.current( )->isDataValid( ) )
+ return false;
+ if( it.current( )->value( ) < last )
+ {
+ KMessageBox::error( this, i18n( "The map values have to be increasing." ),
+ i18n( "Error" ) );
+ it.current( )->setFocus( );
+ return false;
+ }
+ last = it.current( )->value( );
+ }
+ return Base::isDataValid( );
+}
+
+#include "pmtexturemapedit.moc"
diff --git a/kpovmodeler/pmtexturemapedit.h b/kpovmodeler/pmtexturemapedit.h
new file mode 100644
index 00000000..818d7435
--- /dev/null
+++ b/kpovmodeler/pmtexturemapedit.h
@@ -0,0 +1,70 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMTEXTUREMAPEDIT_H
+#define PMTEXTUREMAPEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmtexturebaseedit.h"
+#include <qptrlist.h>
+
+class PMTextureMapBase;
+class PMFloatEdit;
+class QWidget;
+class QVBoxLayout;
+class QLabel;
+
+/**
+ * Dialog edit class for @ref PMTextureMapBase.
+ */
+class PMTextureMapEdit : public PMTextureBaseEdit
+{
+ Q_OBJECT
+ typedef PMTextureBaseEdit Base;
+public:
+ /**
+ * Creates a PMTextureMapEdit with parent and name
+ */
+ PMTextureMapEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMTextureMapBase* m_pDisplayedObject;
+ QPtrList<PMFloatEdit> m_edits;
+ QVBoxLayout* m_pEditLayout;
+ QLabel* m_pNoChildLabel;
+ QLabel* m_pPureLinkLabel;
+ int m_numValues;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmthreestate.h b/kpovmodeler/pmthreestate.h
new file mode 100644
index 00000000..7dd04cf6
--- /dev/null
+++ b/kpovmodeler/pmthreestate.h
@@ -0,0 +1,26 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMTHREESTATE_H
+#define PMTHREESTATE_H
+
+/**
+ * Type for three state attributes: true, false, unspecified
+ */
+enum PMThreeState { PMTrue, PMFalse, PMUnspecified };
+
+#endif
diff --git a/kpovmodeler/pmtokens.h b/kpovmodeler/pmtokens.h
new file mode 100644
index 00000000..f1606e53
--- /dev/null
+++ b/kpovmodeler/pmtokens.h
@@ -0,0 +1,463 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMTOKENS_H
+#define PMTOKENS_H
+
+
+enum PMToken {
+ SCANNER_ERROR_TOK=-2,
+ EOF_TOK=-1,
+ //single character tokens
+ //reserved words in povray
+ AA_LEVEL_TOK=0x100,
+ AA_THRESHOLD_TOK,
+ ABS_TOK,
+ ABSORPTION_TOK,
+ ACCURACY_TOK,
+ ACOS_TOK,
+ ACOSH_TOK,
+ ADAPTIVE_TOK,
+ ADC_BAILOUT_TOK,
+ AGATE_TOK,
+ AGATE_TURB_TOK,
+ ALL_TOK,
+ ALL_INTERSECTIONS_TOK,
+ ALPHA_TOK,
+ ALTITUDE_TOK,
+ ALWAYS_SAMPLE_TOK,
+ AMBIENT_TOK,
+ AMBIENT_LIGHT_TOK,
+ ANGLE_TOK,
+ APERTURE_TOK,
+ ARC_ANGLE_TOK,
+ AREA_LIGHT_TOK,
+ AREA_CIRCULAR_TOK,
+ ASC_TOK,
+ ASIN_TOK,
+ ASINH_TOK,
+ ASSUMED_GAMMA_TOK,
+ ATAN_TOK,
+ ATAN2_TOK,
+ ATANH_TOK,
+ ATMOSPHERE_TOK,
+ ATMOSPHERIC_ATTENUATION_TOK,
+ ATTENUATING_TOK,
+ AUTOSTOP_TOK,
+ AVERAGE_TOK,
+ B_SPLINE_TOK,
+ BACKGROUND_TOK,
+ BEZIER_SPLINE_TOK,
+ BICUBIC_PATCH_TOK,
+ BLACK_HOLE_TOK,
+ BLOB_TOK,
+ BLUE_TOK,
+ BLUR_SAMPLES_TOK,
+ BOUNDED_BY_TOK,
+ BOX_TOK,
+ BOXED_TOK,
+ BOZO_TOK,
+ BREAK_TOK,
+ BRICK_TOK,
+ BRICK_SIZE_TOK,
+ BRIGHTNESS_TOK,
+ BRILLIANCE_TOK,
+ BUMPS_TOK,
+ BUMPY1_TOK,
+ BUMPY2_TOK,
+ BUMPY3_TOK,
+ BUMP_MAP_TOK,
+ BUMP_SIZE_TOK,
+ CAMERA_TOK,
+ CASE_TOK,
+ CAUSTICS_TOK,
+ CEIL_TOK,
+ CELLS_TOK,
+ CHECKER_TOK,
+ CHR_TOK,
+ CLIPPED_BY_TOK,
+ CLOCK_TOK,
+ CLOCK_DELTA_TOK,
+ COLLECT_TOK,
+ COLOR_TOK,
+ COLOR_MAP_TOK,
+ COLOUR_TOK,
+ COLOUR_MAP_TOK,
+ COMPONENT_TOK,
+ COMPOSITE_TOK,
+ CONCAT_TOK,
+ CONE_TOK,
+ CONFIDENCE_TOK,
+ CONIC_SWEEP_TOK,
+ CONSERVE_ENERGY_TOK,
+ CONSTANT_TOK,
+ CONTAINED_BY_TOK,
+ CONTROL0_TOK,
+ CONTROL1_TOK,
+ COS_TOK,
+ COSH_TOK,
+ COUNT_TOK,
+ CRACKLE_TOK,
+ CRAND_TOK,
+ CUBE_TOK,
+ CUBIC_TOK,
+ CUBIC_SPLINE_TOK,
+ CUBIC_WAVE_TOK,
+ CYLINDER_TOK,
+ CYLINDRICAL_TOK,
+ DEBUG_TOK,
+ DECLARE_TOK,
+ DEFAULT_TOK,
+ DEGREES_TOK,
+ DENTS_TOK,
+ DENSITY_TOK,
+ DENSITY_FILE_TOK,
+ DENSITY_MAP_TOK,
+ DF3_TOK,
+ DIFFERENCE_TOK,
+ DIFFUSE_TOK,
+ DIRECTION_TOK,
+ DISC_TOK,
+ DISPERSION_TOK,
+ DISPERSION_SAMPLES_TOK,
+ DIST_EXP_TOK,
+ DISTANCE_TOK,
+ DISTANCE_MAXIMUM_TOK,
+ DIV_TOK,
+ DOUBLE_ILLUMINATE_TOK,
+ DUST_TOK,
+ DUST_TYPE_TOK,
+ ECCENTRICITY_TOK,
+ ELSE_TOK,
+ EMISSION_TOK,
+ EMITTING_TOK,
+ END_TOK,
+ ERROR_TOK,
+ ERROR_BOUND_TOK,
+ EVALUATE_TOK,
+ EXP_TOK,
+ EXPAND_THRESHOLDS_TOK,
+ EXPONENT_TOK,
+ EXTERIOR_TOK,
+ EXTINCTION_TOK,
+ FADE_DISTANCE_TOK,
+ FADE_POWER_TOK,
+ FALLOFF_TOK,
+ FALLOFF_ANGLE_TOK,
+ FALSE_TOK,
+ FILE_EXISTS_TOK,
+ FILTER_TOK,
+ FINISH_TOK,
+ FISHEYE_TOK,
+ FLATNESS_TOK,
+ FLIP_TOK,
+ FLOOR_TOK,
+ FOCAL_POINT_TOK,
+ FOG_TOK,
+ FOG_ALT_TOK,
+ FOG_OFFSET_TOK,
+ FOG_TYPE_TOK,
+ FORM_TOK,
+ FRESNEL_TOK,
+ FREQUENCY_TOK,
+ FUNCTION_TOK,
+ GATHER_TOK,
+ GIF_TOK,
+ GLOBAL_LIGHTS_TOK,
+ GLOBAL_SETTINGS_TOK,
+ GLOWING_TOK,
+ GRADIENT_TOK,
+ GRANITE_TOK,
+ GRAY_THRESHOLD_TOK,
+ GREEN_TOK,
+ HALO_TOK,
+ HEIGHT_FIELD_TOK,
+ HEXAGON_TOK,
+ HF_GRAY_16_TOK,
+ HIERARCHY_TOK,
+ HOLLOW_TOK,
+ HYPERCOMPLEX_TOK,
+ IF_TOK,
+ IFDEF_TOK,
+ IFF_TOK,
+ IFNDEF_TOK,
+ IMAGE_MAP_TOK,
+ INCIDENCE_TOK,
+ INCLUDE_TOK,
+ INSIDE_VECTOR_TOK,
+ INT_TOK,
+ INTERIOR_TOK,
+ INTERIOR_TEXTURE_TOK,
+ INTERPOLATE_TOK,
+ INTERSECTION_TOK,
+ INTERVALS_TOK,
+ INVERSE_TOK,
+ ISOSURFACE_TOK,
+ IOR_TOK,
+ IRID_TOK,
+ IRID_WAVELENGTH_TOK,
+ JITTER_TOK,
+ JULIA_TOK,
+ JULIA_FRACTAL_TOK,
+ LAMBDA_TOK,
+ LATHE_TOK,
+ LEOPARD_TOK,
+ LIGHT_GROUP_TOK,
+ LIGHT_SOURCE_TOK,
+ LINEAR_TOK,
+ LINEAR_SPLINE_TOK,
+ LINEAR_SWEEP_TOK,
+ LOCATION_TOK,
+ LOG_TOK,
+ LOOKS_LIKE_TOK,
+ LOOK_AT_TOK,
+ LOW_ERROR_FACTOR_TOK,
+ MAGNET_TOK,
+ MAJOR_RADIUS_TOK,
+ MANDEL_TOK,
+ MAP_TYPE_TOK,
+ MARBLE_TOK,
+ MATERIAL_TOK,
+ MATERIAL_MAP_TOK,
+ MATRIX_TOK,
+ MAX_TOK,
+ MAX_GRADIENT_TOK,
+ MAX_INTERSECTIONS_TOK,
+ MAX_ITERATION_TOK,
+ MAX_SAMPLE_TOK,
+ MAX_TRACE_TOK,
+ MAX_TRACE_LEVEL_TOK,
+ MAX_VALUE_TOK,
+ MEDIA_TOK,
+ MEDIA_ATTENUATION_TOK,
+ MEDIA_INTERACTION_TOK,
+ MERGE_TOK,
+ MESH_TOK,
+ METALLIC_TOK,
+ METHOD_TOK,
+ METRIC_TOK,
+ MIN_TOK,
+ MINIMUM_REUSE_TOK,
+ MOD_TOK,
+ MORTAR_TOK,
+ NEAREST_COUNT_TOK,
+ NO_TOK,
+ NOISE_GENERATOR_TOK,
+ NORMAL_TOK,
+ NORMAL_MAP_TOK,
+ NO_IMAGE_TOK,
+ NO_REFLECTION_TOK,
+ NO_SHADOW_TOK,
+ NUMBER_OF_WAVES_TOK,
+ OBJECT_TOK,
+ OCTAVES_TOK,
+ OFF_TOK,
+ OFFSET_TOK,
+ OMEGA_TOK,
+ OMNIMAX_TOK,
+ ON_TOK,
+ ONCE_TOK,
+ ONION_TOK,
+ OPEN_TOK,
+ ORIENT_TOK,
+ ORTHOGRAPHIC_TOK,
+ PANORAMIC_TOK,
+ PARALLEL_TOK,
+ PASS_THROUGH_TOK,
+ PATTERN1_TOK,
+ PATTERN2_TOK,
+ PATTERN3_TOK,
+ PERSPECTIVE_TOK,
+ PGM_TOK,
+ PHASE_TOK,
+ PHONG_TOK,
+ PHONG_SIZE_TOK,
+ PHOTONS_TOK,
+ PI_TOK,
+ PIGMENT_TOK,
+ PIGMENT_MAP_TOK,
+ PLANAR_TOK,
+ PLANE_TOK,
+ PNG_TOK,
+ POINT_AT_TOK,
+ POLY_TOK,
+ POLY_WAVE_TOK,
+ POLYGON_TOK,
+ POT_TOK,
+ POW_TOK,
+ PPM_TOK,
+ PRECISION_TOK,
+ PRETRACE_END_TOK,
+ PRETRACE_START_TOK,
+ PRISM_TOK,
+ PROJECTED_THROUGH_TOK,
+ PWR_TOK,
+ QUADRATIC_SPLINE_TOK,
+ QUADRIC_TOK,
+ QUARTIC_TOK,
+ QUATERNION_TOK,
+ QUICK_COLOR_TOK,
+ QUICK_COLOUR_TOK,
+ QUILTED_TOK,
+ RADIAL_TOK,
+ RADIANS_TOK,
+ RADIOSITY_TOK,
+ RADIUS_TOK,
+ RAINBOW_TOK,
+ RAMP_WAVE_TOK,
+ RAND_TOK,
+ RANGE_TOK,
+ RATIO_TOK,
+ RECIPROCAL_TOK,
+ RECURSION_LIMIT_TOK,
+ RED_TOK,
+ REFLECTION_TOK,
+ REFLECTION_EXPONENT_TOK,
+ REFRACTION_TOK,
+ RENDER_TOK,
+ REPEAT_TOK,
+ RGB_TOK,
+ RGBF_TOK,
+ RGBFT_TOK,
+ RGBT_TOK,
+ RIGHT_TOK,
+ RIPPLES_TOK,
+ ROTATE_TOK,
+ ROUGHNESS_TOK,
+ SAMPLES_TOK,
+ SCALE_TOK,
+ SCALLOP_WAVE_TOK,
+ SCATTERING_TOK,
+ SEED_TOK,
+ SHADOWLESS_TOK,
+ SIN_TOK,
+ SINE_WAVE_TOK,
+ SINH_TOK,
+ SKY_TOK,
+ SKY_SPHERE_TOK,
+ SLICE_TOK,
+ SLOPE_TOK,
+ SLOPE_MAP_TOK,
+ SMOOTH_TOK,
+ SMOOTH_TRIANGLE_TOK,
+ SOR_TOK,
+ SOLID_TOK,
+ SPACING_TOK,
+ SPECULAR_TOK,
+ SPHERE_TOK,
+ SPHERE_SWEEP_TOK,
+ SPHERICAL_TOK,
+ SPIRAL_TOK,
+ SPIRAL1_TOK,
+ SPIRAL2_TOK,
+ SPOTLIGHT_TOK,
+ SPOTTED_TOK,
+ SQR_TOK,
+ SQRT_TOK,
+ STATISTICS_TOK,
+ STR_TOK,
+ STRCMP_TOK,
+ STRENGTH_TOK,
+ STRLEN_TOK,
+ STRLWR_TOK,
+ STRUPR_TOK,
+ STURM_TOK,
+ SUBSTR_TOK,
+ SUPERELLIPSOID_TOK,
+ SWITCH_TOK,
+ SYS_TOK,
+ T_TOK,
+ TAN_TOK,
+ TANH_TOK,
+ TARGET_TOK,
+ TEST_CAMERA_1_TOK,
+ TEST_CAMERA_2_TOK,
+ TEST_CAMERA_3_TOK,
+ TEST_CAMERA_4_TOK,
+ TEXT_TOK,
+ TEXTURE_TOK,
+ TEXTURE_MAP_TOK,
+ TGA_TOK,
+ THICKNESS_TOK,
+ THRESHOLD_TOK,
+ TIGHTNESS_TOK,
+ TILE2_TOK,
+ TILES_TOK,
+ TOLERANCE_TOK,
+ TOROIDAL_TOK,
+ TORUS_TOK,
+ TRACK_TOK,
+ TRANSFORM_TOK,
+ TRANSLATE_TOK,
+ TRANSMIT_TOK,
+ TRIANGLE_TOK,
+ TRIANGLE_WAVE_TOK,
+ TRUE_TOK,
+ TTF_TOK,
+ TURBULENCE_TOK,
+ TURB_DEPTH_TOK,
+ TYPE_TOK,
+ U_TOK,
+ ULTRA_WIDE_ANGLE_TOK,
+ UNION_TOK,
+ UP_TOK,
+ USE_COLOR_TOK,
+ USE_COLOUR_TOK,
+ USE_INDEX_TOK,
+ U_STEPS_TOK,
+ UV_MAPPING_TOK,
+ UV_VECTORS_TOK,
+ V_TOK,
+ VAL_TOK,
+ VARIANCE_TOK,
+ VAXIS_ROTATE_TOK,
+ VCROSS_TOK,
+ VDOT_TOK,
+ VERSION_TOK,
+ VLENGTH_TOK,
+ VNORMALIZE_TOK,
+ VOLUME_OBJECT_TOK,
+ VOLUME_RENDERED_TOK,
+ VOL_WITH_LIGHT_TOK,
+ VROTATE_TOK,
+ V_STEPS_TOK,
+ WARNING_TOK,
+ WARP_TOK,
+ WATER_LEVEL_TOK,
+ WAVES_TOK,
+ WHILE_TOK,
+ WIDTH_TOK,
+ WOOD_TOK,
+ WRINKLES_TOK,
+ X_TOK,
+ Y_TOK,
+ YES_TOK,
+ Z_TOK,
+ // extra tokens
+ ID_TOK,
+ INTEGER_TOK,
+ FLOAT_TOK,
+ COMMENT_TOK,
+ LINE_COMMENT_TOK,
+ STRING_TOK,
+ PMNAME_TOK,
+ RAW_POVRAY_TOK
+};
+
+#endif
diff --git a/kpovmodeler/pmtorus.cpp b/kpovmodeler/pmtorus.cpp
new file mode 100644
index 00000000..c6f4238a
--- /dev/null
+++ b/kpovmodeler/pmtorus.cpp
@@ -0,0 +1,379 @@
+/***************************************************************************
+ pmtorus.cpp - description
+ -------------------
+ copyright : (C) 2001 Philippe Van Hecke
+ email : lephiloux@tiscalinet.be
+ copyright : (C) 2002 Andreas Zehender
+ email : zehender@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. *
+ * *
+ ***************************************************************************/
+
+#include "pmtorus.h"
+
+#include "pmxmlhelper.h"
+#include "pmtorusedit.h"
+#include "pmmemento.h"
+#include "pmviewstructure.h"
+#include "pm3dcontrolpoint.h"
+#include "pmdistancecontrolpoint.h"
+#include "pmdefaults.h"
+
+#include <klocale.h>
+
+/** default param for the Torus */
+const double c_defaultminorRadius = 0.25;
+const double c_defaultmajorRadius = 0.5;
+const bool c_defaultsturm = false;
+
+/** default Torus structure */
+PMViewStructure* PMTorus::s_pDefaultViewStructure = 0;
+
+int PMTorus::s_vStep = c_defaultTorusVSteps;
+int PMTorus::s_uStep = c_defaultTorusUSteps;
+int PMTorus::s_parameterKey = 0;
+
+PMDefinePropertyClass( PMTorus, PMTorusProperty );
+
+PMMetaObject* PMTorus::s_pMetaObject = 0;
+PMObject* createNewTorus( PMPart* part )
+{
+ return new PMTorus( part );
+}
+
+PMTorus::PMTorus( PMPart* part )
+ : Base( part )
+{
+ m_minorRadius = c_defaultminorRadius;
+ m_majorRadius = c_defaultmajorRadius;
+ m_sturm = c_defaultsturm ;
+}
+
+PMTorus::PMTorus( const PMTorus& t )
+ : Base( t )
+{
+ m_minorRadius = t.m_minorRadius;
+ m_majorRadius = t.m_majorRadius;
+ m_sturm = t.m_sturm;
+}
+
+PMTorus::~PMTorus( )
+{
+}
+
+
+QString PMTorus::description( ) const
+{
+ return i18n( "torus" );
+}
+
+PMMetaObject* PMTorus::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Torus", Base::metaObject( ),
+ createNewTorus );
+ s_pMetaObject->addProperty(
+ new PMTorusProperty( "minorRadius", &PMTorus::setMinorRadius,
+ &PMTorus::minorRadius ) );
+ s_pMetaObject->addProperty(
+ new PMTorusProperty( "majorRadius", &PMTorus::setMajorRadius,
+ &PMTorus::majorRadius ) );
+ s_pMetaObject->addProperty(
+ new PMTorusProperty( "sturm", &PMTorus::setSturm, &PMTorus::sturm ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMTorus::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "minor_radius", m_minorRadius );
+ e.setAttribute( "major_radius", m_majorRadius );
+ e.setAttribute( "sturm", m_sturm );
+
+ Base::serialize( e, doc );
+}
+
+void PMTorus::readAttributes( const PMXMLHelper& h )
+{
+ m_minorRadius = h.doubleAttribute( "minor_radius", c_defaultminorRadius );
+ m_majorRadius = h.doubleAttribute( "major_radius", c_defaultmajorRadius );
+ m_sturm = h.boolAttribute( "sturm", c_defaultsturm );
+
+ Base::readAttributes( h );
+}
+
+PMDialogEditBase* PMTorus::editWidget( QWidget* parent ) const
+{
+
+ return new PMTorusEdit( parent );
+}
+
+void PMTorus::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMMinorRadiusID:
+ setMinorRadius( data->doubleData( ) );
+ break;
+ case PMMajorRadiusID:
+ setMajorRadius( data->doubleData( ) );
+ break;
+ case PMSturmID:
+ setSturm( data->boolData( ) );
+ default:
+ kdError( PMArea ) << "Wrong ID in PMTorus::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+
+}
+
+void PMTorus::controlPoints( PMControlPointList& list )
+{
+ PMVector majorCenter( 0, 0, 0 );
+ /** control points of the major radius */
+ list.append( new PMDistanceControlPoint( majorCenter, PMVector( 1.0, 0.0, 0.0 ),
+ m_majorRadius, PMMajorRadiusID,
+ i18n( "Major radius (x)" ) ) );
+ PMDistanceControlPoint* rcp =
+ new PMDistanceControlPoint( majorCenter, PMVector( 0.0, 0.0, 1.0 ),
+ m_majorRadius, PMMajorRadiusID,
+ i18n( "Major radius (z)" ) );
+ list.append( rcp );
+
+ PMVector minorCenter( 0.0, 0.0, m_majorRadius );
+ list.append( new PMDistanceControlPoint( rcp, PMVector( 0.0, 1.0, 0.0 ),
+ m_minorRadius, PMMinorRadiusID,
+ i18n( "Minor radius (y)" ) ) );
+ list.append( new PMDistanceControlPoint( rcp, PMVector( 0.0, 0.0, 1.0 ),
+ m_minorRadius, PMMinorRadiusID,
+ i18n( "Minor radius (z)" ) ) );
+}
+
+void PMTorus::controlPointsChanged( PMControlPointList& list )
+{
+ bool majorChanged = false, minorChanged = false;
+ PMControlPoint* p;
+ for( p = list.first( ); p; p = list.next( ) )
+ {
+ if( p->changed( ) )
+ {
+ switch( p->id( ) )
+ {
+ case PMMinorRadiusID:
+ setMinorRadius( ( ( PMDistanceControlPoint* ) p )->distance( ) );
+ ( ( PMDistanceControlPoint* ) p )->setDistance( m_minorRadius );
+ minorChanged = true;
+ break;
+ case PMMajorRadiusID:
+ setMajorRadius( ( ( PMDistanceControlPoint* ) p )->distance( ) );
+ ( ( PMDistanceControlPoint* ) p )->setDistance( m_majorRadius );
+ majorChanged = true;
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMTorus::controlPointsChanged\n";
+ break;
+ }
+ }
+ }
+
+ if( majorChanged )
+ for( p = list.first( ); p; p = list.next( ) )
+ if( p->id( ) == PMMajorRadiusID )
+ ( ( PMDistanceControlPoint* ) p )->setDistance( m_majorRadius );
+ if( minorChanged )
+ for( p = list.first( ); p; p = list.next( ) )
+ if( p->id( ) == PMMinorRadiusID )
+ ( ( PMDistanceControlPoint* ) p )->setDistance( m_minorRadius );
+}
+
+bool PMTorus::isDefault( )
+{
+ if( ( m_minorRadius == c_defaultminorRadius )
+ && ( m_majorRadius == c_defaultmajorRadius )
+ && globalDetail( ) )
+ return true;
+ return false;
+}
+
+void PMTorus::createViewStructure( )
+{
+ if( !m_pViewStructure )
+ {
+ m_pViewStructure = new PMViewStructure( defaultViewStructure( ) );
+ m_pViewStructure->points( ).detach( );
+ }
+
+ int uStep = (int)( ( (float)s_uStep / 2 ) * ( displayDetail( ) + 1 ) );
+ int vStep = (int)( ( (float)s_vStep / 2 ) * ( displayDetail( ) + 1 ) );
+ unsigned ptsSize = vStep * uStep;
+ unsigned lineSize = vStep * uStep * 2;
+
+ if( ptsSize != m_pViewStructure->points( ).size( ) )
+ m_pViewStructure->points( ).resize( ptsSize );
+
+ createPoints( m_pViewStructure->points( ), m_minorRadius, m_majorRadius, uStep, vStep );
+
+ if( lineSize != m_pViewStructure->lines( ).size( ) )
+ {
+ m_pViewStructure->lines( ).detach( );
+ m_pViewStructure->lines( ).resize( lineSize );
+ createLines( m_pViewStructure->lines( ), uStep, vStep );
+ }
+}
+
+PMViewStructure* PMTorus::defaultViewStructure( ) const
+{
+ if( !s_pDefaultViewStructure || s_pDefaultViewStructure->parameterKey( ) != viewStructureParameterKey( ) )
+ {
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ int uStep = (int)( ( (float)s_uStep / 2 ) * ( globalDetailLevel( ) + 1 ) );
+ int vStep = (int)( ( (float)s_vStep / 2 ) * ( globalDetailLevel( ) + 1 ) );
+
+ s_pDefaultViewStructure =
+ new PMViewStructure( vStep * uStep ,
+ vStep * uStep * 2 );
+
+ createPoints( s_pDefaultViewStructure->points( ), c_defaultminorRadius,
+ c_defaultmajorRadius, uStep, vStep );
+
+ createLines( s_pDefaultViewStructure->lines( ), uStep, vStep );
+ }
+ return s_pDefaultViewStructure;
+}
+
+void PMTorus::createLines( PMLineArray& lines, int uStep, int vStep )
+{
+ int u, v;
+ for( u = 0; u < uStep; ++u )
+ {
+ for( v = 0; v < vStep; ++v )
+ {
+ lines[ u * vStep + v ] = PMLine( u * vStep + v, u * vStep + ( (v+1) % vStep ) );
+ lines[ uStep * vStep + u * vStep + v ] = PMLine( u * vStep + v, ( (u+1) % uStep ) * vStep + v );
+ }
+ }
+}
+
+void PMTorus::createPoints( PMPointArray& points, double minor_radius,
+ double major_radius, int uStep, int vStep )
+{
+ double l_UradStep = ( 2.0 * M_PI ) / uStep;
+ double l_VradStep = ( 2.0 * M_PI ) / vStep;
+ double l_u = l_UradStep;
+ int u, v;
+
+ for( u = 0; u < uStep; ++u )
+ {
+ double l_v = 0.0;
+ double y = minor_radius * sin ( l_u );
+ double l_rcosu = major_radius + minor_radius * cos( l_u );
+
+ for( v = 0; v < vStep; ++v )
+ {
+ double x = l_rcosu * cos( l_v );
+ double z = l_rcosu * sin( l_v );
+ points[u * vStep + v ] = PMPoint( x, y, z );
+ l_v = l_v + l_VradStep;
+ }
+ l_u = l_u + l_UradStep;
+ }
+}
+
+void PMTorus::setMinorRadius( double minor_radius )
+{
+ if( m_minorRadius != minor_radius )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMMinorRadiusID, m_minorRadius );
+ m_minorRadius = minor_radius;
+ setViewStructureChanged( );
+ }
+}
+
+void PMTorus::setMajorRadius( double major_radius )
+{
+ if( m_majorRadius != major_radius )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMMajorRadiusID, m_majorRadius );
+ m_majorRadius = major_radius;
+ setViewStructureChanged( );
+ }
+}
+
+void PMTorus::setSturm( bool sturm )
+{
+ if( m_sturm != sturm )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMSturmID, m_sturm );
+ m_sturm = sturm;
+ setViewStructureChanged( );
+ }
+
+}
+
+void PMTorus::setUSteps( int u )
+{
+ if( u >= 2 )
+ {
+ s_uStep = u;
+ if( s_pDefaultViewStructure )
+ {
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ }
+ }
+ else
+ kdDebug( PMArea ) << "PMTorus::setUSteps: U must be greater than 1\n";
+ s_parameterKey++;
+}
+
+void PMTorus::setVSteps( int v )
+{
+ if( v >= 4 )
+ {
+ s_vStep = v;
+ if( s_pDefaultViewStructure )
+ {
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ }
+ }
+ else
+ kdDebug( PMArea ) << "PMTorus::setVSteps: V must be greater than 3\n";
+ s_parameterKey++;
+}
+
+void PMTorus::cleanUp( ) const
+{
+ if( s_pDefaultViewStructure )
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
diff --git a/kpovmodeler/pmtorus.h b/kpovmodeler/pmtorus.h
new file mode 100644
index 00000000..9f3f8225
--- /dev/null
+++ b/kpovmodeler/pmtorus.h
@@ -0,0 +1,172 @@
+/*
+ ***************************************************************************
+ pmtorus.h - description
+ -------------------
+ begin : Fri Jun 22 2001
+ copyright : (C) 2001 Philippe Van Hecke
+ email : lephiloux@tiscalinet.be
+ copyright : (C) 2002 Andreas Zehender
+ email : zehender@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. *
+ * *
+ ***************************************************************************/
+
+#ifndef PMTORUS_H
+#define PMTORUS_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobject.h"
+#include "pmvector.h"
+#include "pmviewstructure.h"
+
+class PMViewStructure;
+
+/**
+ * Class for povray torus.
+ */
+class PMTorus : public PMSolidObject
+{
+ typedef PMSolidObject Base;
+
+public:
+ /**
+ * Create an empty Sphere
+ */
+ PMTorus( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMTorus( const PMTorus& t );
+ /**
+ * Delete the PMTorus
+ */
+ virtual ~PMTorus( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMTorus( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMTrousEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmtorus" ); }
+ /**
+ * set minor radius see povray documentation about torus
+ */
+ void setMinorRadius( double minor_radius );
+ /**
+ * set major radius see povray documentation about torus
+ */
+ void setMajorRadius( double major_radius );
+ /**
+ * use sturm algorithme
+ */
+ void setSturm( bool sturm );
+ /**
+ * return minor radius see povray documentation about torus
+ */
+ double minorRadius( ) const { return m_minorRadius; }
+ /**
+ * return major radius see povray documentation about torus
+ */
+ double majorRadius( ) const { return m_majorRadius; }
+ /**
+ * return if we must use sturm algorithm for the torus
+ */
+ bool sturm( ) const { return m_sturm; }
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /** */
+ virtual void controlPoints( PMControlPointList& list );
+ /** */
+ virtual void controlPointsChanged( PMControlPointList& list );
+ /** */
+ virtual bool hasDisplayDetail( ) const { return true; }
+ /** */
+ virtual void cleanUp( ) const;
+
+ /**
+ * Sets the number of circles
+ */
+ static void setUSteps( int u );
+ /**
+ * Sets the number of point for each circle
+ */
+ static void setVSteps( int v );
+ /**
+ * Returns the number circles
+ */
+ static int uSteps( ) { return s_uStep; }
+ /**
+ * Returns the number of point for each circle
+ */
+ static int vSteps( ) { return s_vStep; }
+
+protected:
+ /** */
+ virtual bool isDefault( );
+ /** */
+ virtual void createViewStructure( );
+ /** */
+ virtual PMViewStructure* defaultViewStructure( ) const;
+ /** */
+ virtual int viewStructureParameterKey( ) const { return s_parameterKey + globalDetailKey(); }
+
+private:
+ static void createLines( PMLineArray& lines, int uStep, int vStep );
+ static void createPoints( PMPointArray& points, double minor_radius,
+ double major_radius, int uStep, int vStep );
+ enum PMTorusMementoID { PMMinorRadiusID, PMMajorRadiusID, PMSturmID };
+ /**
+ * Minor radius
+ */
+ double m_minorRadius;
+ /**
+ * Major radius
+ */
+ double m_majorRadius;
+ /**
+ * use sturm algorithm
+ */
+ bool m_sturm;
+ /**
+ * default view structure
+ */
+ static PMViewStructure* s_pDefaultViewStructure;
+ static int s_vStep;
+ static int s_uStep;
+ static int s_parameterKey;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
+/*
+x = (major + minor cos(u)) cos(v)
+y = (major + minor cos(u)) sin(v)
+z = minor sin (u) */
+
+
diff --git a/kpovmodeler/pmtorusedit.cpp b/kpovmodeler/pmtorusedit.cpp
new file mode 100644
index 00000000..01784e1d
--- /dev/null
+++ b/kpovmodeler/pmtorusedit.cpp
@@ -0,0 +1,105 @@
+/***************************************************************************
+ pmtorusedit.cpp - description
+ -------------------
+ begin : Sun Jul 1 2001
+ copyright : (C) 2001 by Van Hecke Philippe
+ email : lephiloux@tiscalinet.be
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include "pmtorusedit.h"
+#include "pmtorus.h"
+#include "pmvectoredit.h"
+#include "pmlineedits.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <klocale.h>
+#include <qcheckbox.h>
+
+
+PMTorusEdit::PMTorusEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMTorusEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ QGridLayout* gl;
+ QHBoxLayout* hl;
+
+ m_pMinorRadius = new PMFloatEdit( this );
+ m_pMajorRadius = new PMFloatEdit( this );
+ m_pSturm = new QCheckBox( i18n( "Sturm" ), this );
+
+ hl = new QHBoxLayout( topLayout( ) );
+ gl = new QGridLayout( hl, 2, 2 );
+ gl->addWidget( new QLabel( i18n( "Minor radius:" ), this ), 0, 0 );
+ gl->addWidget( m_pMinorRadius, 0, 1 );
+ gl->addWidget( new QLabel( i18n( "Major radius:" ), this ), 1, 0 );
+ gl->addWidget( m_pMajorRadius, 1, 1 );
+ hl->addStretch( 1 );
+
+ topLayout( )->addWidget( m_pSturm );
+
+
+ connect( m_pMinorRadius, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pMajorRadius, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pSturm, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMTorusEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Torus" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMTorus* ) o;
+
+ m_pMajorRadius->setValue( m_pDisplayedObject->majorRadius( ) );
+ m_pMinorRadius->setValue( m_pDisplayedObject->minorRadius( ) );
+ m_pSturm->setChecked( m_pDisplayedObject->sturm( ) );
+
+ m_pMajorRadius->setReadOnly( readOnly );
+ m_pMinorRadius->setReadOnly( readOnly );
+ m_pSturm->setEnabled( !readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMTorusEdit: Can't display object\n";
+}
+
+void PMTorusEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+
+ m_pDisplayedObject->setMajorRadius( m_pMajorRadius->value( ) );
+ m_pDisplayedObject->setMinorRadius( m_pMinorRadius->value( ) );
+ m_pDisplayedObject->setSturm( m_pSturm->isChecked( ) );
+ }
+}
+
+bool PMTorusEdit::isDataValid( )
+{
+ if( m_pMinorRadius->isDataValid( ) )
+ if( m_pMajorRadius->isDataValid( ) )
+ return Base::isDataValid( );
+ return false;
+}
+
+
+#include "pmtorusedit.moc"
+
diff --git a/kpovmodeler/pmtorusedit.h b/kpovmodeler/pmtorusedit.h
new file mode 100644
index 00000000..2aea334b
--- /dev/null
+++ b/kpovmodeler/pmtorusedit.h
@@ -0,0 +1,65 @@
+/*
+ **************************************************************************
+ pmtorusedit.h - description
+ -------------------
+ begin : Sat Jun 30 2001
+ copyright : (C) 2001 Philippe Van Hecke
+ email : lephiloux@tiscalinet.be
+ ***************************************************************************
+
+ ***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef PMTORUSEDIT_H
+#define PMTORUSEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsolidobjectedit.h"
+
+class PMTorus;
+class PMFloatEdit ;
+class QCheckBox;
+
+/**
+ * Dialog edit class for @ref PMTorus
+ */
+class PMTorusEdit : public PMSolidObjectEdit
+{
+ Q_OBJECT
+ typedef PMSolidObjectEdit Base;
+public:
+ /**
+ * Creates a PMSphereEdit with parent and name
+ */
+ PMTorusEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMTorus* m_pDisplayedObject;
+ PMFloatEdit* m_pMinorRadius;
+ PMFloatEdit* m_pMajorRadius;
+ QCheckBox * m_pSturm;
+
+};
+
+
+#endif
diff --git a/kpovmodeler/pmtranslate.cpp b/kpovmodeler/pmtranslate.cpp
new file mode 100644
index 00000000..0cfab44f
--- /dev/null
+++ b/kpovmodeler/pmtranslate.cpp
@@ -0,0 +1,162 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmtranslate.h"
+#include "pmtranslateedit.h"
+
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pmtranslatecontrolpoint.h"
+
+#include <klocale.h>
+
+const PMVector moveDefault = PMVector( 0.0, 0.0, 0.0 );
+
+PMDefinePropertyClass( PMTranslate, PMTranslateProperty );
+
+PMMetaObject* PMTranslate::s_pMetaObject = 0;
+PMObject* createNewTranslate( PMPart* part )
+{
+ return new PMTranslate( part );
+}
+
+PMTranslate::PMTranslate( PMPart* part )
+ : Base( part )
+{
+}
+
+PMTranslate::PMTranslate( const PMTranslate& t )
+ : Base( t )
+{
+ m_move = t.m_move;
+}
+
+PMTranslate::~PMTranslate( )
+{
+}
+
+QString PMTranslate::description( ) const
+{
+ return i18n( "translate" );
+}
+
+void PMTranslate::serialize( QDomElement& e, QDomDocument& /*doc*/ ) const
+{
+ e.setAttribute( "value", m_move.serializeXML( ) );
+}
+
+void PMTranslate::readAttributes( const PMXMLHelper& h )
+{
+ m_move = h.vectorAttribute( "value", moveDefault );
+}
+
+PMMetaObject* PMTranslate::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Translate", Base::metaObject( ),
+ createNewTranslate );
+ s_pMetaObject->addProperty(
+ new PMTranslateProperty( "translation", &PMTranslate::setTranslation, &PMTranslate::translation ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMTranslate::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMTranslate::setTranslation( const PMVector& p )
+{
+ if( p != m_move )
+ {
+ if( m_pMemento )
+ {
+ m_pMemento->addData( s_pMetaObject, PMTranslationID, m_move );
+ m_pMemento->setViewStructureChanged( );
+ }
+ m_move = p;
+ m_move.resize( 3 );
+ }
+}
+
+PMDialogEditBase* PMTranslate::editWidget( QWidget* parent ) const
+{
+ return new PMTranslateEdit( parent );
+}
+
+void PMTranslate::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMTranslationID:
+ setTranslation( data->vectorData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMTranslate::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
+PMMatrix PMTranslate::transformationMatrix( ) const
+{
+ return PMMatrix::translation( m_move[0], m_move[1], m_move[2] );
+}
+
+void PMTranslate::controlPoints( PMControlPointList& list )
+{
+ list.append( new PMTranslateControlPoint( m_move, PMTranslationID ) );
+}
+
+void PMTranslate::controlPointsChanged( PMControlPointList& list )
+{
+ PMControlPoint* p;
+
+ for( p = list.first( ); p; p = list.next( ) )
+ {
+ if( p->changed( ) )
+ {
+ switch( p->id( ) )
+ {
+ case PMTranslationID:
+ setTranslation( ( ( PMTranslateControlPoint* ) p )->translation( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMTranslate::controlPointsChanged\n";
+ break;
+ }
+ }
+ }
+}
diff --git a/kpovmodeler/pmtranslate.h b/kpovmodeler/pmtranslate.h
new file mode 100644
index 00000000..91f1c7c3
--- /dev/null
+++ b/kpovmodeler/pmtranslate.h
@@ -0,0 +1,102 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMTRANSLATE_H
+#define PMTRANSLATE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmobject.h"
+#include "pmvector.h"
+
+/**
+ * Class for povray move commands.
+ */
+
+class PMTranslate : public PMObject
+{
+ typedef PMObject Base;
+public:
+ /**
+ * Creates a move < 0, 0, 0 >
+ */
+ PMTranslate( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMTranslate( const PMTranslate& t );
+ /**
+ * deletes the object
+ */
+ virtual ~PMTranslate( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMTranslate( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMTranslateEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /** */
+ virtual QString pixmap( ) const { return QString( "pmtranslate" ); }
+
+ /**
+ * Returns the movement
+ */
+ PMVector translation( ) const { return m_move; }
+ /**
+ * Sets the movement
+ */
+ void setTranslation( const PMVector& p );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /** */
+ virtual bool hasTransformationMatrix( ) const { return true; }
+ /** */
+ virtual PMMatrix transformationMatrix( ) const;
+
+ /** */
+ virtual void controlPoints( PMControlPointList& list );
+ /** */
+ virtual void controlPointsChanged( PMControlPointList& list );
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMTranslateMementoID { PMTranslationID };
+ PMVector m_move;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmtranslatecontrolpoint.cpp b/kpovmodeler/pmtranslatecontrolpoint.cpp
new file mode 100644
index 00000000..857e3af9
--- /dev/null
+++ b/kpovmodeler/pmtranslatecontrolpoint.cpp
@@ -0,0 +1,50 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmtranslatecontrolpoint.h"
+#include "pmmath.h"
+
+#include <klocale.h>
+#include <math.h>
+
+PMTranslateControlPoint::PMTranslateControlPoint( const PMVector& trans, int id )
+ : PMControlPoint( id, i18n( "Translation" ) )
+{
+ m_translation = trans;
+}
+
+void PMTranslateControlPoint::graphicalChangeStarted( )
+{
+ m_originalTranslation = m_translation;
+}
+
+void PMTranslateControlPoint::graphicalChange( const PMVector& startPoint,
+ const PMVector& /*viewNormal*/,
+ const PMVector& endPoint )
+{
+ m_translation = m_originalTranslation + endPoint - startPoint;
+}
+
+void PMTranslateControlPoint::snapToGrid( )
+{
+ int i;
+ double d = moveGrid( );
+ if( !approxZero( d ) )
+ for( i = 0; i < 3; i++ )
+ m_translation[i] = rint( m_translation[i] / d ) * d;
+ setChanged( );
+}
diff --git a/kpovmodeler/pmtranslatecontrolpoint.h b/kpovmodeler/pmtranslatecontrolpoint.h
new file mode 100644
index 00000000..292e8a67
--- /dev/null
+++ b/kpovmodeler/pmtranslatecontrolpoint.h
@@ -0,0 +1,71 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMTRANSLATECONTROLPOINT_H
+#define PMTRANSLATECONTROLPOINT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include "pmcontrolpoint.h"
+
+/**
+ * Control points for translation
+ */
+class PMTranslateControlPoint : public PMControlPoint
+{
+public:
+ /**
+ * Creates a PMTranslateControlPoint with id.
+ */
+ PMTranslateControlPoint( const PMVector& translation, int id );
+ /**
+ * Deletes the PMTranslateControlPoint
+ */
+ virtual ~PMTranslateControlPoint( ) { };
+
+ /** */
+ virtual PMVector position( ) const { return m_translation; }
+
+ /**
+ * Sets the translation
+ */
+ void setTranslation( PMVector trans ) { m_translation = trans; }
+ /**
+ * Returns the translation
+ */
+ PMVector translation( ) const { return m_translation; }
+
+ /** */
+ virtual PMCPDisplayType displayType( ) const { return CPCross; };
+ /** */
+ virtual void snapToGrid( );
+protected:
+ /** */
+ virtual void graphicalChangeStarted( );
+ /** */
+ virtual void graphicalChange( const PMVector& startPoint,
+ const PMVector& viewNormal,
+ const PMVector& endPoint );
+private:
+ PMVector m_translation, m_originalTranslation;
+};
+
+#endif
diff --git a/kpovmodeler/pmtranslateedit.cpp b/kpovmodeler/pmtranslateedit.cpp
new file mode 100644
index 00000000..d2690f51
--- /dev/null
+++ b/kpovmodeler/pmtranslateedit.cpp
@@ -0,0 +1,74 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmtranslateedit.h"
+#include "pmtranslate.h"
+#include "pmvectoredit.h"
+
+#include <qlayout.h>
+#include <klocale.h>
+
+
+PMTranslateEdit::PMTranslateEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMTranslateEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ m_pVector = new PMVectorEdit( "x", "y", "z", this );
+ topLayout( )->addWidget( m_pVector );
+
+ connect( m_pVector, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMTranslateEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Translate" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMTranslate* ) o;
+
+ m_pVector->setVector( m_pDisplayedObject->translation( ) );
+ m_pVector->setReadOnly( readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMTranslateEdit: Can't display object\n";
+}
+
+void PMTranslateEdit::saveContents( )
+{
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ m_pDisplayedObject->setTranslation( m_pVector->vector( ) );
+ }
+}
+
+bool PMTranslateEdit::isDataValid( )
+{
+ if( m_pVector->isDataValid( ) )
+ return Base::isDataValid( );
+ return false;
+}
+#include "pmtranslateedit.moc"
diff --git a/kpovmodeler/pmtranslateedit.h b/kpovmodeler/pmtranslateedit.h
new file mode 100644
index 00000000..ce27b037
--- /dev/null
+++ b/kpovmodeler/pmtranslateedit.h
@@ -0,0 +1,62 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMMOVEEDIT_H
+#define PMMOVEEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdialogeditbase.h"
+
+class PMTranslate;
+class PMVectorEdit;
+
+/**
+ * Dialog edit class for @ref PMTranslate
+ */
+class PMTranslateEdit : public PMDialogEditBase
+{
+ Q_OBJECT
+ typedef PMDialogEditBase Base;
+public:
+ /**
+ * Creates a PMTranslateEdit with parent and name
+ */
+ PMTranslateEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private:
+ PMTranslate* m_pDisplayedObject;
+ PMVectorEdit* m_pVector;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmtreeview.cpp b/kpovmodeler/pmtreeview.cpp
new file mode 100644
index 00000000..66ec18a0
--- /dev/null
+++ b/kpovmodeler/pmtreeview.cpp
@@ -0,0 +1,820 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include <stdlib.h>
+
+#include <qlistview.h>
+#include <qheader.h>
+#include <qlayout.h>
+#include <qpopupmenu.h>
+#include <qcursor.h>
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <kxmlguifactory.h>
+
+#include "pmtreeview.h"
+#include "pmtreeviewitem.h"
+#include "pmcommand.h"
+#include "pmpart.h"
+#include "pmscene.h"
+#include "pmobjectdrag.h"
+
+
+PMTreeViewWidget::PMTreeViewWidget( PMPart* part, QWidget* parent /*= 0*/,
+ const char* name /*=0*/ )
+ : PMViewBase( parent, name )
+{
+ QHBoxLayout* hl = new QHBoxLayout( this );
+ PMTreeView* tv = new PMTreeView( part, this );
+ hl->addWidget( tv );
+}
+
+QString PMTreeViewWidget::description( ) const
+{
+ return i18n( "Object Tree" );
+}
+
+PMTreeView::PMTreeView( PMPart* part, QWidget* parent /*= 0*/,
+ const char* name /*= 0*/ )
+ : QListView( parent, name )
+{
+ addColumn( i18n( "Objects" ) );
+ header( )->hide( );
+ setRootIsDecorated( true );
+ setSorting( -1 );
+ setSelectionMode( Multi );
+ m_pPart = part;
+
+ m_itemSelected = false;
+ m_itemDeselected = false;
+ m_selectionCleared = false;
+ m_pLastSelected = 0;
+ m_event = false;
+ m_pressed = false;
+ m_pDragOverItem = 0;
+ m_acceptSelect = false;
+ m_pressedItem = 0;
+
+ viewport( )->setAcceptDrops( true );
+ viewport( )->setMouseTracking( true );
+ viewport( )->setFocusPolicy( QWidget::WheelFocus );
+ setFocusPolicy( QWidget::WheelFocus );
+ setAcceptDrops( true );
+
+ connect( part, SIGNAL( refresh( ) ), SLOT( slotRefresh( ) ) );
+ connect( part, SIGNAL( objectChanged( PMObject*, const int, QObject* ) ),
+ SLOT( slotObjectChanged( PMObject*, const int, QObject* ) ) );
+ connect( part, SIGNAL( clear( ) ), SLOT( slotClear( ) ) );
+ connect( this, SIGNAL( objectChanged( PMObject*, const int, QObject* ) ),
+ part, SLOT( slotObjectChanged( PMObject*, const int, QObject* ) ) );
+
+ slotRefresh( );
+}
+
+PMTreeView::~PMTreeView( )
+{
+ emit destroyed( this );
+}
+
+void PMTreeView::slotObjectChanged( PMObject* obj, const int mode,
+ QObject* sender )
+{
+ PMTreeViewItem* pTreeItem = 0;
+ bool as = m_acceptSelect;
+ m_acceptSelect = true;
+
+ if( sender != this )
+ {
+ if( ( mode & PMCAdd ) && !( mode & PMCInsertError ) )
+ {
+ // object was added
+ if( !obj->parent( ) )
+ {
+ // object has no parent, append it as top level item
+ pTreeItem = new PMTreeViewItem( obj, this );
+ }
+ else
+ {
+ // find the parent in the listview
+ QListViewItem* pParentTreeItem = findObject( obj->parent( ) );
+ if( pParentTreeItem )
+ {
+ PMObject* hObj = obj->prevSibling( );
+ QListViewItem* pSibling = 0;
+ bool found = false;
+
+ if( hObj )
+ {
+ // find the previous sibling
+ pSibling = pParentTreeItem->firstChild( );
+ while( pSibling && !found )
+ {
+ if( ( ( PMTreeViewItem* ) pSibling )->object( ) == hObj )
+ found = true;
+ else
+ pSibling = pSibling->nextSibling( );
+ }
+ }
+ if( found )
+ {
+ // object has sibling
+ pTreeItem = new PMTreeViewItem( obj, pParentTreeItem, pSibling );
+ }
+ else
+ {
+ // object has no sibling
+ pTreeItem = new PMTreeViewItem( obj, pParentTreeItem );
+ }
+ }
+ }
+
+ if( pTreeItem )
+ {
+ // add child items if necessary
+ if( obj->countChildren( ) > 0 )
+ addChildItems( pTreeItem );
+ }
+ }
+ if( mode & PMCDescription )
+ {
+ if( !pTreeItem )
+ pTreeItem = findObject( obj );
+
+ if( pTreeItem )
+ pTreeItem->setDescriptions( );
+ }
+ if( mode & PMCChildren )
+ {
+ if( !pTreeItem )
+ pTreeItem = findObject( obj );
+
+ if( pTreeItem )
+ {
+ // delete old items
+ while( pTreeItem->firstChild( ) )
+ delete pTreeItem->firstChild( );
+ // create new
+ addChildItems( pTreeItem );
+ pTreeItem->setOpen( true );
+ }
+ }
+ if( mode & PMCNewSelection )
+ {
+ clearSelection( );
+
+ if( !pTreeItem )
+ pTreeItem = findObject( obj );
+
+ if( pTreeItem )
+ {
+ PMTreeViewItem* p;
+ for( p = pTreeItem->parent( ); p; p = p->parent( ) )
+ p->setOpen( true );
+ pTreeItem->setSelected( true );
+ setCurrentItem( pTreeItem );
+ }
+ }
+ if( mode & PMCDeselected )
+ {
+ if( !pTreeItem )
+ pTreeItem = findObject( obj );
+ pTreeItem->setSelected( false );
+ }
+ if( mode & PMCSelected )
+ {
+ if( !pTreeItem )
+ pTreeItem = findObject( obj );
+ pTreeItem->setSelected( true );
+ }
+ if( mode & PMCRemove )
+ {
+ // object was removed, remove the listview item
+ if( !pTreeItem )
+ pTreeItem = findObject( obj );
+ delete( pTreeItem );
+ }
+ if( mode & PMCData )
+ {
+ // special case for texture maps
+ if( obj )
+ {
+ if( obj->isA( "TextureMapBase" ) )
+ {
+ if( !pTreeItem )
+ pTreeItem = findObject( obj );
+ if( pTreeItem )
+ {
+ PMTreeViewItem* it = ( PMTreeViewItem* ) pTreeItem->firstChild( );
+ for( ; it; it = ( PMTreeViewItem* ) it->nextSibling( ) )
+ it->setDescriptions( );
+ }
+ }
+ }
+ }
+ }
+ m_acceptSelect = as;
+}
+
+
+PMTreeViewItem* PMTreeView::findObject( const PMObject* obj )
+{
+ PMTreeViewItem* pTreeItem = 0;
+
+ if( !obj->parent( ) )
+ {
+ // top level object
+ pTreeItem = ( PMTreeViewItem* ) firstChild( );
+ for( ; pTreeItem; pTreeItem = ( PMTreeViewItem* ) pTreeItem->nextSibling( ) )
+ if( pTreeItem->object( ) == obj )
+ return pTreeItem;
+ }
+ else
+ {
+ pTreeItem = findObject( obj->parent( ) );
+ if( pTreeItem )
+ {
+ pTreeItem = ( PMTreeViewItem* ) pTreeItem->firstChild( );
+ for( ; pTreeItem; pTreeItem = ( PMTreeViewItem* ) pTreeItem->nextSibling( ) )
+ if( pTreeItem->object( ) == obj )
+ return pTreeItem;
+ }
+ }
+ return 0;
+}
+
+
+void PMTreeView::selectItem( QListViewItem* /*sitem*/ )
+{
+/* QListViewItem* pItem = 0;
+ bool emitSig;
+ emitSig = ( m_pSelectedObject != ( ( PMTreeViewItem* ) sitem )->object( ) );
+
+ m_pSelectedObject = ( ( PMTreeViewItem* ) sitem )->object( );
+
+ for( pItem = sitem->parent( ); pItem; pItem = pItem->parent( ) )
+ pItem->setOpen( true );
+ ensureItemVisible( sitem );
+ setCurrentItem( sitem );
+ setSelected( sitem, true );
+ if( emitSig )
+ emit objectSelected( m_pSelectedObject );
+*/
+}
+
+void PMTreeView::addChildItems( PMTreeViewItem* item )
+{
+ PMObject* obj = 0;
+ PMTreeViewItem* listItem = 0;
+
+ for( obj = item->object( )->firstChild( ); obj; obj = obj->nextSibling( ) )
+ {
+ // insert all child objects
+ if( listItem )
+ listItem = new PMTreeViewItem( obj, item, listItem );
+ else
+ // first child
+ listItem = new PMTreeViewItem( obj, item );
+ // recursive call, if child has children
+ if( obj->countChildren( ) > 0 )
+ addChildItems( listItem );
+ }
+}
+
+void PMTreeView::slotRefresh( )
+{
+ PMTreeViewItem* item;
+ slotClear( );
+ // insert the top level items
+ if( m_pPart->scene( ) )
+ {
+ item = new PMTreeViewItem( m_pPart->scene( ), this );
+ addChildItems( item );
+ item->setOpen( true );
+// item = new PMTreeViewItem( m_pPart->insertErrors( ), this );
+// addChildItems( item );
+// item->setOpen( true );
+ }
+}
+
+void PMTreeView::slotClear( )
+{
+ clear( );
+ m_pLastSelected = 0;
+ m_pDragOverItem = 0;
+ m_pressedItem = 0;
+}
+
+void PMTreeView::itemSelected( PMTreeViewItem* item, bool selected )
+{
+ repaintItem( item );
+
+ if( m_event )
+ {
+ m_pLastSelected = item;
+
+ if( selected )
+ m_itemSelected = true;
+ else
+ {
+ if( m_itemDeselected )
+ m_selectionCleared = true;
+ else
+ m_itemDeselected = true;
+ }
+ }
+}
+
+void PMTreeView::contentsMousePressEvent( QMouseEvent * e )
+{
+ m_itemSelected = false;
+ m_itemDeselected = false;
+ m_pLastSelected = 0;
+ m_selectionCleared = false;
+ m_selectOnReleaseEvent = false;
+ bool specialAction = false;
+
+ QListViewItem* oldCurrent = currentItem( );
+
+ m_event = true;
+ m_acceptSelect = true;
+ QListView::contentsMousePressEvent( e );
+ m_event = false;
+ m_acceptSelect = true;
+
+ if( m_selectionCleared )
+ {
+ emit objectChanged( 0, PMCNewSelection, this );
+ specialAction = true;
+ }
+ else if( m_itemSelected || m_itemDeselected )
+ {
+ if( !( e->state( ) & ( ShiftButton | ControlButton ) ) )
+ {
+ specialAction = true;
+ // simple click, deselect all selected item
+ // m_pLastSelected is the new selection
+
+ if( m_itemSelected )
+ {
+ clearSelection( );
+ m_pLastSelected->setSelected( true );
+
+ emit objectChanged( m_pLastSelected->object( ), PMCNewSelection,
+ this );
+ }
+ else
+ {
+ m_selectOnReleaseEvent = true;
+ m_pLastSelected->setSelected( true );
+ }
+ }
+ else if( ( e->state( ) & ShiftButton ) && oldCurrent && m_pLastSelected )
+ {
+ if( ( oldCurrent != m_pLastSelected ) &&
+ ( oldCurrent->parent( ) == m_pLastSelected->parent( ) ) )
+ {
+ specialAction = true;
+
+ // shift click, old current item has the same parent
+ // as the new selection. Select all items between the two
+ // items
+ if( m_pLastSelected->object( )->isSelectable( ) )
+ {
+ bool down = oldCurrent->itemPos( ) < m_pLastSelected->itemPos( );
+ QListViewItem* tmp;
+
+ if( down )
+ {
+ for( tmp = oldCurrent; tmp; tmp = tmp->nextSibling( ) )
+ {
+ tmp->setSelected( true );
+ emit objectChanged( (( PMTreeViewItem* ) tmp)->object( ),
+ PMCSelected, this );
+ if( tmp == m_pLastSelected )
+ break;
+ }
+ }
+ else
+ {
+ for( tmp = m_pLastSelected; tmp; tmp = tmp->nextSibling( ) )
+ {
+ tmp->setSelected( true );
+ emit objectChanged( (( PMTreeViewItem* ) tmp)->object( ),
+ PMCSelected, this );
+ if( tmp == oldCurrent )
+ break;
+ }
+ }
+ }
+ else
+ m_pLastSelected->setSelected( false );
+ }
+ }
+ }
+ if( !specialAction )
+ {
+ // no special action
+ // object is selected or deselected, no other objects are changed
+ if( m_itemSelected )
+ {
+ if( m_pLastSelected->object( )->isSelectable( ) )
+ emit objectChanged( m_pLastSelected->object( ), PMCSelected, this );
+ else
+ m_pLastSelected->setSelected( false );
+ }
+ else if( m_itemDeselected )
+ emit objectChanged( m_pLastSelected->object( ), PMCDeselected, this );
+ }
+ m_acceptSelect = false;
+}
+
+void PMTreeView::contentsMouseMoveEvent( QMouseEvent * e )
+{
+ m_itemSelected = false;
+ m_itemDeselected = false;
+ m_pLastSelected = 0;
+ m_selectionCleared = false;
+
+ m_event = true;
+ QListView::contentsMouseMoveEvent( e );
+ m_event = false;
+
+ // ignore all selections/deselections
+ if( m_itemSelected || m_itemDeselected )
+ m_pLastSelected->setSelected( m_pLastSelected->object( )->isSelected( ) );
+}
+
+void PMTreeView::viewportMousePressEvent( QMouseEvent* e )
+{
+ m_acceptSelect = true;
+ QListView::viewportMousePressEvent( e );
+ m_acceptSelect = false;
+
+ m_pressed = false;
+
+ QPoint p = e->pos( );
+
+ if( e->button( ) & RightButton )
+ {
+ if( m_pPart->factory( ) )
+ {
+ QPopupMenu* m =
+ ( QPopupMenu* ) m_pPart->factory( )->container( "treeViewPopup", m_pPart );
+ if( m )
+ m->exec( QCursor::pos( ) );
+ }
+ return;
+ }
+
+ PMTreeViewItem *item = ( PMTreeViewItem* )itemAt( p );
+ if( item )
+ {
+ // check if the root decoration was clicked
+ if( !( p.x( ) > header( )->cellPos( header( )->mapToActual( 0 ) ) +
+ treeStepSize( ) * ( item->depth( ) + ( rootIsDecorated( ) ? 1 : 0 ) )
+ + itemMargin( ) ||
+ p.x( ) < header( )->cellPos( header( )->mapToActual( 0 ) ) ) )
+ item = 0; // p is on the root decoration
+ }
+
+ if( item )
+ {
+ if( e->button( ) == LeftButton || e->button( ) == MidButton )
+ {
+ m_pressed = true;
+ m_pressedPos = e->pos( );
+ m_pressedItem = item;
+ return;
+ }
+ }
+}
+
+void PMTreeView::viewportMouseReleaseEvent( QMouseEvent* e )
+{
+ QListView::viewportMouseReleaseEvent( e );
+
+ if( !m_pressed )
+ return;
+
+ m_pressed = false;
+ m_pressedItem = 0L;
+
+ if( m_selectOnReleaseEvent )
+ {
+ if( m_pLastSelected )
+ {
+ m_acceptSelect = true;
+ clearSelection( );
+ m_pLastSelected->setSelected( true );
+ m_acceptSelect = false;
+
+ emit objectChanged( m_pLastSelected->object( ), PMCNewSelection, this );
+ }
+ }
+}
+
+void PMTreeView::viewportMouseMoveEvent( QMouseEvent *e )
+{
+ QListView::viewportMouseMoveEvent( e );
+
+ if( m_pressed && m_pressedItem )
+ {
+ int x = e->pos( ).x( );
+ int y = e->pos( ).y( );
+
+ //Is it time to start a drag?
+ if( abs( x - m_pressedPos.x( ) ) > KGlobalSettings::dndEventDelay( ) ||
+ abs( y - m_pressedPos.y( ) ) > KGlobalSettings::dndEventDelay( ) )
+ {
+ m_selectOnReleaseEvent = false;
+
+ // Calculate hotspot
+ QPoint hotspot;
+ PMObjectList sortedList = m_pPart->selectedObjects( );
+
+ // Do not handle more mouse move or mouse release events
+ m_pressed = false;
+
+ if( sortedList.count( ) > 0 )
+ {
+ PMObjectDrag* d = new PMObjectDrag( m_pPart, sortedList, viewport( ) );
+
+ hotspot.setX( m_pressedItem->pixmap( 0 )->width( ) / 2 );
+ hotspot.setY( m_pressedItem->pixmap( 0 )->height( ) / 2 );
+ if( sortedList.count( ) == 1 )
+ d->setPixmap( SmallIcon(
+ sortedList.first( )->pixmap( ) ), hotspot );
+ else
+ d->setPixmap( SmallIcon( "pmdrag" ) );
+
+ if( d->drag( ) )
+ {
+ kdDebug( PMArea ) << "Drag returned true\n";
+ if( !targetDisplaysPart( d->target( ) ) )
+ m_pPart->dragMoveSelectionTo( 0 );
+ }
+ }
+ }
+ }
+}
+
+void PMTreeView::viewportDragMoveEvent( QDragMoveEvent *e )
+{
+ bool accept = false;
+
+ if( m_pPart->isReadWrite( ) )
+ {
+ if( PMObjectDrag::canDecode( e, m_pPart ) )
+ {
+ PMTreeViewItem *item = ( PMTreeViewItem* ) itemAt( e->pos( ) );
+ PMObject* obj = 0;
+
+ if( !item )
+ {
+ accept = false;
+ /*
+ if( e->source( ) == viewport( ) )
+ {
+ if( m_pPart->scene( )->isSelected( ) )
+ accept = false;
+ else
+ accept = true;
+ }
+ else
+ accept = true;
+ obj = m_pPart->scene( );
+ */
+
+ m_pDragOverItem = 0L;
+ obj = 0;
+ }
+ else
+ {
+ obj = item->object( );
+ if( ( obj->isSelectable( ) &&
+ !obj->isSelected( ) ) || ( e->source( ) != viewport( ) ) )
+ {
+ accept = true;
+ setCurrentItem( item );
+ m_pDragOverItem = item;
+ }
+ else
+ {
+ accept = false;
+ m_pDragOverItem = 0L;
+ }
+ }
+
+ if( accept )
+ {
+ accept = false;
+ if( !obj->isReadOnly( ) )
+ accept = true;
+ if( obj->parent( ) )
+ if( !obj->parent( )->isReadOnly( ) )
+ accept = true;
+ }
+ }
+ else
+ accept = false;
+ }
+ else
+ accept = false;
+
+ if( accept )
+ e->acceptAction( );
+ else
+ e->ignore( );
+}
+
+void PMTreeView::viewportDragEnterEvent( QDragEnterEvent *e )
+{
+ m_pDragOverItem = 0L;
+
+ if( m_pPart->isReadWrite( ) )
+ e->accept( PMObjectDrag::canDecode( e, m_pPart ) );
+ else
+ e->ignore( );
+}
+
+void PMTreeView::viewportDragLeaveEvent( QDragLeaveEvent* )
+{
+ m_pDragOverItem = 0L;
+}
+
+void PMTreeView::viewportDropEvent( QDropEvent* e )
+{
+ PMObject* obj;
+
+ if( m_pPart->isReadWrite( ) )
+ {
+ if( m_pDragOverItem )
+ obj = m_pDragOverItem->object( );
+ else
+ obj = m_pPart->scene( );
+
+ if( PMObjectDrag::canDecode( e, m_pPart ) )
+ {
+ if( targetDisplaysPart( e->source( ) ) &&
+ ( e->action( ) == QDropEvent::Move ) )
+ {
+ if( m_pPart->dragMoveSelectionTo( obj ) )
+ e->acceptAction( );
+ else
+ e->ignore( );
+ }
+ else
+ {
+ if( m_pPart->drop( obj, e ) )
+ e->acceptAction( );
+ else
+ e->ignore( );
+ }
+ }
+ else
+ e->ignore( );
+ }
+ else
+ e->ignore( );
+
+ m_pDragOverItem = 0L;
+}
+
+void PMTreeView::focusOutEvent( QFocusEvent* e )
+{
+ QWidget::focusOutEvent( e );
+ m_pressed = false;
+ m_pressedItem = 0;
+}
+
+void PMTreeView::focusInEvent( QFocusEvent* e )
+{
+ QWidget::focusInEvent( e );
+ m_pressed = false;
+ m_pressedItem = 0;
+}
+
+void PMTreeView::keyPressEvent( QKeyEvent* e )
+{
+ QListViewItem* current = currentItem( );
+ QListViewItem* newSelection = 0;
+ bool accept = false;
+ bool deleteItem = false;
+ bool pasteItem = false;
+
+ if( current )
+ {
+ switch( e->key( ) )
+ {
+ case Qt::Key_Up:
+ newSelection = current->itemAbove( );
+ accept = true;
+ break;
+ case Qt::Key_Down:
+ newSelection = current->itemBelow( );
+ accept = true;
+ break;
+ case Qt::Key_Left:
+ newSelection = current->parent( );
+ accept = true;
+ break;
+ case Qt::Key_Right:
+ newSelection = current->firstChild( );
+ accept = true;
+ break;
+ case Qt::Key_Plus:
+ current->setOpen( true );
+ accept = true;
+ break;
+ case Qt::Key_Minus:
+ current->setOpen( false );
+ accept = true;
+ case Qt::Key_Delete:
+ deleteItem = true;
+ accept = true;
+ break;
+ case Qt::CTRL+Qt::Key_V:
+ case Qt::SHIFT+Qt::Key_Insert:
+ pasteItem = true;
+ accept = true;
+ break;
+ }
+ }
+
+ if( newSelection )
+ {
+ m_acceptSelect = true;
+ clearSelection( );
+ newSelection->setSelected( true );
+ setCurrentItem( newSelection );
+ ensureItemVisible( newSelection );
+ m_acceptSelect = false;
+
+ emit objectChanged( ( ( PMTreeViewItem* ) newSelection )->object( ),
+ PMCNewSelection, this );
+ }
+
+ if( deleteItem && m_pPart->isReadWrite( ) )
+ {
+ m_pPart->slotEditDelete( );
+ m_pPart->setModified( true );
+ }
+
+ if( pasteItem && m_pPart->isReadWrite( ) )
+ {
+ m_pPart->slotEditPaste( );
+ m_pPart->setModified( true );
+ }
+
+ if( accept )
+ e->accept( );
+ else
+ e->ignore( );
+ QWidget::keyPressEvent( e );
+}
+
+bool PMTreeView::targetDisplaysPart( QWidget* target )
+{
+ bool result = false;
+ if( !target ) // another application
+ result = false;
+ else if( target == viewport( ) ) // self
+ result = true;
+ else
+ {
+ // Widget may be a view port
+ // find the tree view
+ QWidget* t = target;
+ while( t && !t->isA( "PMTreeView" ) )
+ t = t->parentWidget( );
+ if( t )
+ if( ( ( PMTreeView* ) t )->part( ) == m_pPart )
+ result = true;
+ }
+ return result;
+}
+
+QString PMTreeViewFactory::description( ) const
+{
+ return i18n( "Object Tree" );
+}
+
+#include "pmtreeview.moc"
diff --git a/kpovmodeler/pmtreeview.h b/kpovmodeler/pmtreeview.h
new file mode 100644
index 00000000..24f6f33f
--- /dev/null
+++ b/kpovmodeler/pmtreeview.h
@@ -0,0 +1,182 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMTREEVIEW_H
+#define PMTREEVIEW_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qlistview.h>
+#include "pmobject.h"
+#include "pmviewbase.h"
+#include "pmviewfactory.h"
+
+class PMTreeViewItem;
+class PMPart;
+
+/**
+ * Wrapper class for the treeview/dock widget
+ */
+class PMTreeViewWidget : public PMViewBase
+{
+public:
+ /**
+ * Default constructor
+ */
+ PMTreeViewWidget( PMPart* pare, QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual QString viewType( ) const { return QString( "treeview" ); }
+ /** */
+ virtual QString description( ) const;
+};
+
+/**
+ * Widget that displays the scene as tree view
+ */
+class PMTreeView : public QListView
+{
+ Q_OBJECT
+ friend class PMTreeViewItem;
+public:
+ /**
+ * Creates a PMTreeView with parent and name that displays the
+ * document doc
+ */
+ PMTreeView( PMPart* part, QWidget* parent = 0, const char* name = 0 );
+ /**
+ * Deletes the PMTreeView
+ */
+ ~PMTreeView( );
+
+ /**
+ * Returns true PMTreeViewItem::setSelected should be accepted
+ */
+ bool acceptSelect( ) const { return m_acceptSelect; }
+ /**
+ * Returns the connected part
+ */
+ PMPart* part( ) const { return m_pPart; }
+
+public slots:
+ /**
+ * Called when an object is changed.
+ * @see PMPart::objectChanged( ) */
+ void slotObjectChanged( PMObject* obj, const int mode, QObject* sender );
+ /**
+ * Refreshes the whole csg tree
+ */
+ void slotRefresh( );
+ /**
+ * Clears all data
+ */
+ void slotClear( );
+
+signals:
+ /**
+ * Emitted, when an object is selected or deselected
+ */
+ void objectChanged( PMObject* obj, const int mode, QObject* sender );
+ /**
+ * Emitted in the destructor
+ */
+ void destroyed( PMTreeView* v );
+
+protected:
+ void contentsMousePressEvent( QMouseEvent * e );
+ void contentsMouseMoveEvent( QMouseEvent * e );
+ void itemSelected( PMTreeViewItem* item, bool selected );
+
+ void viewportMousePressEvent( QMouseEvent * e );
+ void viewportMouseReleaseEvent( QMouseEvent* e );
+ void viewportMouseMoveEvent( QMouseEvent* e );
+
+ void viewportDragMoveEvent( QDragMoveEvent *e );
+ void viewportDragEnterEvent( QDragEnterEvent *e );
+ void viewportDragLeaveEvent( QDragLeaveEvent* e );
+ void viewportDropEvent( QDropEvent* e );
+
+ void focusOutEvent( QFocusEvent* e );
+ void focusInEvent( QFocusEvent* e );
+
+ void keyPressEvent( QKeyEvent* e );
+
+private:
+ /**
+ * Adds child items of item to the tree view
+ */
+ void addChildItems( PMTreeViewItem* item );
+ /**
+ * Returns the ListViewItem connected with the PMObject obj
+ */
+ PMTreeViewItem* findObject( const PMObject* obj );
+ /**
+ * Selects the item. Expands the tree if necessary
+ */
+ void selectItem( QListViewItem* item );
+ /**
+ * Returns true if the drop target is a tree view for the same part
+ */
+ bool targetDisplaysPart( QWidget* target );
+
+ /**
+ * the displayed document
+ */
+ PMPart* m_pPart;
+
+ /**
+ * the selected items
+ */
+// QPtrList<PMTreeViewItem> m_selectedItems;
+ PMTreeViewItem* m_pLastSelected;
+ bool m_itemSelected;
+ bool m_itemDeselected;
+ bool m_selectionCleared;
+ bool m_event;
+ bool m_acceptSelect;
+ bool m_selectOnReleaseEvent;
+
+ PMTreeViewItem* m_pDragOverItem;
+// QStringList m_lstDropFormats;
+
+ // for drag and drop, copied from KonqBaseListViewWidget
+ bool m_pressed;
+ QPoint m_pressedPos;
+ PMTreeViewItem* m_pressedItem;
+};
+
+/**
+ * Factory class for the tree view
+ */
+class PMTreeViewFactory : public PMViewTypeFactory
+{
+public:
+ PMTreeViewFactory( ) { }
+ virtual QString viewType( ) const { return QString( "treeview" ); }
+ virtual QString description( ) const;
+ virtual QString iconName( ) const { return QString( "pmtreeview" ); }
+ virtual PMViewBase* newInstance( QWidget* parent, PMPart* part ) const
+ {
+ return new PMTreeViewWidget( part, parent );
+ }
+};
+
+#endif
diff --git a/kpovmodeler/pmtreeviewitem.cpp b/kpovmodeler/pmtreeviewitem.cpp
new file mode 100644
index 00000000..72562f78
--- /dev/null
+++ b/kpovmodeler/pmtreeviewitem.cpp
@@ -0,0 +1,117 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmtreeviewitem.h"
+#include "pmobject.h"
+#include <kiconloader.h>
+
+#include "pmtreeview.h"
+#include "pmfactory.h"
+#include "pmtexturemap.h"
+
+PMTreeViewItem::PMTreeViewItem( PMObject* object, QListView* parent )
+ : QListViewItem( parent )
+{
+ m_pObject = object;
+ setDescriptions( );
+ initSelection( );
+}
+
+PMTreeViewItem::PMTreeViewItem( PMObject* object, QListViewItem* parent )
+ : QListViewItem( parent )
+{
+ m_pObject = object;
+ setDescriptions( );
+ initSelection( );
+}
+
+PMTreeViewItem::PMTreeViewItem( PMObject* object, QListView* parent,
+ QListViewItem* after )
+ : QListViewItem( parent, after )
+{
+ m_pObject = object;
+ setDescriptions( );
+ initSelection( );
+}
+
+PMTreeViewItem::PMTreeViewItem( PMObject* object, QListViewItem* parent,
+ QListViewItem* after )
+ : QListViewItem( parent, after )
+{
+ m_pObject = object;
+ setDescriptions( );
+ initSelection( );
+}
+
+void PMTreeViewItem::setDescriptions( )
+{
+ QString text;
+ setPixmap( 0, SmallIcon( m_pObject->pixmap( ), PMFactory::instance( ) ) );
+
+ if( m_pObject->canHaveName( ) )
+ {
+ text = m_pObject->name( );
+ if( text.isEmpty( ) )
+ text = m_pObject->description( );
+ }
+ else
+ text = m_pObject->description( );
+
+ if( m_pObject->parent( ) )
+ {
+ if( m_pObject->parent( )->isA( "TextureMapBase" ) )
+ {
+ PMTextureMapBase* tm = ( PMTextureMapBase* ) m_pObject->parent( );
+ if( m_pObject->type( ) == tm->mapType( ) )
+ text = QString( "[%1] " ).arg( tm->mapValue( m_pObject ), 4, 'f', 2 ) + text;
+ }
+ }
+ setText( 0, text );
+}
+
+QString PMTreeViewItem::key( int, bool ) const
+{
+ QString result;
+ if( m_pObject->parent( ) )
+ result.sprintf( "%06i", m_pObject->parent( )->findChild( m_pObject ) );
+ else
+ result = "000000";
+ return result;
+}
+
+void PMTreeViewItem::setSelected( bool select )
+{
+ bool ws = isSelected( );
+ PMTreeView* treeview = ( PMTreeView* ) listView( );
+
+ // ignore selections during a move event
+ if( treeview->acceptSelect( ) )
+ {
+ QListViewItem::setSelected( select );
+
+ if( ws != isSelected( ) )
+ treeview->itemSelected( this, isSelected( ) );
+ }
+}
+
+void PMTreeViewItem::initSelection( )
+{
+ QListViewItem::setSelected( m_pObject->isSelected( ) );
+// if( m_pObject->isSelected( ) )
+// repaint( );
+}
diff --git a/kpovmodeler/pmtreeviewitem.h b/kpovmodeler/pmtreeviewitem.h
new file mode 100644
index 00000000..499e2d16
--- /dev/null
+++ b/kpovmodeler/pmtreeviewitem.h
@@ -0,0 +1,88 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMTREEVIEWITEM_H
+#define PMTREEVIEWITEM_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qlistview.h>
+class PMObject;
+
+/**
+ * QListViewItem for a @ref PMObject
+ *
+ * Each PMListViewItem is connected to a PMObject.
+ */
+class PMTreeViewItem : public QListViewItem
+{
+public:
+ /**
+ * Constructs a new top-level list view item in the QListView parent.
+ */
+ PMTreeViewItem( PMObject* object, QListView* parent );
+ /**
+ * Constructs a new list view item which is a child of parent and
+ * first in the parent's list of children.
+ */
+ PMTreeViewItem( PMObject* object, QListViewItem* parent );
+ /**
+ * Constructs a list view item which is a child of parent
+ * and is after after in the parent's list of children.
+ */
+ PMTreeViewItem( PMObject* object, QListView* parent, QListViewItem* after );
+ /**
+ * Constructs a list view item which is a child of parent
+ * and is after after in the parent's list of children.
+ */
+ PMTreeViewItem( PMObject* object, QListViewItem* parent,
+ QListViewItem* after );
+ /**
+ * Returns the connected @ref PMObject
+ */
+ PMObject* object( ) const { return m_pObject; }
+ /**
+ * Returns a key that can be used for sorting, here the index in the
+ * parents list of children
+ */
+ virtual QString key( int column, bool ascending ) const;
+ /**
+ * Returns a pointer to the parent item
+ */
+ PMTreeViewItem* parent( )
+ {
+ return ( PMTreeViewItem* ) QListViewItem::parent( );
+ }
+ void setSelected( bool select );
+
+ /**
+ * Sets the text and pixmap
+ */
+ void setDescriptions( );
+private:
+ /**
+ * Initializes the selection at creation
+ */
+ void initSelection( );
+ PMObject* m_pObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmtriangle.cpp b/kpovmodeler/pmtriangle.cpp
new file mode 100644
index 00000000..3cae7e37
--- /dev/null
+++ b/kpovmodeler/pmtriangle.cpp
@@ -0,0 +1,621 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmtriangle.h"
+#include "pmtriangleedit.h"
+
+#include "pmxmlhelper.h"
+#include "pmmemento.h"
+#include "pmviewstructure.h"
+#include "pm3dcontrolpoint.h"
+#include "pmvectorcontrolpoint.h"
+
+#include <klocale.h>
+
+const PMVector point0Default = PMVector( -1.0, 0.0, 0.0 );
+const PMVector point1Default = PMVector( 1.0, 0.0, 0.0 );
+const PMVector point2Default = PMVector( 0.0, 0.0, 1.0 );
+const PMVector normal0Default = PMVector( 0.0, 1.0, 0.0 );
+const PMVector normal1Default = PMVector( 0.0, 1.0, 0.0 );
+const PMVector normal2Default = PMVector( 0.0, 1.0, 0.0 );
+const PMVector uvVector0Default = PMVector( 0.0, 0.0 );
+const PMVector uvVector1Default = PMVector( 1.0, 0.0 );
+const PMVector uvVector2Default = PMVector( 0.5, 1.0 );
+
+PMDefinePropertyClass( PMTriangle, PMTriangleProperty );
+
+class PMPointProperty : public PMPropertyBase
+{
+public:
+ PMPointProperty( ) : PMPropertyBase( "points", PMVariant::Vector )
+ {
+ m_index = 0;
+ }
+ virtual int dimensions( ) const { return 1; }
+ virtual void setIndex( int /*dimension*/, int index )
+ {
+ if( index < 0 || index > 2 )
+ kdError( PMArea ) << "Illegal index in PMTriangle::PointProperty::setIndex" << endl;
+ else
+ m_index = index;
+ }
+ virtual int size( PMObject* /*object*/, int /*dimension*/ ) const
+ {
+ return 3;
+ }
+protected:
+ virtual bool setProtected( PMObject* obj, const PMVariant& v )
+ {
+ PMTriangle* p = ( PMTriangle* ) obj;
+ p->setPoint( m_index, v.vectorData( ) );
+ return true;
+ }
+ virtual PMVariant getProtected( const PMObject* obj )
+ {
+ const PMTriangle* p = ( const PMTriangle* ) obj;
+ return PMVariant( p->point( m_index ) );
+ }
+
+private:
+ int m_index;
+};
+
+class PMNormalProperty : public PMPropertyBase
+{
+public:
+ PMNormalProperty( ) : PMPropertyBase( "normals", PMVariant::Vector )
+ {
+ m_index = 0;
+ }
+ virtual int dimensions( ) const { return 1; }
+ virtual void setIndex( int /*dimension*/, int index )
+ {
+ if( index < 0 || index > 2 )
+ kdError( PMArea ) << "Illegal index in PMTriangle::NormalProperty::setIndex" << endl;
+ else
+ m_index = index;
+ }
+ virtual int size( PMObject* /*object*/, int /*dimension*/ ) const
+ {
+ return 3;
+ }
+protected:
+ virtual bool setProtected( PMObject* obj, const PMVariant& v )
+ {
+ PMTriangle* p = ( PMTriangle* ) obj;
+ p->setNormal( m_index, v.vectorData( ) );
+ return true;
+ }
+ virtual PMVariant getProtected( const PMObject* obj )
+ {
+ const PMTriangle* p = ( const PMTriangle* ) obj;
+ return PMVariant( p->normal( m_index ) );
+ }
+
+private:
+ int m_index;
+};
+
+class PMUVVectorProperty : public PMPropertyBase
+{
+public:
+ PMUVVectorProperty( )
+ : PMPropertyBase( "uvVectors", PMVariant::Vector )
+ {
+ m_index = 0;
+ }
+ virtual int dimensions( ) const { return 1; }
+ virtual void setIndex( int /*dimension*/, int index )
+ {
+ if( index < 0 || index > 2 )
+ kdError( PMArea ) << "Illegal index in PMTriangle::UVVectorProperty::setIndex" << endl;
+ else
+ m_index = index;
+ }
+ virtual int size( PMObject* /*object*/, int /*dimension*/ ) const
+ {
+ return 2;
+ }
+protected:
+ virtual bool setProtected( PMObject* obj, const PMVariant& v )
+ {
+ PMTriangle* p = ( PMTriangle* ) obj;
+ p->setUVVector( m_index, v.vectorData( ) );
+ return true;
+ }
+ virtual PMVariant getProtected( const PMObject* obj )
+ {
+ const PMTriangle* p = ( const PMTriangle* ) obj;
+ return PMVariant( p->uvVector( m_index ) );
+ }
+
+private:
+ int m_index;
+};
+
+PMMetaObject* PMTriangle::s_pMetaObject = 0;
+PMObject* createNewTriangle( PMPart* part )
+{
+ return new PMTriangle( part );
+}
+PMViewStructure* PMTriangle::s_pDefaultViewStructure = 0;
+
+PMTriangle::PMTriangle( PMPart* part )
+ : Base( part )
+{
+ m_point[0] = point0Default;
+ m_point[1] = point1Default;
+ m_point[2] = point2Default;
+ m_normal[0] = normal0Default;
+ m_normal[1] = normal1Default;
+ m_normal[2] = normal2Default;
+ m_smooth = false;
+ m_uvVector[0] = uvVector0Default;
+ m_uvVector[1] = uvVector1Default;
+ m_uvVector[2] = uvVector2Default;
+ m_uvEnabled = false;
+}
+
+PMTriangle::PMTriangle( const PMTriangle& t )
+ : Base( t )
+{
+ int i;
+ for( i = 0; i < 3; i++ )
+ {
+ m_point[i] = t.m_point[i];
+ m_normal[i] = t.m_normal[i];
+ m_uvVector[i] = t.m_uvVector[i];
+ }
+ m_smooth = t.m_smooth;
+ m_uvEnabled = t.m_uvEnabled;
+}
+
+PMTriangle::~PMTriangle( )
+{
+}
+
+QString PMTriangle::description( ) const
+{
+ if( m_smooth )
+ return i18n( "smooth triangle" );
+ return i18n( "triangle" );
+}
+
+void PMTriangle::serialize( QDomElement& e, QDomDocument& doc ) const
+{
+ e.setAttribute( "point0", m_point[0].serializeXML( ) );
+ e.setAttribute( "point1", m_point[1].serializeXML( ) );
+ e.setAttribute( "point2", m_point[2].serializeXML( ) );
+ e.setAttribute( "normal0", m_normal[0].serializeXML( ) );
+ e.setAttribute( "normal1", m_normal[1].serializeXML( ) );
+ e.setAttribute( "normal2", m_normal[2].serializeXML( ) );
+ e.setAttribute( "smooth", m_smooth );
+ e.setAttribute( "uvVector0", m_uvVector[0].serializeXML( ) );
+ e.setAttribute( "uvVector1", m_uvVector[1].serializeXML( ) );
+ e.setAttribute( "uvVector2", m_uvVector[2].serializeXML( ) );
+ e.setAttribute( "uvEnabled", m_uvEnabled );
+ Base::serialize( e, doc );
+}
+
+void PMTriangle::readAttributes( const PMXMLHelper& h )
+{
+ m_point[0] = h.vectorAttribute( "point0", point0Default );
+ m_point[1] = h.vectorAttribute( "point1", point1Default );
+ m_point[2] = h.vectorAttribute( "point2", point2Default );
+ m_normal[0] = h.vectorAttribute( "normal0", normal0Default );
+ m_normal[1] = h.vectorAttribute( "normal1", normal1Default );
+ m_normal[2] = h.vectorAttribute( "normal2", normal2Default );
+ m_smooth = h.boolAttribute( "smooth", false );
+ m_uvVector[0] = h.vectorAttribute( "uvVector0", uvVector0Default );
+ m_uvVector[1] = h.vectorAttribute( "uvVector1", uvVector1Default );
+ m_uvVector[2] = h.vectorAttribute( "uvVector2", uvVector2Default );
+ m_uvEnabled = h.boolAttribute( "uvEnabled", m_uvEnabled );
+ Base::readAttributes( h );
+}
+
+PMMetaObject* PMTriangle::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Triangle", Base::metaObject( ),
+ createNewTriangle );
+ s_pMetaObject->addProperty(
+ new PMTriangleProperty( "smooth", &PMTriangle::setSmoothTriangle,
+ &PMTriangle::isSmoothTriangle ) );
+ s_pMetaObject->addProperty( new PMPointProperty( ) );
+ s_pMetaObject->addProperty( new PMNormalProperty( ) );
+ s_pMetaObject->addProperty( new PMUVVectorProperty( ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMTriangle::setPoint( int i, const PMVector& p )
+{
+ if( ( i >= 0 ) && ( i <= 2 ) )
+ {
+ if( p != m_point[i] )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMPoint0ID + i, m_point[i] );
+ m_point[i] = p;
+ m_point[i].resize( 3 );
+ setViewStructureChanged( );
+ }
+ }
+ else
+ kdError( PMArea ) << "Wrong index in PMTriangle::setPoint\n";
+}
+
+PMVector PMTriangle::point( int i ) const
+{
+ if( ( i >= 0 ) && ( i <= 2 ) )
+ return m_point[i];
+ else
+ kdError( PMArea ) << "Wrong index in PMTriangle::point\n";
+ return PMVector( 0.0, 0.0, 0.0 );
+}
+
+void PMTriangle::setNormal( int i, const PMVector& p )
+{
+ if( ( i >= 0 ) && ( i <= 2 ) )
+ {
+ if( p != m_normal[i] )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMNormal0ID + i, m_normal[i] );
+ m_normal[i] = p;
+ m_normal[i].resize( 3 );
+ setViewStructureChanged( );
+ }
+ }
+ else
+ kdError( PMArea ) << "Wrong index in PMTriangle::setNormal\n";
+}
+
+PMVector PMTriangle::normal( int i ) const
+{
+ if( ( i >= 0 ) && ( i <= 2 ) )
+ return m_normal[i];
+ else
+ kdError( PMArea ) << "Wrong index in PMTriangle::normal\n";
+ return PMVector( 0.0, 0.0, 0.0 );
+}
+
+void PMTriangle::setSmoothTriangle( bool on )
+{
+ if( on != m_smooth )
+ {
+ if( m_pMemento )
+ {
+ m_pMemento->addData( s_pMetaObject, PMSmoothID, m_smooth );
+ m_pMemento->setDescriptionChanged( );
+ }
+ m_smooth = on;
+ setViewStructureChanged( );
+ }
+}
+
+PMVector PMTriangle::uvVector( int i ) const
+{
+ if( i >= 0 && i < 3 )
+ return m_uvVector[i];
+ else
+ kdError( PMArea ) << "Wrong index in PMTriangle::uvVector\n";
+ return PMVector( 0.0, 0.0 );
+}
+
+void PMTriangle::setUVVector( int i, const PMVector& v )
+{
+ if( i >= 0 && i < 3 )
+ {
+ if( v != m_uvVector[i] )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMUVVector0ID + i, m_uvVector[i] );
+ m_uvVector[i] = v;
+ m_uvVector[i].resize( 2 );
+ }
+ }
+ else
+ kdError( PMArea ) << "Wrong index in PMTriangle::setNormal\n";
+}
+
+void PMTriangle::enableUV( bool yes )
+{
+ if( yes != m_uvEnabled )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMUVEnabledID, m_uvEnabled );
+ m_uvEnabled = yes;
+ }
+}
+
+PMDialogEditBase* PMTriangle::editWidget( QWidget* parent ) const
+{
+ return new PMTriangleEdit( parent );
+}
+
+void PMTriangle::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMPoint0ID:
+ setPoint( 0, data->vectorData( ) );
+ break;
+ case PMPoint1ID:
+ setPoint( 1, data->vectorData( ) );
+ break;
+ case PMPoint2ID:
+ setPoint( 2, data->vectorData( ) );
+ break;
+ case PMNormal0ID:
+ setNormal( 0, data->vectorData( ) );
+ break;
+ case PMNormal1ID:
+ setNormal( 1, data->vectorData( ) );
+ break;
+ case PMNormal2ID:
+ setNormal( 2, data->vectorData( ) );
+ break;
+ case PMSmoothID:
+ setSmoothTriangle( data->boolData( ) );
+ break;
+ case PMUVVector0ID:
+ setUVVector( 0, data->vectorData( ) );
+ break;
+ case PMUVVector1ID:
+ setUVVector( 1, data->vectorData( ) );
+ break;
+ case PMUVVector2ID:
+ setUVVector( 2, data->vectorData( ) );
+ break;
+ case PMUVEnabledID:
+ enableUV( data->boolData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMTriangle::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
+
+
+bool PMTriangle::isDefault( )
+{
+ if( ( m_point[0] == point0Default )
+ && ( m_point[1] == point1Default )
+ && ( m_point[2] == point2Default ) )
+ return true;
+ return false;
+}
+
+void PMTriangle::createViewStructure( )
+{
+ if( !m_pViewStructure )
+ {
+ m_pViewStructure = new PMViewStructure( defaultViewStructure( ) );
+ m_pViewStructure->points( ).detach( );
+ }
+
+ PMPointArray& points = m_pViewStructure->points( );
+
+ points[0] = m_point[0];
+ points[1] = m_point[1];
+ points[2] = m_point[2];
+}
+
+PMViewStructure* PMTriangle::defaultViewStructure( ) const
+{
+ if( !s_pDefaultViewStructure )
+ {
+ s_pDefaultViewStructure = new PMViewStructure( 3, 3 );
+ PMPointArray& points = s_pDefaultViewStructure->points( );
+ PMLineArray& lines = s_pDefaultViewStructure->lines( );
+
+ points[0] = point0Default;
+ points[1] = point1Default;
+ points[2] = point2Default;
+
+ lines[0] = PMLine( 0, 1 );
+ lines[1] = PMLine( 1, 2 );
+ lines[2] = PMLine( 0, 2 );
+ }
+ return s_pDefaultViewStructure;
+}
+
+void PMTriangle::controlPoints( PMControlPointList& list )
+{
+ PM3DControlPoint* cp;
+
+ cp = new PM3DControlPoint( m_point[0], PMPoint0ID,
+ i18n( "Point 1" ) );
+ list.append( cp );
+ if( m_smooth )
+ list.append( new PMVectorControlPoint( cp, m_normal[0], PMNormal0ID,
+ i18n( "Normal 1" ) ) );
+
+ cp = new PM3DControlPoint( m_point[1], PMPoint1ID,
+ i18n( "Point 2" ) );
+ list.append( cp );
+ if( m_smooth )
+ list.append( new PMVectorControlPoint( cp, m_normal[1], PMNormal1ID,
+ i18n( "Normal 2" ) ) );
+
+ cp = new PM3DControlPoint( m_point[2], PMPoint2ID,
+ i18n( "Point 3" ) );
+ list.append( cp );
+ if( m_smooth )
+ list.append( new PMVectorControlPoint( cp, m_normal[2], PMNormal2ID,
+ i18n( "Normal 3" ) ) );
+}
+
+void PMTriangle::controlPointsChanged( PMControlPointList& list )
+{
+ PMControlPoint* p;
+ PMVector p0, p1, p2;
+ PMVector n0, n1, n2;
+ double normalDirection = 1.0;
+ PMVector triangleNormal;
+ bool validNormal = false;
+ double d;
+
+ for( p = list.first( ); p; p = list.next( ) )
+ {
+ switch( p->id( ) )
+ {
+ case PMPoint0ID:
+ p0 = ( ( PM3DControlPoint* ) p )->point( );
+ break;
+ case PMPoint1ID:
+ p1 = ( ( PM3DControlPoint* ) p )->point( );
+ break;
+ case PMPoint2ID:
+ p2 = ( ( PM3DControlPoint* ) p )->point( );
+ break;
+ case PMNormal0ID:
+ n0 = ( ( PMVectorControlPoint* ) p )->vector( );
+ break;
+ case PMNormal1ID:
+ n1 = ( ( PMVectorControlPoint* ) p )->vector( );
+ break;
+ case PMNormal2ID:
+ n2 = ( ( PMVectorControlPoint* ) p )->vector( );
+ break;
+ default:
+ break;
+ }
+ }
+
+ if( m_smooth )
+ {
+ triangleNormal = PMVector::cross( m_point[1] - m_point[0],
+ m_point[2] - m_point[0] );
+ normalDirection = PMVector::dot( triangleNormal, m_normal[0] );
+ if( approxZero( normalDirection ) )
+ normalDirection = PMVector::dot( triangleNormal, m_normal[1] );
+ if( approxZero( normalDirection ) )
+ normalDirection = PMVector::dot( triangleNormal, m_normal[2] );
+ if( normalDirection < 0 )
+ triangleNormal = -triangleNormal;
+ if( !approxZero( triangleNormal.abs( ) ) )
+ {
+ validNormal = true;
+ triangleNormal /= triangleNormal.abs( );
+ }
+ }
+
+ for( p = list.first( ); p; p = list.next( ) )
+ {
+ if( p->changed( ) )
+ {
+ switch( p->id( ) )
+ {
+ case PMPoint0ID:
+ if( !( p0.approxEqual( p1 ) || p0.approxEqual( p2 ) ) )
+ setPoint( 0, p0 );
+ else
+ ( ( PM3DControlPoint* ) p )->setPoint( m_point[0] );
+ break;
+ case PMPoint1ID:
+ if( !( p1.approxEqual( p0 ) || p1.approxEqual( p2 ) ) )
+ setPoint( 1, p1 );
+ else
+ ( ( PM3DControlPoint* ) p )->setPoint( m_point[1] );
+ break;
+ case PMPoint2ID:
+ if( !( p2.approxEqual( p0 ) || p2.approxEqual( p1 ) ) )
+ setPoint( 2, p2 );
+ else
+ ( ( PM3DControlPoint* ) p )->setPoint( m_point[2] );
+ break;
+
+ case PMNormal0ID:
+ if( validNormal )
+ {
+ d = PMVector::dot( triangleNormal, n0 );
+ if( d > 0 )
+ setNormal( 0, n0 );
+ else
+ {
+ setNormal( 0, n0 - ( d - 1e-5 ) * triangleNormal );
+ ( ( PMVectorControlPoint* ) p )->setVector( m_normal[0] );
+ }
+ }
+ else
+ ( ( PMVectorControlPoint* ) p )->setVector( m_normal[0] );
+ break;
+ case PMNormal1ID:
+ if( validNormal )
+ {
+ d = PMVector::dot( triangleNormal, n1 );
+ if( d > 0 )
+ setNormal( 1, n1 );
+ else
+ {
+ setNormal( 1, n1 - ( d - 1e-5 ) * triangleNormal );
+ ( ( PMVectorControlPoint* ) p )->setVector( m_normal[1] );
+ }
+ }
+ else
+ ( ( PMVectorControlPoint* ) p )->setVector( m_normal[1] );
+ break;
+ case PMNormal2ID:
+ if( validNormal )
+ {
+ d = PMVector::dot( triangleNormal, n2 );
+ if( d > 0 )
+ setNormal( 2, n2 );
+ else
+ {
+ setNormal( 2, n2 - ( d - 1e-5 ) * triangleNormal );
+ ( ( PMVectorControlPoint* ) p )->setVector( m_normal[2] );
+ }
+ }
+ else
+ ( ( PMVectorControlPoint* ) p )->setVector( m_normal[2] );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMTriangle::controlPointsChanged\n";
+ break;
+ }
+ }
+ }
+}
+
+void PMTriangle::cleanUp( ) const
+{
+ if( s_pDefaultViewStructure )
+ delete s_pDefaultViewStructure;
+ s_pDefaultViewStructure = 0;
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
diff --git a/kpovmodeler/pmtriangle.h b/kpovmodeler/pmtriangle.h
new file mode 100644
index 00000000..e2309c79
--- /dev/null
+++ b/kpovmodeler/pmtriangle.h
@@ -0,0 +1,158 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMTRIANGLE_H
+#define PMTRIANGLE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmgraphicalobject.h"
+#include "pmvector.h"
+
+class PMViewStructure;
+
+/**
+ * Class for povray triangles.
+ */
+
+class PMTriangle : public PMGraphicalObject
+{
+ typedef PMGraphicalObject Base;
+public:
+ /**
+ * Creates an empty PMTriangle
+ */
+ PMTriangle( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMTriangle( const PMTriangle& t );
+ /**
+ * deletes the PMTriangle
+ */
+ virtual ~PMTriangle( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMTriangle( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+ /**
+ * Returns a new @ref PMTriangleEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmtriangle" ); }
+
+ /**
+ * Returns true if the triangle is a smooth triangle
+ */
+ bool isSmoothTriangle( ) const { return m_smooth; }
+ /**
+ * Enables/disables the normal vectors
+ */
+ void setSmoothTriangle( bool on );
+
+ /**
+ * Returns the point with index i
+ */
+ PMVector point( int i ) const;
+ /**
+ * Sets the point with index i
+ */
+ void setPoint( int i, const PMVector& p );
+ /**
+ * Returns the normal vector with index i
+ */
+ PMVector normal( int i ) const;
+ /**
+ * Sets the mormal vector with index i
+ */
+ void setNormal( int i, const PMVector& n );
+
+ /**
+ * Returns the uv vector with index i
+ */
+ PMVector uvVector( int i ) const;
+ /**
+ * Sets the uv vector with index i
+ */
+ void setUVVector( int i, const PMVector& v );
+ /**
+ * Return true if triangle has uv vectors
+ */
+ bool isUVEnabled( ) const { return m_uvEnabled; }
+ /**
+ * Enables/disable the uv vectors
+ */
+ void enableUV( bool yes );
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+ /** */
+ virtual void controlPoints( PMControlPointList& list );
+ /** */
+ virtual void controlPointsChanged( PMControlPointList& list );
+ /** */
+ virtual void cleanUp( ) const;
+
+protected:
+ /** */
+ virtual bool isDefault( );
+ /** */
+ virtual void createViewStructure( );
+ /** */
+ virtual PMViewStructure* defaultViewStructure( ) const;
+
+protected:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMTriangleMementoID { PMPoint0ID, PMPoint1ID, PMPoint2ID,
+ PMNormal0ID, PMNormal1ID, PMNormal2ID,
+ PMSmoothID,
+ PMUVVector0ID, PMUVVector1ID, PMUVVector2ID,
+ PMUVEnabledID };
+ PMVector m_point[3];
+ PMVector m_normal[3];
+ PMVector m_uvVector[3];
+ bool m_smooth;
+ bool m_uvEnabled;
+
+ /**
+ * The default view structure. It can be shared between triangles
+ */
+ static PMViewStructure* s_pDefaultViewStructure;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmtriangleedit.cpp b/kpovmodeler/pmtriangleedit.cpp
new file mode 100644
index 00000000..7b225aa8
--- /dev/null
+++ b/kpovmodeler/pmtriangleedit.cpp
@@ -0,0 +1,273 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmtriangleedit.h"
+#include "pmtriangle.h"
+#include "pmvectoredit.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <qpushbutton.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+
+PMTriangleEdit::PMTriangleEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMTriangleEdit::createTopWidgets( )
+{
+ Base::createTopWidgets( );
+
+ int i;
+
+ QHBoxLayout *hl = new QHBoxLayout( topLayout( ) );
+ m_pSmooth = new QCheckBox( i18n( "Smooth" ), this );
+ hl->addWidget( m_pSmooth );
+ connect( m_pSmooth, SIGNAL( toggled( bool ) ),
+ SLOT( slotSmoothChecked( bool ) ) );
+
+ m_pUVEnabled = new QCheckBox( i18n( "UV vectors" ), this );
+ hl->addWidget( m_pUVEnabled );
+ connect( m_pUVEnabled, SIGNAL( toggled( bool ) ),
+ SLOT( slotUVVectorsChecked( bool ) ) );
+
+ QGridLayout* gl = new QGridLayout( topLayout( ), 9, 2 );
+
+ for( i = 0; i < 3; i++ )
+ {
+ m_pPoint[i] = new PMVectorEdit( "x", "y", "z", this );
+ gl->addWidget( new QLabel( i18n( "Point %1:" ).arg( i+1 ), this ),
+ i * 3, 0 );
+ gl->addWidget( m_pPoint[i], i * 3, 1 );
+ connect( m_pPoint[i], SIGNAL( dataChanged( ) ),
+ SIGNAL( dataChanged( ) ) );
+
+ m_pNormal[i] = new PMVectorEdit( "x", "y", "z", this );
+ m_pNormalLabel[i] = new QLabel( i18n( "Normal %1:" ).arg( i+1 ), this );
+ gl->addWidget( m_pNormalLabel[i], i * 3 + 1, 0 );
+ gl->addWidget( m_pNormal[i], i * 3 + 1, 1 );
+ connect( m_pNormal[i], SIGNAL( dataChanged( ) ),
+ SIGNAL( dataChanged( ) ) );
+
+ m_pUVVector[i] = new PMVectorEdit( "u", "v", this );
+ m_pUVVectorLabel[i] = new QLabel( i18n( "UV vector %1:" ).arg( i+1 ), this );
+ gl->addWidget( m_pUVVectorLabel[i], i * 3 + 2, 0 );
+ gl->addWidget( m_pUVVector[i], i * 3 + 2, 1 );
+ connect( m_pUVVector[i], SIGNAL( dataChanged( ) ),
+ SIGNAL( dataChanged( ) ) );
+ }
+ hl = new QHBoxLayout( topLayout( ) );
+ m_pMirror = new QPushButton( i18n( "Invert Normal Vectors" ), this );
+ hl->addWidget( m_pMirror );
+ hl->addStretch( 1 );
+ connect( m_pMirror, SIGNAL( clicked( ) ), SLOT( slotInvertNormals( ) ) );
+}
+
+void PMTriangleEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Triangle" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMTriangle* ) o;
+ bool smooth = m_pDisplayedObject->isSmoothTriangle( );
+ bool uvVector = m_pDisplayedObject->isUVEnabled( );
+ int i;
+
+ for( i = 0; i < 3; i++ )
+ {
+ m_pPoint[i]->setVector( m_pDisplayedObject->point( i ) );
+ m_pPoint[i]->setReadOnly( readOnly );
+
+ m_pNormal[i]->setVector( m_pDisplayedObject->normal( i ) );
+ m_pNormal[i]->setReadOnly( readOnly );
+
+ m_pUVVector[i]->setVector( m_pDisplayedObject->uvVector( i ) );
+ m_pUVVector[i]->setReadOnly( readOnly );
+
+ m_pSmooth->setChecked( smooth );
+ if( smooth )
+ {
+ m_pNormal[i]->show( );
+ m_pNormalLabel[i]->show( );
+ m_pMirror->show( );
+ }
+ else
+ {
+ m_pNormal[i]->hide( );
+ m_pNormalLabel[i]->hide( );
+ m_pMirror->hide( );
+ }
+
+ m_pUVEnabled->setChecked( uvVector );
+ if( uvVector )
+ {
+ m_pUVVector[i]->show( );
+ m_pUVVectorLabel[i]->show( );
+ }
+ else
+ {
+ m_pUVVector[i]->hide( );
+ m_pUVVectorLabel[i]->hide( );
+ }
+
+ emit sizeChanged( );
+ }
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMTriangleEdit: Can't display object\n";
+}
+
+void PMTriangleEdit::slotSmoothChecked( bool on )
+{
+ int i;
+ for( i = 0; i < 3; i++ )
+ {
+ if( on )
+ {
+ m_pNormal[i]->show( );
+ m_pNormalLabel[i]->show( );
+ m_pMirror->show( );
+ }
+ else
+ {
+ m_pNormal[i]->hide( );
+ m_pNormalLabel[i]->hide( );
+ m_pMirror->hide( );
+ }
+ }
+ emit sizeChanged( );
+ emit dataChanged( );
+}
+
+void PMTriangleEdit::slotUVVectorsChecked( bool on )
+{
+ int i;
+ for( i = 0; i < 3; ++i )
+ {
+ if( on )
+ {
+ m_pUVVector[i]->show( );
+ m_pUVVectorLabel[i]->show( );
+ }
+ else
+ {
+ m_pUVVector[i]->hide( );
+ m_pUVVectorLabel[i]->hide( );
+ }
+ }
+ emit sizeChanged( );
+ emit dataChanged( );
+}
+
+void PMTriangleEdit::slotInvertNormals( )
+{
+ int i;
+ for( i = 0; i < 3; i++ )
+ if( !m_pNormal[i]->isDataValid( ) )
+ return;
+
+ for( i = 0; i < 3; i++ )
+ m_pNormal[i]->setVector( -( m_pNormal[i]->vector( ) ) );
+}
+
+void PMTriangleEdit::saveContents( )
+{
+ int i;
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ for( i = 0; i < 3; i++ )
+ m_pDisplayedObject->setPoint( i, m_pPoint[i]->vector( ) );
+
+ if( m_pSmooth->isChecked( ) )
+ {
+ m_pDisplayedObject->setSmoothTriangle( true );
+ for( i = 0; i < 3; i++ )
+ m_pDisplayedObject->setNormal( i, m_pNormal[i]->vector( ) );
+ }
+ else
+ m_pDisplayedObject->setSmoothTriangle( false );
+
+ if( m_pUVEnabled->isChecked( ) )
+ {
+ m_pDisplayedObject->enableUV( true );
+ for( i = 0; i < 3; ++i )
+ m_pDisplayedObject->setUVVector( i, m_pUVVector[i]->vector( ) );
+ }
+ else
+ m_pDisplayedObject->enableUV( false );
+ }
+}
+
+bool PMTriangleEdit::isDataValid( )
+{
+ int i;
+ for( i = 0; i < 3; i++ )
+ if( !m_pPoint[i]->isDataValid( ) )
+ return false;
+
+ PMVector p0 = m_pPoint[0]->vector( ),
+ p1 = m_pPoint[1]->vector( ),
+ p2 = m_pPoint[2]->vector( );
+
+ if( p0.approxEqual( p1 ) || p1.approxEqual( p2 ) || p0.approxEqual( p2 ) )
+ {
+ KMessageBox::error( this, i18n( "Please enter a valid triangle." ),
+ i18n( "Error" ) );
+ return false;
+ }
+
+ if( m_pSmooth->isChecked( ) )
+ {
+ for( i = 0; i < 3; i++ )
+ if( !m_pNormal[i]->isDataValid( ) )
+ return false;
+
+ PMVector n0 = m_pNormal[0]->vector( ),
+ n1 = m_pNormal[1]->vector( ),
+ n2 = m_pNormal[2]->vector( );
+ PMVector tn = PMVector::cross( p1 - p0, p2 - p0 );
+ double c0 = PMVector::dot( tn, n0 ),
+ c1 = PMVector::dot( tn, n1 ),
+ c2 = PMVector::dot( tn, n2 );
+ if( ( ( c0 * c1 ) < 0 ) || ( ( c0 * c2 ) < 0 ) )
+ {
+ KMessageBox::error( this, i18n( "All normal vectors have to point"
+ " to the same side of the triangle." ),
+ i18n( "Error" ) );
+ return false;
+ }
+ }
+
+ if( m_pUVEnabled->isChecked( ) )
+ {
+ for( i = 0; i < 3; ++i )
+ if( !m_pUVVector[i]->isDataValid( ) )
+ return false;
+ }
+
+ return Base::isDataValid( );
+}
+
+#include "pmtriangleedit.moc"
diff --git a/kpovmodeler/pmtriangleedit.h b/kpovmodeler/pmtriangleedit.h
new file mode 100644
index 00000000..821ad68d
--- /dev/null
+++ b/kpovmodeler/pmtriangleedit.h
@@ -0,0 +1,77 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMTRIANGLEEDIT_H
+#define PMTRIANGLEEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmgraphicalobjectedit.h"
+
+class PMTriangle;
+class PMVectorEdit;
+class QCheckBox;
+class QLabel;
+class QPushButton;
+
+/**
+ * Dialog edit class for @ref PMTriangle
+ */
+class PMTriangleEdit : public PMGraphicalObjectEdit
+{
+ Q_OBJECT
+ typedef PMGraphicalObjectEdit Base;
+public:
+ /**
+ * Creates a PMTriangleEdit with parent and name
+ */
+ PMTriangleEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+private slots:
+ void slotSmoothChecked( bool on );
+ void slotUVVectorsChecked( bool on );
+ void slotInvertNormals( );
+
+private:
+ PMTriangle* m_pDisplayedObject;
+ PMVectorEdit* m_pPoint[3];
+ PMVectorEdit* m_pNormal[3];
+ QLabel* m_pNormalLabel[3];
+ QCheckBox* m_pSmooth;
+ QLabel* m_pUVVectorLabel[3];
+ PMVectorEdit* m_pUVVector[3];
+ QCheckBox* m_pUVEnabled;
+ QPushButton* m_pMirror;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmtruetypecache.cpp b/kpovmodeler/pmtruetypecache.cpp
new file mode 100644
index 00000000..9aa28d89
--- /dev/null
+++ b/kpovmodeler/pmtruetypecache.cpp
@@ -0,0 +1,395 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmtruetypecache.h"
+#include "pmdebug.h"
+
+//***********************************************************************
+// Part with freetype support
+//***********************************************************************
+
+#ifdef HAVE_FREETYPE
+#define PMFREETYPEDEBUG
+
+PMTrueTypeCache* PMTrueTypeCache::s_pInstance = 0;
+KStaticDeleter<PMTrueTypeCache> PMTrueTypeCache::s_staticDeleter;
+
+PMTrueTypeCache::PMTrueTypeCache( )
+ : m_cache( 10, 17, true )
+{
+ bool error = FT_Init_FreeType( &m_library );
+ if( error )
+ kdError( PMArea ) << "Failed to initialize the freetype library\n";
+
+#ifdef PMFREETYPEDEBUG
+ else
+ kdDebug( PMArea ) << "Freetype 2 initialized\n";
+#endif
+
+ m_cache.setAutoDelete( true );
+}
+
+PMTrueTypeCache::~PMTrueTypeCache( )
+{
+ m_cache.clear( );
+ if( m_library )
+ FT_Done_FreeType( m_library );
+}
+
+PMTrueTypeFont* PMTrueTypeCache::lookUp( const QString& file )
+{
+ if( !m_library )
+ return 0;
+ if( file.isEmpty( ) )
+ return 0;
+
+ PMTrueTypeFont* f = m_cache.find( file );
+ if( !f )
+ {
+ FT_Face face;
+ FT_New_Face( m_library, file.latin1( ), 0, &face );
+ f = new PMTrueTypeFont( m_library, face );
+
+#ifdef PMFREETYPEDEBUG
+ if( face )
+ kdDebug( PMArea ) << "Successfully opened font " << file << endl;
+
+ if( f->isValid( ) )
+ m_cache.insert( file, f, 1 );
+ else
+ m_cache.insert( file, f, 0 );
+#endif
+ }
+
+ if( f->isValid( ) )
+ return f;
+
+ return 0;
+}
+
+PMTrueTypeFont* PMTrueTypeCache::font( const QString& file )
+{
+ if( !s_pInstance )
+ s_staticDeleter.setObject( s_pInstance, new PMTrueTypeCache( ) );
+
+ return s_pInstance->lookUp( file );
+}
+
+PMTrueTypeFont::PMTrueTypeFont( FT_Library lib, FT_Face face )
+ : m_cache( 100, 127 )
+{
+ m_library = lib;
+ m_face = face;
+ m_valid = false;
+ m_validChecked = false;
+ m_useKerning = false;
+ if( m_face )
+ {
+ m_useKerning = FT_HAS_KERNING( m_face );
+ // find the correct encoding
+ int i;
+ bool found = false;
+ for( i = 0; ( i < m_face->num_charmaps ) && !found; i++ )
+ if( m_face->charmaps[i]->platform_id == 3 ) // microsoft encodings
+ FT_Set_Charmap( m_face, m_face->charmaps[i] );
+ for( i = 0; ( i < m_face->num_charmaps ) && !found; i++ )
+ if( m_face->charmaps[i]->platform_id == 1 ) // mac encodings
+ FT_Set_Charmap( m_face, m_face->charmaps[i] );
+ }
+
+ m_cache.setAutoDelete( true );
+}
+
+PMTrueTypeFont::~PMTrueTypeFont( )
+{
+ if( m_face )
+ FT_Done_Face( m_face );
+ m_cache.clear( );
+}
+
+bool PMTrueTypeFont::isValid( )
+{
+ if( !m_validChecked )
+ {
+ if( !m_face )
+ m_valid = false;
+ else
+ m_valid = m_face->face_flags & FT_FACE_FLAG_SCALABLE;
+
+#ifdef PMFREETYPEDEBUG
+ if( m_valid )
+ kdDebug( PMArea ) << "Font: " << m_face->family_name
+ << " style " << m_face->style_name
+ << " units_per_EM " << m_face->units_per_EM
+ << " height " << m_face->height << endl;
+#endif
+
+ m_validChecked = true;
+ }
+
+ return m_valid;
+}
+
+PMTrueTypeOutline* PMTrueTypeFont::outline( QChar c )
+{
+ PMTrueTypeOutline* ol = 0;
+
+ if( isValid( ) )
+ {
+ QString str( c );
+ ol = m_cache.find( str );
+ if( !ol )
+ {
+ FT_UInt glyphIndex = findGlyphIndex( c );
+
+ bool error = !glyphIndex;
+ FT_Glyph glyph = 0;
+
+ if( !error )
+ error = FT_Load_Glyph( m_face, glyphIndex,
+ FT_LOAD_NO_BITMAP | FT_LOAD_NO_SCALE );
+ if( !error )
+ error = FT_Get_Glyph( m_face->glyph, &glyph );
+
+#ifdef PMFREETYPEDEBUG
+ if( error )
+ kdDebug( PMArea ) << "Failed to load glyph for " << c.latin1( ) << "\n";
+ else
+ {
+ FT_Glyph_Metrics* m = &( m_face->glyph->metrics );
+ kdDebug( PMArea ) << "Glyph w: " << m->width << " h: " << m->height
+ << " hbx: " << m->horiBearingX << " hby: " << m->horiBearingY
+ << " ha: " << m->horiAdvance << endl;
+ }
+#endif
+
+ if( !error && glyph && ( glyph->format == ft_glyph_format_outline ) )
+ {
+ FT_OutlineGlyph outlineGlyph = ( FT_OutlineGlyph ) glyph;
+ ol = new PMTrueTypeOutline( outlineGlyph, m_face );
+ }
+
+ if( glyph )
+ FT_Done_Glyph( glyph );
+ if( ol )
+ m_cache.insert( str, ol );
+ }
+ }
+
+ return ol;
+}
+
+double PMTrueTypeFont::kerning( QChar c1, QChar c2 )
+{
+ double k = 0.0;
+ if( m_useKerning && !c1.isNull( ) && !c2.isNull( ) )
+ {
+ FT_UInt gi1 = findGlyphIndex( c1 );
+ FT_UInt gi2 = findGlyphIndex( c2 );
+ if( gi1 && gi2 )
+ {
+ FT_Vector delta;
+ FT_Get_Kerning( m_face, gi1, gi2, ft_kerning_unscaled, &delta );
+ k = ( double ) delta.x / ( double ) m_face->units_per_EM;
+ }
+ }
+
+ return k;
+}
+
+FT_UInt PMTrueTypeFont::findGlyphIndex( QChar c )
+{
+ FT_UInt glyphIndex = 0;
+
+ if( m_face )
+ {
+ // glyphIndex = FT_Get_Char_Index( m_face, c.unicode( ) );
+ // if( !glyphIndex )
+ char ch = c.latin1( );
+ if( !ch )
+ ch = '?';
+ glyphIndex = FT_Get_Char_Index( m_face, ch );
+ }
+ return glyphIndex;
+}
+
+PMTrueTypeOutline::PMTrueTypeOutline( FT_OutlineGlyph glyph, FT_Face face )
+{
+ int n = 0, p = 0, si;
+ FT_Outline* ol = &( glyph->outline );
+
+ PMVector v[4];
+ bool onPoint[4] = { false, false, false, false };
+ bool cubic[4] = { false, false, false, false };
+
+ double dfh = ( double ) face->units_per_EM;
+ double horiBearing = ( double ) face->glyph->metrics.horiBearingX / dfh;
+
+ m_segments = 0;
+ m_contours = ol->n_contours;
+ m_advance = ( double ) face->glyph->metrics.horiAdvance / dfh;
+
+#ifdef PMFREETYPEDEBUG
+
+ /**
+ kdDebug( PMArea ) << "New outline:\n";
+ int dn, dp = 0;
+ for( dn = 0; dn < m_contours; dn++ )
+ {
+ kdDebug( PMArea ) << " Contour " << dn << ":\n";
+ for( ; dp <= ol->contours[dn]; dp++ )
+ {
+ kdDebug( PMArea ) << " <" << ol->points[dp].x << ", "
+ << ol->points[dp].y << ">, "
+ << ( ( ol->tags[dp] & 1 ) == 1 ) << " "
+ << ( ( ol->tags[dp] & 2 ) == 2 ) << endl;
+ }
+ }
+ */
+
+#endif
+
+ for( n = 0; n < m_contours; n++ )
+ {
+ PMSegmentList os;
+ PMSplineSegment s;
+ bool segmentCreated = false;
+ bool quadricSpecialCase = false;
+ bool contourEnd = false;
+ int firstPoint = p;
+
+ si = 0;
+
+ for( ; !contourEnd; p++, si++ )
+ {
+ segmentCreated = false;
+ quadricSpecialCase = false;
+
+ // last point = first point
+ if( p > ol->contours[n] )
+ {
+ p = firstPoint;
+ contourEnd = true;
+ }
+
+ // scale the point
+ v[si] = PMVector( ( double ) ol->points[p].x / dfh - horiBearing,
+ ( double ) ol->points[p].y / dfh );
+ // point type
+ onPoint[si] = ( ( ol->tags[p] & 1 ) == 1 );
+ cubic[si] = ( ( ol->tags[p] & 2 ) == 2 );
+
+ if( onPoint[si] )
+ {
+ switch( si )
+ {
+ case 0:
+ break;
+ case 1:
+ // line
+ s.calculateLinear( v[0], v[1] );
+ segmentCreated = true;
+ break;
+ case 2:
+ // quadric bezier
+ s.calculateQuadricBezier( v[0], v[1], v[2] );
+ segmentCreated = true;
+ break;
+ case 3:
+ // cubic bezier
+ s.calculateBezier( v[0], v[1], v[2], v[3] );
+ segmentCreated = true;
+ break;
+ default:
+ kdError( PMArea ) << "Glyph outline seems incorrect. No on point.\n";
+ si = 0;
+ break;
+ }
+ }
+ else if( ( si == 2 ) && ( !cubic[si] ) )
+ {
+ // two quadric off points
+ // add an on point between them
+ v[3] = v[2];
+ onPoint[3] = onPoint[2];
+ cubic[3] = cubic[2];
+ v[2] = ( v[1] + v[3] ) / 2.0;
+ onPoint[2] = true;
+
+ s.calculateQuadricBezier( v[0], v[1], v[2] );
+ segmentCreated = true;
+ quadricSpecialCase = true;
+ }
+
+ if( segmentCreated )
+ {
+ os.append( s );
+ v[0] = v[si];
+ onPoint[0] = true;
+ si = 0;
+
+ if( quadricSpecialCase )
+ {
+ v[1] = v[3];
+ onPoint[1] = onPoint[3];
+ cubic[1] = onPoint[3];
+ si++;
+ }
+ }
+ }
+
+ m_outline.append( os );
+ m_segments += os.count( );
+ p = ol->contours[n] + 1;
+ }
+}
+
+#else //!HAVE_FREETYPE
+
+//***********************************************************************
+// Part without freetype support
+//***********************************************************************
+
+PMTrueTypeCache::PMTrueTypeCache( )
+{
+}
+
+PMTrueTypeFont* PMTrueTypeCache::font( const QString& )
+{
+ return 0;
+}
+
+PMTrueTypeFont::PMTrueTypeFont( )
+{
+}
+
+bool PMTrueTypeFont::isValid( )
+{
+ return false;
+}
+
+PMTrueTypeOutline* PMTrueTypeFont::outline( QChar )
+{
+ return 0;
+}
+
+double PMTrueTypeFont::kerning( QChar, QChar )
+{
+ return 0;
+}
+
+#endif //HAVE_FREETYPE
diff --git a/kpovmodeler/pmtruetypecache.h b/kpovmodeler/pmtruetypecache.h
new file mode 100644
index 00000000..b305cb1c
--- /dev/null
+++ b/kpovmodeler/pmtruetypecache.h
@@ -0,0 +1,194 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMTRUETYPECACHE_H
+#define PMTRUETYPECACHE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmsplinesegment.h"
+
+#include <qcache.h>
+#include <kstaticdeleter.h>
+
+#ifdef HAVE_FREETYPE
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+#include FT_OUTLINE_H
+#endif
+
+class PMTrueTypeFont;
+
+/**
+ * Cache for truetype fonts
+ */
+class PMTrueTypeCache
+{
+public:
+ /**
+ * Returns a pointer to the font with file name "file" or 0, if the
+ * font does not exist or is no truetype font
+ *
+ * Returns 0 if freetype is not available.
+ */
+ static PMTrueTypeFont* font( const QString& file );
+
+#ifdef HAVE_FREETYPE
+
+ /**
+ * Destructor
+ */
+ ~PMTrueTypeCache( );
+
+private:
+ static PMTrueTypeCache* s_pInstance;
+ static KStaticDeleter<PMTrueTypeCache> s_staticDeleter;
+
+ /**
+ * Lookup function
+ */
+ PMTrueTypeFont* lookUp( const QString& file );
+
+ QCache<PMTrueTypeFont> m_cache;
+ FT_Library m_library;
+
+#endif //HAVE_FREETYPE
+
+private:
+ /**
+ * Standard constructor
+ */
+ PMTrueTypeCache( );
+};
+
+/**
+ * Class that represents a truetype character outline
+ */
+class PMTrueTypeOutline
+{
+public:
+#ifdef HAVE_FREETYPE
+ /**
+ * Constructor that generates the outline for the glyph.
+ * The outline is scaled to match the font height.
+ */
+ PMTrueTypeOutline( FT_OutlineGlyph glyph, FT_Face face );
+#else
+ /**
+ * Standard constructor.
+ *
+ * Don't use this constructor. It is only added as dummy if freetype
+ * is not installed.
+ */
+ PMTrueTypeOutline( )
+ {
+ m_contours = 0;
+ m_segments = 0;
+ m_advance = 0;
+ }
+#endif
+ /**
+ * Returns the outline
+ */
+ const PMSegmentListList& outline( ) const { return m_outline; }
+ /**
+ * Returns the number of contours
+ */
+ int contours( ) const { return m_contours; }
+ /**
+ * Returns the sum of the number of segments for all contours
+ */
+ int segments( ) const { return m_segments; }
+ /**
+ * Returns the offset for the next character
+ */
+ double advance( ) const { return m_advance; }
+
+ PMSegmentListList m_outline;
+ int m_contours;
+ int m_segments;
+ double m_advance;
+};
+
+/**
+ * Class that represents a truetype font.
+ *
+ * This class caches the glyph outlines.
+ */
+class PMTrueTypeFont
+{
+public:
+ /**
+ * Returns the outline for the character
+ *
+ * Returns 0 if there is no glyph for the character or the font is
+ * not a valid, scalable true type font.
+ */
+ PMTrueTypeOutline* outline( QChar c );
+ /**
+ * Returns true if the font is a valid, scalable true type font
+ */
+ bool isValid( );
+ /**
+ * Returns the kerning offset for the two characters
+ */
+ double kerning( QChar c1, QChar c2 );
+
+#ifdef HAVE_FREETYPE
+
+public:
+ /**
+ * Creates a true type font
+ */
+ PMTrueTypeFont( FT_Library lib, FT_Face face );
+ /**
+ * Deletes the true type font
+ */
+ ~PMTrueTypeFont( );
+
+private:
+ FT_UInt findGlyphIndex( QChar c );
+
+ FT_Library m_library;
+ FT_Face m_face;
+
+ bool m_valid;
+ bool m_validChecked;
+ bool m_useKerning;
+
+ QCache<PMTrueTypeOutline> m_cache;
+
+#else //!HAVE_FREETYPE
+
+public:
+ /**
+ * Standard constructor.
+ *
+ * Don't use this constructor. It is only added as dummy if freetype
+ * is not installed.
+ */
+ PMTrueTypeFont( );
+
+#endif //HAVE_FREETYPE
+
+};
+
+#endif
diff --git a/kpovmodeler/pmunknownview.cpp b/kpovmodeler/pmunknownview.cpp
new file mode 100644
index 00000000..b6067c02
--- /dev/null
+++ b/kpovmodeler/pmunknownview.cpp
@@ -0,0 +1,37 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmunknownview.h"
+#include <klocale.h>
+#include <qlayout.h>
+
+PMUnknownView::PMUnknownView( const QString& viewType,
+ QWidget* parent, const char* name )
+ : PMViewBase( parent, name )
+{
+ QHBoxLayout* hl = new QHBoxLayout( this );
+ QLabel* l;
+ l = new QLabel( i18n( "Unknown view type \"%1\"" ).arg( viewType ), this );
+ l->setAlignment( Qt::AlignCenter );
+ hl->addWidget( l );
+ m_viewType = viewType;
+}
+
+QString PMUnknownView::description( ) const
+{
+ return i18n( "Unknown" );
+}
diff --git a/kpovmodeler/pmunknownview.h b/kpovmodeler/pmunknownview.h
new file mode 100644
index 00000000..b8921dd6
--- /dev/null
+++ b/kpovmodeler/pmunknownview.h
@@ -0,0 +1,47 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMUNKNOWNVIEW_H
+#define PMUNKNOWNVIEW_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qlabel.h>
+#include "pmviewbase.h"
+
+/**
+ * Helper view for unknown view types
+ */
+class PMUnknownView : public PMViewBase
+{
+public:
+ /**
+ * Default constructor
+ */
+ PMUnknownView( const QString& viewType, QWidget* parent,
+ const char* name = 0 );
+ /** */
+ virtual QString viewType( ) const { return m_viewType; }
+ /** */
+ virtual QString description( ) const;
+private:
+ QString m_viewType;
+};
+
+#endif
diff --git a/kpovmodeler/pmvalue.h b/kpovmodeler/pmvalue.h
new file mode 100644
index 00000000..3d2ecb02
--- /dev/null
+++ b/kpovmodeler/pmvalue.h
@@ -0,0 +1,102 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMVALUE_H
+#define PMVALUE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmvector.h"
+
+enum PMValueType { PMVFloat, PMVVector, PMVColor };
+
+/**
+ * Helper class for parsing numeric expressions because wo don't know
+ * at begin of an expression, which type it is.
+ *
+ * Colors are stored as 5D vectors.
+ */
+
+class PMValue
+{
+public:
+ /**
+ * Creates a PMValue with type PMVFloat and value 0.0
+ */
+ PMValue( ) : m_v( 0 ) { m_d = 0.0; m_type = PMVFloat; }
+ /**
+ * Copy constructor
+ */
+ PMValue( const PMValue& v )
+ {
+ m_type = v.m_type;
+ m_d = v.m_d;
+ m_v = v.m_v;
+ }
+ /**
+ * Returns the type of the value.
+ * Values can be PMVFloat, PMVVector, PMVColor
+ */
+ PMValueType type( ) const { return m_type; }
+
+ /**
+ * Sets the float value and sets the type to PMVFloat
+ */
+ void setFloat( const double d ) { m_d = d; m_type = PMVFloat; }
+ /**
+ * Sets the vector value and sets the type to PMVVector
+ */
+ void setVector( const PMVector& v ) { m_v = v; m_type = PMVVector; }
+ /**
+ * Sets the color value and sets the type to PMVColor
+ */
+ void setColor( const PMVector& v ) { m_v = v; m_type = PMVColor; }
+
+ /**
+ * Returns the float value
+ */
+ double floatValue( ) const { return m_d; }
+ /**
+ * Returns the vector value
+ */
+ PMVector vector( ) const { return m_v; }
+ /**
+ * Returns the color value
+ */
+ PMVector color( ) const { return m_v; }
+ /**
+ * Assigns v to the value
+ */
+ PMValue& operator= ( const PMValue& v )
+ {
+ m_type = v.m_type;
+ m_d = v.m_d;
+ m_v = v.m_v;
+ return *this;
+ }
+
+private:
+ PMValueType m_type;
+ double m_d;
+ PMVector m_v;
+};
+
+#endif
diff --git a/kpovmodeler/pmvariant.cpp b/kpovmodeler/pmvariant.cpp
new file mode 100644
index 00000000..d6b5384c
--- /dev/null
+++ b/kpovmodeler/pmvariant.cpp
@@ -0,0 +1,920 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmvariant.h"
+
+#include <qstring.h>
+#include "pmcolor.h"
+#include "pmvector.h"
+#include "pmdebug.h"
+
+inline const char* dcopTypeName( const PMVariant& ) { return "PMVariant"; }
+
+PMVariant::PMVariant( )
+{
+ m_dataType = PMVariant::None;
+ m_pData = 0;
+}
+
+PMVariant::PMVariant( int data )
+{
+ m_dataType = PMVariant::Integer;
+ m_pData = new int( data );
+}
+
+PMVariant::PMVariant( unsigned int data )
+{
+ m_dataType = PMVariant::Unsigned;
+ m_pData = new unsigned( data );
+}
+
+PMVariant::PMVariant( double data )
+{
+ m_dataType = PMVariant::Double;
+ m_pData = new double( data );
+}
+
+
+PMVariant::PMVariant( bool data )
+{
+ m_dataType = PMVariant::Bool;
+ m_pData = new bool( data );
+}
+
+PMVariant::PMVariant( PMThreeState data )
+{
+ m_dataType = PMVariant::ThreeState;
+ m_pData = new PMThreeState( data );
+}
+
+
+PMVariant::PMVariant( const QString& data )
+{
+ m_dataType = PMVariant::String;
+ m_pData = new QString( data );
+}
+
+PMVariant::PMVariant( const PMVector& data )
+{
+ m_dataType = PMVariant::Vector;
+ m_pData = new PMVector( data );
+}
+
+PMVariant::PMVariant( const PMColor& data )
+{
+ m_dataType = PMVariant::Color;
+ m_pData = new PMColor( data );
+}
+
+PMVariant::PMVariant( PMObject* obj )
+{
+ m_dataType = PMVariant::ObjectPointer;
+ m_pData = ( void* ) obj;
+}
+
+PMVariant::PMVariant( const PMVariant& v )
+{
+ m_pData = 0;
+ m_dataType = PMVariant::None;
+
+ switch( v.m_dataType )
+ {
+ case PMVariant::Integer:
+ setInt( *( ( int* ) v.m_pData ) );
+ break;
+ case PMVariant::Unsigned:
+ setUnsigned( *( ( unsigned* ) v.m_pData ) );
+ break;
+ case PMVariant::Double:
+ setDouble( *( ( double* ) v.m_pData ) );
+ break;
+ case PMVariant::Bool:
+ setBool( *( ( bool* ) v.m_pData ) );
+ break;
+ case PMVariant::ThreeState:
+ setThreeState( *( ( PMThreeState* ) v.m_pData ) );
+ break;
+ case PMVariant::String:
+ setString( *( ( QString* ) v.m_pData ) );
+ break;
+ case PMVariant::Vector:
+ setVector( *( ( PMVector* ) v.m_pData ) );
+ break;
+ case PMVariant::Color:
+ setColor( *( ( PMColor* ) v.m_pData ) );
+ break;
+ case PMVariant::ObjectPointer:
+ setObject( ( PMObject* ) v.m_pData );
+ break;
+ case PMVariant::None:
+ break;
+ }
+}
+
+PMVariant& PMVariant::operator= ( const PMVariant& v )
+{
+ switch( v.m_dataType )
+ {
+ case PMVariant::Integer:
+ setInt( *( ( int* ) v.m_pData ) );
+ break;
+ case PMVariant::Unsigned:
+ setUnsigned( *( ( unsigned* ) v.m_pData ) );
+ break;
+ case PMVariant::Double:
+ setDouble( *( ( double* ) v.m_pData ) );
+ break;
+ case PMVariant::Bool:
+ setBool( *( ( bool* ) v.m_pData ) );
+ break;
+ case PMVariant::ThreeState:
+ setThreeState( *( ( PMThreeState* ) v.m_pData ) );
+ break;
+ case PMVariant::String:
+ setString( *( ( QString* ) v.m_pData ) );
+ break;
+ case PMVariant::Vector:
+ setVector( *( ( PMVector* ) v.m_pData ) );
+ break;
+ case PMVariant::Color:
+ setColor( *( ( PMColor* ) v.m_pData ) );
+ break;
+ case PMVariant::ObjectPointer:
+ setObject( ( PMObject* ) v.m_pData );
+ break;
+ case PMVariant::None:
+ break;
+ }
+
+ return *this;
+}
+
+PMVariant::~PMVariant( )
+{
+ clear( );
+}
+
+void PMVariant::clear( )
+{
+ switch( m_dataType )
+ {
+ case PMVariant::Integer:
+ delete( ( int* ) m_pData );
+ break;
+ case PMVariant::Unsigned:
+ delete( ( unsigned* ) m_pData );
+ break;
+ case PMVariant::Double:
+ delete( ( double* ) m_pData );
+ break;
+ case PMVariant::Bool:
+ delete( ( bool* ) m_pData );
+ break;
+ case PMVariant::ThreeState:
+ delete( ( PMThreeState* ) m_pData );
+ break;
+ case PMVariant::String:
+ delete( ( QString* ) m_pData );
+ break;
+ case PMVariant::Vector:
+ delete( ( PMVector* ) m_pData );
+ break;
+ case PMVariant::Color:
+ delete( ( PMColor* ) m_pData );
+ break;
+ case PMVariant::ObjectPointer:
+ // delete nothing
+ break;
+ case PMVariant::None:
+ break;
+ }
+
+ m_dataType = PMVariant::None;
+ m_pData = 0;
+}
+
+void PMVariant::setInt( const int data )
+{
+ if( m_dataType != PMVariant::Integer )
+ {
+ clear( );
+ m_pData = new int( data );
+ m_dataType = PMVariant::Integer;
+ }
+ else
+ *( ( int* ) m_pData ) = data;
+}
+
+void PMVariant::setUnsigned( const unsigned int data )
+{
+ if( m_dataType != PMVariant::Unsigned )
+ {
+ clear( );
+ m_pData = new unsigned( data );
+ m_dataType = PMVariant::Unsigned;
+ }
+ else
+ *( ( unsigned* ) m_pData ) = data;
+}
+
+void PMVariant::setDouble( const double data )
+{
+ if( m_dataType != PMVariant::Double )
+ {
+ clear( );
+ m_pData = new double( data );
+ m_dataType = PMVariant::Double;
+ }
+ else
+ *( ( double* ) m_pData ) = data;
+}
+
+void PMVariant::setBool( const bool data )
+{
+ if( m_dataType != PMVariant::Bool )
+ {
+ clear( );
+ m_pData = new bool( data );
+ m_dataType = PMVariant::Bool;
+ }
+ else
+ *( ( bool* ) m_pData ) = data;
+}
+
+void PMVariant::setThreeState( const PMThreeState data )
+{
+ if( m_dataType != PMVariant::ThreeState )
+ {
+ clear( );
+ m_pData = new PMThreeState( data );
+ m_dataType = PMVariant::ThreeState;
+ }
+ else
+ *( ( PMThreeState* ) m_pData ) = data;
+}
+
+void PMVariant::setString( const QString& data )
+{
+ if( m_dataType != PMVariant::String )
+ {
+ clear( );
+ m_pData = new QString( data );
+ m_dataType = PMVariant::String;
+ }
+ else
+ *( ( QString* ) m_pData ) = data;
+}
+
+void PMVariant::setVector( const PMVector& data )
+{
+ if( m_dataType != PMVariant::Vector )
+ {
+ clear( );
+ m_pData = new PMVector( data );
+ m_dataType = PMVariant::Vector;
+ }
+ else
+ *( ( PMVector* ) m_pData ) = data;
+}
+
+void PMVariant::setColor( const PMColor& data )
+{
+ if( m_dataType != PMVariant::Color )
+ {
+ clear( );
+ m_pData = new PMColor( data );
+ m_dataType = PMVariant::Color;
+ }
+ else
+ *( ( PMColor* ) m_pData ) = data;
+}
+
+void PMVariant::setObject( PMObject* obj )
+{
+ if( m_dataType != PMVariant::ObjectPointer )
+ {
+ clear( );
+ m_pData = obj;
+ m_dataType = PMVariant::ObjectPointer;
+ }
+ else
+ m_pData = obj;
+}
+
+int PMVariant::intData( ) const
+{
+ if( m_dataType == PMVariant::Integer )
+ return *( ( int* ) m_pData );
+ kdError( PMArea ) << "Wrong type in PMVariant get function\n";
+ return 0;
+}
+
+int PMVariant::unsignedData( ) const
+{
+ if( m_dataType == PMVariant::Unsigned )
+ return *( ( unsigned* ) m_pData );
+ kdError( PMArea ) << "Wrong type in PMVariant get function\n";
+ return 0;
+}
+
+double PMVariant::doubleData( ) const
+{
+ if( m_dataType == PMVariant::Double )
+ return *( ( double* ) m_pData );
+ kdError( PMArea ) << "Wrong type in PMVariant get function\n";
+ return 0;
+}
+
+bool PMVariant::boolData( ) const
+{
+ if( m_dataType == PMVariant::Bool )
+ return *( ( bool* ) m_pData );
+ kdError( PMArea ) << "Wrong type in PMVariant get function\n";
+ return false;
+}
+
+PMThreeState PMVariant::threeStateData( ) const
+{
+ if( m_dataType == PMVariant::ThreeState )
+ return *( ( PMThreeState* ) m_pData );
+ kdError( PMArea ) << "Wrong type in PMVariant get function\n";
+ return PMUnspecified;
+}
+
+QString PMVariant::stringData( ) const
+{
+ if( m_dataType == PMVariant::String )
+ return *( ( QString* ) m_pData );
+ kdError( PMArea ) << "Wrong type in PMVariant get function\n";
+ return QString::null;
+}
+
+PMVector PMVariant::vectorData( ) const
+{
+ if( m_dataType == PMVariant::Vector )
+ return *( ( PMVector* ) m_pData );
+ kdError( PMArea ) << "Wrong type in PMVariant get function\n";
+ return PMVector( );
+}
+
+PMColor PMVariant::colorData( ) const
+{
+ if( m_dataType == PMVariant::Color )
+ return *( ( PMColor* ) m_pData );
+ kdError( PMArea ) << "Wrong type in PMVariant get function\n";
+ return PMColor( );
+}
+
+PMObject* PMVariant::objectData( ) const
+{
+ if( m_dataType == PMVariant::ObjectPointer )
+ return ( PMObject* ) m_pData;
+ kdError( PMArea ) << "Wrong type in PMVariant get function\n";
+ return 0;
+}
+
+bool PMVariant::convertTo( PMVariant::PMVariantDataType t )
+{
+ bool success = true;
+
+ switch( m_dataType )
+ {
+ case PMVariant::Integer:
+ {
+ int data = *( ( int* ) m_pData );
+
+ switch( t )
+ {
+ case PMVariant::Integer:
+ break;
+ case PMVariant::Unsigned:
+ setUnsigned( ( unsigned ) data );
+ break;
+ case PMVariant::Double:
+ setDouble( ( double ) data );
+ break;
+ case PMVariant::Bool:
+ setBool( ( bool ) data );
+ break;
+ case PMVariant::ThreeState:
+ success = false;
+ break;
+ case PMVariant::String:
+ {
+ QString tmp;
+ tmp.setNum( data );
+ setString( tmp );
+ break;
+ }
+ case PMVariant::Vector:
+ success = false;
+ break;
+ case PMVariant::Color:
+ success = false;
+ break;
+ case PMVariant::ObjectPointer:
+ success = false;
+ break;
+ case PMVariant::None:
+ success = false;
+ break;
+ }
+ break;
+ }
+
+ case PMVariant::Unsigned:
+ {
+ unsigned data = *( ( unsigned* ) m_pData );
+
+ switch( t )
+ {
+ case PMVariant::Integer:
+ setUnsigned( ( int ) data );
+ break;
+ case PMVariant::Unsigned:
+ break;
+ case PMVariant::Double:
+ setDouble( ( double ) data );
+ break;
+ case PMVariant::Bool:
+ setBool( ( bool ) data );
+ break;
+ case PMVariant::ThreeState:
+ success = false;
+ break;
+ case PMVariant::String:
+ {
+ QString tmp;
+ tmp.setNum( data );
+ setString( tmp );
+ break;
+ }
+ case PMVariant::Vector:
+ success = false;
+ break;
+ case PMVariant::Color:
+ success = false;
+ break;
+ case PMVariant::ObjectPointer:
+ success = false;
+ break;
+ case PMVariant::None:
+ success = false;
+ break;
+ }
+ break;
+ }
+
+ case PMVariant::Double:
+ {
+ double data = *( ( double* ) m_pData );
+
+ switch( t )
+ {
+ case PMVariant::Integer:
+ setInt( ( int ) data );
+ break;
+ case PMVariant::Unsigned:
+ setUnsigned( ( unsigned ) data );
+ break;
+ case PMVariant::Double:
+ break;
+ case PMVariant::Bool:
+ setBool( ( bool ) data );
+ break;
+ case PMVariant::ThreeState:
+ success = false;
+ break;
+ case PMVariant::String:
+ {
+ QString tmp;
+ tmp.setNum( data );
+ setString( tmp );
+ break;
+ }
+ case PMVariant::Vector:
+ success = false;
+ break;
+ case PMVariant::Color:
+ success = false;
+ break;
+ case PMVariant::ObjectPointer:
+ success = false;
+ break;
+ case PMVariant::None:
+ success = false;
+ break;
+ }
+ break;
+ }
+
+ case PMVariant::Bool:
+ {
+ bool data = *( ( bool* ) m_pData );
+
+ switch( t )
+ {
+ case PMVariant::Integer:
+ setInt( ( int ) data );
+ break;
+ case PMVariant::Unsigned:
+ setUnsigned( ( unsigned ) data );
+ break;
+ case PMVariant::Double:
+ setDouble( ( double ) data );
+ break;
+ case PMVariant::Bool:
+ break;
+ case PMVariant::ThreeState:
+ if( data )
+ setThreeState( PMTrue );
+ else
+ setThreeState( PMFalse );
+ break;
+ case PMVariant::String:
+ if( data )
+ setString( QString( "true" ) );
+ else
+ setString( QString( "false" ) );
+ break;
+ case PMVariant::Vector:
+ success = false;
+ break;
+ case PMVariant::Color:
+ success = false;
+ break;
+ case PMVariant::ObjectPointer:
+ success = false;
+ break;
+ case PMVariant::None:
+ success = false;
+ break;
+ }
+ break;
+ }
+
+ case PMVariant::ThreeState:
+ {
+ PMThreeState data = *( ( PMThreeState* ) m_pData );
+
+ switch( t )
+ {
+ case PMVariant::Integer:
+ success = false;
+ break;
+ case PMVariant::Unsigned:
+ success = false;
+ break;
+ case PMVariant::Double:
+ success = false;
+ break;
+ case PMVariant::Bool:
+ if( data == PMTrue )
+ setBool( true );
+ else if( data == PMFalse )
+ setBool( false );
+ else
+ success = false;
+ break;
+ case PMVariant::ThreeState:
+ break;
+ case PMVariant::String:
+ if( data == PMTrue )
+ setString( QString( "true" ) );
+ else if( data == PMFalse )
+ setString( QString( "false" ) );
+ else
+ setString( QString( "unspecified" ) );
+ break;
+ case PMVariant::Vector:
+ success = false;
+ break;
+ case PMVariant::Color:
+ success = false;
+ break;
+ case PMVariant::ObjectPointer:
+ success = false;
+ break;
+ case PMVariant::None:
+ success = false;
+ break;
+ }
+ break;
+ }
+
+ case PMVariant::String:
+ {
+ QString data = *( ( QString* ) m_pData );
+
+ switch( t )
+ {
+ case PMVariant::Integer:
+ {
+ int i = data.toInt( &success );
+ if( success )
+ setInt( i );
+ break;
+ }
+ case PMVariant::Unsigned:
+ {
+ unsigned u = data.toUInt( &success );
+ if( success )
+ setUnsigned( u );
+ break;
+ }
+ case PMVariant::Double:
+ {
+ double d = data.toDouble( &success );
+ if( success )
+ setDouble( d );
+ break;
+ }
+ case PMVariant::Bool:
+ if( data == "true" || data == "on" || data == "yes" )
+ setBool( true );
+ else if( data == "false" || data == "off" || data == "no" )
+ setBool( false );
+ else
+ success = false;
+ break;
+ case PMVariant::ThreeState:
+ if( data == "true" || data == "on" || data == "yes" )
+ setThreeState( PMTrue );
+ else if( data == "false" || data == "off" || data == "no" )
+ setThreeState( PMFalse );
+ else if( data == "unspecified" )
+ setThreeState( PMUnspecified );
+ else
+ success = false;
+ break;
+ case PMVariant::String:
+ break;
+ case PMVariant::Vector:
+ success = false;
+ break;
+ case PMVariant::Color:
+ success = false;
+ break;
+ case PMVariant::ObjectPointer:
+ success = false;
+ break;
+ case PMVariant::None:
+ success = false;
+ break;
+ }
+ break;
+ }
+
+ case PMVariant::Vector:
+ {
+ switch( t )
+ {
+ case PMVariant::Vector:
+ break;
+ case PMVariant::Color:
+ {
+ PMVector v = *( ( PMVector* ) m_pData );
+ if( v.size( ) == 5 )
+ setColor( v );
+ else
+ success = false;
+ break;
+ }
+ default:
+ success = false;
+ break;
+ }
+ break;
+ }
+
+ case PMVariant::Color:
+ {
+ switch( t )
+ {
+ case PMVariant::Vector:
+ {
+ PMColor c = *( ( PMColor* ) m_pData );
+ PMVector v( 5 );
+ v[0] = c.red( );
+ v[1] = c.green( );
+ v[2] = c.blue( );
+ v[3] = c.filter( );
+ v[4] = c.transmit( );
+ setVector( v );
+ break;
+ }
+ case PMVariant::Color:
+ break;
+ default:
+ success = false;
+ break;
+ }
+ break;
+ }
+
+ case PMVariant::ObjectPointer:
+ success = ( t == PMVariant::ObjectPointer );
+ break;
+
+ case PMVariant::None:
+ success = ( t == PMVariant::None );
+ break;
+ }
+
+ return success;
+}
+
+QString PMVariant::asString( ) const
+{
+ QString tmp;
+
+ switch( m_dataType )
+ {
+ case PMVariant::Integer:
+ {
+ int data = *( ( int* ) m_pData );
+
+ tmp.setNum( data );
+ break;
+ }
+ case PMVariant::Unsigned:
+ {
+ unsigned data = *( ( unsigned* ) m_pData );
+
+ tmp.setNum( data );
+ break;
+ }
+ case PMVariant::Double:
+ {
+ double data = *( ( double* ) m_pData );
+
+ tmp.setNum( data );
+ break;
+ }
+ case PMVariant::Bool:
+ {
+ bool data = *( ( bool* ) m_pData );
+
+ if( data )
+ tmp = "true";
+ else
+ tmp = "false";
+ break;
+ }
+ case PMVariant::ThreeState:
+ {
+ PMThreeState data = *( ( PMThreeState* ) m_pData );
+
+ if( data == PMTrue )
+ tmp = "true";
+ else if( data == PMFalse )
+ tmp = "false";
+ else
+ tmp = "unspecified";
+ break;
+ }
+ case PMVariant::String:
+ {
+ tmp = *( ( QString* ) m_pData );
+ break;
+ }
+ case PMVariant::Vector:
+ {
+ PMVector v = *( ( PMVector* ) m_pData );
+ tmp = v.serializeXML( );
+ break;
+ }
+
+ case PMVariant::Color:
+ {
+ PMColor c = *( ( PMColor* ) m_pData );
+ tmp = c.serializeXML( );
+ break;
+ }
+
+ case PMVariant::ObjectPointer:
+ tmp = "<object_pointer>";
+ break;
+
+ case PMVariant::None:
+ tmp = "<none>";
+ break;
+
+ default:
+ tmp = "<unknown>";
+ break;
+ }
+
+ return tmp;
+}
+
+bool PMVariant::fromString( const PMVariant::PMVariantDataType t, const QString& value )
+{
+ bool success;
+
+ switch( t )
+ {
+ case PMVariant::Integer:
+ {
+ int i = value.toInt( &success );
+ if( success )
+ setInt( i );
+ break;
+ }
+ case PMVariant::Unsigned:
+ {
+ unsigned u = value.toUInt( &success );
+ if( success )
+ setUnsigned( u );
+ break;
+ }
+ case PMVariant::Double:
+ {
+ double d = value.toDouble( &success );
+ if( success )
+ setDouble( d );
+ break;
+ }
+ case PMVariant::Bool:
+ success = true;
+ if( value == "true" || value == "on" || value == "yes" )
+ setBool( true );
+ else if( value == "false" || value == "off" || value == "no" )
+ setBool( false );
+ else
+ success = false;
+ break;
+ case PMVariant::ThreeState:
+ success = true; // Assume success, set to false if we fail.
+ if( value == "true" || value == "on" || value == "yes" )
+ setThreeState( PMTrue );
+ else if( value == "false" || value == "off" || value == "no" )
+ setThreeState( PMFalse );
+ else if( value == "unspecified" )
+ setThreeState( PMUnspecified );
+ else
+ success = false;
+ break;
+ case PMVariant::String:
+ setString( value );
+ success = true;
+ break;
+ case PMVariant::Vector:
+ {
+ PMVector v;
+ v.loadXML( value );
+ setVector( v );
+ success = true;
+ break;
+ }
+ case PMVariant::Color:
+ {
+ PMColor c;
+ c.loadXML( value );
+ setColor( c );
+ success = true;
+ break;
+ }
+ default:
+ success = false;
+ }
+ return success;
+}
+
+QDataStream& operator<<( QDataStream& stream, const PMVariant& value )
+{
+ stream << (Q_INT8)value.dataType( );
+ stream << value.asString( );
+
+ return stream;
+}
+
+QDataStream& operator>>( QDataStream& stream, PMVariant& value )
+{
+ Q_INT8 type;
+ PMVariant::PMVariantDataType dataType;
+ QString str;
+
+ stream >> type;
+ dataType = (PMVariant::PMVariantDataType)type;
+
+ stream >> str;
+
+ value.fromString(dataType, str);
+
+ return stream;
+}
diff --git a/kpovmodeler/pmvariant.h b/kpovmodeler/pmvariant.h
new file mode 100644
index 00000000..01519a01
--- /dev/null
+++ b/kpovmodeler/pmvariant.h
@@ -0,0 +1,221 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMVARIANT_H
+#define PMVARIANT_H
+
+#include <qstring.h>
+#include "pmcolor.h"
+#include "pmvector.h"
+#include "pmthreestate.h"
+
+class PMObject;
+
+/**
+ * Variant class for KPovModeler.
+ *
+ * Can store and convert: int, unsigned int, double, bool,
+ * PMThreeState, QString, PMVector, PMColor, PMObject*.
+ *
+ * Enums are stored as QString.
+ *
+ * The variant can store one type at a time. You can try to convert
+ * the type with the convertTo* methods. These will return bool on success.
+ * If the variant could not be converted, the old type and value
+ * did not change.
+ */
+
+class PMVariant
+{
+public:
+ /**
+ * Type of stored data
+ */
+ enum PMVariantDataType { Integer, Unsigned, Double, Bool,
+ ThreeState, String, Vector, Color,
+ ObjectPointer, None };
+ /**
+ * Creates an empty variant object
+ */
+ PMVariant( );
+ /**
+ * Stores an integer
+ */
+ PMVariant( int data );
+ /**
+ * Stores an unsigned integer
+ */
+ PMVariant( unsigned int data );
+ /**
+ * Stores a double
+ */
+ PMVariant( double data );
+ /**
+ * Stores a boolean
+ */
+ PMVariant( bool data );
+ /**
+ * Stores a @ref PMThreeState
+ */
+ PMVariant( PMThreeState data );
+ /**
+ * Stores a string
+ */
+ PMVariant( const QString& data );
+ /**
+ * Stores a @ref PMVector
+ */
+ PMVariant( const PMVector& data );
+ /**
+ * Stores a @ref PMColor
+ */
+ PMVariant( const PMColor& data );
+ /**
+ * Stores a pointer to a PMObject
+ */
+ PMVariant( PMObject* obj );
+ /**
+ * Copy constructor
+ */
+ PMVariant( const PMVariant& v );
+ /**
+ * Deletes the variant
+ */
+ ~PMVariant( );
+
+ /**
+ * Assignment operator
+ */
+ PMVariant& operator= ( const PMVariant& v );
+
+ /**
+ * Returns true if no data is stored
+ */
+ bool isNull( ) const { return !m_pData; }
+
+ /**
+ * Sets the integer value
+ */
+ void setInt( int data );
+ /**
+ * Sets the unsigned value
+ */
+ void setUnsigned( unsigned int data );
+ /**
+ * Sets the double value
+ */
+ void setDouble( double data );
+ /**
+ * Sets the boolean value
+ */
+ void setBool( bool data );
+ /**
+ * Sets the PMThreeState value
+ */
+ void setThreeState( PMThreeState data );
+ /**
+ * Sets the string data
+ */
+ void setString( const QString& data );
+ /**
+ * Sets the vector data
+ */
+ void setVector( const PMVector& data );
+ /**
+ * Sets the color data
+ */
+ void setColor( const PMColor& data );
+ /**
+ * Sets the object pointer
+ */
+ void setObject( PMObject* o );
+
+ /**
+ * Returns the integer value. Data type has to be Integer!
+ */
+ int intData( ) const;
+ /**
+ * Returns the unsigned value. Data type has to be Unsigned!
+ */
+ int unsignedData( ) const;
+ /**
+ * Returns the double value. Data type has to be Double!
+ */
+ double doubleData( ) const;
+ /**
+ * Returns the boolean value. Data type has to be Bool!
+ */
+ bool boolData( ) const;
+ /**
+ * Returns the PMThreeState value. Data type has to be ThreeState!
+ */
+ PMThreeState threeStateData( ) const;
+ /**
+ * Returns the string data. Data type has to be String!
+ */
+ QString stringData( ) const;
+ /**
+ * Returns the vector data. Data type has to be Vector!
+ */
+ PMVector vectorData( ) const;
+ /**
+ * Returns the color data. Data type has to be Color!
+ */
+ PMColor colorData( ) const;
+ /**
+ * Returns the object pointer. Data type has to be ObjectPointer!
+ */
+ PMObject* objectData( ) const;
+
+ /**
+ * Converts the variant to an integer. Returns true if possible
+ */
+ bool convertTo( PMVariantDataType t );
+
+ /**
+ * Returns the type of the stored data
+ */
+ PMVariantDataType dataType( ) const { return m_dataType; }
+
+ /**
+ * Returns the value of the stored data in string format
+ */
+ QString asString( ) const;
+ /**
+ * Sets the value of the variant based on the string
+ */
+ bool fromString( const PMVariant::PMVariantDataType t, const QString& value );
+private:
+ void clear( );
+
+ /**
+ * a pointer to the stored data
+ */
+ void* m_pData;
+ /**
+ * Type of the data
+ */
+ PMVariantDataType m_dataType;
+};
+
+// Streaming operators for PMVariant
+QDataStream& operator<<( QDataStream& stream, const PMVariant& value );
+QDataStream& operator>>( QDataStream& stream, PMVariant& value );
+
+
+#endif
diff --git a/kpovmodeler/pmvector.cpp b/kpovmodeler/pmvector.cpp
new file mode 100644
index 00000000..035f0d2b
--- /dev/null
+++ b/kpovmodeler/pmvector.cpp
@@ -0,0 +1,593 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmvector.h"
+#include "pmmath.h"
+#include "pmmatrix.h"
+#include "pmdebug.h"
+
+#include <qtextstream.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+double PMVector::s_dummy = 0;
+
+double& PMVector::operator[] ( int index )
+{
+ if( ( index >= 0 ) && ( index < ( signed ) m_size ) )
+ return m_coord[index];
+ kdError( PMArea ) << "Bad index in PMVector operator []\n";
+ return s_dummy;
+}
+
+const double& PMVector::operator[] ( int index ) const
+{
+ if( ( index >= 0 ) && ( index < ( signed ) m_size ) )
+ return m_coord[index];
+ kdError( PMArea ) << "Bad index in PMVector operator []\n";
+ return s_dummy;
+}
+
+void PMVector::allocateMemory( unsigned int size )
+{
+ m_size = size;
+
+ if( m_size == 0 )
+ m_coord = 0;
+ else
+ m_coord = ( double* ) malloc( sizeof( double ) * m_size );
+}
+
+PMVector::PMVector( const PMVector& v )
+{
+ unsigned int i;
+ allocateMemory( v.m_size );
+
+ for( i = 0; i < m_size; i++ )
+ m_coord[i] = v.m_coord[i];
+}
+
+PMVector::PMVector( )
+{
+ unsigned int i;
+
+ allocateMemory( 3 );
+
+ for( i = 0; i < 3; i++ )
+ m_coord[i] = 0.0;
+}
+
+PMVector::PMVector( unsigned int s )
+{
+ unsigned int i;
+
+ allocateMemory( s );
+
+ for( i = 0; i < s; i++ )
+ m_coord[i] = 0.0;
+}
+
+PMVector::PMVector( const double x, const double y )
+{
+ allocateMemory( 2 );
+
+ m_coord[0] = x;
+ m_coord[1] = y;
+}
+
+PMVector::PMVector( const double x, const double y, const double z )
+{
+ allocateMemory( 3 );
+
+ m_coord[0] = x;
+ m_coord[1] = y;
+ m_coord[2] = z;
+}
+
+PMVector::PMVector( const double x, const double y, const double z,
+ const double t )
+{
+ allocateMemory( 4 );
+
+ m_coord[0] = x;
+ m_coord[1] = y;
+ m_coord[2] = z;
+ m_coord[3] = t;
+}
+
+PMVector::~PMVector( )
+{
+ if( m_coord )
+ free( m_coord );
+}
+
+
+void PMVector::resize( unsigned int s )
+{
+ unsigned int i;
+
+ if( s != m_size )
+ {
+ m_coord = ( double* ) realloc( m_coord, sizeof( double ) * s );
+
+ for( i = m_size; i < s; i++ )
+ m_coord[i] = 0.0;
+
+ if( m_coord )
+ m_size = s;
+ else
+ m_size = 0; // possibly out of memory
+ }
+}
+
+void PMVector::transform( const PMMatrix& m )
+{
+ (*this) = m * (*this);
+}
+
+PMVector& PMVector::operator= ( const PMVector& p )
+{
+ unsigned int i;
+
+ resize( p.m_size );
+ for( i = 0; i < m_size; i++ )
+ m_coord[i] = p[i];
+ return *this;
+}
+
+PMVector& PMVector::operator= ( const double d )
+{
+ unsigned int i;
+
+ for( i = 0; i < m_size; i++ )
+ m_coord[i] = d;
+ return *this;
+}
+
+PMVector& PMVector::operator*= ( const PMVector& p )
+{
+ unsigned int i;
+
+ if( m_size != p.m_size )
+ resize( p.m_size );
+
+ for( i = 0; i < m_size; i++ )
+ m_coord[i] *= p[i];
+
+ return *this;
+}
+
+PMVector& PMVector::operator/= ( const PMVector& p )
+{
+ unsigned int i;
+
+ if( m_size > p.m_size )
+ {
+ kdError( PMArea ) << "Vector p is too small in PMVector& PMVector::operator/= ( const PMVector& p )\n";
+ }
+ else
+ {
+ for( i = 0; i < m_size; i++ )
+ {
+ if( approxZero( p[i] ) )
+ kdError( PMArea ) << "Division by zero in PMVector::operator/= " << "\n";
+ else
+ m_coord[i] *= p[i];
+ }
+ }
+
+ return *this;
+}
+
+PMVector& PMVector::operator*= ( double d )
+{
+ unsigned int i;
+
+ for( i = 0; i < m_size; i++ )
+ m_coord[i] *= d;
+
+ return *this;
+}
+
+PMVector& PMVector::operator/= ( double d )
+{
+ if( approxZero( d ) )
+ {
+ kdError( PMArea ) << "Division by zero in PMVector::operator/= " << "\n";
+ }
+ else
+ {
+ unsigned int i;
+
+ for( i = 0; i < m_size; i++ )
+ m_coord[i] /= d;
+ }
+
+ return *this;
+}
+
+PMVector& PMVector::operator+= ( double d )
+{
+ unsigned int i;
+
+ for( i = 0; i < m_size; i++ )
+ m_coord[i] += d;
+
+ return *this;
+}
+
+PMVector& PMVector::operator-= ( double d )
+{
+ unsigned int i;
+
+ for( i = 0; i < m_size; i++ )
+ m_coord[i] -= d;
+
+ return *this;
+}
+
+PMVector& PMVector::operator+= ( const PMVector& p )
+{
+ unsigned int i;
+
+ if( m_size < p.m_size )
+ resize( p.m_size );
+
+ for( i = 0; i < p.m_size; i++ )
+ m_coord[i] += p[i];
+
+ return *this;
+}
+
+PMVector& PMVector::operator-= ( const PMVector& p )
+{
+ unsigned int i;
+
+ if( m_size < p.m_size )
+ resize( p.m_size );
+
+ for( i = 0; i < m_size; i++ )
+ m_coord[i] -= p[i];
+
+ return *this;
+}
+
+PMVector operator- ( const PMVector& p )
+{
+ PMVector result( p.m_size );
+ unsigned int i;
+
+ for( i = 0; i < p.m_size; i++ )
+ result[i] = -p[i];
+
+ return result;
+}
+
+PMVector operator+ ( const PMVector& p1, const PMVector& p2 )
+{
+ PMVector result( p1 );
+ result += p2;
+
+ return result;
+}
+
+PMVector operator- ( const PMVector& p1, const PMVector& p2 )
+{
+ PMVector result( p1 );
+ result -= p2;
+
+ return result;
+}
+
+PMVector operator* ( const PMVector& p, const double d )
+{
+ PMVector result( p.m_size );
+ unsigned int i;
+
+ for( i = 0; i < p.m_size; i++ )
+ result[i] = p[i] * d;
+
+ return result;
+}
+
+PMVector operator/ ( const PMVector& p, const double d )
+{
+ PMVector result( p.m_size );
+ unsigned int i;
+
+ if( approxZero( d ) )
+ kdError( PMArea ) << "Division by zero in PMVector::operator/ ( PMVector& p, double d ) " << "\n";
+ else
+ for( i = 0; i < p.m_size; i++ )
+ result[i] = p[i] / d;
+
+ return result;
+}
+
+PMVector operator+ ( const PMVector& p, const double d )
+{
+ PMVector result( p.m_size );
+ unsigned int i;
+
+ for( i = 0; i < p.m_size; i++ )
+ result[i] = p[i] + d;
+
+ return result;
+}
+
+PMVector operator- ( const PMVector& p, const double d )
+{
+ PMVector result( p.m_size );
+ unsigned int i;
+
+ for( i = 0; i < p.m_size; i++ )
+ result[i] = p[i] - d;
+
+ return result;
+}
+
+PMVector operator* ( const double d, const PMVector& p )
+{
+ PMVector result( p.m_size );
+ unsigned int i;
+
+ for( i = 0; i < p.m_size; i++ )
+ result[i] = p[i] * d;
+
+ return result;
+}
+
+PMVector operator* ( const PMMatrix& m, const PMVector& p )
+{
+ PMVector result( 3 );
+ int c, i;
+ // for homogenous coordinates
+ double u;
+
+ if( p.m_size != 3 )
+ kdError( PMArea ) << "Vector has not size 3 in PMVector operator* ( const PMVector& p, const PMMatrix& m ) \n";
+ else
+ {
+ for( c=0; c<3; c++ )
+ {
+ result[c] = 0.0;
+ for( i=0; i<4; i++ )
+ result[c] += m[i][c] * ( i<3 ? p[i] : 1.0 );
+ }
+
+ u = 0.0;
+ for( i=0; i<4; i++ )
+ u += m[i][3] * ( i<3 ? p[i] : 1.0 );
+ if( !approxZero( u ) )
+ for( i=0; i<3; i++ )
+ result[i] /= u;
+ }
+
+ return result;
+}
+
+PMVector operator* ( const PMVector& p1, const PMVector& p2 )
+{
+ PMVector result( p1 );
+ result *= p2;
+
+ return result;
+}
+
+PMVector operator/ ( const PMVector& p1, const PMVector& p2 )
+{
+ PMVector result( p1 );
+ result /= p2;
+
+ return result;
+}
+
+bool PMVector::operator== ( const PMVector& p ) const
+{
+ unsigned int i;
+ if( m_size != p.m_size )
+ return false;
+ if( m_size == 0 )
+ return true;
+
+ for( i = 0; i < m_size; i++ )
+ if( p.m_coord[i] != m_coord[i] )
+ return false;
+ return true;
+}
+
+bool PMVector::approxEqual( const PMVector& p, double epsilon ) const
+{
+ unsigned int i;
+ if( m_size != p.m_size )
+ return false;
+ if( m_size == 0 )
+ return true;
+
+ for( i = 0; i < m_size; i++ )
+ if( ! approx( p.m_coord[i], m_coord[i], epsilon ) )
+ return false;
+ return true;
+}
+
+bool PMVector::operator!= ( const PMVector& p ) const
+{
+ return !( *this == p );
+}
+
+
+PMVector PMVector::cross( const PMVector& v1, const PMVector& v2 )
+{
+ PMVector result;
+ if( ( v1.size( ) == 3 ) && ( v2.size( ) == 3 ) )
+ {
+ result[0] = v1[1]*v2[2] - v1[2]*v2[1];
+ result[1] = v1[2]*v2[0] - v1[0]*v2[2];
+ result[2] = v1[0]*v2[1] - v1[1]*v2[0];
+ }
+ else
+ kdError( PMArea ) << "Wrong sizes in PMVector::cross( )\n";
+
+ return result;
+}
+
+double PMVector::dot( const PMVector& v1, const PMVector& v2 )
+{
+ double result = 0.0;
+ unsigned int i;
+
+ if( v1.size( ) == v2.size( ) )
+ {
+ for( i = 0; i < v1.size( ); i++ )
+ result += v1[i] * v2[i];
+ }
+ else
+ kdError( PMArea ) << "Wrong sizes in PMVector::dot( )\n";
+
+ return result;
+}
+
+double PMVector::angle( const PMVector& v1, const PMVector& v2 )
+{
+ PMVector cr;
+ double s, c, n;
+ double a = 0;
+ int i;
+
+ if( ( v1.size( ) == 3 ) && ( v2.size( ) == 3 ) )
+ {
+ n = v1.abs( ) * v2.abs( );
+
+ if( approxZero( n ) )
+ a = 0;
+ else
+ {
+ cr = cross( v1, v2 );
+ s = cr.abs( ) / n;
+
+ c = 0;
+ for( i = 0; i < 3; i++ )
+ c += v1[i] * v2[i];
+
+ c = c / n;
+
+ a = pmatan( s, c );
+ }
+ }
+ else
+ kdError( PMArea ) << "Wrong sizes in PMVector::angle( )\n";
+
+ return a;
+}
+
+double PMVector::abs( ) const
+{
+ unsigned int i;
+ double a = 0.0;
+
+ for( i = 0; i < m_size; i++ )
+ a += m_coord[i] * m_coord[i];
+
+ return sqrt( a );
+}
+
+PMVector PMVector::orthogonal( ) const
+{
+ PMVector result;
+ double l, rl;
+
+ l = abs( );
+ if( approxZero( l ) )
+ {
+ kdError( PMArea ) << "Can't calculate an orthogonal vector from a null vector\n";
+ return PMVector( 1, 0, 0 );
+ }
+
+ result = cross( (*this) / l, PMVector( 0, 0, 1 ) );
+ rl = result.abs( );
+ if( rl < 0.001 )
+ {
+ result = cross( (*this) / l, PMVector( 1, 0, 0 ) );
+ rl = result.abs( );
+ }
+ return result / rl;
+}
+
+QString PMVector::serialize( ) const
+{
+ QString result;
+ QTextStream str( &result, IO_WriteOnly );
+ unsigned int i;
+
+ if( m_size > 0 )
+ {
+ str << '<';
+ for( i = 0; i < m_size; i++ )
+ {
+ if( i > 0 )
+ str << ", ";
+ str << m_coord[i];
+ }
+ str << '>';
+ }
+ else
+ kdError( PMArea ) << "Can't serialize a vector with size 0\n";
+
+ return result;
+}
+
+QString PMVector::serializeXML( ) const
+{
+ QString result;
+ QTextStream str( &result, IO_WriteOnly );
+ unsigned int i;
+
+ if( m_size > 0 )
+ {
+ for( i = 0; i < m_size; i++ )
+ {
+ if( i > 0 )
+ str << ' ';
+ str << m_coord[i];
+ }
+ }
+ else
+ kdError( PMArea ) << "Can't serialize a vector with size 0\n";
+
+ return result;
+}
+
+bool PMVector::loadXML( const QString& str )
+{
+ int i;
+ int size = str.contains( ' ' ) + 1;
+ QString tmp( str );
+ QTextStream s( &tmp, IO_ReadOnly );
+ QString val;
+ bool ok;
+
+ resize( size );
+ for( i = 0; i < size; i++ )
+ {
+ s >> val;
+ m_coord[i] = val.toDouble( &ok );
+ if( !ok )
+ return false;
+ }
+ return true;
+}
diff --git a/kpovmodeler/pmvector.h b/kpovmodeler/pmvector.h
new file mode 100644
index 00000000..6794d02a
--- /dev/null
+++ b/kpovmodeler/pmvector.h
@@ -0,0 +1,275 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMVECTOR_H
+#define PMVECTOR_H
+
+#include <qmemarray.h>
+#include <qstring.h>
+
+class PMMatrix;
+
+/**
+ * Class for vectors with variable size
+ */
+class PMVector
+{
+public:
+ /**
+ * Creates a vector with size s. All values are set to 0
+ */
+ PMVector( unsigned int s );
+ /**
+ * Creates a vector with size 3. All values are set to 0
+ */
+ PMVector( );
+ /**
+ * Creates a vector with coordinates [x,y]
+ */
+ PMVector( const double x, const double y );
+ /**
+ * Creates a vector with coordinates [x,y,z]
+ */
+ PMVector( const double x, const double y, const double z );
+ /**
+ * Creates a vector with coordinates [x,y,z,t]
+ */
+ PMVector( const double x, const double y, const double z, const double t );
+ /**
+ * Copy constructor. Creates a deep copy.
+ */
+ PMVector( const PMVector& v );
+ /**
+ * Deletes the vector
+ */
+ ~PMVector( );
+
+ /**
+ * Returns the size of the vector
+ */
+ unsigned int size( ) const { return m_size; }
+ /**
+ * Resizes the vector. New elements are initialized with 0
+ */
+ void resize( unsigned int size );
+ /**
+ * Returns a reference to a coordinate, 0:x, 1:y, 2:z
+ */
+ double& operator[] ( int index );
+ /**
+ * Returns a reference to a coordinate, 0:x, 1:y, 2:z
+ */
+ const double& operator[] ( int index ) const;
+
+ /**
+ * Returns the x coordinate
+ */
+ double x( ) const { return (*this)[0]; }
+ /**
+ * Returns the y coordinate
+ */
+ double y( ) const { return (*this)[1]; }
+ /**
+ * Returns the z coordinate
+ */
+ double z( ) const { return (*this)[2]; }
+ /**
+ * Returns the t coordinate
+ */
+ double t( ) const { return (*this)[3]; }
+
+ /**
+ * Sets the x coordinate
+ */
+ void setX( const double d ) { (*this)[0] = d; }
+ /**
+ * Sets the y coordinate
+ */
+ void setY( const double d ) { (*this)[1] = d; }
+ /**
+ * Sets the z coordinate
+ */
+ void setZ( const double d ) { (*this)[2] = d; }
+ /**
+ * Sets the x coordinate
+ */
+ void setT( const double d ) { (*this)[3] = d; }
+
+ /**
+ * Transforms the point with the matrix m. Same as p = m * p
+ *
+ * size must be 3!
+ */
+ void transform( const PMMatrix& m );
+
+ /**
+ * Assigns p to the vector. Resizes the vector if necessary.
+ */
+ PMVector& operator= ( const PMVector& p );
+ /**
+ * Sets all values to d
+ */
+ PMVector& operator= ( const double d );
+
+ /**
+ * Multiplies all coordinates with d
+ */
+ PMVector& operator*= ( double d );
+ /**
+ * Divides all coordinates through d
+ */
+ PMVector& operator/= ( double d );
+ /**
+ * Adds d to all coordinates
+ */
+ PMVector& operator+= ( double d );
+ /**
+ * Subtracts d from all coordinates
+ */
+ PMVector& operator-= ( double d );
+
+ /**
+ * Multiplies the vectors (<x1*x2, y1*y2, z1*z2> ...)
+ */
+ PMVector& operator*= ( const PMVector& p );
+ /**
+ * Divides the vectors (<x1/x2, y1/y2, z1/z2> ...)
+ */
+ PMVector& operator/= ( const PMVector& p );
+
+ /**
+ * Adds p to the point.
+ */
+ PMVector& operator+= ( const PMVector& p );
+ /**
+ * Subtracts p from the point.
+ */
+ PMVector& operator-= ( const PMVector& p );
+
+ /**
+ * Returns a point with negated coordinates
+ */
+ friend PMVector operator- ( const PMVector& p );
+ /**
+ * Adds the two points
+ */
+ friend PMVector operator+ ( const PMVector& p1, const PMVector& p2 );
+ /**
+ * Subtracts p2 from p1
+ */
+ friend PMVector operator- ( const PMVector& p1, const PMVector& p2 );
+
+ /**
+ * Multiplies all coordinates with d
+ */
+ friend PMVector operator* ( const PMVector& p, const double d );
+ /**
+ * Divides all coordinates by d
+ */
+ friend PMVector operator/ ( const PMVector& p, const double d );
+ /**
+ * Adds d to all coordinates
+ */
+ friend PMVector operator+ ( const PMVector& p, const double d );
+ /**
+ * Subtracts d from all coordinates
+ */
+ friend PMVector operator- ( const PMVector& p, const double d );
+
+ /**
+ * Multiplies all coordinates with d
+ */
+ friend PMVector operator* ( const double d, const PMVector& p );
+ /**
+ * Multiplies the vectors (<x1*x2, y1*y2, z1*z2> ...)
+ */
+ friend PMVector operator* ( const PMVector& p1, const PMVector& p2 );
+ /**
+ * Divides the vectors (<x1/x2, y1/y2, z1/z2> ...)
+ */
+ friend PMVector operator/ ( const PMVector& p1, const PMVector& p2 );
+ /**
+ * Transforms the point p with the matrix m
+ * @see transform
+ */
+ friend PMVector operator* ( const PMMatrix& m, const PMVector& p );
+
+ /**
+ * Returns true if the vectors have the same size and values
+ */
+ bool operator== ( const PMVector& p ) const;
+ /**
+ * Returns false if the vectors have the same size and values
+ */
+ bool operator!= ( const PMVector& p ) const;
+
+ /**
+ * Returns true if the vectors have the same size and values
+ */
+ bool approxEqual( const PMVector& p, double epsilon = 1e-6 ) const;
+
+ /**
+ * Returns the cross product of v1 and v2
+ *
+ * Size of v1 and v2 has to be 3!
+ */
+ static PMVector cross( const PMVector& v1, const PMVector& v2 );
+ /**
+ * Returns the dot product of v1 and v2
+ */
+ static double dot( const PMVector& v1, const PMVector& v2 );
+
+ /**
+ * Returns the angle between v1 and v2
+ *
+ * Size of v1 and v2 has to be 3!
+ */
+ static double angle( const PMVector& v1, const PMVector& v2 );
+
+ /**
+ * Returns the length of the vector
+ */
+ double abs( ) const;
+
+ /**
+ * Returns a normalized vector that is orthogonal to this vector
+ */
+ PMVector orthogonal( ) const;
+
+ /**
+ * Returns a string for serialization
+ */
+ QString serialize( ) const;
+ /**
+ * Returns a string for xml output
+ */
+ QString serializeXML( ) const;
+ /**
+ * loads the vector data from the xml string
+ */
+ bool loadXML( const QString& str );
+private:
+ void allocateMemory( unsigned int size );
+
+ double* m_coord;
+ static double s_dummy;
+ unsigned int m_size;
+};
+
+#endif
diff --git a/kpovmodeler/pmvectorcontrolpoint.cpp b/kpovmodeler/pmvectorcontrolpoint.cpp
new file mode 100644
index 00000000..0a14d0b8
--- /dev/null
+++ b/kpovmodeler/pmvectorcontrolpoint.cpp
@@ -0,0 +1,89 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmvectorcontrolpoint.h"
+#include "pmmath.h"
+#include <math.h>
+
+PMVectorControlPoint::PMVectorControlPoint( PMControlPoint* base,
+ const PMVector& v, int id,
+ const QString& description,
+ bool extraLine, bool normalize )
+ : PMControlPoint( id, description )
+{
+ m_vector = v;
+ m_pBasePoint = base;
+ m_extraLine = extraLine;
+ m_normalize = normalize;
+}
+
+PMVectorControlPoint::PMVectorControlPoint( const PMVector& base,
+ const PMVector& v, int id,
+ const QString& description,
+ bool extraLine, bool normalize )
+ : PMControlPoint( id, description )
+{
+ m_vector = v;
+ m_constBasePoint = base;
+ m_pBasePoint = 0;
+ m_extraLine = extraLine;
+ m_normalize = normalize;
+}
+
+PMVector PMVectorControlPoint::position( ) const
+{
+ return basePoint( ) + m_vector;
+}
+
+PMVector PMVectorControlPoint::basePoint( ) const
+{
+ if( m_pBasePoint )
+ return m_pBasePoint->position( );
+ return m_constBasePoint;
+}
+
+void PMVectorControlPoint::graphicalChangeStarted( )
+{
+ m_originalVector = m_vector;
+}
+
+void PMVectorControlPoint::graphicalChange( const PMVector& startPoint,
+ const PMVector& /*viewNormal*/,
+ const PMVector& endPoint )
+{
+ double d;
+
+ m_vector = m_originalVector + endPoint - startPoint;
+ if( m_normalize )
+ {
+ d = m_vector.abs( );
+ if( approxZero( d ) )
+ m_vector = m_originalVector;
+ else
+ m_vector /= d;
+ }
+}
+
+void PMVectorControlPoint::snapToGrid( )
+{
+ int i;
+ double d = moveGrid( );
+ if( !approxZero( d ) )
+ for( i = 0; i < 3; i++ )
+ m_vector[i] = rint( m_vector[i] / d ) * d;
+ setChanged( );
+}
diff --git a/kpovmodeler/pmvectorcontrolpoint.h b/kpovmodeler/pmvectorcontrolpoint.h
new file mode 100644
index 00000000..92713bc6
--- /dev/null
+++ b/kpovmodeler/pmvectorcontrolpoint.h
@@ -0,0 +1,101 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMVECTORCONTROLPOINT_H
+#define PMVECTORCONTROLPOINT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+
+#include "pmcontrolpoint.h"
+
+/**
+ * Class for vector like control points
+ */
+class PMVectorControlPoint : public PMControlPoint
+{
+public:
+ /**
+ * Creates a PMVectorControlPoint with id.
+ *
+ * The base point of the vector is given by the control point location.
+ */
+ PMVectorControlPoint( PMControlPoint* location, const PMVector& v,
+ int id, const QString& description,
+ bool extraLine = true, bool normalize = false );
+ /**
+ * Creates a PMVectorControlPoint with id.
+ *
+ * The base point of the vector is given by the vector p.
+ */
+ PMVectorControlPoint( const PMVector& location, const PMVector& v,
+ int id, const QString& description,
+ bool extraLine = true, bool normalize = false );
+ /**
+ * Deletes the PMVectorControlPoint
+ */
+ virtual ~PMVectorControlPoint( ) { };
+
+ /** */
+ virtual PMVector position( ) const;
+ /**
+ * Returns the base point
+ */
+ PMVector basePoint( ) const;
+
+ /**
+ * Sets the vector
+ */
+ void setVector( PMVector newVector ) { m_vector = newVector; }
+ /**
+ * returns the vector
+ */
+ PMVector vector( ) const { return m_vector; }
+
+ /** */
+ virtual bool hasExtraLine( ) const { return m_extraLine; }
+ /**
+ * Returns the start point of the extra line
+ */
+ virtual PMVector extraLineStart( ) const { return basePoint( ); }
+ /**
+ * Returns the end point of the extra line
+ */
+ virtual PMVector extraLineEnd( ) const { return position( ); }
+
+ /** */
+ virtual void snapToGrid( );
+
+protected:
+ /** */
+ virtual void graphicalChangeStarted( );
+ /** */
+ virtual void graphicalChange( const PMVector& startPoint,
+ const PMVector& viewNormal,
+ const PMVector& endPoint );
+private:
+ PMVector m_vector, m_originalVector;
+ PMControlPoint* m_pBasePoint;
+ PMVector m_constBasePoint;
+ bool m_extraLine;
+ bool m_normalize;
+};
+
+#endif
diff --git a/kpovmodeler/pmvectoredit.cpp b/kpovmodeler/pmvectoredit.cpp
new file mode 100644
index 00000000..7264f8f3
--- /dev/null
+++ b/kpovmodeler/pmvectoredit.cpp
@@ -0,0 +1,235 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmvectoredit.h"
+#include "pmdebug.h"
+#include <qstring.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <kdialog.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+
+
+PMVectorEdit::PMVectorEdit( const QString& descriptionX,
+ const QString& descriptionY,
+ QWidget* parent, const char* name )
+ : QWidget( parent, name )
+{
+ unsigned int i;
+ QHBoxLayout* layout;
+ QLabel* label;
+
+ m_edits.resize( 2 );
+ for( i = 0; i < 2; i++ )
+ {
+ m_edits.insert( i, new QLineEdit( this ) );
+ connect( m_edits[i], SIGNAL( textChanged( const QString& ) ),
+ SLOT( slotTextChanged( const QString& ) ) );
+ }
+
+ layout = new QHBoxLayout( this );
+
+ if( !descriptionX.isEmpty( ) )
+ {
+ label = new QLabel( descriptionX, this );
+ layout->addWidget( label );
+ layout->addSpacing( KDialog::spacingHint( ) );
+ }
+ layout->addWidget( m_edits[0] );
+ layout->addSpacing( KDialog::spacingHint( ) );
+
+ if( !descriptionY.isEmpty( ) )
+ {
+ label = new QLabel( descriptionY, this );
+ layout->addWidget( label );
+ layout->addSpacing( KDialog::spacingHint( ) );
+ }
+ layout->addWidget( m_edits[1] );
+}
+
+PMVectorEdit::PMVectorEdit( const QString& descriptionX,
+ const QString& descriptionY,
+ const QString& descriptionZ,
+ QWidget* parent, const char* name )
+ : QWidget( parent, name )
+{
+ unsigned int i;
+ QHBoxLayout* layout;
+ QLabel* label;
+
+ m_edits.resize( 3 );
+ for( i = 0; i < 3; i++ )
+ {
+ m_edits.insert( i, new QLineEdit( this ) );
+ connect( m_edits[i], SIGNAL( textChanged( const QString& ) ),
+ SLOT( slotTextChanged( const QString& ) ) );
+ }
+
+ layout = new QHBoxLayout( this );
+
+ if( !descriptionX.isEmpty( ) )
+ {
+ label = new QLabel( descriptionX, this );
+ layout->addWidget( label );
+ layout->addSpacing( KDialog::spacingHint( ) );
+ }
+ layout->addWidget( m_edits[0] );
+ layout->addSpacing( KDialog::spacingHint( ) );
+
+ if( !descriptionY.isEmpty( ) )
+ {
+ label = new QLabel( descriptionY, this );
+ layout->addWidget( label );
+ layout->addSpacing( KDialog::spacingHint( ) );
+ }
+ layout->addWidget( m_edits[1] );
+ layout->addSpacing( KDialog::spacingHint( ) );
+
+ if( !descriptionZ.isEmpty( ) )
+ {
+ label = new QLabel( descriptionZ, this );
+ layout->addWidget( label );
+ layout->addSpacing( KDialog::spacingHint( ) );
+ }
+ layout->addWidget( m_edits[2] );
+}
+
+PMVectorEdit::PMVectorEdit( const QString& descriptionA,
+ const QString& descriptionB,
+ const QString& descriptionC,
+ const QString& descriptionD,
+ QWidget* parent, const char* name )
+ : QWidget( parent, name )
+{
+ unsigned int i;
+ QHBoxLayout* layout;
+ QLabel* label;
+
+ m_edits.resize( 4 );
+ for( i = 0; i < 4; i++ )
+ {
+ m_edits.insert( i, new QLineEdit( this ) );
+ connect( m_edits[i], SIGNAL( textChanged( const QString& ) ),
+ SLOT( slotTextChanged( const QString& ) ) );
+ }
+
+ layout = new QHBoxLayout( this );
+
+ if( !descriptionA.isEmpty( ) )
+ {
+ label = new QLabel( descriptionA, this );
+ layout->addWidget( label );
+ layout->addSpacing( KDialog::spacingHint( ) );
+ }
+ layout->addWidget( m_edits[0] );
+ layout->addSpacing( KDialog::spacingHint( ) );
+
+ if( !descriptionB.isEmpty( ) )
+ {
+ label = new QLabel( descriptionB, this );
+ layout->addWidget( label );
+ layout->addSpacing( KDialog::spacingHint( ) );
+ }
+ layout->addWidget( m_edits[1] );
+ layout->addSpacing( KDialog::spacingHint( ) );
+
+ if( !descriptionC.isEmpty( ) )
+ {
+ label = new QLabel( descriptionC, this );
+ layout->addWidget( label );
+ layout->addSpacing( KDialog::spacingHint( ) );
+ }
+ layout->addWidget( m_edits[2] );
+ layout->addSpacing( KDialog::spacingHint( ) );
+
+ if( !descriptionD.isEmpty( ) )
+ {
+ label = new QLabel( descriptionD, this );
+ layout->addWidget( label );
+ layout->addSpacing( KDialog::spacingHint( ) );
+ }
+ layout->addWidget( m_edits[3] );
+}
+
+void PMVectorEdit::setVector( const PMVector& v, int precision )
+{
+ unsigned int i;
+ QString str;
+
+ if( v.size( ) != m_edits.size( ) )
+ kdError( PMArea ) << "Vector has wrong size in PMVectorEdit::setVector\n";
+
+ for( i = 0; ( i < m_edits.size( ) ) && ( i < v.size( ) ); i++ )
+ {
+ str.setNum( v[i], 'g', precision );
+ m_edits[i]->setText( str );
+ }
+}
+
+PMVector PMVectorEdit::vector( ) const
+{
+ PMVector result( m_edits.size( ) );
+ unsigned int i;
+
+ for( i = 0; i < m_edits.size( ); i++ )
+ result[i] = m_edits[i]->text( ).toDouble( );
+
+ return result;
+}
+
+bool PMVectorEdit::isDataValid( )
+{
+ bool ok = true;
+ unsigned int i;
+
+ for( i = 0; ( i < m_edits.size( ) ) && ok; i++ )
+ {
+ m_edits[i]->text( ).toDouble( &ok );
+ if( !ok )
+ {
+ KMessageBox::error( this, i18n( "Please enter a valid float value!" ),
+ i18n( "Error" ) );
+ m_edits[i]->setFocus( );
+ m_edits[i]->selectAll( );
+ }
+ }
+
+ return ok;
+}
+
+void PMVectorEdit::slotTextChanged( const QString& )
+{
+ emit dataChanged( );
+}
+
+void PMVectorEdit::setReadOnly( bool yes )
+{
+ unsigned int i;
+ for( i = 0; ( i < m_edits.size( ) ); i++ )
+ m_edits[i]->setReadOnly( yes );
+}
+
+void PMVectorEdit::setEnabled( bool yes )
+{
+ unsigned int i;
+ for( i = 0; ( i < m_edits.size( ) ); i++ )
+ m_edits[i]->setEnabled( yes );
+}
+
+#include "pmvectoredit.moc"
diff --git a/kpovmodeler/pmvectoredit.h b/kpovmodeler/pmvectoredit.h
new file mode 100644
index 00000000..8be64ebe
--- /dev/null
+++ b/kpovmodeler/pmvectoredit.h
@@ -0,0 +1,100 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMVECTOREDIT_H
+#define PMVECTOREDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qwidget.h>
+#include <qptrvector.h>
+#include <qlineedit.h>
+#include "pmvector.h"
+
+/**
+ * Edit widget for @ref PMVector
+ */
+class PMVectorEdit : public QWidget
+{
+ Q_OBJECT
+public:
+ /**
+ * Creates an edit widget for 2D vectors.
+ *
+ * The labels shown are descriptionX and descriptionY
+ */
+ PMVectorEdit( const QString& descriptionX,
+ const QString& descriptionY,
+ QWidget* parent, const char* name = 0 );
+ /**
+ * Creates an edit widget for 3D vectors.
+ *
+ * The labels shown are descriptionX, descriptionY and descriptionZ
+ */
+ PMVectorEdit( const QString& descriptionX,
+ const QString& descriptionY, const QString& descriptionZ,
+ QWidget* parent, const char* name = 0 );
+ /**
+ * Creates an edit widget for 4D vectors.
+ *
+ * The labels shown are descriptionA, descriptionB, descriptionC
+ * and description D
+ */
+ PMVectorEdit( const QString& descriptionA, const QString& descriptionB,
+ const QString& descriptionC, const QString& descriptionD,
+ QWidget* parent, const char* name = 0 );
+
+ /**
+ * Sets the displayed vector
+ */
+ void setVector( const PMVector& v, int precision = 5 );
+ /**
+ * Returns the displayed vector
+ */
+ PMVector vector( ) const;
+
+ /**
+ * Returns true if the text for each coordinate is a valid
+ * float value. Otherwise an error message is shown.
+ */
+ bool isDataValid( );
+
+ /**
+ * Enables or disables read only mode
+ */
+ void setReadOnly( bool yes = true );
+ /**
+ * Reimplemented from QWidget
+ */
+ virtual void setEnabled( bool yes );
+signals:
+ /**
+ * Emitted when one of the coordinates is changed
+ */
+ void dataChanged( );
+
+protected slots:
+ void slotTextChanged( const QString& );
+private:
+ QPtrVector<QLineEdit> m_edits;
+};
+
+#endif
diff --git a/kpovmodeler/pmvectorlistedit.cpp b/kpovmodeler/pmvectorlistedit.cpp
new file mode 100644
index 00000000..224c6b69
--- /dev/null
+++ b/kpovmodeler/pmvectorlistedit.cpp
@@ -0,0 +1,357 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmvectorlistedit.h"
+#include "pmdebug.h"
+
+#include <qheader.h>
+#include <qapplication.h>
+#include <qpalette.h>
+#include <qpainter.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+
+const int c_columnWidth = 65;
+
+
+/*
+PMTableItem::PMTableItem( QTable* table )
+ : QTableItem( table, QTableItem::OnTyping, QString( "" ) )
+{
+ m_readOnly = false;
+}
+
+void PMTableItem::paint( QPainter* p, const QColorGroup& cg,
+ const QRect& cr, bool selected )
+{
+ p->fillRect( 0, 0, cr.width( ), cr.height( ),
+ selected ? cg.brush( QColorGroup::Highlight )
+ : ( m_readOnly ? cg.brush( QColorGroup::Background ) :
+ cg.brush( QColorGroup::Base ) ) );
+
+ int w = cr.width( );
+ int h = cr.height( );
+
+ int x = 0;
+
+ if( selected )
+ p->setPen( cg.highlightedText( ) );
+ else
+ p->setPen( cg.text( ) );
+ p->drawText( x + 2, 0, w - x - 4, h,
+ wordWrap( ) ? ( alignment( ) | WordBreak ) : alignment( ), text( ) );
+}
+*/
+
+PMVectorListEdit::PMVectorListEdit( QWidget* parent, const char* name )
+ : QTable( 1, 3, parent, name )
+{
+ init( 3 );
+
+ QHeader* header = horizontalHeader( );
+ header->setLabel( 0, "x" );
+ header->setLabel( 1, "y" );
+ header->setLabel( 2, "z" );
+}
+
+PMVectorListEdit::PMVectorListEdit( const QString& c1, const QString& c2,
+ const QString& c3, const QString& c4,
+ QWidget* parent, const char* name )
+ : QTable( 1, 4, parent, name )
+{
+ init( 4 );
+
+ QHeader* header = horizontalHeader( );
+ header->setLabel( 0, c1 );
+ header->setLabel( 1, c2 );
+ header->setLabel( 2, c3 );
+ header->setLabel( 3, c4 );
+}
+
+PMVectorListEdit::PMVectorListEdit( const QString& c1, const QString& c2,
+ const QString& c3, QWidget* parent,
+ const char* name )
+ : QTable( 1, 3, parent, name )
+{
+ init( 3 );
+
+ QHeader* header = horizontalHeader( );
+ header->setLabel( 0, c1 );
+ header->setLabel( 1, c2 );
+ header->setLabel( 2, c3 );
+}
+
+PMVectorListEdit::PMVectorListEdit( const QString& c1, const QString& c2,
+ QWidget* parent, const char* name )
+ : QTable( 1, 2, parent, name )
+{
+ init( 2 );
+
+ QHeader* header = horizontalHeader( );
+ header->setLabel( 0, c1 );
+ header->setLabel( 1, c2 );
+}
+
+void PMVectorListEdit::init( int dimensions )
+{
+ int i;
+
+ m_dimension = dimensions;
+ m_size = 0;
+
+ horizontalHeader( )->setResizeEnabled( false );
+ verticalHeader( )->setResizeEnabled( false );
+
+ setSelectionMode( QTable::MultiRow );
+ for( i = 0; i < m_dimension; ++i )
+ setColumnStretchable( i, true );
+ connect( this, SIGNAL( valueChanged( int, int ) ),
+ SLOT( slotTextChanged( int, int ) ) );
+ setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Fixed ) );
+}
+
+void PMVectorListEdit::setVectors( const QValueList<PMVector>& l,
+ bool resize, int prec )
+{
+ QValueList<PMVector>::ConstIterator it;
+ int r, nl = 0;
+
+ for( r = 0; r < ( signed ) m_links.size( ); ++r )
+ if( m_links[r] >= 0 )
+ ++nl;
+
+ if( nl == 0 && resize )
+ setSize( l.size( ) );
+
+ for( r = 0, it = l.begin( ); it != l.end( ) && r < m_size; ++r )
+ {
+ if( m_disabled[r] )
+ {
+ if( !isReadOnly( ) )
+ setRowReadOnly( r, true );
+ }
+ else
+ {
+ setVector( r, *it, prec );
+ if( !isReadOnly( ) )
+ setRowReadOnly( r, false );
+ if( m_links[r] >= 0 )
+ setVector( m_links[r], *it, prec );
+ ++it;
+ }
+ }
+ if( it != l.end( ) )
+ kdError( PMArea ) << "Wrong size of vector list in PMVectorListEdit::setVectors" << endl;
+}
+
+QValueList<PMVector> PMVectorListEdit::vectors( ) const
+{
+ QValueList<PMVector> l;
+ int i;
+
+ for( i = 0; i < m_size; ++i )
+ if( !m_disabled[i] )
+ l.append( vector( i ) );
+
+ return l;
+}
+
+void PMVectorListEdit::setVector( int r, const PMVector& v, int precision )
+{
+ if( r < 0 || r >= m_size )
+ {
+ kdError( PMArea ) << "Wrong vector index in PMVectorListEdit::setVector"
+ << endl;
+ return;
+ }
+
+ bool sb = signalsBlocked( );
+ blockSignals( true );
+
+ int i;
+ QString str;
+
+ for( i = 0; i < m_dimension && i <= ( signed ) v.size( ); ++i )
+ {
+ str.setNum( v[i], 'g', precision );
+ setText( r, i, str );
+ }
+
+ blockSignals( sb );
+}
+
+PMVector PMVectorListEdit::vector( int r ) const
+{
+ PMVector v( m_dimension );
+
+ if( r < 0 || r >= m_size )
+ {
+ kdError( PMArea ) << "Wrong vector index in PMVectorListEdit::vector"
+ << endl;
+ return v;
+ }
+
+ int i;
+ for( i = 0; i < m_dimension; ++i )
+ v[i] = text( r, i ).toDouble( );
+ return v;
+}
+
+void PMVectorListEdit::setSize( int s )
+{
+ if( s < 0 || s == m_size )
+ return;
+
+ setNumRows( s );
+ int i;
+ QHeader* h = verticalHeader( );
+ QString str;
+
+ for( i = 0; i < s; ++i )
+ {
+ setRowStretchable( i, true );
+ setRowReadOnly( i, false );
+
+ str.setNum( i + 1 );
+ h->setLabel( i, str );
+ }
+ m_links.fill( -1, s );
+ m_disabled.fill( false, s );
+ m_size = s;
+ updateGeometry( );
+}
+
+void PMVectorListEdit::setLink( int p1, int p2 )
+{
+ if( p1 < 0 || p1 >= m_size || p2 >= m_size )
+ return;
+
+ QHeader* h = verticalHeader( );
+ QString str;
+
+ // remove old link
+ if( m_links[p1] >= 0 )
+ {
+ str.setNum( m_links[p1] + 1 );
+ h->setLabel( m_links[p1], str );
+ if( !isReadOnly( ) )
+ setRowReadOnly( m_links[p1], false );
+ m_disabled[m_links[p1]] = false;
+ }
+
+ if( p2 >= 0 )
+ {
+ m_disabled[p2] = true;
+ str = QString( "%1 (=%2)" ).arg( p2 + 1 ).arg( p1 + 1 );
+ h->setLabel( p2, str );
+ if( !isReadOnly( ) )
+ setRowReadOnly( p2, true );
+ }
+
+ m_links[p1] = p2;
+}
+
+void PMVectorListEdit::clearLinks( )
+{
+ int i;
+ for( i = 0; i < ( signed ) m_links.size( ); ++i )
+ if( m_links[i] >= 0 )
+ setLink( i, -1 );
+}
+
+bool PMVectorListEdit::isSelected( int i ) const
+{
+ return isRowSelected( i );
+}
+
+void PMVectorListEdit::select( int i )
+{
+ selectRow( i );
+}
+
+void PMVectorListEdit::select( int i, int j )
+{
+ QTableSelection sel( i, 0, j, m_dimension - 1 );
+ addSelection( sel );
+
+}
+
+bool PMVectorListEdit::isDataValid( )
+{
+ int r, i;
+ bool valid = true;
+ double d;
+
+ for( r = 0; r < m_size && valid; ++r )
+ {
+ if( !m_disabled[r] )
+ {
+ for( i = 0; i < m_dimension && valid; ++i )
+ {
+ d = text( r, i ).toDouble( &valid );
+ if( !valid )
+ {
+ setCurrentCell( r, i );
+ KMessageBox::error( this, i18n( "Please enter a valid float value!" ),
+ i18n( "Error" ) );
+ }
+ }
+ }
+ }
+ return valid;
+}
+
+QSize PMVectorListEdit::sizeHint( ) const
+{
+ return QSize( c_columnWidth * m_dimension + frameWidth( ) * 2,
+ frameWidth( ) * 2 + horizontalHeader( )->height( )
+ + verticalHeader( )->sizeHint( ).height( ) );
+}
+
+void PMVectorListEdit::slotTextChanged( int, int )
+{
+ emit dataChanged( );
+}
+
+void PMVectorListEdit::blockSelectionUpdates( bool block )
+{
+ setUpdatesEnabled( !block );
+ verticalHeader( )->setUpdatesEnabled( !block );
+ horizontalHeader( )->setUpdatesEnabled( !block );
+ if( !block )
+ {
+ updateContents( );
+ verticalHeader( )->update( );
+ horizontalHeader( )->update( );
+ }
+}
+
+bool PMVectorListEdit::eventFilter( QObject* o, QEvent* e )
+{
+ if( e->type( ) == QEvent::Wheel && parent( ) )
+ return QApplication::sendEvent( parent( ), e );
+ if( e->type( ) == QEvent::MouseButtonPress
+ && ( ( QMouseEvent* ) e )->button( ) == RightButton )
+ {
+ bool b = QTable::eventFilter( o, e );
+ emit showContextMenu( );
+ return b;
+ }
+ return QTable::eventFilter( o, e );
+}
+
+#include "pmvectorlistedit.moc"
diff --git a/kpovmodeler/pmvectorlistedit.h b/kpovmodeler/pmvectorlistedit.h
new file mode 100644
index 00000000..f8ecb938
--- /dev/null
+++ b/kpovmodeler/pmvectorlistedit.h
@@ -0,0 +1,174 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMVECTORLISTEDIT_H
+#define PMVECTORLISTEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qtable.h>
+#include <qvaluelist.h>
+#include <qmemarray.h>
+
+#include "pmvector.h"
+
+/*
+const int c_pmTableRTTI = 14352;
+
+class PMTableItem : public QTableItem
+{
+public:
+ PMTableItem( QTable* table );
+
+ virtual void paint( QPainter* p, const QColorGroup& cg,
+ const QRect& cr, bool selected );
+
+ int rtti( ) const { return c_pmTableRTTI; }
+
+ void setReadOnly( bool r ) { m_readOnly = r; }
+ bool isReadOnly( ) const { return m_readOnly; }
+
+private:
+ bool m_readOnly;
+};
+*/
+
+
+/**
+ * Widget that displays a list of vectors, based on @ref QTable.
+ */
+class PMVectorListEdit : public QTable
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor for 3d vectors (x, y, z)
+ */
+ PMVectorListEdit( QWidget* parent, const char* name = 0 );
+ /**
+ * Constructor for 3d vectors
+ */
+ PMVectorListEdit( const QString& c1, const QString& c2, const QString& c3,
+ QWidget* parent, const char* name = 0 );
+ /**
+ * Constructor for 2d vectors
+ */
+ PMVectorListEdit( const QString& c1, const QString& c2,
+ QWidget* parent, const char* name = 0 );
+
+ /**
+ * Constructor for 4d vectors
+ */
+ PMVectorListEdit( const QString& c1, const QString& c2, const QString& c3,
+ const QString& c4, QWidget* parent, const char* name = 0 );
+ /**
+ * Sets and displays the vectors. The widget will automatically
+ * resize if no link is set and resize is true.
+ */
+ void setVectors( const QValueList<PMVector>& v, bool resize = false,
+ int precision = 5 );
+ /**
+ * Returns the vectors
+ */
+ QValueList<PMVector> vectors( ) const;
+ /**
+ * Sets the i-th vector
+ */
+ void setVector( int i, const PMVector& v, int precision = 5 );
+ /**
+ * Returns the i-th vector
+ */
+ PMVector vector( int i ) const;
+ /**
+ * Sets the number of vectors
+ */
+ void setSize( int s );
+ /**
+ * Returns the number of vectors
+ */
+ int size( ) const { return m_size; }
+
+ /**
+ * Adds a linked point. The point p2 will be disabled and synchronized
+ * with p1.
+ *
+ * Call this method before displaying vectors and remove the point
+ * p2 from the vector list before you call @ref setVectors( ).
+ * The list returned by @ref vectors( ) will not return this point.
+ *
+ * Set p2 to -1 to remove a link.
+ */
+ void setLink( int p1, int p2 );
+ /**
+ * Removes all links. The widget is not updated. You have to resize
+ * the widget and redisplay the points.
+ */
+ void clearLinks( );
+
+ /**
+ * Returns the selection status of vector i
+ */
+ bool isSelected( int i ) const;
+ /**
+ * Selects vector i
+ */
+ void select( int i );
+ /**
+ * Selects vector i to j
+ */
+ void select( int i, int j );
+ /**
+ * Blocks/unblocks selection updates. If block is false, the
+ * selection is repainted.
+ */
+ void blockSelectionUpdates( bool block );
+
+ /**
+ * Returns true if the edited data is valid.
+ */
+ bool isDataValid( );
+
+ /** */
+ virtual QSize sizeHint( ) const;
+ /** */
+ bool eventFilter( QObject* o, QEvent* e );
+
+protected slots:
+ void slotTextChanged( int, int );
+
+signals:
+ /**
+ * Emitted when the used edits a field
+ */
+ void dataChanged( );
+ /**
+ * Emitted after a right mouse button click
+ */
+ void showContextMenu( );
+private:
+ void init( int dimensions );
+
+ int m_dimension, m_size;
+ QMemArray<int> m_links;
+ QMemArray<bool> m_disabled;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmview.cpp b/kpovmodeler/pmview.cpp
new file mode 100644
index 00000000..fe9f32d4
--- /dev/null
+++ b/kpovmodeler/pmview.cpp
@@ -0,0 +1,108 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include <qprinter.h>
+#include <qpainter.h>
+#include <qsplitter.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <kconfig.h>
+#include <kdialog.h>
+#include <klocale.h>
+
+#include <stdio.h>
+
+// application specific includes
+#include "pmview.h"
+#include "pmpart.h"
+#include "pmtreeview.h"
+#include "pmdialogview.h"
+#include "pmglview.h"
+
+PMView::PMView( PMPart* part, QWidget* parent, const char* name )
+ : QWidget( parent, name )
+{
+ setBackgroundMode( PaletteBase );
+
+ QVBoxLayout* layout = new QVBoxLayout( this );
+ m_pMainSplitter = new QSplitter( Qt::Horizontal, this, "MainSplitter" );
+ m_pTreeEditSplitter = new QSplitter( Qt::Vertical, m_pMainSplitter,
+ "TreeEditSplitter" );
+
+
+ m_pTreeView = new PMTreeView( part, m_pTreeEditSplitter, "TreeView" );
+ m_pTreeView->show( );
+
+ m_pDialogView = new PMDialogView( part, m_pTreeEditSplitter, "EditView" );
+ m_pDialogView->show( );
+
+
+ QWidget* glArea = new QWidget( m_pMainSplitter, "GLArea" );
+ glArea->show( );
+ PMGLView* gl;
+
+ QGridLayout* topLayout = new QGridLayout( glArea, 2, 2, 1, 1 );
+ gl = new PMGLView( part, PMGLView::PMViewPosZ, glArea );
+ topLayout->addWidget( gl, 0, 0 );
+ gl = new PMGLView( part, PMGLView::PMViewPosX, glArea );
+ topLayout->addWidget( gl, 0, 1 );
+ gl = new PMGLView( part, PMGLView::PMViewNegY, glArea );
+ topLayout->addWidget( gl, 1, 0 );
+ gl = new PMGLView( part, PMGLView::PMViewCamera, glArea );
+ topLayout->addWidget( gl, 1, 1 );
+
+ m_pMainSplitter->show( );
+
+ layout->addWidget( m_pMainSplitter );
+ layout->activate( );
+
+ m_pPart = part;
+}
+
+PMView::~PMView( )
+{
+}
+
+void PMView::print( QPrinter* pPrinter )
+{
+ QPainter printpainter;
+ printpainter.begin( pPrinter );
+
+ // TODO: add your printing code here
+
+ printpainter.end( );
+}
+
+void PMView::saveConfig( KConfig* cfg )
+{
+ cfg->setGroup( "Appearance" );
+
+ cfg->writeEntry( "MainSplitter", m_pMainSplitter->sizes( ) );
+ cfg->writeEntry( "TreeEditSplitter", m_pTreeEditSplitter->sizes( ) );
+}
+
+void PMView::restoreConfig( KConfig* cfg )
+{
+ cfg->setGroup( "Appearance" );
+
+ m_pMainSplitter->setSizes( cfg->readIntListEntry( "MainSplitter" ) );
+ m_pTreeEditSplitter->setSizes( cfg->readIntListEntry( "TreeEditSplitter" ) );
+}
+
+
+#include "pmview.moc"
diff --git a/kpovmodeler/pmview.h b/kpovmodeler/pmview.h
new file mode 100644
index 00000000..8a216663
--- /dev/null
+++ b/kpovmodeler/pmview.h
@@ -0,0 +1,76 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMVIEW_H
+#define PMVIEW_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// include files for Qt
+#include <qwidget.h>
+
+class PMTreeView;
+class PMDialogView;
+class PMPart;
+class QSplitter;
+class KConfig;
+
+/**
+ * The PMView class provides the view widget for the PMPart document class.
+ */
+class PMView : public QWidget
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor for the main view
+ */
+ PMView( PMPart* part, QWidget* parent = 0, const char* name = 0 );
+ /**
+ * Destructor for the main view
+ */
+ ~PMView( );
+
+ /**
+ * returns a pointer to the part
+ */
+ PMPart* part( ) const { return m_pPart; }
+
+ /**
+ * contains the implementation for printing functionality TODO*/
+ void print( QPrinter* pPrinter );
+ /**
+ * saves settings
+ */
+ void saveConfig( KConfig* cfg );
+ /**
+ * loads settings
+ */
+ void restoreConfig( KConfig* cfg );
+private:
+ PMTreeView* m_pTreeView;
+ PMPart* m_pPart;
+ PMDialogView* m_pDialogView;
+ QSplitter* m_pMainSplitter;
+ QSplitter* m_pTreeEditSplitter;
+};
+
+#endif
diff --git a/kpovmodeler/pmviewbase.cpp b/kpovmodeler/pmviewbase.cpp
new file mode 100644
index 00000000..44c239ef
--- /dev/null
+++ b/kpovmodeler/pmviewbase.cpp
@@ -0,0 +1,20 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmviewbase.h"
+
+#include "pmviewbase.moc"
diff --git a/kpovmodeler/pmviewbase.h b/kpovmodeler/pmviewbase.h
new file mode 100644
index 00000000..cce59922
--- /dev/null
+++ b/kpovmodeler/pmviewbase.h
@@ -0,0 +1,128 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMVIEWBASE_H
+#define PMVIEWBASE_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qwidget.h>
+#include <qstring.h>
+
+class QDomElement;
+
+/**
+ * This class stores the view configuration for one view.
+ *
+ * Reimplement this class for each view type that has to store
+ * additional values.
+ *
+ * Created, loaded from and saved to the xml config by the corresponding
+ * @ref PMViewTypeFactory factory class.
+ */
+class PMViewOptions
+{
+public:
+ /**
+ * Returns a deep copy
+ */
+ virtual PMViewOptions* copy( ) const = 0;
+ /**
+ * Returns the identifier for the view type. Has to be equal
+ * to @ref PMViewBase::viewType for the corresponding view type.
+ */
+ virtual QString viewType( ) const = 0;
+ /**
+ * Loads the data from the xml element
+ */
+ virtual void loadData( QDomElement& e ) = 0;
+ /**
+ * Saves the data from to xml element
+ */
+ virtual void saveData( QDomElement& e ) = 0;
+};
+
+/**
+ * Base class for configuration widgets for view types
+ * for the layout settings dialog page
+ */
+class PMViewOptionsWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ PMViewOptionsWidget( QWidget* parent, const char* name = 0 )
+ : QWidget( parent, name )
+ {
+ }
+
+signals:
+ /**
+ * Emitted when the view type description has changed
+ */
+ void viewTypeDescriptionChanged( );
+};
+
+/**
+ * Interface for views.
+ *
+ * Each view type has to implement this interface. Handles the
+ * config loading and saving
+ */
+class PMViewBase : public QWidget
+{
+ Q_OBJECT
+public:
+ /**
+ * Default constructor
+ */
+ PMViewBase( QWidget* parent, const char* name = 0, WFlags f = 0 )
+ : QWidget( parent, name, f )
+ {
+ }
+ /**
+ * Returns the identifier for the view type. Has to be unique
+ * for all view types.
+ */
+ virtual QString viewType( ) const = 0;
+ /**
+ * Returns a i18n'ed description
+ */
+ virtual QString description( ) const = 0;
+ /**
+ * Restores the view configuration
+ *
+ * Reimplement this function if the view type has to
+ * restore additional values.
+ * @see PMViewOptions
+ */
+ virtual void restoreViewConfig( PMViewOptions* ) { }
+ /**
+ * Saves the view configuration
+ *
+ * Reimplement this function if the view type has to
+ * restore additional values.
+ * @see PMViewOptions
+ */
+ virtual void saveViewConfig( PMViewOptions* ) const { }
+};
+
+#endif
diff --git a/kpovmodeler/pmviewfactory.cpp b/kpovmodeler/pmviewfactory.cpp
new file mode 100644
index 00000000..58e566cc
--- /dev/null
+++ b/kpovmodeler/pmviewfactory.cpp
@@ -0,0 +1,94 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmviewfactory.h"
+#include "pmglview.h"
+#include "pmtreeview.h"
+#include "pmdialogview.h"
+#include "pmdebug.h"
+#include "pmviewbase.h"
+#include "pmglview.h"
+#include "pmtreeview.h"
+#include "pmdialogview.h"
+#include "pmlibrarybrowser.h"
+
+#include <klocale.h>
+
+PMViewFactory* PMViewFactory::s_pInstance = 0;
+KStaticDeleter<PMViewFactory> PMViewFactory::s_staticDeleter;
+
+PMViewFactory::PMViewFactory( )
+{
+ m_viewTypes.setAutoDelete( true );
+ addViewType( new PMTreeViewFactory( ) );
+ addViewType( new PMDialogViewFactory( ) );
+ addViewType( new PMGLViewFactory( ) );
+ addViewType( new PMLibraryBrowserViewFactory( ) );
+}
+
+PMViewFactory::~PMViewFactory( )
+{
+ m_viewTypes.clear( );
+}
+
+PMViewFactory* PMViewFactory::theFactory( )
+{
+ if( !s_pInstance )
+ s_staticDeleter.setObject( s_pInstance, new PMViewFactory( ) );
+ return s_pInstance;
+}
+
+void PMViewFactory::addViewType( PMViewTypeFactory* vt )
+{
+ if( vt )
+ {
+ m_viewTypes.append( vt );
+ m_dict.insert( vt->viewType( ), vt );
+ }
+}
+
+PMViewBase* PMViewFactory::newViewInstance( const QString& viewType,
+ QWidget* parent, PMPart* part ) const
+{
+ PMViewTypeFactory* f = m_dict.find( viewType );
+ if( f )
+ return f->newInstance( parent, part );
+
+ kdError( PMArea ) << "Unknown view type \"" << viewType << "\"" << endl;
+ return 0;
+}
+
+PMViewOptions* PMViewFactory::newOptionsInstance( const QString& viewType ) const
+{
+ PMViewTypeFactory* f = m_dict.find( viewType );
+ if( f )
+ return f->newOptionsInstance( );
+
+ kdError( PMArea ) << "Unknown view type \"" << viewType << "\"" << endl;
+ return 0;
+}
+
+PMViewTypeFactory* PMViewFactory::viewFactory( const QString& viewType ) const
+{
+ return m_dict.find( viewType );
+}
+
+const QPtrList<PMViewTypeFactory>& PMViewFactory::viewTypes( ) const
+{
+ return m_viewTypes;
+}
+
diff --git a/kpovmodeler/pmviewfactory.h b/kpovmodeler/pmviewfactory.h
new file mode 100644
index 00000000..b24814cf
--- /dev/null
+++ b/kpovmodeler/pmviewfactory.h
@@ -0,0 +1,145 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMVIEWFACTORY_H
+#define PMVIEWFACTORY_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qstring.h>
+#include <qptrlist.h>
+#include <qdict.h>
+#include <kstaticdeleter.h>
+
+class PMViewBase;
+class QWidget;
+class PMPart;
+class QDomElement;
+class PMViewOptions;
+class PMViewOptionsWidget;
+
+/**
+ * Factory and description class for one view type
+ * @see PMViewFactory
+ */
+class PMViewTypeFactory
+{
+public:
+ /**
+ * Default constructor
+ */
+ PMViewTypeFactory( ) { }
+ /**
+ * Destructor
+ */
+ virtual ~PMViewTypeFactory( ) { }
+ /**
+ * Returns the id for the view type. Choose an unique name.
+ */
+ virtual QString viewType( ) const = 0;
+ /**
+ * Returns a i18n'ed description for the view type
+ */
+ virtual QString description( ) const = 0;
+ /**
+ * Returns a i18n'ed description for the view type, dependent
+ * on the options. Calls the method above by default.
+ */
+ virtual QString description( PMViewOptions* ) const
+ {
+ return description( );
+ }
+ /**
+ * Returns the icon name for the view
+ */
+ virtual QString iconName( ) const = 0;
+ /**
+ * Returns a new view instance
+ */
+ virtual PMViewBase* newInstance( QWidget* parent, PMPart* part ) const = 0;
+ /**
+ * Creates a config object for the view type.
+ * If the view doesn't have special attributes, the function returns 0;
+ */
+ virtual PMViewOptions* newOptionsInstance( ) const { return 0; }
+ /**
+ * Creates a widget to configure the custom options
+ */
+ virtual PMViewOptionsWidget* newOptionsWidget( QWidget*, PMViewOptions* )
+ {
+ return 0;
+ }
+};
+
+
+/**
+ * Factory class for KPovModeler views.
+ *
+ * Plugins can add new view types by adding new
+ * @ref PMViewTypeFactory objects.
+ */
+class PMViewFactory
+{
+public:
+ /**
+ * Destructor
+ */
+ ~PMViewFactory( );
+ /**
+ * Returns the factory instance
+ */
+ static PMViewFactory* theFactory( );
+
+ /**
+ * Adds a new view type
+ *
+ * The factory becomes the owner of the object
+ */
+ void addViewType( PMViewTypeFactory* vt );
+ /**
+ * Returns a new view of type viewType if available
+ */
+ PMViewBase* newViewInstance( const QString& viewType,
+ QWidget* parent, PMPart* part ) const;
+ /**
+ * Returns a new view option instance for the given view type
+ */
+ PMViewOptions* newOptionsInstance( const QString& viewType ) const;
+ /**
+ * Returns the factory for the given view type
+ */
+ PMViewTypeFactory* viewFactory( const QString& viewType ) const;
+ /**
+ * Returns the list of available view types
+ */
+ const QPtrList<PMViewTypeFactory>& viewTypes( ) const;
+private:
+ /**
+ * Constructor
+ */
+ PMViewFactory( );
+
+ QPtrList<PMViewTypeFactory> m_viewTypes;
+ QDict<PMViewTypeFactory> m_dict;
+
+ static PMViewFactory* s_pInstance;
+ static KStaticDeleter<PMViewFactory> s_staticDeleter;
+};
+
+#endif
diff --git a/kpovmodeler/pmviewlayoutmanager.cpp b/kpovmodeler/pmviewlayoutmanager.cpp
new file mode 100644
index 00000000..593eed27
--- /dev/null
+++ b/kpovmodeler/pmviewlayoutmanager.cpp
@@ -0,0 +1,935 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmviewlayoutmanager.h"
+#include "pmdockwidget_private.h"
+
+#include <kconfig.h>
+#include <kstandarddirs.h>
+#include <klocale.h>
+#include <kfilterdev.h>
+#include <kpopupmenu.h>
+#include <kiconloader.h>
+
+#include <qfile.h>
+#include <qdom.h>
+#include <qwidgetlist.h>
+#include <qlistbox.h>
+#include <qlineedit.h>
+#include <qlayout.h>
+#include <qlabel.h>
+
+#include "pmshell.h"
+#include "pmdebug.h"
+#include "pmviewfactory.h"
+
+PMViewLayoutManager* PMViewLayoutManager::s_pInstance = 0;
+KStaticDeleter<PMViewLayoutManager> PMViewLayoutManager::s_staticDeleter;
+
+
+//================ PMViewLayoutEntry ====================
+
+PMViewLayoutEntry::PMViewLayoutEntry( )
+{
+ m_viewType = "treeview";
+ m_dockPosition = PMDockWidget::DockRight;
+ m_columnWidth = 33;
+ m_height = 50;
+ m_floatingWidth = 400;
+ m_floatingHeight = 400;
+ m_floatingPositionX = 200;
+ m_floatingPositionY = 200;
+ m_pCustomOptions = 0;
+}
+
+PMViewLayoutEntry::PMViewLayoutEntry( const PMViewLayoutEntry& e )
+{
+ m_viewType = e.m_viewType;
+ m_dockPosition = e.m_dockPosition;
+ m_columnWidth = e.m_columnWidth;
+ m_height = e.m_height;
+ m_floatingWidth = e.m_floatingWidth;
+ m_floatingHeight = e.m_floatingHeight;
+ m_floatingPositionX = e.m_floatingPositionX;
+ m_floatingPositionY = e.m_floatingPositionY;
+ if( e.m_pCustomOptions )
+ m_pCustomOptions = e.m_pCustomOptions->copy( );
+ else
+ m_pCustomOptions = 0;
+}
+
+PMViewLayoutEntry::~PMViewLayoutEntry( )
+{
+ if( m_pCustomOptions )
+ delete m_pCustomOptions;
+}
+
+void PMViewLayoutEntry::loadData( QDomElement& e )
+{
+ QString s;
+ bool ok;
+
+ // Read the view type
+ s = e.tagName( );
+ m_viewType = s;
+
+ // Read dock position
+ s = e.attribute( "position", "Right" );
+ if( s == "Right" ) m_dockPosition = PMDockWidget::DockRight;
+ else if( s == "Bottom" ) m_dockPosition = PMDockWidget::DockBottom;
+ else if( s == "Center" ) m_dockPosition = PMDockWidget::DockCenter;
+ else if( s == "None" ) m_dockPosition = PMDockWidget::DockNone;
+
+ // Read the column width
+ s = e.attribute( "columnWidth", "33" );
+ m_columnWidth = s.toInt( &ok );
+ if( !ok ) m_columnWidth = 33;
+
+ // and view height
+ s = e.attribute( "height", "50" );
+ m_height = s.toInt( &ok );
+ if( !ok ) m_height = 50;
+
+ s = e.attribute( "floatingHeight", "400" );
+ m_floatingHeight = s.toInt( &ok );
+ if( !ok ) m_floatingHeight = 400;
+ s = e.attribute( "floatingWidth", "400" );
+ m_floatingWidth = s.toInt( &ok );
+ if( !ok ) m_floatingWidth = 400;
+
+ s = e.attribute( "floatingPosX", "200" );
+ m_floatingPositionX = s.toInt( &ok );
+ if( !ok ) m_floatingPositionX = 200;
+ s = e.attribute( "floatingPosY", "200" );
+ m_floatingPositionY = s.toInt( &ok );
+ if( !ok ) m_floatingPositionY = 200;
+
+ // Load custom options
+ if( m_pCustomOptions )
+ delete m_pCustomOptions;
+ m_pCustomOptions =
+ PMViewFactory::theFactory( )->newOptionsInstance( m_viewType );
+ if( m_pCustomOptions )
+ m_pCustomOptions->loadData( e );
+}
+
+void PMViewLayoutEntry::saveData( QDomElement& e ) const
+{
+ QString s;
+ e.setTagName( m_viewType );
+ switch( m_dockPosition )
+ {
+ case PMDockWidget::DockRight:
+ e.setAttribute( "position", "Right" );
+ break;
+ case PMDockWidget::DockBottom:
+ e.setAttribute( "position", "Bottom" );
+ break;
+ case PMDockWidget::DockCenter:
+ e.setAttribute( "position", "Center" );
+ break;
+ case PMDockWidget::DockNone:
+ e.setAttribute( "position", "None" );
+ break;
+ default:
+ kdError( PMArea ) << i18n( "Unknown dock position." )
+ << endl;
+ break;
+ }
+ s.setNum( m_columnWidth );
+ e.setAttribute( "columnWidth", s );
+ s.setNum( m_height );
+ e.setAttribute( "height", s );
+ s.setNum( m_floatingHeight );
+ e.setAttribute( "floatingHeight", s );
+ s.setNum( m_floatingWidth );
+ e.setAttribute( "floatingWidth", s );
+ s.setNum( m_floatingPositionX );
+ e.setAttribute( "floatingPosX", s );
+ s.setNum( m_floatingPositionY );
+ e.setAttribute( "floatingPosY", s );
+
+ // save custom options
+ if( m_pCustomOptions )
+ m_pCustomOptions->saveData( e );
+}
+
+void PMViewLayoutEntry::setViewType( const QString& v )
+{
+ m_viewType = v;
+}
+
+void PMViewLayoutEntry::setDockPosition( PMDockWidget::DockPosition i )
+{
+ m_dockPosition = i;
+}
+
+void PMViewLayoutEntry::setColumnWidth( int i )
+{
+ m_columnWidth = i;
+ if( i < 1 )
+ m_columnWidth = 1;
+}
+
+void PMViewLayoutEntry::setHeight( int i )
+{
+ m_height = i;
+ if( i < 1 )
+ m_height = 1;
+}
+
+const QString PMViewLayoutEntry::viewTypeAsString( )
+{
+ PMViewTypeFactory* f = PMViewFactory::theFactory( )->viewFactory( m_viewType );
+ if( f )
+ {
+ if( m_pCustomOptions )
+ return f->description( m_pCustomOptions );
+ else
+ return f->description( );
+ }
+
+ kdError( PMArea ) << i18n( "Unknown view type." )<< endl;
+ return i18n( "Unknown" );
+}
+
+const QString PMViewLayoutEntry::dockPositionAsString( )
+{
+ switch( m_dockPosition )
+ {
+ case PMDockWidget::DockRight:
+ return i18n( "New Column" );
+ case PMDockWidget::DockBottom:
+ return i18n( "Below" );
+ case PMDockWidget::DockCenter:
+ return i18n( "Tabbed" );
+ case PMDockWidget::DockNone:
+ return i18n( "Floating" );
+ default:
+ kdError( PMArea ) << i18n( "Unknown dock position." )
+ << endl;
+ return i18n( "unknown" );
+ }
+}
+
+void PMViewLayoutEntry::setCustomOptions( PMViewOptions* o )
+{
+ if( m_pCustomOptions && m_pCustomOptions != o )
+ delete m_pCustomOptions;
+ m_pCustomOptions = o;
+}
+
+//================== PMViewLayout ======================
+
+PMViewLayout::PMViewLayout( )
+{
+ m_entries.clear( );
+}
+
+PMViewLayout::PMViewLayout( const PMViewLayout& vl )
+{
+ m_entries = vl.m_entries;
+ m_name = vl.m_name;
+}
+
+PMViewLayout& PMViewLayout::operator = ( const PMViewLayout& vl )
+{
+ m_entries = vl.m_entries;
+ m_name = vl.m_name;
+ return *this;
+}
+
+void PMViewLayout::loadData( QDomElement& e )
+{
+ m_entries.clear( );
+ m_name = e.attribute( "name", "unnamed" );
+
+ QDomNode m = e.firstChild( );
+ while( !m.isNull( ) )
+ {
+ if( m.isElement( ) )
+ {
+ QDomElement me = m.toElement( );
+ PMViewLayoutEntry vle;
+
+ vle.loadData( me );
+ m_entries.append( vle );
+ }
+ m = m.nextSibling( );
+ }
+ normalize( );
+}
+
+void PMViewLayout::saveData( QDomElement& e, QDomDocument& doc ) const
+{
+ QValueList< PMViewLayoutEntry>::const_iterator it;
+
+ e.setAttribute( "name", m_name );
+ for( it = m_entries.begin( ); it != m_entries.end( ) ; ++it )
+ {
+ QDomElement a;
+ a = doc.createElement( "unknown" );
+ ( *it ).saveData( a );
+ e.appendChild( a );
+ }
+}
+
+void PMViewLayout::setName( const QString& n )
+{
+ m_name = n;
+}
+
+void PMViewLayout::addEntry( const PMViewLayoutEntry& e, int index )
+{
+ if( index == -1 )
+ m_entries.append( e );
+ else
+ m_entries.insert( m_entries.at( index ), 1, e );
+}
+
+void PMViewLayout::removeEntry( int index )
+{
+ m_entries.remove( m_entries.at( index ) );
+}
+
+void PMViewLayout::displayLayout( PMShell* shell )
+{
+ PMDockWidget* lastWidget = 0;
+ QValueList< PMViewLayoutEntry>::const_iterator it;
+ bool isViewSet = false;
+ int lastWidth = 0, width = 100;
+ int lastHeight = 0, height = 100;
+
+ for( it = m_entries.begin( ); it != m_entries.end( ) ; ++it )
+ {
+ PMDockWidget* dock = shell->createView( ( *it ).viewType( ),
+ ( *it ).customOptions( ),
+ false );
+ // Dock the widget
+ if( ( *it ).dockPosition( ) == PMDockWidget::DockNone )
+ {
+ // the specified target is the desktop
+ dock->manualDock( 0, PMDockWidget::DockDesktop, 50,
+ QPoint( ( *it ).floatingPositionX( ),
+ ( *it ).floatingPositionY( ) ) );
+ dock->resize( ( *it ).floatingWidth( ), ( *it ).floatingHeight( ) );
+ dock->show( );
+ }
+ else
+ {
+ // the first dockwidget is not docked but placed on all the window
+ // through setView( )
+ if( !isViewSet )
+ {
+ shell->setView( dock );
+ isViewSet = true;
+ lastWidget = dock;
+ }
+ else
+ {
+ switch( ( *it ).dockPosition( ) )
+ {
+ case PMDockWidget::DockRight:
+ dock->manualDock( lastWidget, ( *it ).dockPosition( ),
+ lastWidth * 100 / width );
+
+ width -= lastWidth;
+ if( width < 1 ) width = 1;
+ height = 100;
+ lastWidget = dock;
+ break;
+ case PMDockWidget::DockBottom:
+ dock->manualDock( lastWidget, ( *it ).dockPosition( ),
+ lastHeight * 100 / height );
+ height -= lastHeight;
+ if( height < 1 ) height = 1;
+ lastWidget = dock;
+ break;
+ case PMDockWidget::DockCenter:
+ dock->manualDock( lastWidget, ( *it ).dockPosition( ), 100 );
+ break;
+ default:
+ dock->manualDock( 0, PMDockWidget::DockDesktop, 100 );
+ break;
+ }
+ }
+
+ switch( ( *it ).dockPosition( ) )
+ {
+ case PMDockWidget::DockRight:
+ lastWidth = ( *it ).columnWidth( );
+ lastHeight = ( *it ).height( );
+ break;
+ case PMDockWidget::DockBottom:
+ lastHeight = ( *it ).height( );
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+void PMViewLayout::normalize( )
+{
+ iterator it;
+ int sumColWidth = 0;
+
+ it = m_entries.begin( );
+ // the first entry has to be a new column
+ if( it != m_entries.end( ) )
+ if( ( *it ).dockPosition( ) != PMDockWidget::DockRight )
+ ( *it ).setDockPosition( PMDockWidget::DockRight );
+
+ // find negative or zero widths and heights
+ for( it = m_entries.begin( ); it != m_entries.end( ); ++it )
+ {
+ if( ( *it ).columnWidth( ) < 1 )
+ ( *it ).setColumnWidth( 1 );
+ if( ( *it ).height( ) < 1 )
+ ( *it ).setHeight( 1 );
+ }
+
+ // normalize the column widths
+ for( it = m_entries.begin( ); it != m_entries.end( ); ++it )
+ if( ( *it ).dockPosition( ) == PMDockWidget::DockRight )
+ sumColWidth += ( *it ).columnWidth( );
+ if( sumColWidth == 0 )
+ sumColWidth = 1;
+
+ for( it = m_entries.begin( ); it != m_entries.end( ); ++it )
+ {
+ if( ( *it ).dockPosition( ) == PMDockWidget::DockRight )
+ {
+ ( *it ).setColumnWidth( ( int ) ( ( *it ).columnWidth( ) * 100.0
+ / sumColWidth + 0.5 ) );
+ // normalize each column
+ iterator it2 = it;
+ int height = ( *it ).height( );
+
+ for( it2++; it2 != m_entries.end( ) &&
+ ( *it2 ).dockPosition( ) != PMDockWidget::DockRight; ++it2 )
+ if( ( *it2 ).dockPosition( ) == PMDockWidget::DockBottom )
+ height += ( *it2 ).height( );
+ if( height == 0 )
+ height = 1;
+ ( *it ).setHeight( ( int ) ( ( *it ).height( ) * 100.0
+ / height + 0.5 ) );
+ it2 = it;
+ for( it2++; it2 != m_entries.end( ) &&
+ ( *it2 ).dockPosition( ) != PMDockWidget::DockRight; ++it2 )
+ if( ( *it2 ).dockPosition( ) == PMDockWidget::DockBottom )
+ ( *it2 ).setHeight( ( int ) ( ( *it2 ).height( ) * 100.0
+ / height + 0.5 ) );
+ }
+ }
+}
+
+PMViewLayout PMViewLayout::extractViewLayout( PMShell* shell )
+{
+ PMViewLayout layout;
+
+ QValueList< QValueList< PMViewLayoutEntry > > cols;
+ cols.append( QValueList< PMViewLayoutEntry >( ) );
+
+ // find docked widgets
+ recursiveExtractColumns( cols, cols.begin( ), 100,
+ shell->centralWidget( ) );
+
+ QValueListIterator< QValueList< PMViewLayoutEntry > > cit;
+ QValueListIterator< PMViewLayoutEntry > eit;
+
+ for( cit = cols.begin( ); cit != cols.end( ); ++cit )
+ for( eit = ( *cit ).begin( ); eit != ( *cit ).end( ); ++eit )
+ layout.addEntry( *eit );
+
+ // find floating widgets
+ QPtrList<PMDockWidget> list;
+ shell->manager( )->findFloatingWidgets( list );
+ QPtrListIterator<PMDockWidget> it( list );
+
+ for( ; it.current( ); ++it )
+ {
+ kdDebug( PMArea ) << it.current( ) << " " << it.current( )->isVisible( ) << endl;
+ QWidget* w = it.current( )->getWidget( );
+ if( w )
+ {
+ bool invalid = false;
+ PMViewLayoutEntry e;
+ e.setDockPosition( PMDockWidget::DockNone );
+ QPoint p = it.current( )->pos( );
+ e.setFloatingPositionX( p.x( ) );
+ e.setFloatingPositionY( p.y( ) );
+ e.setFloatingWidth( it.current( )->width( ) );
+ e.setFloatingHeight( it.current( )->height( ) );
+
+ if( w->inherits( "PMViewBase" ) )
+ {
+ PMViewBase* v = ( PMViewBase* ) w;
+ e.setViewType( v->viewType( ) );
+ PMViewOptions* vo =
+ PMViewFactory::theFactory( )->newOptionsInstance( v->viewType( ) );
+ if( vo )
+ {
+ v->saveViewConfig( vo );
+ e.setCustomOptions( vo );
+ }
+ }
+ else
+ invalid = true;
+
+ if( !invalid )
+ layout.addEntry( e );
+ }
+ }
+
+ return layout;
+}
+
+void PMViewLayout::recursiveExtractColumns(
+ QValueList< QValueList< PMViewLayoutEntry > >& cols,
+ QValueList< QValueList< PMViewLayoutEntry > >::iterator cit,
+ int width, QWidget* widget )
+{
+ if( !widget )
+ return;
+
+ if( widget->inherits( "PMDockWidget" ) )
+ {
+ PMDockWidget* dw = ( PMDockWidget* ) widget;
+ QWidget* w = dw->getWidget( );
+ if( w )
+ {
+ bool colStart = true;
+ if( w->inherits( "PMDockSplitter" ) )
+ {
+ PMDockSplitter* sp = ( PMDockSplitter* ) w;
+ if( sp->splitterOrientation( ) == Qt::Vertical )
+ {
+ colStart = false;
+ // vertical splitter, split up the current column
+ int w1 = ( int ) ( width * 0.01 * sp->separatorPos( ) + 0.5 );
+ int w2 = width - w1;
+ if( w1 == 0 ) w1++;
+ if( w2 == 0 ) w2++;
+
+ QValueList< QValueList< PMViewLayoutEntry > >::iterator cit1
+ = cols.insert( cit, QValueList< PMViewLayoutEntry >( ) );
+
+ recursiveExtractColumns( cols, cit1, w1, sp->getFirst( ) );
+ recursiveExtractColumns( cols, cit, w2, sp->getLast( ) );
+ }
+ }
+ if( colStart )
+ {
+ // widget is a view, a horizontal splitter or a tab widget
+ // a new column starts
+ PMViewLayoutEntry e;
+ e.setColumnWidth( width );
+ ( *cit ).append( e );
+ recursiveExtractOneColumn( *cit, ( *cit ).begin( ), 100, dw );
+ }
+ }
+ }
+}
+
+void PMViewLayout::recursiveExtractOneColumn(
+ QValueList< PMViewLayoutEntry >& entries,
+ QValueList< PMViewLayoutEntry >::iterator eit,
+ int height, QWidget* widget )
+{
+ if( !widget )
+ return;
+
+ if( widget->inherits( "PMDockWidget" ) )
+ {
+ PMDockWidget* dw = ( PMDockWidget* ) widget;
+ QWidget* w = dw->getWidget( );
+ if( w )
+ {
+ if( w->inherits( "PMDockSplitter" ) )
+ {
+ PMDockSplitter* sp = ( PMDockSplitter* ) w;
+ // splitter, split up the current column
+ int h1 = ( int ) ( height * 0.01 * sp->separatorPos( ) + 0.5 );
+ int h2 = height - h1;
+ if( h1 == 0 ) h1++;
+ if( h2 == 0 ) h2++;
+
+ ( *eit ).setHeight( h1 );
+ ( *eit ).setDockPosition( PMDockWidget::DockRight );
+
+ PMViewLayoutEntry e;
+ e.setHeight( h2 );
+ e.setDockPosition( PMDockWidget::DockBottom );
+ QValueList< PMViewLayoutEntry >::iterator eit1 = eit;
+ eit1 = entries.insert( ++eit1, e );
+
+ recursiveExtractOneColumn( entries, eit, h1, sp->getFirst( ) );
+ recursiveExtractOneColumn( entries, eit1, h2, sp->getLast( ) );
+ }
+ else if( w->inherits( "PMDockTabGroup" ) )
+ {
+ PMDockTabGroup* g = ( PMDockTabGroup* ) w;
+ int num = g->count( );
+ QWidget* tw;
+ int i;
+ for( i = 0; i < num; i++ )
+ {
+ tw = g->page( i );
+ if( i == 0 )
+ recursiveExtractOneColumn( entries, eit, height, tw );
+ else
+ {
+ PMViewLayoutEntry e;
+ e.setHeight( height );
+ e.setDockPosition( PMDockWidget::DockCenter );
+
+ eit++;
+ eit = entries.insert( eit, e );
+ recursiveExtractOneColumn( entries, eit, height, tw );
+ }
+ }
+ }
+ else
+ {
+ // a kpovmodeler view???
+ if( w->inherits( "PMViewBase" ) )
+ {
+ PMViewBase* v = ( PMViewBase* ) w;
+ ( *eit ).setViewType( v->viewType( ) );
+ PMViewOptions* vo =
+ PMViewFactory::theFactory( )->newOptionsInstance( v->viewType( ) );
+ if( vo )
+ {
+ v->saveViewConfig( vo );
+ ( *eit ).setCustomOptions( vo );
+ }
+ }
+ }
+ }
+ }
+}
+
+//=============== PMViewLayoutManager ===================
+
+PMViewLayoutManager::PMViewLayoutManager( )
+{
+ m_layoutsLoaded = false;
+ m_layoutDisplayed = false;
+ loadData( );
+}
+
+PMViewLayoutManager::~PMViewLayoutManager( )
+{
+}
+
+void PMViewLayoutManager::setDefaultLayout( const QString& name )
+{
+ m_defaultLayout = name;
+}
+
+QStringList PMViewLayoutManager::availableLayouts( )
+{
+ QStringList result;
+ QValueListIterator<PMViewLayout> it;
+
+ for( it = m_layouts.begin( ); it != m_layouts.end( ); ++it )
+ result.push_back( ( *it ).name( ) );
+
+ return result;
+}
+
+void PMViewLayoutManager::loadData( )
+{
+ if( m_layoutsLoaded )
+ m_layouts.clear( );
+
+ m_layoutsLoaded = true;
+
+ QString fileName = locate( "data", "kpovmodeler/viewlayouts.xml" );
+ if( fileName.isEmpty( ) )
+ {
+ // Generate a default layout
+ // I have a feeling this shouldn't be here but hey, it works for now
+ // TODO Must find a way to move this cleanly to PMShell
+ PMViewLayout a;
+ a.setName( i18n( "Default" ) );
+ PMViewLayoutEntry p;
+ p.setViewType( "treeview" );
+ p.setDockPosition( PMDockWidget::DockRight );
+ p.setHeight( 50 );
+ p.setColumnWidth( 33 );
+ a.addEntry( p );
+ p.setViewType( "dialogview" );
+ p.setDockPosition( PMDockWidget::DockBottom );
+ p.setHeight( 50 );
+ a.addEntry( p );
+ p.setViewType( "glview" );
+ p.setCustomOptions( new PMGLViewOptions( PMGLView::PMViewPosX ) );
+ p.setDockPosition( PMDockWidget::DockRight );
+ p.setHeight( 50 );
+ p.setColumnWidth( 33 );
+ a.addEntry( p );
+ p.setCustomOptions( new PMGLViewOptions( PMGLView::PMViewNegY ) );
+ p.setDockPosition( PMDockWidget::DockBottom );
+ p.setHeight( 50 );
+ a.addEntry( p );
+ p.setCustomOptions( new PMGLViewOptions( PMGLView::PMViewPosZ ) );
+ p.setDockPosition( PMDockWidget::DockRight );
+ p.setHeight( 50 );
+ p.setColumnWidth( 33 );
+ a.addEntry( p );
+ p.setCustomOptions( new PMGLViewOptions( PMGLView::PMViewCamera ) );
+ p.setDockPosition( PMDockWidget::DockBottom );
+ p.setHeight( 50 );
+ a.addEntry( p );
+
+ m_layouts.append( a );
+ m_defaultLayout = a.name( );
+
+ return;
+ }
+
+ QFile file( fileName );
+ if( !file.open( IO_ReadOnly ) )
+ {
+ kdError( PMArea ) << i18n( "Could not open the view layouts file." )
+ << endl;
+ return;
+ }
+
+ QDomDocument doc( "VIEWLAYOUTS" );
+ doc.setContent( &file );
+
+ QDomElement e = doc.documentElement( );
+ m_defaultLayout = e.attribute( "default", "empty" );
+
+ QDomNode c = e.firstChild( );
+
+ QString str;
+
+ while( !c.isNull( ) )
+ {
+ if( c.isElement( ) )
+ {
+ QDomElement ce = c.toElement( );
+ PMViewLayout v;
+ v.loadData( ce );
+ m_layouts.append( v );
+ }
+ c = c.nextSibling( );
+ }
+}
+
+void PMViewLayoutManager::saveData( )
+{
+ QString fileName = locateLocal( "data", "kpovmodeler/viewlayouts.xml" );
+ if( fileName.isEmpty( ) )
+ {
+ kdError( PMArea ) << i18n( "View layouts not found." ) << endl;
+ return;
+ }
+ QFile file( fileName );
+ if( !file.open( IO_WriteOnly ) )
+ {
+ kdError( PMArea ) << i18n( "Could not open the view layouts file." )
+ << endl;
+ return;
+ }
+ QDomDocument doc( "VIEWLAYOUTS" );
+ QDomElement e = doc.createElement( "viewlist" );
+ e.setAttribute( "default", m_defaultLayout );
+
+ QValueListIterator<PMViewLayout> it;
+
+ for( it = m_layouts.begin( ); it != m_layouts.end( ); ++it )
+ {
+ QDomElement l;
+
+ l = doc.createElement( "viewlayout" );
+ ( *it ).saveData( l, doc );
+ e.appendChild( l );
+ }
+ doc.appendChild( e );
+ QTextStream str( &file );
+ str.setEncoding( QTextStream::UnicodeUTF8 );
+ str << doc.toString( );
+ file.close( );
+}
+
+PMViewLayoutManager* PMViewLayoutManager::theManager( )
+{
+ if( !s_pInstance )
+ s_staticDeleter.setObject( s_pInstance, new PMViewLayoutManager( ) );
+ return s_pInstance;
+}
+
+void PMViewLayoutManager::displayLayout( const QString& name, PMShell* shell )
+{
+ PMViewLayout* v_layout = findLayout( name );
+
+ if( v_layout )
+ {
+ // Destroy the existing dock widgets
+ if( m_layoutDisplayed )
+ {
+ QWidgetList lst;
+
+ if( shell->centralWidget( ) )
+ shell->manager( )->findChildDockWidget( shell->centralWidget( ), lst );
+ while( lst.first( ) )
+ {
+ ( ( PMDockWidget* )lst.first( ) )->undock( );
+ ( ( PMDockWidget* )lst.first( ) )->close( );
+ lst.remove( );
+ }
+
+ QPtrList<PMDockWidget> flist;
+ shell->manager( )->findFloatingWidgets( flist );
+ while( flist.first( ) )
+ {
+ flist.first( )->undock( );
+ flist.first( )->close( );
+ flist.remove( );
+ }
+ }
+ // Create the new layout
+ v_layout->displayLayout( shell );
+ m_layoutDisplayed = true;
+ }
+}
+
+void PMViewLayoutManager::displayDefaultLayout( PMShell* shell )
+{
+ displayLayout( m_defaultLayout, shell );
+}
+
+PMViewLayout* PMViewLayoutManager::findLayout( const QString& name )
+{
+ QValueListIterator<PMViewLayout> it;
+ for( it = m_layouts.begin( ); it != m_layouts.end( ) &&
+ ( *it ).name( ) != name; ++it );
+
+ if( it == m_layouts.end( ) )
+ return 0;
+ return &( *it );
+}
+
+void PMViewLayoutManager::fillPopupMenu( KPopupMenu* pMenu )
+{
+ QStringList lst = availableLayouts( );
+ QStringList::ConstIterator it = lst.begin( );
+
+ pMenu->clear( );
+ if( it != lst.end( ) )
+ {
+ for( ; it != lst.end( ); ++it )
+ pMenu->insertItem( ( *it ) );
+ }
+}
+
+void PMViewLayoutManager::addLayout( const QString& name )
+{
+ PMViewLayout a;
+
+ if( m_layouts.isEmpty( ) )
+ m_defaultLayout = name;
+ a.setName( name );
+ m_layouts.append( a );
+}
+
+void PMViewLayoutManager::removeLayout( const QString& name )
+{
+ QValueListIterator<PMViewLayout> it;
+ for( it = m_layouts.begin( ); it != m_layouts.end( ) &&
+ ( *it ).name( ) != name; ++it );
+
+ if( it != m_layouts.end( ) )
+ m_layouts.remove( it );
+}
+
+
+PMSaveViewLayoutDialog::PMSaveViewLayoutDialog( PMShell* parent,
+ const char* name )
+ : KDialogBase( parent, name, true, i18n( "Save View Layout" ),
+ KDialogBase::Ok | KDialogBase::Cancel )
+{
+ m_pShell = parent;
+
+ setButtonOK( KStdGuiItem::save() );
+ enableButtonOK( false );
+
+ QWidget* w = new QWidget( this );
+ QVBoxLayout* vl = new QVBoxLayout( w, 0, KDialog::spacingHint( ) );
+
+ QLabel* l = new QLabel( i18n( "Enter view layout name:" ), w );
+ vl->addWidget( l );
+
+ m_pLayoutName = new QLineEdit( w );
+ vl->addWidget( m_pLayoutName );
+ connect( m_pLayoutName, SIGNAL( textChanged( const QString& ) ),
+ SLOT( slotNameChanged( const QString& ) ) );
+
+ QListBox* lb = new QListBox( w );
+ vl->addWidget( lb );
+ connect( lb, SIGNAL( highlighted( const QString& ) ),
+ SLOT( slotNameSelected( const QString& ) ) );
+ lb->insertStringList( PMViewLayoutManager::theManager( )
+ ->availableLayouts( ) );
+
+ setMainWidget( w );
+ setInitialSize( QSize( 300, 200 ) );
+}
+
+PMSaveViewLayoutDialog::~PMSaveViewLayoutDialog( )
+{
+}
+
+void PMSaveViewLayoutDialog::slotOk( )
+{
+ QString name = m_pLayoutName->text( );
+
+ PMViewLayoutManager* m = PMViewLayoutManager::theManager( );
+ PMViewLayout* layout = m->findLayout( name );
+
+ PMViewLayout newLayout = PMViewLayout::extractViewLayout( m_pShell );
+ newLayout.setName( name );
+
+ if( layout )
+ *layout = newLayout;
+ else
+ m->addLayout( newLayout );
+
+ m->saveData( );
+
+ KDialogBase::slotOk( );
+}
+
+void PMSaveViewLayoutDialog::slotNameChanged( const QString& s )
+{
+ enableButtonOK( !s.isEmpty( ) );
+}
+
+void PMSaveViewLayoutDialog::slotNameSelected( const QString& s )
+{
+ m_pLayoutName->setText( s );
+}
+
+#include "pmviewlayoutmanager.moc"
diff --git a/kpovmodeler/pmviewlayoutmanager.h b/kpovmodeler/pmviewlayoutmanager.h
new file mode 100644
index 00000000..c0246c5d
--- /dev/null
+++ b/kpovmodeler/pmviewlayoutmanager.h
@@ -0,0 +1,306 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+ copyright : (C) 2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMVIEWLAYOUTMANAGER_H
+#define PMVIEWLAYOUTMANAGER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qstring.h>
+#include <qmap.h>
+#include <qvaluelist.h>
+#include <kstaticdeleter.h>
+
+#include <kdialogbase.h>
+
+#include "pmdockwidget.h"
+#include "pmviewbase.h"
+
+class KConfig;
+class QDomElement;
+class QLineEdit;
+class PMShell;
+
+/**
+ * Class used internally by @ref PMViewLayout
+ *
+ * This class maintains all the information needed to create a docked view.
+ */
+class PMViewLayoutEntry
+{
+public:
+ /**
+ * Constructor
+ */
+ PMViewLayoutEntry( );
+ /**
+ * Copy constructor
+ */
+ PMViewLayoutEntry( const PMViewLayoutEntry& e );
+ /**
+ * Destructor
+ */
+ ~PMViewLayoutEntry( );
+
+ QString viewType( ) const { return m_viewType; }
+ void setViewType( const QString& vt );
+
+ PMDockWidget::DockPosition dockPosition( ) const { return m_dockPosition; }
+ void setDockPosition( PMDockWidget::DockPosition i );
+
+ int columnWidth( ) const { return m_columnWidth; }
+ void setColumnWidth( int i );
+
+ int height( ) const { return m_height; }
+ void setHeight( int i );
+
+ int floatingHeight( ) const { return m_floatingHeight; }
+ void setFloatingHeight( int h ) { m_floatingHeight = h; }
+
+ int floatingWidth( ) const { return m_floatingWidth; }
+ void setFloatingWidth( int w ) { m_floatingWidth = w; }
+
+ int floatingPositionX( ) const { return m_floatingPositionX; }
+ void setFloatingPositionX( int p ) { m_floatingPositionX = p; }
+ int floatingPositionY( ) const { return m_floatingPositionY; }
+ void setFloatingPositionY( int p ) { m_floatingPositionY = p; }
+
+ void loadData( QDomElement& e );
+ void saveData( QDomElement& e ) const;
+
+ PMViewOptions* customOptions( ) const { return m_pCustomOptions; }
+ void setCustomOptions( PMViewOptions* o );
+
+ const QString dockPositionAsString( );
+ const QString viewTypeAsString( );
+
+private:
+ QString m_viewType;
+ PMDockWidget::DockPosition m_dockPosition;
+ int m_columnWidth;
+ int m_height;
+ int m_floatingWidth;
+ int m_floatingHeight;
+ int m_floatingPositionX;
+ int m_floatingPositionY;
+ PMViewOptions* m_pCustomOptions;
+};
+
+/**
+ * Class used internally by @ref PMViewLayoutManager
+ *
+ * This class maintains a named layout. It basically stores all views
+ * associated with that layout.
+ */
+class PMViewLayout
+{
+public:
+ typedef QValueList< PMViewLayoutEntry >::iterator iterator;
+ /**
+ * Constructor
+ */
+ PMViewLayout( );
+ /**
+ * Copy constructor
+ */
+ PMViewLayout( const PMViewLayout& vl );
+ /**
+ * Destructor
+ */
+ ~PMViewLayout( ) { }
+
+ /**
+ * Assignment operator
+ */
+ PMViewLayout& operator = ( const PMViewLayout& vl );
+
+ QString name( ) const { return m_name; }
+
+ void loadData( QDomElement& e );
+
+ void saveData( QDomElement& e, QDomDocument& doc ) const;
+ /**
+ * Destroy all dock widgets in PMShell and create the new ones
+ */
+ void displayLayout( PMShell* shell );
+ /**
+ * Sets the name of the layout
+ */
+ void setName( const QString& n );
+ /**
+ *
+ * Add a new entry to the layout. By default it adds the entry at the end
+ * of the list. If a position is given it adds the entry at the indicated
+ * position
+ */
+ void addEntry( const PMViewLayoutEntry& e, int index = -1 );
+ /**
+ * Removes the entry at the given position
+ */
+ void removeEntry( int index );
+ /**
+ * Returns an iterator to the first entry
+ */
+ iterator begin( ) { return m_entries.begin( ); }
+ /**
+ * Returns an iterator to the last entry
+ */
+ iterator end( ) { return m_entries.end( ); }
+ /**
+ * Returns an iterator to the n-th entry
+ */
+ iterator at( int i ) { return m_entries.at( i ); }
+ /**
+ * Returns the entry at the given position
+ */
+ PMViewLayoutEntry& operator[]( int index ) { return m_entries[ index ]; }
+ /**
+ * Normalizes the column width and view heights
+ */
+ void normalize( );
+
+ /**
+ * Extracts the view layout from the current window
+ */
+ static PMViewLayout extractViewLayout( PMShell* shell );
+private:
+ static void recursiveExtractColumns(
+ QValueList< QValueList< PMViewLayoutEntry > >& cols,
+ QValueList< QValueList< PMViewLayoutEntry > >::iterator cit,
+ int width, QWidget* widget );
+
+ static void recursiveExtractOneColumn(
+ QValueList< PMViewLayoutEntry >& entries,
+ QValueList< PMViewLayoutEntry >::iterator eit,
+ int height, QWidget* widget );
+
+ QString m_name;
+ QValueList< PMViewLayoutEntry > m_entries;
+};
+
+/**
+ * Singleton that contains the view layouts available.
+ *
+ * It interacts with @ref PMShell to create the view layouts.
+ * The class maintains a list of layouts as well as the name of the default
+ * layout. The layouts are stored in a XML file caled viewlayouts.xml.
+ */
+class PMViewLayoutManager
+{
+public:
+ /**
+ * Destructor
+ */
+ ~PMViewLayoutManager( );
+ /**
+ * Returns the manager instance (singleton)
+ */
+ static PMViewLayoutManager* theManager( );
+
+ /**
+ * Returns the list of available view layouts
+ */
+ QStringList availableLayouts( );
+ /**
+ * Sets the default layout
+ */
+ void setDefaultLayout( const QString& name );
+ /**
+ * Returns the default layout
+ */
+ QString defaultLayout( ) const { return m_defaultLayout; }
+ /**
+ * Destroy all dock widgets in PMShell and create the new ones
+ */
+ void displayLayout( const QString& name, PMShell* shell );
+ /**
+ * Displays the layout indicated as default
+ */
+ void displayDefaultLayout( PMShell* shell );
+ /**
+ * Loads all layouts from the configuration file
+ */
+ void loadData( );
+ /**
+ * Saves the current layout collection to the configuration file
+ */
+ void saveData( );
+ /**
+ * Add a new empty layout
+ */
+ void addLayout( const QString& name );
+ /**
+ * Add a new layout
+ */
+ void addLayout( const PMViewLayout& l ) { m_layouts.append( l ); }
+ /**
+ * Remove a layout
+ */
+ void removeLayout( const QString& name );
+ /**
+ * Get a known layout
+ */
+ PMViewLayout* findLayout( const QString& name );
+ /**
+ * Returns the list of available layouts
+ */
+ QValueList<PMViewLayout> layouts( ) { return m_layouts; }
+ /**
+ * Sets the list of available layouts
+ */
+ void setLayouts( const QValueList<PMViewLayout>& l ) { m_layouts = l; }
+ /**
+ * Fill the available layouts menu
+ */
+ void fillPopupMenu( KPopupMenu* pMenu );
+private:
+ /**
+ * Constructor
+ */
+ PMViewLayoutManager( );
+
+ bool m_layoutsLoaded;
+ bool m_layoutDisplayed;
+ QString m_defaultLayout;
+ QValueList< PMViewLayout > m_layouts;
+
+ static PMViewLayoutManager* s_pInstance;
+ static KStaticDeleter<PMViewLayoutManager> s_staticDeleter;
+};
+
+
+class PMSaveViewLayoutDialog : public KDialogBase
+{
+ Q_OBJECT
+public:
+ PMSaveViewLayoutDialog( PMShell* parent, const char* name = 0 );
+ ~PMSaveViewLayoutDialog( );
+protected slots:
+ virtual void slotOk( );
+ void slotNameChanged( const QString& );
+ void slotNameSelected( const QString& );
+private:
+ QLineEdit* m_pLayoutName;
+ PMShell* m_pShell;
+};
+
+#endif
diff --git a/kpovmodeler/pmviewstructure.cpp b/kpovmodeler/pmviewstructure.cpp
new file mode 100644
index 00000000..966df90b
--- /dev/null
+++ b/kpovmodeler/pmviewstructure.cpp
@@ -0,0 +1,127 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#include "pmviewstructure.h"
+
+/*
+void PMViewStructure::render( )
+{
+ glVertexPointer( 3, GL_DOUBLE, sizeof( PMVector ), points.data( ) );
+ glDrawElements( GL_LINES, lines.size( ) * 2,
+ GL_UNSIGNED_INT, lines.data( ) );
+}
+*/
+
+PMViewStructure::PMViewStructure( )
+{
+ m_parameterKey = -1;
+}
+
+PMViewStructure::PMViewStructure( unsigned int n, unsigned int l, unsigned int f )
+{
+ m_points.resize( n );
+ m_lines.resize( l );
+ m_faces.resize( f );
+ m_parameterKey = -1;
+}
+
+PMViewStructure::PMViewStructure( const PMViewStructure& vs )
+{
+ m_points = vs.m_points;
+ m_lines = vs.m_lines;
+ m_faces = vs.m_faces;
+ m_parameterKey = vs.m_parameterKey;
+}
+
+PMViewStructure::PMViewStructure( const PMViewStructure* vs )
+{
+ m_points = vs->m_points;
+ m_lines = vs->m_lines;
+ m_faces = vs->m_faces;
+ m_parameterKey = vs->m_parameterKey;
+}
+
+PMViewStructure& PMViewStructure::operator = ( const PMViewStructure& vs )
+{
+ m_lines = vs.m_lines;
+ m_points = vs.m_points;
+ m_faces = vs.m_faces;
+
+ return *this;
+}
+
+bool PMViewStructure::operator == ( const PMViewStructure& vs ) const
+{
+ return ( ( m_lines.data( ) == vs.m_lines.data( ) )
+ && ( m_points.data( ) == vs.m_points.data( ) )
+ && ( m_faces == vs.m_faces ) );
+}
+
+bool PMViewStructure::operator != ( const PMViewStructure& vs ) const
+{
+ return ( ( m_lines.data( ) != vs.m_lines.data( ) )
+ || ( m_points.data( ) != vs.m_points.data( ) )
+ || !( m_faces == vs.m_faces ) );
+}
+
+
+PMBoundingBox::PMBoundingBox( const PMVector& min, const PMVector& max )
+{
+ m_bValid = true;
+ m_min = min;
+ m_max = max;
+}
+
+PMBoundingBox::PMBoundingBox( )
+{
+ m_bValid = false;
+ m_min = PMVector( 0.0, 0.0, 0.0 );
+ m_max = PMVector( 0.0, 0.0, 0.0 );
+}
+
+void PMBoundingBox::mergeWith( const PMBoundingBox& box )
+{
+ if( m_bValid )
+ {
+ if( box.m_bValid )
+ {
+ if( box.m_min.x( ) < m_min.x( ) )
+ m_min.setX( box.m_min.x( ) );
+ if( box.m_min.y( ) < m_min.y( ) )
+ m_min.setY( box.m_min.y( ) );
+ if( box.m_min.z( ) < m_min.z( ) )
+ m_min.setZ( box.m_min.z( ) );
+
+ if( box.m_max.x( ) > m_max.x( ) )
+ m_max.setX( box.m_max.x( ) );
+ if( box.m_max.y( ) > m_max.y( ) )
+ m_max.setY( box.m_max.y( ) );
+ if( box.m_max.z( ) > m_max.z( ) )
+ m_max.setZ( box.m_max.z( ) );
+ }
+ }
+ else
+ {
+ if( box.m_bValid )
+ {
+ m_bValid = true;
+ m_max = box.m_max;
+ m_min = box.m_min;
+ }
+ }
+}
diff --git a/kpovmodeler/pmviewstructure.h b/kpovmodeler/pmviewstructure.h
new file mode 100644
index 00000000..5356466b
--- /dev/null
+++ b/kpovmodeler/pmviewstructure.h
@@ -0,0 +1,222 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMVIEWSTRUCTURE_H
+#define PMVIEWSTRUCTURE_H
+
+#include "pmface.h"
+#include "pmpoint.h"
+#include "pmline.h"
+#include "pmmatrix.h"
+#include "pmobject.h"
+#include "pmvector.h"
+
+/**
+ * Represents the view structure (points, lines, faces) of an object
+ *
+ * Faces are not implemented yet but are needed later to calculate the view
+ * structure of csg objects
+ */
+
+class PMViewStructure
+{
+ friend class PMObject;
+public:
+ /**
+ * Creates an empty view structure
+ */
+ PMViewStructure( );
+ /**
+ * Creates a view structure with n points, l lines and f faces.
+ */
+ PMViewStructure( unsigned int n, unsigned int l, unsigned int f = 0 );
+ /**
+ * Creates a copy of the view structure. m_points, m_lines and m_faces are shared
+ */
+ PMViewStructure( const PMViewStructure& vs );
+ /**
+ * Creates a copy of the view structure. m_points, m_lines anf m_faces are shared
+ */
+ PMViewStructure( const PMViewStructure* vs );
+
+ /**
+ * Returns a reference to the array of points
+ */
+ PMPointArray& points( ) { return m_points; }
+ /**
+ * Returns a reference to the array of lines
+ */
+ PMLineArray& lines( ) { return m_lines; }
+ /**
+ * Returns a refrence to the array of faces
+ */
+ PMFaceArray& faces( ) { return m_faces; }
+ /**
+ * Returns the parameter key
+ */
+ int parameterKey( ) const { return m_parameterKey; }
+ /**
+ * Sets the parameter key
+ */
+ void setParameterKey( int k ) { m_parameterKey = k; }
+
+ /**
+ * Assigns the view structure to this view structure.
+ * The points and lines are shared
+ */
+ PMViewStructure& operator = ( const PMViewStructure& vs );
+ /**
+ * Returns true if the view structures share the same points and lines
+ */
+ bool operator == ( const PMViewStructure& vs ) const;
+ /**
+ * Returns false if the view structures share the same points and lines
+ */
+ bool operator != ( const PMViewStructure& vs ) const;
+protected:
+ /**
+ * Not transformed points, can be shared between PMObjects
+ * of the same type. m_points.data( ) can be used as vertex array.
+ *
+ * Optimized for fast rendering.
+ */
+ PMPointArray m_points;
+ /**
+ * Lines to display. m_lines.data( ) can be used by glDrawElements.
+ *
+ * Optimized for fast rendering.
+ */
+ PMLineArray m_lines;
+ /**
+ * Faces to display.
+ */
+ PMFaceArray m_faces;
+ /**
+ * View structure parameter key.
+ *
+ * Each class can have parameters that modifies the number of lines and
+ * points of a view structure (detail level).
+ *
+ * The framework determines if the view structure is up to date by
+ * comparing the key with the parameter key of the corresponding class.
+ */
+ int m_parameterKey;
+};
+
+/**
+ * Class for bounding boxes of PMObjects
+ */
+class PMBoundingBox
+{
+public:
+ /**
+ * Creates a bounding box with min and max vectors
+ */
+ PMBoundingBox( const PMVector& min, const PMVector& max );
+ /**
+ * Creates an invalid bounding box. @ref PMObject::boundingBox() returns
+ * an invalid bounding box, if the object has none.
+ */
+ PMBoundingBox( );
+
+ /**
+ * Returns the minimum coordinates
+ */
+ PMVector min( ) const { return m_min; }
+ /**
+ * Returns the maximum coordinates
+ */
+ PMVector max( ) const { return m_max; }
+ /**
+ * Returns the minumum x coordinate
+ */
+ double minX( ) const { return m_min.x( ); }
+ /**
+ * Returns the minumum y coordinate
+ */
+ double minY( ) const { return m_min.y( ); }
+ /**
+ * Returns the minumum z coordinate
+ */
+ double minZ( ) const { return m_min.z( ); }
+ /**
+ * Returns the maximum x coordinate
+ */
+ double maxX( ) const { return m_max.x( ); }
+ /**
+ * Returns the maximum y coordinate
+ */
+ double maxY( ) const { return m_max.y( ); }
+ /**
+ * Returns the maximum z coordinate
+ */
+ double maxZ( ) const { return m_max.z( ); }
+ /**
+ * Sets the minimum coordinates
+ */
+ void setMin( const PMVector& min ) { m_min = min; }
+ /**
+ * Sets the maximum coordinates
+ */
+ void setMax( const PMVector& max ) { m_max = max; }
+ /**
+ * Sets the minimum x coordinate
+ */
+ void setMinX( const double c ) { m_min.setX( c ); }
+ /**
+ * Sets the minimum y coordinate
+ */
+ void setMinY( const double c ) { m_min.setY( c ); }
+ /**
+ * Sets the minimum z coordinate
+ */
+ void setMinZ( const double c ) { m_min.setZ( c ); }
+ /**
+ * Sets the maximum x coordinate
+ */
+ void setMaxX( const double c ) { m_max.setX( c ); }
+ /**
+ * Sets the maximum y coordinate
+ */
+ void setMaxY( const double c ) { m_max.setY( c ); }
+ /**
+ * Sets the maximum z coordinate
+ */
+ void setMaxZ( const double c ) { m_max.setZ( c ); }
+
+ /**
+ * Returns true, if the bounding box is valid
+ */
+ bool isValid( ) const { return m_bValid; }
+ /**
+ * Sets the valid flag to v
+ */
+ void setValid( bool v ) { m_bValid = v; }
+
+ /**
+ * Merges the two bounding boxes
+ */
+ void mergeWith( const PMBoundingBox& box );
+
+private:
+ bool m_bValid;
+ PMVector m_min, m_max;
+};
+
+#endif
diff --git a/kpovmodeler/pmwarp.cpp b/kpovmodeler/pmwarp.cpp
new file mode 100644
index 00000000..76d58cf3
--- /dev/null
+++ b/kpovmodeler/pmwarp.cpp
@@ -0,0 +1,548 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+#include "pmxmlhelper.h"
+#include "pmvector.h"
+#include "pmwarp.h"
+#include "pmwarpedit.h"
+#include "pmmemento.h"
+#include "pmenumproperty.h"
+
+#include <klocale.h>
+
+const PMVector directionDefault = PMVector( 1.0, 0.0, 0.0 );
+const PMVector offsetDefault = PMVector( 0.0, 0.0, 0.0 );
+const PMVector flipDefault = PMVector( 0.0, 0.0, 0.0 );
+const PMVector locationDefault = PMVector( 0.0, 0.0, 0.0 );
+const double radiusDefault = 0;
+const double strengthDefault = 0;
+const double falloffDefault = 0;
+const bool inverseDefault = false;
+const PMVector repeatDefault = PMVector( 0.0, 0.0, 0.0 );
+const PMVector turbulenceDefault = PMVector( 0.0, 0.0, 0.0 );
+const PMVector valueVectorDefault = PMVector( 0.0, 0.0, 0.0 );
+const int octavesDefault = 6;
+const double omegaDefault = 0.5;
+const double lambdaDefault = 2.0;
+const PMVector orientationDefault = PMVector( 0.0, 0.0, 1.0 );
+const double distExpDefault = 0.0;
+const double majorRadiusDefault = 1.0;
+
+PMDefinePropertyClass( PMWarp, PMWarpProperty );
+PMDefineEnumPropertyClass( PMWarp, PMWarp::PMWarpType, PMWarpTypeProperty );
+
+PMMetaObject* PMWarp::s_pMetaObject = 0;
+PMObject* createNewWarp( PMPart* part )
+{
+ return new PMWarp( part );
+}
+
+PMWarp::PMWarp( PMPart* part )
+ : Base( part )
+{
+ m_warpType = PMWarp::Repeat;
+ m_direction = directionDefault;
+ m_offset = offsetDefault;
+ m_flip = flipDefault;
+ m_location = locationDefault;
+ m_radius = radiusDefault;
+ m_strength = strengthDefault;
+ m_falloff = falloffDefault;
+ m_inverse = inverseDefault;
+ m_repeat = repeatDefault;
+ m_turbulence = turbulenceDefault;
+ m_valueVector = valueVectorDefault;
+ m_octaves = octavesDefault;
+ m_omega = omegaDefault;
+ m_lambda = lambdaDefault;
+ m_orientation = orientationDefault;
+ m_distExp = distExpDefault;
+ m_majorRadius = majorRadiusDefault;
+}
+
+PMWarp::PMWarp( const PMWarp& w )
+ : Base( w )
+{
+ m_warpType = w.m_warpType;
+ m_direction = w.m_direction;
+ m_offset = w.m_offset;
+ m_flip = w.m_flip;
+ m_location = w.m_location;
+ m_radius = w.m_radius;
+ m_strength = w.m_strength;
+ m_falloff = w.m_falloff;
+ m_inverse = w.m_inverse;
+ m_repeat = w.m_repeat;
+ m_turbulence = w.m_turbulence;
+ m_valueVector = w.m_valueVector;
+ m_octaves = w.m_octaves;
+ m_omega = w.m_omega;
+ m_lambda = w.m_lambda;
+ m_orientation = w.m_orientation;
+ m_distExp = w.m_distExp;
+ m_majorRadius = w.m_majorRadius;
+}
+
+PMWarp::~PMWarp( )
+{
+}
+
+QString PMWarp::description( ) const
+{
+ return i18n( "warp" );
+}
+
+void PMWarp::serialize( QDomElement& e, QDomDocument& /*doc*/ ) const
+{
+ bool mapping = false;
+
+ switch( m_warpType )
+ {
+ case PMWarp::Repeat:
+ e.setAttribute( "warp_type", "repeat");
+ e.setAttribute( "direction", m_direction.serializeXML( ) );
+ e.setAttribute( "offset", m_offset.serializeXML( ) );
+ e.setAttribute( "flip", m_flip.serializeXML( ) );
+ break;
+ case PMWarp::BlackHole:
+ e.setAttribute( "warp_type", "black hole");
+ e.setAttribute( "location", m_location.serializeXML( ) );
+ e.setAttribute( "radius", m_radius );
+ e.setAttribute( "strength", m_strength );
+ e.setAttribute( "falloff", m_falloff );
+ e.setAttribute( "inverse", m_inverse );
+ e.setAttribute( "repeat", m_repeat.serializeXML( ) );
+ e.setAttribute( "turbulence", m_turbulence.serializeXML( ) );
+ break;
+ case PMWarp::Turbulence:
+ e.setAttribute( "warp_type", "turbulence");
+ e.setAttribute( "turbulence", m_valueVector.serializeXML( ) );
+ e.setAttribute( "octaves", m_octaves );
+ e.setAttribute( "omega", m_omega );
+ e.setAttribute( "lambda", m_lambda );
+ break;
+ case PMWarp::Cylindrical:
+ mapping = true;
+ e.setAttribute( "warp_type", "cylindrical" );
+ break;
+ case PMWarp::Spherical:
+ mapping = true;
+ e.setAttribute( "warp_type", "spherical" );
+ break;
+ case PMWarp::Toroidal:
+ mapping = true;
+ e.setAttribute( "warp_type", "toroidal" );
+ e.setAttribute( "major_radius", m_majorRadius );
+ break;
+ case PMWarp::Planar:
+ mapping = true;
+ e.setAttribute( "warp_type", "planar" );
+ break;
+ }
+
+ if ( mapping )
+ {
+ e.setAttribute( "orientation", m_orientation.serializeXML( ) );
+ e.setAttribute( "dist_exp", m_distExp );
+ }
+}
+
+void PMWarp::readAttributes( const PMXMLHelper& h )
+{
+ bool mapping = false;
+ QString str = h.stringAttribute( "warp_type", "repeat" );
+
+ if( str == "repeat" )
+ {
+ m_warpType = PMWarp::Repeat;
+ m_direction = h.vectorAttribute( "direction", directionDefault );
+ m_offset = h.vectorAttribute( "offset", offsetDefault );
+ m_flip = h.vectorAttribute( "flip", flipDefault );
+ }
+ else if( str == "black hole" )
+ {
+ m_warpType = PMWarp::BlackHole;
+ m_location = h.vectorAttribute( "location", locationDefault );
+ m_radius = h.doubleAttribute( "radius", radiusDefault );
+ m_strength = h.doubleAttribute( "strength", strengthDefault );
+ m_falloff = h.doubleAttribute( "falloff", falloffDefault );
+ m_inverse = h.boolAttribute( "inverse", inverseDefault );
+ m_repeat = h.vectorAttribute( "repeat", repeatDefault );
+ m_turbulence = h.vectorAttribute( "turbulence", turbulenceDefault );
+ }
+ else if( str == "turbulence" )
+ {
+ m_warpType = PMWarp::Turbulence;
+ m_valueVector = h.vectorAttribute( "turbulence", valueVectorDefault );
+ m_octaves = h.intAttribute( "octaves", octavesDefault );
+ m_omega = h.doubleAttribute( "omega", omegaDefault );
+ m_lambda = h.doubleAttribute( "lambda", lambdaDefault );
+ }
+ else if( str == "cylindrical" )
+ {
+ mapping = true;
+ m_warpType = PMWarp::Cylindrical;
+ }
+ else if( str == "spherical" )
+ {
+ mapping = true;
+ m_warpType = PMWarp::Spherical;
+ }
+ else if( str == "toroidal" )
+ {
+ mapping = true;
+ m_warpType = PMWarp::Toroidal;
+ m_majorRadius = h.doubleAttribute( "major_radius", majorRadiusDefault );
+ }
+ else if( str == "planar" )
+ {
+ mapping = true;
+ m_warpType = PMWarp::Planar;
+ }
+
+ if( mapping )
+ {
+ m_orientation = h.vectorAttribute( "orientation", orientationDefault );
+ m_distExp = h.doubleAttribute( "dist_exp", distExpDefault );
+ }
+}
+
+PMMetaObject* PMWarp::metaObject( ) const
+{
+ if( !s_pMetaObject )
+ {
+ s_pMetaObject = new PMMetaObject( "Warp", Base::metaObject( ),
+ createNewWarp );
+
+ PMWarpTypeProperty* p = new PMWarpTypeProperty(
+ "warpType", &PMWarp::setWarpType, &PMWarp::warpType );
+ p->addEnumValue( "Repeat", Repeat );
+ p->addEnumValue( "BlackHole", BlackHole );
+ p->addEnumValue( "Turbulence", Turbulence );
+ p->addEnumValue( "Cylindrical", Cylindrical );
+ p->addEnumValue( "Spherical", Spherical );
+ p->addEnumValue( "Toroidal", Toroidal );
+ p->addEnumValue( "Planar", Planar );
+ s_pMetaObject->addProperty( p );
+
+ s_pMetaObject->addProperty(
+ new PMWarpProperty( "direction", &PMWarp::setDirection, &PMWarp::direction ) );
+ s_pMetaObject->addProperty(
+ new PMWarpProperty( "offset", &PMWarp::setOffset, &PMWarp::offset ) );
+ s_pMetaObject->addProperty(
+ new PMWarpProperty( "flip", &PMWarp::setFlip, &PMWarp::flip ) );
+ s_pMetaObject->addProperty(
+ new PMWarpProperty( "location", &PMWarp::setLocation, &PMWarp::location ) );
+ s_pMetaObject->addProperty(
+ new PMWarpProperty( "radius", &PMWarp::setRadius, &PMWarp::radius ) );
+ s_pMetaObject->addProperty(
+ new PMWarpProperty( "strength", &PMWarp::setStrength, &PMWarp::strength ) );
+ s_pMetaObject->addProperty(
+ new PMWarpProperty( "falloff", &PMWarp::setFalloff, &PMWarp::falloff ) );
+ s_pMetaObject->addProperty(
+ new PMWarpProperty( "inverse", &PMWarp::setInverse, &PMWarp::inverse ) );
+ s_pMetaObject->addProperty(
+ new PMWarpProperty( "repeat", &PMWarp::setRepeat, &PMWarp::repeat ) );
+ s_pMetaObject->addProperty(
+ new PMWarpProperty( "turbulence", &PMWarp::setTurbulence, &PMWarp::turbulence ) );
+ s_pMetaObject->addProperty(
+ new PMWarpProperty( "valueVector", &PMWarp::setValueVector, &PMWarp::valueVector ) );
+ s_pMetaObject->addProperty(
+ new PMWarpProperty( "octaves", &PMWarp::setOctaves, &PMWarp::octaves ) );
+ s_pMetaObject->addProperty(
+ new PMWarpProperty( "omega", &PMWarp::setOmega, &PMWarp::omega ) );
+ s_pMetaObject->addProperty(
+ new PMWarpProperty( "lambda", &PMWarp::setLambda, &PMWarp::lambda ) );
+ s_pMetaObject->addProperty(
+ new PMWarpProperty( "orientation", &PMWarp::setOrientation, &PMWarp::orientation ) );
+ s_pMetaObject->addProperty(
+ new PMWarpProperty( "dist_exp", &PMWarp::setDistExp, &PMWarp::distExp ) );
+ s_pMetaObject->addProperty(
+ new PMWarpProperty( "major_radius", &PMWarp::setMajorRadius, &PMWarp::majorRadius ) );
+ }
+ return s_pMetaObject;
+}
+
+void PMWarp::cleanUp( ) const
+{
+ if( s_pMetaObject )
+ {
+ delete s_pMetaObject;
+ s_pMetaObject = 0;
+ }
+ Base::cleanUp( );
+}
+
+void PMWarp::setWarpType( PMWarpType c )
+{
+ if( c != m_warpType )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMWarpTypeID, m_warpType );
+ m_warpType = c;
+ }
+}
+
+void PMWarp::setDirection( const PMVector& c )
+{
+ if( c != m_direction )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMDirectionID, m_direction );
+ m_direction = c;
+ }
+}
+
+void PMWarp::setOffset( const PMVector& c )
+{
+ if( c != m_offset )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMOffsetID, m_offset );
+ m_offset = c;
+ }
+}
+
+void PMWarp::setFlip( const PMVector& c )
+{
+ if( c != m_flip )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFlipID, m_flip );
+ m_flip = c;
+ }
+}
+
+void PMWarp::setLocation( const PMVector& c )
+{
+ if( c != m_location )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMLocationID, m_location );
+ m_location = c;
+ }
+}
+
+void PMWarp::setRadius( const double c )
+{
+ if( c != m_radius )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMRadiusID, m_radius );
+ m_radius = c;
+ }
+}
+
+void PMWarp::setStrength( const double c )
+{
+ if( c != m_strength )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMStrengthID, m_strength );
+ m_strength = c;
+ }
+}
+
+void PMWarp::setFalloff( const double c )
+{
+ if( c != m_falloff )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMFalloffID, m_falloff );
+ m_falloff = c;
+ }
+}
+
+void PMWarp::setInverse( const bool c )
+{
+ if( c != m_inverse )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMInverseID, m_inverse );
+ m_inverse = c;
+ }
+}
+
+void PMWarp::setRepeat( const PMVector& c )
+{
+ if( c != m_repeat )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMRepeatID, m_repeat );
+ m_repeat = c;
+ }
+}
+
+void PMWarp::setTurbulence( const PMVector& c )
+{
+ if( c != m_turbulence )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMTurbulenceID, m_turbulence );
+ m_turbulence = c;
+ }
+}
+
+void PMWarp::setValueVector( const PMVector& c )
+{
+ if( c != m_valueVector )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMValueVectorID, m_valueVector );
+ m_valueVector = c;
+ }
+}
+
+void PMWarp::setOctaves( const int c )
+{
+ if( c != m_octaves )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMOctavesID, m_octaves );
+ m_octaves = c;
+ }
+}
+
+void PMWarp::setOmega( const double c )
+{
+ if( c != m_omega )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMOmegaID, m_omega );
+ m_omega = c;
+ }
+}
+
+void PMWarp::setLambda( const double c )
+{
+ if( c != m_lambda )
+ {
+ if( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMLambdaID, m_lambda );
+ m_lambda = c;
+ }
+}
+
+void PMWarp::setOrientation( const PMVector& v )
+{
+ if ( v != m_orientation )
+ {
+ if ( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMOrientationID, m_orientation );
+ m_orientation = v;
+ }
+}
+
+void PMWarp::setDistExp( const double c )
+{
+ if ( c != m_distExp )
+ {
+ if ( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMDistExpID, m_distExp );
+ m_distExp = c;
+ }
+}
+
+void PMWarp::setMajorRadius( const double c )
+{
+ if ( c != m_majorRadius )
+ {
+ if ( m_pMemento )
+ m_pMemento->addData( s_pMetaObject, PMMajorRadiusID, m_majorRadius );
+ m_majorRadius = c;
+ }
+}
+
+PMDialogEditBase* PMWarp::editWidget( QWidget* parent ) const
+{
+ return new PMWarpEdit( parent );
+}
+
+void PMWarp::restoreMemento( PMMemento* s )
+{
+ PMMementoDataIterator it( s );
+ PMMementoData* data;
+
+ for( ; it.current( ); ++it )
+ {
+ data = it.current( );
+ if( data->objectType( ) == s_pMetaObject )
+ {
+ switch( data->valueID( ) )
+ {
+ case PMWarpTypeID:
+ setWarpType( ( PMWarpType )data->intData( ) );
+ break;
+ case PMDirectionID:
+ setDirection( data->vectorData( ) );
+ break;
+ case PMOffsetID:
+ setOffset( data->vectorData( ) );
+ break;
+ case PMFlipID:
+ setFlip( data->vectorData( ) );
+ break;
+ case PMLocationID:
+ setLocation( data->vectorData( ) );
+ break;
+ case PMRadiusID:
+ setRadius( data->doubleData( ) );
+ break;
+ case PMStrengthID:
+ setStrength( data->doubleData( ) );
+ break;
+ case PMFalloffID:
+ setFalloff( data->doubleData( ) );
+ break;
+ case PMInverseID:
+ setInverse( data->boolData( ) );
+ break;
+ case PMRepeatID:
+ setRepeat( data->vectorData( ) );
+ break;
+ case PMTurbulenceID:
+ setTurbulence( data->vectorData( ) );
+ break;
+ case PMValueVectorID:
+ setValueVector( data->vectorData( ) );
+ break;
+ case PMOctavesID:
+ setOctaves( data->intData( ) );
+ break;
+ case PMOmegaID:
+ setOmega( data->doubleData( ) );
+ break;
+ case PMLambdaID:
+ setLambda( data->doubleData( ) );
+ break;
+ case PMOrientationID:
+ setOrientation( data->vectorData( ) );
+ break;
+ case PMDistExpID:
+ setDistExp( data->doubleData( ) );
+ break;
+ case PMMajorRadiusID:
+ setMajorRadius( data->doubleData( ) );
+ break;
+ default:
+ kdError( PMArea ) << "Wrong ID in PMWarp::restoreMemento\n";
+ break;
+ }
+ }
+ }
+ Base::restoreMemento( s );
+}
diff --git a/kpovmodeler/pmwarp.h b/kpovmodeler/pmwarp.h
new file mode 100644
index 00000000..a6ed213b
--- /dev/null
+++ b/kpovmodeler/pmwarp.h
@@ -0,0 +1,162 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMWARP_H
+#define PMWARP_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmobject.h"
+
+/**
+ * Class for Repeat Warps
+ */
+
+class PMWarp : public PMObject
+{
+ typedef PMObject Base;
+public:
+ enum PMWarpType { Repeat, BlackHole, Turbulence,
+ Cylindrical, Spherical, Toroidal, Planar };
+
+ /**
+ * Creates a PMWarp
+ */
+ PMWarp( PMPart* part );
+ /**
+ * Copy constructor
+ */
+ PMWarp( const PMWarp& w );
+ /**
+ * deletes the PMWarp
+ */
+ virtual ~PMWarp( );
+
+ /** */
+ virtual PMObject* copy( ) const { return new PMWarp( *this ); }
+ /** */
+ virtual QString description( ) const;
+
+ /** */
+ virtual PMMetaObject* metaObject( ) const;
+ /** */
+ virtual void cleanUp( ) const;
+
+ /** */
+ virtual void serialize( QDomElement& e, QDomDocument& doc ) const;
+ /** */
+ virtual void readAttributes( const PMXMLHelper& h );
+
+ /**
+ * Returns a new @ref PMWarpEdit
+ */
+ virtual PMDialogEditBase* editWidget( QWidget* parent ) const;
+ /**
+ * Returns the name of the pixmap that is displayed in the tree view
+ * and dialog view
+ */
+ virtual QString pixmap( ) const { return QString( "pmwarp" ); }
+
+ PMWarpType warpType( ) const { return m_warpType; }
+ void setWarpType( PMWarpType c );
+
+ PMVector direction( ) const { return m_direction; }
+ void setDirection( const PMVector& c );
+ PMVector offset( ) const { return m_offset; }
+ void setOffset( const PMVector& c );
+ PMVector flip( ) const { return m_flip; }
+ void setFlip( const PMVector& c );
+
+ PMVector location( ) const { return m_location; }
+ void setLocation( const PMVector& v );
+ double radius( ) const { return m_radius; }
+ void setRadius( double c );
+ double strength( ) const { return m_strength; }
+ void setStrength( double c );
+ double falloff( ) const { return m_falloff; }
+ void setFalloff( double c );
+ bool inverse( ) const { return m_inverse; }
+ void setInverse( bool c );
+ PMVector repeat( ) const { return m_repeat; }
+ void setRepeat( const PMVector& v );
+ PMVector turbulence( ) const { return m_turbulence; }
+ void setTurbulence( const PMVector& v );
+
+ PMVector valueVector( ) const { return m_valueVector; }
+ void setValueVector( const PMVector& v );
+ int octaves( ) const { return m_octaves; }
+ void setOctaves( int c );
+ double omega( ) const { return m_omega; }
+ void setOmega( double c );
+ double lambda( ) const { return m_lambda; }
+ void setLambda( double c );
+
+ PMVector orientation( ) const { return m_orientation;}
+ void setOrientation( const PMVector& v );
+ double distExp( ) const { return m_distExp; }
+ void setDistExp( double c );
+ double majorRadius( ) const { return m_majorRadius; }
+ void setMajorRadius( double c );
+
+
+ /** */
+ virtual void restoreMemento( PMMemento* s );
+private:
+ /**
+ * IDs for @ref PMMementoData
+ */
+ enum PMWarpMementoID { PMWarpTypeID, PMDirectionID, PMOffsetID, PMFlipID,
+ PMLocationID, PMRadiusID, PMStrengthID, PMFalloffID,
+ PMInverseID, PMRepeatID, PMTurbulenceID,
+ PMValueVectorID, PMOctavesID, PMOmegaID, PMLambdaID,
+ PMOrientationID, PMDistExpID, PMMajorRadiusID };
+
+ PMWarpType m_warpType;
+
+ // Repeat variables
+ PMVector m_direction;
+ PMVector m_offset;
+ PMVector m_flip;
+
+ // Black Hole variables
+ PMVector m_location;
+ double m_radius;
+ double m_strength;
+ double m_falloff;
+ bool m_inverse;
+ PMVector m_repeat;
+ PMVector m_turbulence;
+
+ // Turbulence variables
+ PMVector m_valueVector;
+ int m_octaves;
+ double m_omega;
+ double m_lambda;
+
+ // Mapping variables
+ PMVector m_orientation;
+ double m_distExp;
+ double m_majorRadius;
+
+ static PMMetaObject* s_pMetaObject;
+};
+
+#endif
diff --git a/kpovmodeler/pmwarpedit.cpp b/kpovmodeler/pmwarpedit.cpp
new file mode 100644
index 00000000..99c620dd
--- /dev/null
+++ b/kpovmodeler/pmwarpedit.cpp
@@ -0,0 +1,407 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#include "pmwarpedit.h"
+#include "pmwarp.h"
+#include "pmvectoredit.h"
+#include "pmlineedits.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcombobox.h>
+#include <qcheckbox.h>
+#include <klocale.h>
+#include <kdialog.h>
+
+
+PMWarpEdit::PMWarpEdit( QWidget* parent, const char* name )
+ : Base( parent, name )
+{
+ m_pDisplayedObject = 0;
+}
+
+void PMWarpEdit::createTopWidgets( )
+{
+ QHBoxLayout* hl;
+ QVBoxLayout* vl;
+ QGridLayout* gl;
+
+ Base::createTopWidgets( );
+
+ QLabel* label = new QLabel( i18n( "Warp type:" ), this );
+ m_pWarpTypeEdit = new QComboBox( false, this );
+ m_pWarpTypeEdit->insertItem( i18n( "Repeat" ) );
+ m_pWarpTypeEdit->insertItem( i18n( "Black Hole" ) );
+ m_pWarpTypeEdit->insertItem( i18n( "Turbulence" ) );
+ m_pWarpTypeEdit->insertItem( i18n( "Cylindrical" ) );
+ m_pWarpTypeEdit->insertItem( i18n( "Spherical" ) );
+ m_pWarpTypeEdit->insertItem( i18n( "Toroidal" ) );
+ m_pWarpTypeEdit->insertItem( i18n( "Planar" ) );
+ hl = new QHBoxLayout( topLayout( ) );
+ hl->addWidget( label );
+ hl->addWidget( m_pWarpTypeEdit );
+ hl->addStretch( 1 );
+
+ /* Repeat Warp Objects */
+ m_pRepeatWidget = new QWidget( this );
+ vl = new QVBoxLayout( m_pRepeatWidget, 0, KDialog::spacingHint( ) );
+ gl = new QGridLayout( vl, 3, 2 );
+ m_pDirectionLabel = new QLabel( i18n( "Direction:" ), m_pRepeatWidget );
+ m_pDirectionEdit = new PMVectorEdit( "x", "y", "z", m_pRepeatWidget );
+ gl->addWidget( m_pDirectionLabel, 0, 0 );
+ gl->addWidget( m_pDirectionEdit, 0, 1 );
+ m_pOffsetLabel = new QLabel( i18n( "Offset:" ), m_pRepeatWidget );
+ m_pOffsetEdit = new PMVectorEdit( "x", "y", "z", m_pRepeatWidget );
+ gl->addWidget( m_pOffsetLabel, 1, 0 );
+ gl->addWidget( m_pOffsetEdit, 1, 1 );
+ m_pFlipLabel = new QLabel( i18n( "Flip:" ), m_pRepeatWidget );
+ m_pFlipEdit = new PMVectorEdit( "x", "y", "z", m_pRepeatWidget );
+ gl->addWidget( m_pFlipLabel, 2, 0 );
+ gl->addWidget( m_pFlipEdit, 2, 1 );
+
+ /* Black Hole Warp Objects */
+ m_pBlackHoleWidget = new QWidget( this );
+ vl = new QVBoxLayout( m_pBlackHoleWidget, 0, KDialog::spacingHint( ) );
+ m_pLocationLabel = new QLabel( i18n( "Location:" ), m_pBlackHoleWidget );
+ m_pLocationEdit = new PMVectorEdit( "x", "y", "z", m_pBlackHoleWidget );
+ hl = new QHBoxLayout( vl );
+ hl->addWidget( m_pLocationLabel );
+ hl->addWidget( m_pLocationEdit );
+ m_pRadiusLabel = new QLabel( i18n( "Radius:" ), m_pBlackHoleWidget );
+ m_pRadiusEdit = new PMFloatEdit( m_pBlackHoleWidget );
+ m_pStrengthLabel = new QLabel( i18n( "Strength:" ), m_pBlackHoleWidget );
+ m_pStrengthEdit = new PMFloatEdit( m_pBlackHoleWidget );
+ m_pFalloffLabel = new QLabel( i18n( "Falloff:" ), m_pBlackHoleWidget );
+ m_pFalloffEdit = new PMFloatEdit( m_pBlackHoleWidget );
+ hl = new QHBoxLayout( vl );
+ gl = new QGridLayout( hl, 3, 2 );
+ gl->addWidget( m_pRadiusLabel, 0, 0 );
+ gl->addWidget( m_pRadiusEdit, 0, 1 );
+ gl->addWidget( m_pStrengthLabel, 1, 0 );
+ gl->addWidget( m_pStrengthEdit, 1, 1 );
+ gl->addWidget( m_pFalloffLabel, 2, 0 );
+ gl->addWidget( m_pFalloffEdit, 2, 1 );
+ hl->addStretch( 1 );
+
+ m_pRepeatLabel = new QLabel( i18n( "Repeat:" ), m_pBlackHoleWidget );
+ m_pRepeatEdit = new PMVectorEdit( "x", "y", "z", m_pBlackHoleWidget );
+ hl = new QHBoxLayout( vl );
+ hl->addWidget( m_pRepeatLabel );
+ hl->addWidget( m_pRepeatEdit );
+ m_pTurbulenceLabel = new QLabel( i18n( "Turbulence:" ), m_pBlackHoleWidget );
+ m_pTurbulenceEdit = new PMVectorEdit( "x", "y", "z", m_pBlackHoleWidget );
+ hl = new QHBoxLayout( vl );
+ hl->addWidget( m_pTurbulenceLabel );
+ hl->addWidget( m_pTurbulenceEdit );
+ m_pInverseEdit = new QCheckBox( i18n( "Inverse" ), m_pBlackHoleWidget );
+ vl->addWidget( m_pInverseEdit );
+
+ /* Turbulence Warp Objects */
+ m_pTurbulenceWidget = new QWidget( this );
+ vl = new QVBoxLayout( m_pTurbulenceWidget, 0, KDialog::spacingHint( ) );
+ m_pValueVectorLabel = new QLabel( i18n( "Value:" ), m_pTurbulenceWidget );
+ m_pValueVectorEdit = new PMVectorEdit( "x", "y", "z", m_pTurbulenceWidget );
+ hl = new QHBoxLayout( vl );
+ hl->addWidget( m_pValueVectorLabel );
+ hl->addWidget( m_pValueVectorEdit );
+
+ hl = new QHBoxLayout( vl );
+ gl = new QGridLayout( hl, 3, 2 );
+ m_pOctavesLabel = new QLabel( i18n( "Octaves:" ), m_pTurbulenceWidget );
+ m_pOctavesEdit = new PMIntEdit( m_pTurbulenceWidget );
+ gl->addWidget( m_pOctavesLabel, 0, 0 );
+ gl->addWidget( m_pOctavesEdit, 0, 1 );
+ m_pOmegaLabel = new QLabel( i18n( "Omega:" ), m_pTurbulenceWidget );
+ m_pOmegaEdit = new PMFloatEdit( m_pTurbulenceWidget );
+ gl->addWidget( m_pOmegaLabel, 1, 0 );
+ gl->addWidget( m_pOmegaEdit, 1, 1 );
+ m_pLambdaLabel = new QLabel( i18n( "Lambda:" ), m_pTurbulenceWidget );
+ m_pLambdaEdit = new PMFloatEdit( m_pTurbulenceWidget );
+ gl->addWidget( m_pLambdaLabel, 2, 0 );
+ gl->addWidget( m_pLambdaEdit, 2, 1 );
+ hl->addStretch( 1 );
+
+ /* Mapping Warp Objects */
+ m_pMappingWidget = new QWidget( this );
+ vl = new QVBoxLayout( m_pMappingWidget, 0, KDialog::spacingHint( ) );
+ label = new QLabel( i18n( "Orientation:" ), m_pMappingWidget );
+ m_pOrientationEdit = new PMVectorEdit( "x", "y", "z", m_pMappingWidget );
+ hl = new QHBoxLayout( vl );
+ hl->addWidget( label );
+ hl->addWidget( m_pOrientationEdit );
+
+ gl = new QGridLayout( vl, 2, 2 );
+ label = new QLabel( i18n( "Distance exponent:" ), m_pMappingWidget );
+ m_pDistExpEdit = new PMFloatEdit( m_pMappingWidget );
+ gl->addWidget( label, 0, 0 );
+ gl->addWidget( m_pDistExpEdit, 0, 1 );
+ m_pMajorRadiusLabel = new QLabel( i18n( "Major radius:" ), m_pMappingWidget );
+ m_pMajorRadiusEdit = new PMFloatEdit( m_pMappingWidget );
+ gl->addWidget( m_pMajorRadiusLabel, 1, 0 );
+ gl->addWidget( m_pMajorRadiusEdit, 1, 1 );
+
+ vl = new QVBoxLayout( topLayout( ) );
+ vl->addSpacing( 0 );
+ vl->addWidget( m_pRepeatWidget );
+ vl->addWidget( m_pBlackHoleWidget );
+ vl->addWidget( m_pTurbulenceWidget );
+ vl->addWidget( m_pMappingWidget );
+
+ connect( m_pWarpTypeEdit, SIGNAL( activated( int ) ), SLOT( slotComboChanged( int ) ) );
+ connect( m_pDirectionEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pOffsetEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pFlipEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pLocationEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pRadiusEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pStrengthEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pFalloffEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pInverseEdit, SIGNAL( clicked( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pRepeatEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pTurbulenceEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pValueVectorEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pOctavesEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pOmegaEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pLambdaEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pOrientationEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pDistExpEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+ connect( m_pMajorRadiusEdit, SIGNAL( dataChanged( ) ), SIGNAL( dataChanged( ) ) );
+}
+
+void PMWarpEdit::displayObject( PMObject* o )
+{
+ if( o->isA( "Warp" ) )
+ {
+ bool readOnly = o->isReadOnly( );
+ m_pDisplayedObject = ( PMWarp* ) o;
+
+ switch( m_pDisplayedObject->warpType( ) )
+ {
+ case PMWarp::Repeat:
+ m_pWarpTypeEdit->setCurrentItem( 0 );
+ slotComboChanged( 0 );
+ break;
+ case PMWarp::BlackHole:
+ m_pWarpTypeEdit->setCurrentItem( 1 );
+ slotComboChanged( 1 );
+ break;
+ case PMWarp::Turbulence:
+ m_pWarpTypeEdit->setCurrentItem( 2 );
+ slotComboChanged( 2 );
+ break;
+ case PMWarp::Cylindrical:
+ m_pWarpTypeEdit->setCurrentItem( 3 );
+ slotComboChanged( 3 );
+ break;
+ case PMWarp::Spherical:
+ m_pWarpTypeEdit->setCurrentItem( 4 );
+ slotComboChanged( 4 );
+ break;
+ case PMWarp::Toroidal:
+ m_pWarpTypeEdit->setCurrentItem( 5 );
+ slotComboChanged( 5 );
+ break;
+ case PMWarp::Planar:
+ m_pWarpTypeEdit->setCurrentItem( 6 );
+ slotComboChanged( 6 );
+ break;
+ }
+ m_pDirectionEdit->setVector( m_pDisplayedObject->direction( ) );
+ m_pDirectionEdit->setReadOnly( readOnly );
+ m_pOffsetEdit->setVector( m_pDisplayedObject->offset( ) );
+ m_pOffsetEdit->setReadOnly( readOnly );
+ m_pFlipEdit->setVector( m_pDisplayedObject->flip( ) );
+ m_pFlipEdit->setReadOnly( readOnly );
+ m_pLocationEdit->setVector( m_pDisplayedObject->location( ) );
+ m_pLocationEdit->setReadOnly( readOnly );
+ m_pRadiusEdit->setValue( m_pDisplayedObject->radius( ) );
+ m_pRadiusEdit->setReadOnly( readOnly );
+ m_pStrengthEdit->setValue( m_pDisplayedObject->strength( ) );
+ m_pStrengthEdit->setReadOnly( readOnly );
+ m_pFalloffEdit->setValue( m_pDisplayedObject->falloff( ) );
+ m_pFalloffEdit->setReadOnly( readOnly );
+ m_pInverseEdit->setChecked( m_pDisplayedObject->inverse( ) );
+ m_pInverseEdit->setEnabled( !readOnly );
+ m_pRepeatEdit->setVector( m_pDisplayedObject->repeat( ) );
+ m_pRepeatEdit->setReadOnly( readOnly );
+ m_pTurbulenceEdit->setVector( m_pDisplayedObject->turbulence( ) );
+ m_pTurbulenceEdit->setReadOnly( readOnly );
+ m_pValueVectorEdit->setVector( m_pDisplayedObject->valueVector( ) );
+ m_pValueVectorEdit->setReadOnly( readOnly );
+ m_pOctavesEdit->setValue( m_pDisplayedObject->octaves( ) );
+ m_pOctavesEdit->setReadOnly( readOnly );
+ m_pOmegaEdit->setValue( m_pDisplayedObject->omega( ) );
+ m_pOmegaEdit->setReadOnly( readOnly );
+ m_pLambdaEdit->setValue( m_pDisplayedObject->lambda( ) );
+ m_pLambdaEdit->setReadOnly( readOnly );
+ m_pOrientationEdit->setVector( m_pDisplayedObject->orientation( ) );
+ m_pOrientationEdit->setReadOnly( readOnly );
+ m_pDistExpEdit->setValue( m_pDisplayedObject->distExp( ) );
+ m_pDistExpEdit->setReadOnly( readOnly );
+ m_pMajorRadiusEdit->setValue( m_pDisplayedObject->majorRadius( ) );
+ m_pMajorRadiusEdit->setReadOnly( readOnly );
+
+ Base::displayObject( o );
+ }
+ else
+ kdError( PMArea ) << "PMWarpEdit: Can't display object\n";
+}
+
+void PMWarpEdit::saveContents( )
+{
+ bool mapping = false;
+
+ if( m_pDisplayedObject )
+ {
+ Base::saveContents( );
+ switch( m_pWarpTypeEdit->currentItem( ) )
+ {
+ case 0:
+ m_pDisplayedObject->setWarpType( PMWarp::Repeat );
+ m_pDisplayedObject->setDirection( m_pDirectionEdit->vector( ) );
+ m_pDisplayedObject->setOffset( m_pOffsetEdit->vector( ) );
+ m_pDisplayedObject->setFlip( m_pOffsetEdit->vector( ) );
+ break;
+ case 1:
+ m_pDisplayedObject->setWarpType( PMWarp::BlackHole );
+ m_pDisplayedObject->setLocation( m_pLocationEdit->vector( ) );
+ m_pDisplayedObject->setRadius( m_pRadiusEdit->value( ) );
+ m_pDisplayedObject->setStrength( m_pStrengthEdit->value( ) );
+ m_pDisplayedObject->setFalloff( m_pFalloffEdit->value( ) );
+ m_pDisplayedObject->setInverse( m_pInverseEdit->isChecked( ) );
+ m_pDisplayedObject->setRepeat( m_pRepeatEdit->vector( ) );
+ m_pDisplayedObject->setTurbulence( m_pTurbulenceEdit->vector( ) );
+ break;
+ case 2:
+ m_pDisplayedObject->setWarpType( PMWarp::Turbulence );
+ m_pDisplayedObject->setValueVector( m_pValueVectorEdit->vector( ) );
+ m_pDisplayedObject->setOctaves( m_pOctavesEdit->value( ) );
+ m_pDisplayedObject->setOmega( m_pOmegaEdit->value( ) );
+ m_pDisplayedObject->setLambda( m_pLambdaEdit->value( ) );
+ break;
+ case 3:
+ m_pDisplayedObject->setWarpType( PMWarp::Cylindrical );
+ mapping = true;
+ break;
+ case 4:
+ m_pDisplayedObject->setWarpType( PMWarp::Spherical );
+ mapping = true;
+ break;
+ case 5:
+ m_pDisplayedObject->setWarpType( PMWarp::Toroidal );
+ m_pDisplayedObject->setMajorRadius( m_pMajorRadiusEdit->value( ) );
+ mapping = true;
+ break;
+ case 6:
+ m_pDisplayedObject->setWarpType( PMWarp::Planar );
+ mapping = true;
+ break;
+ }
+
+ if( mapping )
+ {
+ m_pDisplayedObject->setOrientation( m_pOrientationEdit->vector( ) );
+ m_pDisplayedObject->setDistExp( m_pDistExpEdit->value( ) );
+ }
+ }
+}
+
+bool PMWarpEdit::isDataValid( )
+{
+ double x,y,z;
+
+ switch( m_pWarpTypeEdit->currentItem( ) )
+ {
+ case 0:
+ if( !m_pDirectionEdit->isDataValid( ) ||
+ !m_pOffsetEdit->isDataValid( ) ||
+ !m_pFlipEdit->isDataValid( ) )
+ return false;
+ // The direction vector can only have one non-zero component
+ x = m_pDirectionEdit->vector( ).x( );
+ y = m_pDirectionEdit->vector( ).y( );
+ z = m_pDirectionEdit->vector( ).z( );
+ if( ( x && ( y || z ) ) || ( y && ( x || z )) || ( z && ( x || y ) ) )
+ return false;
+ break;
+ case 1:
+ break;
+ case 2:
+ if( !m_pOctavesEdit->isDataValid( ) ||
+ m_pOctavesEdit->value( ) < 1 ||
+ m_pOctavesEdit->value( ) > 10 )
+ return false;
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ if( !m_pOrientationEdit->isDataValid( ) ||
+ !m_pDistExpEdit->isDataValid( ) ||
+ !m_pMajorRadiusEdit->isDataValid( ) )
+ return false;
+ break;
+ }
+ return Base::isDataValid( );
+}
+
+void PMWarpEdit::slotComboChanged( int c )
+{
+ switch ( c )
+ {
+ case 0:
+ m_pRepeatWidget->show( );
+ m_pBlackHoleWidget->hide( );
+ m_pTurbulenceWidget->hide( );
+ m_pMappingWidget->hide( );
+ break;
+ case 1:
+ m_pRepeatWidget->hide( );
+ m_pBlackHoleWidget->show( );
+ m_pTurbulenceWidget->hide( );
+ m_pMappingWidget->hide( );
+ break;
+ case 2:
+ m_pRepeatWidget->hide( );
+ m_pBlackHoleWidget->hide( );
+ m_pTurbulenceWidget->show( );
+ m_pMappingWidget->hide( );
+ break;
+ case 3:
+ case 4:
+ case 6:
+ m_pRepeatWidget->hide( );
+ m_pBlackHoleWidget->hide( );
+ m_pTurbulenceWidget->hide( );
+ m_pMappingWidget->show( );
+ m_pMajorRadiusLabel->hide( );
+ m_pMajorRadiusEdit->hide( );
+ break;
+ case 5:
+ m_pRepeatWidget->hide( );
+ m_pBlackHoleWidget->hide( );
+ m_pTurbulenceWidget->hide( );
+ m_pMappingWidget->show( );
+ m_pMajorRadiusLabel->show( );
+ m_pMajorRadiusEdit->show( );
+ break;
+ }
+ emit dataChanged( );
+ emit sizeChanged( );
+}
+
+#include "pmwarpedit.moc"
diff --git a/kpovmodeler/pmwarpedit.h b/kpovmodeler/pmwarpedit.h
new file mode 100644
index 00000000..1140e3e6
--- /dev/null
+++ b/kpovmodeler/pmwarpedit.h
@@ -0,0 +1,110 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2001 by Luis Carvalho
+ email : lpassos@mail.telepac.pt
+**************************************************************************
+
+**************************************************************************
+* *
+* 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. *
+* *
+**************************************************************************/
+
+
+#ifndef PMWARPEDIT_H
+#define PMWARPEDIT_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmdialogeditbase.h"
+
+class PMWarp;
+class PMVectorEdit;
+class PMIntEdit;
+class PMFloatEdit;
+class QComboBox;
+class QCheckBox;
+class QLabel;
+
+/**
+ * Dialog edit class for @ref PMWarp.
+ */
+class PMWarpEdit : public PMDialogEditBase
+{
+ Q_OBJECT
+ typedef PMDialogEditBase Base;
+public:
+ /**
+ * Creates a PMWarpEdit with parent and name
+ */
+ PMWarpEdit( QWidget* parent, const char* name = 0 );
+
+ /** */
+ virtual void displayObject( PMObject* o );
+
+ /** */
+ virtual bool isDataValid( );
+protected:
+ /** */
+ virtual void createTopWidgets( );
+ /** */
+ virtual void saveContents( );
+
+protected slots:
+ /** */
+ void slotComboChanged( int c );
+
+private:
+ PMWarp* m_pDisplayedObject;
+ QComboBox* m_pWarpTypeEdit;
+ PMVectorEdit* m_pDirectionEdit;
+ QLabel* m_pDirectionLabel;
+ PMVectorEdit* m_pOffsetEdit;
+ QLabel* m_pOffsetLabel;
+ PMVectorEdit* m_pFlipEdit;
+ QLabel* m_pFlipLabel;
+
+ PMVectorEdit* m_pLocationEdit;
+ QLabel* m_pLocationLabel;
+ PMFloatEdit* m_pRadiusEdit;
+ QLabel* m_pRadiusLabel;
+ PMFloatEdit* m_pStrengthEdit;
+ QLabel* m_pStrengthLabel;
+ PMFloatEdit* m_pFalloffEdit;
+ QLabel* m_pFalloffLabel;
+ QCheckBox* m_pInverseEdit;
+ PMVectorEdit* m_pRepeatEdit;
+ QLabel* m_pRepeatLabel;
+ PMVectorEdit* m_pTurbulenceEdit;
+ QLabel* m_pTurbulenceLabel;
+
+ PMVectorEdit* m_pValueVectorEdit;
+ QLabel* m_pValueVectorLabel;
+ PMIntEdit* m_pOctavesEdit;
+ QLabel* m_pOctavesLabel;
+ PMFloatEdit* m_pOmegaEdit;
+ QLabel* m_pOmegaLabel;
+ PMFloatEdit* m_pLambdaEdit;
+ QLabel* m_pLambdaLabel;
+
+ PMVectorEdit* m_pOrientationEdit;
+ PMFloatEdit* m_pDistExpEdit;
+ PMFloatEdit* m_pMajorRadiusEdit;
+ QLabel* m_pMajorRadiusLabel;
+
+ QWidget* m_pRepeatWidget;
+ QWidget* m_pBlackHoleWidget;
+ QWidget* m_pTurbulenceWidget;
+ QWidget* m_pMappingWidget;
+};
+
+
+#endif
diff --git a/kpovmodeler/pmxmlhelper.cpp b/kpovmodeler/pmxmlhelper.cpp
new file mode 100644
index 00000000..bbb3c32c
--- /dev/null
+++ b/kpovmodeler/pmxmlhelper.cpp
@@ -0,0 +1,160 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmxmlhelper.h"
+
+PMXMLHelper::PMXMLHelper( const QDomElement& e, PMPart* p, PMParser* par,
+ int majorDocumentFormat, int minorDocumentFormat )
+{
+ m_e = e;
+ m_pPart = p;
+ m_pParser = par;
+ m_major = majorDocumentFormat;
+ m_minor = minorDocumentFormat;
+}
+
+bool PMXMLHelper::hasAttribute( const QString& name ) const
+{
+ return m_e.hasAttribute( name );
+}
+
+int PMXMLHelper::intAttribute( const QString& name, int def ) const
+{
+ QString str = m_e.attribute( name );
+ bool ok;
+ int res;
+
+ if( str.isNull( ) )
+ return def;
+ res = str.toInt( &ok );
+ if( ok )
+ return res;
+ return def;
+}
+
+double PMXMLHelper::doubleAttribute( const QString& name, double def ) const
+{
+ QString str = m_e.attribute( name );
+ bool ok;
+ double res;
+
+ if( str.isNull( ) )
+ return def;
+ res = str.toDouble( &ok );
+ if( ok )
+ return res;
+ return def;
+}
+
+bool PMXMLHelper::boolAttribute( const QString& name, bool def ) const
+{
+ QString str = m_e.attribute( name );
+ bool ok;
+ int res;
+
+ if( str.isNull( ) )
+ return def;
+ res = str.toInt( &ok );
+ if( ok )
+ return ( res != 0 );
+ return def;
+}
+
+PMThreeState PMXMLHelper::threeStateAttribute( const QString& name ) const
+{
+ QString str = m_e.attribute( name );
+ bool ok;
+ int res;
+
+ if( str.isNull( ) )
+ return PMUnspecified;
+ res = str.toInt( &ok );
+ if( ok )
+ {
+ if( res == 0 )
+ return PMFalse;
+ else
+ return PMTrue;
+ }
+ return PMUnspecified;
+}
+
+QString PMXMLHelper::stringAttribute( const QString& name, const QString& def ) const
+{
+ return m_e.attribute( name, def );
+}
+
+PMVector PMXMLHelper::vectorAttribute( const QString& name, const PMVector& def ) const
+{
+ QString str = m_e.attribute( name );
+
+ if( str.isNull( ) )
+ return def;
+ else
+ {
+ PMVector v;
+ if( v.loadXML( str ) )
+ return v;
+ }
+ return def;
+}
+
+PMMatrix PMXMLHelper::matrixAttribute( const QString& name, const PMMatrix& def ) const
+{
+ QString str = m_e.attribute( name );
+
+ if( str.isNull( ) )
+ return def;
+ else
+ {
+ PMMatrix m;
+ if( m.loadXML( str ) )
+ return m;
+ }
+ return def;
+}
+
+PMColor PMXMLHelper::colorAttribute( const QString& name, const PMColor& def ) const
+{
+ QString str = m_e.attribute( name );
+
+ if( str.isNull( ) )
+ return def;
+ else
+ {
+ PMColor c;
+ if( c.loadXML( str ) )
+ return c;
+ }
+ return def;
+}
+
+QDomElement PMXMLHelper::extraData( ) const
+{
+ QDomNode c = m_e.firstChild( );
+ while( !c.isNull( ) )
+ {
+ if( c.isElement( ) )
+ {
+ QDomElement ce = c.toElement( );
+ if( ce.tagName( ) == "extra_data" )
+ return ce;
+ }
+ c = c.nextSibling( );
+ }
+ return QDomElement( );
+}
diff --git a/kpovmodeler/pmxmlhelper.h b/kpovmodeler/pmxmlhelper.h
new file mode 100644
index 00000000..25ae6947
--- /dev/null
+++ b/kpovmodeler/pmxmlhelper.h
@@ -0,0 +1,121 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMXMLHELPER_H
+#define PMXMLHELPER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qdom.h>
+#include <qstring.h>
+
+#include "pmobject.h"
+#include "pmcolor.h"
+#include "pmvector.h"
+#include "pmmatrix.h"
+
+class PMPart;
+class PMParser;
+
+/**
+ * Class for reading attributes out of a @ref QDomElement
+ */
+class PMXMLHelper
+{
+public:
+ /**
+ * Creates a PMXMLHelper for the QDomElement& e
+ */
+ PMXMLHelper( const QDomElement& e, PMPart* p, PMParser* par,
+ int majorDocumentFormat, int minorDocumentFormat );
+ /**
+ * Returns the QDomElement
+ */
+ QDomElement element( ) const { return m_e; }
+
+ /**
+ * Returns true if the element contains the attribute
+ */
+ bool hasAttribute( const QString& name ) const;
+ /**
+ * Reads an integer attribute
+ */
+ int intAttribute( const QString& name, int def ) const;
+ /**
+ * Reads a double attribute
+ */
+ double doubleAttribute( const QString& name, double def ) const;
+ /**
+ * Reads a bool attribute
+ */
+ bool boolAttribute( const QString& name, bool def ) const;
+ /**
+ * Reads a PMThreeState attribute
+ */
+ PMThreeState threeStateAttribute( const QString& name ) const;
+ /**
+ * Reads a string attribute
+ */
+ QString stringAttribute( const QString& name, const QString& def ) const;
+ /**
+ * Reads a vector attribute
+ */
+ PMVector vectorAttribute( const QString& name, const PMVector& def ) const;
+ /**
+ * Reads a matrix attribute
+ */
+ PMMatrix matrixAttribute( const QString& name, const PMMatrix& def ) const;
+ /**
+ * Reads a color attribute
+ */
+ PMColor colorAttribute( const QString& name, const PMColor& def ) const;
+
+ /**
+ * Returns the "extra_data" child element or a null element, if there
+ * is no child element with tag name "extra_data"
+ */
+ QDomElement extraData( ) const;
+
+ /**
+ * Returns a pointer to the part
+ */
+ PMPart* part( ) const { return m_pPart; }
+ /**
+ * Returns a pointer to the parser
+ */
+ PMParser* parser( ) const { return m_pParser; }
+ /**
+ * Returns the documents major format number
+ */
+ int majorDocumentFormat( ) const { return m_major; }
+ /**
+ * Returns the documents minor format number
+ */
+ int minorDocumentFormat( ) const { return m_minor; }
+
+private:
+ QDomElement m_e;
+ PMPart* m_pPart;
+ PMParser* m_pParser;
+ int m_major;
+ int m_minor;
+};
+
+#endif
diff --git a/kpovmodeler/pmxmlparser.cpp b/kpovmodeler/pmxmlparser.cpp
new file mode 100644
index 00000000..520b19c0
--- /dev/null
+++ b/kpovmodeler/pmxmlparser.cpp
@@ -0,0 +1,177 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#include "pmxmlparser.h"
+
+#include <qbuffer.h>
+#include <klocale.h>
+
+#include "pmpart.h"
+#include "pmscene.h"
+#include "pmxmlhelper.h"
+#include "pmprototypemanager.h"
+#include "pmdocumentformat.h"
+#include "pmdebug.h"
+
+PMXMLParser::PMXMLParser( PMPart* part, QIODevice* dev )
+ : PMParser( part, dev )
+{
+ init( );
+}
+
+PMXMLParser::PMXMLParser( PMPart* part, const QByteArray& array )
+ : PMParser( part, array )
+{
+ init( );
+}
+
+void PMXMLParser::init( )
+{
+ m_pDoc = 0;
+ m_majorDocumentFormat = 1;
+ m_minorDocumentFormat = 0;
+}
+
+PMXMLParser::~PMXMLParser( )
+{
+ if( m_pDoc )
+ delete m_pDoc;
+}
+
+bool PMXMLParser::initDocument( )
+{
+ if( !m_pDoc )
+ {
+ m_pDoc = new QDomDocument( "KPOVMODELER" );
+ if( m_pDoc->setContent( m_pDevice ) )
+ return true;
+ else
+ {
+ printError( i18n( "Could not load the documents data!" ) );
+ setFatalError( );
+ return false;
+ }
+ }
+ return true;
+}
+
+void PMXMLParser::topParse( )
+{
+ if( initDocument( ) )
+ {
+ QDomElement e = m_pDoc->documentElement( );
+ // read the format number
+ // assume 1.0 on error
+ QString fstring = e.attribute( "majorFormat", "1" );
+ bool ok = true;
+ int format = fstring.toInt( &ok );
+ if( !ok || ( format < 1 ) )
+ format = 1;
+ m_majorDocumentFormat = format;
+
+ fstring = e.attribute( "minorFormat", "0" );
+ ok = true;
+ format = fstring.toInt( &ok );
+ if( !ok || ( format < 0 ) )
+ format = 0;
+ m_minorDocumentFormat = format;
+
+ if( ( m_majorDocumentFormat > c_majorDocumentFormat )
+ || ( m_majorDocumentFormat == c_majorDocumentFormat )
+ && ( m_minorDocumentFormat > c_minorDocumentFormat ) )
+ printWarning( i18n( "This document was created with a newer version of KPovModeler. "
+ "The whole document may not be loaded correctly." ) );
+
+ if( e.tagName( ) == "objects" )
+ {
+ parseChildObjects( e, 0 );
+ }
+ else if( e.tagName( ) == "scene" )
+ {
+ PMScene* scene = new PMScene( m_pPart );
+ insertChild( scene, 0 );
+ PMXMLHelper hlp( e, m_pPart, this,
+ m_majorDocumentFormat, m_minorDocumentFormat );
+ scene->readAttributes( hlp );
+ parseChildObjects( e, scene );
+ }
+ else
+ {
+ printError( i18n( "Wrong top level tag" ) );
+ setFatalError( );
+ }
+ }
+}
+
+void PMXMLParser::parseChildObjects( QDomElement& e, PMObject* parent )
+{
+ QDomNode c = e.firstChild( );
+ while( !c.isNull( ) )
+ {
+ if( c.isElement( ) )
+ {
+ QDomElement ce = c.toElement( );
+ PMPrototypeManager* m = m_pPart->prototypeManager( );
+ PMObject* obj = m->newObject( m->className( ce.tagName( ) ) );
+ if( obj )
+ {
+ PMXMLHelper hlp( ce, m_pPart, this,
+ m_majorDocumentFormat, m_minorDocumentFormat );
+ obj->readAttributes( hlp );
+ if( insertChild( obj, parent ) )
+ {
+ parseChildObjects( ce, obj );
+
+ if( obj->isA( "Declare" ) )
+ checkID( ( PMDeclare* ) obj );
+ }
+ else
+ delete obj;
+ }
+ else if( ce.tagName( ) != "extra_data" )
+ printError( i18n( "Unknown object %1" ).arg( ce.tagName( ) ) );
+ }
+ c = c.nextSibling( );
+ }
+}
+
+
+void PMXMLParser::quickParse( QStringList& list )
+{
+ if( initDocument( ) )
+ {
+ QDomElement e = m_pDoc->documentElement( );
+ if( ( e.tagName( ) == "objects" ) || ( e.tagName( ) == "scene" ) )
+ {
+ QDomNode c = e.firstChild( );
+
+ while( !c.isNull( ) )
+ {
+ if( c.isElement( ) )
+ {
+ QDomElement ce = c.toElement( );
+ QString type = m_pPart->prototypeManager( )->className( ce.tagName( ) );
+ if( !type.isNull( ) )
+ list.append( type );
+ }
+ c = c.nextSibling( );
+ }
+ }
+ else
+ printError( i18n( "Wrong top level tag" ) );
+ }
+}
diff --git a/kpovmodeler/pmxmlparser.h b/kpovmodeler/pmxmlparser.h
new file mode 100644
index 00000000..ca311048
--- /dev/null
+++ b/kpovmodeler/pmxmlparser.h
@@ -0,0 +1,84 @@
+//-*-C++-*-
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2002 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#ifndef PMXMLPARSER_H
+#define PMXMLPARSER_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "pmparser.h"
+
+/**
+ * Parser that parses kpovmodeler xml code
+ */
+class PMXMLParser : public PMParser
+{
+public:
+ /**
+ * Parser that parses the device
+ */
+ PMXMLParser( PMPart* part, QIODevice* device );
+ /**
+ * Parser that parses the byte array
+ */
+ PMXMLParser( PMPart* part, const QByteArray& array );
+ /**
+ * Deletes the parser
+ */
+ virtual ~PMXMLParser( );
+
+ /**
+ * Quickly scans the top level objects. Appends all top level object
+ * types to the list.
+ */
+ virtual void quickParse( QStringList& list );
+ /**
+ * Returns true, if the parser can quickly scan the top level objects.
+ */
+ virtual bool canQuickParse( ) const { return true; }
+protected:
+ /**
+ * Top level parse function
+ */
+ virtual void topParse( );
+
+private:
+ /**
+ * Inializes the parser
+ */
+ void init( );
+ /**
+ * Initializes the QDomDocument. Returns true if successful.
+ */
+ bool initDocument( );
+
+ /**
+ * Looks for child objects, parses them and appends them to the parent
+ * object. If parent is 0, all objects are appended to the result list.
+ */
+ void parseChildObjects( QDomElement& e, PMObject* parent );
+
+ QDomDocument* m_pDoc;
+ int m_majorDocumentFormat;
+ int m_minorDocumentFormat;
+};
+
+
+#endif
diff --git a/kpovmodeler/povraydocmap.xml b/kpovmodeler/povraydocmap.xml
new file mode 100644
index 00000000..1981abe1
--- /dev/null
+++ b/kpovmodeler/povraydocmap.xml
@@ -0,0 +1,174 @@
+<!DOCTYPE DOCMAP>
+<map>
+ <version number="3.1" index="povuser.htm">
+ <item className="Comment" target="pov159.htm"/>
+ <item className="Declare" target="pov190.htm"/>
+
+ <item className="Translate" target="pov217.htm"/>
+ <item className="Scale" target="pov218.htm"/>
+ <item className="Rotate" target="pov219.htm"/>
+ <item className="PovrayMatrix" target="pov220.htm"/>
+
+ <item className="Camera" target="pov224.htm"/>
+
+ <item className="ObjectLink" target="pov236.htm"/>
+ <item className="Blob" target="pov238.htm"/>
+ <item className="BlobSphere" target="pov238.htm"/>
+ <item className="BlobCylinder" target="pov238.htm"/>
+ <item className="Box" target="pov239.htm"/>
+ <item className="Cone" target="pov240.htm"/>
+ <item className="Cylinder" target="pov241.htm"/>
+ <item className="HeightField" target="pov242.htm"/>
+ <item className="JuliaFractal" target="pov243.htm"/>
+ <item className="Lathe" target="pov244.htm"/>
+ <item className="Prism" target="pov245.htm"/>
+ <item className="Sphere" target="pov246.htm"/>
+ <item className="SuperquadricEllipsoid" target="pov247.htm"/>
+ <item className="SurfaceOfRevolution" target="pov248.htm"/>
+ <item className="Text" target="pov249.htm"/>
+ <item className="Torus" target="pov250.htm"/>
+
+ <item className="BicubicPatch" target="pov252.htm"/>
+ <item className="Disc" target="pov253.htm"/>
+ <item className="Mesh" target="pov254.htm"/>
+ <item className="Polygon" target="pov255.htm"/>
+ <item className="Triangle" target="pov256.htm"/>
+
+ <item className="Plane" target="pov258.htm"/>
+ <item className="Polynom" target="pov259.htm"/>
+
+ <item className="Csg" target="pov261.htm"/>
+
+ <item className="Light" target="pov267.htm"/>
+
+ <item className="ClippedBy" target="pov278.htm"/>
+ <item className="BoundedBy" target="pov279.htm"/>
+ <item className="Material" target="pov280.htm"/>
+
+ <item className="Interior" target="pov285.htm"/>
+
+ <item className="Texture" target="pov292.htm"/>
+ <item className="Pigment" target="pov293.htm"/>
+ <item className="SolidColor" target="pov294.htm"/>
+ <item className="ColorList" target="pov295.htm"/>
+ <item className="ColorMap" target="pov296.htm"/>
+ <item className="PigmentMap" target="pov297.htm"/>
+ <item className="PigmentList" target="pov297.htm"/>
+ <item className="ImageMap" target="pov298.htm"/>
+ <item className="QuickColor" target="pov299.htm"/>
+
+ <item className="Normal" target="pov300.htm"/>
+ <item className="SlopeMap" target="pov301.htm"/>
+ <item className="Slope" target="pov301.htm"/>
+ <item className="NormalMap" target="pov302.htm"/>
+ <item className="NormalList" target="pov302.htm"/>
+ <item className="BumpMap" target="pov303.htm"/>
+
+ <item className="Finish" target="pov304.htm"/>
+
+ <item className="TextureMap" target="pov312.htm"/>
+ <item className="TextureList" target="pov312.htm"/>
+ <item className="MaterialMap" target="pov314.htm"/>
+ <item className="Pattern" target="pov316.htm"/>
+ <item className="BlendMapModifiers" target="pov348.htm"/>
+ <item className="Warp" target="pov354.htm"/>
+
+ <item className="Media" target="pov356.htm"/>
+ <item className="Density" target="pov362.htm"/>
+ <item className="DensityList" target="pov365.htm"/>
+ <item className="DensityMap" target="pov365.htm"/>
+
+ <item className="Background" target="pov369.htm"/>
+ <item className="Fog" target="pov370.htm"/>
+ <item className="SkySphere" target="pov371.htm"/>
+ <item className="Rainbow" target="pov372.htm"/>
+
+ <item className="GlobalSettings" target="pov373.htm"/>
+ </version>
+
+ <version number="3.5" index="index.html">
+ <item className="Comment" target="povdoc_157.html#target_530"/>
+ <item className="Declare" target="povdoc_167.html#target_662"/>
+
+ <item className="Translate" target="povdoc_175.html#target_702"/>
+ <item className="Scale" target="povdoc_175.html#target_703"/>
+ <item className="Rotate" target="povdoc_175.html#target_704"/>
+ <item className="PovrayMatrix" target="povdoc_175.html#target_705"/>
+
+ <item className="Camera" target="povdoc_180.html#target_713"/>
+
+ <item className="ObjectLink" target="pov236.htm"/>
+ <item className="Blob" target="povdoc_187.html#target_752"/>
+ <item className="BlobSphere" target="pov238.htm"/>
+ <item className="BlobCylinder" target="pov238.htm"/>
+ <item className="Box" target="povdoc_187.html#target_765"/>
+ <item className="Cone" target="povdoc_187.html#target_766"/>
+ <item className="Cylinder" target="povdoc_187.html#target_767"/>
+ <item className="HeightField" target="povdoc_187.html#target_768"/>
+ <item className="JuliaFractal" target="povdoc_187.html#target_775"/>
+ <item className="Lathe" target="povdoc_187.html#target_800"/>
+ <item className="Prism" target="povdoc_187.html#target_807"/>
+ <item className="Sphere" target="povdoc_187.html#target_812"/>
+ <item className="SuperquadricEllipsoid" target="povdoc_187.html#target_816"/>
+ <item className="SurfaceOfRevolution" target="povdoc_187.html#target_818"/>
+ <item className="Text" target="povdoc_187.html#target_822"/>
+ <item className="Torus" target="povdoc_187.html#target_824"/>
+
+ <item className="BicubicPatch" target="povdoc_188.html#target_828"/>
+ <item className="Disc" target="povdoc_188.html#target_835"/>
+ <item className="Mesh" target="povdoc_188.html#target_837"/>
+ <item className="Polygon" target="povdoc_188.html#target_848"/>
+ <item className="Triangle" target="povdoc_188.html#target_849"/>
+
+ <item className="Plane" target="povdoc_189.html#target_852"/>
+ <item className="Polynom" target="povdoc_189.html#target_853"/>
+
+ <item className="Csg" target="povdoc_192.html#target_905"/>
+
+ <item className="Light" target="povdoc_193.html#target_914"/>
+
+ <item className="ClippedBy" target="povdoc_195.html#target_970"/>
+ <item className="BoundedBy" target="povdoc_195.html#target_971"/>
+ <item className="Material" target="povdoc_195.html#target_972"/>
+
+ <item className="Interior" target="povdoc_196.html#target_980"/>
+
+ <item className="Texture" target="povdoc_205.html#target_1000"/>
+ <item className="Pigment" target="povdoc_206.html#target_1002"/>
+ <item className="SolidColor" target="povdoc_206.html#target_1003"/>
+ <item className="ColorList" target="povdoc_206.html#target_1004"/>
+ <item className="ColorMap" target="povdoc_206.html#target_1005"/>
+ <item className="PigmentMap" target="povdoc_206.html#target_1007"/>
+ <item className="PigmentList" target="povdoc_206.html#target_1007"/>
+ <item className="ImageMap" target="povdoc_206.html#target_1009"/>
+ <item className="QuickColor" target="povdoc_206.html#target_1019"/>
+
+ <item className="Normal" target="povdoc_207.html#target_1021"/>
+ <item className="SlopeMap" target="povdoc_207.html#target_1022"/>
+ <item className="Slope" target="povdoc_207.html#target_1022"/>
+ <item className="NormalMap" target="povdoc_207.html#target_1025"/>
+ <item className="NormalList" target="povdoc_207.html#target_1025"/>
+ <item className="BumpMap" target="povdoc_207.html#target_1027"/>
+
+ <item className="Finish" target="povdoc_208.html#target_1035"/>
+
+ <item className="TextureMap" target="povdoc_210.html#target_1071"/>
+ <item className="TextureList" target="povdoc_210.html#target_1071"/>
+ <item className="MaterialMap" target="povdoc_210.html#target_1077"/>
+ <item className="Pattern" target="povdoc_216.html#target_1089"/>
+ <item className="BlendMapModifiers" target="povdoc_217.html#target_1143"/>
+ <item className="Warp" target="povdoc_217.html#target_1155"/>
+
+ <item className="Media" target="povdoc_218.html#target_1185"/>
+ <item className="Density" target="povdoc_221.html#target_1202"/>
+ <item className="DensityList" target="povdoc_221.html#target_1206"/>
+ <item className="DensityMap" target="povdoc_221.html#target_1206"/>
+
+ <item className="Background" target="povdoc_224.html#target_1211"/>
+ <item className="Fog" target="povdoc_225.html#target_1212"/>
+ <item className="SkySphere" target="povdoc_226.html#target_1220"/>
+ <item className="Rainbow" target="povdoc_227.html#target_1222"/>
+
+ <item className="GlobalSettings" target="povdoc_234.html#target_1265"/>
+ </version>
+</map>
diff --git a/kpovmodeler/questionmark.png b/kpovmodeler/questionmark.png
new file mode 100644
index 00000000..19eb62d8
--- /dev/null
+++ b/kpovmodeler/questionmark.png
Binary files differ
diff --git a/kpovmodeler/version.h b/kpovmodeler/version.h
new file mode 100644
index 00000000..1fbc1f0c
--- /dev/null
+++ b/kpovmodeler/version.h
@@ -0,0 +1,18 @@
+/*
+**************************************************************************
+ description
+ --------------------
+ copyright : (C) 2000-2003 by Andreas Zehender
+ email : zehender@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. *
+* *
+**************************************************************************/
+
+#define KPOVMODELER_VERSION "1.1.3"
diff --git a/kruler/Makefile.am b/kruler/Makefile.am
new file mode 100644
index 00000000..d2b8f278
--- /dev/null
+++ b/kruler/Makefile.am
@@ -0,0 +1,25 @@
+SUBDIRS = pics
+
+INCLUDES= $(all_includes)
+
+bin_PROGRAMS = kruler
+kruler_METASOURCES = AUTO
+kruler_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+kruler_LDADD = $(LIB_KDEUI)
+kruler_SOURCES = klineal.cpp main.cpp
+
+xdg_apps_DATA = kruler.desktop
+
+install-data-local: uninstall.desktop
+ $(mkinstalldirs) $(DESTDIR)$(kde_appsdir)/Graphics
+ $(INSTALL_DATA) $(srcdir)/uninstall.desktop $(DESTDIR)$(kde_appsdir)/Graphics/kruler.desktop
+
+appdir = $(kde_datadir)/kruler
+app_DATA = eventsrc
+
+sounddir = $(kde_datadir)/kruler/sounds
+sound_DATA = move.wav
+
+messages:
+ $(XGETTEXT) $(kruler_SOURCES) -o $(podir)/kruler.pot
+
diff --git a/kruler/eventsrc b/kruler/eventsrc
new file mode 100644
index 00000000..5f178815
--- /dev/null
+++ b/kruler/eventsrc
@@ -0,0 +1,192 @@
+[!Global!]
+IconName=kruler
+Comment=KDE Screen Ruler
+Comment[af]=Kde Skerm Liniaal
+Comment[ar]=مسطرة شاشة KDE
+Comment[az]=KDE Ekran Xətkeşi
+Comment[bg]=Линийка за екрана
+Comment[bs]=KDE ekranski linijar
+Comment[ca]=Regla de pantalla KDE
+Comment[cs]=Obrazovkové pravítko
+Comment[cy]=Mesurydd Sgrîn KDE
+Comment[da]=KDE Skærmlineal
+Comment[de]=Bildschirmlineal
+Comment[el]=Χάρακας οθόνης του KDE
+Comment[eo]=Ekranliniilo
+Comment[es]=Regla para la pantalla de KDE
+Comment[et]=KDE ekraani joonlaud
+Comment[eu]=KDE pantaila erregela
+Comment[fa]=خط‌کش پردۀ KDE
+Comment[fi]=Näytön mittaaja
+Comment[fr]=Règle d'écran pour KDE
+Comment[ga]=Rialóir Scáileáin KDE
+Comment[gl]=Regra de pantalla de KDE
+Comment[he]=סרגל המסך של KDE
+Comment[hi]=केडीई स्क्रीन रूलर
+Comment[hr]=KDE ravnalo za ekran
+Comment[hu]=Képernyővonalzó
+Comment[is]=KDE Reglustikan
+Comment[it]=Righello dello schermo
+Comment[ja]=KDE スクリーン定規
+Comment[kk]=KDE экран өлшегіші
+Comment[km]=បន្ទាត់​អេក្រង់ KDE
+Comment[ko]=KDE용 화면 자
+Comment[lt]=KDE ekrano liniuotė
+Comment[lv]=KDE Ekrāna Mērjosla
+Comment[ms]=Pembaris Skrin KDE
+Comment[mt]=Riga tal-Iskrin KDE
+Comment[nb]=KDE skjermlinjal
+Comment[nds]=KDE-Schirmlineaal
+Comment[ne]=केडीई पर्दा रूलर
+Comment[nl]=KDE Schermliniaal
+Comment[nn]=KDE Skjermlinjal
+Comment[nso]=Molaodi wa Pontsho ya KDE
+Comment[pl]=Linijka ekranowa
+Comment[pt]=Régua do ecrã do KDE
+Comment[pt_BR]=Régua da Tela do KDE
+Comment[ro]=Riglă de ecran pentru KDE
+Comment[ru]=Экранная линейка KDE
+Comment[se]=KDE-šearbmalinjála
+Comment[sk]=KDE pravítko obrazovky
+Comment[sl]=Zaslonsko ravnilo KDE
+Comment[sr]=KDE-ов екрански лењир
+Comment[sr@Latn]=KDE-ov ekranski lenjir
+Comment[sv]=KDE:s skärmlinjal
+Comment[ta]=கேடிஇ திரைக்கான அளவுக்கோல்
+Comment[tg]=Ҷадвали экрании KDE
+Comment[th]=ไม้บรรทัดบนหน้าจอของ KDE
+Comment[tr]=KDE Ekran Cetveli
+Comment[uk]=Лінійка екрана KDE
+Comment[uz]=KDE ekran lineykasi
+Comment[uz@cyrillic]=KDE экран линейкаси
+Comment[ven]=Muvhusi wa tshikirini tsha KDE
+Comment[xh]=Umlawuli wekhusi le KDE
+Comment[zh_CN]=KDE 屏幕标尺
+Comment[zh_HK]=KDE 螢幕尺規
+Comment[zh_TW]=KDE 螢幕尺規
+Comment[zu]=Umlawuli Wesikrini se KDE
+
+[cursormove]
+Name=Moved by Cursor Keys
+Name[af]=Verskuif deur Plekaanduier Sleutels
+Name[ar]=تم تحريكها بمفاتيح الفأرة
+Name[az]=İstiqamət düymələri ilə hərəkət etdirildi
+Name[bg]=Преместване чрез клавиатурата
+Name[bs]=Pomjera se kursorskim tipkama
+Name[ca]=Mogut mitjançant les tecles de cursor
+Name[cs]=Přesunutý kurzorovými klávesami
+Name[cy]=Symudir gan y Bysellau Cyrchydd
+Name[da]=Flyttet med piletaster
+Name[de]=Durch Pfeiltasten verschoben
+Name[el]=Μετακινήθηκε από τα πλήκτρα κίνησης
+Name[eo]=Movata de la direktoklavoj
+Name[es]=Movido por las teclas del cursor
+Name[et]=Liigutati nooleklahve kasutades
+Name[eu]=Cursor Keys-ek mugitua
+Name[fa]=توسط کلیدهای مکان‌نما حرکت کرد
+Name[fi]=Siirrettiin kursorinäppäimillä
+Name[fr]=Déplacée par les touches fléchées
+Name[gl]=Mover coas teclas de cursor
+Name[he]=הזזה באמצעות מקשי החצים
+Name[hi]=संकेतक कुंजियों द्वारा खिसकता है
+Name[hr]=Pomaknuto tipkama za kretanje
+Name[hu]=A vonalzó elmozgatva a kurzorbillentyűkkel
+Name[is]=Fært með örvalyklum
+Name[it]=Spostato dai tasti cursore
+Name[ja]=カーソルキーで移動
+Name[kk]=Жебелі пернелерімен жылжыту
+Name[km]=បាន​ផ្លាស់ទី​ដោយ​គ្រាប់ចុច​ទស្សន៍​ទ្រនិច
+Name[ko]=방향 글쇠로 옮겼습니다
+Name[lt]=Judinama klaviatūros rodyklėmis
+Name[lv]=Pārvietots ar Kursora Taustiņiem
+Name[ms]=Dialih oleh Kekunci Kursor
+Name[mt]=Immexxi bil-buttuni tal-vleġeġ
+Name[nb]=Flyttet med piltaster
+Name[nds]=Mit Pieltasten verschaven
+Name[ne]=कर्सर कुञ्जीद्वारा सारिएको
+Name[nl]=Verplaatst met de cursortoetsen
+Name[nn]=Flytt med piltastane
+Name[nso]=Sutisa ke Ditobetswa tsa Cursor
+Name[pl]=Przesunięto klawiszami kursora
+Name[pt]=Movimentado com as Teclas de Cursor
+Name[pt_BR]=Movido pelas Teclas de Direção
+Name[ro]=Mutat cu tastele cursor
+Name[ru]=Передвижение стрелками
+Name[sk]=Presunutý kurzorovými klávesmi
+Name[sl]=Premaknjeno s smernimi tipkami
+Name[sr]=Померен курсорским тастерима
+Name[sr@Latn]=Pomeren kursorskim tasterima
+Name[sv]=Flyttade med piltangenteran
+Name[ta]=சுட்டி விசையால் நகர்த்தப்பட்டது
+Name[tg]=Ба ҳаракат даровардан бо аломати тира
+Name[th]=ย้ายด้วยปุ่มลูกศร
+Name[tr]=Yön tuşlarıyla hareket ettirildi
+Name[uk]=Пересунуто клавішами курсора
+Name[ven]=Tshimbidzhwa nga khii ya musevhe
+Name[xh]=Ishukunyiswa zizitshixo zesalathisi
+Name[zh_CN]=用光标键移动
+Name[zh_HK]=用游標鍵移動
+Name[zh_TW]=用游標鍵移動
+Name[zu]=Inyakaziswe Izikhiye Ze Cursor
+Comment=The ruler has moved pixelwise using the cursor keys
+Comment[af]=Die liniaal het verskuif beeldelement-gewys te gebruik Die plekaanduier sleutels
+Comment[ar]=تم تحريك المسطرة بكسليا باستخدام مفاتيح الفأرة
+Comment[az]=Cədvəl piksel piksel istiqamət düymələri ilə hərəkət etdirildi
+Comment[bg]=Преместване чрез клавиатурата
+Comment[bs]=Linijar se pomjera u pixelima koristeći kursorske tipke
+Comment[ca]=La regla s'ha mogut píxel a píxel usant les tecles de cursor
+Comment[cs]=Pravítko bylo kurzorovými klávesami posunuto o několik bodů
+Comment[cy]=Mae'r mesurydd wedi symud o safbwynt picseli wrth ddefnyddio'r bysellau cyrchydd
+Comment[da]=Linealen er flyttet en pixel af gangen med piletasterne
+Comment[de]=Das Lineal wurde durch die Pfeiltasten um einige Pixel verschoben
+Comment[el]=Ο χάρακας μετακινήθηκε pixelwise με τη χρήση των πλήκτρων κίνησης
+Comment[eo]=La liniilo estas movita popunkte uzante la direktoklavojn
+Comment[es]=La regla se ha movido entre los pixels usando las teclas del cursor
+Comment[et]=Joonlauda liigutati pikselhaaval nooleklahve kasutades
+Comment[eu]=Erregela mugitu da kurtsore teklek eragina
+Comment[fa]=خط‌کش با استفاده از کلیدهای مکان‌نما در جهت تصویردانه حرکت کرده است.
+Comment[fi]=Mittanauha on liikkunut pikseleitä käyttämällä kursorinäppäimiä
+Comment[fr]=La règle s'est déplacée sous l'action des touches fléchées
+Comment[gl]=A regra moverá o «pixelwise» empregando as teclas de cursor
+Comment[he]=הסרגל הוזז באמצעות מקשי החצים
+Comment[hi]=संकेतक कुंजियों की मदद से रूसर पिक्सलवाइज़ खिसका
+Comment[hr]=Ravnalo je pomaknuto pomoću tipki za kretanje
+Comment[hu]=A vonalzó elmozgatva képpontonként a kurzorbillentyűkkel
+Comment[is]=Reglustikan hefur verið færð um e-a punkta með örvalyklunum
+Comment[it]=Il righello è stato spostato usando i tasti cursore
+Comment[ja]=定規がカーソルキーによってピクセル単位で移動しました
+Comment[kk]=Өлшегіш жебелі пернелер көмегімен пикселдеп жылжиды
+Comment[km]=បន្ទាត់​ត្រូវ​បាន​ផ្លាស់ទី​តាម​ភីកសែល ដោយ​ប្រើ​គ្រាប់ចុច​ទស្សន៍​ទ្រនិច
+Comment[ko]=방향 글쇠로 자대를 옮겼습니다
+Comment[lt]=Liniuote buvo paslinkta kelis taškus naudojant klaviatūros rodykles.
+Comment[lv]=Mērjosla pārvietota pikseļavirzienā izmantojot kursora taustiņus.
+Comment[ms]= Pembaris telah mengalih ikut piksel menggunakan kekunci kursor
+Comment[mt]=Ir-riga mxiet b'tikka waħda permezz tal-buttuni vleġeġ
+Comment[nb]=Linjalen ble flyttet punktvis ved bruk av piltastene
+Comment[nds]=Dat Lineaal warrt mit de Pieltasten pixelwies verschaven
+Comment[ne]=कर्सर कुञ्जी प्रयोग गरेर रूलर पिक्सेलअनुसार सारियो
+Comment[nl]=De liniaal is enkele pixels verplaatst via de cursortoetsen
+Comment[nn]=Linjalen vert flytta piksel for piksel med piltastane
+Comment[nso]=Molaodi o tsamaile ka mokgwa wa pixelwise a somisa ditobetswa tsa cursor
+Comment[pl]=Linijka przesunięta o zadaną ilość pikseli używając klawiszy kursora
+Comment[pt]=A régua foi movida com as teclas de cursor
+Comment[pt_BR]=A régua foi movida usando as teclas de direção
+Comment[ro]=Rigla a fost mutată cîţiva pixeli cu tastele cursor
+Comment[ru]=Линейка сдвигается попиксельно с помощью стрелок.
+Comment[sk]=Pravítko bolo kurzorovými klávesmi posunuté o niekoľko bodov
+Comment[sl]=Ravnilo se je premaknilo po točkah z uporabo smernih tipk
+Comment[sr]=Лењир се померио за пиксел помоћу курсорских тастера
+Comment[sr@Latn]=Lenjir se pomerio za piksel pomoću kursorskih tastera
+Comment[sv]=Linjalen har flyttats bildpunktsvis med piltangenterna
+Comment[ta]=சுட்டி விசைகளை பயன்படுத்தி படத்துணுக்கு மூலமாக வரை உருளை நகர்த்தப்பட்டது
+Comment[tg]=Ҷадвал бо ёрии аломати тира, пикселнокӣ ҳаракат мекунад.
+Comment[tr]=Cetvel piksel piksel yön tuşlarıyla hareket ettirildi
+Comment[uk]=Лінійка пересувається по пікселях за допомогою клавіш курсора
+Comment[ven]=Muvhusi o sudzulusa pixelwise a tshi khou shumisa khii ya Cursor
+Comment[xh]=Umlawuli ushukume jikelele kwipixel esebenzisa izitshixi zesalathisi
+Comment[zh_CN]=标尺已经用光标键按像素移动
+Comment[zh_HK]=使用游標鍵移動尺規單一個像素
+Comment[zh_TW]=使用游標鍵移動尺規單一個像素
+Comment[zu]=Umlawuli unyakazise jikelele kwipixel esebenzisa izikhiye ze cursor
+default_sound=move.wav
+default_presentation=1
diff --git a/kruler/klineal.cpp b/kruler/klineal.cpp
new file mode 100644
index 00000000..8f03c68b
--- /dev/null
+++ b/kruler/klineal.cpp
@@ -0,0 +1,746 @@
+/***************************************************************************
+ klineal.cpp - description
+ -------------------
+ begin : Fri Oct 13 2000
+ copyright : (C) 2000 by Till Krech
+ email : till@snafu.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#include <iostream>
+
+#include <kconfig.h>
+#include <kcursor.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <kimageeffect.h>
+#include <klocale.h>
+#include <kmainwindow.h>
+#include <knotifyclient.h>
+#include <kpopupmenu.h>
+#include <kstandarddirs.h>
+#include <kwin.h>
+#include <kstdguiitem.h>
+
+#include <qbitmap.h>
+#include <qcursor.h>
+#include <qdialog.h>
+#include <qiconset.h>
+#include <qimage.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qwhatsthis.h>
+
+#include "klineal.h"
+
+#define CFG_KEY_BGCOLOR "BgColor"
+#define CFG_KEY_SCALE_FONT "ScaleFont"
+#define CFG_KEY_LENGTH "Length"
+#define CFG_GROUP_SETTINGS "StoredSettings"
+#define DEFAULT_RULER_COLOR QColor(255, 200, 80)
+#define FULLSCREENID 23
+/**
+* this is our cursor bitmap:
+* a line 48 pixels long with an arrow pointing down
+* and a sqare with a one pixel hole at the top (end)
+*/
+static const uchar cursorBits[] = {
+ 0x38, 0x28, 0x38, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
+ 0xfe, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x10,
+};
+
+/**
+* create the thingy with no borders and set up
+* its members
+*/
+KLineal::KLineal(QWidget*parent,const char* name):KMainWindow(parent,name){
+ if (!name) {
+ name = "klineal";
+ }
+ mLenMenu=0;
+ KWin::setType(winId(), NET::Override); // or NET::Normal
+ KWin::setState(winId(), NET::StaysOnTop);
+ setPaletteBackgroundColor(black);
+ QWhatsThis::add(this,
+ i18n(
+ "This is a tool to measure pixel distances and colors on the screen. "
+ "It is useful for working on layouts of dialogs, web pages etc."
+ ));
+ QBitmap bim = QBitmap(QSize(8, 48), cursorBits);
+ QWMatrix m;
+ m.rotate(90.0);
+ mNorthCursor = QCursor(bim, bim, 3, 47);
+ bim = bim.xForm(m);
+ mEastCursor = QCursor(bim, bim, 0, 3);
+ bim = bim.xForm(m);
+ mSouthCursor = QCursor(bim, bim, 4, 0);
+ bim = bim.xForm(m);
+ mWestCursor = QCursor(bim, bim, 47, 4);
+
+ mCurrentCursor = mNorthCursor;
+ setMinimumSize(60,60);
+ setMaximumSize(8000,8000);
+ KConfig *cfg = kapp->config();
+ QColor defaultColor = DEFAULT_RULER_COLOR;
+ QFont defaultFont(KGlobalSettings::generalFont().family(), 8);
+ defaultFont.setPixelSize(8);
+ if (cfg) {
+ cfg->setGroup(CFG_GROUP_SETTINGS);
+ mColor = cfg->readColorEntry(CFG_KEY_BGCOLOR, &defaultColor);
+ mScaleFont = cfg->readFontEntry(CFG_KEY_SCALE_FONT, &defaultFont);
+ mLongEdgeLen = cfg->readNumEntry(CFG_KEY_LENGTH, 600);
+ } else {
+ mColor = defaultColor;
+ mScaleFont = defaultFont;
+ mLongEdgeLen = 400;
+ }
+ kdDebug() << "mLongEdgeLen=" << mLongEdgeLen << endl;
+ mShortEdgeLen = 70;
+
+ mLabel = new QLabel(this);
+ mLabel->setGeometry(0,height()-12,32,12);
+ mLabel->setBackgroundOrigin(ParentOrigin);
+ QFont labelFont(KGlobalSettings::generalFont().family(), 10);
+ labelFont.setPixelSize(10);
+ mLabel->setFont(labelFont);
+ QWhatsThis::add(mLabel,
+ i18n(
+ "This is the current distance measured in pixels."
+ ));
+ mColorLabel = new QLabel(this);
+ mColorLabel->resize(45,12);
+ mColorLabel->setPaletteBackgroundColor(mColor);
+ mColorLabel->hide();
+ QFont colorFont(KGlobalSettings::fixedFont().family(), 10);
+ colorFont.setPixelSize(10);
+ mColorLabel->setFont(colorFont);
+ mColorLabel->move(mLabel->pos() + QPoint(0, 20));
+ QWhatsThis::add(mColorLabel,
+ i18n(
+ "This is the current color in hexadecimal rgb representation as you may use it in HTML or as a QColor name. "
+ "The rectangles background shows the color of the pixel inside the "
+ "little square at the end of the line cursor."
+ ));
+
+ resize(QSize(mLongEdgeLen, mShortEdgeLen));
+ setMouseTracking(TRUE);
+ mDragging = FALSE;
+ mOrientation = South;
+ _clicked = false;
+ setOrientation(South);
+ // setMediumLength();
+ mMenu = new KPopupMenu(this);
+ mMenu->insertTitle(i18n("KRuler"));
+ KPopupMenu *oriMenu = new KPopupMenu(this);
+ oriMenu->insertItem(UserIconSet("kruler-north"), i18n("&North"), this, SLOT(setNorth()), Key_N);
+ oriMenu->insertItem(UserIconSet("kruler-east"), i18n("&East"), this, SLOT(setEast()), Key_E);
+ oriMenu->insertItem(UserIconSet("kruler-south"), i18n("&South"), this, SLOT(setSouth()), Key_S);
+ oriMenu->insertItem(UserIconSet("kruler-west"), i18n("&West"), this, SLOT(setWest()), Key_W);
+ oriMenu->insertItem(i18n("&Turn Right"), this, SLOT(turnRight()), Key_R);
+ oriMenu->insertItem(i18n("Turn &Left"), this, SLOT(turnLeft()), Key_L);
+ mMenu->insertItem(i18n("&Orientation"), oriMenu);
+ mLenMenu = new KPopupMenu(this);
+ mLenMenu->insertItem(i18n("&Short"), this, SLOT(setShortLength()), CTRL+Key_S);
+ mLenMenu->insertItem(i18n("&Medium"), this, SLOT(setMediumLength()), CTRL+Key_M);
+ mLenMenu->insertItem(i18n("&Tall"), this, SLOT(setTallLength()), CTRL+Key_T);
+ mLenMenu->insertItem(i18n("&Full Screen Width"), this, SLOT(setFullLength()), CTRL+Key_F, FULLSCREENID);
+ mMenu->insertItem(i18n("&Length"), mLenMenu);
+ mMenu->insertItem(SmallIcon("colorscm"), i18n("&Choose Color..."), this, SLOT(choseColor()), CTRL+Key_C);
+ mMenu->insertItem(SmallIcon("font"), i18n("Choose &Font..."), this, SLOT(choseFont()), Key_F);
+ mMenu->insertSeparator();
+ mMenu->insertItem(SmallIcon( "help" ), KStdGuiItem::help().text(), helpMenu());
+ mMenu->insertSeparator();
+ mMenu->insertItem(SmallIcon( "exit" ), KStdGuiItem::quit().text(), kapp, SLOT(quit()), CTRL+Key_Q);
+ mLastClickPos = geometry().topLeft()+QPoint(width()/2, height()/2);
+}
+
+KLineal::~KLineal(){
+}
+
+void KLineal::move(int x, int y) {
+ move(QPoint(x, y));
+}
+
+void KLineal::move(const QPoint &p) {
+ setGeometry(QRect(p, size()));
+}
+
+QPoint KLineal::pos() {
+ QRect r = frameGeometry();
+ return r.topLeft();
+}
+int KLineal::x() {
+ return pos().x();
+}
+int KLineal::y() {
+ return pos().y();
+}
+
+static void rotateRect(QRect &r, QPoint center, int nineties) {
+ static int sintab[4] = {0,1,0,-1};
+ static int costab[4] = {1,0,-1,0};
+ int i=0;
+ int x1, y1, x2, y2;
+ if (nineties < 0) {
+ nineties = -nineties+4;
+ }
+ i = nineties % 4;
+ r.moveBy(-center.x(), -center.y());
+ r.coords(&x1, &y1, &x2, &y2);
+ r.setCoords(
+ x1 * costab[i] + y1 * sintab[i],
+ -x1 * sintab[i] + y1 * costab[i],
+ x2 * costab[i] + y2 * sintab[i],
+ -x2 * sintab[i] + y2 * costab[i]
+ );
+ r = r.normalize();
+ r.moveBy(center.x(), center.y());
+}
+
+void KLineal::setupBackground() {
+ QColor a, b, bg = mColor;
+ KImageEffect::GradientType gradType = KImageEffect::HorizontalGradient;
+ switch (mOrientation) {
+ case North:
+ a = bg.light(120);
+ b = bg.dark(130);
+ gradType = KImageEffect::VerticalGradient;
+ break;
+ case South:
+ b = bg.light(120);
+ a = bg.dark(130);
+ gradType = KImageEffect::VerticalGradient;
+ break;
+ case West:
+ a = bg.light(120);
+ b = bg.dark(130);
+ gradType = KImageEffect::HorizontalGradient;
+ break;
+ case East:
+ b = bg.light(120);
+ a = bg.dark(130);
+ gradType = KImageEffect::HorizontalGradient;
+ break;
+ }
+ QPixmap bgPixmap = QPixmap(KImageEffect::gradient(size(), a, b, gradType));
+ setErasePixmap(bgPixmap);
+ mLabel->setErasePixmap(bgPixmap);
+}
+
+void KLineal::setOrientation(int inOrientation) {
+ QRect r = frameGeometry();
+ int nineties = (int)inOrientation - (int)mOrientation;
+ QPoint center = mLastClickPos;
+
+ if (_clicked) {
+ center = mLastClickPos;
+ _clicked = false;
+ } else {
+ center = r.topLeft()+QPoint(width()/2, height()/2);
+ }
+
+ rotateRect(r, center, nineties);
+
+ QRect desktop = KGlobalSettings::desktopGeometry(this);
+ if (r.top() < desktop.top())
+ r.moveTop( desktop.top() );
+ if (r.bottom() > desktop.bottom())
+ r.moveBottom( desktop.bottom() );
+ if (r.left() < desktop.left())
+ r.moveLeft( desktop.left() );
+ if (r.right() > desktop.right())
+ r.moveRight( desktop.right() );
+
+ setGeometry(r);
+ mOrientation = (inOrientation + 4) % 4;
+ switch(mOrientation) {
+ case North:
+ mLabel->move(4, height()-mLabel->height()-4);
+ mColorLabel->move(mLabel->pos() + QPoint(0, -20));
+ mCurrentCursor = mNorthCursor;
+ break;
+ case South:
+ mLabel->move(4, 4);
+ mColorLabel->move(mLabel->pos() + QPoint(0, 20));
+ mCurrentCursor = mSouthCursor;
+ break;
+ case East:
+ mLabel->move(4, 4);
+ mColorLabel->move(mLabel->pos() + QPoint(0, 20));
+ mCurrentCursor = mEastCursor;
+ break;
+ case West:
+ mLabel->move(width()-mLabel->width()-4, 4);
+ mColorLabel->move(mLabel->pos() + QPoint(-5, 20));
+ mCurrentCursor = mWestCursor;
+ break;
+ }
+ if (mLenMenu)
+ mLenMenu->changeItem(FULLSCREENID, mOrientation % 2 ? i18n("&Full Screen Height") : i18n("&Full Screen Width"));
+ setCursor(mCurrentCursor);
+ setupBackground();
+ repaint();
+}
+void KLineal::setNorth() {
+ setOrientation(North);
+}
+void KLineal::setEast() {
+ setOrientation(East);
+}
+void KLineal::setSouth() {
+ setOrientation(South);
+}
+void KLineal::setWest() {
+ setOrientation(West);
+}
+void KLineal::turnRight() {
+ setOrientation(mOrientation - 1);
+}
+void KLineal::turnLeft() {
+ setOrientation(mOrientation + 1);
+}
+void KLineal::reLength(int percentOfScreen) {
+ if (percentOfScreen < 10) {
+ return;
+ }
+ QRect r = KGlobalSettings::desktopGeometry(this);
+
+ if (mOrientation == North || mOrientation == South) {
+ mLongEdgeLen = r.width() * percentOfScreen / 100;
+ resize(mLongEdgeLen, height());
+ } else {
+ mLongEdgeLen = r.height() * percentOfScreen / 100;
+ resize(width(), mLongEdgeLen);
+ }
+ if (x()+width() < 10) {
+ move (10, y());
+ }
+ if (y()+height() < 10) {
+ move (x(), 10);
+ }
+ saveSettings();
+}
+void KLineal::setShortLength() {
+ reLength(30);
+}
+void KLineal::setMediumLength() {
+ reLength(50);
+}
+void KLineal::setTallLength() {
+ reLength(75);
+}
+void KLineal::setFullLength() {
+ reLength(100);
+}
+void KLineal::choseColor() {
+ QRect r = KGlobalSettings::desktopGeometry(this);
+
+ QPoint pos = QCursor::pos();
+ if (pos.x() + mColorSelector.width() > r.width()) {
+ pos.setX(r.width() - mColorSelector.width());
+ }
+ if (pos.y() + mColorSelector.height() > r.height()) {
+ pos.setY(r.height() - mColorSelector.height());
+ }
+ mStoredColor = mColor;
+ mColorSelector.move(pos);
+ mColorSelector.setColor(mColor);
+ mColorSelector.setDefaultColor( DEFAULT_RULER_COLOR );
+ mColorSelector.show();
+
+ connect(&mColorSelector, SIGNAL(okClicked()), this, SLOT(setColor()));
+ connect(&mColorSelector, SIGNAL(yesClicked()), this, SLOT(setColor()));
+ connect(&mColorSelector, SIGNAL(closeClicked()), this, SLOT(setColor()));
+ connect(&mColorSelector, SIGNAL(defaultClicked()), this, SLOT(setColor()));
+ connect(&mColorSelector, SIGNAL(colorSelected(const QColor&)), this, SLOT(setColor(const QColor&)));
+ /*
+ connect(&mColorSelector, SIGNAL(cancelPressed()), this, SLOT(restoreColor()));
+ connect(&mColorSelector, SIGNAL(okPressed()), this, SLOT(saveColor()));
+ */
+}
+
+/**
+* slot to choose a font
+*/
+void KLineal::choseFont() {
+ QFont font = mScaleFont;
+ int result = KFontDialog::getFont(font, false, this);
+ if (result == KFontDialog::Accepted) {
+ setFont(font);
+ }
+}
+
+/**
+* set the ruler color to the previously selected color
+*/
+void KLineal::setFont(QFont &font) {
+ mScaleFont = font;
+ saveSettings();
+ repaint();
+}
+
+
+/**
+* set the ruler color to the previously selected color
+*/
+void KLineal::setColor() {
+ setColor(mColorSelector.color());
+ saveSettings();
+}
+
+/**
+* set the ruler color to some color
+*/
+void KLineal::setColor(const QColor &color) {
+ mColor = color;
+ if ( !mColor.isValid() )
+ mColor = DEFAULT_RULER_COLOR;
+ setupBackground();
+}
+
+/**
+* save the ruler color to the config file
+*/
+void KLineal::saveSettings() {
+ KConfig *cfg = kapp->config(); // new KConfig(locateLocal("config", kapp->name()+"rc"));
+ if (cfg) {
+ QColor color = mColor;
+ cfg->setGroup(CFG_GROUP_SETTINGS);
+ cfg->writeEntry(QString(CFG_KEY_BGCOLOR), color);
+ cfg->writeEntry(QString(CFG_KEY_SCALE_FONT), mScaleFont);
+ cfg->writeEntry(QString(CFG_KEY_LENGTH), mLongEdgeLen);
+ cfg->sync();
+ }
+}
+
+/**
+* restores the color
+*/
+void KLineal::restoreColor() {
+ setColor(mStoredColor);
+}
+/**
+* lets the context menu appear at current cursor position
+*/
+void KLineal::showMenu() {
+ QPoint pos = QCursor::pos();
+ mMenu->popup(pos);
+}
+
+/**
+* overwritten to switch the value label and line cursor on
+*/
+void KLineal::enterEvent(QEvent * /*inEvent*/) {
+ if (!mDragging) showLabel();
+}
+/**
+* overwritten to switch the value label and line cursor off
+*/
+void KLineal::leaveEvent(QEvent * /*inEvent*/) {
+ if (!geometry().contains(QCursor::pos())) {
+ hideLabel();
+ }
+}
+/**
+* shows the value lable
+*/
+void KLineal::showLabel() {
+ adjustLabel();
+ mLabel->show();
+ mColorLabel->show();
+}
+/**
+* hides the value label
+*/
+void KLineal::hideLabel() {
+ mLabel->hide();
+ mColorLabel->hide();
+}
+/**
+* updates the current value label
+*/
+void KLineal::adjustLabel() {
+ QString s;
+ QPoint cpos = QCursor::pos();
+ switch (mOrientation) {
+ case North:
+ s.sprintf("%d px", cpos.x()-x());
+ break;
+ case East:
+ s.sprintf("%d px", cpos.y()-y());
+ break;
+ case West:
+ s.sprintf("%d px", cpos.y()-y());
+ break;
+ case South:
+ s.sprintf("%d px", cpos.x()-x());
+ break;
+ }
+ mLabel->setText(s);
+}
+void KLineal::keyPressEvent(QKeyEvent *e) {
+ QPoint dist(0,0);
+ switch (e->key()) {
+ case Key_F1:
+ kapp->invokeHelp();
+ break;
+ case Key_Left:
+ dist.setX(-1);
+ break;
+ case Key_Right:
+ dist.setX(1);
+ break;
+ case Key_Up:
+ dist.setY(-1);
+ break;
+ case Key_Down:
+ dist.setY(1);
+ break;
+ default:
+ KMainWindow::keyPressEvent(e);
+ return;
+ }
+ if (e->state() & ShiftButton) {
+ dist *= 10;
+ }
+ move(pos()+dist);
+ KNotifyClient::event(0, "cursormove", QString::null);
+}
+/**
+* overwritten to handle the line cursor which is a seperate widget outside the main
+* window. Also used for dragging.
+*/
+void KLineal::mouseMoveEvent(QMouseEvent * /*inEvent*/) {
+ if (mDragging && this == mouseGrabber()) {
+ move(QCursor::pos() - mDragOffset);
+ } else {
+ QPoint p = QCursor::pos();
+ switch (mOrientation) {
+ case North:
+ p.setY(p.y()-46);
+ break;
+ case East:
+ p.setX(p.x()+46);
+ break;
+ case West:
+ p.setX(p.x()-46);
+ break;
+ case South:
+ p.setY(p.y()+46);
+ break;
+ }
+ // cerr << p.x()-x() << "," << p.y()-y() << ": " << KColorDialog::grabColor(p).name() << endl;
+ QColor color = KColorDialog::grabColor(p);
+ int h, s, v;
+ color.hsv(&h, &s, &v);
+ mColorLabel->setText(color.name().upper());
+ mColorLabel->setPaletteBackgroundColor(color);
+ if (v < 255/2) {
+ v = 255;
+ } else {
+ v = 0;
+ }
+ color.setHsv(h, s, v);
+ QPalette palette = mColorLabel->palette();
+ palette.setColor(QColorGroup::Foreground, color);
+ mColorLabel->setPalette(palette);
+ adjustLabel();
+ }
+}
+
+/**
+* overwritten for dragging and contect menu
+*/
+void KLineal::mousePressEvent(QMouseEvent *inEvent) {
+ mLastClickPos = QCursor::pos();
+ hideLabel();
+
+ QRect gr = geometry();
+ mDragOffset = mLastClickPos - QPoint(gr.left(), gr.top());
+ if (inEvent->button() == LeftButton) {
+ if (!mDragging) {
+ grabMouse(KCursor::sizeAllCursor());
+ mDragging = TRUE;
+ }
+ } else if (inEvent->button() == MidButton) {
+ _clicked = true;
+ turnLeft();
+ } else if (inEvent->button() == RightButton) {
+ showMenu();
+ }
+}
+/**
+* overwritten for dragging
+*/
+void KLineal::mouseReleaseEvent(QMouseEvent * /*inEvent*/) {
+ if (mDragging) {
+ mDragging = FALSE;
+ releaseMouse();
+ }
+ showLabel();
+}
+/**
+* draws the scale according to the orientation
+*/
+void KLineal::drawScale(QPainter &painter) {
+ painter.setPen(black);
+ QFont font = mScaleFont;
+ // font.setPixelSize(9);
+ painter.setFont(font);
+ QFontMetrics metrics = painter.fontMetrics();
+ int longCoo;
+ int longLen;
+ int shortStart;
+ int w = width();
+ int h = height();
+
+ // draw a frame around the whole thing
+ // (for some unknown reason, this doesn't show up anymore)
+ switch (mOrientation) {
+ case North:
+ default:
+ shortStart = 0;
+ longLen = w;
+ painter.drawLine(0, 0, 0, h-1);
+ painter.drawLine(0, h-1, w-1, h-1);
+ painter.drawLine(w-1, h-1, w-1, 0);
+ // painter.drawLine(width()-1, 0, 0, 0);
+ break;
+ case East:
+ shortStart = w;
+ longLen = h;
+ painter.drawLine(0, 0, 0, h-1);
+ painter.drawLine(0, h-1, w-1, h-1);
+ // painter.drawLine(width()-1, height()-1, width()-1, 0);
+ painter.drawLine(w-1, 0, 0, 0);
+ break;
+ case South:
+ shortStart = h;
+ longLen = w;
+ painter.drawLine(0, 0, 0, h-1);
+ // painter.drawLine(0, height()-1, width()-1, height()-1);
+ painter.drawLine(w-1, h-1, w-1, 0);
+ painter.drawLine(w-1, 0, 0, 0);
+ break;
+ case West:
+ shortStart = 0;
+ longLen = h;
+ // painter.drawLine(0, 0, 0, height()-1);
+ painter.drawLine(0, h-1, w-1, h-1);
+ painter.drawLine(w-1, h-1, w-1, 0);
+ painter.drawLine(w-1, 0, 0, 0);
+ break;
+ }
+ int ten = 10, twenty = 20, fourty = 40, hundred = 100;
+ for (longCoo = 0; longCoo < longLen; longCoo+=2) {
+ int len = 6;
+ if (ten == 10) {
+ if (twenty == 20) {
+ /**/
+ if (hundred == 100) {
+ font.setBold(true);
+ painter.setFont(font);
+ len = 18;
+ } else {
+ len = 15;
+ }
+ QString units;
+ int digits;
+ if (hundred == 100 || mOrientation == West || mOrientation == East) {
+ digits = longCoo;
+ } else {
+ digits = longCoo % 100;
+ }
+ units.sprintf("%d", digits);
+ QSize textSize = metrics.size(SingleLine, units);
+ int tw = textSize.width();
+ int th = textSize.height();
+ switch (mOrientation) {
+ case North:
+ if (digits < 1000 || fourty == 40 || hundred == 100) {
+ if (longCoo != 0) {
+ painter.drawText(longCoo - tw/2, shortStart + len + th, units);
+ } else {
+ painter.drawText(1, shortStart + len + th, units);
+ }
+ }
+ break;
+ case South:
+ if (digits < 1000 || fourty == 40 || hundred == 100) {
+ if (longCoo != 0) {
+ painter.drawText(longCoo - tw/2, shortStart - len - 2, units);
+ } else {
+ painter.drawText(1, shortStart - len - 2, units);
+ }
+ }
+ break;
+ case East:
+ if (longCoo != 0) {
+ painter.drawText(shortStart - len - tw - 2, longCoo + th/2 - 2, units);
+ } else {
+ painter.drawText(shortStart - len - tw - 2, th-2, units);
+ }
+ break;
+ case West:
+ if (longCoo != 0) {
+ painter.drawText(shortStart + len + 2, longCoo + th/2 - 2, units);
+ } else {
+ painter.drawText(shortStart + len + 2, th-2, units);
+ }
+ break;
+ }
+ } else {
+ len = 10;
+ }
+ }
+ switch(mOrientation) {
+ case North:
+ painter.drawLine(longCoo, shortStart, longCoo, shortStart+len);
+ break;
+ case South:
+ painter.drawLine(longCoo, shortStart, longCoo, shortStart-len);
+ break;
+ case East:
+ painter.drawLine(shortStart, longCoo, shortStart-len, longCoo);
+ break;
+ case West:
+ painter.drawLine(shortStart, longCoo, shortStart+len, longCoo);
+ break;
+ }
+ ten = (ten == 10) ? 2: ten + 2;
+ twenty = (twenty == 20) ? 2: twenty + 2;
+ fourty = (fourty == 40) ? 2: fourty + 2;
+ if (hundred == 100) {
+ hundred = 2;
+ font.setBold(false);
+ painter.setFont(font);
+ } else {
+ hundred += 2;
+ }
+ }
+}
+/**
+* actually draws the ruler
+*/
+void KLineal::paintEvent(QPaintEvent * /*inEvent*/) {
+ QPainter painter;
+ painter.begin(this);
+ drawScale(painter);
+ painter.end();
+}
+
+#include "klineal.moc"
diff --git a/kruler/klineal.h b/kruler/klineal.h
new file mode 100644
index 00000000..6fcf7015
--- /dev/null
+++ b/kruler/klineal.h
@@ -0,0 +1,106 @@
+/***************************************************************************
+ klineal.h - description
+ -------------------
+ begin : Fri Oct 13 2000
+ copyright : (C) 2000 by Till Krech
+ email : till@snafu.de
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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. *
+ * *
+ ***************************************************************************/
+
+#ifndef KLINEAL_H
+#define KLINEAL_H
+
+#include <kapplication.h>
+#include <kpopupmenu.h>
+#include <kmainwindow.h>
+
+#include <kcolordialog.h>
+#include <kfontdialog.h>
+
+#include <qlabel.h>
+#include <qpainter.h>
+#include <qwidget.h>
+#include <qcursor.h>
+
+class KLineal : public KMainWindow {
+ Q_OBJECT
+public:
+ enum { North=0, West=1, South=2, East=3 };
+ /** constructor */
+ KLineal(QWidget*parent=0,const char* name=0);
+ /** destructor */
+ ~KLineal();
+ void move(int x, int y);
+ void move(const QPoint &p);
+ QPoint pos();
+ int x();
+ int y();
+protected:
+ void keyPressEvent(QKeyEvent *e);
+ void mousePressEvent(QMouseEvent *e);
+ void mouseReleaseEvent(QMouseEvent *e);
+ void mouseMoveEvent(QMouseEvent *e);
+ void paintEvent(QPaintEvent *e);
+ void enterEvent(QEvent *e);
+ void leaveEvent(QEvent *e);
+ void setupBackground();
+
+
+private:
+ void drawScale(QPainter &painter);
+ void reLength(int percentOfScreen);
+ bool mDragging;
+ QPoint mLastClickPos;
+ QPoint mDragOffset;
+ QLabel *mLabel;
+ QLabel *mColorLabel;
+ QFrame *mColorRect;
+ int mOrientation;
+ int mLongEdgeLen;
+ int mShortEdgeLen;
+ KPopupMenu *mMenu;
+ KPopupMenu *mLenMenu;
+ QColor mColor;
+ QColor mStoredColor;
+ QCursor mCurrentCursor;
+ QCursor mNorthCursor;
+ QCursor mEastCursor;
+ QCursor mWestCursor;
+ QCursor mSouthCursor;
+ QCursor mDragCursor;
+ KColorDialog mColorSelector;
+ QFont mScaleFont;
+ bool _clicked;
+public slots:
+ void setOrientation(int);
+ void setNorth();
+ void setEast();
+ void setSouth();
+ void setWest();
+ void turnLeft();
+ void turnRight();
+ void showMenu();
+ void hideLabel();
+ void showLabel();
+ void adjustLabel();
+ void setShortLength();
+ void setMediumLength();
+ void setTallLength();
+ void setFullLength();
+ void setColor();
+ void setFont(QFont &);
+ void setColor(const QColor &color);
+ void choseColor();
+ void choseFont();
+ void restoreColor();
+ void saveSettings();
+};
+#endif
diff --git a/kruler/kruler.desktop b/kruler/kruler.desktop
new file mode 100644
index 00000000..0d9e4cc6
--- /dev/null
+++ b/kruler/kruler.desktop
@@ -0,0 +1,90 @@
+[Desktop Entry]
+GenericName=Screen Ruler
+GenericName[af]=Skerm Liniaal
+GenericName[ar]=مسطرة الشاشة
+GenericName[bg]=Линийка за екрана
+GenericName[bs]=Ekranski linijar
+GenericName[ca]=Regla de pantalla
+GenericName[cs]=Obrazovkové pravítko
+GenericName[cy]=Mesurydd Sgrîn
+GenericName[da]=Skærmlineal
+GenericName[de]=Bildschirmlineal
+GenericName[el]=Χάρακας οθόνης
+GenericName[eo]=Ekranliniilo
+GenericName[es]=Regla para la pantalla
+GenericName[et]=Ekraani joonlaud
+GenericName[eu]=Pantaila erregela
+GenericName[fa]=خط‌کش پرده
+GenericName[fi]=Näytön mittaaja
+GenericName[fr]=Règle d'écran
+GenericName[gl]=Regra de pantalla
+GenericName[he]=סרגל מסך
+GenericName[hi]=स्क्रीन रूलर
+GenericName[hr]=Ravnalo
+GenericName[hu]=Képernyővonalzó
+GenericName[is]=Reglustika
+GenericName[it]=Righello per lo schermo
+GenericName[ja]=スクリーン定規
+GenericName[kk]=Экран өлшегіші
+GenericName[km]=បន្ទាត់​អេក្រង់
+GenericName[lt]=Ekrano liniuotė
+GenericName[lv]=Ekrāna Mērjosla
+GenericName[ms]=Pembaris Skrin
+GenericName[nb]=Skjermlinjal
+GenericName[nds]=Schirmlineaal
+GenericName[ne]=पर्दा रूलर
+GenericName[nl]=Schermliniaal
+GenericName[nn]=Skjermlinjal
+GenericName[pl]=Linijka ekranowa
+GenericName[pt]=Régua do Ecrã
+GenericName[pt_BR]=Régua da Tela
+GenericName[ro]=Riglă de ecran
+GenericName[ru]=Экранная линейка KDE
+GenericName[se]=Šearpmalinjála
+GenericName[sk]=Pravítko obrazovky
+GenericName[sl]=Zaslonsko ravnilo
+GenericName[sr]=Екрански лењир
+GenericName[sr@Latn]=Ekranski lenjir
+GenericName[sv]=Skärmlinjal
+GenericName[ta]=திரை உருளை
+GenericName[tg]=Ҷадвали экрании KDE
+GenericName[th]=ไม้บรรทัดสำหรับจอภาพ
+GenericName[tr]=Ekran Cetveli
+GenericName[uk]=Лінійка екрана
+GenericName[uz]=Ekran lineykasi
+GenericName[uz@cyrillic]=Экран линейкаси
+GenericName[ven]=Muvhusi wa Tshikirini
+GenericName[zh_CN]=屏幕标尺
+GenericName[zh_HK]=螢幕尺規
+GenericName[zh_TW]=螢幕尺規
+GenericName[zu]=Umlawuli Wesikrini
+Name=KRuler
+Name[af]=K-lineaal
+Name[ar]=المسطرة (KRuler)
+Name[cy]=KMesurydd
+Name[eo]=Liniilo
+Name[hi]=के-रूलर
+Name[hr]=Ravnalo
+Name[is]=KReglustika
+Name[lv]=KRulers
+Name[ms]=KPembaris
+Name[ne]=केडीई रूलर
+Name[pl]=Linijka
+Name[pt_BR]=KRégua
+Name[ro]=Riglă
+Name[sv]=Kruler
+Name[ta]=கேவரை உருளை
+Name[th]=ไม้บรรทัด - K
+Name[ven]=Muvhusi wa K
+Name[zh_TW]=KRuler 尺規
+Name[zu]=KUmlawuli
+DocPath=kruler/index.html
+MimeType=
+Exec=kruler %i %m
+Type=Application
+Path=
+Icon=kruler
+Terminal=false
+X-KDE-StartupNotify=true
+X-DCOP-ServiceType=Multi
+Categories=Qt;KDE;Graphics;X-KDE-More;
diff --git a/kruler/main.cpp b/kruler/main.cpp
new file mode 100644
index 00000000..484ca318
--- /dev/null
+++ b/kruler/main.cpp
@@ -0,0 +1,48 @@
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <klocale.h>
+
+#include "klineal.h"
+
+static const char homePageURL[] =
+ "http://www.snafu.de/~till/";
+static const char freeFormText[] =
+ "\"May the source be with you.\"";
+
+
+
+static KCmdLineOptions options[] =
+{
+ KCmdLineLastOption
+ // INSERT YOUR COMMANDLINE OPTIONS HERE
+};
+
+int main(int argc, char *argv[])
+{
+
+
+ KAboutData aboutData( "kruler", I18N_NOOP("KDE Screen Ruler"),
+ VERSION,
+ I18N_NOOP("A screen ruler for the K Desktop Environment"),
+ KAboutData::License_GPL,
+ "(c) 2000, Till Krech",
+ freeFormText,
+ homePageURL);
+ aboutData.addAuthor("Till Krech",I18N_NOOP("Programming"), "till@snafu.de");
+ aboutData.addCredit("Gunnstein Lye",I18N_NOOP("Initial port to KDE 2"), "gl@ez.no");
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
+
+ KApplication a;
+
+ KLineal *ruler = new KLineal();
+ a.setMainWidget(ruler);
+ ruler->show();
+
+ return a.exec();
+}
diff --git a/kruler/move.wav b/kruler/move.wav
new file mode 100644
index 00000000..4922ac4b
--- /dev/null
+++ b/kruler/move.wav
Binary files differ
diff --git a/kruler/pics/Makefile.am b/kruler/pics/Makefile.am
new file mode 100644
index 00000000..e29a8776
--- /dev/null
+++ b/kruler/pics/Makefile.am
@@ -0,0 +1,5 @@
+
+pixdir = $(kde_datadir)/kruler/pics
+pix_DATA = kruler-east.png kruler-north.png kruler-south.png kruler-west.png
+
+KDE_ICON = kruler
diff --git a/kruler/pics/hi16-app-kruler.png b/kruler/pics/hi16-app-kruler.png
new file mode 100644
index 00000000..dd1b953c
--- /dev/null
+++ b/kruler/pics/hi16-app-kruler.png
Binary files differ
diff --git a/kruler/pics/hi22-app-kruler.png b/kruler/pics/hi22-app-kruler.png
new file mode 100644
index 00000000..32d29686
--- /dev/null
+++ b/kruler/pics/hi22-app-kruler.png
Binary files differ
diff --git a/kruler/pics/hi32-app-kruler.png b/kruler/pics/hi32-app-kruler.png
new file mode 100644
index 00000000..bd4cc0f5
--- /dev/null
+++ b/kruler/pics/hi32-app-kruler.png
Binary files differ
diff --git a/kruler/pics/hi48-app-kruler.png b/kruler/pics/hi48-app-kruler.png
new file mode 100644
index 00000000..6e35b591
--- /dev/null
+++ b/kruler/pics/hi48-app-kruler.png
Binary files differ
diff --git a/kruler/pics/kruler-east.png b/kruler/pics/kruler-east.png
new file mode 100644
index 00000000..1a87ae7d
--- /dev/null
+++ b/kruler/pics/kruler-east.png
Binary files differ
diff --git a/kruler/pics/kruler-north.png b/kruler/pics/kruler-north.png
new file mode 100644
index 00000000..32d29686
--- /dev/null
+++ b/kruler/pics/kruler-north.png
Binary files differ
diff --git a/kruler/pics/kruler-south.png b/kruler/pics/kruler-south.png
new file mode 100644
index 00000000..d6c3eb5c
--- /dev/null
+++ b/kruler/pics/kruler-south.png
Binary files differ
diff --git a/kruler/pics/kruler-west.png b/kruler/pics/kruler-west.png
new file mode 100644
index 00000000..473ac39b
--- /dev/null
+++ b/kruler/pics/kruler-west.png
Binary files differ
diff --git a/kruler/uninstall.desktop b/kruler/uninstall.desktop
new file mode 100644
index 00000000..e1e3e173
--- /dev/null
+++ b/kruler/uninstall.desktop
@@ -0,0 +1,2 @@
+[Desktop Entry]
+Hidden=true
diff --git a/ksnapshot/Makefile.am b/ksnapshot/Makefile.am
new file mode 100644
index 00000000..a9dae435
--- /dev/null
+++ b/ksnapshot/Makefile.am
@@ -0,0 +1,21 @@
+bin_PROGRAMS= ksnapshot
+
+INCLUDES = -DKSNAPVERSION="\"0.7\"" $(all_includes)
+
+ksnapshot_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+ksnapshot_LDADD = $(LIB_KDEPRINT)
+
+ksnapshot_SOURCES = ksnapshotiface.skel main.cpp ksnapshot.cpp \
+ regiongrabber.cpp windowgrabber.cpp ksnapshotwidget.ui
+
+ksnapshot_METASOURCES = AUTO
+
+xdg_apps_DATA = ksnapshot.desktop
+
+KDE_ICON = ksnapshot
+
+EXTRA_DIST = $(xdg_apps_DATA)
+
+messages: rc.cpp
+ $(XGETTEXT) rc.cpp *.cpp -o $(podir)/ksnapshot.pot
+
diff --git a/ksnapshot/README b/ksnapshot/README
new file mode 100644
index 00000000..0aa0b121
--- /dev/null
+++ b/ksnapshot/README
@@ -0,0 +1,29 @@
+ KSnapshot Release Notes
+ =======================
+
+KSnapshot is intended to be an easy to use program for making
+screenshots. I can be bound to the Print Screen" key, as the program
+takes a snapshot of the desktop on startup (before it displays it
+window), so it's a simple way of of making snapshots.
+
+Currently Implemented features:
+
+- Mini Preview image
+- Adjustable time delay.
+- Auto hides it own window when grabbing.
+- Grabs desktop or specific windows
+- Save to various formats
+- Auto increment filename
+
+
+The original KSnapshot was implemented by Richard Moore (rich@kde.org)
+for KDE1. Shortly before KDE2 I rewrote most of it to bring it a bit
+closer to KDE2' higher standards.
+
+This version is still not good, but I wanted something that doesn't
+break translations and is still comfortable to old ksnapshot users.
+
+Use Pixie if you want more functionality.
+
+Matthias ( ettrich@kde.org)
+
diff --git a/ksnapshot/configure.in.in b/ksnapshot/configure.in.in
new file mode 100644
index 00000000..56c82023
--- /dev/null
+++ b/ksnapshot/configure.in.in
@@ -0,0 +1,6 @@
+dnl Check for the X shaped windows extension - test taken from kdebase/kwin/clients/keramik
+KDE_CHECK_HEADERS(X11/extensions/shape.h,,,
+[
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+])
diff --git a/ksnapshot/hi16-app-ksnapshot.png b/ksnapshot/hi16-app-ksnapshot.png
new file mode 100644
index 00000000..79743e82
--- /dev/null
+++ b/ksnapshot/hi16-app-ksnapshot.png
Binary files differ
diff --git a/ksnapshot/hi22-app-ksnapshot.png b/ksnapshot/hi22-app-ksnapshot.png
new file mode 100644
index 00000000..446af476
--- /dev/null
+++ b/ksnapshot/hi22-app-ksnapshot.png
Binary files differ
diff --git a/ksnapshot/hi32-app-ksnapshot.png b/ksnapshot/hi32-app-ksnapshot.png
new file mode 100644
index 00000000..4619ae8d
--- /dev/null
+++ b/ksnapshot/hi32-app-ksnapshot.png
Binary files differ
diff --git a/ksnapshot/hi48-app-ksnapshot.png b/ksnapshot/hi48-app-ksnapshot.png
new file mode 100644
index 00000000..f962f5a0
--- /dev/null
+++ b/ksnapshot/hi48-app-ksnapshot.png
Binary files differ
diff --git a/ksnapshot/hisc-app-ksnapshot.svgz b/ksnapshot/hisc-app-ksnapshot.svgz
new file mode 100644
index 00000000..22f4e3fb
--- /dev/null
+++ b/ksnapshot/hisc-app-ksnapshot.svgz
Binary files differ
diff --git a/ksnapshot/ksnapshot.cpp b/ksnapshot/ksnapshot.cpp
new file mode 100644
index 00000000..a0e1d06f
--- /dev/null
+++ b/ksnapshot/ksnapshot.cpp
@@ -0,0 +1,510 @@
+/*
+ * KSnapshot
+ *
+ * (c) Richard J. Moore 1997-2002
+ * (c) Matthias Ettrich 2000
+ * (c) Aaron J. Seigo 2002
+ * (c) Nadeem Hasan 2003
+ * (c) Bernd Brandstetter 2004
+ *
+ * Released under the LGPL see file LICENSE for details.
+ */
+
+
+#include <klocale.h>
+#include <kimageio.h>
+#include <kfiledialog.h>
+#include <kimagefilepreview.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <kapplication.h>
+#include <kprinter.h>
+#include <kio/netaccess.h>
+#include <ksavefile.h>
+#include <ktempfile.h>
+
+#include <qbitmap.h>
+#include <qdragobject.h>
+#include <qimage.h>
+#include <qclipboard.h>
+#include <qvbox.h>
+
+#include <kaccel.h>
+#include <knotifyclient.h>
+#include <khelpmenu.h>
+#include <kpopupmenu.h>
+#include <kpushbutton.h>
+#include <kstartupinfo.h>
+
+#include <qcursor.h>
+#include <qregexp.h>
+#include <qpainter.h>
+#include <qpaintdevicemetrics.h>
+#include <qwhatsthis.h>
+
+#include <stdlib.h>
+
+#include "ksnapshot.h"
+#include "regiongrabber.h"
+#include "windowgrabber.h"
+#include "ksnapshotwidget.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+#include <config.h>
+
+#include <kglobal.h>
+
+#define kApp KApplication::kApplication()
+
+KSnapshot::KSnapshot(QWidget *parent, const char *name, bool grabCurrent)
+ : DCOPObject("interface"),
+ KDialogBase(parent, name, true, QString::null, Help|User1, User1,
+ true, KStdGuiItem::quit() )
+{
+ grabber = new QWidget( 0, 0, WStyle_Customize | WX11BypassWM );
+ grabber->move( -1000, -1000 );
+ grabber->installEventFilter( this );
+
+ KStartupInfo::appStarted();
+
+ QVBox *vbox = makeVBoxMainWidget();
+ mainWidget = new KSnapshotWidget( vbox, "mainWidget" );
+
+ connect(mainWidget, SIGNAL(startImageDrag()), SLOT(slotDragSnapshot()));
+
+ connect( mainWidget, SIGNAL( newClicked() ), SLOT( slotGrab() ) );
+ connect( mainWidget, SIGNAL( saveClicked() ), SLOT( slotSaveAs() ) );
+ connect( mainWidget, SIGNAL( printClicked() ), SLOT( slotPrint() ) );
+ connect( mainWidget, SIGNAL( copyClicked() ), SLOT( slotCopy() ) );
+
+ grabber->show();
+ grabber->grabMouse( waitCursor );
+
+ if ( !grabCurrent )
+ snapshot = QPixmap::grabWindow( qt_xrootwin() );
+ else {
+ mainWidget->setMode( WindowUnderCursor );
+ mainWidget->setIncludeDecorations( true );
+ performGrab();
+ }
+
+ updatePreview();
+ grabber->releaseMouse();
+ grabber->hide();
+
+ KConfig *conf=KGlobal::config();
+ conf->setGroup("GENERAL");
+ mainWidget->setDelay(conf->readNumEntry("delay",0));
+ mainWidget->setMode( conf->readNumEntry( "mode", 0 ) );
+ mainWidget->setIncludeDecorations(conf->readBoolEntry("includeDecorations",true));
+ filename = KURL::fromPathOrURL( conf->readPathEntry( "filename", QDir::currentDirPath()+"/"+i18n("snapshot")+"1.png" ));
+
+ // Make sure the name is not already being used
+ while(KIO::NetAccess::exists( filename, false, this )) {
+ autoincFilename();
+ }
+
+ connect( &grabTimer, SIGNAL( timeout() ), this, SLOT( grabTimerDone() ) );
+ connect( &updateTimer, SIGNAL( timeout() ), this, SLOT( updatePreview() ) );
+ QTimer::singleShot( 0, this, SLOT( updateCaption() ) );
+
+ KHelpMenu *helpMenu = new KHelpMenu(this, KGlobal::instance()->aboutData(), false);
+
+ QPushButton *helpButton = actionButton( Help );
+ helpButton->setPopup(helpMenu->menu());
+
+ KAccel* accel = new KAccel(this);
+ accel->insert(KStdAccel::Quit, kapp, SLOT(quit()));
+ accel->insert( "QuickSave", i18n("Quick Save Snapshot &As..."),
+ i18n("Save the snapshot to the file specified by the user without showing the file dialog."),
+ CTRL+SHIFT+Key_S, this, SLOT(slotSave()));
+ accel->insert(KStdAccel::Save, this, SLOT(slotSaveAs()));
+// accel->insert(KShortcut(CTRL+Key_A), this, SLOT(slotSaveAs()));
+ accel->insert( "SaveAs", i18n("Save Snapshot &As..."),
+ i18n("Save the snapshot to the file specified by the user."),
+ CTRL+Key_A, this, SLOT(slotSaveAs()));
+ accel->insert(KStdAccel::Print, this, SLOT(slotPrint()));
+ accel->insert(KStdAccel::New, this, SLOT(slotGrab()));
+ accel->insert(KStdAccel::Copy, this, SLOT(slotCopy()));
+
+ accel->insert( "Quit2", Key_Q, this, SLOT(slotSave()));
+ accel->insert( "Save2", Key_S, this, SLOT(slotSaveAs()));
+ accel->insert( "Print2", Key_P, this, SLOT(slotPrint()));
+ accel->insert( "New2", Key_N, this, SLOT(slotGrab()));
+ accel->insert( "New3", Key_Space, this, SLOT(slotGrab()));
+
+ setEscapeButton( User1 );
+ connect( this, SIGNAL( user1Clicked() ), SLOT( reject() ) );
+
+ mainWidget->btnNew->setFocus();
+}
+
+KSnapshot::~KSnapshot()
+{
+}
+
+void KSnapshot::resizeEvent( QResizeEvent *event)
+{
+ if( !updateTimer.isActive() )
+ updateTimer.start(200, true);
+ else
+ updateTimer.changeInterval(200);
+}
+
+bool KSnapshot::save( const QString &filename )
+{
+ return save( KURL::fromPathOrURL( filename ));
+}
+
+bool KSnapshot::save( const KURL& url )
+{
+ if ( KIO::NetAccess::exists( url, false, this ) ) {
+ const QString title = i18n( "File Exists" );
+ const QString text = i18n( "<qt>Do you really want to overwrite <b>%1</b>?</qt>" ).arg(url.prettyURL());
+ if (KMessageBox::Continue != KMessageBox::warningContinueCancel( this, text, title, i18n("Overwrite") ) )
+ {
+ return false;
+ }
+ }
+
+ QString type( KImageIO::type(url.path()) );
+ if ( type.isNull() )
+ type = "PNG";
+
+ bool ok = false;
+
+ if ( url.isLocalFile() ) {
+ KSaveFile saveFile( url.path() );
+ if ( saveFile.status() == 0 ) {
+ if ( snapshot.save( saveFile.file(), type.latin1() ) )
+ ok = saveFile.close();
+ }
+ }
+ else {
+ KTempFile tmpFile;
+ tmpFile.setAutoDelete( true );
+ if ( tmpFile.status() == 0 ) {
+ if ( snapshot.save( tmpFile.file(), type.latin1() ) ) {
+ if ( tmpFile.close() )
+ ok = KIO::NetAccess::upload( tmpFile.name(), url, this );
+ }
+ }
+ }
+
+ QApplication::restoreOverrideCursor();
+ if ( !ok ) {
+ kdWarning() << "KSnapshot was unable to save the snapshot" << endl;
+
+ QString caption = i18n("Unable to save image");
+ QString text = i18n("KSnapshot was unable to save the image to\n%1.")
+ .arg(url.prettyURL());
+ KMessageBox::error(this, text, caption);
+ }
+
+ return ok;
+}
+
+void KSnapshot::slotSave()
+{
+ if ( save(filename) ) {
+ modified = false;
+ autoincFilename();
+ }
+}
+
+void KSnapshot::slotSaveAs()
+{
+ QStringList mimetypes = KImageIO::mimeTypes( KImageIO::Writing );
+ KFileDialog dlg( filename.url(), mimetypes.join(" "), this, "filedialog", true);
+
+ dlg.setOperationMode( KFileDialog::Saving );
+ dlg.setCaption( i18n("Save As") );
+
+ KImageFilePreview *ip = new KImageFilePreview( &dlg );
+ dlg.setPreviewWidget( ip );
+
+ if ( !dlg.exec() )
+ return;
+
+ KURL url = dlg.selectedURL();
+ if ( !url.isValid() )
+ return;
+
+ if ( save(url) ) {
+ filename = url;
+ modified = false;
+ autoincFilename();
+ }
+}
+
+void KSnapshot::slotCopy()
+{
+ QClipboard *cb = QApplication::clipboard();
+ cb->setPixmap( snapshot );
+}
+
+void KSnapshot::slotDragSnapshot()
+{
+ QDragObject *drobj = new QImageDrag(snapshot.convertToImage(), this);
+ drobj->setPixmap(mainWidget->preview());
+ drobj->dragCopy();
+}
+
+void KSnapshot::slotGrab()
+{
+ hide();
+
+ if ( mainWidget->delay() && mainWidget->mode() != Region )
+ grabTimer.start( mainWidget->delay() * 1000, true );
+ else {
+ if ( mainWidget->mode() == Region ) {
+ rgnGrab = new RegionGrabber();
+ connect( rgnGrab, SIGNAL( regionGrabbed( const QPixmap & ) ),
+ SLOT( slotRegionGrabbed( const QPixmap & ) ) );
+ }
+ else {
+ grabber->show();
+ grabber->grabMouse( crossCursor );
+ }
+ }
+}
+
+void KSnapshot::slotPrint()
+{
+ KPrinter printer;
+ if (snapshot.width() > snapshot.height())
+ printer.setOrientation(KPrinter::Landscape);
+ else
+ printer.setOrientation(KPrinter::Portrait);
+
+ qApp->processEvents();
+
+ if (printer.setup(this, i18n("Print Screenshot")))
+ {
+ qApp->processEvents();
+
+ QPainter painter(&printer);
+ QPaintDeviceMetrics metrics(painter.device());
+
+ float w = snapshot.width();
+ float dw = w - metrics.width();
+ float h = snapshot.height();
+ float dh = h - metrics.height();
+ bool scale = false;
+
+ if ( (dw > 0.0) || (dh > 0.0) )
+ scale = true;
+
+ if ( scale ) {
+
+ QImage img = snapshot.convertToImage();
+ qApp->processEvents();
+
+ float newh, neww;
+ if ( dw > dh ) {
+ neww = w-dw;
+ newh = neww/w*h;
+ }
+ else {
+ newh = h-dh;
+ neww = newh/h*w;
+ }
+
+ img = img.smoothScale( int(neww), int(newh), QImage::ScaleMin );
+ qApp->processEvents();
+
+ int x = (metrics.width()-img.width())/2;
+ int y = (metrics.height()-img.height())/2;
+
+ painter.drawImage( x, y, img);
+ }
+ else {
+ int x = (metrics.width()-snapshot.width())/2;
+ int y = (metrics.height()-snapshot.height())/2;
+ painter.drawPixmap( x, y, snapshot );
+ }
+ }
+
+ qApp->processEvents();
+}
+
+void KSnapshot::slotRegionGrabbed( const QPixmap &pix )
+{
+ if ( !pix.isNull() )
+ {
+ snapshot = pix;
+ updatePreview();
+ modified = true;
+ updateCaption();
+ }
+
+ delete rgnGrab;
+ QApplication::restoreOverrideCursor();
+ show();
+}
+
+void KSnapshot::slotWindowGrabbed( const QPixmap &pix )
+{
+ if ( !pix.isNull() )
+ {
+ snapshot = pix;
+ updatePreview();
+ modified = true;
+ updateCaption();
+ }
+
+ QApplication::restoreOverrideCursor();
+ show();
+}
+
+void KSnapshot::closeEvent( QCloseEvent * e )
+{
+ KConfig *conf=KGlobal::config();
+ conf->setGroup("GENERAL");
+ conf->writeEntry("delay",mainWidget->delay());
+ conf->writeEntry("mode",mainWidget->mode());
+ conf->writeEntry("includeDecorations",mainWidget->includeDecorations());
+ KURL url = filename;
+ url.setPass( QString::null );
+ conf->writePathEntry("filename",url.url());
+ e->accept();
+}
+
+bool KSnapshot::eventFilter( QObject* o, QEvent* e)
+{
+ if ( o == grabber && e->type() == QEvent::MouseButtonPress ) {
+ QMouseEvent* me = (QMouseEvent*) e;
+ if ( QWidget::mouseGrabber() != grabber )
+ return false;
+ if ( me->button() == LeftButton )
+ performGrab();
+ }
+ return false;
+}
+
+void KSnapshot::autoincFilename()
+{
+ // Extract the filename from the path
+ QString name= filename.fileName();
+
+ // If the name contains a number then increment it
+ QRegExp numSearch("[0-9]+");
+
+ // Does it have a number?
+ int start = numSearch.search(name);
+ if (start != -1) {
+ // It has a number, increment it
+ int len = numSearch.matchedLength();
+ QString numAsStr= name.mid(start, len);
+ QString number = QString::number(numAsStr.toInt() + 1);
+ number = number.rightJustify( len, '0');
+ name.replace(start, len, number );
+ }
+ else {
+ // no number
+ start = name.findRev('.');
+ if (start != -1) {
+ // has a . somewhere, e.g. it has an extension
+ name.insert(start, '1');
+ }
+ else {
+ // no extension, just tack it on to the end
+ name += '1';
+ }
+ }
+
+ //Rebuild the path
+ KURL newURL = filename;
+ newURL.setFileName( name );
+ setURL( newURL.url() );
+}
+
+void KSnapshot::updatePreview()
+{
+ mainWidget->setPreview( snapshot );
+}
+
+void KSnapshot::grabTimerDone()
+{
+ if ( mainWidget->mode() == Region ) {
+ rgnGrab = new RegionGrabber();
+ connect( rgnGrab, SIGNAL( regionGrabbed( const QPixmap & ) ),
+ SLOT( slotRegionGrabbed( const QPixmap & ) ) );
+ }
+ else {
+ performGrab();
+ }
+ KNotifyClient::beep(i18n("The screen has been successfully grabbed."));
+}
+
+void KSnapshot::performGrab()
+{
+ grabber->releaseMouse();
+ grabber->hide();
+ grabTimer.stop();
+ if ( mainWidget->mode() == ChildWindow ) {
+ WindowGrabber wndGrab;
+ connect( &wndGrab, SIGNAL( windowGrabbed( const QPixmap & ) ),
+ SLOT( slotWindowGrabbed( const QPixmap & ) ) );
+ wndGrab.exec();
+ }
+ else if ( mainWidget->mode() == WindowUnderCursor ) {
+ snapshot = WindowGrabber::grabCurrent( mainWidget->includeDecorations() );
+ }
+ else {
+ snapshot = QPixmap::grabWindow( qt_xrootwin() );
+ }
+ updatePreview();
+ QApplication::restoreOverrideCursor();
+ modified = true;
+ updateCaption();
+ show();
+}
+
+void KSnapshot::setTime(int newTime)
+{
+ mainWidget->setDelay(newTime);
+}
+
+int KSnapshot::timeout()
+{
+ return mainWidget->delay();
+}
+
+void KSnapshot::setURL( const QString &url )
+{
+ KURL newURL = KURL::fromPathOrURL( url );
+ if ( newURL == filename )
+ return;
+
+ filename = newURL;
+ updateCaption();
+}
+
+void KSnapshot::setGrabMode( int m )
+{
+ mainWidget->setMode( m );
+}
+
+int KSnapshot::grabMode()
+{
+ return mainWidget->mode();
+}
+
+void KSnapshot::updateCaption()
+{
+ setCaption( kApp->makeStdCaption( filename.fileName(), true, modified ) );
+}
+
+void KSnapshot::slotMovePointer(int x, int y)
+{
+ QCursor::setPos( x, y );
+}
+
+void KSnapshot::exit()
+{
+ reject();
+}
+#include "ksnapshot.moc"
diff --git a/ksnapshot/ksnapshot.desktop b/ksnapshot/ksnapshot.desktop
new file mode 100644
index 00000000..311a2199
--- /dev/null
+++ b/ksnapshot/ksnapshot.desktop
@@ -0,0 +1,92 @@
+[Desktop Entry]
+GenericName=Screen Capture Program
+GenericName[af]=Skerm Vang Program
+GenericName[ar]=برنامج تصوير الشاشة
+GenericName[bg]=Снимки на екрана
+GenericName[bs]=Program za "hvatanje" slike
+GenericName[ca]=Programa de captura de pantalla
+GenericName[cs]=Snímač obrazovky
+GenericName[cy]=Rhaglen Cipio'r Sgrîn
+GenericName[da]=Program til øjebliksbilleder
+GenericName[de]=Bildschirmphotos
+GenericName[el]=Πρόγραμμα σύλληψης οθόνης
+GenericName[eo]=Ekranfota programo
+GenericName[es]=Capturador de pantalla
+GenericName[et]=Töölaua pildistamine
+GenericName[eu]=Pantailari argazkiak ateratzeko programa
+GenericName[fa]=برنامۀ گیراندازی پرده
+GenericName[fi]=Ruudunkaappausohjelma
+GenericName[fr]=Logiciel de capture d'écran
+GenericName[ga]=Clár gabhála scáileáin
+GenericName[gl]=Progama para facer capturas de pantalla
+GenericName[he]=תוכנית לצילום המסך
+GenericName[hi]=स्क्रीन केप्चर प्रोग्राम
+GenericName[hr]=Program za snimanje zaslona
+GenericName[hu]=Képlopó
+GenericName[is]=Forrit sem grípur skjámyndir
+GenericName[it]=Scatta foto allo schermo
+GenericName[ja]=スクリーンキャプチャプログラム
+GenericName[kk]=Экраннан түсіріп алу бағдарламасы
+GenericName[km]=កម្មវិធី​ចាប់យក​អេក្រង់
+GenericName[lt]=Ekrano kopijos programa
+GenericName[lv]=Ekrāna Sagrābšanas Programma
+GenericName[ms]=Program Cekupan Skrin
+GenericName[mt]=Programm biex tieħu "ritratt" tal-iskrin
+GenericName[nb]=Skjermdumpprogram
+GenericName[nds]=Schirmfotos opnehmen
+GenericName[ne]=पर्दा समात्ने कार्यक्रम
+GenericName[nl]=Schermafdrukprogramma
+GenericName[nn]=Program for skjermbilete
+GenericName[nso]=Lenaneo lago Apesa Pontsho
+GenericName[pl]=Program do zrzutów ekranu
+GenericName[pt]=Programa de Captura do Ecrã
+GenericName[pt_BR]=Programa de Captura de Tela
+GenericName[ro]=Program de captură de ecran
+GenericName[ru]=Создание снимков экрана
+GenericName[rw]=Porogaramu Gufata Mugaragaza
+GenericName[se]=Šearbmagovvenprográmma
+GenericName[sk]=Zachytenie obrazovky
+GenericName[sl]=Program za zajem zaslona
+GenericName[sr]=Програм за снимање екрана
+GenericName[sr@Latn]=Program za snimanje ekrana
+GenericName[sv]=Ta en skärmdump
+GenericName[ta]=திரை கைப்பற்றும் நிரலி
+GenericName[tg]=Эҷоди суратҳои экран
+GenericName[th]=โปรแกรมจับภาพหน้าจอ
+GenericName[tr]=Ekran Yakalama Programı
+GenericName[uk]=Захоплювач екрана
+GenericName[uz]=Skrinshot olish dasturi
+GenericName[uz@cyrillic]=Скриншот олиш дастури
+GenericName[ven]=Mbekanya mushumo ino gavha tshikirini
+GenericName[wa]=Programe po fé des waitroûlêyes
+GenericName[xh]=Iinkcazelo Ezigcina Ikhusi
+GenericName[zh_CN]=屏幕截图程序
+GenericName[zh_HK]=螢幕擷取程式
+GenericName[zh_TW]=畫面擷取程式
+GenericName[zu]=Iprogremu Yokubamba Isikrini
+Name=KSnapshot
+Name[af]=K-kiekie
+Name[cy]=KCipluniau
+Name[eo]=Ekranfotilo
+Name[fr]=KSnapShot
+Name[hi]=के-स्नेपशॉट
+Name[lv]=KSnapšots
+Name[ne]=केडीई स्न्यापसट
+Name[pl]=Zrzuty ekranu
+Name[sv]=Ksnapshot
+Name[ta]=கேதிரையை நகலெடுத்தல்
+Name[th]=จับภาพ - K
+Name[ven]=Tshinepe tsha K
+Name[wa]=KWaitroûlêye
+Name[zh_TW]=KSnapshot 快照
+Name[zu]=KEsincane isithombe
+MimeType=
+Exec=ksnapshot -caption "%c" %i %m
+Icon=ksnapshot
+Path=
+Type=Application
+Terminal=false
+DocPath=ksnapshot/index.html
+X-KDE-StartupNotify=true
+X-DCOP-ServiceType=Multi
+Categories=Qt;KDE;Graphics;
diff --git a/ksnapshot/ksnapshot.h b/ksnapshot/ksnapshot.h
new file mode 100644
index 00000000..486c0a1b
--- /dev/null
+++ b/ksnapshot/ksnapshot.h
@@ -0,0 +1,150 @@
+// -*- c++ -*-
+
+#ifndef KSNAPSHOT_H
+#define KSNAPSHOT_H
+#include "ksnapshotiface.h"
+
+#include <qbitmap.h>
+#include <qcursor.h>
+#include <qlabel.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qstyle.h>
+#include <qtimer.h>
+
+#include <dcopclient.h>
+#include <kglobalsettings.h>
+#include <kdialogbase.h>
+#include <kurl.h>
+
+class RegionGrabber;
+class KSnapshotWidget;
+
+class KSnapshotPreview : public QLabel
+{
+ Q_OBJECT
+
+ public:
+ KSnapshotPreview(QWidget *parent, const char *name = 0)
+ : QLabel(parent, name)
+ {
+ setAlignment(AlignHCenter | AlignVCenter);
+ setCursor(QCursor(Qt::PointingHandCursor));
+ }
+ virtual ~KSnapshotPreview() {}
+
+ void setPixmap(const QPixmap& pm)
+ {
+ // if this looks convoluted, that's because it is. drawing a PE_SizeGrip
+ // does unexpected things when painting directly onto the pixmap
+ QPixmap pixmap(pm);
+ QPixmap handle(15, 15);
+ QBitmap mask(15, 15, true);
+
+ {
+ QPainter p(&mask);
+ style().drawPrimitive(QStyle::PE_SizeGrip, &p, QRect(0, 0, 15, 15), palette().active());
+ p.end();
+ handle.setMask(mask);
+ }
+
+ {
+ QPainter p(&handle);
+ style().drawPrimitive(QStyle::PE_SizeGrip, &p, QRect(0, 0, 15, 15), palette().active());
+ p.end();
+ }
+
+ QRect rect(pixmap.width() - 16, pixmap.height() - 16, 15, 15);
+ QPainter p(&pixmap);
+ p.drawPixmap(rect, handle);
+ p.end();
+ QLabel::setPixmap(pixmap);
+ }
+
+ signals:
+ void startDrag();
+
+ protected:
+ void mousePressEvent(QMouseEvent * e)
+ {
+ mClickPt = e->pos();
+ }
+
+ void mouseMoveEvent(QMouseEvent * e)
+ {
+ if (mClickPt != QPoint(0, 0) &&
+ (e->pos() - mClickPt).manhattanLength() > KGlobalSettings::dndEventDelay())
+ {
+ mClickPt = QPoint(0, 0);
+ emit startDrag();
+ }
+ }
+
+ void mouseReleaseEvent(QMouseEvent * /*e*/)
+ {
+ mClickPt = QPoint(0, 0);
+ }
+
+ QPoint mClickPt;
+};
+
+class KSnapshot : public KDialogBase, virtual public KSnapshotIface
+{
+ Q_OBJECT
+
+public:
+ KSnapshot(QWidget *parent= 0, const char *name= 0, bool grabCurrent=false);
+ ~KSnapshot();
+
+ enum CaptureMode { FullScreen=0, WindowUnderCursor=1, Region=2, ChildWindow=3 };
+
+ bool save( const QString &filename );
+ QString url() const { return filename.url(); }
+
+protected slots:
+ void slotGrab();
+ void slotSave();
+ void slotSaveAs();
+ void slotCopy();
+ void slotPrint();
+ void slotMovePointer( int x, int y );
+
+ void setTime(int newTime);
+ void setURL(const QString &newURL);
+ void setGrabMode( int m );
+ void exit();
+
+protected:
+ void reject() { close(); }
+
+ virtual void closeEvent( QCloseEvent * e );
+ void resizeEvent(QResizeEvent*);
+ bool eventFilter( QObject*, QEvent* );
+
+private slots:
+ void grabTimerDone();
+ void slotDragSnapshot();
+ void updateCaption();
+ void updatePreview();
+ void slotRegionGrabbed( const QPixmap & );
+ void slotWindowGrabbed( const QPixmap & );
+
+private:
+ bool save( const KURL& url );
+ void performGrab();
+ void autoincFilename();
+ int grabMode();
+ int timeout();
+
+ QPixmap snapshot;
+ QTimer grabTimer;
+ QTimer updateTimer;
+ QWidget* grabber;
+ KURL filename;
+ KSnapshotWidget *mainWidget;
+ RegionGrabber *rgnGrab;
+ bool modified;
+};
+
+#endif // KSNAPSHOT_H
+
diff --git a/ksnapshot/ksnapshotiface.h b/ksnapshot/ksnapshotiface.h
new file mode 100644
index 00000000..6b1f3477
--- /dev/null
+++ b/ksnapshot/ksnapshotiface.h
@@ -0,0 +1,65 @@
+/** KSnapshot DCOP interface
+ File: ksnapshotiface.h
+ Date: January 12, 2001
+ Author: Ian Geiser <geiseri@linuxppc.com>
+ Comments:
+ This is an addition to the existing KSnapshot code
+ that will allow other applications to access internal
+ public member functions via dcop.
+**/
+
+#ifndef __KS_IFACE_H
+#define __KS_IFACE_H
+
+#include <dcopobject.h>
+
+class KSnapshotIface : virtual public DCOPObject
+{
+ K_DCOP
+ k_dcop:
+ /** the current filename (as a URL) that will
+ be used to save to */
+ virtual QString url() const = 0;
+
+ /** Grab an image **/
+ virtual void slotGrab() = 0;
+
+ /** Prints the image. */
+ virtual void slotPrint() = 0;
+
+ /** Saves the image **/
+ virtual void slotSave() = 0;
+
+ /** Save the image to the specified filename */
+ virtual bool save(const QString &filename) = 0;
+
+ /** Saves image as **/
+ virtual void slotSaveAs() = 0;
+
+ /** Copy the snapshot to the clipboard. **/
+ virtual void slotCopy() = 0;
+
+ /** Set the timeout value */
+ virtual void setTime(int newTime) = 0;
+
+ /** Get the current timeout value */
+ virtual int timeout() = 0;
+
+ /** Set the URL to the file to save **/
+ virtual void setURL(const QString &newURL) = 0;
+
+ /** Set the ability to grab the entire screen, just the window
+ containing the mouse, or a region */
+ virtual void setGrabMode(int grab) = 0;
+
+ /** Return the current grab mode */
+ virtual int grabMode() = 0;
+
+ /** Move the mouse pointer. */
+ virtual void slotMovePointer( int x, int y ) = 0;
+
+ /** Exit KSnapshot **/
+ virtual void exit() = 0;
+};
+
+#endif
diff --git a/ksnapshot/ksnapshotwidget.ui b/ksnapshot/ksnapshotwidget.ui
new file mode 100644
index 00000000..88efce1a
--- /dev/null
+++ b/ksnapshot/ksnapshotwidget.ui
@@ -0,0 +1,361 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>KSnapshotWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>KSnapshotWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>356</width>
+ <height>226</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="KSnapshotPreview" row="0" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>lblImage</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>200</width>
+ <height>130</height>
+ </size>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This is a preview of the current snapshot.
+
+The image can be dragged to another application or document to copy the full screenshot there. Try it with the Konqueror file manager.
+
+You can also copy the image to the clipboard by pressing Ctrl+C.</string>
+ </property>
+ </widget>
+ <widget class="Line" row="1" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>line1</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="3" column="1">
+ <property name="name">
+ <cstring>spinDelay</cstring>
+ </property>
+ <property name="suffix">
+ <string> sec</string>
+ </property>
+ <property name="specialValueText">
+ <string>No delay</string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Snapshot delay in seconds</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;
+This is the number of seconds to wait after clicking the &lt;i&gt;New Snapshot&lt;/i&gt; button before taking the snapshot.
+&lt;p&gt;
+This is very useful for getting windows, menus and other items on the screen set up just the way you want.
+&lt;p&gt;
+If &lt;i&gt;no delay&lt;/i&gt; is set, the program will wait for a mouse click before taking a snapshot.
+&lt;/p&gt;
+&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>lblDelay</cstring>
+ </property>
+ <property name="text">
+ <string>Snapshot &amp;delay:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>spinDelay</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Cap&amp;ture mode:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>comboMode</cstring>
+ </property>
+ </widget>
+ <spacer row="3" column="2" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>Spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>156</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QCheckBox" row="4" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>cbIncludeDecorations</cstring>
+ </property>
+ <property name="text">
+ <string>Include &amp;window decorations</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>When enabled, snapshot of a window will also include the window decorations</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="2" column="1" rowspan="1" colspan="3">
+ <item>
+ <property name="text">
+ <string>Full Screen</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Window Under Cursor</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Region</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Section of Window</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>comboMode</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Using this menu, you can select from the four following snapshot modes:
+&lt;p&gt;
+&lt;b&gt;Full Screen&lt;/b&gt; - captures the entire desktop.&lt;br&gt;
+&lt;b&gt;Window Under Cursor&lt;/b&gt; - captures only the window (or menu) that is under the mouse cursor when the snapshot is taken.&lt;br&gt;
+&lt;b&gt;Region&lt;/b&gt; - captures only the region of the desktop that you specify. When taking a new snapshot in this mode you will be able to select any area of the screen by clicking and dragging the mouse.&lt;/p&gt;
+&lt;b&gt;Section of Window&lt;/b&gt; - captures only a section of the window. When taking a new snapshot in this mode you will be able to select any child window by moving the mouse over it.&lt;/p&gt;&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="3">
+ <property name="name">
+ <cstring>layout1</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>btnNew</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;New Snapshot</string>
+ </property>
+ <property name="iconSet">
+ <iconset>"ksnapshot", 32</iconset>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click this button to take a new snapshot.</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>btnSave</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Save As...</string>
+ </property>
+ <property name="iconSet">
+ <iconset>"filesave"</iconset>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click this button to save the current snapshot. To quickly save the snapshot without showing the file dialog, press Ctrl+Shift+S. The filename is automatically incremented after each save.</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>btnCopy</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Copy to Clipboard</string>
+ </property>
+ <property name="iconSet">
+ <iconset>"editcopy"</iconset>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click this button to copy the current snapshot to the clipboard.</string>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>btnPrint</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Print...</string>
+ </property>
+ <property name="iconSet">
+ <iconset>"fileprint"</iconset>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Click this button to print the current screenshot.</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>KSnapshotPreview</class>
+ <header location="local">ksnapshot.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>5</hordata>
+ <verdata>5</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ <signal>startDrag()</signal>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="PNG" length="660">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000025b49444154789cb595bf4b1b6118c73f962bbc070e115af006210107f52fa8b18b071dbb445ca48bb8199c544a8b53b153092e3ad9d8ad53c962390a2da6507227441207e10296be190a774330070af74202760889899e3f22f50bc7ddfb72efe7799eef7bcf7b0305bbc06d9a4a4e9d5f9e2bd885819bd63cba0ff4a6f9eec800e7fffbd2da01fed81ff1a48d52014213b715d22b3d060d853cdce1d587d65407ec491b79b8d31fb02d0d2ea7d2012b15007422f6ab2f6f04a0ae82bbcb3f3939416882e02ca07454c2dab5086a01c9e749e2237174a1230605524ab29fb2e47fe431c652c8a3cf57c1ddca6e67f16b3ef62f1be7c0616e768ecdad4d8686860008c31067df415625beef475610095e7dbddaf3865db4d9dade223d9fc6adb8acbd5ba37c502608028488dee84830407c344e7a298daee90c3f1d263196400c0adc631773da64617e81dcd71caaaeb0be5977032f2e2d32f37206f385090de0319dbb528ae4641273da647c7c1c599591e06b3b2f24243c0d5b830678358ff03444fe9658df2dc2d390443c81eff5e1b1b56b613c3198189d20168b213481e77b88b868d95171c9ede6281f96b18bf6ddc1fe5f1fafe6513fabb7364783bdfc1efaa08e5b7129154b4c3e9b24359ba21ed4717e3a77b3423515eeb18bac4a6455a29a0a73da445624a56209236eb43eb326a497d29119477bac4179bf8c936f65a2ce14c6b0c1f2ea32ebefd7498c24b08b362b6f57709cabd9f65aa1c72e464d088280cc4686cc462672615b6d1b841ebb06dc50085a3d6f8ca56e845d96d06304f56a34f8e264533d3ddf979a5dcf0f75d0dffa6bbaaf1e0cfc0ff3922877348d5d5a0000000049454e44ae426082</data>
+ </image>
+</images>
+<connections>
+ <connection>
+ <sender>comboMode</sender>
+ <signal>activated(int)</signal>
+ <receiver>KSnapshotWidget</receiver>
+ <slot>slotModeChanged(int)</slot>
+ </connection>
+ <connection>
+ <sender>btnNew</sender>
+ <signal>clicked()</signal>
+ <receiver>KSnapshotWidget</receiver>
+ <slot>slotNewClicked()</slot>
+ </connection>
+ <connection>
+ <sender>btnPrint</sender>
+ <signal>clicked()</signal>
+ <receiver>KSnapshotWidget</receiver>
+ <slot>slotPrintClicked()</slot>
+ </connection>
+ <connection>
+ <sender>btnSave</sender>
+ <signal>clicked()</signal>
+ <receiver>KSnapshotWidget</receiver>
+ <slot>slotSaveClicked()</slot>
+ </connection>
+ <connection>
+ <sender>btnCopy</sender>
+ <signal>clicked()</signal>
+ <receiver>KSnapshotWidget</receiver>
+ <slot>slotCopyClicked()</slot>
+ </connection>
+ <connection>
+ <sender>lblImage</sender>
+ <signal>startDrag()</signal>
+ <receiver>KSnapshotWidget</receiver>
+ <slot>slotStartDrag()</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>btnNew</tabstop>
+ <tabstop>btnSave</tabstop>
+ <tabstop>btnCopy</tabstop>
+ <tabstop>btnPrint</tabstop>
+ <tabstop>comboMode</tabstop>
+ <tabstop>spinDelay</tabstop>
+ <tabstop>cbIncludeDecorations</tabstop>
+</tabstops>
+<includes>
+ <include location="global" impldecl="in implementation">kdialog.h</include>
+ <include location="global" impldecl="in implementation">kiconloader.h</include>
+ <include location="global" impldecl="in implementation">kglobalsettings.h</include>
+ <include location="local" impldecl="in implementation">ksnapshotwidget.ui.h</include>
+</includes>
+<signals>
+ <signal>newClicked()</signal>
+ <signal>saveClicked()</signal>
+ <signal>copyClicked()</signal>
+ <signal>printClicked()</signal>
+ <signal>startImageDrag()</signal>
+</signals>
+<slots>
+ <slot access="protected" specifier="non virtual">slotModeChanged( int mode )</slot>
+ <slot access="protected" specifier="non virtual">slotNewClicked()</slot>
+ <slot access="protected" specifier="non virtual">slotSaveClicked()</slot>
+ <slot access="protected" specifier="non virtual">slotCopyClicked()</slot>
+ <slot access="protected" specifier="non virtual">slotPrintClicked()</slot>
+ <slot access="protected" specifier="non virtual">slotStartDrag()</slot>
+ <slot specifier="non virtual" returnType="int">previewWidth()</slot>
+ <slot specifier="non virtual" returnType="int">previewHeight()</slot>
+</slots>
+<functions>
+ <function specifier="non virtual">setPreview( const QPixmap &amp; pm )</function>
+ <function specifier="non virtual">setDelay( int i )</function>
+ <function specifier="non virtual">setIncludeDecorations( bool b )</function>
+ <function specifier="non virtual">setMode( int mode )</function>
+ <function specifier="non virtual" returnType="int">delay()</function>
+ <function specifier="non virtual" returnType="bool">includeDecorations()</function>
+ <function specifier="non virtual" returnType="int">mode()</function>
+ <function specifier="non virtual" returnType="QPixmap">preview()</function>
+</functions>
+<pixmapfunction>SmallIconSet</pixmapfunction>
+<layoutdefaults spacing="6" margin="11"/>
+<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/>
+<includehints>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/ksnapshot/ksnapshotwidget.ui.h b/ksnapshot/ksnapshotwidget.ui.h
new file mode 100644
index 00000000..d7e757f5
--- /dev/null
+++ b/ksnapshot/ksnapshotwidget.ui.h
@@ -0,0 +1,138 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you wish to add, delete or rename functions or slots use
+** Qt Designer which will update this file, preserving your code. Create an
+** init() function in place of a constructor, and a destroy() function in
+** place of a destructor.
+*****************************************************************************/
+
+
+void KSnapshotWidget::slotModeChanged( int mode )
+{
+ switch ( mode )
+ {
+ case 0:
+ cbIncludeDecorations->setEnabled(false);
+ break;
+ case 1:
+ cbIncludeDecorations->setEnabled(true);
+ break;
+ case 2:
+ cbIncludeDecorations->setEnabled(false);
+ break;
+ case 3:
+ cbIncludeDecorations->setEnabled(false);
+ break;
+ default:
+ break;
+ }
+
+ spinDelay->setEnabled(mode != 2);
+}
+
+
+void KSnapshotWidget::setPreview( const QPixmap &pm )
+{
+ QImage img = pm.convertToImage();
+ double r1 = ( ( double ) pm.height() ) / pm.width();
+ if ( r1 * previewWidth() < previewHeight() )
+ img = img.smoothScale( previewWidth(),
+ int( previewWidth() * r1 ),
+ QImage::ScaleMin );
+ else
+ img = img.smoothScale( ( int ) ( ( ( double )previewHeight() ) / r1 ),
+ previewHeight(), QImage::ScaleMin );
+
+ QToolTip::remove( lblImage );
+ QToolTip::add( lblImage,
+ QString( "Preview of the snapshot image (%1 x %2)" )
+ .arg( pm.width() ).arg( pm.height() ) );
+
+ lblImage->setPixmap( img );
+ lblImage->adjustSize();
+}
+
+
+void KSnapshotWidget::setDelay( int i )
+{
+ spinDelay->setValue(i);
+}
+
+
+void KSnapshotWidget::setIncludeDecorations( bool b )
+{
+ cbIncludeDecorations->setChecked(b);
+}
+
+
+void KSnapshotWidget::setMode( int mode )
+{
+ comboMode->setCurrentItem(mode);
+ slotModeChanged(mode);
+}
+
+
+int KSnapshotWidget::delay()
+{
+ return spinDelay->value();
+}
+
+
+bool KSnapshotWidget::includeDecorations()
+{
+ return cbIncludeDecorations->isChecked();
+}
+
+
+int KSnapshotWidget::mode()
+{
+ return comboMode->currentItem();
+}
+
+
+void KSnapshotWidget::slotNewClicked()
+{
+ emit newClicked();
+}
+
+
+void KSnapshotWidget::slotSaveClicked()
+{
+ emit saveClicked();
+}
+
+
+void KSnapshotWidget::slotPrintClicked()
+{
+ emit printClicked();
+}
+
+
+void KSnapshotWidget::slotStartDrag()
+{
+ emit startImageDrag();
+}
+
+
+QPixmap KSnapshotWidget::preview()
+{
+ return *lblImage->pixmap();
+}
+
+
+int KSnapshotWidget::previewWidth()
+{
+ return lblImage->width();
+}
+
+
+int KSnapshotWidget::previewHeight()
+{
+ return lblImage->height();
+}
+
+void KSnapshotWidget::slotCopyClicked()
+{
+ emit copyClicked();
+}
diff --git a/ksnapshot/main.cpp b/ksnapshot/main.cpp
new file mode 100644
index 00000000..f3e397e2
--- /dev/null
+++ b/ksnapshot/main.cpp
@@ -0,0 +1,77 @@
+/*
+ (c) Richard J. Moore 1997-2002
+ (c) Matthias Ettrich 2000
+ (c) Aaron J. Seigo 2002-2004
+ (c) Nadeem Hasan 2003
+ (c) Waldo Bastian 1999-2002
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this library; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kapplication.h>
+#include <kimageio.h>
+#include <klocale.h>
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <kiconloader.h>
+
+#include "ksnapshot.h"
+
+static const char description[] =
+ I18N_NOOP("KDE Screenshot Utility");
+
+static KCmdLineOptions options[] =
+{
+ { "c", 0, 0 },
+ { "current", I18N_NOOP("Captures the window under the mouse on startup (instead of the desktop)"), 0 },
+ { 0, 0, 0 }
+};
+
+int main(int argc, char **argv)
+{
+ KAboutData aboutData( "ksnapshot", I18N_NOOP("KSnapshot"),
+ KSNAPVERSION, description, KAboutData::License_GPL,
+ "(c) 1997-2004, Richard J. Moore,\n(c) 2000, Matthias Ettrich,\n(c) 2002-2003 Aaron J. Seigo");
+ aboutData.addAuthor("Richard J. Moore",0, "rich@kde.org");
+ aboutData.addAuthor("Matthias Ettrich",0, "ettrich@kde.org");
+ aboutData.addAuthor("Aaron J. Seigo", 0, "aseigo@kde.org");
+ aboutData.addCredit( "Nadeem Hasan", I18N_NOOP("Region Grabbing\nReworked GUI"),
+ "nhasan@kde.org" );
+
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ KApplication app;
+
+ KImageIO::registerFormats();
+
+ // Create top level window
+ KSnapshot *toplevel;
+
+ if ( args->isSet( "current" ) )
+ toplevel = new KSnapshot( 0, 0, true );
+ else
+ toplevel = new KSnapshot();
+
+ args->clear();
+ app.dcopClient()->setDefaultObject( toplevel->objId() );
+ toplevel->setCaption( app.makeStdCaption("") );
+ app.setMainWidget(toplevel);
+ toplevel->show();
+ return app.exec();
+}
+
diff --git a/ksnapshot/regiongrabber.cpp b/ksnapshot/regiongrabber.cpp
new file mode 100644
index 00000000..c1d8ed98
--- /dev/null
+++ b/ksnapshot/regiongrabber.cpp
@@ -0,0 +1,177 @@
+/*
+ Copyright (C) 2003 Nadeem Hasan <nhasan@kde.org>
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this library; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "regiongrabber.h"
+
+#include <qapplication.h>
+#include <qpainter.h>
+#include <qpalette.h>
+#include <qstyle.h>
+#include <qtimer.h>
+#include <qtooltip.h>
+
+#include <kglobalsettings.h>
+
+SizeTip::SizeTip( QWidget *parent, const char *name )
+ : QLabel( parent, name, WStyle_Customize | WX11BypassWM |
+ WStyle_StaysOnTop | WStyle_NoBorder | WStyle_Tool )
+{
+ setMargin( 2 );
+ setIndent( 0 );
+ setFrameStyle( QFrame::Plain | QFrame::Box );
+
+ setPalette( QToolTip::palette() );
+}
+
+void SizeTip::setTip( const QRect &rect )
+{
+ QString tip = QString( "%1x%2" ).arg( rect.width() )
+ .arg( rect.height() );
+
+ setText( tip );
+ adjustSize();
+
+ positionTip( rect );
+}
+
+void SizeTip::positionTip( const QRect &rect )
+{
+ QRect tipRect = geometry();
+ tipRect.moveTopLeft( QPoint( 0, 0 ) );
+
+ if ( rect.intersects( tipRect ) )
+ {
+ QRect deskR = KGlobalSettings::desktopGeometry( QPoint( 0, 0 ) );
+
+ tipRect.moveCenter( QPoint( deskR.width()/2, deskR.height()/2 ) );
+ if ( !rect.contains( tipRect, true ) && rect.intersects( tipRect ) )
+ tipRect.moveBottomRight( geometry().bottomRight() );
+ }
+
+ move( tipRect.topLeft() );
+}
+
+RegionGrabber::RegionGrabber()
+ : QWidget( 0, 0, WStyle_Customize | WX11BypassWM ),
+ mouseDown( false ), sizeTip( 0L )
+{
+ sizeTip = new SizeTip( ( QWidget * )0L );
+
+ tipTimer = new QTimer( this );
+ connect( tipTimer, SIGNAL( timeout() ), SLOT( updateSizeTip() ) );
+
+ QTimer::singleShot( 200, this, SLOT( initGrabber() ) );
+}
+
+RegionGrabber::~RegionGrabber()
+{
+ delete sizeTip;
+}
+
+void RegionGrabber::initGrabber()
+{
+ pixmap = QPixmap::grabWindow( qt_xrootwin() );
+ setPaletteBackgroundPixmap( pixmap );
+
+ QDesktopWidget desktopWidget;
+ QRect desktopSize;
+ if ( desktopWidget.isVirtualDesktop() )
+ desktopSize = desktopWidget.geometry();
+ else
+ desktopSize = desktopWidget.screenGeometry( qt_xrootwin() );
+
+ setGeometry( desktopSize );
+ showFullScreen();
+
+ QApplication::setOverrideCursor( crossCursor );
+}
+
+void RegionGrabber::mousePressEvent( QMouseEvent *e )
+{
+ if ( e->button() == LeftButton )
+ {
+ mouseDown = true;
+ grabRect = QRect( e->pos(), e->pos() );
+ }
+}
+
+void RegionGrabber::mouseMoveEvent( QMouseEvent *e )
+{
+ if ( mouseDown )
+ {
+ sizeTip->hide();
+ tipTimer->start( 250, true );
+
+ drawRubber();
+ grabRect.setBottomRight( e->pos() );
+ drawRubber();
+ }
+}
+
+void RegionGrabber::mouseReleaseEvent( QMouseEvent *e )
+{
+ mouseDown = false;
+ drawRubber();
+ sizeTip->hide();
+
+ grabRect.setBottomRight( e->pos() );
+ grabRect = grabRect.normalize();
+
+ QPixmap region = QPixmap::grabWindow( winId(), grabRect.x(), grabRect.y(),
+ grabRect.width(), grabRect.height() );
+
+ QApplication::restoreOverrideCursor();
+
+ emit regionGrabbed( region );
+}
+
+void RegionGrabber::keyPressEvent( QKeyEvent *e )
+{
+ if ( e->key() == Key_Escape )
+ {
+ QApplication::restoreOverrideCursor();
+ emit regionGrabbed( QPixmap() );
+ }
+ else
+ e->ignore();
+}
+
+void RegionGrabber::updateSizeTip()
+{
+ QRect rect = grabRect.normalize();
+
+ sizeTip->setTip( rect );
+ sizeTip->show();
+}
+
+void RegionGrabber::drawRubber()
+{
+ QPainter p;
+ p.begin( this );
+ p.setRasterOp( NotROP );
+ p.setPen( QPen( color0, 1 ) );
+ p.setBrush( NoBrush );
+
+ style().drawPrimitive( QStyle::PE_FocusRect, &p, grabRect, colorGroup(),
+ QStyle::Style_Default, QStyleOption( colorGroup().base() ) );
+
+ p.end();
+}
+
+#include "regiongrabber.moc"
diff --git a/ksnapshot/regiongrabber.h b/ksnapshot/regiongrabber.h
new file mode 100644
index 00000000..ee9a8238
--- /dev/null
+++ b/ksnapshot/regiongrabber.h
@@ -0,0 +1,70 @@
+/*
+ Copyright (C) 2003 Nadeem Hasan <nhasan@kde.org>
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this library; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef REGIONGRABBER_H
+#define REGIONGRABBER_H
+
+#include <qlabel.h>
+#include <qpixmap.h>
+
+class QTimer;
+
+class SizeTip : public QLabel
+{
+ public:
+ SizeTip( QWidget *parent, const char *name=0 );
+ ~SizeTip() {}
+
+ void setTip( const QRect &rect );
+ void positionTip( const QRect &rect );
+};
+
+class RegionGrabber : public QWidget
+{
+ Q_OBJECT
+
+ public:
+ RegionGrabber();
+ ~RegionGrabber();
+
+ protected slots:
+ void initGrabber();
+ void updateSizeTip();
+
+ signals:
+ void regionGrabbed( const QPixmap & );
+
+ protected:
+ void mousePressEvent( QMouseEvent *e );
+ void mouseReleaseEvent( QMouseEvent *e );
+ void mouseMoveEvent( QMouseEvent *e );
+ void keyPressEvent( QKeyEvent *e );
+
+ void drawRubber();
+
+ bool mouseDown;
+ QRect grabRect;
+ QPixmap pixmap;
+
+ SizeTip *sizeTip;
+ QTimer *tipTimer;
+};
+
+#endif // REGIONGRABBER_H
+
diff --git a/ksnapshot/uninstall.desktop b/ksnapshot/uninstall.desktop
new file mode 100644
index 00000000..e1e3e173
--- /dev/null
+++ b/ksnapshot/uninstall.desktop
@@ -0,0 +1,2 @@
+[Desktop Entry]
+Hidden=true
diff --git a/ksnapshot/windowgrabber.cpp b/ksnapshot/windowgrabber.cpp
new file mode 100644
index 00000000..036764b1
--- /dev/null
+++ b/ksnapshot/windowgrabber.cpp
@@ -0,0 +1,353 @@
+/*
+ Copyright (C) 2004 Bernd Brandstetter <bbrand@freenet.de>
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this library; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "windowgrabber.h"
+#include <qbitmap.h>
+#include <qpainter.h>
+#include <qptrlist.h>
+#include <algorithm>
+
+#include <config.h>
+
+#ifdef HAVE_X11_EXTENSIONS_SHAPE_H
+#include <X11/extensions/shape.h>
+#endif
+
+
+static
+const int minSize = 8;
+
+static
+bool operator< ( const QRect& r1, const QRect& r2 )
+{
+ return r1.width() * r1.height() < r2.width() * r2.height();
+}
+
+// Recursively iterates over the window w and its children, thereby building
+// a tree of window descriptors. Windows in non-viewable state or with height
+// or width smaller than minSize will be ignored.
+static
+void getWindowsRecursive( std::vector<QRect>& windows, Window w,
+ int rx = 0, int ry = 0, int depth = 0 )
+{
+ XWindowAttributes atts;
+ XGetWindowAttributes( qt_xdisplay(), w, &atts );
+ if ( atts.map_state == IsViewable &&
+ atts.width >= minSize && atts.height >= minSize ) {
+ int x = 0, y = 0;
+ if ( depth ) {
+ x = atts.x + rx;
+ y = atts.y + ry;
+ }
+
+ QRect r( x, y, atts.width, atts.height );
+ if ( std::find( windows.begin(), windows.end(), r ) == windows.end() ) {
+ windows.push_back( r );
+ }
+
+ Window root, parent;
+ Window* children;
+ unsigned int nchildren;
+
+ if( XQueryTree( qt_xdisplay(), w, &root, &parent, &children, &nchildren ) != 0 ) {
+ for( unsigned int i = 0; i < nchildren; ++i ) {
+ getWindowsRecursive( windows, children[ i ], x, y, depth + 1 );
+ }
+ if( children != NULL )
+ XFree( children );
+ }
+ }
+ if ( depth == 0 )
+ std::sort( windows.begin(), windows.end() );
+}
+
+static
+Window findRealWindow( Window w, int depth = 0 )
+{
+ if( depth > 5 )
+ return None;
+ static Atom wm_state = XInternAtom( qt_xdisplay(), "WM_STATE", False );
+ Atom type;
+ int format;
+ unsigned long nitems, after;
+ unsigned char* prop;
+ if( XGetWindowProperty( qt_xdisplay(), w, wm_state, 0, 0, False, AnyPropertyType,
+ &type, &format, &nitems, &after, &prop ) == Success ) {
+ if( prop != NULL )
+ XFree( prop );
+ if( type != None )
+ return w;
+ }
+ Window root, parent;
+ Window* children;
+ unsigned int nchildren;
+ Window ret = None;
+ if( XQueryTree( qt_xdisplay(), w, &root, &parent, &children, &nchildren ) != 0 ) {
+ for( unsigned int i = 0;
+ i < nchildren && ret == None;
+ ++i )
+ ret = findRealWindow( children[ i ], depth + 1 );
+ if( children != NULL )
+ XFree( children );
+ }
+ return ret;
+}
+
+static
+Window windowUnderCursor( bool includeDecorations = true )
+{
+ Window root;
+ Window child;
+ uint mask;
+ int rootX, rootY, winX, winY;
+ XGrabServer( qt_xdisplay() );
+ XQueryPointer( qt_xdisplay(), qt_xrootwin(), &root, &child,
+ &rootX, &rootY, &winX, &winY, &mask );
+ if( child == None )
+ child = qt_xrootwin();
+ if( !includeDecorations ) {
+ Window real_child = findRealWindow( child );
+ if( real_child != None ) // test just in case
+ child = real_child;
+ }
+ return child;
+}
+
+static
+QPixmap grabWindow( Window child, int x, int y, uint w, uint h, uint border )
+{
+ QPixmap pm( QPixmap::grabWindow( qt_xrootwin(), x, y, w, h ) );
+
+#ifdef HAVE_X11_EXTENSIONS_SHAPE_H
+ int tmp1, tmp2;
+ //Check whether the extension is available
+ if ( XShapeQueryExtension( qt_xdisplay(), &tmp1, &tmp2 ) ) {
+ QBitmap mask( w, h );
+ //As the first step, get the mask from XShape.
+ int count, order;
+ XRectangle* rects = XShapeGetRectangles( qt_xdisplay(), child,
+ ShapeBounding, &count, &order );
+ //The ShapeBounding region is the outermost shape of the window;
+ //ShapeBounding - ShapeClipping is defined to be the border.
+ //Since the border area is part of the window, we use bounding
+ // to limit our work region
+ if (rects) {
+ //Create a QRegion from the rectangles describing the bounding mask.
+ QRegion contents;
+ for ( int pos = 0; pos < count; pos++ )
+ contents += QRegion( rects[pos].x, rects[pos].y,
+ rects[pos].width, rects[pos].height );
+ XFree( rects );
+
+ //Create the bounding box.
+ QRegion bbox( 0, 0, w, h );
+
+ if( border > 0 ) {
+ contents.translate( border, border );
+ contents += QRegion( 0, 0, border, h );
+ contents += QRegion( 0, 0, w, border );
+ contents += QRegion( 0, h - border, w, border );
+ contents += QRegion( w - border, 0, border, h );
+ }
+
+ //Get the masked away area.
+ QRegion maskedAway = bbox - contents;
+ QMemArray<QRect> maskedAwayRects = maskedAway.rects();
+
+ //Construct a bitmap mask from the rectangles
+ QPainter p(&mask);
+ p.fillRect(0, 0, w, h, Qt::color1);
+ for (uint pos = 0; pos < maskedAwayRects.count(); pos++)
+ p.fillRect(maskedAwayRects[pos], Qt::color0);
+ p.end();
+
+ pm.setMask(mask);
+ }
+ }
+#endif
+
+ return pm;
+}
+
+WindowGrabber::WindowGrabber()
+: QDialog( 0, 0, true, Qt::WStyle_Customize | Qt::WStyle_NoBorder |
+ Qt::WStyle_StaysOnTop | Qt::WX11BypassWM ),
+ current( -1 ), yPos( -1 )
+{
+ Window root;
+ int y, x;
+ uint w, h, border, depth;
+ XGrabServer( qt_xdisplay() );
+ Window child = windowUnderCursor();
+ XGetGeometry( qt_xdisplay(), child, &root, &x, &y, &w, &h, &border, &depth );
+ QPixmap pm( grabWindow( child, x, y, w, h, border ) );
+ getWindowsRecursive( windows, child );
+ XUngrabServer( qt_xdisplay() );
+
+ setPaletteBackgroundPixmap( pm );
+ setFixedSize( pm.size() );
+ setMouseTracking( true );
+ setGeometry( x, y, w, h );
+}
+
+WindowGrabber::~WindowGrabber()
+{
+}
+
+QPixmap WindowGrabber::grabCurrent( bool includeDecorations )
+{
+ Window root;
+ int y, x;
+ uint w, h, border, depth;
+ XGrabServer( qt_xdisplay() );
+ Window child = windowUnderCursor( includeDecorations );
+ XGetGeometry( qt_xdisplay(), child, &root, &x, &y, &w, &h, &border, &depth );
+ Window parent;
+ Window* children;
+ unsigned int nchildren;
+ if( XQueryTree( qt_xdisplay(), child, &root, &parent,
+ &children, &nchildren ) != 0 ) {
+ if( children != NULL )
+ XFree( children );
+ int newx, newy;
+ Window dummy;
+ if( XTranslateCoordinates( qt_xdisplay(), parent, qt_xrootwin(),
+ x, y, &newx, &newy, &dummy )) {
+ x = newx;
+ y = newy;
+ }
+ }
+ QPixmap pm( grabWindow( child, x, y, w, h, border ) );
+ XUngrabServer( qt_xdisplay() );
+ return pm;
+}
+
+void WindowGrabber::mousePressEvent( QMouseEvent *e )
+{
+ if ( e->button() == QMouseEvent::RightButton )
+ yPos = e->globalY();
+ else {
+ QPixmap pm;
+ if ( current ) {
+ QRect r( windows[ current ] );
+ int w = r.width();
+ int h = r.height();
+ pm.resize( w, h );
+ copyBlt( &pm, 0, 0, paletteBackgroundPixmap(), r.x(), r.y(), w, h );
+ }
+ emit windowGrabbed( pm );
+ accept();
+ }
+}
+
+void WindowGrabber::mouseReleaseEvent( QMouseEvent *e )
+{
+ if ( e->button() == QMouseEvent::RightButton )
+ yPos = -1;
+}
+
+static
+const int minDistance = 10;
+
+void WindowGrabber::mouseMoveEvent( QMouseEvent *e )
+{
+ if ( yPos == -1 ) {
+ int w = windowIndex( e->pos() );
+ if ( w != -1 && w != current ) {
+ current = w;
+ drawBorder();
+ }
+ }
+ else {
+ int y = e->globalY();
+ if ( y > yPos + minDistance ) {
+ decreaseScope( e->pos() );
+ yPos = y;
+ }
+ else if ( y < yPos - minDistance ) {
+ increaseScope( e->pos() );
+ yPos = y;
+ }
+ }
+}
+
+void WindowGrabber::wheelEvent( QWheelEvent *e )
+{
+ if ( e->delta() > 0 )
+ increaseScope( e->pos() );
+ else if ( e->delta() < 0 )
+ decreaseScope( e->pos() );
+ else
+ e->ignore();
+}
+
+// Increases the scope to the next-bigger window containing the mouse pointer.
+// This method is activated by either rotating the mouse wheel forwards or by
+// dragging the mouse forwards while keeping the right mouse button pressed.
+void WindowGrabber::increaseScope( const QPoint &pos )
+{
+ for ( uint i = current + 1; i < windows.size(); i++ ) {
+ if ( windows[ i ].contains( pos ) ) {
+ current = i;
+ break;
+ }
+ }
+ drawBorder();
+}
+
+// Decreases the scope to the next-smaller window containing the mosue pointer.
+// This method is activated by either rotating the mouse wheel backwards or by
+// dragging the mouse backwards while keeping the right mouse button pressed.
+void WindowGrabber::decreaseScope( const QPoint &pos )
+{
+ for ( int i = current - 1; i >= 0; i-- ) {
+ if ( windows[ i ].contains( pos ) ) {
+ current = i;
+ break;
+ }
+ }
+ drawBorder();
+}
+
+// Searches and returns the index of the first (=smallest) window
+// containing the mouse pointer.
+int WindowGrabber::windowIndex( const QPoint &pos ) const
+{
+ for ( uint i = 0; i < windows.size(); i++ ) {
+ if ( windows[ i ].contains( pos ) )
+ return i;
+ }
+ return -1;
+}
+
+// Draws a border around the (child) window currently containing the pointer
+void WindowGrabber::drawBorder()
+{
+ repaint();
+
+ if ( current >= 0 ) {
+ QPainter p;
+ p.begin( this );
+ p.setPen( QPen( Qt::red, 3 ) );
+ p.drawRect( windows[ current ] );
+ p.end();
+ }
+}
+
+#include "windowgrabber.moc"
diff --git a/ksnapshot/windowgrabber.h b/ksnapshot/windowgrabber.h
new file mode 100644
index 00000000..43598576
--- /dev/null
+++ b/ksnapshot/windowgrabber.h
@@ -0,0 +1,59 @@
+/*
+ Copyright (C) 2004 Bernd Brandstetter <bbrand@freenet.de>
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this library; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef WINDOWGRABBER_H
+#define WINDOWGRABBER_H
+
+#include <qdialog.h>
+#include <qpixmap.h>
+#include <vector>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+class WindowGrabber : public QDialog
+{
+ Q_OBJECT
+
+public:
+ WindowGrabber();
+ ~WindowGrabber();
+
+ static QPixmap grabCurrent( bool includeDecorations = true );
+
+signals:
+ void windowGrabbed( const QPixmap & );
+
+protected:
+ void mousePressEvent( QMouseEvent * );
+ void mouseReleaseEvent( QMouseEvent * );
+ void mouseMoveEvent( QMouseEvent * );
+ void wheelEvent( QWheelEvent * );
+
+private:
+ void drawBorder();
+ void increaseScope( const QPoint & );
+ void decreaseScope( const QPoint & );
+ int windowIndex( const QPoint & ) const;
+ std::vector<QRect> windows;
+ int current;
+ int yPos;
+};
+
+
+#endif // WINDOWGRABBER_H
diff --git a/ksvg/AUTHORS b/ksvg/AUTHORS
new file mode 100644
index 00000000..ead56e6b
--- /dev/null
+++ b/ksvg/AUTHORS
@@ -0,0 +1,2 @@
+Nikolas Zimmermann <wildfox@kde.org>
+Rob Buis <buis@kde.org>
diff --git a/ksvg/FAQ b/ksvg/FAQ
new file mode 100644
index 00000000..68897507
--- /dev/null
+++ b/ksvg/FAQ
@@ -0,0 +1,17 @@
+KSVG FAQ
+-------------------------
+
+Q: Why do my fonts look wrong when trying the offical
+ W3C Testcases? (they don't fit in the boxes)
+
+A: Those testcases all use a font called 'Helvetica',
+ your system may use Verdana instead, which is also
+ wrong. I suggest you replace the following line
+ in your XftConfig file:
+
+ match any family == "Helvetica" edit family += "Verdana";
+
+ with
+
+ match any family == "Helvetica" edit family += "Arial";
+
diff --git a/ksvg/Makefile.am b/ksvg/Makefile.am
new file mode 100644
index 00000000..722e90d7
--- /dev/null
+++ b/ksvg/Makefile.am
@@ -0,0 +1,115 @@
+SUBDIRS = dom impl core ecma . plugin test
+
+lib_LTLIBRARIES = libksvg.la
+libksvg_la_SOURCES = dummy.cc
+libksvg_la_METASOURCES = AUTO
+libksvg_la_LDFLAGS = -version-info 0:1:0 -no-undefined $(all_libraries)
+libksvg_la_LIBADD = dom/libksvgdom.la impl/libksvgdomimpl.la core/libksvgcore.la ecma/libksvgecma.la \
+ $(LCMS_LIBS) impl/libs/xrgbrender/libksvgxrgbrender.la impl/libs/libtext2path/src/libtext2path.la \
+ impl/libs/art_support/libksvgart.la -lkjs $(LIB_KHTML) $(LIBART_LIBS) $(FREETYPE_LIBS) $(FONTCONFIG_LIBS)
+
+INCLUDES = -I$(top_srcdir)/ksvg/dom -I$(top_srcdir)/ksvg/impl $(all_includes)
+
+dummy.cc:
+ echo "" > dummy.cc
+
+# Make it easy for developers :)
+hashtables:
+ cd $(srcdir); \
+ rm -f data/*lut* ; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGElementImpl.cc > data/SVGElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGSVGElementImpl.cc > data/SVGSVGElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGRectElementImpl.cc > data/SVGRectElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGLineElementImpl.cc > data/SVGLineElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGCircleElementImpl.cc > data/SVGCircleElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGImageElementImpl.cc > data/SVGImageElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGEllipseElementImpl.cc > data/SVGEllipseElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedPointsImpl.cc > data/SVGAnimatedPointsImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGPointImpl.cc > data/SVGPointImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGRectImpl.cc > data/SVGRectImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGNumberImpl.cc > data/SVGNumberImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedAngleImpl.cc > data/SVGAnimatedAngleImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedRectImpl.cc > data/SVGAnimatedRectImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedNumberImpl.cc > data/SVGAnimatedNumberImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedNumberListImpl.cc > data/SVGAnimatedNumberListImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedIntegerImpl.cc > data/SVGAnimatedIntegerImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedBooleanImpl.cc > data/SVGAnimatedBooleanImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedEnumerationImpl.cc > data/SVGAnimatedEnumerationImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedStringImpl.cc > data/SVGAnimatedStringImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedLengthImpl.cc > data/SVGAnimatedLengthImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedLengthListImpl.cc > data/SVGAnimatedLengthListImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedPreserveAspectRatioImpl.cc > data/SVGAnimatedPreserveAspectRatioImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGPreserveAspectRatioImpl.cc > data/SVGPreserveAspectRatioImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGLengthImpl.cc > data/SVGLengthImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGMatrixImpl.cc > data/SVGMatrixImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGAngleImpl.cc > data/SVGAngleImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGLocatableImpl.cc > data/SVGLocatableImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGTestsImpl.cc > data/SVGTestsImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGLangSpaceImpl.cc > data/SVGLangSpaceImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGExternalResourcesRequiredImpl.cc > data/SVGExternalResourcesRequiredImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGURIReferenceImpl.cc > data/SVGURIReferenceImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGPaintImpl.cc > data/SVGPaintImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGColorImpl.cc > data/SVGColorImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGICCColorImpl.cc > data/SVGICCColorImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGTextPositioningElementImpl.cc > data/SVGTextPositioningElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGTextContentElementImpl.cc > data/SVGTextContentElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGTransformImpl.cc > data/SVGTransformImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGTransformableImpl.cc > data/SVGTransformableImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGPointListImpl.cc > data/SVGPointListImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGNumberListImpl.cc > data/SVGNumberListImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGLengthListImpl.cc > data/SVGLengthListImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGStringListImpl.cc > data/SVGStringListImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedPathDataImpl.cc > data/SVGAnimatedPathDataImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGPathSegImpl.cc > data/SVGPathSegImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGPathSegArcImpl.cc > data/SVGPathSegArcImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGPathSegMovetoImpl.cc > data/SVGPathSegMovetoImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGPathSegLinetoImpl.cc > data/SVGPathSegLinetoImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGPathSegLinetoHorizontalImpl.cc > data/SVGPathSegLinetoHorizontalImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGPathSegLinetoVerticalImpl.cc > data/SVGPathSegLinetoVerticalImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGPathSegCurvetoCubicImpl.cc > data/SVGPathSegCurvetoCubicImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGPathSegCurvetoCubicSmoothImpl.cc > data/SVGPathSegCurvetoCubicSmoothImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGPathSegCurvetoQuadraticImpl.cc > data/SVGPathSegCurvetoQuadraticImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGPathSegCurvetoQuadraticSmoothImpl.cc > data/SVGPathSegCurvetoQuadraticSmoothImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGPathElementImpl.cc > data/SVGPathElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGPathSegListImpl.cc > data/SVGPathSegListImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGTransformListImpl.cc > data/SVGTransformListImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGAnimatedTransformListImpl.cc > data/SVGAnimatedTransformListImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGAElementImpl.cc > data/SVGAElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGUseElementImpl.cc > data/SVGUseElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGDocumentImpl.cc > data/SVGDocumentImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGForeignObjectElementImpl.cc > data/SVGForeignObjectElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGScriptElementImpl.cc > data/SVGScriptElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGStyleElementImpl.cc > data/SVGStyleElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGZoomAndPanImpl.cc > data/SVGZoomAndPanImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGFitToViewBoxImpl.cc > data/SVGFitToViewBoxImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGStylableImpl.cc > data/SVGStylableImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGEventImpl.cc > data/SVGEventImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGEcma.cc > data/SVGEcma.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGMarkerElementImpl.cc > data/SVGMarkerElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGViewElementImpl.cc > data/SVGViewElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGTextContentElementImpl.cc > data/SVGTextContentElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGClipPathElementImpl.cc > data/SVGClipPathElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGColorProfileElementImpl.cc > data/SVGColorProfileElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGPatternElementImpl.cc > data/SVGPatternElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGGradientElementImpl.cc > data/SVGGradientElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGLinearGradientElementImpl.cc > data/SVGLinearGradientElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGRadialGradientElementImpl.cc > data/SVGRadialGradientElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGStopElementImpl.cc > data/SVGStopElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGAnimationElementImpl.cc > data/SVGAnimationElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGCursorElementImpl.cc > data/SVGCursorElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGSymbolElementImpl.cc > data/SVGSymbolElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGMaskElementImpl.cc > data/SVGMaskElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGGlyphElementImpl.cc > data/SVGGlyphElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGMissingGlyphElementImpl.cc > data/SVGMissingGlyphElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGGlyphRefElementImpl.cc > data/SVGGlyphRefElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGTextPathElementImpl.cc > data/SVGTextPathElementImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table impl/SVGZoomEventImpl.cc > data/SVGZoomEventImpl.lut.h; \
+ ../../kdelibs/kjs/create_hash_table ecma/ksvg_window.cpp > data/ksvg_window.lut.h;
+
+generatedata:
+ cd $(srcdir); \
+ rm impl/generateddata.cpp -f; \
+ cd impl && ../scripts/generate.pl
+
+redo:
+ make hashtables && make generatedata
diff --git a/ksvg/NEWS b/ksvg/NEWS
new file mode 100644
index 00000000..19fead3e
--- /dev/null
+++ b/ksvg/NEWS
@@ -0,0 +1,8 @@
+Mon Sep 8 ??:??:?? CEST 2003
+ o Moved to kdegraphics
+
+Sun Jul 15 13:26:39 CEST 2001
+ o First code
+
+Thu Jun 14 17:44:21 CEST 2001
+ o KSVG Idea
diff --git a/ksvg/README b/ksvg/README
new file mode 100644
index 00000000..a2ad11bc
--- /dev/null
+++ b/ksvg/README
@@ -0,0 +1,9 @@
+KSVG 0.1
+-----------------------------------
+
+KSVG is a KDE implementation of the
+Scalable Vector Graphics Specifications.
+
+Have a lot of fun!
+
+The KSVG Team
diff --git a/ksvg/RELEASE-TODO b/ksvg/RELEASE-TODO
new file mode 100644
index 00000000..d520aaef
--- /dev/null
+++ b/ksvg/RELEASE-TODO
@@ -0,0 +1,10 @@
+KSVG 0.1 - Release TODO List
+--------------------------------------
+
+Task
+We should be done for 0.1 with the feature
+set as promised, years ago :)
+
+Make it nice:
+- idea: offer a tool to select a rectangle to zoom into (like asv has)
+- idea: offer a preview widget like in karbon/kghostview to easily navigate/pan around a drawing
diff --git a/ksvg/TODO b/ksvg/TODO
new file mode 100644
index 00000000..7d407484
--- /dev/null
+++ b/ksvg/TODO
@@ -0,0 +1,10 @@
+Not ordered!
+
+" - unfinished tasks"
+" x finished tasks"
+
+x textPath [Progressing: Niko, Rob]
+- viewBox
+- perhaps seperate parsing and rendering better
+- check events handling (prepareMouseEvent)
+- kill render()
diff --git a/ksvg/VERSION b/ksvg/VERSION
new file mode 100644
index 00000000..fe57fc6a
--- /dev/null
+++ b/ksvg/VERSION
@@ -0,0 +1 @@
+KSVG 0.1
diff --git a/ksvg/configure.in.bot b/ksvg/configure.in.bot
new file mode 100644
index 00000000..cd823b77
--- /dev/null
+++ b/ksvg/configure.in.bot
@@ -0,0 +1,25 @@
+if test -z "$LCMS_LIBS" -o -z "$LIBART_LIBS" -o \
+ -z "$FREETYPE_LIBS" -o -z "$FRIBIDI_LIBS" -o -z "$FONTCONFIG_LIBS"; then
+ echo ""
+ echo "Some of the libraries required for KSVG are missing or too old,"
+ echo "therefore KSVG will not be compiled."
+ echo ""
+ echo "If you want to compile KSVG you should install:"
+ if test -z "$LCMS_LIBS"; then
+ echo " * lcms 1.09 or newer (http://www.littlecms.com/)"
+ fi
+ if test -z "$LIBART_LIBS"; then
+ echo " * libart 2.3.8 or newer (http://www.levien.com/libart/)"
+ fi
+ if test -z "$FREETYPE_LIBS"; then
+ echo " * freetype 2.0.6 or newer (http://www.freetype.org)"
+ fi
+ if test -z "$FONTCONFIG_LIBS"; then
+ echo " * fontconfig 2.2.0 or newer (http://fontconfig.org)"
+ fi
+ if test -z "$FRIBIDI_LIBS"; then
+ echo " * fribidi 0.10.4 or newer (http://freedesktop.org/Software/FriBidi)"
+ fi
+ echo ""
+ all_tests=bad
+fi
diff --git a/ksvg/configure.in.in b/ksvg/configure.in.in
new file mode 100644
index 00000000..34d27f52
--- /dev/null
+++ b/ksvg/configure.in.in
@@ -0,0 +1,203 @@
+# Check for libart
+KDE_FIND_PATH(libart2-config, LIBART_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin],)
+
+if test -n "$LIBART_CONFIG"; then
+ vers=`$LIBART_CONFIG --version 2>/dev/null | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'`
+ if test -n "$vers" && test "$vers" -ge 2003008
+ then
+ LIBART_LIBS="`$LIBART_CONFIG --libs`"
+ LIBART_RPATH=
+ for args in $LIBART_LIBS; do
+ case $args in
+ -L*)
+ LIBART_RPATH="$LIBART_RPATH $args"
+ ;;
+ esac
+ done
+ LIBART_RPATH=`echo $LIBART_RPATH | sed -e "s/-L/-R/g"`
+ LIBART_CFLAGS="`$LIBART_CONFIG --cflags`"
+
+ AC_DEFINE_UNQUOTED(HAVE_LIBART, 1, [Defines if your system has the libart library])
+ fi
+fi
+
+AC_SUBST(LIBART_LIBS)
+AC_SUBST(LIBART_CFLAGS)
+AC_SUBST(LIBART_RPATH)
+
+if test -z "$LIBART_LIBS"; then
+ DO_NOT_COMPILE="$DO_NOT_COMPILE ksvg"
+fi
+
+# Check for fontconfig
+KDE_FIND_PATH(fontconfig-config, FONTCONFIG_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin], [
+ KDE_FIND_PATH( pkg-config, PKG_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin /usr/bin],)
+ if test -n "$PKG_CONFIG"; then
+ if ! $PKG_CONFIG --exists fontconfig; then
+ unset PKG_CONFIG
+ fi
+ fi
+])
+if test -n "$FONTCONFIG_CONFIG" -o -n "$PKG_CONFIG"; then
+ if test -n "$FONTCONFIG_CONFIG"; then
+ fontconfigvers="`$FONTCONFIG_CONFIG --version 2>/dev/null | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'`"
+ fontconfiglibs="`$FONTCONFIG_CONFIG --libs`"
+ fontconfigcflags="`$FONTCONFIG_CONFIG --cflags`"
+ else
+ fontconfigvers=`$PKG_CONFIG --modversion fontconfig 2>/dev/null | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3; }'`
+ fontconfiglibs=`$PKG_CONFIG --libs fontconfig`
+ fontconfigcflags="`$PKG_CONFIG --cflags fontconfig`"
+ fi
+ if test -n "$vers" && test "$vers" -ge 2002000
+ then
+ FONTCONFIG_LIBS=$fontconfiglibs
+ FONTCONFIG_RPATH=
+ for args in $FONTCONFIG_LIBS; do
+ case $args in
+ -L*)
+ FONTCONFIG_RPATH="$FONTCONFIG_RPATH $args"
+ ;;
+ esac
+ done
+ FONTCONFIG_RPATH=`echo $FONTCONFIG_RPATH | sed -e "s/-L/-R/g"`
+ FONTCONFIG_CFLAGS=$fontconfigcflags
+
+ AC_DEFINE_UNQUOTED(HAVE_FONTCONFIG, 1, [Defines if your system has the fontconfig library])
+ fi
+fi
+
+AC_SUBST(FONTCONFIG_LIBS)
+AC_SUBST(FONTCONFIG_CFLAGS)
+AC_SUBST(FONTCONFIG_RPATH)
+
+if test -z "$FONTCONFIG_LIBS"; then
+ DO_NOT_COMPILE="$DO_NOT_COMPILE ksvg"
+fi
+
+# Check for freetype2
+KDE_FIND_PATH(freetype-config, FREETYPE_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin],)
+
+if test -n "$FREETYPE_CONFIG"; then
+ vers=`$FREETYPE_CONFIG --version 2>/dev/null | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'`
+ if test -n "$vers" && test "$vers" -ge 8000002
+ then
+ FREETYPE_LIBS="`$FREETYPE_CONFIG --libs`"
+ FREETYPE_RPATH=
+ for args in $FREETYPE_LIBS; do
+ case $args in
+ -L*)
+ FREETYPE_RPATH="$FREETYPE_RPATH $args"
+ ;;
+ esac
+ done
+ FREETYPE_RPATH=`echo $FREETYPE_RPATH | sed -e "s/-L/-R/g"`
+ FREETYPE_CFLAGS="`$FREETYPE_CONFIG --cflags`"
+
+ AC_DEFINE_UNQUOTED(HAVE_FREETYPE, 1, [Defines if your system has the freetype library])
+
+ ftvers=`$FREETYPE_CONFIG --ftversion 2>/dev/null | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'`
+ if test -n "$ftvers" && test "$ftvers" -ge 2002000
+ then
+ AC_DEFINE_UNQUOTED(HAVE_FREETYPE_2_2_x, 1, [Defines if your system has the 2.2.x freetype library])
+ fi
+ fi
+fi
+
+AC_SUBST(FREETYPE_LIBS)
+AC_SUBST(FREETYPE_CFLAGS)
+AC_SUBST(FREETYPE_RPATH)
+
+if test -z "$FREETYPE_LIBS"; then
+ DO_NOT_COMPILE="$DO_NOT_COMPILE ksvg"
+fi
+
+# Check for lcms
+have_lcms_header='no'
+KDE_CHECK_HEADER(lcms/lcms.h,have_lcms_header='yes',,)
+if test "$have_lcms_header" = 'yes'
+then
+ LCMS_LIBS='-llcms'
+ AC_DEFINE(LCMS_HEADER, <lcms/lcms.h>, [The correct header])
+else
+ # Alternative! Debian does it this way...
+ KDE_CHECK_HEADER(lcms.h,have_lcms_header='yes',,)
+ if test "$have_lcms_header" = 'yes'
+ then
+ LCMS_LIBS='-llcms'
+ AC_DEFINE(LCMS_HEADER, <lcms.h>, [The correct header])
+
+ # Try to find the full path of lcms.h
+ for a in $includedir $prefix/include /usr/include /usr/local/include $kde_extra_includes; do
+ for b in lcms.h lcms/lcms.h ; do
+ if test -d "$a" && test -f "$a/$b" ; then
+ LCMSHDR="$a/$b"
+ fi
+ done
+ done
+ # Check if lcms.h was found. If not then it means that we didn't search
+ # the right dirs since the kde check already found a usable lcms.h
+ if test -n "$LCMSHDR" ; then
+ # Get lcms version
+ lcms_ver_line=`cat $LCMSHDR | grep '^// Version' `
+ if test -z "$lcms_ver_line" ; then
+ # Some versions of lcms have the version in /* */
+ lcms_ver_line=`cat $LCMSHDR | grep '^/\* Version' `
+ fi
+ lcms_ver=`echo "$lcms_ver_line" | head -n 1 | cut -d ' ' -f 3 `
+
+ # Get major and minor version numbers
+ lcms_var_maj=`echo $lcms_ver | cut -d . -f 1`
+
+ # Some versions have a character attached to the end of minor version
+ lcms_var_min=`echo $lcms_ver | cut -d . -f 2 | sed 's,[^0-9],,g'`
+
+ if test "$lcms_var_maj" -gt 1 || test "$lcms_var_min" -lt 9 ; then
+ LCMS_LIBS=''
+ fi
+ fi
+ else
+ LCMS_LIBS=''
+ fi
+fi
+
+if test -z "$LCMS_LIBS"; then
+ DO_NOT_COMPILE="$DO_NOT_COMPILE ksvg"
+fi
+
+AC_SUBST(LCMS_LIBS)
+
+# Check for fribidi
+KDE_FIND_PATH(fribidi-config, FRIBIDI_CONFIG, [${prefix}/bin ${exec_prefix}/bin /usr/local/bin /opt/local/bin],)
+
+if test -n "$FRIBIDI_CONFIG"; then
+ vers=`$FRIBIDI_CONFIG --version 2>/dev/null | awk 'BEGIN { FS = "."; } { printf "%d", ($1 * 1000 + $2) * 1000 + $3;}'`
+ if test -n "$vers" && test "$vers" -ge 10004
+ then
+ FRIBIDI_LIBS="`$FRIBIDI_CONFIG --libs`"
+ FRIBIDI_RPATH=
+ for args in $FIBIDI_LIBS; do
+ case $args in
+ -L*)
+ FRIBIDI_RPATH="$FRIBIDI_CONFIG $args"
+ ;;
+ esac
+ done
+ FRIBIDI_RPATH=`echo $FRIBIDI_RPATH | sed -e "s/-L/-R/g"`
+ FRIBIDI_CFLAGS="`$FRIBIDI_CONFIG --cflags`"
+
+ AC_DEFINE_UNQUOTED(HAVE_FRIBIDI, 1, [Defines if your system has the fribidi library])
+ fi
+fi
+
+AC_SUBST(FRIBIDI_LIBS)
+AC_SUBST(FRIBIDI_CFLAGS)
+AC_SUBST(FRIBIDI_RPATH)
+
+if test -z "$FRIBIDI_LIBS"; then
+ DO_NOT_COMPILE="$DO_NOT_COMPILE ksvg"
+fi
+
+AC_LANG_SAVE
+AC_LANG_CPLUSPLUS
+AC_CHECK_HEADERS(sstream)
+AC_LANG_RESTORE
diff --git a/ksvg/core/CanvasFactory.cpp b/ksvg/core/CanvasFactory.cpp
new file mode 100644
index 00000000..ca2822b2
--- /dev/null
+++ b/ksvg/core/CanvasFactory.cpp
@@ -0,0 +1,176 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qfile.h>
+
+#include <kdebug.h>
+#include <ksimpleconfig.h>
+#include <kparts/componentfactory.h>
+
+#include "KSVGCanvas.h"
+#include "CanvasFactory.h"
+
+using namespace KSVG;
+
+CanvasFactory *CanvasFactory::s_factory = 0;
+
+CanvasFactory::CanvasFactory()
+{
+ m_canvasList.setAutoDelete(true);
+}
+
+CanvasFactory::~CanvasFactory()
+{
+}
+
+CanvasFactory *CanvasFactory::self()
+{
+ if(!s_factory)
+ s_factory = new CanvasFactory();
+
+ return s_factory;
+}
+
+void CanvasFactory::cleanup()
+{
+ m_canvasList.clear();
+}
+
+void CanvasFactory::queryCanvas()
+{
+ m_canvasList.clear();
+
+ QValueList<KService::Ptr> traderList = KTrader::self()->query("KSVG/Renderer", "(Type == 'Service')");
+ KTrader::OfferList::Iterator it(traderList.begin());
+ for( ; it != traderList.end(); ++it)
+ {
+ KService::Ptr ptr = (*it);
+
+ QString name = ptr->property("Name").toString();
+ QString internal = ptr->property("X-KSVG-InternalName").toString();
+ if(name.isEmpty() || internal.isEmpty())
+ continue;
+
+ CanvasInfo *cinfo = new CanvasInfo();
+ cinfo->service = ptr;
+ cinfo->canvas = 0;
+ cinfo->name = name;
+ cinfo->internal = internal;
+
+ m_canvasList.append(cinfo);
+ }
+
+ if(m_canvasList.isEmpty())
+ {
+ kdError(26001) << "Couldn't load any canvas!!! FATAL ERROR." << endl;
+ return;
+ }
+}
+
+KSVGCanvas *CanvasFactory::loadCanvas(int width, int height)
+{
+ queryCanvas();
+
+ KSimpleConfig *config = new KSimpleConfig("ksvgpluginrc", false);
+ config->setGroup("Canvas");
+ QString load = config->readEntry("ActiveCanvas", "libart");
+ delete config;
+
+ QPtrListIterator<CanvasInfo> it(m_canvasList);
+ CanvasInfo *info = it.current();
+ while((info = it.current()) != 0)
+ {
+ if(info->internal == load)
+ {
+ QStringList args;
+ args.prepend(QString::number(width));
+ args.prepend(QString::number(height));
+
+ info->canvas = KParts::ComponentFactory::createInstanceFromLibrary<KSVGCanvas>(QFile::encodeName(info->service->library()), 0, 0, args);
+
+ if(info->canvas)
+ return info->canvas;
+ else
+ {
+ kdError(26001) << "Failed to load canvas: " << load << " FATAL ERROR." << endl;
+ break;
+ }
+ }
+
+ ++it;
+ }
+
+ return 0;
+}
+
+int CanvasFactory::itemInList(KSVGCanvas *canvas)
+{
+ QPtrListIterator<CanvasInfo> it(m_canvasList);
+ CanvasInfo *info = it.current();
+ unsigned int i = 0;
+ while((info = it.current()) != 0)
+ {
+ if(info->canvas == canvas)
+ return i;
+
+ i++;
+ ++it;
+ }
+
+ return 0;
+}
+
+QString CanvasFactory::internalNameFor(const QString &name)
+{
+ QPtrListIterator<CanvasInfo> it(m_canvasList);
+ CanvasInfo *info = it.current();
+ while((info = it.current()) != 0)
+ {
+ if(info->name == name)
+ return info->internal;
+
+ ++it;
+ }
+
+ return QString::null;
+}
+
+void CanvasFactory::deleteCanvas(KSVGCanvas *canvas)
+{
+ QPtrListIterator<CanvasInfo> it(m_canvasList);
+ CanvasInfo *info = it.current();
+ while((info = it.current()) != 0)
+ {
+ if(info->canvas == canvas)
+ {
+ delete info->canvas;
+ info->canvas = 0;
+ }
+
+ ++it;
+ }
+}
+
+QPtrList<CanvasInfo> CanvasFactory::canvasList()
+{
+ return m_canvasList;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/core/CanvasFactory.h b/ksvg/core/CanvasFactory.h
new file mode 100644
index 00000000..dc272700
--- /dev/null
+++ b/ksvg/core/CanvasFactory.h
@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef CANVASFACTORY_H
+#define CANVASFACTORY_H
+
+#include <ktrader.h>
+
+#include <qstring.h>
+#include <qptrlist.h>
+
+namespace KSVG
+{
+
+class KSVGCanvas;
+class CanvasInfo
+{
+public:
+ KService::Ptr service;
+ KSVGCanvas *canvas;
+ QString name, internal;
+};
+
+class CanvasFactory
+{
+public:
+ CanvasFactory();
+ ~CanvasFactory();
+
+ static CanvasFactory *self();
+
+ void cleanup();
+ KSVGCanvas *loadCanvas(int width, int height);
+
+ int itemInList(KSVGCanvas *canvas);
+ QString internalNameFor(const QString &name);
+ void deleteCanvas(KSVGCanvas *canvas);
+
+ QPtrList<CanvasInfo> canvasList();
+
+private:
+ void queryCanvas();
+
+ static CanvasFactory *s_factory;
+ QPtrList<CanvasInfo> m_canvasList;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/core/CanvasItem.h b/ksvg/core/CanvasItem.h
new file mode 100644
index 00000000..7ffc7ad9
--- /dev/null
+++ b/ksvg/core/CanvasItem.h
@@ -0,0 +1,154 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef CANVASITEM_H
+#define CANVASITEM_H
+
+#include <qrect.h>
+#include <qpoint.h>
+#include <qvaluelist.h>
+
+#define CHUNK_SIZE_HORIZONTAL 32
+#define CHUNK_SIZE_VERTICAL 32
+
+namespace KSVG
+{
+
+class SVGElementImpl;
+
+enum RenderContext
+{
+ /* NONE = for initializing */
+ NONE = 0,
+ /* NORMAL = use baseVal()'s for calculation, and fillRule */
+ NORMAL = 1,
+ /* CLIPPING = use baseVal()'s for calculation, and clipRule */
+ CLIPPING = 2,
+ /* ANIMATION = use animVal()'s for calculation, and fillRule */
+ ANIMATION = 4
+};
+
+enum CanvasItemUpdate
+{
+ UPDATE_STYLE,
+ UPDATE_LINEWIDTH,
+ UPDATE_TRANSFORM,
+ UPDATE_ZOOM,
+ UPDATE_PAN
+};
+
+class CanvasItem
+{
+public:
+ CanvasItem() { m_zIndex = 0; m_referenced = false; }
+ virtual ~CanvasItem() { }
+
+ virtual QRect bbox() const = 0;
+ virtual bool fillContains(const QPoint &) = 0;
+ virtual bool strokeContains(const QPoint &) = 0;
+ virtual void update(CanvasItemUpdate reason, int param1 = 0, int param2 = 0) = 0;
+ virtual void draw() = 0;
+ virtual bool isVisible() = 0;
+
+ void setZIndex(unsigned int zIndex) { m_zIndex = zIndex; }
+ unsigned int zIndex() const { return m_zIndex; }
+
+ void setReferenced(bool referenced) { m_referenced = referenced; }
+ bool referenced() const { return m_referenced; }
+
+ virtual SVGElementImpl *element() const { return 0; }
+
+protected:
+ unsigned int m_zIndex;
+ bool m_referenced;
+};
+
+class CanvasItemPtr
+{
+public:
+ CanvasItemPtr() : ptr(0) { }
+ CanvasItemPtr(CanvasItem *p) : ptr(p) { }
+
+ bool operator<=(const CanvasItemPtr& that) const
+ {
+ // Order same-z objects by identity.
+ if(that.ptr->zIndex() == ptr->zIndex())
+ return that.ptr >= ptr;
+ return that.ptr->zIndex() >= ptr->zIndex();
+ }
+ bool operator<(const CanvasItemPtr& that) const
+ {
+ // Order same-z objects by identity.
+ if(that.ptr->zIndex() == ptr->zIndex())
+ return that.ptr > ptr;
+ return that.ptr->zIndex() > ptr->zIndex();
+ }
+ bool operator>(const CanvasItemPtr& that) const
+ {
+ // Order same-z objects by identity.
+ if(that.ptr->zIndex() == ptr->zIndex())
+ return that.ptr < ptr;
+ return that.ptr->zIndex() < ptr->zIndex();
+ }
+ bool operator==(const CanvasItemPtr& that) const { return that.ptr == ptr; }
+ operator CanvasItem *() const { return ptr; }
+
+private:
+ CanvasItem *ptr;
+};
+
+class CanvasItemList : public QValueList<CanvasItem *>
+{
+public:
+ void sort() { qHeapSort(*((QValueList<CanvasItemPtr> *) this)); }
+};
+
+class CanvasChunk
+{
+public:
+ CanvasChunk(short x, short y) : m_x(x), m_y(y), m_dirty(false) { }
+
+ void sort() { m_list.sort(); }
+ const CanvasItemList &list() const { return m_list; }
+
+ void add(CanvasItem *item) { m_list.prepend(item); m_dirty = true; }
+ void remove(CanvasItem *item) { m_list.remove(item); m_dirty = true; }
+
+ void setDirty() { m_dirty = true; }
+ bool unsetDirty() { bool y = m_dirty; m_dirty = false; return y; }
+ bool isDirty() const { return m_dirty; }
+
+ short x() const { return m_x; }
+ short y() const { return m_y; }
+
+ QRect bbox() const { return QRect(m_x * CHUNK_SIZE_HORIZONTAL, m_y * CHUNK_SIZE_VERTICAL, CHUNK_SIZE_HORIZONTAL, CHUNK_SIZE_VERTICAL); }
+
+private:
+ CanvasItemList m_list;
+ short m_x;
+ short m_y;
+ bool m_dirty : 1;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/core/CanvasItems.cpp b/ksvg/core/CanvasItems.cpp
new file mode 100644
index 00000000..0ffd017c
--- /dev/null
+++ b/ksvg/core/CanvasItems.cpp
@@ -0,0 +1,509 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "KSVGCanvas.h"
+#include "KSVGHelper.h"
+#include "KSVGTextChunk.h"
+
+#include "CanvasItems.h"
+
+#include "SVGMatrixImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGPathElementImpl.h"
+#include "SVGMarkerElementImpl.h"
+#include "SVGTSpanElementImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGAnimatedStringImpl.h"
+#include "SVGAnimatedLengthListImpl.h"
+#include "SVGAnimatedEnumerationImpl.h"
+
+#include <Glyph.h>
+#include <Converter.h>
+#include <Font.h>
+
+#include <kdebug.h>
+
+using namespace KSVG;
+
+CanvasText::CanvasText(SVGTextElementImpl *text) : CanvasItem(), m_text(text)
+{
+}
+
+CanvasText::~CanvasText()
+{
+}
+
+void CanvasText::handleTSpan(KSVGCanvas *canvas, const SVGMatrixImpl *screenCTM, int &curx, int &cury, int &endx, int &endy, SVGElementImpl *element, KSVGTextChunk *textChunk, T2P::BezierPath *bpath)
+{
+ SVGTSpanElementImpl *tspan = dynamic_cast<SVGTSpanElementImpl *>(element);
+ if(!tspan)
+ return;
+
+ if(!tspan->text().isEmpty() || element->nodeName() == "tref")
+ {
+ if((KSVG_TOKEN_NOT_PARSED_ELEMENT(SVGTextPositioningElementImpl::X, tspan) && KSVG_TOKEN_NOT_PARSED_ELEMENT(SVGTextPositioningElementImpl::Y, tspan)))// && !bpath)
+ textChunk->addText(tspan->text(), tspan);
+ else
+ {
+ // new absolute value for next textChunk, render old one
+ if(textChunk->count() > 0)
+ {
+ createGlyphs(textChunk, canvas, screenCTM, curx, cury, curx, cury, bpath);
+ textChunk->clear();
+ }
+
+ int usex, usey;
+ bool bMultipleX = false;
+ bool bMultipleY = false;
+
+ if(tspan->x()->baseVal()->numberOfItems() == 0)
+ {
+ usex = curx;
+
+ if(tspan->dx()->baseVal()->numberOfItems() > 0)
+ usex += int(tspan->dx()->baseVal()->getItem(0)->value());
+ }
+ else
+ {
+ if(tspan->x()->baseVal()->numberOfItems() > 1)
+ bMultipleX = true;
+
+ usex = int(tspan->x()->baseVal()->getItem(0)->value());
+ }
+
+ if(tspan->y()->baseVal()->numberOfItems() == 0)
+ {
+ usey = cury;
+
+ if(tspan->dy()->baseVal()->numberOfItems() > 0)
+ usey += int(tspan->dy()->baseVal()->getItem(0)->value());
+ }
+ else
+ {
+ if(tspan->y()->baseVal()->numberOfItems() > 1)
+ bMultipleY = true;
+
+ usey = int(tspan->y()->baseVal()->getItem(0)->value());
+ }
+
+ QString text = tspan->text();
+ if(!text.isEmpty())
+ {
+ T2P::GlyphLayoutParams *params = tspan->layoutParams();
+
+ if(bMultipleX || bMultipleY)
+ {
+ for(unsigned int i = 0; i < text.length(); i++)
+ {
+ if(bMultipleX && i < tspan->x()->baseVal()->numberOfItems())
+ usex = int(tspan->x()->baseVal()->getItem(i)->value());
+ if(bMultipleY && i < tspan->y()->baseVal()->numberOfItems())
+ usey = int(tspan->y()->baseVal()->getItem(i)->value());
+
+ textChunk->addText(QString(text.at(i)), tspan);
+ createGlyphs(textChunk, canvas, screenCTM, usex, usey, endx, endy, bpath);
+ textChunk->clear();
+
+ if(!params->tb())
+ usex += endx;
+ else
+ usey += endy;
+ }
+ }
+ else
+ {
+ textChunk->addText(text, tspan);
+ //createGlyphs(textChunk, canvas, screenCTM, usex, usey, endx, endy, bpath);
+ //textChunk->clear();
+ }
+
+ curx = usex;
+ cury = usey;
+
+ if(!params->tb())
+ curx += endx;
+ else
+ cury += endy;
+
+ delete params;
+ }
+ }
+ }
+
+ DOM::Node node = (tspan->getTextDirection() == LTR) ? tspan->firstChild() : tspan->lastChild();
+
+ bool tspanFound = false;
+ for(; !node.isNull(); node = ((tspan->getTextDirection() == LTR) ? node.nextSibling() : node.previousSibling()))
+ {
+ SVGElementImpl *element = m_text->ownerDoc()->getElementFromHandle(node.handle());
+ if(node.nodeType() == DOM::Node::TEXT_NODE)
+ {
+ if(tspanFound)
+ {
+ DOM::Text text = node;
+ QString temp = text.data().string();
+ textChunk->addText(temp, tspan);
+ }
+ }
+ else if(element->nodeName() == "tspan" || element->nodeName() == "tref")
+ {
+ tspanFound = true;
+ handleTSpan(canvas, screenCTM, curx, cury, endx, endy, element, textChunk, 0);
+ }
+ }
+
+}
+
+KSVGTextChunk *CanvasText::createTextChunk(KSVGCanvas *canvas, const SVGMatrixImpl *screenCTM, int &curx, int &cury, int &endx, int &endy)
+{
+ KSVGTextChunk *textChunk = new KSVGTextChunk();
+
+ SVGLengthImpl *length = m_text->x()->baseVal()->getItem(0);
+ if(length)
+ curx = int(length->value());
+
+ length = m_text->y()->baseVal()->getItem(0);
+ if(length)
+ cury = int(length->value());
+
+ // Otherwhise some js scripts which require a child, don't work (Niko)
+ if(!m_text->hasChildNodes())
+ {
+ DOM::Text impl = static_cast<DOM::Document *>(m_text->ownerDoc())->createTextNode(DOM::DOMString(""));
+ m_text->appendChild(impl);
+ }
+ else
+ {
+ DOM::Node node = (m_text->getTextDirection() == LTR) ? m_text->firstChild() : m_text->lastChild();
+
+ for(; !node.isNull(); node = ((m_text->getTextDirection() == LTR) ? node.nextSibling() : node.previousSibling()))
+ {
+ if(node.nodeType() == DOM::Node::TEXT_NODE)
+ {
+ DOM::Text text = node;
+ QString temp = text.data().string();
+
+ if(!temp.isEmpty())
+ {
+ if(m_text->getTextDirection() != LTR)
+ {
+ QString convert = temp;
+
+ for(int i = temp.length(); i > 0; i--)
+ convert[temp.length() - i] = temp[i - 1];
+
+ temp = convert;
+ }
+
+ textChunk->addText(temp, m_text);
+ }
+ }
+ else
+ {
+ SVGElementImpl *element = m_text->ownerDoc()->getElementFromHandle(node.handle());
+ if(element->nodeName() == "textPath")
+ {
+ // new absolute value for next textChunk, render old one
+ if(textChunk->count() > 0)
+ {
+ createGlyphs(textChunk, canvas, screenCTM, curx, cury, curx, cury);
+ textChunk->clear();
+ }
+
+ SVGTextPathElementImpl *tpath = dynamic_cast<SVGTextPathElementImpl *>(element);
+ QString target = SVGURIReferenceImpl::getTarget(tpath->href()->baseVal().string());
+ SVGPathElementImpl *path = dynamic_cast<SVGPathElementImpl *>(tpath->ownerSVGElement()->getElementById(target));
+
+ T2P::BezierPath *bpath = 0;
+ if(path && path->item())
+ bpath = tpath->ownerDoc()->canvas()->toBezierPath(path->item());
+
+ DOM::Node iterate = tpath->firstChild();
+ for(; !iterate.isNull(); iterate = iterate.nextSibling())
+ {
+ if(iterate.nodeType() == DOM::Node::TEXT_NODE)
+ {
+ DOM::Text text = iterate;
+ QString temp = text.data().string();
+
+ if(!temp.isEmpty())
+ textChunk->addText(temp, tpath);
+ }
+ else
+ {
+ kdDebug() << "FOUND TSPAN IN TEXTPATH! BPATH:" << bpath <<endl;
+
+ SVGElementImpl *itelement = m_text->ownerDoc()->getElementFromHandle(iterate.handle());
+ handleTSpan(canvas, screenCTM, curx, cury, endx, endy, itelement, textChunk, bpath);
+ }
+ }
+
+ if(textChunk->count() > 0)
+ {
+ int usex = 0, usey = 0;
+ createGlyphs(textChunk, canvas, screenCTM, usex, usey, endx, endy, bpath);
+ textChunk->clear();
+
+ curx = usex;
+ cury = usey;
+
+ T2P::GlyphLayoutParams *params = tpath->layoutParams();
+
+ if(!params->tb())
+ curx += endx;
+ else
+ cury += endy;
+
+ delete params;
+ }
+ }
+ else if(element->nodeName() == "tspan" || element->nodeName() == "tref")
+ handleTSpan(canvas, screenCTM, curx, cury, endx, endy, element, textChunk, 0);
+ }
+ }
+ }
+
+ return textChunk;
+}
+
+void CanvasText::createGlyphs(KSVGTextChunk *textChunk, KSVGCanvas *canvas, const SVGMatrixImpl *screenCTM, int curx, int cury, int &endx, int &endy, T2P::BezierPath *bpath) const
+{
+ double _curx = double(curx);
+ QMemArray<double> _cury(1);
+ _cury[0] = double(cury);
+
+ T2P::GlyphLayoutParams *params = m_text->layoutParams();
+ SVGTextPositioningElementImpl *tp = textChunk->getTextElement(0);
+ SVGTextContentElementImpl *tc = textChunk->getTextContentElement(0);
+ SVGTextContentElementImpl *tc0 = tc;
+
+ T2P::SharedFont font;
+ QString text;
+ QPtrList<T2P::GlyphSet> glyphs;
+ glyphs.setAutoDelete(true);
+
+ double pathAdvance = 0;
+ SVGTextPathElementImpl *tpath = dynamic_cast<SVGTextPathElementImpl *>(tc0);
+ if(tpath)
+ pathAdvance = tpath->startOffset()->baseVal()->value();
+ double pathLength = bpath ? bpath->length() : 0;
+ double pathDy = 0;
+ for(unsigned int i = 0; i < textChunk->count(); i++)
+ {
+ tp = textChunk->getTextElement(i);
+ tc = textChunk->getTextContentElement(i);
+
+ if(tp && tp->dx()->baseVal()->numberOfItems() > 0)
+ if(bpath)
+ pathAdvance += tp->dx()->baseVal()->getItem(0)->value() / pathLength;
+ else
+ _curx += tp->dx()->baseVal()->getItem(0)->value();
+ _cury[i] += (tp && tp->dy()->baseVal()->numberOfItems() > 0) ? tp->dy()->baseVal()->getItem(0)->value() : 0;
+
+ SVGMatrixImpl *tempMatrix = SVGSVGElementImpl::createSVGMatrix();
+ tempMatrix->translate(_curx, _cury[i]);
+
+ text = textChunk->getText(i);
+ if(i != textChunk->count() - 1)
+ text += QChar(' ');
+
+ if(!canvas->fontContext()->ready())
+ canvas->fontContext()->init();
+
+ font = canvas->fontContext()->requestFont(canvas->fontVisualParams(tc));
+
+ if(!font)
+ break;
+
+ double addLetterSpacing = 0;
+
+ // Apply affine corrections, through lengthAdjust + textLength
+ if(tp && tp->textLength()->baseVal()->value() != -1)
+ {
+ // #1 Measure text
+ SVGTextElementImpl *textElement = dynamic_cast<SVGTextElementImpl *>(tp);
+ const SVGMatrixImpl *ctm = textElement->screenCTM();
+
+ T2P::Affine affine;
+ {
+ SVGMatrixImpl *temp = SVGSVGElementImpl::createSVGMatrix();
+
+ temp->multiply(ctm);
+ temp->translate(_curx, _cury[0]);
+
+ KSVGHelper::matrixToAffine(temp, affine);
+
+ temp->deref();
+ }
+
+ T2P::GlyphSet *measure = canvas->fontContext()->calcString(font.get(), text.ucs2(), text.length(), affine, params, bpath);
+
+ // Free bpath's
+ measure->set().clear();
+
+ // #2 Calculate textLength
+ double textLength = tp->textLength()->baseVal()->value();
+
+ // #3 Apply the spacing
+ if(tp->lengthAdjust()->baseVal() == LENGTHADJUST_SPACINGANDGLYPHS)
+ tempMatrix->scaleNonUniform((textLength * ctm->a()) / measure->width(), 1);
+ else if(tp->lengthAdjust()->baseVal() == LENGTHADJUST_SPACING)
+ addLetterSpacing = ((textLength - (measure->width() / ctm->a())) / text.length());
+
+ // #4 cleanup
+ delete measure;
+ }
+
+ {
+ T2P::GlyphLayoutParams *params = tc->layoutParams();
+ params->setLetterSpacing(params->letterSpacing() + addLetterSpacing);
+ if(bpath)
+ {
+ params->setTextPathStartOffset(pathAdvance);
+ if(tp && tp->dy()->baseVal()->numberOfItems() > 0)
+ pathDy += tp->dy()->baseVal()->getItem(0)->value();
+ QString shift = QString("%1%%").arg((pathDy / font->fontParams()->size()) * -100.0);
+ params->setBaselineShift(shift.latin1());
+ }
+
+ T2P::Affine affine;
+ KSVGHelper::matrixToAffine(tempMatrix, affine);
+ tempMatrix->deref();
+
+ T2P::GlyphSet *glyph = canvas->fontContext()->calcString(font.get(), text.ucs2(), text.length(), affine, params, bpath);
+ if(bpath)
+ pathAdvance += double(glyph->width()) / pathLength;
+ _curx += (params->tb() ? 0 : glyph->xpen());
+ _cury.resize(i + 2);
+ _cury[i + 1] = _cury[i] + (params->tb() ? glyph->ypen() : 0);
+ if(!glyph)
+ break;
+ else
+ glyphs.append(glyph);
+
+ delete params;
+ }
+ }
+
+ // Calculate text-anchor
+ double anchor = 0;
+
+ // anchor == "start" is the default here (Rob)
+ if(tc->getTextAnchor() == TAMIDDLE)
+ {
+ if(!params->tb())
+ anchor = ((_curx - curx) + 1) / 2;
+ else
+ anchor = ((_cury[textChunk->count()] - cury) + 1) / 2;
+ }
+ else if(tc->getTextAnchor() == TAEND)
+ {
+ if(!params->tb())
+ anchor = (_curx - curx);
+ else
+ anchor = (_cury[textChunk->count()] - cury);
+ }
+
+ // Render all glyphs of the text chunk
+ // Take first glyphset
+ T2P::GlyphSet *glyph = glyphs.at(0);
+ if(!glyph)
+ return;
+
+ // Draw 'text-decoration'
+ // TODO: Currently just ignore text-decoration on vertical layouts, is that correct?
+ // Underline and overline have to be drawn before the glyphs are rendered
+ if(tc0->getTextDecoration() & UNDERLINE && !params->tb())
+ addTextDecoration(tc0, (curx - anchor), (cury + (glyph->underlinePosition() - glyph->pixelBaseline())),
+ _curx - curx, glyph->underlineThickness());
+ if(tc0->getTextDecoration() & OVERLINE && !params->tb())
+ addTextDecoration(tc0, (curx - anchor), (cury + (glyph->overlinePosition() - glyph->pixelBaseline())),
+ _curx - curx, glyph->underlineThickness());
+
+ for(unsigned int j = 0; j < glyphs.count(); j++)
+ {
+ glyph = glyphs.at(j);
+ SVGTextContentElementImpl *style = textChunk->getTextContentElement(j);
+
+ // Draw 'text-decoration'
+ // TODO: Currently just ignore text-decoration on vertical layouts, is that correct?
+ // Underline and overline have to be drawn before the glyphs are rendered
+ if(style->getAttribute("text-decoration") == "underline" && !params->tb())
+ addTextDecoration(style, glyph->bboxX() - anchor, (cury + (glyph->underlinePosition() - glyph->pixelBaseline())),
+ glyph->width(), glyph->underlineThickness());
+ else if(style->getAttribute("text-decoration") == "overline" && !params->tb())
+ addTextDecoration(style, glyph->bboxX() - anchor, (cury + (glyph->overlinePosition() - glyph->pixelBaseline())),
+ glyph->width(), glyph->underlineThickness());
+
+ renderCallback(style, screenCTM, glyph, params, anchor);
+
+ // Clear GlyphAffinePair's
+ for(std::vector<T2P::GlyphAffinePair *>::iterator it = glyph->set().begin(); it != glyph->set().end(); ++it)
+ {
+ T2P::GlyphAffinePair *glyphAffine = *it;
+ delete glyphAffine;
+ }
+
+ glyph->set().clear();
+
+ // Draw 'line-through' text decoration
+ // Line-through has to be drawn after the glyphs are rendered
+ if(style->getAttribute("text-decoration") == "line-through" && !params->tb())
+ addTextDecoration(style, glyph->bboxX() - anchor, (cury + (glyph->strikeThroughPosition() - glyph->pixelBaseline())), glyph->width(), glyph->underlineThickness());
+
+ }
+
+ endx = glyph->bboxX() + glyph->width();
+ endy = int(_cury[glyphs.count() - 1]);
+
+ // Draw 'line-through' text decoration
+ // Line-through has to be drawn after the glyphs are rendered
+ if(tc0->getTextDecoration() & LINE_THROUGH && !params->tb())
+ addTextDecoration(tc0, (curx - anchor), (cury + (glyph->strikeThroughPosition() - glyph->pixelBaseline())), _curx - curx, glyph->underlineThickness());
+
+ delete params;
+}
+
+// #####
+
+void MarkerHelper::doMarker(SVGShapeImpl *shape, SVGStylableImpl *style, double x, double y, double angle, const QString &markerId)
+{
+ SVGMarkerElementImpl *marker = dynamic_cast<SVGMarkerElementImpl *>(shape->ownerSVGElement()->getElementById(markerId));
+ if(marker)
+ marker->draw(shape, x, y, style->getStrokeWidth()->baseVal()->value(), angle);
+}
+
+void MarkerHelper::doStartMarker(SVGShapeImpl *shape, SVGStylableImpl *style, double x, double y, double angle)
+{
+ doMarker(shape, style, x, y, angle, style->getStartMarker());
+}
+
+void MarkerHelper::doMidMarker(SVGShapeImpl *shape, SVGStylableImpl *style, double x, double y, double angle)
+{
+ doMarker(shape, style, x, y, angle, style->getMidMarker());
+}
+
+void MarkerHelper::doEndMarker(SVGShapeImpl *shape, SVGStylableImpl *style, double x, double y, double angle)
+{
+ doMarker(shape, style, x, y, angle, style->getEndMarker());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/core/CanvasItems.h b/ksvg/core/CanvasItems.h
new file mode 100644
index 00000000..8959d6ba
--- /dev/null
+++ b/ksvg/core/CanvasItems.h
@@ -0,0 +1,133 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef CANVASITEMS_H
+#define CANVASITEMS_H
+
+#include <qptrlist.h>
+#include "CanvasItem.h"
+#include "SVGTextElementImpl.h"
+#include "SVGTextPathElementImpl.h"
+
+#include "svgpathparser.h"
+#include "SVGBBoxTarget.h"
+
+namespace T2P
+{
+ class GlyphSet;
+ class BezierPath;
+ class GlyphLayoutParams;
+}
+
+namespace KSVG
+{
+
+class KSVGCanvas;
+class KSVGTextChunk;
+class SVGPathParser;
+class SVGMatrixImpl;
+class SVGMarkerElementImpl;
+class SVGClipPathElementImpl;
+class SVGTextContentElementImpl;
+class SVGTextPathElementImpl;
+
+#define CANVAS_CLASS(Prefix, Class, Postfix, Member) \
+class Canvas##Class : public CanvasItem \
+{ \
+public: \
+ Canvas##Class(Prefix##Class##Postfix *Member) : CanvasItem(), m_##Member(Member) { } \
+ virtual ~Canvas##Class() { } \
+ virtual SVGElementImpl *element() { return reinterpret_cast<SVGElementImpl *>(m_##Member); } \
+protected: \
+ Prefix##Class##Postfix *m_##Member; \
+};
+
+CANVAS_CLASS(SVG, ClipPath, ElementImpl, clipPath)
+
+class CanvasMarker : public CanvasItem
+{
+public:
+ CanvasMarker(SVGMarkerElementImpl *marker) : CanvasItem(), m_marker(marker) {}
+ virtual ~CanvasMarker() {}
+ virtual SVGElementImpl *element() { return reinterpret_cast<SVGElementImpl *>(m_marker); }
+
+ virtual void draw(SVGShapeImpl *obj, double x, double y, double lwidth = 1.0, double angle = 0.0)
+ {
+ Q_UNUSED(obj); Q_UNUSED(x); Q_UNUSED(y); Q_UNUSED(lwidth); Q_UNUSED(angle);
+ }
+
+protected:
+ SVGMarkerElementImpl *m_marker;
+};
+
+class MarkerHelper
+{
+protected:
+ void doStartMarker(SVGShapeImpl *shape, SVGStylableImpl *style, double x, double y, double angle = 0.0);
+ void doMidMarker(SVGShapeImpl *shape, SVGStylableImpl *style, double x, double y, double angle = 0.0);
+ void doEndMarker(SVGShapeImpl *shape, SVGStylableImpl *style, double x, double y, double angle = 0.0);
+
+private:
+ void doMarker(SVGShapeImpl *shape, SVGStylableImpl *style, double x, double y, double angle, const QString &marker);
+};
+
+class CanvasText : public CanvasItem
+{
+public:
+ CanvasText(SVGTextElementImpl *text);
+ virtual ~CanvasText();
+
+ KSVGTextChunk *createTextChunk(KSVGCanvas *canvas, const SVGMatrixImpl *screenCTM, int &curx, int &cury, int &endx, int &endy);
+ virtual SVGElementImpl *element() const { return m_text; }
+
+ virtual void renderCallback(SVGTextContentElementImpl *element, const SVGMatrixImpl *screenCTM, T2P::GlyphSet *glyph, T2P::GlyphLayoutParams *params, double anchor) const = 0;
+ void createGlyphs(KSVGTextChunk *textChunk, KSVGCanvas *canvas, const SVGMatrixImpl *screenCTM, int curx, int cury, int &endx, int &endy, T2P::BezierPath *bpath = 0) const;
+
+ virtual void addTextDecoration(SVGTextContentElementImpl *element, double x, double y, double w, double h) const = 0;
+
+private:
+ void handleTSpan(KSVGCanvas *canvas, const SVGMatrixImpl *screenCTM, int &curx, int &cury, int &endx, int &endy, SVGElementImpl *element, KSVGTextChunk *textChunk, T2P::BezierPath *bpath);
+
+protected:
+ SVGTextElementImpl *m_text;
+};
+
+class CanvasPaintServer : public SVGBBoxTarget
+{
+public:
+ CanvasPaintServer() : SVGBBoxTarget() { m_finalized = false; }
+ virtual ~CanvasPaintServer() {}
+
+ void setFinalized() { m_finalized = true; }
+ void resetFinalized() { m_finalized = false; }
+ bool finalized() { return m_finalized; }
+
+ virtual void finalizePaintServer() = 0;
+ virtual void reference(const QString &href) = 0;
+
+private:
+ bool m_finalized;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/core/DocumentFactory.cpp b/ksvg/core/DocumentFactory.cpp
new file mode 100644
index 00000000..bcc0ddcb
--- /dev/null
+++ b/ksvg/core/DocumentFactory.cpp
@@ -0,0 +1,110 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qobject.h>
+
+#include <kdebug.h>
+#include <kstaticdeleter.h>
+
+#include "SVGDocument.h"
+#include "SVGElementImpl.h"
+#include "SVGDocumentImpl.h"
+#include "DocumentFactory.h"
+
+using namespace KSVG;
+
+namespace KSVG
+{
+ class DocumentFactory::Private
+ {
+ public:
+ Private() { m_docs.setAutoDelete(true); }
+ ~Private() { m_docs.clear(); }
+
+ void setup(bool bFit) { m_docs.append(new SVGDocumentImpl(!bFit /* animations */, bFit)); }
+ SVGDocumentImpl *doc() const { return m_docs.current(); }
+
+ private:
+ QPtrList<SVGDocumentImpl> m_docs;
+ };
+}
+
+static KStaticDeleter<DocumentFactory> s_deleter;
+static DocumentFactory *s_factory = 0;
+
+DocumentFactory::DocumentFactory() : m_d(new Private())
+{
+}
+
+DocumentFactory::~DocumentFactory()
+{
+ delete m_d;
+}
+
+DocumentFactory *DocumentFactory::self()
+{
+ if(!s_factory)
+ s_deleter.setObject(s_factory, new DocumentFactory());
+ return s_factory;
+}
+
+SVGDocument *DocumentFactory::requestDocument(QObject *notifyObject, const char *notifySlot) const
+{
+ SVGDocumentImpl *impl = requestDocumentImpl(false);
+ QObject::connect(impl, SIGNAL(finishedParsing(bool, const QString &)), notifyObject, notifySlot);
+
+ return new SVGDocument(impl);
+}
+
+bool DocumentFactory::startParsing(SVGDocument *document, const KURL &url)
+{
+ if(!document || !document->handle())
+ return false;
+
+ return reinterpret_cast<SVGDocumentImpl *>(document->handle())->open(url);
+}
+
+bool DocumentFactory::attachCanvas(KSVGCanvas *canvas, SVGDocument *document)
+{
+ if(!canvas || !document || !document->handle())
+ return false;
+
+ SVGDocumentImpl *docImpl = reinterpret_cast<SVGDocumentImpl *>(document->handle());
+
+ if(docImpl)
+ {
+ docImpl->attach(canvas);
+ return true;
+ }
+
+ return false;
+}
+
+SVGDocumentImpl *DocumentFactory::requestDocumentImpl(bool bFit) const
+{
+ m_d->setup(bFit);
+
+ SVGDocumentImpl *impl = m_d->doc();
+ impl->ref();
+
+ return impl;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/core/DocumentFactory.h b/ksvg/core/DocumentFactory.h
new file mode 100644
index 00000000..290d54ac
--- /dev/null
+++ b/ksvg/core/DocumentFactory.h
@@ -0,0 +1,63 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef DocumentFactory_H
+#define DocumentFactory_H
+
+#include <kurl.h>
+#include <qobject.h>
+
+namespace KSVG
+{
+
+class KSVGCanvas;
+class SVGDocument;
+class SVGDocumentImpl;
+class DocumentFactory
+{
+public:
+ DocumentFactory();
+ ~DocumentFactory();
+
+ static DocumentFactory *self();
+
+ // Creates a document and connects the parsingFinished() signal to the notifySlot...
+ SVGDocument *requestDocument(QObject *notifyObject, const char *notifySlot) const;
+
+ // Loads 'url' and emits parsingFinisihed() signal, when done
+ bool startParsing(SVGDocument *document, const KURL &url);
+
+ // Attaches the a canvas to the document, that is ksvg specific code
+ bool attachCanvas(KSVGCanvas *canvas, SVGDocument *document);
+
+ // Internal use only - external coders don't have the
+ // possibility to use SVGDocumentImpl anyway
+ SVGDocumentImpl *requestDocumentImpl(bool bFit) const;
+
+private:
+ class Private;
+ Private *m_d;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/core/KSVGCanvas.cpp b/ksvg/core/KSVGCanvas.cpp
new file mode 100644
index 00000000..d4e75d79
--- /dev/null
+++ b/ksvg/core/KSVGCanvas.cpp
@@ -0,0 +1,786 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "CanvasItem.h"
+#include "CanvasItems.h"
+#include "KSVGCanvas.moc"
+
+#include "SVGRectImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGStringListImpl.h"
+#include "SVGClipPathElementImpl.h"
+#include "SVGImageElementImpl.h"
+#include "SVGDocumentImpl.h"
+
+#include <kdebug.h>
+#include <kglobal.h>
+
+#include <qstring.h>
+#include <qdatetime.h>
+#include <qpaintdevicemetrics.h>
+#include <qwmatrix.h>
+
+#include <X11/Xlib.h>
+
+#include <math.h>
+
+#include <libs/xrgbrender/gdk-pixbuf-xlibrgb.h>
+
+#include <Font.h>
+#include <fontconfig/fontconfig.h>
+
+#define USE_TIMER
+
+using namespace KSVG;
+
+KSVGCanvas::KSVGCanvas(unsigned int width, unsigned int height) : m_viewportWidth(width), m_viewportHeight(height), m_width(width), m_height(height)
+{
+ m_fontContext = 0;
+
+ m_items.setAutoDelete(true);
+
+ m_chunkSizeVer = CHUNK_SIZE_VERTICAL;
+ m_chunkSizeHor = CHUNK_SIZE_HORIZONTAL;
+
+ m_zoom = 1;
+
+ m_buffer = 0;
+
+ m_backgroundColor = QColor(250, 250, 250);
+
+ m_immediateUpdate = false;
+}
+
+void KSVGCanvas::setup(QPaintDevice *drawWindow, QPaintDevice *directWindow)
+{
+ m_drawWindow = drawWindow;
+ m_directWindow = directWindow;
+
+ m_buffer = 0;
+ m_nrChannels = 3;
+
+ setRenderBufferSize(m_width, m_height);
+
+ xlib_rgb_init_with_depth(m_drawWindow->x11Display(), XScreenOfDisplay(m_drawWindow->x11Display(), m_drawWindow->x11Screen()), m_drawWindow->x11Depth());
+ m_gc = XCreateGC(m_drawWindow->x11Display(), m_drawWindow->handle(), 0, 0);
+}
+
+void KSVGCanvas::setViewportDimension(unsigned int w, unsigned int h)
+{
+ m_viewportWidth = w;
+ m_viewportHeight = h;
+ setRenderBufferSize(w, h);
+}
+
+void KSVGCanvas::setup(unsigned char *buffer, unsigned int width, unsigned int height)
+{
+ setBuffer(buffer);
+ m_drawWindow = 0;
+ m_directWindow = 0;
+
+ m_nrChannels = 4;
+
+ if(height > 0)
+ {
+ m_width = width;
+ m_height = height;
+ }
+
+ setRenderBufferSize(m_width, m_height);
+
+ m_gc = 0;
+}
+
+void KSVGCanvas::setBuffer(unsigned char *buffer)
+{
+ m_buffer = buffer;
+}
+
+KSVGCanvas::~KSVGCanvas()
+{
+ if(m_fontContext)
+ delete m_fontContext;
+
+ if(m_buffer && m_gc)
+ delete []m_buffer;
+
+ if(m_gc)
+ XFreeGC(m_drawWindow->x11Display(), m_gc);
+
+ reset();
+}
+
+void KSVGCanvas::retune(unsigned int csh, unsigned int csv)
+{
+ m_chunkSizeHor = csh;
+ m_chunkSizeVer = csv;
+}
+
+void KSVGCanvas::resize(unsigned int w, unsigned int h)
+{
+ if(m_buffer && (m_width != int(w) || m_height != int(h)))
+ {
+ unsigned char *oldbuffer = m_buffer;
+
+ m_buffer = new unsigned char[w * h * m_nrChannels];
+
+ int minw = kMin(int(w), m_width);
+ int minh = kMin(int(h), m_height);
+
+ int origstride = m_width * m_nrChannels;
+ int newstride = w * m_nrChannels;
+
+ // Redraw new areas, if any
+ int diffw = w - m_width;
+ int diffh = h - m_height;
+
+ QRect r(m_width, 0, diffw, m_height + diffh);
+ QRect r3(0, m_height, m_width + diffw, diffh);
+
+ QWMatrix mtx;
+ mtx.translate(m_pan.x(), m_pan.y());
+ mtx.scale(m_zoom, m_zoom);
+
+ m_width = w;
+ m_height = h;
+
+ setBuffer(m_buffer);
+ fill();
+
+ if(diffw > 0 || diffh > 0)
+ {
+ CanvasItemList drawables;
+ if(diffw > 0)
+ {
+ QRect r2 = mtx.invert().map(r);
+
+ // Recalc items
+ for(int j = r2.top() / int(m_chunkSizeVer); j <= r2.bottom() / int(m_chunkSizeVer); j++)
+ {
+ for(int i = r2.left() / int(m_chunkSizeHor); i <= r2.right() / int(m_chunkSizeHor); i++)
+ {
+ CanvasChunk *chunk = m_chunkManager.getChunk(i, j);
+ if(chunk)
+ {
+ for(CanvasItemList::ConstIterator it = chunk->list().begin(); it != chunk->list().end(); ++it)
+ {
+ if(!drawables.contains(*it))
+ drawables.append(*it);
+ }
+ }
+ }
+ }
+ }
+
+ if(diffh > 0)
+ {
+ QRect r4 = mtx.invert().map(r3);
+
+ // Recalc items
+ for(int j = r4.top() / int(m_chunkSizeVer); j <= r4.bottom() / int(m_chunkSizeVer); j++)
+ {
+ for(int i = r4.left() / int(m_chunkSizeHor); i <= r4.right() / int(m_chunkSizeHor); i++)
+ {
+ CanvasChunk *chunk = m_chunkManager.getChunk(i, j);
+ if(chunk)
+ {
+ for(CanvasItemList::ConstIterator it = chunk->list().begin(); it != chunk->list().end(); ++it)
+ {
+ if(!drawables.contains(*it))
+ drawables.append(*it);
+ }
+ }
+ }
+ }
+ }
+
+ drawables.sort();
+
+ for(CanvasItemList::Iterator it = drawables.begin(); it != drawables.end(); ++it)
+ (*it)->draw();
+ }
+
+ for(int y = 0; y < minh; y++)
+ memcpy(m_buffer + y * newstride, oldbuffer + y * origstride, minw * m_nrChannels);
+
+ delete []oldbuffer;
+ }
+}
+
+void KSVGCanvas::setRenderBufferSize(int w, int h)
+{
+ kdDebug(26005) << k_funcinfo << endl;
+
+ if(m_drawWindow)
+ {
+ bool needsRedraw = (!m_buffer) || (m_width != w || m_height != h);
+
+ if(needsRedraw)
+ {
+ QPaintDeviceMetrics metrics(m_drawWindow);
+ m_width = kMin(int(w), metrics.width());
+ m_height = kMin(int(h), metrics.height());
+
+ if(m_buffer)
+ delete []m_buffer;
+
+ m_buffer = new unsigned char[m_width * m_height * m_nrChannels];
+ }
+ }
+
+ fill();
+}
+
+void KSVGCanvas::clear(const QRect &r)
+{
+ QRect r2 = r & QRect(0, 0, m_width, m_height);
+ if(!r2.isEmpty() && m_buffer)
+ {
+ for(int i = 0; i < r2.height(); i++)
+ memset(m_buffer + int(r2.x() * m_nrChannels) + int((r2.y() + i) * (m_width * m_nrChannels)), qRgba(250, 250, 250, 250), r2.width() * m_nrChannels);
+ }
+}
+
+void KSVGCanvas::fill()
+{
+ if(m_buffer)
+ {
+ unsigned char r = m_backgroundColor.red();
+ unsigned char g = m_backgroundColor.green();
+ unsigned char b = m_backgroundColor.blue();
+
+ if(m_nrChannels == 3)
+ {
+ if(r == g && r == b)
+ memset(m_buffer, r, m_width * m_height * m_nrChannels);
+ else
+ {
+ unsigned char *p = m_buffer;
+
+ for(int i = 0; i < m_width * m_height; i++)
+ {
+ *p++ = r;
+ *p++ = g;
+ *p++ = b;
+ }
+ }
+ }
+ else
+ {
+ Q_UINT32 *p = reinterpret_cast<Q_UINT32 *>(m_buffer);
+ unsigned char a = qAlpha(m_backgroundColor.rgb());
+
+#if X_BYTE_ORDER == X_LITTLE_ENDIAN
+ Q_UINT32 rgba = (a << 24) | (b << 16) | (g << 8) | r;
+#else
+ Q_UINT32 rgba = (r << 24) | (g << 16) | (b << 8) | a;
+#endif
+ for(int i = 0; i < m_width * m_height; i++)
+ *p++ = rgba;
+ }
+ }
+}
+
+// Clipping
+void KSVGCanvas::clipToBuffer(int &x0, int &y0, int &x1, int &y1) const
+{
+ // clamp to viewport
+ x0 = QMAX(x0, 0);
+ x0 = QMIN(x0, int(m_width - 1));
+
+ y0 = QMAX(y0, 0);
+ y0 = QMIN(y0, int(m_height - 1));
+
+ x1 = QMAX(x1, 0);
+ x1 = QMIN(x1, int(m_width - 1));
+
+ y1 = QMAX(y1, 0);
+ y1 = QMIN(y1, int(m_height - 1));
+}
+
+T2P::FontVisualParams *KSVGCanvas::fontVisualParams(SVGStylableImpl *style) const
+{
+ T2P::FontVisualParams *fontVisualParams = new T2P::FontVisualParams();
+
+ // Calc weight & slant
+ int weight = 0, slant = 0;
+ EFontStyle fontStyle = style->getFontStyle();
+ QString fontWeight = style->getFontWeight();
+
+ if(fontWeight.contains("bold"))
+ weight |= FC_WEIGHT_DEMIBOLD;
+ if(fontWeight.contains("bolder"))
+ weight |= FC_WEIGHT_BOLD;
+ if(fontWeight.contains("lighter"))
+ weight |= FC_WEIGHT_LIGHT;
+
+ bool ok = true;
+ int weightNumber = fontWeight.toInt(&ok);
+
+ if(ok)
+ weight = weightNumber;
+
+ if(fontStyle == FSNORMAL)
+ slant |= FC_SLANT_ROMAN;
+ else if(fontStyle == ITALIC)
+ slant |= FC_SLANT_ITALIC;
+ else if(fontStyle == OBLIQUE)
+ slant |= FC_SLANT_OBLIQUE;
+
+ // Calc font names
+ SVGStringListImpl *fontList = style->getFontFamily();
+
+ for(unsigned int i = 0; i <= fontList->numberOfItems(); i++)
+ {
+ DOM::DOMString *string = fontList->getItem(i);
+
+ if(string)
+ fontVisualParams->fontList().push_back(string->string().latin1());
+ }
+
+ fontVisualParams->setWeight(weight);
+ fontVisualParams->setSlant(slant);
+ fontVisualParams->setSize(style->getFontSize());
+
+ return fontVisualParams;
+}
+
+void KSVGCanvas::invalidate(CanvasItem *item, bool recalc)
+{
+ if(m_chunksByItem.find(item) != m_chunksByItem.end())
+ {
+ if(recalc)
+ {
+ removeFromChunks(item);
+ addToChunks(item);
+ }
+
+ QPtrListIterator<CanvasChunk> it = m_chunksByItem[item];
+ for(it.toFirst(); it.current(); ++it)
+ {
+ (*it)->setDirty();
+ if(!m_dirtyChunks.contains(*it))
+ m_dirtyChunks.append(*it);
+ }
+ }
+ else
+ addToChunks(item);
+}
+
+void KSVGCanvas::insert(CanvasItem *item, int z)
+{
+ if(z == -1)
+ {
+ item->setZIndex(m_chunksByItem.size());
+ m_chunksByItem[item] = QPtrList<CanvasChunk>();
+ addToChunks(item);
+ m_items.append(item);
+
+ bool visible = item->isVisible();
+ if(visible)
+ invalidate(item, false);
+
+ if(m_immediateUpdate)
+ {
+ if(visible)
+ {
+ item->draw();
+ QRect bbox = item->bbox();
+ blit(bbox, true);
+ }
+ }
+ }
+ else
+ {
+ // make some space
+ for(unsigned int i = z; i < m_items.count(); i++)
+ m_items.at(i)->setZIndex(m_items.at(i)->zIndex() + 1);
+
+ item->setZIndex(z);
+ }
+}
+
+void KSVGCanvas::removeItem(CanvasItem *item)
+{
+ removeFromChunks(item);
+ m_items.remove(item);
+}
+
+void KSVGCanvas::removeFromChunks(CanvasItem *item)
+{
+ QPtrListIterator<CanvasChunk> it = m_chunksByItem[item];
+ for(it.toFirst(); it.current(); ++it)
+ {
+ (*it)->remove(item);
+ if(!m_dirtyChunks.contains(*it))
+ m_dirtyChunks.append(*it);
+ }
+ m_chunksByItem.remove(item);
+}
+
+void KSVGCanvas::addToChunks(CanvasItem *item)
+{
+ QRect bbox = item->bbox();
+ QWMatrix mtx;
+ mtx.translate(m_pan.x(), m_pan.y());
+ mtx.scale(m_zoom, m_zoom);
+
+ bbox = mtx.invert().map(bbox);
+ for(int j = bbox.top() / m_chunkSizeVer; j <= (bbox.bottom() / m_chunkSizeVer); j++)
+ {
+ for(int i = bbox.left() / int(m_chunkSizeHor); i <= (bbox.right() / m_chunkSizeHor); i++)
+ {
+ CanvasChunk *chunk = m_chunkManager.getChunk(i, j);
+ if(!chunk)
+ {
+ chunk = new CanvasChunk(i, j);
+ m_chunkManager.addChunk(chunk);
+ }
+
+ chunk->add(item);
+ m_chunksByItem[item].append(chunk);
+ }
+ }
+}
+
+unsigned int KSVGCanvas::setElementItemZIndexRecursive(SVGElementImpl *element, unsigned int z)
+{
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(element);
+
+ if(shape)
+ {
+ CanvasItem *item = shape->item();
+
+ if(item)
+ {
+ SVGImageElementImpl *image = dynamic_cast<SVGImageElementImpl *>(shape);
+
+ if(image && image->svgImageRootElement())
+ {
+ // Set the z for all items in the svg image, since they live in the
+ // same canvas.
+ z = setElementItemZIndexRecursive(image->svgImageRootElement(), z);
+ }
+ else
+ {
+ item->setZIndex(z);
+ invalidate(item, false);
+ z++;
+ }
+ }
+ }
+
+ for(DOM::Node node = element->firstChild(); !node.isNull(); node = node.nextSibling())
+ {
+ SVGElementImpl *e = element->ownerDoc()->getElementFromHandle(node.handle());
+
+ if(e)
+ z = setElementItemZIndexRecursive(e, z);
+ }
+
+ return z;
+}
+
+void KSVGCanvas::update(const QPoint &panPoint, bool erase)
+{
+#ifdef USE_TIMER
+ QTime t;
+ t.start();
+#endif
+
+ int dx = panPoint.x() - m_pan.x();
+ int dy = panPoint.y() - m_pan.y();
+ m_pan = panPoint;
+
+ if(erase)
+ fill();
+
+ // reset clip paths
+ QDictIterator<CanvasClipPath> itr(m_clipPaths);
+ for(; itr.current(); ++itr)
+ (*itr)->update(UPDATE_TRANSFORM);
+
+ QWMatrix mtx;
+ mtx.translate(m_pan.x(), m_pan.y());
+ mtx.scale(m_zoom, m_zoom);
+
+ QRect r(0, 0, m_width, m_height);
+ QRect r2 = mtx.invert().map(r);
+
+ // pan all items
+ for(unsigned int i = 0; i < m_items.count(); i++)
+ m_items.at(i)->update(UPDATE_PAN, dx, dy);
+
+ // recalc items
+ CanvasItemList drawables;
+ QPtrListIterator<CanvasItem> it = m_items;
+ for(int j = r2.top() / m_chunkSizeVer; j <= (r2.bottom() / m_chunkSizeVer); j++)
+ {
+ for(int i = r2.left() / m_chunkSizeHor; i <= (r2.right() / m_chunkSizeHor); i++)
+ {
+ CanvasChunk *chunk = m_chunkManager.getChunk(i, j);
+ if(chunk)
+ {
+ for(CanvasItemList::ConstIterator it = chunk->list().begin(); it != chunk->list().end(); ++it)
+ {
+ if(!drawables.contains(*it))
+ drawables.append(*it);
+ }
+ }
+ }
+ }
+
+ drawables.sort();
+ for(CanvasItemList::Iterator it = drawables.begin(); it != drawables.end(); ++it)
+ (*it)->draw();
+
+ if(m_drawWindow)
+ blit(QRect(0, 0, m_width, m_height), false);
+
+ m_dirtyChunks.clear();
+
+#ifdef USE_TIMER
+ kdDebug(26000) << k_funcinfo << " Total time: " << t.elapsed() << endl;
+#endif
+}
+
+void KSVGCanvas::update(float zoomFactor)
+{
+#ifdef USE_TIMER
+ QTime t;
+ t.start();
+#endif
+
+ if(zoomFactor >= 1)
+ {
+ int newWidth = static_cast<int>(m_viewportWidth * zoomFactor);
+ int newHeight = static_cast<int>(m_viewportHeight * zoomFactor);
+ setRenderBufferSize(newWidth, newHeight);
+ }
+ else
+ fill();
+
+ // reset clip paths
+ QDictIterator<CanvasClipPath> itr(m_clipPaths);
+ for(; itr.current(); ++itr)
+ (*itr)->update(UPDATE_TRANSFORM);
+
+ m_zoom = zoomFactor;
+
+ QWMatrix mtx;
+ mtx.translate(m_pan.x(), m_pan.y());
+ mtx.scale(m_zoom, m_zoom);
+
+ QRect r(0, 0, m_width, m_height);
+ QRect r2 = mtx.invert().map(r);
+
+ // zoom all items
+ for(unsigned int i = 0; i < m_items.count(); i++)
+ m_items.at(i)->update(UPDATE_ZOOM);
+
+ // recalc items
+ CanvasItemList drawables;
+ QPtrListIterator<CanvasItem> it = m_items;
+ for(int j = r2.top() / m_chunkSizeVer; j <= (r2.bottom() / m_chunkSizeVer); j++)
+ {
+ for(int i = r2.left() / m_chunkSizeHor; i <= (r2.right() / m_chunkSizeHor); i++)
+ {
+ CanvasChunk *chunk = m_chunkManager.getChunk(i, j);
+ if(chunk)
+ {
+ for(CanvasItemList::ConstIterator it = chunk->list().begin(); it != chunk->list().end(); ++it)
+ {
+ if(!drawables.contains(*it))
+ drawables.append(*it);
+ }
+ }
+ }
+ }
+
+ drawables.sort();
+ for(CanvasItemList::Iterator it = drawables.begin(); it != drawables.end(); ++it)
+ (*it)->draw();
+
+ if(m_drawWindow)
+ blit(QRect(0, 0, m_width, m_height), false);
+
+ m_dirtyChunks.clear();
+
+#ifdef USE_TIMER
+ kdDebug(26000) << k_funcinfo << " Total time: " << t.elapsed() << endl;
+#endif
+}
+
+void KSVGCanvas::reset()
+{
+ m_items.clear();
+ m_chunkManager.clear();
+ m_chunksByItem.clear();
+ m_dirtyChunks.clear();
+ m_pan.setX(0);
+ m_pan.setY(0);
+ m_zoom = 1;
+}
+
+void KSVGCanvas::update()
+{
+#ifdef USE_TIMER
+ QTime t;
+ t.start();
+#endif
+
+ QWMatrix mtx;
+ mtx.translate(m_pan.x(), m_pan.y());
+ mtx.scale(m_zoom, m_zoom);
+
+ // Process dirty chunks
+ QPtrList<CanvasChunk> chunkList;
+ CanvasItemList drawables;
+ for(unsigned int i = 0; i < m_dirtyChunks.count(); i++)
+ {
+ CanvasChunk *chunk = m_dirtyChunks[i];
+ Q_ASSERT(chunk->isDirty());
+
+ QRect r = chunk->bbox();
+ QRect chunkbox(mtx.map(r.topLeft()), mtx.map(r.bottomRight()));
+ clear(chunkbox);
+ chunkList.append(chunk);
+
+ for(CanvasItemList::ConstIterator it = chunk->list().begin(); it != chunk->list().end(); ++it)
+ {
+// kdDebug(26005) << k_funcinfo << " Checking: " << *it << endl;
+ if(!drawables.contains(*it))
+ {
+// kdDebug(26005) << k_funcinfo << " Yes, appending to update list!" << endl;
+ drawables.append(*it);
+ }
+ }
+
+ chunk->unsetDirty();
+ }
+
+ drawables.sort();
+
+ // Draw dirty chunks
+ for(CanvasItemList::Iterator it = drawables.begin(); it != drawables.end(); ++it)
+ {
+// kdDebug(26005) << " Need to redraw dirty : " << (*it) << " with z : " << (*it)->zIndex() << endl;
+ (*it)->draw();
+ }
+
+ // Blit dirty chunks
+ QPtrListIterator<CanvasChunk> it = chunkList;
+ for(it.toFirst(); it.current(); ++it)
+ {
+ QRect r = (*it)->bbox();
+ QRect chunkbox(mtx.map(r.topLeft()), mtx.map(r.bottomRight()));
+ blit(chunkbox, false);
+ }
+
+ m_dirtyChunks.clear();
+
+#ifdef USE_TIMER
+ kdDebug(26005) << k_funcinfo << " Total time: " << t.elapsed() << endl;
+#endif
+}
+
+CanvasItemList KSVGCanvas::collisions(const QPoint &p, bool exact) const
+{
+ QWMatrix mtx;
+ mtx.translate(m_pan.x(), m_pan.y());
+ mtx.scale(m_zoom, m_zoom);
+
+ QPoint p2 = mtx.invert().map(p);
+ if(p2.x() < 0 || p2.y() < 0)
+ return CanvasItemList();
+
+ unsigned int x = p2.x() / int(m_chunkSizeHor);
+ unsigned int y = p2.y() / int(m_chunkSizeVer);
+
+ CanvasItemList result;
+ CanvasChunk *chunk = m_chunkManager.getChunk(x, y);
+ if(!chunk)
+ return result;
+
+ CanvasItemList list = chunk->list();
+ if(exact)
+ {
+ for(CanvasItemList::Iterator it = list.begin(); it != list.end(); ++it)
+ {
+ if((*it)->fillContains(p) || (*it)->strokeContains(p) || (*it)->bbox().contains(p))
+ result.append(*it);
+ }
+
+ return result;
+ }
+ else
+ return list;
+}
+
+void KSVGCanvas::blit(const QRect &rect, bool direct)
+{
+ if(m_drawWindow && m_width && m_height)
+ {
+ // clamp to viewport
+ int x0 = rect.x();
+ x0 = QMAX(x0, 0);
+ x0 = QMIN(x0, int(m_width - 1));
+
+ int y0 = rect.y();
+ y0 = QMAX(y0, 0);
+ y0 = QMIN(y0, int(m_height - 1));
+
+ int x1 = rect.x() + rect.width() + 1;
+ x1 = QMAX(x1, 0);
+ x1 = QMIN(x1, int(m_width));
+
+ int y1 = rect.y() + rect.height() + 1;
+ y1 = QMAX(y1, 0);
+ y1 = QMIN(y1, int(m_height));
+
+ xlib_draw_rgb_image(direct ? m_directWindow->handle() : m_drawWindow->handle(), m_gc, x0, y0, x1 - x0, y1 - y0, XLIB_RGB_DITHER_NONE, m_buffer + (m_width * y0 + x0) * m_nrChannels, m_width * m_nrChannels);
+ }
+}
+
+void KSVGCanvas::blit()
+{
+ return blit(QRect(0, 0, m_width, m_height), false);
+}
+
+void KSVGCanvas::ChunkManager::addChunk(CanvasChunk *chunk)
+{
+ QString key = QString("%1 %2").arg(chunk->x()).arg(chunk->y());
+// kdDebug(26005) << k_funcinfo << "Adding chunk : " << chunk << endl;
+ m_chunks.insert(key, chunk);
+}
+
+CanvasChunk *KSVGCanvas::ChunkManager::getChunk(short x, short y) const
+{
+// kdDebug(26005) << k_funcinfo << "getting chunk from : " << x << ", " << y << endl;
+ QString key = QString("%1 %2").arg(x).arg(y);
+ return m_chunks[key];
+}
+
+void KSVGCanvas::ChunkManager::clear()
+{
+ m_chunks.clear();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/core/KSVGCanvas.h b/ksvg/core/KSVGCanvas.h
new file mode 100644
index 00000000..7b26997c
--- /dev/null
+++ b/ksvg/core/KSVGCanvas.h
@@ -0,0 +1,190 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSVGCANVAS_H
+#define KSVGCANVAS_H
+
+#include <qmap.h>
+#include <qdict.h>
+#include <qcolor.h>
+#include <qobject.h>
+#include <qptrlist.h>
+#include <qdict.h>
+
+#include <Converter.h>
+
+namespace KSVG
+{
+
+class SVGShapeImpl;
+class SVGMatrixImpl;
+class SVGStylableImpl;
+class SVGElementImpl;
+class SVGTextElementImpl;
+class SVGRectElementImpl;
+class SVGLineElementImpl;
+class SVGPathElementImpl;
+class SVGImageElementImpl;
+class SVGCircleElementImpl;
+class SVGMarkerElementImpl;
+class SVGEllipseElementImpl;
+class SVGPolygonElementImpl;
+class SVGPolylineElementImpl;
+class SVGClipPathElementImpl;
+
+class CanvasItem;
+class CanvasChunk;
+class CanvasItemList;
+class CanvasClipPath;
+class CanvasPaintServer;
+
+// Must be a QObject to be able to be loaded by KLibLoader...
+class KSVGCanvas : public QObject
+{
+Q_OBJECT
+public:
+ KSVGCanvas(unsigned int width, unsigned int height);
+ virtual ~KSVGCanvas();
+
+ void setViewportDimension(unsigned int w, unsigned int h);
+
+ void setup(QPaintDevice *drawWidget, QPaintDevice *directWindow);
+ void setup(unsigned char *buffer, unsigned int width = 0, unsigned int height = 0);
+
+ void reset();
+ void update();
+ void update(float zoomFactor);
+ void update(const QPoint &panPoint, bool erase = true);
+ void resize(unsigned int w, unsigned int h);
+ void retune(unsigned int csh, unsigned int csv);
+ void invalidate(CanvasItem *item, bool recalc = true);
+ CanvasItemList collisions(const QPoint &p, bool exact = false) const;
+
+ void setBackgroundColor(const QColor &c) { m_backgroundColor = c; }
+ void blit();
+ void blit(const QRect &rect, bool direct);
+
+ float zoom() const { return m_zoom; }
+ QPoint pan() const { return m_pan; }
+ void setPan(const QPoint &pan) { m_pan = pan; }
+
+ int width() const { return m_width; }
+ int height() const { return m_height; }
+
+ virtual void setRenderBufferSize(int w, int h);
+ void clipToBuffer(int &x0, int &y0, int &x1, int &y1) const;
+
+ // creating canvas items
+ virtual CanvasItem *createRectangle(SVGRectElementImpl *rect) = 0;
+ virtual CanvasItem *createEllipse(SVGEllipseElementImpl *ellipse) = 0;
+ virtual CanvasItem *createCircle(SVGCircleElementImpl *circle) = 0;
+ virtual CanvasItem *createLine(SVGLineElementImpl *line) = 0;
+ virtual CanvasItem *createPolyline(SVGPolylineElementImpl *poly) = 0;
+ virtual CanvasItem *createPolygon(SVGPolygonElementImpl *poly) = 0;
+ virtual CanvasItem *createPath(SVGPathElementImpl *path) = 0;
+ virtual CanvasItem *createClipPath(SVGClipPathElementImpl *clippath) = 0;
+ virtual CanvasItem *createImage(SVGImageElementImpl *image) = 0;
+ virtual CanvasItem *createCanvasMarker(SVGMarkerElementImpl *marker) = 0;
+ virtual CanvasItem *createText(SVGTextElementImpl *text) = 0;
+ virtual CanvasPaintServer *createPaintServer(SVGElementImpl *pserver) = 0;
+
+ void insert(CanvasItem *item, int z = -1);
+ void removeItem(CanvasItem *);
+
+ // Enable to have the canvas updated and blitted on item insertion.
+ void setImmediateUpdate(bool immediateUpdate) { m_immediateUpdate = immediateUpdate; }
+ bool immediateUpdate() const { return m_immediateUpdate; }
+
+ QPtrList<CanvasItem> allItems() const { return m_items; }
+
+ unsigned char *renderingBuffer() const { return m_buffer; }
+ unsigned int nrChannels() const { return m_nrChannels; }
+ unsigned int rowStride() const { return m_nrChannels * m_width; }
+
+ T2P::Converter *fontContext() { return m_fontContext; }
+ QPaintDevice *drawWindow() { return m_drawWindow; }
+ QPaintDevice *directWindow() { return m_directWindow; }
+
+ T2P::FontVisualParams *fontVisualParams(SVGStylableImpl *style) const;
+ virtual T2P::BezierPath *toBezierPath(CanvasItem *item) const { Q_UNUSED(item); return 0; }
+
+ // Assign z indices to the element and its children, starting with z, and
+ // return the next z value to be used.
+ unsigned int setElementItemZIndexRecursive(SVGElementImpl *element, unsigned int z);
+
+protected:
+ void addToChunks(CanvasItem *item);
+ void removeFromChunks(CanvasItem *item);
+
+ void initVars();
+
+ void fill();
+ void clear(const QRect &r);
+
+ virtual void setBuffer(unsigned char *buffer);
+
+protected:
+ class ChunkManager
+ {
+ public:
+ ChunkManager() { m_chunks.setAutoDelete(true); }
+ void addChunk(CanvasChunk *chunk);
+ CanvasChunk *getChunk(short x, short y) const;
+
+ void clear();
+
+ private:
+ QDict<CanvasChunk> m_chunks;
+ } m_chunkManager;
+
+ QValueList<CanvasChunk *> m_dirtyChunks;
+
+ QMap<CanvasItem *, QPtrList<CanvasChunk> > m_chunksByItem;
+ QPtrList<CanvasItem> m_items;
+
+ QDict<CanvasClipPath> m_clipPaths;
+
+ unsigned int m_viewportWidth, m_viewportHeight;
+ int m_width, m_height;
+ int m_chunkSizeHor, m_chunkSizeVer;
+
+ QPaintDevice *m_drawWindow;
+ QPaintDevice *m_directWindow;
+
+ float m_zoom;
+ QPoint m_pan;
+
+ GC m_gc;
+
+ T2P::Converter *m_fontContext;
+
+ unsigned char *m_buffer;
+ unsigned int m_nrChannels;
+
+ QColor m_backgroundColor;
+
+ bool m_immediateUpdate;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/core/KSVGHelper.cpp b/ksvg/core/KSVGHelper.cpp
new file mode 100644
index 00000000..86d111a6
--- /dev/null
+++ b/ksvg/core/KSVGHelper.cpp
@@ -0,0 +1,92 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <math.h>
+
+#include "KSVGHelper.h"
+
+using namespace KSVG;
+
+bool KSVGHelper::m_initialised = false;
+
+int KSVGHelper::m_linearRGBFromsRGB[256];
+int KSVGHelper::m_sRGBFromLinearRGB[256];
+
+// Force initialisation of the lookup tables
+static KSVGHelper ksvgHelper;
+
+KSVGHelper::KSVGHelper()
+{
+ if(!m_initialised)
+ {
+ initialise();
+ m_initialised = true;
+ }
+}
+
+void KSVGHelper::initialise()
+{
+ // Set up linearRGB - sRGB conversion tables
+ for(int i = 0; i < 256; i++)
+ {
+ m_linearRGBFromsRGB[i] = calcLinearRGBFromsRGB(i);
+ m_sRGBFromLinearRGB[i] = calcSRGBFromLinearRGB(i);
+ }
+}
+
+int KSVGHelper::calcLinearRGBFromsRGB(int sRGB8bit)
+{
+ double sRGB = sRGB8bit / 255.0;
+ double linearRGB;
+
+ if(sRGB <= 0.04045)
+ linearRGB = sRGB / 12.92;
+ else
+ linearRGB = pow((sRGB + 0.055) / 1.055, 2.4);
+
+ return static_cast<int>(linearRGB * 255 + 0.5);
+}
+
+int KSVGHelper::calcSRGBFromLinearRGB(int linearRGB8bit)
+{
+ double linearRGB = linearRGB8bit / 255.0;
+ double sRGB;
+
+ if(linearRGB <= 0.0031308)
+ sRGB = linearRGB * 12.92;
+ else
+ sRGB = 1.055 * pow(linearRGB, 1 / 2.4) - 0.055;
+
+ return static_cast<int>(sRGB * 255 + 0.5);
+}
+
+extern "C"
+int linearRGBFromsRGB(int sRGB8bit)
+{
+ return KSVGHelper::linearRGBFromsRGB(sRGB8bit);
+}
+
+extern "C"
+int sRGBFromLinearRGB(int linearRGB8bit)
+{
+ return KSVGHelper::sRGBFromLinearRGB(linearRGB8bit);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/core/KSVGHelper.h b/ksvg/core/KSVGHelper.h
new file mode 100644
index 00000000..e310889f
--- /dev/null
+++ b/ksvg/core/KSVGHelper.h
@@ -0,0 +1,144 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSVGHelper_H
+#define KSVGHelper_H
+
+#ifdef __cplusplus
+
+#include <qcolor.h>
+#include <qvaluevector.h>
+#include "Affine.h"
+#include "Point.h"
+#include "SVGMatrixImpl.h"
+
+namespace KSVG
+{
+
+class KSVGHelper
+{
+public:
+ KSVGHelper();
+
+ static void matrixToAffine(SVGMatrixImpl *matrix, double affine[6])
+ {
+ affine[0] = matrix->a();
+ affine[1] = matrix->b();
+ affine[2] = matrix->c();
+ affine[3] = matrix->d();
+ affine[4] = matrix->e();
+ affine[5] = matrix->f();
+ }
+
+ static void matrixToAffine(const SVGMatrixImpl *matrix, double affine[6])
+ {
+ KSVGHelper::matrixToAffine(const_cast<SVGMatrixImpl *>(matrix), affine);
+ }
+
+ static void matrixToAffine(const SVGMatrixImpl *matrix, T2P::Affine &affine)
+ {
+ KSVGHelper::matrixToAffine(const_cast<SVGMatrixImpl *>(matrix), affine.data());
+ }
+
+ static void matrixToAffine(SVGMatrixImpl *matrix, T2P::Affine &affine)
+ {
+ KSVGHelper::matrixToAffine(matrix, affine.data());
+ }
+
+ static QString toColorString(QColor color)
+ {
+ int r = color.red();
+ int g = color.green();
+ int b = color.blue();
+
+ return "rgb(" + QString::number(r) + "," + QString::number(g) + "," + QString::number(b) + ")";
+ }
+
+ static unsigned int toArtColor(const QColor &color)
+ {
+ return (qRed(color.rgb()) << 24) | (qGreen(color.rgb()) << 16) | ( qBlue(color.rgb()) << 8) | (qAlpha(color.rgb()));
+ }
+
+ static unsigned int toArtColor(const QColor &color, short opacity)
+ {
+ return (qRed(color.rgb()) << 24) | (qGreen(color.rgb()) << 16) | ( qBlue(color.rgb()) << 8) | (opacity);
+ }
+
+ static int linearRGBFromsRGB(int sRGB8bit) { return m_linearRGBFromsRGB[sRGB8bit]; }
+ static int sRGBFromLinearRGB(int linearRGB8bit) { return m_sRGBFromLinearRGB[linearRGB8bit]; }
+
+private:
+ static void initialise();
+ static int calcLinearRGBFromsRGB(int sRGB8bit);
+ static int calcSRGBFromLinearRGB(int linearRGB8bit);
+
+ static bool m_initialised;
+
+ static int m_linearRGBFromsRGB[256];
+ static int m_sRGBFromLinearRGB[256];
+};
+
+typedef T2P::Point KSVGPoint;
+
+class KSVGPolygon
+{
+public:
+ KSVGPolygon() {}
+
+ void addPoint(const KSVGPoint& point) { m_points.append(point); }
+ void addPoint(double x, double y) { m_points.append(KSVGPoint(x, y)); }
+
+ KSVGPoint point(unsigned int index) const { return index < m_points.count() ? m_points[index] : KSVGPoint(); }
+
+ unsigned int numPoints() const { return m_points.count(); }
+ bool isEmpty() const { return m_points.isEmpty(); }
+
+ void clear() { m_points.clear(); }
+
+private:
+ QValueVector<KSVGPoint> m_points;
+};
+
+class KSVGRectangle : public KSVGPolygon
+{
+public:
+ KSVGRectangle() { addPoint(0, 0); addPoint(0, 0); addPoint(0, 0); addPoint(0, 0); }
+
+ // Convenience constructor for an axis-aligned rectangle
+ KSVGRectangle(double x, double y, double width, double height)
+ { addPoint(KSVGPoint(x, y)); addPoint(KSVGPoint(x, y + height)); addPoint(KSVGPoint(x + width, y + height)); addPoint(KSVGPoint(x + width, y)); }
+
+};
+}
+
+extern "C"
+{
+#endif // __cplusplus
+
+int linearRGBFromsRGB(int sRGB8bit);
+int sRGBFromLinearRGB(int linearRGB8bit);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/core/KSVGLoader.cpp b/ksvg/core/KSVGLoader.cpp
new file mode 100644
index 00000000..7f7591d7
--- /dev/null
+++ b/ksvg/core/KSVGLoader.cpp
@@ -0,0 +1,449 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qxml.h>
+#include <qfile.h>
+#include <qimage.h>
+#include <qbuffer.h>
+
+#include <kurl.h>
+#include <kdebug.h>
+#include <kio/job.h>
+#include <kfilterdev.h>
+#include <kio/netaccess.h>
+
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGImageElementImpl.h"
+
+#include "KSVGLoader.moc"
+
+using namespace KSVG;
+
+KSVGLoader::KSVGLoader() : m_data(0)
+{
+ m_job = 0;
+}
+
+KSVGLoader::~KSVGLoader()
+{
+}
+
+QString KSVGLoader::loadXML(::KURL url)
+{
+ QString tmpFile;
+ if(KIO::NetAccess::download(url, tmpFile, 0))
+ {
+ QIODevice *dev = KFilterDev::deviceForFile(tmpFile, "application/x-gzip", true);
+ QByteArray contents;
+ if(dev->open(IO_ReadOnly))
+ contents = dev->readAll();
+ delete dev;
+ KIO::NetAccess::removeTempFile(tmpFile);
+ return QString(contents);
+ }
+
+ return QString::null;
+}
+
+void KSVGLoader::getSVGContent(::KURL url)
+{
+ if(!url.prettyURL().isEmpty())
+ {
+ if(m_job == 0)
+ m_job = KIO::get(url, false, false);
+
+ m_job->setAutoErrorHandlingEnabled(true);
+
+ connect(m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), this, SLOT(slotData(KIO::Job *, const QByteArray &)));
+ connect(m_job, SIGNAL(result(KIO::Job *)), this, SLOT(slotResult(KIO::Job *)));
+ }
+}
+
+void KSVGLoader::newImageJob(SVGImageElementImpl *image, ::KURL baseURL)
+{
+ if(image && image->fileName().isEmpty())
+ {
+ kdDebug(26001) << "Image Element has no URL!" << endl;
+ return;
+ }
+
+ ImageStreamMap *map = new ImageStreamMap();
+ map->data = new QByteArray();
+ map->imageElement = image;
+
+ KIO::TransferJob *imageJob = KIO::get(::KURL(baseURL, map->imageElement->fileName()), false, false);
+ connect(imageJob, SIGNAL(data(KIO::Job *, const QByteArray &)), this, SLOT(slotData(KIO::Job *, const QByteArray &)));
+ connect(imageJob, SIGNAL(result(KIO::Job *)), this, SLOT(slotResult(KIO::Job *)));
+
+ m_imageJobs.insert(imageJob, map);
+}
+
+void KSVGLoader::slotData(KIO::Job *job, const QByteArray &data)
+{
+ if(job == m_job)
+ {
+ QDataStream dataStream(m_data, IO_WriteOnly | IO_Append);
+ dataStream.writeRawBytes(data.data(), data.size());
+ }
+ else
+ {
+ QMap<KIO::TransferJob *, ImageStreamMap *>::Iterator it;
+ for(it = m_imageJobs.begin(); it != m_imageJobs.end(); ++it)
+ {
+ if(it.key() == job)
+ {
+ QDataStream dataStream(*(it.data())->data, IO_WriteOnly | IO_Append);
+ dataStream.writeRawBytes(data.data(), data.size());
+ break;
+ }
+ }
+ }
+}
+
+void KSVGLoader::slotResult(KIO::Job *job)
+{
+ if(job == m_job)
+ {
+ if(m_job->error() == 0)
+ {
+ QString check = static_cast<KIO::TransferJob *>(job)->url().prettyURL();
+ if(check.contains(".svgz") || check.contains(".svg.gz"))
+ {
+ // decode the gzipped svg and emit it
+ QIODevice *dev = KFilterDev::device(new QBuffer(m_data), "application/x-gzip");
+ dev->open(IO_ReadOnly);
+ emit gotResult(dev);
+ }
+ else
+ {
+ m_job = 0;
+ emit gotResult(new QBuffer(m_data));
+ m_data.resize(0);
+ }
+ }
+ }
+ else if(m_postUrlData.job == job)
+ {
+ // Notify that we're done
+ KJS::List callBackArgs;
+ callBackArgs.append(*m_postUrlData.status);
+
+ m_postUrlData.status->put(m_postUrlData.exec, KJS::Identifier("success"), KJS::Boolean(true));
+ m_postUrlData.callBackFunction->call(m_postUrlData.exec, *m_postUrlData.callBackFunction, callBackArgs);
+ }
+ else
+ {
+ QMap<KIO::TransferJob *, ImageStreamMap *>::Iterator it;
+ for(it = m_imageJobs.begin(); it != m_imageJobs.end(); ++it)
+ {
+ if(it.key() == job)
+ {
+ ImageStreamMap *streamMap = it.data();
+
+ QBuffer buffer(*(streamMap->data));
+
+ if(buffer.open(IO_ReadOnly))
+ {
+ const char *imageFormat = QImageIO::imageFormat(&buffer);
+
+ if(imageFormat != 0)
+ {
+ QImageIO imageIO(&buffer, imageFormat);
+
+ // Gamma correction
+ imageIO.setGamma(1/0.45454);
+
+ if(imageIO.read())
+ {
+ QImage *image = new QImage(imageIO.image());
+ image->detach();
+ (streamMap->imageElement)->setImage(image);
+ }
+ }
+
+ buffer.close();
+ }
+
+ (streamMap->data)->resize(0);
+
+ m_imageJobs.remove(static_cast<KIO::TransferJob *>(job));
+
+ emit imageReady(streamMap->imageElement);
+ break;
+ }
+ }
+ }
+}
+
+QString KSVGLoader::getUrl(::KURL url, bool local)
+{
+ // Security issue: Only retrieve http and https
+ if(local || (!url.prettyURL().isEmpty()) && ((url.protocol() == "http") || (url.protocol() == "https")))
+ return loadXML(url);
+
+ return QString::null;
+}
+
+void KSVGLoader::postUrl(::KURL url, const QByteArray &data, const QString &mimeType, KJS::ExecState *exec, KJS::Object &callBackFunction, KJS::Object &status)
+{
+ KIO::TransferJob *job = KIO::http_post(url, data, false);
+ job->addMetaData("content-type", mimeType);
+
+ m_postUrlData.job = job;
+ m_postUrlData.exec = exec;
+ m_postUrlData.status = &status;
+ m_postUrlData.callBackFunction = &callBackFunction;
+
+ connect(job, SIGNAL(result(KIO::Job *)), SLOT(slotResult(KIO::Job *)));
+}
+
+class CharacterDataSearcher : public QXmlDefaultHandler
+{
+public:
+ CharacterDataSearcher(const QString &id) : m_id(id) { }
+
+ virtual bool startDocument()
+ {
+ m_foundCount = 0;
+ return true;
+ }
+
+ virtual bool startElement(const QString &, const QString &, const QString &qName, const QXmlAttributes &atts)
+ {
+ kdDebug(26001) << "CharacterDataSearcher::startElement, qName " << qName << endl;
+
+ int pos = atts.index("id");
+ if(pos > -1 && atts.value(pos) == m_id)
+ {
+ m_foundCount++;
+ m_tagFound = qName;
+ }
+
+ return true;
+ }
+
+ virtual bool endElement(const QString &, const QString &, const QString &qName)
+ {
+ if(m_tagFound == qName && m_foundCount > 0)
+ {
+ m_foundCount--;
+ if(m_foundCount == 0)
+ return false; // done!
+ }
+
+ return true;
+ }
+
+ virtual bool characters(const QString &ch)
+ {
+ kdDebug(26001) << "CharacterDataSearcher::characters, read " << ch.latin1() << endl;
+
+ if(m_tagFound != 0)
+ m_result += ch;
+
+ return true;
+ }
+
+ QString result() { return m_result; }
+
+private:
+ QString m_id, m_result, m_tagFound;
+ int m_foundCount;
+};
+
+QString KSVGLoader::getCharacterData(::KURL url, const QString &id)
+{
+ QXmlSimpleReader reader;
+
+ CharacterDataSearcher searcher(id);
+ reader.setContentHandler(&searcher);
+ reader.setErrorHandler(&searcher);
+
+ QString s = loadXML(url);
+
+ QXmlInputSource source;
+ source.setData(s);
+
+ reader.parse(&source);
+
+ return searcher.result();
+}
+
+
+
+class SVGFragmentSearcher : public QXmlDefaultHandler
+{
+public:
+ SVGFragmentSearcher(SVGDocumentImpl *doc, const QString &id, ::KURL url) : m_id(id), m_url(url), m_doc(doc) { }
+
+ virtual bool startDocument()
+ {
+ m_result = 0;
+ m_currentNode = 0;
+
+ return true;
+ }
+
+ virtual bool startElement(const QString &namespaceURI, const QString &, const QString &qName, const QXmlAttributes &attrs)
+ {
+ kdDebug(26001) << "SVGFragmentSearcher::startElement, namespaceURI " << namespaceURI << ", qName " << qName << endl;
+ bool parse = m_result;
+ if(!parse)
+ {
+ int pos = attrs.index("id");
+ if(pos > -1 && attrs.value(pos) == m_id)
+ parse = true;
+ }
+
+ if(parse)
+ {
+ DOM::Element impl = static_cast<DOM::Document *>(m_doc)->createElementNS(namespaceURI, qName);
+ SVGElementImpl *newElement = SVGDocumentImpl::createElement(qName, impl, m_doc);
+ newElement->setViewportElement(m_doc->rootElement());
+
+ if(m_currentNode)
+ m_currentNode->appendChild(*newElement);
+ else
+ m_result = newElement;
+
+ QXmlAttributes newAttrs;
+
+ for(int i = 0; i < attrs.count(); i++)
+ {
+ QString name = attrs.localName(i);
+ QString value = attrs.value(i);
+
+ if(name == "id")
+ {
+ value = "@fragment@" + m_url.prettyURL() + "@" + value;
+ m_idMap[value] = newElement;
+ }
+ else
+ if(name == "href")
+ {
+ value.stripWhiteSpace();
+
+ if(value.startsWith("#"))
+ {
+ value.remove(0, 1);
+
+ // Convert the id to its mangled version.
+ QString id = "@fragment@" + m_url.prettyURL() + "@" + value;
+
+ if(m_idMap.contains(id))
+ {
+ // This is a local reference to an element within the fragment.
+ // Just convert the href.
+ value = id;
+ }
+ else
+ {
+ // This is a local reference to an id outside of the fragment.
+ // Change it into an absolute href.
+ value = m_url.prettyURL() + "#" + value;
+ }
+ }
+ }
+
+ newAttrs.append(attrs.qName(i), attrs.uri(i), attrs.localName(i), value);
+ }
+
+ newElement->setAttributes(newAttrs);
+ m_currentNode = newElement;
+ }
+
+ return true;
+ }
+
+ virtual bool endElement(const QString &, const QString &, const QString &)
+ {
+ if(m_result)
+ {
+ m_parentNode = m_currentNode->parentNode();
+
+ if(m_parentNode.isNull())
+ return false; // done!
+
+ m_currentNode = &m_parentNode;
+ }
+
+ return true;
+ }
+
+ virtual bool characters(const QString &ch)
+ {
+ kdDebug(26001) << "SVGFragmentSearcher::characters, read " << ch.latin1() << endl;
+
+ if(m_result)
+ {
+ SVGElementImpl *element = m_result->ownerDoc()->getElementFromHandle(m_currentNode->handle());
+ if(element)
+ {
+ QString t = ch;
+
+ SVGLangSpaceImpl *langSpace = dynamic_cast<SVGLangSpaceImpl *>(element);
+ if(langSpace)
+ t = langSpace->handleText(ch);
+
+ if(!t.isEmpty())
+ {
+ DOM::Text impl = static_cast<DOM::Document *>(m_result->ownerDoc())->createTextNode(t);
+ element->appendChild(impl);
+ }
+ }
+ }
+
+ return true;
+ }
+
+ SVGElementImpl *result() { return m_result; }
+
+private:
+ QString m_id;
+ ::KURL m_url;
+
+ SVGDocumentImpl *m_doc;
+ SVGElementImpl *m_result;
+
+ DOM::Node *m_currentNode, m_parentNode;
+ QMap<QString, SVGElementImpl *> m_idMap;
+};
+
+SVGElementImpl *KSVGLoader::getSVGFragment(::KURL url, SVGDocumentImpl *doc, const QString &id)
+{
+ QXmlSimpleReader reader;
+
+ kdDebug(26001) << "getSVGFragment: " << url.prettyURL() << "#" << id << endl;
+ SVGFragmentSearcher searcher(doc, id, url);
+ reader.setContentHandler(&searcher);
+ reader.setErrorHandler(&searcher);
+
+ QString s = loadXML(url);
+
+ QXmlInputSource source;
+ source.setData(s);
+
+ reader.parse(&source);
+
+ return searcher.result();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/core/KSVGLoader.h b/ksvg/core/KSVGLoader.h
new file mode 100644
index 00000000..d0418411
--- /dev/null
+++ b/ksvg/core/KSVGLoader.h
@@ -0,0 +1,92 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSVGLoader_H
+#define KSVGLoader_H
+
+#include <qobject.h>
+
+class KURL;
+
+namespace KIO
+{
+ class Job;
+ class TransferJob;
+}
+
+namespace KJS
+{
+ class Object;
+ class ExecState;
+}
+
+namespace KSVG
+{
+
+struct ImageStreamMap;
+
+typedef struct
+{
+ KIO::Job *job;
+ KJS::ExecState *exec;
+ KJS::Object *callBackFunction, *status;
+} PostUrlData;
+
+class SVGImageElementImpl;
+class SVGElementImpl;
+class SVGDocumentImpl;
+class KSVGLoader : public QObject
+{
+Q_OBJECT
+public:
+ KSVGLoader();
+ ~KSVGLoader();
+
+ void getSVGContent(::KURL url);
+ void newImageJob(SVGImageElementImpl *impl, ::KURL url);
+
+ static QString getUrl(::KURL url, bool local = false);
+ void postUrl(::KURL url, const QByteArray &data, const QString &mimeType, KJS::ExecState *exec, KJS::Object &callBackFunction, KJS::Object &status);
+ static QString getCharacterData(::KURL url, const QString &id);
+ static SVGElementImpl *getSVGFragment(::KURL, SVGDocumentImpl *doc, const QString &id);
+
+signals:
+ void gotResult(QIODevice *);
+ void imageReady(SVGImageElementImpl *);
+
+private slots:
+ void slotData(KIO::Job *, const QByteArray &);
+ void slotResult(KIO::Job *);
+
+private:
+ static QString loadXML(::KURL);
+
+ PostUrlData m_postUrlData;
+
+ QByteArray m_data;
+ KIO::TransferJob *m_job;
+ QMap<KIO::TransferJob *, ImageStreamMap *> m_imageJobs;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/core/KSVGReader.cc b/ksvg/core/KSVGReader.cc
new file mode 100644
index 00000000..dd73e420
--- /dev/null
+++ b/ksvg/core/KSVGReader.cc
@@ -0,0 +1,500 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <dom/dom_exception.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <qmap.h>
+#include <ksimpleconfig.h>
+#include <KSVGCanvas.h>
+#include "KSVGReader.moc"
+#include "SVGSVGElementImpl.h"
+#include "SVGViewSpecImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGMatrixImpl.h"
+#include "SVGShapeImpl.h"
+#include "SVGLengthImpl.h"
+#include "SVGImageElementImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGUseElementImpl.h"
+
+namespace KSVG
+{
+
+class Helper
+{
+public:
+ static Helper *self(KSVGReader *reader = 0);
+
+ void destroy();
+
+ void setFit(bool bFit = true) { m_bFit = bFit; }
+ bool fit() { return m_bFit; }
+
+ SVGDocumentImpl *doc() const { return m_reader->doc(); }
+ KSVGCanvas *canvas() const { return m_reader->canvas(); }
+
+ void addSVGElement(SVGSVGElementImpl *one, DOM::NodeImpl *two) { m_svgMap.insert(two, one); }
+ SVGSVGElementImpl *nextSVGElement(SVGElementImpl *elem);
+ SVGSVGElementImpl *nextSVGElement(DOM::Node elem);
+ void setFinished(bool error, const QString &errorDesc = "") { m_reader->setFinished(error, errorDesc); }
+
+ // Error handling
+ void setErrorDescription(const QString &err) { m_errorDesc = err; }
+ QString errorDescription() { return m_errorDesc; }
+ bool hasError() const { return !m_errorDesc.isEmpty(); }
+
+ bool getURLMode() const { return m_getURLMode; }
+ void setGetURLMode(bool mode) { m_getURLMode = mode; }
+
+ QString SVGFragmentId() const { return m_SVGFragmentId; }
+ void setSVGFragmentId(const QString &SVGFragmentId) { m_SVGFragmentId = SVGFragmentId; }
+
+protected:
+ Helper(KSVGReader *reader);
+
+private:
+ Helper();
+ Helper(const Helper &rhs);
+ Helper &operator=(const Helper &rhs);
+
+ static Helper *m_instance;
+ QMap<DOM::NodeImpl *, SVGSVGElementImpl *> m_svgMap;
+ KSVGReader *m_reader;
+ bool m_bFit;
+ bool m_getURLMode;
+ QString m_errorDesc;
+ QString m_SVGFragmentId;
+};
+
+class InputHandler : public QXmlDefaultHandler
+{
+public:
+ virtual bool startDocument();
+ virtual bool endDocument();
+ virtual bool startElement(const QString &namespaceURI,
+ const QString &localName,
+ const QString &qName,
+ const QXmlAttributes &atts);
+ virtual bool endElement(const QString &namespaceURI,
+ const QString &localName,
+ const QString &qName);
+ virtual bool characters(const QString &ch);
+ virtual bool warning(const QXmlParseException &e);
+ virtual bool error(const QXmlParseException &e);
+ virtual bool fatalError(const QXmlParseException &e);
+
+private:
+ DOM::Node *m_rootNode;
+ DOM::Node *m_currentNode;
+ DOM::Node m_parentNode;
+
+ bool m_noRendering, m_progressive;
+};
+
+}
+
+using namespace KSVG;
+
+Helper *Helper::m_instance = 0;
+
+Helper::Helper(KSVGReader *reader)
+{
+ m_reader = reader;
+}
+
+Helper *Helper::self(KSVGReader *reader)
+{
+ if(m_instance && reader != 0)
+ m_instance->m_reader = reader;
+ if(!m_instance)
+ {
+ Q_ASSERT(reader != 0);
+ m_instance = new Helper(reader);
+ }
+
+ return m_instance;
+}
+
+void Helper::destroy()
+{
+ m_svgMap.clear();
+}
+
+SVGSVGElementImpl *Helper::nextSVGElement(SVGElementImpl *elem)
+{
+ return nextSVGElement(*elem);
+}
+
+SVGSVGElementImpl *Helper::nextSVGElement(DOM::Node elem)
+{
+ DOM::Node foundSVG;
+ DOM::Node shape = elem.parentNode();
+
+ for(; !shape.isNull(); shape = shape.parentNode())
+ {
+ if(reinterpret_cast<DOM::Element &>(shape).nodeName() == "svg")
+ {
+ foundSVG = shape;
+ break;
+ }
+ }
+
+ SVGSVGElementImpl *svg = m_svgMap[foundSVG.handle()];
+ return svg;
+}
+
+bool InputHandler::startDocument()
+{
+ m_rootNode = 0;
+ m_currentNode = 0;
+ m_noRendering = false;
+
+ KSimpleConfig config("ksvgpluginrc");
+ config.setGroup("Rendering");
+ m_progressive = config.readBoolEntry("ProgressiveRendering", true);
+
+ if(Helper::self()->canvas())
+ Helper::self()->canvas()->setImmediateUpdate(m_progressive);
+
+ return true;
+}
+
+bool InputHandler::endDocument()
+{
+ Helper::self()->setFinished(false);
+ if (Helper::self()->canvas())
+ Helper::self()->canvas()->setImmediateUpdate(false);
+
+ return true;
+}
+
+bool InputHandler::characters(const QString &ch)
+{
+ kdDebug(26001) << "InputHandler::characters, read " << ch << endl;
+
+ if(ch.simplifyWhiteSpace().isEmpty())
+ return true;
+
+ QString t = ch;
+
+ SVGSVGElementImpl *root = Helper::self()->nextSVGElement(*m_currentNode);
+ if(root)
+ {
+ SVGElementImpl *element = root->ownerDoc()->getElementFromHandle(m_currentNode->handle());
+ SVGLangSpaceImpl *langSpace = dynamic_cast<SVGLangSpaceImpl *>(element);
+
+ if(langSpace)
+ t = langSpace->handleText(ch);
+ }
+
+ if(!t.isEmpty())
+ {
+ DOM::Text impl = static_cast<DOM::Document *>(Helper::self()->doc())->createTextNode(t);
+ m_currentNode->appendChild(impl);
+ }
+
+ return true;
+}
+
+bool InputHandler::startElement(const QString &namespaceURI, const QString &, const QString &qName, const QXmlAttributes &attrs)
+{
+ kdDebug(26001) << "InputHandler::startElement, namespaceURI " << namespaceURI << " qName " << qName << endl;
+
+ SVGElementImpl *newElement = 0;
+ SVGSVGElementImpl *svg = 0;
+
+ if(qName == "svg")
+ {
+ DOM::Element impl = static_cast<DOM::Document *>(Helper::self()->doc())->createElementNS(namespaceURI, qName);
+ newElement = SVGDocumentImpl::createElement(qName, impl, Helper::self()->doc());
+ svg = dynamic_cast<SVGSVGElementImpl *>(newElement);
+
+ Helper::self()->addSVGElement(svg, impl.handle());
+
+ // Need this before we can find our ownerSVGElement (AP)
+ if(m_currentNode != 0)
+ m_currentNode->appendChild(*svg);
+ else
+ // TODO: Those set/get attribute callls have NO effect anymore
+ // Convert to the new system, Rob? (Niko)
+ {
+ if(Helper::self()->fit())
+ { // handle fitting of svg into small drawing area(thumb)
+ // TODO : aspectratio? and what about svgs that dont provide width and height?
+ if(svg->getAttribute("viewBox").string().isEmpty())
+ {
+ SVGLengthImpl *width = SVGSVGElementImpl::createSVGLength();
+ SVGLengthImpl *height = SVGSVGElementImpl::createSVGLength();
+ width->setValueAsString(svg->getAttribute("width").string());
+ height->setValueAsString(svg->getAttribute("height").string());
+ QString viewbox = QString("0 0 %1 %2").arg(width->value()).arg(height->value());
+ //kdDebug(26001) << "VIEWBOX : " << viewbox.latin1() << endl;
+ svg->setAttribute("viewBox", viewbox);
+ width->deref();
+ height->deref();
+ }
+ svg->setAttribute("width", QString::number(Helper::self()->canvas()->width()));
+ svg->setAttribute("height", QString::number(Helper::self()->canvas()->height()));
+ }
+
+ if(!Helper::self()->SVGFragmentId().isEmpty())
+ {
+ if(svg->currentView()->parseViewSpec(Helper::self()->SVGFragmentId()))
+ svg->setUseCurrentView(true);
+ }
+ }
+
+ if(m_rootNode == 0)
+ {
+ Helper::self()->doc()->appendChild(*svg);
+ Helper::self()->doc()->setRootElement(svg);
+
+ m_rootNode = svg;
+ }
+ }
+ else
+ {
+ if(!m_rootNode && !Helper::self()->getURLMode())
+ {
+ Helper::self()->setErrorDescription(i18n("A legal svg document requires a <svg> root element"));
+ return false;
+ }
+
+ DOM::Element impl = static_cast<DOM::Document *>(Helper::self()->doc())->createElementNS(namespaceURI, qName);
+ newElement = SVGDocumentImpl::createElement(qName, impl, Helper::self()->doc());
+
+ // m_currentNode == 0 if we are dynamically extending the dom (parsexml...)
+ // and the file doesn't have a root element
+ if(m_currentNode != 0)
+ m_currentNode->appendChild(*newElement);
+ else
+ Helper::self()->doc()->appendChild(*newElement);
+
+ // Special logics:
+ if(qName == "switch" || qName == "pattern" || qName == "mask")
+ m_noRendering = true;
+ }
+
+ newElement->setOwnerSVGElement(Helper::self()->nextSVGElement(newElement));
+ newElement->setViewportElement(newElement->ownerSVGElement());
+
+ newElement->setAttributes(attrs);
+
+ if(svg && svg->ownerSVGElement() == 0)
+ {
+ SVGImageElementImpl *parentImage = Helper::self()->doc()->parentImage();
+
+ if(parentImage)
+ {
+ // We're being displayed in a document via an 'image' element. Set
+ // us up to fit into it's rectangle.
+ parentImage->setupSVGElement(svg);
+ }
+ }
+
+ SVGLocatableImpl *locatable = dynamic_cast<SVGLocatableImpl *>(newElement);
+
+ if(locatable)
+ {
+ // Set up the cached screenCTM
+ SVGLocatableImpl *locatableParent = 0;
+ DOM::Node parentNode = newElement->parentNode();
+
+ if(!parentNode.isNull())
+ {
+ SVGElementImpl *parent = Helper::self()->doc()->getElementFromHandle(parentNode.handle());
+
+ if(parent)
+ locatableParent = dynamic_cast<SVGLocatableImpl *>(parent);
+ }
+
+ SVGMatrixImpl *parentMatrix = 0;
+
+ if(locatableParent)
+ parentMatrix = locatableParent->getScreenCTM();
+ else
+ parentMatrix = SVGSVGElementImpl::createSVGMatrix();
+
+ locatable->updateCachedScreenCTM(parentMatrix);
+ parentMatrix->deref();
+ }
+
+ m_currentNode = newElement;
+ return !Helper::self()->hasError();
+}
+
+bool InputHandler::endElement(const QString &, const QString &, const QString &qName)
+{
+ kdDebug(26001) << "InputHandler::endElement, qName " << qName << endl;
+
+ bool haveCanvas = Helper::self()->canvas();
+
+ SVGSVGElementImpl *root = Helper::self()->nextSVGElement(*m_currentNode);
+ SVGElementImpl *element = root ? root->ownerDoc()->getElementFromHandle(m_currentNode->handle()) : Helper::self()->doc()->getElementFromHandle(m_currentNode->handle());
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(element);
+ SVGTestsImpl *tests = dynamic_cast<SVGTestsImpl *>(element);
+ SVGStylableImpl *style = dynamic_cast<SVGStylableImpl *>(element);
+
+ if(qName != "script" && !m_noRendering && !Helper::self()->getURLMode())
+ {
+ if(!root)
+ {
+ if(haveCanvas)
+ {
+ if(!m_progressive)
+ Helper::self()->canvas()->update();
+
+ Helper::self()->canvas()->blit();
+
+ QValueList<SVGUseElementImpl *> forwardReferencingUseElements = Helper::self()->doc()->forwardReferencingUseElements();
+
+ if(!forwardReferencingUseElements.isEmpty())
+ {
+ // Create the elements again now that we have parsed the whole document.
+ QValueList<SVGUseElementImpl *>::iterator it;
+
+ Helper::self()->canvas()->setImmediateUpdate(false);
+
+ for(it = forwardReferencingUseElements.begin(); it != forwardReferencingUseElements.end(); it++)
+ (*it)->createItem(Helper::self()->canvas());
+
+ // The newly created items will need to be moved into their correct z-order positions.
+ Helper::self()->doc()->resortZIndicesOnFinishedLoading();
+ }
+ }
+
+ return true; // we have reached the bottom
+ }
+
+ if(haveCanvas && (tests ? tests->ok() : true))
+ {
+ if((shape && !shape->isContainer()) || (!shape && element))
+ element->createItem();
+ }
+ }
+
+ // Special logics:
+ if(qName == "switch" || qName == "pattern" || qName == "mask")
+ {
+ m_noRendering = false;
+ bool ok = tests ? tests->ok() : true;
+
+ if(haveCanvas && element && style && ok && style->getDisplay() && style->getVisible() && qName == "pattern" || (shape && shape->directRender()))
+ element->createItem();
+ }
+
+ m_parentNode = m_currentNode->parentNode(); // this is needed since otherwise we get temporary vars
+ m_currentNode = &m_parentNode;
+
+ return true;
+}
+
+bool InputHandler::warning(const QXmlParseException &e)
+{
+ kdDebug(26001) << "[" << e.lineNumber() << ":" << e.columnNumber() << "]: WARNING: " << e.message() << endl;
+ return true;
+}
+
+bool InputHandler::error(const QXmlParseException &e)
+{
+ kdDebug(26001) << "[" << e.lineNumber() << ":" << e.columnNumber() << "]: ERROR: " << e.message() << endl;
+ return true;
+}
+
+bool InputHandler::fatalError(const QXmlParseException &e)
+{
+ QString error;
+
+ if(Helper::self()->hasError())
+ {
+ error = Helper::self()->errorDescription();
+ Helper::self()->setErrorDescription(QString::null);
+ }
+ else
+ error = QString("[%1:%2]: FATAL ERROR: %3").arg(e.lineNumber()).arg(e.columnNumber()).arg(e.message());
+
+ kdDebug(26001) << "InputHandler::fatalError, " << error << endl;
+
+ Helper::self()->setFinished(true, error);
+ return true;
+}
+
+struct KSVGReader::Private
+{
+ QXmlSimpleReader *reader;
+ InputHandler *inputHandler;
+ SVGDocumentImpl *doc;
+ KSVGCanvas *canvas;
+};
+
+KSVGReader::KSVGReader(SVGDocumentImpl *doc, KSVGCanvas *canvas, ParsingArgs args) : QObject(), d(new Private)
+{
+ d->doc = doc;
+ d->canvas = canvas;
+
+ d->reader = new QXmlSimpleReader();
+ d->inputHandler = new InputHandler();
+
+ Helper::self(this);
+ Helper::self()->setFit(args.fit);
+ Helper::self()->setGetURLMode(args.getURLMode);
+ Helper::self()->setSVGFragmentId(args.SVGFragmentId);
+
+ d->reader->setContentHandler(d->inputHandler);
+ d->reader->setErrorHandler(d->inputHandler);
+}
+
+KSVGReader::~KSVGReader()
+{
+ Helper::self()->destroy();
+
+ delete d->reader;
+ delete d->inputHandler;
+ delete d;
+}
+
+void KSVGReader::parse(QXmlInputSource *source)
+{
+ d->reader->parse(source);
+}
+
+void KSVGReader::finishParsing(bool, const QString &errorDesc)
+{
+ Helper::self()->setErrorDescription(errorDesc);
+}
+
+void KSVGReader::setFinished(bool error, const QString &errorDesc)
+{
+ kdDebug(26001) << "KSVGReader::setFinished" << endl;
+ emit finished(error, errorDesc);
+}
+
+SVGDocumentImpl *KSVGReader::doc()
+{
+ return d->doc;
+}
+
+KSVG::KSVGCanvas *KSVGReader::canvas()
+{
+ return d->canvas;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/core/KSVGReader.h b/ksvg/core/KSVGReader.h
new file mode 100644
index 00000000..722720e1
--- /dev/null
+++ b/ksvg/core/KSVGReader.h
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSVGReader_H
+#define KSVGReader_H
+
+#include <qxml.h>
+#include <qobject.h>
+
+namespace KSVG
+{
+
+class SVGDocumentImpl;
+class KSVGReader : public QObject
+{
+Q_OBJECT
+public:
+ struct ParsingArgs
+ {
+ bool fit;
+ bool getURLMode;
+
+ QString SVGFragmentId;
+ };
+
+ KSVGReader(SVGDocumentImpl *doc, KSVGCanvas *canvas, ParsingArgs args);
+ virtual ~KSVGReader();
+
+ void parse(QXmlInputSource *source);
+ void finishParsing(bool, const QString &);
+
+signals:
+ void finished(bool, const QString &);
+
+protected:
+ friend class Helper;
+
+ SVGDocumentImpl *doc();
+ KSVGCanvas *canvas();
+
+ void setFinished(bool error, const QString &errorDesc = 0);
+
+private:
+ struct Private;
+ Private *d;
+};
+
+}
+
+#endif
diff --git a/ksvg/core/KSVGTextChunk.cpp b/ksvg/core/KSVGTextChunk.cpp
new file mode 100644
index 00000000..b8eddcad
--- /dev/null
+++ b/ksvg/core/KSVGTextChunk.cpp
@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGTextContentElementImpl.h"
+#include "SVGTextPositioningElementImpl.h"
+#include "KSVGTextChunk.h"
+
+using namespace KSVG;
+
+// Text chunks (class to store text data)
+KSVGTextChunk::KSVGTextChunk()
+{
+}
+
+KSVGTextChunk::~KSVGTextChunk()
+{
+}
+
+unsigned int KSVGTextChunk::count() const
+{
+ return m_text.count();
+}
+
+QString KSVGTextChunk::getText(unsigned int index) const
+{
+ return m_text[index];
+}
+
+SVGTextPositioningElementImpl *KSVGTextChunk::getTextElement(unsigned int index)
+{
+ SVGTextContentElementImpl *content = getTextContentElement(index);
+ return dynamic_cast<SVGTextPositioningElementImpl *>(content);
+}
+
+SVGTextContentElementImpl *KSVGTextChunk::getTextContentElement(unsigned int index)
+{
+ return m_textElements.at(index);
+}
+
+void KSVGTextChunk::clear()
+{
+ m_text.clear();
+ m_textElements.clear();
+}
+
+void KSVGTextChunk::addText(const QString &text, SVGTextContentElementImpl *textElement)
+{
+ m_text.append(text);
+ m_textElements.append(textElement);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/core/KSVGTextChunk.h b/ksvg/core/KSVGTextChunk.h
new file mode 100644
index 00000000..d684087a
--- /dev/null
+++ b/ksvg/core/KSVGTextChunk.h
@@ -0,0 +1,54 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSVGTEXTCHUNK_H
+#define KSVGTEXTCHUNK_H
+
+#include <qstringlist.h>
+
+namespace KSVG
+{
+
+class SVGTextContentElementImpl;
+class SVGTextPositioningElementImpl;
+class KSVGTextChunk
+{
+public:
+ KSVGTextChunk();
+ ~KSVGTextChunk();
+
+ unsigned int count() const;
+ QString getText(unsigned int index) const;
+ SVGTextPositioningElementImpl *getTextElement(unsigned int index);
+ SVGTextContentElementImpl *getTextContentElement(unsigned int index);
+
+ void clear();
+ void addText(const QString &text, SVGTextContentElementImpl *textElement);
+
+private:
+ QStringList m_text;
+ QPtrList<SVGTextContentElementImpl> m_textElements;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/core/Makefile.am b/ksvg/core/Makefile.am
new file mode 100644
index 00000000..e1867428
--- /dev/null
+++ b/ksvg/core/Makefile.am
@@ -0,0 +1,16 @@
+noinst_LTLIBRARIES = libksvgcore.la
+
+libksvgcore_la_SOURCES = KSVGLoader.cpp KSVGCanvas.cpp KSVGReader.cc KSVGTextChunk.cpp CanvasFactory.cpp CanvasItems.cpp KSVGHelper.cpp DocumentFactory.cpp
+libksvgcore_la_METASOURCES = AUTO
+
+servicetypedir = $(kde_servicetypesdir)
+servicetype_DATA = ksvgrenderer.desktop
+
+ksvginclude_HEADERS = KSVGCanvas.h CanvasItems.h CanvasItem.h CanvasFactory.h DocumentFactory.h
+ksvgincludedir = $(includedir)/ksvg
+
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+INCLUDES = $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) -I$(top_srcdir)/ksvg/dom -I$(top_srcdir)/ksvg/impl -I$(top_srcdir)/ksvg/ecma -I$(top_srcdir)/ksvg/impl/libs/art_support -I$(top_srcdir)/ksvg/impl/libs/libtext2path/src $(all_includes)
+
+KDE_OPTIONS = nofinal
+
diff --git a/ksvg/core/ksvgrenderer.desktop b/ksvg/core/ksvgrenderer.desktop
new file mode 100644
index 00000000..f9307621
--- /dev/null
+++ b/ksvg/core/ksvgrenderer.desktop
@@ -0,0 +1,56 @@
+[Desktop Entry]
+Type=ServiceType
+X-KDE-ServiceType=KSVG/Renderer
+X-KDE-Derived=
+Comment=KSVG Rendering Backend
+Comment[ar]=خلفية رسم KSVG
+Comment[bs]=KSVG renderiranje
+Comment[ca]=Representació en segon pla de KSVG
+Comment[cs]=Vykreslovací nástroj KSVG
+Comment[cy]=Ôl-wyneb Llunio KSVG
+Comment[da]=Underliggende program for KSVG-visning
+Comment[de]=KSVG-Darstellungsmodul
+Comment[el]=Σύστημα υποστήριξης αποτύπωσης του KSVG
+Comment[es]=Motor de procesado de KSVG
+Comment[et]=KSVG renderdamise taustarakendus
+Comment[eu]=KSVG errendatze programa
+Comment[fa]=پایانۀ پشتیبانی پرداخت KSVG
+Comment[fi]=KSVG-piirtäjän taustaohjelma
+Comment[fr]=Moteur de rendu KSVG
+Comment[ga]=Inneall Rindreála KSVG
+Comment[gl]=Backend de Renderizado KSVG
+Comment[he]=מנוע רינדור KSVG
+Comment[hi]=के-एसवीजी रेंडरिंग बैकएण्ड
+Comment[hu]=KSVG megjelenítőmotor
+Comment[is]=KSVG teiknari
+Comment[it]=Backend di KSVG per il rendering
+Comment[ja]=KSVG レンダリングバックエンド
+Comment[kk]=KSVG кескіндеу бағдарламасы
+Comment[km]=កម្មវិធី​សម្រាប់​បង្ហាញ KSVG
+Comment[lt]=KSVG atkūrimo programinė sąsaja
+Comment[ms]=Tepi Belakang Menrealisasi KSVG
+Comment[nb]=Modul for KSVG-tegning
+Comment[nds]=KSVG-Dorstellhölper
+Comment[ne]=KSVG रेन्डरिङ ब्याकइन्ड
+Comment[nl]=KSVG weergavecomponent
+Comment[nn]=Modul for KSVG-teikning
+Comment[pl]=Narzędzie do renderowania KSVG
+Comment[pt]=Infra-Estrutura de Desenho KSVG
+Comment[pt_BR]=Estrutura de Renderização do KSVG
+Comment[ro]=Motorul de randare KSVG
+Comment[ru]=Движок прорисовки KSVG
+Comment[sk]=Nástroj pre zobrazovanie KSVG
+Comment[sl]=Izrisovalnik KSVG
+Comment[sr]=KSVG-ов позадински систем за рендеровање
+Comment[sr@Latn]=KSVG-ov pozadinski sistem za renderovanje
+Comment[sv]=KSVG-uppritningsmodul
+Comment[ta]=KSVG வழங்கும் பின் அமைப்பு
+Comment[tg]=Лағжандаи тасовироти KSVG
+Comment[tr]=KSVG Tarama Arkayüzü
+Comment[uk]=Інтерфейс відтворення KSVG
+Comment[zh_CN]=KSVG 渲染后端
+Comment[zh_HK]=KSVG 合成後端
+Comment[zh_TW]=KSVG 上色後端介面
+
+[PropertyDef::X-KSVG-InternalName]
+Type=QString
diff --git a/ksvg/data/SVGAElementImpl.lut.h b/ksvg/data/SVGAElementImpl.lut.h
new file mode 100644
index 00000000..9ef7a610
--- /dev/null
+++ b/ksvg/data/SVGAElementImpl.lut.h
@@ -0,0 +1,20 @@
+/* Automatically generated from impl/SVGAElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGAElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "target\0"
+};
+
+
+static const struct HashEntry SVGAElementImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGAElementImpl::Target, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGAElementImpl::s_hashTable = { 2, 2, SVGAElementImpl__s_hashTableEntries, 2, SVGAElementImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGAngleImpl.lut.h b/ksvg/data/SVGAngleImpl.lut.h
new file mode 100644
index 00000000..b57f44e1
--- /dev/null
+++ b/ksvg/data/SVGAngleImpl.lut.h
@@ -0,0 +1,77 @@
+/* Automatically generated from impl/SVGAngleImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGAngleImpl__s_hashTableStrings[] = {
+ "\0"
+ "valueInSpecifiedUnits\0"
+ "valueAsString\0"
+ "unitType\0"
+ "value\0"
+};
+
+
+static const struct HashEntry SVGAngleImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 46, SVGAngleImpl::Value, DontDelete, 0, 5 },
+ { 23, SVGAngleImpl::ValueAsString, DontDelete, 0, -1 },
+ { 1, SVGAngleImpl::ValueInSpecifiedUnits, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 37, SVGAngleImpl::UnitType, DontDelete, 0, -1 }
+};
+
+const struct HashTable SVGAngleImpl::s_hashTable = { 2, 6, SVGAngleImpl__s_hashTableEntries, 5, SVGAngleImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGAngleImplProto__s_hashTableStrings[] = {
+ "\0"
+ "convertToSpecifiedUnits\0"
+ "newValueSpecifiedUnits\0"
+};
+
+
+static const struct HashEntry SVGAngleImplProto__s_hashTableEntries[] = {
+ { 1, SVGAngleImpl::ConvertToSpecifiedUnits, DontDelete|Function, 1, -1 },
+ { 25, SVGAngleImpl::NewValueSpecifiedUnits, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGAngleImplProto::s_hashTable = { 2, 3, SVGAngleImplProto__s_hashTableEntries, 3, SVGAngleImplProto__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGAngleImplConstructor__s_hashTableStrings[] = {
+ "\0"
+ "SVG_ANGLETYPE_UNSPECIFIED\0"
+ "SVG_ANGLETYPE_UNKNOWN\0"
+ "SVG_ANGLETYPE_GRAD\0"
+ "SVG_ANGLETYPE_DEG\0"
+ "SVG_ANGLETYPE_RAD\0"
+};
+
+
+static const struct HashEntry SVGAngleImplConstructor__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 1, KSVG::SVG_ANGLETYPE_UNSPECIFIED, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 86, KSVG::SVG_ANGLETYPE_RAD, DontDelete|ReadOnly, 0, 7 },
+ { 49, KSVG::SVG_ANGLETYPE_GRAD, DontDelete|ReadOnly, 0, -1 },
+ { 27, KSVG::SVG_ANGLETYPE_UNKNOWN, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 68, KSVG::SVG_ANGLETYPE_DEG, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGAngleImplConstructor::s_hashTable = { 2, 8, SVGAngleImplConstructor__s_hashTableEntries, 7, SVGAngleImplConstructor__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGAnimatedAngleImpl.lut.h b/ksvg/data/SVGAnimatedAngleImpl.lut.h
new file mode 100644
index 00000000..8635120a
--- /dev/null
+++ b/ksvg/data/SVGAnimatedAngleImpl.lut.h
@@ -0,0 +1,22 @@
+/* Automatically generated from impl/SVGAnimatedAngleImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGAnimatedAngleImpl__s_hashTableStrings[] = {
+ "\0"
+ "animVal\0"
+ "baseVal\0"
+};
+
+
+static const struct HashEntry SVGAnimatedAngleImpl__s_hashTableEntries[] = {
+ { 9, SVGAnimatedAngleImpl::BaseVal, DontDelete|ReadOnly, 0, -1 },
+ { 1, SVGAnimatedAngleImpl::AnimVal, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGAnimatedAngleImpl::s_hashTable = { 2, 3, SVGAnimatedAngleImpl__s_hashTableEntries, 3, SVGAnimatedAngleImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGAnimatedBooleanImpl.lut.h b/ksvg/data/SVGAnimatedBooleanImpl.lut.h
new file mode 100644
index 00000000..928b3f0f
--- /dev/null
+++ b/ksvg/data/SVGAnimatedBooleanImpl.lut.h
@@ -0,0 +1,22 @@
+/* Automatically generated from impl/SVGAnimatedBooleanImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGAnimatedBooleanImpl__s_hashTableStrings[] = {
+ "\0"
+ "animVal\0"
+ "baseVal\0"
+};
+
+
+static const struct HashEntry SVGAnimatedBooleanImpl__s_hashTableEntries[] = {
+ { 9, SVGAnimatedBooleanImpl::BaseVal, DontDelete, 0, -1 },
+ { 1, SVGAnimatedBooleanImpl::AnimVal, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGAnimatedBooleanImpl::s_hashTable = { 2, 3, SVGAnimatedBooleanImpl__s_hashTableEntries, 3, SVGAnimatedBooleanImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGAnimatedEnumerationImpl.lut.h b/ksvg/data/SVGAnimatedEnumerationImpl.lut.h
new file mode 100644
index 00000000..b9a48bde
--- /dev/null
+++ b/ksvg/data/SVGAnimatedEnumerationImpl.lut.h
@@ -0,0 +1,22 @@
+/* Automatically generated from impl/SVGAnimatedEnumerationImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGAnimatedEnumerationImpl__s_hashTableStrings[] = {
+ "\0"
+ "animVal\0"
+ "baseVal\0"
+};
+
+
+static const struct HashEntry SVGAnimatedEnumerationImpl__s_hashTableEntries[] = {
+ { 9, SVGAnimatedEnumerationImpl::BaseVal, DontDelete, 0, -1 },
+ { 1, SVGAnimatedEnumerationImpl::AnimVal, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGAnimatedEnumerationImpl::s_hashTable = { 2, 3, SVGAnimatedEnumerationImpl__s_hashTableEntries, 3, SVGAnimatedEnumerationImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGAnimatedIntegerImpl.lut.h b/ksvg/data/SVGAnimatedIntegerImpl.lut.h
new file mode 100644
index 00000000..91934787
--- /dev/null
+++ b/ksvg/data/SVGAnimatedIntegerImpl.lut.h
@@ -0,0 +1,22 @@
+/* Automatically generated from impl/SVGAnimatedIntegerImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGAnimatedIntegerImpl__s_hashTableStrings[] = {
+ "\0"
+ "animVal\0"
+ "baseVal\0"
+};
+
+
+static const struct HashEntry SVGAnimatedIntegerImpl__s_hashTableEntries[] = {
+ { 9, SVGAnimatedIntegerImpl::BaseVal, DontDelete, 0, -1 },
+ { 1, SVGAnimatedIntegerImpl::AnimVal, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGAnimatedIntegerImpl::s_hashTable = { 2, 3, SVGAnimatedIntegerImpl__s_hashTableEntries, 3, SVGAnimatedIntegerImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGAnimatedLengthImpl.lut.h b/ksvg/data/SVGAnimatedLengthImpl.lut.h
new file mode 100644
index 00000000..b969bf35
--- /dev/null
+++ b/ksvg/data/SVGAnimatedLengthImpl.lut.h
@@ -0,0 +1,22 @@
+/* Automatically generated from impl/SVGAnimatedLengthImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGAnimatedLengthImpl__s_hashTableStrings[] = {
+ "\0"
+ "animVal\0"
+ "baseVal\0"
+};
+
+
+static const struct HashEntry SVGAnimatedLengthImpl__s_hashTableEntries[] = {
+ { 9, SVGAnimatedLengthImpl::BaseVal, DontDelete|ReadOnly, 0, -1 },
+ { 1, SVGAnimatedLengthImpl::AnimVal, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGAnimatedLengthImpl::s_hashTable = { 2, 3, SVGAnimatedLengthImpl__s_hashTableEntries, 3, SVGAnimatedLengthImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGAnimatedLengthListImpl.lut.h b/ksvg/data/SVGAnimatedLengthListImpl.lut.h
new file mode 100644
index 00000000..463d834d
--- /dev/null
+++ b/ksvg/data/SVGAnimatedLengthListImpl.lut.h
@@ -0,0 +1,22 @@
+/* Automatically generated from impl/SVGAnimatedLengthListImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGAnimatedLengthListImpl__s_hashTableStrings[] = {
+ "\0"
+ "animVal\0"
+ "baseVal\0"
+};
+
+
+static const struct HashEntry SVGAnimatedLengthListImpl__s_hashTableEntries[] = {
+ { 9, SVGAnimatedLengthListImpl::BaseVal, DontDelete|ReadOnly, 0, -1 },
+ { 1, SVGAnimatedLengthListImpl::AnimVal, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGAnimatedLengthListImpl::s_hashTable = { 2, 3, SVGAnimatedLengthListImpl__s_hashTableEntries, 3, SVGAnimatedLengthListImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGAnimatedNumberImpl.lut.h b/ksvg/data/SVGAnimatedNumberImpl.lut.h
new file mode 100644
index 00000000..7563430b
--- /dev/null
+++ b/ksvg/data/SVGAnimatedNumberImpl.lut.h
@@ -0,0 +1,22 @@
+/* Automatically generated from impl/SVGAnimatedNumberImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGAnimatedNumberImpl__s_hashTableStrings[] = {
+ "\0"
+ "animVal\0"
+ "baseVal\0"
+};
+
+
+static const struct HashEntry SVGAnimatedNumberImpl__s_hashTableEntries[] = {
+ { 9, SVGAnimatedNumberImpl::BaseVal, DontDelete, 0, -1 },
+ { 1, SVGAnimatedNumberImpl::AnimVal, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGAnimatedNumberImpl::s_hashTable = { 2, 3, SVGAnimatedNumberImpl__s_hashTableEntries, 3, SVGAnimatedNumberImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGAnimatedNumberListImpl.lut.h b/ksvg/data/SVGAnimatedNumberListImpl.lut.h
new file mode 100644
index 00000000..e73471fe
--- /dev/null
+++ b/ksvg/data/SVGAnimatedNumberListImpl.lut.h
@@ -0,0 +1,22 @@
+/* Automatically generated from impl/SVGAnimatedNumberListImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGAnimatedNumberListImpl__s_hashTableStrings[] = {
+ "\0"
+ "animVal\0"
+ "baseVal\0"
+};
+
+
+static const struct HashEntry SVGAnimatedNumberListImpl__s_hashTableEntries[] = {
+ { 9, SVGAnimatedNumberListImpl::BaseVal, DontDelete|ReadOnly, 0, -1 },
+ { 1, SVGAnimatedNumberListImpl::AnimVal, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGAnimatedNumberListImpl::s_hashTable = { 2, 3, SVGAnimatedNumberListImpl__s_hashTableEntries, 3, SVGAnimatedNumberListImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGAnimatedPathDataImpl.lut.h b/ksvg/data/SVGAnimatedPathDataImpl.lut.h
new file mode 100644
index 00000000..8e0e8395
--- /dev/null
+++ b/ksvg/data/SVGAnimatedPathDataImpl.lut.h
@@ -0,0 +1,28 @@
+/* Automatically generated from impl/SVGAnimatedPathDataImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGAnimatedPathDataImpl__s_hashTableStrings[] = {
+ "\0"
+ "animatedNormalizedPathSegList\0"
+ "normalizedPathSegList\0"
+ "animatedPathSegList\0"
+ "pathSegList\0"
+};
+
+
+static const struct HashEntry SVGAnimatedPathDataImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 53, SVGAnimatedPathDataImpl::AnimatedPathSegList, DontDelete|ReadOnly, 0, 6 },
+ { 0, 0, 0, 0, -1 },
+ { 73, SVGAnimatedPathDataImpl::PathSegList, DontDelete|ReadOnly, 0, 5 },
+ { 0, 0, 0, 0, -1 },
+ { 31, SVGAnimatedPathDataImpl::NormalizedPathSegList, DontDelete|ReadOnly, 0, -1 },
+ { 1, SVGAnimatedPathDataImpl::AnimatedNormalizedPathSegList, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGAnimatedPathDataImpl::s_hashTable = { 2, 7, SVGAnimatedPathDataImpl__s_hashTableEntries, 5, SVGAnimatedPathDataImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGAnimatedPointsImpl.lut.h b/ksvg/data/SVGAnimatedPointsImpl.lut.h
new file mode 100644
index 00000000..6b48313a
--- /dev/null
+++ b/ksvg/data/SVGAnimatedPointsImpl.lut.h
@@ -0,0 +1,22 @@
+/* Automatically generated from impl/SVGAnimatedPointsImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGAnimatedPointsImpl__s_hashTableStrings[] = {
+ "\0"
+ "animatedPoints\0"
+ "points\0"
+};
+
+
+static const struct HashEntry SVGAnimatedPointsImpl__s_hashTableEntries[] = {
+ { 16, SVGAnimatedPointsImpl::Points, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGAnimatedPointsImpl::AnimatedPoints, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGAnimatedPointsImpl::s_hashTable = { 2, 3, SVGAnimatedPointsImpl__s_hashTableEntries, 3, SVGAnimatedPointsImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGAnimatedPreserveAspectRatioImpl.lut.h b/ksvg/data/SVGAnimatedPreserveAspectRatioImpl.lut.h
new file mode 100644
index 00000000..a681a408
--- /dev/null
+++ b/ksvg/data/SVGAnimatedPreserveAspectRatioImpl.lut.h
@@ -0,0 +1,22 @@
+/* Automatically generated from impl/SVGAnimatedPreserveAspectRatioImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGAnimatedPreserveAspectRatioImpl__s_hashTableStrings[] = {
+ "\0"
+ "animVal\0"
+ "baseVal\0"
+};
+
+
+static const struct HashEntry SVGAnimatedPreserveAspectRatioImpl__s_hashTableEntries[] = {
+ { 9, SVGAnimatedPreserveAspectRatioImpl::BaseVal, DontDelete|ReadOnly, 0, -1 },
+ { 1, SVGAnimatedPreserveAspectRatioImpl::AnimVal, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGAnimatedPreserveAspectRatioImpl::s_hashTable = { 2, 3, SVGAnimatedPreserveAspectRatioImpl__s_hashTableEntries, 3, SVGAnimatedPreserveAspectRatioImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGAnimatedRectImpl.lut.h b/ksvg/data/SVGAnimatedRectImpl.lut.h
new file mode 100644
index 00000000..9a16c899
--- /dev/null
+++ b/ksvg/data/SVGAnimatedRectImpl.lut.h
@@ -0,0 +1,22 @@
+/* Automatically generated from impl/SVGAnimatedRectImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGAnimatedRectImpl__s_hashTableStrings[] = {
+ "\0"
+ "animVal\0"
+ "baseVal\0"
+};
+
+
+static const struct HashEntry SVGAnimatedRectImpl__s_hashTableEntries[] = {
+ { 9, SVGAnimatedRectImpl::BaseVal, DontDelete, 0, -1 },
+ { 1, SVGAnimatedRectImpl::AnimVal, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGAnimatedRectImpl::s_hashTable = { 2, 3, SVGAnimatedRectImpl__s_hashTableEntries, 3, SVGAnimatedRectImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGAnimatedStringImpl.lut.h b/ksvg/data/SVGAnimatedStringImpl.lut.h
new file mode 100644
index 00000000..add905dd
--- /dev/null
+++ b/ksvg/data/SVGAnimatedStringImpl.lut.h
@@ -0,0 +1,22 @@
+/* Automatically generated from impl/SVGAnimatedStringImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGAnimatedStringImpl__s_hashTableStrings[] = {
+ "\0"
+ "animVal\0"
+ "baseVal\0"
+};
+
+
+static const struct HashEntry SVGAnimatedStringImpl__s_hashTableEntries[] = {
+ { 9, SVGAnimatedStringImpl::BaseVal, DontDelete, 0, -1 },
+ { 1, SVGAnimatedStringImpl::AnimVal, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGAnimatedStringImpl::s_hashTable = { 2, 3, SVGAnimatedStringImpl__s_hashTableEntries, 3, SVGAnimatedStringImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGAnimatedTransformListImpl.lut.h b/ksvg/data/SVGAnimatedTransformListImpl.lut.h
new file mode 100644
index 00000000..7974a00e
--- /dev/null
+++ b/ksvg/data/SVGAnimatedTransformListImpl.lut.h
@@ -0,0 +1,22 @@
+/* Automatically generated from impl/SVGAnimatedTransformListImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGAnimatedTransformListImpl__s_hashTableStrings[] = {
+ "\0"
+ "animVal\0"
+ "baseVal\0"
+};
+
+
+static const struct HashEntry SVGAnimatedTransformListImpl__s_hashTableEntries[] = {
+ { 9, SVGAnimatedTransformListImpl::BaseVal, DontDelete|ReadOnly, 0, -1 },
+ { 1, SVGAnimatedTransformListImpl::AnimVal, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGAnimatedTransformListImpl::s_hashTable = { 2, 3, SVGAnimatedTransformListImpl__s_hashTableEntries, 3, SVGAnimatedTransformListImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGAnimationElementImpl.lut.h b/ksvg/data/SVGAnimationElementImpl.lut.h
new file mode 100644
index 00000000..af8ea0d5
--- /dev/null
+++ b/ksvg/data/SVGAnimationElementImpl.lut.h
@@ -0,0 +1,94 @@
+/* Automatically generated from impl/SVGAnimationElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGAnimationElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "attributeName\0"
+ "attributeType\0"
+ "targetElement\0"
+ "repeatCount\0"
+ "accumulate\0"
+ "keySplines\0"
+ "repeatDur\0"
+ "additive\0"
+ "calcMode\0"
+ "keyTimes\0"
+ "restart\0"
+ "values\0"
+ "begin\0"
+ "fill\0"
+ "from\0"
+ "href\0"
+ "dur\0"
+ "end\0"
+ "max\0"
+ "min\0"
+ "by\0"
+ "to\0"
+};
+
+
+static const struct HashEntry SVGAnimationElementImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 55, SVGAnimationElementImpl::Accumulate, DontDelete|ReadOnly, 0, 25 },
+ { 0, 0, 0, 0, -1 },
+ { 29, SVGAnimationElementImpl::TargetElement, DontDelete|ReadOnly, 0, 26 },
+ { 66, SVGAnimationElementImpl::KeySplines, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 145, SVGAnimationElementImpl::Href, DontDelete|ReadOnly, 0, -1 },
+ { 1, SVGAnimationElementImpl::AttributeName, DontDelete|ReadOnly, 0, -1 },
+ { 150, SVGAnimationElementImpl::Dur, DontDelete|ReadOnly, 0, 30 },
+ { 96, SVGAnimationElementImpl::CalcMode, DontDelete|ReadOnly, 0, -1 },
+ { 129, SVGAnimationElementImpl::Begin, DontDelete|ReadOnly, 0, -1 },
+ { 122, SVGAnimationElementImpl::Values, DontDelete|ReadOnly, 0, 23 },
+ { 0, 0, 0, 0, -1 },
+ { 87, SVGAnimationElementImpl::Additive, DontDelete|ReadOnly, 0, 27 },
+ { 105, SVGAnimationElementImpl::KeyTimes, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 15, SVGAnimationElementImpl::AttributeType, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 169, SVGAnimationElementImpl::To, DontDelete|ReadOnly, 0, 29 },
+ { 0, 0, 0, 0, -1 },
+ { 140, SVGAnimationElementImpl::From, DontDelete|ReadOnly, 0, -1 },
+ { 166, SVGAnimationElementImpl::By, DontDelete|ReadOnly, 0, 24 },
+ { 154, SVGAnimationElementImpl::End, DontDelete|ReadOnly, 0, 28 },
+ { 162, SVGAnimationElementImpl::Min, DontDelete|ReadOnly, 0, -1 },
+ { 158, SVGAnimationElementImpl::Max, DontDelete|ReadOnly, 0, -1 },
+ { 114, SVGAnimationElementImpl::Restart, DontDelete|ReadOnly, 0, -1 },
+ { 43, SVGAnimationElementImpl::RepeatCount, DontDelete|ReadOnly, 0, -1 },
+ { 77, SVGAnimationElementImpl::RepeatDur, DontDelete|ReadOnly, 0, -1 },
+ { 135, SVGAnimationElementImpl::Fill, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGAnimationElementImpl::s_hashTable = { 2, 31, SVGAnimationElementImpl__s_hashTableEntries, 23, SVGAnimationElementImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGAnimationElementImplProto__s_hashTableStrings[] = {
+ "\0"
+ "getSimpleDuration\0"
+ "getCurrentTime\0"
+ "getStartTime\0"
+};
+
+
+static const struct HashEntry SVGAnimationElementImplProto__s_hashTableEntries[] = {
+ { 34, SVGAnimationElementImpl::GetStartTime, DontDelete|Function, 0, -1 },
+ { 1, SVGAnimationElementImpl::GetSimpleDuration, DontDelete|Function, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 19, SVGAnimationElementImpl::GetCurrentTime, DontDelete|Function, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGAnimationElementImplProto::s_hashTable = { 2, 5, SVGAnimationElementImplProto__s_hashTableEntries, 5, SVGAnimationElementImplProto__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGCircleElementImpl.lut.h b/ksvg/data/SVGCircleElementImpl.lut.h
new file mode 100644
index 00000000..dc7fb0cc
--- /dev/null
+++ b/ksvg/data/SVGCircleElementImpl.lut.h
@@ -0,0 +1,26 @@
+/* Automatically generated from impl/SVGCircleElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGCircleElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "cx\0"
+ "cy\0"
+ "r\0"
+};
+
+
+static const struct HashEntry SVGCircleElementImpl__s_hashTableEntries[] = {
+ { 4, SVGCircleElementImpl::Cy, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGCircleElementImpl::Cx, DontDelete|ReadOnly, 0, 5 },
+ { 7, SVGCircleElementImpl::R, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGCircleElementImpl::s_hashTable = { 2, 6, SVGCircleElementImpl__s_hashTableEntries, 5, SVGCircleElementImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGClipPathElementImpl.lut.h b/ksvg/data/SVGClipPathElementImpl.lut.h
new file mode 100644
index 00000000..5f5c7df2
--- /dev/null
+++ b/ksvg/data/SVGClipPathElementImpl.lut.h
@@ -0,0 +1,20 @@
+/* Automatically generated from impl/SVGClipPathElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGClipPathElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "clipPathUnits\0"
+};
+
+
+static const struct HashEntry SVGClipPathElementImpl__s_hashTableEntries[] = {
+ { 1, SVGClipPathElementImpl::ClipPathUnits, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGClipPathElementImpl::s_hashTable = { 2, 2, SVGClipPathElementImpl__s_hashTableEntries, 2, SVGClipPathElementImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGColorImpl.lut.h b/ksvg/data/SVGColorImpl.lut.h
new file mode 100644
index 00000000..e6e0fe48
--- /dev/null
+++ b/ksvg/data/SVGColorImpl.lut.h
@@ -0,0 +1,76 @@
+/* Automatically generated from impl/SVGColorImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGColorImpl__s_hashTableStrings[] = {
+ "\0"
+ "colorType\0"
+ "ICCColor\0"
+ "RGBColor\0"
+};
+
+
+static const struct HashEntry SVGColorImpl__s_hashTableEntries[] = {
+ { 20, SVGColorImpl::RGBColor, DontDelete|ReadOnly, 0, -1 },
+ { 1, SVGColorImpl::ColorType, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 11, SVGColorImpl::ICCColor, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGColorImpl::s_hashTable = { 2, 5, SVGColorImpl__s_hashTableEntries, 5, SVGColorImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGColorImplProto__s_hashTableStrings[] = {
+ "\0"
+ "setRGBColorICCColor\0"
+ "setRGBColor\0"
+ "setColor\0"
+};
+
+
+static const struct HashEntry SVGColorImplProto__s_hashTableEntries[] = {
+ { 1, SVGColorImpl::SetRGBColorICCColor, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 21, SVGColorImpl::SetRGBColor, DontDelete|Function, 1, -1 },
+ { 33, SVGColorImpl::SetColor, DontDelete|Function, 3, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGColorImplProto::s_hashTable = { 2, 5, SVGColorImplProto__s_hashTableEntries, 5, SVGColorImplProto__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGColorImplConstructor__s_hashTableStrings[] = {
+ "\0"
+ "SVG_COLORTYPE_RGBCOLOR_ICCCOLOR\0"
+ "SVG_COLORTYPE_CURRENTCOLOR\0"
+ "SVG_COLORTYPE_RGBCOLOR\0"
+ "SVG_COLORTYPE_UNKNOWN\0"
+};
+
+
+static const struct HashEntry SVGColorImplConstructor__s_hashTableEntries[] = {
+ { 83, KSVG::SVG_COLORTYPE_UNKNOWN, DontDelete|ReadOnly, 0, 6 },
+ { 0, 0, 0, 0, -1 },
+ { 60, KSVG::SVG_COLORTYPE_RGBCOLOR, DontDelete|ReadOnly, 0, 5 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, KSVG::SVG_COLORTYPE_RGBCOLOR_ICCCOLOR, DontDelete|ReadOnly, 0, -1 },
+ { 33, KSVG::SVG_COLORTYPE_CURRENTCOLOR, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGColorImplConstructor::s_hashTable = { 2, 7, SVGColorImplConstructor__s_hashTableEntries, 5, SVGColorImplConstructor__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGColorProfileElementImpl.lut.h b/ksvg/data/SVGColorProfileElementImpl.lut.h
new file mode 100644
index 00000000..40c11854
--- /dev/null
+++ b/ksvg/data/SVGColorProfileElementImpl.lut.h
@@ -0,0 +1,26 @@
+/* Automatically generated from impl/SVGColorProfileElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGColorProfileElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "rendering-intent\0"
+ "href\0"
+ "name\0"
+};
+
+
+static const struct HashEntry SVGColorProfileElementImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 18, SVGColorProfileElementImpl::Href, DontDelete|ReadOnly, 0, 5 },
+ { 23, SVGColorProfileElementImpl::Name, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGColorProfileElementImpl::RenderingIntent, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGColorProfileElementImpl::s_hashTable = { 2, 6, SVGColorProfileElementImpl__s_hashTableEntries, 5, SVGColorProfileElementImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGCursorElementImpl.lut.h b/ksvg/data/SVGCursorElementImpl.lut.h
new file mode 100644
index 00000000..94527e0c
--- /dev/null
+++ b/ksvg/data/SVGCursorElementImpl.lut.h
@@ -0,0 +1,22 @@
+/* Automatically generated from impl/SVGCursorElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGCursorElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "x\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGCursorElementImpl__s_hashTableEntries[] = {
+ { 1, SVGCursorElementImpl::X, DontDelete|ReadOnly, 0, -1 },
+ { 3, SVGCursorElementImpl::Y, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGCursorElementImpl::s_hashTable = { 2, 3, SVGCursorElementImpl__s_hashTableEntries, 3, SVGCursorElementImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGDocumentImpl.lut.h b/ksvg/data/SVGDocumentImpl.lut.h
new file mode 100644
index 00000000..92b7ed14
--- /dev/null
+++ b/ksvg/data/SVGDocumentImpl.lut.h
@@ -0,0 +1,67 @@
+/* Automatically generated from impl/SVGDocumentImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGDocumentImpl__s_hashTableStrings[] = {
+ "\0"
+ "documentElement\0"
+ "implementation\0"
+ "rootElement\0"
+ "referrer\0"
+ "doctype\0"
+ "domain\0"
+ "title\0"
+ "URL\0"
+};
+
+
+static const struct HashEntry SVGDocumentImpl__s_hashTableEntries[] = {
+ { 74, SVGDocumentImpl::Url, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 61, SVGDocumentImpl::Domain, DontDelete|ReadOnly, 0, 10 },
+ { 0, 0, 0, 0, -1 },
+ { 53, SVGDocumentImpl::DocType, DontDelete|ReadOnly, 0, -1 },
+ { 32, SVGDocumentImpl::RootElement, DontDelete|ReadOnly, 0, -1 },
+ { 68, SVGDocumentImpl::Title, DontDelete|ReadOnly, 0, 9 },
+ { 17, SVGDocumentImpl::Implementation, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 44, SVGDocumentImpl::Referrer, DontDelete|ReadOnly, 0, -1 },
+ { 1, SVGDocumentImpl::DocumentElement, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGDocumentImpl::s_hashTable = { 2, 11, SVGDocumentImpl__s_hashTableEntries, 9, SVGDocumentImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGDocumentImplProto__s_hashTableStrings[] = {
+ "\0"
+ "getElementsByTagNameNS\0"
+ "getElementsByTagName\0"
+ "createElementNS\0"
+ "createTextNode\0"
+ "getElementById\0"
+ "createElement\0"
+};
+
+
+static const struct HashEntry SVGDocumentImplProto__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 76, SVGDocumentImpl::GetElementById, DontDelete|Function, 1, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 24, SVGDocumentImpl::GetElementsByTagName, DontDelete|Function, 1, 8 },
+ { 61, SVGDocumentImpl::CreateTextNode, DontDelete|Function, 1, -1 },
+ { 91, SVGDocumentImpl::CreateElement, DontDelete|Function, 1, 7 },
+ { 0, 0, 0, 0, -1 },
+ { 45, SVGDocumentImpl::CreateElementNS, DontDelete|Function, 2, -1 },
+ { 1, SVGDocumentImpl::GetElementsByTagNameNS, DontDelete|Function, 2, -1 }
+};
+
+const struct HashTable SVGDocumentImplProto::s_hashTable = { 2, 9, SVGDocumentImplProto__s_hashTableEntries, 7, SVGDocumentImplProto__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGEcma.lut.h b/ksvg/data/SVGEcma.lut.h
new file mode 100644
index 00000000..54909bab
--- /dev/null
+++ b/ksvg/data/SVGEcma.lut.h
@@ -0,0 +1,396 @@
+/* Automatically generated from impl/SVGEcma.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGDOMNodeBridge__s_hashTableStrings[] = {
+ "\0"
+ "previousSibling\0"
+ "ownerDocument\0"
+ "namespaceURI\0"
+ "nextSibling\0"
+ "attributes\0"
+ "childNodes\0"
+ "firstChild\0"
+ "parentNode\0"
+ "lastChild\0"
+ "localName\0"
+ "nodeValue\0"
+ "nodeName\0"
+ "nodeType\0"
+ "prefix\0"
+};
+
+
+static const struct HashEntry SVGDOMNodeBridge__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 67, SVGDOMNodeBridge::ChildNodes, DontDelete|ReadOnly, 0, -1 },
+ { 100, SVGDOMNodeBridge::LastChild, DontDelete|ReadOnly, 0, -1 },
+ { 89, SVGDOMNodeBridge::ParentNode, DontDelete|ReadOnly, 0, 18 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 139, SVGDOMNodeBridge::NodeType, DontDelete|ReadOnly, 0, 17 },
+ { 130, SVGDOMNodeBridge::NodeName, DontDelete|ReadOnly, 0, 20 },
+ { 17, SVGDOMNodeBridge::OwnerDocument, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 120, SVGDOMNodeBridge::NodeValue, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 78, SVGDOMNodeBridge::FirstChild, DontDelete|ReadOnly, 0, -1 },
+ { 1, SVGDOMNodeBridge::PreviousSibling, DontDelete|ReadOnly, 0, 19 },
+ { 44, SVGDOMNodeBridge::NextSibling, DontDelete|ReadOnly, 0, -1 },
+ { 56, SVGDOMNodeBridge::Attributes, DontDelete|ReadOnly, 0, 22 },
+ { 31, SVGDOMNodeBridge::NamespaceURI, DontDelete|ReadOnly, 0, 21 },
+ { 148, SVGDOMNodeBridge::Prefix, DontDelete, 0, -1 },
+ { 110, SVGDOMNodeBridge::LocalName, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGDOMNodeBridge::s_hashTable = { 2, 23, SVGDOMNodeBridge__s_hashTableEntries, 17, SVGDOMNodeBridge__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGDOMNodeBridgeProto__s_hashTableStrings[] = {
+ "\0"
+ "removeEventListener\0"
+ "getPreviousSibling\0"
+ "addEventListener\0"
+ "getOwnerDocument\0"
+ "getNamespaceURI\0"
+ "getNextSibling\0"
+ "getAttributes\0"
+ "getChildNodes\0"
+ "getFirstChild\0"
+ "getParentNode\0"
+ "hasAttributes\0"
+ "hasChildNodes\0"
+ "getLastChild\0"
+ "getLocalName\0"
+ "getNodeValue\0"
+ "insertBefore\0"
+ "replaceChild\0"
+ "appendChild\0"
+ "getNodeName\0"
+ "getNodeType\0"
+ "isSupported\0"
+ "removeChild\0"
+ "cloneNode\0"
+ "getPrefix\0"
+ "normalize\0"
+ "contains\0"
+};
+
+
+static const struct HashEntry SVGDOMNodeBridgeProto__s_hashTableEntries[] = {
+ { 175, SVGDOMNodeBridge::HasChildNodes, DontDelete|Function, 0, -1 },
+ { 215, SVGDOMNodeBridge::GetNodeValue, DontDelete|Function, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 119, SVGDOMNodeBridge::GetChildNodes, DontDelete|Function, 0, -1 },
+ { 1, SVGDOMNodeBridge::RemoveEventListener, DontDelete|Function, 3, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 302, SVGDOMNodeBridge::RemoveChild, DontDelete|Function, 1, 37 },
+ { 21, SVGDOMNodeBridge::GetPreviousSibling, DontDelete|Function, 0, -1 },
+ { 228, SVGDOMNodeBridge::InsertBefore, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 254, SVGDOMNodeBridge::AppendChild, DontDelete|Function, 1, 36 },
+ { 0, 0, 0, 0, -1 },
+ { 161, SVGDOMNodeBridge::HasAttributes, DontDelete|Function, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 133, SVGDOMNodeBridge::GetFirstChild, DontDelete|Function, 0, 32 },
+ { 314, SVGDOMNodeBridge::CloneNode, DontDelete|Function, 1, 29 },
+ { 57, SVGDOMNodeBridge::GetOwnerDocument, DontDelete|Function, 0, -1 },
+ { 344, SVGDOMNodeBridge::Contains, DontDelete|Function, 1, 30 },
+ { 147, SVGDOMNodeBridge::GetParentNode, DontDelete|Function, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 40, SVGDOMNodeBridge::AddEventListener, DontDelete|Function, 3, -1 },
+ { 290, SVGDOMNodeBridge::IsSupported, DontDelete|Function, 2, 31 },
+ { 241, SVGDOMNodeBridge::ReplaceChild, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 334, SVGDOMNodeBridge::Normalize, DontDelete|Function, 0, 34 },
+ { 266, SVGDOMNodeBridge::GetNodeName, DontDelete|Function, 0, -1 },
+ { 278, SVGDOMNodeBridge::GetNodeType, DontDelete|Function, 0, 33 },
+ { 189, SVGDOMNodeBridge::GetLastChild, DontDelete|Function, 0, 35 },
+ { 90, SVGDOMNodeBridge::GetNextSibling, DontDelete|Function, 0, -1 },
+ { 105, SVGDOMNodeBridge::GetAttributes, DontDelete|Function, 0, -1 },
+ { 74, SVGDOMNodeBridge::GetNamespaceURI, DontDelete|Function, 0, -1 },
+ { 324, SVGDOMNodeBridge::GetPrefix, DontDelete|Function, 0, -1 },
+ { 202, SVGDOMNodeBridge::GetLocalName, DontDelete|Function, 0, -1 }
+};
+
+const struct HashTable SVGDOMNodeBridgeProto::s_hashTable = { 2, 38, SVGDOMNodeBridgeProto__s_hashTableEntries, 29, SVGDOMNodeBridgeProto__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGDOMElementBridge__s_hashTableStrings[] = {
+ "\0"
+ "tagName\0"
+};
+
+
+static const struct HashEntry SVGDOMElementBridge__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGDOMElementBridge::TagName, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGDOMElementBridge::s_hashTable = { 2, 2, SVGDOMElementBridge__s_hashTableEntries, 2, SVGDOMElementBridge__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGDOMElementBridgeProto__s_hashTableStrings[] = {
+ "\0"
+ "getElementByTagNameNS\0"
+ "getElementsByTagName\0"
+ "removeAttributeNode\0"
+ "getAttributeNodeNS\0"
+ "setAttributeNodeNS\0"
+ "removeAttributeNS\0"
+ "getAttributeNode\0"
+ "setAttributeNode\0"
+ "removeAttribute\0"
+ "getAttributeNS\0"
+ "hasAttributeNS\0"
+ "setAttributeNS\0"
+ "getAttribute\0"
+ "hasAttribute\0"
+ "setAttribute\0"
+};
+
+
+static const struct HashEntry SVGDOMElementBridgeProto__s_hashTableEntries[] = {
+ { 64, SVGDOMElementBridge::GetAttributeNodeNS, DontDelete|Function, 2, -1 },
+ { 170, SVGDOMElementBridge::GetAttributeNS, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 44, SVGDOMElementBridge::RemoveAttributeNode, DontDelete|Function, 1, -1 },
+ { 154, SVGDOMElementBridge::RemoveAttribute, DontDelete|Function, 1, 17 },
+ { 241, SVGDOMElementBridge::SetAttribute, DontDelete|Function, 2, -1 },
+ { 228, SVGDOMElementBridge::HasAttribute, DontDelete|Function, 1, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 120, SVGDOMElementBridge::GetAttributeNode, DontDelete|Function, 1, -1 },
+ { 215, SVGDOMElementBridge::GetAttribute, DontDelete|Function, 1, -1 },
+ { 1, SVGDOMElementBridge::GetElementsByTagNameNS, DontDelete|Function, 2, -1 },
+ { 102, SVGDOMElementBridge::RemoveAttributeNS, DontDelete|Function, 2, 18 },
+ { 200, SVGDOMElementBridge::SetAttributeNS, DontDelete|Function, 3, -1 },
+ { 185, SVGDOMElementBridge::HasAttributeNS, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 23, SVGDOMElementBridge::GetElementsByTagName, DontDelete|Function, 1, -1 },
+ { 137, SVGDOMElementBridge::SetAttributeNode, DontDelete|Function, 2, -1 },
+ { 83, SVGDOMElementBridge::SetAttributeNodeNS, DontDelete|Function, 1, -1 }
+};
+
+const struct HashTable SVGDOMElementBridgeProto::s_hashTable = { 2, 19, SVGDOMElementBridgeProto__s_hashTableEntries, 17, SVGDOMElementBridgeProto__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGDOMNodeListBridge__s_hashTableStrings[] = {
+ "\0"
+ "length\0"
+};
+
+
+static const struct HashEntry SVGDOMNodeListBridge__s_hashTableEntries[] = {
+ { 1, SVGDOMNodeListBridge::Length, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGDOMNodeListBridge::s_hashTable = { 2, 2, SVGDOMNodeListBridge__s_hashTableEntries, 2, SVGDOMNodeListBridge__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGDOMNodeListBridgeProto__s_hashTableStrings[] = {
+ "\0"
+ "getLength\0"
+ "item\0"
+};
+
+
+static const struct HashEntry SVGDOMNodeListBridgeProto__s_hashTableEntries[] = {
+ { 1, SVGDOMNodeListBridge::GetLength, DontDelete|Function, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 11, SVGDOMNodeListBridge::Item, DontDelete|Function, 1, -1 }
+};
+
+const struct HashTable SVGDOMNodeListBridgeProto::s_hashTable = { 2, 3, SVGDOMNodeListBridgeProto__s_hashTableEntries, 3, SVGDOMNodeListBridgeProto__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGDOMCharacterDataBridge__s_hashTableStrings[] = {
+ "\0"
+ "length\0"
+ "data\0"
+};
+
+
+static const struct HashEntry SVGDOMCharacterDataBridge__s_hashTableEntries[] = {
+ { 1, SVGDOMCharacterDataBridge::Length, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 8, SVGDOMCharacterDataBridge::Data, DontDelete, 0, -1 }
+};
+
+const struct HashTable SVGDOMCharacterDataBridge::s_hashTable = { 2, 3, SVGDOMCharacterDataBridge__s_hashTableEntries, 3, SVGDOMCharacterDataBridge__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGDOMCharacterDataBridgeProto__s_hashTableStrings[] = {
+ "\0"
+ "substringData\0"
+ "replaceData\0"
+ "appendData\0"
+ "deleteData\0"
+ "insertData\0"
+ "getLength\0"
+ "getData\0"
+ "setData\0"
+};
+
+
+static const struct HashEntry SVGDOMCharacterDataBridgeProto__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 38, SVGDOMCharacterDataBridge::DeleteData, DontDelete|Function, 2, -1 },
+ { 70, SVGDOMCharacterDataBridge::GetData, DontDelete|Function, 0, 12 },
+ { 78, SVGDOMCharacterDataBridge::SetData, DontDelete|Function, 1, 11 },
+ { 1, SVGDOMCharacterDataBridge::SubstringData, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 27, SVGDOMCharacterDataBridge::AppendData, DontDelete|Function, 1, -1 },
+ { 15, SVGDOMCharacterDataBridge::ReplaceData, DontDelete|Function, 2, -1 },
+ { 60, SVGDOMCharacterDataBridge::GetLength, DontDelete|Function, 0, -1 },
+ { 49, SVGDOMCharacterDataBridge::InsertData, DontDelete|Function, 2, -1 }
+};
+
+const struct HashTable SVGDOMCharacterDataBridgeProto::s_hashTable = { 2, 13, SVGDOMCharacterDataBridgeProto__s_hashTableEntries, 11, SVGDOMCharacterDataBridgeProto__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGDOMTextBridge__s_hashTableStrings[] = {
+ "\0"
+ "dummy\0"
+};
+
+
+static const struct HashEntry SVGDOMTextBridge__s_hashTableEntries[] = {
+ { 1, SVGDOMTextBridge::Dummy, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGDOMTextBridge::s_hashTable = { 2, 2, SVGDOMTextBridge__s_hashTableEntries, 2, SVGDOMTextBridge__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGDOMTextBridgeProto__s_hashTableStrings[] = {
+ "\0"
+ "splitText\0"
+};
+
+
+static const struct HashEntry SVGDOMTextBridgeProto__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGDOMTextBridge::SplitText, DontDelete|Function, 1, -1 }
+};
+
+const struct HashTable SVGDOMTextBridgeProto::s_hashTable = { 2, 2, SVGDOMTextBridgeProto__s_hashTableEntries, 2, SVGDOMTextBridgeProto__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGDOMDOMImplementationBridge__s_hashTableStrings[] = {
+ "\0"
+ "dummy\0"
+};
+
+
+static const struct HashEntry SVGDOMDOMImplementationBridge__s_hashTableEntries[] = {
+ { 1, SVGDOMDOMImplementationBridge::Dummy, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGDOMDOMImplementationBridge::s_hashTable = { 2, 2, SVGDOMDOMImplementationBridge__s_hashTableEntries, 2, SVGDOMDOMImplementationBridge__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGDOMDOMImplementationBridgeProto__s_hashTableStrings[] = {
+ "\0"
+ "hasFeature\0"
+};
+
+
+static const struct HashEntry SVGDOMDOMImplementationBridgeProto__s_hashTableEntries[] = {
+ { 1, SVGDOMDOMImplementationBridge::HasFeature, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGDOMDOMImplementationBridgeProto::s_hashTable = { 2, 2, SVGDOMDOMImplementationBridgeProto__s_hashTableEntries, 2, SVGDOMDOMImplementationBridgeProto__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGDOMDocumentFragmentBridge__s_hashTableStrings[] = {
+ "\0"
+ "dummy\0"
+};
+
+
+static const struct HashEntry SVGDOMDocumentFragmentBridge__s_hashTableEntries[] = {
+ { 1, SVGDOMDocumentFragmentBridge::Dummy, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGDOMDocumentFragmentBridge::s_hashTable = { 2, 2, SVGDOMDocumentFragmentBridge__s_hashTableEntries, 2, SVGDOMDocumentFragmentBridge__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGElementImpl.lut.h b/ksvg/data/SVGElementImpl.lut.h
new file mode 100644
index 00000000..fe205a71
--- /dev/null
+++ b/ksvg/data/SVGElementImpl.lut.h
@@ -0,0 +1,92 @@
+/* Automatically generated from impl/SVGElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "ownerSVGElement\0"
+ "viewportElement\0"
+ "onmouseclick\0"
+ "onmousedown\0"
+ "onmousemove\0"
+ "onmouseover\0"
+ "onactivate\0"
+ "onfocusout\0"
+ "onkeypress\0"
+ "onmouseout\0"
+ "onfocusin\0"
+ "onkeydown\0"
+ "onmouseup\0"
+ "onabort\0"
+ "onclick\0"
+ "onerror\0"
+ "onkeyup\0"
+ "xmlbase\0"
+ "onload\0"
+ "id\0"
+};
+
+
+static const struct HashEntry SVGElementImpl__s_hashTableEntries[] = {
+ { 17, SVGElementImpl::ViewportElement, DontDelete|ReadOnly, 0, -1 },
+ { 136, SVGElementImpl::OnKeyDown, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 164, SVGElementImpl::OnClick, DontDelete, 0, 27 },
+ { 33, SVGElementImpl::OnClick, DontDelete, 0, -1 },
+ { 93, SVGElementImpl::OnFocusOut, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 188, SVGElementImpl::XmlBase, DontDelete, 0, 25 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGElementImpl::OwnerSvgElement, DontDelete|ReadOnly, 0, 23 },
+ { 0, 0, 0, 0, -1 },
+ { 196, SVGElementImpl::OnLoad, DontDelete, 0, 29 },
+ { 58, SVGElementImpl::OnMouseMove, DontDelete, 0, -1 },
+ { 46, SVGElementImpl::OnMouseDown, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 191, SVGElementImpl::XmlBase, DontDelete, 0, 26 },
+ { 203, SVGElementImpl::ElementId, DontDelete, 0, 30 },
+ { 70, SVGElementImpl::OnMouseOver, DontDelete, 0, -1 },
+ { 146, SVGElementImpl::OnMouseUp, DontDelete, 0, 24 },
+ { 115, SVGElementImpl::OnMouseOut, DontDelete, 0, 28 },
+ { 82, SVGElementImpl::OnActivate, DontDelete, 0, -1 },
+ { 180, SVGElementImpl::OnKeyUp, DontDelete, 0, -1 },
+ { 104, SVGElementImpl::OnKeyPress, DontDelete, 0, -1 },
+ { 126, SVGElementImpl::OnFocusIn, DontDelete, 0, -1 },
+ { 172, SVGElementImpl::OnError, DontDelete, 0, -1 },
+ { 156, SVGElementImpl::OnAbort, DontDelete, 0, -1 }
+};
+
+const struct HashTable SVGElementImpl::s_hashTable = { 2, 31, SVGElementImpl__s_hashTableEntries, 23, SVGElementImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGElementImplProto__s_hashTableStrings[] = {
+ "\0"
+ "getPropertyValue\0"
+ "setProperty\0"
+ "getStyle\0"
+};
+
+
+static const struct HashEntry SVGElementImplProto__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 18, SVGElementImpl::SetProperty, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGElementImpl::GetPropertyValue, DontDelete|Function, 1, -1 },
+ { 30, SVGElementImpl::GetStyle, DontDelete|Function, 0, -1 }
+};
+
+const struct HashTable SVGElementImplProto::s_hashTable = { 2, 5, SVGElementImplProto__s_hashTableEntries, 5, SVGElementImplProto__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGEllipseElementImpl.lut.h b/ksvg/data/SVGEllipseElementImpl.lut.h
new file mode 100644
index 00000000..a2fe34a7
--- /dev/null
+++ b/ksvg/data/SVGEllipseElementImpl.lut.h
@@ -0,0 +1,28 @@
+/* Automatically generated from impl/SVGEllipseElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGEllipseElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "cx\0"
+ "cy\0"
+ "rx\0"
+ "ry\0"
+};
+
+
+static const struct HashEntry SVGEllipseElementImpl__s_hashTableEntries[] = {
+ { 4, SVGEllipseElementImpl::Cy, DontDelete|ReadOnly, 0, 6 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGEllipseElementImpl::Cx, DontDelete|ReadOnly, 0, 5 },
+ { 7, SVGEllipseElementImpl::Rx, DontDelete|ReadOnly, 0, -1 },
+ { 10, SVGEllipseElementImpl::Ry, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGEllipseElementImpl::s_hashTable = { 2, 7, SVGEllipseElementImpl__s_hashTableEntries, 5, SVGEllipseElementImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGEventImpl.lut.h b/ksvg/data/SVGEventImpl.lut.h
new file mode 100644
index 00000000..3283775e
--- /dev/null
+++ b/ksvg/data/SVGEventImpl.lut.h
@@ -0,0 +1,271 @@
+/* Automatically generated from impl/SVGEventImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGEventImpl__s_hashTableStrings[] = {
+ "\0"
+ "currentTarget\0"
+ "cancelable\0"
+ "eventPhase\0"
+ "timeStamp\0"
+ "bubbles\0"
+ "target\0"
+ "type\0"
+};
+
+
+static const struct HashEntry SVGEventImpl__s_hashTableEntries[] = {
+ { 1, SVGEventImpl::CurrentTarget, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 37, SVGEventImpl::TimeStamp, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 15, SVGEventImpl::Cancelable, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 55, SVGEventImpl::Target, DontDelete|ReadOnly, 0, 11 },
+ { 62, SVGEventImpl::Type, DontDelete|ReadOnly, 0, -1 },
+ { 26, SVGEventImpl::EventPhase, DontDelete|ReadOnly, 0, 12 },
+ { 47, SVGEventImpl::Bubbles, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGEventImpl::s_hashTable = { 2, 13, SVGEventImpl__s_hashTableEntries, 11, SVGEventImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGEventImplProto__s_hashTableStrings[] = {
+ "\0"
+ "getCurrentTarget\0"
+ "stopPropagation\0"
+ "getCurrentNode\0"
+ "preventDefault\0"
+ "getCancelable\0"
+ "getEventphase\0"
+ "getTimeStamp\0"
+ "getBubbles\0"
+ "getTarget\0"
+ "initEvent\0"
+ "getType\0"
+};
+
+
+static const struct HashEntry SVGEventImplProto__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 92, SVGEventImpl::GetTimeStamp, DontDelete|Function, 0, 17 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 34, SVGEventImpl::GetCurrentNode, DontDelete|Function, 0, 14 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 105, SVGEventImpl::GetBubbles, DontDelete|Function, 0, -1 },
+ { 136, SVGEventImpl::GetType, DontDelete|Function, 0, 13 },
+ { 78, SVGEventImpl::GetEventPhase, DontDelete|Function, 0, 15 },
+ { 116, SVGEventImpl::GetTarget, DontDelete|Function, 0, 16 },
+ { 1, SVGEventImpl::GetCurrentTarget, DontDelete|Function, 0, -1 },
+ { 64, SVGEventImpl::GetCancelable, DontDelete|Function, 0, -1 },
+ { 18, SVGEventImpl::StopPropagation, DontDelete|Function, 0, -1 },
+ { 49, SVGEventImpl::PreventDefault, DontDelete|Function, 0, -1 },
+ { 126, SVGEventImpl::InitEvent, DontDelete|Function, 3, -1 }
+};
+
+const struct HashTable SVGEventImplProto::s_hashTable = { 2, 18, SVGEventImplProto__s_hashTableEntries, 13, SVGEventImplProto__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGUIEventImpl__s_hashTableStrings[] = {
+ "\0"
+ "detail\0"
+ "view\0"
+};
+
+
+static const struct HashEntry SVGUIEventImpl__s_hashTableEntries[] = {
+ { 1, SVGUIEventImpl::Detail, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 8, SVGUIEventImpl::View, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGUIEventImpl::s_hashTable = { 2, 3, SVGUIEventImpl__s_hashTableEntries, 3, SVGUIEventImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGUIEventImplProto__s_hashTableStrings[] = {
+ "\0"
+ "initUIEvent\0"
+ "getDetail\0"
+ "getView\0"
+};
+
+
+static const struct HashEntry SVGUIEventImplProto__s_hashTableEntries[] = {
+ { 13, SVGUIEventImpl::GetDetail, DontDelete|Function, 0, -1 },
+ { 23, SVGUIEventImpl::GetView, DontDelete|Function, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGUIEventImpl::InitUIEvent, DontDelete|Function, 5, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGUIEventImplProto::s_hashTable = { 2, 5, SVGUIEventImplProto__s_hashTableEntries, 5, SVGUIEventImplProto__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGKeyEventImpl__s_hashTableStrings[] = {
+ "\0"
+ "outputString\0"
+ "virtKeyVal\0"
+ "charCode\0"
+ "keyCode\0"
+ "keyVal\0"
+};
+
+
+static const struct HashEntry SVGKeyEventImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 34, SVGKeyEventImpl::KeyVal, DontDelete|ReadOnly, 0, -1 },
+ { 25, SVGKeyEventImpl::KeyVal, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 42, SVGKeyEventImpl::KeyVal, DontDelete|ReadOnly, 0, 7 },
+ { 14, SVGKeyEventImpl::VirtKeyVal, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGKeyEventImpl::OutputString, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGKeyEventImpl::s_hashTable = { 2, 8, SVGKeyEventImpl__s_hashTableEntries, 7, SVGKeyEventImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGKeyEventImplProto__s_hashTableStrings[] = {
+ "\0"
+ "checkModifier\0"
+ "getCharCode\0"
+ "getKeyCode\0"
+ "getKeyVal\0"
+};
+
+
+static const struct HashEntry SVGKeyEventImplProto__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGKeyEventImpl::CheckModifier, DontDelete|Function, 1, 7 },
+ { 15, SVGKeyEventImpl::GetKeyVal, DontDelete|Function, 0, 8 },
+ { 0, 0, 0, 0, -1 },
+ { 38, SVGKeyEventImpl::GetKeyVal, DontDelete|Function, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 27, SVGKeyEventImpl::GetKeyVal, DontDelete|Function, 0, -1 },
+ { 15, SVGKeyEventImpl::GetCharCode, DontDelete|Function, 0, -1 }
+};
+
+const struct HashTable SVGKeyEventImplProto::s_hashTable = { 2, 9, SVGKeyEventImplProto__s_hashTableEntries, 7, SVGKeyEventImplProto__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGMouseEventImpl__s_hashTableStrings[] = {
+ "\0"
+ "relatedTarget\0"
+ "shiftKey\0"
+ "clientX\0"
+ "clientY\0"
+ "ctrlKey\0"
+ "metaKey\0"
+ "screenX\0"
+ "screenY\0"
+ "altKey\0"
+ "button\0"
+};
+
+
+static const struct HashEntry SVGMouseEventImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 24, SVGMouseEventImpl::ClientX, DontDelete|ReadOnly, 0, -1 },
+ { 56, SVGMouseEventImpl::ScreenX, DontDelete|ReadOnly, 0, 11 },
+ { 64, SVGMouseEventImpl::ScreenY, DontDelete|ReadOnly, 0, 12 },
+ { 0, 0, 0, 0, -1 },
+ { 48, SVGMouseEventImpl::MetaKey, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 40, SVGMouseEventImpl::CtrlKey, DontDelete|ReadOnly, 0, 14 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGMouseEventImpl::RelatedTarget, DontDelete|ReadOnly, 0, -1 },
+ { 32, SVGMouseEventImpl::ClientY, DontDelete|ReadOnly, 0, 13 },
+ { 15, SVGMouseEventImpl::ShiftKey, DontDelete|ReadOnly, 0, -1 },
+ { 72, SVGMouseEventImpl::AltKey, DontDelete|ReadOnly, 0, -1 },
+ { 79, SVGMouseEventImpl::Button, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGMouseEventImpl::s_hashTable = { 2, 15, SVGMouseEventImpl__s_hashTableEntries, 11, SVGMouseEventImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGMouseEventImplProto__s_hashTableStrings[] = {
+ "\0"
+ "getRelatedTarget\0"
+ "initMouseEvent\0"
+ "getShiftKey\0"
+ "getClientX\0"
+ "getClientY\0"
+ "getCtrlKey\0"
+ "getMetaKey\0"
+ "getScreenX\0"
+ "getScreenY\0"
+ "getAltKey\0"
+ "getButton\0"
+};
+
+
+static const struct HashEntry SVGMouseEventImplProto__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 45, SVGMouseEventImpl::GetClientX, DontDelete|Function, 0, -1 },
+ { 89, SVGMouseEventImpl::GetScreenX, DontDelete|Function, 0, 13 },
+ { 100, SVGMouseEventImpl::GetScreenY, DontDelete|Function, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 78, SVGMouseEventImpl::GetMetaKey, DontDelete|Function, 0, 15 },
+ { 67, SVGMouseEventImpl::GetCtrlKey, DontDelete|Function, 0, -1 },
+ { 33, SVGMouseEventImpl::GetShiftKey, DontDelete|Function, 0, 14 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 56, SVGMouseEventImpl::GetClientY, DontDelete|Function, 0, 16 },
+ { 111, SVGMouseEventImpl::GetAltKey, DontDelete|Function, 0, -1 },
+ { 121, SVGMouseEventImpl::GetButton, DontDelete|Function, 0, -1 },
+ { 1, SVGMouseEventImpl::GetRelatedTarget, DontDelete|Function, 0, 17 },
+ { 18, SVGMouseEventImpl::InitMouseEvent, DontDelete|Function, 15, -1 }
+};
+
+const struct HashTable SVGMouseEventImplProto::s_hashTable = { 2, 18, SVGMouseEventImplProto__s_hashTableEntries, 13, SVGMouseEventImplProto__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGExternalResourcesRequiredImpl.lut.h b/ksvg/data/SVGExternalResourcesRequiredImpl.lut.h
new file mode 100644
index 00000000..2361f729
--- /dev/null
+++ b/ksvg/data/SVGExternalResourcesRequiredImpl.lut.h
@@ -0,0 +1,20 @@
+/* Automatically generated from impl/SVGExternalResourcesRequiredImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGExternalResourcesRequiredImpl__s_hashTableStrings[] = {
+ "\0"
+ "externalResourcesRequired\0"
+};
+
+
+static const struct HashEntry SVGExternalResourcesRequiredImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGExternalResourcesRequiredImpl::ExternalResourcesRequired, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGExternalResourcesRequiredImpl::s_hashTable = { 2, 2, SVGExternalResourcesRequiredImpl__s_hashTableEntries, 2, SVGExternalResourcesRequiredImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGFitToViewBoxImpl.lut.h b/ksvg/data/SVGFitToViewBoxImpl.lut.h
new file mode 100644
index 00000000..7ef28728
--- /dev/null
+++ b/ksvg/data/SVGFitToViewBoxImpl.lut.h
@@ -0,0 +1,22 @@
+/* Automatically generated from impl/SVGFitToViewBoxImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGFitToViewBoxImpl__s_hashTableStrings[] = {
+ "\0"
+ "preserveAspectRatio\0"
+ "viewBox\0"
+};
+
+
+static const struct HashEntry SVGFitToViewBoxImpl__s_hashTableEntries[] = {
+ { 1, SVGFitToViewBoxImpl::PreserveAspectRatio, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 21, SVGFitToViewBoxImpl::ViewBox, DontDelete, 0, -1 }
+};
+
+const struct HashTable SVGFitToViewBoxImpl::s_hashTable = { 2, 3, SVGFitToViewBoxImpl__s_hashTableEntries, 3, SVGFitToViewBoxImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGForeignObjectElementImpl.lut.h b/ksvg/data/SVGForeignObjectElementImpl.lut.h
new file mode 100644
index 00000000..a53be40e
--- /dev/null
+++ b/ksvg/data/SVGForeignObjectElementImpl.lut.h
@@ -0,0 +1,26 @@
+/* Automatically generated from impl/SVGForeignObjectElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGForeignObjectElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "height\0"
+ "width\0"
+ "x\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGForeignObjectElementImpl__s_hashTableEntries[] = {
+ { 14, SVGForeignObjectElementImpl::X, DontDelete|ReadOnly, 0, -1 },
+ { 16, SVGForeignObjectElementImpl::Y, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGForeignObjectElementImpl::Height, DontDelete|ReadOnly, 0, -1 },
+ { 8, SVGForeignObjectElementImpl::Width, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGForeignObjectElementImpl::s_hashTable = { 2, 5, SVGForeignObjectElementImpl__s_hashTableEntries, 5, SVGForeignObjectElementImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGGlyphElementImpl.lut.h b/ksvg/data/SVGGlyphElementImpl.lut.h
new file mode 100644
index 00000000..b4f54c4e
--- /dev/null
+++ b/ksvg/data/SVGGlyphElementImpl.lut.h
@@ -0,0 +1,39 @@
+/* Automatically generated from impl/SVGGlyphElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGGlyphElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "vert-origin-x\0"
+ "vert-origin-y\0"
+ "arabic-form\0"
+ "horiz-adv-x\0"
+ "orientation\0"
+ "glyph-name\0"
+ "vert-adv-y\0"
+ "unicode\0"
+ "lang\0"
+ "d\0"
+};
+
+
+static const struct HashEntry SVGGlyphElementImpl__s_hashTableEntries[] = {
+ { 95, SVGGlyphElementImpl::Lang, DontDelete|ReadOnly, 0, -1 },
+ { 100, SVGGlyphElementImpl::D, DontDelete|ReadOnly, 0, -1 },
+ { 29, SVGGlyphElementImpl::ArabicForm, DontDelete|ReadOnly, 0, -1 },
+ { 41, SVGGlyphElementImpl::HorizAdvX, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 87, SVGGlyphElementImpl::Unicode, DontDelete|ReadOnly, 0, -1 },
+ { 76, SVGGlyphElementImpl::VertAdvY, DontDelete|ReadOnly, 0, -1 },
+ { 53, SVGGlyphElementImpl::Orientation, DontDelete|ReadOnly, 0, -1 },
+ { 65, SVGGlyphElementImpl::GlyphName, DontDelete|ReadOnly, 0, 11 },
+ { 15, SVGGlyphElementImpl::VertOriginY, DontDelete|ReadOnly, 0, -1 },
+ { 1, SVGGlyphElementImpl::VertOriginX, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGGlyphElementImpl::s_hashTable = { 2, 12, SVGGlyphElementImpl__s_hashTableEntries, 11, SVGGlyphElementImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGGlyphRefElementImpl.lut.h b/ksvg/data/SVGGlyphRefElementImpl.lut.h
new file mode 100644
index 00000000..b64aab0f
--- /dev/null
+++ b/ksvg/data/SVGGlyphRefElementImpl.lut.h
@@ -0,0 +1,28 @@
+/* Automatically generated from impl/SVGGlyphRefElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGGlyphRefElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "glyphRef\0"
+ "format\0"
+ "dx\0"
+ "dy\0"
+};
+
+
+static const struct HashEntry SVGGlyphRefElementImpl__s_hashTableEntries[] = {
+ { 1, SVGGlyphRefElementImpl::GlyphRef, DontDelete|ReadOnly, 0, -1 },
+ { 18, SVGGlyphRefElementImpl::X, DontDelete|ReadOnly, 0, -1 },
+ { 21, SVGGlyphRefElementImpl::Y, DontDelete|ReadOnly, 0, -1 },
+ { 17, SVGGlyphRefElementImpl::Dx, DontDelete|ReadOnly, 0, -1 },
+ { 20, SVGGlyphRefElementImpl::Dy, DontDelete|ReadOnly, 0, -1 },
+ { 10, SVGGlyphRefElementImpl::Format, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGGlyphRefElementImpl::s_hashTable = { 2, 7, SVGGlyphRefElementImpl__s_hashTableEntries, 7, SVGGlyphRefElementImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGGradientElementImpl.lut.h b/ksvg/data/SVGGradientElementImpl.lut.h
new file mode 100644
index 00000000..84f5c8d9
--- /dev/null
+++ b/ksvg/data/SVGGradientElementImpl.lut.h
@@ -0,0 +1,51 @@
+/* Automatically generated from impl/SVGGradientElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGGradientElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "gradientTransform\0"
+ "gradientUnits\0"
+ "spreadMethod\0"
+};
+
+
+static const struct HashEntry SVGGradientElementImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 19, SVGGradientElementImpl::GradientUnits, DontDelete|ReadOnly, 0, 5 },
+ { 33, SVGGradientElementImpl::SpreadMethod, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGGradientElementImpl::GradientTransform, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGGradientElementImpl::s_hashTable = { 2, 6, SVGGradientElementImpl__s_hashTableEntries, 5, SVGGradientElementImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGGradientElementImplConstructor__s_hashTableStrings[] = {
+ "\0"
+ "SVG_SPREADMETHOD_REFLECT\0"
+ "SVG_SPREADMETHOD_UNKNOWN\0"
+ "SVG_SPREADMETHOD_REPEAT\0"
+ "SVG_SPREADMETHOD_PAD\0"
+};
+
+
+static const struct HashEntry SVGGradientElementImplConstructor__s_hashTableEntries[] = {
+ { 51, KSVG::SVG_SPREADMETHOD_REPEAT, DontDelete|ReadOnly, 0, -1 },
+ { 26, KSVG::SVG_SPREADMETHOD_UNKNOWN, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, KSVG::SVG_SPREADMETHOD_REFLECT, DontDelete|ReadOnly, 0, -1 },
+ { 75, KSVG::SVG_SPREADMETHOD_PAD, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGGradientElementImplConstructor::s_hashTable = { 2, 5, SVGGradientElementImplConstructor__s_hashTableEntries, 5, SVGGradientElementImplConstructor__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGICCColorImpl.lut.h b/ksvg/data/SVGICCColorImpl.lut.h
new file mode 100644
index 00000000..3ad22c89
--- /dev/null
+++ b/ksvg/data/SVGICCColorImpl.lut.h
@@ -0,0 +1,23 @@
+/* Automatically generated from impl/SVGICCColorImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGICCColorImpl__s_hashTableStrings[] = {
+ "\0"
+ "colorProfile\0"
+ "colors\0"
+};
+
+
+static const struct HashEntry SVGICCColorImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGICCColorImpl::ColorProfile, DontDelete, 0, 3 },
+ { 0, 0, 0, 0, -1 },
+ { 14, SVGICCColorImpl::Colors, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGICCColorImpl::s_hashTable = { 2, 4, SVGICCColorImpl__s_hashTableEntries, 3, SVGICCColorImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGImageElementImpl.lut.h b/ksvg/data/SVGImageElementImpl.lut.h
new file mode 100644
index 00000000..9584ecb8
--- /dev/null
+++ b/ksvg/data/SVGImageElementImpl.lut.h
@@ -0,0 +1,31 @@
+/* Automatically generated from impl/SVGImageElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGImageElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "preserveAspectRatio\0"
+ "height\0"
+ "width\0"
+ "href\0"
+ "x\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGImageElementImpl__s_hashTableEntries[] = {
+ { 1, SVGImageElementImpl::PreserveAspectRatio, DontDelete|ReadOnly, 0, -1 },
+ { 39, SVGImageElementImpl::X, DontDelete|ReadOnly, 0, 7 },
+ { 41, SVGImageElementImpl::Y, DontDelete|ReadOnly, 0, -1 },
+ { 21, SVGImageElementImpl::Height, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 28, SVGImageElementImpl::Width, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 34, SVGImageElementImpl::Href, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGImageElementImpl::s_hashTable = { 2, 8, SVGImageElementImpl__s_hashTableEntries, 7, SVGImageElementImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGLangSpaceImpl.lut.h b/ksvg/data/SVGLangSpaceImpl.lut.h
new file mode 100644
index 00000000..d8c727c4
--- /dev/null
+++ b/ksvg/data/SVGLangSpaceImpl.lut.h
@@ -0,0 +1,24 @@
+/* Automatically generated from impl/SVGLangSpaceImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGLangSpaceImpl__s_hashTableStrings[] = {
+ "\0"
+ "xmlspace\0"
+ "xmllang\0"
+};
+
+
+static const struct HashEntry SVGLangSpaceImpl__s_hashTableEntries[] = {
+ { 10, SVGLangSpaceImpl::XmlLang, DontDelete, 0, -1 },
+ { 1, SVGLangSpaceImpl::XmlSpace, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 13, SVGLangSpaceImpl::XmlLang, DontDelete, 0, -1 },
+ { 4, SVGLangSpaceImpl::XmlSpace, DontDelete, 0, -1 }
+};
+
+const struct HashTable SVGLangSpaceImpl::s_hashTable = { 2, 5, SVGLangSpaceImpl__s_hashTableEntries, 5, SVGLangSpaceImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGLengthImpl.lut.h b/ksvg/data/SVGLengthImpl.lut.h
new file mode 100644
index 00000000..dfd88b2f
--- /dev/null
+++ b/ksvg/data/SVGLengthImpl.lut.h
@@ -0,0 +1,87 @@
+/* Automatically generated from impl/SVGLengthImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGLengthImpl__s_hashTableStrings[] = {
+ "\0"
+ "valueInSpecifiedUnits\0"
+ "valueAsString\0"
+ "unitType\0"
+ "value\0"
+};
+
+
+static const struct HashEntry SVGLengthImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 37, SVGLengthImpl::UnitType, DontDelete|ReadOnly, 0, 5 },
+ { 23, SVGLengthImpl::ValueAsString, DontDelete, 0, -1 },
+ { 1, SVGLengthImpl::ValueInSpecifiedUnits, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 46, SVGLengthImpl::Value, DontDelete, 0, -1 }
+};
+
+const struct HashTable SVGLengthImpl::s_hashTable = { 2, 6, SVGLengthImpl__s_hashTableEntries, 5, SVGLengthImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGLengthImplProto__s_hashTableStrings[] = {
+ "\0"
+ "convertToSpecifiedUnits\0"
+ "newValueSpecifiedUnits\0"
+};
+
+
+static const struct HashEntry SVGLengthImplProto__s_hashTableEntries[] = {
+ { 1, SVGLengthImpl::ConvertToSpecifiedUnits, DontDelete|Function, 1, -1 },
+ { 25, SVGLengthImpl::NewValueSpecifiedUnits, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGLengthImplProto::s_hashTable = { 2, 3, SVGLengthImplProto__s_hashTableEntries, 3, SVGLengthImplProto__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGLengthImplConstructor__s_hashTableStrings[] = {
+ "\0"
+ "SVG_LENGTHTYPE_PERCENTAGE\0"
+ "SVG_LENGTHTYPE_UNKNOWN\0"
+ "SVG_LENGTHTYPE_NUMBER\0"
+ "SVG_LENGTHTYPE_EMS\0"
+ "SVG_LENGTHTYPE_EXS\0"
+ "SVG_LENGTHTYPE_CM\0"
+ "SVG_LENGTHTYPE_MM\0"
+ "SVG_LENGTHTYPE_PC\0"
+ "SVG_LENGTHTYPE_PT\0"
+ "SVG_LENGTHTYPE_PX\0"
+};
+
+
+static const struct HashEntry SVGLengthImplConstructor__s_hashTableEntries[] = {
+ { 1, KSVG::SVG_LENGTHTYPE_PERCENTAGE, DontDelete|ReadOnly, 0, -1 },
+ { 72, KSVG::SVG_LENGTHTYPE_EMS, DontDelete|ReadOnly, 0, 11 },
+ { 27, KSVG::SVG_LENGTHTYPE_UNKNOWN, DontDelete|ReadOnly, 0, 12 },
+ { 128, KSVG::SVG_LENGTHTYPE_MM, DontDelete|ReadOnly, 0, -1 },
+ { 110, KSVG::SVG_LENGTHTYPE_CM, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 182, KSVG::SVG_LENGTHTYPE_PX, DontDelete|ReadOnly, 0, -1 },
+ { 146, KSVG::SVG_LENGTHTYPE_PC, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 50, KSVG::SVG_LENGTHTYPE_NUMBER, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 91, KSVG::SVG_LENGTHTYPE_EXS, DontDelete|ReadOnly, 0, -1 },
+ { 164, KSVG::SVG_LENGTHTYPE_PT, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGLengthImplConstructor::s_hashTable = { 2, 13, SVGLengthImplConstructor__s_hashTableEntries, 11, SVGLengthImplConstructor__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGLengthListImpl.lut.h b/ksvg/data/SVGLengthListImpl.lut.h
new file mode 100644
index 00000000..9f263f81
--- /dev/null
+++ b/ksvg/data/SVGLengthListImpl.lut.h
@@ -0,0 +1,55 @@
+/* Automatically generated from impl/SVGLengthListImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGLengthListImpl__s_hashTableStrings[] = {
+ "\0"
+ "numberOfItems\0"
+};
+
+
+static const struct HashEntry SVGLengthListImpl__s_hashTableEntries[] = {
+ { 1, SVGListDefs::NumberOfItems, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGLengthListImpl::s_hashTable = { 2, 2, SVGLengthListImpl__s_hashTableEntries, 2, SVGLengthListImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGLengthListImplProto__s_hashTableStrings[] = {
+ "\0"
+ "insertItemBefore\0"
+ "replaceItem\0"
+ "appendItem\0"
+ "initialize\0"
+ "removeItem\0"
+ "getItem\0"
+ "clear\0"
+};
+
+
+static const struct HashEntry SVGLengthListImplProto__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 71, SVGListDefs::Clear, DontDelete|Function, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 63, SVGListDefs::GetItem, DontDelete|Function, 1, -1 },
+ { 1, SVGListDefs::InsertItemBefore, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 41, SVGListDefs::Initialize, DontDelete|Function, 1, -1 },
+ { 52, SVGListDefs::RemoveItem, DontDelete|Function, 1, 11 },
+ { 18, SVGListDefs::ReplaceItem, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 30, SVGListDefs::AppendItem, DontDelete|Function, 1, -1 }
+};
+
+const struct HashTable SVGLengthListImplProto::s_hashTable = { 2, 12, SVGLengthListImplProto__s_hashTableEntries, 11, SVGLengthListImplProto__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGLineElementImpl.lut.h b/ksvg/data/SVGLineElementImpl.lut.h
new file mode 100644
index 00000000..857b3ee2
--- /dev/null
+++ b/ksvg/data/SVGLineElementImpl.lut.h
@@ -0,0 +1,27 @@
+/* Automatically generated from impl/SVGLineElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGLineElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "x1\0"
+ "x2\0"
+ "y1\0"
+ "y2\0"
+};
+
+
+static const struct HashEntry SVGLineElementImpl__s_hashTableEntries[] = {
+ { 7, SVGLineElementImpl::Y1, DontDelete|ReadOnly, 0, 5 },
+ { 10, SVGLineElementImpl::Y2, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGLineElementImpl::X1, DontDelete|ReadOnly, 0, -1 },
+ { 4, SVGLineElementImpl::X2, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGLineElementImpl::s_hashTable = { 2, 6, SVGLineElementImpl__s_hashTableEntries, 5, SVGLineElementImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGLinearGradientElementImpl.lut.h b/ksvg/data/SVGLinearGradientElementImpl.lut.h
new file mode 100644
index 00000000..30755f58
--- /dev/null
+++ b/ksvg/data/SVGLinearGradientElementImpl.lut.h
@@ -0,0 +1,27 @@
+/* Automatically generated from impl/SVGLinearGradientElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGLinearGradientElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "x1\0"
+ "x2\0"
+ "y1\0"
+ "y2\0"
+};
+
+
+static const struct HashEntry SVGLinearGradientElementImpl__s_hashTableEntries[] = {
+ { 7, SVGLinearGradientElementImpl::Y1, DontDelete|ReadOnly, 0, 5 },
+ { 10, SVGLinearGradientElementImpl::Y2, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGLinearGradientElementImpl::X1, DontDelete|ReadOnly, 0, -1 },
+ { 4, SVGLinearGradientElementImpl::X2, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGLinearGradientElementImpl::s_hashTable = { 2, 6, SVGLinearGradientElementImpl__s_hashTableEntries, 5, SVGLinearGradientElementImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGLocatableImpl.lut.h b/ksvg/data/SVGLocatableImpl.lut.h
new file mode 100644
index 00000000..5fcafcda
--- /dev/null
+++ b/ksvg/data/SVGLocatableImpl.lut.h
@@ -0,0 +1,49 @@
+/* Automatically generated from impl/SVGLocatableImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGLocatableImpl__s_hashTableStrings[] = {
+ "\0"
+ "farthestViewportElement\0"
+ "nearestViewportElement\0"
+};
+
+
+static const struct HashEntry SVGLocatableImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 25, SVGLocatableImpl::NearestViewportElement, DontDelete, 0, 3 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGLocatableImpl::FarthestViewportElement, DontDelete, 0, -1 }
+};
+
+const struct HashTable SVGLocatableImpl::s_hashTable = { 2, 4, SVGLocatableImpl__s_hashTableEntries, 3, SVGLocatableImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGLocatableImplProto__s_hashTableStrings[] = {
+ "\0"
+ "getTransformToElement\0"
+ "getScreenCTM\0"
+ "getBBox\0"
+ "getCTM\0"
+};
+
+
+static const struct HashEntry SVGLocatableImplProto__s_hashTableEntries[] = {
+ { 1, SVGLocatableImpl::GetTransformToElement, DontDelete|Function, 1, -1 },
+ { 23, SVGLocatableImpl::GetScreenCTM, DontDelete|Function, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 36, SVGLocatableImpl::GetBBox, DontDelete|Function, 0, 5 },
+ { 0, 0, 0, 0, -1 },
+ { 44, SVGLocatableImpl::GetCTM, DontDelete|Function, 0, -1 }
+};
+
+const struct HashTable SVGLocatableImplProto::s_hashTable = { 2, 6, SVGLocatableImplProto__s_hashTableEntries, 5, SVGLocatableImplProto__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGMarkerElementImpl.lut.h b/ksvg/data/SVGMarkerElementImpl.lut.h
new file mode 100644
index 00000000..d89e711c
--- /dev/null
+++ b/ksvg/data/SVGMarkerElementImpl.lut.h
@@ -0,0 +1,90 @@
+/* Automatically generated from impl/SVGMarkerElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGMarkerElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "markerHeight\0"
+ "markerUnits\0"
+ "markerWidth\0"
+ "orientAngle\0"
+ "orientType\0"
+ "orient\0"
+ "refX\0"
+ "refY\0"
+};
+
+
+static const struct HashEntry SVGMarkerElementImpl__s_hashTableEntries[] = {
+ { 1, SVGMarkerElementImpl::MarkerHeight, DontDelete|ReadOnly, 0, 12 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 14, SVGMarkerElementImpl::MarkerUnits, DontDelete|ReadOnly, 0, -1 },
+ { 50, SVGMarkerElementImpl::OrientType, DontDelete|ReadOnly, 0, 13 },
+ { 68, SVGMarkerElementImpl::RefX, DontDelete|ReadOnly, 0, -1 },
+ { 73, SVGMarkerElementImpl::RefY, DontDelete|ReadOnly, 0, 11 },
+ { 26, SVGMarkerElementImpl::MarkerWidth, DontDelete|ReadOnly, 0, -1 },
+ { 38, SVGMarkerElementImpl::OrientAngle, DontDelete|ReadOnly, 0, -1 },
+ { 61, SVGMarkerElementImpl::Orient, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGMarkerElementImpl::s_hashTable = { 2, 14, SVGMarkerElementImpl__s_hashTableEntries, 11, SVGMarkerElementImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGMarkerElementImplProto__s_hashTableStrings[] = {
+ "\0"
+ "setOrientToAngle\0"
+ "setOrientToAuto\0"
+};
+
+
+static const struct HashEntry SVGMarkerElementImplProto__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 18, SVGMarkerElementImpl::SetOrientToAuto, DontDelete|Function, 0, 3 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGMarkerElementImpl::SetOrientToAngle, DontDelete|Function, 0, -1 }
+};
+
+const struct HashTable SVGMarkerElementImplProto::s_hashTable = { 2, 4, SVGMarkerElementImplProto__s_hashTableEntries, 3, SVGMarkerElementImplProto__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGMarkerElementImplConstructor__s_hashTableStrings[] = {
+ "\0"
+ "SVG_MARKERUNITS_USERSPACEONUSE\0"
+ "SVG_MARKERUNITS_STROKEWIDTH\0"
+ "SVG_MARKER_ORIENT_UNKNOWN\0"
+ "SVG_MARKERUNITS_UNKNOWN\0"
+ "SVG_MARKER_ORIENT_ANGLE\0"
+ "SVG_MARKER_ORIENT_AUTO\0"
+};
+
+
+static const struct HashEntry SVGMarkerElementImplConstructor__s_hashTableEntries[] = {
+ { 110, KSVG::SVG_MARKER_ORIENT_ANGLE, DontDelete|ReadOnly, 0, -1 },
+ { 1, KSVG::SVG_MARKERUNITS_USERSPACEONUSE, DontDelete|ReadOnly, 0, -1 },
+ { 86, KSVG::SVG_MARKERUNITS_UNKNOWN, DontDelete|ReadOnly, 0, -1 },
+ { 134, KSVG::SVG_MARKER_ORIENT_AUTO, DontDelete|ReadOnly, 0, -1 },
+ { 32, KSVG::SVG_MARKERUNITS_STROKEWIDTH, DontDelete|ReadOnly, 0, -1 },
+ { 60, KSVG::SVG_MARKER_ORIENT_UNKNOWN, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGMarkerElementImplConstructor::s_hashTable = { 2, 7, SVGMarkerElementImplConstructor__s_hashTableEntries, 7, SVGMarkerElementImplConstructor__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGMaskElementImpl.lut.h b/ksvg/data/SVGMaskElementImpl.lut.h
new file mode 100644
index 00000000..bcc32c39
--- /dev/null
+++ b/ksvg/data/SVGMaskElementImpl.lut.h
@@ -0,0 +1,31 @@
+/* Automatically generated from impl/SVGMaskElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGMaskElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "maskContentUnits\0"
+ "maskUnits\0"
+ "height\0"
+ "width\0"
+ "x\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGMaskElementImpl__s_hashTableEntries[] = {
+ { 18, SVGMaskElementImpl::MaskUnits, DontDelete|ReadOnly, 0, -1 },
+ { 41, SVGMaskElementImpl::X, DontDelete|ReadOnly, 0, -1 },
+ { 43, SVGMaskElementImpl::Y, DontDelete|ReadOnly, 0, -1 },
+ { 1, SVGMaskElementImpl::MaskContentUnits, DontDelete|ReadOnly, 0, 7 },
+ { 0, 0, 0, 0, -1 },
+ { 35, SVGMaskElementImpl::Width, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 28, SVGMaskElementImpl::Height, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGMaskElementImpl::s_hashTable = { 2, 8, SVGMaskElementImpl__s_hashTableEntries, 7, SVGMaskElementImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGMatrixImpl.lut.h b/ksvg/data/SVGMatrixImpl.lut.h
new file mode 100644
index 00000000..05b84cb3
--- /dev/null
+++ b/ksvg/data/SVGMatrixImpl.lut.h
@@ -0,0 +1,74 @@
+/* Automatically generated from impl/SVGMatrixImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGMatrixImpl__s_hashTableStrings[] = {
+ "\0"
+ "a\0"
+ "b\0"
+ "c\0"
+ "d\0"
+ "e\0"
+ "f\0"
+};
+
+
+static const struct HashEntry SVGMatrixImpl__s_hashTableEntries[] = {
+ { 3, SVGMatrixImpl::B, DontDelete, 0, -1 },
+ { 5, SVGMatrixImpl::C, DontDelete, 0, -1 },
+ { 7, SVGMatrixImpl::D, DontDelete, 0, -1 },
+ { 9, SVGMatrixImpl::E, DontDelete, 0, -1 },
+ { 11, SVGMatrixImpl::F, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGMatrixImpl::A, DontDelete, 0, -1 }
+};
+
+const struct HashTable SVGMatrixImpl::s_hashTable = { 2, 7, SVGMatrixImpl__s_hashTableEntries, 7, SVGMatrixImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGMatrixImplProto__s_hashTableStrings[] = {
+ "\0"
+ "rotateFromVector\0"
+ "scaleNonUniform\0"
+ "translate\0"
+ "multiply\0"
+ "inverse\0"
+ "rotate\0"
+ "flipX\0"
+ "flipY\0"
+ "scale\0"
+ "skewX\0"
+ "skewY\0"
+};
+
+
+static const struct HashEntry SVGMatrixImplProto__s_hashTableEntries[] = {
+ { 80, SVGMatrixImpl::Scale, DontDelete|Function, 1, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 61, SVGMatrixImpl::Rotate, DontDelete|Function, 1, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 18, SVGMatrixImpl::ScaleNonUniform, DontDelete|Function, 2, 14 },
+ { 1, SVGMatrixImpl::RotateFromVector, DontDelete|Function, 2, 15 },
+ { 53, SVGMatrixImpl::Inverse, DontDelete|Function, 0, 16 },
+ { 92, SVGMatrixImpl::SkewY, DontDelete|Function, 1, -1 },
+ { 44, SVGMatrixImpl::Multiply, DontDelete|Function, 1, 13 },
+ { 34, SVGMatrixImpl::Translate, DontDelete|Function, 2, -1 },
+ { 68, SVGMatrixImpl::FlipX, DontDelete|Function, 0, -1 },
+ { 74, SVGMatrixImpl::FlipY, DontDelete|Function, 0, -1 },
+ { 86, SVGMatrixImpl::SkewX, DontDelete|Function, 1, -1 }
+};
+
+const struct HashTable SVGMatrixImplProto::s_hashTable = { 2, 17, SVGMatrixImplProto__s_hashTableEntries, 13, SVGMatrixImplProto__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGNumberImpl.lut.h b/ksvg/data/SVGNumberImpl.lut.h
new file mode 100644
index 00000000..eefcb452
--- /dev/null
+++ b/ksvg/data/SVGNumberImpl.lut.h
@@ -0,0 +1,20 @@
+/* Automatically generated from impl/SVGNumberImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGNumberImpl__s_hashTableStrings[] = {
+ "\0"
+ "value\0"
+};
+
+
+static const struct HashEntry SVGNumberImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGNumberImpl::Value, DontDelete, 0, -1 }
+};
+
+const struct HashTable SVGNumberImpl::s_hashTable = { 2, 2, SVGNumberImpl__s_hashTableEntries, 2, SVGNumberImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGNumberListImpl.lut.h b/ksvg/data/SVGNumberListImpl.lut.h
new file mode 100644
index 00000000..59edbafd
--- /dev/null
+++ b/ksvg/data/SVGNumberListImpl.lut.h
@@ -0,0 +1,55 @@
+/* Automatically generated from impl/SVGNumberListImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGNumberListImpl__s_hashTableStrings[] = {
+ "\0"
+ "numberOfItems\0"
+};
+
+
+static const struct HashEntry SVGNumberListImpl__s_hashTableEntries[] = {
+ { 1, SVGListDefs::NumberOfItems, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGNumberListImpl::s_hashTable = { 2, 2, SVGNumberListImpl__s_hashTableEntries, 2, SVGNumberListImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGNumberListImplProto__s_hashTableStrings[] = {
+ "\0"
+ "insertItemBefore\0"
+ "replaceItem\0"
+ "appendItem\0"
+ "initialize\0"
+ "removeItem\0"
+ "getItem\0"
+ "clear\0"
+};
+
+
+static const struct HashEntry SVGNumberListImplProto__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 71, SVGListDefs::Clear, DontDelete|Function, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 63, SVGListDefs::GetItem, DontDelete|Function, 1, -1 },
+ { 1, SVGListDefs::InsertItemBefore, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 41, SVGListDefs::Initialize, DontDelete|Function, 1, -1 },
+ { 52, SVGListDefs::RemoveItem, DontDelete|Function, 1, 11 },
+ { 18, SVGListDefs::ReplaceItem, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 30, SVGListDefs::AppendItem, DontDelete|Function, 1, -1 }
+};
+
+const struct HashTable SVGNumberListImplProto::s_hashTable = { 2, 12, SVGNumberListImplProto__s_hashTableEntries, 11, SVGNumberListImplProto__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGPaintImpl.lut.h b/ksvg/data/SVGPaintImpl.lut.h
new file mode 100644
index 00000000..48c90b33
--- /dev/null
+++ b/ksvg/data/SVGPaintImpl.lut.h
@@ -0,0 +1,59 @@
+/* Automatically generated from impl/SVGPaintImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPaintImpl__s_hashTableStrings[] = {
+ "\0"
+ "paintType\0"
+ "uri\0"
+};
+
+
+static const struct HashEntry SVGPaintImpl__s_hashTableEntries[] = {
+ { 11, SVGPaintImpl::URI, DontDelete, 0, -1 },
+ { 1, SVGPaintImpl::PaintType, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGPaintImpl::s_hashTable = { 2, 3, SVGPaintImpl__s_hashTableEntries, 3, SVGPaintImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPaintImplConstructor__s_hashTableStrings[] = {
+ "\0"
+ "SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR\0"
+ "SVG_PAINTTYPE_URI_CURRENTCOLOR\0"
+ "SVG_PAINTTYPE_CURRENTCOLOR\0"
+ "SVG_PAINTTYPE_URI_RGBCOLOR\0"
+ "SVG_PAINTTYPE_RGBCOLOR\0"
+ "SVG_PAINTTYPE_URI_NONE\0"
+ "SVG_PAINTTYPE_UNKNOWN\0"
+ "SVG_PAINTTYPE_NONE\0"
+ "SVG_PAINTTYPE_URI\0"
+};
+
+
+static const struct HashEntry SVGPaintImplConstructor__s_hashTableEntries[] = {
+ { 145, KSVG::SVG_PAINTTYPE_URI_NONE, DontDelete|ReadOnly, 0, -1 },
+ { 95, KSVG::SVG_PAINTTYPE_URI_RGBCOLOR, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, KSVG::SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR, DontDelete|ReadOnly, 0, -1 },
+ { 68, KSVG::SVG_PAINTTYPE_CURRENTCOLOR, DontDelete|ReadOnly, 0, -1 },
+ { 190, KSVG::SVG_PAINTTYPE_NONE, DontDelete|ReadOnly, 0, -1 },
+ { 122, KSVG::SVG_PAINTTYPE_RGBCOLOR, DontDelete|ReadOnly, 0, 11 },
+ { 209, KSVG::SVG_PAINTTYPE_URI, DontDelete|ReadOnly, 0, -1 },
+ { 168, KSVG::SVG_PAINTTYPE_UNKNOWN, DontDelete|ReadOnly, 0, -1 },
+ { 37, KSVG::SVG_PAINTTYPE_URI_CURRENTCOLOR, DontDelete|ReadOnly, 0, -1 },
+ { 122, KSVG::SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGPaintImplConstructor::s_hashTable = { 2, 12, SVGPaintImplConstructor__s_hashTableEntries, 11, SVGPaintImplConstructor__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGPathElementImpl.lut.h b/ksvg/data/SVGPathElementImpl.lut.h
new file mode 100644
index 00000000..ccded107
--- /dev/null
+++ b/ksvg/data/SVGPathElementImpl.lut.h
@@ -0,0 +1,87 @@
+/* Automatically generated from impl/SVGPathElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPathElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "pathLength\0"
+ "d\0"
+};
+
+
+static const struct HashEntry SVGPathElementImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 12, SVGPathElementImpl::D, DontDelete|ReadOnly, 0, 3 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGPathElementImpl::PathLength, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGPathElementImpl::s_hashTable = { 2, 4, SVGPathElementImpl__s_hashTableEntries, 3, SVGPathElementImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPathElementImplProto__s_hashTableStrings[] = {
+ "\0"
+ "createSVGPathSegCurvetoQuadraticAbs\0"
+ "createSVGPathSegCurvetoQuadraticRel\0"
+ "createSVGPathSegLinetoHorizontalAbs\0"
+ "createSVGPathSegLinetoHorizontalRel\0"
+ "createSVGPathSegLinetoVerticalAbs\0"
+ "createSVGPathSegLinetoVerticalRel\0"
+ "createSVGPathSegCurvetoCubicAbs\0"
+ "createSVGPathSegCurvetoCubicRel\0"
+ "createSVGPathSegClosePath\0"
+ "createSVGPathSegLinetoAbs\0"
+ "createSVGPathSegLinetoRel\0"
+ "createSVGPathSegMovetoAbs\0"
+ "createSVGPathSegMovetoRel\0"
+ "createSVGPathSegArcAbs\0"
+ "createSVGPathSegArcRel\0"
+ "getPathSegAtLength\0"
+ "getPointAtLength\0"
+ "getTotalLength\0"
+};
+
+
+static const struct HashEntry SVGPathElementImplProto__s_hashTableEntries[] = {
+ { 472, SVGPathElementImpl::GetPointAtLength, DontDelete|Function, 1, -1 },
+ { 453, SVGPathElementImpl::GetPathSegAtLength, DontDelete|Function, 1, 23 },
+ { 0, 0, 0, 0, -1 },
+ { 355, SVGPathElementImpl::CreateSVGPathSegMovetoAbs, DontDelete|Function, 2, -1 },
+ { 1, SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticAbs, DontDelete|Function, 4, 28 },
+ { 430, SVGPathElementImpl::CreateSVGPathSegArcRel, DontDelete|Function, 7, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 109, SVGPathElementImpl::CreateSVGPathSegLinetoHorizontalRel, DontDelete|Function, 1, 25 },
+ { 0, 0, 0, 0, -1 },
+ { 303, SVGPathElementImpl::CreateSVGPathSegLinetoAbs, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 277, SVGPathElementImpl::CreateSVGPathSegClosePath, DontDelete|Function, 0, -1 },
+ { 245, SVGPathElementImpl::CreateSVGPathSegCurvetoCubicRel, DontDelete|Function, 6, 27 },
+ { 407, SVGPathElementImpl::CreateSVGPathSegArcAbs, DontDelete|Function, 7, -1 },
+ { 381, SVGPathElementImpl::CreateSVGPathSegMovetoRel, DontDelete|Function, 2, -1 },
+ { 37, SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticRel, DontDelete|Function, 4, 29 },
+ { 0, 0, 0, 0, -1 },
+ { 73, SVGPathElementImpl::CreateSVGPathSegLinetoHorizontalAbs, DontDelete|Function, 1, -1 },
+ { 489, SVGPathElementImpl::GetTotalLength, DontDelete|Function, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 179, SVGPathElementImpl::CreateSVGPathSegLinetoVerticalRel, DontDelete|Function, 1, -1 },
+ { 329, SVGPathElementImpl::CreateSVGPathSegLinetoRel, DontDelete|Function, 2, 24 },
+ { 213, SVGPathElementImpl::CreateSVGPathSegCurvetoCubicAbs, DontDelete|Function, 6, 26 },
+ { 145, SVGPathElementImpl::CreateSVGPathSegLinetoVerticalAbs, DontDelete|Function, 1, -1 },
+ { 213, SVGPathElementImpl::CreateSVGPathSegCurvetoCubicAbs, DontDelete|Function, 4, -1 },
+ { 245, SVGPathElementImpl::CreateSVGPathSegCurvetoCubicRel, DontDelete|Function, 4, -1 },
+ { 1, SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticAbs, DontDelete|Function, 2, -1 },
+ { 37, SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticRel, DontDelete|Function, 2, -1 }
+};
+
+const struct HashTable SVGPathElementImplProto::s_hashTable = { 2, 30, SVGPathElementImplProto__s_hashTableEntries, 23, SVGPathElementImplProto__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGPathSegArcImpl.lut.h b/ksvg/data/SVGPathSegArcImpl.lut.h
new file mode 100644
index 00000000..cfd8ffc8
--- /dev/null
+++ b/ksvg/data/SVGPathSegArcImpl.lut.h
@@ -0,0 +1,75 @@
+/* Automatically generated from impl/SVGPathSegArcImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPathSegArcAbsImpl__s_hashTableStrings[] = {
+ "\0"
+ "largeArcFlag\0"
+ "sweepFlag\0"
+ "angle\0"
+ "r1\0"
+ "r2\0"
+ "x\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGPathSegArcAbsImpl__s_hashTableEntries[] = {
+ { 38, SVGPathSegArcAbsImpl::Y, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 24, SVGPathSegArcAbsImpl::Angle, DontDelete, 0, 12 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 30, SVGPathSegArcAbsImpl::R1, DontDelete, 0, -1 },
+ { 36, SVGPathSegArcAbsImpl::X, DontDelete, 0, 11 },
+ { 33, SVGPathSegArcAbsImpl::R2, DontDelete, 0, -1 },
+ { 1, SVGPathSegArcAbsImpl::LargeArcFlag, DontDelete, 0, 13 },
+ { 14, SVGPathSegArcAbsImpl::SweepFlag, DontDelete, 0, -1 }
+};
+
+const struct HashTable SVGPathSegArcAbsImpl::s_hashTable = { 2, 14, SVGPathSegArcAbsImpl__s_hashTableEntries, 11, SVGPathSegArcAbsImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPathSegArcRelImpl__s_hashTableStrings[] = {
+ "\0"
+ "largeArcFlag\0"
+ "sweepFlag\0"
+ "angle\0"
+ "r1\0"
+ "r2\0"
+ "x\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGPathSegArcRelImpl__s_hashTableEntries[] = {
+ { 38, SVGPathSegArcRelImpl::Y, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 24, SVGPathSegArcRelImpl::Angle, DontDelete, 0, 12 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 30, SVGPathSegArcRelImpl::R1, DontDelete, 0, -1 },
+ { 36, SVGPathSegArcRelImpl::X, DontDelete, 0, 11 },
+ { 33, SVGPathSegArcRelImpl::R2, DontDelete, 0, -1 },
+ { 1, SVGPathSegArcRelImpl::LargeArcFlag, DontDelete, 0, 13 },
+ { 14, SVGPathSegArcRelImpl::SweepFlag, DontDelete, 0, -1 }
+};
+
+const struct HashTable SVGPathSegArcRelImpl::s_hashTable = { 2, 14, SVGPathSegArcRelImpl__s_hashTableEntries, 11, SVGPathSegArcRelImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGPathSegCurvetoCubicImpl.lut.h b/ksvg/data/SVGPathSegCurvetoCubicImpl.lut.h
new file mode 100644
index 00000000..dff7104b
--- /dev/null
+++ b/ksvg/data/SVGPathSegCurvetoCubicImpl.lut.h
@@ -0,0 +1,65 @@
+/* Automatically generated from impl/SVGPathSegCurvetoCubicImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPathSegCurvetoCubicAbsImpl__s_hashTableStrings[] = {
+ "\0"
+ "x1\0"
+ "x2\0"
+ "y1\0"
+ "y2\0"
+ "x\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGPathSegCurvetoCubicAbsImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 13, SVGPathSegCurvetoCubicAbsImpl::X, DontDelete, 0, 7 },
+ { 15, SVGPathSegCurvetoCubicAbsImpl::Y, DontDelete, 0, 8 },
+ { 10, SVGPathSegCurvetoCubicAbsImpl::Y2, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGPathSegCurvetoCubicAbsImpl::X1, DontDelete, 0, -1 },
+ { 7, SVGPathSegCurvetoCubicAbsImpl::Y1, DontDelete, 0, 9 },
+ { 4, SVGPathSegCurvetoCubicAbsImpl::X2, DontDelete, 0, -1 }
+};
+
+const struct HashTable SVGPathSegCurvetoCubicAbsImpl::s_hashTable = { 2, 10, SVGPathSegCurvetoCubicAbsImpl__s_hashTableEntries, 7, SVGPathSegCurvetoCubicAbsImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPathSegCurvetoCubicRelImpl__s_hashTableStrings[] = {
+ "\0"
+ "x1\0"
+ "x2\0"
+ "y1\0"
+ "y2\0"
+ "x\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGPathSegCurvetoCubicRelImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 13, SVGPathSegCurvetoCubicRelImpl::X, DontDelete, 0, 7 },
+ { 15, SVGPathSegCurvetoCubicRelImpl::Y, DontDelete, 0, 8 },
+ { 10, SVGPathSegCurvetoCubicRelImpl::Y2, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGPathSegCurvetoCubicRelImpl::X1, DontDelete, 0, -1 },
+ { 7, SVGPathSegCurvetoCubicRelImpl::Y1, DontDelete, 0, 9 },
+ { 4, SVGPathSegCurvetoCubicRelImpl::X2, DontDelete, 0, -1 }
+};
+
+const struct HashTable SVGPathSegCurvetoCubicRelImpl::s_hashTable = { 2, 10, SVGPathSegCurvetoCubicRelImpl__s_hashTableEntries, 7, SVGPathSegCurvetoCubicRelImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGPathSegCurvetoCubicSmoothImpl.lut.h b/ksvg/data/SVGPathSegCurvetoCubicSmoothImpl.lut.h
new file mode 100644
index 00000000..e84cd124
--- /dev/null
+++ b/ksvg/data/SVGPathSegCurvetoCubicSmoothImpl.lut.h
@@ -0,0 +1,55 @@
+/* Automatically generated from impl/SVGPathSegCurvetoCubicSmoothImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPathSegCurvetoCubicSmoothAbsImpl__s_hashTableStrings[] = {
+ "\0"
+ "x2\0"
+ "y2\0"
+ "x\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGPathSegCurvetoCubicSmoothAbsImpl__s_hashTableEntries[] = {
+ { 7, SVGPathSegCurvetoCubicSmoothAbsImpl::X, DontDelete, 0, 5 },
+ { 9, SVGPathSegCurvetoCubicSmoothAbsImpl::Y, DontDelete, 0, 6 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGPathSegCurvetoCubicSmoothAbsImpl::X2, DontDelete, 0, -1 },
+ { 4, SVGPathSegCurvetoCubicSmoothAbsImpl::Y2, DontDelete, 0, -1 }
+};
+
+const struct HashTable SVGPathSegCurvetoCubicSmoothAbsImpl::s_hashTable = { 2, 7, SVGPathSegCurvetoCubicSmoothAbsImpl__s_hashTableEntries, 5, SVGPathSegCurvetoCubicSmoothAbsImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPathSegCurvetoCubicSmoothRelImpl__s_hashTableStrings[] = {
+ "\0"
+ "x2\0"
+ "y2\0"
+ "x\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGPathSegCurvetoCubicSmoothRelImpl__s_hashTableEntries[] = {
+ { 7, SVGPathSegCurvetoCubicSmoothRelImpl::X, DontDelete, 0, 5 },
+ { 9, SVGPathSegCurvetoCubicSmoothRelImpl::Y, DontDelete, 0, 6 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGPathSegCurvetoCubicSmoothRelImpl::X2, DontDelete, 0, -1 },
+ { 4, SVGPathSegCurvetoCubicSmoothRelImpl::Y2, DontDelete, 0, -1 }
+};
+
+const struct HashTable SVGPathSegCurvetoCubicSmoothRelImpl::s_hashTable = { 2, 7, SVGPathSegCurvetoCubicSmoothRelImpl__s_hashTableEntries, 5, SVGPathSegCurvetoCubicSmoothRelImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGPathSegCurvetoQuadraticImpl.lut.h b/ksvg/data/SVGPathSegCurvetoQuadraticImpl.lut.h
new file mode 100644
index 00000000..8513fdd5
--- /dev/null
+++ b/ksvg/data/SVGPathSegCurvetoQuadraticImpl.lut.h
@@ -0,0 +1,53 @@
+/* Automatically generated from impl/SVGPathSegCurvetoQuadraticImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPathSegCurvetoQuadraticAbsImpl__s_hashTableStrings[] = {
+ "\0"
+ "x1\0"
+ "y1\0"
+ "x\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGPathSegCurvetoQuadraticAbsImpl__s_hashTableEntries[] = {
+ { 7, SVGPathSegCurvetoQuadraticAbsImpl::X, DontDelete, 0, 5 },
+ { 9, SVGPathSegCurvetoQuadraticAbsImpl::Y, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGPathSegCurvetoQuadraticAbsImpl::X1, DontDelete, 0, -1 },
+ { 4, SVGPathSegCurvetoQuadraticAbsImpl::Y1, DontDelete, 0, -1 }
+};
+
+const struct HashTable SVGPathSegCurvetoQuadraticAbsImpl::s_hashTable = { 2, 6, SVGPathSegCurvetoQuadraticAbsImpl__s_hashTableEntries, 5, SVGPathSegCurvetoQuadraticAbsImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPathSegCurvetoQuadraticRelImpl__s_hashTableStrings[] = {
+ "\0"
+ "x1\0"
+ "y1\0"
+ "x\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGPathSegCurvetoQuadraticRelImpl__s_hashTableEntries[] = {
+ { 7, SVGPathSegCurvetoQuadraticRelImpl::X, DontDelete, 0, 5 },
+ { 9, SVGPathSegCurvetoQuadraticRelImpl::Y, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGPathSegCurvetoQuadraticRelImpl::X1, DontDelete, 0, -1 },
+ { 4, SVGPathSegCurvetoQuadraticRelImpl::Y1, DontDelete, 0, -1 }
+};
+
+const struct HashTable SVGPathSegCurvetoQuadraticRelImpl::s_hashTable = { 2, 6, SVGPathSegCurvetoQuadraticRelImpl__s_hashTableEntries, 5, SVGPathSegCurvetoQuadraticRelImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGPathSegCurvetoQuadraticSmoothImpl.lut.h b/ksvg/data/SVGPathSegCurvetoQuadraticSmoothImpl.lut.h
new file mode 100644
index 00000000..6622c341
--- /dev/null
+++ b/ksvg/data/SVGPathSegCurvetoQuadraticSmoothImpl.lut.h
@@ -0,0 +1,43 @@
+/* Automatically generated from impl/SVGPathSegCurvetoQuadraticSmoothImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPathSegCurvetoQuadraticSmoothAbsImpl__s_hashTableStrings[] = {
+ "\0"
+ "x\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGPathSegCurvetoQuadraticSmoothAbsImpl__s_hashTableEntries[] = {
+ { 1, SVGPathSegCurvetoQuadraticSmoothAbsImpl::X, DontDelete, 0, -1 },
+ { 3, SVGPathSegCurvetoQuadraticSmoothAbsImpl::Y, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGPathSegCurvetoQuadraticSmoothAbsImpl::s_hashTable = { 2, 3, SVGPathSegCurvetoQuadraticSmoothAbsImpl__s_hashTableEntries, 3, SVGPathSegCurvetoQuadraticSmoothAbsImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPathSegCurvetoQuadraticSmoothRelImpl__s_hashTableStrings[] = {
+ "\0"
+ "x\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGPathSegCurvetoQuadraticSmoothRelImpl__s_hashTableEntries[] = {
+ { 1, SVGPathSegCurvetoQuadraticSmoothRelImpl::X, DontDelete, 0, -1 },
+ { 3, SVGPathSegCurvetoQuadraticSmoothRelImpl::Y, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGPathSegCurvetoQuadraticSmoothRelImpl::s_hashTable = { 2, 3, SVGPathSegCurvetoQuadraticSmoothRelImpl__s_hashTableEntries, 3, SVGPathSegCurvetoQuadraticSmoothRelImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGPathSegImpl.lut.h b/ksvg/data/SVGPathSegImpl.lut.h
new file mode 100644
index 00000000..94436a77
--- /dev/null
+++ b/ksvg/data/SVGPathSegImpl.lut.h
@@ -0,0 +1,88 @@
+/* Automatically generated from impl/SVGPathSegImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPathSegImpl__s_hashTableStrings[] = {
+ "\0"
+ "pathSegTypeAsLetter\0"
+ "pathSegType\0"
+};
+
+
+static const struct HashEntry SVGPathSegImpl__s_hashTableEntries[] = {
+ { 21, SVGPathSegImpl::PathSegType, DontDelete|ReadOnly, 0, 3 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGPathSegImpl::PathSegTypeAsLetter, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGPathSegImpl::s_hashTable = { 2, 4, SVGPathSegImpl__s_hashTableEntries, 3, SVGPathSegImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPathSegImplConstructor__s_hashTableStrings[] = {
+ "\0"
+ "PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS\0"
+ "PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL\0"
+ "PATHSEG_CURVETO_CUBIC_SMOOTH_ABS\0"
+ "PATHSEG_CURVETO_CUBIC_SMOOTH_REL\0"
+ "PATHSEG_CURVETO_QUADRATIC_ABS\0"
+ "PATHSEG_CURVETO_QUADRATIC_REL\0"
+ "PATHSEG_LINETO_HORIZONTAL_ABS\0"
+ "PATHSEG_LINETO_HORIZONTAL_REL\0"
+ "PATHSEG_LINETO_VERTICAL_ABS\0"
+ "PATHSEG_LINETO_VERTICAL_REL\0"
+ "PATHSEG_CURVETO_CUBIC_ABS\0"
+ "PATHSEG_CURVETO_CUBIC_REL\0"
+ "PATHSEG_LINETO_ABS\0"
+ "PATHSEG_LINETO_REL\0"
+ "PATHSEG_MOVETO_ABS\0"
+ "PATHSEG_MOVETO_REL\0"
+ "PATHSEG_CLOSEPATH\0"
+ "PATHSEG_ARC_ABS\0"
+ "PATHSEG_ARC_REL\0"
+ "PATHSEG_UNKNOWN\0"
+};
+
+
+static const struct HashEntry SVGPathSegImplConstructor__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 317, KSVG::PATHSEG_CURVETO_CUBIC_ABS, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 171, KSVG::PATHSEG_CURVETO_QUADRATIC_REL, DontDelete|ReadOnly, 0, 27 },
+ { 479, KSVG::PATHSEG_ARC_REL, DontDelete|ReadOnly, 0, -1 },
+ { 495, KSVG::PATHSEG_UNKNOWN, DontDelete|ReadOnly, 0, 23 },
+ { 369, KSVG::PATHSEG_LINETO_ABS, DontDelete|ReadOnly, 0, -1 },
+ { 108, KSVG::PATHSEG_CURVETO_CUBIC_SMOOTH_REL, DontDelete|ReadOnly, 0, 28 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 426, KSVG::PATHSEG_MOVETO_REL, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 343, KSVG::PATHSEG_CURVETO_CUBIC_REL, DontDelete|ReadOnly, 0, 24 },
+ { 463, KSVG::PATHSEG_ARC_ABS, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 75, KSVG::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS, DontDelete|ReadOnly, 0, -1 },
+ { 231, KSVG::PATHSEG_LINETO_HORIZONTAL_REL, DontDelete|ReadOnly, 0, -1 },
+ { 388, KSVG::PATHSEG_LINETO_REL, DontDelete|ReadOnly, 0, -1 },
+ { 38, KSVG::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL, DontDelete|ReadOnly, 0, -1 },
+ { 407, KSVG::PATHSEG_MOVETO_ABS, DontDelete|ReadOnly, 0, -1 },
+ { 445, KSVG::PATHSEG_CLOSEPATH, DontDelete|ReadOnly, 0, 25 },
+ { 141, KSVG::PATHSEG_CURVETO_QUADRATIC_ABS, DontDelete|ReadOnly, 0, 26 },
+ { 201, KSVG::PATHSEG_LINETO_HORIZONTAL_ABS, DontDelete|ReadOnly, 0, -1 },
+ { 261, KSVG::PATHSEG_LINETO_VERTICAL_ABS, DontDelete|ReadOnly, 0, -1 },
+ { 289, KSVG::PATHSEG_LINETO_VERTICAL_REL, DontDelete|ReadOnly, 0, -1 },
+ { 1, KSVG::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGPathSegImplConstructor::s_hashTable = { 2, 29, SVGPathSegImplConstructor__s_hashTableEntries, 23, SVGPathSegImplConstructor__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGPathSegLinetoHorizontalImpl.lut.h b/ksvg/data/SVGPathSegLinetoHorizontalImpl.lut.h
new file mode 100644
index 00000000..768ac3a3
--- /dev/null
+++ b/ksvg/data/SVGPathSegLinetoHorizontalImpl.lut.h
@@ -0,0 +1,39 @@
+/* Automatically generated from impl/SVGPathSegLinetoHorizontalImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPathSegLinetoHorizontalAbsImpl__s_hashTableStrings[] = {
+ "\0"
+ "x\0"
+};
+
+
+static const struct HashEntry SVGPathSegLinetoHorizontalAbsImpl__s_hashTableEntries[] = {
+ { 1, SVGPathSegLinetoHorizontalAbsImpl::X, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGPathSegLinetoHorizontalAbsImpl::s_hashTable = { 2, 2, SVGPathSegLinetoHorizontalAbsImpl__s_hashTableEntries, 2, SVGPathSegLinetoHorizontalAbsImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPathSegLinetoHorizontalRelImpl__s_hashTableStrings[] = {
+ "\0"
+ "x\0"
+};
+
+
+static const struct HashEntry SVGPathSegLinetoHorizontalRelImpl__s_hashTableEntries[] = {
+ { 1, SVGPathSegLinetoHorizontalRelImpl::X, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGPathSegLinetoHorizontalRelImpl::s_hashTable = { 2, 2, SVGPathSegLinetoHorizontalRelImpl__s_hashTableEntries, 2, SVGPathSegLinetoHorizontalRelImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGPathSegLinetoImpl.lut.h b/ksvg/data/SVGPathSegLinetoImpl.lut.h
new file mode 100644
index 00000000..5d754cdf
--- /dev/null
+++ b/ksvg/data/SVGPathSegLinetoImpl.lut.h
@@ -0,0 +1,43 @@
+/* Automatically generated from impl/SVGPathSegLinetoImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPathSegLinetoAbsImpl__s_hashTableStrings[] = {
+ "\0"
+ "x\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGPathSegLinetoAbsImpl__s_hashTableEntries[] = {
+ { 1, SVGPathSegLinetoAbsImpl::X, DontDelete, 0, -1 },
+ { 3, SVGPathSegLinetoAbsImpl::Y, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGPathSegLinetoAbsImpl::s_hashTable = { 2, 3, SVGPathSegLinetoAbsImpl__s_hashTableEntries, 3, SVGPathSegLinetoAbsImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPathSegLinetoRelImpl__s_hashTableStrings[] = {
+ "\0"
+ "x\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGPathSegLinetoRelImpl__s_hashTableEntries[] = {
+ { 1, SVGPathSegLinetoRelImpl::X, DontDelete, 0, -1 },
+ { 3, SVGPathSegLinetoRelImpl::Y, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGPathSegLinetoRelImpl::s_hashTable = { 2, 3, SVGPathSegLinetoRelImpl__s_hashTableEntries, 3, SVGPathSegLinetoRelImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGPathSegLinetoVerticalImpl.lut.h b/ksvg/data/SVGPathSegLinetoVerticalImpl.lut.h
new file mode 100644
index 00000000..1a48baaa
--- /dev/null
+++ b/ksvg/data/SVGPathSegLinetoVerticalImpl.lut.h
@@ -0,0 +1,39 @@
+/* Automatically generated from impl/SVGPathSegLinetoVerticalImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPathSegLinetoVerticalAbsImpl__s_hashTableStrings[] = {
+ "\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGPathSegLinetoVerticalAbsImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGPathSegLinetoVerticalAbsImpl::Y, DontDelete, 0, -1 }
+};
+
+const struct HashTable SVGPathSegLinetoVerticalAbsImpl::s_hashTable = { 2, 2, SVGPathSegLinetoVerticalAbsImpl__s_hashTableEntries, 2, SVGPathSegLinetoVerticalAbsImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPathSegLinetoVerticalRelImpl__s_hashTableStrings[] = {
+ "\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGPathSegLinetoVerticalRelImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGPathSegLinetoVerticalRelImpl::Y, DontDelete, 0, -1 }
+};
+
+const struct HashTable SVGPathSegLinetoVerticalRelImpl::s_hashTable = { 2, 2, SVGPathSegLinetoVerticalRelImpl__s_hashTableEntries, 2, SVGPathSegLinetoVerticalRelImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGPathSegListImpl.lut.h b/ksvg/data/SVGPathSegListImpl.lut.h
new file mode 100644
index 00000000..8c4df29a
--- /dev/null
+++ b/ksvg/data/SVGPathSegListImpl.lut.h
@@ -0,0 +1,55 @@
+/* Automatically generated from impl/SVGPathSegListImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPathSegListImpl__s_hashTableStrings[] = {
+ "\0"
+ "numberOfItems\0"
+};
+
+
+static const struct HashEntry SVGPathSegListImpl__s_hashTableEntries[] = {
+ { 1, SVGListDefs::NumberOfItems, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGPathSegListImpl::s_hashTable = { 2, 2, SVGPathSegListImpl__s_hashTableEntries, 2, SVGPathSegListImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPathSegListImplProto__s_hashTableStrings[] = {
+ "\0"
+ "insertItemBefore\0"
+ "replaceItem\0"
+ "appendItem\0"
+ "initialize\0"
+ "removeItem\0"
+ "getItem\0"
+ "clear\0"
+};
+
+
+static const struct HashEntry SVGPathSegListImplProto__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 71, SVGListDefs::Clear, DontDelete|Function, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 63, SVGListDefs::GetItem, DontDelete|Function, 1, -1 },
+ { 1, SVGListDefs::InsertItemBefore, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 41, SVGListDefs::Initialize, DontDelete|Function, 1, -1 },
+ { 52, SVGListDefs::RemoveItem, DontDelete|Function, 1, 11 },
+ { 18, SVGListDefs::ReplaceItem, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 30, SVGListDefs::AppendItem, DontDelete|Function, 1, -1 }
+};
+
+const struct HashTable SVGPathSegListImplProto::s_hashTable = { 2, 12, SVGPathSegListImplProto__s_hashTableEntries, 11, SVGPathSegListImplProto__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGPathSegMovetoImpl.lut.h b/ksvg/data/SVGPathSegMovetoImpl.lut.h
new file mode 100644
index 00000000..60f1c70f
--- /dev/null
+++ b/ksvg/data/SVGPathSegMovetoImpl.lut.h
@@ -0,0 +1,43 @@
+/* Automatically generated from impl/SVGPathSegMovetoImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPathSegMovetoAbsImpl__s_hashTableStrings[] = {
+ "\0"
+ "x\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGPathSegMovetoAbsImpl__s_hashTableEntries[] = {
+ { 1, SVGPathSegMovetoAbsImpl::X, DontDelete, 0, -1 },
+ { 3, SVGPathSegMovetoAbsImpl::Y, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGPathSegMovetoAbsImpl::s_hashTable = { 2, 3, SVGPathSegMovetoAbsImpl__s_hashTableEntries, 3, SVGPathSegMovetoAbsImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPathSegMovetoRelImpl__s_hashTableStrings[] = {
+ "\0"
+ "x\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGPathSegMovetoRelImpl__s_hashTableEntries[] = {
+ { 1, SVGPathSegMovetoRelImpl::X, DontDelete, 0, -1 },
+ { 3, SVGPathSegMovetoRelImpl::Y, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGPathSegMovetoRelImpl::s_hashTable = { 2, 3, SVGPathSegMovetoRelImpl__s_hashTableEntries, 3, SVGPathSegMovetoRelImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGPatternElementImpl.lut.h b/ksvg/data/SVGPatternElementImpl.lut.h
new file mode 100644
index 00000000..dc5b4527
--- /dev/null
+++ b/ksvg/data/SVGPatternElementImpl.lut.h
@@ -0,0 +1,37 @@
+/* Automatically generated from impl/SVGPatternElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPatternElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "patternContentUnits\0"
+ "patternTransform\0"
+ "patternUnits\0"
+ "height\0"
+ "width\0"
+ "x\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGPatternElementImpl__s_hashTableEntries[] = {
+ { 66, SVGPatternElementImpl::Y, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGPatternElementImpl::PatternContentUnits, DontDelete|ReadOnly, 0, -1 },
+ { 58, SVGPatternElementImpl::Width, DontDelete|ReadOnly, 0, -1 },
+ { 51, SVGPatternElementImpl::Height, DontDelete|ReadOnly, 0, 12 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 64, SVGPatternElementImpl::X, DontDelete|ReadOnly, 0, 11 },
+ { 38, SVGPatternElementImpl::PatternUnits, DontDelete|ReadOnly, 0, -1 },
+ { 21, SVGPatternElementImpl::PatternTransform, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGPatternElementImpl::s_hashTable = { 2, 13, SVGPatternElementImpl__s_hashTableEntries, 11, SVGPatternElementImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGPointImpl.lut.h b/ksvg/data/SVGPointImpl.lut.h
new file mode 100644
index 00000000..d024c947
--- /dev/null
+++ b/ksvg/data/SVGPointImpl.lut.h
@@ -0,0 +1,22 @@
+/* Automatically generated from impl/SVGPointImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPointImpl__s_hashTableStrings[] = {
+ "\0"
+ "x\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGPointImpl__s_hashTableEntries[] = {
+ { 1, SVGPointImpl::X, DontDelete, 0, -1 },
+ { 3, SVGPointImpl::Y, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGPointImpl::s_hashTable = { 2, 3, SVGPointImpl__s_hashTableEntries, 3, SVGPointImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGPointListImpl.lut.h b/ksvg/data/SVGPointListImpl.lut.h
new file mode 100644
index 00000000..f483be1e
--- /dev/null
+++ b/ksvg/data/SVGPointListImpl.lut.h
@@ -0,0 +1,55 @@
+/* Automatically generated from impl/SVGPointListImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPointListImpl__s_hashTableStrings[] = {
+ "\0"
+ "numberOfItems\0"
+};
+
+
+static const struct HashEntry SVGPointListImpl__s_hashTableEntries[] = {
+ { 1, SVGListDefs::NumberOfItems, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGPointListImpl::s_hashTable = { 2, 2, SVGPointListImpl__s_hashTableEntries, 2, SVGPointListImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPointListImplProto__s_hashTableStrings[] = {
+ "\0"
+ "insertItemBefore\0"
+ "replaceItem\0"
+ "appendItem\0"
+ "initialize\0"
+ "removeItem\0"
+ "getItem\0"
+ "clear\0"
+};
+
+
+static const struct HashEntry SVGPointListImplProto__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 71, SVGListDefs::Clear, DontDelete|Function, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 63, SVGListDefs::GetItem, DontDelete|Function, 1, -1 },
+ { 1, SVGListDefs::InsertItemBefore, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 41, SVGListDefs::Initialize, DontDelete|Function, 1, -1 },
+ { 52, SVGListDefs::RemoveItem, DontDelete|Function, 1, 11 },
+ { 18, SVGListDefs::ReplaceItem, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 30, SVGListDefs::AppendItem, DontDelete|Function, 1, -1 }
+};
+
+const struct HashTable SVGPointListImplProto::s_hashTable = { 2, 12, SVGPointListImplProto__s_hashTableEntries, 11, SVGPointListImplProto__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGPreserveAspectRatioImpl.lut.h b/ksvg/data/SVGPreserveAspectRatioImpl.lut.h
new file mode 100644
index 00000000..3b73e594
--- /dev/null
+++ b/ksvg/data/SVGPreserveAspectRatioImpl.lut.h
@@ -0,0 +1,73 @@
+/* Automatically generated from impl/SVGPreserveAspectRatioImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPreserveAspectRatioImpl__s_hashTableStrings[] = {
+ "\0"
+ "meetOrSlice\0"
+ "align\0"
+};
+
+
+static const struct HashEntry SVGPreserveAspectRatioImpl__s_hashTableEntries[] = {
+ { 1, SVGPreserveAspectRatioImpl::MeetOrSlice, DontDelete, 0, -1 },
+ { 13, SVGPreserveAspectRatioImpl::Align, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGPreserveAspectRatioImpl::s_hashTable = { 2, 3, SVGPreserveAspectRatioImpl__s_hashTableEntries, 3, SVGPreserveAspectRatioImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGPreserveAspectRatioImplConstructor__s_hashTableStrings[] = {
+ "\0"
+ "SVG_PRESERVEASPECTRATIO_XMAXYMAX\0"
+ "SVG_PRESERVEASPECTRATIO_XMAXYMID\0"
+ "SVG_PRESERVEASPECTRATIO_XMAXYMIN\0"
+ "SVG_PRESERVEASPECTRATIO_XMIDYMAX\0"
+ "SVG_PRESERVEASPECTRATIO_XMIDYMID\0"
+ "SVG_PRESERVEASPECTRATIO_XMIDYMIN\0"
+ "SVG_PRESERVEASPECTRATIO_XMINYMAX\0"
+ "SVG_PRESERVEASPECTRATIO_XMINYMID\0"
+ "SVG_PRESERVEASPECTRATIO_XMINYMIN\0"
+ "SVG_PRESERVEASPECTRATIO_UNKNOWN\0"
+ "SVG_PRESERVEASPECTRATIO_NONE\0"
+ "SVG_MEETORSLICE_UNKNOWN\0"
+ "SVG_MEETORSLICE_SLICE\0"
+ "SVG_MEETORSLICE_MEET\0"
+};
+
+
+static const struct HashEntry SVGPreserveAspectRatioImplConstructor__s_hashTableEntries[] = {
+ { 67, KSVG::SVG_PRESERVEASPECTRATIO_XMAXYMIN, DontDelete|ReadOnly, 0, 18 },
+ { 0, 0, 0, 0, -1 },
+ { 1, KSVG::SVG_PRESERVEASPECTRATIO_XMAXYMAX, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 166, KSVG::SVG_PRESERVEASPECTRATIO_XMIDYMIN, DontDelete|ReadOnly, 0, 17 },
+ { 0, 0, 0, 0, -1 },
+ { 34, KSVG::SVG_PRESERVEASPECTRATIO_XMAXYMID, DontDelete|ReadOnly, 0, 19 },
+ { 0, 0, 0, 0, -1 },
+ { 330, KSVG::SVG_PRESERVEASPECTRATIO_NONE, DontDelete|ReadOnly, 0, -1 },
+ { 298, KSVG::SVG_PRESERVEASPECTRATIO_UNKNOWN, DontDelete|ReadOnly, 0, 20 },
+ { 383, KSVG::SVG_MEETORSLICE_SLICE, DontDelete|ReadOnly, 0, -1 },
+ { 133, KSVG::SVG_PRESERVEASPECTRATIO_XMIDYMID, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 265, KSVG::SVG_PRESERVEASPECTRATIO_XMINYMIN, DontDelete|ReadOnly, 0, -1 },
+ { 359, KSVG::SVG_MEETORSLICE_UNKNOWN, DontDelete|ReadOnly, 0, -1 },
+ { 232, KSVG::SVG_PRESERVEASPECTRATIO_XMINYMID, DontDelete|ReadOnly, 0, -1 },
+ { 199, KSVG::SVG_PRESERVEASPECTRATIO_XMINYMAX, DontDelete|ReadOnly, 0, -1 },
+ { 100, KSVG::SVG_PRESERVEASPECTRATIO_XMIDYMAX, DontDelete|ReadOnly, 0, -1 },
+ { 405, KSVG::SVG_MEETORSLICE_MEET, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGPreserveAspectRatioImplConstructor::s_hashTable = { 2, 21, SVGPreserveAspectRatioImplConstructor__s_hashTableEntries, 17, SVGPreserveAspectRatioImplConstructor__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGRadialGradientElementImpl.lut.h b/ksvg/data/SVGRadialGradientElementImpl.lut.h
new file mode 100644
index 00000000..ab0f702e
--- /dev/null
+++ b/ksvg/data/SVGRadialGradientElementImpl.lut.h
@@ -0,0 +1,30 @@
+/* Automatically generated from impl/SVGRadialGradientElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGRadialGradientElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "cx\0"
+ "cy\0"
+ "fx\0"
+ "fy\0"
+ "r\0"
+};
+
+
+static const struct HashEntry SVGRadialGradientElementImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGRadialGradientElementImpl::Cx, DontDelete|ReadOnly, 0, 7 },
+ { 4, SVGRadialGradientElementImpl::Cy, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 7, SVGRadialGradientElementImpl::Fx, DontDelete|ReadOnly, 0, -1 },
+ { 10, SVGRadialGradientElementImpl::Fy, DontDelete|ReadOnly, 0, -1 },
+ { 13, SVGRadialGradientElementImpl::R, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGRadialGradientElementImpl::s_hashTable = { 2, 8, SVGRadialGradientElementImpl__s_hashTableEntries, 7, SVGRadialGradientElementImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGRectElementImpl.lut.h b/ksvg/data/SVGRectElementImpl.lut.h
new file mode 100644
index 00000000..d51c06c9
--- /dev/null
+++ b/ksvg/data/SVGRectElementImpl.lut.h
@@ -0,0 +1,29 @@
+/* Automatically generated from impl/SVGRectElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGRectElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "height\0"
+ "width\0"
+ "rx\0"
+ "ry\0"
+};
+
+
+static const struct HashEntry SVGRectElementImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 15, SVGRectElementImpl::X, DontDelete|ReadOnly, 0, -1 },
+ { 18, SVGRectElementImpl::Y, DontDelete|ReadOnly, 0, -1 },
+ { 1, SVGRectElementImpl::Height, DontDelete|ReadOnly, 0, 7 },
+ { 17, SVGRectElementImpl::Ry, DontDelete|ReadOnly, 0, -1 },
+ { 8, SVGRectElementImpl::Width, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 14, SVGRectElementImpl::Rx, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGRectElementImpl::s_hashTable = { 2, 8, SVGRectElementImpl__s_hashTableEntries, 7, SVGRectElementImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGRectImpl.lut.h b/ksvg/data/SVGRectImpl.lut.h
new file mode 100644
index 00000000..439835bc
--- /dev/null
+++ b/ksvg/data/SVGRectImpl.lut.h
@@ -0,0 +1,26 @@
+/* Automatically generated from impl/SVGRectImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGRectImpl__s_hashTableStrings[] = {
+ "\0"
+ "height\0"
+ "width\0"
+ "x\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGRectImpl__s_hashTableEntries[] = {
+ { 14, SVGRectImpl::X, DontDelete, 0, -1 },
+ { 16, SVGRectImpl::Y, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGRectImpl::Height, DontDelete, 0, -1 },
+ { 8, SVGRectImpl::Width, DontDelete, 0, -1 }
+};
+
+const struct HashTable SVGRectImpl::s_hashTable = { 2, 5, SVGRectImpl__s_hashTableEntries, 5, SVGRectImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGSVGElementImpl.lut.h b/ksvg/data/SVGSVGElementImpl.lut.h
new file mode 100644
index 00000000..530095f6
--- /dev/null
+++ b/ksvg/data/SVGSVGElementImpl.lut.h
@@ -0,0 +1,136 @@
+/* Automatically generated from impl/SVGSVGElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGSVGElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "screenPixelToMillimeterX\0"
+ "screenPixelToMillimeterY\0"
+ "pixelUnitToMillimeterX\0"
+ "pixelUnitToMillimeterY\0"
+ "contentScriptType\0"
+ "contentStyleType\0"
+ "currentTranslate\0"
+ "useCurrentView\0"
+ "currentScale\0"
+ "onresize\0"
+ "onscroll\0"
+ "onunload\0"
+ "viewport\0"
+ "onerror\0"
+ "height\0"
+ "onzoom\0"
+ "width\0"
+ "x\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGSVGElementImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 186, SVGSVGElementImpl::OnScroll, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 241, SVGSVGElementImpl::X, DontDelete|ReadOnly, 0, 27 },
+ { 243, SVGSVGElementImpl::Y, DontDelete|ReadOnly, 0, -1 },
+ { 228, SVGSVGElementImpl::OnZoom, DontDelete, 0, -1 },
+ { 115, SVGSVGElementImpl::ContentStyleType, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 149, SVGSVGElementImpl::UseCurrentView, DontDelete, 0, 24 },
+ { 221, SVGSVGElementImpl::Height, DontDelete|ReadOnly, 0, 23 },
+ { 74, SVGSVGElementImpl::PixelUnitToMillimeterY, DontDelete|ReadOnly, 0, 25 },
+ { 0, 0, 0, 0, -1 },
+ { 235, SVGSVGElementImpl::Width, DontDelete|ReadOnly, 0, -1 },
+ { 97, SVGSVGElementImpl::ContentScriptType, DontDelete, 0, 26 },
+ { 164, SVGSVGElementImpl::CurrentScale, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGSVGElementImpl::ScreenPixelToMillimeterX, DontDelete|ReadOnly, 0, -1 },
+ { 26, SVGSVGElementImpl::ScreenPixelToMillimeterY, DontDelete|ReadOnly, 0, -1 },
+ { 204, SVGSVGElementImpl::Viewport, DontDelete|ReadOnly, 0, -1 },
+ { 51, SVGSVGElementImpl::PixelUnitToMillimeterX, DontDelete|ReadOnly, 0, -1 },
+ { 132, SVGSVGElementImpl::CurrentTranslate, DontDelete|ReadOnly, 0, -1 },
+ { 195, SVGSVGElementImpl::OnUnload, DontDelete, 0, -1 },
+ { 213, SVGSVGElementImpl::OnError, DontDelete, 0, -1 },
+ { 177, SVGSVGElementImpl::OnResize, DontDelete, 0, -1 }
+};
+
+const struct HashTable SVGSVGElementImpl::s_hashTable = { 2, 28, SVGSVGElementImpl__s_hashTableEntries, 23, SVGSVGElementImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGSVGElementImplProto__s_hashTableStrings[] = {
+ "\0"
+ "createSVGTransformFromMatrix\0"
+ "getIntersectionList\0"
+ "createSVGTransform\0"
+ "unsuspendRedrawAll\0"
+ "checkIntersection\0"
+ "unpauseAnimations\0"
+ "animationsPaused\0"
+ "getEnclosureList\0"
+ "createSVGLength\0"
+ "createSVGMatrix\0"
+ "createSVGNumber\0"
+ "unsuspendRedraw\0"
+ "checkEnclosure\0"
+ "createSVGAngle\0"
+ "createSVGPoint\0"
+ "getCurrentTime\0"
+ "getElementById\0"
+ "setCurrentTime\0"
+ "createSVGRect\0"
+ "deselectAll\0"
+ "forceRedraw\0"
+};
+
+
+static const struct HashEntry SVGSVGElementImplProto__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 30, SVGSVGElementImpl::GetIntersectionList, DontDelete|Function, 2, 34 },
+ { 124, SVGSVGElementImpl::AnimationsPaused, DontDelete|Function, 0, -1 },
+ { 222, SVGSVGElementImpl::CheckEnclosure, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 190, SVGSVGElementImpl::CreateSVGNumber, DontDelete|Function, 0, 30 },
+ { 0, 0, 0, 0, -1 },
+ { 267, SVGSVGElementImpl::GetCurrentTime, DontDelete|Function, 0, -1 },
+ { 338, SVGSVGElementImpl::ForceRedraw, DontDelete|Function, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 88, SVGSVGElementImpl::CheckIntersection, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 106, SVGSVGElementImpl::UnpauseAnimations, DontDelete|Function, 0, -1 },
+ { 1, SVGSVGElementImpl::CreateSVGTransformFromMatrix, DontDelete|Function, 1, 29 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 174, SVGSVGElementImpl::CreateSVGMatrix, DontDelete|Function, 0, -1 },
+ { 312, SVGSVGElementImpl::CreateSVGRect, DontDelete|Function, 0, 31 },
+ { 208, SVGSVGElementImpl::SuspendRedraw, DontDelete|Function, 1, 32 },
+ { 237, SVGSVGElementImpl::CreateSVGAngle, DontDelete|Function, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 141, SVGSVGElementImpl::GetEnclosureList, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 50, SVGSVGElementImpl::CreateSVGTransform, DontDelete|Function, 0, -1 },
+ { 252, SVGSVGElementImpl::CreateSVGPoint, DontDelete|Function, 0, -1 },
+ { 158, SVGSVGElementImpl::CreateSVGLength, DontDelete|Function, 0, -1 },
+ { 206, SVGSVGElementImpl::UnsuspendRedraw, DontDelete|Function, 1, -1 },
+ { 69, SVGSVGElementImpl::UnsuspendRedrawAll, DontDelete|Function, 0, -1 },
+ { 108, SVGSVGElementImpl::PauseAnimations, DontDelete|Function, 0, -1 },
+ { 297, SVGSVGElementImpl::SetCurrentTime, DontDelete|Function, 1, 33 },
+ { 326, SVGSVGElementImpl::DeselectAll, DontDelete|Function, 0, -1 },
+ { 282, SVGSVGElementImpl::GetElementById, DontDelete|Function, 1, -1 }
+};
+
+const struct HashTable SVGSVGElementImplProto::s_hashTable = { 2, 35, SVGSVGElementImplProto__s_hashTableEntries, 29, SVGSVGElementImplProto__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGScriptElementImpl.lut.h b/ksvg/data/SVGScriptElementImpl.lut.h
new file mode 100644
index 00000000..661e35a2
--- /dev/null
+++ b/ksvg/data/SVGScriptElementImpl.lut.h
@@ -0,0 +1,20 @@
+/* Automatically generated from impl/SVGScriptElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGScriptElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "type\0"
+};
+
+
+static const struct HashEntry SVGScriptElementImpl__s_hashTableEntries[] = {
+ { 1, SVGScriptElementImpl::Type, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGScriptElementImpl::s_hashTable = { 2, 2, SVGScriptElementImpl__s_hashTableEntries, 2, SVGScriptElementImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGStopElementImpl.lut.h b/ksvg/data/SVGStopElementImpl.lut.h
new file mode 100644
index 00000000..5bdc3a98
--- /dev/null
+++ b/ksvg/data/SVGStopElementImpl.lut.h
@@ -0,0 +1,22 @@
+/* Automatically generated from impl/SVGStopElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGStopElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "stop-opacity\0"
+ "offset\0"
+};
+
+
+static const struct HashEntry SVGStopElementImpl__s_hashTableEntries[] = {
+ { 1, SVGStopElementImpl::StopOpacity, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 14, SVGStopElementImpl::Offset, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGStopElementImpl::s_hashTable = { 2, 3, SVGStopElementImpl__s_hashTableEntries, 3, SVGStopElementImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGStringListImpl.lut.h b/ksvg/data/SVGStringListImpl.lut.h
new file mode 100644
index 00000000..db89d010
--- /dev/null
+++ b/ksvg/data/SVGStringListImpl.lut.h
@@ -0,0 +1,74 @@
+/* Automatically generated from impl/SVGStringListImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SharedString__s_hashTableStrings[] = {
+ "\0"
+ "dummy\0"
+};
+
+
+static const struct HashEntry SharedString__s_hashTableEntries[] = {
+ { 1, SharedString::Dummy, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SharedString::s_hashTable = { 2, 2, SharedString__s_hashTableEntries, 2, SharedString__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGStringListImpl__s_hashTableStrings[] = {
+ "\0"
+ "numberOfItems\0"
+};
+
+
+static const struct HashEntry SVGStringListImpl__s_hashTableEntries[] = {
+ { 1, SVGListDefs::NumberOfItems, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGStringListImpl::s_hashTable = { 2, 2, SVGStringListImpl__s_hashTableEntries, 2, SVGStringListImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGStringListImplProto__s_hashTableStrings[] = {
+ "\0"
+ "insertItemBefore\0"
+ "replaceItem\0"
+ "appendItem\0"
+ "initialize\0"
+ "removeItem\0"
+ "getItem\0"
+ "clear\0"
+};
+
+
+static const struct HashEntry SVGStringListImplProto__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 71, SVGListDefs::Clear, DontDelete|Function, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 63, SVGListDefs::GetItem, DontDelete|Function, 1, -1 },
+ { 1, SVGListDefs::InsertItemBefore, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 41, SVGListDefs::Initialize, DontDelete|Function, 1, -1 },
+ { 52, SVGListDefs::RemoveItem, DontDelete|Function, 1, 11 },
+ { 18, SVGListDefs::ReplaceItem, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 30, SVGListDefs::AppendItem, DontDelete|Function, 1, -1 }
+};
+
+const struct HashTable SVGStringListImplProto::s_hashTable = { 2, 12, SVGStringListImplProto__s_hashTableEntries, 11, SVGStringListImplProto__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGStylableImpl.lut.h b/ksvg/data/SVGStylableImpl.lut.h
new file mode 100644
index 00000000..f6e0570f
--- /dev/null
+++ b/ksvg/data/SVGStylableImpl.lut.h
@@ -0,0 +1,143 @@
+/* Automatically generated from impl/SVGStylableImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGStylableImpl__s_hashTableStrings[] = {
+ "\0"
+ "glyph-orientation-horizontal\0"
+ "glyph-orientation-vertical\0"
+ "color-interpolation\0"
+ "stroke-dashoffset\0"
+ "stroke-miterlimit\0"
+ "stroke-dasharray\0"
+ "stroke-linejoin\0"
+ "text-decoration\0"
+ "baseline-shift\0"
+ "letter-spacing\0"
+ "pointer-events\0"
+ "stroke-linecap\0"
+ "stroke-opacity\0"
+ "color-profile\0"
+ "fill-opacity\0"
+ "marker-start\0"
+ "stroke-width\0"
+ "unicode-bidi\0"
+ "word-spacing\0"
+ "writing-mode\0"
+ "font-family\0"
+ "font-weight\0"
+ "text-anchor\0"
+ "font-style\0"
+ "marker-end\0"
+ "marker-mid\0"
+ "stop-color\0"
+ "visibility\0"
+ "className\0"
+ "clip-path\0"
+ "clip-rule\0"
+ "direction\0"
+ "fill-rule\0"
+ "font-size\0"
+ "overflow\0"
+ "display\0"
+ "cursor\0"
+ "marker\0"
+ "stroke\0"
+ "clip\0"
+ "fill\0"
+ "mask\0"
+};
+
+
+static const struct HashEntry SVGStylableImpl__s_hashTableEntries[] = {
+ { 523, SVGStylableImpl::Fill, DontDelete|ReadOnly, 0, -1 },
+ { 518, SVGStylableImpl::Clip, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 341, SVGStylableImpl::FontWeight, DontDelete|ReadOnly, 0, -1 },
+ { 353, SVGStylableImpl::TextAnchor, DontDelete|ReadOnly, 0, 52 },
+ { 511, SVGStylableImpl::Stroke, DontDelete|ReadOnly, 0, 56 },
+ { 251, SVGStylableImpl::FillOpacity, DontDelete|ReadOnly, 0, -1 },
+ { 398, SVGStylableImpl::StopColor, DontDelete|ReadOnly, 0, 61 },
+ { 256, SVGStylableImpl::Opacity, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 95, SVGStylableImpl::StrokeMiterlimit, DontDelete|ReadOnly, 0, 49 },
+ { 497, SVGStylableImpl::Cursor, DontDelete|ReadOnly, 0, 60 },
+ { 222, SVGStylableImpl::StrokeOpacity, DontDelete|ReadOnly, 0, 62 },
+ { 130, SVGStylableImpl::StrokeLineJoin, DontDelete|ReadOnly, 0, 53 },
+ { 409, SVGStylableImpl::Visibility, DontDelete|ReadOnly, 0, 57 },
+ { 316, SVGStylableImpl::WritingMode, DontDelete|ReadOnly, 0, 58 },
+ { 0, 0, 0, 0, -1 },
+ { 192, SVGStylableImpl::PointerEvents, DontDelete|ReadOnly, 0, 63 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 450, SVGStylableImpl::Direction, DontDelete|ReadOnly, 0, 51 },
+ { 0, 0, 0, 0, -1 },
+ { 264, SVGStylableImpl::MarkerStart, DontDelete|ReadOnly, 0, 59 },
+ { 0, 0, 0, 0, -1 },
+ { 237, SVGStylableImpl::ColorProfile, DontDelete|ReadOnly, 0, -1 },
+ { 420, SVGStylableImpl::ClassName, DontDelete|ReadOnly, 0, 48 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 57, SVGStylableImpl::ColorInterpolation, DontDelete|ReadOnly, 0, -1 },
+ { 277, SVGStylableImpl::StrokeWidth, DontDelete|ReadOnly, 0, 47 },
+ { 177, SVGStylableImpl::LetterSpacing, DontDelete|ReadOnly, 0, -1 },
+ { 77, SVGStylableImpl::StrokeDashOffset, DontDelete|ReadOnly, 0, -1 },
+ { 470, SVGStylableImpl::FontSize, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 480, SVGStylableImpl::Overflow, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 370, SVGStylableImpl::Style, DontDelete|ReadOnly, 0, -1 },
+ { 329, SVGStylableImpl::FontFamily, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 207, SVGStylableImpl::StrokeLineCap, DontDelete|ReadOnly, 0, 55 },
+ { 403, SVGStylableImpl::Color, DontDelete|ReadOnly, 0, -1 },
+ { 365, SVGStylableImpl::FontStyle, DontDelete|ReadOnly, 0, 50 },
+ { 146, SVGStylableImpl::TextDecoration, DontDelete|ReadOnly, 0, 54 },
+ { 290, SVGStylableImpl::UnicodeBidi, DontDelete|ReadOnly, 0, -1 },
+ { 430, SVGStylableImpl::ClipPath, DontDelete|ReadOnly, 0, 64 },
+ { 387, SVGStylableImpl::MarkerMid, DontDelete|ReadOnly, 0, -1 },
+ { 376, SVGStylableImpl::MarkerEnd, DontDelete|ReadOnly, 0, -1 },
+ { 504, SVGStylableImpl::Marker, DontDelete|ReadOnly, 0, -1 },
+ { 489, SVGStylableImpl::Display, DontDelete|ReadOnly, 0, -1 },
+ { 460, SVGStylableImpl::FillRule, DontDelete|ReadOnly, 0, -1 },
+ { 440, SVGStylableImpl::ClipRule, DontDelete|ReadOnly, 0, -1 },
+ { 113, SVGStylableImpl::StrokeDashArray, DontDelete|ReadOnly, 0, -1 },
+ { 162, SVGStylableImpl::BaselineShift, DontDelete|ReadOnly, 0, -1 },
+ { 303, SVGStylableImpl::WordSpacing, DontDelete|ReadOnly, 0, -1 },
+ { 30, SVGStylableImpl::GlyphOrientationVertical, DontDelete|ReadOnly, 0, -1 },
+ { 1, SVGStylableImpl::GlyphOrientationHorizontal, DontDelete|ReadOnly, 0, -1 },
+ { 528, SVGStylableImpl::Mask, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGStylableImpl::s_hashTable = { 2, 65, SVGStylableImpl__s_hashTableEntries, 47, SVGStylableImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGStylableImplProto__s_hashTableStrings[] = {
+ "\0"
+ "getStyle\0"
+};
+
+
+static const struct HashEntry SVGStylableImplProto__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGStylableImpl::GetStyle, DontDelete|Function, 0, -1 }
+};
+
+const struct HashTable SVGStylableImplProto::s_hashTable = { 2, 2, SVGStylableImplProto__s_hashTableEntries, 2, SVGStylableImplProto__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGStyleElementImpl.lut.h b/ksvg/data/SVGStyleElementImpl.lut.h
new file mode 100644
index 00000000..9eb6c903
--- /dev/null
+++ b/ksvg/data/SVGStyleElementImpl.lut.h
@@ -0,0 +1,27 @@
+/* Automatically generated from impl/SVGStyleElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGStyleElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "xmlspace\0"
+ "media\0"
+ "title\0"
+ "type\0"
+};
+
+
+static const struct HashEntry SVGStyleElementImpl__s_hashTableEntries[] = {
+ { 22, SVGStyleElementImpl::Type, DontDelete, 0, -1 },
+ { 1, SVGStyleElementImpl::Xmlspace, DontDelete, 0, 5 },
+ { 10, SVGStyleElementImpl::Media, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 16, SVGStyleElementImpl::Title, DontDelete, 0, -1 }
+};
+
+const struct HashTable SVGStyleElementImpl::s_hashTable = { 2, 6, SVGStyleElementImpl__s_hashTableEntries, 5, SVGStyleElementImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGSymbolElementImpl.lut.h b/ksvg/data/SVGSymbolElementImpl.lut.h
new file mode 100644
index 00000000..5dba1cce
--- /dev/null
+++ b/ksvg/data/SVGSymbolElementImpl.lut.h
@@ -0,0 +1,22 @@
+/* Automatically generated from impl/SVGSymbolElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGSymbolElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "height\0"
+ "width\0"
+};
+
+
+static const struct HashEntry SVGSymbolElementImpl__s_hashTableEntries[] = {
+ { 1, SVGSymbolElementImpl::Height, DontDelete|ReadOnly, 0, -1 },
+ { 8, SVGSymbolElementImpl::Width, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGSymbolElementImpl::s_hashTable = { 2, 3, SVGSymbolElementImpl__s_hashTableEntries, 3, SVGSymbolElementImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGTestsImpl.lut.h b/ksvg/data/SVGTestsImpl.lut.h
new file mode 100644
index 00000000..07bf4f48
--- /dev/null
+++ b/ksvg/data/SVGTestsImpl.lut.h
@@ -0,0 +1,45 @@
+/* Automatically generated from impl/SVGTestsImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGTestsImpl__s_hashTableStrings[] = {
+ "\0"
+ "requiredExtensions\0"
+ "requiredFeatures\0"
+ "systemLanguage\0"
+};
+
+
+static const struct HashEntry SVGTestsImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 20, SVGTestsImpl::RequiredFeatures, DontDelete|ReadOnly, 0, 5 },
+ { 1, SVGTestsImpl::RequiredExtensions, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 37, SVGTestsImpl::SystemLanguage, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGTestsImpl::s_hashTable = { 2, 6, SVGTestsImpl__s_hashTableEntries, 5, SVGTestsImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGTestsImplProto__s_hashTableStrings[] = {
+ "\0"
+ "hasExtension\0"
+};
+
+
+static const struct HashEntry SVGTestsImplProto__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGTestsImpl::HasExtension, DontDelete|Function, 1, -1 }
+};
+
+const struct HashTable SVGTestsImplProto::s_hashTable = { 2, 2, SVGTestsImplProto__s_hashTableEntries, 2, SVGTestsImplProto__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGTextContentElementImpl.lut.h b/ksvg/data/SVGTextContentElementImpl.lut.h
new file mode 100644
index 00000000..8e0bf2db
--- /dev/null
+++ b/ksvg/data/SVGTextContentElementImpl.lut.h
@@ -0,0 +1,84 @@
+/* Automatically generated from impl/SVGTextContentElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGTextContentElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "lengthAdjust\0"
+ "textLength\0"
+};
+
+
+static const struct HashEntry SVGTextContentElementImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 14, SVGTextContentElementImpl::TextLength, DontDelete|ReadOnly, 0, 3 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGTextContentElementImpl::LengthAdjust, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGTextContentElementImpl::s_hashTable = { 2, 4, SVGTextContentElementImpl__s_hashTableEntries, 3, SVGTextContentElementImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGTextContentElementImplProto__s_hashTableStrings[] = {
+ "\0"
+ "getStartPositionOfChar\0"
+ "getComputedTextLength\0"
+ "getCharNumAtPosition\0"
+ "getEndPositionOfChar\0"
+ "getSubStringLength\0"
+ "getRotationOfChar\0"
+ "getNumberOfChars\0"
+ "getExtentOfChar\0"
+ "selectSubString\0"
+};
+
+
+static const struct HashEntry SVGTextContentElementImplProto__s_hashTableEntries[] = {
+ { 88, SVGTextContentElementImpl::GetSubStringLength, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 67, SVGTextContentElementImpl::GetEndPositionOfChar, DontDelete|Function, 1, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 107, SVGTextContentElementImpl::GetRotationOfChar, DontDelete|Function, 1, -1 },
+ { 46, SVGTextContentElementImpl::GetCharNumAtPosition, DontDelete|Function, 1, -1 },
+ { 24, SVGTextContentElementImpl::GetComputedTextLength, DontDelete|Function, 0, -1 },
+ { 1, SVGTextContentElementImpl::GetStartPositionOfChar, DontDelete|Function, 1, 11 },
+ { 142, SVGTextContentElementImpl::GetExtentOfChar, DontDelete|Function, 1, -1 },
+ { 125, SVGTextContentElementImpl::GetNumberOfChars, DontDelete|Function, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 158, SVGTextContentElementImpl::SelectSubString, DontDelete|Function, 2, -1 }
+};
+
+const struct HashTable SVGTextContentElementImplProto::s_hashTable = { 2, 12, SVGTextContentElementImplProto__s_hashTableEntries, 11, SVGTextContentElementImplProto__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGTextContentElementImplConstructor__s_hashTableStrings[] = {
+ "\0"
+ "LENGTHADJUST_SPACINGANDGLYPHS\0"
+ "LENGTHADJUST_SPACING\0"
+ "LENGTHADJUST_UNKNOWN\0"
+};
+
+
+static const struct HashEntry SVGTextContentElementImplConstructor__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 31, KSVG::LENGTHADJUST_SPACING, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, KSVG::LENGTHADJUST_SPACINGANDGLYPHS, DontDelete|ReadOnly, 0, -1 },
+ { 52, KSVG::LENGTHADJUST_UNKNOWN, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGTextContentElementImplConstructor::s_hashTable = { 2, 5, SVGTextContentElementImplConstructor__s_hashTableEntries, 5, SVGTextContentElementImplConstructor__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGTextPathElementImpl.lut.h b/ksvg/data/SVGTextPathElementImpl.lut.h
new file mode 100644
index 00000000..b13c0b70
--- /dev/null
+++ b/ksvg/data/SVGTextPathElementImpl.lut.h
@@ -0,0 +1,56 @@
+/* Automatically generated from impl/SVGTextPathElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGTextPathElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "startOffset\0"
+ "spacing\0"
+ "method\0"
+};
+
+
+static const struct HashEntry SVGTextPathElementImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 21, SVGTextPathElementImpl::Method, DontDelete|ReadOnly, 0, 5 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGTextPathElementImpl::StartOffset, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 13, SVGTextPathElementImpl::Spacing, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGTextPathElementImpl::s_hashTable = { 2, 6, SVGTextPathElementImpl__s_hashTableEntries, 5, SVGTextPathElementImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGTextPathElementImplConstructor__s_hashTableStrings[] = {
+ "\0"
+ "TEXTPATH_SPACINGTYPE_UNKNOWN\0"
+ "TEXTPATH_METHODTYPE_STRETCH\0"
+ "TEXTPATH_METHODTYPE_UNKNOWN\0"
+ "TEXTPATH_SPACINGTYPE_EXACT\0"
+ "TEXTPATH_METHODTYPE_ALIGN\0"
+ "TEXTPATH_SPACINGTYPE_AUTO\0"
+};
+
+
+static const struct HashEntry SVGTextPathElementImplConstructor__s_hashTableEntries[] = {
+ { 30, KSVG::TEXTPATH_METHODTYPE_STRETCH, DontDelete|ReadOnly, 0, -1 },
+ { 139, KSVG::TEXTPATH_SPACINGTYPE_AUTO, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, KSVG::TEXTPATH_SPACINGTYPE_UNKNOWN, DontDelete|ReadOnly, 0, -1 },
+ { 113, KSVG::TEXTPATH_METHODTYPE_ALIGN, DontDelete|ReadOnly, 0, -1 },
+ { 58, KSVG::TEXTPATH_METHODTYPE_UNKNOWN, DontDelete|ReadOnly, 0, 7 },
+ { 0, 0, 0, 0, -1 },
+ { 86, KSVG::TEXTPATH_SPACINGTYPE_EXACT, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGTextPathElementImplConstructor::s_hashTable = { 2, 8, SVGTextPathElementImplConstructor__s_hashTableEntries, 7, SVGTextPathElementImplConstructor__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGTextPositioningElementImpl.lut.h b/ksvg/data/SVGTextPositioningElementImpl.lut.h
new file mode 100644
index 00000000..de029165
--- /dev/null
+++ b/ksvg/data/SVGTextPositioningElementImpl.lut.h
@@ -0,0 +1,28 @@
+/* Automatically generated from impl/SVGTextPositioningElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGTextPositioningElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "rotate\0"
+ "dx\0"
+ "dy\0"
+};
+
+
+static const struct HashEntry SVGTextPositioningElementImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 9, SVGTextPositioningElementImpl::X, DontDelete|ReadOnly, 0, -1 },
+ { 12, SVGTextPositioningElementImpl::Y, DontDelete|ReadOnly, 0, -1 },
+ { 8, SVGTextPositioningElementImpl::Dx, DontDelete|ReadOnly, 0, -1 },
+ { 11, SVGTextPositioningElementImpl::Dy, DontDelete|ReadOnly, 0, 7 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGTextPositioningElementImpl::Rotate, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGTextPositioningElementImpl::s_hashTable = { 2, 8, SVGTextPositioningElementImpl__s_hashTableEntries, 7, SVGTextPositioningElementImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGTransformImpl.lut.h b/ksvg/data/SVGTransformImpl.lut.h
new file mode 100644
index 00000000..aff39a3b
--- /dev/null
+++ b/ksvg/data/SVGTransformImpl.lut.h
@@ -0,0 +1,89 @@
+/* Automatically generated from impl/SVGTransformImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGTransformImpl__s_hashTableStrings[] = {
+ "\0"
+ "matrix\0"
+ "angle\0"
+ "type\0"
+};
+
+
+static const struct HashEntry SVGTransformImpl__s_hashTableEntries[] = {
+ { 14, SVGTransformImpl::Type, DontDelete|ReadOnly, 0, -1 },
+ { 1, SVGTransformImpl::Matrix, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 8, SVGTransformImpl::Angle, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGTransformImpl::s_hashTable = { 2, 5, SVGTransformImpl__s_hashTableEntries, 5, SVGTransformImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGTransformImplProto__s_hashTableStrings[] = {
+ "\0"
+ "setTranslate\0"
+ "setMatrix\0"
+ "setRotate\0"
+ "setScale\0"
+ "setSkewX\0"
+ "setSkewY\0"
+};
+
+
+static const struct HashEntry SVGTransformImplProto__s_hashTableEntries[] = {
+ { 1, SVGTransformImpl::SetTranslate, DontDelete|Function, 2, -1 },
+ { 34, SVGTransformImpl::SetScale, DontDelete|Function, 2, -1 },
+ { 14, SVGTransformImpl::SetMatrix, DontDelete|Function, 1, -1 },
+ { 24, SVGTransformImpl::SetRotate, DontDelete|Function, 3, -1 },
+ { 43, SVGTransformImpl::SetSkewX, DontDelete|Function, 1, -1 },
+ { 52, SVGTransformImpl::SetSkewY, DontDelete|Function, 1, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGTransformImplProto::s_hashTable = { 2, 7, SVGTransformImplProto__s_hashTableEntries, 7, SVGTransformImplProto__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGTransformImplConstructor__s_hashTableStrings[] = {
+ "\0"
+ "SVG_TRANSFORM_TRANSLATE\0"
+ "SVG_TRANSFORM_UNKNOWN\0"
+ "SVG_TRANSFORM_MATRIX\0"
+ "SVG_TRANSFORM_ROTATE\0"
+ "SVG_TRANSFORM_SCALE\0"
+ "SVG_TRANSFORM_SKEWX\0"
+ "SVG_TRANSFORM_SKEWY\0"
+};
+
+
+static const struct HashEntry SVGTransformImplConstructor__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 1, KSVG::SVG_TRANSFORM_TRANSLATE, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 109, KSVG::SVG_TRANSFORM_SKEWX, DontDelete|ReadOnly, 0, -1 },
+ { 47, KSVG::SVG_TRANSFORM_MATRIX, DontDelete|ReadOnly, 0, 11 },
+ { 89, KSVG::SVG_TRANSFORM_SCALE, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 25, KSVG::SVG_TRANSFORM_UNKNOWN, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 68, KSVG::SVG_TRANSFORM_ROTATE, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 129, KSVG::SVG_TRANSFORM_SKEWY, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGTransformImplConstructor::s_hashTable = { 2, 12, SVGTransformImplConstructor__s_hashTableEntries, 11, SVGTransformImplConstructor__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGTransformListImpl.lut.h b/ksvg/data/SVGTransformListImpl.lut.h
new file mode 100644
index 00000000..8b186a8e
--- /dev/null
+++ b/ksvg/data/SVGTransformListImpl.lut.h
@@ -0,0 +1,55 @@
+/* Automatically generated from impl/SVGTransformListImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGTransformListImpl__s_hashTableStrings[] = {
+ "\0"
+ "numberOfItems\0"
+};
+
+
+static const struct HashEntry SVGTransformListImpl__s_hashTableEntries[] = {
+ { 1, SVGListDefs::NumberOfItems, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGTransformListImpl::s_hashTable = { 2, 2, SVGTransformListImpl__s_hashTableEntries, 2, SVGTransformListImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGTransformListImplProto__s_hashTableStrings[] = {
+ "\0"
+ "insertItemBefore\0"
+ "replaceItem\0"
+ "appendItem\0"
+ "initialize\0"
+ "removeItem\0"
+ "getItem\0"
+ "clear\0"
+};
+
+
+static const struct HashEntry SVGTransformListImplProto__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 71, SVGListDefs::Clear, DontDelete|Function, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 63, SVGListDefs::GetItem, DontDelete|Function, 1, -1 },
+ { 1, SVGListDefs::InsertItemBefore, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 41, SVGListDefs::Initialize, DontDelete|Function, 1, -1 },
+ { 52, SVGListDefs::RemoveItem, DontDelete|Function, 1, 11 },
+ { 18, SVGListDefs::ReplaceItem, DontDelete|Function, 2, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 30, SVGListDefs::AppendItem, DontDelete|Function, 1, -1 }
+};
+
+const struct HashTable SVGTransformListImplProto::s_hashTable = { 2, 12, SVGTransformListImplProto__s_hashTableEntries, 11, SVGTransformListImplProto__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGTransformableImpl.lut.h b/ksvg/data/SVGTransformableImpl.lut.h
new file mode 100644
index 00000000..7ca5e81f
--- /dev/null
+++ b/ksvg/data/SVGTransformableImpl.lut.h
@@ -0,0 +1,20 @@
+/* Automatically generated from impl/SVGTransformableImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGTransformableImpl__s_hashTableStrings[] = {
+ "\0"
+ "transform\0"
+};
+
+
+static const struct HashEntry SVGTransformableImpl__s_hashTableEntries[] = {
+ { 1, SVGTransformableImpl::Transform, DontDelete, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGTransformableImpl::s_hashTable = { 2, 2, SVGTransformableImpl__s_hashTableEntries, 2, SVGTransformableImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGURIReferenceImpl.lut.h b/ksvg/data/SVGURIReferenceImpl.lut.h
new file mode 100644
index 00000000..08eafcb6
--- /dev/null
+++ b/ksvg/data/SVGURIReferenceImpl.lut.h
@@ -0,0 +1,20 @@
+/* Automatically generated from impl/SVGURIReferenceImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGURIReferenceImpl__s_hashTableStrings[] = {
+ "\0"
+ "href\0"
+};
+
+
+static const struct HashEntry SVGURIReferenceImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGURIReferenceImpl::Href, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGURIReferenceImpl::s_hashTable = { 2, 2, SVGURIReferenceImpl__s_hashTableEntries, 2, SVGURIReferenceImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGUseElementImpl.lut.h b/ksvg/data/SVGUseElementImpl.lut.h
new file mode 100644
index 00000000..8f249826
--- /dev/null
+++ b/ksvg/data/SVGUseElementImpl.lut.h
@@ -0,0 +1,36 @@
+/* Automatically generated from impl/SVGUseElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGUseElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "animatedInstanceRoot\0"
+ "instanceRoot\0"
+ "height\0"
+ "width\0"
+ "href\0"
+ "x\0"
+ "y\0"
+};
+
+
+static const struct HashEntry SVGUseElementImpl__s_hashTableEntries[] = {
+ { 55, SVGUseElementImpl::Y, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 48, SVGUseElementImpl::Href, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 42, SVGUseElementImpl::Width, DontDelete|ReadOnly, 0, -1 },
+ { 35, SVGUseElementImpl::Height, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 22, SVGUseElementImpl::InstanceRoot, DontDelete|ReadOnly, 0, 11 },
+ { 0, 0, 0, 0, -1 },
+ { 53, SVGUseElementImpl::X, DontDelete|ReadOnly, 0, -1 },
+ { 1, SVGUseElementImpl::AnimatedInstanceRoot, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGUseElementImpl::s_hashTable = { 2, 12, SVGUseElementImpl__s_hashTableEntries, 11, SVGUseElementImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGViewElementImpl.lut.h b/ksvg/data/SVGViewElementImpl.lut.h
new file mode 100644
index 00000000..cbc29ca3
--- /dev/null
+++ b/ksvg/data/SVGViewElementImpl.lut.h
@@ -0,0 +1,20 @@
+/* Automatically generated from impl/SVGViewElementImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGViewElementImpl__s_hashTableStrings[] = {
+ "\0"
+ "viewTarget\0"
+};
+
+
+static const struct HashEntry SVGViewElementImpl__s_hashTableEntries[] = {
+ { 1, SVGViewElementImpl::ViewTarget, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 }
+};
+
+const struct HashTable SVGViewElementImpl::s_hashTable = { 2, 2, SVGViewElementImpl__s_hashTableEntries, 2, SVGViewElementImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGZoomAndPanImpl.lut.h b/ksvg/data/SVGZoomAndPanImpl.lut.h
new file mode 100644
index 00000000..7886c67f
--- /dev/null
+++ b/ksvg/data/SVGZoomAndPanImpl.lut.h
@@ -0,0 +1,45 @@
+/* Automatically generated from impl/SVGZoomAndPanImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGZoomAndPanImpl__s_hashTableStrings[] = {
+ "\0"
+ "zoomAndPan\0"
+};
+
+
+static const struct HashEntry SVGZoomAndPanImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGZoomAndPanImpl::ZoomAndPan, DontDelete, 0, -1 }
+};
+
+const struct HashTable SVGZoomAndPanImpl::s_hashTable = { 2, 2, SVGZoomAndPanImpl__s_hashTableEntries, 2, SVGZoomAndPanImpl__s_hashTableStrings};
+
+} // namespace
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGZoomAndPanImplConstructor__s_hashTableStrings[] = {
+ "\0"
+ "SVG_ZOOMANDPAN_DISABLE\0"
+ "SVG_ZOOMANDPAN_MAGNIFY\0"
+ "SVG_ZOOMANDPAN_UNKNOWN\0"
+};
+
+
+static const struct HashEntry SVGZoomAndPanImplConstructor__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 24, KSVG::SVG_ZOOMANDPAN_MAGNIFY, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 47, KSVG::SVG_ZOOMANDPAN_UNKNOWN, DontDelete|ReadOnly, 0, 5 },
+ { 1, KSVG::SVG_ZOOMANDPAN_DISABLE, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGZoomAndPanImplConstructor::s_hashTable = { 2, 6, SVGZoomAndPanImplConstructor__s_hashTableEntries, 5, SVGZoomAndPanImplConstructor__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/SVGZoomEventImpl.lut.h b/ksvg/data/SVGZoomEventImpl.lut.h
new file mode 100644
index 00000000..5f5a277b
--- /dev/null
+++ b/ksvg/data/SVGZoomEventImpl.lut.h
@@ -0,0 +1,29 @@
+/* Automatically generated from impl/SVGZoomEventImpl.cc using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char SVGZoomEventImpl__s_hashTableStrings[] = {
+ "\0"
+ "previousTranslate\0"
+ "zoomRectScreen\0"
+ "previousScale\0"
+ "newTranslate\0"
+ "newScale\0"
+};
+
+
+static const struct HashEntry SVGZoomEventImpl__s_hashTableEntries[] = {
+ { 0, 0, 0, 0, -1 },
+ { 1, SVGZoomEventImpl::PreviousTranslate, DontDelete|ReadOnly, 0, -1 },
+ { 34, SVGZoomEventImpl::PreviousScale, DontDelete|ReadOnly, 0, -1 },
+ { 19, SVGZoomEventImpl::ZoomRectScreen, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 48, SVGZoomEventImpl::NewTranslate, DontDelete|ReadOnly, 0, -1 },
+ { 61, SVGZoomEventImpl::NewScale, DontDelete|ReadOnly, 0, -1 }
+};
+
+const struct HashTable SVGZoomEventImpl::s_hashTable = { 2, 7, SVGZoomEventImpl__s_hashTableEntries, 7, SVGZoomEventImpl__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/data/ksvg_window.lut.h b/ksvg/data/ksvg_window.lut.h
new file mode 100644
index 00000000..4b6d270b
--- /dev/null
+++ b/ksvg/data/ksvg_window.lut.h
@@ -0,0 +1,98 @@
+/* Automatically generated from ecma/ksvg_window.cpp using ../../kdelibs/kjs/create_hash_table. DO NOT EDIT ! */
+
+using namespace KJS;
+
+namespace KSVG {
+
+static const char KSVG__Window__s_hashTableStrings[] = {
+ "\0"
+ "SVGPreserveAspectRatio\0"
+ "SVGTextContentElement\0"
+ "getSVGViewerVersion\0"
+ "SVGGradientElement\0"
+ "SVGTextPathElement\0"
+ "SVGMarkerElement\0"
+ "SVGZoomAndPan\0"
+ "clearInterval\0"
+ "SVGTransform\0"
+ "clearTimeout\0"
+ "innerHeight\0"
+ "setInterval\0"
+ "svgDocument\0"
+ "SVGPathSeg\0"
+ "innerWidth\0"
+ "setTimeout\0"
+ "SVGLength\0"
+ "navigator\0"
+ "printNode\0"
+ "SVGAngle\0"
+ "SVGColor\0"
+ "SVGPaint\0"
+ "document\0"
+ "parseXML\0"
+ "confirm\0"
+ "postURL\0"
+ "success\0"
+ "closed\0"
+ "getURL\0"
+ "prompt\0"
+ "window\0"
+ "alert\0"
+ "debug\0"
+ "evt\0"
+};
+
+
+static const struct HashEntry KSVG__Window__s_hashTableEntries[] = {
+ { 244, KSVG::Window::_SVGLength, DontDelete|ReadOnly, 0, 39 },
+ { 0, 0, 0, 0, -1 },
+ { 319, KSVG::Window::_Confirm, DontDelete|Function, 1, -1 },
+ { 283, KSVG::Window::_SVGColor, DontDelete|ReadOnly, 0, -1 },
+ { 162, KSVG::Window::_ClearTimeout, DontDelete|Function, 1, 41 },
+ { 0, 0, 0, 0, -1 },
+ { 149, KSVG::Window::_SVGTransform, DontDelete|ReadOnly, 0, 38 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 377, KSVG::Window::_Debug, DontDelete|Function, 1, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 199, KSVG::Window::_Document, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 301, KSVG::Window::_Document, DontDelete|ReadOnly, 0, 34 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 327, KSVG::Window::_PostURL, DontDelete|Function, 5, -1 },
+ { 364, KSVG::Window::_Window, DontDelete|ReadOnly, 0, -1 },
+ { 175, KSVG::Window::_InnerHeight, DontDelete|ReadOnly, 0, 35 },
+ { 0, 0, 0, 0, -1 },
+ { 233, KSVG::Window::_SetTimeout, DontDelete|Function, 2, -1 },
+ { 343, KSVG::Window::_Closed, DontDelete|ReadOnly, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 46, KSVG::Window::_GetSVGViewerVersion, DontDelete|Function, 0, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 371, KSVG::Window::_Alert, DontDelete|Function, 1, -1 },
+ { 1, KSVG::Window::_SVGPreserveAspectRatio, DontDelete|ReadOnly, 0, -1 },
+ { 357, KSVG::Window::_Prompt, DontDelete|Function, 2, -1 },
+ { 383, KSVG::Window::_Evt, DontDelete|ReadOnly, 0, 36 },
+ { 135, KSVG::Window::_ClearInterval, DontDelete|Function, 1, -1 },
+ { 0, 0, 0, 0, -1 },
+ { 222, KSVG::Window::_InnerWidth, DontDelete|ReadOnly, 0, 43 },
+ { 121, KSVG::Window::_SVGZoomAndPan, DontDelete|ReadOnly, 0, -1 },
+ { 187, KSVG::Window::_SetInterval, DontDelete|Function, 2, 37 },
+ { 254, KSVG::Window::_Navigator, DontDelete|ReadOnly, 0, 45 },
+ { 264, KSVG::Window::_PrintNode, DontDelete|Function, 1, -1 },
+ { 274, KSVG::Window::_SVGAngle, DontDelete|ReadOnly, 0, 44 },
+ { 211, KSVG::Window::_SVGPathSeg, DontDelete|ReadOnly, 0, -1 },
+ { 66, KSVG::Window::_SVGGradientElement, DontDelete|ReadOnly, 0, 40 },
+ { 104, KSVG::Window::_SVGMarkerElement, DontDelete|ReadOnly, 0, 42 },
+ { 85, KSVG::Window::_SVGTextPathElement, DontDelete|ReadOnly, 0, -1 },
+ { 292, KSVG::Window::_SVGPaint, DontDelete|ReadOnly, 0, -1 },
+ { 24, KSVG::Window::_SVGTextContentElement, DontDelete|ReadOnly, 0, 46 },
+ { 335, KSVG::Window::_Success, DontDelete|Function, 1, -1 },
+ { 350, KSVG::Window::_GetURL, DontDelete|Function, 2, -1 },
+ { 310, KSVG::Window::_ParseXML, DontDelete|Function, 1, -1 }
+};
+
+const struct HashTable KSVG::Window::s_hashTable = { 2, 47, KSVG__Window__s_hashTableEntries, 34, KSVG__Window__s_hashTableStrings};
+
+} // namespace
diff --git a/ksvg/dom/Makefile.am b/ksvg/dom/Makefile.am
new file mode 100644
index 00000000..9b6b1cf7
--- /dev/null
+++ b/ksvg/dom/Makefile.am
@@ -0,0 +1,58 @@
+noinst_LTLIBRARIES = libksvgdom.la
+
+myincludedir = $(includedir)/dom
+myinclude_HEADERS = SVGAElement.h SVGAltGlyphElement.h SVGAltGlyphDefElement.h SVGGlyphRefElement.h SVGAngle.h SVGAnimateColorElement.h SVGAnimateElement.h \
+ SVGAnimateMotionElement.h SVGAnimateTransformElement.h SVGAnimatedAngle.h SVGAnimatedBoolean.h \
+ SVGAnimatedEnumeration.h SVGAnimatedInteger.h SVGAnimatedLength.h SVGAnimatedLengthList.h \
+ SVGAnimatedNumber.h SVGAnimatedNumberList.h SVGAnimatedPathData.h SVGAnimatedPoints.h \
+ SVGAnimatedPreserveAspectRatio.h SVGAnimatedRect.h SVGAnimatedString.h SVGAnimatedTransformList.h \
+ SVGAnimationElement.h SVGCSSRule.h SVGCircleElement.h SVGClipPathElement.h SVGColor.h \
+ SVGColorProfileElement.h SVGColorProfileRule.h SVGComponentTransferFunctionElement.h SVGCursorElement.h \
+ SVGDefinitionSrcElement.h SVGDefsElement.h SVGDescElement.h SVGDocument.h SVGElement.h SVGElementInstance.h \
+ SVGElementInstanceList.h SVGEllipseElement.h SVGEvent.h SVGException.h SVGExternalResourcesRequired.h \
+ SVGFEBlendElement.h SVGFEColorMatrixElement.h SVGFEComponentTransferElement.h SVGFECompositeElement.h \
+ SVGFEConvolveMatrixElement.h SVGFEDiffuseLightingElement.h SVGFEDisplacementMapElement.h SVGFEDistantLightElement.h \
+ SVGFEFloodElement.h SVGFEFuncAElement.h SVGFEFuncBElement.h SVGFEFuncGElement.h SVGFEFuncRElement.h \
+ SVGFEGaussianBlurElement.h SVGFEImageElement.h SVGFEMergeElement.h SVGFEMergeNodeElement.h SVGFEMorphologyElement.h \
+ SVGFEOffsetElement.h SVGFEPointLightElement.h SVGFESpecularLightingElement.h SVGFESpotLightElement.h \
+ SVGFETileElement.h SVGFETurbulenceElement.h SVGFilterElement.h SVGFilterPrimitiveStandardAttributes.h \
+ SVGFitToViewBox.h SVGFontElement.h SVGFontFaceElement.h SVGFontFaceFormatElement.h SVGFontFaceNameElement.h \
+ SVGFontFaceSrcElement.h SVGFontFaceUriElement.h SVGForeignObjectElement.h SVGGElement.h SVGGlyphElement.h \
+ SVGGradientElement.h SVGHKernElement.h SVGICCColor.h SVGImageElement.h SVGLangSpace.h SVGLength.h SVGLengthList.h \
+ SVGLineElement.h SVGLinearGradientElement.h SVGLocatable.h SVGMPathElement.h SVGMarkerElement.h SVGMaskElement.h \
+ SVGMatrix.h SVGMetadataElement.h SVGMissingGlyphElement.h SVGNumber.h SVGNumberList.h SVGPaint.h SVGPathElement.h \
+ SVGPathSeg.h SVGPathSegArc.h SVGPathSegClosePath.h SVGPathSegCurvetoCubic.h SVGPathSegCurvetoCubicSmooth.h \
+ SVGPathSegCurvetoQuadratic.h SVGPathSegCurvetoQuadraticSmooth.h SVGPathSegLineto.h SVGPathSegLinetoHorizontal.h \
+ SVGPathSegLinetoVertical.h SVGPathSegList.h SVGPathSegMoveto.h SVGPatternElement.h SVGPoint.h SVGPointList.h \
+ SVGPolygonElement.h SVGPolylineElement.h SVGPreserveAspectRatio.h SVGRadialGradientElement.h SVGRect.h \
+ SVGRectElement.h SVGRenderingIntent.h SVGSVGElement.h SVGScriptElement.h SVGSetElement.h SVGStopElement.h \
+ SVGStringList.h SVGStylable.h SVGStyleElement.h SVGSwitchElement.h SVGSymbolElement.h SVGTRefElement.h \
+ SVGTSpanElement.h SVGTests.h SVGTextContentElement.h SVGTextElement.h SVGTextPathElement.h SVGTextPositioningElement.h \
+ SVGTitleElement.h SVGTransform.h SVGTransformList.h SVGTransformable.h SVGURIReference.h SVGUnitTypes.h \
+ SVGUseElement.h SVGVKernElement.h SVGViewElement.h SVGViewSpec.h SVGWindow.h SVGZoomAndPan.h SVGZoomEvent.h
+
+libksvgdom_la_SOURCES = SVGLength.cc SVGAnimatedLength.cc SVGNumber.cc SVGAnimatedNumber.cc SVGPoint.cc SVGTSpanElement.cc SVGTRefElement.cc \
+ SVGAnimatedLengthList.cc SVGAnimatedNumberList.cc SVGTransformList.cc SVGAElement.cc SVGAnimatedTransformList.cc \
+ SVGRectElement.cc SVGCircleElement.cc SVGEllipseElement.cc SVGLineElement.cc SVGPolylineElement.cc SVGPolygonElement.cc \
+ SVGTextPositioningElement.cc SVGTextContentElement.cc SVGTextElement.cc SVGImageElement.cc SVGUseElement.cc \
+ SVGMatrix.cc SVGTransform.cc SVGPointList.cc SVGDocument.cc SVGAnimatedEnumeration.cc SVGDefsElement.cc \
+ SVGLocatable.cc SVGTransformable.cc SVGStylable.cc SVGGElement.cc SVGAngle.cc SVGAnimatedAngle.cc \
+ SVGColor.cc SVGPathElement.cc SVGPathSegList.cc SVGTests.cc SVGLangSpace.cc SVGStringList.cc \
+ SVGPathSeg.cc SVGPathSegClosePath.cc SVGPathSegMoveto.cc SVGPathSegLinetoHorizontal.cc SVGPathSegLinetoVertical.cc SVGPathSegLineto.cc \
+ SVGPathSegCurvetoCubic.cc SVGDescElement.cc SVGTitleElement.cc SVGExternalResourcesRequired.cc SVGAnimatedBoolean.cc SVGNumberList.cc \
+ SVGPathSegCurvetoCubicSmooth.cc SVGPathSegCurvetoQuadratic.cc SVGAnimatedRect.cc SVGAnimatedString.cc \
+ SVGPathSegCurvetoQuadraticSmooth.cc SVGPathSegArc.cc SVGURIReference.cc SVGAnimatedInteger.cc SVGLengthList.cc \
+ SVGSVGElement.cc SVGRect.cc SVGFitToViewBox.cc SVGAnimatedPreserveAspectRatio.cc SVGPreserveAspectRatio.cc SVGElement.cc \
+ SVGStyleElement.cc SVGClipPathElement.cc SVGMaskElement.cc SVGColorProfileElement.cc SVGColorProfileRule.cc SVGZoomAndPan.cc SVGScriptElement.cc \
+ SVGSwitchElement.cc SVGSymbolElement.cc \
+ SVGDefinitionSrcElement.cc SVGFontFaceElement.cc SVGFontFaceFormatElement.cc SVGFontFaceNameElement.cc SVGFontFaceSrcElement.cc SVGHKernElement.cc SVGMetadataElement.cc SVGVKernElement.cc SVGCursorElement.cc SVGForeignObjectElement.cc SVGFontFaceUriElement.cc \
+ SVGElementInstance.cc SVGElementInstanceList.cc SVGAnimatedPoints.cc SVGAnimatedPathData.cc SVGMarkerElement.cc SVGViewSpec.cc SVGViewElement.cc \
+ SVGFilterElement.cc SVGFilterPrimitiveStandardAttributes.cc SVGFEBlendElement.cc SVGFEColorMatrixElement.cc SVGFEComponentTransferElement.cc SVGComponentTransferFunctionElement.cc SVGFEFuncAElement.cc SVGFEFuncBElement.cc SVGFEFuncGElement.cc SVGFEFuncRElement.cc SVGFECompositeElement.cc SVGFEConvolveMatrixElement.cc SVGFEFloodElement.cc SVGFEGaussianBlurElement.cc SVGFEDiffuseLightingElement.cc SVGFEDistantLightElement.cc SVGFEPointLightElement.cc SVGFESpotLightElement.cc SVGFEDisplacementMapElement.cc SVGFEMergeElement.cc SVGFEMergeNodeElement.cc SVGFEImageElement.cc SVGFEMorphologyElement.cc SVGFEOffsetElement.cc SVGFESpecularLightingElement.cc SVGFETileElement.cc SVGFETurbulenceElement.cc \
+ SVGAnimationElement.cc SVGAnimateElement.cc SVGSetElement.cc SVGAnimateMotionElement.cc SVGAnimateColorElement.cc SVGAnimateTransformElement.cc \
+ SVGEvent.cc SVGZoomEvent.cc SVGICCColor.cc SVGCSSRule.cc \
+ SVGGradientElement.cc SVGRadialGradientElement.cc SVGLinearGradientElement.cc SVGStopElement.cc SVGPatternElement.cc SVGMPathElement.cc \
+ SVGFontElement.cc SVGAltGlyphElement.cc SVGGlyphRefElement.cc SVGAltGlyphDefElement.cc SVGGlyphElement.cc SVGMissingGlyphElement.cc SVGPaint.cc SVGTextPathElement.cc SVGWindow.cc
+
+libksvgdom_la_METASOURCES = AUTO
+
+INCLUDES = -I$(top_srcdir)/ksvg/core -I$(top_srcdir)/ksvg/ecma -I$(top_srcdir)/ksvg/impl -I$(top_srcdir)/ksvg/impl/libs/libtext2path/src -I$(top_srcdir)/impl/ $(all_includes)
diff --git a/ksvg/dom/SVGAElement.cc b/ksvg/dom/SVGAElement.cc
new file mode 100644
index 00000000..a4d7d5b1
--- /dev/null
+++ b/ksvg/dom/SVGAElement.cc
@@ -0,0 +1,80 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAElement.h"
+#include "SVGAElementImpl.h"
+#include "SVGAnimatedString.h"
+
+using namespace KSVG;
+
+SVGAElement::SVGAElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable(), SVGURIReference()
+{
+ impl = 0;
+}
+
+SVGAElement::SVGAElement(const SVGAElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), SVGURIReference(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGAElement &SVGAElement::operator=(const SVGAElement &other)
+{
+ SVGElement::operator=(other);
+ SVGTests::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+ SVGTransformable::operator=(other);
+ SVGURIReference::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGAElement::SVGAElement(SVGAElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), SVGURIReference(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGAElement::~SVGAElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedString SVGAElement::target() const
+{
+ if(!impl) return SVGAnimatedString(0);
+ return SVGAnimatedString(impl->target());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAElement.h b/ksvg/dom/SVGAElement.h
new file mode 100644
index 00000000..98b0f54e
--- /dev/null
+++ b/ksvg/dom/SVGAElement.h
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAElement_H
+#define SVGAElement_H
+
+#include "SVGElement.h"
+#include "SVGTests.h"
+#include "SVGLangSpace.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+#include "SVGTransformable.h"
+#include "SVGURIReference.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedString;
+class SVGAElementImpl;
+class SVGAElement : public SVGElement,
+ public SVGTests,
+ public SVGLangSpace,
+ public SVGExternalResourcesRequired,
+ public SVGStylable,
+ public SVGTransformable,
+ public SVGURIReference
+{
+public:
+ SVGAElement();
+ SVGAElement(const SVGAElement &other);
+ SVGAElement &operator=(const SVGAElement &other);
+ SVGAElement(SVGAElementImpl *other);
+ virtual ~SVGAElement();
+
+ SVGAnimatedString target() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGAElementImpl *handle() const { return impl; }
+
+private:
+ SVGAElementImpl *impl;
+};
+
+}
+
+#endif
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAltGlyphDefElement.cc b/ksvg/dom/SVGAltGlyphDefElement.cc
new file mode 100644
index 00000000..f150b982
--- /dev/null
+++ b/ksvg/dom/SVGAltGlyphDefElement.cc
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAltGlyphDefElement.h"
+#include "SVGAltGlyphDefElementImpl.h"
+
+using namespace KSVG;
+
+SVGAltGlyphDefElement::SVGAltGlyphDefElement() : SVGElement()
+{
+ impl = 0;
+}
+
+SVGAltGlyphDefElement::SVGAltGlyphDefElement(const SVGAltGlyphDefElement &other) : SVGElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGAltGlyphDefElement &SVGAltGlyphDefElement::operator=(const SVGAltGlyphDefElement &other)
+{
+ SVGElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGAltGlyphDefElement::SVGAltGlyphDefElement(SVGAltGlyphDefElementImpl *other) : SVGElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGAltGlyphDefElement::~SVGAltGlyphDefElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAltGlyphDefElement.h b/ksvg/dom/SVGAltGlyphDefElement.h
new file mode 100644
index 00000000..c0672cf6
--- /dev/null
+++ b/ksvg/dom/SVGAltGlyphDefElement.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAltGlyphDefElement_H
+#define SVGAltGlyphDefElement_H
+
+#include "SVGElement.h"
+
+namespace KSVG
+{
+
+class SVGAltGlyphDefElementImpl;
+class SVGAltGlyphDefElement : public SVGElement
+{
+public:
+ SVGAltGlyphDefElement();
+ SVGAltGlyphDefElement(const SVGAltGlyphDefElement &other);
+ SVGAltGlyphDefElement &operator=(const SVGAltGlyphDefElement &other);
+ SVGAltGlyphDefElement(SVGAltGlyphDefElementImpl *other);
+ virtual ~SVGAltGlyphDefElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGAltGlyphDefElementImpl *handle() const { return impl; }
+
+private:
+ SVGAltGlyphDefElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAltGlyphElement.cc b/ksvg/dom/SVGAltGlyphElement.cc
new file mode 100644
index 00000000..33877a74
--- /dev/null
+++ b/ksvg/dom/SVGAltGlyphElement.cc
@@ -0,0 +1,80 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAltGlyphElement.h"
+#include "SVGAltGlyphElementImpl.h"
+
+using namespace KSVG;
+
+SVGAltGlyphElement::SVGAltGlyphElement() : SVGTextPositioningElement(), SVGURIReference()
+{
+ impl = 0;
+}
+
+SVGAltGlyphElement::SVGAltGlyphElement(const SVGAltGlyphElement &other) : SVGTextPositioningElement(other), SVGURIReference(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGAltGlyphElement &SVGAltGlyphElement::operator=(const SVGAltGlyphElement &other)
+{
+ SVGTextPositioningElement::operator=(other);
+ SVGURIReference::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGAltGlyphElement::SVGAltGlyphElement(SVGAltGlyphElementImpl *other) : SVGTextPositioningElement(other), SVGURIReference(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGAltGlyphElement::~SVGAltGlyphElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+DOM::DOMString SVGAltGlyphElement::format()
+{
+ if(!impl) return DOM::DOMString();
+ return impl->format();
+}
+
+DOM::DOMString SVGAltGlyphElement::glyphRef()
+{
+ if(!impl) return DOM::DOMString();
+ return impl->glyphRef();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAltGlyphElement.h b/ksvg/dom/SVGAltGlyphElement.h
new file mode 100644
index 00000000..191c67fe
--- /dev/null
+++ b/ksvg/dom/SVGAltGlyphElement.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAltGlyphElement_H
+#define SVGAltGlyphElement_H
+
+#include "SVGTextPositioningElement.h"
+#include "SVGURIReference.h"
+
+namespace KSVG
+{
+
+class SVGAltGlyphElementImpl;
+class SVGAltGlyphElement : public SVGTextPositioningElement,
+ public SVGURIReference
+{
+public:
+ SVGAltGlyphElement();
+ SVGAltGlyphElement(const SVGAltGlyphElement &other);
+ SVGAltGlyphElement &operator=(const SVGAltGlyphElement &other);
+ SVGAltGlyphElement(SVGAltGlyphElementImpl *other);
+ virtual ~SVGAltGlyphElement();
+
+ DOM::DOMString glyphRef();
+ DOM::DOMString format();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGAltGlyphElementImpl *handle() const { return impl; }
+
+private:
+ SVGAltGlyphElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAngle.cc b/ksvg/dom/SVGAngle.cc
new file mode 100644
index 00000000..c3cb1fae
--- /dev/null
+++ b/ksvg/dom/SVGAngle.cc
@@ -0,0 +1,120 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAngle.h"
+#include "SVGAngleImpl.h"
+
+using namespace KSVG;
+
+SVGAngle::SVGAngle()
+{
+ impl = new SVGAngleImpl();
+ impl->ref();
+}
+
+SVGAngle::SVGAngle(const SVGAngle &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGAngle &SVGAngle::operator =(const SVGAngle &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGAngle::SVGAngle(SVGAngleImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGAngle::~SVGAngle()
+{
+ if(impl)
+ impl->deref();
+}
+
+unsigned short SVGAngle::unitType() const
+{
+ if(!impl) return SVG_ANGLETYPE_UNKNOWN;
+ return impl->unitType();
+}
+
+void SVGAngle::setValue(float value)
+{
+ if(impl)
+ impl->setValue(value);
+}
+
+float SVGAngle::value() const
+{
+ if(!impl) return -1;
+ return impl->value();
+}
+
+void SVGAngle::setValueInSpecifiedUnits(float valueInSpecifiedUnits)
+{
+ if(impl)
+ impl->setValueInSpecifiedUnits(valueInSpecifiedUnits);
+}
+
+float SVGAngle::valueInSpecifiedUnits() const
+{
+ if(!impl) return -1;
+ return impl->valueInSpecifiedUnits();
+}
+
+void SVGAngle::setValueAsString(const DOM::DOMString &valueAsString)
+{
+ if(impl)
+ impl->setValueAsString(valueAsString);
+}
+
+DOM::DOMString SVGAngle::valueAsString() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->valueAsString();
+}
+
+void SVGAngle::newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits)
+{
+ if(impl)
+ impl->newValueSpecifiedUnits(unitType, valueInSpecifiedUnits);
+}
+
+void SVGAngle::convertToSpecifiedUnits(unsigned short unitType)
+{
+ if(impl)
+ impl->convertToSpecifiedUnits(unitType);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAngle.h b/ksvg/dom/SVGAngle.h
new file mode 100644
index 00000000..9e301660
--- /dev/null
+++ b/ksvg/dom/SVGAngle.h
@@ -0,0 +1,74 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAngle_H
+#define SVGAngle_H
+
+#include <dom/dom_string.h>
+
+namespace KSVG
+{
+
+enum
+{
+ SVG_ANGLETYPE_UNKNOWN = 0,
+ SVG_ANGLETYPE_UNSPECIFIED = 1,
+ SVG_ANGLETYPE_DEG = 2,
+ SVG_ANGLETYPE_RAD = 3,
+ SVG_ANGLETYPE_GRAD = 4
+};
+
+class SVGAngleImpl;
+class SVGAngle
+{
+public:
+
+ SVGAngle();
+ SVGAngle(const SVGAngle &other);
+ SVGAngle &operator=(const SVGAngle &other);
+ SVGAngle(SVGAngleImpl *other);
+ ~SVGAngle();
+
+ unsigned short unitType() const;
+
+ void setValue(float value);
+ float value() const;
+
+ void setValueInSpecifiedUnits(float valueInSpecifiedUnits);
+ float valueInSpecifiedUnits() const;
+
+ void setValueAsString(const DOM::DOMString &valueAsString);
+ DOM::DOMString valueAsString() const;
+
+ void newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits);
+ void convertToSpecifiedUnits(unsigned short unitType);
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGAngleImpl *handle() const { return impl; }
+
+private:
+ SVGAngleImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimateColorElement.cc b/ksvg/dom/SVGAnimateColorElement.cc
new file mode 100644
index 00000000..0090513f
--- /dev/null
+++ b/ksvg/dom/SVGAnimateColorElement.cc
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimateColorElement.h"
+#include "SVGAnimateColorElementImpl.h"
+
+using namespace KSVG;
+
+SVGAnimateColorElement::SVGAnimateColorElement() : SVGAnimationElement()
+{
+ impl = 0;
+}
+
+SVGAnimateColorElement::SVGAnimateColorElement(const SVGAnimateColorElement &other) : SVGAnimationElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGAnimateColorElement &SVGAnimateColorElement::operator=(const SVGAnimateColorElement &other)
+{
+ SVGAnimationElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGAnimateColorElement::SVGAnimateColorElement(SVGAnimateColorElementImpl *other) : SVGAnimationElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGAnimateColorElement::~SVGAnimateColorElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimateColorElement.h b/ksvg/dom/SVGAnimateColorElement.h
new file mode 100644
index 00000000..3e5d1616
--- /dev/null
+++ b/ksvg/dom/SVGAnimateColorElement.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimateColorElement_H
+#define SVGAnimateColorElement_H
+
+#include "SVGAnimationElement.h"
+
+namespace KSVG
+{
+
+class SVGAnimateColorElementImpl;
+class SVGAnimateColorElement : public SVGAnimationElement
+{
+public:
+ SVGAnimateColorElement();
+ SVGAnimateColorElement(const SVGAnimateColorElement &other);
+ SVGAnimateColorElement &operator=(const SVGAnimateColorElement &other);
+ SVGAnimateColorElement(SVGAnimateColorElementImpl *other);
+ virtual ~SVGAnimateColorElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGAnimateColorElementImpl *handle() const { return impl; }
+
+private:
+ SVGAnimateColorElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimateElement.cc b/ksvg/dom/SVGAnimateElement.cc
new file mode 100644
index 00000000..b0b4503e
--- /dev/null
+++ b/ksvg/dom/SVGAnimateElement.cc
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimateElement.h"
+#include "SVGAnimateElementImpl.h"
+
+using namespace KSVG;
+
+SVGAnimateElement::SVGAnimateElement() : SVGAnimationElement()
+{
+ impl = 0;
+}
+
+SVGAnimateElement::SVGAnimateElement(const SVGAnimateElement &other) : SVGAnimationElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGAnimateElement &SVGAnimateElement::operator=(const SVGAnimateElement &other)
+{
+ SVGAnimationElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGAnimateElement::SVGAnimateElement(SVGAnimateElementImpl *other) : SVGAnimationElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGAnimateElement::~SVGAnimateElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimateElement.h b/ksvg/dom/SVGAnimateElement.h
new file mode 100644
index 00000000..5856f9b2
--- /dev/null
+++ b/ksvg/dom/SVGAnimateElement.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimateElement_H
+#define SVGAnimateElement_H
+
+#include "SVGAnimationElement.h"
+
+namespace KSVG
+{
+
+class SVGAnimateElementImpl;
+class SVGAnimateElement : public SVGAnimationElement
+{
+public:
+ SVGAnimateElement();
+ SVGAnimateElement(const SVGAnimateElement &other);
+ SVGAnimateElement &operator=(const SVGAnimateElement &other);
+ SVGAnimateElement(SVGAnimateElementImpl *other);
+ virtual ~SVGAnimateElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGAnimateElementImpl *handle() const { return impl; }
+
+private:
+ SVGAnimateElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimateMotionElement.cc b/ksvg/dom/SVGAnimateMotionElement.cc
new file mode 100644
index 00000000..f2758fe3
--- /dev/null
+++ b/ksvg/dom/SVGAnimateMotionElement.cc
@@ -0,0 +1,65 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimateMotionElement.h"
+#include "SVGAnimateMotionElementImpl.h"
+
+using namespace KSVG;
+
+SVGAnimateMotionElement::SVGAnimateMotionElement() : SVGAnimationElement()
+{
+ impl = 0;
+}
+
+SVGAnimateMotionElement::SVGAnimateMotionElement(const SVGAnimateMotionElement &other) : SVGAnimationElement(), impl(0)
+{
+ (*this) = other;
+}
+
+SVGAnimateMotionElement &SVGAnimateMotionElement::operator =(const SVGAnimateMotionElement &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGAnimateMotionElement::SVGAnimateMotionElement(SVGAnimateMotionElementImpl *other) : SVGAnimationElement()
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGAnimateMotionElement::~SVGAnimateMotionElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimateMotionElement.h b/ksvg/dom/SVGAnimateMotionElement.h
new file mode 100644
index 00000000..62b477b0
--- /dev/null
+++ b/ksvg/dom/SVGAnimateMotionElement.h
@@ -0,0 +1,47 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimateMotionElement_H
+#define SVGAnimateMotionElement_H
+
+#include "SVGAnimationElement.h"
+
+namespace KSVG
+{
+
+class SVGAnimateMotionElementImpl;
+class SVGAnimateMotionElement : public SVGAnimationElement
+{
+public:
+ SVGAnimateMotionElement();
+ SVGAnimateMotionElement(const SVGAnimateMotionElement &other);
+ SVGAnimateMotionElement &operator=(const SVGAnimateMotionElement &other);
+ SVGAnimateMotionElement(SVGAnimateMotionElementImpl *other);
+ virtual ~SVGAnimateMotionElement();
+
+private:
+ SVGAnimateMotionElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimateTransformElement.cc b/ksvg/dom/SVGAnimateTransformElement.cc
new file mode 100644
index 00000000..91bbb9a3
--- /dev/null
+++ b/ksvg/dom/SVGAnimateTransformElement.cc
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimateTransformElement.h"
+#include "SVGAnimateTransformElementImpl.h"
+
+using namespace KSVG;
+
+SVGAnimateTransformElement::SVGAnimateTransformElement() : SVGAnimationElement()
+{
+ impl = 0;
+}
+
+SVGAnimateTransformElement::SVGAnimateTransformElement(const SVGAnimateTransformElement &other) : SVGAnimationElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGAnimateTransformElement &SVGAnimateTransformElement::operator=(const SVGAnimateTransformElement &other)
+{
+ SVGAnimationElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGAnimateTransformElement::SVGAnimateTransformElement(SVGAnimateTransformElementImpl *other) : SVGAnimationElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGAnimateTransformElement::~SVGAnimateTransformElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimateTransformElement.h b/ksvg/dom/SVGAnimateTransformElement.h
new file mode 100644
index 00000000..b6c1a5ad
--- /dev/null
+++ b/ksvg/dom/SVGAnimateTransformElement.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimateTransformElement_H
+#define SVGAnimateTransformElement_H
+
+#include "SVGAnimationElement.h"
+
+namespace KSVG
+{
+
+class SVGAnimateTransformElementImpl;
+class SVGAnimateTransformElement : public SVGAnimationElement
+{
+public:
+ SVGAnimateTransformElement();
+ SVGAnimateTransformElement(const SVGAnimateTransformElement &other);
+ SVGAnimateTransformElement &operator=(const SVGAnimateTransformElement &other);
+ SVGAnimateTransformElement(SVGAnimateTransformElementImpl *other);
+ virtual ~SVGAnimateTransformElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGAnimateTransformElementImpl *handle() const { return impl; }
+
+private:
+ SVGAnimateTransformElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedAngle.cc b/ksvg/dom/SVGAnimatedAngle.cc
new file mode 100644
index 00000000..b8c4ff4d
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedAngle.cc
@@ -0,0 +1,79 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedAngle.h"
+#include "SVGAnimatedAngleImpl.h"
+#include "SVGAngle.h"
+
+using namespace KSVG;
+
+SVGAnimatedAngle::SVGAnimatedAngle()
+{
+ impl = new SVGAnimatedAngleImpl();
+ impl->ref();
+}
+
+SVGAnimatedAngle::SVGAnimatedAngle(const SVGAnimatedAngle &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGAnimatedAngle &SVGAnimatedAngle::operator=(const SVGAnimatedAngle &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGAnimatedAngle::SVGAnimatedAngle(SVGAnimatedAngleImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGAnimatedAngle::~SVGAnimatedAngle()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAngle SVGAnimatedAngle::baseVal() const
+{
+ if(!impl) return SVGAngle(0);
+ return SVGAngle(impl->baseVal());
+}
+
+SVGAngle SVGAnimatedAngle::animVal() const
+{
+ if(!impl) return SVGAngle(0);
+ return SVGAngle(impl->animVal());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedAngle.h b/ksvg/dom/SVGAnimatedAngle.h
new file mode 100644
index 00000000..156b9c39
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedAngle.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedAngle_H
+#define SVGAnimatedAngle_H
+
+namespace KSVG
+{
+
+class SVGAngle;
+class SVGAnimatedAngleImpl;
+class SVGAnimatedAngle
+{
+public:
+ SVGAnimatedAngle();
+ SVGAnimatedAngle(const SVGAnimatedAngle &other);
+ SVGAnimatedAngle &operator=(const SVGAnimatedAngle &other);
+ SVGAnimatedAngle(SVGAnimatedAngleImpl *other);
+ ~SVGAnimatedAngle();
+
+ SVGAngle baseVal() const;
+ SVGAngle animVal() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGAnimatedAngleImpl *handle() const { return impl; }
+
+private:
+ SVGAnimatedAngleImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedBoolean.cc b/ksvg/dom/SVGAnimatedBoolean.cc
new file mode 100644
index 00000000..40bb765b
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedBoolean.cc
@@ -0,0 +1,84 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedBoolean.h"
+#include "SVGAnimatedBooleanImpl.h"
+
+using namespace KSVG;
+
+SVGAnimatedBoolean::SVGAnimatedBoolean()
+{
+ impl = new SVGAnimatedBooleanImpl();
+ impl->ref();
+}
+
+SVGAnimatedBoolean::SVGAnimatedBoolean(const SVGAnimatedBoolean &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGAnimatedBoolean &SVGAnimatedBoolean::operator=(const SVGAnimatedBoolean &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGAnimatedBoolean::SVGAnimatedBoolean(SVGAnimatedBooleanImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGAnimatedBoolean::~SVGAnimatedBoolean()
+{
+ if(impl)
+ impl->deref();
+}
+
+void SVGAnimatedBoolean::setBaseVal(bool baseVal)
+{
+ if(impl)
+ impl->setBaseVal(baseVal);
+}
+
+bool SVGAnimatedBoolean::baseVal() const
+{
+ if(!impl) return false;
+ return impl->baseVal();
+}
+
+bool SVGAnimatedBoolean::animVal() const
+{
+ if(!impl) return false;
+ return impl->animVal();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedBoolean.h b/ksvg/dom/SVGAnimatedBoolean.h
new file mode 100644
index 00000000..c223fa9a
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedBoolean.h
@@ -0,0 +1,53 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedBoolean_H
+#define SVGAnimatedBoolean_H
+
+namespace KSVG
+{
+
+class SVGAnimatedBooleanImpl;
+class SVGAnimatedBoolean
+{
+public:
+ SVGAnimatedBoolean();
+ SVGAnimatedBoolean(const SVGAnimatedBoolean &other);
+ SVGAnimatedBoolean &operator=(const SVGAnimatedBoolean &other);
+ SVGAnimatedBoolean(SVGAnimatedBooleanImpl *other);
+ ~SVGAnimatedBoolean();
+
+ void setBaseVal(bool baseVal);
+ bool baseVal() const;
+
+ bool animVal() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGAnimatedBooleanImpl *handle() const { return impl; }
+
+private:
+ SVGAnimatedBooleanImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedEnumeration.cc b/ksvg/dom/SVGAnimatedEnumeration.cc
new file mode 100644
index 00000000..2e9610d4
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedEnumeration.cc
@@ -0,0 +1,84 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedEnumeration.h"
+#include "SVGAnimatedEnumerationImpl.h"
+
+using namespace KSVG;
+
+SVGAnimatedEnumeration::SVGAnimatedEnumeration()
+{
+ impl = new SVGAnimatedEnumerationImpl();
+ impl->ref();
+}
+
+SVGAnimatedEnumeration::SVGAnimatedEnumeration(const SVGAnimatedEnumeration &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGAnimatedEnumeration &SVGAnimatedEnumeration::operator=(const SVGAnimatedEnumeration &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGAnimatedEnumeration::SVGAnimatedEnumeration(SVGAnimatedEnumerationImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGAnimatedEnumeration::~SVGAnimatedEnumeration()
+{
+ if(impl)
+ impl->deref();
+}
+
+void SVGAnimatedEnumeration::setBaseVal(unsigned short baseVal)
+{
+ if(impl)
+ impl->setBaseVal(baseVal);
+}
+
+unsigned short SVGAnimatedEnumeration::baseVal() const
+{
+ if(!impl) return 0;
+ return impl->baseVal();
+}
+
+unsigned short SVGAnimatedEnumeration::animVal() const
+{
+ if(!impl) return 0;
+ return impl->animVal();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedEnumeration.h b/ksvg/dom/SVGAnimatedEnumeration.h
new file mode 100644
index 00000000..79f75a67
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedEnumeration.h
@@ -0,0 +1,53 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedEnumeration_H
+#define SVGAnimatedEnumeration_H
+
+namespace KSVG
+{
+
+class SVGAnimatedEnumerationImpl;
+class SVGAnimatedEnumeration
+{
+public:
+ SVGAnimatedEnumeration();
+ SVGAnimatedEnumeration(const SVGAnimatedEnumeration &other);
+ SVGAnimatedEnumeration &operator=(const SVGAnimatedEnumeration &other);
+ SVGAnimatedEnumeration(SVGAnimatedEnumerationImpl *other);
+ ~SVGAnimatedEnumeration();
+
+ void setBaseVal(unsigned short baseVal);
+ unsigned short baseVal() const;
+
+ unsigned short animVal() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGAnimatedEnumerationImpl *handle() const { return impl; }
+
+private:
+ SVGAnimatedEnumerationImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedInteger.cc b/ksvg/dom/SVGAnimatedInteger.cc
new file mode 100644
index 00000000..df5f9011
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedInteger.cc
@@ -0,0 +1,84 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedInteger.h"
+#include "SVGAnimatedIntegerImpl.h"
+
+using namespace KSVG;
+
+SVGAnimatedInteger::SVGAnimatedInteger()
+{
+ impl = new SVGAnimatedIntegerImpl();
+ impl->ref();
+}
+
+SVGAnimatedInteger::SVGAnimatedInteger(const SVGAnimatedInteger &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGAnimatedInteger &SVGAnimatedInteger::operator=(const SVGAnimatedInteger &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGAnimatedInteger::SVGAnimatedInteger(SVGAnimatedIntegerImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGAnimatedInteger::~SVGAnimatedInteger()
+{
+ if(impl)
+ impl->deref();
+}
+
+void SVGAnimatedInteger::setBaseVal(long baseVal)
+{
+ if(impl)
+ impl->setBaseVal(baseVal);
+}
+
+long SVGAnimatedInteger::baseVal() const
+{
+ if(!impl) return -1;
+ return impl->baseVal();
+}
+
+long SVGAnimatedInteger::animVal() const
+{
+ if(!impl) return -1;
+ return impl->animVal();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedInteger.h b/ksvg/dom/SVGAnimatedInteger.h
new file mode 100644
index 00000000..495cda75
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedInteger.h
@@ -0,0 +1,53 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedInteger_H
+#define SVGAnimatedInteger_H
+
+namespace KSVG
+{
+
+class SVGAnimatedIntegerImpl;
+class SVGAnimatedInteger
+{
+public:
+ SVGAnimatedInteger();
+ SVGAnimatedInteger(const SVGAnimatedInteger &other);
+ SVGAnimatedInteger &operator=(const SVGAnimatedInteger &other);
+ SVGAnimatedInteger(SVGAnimatedIntegerImpl *other);
+ ~SVGAnimatedInteger();
+
+ void setBaseVal(long baseVal);
+ long baseVal() const;
+
+ long animVal() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGAnimatedIntegerImpl *handle() const { return impl; }
+
+private:
+ SVGAnimatedIntegerImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedLength.cc b/ksvg/dom/SVGAnimatedLength.cc
new file mode 100644
index 00000000..50172f13
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedLength.cc
@@ -0,0 +1,79 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedLength.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGLength.h"
+
+using namespace KSVG;
+
+SVGAnimatedLength::SVGAnimatedLength()
+{
+ impl = new SVGAnimatedLengthImpl();
+ impl->ref();
+}
+
+SVGAnimatedLength::SVGAnimatedLength(const SVGAnimatedLength &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGAnimatedLength &SVGAnimatedLength::operator=(const SVGAnimatedLength &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGAnimatedLength::SVGAnimatedLength(SVGAnimatedLengthImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGAnimatedLength::~SVGAnimatedLength()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGLength SVGAnimatedLength::baseVal() const
+{
+ if(!impl) return SVGLength(0);
+ return SVGLength(impl->baseVal());
+}
+
+SVGLength SVGAnimatedLength::animVal() const
+{
+ if(!impl) return SVGLength(0);
+ return SVGLength(impl->animVal());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedLength.h b/ksvg/dom/SVGAnimatedLength.h
new file mode 100644
index 00000000..a59792e3
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedLength.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedLength_H
+#define SVGAnimatedLength_H
+
+namespace KSVG
+{
+
+class SVGLength;
+class SVGAnimatedLengthImpl;
+class SVGAnimatedLength
+{
+public:
+ SVGAnimatedLength();
+ SVGAnimatedLength(const SVGAnimatedLength &other);
+ SVGAnimatedLength &operator=(const SVGAnimatedLength &other);
+ SVGAnimatedLength(SVGAnimatedLengthImpl *other);
+ ~SVGAnimatedLength();
+
+ SVGLength baseVal() const;
+ SVGLength animVal() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGAnimatedLengthImpl *handle() const { return impl; }
+
+private:
+ SVGAnimatedLengthImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedLengthList.cc b/ksvg/dom/SVGAnimatedLengthList.cc
new file mode 100644
index 00000000..f1e9c001
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedLengthList.cc
@@ -0,0 +1,78 @@
+/*
+ Copyright (C) 2002 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedLengthList.h"
+#include "SVGAnimatedLengthListImpl.h"
+
+using namespace KSVG;
+
+SVGAnimatedLengthList::SVGAnimatedLengthList()
+{
+ impl = new SVGAnimatedLengthListImpl();
+ impl->ref();
+}
+
+SVGAnimatedLengthList::SVGAnimatedLengthList(const SVGAnimatedLengthList &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGAnimatedLengthList &SVGAnimatedLengthList::operator=(const SVGAnimatedLengthList &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGAnimatedLengthList::SVGAnimatedLengthList(SVGAnimatedLengthListImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGAnimatedLengthList::~SVGAnimatedLengthList()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGLengthList SVGAnimatedLengthList::baseVal() const
+{
+ if(!impl) return 0;
+ return impl->animVal();
+}
+
+SVGLengthList SVGAnimatedLengthList::animVal() const
+{
+ if(!impl) return 0;
+ return impl->baseVal();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedLengthList.h b/ksvg/dom/SVGAnimatedLengthList.h
new file mode 100644
index 00000000..80eafb03
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedLengthList.h
@@ -0,0 +1,51 @@
+/*
+ Copyright (C) 2002 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedLengthList_H
+#define SVGAnimatedLengthList_H
+
+#include "SVGLengthList.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedLengthListImpl;
+class SVGAnimatedLengthList
+{
+public:
+ SVGAnimatedLengthList();
+ SVGAnimatedLengthList(const SVGAnimatedLengthList &);
+ SVGAnimatedLengthList &operator=(const SVGAnimatedLengthList &);
+ SVGAnimatedLengthList(SVGAnimatedLengthListImpl *);
+ ~SVGAnimatedLengthList();
+
+ SVGLengthList baseVal() const;
+ SVGLengthList animVal() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGAnimatedLengthListImpl *handle() const { return impl; }
+
+private:
+ SVGAnimatedLengthListImpl *impl;
+};
+
+}
+
+#endif
diff --git a/ksvg/dom/SVGAnimatedNumber.cc b/ksvg/dom/SVGAnimatedNumber.cc
new file mode 100644
index 00000000..9e801842
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedNumber.cc
@@ -0,0 +1,84 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedNumber.h"
+#include "SVGAnimatedNumberImpl.h"
+
+using namespace KSVG;
+
+SVGAnimatedNumber::SVGAnimatedNumber()
+{
+ impl = new SVGAnimatedNumberImpl();
+ impl->ref();
+}
+
+SVGAnimatedNumber::SVGAnimatedNumber(const SVGAnimatedNumber &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGAnimatedNumber &SVGAnimatedNumber::operator=(const SVGAnimatedNumber &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGAnimatedNumber::SVGAnimatedNumber(SVGAnimatedNumberImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGAnimatedNumber::~SVGAnimatedNumber()
+{
+ if(impl)
+ impl->deref();
+}
+
+void SVGAnimatedNumber::setBaseVal(float baseVal)
+{
+ if(impl)
+ impl->setBaseVal(baseVal);
+}
+
+float SVGAnimatedNumber::baseVal() const
+{
+ if(!impl) return -1;
+ return impl->baseVal();
+}
+
+float SVGAnimatedNumber::animVal() const
+{
+ if(!impl) return -1;
+ return impl->animVal();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedNumber.h b/ksvg/dom/SVGAnimatedNumber.h
new file mode 100644
index 00000000..8c3f1670
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedNumber.h
@@ -0,0 +1,53 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedNumber_H
+#define SVGAnimatedNumber_H
+
+namespace KSVG
+{
+
+class SVGAnimatedNumberImpl;
+class SVGAnimatedNumber
+{
+public:
+ SVGAnimatedNumber();
+ SVGAnimatedNumber(const SVGAnimatedNumber &other);
+ SVGAnimatedNumber &operator=(const SVGAnimatedNumber &other);
+ SVGAnimatedNumber(SVGAnimatedNumberImpl *other);
+ ~SVGAnimatedNumber();
+
+ void setBaseVal(float baseVal);
+ float baseVal() const;
+
+ float animVal() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGAnimatedNumberImpl *handle() const { return impl; }
+
+private:
+ SVGAnimatedNumberImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedNumberList.cc b/ksvg/dom/SVGAnimatedNumberList.cc
new file mode 100644
index 00000000..66881cac
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedNumberList.cc
@@ -0,0 +1,78 @@
+/*
+ Copyright (C) 2002 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedNumberList.h"
+#include "SVGAnimatedNumberListImpl.h"
+
+using namespace KSVG;
+
+SVGAnimatedNumberList::SVGAnimatedNumberList()
+{
+ impl = new SVGAnimatedNumberListImpl();
+ impl->ref();
+}
+
+SVGAnimatedNumberList::SVGAnimatedNumberList(const SVGAnimatedNumberList &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGAnimatedNumberList &SVGAnimatedNumberList::operator=(const SVGAnimatedNumberList &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGAnimatedNumberList::SVGAnimatedNumberList(SVGAnimatedNumberListImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGAnimatedNumberList::~SVGAnimatedNumberList()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGNumberList SVGAnimatedNumberList::baseVal() const
+{
+ if(!impl) return 0;
+ return impl->animVal();
+}
+
+SVGNumberList SVGAnimatedNumberList::animVal() const
+{
+ if(!impl) return 0;
+ return impl->baseVal();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedNumberList.h b/ksvg/dom/SVGAnimatedNumberList.h
new file mode 100644
index 00000000..525ce0fd
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedNumberList.h
@@ -0,0 +1,51 @@
+/*
+ Copyright (C) 2002 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedNumberList_H
+#define SVGAnimatedNumberList_H
+
+#include "SVGNumberList.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedNumberListImpl;
+class SVGAnimatedNumberList
+{
+public:
+ SVGAnimatedNumberList();
+ SVGAnimatedNumberList(const SVGAnimatedNumberList &);
+ SVGAnimatedNumberList &operator=(const SVGAnimatedNumberList &);
+ SVGAnimatedNumberList(SVGAnimatedNumberListImpl *);
+ ~SVGAnimatedNumberList();
+
+ SVGNumberList baseVal() const;
+ SVGNumberList animVal() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGAnimatedNumberListImpl *handle() const { return impl; }
+
+private:
+ SVGAnimatedNumberListImpl *impl;
+};
+
+}
+
+#endif
diff --git a/ksvg/dom/SVGAnimatedPathData.cc b/ksvg/dom/SVGAnimatedPathData.cc
new file mode 100644
index 00000000..d332f567
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedPathData.cc
@@ -0,0 +1,91 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedPathData.h"
+#include "SVGAnimatedPathDataImpl.h"
+#include "SVGPathSegList.h"
+
+using namespace KSVG;
+
+SVGAnimatedPathData::SVGAnimatedPathData()
+{
+ impl = new SVGAnimatedPathDataImpl();
+ impl->ref();
+}
+
+SVGAnimatedPathData::SVGAnimatedPathData(const SVGAnimatedPathData &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGAnimatedPathData &SVGAnimatedPathData::operator=(const SVGAnimatedPathData &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGAnimatedPathData::SVGAnimatedPathData(SVGAnimatedPathDataImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGAnimatedPathData::~SVGAnimatedPathData()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGPathSegList SVGAnimatedPathData::pathSegList() const
+{
+ if(!impl) return SVGPathSegList(0);
+ return SVGPathSegList(impl->pathSegList());
+}
+
+SVGPathSegList SVGAnimatedPathData::normalizedPathSegList() const
+{
+ if(!impl) return SVGPathSegList(0);
+ return SVGPathSegList(impl->normalizedPathSegList());
+}
+
+SVGPathSegList SVGAnimatedPathData::animatedPathSegList() const
+{
+ if(!impl) return SVGPathSegList(0);
+ return SVGPathSegList(impl->animatedPathSegList());
+}
+
+SVGPathSegList SVGAnimatedPathData::animatedNormalizedPathSegList() const
+{
+ if(!impl) return SVGPathSegList(0);
+ return SVGPathSegList(impl->animatedNormalizedPathSegList());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedPathData.h b/ksvg/dom/SVGAnimatedPathData.h
new file mode 100644
index 00000000..06ae2905
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedPathData.h
@@ -0,0 +1,54 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedPathData_H
+#define SVGAnimatedPathData_H
+
+namespace KSVG
+{
+
+class SVGPathSegList;
+class SVGAnimatedPathDataImpl;
+class SVGAnimatedPathData
+{
+public:
+ SVGAnimatedPathData();
+ SVGAnimatedPathData(const SVGAnimatedPathData &other);
+ SVGAnimatedPathData &operator=(const SVGAnimatedPathData &other);
+ SVGAnimatedPathData(SVGAnimatedPathDataImpl *other);
+ virtual ~SVGAnimatedPathData();
+
+ SVGPathSegList pathSegList() const;
+ SVGPathSegList normalizedPathSegList() const;
+ SVGPathSegList animatedPathSegList() const;
+ SVGPathSegList animatedNormalizedPathSegList() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGAnimatedPathDataImpl *handle() const { return impl; }
+
+private:
+ SVGAnimatedPathDataImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedPoints.cc b/ksvg/dom/SVGAnimatedPoints.cc
new file mode 100644
index 00000000..cc4e999d
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedPoints.cc
@@ -0,0 +1,79 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedPoints.h"
+#include "SVGAnimatedPointsImpl.h"
+#include "SVGPointList.h"
+
+using namespace KSVG;
+
+SVGAnimatedPoints::SVGAnimatedPoints()
+{
+ impl = new SVGAnimatedPointsImpl();
+ impl->ref();
+}
+
+SVGAnimatedPoints::SVGAnimatedPoints(const SVGAnimatedPoints &other) : impl(0)
+{
+ (*this) = other;;
+}
+
+SVGAnimatedPoints &SVGAnimatedPoints::operator=(const SVGAnimatedPoints &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGAnimatedPoints::SVGAnimatedPoints(SVGAnimatedPointsImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGAnimatedPoints::~SVGAnimatedPoints()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGPointList SVGAnimatedPoints::points() const
+{
+ if(!impl) return SVGPointList(0);
+ return SVGPointList(impl->points());
+}
+
+SVGPointList SVGAnimatedPoints::animatedPoints() const
+{
+ if(!impl) return SVGPointList(0);
+ return SVGPointList(impl->animatedPoints());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedPoints.h b/ksvg/dom/SVGAnimatedPoints.h
new file mode 100644
index 00000000..3f035722
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedPoints.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedPoints_H
+#define SVGAnimatedPoints_H
+
+namespace KSVG
+{
+
+class SVGPointList;
+class SVGAnimatedPointsImpl;
+class SVGAnimatedPoints
+{
+public:
+ SVGAnimatedPoints();
+ SVGAnimatedPoints(const SVGAnimatedPoints &other);
+ SVGAnimatedPoints &operator=(const SVGAnimatedPoints &other);
+ SVGAnimatedPoints(SVGAnimatedPointsImpl *other);
+ virtual ~SVGAnimatedPoints();
+
+ SVGPointList points() const;
+ SVGPointList animatedPoints() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGAnimatedPointsImpl *handle() const { return impl; }
+
+private:
+ SVGAnimatedPointsImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedPreserveAspectRatio.cc b/ksvg/dom/SVGAnimatedPreserveAspectRatio.cc
new file mode 100644
index 00000000..ed157028
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedPreserveAspectRatio.cc
@@ -0,0 +1,79 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedPreserveAspectRatio.h"
+#include "SVGAnimatedPreserveAspectRatioImpl.h"
+#include "SVGPreserveAspectRatio.h"
+
+using namespace KSVG;
+
+SVGAnimatedPreserveAspectRatio::SVGAnimatedPreserveAspectRatio()
+{
+ impl = new SVGAnimatedPreserveAspectRatioImpl();
+ impl->ref();
+}
+
+SVGAnimatedPreserveAspectRatio::SVGAnimatedPreserveAspectRatio(const SVGAnimatedPreserveAspectRatio &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGAnimatedPreserveAspectRatio &SVGAnimatedPreserveAspectRatio::operator=(const SVGAnimatedPreserveAspectRatio &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGAnimatedPreserveAspectRatio::SVGAnimatedPreserveAspectRatio(SVGAnimatedPreserveAspectRatioImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGAnimatedPreserveAspectRatio::~SVGAnimatedPreserveAspectRatio()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGPreserveAspectRatio SVGAnimatedPreserveAspectRatio::baseVal() const
+{
+ if(!impl) return SVGPreserveAspectRatio(0);
+ return SVGPreserveAspectRatio(impl->baseVal());
+}
+
+SVGPreserveAspectRatio SVGAnimatedPreserveAspectRatio::animVal() const
+{
+ if(!impl) return SVGPreserveAspectRatio(0);
+ return SVGPreserveAspectRatio(impl->animVal());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedPreserveAspectRatio.h b/ksvg/dom/SVGAnimatedPreserveAspectRatio.h
new file mode 100644
index 00000000..4eea042f
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedPreserveAspectRatio.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedPreserveAspectRatio_H
+#define SVGAnimatedPreserveAspectRatio_H
+
+
+namespace KSVG
+{
+
+class SVGPreserveAspectRatio;
+class SVGAnimatedPreserveAspectRatioImpl;
+class SVGAnimatedPreserveAspectRatio
+{
+public:
+ SVGAnimatedPreserveAspectRatio();
+ SVGAnimatedPreserveAspectRatio(const SVGAnimatedPreserveAspectRatio &other);
+ SVGAnimatedPreserveAspectRatio &operator=(const SVGAnimatedPreserveAspectRatio &other);
+ SVGAnimatedPreserveAspectRatio(SVGAnimatedPreserveAspectRatioImpl *other);
+ ~SVGAnimatedPreserveAspectRatio();
+
+ SVGPreserveAspectRatio baseVal() const;
+ SVGPreserveAspectRatio animVal() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGAnimatedPreserveAspectRatioImpl *handle() const { return impl; }
+
+private:
+ SVGAnimatedPreserveAspectRatioImpl *impl;
+};
+
+}
+
+#endif
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedRect.cc b/ksvg/dom/SVGAnimatedRect.cc
new file mode 100644
index 00000000..2c315003
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedRect.cc
@@ -0,0 +1,79 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedRect.h"
+#include "SVGAnimatedRectImpl.h"
+#include "SVGRect.h"
+
+using namespace KSVG;
+
+SVGAnimatedRect::SVGAnimatedRect()
+{
+ impl = new SVGAnimatedRectImpl();
+ impl->ref();
+}
+
+SVGAnimatedRect::SVGAnimatedRect(const SVGAnimatedRect &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGAnimatedRect &SVGAnimatedRect::operator=(const SVGAnimatedRect &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGAnimatedRect::SVGAnimatedRect(SVGAnimatedRectImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGAnimatedRect::~SVGAnimatedRect()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGRect SVGAnimatedRect::baseVal() const
+{
+ if(!impl) return SVGRect(0);
+ return SVGRect(impl->baseVal());
+}
+
+SVGRect SVGAnimatedRect::animVal() const
+{
+ if(!impl) return SVGRect(0);
+ return SVGRect(impl->animVal());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedRect.h b/ksvg/dom/SVGAnimatedRect.h
new file mode 100644
index 00000000..c45a8f2d
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedRect.h
@@ -0,0 +1,51 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedRect_H
+#define SVGAnimatedRect_H
+
+namespace KSVG
+{
+
+class SVGRect;
+class SVGAnimatedRectImpl;
+class SVGAnimatedRect
+{
+public:
+ SVGAnimatedRect();
+ SVGAnimatedRect(const SVGAnimatedRect &other);
+ SVGAnimatedRect &operator=(const SVGAnimatedRect &other);
+ SVGAnimatedRect(SVGAnimatedRectImpl *other);
+ ~SVGAnimatedRect();
+
+ SVGRect baseVal() const;
+ SVGRect animVal() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGAnimatedRectImpl *handle() const { return impl; }
+
+private:
+ SVGAnimatedRectImpl *impl;
+};
+
+}
+
+#endif
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedString.cc b/ksvg/dom/SVGAnimatedString.cc
new file mode 100644
index 00000000..5d22f4ae
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedString.cc
@@ -0,0 +1,84 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedString.h"
+#include "SVGAnimatedStringImpl.h"
+
+using namespace KSVG;
+
+SVGAnimatedString::SVGAnimatedString()
+{
+ impl = new SVGAnimatedStringImpl();
+ impl->ref();
+}
+
+SVGAnimatedString::SVGAnimatedString(const SVGAnimatedString &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGAnimatedString &SVGAnimatedString::operator=(const SVGAnimatedString &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGAnimatedString::SVGAnimatedString(SVGAnimatedStringImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGAnimatedString::~SVGAnimatedString()
+{
+ if(impl)
+ impl->deref();
+}
+
+void SVGAnimatedString::setBaseVal(const DOM::DOMString &baseVal)
+{
+ if(impl)
+ impl->setBaseVal(baseVal);
+}
+
+DOM::DOMString SVGAnimatedString::baseVal() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->baseVal();
+}
+
+DOM::DOMString SVGAnimatedString::animVal() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->animVal();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedString.h b/ksvg/dom/SVGAnimatedString.h
new file mode 100644
index 00000000..f97bb5c8
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedString.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedString_H
+#define SVGAnimatedString_H
+
+#include <dom/dom_string.h>
+
+namespace KSVG
+{
+
+class SVGAnimatedStringImpl;
+class SVGAnimatedString
+{
+public:
+ SVGAnimatedString();
+ SVGAnimatedString(const SVGAnimatedString &other);
+ SVGAnimatedString &operator=(const SVGAnimatedString &other);
+ SVGAnimatedString(SVGAnimatedStringImpl *other);
+ ~SVGAnimatedString();
+
+ void setBaseVal(const DOM::DOMString &baseVal);
+ DOM::DOMString baseVal() const;
+
+ DOM::DOMString animVal() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGAnimatedStringImpl *handle() const { return impl; }
+
+private:
+ SVGAnimatedStringImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedTransformList.cc b/ksvg/dom/SVGAnimatedTransformList.cc
new file mode 100644
index 00000000..a1eb43ca
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedTransformList.cc
@@ -0,0 +1,79 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedTransformList.h"
+#include "SVGAnimatedTransformListImpl.h"
+#include "SVGTransformList.h"
+
+using namespace KSVG;
+
+SVGAnimatedTransformList::SVGAnimatedTransformList()
+{
+ impl = new SVGAnimatedTransformListImpl();
+ impl->ref();
+}
+
+SVGAnimatedTransformList::SVGAnimatedTransformList(const SVGAnimatedTransformList &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGAnimatedTransformList &SVGAnimatedTransformList::operator=(const SVGAnimatedTransformList &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGAnimatedTransformList::SVGAnimatedTransformList(SVGAnimatedTransformListImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGAnimatedTransformList::~SVGAnimatedTransformList()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGTransformList SVGAnimatedTransformList::baseVal() const
+{
+ if(!impl) return SVGTransformList(0);
+ return SVGTransformList(impl->baseVal());
+}
+
+SVGTransformList SVGAnimatedTransformList::animVal() const
+{
+ if(!impl) return SVGTransformList(0);
+ return SVGTransformList(impl->animVal());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimatedTransformList.h b/ksvg/dom/SVGAnimatedTransformList.h
new file mode 100644
index 00000000..87a12d3b
--- /dev/null
+++ b/ksvg/dom/SVGAnimatedTransformList.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedTransformList_H
+#define SVGAnimatedTransformList_H
+
+namespace KSVG
+{
+
+class SVGTransformList;
+class SVGAnimatedTransformListImpl;
+class SVGAnimatedTransformList
+{
+public:
+ SVGAnimatedTransformList();
+ SVGAnimatedTransformList(const SVGAnimatedTransformList &other);
+ SVGAnimatedTransformList &operator=(const SVGAnimatedTransformList &other);
+ SVGAnimatedTransformList(SVGAnimatedTransformListImpl *other);
+ ~SVGAnimatedTransformList();
+
+ SVGTransformList baseVal() const;
+ SVGTransformList animVal() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGAnimatedTransformListImpl *handle() const { return impl; }
+
+private:
+ SVGAnimatedTransformListImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimationElement.cc b/ksvg/dom/SVGAnimationElement.cc
new file mode 100644
index 00000000..0d4014a7
--- /dev/null
+++ b/ksvg/dom/SVGAnimationElement.cc
@@ -0,0 +1,93 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimationElement.h"
+#include "SVGAnimationElementImpl.h"
+
+using namespace KSVG;
+
+SVGAnimationElement::SVGAnimationElement() : SVGElement(), SVGTests(), SVGExternalResourcesRequired()
+{
+ impl = 0;
+}
+
+SVGAnimationElement::SVGAnimationElement(const SVGAnimationElement &other) : SVGElement(other), SVGTests(other), SVGExternalResourcesRequired(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGAnimationElement &SVGAnimationElement::operator=(const SVGAnimationElement &other)
+{
+ SVGElement::operator=(other);
+ SVGTests::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGAnimationElement::SVGAnimationElement(SVGAnimationElementImpl *other) : SVGElement(other), SVGTests(other), SVGExternalResourcesRequired(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGAnimationElement::~SVGAnimationElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGElement SVGAnimationElement::targetElement() const
+{
+ if(!impl) return SVGElement(0);
+ return SVGElement(impl->targetElement());
+}
+
+float SVGAnimationElement::getStartTime()
+{
+ if(!impl) return -1;
+ return impl->getStartTime();
+}
+
+float SVGAnimationElement::getCurrentTime()
+{
+ if(!impl) return -1;
+ return impl->getCurrentTime();
+}
+
+float SVGAnimationElement::getSimpleDuration()
+{
+ if(!impl) return -1;
+ return impl->getSimpleDuration();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGAnimationElement.h b/ksvg/dom/SVGAnimationElement.h
new file mode 100644
index 00000000..2e4df665
--- /dev/null
+++ b/ksvg/dom/SVGAnimationElement.h
@@ -0,0 +1,60 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimationElement_H
+#define SVGAnimationElement_H
+
+#include "SVGElement.h"
+#include "SVGTests.h"
+#include "SVGExternalResourcesRequired.h"
+
+namespace KSVG
+{
+
+class SVGAnimationElementImpl;
+class SVGAnimationElement : public SVGElement,
+ public SVGTests,
+ public SVGExternalResourcesRequired
+{
+public:
+ SVGAnimationElement();
+ SVGAnimationElement(const SVGAnimationElement &other);
+ SVGAnimationElement &operator=(const SVGAnimationElement &other);
+ SVGAnimationElement(SVGAnimationElementImpl *other);
+ virtual ~SVGAnimationElement();
+
+ SVGElement targetElement() const;
+
+ float getStartTime();
+ float getCurrentTime();
+ float getSimpleDuration();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGAnimationElementImpl *handle() const { return impl; }
+
+private:
+ SVGAnimationElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGCSSRule.cc b/ksvg/dom/SVGCSSRule.cc
new file mode 100644
index 00000000..cad5657e
--- /dev/null
+++ b/ksvg/dom/SVGCSSRule.cc
@@ -0,0 +1,66 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGCSSRule.h"
+#include "SVGCSSRuleImpl.h"
+
+using namespace KSVG;
+
+SVGCSSRule::SVGCSSRule() //: css::CSSRule()
+{
+ impl = new SVGCSSRuleImpl();
+ impl->ref();
+}
+
+SVGCSSRule::SVGCSSRule(const SVGCSSRule &other) : /*css::CSSRule(),*/ impl(0)
+{
+ (*this) = other;
+}
+
+SVGCSSRule &SVGCSSRule::operator=(const SVGCSSRule &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGCSSRule::SVGCSSRule(SVGCSSRuleImpl *other) //: css::CSSRule()
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGCSSRule::~SVGCSSRule()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGCSSRule.h b/ksvg/dom/SVGCSSRule.h
new file mode 100644
index 00000000..dc9e9360
--- /dev/null
+++ b/ksvg/dom/SVGCSSRule.h
@@ -0,0 +1,51 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGCSSRule_H
+#define SVGCSSRule_H
+
+namespace KSVG
+{
+
+class SVGCSSRuleImpl;
+class SVGCSSRule //: public css::CSSRule
+{
+public:
+ SVGCSSRule();
+ SVGCSSRule(const SVGCSSRule &other);
+ SVGCSSRule &operator=(const SVGCSSRule &other);
+ SVGCSSRule(SVGCSSRuleImpl *other);
+ virtual ~SVGCSSRule();
+
+ // add to enum
+ // const unsigned short COLOR_PROFILE_RULE = 7;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGCSSRuleImpl *handle() const { return impl; }
+
+private:
+ SVGCSSRuleImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGCircleElement.cc b/ksvg/dom/SVGCircleElement.cc
new file mode 100644
index 00000000..13875211
--- /dev/null
+++ b/ksvg/dom/SVGCircleElement.cc
@@ -0,0 +1,92 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+#include "SVGCircleElement.h"
+#include "SVGCircleElementImpl.h"
+#include "SVGAnimatedLength.h"
+
+using namespace KSVG;
+
+SVGCircleElement::SVGCircleElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable()
+{
+ impl = 0;
+}
+
+SVGCircleElement::SVGCircleElement(const SVGCircleElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGCircleElement &SVGCircleElement::operator=(const SVGCircleElement &other)
+{
+ SVGElement::operator=(other);
+ SVGTests::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+ SVGTransformable::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGCircleElement::SVGCircleElement(SVGCircleElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGCircleElement::~SVGCircleElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedLength SVGCircleElement::cx()
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->cx());
+}
+
+SVGAnimatedLength SVGCircleElement::cy()
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->cy());
+}
+
+SVGAnimatedLength SVGCircleElement::r()
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->r());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGCircleElement.h b/ksvg/dom/SVGCircleElement.h
new file mode 100644
index 00000000..65406a1c
--- /dev/null
+++ b/ksvg/dom/SVGCircleElement.h
@@ -0,0 +1,117 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; see the file COPYING.LIB. If
+ not, write to the Free Software Foundation, Inc., 51 Franklin Street,
+ Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+ This file includes excerpts from the Scalable Vector Graphics
+ (SVG) 1.0 Specification (Proposed Recommendation)
+ http://www.w3.org/TR/SVG
+
+ Copyright 2001 World Wide Web Consortium, (Massachusetts
+ Institute of Technology, Institut National de Recherche en
+ Informatique et en Automatique, Keio University).
+ All Rights Reserved.
+
+ $Id$
+ */
+
+#ifndef SVGCircleElement_H
+#define SVGCircleElement_H
+
+#include "SVGElement.h"
+#include "SVGTests.h"
+#include "SVGLangSpace.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+#include "SVGTransformable.h"
+
+namespace KSVG
+{
+
+class SVGCircleElementImpl;
+
+class SVGAnimatedLength;
+/**
+ * The <code>circle</code> element defines a circle based on a center
+ * point and radius.
+ *
+ * For more info look here : <a href =
+ * "http://www.w3.org/TR/SVG/shapes.html#CircleElement">9.3 The
+ * 'circle' element</a>.
+ */
+class SVGCircleElement : public SVGElement,
+ public SVGTests,
+ public SVGLangSpace,
+ public SVGExternalResourcesRequired,
+ public SVGStylable,
+ public SVGTransformable
+{
+public:
+ SVGCircleElement();
+ SVGCircleElement(const SVGCircleElement &);
+ SVGCircleElement &operator=(const SVGCircleElement &other);
+ SVGCircleElement(SVGCircleElementImpl *);
+ ~SVGCircleElement();
+
+ /**
+ * The x-axis coordinate of the center of the circle.
+ * If the attribute is not specified, the effect is as if a value
+ * of "0" were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The x-axis coordinate of the center of the circle.
+ */
+ SVGAnimatedLength cx();
+
+ /**
+ * The y-axis coordinate of the center of the circle.
+ * If the attribute is not specified, the effect is as if a value
+ * of "0" were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The y-axis coordinate of the center of the circle.
+ */
+ SVGAnimatedLength cy();
+
+ /**
+ * The radius of the circle.
+ * A negative value is an error (see <a href =
+ * "http://www.w3.org/TR/SVG/implnote.html#ErrorProcessing">
+ * Error processing</a>). A value of zero disables rendering of
+ * the element.
+ *
+ * This attribute is animatable.
+ *
+ * @return The radius of the circle.
+ */
+ SVGAnimatedLength r();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGCircleElementImpl *handle() const { return impl; }
+
+private:
+ SVGCircleElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGClipPathElement.cc b/ksvg/dom/SVGClipPathElement.cc
new file mode 100644
index 00000000..f0785efc
--- /dev/null
+++ b/ksvg/dom/SVGClipPathElement.cc
@@ -0,0 +1,79 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGClipPathElement.h"
+#include "SVGClipPathElementImpl.h"
+#include "SVGAnimatedEnumeration.h"
+
+using namespace KSVG;
+
+SVGClipPathElement::SVGClipPathElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable()
+{
+ impl = 0;
+}
+
+SVGClipPathElement::SVGClipPathElement(const SVGClipPathElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other)
+{
+ (*this) = other;
+}
+
+SVGClipPathElement &SVGClipPathElement::operator=(const SVGClipPathElement &other)
+{
+ SVGElement::operator=(other);
+ SVGTests::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+ SVGTransformable::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGClipPathElement::SVGClipPathElement(SVGClipPathElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGClipPathElement::~SVGClipPathElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedEnumeration SVGClipPathElement::clipPathUnits() const
+{
+ if(!impl) return SVGAnimatedEnumeration(0);
+ return SVGAnimatedEnumeration(impl->clipPathUnits());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGClipPathElement.h b/ksvg/dom/SVGClipPathElement.h
new file mode 100644
index 00000000..70cfe6bb
--- /dev/null
+++ b/ksvg/dom/SVGClipPathElement.h
@@ -0,0 +1,65 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGClipPathElement_H
+#define SVGClipPathElement_H
+
+#include "SVGElement.h"
+#include "SVGTests.h"
+#include "SVGLangSpace.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+#include "SVGTransformable.h"
+#include "SVGUnitTypes.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedEnumeration;
+class SVGClipPathElementImpl;
+class SVGClipPathElement : public SVGElement,
+ public SVGTests,
+ public SVGLangSpace,
+ public SVGExternalResourcesRequired,
+ public SVGStylable,
+ public SVGTransformable,
+ public SVGUnitTypes
+{
+public:
+ SVGClipPathElement();
+ SVGClipPathElement(const SVGClipPathElement &other);
+ SVGClipPathElement &operator=(const SVGClipPathElement &other);
+ SVGClipPathElement(SVGClipPathElementImpl *other);
+ virtual ~SVGClipPathElement();
+
+ SVGAnimatedEnumeration clipPathUnits() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGClipPathElementImpl *handle() const { return impl; }
+
+private:
+ SVGClipPathElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGColor.cc b/ksvg/dom/SVGColor.cc
new file mode 100644
index 00000000..e9294c5d
--- /dev/null
+++ b/ksvg/dom/SVGColor.cc
@@ -0,0 +1,105 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option); any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGColor.h"
+#include "SVGICCColor.h"
+#include "SVGColorImpl.h"
+
+using namespace KSVG;
+
+SVGColor::SVGColor()
+{
+ // FIXME: no icc color support...
+ impl = new SVGColorImpl(0);
+ impl->ref();
+}
+
+SVGColor::SVGColor(const SVGColor &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGColor &SVGColor::operator=(const SVGColor &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+
+}
+
+SVGColor::SVGColor(SVGColorImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGColor::~SVGColor()
+{
+ if(impl)
+ impl->deref();
+}
+
+unsigned short SVGColor::colorType() const
+{
+ if(!impl) return SVG_COLORTYPE_UNKNOWN;
+ return impl->colorType();
+}
+
+DOM::RGBColor SVGColor::rgbColor() const
+{
+ if(!impl) return DOM::RGBColor();
+ return impl->rgbColor();
+}
+
+SVGICCColor SVGColor::iccColor() const
+{
+ if(!impl) return SVGICCColor();
+ return impl->iccColor();
+}
+
+void SVGColor::setRGBColor(const DOM::DOMString &rgbColor)
+{
+ if(impl)
+ impl->setRGBColor(rgbColor);
+}
+
+void SVGColor::setRGBColorICCColor(const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor)
+{
+ if(impl)
+ impl->setRGBColorICCColor(rgbColor, iccColor);
+}
+
+void SVGColor::setColor(unsigned short colorType, const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor)
+{
+ if(impl)
+ impl->setColor(colorType, rgbColor, iccColor);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGColor.h b/ksvg/dom/SVGColor.h
new file mode 100644
index 00000000..62147ed0
--- /dev/null
+++ b/ksvg/dom/SVGColor.h
@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGColor_H
+#define SVGColor_H
+
+#include <dom/css_value.h>
+#include <dom/dom_string.h>
+
+namespace KSVG
+{
+
+enum
+{
+ SVG_COLORTYPE_UNKNOWN = 0,
+ SVG_COLORTYPE_RGBCOLOR = 1,
+ SVG_COLORTYPE_RGBCOLOR_ICCCOLOR = 2,
+ SVG_COLORTYPE_CURRENTCOLOR = 3
+};
+
+class SVGColorImpl;
+class SVGICCColor;
+class SVGColor // : public css::CSSValue
+{
+public:
+ SVGColor();
+ SVGColor(const SVGColor &);
+ SVGColor &operator=(const SVGColor &other);
+ SVGColor(SVGColorImpl *);
+ ~SVGColor();
+
+ unsigned short colorType() const;
+
+ DOM::RGBColor rgbColor() const;
+ SVGICCColor iccColor() const;
+
+ void setRGBColor(const DOM::DOMString &rgbColor);
+ void setRGBColorICCColor(const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor);
+ void setColor(unsigned short colorType, const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor);
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGColorImpl *handle() const { return impl; }
+
+private:
+ SVGColorImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGColorProfileElement.cc b/ksvg/dom/SVGColorProfileElement.cc
new file mode 100644
index 00000000..5acdb1a1
--- /dev/null
+++ b/ksvg/dom/SVGColorProfileElement.cc
@@ -0,0 +1,105 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGColorProfileElement.h"
+#include "SVGColorProfileElementImpl.h"
+#include "SVGRenderingIntent.h"
+
+using namespace KSVG;
+
+SVGColorProfileElement::SVGColorProfileElement() : SVGElement(), SVGURIReference()
+{
+ impl = 0;
+}
+
+SVGColorProfileElement::SVGColorProfileElement(const SVGColorProfileElement &other) : SVGElement(other), SVGURIReference(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGColorProfileElement &SVGColorProfileElement::operator=(const SVGColorProfileElement &other)
+{
+ SVGElement::operator=(other);
+ SVGURIReference::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGColorProfileElement::SVGColorProfileElement(SVGColorProfileElementImpl *other) : SVGElement(other), SVGURIReference(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGColorProfileElement::~SVGColorProfileElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+void SVGColorProfileElement::setLocal(const DOM::DOMString &local)
+{
+ if(impl)
+ impl->setLocal(local);
+}
+
+DOM::DOMString SVGColorProfileElement::local() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->local();
+}
+
+void SVGColorProfileElement::setName(const DOM::DOMString &name)
+{
+ if(impl)
+ impl->setName(name);
+}
+
+DOM::DOMString SVGColorProfileElement::name() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->name();
+}
+
+void SVGColorProfileElement::setRenderingIntent(unsigned short renderingIntent)
+{
+ if(impl)
+ impl->setRenderingIntent(renderingIntent);
+}
+
+unsigned short SVGColorProfileElement::renderingIntent() const
+{
+ if(!impl) return RENDERING_INTENT_UNKNOWN;
+ return impl->renderingIntent();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGColorProfileElement.h b/ksvg/dom/SVGColorProfileElement.h
new file mode 100644
index 00000000..f7f3bd41
--- /dev/null
+++ b/ksvg/dom/SVGColorProfileElement.h
@@ -0,0 +1,62 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGColorProfileElement_H
+#define SVGColorProfileElement_H
+
+#include "SVGElement.h"
+#include "SVGURIReference.h"
+#include <dom/dom_string.h>
+
+namespace KSVG
+{
+
+class SVGColorProfileElementImpl;
+class SVGColorProfileElement : public SVGElement,
+ public SVGURIReference
+{
+public:
+ SVGColorProfileElement();
+ SVGColorProfileElement(const SVGColorProfileElement &other);
+ SVGColorProfileElement &operator=(const SVGColorProfileElement &other);
+ SVGColorProfileElement(SVGColorProfileElementImpl *other);
+ virtual ~SVGColorProfileElement();
+
+ void setLocal(const DOM::DOMString &local);
+ DOM::DOMString local() const;
+
+ void setName(const DOM::DOMString &name);
+ DOM::DOMString name() const;
+
+ void setRenderingIntent(unsigned short renderingIntent);
+ unsigned short renderingIntent() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGColorProfileElementImpl *handle() const { return impl; }
+
+private:
+ SVGColorProfileElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGColorProfileRule.cc b/ksvg/dom/SVGColorProfileRule.cc
new file mode 100644
index 00000000..8c4ecea7
--- /dev/null
+++ b/ksvg/dom/SVGColorProfileRule.cc
@@ -0,0 +1,103 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGColorProfileRule.h"
+#include "SVGColorProfileRuleImpl.h"
+#include "SVGRenderingIntent.h"
+
+using namespace KSVG;
+
+SVGColorProfileRule::SVGColorProfileRule() : SVGCSSRule()
+{
+ impl = new SVGColorProfileRuleImpl();
+ impl->ref();
+}
+
+SVGColorProfileRule::SVGColorProfileRule(const SVGColorProfileRule &other) : SVGCSSRule(), impl(0)
+{
+ (*this) = other;
+}
+
+SVGColorProfileRule &SVGColorProfileRule::operator=(const SVGColorProfileRule &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGColorProfileRule::SVGColorProfileRule(SVGColorProfileRuleImpl *other) : SVGCSSRule(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGColorProfileRule::~SVGColorProfileRule()
+{
+ if(impl)
+ impl->deref();
+}
+
+void SVGColorProfileRule::setSrc(const DOM::DOMString &src)
+{
+ if(impl)
+ impl->setSrc(src);
+}
+
+DOM::DOMString SVGColorProfileRule::src() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->src();
+}
+
+void SVGColorProfileRule::setName(const DOM::DOMString &name)
+{
+ if(impl)
+ impl->setName(name);
+}
+
+DOM::DOMString SVGColorProfileRule::name() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->name();
+}
+
+void SVGColorProfileRule::setRenderingIntent(unsigned short renderingIntent)
+{
+ if(impl)
+ impl->setRenderingIntent(renderingIntent);
+}
+
+unsigned short SVGColorProfileRule::renderingIntent() const
+{
+ if(!impl) return RENDERING_INTENT_UNKNOWN;
+ return impl->renderingIntent();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGColorProfileRule.h b/ksvg/dom/SVGColorProfileRule.h
new file mode 100644
index 00000000..b99321ad
--- /dev/null
+++ b/ksvg/dom/SVGColorProfileRule.h
@@ -0,0 +1,57 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGColorProfileRule_H
+#define SVGColorProfileRule_H
+
+#include <dom/dom_string.h>
+#include "SVGCSSRule.h"
+
+namespace KSVG
+{
+
+class SVGColorProfileRuleImpl;
+class SVGColorProfileRule : public SVGCSSRule
+{
+public:
+ SVGColorProfileRule();
+ SVGColorProfileRule(const SVGColorProfileRule &other);
+ SVGColorProfileRule &operator=(const SVGColorProfileRule &other);
+ SVGColorProfileRule(SVGColorProfileRuleImpl *other);
+ virtual ~SVGColorProfileRule();
+
+ void setSrc(const DOM::DOMString &src);
+ DOM::DOMString src() const;
+
+ void setName(const DOM::DOMString &name);
+ DOM::DOMString name() const;
+
+ void setRenderingIntent(unsigned short renderingIntent);
+ unsigned short renderingIntent() const;
+
+private:
+ SVGColorProfileRuleImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGComponentTransferFunctionElement.cc b/ksvg/dom/SVGComponentTransferFunctionElement.cc
new file mode 100644
index 00000000..970da9ea
--- /dev/null
+++ b/ksvg/dom/SVGComponentTransferFunctionElement.cc
@@ -0,0 +1,112 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGComponentTransferFunctionElement.h"
+#include "SVGComponentTransferFunctionElementImpl.h"
+#include "SVGAnimatedNumber.h"
+#include "SVGAnimatedNumberList.h"
+#include "SVGAnimatedEnumeration.h"
+
+using namespace KSVG;
+
+SVGComponentTransferFunctionElement::SVGComponentTransferFunctionElement() : SVGElement()
+{
+ impl = 0;
+}
+
+SVGComponentTransferFunctionElement::SVGComponentTransferFunctionElement(const SVGComponentTransferFunctionElement &other) : SVGElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGComponentTransferFunctionElement &SVGComponentTransferFunctionElement::operator =(const SVGComponentTransferFunctionElement &other)
+{
+ SVGElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGComponentTransferFunctionElement::SVGComponentTransferFunctionElement(SVGComponentTransferFunctionElementImpl *other) : SVGElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGComponentTransferFunctionElement::~SVGComponentTransferFunctionElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedEnumeration SVGComponentTransferFunctionElement::type() const
+{
+ if(!impl) return SVGAnimatedEnumeration(0);
+ return SVGAnimatedEnumeration(impl->type());
+}
+
+SVGAnimatedNumberList SVGComponentTransferFunctionElement::tableValues() const
+{
+ if(!impl) return SVGAnimatedNumberList(0);
+ return SVGAnimatedNumberList(impl->tableValues());
+}
+
+SVGAnimatedNumber SVGComponentTransferFunctionElement::slope() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->slope());
+}
+
+SVGAnimatedNumber SVGComponentTransferFunctionElement::intercept() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->intercept());
+}
+
+SVGAnimatedNumber SVGComponentTransferFunctionElement::amplitude() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->amplitude());
+}
+
+SVGAnimatedNumber SVGComponentTransferFunctionElement::exponent() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->exponent());
+}
+
+SVGAnimatedNumber SVGComponentTransferFunctionElement::offset() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->offset());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGComponentTransferFunctionElement.h b/ksvg/dom/SVGComponentTransferFunctionElement.h
new file mode 100644
index 00000000..d9dd0080
--- /dev/null
+++ b/ksvg/dom/SVGComponentTransferFunctionElement.h
@@ -0,0 +1,71 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGComponentTransferFunctionElement_H
+#define SVGComponentTransferFunctionElement_H
+
+#include "SVGElement.h"
+
+namespace KSVG
+{
+
+enum
+{
+ SVG_FECOMPONENTTRANSFER_TYPE_UNKNOWN = 0,
+ SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY = 1,
+ SVG_FECOMPONENTTRANSFER_TYPE_TABLE = 2,
+ SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE = 3,
+ SVG_FECOMPONENTTRANSFER_TYPE_LINEAR = 4,
+ SVG_FECOMPONENTTRANSFER_TYPE_GAMMA = 5
+};
+
+class SVGAnimatedEnumeration;
+class SVGAnimatedNumberList;
+class SVGAnimatedNumber;
+class SVGComponentTransferFunctionElementImpl;
+class SVGComponentTransferFunctionElement : public SVGElement
+{
+public:
+ SVGComponentTransferFunctionElement();
+ SVGComponentTransferFunctionElement(const SVGComponentTransferFunctionElement &other);
+ SVGComponentTransferFunctionElement &operator=(const SVGComponentTransferFunctionElement &other);
+ SVGComponentTransferFunctionElement(SVGComponentTransferFunctionElementImpl *other);
+ virtual ~SVGComponentTransferFunctionElement();
+
+ SVGAnimatedEnumeration type() const;
+ SVGAnimatedNumberList tableValues() const;
+ SVGAnimatedNumber slope() const;
+ SVGAnimatedNumber intercept() const;
+ SVGAnimatedNumber amplitude() const;
+ SVGAnimatedNumber exponent() const;
+ SVGAnimatedNumber offset() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGComponentTransferFunctionElementImpl *handle() const { return impl; }
+
+private:
+ SVGComponentTransferFunctionElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGCursorElement.cc b/ksvg/dom/SVGCursorElement.cc
new file mode 100644
index 00000000..2eb3c0dc
--- /dev/null
+++ b/ksvg/dom/SVGCursorElement.cc
@@ -0,0 +1,83 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGCursorElement.h"
+#include "SVGCursorElementImpl.h"
+#include "SVGAnimatedLength.h"
+
+using namespace KSVG;
+
+SVGCursorElement::SVGCursorElement() : SVGElement(), SVGURIReference(), SVGTests(), SVGExternalResourcesRequired()
+{
+ impl = 0;
+}
+
+SVGCursorElement::SVGCursorElement(const SVGCursorElement &other) : SVGElement(other), SVGURIReference(other), SVGTests(other), SVGExternalResourcesRequired(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGCursorElement &SVGCursorElement::operator =(const SVGCursorElement &other)
+{
+ SVGElement::operator=(other);
+ SVGURIReference::operator=(other);
+ SVGTests::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGCursorElement::SVGCursorElement(SVGCursorElementImpl *other) : SVGElement(other), SVGURIReference(other), SVGTests(other), SVGExternalResourcesRequired(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGCursorElement::~SVGCursorElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedLength SVGCursorElement::x() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->x());
+}
+
+SVGAnimatedLength SVGCursorElement::y() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->y());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGCursorElement.h b/ksvg/dom/SVGCursorElement.h
new file mode 100644
index 00000000..feb9b2b7
--- /dev/null
+++ b/ksvg/dom/SVGCursorElement.h
@@ -0,0 +1,60 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGCursorElement_H
+#define SVGCursorElement_H
+
+#include "SVGElement.h"
+#include "SVGURIReference.h"
+#include "SVGTests.h"
+#include "SVGExternalResourcesRequired.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedLength;
+class SVGCursorElementImpl;
+class SVGCursorElement : public SVGElement,
+ public SVGURIReference,
+ public SVGTests,
+ public SVGExternalResourcesRequired
+{
+public:
+ SVGCursorElement();
+ SVGCursorElement(const SVGCursorElement &other);
+ SVGCursorElement &operator=(const SVGCursorElement &other);
+ SVGCursorElement(SVGCursorElementImpl *other);
+ virtual ~SVGCursorElement();
+
+ SVGAnimatedLength x() const;
+ SVGAnimatedLength y() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGCursorElementImpl *handle() const { return impl; }
+
+private:
+ SVGCursorElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGDefinitionSrcElement.cc b/ksvg/dom/SVGDefinitionSrcElement.cc
new file mode 100644
index 00000000..755b6b4f
--- /dev/null
+++ b/ksvg/dom/SVGDefinitionSrcElement.cc
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGDefinitionSrcElement.h"
+#include "SVGDefinitionSrcElementImpl.h"
+
+using namespace KSVG;
+
+SVGDefinitionSrcElement::SVGDefinitionSrcElement() : SVGElement()
+{
+ impl = 0;
+}
+
+SVGDefinitionSrcElement::SVGDefinitionSrcElement(const SVGDefinitionSrcElement &other) : SVGElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGDefinitionSrcElement &SVGDefinitionSrcElement::operator =(const SVGDefinitionSrcElement &other)
+{
+ SVGElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGDefinitionSrcElement::SVGDefinitionSrcElement(SVGDefinitionSrcElementImpl *other) : SVGElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGDefinitionSrcElement::~SVGDefinitionSrcElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGDefinitionSrcElement.h b/ksvg/dom/SVGDefinitionSrcElement.h
new file mode 100644
index 00000000..fc1b7f52
--- /dev/null
+++ b/ksvg/dom/SVGDefinitionSrcElement.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGDefinitionSrcElement_H
+#define SVGDefinitionSrcElement_H
+
+#include "SVGElement.h"
+
+namespace KSVG
+{
+
+class SVGDefinitionSrcElementImpl;
+class SVGDefinitionSrcElement : public SVGElement
+{
+public:
+ SVGDefinitionSrcElement();
+ SVGDefinitionSrcElement(const SVGDefinitionSrcElement &other);
+ SVGDefinitionSrcElement &operator=(const SVGDefinitionSrcElement &other);
+ SVGDefinitionSrcElement(SVGDefinitionSrcElementImpl *other);
+ virtual ~SVGDefinitionSrcElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGDefinitionSrcElementImpl *handle() const { return impl; }
+
+private:
+ SVGDefinitionSrcElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGDefsElement.cc b/ksvg/dom/SVGDefsElement.cc
new file mode 100644
index 00000000..67bb2baf
--- /dev/null
+++ b/ksvg/dom/SVGDefsElement.cc
@@ -0,0 +1,72 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGDefsElement.h"
+#include "SVGDefsElementImpl.h"
+
+using namespace KSVG;
+
+SVGDefsElement::SVGDefsElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable()
+{
+ impl = 0;
+}
+
+SVGDefsElement::SVGDefsElement(const SVGDefsElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGDefsElement &SVGDefsElement::operator =(const SVGDefsElement &other)
+{
+ SVGElement::operator=(other);
+ SVGTests::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+ SVGTransformable::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGDefsElement::SVGDefsElement(SVGDefsElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGDefsElement::~SVGDefsElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGDefsElement.h b/ksvg/dom/SVGDefsElement.h
new file mode 100644
index 00000000..e1e7e0a5
--- /dev/null
+++ b/ksvg/dom/SVGDefsElement.h
@@ -0,0 +1,78 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+
+ This file includes excerpts from the Scalable Vector Graphics
+ (SVG) 1.0 Specification (Proposed Recommendation)
+ http://www.w3.org/TR/SVG
+
+ Copyright 2001 World Wide Web Consortium, (Massachusetts
+ Institute of Technology, Institut National de Recherche en
+ Informatique et en Automatique, Keio University).
+ All Rights Reserved.
+*/
+
+#ifndef SVGDefsElement_H
+#define SVGDefsElement_H
+
+#include "SVGElement.h"
+#include "SVGTests.h"
+#include "SVGLangSpace.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+#include "SVGTransformable.h"
+
+namespace KSVG
+{
+
+class SVGDefsElementImpl;
+
+/**
+ * The 'defs' element is a container element for referenced elements. For understandability and accessibility
+ * reasons, it is recommended that, whenever possible, referenced elements be defined inside of a 'defs'.
+ *
+ * The content model for 'defs' is the same as for the <code> g </code> element; thus, any element that can be a child of
+ * a <code> g </code> can also be a child of a 'defs', and vice versa.
+ */
+class SVGDefsElement : public SVGElement,
+ public SVGTests,
+ public SVGLangSpace,
+ public SVGExternalResourcesRequired,
+ public SVGStylable,
+ public SVGTransformable
+{
+public:
+ SVGDefsElement();
+ SVGDefsElement(const SVGDefsElement &other);
+ SVGDefsElement &operator=(const SVGDefsElement &other);
+ SVGDefsElement(SVGDefsElementImpl *other);
+ virtual ~SVGDefsElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGDefsElementImpl *handle() const { return impl; }
+
+private:
+ SVGDefsElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGDescElement.cc b/ksvg/dom/SVGDescElement.cc
new file mode 100644
index 00000000..6eed0ed9
--- /dev/null
+++ b/ksvg/dom/SVGDescElement.cc
@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGDescElement.h"
+#include "SVGDescElementImpl.h"
+
+using namespace KSVG;
+
+SVGDescElement::SVGDescElement() : SVGElement(), SVGLangSpace(), SVGStylable()
+{
+ impl = 0;
+}
+
+SVGDescElement::SVGDescElement(const SVGDescElement &other) : SVGElement(other), SVGLangSpace(other), SVGStylable(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGDescElement &SVGDescElement::operator =(const SVGDescElement &other)
+{
+ SVGElement::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGStylable::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGDescElement::SVGDescElement(SVGDescElementImpl *other) : SVGElement(other), SVGLangSpace(other), SVGStylable(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGDescElement::~SVGDescElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGDescElement.h b/ksvg/dom/SVGDescElement.h
new file mode 100644
index 00000000..9a5b270f
--- /dev/null
+++ b/ksvg/dom/SVGDescElement.h
@@ -0,0 +1,54 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGDescElement_H
+#define SVGDescElement_H
+
+#include "SVGElement.h"
+#include "SVGLangSpace.h"
+#include "SVGStylable.h"
+
+namespace KSVG
+{
+
+class SVGDescElementImpl;
+class SVGDescElement : public SVGElement,
+ public SVGLangSpace,
+ public SVGStylable
+{
+public:
+ SVGDescElement();
+ SVGDescElement(const SVGDescElement &other);
+ SVGDescElement &operator=(const SVGDescElement &other);
+ SVGDescElement(SVGDescElementImpl *other);
+ virtual ~SVGDescElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGDescElementImpl *handle() const { return impl; }
+
+private:
+ SVGDescElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGDocument.cc b/ksvg/dom/SVGDocument.cc
new file mode 100644
index 00000000..8734b8da
--- /dev/null
+++ b/ksvg/dom/SVGDocument.cc
@@ -0,0 +1,138 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "ksvg_ecma.h"
+
+#include "SVGDocument.h"
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElement.h"
+#include "SVGWindow.h"
+
+using namespace KSVG;
+
+SVGDocument::SVGDocument() : DOM::Document(*(new SVGDocumentImpl()))
+{
+ impl = reinterpret_cast<SVGDocumentImpl *>(handle());
+ impl->ref();
+}
+
+SVGDocument::SVGDocument(const SVGDocument &other) : DOM::Document(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGDocument &SVGDocument::operator=(const SVGDocument &other)
+{
+ DOM::Document::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGDocument::SVGDocument(SVGDocumentImpl *other) : DOM::Document(other->handle())
+{
+ impl = other;
+
+ if(impl)
+ impl->ref();
+}
+
+SVGDocument::~SVGDocument()
+{
+ if(impl)
+ impl->deref();
+}
+
+DOM::DOMString SVGDocument::title() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->title();
+}
+
+DOM::DOMString SVGDocument::referrer() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->referrer();
+}
+
+DOM::DOMString SVGDocument::domain() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->domain();
+}
+
+DOM::DOMString SVGDocument::URL() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->URL();
+}
+
+SVGWindow SVGDocument::window() const
+{
+ if(!impl) return SVGWindow();
+ return impl->window();
+}
+
+SVGSVGElement SVGDocument::rootElement() const
+{
+ if(!impl) return SVGSVGElement(0);
+ return SVGSVGElement(impl->rootElement());
+}
+
+SVGElement SVGDocument::createElement(const DOM::DOMString &tagName)
+{
+ if(!impl) return SVGElement(0);
+
+ DOM::Element impl = DOM::Document::createElement(tagName);
+ return SVGElement(SVGDocumentImpl::createElement(tagName, impl));
+}
+
+SVGElement SVGDocument::createElementNS(const DOM::DOMString &namespaceURI, const DOM::DOMString &qualifiedName)
+{
+ if(!impl) return SVGElement(0);
+
+ DOM::Element impl = DOM::Document::createElementNS(namespaceURI, qualifiedName);
+ return SVGElement(SVGDocumentImpl::createElement(qualifiedName, impl));
+}
+
+// Internal
+KJS::Object SVGDocument::globalJSObject()
+{
+ if(!impl) return KJS::Object();
+ return impl->ecmaEngine()->globalObject();
+}
+
+KJS::ExecState *SVGDocument::globalJSExec()
+{
+ if(!impl) return 0;
+ return impl->ecmaEngine()->globalExec();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGDocument.h b/ksvg/dom/SVGDocument.h
new file mode 100644
index 00000000..c3f5c7bd
--- /dev/null
+++ b/ksvg/dom/SVGDocument.h
@@ -0,0 +1,70 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGDocument_H
+#define SVGDocument_H
+
+#include <kjs/object.h>
+
+#include <dom/dom_doc.h>
+#include <dom/dom_string.h>
+
+namespace KSVG
+{
+
+class SVGWindow;
+class SVGElement;
+class SVGSVGElement;
+class SVGDocumentImpl;
+class SVGDocument : public DOM::Document
+{
+public:
+ SVGDocument();
+ SVGDocument(const SVGDocument &other);
+ SVGDocument &operator=(const SVGDocument &other);
+ SVGDocument(SVGDocumentImpl *other);
+ ~SVGDocument();
+
+ DOM::DOMString title() const;
+ DOM::DOMString referrer() const;
+ DOM::DOMString domain() const;
+ DOM::DOMString URL() const;
+ SVGWindow window() const;
+
+ SVGSVGElement rootElement() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGDocumentImpl *handle() const { return impl; }
+
+ SVGElement createElement(const DOM::DOMString &tagName);
+ SVGElement createElementNS(const DOM::DOMString &namespaceURI, const DOM::DOMString &qualifiedName);
+
+ KJS::Object globalJSObject();
+ KJS::ExecState *globalJSExec();
+
+private:
+ SVGDocumentImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGElement.cc b/ksvg/dom/SVGElement.cc
new file mode 100644
index 00000000..0edef368
--- /dev/null
+++ b/ksvg/dom/SVGElement.cc
@@ -0,0 +1,124 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGSVGElement.h"
+#include "SVGElement.h"
+#include "SVGElementImpl.h"
+
+using namespace KSVG;
+
+// There is no way to create a SVGElement this way! Use SVGDocument.
+SVGElement::SVGElement() : DOM::Element()
+{
+ impl = 0; // new SVGElementImpl(ownerDocument().createElement().handle());
+}
+
+SVGElement::SVGElement(const SVGElement &other) : DOM::Element(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGElement &SVGElement::operator=(const SVGElement &other)
+{
+ // Baseclass assignement operators always first (Niko)
+ DOM::Element::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGElement::SVGElement(SVGElementImpl *other) : DOM::Element(other->handle())
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGElement::~SVGElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+void SVGElement::setId(DOM::DOMString value)
+{
+ if(impl)
+ impl->setId(value);
+}
+
+DOM::DOMString SVGElement::id()
+{
+ if(!impl) return DOM::DOMString();
+ return impl->id();
+}
+
+void SVGElement::setXmlbase(DOM::DOMString value)
+{
+ if(impl)
+ impl->setXmlbase(value);
+}
+
+DOM::DOMString SVGElement::xmlbase()
+{
+ if(!impl) return DOM::DOMString();
+ return impl->xmlbase();
+}
+
+SVGSVGElement SVGElement::ownerSVGElement()
+{
+ if(!impl) return SVGSVGElement(0);
+ return impl->ownerSVGElement();
+}
+
+SVGElement SVGElement::viewportElement()
+{
+ if(!impl) return SVGElement(0);
+ return impl->viewportElement();
+}
+
+void SVGElement::setAttribute(const DOM::DOMString &name, const DOM::DOMString &value)
+{
+ if(impl)
+ impl->setAttributeInternal(name, value);
+}
+
+DOM::DOMString SVGElement::getAttribute(const DOM::DOMString &name)
+{
+ if(!impl) return DOM::DOMString();
+ return impl->getAttributeInternal(name);
+}
+
+bool SVGElement::hasAttribute(const DOM::DOMString &name)
+{
+ if(!impl) return false;
+ return impl->hasAttribute(name);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGElement.h b/ksvg/dom/SVGElement.h
new file mode 100644
index 00000000..12191b05
--- /dev/null
+++ b/ksvg/dom/SVGElement.h
@@ -0,0 +1,83 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGElement_H
+#define SVGElement_H
+
+#include <dom/dom_string.h>
+#include <dom/dom_element.h>
+
+namespace KSVG
+{
+
+// Not part of the DOM specification. Internal use only!
+#define dom_cast(Class, Obj) reinterpret_cast<Class##Impl *>(Obj.handle())
+
+template<class A, class B>
+class SVGSafeCreator
+{
+public:
+ SVGSafeCreator() { }
+ ~SVGSafeCreator() { }
+
+ static A create(B *impl)
+ {
+ if(!impl) return A(); // Don't use A(0) it'll crash!
+ return A(impl);
+ }
+};
+
+class SVGSVGElement;
+class SVGElementImpl;
+class SVGElement : public DOM::Element
+{
+public:
+ SVGElement();
+ SVGElement(const SVGElement &other);
+ SVGElement &operator=(const SVGElement &other);
+ SVGElement(SVGElementImpl *other);
+ ~SVGElement();
+
+ void setId(DOM::DOMString);
+ DOM::DOMString id();
+
+ void setXmlbase(DOM::DOMString);
+ DOM::DOMString xmlbase();
+
+ SVGSVGElement ownerSVGElement();
+ SVGElement viewportElement();
+
+ // We need to overwrite set/get/hasAttribute(s)
+ void setAttribute(const DOM::DOMString &name, const DOM::DOMString &value);
+ DOM::DOMString getAttribute(const DOM::DOMString &name);
+ bool hasAttribute(const DOM::DOMString &name);
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGElementImpl *handle() const { return impl; }
+
+private:
+ SVGElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGElementInstance.cc b/ksvg/dom/SVGElementInstance.cc
new file mode 100644
index 00000000..9bc027c0
--- /dev/null
+++ b/ksvg/dom/SVGElementInstance.cc
@@ -0,0 +1,117 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGElementInstance.h"
+#include "SVGElementInstanceImpl.h"
+#include "SVGElementInstanceList.h"
+#include "SVGElement.h"
+#include "SVGUseElement.h"
+
+using namespace KSVG;
+
+SVGElementInstance::SVGElementInstance()
+{
+ impl = new SVGElementInstanceImpl();
+ impl->ref();
+}
+
+SVGElementInstance::SVGElementInstance(const SVGElementInstance &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGElementInstance &SVGElementInstance::operator =(const SVGElementInstance &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGElementInstance::SVGElementInstance(SVGElementInstanceImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGElementInstance::~SVGElementInstance()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGElement SVGElementInstance::correspondingElement() const
+{
+ if(!impl) return SVGElement(0);
+ return SVGElement(impl->correspondingElement());
+}
+
+SVGUseElement SVGElementInstance::correspondingUseElement() const
+{
+ if(!impl) return SVGUseElement(0);
+ return SVGUseElement(impl->correspondingUseElement());
+}
+
+SVGElementInstance SVGElementInstance::parentNode() const
+{
+ if(!impl) return SVGElementInstance(0);
+ return SVGElementInstance(impl->parentNode());
+}
+
+SVGElementInstanceList SVGElementInstance::childNodes() const
+{
+ if(!impl) return SVGElementInstanceList(0);
+ return SVGElementInstanceList(impl->childNodes());
+}
+
+SVGElementInstance SVGElementInstance::firstChild() const
+{
+ if(!impl) return SVGElementInstance(0);
+ return SVGElementInstance(impl->firstChild());
+}
+
+SVGElementInstance SVGElementInstance::lastChild() const
+{
+ if(!impl) return SVGElementInstance(0);
+ return SVGElementInstance(impl->lastChild());
+}
+
+SVGElementInstance SVGElementInstance::previousSibling() const
+{
+ if(!impl) return SVGElementInstance(0);
+ return SVGElementInstance(impl->previousSibling());
+}
+
+SVGElementInstance SVGElementInstance::nextSibling() const
+{
+ if(!impl) return SVGElementInstance(0);
+ return SVGElementInstance(impl->nextSibling());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGElementInstance.h b/ksvg/dom/SVGElementInstance.h
new file mode 100644
index 00000000..51d81831
--- /dev/null
+++ b/ksvg/dom/SVGElementInstance.h
@@ -0,0 +1,60 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGElementInstance_H
+#define SVGElementInstance_H
+
+namespace KSVG
+{
+
+class SVGElement;
+class SVGUseElement;
+class SVGElementInstanceList;
+class SVGElementInstanceImpl;
+class SVGElementInstance
+{
+public:
+ SVGElementInstance();
+ SVGElementInstance(const SVGElementInstance &other);
+ SVGElementInstance &operator=(const SVGElementInstance &other);
+ SVGElementInstance(SVGElementInstanceImpl *other);
+ ~SVGElementInstance();
+
+ SVGElement correspondingElement() const;
+ SVGUseElement correspondingUseElement() const;
+ SVGElementInstance parentNode() const;
+ SVGElementInstanceList childNodes() const;
+ SVGElementInstance firstChild() const;
+ SVGElementInstance lastChild() const;
+ SVGElementInstance previousSibling() const;
+ SVGElementInstance nextSibling() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGElementInstanceImpl *handle() const { return impl; }
+
+private:
+ SVGElementInstanceImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGElementInstanceList.cc b/ksvg/dom/SVGElementInstanceList.cc
new file mode 100644
index 00000000..ccc99f37
--- /dev/null
+++ b/ksvg/dom/SVGElementInstanceList.cc
@@ -0,0 +1,79 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGElementInstanceList.h"
+#include "SVGElementInstanceListImpl.h"
+#include "SVGElementInstance.h"
+
+using namespace KSVG;
+
+SVGElementInstanceList::SVGElementInstanceList()
+{
+ impl = new SVGElementInstanceListImpl();
+ impl->ref();
+}
+
+SVGElementInstanceList::SVGElementInstanceList(const SVGElementInstanceList &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGElementInstanceList &SVGElementInstanceList::operator=(const SVGElementInstanceList &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGElementInstanceList::SVGElementInstanceList(SVGElementInstanceListImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGElementInstanceList::~SVGElementInstanceList()
+{
+ if(impl)
+ impl->deref();
+}
+
+unsigned long SVGElementInstanceList::length() const
+{
+ if(!impl) return 0;
+ return impl->length();
+}
+
+SVGElementInstance SVGElementInstanceList::item(unsigned long index)
+{
+ if(!impl) return SVGElementInstance(0);
+ return SVGElementInstance(impl->item(index));
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGElementInstanceList.h b/ksvg/dom/SVGElementInstanceList.h
new file mode 100644
index 00000000..9beb40ed
--- /dev/null
+++ b/ksvg/dom/SVGElementInstanceList.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGElementInstanceList_H
+#define SVGElementInstanceList_H
+
+namespace KSVG
+{
+
+class SVGElementInstance;
+class SVGElementInstanceListImpl;
+class SVGElementInstanceList
+{
+public:
+ SVGElementInstanceList();
+ SVGElementInstanceList(const SVGElementInstanceList &other);
+ SVGElementInstanceList &operator=(const SVGElementInstanceList &other);
+ SVGElementInstanceList(SVGElementInstanceListImpl *other);
+ ~SVGElementInstanceList();
+
+ unsigned long length() const;
+ SVGElementInstance item(unsigned long index);
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGElementInstanceListImpl *handle() const { return impl; }
+
+private:
+ SVGElementInstanceListImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGEllipseElement.cc b/ksvg/dom/SVGEllipseElement.cc
new file mode 100644
index 00000000..2b744ccb
--- /dev/null
+++ b/ksvg/dom/SVGEllipseElement.cc
@@ -0,0 +1,98 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+#include "SVGEllipseElement.h"
+#include "SVGEllipseElementImpl.h"
+#include "SVGAnimatedLength.h"
+
+using namespace KSVG;
+
+SVGEllipseElement::SVGEllipseElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable()
+{
+ impl = 0;
+}
+
+SVGEllipseElement::SVGEllipseElement(const SVGEllipseElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGEllipseElement &SVGEllipseElement::operator=(const SVGEllipseElement &other)
+{
+ SVGElement::operator=(other);
+ SVGTests::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+ SVGTransformable::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGEllipseElement::SVGEllipseElement(SVGEllipseElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGEllipseElement::~SVGEllipseElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedLength SVGEllipseElement::cx()
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->cx());
+}
+
+SVGAnimatedLength SVGEllipseElement::cy()
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->cy());
+}
+
+SVGAnimatedLength SVGEllipseElement::rx()
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->rx());
+}
+
+SVGAnimatedLength SVGEllipseElement::ry()
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->ry());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGEllipseElement.h b/ksvg/dom/SVGEllipseElement.h
new file mode 100644
index 00000000..78399779
--- /dev/null
+++ b/ksvg/dom/SVGEllipseElement.h
@@ -0,0 +1,131 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; see the file COPYING.LIB. If
+ not, write to the Free Software Foundation, Inc., 51 Franklin Street,
+ Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+ This file includes excerpts from the Scalable Vector Graphics
+ (SVG) 1.0 Specification (Proposed Recommendation)
+ http://www.w3.org/TR/SVG
+
+ Copyright 2001 World Wide Web Consortium, (Massachusetts
+ Institute of Technology, Institut National de Recherche en
+ Informatique et en Automatique, Keio University).
+ All Rights Reserved.
+
+ $Id$
+ */
+
+#ifndef SVGEllipseElement_H
+#define SVGEllipseElement_H
+
+#include "SVGElement.h"
+#include "SVGTests.h"
+#include "SVGLangSpace.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+#include "SVGTransformable.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedLength;
+class SVGEllipseElementImpl;
+
+/**
+ * The <code>ellipse</code> element defines an ellipse which is
+ * axis-aligned with the current user coordinate system based on a
+ * center point and two radii.
+ *
+ * For more info look here : <a href =
+ * "http://www.w3.org/TR/SVG/shapes.html#EllipseElement">9.4 The
+ * 'ellipse' element</a>.
+ */
+class SVGEllipseElement : public SVGElement,
+ public SVGTests,
+ public SVGLangSpace,
+ public SVGExternalResourcesRequired,
+ public SVGStylable,
+ public SVGTransformable
+{
+public:
+ SVGEllipseElement();
+ SVGEllipseElement(const SVGEllipseElement &);
+ SVGEllipseElement &operator=(const SVGEllipseElement &other);
+ SVGEllipseElement(SVGEllipseElementImpl *);
+ ~SVGEllipseElement();
+
+ /**
+ * The x-axis coordinate of the center of the ellipse.
+ * If the attribute is not specified, the effect is as if a value
+ * of "0" were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The x-axis coordinate of the center of the ellipse.
+ */
+ SVGAnimatedLength cx();
+
+ /**
+ * The y-axis coordinate of the center of the ellipse.
+ * If the attribute is not specified, the effect is as if a value
+ * of "0" were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The y-axis coordinate of the center of the ellipse.
+ */
+ SVGAnimatedLength cy();
+
+ /**
+ * The x-axis radius of the ellipse.
+ * A negative value is an error (see <a href =
+ * "http://www.w3.org/TR/SVG/implnote.html#ErrorProcessing">
+ * Error processing</a>). A value of zero disables rendering of
+ * the element.
+ *
+ * This attribute is animatable.
+ *
+ * @return The x-radius of the ellipse.
+ */
+ SVGAnimatedLength rx();
+
+ /**
+ * The y-axis radius of the ellipse.
+ * A negative value is an error (see <a href =
+ * "http://www.w3.org/TR/SVG/implnote.html#ErrorProcessing">
+ * Error processing</a>). A value of zero disables rendering of
+ * the element.
+ *
+ * This attribute is animatable.
+ *
+ * @return The y-radius of the ellipse.
+ */
+ SVGAnimatedLength ry();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGEllipseElementImpl *handle() const { return impl; }
+
+private:
+ SVGEllipseElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGEvent.cc b/ksvg/dom/SVGEvent.cc
new file mode 100644
index 00000000..19fa6d27
--- /dev/null
+++ b/ksvg/dom/SVGEvent.cc
@@ -0,0 +1,187 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGEvent.h"
+#include "SVGEventImpl.h"
+
+using namespace KSVG;
+
+SVGEvent::SVGEvent() : DOM::Event()
+{
+ impl = 0;
+}
+
+SVGEvent::SVGEvent(const SVGEvent &other) : DOM::Event(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGEvent &SVGEvent::operator =(const SVGEvent &other)
+{
+ DOM::Event::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGEvent::SVGEvent(SVGEventImpl *other) : DOM::Event()
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGEvent::~SVGEvent()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGEvent::EventId SVGEvent::typeToId(DOM::DOMString type)
+{
+ if(type == "DOMFocusIn")
+ return DOMFOCUSIN_EVENT;
+ else if(type == "DOMFocusOut")
+ return DOMFOCUSOUT_EVENT;
+ else if(type == "DOMActivate")
+ return DOMACTIVATE_EVENT;
+ else if(type == "click")
+ return CLICK_EVENT;
+ else if(type == "mousedown")
+ return MOUSEDOWN_EVENT;
+ else if(type == "mouseup")
+ return MOUSEUP_EVENT;
+ else if(type == "mouseover")
+ return MOUSEOVER_EVENT;
+ else if(type == "mousemove")
+ return MOUSEMOVE_EVENT;
+ else if(type == "mouseout")
+ return MOUSEOUT_EVENT;
+ else if(type == "DOMSubtreeModified")
+ return DOMSUBTREEMODIFIED_EVENT;
+ else if(type == "DOMNodeInserted")
+ return DOMNODEINSERTED_EVENT;
+ else if(type == "DOMNodeRemoved")
+ return DOMNODEREMOVED_EVENT;
+ else if(type == "DOMNodeRemovedFromDocument")
+ return DOMNODEREMOVEDFROMDOCUMENT_EVENT;
+ else if(type == "DOMNodeInsertedIntoDocument")
+ return DOMNODEINSERTEDINTODOCUMENT_EVENT;
+ else if(type == "DOMAttrModified")
+ return DOMATTRMODIFIED_EVENT;
+ else if(type == "DOMCharacterDataModified")
+ return DOMCHARACTERDATAMODIFIED_EVENT;
+ else if(type == "load")
+ return LOAD_EVENT;
+ else if(type == "unload")
+ return UNLOAD_EVENT;
+ else if(type == "abort")
+ return ABORT_EVENT;
+ else if(type == "error")
+ return ERROR_EVENT;
+ else if(type == "resize")
+ return RESIZE_EVENT;
+ else if(type == "scroll")
+ return SCROLL_EVENT;
+ else if(type == "zoom")
+ return ZOOM_EVENT;
+ else if(type == "keydown")
+ return KEYDOWN_EVENT;
+ else if(type == "keyup")
+ return KEYUP_EVENT;
+ else if(type == "keypress")
+ return KEYPRESS_EVENT;
+
+ return UNKNOWN_EVENT;
+}
+
+DOM::DOMString SVGEvent::idToType(EventId id)
+{
+ switch(id)
+ {
+ case DOMFOCUSIN_EVENT:
+ return "DOMFocusIn";
+ case DOMFOCUSOUT_EVENT:
+ return "DOMFocusOut";
+ case DOMACTIVATE_EVENT:
+ return "DOMActivate";
+ case CLICK_EVENT:
+ return "click";
+ case MOUSEDOWN_EVENT:
+ return "mousedown";
+ case MOUSEUP_EVENT:
+ return "mouseup";
+ case MOUSEOVER_EVENT:
+ return "mouseover";
+ case MOUSEMOVE_EVENT:
+ return "mousemove";
+ case MOUSEOUT_EVENT:
+ return "mouseout";
+ case DOMSUBTREEMODIFIED_EVENT:
+ return "DOMSubtreeModified";
+ case DOMNODEINSERTED_EVENT:
+ return "DOMNodeInserted";
+ case DOMNODEREMOVED_EVENT:
+ return "DOMNodeRemoved";
+ case DOMNODEREMOVEDFROMDOCUMENT_EVENT:
+ return "DOMNodeRemovedFromDocument";
+ case DOMNODEINSERTEDINTODOCUMENT_EVENT:
+ return "DOMNodeInsertedIntoDocument";
+ case DOMATTRMODIFIED_EVENT:
+ return "DOMAttrModified";
+ case DOMCHARACTERDATAMODIFIED_EVENT:
+ return "DOMCharacterDataModified";
+ case LOAD_EVENT:
+ return "load";
+ case UNLOAD_EVENT:
+ return "unload";
+ case ABORT_EVENT:
+ return "abort";
+ case ERROR_EVENT:
+ return "error";
+ case RESIZE_EVENT:
+ return "resize";
+ case SCROLL_EVENT:
+ return "scroll";
+ case ZOOM_EVENT:
+ return "zoom";
+ case KEYDOWN_EVENT:
+ return "keydown";
+ case KEYUP_EVENT:
+ return "keyup";
+ case KEYPRESS_EVENT:
+ return "keypress";
+ default:
+ return DOM::DOMString();
+ break;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGEvent.h b/ksvg/dom/SVGEvent.h
new file mode 100644
index 00000000..6aebf0aa
--- /dev/null
+++ b/ksvg/dom/SVGEvent.h
@@ -0,0 +1,95 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGEvent_H
+#define SVGEvent_H
+
+#include <dom/dom2_events.h>
+
+namespace KSVG
+{
+
+class SVGEventImpl;
+class SVGEvent : public DOM::Event
+{
+public:
+ enum EventId
+ {
+ UNKNOWN_EVENT = 0,
+
+ // UI events
+ DOMFOCUSIN_EVENT,
+ DOMFOCUSOUT_EVENT,
+ DOMACTIVATE_EVENT,
+
+ // Mouse events
+ CLICK_EVENT,
+ MOUSEDOWN_EVENT,
+ MOUSEUP_EVENT,
+ MOUSEOVER_EVENT,
+ MOUSEMOVE_EVENT,
+ MOUSEOUT_EVENT,
+
+ // Mutation events
+ DOMSUBTREEMODIFIED_EVENT,
+ DOMNODEINSERTED_EVENT,
+ DOMNODEREMOVED_EVENT,
+ DOMNODEREMOVEDFROMDOCUMENT_EVENT,
+ DOMNODEINSERTEDINTODOCUMENT_EVENT,
+ DOMATTRMODIFIED_EVENT,
+ DOMCHARACTERDATAMODIFIED_EVENT,
+
+ // SVG events
+ LOAD_EVENT,
+ UNLOAD_EVENT,
+ ABORT_EVENT,
+ ERROR_EVENT,
+ RESIZE_EVENT,
+ SCROLL_EVENT,
+ ZOOM_EVENT,
+
+ // Key Events
+ KEYDOWN_EVENT,
+ KEYPRESS_EVENT,
+ KEYUP_EVENT
+ };
+
+ SVGEvent();
+ SVGEvent(const SVGEvent &other);
+ SVGEvent &operator=(const SVGEvent &other);
+ SVGEvent(SVGEventImpl *other);
+ virtual ~SVGEvent();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGEventImpl *handle() const { return impl; }
+
+ // Helper functions
+ static EventId typeToId(DOM::DOMString type);
+ static DOM::DOMString idToType(EventId id);
+
+private:
+ SVGEventImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGException.h b/ksvg/dom/SVGException.h
new file mode 100644
index 00000000..dbbe7175
--- /dev/null
+++ b/ksvg/dom/SVGException.h
@@ -0,0 +1,51 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGException_H
+#define SVGException_H
+
+namespace KSVG
+{
+// TODO : use when DOM is full and/or ecma binding comes into play
+class SVGException
+{
+public:
+ SVGException(unsigned short code) { m_code = code; }
+ SVGException(const SVGException &other) { m_code = other.m_code; }
+ SVGException &operator=(const SVGException &other)
+ {
+ m_code = other.m_code;
+ return *this;
+ }
+ ~SVGException() {}
+
+ enum ExceptionCode {
+ SVG_WRONG_TYPE_ERR = 0,
+ SVG_INVALID_VALUE_ERR = 1,
+ SVG_MATRIX_NOT_INVERTABLE = 2
+ };
+ unsigned short m_code;
+};
+
+};
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGExternalResourcesRequired.cc b/ksvg/dom/SVGExternalResourcesRequired.cc
new file mode 100644
index 00000000..986bf564
--- /dev/null
+++ b/ksvg/dom/SVGExternalResourcesRequired.cc
@@ -0,0 +1,65 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGExternalResourcesRequired.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+#include "SVGAnimatedBoolean.h"
+
+using namespace KSVG;
+
+// This class can't be constructed seperately.
+SVGExternalResourcesRequired::SVGExternalResourcesRequired()
+{
+ impl = 0;
+}
+
+SVGExternalResourcesRequired::SVGExternalResourcesRequired(const SVGExternalResourcesRequired &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGExternalResourcesRequired &SVGExternalResourcesRequired::operator=(const SVGExternalResourcesRequired &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ impl = other.impl;
+
+ return *this;
+}
+
+SVGExternalResourcesRequired::SVGExternalResourcesRequired(SVGExternalResourcesRequiredImpl *other)
+{
+ impl = other;
+}
+
+SVGExternalResourcesRequired::~SVGExternalResourcesRequired()
+{
+ // We are not allowed to delete 'impl' as it's not refcounted.
+ // delete impl;
+}
+
+SVGAnimatedBoolean SVGExternalResourcesRequired::externalResourcesRequired() const
+{
+ if(!impl) return SVGAnimatedBoolean(0);
+ return SVGAnimatedBoolean(impl->externalResourcesRequired());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGExternalResourcesRequired.h b/ksvg/dom/SVGExternalResourcesRequired.h
new file mode 100644
index 00000000..e3668881
--- /dev/null
+++ b/ksvg/dom/SVGExternalResourcesRequired.h
@@ -0,0 +1,53 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGExternalResourcesRequired_H
+#define SVGExternalResourcesRequired_H
+
+namespace KSVG
+{
+
+class SVGAnimatedBoolean;
+class SVGExternalResourcesRequiredImpl;
+class SVGExternalResourcesRequired
+{
+public:
+ SVGExternalResourcesRequired(const SVGExternalResourcesRequired &other);
+ SVGExternalResourcesRequired &operator=(const SVGExternalResourcesRequired &other);
+ SVGExternalResourcesRequired(SVGExternalResourcesRequiredImpl *other);
+ ~SVGExternalResourcesRequired();
+
+ SVGAnimatedBoolean externalResourcesRequired() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGExternalResourcesRequiredImpl *handle() const { return impl; }
+
+protected:
+ SVGExternalResourcesRequired();
+
+private:
+ SVGExternalResourcesRequiredImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEBlendElement.cc b/ksvg/dom/SVGFEBlendElement.cc
new file mode 100644
index 00000000..c991d18c
--- /dev/null
+++ b/ksvg/dom/SVGFEBlendElement.cc
@@ -0,0 +1,88 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEBlendElement.h"
+#include "SVGFEBlendElementImpl.h"
+#include "SVGAnimatedString.h"
+#include "SVGAnimatedEnumeration.h"
+
+using namespace KSVG;
+
+SVGFEBlendElement::SVGFEBlendElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes()
+{
+ impl = 0;
+}
+
+SVGFEBlendElement::SVGFEBlendElement(const SVGFEBlendElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFEBlendElement &SVGFEBlendElement::operator =(const SVGFEBlendElement &other)
+{
+ SVGElement::operator=(other);
+ SVGFilterPrimitiveStandardAttributes::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFEBlendElement::SVGFEBlendElement(SVGFEBlendElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFEBlendElement::~SVGFEBlendElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedString SVGFEBlendElement::in1() const
+{
+ if(!impl) return SVGAnimatedString(0);
+ return SVGAnimatedString(impl->in1());
+}
+
+SVGAnimatedString SVGFEBlendElement::in2() const
+{
+ if(!impl) return SVGAnimatedString(0);
+ return SVGAnimatedString(impl->in2());
+}
+
+SVGAnimatedEnumeration SVGFEBlendElement::mode() const
+{
+ if(!impl) return SVGAnimatedEnumeration(0);
+ return SVGAnimatedEnumeration(impl->mode());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEBlendElement.h b/ksvg/dom/SVGFEBlendElement.h
new file mode 100644
index 00000000..91c64b3f
--- /dev/null
+++ b/ksvg/dom/SVGFEBlendElement.h
@@ -0,0 +1,68 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEBlendElement_H
+#define SVGFEBlendElement_H
+
+#include "SVGElement.h"
+#include "SVGFilterPrimitiveStandardAttributes.h"
+
+namespace KSVG
+{
+
+enum
+{
+ SVG_FEBLEND_MODE_UNKNOWN = 0,
+ SVG_FEBLEND_MODE_NORMAL = 1,
+ SVG_FEBLEND_MODE_MULTIPLY = 2,
+ SVG_FEBLEND_MODE_SCREEN = 3,
+ SVG_FEBLEND_MODE_DARKEN = 4,
+ SVG_FEBLEND_MODE_LIGHTEN = 5
+};
+
+class SVGAnimatedString;
+class SVGAnimatedEnumeration;
+class SVGFEBlendElementImpl;
+class SVGFEBlendElement : public SVGElement,
+ public SVGFilterPrimitiveStandardAttributes
+{
+public:
+ SVGFEBlendElement();
+ SVGFEBlendElement(const SVGFEBlendElement &other);
+ SVGFEBlendElement &operator=(const SVGFEBlendElement &other);
+ SVGFEBlendElement(SVGFEBlendElementImpl *other);
+ virtual ~SVGFEBlendElement();
+
+ SVGAnimatedString in1() const;
+ SVGAnimatedString in2() const;
+ SVGAnimatedEnumeration mode() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFEBlendElementImpl *handle() const { return impl; }
+
+private:
+ SVGFEBlendElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEColorMatrixElement.cc b/ksvg/dom/SVGFEColorMatrixElement.cc
new file mode 100644
index 00000000..1f77ac0e
--- /dev/null
+++ b/ksvg/dom/SVGFEColorMatrixElement.cc
@@ -0,0 +1,89 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEColorMatrixElement.h"
+#include "SVGFEColorMatrixElementImpl.h"
+#include "SVGAnimatedString.h"
+#include "SVGAnimatedEnumeration.h"
+#include "SVGAnimatedNumberList.h"
+
+using namespace KSVG;
+
+SVGFEColorMatrixElement::SVGFEColorMatrixElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes()
+{
+ impl = 0;
+}
+
+SVGFEColorMatrixElement::SVGFEColorMatrixElement(const SVGFEColorMatrixElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFEColorMatrixElement &SVGFEColorMatrixElement::operator =(const SVGFEColorMatrixElement &other)
+{
+ SVGElement::operator=(other);
+ SVGFilterPrimitiveStandardAttributes::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFEColorMatrixElement::SVGFEColorMatrixElement(SVGFEColorMatrixElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFEColorMatrixElement::~SVGFEColorMatrixElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedString SVGFEColorMatrixElement::in1() const
+{
+ if(!impl) return SVGAnimatedString(0);
+ return SVGAnimatedString(impl->in1());
+}
+
+SVGAnimatedEnumeration SVGFEColorMatrixElement::type() const
+{
+ if(!impl) return SVGAnimatedEnumeration(0);
+ return SVGAnimatedEnumeration(impl->type());
+}
+
+SVGAnimatedNumberList SVGFEColorMatrixElement::values() const
+{
+ if(!impl) return SVGAnimatedNumberList(0);
+ return SVGAnimatedNumberList(impl->values());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEColorMatrixElement.h b/ksvg/dom/SVGFEColorMatrixElement.h
new file mode 100644
index 00000000..bbe51f16
--- /dev/null
+++ b/ksvg/dom/SVGFEColorMatrixElement.h
@@ -0,0 +1,68 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEColorMatrixElement_H
+#define SVGFEColorMatrixElement_H
+
+#include "SVGElement.h"
+#include "SVGFilterPrimitiveStandardAttributes.h"
+
+namespace KSVG
+{
+
+enum
+{
+ SVG_FECOLORMATRIX_TYPE_UNKNOWN = 0,
+ SVG_FECOLORMATRIX_TYPE_MATRIX = 1,
+ SVG_FECOLORMATRIX_TYPE_SATURATE = 2,
+ SVG_FECOLORMATRIX_TYPE_HUEROTATE = 3,
+ SVG_FECOLORMATRIX_TYPE_LUMINANCETOALPHA = 4
+};
+
+class SVGAnimatedString;
+class SVGAnimatedEnumeration;
+class SVGAnimatedNumberList;
+class SVGFEColorMatrixElementImpl;
+class SVGFEColorMatrixElement : public SVGElement,
+ public SVGFilterPrimitiveStandardAttributes
+{
+public:
+ SVGFEColorMatrixElement();
+ SVGFEColorMatrixElement(const SVGFEColorMatrixElement &other);
+ SVGFEColorMatrixElement &operator=(const SVGFEColorMatrixElement &other);
+ SVGFEColorMatrixElement(SVGFEColorMatrixElementImpl *other);
+ virtual ~SVGFEColorMatrixElement();
+
+ SVGAnimatedString in1() const;
+ SVGAnimatedEnumeration type() const;
+ SVGAnimatedNumberList values() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFEColorMatrixElementImpl *handle() const { return impl; }
+
+private:
+ SVGFEColorMatrixElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEComponentTransferElement.cc b/ksvg/dom/SVGFEComponentTransferElement.cc
new file mode 100644
index 00000000..ea0d7490
--- /dev/null
+++ b/ksvg/dom/SVGFEComponentTransferElement.cc
@@ -0,0 +1,75 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEComponentTransferElement.h"
+#include "SVGFEComponentTransferElementImpl.h"
+#include "SVGAnimatedString.h"
+
+using namespace KSVG;
+
+SVGFEComponentTransferElement::SVGFEComponentTransferElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes()
+{
+ impl = 0;
+}
+
+SVGFEComponentTransferElement::SVGFEComponentTransferElement(const SVGFEComponentTransferElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFEComponentTransferElement &SVGFEComponentTransferElement::operator =(const SVGFEComponentTransferElement &other)
+{
+ SVGElement::operator=(other);
+ SVGFilterPrimitiveStandardAttributes::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFEComponentTransferElement::SVGFEComponentTransferElement(SVGFEComponentTransferElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFEComponentTransferElement::~SVGFEComponentTransferElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedString SVGFEComponentTransferElement::in1() const
+{
+ if(!impl) return SVGAnimatedString(0);
+ return SVGAnimatedString(impl->in1());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEComponentTransferElement.h b/ksvg/dom/SVGFEComponentTransferElement.h
new file mode 100644
index 00000000..c387a4ca
--- /dev/null
+++ b/ksvg/dom/SVGFEComponentTransferElement.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEComponentTransferElement_H
+#define SVGFEComponentTransferElement_H
+
+#include "SVGElement.h"
+#include "SVGFilterPrimitiveStandardAttributes.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedString;
+class SVGFEComponentTransferElementImpl;
+class SVGFEComponentTransferElement : public SVGElement,
+ public SVGFilterPrimitiveStandardAttributes
+{
+public:
+ SVGFEComponentTransferElement();
+ SVGFEComponentTransferElement(const SVGFEComponentTransferElement &other);
+ SVGFEComponentTransferElement &operator=(const SVGFEComponentTransferElement &other);
+ SVGFEComponentTransferElement(SVGFEComponentTransferElementImpl *other);
+ virtual ~SVGFEComponentTransferElement();
+
+ SVGAnimatedString in1() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFEComponentTransferElementImpl *handle() const { return impl; }
+
+private:
+ SVGFEComponentTransferElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFECompositeElement.cc b/ksvg/dom/SVGFECompositeElement.cc
new file mode 100644
index 00000000..61cf4352
--- /dev/null
+++ b/ksvg/dom/SVGFECompositeElement.cc
@@ -0,0 +1,113 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFECompositeElement.h"
+#include "SVGFECompositeElementImpl.h"
+#include "SVGAnimatedNumber.h"
+#include "SVGAnimatedString.h"
+#include "SVGAnimatedEnumeration.h"
+
+using namespace KSVG;
+
+SVGFECompositeElement::SVGFECompositeElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes()
+{
+ impl = 0;
+}
+
+SVGFECompositeElement::SVGFECompositeElement(const SVGFECompositeElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFECompositeElement &SVGFECompositeElement::operator =(const SVGFECompositeElement &other)
+{
+ SVGElement::operator=(other);
+ SVGFilterPrimitiveStandardAttributes::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFECompositeElement::SVGFECompositeElement(SVGFECompositeElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFECompositeElement::~SVGFECompositeElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedString SVGFECompositeElement::in1() const
+{
+ if(!impl) return SVGAnimatedString(0);
+ return SVGAnimatedString(impl->in1());
+}
+
+SVGAnimatedString SVGFECompositeElement::in2() const
+{
+ if(!impl) return SVGAnimatedString(0);
+ return SVGAnimatedString(impl->in2());
+}
+
+SVGAnimatedEnumeration SVGFECompositeElement::Operator() const
+{
+ if(!impl) return SVGAnimatedEnumeration(0);
+ return SVGAnimatedEnumeration(impl->Operator());
+}
+
+SVGAnimatedNumber SVGFECompositeElement::k1() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->k1());
+}
+
+SVGAnimatedNumber SVGFECompositeElement::k2() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->k2());
+}
+
+SVGAnimatedNumber SVGFECompositeElement::k3() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->k3());
+}
+
+SVGAnimatedNumber SVGFECompositeElement::k4() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->k4());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFECompositeElement.h b/ksvg/dom/SVGFECompositeElement.h
new file mode 100644
index 00000000..dcfa1817
--- /dev/null
+++ b/ksvg/dom/SVGFECompositeElement.h
@@ -0,0 +1,74 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFECompositeElement_H
+#define SVGFECompositeElement_H
+
+#include "SVGElement.h"
+#include "SVGFilterPrimitiveStandardAttributes.h"
+
+namespace KSVG
+{
+
+enum
+{
+ SVG_FECOMPOSITE_OPERATOR_UNKNOWN = 0,
+ SVG_FECOMPOSITE_OPERATOR_OVER = 1,
+ SVG_FECOMPOSITE_OPERATOR_IN = 2,
+ SVG_FECOMPOSITE_OPERATOR_OUT = 3,
+ SVG_FECOMPOSITE_OPERATOR_ATOP = 4,
+ SVG_FECOMPOSITE_OPERATOR_XOR = 5,
+ SVG_FECOMPOSITE_OPERATOR_ARITHMETIC = 6
+};
+
+class SVGAnimatedString;
+class SVGAnimatedEnumeration;
+class SVGAnimatedNumber;
+class SVGFECompositeElementImpl;
+class SVGFECompositeElement : public SVGElement,
+ public SVGFilterPrimitiveStandardAttributes
+{
+public:
+ SVGFECompositeElement();
+ SVGFECompositeElement(const SVGFECompositeElement &other);
+ SVGFECompositeElement &operator=(const SVGFECompositeElement &other);
+ SVGFECompositeElement(SVGFECompositeElementImpl *other);
+ virtual ~SVGFECompositeElement();
+
+ SVGAnimatedString in1() const;
+ SVGAnimatedString in2() const;
+ SVGAnimatedEnumeration Operator() const; // TODO : impossible otherwise ?
+ SVGAnimatedNumber k1() const;
+ SVGAnimatedNumber k2() const;
+ SVGAnimatedNumber k3() const;
+ SVGAnimatedNumber k4() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFECompositeElementImpl *handle() const { return impl; }
+
+private:
+ SVGFECompositeElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEConvolveMatrixElement.cc b/ksvg/dom/SVGFEConvolveMatrixElement.cc
new file mode 100644
index 00000000..5ecc292c
--- /dev/null
+++ b/ksvg/dom/SVGFEConvolveMatrixElement.cc
@@ -0,0 +1,140 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEConvolveMatrixElement.h"
+#include "SVGFEConvolveMatrixElementImpl.h"
+#include "SVGAnimatedInteger.h"
+#include "SVGAnimatedNumberList.h"
+#include "SVGAnimatedNumber.h"
+#include "SVGAnimatedEnumeration.h"
+#include "SVGAnimatedLength.h"
+#include "SVGAnimatedBoolean.h"
+
+using namespace KSVG;
+
+SVGFEConvolveMatrixElement::SVGFEConvolveMatrixElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes()
+{
+ impl = 0;
+}
+
+SVGFEConvolveMatrixElement::SVGFEConvolveMatrixElement(const SVGFEConvolveMatrixElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFEConvolveMatrixElement &SVGFEConvolveMatrixElement::operator =(const SVGFEConvolveMatrixElement &other)
+{
+ SVGElement::operator=(other);
+ SVGFilterPrimitiveStandardAttributes::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFEConvolveMatrixElement::SVGFEConvolveMatrixElement(SVGFEConvolveMatrixElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFEConvolveMatrixElement::~SVGFEConvolveMatrixElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedInteger SVGFEConvolveMatrixElement::orderX() const
+{
+ if(!impl) return SVGAnimatedInteger(0);
+ return SVGAnimatedInteger(impl->orderX());
+}
+
+SVGAnimatedInteger SVGFEConvolveMatrixElement::orderY() const
+{
+ if(!impl) return SVGAnimatedInteger(0);
+ return SVGAnimatedInteger(impl->orderY());
+}
+
+SVGAnimatedNumberList SVGFEConvolveMatrixElement::kernelMatrix() const
+{
+ if(!impl) return SVGAnimatedNumberList(0);
+ return SVGAnimatedNumberList(impl->kernelMatrix());
+}
+
+SVGAnimatedNumber SVGFEConvolveMatrixElement::divisor() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->divisor());
+}
+
+SVGAnimatedNumber SVGFEConvolveMatrixElement::bias() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->bias());
+}
+
+SVGAnimatedInteger SVGFEConvolveMatrixElement::targetX() const
+{
+ if(!impl) return SVGAnimatedInteger(0);
+ return SVGAnimatedInteger(impl->targetX());
+}
+
+SVGAnimatedInteger SVGFEConvolveMatrixElement::targetY() const
+{
+ if(!impl) return SVGAnimatedInteger(0);
+ return SVGAnimatedInteger(impl->targetY());
+}
+
+SVGAnimatedEnumeration SVGFEConvolveMatrixElement::edgeMode() const
+{
+ if(!impl) return SVGAnimatedEnumeration(0);
+ return SVGAnimatedEnumeration(impl->edgeMode());
+}
+
+SVGAnimatedLength SVGFEConvolveMatrixElement::kernelUnitLengthX() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->kernelUnitLengthX());
+}
+
+SVGAnimatedLength SVGFEConvolveMatrixElement::kernelUnitLengthY() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->kernelUnitLengthY());
+}
+
+SVGAnimatedBoolean SVGFEConvolveMatrixElement::preserveAlpha() const
+{
+ if(!impl) return SVGAnimatedBoolean(0);
+ return SVGAnimatedBoolean(impl->preserveAlpha());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEConvolveMatrixElement.h b/ksvg/dom/SVGFEConvolveMatrixElement.h
new file mode 100644
index 00000000..88a7ed00
--- /dev/null
+++ b/ksvg/dom/SVGFEConvolveMatrixElement.h
@@ -0,0 +1,78 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEConvolveMatrixElement_H
+#define SVGFEConvolveMatrixElement_H
+
+#include "SVGElement.h"
+#include "SVGFilterPrimitiveStandardAttributes.h"
+
+namespace KSVG
+{
+
+enum
+{
+ SVG_EDGEMODE_UNKNOWN = 0,
+ SVG_EDGEMODE_DUPLICATE = 1,
+ SVG_EDGEMODE_WRAP = 2,
+ SVG_EDGEMODE_NONE = 3
+};
+
+class SVGAnimatedInteger;
+class SVGAnimatedNumberList;
+class SVGAnimatedNumber;
+class SVGAnimatedEnumeration;
+class SVGAnimatedLength;
+class SVGAnimatedBoolean;
+class SVGFEConvolveMatrixElementImpl;
+class SVGFEConvolveMatrixElement : public SVGElement,
+ public SVGFilterPrimitiveStandardAttributes
+{
+public:
+ SVGFEConvolveMatrixElement();
+ SVGFEConvolveMatrixElement(const SVGFEConvolveMatrixElement &other);
+ SVGFEConvolveMatrixElement &operator=(const SVGFEConvolveMatrixElement &other);
+ SVGFEConvolveMatrixElement(SVGFEConvolveMatrixElementImpl *other);
+ virtual ~SVGFEConvolveMatrixElement();
+
+ SVGAnimatedInteger orderX() const;
+ SVGAnimatedInteger orderY() const;
+ SVGAnimatedNumberList kernelMatrix() const;
+ SVGAnimatedNumber divisor() const;
+ SVGAnimatedNumber bias() const;
+ SVGAnimatedInteger targetX() const;
+ SVGAnimatedInteger targetY() const;
+ SVGAnimatedEnumeration edgeMode() const;
+ SVGAnimatedLength kernelUnitLengthX() const;
+ SVGAnimatedLength kernelUnitLengthY() const;
+ SVGAnimatedBoolean preserveAlpha() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFEConvolveMatrixElementImpl *handle() const { return impl; }
+
+private:
+ SVGFEConvolveMatrixElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEDiffuseLightingElement.cc b/ksvg/dom/SVGFEDiffuseLightingElement.cc
new file mode 100644
index 00000000..eba5935f
--- /dev/null
+++ b/ksvg/dom/SVGFEDiffuseLightingElement.cc
@@ -0,0 +1,88 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEDiffuseLightingElement.h"
+#include "SVGFEDiffuseLightingElementImpl.h"
+#include "SVGAnimatedString.h"
+#include "SVGAnimatedNumber.h"
+
+using namespace KSVG;
+
+SVGFEDiffuseLightingElement::SVGFEDiffuseLightingElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes()
+{
+ impl = 0;
+}
+
+SVGFEDiffuseLightingElement::SVGFEDiffuseLightingElement(const SVGFEDiffuseLightingElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFEDiffuseLightingElement &SVGFEDiffuseLightingElement::operator =(const SVGFEDiffuseLightingElement &other)
+{
+ SVGElement::operator=(other);
+ SVGFilterPrimitiveStandardAttributes::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFEDiffuseLightingElement::SVGFEDiffuseLightingElement(SVGFEDiffuseLightingElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFEDiffuseLightingElement::~SVGFEDiffuseLightingElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedString SVGFEDiffuseLightingElement::in1() const
+{
+ if(!impl) return SVGAnimatedString(0);
+ return SVGAnimatedString(impl->in1());
+}
+
+SVGAnimatedNumber SVGFEDiffuseLightingElement::surfaceScale() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->surfaceScale());
+}
+
+SVGAnimatedNumber SVGFEDiffuseLightingElement::diffuseConstant() const
+{
+ if(!impl) return SVGAnimatedNumber();
+ return SVGAnimatedNumber(impl->diffuseConstant());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEDiffuseLightingElement.h b/ksvg/dom/SVGFEDiffuseLightingElement.h
new file mode 100644
index 00000000..6356d996
--- /dev/null
+++ b/ksvg/dom/SVGFEDiffuseLightingElement.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEDiffuseLightingElement_H
+#define SVGFEDiffuseLightingElement_H
+
+#include "SVGElement.h"
+#include "SVGFilterPrimitiveStandardAttributes.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedString;
+class SVGAnimatedNumber;
+class SVGFEDiffuseLightingElementImpl;
+class SVGFEDiffuseLightingElement : public SVGElement,
+ public SVGFilterPrimitiveStandardAttributes
+{
+public:
+ SVGFEDiffuseLightingElement();
+ SVGFEDiffuseLightingElement(const SVGFEDiffuseLightingElement &other);
+ SVGFEDiffuseLightingElement &operator=(const SVGFEDiffuseLightingElement &other);
+ SVGFEDiffuseLightingElement(SVGFEDiffuseLightingElementImpl *other);
+ virtual ~SVGFEDiffuseLightingElement();
+
+ SVGAnimatedString in1() const;
+ SVGAnimatedNumber surfaceScale() const;
+ SVGAnimatedNumber diffuseConstant() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFEDiffuseLightingElementImpl *handle() const { return impl; }
+
+private:
+ SVGFEDiffuseLightingElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEDisplacementMapElement.cc b/ksvg/dom/SVGFEDisplacementMapElement.cc
new file mode 100644
index 00000000..7c41fd3e
--- /dev/null
+++ b/ksvg/dom/SVGFEDisplacementMapElement.cc
@@ -0,0 +1,101 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEDisplacementMapElement.h"
+#include "SVGFEDisplacementMapElementImpl.h"
+#include "SVGAnimatedString.h"
+#include "SVGAnimatedNumber.h"
+#include "SVGAnimatedEnumeration.h"
+
+using namespace KSVG;
+
+SVGFEDisplacementMapElement::SVGFEDisplacementMapElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes()
+{
+ impl = 0;
+}
+
+SVGFEDisplacementMapElement::SVGFEDisplacementMapElement(const SVGFEDisplacementMapElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFEDisplacementMapElement &SVGFEDisplacementMapElement::operator =(const SVGFEDisplacementMapElement &other)
+{
+ SVGElement::operator=(other);
+ SVGFilterPrimitiveStandardAttributes::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFEDisplacementMapElement::SVGFEDisplacementMapElement(SVGFEDisplacementMapElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFEDisplacementMapElement::~SVGFEDisplacementMapElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedString SVGFEDisplacementMapElement::in1() const
+{
+ if(!impl) return SVGAnimatedString(0);
+ return SVGAnimatedString(impl->in1());
+}
+
+SVGAnimatedString SVGFEDisplacementMapElement::in2() const
+{
+ if(!impl) return SVGAnimatedString(0);
+ return SVGAnimatedString(impl->in2());
+}
+
+SVGAnimatedNumber SVGFEDisplacementMapElement::scale() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->scale());
+}
+
+SVGAnimatedEnumeration SVGFEDisplacementMapElement::xChannelSelector() const
+{
+ if(!impl) return SVGAnimatedEnumeration(0);
+ return SVGAnimatedEnumeration(impl->xChannelSelector());
+}
+
+SVGAnimatedEnumeration SVGFEDisplacementMapElement::yChannelSelector() const
+{
+ if(!impl) return SVGAnimatedEnumeration(0);
+ return SVGAnimatedEnumeration(impl->yChannelSelector());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEDisplacementMapElement.h b/ksvg/dom/SVGFEDisplacementMapElement.h
new file mode 100644
index 00000000..ee591ca4
--- /dev/null
+++ b/ksvg/dom/SVGFEDisplacementMapElement.h
@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEDisplacementMapElement_H
+#define SVGFEDisplacementMapElement_H
+
+#include "SVGElement.h"
+#include "SVGFilterPrimitiveStandardAttributes.h"
+
+namespace KSVG
+{
+enum
+{
+ SVG_CHANNEL_UNKNOWN = 0,
+ SVG_CHANNEL_R = 1,
+ SVG_CHANNEL_G = 2,
+ SVG_CHANNEL_B = 3,
+ SVG_CHANNEL_A = 4
+};
+
+class SVGAnimatedNumber;
+class SVGAnimatedString;
+class SVGAnimatedEnumeration;
+class SVGFEDisplacementMapElementImpl;
+class SVGFEDisplacementMapElement : public SVGElement,
+ public SVGFilterPrimitiveStandardAttributes
+{
+public:
+ SVGFEDisplacementMapElement();
+ SVGFEDisplacementMapElement(const SVGFEDisplacementMapElement &other);
+ SVGFEDisplacementMapElement &operator=(const SVGFEDisplacementMapElement &other);
+ SVGFEDisplacementMapElement(SVGFEDisplacementMapElementImpl *other);
+ virtual ~SVGFEDisplacementMapElement();
+
+ SVGAnimatedString in1() const;
+ SVGAnimatedString in2() const;
+ SVGAnimatedNumber scale() const;
+ SVGAnimatedEnumeration xChannelSelector() const;
+ SVGAnimatedEnumeration yChannelSelector() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFEDisplacementMapElementImpl *handle() const { return impl; }
+
+private:
+ SVGFEDisplacementMapElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEDistantLightElement.cc b/ksvg/dom/SVGFEDistantLightElement.cc
new file mode 100644
index 00000000..92371abc
--- /dev/null
+++ b/ksvg/dom/SVGFEDistantLightElement.cc
@@ -0,0 +1,80 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEDistantLightElement.h"
+#include "SVGFEDistantLightElementImpl.h"
+#include "SVGAnimatedNumber.h"
+
+using namespace KSVG;
+
+SVGFEDistantLightElement::SVGFEDistantLightElement() : SVGElement()
+{
+ impl = 0;
+}
+
+SVGFEDistantLightElement::SVGFEDistantLightElement(const SVGFEDistantLightElement &other) : SVGElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFEDistantLightElement &SVGFEDistantLightElement::operator =(const SVGFEDistantLightElement &other)
+{
+ SVGElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFEDistantLightElement::SVGFEDistantLightElement(SVGFEDistantLightElementImpl *other) : SVGElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFEDistantLightElement::~SVGFEDistantLightElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedNumber SVGFEDistantLightElement::azimuth() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->azimuth());
+}
+
+SVGAnimatedNumber SVGFEDistantLightElement::elevation() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->elevation());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEDistantLightElement.h b/ksvg/dom/SVGFEDistantLightElement.h
new file mode 100644
index 00000000..4b2c926a
--- /dev/null
+++ b/ksvg/dom/SVGFEDistantLightElement.h
@@ -0,0 +1,54 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEDistantLightElement_H
+#define SVGFEDistantLightElement_H
+
+#include "SVGElement.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedNumber;
+class SVGFEDistantLightElementImpl;
+class SVGFEDistantLightElement : public SVGElement
+{
+public:
+ SVGFEDistantLightElement();
+ SVGFEDistantLightElement(const SVGFEDistantLightElement &other);
+ SVGFEDistantLightElement &operator=(const SVGFEDistantLightElement &other);
+ SVGFEDistantLightElement(SVGFEDistantLightElementImpl *other);
+ virtual ~SVGFEDistantLightElement();
+
+ SVGAnimatedNumber azimuth() const;
+ SVGAnimatedNumber elevation() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFEDistantLightElementImpl *handle() const { return impl; }
+
+private:
+ SVGFEDistantLightElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEFloodElement.cc b/ksvg/dom/SVGFEFloodElement.cc
new file mode 100644
index 00000000..7b0b320c
--- /dev/null
+++ b/ksvg/dom/SVGFEFloodElement.cc
@@ -0,0 +1,76 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEFloodElement.h"
+#include "SVGFEFloodElementImpl.h"
+#include "SVGAnimatedString.h"
+
+using namespace KSVG;
+
+SVGFEFloodElement::SVGFEFloodElement() : SVGElement(), SVGStylable(), SVGFilterPrimitiveStandardAttributes()
+{
+ impl = 0;
+}
+
+SVGFEFloodElement::SVGFEFloodElement(const SVGFEFloodElement &other) : SVGElement(other), SVGStylable(other), SVGFilterPrimitiveStandardAttributes(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFEFloodElement &SVGFEFloodElement::operator =(const SVGFEFloodElement &other)
+{
+ SVGElement::operator=(other);
+ SVGStylable::operator=(other);
+ SVGFilterPrimitiveStandardAttributes::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFEFloodElement::SVGFEFloodElement(SVGFEFloodElementImpl *other) : SVGElement(other), SVGStylable(other), SVGFilterPrimitiveStandardAttributes(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFEFloodElement::~SVGFEFloodElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedString SVGFEFloodElement::in1() const
+{
+ if(!impl) return SVGAnimatedString(0);
+ return SVGAnimatedString(impl->in1());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEFloodElement.h b/ksvg/dom/SVGFEFloodElement.h
new file mode 100644
index 00000000..401e056b
--- /dev/null
+++ b/ksvg/dom/SVGFEFloodElement.h
@@ -0,0 +1,57 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEFloodElement_H
+#define SVGFEFloodElement_H
+
+#include "SVGElement.h"
+#include "SVGStylable.h"
+#include "SVGFilterPrimitiveStandardAttributes.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedString;
+class SVGFEFloodElementImpl;
+class SVGFEFloodElement : public SVGElement,
+ public SVGStylable,
+ public SVGFilterPrimitiveStandardAttributes
+{
+public:
+ SVGFEFloodElement();
+ SVGFEFloodElement(const SVGFEFloodElement &other);
+ SVGFEFloodElement &operator=(const SVGFEFloodElement &other);
+ SVGFEFloodElement(SVGFEFloodElementImpl *other);
+ virtual ~SVGFEFloodElement();
+
+ SVGAnimatedString in1() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFEFloodElementImpl *handle() const { return impl; }
+
+private:
+ SVGFEFloodElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEFuncAElement.cc b/ksvg/dom/SVGFEFuncAElement.cc
new file mode 100644
index 00000000..cd0e9f10
--- /dev/null
+++ b/ksvg/dom/SVGFEFuncAElement.cc
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEFuncAElement.h"
+#include "SVGFEFuncAElementImpl.h"
+
+using namespace KSVG;
+
+SVGFEFuncAElement::SVGFEFuncAElement() : SVGComponentTransferFunctionElement()
+{
+ impl = 0;
+}
+
+SVGFEFuncAElement::SVGFEFuncAElement(const SVGFEFuncAElement &other) : SVGComponentTransferFunctionElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFEFuncAElement &SVGFEFuncAElement::operator =(const SVGFEFuncAElement &other)
+{
+ SVGComponentTransferFunctionElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFEFuncAElement::SVGFEFuncAElement(SVGFEFuncAElementImpl *other) : SVGComponentTransferFunctionElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFEFuncAElement::~SVGFEFuncAElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEFuncAElement.h b/ksvg/dom/SVGFEFuncAElement.h
new file mode 100644
index 00000000..64287f27
--- /dev/null
+++ b/ksvg/dom/SVGFEFuncAElement.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEFuncAElement_H
+#define SVGFEFuncAElement_H
+
+#include "SVGComponentTransferFunctionElement.h"
+
+namespace KSVG
+{
+
+class SVGFEFuncAElementImpl;
+class SVGFEFuncAElement : public SVGComponentTransferFunctionElement
+{
+public:
+ SVGFEFuncAElement();
+ SVGFEFuncAElement(const SVGFEFuncAElement &other);
+ SVGFEFuncAElement &operator=(const SVGFEFuncAElement &other);
+ SVGFEFuncAElement(SVGFEFuncAElementImpl *other);
+ virtual ~SVGFEFuncAElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFEFuncAElementImpl *handle() const { return impl; }
+
+private:
+ SVGFEFuncAElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEFuncBElement.cc b/ksvg/dom/SVGFEFuncBElement.cc
new file mode 100644
index 00000000..2cf0fdb0
--- /dev/null
+++ b/ksvg/dom/SVGFEFuncBElement.cc
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEFuncBElement.h"
+#include "SVGFEFuncBElementImpl.h"
+
+using namespace KSVG;
+
+SVGFEFuncBElement::SVGFEFuncBElement() : SVGComponentTransferFunctionElement()
+{
+ impl = 0;
+}
+
+SVGFEFuncBElement::SVGFEFuncBElement(const SVGFEFuncBElement &other) : SVGComponentTransferFunctionElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFEFuncBElement &SVGFEFuncBElement::operator =(const SVGFEFuncBElement &other)
+{
+ SVGComponentTransferFunctionElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFEFuncBElement::SVGFEFuncBElement(SVGFEFuncBElementImpl *other) : SVGComponentTransferFunctionElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFEFuncBElement::~SVGFEFuncBElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEFuncBElement.h b/ksvg/dom/SVGFEFuncBElement.h
new file mode 100644
index 00000000..2eacbbc3
--- /dev/null
+++ b/ksvg/dom/SVGFEFuncBElement.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEFuncBElement_H
+#define SVGFEFuncBElement_H
+
+#include "SVGComponentTransferFunctionElement.h"
+
+namespace KSVG
+{
+
+class SVGFEFuncBElementImpl;
+class SVGFEFuncBElement : public SVGComponentTransferFunctionElement
+{
+public:
+ SVGFEFuncBElement();
+ SVGFEFuncBElement(const SVGFEFuncBElement &other);
+ SVGFEFuncBElement &operator=(const SVGFEFuncBElement &other);
+ SVGFEFuncBElement(SVGFEFuncBElementImpl *other);
+ virtual ~SVGFEFuncBElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFEFuncBElementImpl *handle() const { return impl; }
+
+private:
+ SVGFEFuncBElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEFuncGElement.cc b/ksvg/dom/SVGFEFuncGElement.cc
new file mode 100644
index 00000000..ef8fdfea
--- /dev/null
+++ b/ksvg/dom/SVGFEFuncGElement.cc
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEFuncGElement.h"
+#include "SVGFEFuncGElementImpl.h"
+
+using namespace KSVG;
+
+SVGFEFuncGElement::SVGFEFuncGElement() : SVGComponentTransferFunctionElement()
+{
+ impl = 0;
+}
+
+SVGFEFuncGElement::SVGFEFuncGElement(const SVGFEFuncGElement &other) : SVGComponentTransferFunctionElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFEFuncGElement &SVGFEFuncGElement::operator =(const SVGFEFuncGElement &other)
+{
+ SVGComponentTransferFunctionElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFEFuncGElement::SVGFEFuncGElement(SVGFEFuncGElementImpl *other) : SVGComponentTransferFunctionElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFEFuncGElement::~SVGFEFuncGElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEFuncGElement.h b/ksvg/dom/SVGFEFuncGElement.h
new file mode 100644
index 00000000..09c98195
--- /dev/null
+++ b/ksvg/dom/SVGFEFuncGElement.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEFuncGElement_H
+#define SVGFEFuncGElement_H
+
+#include "SVGComponentTransferFunctionElement.h"
+
+namespace KSVG
+{
+
+class SVGFEFuncGElementImpl;
+class SVGFEFuncGElement : public SVGComponentTransferFunctionElement
+{
+public:
+ SVGFEFuncGElement();
+ SVGFEFuncGElement(const SVGFEFuncGElement &other);
+ SVGFEFuncGElement &operator=(const SVGFEFuncGElement &other);
+ SVGFEFuncGElement(SVGFEFuncGElementImpl *other);
+ virtual ~SVGFEFuncGElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFEFuncGElementImpl *handle() const { return impl; }
+
+private:
+ SVGFEFuncGElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEFuncRElement.cc b/ksvg/dom/SVGFEFuncRElement.cc
new file mode 100644
index 00000000..2020e33c
--- /dev/null
+++ b/ksvg/dom/SVGFEFuncRElement.cc
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEFuncRElement.h"
+#include "SVGFEFuncRElementImpl.h"
+
+using namespace KSVG;
+
+SVGFEFuncRElement::SVGFEFuncRElement() : SVGComponentTransferFunctionElement()
+{
+ impl = 0;
+}
+
+SVGFEFuncRElement::SVGFEFuncRElement(const SVGFEFuncRElement &other) : SVGComponentTransferFunctionElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFEFuncRElement &SVGFEFuncRElement::operator =(const SVGFEFuncRElement &other)
+{
+ SVGComponentTransferFunctionElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFEFuncRElement::SVGFEFuncRElement(SVGFEFuncRElementImpl *other) : SVGComponentTransferFunctionElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFEFuncRElement::~SVGFEFuncRElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEFuncRElement.h b/ksvg/dom/SVGFEFuncRElement.h
new file mode 100644
index 00000000..1a58ef15
--- /dev/null
+++ b/ksvg/dom/SVGFEFuncRElement.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEFuncRElement_H
+#define SVGFEFuncRElement_H
+
+#include "SVGComponentTransferFunctionElement.h"
+
+namespace KSVG
+{
+
+class SVGFEFuncRElementImpl;
+class SVGFEFuncRElement : public SVGComponentTransferFunctionElement
+{
+public:
+ SVGFEFuncRElement();
+ SVGFEFuncRElement(const SVGFEFuncRElement &other);
+ SVGFEFuncRElement &operator=(const SVGFEFuncRElement &other);
+ SVGFEFuncRElement(SVGFEFuncRElementImpl *other);
+ virtual ~SVGFEFuncRElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFEFuncRElementImpl *handle() const { return impl; }
+
+private:
+ SVGFEFuncRElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEGaussianBlurElement.cc b/ksvg/dom/SVGFEGaussianBlurElement.cc
new file mode 100644
index 00000000..2daaa8b8
--- /dev/null
+++ b/ksvg/dom/SVGFEGaussianBlurElement.cc
@@ -0,0 +1,94 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEGaussianBlurElement.h"
+#include "SVGFEGaussianBlurElementImpl.h"
+#include "SVGAnimatedString.h"
+#include "SVGAnimatedNumber.h"
+
+using namespace KSVG;
+
+SVGFEGaussianBlurElement::SVGFEGaussianBlurElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes()
+{
+ impl = 0;
+}
+
+SVGFEGaussianBlurElement::SVGFEGaussianBlurElement(const SVGFEGaussianBlurElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFEGaussianBlurElement &SVGFEGaussianBlurElement::operator =(const SVGFEGaussianBlurElement &other)
+{
+ SVGElement::operator=(other);
+ SVGFilterPrimitiveStandardAttributes::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFEGaussianBlurElement::SVGFEGaussianBlurElement(SVGFEGaussianBlurElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFEGaussianBlurElement::~SVGFEGaussianBlurElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedString SVGFEGaussianBlurElement::in1() const
+{
+ if(!impl) return SVGAnimatedString(0);
+ return SVGAnimatedString(impl->in1());
+}
+
+SVGAnimatedNumber SVGFEGaussianBlurElement::stdDeviationX() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->stdDeviationX());
+}
+
+SVGAnimatedNumber SVGFEGaussianBlurElement::stdDeviationY() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->stdDeviationY());
+}
+
+void SVGFEGaussianBlurElement::setStdDeviation(float stdDeviationX, float stdDeviationY)
+{
+ if(impl)
+ impl->setStdDeviation(stdDeviationX, stdDeviationY);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEGaussianBlurElement.h b/ksvg/dom/SVGFEGaussianBlurElement.h
new file mode 100644
index 00000000..a920ea68
--- /dev/null
+++ b/ksvg/dom/SVGFEGaussianBlurElement.h
@@ -0,0 +1,60 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEGaussianBlurElement_H
+#define SVGFEGaussianBlurElement_H
+
+#include "SVGElement.h"
+#include "SVGFilterPrimitiveStandardAttributes.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedString;
+class SVGAnimatedNumber;
+class SVGFEGaussianBlurElementImpl;
+class SVGFEGaussianBlurElement : public SVGElement,
+ public SVGFilterPrimitiveStandardAttributes
+{
+public:
+ SVGFEGaussianBlurElement();
+ SVGFEGaussianBlurElement(const SVGFEGaussianBlurElement &other);
+ SVGFEGaussianBlurElement &operator=(const SVGFEGaussianBlurElement &other);
+ SVGFEGaussianBlurElement(SVGFEGaussianBlurElementImpl *other);
+ virtual ~SVGFEGaussianBlurElement();
+
+ SVGAnimatedString in1() const;
+ SVGAnimatedNumber stdDeviationX() const;
+ SVGAnimatedNumber stdDeviationY() const;
+
+ void setStdDeviation(float stdDeviationX, float stdDeviationY);
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFEGaussianBlurElementImpl *handle() const { return impl; }
+
+private:
+ SVGFEGaussianBlurElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEImageElement.cc b/ksvg/dom/SVGFEImageElement.cc
new file mode 100644
index 00000000..6781edb6
--- /dev/null
+++ b/ksvg/dom/SVGFEImageElement.cc
@@ -0,0 +1,72 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEImageElement.h"
+#include "SVGFEImageElementImpl.h"
+
+using namespace KSVG;
+
+SVGFEImageElement::SVGFEImageElement() : SVGElement(), SVGURIReference(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGFilterPrimitiveStandardAttributes()
+{
+ impl = 0;
+}
+
+SVGFEImageElement::SVGFEImageElement(const SVGFEImageElement &other) : SVGElement(other), SVGURIReference(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGFilterPrimitiveStandardAttributes(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFEImageElement &SVGFEImageElement::operator =(const SVGFEImageElement &other)
+{
+ SVGElement::operator=(other);
+ SVGURIReference::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+ SVGFilterPrimitiveStandardAttributes::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFEImageElement::SVGFEImageElement(SVGFEImageElementImpl *other) : SVGElement(other), SVGURIReference(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGFilterPrimitiveStandardAttributes(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFEImageElement::~SVGFEImageElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEImageElement.h b/ksvg/dom/SVGFEImageElement.h
new file mode 100644
index 00000000..2c8d5b38
--- /dev/null
+++ b/ksvg/dom/SVGFEImageElement.h
@@ -0,0 +1,60 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEImageElement_H
+#define SVGFEImageElement_H
+
+#include "SVGElement.h"
+#include "SVGURIReference.h"
+#include "SVGLangSpace.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+#include "SVGFilterPrimitiveStandardAttributes.h"
+
+namespace KSVG
+{
+
+class SVGFEImageElementImpl;
+class SVGFEImageElement : public SVGElement,
+ public SVGURIReference,
+ public SVGLangSpace,
+ public SVGExternalResourcesRequired,
+ public SVGStylable,
+ public SVGFilterPrimitiveStandardAttributes
+{
+public:
+ SVGFEImageElement();
+ SVGFEImageElement(const SVGFEImageElement &other);
+ SVGFEImageElement &operator=(const SVGFEImageElement &other);
+ SVGFEImageElement(SVGFEImageElementImpl *other);
+ virtual ~SVGFEImageElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFEImageElementImpl *handle() const { return impl; }
+
+private:
+ SVGFEImageElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEMergeElement.cc b/ksvg/dom/SVGFEMergeElement.cc
new file mode 100644
index 00000000..8440cd53
--- /dev/null
+++ b/ksvg/dom/SVGFEMergeElement.cc
@@ -0,0 +1,68 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEMergeElement.h"
+#include "SVGFEMergeElementImpl.h"
+
+using namespace KSVG;
+
+SVGFEMergeElement::SVGFEMergeElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes()
+{
+ impl = 0;
+}
+
+SVGFEMergeElement::SVGFEMergeElement(const SVGFEMergeElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFEMergeElement &SVGFEMergeElement::operator =(const SVGFEMergeElement &other)
+{
+ SVGElement::operator=(other);
+ SVGFilterPrimitiveStandardAttributes::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFEMergeElement::SVGFEMergeElement(SVGFEMergeElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFEMergeElement::~SVGFEMergeElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEMergeElement.h b/ksvg/dom/SVGFEMergeElement.h
new file mode 100644
index 00000000..72e915ec
--- /dev/null
+++ b/ksvg/dom/SVGFEMergeElement.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEMergeElement_H
+#define SVGFEMergeElement_H
+
+#include "SVGElement.h"
+#include "SVGFilterPrimitiveStandardAttributes.h"
+
+namespace KSVG
+{
+
+class SVGFEMergeElementImpl;
+class SVGFEMergeElement : public SVGElement,
+ public SVGFilterPrimitiveStandardAttributes
+{
+public:
+ SVGFEMergeElement();
+ SVGFEMergeElement(const SVGFEMergeElement &other);
+ SVGFEMergeElement &operator=(const SVGFEMergeElement &other);
+ SVGFEMergeElement(SVGFEMergeElementImpl *other);
+ virtual ~SVGFEMergeElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFEMergeElementImpl *handle() const { return impl; }
+
+private:
+ SVGFEMergeElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEMergeNodeElement.cc b/ksvg/dom/SVGFEMergeNodeElement.cc
new file mode 100644
index 00000000..7abe70e7
--- /dev/null
+++ b/ksvg/dom/SVGFEMergeNodeElement.cc
@@ -0,0 +1,74 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEMergeNodeElement.h"
+#include "SVGFEMergeNodeElementImpl.h"
+#include "SVGAnimatedString.h"
+
+using namespace KSVG;
+
+SVGFEMergeNodeElement::SVGFEMergeNodeElement() : SVGElement()
+{
+ impl = 0;
+}
+
+SVGFEMergeNodeElement::SVGFEMergeNodeElement(const SVGFEMergeNodeElement &other) : SVGElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFEMergeNodeElement &SVGFEMergeNodeElement::operator =(const SVGFEMergeNodeElement &other)
+{
+ SVGElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFEMergeNodeElement::SVGFEMergeNodeElement(SVGFEMergeNodeElementImpl *other) : SVGElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFEMergeNodeElement::~SVGFEMergeNodeElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedString SVGFEMergeNodeElement::in1() const
+{
+ if(!impl) return SVGAnimatedString(0);
+ return SVGAnimatedString(impl->in1());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEMergeNodeElement.h b/ksvg/dom/SVGFEMergeNodeElement.h
new file mode 100644
index 00000000..e9002f0c
--- /dev/null
+++ b/ksvg/dom/SVGFEMergeNodeElement.h
@@ -0,0 +1,53 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEMergeNodeElement_H
+#define SVGFEMergeNodeElement_H
+
+#include "SVGElement.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedString;
+class SVGFEMergeNodeElementImpl;
+class SVGFEMergeNodeElement : public SVGElement
+{
+public:
+ SVGFEMergeNodeElement();
+ SVGFEMergeNodeElement(const SVGFEMergeNodeElement &other);
+ SVGFEMergeNodeElement &operator=(const SVGFEMergeNodeElement &other);
+ SVGFEMergeNodeElement(SVGFEMergeNodeElementImpl *other);
+ virtual ~SVGFEMergeNodeElement();
+
+ SVGAnimatedString in1() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFEMergeNodeElementImpl *handle() const { return impl; }
+
+private:
+ SVGFEMergeNodeElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEMorphologyElement.cc b/ksvg/dom/SVGFEMorphologyElement.cc
new file mode 100644
index 00000000..293d86a8
--- /dev/null
+++ b/ksvg/dom/SVGFEMorphologyElement.cc
@@ -0,0 +1,95 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEMorphologyElement.h"
+#include "SVGFEMorphologyElementImpl.h"
+#include "SVGAnimatedString.h"
+#include "SVGAnimatedEnumeration.h"
+#include "SVGAnimatedLength.h"
+
+using namespace KSVG;
+
+SVGFEMorphologyElement::SVGFEMorphologyElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes()
+{
+ impl = 0;
+}
+
+SVGFEMorphologyElement::SVGFEMorphologyElement(const SVGFEMorphologyElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFEMorphologyElement &SVGFEMorphologyElement::operator =(const SVGFEMorphologyElement &other)
+{
+ SVGElement::operator=(other);
+ SVGFilterPrimitiveStandardAttributes::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFEMorphologyElement::SVGFEMorphologyElement(SVGFEMorphologyElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFEMorphologyElement::~SVGFEMorphologyElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedString SVGFEMorphologyElement::in1() const
+{
+ if(!impl) return SVGAnimatedString(0);
+ return SVGAnimatedString(impl->in1());
+}
+
+SVGAnimatedEnumeration SVGFEMorphologyElement::Operator() const
+{
+ if(!impl) return SVGAnimatedEnumeration(0);
+ return SVGAnimatedEnumeration(impl->Operator());
+}
+
+SVGAnimatedLength SVGFEMorphologyElement::radiusX() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->radiusX());
+}
+
+SVGAnimatedLength SVGFEMorphologyElement::radiusY() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->radiusY());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEMorphologyElement.h b/ksvg/dom/SVGFEMorphologyElement.h
new file mode 100644
index 00000000..7ca1b6a0
--- /dev/null
+++ b/ksvg/dom/SVGFEMorphologyElement.h
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEMorphologyElement_H
+#define SVGFEMorphologyElement_H
+
+#include "SVGElement.h"
+#include "SVGFilterPrimitiveStandardAttributes.h"
+
+namespace KSVG
+{
+
+enum
+{
+ SVG_MORPHOLOGY_OPERATOR_UNKNOWN = 0,
+ SVG_MORPHOLOGY_OPERATOR_ERODE = 1,
+ SVG_MORPHOLOGY_OPERATOR_DILATE = 2
+};
+
+class SVGAnimatedString;
+class SVGAnimatedEnumeration;
+class SVGAnimatedLength;
+class SVGFEMorphologyElementImpl;
+class SVGFEMorphologyElement : public SVGElement,
+ public SVGFilterPrimitiveStandardAttributes
+{
+public:
+ SVGFEMorphologyElement();
+ SVGFEMorphologyElement(const SVGFEMorphologyElement &other);
+ SVGFEMorphologyElement &operator=(const SVGFEMorphologyElement &other);
+ SVGFEMorphologyElement(SVGFEMorphologyElementImpl *other);
+ virtual ~SVGFEMorphologyElement();
+
+ SVGAnimatedString in1() const;
+ SVGAnimatedEnumeration Operator() const;
+ SVGAnimatedLength radiusX() const;
+ SVGAnimatedLength radiusY() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFEMorphologyElementImpl *handle() const { return impl; }
+
+private:
+ SVGFEMorphologyElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEOffsetElement.cc b/ksvg/dom/SVGFEOffsetElement.cc
new file mode 100644
index 00000000..f16ff5ed
--- /dev/null
+++ b/ksvg/dom/SVGFEOffsetElement.cc
@@ -0,0 +1,88 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEOffsetElement.h"
+#include "SVGFEOffsetElementImpl.h"
+#include "SVGAnimatedNumber.h"
+#include "SVGAnimatedString.h"
+
+using namespace KSVG;
+
+SVGFEOffsetElement::SVGFEOffsetElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes()
+{
+ impl = 0;
+}
+
+SVGFEOffsetElement::SVGFEOffsetElement(const SVGFEOffsetElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFEOffsetElement &SVGFEOffsetElement::operator =(const SVGFEOffsetElement &other)
+{
+ SVGElement::operator=(other);
+ SVGFilterPrimitiveStandardAttributes::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFEOffsetElement::SVGFEOffsetElement(SVGFEOffsetElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFEOffsetElement::~SVGFEOffsetElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedString SVGFEOffsetElement::in1() const
+{
+ if(!impl) return SVGAnimatedString(0);
+ return SVGAnimatedString(impl->in1());
+}
+
+SVGAnimatedNumber SVGFEOffsetElement::dx() const
+{
+ if(!impl) return SVGAnimatedNumber(0); // FIXME
+ return SVGAnimatedNumber(impl->dx());
+}
+
+SVGAnimatedNumber SVGFEOffsetElement::dy() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->dy());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEOffsetElement.h b/ksvg/dom/SVGFEOffsetElement.h
new file mode 100644
index 00000000..62b63407
--- /dev/null
+++ b/ksvg/dom/SVGFEOffsetElement.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEOffsetElement_H
+#define SVGFEOffsetElement_H
+
+#include "SVGElement.h"
+#include "SVGFilterPrimitiveStandardAttributes.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedString;
+class SVGAnimatedNumber;
+class SVGFEOffsetElementImpl;
+class SVGFEOffsetElement : public SVGElement,
+ public SVGFilterPrimitiveStandardAttributes
+{
+public:
+ SVGFEOffsetElement();
+ SVGFEOffsetElement(const SVGFEOffsetElement &other);
+ SVGFEOffsetElement &operator=(const SVGFEOffsetElement &other);
+ SVGFEOffsetElement(SVGFEOffsetElementImpl *other);
+ virtual ~SVGFEOffsetElement();
+
+ SVGAnimatedString in1() const;
+ SVGAnimatedNumber dx() const;
+ SVGAnimatedNumber dy() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFEOffsetElementImpl *handle() const { return impl; }
+
+private:
+ SVGFEOffsetElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEPointLightElement.cc b/ksvg/dom/SVGFEPointLightElement.cc
new file mode 100644
index 00000000..ce5e4635
--- /dev/null
+++ b/ksvg/dom/SVGFEPointLightElement.cc
@@ -0,0 +1,86 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEPointLightElement.h"
+#include "SVGFEPointLightElementImpl.h"
+#include "SVGAnimatedNumber.h"
+
+using namespace KSVG;
+
+SVGFEPointLightElement::SVGFEPointLightElement() : SVGElement()
+{
+ impl = 0;
+}
+
+SVGFEPointLightElement::SVGFEPointLightElement(const SVGFEPointLightElement &other) : SVGElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFEPointLightElement &SVGFEPointLightElement::operator =(const SVGFEPointLightElement &other)
+{
+ SVGElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFEPointLightElement::SVGFEPointLightElement(SVGFEPointLightElementImpl *other) : SVGElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFEPointLightElement::~SVGFEPointLightElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedNumber SVGFEPointLightElement::x() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->x());
+}
+
+SVGAnimatedNumber SVGFEPointLightElement::y() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->y());
+}
+
+SVGAnimatedNumber SVGFEPointLightElement::z() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->z());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFEPointLightElement.h b/ksvg/dom/SVGFEPointLightElement.h
new file mode 100644
index 00000000..1d029e00
--- /dev/null
+++ b/ksvg/dom/SVGFEPointLightElement.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEPointLightElement_H
+#define SVGFEPointLightElement_H
+
+#include "SVGElement.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedNumber;
+class SVGFEPointLightElementImpl;
+class SVGFEPointLightElement : public SVGElement
+{
+public:
+ SVGFEPointLightElement();
+ SVGFEPointLightElement(const SVGFEPointLightElement &other);
+ SVGFEPointLightElement &operator=(const SVGFEPointLightElement &other);
+ SVGFEPointLightElement(SVGFEPointLightElementImpl *other);
+ virtual ~SVGFEPointLightElement();
+
+ SVGAnimatedNumber x() const;
+ SVGAnimatedNumber y() const;
+ SVGAnimatedNumber z() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFEPointLightElementImpl *handle() const { return impl; }
+
+private:
+ SVGFEPointLightElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFESpecularLightingElement.cc b/ksvg/dom/SVGFESpecularLightingElement.cc
new file mode 100644
index 00000000..924e1ce7
--- /dev/null
+++ b/ksvg/dom/SVGFESpecularLightingElement.cc
@@ -0,0 +1,94 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFESpecularLightingElement.h"
+#include "SVGFESpecularLightingElementImpl.h"
+#include "SVGAnimatedNumber.h"
+#include "SVGAnimatedString.h"
+
+using namespace KSVG;
+
+SVGFESpecularLightingElement::SVGFESpecularLightingElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes()
+{
+ impl = 0;
+}
+
+SVGFESpecularLightingElement::SVGFESpecularLightingElement(const SVGFESpecularLightingElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFESpecularLightingElement &SVGFESpecularLightingElement::operator =(const SVGFESpecularLightingElement &other)
+{
+ SVGElement::operator=(other);
+ SVGFilterPrimitiveStandardAttributes::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFESpecularLightingElement::SVGFESpecularLightingElement(SVGFESpecularLightingElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFESpecularLightingElement::~SVGFESpecularLightingElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedString SVGFESpecularLightingElement::in1() const
+{
+ if(!impl) return SVGAnimatedString(0);
+ return SVGAnimatedString(impl->in1());
+}
+
+SVGAnimatedNumber SVGFESpecularLightingElement::surfaceScale() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->surfaceScale());
+}
+
+SVGAnimatedNumber SVGFESpecularLightingElement::specularConstant() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->specularConstant());
+}
+
+SVGAnimatedNumber SVGFESpecularLightingElement::specularExponent() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->specularExponent());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFESpecularLightingElement.h b/ksvg/dom/SVGFESpecularLightingElement.h
new file mode 100644
index 00000000..3566006c
--- /dev/null
+++ b/ksvg/dom/SVGFESpecularLightingElement.h
@@ -0,0 +1,59 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFESpecularLightingElement_H
+#define SVGFESpecularLightingElement_H
+
+#include "SVGElement.h"
+#include "SVGFilterPrimitiveStandardAttributes.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedString;
+class SVGAnimatedNumber;
+class SVGFESpecularLightingElementImpl;
+class SVGFESpecularLightingElement : public SVGElement,
+ public SVGFilterPrimitiveStandardAttributes
+{
+public:
+ SVGFESpecularLightingElement();
+ SVGFESpecularLightingElement(const SVGFESpecularLightingElement &other);
+ SVGFESpecularLightingElement &operator=(const SVGFESpecularLightingElement &other);
+ SVGFESpecularLightingElement(SVGFESpecularLightingElementImpl *other);
+ virtual ~SVGFESpecularLightingElement();
+
+ SVGAnimatedString in1() const;
+ SVGAnimatedNumber surfaceScale() const;
+ SVGAnimatedNumber specularConstant() const;
+ SVGAnimatedNumber specularExponent() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFESpecularLightingElementImpl *handle() const { return impl; }
+
+private:
+ SVGFESpecularLightingElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFESpotLightElement.cc b/ksvg/dom/SVGFESpotLightElement.cc
new file mode 100644
index 00000000..57dd498f
--- /dev/null
+++ b/ksvg/dom/SVGFESpotLightElement.cc
@@ -0,0 +1,116 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFESpotLightElement.h"
+#include "SVGFESpotLightElementImpl.h"
+#include "SVGAnimatedNumber.h"
+
+using namespace KSVG;
+
+SVGFESpotLightElement::SVGFESpotLightElement() : SVGElement()
+{
+ impl = 0;
+}
+
+SVGFESpotLightElement::SVGFESpotLightElement(const SVGFESpotLightElement &other) : SVGElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFESpotLightElement &SVGFESpotLightElement::operator =(const SVGFESpotLightElement &other)
+{
+ SVGElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFESpotLightElement::SVGFESpotLightElement(SVGFESpotLightElementImpl *other) : SVGElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFESpotLightElement::~SVGFESpotLightElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedNumber SVGFESpotLightElement::x() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->x());
+}
+
+SVGAnimatedNumber SVGFESpotLightElement::y() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->y());
+}
+
+SVGAnimatedNumber SVGFESpotLightElement::z() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->z());
+}
+
+SVGAnimatedNumber SVGFESpotLightElement::pointsAtX() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->pointsAtX());
+}
+
+SVGAnimatedNumber SVGFESpotLightElement::pointsAtY() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->pointsAtY());
+}
+
+SVGAnimatedNumber SVGFESpotLightElement::pointsAtZ() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->pointsAtZ());
+}
+
+SVGAnimatedNumber SVGFESpotLightElement::specularExponent() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->specularExponent());
+}
+
+SVGAnimatedNumber SVGFESpotLightElement::limitingConeAngle() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->limitingConeAngle());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFESpotLightElement.h b/ksvg/dom/SVGFESpotLightElement.h
new file mode 100644
index 00000000..735a6428
--- /dev/null
+++ b/ksvg/dom/SVGFESpotLightElement.h
@@ -0,0 +1,60 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFESpotLightElement_H
+#define SVGFESpotLightElement_H
+
+#include "SVGElement.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedNumber;
+class SVGFESpotLightElementImpl;
+class SVGFESpotLightElement : public SVGElement
+{
+public:
+ SVGFESpotLightElement();
+ SVGFESpotLightElement(const SVGFESpotLightElement &other);
+ SVGFESpotLightElement &operator=(const SVGFESpotLightElement &other);
+ SVGFESpotLightElement(SVGFESpotLightElementImpl *other);
+ virtual ~SVGFESpotLightElement();
+
+ SVGAnimatedNumber x() const;
+ SVGAnimatedNumber y() const;
+ SVGAnimatedNumber z() const;
+ SVGAnimatedNumber pointsAtX() const;
+ SVGAnimatedNumber pointsAtY() const;
+ SVGAnimatedNumber pointsAtZ() const;
+ SVGAnimatedNumber specularExponent() const;
+ SVGAnimatedNumber limitingConeAngle() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFESpotLightElementImpl *handle() const { return impl; }
+
+private:
+ SVGFESpotLightElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFETileElement.cc b/ksvg/dom/SVGFETileElement.cc
new file mode 100644
index 00000000..01c7ffed
--- /dev/null
+++ b/ksvg/dom/SVGFETileElement.cc
@@ -0,0 +1,75 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFETileElement.h"
+#include "SVGFETileElementImpl.h"
+#include "SVGAnimatedString.h"
+
+using namespace KSVG;
+
+SVGFETileElement::SVGFETileElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes()
+{
+ impl = 0;
+}
+
+SVGFETileElement::SVGFETileElement(const SVGFETileElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFETileElement &SVGFETileElement::operator =(const SVGFETileElement &other)
+{
+ SVGElement::operator=(other);
+ SVGFilterPrimitiveStandardAttributes::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFETileElement::SVGFETileElement(SVGFETileElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFETileElement::~SVGFETileElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedString SVGFETileElement::in1() const
+{
+ if(!impl) return SVGAnimatedString(0);
+ return SVGAnimatedString(impl->in1());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFETileElement.h b/ksvg/dom/SVGFETileElement.h
new file mode 100644
index 00000000..cbf548b1
--- /dev/null
+++ b/ksvg/dom/SVGFETileElement.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFETileElement_H
+#define SVGFETileElement_H
+
+#include "SVGElement.h"
+#include "SVGFilterPrimitiveStandardAttributes.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedString;
+class SVGFETileElementImpl;
+class SVGFETileElement : public SVGElement,
+ public SVGFilterPrimitiveStandardAttributes
+{
+public:
+ SVGFETileElement();
+ SVGFETileElement(const SVGFETileElement &other);
+ SVGFETileElement &operator=(const SVGFETileElement &other);
+ SVGFETileElement(SVGFETileElementImpl *other);
+ virtual ~SVGFETileElement();
+
+ SVGAnimatedString in1() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFETileElementImpl *handle() const { return impl; }
+
+private:
+ SVGFETileElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFETurbulenceElement.cc b/ksvg/dom/SVGFETurbulenceElement.cc
new file mode 100644
index 00000000..7d846e6b
--- /dev/null
+++ b/ksvg/dom/SVGFETurbulenceElement.cc
@@ -0,0 +1,107 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFETurbulenceElement.h"
+#include "SVGFETurbulenceElementImpl.h"
+#include "SVGAnimatedEnumeration.h"
+#include "SVGAnimatedNumber.h"
+#include "SVGAnimatedInteger.h"
+
+using namespace KSVG;
+
+SVGFETurbulenceElement::SVGFETurbulenceElement() : SVGElement(), SVGFilterPrimitiveStandardAttributes()
+{
+ impl = 0;
+}
+
+SVGFETurbulenceElement::SVGFETurbulenceElement(const SVGFETurbulenceElement &other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFETurbulenceElement &SVGFETurbulenceElement::operator =(const SVGFETurbulenceElement &other)
+{
+ SVGElement::operator=(other);
+ SVGFilterPrimitiveStandardAttributes::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFETurbulenceElement::SVGFETurbulenceElement(SVGFETurbulenceElementImpl *other) : SVGElement(other), SVGFilterPrimitiveStandardAttributes(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFETurbulenceElement::~SVGFETurbulenceElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedNumber SVGFETurbulenceElement::baseFrequencyX() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->baseFrequencyX());
+}
+
+SVGAnimatedNumber SVGFETurbulenceElement::baseFrequencyY() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->baseFrequencyY());
+}
+
+SVGAnimatedInteger SVGFETurbulenceElement::numOctaves() const
+{
+ if(!impl) return SVGAnimatedInteger(0);
+ return SVGAnimatedInteger(impl->numOctaves());
+}
+
+SVGAnimatedNumber SVGFETurbulenceElement::seed() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->seed());
+}
+
+SVGAnimatedEnumeration SVGFETurbulenceElement::stitchTiles() const
+{
+ if(!impl) return SVGAnimatedEnumeration(0);
+ return SVGAnimatedEnumeration(impl->stitchTiles());
+}
+
+SVGAnimatedEnumeration SVGFETurbulenceElement::type() const
+{
+ if(!impl) return SVGAnimatedEnumeration(0);
+ return SVGAnimatedEnumeration(impl->type());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFETurbulenceElement.h b/ksvg/dom/SVGFETurbulenceElement.h
new file mode 100644
index 00000000..39b6050d
--- /dev/null
+++ b/ksvg/dom/SVGFETurbulenceElement.h
@@ -0,0 +1,71 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFETurbulenceElement_H
+#define SVGFETurbulenceElement_H
+
+#include "SVGElement.h"
+#include "SVGFilterPrimitiveStandardAttributes.h"
+
+namespace KSVG
+{
+enum
+{
+ SVG_TURBULENCE_TYPE_UNKNOWN = 0,
+ SVG_TURBULENCE_TYPE_FRACTALNOISE = 1,
+ SVG_TURBULENCE_TYPE_TURBULENCE = 2,
+ SVG_STITCHTYPE_UNKNOWN = 0,
+ SVG_STITCHTYPE_STITCH = 1,
+ SVG_STITCHTYPE_NOSTITCH = 2
+};
+
+class SVGAnimatedEnumeration;
+class SVGAnimatedNumber;
+class SVGAnimatedInteger;
+class SVGFETurbulenceElementImpl;
+class SVGFETurbulenceElement : public SVGElement,
+ public SVGFilterPrimitiveStandardAttributes
+{
+public:
+ SVGFETurbulenceElement();
+ SVGFETurbulenceElement(const SVGFETurbulenceElement &other);
+ SVGFETurbulenceElement &operator=(const SVGFETurbulenceElement &other);
+ SVGFETurbulenceElement(SVGFETurbulenceElementImpl *other);
+ virtual ~SVGFETurbulenceElement();
+
+ SVGAnimatedNumber baseFrequencyX() const;
+ SVGAnimatedNumber baseFrequencyY() const;
+ SVGAnimatedInteger numOctaves() const;
+ SVGAnimatedNumber seed() const;
+ SVGAnimatedEnumeration stitchTiles() const;
+ SVGAnimatedEnumeration type() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFETurbulenceElementImpl *handle() const { return impl; }
+
+private:
+ SVGFETurbulenceElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFilterElement.cc b/ksvg/dom/SVGFilterElement.cc
new file mode 100644
index 00000000..3644a807
--- /dev/null
+++ b/ksvg/dom/SVGFilterElement.cc
@@ -0,0 +1,128 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFilterElement.h"
+#include "SVGFilterElementImpl.h"
+#include "SVGAnimatedEnumeration.h"
+#include "SVGAnimatedInteger.h"
+#include "SVGAnimatedLength.h"
+
+using namespace KSVG;
+
+SVGFilterElement::SVGFilterElement() : SVGElement(), SVGURIReference(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGUnitTypes()
+{
+ impl = 0;
+}
+
+SVGFilterElement::SVGFilterElement(const SVGFilterElement &other) : SVGElement(other), SVGURIReference(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGUnitTypes(), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFilterElement &SVGFilterElement::operator =(const SVGFilterElement &other)
+{
+ SVGElement::operator=(other);
+ SVGURIReference::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFilterElement::SVGFilterElement(SVGFilterElementImpl *other) : SVGElement(other), SVGURIReference(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGUnitTypes()
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFilterElement::~SVGFilterElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedEnumeration SVGFilterElement::filterUnits() const
+{
+ if(!impl) return SVGAnimatedEnumeration(0);
+ return SVGAnimatedEnumeration(impl->filterUnits());
+}
+
+SVGAnimatedEnumeration SVGFilterElement::primitiveUnits() const
+{
+ if(!impl) return SVGAnimatedEnumeration(0);
+ return SVGAnimatedEnumeration(impl->primitiveUnits());
+}
+
+SVGAnimatedLength SVGFilterElement::x() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->x());
+}
+
+SVGAnimatedLength SVGFilterElement::y() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->y());
+}
+
+SVGAnimatedLength SVGFilterElement::width() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->width());
+}
+
+SVGAnimatedLength SVGFilterElement::height() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->height());
+}
+
+SVGAnimatedInteger SVGFilterElement::filterResX() const
+{
+ if(!impl) return SVGAnimatedInteger(0);
+ return SVGAnimatedInteger(impl->filterResX());
+}
+
+SVGAnimatedInteger SVGFilterElement::filterResY() const
+{
+ if(!impl) return SVGAnimatedInteger(0);
+ return SVGAnimatedInteger(impl->filterResY());
+}
+
+void SVGFilterElement::setFilterRes(unsigned long filterResX, unsigned long filterResY)
+{
+ if(impl)
+ impl->setFilterRes(filterResX, filterResY);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFilterElement.h b/ksvg/dom/SVGFilterElement.h
new file mode 100644
index 00000000..82f67e5c
--- /dev/null
+++ b/ksvg/dom/SVGFilterElement.h
@@ -0,0 +1,74 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFilterElement_H
+#define SVGFilterElement_H
+
+#include "SVGElement.h"
+#include "SVGURIReference.h"
+#include "SVGLangSpace.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+#include "SVGUnitTypes.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedEnumeration;
+class SVGAnimatedLength;
+class SVGAnimatedInteger;
+class SVGFilterElementImpl;
+class SVGFilterElement : public SVGElement,
+ public SVGURIReference,
+ public SVGLangSpace,
+ public SVGExternalResourcesRequired,
+ public SVGStylable,
+ public SVGUnitTypes
+{
+public:
+ SVGFilterElement();
+ SVGFilterElement(const SVGFilterElement &other);
+ SVGFilterElement &operator=(const SVGFilterElement &other);
+ SVGFilterElement(SVGFilterElementImpl *other);
+ virtual ~SVGFilterElement();
+
+ SVGAnimatedEnumeration filterUnits() const;
+ SVGAnimatedEnumeration primitiveUnits() const;
+ SVGAnimatedLength x() const;
+ SVGAnimatedLength y() const;
+ SVGAnimatedLength width() const;
+ SVGAnimatedLength height() const;
+ SVGAnimatedInteger filterResX() const;
+ SVGAnimatedInteger filterResY() const;
+
+ void setFilterRes(unsigned long filterResX, unsigned long filterResY);
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFilterElementImpl *handle() const { return impl; }
+
+private:
+ SVGFilterElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFilterPrimitiveStandardAttributes.cc b/ksvg/dom/SVGFilterPrimitiveStandardAttributes.cc
new file mode 100644
index 00000000..05b2ef2a
--- /dev/null
+++ b/ksvg/dom/SVGFilterPrimitiveStandardAttributes.cc
@@ -0,0 +1,88 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFilterPrimitiveStandardAttributes.h"
+#include "SVGFilterPrimitiveStandardAttributesImpl.h"
+#include "SVGAnimatedString.h"
+#include "SVGAnimatedLength.h"
+
+using namespace KSVG;
+
+SVGFilterPrimitiveStandardAttributes::SVGFilterPrimitiveStandardAttributes()
+{
+ impl = new SVGFilterPrimitiveStandardAttributesImpl();
+}
+
+SVGFilterPrimitiveStandardAttributes::SVGFilterPrimitiveStandardAttributes(const SVGFilterPrimitiveStandardAttributes &other)
+{
+ impl = other.impl;
+}
+
+SVGFilterPrimitiveStandardAttributes &SVGFilterPrimitiveStandardAttributes::operator=(const SVGFilterPrimitiveStandardAttributes &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ delete impl;
+ impl = other.impl;
+
+ return *this;
+}
+
+SVGFilterPrimitiveStandardAttributes::SVGFilterPrimitiveStandardAttributes(SVGFilterPrimitiveStandardAttributesImpl *other)
+{
+ impl = other;
+}
+
+SVGFilterPrimitiveStandardAttributes::~SVGFilterPrimitiveStandardAttributes()
+{
+}
+
+SVGAnimatedLength SVGFilterPrimitiveStandardAttributes::x() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->x());
+}
+
+SVGAnimatedLength SVGFilterPrimitiveStandardAttributes::y() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->y());
+}
+
+SVGAnimatedLength SVGFilterPrimitiveStandardAttributes::width() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->width());
+}
+
+SVGAnimatedLength SVGFilterPrimitiveStandardAttributes::height() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->height());
+}
+
+SVGAnimatedString SVGFilterPrimitiveStandardAttributes::result() const
+{
+ if(!impl) return SVGAnimatedString(0);
+ return SVGAnimatedString(impl->result());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFilterPrimitiveStandardAttributes.h b/ksvg/dom/SVGFilterPrimitiveStandardAttributes.h
new file mode 100644
index 00000000..9d2c9894
--- /dev/null
+++ b/ksvg/dom/SVGFilterPrimitiveStandardAttributes.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFilterPrimitiveStandardAttributes_H
+#define SVGFilterPrimitiveStandardAttributes_H
+
+namespace KSVG
+{
+
+class SVGAnimatedLength;
+class SVGAnimatedString;
+class SVGFilterPrimitiveStandardAttributesImpl;
+class SVGFilterPrimitiveStandardAttributes
+{
+public:
+ SVGFilterPrimitiveStandardAttributes(const SVGFilterPrimitiveStandardAttributes &other);
+ SVGFilterPrimitiveStandardAttributes &operator=(const SVGFilterPrimitiveStandardAttributes &other);
+ SVGFilterPrimitiveStandardAttributes(SVGFilterPrimitiveStandardAttributesImpl *other);
+ virtual ~SVGFilterPrimitiveStandardAttributes();
+
+ SVGAnimatedLength x() const;
+ SVGAnimatedLength y() const;
+ SVGAnimatedLength width() const;
+ SVGAnimatedLength height() const;
+ SVGAnimatedString result() const;
+
+protected:
+ SVGFilterPrimitiveStandardAttributes();
+
+private:
+ SVGFilterPrimitiveStandardAttributesImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFitToViewBox.cc b/ksvg/dom/SVGFitToViewBox.cc
new file mode 100644
index 00000000..e0d576f0
--- /dev/null
+++ b/ksvg/dom/SVGFitToViewBox.cc
@@ -0,0 +1,72 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFitToViewBox.h"
+#include "SVGFitToViewBoxImpl.h"
+#include "SVGAnimatedRect.h"
+#include "SVGAnimatedPreserveAspectRatio.h"
+
+using namespace KSVG;
+
+// This class can't be constructed seperately.
+SVGFitToViewBox::SVGFitToViewBox()
+{
+ impl = 0;
+}
+
+SVGFitToViewBox::SVGFitToViewBox(const SVGFitToViewBox &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGFitToViewBox &SVGFitToViewBox::operator=(const SVGFitToViewBox &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ impl = other.impl;
+
+ return *this;
+}
+
+SVGFitToViewBox::SVGFitToViewBox(SVGFitToViewBoxImpl *other)
+{
+ impl = other;
+}
+
+SVGFitToViewBox::~SVGFitToViewBox()
+{
+ // We are not allowed to delete 'impl' as it's not refcounted.
+ // delete impl;
+}
+
+SVGAnimatedRect SVGFitToViewBox::viewBox() const
+{
+ if(!impl) return SVGAnimatedRect(0);
+ return SVGAnimatedRect(impl->viewBox());
+}
+
+SVGAnimatedPreserveAspectRatio SVGFitToViewBox::preserveAspectRatio() const
+{
+ if(!impl) return SVGAnimatedPreserveAspectRatio(0);
+ return SVGAnimatedPreserveAspectRatio(impl->preserveAspectRatio());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFitToViewBox.h b/ksvg/dom/SVGFitToViewBox.h
new file mode 100644
index 00000000..50778657
--- /dev/null
+++ b/ksvg/dom/SVGFitToViewBox.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFitToViewBox_H
+#define SVGFitToViewBox_H
+
+namespace KSVG
+{
+
+class SVGAnimatedRect;
+class SVGAnimatedPreserveAspectRatio;
+class SVGFitToViewBoxImpl;
+class SVGFitToViewBox
+{
+public:
+ SVGFitToViewBox(const SVGFitToViewBox &other);
+ SVGFitToViewBox &operator=(const SVGFitToViewBox &other);
+ SVGFitToViewBox(SVGFitToViewBoxImpl *other);
+ ~SVGFitToViewBox();
+
+ SVGAnimatedRect viewBox() const;
+ SVGAnimatedPreserveAspectRatio preserveAspectRatio() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFitToViewBoxImpl *handle() const { return impl; }
+
+protected:
+ SVGFitToViewBox();
+
+private:
+ SVGFitToViewBoxImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFontElement.cc b/ksvg/dom/SVGFontElement.cc
new file mode 100644
index 00000000..5fae52ee
--- /dev/null
+++ b/ksvg/dom/SVGFontElement.cc
@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFontElement.h"
+#include "SVGFontElementImpl.h"
+
+using namespace KSVG;
+
+SVGFontElement::SVGFontElement() : SVGElement(), SVGExternalResourcesRequired(), SVGStylable()
+{
+ impl = 0;
+}
+
+SVGFontElement::SVGFontElement(const SVGFontElement &other) : SVGElement(other), SVGExternalResourcesRequired(other), SVGStylable(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFontElement &SVGFontElement::operator =(const SVGFontElement &other)
+{
+ SVGElement::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFontElement::SVGFontElement(SVGFontElementImpl *other) : SVGElement(other), SVGExternalResourcesRequired(other), SVGStylable(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFontElement::~SVGFontElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFontElement.h b/ksvg/dom/SVGFontElement.h
new file mode 100644
index 00000000..9ecc36bf
--- /dev/null
+++ b/ksvg/dom/SVGFontElement.h
@@ -0,0 +1,54 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFontElement_H
+#define SVGFontElement_H
+
+#include "SVGElement.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+
+namespace KSVG
+{
+
+class SVGFontElementImpl;
+class SVGFontElement : public SVGElement,
+ public SVGExternalResourcesRequired,
+ public SVGStylable
+{
+public:
+ SVGFontElement();
+ SVGFontElement(const SVGFontElement &other);
+ SVGFontElement &operator=(const SVGFontElement &other);
+ SVGFontElement(SVGFontElementImpl *other);
+ virtual ~SVGFontElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFontElementImpl *handle() const { return impl; }
+
+private:
+ SVGFontElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFontFaceElement.cc b/ksvg/dom/SVGFontFaceElement.cc
new file mode 100644
index 00000000..6d542a04
--- /dev/null
+++ b/ksvg/dom/SVGFontFaceElement.cc
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFontFaceElement.h"
+#include "SVGFontFaceElementImpl.h"
+
+using namespace KSVG;
+
+SVGFontFaceElement::SVGFontFaceElement() : SVGElement()
+{
+ impl = 0;
+}
+
+SVGFontFaceElement::SVGFontFaceElement(const SVGFontFaceElement &other) : SVGElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFontFaceElement &SVGFontFaceElement::operator =(const SVGFontFaceElement &other)
+{
+ SVGElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFontFaceElement::SVGFontFaceElement(SVGFontFaceElementImpl *other) : SVGElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFontFaceElement::~SVGFontFaceElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFontFaceElement.h b/ksvg/dom/SVGFontFaceElement.h
new file mode 100644
index 00000000..f16d0eb2
--- /dev/null
+++ b/ksvg/dom/SVGFontFaceElement.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFontFaceElement_H
+#define SVGFontFaceElement_H
+
+#include "SVGElement.h"
+
+namespace KSVG
+{
+
+class SVGFontFaceElementImpl;
+class SVGFontFaceElement : public SVGElement
+{
+public:
+ SVGFontFaceElement();
+ SVGFontFaceElement(const SVGFontFaceElement &other);
+ SVGFontFaceElement &operator=(const SVGFontFaceElement &other);
+ SVGFontFaceElement(SVGFontFaceElementImpl *other);
+ virtual ~SVGFontFaceElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFontFaceElementImpl *handle() const { return impl; }
+
+private:
+ SVGFontFaceElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFontFaceFormatElement.cc b/ksvg/dom/SVGFontFaceFormatElement.cc
new file mode 100644
index 00000000..a64c5fa8
--- /dev/null
+++ b/ksvg/dom/SVGFontFaceFormatElement.cc
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFontFaceFormatElement.h"
+#include "SVGFontFaceFormatElementImpl.h"
+
+using namespace KSVG;
+
+SVGFontFaceFormatElement::SVGFontFaceFormatElement() : SVGElement()
+{
+ impl = 0;
+}
+
+SVGFontFaceFormatElement::SVGFontFaceFormatElement(const SVGFontFaceFormatElement &other) : SVGElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFontFaceFormatElement &SVGFontFaceFormatElement::operator =(const SVGFontFaceFormatElement &other)
+{
+ SVGElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFontFaceFormatElement::SVGFontFaceFormatElement(SVGFontFaceFormatElementImpl *other) : SVGElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFontFaceFormatElement::~SVGFontFaceFormatElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFontFaceFormatElement.h b/ksvg/dom/SVGFontFaceFormatElement.h
new file mode 100644
index 00000000..577cae35
--- /dev/null
+++ b/ksvg/dom/SVGFontFaceFormatElement.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFontFaceFormatElement_H
+#define SVGFontFaceFormatElement_H
+
+#include "SVGElement.h"
+
+namespace KSVG
+{
+
+class SVGFontFaceFormatElementImpl;
+class SVGFontFaceFormatElement : public SVGElement
+{
+public:
+ SVGFontFaceFormatElement();
+ SVGFontFaceFormatElement(const SVGFontFaceFormatElement &other);
+ SVGFontFaceFormatElement &operator=(const SVGFontFaceFormatElement &other);
+ SVGFontFaceFormatElement(SVGFontFaceFormatElementImpl *other);
+ virtual ~SVGFontFaceFormatElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFontFaceFormatElementImpl *handle() const { return impl; }
+
+private:
+ SVGFontFaceFormatElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFontFaceNameElement.cc b/ksvg/dom/SVGFontFaceNameElement.cc
new file mode 100644
index 00000000..e5160869
--- /dev/null
+++ b/ksvg/dom/SVGFontFaceNameElement.cc
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFontFaceNameElement.h"
+#include "SVGFontFaceNameElementImpl.h"
+
+using namespace KSVG;
+
+SVGFontFaceNameElement::SVGFontFaceNameElement() : SVGElement()
+{
+ impl = 0;
+}
+
+SVGFontFaceNameElement::SVGFontFaceNameElement(const SVGFontFaceNameElement &other) : SVGElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFontFaceNameElement &SVGFontFaceNameElement::operator =(const SVGFontFaceNameElement &other)
+{
+ SVGElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFontFaceNameElement::SVGFontFaceNameElement(SVGFontFaceNameElementImpl *other) : SVGElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFontFaceNameElement::~SVGFontFaceNameElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFontFaceNameElement.h b/ksvg/dom/SVGFontFaceNameElement.h
new file mode 100644
index 00000000..b246e61d
--- /dev/null
+++ b/ksvg/dom/SVGFontFaceNameElement.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFontFaceNameElement_H
+#define SVGFontFaceNameElement_H
+
+#include "SVGElement.h"
+
+namespace KSVG
+{
+
+class SVGFontFaceNameElementImpl;
+class SVGFontFaceNameElement : public SVGElement
+{
+public:
+ SVGFontFaceNameElement();
+ SVGFontFaceNameElement(const SVGFontFaceNameElement &other);
+ SVGFontFaceNameElement &operator=(const SVGFontFaceNameElement &other);
+ SVGFontFaceNameElement(SVGFontFaceNameElementImpl *other);
+ virtual ~SVGFontFaceNameElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFontFaceNameElementImpl *handle() const { return impl; }
+
+private:
+ SVGFontFaceNameElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFontFaceSrcElement.cc b/ksvg/dom/SVGFontFaceSrcElement.cc
new file mode 100644
index 00000000..8ecbbffa
--- /dev/null
+++ b/ksvg/dom/SVGFontFaceSrcElement.cc
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFontFaceSrcElement.h"
+#include "SVGFontFaceSrcElementImpl.h"
+
+using namespace KSVG;
+
+SVGFontFaceSrcElement::SVGFontFaceSrcElement() : SVGElement()
+{
+ impl = 0;
+}
+
+SVGFontFaceSrcElement::SVGFontFaceSrcElement(const SVGFontFaceSrcElement &other) : SVGElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFontFaceSrcElement &SVGFontFaceSrcElement::operator =(const SVGFontFaceSrcElement &other)
+{
+ SVGElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFontFaceSrcElement::SVGFontFaceSrcElement(SVGFontFaceSrcElementImpl *other) : SVGElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFontFaceSrcElement::~SVGFontFaceSrcElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFontFaceSrcElement.h b/ksvg/dom/SVGFontFaceSrcElement.h
new file mode 100644
index 00000000..585971e0
--- /dev/null
+++ b/ksvg/dom/SVGFontFaceSrcElement.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFontFaceSrcElement_H
+#define SVGFontFaceSrcElement_H
+
+#include "SVGElement.h"
+
+namespace KSVG
+{
+
+class SVGFontFaceSrcElementImpl;
+class SVGFontFaceSrcElement : public SVGElement
+{
+public:
+ SVGFontFaceSrcElement();
+ SVGFontFaceSrcElement(const SVGFontFaceSrcElement &other);
+ SVGFontFaceSrcElement &operator=(const SVGFontFaceSrcElement &other);
+ SVGFontFaceSrcElement(SVGFontFaceSrcElementImpl *other);
+ virtual ~SVGFontFaceSrcElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFontFaceSrcElementImpl *handle() const { return impl; }
+
+private:
+ SVGFontFaceSrcElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFontFaceUriElement.cc b/ksvg/dom/SVGFontFaceUriElement.cc
new file mode 100644
index 00000000..aafb392b
--- /dev/null
+++ b/ksvg/dom/SVGFontFaceUriElement.cc
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFontFaceUriElement.h"
+#include "SVGFontFaceUriElementImpl.h"
+
+using namespace KSVG;
+
+SVGFontFaceUriElement::SVGFontFaceUriElement() : SVGElement()
+{
+ impl = 0;
+}
+
+SVGFontFaceUriElement::SVGFontFaceUriElement(const SVGFontFaceUriElement &other) : SVGElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGFontFaceUriElement &SVGFontFaceUriElement::operator =(const SVGFontFaceUriElement &other)
+{
+ SVGElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGFontFaceUriElement::SVGFontFaceUriElement(SVGFontFaceUriElementImpl *other) : SVGElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGFontFaceUriElement::~SVGFontFaceUriElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGFontFaceUriElement.h b/ksvg/dom/SVGFontFaceUriElement.h
new file mode 100644
index 00000000..c2dd6514
--- /dev/null
+++ b/ksvg/dom/SVGFontFaceUriElement.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFontFaceUriElement_H
+#define SVGFontFaceUriElement_H
+
+#include "SVGElement.h"
+
+namespace KSVG
+{
+
+class SVGFontFaceUriElementImpl;
+class SVGFontFaceUriElement : public SVGElement
+{
+public:
+ SVGFontFaceUriElement();
+ SVGFontFaceUriElement(const SVGFontFaceUriElement &other);
+ SVGFontFaceUriElement &operator=(const SVGFontFaceUriElement &other);
+ SVGFontFaceUriElement(SVGFontFaceUriElementImpl *other);
+ virtual ~SVGFontFaceUriElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGFontFaceUriElementImpl *handle() const { return impl; }
+
+private:
+ SVGFontFaceUriElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGForeignObjectElement.cc b/ksvg/dom/SVGForeignObjectElement.cc
new file mode 100644
index 00000000..e12a194a
--- /dev/null
+++ b/ksvg/dom/SVGForeignObjectElement.cc
@@ -0,0 +1,97 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGForeignObjectElement.h"
+#include "SVGForeignObjectElementImpl.h"
+#include "SVGAnimatedLength.h"
+
+using namespace KSVG;
+
+SVGForeignObjectElement::SVGForeignObjectElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable()
+{
+ impl = 0;
+}
+
+SVGForeignObjectElement::SVGForeignObjectElement(const SVGForeignObjectElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other)
+{
+ (*this) = other;
+}
+
+SVGForeignObjectElement &SVGForeignObjectElement::operator =(const SVGForeignObjectElement &other)
+{
+ SVGElement::operator=(other);
+ SVGTests::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+ SVGTransformable::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGForeignObjectElement::SVGForeignObjectElement(SVGForeignObjectElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGForeignObjectElement::~SVGForeignObjectElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedLength SVGForeignObjectElement::x() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->x());
+}
+
+SVGAnimatedLength SVGForeignObjectElement::y() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->y());
+}
+
+SVGAnimatedLength SVGForeignObjectElement::width() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->width());
+}
+
+SVGAnimatedLength SVGForeignObjectElement::height() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->height());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGForeignObjectElement.h b/ksvg/dom/SVGForeignObjectElement.h
new file mode 100644
index 00000000..0d35019f
--- /dev/null
+++ b/ksvg/dom/SVGForeignObjectElement.h
@@ -0,0 +1,66 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGForeignObjectElement_H
+#define SVGForeignObjectElement_H
+
+#include "SVGElement.h"
+#include "SVGTests.h"
+#include "SVGLangSpace.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+#include "SVGTransformable.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedLength;
+class SVGForeignObjectElementImpl;
+class SVGForeignObjectElement : public SVGElement,
+ public SVGTests,
+ public SVGLangSpace,
+ public SVGExternalResourcesRequired,
+ public SVGStylable,
+ public SVGTransformable
+{
+public:
+ SVGForeignObjectElement();
+ SVGForeignObjectElement(const SVGForeignObjectElement &other);
+ SVGForeignObjectElement &operator=(const SVGForeignObjectElement &other);
+ SVGForeignObjectElement(SVGForeignObjectElementImpl *other);
+ virtual ~SVGForeignObjectElement();
+
+ SVGAnimatedLength x() const;
+ SVGAnimatedLength y() const;
+ SVGAnimatedLength width() const;
+ SVGAnimatedLength height() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGForeignObjectElementImpl *handle() const { return impl; }
+
+private:
+ SVGForeignObjectElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGGElement.cc b/ksvg/dom/SVGGElement.cc
new file mode 100644
index 00000000..272c7608
--- /dev/null
+++ b/ksvg/dom/SVGGElement.cc
@@ -0,0 +1,72 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGGElement.h"
+#include "SVGGElementImpl.h"
+
+using namespace KSVG;
+
+SVGGElement::SVGGElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable()
+{
+ impl = 0;
+}
+
+SVGGElement::SVGGElement(const SVGGElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGGElement &SVGGElement::operator =(const SVGGElement &other)
+{
+ SVGElement::operator=(other);
+ SVGTests::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+ SVGTransformable::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGGElement::SVGGElement(SVGGElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGGElement::~SVGGElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGGElement.h b/ksvg/dom/SVGGElement.h
new file mode 100644
index 00000000..724bbadb
--- /dev/null
+++ b/ksvg/dom/SVGGElement.h
@@ -0,0 +1,83 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+
+ This file includes excerpts from the Scalable Vector Graphics
+ (SVG) 1.0 Specification (Proposed Recommendation)
+ http://www.w3.org/TR/SVG
+
+ Copyright 2001 World Wide Web Consortium, (Massachusetts
+ Institute of Technology, Institut National de Recherche en
+ Informatique et en Automatique, Keio University).
+ All Rights Reserved.
+*/
+
+#ifndef SVGGElement_H
+#define SVGGElement_H
+
+#include "SVGElement.h"
+#include "SVGTests.h"
+#include "SVGLangSpace.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+#include "SVGTransformable.h"
+
+namespace KSVG
+{
+
+class SVGGElementImpl;
+
+/**
+ * The 'g' element is a container element for grouping together related graphics elements.
+ *
+ * Grouping constructs, when used in conjunction with the @ref desc and @ref title elements, provide
+ * information about document structure and semantics. Documents that are rich in structure may be
+ * rendered graphically, as speech, or as braille, and thus promote accessibility.
+ *
+ * A group of elements, as well as individual objects, can be given a name using the <code> id </code> attribute.
+ * Named groups are needed for several purposes such as animation and re-usable objects.
+ *
+ * A 'g' element can contain other 'g' elements nested within it, to an arbitrary depth.
+ */
+class SVGGElement : public SVGElement,
+ public SVGTests,
+ public SVGLangSpace,
+ public SVGExternalResourcesRequired,
+ public SVGStylable,
+ public SVGTransformable
+{
+public:
+ SVGGElement();
+ SVGGElement(const SVGGElement &other);
+ SVGGElement &operator=(const SVGGElement &other);
+ SVGGElement(SVGGElementImpl *other);
+ ~SVGGElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGGElementImpl *handle() const { return impl; }
+
+private:
+ SVGGElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGGlyphElement.cc b/ksvg/dom/SVGGlyphElement.cc
new file mode 100644
index 00000000..c852d44d
--- /dev/null
+++ b/ksvg/dom/SVGGlyphElement.cc
@@ -0,0 +1,68 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGGlyphElement.h"
+#include "SVGGlyphElementImpl.h"
+
+using namespace KSVG;
+
+SVGGlyphElement::SVGGlyphElement() : SVGElement(), SVGStylable()
+{
+ impl = 0;
+}
+
+SVGGlyphElement::SVGGlyphElement(const SVGGlyphElement &other) : SVGElement(other), SVGStylable(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGGlyphElement &SVGGlyphElement::operator =(const SVGGlyphElement &other)
+{
+ SVGElement::operator=(other);
+ SVGStylable::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGGlyphElement::SVGGlyphElement(SVGGlyphElementImpl *other) : SVGElement(other), SVGStylable(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGGlyphElement::~SVGGlyphElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGGlyphElement.h b/ksvg/dom/SVGGlyphElement.h
new file mode 100644
index 00000000..c3d2237b
--- /dev/null
+++ b/ksvg/dom/SVGGlyphElement.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGGlyphElement_H
+#define SVGGlyphElement_H
+
+#include "SVGElement.h"
+#include "SVGStylable.h"
+
+namespace KSVG
+{
+
+class SVGGlyphElementImpl;
+class SVGGlyphElement : public SVGElement,
+ public SVGStylable
+{
+public:
+ SVGGlyphElement();
+ SVGGlyphElement(const SVGGlyphElement &other);
+ SVGGlyphElement &operator=(const SVGGlyphElement &other);
+ SVGGlyphElement(SVGGlyphElementImpl *other);
+ virtual ~SVGGlyphElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGGlyphElementImpl *handle() const { return impl; }
+
+private:
+ SVGGlyphElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGGlyphRefElement.cc b/ksvg/dom/SVGGlyphRefElement.cc
new file mode 100644
index 00000000..85c4c39f
--- /dev/null
+++ b/ksvg/dom/SVGGlyphRefElement.cc
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGGlyphRefElement.h"
+#include "SVGGlyphRefElementImpl.h"
+
+using namespace KSVG;
+
+SVGGlyphRefElement::SVGGlyphRefElement() : SVGElement(), SVGURIReference(), SVGStylable()
+{
+ impl = 0;
+}
+
+SVGGlyphRefElement::SVGGlyphRefElement(const SVGGlyphRefElement &other) : SVGElement(other), SVGURIReference(other), SVGStylable(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGGlyphRefElement &SVGGlyphRefElement::operator =(const SVGGlyphRefElement &other)
+{
+ SVGElement::operator=(other);
+ SVGURIReference::operator=(other);
+ SVGStylable::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGGlyphRefElement::SVGGlyphRefElement(SVGGlyphRefElementImpl *other) : SVGElement(other), SVGURIReference(other), SVGStylable(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGGlyphRefElement::~SVGGlyphRefElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+DOM::DOMString SVGGlyphRefElement::format()
+{
+ if(!impl) return DOM::DOMString();
+ return impl->format();
+}
+
+DOM::DOMString SVGGlyphRefElement::glyphRef()
+{
+ if(!impl) return DOM::DOMString();
+ return impl->glyphRef();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGGlyphRefElement.h b/ksvg/dom/SVGGlyphRefElement.h
new file mode 100644
index 00000000..29e91e57
--- /dev/null
+++ b/ksvg/dom/SVGGlyphRefElement.h
@@ -0,0 +1,57 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGGlyphRefElement_H
+#define SVGGlyphRefElement_H
+
+#include "SVGElement.h"
+#include "SVGURIReference.h"
+#include "SVGStylable.h"
+
+namespace KSVG
+{
+
+class SVGGlyphRefElementImpl;
+class SVGGlyphRefElement : public SVGElement,
+ public SVGURIReference,
+ public SVGStylable
+{
+public:
+ SVGGlyphRefElement();
+ SVGGlyphRefElement(const SVGGlyphRefElement &other);
+ SVGGlyphRefElement &operator=(const SVGGlyphRefElement &other);
+ SVGGlyphRefElement(SVGGlyphRefElementImpl *other);
+ virtual ~SVGGlyphRefElement();
+
+ DOM::DOMString glyphRef();
+ DOM::DOMString format();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGGlyphRefElementImpl *handle() const { return impl; }
+
+private:
+ SVGGlyphRefElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGGradientElement.cc b/ksvg/dom/SVGGradientElement.cc
new file mode 100644
index 00000000..2afb305e
--- /dev/null
+++ b/ksvg/dom/SVGGradientElement.cc
@@ -0,0 +1,80 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGGradientElement.h"
+#include "SVGGradientElementImpl.h"
+#include "SVGAnimatedTransformList.h"
+#include "SVGAnimatedEnumeration.h"
+
+using namespace KSVG;
+
+SVGGradientElement::SVGGradientElement() : SVGElement(), SVGURIReference(), SVGExternalResourcesRequired(), SVGStylable(), SVGUnitTypes()
+{
+ impl = 0;
+}
+
+SVGGradientElement::SVGGradientElement(const SVGGradientElement &other) : SVGElement(other), SVGURIReference(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGUnitTypes(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGGradientElement &SVGGradientElement::operator =(const SVGGradientElement &other)
+{
+ SVGElement::operator=(other);
+ SVGURIReference::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ impl = other.impl;
+
+ return *this;
+}
+
+SVGGradientElement::SVGGradientElement(SVGGradientElementImpl *other) : SVGElement(other), SVGURIReference(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGUnitTypes()
+{
+ impl = other;
+}
+
+SVGGradientElement::~SVGGradientElement()
+{
+}
+
+SVGAnimatedEnumeration SVGGradientElement::gradientUnits() const
+{
+ if(!impl) return SVGAnimatedEnumeration(0);
+ return SVGAnimatedEnumeration(impl->gradientUnits());
+}
+
+SVGAnimatedTransformList SVGGradientElement::gradientTransform() const
+{
+ if(!impl) return SVGAnimatedTransformList(0);
+ return SVGAnimatedTransformList(impl->gradientTransform());
+}
+
+SVGAnimatedEnumeration SVGGradientElement::spreadMethod() const
+{
+ if(!impl) return SVGAnimatedEnumeration(0);
+ return SVGAnimatedEnumeration(impl->spreadMethod());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGGradientElement.h b/ksvg/dom/SVGGradientElement.h
new file mode 100644
index 00000000..cff47ad8
--- /dev/null
+++ b/ksvg/dom/SVGGradientElement.h
@@ -0,0 +1,71 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGGradientElement_H
+#define SVGGradientElement_H
+
+#include "SVGElement.h"
+#include "SVGURIReference.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+#include "SVGUnitTypes.h"
+
+namespace KSVG
+{
+
+enum
+{
+ SVG_SPREADMETHOD_UNKNOWN = 0,
+ SVG_SPREADMETHOD_PAD = 1,
+ SVG_SPREADMETHOD_REFLECT = 2,
+ SVG_SPREADMETHOD_REPEAT = 3
+};
+
+class SVGAnimatedEnumeration;
+class SVGAnimatedTransformList;
+class SVGGradientElementImpl;
+class SVGGradientElement : public SVGElement,
+ public SVGURIReference,
+ public SVGExternalResourcesRequired,
+ public SVGStylable,
+ public SVGUnitTypes
+{
+public:
+ SVGGradientElement(const SVGGradientElement &other);
+ SVGGradientElement &operator=(const SVGGradientElement &other);
+ SVGGradientElement(SVGGradientElementImpl *other);
+ virtual ~SVGGradientElement();
+
+ SVGAnimatedEnumeration gradientUnits() const;
+ SVGAnimatedTransformList gradientTransform() const;
+ SVGAnimatedEnumeration spreadMethod() const;
+
+protected:
+ SVGGradientElement();
+
+private:
+ SVGGradientElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGHKernElement.cc b/ksvg/dom/SVGHKernElement.cc
new file mode 100644
index 00000000..db46aa63
--- /dev/null
+++ b/ksvg/dom/SVGHKernElement.cc
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGHKernElement.h"
+#include "SVGHKernElementImpl.h"
+
+using namespace KSVG;
+
+SVGHKernElement::SVGHKernElement() : SVGElement()
+{
+ impl = 0;
+}
+
+SVGHKernElement::SVGHKernElement(const SVGHKernElement &other) : SVGElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGHKernElement &SVGHKernElement::operator =(const SVGHKernElement &other)
+{
+ SVGElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGHKernElement::SVGHKernElement(SVGHKernElementImpl *other) : SVGElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGHKernElement::~SVGHKernElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGHKernElement.h b/ksvg/dom/SVGHKernElement.h
new file mode 100644
index 00000000..42890727
--- /dev/null
+++ b/ksvg/dom/SVGHKernElement.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGHKernElement_H
+#define SVGHKernElement_H
+
+#include "SVGElement.h"
+
+namespace KSVG
+{
+
+class SVGHKernElementImpl;
+class SVGHKernElement : public SVGElement
+{
+public:
+ SVGHKernElement();
+ SVGHKernElement(const SVGHKernElement &other);
+ SVGHKernElement &operator=(const SVGHKernElement &other);
+ SVGHKernElement(SVGHKernElementImpl *other);
+ virtual ~SVGHKernElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGHKernElementImpl *handle() const { return impl; }
+
+private:
+ SVGHKernElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGICCColor.cc b/ksvg/dom/SVGICCColor.cc
new file mode 100644
index 00000000..6b21f3fb
--- /dev/null
+++ b/ksvg/dom/SVGICCColor.cc
@@ -0,0 +1,85 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGICCColor.h"
+#include "SVGICCColorImpl.h"
+#include "SVGNumberList.h"
+
+using namespace KSVG;
+
+SVGICCColor::SVGICCColor()
+{
+ impl = new SVGICCColorImpl();
+ impl->ref();
+}
+
+SVGICCColor::SVGICCColor(const SVGICCColor &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGICCColor &SVGICCColor::operator =(const SVGICCColor &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGICCColor::SVGICCColor(SVGICCColorImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGICCColor::~SVGICCColor()
+{
+ if(impl)
+ impl->deref();
+}
+
+void SVGICCColor::setColorProfile(const DOM::DOMString &colorProfile)
+{
+ if(impl)
+ impl->setColorProfile(colorProfile);
+}
+
+DOM::DOMString SVGICCColor::colorProfile() const
+{
+ if(!impl) return DOM::DOMString();
+ return DOM::DOMString(impl->colorProfile());
+}
+
+SVGNumberList SVGICCColor::colors() const
+{
+ if(!impl) return SVGNumberList(0);
+ return SVGNumberList(impl->colors());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGICCColor.h b/ksvg/dom/SVGICCColor.h
new file mode 100644
index 00000000..628feda9
--- /dev/null
+++ b/ksvg/dom/SVGICCColor.h
@@ -0,0 +1,56 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGICCColor_H
+#define SVGICCColor_H
+
+#include <dom/dom_string.h>
+
+namespace KSVG
+{
+
+class SVGNumberList;
+class SVGICCColorImpl;
+class SVGICCColor
+{
+public:
+ SVGICCColor();
+ SVGICCColor(const SVGICCColor &other);
+ SVGICCColor &operator=(const SVGICCColor &other);
+ SVGICCColor(SVGICCColorImpl *other);
+ ~SVGICCColor();
+
+ void setColorProfile(const DOM::DOMString &colorProfile);
+ DOM::DOMString colorProfile() const;
+
+ SVGNumberList colors() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGICCColorImpl *handle() const { return impl; }
+
+private:
+ SVGICCColorImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGImageElement.cc b/ksvg/dom/SVGImageElement.cc
new file mode 100644
index 00000000..9d9374fa
--- /dev/null
+++ b/ksvg/dom/SVGImageElement.cc
@@ -0,0 +1,106 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+#include "SVGImageElement.h"
+#include "SVGImageElementImpl.h"
+#include "SVGAnimatedLength.h"
+#include "SVGAnimatedPreserveAspectRatio.h"
+
+using namespace KSVG;
+
+SVGImageElement::SVGImageElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable(), SVGURIReference()
+{
+ impl = 0;
+}
+
+SVGImageElement::SVGImageElement(const SVGImageElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), SVGURIReference(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGImageElement &SVGImageElement::operator=(const SVGImageElement &other)
+{
+ SVGElement::operator=(other);
+ SVGTests::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+ SVGTransformable::operator=(other);
+ SVGURIReference::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGImageElement::SVGImageElement(SVGImageElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), SVGURIReference(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGImageElement::~SVGImageElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedLength SVGImageElement::x()
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->x());
+}
+
+SVGAnimatedLength SVGImageElement::y()
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->y());
+}
+
+SVGAnimatedLength SVGImageElement::width()
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->width());
+}
+
+SVGAnimatedLength SVGImageElement::height()
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->height());
+}
+
+SVGAnimatedPreserveAspectRatio SVGImageElement::preserveAspectRatio() const
+{
+ if(!impl) return SVGAnimatedPreserveAspectRatio(0);
+ return SVGAnimatedPreserveAspectRatio(impl->preserveAspectRatio());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGImageElement.h b/ksvg/dom/SVGImageElement.h
new file mode 100644
index 00000000..c6487fed
--- /dev/null
+++ b/ksvg/dom/SVGImageElement.h
@@ -0,0 +1,70 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGImageElement_H
+#define SVGImageElement_H
+
+#include "SVGElement.h"
+#include "SVGTests.h"
+#include "SVGLangSpace.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+#include "SVGTransformable.h"
+#include "SVGURIReference.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedPreserveAspectRatio;
+class SVGAnimatedLength;
+class SVGImageElementImpl;
+class SVGImageElement : public SVGElement,
+ public SVGTests,
+ public SVGLangSpace,
+ public SVGExternalResourcesRequired,
+ public SVGStylable,
+ public SVGTransformable,
+ public SVGURIReference
+{
+public:
+ SVGImageElement();
+ SVGImageElement(const SVGImageElement &);
+ SVGImageElement &operator=(const SVGImageElement &other);
+ SVGImageElement(SVGImageElementImpl *);
+ ~SVGImageElement();
+
+ SVGAnimatedLength x();
+ SVGAnimatedLength y();
+ SVGAnimatedLength width();
+ SVGAnimatedLength height();
+ SVGAnimatedPreserveAspectRatio preserveAspectRatio() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGImageElementImpl *handle() const { return impl; }
+
+private:
+ SVGImageElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGLangSpace.cc b/ksvg/dom/SVGLangSpace.cc
new file mode 100644
index 00000000..2373e648
--- /dev/null
+++ b/ksvg/dom/SVGLangSpace.cc
@@ -0,0 +1,82 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGLangSpace.h"
+#include "SVGLangSpaceImpl.h"
+
+using namespace KSVG;
+
+// This class can't be constructed seperately.
+SVGLangSpace::SVGLangSpace()
+{
+ impl = 0;
+}
+
+SVGLangSpace::SVGLangSpace(const SVGLangSpace &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGLangSpace &SVGLangSpace::operator=(const SVGLangSpace &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ impl = other.impl;
+
+ return *this;
+}
+
+SVGLangSpace::SVGLangSpace(SVGLangSpaceImpl *other)
+{
+ impl = other;
+}
+
+SVGLangSpace::~SVGLangSpace()
+{
+ // We are not allowed to delete 'impl' as it's not refcounted.
+ // delete impl;
+}
+
+void SVGLangSpace::setXmllang(const DOM::DOMString &xmllang)
+{
+ if(impl)
+ impl->setXmllang(xmllang);
+}
+
+DOM::DOMString SVGLangSpace::xmllang() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->xmllang();
+}
+
+void SVGLangSpace::setXmlspace(const DOM::DOMString &xmlspace)
+{
+ if(impl)
+ impl->setXmlspace(xmlspace);
+}
+
+DOM::DOMString SVGLangSpace::xmlspace() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->xmlspace();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGLangSpace.h b/ksvg/dom/SVGLangSpace.h
new file mode 100644
index 00000000..391e625d
--- /dev/null
+++ b/ksvg/dom/SVGLangSpace.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGLangSpace_H
+#define SVGLangSpace_H
+
+#include <dom/dom_string.h>
+
+namespace KSVG
+{
+
+class SVGLangSpaceImpl;
+class SVGLangSpace
+{
+public:
+ SVGLangSpace(const SVGLangSpace &other);
+ SVGLangSpace &operator=(const SVGLangSpace &other);
+ SVGLangSpace(SVGLangSpaceImpl *other);
+ ~SVGLangSpace();
+
+ void setXmllang(const DOM::DOMString &xmllang);
+ DOM::DOMString xmllang() const;
+
+ void setXmlspace(const DOM::DOMString &xmlspace);
+ DOM::DOMString xmlspace() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGLangSpaceImpl *handle() const { return impl; }
+
+protected:
+ SVGLangSpace();
+
+private:
+ SVGLangSpaceImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGLength.cc b/ksvg/dom/SVGLength.cc
new file mode 100644
index 00000000..bb2db73f
--- /dev/null
+++ b/ksvg/dom/SVGLength.cc
@@ -0,0 +1,135 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <dom/dom_string.h>
+#include "SVGLength.h"
+#include "SVGShapeImpl.h"
+#include "SVGLengthImpl.h"
+
+using namespace KSVG;
+
+SVGLength::SVGLength()
+{
+ impl = new SVGLengthImpl();
+ impl->ref();
+}
+
+SVGLength::SVGLength(const SVGLength &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGLength &SVGLength::operator =(const SVGLength &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGLength::SVGLength(SVGLengthImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGLength::~SVGLength()
+{
+ if(impl)
+ impl->deref();
+}
+
+unsigned short SVGLength::unitType() const
+{
+ if(!impl) return SVG_LENGTHTYPE_UNKNOWN;
+ return impl->unitType();
+}
+
+void SVGLength::setValue(float value)
+{
+ if(impl)
+ {
+ impl->setValue(value);
+
+ // Automatic updating of the shape if any value is changed, imagine:
+ // SVGCircleElement c; [...] c.r().baseVal().setValue(150);
+ if(impl->context() && dynamic_cast<SVGShapeImpl *>(impl->context()))
+ dynamic_cast<SVGShapeImpl *>(impl->context())->update(UPDATE_TRANSFORM, 0, 0);
+ }
+}
+
+float SVGLength::value() const
+{
+ if(!impl) return -1;
+ return impl->value();
+}
+
+void SVGLength::setValueInSpecifiedUnits(float valueInSpecifiedUnits)
+{
+ if(impl)
+ impl->setValueInSpecifiedUnits(valueInSpecifiedUnits);
+}
+
+float SVGLength::valueInSpecifiedUnits() const
+{
+ if(!impl) return -1;
+ return impl->valueInSpecifiedUnits();
+}
+
+void SVGLength::setValueAsString(const DOM::DOMString &valueAsString)
+{
+ if(impl)
+ impl->setValueAsString(valueAsString);
+}
+
+DOM::DOMString SVGLength::valueAsString() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->valueAsString();
+}
+
+void SVGLength::newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits)
+{
+ if(impl)
+ impl->newValueSpecifiedUnits(unitType, valueInSpecifiedUnits);
+}
+
+void SVGLength::convertToSpecifiedUnits(unsigned short unitType)
+{
+ if(impl)
+ impl->convertToSpecifiedUnits(unitType);
+}
+
+SVGLength::operator float()
+{
+ if(!impl) return -1;
+ return impl->valueInSpecifiedUnits();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGLength.h b/ksvg/dom/SVGLength.h
new file mode 100644
index 00000000..1f0bbdae
--- /dev/null
+++ b/ksvg/dom/SVGLength.h
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGLength_H
+#define SVGLength_H
+
+#include <dom/dom_string.h>
+
+namespace KSVG
+{
+
+enum
+{
+ SVG_LENGTHTYPE_UNKNOWN,
+ SVG_LENGTHTYPE_NUMBER,
+ SVG_LENGTHTYPE_PERCENTAGE,
+ SVG_LENGTHTYPE_EMS,
+ SVG_LENGTHTYPE_EXS,
+ SVG_LENGTHTYPE_PX,
+ SVG_LENGTHTYPE_CM,
+ SVG_LENGTHTYPE_MM,
+ SVG_LENGTHTYPE_IN,
+ SVG_LENGTHTYPE_PT,
+ SVG_LENGTHTYPE_PC
+};
+
+class SVGLengthImpl;
+class SVGLength
+{
+public:
+ SVGLength();
+ SVGLength(const SVGLength &);
+ SVGLength(SVGLengthImpl *);
+ SVGLength &operator=(const SVGLength &);
+ ~SVGLength();
+
+ unsigned short unitType() const;
+
+ void setValue(float value);
+ float value() const;
+
+ void setValueInSpecifiedUnits(float valueInSpecifiedUnits);
+ float valueInSpecifiedUnits() const;
+
+ void setValueAsString(const DOM::DOMString &);
+ DOM::DOMString valueAsString() const;
+
+ void newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits);
+ void convertToSpecifiedUnits(unsigned short unitType);
+
+ operator float();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGLengthImpl *handle() const { return impl; }
+
+private:
+ SVGLengthImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGLengthList.cc b/ksvg/dom/SVGLengthList.cc
new file mode 100644
index 00000000..c308019b
--- /dev/null
+++ b/ksvg/dom/SVGLengthList.cc
@@ -0,0 +1,115 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGLengthList.h"
+#include "SVGLengthListImpl.h"
+#include "SVGLength.h"
+
+using namespace KSVG;
+
+SVGLengthList::SVGLengthList()
+{
+ impl = new SVGLengthListImpl();
+ impl->ref();
+}
+
+SVGLengthList::SVGLengthList(const SVGLengthList &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGLengthList &SVGLengthList::operator=(const SVGLengthList &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGLengthList::SVGLengthList(SVGLengthListImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGLengthList::~SVGLengthList()
+{
+ if(impl)
+ impl->deref();
+}
+
+unsigned long SVGLengthList::numberOfItems() const
+{
+ if(!impl) return 0;
+ return impl->numberOfItems();
+}
+
+void SVGLengthList::clear()
+{
+ if(impl)
+ impl->clear();
+}
+
+SVGLength *SVGLengthList::initialize(SVGLength *newItem)
+{
+ if(!impl) return new SVGLength(0);
+ return new SVGLength(impl->initialize(newItem->handle()));
+}
+
+SVGLength *SVGLengthList::getItem(unsigned long index)
+{
+ if(!impl) return new SVGLength(0);
+ return new SVGLength(impl->getItem(index));
+}
+
+SVGLength *SVGLengthList::insertItemBefore(SVGLength *newItem, unsigned long index)
+{
+ if(!impl) return new SVGLength(0);
+ return new SVGLength(impl->insertItemBefore(newItem->handle(), index));
+}
+
+SVGLength *SVGLengthList::replaceItem(SVGLength *newItem, unsigned long index)
+{
+ if(!impl) return new SVGLength(0);
+ return new SVGLength(impl->replaceItem(newItem->handle(), index));
+}
+
+SVGLength *SVGLengthList::removeItem(unsigned long index)
+{
+ if(!impl) return new SVGLength(0);
+ return new SVGLength(impl->removeItem(index));
+}
+
+SVGLength *SVGLengthList::appendItem(SVGLength *newItem)
+{
+ if(!impl) return new SVGLength(0);
+ return new SVGLength(impl->appendItem(newItem->handle()));
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGLengthList.h b/ksvg/dom/SVGLengthList.h
new file mode 100644
index 00000000..bf4ab633
--- /dev/null
+++ b/ksvg/dom/SVGLengthList.h
@@ -0,0 +1,59 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGLengthList_H
+#define SVGLengthList_H
+
+namespace KSVG
+{
+
+class SVGLength;
+class SVGLengthListImpl;
+class SVGLengthList
+{
+public:
+ SVGLengthList();
+ SVGLengthList(const SVGLengthList &);
+ SVGLengthList &operator=(const SVGLengthList &);
+ SVGLengthList(SVGLengthListImpl *);
+ ~SVGLengthList();
+
+ unsigned long numberOfItems() const;
+ void clear();
+
+ SVGLength *initialize(SVGLength *newItem);
+ SVGLength *getItem(unsigned long index);
+ SVGLength *insertItemBefore(SVGLength *newItem, unsigned long index);
+ SVGLength *replaceItem(SVGLength *newItem, unsigned long index);
+ SVGLength *removeItem(unsigned long index);
+ SVGLength *appendItem(SVGLength *newItem);
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGLengthListImpl *handle() const { return impl; }
+
+private:
+ SVGLengthListImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGLineElement.cc b/ksvg/dom/SVGLineElement.cc
new file mode 100644
index 00000000..583c3fe3
--- /dev/null
+++ b/ksvg/dom/SVGLineElement.cc
@@ -0,0 +1,98 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+#include "SVGLineElement.h"
+#include "SVGLineElementImpl.h"
+#include "SVGAnimatedLength.h"
+
+using namespace KSVG;
+
+SVGLineElement::SVGLineElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable()
+{
+ impl = 0;
+}
+
+SVGLineElement::SVGLineElement(const SVGLineElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGLineElement &SVGLineElement::operator=(const SVGLineElement &other)
+{
+ SVGElement::operator=(other);
+ SVGTests::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+ SVGTransformable::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGLineElement::SVGLineElement(SVGLineElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGLineElement::~SVGLineElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedLength SVGLineElement::x1()
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->x1());
+}
+
+SVGAnimatedLength SVGLineElement::y1()
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->y1());
+}
+
+SVGAnimatedLength SVGLineElement::x2()
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->x2());
+}
+
+SVGAnimatedLength SVGLineElement::y2()
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->y2());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGLineElement.h b/ksvg/dom/SVGLineElement.h
new file mode 100644
index 00000000..b08a78ba
--- /dev/null
+++ b/ksvg/dom/SVGLineElement.h
@@ -0,0 +1,126 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; see the file COPYING.LIB. If
+ not, write to the Free Software Foundation, Inc., 51 Franklin Street,
+ Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+ This file includes excerpts from the Scalable Vector Graphics
+ (SVG) 1.0 Specification (Proposed Recommendation)
+ http://www.w3.org/TR/SVG
+
+ Copyright 2001 World Wide Web Consortium, (Massachusetts
+ Institute of Technology, Institut National de Recherche en
+ Informatique et en Automatique, Keio University).
+ All Rights Reserved.
+
+ $Id$
+ */
+
+#ifndef SVGLineElement_H
+#define SVGLineElement_H
+
+#include "SVGElement.h"
+#include "SVGTests.h"
+#include "SVGLangSpace.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+#include "SVGTransformable.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedLength;
+class SVGLineElementImpl;
+
+/**
+ * The <code>line</code> element defines a line segment that starts at
+ * one point and ends at another.
+ *
+ * For more info look here : <a href =
+ * "http://www.w3.org/TR/SVG/shapes.html#CircleElement">9.5 The
+ * 'line' element</a>.
+ */
+class SVGLineElement : public SVGElement,
+ public SVGTests,
+ public SVGLangSpace,
+ public SVGExternalResourcesRequired,
+ public SVGStylable,
+ public SVGTransformable
+{
+public:
+ SVGLineElement();
+ SVGLineElement(const SVGLineElement &);
+ SVGLineElement &operator=(const SVGLineElement &other);
+ SVGLineElement(SVGLineElementImpl *);
+ ~SVGLineElement();
+
+ /**
+ * The x-axis coordinate of the start of the line.
+ * If the attribute is not specified, the effect is as if a value
+ * of "0" were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The x-axis coordinate of the start of the line.
+ */
+ SVGAnimatedLength x1();
+
+ /**
+ * The y-axis coordinate of the start of the line.
+ * If the attribute is not specified, the effect is as if a value
+ * of "0" were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The y-axis coordinate of the start of the line.
+ */
+ SVGAnimatedLength y1();
+
+ /**
+ * The x-axis coordinate of the end of the line.
+ * If the attribute is not specified, the effect is as if a value
+ * of "0" were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The x-axis coordinate of the end of the line.
+ */
+ SVGAnimatedLength x2();
+
+ /**
+ * The y-axis coordinate of the end of the line.
+ * If the attribute is not specified, the effect is as if a value
+ * of "0" were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The y-axis coordinate of the end of the line.
+ */
+ SVGAnimatedLength y2();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGLineElementImpl *handle() const { return impl; }
+
+private:
+ SVGLineElementImpl *impl;
+};
+
+}
+
+#endif
+
+//vim:ts=4:noet
diff --git a/ksvg/dom/SVGLinearGradientElement.cc b/ksvg/dom/SVGLinearGradientElement.cc
new file mode 100644
index 00000000..b3936dc4
--- /dev/null
+++ b/ksvg/dom/SVGLinearGradientElement.cc
@@ -0,0 +1,92 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGLinearGradientElement.h"
+#include "SVGLinearGradientElementImpl.h"
+#include "SVGAnimatedLength.h"
+
+using namespace KSVG;
+
+SVGLinearGradientElement::SVGLinearGradientElement() : SVGGradientElement()
+{
+ impl = 0;
+}
+
+SVGLinearGradientElement::SVGLinearGradientElement(const SVGLinearGradientElement &other) : SVGGradientElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGLinearGradientElement &SVGLinearGradientElement::operator =(const SVGLinearGradientElement &other)
+{
+ SVGGradientElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGLinearGradientElement::SVGLinearGradientElement(SVGLinearGradientElementImpl *other) : SVGGradientElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGLinearGradientElement::~SVGLinearGradientElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedLength SVGLinearGradientElement::x1() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->x1());
+}
+
+SVGAnimatedLength SVGLinearGradientElement::y1() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->y1());
+}
+
+SVGAnimatedLength SVGLinearGradientElement::x2() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->x2());
+}
+
+SVGAnimatedLength SVGLinearGradientElement::y2() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->y2());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGLinearGradientElement.h b/ksvg/dom/SVGLinearGradientElement.h
new file mode 100644
index 00000000..fe60df89
--- /dev/null
+++ b/ksvg/dom/SVGLinearGradientElement.h
@@ -0,0 +1,141 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+
+ This file includes excerpts from the Scalable Vector Graphics
+ (SVG) 1.0 Specification (Proposed Recommendation)
+ http://www.w3.org/TR/SVG
+
+ Copyright 2001 World Wide Web Consortium, (Massachusetts
+ Institute of Technology, Institut National de Recherche en
+ Informatique et en Automatique, Keio University).
+ All Rights Reserved.
+*/
+
+#ifndef SVGLinearGradientElement_H
+#define SVGLinearGradientElement_H
+
+#include "SVGGradientElement.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedLength;
+class SVGLinearGradientElementImpl;
+
+/**
+ * <code>linearGradient</code> elements are never rendered directly; their
+ * only usage is as something that can be referenced using the
+ * <code>fill</code> and <code>stroke</code> properties.
+ * The <code>display</code> property does not apply to the
+ * <code>linearGradient</code> element; thus,
+ * <code>linearGradient</code> elements are not directly rendered even if the
+ * <code>display</code> property is set to a value other than none, and
+ * <code>linearGradient</code> elements are available for referencing even when
+ * the <code>display</code> property on the <code>linearGradient</code> element
+ * or any of its ancestors is set to none.
+ *
+ * For more information :
+ * <a href="http://www.w3.org/TR/SVG/pservers.html#LinearGradients">
+ * 13.2.2 Linear gradients</a>
+ *
+ */
+
+class SVGLinearGradientElement : public SVGGradientElement
+{
+public:
+ SVGLinearGradientElement();
+ SVGLinearGradientElement(const SVGLinearGradientElement &other);
+ SVGLinearGradientElement &operator=(const SVGLinearGradientElement &other);
+ SVGLinearGradientElement(SVGLinearGradientElementImpl *other);
+ virtual ~SVGLinearGradientElement();
+
+ /**
+ * x1, y1, x2, y2 define a gradient vector for the linear gradient.
+ * This gradient vector provides starting and ending points onto which the
+ * @ref SVGGradientElement (gradient stops) are mapped. The values of x1,
+ * y1, x2, y2 can be either numbers or percentages.
+ *
+ * If the attribute is not specified, the effect is as if a value of "0%"
+ * were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The x1 value
+ */
+ SVGAnimatedLength x1() const;
+
+ /**
+ * x1, y1, x2, y2 define a gradient vector for the linear gradient.
+ * This gradient vector provides starting and ending points onto which the
+ * @ref SVGGradientElement (gradient stops) are mapped. The values of x1,
+ * y1, x2, y2 can be either numbers or percentages.
+ *
+ * If the attribute is not specified, the effect is as if a value of "0%"
+ * were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The y1 value
+ */
+ SVGAnimatedLength y1() const;
+
+ /**
+ * x1, y1, x2, y2 define a gradient vector for the linear gradient.
+ * This gradient vector provides starting and ending points onto which the
+ * @ref SVGGradientElement (gradient stops) are mapped. The values of x1,
+ * y1, x2, y2 can be either numbers or percentages.
+ *
+ * If the attribute is not specified, the effect is as if a value of "100%"
+ * were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The x2 value
+ */
+ SVGAnimatedLength x2() const;
+
+ /**
+ * x1, y1, x2, y2 define a gradient vector for the linear gradient.
+ * This gradient vector provides starting and ending points onto which the
+ * @ref SVGGradientElement (gradient stops) are mapped. The values of x1,
+ * y1, x2, y2 can be either numbers or percentages.
+ *
+ * If the attribute is not specified, the effect is as if a value of "0%"
+ * were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The y2 value
+ */
+ SVGAnimatedLength y2() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGLinearGradientElementImpl *handle() const { return impl; }
+
+private:
+ SVGLinearGradientElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
+
diff --git a/ksvg/dom/SVGLocatable.cc b/ksvg/dom/SVGLocatable.cc
new file mode 100644
index 00000000..62a89e2e
--- /dev/null
+++ b/ksvg/dom/SVGLocatable.cc
@@ -0,0 +1,97 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGLocatable.h"
+#include "SVGLocatableImpl.h"
+#include "SVGElement.h"
+#include "SVGRect.h"
+#include "SVGMatrix.h"
+
+using namespace KSVG;
+
+// This class can't be constructed seperately.
+SVGLocatable::SVGLocatable()
+{
+ impl = 0;
+}
+
+SVGLocatable::SVGLocatable(const SVGLocatable &other)
+{
+ (*this) = other;
+}
+
+SVGLocatable &SVGLocatable::operator=(const SVGLocatable &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ impl = other.impl;
+
+ return *this;
+}
+
+SVGLocatable::SVGLocatable(SVGLocatableImpl *other)
+{
+ impl = other;
+}
+
+SVGLocatable::~SVGLocatable()
+{
+ // We are not allowed to delete 'impl' as it's not refcounted.
+ // delete impl;
+}
+
+SVGElement SVGLocatable::nearestViewportElement() const
+{
+ if(!impl) return SVGElement(0);
+ return impl->nearestViewportElement();
+}
+
+SVGElement SVGLocatable::farthestViewportElement() const
+{
+ if(!impl) return SVGElement(0);
+ return impl->farthestViewportElement();
+}
+
+SVGRect SVGLocatable::getBBox()
+{
+ if(!impl) return SVGRect(0);
+ return SVGRect(impl->getBBox()); // TODO: Check correctness
+}
+
+SVGMatrix SVGLocatable::getCTM()
+{
+ if(!impl) return SVGMatrix(0);
+ return SVGMatrix(impl->getCTM());
+}
+
+SVGMatrix SVGLocatable::getScreenCTM()
+{
+ if(!impl) return SVGMatrix(0);
+ return SVGMatrix(impl->getScreenCTM());
+}
+
+SVGMatrix SVGLocatable::getTransformToElement(const SVGElement &element)
+{
+ if(!impl) return SVGMatrix(0);
+ return SVGMatrix(impl->getTransformToElement(element.handle()));
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGLocatable.h b/ksvg/dom/SVGLocatable.h
new file mode 100644
index 00000000..ecb93adc
--- /dev/null
+++ b/ksvg/dom/SVGLocatable.h
@@ -0,0 +1,122 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+
+ This file includes excerpts from the Scalable Vector Graphics
+ (SVG) 1.0 Specification (Proposed Recommendation)
+ http://www.w3.org/TR/SVG
+
+ Copyright 2001 World Wide Web Consortium, (Massachusetts
+ Institute of Technology, Institut National de Recherche en
+ Informatique et en Automatique, Keio University).
+ All Rights Reserved.
+*/
+
+#ifndef SVGLocatable_H
+#define SVGLocatable_H
+
+namespace KSVG
+{
+
+class SVGElement;
+class SVGMatrix;
+class SVGRect;
+class SVGLocatableImpl;
+
+/**
+ * Interface SVGLocatable is for all elements which either have a <code>transform</code>
+ * attribute or don't have a <code>transform</code> attribute but whose content can have
+ * a bounding box in current user space.
+ */
+class SVGLocatable
+{
+public:
+ SVGLocatable(const SVGLocatable &other);
+ SVGLocatable &operator=(const SVGLocatable &other);
+ SVGLocatable(SVGLocatableImpl *other);
+ virtual ~SVGLocatable();
+
+ /**
+ * The element which established the current viewport. Often, the nearest
+ * ancestor 'svg' element. Null if the current element is the outermost 'svg' element.
+ */
+ SVGElement nearestViewportElement() const;
+
+ /**
+ * The farthest ancestor 'svg' element. Null if the current element is
+ * the outermost 'svg' element.
+ */
+ SVGElement farthestViewportElement() const;
+
+ /**
+ * Returns the tight bounding box in current user space (i.e., after application of
+ * the <code>transform</code> attribute, if any) on the geometry of all contained graphics
+ * elements, exclusive of stroke-width and filter effects).
+ *
+ * @return An SVGRect object that defines the bounding box.
+ */
+ SVGRect getBBox();
+
+ /**
+ * Returns the transformation matrix from current user units (i.e., after application of
+ * the <code>transform</code> attribute, if any) to the viewport coordinate system for
+ * the nearestViewportElement.
+ *
+ * @return An SVGMatrix object that defines the CTM.
+ */
+ SVGMatrix getCTM();
+
+ /**
+ * Returns the transformation matrix from current user units (i.e., after application of
+ * the <code>transform</code> attribute, if any) to the parent user agent's notice of a "pixel".
+ * For display devices, ideally this represents a physical screen pixel. For other devices or
+ * environments where physical pixel sizes are not known, then an algorithm similar to the
+ * CSS2 definition of a "pixel" can be used instead.
+ *
+ * @return An SVGMatrix object that defines the given transformation matrix.
+ */
+ SVGMatrix getScreenCTM();
+
+ /**
+ * Returns the transformation matrix from the user coordinate system on the current
+ * element (after application of the <code>transform</code> attribute, if any) to the
+ * user coordinate system on parameter element (after application of its
+ * <code>transform</code> attribute, if any).
+ *
+ * @param element The target element.
+ *
+ * @return An SVGMatrix object that defines the transformation.
+ */
+ SVGMatrix getTransformToElement(const SVGElement &element);
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGLocatableImpl *handle() const { return impl; }
+
+protected:
+ SVGLocatable();
+
+private:
+ SVGLocatableImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGMPathElement.cc b/ksvg/dom/SVGMPathElement.cc
new file mode 100644
index 00000000..6d7a36e4
--- /dev/null
+++ b/ksvg/dom/SVGMPathElement.cc
@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGMPathElement.h"
+#include "SVGMPathElementImpl.h"
+
+using namespace KSVG;
+
+SVGMPathElement::SVGMPathElement() : SVGElement(), SVGURIReference(), SVGExternalResourcesRequired()
+{
+ impl = 0;
+}
+
+SVGMPathElement::SVGMPathElement(const SVGMPathElement &other) : SVGElement(other), SVGURIReference(other), SVGExternalResourcesRequired(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGMPathElement &SVGMPathElement::operator =(const SVGMPathElement &other)
+{
+ SVGElement::operator=(other);
+ SVGURIReference::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGMPathElement::SVGMPathElement(SVGMPathElementImpl *other) : SVGElement(other), SVGURIReference(other), SVGExternalResourcesRequired(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGMPathElement::~SVGMPathElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGMPathElement.h b/ksvg/dom/SVGMPathElement.h
new file mode 100644
index 00000000..e972e7ca
--- /dev/null
+++ b/ksvg/dom/SVGMPathElement.h
@@ -0,0 +1,54 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGMPathElement_H
+#define SVGMPathElement_H
+
+#include "SVGElement.h"
+#include "SVGURIReference.h"
+#include "SVGExternalResourcesRequired.h"
+
+namespace KSVG
+{
+
+class SVGMPathElementImpl;
+class SVGMPathElement : public SVGElement,
+ public SVGURIReference,
+ public SVGExternalResourcesRequired
+{
+public:
+ SVGMPathElement();
+ SVGMPathElement(const SVGMPathElement &other);
+ SVGMPathElement &operator=(const SVGMPathElement &other);
+ SVGMPathElement(SVGMPathElementImpl *other);
+ virtual ~SVGMPathElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGMPathElementImpl *handle() const { return impl; }
+
+private:
+ SVGMPathElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGMarkerElement.cc b/ksvg/dom/SVGMarkerElement.cc
new file mode 100644
index 00000000..7d7551da
--- /dev/null
+++ b/ksvg/dom/SVGMarkerElement.cc
@@ -0,0 +1,129 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGMarkerElement.h"
+#include "SVGMarkerElementImpl.h"
+#include "SVGAnimatedLength.h"
+#include "SVGAnimatedAngle.h"
+#include "SVGAngle.h"
+#include "SVGAnimatedEnumeration.h"
+
+using namespace KSVG;
+
+SVGMarkerElement::SVGMarkerElement() : SVGElement(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGFitToViewBox()
+{
+ impl = 0;
+}
+
+SVGMarkerElement::SVGMarkerElement(const SVGMarkerElement &other) : SVGElement(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGFitToViewBox(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGMarkerElement &SVGMarkerElement::operator =(const SVGMarkerElement &other)
+{
+ SVGElement::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+ SVGFitToViewBox::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGMarkerElement::SVGMarkerElement(SVGMarkerElementImpl *other) : SVGElement(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGFitToViewBox(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGMarkerElement::~SVGMarkerElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedLength SVGMarkerElement::refX() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->refX());
+}
+
+SVGAnimatedLength SVGMarkerElement::refY() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->refY());
+}
+
+SVGAnimatedEnumeration SVGMarkerElement::markerUnits() const
+{
+ if(!impl) return SVGAnimatedEnumeration(0);
+ return SVGAnimatedEnumeration(impl->markerUnits());
+}
+
+SVGAnimatedLength SVGMarkerElement::markerWidth() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->markerWidth());
+}
+
+SVGAnimatedLength SVGMarkerElement::markerHeight() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->markerHeight());
+}
+
+SVGAnimatedEnumeration SVGMarkerElement::orientType() const
+{
+ if(!impl) return SVGAnimatedEnumeration(0);
+ return SVGAnimatedEnumeration(impl->orientType());
+}
+
+SVGAnimatedAngle SVGMarkerElement::orientAngle() const
+{
+ if(!impl) return SVGAnimatedAngle(0);
+ return SVGAnimatedAngle(impl->orientAngle());
+}
+
+void SVGMarkerElement::setOrientToAuto()
+{
+ if(impl)
+ impl->setOrientToAuto();
+}
+
+void SVGMarkerElement::setOrientToAngle(const SVGAngle &angle)
+{
+ if(impl)
+ impl->setOrientToAngle(angle.handle());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGMarkerElement.h b/ksvg/dom/SVGMarkerElement.h
new file mode 100644
index 00000000..d2f54904
--- /dev/null
+++ b/ksvg/dom/SVGMarkerElement.h
@@ -0,0 +1,87 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGMarkerElement_H
+#define SVGMarkerElement_H
+
+#include "SVGElement.h"
+#include "SVGLangSpace.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+#include "SVGFitToViewBox.h"
+
+namespace KSVG
+{
+
+enum
+{
+ SVG_MARKERUNITS_UNKNOWN = 0,
+ SVG_MARKERUNITS_USERSPACEONUSE = 1,
+ SVG_MARKERUNITS_STROKEWIDTH = 2
+};
+
+enum
+{
+ SVG_MARKER_ORIENT_UNKNOWN = 0,
+ SVG_MARKER_ORIENT_AUTO = 1,
+ SVG_MARKER_ORIENT_ANGLE = 2
+};
+
+class SVGAnimatedLength;
+class SVGAnimatedAngle;
+class SVGAngle;
+class SVGAnimatedEnumeration;
+class SVGMarkerElementImpl;
+class SVGMarkerElement : public SVGElement,
+ public SVGLangSpace,
+ public SVGExternalResourcesRequired,
+ public SVGStylable,
+ public SVGFitToViewBox
+{
+public:
+ SVGMarkerElement();
+ SVGMarkerElement(const SVGMarkerElement &other);
+ SVGMarkerElement &operator=(const SVGMarkerElement &other);
+ SVGMarkerElement(SVGMarkerElementImpl *other);
+ virtual ~SVGMarkerElement();
+
+ SVGAnimatedLength refX() const;
+ SVGAnimatedLength refY() const;
+ SVGAnimatedEnumeration markerUnits() const;
+ SVGAnimatedLength markerWidth() const;
+ SVGAnimatedLength markerHeight() const;
+ SVGAnimatedEnumeration orientType() const;
+ SVGAnimatedAngle orientAngle() const;
+
+ void setOrientToAuto();
+ void setOrientToAngle(const SVGAngle &angle);
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGMarkerElementImpl *handle() const { return impl; }
+
+private:
+ SVGMarkerElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGMaskElement.cc b/ksvg/dom/SVGMaskElement.cc
new file mode 100644
index 00000000..c4513adc
--- /dev/null
+++ b/ksvg/dom/SVGMaskElement.cc
@@ -0,0 +1,109 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGMaskElement.h"
+#include "SVGMaskElementImpl.h"
+#include "SVGAnimatedLength.h"
+#include "SVGAnimatedEnumeration.h"
+
+using namespace KSVG;
+
+SVGMaskElement::SVGMaskElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGUnitTypes()
+{
+ impl = 0;
+}
+
+SVGMaskElement::SVGMaskElement(const SVGMaskElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGUnitTypes(), impl(0)
+{
+ (*this) = other;
+}
+
+SVGMaskElement &SVGMaskElement::operator =(const SVGMaskElement &other)
+{
+ SVGElement::operator=(other);
+ SVGTests::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGMaskElement::SVGMaskElement(SVGMaskElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGUnitTypes()
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGMaskElement::~SVGMaskElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedEnumeration SVGMaskElement::maskUnits() const
+{
+ if(!impl) return SVGAnimatedEnumeration(0);
+ return SVGAnimatedEnumeration(impl->maskUnits());
+}
+
+SVGAnimatedEnumeration SVGMaskElement::maskContentUnits() const
+{
+ if(!impl) return SVGAnimatedEnumeration(0);
+ return SVGAnimatedEnumeration(impl->maskContentUnits());
+}
+
+SVGAnimatedLength SVGMaskElement::x() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->x());
+}
+
+SVGAnimatedLength SVGMaskElement::y() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->y());
+}
+
+SVGAnimatedLength SVGMaskElement::width() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->width());
+}
+
+SVGAnimatedLength SVGMaskElement::height() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->height());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGMaskElement.h b/ksvg/dom/SVGMaskElement.h
new file mode 100644
index 00000000..6a8e26a4
--- /dev/null
+++ b/ksvg/dom/SVGMaskElement.h
@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGMaskElement_H
+#define SVGMaskElement_H
+
+#include "SVGElement.h"
+#include "SVGTests.h"
+#include "SVGLangSpace.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+#include "SVGUnitTypes.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedEnumeration;
+class SVGAnimatedLength;
+class SVGMaskElementImpl;
+class SVGMaskElement : public SVGElement,
+ public SVGTests,
+ public SVGLangSpace,
+ public SVGExternalResourcesRequired,
+ public SVGStylable,
+ public SVGUnitTypes
+{
+public:
+ SVGMaskElement();
+ SVGMaskElement(const SVGMaskElement &other);
+ SVGMaskElement &operator=(const SVGMaskElement &other);
+ SVGMaskElement(SVGMaskElementImpl *other);
+ virtual ~SVGMaskElement();
+
+ SVGAnimatedEnumeration maskUnits() const;
+ SVGAnimatedEnumeration maskContentUnits() const;
+ SVGAnimatedLength x() const;
+ SVGAnimatedLength y() const;
+ SVGAnimatedLength width() const;
+ SVGAnimatedLength height() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGMaskElementImpl *handle() const { return impl; }
+
+private:
+ SVGMaskElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGMatrix.cc b/ksvg/dom/SVGMatrix.cc
new file mode 100644
index 00000000..30eeda56
--- /dev/null
+++ b/ksvg/dom/SVGMatrix.cc
@@ -0,0 +1,210 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGMatrixImpl.h"
+#include "SVGMatrix.h"
+
+using namespace KSVG;
+
+SVGMatrix::SVGMatrix()
+{
+ impl = new SVGMatrixImpl();
+ impl->ref();
+}
+
+SVGMatrix::SVGMatrix(double a, double b, double c, double d, double e, double f)
+{
+ impl = new SVGMatrixImpl(a, b, c, d, e, f);
+ impl->ref();
+}
+
+SVGMatrix::SVGMatrix(const SVGMatrix &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGMatrix &SVGMatrix::operator=(const SVGMatrix &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGMatrix::SVGMatrix(SVGMatrixImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGMatrix::~SVGMatrix()
+{
+ if(impl)
+ impl->deref();
+}
+
+void SVGMatrix::setA(const double &a)
+{
+ if(impl)
+ impl->setA(a);
+}
+
+double SVGMatrix::a() const
+{
+ if(!impl) return -1;
+ return impl->a();
+}
+
+void SVGMatrix::setB(const double &b)
+{
+ if(impl)
+ impl->setB(b);
+}
+
+double SVGMatrix::b() const
+{
+ if(!impl) return -1;
+ return impl->b();
+}
+
+void SVGMatrix::setC(const double &c)
+{
+ if(impl)
+ impl->setC(c);
+}
+
+double SVGMatrix::c() const
+{
+ if(!impl) return -1;
+ return impl->c();
+}
+
+void SVGMatrix::setD(const double &d)
+{
+ if(impl)
+ impl->setD(d);
+}
+
+double SVGMatrix::d() const
+{
+ if(!impl) return -1;
+ return impl->d();
+}
+
+void SVGMatrix::setE(const double &e)
+{
+ if(impl)
+ impl->setE(e);
+}
+
+double SVGMatrix::e() const
+{
+ if(!impl) return -1;
+ return impl->e();
+}
+
+void SVGMatrix::setF(const double &f)
+{
+ if(impl)
+ impl->setF(f);
+}
+
+double SVGMatrix::f() const
+{
+ if(!impl) return -1;
+ return impl->f();
+}
+
+SVGMatrix SVGMatrix::multiply(SVGMatrix &secondMatrix)
+{
+ if(!impl) return SVGMatrix(0);
+ return SVGMatrix(impl->multiply(secondMatrix.handle()));
+}
+
+SVGMatrix SVGMatrix::inverse()
+{
+ if(!impl) return SVGMatrix(0);
+ return SVGMatrix(impl->inverse());
+}
+
+SVGMatrix SVGMatrix::translate(const double &x, const double &y)
+{
+ if(!impl) return SVGMatrix(0);
+ return SVGMatrix(impl->translate(x, y));
+}
+
+SVGMatrix SVGMatrix::scale(const double &scaleFactor)
+{
+ if(!impl) return SVGMatrix(0);
+ return SVGMatrix(impl->scale(scaleFactor));
+}
+
+SVGMatrix SVGMatrix::scaleNonUniform(const double &scaleFactorX, const double &scaleFactorY)
+{
+ if(!impl) return SVGMatrix(0);
+ return SVGMatrix(impl->scaleNonUniform(scaleFactorX, scaleFactorY));
+}
+
+SVGMatrix SVGMatrix::rotate(const double &angle)
+{
+ if(!impl) return SVGMatrix(0);
+ return SVGMatrix(impl->rotate(angle));
+}
+
+SVGMatrix SVGMatrix::rotateFromVector(const double &x, const double &y)
+{
+ if(!impl) return SVGMatrix(0);
+ return SVGMatrix(impl->rotateFromVector(x, y));
+}
+
+SVGMatrix SVGMatrix::flipX()
+{
+ if(!impl) return SVGMatrix(0);
+ return SVGMatrix(impl->flipX());
+}
+
+SVGMatrix SVGMatrix::flipY()
+{
+ if(!impl) return SVGMatrix(0);
+ return SVGMatrix(impl->flipY());
+}
+
+SVGMatrix SVGMatrix::skewX(const double &angle)
+{
+ if(!impl) return SVGMatrix(0);
+ return SVGMatrix(impl->skewX(angle));
+}
+
+SVGMatrix SVGMatrix::skewY(const double &angle)
+{
+ if(!impl) return SVGMatrix(0);
+ return SVGMatrix(impl->skewY(angle));
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGMatrix.h b/ksvg/dom/SVGMatrix.h
new file mode 100644
index 00000000..caf2b9a8
--- /dev/null
+++ b/ksvg/dom/SVGMatrix.h
@@ -0,0 +1,79 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGMatrix_H
+#define SVGMatrix_H
+
+namespace KSVG
+{
+
+class SVGMatrixImpl;
+class SVGMatrix
+{
+public:
+ SVGMatrix();
+ SVGMatrix(double, double, double, double, double, double);
+ SVGMatrix(const SVGMatrix &);
+ SVGMatrix &operator=(const SVGMatrix &);
+ SVGMatrix(SVGMatrixImpl *);
+ ~SVGMatrix();
+
+ void setA(const double &);
+ double a() const;
+
+ void setB(const double &);
+ double b() const;
+
+ void setC(const double &);
+ double c() const;
+
+ void setD(const double &);
+ double d() const;
+
+ void setE(const double &);
+ double e() const;
+
+ void setF(const double &);
+ double f() const;
+
+ SVGMatrix multiply(SVGMatrix &secondMatrix);
+ SVGMatrix inverse();
+ SVGMatrix translate(const double &x, const double &y);
+ SVGMatrix scale(const double &scaleFactor);
+ SVGMatrix scaleNonUniform(const double &scaleFactorX, const double &scaleFactorY);
+ SVGMatrix rotate(const double &angle);
+ SVGMatrix rotateFromVector(const double &x, const double &y);
+ SVGMatrix flipX();
+ SVGMatrix flipY();
+ SVGMatrix skewX(const double &angle);
+ SVGMatrix skewY(const double &angle);
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGMatrixImpl *handle() const { return impl; }
+
+private:
+ SVGMatrixImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGMetadataElement.cc b/ksvg/dom/SVGMetadataElement.cc
new file mode 100644
index 00000000..e874e95c
--- /dev/null
+++ b/ksvg/dom/SVGMetadataElement.cc
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGMetadataElement.h"
+#include "SVGMetadataElementImpl.h"
+
+using namespace KSVG;
+
+SVGMetadataElement::SVGMetadataElement() : SVGElement()
+{
+ impl = 0;
+}
+
+SVGMetadataElement::SVGMetadataElement(const SVGMetadataElement &other) : SVGElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGMetadataElement &SVGMetadataElement::operator =(const SVGMetadataElement &other)
+{
+ SVGElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGMetadataElement::SVGMetadataElement(SVGMetadataElementImpl *other) : SVGElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGMetadataElement::~SVGMetadataElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGMetadataElement.h b/ksvg/dom/SVGMetadataElement.h
new file mode 100644
index 00000000..703e48a6
--- /dev/null
+++ b/ksvg/dom/SVGMetadataElement.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGMetadataElement_H
+#define SVGMetadataElement_H
+
+#include "SVGElement.h"
+
+namespace KSVG
+{
+
+class SVGMetadataElementImpl;
+class SVGMetadataElement : public SVGElement
+{
+public:
+ SVGMetadataElement();
+ SVGMetadataElement(const SVGMetadataElement &other);
+ SVGMetadataElement &operator=(const SVGMetadataElement &other);
+ SVGMetadataElement(SVGMetadataElementImpl *other);
+ virtual ~SVGMetadataElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGMetadataElementImpl *handle() const { return impl; }
+
+private:
+ SVGMetadataElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGMissingGlyphElement.cc b/ksvg/dom/SVGMissingGlyphElement.cc
new file mode 100644
index 00000000..d9bff554
--- /dev/null
+++ b/ksvg/dom/SVGMissingGlyphElement.cc
@@ -0,0 +1,68 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGMissingGlyphElement.h"
+#include "SVGMissingGlyphElementImpl.h"
+
+using namespace KSVG;
+
+SVGMissingGlyphElement::SVGMissingGlyphElement() : SVGElement(), SVGStylable()
+{
+ impl = 0;
+}
+
+SVGMissingGlyphElement::SVGMissingGlyphElement(const SVGMissingGlyphElement &other) : SVGElement(other), SVGStylable(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGMissingGlyphElement &SVGMissingGlyphElement::operator =(const SVGMissingGlyphElement &other)
+{
+ SVGElement::operator=(other);
+ SVGStylable::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGMissingGlyphElement::SVGMissingGlyphElement(SVGMissingGlyphElementImpl *other) : SVGElement(other), SVGStylable(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGMissingGlyphElement::~SVGMissingGlyphElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGMissingGlyphElement.h b/ksvg/dom/SVGMissingGlyphElement.h
new file mode 100644
index 00000000..5b7e6f62
--- /dev/null
+++ b/ksvg/dom/SVGMissingGlyphElement.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGMissingGlyphElement_H
+#define SVGMissingGlyphElement_H
+
+#include "SVGElement.h"
+#include "SVGStylable.h"
+
+namespace KSVG
+{
+
+class SVGMissingGlyphElementImpl;
+class SVGMissingGlyphElement : public SVGElement,
+ public SVGStylable
+{
+public:
+ SVGMissingGlyphElement();
+ SVGMissingGlyphElement(const SVGMissingGlyphElement &other);
+ SVGMissingGlyphElement &operator=(const SVGMissingGlyphElement &other);
+ SVGMissingGlyphElement(SVGMissingGlyphElementImpl *other);
+ virtual ~SVGMissingGlyphElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGMissingGlyphElementImpl *handle() const { return impl; }
+
+private:
+ SVGMissingGlyphElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGNumber.cc b/ksvg/dom/SVGNumber.cc
new file mode 100644
index 00000000..81208987
--- /dev/null
+++ b/ksvg/dom/SVGNumber.cc
@@ -0,0 +1,78 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGNumber.h"
+#include "SVGNumberImpl.h"
+
+using namespace KSVG;
+
+SVGNumber::SVGNumber()
+{
+ impl = new SVGNumberImpl();
+ impl->ref();
+}
+
+SVGNumber::SVGNumber(const SVGNumber &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGNumber &SVGNumber::operator=(const SVGNumber &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGNumber::SVGNumber(SVGNumberImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGNumber::~SVGNumber()
+{
+ if(impl)
+ impl->deref();
+}
+
+void SVGNumber::setValue(float value)
+{
+ if(impl)
+ impl->setValue(value);
+}
+
+float SVGNumber::value() const
+{
+ if(!impl) return -1;
+ return impl->value();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGNumber.h b/ksvg/dom/SVGNumber.h
new file mode 100644
index 00000000..d3efbe42
--- /dev/null
+++ b/ksvg/dom/SVGNumber.h
@@ -0,0 +1,51 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGNumber_H
+#define SVGNumber_H
+
+namespace KSVG
+{
+
+class SVGNumberImpl;
+class SVGNumber
+{
+public:
+ SVGNumber();
+ SVGNumber(const SVGNumber &);
+ SVGNumber &operator=(const SVGNumber &);
+ SVGNumber(SVGNumberImpl *);
+ ~SVGNumber();
+
+ void setValue(float value);
+ float value() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGNumberImpl *handle() const { return impl; }
+
+private:
+ SVGNumberImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGNumberList.cc b/ksvg/dom/SVGNumberList.cc
new file mode 100644
index 00000000..92adec50
--- /dev/null
+++ b/ksvg/dom/SVGNumberList.cc
@@ -0,0 +1,115 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGNumberList.h"
+#include "SVGNumberListImpl.h"
+#include "SVGNumber.h"
+
+using namespace KSVG;
+
+SVGNumberList::SVGNumberList()
+{
+ impl = new SVGNumberListImpl();
+ impl->ref();
+}
+
+SVGNumberList::SVGNumberList(const SVGNumberList &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGNumberList &SVGNumberList::operator=(const SVGNumberList &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGNumberList::SVGNumberList(SVGNumberListImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGNumberList::~SVGNumberList()
+{
+ if(impl)
+ impl->deref();
+}
+
+unsigned long SVGNumberList::numberOfItems() const
+{
+ if(!impl) return 0;
+ return impl->numberOfItems();
+}
+
+void SVGNumberList::clear()
+{
+ if(impl)
+ impl->clear();
+}
+
+SVGNumber *SVGNumberList::initialize(SVGNumber *newItem)
+{
+ if(!impl) return new SVGNumber(0);
+ return new SVGNumber(impl->initialize(newItem->handle()));
+}
+
+SVGNumber *SVGNumberList::getItem(unsigned long index)
+{
+ if(!impl) return new SVGNumber(0);
+ return new SVGNumber(impl->getItem(index));
+}
+
+SVGNumber *SVGNumberList::insertItemBefore(SVGNumber *newItem, unsigned long index)
+{
+ if(!impl) return new SVGNumber(0);
+ return new SVGNumber(impl->insertItemBefore(newItem->handle(), index));
+}
+
+SVGNumber *SVGNumberList::replaceItem(SVGNumber *newItem, unsigned long index)
+{
+ if(!impl) return new SVGNumber(0);
+ return new SVGNumber(impl->replaceItem(newItem->handle(), index));
+}
+
+SVGNumber *SVGNumberList::removeItem(unsigned long index)
+{
+ if(!impl) return new SVGNumber(0);
+ return new SVGNumber(impl->removeItem(index));
+}
+
+SVGNumber *SVGNumberList::appendItem(SVGNumber *newItem)
+{
+ if(!impl) return new SVGNumber(0);
+ return new SVGNumber(impl->appendItem(newItem->handle()));
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGNumberList.h b/ksvg/dom/SVGNumberList.h
new file mode 100644
index 00000000..920574d7
--- /dev/null
+++ b/ksvg/dom/SVGNumberList.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGNumberList_H
+#define SVGNumberList_H
+
+namespace KSVG
+{
+
+class SVGNumber;
+class SVGNumberListImpl;
+class SVGNumberList
+{
+public:
+ SVGNumberList();
+ SVGNumberList(const SVGNumberList &);
+ SVGNumberList &operator=(const SVGNumberList &);
+ SVGNumberList(SVGNumberListImpl *);
+ ~SVGNumberList();
+
+ unsigned long numberOfItems() const;
+ void clear();
+ SVGNumber *initialize(SVGNumber *newItem);
+ SVGNumber *getItem(unsigned long index);
+ SVGNumber *insertItemBefore(SVGNumber *newItem, unsigned long index);
+ SVGNumber *replaceItem(SVGNumber *newItem, unsigned long index);
+ SVGNumber *removeItem(unsigned long index);
+ SVGNumber *appendItem(SVGNumber *newItem);
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGNumberListImpl *handle() const { return impl; }
+
+private:
+ SVGNumberListImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPaint.cc b/ksvg/dom/SVGPaint.cc
new file mode 100644
index 00000000..7e7051d5
--- /dev/null
+++ b/ksvg/dom/SVGPaint.cc
@@ -0,0 +1,93 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGPaint.h"
+#include "SVGPaintImpl.h"
+
+using namespace KSVG;
+
+SVGPaint::SVGPaint() : SVGColor()
+{
+ // FIXME: no icc color support...
+ impl = new SVGPaintImpl(0);
+ impl->ref();
+}
+
+SVGPaint::SVGPaint(const SVGPaint &other) : SVGColor(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGPaint &SVGPaint::operator =(const SVGPaint &other)
+{
+ SVGColor::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGPaint::SVGPaint(SVGPaintImpl *other) : SVGColor(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGPaint::~SVGPaint()
+{
+ if(impl)
+ impl->deref();
+}
+
+unsigned short SVGPaint::paintType() const
+{
+ if(!impl) return SVG_PAINTTYPE_UNKNOWN;
+ return impl->paintType();
+}
+
+DOM::DOMString SVGPaint::uri() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->uri();
+}
+
+void SVGPaint::setUri(const DOM::DOMString &uri)
+{
+ if(impl)
+ impl->setUri(uri);
+}
+
+void SVGPaint::setPaint(unsigned short paintType, const DOM::DOMString &uri, const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor)
+{
+ if(impl)
+ impl->setPaint(paintType, uri, rgbColor, iccColor);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPaint.h b/ksvg/dom/SVGPaint.h
new file mode 100644
index 00000000..84f331fb
--- /dev/null
+++ b/ksvg/dom/SVGPaint.h
@@ -0,0 +1,70 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPaint_H
+#define SVGPaint_H
+
+#include "SVGColor.h"
+#include <dom/dom_string.h>
+
+namespace KSVG
+{
+
+enum
+{
+ SVG_PAINTTYPE_UNKNOWN = 0,
+ SVG_PAINTTYPE_RGBCOLOR = 1,
+ SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR = 2,
+ SVG_PAINTTYPE_NONE = 101,
+ SVG_PAINTTYPE_CURRENTCOLOR = 102,
+ SVG_PAINTTYPE_URI_NONE = 103,
+ SVG_PAINTTYPE_URI_CURRENTCOLOR = 104,
+ SVG_PAINTTYPE_URI_RGBCOLOR = 105,
+ SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR = 106,
+ SVG_PAINTTYPE_URI = 107
+};
+
+class SVGPaintImpl;
+class SVGPaint : public SVGColor
+{
+public:
+ SVGPaint();
+ SVGPaint(const SVGPaint &other);
+ SVGPaint &operator=(const SVGPaint &other);
+ SVGPaint(SVGPaintImpl *other);
+ virtual ~SVGPaint();
+
+ unsigned short paintType() const;
+ DOM::DOMString uri() const;
+ void setUri(const DOM::DOMString &uri);
+ void setPaint(unsigned short paintType, const DOM::DOMString &uri, const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor);
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPaintImpl *handle() const { return impl; }
+
+private:
+ SVGPaintImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathElement.cc b/ksvg/dom/SVGPathElement.cc
new file mode 100644
index 00000000..1153cf65
--- /dev/null
+++ b/ksvg/dom/SVGPathElement.cc
@@ -0,0 +1,200 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGPathElement.h"
+#include "SVGPathElementImpl.h"
+#include "SVGPoint.h"
+#include "SVGPathSegClosePath.h"
+#include "SVGPathSegLineto.h"
+#include "SVGPathSegLinetoHorizontal.h"
+#include "SVGPathSegLinetoVertical.h"
+#include "SVGPathSegMoveto.h"
+#include "SVGPathSegArc.h"
+#include "SVGPathSegCurvetoCubic.h"
+#include "SVGPathSegCurvetoCubicSmooth.h"
+#include "SVGPathSegCurvetoQuadratic.h"
+#include "SVGPathSegCurvetoQuadraticSmooth.h"
+
+using namespace KSVG;
+
+SVGPathElement::SVGPathElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable(), SVGAnimatedPathData()
+{
+ impl = 0;
+}
+
+SVGPathElement::SVGPathElement(const SVGPathElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), SVGAnimatedPathData(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGPathElement &SVGPathElement::operator=(const SVGPathElement &other)
+{
+ SVGElement::operator=(other);
+ SVGTests::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+ SVGTransformable::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGPathElement::SVGPathElement(SVGPathElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), SVGAnimatedPathData(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGPathElement::~SVGPathElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+/*
+SVGAnimatedNumber SVGPathElement::pathLength() const
+{
+ return m_pathLength;
+}
+*/
+
+float SVGPathElement::getTotalLength()
+{
+ return impl->getTotalLength();
+}
+
+SVGPoint SVGPathElement::getPointAtLength(float distance)
+{
+ return SVGPoint(impl->getPointAtLength(distance));
+}
+
+unsigned long SVGPathElement::getPathSegAtLength(float distance)
+{
+ return impl->getPathSegAtLength(distance);
+}
+
+SVGPathSegClosePath SVGPathElement::createSVGPathSegClosePath()
+{
+ return impl->createSVGPathSegClosePath();
+}
+
+SVGPathSegMovetoAbs SVGPathElement::createSVGPathSegMovetoAbs(float x,float y)
+{
+ return impl->createSVGPathSegMovetoAbs(x, y);;
+}
+
+SVGPathSegMovetoRel SVGPathElement::createSVGPathSegMovetoRel(float x,float y)
+{
+ return impl->createSVGPathSegMovetoRel(x, y);
+}
+
+SVGPathSegLinetoAbs SVGPathElement::createSVGPathSegLinetoAbs(float x,float y)
+{
+ return impl->createSVGPathSegLinetoAbs(x, y);
+}
+
+SVGPathSegLinetoRel SVGPathElement::createSVGPathSegLinetoRel(float x,float y)
+{
+ return impl->createSVGPathSegLinetoRel(x, y);
+}
+
+SVGPathSegCurvetoCubicAbs SVGPathElement::createSVGPathSegCurvetoCubicAbs(float x,float y,float x1,float y1,float x2,float y2)
+{
+ return impl->createSVGPathSegCurvetoCubicAbs(x, y, x1, y1, x2, y2);
+}
+
+SVGPathSegCurvetoCubicRel SVGPathElement::createSVGPathSegCurvetoCubicRel(float x,float y,float x1,float y1,float x2,float y2)
+{
+ return impl->createSVGPathSegCurvetoCubicRel(x, y, x1, y1, x2, y2);
+}
+
+SVGPathSegCurvetoQuadraticAbs SVGPathElement::createSVGPathSegCurvetoQuadraticAbs(float x,float y,float x1,float y1)
+{
+ return impl->createSVGPathSegCurvetoQuadraticAbs(x, y, x1, y1);
+}
+
+SVGPathSegCurvetoQuadraticRel SVGPathElement::createSVGPathSegCurvetoQuadraticRel(float x,float y,float x1,float y1)
+{
+ return impl->createSVGPathSegCurvetoQuadraticRel(x, y, x1, y1);
+}
+
+SVGPathSegArcAbs SVGPathElement::createSVGPathSegArcAbs(float x,float y,float r1,float r2,float angle,bool largeArcFlag,bool sweepFlag)
+{
+ return impl->createSVGPathSegArcAbs(x, y, r1, r2, angle, largeArcFlag, sweepFlag);
+}
+
+SVGPathSegArcRel SVGPathElement::createSVGPathSegArcRel(float x,float y,float r1,float r2,float angle,bool largeArcFlag,bool sweepFlag)
+{
+ return impl->createSVGPathSegArcRel(x, y, r1, r2, angle, largeArcFlag, sweepFlag);
+}
+
+SVGPathSegLinetoHorizontalAbs SVGPathElement::createSVGPathSegLinetoHorizontalAbs(float x)
+{
+ return impl->createSVGPathSegLinetoHorizontalAbs(x);
+}
+
+SVGPathSegLinetoHorizontalRel SVGPathElement::createSVGPathSegLinetoHorizontalRel(float x)
+{
+ return impl->createSVGPathSegLinetoHorizontalRel(x);
+}
+
+SVGPathSegLinetoVerticalAbs SVGPathElement::createSVGPathSegLinetoVerticalAbs(float y)
+{
+ return impl->createSVGPathSegLinetoVerticalAbs(y);
+}
+
+SVGPathSegLinetoVerticalRel SVGPathElement::createSVGPathSegLinetoVerticalRel(float y)
+{
+ return impl->createSVGPathSegLinetoVerticalRel(y);
+}
+
+SVGPathSegCurvetoCubicSmoothAbs SVGPathElement::createSVGPathSegCurvetoCubicSmoothAbs(float x,float y,float x2,float y2)
+{
+ return impl->createSVGPathSegCurvetoCubicSmoothAbs(x, y, x2, y2);;
+}
+
+SVGPathSegCurvetoCubicSmoothRel SVGPathElement::createSVGPathSegCurvetoCubicSmoothRel(float x,float y,float x2,float y2)
+{
+ return impl->createSVGPathSegCurvetoCubicSmoothRel(x, y, x2, y2);
+}
+
+SVGPathSegCurvetoQuadraticSmoothAbs SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothAbs(float x,float y)
+{
+ return impl->createSVGPathSegCurvetoQuadraticSmoothAbs(x, y);
+}
+
+SVGPathSegCurvetoQuadraticSmoothRel SVGPathElement::createSVGPathSegCurvetoQuadraticSmoothRel(float x,float y)
+{
+ return impl->createSVGPathSegCurvetoQuadraticSmoothRel(x, y);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathElement.h b/ksvg/dom/SVGPathElement.h
new file mode 100644
index 00000000..fa4cb379
--- /dev/null
+++ b/ksvg/dom/SVGPathElement.h
@@ -0,0 +1,107 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathElement_H
+#define SVGPathElement_H
+
+#include "SVGElement.h"
+#include "SVGTests.h"
+#include "SVGLangSpace.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+#include "SVGTransformable.h"
+#include "SVGAnimatedPathData.h"
+
+namespace KSVG
+{
+
+class SVGPoint;
+class SVGPathSegClosePath;
+class SVGPathSegLinetoAbs;
+class SVGPathSegLinetoRel;
+class SVGPathSegLinetoHorizontalAbs;
+class SVGPathSegLinetoHorizontalRel;
+class SVGPathSegLinetoVerticalAbs;
+class SVGPathSegLinetoVerticalRel;
+class SVGPathSegMovetoAbs;
+class SVGPathSegMovetoRel;
+class SVGPathSegArcAbs;
+class SVGPathSegArcRel;
+class SVGPathSegCurvetoCubicAbs;
+class SVGPathSegCurvetoCubicRel;
+class SVGPathSegCurvetoCubicSmoothAbs;
+class SVGPathSegCurvetoCubicSmoothRel;
+class SVGPathSegCurvetoQuadraticAbs;
+class SVGPathSegCurvetoQuadraticRel;
+class SVGPathSegCurvetoQuadraticSmoothAbs;
+class SVGPathSegCurvetoQuadraticSmoothRel;
+class SVGPathElementImpl;
+class SVGPathElement : public SVGElement,
+ public SVGTests,
+ public SVGLangSpace,
+ public SVGExternalResourcesRequired,
+ public SVGStylable,
+ public SVGTransformable,
+ public SVGAnimatedPathData
+{
+public:
+ SVGPathElement();
+ SVGPathElement(const SVGPathElement &);
+ SVGPathElement &operator=(const SVGPathElement &other);
+ SVGPathElement(SVGPathElementImpl *);
+ ~SVGPathElement();
+
+ //SVGAnimatedNumber pathLength() const;
+ float getTotalLength();
+ SVGPoint getPointAtLength(float distance);
+ unsigned long getPathSegAtLength(float distance);
+
+ SVGPathSegClosePath createSVGPathSegClosePath();
+ SVGPathSegMovetoAbs createSVGPathSegMovetoAbs(float x,float y);
+ SVGPathSegMovetoRel createSVGPathSegMovetoRel(float x,float y);
+ SVGPathSegLinetoAbs createSVGPathSegLinetoAbs(float x,float y);
+ SVGPathSegLinetoRel createSVGPathSegLinetoRel(float x,float y);
+ SVGPathSegCurvetoCubicAbs createSVGPathSegCurvetoCubicAbs(float x,float y,float x1,float y1,float x2,float y2);
+ SVGPathSegCurvetoCubicRel createSVGPathSegCurvetoCubicRel(float x,float y,float x1,float y1,float x2,float y2);
+ SVGPathSegCurvetoQuadraticAbs createSVGPathSegCurvetoQuadraticAbs(float x,float y,float x1,float y1);
+ SVGPathSegCurvetoQuadraticRel createSVGPathSegCurvetoQuadraticRel(float x,float y,float x1,float y1);
+ SVGPathSegArcAbs createSVGPathSegArcAbs(float x,float y,float r1,float r2,float angle,bool largeArcFlag,bool sweepFlag);
+ SVGPathSegArcRel createSVGPathSegArcRel(float x,float y,float r1,float r2,float angle,bool largeArcFlag,bool sweepFlag);
+ SVGPathSegLinetoHorizontalAbs createSVGPathSegLinetoHorizontalAbs(float x);
+ SVGPathSegLinetoHorizontalRel createSVGPathSegLinetoHorizontalRel(float x);
+ SVGPathSegLinetoVerticalAbs createSVGPathSegLinetoVerticalAbs(float y);
+ SVGPathSegLinetoVerticalRel createSVGPathSegLinetoVerticalRel(float y);
+ SVGPathSegCurvetoCubicSmoothAbs createSVGPathSegCurvetoCubicSmoothAbs(float x,float y,float x2,float y2);
+ SVGPathSegCurvetoCubicSmoothRel createSVGPathSegCurvetoCubicSmoothRel(float x,float y,float x2,float y2);
+ SVGPathSegCurvetoQuadraticSmoothAbs createSVGPathSegCurvetoQuadraticSmoothAbs(float x,float y);
+ SVGPathSegCurvetoQuadraticSmoothRel createSVGPathSegCurvetoQuadraticSmoothRel(float x,float y);
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPathElementImpl *handle() const { return impl; }
+
+private:
+ SVGPathElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathSeg.cc b/ksvg/dom/SVGPathSeg.cc
new file mode 100644
index 00000000..3fc31148
--- /dev/null
+++ b/ksvg/dom/SVGPathSeg.cc
@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGPathSeg.h"
+#include "SVGPathSegImpl.h"
+
+using namespace KSVG;
+
+SVGPathSeg::SVGPathSeg()
+{
+ impl = new SVGPathSegImpl();
+}
+
+SVGPathSeg::SVGPathSeg(const SVGPathSeg &other)
+{
+ impl = other.impl;
+}
+
+SVGPathSeg &SVGPathSeg::operator=(const SVGPathSeg &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ delete impl;
+ impl = other.impl;
+
+ return *this;
+}
+
+SVGPathSeg::SVGPathSeg(SVGPathSegImpl *other)
+{
+ impl = other;
+}
+
+SVGPathSeg::~SVGPathSeg()
+{
+ delete impl;
+}
+
+unsigned short SVGPathSeg::pathSegType() const
+{
+ if(!impl) return PATHSEG_UNKNOWN;
+ return impl->pathSegType();
+}
+
+DOM::DOMString SVGPathSeg::pathSegTypeAsLetter() const
+{
+ if(!impl) return DOM::DOMString("");
+ return impl->pathSegTypeAsLetter();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathSeg.h b/ksvg/dom/SVGPathSeg.h
new file mode 100644
index 00000000..f82e3c80
--- /dev/null
+++ b/ksvg/dom/SVGPathSeg.h
@@ -0,0 +1,76 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+#ifndef SVGPathSeg_H
+#define SVGPathSeg_H
+
+#include <dom/dom_string.h>
+
+namespace KSVG
+{
+
+enum
+{
+ PATHSEG_UNKNOWN = 0,
+ PATHSEG_CLOSEPATH = 1,
+ PATHSEG_MOVETO_ABS = 2,
+ PATHSEG_MOVETO_REL = 3,
+ PATHSEG_LINETO_ABS = 4,
+ PATHSEG_LINETO_REL = 5,
+ PATHSEG_CURVETO_CUBIC_ABS = 6,
+ PATHSEG_CURVETO_CUBIC_REL = 7,
+ PATHSEG_CURVETO_QUADRATIC_ABS = 8,
+ PATHSEG_CURVETO_QUADRATIC_REL = 9,
+ PATHSEG_ARC_ABS = 10,
+ PATHSEG_ARC_REL = 11,
+ PATHSEG_LINETO_HORIZONTAL_ABS = 12,
+ PATHSEG_LINETO_HORIZONTAL_REL = 13,
+ PATHSEG_LINETO_VERTICAL_ABS = 14,
+ PATHSEG_LINETO_VERTICAL_REL = 15,
+ PATHSEG_CURVETO_CUBIC_SMOOTH_ABS = 16,
+ PATHSEG_CURVETO_CUBIC_SMOOTH_REL = 17,
+ PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS = 18,
+ PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL = 19
+};
+
+class SVGPathSegImpl;
+class SVGPathSeg
+{
+public:
+ SVGPathSeg();
+ SVGPathSeg(const SVGPathSeg &);
+ SVGPathSeg &operator=(const SVGPathSeg &other);
+ SVGPathSeg(SVGPathSegImpl *);
+ ~SVGPathSeg();
+
+ unsigned short pathSegType() const;
+ DOM::DOMString pathSegTypeAsLetter() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPathSegImpl *handle() const { return impl; }
+
+private:
+ SVGPathSegImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathSegArc.cc b/ksvg/dom/SVGPathSegArc.cc
new file mode 100644
index 00000000..078137ab
--- /dev/null
+++ b/ksvg/dom/SVGPathSegArc.cc
@@ -0,0 +1,238 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGPathSegArc.h"
+#include "SVGPathSegArcImpl.h"
+
+using namespace KSVG;
+
+SVGPathSegArcAbs::SVGPathSegArcAbs() : SVGPathSeg()
+{
+ impl = new SVGPathSegArcAbsImpl();
+}
+
+SVGPathSegArcAbs::SVGPathSegArcAbs(const SVGPathSegArcAbs &other) : SVGPathSeg(other)
+{
+ impl = other.impl;
+}
+
+SVGPathSegArcAbs::SVGPathSegArcAbs(SVGPathSegArcAbsImpl *other) : SVGPathSeg(other)
+{
+ impl = other;
+}
+
+SVGPathSegArcAbs::~SVGPathSegArcAbs()
+{
+ delete impl;
+}
+
+void SVGPathSegArcAbs::setX(const float &x)
+{
+ if(impl)
+ impl->setX(x);
+}
+
+float SVGPathSegArcAbs::x() const
+{
+ if(!impl) return -1;
+ return impl->x();
+}
+
+void SVGPathSegArcAbs::setY(const float &y)
+{
+ if(impl)
+ impl->setY(y);
+}
+
+float SVGPathSegArcAbs::y() const
+{
+ if(!impl) return -1;
+ return impl->y();
+}
+
+void SVGPathSegArcAbs::setR1(const float &r1)
+{
+ if(impl)
+ impl->setR1(r1);
+}
+
+float SVGPathSegArcAbs::r1() const
+{
+ if(!impl) return -1;
+ return impl->r1();
+}
+
+void SVGPathSegArcAbs::setR2(const float &r2)
+{
+ if(impl)
+ impl->setR2(r2);
+}
+
+float SVGPathSegArcAbs::r2() const
+{
+ if(!impl) return -1;
+ return impl->r2();
+}
+
+void SVGPathSegArcAbs::setAngle(const float &angle)
+{
+ if(impl)
+ impl->setAngle(angle);
+}
+
+float SVGPathSegArcAbs::angle() const
+{
+ if(!impl) return -1;
+ return impl->angle();
+}
+
+void SVGPathSegArcAbs::setLargeArcFlag(bool largeArcFlag)
+{
+ if(impl)
+ impl->setLargeArcFlag(largeArcFlag);
+}
+
+bool SVGPathSegArcAbs::largeArcFlag() const
+{
+ if(!impl) return false;
+ return impl->largeArcFlag();
+}
+
+void SVGPathSegArcAbs::setSweepFlag(bool sweepFlag)
+{
+ if(impl)
+ impl->setSweepFlag(sweepFlag);
+}
+
+bool SVGPathSegArcAbs::sweepFlag() const
+{
+ if(!impl) return false;
+ return impl->sweepFlag();
+}
+
+
+
+
+
+SVGPathSegArcRel::SVGPathSegArcRel() : SVGPathSeg()
+{
+ impl = new SVGPathSegArcRelImpl();
+}
+
+SVGPathSegArcRel::SVGPathSegArcRel(const SVGPathSegArcRel &other) : SVGPathSeg(other)
+{
+ impl = other.impl;
+}
+
+SVGPathSegArcRel::SVGPathSegArcRel(SVGPathSegArcRelImpl *other) : SVGPathSeg(other)
+{
+ impl = other;
+}
+
+SVGPathSegArcRel::~SVGPathSegArcRel()
+{
+ delete impl;
+}
+
+void SVGPathSegArcRel::setX(const float &x)
+{
+ if(impl)
+ impl->setX(x);
+}
+
+float SVGPathSegArcRel::x() const
+{
+ if(!impl) return -1;
+ return impl->x();
+}
+
+void SVGPathSegArcRel::setY(const float &y)
+{
+ if(impl)
+ impl->setY(y);
+}
+
+float SVGPathSegArcRel::y() const
+{
+ if(!impl) return -1;
+ return impl->y();
+}
+
+void SVGPathSegArcRel::setR1(const float &r1)
+{
+ if(impl)
+ impl->setR1(r1);
+}
+
+float SVGPathSegArcRel::r1() const
+{
+ if(!impl) return -1;
+ return impl->r1();
+}
+
+void SVGPathSegArcRel::setR2(const float &r2)
+{
+ if(impl)
+ impl->setR2(r2);
+}
+
+float SVGPathSegArcRel::r2() const
+{
+ if(!impl) return -1;
+ return impl->r2();
+}
+
+void SVGPathSegArcRel::setAngle(const float &angle)
+{
+ if(impl)
+ impl->setAngle(angle);
+}
+
+float SVGPathSegArcRel::angle() const
+{
+ if(!impl) return -1;
+ return impl->angle();
+}
+
+void SVGPathSegArcRel::setLargeArcFlag(bool largeArcFlag)
+{
+ if(impl)
+ impl->setLargeArcFlag(largeArcFlag);
+}
+
+bool SVGPathSegArcRel::largeArcFlag() const
+{
+ if(!impl) return false;
+ return impl->largeArcFlag();
+}
+
+void SVGPathSegArcRel::setSweepFlag(bool sweepFlag)
+{
+ if(impl)
+ impl->setSweepFlag(sweepFlag);
+}
+
+bool SVGPathSegArcRel::sweepFlag() const
+{
+ if(!impl) return false;
+ return impl->sweepFlag();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathSegArc.h b/ksvg/dom/SVGPathSegArc.h
new file mode 100644
index 00000000..e9b83786
--- /dev/null
+++ b/ksvg/dom/SVGPathSegArc.h
@@ -0,0 +1,109 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathSegArc_H
+#define SVGPathSegArc_H
+
+#include "SVGPathSeg.h"
+
+namespace KSVG
+{
+
+class SVGPathSegArcAbsImpl;
+class SVGPathSegArcAbs : public SVGPathSeg
+{
+public:
+ SVGPathSegArcAbs();
+ SVGPathSegArcAbs(const SVGPathSegArcAbs &);
+ SVGPathSegArcAbs &operator=(const SVGPathSegArcAbs &other);
+ SVGPathSegArcAbs(SVGPathSegArcAbsImpl *);
+ ~SVGPathSegArcAbs();
+
+ void setX(const float &);
+ float x() const;
+
+ void setY(const float &);
+ float y() const;
+
+ void setR1(const float &);
+ float r1() const;
+
+ void setR2(const float &);
+ float r2() const;
+
+ void setAngle(const float &);
+ float angle() const;
+
+ void setLargeArcFlag(bool);
+ bool largeArcFlag() const;
+
+ void setSweepFlag(bool);
+ bool sweepFlag() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPathSegArcAbsImpl *handle() const { return impl; }
+
+private:
+ SVGPathSegArcAbsImpl *impl;
+};
+
+class SVGPathSegArcRelImpl;
+class SVGPathSegArcRel : public SVGPathSeg
+{
+public:
+ SVGPathSegArcRel();
+ SVGPathSegArcRel(const SVGPathSegArcRel &);
+ SVGPathSegArcRel &operator=(const SVGPathSegArcRel &other);
+ SVGPathSegArcRel(SVGPathSegArcRelImpl *);
+ ~SVGPathSegArcRel();
+
+ void setX(const float &);
+ float x() const;
+
+ void setY(const float &);
+ float y() const;
+
+ void setR1(const float &);
+ float r1() const;
+
+ void setR2(const float &);
+ float r2() const;
+
+ void setAngle(const float &);
+ float angle() const;
+
+ void setLargeArcFlag(bool);
+ bool largeArcFlag() const;
+
+ void setSweepFlag(bool);
+ bool sweepFlag() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPathSegArcRelImpl *handle() const { return impl; }
+
+private:
+ SVGPathSegArcRelImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathSegClosePath.cc b/ksvg/dom/SVGPathSegClosePath.cc
new file mode 100644
index 00000000..d9f33877
--- /dev/null
+++ b/ksvg/dom/SVGPathSegClosePath.cc
@@ -0,0 +1,46 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGPathSegClosePath.h"
+#include "SVGPathSegClosePathImpl.h"
+
+using namespace KSVG;
+
+SVGPathSegClosePath::SVGPathSegClosePath() : SVGPathSeg()
+{
+ impl = new SVGPathSegClosePathImpl();
+}
+
+SVGPathSegClosePath::SVGPathSegClosePath(const SVGPathSegClosePath &other) : SVGPathSeg(other)
+{
+ impl = other.impl;
+}
+
+SVGPathSegClosePath::SVGPathSegClosePath(SVGPathSegClosePathImpl *other) : SVGPathSeg(other)
+{
+ impl = other;
+}
+
+SVGPathSegClosePath::~SVGPathSegClosePath()
+{
+ delete impl;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathSegClosePath.h b/ksvg/dom/SVGPathSegClosePath.h
new file mode 100644
index 00000000..a7f32021
--- /dev/null
+++ b/ksvg/dom/SVGPathSegClosePath.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathSegClosePath_H
+#define SVGPathSegClosePath_H
+
+#include "SVGPathSeg.h"
+
+namespace KSVG
+{
+
+class SVGPathSegClosePathImpl;
+class SVGPathSegClosePath : public SVGPathSeg
+{
+public:
+ SVGPathSegClosePath();
+ SVGPathSegClosePath(const SVGPathSegClosePath &);
+ SVGPathSegClosePath &operator=(const SVGPathSegClosePath &other);
+ SVGPathSegClosePath(SVGPathSegClosePathImpl *);
+ ~SVGPathSegClosePath();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPathSegClosePathImpl *handle() const { return impl; }
+
+private:
+ SVGPathSegClosePathImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathSegCurvetoCubic.cc b/ksvg/dom/SVGPathSegCurvetoCubic.cc
new file mode 100644
index 00000000..bee9ce00
--- /dev/null
+++ b/ksvg/dom/SVGPathSegCurvetoCubic.cc
@@ -0,0 +1,214 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGPathSegCurvetoCubic.h"
+#include "SVGPathSegCurvetoCubicImpl.h"
+
+using namespace KSVG;
+
+SVGPathSegCurvetoCubicAbs::SVGPathSegCurvetoCubicAbs() : SVGPathSeg()
+{
+ impl = new SVGPathSegCurvetoCubicAbsImpl();
+}
+
+SVGPathSegCurvetoCubicAbs::SVGPathSegCurvetoCubicAbs(const SVGPathSegCurvetoCubicAbs &other) : SVGPathSeg(other)
+{
+ impl = other.impl;
+}
+
+SVGPathSegCurvetoCubicAbs::SVGPathSegCurvetoCubicAbs(SVGPathSegCurvetoCubicAbsImpl *other) : SVGPathSeg(other)
+{
+ impl = other;
+}
+
+SVGPathSegCurvetoCubicAbs::~SVGPathSegCurvetoCubicAbs()
+{
+ delete impl;
+}
+
+void SVGPathSegCurvetoCubicAbs::setX(const float &x)
+{
+ if(impl)
+ impl->setX(x);
+}
+
+float SVGPathSegCurvetoCubicAbs::x() const
+{
+ if(!impl) return -1;
+ return impl->x();
+}
+
+void SVGPathSegCurvetoCubicAbs::setY(const float &y)
+{
+ if(impl)
+ impl->setY(y);
+}
+
+float SVGPathSegCurvetoCubicAbs::y() const
+{
+ if(!impl) return -1;
+ return impl->y();
+}
+
+void SVGPathSegCurvetoCubicAbs::setX1(const float &x1)
+{
+ if(impl)
+ impl->setX1(x1);
+}
+
+float SVGPathSegCurvetoCubicAbs::x1() const
+{
+ if(!impl) return -1;
+ return impl->x1();
+}
+
+void SVGPathSegCurvetoCubicAbs::setY1(const float &y1)
+{
+ if(impl)
+ impl->setY1(y1);
+}
+
+float SVGPathSegCurvetoCubicAbs::y1() const
+{
+ if(!impl) return -1;
+ return impl->y1();
+}
+
+void SVGPathSegCurvetoCubicAbs::setX2(const float &x2)
+{
+ if(impl)
+ impl->setX2(x2);
+}
+
+float SVGPathSegCurvetoCubicAbs::x2() const
+{
+ if(!impl) return -1;
+ return impl->x2();
+}
+
+void SVGPathSegCurvetoCubicAbs::setY2(const float &y2)
+{
+ if(impl)
+ impl->setY2(y2);
+}
+
+float SVGPathSegCurvetoCubicAbs::y2() const
+{
+ if(!impl) return -1;
+ return impl->y2();
+}
+
+
+
+
+
+SVGPathSegCurvetoCubicRel::SVGPathSegCurvetoCubicRel() : SVGPathSeg()
+{
+ impl = new SVGPathSegCurvetoCubicRelImpl();
+}
+
+SVGPathSegCurvetoCubicRel::SVGPathSegCurvetoCubicRel(const SVGPathSegCurvetoCubicRel &other) : SVGPathSeg(other)
+{
+ impl = other.impl;
+}
+
+SVGPathSegCurvetoCubicRel::SVGPathSegCurvetoCubicRel(SVGPathSegCurvetoCubicRelImpl *other) : SVGPathSeg(other)
+{
+ impl = other;
+}
+
+SVGPathSegCurvetoCubicRel::~SVGPathSegCurvetoCubicRel()
+{
+ delete impl;
+}
+
+void SVGPathSegCurvetoCubicRel::setX(const float &x)
+{
+ if(impl)
+ impl->setX(x);
+}
+
+float SVGPathSegCurvetoCubicRel::x() const
+{
+ if(!impl) return -1;
+ return impl->x();
+}
+
+void SVGPathSegCurvetoCubicRel::setY(const float &y)
+{
+ if(impl)
+ impl->setY(y);
+}
+
+float SVGPathSegCurvetoCubicRel::y() const
+{
+ if(!impl) return -1;
+ return impl->y();
+}
+
+void SVGPathSegCurvetoCubicRel::setX1(const float &x1)
+{
+ if(impl)
+ impl->setX1(x1);
+}
+
+float SVGPathSegCurvetoCubicRel::x1() const
+{
+ if(!impl) return -1;
+ return impl->x1();
+}
+
+void SVGPathSegCurvetoCubicRel::setY1(const float &y1)
+{
+ if(impl)
+ impl->setY1(y1);
+}
+
+float SVGPathSegCurvetoCubicRel::y1() const
+{
+ if(!impl) return -1;
+ return impl->y1();
+}
+
+void SVGPathSegCurvetoCubicRel::setX2(const float &x2)
+{
+ if(impl)
+ impl->setX2(x2);
+}
+
+float SVGPathSegCurvetoCubicRel::x2() const
+{
+ if(!impl) return -1;
+ return impl->x2();
+}
+
+void SVGPathSegCurvetoCubicRel::setY2(const float &y2)
+{
+ if(impl)
+ impl->setY2(y2);
+}
+
+float SVGPathSegCurvetoCubicRel::y2() const
+{
+ if(!impl) return -1;
+ return impl->y2();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathSegCurvetoCubic.h b/ksvg/dom/SVGPathSegCurvetoCubic.h
new file mode 100644
index 00000000..99fde23e
--- /dev/null
+++ b/ksvg/dom/SVGPathSegCurvetoCubic.h
@@ -0,0 +1,103 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathSegCurvetoCubic_H
+#define SVGPathSegCurvetoCubic_H
+
+#include "SVGPathSeg.h"
+
+namespace KSVG
+{
+
+class SVGPathSegCurvetoCubicAbsImpl;
+class SVGPathSegCurvetoCubicAbs : public SVGPathSeg
+{
+public:
+ SVGPathSegCurvetoCubicAbs();
+ SVGPathSegCurvetoCubicAbs(const SVGPathSegCurvetoCubicAbs &);
+ SVGPathSegCurvetoCubicAbs &operator=(const SVGPathSegCurvetoCubicAbs &other);
+ SVGPathSegCurvetoCubicAbs(SVGPathSegCurvetoCubicAbsImpl *);
+ ~SVGPathSegCurvetoCubicAbs();
+
+ void setX(const float &);
+ float x() const;
+
+ void setY(const float &);
+ float y() const;
+
+ void setX1(const float &);
+ float x1() const;
+
+ void setY1(const float &);
+ float y1() const;
+
+ void setX2(const float &);
+ float x2() const;
+
+ void setY2(const float &);
+ float y2() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPathSegCurvetoCubicAbsImpl *handle() const { return impl; }
+
+private:
+ SVGPathSegCurvetoCubicAbsImpl *impl;
+};
+
+class SVGPathSegCurvetoCubicRelImpl;
+class SVGPathSegCurvetoCubicRel : public SVGPathSeg
+{
+public:
+ SVGPathSegCurvetoCubicRel();
+ SVGPathSegCurvetoCubicRel(const SVGPathSegCurvetoCubicRel &);
+ SVGPathSegCurvetoCubicRel &operator=(const SVGPathSegCurvetoCubicRel &other);
+ SVGPathSegCurvetoCubicRel(SVGPathSegCurvetoCubicRelImpl *);
+ ~SVGPathSegCurvetoCubicRel();
+
+ void setX(const float &);
+ float x() const;
+
+ void setY(const float &);
+ float y() const;
+
+ void setX1(const float &);
+ float x1() const;
+
+ void setY1(const float &);
+ float y1() const;
+
+ void setX2(const float &);
+ float x2() const;
+
+ void setY2(const float &);
+ float y2() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPathSegCurvetoCubicRelImpl *handle() const { return impl; }
+
+private:
+ SVGPathSegCurvetoCubicRelImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathSegCurvetoCubicSmooth.cc b/ksvg/dom/SVGPathSegCurvetoCubicSmooth.cc
new file mode 100644
index 00000000..5bb9df25
--- /dev/null
+++ b/ksvg/dom/SVGPathSegCurvetoCubicSmooth.cc
@@ -0,0 +1,166 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGPathSegCurvetoCubicSmooth.h"
+#include "SVGPathSegCurvetoCubicSmoothImpl.h"
+
+using namespace KSVG;
+
+SVGPathSegCurvetoCubicSmoothAbs::SVGPathSegCurvetoCubicSmoothAbs() : SVGPathSeg()
+{
+ impl = new SVGPathSegCurvetoCubicSmoothAbsImpl();
+}
+
+SVGPathSegCurvetoCubicSmoothAbs::SVGPathSegCurvetoCubicSmoothAbs(const SVGPathSegCurvetoCubicSmoothAbs &other) : SVGPathSeg(other)
+{
+ impl = other.impl;
+}
+
+SVGPathSegCurvetoCubicSmoothAbs::SVGPathSegCurvetoCubicSmoothAbs(SVGPathSegCurvetoCubicSmoothAbsImpl *other) : SVGPathSeg(other)
+{
+ impl = other;
+}
+
+SVGPathSegCurvetoCubicSmoothAbs::~SVGPathSegCurvetoCubicSmoothAbs()
+{
+ delete impl;
+}
+
+void SVGPathSegCurvetoCubicSmoothAbs::setX(const float &x)
+{
+ if(impl)
+ impl->setX(x);
+}
+
+float SVGPathSegCurvetoCubicSmoothAbs::x() const
+{
+ if(!impl) return -1;
+ return impl->x();
+}
+
+void SVGPathSegCurvetoCubicSmoothAbs::setY(const float &y)
+{
+ if(impl)
+ impl->setY(y);
+}
+
+float SVGPathSegCurvetoCubicSmoothAbs::y() const
+{
+ if(!impl) return -1;
+ return impl->y();
+}
+
+void SVGPathSegCurvetoCubicSmoothAbs::setX2(const float &x2)
+{
+ if(impl)
+ impl->setX2(x2);
+}
+
+float SVGPathSegCurvetoCubicSmoothAbs::x2() const
+{
+ if(!impl) return -1;
+ return impl->x2();
+}
+
+void SVGPathSegCurvetoCubicSmoothAbs::setY2(const float &y2)
+{
+ if(impl)
+ impl->setY2(y2);
+}
+
+float SVGPathSegCurvetoCubicSmoothAbs::y2() const
+{
+ if(!impl) return -1;
+ return impl->y2();
+}
+
+
+
+
+
+SVGPathSegCurvetoCubicSmoothRel::SVGPathSegCurvetoCubicSmoothRel() : SVGPathSeg()
+{
+ impl = new SVGPathSegCurvetoCubicSmoothRelImpl();
+}
+
+SVGPathSegCurvetoCubicSmoothRel::SVGPathSegCurvetoCubicSmoothRel(const SVGPathSegCurvetoCubicSmoothRel &other) : SVGPathSeg(other)
+{
+ impl = other.impl;
+}
+
+SVGPathSegCurvetoCubicSmoothRel::SVGPathSegCurvetoCubicSmoothRel(SVGPathSegCurvetoCubicSmoothRelImpl *other) : SVGPathSeg(other)
+{
+ impl = other;
+}
+
+SVGPathSegCurvetoCubicSmoothRel::~SVGPathSegCurvetoCubicSmoothRel()
+{
+ delete impl;
+}
+
+void SVGPathSegCurvetoCubicSmoothRel::setX(const float &x)
+{
+ if(impl)
+ impl->setX(x);
+}
+
+float SVGPathSegCurvetoCubicSmoothRel::x() const
+{
+ if(!impl) return -1;
+ return impl->x();
+}
+
+void SVGPathSegCurvetoCubicSmoothRel::setY(const float &y)
+{
+ if(impl)
+ impl->setY(y);
+}
+
+float SVGPathSegCurvetoCubicSmoothRel::y() const
+{
+ if(!impl) return -1;
+ return impl->y();
+}
+
+void SVGPathSegCurvetoCubicSmoothRel::setX2(const float &x2)
+{
+ if(impl)
+ impl->setX2(x2);
+}
+
+float SVGPathSegCurvetoCubicSmoothRel::x2() const
+{
+ if(!impl) return -1;
+ return impl->x2();
+}
+
+void SVGPathSegCurvetoCubicSmoothRel::setY2(const float &y2)
+{
+ if(impl)
+ impl->setY2(y2);
+}
+
+float SVGPathSegCurvetoCubicSmoothRel::y2() const
+{
+ if(!impl) return -1;
+ return impl->y2();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathSegCurvetoCubicSmooth.h b/ksvg/dom/SVGPathSegCurvetoCubicSmooth.h
new file mode 100644
index 00000000..444e54f0
--- /dev/null
+++ b/ksvg/dom/SVGPathSegCurvetoCubicSmooth.h
@@ -0,0 +1,91 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathSegCurvetoCubicSmooth_H
+#define SVGPathSegCurvetoCubicSmooth_H
+
+#include "SVGPathSeg.h"
+
+namespace KSVG
+{
+
+class SVGPathSegCurvetoCubicSmoothAbsImpl;
+class SVGPathSegCurvetoCubicSmoothAbs : public SVGPathSeg
+{
+public:
+ SVGPathSegCurvetoCubicSmoothAbs();
+ SVGPathSegCurvetoCubicSmoothAbs(const SVGPathSegCurvetoCubicSmoothAbs &);
+ SVGPathSegCurvetoCubicSmoothAbs &operator=(const SVGPathSegCurvetoCubicSmoothAbs &other);
+ SVGPathSegCurvetoCubicSmoothAbs(SVGPathSegCurvetoCubicSmoothAbsImpl *);
+ ~SVGPathSegCurvetoCubicSmoothAbs();
+
+ void setX(const float &);
+ float x() const;
+
+ void setY(const float &);
+ float y() const;
+
+ void setX2(const float &);
+ float x2() const;
+
+ void setY2(const float &);
+ float y2() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPathSegCurvetoCubicSmoothAbsImpl *handle() const { return impl; }
+
+private:
+ SVGPathSegCurvetoCubicSmoothAbsImpl *impl;
+};
+
+class SVGPathSegCurvetoCubicSmoothRelImpl;
+class SVGPathSegCurvetoCubicSmoothRel : public SVGPathSeg
+{
+public:
+ SVGPathSegCurvetoCubicSmoothRel();
+ SVGPathSegCurvetoCubicSmoothRel(const SVGPathSegCurvetoCubicSmoothRel &);
+ SVGPathSegCurvetoCubicSmoothRel &operator=(const SVGPathSegCurvetoCubicSmoothRel &other);
+ SVGPathSegCurvetoCubicSmoothRel(SVGPathSegCurvetoCubicSmoothRelImpl *);
+ ~SVGPathSegCurvetoCubicSmoothRel();
+
+ void setX(const float &);
+ float x() const;
+
+ void setY(const float &);
+ float y() const;
+
+ void setX2(const float &);
+ float x2() const;
+
+ void setY2(const float &);
+ float y2() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPathSegCurvetoCubicSmoothRelImpl *handle() const { return impl; }
+
+private:
+ SVGPathSegCurvetoCubicSmoothRelImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathSegCurvetoQuadratic.cc b/ksvg/dom/SVGPathSegCurvetoQuadratic.cc
new file mode 100644
index 00000000..7792db31
--- /dev/null
+++ b/ksvg/dom/SVGPathSegCurvetoQuadratic.cc
@@ -0,0 +1,166 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGPathSegCurvetoQuadratic.h"
+#include "SVGPathSegCurvetoQuadraticImpl.h"
+
+using namespace KSVG;
+
+SVGPathSegCurvetoQuadraticAbs::SVGPathSegCurvetoQuadraticAbs() : SVGPathSeg()
+{
+ impl = new SVGPathSegCurvetoQuadraticAbsImpl();
+}
+
+SVGPathSegCurvetoQuadraticAbs::SVGPathSegCurvetoQuadraticAbs(const SVGPathSegCurvetoQuadraticAbs &other) : SVGPathSeg(other)
+{
+ impl = other.impl;
+}
+
+SVGPathSegCurvetoQuadraticAbs::SVGPathSegCurvetoQuadraticAbs(SVGPathSegCurvetoQuadraticAbsImpl *other) : SVGPathSeg(other)
+{
+ impl = other;
+}
+
+SVGPathSegCurvetoQuadraticAbs::~SVGPathSegCurvetoQuadraticAbs()
+{
+ delete impl;
+}
+
+void SVGPathSegCurvetoQuadraticAbs::setX(const float &x)
+{
+ if(impl)
+ impl->setX(x);
+}
+
+float SVGPathSegCurvetoQuadraticAbs::x() const
+{
+ if(!impl) return -1;
+ return impl->x();
+}
+
+void SVGPathSegCurvetoQuadraticAbs::setY(const float &y)
+{
+ if(impl)
+ impl->setY(y);
+}
+
+float SVGPathSegCurvetoQuadraticAbs::y() const
+{
+ if(!impl) return -1;
+ return impl->y();
+}
+
+void SVGPathSegCurvetoQuadraticAbs::setX1(const float &x1)
+{
+ if(impl)
+ impl->setX1(x1);
+}
+
+float SVGPathSegCurvetoQuadraticAbs::x1() const
+{
+ if(!impl) return -1;
+ return impl->x1();
+}
+
+void SVGPathSegCurvetoQuadraticAbs::setY1(const float &y1)
+{
+ if(impl)
+ impl->setY1(y1);
+}
+
+float SVGPathSegCurvetoQuadraticAbs::y1() const
+{
+ if(!impl) return -1;
+ return impl->y1();
+}
+
+
+
+
+
+SVGPathSegCurvetoQuadraticRel::SVGPathSegCurvetoQuadraticRel() : SVGPathSeg()
+{
+ impl = new SVGPathSegCurvetoQuadraticRelImpl();
+}
+
+SVGPathSegCurvetoQuadraticRel::SVGPathSegCurvetoQuadraticRel(const SVGPathSegCurvetoQuadraticRel &other) : SVGPathSeg(other)
+{
+ impl = other.impl;
+}
+
+SVGPathSegCurvetoQuadraticRel::SVGPathSegCurvetoQuadraticRel(SVGPathSegCurvetoQuadraticRelImpl *other) : SVGPathSeg(other)
+{
+ impl = other;
+}
+
+SVGPathSegCurvetoQuadraticRel::~SVGPathSegCurvetoQuadraticRel()
+{
+ delete impl;
+}
+
+void SVGPathSegCurvetoQuadraticRel::setX(const float &x)
+{
+ if(impl)
+ impl->setX(x);
+}
+
+float SVGPathSegCurvetoQuadraticRel::x() const
+{
+ if(!impl) return -1;
+ return impl->x();
+}
+
+void SVGPathSegCurvetoQuadraticRel::setY(const float &y)
+{
+ if(impl)
+ impl->setY(y);
+}
+
+float SVGPathSegCurvetoQuadraticRel::y() const
+{
+ if(!impl) return -1;
+ return impl->y();
+}
+
+void SVGPathSegCurvetoQuadraticRel::setX1(const float &x1)
+{
+ if(impl)
+ impl->setX1(x1);
+}
+
+float SVGPathSegCurvetoQuadraticRel::x1() const
+{
+ if(!impl) return -1;
+ return impl->x1();
+}
+
+void SVGPathSegCurvetoQuadraticRel::setY1(const float &y1)
+{
+ if(impl)
+ impl->setY1(y1);
+}
+
+float SVGPathSegCurvetoQuadraticRel::y1() const
+{
+ if(!impl) return -1;
+ return impl->y1();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathSegCurvetoQuadratic.h b/ksvg/dom/SVGPathSegCurvetoQuadratic.h
new file mode 100644
index 00000000..68bb3364
--- /dev/null
+++ b/ksvg/dom/SVGPathSegCurvetoQuadratic.h
@@ -0,0 +1,91 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathSegCurvetoQuadratic_H
+#define SVGPathSegCurvetoQuadratic_H
+
+#include "SVGPathSeg.h"
+
+namespace KSVG
+{
+
+class SVGPathSegCurvetoQuadraticAbsImpl;
+class SVGPathSegCurvetoQuadraticAbs : public SVGPathSeg
+{
+public:
+ SVGPathSegCurvetoQuadraticAbs();
+ SVGPathSegCurvetoQuadraticAbs(const SVGPathSegCurvetoQuadraticAbs &);
+ SVGPathSegCurvetoQuadraticAbs &operator=(const SVGPathSegCurvetoQuadraticAbs &other);
+ SVGPathSegCurvetoQuadraticAbs(SVGPathSegCurvetoQuadraticAbsImpl *);
+ ~SVGPathSegCurvetoQuadraticAbs();
+
+ void setX(const float &);
+ float x() const;
+
+ void setY(const float &);
+ float y() const;
+
+ void setX1(const float &);
+ float x1() const;
+
+ void setY1(const float &);
+ float y1() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPathSegCurvetoQuadraticAbsImpl *handle() const { return impl; }
+
+private:
+ SVGPathSegCurvetoQuadraticAbsImpl *impl;
+};
+
+class SVGPathSegCurvetoQuadraticRelImpl;
+class SVGPathSegCurvetoQuadraticRel : public SVGPathSeg
+{
+public:
+ SVGPathSegCurvetoQuadraticRel();
+ SVGPathSegCurvetoQuadraticRel(const SVGPathSegCurvetoQuadraticRel &);
+ SVGPathSegCurvetoQuadraticRel &operator=(const SVGPathSegCurvetoQuadraticRel &other);
+ SVGPathSegCurvetoQuadraticRel(SVGPathSegCurvetoQuadraticRelImpl *);
+ ~SVGPathSegCurvetoQuadraticRel();
+
+ void setX(const float &);
+ float x() const;
+
+ void setY(const float &);
+ float y() const;
+
+ void setX1(const float &);
+ float x1() const;
+
+ void setY1(const float &);
+ float y1() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPathSegCurvetoQuadraticRelImpl *handle() const { return impl; }
+
+private:
+ SVGPathSegCurvetoQuadraticRelImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathSegCurvetoQuadraticSmooth.cc b/ksvg/dom/SVGPathSegCurvetoQuadraticSmooth.cc
new file mode 100644
index 00000000..35a841c8
--- /dev/null
+++ b/ksvg/dom/SVGPathSegCurvetoQuadraticSmooth.cc
@@ -0,0 +1,118 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGPathSegCurvetoQuadraticSmooth.h"
+#include "SVGPathSegCurvetoQuadraticSmoothImpl.h"
+
+using namespace KSVG;
+
+SVGPathSegCurvetoQuadraticSmoothAbs::SVGPathSegCurvetoQuadraticSmoothAbs() : SVGPathSeg()
+{
+ impl = new SVGPathSegCurvetoQuadraticSmoothAbsImpl();
+}
+
+SVGPathSegCurvetoQuadraticSmoothAbs::SVGPathSegCurvetoQuadraticSmoothAbs(const SVGPathSegCurvetoQuadraticSmoothAbs &other) : SVGPathSeg(other)
+{
+ impl = other.impl;
+}
+
+SVGPathSegCurvetoQuadraticSmoothAbs::SVGPathSegCurvetoQuadraticSmoothAbs(SVGPathSegCurvetoQuadraticSmoothAbsImpl *other) : SVGPathSeg(other)
+{
+ impl = other;
+}
+
+SVGPathSegCurvetoQuadraticSmoothAbs::~SVGPathSegCurvetoQuadraticSmoothAbs()
+{
+ delete impl;
+}
+
+void SVGPathSegCurvetoQuadraticSmoothAbs::setX(const float &x)
+{
+ if(impl)
+ impl->setX(x);
+}
+
+float SVGPathSegCurvetoQuadraticSmoothAbs::x() const
+{
+ if(!impl) return -1;
+ return impl->x();
+}
+
+void SVGPathSegCurvetoQuadraticSmoothAbs::setY(const float &y)
+{
+ if(impl)
+ impl->setY(y);
+}
+
+float SVGPathSegCurvetoQuadraticSmoothAbs::y() const
+{
+ if(!impl) return -1;
+ return impl->y();
+}
+
+
+
+
+
+SVGPathSegCurvetoQuadraticSmoothRel::SVGPathSegCurvetoQuadraticSmoothRel() : SVGPathSeg()
+{
+ impl = new SVGPathSegCurvetoQuadraticSmoothRelImpl();
+}
+
+SVGPathSegCurvetoQuadraticSmoothRel::SVGPathSegCurvetoQuadraticSmoothRel(const SVGPathSegCurvetoQuadraticSmoothRel &other) : SVGPathSeg(other)
+{
+ impl = other.impl;
+}
+
+SVGPathSegCurvetoQuadraticSmoothRel::SVGPathSegCurvetoQuadraticSmoothRel(SVGPathSegCurvetoQuadraticSmoothRelImpl *other) : SVGPathSeg(other)
+{
+ impl = other;
+}
+
+SVGPathSegCurvetoQuadraticSmoothRel::~SVGPathSegCurvetoQuadraticSmoothRel()
+{
+ delete impl;
+}
+
+void SVGPathSegCurvetoQuadraticSmoothRel::setX(const float &x)
+{
+ if(impl)
+ impl->setX(x);
+}
+
+float SVGPathSegCurvetoQuadraticSmoothRel::x() const
+{
+ if(!impl) return -1;
+ return impl->x();
+}
+
+void SVGPathSegCurvetoQuadraticSmoothRel::setY(const float &y)
+{
+ if(impl)
+ impl->setY(y);
+}
+
+float SVGPathSegCurvetoQuadraticSmoothRel::y() const
+{
+ if(!impl) return -1;
+ return impl->y();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathSegCurvetoQuadraticSmooth.h b/ksvg/dom/SVGPathSegCurvetoQuadraticSmooth.h
new file mode 100644
index 00000000..e5a2782f
--- /dev/null
+++ b/ksvg/dom/SVGPathSegCurvetoQuadraticSmooth.h
@@ -0,0 +1,79 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathSegCurvetoQuadraticSmooth_H
+#define SVGPathSegCurvetoQuadraticSmooth_H
+
+#include "SVGPathSeg.h"
+
+namespace KSVG
+{
+
+class SVGPathSegCurvetoQuadraticSmoothAbsImpl;
+class SVGPathSegCurvetoQuadraticSmoothAbs : public SVGPathSeg
+{
+public:
+ SVGPathSegCurvetoQuadraticSmoothAbs();
+ SVGPathSegCurvetoQuadraticSmoothAbs(const SVGPathSegCurvetoQuadraticSmoothAbs &);
+ SVGPathSegCurvetoQuadraticSmoothAbs &operator=(const SVGPathSegCurvetoQuadraticSmoothAbs &other);
+ SVGPathSegCurvetoQuadraticSmoothAbs(SVGPathSegCurvetoQuadraticSmoothAbsImpl *);
+ ~SVGPathSegCurvetoQuadraticSmoothAbs();
+
+ void setX(const float &);
+ float x() const;
+
+ void setY(const float &);
+ float y() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPathSegCurvetoQuadraticSmoothAbsImpl *handle() const { return impl; }
+
+private:
+ SVGPathSegCurvetoQuadraticSmoothAbsImpl *impl;
+};
+
+class SVGPathSegCurvetoQuadraticSmoothRelImpl;
+class SVGPathSegCurvetoQuadraticSmoothRel : public SVGPathSeg
+{
+public:
+ SVGPathSegCurvetoQuadraticSmoothRel();
+ SVGPathSegCurvetoQuadraticSmoothRel(const SVGPathSegCurvetoQuadraticSmoothRel &);
+ SVGPathSegCurvetoQuadraticSmoothRel &operator=(const SVGPathSegCurvetoQuadraticSmoothRel &other);
+ SVGPathSegCurvetoQuadraticSmoothRel(SVGPathSegCurvetoQuadraticSmoothRelImpl *);
+ ~SVGPathSegCurvetoQuadraticSmoothRel();
+
+ void setX(const float &);
+ float x() const;
+
+ void setY(const float &);
+ float y() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPathSegCurvetoQuadraticSmoothRelImpl *handle() const { return impl; }
+
+private:
+ SVGPathSegCurvetoQuadraticSmoothRelImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathSegLineto.cc b/ksvg/dom/SVGPathSegLineto.cc
new file mode 100644
index 00000000..faabb04e
--- /dev/null
+++ b/ksvg/dom/SVGPathSegLineto.cc
@@ -0,0 +1,118 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGPathSegLineto.h"
+#include "SVGPathSegLinetoImpl.h"
+
+using namespace KSVG;
+
+SVGPathSegLinetoAbs::SVGPathSegLinetoAbs() : SVGPathSeg()
+{
+ impl = new SVGPathSegLinetoAbsImpl();
+}
+
+SVGPathSegLinetoAbs::SVGPathSegLinetoAbs(const SVGPathSegLinetoAbs &other) : SVGPathSeg(other)
+{
+ impl = other.impl;
+}
+
+SVGPathSegLinetoAbs::SVGPathSegLinetoAbs(SVGPathSegLinetoAbsImpl *other) : SVGPathSeg(other)
+{
+ impl = other;
+}
+
+SVGPathSegLinetoAbs::~SVGPathSegLinetoAbs()
+{
+ delete impl;
+}
+
+void SVGPathSegLinetoAbs::setX(const float &x)
+{
+ if(impl)
+ impl->setX(x);
+}
+
+float SVGPathSegLinetoAbs::x() const
+{
+ if(!impl) return -1;
+ return impl->x();
+}
+
+void SVGPathSegLinetoAbs::setY(const float &y)
+{
+ if(impl)
+ impl->setY(y);
+}
+
+float SVGPathSegLinetoAbs::y() const
+{
+ if(!impl) return -1;
+ return impl->y();
+}
+
+
+
+
+
+SVGPathSegLinetoRel::SVGPathSegLinetoRel() : SVGPathSeg()
+{
+ impl = new SVGPathSegLinetoRelImpl();
+}
+
+SVGPathSegLinetoRel::SVGPathSegLinetoRel(const SVGPathSegLinetoRel &other) : SVGPathSeg(other)
+{
+ impl = other.impl;
+}
+
+SVGPathSegLinetoRel::SVGPathSegLinetoRel(SVGPathSegLinetoRelImpl *other) : SVGPathSeg(other)
+{
+ impl = other;
+}
+
+SVGPathSegLinetoRel::~SVGPathSegLinetoRel()
+{
+ delete impl;
+}
+
+void SVGPathSegLinetoRel::setX(const float &x)
+{
+ if(impl)
+ impl->setX(x);
+}
+
+float SVGPathSegLinetoRel::x() const
+{
+ if(!impl) return -1;
+ return impl->x();
+}
+
+void SVGPathSegLinetoRel::setY(const float &y)
+{
+ if(impl)
+ impl->setY(y);
+}
+
+float SVGPathSegLinetoRel::y() const
+{
+ if(!impl) return -1;
+ return impl->y();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathSegLineto.h b/ksvg/dom/SVGPathSegLineto.h
new file mode 100644
index 00000000..df1b9862
--- /dev/null
+++ b/ksvg/dom/SVGPathSegLineto.h
@@ -0,0 +1,79 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathSegLineto_H
+#define SVGPathSegLineto_H
+
+#include "SVGPathSeg.h"
+
+namespace KSVG
+{
+
+class SVGPathSegLinetoAbsImpl;
+class SVGPathSegLinetoAbs : public SVGPathSeg
+{
+public:
+ SVGPathSegLinetoAbs();
+ SVGPathSegLinetoAbs(const SVGPathSegLinetoAbs &);
+ SVGPathSegLinetoAbs &operator=(const SVGPathSegLinetoAbs &other);
+ SVGPathSegLinetoAbs(SVGPathSegLinetoAbsImpl *);
+ ~SVGPathSegLinetoAbs();
+
+ void setX(const float &);
+ float x() const;
+
+ void setY(const float &);
+ float y() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPathSegLinetoAbsImpl *handle() const { return impl; }
+
+private:
+ SVGPathSegLinetoAbsImpl *impl;
+};
+
+class SVGPathSegLinetoRelImpl;
+class SVGPathSegLinetoRel : public SVGPathSeg
+{
+public:
+ SVGPathSegLinetoRel();
+ SVGPathSegLinetoRel(const SVGPathSegLinetoRel &);
+ SVGPathSegLinetoRel &operator=(const SVGPathSegLinetoRel &other);
+ SVGPathSegLinetoRel(SVGPathSegLinetoRelImpl *);
+ ~SVGPathSegLinetoRel();
+
+ void setX(const float &);
+ float x() const;
+
+ void setY(const float &);
+ float y() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPathSegLinetoRelImpl *handle() const { return impl; }
+
+private:
+ SVGPathSegLinetoRelImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathSegLinetoHorizontal.cc b/ksvg/dom/SVGPathSegLinetoHorizontal.cc
new file mode 100644
index 00000000..22af4e40
--- /dev/null
+++ b/ksvg/dom/SVGPathSegLinetoHorizontal.cc
@@ -0,0 +1,94 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGPathSegLinetoHorizontal.h"
+#include "SVGPathSegLinetoHorizontalImpl.h"
+
+using namespace KSVG;
+
+SVGPathSegLinetoHorizontalAbs::SVGPathSegLinetoHorizontalAbs() : SVGPathSeg()
+{
+ impl = new SVGPathSegLinetoHorizontalAbsImpl();
+}
+
+SVGPathSegLinetoHorizontalAbs::SVGPathSegLinetoHorizontalAbs(const SVGPathSegLinetoHorizontalAbs &other) : SVGPathSeg(other)
+{
+ impl = other.impl;
+}
+
+SVGPathSegLinetoHorizontalAbs::SVGPathSegLinetoHorizontalAbs(SVGPathSegLinetoHorizontalAbsImpl *other) : SVGPathSeg(other)
+{
+ impl = other;
+}
+
+SVGPathSegLinetoHorizontalAbs::~SVGPathSegLinetoHorizontalAbs()
+{
+ delete impl;
+}
+
+void SVGPathSegLinetoHorizontalAbs::setX(const float &x)
+{
+ if(impl)
+ impl->setX(x);
+}
+
+float SVGPathSegLinetoHorizontalAbs::x() const
+{
+ if(!impl) return -1;
+ return impl->x();
+}
+
+
+
+
+
+SVGPathSegLinetoHorizontalRel::SVGPathSegLinetoHorizontalRel() : SVGPathSeg()
+{
+ impl = new SVGPathSegLinetoHorizontalRelImpl();
+}
+
+SVGPathSegLinetoHorizontalRel::SVGPathSegLinetoHorizontalRel(const SVGPathSegLinetoHorizontalRel &other) : SVGPathSeg(other)
+{
+ impl = other.impl;
+}
+
+SVGPathSegLinetoHorizontalRel::SVGPathSegLinetoHorizontalRel(SVGPathSegLinetoHorizontalRelImpl *other) : SVGPathSeg(other)
+{
+ impl = other;
+}
+
+SVGPathSegLinetoHorizontalRel::~SVGPathSegLinetoHorizontalRel()
+{
+ delete impl;
+}
+
+void SVGPathSegLinetoHorizontalRel::setX(const float &x)
+{
+ if(impl)
+ impl->setX(x);
+}
+
+float SVGPathSegLinetoHorizontalRel::x() const
+{
+ if(!impl) return -1;
+ return impl->x();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathSegLinetoHorizontal.h b/ksvg/dom/SVGPathSegLinetoHorizontal.h
new file mode 100644
index 00000000..51edd6ff
--- /dev/null
+++ b/ksvg/dom/SVGPathSegLinetoHorizontal.h
@@ -0,0 +1,73 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathSegLinetoHorizontal_H
+#define SVGPathSegLinetoHorizontal_H
+
+#include "SVGPathSeg.h"
+
+namespace KSVG
+{
+
+class SVGPathSegLinetoHorizontalAbsImpl;
+class SVGPathSegLinetoHorizontalAbs : public SVGPathSeg
+{
+public:
+ SVGPathSegLinetoHorizontalAbs();
+ SVGPathSegLinetoHorizontalAbs(const SVGPathSegLinetoHorizontalAbs &);
+ SVGPathSegLinetoHorizontalAbs &operator=(const SVGPathSegLinetoHorizontalAbs &other);
+ SVGPathSegLinetoHorizontalAbs(SVGPathSegLinetoHorizontalAbsImpl *);
+ ~SVGPathSegLinetoHorizontalAbs();
+
+ void setX(const float &);
+ float x() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPathSegLinetoHorizontalAbsImpl *handle() const { return impl; }
+
+private:
+ SVGPathSegLinetoHorizontalAbsImpl *impl;
+};
+
+class SVGPathSegLinetoHorizontalRelImpl;
+class SVGPathSegLinetoHorizontalRel : public SVGPathSeg
+{
+public:
+ SVGPathSegLinetoHorizontalRel();
+ SVGPathSegLinetoHorizontalRel(const SVGPathSegLinetoHorizontalRel &);
+ SVGPathSegLinetoHorizontalRel &operator=(const SVGPathSegLinetoHorizontalRel &other);
+ SVGPathSegLinetoHorizontalRel(SVGPathSegLinetoHorizontalRelImpl *);
+ ~SVGPathSegLinetoHorizontalRel();
+
+ void setX(const float &);
+ float x() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPathSegLinetoHorizontalRelImpl *handle() const { return impl; }
+
+private:
+ SVGPathSegLinetoHorizontalRelImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathSegLinetoVertical.cc b/ksvg/dom/SVGPathSegLinetoVertical.cc
new file mode 100644
index 00000000..86e0c33e
--- /dev/null
+++ b/ksvg/dom/SVGPathSegLinetoVertical.cc
@@ -0,0 +1,94 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGPathSegLinetoVertical.h"
+#include "SVGPathSegLinetoVerticalImpl.h"
+
+using namespace KSVG;
+
+SVGPathSegLinetoVerticalAbs::SVGPathSegLinetoVerticalAbs() : SVGPathSeg()
+{
+ impl = new SVGPathSegLinetoVerticalAbsImpl();
+}
+
+SVGPathSegLinetoVerticalAbs::SVGPathSegLinetoVerticalAbs(const SVGPathSegLinetoVerticalAbs &other) : SVGPathSeg(other)
+{
+ impl = other.impl;
+}
+
+SVGPathSegLinetoVerticalAbs::SVGPathSegLinetoVerticalAbs(SVGPathSegLinetoVerticalAbsImpl *other) : SVGPathSeg(other)
+{
+ impl = other;
+}
+
+SVGPathSegLinetoVerticalAbs::~SVGPathSegLinetoVerticalAbs()
+{
+ delete impl;
+}
+
+void SVGPathSegLinetoVerticalAbs::setY(const float &y)
+{
+ if(impl)
+ impl->setY(y);
+}
+
+float SVGPathSegLinetoVerticalAbs::y() const
+{
+ if(!impl) return -1;
+ return impl->y();
+}
+
+
+
+
+
+SVGPathSegLinetoVerticalRel::SVGPathSegLinetoVerticalRel() : SVGPathSeg()
+{
+ impl = new SVGPathSegLinetoVerticalRelImpl();
+}
+
+SVGPathSegLinetoVerticalRel::SVGPathSegLinetoVerticalRel(const SVGPathSegLinetoVerticalRel &other) : SVGPathSeg(other)
+{
+ impl = other.impl;
+}
+
+SVGPathSegLinetoVerticalRel::SVGPathSegLinetoVerticalRel(SVGPathSegLinetoVerticalRelImpl *other) : SVGPathSeg(other)
+{
+ impl = other;
+}
+
+SVGPathSegLinetoVerticalRel::~SVGPathSegLinetoVerticalRel()
+{
+ delete impl;
+}
+
+void SVGPathSegLinetoVerticalRel::setY(const float &y)
+{
+ if(impl)
+ impl->setY(y);
+}
+
+float SVGPathSegLinetoVerticalRel::y() const
+{
+ if(!impl) return -1;
+ return impl->y();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathSegLinetoVertical.h b/ksvg/dom/SVGPathSegLinetoVertical.h
new file mode 100644
index 00000000..05e516a7
--- /dev/null
+++ b/ksvg/dom/SVGPathSegLinetoVertical.h
@@ -0,0 +1,73 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathSegLinetoVertical_H
+#define SVGPathSegLinetoVertical_H
+
+#include "SVGPathSeg.h"
+
+namespace KSVG
+{
+
+class SVGPathSegLinetoVerticalAbsImpl;
+class SVGPathSegLinetoVerticalAbs : public SVGPathSeg
+{
+public:
+ SVGPathSegLinetoVerticalAbs();
+ SVGPathSegLinetoVerticalAbs(const SVGPathSegLinetoVerticalAbs &);
+ SVGPathSegLinetoVerticalAbs &operator=(const SVGPathSegLinetoVerticalAbs &other);
+ SVGPathSegLinetoVerticalAbs(SVGPathSegLinetoVerticalAbsImpl *);
+ ~SVGPathSegLinetoVerticalAbs();
+
+ void setY(const float &);
+ float y() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPathSegLinetoVerticalAbsImpl *handle() const { return impl; }
+
+private:
+ SVGPathSegLinetoVerticalAbsImpl *impl;
+};
+
+class SVGPathSegLinetoVerticalRelImpl;
+class SVGPathSegLinetoVerticalRel : public SVGPathSeg
+{
+public:
+ SVGPathSegLinetoVerticalRel();
+ SVGPathSegLinetoVerticalRel(const SVGPathSegLinetoVerticalRel &);
+ SVGPathSegLinetoVerticalRel &operator=(const SVGPathSegLinetoVerticalRel &other);
+ SVGPathSegLinetoVerticalRel(SVGPathSegLinetoVerticalRelImpl *);
+ ~SVGPathSegLinetoVerticalRel();
+
+ void setY(const float &);
+ float y() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPathSegLinetoVerticalRelImpl *handle() const { return impl; }
+
+private:
+ SVGPathSegLinetoVerticalRelImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathSegList.cc b/ksvg/dom/SVGPathSegList.cc
new file mode 100644
index 00000000..e653adc6
--- /dev/null
+++ b/ksvg/dom/SVGPathSegList.cc
@@ -0,0 +1,114 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGPathSegList.h"
+#include "SVGPathSegListImpl.h"
+
+using namespace KSVG;
+
+SVGPathSegList::SVGPathSegList()
+{
+ impl = new SVGPathSegListImpl();
+ impl->ref();
+}
+
+SVGPathSegList::SVGPathSegList(const SVGPathSegList &other)
+{
+ (*this) = other;
+}
+
+SVGPathSegList &SVGPathSegList::operator=(const SVGPathSegList &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGPathSegList::SVGPathSegList(SVGPathSegListImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGPathSegList::~SVGPathSegList()
+{
+ if(impl)
+ impl->deref();
+}
+
+unsigned long SVGPathSegList::numberOfItems() const
+{
+ if(!impl) return 0;
+ return impl->numberOfItems();
+}
+
+void SVGPathSegList::clear()
+{
+ if(impl)
+ impl->clear();
+}
+
+SVGPathSeg *SVGPathSegList::initialize(SVGPathSeg *newItem)
+{
+ if(!impl) return new SVGPathSeg(0);
+ return new SVGPathSeg(impl->initialize(newItem->handle()));
+}
+
+SVGPathSeg *SVGPathSegList::getItem(unsigned long index)
+{
+ if(!impl) return new SVGPathSeg(0);
+ return new SVGPathSeg(impl->getItem(index));
+}
+
+SVGPathSeg *SVGPathSegList::insertItemBefore(SVGPathSeg *newItem, unsigned long index)
+{
+ if(!impl) return new SVGPathSeg(0);
+ return new SVGPathSeg(impl->insertItemBefore(newItem->handle(), index));
+}
+
+SVGPathSeg *SVGPathSegList::replaceItem(SVGPathSeg *newItem, unsigned long index)
+{
+ if(!impl) return new SVGPathSeg(0);
+ return new SVGPathSeg(impl->replaceItem(newItem->handle(), index));
+}
+
+SVGPathSeg *SVGPathSegList::removeItem(unsigned long index)
+{
+ if(!impl) return new SVGPathSeg(0);
+ return new SVGPathSeg(impl->removeItem(index));
+}
+
+SVGPathSeg *SVGPathSegList::appendItem(SVGPathSeg *newItem)
+{
+ if(!impl) return new SVGPathSeg(0);
+ return new SVGPathSeg(impl->appendItem(newItem->handle()));
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathSegList.h b/ksvg/dom/SVGPathSegList.h
new file mode 100644
index 00000000..b9feca72
--- /dev/null
+++ b/ksvg/dom/SVGPathSegList.h
@@ -0,0 +1,59 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathSegList_H
+#define SVGPathSegList_H
+
+namespace KSVG
+{
+
+class SVGPathSeg;
+class SVGPathSegListImpl;
+class SVGPathSegList
+{
+public:
+ SVGPathSegList();
+ SVGPathSegList(const SVGPathSegList &);
+ SVGPathSegList &operator=(const SVGPathSegList &other);
+ SVGPathSegList(SVGPathSegListImpl *);
+ ~SVGPathSegList();
+
+ unsigned long numberOfItems() const;
+ void clear();
+
+ SVGPathSeg *initialize(SVGPathSeg *newItem);
+ SVGPathSeg *getItem(unsigned long index);
+ SVGPathSeg *insertItemBefore(SVGPathSeg *newItem, unsigned long index);
+ SVGPathSeg *replaceItem(SVGPathSeg *newItem, unsigned long index);
+ SVGPathSeg *removeItem(unsigned long index);
+ SVGPathSeg *appendItem(SVGPathSeg *newItem);
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPathSegListImpl *handle() const { return impl; }
+
+private:
+ SVGPathSegListImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathSegMoveto.cc b/ksvg/dom/SVGPathSegMoveto.cc
new file mode 100644
index 00000000..c5a1dac0
--- /dev/null
+++ b/ksvg/dom/SVGPathSegMoveto.cc
@@ -0,0 +1,118 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGPathSegMoveto.h"
+#include "SVGPathSegMovetoImpl.h"
+
+using namespace KSVG;
+
+SVGPathSegMovetoAbs::SVGPathSegMovetoAbs() : SVGPathSeg()
+{
+ impl = new SVGPathSegMovetoAbsImpl();
+}
+
+SVGPathSegMovetoAbs::SVGPathSegMovetoAbs(const SVGPathSegMovetoAbs &other) : SVGPathSeg(other)
+{
+ impl = other.impl;
+}
+
+SVGPathSegMovetoAbs::SVGPathSegMovetoAbs(SVGPathSegMovetoAbsImpl *other) : SVGPathSeg(other)
+{
+ impl = other;
+}
+
+SVGPathSegMovetoAbs::~SVGPathSegMovetoAbs()
+{
+ delete impl;
+}
+
+void SVGPathSegMovetoAbs::setX(const float &x)
+{
+ if(impl)
+ impl->setX(x);
+}
+
+float SVGPathSegMovetoAbs::x() const
+{
+ if(!impl) return -1;
+ return impl->x();
+}
+
+void SVGPathSegMovetoAbs::setY(const float &y)
+{
+ if(impl)
+ impl->setY(y);
+}
+
+float SVGPathSegMovetoAbs::y() const
+{
+ if(!impl) return -1;
+ return impl->y();
+}
+
+
+
+
+
+SVGPathSegMovetoRel::SVGPathSegMovetoRel() : SVGPathSeg()
+{
+ impl = new SVGPathSegMovetoRelImpl();
+}
+
+SVGPathSegMovetoRel::SVGPathSegMovetoRel(const SVGPathSegMovetoRel &other) : SVGPathSeg(other)
+{
+ impl = other.impl;
+}
+
+SVGPathSegMovetoRel::SVGPathSegMovetoRel(SVGPathSegMovetoRelImpl *other) : SVGPathSeg(other)
+{
+ impl = other;
+}
+
+SVGPathSegMovetoRel::~SVGPathSegMovetoRel()
+{
+ delete impl;
+}
+
+void SVGPathSegMovetoRel::setX(const float &x)
+{
+ if(impl)
+ impl->setX(x);
+}
+
+float SVGPathSegMovetoRel::x() const
+{
+ if(!impl) return -1;
+ return impl->x();
+}
+
+void SVGPathSegMovetoRel::setY(const float &y)
+{
+ if(impl)
+ impl->setY(y);
+}
+
+float SVGPathSegMovetoRel::y() const
+{
+ if(!impl) return -1;
+ return impl->y();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPathSegMoveto.h b/ksvg/dom/SVGPathSegMoveto.h
new file mode 100644
index 00000000..874443c3
--- /dev/null
+++ b/ksvg/dom/SVGPathSegMoveto.h
@@ -0,0 +1,79 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathSegMoveto_H
+#define SVGPathSegMoveto_H
+
+#include "SVGPathSeg.h"
+
+namespace KSVG
+{
+
+class SVGPathSegMovetoAbsImpl;
+class SVGPathSegMovetoAbs : public SVGPathSeg
+{
+public:
+ SVGPathSegMovetoAbs();
+ SVGPathSegMovetoAbs(const SVGPathSegMovetoAbs &);
+ SVGPathSegMovetoAbs &operator=(const SVGPathSegMovetoAbs &other);
+ SVGPathSegMovetoAbs(SVGPathSegMovetoAbsImpl *);
+ ~SVGPathSegMovetoAbs();
+
+ void setX(const float &);
+ float x() const;
+
+ void setY(const float &);
+ float y() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPathSegMovetoAbsImpl *handle() const { return impl; }
+
+private:
+ SVGPathSegMovetoAbsImpl *impl;
+};
+
+class SVGPathSegMovetoRelImpl;
+class SVGPathSegMovetoRel : public SVGPathSeg
+{
+public:
+ SVGPathSegMovetoRel();
+ SVGPathSegMovetoRel(const SVGPathSegMovetoRel &);
+ SVGPathSegMovetoRel &operator=(const SVGPathSegMovetoRel &other);
+ SVGPathSegMovetoRel(SVGPathSegMovetoRelImpl *);
+ ~SVGPathSegMovetoRel();
+
+ void setX(const float &);
+ float x() const;
+
+ void setY(const float &);
+ float y() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPathSegMovetoRelImpl *handle() const { return impl; }
+
+private:
+ SVGPathSegMovetoRelImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPatternElement.cc b/ksvg/dom/SVGPatternElement.cc
new file mode 100644
index 00000000..fc387a97
--- /dev/null
+++ b/ksvg/dom/SVGPatternElement.cc
@@ -0,0 +1,117 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGPatternElement.h"
+#include "SVGPatternElementImpl.h"
+#include "SVGAnimatedTransformList.h"
+#include "SVGAnimatedLength.h"
+#include "SVGAnimatedEnumeration.h"
+
+using namespace KSVG;
+
+SVGPatternElement::SVGPatternElement() : SVGElement(), SVGURIReference(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGFitToViewBox(), SVGUnitTypes()
+{
+ impl = 0;
+}
+
+SVGPatternElement::SVGPatternElement(const SVGPatternElement &other) : SVGElement(other), SVGURIReference(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGFitToViewBox(other), SVGUnitTypes(), impl(0)
+{
+ (*this) = other;
+}
+
+SVGPatternElement &SVGPatternElement::operator =(const SVGPatternElement &other)
+{
+ SVGElement::operator=(other);
+ SVGTests::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+ SVGFitToViewBox::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGPatternElement::SVGPatternElement(SVGPatternElementImpl *other) : SVGElement(other), SVGURIReference(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGFitToViewBox(other), SVGUnitTypes()
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGPatternElement::~SVGPatternElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedEnumeration SVGPatternElement::patternUnits() const
+{
+ if(!impl) return SVGAnimatedEnumeration(0);
+ return SVGAnimatedEnumeration(impl->patternUnits());
+}
+
+SVGAnimatedEnumeration SVGPatternElement::patternContentUnits() const
+{
+ if(!impl) return SVGAnimatedEnumeration(0);
+ return SVGAnimatedEnumeration(impl->patternContentUnits());
+}
+
+SVGAnimatedTransformList SVGPatternElement::patternTransform() const
+{
+ if(!impl) return SVGAnimatedTransformList(0);
+ return SVGAnimatedTransformList(impl->patternTransform());
+}
+
+SVGAnimatedLength SVGPatternElement::x() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->x());
+}
+
+SVGAnimatedLength SVGPatternElement::y() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->y());
+}
+
+SVGAnimatedLength SVGPatternElement::width() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->width());
+}
+
+SVGAnimatedLength SVGPatternElement::height() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->height());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPatternElement.h b/ksvg/dom/SVGPatternElement.h
new file mode 100644
index 00000000..9caf5c14
--- /dev/null
+++ b/ksvg/dom/SVGPatternElement.h
@@ -0,0 +1,188 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+
+ This file includes excerpts from the Scalable Vector Graphics
+ (SVG) 1.0 Specification (Proposed Recommendation)
+ http://www.w3.org/TR/SVG
+
+ Copyright 2001 World Wide Web Consortium, (Massachusetts
+ Institute of Technology, Institut National de Recherche en
+ Informatique et en Automatique, Keio University).
+ All Rights Reserved.
+*/
+
+#ifndef SVGPatternElement_H
+#define SVGPatternElement_H
+
+#include "SVGElement.h"
+#include "SVGURIReference.h"
+#include "SVGTests.h"
+#include "SVGLangSpace.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+#include "SVGFitToViewBox.h"
+#include "SVGUnitTypes.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedEnumeration;
+class SVGAnimatedTransformList;
+class SVGAnimatedLength;
+class SVGPatternElementImpl;
+
+/**
+ * A pattern is used to fill or stroke an object using a pre-defined graphic object which can be
+ * replicated ("tiled") at fixed intervals in x and y to cover the areas to be painted.
+ *
+ * Patterns are defined using a 'pattern' element and then referenced by properties 'fill' and 'stroke'
+ * on a given graphics element to indicate that the given element shall be filled or stroked with the
+ * referenced pattern.
+ */
+class SVGPatternElement : public SVGElement,
+ public SVGURIReference,
+ public SVGTests,
+ public SVGLangSpace,
+ public SVGExternalResourcesRequired,
+ public SVGStylable,
+ public SVGFitToViewBox,
+ public SVGUnitTypes
+{
+public:
+ SVGPatternElement();
+ SVGPatternElement(const SVGPatternElement &other);
+ SVGPatternElement &operator=(const SVGPatternElement &other);
+ SVGPatternElement(SVGPatternElementImpl *other);
+ virtual ~SVGPatternElement();
+
+ /**
+ * Defines the coordinate system for attributes <code>x</code>, <code>y</code>, <code>width</code>, <code>height</code>.
+ * If patternUnits="userSpaceOnUse", <code>x</code>, <code>y</code>, <code>width</code>, <code>height</code> represent
+ * values in the coordinate system that results from taking the current user coordinate system in place at the time when
+ * the 'pattern' element is referenced (i.e., the user coordinate system for the element referencing the 'pattern' element
+ * via a 'fill' or 'stroke' property) and then applying the transform specified by attribute patternTransform.
+ * If patternUnits="objectBoundingBox", the user coordinate system for attributes <code>x</code>, <code>y</code>, <code>width</code>,
+ * <code>height</code> is established using the bounding box of the element to which the pattern is applied and then applying
+ * the transform specified by attribute <code>patternTransform</code>.
+ * If attribute <code>patternUnits</code> is not specified, then the effect is as if a value of objectBoundingBox were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The current target coordinate system mode.
+ */
+ SVGAnimatedEnumeration patternUnits() const;
+
+ /**
+ * Defines the coordinate system for the contents of the 'pattern'. Note that this attribute has no effect
+ * if attribute <code>viewBox</code> is specified.
+ * If patternContentUnits="userSpaceOnUse", the user coordinate system for the contents of the 'pattern' element
+ * is the coordinate system that results from taking the current user coordinate system in place at the time
+ * when the 'pattern' element is referenced (i.e., the user coordinate system for the element referencing the
+ * 'pattern' element via a 'fill' or 'stroke' property) and then applying the transform specified by attribute
+ * <code>patternTransform</code>.
+ * If patternContentUnits="objectBoundingBox", the user coordinate system for the contents of the 'pattern' element
+ * is established using the bounding box of the element to which the pattern is applied and then applying the
+ * transform specified by attribute <code>patternTransform</code>.
+ * If attribute <code>patternContentUnits</code> is not specified, then the effect is as if a value of
+ * userSpaceOnUse were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The current content coordinate system mode.
+ */
+ SVGAnimatedEnumeration patternContentUnits() const;
+
+ /**
+ * Contains the definition of an optional additional transformation from the pattern coordinate
+ * system onto the target coordinate system (i.e., userSpaceOnUse or objectBoundingBox).
+ * This allows for things such as skewing the pattern tiles. This additional transformation
+ * matrix is post-multiplied to (i.e., inserted to the right of) any previously defined
+ * transformations, including the implicit transformation necessary to convert from object
+ * bounding box units to user space.
+ * If attribute <code>patternTransform</code> is not specified, then the effect is as if an identity transform
+ * were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The transformation list that is applied to the pattern tile.
+ */
+ SVGAnimatedTransformList patternTransform() const;
+
+ /**
+ * The attributes <code>x</code>, <code>y</code>, <code>width</code>, <code>height</code>
+ * indicate how the pattern tiles are placed and spaced.
+ * These attributes represent coordinates and values in the coordinate space specified by
+ * the combination of attributes <code>patternUnits</code> and <code>patternTransform</code>.
+ * If the attribute is not specified, the effect is as if a value of zero were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The x-axis coordinate of the pattern tile.
+ */
+ SVGAnimatedLength x() const;
+
+ /**
+ * @see x
+ * If the attribute is not specified, the effect is as if a value of zero were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The y-axis coordinate of the pattern tile.
+ */
+ SVGAnimatedLength y() const;
+
+ /**
+ * @see x
+ * A negative value is an error. A value of zero disables rendering of
+ * the element (i.e., no paint is applied).
+ *
+ * If the attribute is not specified, the effect is as if a value of zero were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The width of the pattern tile.
+ */
+ SVGAnimatedLength width() const;
+
+ /**
+ * @see x
+ * A negative value is an error. A value of zero disables rendering of
+ * the element (i.e., no paint is applied).
+ *
+ * If the attribute is not specified, the effect is as if a value of zero were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The height coordinate of the pattern tile.
+ */
+ SVGAnimatedLength height() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPatternElementImpl *handle() const { return impl; }
+
+private:
+ SVGPatternElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPoint.cc b/ksvg/dom/SVGPoint.cc
new file mode 100644
index 00000000..ac194e7e
--- /dev/null
+++ b/ksvg/dom/SVGPoint.cc
@@ -0,0 +1,97 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGPoint.h"
+#include "SVGMatrix.h"
+#include "SVGPointImpl.h"
+
+using namespace KSVG;
+
+SVGPoint::SVGPoint()
+{
+ impl = new SVGPointImpl();
+ impl->ref();
+}
+
+SVGPoint::SVGPoint(const SVGPoint &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGPoint &SVGPoint::operator=(const SVGPoint &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGPoint::SVGPoint(SVGPointImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGPoint::~SVGPoint()
+{
+ if(impl)
+ impl->deref();
+}
+
+void SVGPoint::setX(float x)
+{
+ if(impl)
+ impl->setX(x);
+}
+
+float SVGPoint::x()
+{
+ if(!impl) return -1;
+ return impl->x();
+}
+
+void SVGPoint::setY(float y)
+{
+ if(impl)
+ impl->setY(y);
+}
+
+float SVGPoint::y()
+{
+ if(!impl) return -1;
+ return impl->y();
+}
+
+SVGPoint SVGPoint::matrixTransform(SVGMatrix &matrix)
+{
+ if(!impl) return SVGPoint(0);
+ return SVGPoint(impl->matrixTransform(*matrix.handle()));
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPoint.h b/ksvg/dom/SVGPoint.h
new file mode 100644
index 00000000..84b38e86
--- /dev/null
+++ b/ksvg/dom/SVGPoint.h
@@ -0,0 +1,57 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPoint_H
+#define SVGPoint_H
+
+namespace KSVG
+{
+
+class SVGMatrix;
+class SVGPointImpl;
+class SVGPoint
+{
+public:
+ SVGPoint();
+ SVGPoint(const SVGPoint &);
+ SVGPoint &operator=(const SVGPoint &);
+ SVGPoint(SVGPointImpl *);
+ ~SVGPoint();
+
+ void setX(float x);
+ float x();
+
+ void setY(float y);
+ float y();
+
+ SVGPoint matrixTransform(SVGMatrix &matrix);
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPointImpl *handle() const { return impl; }
+
+private:
+ SVGPointImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPointList.cc b/ksvg/dom/SVGPointList.cc
new file mode 100644
index 00000000..963b1c60
--- /dev/null
+++ b/ksvg/dom/SVGPointList.cc
@@ -0,0 +1,114 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGPoint.h"
+#include "SVGPointImpl.h"
+#include "SVGPointList.h"
+#include "SVGPointListImpl.h"
+
+using namespace KSVG;
+
+SVGPointList::SVGPointList()
+{
+ impl = new SVGPointListImpl();
+ impl->ref();
+}
+
+SVGPointList::SVGPointList(const SVGPointList &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGPointList &SVGPointList::operator=(const SVGPointList &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGPointList::SVGPointList(SVGPointListImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGPointList::~SVGPointList()
+{
+ if(impl)
+ impl->deref();
+}
+
+unsigned long SVGPointList::numberOfItems() const
+{
+ if(!impl) return 0;
+ return impl->numberOfItems();
+}
+
+void SVGPointList::clear()
+{
+ if(impl)
+ impl->clear();
+}
+
+SVGPoint *SVGPointList::initialize(SVGPoint *newItem)
+{
+ if(!impl) return new SVGPoint(0);
+ return new SVGPoint(impl->initialize(newItem->handle()));
+}
+
+SVGPoint *SVGPointList::getItem(unsigned long index)
+{
+ if(!impl) return new SVGPoint(0);
+ return new SVGPoint(impl->getItem(index));
+}
+
+SVGPoint *SVGPointList::insertItemBefore(SVGPoint *newItem, unsigned long index)
+{
+ if(!impl) return new SVGPoint(0);
+ return new SVGPoint(impl->insertItemBefore(newItem->handle(), index));
+}
+
+SVGPoint *SVGPointList::replaceItem(SVGPoint *newItem, unsigned long index)
+{
+ if(!impl) return new SVGPoint(0);
+ return new SVGPoint(impl->replaceItem(newItem->handle(), index));
+}
+
+SVGPoint *SVGPointList::removeItem(unsigned long index)
+{
+ if(!impl) return new SVGPoint(0);
+ return new SVGPoint(impl->removeItem(index));
+}
+
+SVGPoint *SVGPointList::appendItem(SVGPoint *newItem)
+{
+ if(!impl) return new SVGPoint(0);
+ return new SVGPoint(impl->appendItem(newItem->handle()));
+}
diff --git a/ksvg/dom/SVGPointList.h b/ksvg/dom/SVGPointList.h
new file mode 100644
index 00000000..cfdec4c5
--- /dev/null
+++ b/ksvg/dom/SVGPointList.h
@@ -0,0 +1,57 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPointList_H
+#define SVGPointList_H
+
+namespace KSVG
+{
+
+class SVGPoint;
+class SVGPointListImpl;
+class SVGPointList
+{
+public:
+ SVGPointList();
+ SVGPointList(const SVGPointList &);
+ SVGPointList &operator=(const SVGPointList &);
+ SVGPointList(SVGPointListImpl *);
+ ~SVGPointList();
+
+ unsigned long numberOfItems() const;
+ void clear();
+
+ SVGPoint *initialize(SVGPoint *newItem);
+ SVGPoint *getItem(unsigned long index);
+ SVGPoint *insertItemBefore(SVGPoint *newItem, unsigned long index);
+ SVGPoint *replaceItem(SVGPoint *newItem, unsigned long index);
+ SVGPoint *removeItem(unsigned long index);
+ SVGPoint *appendItem(SVGPoint *newItem);
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPointListImpl *handle() const { return impl; }
+
+private:
+ SVGPointListImpl *impl;
+};
+
+}
+
+#endif
diff --git a/ksvg/dom/SVGPolygonElement.cc b/ksvg/dom/SVGPolygonElement.cc
new file mode 100644
index 00000000..043c19df
--- /dev/null
+++ b/ksvg/dom/SVGPolygonElement.cc
@@ -0,0 +1,84 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+#include "SVGPolygonElement.h"
+#include "SVGPolygonElementImpl.h"
+#include "SVGPointList.h"
+
+using namespace KSVG;
+
+SVGPolygonElement::SVGPolygonElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable(), SVGAnimatedPoints()
+{
+ impl = 0;
+}
+
+SVGPolygonElement::SVGPolygonElement(const SVGPolygonElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), SVGAnimatedPoints(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGPolygonElement &SVGPolygonElement::operator=(const SVGPolygonElement &other)
+{
+ SVGElement::operator=(other);
+ SVGTests::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+ SVGTransformable::operator=(other);
+ SVGAnimatedPoints::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+ return *this;
+}
+
+SVGPolygonElement::SVGPolygonElement(SVGPolygonElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), SVGAnimatedPoints(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGPolygonElement::~SVGPolygonElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGPointList SVGPolygonElement::points()
+{
+ if(!impl) return SVGPointList(0);
+ return SVGPointList(impl->points());
+}
+
+SVGPointList SVGPolygonElement::animatedPoints()
+{
+ if(!impl) return SVGPointList(0);
+ return SVGPointList(impl->animatedPoints());
+}
diff --git a/ksvg/dom/SVGPolygonElement.h b/ksvg/dom/SVGPolygonElement.h
new file mode 100644
index 00000000..526e9815
--- /dev/null
+++ b/ksvg/dom/SVGPolygonElement.h
@@ -0,0 +1,106 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; see the file COPYING.LIB. If
+ not, write to the Free Software Foundation, Inc., 51 Franklin Street,
+ Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+ This file includes excerpts from the Scalable Vector Graphics
+ (SVG) 1.0 Specification (Proposed Recommendation)
+ http://www.w3.org/TR/SVG
+
+ Copyright 2001 World Wide Web Consortium, (Massachusetts
+ Institute of Technology, Institut National de Recherche en
+ Informatique et en Automatique, Keio University).
+ All Rights Reserved.
+
+ $Id$
+ */
+
+#ifndef SVGPolygonElement_H
+#define SVGPolygonElement_H
+
+#include "SVGElement.h"
+#include "SVGTests.h"
+#include "SVGLangSpace.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+#include "SVGTransformable.h"
+#include "SVGAnimatedPoints.h"
+
+namespace KSVG
+{
+
+class SVGPointList;
+class SVGPolygonElementImpl;
+
+/**
+ * The <code>polygon</code> element defines a closed shape consisting
+ * of connected straight line segments.
+ *
+ * For more info look here : <a href =
+ * "http://www.w3.org/TR/SVG/shapes.html#PolylineElement">9.7 The
+ * 'polygon' element</a>.
+ */
+class SVGPolygonElement : public SVGElement,
+ public SVGTests,
+ public SVGLangSpace,
+ public SVGExternalResourcesRequired,
+ public SVGStylable,
+ public SVGTransformable,
+ public SVGAnimatedPoints
+{
+public:
+ SVGPolygonElement();
+ SVGPolygonElement(const SVGPolygonElement &);
+ SVGPolygonElement &operator=(const SVGPolygonElement &);
+ SVGPolygonElement(SVGPolygonElementImpl *);
+ ~SVGPolygonElement();
+
+ /**
+ * Provides access to the base (i.e., static) contents of the
+ * points attribute.
+ *
+ * @return A static list of the polygons points
+ */
+ SVGPointList points();
+
+ /**
+ * Provides access to the current animated contents of the points
+ * attribute.
+ * If the given attribute or property is being animated, contains
+ * the current animated value of the attribute or property.
+ * If the given attribute or property is not currently being
+ * animated, contains the same value as <code>points</code>'.
+ *
+ * This attribute is animatable.
+ *
+ * @return A list of the polygons points
+ */
+ SVGPointList animatedPoints();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPolygonElementImpl *handle() const { return impl; }
+
+private:
+ SVGPolygonElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPolylineElement.cc b/ksvg/dom/SVGPolylineElement.cc
new file mode 100644
index 00000000..789c5847
--- /dev/null
+++ b/ksvg/dom/SVGPolylineElement.cc
@@ -0,0 +1,85 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+#include "SVGPolylineElement.h"
+#include "SVGPolylineElementImpl.h"
+#include "SVGPointList.h"
+
+using namespace KSVG;
+
+SVGPolylineElement::SVGPolylineElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable(), SVGAnimatedPoints()
+{
+ impl = 0;
+}
+
+SVGPolylineElement::SVGPolylineElement(const SVGPolylineElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), SVGAnimatedPoints(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGPolylineElement &SVGPolylineElement::operator=(const SVGPolylineElement &other)
+{
+ SVGElement::operator=(other);
+ SVGTests::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+ SVGTransformable::operator=(other);
+ SVGAnimatedPoints::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGPolylineElement::SVGPolylineElement(SVGPolylineElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), SVGAnimatedPoints(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGPolylineElement::~SVGPolylineElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGPointList SVGPolylineElement::points()
+{
+ if(!impl) return SVGPointList(0);
+ return SVGPointList(impl->points());
+}
+
+SVGPointList SVGPolylineElement::animatedPoints()
+{
+ if(!impl) return SVGPointList(0);
+ return SVGPointList(impl->animatedPoints());
+}
diff --git a/ksvg/dom/SVGPolylineElement.h b/ksvg/dom/SVGPolylineElement.h
new file mode 100644
index 00000000..35e948f7
--- /dev/null
+++ b/ksvg/dom/SVGPolylineElement.h
@@ -0,0 +1,106 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; see the file COPYING.LIB. If
+ not, write to the Free Software Foundation, Inc., 51 Franklin Street,
+ Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+ This file includes excerpts from the Scalable Vector Graphics
+ (SVG) 1.0 Specification (Proposed Recommendation)
+ http://www.w3.org/TR/SVG
+
+ Copyright 2001 World Wide Web Consortium, (Massachusetts
+ Institute of Technology, Institut National de Recherche en
+ Informatique et en Automatique, Keio University).
+ All Rights Reserved.
+
+ $Id$
+ */
+
+#ifndef SVGPolylineElement_H
+#define SVGPolylineElement_H
+
+#include "SVGElement.h"
+#include "SVGTests.h"
+#include "SVGLangSpace.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+#include "SVGTransformable.h"
+#include "SVGAnimatedPoints.h"
+
+namespace KSVG
+{
+
+/**
+ * The <code>polyline</code> element defines a set of connected
+ * straight line segments. Typically, <code>polyline</code> elements
+ * define open shapes.
+ *
+ * For more info look here : <a href =
+ * "http://www.w3.org/TR/SVG/shapes.html#PolylineElement">9.6 The
+ * 'polyline' element</a>.
+ */
+class SVGPointList;
+class SVGPolylineElementImpl;
+class SVGPolylineElement : public SVGElement,
+ public SVGTests,
+ public SVGLangSpace,
+ public SVGExternalResourcesRequired,
+ public SVGStylable,
+ public SVGTransformable,
+ public SVGAnimatedPoints
+{
+public:
+ SVGPolylineElement();
+ SVGPolylineElement(const SVGPolylineElement &);
+ SVGPolylineElement &operator=(const SVGPolylineElement &);
+ SVGPolylineElement(SVGPolylineElementImpl *);
+ ~SVGPolylineElement();
+
+ /**
+ * Provides access to the base (i.e., static) contents of the
+ * points attribute.
+ *
+ * @return A static list of the polygons points
+ */
+ SVGPointList points();
+
+ /**
+ * Provides access to the current animated contents of the points
+ * attribute.
+ * If the given attribute or property is being animated, contains
+ * the current animated value of the attribute or property.
+ * If the given attribute or property is not currently being
+ * animated, contains the same value as <code>points</code>'.
+ *
+ * This attribute is animatable.
+ *
+ * @return A list of the polygons points
+ */
+ SVGPointList animatedPoints();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPolylineElementImpl *handle() const { return impl; }
+
+private:
+ SVGPolylineElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPreserveAspectRatio.cc b/ksvg/dom/SVGPreserveAspectRatio.cc
new file mode 100644
index 00000000..f86ca1b4
--- /dev/null
+++ b/ksvg/dom/SVGPreserveAspectRatio.cc
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGPreserveAspectRatio.h"
+#include "SVGPreserveAspectRatioImpl.h"
+
+using namespace KSVG;
+
+SVGPreserveAspectRatio::SVGPreserveAspectRatio()
+{
+ impl = new SVGPreserveAspectRatioImpl();
+}
+
+SVGPreserveAspectRatio::SVGPreserveAspectRatio(const SVGPreserveAspectRatio &other)
+{
+ impl = other.impl;
+}
+
+SVGPreserveAspectRatio &SVGPreserveAspectRatio::operator=(const SVGPreserveAspectRatio &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ delete impl;
+ impl = other.impl;
+
+ return *this;
+}
+
+SVGPreserveAspectRatio::SVGPreserveAspectRatio(SVGPreserveAspectRatioImpl *other)
+{
+ impl = other;
+}
+
+SVGPreserveAspectRatio::~SVGPreserveAspectRatio()
+{
+ delete impl;
+}
+
+void SVGPreserveAspectRatio::setAlign(unsigned short align)
+{
+ if(impl)
+ impl->setAlign(align);
+}
+
+unsigned short SVGPreserveAspectRatio::align() const
+{
+ if(!impl) return SVG_PRESERVEASPECTRATIO_UNKNOWN;
+ return impl->align();
+}
+
+void SVGPreserveAspectRatio::setMeetOrSlice(unsigned short meetOrSlice)
+{
+ if(impl)
+ impl->setMeetOrSlice(meetOrSlice);
+}
+
+unsigned short SVGPreserveAspectRatio::meetOrSlice() const
+{
+ if(!impl) return SVG_MEETORSLICE_UNKNOWN;
+ return impl->meetOrSlice();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGPreserveAspectRatio.h b/ksvg/dom/SVGPreserveAspectRatio.h
new file mode 100644
index 00000000..3c1a4823
--- /dev/null
+++ b/ksvg/dom/SVGPreserveAspectRatio.h
@@ -0,0 +1,76 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPreserveAspectRatio_H
+#define SVGPreserveAspectRatio_H
+
+namespace KSVG
+{
+
+enum
+{
+ SVG_PRESERVEASPECTRATIO_UNKNOWN = 0,
+ SVG_PRESERVEASPECTRATIO_NONE = 1,
+ SVG_PRESERVEASPECTRATIO_XMINYMIN = 2,
+ SVG_PRESERVEASPECTRATIO_XMIDYMIN = 3,
+ SVG_PRESERVEASPECTRATIO_XMAXYMIN = 4,
+ SVG_PRESERVEASPECTRATIO_XMINYMID = 5,
+ SVG_PRESERVEASPECTRATIO_XMIDYMID = 6,
+ SVG_PRESERVEASPECTRATIO_XMAXYMID = 7,
+ SVG_PRESERVEASPECTRATIO_XMINYMAX = 8,
+ SVG_PRESERVEASPECTRATIO_XMIDYMAX = 9,
+ SVG_PRESERVEASPECTRATIO_XMAXYMAX = 10
+};
+
+enum
+{
+ SVG_MEETORSLICE_UNKNOWN = 0,
+ SVG_MEETORSLICE_MEET = 1,
+ SVG_MEETORSLICE_SLICE = 2
+};
+
+class SVGPreserveAspectRatioImpl;
+class SVGPreserveAspectRatio
+{
+public:
+ SVGPreserveAspectRatio();
+ SVGPreserveAspectRatio(const SVGPreserveAspectRatio &);
+ SVGPreserveAspectRatio &operator=(const SVGPreserveAspectRatio &other);
+ SVGPreserveAspectRatio(SVGPreserveAspectRatioImpl *);
+ ~SVGPreserveAspectRatio();
+
+ void setAlign(unsigned short);
+ unsigned short align() const;
+
+ void setMeetOrSlice(unsigned short);
+ unsigned short meetOrSlice() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGPreserveAspectRatioImpl *handle() const { return impl; }
+
+protected:
+ SVGPreserveAspectRatioImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGRadialGradientElement.cc b/ksvg/dom/SVGRadialGradientElement.cc
new file mode 100644
index 00000000..02f3d5f2
--- /dev/null
+++ b/ksvg/dom/SVGRadialGradientElement.cc
@@ -0,0 +1,98 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGRadialGradientElement.h"
+#include "SVGRadialGradientElementImpl.h"
+#include "SVGAnimatedLength.h"
+
+using namespace KSVG;
+
+SVGRadialGradientElement::SVGRadialGradientElement() : SVGGradientElement()
+{
+ impl = 0;
+}
+
+SVGRadialGradientElement::SVGRadialGradientElement(const SVGRadialGradientElement &other) : SVGGradientElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGRadialGradientElement &SVGRadialGradientElement::operator =(const SVGRadialGradientElement &other)
+{
+ SVGGradientElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGRadialGradientElement::SVGRadialGradientElement(SVGRadialGradientElementImpl *other) : SVGGradientElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGRadialGradientElement::~SVGRadialGradientElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedLength SVGRadialGradientElement::cx() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->cx());
+}
+
+SVGAnimatedLength SVGRadialGradientElement::cy() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->cy());
+}
+
+SVGAnimatedLength SVGRadialGradientElement::r() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->r());
+}
+
+SVGAnimatedLength SVGRadialGradientElement::fx() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->fx());
+}
+
+SVGAnimatedLength SVGRadialGradientElement::fy() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->fy());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGRadialGradientElement.h b/ksvg/dom/SVGRadialGradientElement.h
new file mode 100644
index 00000000..c60a00ed
--- /dev/null
+++ b/ksvg/dom/SVGRadialGradientElement.h
@@ -0,0 +1,57 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGRadialGradientElement_H
+#define SVGRadialGradientElement_H
+
+#include "SVGGradientElement.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedLength;
+class SVGRadialGradientElementImpl;
+class SVGRadialGradientElement : public SVGGradientElement
+{
+public:
+ SVGRadialGradientElement();
+ SVGRadialGradientElement(const SVGRadialGradientElement &other);
+ SVGRadialGradientElement &operator=(const SVGRadialGradientElement &other);
+ SVGRadialGradientElement(SVGRadialGradientElementImpl *other);
+ virtual ~SVGRadialGradientElement();
+
+ SVGAnimatedLength cx() const;
+ SVGAnimatedLength cy() const;
+ SVGAnimatedLength r() const;
+ SVGAnimatedLength fx() const;
+ SVGAnimatedLength fy() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGRadialGradientElementImpl *handle() const { return impl; }
+
+private:
+ SVGRadialGradientElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGRect.cc b/ksvg/dom/SVGRect.cc
new file mode 100644
index 00000000..39ba48a4
--- /dev/null
+++ b/ksvg/dom/SVGRect.cc
@@ -0,0 +1,114 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGRect.h"
+#include "SVGRectImpl.h"
+
+using namespace KSVG;
+
+SVGRect::SVGRect()
+{
+ impl = new SVGRectImpl();
+ impl->ref();
+}
+
+SVGRect::SVGRect(const SVGRect &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGRect &SVGRect::operator=(const SVGRect &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGRect::SVGRect(SVGRectImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGRect::~SVGRect()
+{
+ if(impl)
+ impl->deref();
+}
+
+void SVGRect::setX(float x)
+{
+ if(impl)
+ impl->setX(x);
+}
+
+float SVGRect::x() const
+{
+ if(!impl) return -1;
+ return impl->x();
+}
+
+void SVGRect::setY(float y)
+{
+ if(impl)
+ impl->setY(y);
+}
+
+float SVGRect::y() const
+{
+ if(!impl) return -1;
+ return impl->y();
+}
+
+void SVGRect::setWidth(float width)
+{
+ if(impl)
+ impl->setWidth(width);
+}
+
+float SVGRect::width() const
+{
+ if(!impl) return -1;
+ return impl->width();
+}
+
+void SVGRect::setHeight(float height)
+{
+ if(impl)
+ impl->setHeight(height);
+}
+
+float SVGRect::height() const
+{
+ if(!impl) return -1;
+ return impl->height();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGRect.h b/ksvg/dom/SVGRect.h
new file mode 100644
index 00000000..e9be6849
--- /dev/null
+++ b/ksvg/dom/SVGRect.h
@@ -0,0 +1,87 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+
+ This file includes excerpts from the Scalable Vector Graphics
+ (SVG) 1.0 Specification (Proposed Recommendation)
+ http://www.w3.org/TR/SVG
+
+ Copyright 2001 World Wide Web Consortium, (Massachusetts
+ Institute of Technology, Institut National de Recherche en
+ Informatique et en Automatique, Keio University).
+ All Rights Reserved.
+*/
+
+#ifndef SVGRect_H
+#define SVGRect_H
+
+namespace KSVG
+{
+
+/**
+ * Rectangles are defined as consisting of a (x,y) coordinate pair
+ * identifying a minimum X value, a minimum Y value, and a width and
+ * height, which are usually constrained to be non-negative.
+ */
+class SVGRectImpl;
+class SVGRect
+{
+public:
+ SVGRect();
+ SVGRect(const SVGRect &);
+ SVGRect &operator=(const SVGRect &);
+ SVGRect(SVGRectImpl *);
+ ~SVGRect();
+
+ /**
+ * Corresponds to attribute <code>x</code> on the given element.
+ */
+ void setX(float x);
+ float x() const;
+
+ /**
+ * Corresponds to attribute <code>y</code> on the given element.
+ */
+ void setY(float y);
+ float y() const;
+
+ /**
+ * Corresponds to attribute <code>width</code> on the given element.
+ */
+ void setWidth(float width);
+ float width() const;
+
+ /**
+ * Corresponds to attribute <code>height</code> on the given element.
+ */
+ void setHeight(float height);
+ float height() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGRectImpl *handle() const { return impl; }
+
+private:
+ SVGRectImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGRectElement.cc b/ksvg/dom/SVGRectElement.cc
new file mode 100644
index 00000000..ef4038d4
--- /dev/null
+++ b/ksvg/dom/SVGRectElement.cc
@@ -0,0 +1,109 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGRectElement.h"
+#include "SVGRectElementImpl.h"
+#include "SVGAnimatedLength.h"
+
+using namespace KSVG;
+
+SVGRectElement::SVGRectElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable()
+{
+ impl = 0;
+}
+
+SVGRectElement::SVGRectElement(const SVGRectElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGRectElement &SVGRectElement::operator=(const SVGRectElement &other)
+{
+ SVGElement::operator=(other);
+ SVGTests::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+ SVGTransformable::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGRectElement::SVGRectElement(SVGRectElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGRectElement::~SVGRectElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedLength SVGRectElement::x()
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->x());
+}
+
+SVGAnimatedLength SVGRectElement::y()
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->y());
+}
+
+SVGAnimatedLength SVGRectElement::width()
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->width());
+}
+
+SVGAnimatedLength SVGRectElement::height()
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->height());
+}
+
+SVGAnimatedLength SVGRectElement::rx()
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->rx());
+}
+
+SVGAnimatedLength SVGRectElement::ry()
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->ry());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGRectElement.h b/ksvg/dom/SVGRectElement.h
new file mode 100644
index 00000000..2a77420d
--- /dev/null
+++ b/ksvg/dom/SVGRectElement.h
@@ -0,0 +1,173 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; see the file COPYING.LIB. If
+ not, write to the Free Software Foundation, Inc., 51 Franklin Street,
+ Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+ This file includes excerpts from the Scalable Vector Graphics
+ (SVG) 1.0 Specification (Proposed Recommendation)
+ http://www.w3.org/TR/SVG
+
+ Copyright 2001 World Wide Web Consortium, (Massachusetts
+ Institute of Technology, Institut National de Recherche en
+ Informatique et en Automatique, Keio University).
+ All Rights Reserved.
+
+ $Id$
+ */
+
+#ifndef SVGRectElement_H
+#define SVGRectElement_H
+
+#include "SVGElement.h"
+#include "SVGTests.h"
+#include "SVGLangSpace.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+#include "SVGTransformable.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedLength;
+class SVGRectElementImpl;
+
+/**
+ * The <code> rect </code> element defines a rectangle which is
+ * axis-aligned with the current <a href =
+ * "http://www.w3.org/TR/SVG/intro.html#TermUserCoordinateSystem">
+ * user coordinate</a> system.
+ * Rounded rectangles can be achieved by setting appropriate values
+ * for attributes <code> x </code> and <code> y</code>.
+ *
+ * For more info look here : <a href =
+ * "http://www.w3.org/TR/SVG/shapes.html#RectElement"> 9.2 The
+ * 'rect' element</a>.
+ */
+class SVGRectElement : public SVGElement,
+ public SVGTests,
+ public SVGLangSpace,
+ public SVGExternalResourcesRequired,
+ public SVGStylable,
+ public SVGTransformable
+{
+public:
+ SVGRectElement();
+ SVGRectElement(const SVGRectElement &);
+ SVGRectElement &operator=(const SVGRectElement &other);
+ SVGRectElement(SVGRectElementImpl *);
+ ~SVGRectElement();
+
+ /**
+ * The x-axis coordinate of the side of the rectangle which has
+ * the smaller x-axis coordinate value in the current user
+ * coordinate system.
+ * If the attribute is not specified, the effect is as if a value
+ * of "0" were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The x-axis coordinate of the rectangle.
+ */
+ SVGAnimatedLength x();
+
+ /**
+ * The y-axis coordinate of the side of the rectangle which has
+ * the smaller y-axis coordinate value in the current user
+ * coordinate system. If the attribute is not specified, the
+ * effect is as if a value of "0" were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The y-axis coordinate of the rectangle.
+ */
+ SVGAnimatedLength y();
+
+ /**
+ * The width of the rectangle. A negative value is an error (see
+ * <a href =
+ * "http://www.w3.org/TR/SVG/implnote.html#ErrorProcessing">
+ * Error processing</a>).
+ * A value of zero disables rendering of the element.
+ *
+ * This attribute is animatable.
+ *
+ * @return The width of the rectangle.
+ */
+ SVGAnimatedLength width();
+
+ /**
+ * The heigth of the rectangle. A negative value is an error (see
+ * <a href =
+ * "http://www.w3.org/TR/SVG/implnote.html#ErrorProcessing">
+ * Error processing</a>). A value of zero disables rendering of
+ * the element.
+ *
+ * This attribute is animatable.
+ *
+ * @return The height of the rectangle
+ */
+ SVGAnimatedLength height();
+
+ /**
+ * For rounded rectangles, the x-axis radius of the ellipse used
+ * to round off the corners of the rectangle. A negative value is
+ * an error (see <a href =
+ * "http://www.w3.org/TR/SVG/implnote.html#ErrorProcessing"> Error
+ * processing</a>).
+ *
+ * See <a href="http://www.w3.org/TR/SVG/shapes.html#RectElement">
+ * 9.2 The 'rect' element </a> for info about what happens if the
+ * attribute is not specified.
+ *
+ * This attribute is animatable
+ *
+ * @return The x-axis radius of the ellipse used to round off the
+ * corners of the rectangle.
+ */
+ SVGAnimatedLength rx();
+
+ /**
+ * For rounded rectangles, the y-axis radius of the ellipse used
+ * to round off the corners of the rectangle. A negative value is
+ * an error (see <a href =
+ * "http://www.w3.org/TR/SVG/implnote.html#ErrorProcessing">Error
+ * processing</a>).
+ *
+ * See <a href="http://www.w3.org/TR/SVG/shapes.html#RectElement">
+ * 9.2 The 'rect' element </a> for info about what happens if the
+ * attribute is not specified.
+ *
+ * This attribute is animatable
+ *
+ * @return The y-axis radius of the ellipse used to round off the
+ * corners of the rectangle.
+ */
+ SVGAnimatedLength ry();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGRectElementImpl *handle() const { return impl; }
+
+private:
+ SVGRectElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGRenderingIntent.h b/ksvg/dom/SVGRenderingIntent.h
new file mode 100644
index 00000000..5293f92b
--- /dev/null
+++ b/ksvg/dom/SVGRenderingIntent.h
@@ -0,0 +1,41 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGRenderingIntent_H
+#define SVGRenderingIntent_H
+
+namespace KSVG
+{
+
+enum
+{
+ RENDERING_INTENT_UNKNOWN = 0,
+ RENDERING_INTENT_AUTO = 1,
+ RENDERING_INTENT_PERCEPTUAL = 2,
+ RENDERING_INTENT_RELATIVE_COLORIMETRIC = 3,
+ RENDERING_INTENT_SATURATION = 4,
+ RENDERING_INTENT_ABSOLUTE_COLORIMETRIC = 5
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGSVGElement.cc b/ksvg/dom/SVGSVGElement.cc
new file mode 100644
index 00000000..204de90c
--- /dev/null
+++ b/ksvg/dom/SVGSVGElement.cc
@@ -0,0 +1,337 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGRect.h"
+#include "SVGSVGElement.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGAnimatedLength.h"
+#include "SVGPoint.h"
+#include "SVGNumber.h"
+#include "SVGAngle.h"
+#include "SVGMatrix.h"
+#include "SVGLength.h"
+#include "SVGRect.h"
+#include "SVGTransform.h"
+#include "SVGViewSpec.h"
+#include <kdebug.h>
+
+using namespace KSVG;
+
+SVGSVGElement::SVGSVGElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGLocatable(), SVGFitToViewBox(), SVGZoomAndPan()
+{
+ impl = 0;
+}
+
+SVGSVGElement::SVGSVGElement(const SVGSVGElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGLocatable(other), SVGFitToViewBox(other), SVGZoomAndPan(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGSVGElement &SVGSVGElement::operator=(const SVGSVGElement &other)
+{
+ SVGElement::operator=(other);
+ SVGTests::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+ SVGLocatable::operator=(other);
+ SVGFitToViewBox::operator=(other);
+ SVGZoomAndPan::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGSVGElement::SVGSVGElement(SVGSVGElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGLocatable(other), SVGFitToViewBox(other), SVGZoomAndPan(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGSVGElement::~SVGSVGElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedLength SVGSVGElement::x() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGSafeCreator<SVGAnimatedLength, SVGAnimatedLengthImpl>::create(impl->x());
+}
+
+SVGAnimatedLength SVGSVGElement::y() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGSafeCreator<SVGAnimatedLength, SVGAnimatedLengthImpl>::create(impl->y());
+}
+
+SVGAnimatedLength SVGSVGElement::width() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGSafeCreator<SVGAnimatedLength, SVGAnimatedLengthImpl>::create(impl->width());
+}
+
+SVGAnimatedLength SVGSVGElement::height() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGSafeCreator<SVGAnimatedLength, SVGAnimatedLengthImpl>::create(impl->height());
+}
+
+void SVGSVGElement::setContentScriptType(const DOM::DOMString &contentScriptType)
+{
+ if(impl)
+ setContentScriptType(contentScriptType);
+}
+
+DOM::DOMString SVGSVGElement::contentScriptType() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->contentScriptType();
+}
+
+void SVGSVGElement::setContentStyleType(const DOM::DOMString &contentStyleType)
+{
+ if(impl)
+ setContentStyleType(contentStyleType);
+}
+
+DOM::DOMString SVGSVGElement::contentStyleType() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->contentStyleType();
+}
+
+SVGRect SVGSVGElement::viewport() const
+{
+ if(!impl) return SVGRect(0);
+ return SVGRect(impl->viewport());
+}
+
+float SVGSVGElement::pixelUnitToMillimeterX() const
+{
+ if(!impl) return -1;
+ return impl->pixelUnitToMillimeterX();
+}
+
+float SVGSVGElement::pixelUnitToMillimeterY() const
+{
+ if(!impl) return -1;
+ return impl->pixelUnitToMillimeterY();
+}
+
+float SVGSVGElement::screenPixelToMillimeterX() const
+{
+ if(!impl) return -1;
+ return impl->screenPixelToMillimeterX();
+}
+
+float SVGSVGElement::screenPixelToMillimeterY() const
+{
+ if(!impl) return -1;
+ return impl->screenPixelToMillimeterY();
+}
+
+void SVGSVGElement::setUseCurrentView(bool useCurrentView)
+{
+ if(impl)
+ impl->setUseCurrentView(useCurrentView);
+}
+
+bool SVGSVGElement::useCurrentView() const
+{
+ if(!impl) return false;
+ return impl->useCurrentView();
+}
+
+SVGViewSpec SVGSVGElement::currentView() const
+{
+ if(!impl) return SVGViewSpec(0);
+ return impl->currentView();
+}
+
+void SVGSVGElement::setCurrentScale(float currentScale)
+{
+ if(impl)
+ impl->setCurrentScale(currentScale);
+}
+
+float SVGSVGElement::currentScale() const
+{
+ if(!impl) return -1;
+ return impl->currentScale();
+}
+
+SVGPoint SVGSVGElement::currentTranslate() const
+{
+ if(!impl) return SVGPoint(0);
+ return SVGSafeCreator<SVGPoint, SVGPointImpl>::create(impl->currentTranslate());
+}
+
+unsigned long SVGSVGElement::suspendRedraw(unsigned long time)
+{
+ if(!impl) return 0;
+ return impl->suspendRedraw(time);
+}
+
+void SVGSVGElement::unsuspendRedraw(unsigned long id)
+{
+ if(impl)
+ impl->unsuspendRedraw(id);
+}
+
+void SVGSVGElement::unsuspendRedrawAll()
+{
+ if(impl)
+ impl->unsuspendRedrawAll();
+}
+
+void SVGSVGElement::forceRedraw()
+{
+ if(impl)
+ impl->forceRedraw();
+}
+
+void SVGSVGElement::pauseAnimations()
+{
+ if(impl)
+ impl->pauseAnimations();
+}
+
+void SVGSVGElement::unpauseAnimations()
+{
+ if(impl)
+ impl->unpauseAnimations();
+}
+
+bool SVGSVGElement::animationsPaused()
+{
+ if(!impl) return false;
+ return impl->animationsPaused();
+}
+
+float SVGSVGElement::getCurrentTime()
+{
+ if(!impl) return -1;
+ return impl->getCurrentTime();
+}
+
+void SVGSVGElement::setCurrentTime(float time)
+{
+ if(impl)
+ impl->setCurrentTime(time);
+}
+
+DOM::NodeList SVGSVGElement::getIntersectionList(const SVGRect &rect,const SVGElement &referenceElement)
+{
+ if(!impl) return DOM::NodeList();
+ return impl->getIntersectionList(rect.handle(), referenceElement.handle());
+}
+
+DOM::NodeList SVGSVGElement::getEnclosureList(const SVGRect &rect,const SVGElement &referenceElement)
+{
+ if(!impl) return DOM::NodeList();
+ return impl->getEnclosureList(rect.handle(), referenceElement.handle());
+}
+
+bool SVGSVGElement::checkIntersection(const SVGElement &element,const SVGRect &rect)
+{
+ if(!impl) return false;
+ return impl->checkIntersection(element.handle(), rect.handle());
+}
+
+bool SVGSVGElement::checkEnclosure(const SVGElement &element,const SVGRect &rect)
+{
+ if(!impl) return false;
+ return impl->checkEnclosure(element.handle(), rect.handle());
+}
+
+void SVGSVGElement::deSelectAll()
+{
+ if(impl)
+ impl->deSelectAll();
+}
+
+SVGNumber SVGSVGElement::createSVGNumber()
+{
+ if(!impl) return SVGNumber(0);
+ return SVGSafeCreator<SVGNumber, SVGNumberImpl>::create(impl->createSVGNumber());
+}
+
+SVGLength SVGSVGElement::createSVGLength()
+{
+ if(!impl) return SVGLength(0);
+ return SVGSafeCreator<SVGLength, SVGLengthImpl>::create(impl->createSVGLength());
+}
+
+SVGAngle SVGSVGElement::createSVGAngle()
+{
+ if(!impl) return SVGAngle(0);
+ return SVGSafeCreator<SVGAngle, SVGAngleImpl>::create(impl->createSVGAngle());
+}
+
+SVGPoint SVGSVGElement::createSVGPoint()
+{
+ if(!impl) return SVGPoint(0);
+ return SVGSafeCreator<SVGPoint, SVGPointImpl>::create(impl->createSVGPoint());
+}
+
+SVGMatrix SVGSVGElement::createSVGMatrix()
+{
+ if(!impl) return SVGMatrix(0);
+ return SVGSafeCreator<SVGMatrix, SVGMatrixImpl>::create(impl->createSVGMatrix());
+}
+
+SVGRect SVGSVGElement::createSVGRect()
+{
+ if(!impl) return SVGRect(0);
+ return SVGSafeCreator<SVGRect, SVGRectImpl>::create(impl->createSVGRect());
+}
+
+SVGTransform SVGSVGElement::createSVGTransform()
+{
+ if(!impl) return SVGTransform(0);
+ return SVGSafeCreator<SVGTransform, SVGTransformImpl>::create(impl->createSVGTransform());
+}
+
+SVGTransform SVGSVGElement::createSVGTransformFromMatrix(const SVGMatrix &matrix)
+{
+ if(!impl) return SVGTransform(0);
+ return SVGSafeCreator<SVGTransform, SVGTransformImpl>::create(impl->createSVGTransformFromMatrix(matrix.handle()));
+}
+
+SVGElement SVGSVGElement::getElementById(const DOM::DOMString &elementId)
+{
+ if(!impl) return SVGElement(0);
+ return SVGSafeCreator<SVGElement, SVGElementImpl>::create(impl->getElementById(elementId));
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGSVGElement.h b/ksvg/dom/SVGSVGElement.h
new file mode 100644
index 00000000..59621e2e
--- /dev/null
+++ b/ksvg/dom/SVGSVGElement.h
@@ -0,0 +1,581 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+
+ This file includes excerpts from the Scalable Vector Graphics
+ (SVG) 1.0 Specification (Proposed Recommendation)
+ http://www.w3.org/TR/SVG
+
+ Copyright 2001 World Wide Web Consortium, (Massachusetts
+ Institute of Technology, Institut National de Recherche en
+ Informatique et en Automatique, Keio University).
+ All Rights Reserved.
+*/
+
+#ifndef SVGSVGElement_H
+#define SVGSVGElement_H
+
+#include <dom/dom_string.h>
+#include "SVGElement.h"
+#include "SVGTests.h"
+#include "SVGLangSpace.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+#include "SVGLocatable.h"
+#include "SVGFitToViewBox.h"
+#include "SVGZoomAndPan.h"
+
+namespace KSVG
+{
+class SVGAnimatedLength;
+class SVGPoint;
+class SVGNumber;
+class SVGAngle;
+class SVGMatrix;
+class SVGLength;
+class SVGRect;
+class SVGTransform;
+class SVGViewSpec;
+class SVGSVGElementImpl;
+
+/**
+ * A key interface definition is the SVGSVGElement interface, which is the
+ * interface that corresponds to the 'svg' element. This interface contains
+ * various miscellaneous commonly-used utility methods, such as matrix
+ * operations and the ability to control the time of redraw on visual
+ * rendering devices. SVGSVGElement extends ViewCSS and DocumentCSS to provide
+ * access to the computed values of properties and the override style sheet
+ * as described in DOM2.
+ *
+ * For more information :
+ * <a href="http://www.w3.org/TR/SVG/struct.html#NewDocument">
+ * the 'svg' element</a>
+ */
+class SVGSVGElement : public SVGElement,
+ public SVGTests,
+ public SVGLangSpace,
+ public SVGExternalResourcesRequired,
+ public SVGStylable,
+ public SVGLocatable,
+ public SVGFitToViewBox,
+ public SVGZoomAndPan
+ //public events::EventTarget,
+ //public events::DocumentEvent,
+ //public css::ViewCSS,
+ //public css::DocumentCSS
+{
+public:
+ SVGSVGElement();
+ SVGSVGElement(const SVGSVGElement &);
+ SVGSVGElement &operator=(const SVGSVGElement &other);
+ SVGSVGElement(SVGSVGElementImpl *);
+ virtual ~SVGSVGElement();
+
+ /**
+ * (Has no meaning or effect on outermost 'svg' elements.)
+ * The x-axis coordinate of one corner of the rectangular region into which an
+ * embedded 'svg' element is placed. If the attribute is not specified, the
+ * effect is as if a value of "0" were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The x-axis coordinate of the viewport of the 'svg' element.
+ */
+ SVGAnimatedLength x() const;
+
+ /**
+ * (Has no meaning or effect on outermost 'svg' elements.)
+ * The x-axis coordinate of one corner of the rectangular region into which an
+ * embedded 'svg' element is placed. If the attribute is not specified, the
+ * effect is as if a value of "0" were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The y-axis coordinate of the viewport of the 'svg' element.
+ */
+ SVGAnimatedLength y() const;
+
+ /**
+ * For outermost 'svg' elements, the intrinsic width of the SVG document
+ * fragment. For embedded 'svg' elements, the width of the rectangular
+ * region into which the 'svg' element is placed.
+ * A negative value is an error (see <a
+ * href="http://www.w3.org/TR/SVG/implnote.html#ErrorProcessing"> Error
+ * processing </a>).
+ * A value of zero disables rendering of the element. If the attribute is not
+ * specified, the effect is as if a value of "100%" were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The width of the viewport of the 'svg' element.
+ */
+ SVGAnimatedLength width() const;
+
+ /**
+ * For outermost 'svg' elements, the intrinsic height of the SVG document
+ * fragment. For embedded 'svg' elements, the height of the rectangular region
+ * into which the 'svg' element is placed.
+ * A negative value is an error (see <a
+ * href="http://www.w3.org/TR/SVG/implnote.html#ErrorProcessing"> Error
+ * processing </a>).
+ * A value of zero disables rendering of the element. If the attribute is not
+ * specified, the effect is as if a value of "100%" were specified.
+ *
+ * This attribute is animatable.
+ *
+ * @return The height of the viewport of the 'svg' element.
+ */
+ SVGAnimatedLength height() const;
+
+ /**
+ * The <code> contentScriptType </code> attribute identifies the default
+ * scripting language for the given document. This attribute sets the scripting
+ * language used to process the value strings in event attributes. The value
+ * content-type specifies a media type, per <a
+ * href="http://www.ietf.org/rfc/rfc2045.txt"> [RFC2045]</a>. The default value
+ * is "text/ecmascript".
+ *
+ * This attribute is not animatable.
+ *
+ * @exception
+ * NO_MODIFICATION_ALLOWED_ERR: Raised on an attempt to change the value of a
+ * readonly attribute.
+ */
+ void setContentScriptType(const DOM::DOMString &);
+
+ /**
+ * @return The value of the <code>contentScript</code> attribute on the given
+ * 'svg' element.
+ */
+ DOM::DOMString contentScriptType() const;
+
+ /**
+ * Identifies the default style sheet language for the given document. This
+ * attribute sets the style sheet language for the style attributes that are
+ * available on many elements. The value of the attribute consists of a media
+ * type, per <a href="http://www.ietf.org/rfc/rfc2045.txt">[RFC2045]</a>.
+ * The default value is "text/css".
+ */
+ void setContentStyleType(const DOM::DOMString &);
+
+ /**
+ * @return The value of the <code>contentStyle</code> attribute on the given
+ * 'svg' element.
+ */
+ DOM::DOMString contentStyleType() const;
+
+ /**
+ * The position and size of the viewport (implicit or explicit) that
+ * corresponds to this 'svg' element. When the user agent is actually
+ * rendering the content, then the position and size values represent the
+ * actual values when rendering. The position and size values are unitless
+ * values in the coordinate system of the parent element. If no parent element
+ * exists (i.e., 'svg' element represents the root of the document tree), if
+ * this SVG document is embedded as part of another document (e.g., via the
+ * HTML 'object' element), then the position and size are unitless values in
+ * the coordinate system of the parent document. (If the parent uses CSS or
+ * XSL layout, then unitless values represent pixel units for the current CSS
+ * or XSL viewport, as described in the CSS2 specification.) If the parent
+ * element does not have a coordinate system, then the user agent should
+ * provide reasonable default values for this attribute.
+ *
+ * @return The viewport represented by a <code>SVGRect</rect>.
+ */
+ SVGRect viewport() const;
+
+ /**
+ * Size of a pixel units (as defined by CSS2) along the x-axis of the viewport,
+ * which represents a unit somewhere in the range of 70dpi to 120dpi, and, on
+ * systems that support this, might actually match the characteristics of the
+ * target medium. On systems where it is impossible to know the size of a
+ * pixel, a suitable default pixel size is provided.
+ *
+ * @return Corresponding size of a pixel unit along the x-axis of the viewport.
+ */
+ float pixelUnitToMillimeterX() const;
+
+ /**
+ * @return Corresponding size of a pixel unit along the y-axis of the viewport.
+ */
+ float pixelUnitToMillimeterY() const;
+
+ /**
+ * User interface (UI) events in DOM Level 2 indicate the screen positions at
+ * which the given UI event occurred. When the user agent actually knows the
+ * physical size of a "screen unit", this attribute will express that
+ * information; otherwise, user agents will provide a suitable default value
+ * such as .28mm.
+ *
+ * @return Corresponding size of a screen pixel along the x-axis of the
+ * viewport.
+ */
+ float screenPixelToMillimeterX() const;
+
+ /**
+ * @return Corresponding size of a screen pixel along the y-axis of the
+ * viewport.
+ */
+ float screenPixelToMillimeterY() const;
+
+ /**
+ * The initial view (i.e., before magnification and panning) of the current
+ * innermost SVG document fragment can be either the "standard" view (i.e.,
+ * based on attributes on the 'svg' element such as fitBoxToViewport) or to a
+ * "custom" view (i.e., a hyperlink into a particular 'view' or other element -
+ * see <a href="http://www.w3.org/TR/SVG/linking.html#LinksIntoSVG"> Linking
+ * into SVG content: URI fragments and SVG views)</a>. If the initial view
+ * is the "standard" view, then this attribute is false. If the initial
+ * view is a "custom" view, then this attribute is true.
+ *
+ * @exception DOMException
+ * NO_MODIFICATION_ALLOWED_ERR: Raised on an attempt to change the value of a
+ * readonly attribute.
+ */
+ void setUseCurrentView(bool);
+
+ /**
+ * @return Indicated whether the view is "custom" or not.
+ */
+ bool useCurrentView() const;
+
+ /**
+ * The definition of the initial view (i.e., before magnification and panning)
+ * of the current innermost SVG document fragment. The meaning depends on the
+ * situation:
+ *
+ * If the initial view was a "standard" view, then:
+ *
+ * the values for <code>viewBox</code>, <code>preserveAspectRatio</code> and
+ * <code>zoomAndPan</code> within <code>currentView</code> will match the
+ * values for the corresponding DOM attributes that are on SVGSVGElement
+ * directly.
+ * the values for <code>transform</code> and <code>viewTarget</code> within
+ * <code>currentView</code> will be null.
+ *
+ * If the initial view was a link into a 'view' element, then:
+ *
+ * the values for <code>viewBox</code>, <code>preserveAspectRatio</code> and
+ * <code>zoomAndPan</code> within <code>currentView</code> will correspond to
+ * the corresponding attributes for the given 'view' element.
+ * the values for <code>transform</code> and <code>viewTarget</code> within
+ * <code>currentView </code>will be null
+ *
+ * If the initial view was a link into another element (i.e., other than a
+ *'view'), then:
+ *
+ * the values for <code>viewBox</code>, <code>preserveAspectRatio</code> and
+ * <code>zoomAndPan</code> within <code>currentView</code> will match the
+ * values for the corresponding DOM attributes that are on SVGSVGElement
+ * directly for the closest ancestor 'svg' element.
+ * the values for transform within <code>currentView</code> will be null.
+ * the <code>viewTarget</code> within <code>currentView</code> will represent
+ * the target of the link.
+ *
+ * If the initial view was a link into the SVG document fragment using an SVG
+ * view specification fragment identifier (i.e., #svgView(...)), then:
+ *
+ * the values for <code>viewBox</code>, <code>preserveAspectRatio</code>,
+ * <code>zoomAndPan</code>, <code>transform</code> and <code>viewTarget</code>
+ * within <code>currentView</code> will correspond to the values from the SVG
+ * view specification fragment identifier
+ *
+ * The object itself and its contents are both readonly.
+ */
+ SVGViewSpec currentView() const;
+
+ /**
+ * The currentScale attribute indicates the current scale factor relative to
+ * the initial view to take into account user magnification and panning
+ * operations, as described under
+ * <a href="http://www.w3.org/TR/SVG/interact.html#ZoomAndPanAttribute">
+ * Magnification and panning</a>. DOM attributes currentScale and
+ * currentTranslate are equivalent to the 2x3 matrix [a b c d e f] =
+ * [currentScale 0 0 currentScale currentTranslate.x currentTranslate.y].
+ * If "magnification" is enabled (i.e., zoomAndPan="magnify"), then the effect
+ * is as if an extra transformation were placed at the outermost level on the
+ * SVG document fragment (i.e., outside the outermost 'svg' element).
+ *
+ * @exception DOMException
+ * NO_MODIFICATION_ALLOWED_ERR: Raised on an attempt to change the value of a
+ * readonly attribute.
+ *
+ * @param The new value of the currentScale attribute.
+ */
+ void setCurrentScale(float);
+
+ /**
+ * @return The <code> currentScale </code> attribute value as described above.
+ */
+ float currentScale() const;
+
+ /**
+ * The corresponding translation factor that takes into account user
+ * "magnification".
+ *
+ * @return The translation factor represented by an <code> SVGPoint </code>.
+ */
+ SVGPoint currentTranslate() const;
+
+ /**
+ * Takes a time-out value which indicates that redraw shall not occur until:
+ *
+ * (a) the corresponding unsuspendRedraw(suspend_handle_id) call has been made
+ * (b) an unsuspendRedrawAll() call has been made
+ * (c) its timer has timed out.
+ *
+ * In environments that do not support interactivity (e.g., print media), then
+ * redraw shall not be suspended suspend_handle_id =
+ * suspendRedraw(max_wait_milliseconds) and unsuspendRedraw(suspend_handle_id)
+ * must be packaged as balanced pairs. When you want to suspend redraw actions
+ * as a collection of SVG DOM changes occur, then precede the changes to the
+ * SVG DOM with a method call similar to suspend_handle_id =
+ * suspendRedraw(max_wait_milliseconds) and follow the changes with a method
+ * call similar to unsuspendRedraw(suspend_handle_id). Note that multiple
+ * suspendRedraw calls can be used at once and that each such method call is
+ * treated independently of the other suspendRedraw method calls.
+ *
+ * @param max_wait_milliseconds The amount of time in milliseconds to hold off
+ * before redrawing the device.Values greater than 60 seconds will be
+ * truncated down to 60 seconds.
+ *
+ * @return A number which acts as a unique identifier for the given
+ * suspendRedraw() call. This value must be passed as the parameter to the
+ * corresponding unsuspendRedraw() method call.
+ */
+ unsigned long suspendRedraw(unsigned long max_wait_milliseconds);
+
+ /**
+ * Cancels a specified suspendRedraw() by providing a unique suspend_handle_id.
+ *
+ * @param suspend_handle_id A number which acts as a unique identifier for the
+ * desired suspendRedraw() call. The number supplied must be a value returned
+ * from a previous call to suspendRedraw().
+ */
+ void unsuspendRedraw(unsigned long suspend_handle_id);
+
+ /**
+ * Cancels all currently active suspendRedraw() method calls. This method is
+ * most useful at the very end of a set of SVG DOM calls to ensure that all
+ * pending suspendRedraw() method calls have been cancelled.
+ */
+ void unsuspendRedrawAll();
+
+ /**
+ * In rendering environments supporting interactivity, forces the user agent to
+ * immediately redraw all regions of the viewport that require updating.
+ */
+ void forceRedraw();
+
+ /**
+ * Suspends (i.e., pauses) all currently running animations that are defined
+ * within the SVG document fragment corresponding to this 'svg' element,
+ * causing the animation clock corresponding to this document fragment to stand
+ * still until it is paused.
+ */
+ void pauseAnimations();
+
+ /**
+ * Unsuspends (i.e., pauses) currently running animations that are defined
+ * within the SVG document fragment, causing the animation clock to continue
+ * from the time it was suspended.
+ */
+ void unpauseAnimations();
+
+ /**
+ * Returns true if this SVG Document fragment is in a paused state.
+ *
+ * @return Boolean indicating whether this SVG document fragment is in a paused
+ * state.
+ */
+ bool animationsPaused();
+
+ /**
+ * Returns the current time in seconds relative to the start time for the
+ * current SVG document fragment.
+ *
+ * @return The current time in seconds.
+ */
+ float getCurrentTime();
+
+ /**
+ * Adjusts the clock for this SVG document fragment, establishing a new current
+ * time.
+ *
+ * @param seconds The new current time in seconds relative to the start time
+ * for the current SVG document fragment.
+ */
+ void setCurrentTime(float seconds);
+
+ /**
+ * Returns the list of graphics elements whose rendered content intersects the
+ * supplied rectangle, honoring the 'pointer-events' property value on each
+ * candidate graphics element.
+ *
+ * @param rect The test rectangle. The values are in the initial coordinate
+ * system for the current 'svg' element.
+ * @param referenceElement If not null, then only return elements whose drawing
+ * order has them below the given reference element.
+ *
+ * @return A list of Elements whose content is intersects the supplied
+ * rectangle.
+ */
+ DOM::NodeList getIntersectionList(const SVGRect &rect, const SVGElement
+ &referenceElement);
+
+ /**
+ * Returns the list of graphics elements whose rendered content is entirely
+ * contained within the supplied rectangle, honoring the 'pointer-events'
+ * property value on each candidate graphics element.
+ *
+ * @param rect The test rectangle. The values are in the initial coordinate
+ * system for the current 'svg' element.
+ * @param referenceElement If not null, then only return elements whose drawing
+ * order has them below the given reference element.
+ *
+ * @return A list of Elements whose content is enclosed by the supplied
+ * rectangle.
+ */
+ DOM::NodeList getEnclosureList(const SVGRect &rect, const SVGElement
+ &referenceElement);
+
+ /**
+ * Returns true if the rendered content of the given element intersects the
+ * supplied rectangle, honoring the 'pointer-events' property value on each
+ * candidate graphics element.
+ *
+ * @param element The element on which to perform the given test.
+ * @param rect The test rectangle. The values are in the initial coordinate
+ * system for the current 'svg' element.
+ *
+ * @return True or false, depending on whether the given element intersects the
+ * supplied rectangle.
+ */
+ bool checkIntersection(const SVGElement &element, const SVGRect &rect);
+
+ /**
+ * Returns true if the rendered content of the given element is entirely
+ * contained within the supplied rectangle, honoring the 'pointer-events'
+ * property value on each candidate graphics element.
+ *
+ * @param element The element on which to perform the given test.
+ * @param rect The test rectangle. The values are in the initial coordinate
+ * system for the current 'svg' element.
+ *
+ * @return True or false, depending on whether the given element is enclosed by
+ * the supplied rectangle.
+ */
+ bool checkEnclosure(const SVGElement &element, const SVGRect &rect);
+
+ /**
+ * Unselects any selected objects, including any selections of text
+ * strings and type-in bars.
+ */
+ void deSelectAll();
+
+ /**
+ * Creates an <code> SVGNumber </code> object outside of any document trees.
+ * The object is initialized to a value of zero.
+ *
+ * @return An <code> SVGNumber </code> object.
+ */
+ SVGNumber createSVGNumber();
+
+ /**
+ * Creates an <code> SVGLength </code> object outside of any document trees.
+ * The object is initialized to a value of zero user units.
+ *
+ * @return An <code> SVGLength </code> object.
+ */
+ SVGLength createSVGLength();
+
+ /**
+ * Creates an <code> SVGAngle </code> object outside of any document trees.
+ * The object is initialized to a value of zero degreesunitless).
+ *
+ * @return An <code> SVGAngle </code> object.
+ */
+ SVGAngle createSVGAngle();
+
+ /**
+ * Creates an <code> SVGPoint </code> object outside of any document trees.
+ * The object is initialized to the point (0,0) in the user coordinate system.
+ *
+ * @return An <code> SVGPoint </code> object.
+ */
+ SVGPoint createSVGPoint();
+
+ /**
+ * Creates an <code> SVGMatrix </code> object outside of any document trees.
+ * The object is initialized to a value of the identity matrix.
+ *
+ * @return An <code> SVGMatrix </code> object.
+ */
+ SVGMatrix createSVGMatrix();
+
+ /**
+ * Creates an <code> SVGRect </code> object outside of any document trees.
+ * The object is initialized such that all values are set to 0 user units.
+ *
+ * @return An <code> SVGRect </code> object.
+ */
+ SVGRect createSVGRect();
+
+ /**
+ * Creates an <code> SVGTransform </code> object outside of any document trees.
+ * The object is initialized to an identity matrix transform
+ * (SVG_TRANSFORM_MATRIX).
+ *
+ * @return An <code> SVGTransform </code> object.
+ */
+ SVGTransform createSVGTransform();
+
+ /**
+ * Creates an <code> SVGTransform </code> object outside of any document trees.
+ * The object is initialized to the given matrix transform (i.e.,
+ * SVG_TRANSFORM_MATRIX).
+ *
+ * @return An <code> SVGTransform </code> object.
+ */
+ SVGTransform createSVGTransformFromMatrix(const SVGMatrix &matrix);
+
+ /**
+ * Searches this SVG document fragment (i.e., the search is restricted to a
+ * subset of the document tree) for an <code> Element </code> whose id is given
+ * by elementId. If an <code> Element </code> is found, that <code> Element
+ * </code> is returned. If no such element exists, returns null. Behavior
+ * is not defined if more than one element has this id.
+ *
+ * @param elementId The unique id value for an element.
+ *
+ * @return The matching element.
+ */
+ SVGElement getElementById(const DOM::DOMString &elementId);
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGSVGElementImpl *handle() const { return impl; }
+
+private:
+ SVGSVGElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGScriptElement.cc b/ksvg/dom/SVGScriptElement.cc
new file mode 100644
index 00000000..f599a273
--- /dev/null
+++ b/ksvg/dom/SVGScriptElement.cc
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGScriptElement.h"
+#include "SVGScriptElementImpl.h"
+
+using namespace KSVG;
+
+SVGScriptElement::SVGScriptElement() : SVGElement(), SVGURIReference(), SVGExternalResourcesRequired()
+{
+ impl = 0;
+}
+
+SVGScriptElement::SVGScriptElement(const SVGScriptElement &other) : SVGElement(other), SVGURIReference(other), SVGExternalResourcesRequired(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGScriptElement &SVGScriptElement::operator =(const SVGScriptElement &other)
+{
+ SVGElement::operator=(other);
+ SVGURIReference::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGScriptElement::SVGScriptElement(SVGScriptElementImpl *other) : SVGElement(other), SVGURIReference(other), SVGExternalResourcesRequired(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGScriptElement::~SVGScriptElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+void SVGScriptElement::setType(const DOM::DOMString &type)
+{
+ if(impl)
+ impl->setType(type);
+}
+
+DOM::DOMString SVGScriptElement::type() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->type();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGScriptElement.h b/ksvg/dom/SVGScriptElement.h
new file mode 100644
index 00000000..aae1d79b
--- /dev/null
+++ b/ksvg/dom/SVGScriptElement.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGScriptElement_H
+#define SVGScriptElement_H
+
+#include <dom/dom_string.h>
+#include "SVGElement.h"
+#include "SVGURIReference.h"
+#include "SVGExternalResourcesRequired.h"
+
+namespace KSVG
+{
+
+class SVGScriptElementImpl;
+class SVGScriptElement : public SVGElement,
+ public SVGURIReference,
+ public SVGExternalResourcesRequired
+{
+public:
+ SVGScriptElement();
+ SVGScriptElement(const SVGScriptElement &other);
+ SVGScriptElement &operator=(const SVGScriptElement &other);
+ SVGScriptElement(SVGScriptElementImpl *other);
+ virtual ~SVGScriptElement();
+
+ void setType(const DOM::DOMString &type);
+ DOM::DOMString type() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGScriptElementImpl *handle() const { return impl; }
+
+private:
+ SVGScriptElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGSetElement.cc b/ksvg/dom/SVGSetElement.cc
new file mode 100644
index 00000000..7a47c993
--- /dev/null
+++ b/ksvg/dom/SVGSetElement.cc
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGSetElement.h"
+#include "SVGSetElementImpl.h"
+
+using namespace KSVG;
+
+SVGSetElement::SVGSetElement() : SVGAnimationElement()
+{
+ impl = 0;
+}
+
+SVGSetElement::SVGSetElement(const SVGSetElement &other) : SVGAnimationElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGSetElement &SVGSetElement::operator =(const SVGSetElement &other)
+{
+ SVGAnimationElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGSetElement::SVGSetElement(SVGSetElementImpl *other) : SVGAnimationElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGSetElement::~SVGSetElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGSetElement.h b/ksvg/dom/SVGSetElement.h
new file mode 100644
index 00000000..f65a8704
--- /dev/null
+++ b/ksvg/dom/SVGSetElement.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGSetElement_H
+#define SVGSetElement_H
+
+#include "SVGAnimationElement.h"
+
+namespace KSVG
+{
+
+class SVGSetElementImpl;
+class SVGSetElement : public SVGAnimationElement
+{
+public:
+ SVGSetElement();
+ SVGSetElement(const SVGSetElement &other);
+ SVGSetElement &operator=(const SVGSetElement &other);
+ SVGSetElement(SVGSetElementImpl *other);
+ virtual ~SVGSetElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGSetElementImpl *handle() const { return impl; }
+
+private:
+ SVGSetElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGStopElement.cc b/ksvg/dom/SVGStopElement.cc
new file mode 100644
index 00000000..a9db9a56
--- /dev/null
+++ b/ksvg/dom/SVGStopElement.cc
@@ -0,0 +1,75 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGStopElement.h"
+#include "SVGStopElementImpl.h"
+#include "SVGAnimatedNumber.h"
+
+using namespace KSVG;
+
+SVGStopElement::SVGStopElement() : SVGElement(), SVGStylable()
+{
+ impl = 0;
+}
+
+SVGStopElement::SVGStopElement(const SVGStopElement &other) : SVGElement(other), SVGStylable(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGStopElement &SVGStopElement::operator =(const SVGStopElement &other)
+{
+ SVGElement::operator=(other);
+ SVGStylable::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGStopElement::SVGStopElement(SVGStopElementImpl *other) : SVGElement(other), SVGStylable(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGStopElement::~SVGStopElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedNumber SVGStopElement::offset() const
+{
+ if(!impl) return SVGAnimatedNumber(0);
+ return SVGAnimatedNumber(impl->offset());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGStopElement.h b/ksvg/dom/SVGStopElement.h
new file mode 100644
index 00000000..3002e0cf
--- /dev/null
+++ b/ksvg/dom/SVGStopElement.h
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+
+ This file includes excerpts from the Scalable Vector Graphics
+ (SVG) 1.0 Specification (Proposed Recommendation)
+ http://www.w3.org/TR/SVG
+
+ Copyright 2001 World Wide Web Consortium, (Massachusetts
+ Institute of Technology, Institut National de Recherche en
+ Informatique et en Automatique, Keio University).
+ All Rights Reserved.
+*/
+
+#ifndef SVGStopElement_H
+#define SVGStopElement_H
+
+#include "SVGElement.h"
+#include "SVGStylable.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedNumber;
+class SVGStopElementImpl;
+
+/**
+ * The ramp of colors to use on a gradient is defined by the 'stop' elements that
+ * are child elements to either the 'linearGradient' element or the 'radialGradient' element.
+ */
+class SVGStopElement : public SVGElement,
+ public SVGStylable
+{
+public:
+ SVGStopElement();
+ SVGStopElement(const SVGStopElement &other);
+ SVGStopElement &operator=(const SVGStopElement &other);
+ SVGStopElement(SVGStopElementImpl *other);
+ virtual ~SVGStopElement();
+
+ /**
+ * The <code>offset</code> attribute is either a <number> (usually ranging from 0 to 1)
+ * or a <percentage> (usually ranging from 0% to 100%) which indicates where the gradient
+ * stop is placed. For linear gradients, the offset attribute represents a location along
+ * the gradient vector. For radial gradients, it represents a percentage distance from
+ * (fx,fy) to the edge of the outermost/largest circle.
+ *
+ * This attribute is animatable.
+ *
+ * @return The offset where this gradient stop is placed.
+ */
+ SVGAnimatedNumber offset() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGStopElementImpl *handle() const { return impl; }
+
+private:
+ SVGStopElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGStringList.cc b/ksvg/dom/SVGStringList.cc
new file mode 100644
index 00000000..c7700e06
--- /dev/null
+++ b/ksvg/dom/SVGStringList.cc
@@ -0,0 +1,115 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <dom/dom_string.h>
+#include "SVGStringList.h"
+#include "SVGStringListImpl.h"
+
+using namespace KSVG;
+
+SVGStringList::SVGStringList()
+{
+ impl = new SVGStringListImpl();
+ impl->ref();
+}
+
+SVGStringList::SVGStringList(const SVGStringList &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGStringList &SVGStringList::operator=(const SVGStringList &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGStringList::SVGStringList(SVGStringListImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGStringList::~SVGStringList()
+{
+ if(impl)
+ impl->deref();
+}
+
+unsigned long SVGStringList::numberOfItems() const
+{
+ if(!impl) return 0;
+ return impl->numberOfItems();
+}
+
+void SVGStringList::clear()
+{
+ if(impl)
+ impl->clear();
+}
+
+DOM::DOMString *SVGStringList::initialize(DOM::DOMString *newItem)
+{
+ if(!impl) return new DOM::DOMString();
+ return impl->initialize(new SharedString(newItem));
+}
+
+DOM::DOMString *SVGStringList::getItem(unsigned long index)
+{
+ if(!impl) return new DOM::DOMString();
+ return impl->getItem(index);
+}
+
+DOM::DOMString *SVGStringList::insertItemBefore(DOM::DOMString *newItem, unsigned long index)
+{
+ if(!impl) return new DOM::DOMString();
+ return impl->insertItemBefore(new SharedString(newItem), index);
+}
+
+DOM::DOMString *SVGStringList::replaceItem(DOM::DOMString *newItem, unsigned long index)
+{
+ if(!impl) return new DOM::DOMString();
+ return impl->replaceItem(new SharedString(newItem), index);
+}
+
+DOM::DOMString *SVGStringList::removeItem(unsigned long index)
+{
+ if(!impl) return new DOM::DOMString();
+ return impl->removeItem(index);
+}
+
+DOM::DOMString *SVGStringList::appendItem(DOM::DOMString *newItem)
+{
+ if(!impl) return new DOM::DOMString();
+ return impl->appendItem(new SharedString(newItem));
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGStringList.h b/ksvg/dom/SVGStringList.h
new file mode 100644
index 00000000..477273a6
--- /dev/null
+++ b/ksvg/dom/SVGStringList.h
@@ -0,0 +1,60 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGStringList_H
+#define SVGStringList_H
+
+#include <dom/dom_string.h>
+
+namespace KSVG
+{
+
+class SVGStringListImpl;
+class SVGStringList
+{
+public:
+ SVGStringList();
+ SVGStringList(const SVGStringList &);
+ SVGStringList &operator=(const SVGStringList &);
+ SVGStringList(SVGStringListImpl *);
+ ~SVGStringList();
+
+ unsigned long numberOfItems() const;
+ void clear();
+
+ DOM::DOMString *initialize(DOM::DOMString *newItem);
+ DOM::DOMString *getItem(unsigned long index);
+ DOM::DOMString *insertItemBefore(DOM::DOMString *newItem, unsigned long index);
+ DOM::DOMString *replaceItem(DOM::DOMString *newItem, unsigned long index);
+ DOM::DOMString *removeItem(unsigned long index);
+ DOM::DOMString *appendItem(DOM::DOMString *newItem);
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGStringListImpl *handle() const { return impl; }
+
+private:
+ SVGStringListImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGStylable.cc b/ksvg/dom/SVGStylable.cc
new file mode 100644
index 00000000..14136d7d
--- /dev/null
+++ b/ksvg/dom/SVGStylable.cc
@@ -0,0 +1,76 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGStylable.h"
+#include "SVGStylableImpl.h"
+#include <kdebug.h>
+
+using namespace KSVG;
+
+// This class can't be constructed seperately.
+SVGStylable::SVGStylable()
+{
+ impl = 0;
+}
+
+SVGStylable::SVGStylable(const SVGStylable &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGStylable &SVGStylable::operator=(const SVGStylable &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ impl = other.impl;
+
+ return *this;
+}
+
+SVGStylable::SVGStylable(SVGStylableImpl *other)
+{
+ impl = other;
+}
+
+SVGStylable::~SVGStylable()
+{
+ // We are not allowed to delete 'impl' as it's not refcounted.
+ // delete impl;
+}
+
+/*
+SVGAnimatedString SVGStylable::className() const
+{
+ return impl->className();
+}
+
+css::CSSStyleDeclaration SVGStylable::style() const
+{
+ return impl->style();
+}
+
+css::CSSValue SVGStylable::getPresentationAttribute(const DOMString &name)
+{
+ return impl->getPresentationAttribute(name);
+}
+*/
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGStylable.h b/ksvg/dom/SVGStylable.h
new file mode 100644
index 00000000..2fb3cf11
--- /dev/null
+++ b/ksvg/dom/SVGStylable.h
@@ -0,0 +1,56 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGStylable_H
+#define SVGStylable_H
+
+namespace KSVG
+{
+
+class SVGStylableImpl;
+class SVGStylable
+{
+public:
+ SVGStylable(const SVGStylable &other);
+ SVGStylable &operator=(const SVGStylable &other);
+ SVGStylable(SVGStylableImpl *other);
+ ~SVGStylable();
+
+ // TODO : stylesheet support
+ //SVGAnimatedString className() const;
+ //css::CSSStyleDeclaration style() const;
+ //css::CSSValue getPresentationAttribute(const DOMString &name);
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGStylableImpl *handle() const { return impl; }
+
+protected:
+ SVGStylable();
+
+private:
+ SVGStylableImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
+
diff --git a/ksvg/dom/SVGStyleElement.cc b/ksvg/dom/SVGStyleElement.cc
new file mode 100644
index 00000000..8cf02024
--- /dev/null
+++ b/ksvg/dom/SVGStyleElement.cc
@@ -0,0 +1,115 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGStyleElement.h"
+#include "SVGStyleElementImpl.h"
+
+using namespace KSVG;
+
+SVGStyleElement::SVGStyleElement() : SVGElement()
+{
+ impl = 0;
+}
+
+SVGStyleElement::SVGStyleElement(const SVGStyleElement &other) : SVGElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGStyleElement &SVGStyleElement::operator =(const SVGStyleElement &other)
+{
+ SVGElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGStyleElement::SVGStyleElement(SVGStyleElementImpl *other) : SVGElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGStyleElement::~SVGStyleElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+void SVGStyleElement::setXmlspace(const DOM::DOMString &xmlspace)
+{
+ if(impl)
+ impl->setXmlspace(xmlspace);
+}
+
+DOM::DOMString SVGStyleElement::xmlspace() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->xmlspace();
+}
+
+void SVGStyleElement::setType(const DOM::DOMString &type)
+{
+ if(impl)
+ impl->setType(type);
+}
+
+DOM::DOMString SVGStyleElement::type() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->type();
+}
+
+void SVGStyleElement::setMedia(const DOM::DOMString &media)
+{
+ if(impl)
+ impl->setMedia(media);
+}
+
+DOM::DOMString SVGStyleElement::media() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->media();
+}
+
+void SVGStyleElement::setTitle(const DOM::DOMString &title)
+{
+ if(impl)
+ impl->setTitle(title);
+}
+
+DOM::DOMString SVGStyleElement::title() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->title();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGStyleElement.h b/ksvg/dom/SVGStyleElement.h
new file mode 100644
index 00000000..2a1c63b8
--- /dev/null
+++ b/ksvg/dom/SVGStyleElement.h
@@ -0,0 +1,63 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGStyleElement_H
+#define SVGStyleElement_H
+
+#include <dom/dom_string.h>
+#include "SVGElement.h"
+
+namespace KSVG
+{
+
+class SVGStyleElementImpl;
+class SVGStyleElement : public SVGElement
+{
+public:
+ SVGStyleElement();
+ SVGStyleElement(const SVGStyleElement &other);
+ SVGStyleElement &operator=(const SVGStyleElement &other);
+ SVGStyleElement(SVGStyleElementImpl *other);
+ virtual ~SVGStyleElement();
+
+ void setXmlspace(const DOM::DOMString &xmlspace);
+ DOM::DOMString xmlspace() const;
+
+ void setType(const DOM::DOMString &type);
+ DOM::DOMString type() const;
+
+ void setMedia(const DOM::DOMString &media);
+ DOM::DOMString media() const;
+
+ void setTitle(const DOM::DOMString &title);
+ DOM::DOMString title() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGStyleElementImpl *handle() const { return impl; }
+
+private:
+ SVGStyleElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGSwitchElement.cc b/ksvg/dom/SVGSwitchElement.cc
new file mode 100644
index 00000000..2c4a8701
--- /dev/null
+++ b/ksvg/dom/SVGSwitchElement.cc
@@ -0,0 +1,72 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGSwitchElement.h"
+#include "SVGSwitchElementImpl.h"
+
+using namespace KSVG;
+
+SVGSwitchElement::SVGSwitchElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable()
+{
+ impl = 0;
+}
+
+SVGSwitchElement::SVGSwitchElement(const SVGSwitchElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGSwitchElement &SVGSwitchElement::operator =(const SVGSwitchElement &other)
+{
+ SVGElement::operator=(other);
+ SVGTests::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+ SVGTransformable::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGSwitchElement::SVGSwitchElement(SVGSwitchElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGSwitchElement::~SVGSwitchElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGSwitchElement.h b/ksvg/dom/SVGSwitchElement.h
new file mode 100644
index 00000000..a4f8819d
--- /dev/null
+++ b/ksvg/dom/SVGSwitchElement.h
@@ -0,0 +1,60 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGSwitchElement_H
+#define SVGSwitchElement_H
+
+#include "SVGElement.h"
+#include "SVGTests.h"
+#include "SVGLangSpace.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+#include "SVGTransformable.h"
+
+namespace KSVG
+{
+
+class SVGSwitchElementImpl;
+class SVGSwitchElement : public SVGElement,
+ public SVGTests,
+ public SVGLangSpace,
+ public SVGExternalResourcesRequired,
+ public SVGStylable,
+ public SVGTransformable
+{
+public:
+ SVGSwitchElement();
+ SVGSwitchElement(const SVGSwitchElement &other);
+ SVGSwitchElement &operator=(const SVGSwitchElement &other);
+ SVGSwitchElement(SVGSwitchElementImpl *other);
+ virtual ~SVGSwitchElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGSwitchElementImpl *handle() const { return impl; }
+
+private:
+ SVGSwitchElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGSymbolElement.cc b/ksvg/dom/SVGSymbolElement.cc
new file mode 100644
index 00000000..d83947a5
--- /dev/null
+++ b/ksvg/dom/SVGSymbolElement.cc
@@ -0,0 +1,71 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGSymbolElement.h"
+#include "SVGSymbolElementImpl.h"
+
+using namespace KSVG;
+
+SVGSymbolElement::SVGSymbolElement() : SVGElement(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGFitToViewBox()
+{
+ impl = 0;
+}
+
+SVGSymbolElement::SVGSymbolElement(const SVGSymbolElement &other) : SVGElement(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGFitToViewBox(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGSymbolElement &SVGSymbolElement::operator =(const SVGSymbolElement &other)
+{
+ SVGElement::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+ SVGFitToViewBox::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGSymbolElement::SVGSymbolElement(SVGSymbolElementImpl *other) : SVGElement(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGFitToViewBox(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGSymbolElement::~SVGSymbolElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGSymbolElement.h b/ksvg/dom/SVGSymbolElement.h
new file mode 100644
index 00000000..8d02987e
--- /dev/null
+++ b/ksvg/dom/SVGSymbolElement.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGSymbolElement_H
+#define SVGSymbolElement_H
+
+#include "SVGElement.h"
+#include "SVGLangSpace.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+#include "SVGFitToViewBox.h"
+
+namespace KSVG
+{
+
+class SVGSymbolElementImpl;
+class SVGSymbolElement : public SVGElement,
+ public SVGLangSpace,
+ public SVGExternalResourcesRequired,
+ public SVGStylable,
+ public SVGFitToViewBox
+{
+public:
+ SVGSymbolElement();
+ SVGSymbolElement(const SVGSymbolElement &other);
+ SVGSymbolElement &operator=(const SVGSymbolElement &other);
+ SVGSymbolElement(SVGSymbolElementImpl *other);
+ virtual ~SVGSymbolElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGSymbolElementImpl *handle() const { return impl; }
+
+private:
+ SVGSymbolElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGTRefElement.cc b/ksvg/dom/SVGTRefElement.cc
new file mode 100644
index 00000000..4faa18ec
--- /dev/null
+++ b/ksvg/dom/SVGTRefElement.cc
@@ -0,0 +1,68 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGTRefElement.h"
+#include "SVGTRefElementImpl.h"
+
+using namespace KSVG;
+
+SVGTRefElement::SVGTRefElement() : SVGTextPositioningElement(), SVGURIReference()
+{
+ impl = 0;
+}
+
+SVGTRefElement::SVGTRefElement(const SVGTRefElement &other) : SVGTextPositioningElement(other), SVGURIReference(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGTRefElement &SVGTRefElement::operator =(const SVGTRefElement &other)
+{
+ SVGTextPositioningElement::operator=(other);
+ SVGURIReference::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGTRefElement::SVGTRefElement(SVGTRefElementImpl *other) : SVGTextPositioningElement(other), SVGURIReference(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGTRefElement::~SVGTRefElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGTRefElement.h b/ksvg/dom/SVGTRefElement.h
new file mode 100644
index 00000000..5585f1d7
--- /dev/null
+++ b/ksvg/dom/SVGTRefElement.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGTRefElement_H
+#define SVGTRefElement_H
+
+#include "SVGTextPositioningElement.h"
+#include "SVGURIReference.h"
+
+namespace KSVG
+{
+
+class SVGTRefElementImpl;
+class SVGTRefElement : public SVGTextPositioningElement,
+ public SVGURIReference
+{
+public:
+ SVGTRefElement();
+ SVGTRefElement(const SVGTRefElement &other);
+ SVGTRefElement &operator=(const SVGTRefElement &other);
+ SVGTRefElement(SVGTRefElementImpl *other);
+ virtual ~SVGTRefElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGTRefElementImpl *handle() const { return impl; }
+
+private:
+ SVGTRefElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGTSpanElement.cc b/ksvg/dom/SVGTSpanElement.cc
new file mode 100644
index 00000000..fc43309c
--- /dev/null
+++ b/ksvg/dom/SVGTSpanElement.cc
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGTSpanElement.h"
+#include "SVGTSpanElementImpl.h"
+
+using namespace KSVG;
+
+SVGTSpanElement::SVGTSpanElement() : SVGTextPositioningElement()
+{
+ impl = 0;
+}
+
+SVGTSpanElement::SVGTSpanElement(const SVGTSpanElement &other) : SVGTextPositioningElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGTSpanElement &SVGTSpanElement::operator =(const SVGTSpanElement &other)
+{
+ SVGTextPositioningElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGTSpanElement::SVGTSpanElement(SVGTSpanElementImpl *other) : SVGTextPositioningElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGTSpanElement::~SVGTSpanElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGTSpanElement.h b/ksvg/dom/SVGTSpanElement.h
new file mode 100644
index 00000000..8fac655b
--- /dev/null
+++ b/ksvg/dom/SVGTSpanElement.h
@@ -0,0 +1,70 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+
+ This file includes excerpts from the Scalable Vector Graphics
+ (SVG) 1.0 Specification (Proposed Recommendation)
+ http://www.w3.org/TR/SVG
+
+ Copyright 2001 World Wide Web Consortium, (Massachusetts
+ Institute of Technology, Institut National de Recherche en
+ Informatique et en Automatique, Keio University).
+ All Rights Reserved.
+*/
+
+#ifndef SVGTSpanElement_H
+#define SVGTSpanElement_H
+
+#include "SVGTextPositioningElement.h"
+
+namespace KSVG
+{
+
+class SVGTSpanElementImpl;
+
+/**
+ * Within a <code>text</code> element, text and font properties and the current
+ * text position can be adjusted with absolute or relative coordinate values by
+ * including a <code>tspan</code> element.
+ *
+ * For more information :
+ * <a href="http://www.w3.org/TR/SVG/text.html#TSpanElement">
+ * 10.5 the 'tspan' element</a>
+ */
+class SVGTSpanElement : public SVGTextPositioningElement
+{
+public:
+ SVGTSpanElement();
+ SVGTSpanElement(const SVGTSpanElement &other);
+ SVGTSpanElement &operator=(const SVGTSpanElement &other);
+ SVGTSpanElement(SVGTSpanElementImpl *other);
+ virtual ~SVGTSpanElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGTSpanElementImpl *handle() const { return impl; }
+
+private:
+ SVGTSpanElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGTests.cc b/ksvg/dom/SVGTests.cc
new file mode 100644
index 00000000..9c3063b1
--- /dev/null
+++ b/ksvg/dom/SVGTests.cc
@@ -0,0 +1,83 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGTests.h"
+#include "SVGTestsImpl.h"
+#include "SVGStringList.h"
+
+using namespace KSVG;
+
+// This class can't be constructed seperately.
+SVGTests::SVGTests()
+{
+ impl = 0;
+}
+
+SVGTests::SVGTests(const SVGTests &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGTests &SVGTests::operator=(const SVGTests &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ impl = other.impl;
+
+ return *this;
+}
+
+SVGTests::SVGTests(SVGTestsImpl *other)
+{
+ impl = other;
+}
+
+SVGTests::~SVGTests()
+{
+ // We are not allowed to delete 'impl' as it's not refcounted.
+ // delete impl;
+}
+
+SVGStringList SVGTests::requiredFeatures() const
+{
+ if(!impl) return SVGStringList(0);
+ return SVGStringList(impl->requiredFeatures());
+}
+
+SVGStringList SVGTests::requiredExtensions() const
+{
+ if(!impl) return SVGStringList(0);
+ return SVGStringList(impl->requiredExtensions());
+}
+
+SVGStringList SVGTests::systemLanguage() const
+{
+ if(!impl) return SVGStringList(0);
+ return SVGStringList(impl->systemLanguage());
+}
+
+bool SVGTests::hasExtension(const DOM::DOMString &extension)
+{
+ if(!impl) return false;
+ return impl->hasExtension(extension);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGTests.h b/ksvg/dom/SVGTests.h
new file mode 100644
index 00000000..729b0efc
--- /dev/null
+++ b/ksvg/dom/SVGTests.h
@@ -0,0 +1,59 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGTests_H
+#define SVGTests_H
+
+#include <dom/dom_string.h>
+
+namespace KSVG
+{
+
+class SVGStringList;
+class SVGTestsImpl;
+class SVGTests
+{
+public:
+ SVGTests(const SVGTests &other);
+ SVGTests &operator=(const SVGTests &other);
+ SVGTests(SVGTestsImpl *other);
+ ~SVGTests();
+
+ SVGStringList requiredFeatures() const;
+ SVGStringList requiredExtensions() const;
+ SVGStringList systemLanguage() const;
+
+ bool hasExtension(const DOM::DOMString &extension);
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGTestsImpl *handle() const { return impl; }
+
+protected:
+ SVGTests();
+
+private:
+ SVGTestsImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGTextContentElement.cc b/ksvg/dom/SVGTextContentElement.cc
new file mode 100644
index 00000000..f40d23b6
--- /dev/null
+++ b/ksvg/dom/SVGTextContentElement.cc
@@ -0,0 +1,120 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGTextContentElement.h"
+#include "SVGTextContentElementImpl.h"
+#include "SVGAnimatedEnumeration.h"
+#include "SVGAnimatedLength.h"
+
+using namespace KSVG;
+
+SVGTextContentElement::SVGTextContentElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable()
+{
+ impl = new SVGTextContentElementImpl(0);
+}
+
+SVGTextContentElement::SVGTextContentElement(const SVGTextContentElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other)
+{
+ impl = other.impl;
+}
+
+SVGTextContentElement &SVGTextContentElement::operator=(const SVGTextContentElement &other)
+{
+ SVGElement::operator=(other);
+ SVGTests::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ delete impl;
+ impl = other.impl;
+
+ return *this;
+}
+
+SVGTextContentElement::SVGTextContentElement(SVGTextContentElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other)
+{
+ impl = other;
+}
+
+SVGTextContentElement::~SVGTextContentElement()
+{
+}
+
+
+SVGAnimatedLength SVGTextContentElement::textLength() const
+{
+ return impl->textLength();
+}
+
+SVGAnimatedEnumeration SVGTextContentElement::lengthAdjust() const
+{
+ if(!impl) return SVGAnimatedEnumeration(0);
+ return SVGAnimatedEnumeration(impl->lengthAdjust());
+}
+
+long SVGTextContentElement::getNumberOfChars()
+{
+ return impl->getNumberOfChars();
+}
+
+float SVGTextContentElement::getComputedTextLength()
+{
+ return impl->getComputedTextLength();
+}
+/*
+float SVGTextContentElement::getSubStringLength(const unsigned long &charnum, const unsigned long &nchars)
+{
+ return impl->getSubStringLength(charnum, nchars);
+}
+
+SVGPoint SVGTextContentElement::getStartPositionOfChar(const unsigned long &charnum)
+{
+ return impl->getStartPositionOfChar(charnum);
+}
+
+SVGPoint SVGTextContentElement::getEndPositionOfChar(const unsigned long &charnum)
+{
+ return impl->getEndPositionOfChar(charnum);
+}
+
+SVGRect SVGTextContentElement::getExtentOfChar(const unsigned long &charnum)
+{
+ return impl->getExtentOfChar(charnum);
+}
+
+float SVGTextContentElement::getRotationOfChar(const unsigned long &charnum)
+{
+ return impl->getRotationOfChar(charnum);
+}
+
+long SVGTextContentElement::getCharNumAtPosition(const SVGPoint &point)
+{
+ return impl->getCharNumAtPosition(point);
+}
+
+void SVGTextContentElement::selectSubString(const unsigned long &charnum, const unsigned long &nchars)
+{
+ return impl->selectSubString(charnum, nchars);
+}
+*/
diff --git a/ksvg/dom/SVGTextContentElement.h b/ksvg/dom/SVGTextContentElement.h
new file mode 100644
index 00000000..2f943c06
--- /dev/null
+++ b/ksvg/dom/SVGTextContentElement.h
@@ -0,0 +1,79 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGTextContentElement_H
+#define SVGTextContentElement_H
+
+#include "SVGElement.h"
+#include "SVGTests.h"
+#include "SVGLangSpace.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+
+namespace KSVG
+{
+
+enum
+{
+ LENGTHADJUST_UNKNOWN = 0,
+ LENGTHADJUST_SPACING = 1,
+ LENGTHADJUST_SPACINGANDGLYPHS = 2
+};
+
+class SVGAnimatedLength;
+class SVGAnimatedEnumeration;
+class SVGTextContentElementImpl;
+class SVGTextContentElement : public SVGElement,
+ public SVGTests,
+ public SVGLangSpace,
+ public SVGExternalResourcesRequired,
+ public SVGStylable
+{
+public:
+ SVGTextContentElement(const SVGTextContentElement &);
+ SVGTextContentElement &operator=(const SVGTextContentElement &other);
+ SVGTextContentElement(SVGTextContentElementImpl *);
+ ~SVGTextContentElement();
+
+ SVGAnimatedLength textLength() const;
+ SVGAnimatedEnumeration lengthAdjust() const;
+ long getNumberOfChars();
+ float getComputedTextLength();
+// float getSubStringLength(const unsigned long &charnum, const unsigned long &nchars);
+// SVGPoint getStartPositionOfChar(const unsigned long &charnum);
+// SVGPoint getEndPositionOfChar(const unsigned long &charnum);
+// SVGRect getExtentOfChar(const unsigned long &charnum);
+// float getRotationOfChar(const unsigned long &charnum);
+// long getCharNumAtPosition(const SVGPoint &point);
+// void selectSubString(const unsigned long &charnum, const unsigned long &nchars);
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGTextContentElementImpl *handle() const { return impl; }
+
+protected:
+ SVGTextContentElement();
+
+private:
+ SVGTextContentElementImpl *impl;
+};
+
+}
+
+#endif
diff --git a/ksvg/dom/SVGTextElement.cc b/ksvg/dom/SVGTextElement.cc
new file mode 100644
index 00000000..b80a148a
--- /dev/null
+++ b/ksvg/dom/SVGTextElement.cc
@@ -0,0 +1,68 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+#include "SVGTextElement.h"
+#include "SVGTextElementImpl.h"
+#include "SVGAnimatedLength.h"
+
+using namespace KSVG;
+
+SVGTextElement::SVGTextElement() : SVGTextPositioningElement(), SVGTransformable()
+{
+ impl = 0;
+}
+
+SVGTextElement::SVGTextElement(const SVGTextElement &other) : SVGTextPositioningElement(other), SVGTransformable(other)
+{
+ (*this) = other;
+}
+
+SVGTextElement &SVGTextElement::operator =(const SVGTextElement &other)
+{
+ SVGTextPositioningElement::operator=(other);
+ SVGTransformable::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGTextElement::SVGTextElement(SVGTextElementImpl *other) : SVGTextPositioningElement(other), SVGTransformable(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGTextElement::~SVGTextElement()
+{
+ if(impl)
+ impl->deref();
+}
diff --git a/ksvg/dom/SVGTextElement.h b/ksvg/dom/SVGTextElement.h
new file mode 100644
index 00000000..0bf459fe
--- /dev/null
+++ b/ksvg/dom/SVGTextElement.h
@@ -0,0 +1,115 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with this library; see the file COPYING.LIB. If
+ not, write to the Free Software Foundation, Inc., 51 Franklin Street,
+ Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+ This file includes excerpts from the Scalable Vector Graphics
+ (SVG) 1.0 Specification (Proposed Recommendation)
+ http://www.w3.org/TR/SVG
+
+ Copyright 2001 World Wide Web Consortium, (Massachusetts
+ Institute of Technology, Institut National de Recherche en
+ Informatique et en Automatique, Keio University).
+ All Rights Reserved.
+
+ $Id$
+ */
+
+
+#ifndef SVGTextElement_H
+#define SVGTextElement_H
+
+#include "SVGTextPositioningElement.h"
+#include "SVGTransformable.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedLength;
+class SVGTextElementImpl;
+
+/**
+ * @short The <code>text</code> element defines a graphics element
+ * consisting of text.
+ *
+ * The XML character data within the <code>text</code> element, along
+ * with relevant attributes and properties and character-to-glyph
+ * mapping tables within the font itself, define the glyphs to be
+ * rendered. (See <a
+ * href="http://www.w3.org/TR/SVG/text.html#CharactersAndGlyphs"> Characters
+ * and their corresponding glyphs </a>.) The attributes and properties on the
+ * 'text' element indicate such things as the writing direction, font
+ * specification and painting attributes which describe how exactly to render
+ * the characters. Since <code>text</code> elements are rendered using the
+ * same rendering methods as other graphics elements, all of the same
+ * coordinate system transformations, painting, clipping and masking
+ * features that apply to shapes such as paths and rectangles also
+ * apply to <code>text</code> elements.
+ *
+ * It is possible to apply a gradient, pattern, clipping path, mask or
+ * filter to text.When one of these facilities is applied to text and
+ * keyword objectBoundingBox is used to specify a graphical effect
+ * relative to the "object bounding box", then the object bounding box
+ * units are computed relative to the entire 'text' element in all
+ * cases, even when different effects are applied to different 'tspan'
+ * elements within the same 'text' element.
+ *
+
+ * The <code>text</code> element renders its first glyph (after <a
+ * href = "http://www.w3.org/TR/SVG/text.html#RelationshipWithBiDirectionality"
+ * >bidirectionality</a> reordering) at the initial current text
+ * position, which is established by the <code>x</code> and
+ * <code>y</code> attributes on the <code>text</code> element (with
+ * possible adjustments due to the value of the @ref text-anchor
+ * property, the presence of a @ref textPath element containing the
+ * first character, and/or an <code>x</code>, <code>y</code>,
+ * <code>dx</code> or <code>dy</code> attributes on a @ref tspan, @ref
+ * tref or @ref altGlyph element which contains the first character).
+ * After the glyph(s) corresponding to the given character is(are)
+ * rendered, the current text position is updated for the next
+ * character. In the simplest case, the new current text position is
+ * the previous current text position plus the glyphs' advance value
+ * (horizontal or vertical).
+ *
+ * @see SVGShape
+ * @see SVGTextPositioningElement
+ *
+ * For more info look here : <a href =
+ * "http://www.w3.org/TR/SVG/text.html#TextElement"> 10.4 The
+ * 'text' element</a>.
+ */
+class SVGTextElement : public SVGTextPositioningElement,
+ public SVGTransformable
+{
+public:
+ SVGTextElement();
+ SVGTextElement(const SVGTextElement &);
+ SVGTextElement &operator=(const SVGTextElement &other);
+ SVGTextElement(SVGTextElementImpl *);
+ ~SVGTextElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGTextElementImpl *handle() const { return impl; }
+
+private:
+ SVGTextElementImpl *impl;
+};
+
+}
+
+#endif
diff --git a/ksvg/dom/SVGTextPathElement.cc b/ksvg/dom/SVGTextPathElement.cc
new file mode 100644
index 00000000..1cb6b833
--- /dev/null
+++ b/ksvg/dom/SVGTextPathElement.cc
@@ -0,0 +1,89 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGTextPathElement.h"
+#include "SVGTextPathElementImpl.h"
+#include "SVGAnimatedEnumeration.h"
+#include "SVGAnimatedLength.h"
+
+using namespace KSVG;
+
+SVGTextPathElement::SVGTextPathElement() : SVGTextContentElement(), SVGURIReference()
+{
+ impl = new SVGTextPathElementImpl(0);
+ impl->ref();
+}
+
+SVGTextPathElement::SVGTextPathElement(const SVGTextPathElement &other) : SVGTextContentElement(other), SVGURIReference(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGTextPathElement &SVGTextPathElement::operator =(const SVGTextPathElement &other)
+{
+ SVGTextContentElement::operator=(other);
+ SVGURIReference::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGTextPathElement::SVGTextPathElement(SVGTextPathElementImpl *other) : SVGTextContentElement(other), SVGURIReference(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGTextPathElement::~SVGTextPathElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedLength SVGTextPathElement::startOffset() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->startOffset());
+}
+
+SVGAnimatedEnumeration SVGTextPathElement::method() const
+{
+ if(!impl) return SVGAnimatedEnumeration(0);
+ return SVGAnimatedEnumeration(impl->method());
+}
+
+SVGAnimatedEnumeration SVGTextPathElement::spacing() const
+{
+ if(!impl) return SVGAnimatedEnumeration(0);
+ return SVGAnimatedEnumeration(impl->spacing());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGTextPathElement.h b/ksvg/dom/SVGTextPathElement.h
new file mode 100644
index 00000000..69c7fe79
--- /dev/null
+++ b/ksvg/dom/SVGTextPathElement.h
@@ -0,0 +1,70 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGTextPathElement_H
+#define SVGTextPathElement_H
+
+#include "SVGTextContentElement.h"
+#include "SVGURIReference.h"
+
+namespace KSVG
+{
+
+enum
+{
+ TEXTPATH_METHODTYPE_UNKNOWN = 0,
+ TEXTPATH_METHODTYPE_ALIGN = 1,
+ TEXTPATH_METHODTYPE_STRETCH = 2
+};
+
+enum
+{
+ TEXTPATH_SPACINGTYPE_UNKNOWN = 0,
+ TEXTPATH_SPACINGTYPE_AUTO = 1,
+ TEXTPATH_SPACINGTYPE_EXACT = 2
+};
+
+class SVGTextPathElementImpl;
+class SVGTextPathElement : public SVGTextContentElement,
+ public SVGURIReference
+{
+public:
+ SVGTextPathElement();
+ SVGTextPathElement(const SVGTextPathElement &other);
+ SVGTextPathElement &operator=(const SVGTextPathElement &other);
+ SVGTextPathElement(SVGTextPathElementImpl *other);
+ virtual ~SVGTextPathElement();
+
+ SVGAnimatedLength startOffset() const;
+ SVGAnimatedEnumeration method() const;
+ SVGAnimatedEnumeration spacing() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGTextPathElementImpl *handle() const { return impl; }
+
+private:
+ SVGTextPathElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGTextPositioningElement.cc b/ksvg/dom/SVGTextPositioningElement.cc
new file mode 100644
index 00000000..6ce7d346
--- /dev/null
+++ b/ksvg/dom/SVGTextPositioningElement.cc
@@ -0,0 +1,85 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+#include "SVGTextPositioningElement.h"
+#include "SVGTextPositioningElementImpl.h"
+#include "SVGAnimatedNumber.h"
+#include "SVGAnimatedNumberList.h"
+#include "SVGAnimatedLength.h"
+#include "SVGAnimatedLengthList.h"
+
+using namespace KSVG;
+
+SVGTextPositioningElement::SVGTextPositioningElement() : SVGTextContentElement()
+{
+ impl = new SVGTextPositioningElementImpl(0);
+}
+
+SVGTextPositioningElement::SVGTextPositioningElement(const SVGTextPositioningElement &other) : SVGTextContentElement(other)
+{
+ impl = other.impl;
+}
+
+SVGTextPositioningElement &SVGTextPositioningElement::operator=(const SVGTextPositioningElement &other)
+{
+ SVGTextContentElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ delete impl;
+ impl = other.impl;
+
+ return *this;
+}
+SVGTextPositioningElement::SVGTextPositioningElement(SVGTextPositioningElementImpl *other) : SVGTextContentElement(other)
+{
+ impl = other;
+}
+
+SVGTextPositioningElement::~SVGTextPositioningElement()
+{
+}
+
+SVGAnimatedLengthList SVGTextPositioningElement::x()
+{
+ return SVGAnimatedLengthList(impl->x());
+}
+
+SVGAnimatedLengthList SVGTextPositioningElement::y()
+{
+ return SVGAnimatedLengthList(impl->y());
+}
+
+SVGAnimatedLengthList SVGTextPositioningElement::dx()
+{
+ return SVGAnimatedLengthList(impl->dx());
+}
+
+SVGAnimatedLengthList SVGTextPositioningElement::dy()
+{
+ return SVGAnimatedLengthList(impl->dy());
+}
+
+SVGAnimatedNumberList SVGTextPositioningElement::rotate()
+{
+ return SVGAnimatedNumberList(impl->rotate());
+}
diff --git a/ksvg/dom/SVGTextPositioningElement.h b/ksvg/dom/SVGTextPositioningElement.h
new file mode 100644
index 00000000..f02950ca
--- /dev/null
+++ b/ksvg/dom/SVGTextPositioningElement.h
@@ -0,0 +1,60 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGTextPositioningElement_H
+#define SVGTextPositioningElement_H
+
+#include "SVGTextContentElement.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedLength;
+class SVGAnimatedLengthList;
+class SVGAnimatedNumber;
+class SVGAnimatedNumberList;
+class SVGTextPositioningElementImpl;
+class SVGTextPositioningElement : public SVGTextContentElement
+{
+public:
+ SVGTextPositioningElement(const SVGTextPositioningElement &);
+ SVGTextPositioningElement &operator=(const SVGTextPositioningElement &other);
+ SVGTextPositioningElement(SVGTextPositioningElementImpl *);
+ ~SVGTextPositioningElement();
+
+ SVGAnimatedLengthList x();
+ SVGAnimatedLengthList y();
+ SVGAnimatedLengthList dx();
+ SVGAnimatedLengthList dy();
+ SVGAnimatedNumberList rotate();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGTextPositioningElementImpl *handle() const { return impl; }
+
+protected:
+ SVGTextPositioningElement();
+
+private:
+ SVGTextPositioningElementImpl *impl;
+};
+
+}
+
+#endif
diff --git a/ksvg/dom/SVGTitleElement.cc b/ksvg/dom/SVGTitleElement.cc
new file mode 100644
index 00000000..f319c126
--- /dev/null
+++ b/ksvg/dom/SVGTitleElement.cc
@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGTitleElement.h"
+#include "SVGTitleElementImpl.h"
+
+using namespace KSVG;
+
+SVGTitleElement::SVGTitleElement() : SVGElement(), SVGLangSpace(), SVGStylable()
+{
+ impl = 0;
+}
+
+SVGTitleElement::SVGTitleElement(const SVGTitleElement &other) : SVGElement(other), SVGLangSpace(other), SVGStylable(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGTitleElement &SVGTitleElement::operator =(const SVGTitleElement &other)
+{
+ SVGElement::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGStylable::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGTitleElement::SVGTitleElement(SVGTitleElementImpl *other) : SVGElement(other), SVGLangSpace(other), SVGStylable(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGTitleElement::~SVGTitleElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGTitleElement.h b/ksvg/dom/SVGTitleElement.h
new file mode 100644
index 00000000..95f26272
--- /dev/null
+++ b/ksvg/dom/SVGTitleElement.h
@@ -0,0 +1,54 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGTitleElement_H
+#define SVGTitleElement_H
+
+#include "SVGElement.h"
+#include "SVGLangSpace.h"
+#include "SVGStylable.h"
+
+namespace KSVG
+{
+
+class SVGTitleElementImpl;
+class SVGTitleElement : public SVGElement,
+ public SVGLangSpace,
+ public SVGStylable
+{
+public:
+ SVGTitleElement();
+ SVGTitleElement(const SVGTitleElement &other);
+ SVGTitleElement &operator=(const SVGTitleElement &other);
+ SVGTitleElement(SVGTitleElementImpl *other);
+ virtual ~SVGTitleElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGTitleElementImpl *handle() const { return impl; }
+
+private:
+ SVGTitleElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGTransform.cc b/ksvg/dom/SVGTransform.cc
new file mode 100644
index 00000000..df660678
--- /dev/null
+++ b/ksvg/dom/SVGTransform.cc
@@ -0,0 +1,119 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGTransformImpl.h"
+#include "SVGTransform.h"
+#include "SVGMatrix.h"
+
+using namespace KSVG;
+
+SVGTransform::SVGTransform()
+{
+ impl = new SVGTransformImpl();
+ impl->ref();
+}
+
+SVGTransform::SVGTransform(const SVGTransform &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGTransform &SVGTransform::operator=(const SVGTransform &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGTransform::SVGTransform(SVGTransformImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGTransform::~SVGTransform()
+{
+}
+
+unsigned short SVGTransform::type() const
+{
+ if(!impl) return SVG_TRANSFORM_UNKNOWN;
+ return impl->type();
+}
+
+SVGMatrix SVGTransform::matrix() const
+{
+ if(!impl) return SVGMatrix(0);
+ return SVGMatrix(impl->matrix());
+}
+
+double SVGTransform::angle() const
+{
+ if(!impl) return -1;
+ return impl->angle();
+}
+
+void SVGTransform::setMatrix(SVGMatrix matrix)
+{
+ if(impl)
+ impl->setMatrix(matrix.handle());
+}
+
+void SVGTransform::setTranslate(double tx, double ty)
+{
+ if(impl)
+ impl->setTranslate(tx, ty);
+}
+
+void SVGTransform::setScale(double sx, double sy)
+{
+ if(impl)
+ impl->setScale(sx, sy);
+}
+
+void SVGTransform::setRotate(double angle, double cx, double cy)
+{
+ if(impl)
+ impl->setRotate(angle, cx, cy);
+}
+
+void SVGTransform::setSkewX(double angle)
+{
+ if(impl)
+ impl->setSkewX(angle);
+}
+
+void SVGTransform::setSkewY(double angle)
+{
+ if(impl)
+ impl->setSkewY(angle);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGTransform.h b/ksvg/dom/SVGTransform.h
new file mode 100644
index 00000000..b7ca927f
--- /dev/null
+++ b/ksvg/dom/SVGTransform.h
@@ -0,0 +1,71 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGTransform_H
+#define SVGTransform_H
+
+namespace KSVG
+{
+
+enum
+{
+ SVG_TRANSFORM_UNKNOWN = 0,
+ SVG_TRANSFORM_MATRIX = 1,
+ SVG_TRANSFORM_TRANSLATE = 2,
+ SVG_TRANSFORM_SCALE = 3,
+ SVG_TRANSFORM_ROTATE = 4,
+ SVG_TRANSFORM_SKEWX = 5,
+ SVG_TRANSFORM_SKEWY = 6
+};
+
+class SVGMatrix;
+class SVGTransformImpl;
+class SVGTransform
+{
+public:
+ SVGTransform();
+ SVGTransform(const SVGTransform &);
+ SVGTransform &operator=(const SVGTransform &);
+ SVGTransform(SVGTransformImpl *);
+ ~SVGTransform();
+
+ unsigned short type() const;
+ SVGMatrix matrix() const;
+ double angle() const;
+
+ void setMatrix(SVGMatrix);
+ void setTranslate(double, double);
+ void setScale(double, double);
+ void setRotate(double, double, double);
+ void setSkewX(double);
+ void setSkewY(double);
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGTransformImpl *handle() const { return impl; }
+
+private:
+ SVGTransformImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGTransformList.cc b/ksvg/dom/SVGTransformList.cc
new file mode 100644
index 00000000..541db510
--- /dev/null
+++ b/ksvg/dom/SVGTransformList.cc
@@ -0,0 +1,129 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGTransformList.h"
+#include "SVGTransformListImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGMatrix.h"
+#include "SVGTransform.h"
+
+using namespace KSVG;
+
+SVGTransformList::SVGTransformList()
+{
+ impl = new SVGTransformListImpl();
+ impl->ref();
+}
+
+SVGTransformList::SVGTransformList(const SVGTransformList &other)
+{
+ (*this) = other;
+}
+
+SVGTransformList &SVGTransformList::operator=(const SVGTransformList &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGTransformList::SVGTransformList(SVGTransformListImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGTransformList::~SVGTransformList()
+{
+ if(impl)
+ impl->deref();
+}
+
+unsigned long SVGTransformList::numberOfItems() const
+{
+ if(!impl) return 0;
+ return impl->numberOfItems();
+}
+
+void SVGTransformList::clear()
+{
+ if(impl)
+ impl->clear();
+}
+
+SVGTransform *SVGTransformList::initialize(SVGTransform *newItem)
+{
+ if(!impl) return new SVGTransform(0);
+ return new SVGTransform(impl->initialize(newItem->handle()));
+}
+
+SVGTransform *SVGTransformList::getItem(unsigned long index)
+{
+ if(!impl) return new SVGTransform(0);
+ return new SVGTransform(impl->getItem(index));
+}
+
+SVGTransform *SVGTransformList::insertItemBefore(SVGTransform *newItem, unsigned long index)
+{
+ if(!impl) return new SVGTransform(0);
+ return new SVGTransform(impl->insertItemBefore(newItem->handle(), index));
+}
+
+SVGTransform *SVGTransformList::replaceItem(SVGTransform *newItem, unsigned long index)
+{
+ if(!impl) return new SVGTransform(0);
+ return new SVGTransform(impl->replaceItem(newItem->handle(), index));
+}
+
+SVGTransform *SVGTransformList::removeItem(unsigned long index)
+{
+ if(!impl) return new SVGTransform(0);
+ return new SVGTransform(impl->removeItem(index));
+}
+
+SVGTransform *SVGTransformList::appendItem(SVGTransform *newItem)
+{
+ if(!impl) return new SVGTransform(0);
+ return new SVGTransform(impl->appendItem(newItem->handle()));
+}
+
+SVGTransform *SVGTransformList::createSVGTransformFromMatrix(SVGMatrix &matrix)
+{
+ if(!impl) return new SVGTransform(0);
+ return new SVGTransform(SVGSVGElementImpl::createSVGTransformFromMatrix(matrix.handle()));
+}
+
+SVGTransform *SVGTransformList::consolidate()
+{
+ if(!impl || impl->numberOfItems()==0) return 0;
+ return new SVGTransform(impl->consolidate());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGTransformList.h b/ksvg/dom/SVGTransformList.h
new file mode 100644
index 00000000..8d448718
--- /dev/null
+++ b/ksvg/dom/SVGTransformList.h
@@ -0,0 +1,63 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGTransformList_H
+#define SVGTransformList_H
+
+namespace KSVG
+{
+
+class SVGMatrix;
+class SVGTransform;
+class SVGTransformListImpl;
+class SVGTransformList
+{
+public:
+ SVGTransformList();
+ SVGTransformList(const SVGTransformList &);
+ SVGTransformList &operator=(const SVGTransformList &);
+ SVGTransformList(SVGTransformListImpl *);
+ ~SVGTransformList();
+
+ unsigned long numberOfItems() const;
+ void clear();
+
+ SVGTransform *initialize(SVGTransform *newItem);
+ SVGTransform *getItem(unsigned long index);
+ SVGTransform *insertItemBefore(SVGTransform *newItem, unsigned long index);
+ SVGTransform *replaceItem(SVGTransform *newItem, unsigned long index);
+ SVGTransform *removeItem(unsigned long index);
+ SVGTransform *appendItem(SVGTransform *newItem);
+
+ SVGTransform *createSVGTransformFromMatrix(SVGMatrix &matrix);
+ SVGTransform *consolidate();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGTransformListImpl *handle() const { return impl; }
+
+private:
+ SVGTransformListImpl *impl;
+};
+
+}
+
+#endif
+// vim:ts=4:noet
+
diff --git a/ksvg/dom/SVGTransformable.cc b/ksvg/dom/SVGTransformable.cc
new file mode 100644
index 00000000..64530d39
--- /dev/null
+++ b/ksvg/dom/SVGTransformable.cc
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGTransformable.h"
+#include "SVGTransformableImpl.h"
+#include "SVGAnimatedTransformList.h"
+
+using namespace KSVG;
+
+// This class can't be constructed seperately.
+SVGTransformable::SVGTransformable() : SVGLocatable()
+{
+ impl = 0;
+}
+
+SVGTransformable::SVGTransformable(const SVGTransformable &other) : SVGLocatable(other)
+{
+ (*this) = other;
+}
+
+SVGTransformable &SVGTransformable::operator=(const SVGTransformable &other)
+{
+ SVGLocatable::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ impl = other.impl;
+
+ return *this;
+}
+
+SVGTransformable::SVGTransformable(SVGTransformableImpl *other) : SVGLocatable(other)
+{
+ impl = other;
+}
+
+SVGTransformable::~SVGTransformable()
+{
+ // We are not allowed to delete 'impl' as it's not refcounted.
+ // delete impl;
+}
+
+SVGAnimatedTransformList SVGTransformable::transform()
+{
+ if(!impl) return SVGAnimatedTransformList(0);
+ return SVGAnimatedTransformList(impl->transform());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGTransformable.h b/ksvg/dom/SVGTransformable.h
new file mode 100644
index 00000000..54bf0a40
--- /dev/null
+++ b/ksvg/dom/SVGTransformable.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGTransformable_H
+#define SVGTransformable_H
+
+#include "SVGLocatable.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedTransformList;
+class SVGTransformableImpl;
+class SVGTransformable : public SVGLocatable
+{
+public:
+ SVGTransformable(const SVGTransformable &other);
+ SVGTransformable &operator=(const SVGTransformable &other);
+ SVGTransformable(SVGTransformableImpl *other);
+ virtual ~SVGTransformable();
+
+ SVGAnimatedTransformList transform();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGTransformableImpl *handle() const { return impl; }
+
+protected:
+ SVGTransformable();
+
+private:
+ SVGTransformableImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGURIReference.cc b/ksvg/dom/SVGURIReference.cc
new file mode 100644
index 00000000..e872e9d6
--- /dev/null
+++ b/ksvg/dom/SVGURIReference.cc
@@ -0,0 +1,63 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGURIReference.h"
+#include "SVGURIReferenceImpl.h"
+#include "SVGAnimatedString.h"
+
+using namespace KSVG;
+
+SVGURIReference::SVGURIReference()
+{
+ impl = new SVGURIReferenceImpl();
+}
+
+SVGURIReference::SVGURIReference(const SVGURIReference &other)
+{
+ impl = other.impl;
+}
+
+SVGURIReference &SVGURIReference::operator=(const SVGURIReference &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ delete impl;
+ impl = other.impl;
+
+ return *this;
+}
+
+SVGURIReference::SVGURIReference(SVGURIReferenceImpl *other)
+{
+ impl = other;
+}
+
+SVGURIReference::~SVGURIReference()
+{
+}
+
+SVGAnimatedString SVGURIReference::href() const
+{
+ if(!impl) return SVGAnimatedString(0);
+ return SVGAnimatedString(impl->href());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGURIReference.h b/ksvg/dom/SVGURIReference.h
new file mode 100644
index 00000000..571cd2b2
--- /dev/null
+++ b/ksvg/dom/SVGURIReference.h
@@ -0,0 +1,53 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGURIReference_H
+#define SVGURIReference_H
+
+namespace KSVG
+{
+
+class SVGAnimatedString;
+class SVGURIReferenceImpl;
+class SVGURIReference
+{
+public:
+ SVGURIReference(const SVGURIReference &other);
+ SVGURIReference &operator=(const SVGURIReference &other);
+ SVGURIReference(SVGURIReferenceImpl *other);
+ virtual ~SVGURIReference();
+
+ SVGAnimatedString href() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGURIReferenceImpl *handle() const { return impl; }
+
+protected:
+ SVGURIReference();
+
+private:
+ SVGURIReferenceImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGUnitTypes.h b/ksvg/dom/SVGUnitTypes.h
new file mode 100644
index 00000000..76079af2
--- /dev/null
+++ b/ksvg/dom/SVGUnitTypes.h
@@ -0,0 +1,41 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGUnitTypes_H
+#define SVGUnitTypes_H
+
+namespace KSVG
+{
+
+struct SVGUnitTypes
+{
+ enum
+ {
+ SVG_UNIT_TYPE_UNKNOWN = 0,
+ SVG_UNIT_TYPE_USERSPACEONUSE = 1,
+ SVG_UNIT_TYPE_OBJECTBOUNDINGBOX = 2
+ };
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGUseElement.cc b/ksvg/dom/SVGUseElement.cc
new file mode 100644
index 00000000..8cd8ef26
--- /dev/null
+++ b/ksvg/dom/SVGUseElement.cc
@@ -0,0 +1,111 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGUseElement.h"
+#include "SVGUseElementImpl.h"
+#include "SVGElementInstance.h"
+#include "SVGAnimatedLength.h"
+
+using namespace KSVG;
+
+SVGUseElement::SVGUseElement() : SVGElement(), SVGTests(), SVGLangSpace(), SVGExternalResourcesRequired(), SVGStylable(), SVGTransformable(), SVGURIReference()
+{
+ impl = 0;
+}
+
+SVGUseElement::SVGUseElement(const SVGUseElement &other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), SVGURIReference(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGUseElement &SVGUseElement::operator =(const SVGUseElement &other)
+{
+ SVGElement::operator=(other);
+ SVGTests::operator=(other);
+ SVGLangSpace::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGStylable::operator=(other);
+ SVGTransformable::operator=(other);
+ SVGURIReference::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGUseElement::SVGUseElement(SVGUseElementImpl *other) : SVGElement(other), SVGTests(other), SVGLangSpace(other), SVGExternalResourcesRequired(other), SVGStylable(other), SVGTransformable(other), SVGURIReference(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGUseElement::~SVGUseElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGAnimatedLength SVGUseElement::x() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->x());
+}
+
+SVGAnimatedLength SVGUseElement::y() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->y());
+}
+
+SVGAnimatedLength SVGUseElement::width() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->width());
+}
+
+SVGAnimatedLength SVGUseElement::height() const
+{
+ if(!impl) return SVGAnimatedLength(0);
+ return SVGAnimatedLength(impl->height());
+}
+
+SVGElementInstance SVGUseElement::instanceRoot() const
+{
+ if(!impl) return SVGElementInstance(0);
+ return impl->instanceRoot();
+}
+
+SVGElementInstance SVGUseElement::animatedInstanceRoot() const
+{
+ if(!impl) return SVGElementInstance(0);
+ return impl->animatedInstanceRoot();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGUseElement.h b/ksvg/dom/SVGUseElement.h
new file mode 100644
index 00000000..fb494abb
--- /dev/null
+++ b/ksvg/dom/SVGUseElement.h
@@ -0,0 +1,71 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGUseElement_H
+#define SVGUseElement_H
+
+#include "SVGElement.h"
+#include "SVGTests.h"
+#include "SVGLangSpace.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGStylable.h"
+#include "SVGTransformable.h"
+#include "SVGURIReference.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedLength;
+class SVGElementInstance;
+class SVGUseElementImpl;
+class SVGUseElement : public SVGElement,
+ public SVGTests,
+ public SVGLangSpace,
+ public SVGExternalResourcesRequired,
+ public SVGStylable,
+ public SVGTransformable,
+ public SVGURIReference
+{
+public:
+ SVGUseElement();
+ SVGUseElement(const SVGUseElement &other);
+ SVGUseElement &operator=(const SVGUseElement &other);
+ SVGUseElement(SVGUseElementImpl *other);
+ virtual ~SVGUseElement();
+
+ SVGAnimatedLength x() const;
+ SVGAnimatedLength y() const;
+ SVGAnimatedLength width() const;
+ SVGAnimatedLength height() const;
+ SVGElementInstance instanceRoot() const;
+ SVGElementInstance animatedInstanceRoot() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGUseElementImpl *handle() const { return impl; }
+
+private:
+ SVGUseElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGVKernElement.cc b/ksvg/dom/SVGVKernElement.cc
new file mode 100644
index 00000000..ad6dbee5
--- /dev/null
+++ b/ksvg/dom/SVGVKernElement.cc
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGVKernElement.h"
+#include "SVGVKernElementImpl.h"
+
+using namespace KSVG;
+
+SVGVKernElement::SVGVKernElement() : SVGElement()
+{
+ impl = 0;
+}
+
+SVGVKernElement::SVGVKernElement(const SVGVKernElement &other) : SVGElement(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGVKernElement &SVGVKernElement::operator =(const SVGVKernElement &other)
+{
+ SVGElement::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGVKernElement::SVGVKernElement(SVGVKernElementImpl *other) : SVGElement(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGVKernElement::~SVGVKernElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGVKernElement.h b/ksvg/dom/SVGVKernElement.h
new file mode 100644
index 00000000..6649ab1a
--- /dev/null
+++ b/ksvg/dom/SVGVKernElement.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGVKernElement_H
+#define SVGVKernElement_H
+
+#include "SVGElement.h"
+
+namespace KSVG
+{
+
+class SVGVKernElementImpl;
+class SVGVKernElement : public SVGElement
+{
+public:
+ SVGVKernElement();
+ SVGVKernElement(const SVGVKernElement &other);
+ SVGVKernElement &operator=(const SVGVKernElement &other);
+ SVGVKernElement(SVGVKernElementImpl *other);
+ virtual ~SVGVKernElement();
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGVKernElementImpl *handle() const { return impl; }
+
+private:
+ SVGVKernElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGViewElement.cc b/ksvg/dom/SVGViewElement.cc
new file mode 100644
index 00000000..040d6966
--- /dev/null
+++ b/ksvg/dom/SVGViewElement.cc
@@ -0,0 +1,77 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGViewElement.h"
+#include "SVGViewElementImpl.h"
+#include "SVGStringList.h"
+
+using namespace KSVG;
+
+SVGViewElement::SVGViewElement() : SVGElement(), SVGExternalResourcesRequired(), SVGFitToViewBox(), SVGZoomAndPan()
+{
+ impl = 0;
+}
+
+SVGViewElement::SVGViewElement(const SVGViewElement &other) : SVGElement(other), SVGExternalResourcesRequired(other), SVGFitToViewBox(other), SVGZoomAndPan(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGViewElement &SVGViewElement::operator =(const SVGViewElement &other)
+{
+ SVGElement::operator=(other);
+ SVGExternalResourcesRequired::operator=(other);
+ SVGFitToViewBox::operator=(other);
+ SVGZoomAndPan::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGViewElement::SVGViewElement(SVGViewElementImpl *other) : SVGElement(other), SVGExternalResourcesRequired(other), SVGFitToViewBox(other), SVGZoomAndPan(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGViewElement::~SVGViewElement()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGStringList SVGViewElement::viewTarget() const
+{
+ if(!impl) return SVGStringList(0);
+ return SVGStringList(impl->viewTarget());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGViewElement.h b/ksvg/dom/SVGViewElement.h
new file mode 100644
index 00000000..fccedbc8
--- /dev/null
+++ b/ksvg/dom/SVGViewElement.h
@@ -0,0 +1,59 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGViewElement_H
+#define SVGViewElement_H
+
+#include "SVGElement.h"
+#include "SVGExternalResourcesRequired.h"
+#include "SVGFitToViewBox.h"
+#include "SVGZoomAndPan.h"
+
+namespace KSVG
+{
+
+class SVGStringList;
+class SVGViewElementImpl;
+class SVGViewElement : public SVGElement,
+ public SVGExternalResourcesRequired,
+ public SVGFitToViewBox,
+ public SVGZoomAndPan
+{
+public:
+ SVGViewElement();
+ SVGViewElement(const SVGViewElement &other);
+ SVGViewElement &operator=(const SVGViewElement &other);
+ SVGViewElement(SVGViewElementImpl *other);
+ virtual ~SVGViewElement();
+
+ SVGStringList viewTarget() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGViewElementImpl *handle() const { return impl; }
+
+private:
+ SVGViewElementImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGViewSpec.cc b/ksvg/dom/SVGViewSpec.cc
new file mode 100644
index 00000000..a01f7b86
--- /dev/null
+++ b/ksvg/dom/SVGViewSpec.cc
@@ -0,0 +1,107 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGViewSpec.h"
+#include "SVGViewSpecImpl.h"
+#include "SVGElement.h"
+#include "SVGTransformList.h"
+
+using namespace KSVG;
+
+SVGViewSpec::SVGViewSpec() : SVGZoomAndPan(), SVGFitToViewBox()
+{
+ impl = new SVGViewSpecImpl();
+ impl->ref();
+}
+
+SVGViewSpec::SVGViewSpec(const SVGViewSpec &other) : SVGZoomAndPan(other), SVGFitToViewBox(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGViewSpec &SVGViewSpec::operator =(const SVGViewSpec &other)
+{
+ SVGZoomAndPan::operator=(other);
+ SVGFitToViewBox::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGViewSpec::SVGViewSpec(SVGViewSpecImpl *other) : SVGZoomAndPan(other), SVGFitToViewBox(other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGViewSpec::~SVGViewSpec()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGTransformList SVGViewSpec::transform() const
+{
+ if(!impl) return SVGTransformList(0);
+ return SVGTransformList(impl->transform());
+}
+
+SVGElement SVGViewSpec::viewTarget() const
+{
+ if(!impl) return SVGElement(0);
+ return SVGElement(impl->viewTarget());
+}
+
+DOM::DOMString SVGViewSpec::viewBoxString() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->viewBoxString();
+}
+
+DOM::DOMString SVGViewSpec::preserveAspectRatioString() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->preserveAspectRatioString();
+}
+
+DOM::DOMString SVGViewSpec::transformString() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->transformString();
+}
+
+DOM::DOMString SVGViewSpec::viewTargetString() const
+{
+ if(!impl) return DOM::DOMString();
+ return impl->viewTargetString();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGViewSpec.h b/ksvg/dom/SVGViewSpec.h
new file mode 100644
index 00000000..c1c7ef8e
--- /dev/null
+++ b/ksvg/dom/SVGViewSpec.h
@@ -0,0 +1,63 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGViewSpec_H
+#define SVGViewSpec_H
+
+#include "SVGZoomAndPan.h"
+#include "SVGFitToViewBox.h"
+#include <dom/dom_string.h>
+
+namespace KSVG
+{
+
+class SVGTransformList;
+class SVGElement;
+class SVGViewSpecImpl;
+class SVGViewSpec : public SVGZoomAndPan,
+ public SVGFitToViewBox
+{
+public:
+ SVGViewSpec();
+ SVGViewSpec(const SVGViewSpec &other);
+ SVGViewSpec &operator=(const SVGViewSpec &other);
+ SVGViewSpec(SVGViewSpecImpl *other);
+ virtual ~SVGViewSpec();
+
+ SVGTransformList transform() const;
+ SVGElement viewTarget() const;
+
+ DOM::DOMString viewBoxString() const;
+ DOM::DOMString preserveAspectRatioString() const;
+ DOM::DOMString transformString() const;
+ DOM::DOMString viewTargetString() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGViewSpecImpl *handle() const { return impl; }
+
+private:
+ SVGViewSpecImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGWindow.cc b/ksvg/dom/SVGWindow.cc
new file mode 100644
index 00000000..9f0fedaf
--- /dev/null
+++ b/ksvg/dom/SVGWindow.cc
@@ -0,0 +1,175 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGWindow.h"
+#include "SVGWindowImpl.h"
+#include "SVGDocument.h"
+
+using namespace KSVG;
+
+SVGWindow::SVGWindow()
+{
+ impl = new SVGWindowImpl();
+ impl->ref();
+}
+
+SVGWindow::SVGWindow(const SVGWindow &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGWindow &SVGWindow::operator =(const SVGWindow &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGWindow::SVGWindow(SVGWindowImpl *other)
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGWindow::~SVGWindow()
+{
+ if(impl)
+ impl->deref();
+}
+
+/*StyleSheet SVGWindow::defaultStyleSheet() const
+{
+ if(!impl) return ; // FIXME
+ return impl->defaultStyleSheet();
+}*/
+
+SVGDocument SVGWindow::document() const
+{
+ if(!impl) return SVGDocument(0); // FIXME
+ return impl->document();
+}
+
+DOM::Event SVGWindow::evt() const
+{
+ if(!impl) return DOM::Event(); // FIXME
+ return impl->evt();
+}
+
+long SVGWindow::innerHeight() const
+{
+ if(!impl) return 0; // FIXME
+ return impl->innerHeight();
+}
+
+long SVGWindow::innerWidth() const
+{
+ if(!impl) return 0; // FIXME
+ return impl->innerWidth();
+}
+
+void SVGWindow::setSrc(const DOM::DOMString &src)
+{
+ if(impl)
+ impl->setSrc(src);
+}
+
+DOM::DOMString SVGWindow::src() const
+{
+ if(!impl) return DOM::DOMString(); // FIXME
+ return impl->src();
+}
+
+void SVGWindow::clearInterval(long interval)
+{
+ if(impl)
+ impl->clearInterval(interval);
+}
+
+void SVGWindow::clearTimeout(long timeout)
+{
+ if(impl)
+ impl->clearTimeout(timeout);
+}
+
+void SVGWindow::getURL(const DOM::DOMString &uri, const DOM::EventListener &callback)
+{
+ if(impl)
+ impl->getURL(uri, callback);
+}
+
+/*DocumentFragment SVGWindow::parseXML(const DOM::DOMString &source, const Document &document)
+{
+ if(!impl) return ; // FIXME
+ return impl->parseXML(source, document);
+}*/
+
+void SVGWindow::postURL(const DOM::DOMString &uri, const DOM::DOMString &data, const DOM::EventListener &callback, const DOM::DOMString &mimeType, const DOM::DOMString &contentEncoding)
+{
+ if(impl)
+ impl->postURL(uri, data, callback, mimeType, contentEncoding);
+}
+
+DOM::DOMString SVGWindow::printNode(const DOM::Node &node)
+{
+ if(!impl) return DOM::DOMString(); // FIXME
+ return impl->printNode(node);
+}
+
+long SVGWindow::setInterval(const DOM::DOMString &code, const long &delay)
+{
+ if(!impl) return 0; // FIXME
+ return impl->setInterval(code, delay);
+}
+
+long SVGWindow::setTimeout(const DOM::DOMString &code, const long &delay)
+{
+ if(!impl) return 0; // FIXME
+ return impl->setTimeout(code, delay);
+}
+
+void SVGWindow::alert(const DOM::DOMString &message)
+{
+ if(impl)
+ impl->alert(message);
+}
+
+bool SVGWindow::confirm(const DOM::DOMString &message)
+{
+ if(!impl) return false; // FIXME
+ return impl->confirm(message);
+}
+
+DOM::DOMString SVGWindow::prompt(const DOM::DOMString &message, const DOM::DOMString &_default)
+{
+ if(!impl) return DOM::DOMString(); // FIXME
+ return impl->prompt(message, _default);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGWindow.h b/ksvg/dom/SVGWindow.h
new file mode 100644
index 00000000..2389286f
--- /dev/null
+++ b/ksvg/dom/SVGWindow.h
@@ -0,0 +1,127 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGWindow_H
+#define SVGWindow_H
+
+#include <dom/dom_string.h>
+#include <dom/dom_node.h>
+#include <dom/dom2_events.h>
+
+namespace KSVG
+{
+
+class SVGDocument;
+class SVGWindowImpl;
+
+class SVGWindow
+{
+public:
+ SVGWindow();
+ SVGWindow(const SVGWindow &other);
+ SVGWindow &operator=(const SVGWindow &other);
+ SVGWindow(SVGWindowImpl *other);
+ virtual ~SVGWindow();
+
+ //StyleSheet defaultStyleSheet() const;
+ SVGDocument document() const;
+ DOM::Event evt() const;
+
+ /**
+ * @return Viewport height in pixels.
+ */
+ long innerHeight() const;
+
+ /**
+ * @return Viewport width in pixels.
+ */
+ long innerWidth() const;
+
+ void setSrc(const DOM::DOMString &src);
+
+ /**
+ * @return The URI of the current document.
+ */
+ DOM::DOMString src() const;
+
+ void clearInterval(long interval);
+ void clearTimeout(long timeout);
+
+ /**
+ * Get data from the given URL using the HTTP GET method. Notify the callback when done.
+ *
+ * @param uri The URI reference for the data to be loaded.
+ * @param callback The method to be invoked when the data is available.
+ */
+ void getURL(const DOM::DOMString &uri, const DOM::EventListener &callback);
+ //DOM::DocumentFragment parseXML(const DOM::DOMString &source, const DOM::Document &document);
+ void postURL(const DOM::DOMString &uri, const DOM::DOMString &data, const DOM::EventListener &callback, const DOM::DOMString &mimeType, const DOM::DOMString &contentEncoding);
+
+ /**
+ * Converts a Node into a DOMString. The string is an XML representation of the Node.
+ *
+ * @param node The Node to be converted.
+ * @return Converts a Node into a DOMString. The string is an XML representation of the Node.
+ */
+ DOM::DOMString printNode(const DOM::Node &node);
+ long setInterval(const DOM::DOMString &code, const long &delay);
+ long setTimeout(const DOM::DOMString &code, const long &delay);
+
+ /**
+ * Displays a modal synchronous message to the user if possible in the current user environment.
+ * Commonly, this message takes the form of a pop-up window with a single dispose button.
+ *
+ * @param message The message to be displayed.
+ */
+ void alert(const DOM::DOMString &message);
+
+ /**
+ * Displays a modal synchronous message to the user if possible in the current user environment.
+ * The user is able to accept or reject the message. Commonly, this message takes the form of
+ * a pop-up window with either a Yes/No or OK/Cancel button pair.
+ *
+ * @param message The message to be displayed.
+ * @return A boolean indicating the user's response. True for accept, False for reject.
+ */
+ bool confirm(const DOM::DOMString &message);
+
+ /**
+ * Displays a modal synchronous message to the user if possible in the current user environment.
+ * The user is able to enter a response to the message. Commonly, this message takes the form of
+ * a pop-up window with a single text entry field.
+ *
+ * @param message The message to be displayed.
+ * @param _default The default response to suggest to the user. This can be displayed in the text field and be modified by the user.
+ * @return A boolean indicating the user's response. True for accept, False for reject.
+ */
+ DOM::DOMString prompt(const DOM::DOMString &message, const DOM::DOMString &_default);
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGWindowImpl *handle() const { return impl; }
+
+private:
+ SVGWindowImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGZoomAndPan.cc b/ksvg/dom/SVGZoomAndPan.cc
new file mode 100644
index 00000000..a65284f1
--- /dev/null
+++ b/ksvg/dom/SVGZoomAndPan.cc
@@ -0,0 +1,70 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGZoomAndPan.h"
+#include "SVGZoomAndPanImpl.h"
+
+using namespace KSVG;
+
+// This class can't be constructed seperately.
+SVGZoomAndPan::SVGZoomAndPan()
+{
+ impl = 0;
+}
+
+SVGZoomAndPan::SVGZoomAndPan(const SVGZoomAndPan &other) : impl(0)
+{
+ (*this) = other;
+}
+
+SVGZoomAndPan &SVGZoomAndPan::operator=(const SVGZoomAndPan &other)
+{
+ if(impl == other.impl)
+ return *this;
+
+ impl = other.impl;
+
+ return *this;
+}
+
+SVGZoomAndPan::SVGZoomAndPan(SVGZoomAndPanImpl *other)
+{
+ impl = other;
+}
+
+SVGZoomAndPan::~SVGZoomAndPan()
+{
+ // We are not allowed to delete 'impl' as it's not refcounted.
+ // delete impl;
+}
+
+void SVGZoomAndPan::setZoomAndPan(unsigned short zoomAndPan)
+{
+ if(impl)
+ impl->setZoomAndPan(zoomAndPan);
+}
+
+unsigned short SVGZoomAndPan::zoomAndPan() const
+{
+ if(!impl) return SVG_ZOOMANDPAN_UNKNOWN;
+ return impl->zoomAndPan();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGZoomAndPan.h b/ksvg/dom/SVGZoomAndPan.h
new file mode 100644
index 00000000..0a1cdf19
--- /dev/null
+++ b/ksvg/dom/SVGZoomAndPan.h
@@ -0,0 +1,60 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGZoomAndPan_H
+#define SVGZoomAndPan_H
+
+namespace KSVG
+{
+
+enum ZoomAndPan
+{
+ SVG_ZOOMANDPAN_UNKNOWN = 0,
+ SVG_ZOOMANDPAN_DISABLE = 1,
+ SVG_ZOOMANDPAN_MAGNIFY = 2
+};
+
+class SVGZoomAndPanImpl;
+class SVGZoomAndPan
+{
+public:
+ SVGZoomAndPan(const SVGZoomAndPan &other);
+ SVGZoomAndPan &operator=(const SVGZoomAndPan &other);
+ SVGZoomAndPan(SVGZoomAndPanImpl *other);
+ virtual ~SVGZoomAndPan();
+
+ void setZoomAndPan(unsigned short zoomAndPan);
+ unsigned short zoomAndPan() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGZoomAndPanImpl *handle() const { return impl; }
+
+protected:
+ SVGZoomAndPan();
+
+private:
+ SVGZoomAndPanImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGZoomEvent.cc b/ksvg/dom/SVGZoomEvent.cc
new file mode 100644
index 00000000..bc73a438
--- /dev/null
+++ b/ksvg/dom/SVGZoomEvent.cc
@@ -0,0 +1,99 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGZoomEvent.h"
+#include "SVGZoomEventImpl.h"
+#include "SVGRect.h"
+#include "SVGPoint.h"
+
+using namespace KSVG;
+
+SVGZoomEvent::SVGZoomEvent() : DOM::UIEvent()
+{
+ impl = 0;
+}
+
+SVGZoomEvent::SVGZoomEvent(const SVGZoomEvent &other) : DOM::UIEvent(other), impl(0)
+{
+ (*this) = other;
+}
+
+SVGZoomEvent &SVGZoomEvent::operator =(const SVGZoomEvent &other)
+{
+ DOM::UIEvent::operator=(other);
+
+ if(impl == other.impl)
+ return *this;
+
+ if(impl)
+ impl->deref();
+
+ impl = other.impl;
+
+ if(impl)
+ impl->ref();
+
+ return *this;
+}
+
+SVGZoomEvent::SVGZoomEvent(SVGZoomEventImpl *other) : DOM::UIEvent()
+{
+ impl = other;
+ if(impl)
+ impl->ref();
+}
+
+SVGZoomEvent::~SVGZoomEvent()
+{
+ if(impl)
+ impl->deref();
+}
+
+SVGRect SVGZoomEvent::zoomRectScreen() const
+{
+ if(!impl) return SVGRect(0);
+ return SVGRect(impl->zoomRectScreen());
+}
+
+float SVGZoomEvent::previousScale() const
+{
+ if(!impl) return -1;
+ return impl->previousScale();
+}
+
+SVGPoint SVGZoomEvent::previousTranslate() const
+{
+ if(!impl) return SVGPoint(0);
+ return SVGPoint(impl->previousTranslate());
+}
+
+float SVGZoomEvent::newScale() const
+{
+ if(!impl) return -1;
+ return impl->newScale();
+}
+
+SVGPoint SVGZoomEvent::newTranslate() const
+{
+ if(!impl) return SVGPoint(0);
+ return SVGPoint(impl->newTranslate());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/dom/SVGZoomEvent.h b/ksvg/dom/SVGZoomEvent.h
new file mode 100644
index 00000000..f759e9bd
--- /dev/null
+++ b/ksvg/dom/SVGZoomEvent.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGZoomEvent_H
+#define SVGZoomEvent_H
+
+#include <dom/dom2_events.h>
+
+namespace KSVG
+{
+
+class SVGRect;
+class SVGPoint;
+class SVGZoomEventImpl;
+class SVGZoomEvent : public DOM::UIEvent
+{
+public:
+ SVGZoomEvent();
+ SVGZoomEvent(const SVGZoomEvent &other);
+ SVGZoomEvent &operator=(const SVGZoomEvent &other);
+ SVGZoomEvent(SVGZoomEventImpl *other);
+ virtual ~SVGZoomEvent();
+
+ SVGRect zoomRectScreen() const;
+ float previousScale() const;
+ SVGPoint previousTranslate() const;
+ float newScale() const;
+ SVGPoint newTranslate() const;
+
+ // Internal! - NOT PART OF THE SVG SPECIFICATION
+ SVGZoomEventImpl *handle() const { return impl; }
+
+private:
+ SVGZoomEventImpl *impl;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/ecma/Makefile.am b/ksvg/ecma/Makefile.am
new file mode 100644
index 00000000..b3eea2b5
--- /dev/null
+++ b/ksvg/ecma/Makefile.am
@@ -0,0 +1,7 @@
+INCLUDES = $(FREETYPE_CFLAGS) -I$(top_srcdir)/ksvg/dom -I$(top_srcdir)/ksvg/impl -I$(top_srcdir)/ksvg/core -I$(top_srcdir)/ksvg/data -I$(top_srcdir)/ksvg/impl/libs/libtext2path/src $(all_includes)
+METASOURCES = AUTO
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+
+noinst_LTLIBRARIES = libksvgecma.la
+
+libksvgecma_la_SOURCES = ksvg_scriptinterpreter.cpp ksvg_ecma.cpp ksvg_helper.cpp ksvg_ecmaeventlistener.cpp ksvg_window.cpp
diff --git a/ksvg/ecma/ksvg_bridge.h b/ksvg/ecma/ksvg_bridge.h
new file mode 100644
index 00000000..784dea15
--- /dev/null
+++ b/ksvg/ecma/ksvg_bridge.h
@@ -0,0 +1,103 @@
+/*
+ Copyright (C) 2002-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSVGBridge_H
+#define KSVGBridge_H
+
+#include <kdebug.h>
+
+#include <kjs/object.h>
+#include <kjs/lookup.h>
+#include <kjs/interpreter.h> // for ExecState
+
+namespace KJS
+{
+ class Value;
+ class UString;
+ class ExecState;
+}
+
+// Base class for all bridges
+// The T class must provide prototype(exec), get and hasProperty
+// and have a static s_classInfo object
+template<class T>
+class KSVGBridge : public KJS::ObjectImp
+{
+public:
+ KSVGBridge(KJS::ExecState *exec, T *impl) : KJS::ObjectImp(impl->prototype(exec)), m_impl(impl) { }
+
+ T *impl() const { return m_impl; }
+
+ virtual KJS::Value get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const
+ {
+ kdDebug(26004) << "KSVGBridge::get(), " << propertyName.qstring() << " Name: " << classInfo()->className << " Object: " << m_impl << endl;
+
+ // Look for standard properties (e.g. those in the hashtables)
+ KJS::Value val = m_impl->get(exec, propertyName, this);
+
+ if(val.type() != KJS::UndefinedType)
+ return val;
+
+ // Not found -> forward to ObjectImp.
+ val = KJS::ObjectImp::get(exec, propertyName);
+ if(val.type() == KJS::UndefinedType)
+ kdDebug(26004) << "WARNING: " << propertyName.qstring() << " not found in... Name: " << classInfo()->className << " Object: " << m_impl << " on line : " << exec->context().curStmtFirstLine() << endl;
+ return val;
+ }
+
+ virtual bool hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const
+ {
+ kdDebug(26004) << "KSVGBridge::hasProperty(), " << propertyName.qstring() << " Name: " << classInfo()->className << " Object: " << m_impl << endl;
+
+ if(m_impl->hasProperty(exec, propertyName))
+ return true;
+
+ return KJS::ObjectImp::hasProperty(exec, propertyName);
+ }
+
+ virtual const KJS::ClassInfo *classInfo() const { return &T::s_classInfo; }
+
+protected:
+ T *m_impl;
+};
+
+// Base class for readwrite bridges
+// T must also implement put (use KSVG_PUT in the header file)
+template<class T>
+class KSVGRWBridge : public KSVGBridge<T>
+{
+public:
+ KSVGRWBridge(KJS::ExecState *exec, T *impl) : KSVGBridge<T>(exec, impl) { }
+
+ virtual void put(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value &value, int attr)
+ {
+// if(!(attr & KJS::Internal))
+// kdDebug(26004) << "KSVGBridge::put(), " << propertyName.qstring() << " Name: " << classInfo()->className << " Object: " << m_impl << endl;
+
+ // Try to see if we know this property (and need to take special action)
+ if(this->m_impl->put(exec, propertyName, value, attr))
+ return;
+
+ // We don't -> set property in ObjectImp.
+ KJS::ObjectImp::put(exec, propertyName, value, attr);
+ }
+};
+
+#endif
diff --git a/ksvg/ecma/ksvg_cacheimpl.h b/ksvg/ecma/ksvg_cacheimpl.h
new file mode 100644
index 00000000..1140f1b4
--- /dev/null
+++ b/ksvg/ecma/ksvg_cacheimpl.h
@@ -0,0 +1,65 @@
+/*
+ Copyright (C) 2002-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSVGCacheImpl_H
+#define KSVGCacheImpl_H
+
+#include "ksvg_scriptinterpreter.h"
+
+// Lookup or create JS object around an existing "DOM Object"
+template<class DOMObj, class KJSDOMObj>
+inline KJS::Value cacheDOMObject(KJS::ExecState *exec, DOMObj *domObj)
+{
+ KJS::ObjectImp *ret;
+ if(!domObj)
+ return KJS::Null();
+
+ KSVGScriptInterpreter *interp = static_cast<KSVGScriptInterpreter *>(exec->interpreter());
+ if((ret = interp->getDOMObject(domObj)))
+ return KJS::Value(ret);
+ else
+ {
+ ret = new KJSDOMObj(exec, domObj);
+ interp->putDOMObject(domObj, ret);
+ return KJS::Value(ret);
+ }
+}
+
+// Lookup or create singleton Impl object, and return a unique bridge object for it.
+// (Very much like KJS::cacheGlobalObject, which is for a singleton ObjectImp)
+// This one is mostly used for Constructor objects.
+template <class ClassCtor>
+inline KJS::Object cacheGlobalBridge(KJS::ExecState *exec, const KJS::Identifier &propertyName)
+{
+ KJS::ValueImp *obj = static_cast<KJS::ObjectImp*>(exec->interpreter()->globalObject().imp())->getDirect(propertyName);
+ if(obj)
+ return KJS::Object::dynamicCast(KJS::Value(obj));
+ else
+ {
+ ClassCtor* ctor = new ClassCtor(exec); // create the ClassCtor instance
+ KJS::Object newObject(new KSVGBridge<ClassCtor>(exec, ctor)); // create the bridge around it
+ exec->interpreter()->globalObject().put(exec, propertyName, newObject, KJS::Internal);
+ return newObject;
+ }
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/ecma/ksvg_ecma.cpp b/ksvg/ecma/ksvg_ecma.cpp
new file mode 100644
index 00000000..a2aed6ce
--- /dev/null
+++ b/ksvg/ecma/ksvg_ecma.cpp
@@ -0,0 +1,336 @@
+/*
+ Copyright (C) 2002-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include <qvariant.h>
+
+#include <dom/dom2_events.h>
+
+#include "SVGEcma.h"
+
+#include "SVGDocumentImpl.h"
+
+#include "ksvg_ecma.h"
+#include "ksvg_window.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_ecmaeventlistener.h"
+
+#include "KSVGLoader.h"
+
+using namespace KSVG;
+using namespace KJS;
+
+class AsyncStatus : public ObjectImp
+{
+public:
+ AsyncStatus() : ObjectImp() { }
+
+ virtual bool implementsCall() const { return true; }
+ virtual Value call(ExecState *exec, Object &thisObj, const List &args);
+};
+
+Value AsyncStatus::call(ExecState *exec, Object &, const List &args)
+{
+ kdDebug(26004) << "[AsyncStatus] " << args[0].toString(exec).ascii() << endl;
+
+ if(args[0].toString(exec) == "success")
+ return Number(1);
+ else
+ return Undefined();
+}
+
+KSVGEcma::KSVGEcma(SVGDocumentImpl *doc) : m_doc(doc)
+{
+ m_init = false;
+ m_hasListeners = false;
+
+ m_window = 0;
+ m_interpreter = 0;
+
+ m_ecmaEventListeners.setAutoDelete(true);
+}
+
+KSVGEcma::~KSVGEcma()
+{
+ // We are 0 soon so event listeners may NOT call us
+ QPtrListIterator<KSVGEcmaEventListener> it(m_ecmaEventListeners);
+ for(; it.current(); ++it)
+ it.current()->forbidRemove();
+
+ if(m_interpreter)
+ delete m_interpreter;
+}
+
+bool KSVGEcma::initialized()
+{
+ return m_init;
+}
+
+void KSVGEcma::setup()
+{
+ if(m_init)
+ return;
+
+ m_init = true;
+
+ // Create handler for js calls
+ m_window = new KSVG::Window(m_doc);
+ Object globalObject(m_window);
+
+ // Create code interpreter
+ m_interpreter = new KSVGScriptInterpreter(globalObject, m_doc);
+
+ // Set object prototype for global object
+ m_window->setPrototype(m_interpreter->builtinObjectPrototype());
+
+ // Create bridge for document. Could be done on demand now, though
+ KSVGBridge<SVGDocumentImpl> *documentRequest = new KSVGBridge<SVGDocumentImpl>(m_interpreter->globalExec(), m_doc);
+ documentRequest->ref();
+
+ m_interpreter->putDOMObject(m_doc->handle(), documentRequest);
+}
+
+Completion KSVGEcma::evaluate(const UString &code, const Value &thisV)
+{
+#ifdef KJS_VERBOSE
+ kdDebug(6070) << "KSVGEcma::evaluate " << code.qstring() << endl;
+#endif
+
+ return m_interpreter->evaluate(code, thisV);
+}
+
+Object KSVGEcma::globalObject()
+{
+ return m_interpreter->globalObject();
+}
+
+ExecState *KSVGEcma::globalExec()
+{
+ return m_interpreter->globalExec();
+}
+
+SVGEventListener *KSVGEcma::createEventListener(DOM::DOMString type)
+{
+ QPtrListIterator<KSVGEcmaEventListener> it(m_ecmaEventListeners);
+
+ for(; it.current(); ++it)
+ {
+ if(it.current()->type() == type.string())
+ return static_cast<SVGEventListener *>(it.current());
+ }
+
+ setup();
+
+ Object constr = m_interpreter->builtinFunction();
+
+ List args;
+ args.append(String("event"));
+ args.append(String(type.string()));
+
+ Object obj = constr.construct(m_interpreter->globalExec(), args);
+
+ // Note that the KSVGEcmaEventListener constructor adds itself to the m_ecmaEventListeners list
+ KSVGEcmaEventListener *event = new KSVGEcmaEventListener(obj, type.string(), this);
+ event->ref();
+
+ // addEventListener() is called by KSVGEcmaListeners ctor, so it's
+ // safe to check to count of the eventListeners list (Niko)
+ if(m_ecmaEventListeners.count() > 0)
+ m_hasListeners = true;
+
+ return event;
+}
+
+QString KSVGEcma::valueOfEventListener(SVGEventListener *listener) const
+{
+ KSVGEcmaEventListener *event = static_cast<KSVGEcmaEventListener *>(listener);
+ if(!event)
+ return QString::null;
+
+ return event->type();
+}
+
+void KSVGEcma::addEventListener(KSVGEcmaEventListener *listener)
+{
+ m_ecmaEventListeners.append(listener);
+}
+
+void KSVGEcma::removeEventListener(KSVGEcmaEventListener *listener)
+{
+ m_ecmaEventListeners.take(m_ecmaEventListeners.find(listener));
+
+ if(m_ecmaEventListeners.count() == 0)
+ m_hasListeners = false;
+}
+
+bool KSVGEcma::hasEventListeners()
+{
+ return m_hasListeners;
+}
+
+void KSVGEcma::finishedWithEvent(SVGEventImpl *event)
+{
+ KSVGScriptInterpreter *interpreter = static_cast<KSVGScriptInterpreter *>(globalExec()->interpreter());
+ interpreter->removeDOMObject(event);
+}
+
+Value KSVGEcma::getUrl(ExecState *exec, ::KURL url)
+{
+ Object *status = new Object(new AsyncStatus());
+
+ // FIXME: Security issue, allows local testing of getURL(), REMOVE BEFORE RELEASE! (Niko)
+ QString svgDocument = KSVGLoader::getUrl(url, true);
+ if(svgDocument.length() > 0)
+ {
+ status->put(exec, Identifier("success"), Boolean(true));
+ status->put(exec, Identifier("content"), String(svgDocument));
+ }
+ else
+ {
+ status->put(exec, Identifier("success"), Boolean(false));
+ status->put(exec, Identifier("content"), String(""));
+ }
+
+ return Value(*status);
+}
+
+void KSVGEcma::postUrl(ExecState *exec, ::KURL url, const QString &data, const QString &mimeType, const QString &contentEncoding, Object &callBackFunction)
+{
+ Object *status = new Object(new AsyncStatus());
+ status->put(exec, Identifier("content"), String(""));
+ status->put(exec, Identifier("success"), Boolean(false));
+
+ QByteArray byteArray;
+ QDataStream ds(byteArray, IO_WriteOnly);
+ ds << data;
+
+ // Support gzip compression
+ if(contentEncoding == "gzip" || contentEncoding == "deflate")
+ byteArray = qCompress(byteArray);
+
+ KSVGLoader *loader = new KSVGLoader();
+ loader->postUrl(url, byteArray, mimeType, exec, callBackFunction, *status);
+ delete loader;
+}
+
+// Helpers
+Value KSVG::getDOMNode(ExecState *exec, DOM::Node n)
+{
+ ObjectImp *ret = 0;
+ if(n.isNull())
+ return Null();
+
+ KSVGScriptInterpreter *interpreter = static_cast<KSVGScriptInterpreter *>(exec->interpreter());
+
+ ObjectImp *request = interpreter->getDOMObject(n.handle());
+ if(request)
+ return Value(request);
+
+ SVGElementImpl *elem = 0;
+
+ switch(n.nodeType())
+ {
+ case DOM::Node::ELEMENT_NODE:
+ elem = interpreter->document()->getElementFromHandle(n.handle());
+ if(!elem)
+ {
+ // Lookup different document, if possible
+ SVGDocumentImpl *different = interpreter->document()->getDocumentFromHandle(n.ownerDocument().handle());
+
+ if(!different)
+ return Null();
+
+ elem = different->getElementFromHandle(n.handle());
+
+ if(!elem)
+ return Null();
+ }
+
+ // The generated bridge() function does not ref the ret itself
+ ret = elem->bridge(exec);
+ ret->ref();
+ break;
+ case DOM::Node::TEXT_NODE:
+ ret = new KSVGRWBridge<SVGDOMTextBridge>(exec, new SVGDOMTextBridge(n));
+ ret->ref();
+ break;
+ default:
+ ret = new KSVGBridge<SVGDOMNodeBridge>(exec, new SVGDOMNodeBridge(n));
+ ret->ref();
+ break;
+ }
+
+ interpreter->putDOMObject(n.handle(), ret);
+
+ return Value(ret);
+}
+
+Value KSVG::getDOMEvent(ExecState *exec, SVGEventImpl *e)
+{
+ return e->cache(exec);
+}
+
+Value KSVG::getString(DOM::DOMString s)
+{
+ if(s.isNull())
+ return Null();
+ else
+ return String(s);
+}
+
+DOM::Node KSVG::toNode(const Value &val)
+{
+ Object obj = Object::dynamicCast(val);
+ if(obj.isNull())
+ return DOM::Node();
+
+ SVGDOMNodeBridge *bridge = toNodeBridge(static_cast<ObjectImp *>(obj.imp()));
+
+ if(bridge)
+ return bridge->impl();
+
+ return DOM::Node();
+}
+
+QVariant KSVG::valueToVariant(ExecState *exec, const Value &val)
+{
+ QVariant res;
+
+ switch(val.type())
+ {
+ case BooleanType:
+ res = QVariant(val.toBoolean(exec), 0);
+ break;
+ case NumberType:
+ res = QVariant(val.toNumber(exec));
+ break;
+ case StringType:
+ res = QVariant(val.toString(exec).qstring());
+ break;
+ default:
+ // everything else will be 'invalid'
+ break;
+ }
+
+ return res;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/ecma/ksvg_ecma.h b/ksvg/ecma/ksvg_ecma.h
new file mode 100644
index 00000000..7c236454
--- /dev/null
+++ b/ksvg/ecma/ksvg_ecma.h
@@ -0,0 +1,114 @@
+/*
+ Copyright (C) 2002-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSVGEcma_H
+#define KSVGEcma_H
+
+#include <qptrlist.h>
+
+#include "ksvg_bridge.h"
+
+namespace DOM
+{
+ class Node;
+ class DOMString;
+}
+
+namespace KJS
+{
+ class Value;
+ class Object;
+ class UString;
+ class ExecState;
+ class Completion;
+}
+
+namespace KSVG
+{
+ class Window;
+ class SVGEventImpl;
+ class SVGDocumentImpl;
+ class SVGEventListener;
+ class SVGDOMNodeBridge;
+}
+
+class QVariant;
+
+class KSVGEcmaEventListener;
+class KSVGScriptInterpreter;
+
+typedef KSVGBridge<KSVG::SVGEventImpl> KSVGEcmaEvent;
+
+// Helpers
+namespace KSVG
+{
+ KJS::Value getDOMNode(KJS::ExecState *, DOM::Node);
+ KJS::Value getDOMEvent(KJS::ExecState *, KSVG::SVGEventImpl *);
+ KJS::Value getString(DOM::DOMString);
+
+ QVariant valueToVariant(KJS::ExecState *, const KJS::Value &);
+
+ DOM::Node toNode(const KJS::Value &);
+
+ // This one is part of generateddata.cpp
+ SVGDOMNodeBridge *toNodeBridge(const KJS::ObjectImp *);
+}
+
+class KSVGEcma
+{
+public:
+ KSVGEcma(KSVG::SVGDocumentImpl *doc);
+ ~KSVGEcma();
+
+ void setup();
+ bool initialized();
+
+ KJS::Completion evaluate(const KJS::UString &code, const KJS::Value &thisV);
+
+ KJS::Object globalObject();
+ KJS::ExecState *globalExec();
+
+ KSVGScriptInterpreter *interpreter() { return m_interpreter; }
+
+ KSVG::SVGEventListener *createEventListener(DOM::DOMString type);
+ QString valueOfEventListener(KSVG::SVGEventListener *listener) const;
+ void addEventListener(KSVGEcmaEventListener *listener);
+ void removeEventListener(KSVGEcmaEventListener *listener);
+ bool hasEventListeners();
+
+ void finishedWithEvent(KSVG::SVGEventImpl *event);
+
+ KJS::Value getUrl(KJS::ExecState *exec, ::KURL url);
+ void postUrl(KJS::ExecState *exec, ::KURL url, const QString &data, const QString &mimeType, const QString &contentEncoding, KJS::Object &callBackFunction);
+
+private:
+ bool m_init, m_hasListeners;
+
+ KSVG::SVGDocumentImpl *m_doc;
+
+ KSVG::Window *m_window;
+ KSVGScriptInterpreter *m_interpreter;
+ QPtrList<KSVGEcmaEventListener> m_ecmaEventListeners;
+
+};
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/ecma/ksvg_ecmaeventlistener.cpp b/ksvg/ecma/ksvg_ecmaeventlistener.cpp
new file mode 100644
index 00000000..4b59f924
--- /dev/null
+++ b/ksvg/ecma/ksvg_ecmaeventlistener.cpp
@@ -0,0 +1,99 @@
+/*
+ Copyright (C) 2002-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include <qvariant.h>
+
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+
+#include "ksvg_ecma.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_ecmaeventlistener.h"
+
+using namespace KSVG;
+using namespace KJS;
+
+KSVGEcmaEventListener::KSVGEcmaEventListener(KJS::Object _listener, QString _type, KSVGEcma *_ecma) : SVGEventListener()
+{
+ m_listener = _listener;
+ m_remove = true;
+ m_type = _type;
+ m_ecma = _ecma;
+
+ m_ecma->addEventListener(this);
+}
+
+KSVGEcmaEventListener::~KSVGEcmaEventListener()
+{
+ if(m_remove)
+ m_ecma->removeEventListener(this);
+}
+
+void KSVGEcmaEventListener::forbidRemove()
+{
+ m_remove = false;
+}
+
+void KSVGEcmaEventListener::handleEvent(SVGEventImpl *evt)
+{
+ if(m_ecma && m_listener.implementsCall())
+ {
+ KSVGScriptInterpreter *interpreter = m_ecma->interpreter();
+ ExecState *exec = m_ecma->globalExec();
+
+ // Append 'evt'
+ List args;
+ args.append(getDOMEvent(exec, evt));
+
+ // Set current event
+ interpreter->setCurrentEvent(evt);
+
+ // Call it!
+ Object thisObj = Object::dynamicCast(getDOMNode(exec, *evt->currentTarget()));
+ Value retval = m_listener.call(exec, thisObj, args);
+
+ interpreter->setCurrentEvent(0);
+
+ if(exec->hadException())
+ {
+ exec->clearException();
+
+ // onerror support
+ SVGSVGElementImpl *rootElement = static_cast<KSVGScriptInterpreter *>(exec->interpreter())->document()->rootElement();
+ if(rootElement)
+ rootElement->dispatchEvent(SVGEvent::ERROR_EVENT, true, false);
+ }
+ else
+ {
+ QVariant ret = valueToVariant(exec, retval);
+ if(ret.type() == QVariant::Bool && ret.toBool() == false)
+ evt->preventDefault();
+ }
+ }
+}
+
+DOM::DOMString KSVGEcmaEventListener::eventListenerType()
+{
+ return "KSVGEcmaEventListener - " + m_type;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/ecma/ksvg_ecmaeventlistener.h b/ksvg/ecma/ksvg_ecmaeventlistener.h
new file mode 100644
index 00000000..16ebe3bc
--- /dev/null
+++ b/ksvg/ecma/ksvg_ecmaeventlistener.h
@@ -0,0 +1,54 @@
+/*
+ Copyright (C) 2002-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSVGEcmaEventListener_H
+#define KSVGEcmaEventListener_H
+
+#include "SVGEventImpl.h"
+
+namespace KJS
+{
+ class Object;
+}
+
+class KSVGEcmaEventListener : public KSVG::SVGEventListener
+{
+public:
+ KSVGEcmaEventListener(KJS::Object _listener, QString _type, KSVGEcma *_ecma);
+ virtual ~KSVGEcmaEventListener();
+
+ virtual void handleEvent(KSVG::SVGEventImpl *evt);
+ virtual DOM::DOMString eventListenerType();
+
+ QString type() { return m_type; }
+
+ void forbidRemove();
+
+private:
+ KSVGEcma *m_ecma;
+ QString m_type;
+ bool m_remove;
+
+ KJS::Object m_listener;
+};
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/ecma/ksvg_helper.cpp b/ksvg/ecma/ksvg_helper.cpp
new file mode 100644
index 00000000..597f9a06
--- /dev/null
+++ b/ksvg/ecma/ksvg_helper.cpp
@@ -0,0 +1,68 @@
+/*
+ Copyright (C) 2002-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kjs/ustring.h>
+#include <kjs/identifier.h>
+
+#include <dom/dom_string.h>
+
+KJS::UString::UString(const DOM::DOMString &d)
+{
+ if(d.isNull())
+ {
+ attach(&Rep::null);
+ return;
+ }
+
+ unsigned int len = d.length();
+ KJS::UChar *dat = new UChar[len];
+ memcpy(dat, d.unicode(), len * sizeof(UChar));
+ rep = KJS::UString::Rep::create(dat, len);
+}
+
+KJS::UString::UString(const QString &d)
+{
+ unsigned int len = d.length();
+ KJS::UChar *dat = new UChar[len];
+ memcpy(dat, d.unicode(), len * sizeof(UChar));
+ rep = KJS::UString::Rep::create(dat, len);
+}
+
+QString KJS::UString::qstring() const
+{
+ return QString(reinterpret_cast<QChar *>(const_cast<KJS::UChar *>(data())), size());
+}
+
+DOM::DOMString KJS::UString::string() const
+{
+ return DOM::DOMString(reinterpret_cast<QChar *>(const_cast<KJS::UChar *>(data())), size());
+}
+
+DOM::DOMString KJS::Identifier::string() const
+{
+ return DOM::DOMString((QChar*) data(), size());
+}
+
+QString KJS::Identifier::qstring() const
+{
+ return QString((QChar*) data(), size());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/ecma/ksvg_lookup.h b/ksvg/ecma/ksvg_lookup.h
new file mode 100644
index 00000000..11c41462
--- /dev/null
+++ b/ksvg/ecma/ksvg_lookup.h
@@ -0,0 +1,318 @@
+/*
+ Copyright (C) 2002-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSVG_LOOKUP_H
+#define KSVG_LOOKUP_H
+
+#include <kjs/object.h>
+#include <kjs/lookup.h>
+#include <kjs/interpreter.h> // for ExecState
+
+#include "ksvg_bridge.h"
+#include "ksvg_scriptinterpreter.h"
+
+#define KSVG_GET_COMMON \
+public: \
+ \
+ /* The standard hasProperty call, auto-generated. Looks in hashtable, forwards to parents. */ \
+ bool hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \
+ \
+ /* get() method, called by KSVGBridge::get */ \
+ KJS::Value get(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::ObjectImp* bridge) const; \
+ \
+ /* Called by lookupGet(). Auto-generated. Forwards to the parent which has the given property. */ \
+ KJS::Value getInParents(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::ObjectImp* bridge) const; \
+ \
+ KJS::Object prototype(KJS::ExecState *exec) const;\
+ \
+ static const KJS::ClassInfo s_classInfo; \
+ \
+ static const struct KJS::HashTable s_hashTable; \
+ \
+ int m_attrFlags;
+
+// For classes with properties to read, and a hashtable.
+#define KSVG_GET \
+ KSVG_GET_COMMON \
+ KJS::Value cache(KJS::ExecState *exec) const;
+
+// Same thing, for base classes (kalyptus helps finding them)
+// The difference is that cache() is virtual
+#define KSVG_BASECLASS_GET \
+ KSVG_GET_COMMON \
+ virtual KJS::Value cache(KJS::ExecState *exec) const;
+
+// For classes without properties, but with a parent class to forward to
+#define KSVG_FORWARDGET \
+public: \
+ \
+ bool hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \
+ \
+ /* will have the code for getInParents */ \
+ KJS::Value get(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::ObjectImp* bridge) const; \
+ \
+ KJS::Object prototype(KJS::ExecState *exec) const;\
+ \
+ static const KJS::ClassInfo s_classInfo; \
+ \
+ KJS::Value cache(KJS::ExecState *exec) const;
+
+// For read-write classes only, i.e. those which support put()
+#define KSVG_PUT \
+ \
+ /* put() method, called by KSVGBridge::put */ \
+ bool put(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value &value, int attr); \
+ \
+ /* Called by lookupPut. Auto-generated. Looks in hashtable, forwards to parents. */ \
+ bool putInParents(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value &value, int attr);
+
+// For classes which inherit a read-write class, but have no readwrite property themselves
+#define KSVG_FORWARDPUT \
+ \
+ /* put() method, called by KSVGBridge::put */ \
+ bool put(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value &value, int attr);
+
+// For classes which need to be accessable with getElementById -> elements
+#define KSVG_NO_TAG_BRIDGE \
+public: \
+ KJS::ObjectImp *bridge(KJS::ExecState *) const { return 0; }
+
+#define KSVG_BRIDGE \
+public: \
+ KJS::ObjectImp *bridge(KJS::ExecState *) const; \
+ virtual DOM::DOMString tagName() const { return s_tagName; } \
+ static const DOM::DOMString s_tagName;
+
+// Fast setting of default values, if the token is known
+// Note: this is actually misnamed it should be KSVG_SET_DEFAULT_ATTRIBUTE
+#define KSVG_SET_ALT_ATTRIBUTE(Token, Name) putValueProperty(ownerDoc()->ecmaEngine()->globalExec(), Token, String(Name), Internal);
+
+// Check if attribute has not been parsed, if the token is known
+#define KSVG_TOKEN_NOT_PARSED_ELEMENT(Token, Element) (~Element->m_attrFlags & (1 << Token))
+#define KSVG_TOKEN_NOT_PARSED(Token) KSVG_TOKEN_NOT_PARSED_ELEMENT(Token, this)
+
+// Checks if the interpreter is in attribute "getting" mode
+#define KSVG_CHECK_ATTRIBUTE bool attributeMode = static_cast<KSVGScriptInterpreter *>(exec->interpreter())->attributeGetMode();
+
+// Sets the class specific flags to a ZERO value
+#define KSVG_EMPTY_FLAGS m_attrFlags = 0;
+
+// to be used in generatedata.cpp
+// GET p1=exec, p2=propertyName, p3=bridge
+// PUT p1=exec, p2=propertyName, p3=value, p4=attr
+#define GET_METHOD_ARGS KJS::ExecState *p1, const KJS::Identifier &p2, const KJS::ObjectImp *p3
+#define PUT_METHOD_ARGS KJS::ExecState *p1, const KJS::Identifier &p2, const KJS::Value &p3, int p4
+
+namespace KSVG
+{
+ /**
+ * Helper method for property lookups
+ *
+ * This method does it all (looking in the hashtable, checking for function
+ * overrides, creating the function or retrieving from cache, calling
+ * getValueProperty in case of a non-function property, forwarding to parent[s] if
+ * unknown property).
+ *
+ * Template arguments:
+ * @param FuncImp the class which implements this object's functions
+ * @param ThisImp the class of "this". It must implement the getValueProperty(exec,token) method,
+ * for non-function properties, and the getInParents() method (auto-generated).
+ *
+ * Method arguments:
+ * @param exec execution state, as usual
+ * @param propertyName the property we're looking for
+ * @param table the static hashtable for this class
+ * @param thisObj "this"
+ */
+ template<class FuncImp, class ThisImp>
+ inline KJS::Value lookupGet(KJS::ExecState *exec,
+ const KJS::Identifier &propertyName,
+ const KJS::HashTable *table,
+ const ThisImp *thisObj, // the 'impl' object
+ const KJS::ObjectImp *bridge)
+ {
+ const KJS::HashEntry *entry = KJS::Lookup::findEntry(table, propertyName);
+
+ if(!entry) // not found, forward to parents
+ return thisObj->getInParents(exec, propertyName, bridge);
+
+ if(entry->attr & KJS::Function)
+ return KJS::lookupOrCreateFunction<FuncImp>(exec, propertyName,
+ const_cast<KJS::ObjectImp *>(bridge),
+ entry->value, entry->params, entry->attr);
+
+ return thisObj->getValueProperty(exec, entry->value);
+ }
+
+ /**
+ * Simplified version of lookupGet in case there are no functions, only "values".
+ * Using this instead of lookupGet removes the need for a FuncImp class.
+ */
+ template <class ThisImp>
+ inline KJS::Value lookupGetValue(KJS::ExecState *exec,
+ const KJS::Identifier &propertyName,
+ const KJS::HashTable *table,
+ const ThisImp *thisObj, // the 'impl' object
+ const KJS::ObjectImp *bridge)
+ {
+ const KJS::HashEntry *entry = KJS::Lookup::findEntry(table, propertyName);
+
+ if(!entry) // not found, forward to parents
+ return thisObj->getInParents(exec, propertyName, bridge);
+
+ if(entry->attr & KJS::Function)
+ kdError(26004) << "Function bit set! Shouldn't happen in lookupGetValue! propertyName was " << propertyName.qstring() << endl;
+
+ return thisObj->getValueProperty(exec, entry->value);
+ }
+
+ /**
+ * This one is for "put".
+ * Lookup hash entry for property to be set, and set the value.
+ * The "this" class must implement putValueProperty.
+ * If it returns false, put() will return false, and KSVGRequest will set a dynamic property in ObjectImp
+ */
+ template <class ThisImp>
+ inline bool lookupPut(KJS::ExecState *exec,
+ const KJS::Identifier &propertyName,
+ const KJS::Value &value,
+ int attr,
+ const KJS::HashTable *table,
+ ThisImp *thisObj)
+ {
+ const KJS::HashEntry *entry = KJS::Lookup::findEntry(table, propertyName);
+
+ if(!entry) // not found, forward to parents
+ return thisObj->putInParents(exec, propertyName, value, attr);
+ else if(entry->attr & KJS::Function) // Function: put as override property
+ return false;
+ else if(entry->attr & KJS::ReadOnly && !(attr & KJS::Internal)) // readonly! Can't put!
+ {
+#ifdef KJS_VERBOSE
+ kdWarning(26004) <<" Attempt to change value of readonly property '" << propertyName.qstring() << "'" << endl;
+#endif
+ return true; // "we did it" -> don't put override property
+ }
+ else
+ {
+ if(static_cast<KSVGScriptInterpreter *>(exec->interpreter())->attributeSetMode())
+ thisObj->m_attrFlags |= (1 << entry->value);
+
+ thisObj->putValueProperty(exec, entry->value, value, attr);
+ return true;
+ }
+ }
+}
+
+// Same as kjs' DEFINE_PROTOTYPE, but with a pointer to the hashtable too, and no ClassName here
+// The ClassProto ctor(exec) must be public, so we can use KJS::cacheGlobalObject... (Niko)
+#define KSVG_DEFINE_PROTOTYPE(ClassProto) \
+ namespace KSVG { \
+ class ClassProto : public KJS::ObjectImp { \
+ public: \
+ static KJS::Object self(KJS::ExecState *exec); \
+ ClassProto( KJS::ExecState *exec ) \
+ : KJS::ObjectImp( exec->interpreter()->builtinObjectPrototype() ) {} \
+ virtual const KJS::ClassInfo *classInfo() const { return &info; } \
+ static const KJS::ClassInfo info; \
+ KJS::Value get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \
+ bool hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const; \
+ \
+ static const struct KJS::HashTable s_hashTable; \
+ }; \
+ }
+
+// same as IMPLEMENT_PROTOTYPE but in the KSVG namespace, and with ClassName here
+// so that KSVG_DEFINE_PROTOTYPE can be put in a header file ('info' defined here)
+#define KSVG_IMPLEMENT_PROTOTYPE(ClassName,ClassProto,ClassFunc) \
+ KJS::Value KSVG::ClassProto::get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \
+ { \
+ return lookupGetFunction<ClassFunc,KJS::ObjectImp>(exec, propertyName, &s_hashTable, this ); \
+ } \
+ bool KSVG::ClassProto::hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \
+ { /*stupid but we need this to have a common macro for the declaration*/ \
+ return KJS::ObjectImp::hasProperty(exec, propertyName); \
+ } \
+ KJS::Object KSVG::ClassProto::self(KJS::ExecState *exec) \
+ { \
+ return KJS::cacheGlobalObject<ClassProto>( exec, "[[" ClassName ".prototype]]" ); \
+ } \
+ const KJS::ClassInfo ClassProto::info = { ClassName, 0, &s_hashTable, 0 }; \
+
+// same as KSVG_IMPLEMENT_PROTOTYPE but with a parent class to forward calls to
+// Not used within KSVG up to now - each class does a self proto lookup in generateddata.cpp
+#define KSVG_IMPLEMENT_PROTOTYPE_WITH_PARENT(ClassName,ClassProto,ClassFunc,ParentProto) \
+ KJS::Value KSVG::ClassProto::get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \
+ { \
+ KJS::Value val = lookupGetFunction<ClassFunc,KJS::ObjectImp>(exec, propertyName, &s_hashTable, this ); \
+ if ( val.type() != UndefinedType ) return val; \
+ /* Not found -> forward request to "parent" prototype */ \
+ return ParentProto::self(exec).get( exec, propertyName ); \
+ } \
+ bool KSVG::ClassProto::hasProperty(KJS::ExecState *exec, const KJS::Identifier &propertyName) const \
+ { \
+ if (KJS::ObjectImp::hasProperty(exec, propertyName)) \
+ return true; \
+ return ParentProto::self(exec).hasProperty(exec, propertyName); \
+ } \
+ KJS::Object KSVG::ClassProto::self(KJS::ExecState *exec) \
+ { \
+ return KJS::cacheGlobalObject<ClassProto>( exec, "[[" ClassName ".prototype]]" ); \
+ } \
+ const KJS::ClassInfo ClassProto::info = { ClassName, 0, &s_hashTable, 0 }; \
+
+#define KSVG_IMPLEMENT_PROTOFUNC(ClassFunc,Class) \
+ namespace KSVG { \
+ class ClassFunc : public KJS::ObjectImp { \
+ public: \
+ ClassFunc(KJS::ExecState *exec, int i, int len) \
+ : KJS::ObjectImp( /*proto? */ ), id(i) { \
+ KJS::Value protect(this); \
+ put(exec,"length",KJS::Number(len),KJS::DontDelete|KJS::ReadOnly|KJS::DontEnum); \
+ } \
+ /** Used by call() to check the type of thisObj. Generated code */ \
+ Class * cast(const KJS::ObjectImp* bridge) const; \
+ \
+ virtual bool implementsCall() const { return true; } \
+ /** You need to implement that one */ \
+ virtual KJS::Value call(KJS::ExecState *exec, KJS::Object &thisObj, const KJS::List &args); \
+ private: \
+ int id; \
+ }; \
+ }
+
+// To be used when casting the type of an argument
+#define KSVG_CHECK(ClassName, theObj) \
+ ClassName* obj = cast(static_cast<KJS::ObjectImp*>(theObj.imp())); \
+ if (!obj) { \
+ kdDebug(26004) << k_funcinfo << " Wrong object type: expected " << ClassName::s_classInfo.className << " got " << thisObj.classInfo()->className << endl; \
+ Object err = Error::create(exec,TypeError); \
+ exec->setException(err); \
+ return err; \
+ }
+
+// To be used in all call() implementations!
+// Can't use if (!thisObj.inherits(&ClassName::s_classInfo) since we don't
+// use the (single-parent) inheritance of ClassInfo...
+#define KSVG_CHECK_THIS(ClassName) KSVG_CHECK(ClassName, thisObj)
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/ecma/ksvg_scriptinterpreter.cpp b/ksvg/ecma/ksvg_scriptinterpreter.cpp
new file mode 100644
index 00000000..b5b9e6dd
--- /dev/null
+++ b/ksvg/ecma/ksvg_scriptinterpreter.cpp
@@ -0,0 +1,92 @@
+/*
+ Copyright (C) 2002-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGEventImpl.h"
+#include "SVGDocumentImpl.h"
+#include "ksvg_scriptinterpreter.h"
+
+using namespace KSVG;
+using namespace KJS;
+
+KSVGScriptInterpreter::KSVGScriptInterpreter(const Object &global, SVGDocumentImpl *doc) : Interpreter(global), m_document(doc)
+{
+ m_evt = 0;
+
+ m_attributeGetMode = false;
+ m_attributeSetMode = false;
+}
+
+KSVGScriptInterpreter::~KSVGScriptInterpreter()
+{
+ if(m_evt)
+ m_evt->deref();
+}
+
+SVGDocumentImpl *KSVGScriptInterpreter::document()
+{
+ return m_document;
+}
+
+KSVG::SVGEventImpl *KSVGScriptInterpreter::currentEvent()
+{
+ return m_evt;
+}
+
+void KSVGScriptInterpreter::setCurrentEvent(KSVG::SVGEventImpl *evt)
+{
+ m_evt = evt;
+}
+
+KJS::ObjectImp *KSVGScriptInterpreter::getDOMObject(void *objectHandle) const
+{
+ return m_domObjects[objectHandle];
+}
+
+void KSVGScriptInterpreter::putDOMObject(void *objectHandle, KJS::ObjectImp *obj)
+{
+ m_domObjects.insert(objectHandle, obj);
+}
+
+void KSVGScriptInterpreter::removeDOMObject(void *objectHandle)
+{
+ m_domObjects.take(objectHandle);
+}
+
+bool KSVGScriptInterpreter::attributeGetMode()
+{
+ return m_attributeGetMode;
+}
+
+bool KSVGScriptInterpreter::attributeSetMode()
+{
+ return m_attributeSetMode;
+}
+
+void KSVGScriptInterpreter::setAttributeGetMode(bool temp)
+{
+ m_attributeGetMode = temp;
+}
+
+void KSVGScriptInterpreter::setAttributeSetMode(bool temp)
+{
+ m_attributeSetMode = temp;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/ecma/ksvg_scriptinterpreter.h b/ksvg/ecma/ksvg_scriptinterpreter.h
new file mode 100644
index 00000000..ed7c6af8
--- /dev/null
+++ b/ksvg/ecma/ksvg_scriptinterpreter.h
@@ -0,0 +1,71 @@
+/*
+ Copyright (C) 2002-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSVGScriptInterpreter_H
+#define KSVGScriptInterpreter_H
+
+#include <qptrdict.h>
+
+namespace KJS
+{
+ class Value;
+ class Object;
+ class Interpreter;
+}
+
+namespace KSVG
+{
+ class SVGEventImpl;
+ class SVGDocumentImpl;
+}
+
+class KSVGScriptInterpreter : public KJS::Interpreter
+{
+public:
+ KSVGScriptInterpreter(const KJS::Object &global, KSVG::SVGDocumentImpl *doc);
+ virtual ~KSVGScriptInterpreter();
+
+ KSVG::SVGDocumentImpl *document();
+
+ KJS::ObjectImp *getDOMObject(void *objectHandle) const;
+ void putDOMObject(void *objectHandle, KJS::ObjectImp *obj);
+ void removeDOMObject(void *objectHandle);
+
+ KSVG::SVGEventImpl *currentEvent();
+ void setCurrentEvent(KSVG::SVGEventImpl *evt);
+
+ bool attributeGetMode();
+ void setAttributeGetMode(bool temp);
+
+ bool attributeSetMode();
+ void setAttributeSetMode(bool temp);
+
+private:
+ KSVG::SVGDocumentImpl *m_document;
+ KSVG::SVGEventImpl *m_evt;
+
+ bool m_attributeGetMode, m_attributeSetMode;
+
+ QPtrDict<KJS::ObjectImp> m_domObjects;
+};
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/ecma/ksvg_window.cpp b/ksvg/ecma/ksvg_window.cpp
new file mode 100644
index 00000000..d4c04de3
--- /dev/null
+++ b/ksvg/ecma/ksvg_window.cpp
@@ -0,0 +1,578 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 David Faure <faure@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2, as published by the Free Software Foundation.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "ksvg_window.moc"
+#include "ksvg_lookup.h"
+#include "ksvg_ecma.h"
+#include "ksvg_bridge.h"
+#include "ksvg_scriptinterpreter.h"
+#include <SVGEventImpl.h>
+#include <SVGDocumentImpl.h>
+#include <KSVGCanvas.h>
+#include <SVGWindowImpl.h>
+// for js constants
+#include <SVGTransformImpl.h>
+#include <SVGLengthImpl.h>
+#include <SVGAngleImpl.h>
+#include <SVGColorImpl.h>
+#include <SVGPreserveAspectRatioImpl.h>
+#include <SVGTextContentElementImpl.h>
+#include <SVGPathSegImpl.h>
+#include <SVGGradientElementImpl.h>
+#include <SVGMarkerElementImpl.h>
+#include <SVGTextPathElementImpl.h>
+#include <SVGPaintImpl.h>
+#include <SVGZoomAndPanImpl.h>
+
+#include <kparts/part.h>
+#include <assert.h>
+#include <kdebug.h>
+#include <qstylesheet.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include <kinputdialog.h>
+
+using namespace KSVG;
+
+#include "ksvg_window.lut.h"
+
+// Spec on http://www.protocol7.com/svg-wiki/ow.asp?AdobeSVGViewerWindow
+
+/*
+@namespace KSVG
+@begin KSVG::Window::s_hashTable 34
+ closed KSVG::Window::_Closed DontDelete|ReadOnly
+ window KSVG::Window::_Window DontDelete|ReadOnly
+ evt KSVG::Window::_Evt DontDelete|ReadOnly
+ document KSVG::Window::_Document DontDelete|ReadOnly
+ svgDocument KSVG::Window::_Document DontDelete|ReadOnly
+ innerWidth KSVG::Window::_InnerWidth DontDelete|ReadOnly
+ innerHeight KSVG::Window::_InnerHeight DontDelete|ReadOnly
+ setTimeout KSVG::Window::_SetTimeout DontDelete|Function 2
+ clearTimeout KSVG::Window::_ClearTimeout DontDelete|Function 1
+ setInterval KSVG::Window::_SetInterval DontDelete|Function 2
+ clearInterval KSVG::Window::_ClearInterval DontDelete|Function 1
+ navigator KSVG::Window::_Navigator DontDelete|ReadOnly
+ printNode KSVG::Window::_PrintNode DontDelete|Function 1
+
+# todo navigator, status/defaultstatus, like in KJS::Window (khtml)
+# todo close
+# todo instancename
+# todo setsrc, getsrc, reload, focus, blur, browsereval, findinstancebyname
+
+# "Constructors" (usually repositories for constants)
+ SVGTransform KSVG::Window::_SVGTransform DontDelete|ReadOnly
+ SVGLength KSVG::Window::_SVGLength DontDelete|ReadOnly
+ SVGAngle KSVG::Window::_SVGAngle DontDelete|ReadOnly
+ SVGPreserveAspectRatio KSVG::Window::_SVGPreserveAspectRatio DontDelete|ReadOnly
+ SVGPathSeg KSVG::Window::_SVGPathSeg DontDelete|ReadOnly
+ SVGGradientElement KSVG::Window::_SVGGradientElement DontDelete|ReadOnly
+ SVGMarkerElement KSVG::Window::_SVGMarkerElement DontDelete|ReadOnly
+ SVGTextPathElement KSVG::Window::_SVGTextPathElement DontDelete|ReadOnly
+ SVGPaint KSVG::Window::_SVGPaint DontDelete|ReadOnly
+ SVGTextContentElement KSVG::Window::_SVGTextContentElement DontDelete|ReadOnly
+ SVGZoomAndPan KSVG::Window::_SVGZoomAndPan DontDelete|ReadOnly
+ SVGColor KSVG::Window::_SVGColor DontDelete|ReadOnly
+
+# Functions
+ alert KSVG::Window::_Alert DontDelete|Function 1
+ prompt KSVG::Window::_Prompt DontDelete|Function 2
+ confirm KSVG::Window::_Confirm DontDelete|Function 1
+ debug KSVG::Window::_Debug DontDelete|Function 1
+ success KSVG::Window::_Success DontDelete|Function 1
+ getSVGViewerVersion KSVG::Window::_GetSVGViewerVersion DontDelete|Function 0
+ getURL KSVG::Window::_GetURL DontDelete|Function 2
+ postURL KSVG::Window::_PostURL DontDelete|Function 5
+ parseXML KSVG::Window::_ParseXML DontDelete|Function 1
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOFUNC(WindowFunc, Window)
+
+const ClassInfo KSVG::Window::s_classInfo = { "Window", 0, &s_hashTable, 0 };
+
+KSVG::Window::Window(KSVG::SVGDocumentImpl *p) : ObjectImp(), m_doc(p)
+{
+ winq = new WindowQObject(this);
+}
+
+KSVG::Window::~Window()
+{
+ delete winq;
+}
+
+KSVG::Window *KSVG::Window::retrieveActive(ExecState *exec)
+{
+ ValueImp *imp = exec->interpreter()->globalObject().imp();
+ assert(imp);
+ return static_cast<KSVG::Window*>(imp);
+}
+
+bool KSVG::Window::hasProperty(ExecState *, const Identifier &) const
+{
+ return true; // See KJS::KSVG::Window::hasProperty
+}
+
+Value KSVG::Window::get(ExecState *exec, const Identifier &p) const
+{
+ kdDebug(26004) << "KSVG::Window (" << this << ")::get " << p.qstring() << endl;
+
+ if(p == "closed")
+ return Boolean(m_doc.isNull());
+
+ // we don't want any operations on a closed window
+ if(m_doc.isNull())
+ return Undefined();
+
+ // Look for overrides first
+ Value val = ObjectImp::get(exec, p);
+ if(!val.isA(UndefinedType))
+ return isSafeScript(exec) ? val : Undefined();
+
+ // Not the right way in the long run. Should use retrieve(m_doc)...
+ KSVGScriptInterpreter* interpreter = static_cast<KSVGScriptInterpreter *>(exec->interpreter());
+
+ const HashEntry *entry = Lookup::findEntry(&KSVG::Window::s_hashTable, p);
+ if(entry)
+ {
+ switch(entry->value)
+ {
+ case _Document:
+ // special case, KSVGEcma::setup created it, so we don't need to do it
+ return Value(interpreter->getDOMObject(m_doc->handle()));
+ case _Window:
+ return Value(const_cast<Window *>(this));
+ case _Evt:
+ {
+ KSVG::SVGEventImpl *evt = interpreter->currentEvent();
+ if(evt)
+ return getDOMEvent(exec, evt);
+ else
+ return Undefined();
+ }
+ case _InnerWidth:
+ return Number(m_doc->canvas()->width());
+ case _InnerHeight:
+ return Number(m_doc->canvas()->height());
+ case _SetTimeout:
+ case _ClearTimeout:
+ case _SetInterval:
+ case _ClearInterval:
+ case _PrintNode:
+ {
+ if(isSafeScript(exec))
+ return lookupOrCreateFunction<WindowFunc>(exec, p, this, entry->value, entry->params, entry->attr);
+ else
+ return Undefined();
+ }
+ case _Alert:
+ case _Confirm:
+ case _Debug:
+ case _Success:
+ case _GetSVGViewerVersion:
+ case _GetURL:
+ case _PostURL:
+ case _ParseXML:
+ case _Prompt:
+ return lookupOrCreateFunction<WindowFunc>(exec, p, this, entry->value, entry->params, entry->attr);
+ case _SVGTransform:
+ return getSVGTransformImplConstructor(exec);
+ case _SVGLength:
+ return getSVGLengthImplConstructor(exec);
+ case _SVGAngle:
+ return getSVGAngleImplConstructor(exec);
+ case _SVGColor:
+ return getSVGColorImplConstructor(exec);
+ case _SVGPreserveAspectRatio:
+ return getSVGPreserveAspectRatioImplConstructor(exec);
+ case _SVGPathSeg:
+ return getSVGPathSegImplConstructor(exec);
+ case _SVGGradientElement:
+ return getSVGGradientElementImplConstructor(exec);
+ case _SVGMarkerElement:
+ return getSVGMarkerElementImplConstructor(exec);
+ case _SVGTextPathElement:
+ return getSVGTextPathElementImplConstructor(exec);
+ case _SVGPaint:
+ return getSVGPaintImplConstructor(exec);
+ case _SVGTextContentElement:
+ return getSVGTextContentElementImplConstructor(exec);
+ case _SVGZoomAndPan:
+ return getSVGZoomAndPanImplConstructor(exec);
+ }
+ }
+
+ // This isn't necessarily a bug. Some code uses if(!window.blah) window.blah=1
+ // But it can also mean something isn't loaded or implemented...
+ kdDebug(26004) << "KSVG::Window::get property not found: " << p.qstring() << endl;
+
+ return Undefined();
+}
+
+void KSVG::Window::put(ExecState* exec, const Identifier &propertyName, const Value &value, int attr)
+{
+ // Called by an internal KJS call (e.g. InterpreterImp's constructor) ?
+ // If yes, save time and jump directly to ObjectImp.
+ if((attr != None && attr != DontDelete)
+ // Same thing if we have a local override (e.g. "var location")
+ || (ObjectImp::getDirect(propertyName) && isSafeScript(exec)))
+ {
+ ObjectImp::put( exec, propertyName, value, attr );
+ return;
+ }
+
+ const HashEntry *entry = Lookup::findEntry(&KSVG::Window::s_hashTable, propertyName);
+ if(entry)
+ {
+#ifdef KJS_VERBOSE
+ kdDebug(26004) << "Window(" << this << ")::put " << propertyName.qstring() << endl;
+#endif
+ //switch(entry->value)
+ //{
+ // ...
+ //}
+ }
+
+ if(isSafeScript(exec))
+ ObjectImp::put(exec, propertyName, value, attr);
+}
+
+bool KSVG::Window::isSafeScript(ExecState *exec) const
+{
+ if(m_doc.isNull()) // part deleted ? can't grant access
+ {
+ kdDebug(26004) << "KSVG::Window::isSafeScript: accessing deleted part !" << endl;
+ return false;
+ }
+
+ KSVG::SVGDocumentImpl *activePart = static_cast<KSVGScriptInterpreter *>(exec->interpreter())->document();
+
+ if(!activePart)
+ {
+ kdDebug(26004) << "KSVG::Window::isSafeScript: current interpreter's part is 0L!" << endl;
+ return false;
+ }
+
+ if(activePart == m_doc) // Not calling from another frame, no problem.
+ return true;
+
+ return false;
+}
+
+void KSVG::Window::clear(ExecState *exec)
+{
+ kdDebug(26004) << "KSVG::Window::clear " << this << endl;
+ delete winq;
+ winq = new WindowQObject(this);;
+
+ // Get rid of everything, those user vars could hold references to DOM nodes
+ deleteAllProperties(exec);
+
+ // Really delete those properties, so that the DOM nodes get deref'ed
+ // KJS::Collector::collect();
+
+ // Now recreate a working global object for the next URL that will use us
+ Interpreter *interpreter = exec->interpreter();
+ interpreter->initGlobalObject();
+}
+
+Value WindowFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ if(!thisObj.inherits(&KSVG::Window::s_classInfo))
+ {
+ Object err = Error::create(exec, TypeError);
+ exec->setException(err);
+ return err;
+ }
+
+ Window *window = static_cast<Window *>(thisObj.imp());
+ Value v = args[0];
+ UString s = v.toString(exec);
+ QString str = s.qstring();
+
+ switch(id)
+ {
+ case KSVG::Window::_Alert:
+ SVGWindowImpl::alert(DOM::DOMString(str), "Javascript");
+ return Undefined();
+ case KSVG::Window::_Confirm:
+ return Boolean(SVGWindowImpl::confirm(DOM::DOMString(str), "Javascript"));
+ case KSVG::Window::_Debug:
+ kdDebug(26004) << "[Debug] " << str << endl;
+ return Undefined();
+ case KSVG::Window::_Success:
+ //if(args[0].toString(exec) == "success") // ? Did you really mean that ?
+ return Number(1);
+ //return Undefined();
+ case KSVG::Window::_GetSVGViewerVersion:
+ return String("0.1"); // I cant really find a central place for the version nr, so... (Rob)
+ case KSVG::Window::_ClearTimeout:
+ case KSVG::Window::_ClearInterval:
+ (const_cast<Window *>(window))->clearTimeout(v.toInt32(exec));
+ return Undefined();
+ case KSVG::Window::_PrintNode:
+ return String(const_cast<Window *>(window)->doc()->window()->printNode(toNode(args[0])));
+ case KSVG::Window::_GetURL:
+ {
+ KURL url((const_cast<Window *>(window))->doc()->baseUrl(), args[0].toString(exec).qstring());
+ Value asyncStatus = (const_cast<Window *>(window))->doc()->ecmaEngine()->getUrl(exec, url);
+ Object callBackFunction = Object::dynamicCast(args[1]);
+ List callBackArgs;
+
+ callBackArgs.append(asyncStatus);
+ callBackFunction.call(exec, callBackFunction, callBackArgs);
+
+ return Undefined();
+ }
+ case KSVG::Window::_PostURL:
+ {
+ KURL url((const_cast<Window *>(window))->doc()->baseUrl(), args[0].toString(exec).qstring());
+ QString data = args[1].toString(exec).qstring();
+ QString mimeType = args[3].toString(exec).qstring();
+ QString contentEncoding = args[4].toString(exec).qstring();
+ Object callBackFunction = Object::dynamicCast(args[2]);
+
+ (const_cast<Window *>(window))->doc()->ecmaEngine()->postUrl(exec, url, data, mimeType, contentEncoding, callBackFunction);
+
+ return Undefined();
+ };
+ case KSVG::Window::_ParseXML:
+ {
+ SVGDocumentImpl *doc = new SVGDocumentImpl();
+ doc->ref();
+ doc->attach(0);
+
+ // So we can find it later...
+ (const_cast<Window *>(window))->doc()->addToDocumentDict(doc->handle(), doc);
+
+ // Also add the current doc to the new doc!
+ SVGDocumentImpl *curDoc = (const_cast<Window *>(window))->doc();
+ doc->addToDocumentDict(curDoc->handle(), curDoc);
+
+ QXmlInputSource *svgFragment = new QXmlInputSource();
+ svgFragment->setData(args[0].toString(exec).qstring());
+
+ doc->parseSVG(svgFragment, true);
+
+ DOM::DocumentFragment fragment = doc->createDocumentFragment();
+ DOM::Node node = doc->firstChild();
+ for(; !node.isNull(); node = node.nextSibling())
+ fragment.appendChild(node);
+
+
+// fragment = *doc; // Should copy the nodes into here...
+
+ return (new SVGDOMDocumentFragmentBridge(fragment))->cache(exec);
+ }
+ case KSVG::Window::_Prompt:
+ {
+ // mop: from khtml. do we need that?
+ // part->xmlDocImpl()->updateRendering();
+ bool ok;
+ QString str2;
+ if (args.size() >= 2)
+ str2 = KInputDialog::getText(i18n("Prompt"),
+ QStyleSheet::convertFromPlainText(str),
+ args[1].toString(exec).qstring(), &ok);
+ else
+ str2 = KInputDialog::getText(i18n("Prompt"),
+ QStyleSheet::convertFromPlainText(str),
+ QString::null, &ok);
+ if ( ok )
+ return String(str2);
+ else
+ return Null();
+ }
+ case KSVG::Window::_SetInterval:
+ if(args.size() >= 2 && v.isA(StringType))
+ {
+ int i = args[1].toInt32(exec);
+ int r = (const_cast<Window *>(window))->installTimeout(s, i, false);
+ return Number(r);
+ }
+ else if(args.size() >= 2 && !Object::dynamicCast(v).isNull() && Object::dynamicCast(v).implementsCall())
+ {
+ Value func = args[0];
+ int i = args[1].toInt32(exec);
+ int r = (const_cast<Window *>(window))->installTimeout(s, i, false);
+ return Number(r);
+ }
+ else
+ return Undefined();
+ case KSVG::Window::_SetTimeout:
+ if (args.size() == 2 && v.isA(StringType))
+ {
+ int i = args[1].toInt32(exec);
+ int r = (const_cast<Window *>(window))->installTimeout(s, i, true /*single shot*/);
+ return Number(r);
+ }
+ else if(args.size() >= 2 && v.isA(ObjectType) && Object::dynamicCast(v).implementsCall())
+ {
+ Value func = args[0];
+ int i = args[1].toInt32(exec);
+ int r = (const_cast<Window *>(window))->installTimeout(s, i, false);
+ return Number(r);
+ }
+ else
+ return Undefined();
+ }
+
+ return Undefined();
+}
+
+int KSVG::Window::installTimeout(const UString &handler, int t, bool singleShot)
+{
+ return winq->installTimeout(handler, t, singleShot);
+}
+
+void KSVG::Window::clearTimeout(int timerId)
+{
+ winq->clearTimeout(timerId);
+}
+
+////////////////////// ScheduledAction ////////////////////////
+
+ScheduledAction::ScheduledAction(Object _func, List _args, bool _singleShot)
+{
+ func = _func;
+ args = _args;
+ isFunction = true;
+ singleShot = _singleShot;
+}
+
+ScheduledAction::ScheduledAction(QString _code, bool _singleShot)
+{
+ code = _code;
+ isFunction = false;
+ singleShot = _singleShot;
+}
+
+ScheduledAction::~ScheduledAction()
+{
+}
+
+void ScheduledAction::execute(Window *window)
+{
+ Q_ASSERT(window->doc());
+
+ KSVGScriptInterpreter *interpreter = window->doc()->ecmaEngine()->interpreter();
+ if(isFunction)
+ {
+ if(func.implementsCall())
+ {
+ ExecState *exec = interpreter->globalExec();
+ Q_ASSERT(window == interpreter->globalObject().imp());
+ Object obj(window);
+ func.call(exec, obj, args); // note that call() creates its own execution state for the func call
+ }
+ }
+ else
+ {
+ interpreter->evaluate(code);
+ window->doc()->rerender();
+ }
+}
+
+////////////////////// WindowQObject ////////////////////////
+
+WindowQObject::WindowQObject(Window *w) : parent(w)
+{
+}
+
+WindowQObject::~WindowQObject()
+{
+ parentDestroyed(); // reuse same code
+}
+
+void WindowQObject::parentDestroyed()
+{
+ killTimers();
+
+ QMapIterator<int, ScheduledAction *> it;
+ for(it = scheduledActions.begin(); it != scheduledActions.end(); ++it)
+ {
+ ScheduledAction *action = *it;
+ delete action;
+ }
+
+ scheduledActions.clear();
+}
+
+int WindowQObject::installTimeout(const UString &handler, int t, bool singleShot)
+{
+ int id = startTimer(t);
+ ScheduledAction *action = new ScheduledAction(handler.qstring(), singleShot);
+ scheduledActions.insert(id, action);
+ return id;
+}
+
+int WindowQObject::installTimeout(const Value &func, List args, int t, bool singleShot)
+{
+ Object objFunc = Object::dynamicCast(func);
+ int id = startTimer(t);
+ scheduledActions.insert(id, new ScheduledAction(objFunc, args, singleShot));
+ return id;
+}
+
+void WindowQObject::clearTimeout(int timerId, bool delAction)
+{
+ killTimer(timerId);
+
+ if(delAction)
+ {
+ QMapIterator<int, ScheduledAction *> it = scheduledActions.find(timerId);
+ if(it != scheduledActions.end())
+ {
+ ScheduledAction *action = *it;
+ scheduledActions.remove(it);
+ delete action;
+ }
+ }
+}
+
+void WindowQObject::timerEvent(QTimerEvent *e)
+{
+ QMapIterator<int, ScheduledAction *> it = scheduledActions.find(e->timerId());
+ if(it != scheduledActions.end())
+ {
+ ScheduledAction *action = *it;
+ bool singleShot = action->singleShot;
+
+ // remove single shots installed by setTimeout()
+ if(singleShot)
+ {
+ clearTimeout(e->timerId(), false);
+ scheduledActions.remove(it);
+ }
+
+ if(parent->doc())
+ action->execute(parent);
+
+ // It is important to test singleShot and not action->singleShot here - the
+ // action could have been deleted already if not single shot and if the
+ // JS code called by execute() calls clearTimeout().
+ if(singleShot)
+ delete action;
+ }
+ else
+ kdWarning(6070) << "WindowQObject::timerEvent this=" << this << " timer " << e->timerId() << " not found (" << scheduledActions.count() << " actions in map)" << endl;
+}
+
+void WindowQObject::timeoutClose()
+{
+}
diff --git a/ksvg/ecma/ksvg_window.h b/ksvg/ecma/ksvg_window.h
new file mode 100644
index 00000000..28c9699e
--- /dev/null
+++ b/ksvg/ecma/ksvg_window.h
@@ -0,0 +1,122 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 David Faure <faure@kde.org>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2, as published by the Free Software Foundation.
+
+ 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSVG_WINDOW_H
+#define KSVG_WINDOW_H
+
+#include <kjs/object.h>
+#include <qguardedptr.h>
+
+namespace KSVG {
+
+class SVGDocumentImpl;
+class WindowQObject;
+
+// This is currently a fork of khtml's Window object, simplified.
+// However in the long run it could become a base class for it.
+// Author: David Faure <faure@kde.org>
+class Window : public KJS::ObjectImp {
+ friend class WindowFunc;
+ friend class WindowQObject;
+ friend class ScheduledAction;
+public:
+ Window(KSVG::SVGDocumentImpl *p);
+ ~Window();
+
+ virtual KJS::Value get(KJS::ExecState *exec, const KJS::Identifier &propertyName) const;
+ virtual void put(KJS::ExecState *exec, const KJS::Identifier &propertyName, const KJS::Value &value, int attr = KJS::None);
+ virtual bool hasProperty(KJS::ExecState * /*exec*/, const KJS::Identifier &/*p*/) const;
+
+ /**
+ * Returns and registers a window object. In case there's already a Window
+ * for the specified part p this will be returned in order to have unique
+ * bindings.
+ */
+ //static KJS::Value retrieve(KSVG::SVGDocumentImpl *p);
+ /**
+ * Returns the Window object for a given part
+ */
+ //static Window *retrieveWindow(KSVG::SVGDocumentImpl *p);
+ /**
+ * returns a pointer to the Window object this javascript interpreting instance
+ * was called from.
+ */
+ static Window *retrieveActive(KJS::ExecState *exec);
+
+ QGuardedPtr<KSVG::SVGDocumentImpl> doc() const { return m_doc; }
+
+ int installTimeout(const KJS::UString &handler, int t, bool singleShot);
+ void clearTimeout(int timerId);
+
+ bool isSafeScript(KJS::ExecState *exec) const;
+ void clear( KJS::ExecState *exec );
+
+ enum {
+ // Properties
+ _Closed, _Window, _Document, _Evt, _InnerWidth, _InnerHeight,
+ _SVGTransform, _SVGLength, _SVGAngle, _SVGColor, _SVGPreserveAspectRatio, _SVGGradientElement,
+ _SVGPathSeg, _SVGTextContentElement, _SVGPaint, _SVGZoomAndPan, _SVGMarkerElement, _SVGTextPathElement,
+ _SetInterval, _ClearInterval, _SetTimeout, _ClearTimeout, _Navigator, _PrintNode,
+ // Functions
+ _Alert, _Confirm, _Debug, _Success, _GetSVGViewerVersion, _GetURL, _PostURL, _ParseXML, _Prompt
+ };
+
+ virtual const KJS::ClassInfo* classInfo() const { return &s_classInfo; }
+ static const KJS::ClassInfo s_classInfo;
+ static const struct KJS::HashTable s_hashTable;
+
+private:
+ WindowQObject *winq;
+ QGuardedPtr<KSVG::SVGDocumentImpl> m_doc;
+};
+
+class ScheduledAction {
+public:
+ ScheduledAction(KJS::Object _func, KJS::List _args, bool _singleShot);
+ ScheduledAction(QString _code, bool _singleShot);
+ ~ScheduledAction();
+ void execute(Window *window);
+ KJS::Object func;
+ KJS::List args;
+ QString code;
+ bool isFunction;
+ bool singleShot;
+};
+
+class WindowQObject : public QObject {
+ Q_OBJECT
+public:
+ WindowQObject(Window *w);
+ ~WindowQObject();
+ int installTimeout(const KJS::UString &handler, int t, bool singleShot);
+ int installTimeout(const KJS::Value &func, KJS::List args, int t, bool singleShot);
+ void clearTimeout(int timerId, bool delAction = true);
+public slots:
+ void timeoutClose();
+protected slots:
+ void parentDestroyed();
+protected:
+ void timerEvent(QTimerEvent *e);
+private:
+ Window *parent;
+ //KHTMLPart *part; // not guarded, may be dangling
+ QMap<int, ScheduledAction*> scheduledActions;
+};
+
+}
+#endif // KSVG_WINDOW_H
diff --git a/ksvg/impl/LRUCache.h b/ksvg/impl/LRUCache.h
new file mode 100644
index 00000000..879f1856
--- /dev/null
+++ b/ksvg/impl/LRUCache.h
@@ -0,0 +1,169 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef LRUCACHE_H
+#define LRUCACHE_H
+
+#include <qvaluelist.h>
+
+namespace KSVG
+{
+
+// A value-based LRU cache with a maximum total cost constraint, but with the exception that the
+// most recently added item is kept in the cache even if its cost exceeds the maximum total cost.
+template<class keyType, class valueType>
+class MinOneLRUCache
+{
+public:
+ MinOneLRUCache(int maxTotalCost = 0) : m_maxTotalCost(maxTotalCost), m_totalCost(0) {}
+ virtual ~MinOneLRUCache() {}
+
+ void insert(const keyType& key, const valueType& value, int cost);
+ bool find(const keyType& key, valueType& result);
+
+ void setMaxTotalCost(int maxTotalCost);
+ int maxTotalCost() const { return m_maxTotalCost; }
+ int totalCost() const { return m_totalCost; }
+
+ void clear();
+
+protected:
+ class CacheItem
+ {
+ public:
+ CacheItem() : m_cost(0) {}
+ CacheItem(const keyType& key, const valueType& value, int cost) : m_key(key), m_value(value), m_cost(cost) {}
+
+ const keyType& key() const { return m_key; }
+ const valueType& value() const { return m_value; }
+ int cost() const { return m_cost; }
+
+ private:
+ keyType m_key;
+ valueType m_value;
+ int m_cost;
+ };
+
+ typedef QValueList<CacheItem> CacheItemList;
+
+ typename CacheItemList::iterator find(const keyType& key);
+ void enforceCostConstraint();
+
+ CacheItemList m_items;
+ int m_maxTotalCost;
+ int m_totalCost;
+};
+
+template<class keyType, class valueType>
+void MinOneLRUCache<keyType, valueType>::insert(const keyType& key, const valueType& value, int cost)
+{
+ typename CacheItemList::iterator it = find(key);
+
+ if(it != m_items.end())
+ {
+ // Replace the existing item.
+ m_totalCost -= (*it).cost();
+ m_items.erase(it);
+ }
+
+ // We always hold the most recently added item in the cache, even if it exceeds
+ // the maximum total cost.
+ m_items.push_front(CacheItem(key, value, cost));
+ m_totalCost += cost;
+ enforceCostConstraint();
+}
+
+template<class keyType, class valueType>
+bool MinOneLRUCache<keyType, valueType>::find(const keyType& key, valueType& result)
+{
+ bool foundKey = false;
+ typename CacheItemList::iterator it = find(key);
+
+ if(it != m_items.end())
+ {
+ CacheItem item = *it;
+ result = item.value();
+
+ if(it != m_items.begin())
+ {
+ // This is now the most recently used item.
+ m_items.erase(it);
+ m_items.push_front(item);
+ }
+
+ foundKey = true;
+ }
+
+ return foundKey;
+}
+
+template<class keyType, class valueType>
+typename MinOneLRUCache<keyType, valueType>::CacheItemList::iterator MinOneLRUCache<keyType, valueType>::find(const keyType& key)
+{
+ typename CacheItemList::iterator it;
+
+ for(it = m_items.begin(); it != m_items.end(); it++)
+ {
+ if((*it).key() == key)
+ break;
+ }
+
+ return it;
+}
+
+template<class keyType, class valueType>
+void MinOneLRUCache<keyType, valueType>::enforceCostConstraint()
+{
+ if(m_totalCost > m_maxTotalCost && m_items.size() > 1)
+ {
+ typename CacheItemList::iterator it = m_items.begin();
+ m_totalCost = (*it).cost();
+ ++it;
+
+ while(it != m_items.end() && m_totalCost + (*it).cost() <= m_maxTotalCost)
+ {
+ m_totalCost += (*it).cost();
+ ++it;
+ }
+
+ // Remove the remainder
+ while(it != m_items.end())
+ it = m_items.erase(it);
+ }
+}
+
+template<class keyType, class valueType>
+void MinOneLRUCache<keyType, valueType>::setMaxTotalCost(int maxTotalCost)
+{
+ m_maxTotalCost = maxTotalCost;
+ enforceCostConstraint();
+}
+
+template<class keyType, class valueType>
+void MinOneLRUCache<keyType, valueType>::clear()
+{
+ m_items.clear();
+ m_totalCost = 0;
+}
+
+}
+
+#endif
+
diff --git a/ksvg/impl/Makefile.am b/ksvg/impl/Makefile.am
new file mode 100644
index 00000000..24e40d67
--- /dev/null
+++ b/ksvg/impl/Makefile.am
@@ -0,0 +1,116 @@
+SUBDIRS = libs
+noinst_LTLIBRARIES = libksvgdomimpl.la
+
+KDE_OPTIONS = nofinal
+
+# The makefile has the following structure:
+# datatypes
+# animated datatypes
+# lists
+# animated lists
+# base classes
+# document structure
+# styling
+# paths
+# basic shapes
+# text
+# painting
+# color
+# gradients & patterns
+# clipping & masking
+# filters
+# interactivity
+# linking
+# scripting
+# animations
+# font & glyph stuff
+# metadata
+# extensibility
+
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+libksvgdomimpl_la_SOURCES = \
+SVGLengthImpl.cc SVGNumberImpl.cc SVGPointImpl.cc SVGTransformImpl.cc \
+SVGMatrixImpl.cc SVGRectImpl.cc SVGAngleImpl.cc \
+\
+SVGAnimatedLengthImpl.cc SVGAnimatedNumberImpl.cc SVGAnimatedIntegerImpl.cc \
+SVGAnimatedBooleanImpl.cc SVGAnimatedEnumerationImpl.cc SVGAnimatedPreserveAspectRatioImpl.cc \
+SVGAnimatedRectImpl.cc SVGAnimatedAngleImpl.cc SVGAnimatedPathDataImpl.cc SVGAnimatedStringImpl.cc \
+\
+SVGLengthListImpl.cc SVGNumberListImpl.cc SVGPointListImpl.cc SVGTransformListImpl.cc \
+SVGStringListImpl.cc SVGPathSegListImpl.cc SVGElementInstanceListImpl.cc \
+\
+SVGAnimatedLengthListImpl.cc SVGAnimatedNumberListImpl.cc \
+SVGAnimatedPointsImpl.cc SVGAnimatedTransformListImpl.cc \
+\
+SVGShapeImpl.cc SVGContainerImpl.cc SVGBBoxTarget.cc SVGHelperImpl.cc \
+SVGStylableImpl.cc SVGTransformableImpl.cc SVGTestsImpl.cc SVGLangSpaceImpl.cc \
+SVGExternalResourcesRequiredImpl.cc SVGLocatableImpl.cc SVGFitToViewBoxImpl.cc \
+SVGPreserveAspectRatioImpl.cc SVGZoomAndPanImpl.cc SVGViewSpecImpl.cc \
+\
+SVGElementImpl.cc SVGElementInstanceImpl.cc \
+SVGDocumentImpl.cc SVGSVGElementImpl.cc SVGWindowImpl.cc \
+SVGDefsElementImpl.cc SVGUseElementImpl.cc \
+SVGDescElementImpl.cc SVGTitleElementImpl.cc \
+SVGGElementImpl.cc SVGSwitchElementImpl.cc \
+SVGSymbolElementImpl.cc SVGImageElementImpl.cc \
+SVGURIReferenceImpl.cc \
+\
+SVGStyleElementImpl.cc SVGCSSRuleImpl.cc \
+\
+SVGPathElementImpl.cc SVGPathSegImpl.cc SVGPathSegClosePathImpl.cc SVGPathSegArcImpl.cc \
+SVGPathSegMovetoImpl.cc SVGPathSegCurvetoQuadraticImpl.cc SVGPathSegCurvetoQuadraticSmoothImpl.cc \
+SVGPathSegCurvetoCubicImpl.cc SVGPathSegCurvetoCubicSmoothImpl.cc SVGPathSegLinetoImpl.cc \
+SVGPathSegLinetoHorizontalImpl.cc SVGPathSegLinetoVerticalImpl.cc \
+\
+SVGRectElementImpl.cc SVGCircleElementImpl.cc SVGEllipseElementImpl.cc SVGLineElementImpl.cc \
+SVGPolyElementImpl.cc SVGPolylineElementImpl.cc SVGPolygonElementImpl.cc \
+\
+SVGTextElementImpl.cc SVGTSpanElementImpl.cc SVGTRefElementImpl.cc \
+SVGTextPositioningElementImpl.cc SVGTextContentElementImpl.cc SVGTextPathElementImpl.cc \
+\
+SVGPaintImpl.cc SVGMarkerElementImpl.cc \
+\
+SVGColorImpl.cc SVGICCColorImpl.cc SVGColorProfileElementImpl.cc SVGColorProfileRuleImpl.cc \
+\
+SVGPaintServerImpl.cc SVGGradientElementImpl.cc SVGStopElementImpl.cc \
+SVGLinearGradientElementImpl.cc SVGRadialGradientElementImpl.cc SVGPatternElementImpl.cc \
+\
+SVGClipPathElementImpl.cc SVGMaskElementImpl.cc \
+\
+SVGFilterElementImpl.cc SVGFilterPrimitiveStandardAttributesImpl.cc \
+SVGFEBlendElementImpl.cc SVGFEColorMatrixElementImpl.cc \
+SVGFEComponentTransferElementImpl.cc SVGComponentTransferFunctionElementImpl.cc \
+SVGFEFuncAElementImpl.cc SVGFEFuncBElementImpl.cc SVGFEFuncGElementImpl.cc \
+SVGFEFuncRElementImpl.cc SVGFECompositeElementImpl.cc SVGFEConvolveMatrixElementImpl.cc \
+SVGFEFloodElementImpl.cc SVGFEGaussianBlurElementImpl.cc SVGFEDiffuseLightingElementImpl.cc \
+SVGFEDistantLightElementImpl.cc SVGFEPointLightElementImpl.cc SVGFESpotLightElementImpl.cc \
+SVGFEDisplacementMapElementImpl.cc SVGFEMergeElementImpl.cc SVGFEMergeNodeElementImpl.cc \
+SVGFEImageElementImpl.cc SVGFEMorphologyElementImpl.cc SVGFEOffsetElementImpl.cc \
+SVGFESpecularLightingElementImpl.cc SVGFETileElementImpl.cc SVGFETurbulenceElementImpl.cc \
+\
+SVGCursorElementImpl.cc \
+\
+SVGAElementImpl.cc SVGViewElementImpl.cc \
+\
+SVGScriptElementImpl.cc SVGEventImpl.cc SVGZoomEventImpl.cc \
+SVGEcma.cc generateddata.cpp \
+\
+SVGAnimationElementImpl.cc SVGAnimateElementImpl.cc SVGSetElementImpl.cc \
+SVGAnimateMotionElementImpl.cc SVGAnimateColorElementImpl.cc \
+SVGAnimateTransformElementImpl.cc SVGMPathElementImpl.cc SVGTimeScheduler.cc \
+\
+SVGFontElementImpl.cc SVGAltGlyphElementImpl.cc SVGAltGlyphDefElementImpl.cc \
+SVGGlyphRefElementImpl.cc SVGGlyphElementImpl.cc SVGMissingGlyphElementImpl.cc \
+SVGFontFaceElementImpl.cc SVGFontFaceFormatElementImpl.cc SVGFontFaceNameElementImpl.cc \
+SVGFontFaceSrcElementImpl.cc SVGFontFaceUriElementImpl.cc SVGDefinitionSrcElementImpl.cc \
+SVGHKernElementImpl.cc SVGVKernElementImpl.cc \
+\
+SVGMetadataElementImpl.cc \
+\
+SVGForeignObjectElementImpl.cc \
+\
+svgpathparser.cc
+
+libksvgdomimpl_la_METASOURCES = AUTO
+
+INCLUDES = $(FREETYPE_CFLAGS) -I$(top_srcdir)/ksvg/core -I$(top_srcdir)/ksvg/dom -I$(top_srcdir)/ksvg/ecma -I$(top_srcdir)/ksvg/data -I$(top_srcdir)/ksvg/impl/libs/art_support -I$(top_srcdir)/ksvg/impl/libs/libtext2path/src $(all_includes)
diff --git a/ksvg/impl/SVGAElementImpl.cc b/ksvg/impl/SVGAElementImpl.cc
new file mode 100644
index 00000000..153ff5ff
--- /dev/null
+++ b/ksvg/impl/SVGAElementImpl.cc
@@ -0,0 +1,117 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGAElementImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGAnimatedStringImpl.h"
+
+using namespace KSVG;
+
+#include "SVGAElementImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+SVGAElementImpl::SVGAElementImpl(DOM::ElementImpl *impl) : SVGContainerImpl(impl), SVGURIReferenceImpl(), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_target = new SVGAnimatedStringImpl();
+ m_target->ref();
+}
+
+SVGAElementImpl::~SVGAElementImpl()
+{
+ if(m_target)
+ m_target->deref();
+}
+
+/*
+@namespace KSVG
+@begin SVGAElementImpl::s_hashTable 2
+ target SVGAElementImpl::Target DontDelete|ReadOnly
+@end
+*/
+
+Value SVGAElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case Target:
+ return m_target->cache(exec);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGAElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case Target:
+ {
+ if(m_target)
+ m_target->deref();
+
+ SVGAnimatedStringImpl *temp = new SVGAnimatedStringImpl();
+ temp->ref();
+ temp->setBaseVal(value.toString(exec).string());
+ setTarget(temp);
+ break;
+ }
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+void SVGAElementImpl::setTarget(SVGAnimatedStringImpl *target)
+{
+ m_target = target;
+}
+
+SVGAnimatedStringImpl *SVGAElementImpl::target() const
+{
+ return m_target;
+}
+
+SVGAElementImpl *SVGAElementImpl::getLink(SVGElementImpl *sourceElem)
+{
+ for(DOM::Node node = *sourceElem; !node.isNull(); node = node.parentNode())
+ {
+ SVGElementImpl *elem = sourceElem->ownerDoc()->getElementFromHandle(node.handle());
+ if(elem)
+ {
+ SVGAElementImpl *link = dynamic_cast<SVGAElementImpl *>(elem);
+ if(link)
+ return link;
+ }
+ }
+
+ return false;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAElementImpl.h b/ksvg/impl/SVGAElementImpl.h
new file mode 100644
index 00000000..2da4c3d4
--- /dev/null
+++ b/ksvg/impl/SVGAElementImpl.h
@@ -0,0 +1,79 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAElementImpl_H
+#define SVGAElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGTestsImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGLangSpaceImpl.h"
+#include "SVGContainerImpl.h"
+#include "SVGURIReferenceImpl.h"
+#include "SVGTransformableImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+
+namespace KSVG
+{
+
+class SVGAnimatedStringImpl;
+class SVGAElementImpl : public SVGContainerImpl,
+ public SVGURIReferenceImpl,
+ public SVGTestsImpl,
+ public SVGLangSpaceImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGStylableImpl,
+ public SVGTransformableImpl
+{
+public:
+ SVGAElementImpl(DOM::ElementImpl *);
+ virtual ~SVGAElementImpl();
+
+ void setTarget(SVGAnimatedStringImpl *target);
+ SVGAnimatedStringImpl *target() const;
+
+ static SVGAElementImpl *getLink(SVGElementImpl *sourceElem);
+
+private:
+ SVGAnimatedStringImpl *m_target;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+ KSVG_BRIDGE
+
+ enum
+ {
+ // Properties
+ Target
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+KSVG_REGISTER_ELEMENT(SVGAElementImpl, "a")
+
+}
+
+#endif
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAltGlyphDefElementImpl.cc b/ksvg/impl/SVGAltGlyphDefElementImpl.cc
new file mode 100644
index 00000000..2a0b5fe9
--- /dev/null
+++ b/ksvg/impl/SVGAltGlyphDefElementImpl.cc
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAltGlyphDefElementImpl.h"
+
+using namespace KSVG;
+
+SVGAltGlyphDefElementImpl::SVGAltGlyphDefElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl)
+{
+}
+
+SVGAltGlyphDefElementImpl::~SVGAltGlyphDefElementImpl()
+{
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAltGlyphDefElementImpl.h b/ksvg/impl/SVGAltGlyphDefElementImpl.h
new file mode 100644
index 00000000..cc1c92f4
--- /dev/null
+++ b/ksvg/impl/SVGAltGlyphDefElementImpl.h
@@ -0,0 +1,49 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAltGlyphDefElementImpl_H
+#define SVGAltGlyphDefElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGElementImpl.h"
+
+namespace KSVG
+{
+
+class SVGAltGlyphDefElementImpl : public SVGElementImpl
+{
+public:
+ SVGAltGlyphDefElementImpl(DOM::ElementImpl *);
+ virtual ~SVGAltGlyphDefElementImpl();
+
+public:
+ KSVG_BRIDGE
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+KSVG_REGISTER_ELEMENT(SVGAltGlyphDefElementImpl, "altGlyphDef")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAltGlyphElementImpl.cc b/ksvg/impl/SVGAltGlyphElementImpl.cc
new file mode 100644
index 00000000..d426bd74
--- /dev/null
+++ b/ksvg/impl/SVGAltGlyphElementImpl.cc
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGSVGElementImpl.h"
+#include "SVGAltGlyphElementImpl.h"
+
+using namespace KSVG;
+
+SVGAltGlyphElementImpl::SVGAltGlyphElementImpl(DOM::ElementImpl *impl) : SVGTSpanElementImpl(impl), SVGURIReferenceImpl()
+{
+}
+
+SVGAltGlyphElementImpl::~SVGAltGlyphElementImpl()
+{
+}
+
+void SVGAltGlyphElementImpl::setAttributes()
+{
+ SVGTSpanElementImpl::setAttributes();
+}
+
+DOM::DOMString SVGAltGlyphElementImpl::format()
+{
+ return "";
+}
+
+DOM::DOMString SVGAltGlyphElementImpl::glyphRef()
+{
+ return "";
+}
+
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAltGlyphElementImpl.h b/ksvg/impl/SVGAltGlyphElementImpl.h
new file mode 100644
index 00000000..8dcfe479
--- /dev/null
+++ b/ksvg/impl/SVGAltGlyphElementImpl.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAltGlyphElementImpl_H
+#define SVGAltGlyphElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGTSpanElementImpl.h"
+#include "SVGURIReferenceImpl.h"
+
+namespace KSVG
+{
+
+class SVGAltGlyphElementImpl : public SVGTSpanElementImpl,
+ public SVGURIReferenceImpl
+{
+public:
+ SVGAltGlyphElementImpl(DOM::ElementImpl *);
+ virtual ~SVGAltGlyphElementImpl();
+ virtual void setAttributes();
+
+ DOM::DOMString glyphRef();
+ DOM::DOMString format();
+
+public:
+ KSVG_BRIDGE
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+KSVG_REGISTER_ELEMENT(SVGAltGlyphElementImpl, "altGlyph")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAngleImpl.cc b/ksvg/impl/SVGAngleImpl.cc
new file mode 100644
index 00000000..6102329d
--- /dev/null
+++ b/ksvg/impl/SVGAngleImpl.cc
@@ -0,0 +1,277 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGAngle.h"
+
+#include "SVGAngleImpl.h"
+
+using namespace KSVG;
+
+#include "SVGAngleImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_cacheimpl.h"
+
+const double deg2rad = 0.017453292519943295769; // pi/180
+const double deg2grad = 400.0 / 360.0;
+const double rad2grad = deg2grad / deg2rad;
+
+SVGAngleImpl::SVGAngleImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_unitType = SVG_ANGLETYPE_UNKNOWN;
+ m_valueInSpecifiedUnits = 0;
+ m_value = 0;
+}
+
+SVGAngleImpl::~SVGAngleImpl()
+{
+}
+
+unsigned short SVGAngleImpl::unitType() const
+{
+ return m_unitType;
+}
+
+void SVGAngleImpl::setValue(float value)
+{
+ m_value = value;
+}
+
+float SVGAngleImpl::value() const
+{
+ return m_value;
+}
+
+// calc m_value
+void SVGAngleImpl::calculate()
+{
+ if(m_unitType == SVG_ANGLETYPE_GRAD)
+ m_value = m_valueInSpecifiedUnits / deg2grad;
+ else if(m_unitType == SVG_ANGLETYPE_RAD)
+ m_value = m_valueInSpecifiedUnits / deg2rad;
+ else if(m_unitType == SVG_ANGLETYPE_UNSPECIFIED || m_unitType == SVG_ANGLETYPE_DEG)
+ m_value = m_valueInSpecifiedUnits;
+}
+
+void SVGAngleImpl::setValueInSpecifiedUnits(float valueInSpecifiedUnits)
+{
+ m_valueInSpecifiedUnits = valueInSpecifiedUnits;
+ calculate();
+}
+
+float SVGAngleImpl::valueInSpecifiedUnits() const
+{
+ return m_valueInSpecifiedUnits;
+}
+
+void SVGAngleImpl::setValueAsString(const DOM::DOMString &valueAsString)
+{
+ m_valueAsString = valueAsString;
+
+ QString s = valueAsString.string();
+
+ bool bOK;
+ m_valueInSpecifiedUnits = s.toFloat(&bOK);
+ m_unitType = SVG_ANGLETYPE_UNSPECIFIED;
+
+ if(!bOK)
+ {
+ if(s.endsWith("deg"))
+ m_unitType = SVG_ANGLETYPE_DEG;
+ else if(s.endsWith("grad"))
+ m_unitType = SVG_ANGLETYPE_GRAD;
+ else if(s.endsWith("rad"))
+ m_unitType = SVG_ANGLETYPE_RAD;
+ }
+
+ calculate();
+}
+
+DOM::DOMString SVGAngleImpl::valueAsString() const
+{
+ m_valueAsString.string().setNum(m_valueInSpecifiedUnits);
+
+ switch(m_unitType)
+ {
+ case SVG_ANGLETYPE_UNSPECIFIED:
+ case SVG_ANGLETYPE_DEG:
+ m_valueAsString.string() += "deg";
+ break;
+ case SVG_ANGLETYPE_RAD:
+ m_valueAsString.string() += "rad";
+ break;
+ case SVG_ANGLETYPE_GRAD:
+ m_valueAsString.string() += "grad";
+ break;
+ }
+
+ return m_valueAsString;
+}
+
+void SVGAngleImpl::newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits)
+{
+ m_unitType = unitType;
+ m_valueInSpecifiedUnits = valueInSpecifiedUnits;
+ calculate();
+}
+
+void SVGAngleImpl::convertToSpecifiedUnits(unsigned short unitType)
+{
+ if(m_unitType == unitType)
+ return;
+
+ if(m_unitType == SVG_ANGLETYPE_DEG && unitType == SVG_ANGLETYPE_RAD)
+ m_valueInSpecifiedUnits *= deg2rad;
+ else if(m_unitType == SVG_ANGLETYPE_GRAD && unitType == SVG_ANGLETYPE_RAD)
+ m_valueInSpecifiedUnits /= rad2grad;
+ else if(m_unitType == SVG_ANGLETYPE_DEG && unitType == SVG_ANGLETYPE_GRAD)
+ m_valueInSpecifiedUnits *= deg2grad;
+ else if(m_unitType == SVG_ANGLETYPE_RAD && unitType == SVG_ANGLETYPE_GRAD)
+ m_valueInSpecifiedUnits *= rad2grad;
+ else if(m_unitType == SVG_ANGLETYPE_RAD && unitType == SVG_ANGLETYPE_DEG)
+ m_valueInSpecifiedUnits /= deg2rad;
+ else if(m_unitType == SVG_ANGLETYPE_GRAD && unitType == SVG_ANGLETYPE_DEG)
+ m_valueInSpecifiedUnits /= deg2grad;
+
+ m_unitType = unitType;
+}
+
+// Helpers
+double SVGAngleImpl::todeg(double rad)
+{
+ return rad / deg2rad;
+}
+
+double SVGAngleImpl::torad(double deg)
+{
+ return deg * deg2rad;
+}
+
+double SVGAngleImpl::shortestArcBisector(double angle1, double angle2)
+{
+ double bisector = (angle1 + angle2) / 2;
+
+ if(fabs(angle1 - angle2) > 180)
+ bisector += 180;
+
+ return bisector;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGAngleImpl::s_hashTable 5
+ value SVGAngleImpl::Value DontDelete
+ valueInSpecifiedUnits SVGAngleImpl::ValueInSpecifiedUnits DontDelete
+ valueAsString SVGAngleImpl::ValueAsString DontDelete
+ unitType SVGAngleImpl::UnitType DontDelete
+@end
+@namespace KSVG
+@begin SVGAngleImplProto::s_hashTable 3
+ convertToSpecifiedUnits SVGAngleImpl::ConvertToSpecifiedUnits DontDelete|Function 1
+ newValueSpecifiedUnits SVGAngleImpl::NewValueSpecifiedUnits DontDelete|Function 2
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGAngle", SVGAngleImplProto, SVGAngleImplProtoFunc)
+
+Value SVGAngleImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case Value:
+ return Number(value());
+ case ValueInSpecifiedUnits:
+ return Number(valueInSpecifiedUnits());
+ case ValueAsString:
+ return String(valueAsString().string());
+ case UnitType:
+ return Number(unitType());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGAngleImpl::putValueProperty(ExecState *exec, int token, const KJS::Value &value, int)
+{
+ switch(token)
+ {
+ case Value:
+ setValue(value.toNumber(exec));
+ break;
+ case ValueInSpecifiedUnits:
+ setValueInSpecifiedUnits(value.toNumber(exec));
+ break;
+ case ValueAsString:
+ setValueAsString(value.toString(exec).string());
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+Value SVGAngleImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGAngleImpl)
+
+ switch(id)
+ {
+ case SVGAngleImpl::ConvertToSpecifiedUnits:
+ obj->convertToSpecifiedUnits(static_cast<unsigned short>(args[0].toNumber(exec)));
+ break;
+ case SVGAngleImpl::NewValueSpecifiedUnits:
+ obj->newValueSpecifiedUnits(static_cast<unsigned short>(args[0].toNumber(exec)), args[1].toNumber(exec));
+ break;
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return Undefined();
+}
+
+/*
+@namespace KSVG
+@begin SVGAngleImplConstructor::s_hashTable 7
+ SVG_ANGLETYPE_UNKNOWN KSVG::SVG_ANGLETYPE_UNKNOWN DontDelete|ReadOnly
+ SVG_ANGLETYPE_UNSPECIFIED KSVG::SVG_ANGLETYPE_UNSPECIFIED DontDelete|ReadOnly
+ SVG_ANGLETYPE_RAD KSVG::SVG_ANGLETYPE_RAD DontDelete|ReadOnly
+ SVG_ANGLETYPE_DEG KSVG::SVG_ANGLETYPE_DEG DontDelete|ReadOnly
+ SVG_ANGLETYPE_GRAD KSVG::SVG_ANGLETYPE_GRAD DontDelete|ReadOnly
+@end
+*/
+
+Value SVGAngleImplConstructor::getValueProperty(ExecState *, int token) const
+{
+ return Number(token);
+}
+
+Value KSVG::getSVGAngleImplConstructor(ExecState *exec)
+{
+ return cacheGlobalBridge<SVGAngleImplConstructor>(exec, "[[svgangle.constructor]]");
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAngleImpl.h b/ksvg/impl/SVGAngleImpl.h
new file mode 100644
index 00000000..d3c656de
--- /dev/null
+++ b/ksvg/impl/SVGAngleImpl.h
@@ -0,0 +1,102 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAngleImpl_H
+#define SVGAngleImpl_H
+
+#include <dom/dom_misc.h>
+#include <dom/dom_string.h>
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAngleImpl : public DOM::DomShared
+{
+public:
+ SVGAngleImpl();
+ virtual ~SVGAngleImpl();
+
+ unsigned short unitType() const;
+
+ void setValue(float value);
+ float value() const;
+
+ void setValueInSpecifiedUnits(float valueInSpecifiedUnits);
+ float valueInSpecifiedUnits() const;
+
+ void setValueAsString(const DOM::DOMString &valueAsString);
+ DOM::DOMString valueAsString() const;
+
+ void newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits);
+ void convertToSpecifiedUnits(unsigned short unitType);
+
+ // Helpers
+ static double todeg(double rad);
+ static double torad(double deg);
+
+ // Returns the angle that divides the shortest arc between the two angles.
+ static double shortestArcBisector(double angle1, double angle2);
+
+private:
+ unsigned short m_unitType;
+ float m_value;
+ float m_valueInSpecifiedUnits;
+ DOM::DOMString m_valueAsString;
+
+ void calculate();
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ Value, ValueInSpecifiedUnits, ValueAsString, UnitType,
+ // Functions
+ ConvertToSpecifiedUnits, NewValueSpecifiedUnits
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+class SVGAngleImplConstructor : public KJS::ObjectImp
+{
+public:
+ SVGAngleImplConstructor(KJS::ExecState *) { }
+ KJS::Value getValueProperty(KJS::ExecState *, int token) const;
+
+ // no put - all read-only
+ KSVG_GET
+};
+
+KJS::Value getSVGAngleImplConstructor(KJS::ExecState *exec);
+
+}
+
+KSVG_DEFINE_PROTOTYPE(SVGAngleImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGAngleImplProtoFunc, SVGAngleImpl)
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimateColorElementImpl.cc b/ksvg/impl/SVGAnimateColorElementImpl.cc
new file mode 100644
index 00000000..c4cc0ad4
--- /dev/null
+++ b/ksvg/impl/SVGAnimateColorElementImpl.cc
@@ -0,0 +1,98 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <math.h>
+
+#include <kdebug.h>
+
+#include "SVGColorImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGAnimateColorElementImpl.h"
+
+using namespace KSVG;
+
+SVGAnimateColorElementImpl::SVGAnimateColorElementImpl(DOM::ElementImpl *impl) : SVGAnimationElementImpl(impl)
+{
+ m_fromColor = new SVGColorImpl(this);
+ m_fromColor->ref();
+
+ m_toColor = new SVGColorImpl(this);
+ m_toColor->ref();
+}
+
+SVGAnimateColorElementImpl::~SVGAnimateColorElementImpl()
+{
+ m_fromColor->deref();
+ m_toColor->deref();
+}
+
+/*
+ * Outstanding issues
+ * - 'values' support
+ * - 'by' support
+ */
+
+void SVGAnimateColorElementImpl::setAttributes()
+{
+ SVGAnimationElementImpl::setAttributes();
+
+ SVGStylableImpl::setColor(getFrom(), m_fromColor);
+ SVGStylableImpl::setColor(getTo(), m_toColor);
+
+ ownerDoc()->timeScheduler()->addTimer(this, int(getStartTime() * 1000.0));
+}
+
+void SVGAnimateColorElementImpl::handleTimerEvent()
+{
+ if(!m_connected)
+ {
+ double duration = getSimpleDuration() * 1000.0;
+ double dinterval = SVGTimeScheduler::staticTimerInterval;
+
+ m_step = 0;
+ m_steps = (int) rint(duration / dinterval);
+
+ m_connected = true;
+ ownerDoc()->timeScheduler()->connectIntervalTimer(this);
+ }
+ else
+ {
+ QColor fromColor(m_fromColor->rgbColor().color());
+ QColor toColor(m_toColor->rgbColor().color());
+
+ int red = (int) rint(((toColor.red() - fromColor.red()) / static_cast<double>(m_steps)) * m_step + fromColor.red());
+ int green = (int) rint(((toColor.green() - fromColor.green()) / static_cast<double>(m_steps)) * m_step + fromColor.green());
+ int blue = (int) rint(((toColor.blue() - fromColor.blue()) / static_cast<double>(m_steps)) * m_step + fromColor.blue());
+
+ QString color = "rgb(" + QString::number(red) + "," + QString::number(green) + "," + QString::number(blue) + ")";
+ applyAttribute(getAttributeName(), color);
+ }
+
+ if(m_step < m_steps)
+ m_step++;
+ else
+ {
+ ownerDoc()->timeScheduler()->disconnectIntervalTimer(this);
+ m_connected = false;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimateColorElementImpl.h b/ksvg/impl/SVGAnimateColorElementImpl.h
new file mode 100644
index 00000000..2832802e
--- /dev/null
+++ b/ksvg/impl/SVGAnimateColorElementImpl.h
@@ -0,0 +1,60 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimateColorElementImpl_H
+#define SVGAnimateColorElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGAnimationElementImpl.h"
+
+class QTimer;
+
+namespace KSVG
+{
+
+class SVGColorImpl;
+class SVGAnimateColorElementImpl : public SVGAnimationElementImpl
+{
+public:
+ SVGAnimateColorElementImpl(DOM::ElementImpl *);
+ virtual ~SVGAnimateColorElementImpl();
+
+ virtual void handleTimerEvent();
+ virtual void setAttributes();
+
+private:
+ SVGColorImpl *m_toColor, *m_fromColor;
+
+ int m_steps, m_step;
+
+public:
+ KSVG_BRIDGE
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+KSVG_REGISTER_ELEMENT(SVGAnimateColorElementImpl, "animateColor")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimateElementImpl.cc b/ksvg/impl/SVGAnimateElementImpl.cc
new file mode 100644
index 00000000..ab9bc52c
--- /dev/null
+++ b/ksvg/impl/SVGAnimateElementImpl.cc
@@ -0,0 +1,191 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGDocumentImpl.h"
+#include "SVGAnimateElementImpl.h"
+
+using namespace KSVG;
+
+SVGAnimateElementImpl::SVGAnimateElementImpl(DOM::ElementImpl *impl) : SVGAnimationElementImpl(impl)
+{
+ m_animVal = 0.0;
+ m_addStep = 0.0;
+}
+
+SVGAnimateElementImpl::~SVGAnimateElementImpl()
+{
+}
+
+void SVGAnimateElementImpl::setAttributes()
+{
+ SVGAnimationElementImpl::setAttributes();
+
+ ownerDoc()->timeScheduler()->addTimer(this, int(getStartTime() * 1000.0));
+}
+
+void SVGAnimateElementImpl::handleTimerEvent()
+{
+ if(!m_connected)
+ {
+ double duration = getSimpleDuration() * 1000.0;
+ double dinterval = SVGTimeScheduler::staticTimerInterval;
+
+ m_step = 0;
+ m_steps = (int) rint(duration / dinterval);
+
+ double to = 0, from = 0;
+ if(getTo().isEmpty())
+ to = targetElement()->getAttribute(getAttributeName()).string().toDouble();
+ else
+ to = getTo().toDouble();
+
+ if(getFrom().isEmpty())
+ from = targetElement()->getAttribute(getAttributeName()).string().toDouble();
+ else
+ from = getFrom().toDouble();
+
+ // 'by' support
+ if(!getBy().isEmpty())
+ {
+ m_animVal = from;
+ m_addStep = getBy().toDouble() / m_steps;
+ }
+ else
+ {
+ m_animVal = from;
+ m_addStep = (to - m_animVal) / m_steps;
+ }
+
+ m_connected = true;
+ ownerDoc()->timeScheduler()->connectIntervalTimer(this);
+ }
+ else
+ {
+ m_animVal += m_addStep;
+ applyAttribute(getAttributeName(), QString::number(m_animVal));
+ }
+
+ if(m_step < m_steps)
+ m_step++;
+ else
+ {
+ ownerDoc()->timeScheduler()->disconnectIntervalTimer(this);
+ m_connected = false;
+ if(m_fill == REMOVE)
+ applyAttribute(getAttributeName(), targetElement()->getAttribute(getAttributeName()).string());
+ }
+
+#if 0
+ m_attributeTimer = addTimer(interval() * 1000, false);
+
+
+ /*
+ m_steps = (getSimpleDuration() * 1000) / SVGAnimationElementImpl::timerTime;
+ m_step = 0;
+
+ if(m_additive == "sum" && m_times == 1 && !needCombine)
+ {
+ float add;
+
+ SVGLengthImpl *temp = new SVGLengthImpl();
+ temp->ref();
+ temp->setValueAsString(targetElement()->getAttribute(m_attributeName).string());
+ add = temp->value();
+ temp->deref();
+
+ m_from += add;
+ m_newFrom += add;
+ m_to += add;
+ m_newTo += add;
+
+ m_additiveAdded = add;
+ }
+
+ m_addStep = (m_to - m_from) / m_steps;
+ m_attributeTimer = addTimer(SVGAnimationElementImpl::timerTime, false);*/
+ }
+ else
+ {
+/* m_from += m_addStep;
+
+ if(m_additive == "replace" && needCombine)
+ needCombine = false;
+
+ applyAttribute(m_attributeName, QString::number(m_from), needCombine);
+
+ m_step++;
+
+ if(m_step == m_steps)
+ {
+ removeTimer(m_attributeTimer);
+
+ if(getRepeatDuration() == "indefinite" || getRepeatCount() == "indefinite")
+ {
+ m_times++;
+ m_firstEvent = true;
+
+ if(m_accumulate != "sum")
+ {
+ m_from = m_newFrom;
+ m_to = m_newTo;
+ }
+ else
+ {
+ m_from += (m_newFrom - m_additiveAdded) / 2;
+ m_to += (m_newTo - m_additiveAdded) / 2;
+ }
+
+ m_addStep = 0;
+ m_attributeTimer = 0;
+
+ addTimer(1);
+ }
+ else if(!getRepeatCount().isEmpty())
+ {
+ if(m_times <= getRepeatCount().toInt())
+ {
+ m_times++;
+ m_firstEvent = true;
+
+ if(m_accumulate != "sum")
+ {
+ m_from = m_newFrom;
+ m_to = m_newTo;
+ }
+ else
+ {
+ m_from += (m_newFrom - m_additiveAdded) / 2;
+ m_to += (m_newTo - m_additiveAdded) / 2;
+ }
+
+ m_addStep = 0;
+ m_attributeTimer = 0;
+
+ addTimer(1);
+ }
+ }
+ }*/
+ }
+#endif // 0
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimateElementImpl.h b/ksvg/impl/SVGAnimateElementImpl.h
new file mode 100644
index 00000000..855ced6e
--- /dev/null
+++ b/ksvg/impl/SVGAnimateElementImpl.h
@@ -0,0 +1,59 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimateElementImpl_H
+#define SVGAnimateElementImpl_H
+
+#include "ksvg_lookup.h"
+#include "SVGAnimationElementImpl.h"
+
+class QTimer;
+
+namespace KSVG
+{
+
+class SVGAnimateElementImpl : public SVGAnimationElementImpl
+{
+public:
+ SVGAnimateElementImpl(DOM::ElementImpl *);
+ virtual ~SVGAnimateElementImpl();
+
+ virtual void handleTimerEvent();
+ virtual void setAttributes();
+
+private:
+ double m_addStep, m_animVal;
+ QTimer *m_timer;
+
+ int m_steps, m_step;
+
+public:
+ KSVG_BRIDGE
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+KSVG_REGISTER_ELEMENT(SVGAnimateElementImpl, "animate")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimateMotionElementImpl.cc b/ksvg/impl/SVGAnimateMotionElementImpl.cc
new file mode 100644
index 00000000..ce756d55
--- /dev/null
+++ b/ksvg/impl/SVGAnimateMotionElementImpl.cc
@@ -0,0 +1,102 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// TODO: CLEANUP
+
+#include <dom/dom_doc.h>
+#include "SVGDocumentImpl.h"
+#include "SVGPathElementImpl.h"
+#include "SVGAnimateMotionElementImpl.h"
+
+using namespace KSVG;
+
+SVGAnimateMotionElementImpl::SVGAnimateMotionElementImpl(DOM::ElementImpl *impl) : SVGAnimationElementImpl(impl)
+{
+}
+
+SVGAnimateMotionElementImpl::~SVGAnimateMotionElementImpl()
+{
+}
+
+void SVGAnimateMotionElementImpl::setAttributes()
+{
+ SVGAnimationElementImpl::setAttributes();
+
+/*
+ // TODO: rotate..
+
+ DOM::DOMString _path = getAttribute("path");
+ if(!_path.isNull())
+ {
+ if(m_path)
+ m_path->deref();
+
+ m_path = new SVGPathElementImpl(reinterpret_cast<DOM::ElementImpl *>(static_cast<DOM::Document *>(ownerDoc())->createElement("path").handle()));
+ m_path->setOwnerDoc(ownerDoc());
+ m_path->setAttribute("d", _path);
+ m_path->setAttributes();
+ }
+
+ addTimer(int(getStartTime() * 1000));*/
+}
+
+//void SVGAnimateMotionElementImpl::prerender(KSVGPainter *p)
+//{
+// SVGAnimationElementImpl::prerender(p);
+
+/* if(!m_pathArray)
+ {
+ bool temp;
+ m_pathArray = m_path->preparePath(&temp, p->worldMatrix());
+ }*/
+//}
+
+void SVGAnimateMotionElementImpl::handleTimerEvent(bool /*needCombine*/)
+{
+/* if(m_firstEvent)
+ {
+ m_firstEvent = false;
+
+ m_steps = (int) (getSimpleDuration() * 1000) / interval();
+ m_step = 0;
+
+ m_motionTimer = addTimer(interval() * 1000, false);
+ }
+ else
+ {
+ m_step++;
+
+ if(m_step <= m_pathArray->count() - 1)
+ {
+ QPoint p = m_pathArray->point(m_step - 50);
+ applyAttribute("x", QString::number(p.x()));
+ applyAttribute("y", QString::number(p.y()));
+ kdDebug() << " X " << p.x() << " Y " << p.y() << " (" << m_pathArray->count() << "; " << m_step << ")" <<endl;
+ }
+
+ if(m_step == m_steps)
+ {
+ // TODO: repeat
+ removeTimer(m_motionTimer);
+ }
+ }*/
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimateMotionElementImpl.h b/ksvg/impl/SVGAnimateMotionElementImpl.h
new file mode 100644
index 00000000..fed4c550
--- /dev/null
+++ b/ksvg/impl/SVGAnimateMotionElementImpl.h
@@ -0,0 +1,56 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimateMotionElementImpl_H
+#define SVGAnimateMotionElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGAnimationElementImpl.h"
+
+namespace KSVG
+{
+
+class SVGPathElementImpl;
+class SVGAnimateMotionElementImpl : public SVGAnimationElementImpl
+{
+public:
+ SVGAnimateMotionElementImpl(DOM::ElementImpl *);
+ virtual ~SVGAnimateMotionElementImpl();
+
+ virtual void handleTimerEvent(bool needCombine = false);
+ virtual void setAttributes();
+
+private:
+ int m_steps, m_step;
+
+public:
+ KSVG_BRIDGE
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+KSVG_REGISTER_ELEMENT(SVGAnimateMotionElementImpl, "animateMotion")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimateTransformElementImpl.cc b/ksvg/impl/SVGAnimateTransformElementImpl.cc
new file mode 100644
index 00000000..d2634bb1
--- /dev/null
+++ b/ksvg/impl/SVGAnimateTransformElementImpl.cc
@@ -0,0 +1,257 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qstringlist.h>
+
+#include "SVGLengthImpl.h"
+#include "SVGHelperImpl.h"
+#include "SVGTransformImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGTransformListImpl.h"
+#include "SVGAnimatedTransformListImpl.h"
+#include "SVGAnimateTransformElementImpl.h"
+
+using namespace KSVG;
+
+SVGAnimateTransformElementImpl::SVGAnimateTransformElementImpl(DOM::ElementImpl *impl) : SVGAnimationElementImpl(impl)
+{
+ m_firstEvent = true;
+ m_setAttributes = false;
+
+ m_rotateX = -1;
+ m_rotateY = -1;
+ m_times = 1;
+ m_from = 0;
+ m_to = 0;
+
+ m_addStep = 0;
+}
+
+SVGAnimateTransformElementImpl::~SVGAnimateTransformElementImpl()
+{
+}
+
+void SVGAnimateTransformElementImpl::setAttributes()
+{
+ if(m_setAttributes)
+ return;
+
+ m_setAttributes = true;
+
+ SVGAnimationElementImpl::setAttributes();
+
+ /*
+ // TODO: much :)
+
+ DOM::DOMString _type = getAttribute("type");
+ if(!_type.isNull())
+ m_type = _type.string().lower();
+
+ DOM::DOMString _from = getAttribute("from");
+ if(!_from.isNull())
+ {
+ if(m_type != "rotate")
+ {
+ SVGLengthImpl *temp = SVGSVGElementImpl::createSVGLength();
+ temp->setValueAsString(_from.string());
+
+ m_from = temp->value();
+
+ temp->deref();
+ }
+ else
+ {
+ SVGTransformListImpl *list = new SVGTransformListImpl();
+ list->ref();
+
+ SVGHelperImpl::parseTransformAttribute(list, m_type + "(" + _from.string() + ")");
+
+ m_from = list->getFirst()->angle();
+
+ QStringList stringList = QStringList::split(' ', list->getFirst()->toString());
+ m_rotateX = stringList[1].toInt();
+ m_rotateY = stringList[2].mid(0, stringList[2].length() - 1).toInt();
+
+ list->deref();
+ }
+
+ m_newFrom = m_from;
+ m_addStep = m_from;
+ }
+
+ DOM::DOMString _to = getAttribute("to");
+ if(!_to.isNull())
+ {
+ if(m_type != "rotate")
+ {
+ SVGLengthImpl *temp = SVGSVGElementImpl::createSVGLength();
+ temp->setValueAsString(_to.string());
+
+ m_to = temp->value();
+
+ temp->deref();
+ }
+ else
+ {
+ SVGTransformListImpl *list = new SVGTransformListImpl();
+ list->ref();
+
+ SVGHelperImpl::parseTransformAttribute(list, m_type + "(" + _to.string() + ")");
+
+ m_to = list->getFirst()->angle();
+
+ list->deref();
+ }
+
+ m_newTo = m_to;
+ }
+
+ // TODO: values + rotate including cx + cy
+ DOM::DOMString _values = getAttribute("values");
+ if(!_values.isNull())
+ {
+ QString test = _values.string();
+
+ if(test.contains(";"))
+ {
+ SVGLengthImpl *temp = SVGSVGElementImpl::createSVGLength();
+
+ QStringList list = QStringList::split(';', test);
+ temp->setValueAsString(list[0]);
+ m_from = temp->value();
+ temp->setValueAsString(list[1]);
+ m_to = temp->value();
+
+ m_newFrom = m_from;
+ m_newTo = m_to;
+ m_addStep = m_from;
+
+ temp->deref();
+ }
+ }
+
+ if(getStartTime() != -1)
+ addTimer(int(getStartTime() * 1000));
+ else
+ addTimer(1);
+ */
+}
+
+void SVGAnimateTransformElementImpl::handleTimerEvent(bool)
+{ /*
+ if(m_firstEvent)
+ {
+ m_firstEvent = false;
+
+ m_steps = (int) (getSimpleDuration() * 1000) / interval();
+ m_step = 0;
+
+ m_addStep = (m_to - m_from) / m_steps;
+
+ m_transformTimer = addTimer(interval() * 1000, false);
+ }
+ else
+ {
+ m_from += m_addStep;
+
+ SVGTransformImpl *transform = SVGSVGElementImpl::createSVGTransform();
+
+ if(m_type == "rotate")
+ {
+ int x = 0, y = 0;
+
+ if(m_rotateX != -1)
+ x = m_rotateX;
+
+ if(m_rotateY != -1)
+ y = m_rotateY;
+
+ transform->setRotate(m_from, x, y);
+ }
+ else if(m_type == "scale")
+ transform->setScale(m_from, m_from);
+ else if(m_type == "skewx")
+ transform->setSkewX(m_from);
+ else if(m_type == "skewy")
+ transform->setSkewY(m_from);
+
+ QString trans = transform->toString();
+ QString last = trans;
+
+ if(targetElement()->hasAttribute("transform"))
+ {
+ trans += " " + targetElement()->getAttribute("transform").string();
+
+ if(!m_lastTransform.isEmpty())
+ {
+ int pos = trans.find(m_lastTransform);
+
+ QString extract;
+ extract += trans.mid(0, pos);
+ extract += trans.mid(pos + m_lastTransform.length() + 1, trans.length());
+
+ trans = extract;
+ }
+ }
+
+ m_lastTransform = last;
+
+ transform->deref();
+
+ applyAttribute("transform", trans);
+
+ m_step++;
+
+ if(m_step == m_steps)
+ {
+ removeTimer(m_transformTimer);
+
+ if(getRepeatDuration() == "indefinite" || getRepeatCount() == "indefinite")
+ {
+ m_firstEvent = true;
+ m_from = m_newFrom;
+ m_to = m_newTo;
+
+ m_addStep = 0;
+ m_transformTimer = 0;
+
+ addTimer(1);
+ }
+ else if(!getRepeatCount().isEmpty())
+ {
+ if(m_times <= getRepeatCount().toInt())
+ {
+ m_times++;
+ m_firstEvent = true;
+ m_from = m_newFrom;
+ m_to = m_newTo;
+
+ m_addStep = 0;
+ m_transformTimer = 0;
+
+ addTimer(1);
+ }
+ }
+ }
+ }
+ */
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimateTransformElementImpl.h b/ksvg/impl/SVGAnimateTransformElementImpl.h
new file mode 100644
index 00000000..7e6e2653
--- /dev/null
+++ b/ksvg/impl/SVGAnimateTransformElementImpl.h
@@ -0,0 +1,74 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimateTransformElementImpl_H
+#define SVGAnimateTransformElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGAnimationElementImpl.h"
+
+class QTimer;
+
+namespace KSVG
+{
+
+class SVGTransformImpl;
+class SVGTransformListImpl;
+class SVGAnimateTransformElementImpl : public SVGAnimationElementImpl
+{
+public:
+ SVGAnimateTransformElementImpl(DOM::ElementImpl *);
+ virtual ~SVGAnimateTransformElementImpl();
+
+ virtual void handleTimerEvent(bool needCombine = false);
+ virtual void setAttributes();
+
+private:
+ QString m_type, m_lastTransform;
+
+ int m_times;
+
+ int m_rotateX, m_rotateY;
+
+ int m_steps, m_step;
+
+ double m_from, m_to, m_newFrom, m_newTo;
+ double m_addStep;
+
+ QTimer *m_transformTimer;
+ SVGTransformListImpl *m_transformList;
+
+ bool m_firstEvent;
+ bool m_setAttributes;
+
+public:
+ KSVG_BRIDGE
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+KSVG_REGISTER_ELEMENT(SVGAnimateTransformElementImpl, "animateTransform")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedAngleImpl.cc b/ksvg/impl/SVGAnimatedAngleImpl.cc
new file mode 100644
index 00000000..63f0c000
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedAngleImpl.cc
@@ -0,0 +1,83 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGAngleImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGAnimatedAngleImpl.h"
+
+using namespace KSVG;
+
+#include "SVGAnimatedAngleImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+SVGAnimatedAngleImpl::SVGAnimatedAngleImpl() : DOM::DomShared()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_baseVal = SVGSVGElementImpl::createSVGAngle();
+ m_animVal = SVGSVGElementImpl::createSVGAngle();
+}
+
+SVGAnimatedAngleImpl::~SVGAnimatedAngleImpl()
+{
+ if(m_baseVal)
+ m_baseVal->deref();
+ if(m_animVal)
+ m_animVal->deref();
+}
+
+SVGAngleImpl *SVGAnimatedAngleImpl::baseVal() const
+{
+ return m_baseVal;
+}
+
+SVGAngleImpl *SVGAnimatedAngleImpl::animVal() const
+{
+ return m_animVal;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGAnimatedAngleImpl::s_hashTable 3
+ baseVal SVGAnimatedAngleImpl::BaseVal DontDelete|ReadOnly
+ animVal SVGAnimatedAngleImpl::AnimVal DontDelete|ReadOnly
+@end
+*/
+
+Value SVGAnimatedAngleImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case BaseVal:
+ return m_baseVal->cache(exec);
+ case AnimVal:
+ return m_animVal->cache(exec);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedAngleImpl.h b/ksvg/impl/SVGAnimatedAngleImpl.h
new file mode 100644
index 00000000..f6617ce6
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedAngleImpl.h
@@ -0,0 +1,61 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedAngleImpl_H
+#define SVGAnimatedAngleImpl_H
+
+#include <dom/dom_misc.h>
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAngleImpl;
+class SVGAnimatedAngleImpl : public DOM::DomShared
+{
+public:
+ SVGAnimatedAngleImpl();
+ virtual ~SVGAnimatedAngleImpl();
+
+ SVGAngleImpl *baseVal() const;
+ SVGAngleImpl *animVal() const;
+
+private:
+ SVGAngleImpl *m_baseVal;
+ SVGAngleImpl *m_animVal;
+
+public:
+ KSVG_GET
+
+ enum
+ {
+ // Properties
+ BaseVal, AnimVal
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedBooleanImpl.cc b/ksvg/impl/SVGAnimatedBooleanImpl.cc
new file mode 100644
index 00000000..d30fa5ef
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedBooleanImpl.cc
@@ -0,0 +1,93 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGAnimatedBooleanImpl.h"
+
+using namespace KSVG;
+
+#include "SVGAnimatedBooleanImpl.lut.h"
+#include "ksvg_bridge.h"
+
+SVGAnimatedBooleanImpl::SVGAnimatedBooleanImpl() : DOM::DomShared()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_baseVal = false;
+ m_animVal = false;
+}
+
+SVGAnimatedBooleanImpl::~SVGAnimatedBooleanImpl()
+{
+}
+
+void SVGAnimatedBooleanImpl::setBaseVal(bool baseVal)
+{
+ m_baseVal = baseVal;
+}
+
+bool SVGAnimatedBooleanImpl::baseVal() const
+{
+ return m_baseVal;
+}
+
+bool SVGAnimatedBooleanImpl::animVal() const
+{
+ return m_animVal;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGAnimatedBooleanImpl::s_hashTable 3
+ baseVal SVGAnimatedBooleanImpl::BaseVal DontDelete
+ animVal SVGAnimatedBooleanImpl::AnimVal DontDelete|ReadOnly
+@end
+*/
+
+Value SVGAnimatedBooleanImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case BaseVal:
+ return Number(baseVal());
+ case AnimVal:
+ return Number(animVal());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGAnimatedBooleanImpl::putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int)
+{
+ switch(token)
+ {
+ case BaseVal:
+ setBaseVal(value.toBoolean(exec));
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedBooleanImpl.h b/ksvg/impl/SVGAnimatedBooleanImpl.h
new file mode 100644
index 00000000..9e31792e
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedBooleanImpl.h
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedBooleanImpl_H
+#define SVGAnimatedBooleanImpl_H
+
+#include <dom/dom_misc.h>
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedBooleanImpl : public DOM::DomShared
+{
+public:
+ SVGAnimatedBooleanImpl();
+ virtual ~SVGAnimatedBooleanImpl();
+
+ void setBaseVal(bool baseVal);
+ bool baseVal() const;
+
+ bool animVal() const;
+
+private:
+ bool m_baseVal;
+ bool m_animVal;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ BaseVal, AnimVal
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedEnumerationImpl.cc b/ksvg/impl/SVGAnimatedEnumerationImpl.cc
new file mode 100644
index 00000000..f619f231
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedEnumerationImpl.cc
@@ -0,0 +1,93 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGAnimatedEnumerationImpl.h"
+
+using namespace KSVG;
+
+#include "SVGAnimatedEnumerationImpl.lut.h"
+#include "ksvg_bridge.h"
+
+SVGAnimatedEnumerationImpl::SVGAnimatedEnumerationImpl() : DOM::DomShared()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_baseVal = 0;
+ m_animVal = 0;
+}
+
+SVGAnimatedEnumerationImpl::~SVGAnimatedEnumerationImpl()
+{
+}
+
+void SVGAnimatedEnumerationImpl::setBaseVal(unsigned short baseVal)
+{
+ m_baseVal = baseVal;
+}
+
+unsigned short SVGAnimatedEnumerationImpl::baseVal() const
+{
+ return m_baseVal;
+}
+
+unsigned short SVGAnimatedEnumerationImpl::animVal() const
+{
+ return m_animVal;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGAnimatedEnumerationImpl::s_hashTable 3
+ baseVal SVGAnimatedEnumerationImpl::BaseVal DontDelete
+ animVal SVGAnimatedEnumerationImpl::AnimVal DontDelete|ReadOnly
+@end
+*/
+
+Value SVGAnimatedEnumerationImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case BaseVal:
+ return Number(baseVal());
+ case AnimVal:
+ return Number(animVal());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGAnimatedEnumerationImpl::putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int)
+{
+ switch(token)
+ {
+ case BaseVal:
+ setBaseVal(static_cast<unsigned short>(value.toNumber(exec)));
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedEnumerationImpl.h b/ksvg/impl/SVGAnimatedEnumerationImpl.h
new file mode 100644
index 00000000..ae4638f4
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedEnumerationImpl.h
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedEnumerationImpl_H
+#define SVGAnimatedEnumerationImpl_H
+
+#include <dom/dom_misc.h>
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedEnumerationImpl : public DOM::DomShared
+{
+public:
+ SVGAnimatedEnumerationImpl();
+ virtual ~SVGAnimatedEnumerationImpl();
+
+ void setBaseVal(unsigned short baseVal);
+ unsigned short baseVal() const;
+
+ unsigned short animVal() const;
+
+private:
+ unsigned short m_baseVal;
+ unsigned short m_animVal;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ BaseVal, AnimVal
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedIntegerImpl.cc b/ksvg/impl/SVGAnimatedIntegerImpl.cc
new file mode 100644
index 00000000..8bf08a87
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedIntegerImpl.cc
@@ -0,0 +1,91 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGAnimatedIntegerImpl.h"
+
+using namespace KSVG;
+
+#include "SVGAnimatedIntegerImpl.lut.h"
+#include "ksvg_bridge.h"
+
+SVGAnimatedIntegerImpl::SVGAnimatedIntegerImpl() : DOM::DomShared()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_baseVal = 0;
+ m_animVal = 0;
+}
+
+SVGAnimatedIntegerImpl::~SVGAnimatedIntegerImpl()
+{
+}
+
+void SVGAnimatedIntegerImpl::setBaseVal(long baseVal)
+{
+ m_baseVal = baseVal;
+}
+
+long SVGAnimatedIntegerImpl::baseVal() const
+{
+ return m_baseVal;
+}
+
+long SVGAnimatedIntegerImpl::animVal() const
+{
+ return m_animVal;
+}
+
+/*
+@namespace KSVG
+@begin SVGAnimatedIntegerImpl::s_hashTable 3
+ baseVal SVGAnimatedIntegerImpl::BaseVal DontDelete
+ animVal SVGAnimatedIntegerImpl::AnimVal DontDelete
+@end
+*/
+
+Value SVGAnimatedIntegerImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case BaseVal:
+ return Number(baseVal());
+ case AnimVal:
+ return Number(animVal());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+ return KJS::Undefined();
+}
+
+void SVGAnimatedIntegerImpl::putValueProperty(ExecState *exec, int token, const KJS::Value &value, int)
+{
+ switch(token)
+ {
+ case BaseVal:
+ setBaseVal(value.toInteger(exec));
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedIntegerImpl.h b/ksvg/impl/SVGAnimatedIntegerImpl.h
new file mode 100644
index 00000000..8ad7ad88
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedIntegerImpl.h
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedIntegerImpl_H
+#define SVGAnimatedIntegerImpl_H
+
+#include <dom/dom_misc.h>
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedIntegerImpl : public DOM::DomShared
+{
+public:
+ SVGAnimatedIntegerImpl();
+ virtual ~SVGAnimatedIntegerImpl();
+
+ void setBaseVal(long baseVal);
+ long baseVal() const;
+
+ long animVal() const;
+
+private:
+ long m_baseVal;
+ long m_animVal;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ BaseVal, AnimVal
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedLengthImpl.cc b/ksvg/impl/SVGAnimatedLengthImpl.cc
new file mode 100644
index 00000000..25176965
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedLengthImpl.cc
@@ -0,0 +1,96 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGElementImpl.h"
+
+using namespace KSVG;
+
+#include "SVGAnimatedLengthImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+SVGAnimatedLengthImpl::SVGAnimatedLengthImpl(LengthMode mode, SVGElementImpl *object) : DOM::DomShared()
+{
+ m_baseVal = new SVGLengthImpl(mode, object);
+ m_baseVal->ref();
+
+ m_animVal = new SVGLengthImpl(mode, object);
+ m_animVal->ref();
+}
+
+SVGAnimatedLengthImpl::SVGAnimatedLengthImpl(const SVGAnimatedLengthImpl &other) : DOM::DomShared()
+{
+ (*this) = other;
+}
+
+SVGAnimatedLengthImpl::~SVGAnimatedLengthImpl()
+{
+ if(m_baseVal)
+ m_baseVal->deref();
+ if(m_animVal)
+ m_animVal->deref();
+}
+
+SVGAnimatedLengthImpl &SVGAnimatedLengthImpl::operator=(const SVGAnimatedLengthImpl &other)
+{
+ *m_baseVal = *(other.m_baseVal);
+ *m_animVal = *(other.m_animVal);
+
+ return *this;
+}
+
+SVGLengthImpl *SVGAnimatedLengthImpl::baseVal() const
+{
+ return m_baseVal;
+}
+
+SVGLengthImpl *SVGAnimatedLengthImpl::animVal() const
+{
+ return m_animVal;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGAnimatedLengthImpl::s_hashTable 3
+ baseVal SVGAnimatedLengthImpl::BaseVal DontDelete|ReadOnly
+ animVal SVGAnimatedLengthImpl::AnimVal DontDelete|ReadOnly
+@end
+*/
+
+Value SVGAnimatedLengthImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case BaseVal:
+ return m_baseVal->cache(exec);
+ case AnimVal:
+ return m_animVal->cache(exec);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedLengthImpl.h b/ksvg/impl/SVGAnimatedLengthImpl.h
new file mode 100644
index 00000000..80f473db
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedLengthImpl.h
@@ -0,0 +1,65 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedLengthImpl_H
+#define SVGAnimatedLengthImpl_H
+
+#include <dom/dom_misc.h>
+
+#include "SVGLengthImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+class SVGElementImpl;
+class SVGAnimatedLengthImpl : public DOM::DomShared
+{
+public:
+ SVGAnimatedLengthImpl(LengthMode mode = LENGTHMODE_UNKNOWN, SVGElementImpl *object = 0);
+ SVGAnimatedLengthImpl(const SVGAnimatedLengthImpl &);
+ virtual ~SVGAnimatedLengthImpl();
+
+ SVGAnimatedLengthImpl &operator=(const SVGAnimatedLengthImpl &);
+
+ SVGLengthImpl *baseVal() const;
+ SVGLengthImpl *animVal() const;
+
+private:
+ SVGLengthImpl *m_baseVal;
+ SVGLengthImpl *m_animVal;
+
+public:
+ KSVG_GET
+
+ enum
+ {
+ // Properties
+ BaseVal, AnimVal
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedLengthListImpl.cc b/ksvg/impl/SVGAnimatedLengthListImpl.cc
new file mode 100644
index 00000000..296fa1ea
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedLengthListImpl.cc
@@ -0,0 +1,95 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGAnimatedLengthListImpl.h"
+
+using namespace KSVG;
+
+#include "SVGAnimatedLengthListImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+SVGAnimatedLengthListImpl::SVGAnimatedLengthListImpl() : DOM::DomShared()
+{
+ m_baseVal = new SVGLengthListImpl();
+ m_baseVal->ref();
+
+ m_animVal = new SVGLengthListImpl();
+ m_animVal->ref();
+}
+
+SVGAnimatedLengthListImpl::SVGAnimatedLengthListImpl(const SVGAnimatedLengthListImpl &other) : DOM::DomShared()
+{
+ (*this) = other;
+}
+
+SVGAnimatedLengthListImpl::~SVGAnimatedLengthListImpl()
+{
+ if(m_baseVal)
+ m_baseVal->deref();
+ if(m_animVal)
+ m_animVal->deref();
+}
+
+SVGAnimatedLengthListImpl &SVGAnimatedLengthListImpl::operator=(const SVGAnimatedLengthListImpl &other)
+{
+ *m_baseVal = *(other.m_baseVal);
+ *m_animVal = *(other.m_animVal);
+
+ return *this;
+}
+
+SVGLengthListImpl *SVGAnimatedLengthListImpl::baseVal() const
+{
+ return m_baseVal;
+}
+
+SVGLengthListImpl *SVGAnimatedLengthListImpl::animVal() const
+{
+ return m_animVal;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGAnimatedLengthListImpl::s_hashTable 3
+ baseVal SVGAnimatedLengthListImpl::BaseVal DontDelete|ReadOnly
+ animVal SVGAnimatedLengthListImpl::AnimVal DontDelete|ReadOnly
+@end
+*/
+
+Value SVGAnimatedLengthListImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case BaseVal:
+ return m_baseVal->cache(exec);
+ case AnimVal:
+ return m_animVal->cache(exec);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedLengthListImpl.h b/ksvg/impl/SVGAnimatedLengthListImpl.h
new file mode 100644
index 00000000..74f3cb1e
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedLengthListImpl.h
@@ -0,0 +1,61 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedLengthListImpl_H
+#define SVGAnimatedLengthListImpl_H
+
+#include "SVGLengthListImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedLengthListImpl : public DOM::DomShared
+{
+public:
+ SVGAnimatedLengthListImpl();
+ SVGAnimatedLengthListImpl(const SVGAnimatedLengthListImpl &);
+ virtual ~SVGAnimatedLengthListImpl();
+
+ SVGAnimatedLengthListImpl &operator=(const SVGAnimatedLengthListImpl &);
+
+ SVGLengthListImpl *baseVal() const;
+ SVGLengthListImpl *animVal() const;
+
+private:
+ SVGLengthListImpl *m_baseVal;
+ SVGLengthListImpl *m_animVal;
+
+public:
+ KSVG_GET
+
+ enum
+ {
+ // Properties
+ BaseVal, AnimVal
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+};
+
+}
+
+#endif
diff --git a/ksvg/impl/SVGAnimatedNumberImpl.cc b/ksvg/impl/SVGAnimatedNumberImpl.cc
new file mode 100644
index 00000000..2937c233
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedNumberImpl.cc
@@ -0,0 +1,94 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGAnimatedNumberImpl.h"
+
+using namespace KSVG;
+
+#include "SVGAnimatedNumberImpl.lut.h"
+#include "ksvg_bridge.h"
+
+SVGAnimatedNumberImpl::SVGAnimatedNumberImpl() : DOM::DomShared()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_baseVal = 0;
+ m_animVal = 0;
+}
+
+SVGAnimatedNumberImpl::~SVGAnimatedNumberImpl()
+{
+}
+
+void SVGAnimatedNumberImpl::setBaseVal(float baseVal)
+{
+ m_baseVal = baseVal;
+}
+
+float SVGAnimatedNumberImpl::baseVal() const
+{
+ return m_baseVal;
+}
+
+float SVGAnimatedNumberImpl::animVal() const
+{
+ return m_animVal;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGAnimatedNumberImpl::s_hashTable 3
+ baseVal SVGAnimatedNumberImpl::BaseVal DontDelete
+ animVal SVGAnimatedNumberImpl::AnimVal DontDelete|ReadOnly
+@end
+*/
+
+Value SVGAnimatedNumberImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case BaseVal:
+ return Number(baseVal());
+ case AnimVal:
+ return Number(animVal());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+
+ return Undefined();
+}
+
+void SVGAnimatedNumberImpl::putValueProperty(ExecState *exec, int token, const KJS::Value &value, int)
+{
+ switch(token)
+ {
+ case BaseVal:
+ setBaseVal(value.toNumber(exec));
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedNumberImpl.h b/ksvg/impl/SVGAnimatedNumberImpl.h
new file mode 100644
index 00000000..81c9217b
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedNumberImpl.h
@@ -0,0 +1,63 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedNumberImpl_H
+#define SVGAnimatedNumberImpl_H
+
+#include <dom/dom_misc.h>
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedNumberImpl : public DOM::DomShared
+{
+public:
+ SVGAnimatedNumberImpl();
+ virtual ~SVGAnimatedNumberImpl();
+
+ void setBaseVal(float baseVal);
+ float baseVal() const;
+
+ float animVal() const;
+
+private:
+ float m_baseVal;
+ float m_animVal;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ BaseVal, AnimVal
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedNumberListImpl.cc b/ksvg/impl/SVGAnimatedNumberListImpl.cc
new file mode 100644
index 00000000..d6ff44e0
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedNumberListImpl.cc
@@ -0,0 +1,82 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGAnimatedNumberListImpl.h"
+
+using namespace KSVG;
+
+#include "SVGAnimatedNumberListImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+SVGAnimatedNumberListImpl::SVGAnimatedNumberListImpl() : DOM::DomShared()
+{
+ m_baseVal = new SVGNumberListImpl();
+ m_baseVal->ref();
+
+ m_animVal = new SVGNumberListImpl();
+ m_animVal->ref();
+}
+
+SVGAnimatedNumberListImpl::~SVGAnimatedNumberListImpl()
+{
+ if(m_baseVal)
+ m_baseVal->deref();
+ if(m_animVal)
+ m_animVal->deref();
+}
+
+SVGNumberListImpl *SVGAnimatedNumberListImpl::baseVal() const
+{
+ return m_baseVal;
+}
+
+SVGNumberListImpl *SVGAnimatedNumberListImpl::animVal() const
+{
+ return m_animVal;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGAnimatedNumberListImpl::s_hashTable 3
+ baseVal SVGAnimatedNumberListImpl::BaseVal DontDelete|ReadOnly
+ animVal SVGAnimatedNumberListImpl::AnimVal DontDelete|ReadOnly
+@end
+*/
+
+Value SVGAnimatedNumberListImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case BaseVal:
+ return m_baseVal->cache(exec);
+ case AnimVal:
+ return m_animVal->cache(exec);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedNumberListImpl.h b/ksvg/impl/SVGAnimatedNumberListImpl.h
new file mode 100644
index 00000000..b44b3ffd
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedNumberListImpl.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedNumberListImpl_H
+#define SVGAnimatedNumberListImpl_H
+
+#include "SVGNumberListImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedNumberListImpl : public DOM::DomShared
+{
+public:
+ SVGAnimatedNumberListImpl();
+ virtual ~SVGAnimatedNumberListImpl();
+
+ SVGNumberListImpl *baseVal() const;
+ SVGNumberListImpl *animVal() const;
+
+private:
+ SVGNumberListImpl *m_baseVal;
+ SVGNumberListImpl *m_animVal;
+
+public:
+ KSVG_GET
+
+ enum
+ {
+ // Properties
+ BaseVal, AnimVal
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+};
+
+}
+
+#endif
diff --git a/ksvg/impl/SVGAnimatedPathDataImpl.cc b/ksvg/impl/SVGAnimatedPathDataImpl.cc
new file mode 100644
index 00000000..2b9ebf4c
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedPathDataImpl.cc
@@ -0,0 +1,108 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGPathSegListImpl.h"
+#include "SVGAnimatedPathDataImpl.h"
+
+using namespace KSVG;
+
+#include "SVGAnimatedPathDataImpl.lut.h"
+#include "ksvg_bridge.h"
+
+SVGAnimatedPathDataImpl::SVGAnimatedPathDataImpl() : DOM::DomShared()
+{
+ m_pathSegList = new SVGPathSegListImpl();
+ m_pathSegList->ref();
+
+ m_normalizedPathSegList = new SVGPathSegListImpl();
+ m_normalizedPathSegList->ref();
+
+ m_animatedPathSegList = new SVGPathSegListImpl();
+ m_animatedPathSegList->ref();
+
+ m_animatedNormalizedPathSegList = new SVGPathSegListImpl();
+ m_animatedNormalizedPathSegList->ref();
+}
+
+SVGAnimatedPathDataImpl::~SVGAnimatedPathDataImpl()
+{
+ if(m_pathSegList)
+ m_pathSegList->deref();
+ if(m_normalizedPathSegList)
+ m_normalizedPathSegList->deref();
+ if(m_animatedPathSegList)
+ m_animatedPathSegList->deref();
+ if(m_animatedNormalizedPathSegList)
+ m_animatedNormalizedPathSegList->deref();
+}
+
+SVGPathSegListImpl *SVGAnimatedPathDataImpl::pathSegList() const
+{
+ return m_pathSegList;
+}
+
+SVGPathSegListImpl *SVGAnimatedPathDataImpl::normalizedPathSegList() const
+{
+ return m_normalizedPathSegList;
+}
+
+SVGPathSegListImpl *SVGAnimatedPathDataImpl::animatedPathSegList() const
+{
+ return m_animatedPathSegList;
+}
+
+SVGPathSegListImpl *SVGAnimatedPathDataImpl::animatedNormalizedPathSegList() const
+{
+ return m_animatedNormalizedPathSegList;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGAnimatedPathDataImpl::s_hashTable 5
+ pathSegList SVGAnimatedPathDataImpl::PathSegList DontDelete|ReadOnly
+ normalizedPathSegList SVGAnimatedPathDataImpl::NormalizedPathSegList DontDelete|ReadOnly
+ animatedPathSegList SVGAnimatedPathDataImpl::AnimatedPathSegList DontDelete|ReadOnly
+ animatedNormalizedPathSegList SVGAnimatedPathDataImpl::AnimatedNormalizedPathSegList DontDelete|ReadOnly
+@end
+*/
+
+Value SVGAnimatedPathDataImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case PathSegList:
+ return pathSegList()->cache(exec);
+ case NormalizedPathSegList:
+ return normalizedPathSegList()->cache(exec);
+ case AnimatedPathSegList:
+ return animatedPathSegList()->cache(exec);
+ case AnimatedNormalizedPathSegList:
+ return animatedNormalizedPathSegList()->cache(exec);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+}
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedPathDataImpl.h b/ksvg/impl/SVGAnimatedPathDataImpl.h
new file mode 100644
index 00000000..2af1f893
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedPathDataImpl.h
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedPathDataImpl_H
+#define SVGAnimatedPathDataImpl_H
+
+#include <dom/dom_misc.h>
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGPathSegListImpl;
+
+// special case, virtual public HAS to stay
+class SVGAnimatedPathDataImpl : virtual public DOM::DomShared
+{
+public:
+ SVGAnimatedPathDataImpl();
+ virtual ~SVGAnimatedPathDataImpl();
+
+ SVGPathSegListImpl *pathSegList() const;
+ SVGPathSegListImpl *normalizedPathSegList() const;
+ SVGPathSegListImpl *animatedPathSegList() const;
+ SVGPathSegListImpl *animatedNormalizedPathSegList() const;
+
+private:
+ SVGPathSegListImpl *m_pathSegList;
+ SVGPathSegListImpl *m_normalizedPathSegList;
+ SVGPathSegListImpl *m_animatedPathSegList;
+ SVGPathSegListImpl *m_animatedNormalizedPathSegList;
+
+public:
+ KSVG_GET
+
+ enum
+ {
+ // Properties
+ PathSegList, NormalizedPathSegList, AnimatedPathSegList, AnimatedNormalizedPathSegList
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedPointsImpl.cc b/ksvg/impl/SVGAnimatedPointsImpl.cc
new file mode 100644
index 00000000..093ded77
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedPointsImpl.cc
@@ -0,0 +1,139 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include <qstringlist.h>
+
+#include "CanvasItem.h"
+#include "SVGPointListImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGAnimatedPointsImpl.h"
+
+using namespace KSVG;
+
+#include "SVGAnimatedPointsImpl.lut.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+
+SVGAnimatedPointsImpl::SVGAnimatedPointsImpl() : DOM::DomShared()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_points = new SVGPointListImpl();
+ m_points->ref();
+
+ m_animatedPoints = new SVGPointListImpl();
+ m_animatedPoints->ref();
+}
+
+SVGAnimatedPointsImpl::~SVGAnimatedPointsImpl()
+{
+ if(m_points)
+ m_points->deref();
+ if(m_animatedPoints)
+ m_animatedPoints->deref();
+}
+
+SVGPointListImpl *SVGAnimatedPointsImpl::points() const
+{
+ return m_points;
+}
+
+SVGPointListImpl *SVGAnimatedPointsImpl::animatedPoints() const
+{
+ return m_animatedPoints;
+}
+
+void SVGAnimatedPointsImpl::parsePoints(QString _points, SVGPointListImpl *points)
+{
+ if(_points.isEmpty())
+ return;
+
+ _points = _points.simplifyWhiteSpace();
+
+ if(_points.contains(",,") || _points.contains(", ,"))
+ return;
+
+ _points.replace(',', ' ');
+ _points.replace('\r', QString::null);
+ _points.replace('\n', QString::null);
+
+ _points = _points.simplifyWhiteSpace();
+
+ QStringList pointList = QStringList::split(' ', _points);
+ for(QStringList::Iterator it = pointList.begin(); it != pointList.end(); it++)
+ {
+ SVGPointImpl *point = SVGSVGElementImpl::createSVGPoint();
+ point->setX((*(it++)).toFloat());
+ point->setY((*it).toFloat());
+
+ points->appendItem(point);
+ }
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGAnimatedPointsImpl::s_hashTable 3
+ points SVGAnimatedPointsImpl::Points DontDelete|ReadOnly
+ animatedPoints SVGAnimatedPointsImpl::AnimatedPoints DontDelete|ReadOnly
+@end
+*/
+
+Value SVGAnimatedPointsImpl::getValueProperty(ExecState *exec, int token) const
+{
+ //KSVG_CHECK_ATTRIBUTE
+
+ switch(token)
+ {
+ case Points: // TODO: We need a pointList->toText function, quite trivial
+// if(!attributeMode)
+ return points()->cache(exec);
+ case AnimatedPoints:
+ return animatedPoints()->cache(exec);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGAnimatedPointsImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case Points:
+ parsePoints(value.toString(exec).qstring(), m_points);
+ break;
+ case AnimatedPoints:
+ parsePoints(value.toString(exec).qstring(), m_animatedPoints);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedPointsImpl.h b/ksvg/impl/SVGAnimatedPointsImpl.h
new file mode 100644
index 00000000..ef4dafca
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedPointsImpl.h
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedPointsImpl_H
+#define SVGAnimatedPointsImpl_H
+
+#include <dom/dom_misc.h>
+
+#include "ksvg_lookup.h"
+
+class QString;
+
+namespace KSVG
+{
+
+class SVGPointListImpl;
+class SVGAnimatedPointsImpl : virtual public DOM::DomShared
+{
+public:
+ SVGAnimatedPointsImpl();
+ virtual ~SVGAnimatedPointsImpl();
+
+ SVGPointListImpl *points() const;
+ SVGPointListImpl *animatedPoints() const;
+
+ static void parsePoints(QString _points, SVGPointListImpl *points);
+
+protected:
+ SVGPointListImpl *m_points;
+ SVGPointListImpl *m_animatedPoints;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ Points, AnimatedPoints
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedPreserveAspectRatioImpl.cc b/ksvg/impl/SVGAnimatedPreserveAspectRatioImpl.cc
new file mode 100644
index 00000000..166b987f
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedPreserveAspectRatioImpl.cc
@@ -0,0 +1,83 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGPreserveAspectRatioImpl.h"
+#include "SVGAnimatedPreserveAspectRatioImpl.h"
+
+using namespace KSVG;
+
+#include "SVGAnimatedPreserveAspectRatioImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+SVGAnimatedPreserveAspectRatioImpl::SVGAnimatedPreserveAspectRatioImpl() : DOM::DomShared()
+{
+ m_baseVal = new SVGPreserveAspectRatioImpl();
+ m_baseVal->ref();
+
+ m_animVal = new SVGPreserveAspectRatioImpl();
+ m_animVal->ref();
+}
+
+SVGAnimatedPreserveAspectRatioImpl::~SVGAnimatedPreserveAspectRatioImpl()
+{
+ if(m_baseVal)
+ m_baseVal->deref();
+ if(m_animVal)
+ m_animVal->deref();
+}
+
+SVGPreserveAspectRatioImpl *SVGAnimatedPreserveAspectRatioImpl::baseVal() const
+{
+ return m_baseVal;
+}
+
+SVGPreserveAspectRatioImpl *SVGAnimatedPreserveAspectRatioImpl::animVal() const
+{
+ return m_animVal;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGAnimatedPreserveAspectRatioImpl::s_hashTable 3
+ baseVal SVGAnimatedPreserveAspectRatioImpl::BaseVal DontDelete|ReadOnly
+ animVal SVGAnimatedPreserveAspectRatioImpl::AnimVal DontDelete|ReadOnly
+@end
+*/
+
+Value SVGAnimatedPreserveAspectRatioImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case BaseVal:
+ return m_baseVal->cache(exec);
+ case AnimVal:
+ return m_animVal->cache(exec);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedPreserveAspectRatioImpl.h b/ksvg/impl/SVGAnimatedPreserveAspectRatioImpl.h
new file mode 100644
index 00000000..30fb7c87
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedPreserveAspectRatioImpl.h
@@ -0,0 +1,61 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedPreserveAspectRatioImpl_H
+#define SVGAnimatedPreserveAspectRatioImpl_H
+
+#include <dom/dom_misc.h>
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGPreserveAspectRatioImpl;
+class SVGAnimatedPreserveAspectRatioImpl : public DOM::DomShared
+{
+public:
+ SVGAnimatedPreserveAspectRatioImpl();
+ virtual ~SVGAnimatedPreserveAspectRatioImpl();
+
+ SVGPreserveAspectRatioImpl *baseVal() const;
+ SVGPreserveAspectRatioImpl *animVal() const;
+
+private:
+ SVGPreserveAspectRatioImpl *m_baseVal;
+ SVGPreserveAspectRatioImpl *m_animVal;
+
+public:
+ KSVG_GET
+
+ enum
+ {
+ // Properties
+ BaseVal, AnimVal
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedRectImpl.cc b/ksvg/impl/SVGAnimatedRectImpl.cc
new file mode 100644
index 00000000..4ba7a50d
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedRectImpl.cc
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGRectImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGAnimatedRectImpl.h"
+
+using namespace KSVG;
+
+#include "SVGAnimatedRectImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+SVGAnimatedRectImpl::SVGAnimatedRectImpl() : DOM::DomShared()
+{
+ m_baseVal = SVGSVGElementImpl::createSVGRect();
+ m_animVal = SVGSVGElementImpl::createSVGRect();
+}
+
+SVGAnimatedRectImpl::~SVGAnimatedRectImpl()
+{
+ if(m_baseVal)
+ m_baseVal->deref();
+ if(m_animVal)
+ m_animVal->deref();
+}
+
+SVGRectImpl *SVGAnimatedRectImpl::baseVal() const
+{
+ return m_baseVal;
+}
+
+SVGRectImpl *SVGAnimatedRectImpl::animVal() const
+{
+ return m_animVal;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGAnimatedRectImpl::s_hashTable 3
+ baseVal SVGAnimatedRectImpl::BaseVal DontDelete
+ animVal SVGAnimatedRectImpl::AnimVal DontDelete
+@end
+*/
+
+Value SVGAnimatedRectImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case BaseVal:
+ return m_baseVal->cache(exec);
+ case AnimVal:
+ return m_animVal->cache(exec);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedRectImpl.h b/ksvg/impl/SVGAnimatedRectImpl.h
new file mode 100644
index 00000000..0619505d
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedRectImpl.h
@@ -0,0 +1,61 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedRectImpl_H
+#define SVGAnimatedRectImpl_H
+
+#include <dom/dom_misc.h>
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGRectImpl;
+class SVGAnimatedRectImpl : public DOM::DomShared
+{
+public:
+ SVGAnimatedRectImpl();
+ virtual ~SVGAnimatedRectImpl();
+
+ SVGRectImpl *baseVal() const;
+ SVGRectImpl *animVal() const;
+
+private:
+ SVGRectImpl *m_baseVal;
+ SVGRectImpl *m_animVal;
+
+public:
+ KSVG_GET
+
+ enum
+ {
+ // Properties
+ BaseVal, AnimVal
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedStringImpl.cc b/ksvg/impl/SVGAnimatedStringImpl.cc
new file mode 100644
index 00000000..1ce4f00b
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedStringImpl.cc
@@ -0,0 +1,90 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGAnimatedStringImpl.h"
+
+using namespace KSVG;
+
+#include "SVGAnimatedStringImpl.lut.h"
+#include "ksvg_bridge.h"
+
+SVGAnimatedStringImpl::SVGAnimatedStringImpl() : DOM::DomShared()
+{
+ KSVG_EMPTY_FLAGS
+}
+
+SVGAnimatedStringImpl::~SVGAnimatedStringImpl()
+{
+}
+
+void SVGAnimatedStringImpl::setBaseVal(const DOM::DOMString &baseVal)
+{
+ m_baseVal = baseVal;
+}
+
+DOM::DOMString SVGAnimatedStringImpl::baseVal() const
+{
+ return m_baseVal;
+}
+
+DOM::DOMString SVGAnimatedStringImpl::animVal() const
+{
+ return m_animVal;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGAnimatedStringImpl::s_hashTable 3
+ baseVal SVGAnimatedStringImpl::BaseVal DontDelete
+ animVal SVGAnimatedStringImpl::AnimVal DontDelete|ReadOnly
+@end
+*/
+
+Value SVGAnimatedStringImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case BaseVal:
+ return String(baseVal().string());
+ case AnimVal:
+ return String(animVal().string());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGAnimatedStringImpl::putValueProperty(ExecState *exec, int token, const Value &value, int)
+{
+ switch(token)
+ {
+ case BaseVal:
+ setBaseVal(value.toString(exec).string());
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedStringImpl.h b/ksvg/impl/SVGAnimatedStringImpl.h
new file mode 100644
index 00000000..cc15f7e2
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedStringImpl.h
@@ -0,0 +1,65 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedStringImpl_H
+#define SVGAnimatedStringImpl_H
+
+#include <dom/dom_misc.h>
+#include <dom/dom_string.h>
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedStringImpl : public DOM::DomShared
+{
+public:
+ SVGAnimatedStringImpl();
+ virtual ~SVGAnimatedStringImpl();
+
+ void setBaseVal(const DOM::DOMString &baseVal);
+ DOM::DOMString baseVal() const;
+
+ DOM::DOMString animVal() const;
+
+private:
+ DOM::DOMString m_baseVal;
+ DOM::DOMString m_animVal;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ BaseVal, AnimVal
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedTransformListImpl.cc b/ksvg/impl/SVGAnimatedTransformListImpl.cc
new file mode 100644
index 00000000..2e3b5536
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedTransformListImpl.cc
@@ -0,0 +1,83 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGTransformListImpl.h"
+#include "SVGAnimatedTransformListImpl.h"
+
+using namespace KSVG;
+
+#include "SVGAnimatedTransformListImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+SVGAnimatedTransformListImpl::SVGAnimatedTransformListImpl() : DOM::DomShared()
+{
+ m_baseVal = new SVGTransformListImpl();
+ m_baseVal->ref();
+
+ m_animVal = new SVGTransformListImpl();
+ m_animVal->ref();
+}
+
+SVGAnimatedTransformListImpl::~SVGAnimatedTransformListImpl()
+{
+ if(m_baseVal)
+ m_baseVal->deref();
+ if(m_animVal)
+ m_animVal->deref();
+}
+
+SVGTransformListImpl *SVGAnimatedTransformListImpl::baseVal() const
+{
+ return m_baseVal;
+}
+
+SVGTransformListImpl *SVGAnimatedTransformListImpl::animVal() const
+{
+ return m_animVal;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGAnimatedTransformListImpl::s_hashTable 3
+ baseVal SVGAnimatedTransformListImpl::BaseVal DontDelete|ReadOnly
+ animVal SVGAnimatedTransformListImpl::AnimVal DontDelete|ReadOnly
+@end
+*/
+
+Value SVGAnimatedTransformListImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case BaseVal:
+ return m_baseVal->cache(exec);
+ case AnimVal:
+ return m_animVal->cache(exec);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimatedTransformListImpl.h b/ksvg/impl/SVGAnimatedTransformListImpl.h
new file mode 100644
index 00000000..dc4be7e1
--- /dev/null
+++ b/ksvg/impl/SVGAnimatedTransformListImpl.h
@@ -0,0 +1,61 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimatedTransformListImpl_H
+#define SVGAnimatedTransformListImpl_H
+
+#include <dom/dom_misc.h>
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGTransformListImpl;
+class SVGAnimatedTransformListImpl : public DOM::DomShared
+{
+public:
+ SVGAnimatedTransformListImpl();
+ virtual ~SVGAnimatedTransformListImpl();
+
+ SVGTransformListImpl *baseVal() const;
+ SVGTransformListImpl *animVal() const;
+
+private:
+ SVGTransformListImpl *m_baseVal;
+ SVGTransformListImpl *m_animVal;
+
+public:
+ KSVG_GET
+
+ enum
+ {
+ // Properties
+ BaseVal, AnimVal
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimationElementImpl.cc b/ksvg/impl/SVGAnimationElementImpl.cc
new file mode 100644
index 00000000..454a323e
--- /dev/null
+++ b/ksvg/impl/SVGAnimationElementImpl.cc
@@ -0,0 +1,465 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <math.h>
+
+#include <kdebug.h>
+
+#include <qtimer.h>
+
+#include "CanvasItem.h"
+#include "SVGHelperImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGStringListImpl.h"
+#include "SVGURIReferenceImpl.h"
+#include "SVGAnimationElementImpl.h"
+
+using namespace KSVG;
+
+#include "SVGAnimationElementImpl.lut.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+
+SVGAnimationElementImpl::SVGAnimationElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGTestsImpl(), SVGExternalResourcesRequiredImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_connected = false;
+ m_targetElement = 0;
+
+ m_values = new SVGStringListImpl();
+ m_keyTimes= new SVGStringListImpl();
+ m_keySplines = new SVGStringListImpl();
+
+ m_fill = REMOVE;
+ m_additive = REPLACE;
+ m_accumulate = ACCUMULATE_NONE;
+}
+
+SVGAnimationElementImpl::~SVGAnimationElementImpl()
+{
+ if(m_targetElement)
+ m_targetElement->deref();
+}
+
+SVGElementImpl *SVGAnimationElementImpl::targetElement() const
+{
+ if(!m_targetElement)
+ {
+ SVGAnimationElementImpl *modify = const_cast<SVGAnimationElementImpl *>(this);
+ if(!m_href.isEmpty())
+ modify->setTargetElement(ownerDoc()->getElementByIdRecursive(ownerSVGElement(), SVGURIReferenceImpl::getTarget(m_href)));
+ else if(!parentNode().isNull())
+ modify->setTargetElement(ownerDoc()->getElementFromHandle(parentNode().handle()));
+ }
+
+ return m_targetElement;
+}
+
+double SVGAnimationElementImpl::parseClockValue(const QString &data) const
+{
+ QString parse = data.stripWhiteSpace();
+ QString debugOutput = "parseClockValue(" + parse + ") -> ";
+
+ if(parse == "indefinite") // Saves some time...
+ return -1;
+
+ double result;
+
+ int doublePointOne = parse.find(':');
+ int doublePointTwo = parse.find(':', doublePointOne + 1);
+
+ if(doublePointOne != -1 && doublePointTwo != -1) // Spec: "Full clock values"
+ {
+ unsigned int hours = parse.mid(0, 2).toUInt();
+ unsigned int minutes = parse.mid(3, 2).toUInt();
+ unsigned int seconds = parse.mid(6, 2).toUInt();
+ unsigned int milliseconds = 0;
+
+ result = (3600 * hours) + (60 * minutes) + seconds;
+
+ if(parse.find('.') != -1)
+ {
+ QString temp = parse.mid(9, 2);
+ milliseconds = temp.toUInt();
+ result += (milliseconds * (1 / pow(10.0, temp.length())));
+ }
+ }
+ else if(doublePointOne != -1 && doublePointTwo == -1) // Spec: "Partial clock values"
+ {
+ unsigned int minutes = parse.mid(0, 2).toUInt();
+ unsigned int seconds = parse.mid(3, 2).toUInt();
+ unsigned int milliseconds = 0;
+
+ result = (60 * minutes) + seconds;
+
+ if(parse.find('.') != -1)
+ {
+ QString temp = parse.mid(6, 2);
+ milliseconds = temp.toUInt();
+ result += (milliseconds * (1 / pow(10.0, temp.length())));
+ }
+ }
+ else // Spec: "Timecount values"
+ {
+ int dotPosition = parse.find('.');
+
+ if(parse.endsWith("h"))
+ {
+ if(dotPosition == -1)
+ result = parse.mid(0, parse.length() - 1).toUInt() * 3600;
+ else
+ {
+ result = parse.mid(0, dotPosition).toUInt() * 3600;
+ QString temp = parse.mid(dotPosition + 1, parse.length() - dotPosition - 2);
+ result += (3600.0 * temp.toUInt()) * (1 / pow(10.0, temp.length()));
+ }
+ }
+ else if(parse.endsWith("min"))
+ {
+ if(dotPosition == -1)
+ result = parse.mid(0, parse.length() - 3).toUInt() * 60;
+ else
+ {
+ result = parse.mid(0, dotPosition).toUInt() * 60;
+ QString temp = parse.mid(dotPosition + 1, parse.length() - dotPosition - 4);
+ result += (60.0 * temp.toUInt()) * (1 / pow(10.0, temp.length()));
+ }
+ }
+ else if(parse.endsWith("ms"))
+ {
+ if(dotPosition == -1)
+ result = parse.mid(0, parse.length() - 2).toUInt() / 1000.0;
+ else
+ {
+ result = parse.mid(0, dotPosition).toUInt() / 1000.0;
+ QString temp = parse.mid(dotPosition + 1, parse.length() - dotPosition - 3);
+ result += (temp.toUInt() / 1000.0) * (1 / pow(10.0, temp.length()));
+ }
+ }
+ else if(parse.endsWith("s"))
+ {
+ if(dotPosition == -1)
+ result = parse.mid(0, parse.length() - 1).toUInt();
+ else
+ {
+ result = parse.mid(0, dotPosition).toUInt();
+ QString temp = parse.mid(dotPosition + 1, parse.length() - dotPosition - 2);
+ result += temp.toUInt() * (1 / pow(10.0, temp.length()));
+ }
+ }
+ else
+ result = parse.toDouble();
+ }
+
+ kdDebug() << debugOutput << result << endl;
+ return result;
+}
+
+/*
+@namespace KSVG
+@begin SVGAnimationElementImpl::s_hashTable 23
+ targetElement SVGAnimationElementImpl::TargetElement DontDelete|ReadOnly
+ href SVGAnimationElementImpl::Href DontDelete|ReadOnly
+ additive SVGAnimationElementImpl::Additive DontDelete|ReadOnly
+ accumulate SVGAnimationElementImpl::Accumulate DontDelete|ReadOnly
+ attributeName SVGAnimationElementImpl::AttributeName DontDelete|ReadOnly
+ attributeType SVGAnimationElementImpl::AttributeType DontDelete|ReadOnly
+ calcMode SVGAnimationElementImpl::CalcMode DontDelete|ReadOnly
+ values SVGAnimationElementImpl::Values DontDelete|ReadOnly
+ keyTimes SVGAnimationElementImpl::KeyTimes DontDelete|ReadOnly
+ keySplines SVGAnimationElementImpl::KeySplines DontDelete|ReadOnly
+ from SVGAnimationElementImpl::From DontDelete|ReadOnly
+ to SVGAnimationElementImpl::To DontDelete|ReadOnly
+ by SVGAnimationElementImpl::By DontDelete|ReadOnly
+ begin SVGAnimationElementImpl::Begin DontDelete|ReadOnly
+ dur SVGAnimationElementImpl::Dur DontDelete|ReadOnly
+ end SVGAnimationElementImpl::End DontDelete|ReadOnly
+ min SVGAnimationElementImpl::Min DontDelete|ReadOnly
+ max SVGAnimationElementImpl::Max DontDelete|ReadOnly
+ restart SVGAnimationElementImpl::Restart DontDelete|ReadOnly
+ repeatCount SVGAnimationElementImpl::RepeatCount DontDelete|ReadOnly
+ repeatDur SVGAnimationElementImpl::RepeatDur DontDelete|ReadOnly
+ fill SVGAnimationElementImpl::Fill DontDelete|ReadOnly
+@end
+@namespace KSVG
+@begin SVGAnimationElementImplProto::s_hashTable 5
+ getStartTime SVGAnimationElementImpl::GetStartTime DontDelete|Function 0
+ getCurrentTime SVGAnimationElementImpl::GetCurrentTime DontDelete|Function 0
+ getSimpleDuration SVGAnimationElementImpl::GetSimpleDuration DontDelete|Function 0
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGAnimationElement",SVGAnimationElementImplProto,SVGAnimationElementImplProtoFunc)
+
+Value SVGAnimationElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case TargetElement:
+ return m_targetElement->cache(exec);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGAnimationElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ QString val = value.toString(exec).qstring();
+ switch(token)
+ {
+ case Href:
+ m_href = val;
+ break;
+ case Additive:
+ m_additive = (val == "sum") ? SUM : REPLACE;
+ break;
+ case Accumulate:
+ m_accumulate = (val == "sum") ? ACCUMULATE_SUM : ACCUMULATE_NONE;
+ break;
+ case AttributeName:
+ m_attributeName = val;
+ break;
+ case AttributeType:
+ if(val == "css")
+ m_attributeType = CSS;
+ else if(val == "xml")
+ m_attributeType = XML;
+ else
+ m_attributeType = AUTO;
+ break;
+ case CalcMode: // FIXME: See spec for default values!!!
+ if(val == "discrete")
+ m_calcMode = DISCRETE;
+ else if(val == "linear")
+ m_calcMode = LINEAR;
+ else if(val == "spline")
+ m_calcMode = SPLINE;
+ else if(val == "paced")
+ m_calcMode = PACED;
+ break;
+ case Values:
+ SVGHelperImpl::parseSemicolonSeperatedList(m_values, val);
+ break;
+ case KeyTimes:
+ SVGHelperImpl::parseSemicolonSeperatedList(m_keyTimes, val);
+ break;
+ case KeySplines:
+ SVGHelperImpl::parseSemicolonSeperatedList(m_keySplines, val);
+ break;
+ case From:
+ m_from = val;
+ break;
+ case To:
+ m_to = val;
+ break;
+ case By:
+ m_by = val;
+ break;
+ case Begin:
+ case End:
+ {
+ // Create list
+ SVGStringListImpl *temp = new SVGStringListImpl();
+ temp->ref();
+
+ // Feed data into list
+ SVGHelperImpl::parseSemicolonSeperatedList(temp, val);
+
+ // Parse data
+ for(unsigned int i = 0; i < temp->numberOfItems(); i++)
+ {
+ QString current = temp->getItem(i)->string();
+
+ if(current.startsWith("accessKey"))
+ {
+ // Register keyDownEventListener for the character
+ QString character = current.mid(current.length() - 2, 1);
+
+ kdDebug() << "ACCESSKEY CHARACTER " << character << endl;
+ }
+ else if(current.startsWith("wallclock"))
+ {
+ int firstBrace = current.find("(");
+ int secondBrace = current.find(")");
+
+ QString wallclockValue = current.mid(firstBrace + 1, secondBrace - firstBrace - 2);
+
+ kdDebug() << "WALLCLOCK VALUE " << wallclockValue << endl;
+ }
+ else if(current.contains("."))
+ {
+ int dotPosition = current.find(".");
+
+ QString element = current.mid(0, dotPosition);
+ QString clockValue;
+
+ if(current.contains("begin"))
+ clockValue = current.mid(dotPosition + 6);
+ else if(current.contains("end"))
+ clockValue = current.mid(dotPosition + 4);
+ else if(current.contains("repeat"))
+ clockValue = current.mid(dotPosition + 7);
+ else // DOM2 Event Reference
+ {
+ int plusMinusPosition = -1;
+
+ if(current.contains("+"))
+ plusMinusPosition = current.find("+");
+ else if(current.contains("-"))
+ plusMinusPosition = current.find("-");
+
+ QString event = current.mid(dotPosition + 1, plusMinusPosition - dotPosition - 1);
+
+ clockValue = current.mid(dotPosition + event.length() + 1);
+ kdDebug() << "EVENT " << event << endl;
+ }
+
+ kdDebug() << "ELEMENT " << element << " CLOCKVALUE " << clockValue << endl;
+ }
+ else
+ {
+ if(token == Begin)
+ m_begin = parseClockValue(current);
+ else
+ m_end = parseClockValue(current);
+ }
+ }
+
+ temp->deref();
+
+ break;
+ }
+ case Dur:
+ m_duration = parseClockValue(val);
+ break;
+// case Min:
+// case Max:
+ case Restart:
+ if(val == "whenNotActive")
+ m_restart = WHENNOTACTIVE;
+ else if(val == "never")
+ m_restart = NEVER;
+ else
+ m_restart = ALWAYS;
+ break;
+ case RepeatCount:
+ m_repeatCount = val;
+ break;
+ case RepeatDur:
+ m_repeatDur = val;
+ break;
+ case Fill:
+ m_fill = (val == "freeze") ? FREEZE : REMOVE;
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+Value SVGAnimationElementImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &)
+{
+ KSVG_CHECK_THIS(SVGAnimationElementImpl)
+
+ switch(id)
+ {
+ case SVGAnimationElementImpl::GetStartTime:
+ return Number(obj->getStartTime());
+ case SVGAnimationElementImpl::GetCurrentTime:
+ return Number(obj->getCurrentTime());
+ case SVGAnimationElementImpl::GetSimpleDuration:
+ return Number(obj->getSimpleDuration());
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return Undefined();
+}
+
+void SVGAnimationElementImpl::setAttributes()
+{
+ SVGElementImpl::setAttributes();
+
+ // Spec: Default value is "replace"
+ if(KSVG_TOKEN_NOT_PARSED(Additive))
+ KSVG_SET_ALT_ATTRIBUTE(Additive, "replace")
+
+ // Spec: Default value is "none"
+ if(KSVG_TOKEN_NOT_PARSED(Accumulate))
+ KSVG_SET_ALT_ATTRIBUTE(Accumulate, "none")
+
+ // Spec: Default value is "always"
+ if(KSVG_TOKEN_NOT_PARSED(Restart))
+ KSVG_SET_ALT_ATTRIBUTE(Restart, "always")
+}
+
+void SVGAnimationElementImpl::setTargetElement(SVGElementImpl *target)
+{
+ if(m_targetElement)
+ m_targetElement->deref();
+
+ m_targetElement = target;
+ m_targetElement->ref();
+}
+
+void SVGAnimationElementImpl::applyAttribute(const QString &name, const QString &value)
+{
+ SVGElementImpl *target = targetElement();
+ if(!target)
+ {
+ kdDebug() << k_funcinfo << " name: " << name << " value: " << value << " NO TARGET ELEMENT!" << endl;
+ return;
+ }
+
+ // The only two cases I can imagine, where combining is needed (Niko)
+ bool combine = (name == "style" || name == "transform");
+
+ if(!combine)
+ target->setAttributeInternal(name, value);
+ else
+ {
+ kdDebug() << "TODO COMBINE: " << value << " NAME " << name << endl;
+ }
+}
+
+double SVGAnimationElementImpl::getStartTime() const
+{
+ return m_begin;
+}
+
+double SVGAnimationElementImpl::getCurrentTime() const
+{
+ return 0.0;
+}
+
+double SVGAnimationElementImpl::getSimpleDuration() const
+{
+ return m_duration;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGAnimationElementImpl.h b/ksvg/impl/SVGAnimationElementImpl.h
new file mode 100644
index 00000000..9fd9446e
--- /dev/null
+++ b/ksvg/impl/SVGAnimationElementImpl.h
@@ -0,0 +1,149 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGAnimationElementImpl_H
+#define SVGAnimationElementImpl_H
+
+#include "SVGElementImpl.h"
+#include "SVGTestsImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+enum EFillMode
+{
+ REMOVE,
+ FREEZE
+};
+
+enum EAdditiveMode
+{
+ REPLACE,
+ SUM
+};
+
+enum EAccumulateMode
+{
+ ACCUMULATE_NONE,
+ ACCUMULATE_SUM
+};
+
+enum ECalcMode
+{
+ DISCRETE,
+ LINEAR,
+ PACED,
+ SPLINE
+};
+
+enum ERestart
+{
+ ALWAYS,
+ WHENNOTACTIVE,
+ NEVER
+};
+
+enum EAttributeType
+{
+ CSS,
+ XML,
+ AUTO
+};
+
+class SVGAnimationElementImpl : public SVGElementImpl,
+ public SVGTestsImpl,
+ public SVGExternalResourcesRequiredImpl
+{
+public:
+ SVGAnimationElementImpl(DOM::ElementImpl *);
+ virtual ~SVGAnimationElementImpl();
+
+ SVGElementImpl *targetElement() const;
+ void setTargetElement(SVGElementImpl *target);
+
+ void applyAttribute(const QString &name, const QString &value);
+
+ virtual void handleTimerEvent() { } //= 0;
+ virtual void setAttributes();
+
+ double getStartTime() const;
+ double getCurrentTime() const;
+ double getSimpleDuration() const;
+
+ QString getRepeatCount() const { return m_repeatCount; }
+ QString getRepeatDuration() const { return m_repeatDur; }
+
+ QString getAttributeName() const { return m_attributeName; }
+ QString getFrom() const { return m_from; }
+ QString getTo() const { return m_to; }
+ QString getBy() const { return m_by; }
+
+protected:
+ double parseClockValue(const QString &data) const;
+
+ bool m_connected;
+ EFillMode m_fill : 1;
+ EAdditiveMode m_additive : 1;
+ EAccumulateMode m_accumulate : 1;
+ ECalcMode m_calcMode : 2;
+ ERestart m_restart : 2;
+ EAttributeType m_attributeType : 2;
+ SVGElementImpl *m_targetElement;
+
+ QString m_href;
+ QString m_attributeName;
+ QString m_from, m_to, m_by;
+
+ double m_begin, m_end, m_duration;
+
+ QString m_repeatCount, m_repeatDur;
+
+ SVGStringListImpl *m_values, *m_keyTimes, *m_keySplines;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ TargetElement,
+ Href, Additive, Accumulate, AttributeName, AttributeType,
+ CalcMode, Values, KeyTimes, KeySplines, From, To, By,
+ Begin, Dur, End, Min, Max, Restart, RepeatCount, RepeatDur, Fill,
+ // Functions
+ GetStartTime, GetCurrentTime, GetSimpleDuration
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+KSVG_DEFINE_PROTOTYPE(SVGAnimationElementImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGAnimationElementImplProtoFunc, SVGAnimationElementImpl)
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGBBoxTarget.cc b/ksvg/impl/SVGBBoxTarget.cc
new file mode 100644
index 00000000..fcef164e
--- /dev/null
+++ b/ksvg/impl/SVGBBoxTarget.cc
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <dom/dom_misc.h>
+
+#include "SVGShapeImpl.h"
+#include "SVGBBoxTarget.h"
+
+using namespace KSVG;
+
+SVGBBoxTarget::SVGBBoxTarget()
+{
+ m_target = 0;
+}
+
+SVGBBoxTarget::~SVGBBoxTarget()
+{
+ if(m_target)
+ dynamic_cast<DOM::DomShared *>(m_target)->deref();
+}
+
+SVGShapeImpl *SVGBBoxTarget::getBBoxTarget() const
+{
+ return m_target;
+}
+
+void SVGBBoxTarget::setBBoxTarget(SVGShapeImpl *target)
+{
+ if(m_target)
+ dynamic_cast<DOM::DomShared *>(m_target)->deref();
+
+ m_target = target;
+
+ if(m_target)
+ dynamic_cast<DOM::DomShared *>(m_target)->ref();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGBBoxTarget.h b/ksvg/impl/SVGBBoxTarget.h
new file mode 100644
index 00000000..03de657d
--- /dev/null
+++ b/ksvg/impl/SVGBBoxTarget.h
@@ -0,0 +1,45 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGBBoxTarget_H
+#define SVGBBoxTarget_H
+
+namespace KSVG
+{
+
+class SVGShapeImpl;
+class SVGBBoxTarget
+{
+public:
+ SVGBBoxTarget();
+ virtual ~SVGBBoxTarget();
+
+ SVGShapeImpl *getBBoxTarget() const;
+ void setBBoxTarget(SVGShapeImpl *target);
+
+protected:
+ SVGShapeImpl *m_target;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGCSSRuleImpl.cc b/ksvg/impl/SVGCSSRuleImpl.cc
new file mode 100644
index 00000000..991487e3
--- /dev/null
+++ b/ksvg/impl/SVGCSSRuleImpl.cc
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGCSSRuleImpl.h"
+
+using namespace KSVG;
+
+SVGCSSRuleImpl::SVGCSSRuleImpl() : DOM::DomShared()//, css::CSSRule()
+{
+}
+
+SVGCSSRuleImpl::~SVGCSSRuleImpl()
+{
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGCSSRuleImpl.h b/ksvg/impl/SVGCSSRuleImpl.h
new file mode 100644
index 00000000..03ab4e8b
--- /dev/null
+++ b/ksvg/impl/SVGCSSRuleImpl.h
@@ -0,0 +1,42 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGCSSRuleImpl_H
+#define SVGCSSRuleImpl_H
+
+#include <dom/dom_misc.h>
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGCSSRuleImpl : public DOM::DomShared //, public css::CSSRule
+{
+public:
+ SVGCSSRuleImpl();
+ virtual ~SVGCSSRuleImpl();
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGCircleElementImpl.cc b/ksvg/impl/SVGCircleElementImpl.cc
new file mode 100644
index 00000000..b6246d1a
--- /dev/null
+++ b/ksvg/impl/SVGCircleElementImpl.cc
@@ -0,0 +1,178 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "CanvasItem.h"
+#include "KSVGCanvas.h"
+
+#include "SVGRectImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGCircleElementImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+
+using namespace KSVG;
+
+#include "SVGCircleElementImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+
+SVGCircleElementImpl::SVGCircleElementImpl(DOM::ElementImpl *impl) : SVGShapeImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_cx = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this);
+ m_cx->ref();
+ m_cx->baseVal()->setValueAsString("-1");
+
+ m_cy = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this);
+ m_cy->ref();
+ m_cy->baseVal()->setValueAsString("-1");
+
+ m_r = new SVGAnimatedLengthImpl(LENGTHMODE_OTHER, this);
+ m_r->ref();
+ m_r->baseVal()->setValueAsString("-1");
+}
+
+SVGCircleElementImpl::~SVGCircleElementImpl()
+{
+ if(m_cx)
+ m_cx->deref();
+ if(m_cy)
+ m_cy->deref();
+ if(m_r)
+ m_r->deref();
+}
+
+SVGAnimatedLengthImpl *SVGCircleElementImpl::cx()
+{
+ return m_cx;
+}
+
+SVGAnimatedLengthImpl *SVGCircleElementImpl::cy()
+{
+ return m_cy;
+}
+
+SVGAnimatedLengthImpl *SVGCircleElementImpl::r()
+{
+ return m_r;
+}
+
+/*
+@namespace KSVG
+@begin SVGCircleElementImpl::s_hashTable 5
+ cx SVGCircleElementImpl::Cx DontDelete|ReadOnly
+ cy SVGCircleElementImpl::Cy DontDelete|ReadOnly
+ r SVGCircleElementImpl::R DontDelete|ReadOnly
+@end
+*/
+
+Value SVGCircleElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ KSVG_CHECK_ATTRIBUTE
+
+ switch(token)
+ {
+ case Cx:
+ if(!attributeMode)
+ return m_cx->cache(exec);
+ else
+ return Number(m_cx->baseVal()->value());
+ case Cy:
+ if(!attributeMode)
+ return m_cy->cache(exec);
+ else
+ return Number(m_cy->baseVal()->value());
+ case R:
+ if(!attributeMode)
+ return m_r->cache(exec);
+ else
+ return Number(m_r->baseVal()->value());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGCircleElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case Cx:
+ cx()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ case Cy:
+ cy()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ case R:
+ r()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ if(r()->baseVal()->value() < 0) // A negative value is an error
+ gotError(i18n("Negative value for attribute r of element <circle> is illegal"));
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+SVGRectImpl *SVGCircleElementImpl::getBBox()
+{
+ SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect();
+ ret->setX(m_cx->baseVal()->value() - m_r->baseVal()->value());
+ ret->setY(m_cy->baseVal()->value() - m_r->baseVal()->value());
+ ret->setWidth(m_r->baseVal()->value() * 2.0);
+ ret->setHeight(m_r->baseVal()->value() * 2.0);
+ return ret;
+}
+
+void SVGCircleElementImpl::setAttributes()
+{
+ SVGElementImpl::setAttributes();
+
+ // Spec: if not specified, effect is as if a value of "0" were specified
+ if(KSVG_TOKEN_NOT_PARSED(Cx))
+ KSVG_SET_ALT_ATTRIBUTE(Cx, "0")
+
+ // Spec: if not specified, effect is as if a value of "0" were specified
+ if(KSVG_TOKEN_NOT_PARSED(Cy))
+ KSVG_SET_ALT_ATTRIBUTE(Cy, "0")
+}
+
+void SVGCircleElementImpl::createItem(KSVGCanvas *c)
+{
+ if(!c)
+ c = ownerDoc()->canvas();
+
+ if(!m_item)
+ {
+ m_item = c->createCircle(this);
+ c->insert(m_item);
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGCircleElementImpl.h b/ksvg/impl/SVGCircleElementImpl.h
new file mode 100644
index 00000000..29e0df3f
--- /dev/null
+++ b/ksvg/impl/SVGCircleElementImpl.h
@@ -0,0 +1,84 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGCircleElementImpl_H
+#define SVGCircleElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGShapeImpl.h"
+#include "SVGTestsImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGLangSpaceImpl.h"
+#include "SVGTransformableImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+namespace KSVG
+{
+
+class SVGRectImpl;
+class SVGAnimatedLengthImpl;
+class SVGCircleElementImpl : public SVGShapeImpl,
+ public SVGTestsImpl,
+ public SVGLangSpaceImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGStylableImpl,
+ public SVGTransformableImpl
+{
+public:
+ SVGCircleElementImpl(DOM::ElementImpl *);
+ virtual ~SVGCircleElementImpl();
+
+ SVGAnimatedLengthImpl *cx();
+ SVGAnimatedLengthImpl *cy();
+ SVGAnimatedLengthImpl *r();
+
+ virtual void createItem(KSVGCanvas *c = 0);
+ virtual void setAttributes();
+
+ virtual SVGRectImpl *getBBox();
+
+private:
+ SVGAnimatedLengthImpl *m_cx;
+ SVGAnimatedLengthImpl *m_cy;
+ SVGAnimatedLengthImpl *m_r;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+ KSVG_BRIDGE
+
+ enum
+ {
+ // Properties
+ Cx, Cy, R
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+KSVG_REGISTER_ELEMENT(SVGCircleElementImpl, "circle")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGClipPathElementImpl.cc b/ksvg/impl/SVGClipPathElementImpl.cc
new file mode 100644
index 00000000..87b4d4ac
--- /dev/null
+++ b/ksvg/impl/SVGClipPathElementImpl.cc
@@ -0,0 +1,104 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGClipPathElement.h"
+#include "SVGClipPathElementImpl.h"
+#include "KSVGCanvas.h"
+#include "SVGDocumentImpl.h"
+#include "SVGAnimatedEnumerationImpl.h"
+
+using namespace KSVG;
+
+#include "SVGClipPathElementImpl.lut.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+
+SVGClipPathElementImpl::SVGClipPathElementImpl(DOM::ElementImpl *impl) : SVGContainerImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl(), SVGBBoxTarget()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_clipPathUnits = new SVGAnimatedEnumerationImpl();
+ m_clipPathUnits->ref();
+ m_clipPathUnits->setBaseVal(SVGClipPathElement::SVG_UNIT_TYPE_UNKNOWN);
+}
+
+SVGClipPathElementImpl::~SVGClipPathElementImpl()
+{
+ if(m_clipPathUnits)
+ m_clipPathUnits->deref();
+}
+
+SVGAnimatedEnumerationImpl *SVGClipPathElementImpl::clipPathUnits() const
+{
+ return m_clipPathUnits;
+}
+
+/*
+@namespace KSVG
+@begin SVGClipPathElementImpl::s_hashTable 2
+ clipPathUnits SVGClipPathElementImpl::ClipPathUnits DontDelete|ReadOnly
+@end
+*/
+
+Value SVGClipPathElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case ClipPathUnits:
+ return m_clipPathUnits->cache(exec);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGClipPathElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case ClipPathUnits:
+ if(value.toString(exec).qstring() == "objectBoundingBox")
+ m_clipPathUnits->setBaseVal(SVGClipPathElement::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
+ else
+ m_clipPathUnits->setBaseVal(SVGClipPathElement::SVG_UNIT_TYPE_USERSPACEONUSE);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+void SVGClipPathElementImpl::setAttributes()
+{
+ SVGElementImpl::setAttributes();
+
+ // Spec: if attribute not specified, use userSpaceOnUse
+ if(KSVG_TOKEN_NOT_PARSED(ClipPathUnits))
+ KSVG_SET_ALT_ATTRIBUTE(ClipPathUnits, "userSpaceOnUse")
+
+ if(!m_item)
+ m_item = ownerDoc()->canvas()->createClipPath(this);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGClipPathElementImpl.h b/ksvg/impl/SVGClipPathElementImpl.h
new file mode 100644
index 00000000..1e1879a9
--- /dev/null
+++ b/ksvg/impl/SVGClipPathElementImpl.h
@@ -0,0 +1,80 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGClipPathElementImpl_H
+#define SVGClipPathElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGTestsImpl.h"
+#include "SVGBBoxTarget.h"
+#include "SVGStylableImpl.h"
+#include "SVGLangSpaceImpl.h"
+#include "SVGContainerImpl.h"
+#include "SVGTransformableImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedEnumerationImpl;
+class SVGClipPathElementImpl : public SVGContainerImpl,
+ public SVGTestsImpl,
+ public SVGLangSpaceImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGStylableImpl,
+ public SVGTransformableImpl,
+ public SVGBBoxTarget
+{
+public:
+ SVGClipPathElementImpl(DOM::ElementImpl *);
+ virtual ~SVGClipPathElementImpl();
+
+ SVGAnimatedEnumerationImpl *clipPathUnits() const;
+
+ virtual void setAttributes();
+
+ virtual bool directRender() { return false; }
+
+private:
+ SVGAnimatedEnumerationImpl *m_clipPathUnits;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+ KSVG_BRIDGE
+
+ enum
+ {
+ // Properties
+ ClipPathUnits
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+KSVG_REGISTER_ELEMENT(SVGClipPathElementImpl, "clipPath")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGColorImpl.cc b/ksvg/impl/SVGColorImpl.cc
new file mode 100644
index 00000000..a01e1113
--- /dev/null
+++ b/ksvg/impl/SVGColorImpl.cc
@@ -0,0 +1,540 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option); any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include <qstringlist.h>
+
+#include "SVGColor.h"
+
+#include "SVGColorImpl.h"
+#include "SVGNumberImpl.h"
+#include "SVGICCColorImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGNumberListImpl.h"
+#include "SVGURIReferenceImpl.h"
+#include "SVGColorProfileElementImpl.h"
+
+using namespace KSVG;
+
+#include "SVGColorImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_cacheimpl.h"
+
+SVGColorImpl::SVGColorImpl(SVGElementImpl *object) : m_object(object)
+{
+ m_colorType = SVG_COLORTYPE_UNKNOWN;
+ m_iccColor = 0;
+}
+
+SVGColorImpl::SVGColorImpl(const SVGColorImpl &other) : DOM::DomShared()
+{
+ (*this) = other;
+}
+
+SVGColorImpl::~SVGColorImpl()
+{
+ if(m_iccColor)
+ m_iccColor->deref();
+}
+
+SVGColorImpl &SVGColorImpl::operator=(const SVGColorImpl &other)
+{
+ m_colorType = other.m_colorType;
+ m_rgbColor = other.m_rgbColor;
+
+ if(m_iccColor && other.m_iccColor)
+ *m_iccColor = *(other.m_iccColor);
+
+ return *this;
+}
+
+unsigned short SVGColorImpl::colorType() const
+{
+ return m_colorType;
+}
+
+DOM::RGBColor SVGColorImpl::rgbColor() const
+{
+ return m_rgbColor;
+}
+
+SVGICCColorImpl *SVGColorImpl::iccColor() const
+{
+ return m_iccColor;
+}
+
+void SVGColorImpl::setRGBColor(QColor color)
+{
+ m_colorType = SVG_COLORTYPE_RGBCOLOR;
+ m_rgbColor = DOM::RGBColor(color.rgb());
+}
+
+void SVGColorImpl::setRGBColor(int r, int g, int b)
+{
+ m_colorType = SVG_COLORTYPE_RGBCOLOR;
+ m_rgbColor = DOM::RGBColor(QColor(r, g, b).rgb());
+}
+
+void SVGColorImpl::setRGBColor(const DOM::DOMString &rgbColor)
+{
+ if(rgbColor == "aliceblue")
+ setRGBColor(240, 248, 255);
+ else if(rgbColor == "antiquewhite")
+ setRGBColor(250, 235, 215);
+ else if(rgbColor == "aqua")
+ setRGBColor(0, 255, 255);
+ else if(rgbColor == "aquamarine")
+ setRGBColor(127, 255, 212);
+ else if(rgbColor == "azure")
+ setRGBColor(240, 255, 255);
+ else if(rgbColor == "beige")
+ setRGBColor(245, 245, 220);
+ else if(rgbColor == "bisque")
+ setRGBColor(255, 228, 196);
+ else if(rgbColor == "black")
+ setRGBColor(0, 0, 0);
+ else if(rgbColor == "blanchedalmond")
+ setRGBColor(255, 235, 205);
+ else if(rgbColor == "blue")
+ setRGBColor(0, 0, 255);
+ else if(rgbColor == "blueviolet")
+ setRGBColor(138, 43, 226);
+ else if(rgbColor == "brown")
+ setRGBColor(165, 42, 42);
+ else if(rgbColor == "burlywood")
+ setRGBColor(222, 184, 135);
+ else if(rgbColor == "cadetblue")
+ setRGBColor(95, 158, 160);
+ else if(rgbColor == "chartreuse")
+ setRGBColor(127, 255, 0);
+ else if(rgbColor == "chocolate")
+ setRGBColor(210, 105, 30);
+ else if(rgbColor == "coral")
+ setRGBColor(255, 127, 80);
+ else if(rgbColor == "cornflowerblue")
+ setRGBColor(100, 149, 237);
+ else if(rgbColor == "cornsilk")
+ setRGBColor(255, 248, 220);
+ else if(rgbColor == "crimson")
+ setRGBColor(220, 20, 60);
+ else if(rgbColor == "cyan")
+ setRGBColor(0, 255, 255);
+ else if(rgbColor == "darkblue")
+ setRGBColor(0, 0, 139);
+ else if(rgbColor == "darkcyan")
+ setRGBColor(0, 139, 139);
+ else if(rgbColor == "darkgoldenrod")
+ setRGBColor(184, 134, 11);
+ else if(rgbColor == "darkgray")
+ setRGBColor(169, 169, 169);
+ else if(rgbColor == "darkgrey")
+ setRGBColor(169, 169, 169);
+ else if(rgbColor == "darkgreen")
+ setRGBColor(0, 100, 0);
+ else if(rgbColor == "darkkhaki")
+ setRGBColor(189, 183, 107);
+ else if(rgbColor == "darkmagenta")
+ setRGBColor(139, 0, 139);
+ else if(rgbColor == "darkolivegreen")
+ setRGBColor(85, 107, 47);
+ else if(rgbColor == "darkorange")
+ setRGBColor(255, 140, 0);
+ else if(rgbColor == "darkorchid")
+ setRGBColor(153, 50, 204);
+ else if(rgbColor == "darkred")
+ setRGBColor(139, 0, 0);
+ else if(rgbColor == "darksalmon")
+ setRGBColor(233, 150, 122);
+ else if(rgbColor == "darkseagreen")
+ setRGBColor(143, 188, 143);
+ else if(rgbColor == "darkslateblue")
+ setRGBColor(72, 61, 139);
+ else if(rgbColor == "darkslategray")
+ setRGBColor(47, 79, 79);
+ else if(rgbColor == "darkslategrey")
+ setRGBColor(47, 79, 79);
+ else if(rgbColor == "darkturquoise")
+ setRGBColor(0, 206, 209);
+ else if(rgbColor == "darkviolet")
+ setRGBColor(148, 0, 211);
+ else if(rgbColor == "deeppink")
+ setRGBColor(255, 20, 147);
+ else if(rgbColor == "deepskyblue")
+ setRGBColor(0, 191, 255);
+ else if(rgbColor == "dimgray")
+ setRGBColor(105, 105, 105);
+ else if(rgbColor == "dimgrey")
+ setRGBColor(105, 105, 105);
+ else if(rgbColor == "dodgerblue")
+ setRGBColor(30, 144, 255);
+ else if(rgbColor == "firebrick")
+ setRGBColor(178, 34, 34);
+ else if(rgbColor == "floralwhite")
+ setRGBColor(255, 250, 240);
+ else if(rgbColor == "forestgreen")
+ setRGBColor(34, 139, 34);
+ else if(rgbColor == "fuchsia")
+ setRGBColor(255, 0, 255);
+ else if(rgbColor == "gainsboro")
+ setRGBColor(220, 220, 220);
+ else if(rgbColor == "ghostwhite")
+ setRGBColor(248, 248, 255);
+ else if(rgbColor == "gold")
+ setRGBColor(255, 215, 0);
+ else if(rgbColor == "goldenrod")
+ setRGBColor(218, 165, 32);
+ else if(rgbColor == "gray")
+ setRGBColor(128, 128, 128);
+ else if(rgbColor == "grey")
+ setRGBColor(128, 128, 128);
+ else if(rgbColor == "green")
+ setRGBColor(0, 128, 0);
+ else if(rgbColor == "greenyellow")
+ setRGBColor(173, 255, 47);
+ else if(rgbColor == "honeydew")
+ setRGBColor(240, 255, 240);
+ else if(rgbColor == "hotpink")
+ setRGBColor(255, 105, 180);
+ else if(rgbColor == "indianred")
+ setRGBColor(205, 92, 92);
+ else if(rgbColor == "indigo")
+ setRGBColor(75, 0, 130);
+ else if(rgbColor == "ivory")
+ setRGBColor(255, 255, 240);
+ else if(rgbColor == "khaki")
+ setRGBColor(240, 230, 140);
+ else if(rgbColor == "lavender")
+ setRGBColor(230, 230, 250);
+ else if(rgbColor == "lavenderblush")
+ setRGBColor(255, 240, 245);
+ else if(rgbColor == "lawngreen")
+ setRGBColor(124, 252, 0);
+ else if(rgbColor == "lemonchiffon")
+ setRGBColor(255, 250, 205);
+ else if(rgbColor == "lightblue")
+ setRGBColor(173, 216, 230);
+ else if(rgbColor == "lightcoral")
+ setRGBColor(240, 128, 128);
+ else if(rgbColor == "lightcyan")
+ setRGBColor(224, 255, 255);
+ else if(rgbColor == "lightgoldenrodyellow")
+ setRGBColor(250, 250, 210);
+ else if(rgbColor == "lightgray")
+ setRGBColor(211, 211, 211);
+ else if(rgbColor == "lightgrey")
+ setRGBColor(211, 211, 211);
+ else if(rgbColor == "lightgreen")
+ setRGBColor(144, 238, 144);
+ else if(rgbColor == "lightpink")
+ setRGBColor(255, 182, 193);
+ else if(rgbColor == "lightsalmon")
+ setRGBColor(255, 160, 122);
+ else if(rgbColor == "lightseagreen")
+ setRGBColor(32, 178, 170);
+ else if(rgbColor == "lightskyblue")
+ setRGBColor(135, 206, 250);
+ else if(rgbColor == "lightslategray")
+ setRGBColor(119, 136, 153);
+ else if(rgbColor == "lightslategrey")
+ setRGBColor(119, 136, 153);
+ else if(rgbColor == "lightsteelblue")
+ setRGBColor(176, 196, 222);
+ else if(rgbColor == "lightyellow")
+ setRGBColor(255, 255, 224);
+ else if(rgbColor == "lime")
+ setRGBColor(0, 255, 0);
+ else if(rgbColor == "limegreen")
+ setRGBColor(50, 205, 50);
+ else if(rgbColor == "linen")
+ setRGBColor(250, 240, 230);
+ else if(rgbColor == "magenta")
+ setRGBColor(255, 0, 255);
+ else if(rgbColor == "maroon")
+ setRGBColor(128, 0, 0);
+ else if(rgbColor == "mediumaquamarine")
+ setRGBColor(102, 205, 170);
+ else if(rgbColor == "mediumblue")
+ setRGBColor(0, 0, 205);
+ else if(rgbColor == "mediumorchid")
+ setRGBColor(186, 85, 211);
+ else if(rgbColor == "mediumpurple")
+ setRGBColor(147, 112, 219);
+ else if(rgbColor == "mediumseagreen")
+ setRGBColor(60, 179, 113);
+ else if(rgbColor == "mediumslateblue")
+ setRGBColor(123, 104, 238);
+ else if(rgbColor == "mediumspringgreen")
+ setRGBColor(0, 250, 154);
+ else if(rgbColor == "mediumturquoise")
+ setRGBColor(72, 209, 204);
+ else if(rgbColor == "mediumvioletred")
+ setRGBColor(199, 21, 133);
+ else if(rgbColor == "midnightblue")
+ setRGBColor(25, 25, 112);
+ else if(rgbColor == "mintcream")
+ setRGBColor(245, 255, 250);
+ else if(rgbColor == "mistyrose")
+ setRGBColor(255, 228, 225);
+ else if(rgbColor == "moccasin")
+ setRGBColor(255, 228, 181);
+ else if(rgbColor == "navajowhite")
+ setRGBColor(255, 222, 173);
+ else if(rgbColor == "navy")
+ setRGBColor(0, 0, 128);
+ else if(rgbColor == "oldlace")
+ setRGBColor(253, 245, 230);
+ else if(rgbColor == "olive")
+ setRGBColor(128, 128, 0);
+ else if(rgbColor == "olivedrab")
+ setRGBColor(107, 142, 35);
+ else if(rgbColor == "orange")
+ setRGBColor(255, 165, 0);
+ else if(rgbColor == "orangered")
+ setRGBColor(255, 69, 0);
+ else if(rgbColor == "orchid")
+ setRGBColor(218, 112, 214);
+ else if(rgbColor == "palegoldenrod")
+ setRGBColor(238, 232, 170);
+ else if(rgbColor == "palegreen")
+ setRGBColor(152, 251, 152);
+ else if(rgbColor == "paleturquoise")
+ setRGBColor(175, 238, 238);
+ else if(rgbColor == "palevioletred")
+ setRGBColor(219, 112, 147);
+ else if(rgbColor == "papayawhip")
+ setRGBColor(255, 239, 213);
+ else if(rgbColor == "peachpuff")
+ setRGBColor(255, 218, 185);
+ else if(rgbColor == "peru")
+ setRGBColor(205, 133, 63);
+ else if(rgbColor == "pink")
+ setRGBColor(255, 192, 203);
+ else if(rgbColor == "plum")
+ setRGBColor(221, 160, 221);
+ else if(rgbColor == "powderblue")
+ setRGBColor(176, 224, 230);
+ else if(rgbColor == "purple")
+ setRGBColor(128, 0, 128);
+ else if(rgbColor == "red")
+ setRGBColor(255, 0, 0);
+ else if(rgbColor == "rosybrown")
+ setRGBColor(188, 143, 143);
+ else if(rgbColor == "royalblue")
+ setRGBColor(65, 105, 225);
+ else if(rgbColor == "saddlebrown")
+ setRGBColor(139, 69, 19);
+ else if(rgbColor == "salmon")
+ setRGBColor(250, 128, 114);
+ else if(rgbColor == "sandybrown")
+ setRGBColor(244, 164, 96);
+ else if(rgbColor == "seagreen")
+ setRGBColor(46, 139, 87);
+ else if(rgbColor == "seashell")
+ setRGBColor(255, 245, 238);
+ else if(rgbColor == "sienna")
+ setRGBColor(160, 82, 45);
+ else if(rgbColor == "silver")
+ setRGBColor(192, 192, 192);
+ else if(rgbColor == "skyblue")
+ setRGBColor(135, 206, 235);
+ else if(rgbColor == "slateblue")
+ setRGBColor(106, 90, 205);
+ else if(rgbColor == "slategray")
+ setRGBColor(112, 128, 144);
+ else if(rgbColor == "slategrey")
+ setRGBColor(112, 128, 144);
+ else if(rgbColor == "snow")
+ setRGBColor(255, 250, 250);
+ else if(rgbColor == "springgreen")
+ setRGBColor(0, 255, 127);
+ else if(rgbColor == "steelblue")
+ setRGBColor(70, 130, 180);
+ else if(rgbColor == "tan")
+ setRGBColor(210, 180, 140);
+ else if(rgbColor == "teal")
+ setRGBColor(0, 128, 128);
+ else if(rgbColor == "thistle")
+ setRGBColor(216, 191, 216);
+ else if(rgbColor == "tomato")
+ setRGBColor(255, 99, 71);
+ else if(rgbColor == "turquoise")
+ setRGBColor(64, 224, 208);
+ else if(rgbColor == "violet")
+ setRGBColor(238, 130, 238);
+ else if(rgbColor == "wheat")
+ setRGBColor(245, 222, 179);
+ else if(rgbColor == "white")
+ setRGBColor(255, 255, 255);
+ else if(rgbColor == "whitesmoke")
+ setRGBColor(245, 245, 245);
+ else if(rgbColor == "yellow")
+ setRGBColor(255, 255, 0);
+ else if(rgbColor == "yellowgreen")
+ setRGBColor(154, 205, 50);
+}
+
+void SVGColorImpl::setRGBColorICCColor(const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor)
+{
+ QColor color;
+
+ QString content = iccColor.string().right(iccColor.string().length() - 10);
+ QString iccTarget = content.mid(0, content.find(','));
+
+ QStringList colors = QStringList::split(',', content);
+ QString r = colors[1];
+ QString g = colors[2];
+ QString b = colors[3].left(colors[3].length() - 1);
+
+ iccTarget = SVGURIReferenceImpl::getTarget(iccTarget);
+
+ SVGColorProfileElementImpl *handle = 0;
+ if(m_object)
+ handle = static_cast<SVGColorProfileElementImpl *>(dynamic_cast<SVGElementImpl *>(m_object)->ownerDoc()->rootElement()->getElementById(iccTarget));
+
+ if(iccTarget.isEmpty() || !handle)
+ {
+ color.setNamedColor(rgbColor.string().stripWhiteSpace());
+ setRGBColor(color);
+ }
+ else
+ {
+ color.setRgb(handle->correctPixel(r.toFloat() * 257, g.toFloat() * 257, b.toFloat() * 257));
+ setRGBColor(color);
+
+ m_colorType = SVG_COLORTYPE_RGBCOLOR_ICCCOLOR;
+
+ if(!m_iccColor)
+ {
+ m_iccColor = new SVGICCColorImpl();
+ m_iccColor->ref();
+ }
+
+ m_iccColor->setColorProfile(DOM::DOMString(content));
+
+ SVGNumberImpl *rnumber = SVGSVGElementImpl::createSVGNumber();
+ rnumber->setValue(r.toFloat());
+
+ SVGNumberImpl *gnumber = SVGSVGElementImpl::createSVGNumber();
+ gnumber->setValue(g.toFloat());
+
+ SVGNumberImpl *bnumber = SVGSVGElementImpl::createSVGNumber();
+ bnumber->setValue(b.toFloat());
+
+ m_iccColor->colors()->clear();
+ m_iccColor->colors()->appendItem(bnumber);
+ m_iccColor->colors()->appendItem(gnumber);
+ m_iccColor->colors()->appendItem(rnumber);
+ }
+}
+
+void SVGColorImpl::setColor(unsigned short colorType, const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor)
+{
+ m_colorType = colorType;
+
+ if(m_colorType == SVG_COLORTYPE_UNKNOWN || m_colorType == SVG_COLORTYPE_CURRENTCOLOR)
+ return;
+
+ setRGBColorICCColor(rgbColor, iccColor);
+}
+
+// Ecma stuff
+/*
+@namespace KSVG
+@begin SVGColorImpl::s_hashTable 5
+ colorType SVGColorImpl::ColorType DontDelete|ReadOnly
+ RGBColor SVGColorImpl::RGBColor DontDelete|ReadOnly
+ ICCColor SVGColorImpl::ICCColor DontDelete|ReadOnly
+@end
+@namespace KSVG
+@begin SVGColorImplProto::s_hashTable 5
+ setRGBColor SVGColorImpl::SetRGBColor DontDelete|Function 1
+ setRGBColorICCColor SVGColorImpl::SetRGBColorICCColor DontDelete|Function 2
+ setColor SVGColorImpl::SetColor DontDelete|Function 3
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGColor", SVGColorImplProto, SVGColorImplProtoFunc)
+
+Value SVGColorImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case ColorType:
+ return Number(colorType());
+#ifdef __GNUC__
+#warning FIXME bridge stuff
+#endif
+ case RGBColor:
+ return Undefined();
+ case ICCColor:
+ return m_iccColor->cache(exec);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+Value SVGColorImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGColorImpl)
+
+ switch(id)
+ {
+ case SVGColorImpl::SetRGBColor:
+ obj->setRGBColor(args[0].toString(exec).string());
+ break;
+ case SVGColorImpl::SetRGBColorICCColor:
+ obj->setRGBColorICCColor(args[0].toString(exec).string(), args[1].toString(exec).string());
+ break;
+ case SVGColorImpl::SetColor:
+ obj->setColor(static_cast<unsigned short>(args[0].toNumber(exec)), args[1].toString(exec).string(), args[2].toString(exec).string());
+ break;
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return Undefined();
+}
+
+/*
+@namespace KSVG
+@begin SVGColorImplConstructor::s_hashTable 5
+ SVG_COLORTYPE_UNKNOWN KSVG::SVG_COLORTYPE_UNKNOWN DontDelete|ReadOnly
+ SVG_COLORTYPE_RGBCOLOR KSVG::SVG_COLORTYPE_RGBCOLOR DontDelete|ReadOnly
+ SVG_COLORTYPE_RGBCOLOR_ICCCOLOR KSVG::SVG_COLORTYPE_RGBCOLOR_ICCCOLOR DontDelete|ReadOnly
+ SVG_COLORTYPE_CURRENTCOLOR KSVG::SVG_COLORTYPE_CURRENTCOLOR DontDelete|ReadOnly
+@end
+*/
+
+Value SVGColorImplConstructor::getValueProperty(ExecState *, int token) const
+{
+ return Number(token);
+}
+
+Value KSVG::getSVGColorImplConstructor(ExecState *exec)
+{
+ return cacheGlobalBridge<SVGColorImplConstructor>(exec, "[[svgcolor.constructor]]");
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGColorImpl.h b/ksvg/impl/SVGColorImpl.h
new file mode 100644
index 00000000..d49c6f82
--- /dev/null
+++ b/ksvg/impl/SVGColorImpl.h
@@ -0,0 +1,94 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGColorImpl_H
+#define SVGColorImpl_H
+
+#include <dom/dom_misc.h>
+#include <dom/css_value.h>
+#include <dom/dom_string.h>
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+class SVGElementImpl;
+class SVGICCColorImpl;
+class SVGColorImpl : public DOM::DomShared
+{
+public:
+ SVGColorImpl(SVGElementImpl *object);
+ SVGColorImpl(const SVGColorImpl &);
+ virtual ~SVGColorImpl();
+
+ SVGColorImpl &operator=(const SVGColorImpl &);
+
+ unsigned short colorType() const;
+
+ DOM::RGBColor rgbColor() const;
+ SVGICCColorImpl *iccColor() const;
+
+ virtual void setRGBColor(const DOM::DOMString &rgbColor);
+ virtual void setRGBColor(int r, int g, int b);
+ virtual void setRGBColor(QColor color);
+ virtual void setRGBColorICCColor(const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor);
+ virtual void setColor(unsigned short colorType, const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor);
+
+private:
+ unsigned short m_colorType;
+ DOM::RGBColor m_rgbColor;
+ SVGICCColorImpl *m_iccColor;
+ SVGElementImpl *m_object;
+
+public:
+ KSVG_BASECLASS_GET
+
+ enum
+ {
+ // Properties
+ ColorType, RGBColor, ICCColor,
+ // Functions
+ SetRGBColor, SetRGBColorICCColor, SetColor
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+class SVGColorImplConstructor : public KJS::ObjectImp
+{
+public:
+ SVGColorImplConstructor(KJS::ExecState *) { }
+ KJS::Value getValueProperty(KJS::ExecState *, int token) const;
+
+ // no put - all read-only
+ KSVG_GET
+};
+
+KJS::Value getSVGColorImplConstructor(KJS::ExecState *exec);
+
+}
+
+KSVG_DEFINE_PROTOTYPE(SVGColorImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGColorImplProtoFunc, SVGColorImpl)
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGColorProfileElementImpl.cc b/ksvg/impl/SVGColorProfileElementImpl.cc
new file mode 100644
index 00000000..f898188b
--- /dev/null
+++ b/ksvg/impl/SVGColorProfileElementImpl.cc
@@ -0,0 +1,271 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kurl.h>
+#include <kdebug.h>
+#include <kio/netaccess.h>
+
+#include <qimage.h>
+
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+
+#include "SVGRenderingIntent.h"
+
+#include "SVGAnimatedStringImpl.h"
+#include "SVGColorProfileElementImpl.h"
+
+using namespace KSVG;
+
+#include "SVGColorProfileElementImpl.lut.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+
+SVGColorProfileElementImpl::SVGColorProfileElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGURIReferenceImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_loaded = false;
+
+ // Spec: Default value 'auto', if not overwritten later
+ m_renderingIntent = RENDERING_INTENT_AUTO;
+}
+
+SVGColorProfileElementImpl::~SVGColorProfileElementImpl()
+{
+ if(m_loaded)
+ closeColorProfile();
+}
+
+/*
+@namespace KSVG
+@begin SVGColorProfileElementImpl::s_hashTable 5
+ name SVGColorProfileElementImpl::Name DontDelete|ReadOnly
+ href SVGColorProfileElementImpl::Href DontDelete|ReadOnly
+ rendering-intent SVGColorProfileElementImpl::RenderingIntent DontDelete|ReadOnly
+@end
+*/
+
+Value SVGColorProfileElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case Name:
+ return String(m_name);
+ case Href:
+ return href()->cache(exec);
+ case RenderingIntent:
+ return Number(m_renderingIntent);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGColorProfileElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case Name:
+ m_name = value.toString(exec).string();
+ ownerDoc()->rootElement()->addToIdMap(m_name.string(), this);
+ break;
+ case Href:
+ href()->setBaseVal(value.toString(exec).string());
+ break;
+ case RenderingIntent:
+ {
+ QString compare = value.toString(exec).qstring().lower();
+
+ if(compare == "perceptual")
+ m_renderingIntent = RENDERING_INTENT_PERCEPTUAL;
+ else if(compare == "relative-colorimetric")
+ m_renderingIntent = RENDERING_INTENT_RELATIVE_COLORIMETRIC;
+ else if(compare == "saturation")
+ m_renderingIntent = RENDERING_INTENT_SATURATION;
+ else if(compare == "absolute-colorimetric")
+ m_renderingIntent = RENDERING_INTENT_ABSOLUTE_COLORIMETRIC;
+ else
+ m_renderingIntent = RENDERING_INTENT_AUTO;
+ break;
+ }
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+void SVGColorProfileElementImpl::setLocal(const DOM::DOMString &local)
+{
+ m_local = local;
+}
+
+DOM::DOMString SVGColorProfileElementImpl::local() const
+{
+ return m_local;
+}
+
+void SVGColorProfileElementImpl::setName(const DOM::DOMString &name)
+{
+ m_name = name;
+}
+
+DOM::DOMString SVGColorProfileElementImpl::name() const
+{
+ return m_name;
+}
+
+void SVGColorProfileElementImpl::setRenderingIntent(unsigned short renderingIntent)
+{
+ m_renderingIntent = renderingIntent;
+}
+
+unsigned short SVGColorProfileElementImpl::renderingIntent() const
+{
+ return m_renderingIntent;
+}
+
+bool SVGColorProfileElementImpl::canLoad()
+{
+ QString open;
+ bool temp;
+ return canLoad(false, temp, open, true);
+}
+
+bool SVGColorProfileElementImpl::canLoad(bool remote, bool &tempFile, QString &open, bool verbose)
+{
+ KURL file;
+
+ if(!KURL::isRelativeURL(href()->baseVal().string()))
+ file = KURL(href()->baseVal().string());
+ else
+ file = KURL(ownerDoc()->baseUrl(), href()->baseVal().string());
+
+ if(file.path().isEmpty())
+ {
+ if(verbose)
+ kdDebug() << "Couldn't load color profile " << file.path() << "!" << endl;
+
+ return false;
+ }
+
+ if(file.isLocalFile())
+ {
+ open = file.path();
+
+ if(!QFile::exists(open))
+ {
+ if(verbose)
+ kdDebug() << "Couldn't load color profile " << file.path() << "! It does not exist." << endl;
+
+ return false;
+ }
+ }
+ else
+ {
+ if(remote)
+ {
+ if(KIO::NetAccess::download(file, open, 0))
+ tempFile = true;
+ }
+ }
+
+ return true;
+}
+
+bool SVGColorProfileElementImpl::loadColorProfile()
+{
+ QString open;
+ bool tempFile = false;
+
+ if(!canLoad(true, tempFile, open, false))
+ return false;
+
+ m_hInput = cmsOpenProfileFromFile(open.latin1(), "r");
+ m_hOutput = cmsCreate_sRGBProfile();
+
+ unsigned int dwIn = BYTES_SH(2) | CHANNELS_SH(_cmsChannelsOf(m_inputColorSpace));
+ unsigned int dwOut = BYTES_SH(2) | CHANNELS_SH(_cmsChannelsOf(m_outputColorSpace));
+
+ if(m_renderingIntent != RENDERING_INTENT_AUTO)
+ m_hTrans = cmsCreateTransform(m_hInput, dwIn, m_hOutput, dwOut, m_renderingIntent - 2, cmsFLAGS_NOTPRECALC);
+ else
+ m_hTrans = cmsCreateTransform(m_hInput, dwIn, m_hOutput, dwOut, cmsTakeRenderingIntent(m_hInput), cmsFLAGS_NOTPRECALC);
+
+ m_inputColorSpace = cmsGetColorSpace(m_hInput);
+ m_outputColorSpace = cmsGetColorSpace(m_hOutput);
+ m_loaded = true;
+
+ if(tempFile)
+ KIO::NetAccess::removeTempFile(open);
+
+ return true;
+}
+
+void SVGColorProfileElementImpl::closeColorProfile()
+{
+ cmsDeleteTransform(m_hTrans);
+ cmsCloseProfile(m_hInput);
+}
+
+QRgb SVGColorProfileElementImpl::correctPixel(float r, float g, float b)
+{
+ if(!m_loaded)
+ {
+ if(!loadColorProfile())
+ return qRgb(0, 0, 0);
+ }
+
+ unsigned short input[MAXCHANNELS], output[MAXCHANNELS];
+
+ input[0] = ((unsigned int) r) * 257;
+ input[1] = ((unsigned int) g) * 257;
+ input[2] = ((unsigned int) b) * 257;
+
+ cmsDoTransform(m_hTrans, input, output, 1);
+
+ if(m_outputColorSpace == icSigRgbData)
+ return qRgb(output[0] / 257, output[1] / 257, output[2] / 257);
+
+ return qRgb(0, 0, 0);
+}
+
+QImage *SVGColorProfileElementImpl::correctImage(QImage *input)
+{
+ if(!canLoad())
+ return input;
+
+ for(int y = 0; y < input->height(); y++)
+ {
+ for(int x = 0; x < input->width(); x++)
+ {
+ QRgb pixel = input->pixel(x, y);
+ input->setPixel(x, y, correctPixel(qRed(pixel), qGreen(pixel), qBlue(pixel)));
+ }
+ }
+
+ return input;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGColorProfileElementImpl.h b/ksvg/impl/SVGColorProfileElementImpl.h
new file mode 100644
index 00000000..2f735f03
--- /dev/null
+++ b/ksvg/impl/SVGColorProfileElementImpl.h
@@ -0,0 +1,100 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGColorProfileElementImpl_H
+#define SVGColorProfileElementImpl_H
+
+#include <dom/dom_string.h>
+
+// Provided by configure checks....
+#include <config.h>
+#undef QT_VERSION // Needed for 1.08 *grml*
+#include LCMS_HEADER
+
+#include "SVGElementImpl.h"
+#include "SVGURIReferenceImpl.h"
+
+#include "ksvg_lookup.h"
+
+class QImage;
+
+namespace KSVG
+{
+
+class SVGColorProfileElementImpl : public SVGElementImpl,
+ public SVGURIReferenceImpl
+{
+public:
+ SVGColorProfileElementImpl(DOM::ElementImpl *);
+ virtual ~SVGColorProfileElementImpl();
+
+ void setLocal(const DOM::DOMString &local);
+ DOM::DOMString local() const;
+
+ void setName(const DOM::DOMString &name);
+ DOM::DOMString name() const;
+
+ void setRenderingIntent(unsigned short renderingIntent);
+ unsigned short renderingIntent() const;
+
+ QImage *correctImage(QImage *input);
+ QRgb correctPixel(float r, float g, float b);
+
+private:
+ bool loadColorProfile();
+ void closeColorProfile();
+
+ bool canLoad();
+ bool canLoad(bool remote, bool &tempFile, QString &open, bool verbose);
+
+ DOM::DOMString m_local;
+ DOM::DOMString m_name;
+ unsigned short m_renderingIntent;
+
+ bool m_loaded;
+
+ cmsHPROFILE m_hInput, m_hOutput;
+ cmsHTRANSFORM m_hTrans;
+ int m_intent;
+
+ icColorSpaceSignature m_inputColorSpace, m_outputColorSpace;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+ KSVG_BRIDGE
+
+ enum
+ {
+ // Properties
+ Name, Href, RenderingIntent
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+KSVG_REGISTER_ELEMENT(SVGColorProfileElementImpl, "color-profile")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGColorProfileRuleImpl.cc b/ksvg/impl/SVGColorProfileRuleImpl.cc
new file mode 100644
index 00000000..3cfca560
--- /dev/null
+++ b/ksvg/impl/SVGColorProfileRuleImpl.cc
@@ -0,0 +1,63 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGColorProfileRuleImpl.h"
+
+using namespace KSVG;
+
+SVGColorProfileRuleImpl::SVGColorProfileRuleImpl() : SVGCSSRuleImpl()
+{
+}
+
+SVGColorProfileRuleImpl::~SVGColorProfileRuleImpl()
+{
+}
+
+void SVGColorProfileRuleImpl::setSrc(const DOM::DOMString &src)
+{
+ m_src = src;
+}
+
+DOM::DOMString SVGColorProfileRuleImpl::src() const
+{
+ return m_src;
+}
+
+void SVGColorProfileRuleImpl::setName(const DOM::DOMString &name)
+{
+ m_name = name;
+}
+
+DOM::DOMString SVGColorProfileRuleImpl::name() const
+{
+ return m_name;
+}
+
+void SVGColorProfileRuleImpl::setRenderingIntent(unsigned short renderingIntent)
+{
+ m_renderingIntent = renderingIntent;
+}
+
+unsigned short SVGColorProfileRuleImpl::renderingIntent() const
+{
+ return m_renderingIntent;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGColorProfileRuleImpl.h b/ksvg/impl/SVGColorProfileRuleImpl.h
new file mode 100644
index 00000000..976a76a8
--- /dev/null
+++ b/ksvg/impl/SVGColorProfileRuleImpl.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGColorProfileRuleImpl_H
+#define SVGColorProfileRuleImpl_H
+
+#include <dom/dom_string.h>
+
+#include "SVGCSSRuleImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGColorProfileRuleImpl : public SVGCSSRuleImpl
+{
+public:
+ SVGColorProfileRuleImpl();
+ virtual ~SVGColorProfileRuleImpl();
+
+ void setSrc(const DOM::DOMString &src);
+ DOM::DOMString src() const;
+
+ void setName(const DOM::DOMString &name);
+ DOM::DOMString name() const;
+
+ void setRenderingIntent(unsigned short renderingIntent);
+ unsigned short renderingIntent() const;
+
+private:
+ DOM::DOMString m_src;
+ DOM::DOMString m_name;
+ unsigned short m_renderingIntent;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGComponentTransferFunctionElementImpl.cc b/ksvg/impl/SVGComponentTransferFunctionElementImpl.cc
new file mode 100644
index 00000000..0db14aae
--- /dev/null
+++ b/ksvg/impl/SVGComponentTransferFunctionElementImpl.cc
@@ -0,0 +1,105 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedNumberImpl.h"
+#include "SVGAnimatedNumberListImpl.h"
+#include "SVGAnimatedEnumerationImpl.h"
+#include "SVGComponentTransferFunctionElementImpl.h"
+
+using namespace KSVG;
+
+SVGComponentTransferFunctionElementImpl::SVGComponentTransferFunctionElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl)
+{
+ m_type = new SVGAnimatedEnumerationImpl();
+ m_type->ref();
+
+ m_tableValues = new SVGAnimatedNumberListImpl();
+ m_tableValues->ref();
+
+ m_slope = new SVGAnimatedNumberImpl();
+ m_slope->ref();
+
+ m_intercept = new SVGAnimatedNumberImpl();
+ m_intercept->ref();
+
+ m_amplitude = new SVGAnimatedNumberImpl();
+ m_amplitude->ref();
+
+ m_exponent = new SVGAnimatedNumberImpl();
+ m_exponent->ref();
+
+ m_offset = new SVGAnimatedNumberImpl();
+ m_offset->ref();
+}
+
+SVGComponentTransferFunctionElementImpl::~SVGComponentTransferFunctionElementImpl()
+{
+ if(m_type)
+ m_type->deref();
+ if(m_tableValues)
+ m_tableValues->deref();
+ if(m_slope)
+ m_slope->deref();
+ if(m_intercept)
+ m_intercept->deref();
+ if(m_amplitude)
+ m_amplitude->deref();
+ if(m_exponent)
+ m_exponent->deref();
+ if(m_offset)
+ m_offset->deref();
+}
+
+SVGAnimatedEnumerationImpl *SVGComponentTransferFunctionElementImpl::type() const
+{
+ return m_type;
+}
+
+SVGAnimatedNumberListImpl *SVGComponentTransferFunctionElementImpl::tableValues() const
+{
+ return m_tableValues;
+}
+
+SVGAnimatedNumberImpl *SVGComponentTransferFunctionElementImpl::slope() const
+{
+ return m_slope;
+}
+
+SVGAnimatedNumberImpl *SVGComponentTransferFunctionElementImpl::intercept() const
+{
+ return m_intercept;
+}
+
+SVGAnimatedNumberImpl *SVGComponentTransferFunctionElementImpl::amplitude() const
+{
+ return m_amplitude;
+}
+
+SVGAnimatedNumberImpl *SVGComponentTransferFunctionElementImpl::exponent() const
+{
+ return m_exponent;
+}
+
+SVGAnimatedNumberImpl *SVGComponentTransferFunctionElementImpl::offset() const
+{
+ return m_offset;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGComponentTransferFunctionElementImpl.h b/ksvg/impl/SVGComponentTransferFunctionElementImpl.h
new file mode 100644
index 00000000..e277d462
--- /dev/null
+++ b/ksvg/impl/SVGComponentTransferFunctionElementImpl.h
@@ -0,0 +1,66 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGComponentTransferFunctionElementImpl_H
+#define SVGComponentTransferFunctionElementImpl_H
+
+#include "SVGElementImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedNumberImpl;
+class SVGAnimatedNumberListImpl;
+class SVGAnimatedEnumerationImpl;
+class SVGComponentTransferFunctionElementImpl : public SVGElementImpl
+{
+public:
+ SVGComponentTransferFunctionElementImpl(DOM::ElementImpl *);
+ virtual ~SVGComponentTransferFunctionElementImpl();
+
+ SVGAnimatedEnumerationImpl *type() const;
+ SVGAnimatedNumberListImpl *tableValues() const;
+ SVGAnimatedNumberImpl *slope() const;
+ SVGAnimatedNumberImpl *intercept() const;
+ SVGAnimatedNumberImpl *amplitude() const;
+ SVGAnimatedNumberImpl *exponent() const;
+ SVGAnimatedNumberImpl *offset() const;
+
+private:
+ SVGAnimatedEnumerationImpl *m_type;
+ SVGAnimatedNumberListImpl *m_tableValues;
+ SVGAnimatedNumberImpl *m_slope;
+ SVGAnimatedNumberImpl *m_intercept;
+ SVGAnimatedNumberImpl *m_amplitude;
+ SVGAnimatedNumberImpl *m_exponent;
+ SVGAnimatedNumberImpl *m_offset;
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGContainerImpl.cc b/ksvg/impl/SVGContainerImpl.cc
new file mode 100644
index 00000000..88fb87a8
--- /dev/null
+++ b/ksvg/impl/SVGContainerImpl.cc
@@ -0,0 +1,135 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGRectImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGContainerImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "kdebug.h"
+
+using namespace KSVG;
+
+SVGContainerImpl::SVGContainerImpl(DOM::ElementImpl *impl) : SVGShapeImpl(impl)
+{
+}
+
+SVGContainerImpl::~SVGContainerImpl()
+{
+}
+
+SVGRectImpl *SVGContainerImpl::getBBox()
+{
+ // just get the union of the children bboxes
+ QRect rect;
+ DOM::Node node = firstChild();
+ for(; !node.isNull(); node = node.nextSibling())
+ {
+ SVGElementImpl *elem = ownerDoc()->getElementFromHandle(node.handle());
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(elem);
+ SVGTestsImpl *tests = dynamic_cast<SVGTestsImpl *>(elem);
+ SVGStylableImpl *style = dynamic_cast<SVGStylableImpl *>(elem);
+
+ bool ok = tests ? tests->ok() : true;
+
+ if(shape && style && ok && style->getVisible() && style->getDisplay())
+ {
+ SVGRectImpl *current = shape->getBBox();
+ rect = rect.unite(current->qrect());
+ current->deref();
+ }
+ }
+
+ SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect();
+ *ret = rect;
+ return ret;
+}
+
+void SVGContainerImpl::createItem(KSVGCanvas *c)
+{
+ DOM::Node node = firstChild();
+ for(; !node.isNull(); node = node.nextSibling())
+ {
+ SVGElementImpl *elem = ownerDoc()->getElementFromHandle(node.handle());
+ if(elem)
+ elem->createItem(c);
+ }
+}
+
+void SVGContainerImpl::removeItem(KSVGCanvas *c)
+{
+ SVGShapeImpl::removeItem(c);
+
+ for(DOM::Node node = firstChild(); !node.isNull(); node = node.nextSibling())
+ {
+ SVGElementImpl *elem = ownerDoc()->getElementFromHandle(node.handle());
+ if(elem)
+ elem->removeItem(c);
+ }
+}
+
+void SVGContainerImpl::update(CanvasItemUpdate reason, int param1, int param2)
+{
+ SVGShapeImpl::update(reason, param1, param2);
+
+ for(DOM::Node node = firstChild(); !node.isNull(); node = node.nextSibling())
+ {
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(ownerDoc()->getElementFromHandle(node.handle()));
+ if(shape)
+ shape->update(reason, param1, param2);
+ }
+}
+
+void SVGContainerImpl::invalidate(KSVGCanvas *c, bool recalc)
+{
+ SVGShapeImpl::invalidate(c, recalc);
+
+ for(DOM::Node node = firstChild(); !node.isNull(); node = node.nextSibling())
+ {
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(ownerDoc()->getElementFromHandle(node.handle()));
+ if(shape)
+ shape->invalidate(c, recalc);
+ }
+}
+
+void SVGContainerImpl::setReferenced(bool referenced)
+{
+ SVGShapeImpl::setReferenced(referenced);
+
+ for(DOM::Node node = firstChild(); !node.isNull(); node = node.nextSibling())
+ {
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(ownerDoc()->getElementFromHandle(node.handle()));
+ if(shape)
+ shape->setReferenced(referenced);
+ }
+}
+
+void SVGContainerImpl::draw()
+{
+ SVGShapeImpl::draw();
+
+ for(DOM::Node node = firstChild(); !node.isNull(); node = node.nextSibling())
+ {
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(ownerDoc()->getElementFromHandle(node.handle()));
+ if(shape)
+ shape->draw();
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGContainerImpl.h b/ksvg/impl/SVGContainerImpl.h
new file mode 100644
index 00000000..353a6154
--- /dev/null
+++ b/ksvg/impl/SVGContainerImpl.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGContainerImpl_H
+#define SVGContainerImpl_H
+
+#include "SVGShapeImpl.h"
+
+namespace KSVG
+{
+enum CanvasItemUpdate;
+class KSVGCanvas;
+
+class SVGContainerImpl : public SVGShapeImpl
+{
+public:
+ SVGContainerImpl(DOM::ElementImpl *);
+ virtual ~SVGContainerImpl();
+
+ virtual bool isContainer() const { return true; }
+
+ virtual void createItem(KSVGCanvas *c = 0);
+ virtual void removeItem(KSVGCanvas *c);
+
+ virtual void update(CanvasItemUpdate reason, int param1, int param2);
+ virtual void invalidate(KSVGCanvas *c, bool recalc);
+ virtual void setReferenced(bool referenced);
+ virtual void draw();
+
+ virtual SVGRectImpl *getBBox();
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGCursorElementImpl.cc b/ksvg/impl/SVGCursorElementImpl.cc
new file mode 100644
index 00000000..331f8826
--- /dev/null
+++ b/ksvg/impl/SVGCursorElementImpl.cc
@@ -0,0 +1,104 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGCursorElementImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+
+using namespace KSVG;
+
+#include "SVGCursorElementImpl.lut.h"
+#include "ksvg_bridge.h"
+
+SVGCursorElementImpl::SVGCursorElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGURIReferenceImpl(), SVGTestsImpl(), SVGExternalResourcesRequiredImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_x = new SVGAnimatedLengthImpl();
+ m_x->ref();
+
+ m_y = new SVGAnimatedLengthImpl();
+ m_y->ref();
+}
+
+SVGCursorElementImpl::~SVGCursorElementImpl()
+{
+ if(m_x)
+ m_x->deref();
+ if(m_y)
+ m_y->deref();
+}
+
+SVGAnimatedLengthImpl *SVGCursorElementImpl::x() const
+{
+ return m_x;
+}
+
+SVGAnimatedLengthImpl *SVGCursorElementImpl::y() const
+{
+ return m_y;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGCursorElementImpl::s_hashTable 3
+ x SVGCursorElementImpl::X DontDelete|ReadOnly
+ y SVGCursorElementImpl::Y DontDelete|ReadOnly
+@end
+*/
+
+Value SVGCursorElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case X:
+ return m_x->cache(exec);
+ case Y:
+ return m_y->cache(exec);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGCursorElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case X:
+ x()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ case Y:
+ y()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGCursorElementImpl.h b/ksvg/impl/SVGCursorElementImpl.h
new file mode 100644
index 00000000..a063acd0
--- /dev/null
+++ b/ksvg/impl/SVGCursorElementImpl.h
@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGCursorElementImpl_H
+#define SVGCursorElementImpl_H
+
+#include "SVGTestsImpl.h"
+#include "SVGElementImpl.h"
+#include "SVGURIReferenceImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedLengthImpl;
+class SVGCursorElementImpl : public SVGElementImpl,
+ public SVGURIReferenceImpl,
+ public SVGTestsImpl,
+ public SVGExternalResourcesRequiredImpl
+{
+public:
+ SVGCursorElementImpl(DOM::ElementImpl *);
+ virtual ~SVGCursorElementImpl();
+
+ SVGAnimatedLengthImpl *x() const;
+ SVGAnimatedLengthImpl *y() const;
+
+private:
+ SVGAnimatedLengthImpl *m_x;
+ SVGAnimatedLengthImpl *m_y;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ X, Y
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGDefinitionSrcElementImpl.cc b/ksvg/impl/SVGDefinitionSrcElementImpl.cc
new file mode 100644
index 00000000..cf5d764c
--- /dev/null
+++ b/ksvg/impl/SVGDefinitionSrcElementImpl.cc
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGDefinitionSrcElementImpl.h"
+
+using namespace KSVG;
+
+SVGDefinitionSrcElementImpl::SVGDefinitionSrcElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl)
+{
+}
+
+SVGDefinitionSrcElementImpl::~SVGDefinitionSrcElementImpl()
+{
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGDefinitionSrcElementImpl.h b/ksvg/impl/SVGDefinitionSrcElementImpl.h
new file mode 100644
index 00000000..65fb359c
--- /dev/null
+++ b/ksvg/impl/SVGDefinitionSrcElementImpl.h
@@ -0,0 +1,46 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGDefinitionSrcElementImpl_H
+#define SVGDefinitionSrcElementImpl_H
+
+#include "SVGElementImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGDefinitionSrcElementImpl : public SVGElementImpl
+{
+public:
+ SVGDefinitionSrcElementImpl(DOM::ElementImpl *);
+ virtual ~SVGDefinitionSrcElementImpl();
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGDefsElementImpl.cc b/ksvg/impl/SVGDefsElementImpl.cc
new file mode 100644
index 00000000..e5d7d398
--- /dev/null
+++ b/ksvg/impl/SVGDefsElementImpl.cc
@@ -0,0 +1,34 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGDefsElementImpl.h"
+
+using namespace KSVG;
+
+SVGDefsElementImpl::SVGDefsElementImpl(DOM::ElementImpl *impl) : SVGContainerImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl()
+{
+ m_display = false; // implicit display=none
+}
+
+SVGDefsElementImpl::~SVGDefsElementImpl()
+{
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGDefsElementImpl.h b/ksvg/impl/SVGDefsElementImpl.h
new file mode 100644
index 00000000..e32f0dc9
--- /dev/null
+++ b/ksvg/impl/SVGDefsElementImpl.h
@@ -0,0 +1,61 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGDefsElementImpl_H
+#define SVGDefsElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGTestsImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGContainerImpl.h"
+#include "SVGLangSpaceImpl.h"
+#include "SVGTransformableImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+namespace KSVG
+{
+
+class SVGDefsElementImpl : public SVGContainerImpl,
+ public SVGTestsImpl,
+ public SVGLangSpaceImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGStylableImpl,
+ public SVGTransformableImpl
+{
+public:
+ SVGDefsElementImpl(DOM::ElementImpl *);
+ virtual ~SVGDefsElementImpl();
+
+ virtual bool directRender() { return false; }
+
+public:
+ KSVG_BRIDGE
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+KSVG_REGISTER_ELEMENT(SVGDefsElementImpl, "defs")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGDescElementImpl.cc b/ksvg/impl/SVGDescElementImpl.cc
new file mode 100644
index 00000000..cb0958dd
--- /dev/null
+++ b/ksvg/impl/SVGDescElementImpl.cc
@@ -0,0 +1,39 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGDocumentImpl.h"
+#include "SVGDescElementImpl.h"
+
+using namespace KSVG;
+
+SVGDescElementImpl::SVGDescElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGLangSpaceImpl(), SVGStylableImpl(this)
+{
+}
+
+SVGDescElementImpl::~SVGDescElementImpl()
+{
+}
+
+void SVGDescElementImpl::createItem(KSVGCanvas *)
+{
+ emit ownerDoc()->gotDescription(collectText());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGDescElementImpl.h b/ksvg/impl/SVGDescElementImpl.h
new file mode 100644
index 00000000..c8136eb6
--- /dev/null
+++ b/ksvg/impl/SVGDescElementImpl.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGDescElementImpl_H
+#define SVGDescElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGElementImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGLangSpaceImpl.h"
+
+namespace KSVG
+{
+
+class SVGDescElementImpl : public SVGElementImpl,
+ public SVGLangSpaceImpl,
+ public SVGStylableImpl
+{
+public:
+ SVGDescElementImpl(DOM::ElementImpl *impl);
+ virtual ~SVGDescElementImpl();
+
+ virtual void createItem(KSVGCanvas *c = 0);
+
+public:
+ KSVG_BRIDGE
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+KSVG_REGISTER_ELEMENT(SVGDescElementImpl, "desc")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGDocumentImpl.cc b/ksvg/impl/SVGDocumentImpl.cc
new file mode 100644
index 00000000..4bbe2664
--- /dev/null
+++ b/ksvg/impl/SVGDocumentImpl.cc
@@ -0,0 +1,705 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#define USE_VALGRIND 0
+
+#if USE_VALGRIND
+#include <valgrind/calltree.h>
+#endif
+
+#include "SVGEvent.h"
+#include "SVGMatrixImpl.h"
+#include "SVGWindowImpl.h"
+#include "SVGElementImpl.h"
+#include "SVGDocumentImpl.moc"
+#include "SVGSVGElementImpl.h"
+#include "SVGImageElementImpl.h"
+#include "SVGScriptElementImpl.h"
+#include "SVGTitleElementImpl.h"
+#include "SVGAnimationElementImpl.h"
+
+#include "KSVGReader.h"
+#include "KSVGLoader.h"
+#include "KSVGCanvas.h"
+#include "CanvasItem.h"
+
+#include <qpaintdevicemetrics.h>
+
+using namespace KSVG;
+
+#include "SVGDocumentImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+
+// A sequence of prime numbers that sets the m_elemDict's hash table size as the
+// number of elements in the dictionary passes each level. This keeps the lookup
+// performance high as the number of elements grows. See the QDict documentation.
+unsigned int SVGDocumentImpl::elemDictHashSizes [] =
+{
+ 101,
+ 211,
+ 401,
+ 809,
+ 1601,
+ 3203,
+ 6421,
+ 12809,
+ 25601,
+ 51203,
+ 102407,
+ 204803,
+ 409609,
+ 819229
+};
+
+const int SVGDocumentImpl::numElemDictHashSizes = sizeof(elemDictHashSizes) / sizeof(elemDictHashSizes[0]);
+
+SVGDocumentImpl::SVGDocumentImpl(bool anim, bool fit, SVGImageElementImpl *parentImage) : QObject(), DOM::DomShared(), DOM::Document(), SVGDOMNodeBridge(static_cast<DOM::Node>(*this))
+{
+ m_animations = anim;
+
+ m_reader = 0;
+ m_loader = 0;
+ m_canvas = 0;
+ m_rootElement = 0;
+ m_lastTarget = 0;
+ m_window = 0;
+
+ m_elemDictHashSizeIndex = 0;
+ m_elemDict.resize(elemDictHashSizes[m_elemDictHashSizeIndex]);
+
+ m_timeScheduler = new SVGTimeScheduler(this);
+ m_ecmaEngine = new KSVGEcma(this);
+ m_ecmaEngine->setup();
+
+ m_finishedParsing = false;
+ m_finishedLoading = false;
+ m_resortZIndicesOnFinishedLoading = false;
+ m_fit = fit;
+
+ m_parentImage = parentImage;
+ if(m_parentImage)
+ m_parentImage->ref();
+}
+
+SVGDocumentImpl::~SVGDocumentImpl()
+{
+ if(rootElement() && rootElement()->hasEventListener(SVGEvent::UNLOAD_EVENT, true))
+ rootElement()->dispatchEvent(SVGEvent::UNLOAD_EVENT, false, false);
+
+ QPtrList<SVGShapeImpl> killList;
+
+ DOM::Node node = firstChild();
+ for(; !node.isNull(); node = node.nextSibling())
+ {
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(getElementFromHandle(node.handle()));
+ if(shape)
+ killList.append(shape);
+ }
+
+ SVGShapeImpl *rend = 0;
+ for(rend = killList.first(); rend; rend = killList.next())
+ delete rend;
+
+ delete m_timeScheduler;
+ delete m_ecmaEngine;
+ delete m_reader;
+ delete m_loader;
+
+ if(m_window)
+ m_window->deref();
+
+ if(m_parentImage)
+ m_parentImage->deref();
+}
+
+SVGWindowImpl *SVGDocumentImpl::window()
+{
+ if(!m_window)
+ {
+ m_window = new SVGWindowImpl(const_cast<SVGDocumentImpl *>(this));
+ m_window->ref();
+ }
+
+ return m_window;
+}
+
+float SVGDocumentImpl::screenPixelsPerMillimeterX() const
+{
+ if(canvas() && canvas()->drawWindow())
+ {
+ QPaintDeviceMetrics metrics(canvas()->drawWindow());
+ return float(metrics.width()) / float(metrics.widthMM());
+ }
+ else
+ return 90.0;
+}
+
+float SVGDocumentImpl::screenPixelsPerMillimeterY() const
+{
+ if(canvas() && canvas()->drawWindow())
+ {
+ QPaintDeviceMetrics metrics(canvas()->drawWindow());
+ return float(metrics.height()) / float(metrics.heightMM());
+ }
+ else
+ return 90.0;
+}
+
+DOM::DOMString SVGDocumentImpl::title() const
+{
+ DOM::Node n;
+ for(n = rootElement()->firstChild(); !n.isNull(); n = n.nextSibling())
+ {
+ SVGElementImpl *elem = getElementFromHandle(n.handle());
+ if(dynamic_cast<SVGTitleElementImpl *>(elem))
+ return elem->collectText();
+ }
+ return "";
+}
+
+DOM::DOMString SVGDocumentImpl::referrer() const
+{
+ return m_referrer;
+}
+
+DOM::DOMString SVGDocumentImpl::domain() const
+{
+ return m_baseURL.host();
+}
+
+DOM::DOMString SVGDocumentImpl::URL() const
+{
+ return m_baseURL.prettyURL();
+}
+
+void SVGDocumentImpl::setReferrer(const DOM::DOMString &referrer)
+{
+ // TODO : better may be to request for referrer instead of storing it
+ m_referrer = referrer;
+}
+
+void SVGDocumentImpl::setRootElement(SVGSVGElementImpl *elem)
+{
+ m_rootElement = elem;
+}
+
+SVGSVGElementImpl *SVGDocumentImpl::rootElement() const
+{
+ return m_rootElement;
+}
+
+SVGElementImpl *SVGDocumentImpl::createElement(const DOM::DOMString &name, DOM::Element impl, SVGDocumentImpl *doc)
+{
+ DOM::ElementImpl *handle = reinterpret_cast<DOM::ElementImpl *>(impl.handle());
+ SVGElementImpl *element = SVGElementImpl::Factory::self()->create(std::string(name.string().latin1()), handle);
+
+ if(!element)
+ element = new SVGElementImpl(handle);
+
+ element->setOwnerDoc(doc);
+ element->ref();
+ return element;
+}
+
+bool SVGDocumentImpl::open(const ::KURL &url)
+{
+ if(!url.prettyURL().isEmpty())
+ {
+ m_baseURL = url;
+
+ if(!m_loader)
+ m_loader = new KSVGLoader();
+
+ connect(m_loader, SIGNAL(gotResult(QIODevice *)), this, SLOT(slotSVGContent(QIODevice *)));
+ m_loader->getSVGContent(url);
+ }
+ else
+ return false;
+
+ return true;
+}
+
+void SVGDocumentImpl::slotSVGContent(QIODevice *dev)
+{
+ QXmlInputSource *inputSource = new QXmlInputSource(dev);
+
+ if(m_reader)
+ delete m_reader;
+
+ KSVGReader::ParsingArgs args;
+ args.fit = m_fit;
+ args.getURLMode = false;
+
+ QString url = m_baseURL.prettyURL();
+ int pos = url.find('#'); // url can become like this.svg#svgView(viewBox(63,226,74,74)), get part after '#'
+ if(pos > -1)
+ args.SVGFragmentId = url.mid(pos + 1);
+
+ m_reader = new KSVGReader(this, m_canvas, args);
+ connect(m_reader, SIGNAL(finished(bool, const QString &)), this, SLOT(slotFinishedParsing(bool, const QString &)));
+ m_t.start();
+
+#if USE_VALGRIND
+ CALLTREE_ZERO_STATS();
+#endif
+
+ m_reader->parse(inputSource);
+ delete dev;
+}
+
+void SVGDocumentImpl::parseSVG(QXmlInputSource *inputSource, bool getURLMode)
+{
+ if(m_reader)
+ delete m_reader;
+
+ KSVGReader::ParsingArgs args;
+ args.fit = m_fit;
+ args.getURLMode = getURLMode;
+ m_reader = new KSVGReader(this, 0, args);
+ connect(m_reader, SIGNAL(finished(bool, const QString &)), this, SLOT(slotFinishedParsing(bool, const QString &)));
+
+#if USE_VALGRIND
+ CALLTREE_ZERO_STATS();
+#endif
+
+ m_reader->parse(inputSource);
+}
+
+void SVGDocumentImpl::finishParsing(bool error, const QString &errorDesc)
+{
+ if(m_reader)
+ m_reader->finishParsing(error, errorDesc);
+}
+
+void SVGDocumentImpl::slotFinishedParsing(bool error, const QString &errorDesc)
+{
+ kdDebug(26000) << k_funcinfo << "total time : " << m_t.elapsed() << endl;
+
+#if USE_VALGRIND
+ CALLTREE_DUMP_STATS();
+#endif
+
+ if(m_animations)
+ m_timeScheduler->startAnimations();
+
+ if(m_canvas && !error && rootElement())
+ executeScripts();
+
+ m_finishedParsing = true;
+
+ emit finishedParsing(error, errorDesc);
+ if(!error)
+ emit finishedRendering();
+
+ checkFinishedLoading();
+}
+
+void SVGDocumentImpl::newImageJob(SVGImageElementImpl *image)
+{
+ kdDebug(26002) << "SVGDocumentImpl::newImageJob, " << image << endl;
+ m_loader->newImageJob(image, m_baseURL);
+}
+
+void SVGDocumentImpl::notifyImageLoading(SVGImageElementImpl *image)
+{
+ m_imagesLoading.append(image);
+}
+
+void SVGDocumentImpl::notifyImageLoaded(SVGImageElementImpl *image)
+{
+ m_imagesLoading.remove(image);
+
+ if(m_imagesLoading.isEmpty())
+ checkFinishedLoading();
+}
+
+void SVGDocumentImpl::checkFinishedLoading()
+{
+ if(m_finishedParsing && m_imagesLoading.isEmpty())
+ {
+ m_finishedLoading = true;
+
+ if(m_resortZIndicesOnFinishedLoading)
+ {
+ // Only resort if we're the 'outermost' document, i.e. we're not an svg image
+ // inside another document. We could resort as each image finishes loading, but it
+ // slows down the parsing phase.
+ if(m_parentImage == 0 && m_canvas && m_rootElement)
+ {
+ m_canvas->setElementItemZIndexRecursive(m_rootElement, 0);
+ m_canvas->update();
+ }
+ }
+
+ emit finishedLoading();
+ }
+}
+
+void SVGDocumentImpl::addForwardReferencingUseElement(SVGUseElementImpl *use)
+{
+ if(!m_forwardReferencingUseElements.contains(use))
+ m_forwardReferencingUseElements.append(use);
+}
+
+void SVGDocumentImpl::slotPaint()
+{
+ rerender();
+}
+
+void SVGDocumentImpl::rerender()
+{
+ m_canvas->update();
+ emit finishedRendering();
+}
+
+void SVGDocumentImpl::attach(KSVG::KSVGCanvas *c)
+{
+ m_canvas = c;
+}
+
+void SVGDocumentImpl::detach()
+{
+ m_canvas = 0;
+}
+
+KSVG::KSVGCanvas *SVGDocumentImpl::canvas() const
+{
+ return m_canvas;
+}
+
+void SVGDocumentImpl::syncCachedMatrices()
+{
+ if(rootElement())
+ {
+ SVGMatrixImpl *parentMatrix = SVGSVGElementImpl::createSVGMatrix();
+ rootElement()->checkCachedScreenCTM(parentMatrix);
+ parentMatrix->deref();
+ }
+}
+
+void SVGDocumentImpl::executeScriptsRecursive(DOM::Node start)
+{
+ DOM::Node node = start.firstChild();
+
+ for(; !node.isNull(); node = node.nextSibling())
+ {
+ SVGElementImpl *element = getElementFromHandle(node.handle());
+
+ SVGContainerImpl *container = dynamic_cast<SVGContainerImpl *>(element);
+ if(container)
+ executeScriptsRecursive(node);
+
+ SVGScriptElementImpl *script = dynamic_cast<SVGScriptElementImpl *>(element);
+
+ if(script)
+ script->executeScript(DOM::Node());
+ }
+}
+
+bool SVGDocumentImpl::executeScriptsRecursiveCheck(DOM::Node start)
+{
+ bool test = true;
+
+ DOM::Node node = start.firstChild();
+
+ for(; !node.isNull(); node = node.nextSibling())
+ {
+ SVGElementImpl *element = getElementFromHandle(node.handle());
+
+ SVGContainerImpl *container = dynamic_cast<SVGContainerImpl *>(element);
+ if(container)
+ {
+ if(!executeScriptsRecursiveCheck(node))
+ return false;
+ }
+
+ SVGScriptElementImpl *script = dynamic_cast<SVGScriptElementImpl *>(element);
+
+ if(script)
+ {
+ if(!script->canExecuteScript())
+ {
+ test = false;
+ break;
+ }
+ }
+ }
+
+ return test;
+}
+
+void SVGDocumentImpl::executeScripts()
+{
+ bool test = executeScriptsRecursiveCheck(*rootElement());
+
+ if(!test)
+ QTimer::singleShot(50, this, SLOT(executeScripts()));
+ else
+ {
+ executeScriptsRecursive(*rootElement());
+
+ // mop: only rerender if an loadevent has been found
+ if(dispatchRecursiveEvent(SVGEvent::LOAD_EVENT, lastChild()))
+ m_canvas->update();
+ }
+}
+
+// Dispatches a non-cancelable, non-bubbles event to every child
+bool SVGDocumentImpl::dispatchRecursiveEvent(SVGEvent::EventId id, DOM::Node start)
+{
+ bool eventExecuted = false;
+
+ // Iterate the tree, backwards, and dispatch the event to every child
+ DOM::Node node = start;
+ for(; !node.isNull(); node = node.previousSibling())
+ {
+ SVGElementImpl *element = getElementFromHandle(node.handle());
+
+ if(element && element->hasChildNodes())
+ {
+ // Dispatch to all children
+ eventExecuted = dispatchRecursiveEvent(id, element->lastChild()) ? true : eventExecuted;
+
+ // Dispatch, locally
+ if(element->hasEventListener(id, true))
+ {
+ element->dispatchEvent(id, false, false);
+ eventExecuted = true;
+ }
+ }
+ else if(element && element->hasEventListener(id, true))
+ {
+ element->dispatchEvent(id, false, false);
+ eventExecuted = true;
+ }
+ }
+
+ return eventExecuted;
+}
+
+SVGEventListener *SVGDocumentImpl::createEventListener(DOM::DOMString type)
+{
+ return m_ecmaEngine->createEventListener(type);
+}
+
+SVGElementImpl *SVGDocumentImpl::recursiveSearch(DOM::Node start, const DOM::DOMString &id)
+{
+ DOM::Node node = start.firstChild();
+ for(; !node.isNull(); node = node.nextSibling())
+ {
+ SVGElementImpl *test = getElementFromHandle(node.handle());
+
+ // Look in containers
+ SVGContainerImpl *container = dynamic_cast<SVGContainerImpl *>(test);
+ if(container)
+ {
+ SVGElementImpl *found = recursiveSearch(node, id);
+ if(found)
+ return found;
+ }
+
+ // Look in SVGSVGElementImpl's
+ SVGSVGElementImpl *svgtest = dynamic_cast<SVGSVGElementImpl *>(test);
+ if(svgtest)
+ {
+ SVGElementImpl *element = svgtest->getElementById(id);
+ if(element)
+ return element;
+ }
+ }
+
+ return 0;
+}
+
+/*
+@namespace KSVG
+@begin SVGDocumentImpl::s_hashTable 9
+ title SVGDocumentImpl::Title DontDelete|ReadOnly
+ referrer SVGDocumentImpl::Referrer DontDelete|ReadOnly
+ domain SVGDocumentImpl::Domain DontDelete|ReadOnly
+ URL SVGDocumentImpl::Url DontDelete|ReadOnly
+ doctype SVGDocumentImpl::DocType DontDelete|ReadOnly
+ implementation SVGDocumentImpl::Implementation DontDelete|ReadOnly
+ rootElement SVGDocumentImpl::RootElement DontDelete|ReadOnly
+ documentElement SVGDocumentImpl::DocumentElement DontDelete|ReadOnly
+@end
+@namespace KSVG
+@begin SVGDocumentImplProto::s_hashTable 7
+ createTextNode SVGDocumentImpl::CreateTextNode DontDelete|Function 1
+ createElement SVGDocumentImpl::CreateElement DontDelete|Function 1
+ createElementNS SVGDocumentImpl::CreateElementNS DontDelete|Function 2
+ getElementById SVGDocumentImpl::GetElementById DontDelete|Function 1
+ getElementsByTagName SVGDocumentImpl::GetElementsByTagName DontDelete|Function 1
+ getElementsByTagNameNS SVGDocumentImpl::GetElementsByTagNameNS DontDelete|Function 2
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGDocument", SVGDocumentImplProto, SVGDocumentImplProtoFunc)
+
+Value SVGDocumentImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case Title:
+ return String(title().string());
+ case Referrer:
+ return String(referrer().string());
+ case Domain:
+ return String(domain().string());
+ case Url:
+ return String(URL().string());
+ case DocType:
+ return getDOMNode(exec, doctype());
+ case Implementation:
+ return (new SVGDOMDOMImplementationBridge(implementation()))->cache(exec);
+ case RootElement:
+ case DocumentElement:
+ return m_rootElement->cache(exec);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+Value SVGDocumentImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGDocumentImpl)
+
+ switch(id)
+ {
+ case SVGDocumentImpl::CreateTextNode:
+ return getDOMNode(exec, obj->createTextNode(args[0].toString(exec).string()));
+ case SVGDocumentImpl::CreateElement:
+ case SVGDocumentImpl::CreateElementNS:
+ {
+ SVGElementImpl *newElement = 0;
+
+ if(id == SVGDocumentImpl::CreateElement)
+ newElement = obj->createElement(args[0].toString(exec).qstring(), static_cast<DOM::Document *>(obj)->createElement(args[0].toString(exec).string()), obj);
+ else if(id == SVGDocumentImpl::CreateElementNS)
+ newElement = obj->createElement(args[1].toString(exec).qstring(), static_cast<DOM::Document *>(obj)->createElementNS(args[0].toString(exec).string(), args[1].toString(exec).string()), obj);
+
+ newElement->setOwnerSVGElement(obj->rootElement()); // FIXME: Correct in all situations?
+ newElement->setViewportElement(obj->rootElement());
+ newElement->setAttributes();
+
+ return getDOMNode(exec, *newElement);
+ }
+ case SVGDocumentImpl::GetElementById:
+ {
+ Value ret;
+
+ SVGElementImpl *element = obj->rootElement()->getElementById(args[0].toString(exec).string());
+
+ if(element)
+ ret = getDOMNode(exec, *element);
+ else
+ {
+ element = obj->recursiveSearch(*obj, args[0].toString(exec).string());
+ if(!element)
+ return Null();
+
+ ret = getDOMNode(exec, *element);
+ }
+
+ return ret;
+ }
+ case SVGDocumentImpl::GetElementsByTagName:
+ return (new SVGDOMNodeListBridge(obj->getElementsByTagName(args[0].toString(exec).string())))->cache(exec);
+ case SVGDocumentImpl::GetElementsByTagNameNS:
+ return (new SVGDOMNodeListBridge(obj->getElementsByTagNameNS(args[0].toString(exec).string(), args[1].toString(exec).string())))->cache(exec);
+ default:
+ break;
+ }
+
+ return KJS::Undefined();
+}
+
+SVGElementImpl *SVGDocumentImpl::getElementFromHandle(DOM::NodeImpl *handle) const
+{
+ return m_elemDict[handle];
+}
+
+void SVGDocumentImpl::addToElemDict(DOM::NodeImpl *handle, SVGElementImpl *obj)
+{
+ m_elemDict.insert(handle, obj);
+
+ if(m_elemDict.count()>m_elemDict.size() && m_elemDictHashSizeIndex<numElemDictHashSizes-1)
+ {
+ // Increase the hash table size to maintain good lookup speed.
+ m_elemDictHashSizeIndex++;
+ m_elemDict.resize(elemDictHashSizes[m_elemDictHashSizeIndex]);
+ }
+}
+
+void SVGDocumentImpl::removeFromElemDict(DOM::NodeImpl *handle)
+{
+ m_elemDict.remove(handle);
+}
+
+SVGDocumentImpl *SVGDocumentImpl::getDocumentFromHandle(DOM::NodeImpl *handle) const
+{
+ return m_documentDict[handle];
+}
+
+void SVGDocumentImpl::addToDocumentDict(DOM::NodeImpl *handle, SVGDocumentImpl *obj)
+{
+ m_documentDict.insert(handle, obj);
+}
+
+SVGElementImpl *SVGDocumentImpl::getElementByIdRecursive(SVGSVGElementImpl *start, const DOM::DOMString &elementId, bool dontSearch)
+{
+ SVGElementImpl *element = 0;
+
+ // #1 Look in passed SVGSVGElementImpl
+ if(start)
+ {
+ element = start->getElementById(elementId);
+
+ if(element)
+ return element;
+ }
+
+ // #2 Search in all child SVGSVGElementImpl's
+ element = recursiveSearch(*this, elementId);
+
+ if(element)
+ return element;
+
+ // #3 Search in other documents
+ if(!dontSearch)
+ {
+ QPtrDictIterator<SVGDocumentImpl> it(m_documentDict);
+ for(; it.current(); ++it)
+ {
+ SVGElementImpl *temp = it.current()->getElementByIdRecursive(0, elementId, true);
+ if(temp)
+ return temp;
+ }
+ }
+
+ return element;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGDocumentImpl.h b/ksvg/impl/SVGDocumentImpl.h
new file mode 100644
index 00000000..c4156910
--- /dev/null
+++ b/ksvg/impl/SVGDocumentImpl.h
@@ -0,0 +1,245 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGDocumentImpl_H
+#define SVGDocumentImpl_H
+
+#include <kurl.h>
+
+#include <qxml.h>
+#include <qobject.h>
+#include <qptrdict.h>
+#include <qptrlist.h>
+#include <qdatetime.h>
+#include <qstringlist.h>
+
+#include <kjs/object.h>
+
+#include <dom/dom_doc.h>
+#include <dom/dom_misc.h>
+#include <dom/dom_string.h>
+
+#include "ksvg_lookup.h"
+
+#include "SVGEvent.h"
+#include "SVGTimeScheduler.h"
+
+class KSVGEcma;
+class KSVGRequest;
+
+namespace KJS
+{
+ class Value;
+ class UString;
+ class ExecState;
+ class Identifier;
+}
+
+namespace KSVG
+{
+
+class SVGTimer;
+class KSVGLoader;
+class KSVGReader;
+class KSVGCanvas;
+class SVGImageElementImpl;
+class SVGSVGElementImpl;
+class SVGWindowImpl;
+class SVGScriptElementImpl;
+class SVGDescElementImpl;
+class SVGTitleElementImpl;
+class SVGUseElementImpl;
+class SVGDocumentImpl : public QObject,
+ public DOM::DomShared,
+ public DOM::Document,
+ public SVGDOMNodeBridge
+{
+Q_OBJECT
+public:
+ SVGDocumentImpl(bool anim = true, bool bFit = false, SVGImageElementImpl *parentImage = 0);
+ virtual ~SVGDocumentImpl();
+
+ float screenPixelsPerMillimeterX() const;
+ float screenPixelsPerMillimeterY() const;
+
+ DOM::DOMString title() const;
+ DOM::DOMString referrer() const;
+ DOM::DOMString domain() const;
+ DOM::DOMString URL() const;
+
+ void setReferrer(const DOM::DOMString &referrer);
+
+ void setRootElement(SVGSVGElementImpl *);
+ SVGSVGElementImpl *rootElement() const;
+
+ SVGImageElementImpl *parentImage() const { return m_parentImage; }
+
+ SVGWindowImpl *window();
+
+ static SVGElementImpl *createElement(const DOM::DOMString &name, DOM::Element impl, SVGDocumentImpl *doc = 0);
+
+ bool open(const KURL &url);
+ void rerender();
+
+ void attach(KSVG::KSVGCanvas *p);
+ void detach();
+
+ bool ready() { return m_finishedParsing; }
+
+ KURL baseUrl() { return m_baseURL; }
+ KSVGCanvas *canvas() const;
+
+ // Ecma stuff
+ KSVGEcma *ecmaEngine() { return m_ecmaEngine; }
+
+ void parseSVG(QXmlInputSource *inputSource, bool getURLMode = false);
+
+ virtual bool implementsCall() const { return true; }
+
+ void executeScriptsRecursive(DOM::Node start);
+ bool executeScriptsRecursiveCheck(DOM::Node start);
+
+ bool dispatchRecursiveEvent(SVGEvent::EventId id, DOM::Node start);
+
+ SVGElementImpl *getElementByIdRecursive(SVGSVGElementImpl *start, const DOM::DOMString &elementId, bool dontSearch = false);
+
+ // Event stuff
+ SVGEventListener *createEventListener(DOM::DOMString type);
+
+ void setLastTarget(SVGElementImpl *elem) { m_lastTarget = elem; }
+ SVGElementImpl *lastTarget() { return m_lastTarget; }
+
+ // Animation stuff
+ SVGTimeScheduler *timeScheduler() const { return m_timeScheduler; }
+
+ // Internal
+ SVGElementImpl *getElementFromHandle(DOM::NodeImpl *handle) const;
+ void addToElemDict(DOM::NodeImpl *handle, SVGElementImpl *obj);
+ void removeFromElemDict(DOM::NodeImpl *handle);
+
+ SVGDocumentImpl *getDocumentFromHandle(DOM::NodeImpl *handle) const;
+ void addToDocumentDict(DOM::NodeImpl *handle, SVGDocumentImpl *obj);
+
+ SVGElementImpl *recursiveSearch(DOM::Node start, const DOM::DOMString &id);
+
+ void finishParsing(bool error, const QString &errorDesc);
+
+ void newImageJob(SVGImageElementImpl *);
+
+ void notifyImageLoading(SVGImageElementImpl *image);
+ void notifyImageLoaded(SVGImageElementImpl *image);
+ void resortZIndicesOnFinishedLoading() { m_resortZIndicesOnFinishedLoading = true; }
+
+ void addForwardReferencingUseElement(SVGUseElementImpl *use);
+ QValueList<SVGUseElementImpl *> forwardReferencingUseElements() const { return m_forwardReferencingUseElements; }
+
+ // Traverse the element hierarchy and update any cached matrices that are
+ // no longer valid.
+ void syncCachedMatrices();
+
+public slots:
+ void slotPaint();
+ void executeScripts();
+
+private slots:
+ void slotSVGContent(QIODevice *);
+ void slotFinishedParsing(bool error, const QString &errorDesc);
+
+// KDE invents public signals :)
+#undef signals
+#define signals public
+signals:
+ void gotDescription(const QString &);
+ void gotTitle(const QString &);
+ void gotURL(const QString &);
+
+ void finishedParsing(bool error, const QString &errorDesc);
+ void finishedRendering();
+ void finishedLoading();
+
+private:
+ void checkFinishedLoading();
+
+ bool m_finishedParsing;
+ bool m_finishedLoading;
+ bool m_animations;
+
+ SVGSVGElementImpl *m_rootElement;
+
+ SVGTimeScheduler *m_timeScheduler;
+
+ // Set if this document is being displayed by an 'image' element reference
+ // rather than as the main document, 0 otherwise.
+ SVGImageElementImpl *m_parentImage;
+
+ KSVGReader *m_reader;
+ KSVGLoader *m_loader;
+ KSVGCanvas *m_canvas;
+
+ KSVGEcma *m_ecmaEngine;
+
+ QPtrDict<SVGElementImpl> m_elemDict;
+ QPtrDict<SVGDocumentImpl> m_documentDict;
+
+ static uint elemDictHashSizes[];
+ static const int numElemDictHashSizes;
+ int m_elemDictHashSizeIndex;
+
+ SVGWindowImpl *m_window;
+ SVGElementImpl *m_lastTarget;
+
+ KURL m_baseURL;
+
+ DOM::DOMString m_referrer;
+
+ bool m_fit;
+
+ QTime m_t;
+
+ QValueList<SVGImageElementImpl *> m_imagesLoading;
+ bool m_resortZIndicesOnFinishedLoading;
+
+ QValueList<SVGUseElementImpl *> m_forwardReferencingUseElements;
+
+public:
+ KSVG_BASECLASS_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ Title, Referrer, Domain, Url,
+ DocType, Implementation, RootElement, DocumentElement,
+ // Functions
+ CreateTextNode, CreateElement, CreateElementNS,
+ GetElementById, GetElementsByTagName, GetElementsByTagNameNS
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+};
+
+}
+
+KSVG_DEFINE_PROTOTYPE(SVGDocumentImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGDocumentImplProtoFunc, SVGDocumentImpl)
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGEcma.cc b/ksvg/impl/SVGEcma.cc
new file mode 100644
index 00000000..08870d0c
--- /dev/null
+++ b/ksvg/impl/SVGEcma.cc
@@ -0,0 +1,844 @@
+/*
+ Copyright (C) 2002-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <typeinfo>
+
+#include <kdebug.h>
+
+#include <dom/dom_exception.h>
+
+#include "CanvasItem.h"
+#include "KSVGCanvas.h"
+
+#include "SVGEcma.h"
+#include "SVGShapeImpl.h"
+#include "SVGHelperImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+
+using namespace KSVG;
+
+#include "SVGEcma.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_ecmaeventlistener.h"
+#include "ksvg_window.h"
+#include "ksvg_ecma.h"
+
+// SVGDOMNodeBridge
+
+/*
+@namespace KSVG
+@begin SVGDOMNodeBridge::s_hashTable 17
+ nodeName SVGDOMNodeBridge::NodeName DontDelete|ReadOnly
+ nodeValue SVGDOMNodeBridge::NodeValue DontDelete
+ nodeType SVGDOMNodeBridge::NodeType DontDelete|ReadOnly
+ parentNode SVGDOMNodeBridge::ParentNode DontDelete|ReadOnly
+ childNodes SVGDOMNodeBridge::ChildNodes DontDelete|ReadOnly
+ firstChild SVGDOMNodeBridge::FirstChild DontDelete|ReadOnly
+ lastChild SVGDOMNodeBridge::LastChild DontDelete|ReadOnly
+ previousSibling SVGDOMNodeBridge::PreviousSibling DontDelete|ReadOnly
+ nextSibling SVGDOMNodeBridge::NextSibling DontDelete|ReadOnly
+ attributes SVGDOMNodeBridge::Attributes DontDelete|ReadOnly
+ namespaceURI SVGDOMNodeBridge::NamespaceURI DontDelete|ReadOnly
+ prefix SVGDOMNodeBridge::Prefix DontDelete
+ localName SVGDOMNodeBridge::LocalName DontDelete|ReadOnly
+ ownerDocument SVGDOMNodeBridge::OwnerDocument DontDelete|ReadOnly
+@end
+@namespace KSVG
+@begin SVGDOMNodeBridgeProto::s_hashTable 29
+ insertBefore SVGDOMNodeBridge::InsertBefore DontDelete|Function 2
+ replaceChild SVGDOMNodeBridge::ReplaceChild DontDelete|Function 2
+ removeChild SVGDOMNodeBridge::RemoveChild DontDelete|Function 1
+ appendChild SVGDOMNodeBridge::AppendChild DontDelete|Function 1
+ hasAttributes SVGDOMNodeBridge::HasAttributes DontDelete|Function 0
+ hasChildNodes SVGDOMNodeBridge::HasChildNodes DontDelete|Function 0
+ cloneNode SVGDOMNodeBridge::CloneNode DontDelete|Function 1
+ normalize SVGDOMNodeBridge::Normalize DontDelete|Function 0
+ isSupported SVGDOMNodeBridge::IsSupported DontDelete|Function 2
+ addEventListener SVGDOMNodeBridge::AddEventListener DontDelete|Function 3
+ removeEventListener SVGDOMNodeBridge::RemoveEventListener DontDelete|Function 3
+ contains SVGDOMNodeBridge::Contains DontDelete|Function 1
+ getNodeName SVGDOMNodeBridge::GetNodeName DontDelete|Function 0
+ getNodeValue SVGDOMNodeBridge::GetNodeValue DontDelete|Function 0
+ getNodeType SVGDOMNodeBridge::GetNodeType DontDelete|Function 0
+ getParentNode SVGDOMNodeBridge::GetParentNode DontDelete|Function 0
+ getChildNodes SVGDOMNodeBridge::GetChildNodes DontDelete|Function 0
+ getFirstChild SVGDOMNodeBridge::GetFirstChild DontDelete|Function 0
+ getLastChild SVGDOMNodeBridge::GetLastChild DontDelete|Function 0
+ getPreviousSibling SVGDOMNodeBridge::GetPreviousSibling DontDelete|Function 0
+ getNextSibling SVGDOMNodeBridge::GetNextSibling DontDelete|Function 0
+ getAttributes SVGDOMNodeBridge::GetAttributes DontDelete|Function 0
+ getNamespaceURI SVGDOMNodeBridge::GetNamespaceURI DontDelete|Function 0
+ getPrefix SVGDOMNodeBridge::GetPrefix DontDelete|Function 0
+ getLocalName SVGDOMNodeBridge::GetLocalName DontDelete|Function 0
+ getOwnerDocument SVGDOMNodeBridge::GetOwnerDocument DontDelete|Function 0
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("DOMNode", SVGDOMNodeBridgeProto, SVGDOMNodeBridgeProtoFunc)
+
+Value SVGDOMNodeBridge::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case NodeName:
+ return getString(m_impl.nodeName());
+ case NodeValue:
+ return getString(m_impl.nodeValue());
+ case NodeType:
+ return Number(m_impl.nodeType());
+ case ParentNode:
+ return getDOMNode(exec, m_impl.parentNode());
+ case ChildNodes:
+ return (new SVGDOMNodeListBridge(m_impl.childNodes()))->cache(exec);
+ case FirstChild:
+ return getDOMNode(exec, m_impl.firstChild());
+ case LastChild:
+ return getDOMNode(exec, m_impl.lastChild());
+ case PreviousSibling:
+ return getDOMNode(exec, m_impl.previousSibling());
+ case NextSibling:
+ return getDOMNode(exec, m_impl.nextSibling());
+// case Attributes: // TODO
+ case NamespaceURI:
+ return getString(m_impl.namespaceURI());
+ case Prefix:
+ return getString(m_impl.prefix());
+ case LocalName:
+ return getString(m_impl.localName());
+ case OwnerDocument:
+ return getDOMNode(exec, m_impl.ownerDocument());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGDOMNodeBridge::putValueProperty(ExecState *exec, int token, const Value &value, int)
+{
+ switch(token)
+ {
+ case NodeValue:
+ m_impl.setNodeValue(value.toString(exec).string());
+ break;
+ case Prefix:
+ m_impl.setPrefix(value.toString(exec).string());
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// Special variantion to update the <text> element,
+// triggered by one of the child nodes
+void updateTextItem(ExecState *exec, const DOM::Node node)
+{
+ DOM::Node parent;
+ while(!(parent = node.parentNode()).isNull())
+ {
+ DOM::DOMString name = parent.nodeName();
+ if(name == "text" || name == "tspan" || name == "tref")
+ {
+ SVGHelperImpl::updateItem(exec, parent);
+ break;
+ }
+ }
+}
+
+// Remove item from canvas
+void removeItem(ExecState *exec, DOM::Node &node)
+{
+ // Get document
+ SVGDocumentImpl *doc = KSVG::Window::retrieveActive(exec)->doc();
+
+ // Update canvas
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(doc->getElementFromHandle(node.handle()));
+ if(shape && shape->item())
+ doc->canvas()->removeItem(shape->item());
+}
+
+// parseXML + getURL() need all these 5 functions to work properly
+void correctHandles(SVGElementImpl *main, DOM::Node &node)
+{
+ DOM::Element old(node.handle());
+ DOM::Element *replace = static_cast<DOM::Element *>(main->ownerDoc()->getElementFromHandle(node.handle()));
+
+ if(replace && node.nodeType() == DOM::Node::ELEMENT_NODE)
+ *replace = old;
+
+ if(node.hasChildNodes())
+ {
+ for(DOM::Node iterate = node.firstChild(); !iterate.isNull(); iterate = iterate.nextSibling())
+ correctHandles(main, iterate);
+ }
+}
+
+void integrateTree(SVGElementImpl *main, DOM::Node &node, DOM::Node &newNode, SVGElementImpl *obj, SVGDocumentImpl *doc)
+{
+ if(!obj)
+ return;
+
+ // Add to global element dicts
+ doc->addToElemDict(newNode.handle(), obj);
+ doc->addToElemDict(node.handle(), obj);
+
+ if(node.hasChildNodes())
+ {
+ DOM::Node iterate2 = newNode.firstChild();
+ for(DOM::Node iterate = node.firstChild(); !iterate.isNull(); iterate = iterate.nextSibling())
+ {
+ integrateTree(main, iterate, iterate2, obj->ownerDoc()->getElementFromHandle(iterate2.handle()), doc);
+ iterate2 = iterate2.nextSibling();
+ }
+ }
+}
+
+void correctDocument(SVGElementImpl *main, DOM::Node &node, SVGElementImpl *obj, SVGDocumentImpl *doc)
+{
+ if(!obj)
+ return;
+
+ // Correct document
+ obj->setOwnerDoc(main->ownerDoc());
+
+ // Correct rootElement
+ if(!obj->ownerSVGElement())
+ obj->setOwnerSVGElement(main->ownerSVGElement());
+
+ // Correct viewportElement
+ if(!obj->viewportElement())
+ obj->setViewportElement(main->viewportElement());
+
+ // Properly (re-)register events in the current active document
+ obj->setupEventListeners(main->ownerDoc(), doc);
+
+ if(node.hasChildNodes())
+ {
+ for(DOM::Node iterate = node.firstChild(); !iterate.isNull(); iterate = iterate.nextSibling())
+ correctDocument(main, iterate, doc->getElementFromHandle(iterate.handle()), doc);
+ }
+}
+
+void registerAdditional(ExecState *exec, SVGDocumentImpl *doc, DOM::Node node)
+{
+ // Register ID in rootElement!
+ SVGElementImpl *resultElement = doc->getElementFromHandle(node.handle());
+ if(resultElement && resultElement->hasAttribute("id"))
+ doc->rootElement()->addToIdMap(resultElement->getAttribute("id").string(), resultElement);
+
+ if(node.hasChildNodes())
+ {
+ for(DOM::Node iterate = node.firstChild(); !iterate.isNull(); iterate = iterate.nextSibling())
+ registerAdditional(exec, doc, iterate);
+ }
+}
+
+Value appendHelper(ExecState *exec, DOM::Node node, DOM::Node newNode)
+{
+ // This is quite tricky code by me (Niko)
+ // Don't even try to modify it.
+ if(!(node.ownerDocument() == newNode.ownerDocument()))
+ {
+ // Get document
+ SVGDocumentImpl *doc = KSVG::Window::retrieveActive(exec)->doc();
+
+ // Detect ownerDoc() of newNode
+ SVGDocumentImpl *newDoc = doc->getDocumentFromHandle(newNode.ownerDocument().handle());
+
+ // Get some SVGElementImpl's
+ SVGElementImpl *nodeElement = doc->getElementFromHandle(node.handle());
+ SVGElementImpl *newNodeElement = newDoc->getElementFromHandle(newNode.handle());
+
+ // Import node into document
+ DOM::Node result = doc->importNode(newNode, true);
+
+ // Associate the imported node 'result' with the
+ // 'newNodeElement' which belongs to 'newDoc'
+ integrateTree(nodeElement, result, newNode, newNodeElement, doc);
+
+ // Correct handles in SVG* elements
+ correctHandles(nodeElement, result);
+
+ // Correct ownerDoc() etc..
+ correctDocument(nodeElement, newNode, newNodeElement, newDoc);
+
+ // Register ID in global map
+ registerAdditional(exec, doc, result);
+
+ // Recalc style
+ newNodeElement->setAttributes();
+
+ // Append + create + update element
+ Value retVal = getDOMNode(exec, node.appendChild(result));
+
+ doc->syncCachedMatrices();
+ newNodeElement->createItem(doc->canvas());
+ SVGHelperImpl::updateItem(exec, *newNodeElement);
+
+ return retVal;
+ }
+ else
+ {
+ Value retVal = getDOMNode(exec, node.appendChild(newNode));
+
+ // Get document
+ SVGDocumentImpl *doc = KSVG::Window::retrieveActive(exec)->doc();
+ doc->syncCachedMatrices();
+
+ // Get some SVGElementImpl's
+ SVGElementImpl *nodeElement = doc->getElementFromHandle(newNode.handle());
+ // TODO : extra check needed to see if the new elements parent is already appended
+ // in the doc. Not really nice, should be some other way? (Rob)
+ if(nodeElement && !nodeElement->parentNode().parentNode().isNull())
+ {
+ nodeElement->setAttributes(true);
+ nodeElement->createItem();
+ SVGHelperImpl::updateItem(exec, newNode);
+ }
+
+ return retVal;
+ }
+}
+
+Value SVGDOMNodeBridgeProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGDOMNodeBridge)
+ DOM::Node node = obj->impl();
+
+ switch(id)
+ {
+ case SVGDOMNodeBridge::InsertBefore:
+ {
+ DOM::Node newChild = toNode(args[0]);
+ DOM::Node beforeChild = toNode(args[1]);
+ Value retVal = getDOMNode(exec, node.insertBefore(newChild, beforeChild));
+
+ // Get document
+ SVGDocumentImpl *doc = Window::retrieveActive(exec)->doc();
+
+ // Get some SVGElementImpl's
+ SVGShapeImpl *newShape = dynamic_cast<SVGShapeImpl *>(doc->getElementFromHandle(newChild.handle()));
+ SVGElementImpl *newElement = doc->getElementFromHandle(newChild.handle());
+ SVGShapeImpl *beforeElement = dynamic_cast<SVGShapeImpl *>(doc->getElementFromHandle(beforeChild.handle()));
+ if(newShape && beforeElement && beforeElement->item())
+ {
+ int z = beforeElement->item()->zIndex();
+ newElement->createItem();
+ doc->canvas()->insert(newShape->item(), z);
+ }
+ SVGHelperImpl::updateItem(exec, newChild);
+
+ return retVal;
+ }
+ case SVGDOMNodeBridge::ReplaceChild:
+ {
+ DOM::Node newChild = toNode(args[0]);
+ Value retVal = getDOMNode(exec, node.replaceChild(newChild, toNode(args[1])));
+ SVGHelperImpl::updateItem(exec, newChild);
+ return retVal;
+ }
+ case SVGDOMNodeBridge::RemoveChild:
+ {
+ DOM::Node remove = toNode(args[0]);
+ if(remove.isNull())
+ return Undefined();
+
+ // New removeChild logic:
+ // - remove from DOM tree
+ // - delete element (also deletes it's child element's)
+ removeItem(exec, remove);
+ Value retVal = getDOMNode(exec, node.removeChild(remove));
+ return retVal;
+ }
+ case SVGDOMNodeBridge::AppendChild:
+ return appendHelper(exec, node, toNode(args[0]));
+ case SVGDOMNodeBridge::HasAttributes:
+ {
+ SVGDocumentImpl *doc = Window::retrieveActive(exec)->doc();
+ SVGElementImpl *element = doc->getElementFromHandle(node.handle());
+
+ if(!element)
+ return Undefined();
+
+ return Boolean(element->hasAttributes());
+ }
+ case SVGDOMNodeBridge::HasChildNodes:
+ return Boolean(node.hasChildNodes());
+ case SVGDOMNodeBridge::CloneNode:
+ {
+ SVGDocumentImpl *doc = Window::retrieveActive(exec)->doc();
+ SVGElementImpl *element = doc->getElementFromHandle(node.handle());
+ SVGElementImpl *newElement = element->cloneNode(args[0].toBoolean(exec));
+
+ return getDOMNode(exec, *newElement);
+ }
+ case SVGDOMNodeBridge::Normalize:
+ {
+ node.normalize();
+ return Undefined();
+ }
+ case SVGDOMNodeBridge::IsSupported:
+ return Boolean(node.isSupported(args[0].toString(exec).string(), args[1].toString(exec).string()));
+ case SVGDOMNodeBridge::AddEventListener:
+ {
+ SVGDocumentImpl *doc = Window::retrieveActive(exec)->doc();
+ SVGElementImpl *element = doc->getElementFromHandle(node.handle());
+
+ if(element)
+ {
+ SVGEvent::EventId eventId = SVGEvent::typeToId(args[0].toString(exec).string());
+ if(eventId != SVGEvent::UNKNOWN_EVENT)
+ element->setEventListener(eventId, new KSVGEcmaEventListener(Object::dynamicCast(args[1]), QString::null, doc->ecmaEngine()));
+ }
+ return Undefined();
+ }
+ case SVGDOMNodeBridge::RemoveEventListener:
+ {
+ SVGDocumentImpl *doc = Window::retrieveActive(exec)->doc();
+ SVGElementImpl *element = doc->getElementFromHandle(node.handle());
+
+ if(element)
+ {
+ SVGEvent::EventId eventId = SVGEvent::typeToId(args[0].toString(exec).string());
+ if(eventId != SVGEvent::UNKNOWN_EVENT)
+ element->removeEventListener((int) eventId);
+ }
+ return Undefined();
+ }
+// case SVGDOMNodeBridge::Contains: // TODO
+ case SVGDOMNodeBridge::GetNodeName:
+ return getString(node.nodeName());
+ case SVGDOMNodeBridge::GetNodeValue:
+ return getString(node.nodeValue());
+ case SVGDOMNodeBridge::GetNodeType:
+ return Number(node.nodeType());
+ case SVGDOMNodeBridge::GetParentNode:
+ return getDOMNode(exec, node.parentNode());
+ case SVGDOMNodeBridge::GetChildNodes:
+ return (new SVGDOMNodeListBridge(node.childNodes()))->cache(exec);
+ case SVGDOMNodeBridge::GetFirstChild:
+ return getDOMNode(exec, node.firstChild());
+ case SVGDOMNodeBridge::GetLastChild:
+ return getDOMNode(exec, node.lastChild());
+ case SVGDOMNodeBridge::GetPreviousSibling:
+ return getDOMNode(exec, node.previousSibling());
+ case SVGDOMNodeBridge::GetNextSibling:
+ return getDOMNode(exec, node.nextSibling());
+// case SVGDOMNodeBridge::GetAttributes: // TODO
+ case SVGDOMNodeBridge::GetNamespaceURI:
+ return getString(node.namespaceURI());
+ case SVGDOMNodeBridge::GetPrefix:
+ return getString(node.prefix());
+ case SVGDOMNodeBridge::GetLocalName:
+ return getString(node.localName());
+ case SVGDOMNodeBridge::GetOwnerDocument:
+ return getDOMNode(exec, node.ownerDocument());
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return Undefined();
+}
+
+// SVGDOMElementBridge
+
+/*
+@namespace KSVG
+@begin SVGDOMElementBridge::s_hashTable 2
+ tagName SVGDOMElementBridge::TagName DontDelete|ReadOnly
+@end
+@namespace KSVG
+@begin SVGDOMElementBridgeProto::s_hashTable 17
+ getAttribute SVGDOMElementBridge::GetAttribute DontDelete|Function 1
+ setAttribute SVGDOMElementBridge::SetAttribute DontDelete|Function 2
+ removeAttribute SVGDOMElementBridge::RemoveAttribute DontDelete|Function 1
+ getAttributeNode SVGDOMElementBridge::GetAttributeNode DontDelete|Function 1
+ setAttributeNode SVGDOMElementBridge::SetAttributeNode DontDelete|Function 2
+ removeAttributeNode SVGDOMElementBridge::RemoveAttributeNode DontDelete|Function 1
+ getElementsByTagName SVGDOMElementBridge::GetElementsByTagName DontDelete|Function 1
+ hasAttribute SVGDOMElementBridge::HasAttribute DontDelete|Function 1
+ getAttributeNS SVGDOMElementBridge::GetAttributeNS DontDelete|Function 2
+ setAttributeNS SVGDOMElementBridge::SetAttributeNS DontDelete|Function 3
+ removeAttributeNS SVGDOMElementBridge::RemoveAttributeNS DontDelete|Function 2
+ getAttributeNodeNS SVGDOMElementBridge::GetAttributeNodeNS DontDelete|Function 2
+ setAttributeNodeNS SVGDOMElementBridge::SetAttributeNodeNS DontDelete|Function 1
+ getElementByTagNameNS SVGDOMElementBridge::GetElementsByTagNameNS DontDelete|Function 2
+ hasAttributeNS SVGDOMElementBridge::HasAttributeNS DontDelete|Function 2
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("DOMElement", SVGDOMElementBridgeProto, SVGDOMElementBridgeProtoFunc)
+
+Value SVGDOMElementBridge::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case TagName:
+ return getString(m_impl.tagName());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+Value SVGDOMElementBridgeProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGDOMElementBridge)
+ DOM::Element elem = obj->impl();
+
+ switch(id)
+ {
+ case SVGDOMElementBridge::GetAttribute:
+ {
+ SVGDocumentImpl *doc = Window::retrieveActive(exec)->doc();
+ SVGElementImpl *element = doc->getElementFromHandle(elem.handle());
+ if(element)
+ return String(element->getAttribute(args[0].toString(exec).string()));
+ else
+ return Undefined();
+ }
+ case SVGDOMElementBridge::SetAttribute:
+ {
+ SVGDocumentImpl *doc = Window::retrieveActive(exec)->doc();
+ SVGElementImpl *element = doc->getElementFromHandle(elem.handle());
+ if(element)
+ {
+ element->setAttribute(args[0].toString(exec).string(), args[1].toString(exec).string());
+ element->setAttributeInternal(args[0].toString(exec).string(), args[1].toString(exec).string());
+
+ SVGHelperImpl::updateItem(exec, elem);
+ }
+
+ return Undefined();
+ }
+ case SVGDOMElementBridge::RemoveAttribute:
+ {
+ elem.removeAttribute(args[0].toString(exec).string());
+ return Undefined();
+ }
+ case SVGDOMElementBridge::GetAttributeNode:
+ return getDOMNode(exec, elem.getAttributeNode(args[0].toString(exec).string()));
+ case SVGDOMElementBridge::SetAttributeNode: // TODO: Correct?
+ return getDOMNode(exec, elem.setAttributeNode(toNode(args[0])));
+ case SVGDOMElementBridge::RemoveAttributeNode: // TODO: Correct?
+ return getDOMNode(exec, elem.removeAttributeNode(toNode(args[0])));
+ case SVGDOMElementBridge::GetElementsByTagName:
+ return (new SVGDOMNodeListBridge(elem.getElementsByTagName(args[0].toString(exec).string())))->cache(exec);
+ case SVGDOMElementBridge::GetAttributeNS:
+ {
+ // This just skips NS! (Rob)
+ SVGDocumentImpl *doc = Window::retrieveActive(exec)->doc();
+ SVGElementImpl *element = doc->getElementFromHandle(elem.handle());
+ if(element)
+ return String(element->getAttribute(args[1].toString(exec).string()));
+ else
+ return Undefined();
+ }
+ case SVGDOMElementBridge::SetAttributeNS:
+ {
+ // For now, we strip the NS part (Rob)
+ DOM::DOMString attr = args[1].toString(exec).string();
+ int pos = attr.string().find(':');
+ if(pos > -1)
+ attr = attr.string().mid(pos + 1);
+
+ SVGDocumentImpl *doc = Window::retrieveActive(exec)->doc();
+ SVGElementImpl *element = doc->getElementFromHandle(elem.handle());
+ if(element)
+ {
+ element->setAttribute(attr.string(), args[2].toString(exec).string());
+ element->setAttributeInternal(attr.string(), args[2].toString(exec).string());
+
+ SVGHelperImpl::updateItem(exec, *element);
+ }
+
+ return Undefined();
+ }
+ case SVGDOMElementBridge::RemoveAttributeNS:
+ {
+ elem.removeAttributeNS(args[0].toString(exec).string(), args[1].toString(exec).string());
+ return Undefined();
+ }
+ case SVGDOMElementBridge::GetAttributeNodeNS:
+ return getDOMNode(exec, elem.getAttributeNodeNS(args[0].toString(exec).string(), args[1].toString(exec).string()));
+ case SVGDOMElementBridge::SetAttributeNodeNS: // TODO: Correct?
+ return getDOMNode(exec, elem.setAttributeNodeNS(toNode(args[0])));
+ case SVGDOMElementBridge::GetElementsByTagNameNS:
+ return (new SVGDOMNodeListBridge(elem.getElementsByTagNameNS(args[0].toString(exec).string(), args[1].toString(exec).string())))->cache(exec);
+ case SVGDOMElementBridge::HasAttribute:
+ return Boolean(elem.hasAttribute(args[0].toString(exec).string()));
+ case SVGDOMElementBridge::HasAttributeNS:
+ return Boolean(elem.hasAttributeNS(args[0].toString(exec).string(), args[1].toString(exec).string()));
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return Undefined();
+}
+
+
+// SVGDOMNodeListBridge
+
+/*
+@namespace KSVG
+@begin SVGDOMNodeListBridge::s_hashTable 2
+ length SVGDOMNodeListBridge::Length DontDelete
+@end
+@namespace KSVG
+@begin SVGDOMNodeListBridgeProto::s_hashTable 3
+ getLength SVGDOMNodeListBridge::GetLength DontDelete|Function 0
+ item SVGDOMNodeListBridge::Item DontDelete|Function 1
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("DOMNodeList", SVGDOMNodeListBridgeProto, SVGDOMNodeListBridgeProtoFunc)
+
+Value SVGDOMNodeListBridge::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case Length:
+ return Number(m_impl.length());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+Value SVGDOMNodeListBridgeProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGDOMNodeListBridge)
+ DOM::NodeList nodeList = obj->impl();
+
+ switch(id)
+ {
+ case SVGDOMNodeListBridge::GetLength:
+ return Number(nodeList.length());
+ case SVGDOMNodeListBridge::Item:
+ return getDOMNode(exec, nodeList.item((unsigned long)args[0].toNumber(exec)));
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return Undefined();
+}
+
+// SVGDOMCharacterDataBridge
+
+/*
+@namespace KSVG
+@begin SVGDOMCharacterDataBridge::s_hashTable 3
+ data SVGDOMCharacterDataBridge::Data DontDelete
+ length SVGDOMCharacterDataBridge::Length DontDelete|ReadOnly
+@end
+@namespace KSVG
+@begin SVGDOMCharacterDataBridgeProto::s_hashTable 11
+ getData SVGDOMCharacterDataBridge::GetData DontDelete|Function 0
+ setData SVGDOMCharacterDataBridge::SetData DontDelete|Function 1
+ getLength SVGDOMCharacterDataBridge::GetLength DontDelete|Function 0
+ substringData SVGDOMCharacterDataBridge::SubstringData DontDelete|Function 2
+ appendData SVGDOMCharacterDataBridge::AppendData DontDelete|Function 1
+ insertData SVGDOMCharacterDataBridge::InsertData DontDelete|Function 2
+ deleteData SVGDOMCharacterDataBridge::DeleteData DontDelete|Function 2
+ replaceData SVGDOMCharacterDataBridge::ReplaceData DontDelete|Function 2
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("DOMCharacterData", SVGDOMCharacterDataBridgeProto, SVGDOMCharacterDataBridgeProtoFunc)
+
+Value SVGDOMCharacterDataBridge::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case Data:
+ return String(m_impl.data());
+ case Length:
+ return Number(m_impl.length());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGDOMCharacterDataBridge::putValueProperty(ExecState *exec, int token, const Value &value, int)
+{
+ switch(token)
+ {
+ case Data:
+ m_impl.setData(value.toString(exec).string());
+ updateTextItem(exec, m_impl);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+Value SVGDOMCharacterDataBridgeProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGDOMCharacterDataBridge)
+ DOM::CharacterData node = obj->impl();
+
+ switch(id)
+ {
+ case SVGDOMCharacterDataBridge::GetData:
+ return String(node.data());
+ case SVGDOMCharacterDataBridge::SetData:
+ node.setData(args[0].toString(exec).string());
+ updateTextItem(exec, node);
+ return Undefined();
+ case SVGDOMCharacterDataBridge::GetLength:
+ return Number(node.length());
+ case SVGDOMCharacterDataBridge::SubstringData:
+ {
+ DOM::DOMString ret = node.substringData(args[0].toInteger(exec), args[1].toInteger(exec));
+ updateTextItem(exec, node);
+ return String(ret);
+ }
+ case SVGDOMCharacterDataBridge::AppendData:
+ node.appendData(args[0].toString(exec).string());
+ updateTextItem(exec, node);
+ return Undefined();
+ case SVGDOMCharacterDataBridge::InsertData:
+ node.insertData(args[0].toInteger(exec), args[1].toString(exec).string());
+ updateTextItem(exec, node);
+ return Undefined();
+ case SVGDOMCharacterDataBridge::DeleteData:
+ node.deleteData(args[0].toInteger(exec), args[1].toInteger(exec));
+ updateTextItem(exec, node);
+ return Undefined();
+ case SVGDOMCharacterDataBridge::ReplaceData:
+ node.replaceData(args[0].toInteger(exec), args[1].toInteger(exec), args[2].toString(exec).string());
+ updateTextItem(exec, node);
+ return Undefined();
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return Undefined();
+}
+
+// SVGDOMTextBridge
+
+/*
+@namespace KSVG
+@begin SVGDOMTextBridge::s_hashTable 2
+ dummy SVGDOMTextBridge::Dummy DontDelete|ReadOnly
+@end
+@namespace KSVG
+@begin SVGDOMTextBridgeProto::s_hashTable 2
+ splitText SVGDOMTextBridge::SplitText DontDelete|Function 1
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("DOMText", SVGDOMTextBridgeProto, SVGDOMTextBridgeProtoFunc)
+
+Value SVGDOMTextBridge::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+Value SVGDOMTextBridgeProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGDOMTextBridge)
+ DOM::Text node = obj->impl();
+
+ switch(id)
+ {
+ case SVGDOMTextBridge::SplitText:
+ return getDOMNode(exec, node.splitText(args[0].toInteger(exec)));
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return Undefined();
+}
+
+// SVGDOMDOMImplementationBridge
+
+/*
+@namespace KSVG
+@begin SVGDOMDOMImplementationBridge::s_hashTable 2
+ dummy SVGDOMDOMImplementationBridge::Dummy DontDelete|ReadOnly
+@end
+@namespace KSVG
+@begin SVGDOMDOMImplementationBridgeProto::s_hashTable 2
+ hasFeature SVGDOMDOMImplementationBridge::HasFeature DontDelete|Function 2
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("DOMDOMImplementation", SVGDOMDOMImplementationBridgeProto, SVGDOMDOMImplementationBridgeProtoFunc)
+
+Value SVGDOMDOMImplementationBridge::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+Value SVGDOMDOMImplementationBridgeProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGDOMDOMImplementationBridge)
+ DOM::DOMImplementation node = obj->impl();
+
+ switch(id)
+ {
+ case SVGDOMDOMImplementationBridge::HasFeature:
+ return Boolean(node.hasFeature(args[0].toString(exec).string(), args[1].toString(exec).string()));
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return Undefined();
+}
+
+// SVGDOMDocumentFragmentBridge
+
+/*
+@namespace KSVG
+@begin SVGDOMDocumentFragmentBridge::s_hashTable 2
+ dummy SVGDOMDocumentFragmentBridge::Dummy DontDelete|ReadOnly
+@end
+*/
+
+Value SVGDOMDocumentFragmentBridge::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGEcma.h b/ksvg/impl/SVGEcma.h
new file mode 100644
index 00000000..adf1ec85
--- /dev/null
+++ b/ksvg/impl/SVGEcma.h
@@ -0,0 +1,250 @@
+/*
+ Copyright (C) 2002-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGEcma_H
+#define SVGEcma_H
+
+#include <dom/dom_doc.h>
+#include <dom/dom_node.h>
+#include <dom/dom_text.h>
+#include <dom/dom_element.h>
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+// Access DOM::Node via js
+class SVGDOMNodeBridge
+{
+public:
+ SVGDOMNodeBridge(DOM::Node impl) : m_impl(impl) { KSVG_EMPTY_FLAGS }
+ virtual ~SVGDOMNodeBridge() { }
+
+ DOM::Node impl() const { return m_impl; }
+
+ KSVG_BASECLASS_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ NodeName, NodeValue, NodeType, ParentNode,
+ ChildNodes, FirstChild, LastChild, PreviousSibling,
+ NextSibling, Attributes, NamespaceURI, Prefix,
+ LocalName, OwnerDocument,
+ // Functions
+ InsertBefore, ReplaceChild, RemoveChild, AppendChild,
+ HasAttributes, HasChildNodes, CloneNode, Normalize,
+ IsSupported, AddEventListener, RemoveEventListener, Contains,
+ GetNodeName, GetNodeValue, GetNodeType, GetParentNode,
+ GetChildNodes, GetFirstChild, GetLastChild, GetPreviousSibling,
+ GetNextSibling, GetAttributes, GetNamespaceURI, GetPrefix,
+ GetLocalName, GetOwnerDocument
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+
+private:
+ DOM::Node m_impl;
+};
+
+// Access DOM::Element via js
+class SVGDOMElementBridge : public SVGDOMNodeBridge
+{
+public:
+ SVGDOMElementBridge(DOM::Element impl) : SVGDOMNodeBridge(static_cast<DOM::Node>(impl)), m_impl(impl) { }
+ ~SVGDOMElementBridge() { }
+
+ DOM::Element impl() const { return m_impl; }
+
+ KSVG_GET
+ KSVG_FORWARDPUT
+
+ enum
+ {
+ // Properties
+ TagName,
+ // Functions
+ GetAttribute, SetAttribute, RemoveAttribute, GetAttributeNode,
+ SetAttributeNode, RemoveAttributeNode, GetElementsByTagName,
+ GetAttributeNS, SetAttributeNS, RemoveAttributeNS, GetAttributeNodeNS,
+ SetAttributeNodeNS, GetElementsByTagNameNS, HasAttribute, HasAttributeNS
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+
+private:
+ DOM::Element m_impl;
+};
+
+// Access DOM::NodeList via js
+class SVGDOMNodeListBridge
+{
+public:
+ SVGDOMNodeListBridge(DOM::NodeList impl) : m_impl(impl) { }
+ ~SVGDOMNodeListBridge() { }
+
+ DOM::NodeList impl() const { return m_impl; }
+
+ KSVG_GET
+
+ enum
+ {
+ // Properties
+ Length,
+ // Functions
+ GetLength, Item
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+
+private:
+ DOM::NodeList m_impl;
+};
+
+// Access DOM::CharacterData via js
+class SVGDOMCharacterDataBridge : public SVGDOMNodeBridge
+{
+public:
+ SVGDOMCharacterDataBridge(DOM::CharacterData impl) : SVGDOMNodeBridge(static_cast<DOM::Node>(impl)), m_impl(impl) { KSVG_EMPTY_FLAGS }
+ ~SVGDOMCharacterDataBridge() { }
+
+ DOM::CharacterData impl() const { return m_impl; }
+
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ Data, Length,
+ // Functions
+ GetData, SetData, GetLength,
+ SubstringData, AppendData, InsertData, DeleteData, ReplaceData
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+
+private:
+ DOM::CharacterData m_impl;
+};
+
+// Access DOM::Text via js
+class SVGDOMTextBridge : public SVGDOMCharacterDataBridge
+{
+public:
+ SVGDOMTextBridge(DOM::Text impl) : SVGDOMCharacterDataBridge(static_cast<DOM::CharacterData>(impl)), m_impl(impl) { }
+ ~SVGDOMTextBridge() { }
+
+ DOM::Text impl() const { return m_impl; }
+
+ KSVG_GET
+ KSVG_FORWARDPUT
+
+ enum
+ {
+ // Properties
+ Dummy,
+ // Functions
+ SplitText
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+
+private:
+ DOM::Text m_impl;
+};
+
+// Access DOM::DOMImplementation via js
+class SVGDOMDOMImplementationBridge
+{
+public:
+ SVGDOMDOMImplementationBridge(DOM::DOMImplementation impl) : m_impl(impl) { }
+ ~SVGDOMDOMImplementationBridge() { }
+
+ DOM::DOMImplementation impl() const { return m_impl; }
+
+ KSVG_GET
+ KSVG_FORWARDPUT
+
+ enum
+ {
+ // Properties
+ Dummy,
+ // Functions
+ HasFeature
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+
+private:
+ DOM::DOMImplementation m_impl;
+};
+
+// Access DOM::DocumentFragment via js
+class SVGDOMDocumentFragmentBridge : public SVGDOMNodeBridge
+{
+public:
+ SVGDOMDocumentFragmentBridge(DOM::DocumentFragment impl) : SVGDOMNodeBridge(static_cast<DOM::Node>(impl)), m_impl(impl) { }
+ ~SVGDOMDocumentFragmentBridge() { }
+
+ DOM::DocumentFragment impl() const { return m_impl; }
+
+ KSVG_GET
+ KSVG_FORWARDPUT
+
+ enum
+ {
+ // Properties
+ Dummy
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+
+private:
+ DOM::DocumentFragment m_impl;
+};
+
+}
+
+KSVG_DEFINE_PROTOTYPE(SVGDOMNodeBridgeProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGDOMNodeBridgeProtoFunc, SVGDOMNodeBridge)
+
+KSVG_DEFINE_PROTOTYPE(SVGDOMElementBridgeProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGDOMElementBridgeProtoFunc, SVGDOMElementBridge)
+
+KSVG_DEFINE_PROTOTYPE(SVGDOMNodeListBridgeProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGDOMNodeListBridgeProtoFunc, SVGDOMNodeListBridge)
+
+KSVG_DEFINE_PROTOTYPE(SVGDOMCharacterDataBridgeProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGDOMCharacterDataBridgeProtoFunc, SVGDOMCharacterDataBridge)
+
+KSVG_DEFINE_PROTOTYPE(SVGDOMTextBridgeProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGDOMTextBridgeProtoFunc, SVGDOMTextBridge)
+
+KSVG_DEFINE_PROTOTYPE(SVGDOMDOMImplementationBridgeProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGDOMDOMImplementationBridgeProtoFunc, SVGDOMDOMImplementationBridge)
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGElementImpl.cc b/ksvg/impl/SVGElementImpl.cc
new file mode 100644
index 00000000..2f3d70c6
--- /dev/null
+++ b/ksvg/impl/SVGElementImpl.cc
@@ -0,0 +1,713 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qxml.h>
+
+#include <kdebug.h>
+
+#include "SVGEvent.h"
+#include "SVGEventImpl.h"
+#include "SVGHelperImpl.h"
+#include "SVGElementImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+
+using namespace KSVG;
+
+#include "SVGElementImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_ecma.h"
+
+SVGElementImpl::Factory *SVGElementImpl::Factory::m_instance = 0;
+
+SVGElementImpl::SVGElementImpl(DOM::ElementImpl *impl) : DOM::DomShared(), DOM::Element(impl), SVGDOMElementBridge(static_cast<DOM::Element>(*this))
+{
+ KSVG_EMPTY_FLAGS
+
+ m_ownerSVGElement = 0;
+ m_viewportElement = 0;
+ m_ownerDoc = 0;
+
+ m_mouseOver = false;
+ m_focus = false;
+
+ m_eventListeners.setAutoDelete(true);
+ m_attributes.setAutoDelete(true);
+}
+
+SVGElementImpl::~SVGElementImpl()
+{
+ if(m_ownerSVGElement)
+ m_ownerSVGElement->deref();
+}
+
+void SVGElementImpl::setEventListener(int id, SVGEventListener *listener)
+{
+ if(listener)
+ listener->ref();
+
+ removeEventListener(id);
+
+ if(listener)
+ {
+ SVGRegisteredEventListener *rl = new SVGRegisteredEventListener(static_cast<SVGEvent::EventId>(id), listener, false);
+ m_eventListeners.append(rl);
+
+ listener->deref();
+ }
+}
+
+int SVGElementImpl::getEventListeners(bool local)
+{
+ int events = 0;
+
+ QPtrListIterator<SVGRegisteredEventListener> it(m_eventListeners);
+ for(; it.current(); ++it)
+ events |= (1 << it.current()->id);
+
+ if(local)
+ return events;
+
+ for(DOM::Node node = parentNode(); !node.isNull(); node = node.parentNode())
+ {
+ SVGElementImpl *element = ownerDoc()->getElementFromHandle(node.handle());
+
+ if(element)
+ {
+ QPtrListIterator<SVGRegisteredEventListener> it(element->m_eventListeners);
+ for(; it.current(); ++it)
+ events |= (1 << it.current()->id);
+ }
+ }
+
+ return events;
+}
+
+void SVGElementImpl::setupEventListeners(SVGDocumentImpl *doc, SVGDocumentImpl *newDoc)
+{
+ if(!doc || !newDoc)
+ return;
+
+ // Changes the document where the eventlisteners are registered
+ // Needed for parseXML'ed elements with events, their listeners
+ // are created in the temporary document fragment and need to be
+ // registered in the main document (Niko)
+ QPtrListIterator<SVGRegisteredEventListener> it(m_eventListeners);
+ for(; it.current(); ++it)
+ {
+ SVGRegisteredEventListener *current = it.current();
+
+ QString valueOfCurrent = newDoc->ecmaEngine()->valueOfEventListener(current->listener);
+ setEventListener(current->id, doc->createEventListener(valueOfCurrent));
+ }
+}
+
+bool SVGElementImpl::hasEventListener(int id, bool local)
+{
+ // First check if we have the listener, locally
+ QPtrListIterator<SVGRegisteredEventListener> it(m_eventListeners);
+ for(; it.current(); ++it)
+ {
+ if(it.current()->id == id)
+ return true;
+ }
+
+ // We have no local listeners, if we are just interessted
+ // in those listeners, then return now...
+ if(local)
+ return false;
+
+ // Check every parent element
+ for(DOM::Node node = parentNode(); !node.isNull(); node = node.parentNode())
+ {
+ SVGElementImpl *element = ownerDoc()->getElementFromHandle(node.handle());
+
+ if(element)
+ {
+ QPtrListIterator<SVGRegisteredEventListener> it(element->m_eventListeners);
+ for(; it.current(); ++it)
+ {
+ if(it.current()->id == id)
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+void SVGElementImpl::removeEventListener(int id)
+{
+ QPtrListIterator<SVGRegisteredEventListener> it(m_eventListeners);
+ for(; it.current(); ++it)
+ {
+ if(it.current()->id == id)
+ {
+ m_eventListeners.removeRef(it.current());
+ break;
+ }
+ }
+}
+
+void SVGElementImpl::handleLocalEvents(SVGEventImpl *evt, bool useCapture)
+{
+ QPtrListIterator<SVGRegisteredEventListener> it(m_eventListeners);
+ for(; it.current(); ++it)
+ {
+ if(it.current()->id == evt->id() && it.current()->useCapture == useCapture)
+ {
+ it.current()->listener->handleEvent(evt);
+ break;
+ }
+ }
+}
+
+void SVGElementImpl::defaultEventHandler(SVGEventImpl *)
+{
+}
+
+/*
+@namespace KSVG
+@begin SVGElementImpl::s_hashTable 23
+ id SVGElementImpl::ElementId DontDelete
+ ownerSVGElement SVGElementImpl::OwnerSvgElement DontDelete|ReadOnly
+ viewportElement SVGElementImpl::ViewportElement DontDelete|ReadOnly
+ xmlbase SVGElementImpl::XmlBase DontDelete
+ base SVGElementImpl::XmlBase DontDelete
+ onmouseup SVGElementImpl::OnMouseUp DontDelete
+ onmousedown SVGElementImpl::OnMouseDown DontDelete
+ onmousemove SVGElementImpl::OnMouseMove DontDelete
+ onmouseover SVGElementImpl::OnMouseOver DontDelete
+ onmouseout SVGElementImpl::OnMouseOut DontDelete
+ onclick SVGElementImpl::OnClick DontDelete
+ onmouseclick SVGElementImpl::OnClick DontDelete
+ onactivate SVGElementImpl::OnActivate DontDelete
+ onkeydown SVGElementImpl::OnKeyDown DontDelete
+ onkeyup SVGElementImpl::OnKeyUp DontDelete
+ onkeypress SVGElementImpl::OnKeyPress DontDelete
+ onload SVGElementImpl::OnLoad DontDelete
+ onfocusin SVGElementImpl::OnFocusIn DontDelete
+ onfocusout SVGElementImpl::OnFocusOut DontDelete
+ onerror SVGElementImpl::OnError DontDelete
+ onabort SVGElementImpl::OnAbort DontDelete
+@end
+@namespace KSVG
+@begin SVGElementImplProto::s_hashTable 5
+ getStyle SVGElementImpl::GetStyle DontDelete|Function 0
+ setProperty SVGElementImpl::SetProperty DontDelete|Function 2
+ getPropertyValue SVGElementImpl::GetPropertyValue DontDelete|Function 1
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGElement", SVGElementImplProto, SVGElementImplProtoFunc)
+
+Value SVGElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case ElementId:
+ return String(id().string());
+ case XmlBase:
+ return String(xmlbase().string());
+ case OwnerSvgElement:
+ return getDOMNode(exec, *ownerSVGElement());
+ case ViewportElement:
+ return getDOMNode(exec, *viewportElement());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int)
+{
+ switch(token)
+ {
+ case ElementId:
+ setId(value.toString(exec).string());
+ break;
+ case XmlBase:
+ setXmlbase(value.toString(exec).string());
+ break;
+ case OnMouseUp:
+ setEventListener(SVGEvent::MOUSEUP_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string()));
+ break;
+ case OnMouseDown:
+ setEventListener(SVGEvent::MOUSEDOWN_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string()));
+ break;
+ case OnMouseMove:
+ setEventListener(SVGEvent::MOUSEMOVE_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string()));
+ break;
+ case OnMouseOver:
+ setEventListener(SVGEvent::MOUSEOVER_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string()));
+ break;
+ case OnMouseOut:
+ setEventListener(SVGEvent::MOUSEOUT_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string()));
+ break;
+ case OnClick:
+ setEventListener(SVGEvent::CLICK_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string()));
+ break;
+ case OnActivate:
+ setEventListener(SVGEvent::DOMACTIVATE_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string()));
+ break;
+ case OnKeyDown:
+ setEventListener(SVGEvent::KEYDOWN_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string()));
+ break;
+ case OnKeyUp:
+ setEventListener(SVGEvent::KEYUP_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string()));
+ break;
+ case OnKeyPress:
+ setEventListener(SVGEvent::KEYPRESS_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string()));
+ break;
+ case OnLoad:
+ setEventListener(SVGEvent::LOAD_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string()));
+ break;
+ case OnFocusIn:
+ setEventListener(SVGEvent::DOMFOCUSIN_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string()));
+ break;
+ case OnFocusOut:
+ setEventListener(SVGEvent::DOMFOCUSOUT_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string()));
+ break;
+ case OnError:
+ setEventListener(SVGEvent::ERROR_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string()));
+ break;
+ case OnAbort:
+ setEventListener(SVGEvent::ABORT_EVENT, m_ownerDoc->createEventListener(value.toString(exec).string()));
+ break;
+ default:
+ kdWarning() << k_funcinfo << "unhandled token " << token << endl;
+ }
+}
+
+Value SVGElementImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGElementImpl)
+
+ switch(id)
+ {
+ case SVGElementImpl::GetStyle:
+ return obj->cache(exec);
+ case SVGElementImpl::SetProperty:
+ {
+ DOM::DOMString attribute = args[0].toString(exec).qstring().lower();
+ DOM::DOMString value = args[1].toString(exec).qstring();
+ obj->setAttribute(attribute, value);
+ break;
+ }
+ case SVGElementImpl::GetPropertyValue:
+ return String(obj->getAttribute(args[0].toString(exec).qstring()));
+ default:
+ break;
+ }
+
+ return Undefined();
+}
+
+QDict<DOM::DOMString> &SVGElementImpl::attributes()
+{
+ return m_attributes;
+}
+
+// khtml overrides
+void SVGElementImpl::setAttribute(const DOM::DOMString &name, const DOM::DOMString &value)
+{
+ m_attributes.replace(name.string(), new DOM::DOMString(value));
+}
+
+// Changes internal value. This will have no effect on getAttribute().
+void SVGElementImpl::setAttributeInternal(const DOM::DOMString &name, const DOM::DOMString &value)
+{
+ ExecState *exec = ownerDoc()->ecmaEngine()->globalExec();
+
+ static_cast<KSVGScriptInterpreter *>(exec->interpreter())->setAttributeSetMode(true);
+ bridge(exec)->put(exec, Identifier(UString(name)), String(value), KJS::Internal);
+ static_cast<KSVGScriptInterpreter *>(exec->interpreter())->setAttributeSetMode(false);
+}
+
+// This gets the actual attribute as set in the svg source
+DOM::DOMString SVGElementImpl::getAttribute(const DOM::DOMString &name) const
+{
+ DOM::DOMString *result = m_attributes[name.string()];
+ if(result)
+ return *result;
+ else
+ return DOM::DOMString();
+}
+
+// This gets the internal, real-time value. This means it can return a default value
+// for an attribute even if its not explicitly set in the svg source.
+DOM::DOMString SVGElementImpl::getAttributeInternal(const DOM::DOMString &name)
+{
+ ExecState *exec = ownerDoc()->ecmaEngine()->globalExec();
+
+ DOM::DOMString retVal;
+
+ static_cast<KSVGScriptInterpreter *>(exec->interpreter())->setAttributeGetMode(true);
+ retVal = bridge(exec)->get(exec, Identifier(UString(name))).toString(exec).string();
+ static_cast<KSVGScriptInterpreter *>(exec->interpreter())->setAttributeGetMode(false);
+
+ return retVal;
+}
+
+bool SVGElementImpl::hasAttribute(const DOM::DOMString &name)
+{
+ return m_attributes.find(name.string()) != 0;
+}
+
+bool SVGElementImpl::hasAttributes()
+{
+ return m_attributes.count() > 0;
+}
+
+void SVGElementImpl::setApplyAttribute(const QString &name, const QString &value)
+{
+ if(hasAttribute(name))
+ {
+ QString cur = getAttribute(name).string();
+ cur = cur.simplifyWhiteSpace();
+
+ if(!cur.endsWith(";"))
+ cur += "; ";
+
+ cur += value;
+
+ setAttribute(name, cur);
+ }
+ else
+ setAttribute(name, value);
+}
+
+void SVGElementImpl::setId(DOM::DOMString id)
+{
+ setAttribute("id", id);
+
+ if(ownerDoc() && ownerDoc()->rootElement() && !id.isEmpty())
+ ownerDoc()->rootElement()->addToIdMap(id.string(), this);
+ else if(m_ownerSVGElement && !id.isEmpty())
+ m_ownerSVGElement->addToIdMap(id.string(), this);
+}
+
+DOM::DOMString SVGElementImpl::id() const
+{
+ return getAttribute("id");
+}
+
+void SVGElementImpl::setXmlbase(DOM::DOMString xmlbase)
+{
+ setAttribute("xml:base", xmlbase);
+}
+
+DOM::DOMString SVGElementImpl::xmlbase() const
+{
+ return getAttribute("xml:base");
+}
+
+void SVGElementImpl::setOwnerSVGElement(SVGSVGElementImpl *owner)
+{
+ if(m_ownerSVGElement)
+ m_ownerSVGElement->deref();
+
+ m_ownerSVGElement = owner;
+
+ if(m_ownerSVGElement)
+ m_ownerSVGElement->ref();
+}
+
+void SVGElementImpl::setViewportElement(SVGElementImpl *viewport)
+{
+ if(m_viewportElement)
+ m_viewportElement->deref();
+
+ m_viewportElement = viewport;
+
+ if(m_viewportElement)
+ m_viewportElement->ref();
+}
+
+SVGSVGElementImpl *SVGElementImpl::ownerSVGElement() const
+{
+ return m_ownerSVGElement;
+}
+
+SVGElementImpl *SVGElementImpl::viewportElement() const
+{
+ return m_viewportElement;
+}
+
+void SVGElementImpl::setAttributes(const QXmlAttributes &attrs)
+{
+ for(int i = 0; i < attrs.length(); i++)
+ {
+ setAttribute(attrs.localName(i), attrs.value(i));
+ setAttributeInternal(attrs.localName(i), attrs.value(i));
+ }
+
+ setAttributes();
+}
+
+void SVGElementImpl::setAttributes()
+{
+ // Finalize style
+ SVGStylableImpl *style = dynamic_cast<SVGStylableImpl *>(this);
+
+ if(style)
+ style->processStyle();
+}
+
+void SVGElementImpl::setAttributes(bool deep)
+{
+ // Finalize style
+ SVGStylableImpl *style = dynamic_cast<SVGStylableImpl *>(this);
+
+ if(style)
+ style->processStyle();
+
+ if(deep)
+ {
+ if(hasChildNodes())
+ {
+ DOM::Node n;
+ for(n = firstChild(); !n.isNull(); n = n.nextSibling())
+ {
+ SVGElementImpl *elem = ownerDoc()->getElementFromHandle(n.handle());
+ if(elem)
+ elem->setAttributes(true);
+ }
+ }
+ }
+}
+
+bool SVGElementImpl::prepareMouseEvent(const QPoint &p, const QPoint &a, SVGMouseEventImpl *mev)
+{
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(this);
+ if(shape)
+ return shape->prepareMouseEvent(p, a, mev);
+
+ return false;
+}
+
+bool SVGElementImpl::dispatchEvent(int id, bool canBubbleArg, bool cancelableArg)
+{
+ SVGEventImpl *evt = new SVGEventImpl(static_cast<SVGEvent::EventId>(id), canBubbleArg, cancelableArg);
+
+ evt->ref();
+ bool ret = dispatchEvent(evt, true);
+ evt->deref();
+
+ return ret;
+}
+
+bool SVGElementImpl::dispatchEvent(SVGEventImpl *evt, bool tempEvent)
+{
+ evt->setTarget(this);
+
+ // Find out, where to send to -> collect parent nodes
+ QPtrList<SVGElementImpl> nodeChain;
+
+ for(DOM::Element e = *this; !e.isNull(); e = e.parentNode())
+ nodeChain.prepend(ownerDoc()->getElementFromHandle(e.handle()));
+
+ // Trigger any capturing event handlers on our way down
+ evt->setEventPhase(DOM::Event::CAPTURING_PHASE);
+
+ QPtrListIterator<SVGElementImpl> it(nodeChain);
+ for(; it.current() && it.current() != this && !evt->propagationStopped(); ++it)
+ {
+ evt->setCurrentTarget(it.current());
+
+ if(it.current())
+ it.current()->handleLocalEvents(evt, true);
+ }
+
+ // Dispatch to the actual target node
+ it.toLast();
+ if(!evt->propagationStopped())
+ {
+ evt->setEventPhase(DOM::Event::AT_TARGET);
+ evt->setCurrentTarget(it.current());
+
+ if(it.current())
+ it.current()->handleLocalEvents(evt, false);
+ }
+
+ --it;
+
+ // Bubble up again
+ if(evt->bubbles())
+ {
+ evt->setEventPhase(DOM::Event::BUBBLING_PHASE);
+ for(; it.current() && !evt->propagationStopped(); --it)
+ {
+ evt->setCurrentTarget(it.current());
+
+ if(it.current())
+ it.current()->handleLocalEvents(evt, false);
+ }
+ }
+
+ evt->setCurrentTarget(0);
+ evt->setEventPhase(0); // I guess this is correct, the spec does not seem to say
+ // anything about the default event handler phase.
+
+ if(evt->bubbles())
+ {
+ // now we call all default event handlers (this is not part of DOM - it is internal to ksvg)
+ it.toLast();
+ for(; it.current() && !evt->propagationStopped() && !evt->defaultPrevented() && !evt->defaultHandled(); --it)
+ it.current()->defaultEventHandler(evt);
+ }
+
+ // If tempEvent is true, this means that the DOM implementation will not be storing a reference to the event, i.e.
+ // there is no way to retrieve it from javascript if a script does not already have a reference to it in a variable.
+ // So there is no need for the interpreter to keep the event in its cache
+ if(tempEvent)
+ ownerDoc()->ecmaEngine()->finishedWithEvent(evt);
+
+ return !evt->defaultPrevented(); // ### what if defaultPrevented was called before dispatchEvent?
+}
+
+bool SVGElementImpl::dispatchKeyEvent(QKeyEvent *ke)
+{
+ DOM::AbstractView temp;
+
+ SVGEvent::EventId evtId = SVGEvent::UNKNOWN_EVENT;
+
+ if(ke->type() == QEvent::KeyRelease && !ke->isAutoRepeat())
+ evtId = SVGEvent::KEYUP_EVENT;
+ else if(ke->isAutoRepeat())
+ evtId = SVGEvent::KEYPRESS_EVENT;
+ else if(ke->type() == QEvent::KeyPress)
+ evtId = SVGEvent::KEYDOWN_EVENT;
+
+ if(evtId == SVGEvent::KEYUP_EVENT && hasEventListener(SVGEvent::DOMACTIVATE_EVENT, false))
+ dispatchEvent(SVGEvent::DOMACTIVATE_EVENT, true, true);
+
+ if(!hasEventListener(evtId, false))
+ return false;
+
+ SVGEventImpl *evt = new SVGKeyEventImpl(ke, temp, evtId);
+
+ evt->ref();
+ bool ret = dispatchEvent(evt, true);
+ evt->deref();
+
+ // Rerender now! Once! (Niko)
+ ownerDoc()->rerender();
+
+ return ret;
+}
+
+bool SVGElementImpl::dispatchMouseEvent(int id, bool canBubbleArg, bool cancelableArg, long detailArg, long screenXArg, long screenYArg, long clientXArg, long clientYArg, bool ctrlKeyArg, bool altKeyArg, bool shiftKeyArg, bool metaKeyArg, unsigned short buttonArg, SVGElementImpl *relatedTargetArg)
+{
+ DOM::AbstractView temp;
+
+ SVGEventImpl *evt = new SVGMouseEventImpl(static_cast<SVGEvent::EventId>(id),
+ canBubbleArg, cancelableArg, temp, detailArg,
+ screenXArg, screenYArg,
+ clientXArg, clientYArg,
+ ctrlKeyArg, altKeyArg, shiftKeyArg, metaKeyArg,
+ buttonArg, relatedTargetArg);
+
+ evt->ref();
+ bool ret = dispatchEvent(evt, true);
+ evt->deref();
+
+ return ret;
+}
+
+void SVGElementImpl::setOwnerDoc(SVGDocumentImpl *doc)
+{
+ if(m_ownerDoc)
+ m_ownerDoc->removeFromElemDict(handle());
+
+ m_ownerDoc = doc;
+
+ if(m_ownerDoc)
+ m_ownerDoc->addToElemDict(handle(), this);
+}
+
+SVGDocumentImpl *SVGElementImpl::ownerDoc() const
+{
+ return m_ownerDoc;
+}
+
+SVGElementImpl *SVGElementImpl::cloneNode(bool deep)
+{
+ DOM::Element impl = static_cast<DOM::Document *>(ownerDoc())->createElementNS("", tagName());
+ SVGElementImpl *newElement = SVGDocumentImpl::createElement(tagName(), impl.cloneNode(false), ownerDoc());
+ newElement->setOwnerSVGElement(ownerSVGElement());
+ newElement->setViewportElement(viewportElement());
+
+ SVGHelperImpl::copyAttributes(this, newElement);
+
+ // Recalc style
+ //newElement->setAttributes();
+
+ if(deep)
+ cloneChildNodes(newElement);
+
+ return newElement;
+}
+
+void SVGElementImpl::cloneChildNodes(SVGElementImpl *clone)
+{
+ DOM::Node n;
+ for(n = firstChild(); !n.isNull(); n = n.nextSibling())
+ {
+ SVGElementImpl *elem = ownerDoc()->getElementFromHandle(n.handle());
+ if(elem)
+ clone->appendChild(*elem->cloneNode(true));
+ else if(n.nodeType() == DOM::Node::TEXT_NODE)
+ clone->appendChild(n.cloneNode(true));
+ }
+}
+
+void SVGElementImpl::gotError(const QString &errorDesc)
+{
+ if(ownerDoc())
+ {
+ ownerDoc()->finishParsing(true, errorDesc);
+ if(hasEventListener(SVGEvent::ERROR_EVENT, true))
+ dispatchEvent(SVGEvent::ERROR_EVENT, false, false);
+ }
+}
+
+QString SVGElementImpl::collectText()
+{
+ QString text;
+
+ if(hasChildNodes())
+ {
+ DOM::Node node = firstChild();
+
+ for(; !node.isNull(); node = node.nextSibling())
+ {
+ if(node.nodeType() == DOM::Node::TEXT_NODE)
+ {
+ DOM::Text textNode = node;
+ text += textNode.data().string();
+ }
+ }
+ }
+
+ return text;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGElementImpl.h b/ksvg/impl/SVGElementImpl.h
new file mode 100644
index 00000000..c69a83e8
--- /dev/null
+++ b/ksvg/impl/SVGElementImpl.h
@@ -0,0 +1,229 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGElementImpl_H
+#define SVGElementImpl_H
+
+#include <map>
+#include <string>
+
+#include <qdict.h>
+#include <qptrlist.h>
+
+#include <dom/dom_string.h>
+
+#include "SVGEcma.h"
+
+#include "ksvg_lookup.h"
+
+class QKeyEvent;
+class QXmlAttributes;
+
+namespace KJS
+{
+ class Value;
+ class UString;
+ class ExecState;
+}
+
+namespace KSVG
+{
+
+class KSVGCanvas;
+class SVGEventImpl;
+class SVGDocumentImpl;
+class SVGEventListener;
+class SVGSVGElementImpl;
+class SVGMouseEventImpl;
+class SVGRegisteredEventListener;
+class SVGElementImpl : virtual public DOM::DomShared,
+ public DOM::Element,
+ public SVGDOMElementBridge
+{
+public:
+ SVGElementImpl(DOM::ElementImpl *impl);
+ virtual ~SVGElementImpl();
+
+ // Attribute setting
+ // "Override" khtml's functions with ours
+ void setAttribute(const DOM::DOMString &name, const DOM::DOMString &value);
+ void setAttributeInternal(const DOM::DOMString &name, const DOM::DOMString &value);
+ DOM::DOMString getAttribute(const DOM::DOMString &name) const;
+ DOM::DOMString getAttributeInternal(const DOM::DOMString &name);
+ bool hasAttribute(const DOM::DOMString &name);
+ bool hasAttributes();
+
+ QDict<DOM::DOMString> &attributes();
+ void setApplyAttribute(const QString &name, const QString &value);
+
+ void setId(DOM::DOMString);
+ DOM::DOMString id() const;
+
+ void setXmlbase(DOM::DOMString);
+ DOM::DOMString xmlbase() const;
+
+ void setOwnerSVGElement(SVGSVGElementImpl *owner);
+ void setViewportElement(SVGElementImpl *viewport);
+
+ SVGSVGElementImpl *ownerSVGElement() const;
+ SVGElementImpl *viewportElement() const;
+
+ void setAttributes(const QXmlAttributes &);
+ virtual void setAttributes();
+ void setAttributes(bool deep);
+
+ QString collectText();
+
+ void setOwnerDoc(SVGDocumentImpl *doc);
+ SVGDocumentImpl *ownerDoc() const;
+
+ virtual SVGElementImpl *cloneNode(bool deep);
+ void cloneChildNodes(SVGElementImpl *clone);
+
+ // Event stuff
+ bool dispatchEvent(int id, bool canBubbleArg, bool cancelableArg);
+ bool dispatchEvent(SVGEventImpl *evt, bool tempEvent);
+ bool dispatchMouseEvent(int id, bool canBubbleArg, bool cancelableArg, long detailArg, long screenXArg, long screenYArg, long clientXArg, long clientYArg, bool ctrlKeyArg, bool altKeyArg, bool shiftKeyArg, bool metaKeyArg, unsigned short buttonArg, SVGElementImpl *relatedTargetArg);
+ bool dispatchKeyEvent(QKeyEvent *ke);
+
+ void setEventListener(int id, SVGEventListener *listener);
+ bool hasEventListener(int id, bool local);
+ int getEventListeners(bool local);
+ void removeEventListener(int id);
+ void setupEventListeners(SVGDocumentImpl *doc, SVGDocumentImpl *newDoc);
+
+ // Use with care! Internal only.
+ const QPtrList<SVGRegisteredEventListener> &eventListeners() { return m_eventListeners; }
+
+ void handleLocalEvents(SVGEventImpl *evt, bool useCapture);
+ virtual void defaultEventHandler(SVGEventImpl *evt);
+
+ bool mouseOver() { return m_mouseOver; }
+ void setMouseOver(bool v) { m_mouseOver = v; }
+
+ bool focus() { return m_focus; }
+ void setFocus(bool v) { m_focus = v; }
+
+ virtual bool prepareMouseEvent(const QPoint &, const QPoint &, SVGMouseEventImpl *);
+
+ virtual void createItem(KSVGCanvas *c = 0) { Q_UNUSED(c); }
+ virtual void removeItem(KSVGCanvas *c) { Q_UNUSED(c); }
+
+ // Element creation
+ typedef SVGElementImpl *(*FactoryFn)(DOM::ElementImpl *impl);
+ class Factory
+ {
+ public:
+ static Factory *self()
+ {
+ if(!m_instance)
+ m_instance = new Factory();
+
+ return m_instance;
+ }
+
+ void announce(SVGElementImpl::FactoryFn factoryFn, const std::string &tag)
+ {
+ if(m_elementMap.find(tag) == m_elementMap.end())
+ m_elementMap[tag] = factoryFn;
+ }
+
+ SVGElementImpl *create(const std::string &tag, DOM::ElementImpl *impl) const
+ {
+ ElementMap::const_iterator it = m_elementMap.find(tag);
+ if(it != m_elementMap.end())
+ return it->second(impl);
+ return 0;
+ }
+
+ private:
+ Factory() { }
+ Factory(const Factory &rhs);
+ Factory &operator=(const Factory &rhs);
+
+ static Factory *m_instance;
+
+ typedef std::map<std::string, SVGElementImpl::FactoryFn> ElementMap;
+ mutable ElementMap m_elementMap;
+ };
+
+ template <class T>
+ class Registrar
+ {
+ public:
+ Registrar(const std::string &tag)
+ {
+ SVGElementImpl::Factory::self()->announce(&factoryFn, tag);
+ }
+
+ static SVGElementImpl *factoryFn(DOM::ElementImpl *impl)
+ {
+ return new T(impl);
+ }
+ };
+
+#define KSVG_REGISTER_ELEMENT(Class, Tag) \
+ static SVGElementImpl::Registrar<Class> Class##Registrar(Tag);
+
+protected:
+ void gotError(const QString &errorDesc);
+
+private:
+ SVGSVGElementImpl *m_ownerSVGElement;
+ SVGElementImpl *m_viewportElement;
+ SVGDocumentImpl *m_ownerDoc;
+
+ bool m_mouseOver : 1;
+ bool m_focus : 1;
+
+ QPtrList<SVGRegisteredEventListener> m_eventListeners;
+ QDict<DOM::DOMString> m_attributes;
+
+public:
+ KSVG_BASECLASS_GET
+ KSVG_PUT
+
+ virtual KJS::ObjectImp *bridge(KJS::ExecState *exec) const; // NEEDS TO BE VIRTUAL HERE
+
+ enum
+ {
+ // Properties
+ ElementId, OwnerSvgElement, ViewportElement, XmlBase,
+ OnMouseUp, OnMouseDown, OnMouseMove, OnMouseOver, OnMouseOut,
+ OnClick, OnActivate, OnKeyDown, OnKeyUp, OnKeyPress, OnLoad,
+ OnFocusIn, OnFocusOut, OnError, OnAbort,
+ // Functions
+ GetStyle,
+ // these do not really belong here, but the css doesnt work yet...
+ SetProperty, GetPropertyValue
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+KSVG_DEFINE_PROTOTYPE(SVGElementImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGElementImplProtoFunc, SVGElementImpl)
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGElementInstanceImpl.cc b/ksvg/impl/SVGElementInstanceImpl.cc
new file mode 100644
index 00000000..97cd28a2
--- /dev/null
+++ b/ksvg/impl/SVGElementInstanceImpl.cc
@@ -0,0 +1,108 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGElementImpl.h"
+#include "SVGUseElementImpl.h"
+#include "SVGElementInstanceImpl.h"
+#include "SVGElementInstanceListImpl.h"
+
+using namespace KSVG;
+
+SVGElementInstanceImpl::SVGElementInstanceImpl()//FIXME : events::EventTarget()
+{
+ m_correspondingElement = 0;
+ m_correspondingUseElement = 0;
+ m_parentNode = 0;
+ m_childNodes = 0;
+ m_firstChild = 0;
+ m_lastChild = 0;
+ m_previousSibling = 0;
+ m_nextSibling = 0;
+}
+
+SVGElementInstanceImpl::~SVGElementInstanceImpl()
+{
+ if(m_correspondingElement)
+ m_correspondingElement->deref();
+ if(m_correspondingUseElement)
+ m_correspondingUseElement->deref();
+ if(m_parentNode)
+ m_parentNode->deref();
+ if(m_childNodes)
+ m_childNodes->deref();
+ if(m_firstChild)
+ m_firstChild->deref();
+ if(m_lastChild)
+ m_lastChild->deref();
+ if(m_previousSibling)
+ m_previousSibling->deref();
+ if(m_nextSibling)
+ m_nextSibling->deref();
+}
+
+void SVGElementInstanceImpl::setCorrespondingElement(SVGElementImpl *corresponding)
+{
+ m_correspondingElement = corresponding;
+
+ if(m_correspondingElement)
+ m_correspondingElement->ref();
+}
+
+SVGElementImpl *SVGElementInstanceImpl::correspondingElement() const
+{
+ return m_correspondingElement;
+}
+
+SVGUseElementImpl *SVGElementInstanceImpl::correspondingUseElement() const
+{
+ return m_correspondingUseElement;
+}
+
+SVGElementInstanceImpl *SVGElementInstanceImpl::parentNode() const
+{
+ return m_parentNode;
+}
+
+SVGElementInstanceListImpl *SVGElementInstanceImpl::childNodes() const
+{
+ return m_childNodes;
+}
+
+SVGElementInstanceImpl *SVGElementInstanceImpl::firstChild() const
+{
+ return m_firstChild;
+}
+
+SVGElementInstanceImpl *SVGElementInstanceImpl::lastChild() const
+{
+ return m_lastChild;
+}
+
+SVGElementInstanceImpl *SVGElementInstanceImpl::previousSibling() const
+{
+ return m_previousSibling;
+}
+
+SVGElementInstanceImpl *SVGElementInstanceImpl::nextSibling() const
+{
+ return m_nextSibling;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGElementInstanceImpl.h b/ksvg/impl/SVGElementInstanceImpl.h
new file mode 100644
index 00000000..d9f3afae
--- /dev/null
+++ b/ksvg/impl/SVGElementInstanceImpl.h
@@ -0,0 +1,70 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGElementInstanceImpl_H
+#define SVGElementInstanceImpl_H
+
+#include <dom/dom_misc.h>
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGElementImpl;
+class SVGUseElementImpl;
+class SVGElementInstanceImpl;
+class SVGElementInstanceListImpl;
+class SVGElementInstanceImpl : public DOM::DomShared
+{
+public:
+ SVGElementInstanceImpl();
+ virtual ~SVGElementInstanceImpl();
+
+ SVGElementImpl *correspondingElement() const;
+ SVGUseElementImpl *correspondingUseElement() const;
+ SVGElementInstanceImpl *parentNode() const;
+ SVGElementInstanceListImpl *childNodes() const;
+ SVGElementInstanceImpl *firstChild() const;
+ SVGElementInstanceImpl *lastChild() const;
+ SVGElementInstanceImpl *previousSibling() const;
+ SVGElementInstanceImpl *nextSibling() const;
+
+ void setCorrespondingElement(SVGElementImpl *);
+
+private:
+ SVGElementImpl *m_correspondingElement;
+ SVGUseElementImpl *m_correspondingUseElement;
+ SVGElementInstanceImpl *m_parentNode;
+ SVGElementInstanceListImpl *m_childNodes;
+ SVGElementInstanceImpl *m_firstChild;
+ SVGElementInstanceImpl *m_lastChild;
+ SVGElementInstanceImpl *m_previousSibling;
+ SVGElementInstanceImpl *m_nextSibling;
+
+public:
+ //KSVG_FORWARDGET
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGElementInstanceListImpl.cc b/ksvg/impl/SVGElementInstanceListImpl.cc
new file mode 100644
index 00000000..187255ab
--- /dev/null
+++ b/ksvg/impl/SVGElementInstanceListImpl.cc
@@ -0,0 +1,44 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGElementInstanceImpl.h"
+#include "SVGElementInstanceListImpl.h"
+
+using namespace KSVG;
+
+SVGElementInstanceListImpl::SVGElementInstanceListImpl()
+{
+}
+
+SVGElementInstanceListImpl::~SVGElementInstanceListImpl()
+{
+}
+
+unsigned long SVGElementInstanceListImpl::length() const
+{
+ return m_length;
+}
+
+SVGElementInstanceImpl *SVGElementInstanceListImpl::item(unsigned long /*index*/)
+{
+ return 0;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGElementInstanceListImpl.h b/ksvg/impl/SVGElementInstanceListImpl.h
new file mode 100644
index 00000000..c9ac0dd2
--- /dev/null
+++ b/ksvg/impl/SVGElementInstanceListImpl.h
@@ -0,0 +1,49 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGElementInstanceListImpl_H
+#define SVGElementInstanceListImpl_H
+
+#include <dom/dom_misc.h>
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGElementInstanceImpl;
+class SVGElementInstanceListImpl : public DOM::DomShared
+{
+public:
+ SVGElementInstanceListImpl();
+ virtual ~SVGElementInstanceListImpl();
+
+ unsigned long length() const;
+ SVGElementInstanceImpl *item(unsigned long index);
+
+private:
+ unsigned long m_length;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGEllipseElementImpl.cc b/ksvg/impl/SVGEllipseElementImpl.cc
new file mode 100644
index 00000000..9908941a
--- /dev/null
+++ b/ksvg/impl/SVGEllipseElementImpl.cc
@@ -0,0 +1,200 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "CanvasItem.h"
+#include "KSVGCanvas.h"
+
+#include "SVGRectImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGEllipseElementImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+
+using namespace KSVG;
+
+#include "SVGEllipseElementImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+
+SVGEllipseElementImpl::SVGEllipseElementImpl(DOM::ElementImpl *impl) : SVGShapeImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_cx = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this);
+ m_cx->ref();
+ m_cx->baseVal()->setValueAsString("-1");
+
+ m_cy = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this);
+ m_cy->ref();
+ m_cy->baseVal()->setValueAsString("-1");
+
+ m_rx = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this);
+ m_rx->ref();
+ m_rx->baseVal()->setValueAsString("-1");
+
+ m_ry = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this);
+ m_ry->ref();
+ m_ry->baseVal()->setValueAsString("-1");
+}
+
+SVGEllipseElementImpl::~SVGEllipseElementImpl()
+{
+ if(m_cx)
+ m_cx->deref();
+ if(m_cy)
+ m_cy->deref();
+ if(m_rx)
+ m_rx->deref();
+ if(m_ry)
+ m_ry->deref();
+}
+
+SVGAnimatedLengthImpl *SVGEllipseElementImpl::cx()
+{
+ return m_cx;
+}
+
+SVGAnimatedLengthImpl *SVGEllipseElementImpl::cy()
+{
+ return m_cy;
+}
+
+SVGAnimatedLengthImpl *SVGEllipseElementImpl::rx()
+{
+ return m_rx;
+}
+
+SVGAnimatedLengthImpl *SVGEllipseElementImpl::ry()
+{
+ return m_ry;
+}
+
+/*
+@namespace KSVG
+@begin SVGEllipseElementImpl::s_hashTable 5
+ cx SVGEllipseElementImpl::Cx DontDelete|ReadOnly
+ cy SVGEllipseElementImpl::Cy DontDelete|ReadOnly
+ rx SVGEllipseElementImpl::Rx DontDelete|ReadOnly
+ ry SVGEllipseElementImpl::Ry DontDelete|ReadOnly
+@end
+*/
+
+Value SVGEllipseElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ KSVG_CHECK_ATTRIBUTE
+
+ switch(token)
+ {
+ case Cx:
+ if(!attributeMode)
+ return m_cx->cache(exec);
+ else
+ return Number(m_cx->baseVal()->value());
+ case Cy:
+ if(!attributeMode)
+ return m_cy->cache(exec);
+ else
+ return Number(m_cy->baseVal()->value());
+ case Rx:
+ if(!attributeMode)
+ return m_rx->cache(exec);
+ else
+ return Number(m_rx->baseVal()->value());
+ case Ry:
+ if(!attributeMode)
+ return m_ry->cache(exec);
+ else
+ return Number(m_ry->baseVal()->value());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGEllipseElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case Cx:
+ cx()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ case Cy:
+ cy()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ case Rx:
+ rx()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ if(rx()->baseVal()->value() < 0) // A negative value is an error
+ gotError("Negative value for attribute rx of element <ellipse> is illegal");
+ break;
+ case Ry:
+ ry()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ if(ry()->baseVal()->value() < 0) // A negative value is an error
+ gotError(i18n("Negative value for attribute ry of element <ellipse> is illegal"));
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+SVGRectImpl *SVGEllipseElementImpl::getBBox()
+{
+ SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect();
+ ret->setX(m_cx->baseVal()->value() - m_rx->baseVal()->value());
+ ret->setY(m_cy->baseVal()->value() - m_ry->baseVal()->value());
+ ret->setWidth(m_rx->baseVal()->value() * 2.0);
+ ret->setHeight(m_ry->baseVal()->value() * 2.0);
+ return ret;
+}
+
+void SVGEllipseElementImpl::setAttributes()
+{
+ SVGElementImpl::setAttributes();
+
+ // Spec: if not specified, effect is as if a value of "0" were specified
+ if(KSVG_TOKEN_NOT_PARSED(Cx))
+ KSVG_SET_ALT_ATTRIBUTE(Cx, "0")
+
+ // Spec: if not specified, effect is as if a value of "0" were specified
+ if(KSVG_TOKEN_NOT_PARSED(Cy))
+ KSVG_SET_ALT_ATTRIBUTE(Cy, "0")
+}
+
+void SVGEllipseElementImpl::createItem(KSVGCanvas *c)
+{
+ if(!c)
+ c = ownerDoc()->canvas();
+
+ if(!m_item)
+ {
+ m_item = c->createEllipse(this);
+ c->insert(m_item);
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGEllipseElementImpl.h b/ksvg/impl/SVGEllipseElementImpl.h
new file mode 100644
index 00000000..131098ba
--- /dev/null
+++ b/ksvg/impl/SVGEllipseElementImpl.h
@@ -0,0 +1,86 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGEllipseElementImpl_H
+#define SVGEllipseElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGShapeImpl.h"
+#include "SVGTestsImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGLangSpaceImpl.h"
+#include "SVGTransformableImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+namespace KSVG
+{
+
+class SVGRectImpl;
+class SVGAnimatedLengthImpl;
+class SVGEllipseElementImpl : public SVGShapeImpl,
+ public SVGTestsImpl,
+ public SVGLangSpaceImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGStylableImpl,
+ public SVGTransformableImpl
+{
+public:
+ SVGEllipseElementImpl(DOM::ElementImpl *);
+ virtual ~SVGEllipseElementImpl();
+
+ SVGAnimatedLengthImpl *cx();
+ SVGAnimatedLengthImpl *cy();
+ SVGAnimatedLengthImpl *rx();
+ SVGAnimatedLengthImpl *ry();
+
+ virtual void createItem(KSVGCanvas *c = 0);
+ virtual void setAttributes();
+
+ virtual SVGRectImpl *getBBox();
+
+private:
+ SVGAnimatedLengthImpl *m_cx;
+ SVGAnimatedLengthImpl *m_cy;
+ SVGAnimatedLengthImpl *m_rx;
+ SVGAnimatedLengthImpl *m_ry;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+ KSVG_BRIDGE
+
+ enum
+ {
+ // Properties
+ Cx, Cy, Rx, Ry
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+KSVG_REGISTER_ELEMENT(SVGEllipseElementImpl, "ellipse")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGEventImpl.cc b/ksvg/impl/SVGEventImpl.cc
new file mode 100644
index 00000000..418e0044
--- /dev/null
+++ b/ksvg/impl/SVGEventImpl.cc
@@ -0,0 +1,992 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ Additional copyright:
+ (C) 2001 Peter Kelly <pmk@post.com>
+ (C) 2001 Tobias Anton <anton@stud.fbi.fh-darmstadt.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGDocumentImpl.h"
+#include "SVGEventImpl.h"
+
+#include <kdebug.h>
+
+using namespace KSVG;
+
+#include "ksvg_scriptinterpreter.h"
+#include "SVGEventImpl.lut.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+
+SVGEventImpl::SVGEventImpl()
+{
+ m_canBubble = false;
+ m_cancelable = false;
+
+ m_propagationStopped = false;
+ m_defaultPrevented = false;
+ m_id = SVGEvent::UNKNOWN_EVENT;
+ m_eventPhase = 0;
+ m_createTime = QDateTime::currentDateTime();
+ m_defaultHandled = false;
+
+ m_target = 0;
+ m_currentTarget = 0;
+}
+
+SVGEventImpl::SVGEventImpl(SVGEvent::EventId _id, bool canBubbleArg, bool cancelableArg)
+{
+ DOM::DOMString t = SVGEvent::idToType(_id);
+ m_type = t.implementation();
+
+ m_canBubble = canBubbleArg;
+ m_cancelable = cancelableArg;
+
+ m_propagationStopped = false;
+ m_defaultPrevented = false;
+ m_id = _id;
+ m_eventPhase = 0;
+ m_createTime = QDateTime::currentDateTime();
+ m_defaultHandled = false;
+
+ m_target = 0;
+ m_currentTarget = 0;
+}
+
+SVGEventImpl::~SVGEventImpl()
+{
+}
+
+DOM::DOMString SVGEventImpl::type() const
+{
+ return m_type;
+}
+
+SVGElementImpl *SVGEventImpl::target() const
+{
+ return m_target;
+}
+
+void SVGEventImpl::setTarget(SVGElementImpl *_target)
+{
+ m_target = _target;
+}
+
+SVGElementImpl *SVGEventImpl::currentTarget() const
+{
+ return m_currentTarget;
+}
+
+void SVGEventImpl::setCurrentTarget(SVGElementImpl *_currentTarget)
+{
+ m_currentTarget = _currentTarget;
+}
+
+unsigned short SVGEventImpl::eventPhase() const
+{
+ return m_eventPhase;
+}
+
+void SVGEventImpl::setEventPhase(unsigned short _eventPhase)
+{
+ m_eventPhase = _eventPhase;
+}
+
+bool SVGEventImpl::bubbles() const
+{
+ return m_canBubble;
+}
+
+bool SVGEventImpl::cancelable() const
+{
+ return m_cancelable;
+}
+
+DOM::DOMTimeStamp SVGEventImpl::timeStamp()
+{
+ QDateTime epoch(QDate(1970, 1, 1), QTime(0, 0));
+
+ // ### kjs does not yet support long long (?) so the value wraps around
+ return epoch.secsTo(m_createTime) * 1000 + m_createTime.time().msec();
+}
+
+void SVGEventImpl::stopPropagation()
+{
+ m_propagationStopped = true;
+}
+
+void SVGEventImpl::preventDefault()
+{
+ if(m_cancelable)
+ m_defaultPrevented = true;
+}
+
+void SVGEventImpl::initEvent(const DOM::DOMString &eventTypeArg, bool canBubbleArg, bool cancelableArg)
+{
+ // ### ensure this is not called after we have been dispatched (also for subclasses)
+ m_type = eventTypeArg.implementation();
+ m_id = SVGEvent::typeToId(eventTypeArg);
+
+ m_canBubble = canBubbleArg;
+ m_cancelable = cancelableArg;
+}
+
+void SVGEventImpl::setDefaultHandled()
+{
+ m_defaultHandled = true;
+}
+
+/*
+@namespace KSVG
+@begin SVGEventImpl::s_hashTable 11
+ type SVGEventImpl::Type DontDelete|ReadOnly
+ target SVGEventImpl::Target DontDelete|ReadOnly
+ currentTarget SVGEventImpl::CurrentTarget DontDelete|ReadOnly
+ eventPhase SVGEventImpl::EventPhase DontDelete|ReadOnly
+ bubbles SVGEventImpl::Bubbles DontDelete|ReadOnly
+ cancelable SVGEventImpl::Cancelable DontDelete|ReadOnly
+ timeStamp SVGEventImpl::TimeStamp DontDelete|ReadOnly
+@end
+@namespace KSVG
+@begin SVGEventImplProto::s_hashTable 13
+ getType SVGEventImpl::GetType DontDelete|Function 0
+ getTarget SVGEventImpl::GetTarget DontDelete|Function 0
+ getCurrentTarget SVGEventImpl::GetCurrentTarget DontDelete|Function 0
+ getCurrentNode SVGEventImpl::GetCurrentNode DontDelete|Function 0
+ getEventphase SVGEventImpl::GetEventPhase DontDelete|Function 0
+ getBubbles SVGEventImpl::GetBubbles DontDelete|Function 0
+ getCancelable SVGEventImpl::GetCancelable DontDelete|Function 0
+ getTimeStamp SVGEventImpl::GetTimeStamp DontDelete|Function 0
+ stopPropagation SVGEventImpl::StopPropagation DontDelete|Function 0
+ preventDefault SVGEventImpl::PreventDefault DontDelete|Function 0
+ initEvent SVGEventImpl::InitEvent DontDelete|Function 3
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGEvent", SVGEventImplProto, SVGEventImplProtoFunc)
+
+Value SVGEventImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case Type:
+ return String(type());
+ case Target:
+ return getDOMNode(exec, *target());
+ case CurrentTarget:
+ return getDOMNode(exec, *currentTarget());
+ case EventPhase:
+ return Number(eventPhase());
+ case Bubbles:
+ return Boolean(bubbles());
+ case Cancelable:
+ return Boolean(cancelable());
+// case TimeStamp: // TODO
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return KJS::Undefined();
+ }
+}
+
+Value SVGEventImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGEventImpl)
+
+ switch(id)
+ {
+ case SVGEventImpl::GetType:
+ return String(obj->type());
+ case SVGEventImpl::GetTarget:
+ return getDOMNode(exec, *obj->target());
+ case SVGEventImpl::GetCurrentTarget:
+ case SVGEventImpl::GetCurrentNode:
+ return getDOMNode(exec, *obj->currentTarget());
+ case SVGEventImpl::GetEventPhase:
+ return Number(obj->eventPhase());
+ case SVGEventImpl::GetBubbles:
+ return Boolean(obj->bubbles());
+ case SVGEventImpl::GetCancelable:
+ return Boolean(obj->cancelable());
+// case SVGEventImpl::GetTimeStamp: // TODO
+ case SVGEventImpl::StopPropagation:
+ {
+ obj->stopPropagation();
+ return Undefined();
+ }
+ case SVGEventImpl::PreventDefault:
+ {
+ obj->preventDefault();
+ return Undefined();
+ }
+ case SVGEventImpl::InitEvent:
+ {
+ obj->initEvent(args[0].toString(exec).string(), args[1].toBoolean(exec), args[2].toBoolean(exec));
+ return Undefined();
+ }
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return Undefined();
+}
+
+
+
+
+
+SVGUIEventImpl::SVGUIEventImpl() : SVGEventImpl()
+{
+ m_detail = 0;
+}
+
+SVGUIEventImpl::SVGUIEventImpl(SVGEvent::EventId _id, bool canBubbleArg, bool cancelableArg, DOM::AbstractView &viewArg, long detailArg)
+: SVGEventImpl(_id, canBubbleArg, cancelableArg)
+{
+ m_view = viewArg;
+ m_detail = detailArg;
+}
+
+SVGUIEventImpl::~SVGUIEventImpl()
+{
+}
+
+DOM::AbstractView SVGUIEventImpl::view() const
+{
+ return m_view;
+}
+
+long SVGUIEventImpl::detail() const
+{
+ return m_detail;
+}
+
+void SVGUIEventImpl::initUIEvent(const DOM::DOMString &typeArg,
+ bool canBubbleArg,
+ bool cancelableArg,
+ const DOM::AbstractView &viewArg,
+ long detailArg)
+{
+ SVGEventImpl::initEvent(typeArg, canBubbleArg, cancelableArg);
+
+ m_view = viewArg;
+ m_detail = detailArg;
+}
+
+/*
+@namespace KSVG
+@begin SVGUIEventImpl::s_hashTable 3
+ view SVGUIEventImpl::View DontDelete|ReadOnly
+ detail SVGUIEventImpl::Detail DontDelete|ReadOnly
+@end
+@namespace KSVG
+@begin SVGUIEventImplProto::s_hashTable 5
+ getView SVGUIEventImpl::GetView DontDelete|Function 0
+ getDetail SVGUIEventImpl::GetDetail DontDelete|Function 0
+ initUIEvent SVGUIEventImpl::InitUIEvent DontDelete|Function 5
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGUIEvent", SVGUIEventImplProto, SVGUIEventImplProtoFunc)
+
+Value SVGUIEventImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+// case View: // TODO
+ case Detail:
+ return Number(detail());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return KJS::Undefined();
+ }
+}
+
+Value SVGUIEventImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &)
+{
+ KSVG_CHECK_THIS(SVGUIEventImpl)
+
+ switch(id)
+ {
+// case SVGUIEventImpl::GetView: // TODO
+ case SVGUIEventImpl::GetDetail:
+ return Number(obj->detail());
+// case SVGUIEventImpl::InitUIEvent: // TODO
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return Undefined();
+}
+
+SVGKeyEventImpl::SVGKeyEventImpl() : SVGUIEventImpl()
+{
+ qKeyEvent = 0;
+}
+
+SVGKeyEventImpl::SVGKeyEventImpl(QKeyEvent *key, DOM::AbstractView &view, SVGEvent::EventId _id) : SVGUIEventImpl(_id, true, true, view, 0)
+{
+ qKeyEvent = new QKeyEvent(key->type(), key->key(), key->ascii(), key->state(), key->text(), key->isAutoRepeat(), key->count());
+
+ // Events are supposed to be accepted by default in Qt!
+ // This line made QLineEdit's keyevents be ignored, so they were sent to the khtmlview
+ // (and e.g. space would make it scroll down)
+ //qKeyEvent->ignore();
+
+ m_detail = key->count();
+
+ m_numPad = false;
+ m_keyVal = 0;
+ m_virtKeyVal = DOM_VK_UNDEFINED;
+ m_inputGenerated = true;
+
+ switch(key->key())
+ {
+ case Qt::Key_Enter:
+ m_numPad = true;
+ /* fall through */
+ case Qt::Key_Return:
+ m_virtKeyVal = DOM_VK_ENTER;
+ break;
+ case Qt::Key_NumLock:
+ m_numPad = true;
+ m_virtKeyVal = DOM_VK_NUM_LOCK;
+ break;
+ case Qt::Key_Alt:
+ m_virtKeyVal = DOM_VK_RIGHT_ALT;
+ // ### DOM_VK_LEFT_ALT;
+ break;
+ case Qt::Key_Control:
+ m_virtKeyVal = DOM_VK_LEFT_CONTROL;
+ // ### DOM_VK_RIGHT_CONTROL
+ break;
+ case Qt::Key_Shift:
+ m_virtKeyVal = DOM_VK_LEFT_SHIFT;
+ // ### DOM_VK_RIGHT_SHIFT
+ break;
+ case Qt::Key_Meta:
+ m_virtKeyVal = DOM_VK_LEFT_META;
+ // ### DOM_VK_RIGHT_META
+ break;
+ case Qt::Key_CapsLock:
+ m_virtKeyVal = DOM_VK_CAPS_LOCK;
+ break;
+ case Qt::Key_Delete:
+ m_virtKeyVal = DOM_VK_DELETE;
+ break;
+ case Qt::Key_End:
+ m_virtKeyVal = DOM_VK_END;
+ break;
+ case Qt::Key_Escape:
+ m_virtKeyVal = DOM_VK_ESCAPE;
+ break;
+ case Qt::Key_Home:
+ m_virtKeyVal = DOM_VK_HOME;
+ break;
+ case Qt::Key_Insert:
+ m_virtKeyVal = DOM_VK_INSERT;
+ break;
+ case Qt::Key_Pause:
+ m_virtKeyVal = DOM_VK_PAUSE;
+ break;
+ case Qt::Key_Print:
+ m_virtKeyVal = DOM_VK_PRINTSCREEN;
+ break;
+ case Qt::Key_ScrollLock:
+ m_virtKeyVal = DOM_VK_SCROLL_LOCK;
+ break;
+ case Qt::Key_Left:
+ m_virtKeyVal = DOM_VK_LEFT;
+ break;
+ case Qt::Key_Right:
+ m_virtKeyVal = DOM_VK_RIGHT;
+ break;
+ case Qt::Key_Up:
+ m_virtKeyVal = DOM_VK_UP;
+ break;
+ case Qt::Key_Down:
+ m_virtKeyVal = DOM_VK_DOWN;
+ break;
+ case Qt::Key_Next:
+ m_virtKeyVal = DOM_VK_PAGE_DOWN;
+ break;
+ case Qt::Key_Prior:
+ m_virtKeyVal = DOM_VK_PAGE_UP;
+ break;
+ case Qt::Key_F1:
+ m_virtKeyVal = DOM_VK_F1;
+ break;
+ case Qt::Key_F2:
+ m_virtKeyVal = DOM_VK_F2;
+ break;
+ case Qt::Key_F3:
+ m_virtKeyVal = DOM_VK_F3;
+ break;
+ case Qt::Key_F4:
+ m_virtKeyVal = DOM_VK_F4;
+ break;
+ case Qt::Key_F5:
+ m_virtKeyVal = DOM_VK_F5;
+ break;
+ case Qt::Key_F6:
+ m_virtKeyVal = DOM_VK_F6;
+ break;
+ case Qt::Key_F7:
+ m_virtKeyVal = DOM_VK_F7;
+ break;
+ case Qt::Key_F8:
+ m_virtKeyVal = DOM_VK_F8;
+ break;
+ case Qt::Key_F9:
+ m_virtKeyVal = DOM_VK_F9;
+ break;
+ case Qt::Key_F10:
+ m_virtKeyVal = DOM_VK_F10;
+ break;
+ case Qt::Key_F11:
+ m_virtKeyVal = DOM_VK_F11;
+ break;
+ case Qt::Key_F12:
+ m_virtKeyVal = DOM_VK_F12;
+ break;
+ case Qt::Key_F13:
+ m_virtKeyVal = DOM_VK_F13;
+ break;
+ case Qt::Key_F14:
+ m_virtKeyVal = DOM_VK_F14;
+ break;
+ case Qt::Key_F15:
+ m_virtKeyVal = DOM_VK_F15;
+ break;
+ case Qt::Key_F16:
+ m_virtKeyVal = DOM_VK_F16;
+ break;
+ case Qt::Key_F17:
+ m_virtKeyVal = DOM_VK_F17;
+ break;
+ case Qt::Key_F18:
+ m_virtKeyVal = DOM_VK_F18;
+ break;
+ case Qt::Key_F19:
+ m_virtKeyVal = DOM_VK_F19;
+ break;
+ case Qt::Key_F20:
+ m_virtKeyVal = DOM_VK_F20;
+ break;
+ case Qt::Key_F21:
+ m_virtKeyVal = DOM_VK_F21;
+ break;
+ case Qt::Key_F22:
+ m_virtKeyVal = DOM_VK_F22;
+ break;
+ case Qt::Key_F23:
+ m_virtKeyVal = DOM_VK_F23;
+ break;
+ case Qt::Key_F24:
+ m_virtKeyVal = DOM_VK_F24;
+ break;
+ default:
+ m_virtKeyVal = DOM_VK_UNDEFINED;
+ break;
+ }
+
+ // m_keyVal should contain the unicode value
+ // of the pressed key if available.
+ if (!key->text().isNull())
+ m_keyVal = key->text().unicode()[0];
+
+ // m_numPad = ???
+
+ // key->state returns enum ButtonState, which is ShiftButton, ControlButton and AltButton or'ed together.
+ m_modifier = key->state();
+
+ // key->text() returns the unicode sequence as a QString
+ m_outputString = DOM::DOMString(key->text());
+}
+
+SVGKeyEventImpl::SVGKeyEventImpl(SVGEvent::EventId _id,
+ bool canBubbleArg,
+ bool cancelableArg,
+ DOM::AbstractView &viewArg,
+ unsigned short detailArg,
+ DOM::DOMString &outputStringArg,
+ unsigned long keyValArg,
+ unsigned long virtKeyValArg,
+ bool inputGeneratedArg,
+ bool numPadArg)
+: SVGUIEventImpl(_id, canBubbleArg, cancelableArg, viewArg, detailArg)
+{
+ qKeyEvent = 0;
+ m_keyVal = keyValArg;
+ m_virtKeyVal = virtKeyValArg;
+ m_inputGenerated = inputGeneratedArg;
+ m_outputString = outputStringArg;
+ m_numPad = numPadArg;
+ m_modifier = 0;
+}
+
+SVGKeyEventImpl::~SVGKeyEventImpl()
+{
+ delete qKeyEvent;
+}
+
+bool SVGKeyEventImpl::checkModifier(unsigned long modifierArg)
+{
+ return ((m_modifier && modifierArg) == modifierArg);
+}
+
+void SVGKeyEventImpl::initKeyEvent(DOM::DOMString &typeArg,
+ bool canBubbleArg,
+ bool cancelableArg,
+ const DOM::AbstractView &viewArg,
+ long detailArg,
+ DOM::DOMString &outputStringArg,
+ unsigned long keyValArg,
+ unsigned long virtKeyValArg,
+ bool inputGeneratedArg,
+ bool numPadArg)
+{
+ SVGUIEventImpl::initUIEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg);
+
+ m_outputString = outputStringArg;
+ m_keyVal = keyValArg;
+ m_virtKeyVal = virtKeyValArg;
+ m_inputGenerated = inputGeneratedArg;
+ m_numPad = numPadArg;
+}
+
+void SVGKeyEventImpl::initModifier(unsigned long modifierArg, bool valueArg)
+{
+ if(valueArg)
+ m_modifier |= modifierArg;
+ else
+ m_modifier &= (modifierArg ^ 0xFFFFFFFF);
+}
+
+bool SVGKeyEventImpl::inputGenerated() const
+{
+ return m_inputGenerated;
+}
+
+unsigned long SVGKeyEventImpl::keyVal() const
+{
+ return m_keyVal;
+}
+
+DOM::DOMString SVGKeyEventImpl::outputString() const
+{
+ return m_outputString;
+}
+
+/*
+@namespace KSVG
+@begin SVGKeyEventImpl::s_hashTable 7
+ keyVal SVGKeyEventImpl::KeyVal DontDelete|ReadOnly
+ keyCode SVGKeyEventImpl::KeyVal DontDelete|ReadOnly
+ charCode SVGKeyEventImpl::KeyVal DontDelete|ReadOnly
+ outputString SVGKeyEventImpl::OutputString DontDelete|ReadOnly
+ virtKeyVal SVGKeyEventImpl::VirtKeyVal DontDelete|ReadOnly
+# todo visibleOutputGenerated numPad
+@end
+@namespace KSVG
+@begin SVGKeyEventImplProto::s_hashTable 7
+ checkModifier SVGKeyEventImpl::CheckModifier DontDelete|Function 1
+ getKeyCode SVGKeyEventImpl::GetKeyVal DontDelete|Function 0
+ getCharCode SVGKeyEventImpl::GetKeyVal DontDelete|Function 0
+ getKeyVal SVGKeyEventImpl::GetKeyVal DontDelete|Function 0
+ getCharCode SVGKeyEventImpl::GetCharCode DontDelete|Function 0
+# todo initModifier
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGKeyEvent", SVGKeyEventImplProto, SVGKeyEventImplProtoFunc)
+
+Value SVGKeyEventImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case KeyVal:
+ return Number(keyVal());
+ case VirtKeyVal:
+ return Number(virtKeyVal());
+ case OutputString:
+ return String(outputString());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+Value SVGKeyEventImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGKeyEventImpl)
+
+ switch(id)
+ {
+ case SVGKeyEventImpl::CheckModifier:
+ return Boolean((static_cast<KSVGBridge<SVGKeyEventImpl> *>(static_cast<ObjectImp *>(thisObj.imp()))->impl())->checkModifier(args[0].toUInt32(exec)));
+ case SVGKeyEventImpl::GetKeyVal:
+ case SVGKeyEventImpl::GetCharCode:
+ return Number((static_cast<KSVGBridge<SVGKeyEventImpl> *>(static_cast<ObjectImp *>(thisObj.imp()))->impl())->keyVal());
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return Undefined();
+}
+
+
+
+// -----------------------------------------------------------------------------
+
+SVGMouseEventImpl::SVGMouseEventImpl() : SVGUIEventImpl()
+{
+ m_screenX = 0;
+ m_screenY = 0;
+ m_clientX = 0;
+ m_clientY = 0;
+ m_ctrlKey = false;
+ m_altKey = false;
+ m_shiftKey = false;
+ m_metaKey = false;
+ m_button = 0;
+}
+
+SVGMouseEventImpl::SVGMouseEventImpl(SVGEvent::EventId _id,
+ bool canBubbleArg,
+ bool cancelableArg,
+ DOM::AbstractView &viewArg,
+ long detailArg,
+ long screenXArg,
+ long screenYArg,
+ long clientXArg,
+ long clientYArg,
+ bool ctrlKeyArg,
+ bool altKeyArg,
+ bool shiftKeyArg,
+ bool metaKeyArg,
+ unsigned short buttonArg,
+ SVGElementImpl *relatedTargetArg)
+: SVGUIEventImpl(_id, canBubbleArg, cancelableArg, viewArg, detailArg)
+{
+ m_screenX = screenXArg;
+ m_screenY = screenYArg;
+ m_clientX = clientXArg;
+ m_clientY = clientYArg;
+ m_ctrlKey = ctrlKeyArg;
+ m_altKey = altKeyArg;
+ m_shiftKey = shiftKeyArg;
+ m_metaKey = metaKeyArg;
+ m_button = buttonArg;
+ m_relatedTarget = relatedTargetArg;
+}
+
+SVGMouseEventImpl::~SVGMouseEventImpl()
+{
+}
+
+long SVGMouseEventImpl::screenX() const
+{
+ return m_screenX;
+}
+
+long SVGMouseEventImpl::screenY() const
+{
+ return m_screenY;
+}
+
+long SVGMouseEventImpl::clientX() const
+{
+ return m_clientX;
+}
+
+long SVGMouseEventImpl::clientY() const
+{
+ return m_clientY;
+}
+
+bool SVGMouseEventImpl::ctrlKey() const
+{
+ return m_ctrlKey;
+}
+
+bool SVGMouseEventImpl::shiftKey() const
+{
+ return m_shiftKey;
+}
+
+bool SVGMouseEventImpl::altKey() const
+{
+ return m_altKey;
+}
+
+bool SVGMouseEventImpl::metaKey() const
+{
+ return m_metaKey;
+}
+
+unsigned short SVGMouseEventImpl::button() const
+{
+ return m_button;
+}
+
+SVGElementImpl *SVGMouseEventImpl::relatedTarget() const
+{
+ return m_relatedTarget;
+}
+
+DOM::DOMString SVGMouseEventImpl::url() const
+{
+ return m_url;
+}
+
+void SVGMouseEventImpl::setURL(DOM::DOMString url)
+{
+ m_url = url;
+}
+
+void SVGMouseEventImpl::initMouseEvent(const DOM::DOMString &typeArg,
+ bool canBubbleArg,
+ bool cancelableArg,
+ const DOM::AbstractView &viewArg,
+ long detailArg,
+ long screenXArg,
+ long screenYArg,
+ long clientXArg,
+ long clientYArg,
+ bool ctrlKeyArg,
+ bool altKeyArg,
+ bool shiftKeyArg,
+ bool metaKeyArg,
+ unsigned short buttonArg,
+ SVGElementImpl *relatedTargetArg)
+{
+ SVGUIEventImpl::initUIEvent(typeArg, canBubbleArg, cancelableArg, viewArg, detailArg);
+
+ m_screenX = screenXArg;
+ m_screenY = screenYArg;
+ m_clientX = clientXArg;
+ m_clientY = clientYArg;
+ m_ctrlKey = ctrlKeyArg;
+ m_altKey = altKeyArg;
+ m_shiftKey = shiftKeyArg;
+ m_metaKey = metaKeyArg;
+ m_button = buttonArg;
+ m_relatedTarget = relatedTargetArg;
+}
+
+/*
+@namespace KSVG
+@begin SVGMouseEventImpl::s_hashTable 11
+ screenX SVGMouseEventImpl::ScreenX DontDelete|ReadOnly
+ screenY SVGMouseEventImpl::ScreenY DontDelete|ReadOnly
+ clientX SVGMouseEventImpl::ClientX DontDelete|ReadOnly
+ clientY SVGMouseEventImpl::ClientY DontDelete|ReadOnly
+ ctrlKey SVGMouseEventImpl::CtrlKey DontDelete|ReadOnly
+ shiftKey SVGMouseEventImpl::ShiftKey DontDelete|ReadOnly
+ altKey SVGMouseEventImpl::AltKey DontDelete|ReadOnly
+ metaKey SVGMouseEventImpl::MetaKey DontDelete|ReadOnly
+ button SVGMouseEventImpl::Button DontDelete|ReadOnly
+ relatedTarget SVGMouseEventImpl::RelatedTarget DontDelete|ReadOnly
+@end
+@namespace KSVG
+@begin SVGMouseEventImplProto::s_hashTable 13
+ getScreenX SVGMouseEventImpl::GetScreenX DontDelete|Function 0
+ getScreenY SVGMouseEventImpl::GetScreenY DontDelete|Function 0
+ getClientX SVGMouseEventImpl::GetClientX DontDelete|Function 0
+ getClientY SVGMouseEventImpl::GetClientY DontDelete|Function 0
+ getCtrlKey SVGMouseEventImpl::GetCtrlKey DontDelete|Function 0
+ getShiftKey SVGMouseEventImpl::GetShiftKey DontDelete|Function 0
+ getAltKey SVGMouseEventImpl::GetAltKey DontDelete|Function 0
+ getMetaKey SVGMouseEventImpl::GetMetaKey DontDelete|Function 0
+ getButton SVGMouseEventImpl::GetButton DontDelete|Function 0
+ getRelatedTarget SVGMouseEventImpl::GetRelatedTarget DontDelete|Function 0
+ initMouseEvent SVGMouseEventImpl::InitMouseEvent DontDelete|Function 15
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGMouseEvent", SVGMouseEventImplProto, SVGMouseEventImplProtoFunc)
+
+Value SVGMouseEventImpl::getValueProperty(ExecState *exec, int token) const
+{
+ kdDebug(26004) << k_funcinfo << endl;
+ switch(token)
+ {
+ case ScreenX:
+ return Number(screenX());
+ case ScreenY:
+ return Number(screenY());
+ case ClientX:
+ return Number(clientX());
+ case ClientY:
+ return Number(clientY());
+ case CtrlKey:
+ return Number(ctrlKey());
+ case ShiftKey:
+ return Number(shiftKey());
+ case AltKey:
+ return Number(altKey());
+ case MetaKey:
+ return Number(metaKey());
+ case Button:
+ return Number(button());
+ case RelatedTarget:
+ return getDOMNode(exec, *relatedTarget());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return KJS::Undefined();
+ }
+}
+
+Value SVGMouseEventImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &)
+{
+ kdDebug(26004) << k_funcinfo << endl;
+ KSVG_CHECK_THIS(SVGMouseEventImpl)
+
+ switch(id)
+ {
+ case SVGMouseEventImpl::GetScreenX:
+ return Number(obj->screenX());
+ case SVGMouseEventImpl::GetScreenY:
+ return Number(obj->screenY());
+ case SVGMouseEventImpl::GetClientX:
+ return Number(obj->clientX());
+ case SVGMouseEventImpl::GetClientY:
+ return Number(obj->clientY());
+ case SVGMouseEventImpl::GetCtrlKey:
+ return Number(obj->ctrlKey());
+ case SVGMouseEventImpl::GetShiftKey:
+ return Number(obj->shiftKey());
+ case SVGMouseEventImpl::GetAltKey:
+ return Number(obj->altKey());
+ case SVGMouseEventImpl::GetMetaKey:
+ return Number(obj->metaKey());
+ case SVGMouseEventImpl::GetButton:
+ return Number(obj->button());
+ case SVGMouseEventImpl::GetRelatedTarget:
+ return getDOMNode(exec, *obj->relatedTarget());
+// case SVGMouseEventImpl::InitMouseEvent: // TODO
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return Undefined();
+}
+
+
+
+
+SVGMutationEventImpl::SVGMutationEventImpl() : SVGEventImpl()
+{
+ m_attrChange = 0;
+}
+
+SVGMutationEventImpl::SVGMutationEventImpl(SVGEvent::EventId _id,
+ bool canBubbleArg,
+ bool cancelableArg,
+ SVGElementImpl *relatedNodeArg,
+ const DOM::DOMString &prevValueArg,
+ const DOM::DOMString &newValueArg,
+ const DOM::DOMString &attrNameArg,
+ unsigned short attrChangeArg)
+: SVGEventImpl(_id, canBubbleArg, cancelableArg)
+{
+ m_relatedNode = relatedNodeArg;
+ m_prevValue = prevValueArg.implementation();
+ m_newValue = newValueArg.implementation();
+ m_attrName = attrNameArg.implementation();
+ m_attrChange = attrChangeArg;
+}
+
+SVGMutationEventImpl::~SVGMutationEventImpl()
+{
+}
+
+SVGElementImpl *SVGMutationEventImpl::relatedNode() const
+{
+ return m_relatedNode;
+}
+
+DOM::DOMString SVGMutationEventImpl::prevValue() const
+{
+ return m_prevValue;
+}
+
+DOM::DOMString SVGMutationEventImpl::newValue() const
+{
+ return m_newValue;
+}
+
+DOM::DOMString SVGMutationEventImpl::attrName() const
+{
+ return m_attrName;
+}
+
+unsigned short SVGMutationEventImpl::attrChange() const
+{
+ return m_attrChange;
+}
+
+void SVGMutationEventImpl::initMutationEvent(const DOM::DOMString &typeArg,
+ bool canBubbleArg,
+ bool cancelableArg,
+ SVGElementImpl *relatedNodeArg,
+ const DOM::DOMString &prevValueArg,
+ const DOM::DOMString &newValueArg,
+ const DOM::DOMString &attrNameArg,
+ unsigned short attrChangeArg)
+{
+ SVGEventImpl::initEvent(typeArg, canBubbleArg, cancelableArg);
+
+ m_relatedNode = relatedNodeArg;
+ m_prevValue = prevValueArg.implementation();
+ m_newValue = newValueArg.implementation();
+ m_attrName = attrNameArg.implementation();
+ m_attrChange = attrChangeArg;
+}
+
+
+
+
+
+SVGRegisteredEventListener::SVGRegisteredEventListener(SVGEvent::EventId _id, SVGEventListener *_listener, bool _useCapture)
+{
+ id = _id;
+ listener = _listener;
+ useCapture = _useCapture;
+
+ listener->ref();
+}
+
+SVGRegisteredEventListener::~SVGRegisteredEventListener()
+{
+ listener->deref();
+}
+
+bool SVGRegisteredEventListener::operator==(const SVGRegisteredEventListener &other)
+{
+ return (id == other.id &&
+ listener == other.listener &&
+ useCapture == other.useCapture);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGEventImpl.h b/ksvg/impl/SVGEventImpl.h
new file mode 100644
index 00000000..a123b09e
--- /dev/null
+++ b/ksvg/impl/SVGEventImpl.h
@@ -0,0 +1,468 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ Additional copyright:
+ (C) 2001 Peter Kelly <pmk@post.com>
+ (C) 2001 Tobias Anton <anton@stud.fbi.fh-darmstadt.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGEventImpl_H
+#define SVGEventImpl_H
+
+#include <qevent.h>
+#include <qdatetime.h>
+
+#include <dom/dom_misc.h>
+#include <dom/dom_node.h>
+#include <dom/dom2_views.h>
+#include <dom/dom_string.h>
+
+#include "SVGEvent.h"
+#include "SVGElementImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+// @ecma-checked 07/07/02@
+class SVGEventImpl : public DOM::DomShared
+{
+public:
+ SVGEventImpl();
+ SVGEventImpl(SVGEvent::EventId _id, bool canBubbleArg, bool cancelableArg);
+ virtual ~SVGEventImpl();
+
+ SVGEvent::EventId id() { return m_id; }
+
+ DOM::DOMString type() const;
+
+ SVGElementImpl *target() const;
+ void setTarget(SVGElementImpl *_target);
+
+ SVGElementImpl *currentTarget() const;
+ void setCurrentTarget(SVGElementImpl *_currentTarget);
+
+ unsigned short eventPhase() const;
+ void setEventPhase(unsigned short _eventPhase);
+
+ bool bubbles() const;
+ bool cancelable() const;
+
+ DOM::DOMTimeStamp timeStamp();
+
+ void stopPropagation();
+ void preventDefault();
+ void initEvent(const DOM::DOMString &eventTypeArg, bool canBubbleArg, bool cancelableArg);
+
+ virtual bool isUIEvent() { return false; }
+ virtual bool isMouseEvent() { return false; }
+ virtual bool isMutationEvent() { return false; }
+ virtual bool isKeyEvent() { return false; }
+
+ virtual DOM::DOMString eventModuleName() { return ""; }
+
+ virtual bool propagationStopped() { return m_propagationStopped; }
+ virtual bool defaultPrevented() { return m_defaultPrevented; }
+
+ void setDefaultHandled();
+ bool defaultHandled() const { return m_defaultHandled; }
+
+protected:
+ DOM::DOMString m_type;
+ bool m_canBubble;
+ bool m_cancelable;
+
+ bool m_propagationStopped;
+ bool m_defaultPrevented;
+ bool m_defaultHandled;
+
+ SVGEvent::EventId m_id;
+ SVGElementImpl *m_currentTarget;
+ SVGElementImpl *m_target;
+
+ unsigned short m_eventPhase;
+ QDateTime m_createTime;
+
+public:
+ KSVG_BASECLASS_GET
+
+ enum
+ {
+ // Properties
+ Type, Target, CurrentTarget, EventPhase,
+ Bubbles, Cancelable, TimeStamp,
+ // Functions
+ GetType, GetTarget, GetCurrentTarget, GetEventPhase,
+ GetBubbles, GetCancelable, GetTimeStamp,
+ StopPropagation, PreventDefault, InitEvent,
+ GetCurrentNode // Out-Of-Spec
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+};
+
+class SVGEventListener : public DOM::DomShared
+{
+public:
+ SVGEventListener() { }
+ virtual ~SVGEventListener() { }
+
+ virtual void handleEvent(SVGEventImpl *) { }
+ virtual DOM::DOMString eventListenerType() { return ""; }
+};
+
+// @ecma-checked 07/07/02@
+class SVGUIEventImpl : public SVGEventImpl
+{
+public:
+ SVGUIEventImpl();
+ SVGUIEventImpl(SVGEvent::EventId _id,
+ bool canBubbleArg,
+ bool cancelableArg,
+ DOM::AbstractView &viewArg,
+ long detailArg);
+
+ virtual ~SVGUIEventImpl();
+
+ DOM::AbstractView view() const;
+ long detail() const;
+
+ void initUIEvent(const DOM::DOMString &typeArg,
+ bool canBubbleArg,
+ bool cancelableArg,
+ const DOM::AbstractView &viewArg,
+ long detailArg);
+
+ virtual bool isUIEvent() { return true; }
+ virtual DOM::DOMString eventModuleName() { return "UIEvents"; }
+
+protected:
+ DOM::AbstractView m_view;
+ long m_detail;
+
+public:
+ KSVG_GET
+
+ enum
+ {
+ // Properties
+ View, Detail,
+ // Functions
+ GetView, GetDetail, InitUIEvent
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+};
+
+// @ecma-checked 07/07/02@
+// Introduced in DOM Level 2: - internal
+class SVGMouseEventImpl : public SVGUIEventImpl
+{
+public:
+ SVGMouseEventImpl();
+ SVGMouseEventImpl(SVGEvent::EventId _id,
+ bool canBubbleArg,
+ bool cancelableArg,
+ DOM::AbstractView &viewArg,
+ long detailArg,
+ long screenXArg,
+ long screenYArg,
+ long clientXArg,
+ long clientYArg,
+ bool ctrlKeyArg,
+ bool altKeyArg,
+ bool shiftKeyArg,
+ bool metaKeyArg,
+ unsigned short buttonArg,
+ SVGElementImpl *relatedTargetArg);
+
+ virtual ~SVGMouseEventImpl();
+
+ long screenX() const;
+ long screenY() const;
+ long clientX() const;
+ long clientY() const;
+ bool ctrlKey() const;
+ bool shiftKey() const;
+ bool altKey() const;
+ bool metaKey() const;
+
+ unsigned short button() const;
+
+ SVGElementImpl *relatedTarget() const;
+
+ void initMouseEvent(const DOM::DOMString &typeArg,
+ bool canBubbleArg,
+ bool cancelableArg,
+ const DOM::AbstractView &viewArg,
+ long detailArg,
+ long screenXArg,
+ long screenYArg,
+ long clientXArg,
+ long clientYArg,
+ bool ctrlKeyArg,
+ bool altKeyArg,
+ bool shiftKeyArg,
+ bool metaKeyArg,
+ unsigned short buttonArg,
+ SVGElementImpl *relatedTargetArg);
+
+ virtual bool isMouseEvent() { return true; }
+ virtual DOM::DOMString eventModuleName() { return "MouseEvents"; }
+
+ // KSVG extensions
+ DOM::DOMString url() const;
+ void setURL(DOM::DOMString url);
+
+protected:
+ long m_screenX;
+ long m_screenY;
+ long m_clientX;
+ long m_clientY;
+ bool m_ctrlKey;
+ bool m_altKey;
+ bool m_shiftKey;
+ bool m_metaKey;
+ unsigned short m_button;
+ SVGElementImpl *m_relatedTarget;
+
+ // KSVG extension
+ DOM::DOMString m_url;
+
+public:
+ KSVG_GET
+
+ enum
+ {
+ // Properties
+ ScreenX, ScreenY, ClientX, ClientY, CtrlKey,
+ ShiftKey, AltKey, MetaKey, Button, RelatedTarget,
+ // Functions
+ GetScreenX, GetScreenY, GetClientX, GetClientY, GetCtrlKey,
+ GetShiftKey, GetAltKey, GetMetaKey, GetButton, GetRelatedTarget,
+ InitMouseEvent
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+};
+
+class SVGKeyEventImpl : public SVGUIEventImpl
+{
+public:
+ SVGKeyEventImpl();
+ SVGKeyEventImpl(SVGEvent::EventId _id,
+ bool canBubbleArg,
+ bool cancelableArg,
+ DOM::AbstractView &viewArg,
+ unsigned short detailArg,
+ DOM::DOMString &outputStringArg,
+ unsigned long keyValArg,
+ unsigned long virtKeyValArg,
+ bool inputGeneratedArg,
+ bool numPadArg);
+
+ SVGKeyEventImpl(QKeyEvent *key, DOM::AbstractView &view, SVGEvent::EventId _id);
+
+ virtual bool isKeyEvent() { return true; }
+
+ virtual ~SVGKeyEventImpl();
+
+ enum KeyCodes
+ {
+ DOM_VK_UNDEFINED = 0x0,
+ DOM_VK_RIGHT_ALT = 0x01,
+ DOM_VK_LEFT_ALT = 0x02,
+ DOM_VK_LEFT_CONTROL = 0x03,
+ DOM_VK_RIGHT_CONTROL = 0x04,
+ DOM_VK_LEFT_SHIFT = 0x05,
+ DOM_VK_RIGHT_SHIFT = 0x06,
+ DOM_VK_LEFT_META = 0x07,
+ DOM_VK_RIGHT_META = 0x08,
+ DOM_VK_CAPS_LOCK = 0x09,
+ DOM_VK_DELETE = 0x0A,
+ DOM_VK_END = 0x0B,
+ DOM_VK_ENTER = 0x0C,
+ DOM_VK_ESCAPE = 0x0D,
+ DOM_VK_HOME = 0x0E,
+ DOM_VK_INSERT = 0x0F,
+ DOM_VK_NUM_LOCK = 0x10,
+ DOM_VK_PAUSE = 0x11,
+ DOM_VK_PRINTSCREEN = 0x12,
+ DOM_VK_SCROLL_LOCK = 0x13,
+ DOM_VK_LEFT = 0x14,
+ DOM_VK_RIGHT = 0x15,
+ DOM_VK_UP = 0x16,
+ DOM_VK_DOWN = 0x17,
+ DOM_VK_PAGE_DOWN = 0x18,
+ DOM_VK_PAGE_UP = 0x19,
+ DOM_VK_F1 = 0x1A,
+ DOM_VK_F2 = 0x1B,
+ DOM_VK_F3 = 0x1C,
+ DOM_VK_F4 = 0x1D,
+ DOM_VK_F5 = 0x1E,
+ DOM_VK_F6 = 0x1F,
+ DOM_VK_F7 = 0x20,
+ DOM_VK_F8 = 0x21,
+ DOM_VK_F9 = 0x22,
+ DOM_VK_F10 = 0x23,
+ DOM_VK_F11 = 0x24,
+ DOM_VK_F12 = 0x25,
+ DOM_VK_F13 = 0x26,
+ DOM_VK_F14 = 0x27,
+ DOM_VK_F15 = 0x28,
+ DOM_VK_F16 = 0x29,
+ DOM_VK_F17 = 0x2A,
+ DOM_VK_F18 = 0x2B,
+ DOM_VK_F19 = 0x2C,
+ DOM_VK_F20 = 0x2D,
+ DOM_VK_F21 = 0x2E,
+ DOM_VK_F22 = 0x2F,
+ DOM_VK_F23 = 0x30,
+ DOM_VK_F24 = 0x31
+ };
+
+
+ bool checkModifier(unsigned long modiferArg);
+
+ void initKeyEvent(DOM::DOMString &typeArg,
+ bool canBubbleArg,
+ bool cancelableArg,
+ const DOM::AbstractView &viewArg,
+ long detailArg,
+ DOM::DOMString &outputStringArg,
+ unsigned long keyValArg,
+ unsigned long virtKeyValArg,
+ bool inputGeneratedArg,
+ bool numPadArg);
+
+ void initModifier(unsigned long modifierArg, bool valueArg);
+
+ bool inputGenerated() const;
+
+ unsigned long keyVal() const;
+
+ bool numPad() const { return m_numPad; }
+ DOM::DOMString outputString() const;
+
+ unsigned long virtKeyVal() const { return m_virtKeyVal; }
+
+ QKeyEvent *qKeyEvent;
+
+private:
+ unsigned long m_keyVal;
+ unsigned long m_virtKeyVal;
+ bool m_inputGenerated;
+ DOM::DOMString m_outputString;
+ bool m_numPad;
+
+ // bitfield containing state of modifiers. not part of the dom.
+ unsigned long m_modifier;
+
+public:
+ KSVG_GET
+
+ enum
+ {
+ // Properties
+ KeyVal, VirtKeyVal, OutputString,
+ // Functions
+ CheckModifier, GetKeyVal, GetCharCode
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+};
+
+class SVGMutationEventImpl : public SVGEventImpl
+{
+public:
+ SVGMutationEventImpl();
+ SVGMutationEventImpl(SVGEvent::EventId _id,
+ bool canBubbleArg,
+ bool cancelableArg,
+ SVGElementImpl *relatedNodeArg,
+ const DOM::DOMString &prevValueArg,
+ const DOM::DOMString &newValueArg,
+ const DOM::DOMString &attrNameArg,
+ unsigned short attrChangeArg);
+ ~SVGMutationEventImpl();
+
+ SVGElementImpl *relatedNode() const;
+ DOM::DOMString prevValue() const;
+ DOM::DOMString newValue() const;
+ DOM::DOMString attrName() const;
+ unsigned short attrChange() const;
+
+ void initMutationEvent(const DOM::DOMString &typeArg,
+ bool canBubbleArg,
+ bool cancelableArg,
+ SVGElementImpl *relatedNodeArg,
+ const DOM::DOMString &prevValueArg,
+ const DOM::DOMString &newValueArg,
+ const DOM::DOMString &attrNameArg,
+ unsigned short attrChangeArg);
+
+ virtual bool isMutationEvent() { return true; }
+ virtual DOM::DOMString eventModuleName() { return "MutationEvents"; }
+
+protected:
+ SVGElementImpl *m_relatedNode;
+ DOM::DOMString m_prevValue;
+ DOM::DOMString m_newValue;
+ DOM::DOMString m_attrName;
+ unsigned short m_attrChange;
+
+public:
+ KSVG_FORWARDGET
+};
+
+class SVGRegisteredEventListener
+{
+public:
+ SVGRegisteredEventListener(SVGEvent::EventId _id, SVGEventListener *_listener, bool _useCapture);
+ ~SVGRegisteredEventListener();
+
+ bool operator==(const SVGRegisteredEventListener &other);
+
+ SVGEvent::EventId id;
+ SVGEventListener *listener;
+ bool useCapture;
+
+private:
+ SVGRegisteredEventListener(const SVGRegisteredEventListener &);
+ SVGRegisteredEventListener &operator=(const SVGRegisteredEventListener &);
+};
+
+}
+
+KSVG_DEFINE_PROTOTYPE(SVGEventImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGEventImplProtoFunc, SVGEventImpl)
+
+KSVG_DEFINE_PROTOTYPE(SVGUIEventImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGUIEventImplProtoFunc, SVGUIEventImpl)
+
+KSVG_DEFINE_PROTOTYPE(SVGMouseEventImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGMouseEventImplProtoFunc, SVGMouseEventImpl)
+
+KSVG_DEFINE_PROTOTYPE(SVGKeyEventImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGKeyEventImplProtoFunc, SVGKeyEventImpl)
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGExternalResourcesRequiredImpl.cc b/ksvg/impl/SVGExternalResourcesRequiredImpl.cc
new file mode 100644
index 00000000..90fd9141
--- /dev/null
+++ b/ksvg/impl/SVGExternalResourcesRequiredImpl.cc
@@ -0,0 +1,88 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGAnimatedBooleanImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+using namespace KSVG;
+
+#include "SVGExternalResourcesRequiredImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+SVGExternalResourcesRequiredImpl::SVGExternalResourcesRequiredImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_externalResourcesRequired = new SVGAnimatedBooleanImpl();
+ m_externalResourcesRequired->ref();
+}
+
+SVGExternalResourcesRequiredImpl::~SVGExternalResourcesRequiredImpl()
+{
+ if(m_externalResourcesRequired)
+ m_externalResourcesRequired->deref();
+}
+
+SVGAnimatedBooleanImpl *SVGExternalResourcesRequiredImpl::externalResourcesRequired() const
+{
+ return m_externalResourcesRequired;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGExternalResourcesRequiredImpl::s_hashTable 2
+ externalResourcesRequired SVGExternalResourcesRequiredImpl::ExternalResourcesRequired DontDelete|ReadOnly
+@end
+*/
+
+Value SVGExternalResourcesRequiredImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case ExternalResourcesRequired:
+ return m_externalResourcesRequired->cache(exec);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGExternalResourcesRequiredImpl::putValueProperty(ExecState *exec, int token, const KJS::Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+ switch(token)
+ {
+ case ExternalResourcesRequired:
+ m_externalResourcesRequired->setBaseVal(value.toBoolean(exec));
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGExternalResourcesRequiredImpl.h b/ksvg/impl/SVGExternalResourcesRequiredImpl.h
new file mode 100644
index 00000000..9c5b93eb
--- /dev/null
+++ b/ksvg/impl/SVGExternalResourcesRequiredImpl.h
@@ -0,0 +1,59 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGExternalResourcesRequiredImpl_H
+#define SVGExternalResourcesRequiredImpl_H
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedBooleanImpl;
+class SVGExternalResourcesRequiredImpl
+{
+public:
+ SVGExternalResourcesRequiredImpl();
+ ~SVGExternalResourcesRequiredImpl();
+
+ SVGAnimatedBooleanImpl *externalResourcesRequired() const;
+
+private:
+ SVGAnimatedBooleanImpl *m_externalResourcesRequired;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ ExternalResourcesRequired
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEBlendElementImpl.cc b/ksvg/impl/SVGFEBlendElementImpl.cc
new file mode 100644
index 00000000..8b29cad5
--- /dev/null
+++ b/ksvg/impl/SVGFEBlendElementImpl.cc
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEBlendElementImpl.h"
+#include "SVGAnimatedStringImpl.h"
+#include "SVGAnimatedEnumerationImpl.h"
+
+using namespace KSVG;
+
+SVGFEBlendElementImpl::SVGFEBlendElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl()
+{
+ m_in1 = new SVGAnimatedStringImpl();
+ m_in1->ref();
+
+ m_in2 = new SVGAnimatedStringImpl();
+ m_in2->ref();
+
+ m_mode = new SVGAnimatedEnumerationImpl();
+ m_mode->ref();
+}
+
+SVGFEBlendElementImpl::~SVGFEBlendElementImpl()
+{
+ if(m_in1)
+ m_in1->deref();
+ if(m_in2)
+ m_in2->deref();
+ if(m_mode)
+ m_mode->deref();
+}
+
+SVGAnimatedStringImpl *SVGFEBlendElementImpl::in1() const
+{
+ return m_in1;
+}
+
+SVGAnimatedStringImpl *SVGFEBlendElementImpl::in2() const
+{
+ return m_in2;
+}
+
+SVGAnimatedEnumerationImpl *SVGFEBlendElementImpl::mode() const
+{
+ return m_mode;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEBlendElementImpl.h b/ksvg/impl/SVGFEBlendElementImpl.h
new file mode 100644
index 00000000..36aab059
--- /dev/null
+++ b/ksvg/impl/SVGFEBlendElementImpl.h
@@ -0,0 +1,59 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEBlendElementImpl_H
+#define SVGFEBlendElementImpl_H
+
+#include "SVGElementImpl.h"
+#include "SVGFilterPrimitiveStandardAttributesImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedStringImpl;
+class SVGAnimatedEnumerationImpl;
+class SVGFEBlendElementImpl : public SVGElementImpl,
+ public SVGFilterPrimitiveStandardAttributesImpl
+{
+public:
+ SVGFEBlendElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFEBlendElementImpl();
+
+ SVGAnimatedStringImpl *in1() const;
+ SVGAnimatedStringImpl *in2() const;
+ SVGAnimatedEnumerationImpl *mode() const;
+
+private:
+ SVGAnimatedStringImpl *m_in1;
+ SVGAnimatedStringImpl *m_in2;
+ SVGAnimatedEnumerationImpl *m_mode;
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEColorMatrixElementImpl.cc b/ksvg/impl/SVGFEColorMatrixElementImpl.cc
new file mode 100644
index 00000000..14c68a56
--- /dev/null
+++ b/ksvg/impl/SVGFEColorMatrixElementImpl.cc
@@ -0,0 +1,65 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedStringImpl.h"
+#include "SVGAnimatedNumberListImpl.h"
+#include "SVGAnimatedEnumerationImpl.h"
+#include "SVGFEColorMatrixElementImpl.h"
+
+using namespace KSVG;
+
+SVGFEColorMatrixElementImpl::SVGFEColorMatrixElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl()
+{
+ m_in1 = new SVGAnimatedStringImpl();
+ m_in1->ref();
+
+ m_type = new SVGAnimatedEnumerationImpl();
+ m_type->ref();
+
+ m_values = new SVGAnimatedNumberListImpl();
+ m_values->ref();
+}
+
+SVGFEColorMatrixElementImpl::~SVGFEColorMatrixElementImpl()
+{
+ if(m_in1)
+ m_in1->deref();
+ if(m_type)
+ m_type->deref();
+ if(m_values)
+ m_values->deref();
+}
+
+SVGAnimatedStringImpl *SVGFEColorMatrixElementImpl::in1() const
+{
+ return m_in1;
+}
+
+SVGAnimatedEnumerationImpl *SVGFEColorMatrixElementImpl::type() const
+{
+ return m_type;
+}
+
+SVGAnimatedNumberListImpl *SVGFEColorMatrixElementImpl::values() const
+{
+ return m_values;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEColorMatrixElementImpl.h b/ksvg/impl/SVGFEColorMatrixElementImpl.h
new file mode 100644
index 00000000..b637690b
--- /dev/null
+++ b/ksvg/impl/SVGFEColorMatrixElementImpl.h
@@ -0,0 +1,60 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEColorMatrixElementImpl_H
+#define SVGFEColorMatrixElementImpl_H
+
+#include "SVGElementImpl.h"
+#include "SVGFilterPrimitiveStandardAttributesImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedStringImpl;
+class SVGAnimatedEnumerationImpl;
+class SVGAnimatedNumberListImpl;
+class SVGFEColorMatrixElementImpl : public SVGElementImpl,
+ public SVGFilterPrimitiveStandardAttributesImpl
+{
+public:
+ SVGFEColorMatrixElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFEColorMatrixElementImpl();
+
+ SVGAnimatedStringImpl *in1() const;
+ SVGAnimatedEnumerationImpl *type() const;
+ SVGAnimatedNumberListImpl *values() const;
+
+private:
+ SVGAnimatedStringImpl *m_in1;
+ SVGAnimatedEnumerationImpl *m_type;
+ SVGAnimatedNumberListImpl *m_values;
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEComponentTransferElementImpl.cc b/ksvg/impl/SVGFEComponentTransferElementImpl.cc
new file mode 100644
index 00000000..71ee4629
--- /dev/null
+++ b/ksvg/impl/SVGFEComponentTransferElementImpl.cc
@@ -0,0 +1,43 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedStringImpl.h"
+#include "SVGFEComponentTransferElementImpl.h"
+
+using namespace KSVG;
+
+SVGFEComponentTransferElementImpl::SVGFEComponentTransferElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl()
+{
+ m_in1 = new SVGAnimatedStringImpl();
+ m_in1->ref();
+}
+
+SVGFEComponentTransferElementImpl::~SVGFEComponentTransferElementImpl()
+{
+ if(m_in1)
+ m_in1->deref();
+}
+
+SVGAnimatedStringImpl *SVGFEComponentTransferElementImpl::in1() const
+{
+ return m_in1;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEComponentTransferElementImpl.h b/ksvg/impl/SVGFEComponentTransferElementImpl.h
new file mode 100644
index 00000000..21c0fd88
--- /dev/null
+++ b/ksvg/impl/SVGFEComponentTransferElementImpl.h
@@ -0,0 +1,54 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEComponentTransferElementImpl_H
+#define SVGFEComponentTransferElementImpl_H
+
+#include "SVGElementImpl.h"
+#include "SVGFilterPrimitiveStandardAttributesImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedStringImpl;
+class SVGFEComponentTransferElementImpl : public SVGElementImpl,
+ public SVGFilterPrimitiveStandardAttributesImpl
+{
+public:
+ SVGFEComponentTransferElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFEComponentTransferElementImpl();
+
+ SVGAnimatedStringImpl *in1() const;
+
+private:
+ SVGAnimatedStringImpl *m_in1;
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFECompositeElementImpl.cc b/ksvg/impl/SVGFECompositeElementImpl.cc
new file mode 100644
index 00000000..e8b91b95
--- /dev/null
+++ b/ksvg/impl/SVGFECompositeElementImpl.cc
@@ -0,0 +1,105 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedNumberImpl.h"
+#include "SVGAnimatedStringImpl.h"
+#include "SVGFECompositeElementImpl.h"
+#include "SVGAnimatedEnumerationImpl.h"
+
+using namespace KSVG;
+
+SVGFECompositeElementImpl::SVGFECompositeElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl()
+{
+ m_in1 = new SVGAnimatedStringImpl();
+ m_in1->ref();
+
+ m_in2 = new SVGAnimatedStringImpl();
+ m_in2->ref();
+
+ m_operator = new SVGAnimatedEnumerationImpl();
+ m_operator->ref();
+
+ m_k1 = new SVGAnimatedNumberImpl();
+ m_k1->ref();
+
+ m_k2 = new SVGAnimatedNumberImpl();
+ m_k2->ref();
+
+ m_k3 = new SVGAnimatedNumberImpl();
+ m_k3->ref();
+
+ m_k4 = new SVGAnimatedNumberImpl();
+ m_k4->ref();
+}
+
+SVGFECompositeElementImpl::~SVGFECompositeElementImpl()
+{
+ if(m_in1)
+ m_in1->deref();
+ if(m_in2)
+ m_in2->deref();
+ if(m_operator)
+ m_operator->deref();
+ if(m_k1)
+ m_k1->deref();
+ if(m_k2)
+ m_k2->deref();
+ if(m_k3)
+ m_k3->deref();
+ if(m_k4)
+ m_k4->deref();
+}
+
+SVGAnimatedStringImpl *SVGFECompositeElementImpl::in1() const
+{
+ return m_in1;
+}
+
+SVGAnimatedStringImpl *SVGFECompositeElementImpl::in2() const
+{
+ return m_in2;
+}
+
+SVGAnimatedEnumerationImpl *SVGFECompositeElementImpl::Operator() const
+{
+ return m_operator;
+}
+
+SVGAnimatedNumberImpl *SVGFECompositeElementImpl::k1() const
+{
+ return m_k1;
+}
+
+SVGAnimatedNumberImpl *SVGFECompositeElementImpl::k2() const
+{
+ return m_k2;
+}
+
+SVGAnimatedNumberImpl *SVGFECompositeElementImpl::k3() const
+{
+ return m_k3;
+}
+
+SVGAnimatedNumberImpl *SVGFECompositeElementImpl::k4() const
+{
+ return m_k4;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFECompositeElementImpl.h b/ksvg/impl/SVGFECompositeElementImpl.h
new file mode 100644
index 00000000..10796ec1
--- /dev/null
+++ b/ksvg/impl/SVGFECompositeElementImpl.h
@@ -0,0 +1,68 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFECompositeElementImpl_H
+#define SVGFECompositeElementImpl_H
+
+#include "SVGElementImpl.h"
+#include "SVGFilterPrimitiveStandardAttributesImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedStringImpl;
+class SVGAnimatedNumberImpl;
+class SVGAnimatedEnumerationImpl;
+class SVGFECompositeElementImpl : public SVGElementImpl,
+ public SVGFilterPrimitiveStandardAttributesImpl
+{
+public:
+ SVGFECompositeElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFECompositeElementImpl();
+
+ SVGAnimatedStringImpl *in1() const;
+ SVGAnimatedStringImpl *in2() const;
+ SVGAnimatedEnumerationImpl *Operator() const;
+ SVGAnimatedNumberImpl *k1() const;
+ SVGAnimatedNumberImpl *k2() const;
+ SVGAnimatedNumberImpl *k3() const;
+ SVGAnimatedNumberImpl *k4() const;
+
+private:
+ SVGAnimatedStringImpl *m_in1;
+ SVGAnimatedStringImpl *m_in2;
+ SVGAnimatedEnumerationImpl *m_operator;
+ SVGAnimatedNumberImpl *m_k1;
+ SVGAnimatedNumberImpl *m_k2;
+ SVGAnimatedNumberImpl *m_k3;
+ SVGAnimatedNumberImpl *m_k4;
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEConvolveMatrixElementImpl.cc b/ksvg/impl/SVGFEConvolveMatrixElementImpl.cc
new file mode 100644
index 00000000..88eb00ee
--- /dev/null
+++ b/ksvg/impl/SVGFEConvolveMatrixElementImpl.cc
@@ -0,0 +1,149 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedNumberImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGAnimatedIntegerImpl.h"
+#include "SVGAnimatedBooleanImpl.h"
+#include "SVGAnimatedIntegerImpl.h"
+#include "SVGAnimatedNumberListImpl.h"
+#include "SVGAnimatedEnumerationImpl.h"
+#include "SVGFEConvolveMatrixElementImpl.h"
+
+using namespace KSVG;
+
+SVGFEConvolveMatrixElementImpl::SVGFEConvolveMatrixElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl()
+{
+ m_orderX = new SVGAnimatedIntegerImpl();
+ m_orderX->ref();
+
+ m_orderY = new SVGAnimatedIntegerImpl();
+ m_orderY->ref();
+
+ m_kernelMatrix = new SVGAnimatedNumberListImpl();
+ m_kernelMatrix->ref();
+
+ m_divisor = new SVGAnimatedNumberImpl();
+ m_divisor->ref();
+
+ m_bias = new SVGAnimatedNumberImpl();
+ m_bias->ref();
+
+ m_targetX = new SVGAnimatedIntegerImpl();
+ m_targetX->ref();
+
+ m_targetY = new SVGAnimatedIntegerImpl();
+ m_targetY->ref();
+
+ m_edgeMode = new SVGAnimatedEnumerationImpl();
+ m_edgeMode->ref();
+
+ m_kernelUnitLengthX = new SVGAnimatedLengthImpl();
+ m_kernelUnitLengthX->ref();
+
+ m_kernelUnitLengthY = new SVGAnimatedLengthImpl();
+ m_kernelUnitLengthY->ref();
+
+ m_preserveAlpha = new SVGAnimatedBooleanImpl();
+ m_preserveAlpha->ref();
+}
+
+SVGFEConvolveMatrixElementImpl::~SVGFEConvolveMatrixElementImpl()
+{
+ if(m_orderX)
+ m_orderX->deref();
+ if(m_orderY)
+ m_orderY->deref();
+ if(m_kernelMatrix)
+ m_kernelMatrix->deref();
+ if(m_divisor)
+ m_divisor->deref();
+ if(m_bias)
+ m_bias->deref();
+ if(m_targetX)
+ m_targetX->deref();
+ if(m_targetY)
+ m_targetY->deref();
+ if(m_edgeMode)
+ m_edgeMode->deref();
+ if(m_kernelUnitLengthX)
+ m_kernelUnitLengthX->deref();
+ if(m_kernelUnitLengthY)
+ m_kernelUnitLengthY->deref();
+ if(m_preserveAlpha)
+ m_preserveAlpha->deref();
+}
+
+SVGAnimatedIntegerImpl *SVGFEConvolveMatrixElementImpl::orderX() const
+{
+ return m_orderX;
+}
+
+SVGAnimatedIntegerImpl *SVGFEConvolveMatrixElementImpl::orderY() const
+{
+ return m_orderY;
+}
+
+SVGAnimatedNumberListImpl *SVGFEConvolveMatrixElementImpl::kernelMatrix() const
+{
+ return m_kernelMatrix;
+}
+
+SVGAnimatedNumberImpl *SVGFEConvolveMatrixElementImpl::divisor() const
+{
+ return m_divisor;
+}
+
+SVGAnimatedNumberImpl *SVGFEConvolveMatrixElementImpl::bias() const
+{
+ return m_bias;
+}
+
+SVGAnimatedIntegerImpl *SVGFEConvolveMatrixElementImpl::targetX() const
+{
+ return m_targetX;
+}
+
+SVGAnimatedIntegerImpl *SVGFEConvolveMatrixElementImpl::targetY() const
+{
+ return m_targetY;
+}
+
+SVGAnimatedEnumerationImpl *SVGFEConvolveMatrixElementImpl::edgeMode() const
+{
+ return m_edgeMode;
+}
+
+SVGAnimatedLengthImpl *SVGFEConvolveMatrixElementImpl::kernelUnitLengthX() const
+{
+ return m_kernelUnitLengthX;
+}
+
+SVGAnimatedLengthImpl *SVGFEConvolveMatrixElementImpl::kernelUnitLengthY() const
+{
+ return m_kernelUnitLengthY;
+}
+
+SVGAnimatedBooleanImpl *SVGFEConvolveMatrixElementImpl::preserveAlpha() const
+{
+ return m_preserveAlpha;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEConvolveMatrixElementImpl.h b/ksvg/impl/SVGFEConvolveMatrixElementImpl.h
new file mode 100644
index 00000000..e26518d5
--- /dev/null
+++ b/ksvg/impl/SVGFEConvolveMatrixElementImpl.h
@@ -0,0 +1,80 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEConvolveMatrixElementImpl_H
+#define SVGFEConvolveMatrixElementImpl_H
+
+#include "SVGElementImpl.h"
+#include "SVGFilterPrimitiveStandardAttributesImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedNumberImpl;
+class SVGAnimatedLengthImpl;
+class SVGAnimatedIntegerImpl;
+class SVGAnimatedIntegerImpl;
+class SVGAnimatedBooleanImpl;
+class SVGAnimatedNumberListImpl;
+class SVGAnimatedEnumerationImpl;
+class SVGFEConvolveMatrixElementImpl : public SVGElementImpl,
+ public SVGFilterPrimitiveStandardAttributesImpl
+{
+public:
+ SVGFEConvolveMatrixElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFEConvolveMatrixElementImpl();
+
+ SVGAnimatedIntegerImpl *orderX() const;
+ SVGAnimatedIntegerImpl *orderY() const;
+ SVGAnimatedNumberListImpl *kernelMatrix() const;
+ SVGAnimatedNumberImpl *divisor() const;
+ SVGAnimatedNumberImpl *bias() const;
+ SVGAnimatedIntegerImpl *targetX() const;
+ SVGAnimatedIntegerImpl *targetY() const;
+ SVGAnimatedEnumerationImpl *edgeMode() const;
+ SVGAnimatedLengthImpl *kernelUnitLengthX() const;
+ SVGAnimatedLengthImpl *kernelUnitLengthY() const;
+ SVGAnimatedBooleanImpl *preserveAlpha() const;
+
+private:
+ SVGAnimatedIntegerImpl *m_orderX;
+ SVGAnimatedIntegerImpl *m_orderY;
+ SVGAnimatedNumberListImpl *m_kernelMatrix;
+ SVGAnimatedNumberImpl *m_divisor;
+ SVGAnimatedNumberImpl *m_bias;
+ SVGAnimatedIntegerImpl *m_targetX;
+ SVGAnimatedIntegerImpl *m_targetY;
+ SVGAnimatedEnumerationImpl *m_edgeMode;
+ SVGAnimatedLengthImpl *m_kernelUnitLengthX;
+ SVGAnimatedLengthImpl *m_kernelUnitLengthY;
+ SVGAnimatedBooleanImpl *m_preserveAlpha;
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEDiffuseLightingElementImpl.cc b/ksvg/impl/SVGFEDiffuseLightingElementImpl.cc
new file mode 100644
index 00000000..0b5c2565
--- /dev/null
+++ b/ksvg/impl/SVGFEDiffuseLightingElementImpl.cc
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedStringImpl.h"
+#include "SVGAnimatedNumberImpl.h"
+#include "SVGFEDiffuseLightingElementImpl.h"
+
+using namespace KSVG;
+
+SVGFEDiffuseLightingElementImpl::SVGFEDiffuseLightingElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl()
+{
+ m_in1 = new SVGAnimatedStringImpl();
+ m_in1->ref();
+
+ m_surfaceScale = new SVGAnimatedNumberImpl();
+ m_surfaceScale->ref();
+
+ m_diffuseConstant = new SVGAnimatedNumberImpl();
+ m_diffuseConstant->ref();
+}
+
+SVGFEDiffuseLightingElementImpl::~SVGFEDiffuseLightingElementImpl()
+{
+ if(m_in1)
+ m_in1->deref();
+ if(m_surfaceScale)
+ m_surfaceScale->deref();
+ if(m_diffuseConstant)
+ m_diffuseConstant->deref();
+}
+
+SVGAnimatedStringImpl *SVGFEDiffuseLightingElementImpl::in1() const
+{
+ return m_in1;
+}
+
+SVGAnimatedNumberImpl *SVGFEDiffuseLightingElementImpl::surfaceScale() const
+{
+ return m_surfaceScale;
+}
+
+SVGAnimatedNumberImpl *SVGFEDiffuseLightingElementImpl::diffuseConstant() const
+{
+ return m_diffuseConstant;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEDiffuseLightingElementImpl.h b/ksvg/impl/SVGFEDiffuseLightingElementImpl.h
new file mode 100644
index 00000000..0be4f7f1
--- /dev/null
+++ b/ksvg/impl/SVGFEDiffuseLightingElementImpl.h
@@ -0,0 +1,59 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEDiffuseLightingElementImpl_H
+#define SVGFEDiffuseLightingElementImpl_H
+
+#include "SVGElementImpl.h"
+#include "SVGFilterPrimitiveStandardAttributesImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedStringImpl;
+class SVGAnimatedNumberImpl;
+class SVGFEDiffuseLightingElementImpl : public SVGElementImpl,
+ public SVGFilterPrimitiveStandardAttributesImpl
+{
+public:
+ SVGFEDiffuseLightingElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFEDiffuseLightingElementImpl();
+
+ SVGAnimatedStringImpl *in1() const;
+ SVGAnimatedNumberImpl *surfaceScale() const;
+ SVGAnimatedNumberImpl *diffuseConstant() const;
+
+private:
+ SVGAnimatedStringImpl *m_in1;
+ SVGAnimatedNumberImpl *m_surfaceScale;
+ SVGAnimatedNumberImpl *m_diffuseConstant;
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEDisplacementMapElementImpl.cc b/ksvg/impl/SVGFEDisplacementMapElementImpl.cc
new file mode 100644
index 00000000..92665ec7
--- /dev/null
+++ b/ksvg/impl/SVGFEDisplacementMapElementImpl.cc
@@ -0,0 +1,85 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedStringImpl.h"
+#include "SVGAnimatedNumberImpl.h"
+#include "SVGAnimatedEnumerationImpl.h"
+#include "SVGFEDisplacementMapElementImpl.h"
+
+using namespace KSVG;
+
+SVGFEDisplacementMapElementImpl::SVGFEDisplacementMapElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl()
+{
+ m_in1 = new SVGAnimatedStringImpl();
+ m_in1->ref();
+
+ m_in2 = new SVGAnimatedStringImpl();
+ m_in2->ref();
+
+ m_scale = new SVGAnimatedNumberImpl();
+ m_scale->ref();
+
+ m_xChannelSelector = new SVGAnimatedEnumerationImpl();
+ m_xChannelSelector->ref();
+
+ m_yChannelSelector = new SVGAnimatedEnumerationImpl();
+ m_yChannelSelector->ref();
+}
+
+SVGFEDisplacementMapElementImpl::~SVGFEDisplacementMapElementImpl()
+{
+ if(m_in1)
+ m_in1->deref();
+ if(m_in2)
+ m_in2->deref();
+ if(m_scale)
+ m_scale->deref();
+ if(m_xChannelSelector)
+ m_xChannelSelector->deref();
+ if(m_yChannelSelector)
+ m_yChannelSelector->deref();
+}
+
+SVGAnimatedStringImpl *SVGFEDisplacementMapElementImpl::in1() const
+{
+ return m_in1;
+}
+
+SVGAnimatedStringImpl *SVGFEDisplacementMapElementImpl::in2() const
+{
+ return m_in2;
+}
+
+SVGAnimatedNumberImpl *SVGFEDisplacementMapElementImpl::scale() const
+{
+ return m_scale;
+}
+
+SVGAnimatedEnumerationImpl *SVGFEDisplacementMapElementImpl::xChannelSelector() const
+{
+ return m_xChannelSelector;
+}
+
+SVGAnimatedEnumerationImpl *SVGFEDisplacementMapElementImpl::yChannelSelector() const
+{
+ return m_yChannelSelector;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEDisplacementMapElementImpl.h b/ksvg/impl/SVGFEDisplacementMapElementImpl.h
new file mode 100644
index 00000000..3774b6cc
--- /dev/null
+++ b/ksvg/impl/SVGFEDisplacementMapElementImpl.h
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEDisplacementMapElementImpl_H
+#define SVGFEDisplacementMapElementImpl_H
+
+#include "SVGElementImpl.h"
+#include "SVGFilterPrimitiveStandardAttributesImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedStringImpl;
+class SVGAnimatedNumberImpl;
+class SVGAnimatedEnumerationImpl;
+class SVGFEDisplacementMapElementImpl : public SVGElementImpl,
+ public SVGFilterPrimitiveStandardAttributesImpl
+{
+public:
+ SVGFEDisplacementMapElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFEDisplacementMapElementImpl();
+
+ SVGAnimatedStringImpl *in1() const;
+ SVGAnimatedStringImpl *in2() const;
+ SVGAnimatedNumberImpl *scale() const;
+ SVGAnimatedEnumerationImpl *xChannelSelector() const;
+ SVGAnimatedEnumerationImpl *yChannelSelector() const;
+
+private:
+ SVGAnimatedStringImpl *m_in1;
+ SVGAnimatedStringImpl *m_in2;
+ SVGAnimatedNumberImpl *m_scale;
+ SVGAnimatedEnumerationImpl *m_xChannelSelector;
+ SVGAnimatedEnumerationImpl *m_yChannelSelector;
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEDistantLightElementImpl.cc b/ksvg/impl/SVGFEDistantLightElementImpl.cc
new file mode 100644
index 00000000..b40885e0
--- /dev/null
+++ b/ksvg/impl/SVGFEDistantLightElementImpl.cc
@@ -0,0 +1,53 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedNumberImpl.h"
+#include "SVGFEDistantLightElementImpl.h"
+
+using namespace KSVG;
+
+SVGFEDistantLightElementImpl::SVGFEDistantLightElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl)
+{
+ m_azimuth = new SVGAnimatedNumberImpl();
+ m_azimuth->ref();
+
+ m_elevation = new SVGAnimatedNumberImpl();
+ m_elevation->ref();
+}
+
+SVGFEDistantLightElementImpl::~SVGFEDistantLightElementImpl()
+{
+ if(m_azimuth)
+ m_azimuth->deref();
+ if(m_elevation)
+ m_elevation->deref();
+}
+
+SVGAnimatedNumberImpl *SVGFEDistantLightElementImpl::azimuth() const
+{
+ return m_azimuth;
+}
+
+SVGAnimatedNumberImpl *SVGFEDistantLightElementImpl::elevation() const
+{
+ return m_elevation;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEDistantLightElementImpl.h b/ksvg/impl/SVGFEDistantLightElementImpl.h
new file mode 100644
index 00000000..4d995a44
--- /dev/null
+++ b/ksvg/impl/SVGFEDistantLightElementImpl.h
@@ -0,0 +1,54 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEDistantLightElementImpl_H
+#define SVGFEDistantLightElementImpl_H
+
+#include "SVGElementImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedNumberImpl;
+class SVGFEDistantLightElementImpl : public SVGElementImpl
+{
+public:
+ SVGFEDistantLightElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFEDistantLightElementImpl();
+
+ SVGAnimatedNumberImpl *azimuth() const;
+ SVGAnimatedNumberImpl *elevation() const;
+
+private:
+ SVGAnimatedNumberImpl *m_azimuth;
+ SVGAnimatedNumberImpl *m_elevation;
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEFloodElementImpl.cc b/ksvg/impl/SVGFEFloodElementImpl.cc
new file mode 100644
index 00000000..7cbecafd
--- /dev/null
+++ b/ksvg/impl/SVGFEFloodElementImpl.cc
@@ -0,0 +1,43 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEFloodElementImpl.h"
+#include "SVGAnimatedStringImpl.h"
+
+using namespace KSVG;
+
+SVGFEFloodElementImpl::SVGFEFloodElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGStylableImpl(this), SVGFilterPrimitiveStandardAttributesImpl()
+{
+ m_in1 = new SVGAnimatedStringImpl();
+ m_in1->ref();
+}
+
+SVGFEFloodElementImpl::~SVGFEFloodElementImpl()
+{
+ if(m_in1)
+ m_in1->deref();
+}
+
+SVGAnimatedStringImpl *SVGFEFloodElementImpl::in1() const
+{
+ return m_in1;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEFloodElementImpl.h b/ksvg/impl/SVGFEFloodElementImpl.h
new file mode 100644
index 00000000..858959a9
--- /dev/null
+++ b/ksvg/impl/SVGFEFloodElementImpl.h
@@ -0,0 +1,56 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEFloodElementImpl_H
+#define SVGFEFloodElementImpl_H
+
+#include "SVGElementImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGFilterPrimitiveStandardAttributesImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedStringImpl;
+class SVGFEFloodElementImpl : public SVGElementImpl,
+ public SVGStylableImpl,
+ public SVGFilterPrimitiveStandardAttributesImpl
+{
+public:
+ SVGFEFloodElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFEFloodElementImpl();
+
+ SVGAnimatedStringImpl *in1() const;
+
+private:
+ SVGAnimatedStringImpl *m_in1;
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEFuncAElementImpl.cc b/ksvg/impl/SVGFEFuncAElementImpl.cc
new file mode 100644
index 00000000..c7a535fa
--- /dev/null
+++ b/ksvg/impl/SVGFEFuncAElementImpl.cc
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEFuncAElementImpl.h"
+
+using namespace KSVG;
+
+SVGFEFuncAElementImpl::SVGFEFuncAElementImpl(DOM::ElementImpl *impl) : SVGComponentTransferFunctionElementImpl(impl)
+{
+}
+
+SVGFEFuncAElementImpl::~SVGFEFuncAElementImpl()
+{
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEFuncAElementImpl.h b/ksvg/impl/SVGFEFuncAElementImpl.h
new file mode 100644
index 00000000..7999c7e2
--- /dev/null
+++ b/ksvg/impl/SVGFEFuncAElementImpl.h
@@ -0,0 +1,46 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEFuncAElementImpl_H
+#define SVGFEFuncAElementImpl_H
+
+#include "SVGComponentTransferFunctionElementImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGFEFuncAElementImpl : public SVGComponentTransferFunctionElementImpl
+{
+public:
+ SVGFEFuncAElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFEFuncAElementImpl();
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEFuncBElementImpl.cc b/ksvg/impl/SVGFEFuncBElementImpl.cc
new file mode 100644
index 00000000..4b0bbf71
--- /dev/null
+++ b/ksvg/impl/SVGFEFuncBElementImpl.cc
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEFuncBElementImpl.h"
+
+using namespace KSVG;
+
+SVGFEFuncBElementImpl::SVGFEFuncBElementImpl(DOM::ElementImpl *impl) : SVGComponentTransferFunctionElementImpl(impl)
+{
+}
+
+SVGFEFuncBElementImpl::~SVGFEFuncBElementImpl()
+{
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEFuncBElementImpl.h b/ksvg/impl/SVGFEFuncBElementImpl.h
new file mode 100644
index 00000000..7236debb
--- /dev/null
+++ b/ksvg/impl/SVGFEFuncBElementImpl.h
@@ -0,0 +1,45 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEFuncBElementImpl_H
+#define SVGFEFuncBElementImpl_H
+
+#include "SVGComponentTransferFunctionElementImpl.h"
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGFEFuncBElementImpl : public SVGComponentTransferFunctionElementImpl
+{
+public:
+ SVGFEFuncBElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFEFuncBElementImpl();
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEFuncGElementImpl.cc b/ksvg/impl/SVGFEFuncGElementImpl.cc
new file mode 100644
index 00000000..8a60fbee
--- /dev/null
+++ b/ksvg/impl/SVGFEFuncGElementImpl.cc
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEFuncGElementImpl.h"
+
+using namespace KSVG;
+
+SVGFEFuncGElementImpl::SVGFEFuncGElementImpl(DOM::ElementImpl *impl) : SVGComponentTransferFunctionElementImpl(impl)
+{
+}
+
+SVGFEFuncGElementImpl::~SVGFEFuncGElementImpl()
+{
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEFuncGElementImpl.h b/ksvg/impl/SVGFEFuncGElementImpl.h
new file mode 100644
index 00000000..44baec8d
--- /dev/null
+++ b/ksvg/impl/SVGFEFuncGElementImpl.h
@@ -0,0 +1,46 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEFuncGElementImpl_H
+#define SVGFEFuncGElementImpl_H
+
+#include "SVGComponentTransferFunctionElementImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGFEFuncGElementImpl : public SVGComponentTransferFunctionElementImpl
+{
+public:
+ SVGFEFuncGElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFEFuncGElementImpl();
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEFuncRElementImpl.cc b/ksvg/impl/SVGFEFuncRElementImpl.cc
new file mode 100644
index 00000000..fe1b2d44
--- /dev/null
+++ b/ksvg/impl/SVGFEFuncRElementImpl.cc
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEFuncRElementImpl.h"
+
+using namespace KSVG;
+
+SVGFEFuncRElementImpl::SVGFEFuncRElementImpl(DOM::ElementImpl *impl) : SVGComponentTransferFunctionElementImpl(impl)
+{
+}
+
+SVGFEFuncRElementImpl::~SVGFEFuncRElementImpl()
+{
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEFuncRElementImpl.h b/ksvg/impl/SVGFEFuncRElementImpl.h
new file mode 100644
index 00000000..17aa7812
--- /dev/null
+++ b/ksvg/impl/SVGFEFuncRElementImpl.h
@@ -0,0 +1,46 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEFuncRElementImpl_H
+#define SVGFEFuncRElementImpl_H
+
+#include "SVGComponentTransferFunctionElementImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGFEFuncRElementImpl : public SVGComponentTransferFunctionElementImpl
+{
+public:
+ SVGFEFuncRElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFEFuncRElementImpl();
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEGaussianBlurElementImpl.cc b/ksvg/impl/SVGFEGaussianBlurElementImpl.cc
new file mode 100644
index 00000000..bcc2e0bf
--- /dev/null
+++ b/ksvg/impl/SVGFEGaussianBlurElementImpl.cc
@@ -0,0 +1,68 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedStringImpl.h"
+#include "SVGAnimatedNumberImpl.h"
+#include "SVGFEGaussianBlurElementImpl.h"
+
+using namespace KSVG;
+
+SVGFEGaussianBlurElementImpl::SVGFEGaussianBlurElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl()
+{
+ m_in1 = new SVGAnimatedStringImpl();
+ m_in1->ref();
+
+ m_stdDeviationX = new SVGAnimatedNumberImpl();
+ m_stdDeviationX->ref();
+
+ m_stdDeviationY = new SVGAnimatedNumberImpl();
+ m_stdDeviationY->ref();
+}
+
+SVGFEGaussianBlurElementImpl::~SVGFEGaussianBlurElementImpl()
+{
+ if(m_in1)
+ m_in1->deref();
+ if(m_stdDeviationX)
+ m_stdDeviationX->deref();
+ if(m_stdDeviationY)
+ m_stdDeviationY->deref();
+}
+
+SVGAnimatedStringImpl *SVGFEGaussianBlurElementImpl::in1() const
+{
+ return m_in1;
+}
+
+SVGAnimatedNumberImpl *SVGFEGaussianBlurElementImpl::stdDeviationX() const
+{
+ return m_stdDeviationX;
+}
+
+SVGAnimatedNumberImpl *SVGFEGaussianBlurElementImpl::stdDeviationY() const
+{
+ return m_stdDeviationY;
+}
+
+void SVGFEGaussianBlurElementImpl::setStdDeviation(float /*stdDeviationX*/, float /*stdDeviationY*/)
+{
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEGaussianBlurElementImpl.h b/ksvg/impl/SVGFEGaussianBlurElementImpl.h
new file mode 100644
index 00000000..97707edb
--- /dev/null
+++ b/ksvg/impl/SVGFEGaussianBlurElementImpl.h
@@ -0,0 +1,60 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEGaussianBlurElementImpl_H
+#define SVGFEGaussianBlurElementImpl_H
+
+#include "SVGElementImpl.h"
+#include "SVGFilterPrimitiveStandardAttributesImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedStringImpl;
+class SVGAnimatedNumberImpl;
+class SVGFEGaussianBlurElementImpl : public SVGElementImpl,
+ public SVGFilterPrimitiveStandardAttributesImpl
+{
+public:
+ SVGFEGaussianBlurElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFEGaussianBlurElementImpl();
+
+ SVGAnimatedStringImpl *in1() const;
+ SVGAnimatedNumberImpl *stdDeviationX() const;
+ SVGAnimatedNumberImpl *stdDeviationY() const;
+ void setStdDeviation(float stdDeviationX, float stdDeviationY);
+
+private:
+ SVGAnimatedStringImpl *m_in1;
+ SVGAnimatedNumberImpl *m_stdDeviationX;
+ SVGAnimatedNumberImpl *m_stdDeviationY;
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEImageElementImpl.cc b/ksvg/impl/SVGFEImageElementImpl.cc
new file mode 100644
index 00000000..f41e482d
--- /dev/null
+++ b/ksvg/impl/SVGFEImageElementImpl.cc
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEImageElementImpl.h"
+
+using namespace KSVG;
+
+SVGFEImageElementImpl::SVGFEImageElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGURIReferenceImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGFilterPrimitiveStandardAttributesImpl()
+{
+}
+
+SVGFEImageElementImpl::~SVGFEImageElementImpl()
+{
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEImageElementImpl.h b/ksvg/impl/SVGFEImageElementImpl.h
new file mode 100644
index 00000000..3d03e77d
--- /dev/null
+++ b/ksvg/impl/SVGFEImageElementImpl.h
@@ -0,0 +1,56 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEImageElementImpl_H
+#define SVGFEImageElementImpl_H
+
+#include "SVGElementImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGLangSpaceImpl.h"
+#include "SVGURIReferenceImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+#include "SVGFilterPrimitiveStandardAttributesImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGFEImageElementImpl : public SVGElementImpl,
+ public SVGURIReferenceImpl,
+ public SVGLangSpaceImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGStylableImpl,
+ public SVGFilterPrimitiveStandardAttributesImpl
+{
+public:
+ SVGFEImageElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFEImageElementImpl();
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEMergeElementImpl.cc b/ksvg/impl/SVGFEMergeElementImpl.cc
new file mode 100644
index 00000000..6eca907a
--- /dev/null
+++ b/ksvg/impl/SVGFEMergeElementImpl.cc
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFEMergeElementImpl.h"
+
+using namespace KSVG;
+
+SVGFEMergeElementImpl::SVGFEMergeElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl()
+{
+}
+
+SVGFEMergeElementImpl::~SVGFEMergeElementImpl()
+{
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEMergeElementImpl.h b/ksvg/impl/SVGFEMergeElementImpl.h
new file mode 100644
index 00000000..f4b6aaaf
--- /dev/null
+++ b/ksvg/impl/SVGFEMergeElementImpl.h
@@ -0,0 +1,48 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEMergeElementImpl_H
+#define SVGFEMergeElementImpl_H
+
+#include "SVGElementImpl.h"
+#include "SVGFilterPrimitiveStandardAttributesImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGFEMergeElementImpl : public SVGElementImpl,
+ public SVGFilterPrimitiveStandardAttributesImpl
+{
+public:
+ SVGFEMergeElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFEMergeElementImpl();
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEMergeNodeElementImpl.cc b/ksvg/impl/SVGFEMergeNodeElementImpl.cc
new file mode 100644
index 00000000..1191df3b
--- /dev/null
+++ b/ksvg/impl/SVGFEMergeNodeElementImpl.cc
@@ -0,0 +1,43 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedStringImpl.h"
+#include "SVGFEMergeNodeElementImpl.h"
+
+using namespace KSVG;
+
+SVGFEMergeNodeElementImpl::SVGFEMergeNodeElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl)
+{
+ m_in1 = new SVGAnimatedStringImpl();
+ m_in1->ref();
+}
+
+SVGFEMergeNodeElementImpl::~SVGFEMergeNodeElementImpl()
+{
+ if(m_in1)
+ m_in1->deref();
+}
+
+SVGAnimatedStringImpl *SVGFEMergeNodeElementImpl::in1() const
+{
+ return m_in1;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEMergeNodeElementImpl.h b/ksvg/impl/SVGFEMergeNodeElementImpl.h
new file mode 100644
index 00000000..5b380757
--- /dev/null
+++ b/ksvg/impl/SVGFEMergeNodeElementImpl.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEMergeNodeElementImpl_H
+#define SVGFEMergeNodeElementImpl_H
+
+#include "SVGElementImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedStringImpl;
+class SVGFEMergeNodeElementImpl : public SVGElementImpl
+{
+public:
+ SVGFEMergeNodeElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFEMergeNodeElementImpl();
+
+ SVGAnimatedStringImpl *in1() const;
+
+private:
+ SVGAnimatedStringImpl *m_in1;
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEMorphologyElementImpl.cc b/ksvg/impl/SVGFEMorphologyElementImpl.cc
new file mode 100644
index 00000000..e7f1a100
--- /dev/null
+++ b/ksvg/impl/SVGFEMorphologyElementImpl.cc
@@ -0,0 +1,75 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedStringImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGAnimatedEnumerationImpl.h"
+#include "SVGFEMorphologyElementImpl.h"
+
+using namespace KSVG;
+
+SVGFEMorphologyElementImpl::SVGFEMorphologyElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl()
+{
+ m_in1 = new SVGAnimatedStringImpl();
+ m_in1->ref();
+
+ m_operator = new SVGAnimatedEnumerationImpl();
+ m_operator->ref();
+
+ m_radiusX = new SVGAnimatedLengthImpl();
+ m_radiusX->ref();
+
+ m_radiusY = new SVGAnimatedLengthImpl();
+ m_radiusY->ref();
+}
+
+SVGFEMorphologyElementImpl::~SVGFEMorphologyElementImpl()
+{
+ if(m_in1)
+ m_in1->deref();
+ if(m_operator)
+ m_operator->deref();
+ if(m_radiusX)
+ m_radiusX->deref();
+ if(m_radiusY)
+ m_radiusY->deref();
+}
+
+SVGAnimatedStringImpl *SVGFEMorphologyElementImpl::in1() const
+{
+ return m_in1;
+}
+
+SVGAnimatedEnumerationImpl *SVGFEMorphologyElementImpl::Operator() const
+{
+ return m_operator;
+}
+
+SVGAnimatedLengthImpl *SVGFEMorphologyElementImpl::radiusX() const
+{
+ return m_radiusX;
+}
+
+SVGAnimatedLengthImpl *SVGFEMorphologyElementImpl::radiusY() const
+{
+ return m_radiusY;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEMorphologyElementImpl.h b/ksvg/impl/SVGFEMorphologyElementImpl.h
new file mode 100644
index 00000000..7941e772
--- /dev/null
+++ b/ksvg/impl/SVGFEMorphologyElementImpl.h
@@ -0,0 +1,62 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEMorphologyElementImpl_H
+#define SVGFEMorphologyElementImpl_H
+
+#include "SVGElementImpl.h"
+#include "SVGFilterPrimitiveStandardAttributesImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedStringImpl;
+class SVGAnimatedLengthImpl;
+class SVGAnimatedEnumerationImpl;
+class SVGFEMorphologyElementImpl : public SVGElementImpl,
+ public SVGFilterPrimitiveStandardAttributesImpl
+{
+public:
+ SVGFEMorphologyElementImpl(DOM::ElementImpl *impl);
+ virtual ~SVGFEMorphologyElementImpl();
+
+ SVGAnimatedStringImpl *in1() const;
+ SVGAnimatedEnumerationImpl *Operator() const;
+ SVGAnimatedLengthImpl *radiusX() const;
+ SVGAnimatedLengthImpl *radiusY() const;
+
+private:
+ SVGAnimatedStringImpl *m_in1;
+ SVGAnimatedEnumerationImpl *m_operator;
+ SVGAnimatedLengthImpl *m_radiusX;
+ SVGAnimatedLengthImpl *m_radiusY;
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEOffsetElementImpl.cc b/ksvg/impl/SVGFEOffsetElementImpl.cc
new file mode 100644
index 00000000..8c8bfbeb
--- /dev/null
+++ b/ksvg/impl/SVGFEOffsetElementImpl.cc
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedStringImpl.h"
+#include "SVGAnimatedNumberImpl.h"
+#include "SVGFEOffsetElementImpl.h"
+
+using namespace KSVG;
+
+SVGFEOffsetElementImpl::SVGFEOffsetElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl()
+{
+ m_in1 = new SVGAnimatedStringImpl();
+ m_in1->ref();
+
+ m_dx = new SVGAnimatedNumberImpl();
+ m_dx->ref();
+
+ m_dy = new SVGAnimatedNumberImpl();
+ m_dy->ref();
+}
+
+SVGFEOffsetElementImpl::~SVGFEOffsetElementImpl()
+{
+ if(m_in1)
+ m_in1->deref();
+ if(m_dx)
+ m_dx->deref();
+ if(m_dy)
+ m_dy->deref();
+}
+
+SVGAnimatedStringImpl *SVGFEOffsetElementImpl::in1() const
+{
+ return m_in1;
+}
+
+SVGAnimatedNumberImpl *SVGFEOffsetElementImpl::dx() const
+{
+ return m_dx;
+}
+
+SVGAnimatedNumberImpl *SVGFEOffsetElementImpl::dy() const
+{
+ return m_dy;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEOffsetElementImpl.h b/ksvg/impl/SVGFEOffsetElementImpl.h
new file mode 100644
index 00000000..e8c3448a
--- /dev/null
+++ b/ksvg/impl/SVGFEOffsetElementImpl.h
@@ -0,0 +1,59 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEOffsetElementImpl_H
+#define SVGFEOffsetElementImpl_H
+
+#include "SVGElementImpl.h"
+#include "SVGFilterPrimitiveStandardAttributesImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedStringImpl;
+class SVGAnimatedNumberImpl;
+class SVGFEOffsetElementImpl : public SVGElementImpl,
+ public SVGFilterPrimitiveStandardAttributesImpl
+{
+public:
+ SVGFEOffsetElementImpl(DOM::ElementImpl *impl);
+ virtual ~SVGFEOffsetElementImpl();
+
+ SVGAnimatedStringImpl *in1() const;
+ SVGAnimatedNumberImpl *dx() const;
+ SVGAnimatedNumberImpl *dy() const;
+
+private:
+ SVGAnimatedStringImpl *m_in1;
+ SVGAnimatedNumberImpl *m_dx;
+ SVGAnimatedNumberImpl *m_dy;
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEPointLightElementImpl.cc b/ksvg/impl/SVGFEPointLightElementImpl.cc
new file mode 100644
index 00000000..ad95d20a
--- /dev/null
+++ b/ksvg/impl/SVGFEPointLightElementImpl.cc
@@ -0,0 +1,63 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedNumberImpl.h"
+#include "SVGFEPointLightElementImpl.h"
+
+using namespace KSVG;
+
+SVGFEPointLightElementImpl::SVGFEPointLightElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl)
+{
+ m_x = new SVGAnimatedNumberImpl();
+ m_x->ref();
+
+ m_y = new SVGAnimatedNumberImpl();
+ m_y->ref();
+
+ m_z = new SVGAnimatedNumberImpl();
+ m_z->ref();
+}
+
+SVGFEPointLightElementImpl::~SVGFEPointLightElementImpl()
+{
+ if(m_x)
+ m_x->deref();
+ if(m_y)
+ m_y->deref();
+ if(m_z)
+ m_z->deref();
+}
+
+SVGAnimatedNumberImpl *SVGFEPointLightElementImpl::x() const
+{
+ return m_x;
+}
+
+SVGAnimatedNumberImpl *SVGFEPointLightElementImpl::y() const
+{
+ return m_y;
+}
+
+SVGAnimatedNumberImpl *SVGFEPointLightElementImpl::z() const
+{
+ return m_z;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFEPointLightElementImpl.h b/ksvg/impl/SVGFEPointLightElementImpl.h
new file mode 100644
index 00000000..6d66c98b
--- /dev/null
+++ b/ksvg/impl/SVGFEPointLightElementImpl.h
@@ -0,0 +1,56 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFEPointLightElementImpl_H
+#define SVGFEPointLightElementImpl_H
+
+#include "SVGElementImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedNumberImpl;
+class SVGFEPointLightElementImpl : public SVGElementImpl
+{
+public:
+ SVGFEPointLightElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFEPointLightElementImpl();
+
+ SVGAnimatedNumberImpl *x() const;
+ SVGAnimatedNumberImpl *y() const;
+ SVGAnimatedNumberImpl *z() const;
+
+private:
+ SVGAnimatedNumberImpl *m_x;
+ SVGAnimatedNumberImpl *m_y;
+ SVGAnimatedNumberImpl *m_z;
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFESpecularLightingElementImpl.cc b/ksvg/impl/SVGFESpecularLightingElementImpl.cc
new file mode 100644
index 00000000..9974e146
--- /dev/null
+++ b/ksvg/impl/SVGFESpecularLightingElementImpl.cc
@@ -0,0 +1,74 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedStringImpl.h"
+#include "SVGAnimatedNumberImpl.h"
+#include "SVGFESpecularLightingElementImpl.h"
+
+using namespace KSVG;
+
+SVGFESpecularLightingElementImpl::SVGFESpecularLightingElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl()
+{
+ m_in1 = new SVGAnimatedStringImpl();
+ m_in1->ref();
+
+ m_surfaceScale = new SVGAnimatedNumberImpl();
+ m_surfaceScale->ref();
+
+ m_specularConstant = new SVGAnimatedNumberImpl();
+ m_specularConstant->ref();
+
+ m_specularExponent = new SVGAnimatedNumberImpl();
+ m_specularExponent->ref();
+}
+
+SVGFESpecularLightingElementImpl::~SVGFESpecularLightingElementImpl()
+{
+ if(m_in1)
+ m_in1->deref();
+ if(m_surfaceScale)
+ m_surfaceScale->deref();
+ if(m_specularConstant)
+ m_specularConstant->deref();
+ if(m_specularExponent)
+ m_specularExponent->deref();
+}
+
+SVGAnimatedStringImpl *SVGFESpecularLightingElementImpl::in1() const
+{
+ return m_in1;
+}
+
+SVGAnimatedNumberImpl *SVGFESpecularLightingElementImpl::surfaceScale() const
+{
+ return m_surfaceScale;
+}
+
+SVGAnimatedNumberImpl *SVGFESpecularLightingElementImpl::specularConstant() const
+{
+ return m_specularConstant;
+}
+
+SVGAnimatedNumberImpl *SVGFESpecularLightingElementImpl::specularExponent() const
+{
+ return m_specularExponent;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFESpecularLightingElementImpl.h b/ksvg/impl/SVGFESpecularLightingElementImpl.h
new file mode 100644
index 00000000..527e7f5b
--- /dev/null
+++ b/ksvg/impl/SVGFESpecularLightingElementImpl.h
@@ -0,0 +1,61 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFESpecularLightingElementImpl_H
+#define SVGFESpecularLightingElementImpl_H
+
+#include "SVGElementImpl.h"
+#include "SVGFilterPrimitiveStandardAttributesImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedStringImpl;
+class SVGAnimatedNumberImpl;
+class SVGFESpecularLightingElementImpl : public SVGElementImpl,
+ public SVGFilterPrimitiveStandardAttributesImpl
+{
+public:
+ SVGFESpecularLightingElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFESpecularLightingElementImpl();
+
+ SVGAnimatedStringImpl *in1() const;
+ SVGAnimatedNumberImpl *surfaceScale() const;
+ SVGAnimatedNumberImpl *specularConstant() const;
+ SVGAnimatedNumberImpl *specularExponent() const;
+
+private:
+ SVGAnimatedStringImpl *m_in1;
+ SVGAnimatedNumberImpl *m_surfaceScale;
+ SVGAnimatedNumberImpl *m_specularConstant;
+ SVGAnimatedNumberImpl *m_specularExponent;
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFESpotLightElementImpl.cc b/ksvg/impl/SVGFESpotLightElementImpl.cc
new file mode 100644
index 00000000..96950eda
--- /dev/null
+++ b/ksvg/impl/SVGFESpotLightElementImpl.cc
@@ -0,0 +1,113 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedNumberImpl.h"
+#include "SVGFESpotLightElementImpl.h"
+
+using namespace KSVG;
+
+SVGFESpotLightElementImpl::SVGFESpotLightElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl)
+{
+ m_x = new SVGAnimatedNumberImpl();
+ m_x->ref();
+
+ m_y = new SVGAnimatedNumberImpl();
+ m_y->ref();
+
+ m_z = new SVGAnimatedNumberImpl();
+ m_z->ref();
+
+ m_pointsAtX = new SVGAnimatedNumberImpl();
+ m_pointsAtX->ref();
+
+ m_pointsAtY = new SVGAnimatedNumberImpl();
+ m_pointsAtY->ref();
+
+ m_pointsAtZ = new SVGAnimatedNumberImpl();
+ m_pointsAtZ->ref();
+
+ m_specularExponent = new SVGAnimatedNumberImpl();
+ m_specularExponent->ref();
+
+ m_limitingConeAngle = new SVGAnimatedNumberImpl();
+ m_limitingConeAngle->ref();
+}
+
+SVGFESpotLightElementImpl::~SVGFESpotLightElementImpl()
+{
+ if(m_x)
+ m_x->deref();
+ if(m_y)
+ m_y->deref();
+ if(m_z)
+ m_z->deref();
+ if(m_pointsAtX)
+ m_pointsAtX->deref();
+ if(m_pointsAtY)
+ m_pointsAtY->deref();
+ if(m_pointsAtZ)
+ m_pointsAtZ->deref();
+ if(m_specularExponent)
+ m_specularExponent->deref();
+ if(m_limitingConeAngle)
+ m_limitingConeAngle->deref();
+}
+
+SVGAnimatedNumberImpl *SVGFESpotLightElementImpl::x() const
+{
+ return m_x;
+}
+
+SVGAnimatedNumberImpl *SVGFESpotLightElementImpl::y() const
+{
+ return m_y;
+}
+
+SVGAnimatedNumberImpl *SVGFESpotLightElementImpl::z() const
+{
+ return m_z;
+}
+
+SVGAnimatedNumberImpl *SVGFESpotLightElementImpl::pointsAtX() const
+{
+ return m_pointsAtX;
+}
+
+SVGAnimatedNumberImpl *SVGFESpotLightElementImpl::pointsAtY() const
+{
+ return m_pointsAtY;
+}
+
+SVGAnimatedNumberImpl *SVGFESpotLightElementImpl::pointsAtZ() const
+{
+ return m_pointsAtZ;
+}
+
+SVGAnimatedNumberImpl *SVGFESpotLightElementImpl::specularExponent() const
+{
+ return m_specularExponent;
+}
+
+SVGAnimatedNumberImpl *SVGFESpotLightElementImpl::limitingConeAngle() const
+{
+ return m_limitingConeAngle;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFESpotLightElementImpl.h b/ksvg/impl/SVGFESpotLightElementImpl.h
new file mode 100644
index 00000000..3c808698
--- /dev/null
+++ b/ksvg/impl/SVGFESpotLightElementImpl.h
@@ -0,0 +1,65 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFESpotLightElementImpl_H
+#define SVGFESpotLightElementImpl_H
+
+#include "SVGElementImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedNumberImpl;
+class SVGFESpotLightElementImpl : public SVGElementImpl
+{
+public:
+ SVGFESpotLightElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFESpotLightElementImpl();
+
+ SVGAnimatedNumberImpl *x() const;
+ SVGAnimatedNumberImpl *y() const;
+ SVGAnimatedNumberImpl *z() const;
+ SVGAnimatedNumberImpl *pointsAtX() const;
+ SVGAnimatedNumberImpl *pointsAtY() const;
+ SVGAnimatedNumberImpl *pointsAtZ() const;
+ SVGAnimatedNumberImpl *specularExponent() const;
+ SVGAnimatedNumberImpl *limitingConeAngle() const;
+
+private:
+ SVGAnimatedNumberImpl *m_x;
+ SVGAnimatedNumberImpl *m_y;
+ SVGAnimatedNumberImpl *m_z;
+ SVGAnimatedNumberImpl *m_pointsAtX;
+ SVGAnimatedNumberImpl *m_pointsAtY;
+ SVGAnimatedNumberImpl *m_pointsAtZ;
+ SVGAnimatedNumberImpl *m_specularExponent;
+ SVGAnimatedNumberImpl *m_limitingConeAngle;
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFETileElementImpl.cc b/ksvg/impl/SVGFETileElementImpl.cc
new file mode 100644
index 00000000..2a794302
--- /dev/null
+++ b/ksvg/impl/SVGFETileElementImpl.cc
@@ -0,0 +1,43 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFETileElementImpl.h"
+#include "SVGAnimatedStringImpl.h"
+
+using namespace KSVG;
+
+SVGFETileElementImpl::SVGFETileElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl()
+{
+ m_in1 = new SVGAnimatedStringImpl();
+ m_in1->ref();
+}
+
+SVGFETileElementImpl::~SVGFETileElementImpl()
+{
+ if(m_in1)
+ m_in1->deref();
+}
+
+SVGAnimatedStringImpl *SVGFETileElementImpl::in1() const
+{
+ return m_in1;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFETileElementImpl.h b/ksvg/impl/SVGFETileElementImpl.h
new file mode 100644
index 00000000..29cd4167
--- /dev/null
+++ b/ksvg/impl/SVGFETileElementImpl.h
@@ -0,0 +1,54 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFETileElementImpl_H
+#define SVGFETileElementImpl_H
+
+#include "SVGElementImpl.h"
+#include "SVGFilterPrimitiveStandardAttributesImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedStringImpl;
+class SVGFETileElementImpl : public SVGElementImpl,
+ public SVGFilterPrimitiveStandardAttributesImpl
+{
+public:
+ SVGFETileElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFETileElementImpl();
+
+ SVGAnimatedStringImpl *in1() const;
+
+private:
+ SVGAnimatedStringImpl *m_in1;
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFETurbulenceElementImpl.cc b/ksvg/impl/SVGFETurbulenceElementImpl.cc
new file mode 100644
index 00000000..79c68de3
--- /dev/null
+++ b/ksvg/impl/SVGFETurbulenceElementImpl.cc
@@ -0,0 +1,100 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedNumberImpl.h"
+#include "SVGAnimatedIntegerImpl.h"
+#include "SVGAnimatedEnumerationImpl.h"
+#include "SVGFETurbulenceElementImpl.h"
+
+using namespace KSVG;
+
+SVGFETurbulenceElementImpl::SVGFETurbulenceElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGFilterPrimitiveStandardAttributesImpl()
+{
+ m_baseFrequencyX = new SVGAnimatedNumberImpl();
+ m_baseFrequencyX->ref();
+
+ m_baseFrequencyY = new SVGAnimatedNumberImpl();
+ m_baseFrequencyY->ref();
+
+ m_numOctaves = new SVGAnimatedIntegerImpl();
+ m_numOctaves->ref();
+
+ m_seed = new SVGAnimatedNumberImpl();
+ m_seed->ref();
+
+ m_stitchTiles = new SVGAnimatedEnumerationImpl();
+ m_stitchTiles->ref();
+
+ m_type = new SVGAnimatedEnumerationImpl();
+ m_type->ref();
+}
+
+SVGFETurbulenceElementImpl::~SVGFETurbulenceElementImpl()
+{
+ if(m_baseFrequencyX)
+ m_baseFrequencyX->deref();
+
+ if(m_baseFrequencyY)
+ m_baseFrequencyY->deref();
+
+ if(m_numOctaves)
+ m_numOctaves->deref();
+
+ if(m_seed)
+ m_seed->deref();
+
+ if(m_stitchTiles)
+ m_stitchTiles->deref();
+
+ if(m_type)
+ m_type->deref();
+}
+
+SVGAnimatedNumberImpl *SVGFETurbulenceElementImpl::baseFrequencyX() const
+{
+ return m_baseFrequencyX;
+}
+
+SVGAnimatedNumberImpl *SVGFETurbulenceElementImpl::baseFrequencyY() const
+{
+ return m_baseFrequencyY;
+}
+
+SVGAnimatedIntegerImpl *SVGFETurbulenceElementImpl::numOctaves() const
+{
+ return m_numOctaves;
+}
+
+SVGAnimatedNumberImpl *SVGFETurbulenceElementImpl::seed() const
+{
+ return m_seed;
+}
+
+SVGAnimatedEnumerationImpl *SVGFETurbulenceElementImpl::stitchTiles() const
+{
+ return m_stitchTiles;
+}
+
+SVGAnimatedEnumerationImpl *SVGFETurbulenceElementImpl::type() const
+{
+ return m_type;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFETurbulenceElementImpl.h b/ksvg/impl/SVGFETurbulenceElementImpl.h
new file mode 100644
index 00000000..1275f8ca
--- /dev/null
+++ b/ksvg/impl/SVGFETurbulenceElementImpl.h
@@ -0,0 +1,65 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFETurbulenceElementImpl_H
+#define SVGFETurbulenceElementImpl_H
+
+#include "SVGElementImpl.h"
+#include "SVGFilterPrimitiveStandardAttributesImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedNumberImpl;
+class SVGAnimatedIntegerImpl;
+class SVGAnimatedEnumerationImpl;
+class SVGFETurbulenceElementImpl : public SVGElementImpl, public SVGFilterPrimitiveStandardAttributesImpl
+{
+public:
+ SVGFETurbulenceElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFETurbulenceElementImpl();
+
+ SVGAnimatedNumberImpl *baseFrequencyX() const;
+ SVGAnimatedNumberImpl *baseFrequencyY() const;
+ SVGAnimatedIntegerImpl *numOctaves() const;
+ SVGAnimatedNumberImpl *seed() const;
+ SVGAnimatedEnumerationImpl *stitchTiles() const;
+ SVGAnimatedEnumerationImpl *type() const;
+
+private:
+ SVGAnimatedNumberImpl *m_baseFrequencyX;
+ SVGAnimatedNumberImpl *m_baseFrequencyY;
+ SVGAnimatedIntegerImpl *m_numOctaves;
+ SVGAnimatedNumberImpl *m_seed;
+ SVGAnimatedEnumerationImpl *m_stitchTiles;
+ SVGAnimatedEnumerationImpl *m_type;
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFilterElementImpl.cc b/ksvg/impl/SVGFilterElementImpl.cc
new file mode 100644
index 00000000..eb83ad4b
--- /dev/null
+++ b/ksvg/impl/SVGFilterElementImpl.cc
@@ -0,0 +1,119 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFilterElementImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGAnimatedIntegerImpl.h"
+#include "SVGAnimatedEnumerationImpl.h"
+
+using namespace KSVG;
+
+SVGFilterElementImpl::SVGFilterElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGURIReferenceImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this)
+{
+ m_filterUnits = new SVGAnimatedEnumerationImpl();
+ m_filterUnits->ref();
+
+ m_primitiveUnits = new SVGAnimatedEnumerationImpl();
+ m_primitiveUnits->ref();
+
+ m_x = new SVGAnimatedLengthImpl();
+ m_x->ref();
+
+ m_y = new SVGAnimatedLengthImpl();
+ m_y->ref();
+
+ m_width = new SVGAnimatedLengthImpl();
+ m_width->ref();
+
+ m_height = new SVGAnimatedLengthImpl();
+ m_height->ref();
+
+ m_filterResX = new SVGAnimatedIntegerImpl();
+ m_filterResX->ref();
+
+ m_filterResY = new SVGAnimatedIntegerImpl();
+ m_filterResY->ref();
+}
+
+SVGFilterElementImpl::~SVGFilterElementImpl()
+{
+ if(m_filterUnits)
+ m_filterUnits->deref();
+ if(m_primitiveUnits)
+ m_primitiveUnits->deref();
+ if(m_x)
+ m_x->deref();
+ if(m_y)
+ m_y->deref();
+ if(m_width)
+ m_width->deref();
+ if(m_height)
+ m_height->deref();
+ if(m_filterResX)
+ m_filterResX->deref();
+ if(m_filterResY)
+ m_filterResY->deref();
+}
+
+SVGAnimatedEnumerationImpl *SVGFilterElementImpl::filterUnits() const
+{
+ return m_filterUnits;
+}
+
+SVGAnimatedEnumerationImpl *SVGFilterElementImpl::primitiveUnits() const
+{
+ return m_primitiveUnits;
+}
+
+SVGAnimatedLengthImpl *SVGFilterElementImpl::x() const
+{
+ return m_x;
+}
+
+SVGAnimatedLengthImpl *SVGFilterElementImpl::y() const
+{
+ return m_y;
+}
+
+SVGAnimatedLengthImpl *SVGFilterElementImpl::width() const
+{
+ return m_width;
+}
+
+SVGAnimatedLengthImpl *SVGFilterElementImpl::height() const
+{
+ return m_height;
+}
+
+SVGAnimatedIntegerImpl *SVGFilterElementImpl::filterResX() const
+{
+ return m_filterResX;
+}
+
+SVGAnimatedIntegerImpl *SVGFilterElementImpl::filterResY() const
+{
+ return m_filterResY;
+}
+
+void SVGFilterElementImpl::setFilterRes(unsigned long /*filterResX*/, unsigned long /*filterResY*/)
+{
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFilterElementImpl.h b/ksvg/impl/SVGFilterElementImpl.h
new file mode 100644
index 00000000..ad12a9e9
--- /dev/null
+++ b/ksvg/impl/SVGFilterElementImpl.h
@@ -0,0 +1,76 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFilterElementImpl_H
+#define SVGFilterElementImpl_H
+
+#include "SVGElementImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGLangSpaceImpl.h"
+#include "SVGURIReferenceImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedLengthImpl;
+class SVGAnimatedIntegerImpl;
+class SVGAnimatedEnumerationImpl;
+class SVGFilterElementImpl : public SVGElementImpl,
+ public SVGURIReferenceImpl,
+ public SVGLangSpaceImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGStylableImpl
+{
+public:
+ SVGFilterElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFilterElementImpl();
+
+ SVGAnimatedEnumerationImpl *filterUnits() const;
+ SVGAnimatedEnumerationImpl *primitiveUnits() const;
+ SVGAnimatedLengthImpl *x() const;
+ SVGAnimatedLengthImpl *y() const;
+ SVGAnimatedLengthImpl *width() const;
+ SVGAnimatedLengthImpl *height() const;
+ SVGAnimatedIntegerImpl *filterResX() const;
+ SVGAnimatedIntegerImpl *filterResY() const;
+ void setFilterRes(unsigned long filterResX, unsigned long filterResY);
+
+private:
+ SVGAnimatedEnumerationImpl *m_filterUnits;
+ SVGAnimatedEnumerationImpl *m_primitiveUnits;
+ SVGAnimatedLengthImpl *m_x;
+ SVGAnimatedLengthImpl *m_y;
+ SVGAnimatedLengthImpl *m_width;
+ SVGAnimatedLengthImpl *m_height;
+ SVGAnimatedIntegerImpl *m_filterResX;
+ SVGAnimatedIntegerImpl *m_filterResY;
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFilterPrimitiveStandardAttributesImpl.cc b/ksvg/impl/SVGFilterPrimitiveStandardAttributesImpl.cc
new file mode 100644
index 00000000..3f403009
--- /dev/null
+++ b/ksvg/impl/SVGFilterPrimitiveStandardAttributesImpl.cc
@@ -0,0 +1,84 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGAnimatedStringImpl.h"
+#include "SVGFilterPrimitiveStandardAttributesImpl.h"
+
+using namespace KSVG;
+
+SVGFilterPrimitiveStandardAttributesImpl::SVGFilterPrimitiveStandardAttributesImpl()
+{
+ m_x = new SVGAnimatedLengthImpl();
+ m_x->ref();
+
+ m_y = new SVGAnimatedLengthImpl();
+ m_y->ref();
+
+ m_width = new SVGAnimatedLengthImpl();
+ m_width->ref();
+
+ m_height = new SVGAnimatedLengthImpl();
+ m_height->ref();
+
+ m_result = new SVGAnimatedStringImpl();
+ m_result->ref();
+}
+
+SVGFilterPrimitiveStandardAttributesImpl::~SVGFilterPrimitiveStandardAttributesImpl()
+{
+ if(m_x)
+ m_x->deref();
+ if(m_y)
+ m_y->deref();
+ if(m_width)
+ m_width->deref();
+ if(m_height)
+ m_height->deref();
+ if(m_result)
+ m_result->deref();
+}
+
+SVGAnimatedLengthImpl *SVGFilterPrimitiveStandardAttributesImpl::x() const
+{
+ return m_x;
+}
+
+SVGAnimatedLengthImpl *SVGFilterPrimitiveStandardAttributesImpl::y() const
+{
+ return m_y;
+}
+
+SVGAnimatedLengthImpl *SVGFilterPrimitiveStandardAttributesImpl::width() const
+{
+ return m_width;
+}
+
+SVGAnimatedLengthImpl *SVGFilterPrimitiveStandardAttributesImpl::height() const
+{
+ return m_height;
+}
+
+SVGAnimatedStringImpl *SVGFilterPrimitiveStandardAttributesImpl::result() const
+{
+ return m_result;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFilterPrimitiveStandardAttributesImpl.h b/ksvg/impl/SVGFilterPrimitiveStandardAttributesImpl.h
new file mode 100644
index 00000000..45bcd4d0
--- /dev/null
+++ b/ksvg/impl/SVGFilterPrimitiveStandardAttributesImpl.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPrimitiveStandardAttributesImpl_H
+#define SVGPrimitiveStandardAttributesImpl_H
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedLengthImpl;
+class SVGAnimatedStringImpl;
+class SVGFilterPrimitiveStandardAttributesImpl
+{
+public:
+ SVGFilterPrimitiveStandardAttributesImpl();
+ virtual ~SVGFilterPrimitiveStandardAttributesImpl();
+
+ SVGAnimatedLengthImpl *x() const;
+ SVGAnimatedLengthImpl *y() const;
+ SVGAnimatedLengthImpl *width() const;
+ SVGAnimatedLengthImpl *height() const;
+ SVGAnimatedStringImpl *result() const;
+
+private:
+ SVGAnimatedLengthImpl *m_x;
+ SVGAnimatedLengthImpl *m_y;
+ SVGAnimatedLengthImpl *m_width;
+ SVGAnimatedLengthImpl *m_height;
+ SVGAnimatedStringImpl *m_result;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFitToViewBoxImpl.cc b/ksvg/impl/SVGFitToViewBoxImpl.cc
new file mode 100644
index 00000000..fee367b9
--- /dev/null
+++ b/ksvg/impl/SVGFitToViewBoxImpl.cc
@@ -0,0 +1,141 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include <qstring.h>
+#include <qstringlist.h>
+
+#include "SVGPreserveAspectRatio.h"
+
+#include "SVGRectImpl.h"
+#include "SVGFitToViewBoxImpl.h"
+#include "SVGAnimatedRectImpl.h"
+#include "SVGPreserveAspectRatioImpl.h"
+#include "SVGAnimatedPreserveAspectRatioImpl.h"
+#include "SVGSVGElementImpl.h"
+
+using namespace KSVG;
+
+#include "SVGFitToViewBoxImpl.lut.h"
+
+SVGFitToViewBoxImpl::SVGFitToViewBoxImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_viewBox = new SVGAnimatedRectImpl();
+ m_viewBox->ref();
+
+ m_preserveAspectRatio = new SVGAnimatedPreserveAspectRatioImpl();
+ m_preserveAspectRatio->ref();
+}
+
+SVGFitToViewBoxImpl::~SVGFitToViewBoxImpl()
+{
+ if(m_viewBox)
+ m_viewBox->deref();
+ if(m_preserveAspectRatio)
+ m_preserveAspectRatio->deref();
+}
+
+SVGAnimatedRectImpl *SVGFitToViewBoxImpl::viewBox() const
+{
+ return m_viewBox;
+}
+
+SVGAnimatedPreserveAspectRatioImpl *SVGFitToViewBoxImpl::preserveAspectRatio() const
+{
+ return m_preserveAspectRatio;
+}
+
+void SVGFitToViewBoxImpl::parseViewBox(const QString &s)
+{
+ // Set default if preserveAspectRatio wasnt parsed earlier (Rob)
+ if(m_preserveAspectRatio->baseVal()->align() == SVG_PRESERVEASPECTRATIO_UNKNOWN)
+ m_preserveAspectRatio->baseVal()->setAlign(SVG_PRESERVEASPECTRATIO_XMIDYMID);
+ if(m_preserveAspectRatio->baseVal()->meetOrSlice() == SVG_MEETORSLICE_UNKNOWN)
+ m_preserveAspectRatio->baseVal()->setMeetOrSlice(SVG_MEETORSLICE_MEET);
+
+ // allow for viewbox def with ',' or whitespace
+ QString viewbox(s);
+ QStringList points = QStringList::split(' ', viewbox.replace(',', ' ').simplifyWhiteSpace());
+
+ viewBox()->baseVal()->setX(points[0].toFloat());
+ viewBox()->baseVal()->setY(points[1].toFloat());
+ viewBox()->baseVal()->setWidth(points[2].toFloat());
+ viewBox()->baseVal()->setHeight(points[3].toFloat());
+}
+
+SVGMatrixImpl *SVGFitToViewBoxImpl::viewBoxToViewTransform(float viewWidth, float viewHeight) const
+{
+ if(viewBox()->baseVal()->width() == 0 || viewBox()->baseVal()->height() == 0)
+ return SVGSVGElementImpl::createSVGMatrix();
+ else
+ return preserveAspectRatio()->baseVal()->getCTM(viewBox()->baseVal()->x(),
+ viewBox()->baseVal()->y(), viewBox()->baseVal()->width(), viewBox()->baseVal()->height(),
+ 0, 0, viewWidth, viewHeight);
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGFitToViewBoxImpl::s_hashTable 3
+ viewBox SVGFitToViewBoxImpl::ViewBox DontDelete
+ preserveAspectRatio SVGFitToViewBoxImpl::PreserveAspectRatio DontDelete
+@end
+*/
+
+Value SVGFitToViewBoxImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case ViewBox:
+ return m_viewBox->cache(exec);
+ case PreserveAspectRatio:
+ return m_preserveAspectRatio->cache(exec);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGFitToViewBoxImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case ViewBox:
+ parseViewBox(value.toString(exec).qstring());
+ break;
+ case PreserveAspectRatio:
+ if(preserveAspectRatio())
+ preserveAspectRatio()->baseVal()->parsePreserveAspectRatio(value.toString(exec).qstring());
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFitToViewBoxImpl.h b/ksvg/impl/SVGFitToViewBoxImpl.h
new file mode 100644
index 00000000..b511d63e
--- /dev/null
+++ b/ksvg/impl/SVGFitToViewBoxImpl.h
@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFitToViewBoxImpl_H
+#define SVGFitToViewBoxImpl_H
+
+#include "ksvg_lookup.h"
+
+class QString;
+
+namespace KSVG
+{
+
+class SVGAnimatedRectImpl;
+class SVGAnimatedPreserveAspectRatioImpl;
+class SVGMatrixImpl;
+class SVGFitToViewBoxImpl
+{
+public:
+ SVGFitToViewBoxImpl();
+ ~SVGFitToViewBoxImpl();
+
+ SVGAnimatedRectImpl *viewBox() const;
+ SVGAnimatedPreserveAspectRatioImpl *preserveAspectRatio() const;
+
+ void parseViewBox(const QString &);
+
+ SVGMatrixImpl *viewBoxToViewTransform(float viewWidth, float viewHeight) const;
+
+protected:
+ SVGAnimatedRectImpl *m_viewBox;
+ SVGAnimatedPreserveAspectRatioImpl *m_preserveAspectRatio;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ ViewBox, PreserveAspectRatio
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFontElementImpl.cc b/ksvg/impl/SVGFontElementImpl.cc
new file mode 100644
index 00000000..30d4f63f
--- /dev/null
+++ b/ksvg/impl/SVGFontElementImpl.cc
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFontElementImpl.h"
+
+using namespace KSVG;
+
+SVGFontElementImpl::SVGFontElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this)
+{
+}
+
+SVGFontElementImpl::~SVGFontElementImpl()
+{
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFontElementImpl.h b/ksvg/impl/SVGFontElementImpl.h
new file mode 100644
index 00000000..3a753797
--- /dev/null
+++ b/ksvg/impl/SVGFontElementImpl.h
@@ -0,0 +1,49 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFontElementImpl_H
+#define SVGFontElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGElementImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+namespace KSVG
+{
+
+class SVGFontElementImpl : public SVGElementImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGStylableImpl
+{
+public:
+ SVGFontElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFontElementImpl();
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFontFaceElementImpl.cc b/ksvg/impl/SVGFontFaceElementImpl.cc
new file mode 100644
index 00000000..d53e70ad
--- /dev/null
+++ b/ksvg/impl/SVGFontFaceElementImpl.cc
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFontFaceElementImpl.h"
+
+using namespace KSVG;
+
+SVGFontFaceElementImpl::SVGFontFaceElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl)
+{
+}
+
+SVGFontFaceElementImpl::~SVGFontFaceElementImpl()
+{
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFontFaceElementImpl.h b/ksvg/impl/SVGFontFaceElementImpl.h
new file mode 100644
index 00000000..0479ccea
--- /dev/null
+++ b/ksvg/impl/SVGFontFaceElementImpl.h
@@ -0,0 +1,46 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFontFaceElementImpl_H
+#define SVGFontFaceElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGElementImpl.h"
+
+namespace KSVG
+{
+
+class SVGFontFaceElementImpl : public SVGElementImpl
+{
+public:
+ SVGFontFaceElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFontFaceElementImpl();
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFontFaceFormatElementImpl.cc b/ksvg/impl/SVGFontFaceFormatElementImpl.cc
new file mode 100644
index 00000000..48651a68
--- /dev/null
+++ b/ksvg/impl/SVGFontFaceFormatElementImpl.cc
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFontFaceFormatElementImpl.h"
+
+using namespace KSVG;
+
+SVGFontFaceFormatElementImpl::SVGFontFaceFormatElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl)
+{
+}
+
+SVGFontFaceFormatElementImpl::~SVGFontFaceFormatElementImpl()
+{
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFontFaceFormatElementImpl.h b/ksvg/impl/SVGFontFaceFormatElementImpl.h
new file mode 100644
index 00000000..380e29b1
--- /dev/null
+++ b/ksvg/impl/SVGFontFaceFormatElementImpl.h
@@ -0,0 +1,46 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFontFaceFormatElementImpl_H
+#define SVGFontFaceFormatElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGElementImpl.h"
+
+namespace KSVG
+{
+
+class SVGFontFaceFormatElementImpl : public SVGElementImpl
+{
+public:
+ SVGFontFaceFormatElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFontFaceFormatElementImpl();
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFontFaceNameElementImpl.cc b/ksvg/impl/SVGFontFaceNameElementImpl.cc
new file mode 100644
index 00000000..276f3ae3
--- /dev/null
+++ b/ksvg/impl/SVGFontFaceNameElementImpl.cc
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFontFaceNameElementImpl.h"
+
+using namespace KSVG;
+
+SVGFontFaceNameElementImpl::SVGFontFaceNameElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl)
+{
+}
+
+SVGFontFaceNameElementImpl::~SVGFontFaceNameElementImpl()
+{
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFontFaceNameElementImpl.h b/ksvg/impl/SVGFontFaceNameElementImpl.h
new file mode 100644
index 00000000..797ee17e
--- /dev/null
+++ b/ksvg/impl/SVGFontFaceNameElementImpl.h
@@ -0,0 +1,46 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFontFaceNameElementImpl_H
+#define SVGFontFaceNameElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGElementImpl.h"
+
+namespace KSVG
+{
+
+class SVGFontFaceNameElementImpl : public SVGElementImpl
+{
+public:
+ SVGFontFaceNameElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFontFaceNameElementImpl();
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFontFaceSrcElementImpl.cc b/ksvg/impl/SVGFontFaceSrcElementImpl.cc
new file mode 100644
index 00000000..bdc40611
--- /dev/null
+++ b/ksvg/impl/SVGFontFaceSrcElementImpl.cc
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFontFaceSrcElementImpl.h"
+
+using namespace KSVG;
+
+SVGFontFaceSrcElementImpl::SVGFontFaceSrcElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl)
+{
+}
+
+SVGFontFaceSrcElementImpl::~SVGFontFaceSrcElementImpl()
+{
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFontFaceSrcElementImpl.h b/ksvg/impl/SVGFontFaceSrcElementImpl.h
new file mode 100644
index 00000000..f858e829
--- /dev/null
+++ b/ksvg/impl/SVGFontFaceSrcElementImpl.h
@@ -0,0 +1,45 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFontFaceSrcElementImpl_H
+#define SVGFontFaceSrcElementImpl_H
+
+#include "ksvg_lookup.h"
+#include "SVGElementImpl.h"
+
+namespace KSVG
+{
+
+class SVGFontFaceSrcElementImpl : public SVGElementImpl
+{
+public:
+ SVGFontFaceSrcElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFontFaceSrcElementImpl();
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFontFaceUriElementImpl.cc b/ksvg/impl/SVGFontFaceUriElementImpl.cc
new file mode 100644
index 00000000..cef5a30f
--- /dev/null
+++ b/ksvg/impl/SVGFontFaceUriElementImpl.cc
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGFontFaceUriElementImpl.h"
+
+using namespace KSVG;
+
+SVGFontFaceUriElementImpl::SVGFontFaceUriElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl)
+{
+}
+
+SVGFontFaceUriElementImpl::~SVGFontFaceUriElementImpl()
+{
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGFontFaceUriElementImpl.h b/ksvg/impl/SVGFontFaceUriElementImpl.h
new file mode 100644
index 00000000..2b670a82
--- /dev/null
+++ b/ksvg/impl/SVGFontFaceUriElementImpl.h
@@ -0,0 +1,46 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGFontFaceUriElementImpl_H
+#define SVGFontFaceUriElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGElementImpl.h"
+
+namespace KSVG
+{
+
+class SVGFontFaceUriElementImpl : public SVGElementImpl
+{
+public:
+ SVGFontFaceUriElementImpl(DOM::ElementImpl *);
+ virtual ~SVGFontFaceUriElementImpl();
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGForeignObjectElementImpl.cc b/ksvg/impl/SVGForeignObjectElementImpl.cc
new file mode 100644
index 00000000..ff605cf0
--- /dev/null
+++ b/ksvg/impl/SVGForeignObjectElementImpl.cc
@@ -0,0 +1,121 @@
+/*
+ Copyright (C) 2001-20032 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGRectImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGForeignObjectElementImpl.h"
+
+using namespace KSVG;
+
+#include "SVGForeignObjectElementImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+SVGForeignObjectElementImpl::SVGForeignObjectElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl()
+{
+ m_x = new SVGAnimatedLengthImpl();
+ m_x->ref();
+
+ m_y = new SVGAnimatedLengthImpl();
+ m_y->ref();
+
+ m_width = new SVGAnimatedLengthImpl();
+ m_width->ref();
+
+ m_height = new SVGAnimatedLengthImpl();
+ m_height->ref();
+}
+
+SVGForeignObjectElementImpl::~SVGForeignObjectElementImpl()
+{
+ if(m_x)
+ m_x->deref();
+ if(m_y)
+ m_y->deref();
+ if(m_width)
+ m_width->deref();
+ if(m_height)
+ m_height->deref();
+}
+
+SVGRectImpl *SVGForeignObjectElementImpl::getBBox()
+{
+ SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect();
+ ret->setX(m_x->baseVal()->value());
+ ret->setY(m_y->baseVal()->value());
+ ret->setWidth(m_width->baseVal()->value());
+ ret->setHeight(m_height->baseVal()->value());
+ return ret;
+}
+
+SVGAnimatedLengthImpl *SVGForeignObjectElementImpl::x() const
+{
+ return m_x;
+}
+
+SVGAnimatedLengthImpl *SVGForeignObjectElementImpl::y() const
+{
+ return m_y;
+}
+
+SVGAnimatedLengthImpl *SVGForeignObjectElementImpl::width() const
+{
+ return m_width;
+}
+
+SVGAnimatedLengthImpl *SVGForeignObjectElementImpl::height() const
+{
+ return m_height;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGForeignObjectElementImpl::s_hashTable 5
+ x SVGForeignObjectElementImpl::X DontDelete|ReadOnly
+ y SVGForeignObjectElementImpl::Y DontDelete|ReadOnly
+ width SVGForeignObjectElementImpl::Width DontDelete|ReadOnly
+ height SVGForeignObjectElementImpl::Height DontDelete|ReadOnly
+@end
+*/
+
+Value SVGForeignObjectElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case X:
+ return m_x->cache(exec);
+ case Y:
+ return m_y->cache(exec);
+ case Width:
+ return m_width->cache(exec);
+ case Height:
+ return m_height->cache(exec);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGForeignObjectElementImpl.h b/ksvg/impl/SVGForeignObjectElementImpl.h
new file mode 100644
index 00000000..3fea4877
--- /dev/null
+++ b/ksvg/impl/SVGForeignObjectElementImpl.h
@@ -0,0 +1,78 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGForeignObjectElementImpl_H
+#define SVGForeignObjectElementImpl_H
+
+#include "SVGTestsImpl.h"
+#include "SVGElementImpl.h"
+#include "SVGLangSpaceImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGTransformableImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedLengthImpl;
+class SVGForeignObjectElementImpl : public SVGElementImpl,
+ public SVGTestsImpl,
+ public SVGLangSpaceImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGStylableImpl,
+ public SVGTransformableImpl
+{
+public:
+ SVGForeignObjectElementImpl(DOM::ElementImpl *);
+ virtual ~SVGForeignObjectElementImpl();
+
+ virtual SVGRectImpl *getBBox();
+
+ SVGAnimatedLengthImpl *x() const;
+ SVGAnimatedLengthImpl *y() const;
+ SVGAnimatedLengthImpl *width() const;
+ SVGAnimatedLengthImpl *height() const;
+
+private:
+ SVGAnimatedLengthImpl *m_x;
+ SVGAnimatedLengthImpl *m_y;
+ SVGAnimatedLengthImpl *m_width;
+ SVGAnimatedLengthImpl *m_height;
+
+public:
+ KSVG_GET
+ KSVG_FORWARDPUT
+
+ enum
+ {
+ // Properties
+ X, Y, Width, Height
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGGElementImpl.cc b/ksvg/impl/SVGGElementImpl.cc
new file mode 100644
index 00000000..9f355540
--- /dev/null
+++ b/ksvg/impl/SVGGElementImpl.cc
@@ -0,0 +1,36 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGGElementImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGAElementImpl.h"
+#include "SVGAnimatedStringImpl.h"
+
+using namespace KSVG;
+
+SVGGElementImpl::SVGGElementImpl(DOM::ElementImpl *impl) : SVGContainerImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl()
+{
+}
+
+SVGGElementImpl::~SVGGElementImpl()
+{
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGGElementImpl.h b/ksvg/impl/SVGGElementImpl.h
new file mode 100644
index 00000000..ca4a9b4e
--- /dev/null
+++ b/ksvg/impl/SVGGElementImpl.h
@@ -0,0 +1,59 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGGElementImpl_H
+#define SVGGElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGTestsImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGContainerImpl.h"
+#include "SVGLangSpaceImpl.h"
+#include "SVGTransformableImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+namespace KSVG
+{
+
+class SVGGElementImpl : public SVGContainerImpl,
+ public SVGTestsImpl,
+ public SVGLangSpaceImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGStylableImpl,
+ public SVGTransformableImpl
+{
+public:
+ SVGGElementImpl(DOM::ElementImpl *);
+ virtual ~SVGGElementImpl();
+
+public:
+ KSVG_BRIDGE
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+KSVG_REGISTER_ELEMENT(SVGGElementImpl, "g")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGGlyphElementImpl.cc b/ksvg/impl/SVGGlyphElementImpl.cc
new file mode 100644
index 00000000..dd201466
--- /dev/null
+++ b/ksvg/impl/SVGGlyphElementImpl.cc
@@ -0,0 +1,98 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGGlyphElementImpl.h"
+
+using namespace KSVG;
+
+#include "SVGGlyphElementImpl.lut.h"
+
+SVGGlyphElementImpl::SVGGlyphElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGStylableImpl(this)
+{
+ KSVG_EMPTY_FLAGS
+}
+
+SVGGlyphElementImpl::~SVGGlyphElementImpl()
+{
+}
+
+QString SVGGlyphElementImpl::d() const
+{
+ return m_d;
+}
+
+/*
+@namespace KSVG
+@begin SVGGlyphElementImpl::s_hashTable 11
+ unicode SVGGlyphElementImpl::Unicode DontDelete|ReadOnly
+ glyph-name SVGGlyphElementImpl::GlyphName DontDelete|ReadOnly
+ d SVGGlyphElementImpl::D DontDelete|ReadOnly
+ orientation SVGGlyphElementImpl::Orientation DontDelete|ReadOnly
+ arabic-form SVGGlyphElementImpl::ArabicForm DontDelete|ReadOnly
+ lang SVGGlyphElementImpl::Lang DontDelete|ReadOnly
+ horiz-adv-x SVGGlyphElementImpl::HorizAdvX DontDelete|ReadOnly
+ vert-origin-x SVGGlyphElementImpl::VertOriginX DontDelete|ReadOnly
+ vert-origin-y SVGGlyphElementImpl::VertOriginY DontDelete|ReadOnly
+ vert-adv-y SVGGlyphElementImpl::VertAdvY DontDelete|ReadOnly
+@end
+*/
+
+Value SVGGlyphElementImpl::getValueProperty(ExecState *, int token) const
+{
+ //KSVG_CHECK_ATTRIBUTE
+
+ switch(token)
+ {
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGGlyphElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case D:
+ m_d = value.toString(exec).qstring();
+ break;
+ case Unicode:
+ case GlyphName:
+ case Orientation:
+ case ArabicForm:
+ case Lang:
+ case HorizAdvX:
+ case VertOriginX:
+ case VertOriginY:
+ case VertAdvY:
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGGlyphElementImpl.h b/ksvg/impl/SVGGlyphElementImpl.h
new file mode 100644
index 00000000..35781b2c
--- /dev/null
+++ b/ksvg/impl/SVGGlyphElementImpl.h
@@ -0,0 +1,66 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGGlyphElementImpl_H
+#define SVGGlyphElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGElementImpl.h"
+#include "SVGStylableImpl.h"
+
+namespace KSVG
+{
+
+class SVGGlyphElementImpl : public SVGElementImpl,
+ public SVGStylableImpl
+{
+public:
+ SVGGlyphElementImpl(DOM::ElementImpl *);
+ virtual ~SVGGlyphElementImpl();
+
+ QString d() const;
+
+private:
+ QString m_d;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+ KSVG_BRIDGE
+
+ enum
+ {
+ // Properties
+ Unicode, GlyphName, D, Orientation, ArabicForm,
+ Lang, HorizAdvX, VertOriginX, VertOriginY, VertAdvY
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+KSVG_REGISTER_ELEMENT(SVGGlyphElementImpl, "glyph")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGGlyphRefElementImpl.cc b/ksvg/impl/SVGGlyphRefElementImpl.cc
new file mode 100644
index 00000000..438fa0b0
--- /dev/null
+++ b/ksvg/impl/SVGGlyphRefElementImpl.cc
@@ -0,0 +1,134 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGSVGElementImpl.h"
+#include "SVGGlyphRefElementImpl.h"
+
+using namespace KSVG;
+
+#include "SVGGlyphRefElementImpl.lut.h"
+#include "ksvg_lookup.h"
+
+SVGGlyphRefElementImpl::SVGGlyphRefElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGURIReferenceImpl(), SVGStylableImpl(this)
+{
+}
+
+SVGGlyphRefElementImpl::~SVGGlyphRefElementImpl()
+{
+}
+
+void SVGGlyphRefElementImpl::setAttributes()
+{
+ SVGElementImpl::setAttributes();
+}
+
+DOM::DOMString SVGGlyphRefElementImpl::format()
+{
+ return "";
+}
+
+DOM::DOMString SVGGlyphRefElementImpl::glyphRef()
+{
+ return "";
+}
+
+float SVGGlyphRefElementImpl::x() const
+{
+ return m_x;
+}
+
+float SVGGlyphRefElementImpl::y() const
+{
+ return m_y;
+}
+
+float SVGGlyphRefElementImpl::dx() const
+{
+ return m_dx;
+}
+
+float SVGGlyphRefElementImpl::dy() const
+{
+ return m_dy;
+}
+
+/*
+@namespace KSVG
+@begin SVGGlyphRefElementImpl::s_hashTable 7
+ glyphRef SVGGlyphRefElementImpl::GlyphRef DontDelete|ReadOnly
+ format SVGGlyphRefElementImpl::Format DontDelete|ReadOnly
+ x SVGGlyphRefElementImpl::X DontDelete|ReadOnly
+ y SVGGlyphRefElementImpl::Y DontDelete|ReadOnly
+ dx SVGGlyphRefElementImpl::Dx DontDelete|ReadOnly
+ dy SVGGlyphRefElementImpl::Dy DontDelete|ReadOnly
+@end
+*/
+
+Value SVGGlyphRefElementImpl::getValueProperty(ExecState *, int token) const
+{
+ //KSVG_CHECK_ATTRIBUTE
+
+ switch(token)
+ {
+ case GlyphRef: return String(m_glyphRef);
+ case Format: return String(m_format);
+ case X: return Number(m_x);
+ case Y: return Number(m_y);
+ case Dx: return Number(m_dx);
+ case Dy: return Number(m_dy);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGGlyphRefElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case GlyphRef:
+ m_glyphRef = value.toString(exec).string();
+ break;
+ case Format:
+ m_format = value.toString(exec).string();
+ break;
+ case X:
+ m_x = value.toNumber(exec);
+ break;
+ case Y:
+ m_y = value.toNumber(exec);
+ break;
+ case Dx:
+ m_dx = value.toNumber(exec);
+ break;
+ case Dy:
+ m_dy = value.toNumber(exec);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGGlyphRefElementImpl.h b/ksvg/impl/SVGGlyphRefElementImpl.h
new file mode 100644
index 00000000..6a292a64
--- /dev/null
+++ b/ksvg/impl/SVGGlyphRefElementImpl.h
@@ -0,0 +1,79 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGGlyphRefElementImpl_H
+#define SVGGlyphRefElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGElementImpl.h"
+#include "SVGURIReferenceImpl.h"
+#include "SVGStylableImpl.h"
+
+namespace KSVG
+{
+
+class SVGGlyphRefElementImpl : public SVGElementImpl,
+ public SVGURIReferenceImpl,
+ public SVGStylableImpl
+{
+public:
+ SVGGlyphRefElementImpl(DOM::ElementImpl *);
+ virtual ~SVGGlyphRefElementImpl();
+ virtual void setAttributes();
+
+ DOM::DOMString glyphRef();
+ DOM::DOMString format();
+
+ float x() const;
+ float y() const;
+ float dx() const;
+ float dy() const;
+
+private:
+ DOM::DOMString m_glyphRef;
+ DOM::DOMString m_format;
+ float m_x;
+ float m_y;
+ float m_dx;
+ float m_dy;
+
+public:
+ KSVG_BRIDGE
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ GlyphRef, Format, X, Y, Dx, Dy
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+KSVG_REGISTER_ELEMENT(SVGGlyphRefElementImpl, "glyphRef")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGGradientElementImpl.cc b/ksvg/impl/SVGGradientElementImpl.cc
new file mode 100644
index 00000000..180b230a
--- /dev/null
+++ b/ksvg/impl/SVGGradientElementImpl.cc
@@ -0,0 +1,264 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGGradientElement.h"
+#include "SVGGradientElementImpl.h"
+#include "SVGStopElementImpl.h"
+#include "SVGAnimatedStringImpl.h"
+#include "SVGSVGElementImpl.h"
+
+#include "KSVGCanvas.h"
+#include "CanvasItems.h"
+#include "SVGHelperImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGAnimatedEnumerationImpl.h"
+#include "SVGAnimatedTransformListImpl.h"
+#include "SVGTransformListImpl.h"
+#include "SVGUnitConverter.h"
+
+using namespace KSVG;
+
+#include "SVGGradientElementImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+#include "ksvg_cacheimpl.h"
+
+SVGGradientElementImpl::SVGGradientElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGURIReferenceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGPaintServerImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_gradientUnits = new SVGAnimatedEnumerationImpl();
+ m_gradientUnits->ref();
+
+ m_gradientTransform = new SVGAnimatedTransformListImpl();
+ m_gradientTransform->ref();
+
+ m_spreadMethod = new SVGAnimatedEnumerationImpl();
+ m_spreadMethod->ref();
+
+ m_converter = new SVGUnitConverter();
+}
+
+SVGGradientElementImpl::~SVGGradientElementImpl()
+{
+ if(m_gradientUnits)
+ m_gradientUnits->deref();
+ if(m_gradientTransform)
+ m_gradientTransform->deref();
+ if(m_spreadMethod)
+ m_spreadMethod->deref();
+ delete m_converter;
+}
+
+SVGAnimatedEnumerationImpl *SVGGradientElementImpl::gradientUnits() const
+{
+ return m_gradientUnits;
+}
+
+SVGAnimatedTransformListImpl *SVGGradientElementImpl::gradientTransform() const
+{
+ return m_gradientTransform;
+}
+
+SVGAnimatedEnumerationImpl *SVGGradientElementImpl::spreadMethod() const
+{
+ return m_spreadMethod;
+}
+
+/*
+@namespace KSVG
+@begin SVGGradientElementImpl::s_hashTable 5
+ gradientUnits SVGGradientElementImpl::GradientUnits DontDelete|ReadOnly
+ gradientTransform SVGGradientElementImpl::GradientTransform DontDelete|ReadOnly
+ spreadMethod SVGGradientElementImpl::SpreadMethod DontDelete|ReadOnly
+@end
+*/
+
+Value SVGGradientElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case GradientUnits:
+ return m_gradientUnits->cache(exec);
+ case GradientTransform:
+ return m_gradientTransform->cache(exec);
+ case SpreadMethod:
+ return m_spreadMethod->cache(exec);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGGradientElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case GradientUnits:
+ if(value.toString(exec).qstring() == "userSpaceOnUse")
+ m_gradientUnits->setBaseVal(SVGGradientElement::SVG_UNIT_TYPE_USERSPACEONUSE);
+ else
+ m_gradientUnits->setBaseVal(SVGGradientElement::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
+ break;
+ case GradientTransform:
+ m_gradientTransform->baseVal()->clear();
+ SVGHelperImpl::parseTransformAttribute(m_gradientTransform->baseVal(), value.toString(exec).qstring());
+ break;
+ case SpreadMethod:
+ {
+ QString spreadMethod = value.toString(exec).qstring();
+
+ if(spreadMethod == "repeat")
+ m_spreadMethod->setBaseVal(SVG_SPREADMETHOD_REPEAT);
+ else if(spreadMethod == "reflect")
+ m_spreadMethod->setBaseVal(SVG_SPREADMETHOD_REFLECT);
+ else
+ m_spreadMethod->setBaseVal(SVG_SPREADMETHOD_PAD);
+ break;
+ }
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+void SVGGradientElementImpl::setAttributes()
+{
+ SVGElementImpl::setAttributes();
+ setAttributesFromHref();
+
+ // Spec: if attribute not specified, use "pad"
+ if(KSVG_TOKEN_NOT_PARSED(SpreadMethod))
+ KSVG_SET_ALT_ATTRIBUTE(SpreadMethod, "pad")
+
+ // Spec: if attribute not specified, use objectBoundingBox
+ if(KSVG_TOKEN_NOT_PARSED(GradientUnits))
+ KSVG_SET_ALT_ATTRIBUTE(GradientUnits, "objectBoundingBox")
+}
+
+void SVGGradientElementImpl::setAttributesFromHref()
+{
+ QString _href = SVGURIReferenceImpl::getTarget(href()->baseVal().string());
+
+ if(!_href.isEmpty())
+ {
+ SVGGradientElementImpl *refGradient = dynamic_cast<SVGGradientElementImpl *>(ownerSVGElement()->getElementById(_href));
+
+ if(refGradient)
+ {
+ QMap<QString, DOM::DOMString> refAttributes = refGradient->gradientAttributes();
+ QMap<QString, DOM::DOMString>::iterator it;
+
+ for(it = refAttributes.begin(); it != refAttributes.end(); ++it)
+ {
+ QString name = it.key();
+ DOM::DOMString value = it.data();
+
+ if(!hasAttribute(name))
+ {
+ setAttribute(name, value);
+ setAttributeInternal(name, value);
+ }
+ }
+ }
+ }
+}
+
+SVGGradientElementImpl *SVGGradientElementImpl::stopsSource()
+{
+ // Spec:
+ // If this element has no defined gradient stops, and the referenced element does
+ // (possibly due to its own href attribute), then this element inherits the gradient stop from the referenced element.
+ // Inheritance can be indirect to an arbitrary level; thus, if the referenced element inherits attribute or gradient stops
+ // due to its own href attribute, then the current element can inherit those attributes or gradient stops. (mop)
+ bool haveStops = false;
+
+ for(DOM::Node node = firstChild(); !node.isNull(); node = node.nextSibling())
+ {
+ SVGStopElementImpl *stop = dynamic_cast<SVGStopElementImpl *>(ownerDoc()->getElementFromHandle(node.handle()));
+
+ if(stop)
+ {
+ haveStops = true;
+ break;
+ }
+ }
+
+ SVGGradientElementImpl *source = this;
+
+ if(!haveStops)
+ {
+ QString _href = SVGURIReferenceImpl::getTarget(href()->baseVal().string());
+
+ if(!_href.isEmpty())
+ {
+ SVGGradientElementImpl *refGradient = dynamic_cast<SVGGradientElementImpl *>(ownerSVGElement()->getElementById(_href));
+
+ if(refGradient)
+ source = refGradient->stopsSource();
+ }
+ }
+
+ return source;
+}
+
+void SVGGradientElementImpl::createItem(KSVGCanvas *c)
+{
+ if(!c)
+ c = ownerDoc()->canvas();
+
+ if(!m_paintServer)
+ m_paintServer = c->createPaintServer(this);
+}
+
+void SVGGradientElementImpl::removeItem(KSVGCanvas *)
+{
+ delete m_paintServer;
+ m_paintServer = 0;
+}
+
+/*
+@namespace KSVG
+@begin SVGGradientElementImplConstructor::s_hashTable 5
+ SVG_SPREADMETHOD_UNKNOWN KSVG::SVG_SPREADMETHOD_UNKNOWN DontDelete|ReadOnly
+ SVG_SPREADMETHOD_PAD KSVG::SVG_SPREADMETHOD_PAD DontDelete|ReadOnly
+ SVG_SPREADMETHOD_REFLECT KSVG::SVG_SPREADMETHOD_REFLECT DontDelete|ReadOnly
+ SVG_SPREADMETHOD_REPEAT KSVG::SVG_SPREADMETHOD_REPEAT DontDelete|ReadOnly
+@end
+*/
+
+using namespace KJS;
+
+Value SVGGradientElementImplConstructor::getValueProperty(ExecState *, int token) const
+{
+ return Number(token);
+}
+
+Value KSVG::getSVGGradientElementImplConstructor(ExecState *exec)
+{
+ return cacheGlobalBridge<SVGGradientElementImplConstructor>(exec, "[[svggradientelement.constructor]]");
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGGradientElementImpl.h b/ksvg/impl/SVGGradientElementImpl.h
new file mode 100644
index 00000000..e9be92d8
--- /dev/null
+++ b/ksvg/impl/SVGGradientElementImpl.h
@@ -0,0 +1,110 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGGradientElementImpl_H
+#define SVGGradientElementImpl_H
+
+#include <qmap.h>
+
+#include "SVGElementImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGURIReferenceImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+#include "SVGPaintServerImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGUnitConverter;
+class SVGAnimatedEnumerationImpl;
+class SVGAnimatedTransformListImpl;
+class SVGGradientElementImpl : public SVGElementImpl,
+ public SVGURIReferenceImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGStylableImpl,
+ public SVGPaintServerImpl
+{
+public:
+ SVGGradientElementImpl(DOM::ElementImpl *);
+ virtual ~SVGGradientElementImpl();
+
+ SVGAnimatedEnumerationImpl *gradientUnits() const;
+ SVGAnimatedTransformListImpl *gradientTransform() const;
+ SVGAnimatedEnumerationImpl *spreadMethod() const;
+
+ virtual void setAttributes();
+
+ virtual void createItem(KSVGCanvas *c = 0);
+ virtual void removeItem(KSVGCanvas *c);
+
+ SVGUnitConverter *converter() const { return m_converter; }
+
+ // Returns the gradient element that holds the stops for this gradient,
+ // taking into account indirection through href.
+ SVGGradientElementImpl *stopsSource();
+
+ // Returns the linear/radial gradient attributes set on this element,
+ // taking into account indirection through href.
+ virtual QMap<QString, DOM::DOMString> gradientAttributes() = 0;
+
+protected:
+ void setAttributesFromHref();
+
+private:
+ SVGAnimatedEnumerationImpl *m_gradientUnits;
+ SVGAnimatedTransformListImpl *m_gradientTransform;
+ SVGAnimatedEnumerationImpl *m_spreadMethod;
+
+ SVGUnitConverter *m_converter;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+ KSVG_NO_TAG_BRIDGE
+
+ enum
+ {
+ // Properties
+ GradientUnits, GradientTransform, SpreadMethod
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+class SVGGradientElementImplConstructor : public KJS::ObjectImp
+{
+public:
+ SVGGradientElementImplConstructor(KJS::ExecState *) { }
+ KJS::Value getValueProperty(KJS::ExecState *, int token) const;
+
+ // no put - all read-only
+ KSVG_GET
+};
+
+KJS::Value getSVGGradientElementImplConstructor(KJS::ExecState *exec);
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGHKernElementImpl.cc b/ksvg/impl/SVGHKernElementImpl.cc
new file mode 100644
index 00000000..df310d6e
--- /dev/null
+++ b/ksvg/impl/SVGHKernElementImpl.cc
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGHKernElementImpl.h"
+
+using namespace KSVG;
+
+SVGHKernElementImpl::SVGHKernElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl)
+{
+}
+
+SVGHKernElementImpl::~SVGHKernElementImpl()
+{
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGHKernElementImpl.h b/ksvg/impl/SVGHKernElementImpl.h
new file mode 100644
index 00000000..6858b5be
--- /dev/null
+++ b/ksvg/impl/SVGHKernElementImpl.h
@@ -0,0 +1,46 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGHKernElementImpl_H
+#define SVGHKernElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGElementImpl.h"
+
+namespace KSVG
+{
+
+class SVGHKernElementImpl : public SVGElementImpl
+{
+public:
+ SVGHKernElementImpl(DOM::ElementImpl *);
+ virtual ~SVGHKernElementImpl();
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGHelperImpl.cc b/ksvg/impl/SVGHelperImpl.cc
new file mode 100644
index 00000000..ed7e8be4
--- /dev/null
+++ b/ksvg/impl/SVGHelperImpl.cc
@@ -0,0 +1,230 @@
+/*
+ Copyright (C) 2002-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include <qregexp.h>
+
+#include "SVGRectImpl.h"
+#include "SVGMatrixImpl.h"
+#include "SVGHelperImpl.h"
+#include "SVGElementImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGTransformImpl.h"
+#include "SVGStringListImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGTransformListImpl.h"
+#include "SVGTransformableImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGAnimatedLengthListImpl.h"
+
+#include "KSVGCanvas.h"
+#include "CanvasItem.h"
+
+using namespace KSVG;
+
+#include "ksvg_ecma.h"
+#include "ksvg_window.h"
+
+SVGHelperImpl::SVGHelperImpl()
+{
+}
+
+SVGHelperImpl::~SVGHelperImpl()
+{
+}
+
+void SVGHelperImpl::updateItem(KJS::ExecState *exec, const DOM::Node node)
+{
+ // Get document
+ SVGDocumentImpl *doc = Window::retrieveActive(exec)->doc();
+
+ // Update canvas, recursively if needed
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(doc->getElementFromHandle(node.handle()));
+
+ if(shape && shape->item())
+ {
+ shape->item()->update(UPDATE_TRANSFORM);
+ shape->item()->draw();
+ shape->blit(doc->canvas());
+ }
+
+ if(const_cast<DOM::Node &>(node).hasChildNodes())
+ {
+ DOM::Node iterate = node.firstChild();
+ for(; !iterate.isNull(); iterate = iterate.nextSibling())
+ updateItem(exec, iterate);
+ }
+}
+
+void SVGHelperImpl::copyAttributes(SVGElementImpl *src, SVGElementImpl *dst)
+{
+ QDictIterator<DOM::DOMString> it(src->attributes());
+ for(; it.current(); ++it)
+ {
+ DOM::DOMString name = it.currentKey();
+ DOM::DOMString value = it.current()->string();
+
+ if(name != "id" && !dst->hasAttribute(name))
+ {
+ dst->setAttribute(name, value);
+ dst->setAttributeInternal(name, value);
+ }
+ }
+}
+
+void SVGHelperImpl::parseList(SVGStringListImpl *list, char seperator, const QString &data)
+{
+ // TODO : more error checking/reporting
+ list->clear();
+
+ QStringList substrings = QStringList::split(seperator, data);
+ QStringList::ConstIterator it = substrings.begin();
+ QStringList::ConstIterator end = substrings.end();
+ for(; it != end; ++it)
+ {
+ SharedString *string = new SharedString(*it);
+ string->ref();
+
+ list->appendItem(string);
+ }
+}
+
+void SVGHelperImpl::parseLengthList(SVGAnimatedLengthListImpl *list, const QString &lengths, LengthMode mode, SVGElementImpl *object)
+{
+ // get either comma or space delimited lists
+ // TODO : more error checking/reporting
+ QStringList sublengths = QStringList::split(QRegExp("[, ]"), lengths);
+ QStringList::ConstIterator it = sublengths.begin();
+ QStringList::ConstIterator end = sublengths.end();
+
+ SVGLengthImpl *lengthImpl = 0;
+ for(; it != end; ++it)
+ {
+ lengthImpl = new SVGLengthImpl(mode, object);
+ lengthImpl->ref();
+
+ lengthImpl->setValueAsString(*it);
+ list->baseVal()->appendItem(lengthImpl);
+ }
+}
+
+void SVGHelperImpl::parseCommaSeperatedList(SVGStringListImpl *list, const QString &data)
+{
+ parseList(list, ',', data);
+}
+
+void SVGHelperImpl::parseSemicolonSeperatedList(SVGStringListImpl *list, const QString &data)
+{
+ parseList(list, ';', data);
+}
+
+void SVGHelperImpl::parseTransformAttribute(SVGTransformListImpl *list, const QString &transform)
+{
+ // Split string for handling 1 transform statement at a time
+ QStringList subtransforms = QStringList::split(')', transform);
+ QStringList::ConstIterator it = subtransforms.begin();
+ QStringList::ConstIterator end = subtransforms.end();
+ for(; it != end; ++it)
+ {
+ QStringList subtransform = QStringList::split('(', (*it));
+
+ subtransform[0] = subtransform[0].stripWhiteSpace().lower();
+ subtransform[1] = subtransform[1].simplifyWhiteSpace();
+ QRegExp reg("([-]?\\d*\\.?\\d+(?:e[-]?\\d+)?)");
+
+ int pos = 0;
+ QStringList params;
+
+ while(pos >= 0)
+ {
+ pos = reg.search(subtransform[1], pos);
+ if(pos != -1)
+ {
+ params += reg.cap(1);
+ pos += reg.matchedLength();
+ }
+ }
+
+ if(subtransform[0].startsWith(";") || subtransform[0].startsWith(","))
+ subtransform[0] = subtransform[0].right(subtransform[0].length() - 1);
+
+ SVGTransformImpl *t = SVGSVGElementImpl::createSVGTransform();
+
+ if(subtransform[0] == "rotate")
+ {
+ if(params.count() == 3)
+ t->setRotate(params[0].toDouble(),
+ params[1].toDouble(),
+ params[2].toDouble());
+ else
+ t->setRotate(params[0].toDouble(), 0, 0);
+ }
+ else if(subtransform[0] == "translate")
+ {
+ if(params.count() == 2)
+ t->setTranslate(params[0].toDouble(), params[1].toDouble());
+ else // Spec : if only one param given, assume 2nd param to be 0
+ t->setTranslate(params[0].toDouble(), 0);
+ }
+ else if(subtransform[0] == "scale")
+ {
+ if(params.count() == 2)
+ t->setScale(params[0].toDouble(), params[1].toDouble());
+ else // Spec : if only one param given, assume uniform scaling
+ t->setScale(params[0].toDouble(), params[0].toDouble());
+ }
+ else if(subtransform[0] == "skewx")
+ t->setSkewX(params[0].toDouble());
+ else if(subtransform[0] == "skewy")
+ t->setSkewY(params[0].toDouble());
+ else if(subtransform[0] == "matrix")
+ {
+ if(params.count() >= 6)
+ {
+ SVGMatrixImpl *ret = new SVGMatrixImpl(params[0].toDouble(),
+ params[1].toDouble(),
+ params[2].toDouble(),
+ params[3].toDouble(),
+ params[4].toDouble(),
+ params[5].toDouble());
+ t->setMatrix(ret);
+ }
+ }
+
+ list->appendItem(t);
+ }
+}
+
+/// convert from user space to "real" pixels on rendering area
+QRect SVGHelperImpl::fromUserspace(SVGElementImpl *obj, const QRect &r)
+{
+ QRect sr;
+
+ SVGLocatableImpl *locate = dynamic_cast<SVGLocatableImpl *>(obj);
+
+ if(locate)
+ sr = locate->screenCTM()->qmatrix().mapRect(r);
+
+ return sr;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGHelperImpl.h b/ksvg/impl/SVGHelperImpl.h
new file mode 100644
index 00000000..e8bbdb39
--- /dev/null
+++ b/ksvg/impl/SVGHelperImpl.h
@@ -0,0 +1,88 @@
+/*
+ Copyright (C) 2002-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGHelperImpl_H
+#define SVGHelperImpl_H
+
+#include <dom/dom_element.h>
+
+#include "SVGElementImpl.h"
+#include "SVGLengthImpl.h"
+#include "SVGDocumentImpl.h"
+#include "ksvg_ecma.h"
+
+#include "ksvg_lookup.h"
+
+class QRect;
+class QString;
+
+namespace KSVG
+{
+class SVGStringListImpl;
+class SVGTransformListImpl;
+class SVGAnimatedLengthListImpl;
+
+class SVGHelperImpl
+{
+public:
+ SVGHelperImpl();
+ ~SVGHelperImpl();
+
+ // Dynamic attribute updating
+ template<class T>
+ static void applyContainer(T *obj, int token, const QString &value)
+ {
+ SVGElementImpl *element = dynamic_cast<SVGElementImpl *>(obj);
+ if(!element || !element->hasChildNodes())
+ return;
+
+ // Very fast propagation of attributes, when the token is known! (Niko)
+ for(DOM::Node node = element->firstChild(); !node.isNull(); node = node.nextSibling())
+ {
+ T *cast = dynamic_cast<T *>(element->ownerDoc()->getElementFromHandle(node.handle()));
+ if(cast)
+ cast->putValueProperty(element->ownerDoc()->ecmaEngine()->globalExec(), token, KJS::String(value), KJS::Internal);
+ }
+ }
+
+ // Update item on canvas
+ static void updateItem(KJS::ExecState *exec, const DOM::Node node);
+ static void copyAttributes(SVGElementImpl *src, SVGElementImpl *dst);
+
+ // SVGAnimatedLengthList
+ static void parseLengthList(SVGAnimatedLengthListImpl *list, const QString &lengths, LengthMode mode = LENGTHMODE_UNKNOWN, SVGElementImpl *object = 0);
+
+ // SVGStringList
+ static void parseList(SVGStringListImpl *list, char seperator, const QString &data);
+ static void parseCommaSeperatedList(SVGStringListImpl *list, const QString &data);
+ static void parseSemicolonSeperatedList(SVGStringListImpl *list, const QString &data);
+
+ // SVGTransformList
+ static void parseTransformAttribute(SVGTransformListImpl *list, const QString &transform);
+
+ // Tools
+ static QRect fromUserspace(SVGElementImpl *, const QRect &);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGICCColorImpl.cc b/ksvg/impl/SVGICCColorImpl.cc
new file mode 100644
index 00000000..3e708ee9
--- /dev/null
+++ b/ksvg/impl/SVGICCColorImpl.cc
@@ -0,0 +1,107 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGICCColorImpl.h"
+#include "SVGNumberListImpl.h"
+
+using namespace KSVG;
+
+#include "SVGICCColorImpl.lut.h"
+#include "ksvg_bridge.h"
+
+SVGICCColorImpl::SVGICCColorImpl() : DOM::DomShared()
+{
+ m_colors = new SVGNumberListImpl();
+ m_colors->ref();
+}
+
+SVGICCColorImpl::SVGICCColorImpl(const SVGICCColorImpl &other) : DOM::DomShared()
+{
+ (*this) = other;
+}
+
+SVGICCColorImpl::~SVGICCColorImpl()
+{
+ if(m_colors)
+ m_colors->deref();
+}
+
+SVGICCColorImpl &SVGICCColorImpl::operator=(const SVGICCColorImpl &other)
+{
+ m_colorProfile = other.m_colorProfile;
+ *m_colors = *(other.m_colors);
+
+ return *this;
+}
+
+DOM::DOMString SVGICCColorImpl::colorProfile() const
+{
+ return m_colorProfile;
+}
+
+void SVGICCColorImpl::setColorProfile(const DOM::DOMString &colorProfile)
+{
+ m_colorProfile = colorProfile;
+}
+
+SVGNumberListImpl *SVGICCColorImpl::colors() const
+{
+ return m_colors;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGICCColorImpl::s_hashTable 3
+ colorProfile SVGICCColorImpl::ColorProfile DontDelete
+ colors SVGICCColorImpl::Colors DontDelete|ReadOnly
+@end
+*/
+
+Value SVGICCColorImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case ColorProfile:
+ return String(m_colorProfile.string());
+ case Colors:
+ return m_colors->cache(exec);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGICCColorImpl::putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int)
+{
+ switch(token)
+ {
+ case ColorProfile:
+ m_colorProfile = value.toString(exec).string();
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGICCColorImpl.h b/ksvg/impl/SVGICCColorImpl.h
new file mode 100644
index 00000000..1427e59c
--- /dev/null
+++ b/ksvg/impl/SVGICCColorImpl.h
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGICCColorImpl_H
+#define SVGICCColorImpl_H
+
+#include <dom/dom_misc.h>
+#include <dom/dom_string.h>
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGNumberListImpl;
+class SVGICCColorImpl : public DOM::DomShared
+{
+public:
+ SVGICCColorImpl();
+ SVGICCColorImpl(const SVGICCColorImpl &);
+ virtual ~SVGICCColorImpl();
+
+ SVGICCColorImpl &operator=(const SVGICCColorImpl &);
+
+ void setColorProfile(const DOM::DOMString &colorProfile);
+ DOM::DOMString colorProfile() const;
+ SVGNumberListImpl *colors() const;
+
+private:
+ DOM::DOMString m_colorProfile;
+ SVGNumberListImpl *m_colors;
+
+public:
+ KSVG_GET
+
+ enum
+ {
+ // Properties
+ ColorProfile, Colors
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGImageElementImpl.cc b/ksvg/impl/SVGImageElementImpl.cc
new file mode 100644
index 00000000..608dbda5
--- /dev/null
+++ b/ksvg/impl/SVGImageElementImpl.cc
@@ -0,0 +1,522 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qimage.h>
+#include <qtimer.h>
+
+#include <kdebug.h>
+
+#include "CanvasItem.h"
+#include "KSVGCanvas.h"
+#include "KSVGHelper.h"
+
+#include "SVGRectImpl.h"
+#include "SVGEventImpl.h"
+#include "SVGMatrixImpl.h"
+#include "SVGHelperImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGTransformImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGTransformListImpl.h"
+#include "SVGAnimatedStringImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGImageElementImpl.moc"
+#include "SVGColorProfileElementImpl.h"
+#include "SVGPreserveAspectRatioImpl.h"
+#include "SVGAnimatedTransformListImpl.h"
+#include "SVGAnimatedPreserveAspectRatioImpl.h"
+#include "SVGPatternElementImpl.h"
+
+using namespace KSVG;
+
+#include "SVGImageElementImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+
+SVGImageElementImpl::SVGImageElementImpl(DOM::ElementImpl *impl) : QObject(), SVGShapeImpl(impl), SVGURIReferenceImpl(), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_x = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this);
+ m_x->ref();
+ m_x->baseVal()->setValueAsString("-1");
+
+ m_y = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this);
+ m_y->ref();
+ m_y->baseVal()->setValueAsString("-1");
+
+ m_width = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this);
+ m_width->ref();
+ m_width->baseVal()->setValueAsString("-1");
+
+ m_height = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this);
+ m_height->ref();
+ m_height->baseVal()->setValueAsString("-1");
+
+ m_preserveAspectRatio = 0;
+
+ m_doc = 0;
+ m_image = 0;
+ m_svgRoot = 0;
+ m_colorProfile = 0;
+ m_colorProfileApplied = false;
+}
+
+SVGImageElementImpl::~SVGImageElementImpl()
+{
+ if(m_x)
+ m_x->deref();
+ if(m_y)
+ m_y->deref();
+ if(m_width)
+ m_width->deref();
+ if(m_height)
+ m_height->deref();
+ if(m_preserveAspectRatio)
+ m_preserveAspectRatio->deref();
+ if(m_doc)
+ m_doc->deref();
+
+ delete m_image;
+}
+
+SVGAnimatedLengthImpl *SVGImageElementImpl::x()
+{
+ return m_x;
+}
+
+SVGAnimatedLengthImpl *SVGImageElementImpl::y()
+{
+ return m_y;
+}
+
+SVGAnimatedLengthImpl *SVGImageElementImpl::width()
+{
+ return m_width;
+}
+
+SVGAnimatedLengthImpl *SVGImageElementImpl::height()
+{
+ return m_height;
+}
+
+SVGAnimatedPreserveAspectRatioImpl *SVGImageElementImpl::preserveAspectRatio() const
+{
+ return m_preserveAspectRatio;
+}
+
+/*
+@namespace KSVG
+@namespace KSVG
+@begin SVGImageElementImpl::s_hashTable 7
+ x SVGImageElementImpl::X DontDelete|ReadOnly
+ y SVGImageElementImpl::Y DontDelete|ReadOnly
+ width SVGImageElementImpl::Width DontDelete|ReadOnly
+ height SVGImageElementImpl::Height DontDelete|ReadOnly
+ preserveAspectRatio SVGImageElementImpl::PreserveAspectRatio DontDelete|ReadOnly
+ href SVGImageElementImpl::Href DontDelete|ReadOnly
+@end
+*/
+
+Value SVGImageElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ KSVG_CHECK_ATTRIBUTE
+
+ switch(token)
+ {
+ case X:
+ if(!attributeMode)
+ return m_x->cache(exec);
+ else
+ return Number(m_x->baseVal()->value());
+ case Y:
+ if(!attributeMode)
+ return m_y->cache(exec);
+ else
+ return Number(m_y->baseVal()->value());
+ case Width:
+ if(!attributeMode)
+ return m_width->cache(exec);
+ else
+ return Number(m_width->baseVal()->value());
+ case Height:
+ if(!attributeMode)
+ return m_height->cache(exec);
+ else
+ return Number(m_height->baseVal()->value());
+ case PreserveAspectRatio:
+ if(m_preserveAspectRatio)
+ return m_preserveAspectRatio->cache(exec);
+ else
+ return Undefined();
+ case Href:
+ SVGURIReferenceImpl::getValueProperty(exec, token);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGImageElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case X:
+ x()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ case Y:
+ y()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ case Width:
+ width()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ case Height:
+ height()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ case PreserveAspectRatio:
+ if(!preserveAspectRatio())
+ {
+ m_preserveAspectRatio = new SVGAnimatedPreserveAspectRatioImpl();
+ m_preserveAspectRatio->ref();
+ }
+
+ preserveAspectRatio()->baseVal()->parsePreserveAspectRatio(value.toString(exec).qstring());
+ break;
+ case Href:
+ SVGURIReferenceImpl::putValueProperty(exec, SVGURIReferenceImpl::Href, value, attr);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+SVGRectImpl *SVGImageElementImpl::getBBox()
+{
+ SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect();
+ ret->setX(m_x->baseVal()->value());
+ ret->setY(m_y->baseVal()->value());
+ ret->setWidth(m_width->baseVal()->value());
+ ret->setHeight(m_height->baseVal()->value());
+ return ret;
+}
+
+void SVGImageElementImpl::setAttributes()
+{
+ SVGElementImpl::setAttributes();
+
+ if(KSVG_TOKEN_NOT_PARSED(X))
+ KSVG_SET_ALT_ATTRIBUTE(X, "0")
+
+ if(KSVG_TOKEN_NOT_PARSED(Y))
+ KSVG_SET_ALT_ATTRIBUTE(Y, "0")
+
+ if(KSVG_TOKEN_NOT_PARSED(PreserveAspectRatio))
+ {
+ setAttribute("preserveAspectRatio", "xMidYMid meet");
+ KSVG_SET_ALT_ATTRIBUTE(PreserveAspectRatio, "xMidYMid meet")
+ }
+}
+
+void SVGImageElementImpl::slotParsingFinished(bool error, const QString &errorDesc)
+{
+ if(error)
+ kdDebug(26003) << "Finished with error : " << errorDesc << endl;
+ else
+ kdDebug(26003) << "Finished without errors!" << endl;
+
+ m_svgRoot = m_doc->rootElement();
+}
+
+void SVGImageElementImpl::slotLoadingFinished()
+{
+ ownerDoc()->notifyImageLoaded(this);
+}
+
+void SVGImageElementImpl::createItem(KSVGCanvas *c)
+{
+ if(!m_item)
+ {
+ if(!c)
+ c = ownerDoc()->canvas();
+
+ m_item = c->createImage(this);
+ c->insert(m_item);
+
+ if(href()->baseVal().string().endsWith(".svg") || href()->baseVal().string().endsWith(".svgz"))
+ {
+ if(!m_svgRoot)
+ {
+ m_doc = new SVGDocumentImpl(true, false, this);
+ m_doc->ref();
+ m_doc->attach(c);
+
+ connect(m_doc, SIGNAL(finishedParsing(bool, const QString &)), this, SLOT(slotParsingFinished(bool, const QString &)));
+ connect(m_doc, SIGNAL(finishedLoading()), this, SLOT(slotLoadingFinished()));
+
+ KURL file;
+
+ if(!KURL::isRelativeURL(href()->baseVal().string()))
+ file = KURL(href()->baseVal().string());
+ else
+ file = KURL(ownerDoc()->baseUrl(), href()->baseVal().string());
+
+ m_doc->open(file);
+
+ // The svg image will add items to the canvas in parallel with the main
+ // document, so the z-order will not be correct. Get it to fix this when everything's
+ // finished loading.
+ ownerDoc()->resortZIndicesOnFinishedLoading();
+ ownerDoc()->notifyImageLoading(this);
+ }
+ else
+ m_svgRoot->createItem(c);
+ }
+ else
+ {
+ if(!m_image)
+ {
+ ownerDoc()->newImageJob(this);
+ ownerDoc()->notifyImageLoading(this);
+ }
+ }
+ }
+}
+
+void SVGImageElementImpl::removeItem(KSVGCanvas *c)
+{
+ if(m_item && c)
+ {
+ if(m_svgRoot)
+ m_svgRoot->removeItem(c);
+
+ c->removeItem(m_item);
+ m_item = 0;
+ }
+}
+
+void SVGImageElementImpl::setupSVGElement(SVGSVGElementImpl *svg)
+{
+ // Set up the root svg for an svg image.
+ svg->setAttributeInternal("x", QString("%1").arg(x()->baseVal()->value()));
+ svg->setAttributeInternal("y", QString("%1").arg(y()->baseVal()->value()));
+ svg->setAttributeInternal("width", QString("%1").arg(width()->baseVal()->value()));
+ svg->setAttributeInternal("height", QString("%1").arg(height()->baseVal()->value()));
+
+ QString par = getAttribute("preserveAspectRatio").string().stripWhiteSpace();
+
+ if(par.startsWith("defer"))
+ {
+ if(svg->getAttribute("preserveAspectRatio").isEmpty())
+ {
+ par.remove("defer");
+ svg->setAttribute("preserveAspectRatio", par);
+ svg->setAttributeInternal("preserveAspectRatio", par);
+ }
+ }
+ else
+ {
+ svg->setAttribute("preserveAspectRatio", par);
+ svg->setAttributeInternal("preserveAspectRatio", par);
+ }
+
+ svg->setAttributes();
+ svg->setRootParentScreenCTM(getScreenCTM());
+}
+
+void SVGImageElementImpl::onScreenCTMUpdated()
+{
+ if(m_svgRoot)
+ {
+ SVGMatrixImpl *ctm = getScreenCTM();
+
+ m_svgRoot->setRootParentScreenCTM(ctm);
+ m_svgRoot->invalidateCachedMatrices();
+ m_svgRoot->ownerDoc()->syncCachedMatrices();
+ }
+}
+
+bool SVGImageElementImpl::prepareMouseEvent(const QPoint &p, const QPoint &, SVGMouseEventImpl *mev)
+{
+ // TODO : pointer-events should be stored here, not in SVGStylableImpl.
+ SVGStylableImpl *style = dynamic_cast<SVGStylableImpl *>(this);
+ if(!style || style->getPointerEvents() == PE_NONE)
+ return false;
+ bool test = true;
+ switch(style->getPointerEvents())
+ {
+ case PE_VISIBLE:
+ case PE_VISIBLE_PAINTED:
+ case PE_VISIBLE_FILL:
+ case PE_VISIBLE_STROKE: test = style->getVisible(); break;
+ case PE_PAINTED:
+ case PE_FILL:
+ case PE_STROKE:
+ case PE_ALL: break;
+ default: test = false;
+ };
+
+ if(test && m_item)
+ {
+ if(m_item->bbox().contains(p))
+ {
+ mev->setTarget(dynamic_cast<SVGElementImpl *>(this));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void SVGImageElementImpl::setImage(QImage *image)
+{
+ m_image = image;
+
+ if(m_image)
+ {
+ *m_image = m_image->convertDepth(32);
+
+ if(m_colorProfile != 0 && !m_colorProfileApplied)
+ {
+ m_colorProfileApplied = true;
+ applyColorProfile();
+ }
+
+ SVGPatternElementImpl::flushCachedTiles();
+
+ if(m_item)
+ {
+ ownerDoc()->canvas()->invalidate(m_item, false);
+ ownerDoc()->rerender();
+ }
+ }
+
+ ownerDoc()->notifyImageLoaded(this);
+}
+
+QImage SVGImageElementImpl::scaledImage()
+{
+ SVGMatrixImpl *matrix = imageMatrix();
+ double sx, sy;
+
+ matrix->removeScale(&sx, &sy);
+ matrix->deref();
+
+ QImage img;
+
+ if(sx != 1 || sy != 1)
+ {
+ int scaledWidth = static_cast<int>(m_image->width() * sx + 0.5);
+ int scaledHeight = static_cast<int>(m_image->height() * sy + 0.5);
+
+ img = m_image->smoothScale(scaledWidth, scaledHeight);
+ }
+ else
+ img = *m_image;
+
+ return img;
+}
+
+SVGMatrixImpl *SVGImageElementImpl::imageMatrix()
+{
+ SVGMatrixImpl *ctm = getScreenCTM();
+
+ ctm->translate(x()->baseVal()->value(), y()->baseVal()->value());
+
+ SVGMatrixImpl *viewboxMatrix = preserveAspectRatio()->baseVal()->getCTM(0, 0, image()->width(), image()->height(), 0, 0, width()->baseVal()->value(), height()->baseVal()->value());
+
+ ctm->multiply(viewboxMatrix);
+ viewboxMatrix->deref();
+
+ return ctm;
+}
+
+SVGMatrixImpl *SVGImageElementImpl::scaledImageMatrix()
+{
+ SVGMatrixImpl *matrix = imageMatrix();
+ double sx, sy;
+
+ matrix->removeScale(&sx, &sy);
+
+ if(sx != 1 || sy != 1)
+ {
+ int imageWidth = static_cast<int>(m_image->width() * sx + 0.5);
+ int imageHeight = static_cast<int>(m_image->height() * sy + 0.5);
+
+ double trueWidth = m_image->width() * sx;
+ double trueHeight = m_image->height() * sy;
+
+ matrix->scaleNonUniform(trueWidth / imageWidth, trueHeight / imageHeight);
+ }
+
+ return matrix;
+}
+
+KSVGPolygon SVGImageElementImpl::clippingShape()
+{
+ KSVGRectangle viewport(0, 0, width()->baseVal()->value(), height()->baseVal()->value());
+ SVGMatrixImpl *matrix = preserveAspectRatio()->baseVal()->getCTM(0, 0, image()->width(), image()->height(), 0, 0, width()->baseVal()->value(), height()->baseVal()->value());
+ KSVGPolygon p = matrix->inverseMap(viewport);
+ matrix->deref();
+
+ matrix = imageMatrix();
+ p = matrix->map(p);
+ matrix->deref();
+
+ return p;
+}
+
+QString SVGImageElementImpl::fileName() const
+{
+ return href()->baseVal().string();
+}
+
+void SVGImageElementImpl::applyColorProfile()
+{
+ m_image = m_colorProfile->correctImage(m_image);
+}
+
+void SVGImageElementImpl::applyColorProfile(SVGColorProfileElementImpl *profile, SVGImageElementImpl *image)
+{
+ // Only apply once, if it's the same (Niko)
+ if(image->m_colorProfile == profile)
+ return;
+
+ image->m_colorProfile = profile;
+
+ if(image->m_image)
+ {
+ // Image is already painted, we apply the color profile and repaint it
+ image->applyColorProfile();
+
+ if(image->item())
+ {
+ image->ownerDoc()->canvas()->invalidate(image->item(), false);
+ image->ownerDoc()->rerender();
+ }
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGImageElementImpl.h b/ksvg/impl/SVGImageElementImpl.h
new file mode 100644
index 00000000..35ae161f
--- /dev/null
+++ b/ksvg/impl/SVGImageElementImpl.h
@@ -0,0 +1,140 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGImageElementImpl_H
+#define SVGImageElementImpl_H
+
+#include <qobject.h>
+
+#include "ksvg_lookup.h"
+
+#include "SVGTestsImpl.h"
+#include "SVGShapeImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGLangSpaceImpl.h"
+#include "SVGURIReferenceImpl.h"
+#include "SVGTransformableImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+namespace KSVG
+{
+
+class KSVGPolygon;
+class SVGDocumentImpl;
+class SVGSVGElementImpl;
+class SVGAnimatedLengthImpl;
+class SVGColorProfileElementImpl;
+class SVGAnimatedPreserveAspectRatioImpl;
+class SVGImageElementImpl : public QObject,
+ public SVGShapeImpl,
+ public SVGURIReferenceImpl,
+ public SVGTestsImpl,
+ public SVGLangSpaceImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGStylableImpl,
+ public SVGTransformableImpl
+{
+Q_OBJECT
+public:
+ SVGImageElementImpl(DOM::ElementImpl *);
+ virtual ~SVGImageElementImpl();
+
+ SVGAnimatedLengthImpl *x();
+ SVGAnimatedLengthImpl *y();
+ SVGAnimatedLengthImpl *width();
+ SVGAnimatedLengthImpl *height();
+ SVGAnimatedPreserveAspectRatioImpl *preserveAspectRatio() const;
+
+ virtual void createItem(KSVGCanvas *c);
+ virtual void removeItem(KSVGCanvas *c);
+
+ virtual void setAttributes();
+
+ virtual bool prepareMouseEvent(const QPoint &p, const QPoint &a, SVGMouseEventImpl *mev);
+
+ void setImage(QImage *image);
+ QImage *image() { return m_image; }
+
+ QImage scaledImage();
+ SVGMatrixImpl *imageMatrix();
+ SVGMatrixImpl *scaledImageMatrix();
+
+ SVGSVGElementImpl *svgImageRootElement() const { return m_svgRoot; }
+
+ void applyColorProfile();
+ static void applyColorProfile(SVGColorProfileElementImpl *profile, SVGImageElementImpl *image);
+
+ QString fileName() const;
+
+ virtual SVGRectImpl *getBBox();
+
+ // Screen-space clipping shape
+ KSVGPolygon clippingShape();
+
+ void onScreenCTMUpdated();
+
+ void setupSVGElement(SVGSVGElementImpl *svg);
+
+private slots:
+ void slotParsingFinished(bool error, const QString &errorDesc);
+ void slotLoadingFinished();
+
+private:
+ SVGAnimatedLengthImpl *m_x;
+ SVGAnimatedLengthImpl *m_y;
+ SVGAnimatedLengthImpl *m_width;
+ SVGAnimatedLengthImpl *m_height;
+
+ QImage *m_image;
+
+ bool m_colorProfileApplied;
+ SVGAnimatedPreserveAspectRatioImpl *m_preserveAspectRatio;
+ SVGColorProfileElementImpl *m_colorProfile;
+ SVGSVGElementImpl *m_svgRoot;
+ SVGDocumentImpl *m_doc;
+
+public:
+ KSVG_GET
+ KSVG_BRIDGE
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ X, Y, Width, Height, PreserveAspectRatio, Href
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+struct ImageStreamMap
+{
+ QByteArray *data;
+ SVGImageElementImpl *imageElement;
+};
+
+KSVG_REGISTER_ELEMENT(SVGImageElementImpl, "image")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGLangSpaceImpl.cc b/ksvg/impl/SVGLangSpaceImpl.cc
new file mode 100644
index 00000000..0eaada47
--- /dev/null
+++ b/ksvg/impl/SVGLangSpaceImpl.cc
@@ -0,0 +1,130 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGLangSpaceImpl.h"
+
+using namespace KSVG;
+
+#include "SVGLangSpaceImpl.lut.h"
+#include "ksvg_bridge.h"
+
+SVGLangSpaceImpl::SVGLangSpaceImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ // Spec: default for xml:space is "default"
+ setXmlspace("default");
+}
+
+SVGLangSpaceImpl::~SVGLangSpaceImpl()
+{
+}
+
+void SVGLangSpaceImpl::setXmllang(const DOM::DOMString &xmllang)
+{
+ m_xmllang = xmllang;
+}
+
+DOM::DOMString SVGLangSpaceImpl::xmllang() const
+{
+ return m_xmllang;
+}
+
+void SVGLangSpaceImpl::setXmlspace(const DOM::DOMString &xmlspace)
+{
+ m_xmlspace = xmlspace;
+}
+
+DOM::DOMString SVGLangSpaceImpl::xmlspace() const
+{
+ return m_xmlspace;
+}
+
+QString SVGLangSpaceImpl::handleText(const QString &data) const
+{
+ QString result = data;
+
+ if(xmlspace() == "preserve")
+ {
+ // Spec: What to do here?
+ // It will convert all newline and tab characters into space characters
+ result.replace("\n\r", QString(" "));
+ result.replace("\r\n", QString(" "));
+ result.replace('\t', ' ');
+ }
+ else if(xmlspace() == "default")
+ {
+ // Spec: What to do here?
+ // First, it will remove all newline characters (replace)
+ // Then it will convert all tab characters into space characters (simplifyWhiteSpace)
+ // Then, it will strip off all leading and trailing space characters (stripWhiteSpace)
+ // Then, all contiguous space characters will be consolidated. (simplifyWhiteSpace)
+ result.replace('\n', QString::null);
+ result.replace('\r', QString::null);
+ result = result.stripWhiteSpace().simplifyWhiteSpace();
+ }
+
+ return result;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGLangSpaceImpl::s_hashTable 5
+ xmllang SVGLangSpaceImpl::XmlLang DontDelete
+ xmlspace SVGLangSpaceImpl::XmlSpace DontDelete
+ lang SVGLangSpaceImpl::XmlLang DontDelete
+ space SVGLangSpaceImpl::XmlSpace DontDelete
+@end
+*/
+
+Value SVGLangSpaceImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case XmlLang:
+ return String(m_xmllang.string());
+ case XmlSpace:
+ return String(m_xmlspace.string());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGLangSpaceImpl::putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int /*attr*/)
+{
+ switch(token)
+ {
+ case XmlLang:
+ m_xmllang = value.toString(exec).string();
+ break;
+ case XmlSpace:
+ m_xmlspace = value.toString(exec).string();
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGLangSpaceImpl.h b/ksvg/impl/SVGLangSpaceImpl.h
new file mode 100644
index 00000000..4a8c199a
--- /dev/null
+++ b/ksvg/impl/SVGLangSpaceImpl.h
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGLangSpaceImpl_H
+#define SVGLangSpaceImpl_H
+
+#include <dom/dom_string.h>
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGLangSpaceImpl
+{
+public:
+ SVGLangSpaceImpl();
+ virtual ~SVGLangSpaceImpl();
+
+ void setXmllang(const DOM::DOMString &xmllang);
+ DOM::DOMString xmllang() const;
+
+ void setXmlspace(const DOM::DOMString &xmlspace);
+ DOM::DOMString xmlspace() const;
+
+ QString handleText(const QString &data) const;
+
+private:
+ DOM::DOMString m_xmllang;
+ DOM::DOMString m_xmlspace;
+
+public:
+ KSVG_BASECLASS_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ XmlLang, XmlSpace
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGLengthImpl.cc b/ksvg/impl/SVGLengthImpl.cc
new file mode 100644
index 00000000..46529022
--- /dev/null
+++ b/ksvg/impl/SVGLengthImpl.cc
@@ -0,0 +1,510 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include <qfont.h>
+#include <qregexp.h>
+#include <qwidget.h>
+#include <qpaintdevicemetrics.h>
+
+#include "SVGLength.h"
+
+#include "SVGRectImpl.h"
+#include "SVGLengthImpl.h"
+#include "SVGMatrixImpl.h"
+#include "SVGHelperImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGStringListImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGAnimatedRectImpl.h"
+#include "svgpathparser.h"
+
+#include "KSVGCanvas.h"
+
+using namespace KSVG;
+
+#include "SVGLengthImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_cacheimpl.h"
+
+// keep track of textual description of the unit type
+QString UnitText[] =
+{
+ "", "", "%", "em", "ex", "px", "cm", "mm", "in", "pt", "pc"
+};
+
+SVGLengthImpl::SVGLengthImpl(LengthMode mode, SVGElementImpl *context) : DOM::DomShared(), m_mode(mode), m_context(context)
+{
+ KSVG_EMPTY_FLAGS
+
+ m_unitType = SVG_LENGTHTYPE_UNKNOWN;
+ m_value = 0;
+ m_valueInSpecifiedUnits = 0;
+ m_bboxContext = 0;
+}
+
+SVGLengthImpl::SVGLengthImpl(const SVGLengthImpl &other) : DOM::DomShared()
+{
+ (*this) = other;
+}
+
+SVGLengthImpl::~SVGLengthImpl()
+{
+}
+
+double SVGLengthImpl::dpi()
+{
+ if(m_context && m_context->ownerDoc())
+ {
+ if(m_mode == LENGTHMODE_WIDTH)
+ return 25.4 * m_context->ownerDoc()->screenPixelsPerMillimeterX();
+ else if(m_mode == LENGTHMODE_HEIGHT)
+ return 25.4 * m_context->ownerDoc()->screenPixelsPerMillimeterY();
+ else if(m_mode == LENGTHMODE_OTHER)
+ return 25.4 * m_context->ownerDoc()->screenPixelsPerMillimeterX();
+ }
+ return 90.0;
+}
+
+SVGLengthImpl &SVGLengthImpl::operator=(const SVGLengthImpl &other)
+{
+ m_unitType = other.m_unitType;
+ m_value = other.m_value;
+ m_valueInSpecifiedUnits = other.m_valueInSpecifiedUnits;
+ m_bboxContext = other.m_bboxContext;
+ m_mode = other.m_mode;
+ m_context = other.m_context;
+
+ return *this;
+}
+
+unsigned short SVGLengthImpl::unitType() const
+{
+ return m_unitType;
+}
+
+void SVGLengthImpl::setValue(float value)
+{
+ m_value = value;
+ getValFromPx();
+}
+
+float SVGLengthImpl::value()
+{
+ if(m_unitType == SVG_LENGTHTYPE_PERCENTAGE)
+ {
+ float value = m_valueInSpecifiedUnits / 100.0;
+ SVGRectImpl *bbox = 0;
+ if(m_bboxContext && (bbox = m_bboxContext->getBBox()))
+ {
+ float result = 0;
+ if(m_mode == LENGTHMODE_WIDTH)
+ result = value * bbox->width();
+ else if(m_mode == LENGTHMODE_HEIGHT)
+ result = value * bbox->height();
+ else if(m_mode == LENGTHMODE_OTHER)
+ result = value * sqrt(pow(bbox->width(), 2) + pow(bbox->height(), 2)) / sqrt(2.0);
+
+ bbox->deref();
+ return result;
+ }
+ else
+ return percentageOfViewport();
+ }
+ else
+ return m_value;
+}
+
+void SVGLengthImpl::setValueInSpecifiedUnits(float valueInSpecifiedUnits)
+{
+ m_valueInSpecifiedUnits = valueInSpecifiedUnits;
+ convertNumToPx();
+}
+
+float SVGLengthImpl::valueInSpecifiedUnits() const
+{
+ return m_valueInSpecifiedUnits;
+}
+
+void SVGLengthImpl::setValueAsString(const DOM::DOMString &valueAsString)
+{
+ convertStringToPx(valueAsString.string());
+}
+
+DOM::DOMString SVGLengthImpl::valueAsString() const
+{
+ DOM::DOMString valueAsString = QString::number(m_valueInSpecifiedUnits);
+ valueAsString += UnitText[m_unitType];
+ return valueAsString;
+}
+
+void SVGLengthImpl::newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits)
+{
+ m_valueInSpecifiedUnits = valueInSpecifiedUnits;
+ m_unitType = unitType;
+ convertNumToPx();
+}
+
+void SVGLengthImpl::convertToSpecifiedUnits(unsigned short unitType)
+{
+ m_unitType = unitType;
+ getValFromPx();
+}
+
+SVGLengthImpl::operator float()
+{
+ return valueInSpecifiedUnits();
+}
+
+bool SVGLengthImpl::getValFromPx()
+{
+ if(m_unitType == SVG_LENGTHTYPE_UNKNOWN)
+ return false;
+
+ switch(m_unitType)
+ {
+ // case SVG_LENGTHTYPE_PERCENTAGE: TODO
+ // case SVG_LENGTHTYPE_EMS: TODO
+ // case SVG_LENGTHTYPE_EXS: TODO
+ //break;
+ case SVG_LENGTHTYPE_PX:
+ m_valueInSpecifiedUnits = m_value;
+ break;
+ case SVG_LENGTHTYPE_CM:
+ m_valueInSpecifiedUnits = m_value / dpi() * 2.54;
+ break;
+ case SVG_LENGTHTYPE_MM:
+ m_valueInSpecifiedUnits = m_value / dpi() * 25.4;
+ break;
+ case SVG_LENGTHTYPE_IN:
+ m_valueInSpecifiedUnits = m_value / dpi();
+ break;
+ case SVG_LENGTHTYPE_PT:
+ m_valueInSpecifiedUnits = m_value / dpi() * 72.0;
+ break;
+ case SVG_LENGTHTYPE_PC:
+ m_valueInSpecifiedUnits = m_value / dpi() * 6.0;
+ break;
+ };
+ return true;
+}
+
+void SVGLengthImpl::convertStringToPx(QString s)
+{
+ if(s.isEmpty())
+ return;
+
+ double convNum = 0;
+ const char *start = s.latin1();
+ const char *end = getNumber(start, convNum);
+ m_valueInSpecifiedUnits = convNum;
+
+ if(uint(end - start) < s.length())
+ {
+ if(s.endsWith(UnitText[SVG_LENGTHTYPE_PX]))
+ m_unitType = SVG_LENGTHTYPE_PX;
+ else if(s.endsWith(UnitText[SVG_LENGTHTYPE_CM]))
+ m_unitType = SVG_LENGTHTYPE_CM;
+ else if(s.endsWith(UnitText[SVG_LENGTHTYPE_PC]))
+ m_unitType = SVG_LENGTHTYPE_PC;
+ else if(s.endsWith(UnitText[SVG_LENGTHTYPE_MM]))
+ m_unitType = SVG_LENGTHTYPE_MM;
+ else if(s.endsWith(UnitText[SVG_LENGTHTYPE_IN]))
+ m_unitType = SVG_LENGTHTYPE_IN;
+ else if(s.endsWith(UnitText[SVG_LENGTHTYPE_PT]))
+ m_unitType = SVG_LENGTHTYPE_PT;
+ else if(s.endsWith(UnitText[SVG_LENGTHTYPE_PERCENTAGE]))
+ m_unitType = SVG_LENGTHTYPE_PERCENTAGE;
+ else if(s.endsWith(UnitText[SVG_LENGTHTYPE_EMS]))
+ m_unitType = SVG_LENGTHTYPE_EMS;
+ else if(s.endsWith(UnitText[SVG_LENGTHTYPE_EXS]))
+ m_unitType = SVG_LENGTHTYPE_EXS;
+ else if(s.isEmpty())
+ m_unitType = SVG_LENGTHTYPE_NUMBER;
+ else
+ m_unitType = SVG_LENGTHTYPE_UNKNOWN;
+ }
+ else
+ m_unitType = SVG_LENGTHTYPE_PX;
+ convertNumToPx();
+}
+
+void SVGLengthImpl::convertNumToPx()
+{
+ switch(m_unitType)
+ {
+ case SVG_LENGTHTYPE_PX:
+ m_value = m_valueInSpecifiedUnits;
+ break;
+ case SVG_LENGTHTYPE_CM:
+ m_value = (m_valueInSpecifiedUnits / 2.54) * dpi();
+ break;
+ case SVG_LENGTHTYPE_MM:
+ m_value = (m_valueInSpecifiedUnits / 25.4) * dpi();
+ break;
+ case SVG_LENGTHTYPE_IN:
+ m_value = m_valueInSpecifiedUnits * dpi();
+ break;
+ case SVG_LENGTHTYPE_PT:
+ m_value = (m_valueInSpecifiedUnits / 72.0) * dpi();
+ break;
+ case SVG_LENGTHTYPE_PC:
+ m_value = (m_valueInSpecifiedUnits / 6.0) * dpi();
+ break;
+ case SVG_LENGTHTYPE_EMS: // Be careful here, always recheck coords-units-BE-01.svg after touching (Niko)
+ case SVG_LENGTHTYPE_EXS:
+ if(m_context)
+ {
+ SVGStylableImpl *style = dynamic_cast<SVGStylableImpl *>(m_context);
+ if(!style)
+ break;
+
+ bool sizeLocal = (style->getFontSize() != -1);
+ bool familyLocal = (style->getFontFamily() && style->getFontFamily()->getFirst());
+
+ SVGStylableImpl *parentStyle = 0;
+ if((!sizeLocal || !familyLocal) && m_context)
+ parentStyle = dynamic_cast<SVGStylableImpl *>(m_context->ownerDoc()->getElementFromHandle(m_context->parentNode().handle()));
+
+ // Look up font-size in a SAFE way, because at this place
+ // processStyle() has NOT yet been called, so we need
+ // a different solution (Niko)
+ QString useFont = "Arial";
+ double useSize = 12;
+
+ if(sizeLocal)
+ useSize = style->getFontSize();
+ else if(parentStyle && parentStyle->getFontSize() != -1)
+ useSize = parentStyle->getFontSize();
+
+ if(familyLocal)
+ useFont = style->getFontFamily()->getFirst()->string();
+ else if(parentStyle && parentStyle->getFontFamily() && parentStyle->getFontFamily()->getFirst())
+ useFont = parentStyle->getFontFamily()->getFirst()->string();
+
+ if(m_unitType == SVG_LENGTHTYPE_EMS)
+ m_value = m_valueInSpecifiedUnits * useSize;
+ else
+ {
+ // Easiest way, use qfont (Niko)
+ QFont font(useFont);
+ font.setPixelSize(static_cast<int>(useSize));
+
+ QFontMetrics fm(font);
+ m_value = m_valueInSpecifiedUnits * fm.boundingRect('x').height();
+ }
+ }
+ break;
+ };
+}
+
+void SVGLengthImpl::convertPercentageToFloat(const QString &perc, float &result)
+{
+ // TODO : more error checking ?
+ if(perc.endsWith("%"))
+ result = perc.left(perc.length() - 1).toFloat() / 100.0;
+ else
+ result = perc.toFloat();
+}
+
+QString SVGLengthImpl::convertValToPercentage(const QString &val, float benchmark)
+{
+ if(val.endsWith("%"))
+ return val;
+
+ QString result;
+ float temp = val.toFloat();
+
+ temp = (temp / benchmark) * 100.0;
+ result.setNum(temp);
+ result.append("%");
+
+ return result;
+}
+
+SVGElementImpl *SVGLengthImpl::context() const
+{
+ return m_context;
+}
+
+void SVGLengthImpl::setContext(SVGElementImpl *context)
+{
+ m_context = context;
+}
+
+void SVGLengthImpl::setBBoxContext(SVGShapeImpl *bbox)
+{
+ m_bboxContext = bbox;
+ convertNumToPx();
+}
+
+float SVGLengthImpl::percentageOfViewport()
+{
+ float width = 0, height = 0;
+ float value = m_valueInSpecifiedUnits / 100.0;
+ if(m_context->viewportElement())
+ {
+ SVGSVGElementImpl *svg = dynamic_cast<SVGSVGElementImpl *>(m_context->viewportElement());
+ if(svg)
+ {
+ // Calculate against viewBox, otherwise svg width/height
+ width = svg->viewBox()->baseVal()->width();
+ if(width == 0)
+ width = svg->width()->baseVal()->value();
+ height = svg->viewBox()->baseVal()->height();
+ if(height == 0)
+ height = svg->height()->baseVal()->value();
+ }
+
+ if(m_mode == LENGTHMODE_WIDTH)
+ return value * width;
+ else if(m_mode == LENGTHMODE_HEIGHT)
+ return value * height;
+ else if(m_mode == LENGTHMODE_OTHER)
+ return value * sqrt(pow(width, 2) + pow(height, 2)) / sqrt(2.0);
+ }
+ else if(m_context == m_context->ownerDoc()->rootElement())
+ {
+ if(!m_context->ownerDoc()->canvas()) // Happens when parsing <svg width="100%"> with printnodetest
+ return 0.0;
+
+ QPaintDeviceMetrics metrics(m_context->ownerDoc()->canvas()->drawWindow());
+
+ if(m_mode == LENGTHMODE_WIDTH)
+ return value * metrics.width();
+ else if(m_mode == LENGTHMODE_HEIGHT)
+ return value * metrics.height();
+ else if(m_mode == LENGTHMODE_OTHER)
+ return value * sqrt(pow(metrics.width(), 2) + pow(metrics.height(), 2)) / sqrt(2.0);
+ }
+
+ return 0;
+}
+
+// Ecma stuff
+//
+/*
+@namespace KSVG
+@begin SVGLengthImpl::s_hashTable 5
+ unitType SVGLengthImpl::UnitType DontDelete|ReadOnly
+ value SVGLengthImpl::Value DontDelete
+ valueAsString SVGLengthImpl::ValueAsString DontDelete
+ valueInSpecifiedUnits SVGLengthImpl::ValueInSpecifiedUnits DontDelete
+@end
+@namespace KSVG
+@begin SVGLengthImplProto::s_hashTable 3
+ newValueSpecifiedUnits SVGLengthImpl::NewValueSpecifiedUnits DontDelete|Function 2
+ convertToSpecifiedUnits SVGLengthImpl::ConvertToSpecifiedUnits DontDelete|Function 1
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGLength", SVGLengthImplProto, SVGLengthImplProtoFunc)
+
+Value SVGLengthImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case UnitType:
+ return Number(unitType());
+ case Value:
+ return Number(m_value);
+ case ValueAsString:
+ return String(valueAsString().string());
+ case ValueInSpecifiedUnits:
+ return Number(valueInSpecifiedUnits());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return KJS::Undefined();
+ }
+}
+
+void SVGLengthImpl::putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int)
+{
+ switch(token)
+ {
+ case Value:
+ setValue(value.toNumber(exec));
+ SVGHelperImpl::updateItem(exec, *m_context);
+ break;
+ case ValueAsString:
+ setValueAsString(value.toString(exec).string());
+ SVGHelperImpl::updateItem(exec, *m_context);
+ break;
+ case ValueInSpecifiedUnits:
+ setValueInSpecifiedUnits(value.toNumber(exec));
+ SVGHelperImpl::updateItem(exec, *m_context);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+Value SVGLengthImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGLengthImpl)
+
+ switch(id)
+ {
+ case SVGLengthImpl::NewValueSpecifiedUnits:
+ obj->newValueSpecifiedUnits(static_cast<unsigned short>(args[0].toNumber(exec)), args[1].toNumber(exec));
+ SVGHelperImpl::updateItem(exec, *obj->context());
+ return Undefined();
+ case SVGLengthImpl::ConvertToSpecifiedUnits:
+ obj->convertToSpecifiedUnits(static_cast<unsigned short>(args[0].toNumber(exec)));
+ SVGHelperImpl::updateItem(exec, *obj->context());
+ return Undefined();
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return Undefined();
+}
+
+/*
+@namespace KSVG
+@begin SVGLengthImplConstructor::s_hashTable 11
+ SVG_LENGTHTYPE_UNKNOWN KSVG::SVG_LENGTHTYPE_UNKNOWN DontDelete|ReadOnly
+ SVG_LENGTHTYPE_NUMBER KSVG::SVG_LENGTHTYPE_NUMBER DontDelete|ReadOnly
+ SVG_LENGTHTYPE_PERCENTAGE KSVG::SVG_LENGTHTYPE_PERCENTAGE DontDelete|ReadOnly
+ SVG_LENGTHTYPE_EMS KSVG::SVG_LENGTHTYPE_EMS DontDelete|ReadOnly
+ SVG_LENGTHTYPE_EXS KSVG::SVG_LENGTHTYPE_EXS DontDelete|ReadOnly
+ SVG_LENGTHTYPE_PX KSVG::SVG_LENGTHTYPE_PX DontDelete|ReadOnly
+ SVG_LENGTHTYPE_CM KSVG::SVG_LENGTHTYPE_CM DontDelete|ReadOnly
+ SVG_LENGTHTYPE_MM KSVG::SVG_LENGTHTYPE_MM DontDelete|ReadOnly
+ SVG_LENGTHTYPE_PT KSVG::SVG_LENGTHTYPE_PT DontDelete|ReadOnly
+ SVG_LENGTHTYPE_PC KSVG::SVG_LENGTHTYPE_PC DontDelete|ReadOnly
+@end
+*/
+
+Value SVGLengthImplConstructor::getValueProperty(ExecState *, int token) const
+{
+ return Number(token);
+}
+
+Value KSVG::getSVGLengthImplConstructor(ExecState *exec)
+{
+ return cacheGlobalBridge<SVGLengthImplConstructor>(exec, "[[svglength.constructor]]");
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGLengthImpl.h b/ksvg/impl/SVGLengthImpl.h
new file mode 100644
index 00000000..5879a091
--- /dev/null
+++ b/ksvg/impl/SVGLengthImpl.h
@@ -0,0 +1,136 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGLengthImpl_H
+#define SVGLengthImpl_H
+
+#include <dom/dom_misc.h>
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+enum LengthMode
+{
+ LENGTHMODE_UNKNOWN = 0,
+ LENGTHMODE_WIDTH = 1,
+ LENGTHMODE_HEIGHT = 2,
+ LENGTHMODE_OTHER = 3
+};
+
+class SVGShapeImpl;
+class SVGLocatableImpl;
+class SVGElementImpl;
+class SVGLengthImpl : public DOM::DomShared
+{
+public:
+ SVGLengthImpl(LengthMode mode = LENGTHMODE_UNKNOWN, SVGElementImpl *context = 0);
+ SVGLengthImpl(const SVGLengthImpl &);
+ virtual ~SVGLengthImpl();
+
+ SVGLengthImpl &operator=(const SVGLengthImpl &);
+
+ unsigned short unitType() const;
+
+ void setValue(float value);
+ float value();
+
+ void setValueInSpecifiedUnits(float valueInSpecifiedUnits);
+ float valueInSpecifiedUnits() const;
+
+ void setValueAsString(const DOM::DOMString &);
+ DOM::DOMString valueAsString() const;
+
+ void newValueSpecifiedUnits(unsigned short unitType, float valueInSpecifiedUnits);
+ void convertToSpecifiedUnits(unsigned short unitType);
+
+ operator float();
+
+ static void convertPercentageToFloat(const QString &perc, float &result);
+
+ // This method converts the value val to percentage notation ("xxx%").
+ // If the value string ends with the percentage sign it is returned,
+ // else the value is calculated against benchmark, ie. "0.2" -> "20%"
+ // for benchmark 1.0. This method should be useful in contexts that
+ // know the values should be in percentages up front, like bbox
+ // calculations.
+ static QString convertValToPercentage(const QString &val, float benchmark = 1.0);
+
+ SVGElementImpl *context() const;
+ void setContext(SVGElementImpl *context);
+ void setBBoxContext(SVGShapeImpl *bbox);
+
+private:
+ float m_value;
+ float m_valueInSpecifiedUnits;
+
+ float percentageOfViewport();
+
+ void convertStringToPx(QString s);
+ void convertNumToPx();
+ bool getValFromPx();
+
+ unsigned short m_unitType : 4;
+
+ // KSVG extension
+ LengthMode m_mode : 2;
+ SVGElementImpl *m_context;
+ SVGShapeImpl *m_bboxContext;
+
+ double dpi();
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ UnitType, Value, ValueAsString, ValueInSpecifiedUnits,
+ // Functions
+ NewValueSpecifiedUnits, ConvertToSpecifiedUnits
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+
+};
+
+class SVGLengthImplConstructor : public KJS::ObjectImp
+{
+public:
+ SVGLengthImplConstructor(KJS::ExecState *) { }
+ KJS::Value getValueProperty(KJS::ExecState *, int token) const;
+
+ // no put - all read-only
+ KSVG_GET
+};
+
+KJS::Value getSVGLengthImplConstructor(KJS::ExecState *exec);
+
+}
+
+KSVG_DEFINE_PROTOTYPE(SVGLengthImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGLengthImplProtoFunc, SVGLengthImpl)
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGLengthListImpl.cc b/ksvg/impl/SVGLengthListImpl.cc
new file mode 100644
index 00000000..31215ddd
--- /dev/null
+++ b/ksvg/impl/SVGLengthListImpl.cc
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGLengthListImpl.h"
+
+using namespace KSVG;
+
+#include "SVGLengthListImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGLengthListImpl::s_hashTable 2
+ numberOfItems SVGListDefs::NumberOfItems DontDelete|ReadOnly
+@end
+@namespace KSVG
+@begin SVGLengthListImplProto::s_hashTable 11
+ getItem SVGListDefs::GetItem DontDelete|Function 1
+ removeItem SVGListDefs::RemoveItem DontDelete|Function 1
+ appendItem SVGListDefs::AppendItem DontDelete|Function 1
+ initialize SVGListDefs::Initialize DontDelete|Function 1
+ insertItemBefore SVGListDefs::InsertItemBefore DontDelete|Function 2
+ replaceItem SVGListDefs::ReplaceItem DontDelete|Function 2
+ clear SVGListDefs::Clear DontDelete|Function 0
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGLengthList", SVGLengthListImplProto, SVGLengthListImplProtoFunc)
+
+Value SVGLengthListImpl::getValueProperty(ExecState *exec, int token) const
+{
+ return SVGList<SVGLengthImpl>::getValueProperty(exec, token);
+}
+
+Value SVGLengthListImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGLengthListImpl)
+
+ return obj->call(exec, static_cast<SVGList<SVGLengthImpl> *>(obj), args, id);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGLengthListImpl.h b/ksvg/impl/SVGLengthListImpl.h
new file mode 100644
index 00000000..7ef8c80d
--- /dev/null
+++ b/ksvg/impl/SVGLengthListImpl.h
@@ -0,0 +1,48 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGLengthListImpl_H
+#define SVGLengthListImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGList.h"
+
+#include "SVGLengthImpl.h"
+
+namespace KSVG
+{
+
+class SVGLengthListImpl : public SVGList<SVGLengthImpl>
+{
+public:
+ KSVG_GET
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+};
+
+}
+
+KSVG_DEFINE_PROTOTYPE(SVGLengthListImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGLengthListImplProtoFunc, SVGLengthListImpl)
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGLineElementImpl.cc b/ksvg/impl/SVGLineElementImpl.cc
new file mode 100644
index 00000000..7e13f46c
--- /dev/null
+++ b/ksvg/impl/SVGLineElementImpl.cc
@@ -0,0 +1,213 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <math.h>
+#include <kglobal.h>
+
+#include <kdebug.h>
+
+#include "CanvasItem.h"
+#include "KSVGCanvas.h"
+
+#include "SVGRectImpl.h"
+#include "SVGAngleImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGLineElementImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+
+using namespace KSVG;
+
+#include "SVGLineElementImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+
+SVGLineElementImpl::SVGLineElementImpl(DOM::ElementImpl *impl) : SVGShapeImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_x1 = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this);
+ m_x1->ref();
+ m_x1->baseVal()->setValueAsString("-1");
+
+ m_y1 = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this);
+ m_y1->ref();
+ m_y1->baseVal()->setValueAsString("-1");
+
+ m_x2 = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this);
+ m_x2->ref();
+ m_x2->baseVal()->setValueAsString("-1");
+
+ m_y2 = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this);
+ m_y2->ref();
+ m_y2->baseVal()->setValueAsString("-1");
+}
+
+SVGLineElementImpl::~SVGLineElementImpl()
+{
+ if(m_x1)
+ m_x1->deref();
+ if(m_x2)
+ m_x2->deref();
+ if(m_y1)
+ m_y1->deref();
+ if(m_y2)
+ m_y2->deref();
+}
+
+SVGAnimatedLengthImpl *SVGLineElementImpl::x1()
+{
+ return m_x1;
+}
+
+SVGAnimatedLengthImpl *SVGLineElementImpl::y1()
+{
+ return m_y1;
+}
+
+SVGAnimatedLengthImpl *SVGLineElementImpl::x2()
+{
+ return m_x2;
+}
+
+SVGAnimatedLengthImpl *SVGLineElementImpl::y2()
+{
+ return m_y2;
+}
+
+/*
+@namespace KSVG
+@begin SVGLineElementImpl::s_hashTable 5
+ x1 SVGLineElementImpl::X1 DontDelete|ReadOnly
+ y1 SVGLineElementImpl::Y1 DontDelete|ReadOnly
+ x2 SVGLineElementImpl::X2 DontDelete|ReadOnly
+ y2 SVGLineElementImpl::Y2 DontDelete|ReadOnly
+@end
+*/
+
+Value SVGLineElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ KSVG_CHECK_ATTRIBUTE
+
+ switch(token)
+ {
+ case X1:
+ if(!attributeMode)
+ return m_x1->cache(exec);
+ else
+ return Number(m_x1->baseVal()->value());
+ case Y1:
+ if(!attributeMode)
+ return m_y1->cache(exec);
+ else
+ return Number(m_y1->baseVal()->value());
+ case X2:
+ if(!attributeMode)
+ return m_x2->cache(exec);
+ else
+ return Number(m_x2->baseVal()->value());
+ case Y2:
+ if(!attributeMode)
+ return m_y2->cache(exec);
+ else
+ return Number(m_y2->baseVal()->value());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGLineElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case X1:
+ x1()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ case Y1:
+ y1()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ case X2:
+ x2()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ case Y2:
+ y2()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+SVGRectImpl *SVGLineElementImpl::getBBox()
+{
+ SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect();
+
+ float minx = kMin(m_x1->baseVal()->value(), m_x2->baseVal()->value());
+ float miny = kMin(m_y1->baseVal()->value(), m_y2->baseVal()->value());
+ float maxx = kMax(m_x1->baseVal()->value(), m_x2->baseVal()->value());
+ float maxy = kMax(m_y1->baseVal()->value(), m_y2->baseVal()->value());
+ ret->setX(minx);
+ ret->setY(miny);
+ ret->setWidth(maxx - minx);
+ ret->setHeight(maxy - miny);
+
+ return ret;
+}
+
+void SVGLineElementImpl::setAttributes()
+{
+ SVGElementImpl::setAttributes();
+
+ // Spec: if not specified, effect is as if a value of "0" were specified
+ if(KSVG_TOKEN_NOT_PARSED(X1))
+ KSVG_SET_ALT_ATTRIBUTE(X1, "0")
+
+ // Spec: if not specified, effect is as if a value of "0" were specified
+ if(KSVG_TOKEN_NOT_PARSED(Y1))
+ KSVG_SET_ALT_ATTRIBUTE(Y1, "0")
+
+ // Spec: if not specified, effect is as if a value of "0" were specified
+ if(KSVG_TOKEN_NOT_PARSED(X2))
+ KSVG_SET_ALT_ATTRIBUTE(X2, "0")
+
+ // Spec: if not specified, effect is as if a value of "0" were specified
+ if(KSVG_TOKEN_NOT_PARSED(Y2))
+ KSVG_SET_ALT_ATTRIBUTE(Y2, "0")
+}
+
+void SVGLineElementImpl::createItem(KSVGCanvas *c)
+{
+ if(!c)
+ c = ownerDoc()->canvas();
+
+ if(!m_item)
+ {
+ m_item = c->createLine(this);
+ c->insert(m_item);
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGLineElementImpl.h b/ksvg/impl/SVGLineElementImpl.h
new file mode 100644
index 00000000..725881a3
--- /dev/null
+++ b/ksvg/impl/SVGLineElementImpl.h
@@ -0,0 +1,86 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGLineElementImpl_H
+#define SVGLineElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGShapeImpl.h"
+#include "SVGTestsImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGLangSpaceImpl.h"
+#include "SVGTransformableImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+namespace KSVG
+{
+
+class SVGRectImpl;
+class SVGAnimatedLengthImpl;
+class SVGLineElementImpl : public SVGShapeImpl,
+ public SVGTestsImpl,
+ public SVGLangSpaceImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGStylableImpl,
+ public SVGTransformableImpl
+{
+public:
+ SVGLineElementImpl(DOM::ElementImpl *);
+ virtual ~SVGLineElementImpl();
+
+ SVGAnimatedLengthImpl *x1();
+ SVGAnimatedLengthImpl *y1();
+ SVGAnimatedLengthImpl *x2();
+ SVGAnimatedLengthImpl *y2();
+
+ virtual void createItem(KSVGCanvas *c = 0);
+ virtual void setAttributes();
+
+ virtual SVGRectImpl *getBBox();
+
+private:
+ SVGAnimatedLengthImpl *m_x1;
+ SVGAnimatedLengthImpl *m_y1;
+ SVGAnimatedLengthImpl *m_x2;
+ SVGAnimatedLengthImpl *m_y2;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+ KSVG_BRIDGE
+
+ enum
+ {
+ // Properties
+ X1, Y1, X2, Y2
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+KSVG_REGISTER_ELEMENT(SVGLineElementImpl, "line")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGLinearGradientElementImpl.cc b/ksvg/impl/SVGLinearGradientElementImpl.cc
new file mode 100644
index 00000000..54c97f01
--- /dev/null
+++ b/ksvg/impl/SVGLinearGradientElementImpl.cc
@@ -0,0 +1,201 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGGradientElement.h"
+#include "SVGLinearGradientElementImpl.h"
+
+#include "SVGDocumentImpl.h"
+#include "KSVGCanvas.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGLengthImpl.h"
+#include "SVGUnitConverter.h"
+
+using namespace KSVG;
+
+#include "SVGLinearGradientElementImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+
+SVGLinearGradientElementImpl::SVGLinearGradientElementImpl(DOM::ElementImpl *impl) : SVGGradientElementImpl(impl)
+{
+ KSVG_EMPTY_FLAGS
+
+ m_x1 = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this);
+ m_x1->ref();
+
+ m_y1 = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this);
+ m_y1->ref();
+
+ m_x2 = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this);
+ m_x2->ref();
+
+ m_y2 = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this);
+ m_y2->ref();
+
+ converter()->add(m_x1);
+ converter()->add(m_y1);
+ converter()->add(m_x2);
+ converter()->add(m_y2);
+}
+
+SVGLinearGradientElementImpl::~SVGLinearGradientElementImpl()
+{
+ if(m_x1)
+ m_x1->deref();
+ if(m_y1)
+ m_y1->deref();
+ if(m_x2)
+ m_x2->deref();
+ if(m_y2)
+ m_y2->deref();
+}
+
+SVGAnimatedLengthImpl *SVGLinearGradientElementImpl::x1() const
+{
+ return m_x1;
+}
+
+SVGAnimatedLengthImpl *SVGLinearGradientElementImpl::y1() const
+{
+ return m_y1;
+}
+
+SVGAnimatedLengthImpl *SVGLinearGradientElementImpl::x2() const
+{
+ return m_x2;
+}
+
+SVGAnimatedLengthImpl *SVGLinearGradientElementImpl::y2() const
+{
+ return m_y2;
+}
+
+/*
+@namespace KSVG
+@begin SVGLinearGradientElementImpl::s_hashTable 5
+ x1 SVGLinearGradientElementImpl::X1 DontDelete|ReadOnly
+ y1 SVGLinearGradientElementImpl::Y1 DontDelete|ReadOnly
+ x2 SVGLinearGradientElementImpl::X2 DontDelete|ReadOnly
+ y2 SVGLinearGradientElementImpl::Y2 DontDelete|ReadOnly
+@end
+*/
+
+Value SVGLinearGradientElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ KSVG_CHECK_ATTRIBUTE
+
+ switch(token)
+ {
+ case X1:
+ if(!attributeMode)
+ return m_x1->cache(exec);
+ else
+ return Number(m_x1->baseVal()->value());
+ case Y1:
+ if(!attributeMode)
+ return m_y1->cache(exec);
+ else
+ return Number(m_y1->baseVal()->value());
+ case X2:
+ if(!attributeMode)
+ return m_x2->cache(exec);
+ else
+ return Number(m_x2->baseVal()->value());
+ case Y2:
+ if(!attributeMode)
+ return m_y2->cache(exec);
+ else
+ return Number(m_y2->baseVal()->value());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGLinearGradientElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case X1:
+ converter()->modify(x1(), value.toString(exec).qstring());
+ break;
+ case Y1:
+ converter()->modify(y1(), value.toString(exec).qstring());
+ break;
+ case X2:
+ converter()->modify(x2(), value.toString(exec).qstring());
+ break;
+ case Y2:
+ converter()->modify(y2(), value.toString(exec).qstring());
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+void SVGLinearGradientElementImpl::setAttributes()
+{
+ SVGGradientElementImpl::setAttributes();
+
+ // Spec: no attribute, effect is af value 0% is specified
+ if(KSVG_TOKEN_NOT_PARSED(X1))
+ KSVG_SET_ALT_ATTRIBUTE(X1, "0")
+
+ // Spec: no attribute, effect is af value 0% is specified
+ if(KSVG_TOKEN_NOT_PARSED(Y1))
+ KSVG_SET_ALT_ATTRIBUTE(Y1, "0")
+
+ // Spec: no attribute, effect is af value 100% is specified
+ if(KSVG_TOKEN_NOT_PARSED(X2))
+ KSVG_SET_ALT_ATTRIBUTE(X2, "100%")
+
+ // Spec: no attribute, effect is af value 0% is specified
+ if(KSVG_TOKEN_NOT_PARSED(Y2))
+ KSVG_SET_ALT_ATTRIBUTE(Y2, "0")
+}
+
+QMap<QString, DOM::DOMString> SVGLinearGradientElementImpl::gradientAttributes()
+{
+ setAttributes();
+
+ QMap<QString, DOM::DOMString> gradAttributes;
+ QDictIterator<DOM::DOMString> it(attributes());
+
+ for(; it.current(); ++it)
+ {
+ DOM::DOMString name = it.currentKey();
+ DOM::DOMString value = it.current()->string();
+
+ if(name == "gradientUnits" || name == "gradientTransform" || name == "spreadMethod" || name == "x1" || name == "x2" || name == "y1" || name == "y2")
+ {
+ gradAttributes.insert(name.string(), value.copy());
+ }
+ }
+
+ return gradAttributes;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGLinearGradientElementImpl.h b/ksvg/impl/SVGLinearGradientElementImpl.h
new file mode 100644
index 00000000..a230a0fe
--- /dev/null
+++ b/ksvg/impl/SVGLinearGradientElementImpl.h
@@ -0,0 +1,74 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGLinearGradientElementImpl_H
+#define SVGLinearGradientElementImpl_H
+
+#include "SVGGradientElementImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedLengthImpl;
+class SVGLinearGradientElementImpl : public SVGGradientElementImpl
+{
+public:
+ SVGLinearGradientElementImpl(DOM::ElementImpl *);
+ virtual ~SVGLinearGradientElementImpl();
+
+ SVGAnimatedLengthImpl *x1() const;
+ SVGAnimatedLengthImpl *y1() const;
+ SVGAnimatedLengthImpl *x2() const;
+ SVGAnimatedLengthImpl *y2() const;
+
+ virtual void setAttributes();
+
+ virtual QMap<QString, DOM::DOMString> gradientAttributes();
+
+private:
+ SVGAnimatedLengthImpl *m_x1;
+ SVGAnimatedLengthImpl *m_y1;
+ SVGAnimatedLengthImpl *m_x2;
+ SVGAnimatedLengthImpl *m_y2;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+ KSVG_BRIDGE
+
+ enum
+ {
+ // Properties
+ X1, X2, Y1, Y2, Href
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+KSVG_REGISTER_ELEMENT(SVGLinearGradientElementImpl, "linearGradient")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGList.h b/ksvg/impl/SVGList.h
new file mode 100644
index 00000000..45eb81ba
--- /dev/null
+++ b/ksvg/impl/SVGList.h
@@ -0,0 +1,174 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGList_H
+#define SVGList_H
+
+#include "ksvg_bridge.h"
+#include "ksvg_lookup.h"
+#include "ksvg_scriptinterpreter.h"
+#include <qptrlist.h>
+#include <dom/dom_misc.h>
+
+namespace KSVG
+{
+
+class SVGListDefs
+{
+public:
+ enum
+ {
+ // Properties
+ NumberOfItems,
+ // Functions
+ GetItem, RemoveItem, AppendItem, Initialize,
+ InsertItemBefore, ReplaceItem, Clear
+ };
+};
+
+template<class T>
+class SVGList : public DOM::DomShared
+{
+public:
+ SVGList() { m_impl.setAutoDelete(false); }
+ SVGList(const SVGList &other) { *this = other; }
+ ~SVGList() { clear(); }
+
+ SVGList<T> &operator=(const SVGList<T> &other)
+ {
+ // Clear own list
+ clear();
+
+ // Clone other's elements and append them
+ SVGList<T> &get = const_cast<SVGList<T> &>(other);
+ for(unsigned int i = 0; i < other.numberOfItems(); i++)
+ {
+ T *obj = new T(*get.getItem(i));
+ obj->ref();
+
+ appendItem(obj);
+ }
+
+ return *this;
+ }
+
+ unsigned int numberOfItems() const { return m_impl.count(); }
+
+ void clear()
+ {
+ for(unsigned int i = 0; i < numberOfItems(); i++)
+ getItem(i)->deref();
+
+ m_impl.clear();
+ }
+
+ T *initialize(T *newItem)
+ {
+ clear();
+ return appendItem(newItem);
+ }
+
+ T *getFirst() const { return m_impl.getFirst(); }
+
+ T *getLast() const { return m_impl.getLast(); }
+
+ T *getItem(unsigned int index) { return m_impl.at(index); }
+ const T *getItem(unsigned int index) const { return const_cast<SVGList<T> *>(this)->m_impl.at(index); }
+
+ T *insertItemBefore(T *newItem, unsigned int index)
+ {
+ if (index < m_vector.size()) {
+ m_vector.insert(index, newItem);
+ } else {
+ m_vector.append(newItem);
+ }
+ return newItem;
+ }
+
+ T *replaceItem(T *newItem, unsigned int index)
+ {
+ m_impl.take(index);
+ m_impl.insert(index, newItem);
+ return newItem;
+ }
+
+ T *removeItem(unsigned int index)
+ {
+ return m_impl.take(index);
+ }
+
+ void removeItem(const T *item)
+ {
+ m_impl.remove(item);
+ }
+
+ T *appendItem(T *newItem)
+ {
+ m_impl.append(newItem);
+ return newItem;
+ }
+
+ // Ecma stuff
+ KJS::Value getValueProperty(KJS::ExecState *, int token) const
+ {
+ switch(token)
+ {
+ case SVGListDefs::NumberOfItems:
+ return KJS::Number(numberOfItems());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return KJS::Undefined();
+ }
+ }
+
+ KJS::Value call(KJS::ExecState *exec, SVGList<T> *obj, const KJS::List &args, int id)
+ {
+ switch(id)
+ {
+ case SVGListDefs::GetItem:
+ return obj->getItem(static_cast<unsigned int>(args[0].toNumber(exec)))->cache(exec);
+ case SVGListDefs::RemoveItem:
+ return obj->removeItem(static_cast<unsigned int>(args[0].toNumber(exec)))->cache(exec);
+ case SVGListDefs::AppendItem:
+ return obj->appendItem(static_cast<KSVGBridge<T> *>(args[0].imp())->impl())->cache(exec);
+ case SVGListDefs::InsertItemBefore:
+ return obj->insertItemBefore(static_cast<KSVGBridge<T> *>(args[0].imp())->impl(), static_cast<unsigned int>(args[1].toNumber(exec)))->cache(exec);
+ case SVGListDefs::Initialize:
+ return obj->initialize(static_cast<KSVGBridge<T> *>(args[0].imp())->impl())->cache(exec);
+ case SVGListDefs::Clear:
+ {
+ obj->clear();
+ return KJS::Undefined();
+ }
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return KJS::Undefined();
+ }
+
+private:
+ QPtrList<T> m_impl;
+};
+
+}
+
+#endif
diff --git a/ksvg/impl/SVGLocatableImpl.cc b/ksvg/impl/SVGLocatableImpl.cc
new file mode 100644
index 00000000..0ae143fa
--- /dev/null
+++ b/ksvg/impl/SVGLocatableImpl.cc
@@ -0,0 +1,208 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGRectImpl.h"
+#include "SVGShapeImpl.h"
+#include "SVGContainerImpl.h"
+#include "SVGMatrixImpl.h"
+#include "SVGElementImpl.h"
+#include "SVGLocatableImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGDocumentImpl.h"
+
+using namespace KSVG;
+
+#include "SVGLocatableImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+SVGLocatableImpl::SVGLocatableImpl()
+{
+ m_nearestViewportElement = 0;
+ m_farthestViewportElement = 0;
+ m_cachedScreenCTM = SVGSVGElementImpl::createSVGMatrix();
+ m_cachedScreenCTMIsValid = false;
+}
+
+SVGLocatableImpl::~SVGLocatableImpl()
+{
+ if(m_nearestViewportElement)
+ m_nearestViewportElement->deref();
+ if(m_farthestViewportElement)
+ m_farthestViewportElement->deref();
+ if(m_cachedScreenCTM)
+ m_cachedScreenCTM->deref();
+}
+
+SVGRectImpl *SVGLocatableImpl::getBBox()
+{
+ SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect();
+ return ret;
+}
+
+SVGMatrixImpl *SVGLocatableImpl::getCTM()
+{
+ SVGMatrixImpl *ret = SVGSVGElementImpl::createSVGMatrix();
+ return ret;
+}
+
+SVGMatrixImpl *SVGLocatableImpl::getScreenCTM()
+{
+ SVGMatrixImpl *ret = SVGSVGElementImpl::createSVGMatrix();
+ ret->copy(m_cachedScreenCTM);
+
+ return ret;
+}
+
+SVGMatrixImpl *SVGLocatableImpl::getTransformToElement(SVGElementImpl *)
+{
+ SVGMatrixImpl *ret = SVGSVGElementImpl::createSVGMatrix();
+ return ret;
+}
+
+void SVGLocatableImpl::updateCachedScreenCTM(const SVGMatrixImpl *parentScreenCTM)
+{
+ m_cachedScreenCTM->copy(parentScreenCTM);
+
+ const SVGMatrixImpl *local = localMatrix();
+
+ if(local)
+ m_cachedScreenCTM->multiply(local);
+ m_cachedScreenCTMIsValid = true;
+
+ // Notify the element
+ onScreenCTMUpdated();
+
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(this);
+
+ if(shape)
+ {
+ // TODO: Update due to matrix animations
+ //if(shape->item())
+ // shape->item()->update(updateReason);
+
+ SVGElementImpl *element = dynamic_cast<SVGElementImpl *>(this);
+
+ DOM::Node node = element->firstChild();
+ for(; !node.isNull(); node = node.nextSibling())
+ {
+ SVGElementImpl *child = element->ownerDoc()->getElementFromHandle(node.handle());
+ SVGLocatableImpl *locatable = dynamic_cast<SVGLocatableImpl *>(child);
+
+ if(child && locatable)
+ locatable->updateCachedScreenCTM(m_cachedScreenCTM);
+ }
+ }
+}
+
+void SVGLocatableImpl::checkCachedScreenCTM(const SVGMatrixImpl *parentScreenCTM)
+{
+ if(m_cachedScreenCTMIsValid)
+ {
+ SVGElementImpl *element = dynamic_cast<SVGElementImpl *>(this);
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(this);
+
+ if(shape)
+ {
+ DOM::Node node = element->firstChild();
+ for(; !node.isNull(); node = node.nextSibling())
+ {
+ SVGElementImpl *child = element->ownerDoc()->getElementFromHandle(node.handle());
+ SVGLocatableImpl *locatable = dynamic_cast<SVGLocatableImpl *>(child);
+
+ if(child && locatable)
+ locatable->checkCachedScreenCTM(m_cachedScreenCTM);
+ }
+ }
+ }
+ else
+ updateCachedScreenCTM(parentScreenCTM);
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGLocatableImpl::s_hashTable 3
+ nearestViewportElement SVGLocatableImpl::NearestViewportElement DontDelete
+ farthestViewportElement SVGLocatableImpl::FarthestViewportElement DontDelete
+@end
+@namespace KSVG
+@begin SVGLocatableImplProto::s_hashTable 5
+ getBBox SVGLocatableImpl::GetBBox DontDelete|Function 0
+ getCTM SVGLocatableImpl::GetCTM DontDelete|Function 0
+ getScreenCTM SVGLocatableImpl::GetScreenCTM DontDelete|Function 0
+ getTransformToElement SVGLocatableImpl::GetTransformToElement DontDelete|Function 1
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGLocatable", SVGLocatableImplProto, SVGLocatableImplProtoFunc)
+
+Value SVGLocatableImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case NearestViewportElement:
+ return nearestViewportElement() ? nearestViewportElement()->cache(exec) : Undefined();
+ case FarthestViewportElement:
+ return farthestViewportElement() ? farthestViewportElement()->cache(exec) : Undefined();
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+Value SVGLocatableImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGLocatableImpl)
+
+ switch(id)
+ {
+ case SVGLocatableImpl::GetBBox:
+ {
+ SVGContainerImpl *container = dynamic_cast<SVGContainerImpl *>(obj);
+ if(container)
+ return container->getBBox()->cache(exec);
+ else
+ {
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(obj);
+ if(shape)
+ return shape->getBBox()->cache(exec);
+ else
+ return obj->getBBox()->cache(exec);
+ }
+ }
+ case SVGLocatableImpl::GetCTM:
+ return obj->getCTM()->cache(exec);
+ case SVGLocatableImpl::GetScreenCTM:
+ return obj->getScreenCTM()->cache(exec);
+ case SVGLocatableImpl::GetTransformToElement:
+ return obj->getTransformToElement(static_cast<KSVGBridge<SVGElementImpl> *>(args[0].imp())->impl())->cache(exec);
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return Undefined();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGLocatableImpl.h b/ksvg/impl/SVGLocatableImpl.h
new file mode 100644
index 00000000..81ce3326
--- /dev/null
+++ b/ksvg/impl/SVGLocatableImpl.h
@@ -0,0 +1,94 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGLocatableImpl_H
+#define SVGLocatableImpl_H
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGRectImpl;
+class SVGMatrixImpl;
+class SVGElementImpl;
+class SVGLocatableImpl
+{
+public:
+ SVGLocatableImpl();
+ virtual ~SVGLocatableImpl();
+
+ SVGElementImpl *nearestViewportElement() const { return m_nearestViewportElement; }
+ SVGElementImpl *farthestViewportElement() const{ return m_farthestViewportElement; }
+
+ virtual SVGRectImpl *getBBox();
+ virtual SVGMatrixImpl *getCTM();
+ virtual SVGMatrixImpl *getScreenCTM();
+
+ // Faster access for when a new copy isn't required.
+ const SVGMatrixImpl *screenCTM() const { return m_cachedScreenCTM; }
+
+ SVGMatrixImpl *getTransformToElement(SVGElementImpl *element);
+
+ // The local transformations concatenated together. 0 if
+ // there are no local transformations.
+ virtual const SVGMatrixImpl *localMatrix() { return 0; }
+
+ bool cachedScreenCTMIsValid() const { return m_cachedScreenCTMIsValid; }
+ void invalidateCachedMatrices() { m_cachedScreenCTMIsValid = false; }
+
+ // If the cached matrix is invalid, update it and update any child elements
+ // recursively. Otherwise, check child elements recursively.
+ virtual void checkCachedScreenCTM(const SVGMatrixImpl *parentScreenCTM);
+ // Update the cached matrix, and update child element cached matrices,
+ // recursively.
+ virtual void updateCachedScreenCTM(const SVGMatrixImpl *parentScreenCTM);
+
+ // Called immediately after the screen ctm has been updated.
+ virtual void onScreenCTMUpdated() {}
+
+protected:
+ SVGElementImpl *m_nearestViewportElement;
+ SVGElementImpl *m_farthestViewportElement;
+ SVGMatrixImpl *m_cachedScreenCTM;
+ bool m_cachedScreenCTMIsValid;
+
+public:
+ KSVG_BASECLASS_GET
+
+ enum
+ {
+ // Properties
+ NearestViewportElement, FarthestViewportElement,
+ // Functions
+ GetBBox, GetCTM, GetScreenCTM, GetTransformToElement
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+};
+
+}
+
+KSVG_DEFINE_PROTOTYPE(SVGLocatableImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGLocatableImplProtoFunc, SVGLocatableImpl)
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGMPathElementImpl.cc b/ksvg/impl/SVGMPathElementImpl.cc
new file mode 100644
index 00000000..84d48274
--- /dev/null
+++ b/ksvg/impl/SVGMPathElementImpl.cc
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGMPathElementImpl.h"
+
+using namespace KSVG;
+
+SVGMPathElementImpl::SVGMPathElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGURIReferenceImpl(), SVGExternalResourcesRequiredImpl()
+{
+}
+
+SVGMPathElementImpl::~SVGMPathElementImpl()
+{
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGMPathElementImpl.h b/ksvg/impl/SVGMPathElementImpl.h
new file mode 100644
index 00000000..8d0bd96b
--- /dev/null
+++ b/ksvg/impl/SVGMPathElementImpl.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGMPathElementImpl_H
+#define SVGMPathElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGElementImpl.h"
+#include "SVGURIReferenceImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+namespace KSVG
+{
+
+class SVGMPathElementImpl : public SVGElementImpl,
+ public SVGURIReferenceImpl,
+ public SVGExternalResourcesRequiredImpl
+{
+public:
+ SVGMPathElementImpl(DOM::ElementImpl *);
+ virtual ~SVGMPathElementImpl();
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGMarkerElementImpl.cc b/ksvg/impl/SVGMarkerElementImpl.cc
new file mode 100644
index 00000000..0fc1d263
--- /dev/null
+++ b/ksvg/impl/SVGMarkerElementImpl.cc
@@ -0,0 +1,424 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGMarkerElement.h"
+
+#include "SVGRectImpl.h"
+#include "SVGAngleImpl.h"
+#include "SVGMatrixImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGTransformImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGAnimatedRectImpl.h"
+#include "SVGMarkerElementImpl.h"
+#include "SVGAnimatedAngleImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGAnimatedEnumerationImpl.h"
+#include "SVGPreserveAspectRatioImpl.h"
+#include "SVGAnimatedPreserveAspectRatioImpl.h"
+
+#include "KSVGCanvas.h"
+
+using namespace KSVG;
+
+#include "SVGMarkerElementImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+#include "ksvg_cacheimpl.h"
+
+SVGMarkerElementImpl::SVGMarkerElementImpl(DOM::ElementImpl *impl) : SVGContainerImpl(impl), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGFitToViewBoxImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_refX = new SVGAnimatedLengthImpl();
+ m_refX->ref();
+
+ m_refY = new SVGAnimatedLengthImpl();
+ m_refY->ref();
+
+ m_markerUnits = new SVGAnimatedEnumerationImpl();
+ m_markerUnits->ref();
+
+ m_markerWidth = new SVGAnimatedLengthImpl();
+ m_markerWidth->ref();
+
+ m_markerHeight = new SVGAnimatedLengthImpl();
+ m_markerHeight->ref();
+
+ m_orientType = new SVGAnimatedEnumerationImpl();
+ m_orientType->ref();
+
+ m_orientAngle = new SVGAnimatedAngleImpl();
+ m_orientAngle->ref();
+}
+
+SVGMarkerElementImpl::~SVGMarkerElementImpl()
+{
+ if(m_refX)
+ m_refX->deref();
+ if(m_refY)
+ m_refY->deref();
+ if(m_markerUnits)
+ m_markerUnits->deref();
+ if(m_markerWidth)
+ m_markerWidth->deref();
+ if(m_markerHeight)
+ m_markerHeight->deref();
+ if(m_orientType)
+ m_orientType->deref();
+ if(m_orientAngle)
+ m_orientAngle->deref();
+}
+
+SVGAnimatedLengthImpl *SVGMarkerElementImpl::refX() const
+{
+ return m_refX;
+}
+
+SVGAnimatedLengthImpl *SVGMarkerElementImpl::refY() const
+{
+ return m_refY;
+}
+
+SVGAnimatedEnumerationImpl *SVGMarkerElementImpl::markerUnits() const
+{
+ return m_markerUnits;
+}
+
+SVGAnimatedLengthImpl *SVGMarkerElementImpl::markerWidth() const
+{
+ return m_markerWidth;
+}
+
+SVGAnimatedLengthImpl *SVGMarkerElementImpl::markerHeight() const
+{
+ return m_markerHeight;
+}
+
+SVGAnimatedEnumerationImpl *SVGMarkerElementImpl::orientType() const
+{
+ return m_orientType;
+}
+
+SVGAnimatedAngleImpl *SVGMarkerElementImpl::orientAngle() const
+{
+ return m_orientAngle;
+}
+
+void SVGMarkerElementImpl::setOrientToAuto()
+{
+ orientType()->setBaseVal(SVG_MARKER_ORIENT_AUTO);
+}
+
+void SVGMarkerElementImpl::setOrientToAngle(SVGAngleImpl *angle)
+{
+ m_orientAngle->baseVal()->setValue(angle->value());
+}
+
+void SVGMarkerElementImpl::setAttributes()
+{
+ SVGElementImpl::setAttributes();
+
+ // Spec: if not specified, effect is as if a value of "0" were specified
+ if(KSVG_TOKEN_NOT_PARSED(RefX))
+ KSVG_SET_ALT_ATTRIBUTE(RefX, "0")
+
+ // Spec: if not specified, effect is as if a value of "0" were specified
+ if(KSVG_TOKEN_NOT_PARSED(RefY))
+ KSVG_SET_ALT_ATTRIBUTE(RefY, "0")
+
+ // Spec: if not specified, effect is as if a value of "3" were specified
+ if(KSVG_TOKEN_NOT_PARSED(MarkerWidth))
+ KSVG_SET_ALT_ATTRIBUTE(MarkerWidth, "3")
+
+ // Spec: if not specified, effect is as if a value of "3" were specified
+ if(KSVG_TOKEN_NOT_PARSED(MarkerHeight))
+ KSVG_SET_ALT_ATTRIBUTE(MarkerHeight, "3")
+
+ // Spec: if attribute not specified, use strokeWidth
+ if(KSVG_TOKEN_NOT_PARSED(MarkerUnits))
+ KSVG_SET_ALT_ATTRIBUTE(MarkerUnits, "strokeWidth")
+
+ // Spec: if attribute not specified, use angle
+ if(KSVG_TOKEN_NOT_PARSED(Orient))
+ KSVG_SET_ALT_ATTRIBUTE(Orient, "angle")
+}
+
+void SVGMarkerElementImpl::createItem(KSVGCanvas *c)
+{
+ if(!c)
+ c = ownerDoc()->canvas();
+
+ if(!m_item)
+ {
+ m_item = c->createCanvasMarker(this);
+ c->insert(m_item);
+ }
+}
+
+void SVGMarkerElementImpl::draw(SVGShapeImpl *referencingElement, double x, double y, double lwidth, double angle)
+{
+ SVGMatrixImpl *mtx = dynamic_cast<SVGLocatableImpl *>(referencingElement)->getScreenCTM();
+
+ // move to dest
+ mtx->translate(x, y);
+
+ // scale by linewidth if marker units == strokewidth
+ if(markerUnits()->baseVal() == SVG_MARKERUNITS_STROKEWIDTH)
+ mtx->scale(lwidth);
+
+ // select appropriate rotation
+ if(orientType()->baseVal() == SVG_MARKER_ORIENT_AUTO)
+ mtx->rotate(angle);
+ else
+ mtx->rotate(orientAngle()->baseVal()->value());
+
+ SVGRectImpl *viewBoxRect = viewBox()->baseVal();
+ SVGMatrixImpl *pres = preserveAspectRatio()->baseVal()->getCTM(viewBoxRect->x(), viewBoxRect->y(),
+ viewBoxRect->width(), viewBoxRect->height(),
+ 0, 0, markerWidth()->baseVal()->value(),
+ markerHeight()->baseVal()->value());
+
+ // viewbox stuff
+ mtx->multiply(pres);
+
+ // Get the vertex position in viewbox coordinates. The vertex is at (0, 0) in viewport coordinates.
+ double vertexX, vertexY;
+ pres->qmatrix().invert().map(0, 0, &vertexX, &vertexY);
+
+ // Translate so that the vertex is at (refX, refY) in viewbox coordinates.
+ mtx->translate(vertexX - refX()->baseVal()->value(), vertexY - refY()->baseVal()->value());
+
+ if(getOverflow())
+ m_clipShape.clear();
+ else
+ {
+ KSVGRectangle viewport;
+
+ if(hasAttribute("viewBox"))
+ {
+ // Get the viewport ((0, 0) - (markerWidth, markerHeight)) in viewbox coordinates.
+ double w, h;
+ pres->qmatrix().invert().map(markerWidth()->baseVal()->value(), markerHeight()->baseVal()->value(), &w, &h);
+
+ viewport = KSVGRectangle(vertexX, vertexY, w - vertexX, h - vertexY);
+ }
+ else
+ viewport = KSVGRectangle(0, 0, markerWidth()->baseVal()->value(), markerHeight()->baseVal()->value());
+
+ // Transform to screen coordinates.
+ m_clipShape = mtx->map(viewport);
+ }
+
+ pres->deref();
+
+ DOM::Node node = firstChild();
+ for(; !node.isNull(); node = node.nextSibling())
+ {
+ SVGElementImpl *element = ownerDoc()->getElementFromHandle(node.handle());
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(element);
+ SVGTestsImpl *tests = dynamic_cast<SVGTestsImpl *>(element);
+ SVGStylableImpl *style = dynamic_cast<SVGStylableImpl *>(element);
+
+ bool ok = tests ? tests->ok() : true;
+ if(element && shape && style && ok && style->getVisible() && style->getDisplay())
+ {
+ SVGLocatableImpl *locatable = dynamic_cast<SVGLocatableImpl *>(element);
+ if(locatable)
+ locatable->updateCachedScreenCTM(mtx);
+
+ shape->update(UPDATE_TRANSFORM);
+ shape->setReferenced(true);
+ shape->draw();
+ shape->setReferenced(false);
+ }
+ }
+
+ mtx->deref();
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGMarkerElementImpl::s_hashTable 11
+ refX SVGMarkerElementImpl::RefX DontDelete|ReadOnly
+ refY SVGMarkerElementImpl::RefY DontDelete|ReadOnly
+ markerUnits SVGMarkerElementImpl::MarkerUnits DontDelete|ReadOnly
+ markerWidth SVGMarkerElementImpl::MarkerWidth DontDelete|ReadOnly
+ markerHeight SVGMarkerElementImpl::MarkerHeight DontDelete|ReadOnly
+ orientType SVGMarkerElementImpl::OrientType DontDelete|ReadOnly
+ orientAngle SVGMarkerElementImpl::OrientAngle DontDelete|ReadOnly
+ orient SVGMarkerElementImpl::Orient DontDelete|ReadOnly
+@end
+@namespace KSVG
+@begin SVGMarkerElementImplProto::s_hashTable 3
+ setOrientToAuto SVGMarkerElementImpl::SetOrientToAuto DontDelete|Function 0
+ setOrientToAngle SVGMarkerElementImpl::SetOrientToAngle DontDelete|Function 0
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGMarkerElement", SVGMarkerElementImplProto, SVGMarkerElementImplProtoFunc)
+
+Value SVGMarkerElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ KSVG_CHECK_ATTRIBUTE
+
+ switch(token)
+ {
+ case RefX:
+ if(!attributeMode)
+ return m_refX->cache(exec);
+ else
+ return Number(m_refX->baseVal()->value());
+ case RefY:
+ if(!attributeMode)
+ return m_refY->cache(exec);
+ else
+ return Number(m_refY->baseVal()->value());
+ case MarkerUnits:
+ if(!attributeMode)
+ return m_markerUnits->cache(exec);
+ else
+ return Number(m_markerUnits->baseVal());
+ case MarkerWidth:
+ if(!attributeMode)
+ return m_markerWidth->cache(exec);
+ else
+ return Number(m_markerWidth->baseVal()->value());
+ case MarkerHeight:
+ if(!attributeMode)
+ return m_markerHeight->cache(exec);
+ else
+ return Number(m_markerHeight->baseVal()->value());
+ case OrientType:
+ if(!attributeMode)
+ return m_orientType->cache(exec);
+ else
+ return Number(m_orientType->baseVal());
+ case OrientAngle:
+ if(!attributeMode)
+ return m_orientAngle->cache(exec);
+ else
+ return Number(m_orientAngle->baseVal()->value());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGMarkerElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case RefX:
+ refX()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ case RefY:
+ refY()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ case MarkerWidth:
+ markerWidth()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ case MarkerHeight:
+ markerHeight()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ case MarkerUnits:
+ if(value.toString(exec).qstring() == "userSpaceOnUse")
+ markerUnits()->setBaseVal(SVG_MARKERUNITS_USERSPACEONUSE);
+ else
+ markerUnits()->setBaseVal(SVG_MARKERUNITS_STROKEWIDTH);
+ break;
+ case Orient:
+ {
+ QString param = value.toString(exec).qstring();
+
+ if(param == "auto")
+ orientType()->setBaseVal(SVG_MARKER_ORIENT_AUTO);
+ else
+ {
+ orientType()->setBaseVal(SVG_MARKER_ORIENT_ANGLE);
+ m_orientAngle->baseVal()->setValueAsString(param);
+ }
+ break;
+ }
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+Value SVGMarkerElementImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGMarkerElementImpl)
+
+ switch(id)
+ {
+ case SVGMarkerElementImpl::SetOrientToAuto:
+ obj->setOrientToAuto();
+ return Undefined();
+#ifdef __GNUC__
+#warning FIXME cache stuff
+#endif
+ case SVGMarkerElementImpl::SetOrientToAngle:
+ obj->setOrientToAngle(static_cast<KSVGBridge<SVGAngleImpl> *>(args[0].imp())->impl());
+ return Undefined();
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return Undefined();
+}
+
+// CONSTANTS
+
+/*
+@namespace KSVG
+@begin SVGMarkerElementImplConstructor::s_hashTable 7
+ SVG_MARKERUNITS_UNKNOWN KSVG::SVG_MARKERUNITS_UNKNOWN DontDelete|ReadOnly
+ SVG_MARKERUNITS_USERSPACEONUSE KSVG::SVG_MARKERUNITS_USERSPACEONUSE DontDelete|ReadOnly
+ SVG_MARKERUNITS_STROKEWIDTH KSVG::SVG_MARKERUNITS_STROKEWIDTH DontDelete|ReadOnly
+ SVG_MARKER_ORIENT_UNKNOWN KSVG::SVG_MARKER_ORIENT_UNKNOWN DontDelete|ReadOnly
+ SVG_MARKER_ORIENT_AUTO KSVG::SVG_MARKER_ORIENT_AUTO DontDelete|ReadOnly
+ SVG_MARKER_ORIENT_ANGLE KSVG::SVG_MARKER_ORIENT_ANGLE DontDelete|ReadOnly
+@end
+*/
+
+using namespace KJS;
+
+Value SVGMarkerElementImplConstructor::getValueProperty(ExecState *, int token) const
+{
+ return Number(token);
+}
+
+Value KSVG::getSVGMarkerElementImplConstructor(ExecState *exec)
+{
+ return cacheGlobalBridge<SVGMarkerElementImplConstructor>(exec, "[[svgmarkerelement.constructor]]");
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGMarkerElementImpl.h b/ksvg/impl/SVGMarkerElementImpl.h
new file mode 100644
index 00000000..7e6539e3
--- /dev/null
+++ b/ksvg/impl/SVGMarkerElementImpl.h
@@ -0,0 +1,121 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGMarkerElementImpl_H
+#define SVGMarkerElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGStylableImpl.h"
+#include "SVGLangSpaceImpl.h"
+#include "SVGContainerImpl.h"
+#include "SVGFitToViewBoxImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+#include "KSVGHelper.h"
+
+namespace KSVG
+{
+
+class SVGAngleImpl;
+class SVGAnimatedAngleImpl;
+class SVGAnimatedLengthImpl;
+class SVGAnimatedEnumerationImpl;
+class SVGMarkerElementImpl : public SVGContainerImpl,
+ public SVGLangSpaceImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGStylableImpl,
+ public SVGFitToViewBoxImpl
+{
+public:
+ SVGMarkerElementImpl(DOM::ElementImpl *);
+ virtual ~SVGMarkerElementImpl();
+
+ SVGAnimatedLengthImpl *refX() const;
+ SVGAnimatedLengthImpl *refY() const;
+ SVGAnimatedEnumerationImpl *markerUnits() const;
+ SVGAnimatedLengthImpl *markerWidth() const;
+ SVGAnimatedLengthImpl *markerHeight() const;
+ SVGAnimatedEnumerationImpl *orientType() const;
+ SVGAnimatedAngleImpl *orientAngle() const;
+
+ void setOrientToAuto();
+ void setOrientToAngle(SVGAngleImpl *angle);
+
+ virtual void setAttributes();
+ virtual void createItem(KSVGCanvas *c = 0);
+
+ void draw(SVGShapeImpl *referencingElement, double x, double y, double lwidth, double angle);
+
+ KSVGPolygon clipShape() const { return m_clipShape; }
+
+ virtual bool directRender() { return false; }
+ virtual bool isContainer() const { return false; }
+
+private:
+ SVGAnimatedLengthImpl *m_refX;
+ SVGAnimatedLengthImpl *m_refY;
+ SVGAnimatedEnumerationImpl *m_markerUnits;
+ SVGAnimatedLengthImpl *m_markerWidth;
+ SVGAnimatedLengthImpl *m_markerHeight;
+ SVGAnimatedEnumerationImpl *m_orientType;
+ SVGAnimatedAngleImpl *m_orientAngle;
+
+ KSVGPolygon m_clipShape;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+ KSVG_BRIDGE
+
+ enum
+ {
+ // Properties
+ RefX, RefY, MarkerUnits, MarkerWidth, MarkerHeight, OrientType, OrientAngle,
+ Orient, ViewBox, PreserveAspectRatio,
+ // Functions
+ SetOrientToAuto, SetOrientToAngle
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+class SVGMarkerElementImplConstructor : public KJS::ObjectImp
+{
+public:
+ SVGMarkerElementImplConstructor(KJS::ExecState *) { }
+ KJS::Value getValueProperty(KJS::ExecState *, int token) const;
+
+ // no put - all read-only
+ KSVG_GET
+};
+
+KJS::Value getSVGMarkerElementImplConstructor(KJS::ExecState *exec);
+
+KSVG_REGISTER_ELEMENT(SVGMarkerElementImpl, "marker")
+
+}
+
+KSVG_DEFINE_PROTOTYPE(SVGMarkerElementImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGMarkerElementImplProtoFunc, SVGMarkerElementImpl)
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGMaskElementImpl.cc b/ksvg/impl/SVGMaskElementImpl.cc
new file mode 100644
index 00000000..5cd2151e
--- /dev/null
+++ b/ksvg/impl/SVGMaskElementImpl.cc
@@ -0,0 +1,542 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <cfloat>
+
+#include <kdebug.h>
+#include <qimage.h>
+
+#include "SVGMaskElement.h"
+
+#include "SVGRectImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGMaskElementImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGAnimatedEnumerationImpl.h"
+#include "SVGUnitConverter.h"
+#include "SVGShapeImpl.h"
+#include "SVGMatrixImpl.h"
+#include "KSVGCanvas.h"
+#include "CanvasItems.h"
+#include "CanvasFactory.h"
+#include "KSVGHelper.h"
+
+#include <X11/Xos.h>
+
+using namespace KSVG;
+
+#include "SVGMaskElementImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_ecma.h"
+
+SVGMaskElementImpl::SVGMaskElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGBBoxTarget()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_x = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this);
+ m_x->ref();
+
+ m_y = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this);
+ m_y->ref();
+
+ m_width = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this);
+ m_width->ref();
+
+ m_height = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this);
+ m_height->ref();
+
+ m_maskUnits = new SVGAnimatedEnumerationImpl();
+ m_maskUnits->ref();
+
+ m_maskContentUnits = new SVGAnimatedEnumerationImpl();
+ m_maskContentUnits->ref();
+
+ m_converter = new SVGUnitConverter();
+ m_converter->add(m_x);
+ m_converter->add(m_y);
+ m_converter->add(m_width);
+ m_converter->add(m_height);
+
+ m_canvas = 0;
+
+ m_maskCache.setMaxTotalCost(1024 * 1024);
+}
+
+SVGMaskElementImpl::~SVGMaskElementImpl()
+{
+ if(m_x)
+ m_x->deref();
+ if(m_y)
+ m_y->deref();
+ if(m_width)
+ m_width->deref();
+ if(m_height)
+ m_height->deref();
+ if(m_maskUnits)
+ m_maskContentUnits->deref();
+ if(m_maskUnits)
+ m_maskContentUnits->deref();
+ delete m_converter;
+ if(m_canvas)
+ delete m_canvas;
+}
+
+SVGAnimatedEnumerationImpl *SVGMaskElementImpl::maskUnits() const
+{
+ return m_maskUnits;
+}
+
+SVGAnimatedEnumerationImpl *SVGMaskElementImpl::maskContentUnits() const
+{
+ return m_maskContentUnits;
+}
+
+SVGAnimatedLengthImpl *SVGMaskElementImpl::x() const
+{
+ return m_x;
+}
+
+SVGAnimatedLengthImpl *SVGMaskElementImpl::y() const
+{
+ return m_y;
+}
+
+SVGAnimatedLengthImpl *SVGMaskElementImpl::width() const
+{
+ return m_width;
+}
+
+SVGAnimatedLengthImpl *SVGMaskElementImpl::height() const
+{
+ return m_height;
+}
+
+/*
+@namespace KSVG
+@begin SVGMaskElementImpl::s_hashTable 7
+ maskUnits SVGMaskElementImpl::MaskUnits DontDelete|ReadOnly
+ maskContentUnits SVGMaskElementImpl::MaskContentUnits DontDelete|ReadOnly
+ x SVGMaskElementImpl::X DontDelete|ReadOnly
+ y SVGMaskElementImpl::Y DontDelete|ReadOnly
+ width SVGMaskElementImpl::Width DontDelete|ReadOnly
+ height SVGMaskElementImpl::Height DontDelete|ReadOnly
+@end
+*/
+Value SVGMaskElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ KSVG_CHECK_ATTRIBUTE
+
+ switch(token)
+ {
+ case MaskUnits:
+ if(!attributeMode)
+ return m_maskUnits->cache(exec);
+ else
+ return Number(m_maskUnits->baseVal());
+ case MaskContentUnits:
+ if(!attributeMode)
+ return m_maskContentUnits->cache(exec);
+ else
+ return Number(m_maskContentUnits->baseVal());
+ case X:
+ if(!attributeMode)
+ return m_x->cache(exec);
+ else
+ return Number(m_x->baseVal()->value());
+ case Y:
+ if(!attributeMode)
+ return m_y->cache(exec);
+ else
+ return Number(m_y->baseVal()->value());
+ case Width:
+ if(!attributeMode)
+ return m_width->cache(exec);
+ else
+ return Number(m_width->baseVal()->value());
+
+ case Height:
+ if(!attributeMode)
+ return m_height->cache(exec);
+ else
+ return Number(m_height->baseVal()->value());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGMaskElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case MaskUnits:
+ if(value.toString(exec).qstring() == "objectBoundingBox")
+ m_maskUnits->setBaseVal(SVGMaskElement::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
+ else
+ m_maskUnits->setBaseVal(SVGMaskElement::SVG_UNIT_TYPE_USERSPACEONUSE);
+ break;
+ case MaskContentUnits:
+ if(value.toString(exec).qstring() == "objectBoundingBox")
+ m_maskContentUnits->setBaseVal(SVGMaskElement::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
+ else
+ m_maskContentUnits->setBaseVal(SVGMaskElement::SVG_UNIT_TYPE_USERSPACEONUSE);
+ break;
+ case X:
+ converter()->modify(x(), value.toString(exec).qstring());
+ break;
+ case Y:
+ converter()->modify(y(), value.toString(exec).qstring());
+ break;
+ case Width:
+ converter()->modify(width(), value.toString(exec).qstring());
+ break;
+ case Height:
+ converter()->modify(height(), value.toString(exec).qstring());
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+SVGRectImpl *SVGMaskElementImpl::getBBox()
+{
+ SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect();
+ ret->setX(m_x->baseVal()->value());
+ ret->setY(m_y->baseVal()->value());
+ ret->setWidth(m_width->baseVal()->value());
+ ret->setHeight(m_height->baseVal()->value());
+ return ret;
+}
+
+void SVGMaskElementImpl::setAttributes()
+{
+ SVGElementImpl::setAttributes();
+
+ // Spec: if attribute not specified, use objectBoundingBox
+ if(KSVG_TOKEN_NOT_PARSED(MaskUnits))
+ KSVG_SET_ALT_ATTRIBUTE(MaskUnits, "objectBoundingBox")
+
+ // Spec: if attribute not specified, use userSpaceOnUse
+ if(KSVG_TOKEN_NOT_PARSED(MaskContentUnits))
+ KSVG_SET_ALT_ATTRIBUTE(MaskContentUnits, "userSpaceOnUse")
+
+ // Spec: if attribute not specified, use "-10%"
+ if(KSVG_TOKEN_NOT_PARSED(X))
+ KSVG_SET_ALT_ATTRIBUTE(X, "-10%");
+
+ // Spec: if attribute not specified, use "-10%"
+ if(KSVG_TOKEN_NOT_PARSED(Y))
+ KSVG_SET_ALT_ATTRIBUTE(Y, "-10%");
+
+ // Spec: if attribute not specified, use "120%"
+ if(KSVG_TOKEN_NOT_PARSED(Width))
+ KSVG_SET_ALT_ATTRIBUTE(Width, "120%");
+
+ // Spec: if attribute not specified, use "120%"
+ if(KSVG_TOKEN_NOT_PARSED(Height))
+ KSVG_SET_ALT_ATTRIBUTE(Height, "120%");
+}
+
+SVGMaskElementImpl::Mask SVGMaskElementImpl::createMask(SVGShapeImpl *referencingElement, int imageWidth, int imageHeight)
+{
+ converter()->finalize(referencingElement, ownerSVGElement(), maskUnits()->baseVal());
+
+ Q_UINT32 *imageBits = new Q_UINT32[imageWidth * imageHeight];
+
+ if(m_canvas == 0)
+ m_canvas = CanvasFactory::self()->loadCanvas(imageWidth, imageHeight);
+
+ m_canvas->setup(reinterpret_cast<unsigned char *>(imageBits), imageWidth, imageHeight);
+ m_canvas->setBackgroundColor(qRgba(0, 0, 0, 0));
+
+ SVGMatrixImpl *baseMatrix = SVGSVGElementImpl::createSVGMatrix();
+
+ // Set the scale to map the mask onto the image
+ double xScale = static_cast<double>(imageWidth) / width()->baseVal()->value();
+ double yScale = static_cast<double>(imageHeight) / height()->baseVal()->value();
+
+ baseMatrix->scaleNonUniform(xScale, yScale);
+
+ SVGRectImpl *bbox = referencingElement->getBBox();
+
+ if(maskUnits()->baseVal() == SVGMaskElement::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
+ baseMatrix->translate(-(bbox->x() + x()->baseVal()->value()), -(bbox->y() + y()->baseVal()->value()));
+ else
+ baseMatrix->translate(-x()->baseVal()->value(), -y()->baseVal()->value());
+
+ if(maskContentUnits()->baseVal() == SVGMaskElement::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
+ {
+ baseMatrix->translate(bbox->x(), bbox->y());
+ baseMatrix->scaleNonUniform(bbox->width(), bbox->height());
+ }
+
+ for(DOM::Node node = firstChild(); !node.isNull(); node = node.nextSibling())
+ {
+ SVGElementImpl *element = ownerDoc()->getElementFromHandle(node.handle());
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(element);
+ SVGTestsImpl *tests = dynamic_cast<SVGTestsImpl *>(element);
+ SVGStylableImpl *style = dynamic_cast<SVGStylableImpl *>(element);
+
+ bool ok = tests ? tests->ok() : true;
+ if(element && shape && style && ok && style->getVisible() && style->getDisplay())
+ {
+ SVGLocatableImpl *locatable = dynamic_cast<SVGLocatableImpl *>(element);
+ if(locatable)
+ locatable->updateCachedScreenCTM(baseMatrix);
+
+ element->createItem(m_canvas);
+ if(shape->item())
+ {
+ shape->item()->setReferenced(true);
+ m_canvas->invalidate(shape->item(), true);
+ }
+ }
+ }
+
+ m_canvas->update(float(1));
+
+ for(DOM::Node node = firstChild(); !node.isNull(); node = node.nextSibling())
+ {
+ SVGElementImpl *element = ownerDoc()->getElementFromHandle(node.handle());
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(element);
+ SVGTestsImpl *tests = dynamic_cast<SVGTestsImpl *>(element);
+ SVGStylableImpl *style = dynamic_cast<SVGStylableImpl *>(element);
+
+ bool ok = tests ? tests->ok() : true;
+ if(element && shape && style && ok && style->getVisible() && style->getDisplay())
+ {
+ if(shape)
+ shape->removeItem(m_canvas);
+ }
+ }
+
+
+ {
+ // Note: r and b reversed
+ //QImage maskImage(reinterpret_cast<unsigned char *>(imageBits), imageWidth, imageHeight, 32, 0, 0, QImage::IgnoreEndian);
+ //maskImage.setAlphaBuffer(true);
+ //maskImage.save("mask.png", "PNG");
+ }
+
+ QByteArray maskData(imageWidth * imageHeight);
+ const double epsilon = DBL_EPSILON;
+
+ // Convert the rgba image into an 8-bit mask, according to the specs.
+ for(int i = 0; i < imageWidth * imageHeight; i++)
+ {
+ Q_UINT32 rgba = imageBits[i];
+
+#if X_BYTE_ORDER == X_LITTLE_ENDIAN
+ double r = (rgba & 0xff) / 255.0;
+ double g = ((rgba >> 8) & 0xff) / 255.0;
+ double b = ((rgba >> 16) & 0xff) / 255.0;
+ double a = ((rgba >> 24) & 0xff) / 255.0;
+#else
+ double a = (rgba & 0xff) / 255.0;
+ double b = ((rgba >> 8) & 0xff) / 255.0;
+ double g = ((rgba >> 16) & 0xff) / 255.0;
+ double r = ((rgba >> 24) & 0xff) / 255.0;
+#endif
+
+ // Remove pre-multiplication by alpha.
+ if(a > epsilon)
+ {
+ r /= a;
+ g /= a;
+ b /= a;
+ }
+
+ // Convert to linear RGB
+ r = KSVGHelper::linearRGBFromsRGB(int(r * 255 + 0.5)) / 255.0;
+ g = KSVGHelper::linearRGBFromsRGB(int(g * 255 + 0.5)) / 255.0;
+ b = KSVGHelper::linearRGBFromsRGB(int(b * 255 + 0.5)) / 255.0;
+
+ // Convert 'luminance to alpha'
+ double luminanceAlpha = 0.2125 * r + 0.7154 * g + 0.0721 * b;
+
+ // Multiply by alpha.
+ double maskValue = luminanceAlpha * a;
+
+ maskData[i] = static_cast<unsigned char>(maskValue * 255 + 0.5);
+ }
+
+ delete [] imageBits;
+
+ baseMatrix->deref();
+ bbox->deref();
+
+ // The screenToMask matrix is calculated each time the mask is used so we don't
+ // need to set it here.
+ QWMatrix tempMatrix;
+
+ return Mask(maskData, tempMatrix, imageWidth, imageHeight);
+}
+
+SVGMaskElementImpl::Mask SVGMaskElementImpl::createMask(SVGShapeImpl *referencingElement)
+{
+ converter()->finalize(referencingElement, ownerSVGElement(), maskUnits()->baseVal());
+
+ SVGMatrixImpl *refCTM = 0;
+ SVGLocatableImpl *locatableRef = dynamic_cast<SVGLocatableImpl *>(referencingElement);
+ if(locatableRef)
+ refCTM = locatableRef->getScreenCTM();
+ else
+ refCTM = SVGSVGElementImpl::createSVGMatrix();
+
+ double xScale, yScale;
+
+ refCTM->removeScale(&xScale, &yScale);
+ refCTM->deref();
+
+ int imageWidth = static_cast<int>(width()->baseVal()->value() * xScale + 0.5);
+ int imageHeight = static_cast<int>(height()->baseVal()->value() * yScale + 0.5);
+
+ Mask mask;
+
+ if(imageWidth > 0 && imageHeight > 0)
+ {
+ CacheKey key(referencingElement, imageWidth, imageHeight);
+
+ if(!m_maskCache.find(key, mask))
+ {
+ mask = createMask(referencingElement, imageWidth, imageHeight);
+ m_maskCache.insert(key, mask, imageWidth * imageHeight);
+ }
+
+ // Generate a mask-coordinates to screen-coordinates matrix
+ SVGMatrixImpl *matrix = 0;
+ if(locatableRef)
+ matrix = locatableRef->getScreenCTM();
+ else
+ matrix = SVGSVGElementImpl::createSVGMatrix();
+
+ if(maskUnits()->baseVal() == SVGMaskElement::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
+ {
+ SVGRectImpl *bbox = referencingElement->getBBox();
+ matrix->translate(bbox->x() + x()->baseVal()->value(), bbox->y() + y()->baseVal()->value());
+ bbox->deref();
+ }
+ else
+ matrix->translate(x()->baseVal()->value(), y()->baseVal()->value());
+
+ matrix->scaleNonUniform(1 / xScale, 1 / yScale);
+
+ QWMatrix screenToMask = matrix->qmatrix().invert();
+ matrix->deref();
+
+ mask.setScreenToMask(screenToMask);
+ }
+
+ return mask;
+}
+
+QByteArray SVGMaskElementImpl::maskRectangle(SVGShapeImpl *shape, const QRect& screenRectangle)
+{
+ QByteArray cumulativeMask;
+
+ do
+ {
+ SVGStylableImpl *style = dynamic_cast<SVGStylableImpl *>(shape);
+
+ if(style && style->hasMask())
+ {
+ SVGElementImpl *element = shape->ownerDoc()->rootElement()->getElementById(style->getMask());
+
+ if(element)
+ {
+ SVGMaskElementImpl *maskElement = dynamic_cast<SVGMaskElementImpl *>(element);
+
+ if(maskElement)
+ {
+ SVGMaskElementImpl::Mask mask = maskElement->createMask(shape);
+
+ if(!mask.isEmpty())
+ {
+ QByteArray maskData = mask.rectangle(screenRectangle);
+
+ if(cumulativeMask.size() == 0)
+ cumulativeMask = maskData;
+ else
+ {
+ int size = cumulativeMask.size();
+
+ // Multiply into the cumulative mask (using fast divide by 255)
+ for(int i = 0; i < size; i++)
+ {
+ int tmp = maskData[i] * cumulativeMask[i] + 0x80;
+ cumulativeMask[i] = (tmp + (tmp >> 8)) >> 8;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ DOM::Node parentNode = shape->parentNode();
+
+ if(!parentNode.isNull())
+ {
+ SVGElementImpl *parent = shape->ownerDoc()->getElementFromHandle(parentNode.handle());
+
+ if(parent)
+ shape = dynamic_cast<SVGShapeImpl *>(parent);
+ else
+ shape = 0;
+ }
+ else
+ shape = 0;
+
+ } while(shape);
+
+ return cumulativeMask;
+}
+
+SVGMaskElementImpl::Mask::Mask(const QByteArray& mask, const QWMatrix& screenToMask, int width, int height)
+ : m_width(width), m_height(height), m_mask(mask), m_screenToMask(screenToMask)
+{
+}
+
+QByteArray SVGMaskElementImpl::Mask::rectangle(int screenX, int screenY, int width, int height)
+{
+ QByteArray rect(width * height);
+
+ for(int x = 0; x < width; x++)
+ {
+ for(int y = 0; y < height; y++)
+ {
+ rect[x + y * width] = value(screenX + x, screenY + y);
+ }
+ }
+
+ return rect;
+}
+
+QByteArray SVGMaskElementImpl::Mask::rectangle(const QRect& rect)
+{
+ return rectangle(rect.x(), rect.y(), rect.width(), rect.height());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGMaskElementImpl.h b/ksvg/impl/SVGMaskElementImpl.h
new file mode 100644
index 00000000..cdd1c125
--- /dev/null
+++ b/ksvg/impl/SVGMaskElementImpl.h
@@ -0,0 +1,158 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGMaskElementImpl_H
+#define SVGMaskElementImpl_H
+
+#include <qwmatrix.h>
+
+#include "SVGTestsImpl.h"
+#include "SVGBBoxTarget.h"
+#include "SVGElementImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGLangSpaceImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+#include "LRUCache.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+
+class SVGUnitConverter;
+class KSVGCanvas;
+class SVGShapeImpl;
+class SVGRectImpl;
+class SVGAnimatedLengthImpl;
+class SVGAnimatedEnumerationImpl;
+class SVGMaskElementImpl : public SVGElementImpl,
+ public SVGTestsImpl,
+ public SVGLangSpaceImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGStylableImpl,
+ public SVGBBoxTarget
+{
+public:
+
+ class Mask
+ {
+ public:
+ Mask() : m_width(0), m_height(0) {}
+ Mask(const QByteArray& mask, const QWMatrix& screenToMask, int width, int height);
+ ~Mask() {}
+
+ bool isEmpty() const { return m_width == 0; }
+ unsigned char value(int screenX, int screenY) const;
+ QByteArray rectangle(int screenX, int screenY, int width, int height);
+ QByteArray rectangle(const QRect& rect);
+ void setScreenToMask(const QWMatrix& matrix) { m_screenToMask = matrix; }
+
+ private:
+ int m_width;
+ int m_height;
+ QByteArray m_mask;
+ QWMatrix m_screenToMask;
+ };
+
+ SVGMaskElementImpl(DOM::ElementImpl *);
+ virtual ~SVGMaskElementImpl();
+
+ SVGAnimatedEnumerationImpl *maskUnits() const;
+ SVGAnimatedEnumerationImpl *maskContentUnits() const;
+ SVGAnimatedLengthImpl *x() const;
+ SVGAnimatedLengthImpl *y() const;
+ SVGAnimatedLengthImpl *width() const;
+ SVGAnimatedLengthImpl *height() const;
+
+ virtual SVGRectImpl *getBBox();
+ virtual void setAttributes();
+
+ SVGUnitConverter *converter() const { return m_converter; }
+
+ Mask createMask(SVGShapeImpl *referencingElement);
+
+ // Compute the mask on a given shape, taking into account all masks defined
+ // on the shape's ancestors. This is a workaround for us not having a buffer
+ // for container elements, so we can't mask containers directly.
+ static QByteArray maskRectangle(SVGShapeImpl *shape, const QRect& screenRectangle);
+
+private:
+ class CacheKey
+ {
+ public:
+ CacheKey() : m_element(0), m_width(0), m_height(0) {}
+ CacheKey(SVGElementImpl *element, int width, int height) : m_element(element), m_width(width), m_height(height) {}
+ bool operator==(const CacheKey& other) const { return m_element == other.m_element && m_width == other.m_width && m_height == other.m_height; }
+
+ private:
+ SVGElementImpl *m_element;
+ int m_width;
+ int m_height;
+ };
+
+ Mask createMask(SVGShapeImpl *referencingElement, int imageWidth, int imageHeight);
+
+ SVGAnimatedEnumerationImpl *m_maskUnits;
+ SVGAnimatedEnumerationImpl *m_maskContentUnits;
+ SVGAnimatedLengthImpl *m_x;
+ SVGAnimatedLengthImpl *m_y;
+ SVGAnimatedLengthImpl *m_width;
+ SVGAnimatedLengthImpl *m_height;
+
+ SVGUnitConverter *m_converter;
+ KSVGCanvas *m_canvas;
+
+ MinOneLRUCache<CacheKey, Mask> m_maskCache;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+ KSVG_BRIDGE
+
+ enum
+ {
+ // Properties
+ MaskUnits, MaskContentUnits, X, Y, Width, Height
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+KSVG_REGISTER_ELEMENT(SVGMaskElementImpl, "mask")
+
+inline unsigned char SVGMaskElementImpl::Mask::value(int screenX, int screenY) const
+{
+ int x, y;
+
+ m_screenToMask.map(screenX, screenY, &x, &y);
+
+ if(x >= 0 && x < m_width && y >= 0 && y < m_height)
+ return m_mask[x + y * m_width];
+ else
+ return 0;
+}
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGMatrixImpl.cc b/ksvg/impl/SVGMatrixImpl.cc
new file mode 100644
index 00000000..81f14f66
--- /dev/null
+++ b/ksvg/impl/SVGMatrixImpl.cc
@@ -0,0 +1,460 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <math.h>
+
+#include <kdebug.h>
+
+#include "SVGAngleImpl.h"
+#include "SVGMatrixImpl.h"
+#include "KSVGHelper.h"
+
+using namespace KSVG;
+
+#include "SVGMatrixImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+SVGMatrixImpl::SVGMatrixImpl()
+{
+ KSVG_EMPTY_FLAGS
+}
+
+SVGMatrixImpl::SVGMatrixImpl(QWMatrix mat)
+{
+ m_mat = mat;
+}
+
+SVGMatrixImpl::SVGMatrixImpl(double a, double b, double c, double d, double e, double f)
+{
+ m_mat.setMatrix(a, b, c, d, e, f);
+}
+
+SVGMatrixImpl::~SVGMatrixImpl()
+{
+}
+
+void SVGMatrixImpl::setA(const double &a)
+{
+ m_mat.setMatrix(a, m_mat.m12(), m_mat.m21(), m_mat.m22(), m_mat.dx(), m_mat.dy());
+}
+
+double SVGMatrixImpl::a() const
+{
+ return m_mat.m11();
+}
+
+void SVGMatrixImpl::setB(const double &b)
+{
+ m_mat.setMatrix(m_mat.m11(), b, m_mat.m21(), m_mat.m22(), m_mat.dx(), m_mat.dy());
+}
+
+double SVGMatrixImpl::b() const
+{
+ return m_mat.m12();
+}
+
+void SVGMatrixImpl::setC(const double &c)
+{
+ m_mat.setMatrix(m_mat.m11(), m_mat.m12(), c, m_mat.m22(), m_mat.dx(), m_mat.dy());
+}
+
+double SVGMatrixImpl::c() const
+{
+ return m_mat.m21();
+}
+
+void SVGMatrixImpl::setD(const double &d)
+{
+ m_mat.setMatrix(m_mat.m11(), m_mat.m12(), m_mat.m21(), d, m_mat.dx(), m_mat.dy());
+}
+
+double SVGMatrixImpl::d() const
+{
+ return m_mat.m22();
+}
+
+void SVGMatrixImpl::setE(const double &e)
+{
+ m_mat.setMatrix(m_mat.m11(), m_mat.m12(), m_mat.m21(), m_mat.m22(), e, m_mat.dy());
+}
+
+double SVGMatrixImpl::e() const
+{
+ return m_mat.dx();
+}
+
+void SVGMatrixImpl::setF(const double &f)
+{
+ m_mat.setMatrix(m_mat.m11(), m_mat.m12(), m_mat.m21(), m_mat.m22(), m_mat.dx(), f);
+}
+
+double SVGMatrixImpl::f() const
+{
+ return m_mat.dy();
+}
+
+void SVGMatrixImpl::copy(const SVGMatrixImpl *other)
+{
+ m_mat.setMatrix(other->m_mat.m11(), other->m_mat.m12(), other->m_mat.m21(), other->m_mat.m22(), other->m_mat.dx(), other->m_mat.dy());
+}
+
+SVGMatrixImpl *SVGMatrixImpl::postMultiply(const SVGMatrixImpl *secondMatrix)
+{
+ QWMatrix temp(secondMatrix->a(), secondMatrix->b(), secondMatrix->c(), secondMatrix->d(), secondMatrix->e(), secondMatrix->f());
+ m_mat *= temp;
+ return this;
+}
+
+SVGMatrixImpl *SVGMatrixImpl::inverse()
+{
+ m_mat = m_mat.invert();
+ return this;
+}
+
+SVGMatrixImpl *SVGMatrixImpl::postTranslate(const double &x, const double &y)
+{
+ // Could optimise these.
+ QWMatrix temp;
+ temp.translate(x, y);
+ m_mat *= temp;
+ return this;
+}
+
+SVGMatrixImpl *SVGMatrixImpl::postScale(const double &scaleFactor)
+{
+ QWMatrix temp;
+ temp.scale(scaleFactor, scaleFactor);
+ m_mat *= temp;
+ return this;
+}
+
+SVGMatrixImpl *SVGMatrixImpl::postScaleNonUniform(const double &scaleFactorX, const double &scaleFactorY)
+{
+ QWMatrix temp;
+ temp.scale(scaleFactorX, scaleFactorY);
+ m_mat *= temp;
+ return this;
+}
+
+SVGMatrixImpl *SVGMatrixImpl::postRotate(const double &angle)
+{
+ QWMatrix temp;
+ temp.rotate(angle);
+ m_mat *= temp;
+ return this;
+}
+
+SVGMatrixImpl *SVGMatrixImpl::postRotateFromVector(const double &x, const double &y)
+{
+ QWMatrix temp;
+ temp.rotate(SVGAngleImpl::todeg(atan2(y, x)));
+ m_mat *= temp;
+ return this;
+}
+
+SVGMatrixImpl *SVGMatrixImpl::postFlipX()
+{
+ QWMatrix temp(-1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F);
+ m_mat *= temp;
+ return this;
+}
+
+SVGMatrixImpl *SVGMatrixImpl::postFlipY()
+{
+ QWMatrix temp(1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F);
+ m_mat *= temp;
+ return this;
+}
+
+SVGMatrixImpl *SVGMatrixImpl::postSkewX(const double &angle)
+{
+ QWMatrix temp;
+ temp.shear(tan(SVGAngleImpl::torad(angle)), 0.0F);
+ m_mat *= temp;
+ return this;
+}
+
+SVGMatrixImpl *SVGMatrixImpl::postSkewY(const double &angle)
+{
+ QWMatrix temp;
+ temp.shear(0.0F, tan(SVGAngleImpl::torad(angle)));
+ m_mat *= temp;
+ return this;
+}
+
+SVGMatrixImpl *SVGMatrixImpl::multiply(const SVGMatrixImpl *secondMatrix)
+{
+ QWMatrix temp(secondMatrix->a(), secondMatrix->b(), secondMatrix->c(), secondMatrix->d(), secondMatrix->e(), secondMatrix->f());
+ temp *= m_mat;
+ m_mat = temp;
+ return this;
+}
+
+SVGMatrixImpl *SVGMatrixImpl::translate(const double &x, const double &y)
+{
+ m_mat.translate(x, y);
+ return this;
+}
+
+SVGMatrixImpl *SVGMatrixImpl::scale(const double &scaleFactor)
+{
+ m_mat.scale(scaleFactor, scaleFactor);
+ return this;
+}
+
+SVGMatrixImpl *SVGMatrixImpl::scaleNonUniform(const double &scaleFactorX, const double &scaleFactorY)
+{
+ m_mat.scale(scaleFactorX, scaleFactorY);
+ return this;
+}
+
+SVGMatrixImpl *SVGMatrixImpl::rotate(const double &angle)
+{
+ m_mat.rotate(angle);
+ return this;
+}
+
+SVGMatrixImpl *SVGMatrixImpl::rotateFromVector(const double &x, const double &y)
+{
+ m_mat.rotate(SVGAngleImpl::todeg(atan2(y, x)));
+ return this;
+}
+
+SVGMatrixImpl *SVGMatrixImpl::flipX()
+{
+ m_mat.scale(-1.0f, 1.0f);
+ return this;
+}
+
+SVGMatrixImpl *SVGMatrixImpl::flipY()
+{
+ m_mat.scale(1.0f, -1.0f);
+ return this;
+}
+
+SVGMatrixImpl *SVGMatrixImpl::skewX(const double &angle)
+{
+ m_mat.shear(tan(SVGAngleImpl::torad(angle)), 0.0F);
+ return this;
+}
+
+SVGMatrixImpl *SVGMatrixImpl::skewY(const double &angle)
+{
+ m_mat.shear(0.0F, tan(SVGAngleImpl::torad(angle)));
+ return this;
+}
+
+void SVGMatrixImpl::setMatrix(QWMatrix mat)
+{
+ m_mat = mat;
+}
+
+QWMatrix &SVGMatrixImpl::qmatrix()
+{
+ return m_mat;
+}
+
+const QWMatrix &SVGMatrixImpl::qmatrix() const
+{
+ return m_mat;
+}
+
+void SVGMatrixImpl::reset()
+{
+ m_mat.reset();
+}
+
+void SVGMatrixImpl::removeScale(double *xScale, double *yScale)
+{
+ double sx = sqrt(a()*a() + b()*b());
+ double sy = sqrt(c()*c() + d()*d());
+
+ // Remove the scaling from the matrix.
+
+ setA(a()/sx);
+ setB(b()/sx);
+ setC(c()/sy);
+ setD(d()/sy);
+
+ *xScale = sx;
+ *yScale = sy;
+}
+
+KSVGPolygon SVGMatrixImpl::map(const KSVGPolygon& polygon) const
+{
+ KSVGPolygon mapped;
+
+ for(unsigned int i = 0; i < polygon.numPoints(); i++)
+ {
+ double x, y;
+
+ m_mat.map(polygon.point(i).x(), polygon.point(i).y(), &x, &y);
+ mapped.addPoint(x, y);
+ }
+
+ return mapped;
+}
+
+KSVGPolygon SVGMatrixImpl::inverseMap(const KSVGPolygon& polygon) const
+{
+ QWMatrix inverse = m_mat.invert();
+ KSVGPolygon mapped;
+
+ for(unsigned int i = 0; i < polygon.numPoints(); i++)
+ {
+ double x, y;
+
+ inverse.map(polygon.point(i).x(), polygon.point(i).y(), &x, &y);
+ mapped.addPoint(x, y);
+ }
+
+ return mapped;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGMatrixImpl::s_hashTable 7
+ a SVGMatrixImpl::A DontDelete
+ b SVGMatrixImpl::B DontDelete
+ c SVGMatrixImpl::C DontDelete
+ d SVGMatrixImpl::D DontDelete
+ e SVGMatrixImpl::E DontDelete
+ f SVGMatrixImpl::F DontDelete
+@end
+@namespace KSVG
+@begin SVGMatrixImplProto::s_hashTable 13
+ inverse SVGMatrixImpl::Inverse DontDelete|Function 0
+ multiply SVGMatrixImpl::Multiply DontDelete|Function 1
+ translate SVGMatrixImpl::Translate DontDelete|Function 2
+ scale SVGMatrixImpl::Scale DontDelete|Function 1
+ rotate SVGMatrixImpl::Rotate DontDelete|Function 1
+ rotateFromVector SVGMatrixImpl::RotateFromVector DontDelete|Function 2
+ scaleNonUniform SVGMatrixImpl::ScaleNonUniform DontDelete|Function 2
+ flipX SVGMatrixImpl::FlipX DontDelete|Function 0
+ flipY SVGMatrixImpl::FlipY DontDelete|Function 0
+ skewX SVGMatrixImpl::SkewX DontDelete|Function 1
+ skewY SVGMatrixImpl::SkewY DontDelete|Function 1
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGMatrix", SVGMatrixImplProto, SVGMatrixImplProtoFunc)
+
+Value SVGMatrixImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case A:
+ return Number(a());
+ case B:
+ return Number(b());
+ case C:
+ return Number(c());
+ case D:
+ return Number(d());
+ case E:
+ return Number(e());
+ case F:
+ return Number(f());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return KJS::Undefined();
+ }
+}
+
+
+void SVGMatrixImpl::putValueProperty(ExecState *exec, int token, const KJS::Value &value, int)
+{
+ switch(token)
+ {
+ case A:
+ setA(value.toNumber(exec));
+ break;
+ case B:
+ setB(value.toNumber(exec));
+ break;
+ case C:
+ setC(value.toNumber(exec));
+ break;
+ case D:
+ setD(value.toNumber(exec));
+ break;
+ case E:
+ setE(value.toNumber(exec));
+ break;
+ case F:
+ setF(value.toNumber(exec));
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ break;
+ }
+}
+
+Value SVGMatrixImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGMatrixImpl)
+
+ switch(id)
+ {
+ case SVGMatrixImpl::Inverse:
+ return obj->inverse()->cache(exec);
+ break;
+ case SVGMatrixImpl::Multiply:
+ return obj->multiply(static_cast<KSVGBridge<SVGMatrixImpl> *>(args[0].imp())->impl())->cache(exec);
+ break;
+ case SVGMatrixImpl::Translate:
+ return obj->translate(args[0].toNumber(exec), args[1].toNumber(exec))->cache(exec);
+ break;
+ case SVGMatrixImpl::Scale:
+ return obj->scale(args[0].toNumber(exec))->cache(exec);
+ break;
+ case SVGMatrixImpl::Rotate:
+ return obj->rotate(args[0].toNumber(exec))->cache(exec);
+ break;
+ case SVGMatrixImpl::RotateFromVector:
+ return obj->rotateFromVector(args[0].toNumber(exec), args[1].toNumber(exec))->cache(exec);
+ break;
+ case SVGMatrixImpl::ScaleNonUniform:
+ return obj->scaleNonUniform(args[0].toNumber(exec), args[1].toNumber(exec))->cache(exec);
+ break;
+ case SVGMatrixImpl::FlipX:
+ return obj->flipX()->cache(exec);
+ break;
+ case SVGMatrixImpl::FlipY:
+ return obj->flipY()->cache(exec);
+ break;
+ case SVGMatrixImpl::SkewX:
+ return obj->skewX(args[0].toNumber(exec))->cache(exec);
+ break;
+ case SVGMatrixImpl::SkewY:
+ return obj->skewY(args[0].toNumber(exec))->cache(exec);;
+ break;
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return Undefined();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGMatrixImpl.h b/ksvg/impl/SVGMatrixImpl.h
new file mode 100644
index 00000000..a5d8edf3
--- /dev/null
+++ b/ksvg/impl/SVGMatrixImpl.h
@@ -0,0 +1,130 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGMatrixImpl_H
+#define SVGMatrixImpl_H
+
+#include <qwmatrix.h>
+
+#include <dom/dom_misc.h>
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+class KSVGPolygon;
+
+class SVGMatrixImpl : public DOM::DomShared
+{
+public:
+ SVGMatrixImpl();
+ SVGMatrixImpl(QWMatrix mat);
+ SVGMatrixImpl(double, double, double, double, double, double);
+ ~SVGMatrixImpl();
+
+ void setA(const double &);
+ double a() const;
+
+ void setB(const double &);
+ double b() const;
+
+ void setC(const double &);
+ double c() const;
+
+ void setD(const double &);
+ double d() const;
+
+ void setE(const double &);
+ double e() const;
+
+ void setF(const double &);
+ double f() const;
+
+ void copy(const SVGMatrixImpl *other);
+
+ SVGMatrixImpl *inverse();
+
+ // Pre-multiplied operations, as per the specs.
+ SVGMatrixImpl *multiply(const SVGMatrixImpl *secondMatrix);
+ SVGMatrixImpl *translate(const double &x, const double &y);
+ SVGMatrixImpl *scale(const double &scaleFactor);
+ SVGMatrixImpl *scaleNonUniform(const double &scaleFactorX, const double &scaleFactorY);
+ SVGMatrixImpl *rotate(const double &angle);
+ SVGMatrixImpl *rotateFromVector(const double &x, const double &y);
+ SVGMatrixImpl *flipX();
+ SVGMatrixImpl *flipY();
+ SVGMatrixImpl *skewX(const double &angle);
+ SVGMatrixImpl *skewY(const double &angle);
+
+ // Post-multiplied operations
+ SVGMatrixImpl *postMultiply(const SVGMatrixImpl *secondMatrix);
+ SVGMatrixImpl *postTranslate(const double &x, const double &y);
+ SVGMatrixImpl *postScale(const double &scaleFactor);
+ SVGMatrixImpl *postScaleNonUniform(const double &scaleFactorX, const double &scaleFactorY);
+ SVGMatrixImpl *postRotate(const double &angle);
+ SVGMatrixImpl *postRotateFromVector(const double &x, const double &y);
+ SVGMatrixImpl *postFlipX();
+ SVGMatrixImpl *postFlipY();
+ SVGMatrixImpl *postSkewX(const double &angle);
+ SVGMatrixImpl *postSkewY(const double &angle);
+
+ void reset();
+
+ // KSVG helper method
+ QWMatrix &qmatrix();
+ const QWMatrix &qmatrix() const;
+
+ // Determine the scaling component of the matrix and factor it out. After
+ // this operation, the matrix has x and y scale of one.
+ void removeScale(double *xScale, double *yScale);
+
+ KSVGPolygon map(const KSVGPolygon& polygon) const;
+ KSVGPolygon inverseMap(const KSVGPolygon& polygon) const;
+
+private:
+ void setMatrix(QWMatrix mat);
+ QWMatrix m_mat;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ A, B, C, D, E, F,
+ // Functions
+ Inverse, Multiply, Translate, Scale, Rotate,
+ RotateFromVector, ScaleNonUniform,
+ FlipX, FlipY, SkewX, SkewY
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+KSVG_DEFINE_PROTOTYPE(SVGMatrixImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGMatrixImplProtoFunc, SVGMatrixImpl)
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGMetadataElementImpl.cc b/ksvg/impl/SVGMetadataElementImpl.cc
new file mode 100644
index 00000000..d55d4302
--- /dev/null
+++ b/ksvg/impl/SVGMetadataElementImpl.cc
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGMetadataElementImpl.h"
+
+using namespace KSVG;
+
+SVGMetadataElementImpl::SVGMetadataElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl)
+{
+}
+
+SVGMetadataElementImpl::~SVGMetadataElementImpl()
+{
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGMetadataElementImpl.h b/ksvg/impl/SVGMetadataElementImpl.h
new file mode 100644
index 00000000..363a9c11
--- /dev/null
+++ b/ksvg/impl/SVGMetadataElementImpl.h
@@ -0,0 +1,46 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGMetadataElementImpl_H
+#define SVGMetadataElementImpl_H
+
+#include "SVGElementImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGMetadataElementImpl : public SVGElementImpl
+{
+public:
+ SVGMetadataElementImpl(DOM::ElementImpl *);
+ virtual ~SVGMetadataElementImpl();
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGMissingGlyphElementImpl.cc b/ksvg/impl/SVGMissingGlyphElementImpl.cc
new file mode 100644
index 00000000..986750c3
--- /dev/null
+++ b/ksvg/impl/SVGMissingGlyphElementImpl.cc
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGMissingGlyphElementImpl.h"
+
+using namespace KSVG;
+
+SVGMissingGlyphElementImpl::SVGMissingGlyphElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGStylableImpl(this)
+{
+}
+
+SVGMissingGlyphElementImpl::~SVGMissingGlyphElementImpl()
+{
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGMissingGlyphElementImpl.h b/ksvg/impl/SVGMissingGlyphElementImpl.h
new file mode 100644
index 00000000..275aba86
--- /dev/null
+++ b/ksvg/impl/SVGMissingGlyphElementImpl.h
@@ -0,0 +1,47 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGMissingGlyphElementImpl_H
+#define SVGMissingGlyphElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGElementImpl.h"
+#include "SVGStylableImpl.h"
+
+namespace KSVG
+{
+
+class SVGMissingGlyphElementImpl : public SVGElementImpl,
+ public SVGStylableImpl
+{
+public:
+ SVGMissingGlyphElementImpl(DOM::ElementImpl *);
+ virtual ~SVGMissingGlyphElementImpl();
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGNumberImpl.cc b/ksvg/impl/SVGNumberImpl.cc
new file mode 100644
index 00000000..b926e9c2
--- /dev/null
+++ b/ksvg/impl/SVGNumberImpl.cc
@@ -0,0 +1,83 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGNumberImpl.h"
+
+using namespace KSVG;
+
+#include "SVGNumberImpl.lut.h"
+#include "ksvg_bridge.h"
+
+SVGNumberImpl::SVGNumberImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_value = 0;
+}
+
+SVGNumberImpl::~SVGNumberImpl()
+{
+}
+
+void SVGNumberImpl::setValue(float value)
+{
+ m_value = value;
+}
+
+float SVGNumberImpl::value()
+{
+ return m_value;
+}
+
+/*
+@namespace KSVG
+@begin SVGNumberImpl::s_hashTable 2
+ value SVGNumberImpl::Value DontDelete
+@end
+*/
+
+Value SVGNumberImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case Value:
+ return Number(m_value);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+
+ return Undefined();
+}
+
+void SVGNumberImpl::putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int)
+{
+ switch(token)
+ {
+ case Value:
+ m_value = value.toNumber(exec);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGNumberImpl.h b/ksvg/impl/SVGNumberImpl.h
new file mode 100644
index 00000000..d94b3d63
--- /dev/null
+++ b/ksvg/impl/SVGNumberImpl.h
@@ -0,0 +1,61 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGNumberImpl_H
+#define SVGNumberImpl_H
+
+#include <dom/dom_misc.h>
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGNumberImpl : public DOM::DomShared
+{
+public:
+ SVGNumberImpl();
+ virtual ~SVGNumberImpl();
+
+ void setValue(float value);
+ float value();
+
+private:
+ float m_value;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ Value
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGNumberListImpl.cc b/ksvg/impl/SVGNumberListImpl.cc
new file mode 100644
index 00000000..8048640c
--- /dev/null
+++ b/ksvg/impl/SVGNumberListImpl.cc
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGNumberListImpl.h"
+
+using namespace KSVG;
+
+#include "SVGNumberListImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGNumberListImpl::s_hashTable 2
+ numberOfItems SVGListDefs::NumberOfItems DontDelete|ReadOnly
+@end
+@namespace KSVG
+@begin SVGNumberListImplProto::s_hashTable 11
+ getItem SVGListDefs::GetItem DontDelete|Function 1
+ removeItem SVGListDefs::RemoveItem DontDelete|Function 1
+ appendItem SVGListDefs::AppendItem DontDelete|Function 1
+ initialize SVGListDefs::Initialize DontDelete|Function 1
+ insertItemBefore SVGListDefs::InsertItemBefore DontDelete|Function 2
+ replaceItem SVGListDefs::ReplaceItem DontDelete|Function 2
+ clear SVGListDefs::Clear DontDelete|Function 0
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGNumberList", SVGNumberListImplProto, SVGNumberListImplProtoFunc)
+
+Value SVGNumberListImpl::getValueProperty(ExecState *exec, int token) const
+{
+ return SVGList<SVGNumberImpl>::getValueProperty(exec, token);
+}
+
+Value SVGNumberListImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGNumberListImpl)
+
+ return obj->call(exec, static_cast<SVGList<SVGNumberImpl> *>(obj), args, id);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGNumberListImpl.h b/ksvg/impl/SVGNumberListImpl.h
new file mode 100644
index 00000000..87dadb6f
--- /dev/null
+++ b/ksvg/impl/SVGNumberListImpl.h
@@ -0,0 +1,48 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGNumberListImpl_H
+#define SVGNumberListImpl_H
+
+#include "SVGList.h"
+
+#include "SVGNumberImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGNumberListImpl : public SVGList<SVGNumberImpl>
+{
+public:
+ KSVG_GET
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+};
+
+}
+
+KSVG_DEFINE_PROTOTYPE(SVGNumberListImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGNumberListImplProtoFunc, SVGNumberListImpl)
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPaintImpl.cc b/ksvg/impl/SVGPaintImpl.cc
new file mode 100644
index 00000000..c1818892
--- /dev/null
+++ b/ksvg/impl/SVGPaintImpl.cc
@@ -0,0 +1,175 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGPaint.h"
+#include "SVGColor.h"
+
+#include "SVGPaintImpl.h"
+
+using namespace KSVG;
+
+#include "SVGPaintImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_cacheimpl.h"
+
+SVGPaintImpl::SVGPaintImpl(SVGElementImpl *object) : SVGColorImpl(object)
+{
+ m_paintType = SVG_PAINTTYPE_UNKNOWN;
+}
+
+SVGPaintImpl::SVGPaintImpl(const SVGPaintImpl &other) : SVGColorImpl(other)
+{
+ (*this) = other;
+}
+
+SVGPaintImpl::~SVGPaintImpl()
+{
+}
+
+SVGPaintImpl &SVGPaintImpl::operator=(const SVGPaintImpl &other)
+{
+ m_uri = other.m_uri;
+ m_paintType = other.m_paintType;
+
+ *(static_cast<SVGColorImpl *>(this)) = other;
+
+ return *this;
+}
+
+unsigned short SVGPaintImpl::paintType() const
+{
+ return m_paintType;
+}
+
+DOM::DOMString SVGPaintImpl::uri() const
+{
+ return m_uri;
+}
+
+void SVGPaintImpl::setUri(const DOM::DOMString &uri)
+{
+ m_uri = uri;
+ m_paintType = SVG_PAINTTYPE_URI;
+}
+
+void SVGPaintImpl::setPaint(unsigned short paintType, const DOM::DOMString &/*uri*/, const DOM::DOMString &/*rgbColor*/, const DOM::DOMString &/*iccColor*/)
+{
+ m_paintType = paintType;
+}
+
+void SVGPaintImpl::setRGBColor(QColor color)
+{
+ m_paintType = SVG_PAINTTYPE_RGBCOLOR;
+ SVGColorImpl::setRGBColor(color);
+}
+
+void SVGPaintImpl::setRGBColor(int r, int g, int b)
+{
+ m_paintType = SVG_PAINTTYPE_RGBCOLOR;
+ SVGColorImpl::setRGBColor(r, g, b);
+}
+
+void SVGPaintImpl::setRGBColor(const DOM::DOMString &rgbColor)
+{
+ m_paintType = SVG_PAINTTYPE_RGBCOLOR;
+ SVGColorImpl::setRGBColor(rgbColor);
+}
+
+void SVGPaintImpl::setRGBColorICCColor(const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor)
+{
+ m_paintType = SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR;
+ SVGColorImpl::setRGBColorICCColor(rgbColor, iccColor);
+}
+
+void SVGPaintImpl::setColor(unsigned short colorType, const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor)
+{
+ SVGColorImpl::setColor(colorType, rgbColor, iccColor);
+
+ switch(colorType)
+ {
+ case SVG_COLORTYPE_CURRENTCOLOR:
+ m_paintType = SVG_PAINTTYPE_CURRENTCOLOR;
+ break;
+ case SVG_COLORTYPE_RGBCOLOR:
+ m_paintType = SVG_PAINTTYPE_CURRENTCOLOR;
+ break;
+ case SVG_COLORTYPE_RGBCOLOR_ICCCOLOR:
+ m_paintType = SVG_PAINTTYPE_CURRENTCOLOR;
+ break;
+ case SVG_COLORTYPE_UNKNOWN:
+ m_paintType = SVG_PAINTTYPE_UNKNOWN;
+ break;
+ }
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPaintImpl::s_hashTable 3
+ paintType SVGPaintImpl::PaintType DontDelete
+ uri SVGPaintImpl::URI DontDelete
+@end
+*/
+
+Value SVGPaintImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case PaintType:
+ return Number(paintType());
+ case URI:
+ return String(uri().string());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+/*
+@namespace KSVG
+@begin SVGPaintImplConstructor::s_hashTable 11
+SVG_PAINTTYPE_UNKNOWN KSVG::SVG_PAINTTYPE_UNKNOWN DontDelete|ReadOnly
+SVG_PAINTTYPE_CURRENTCOLOR KSVG::SVG_PAINTTYPE_CURRENTCOLOR DontDelete|ReadOnly
+SVG_PAINTTYPE_RGBCOLOR KSVG::SVG_PAINTTYPE_RGBCOLOR DontDelete|ReadOnly
+SVG_PAINTTYPE_RGBCOLOR KSVG::SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR DontDelete|ReadOnly
+SVG_PAINTTYPE_NONE KSVG::SVG_PAINTTYPE_NONE DontDelete|ReadOnly
+SVG_PAINTTYPE_URI_NONE KSVG::SVG_PAINTTYPE_URI_NONE DontDelete|ReadOnly
+SVG_PAINTTYPE_URI_RGBCOLOR KSVG::SVG_PAINTTYPE_URI_RGBCOLOR DontDelete|ReadOnly
+SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR KSVG::SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR DontDelete|ReadOnly
+SVG_PAINTTYPE_URI_CURRENTCOLOR KSVG::SVG_PAINTTYPE_URI_CURRENTCOLOR DontDelete|ReadOnly
+SVG_PAINTTYPE_URI KSVG::SVG_PAINTTYPE_URI DontDelete|ReadOnly
+@end
+*/
+
+Value SVGPaintImplConstructor::getValueProperty(ExecState *, int token) const
+{
+ return Number(token);
+}
+
+Value KSVG::getSVGPaintImplConstructor(ExecState *exec)
+{
+ return cacheGlobalBridge<SVGPaintImplConstructor>(exec, "[[svgpaint.constructor]]");
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPaintImpl.h b/ksvg/impl/SVGPaintImpl.h
new file mode 100644
index 00000000..f2aa0691
--- /dev/null
+++ b/ksvg/impl/SVGPaintImpl.h
@@ -0,0 +1,85 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPaintImpl_H
+#define SVGPaintImpl_H
+
+#include <dom/dom_string.h>
+
+#include "ksvg_lookup.h"
+
+#include "SVGColorImpl.h"
+
+namespace KSVG
+{
+
+class SVGPaintImpl : public SVGColorImpl
+{
+public:
+ SVGPaintImpl(SVGElementImpl *object);
+ SVGPaintImpl(const SVGPaintImpl &);
+ virtual ~SVGPaintImpl();
+
+ SVGPaintImpl &operator=(const SVGPaintImpl &);
+
+ unsigned short paintType() const;
+ DOM::DOMString uri() const;
+ void setUri(const DOM::DOMString &uri);
+ void setPaint(unsigned short paintType, const DOM::DOMString &uri = "", const DOM::DOMString &rgbColor = "", const DOM::DOMString &iccColor = "");
+
+ virtual void setRGBColor(const DOM::DOMString &rgbColor);
+ virtual void setRGBColor(int r, int g, int b);
+ virtual void setRGBColor(QColor color);
+ virtual void setRGBColorICCColor(const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor);
+ virtual void setColor(unsigned short colorType, const DOM::DOMString &rgbColor, const DOM::DOMString &iccColor);
+
+private:
+ unsigned short m_paintType;
+ DOM::DOMString m_uri;
+
+public:
+ KSVG_GET
+
+ enum
+ {
+ // Properties
+ PaintType, URI
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+};
+
+class SVGPaintImplConstructor : public KJS::ObjectImp
+{
+public:
+ SVGPaintImplConstructor(KJS::ExecState *) { }
+ KJS::Value getValueProperty(KJS::ExecState *, int token) const;
+
+ // no put - all read-only
+ KSVG_GET
+};
+
+KJS::Value getSVGPaintImplConstructor(KJS::ExecState *exec);
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPaintServerImpl.cc b/ksvg/impl/SVGPaintServerImpl.cc
new file mode 100644
index 00000000..b3275231
--- /dev/null
+++ b/ksvg/impl/SVGPaintServerImpl.cc
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGPaintServerImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+
+using namespace KSVG;
+
+SVGPaintServerImpl::SVGPaintServerImpl()
+{
+ m_paintServer = 0;
+}
+
+SVGPaintServerImpl::~SVGPaintServerImpl()
+{
+}
+
+CanvasPaintServer *SVGPaintServerImpl::paintServer(SVGDocumentImpl *doc, const QString& id)
+{
+ CanvasPaintServer *pserver = 0;
+ SVGElementImpl *element = doc->rootElement()->getElementById(id);
+
+ if(element)
+ {
+ SVGPaintServerImpl *paintServerElement = dynamic_cast<SVGPaintServerImpl *>(element);
+
+ if(paintServerElement)
+ pserver = paintServerElement->paintServer();
+ }
+
+ return pserver;
+}
+
+// vim:ts=4:noet
+
diff --git a/ksvg/impl/SVGPaintServerImpl.h b/ksvg/impl/SVGPaintServerImpl.h
new file mode 100644
index 00000000..df276758
--- /dev/null
+++ b/ksvg/impl/SVGPaintServerImpl.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPaintServerImpl_H
+#define SVGPaintServerImpl_H
+
+namespace KSVG
+{
+
+class SVGDocumentImpl;
+
+class CanvasPaintServer;
+
+class SVGPaintServerImpl
+{
+public:
+ SVGPaintServerImpl();
+ virtual ~SVGPaintServerImpl();
+
+ CanvasPaintServer *paintServer() { return m_paintServer; }
+
+ static CanvasPaintServer *paintServer(SVGDocumentImpl *doc, const QString& id);
+
+protected:
+ CanvasPaintServer *m_paintServer;
+
+private:
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
+
diff --git a/ksvg/impl/SVGPathElementImpl.cc b/ksvg/impl/SVGPathElementImpl.cc
new file mode 100644
index 00000000..f34600b8
--- /dev/null
+++ b/ksvg/impl/SVGPathElementImpl.cc
@@ -0,0 +1,868 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <math.h>
+#include <cfloat>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "SVGRectImpl.h"
+#include "SVGPaintImpl.h"
+#include "SVGPointImpl.h"
+#include "SVGAngleImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGPathSegArcImpl.h"
+#include "SVGPathSegListImpl.h"
+#include "SVGPathElementImpl.h"
+#include "SVGPathSegLinetoImpl.h"
+#include "SVGPathSegMovetoImpl.h"
+#include "SVGAnimatedNumberImpl.h"
+#include "SVGPathSegClosePathImpl.h"
+#include "SVGPathSegCurvetoCubicImpl.h"
+#include "SVGPathSegLinetoVerticalImpl.h"
+#include "SVGPathSegLinetoHorizontalImpl.h"
+#include "SVGPathSegCurvetoQuadraticImpl.h"
+#include "SVGPathSegCurvetoCubicSmoothImpl.h"
+#include "SVGPathSegCurvetoQuadraticSmoothImpl.h"
+
+#include "SVGPaint.h"
+
+#include "CanvasItem.h"
+#include "KSVGCanvas.h"
+#include "BezierPath.h"
+#include "Point.h"
+
+using namespace KSVG;
+
+#include "SVGPathElementImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+
+SVGPathElementImpl::SVGPathElementImpl(DOM::ElementImpl *impl) : SVGShapeImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl(), SVGAnimatedPathDataImpl(), SVGPathParser()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_pathLength = new SVGAnimatedNumberImpl();
+ m_pathLength->ref();
+
+ m_pathLength->setBaseVal(0);
+}
+
+SVGPathElementImpl::~SVGPathElementImpl()
+{
+ pathSegList()->clear();
+
+ if(m_pathLength)
+ m_pathLength->deref();
+}
+
+SVGAnimatedNumberImpl *SVGPathElementImpl::pathLength() const
+{
+ return m_pathLength;
+}
+
+double SVGPathElementImpl::getTotalLength()
+{
+ T2P::BezierPath *path = ownerDoc()->canvas()->toBezierPath(m_item);
+ if(path)
+ return path->length();
+
+ return 0;
+}
+
+SVGPointImpl *SVGPathElementImpl::getPointAtLength(double distance)
+{
+ SVGPointImpl *ret = SVGSVGElementImpl::createSVGPoint();
+ double totalDistance = getTotalLength();
+ T2P::BezierPath *path = ownerDoc()->canvas()->toBezierPath(m_item);
+ if(path)
+ {
+ T2P::Point p;
+ path->pointTangentNormalAt(distance / totalDistance, &p);
+ ret->setX(p.x());
+ ret->setY(p.y());
+ }
+
+ return ret;
+}
+
+unsigned long SVGPathElementImpl::getPathSegAtLength(double)
+{
+ return 0;
+}
+
+SVGPathSegClosePathImpl *SVGPathElementImpl::createSVGPathSegClosePath()
+{
+ SVGPathSegClosePathImpl *temp = new SVGPathSegClosePathImpl();
+ temp->ref();
+
+ return temp;
+}
+
+SVGPathSegMovetoAbsImpl *SVGPathElementImpl::createSVGPathSegMovetoAbs(double x, double y)
+{
+ SVGPathSegMovetoAbsImpl *temp = new SVGPathSegMovetoAbsImpl();
+ temp->ref();
+
+ temp->setX(x);
+ temp->setY(y);
+ return temp;
+}
+
+SVGPathSegMovetoRelImpl *SVGPathElementImpl::createSVGPathSegMovetoRel(double x, double y)
+{
+ SVGPathSegMovetoRelImpl *temp = new SVGPathSegMovetoRelImpl();
+ temp->ref();
+
+ temp->setX(x);
+ temp->setY(y);
+ return temp;
+}
+
+SVGPathSegLinetoAbsImpl *SVGPathElementImpl::createSVGPathSegLinetoAbs(double x, double y)
+{
+ SVGPathSegLinetoAbsImpl *temp = new SVGPathSegLinetoAbsImpl();
+ temp->ref();
+
+ temp->setX(x);
+ temp->setY(y);
+ return temp;
+}
+
+SVGPathSegLinetoRelImpl *SVGPathElementImpl::createSVGPathSegLinetoRel(double x, double y)
+{
+ SVGPathSegLinetoRelImpl *temp = new SVGPathSegLinetoRelImpl();
+ temp->ref();
+
+ temp->setX(x);
+ temp->setY(y);
+ return temp;
+}
+
+SVGPathSegCurvetoCubicAbsImpl *SVGPathElementImpl::createSVGPathSegCurvetoCubicAbs(double x, double y, double x1, double y1, double x2, double y2)
+{
+ SVGPathSegCurvetoCubicAbsImpl *temp = new SVGPathSegCurvetoCubicAbsImpl();
+ temp->ref();
+
+ temp->setX(x);
+ temp->setY(y);
+ temp->setX1(x1);
+ temp->setY1(y1);
+ temp->setX2(x2);
+ temp->setY2(y2);
+ return temp;
+}
+
+SVGPathSegCurvetoCubicRelImpl *SVGPathElementImpl::createSVGPathSegCurvetoCubicRel(double x, double y, double x1, double y1, double x2, double y2)
+{
+ SVGPathSegCurvetoCubicRelImpl *temp = new SVGPathSegCurvetoCubicRelImpl();
+ temp->ref();
+
+ temp->setX(x);
+ temp->setY(y);
+ temp->setX1(x1);
+ temp->setY1(y1);
+ temp->setX2(x2);
+ temp->setY2(y2);
+ return temp;
+}
+
+SVGPathSegCurvetoQuadraticAbsImpl *SVGPathElementImpl::createSVGPathSegCurvetoQuadraticAbs(double x, double y, double x1, double y1)
+{
+ SVGPathSegCurvetoQuadraticAbsImpl *temp = new SVGPathSegCurvetoQuadraticAbsImpl();
+ temp->ref();
+
+ temp->setX(x);
+ temp->setY(y);
+ temp->setX1(x1);
+ temp->setY1(y1);
+ return temp;
+}
+
+SVGPathSegCurvetoQuadraticRelImpl *SVGPathElementImpl::createSVGPathSegCurvetoQuadraticRel(double x, double y, double x1, double y1)
+{
+ SVGPathSegCurvetoQuadraticRelImpl *temp = new SVGPathSegCurvetoQuadraticRelImpl();
+ temp->ref();
+
+ temp->setX(x);
+ temp->setY(y);
+ temp->setX1(x1);
+ temp->setY1(y1);
+ return temp;
+}
+
+SVGPathSegArcAbsImpl *SVGPathElementImpl::createSVGPathSegArcAbs(double x, double y, double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag)
+{
+ SVGPathSegArcAbsImpl *temp = new SVGPathSegArcAbsImpl();
+ temp->ref();
+
+ temp->setX(x);
+ temp->setY(y);
+ temp->setR1(r1);
+ temp->setR2(r2);
+ temp->setAngle(angle);
+ temp->setLargeArcFlag(largeArcFlag);
+ temp->setSweepFlag(sweepFlag);
+ return temp;
+}
+
+SVGPathSegArcRelImpl *SVGPathElementImpl::createSVGPathSegArcRel(double x, double y, double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag)
+{
+ SVGPathSegArcRelImpl *temp = new SVGPathSegArcRelImpl();
+ temp->ref();
+
+ temp->setX(x);
+ temp->setY(y);
+ temp->setR1(r1);
+ temp->setR2(r2);
+ temp->setAngle(angle);
+ temp->setLargeArcFlag(largeArcFlag);
+ temp->setSweepFlag(sweepFlag);
+ return temp;
+}
+
+SVGPathSegLinetoHorizontalAbsImpl *SVGPathElementImpl::createSVGPathSegLinetoHorizontalAbs(double x)
+{
+ SVGPathSegLinetoHorizontalAbsImpl *temp = new SVGPathSegLinetoHorizontalAbsImpl();
+ temp->ref();
+
+ temp->setX(x);
+ return temp;
+}
+
+SVGPathSegLinetoHorizontalRelImpl *SVGPathElementImpl::createSVGPathSegLinetoHorizontalRel(double x)
+{
+ SVGPathSegLinetoHorizontalRelImpl *temp = new SVGPathSegLinetoHorizontalRelImpl();
+ temp->ref();
+
+ temp->setX(x);
+ return temp;
+}
+
+SVGPathSegLinetoVerticalAbsImpl *SVGPathElementImpl::createSVGPathSegLinetoVerticalAbs(double y)
+{
+ SVGPathSegLinetoVerticalAbsImpl *temp = new SVGPathSegLinetoVerticalAbsImpl();
+ temp->ref();
+
+ temp->setY(y);
+ return temp;
+}
+
+SVGPathSegLinetoVerticalRelImpl *SVGPathElementImpl::createSVGPathSegLinetoVerticalRel(double y)
+{
+ SVGPathSegLinetoVerticalRelImpl *temp = new SVGPathSegLinetoVerticalRelImpl();
+ temp->ref();
+
+ temp->setY(y);
+ return temp;
+}
+
+SVGPathSegCurvetoCubicSmoothAbsImpl *SVGPathElementImpl::createSVGPathSegCurvetoCubicSmoothAbs(double x, double y, double x2, double y2)
+{
+ SVGPathSegCurvetoCubicSmoothAbsImpl *temp = new SVGPathSegCurvetoCubicSmoothAbsImpl();
+ temp->ref();
+
+ temp->setX(x);
+ temp->setY(y);
+ temp->setX2(x2);
+ temp->setY2(y2);
+ return temp;
+}
+
+SVGPathSegCurvetoCubicSmoothRelImpl *SVGPathElementImpl::createSVGPathSegCurvetoCubicSmoothRel(double x, double y, double x2, double y2)
+{
+ SVGPathSegCurvetoCubicSmoothRelImpl *temp = new SVGPathSegCurvetoCubicSmoothRelImpl();
+ temp->ref();
+
+ temp->setX(x);
+ temp->setY(y);
+ temp->setX2(x2);
+ temp->setY2(y2);
+ return temp;
+}
+
+SVGPathSegCurvetoQuadraticSmoothAbsImpl *SVGPathElementImpl::createSVGPathSegCurvetoQuadraticSmoothAbs(double x, double y)
+{
+ SVGPathSegCurvetoQuadraticSmoothAbsImpl *temp = new SVGPathSegCurvetoQuadraticSmoothAbsImpl();
+ temp->ref();
+
+ temp->setX(x);
+ temp->setY(y);
+ return temp;
+}
+
+SVGPathSegCurvetoQuadraticSmoothRelImpl *SVGPathElementImpl::createSVGPathSegCurvetoQuadraticSmoothRel(double x, double y)
+{
+ SVGPathSegCurvetoQuadraticSmoothRelImpl *temp = new SVGPathSegCurvetoQuadraticSmoothRelImpl();
+ temp->ref();
+
+ temp->setX(x);
+ temp->setY(y);
+ return temp;
+}
+
+void SVGPathElementImpl::svgMoveTo(double x1, double y1, bool, bool abs)
+{
+ if(abs)
+ pathSegList()->appendItem(createSVGPathSegMovetoAbs(x1, y1));
+ else
+ pathSegList()->appendItem(createSVGPathSegMovetoRel(x1, y1));
+}
+
+void SVGPathElementImpl::svgLineTo(double x1, double y1, bool abs)
+{
+ if(abs)
+ pathSegList()->appendItem(createSVGPathSegLinetoAbs(x1, y1));
+ else
+ pathSegList()->appendItem(createSVGPathSegLinetoRel(x1, y1));
+}
+
+void SVGPathElementImpl::svgLineToHorizontal(double x, bool abs)
+{
+ if(abs)
+ pathSegList()->appendItem(createSVGPathSegLinetoHorizontalAbs(x));
+ else
+ pathSegList()->appendItem(createSVGPathSegLinetoHorizontalRel(x));
+}
+
+void SVGPathElementImpl::svgLineToVertical(double y, bool abs)
+{
+ if(abs)
+ pathSegList()->appendItem(createSVGPathSegLinetoVerticalAbs(y));
+ else
+ pathSegList()->appendItem(createSVGPathSegLinetoVerticalRel(y));
+}
+
+void SVGPathElementImpl::svgCurveToCubic(double x1, double y1, double x2, double y2, double x, double y, bool abs)
+{
+ if(abs)
+ pathSegList()->appendItem(createSVGPathSegCurvetoCubicAbs(x, y, x1, y1, x2, y2));
+ else
+ pathSegList()->appendItem(createSVGPathSegCurvetoCubicRel(x, y, x1, y1, x2, y2));
+}
+
+void SVGPathElementImpl::svgCurveToCubicSmooth(double x, double y, double x2, double y2, bool abs)
+{
+ if(abs)
+ pathSegList()->appendItem(createSVGPathSegCurvetoCubicSmoothAbs(x2, y2, x, y));
+ else
+ pathSegList()->appendItem(createSVGPathSegCurvetoCubicSmoothRel(x2, y2, x, y));
+}
+
+void SVGPathElementImpl::svgCurveToQuadratic(double x, double y, double x1, double y1, bool abs)
+{
+ if(abs)
+ pathSegList()->appendItem(createSVGPathSegCurvetoQuadraticAbs(x1, y1, x, y));
+ else
+ pathSegList()->appendItem(createSVGPathSegCurvetoQuadraticRel(x1, y1, x, y));
+}
+
+void SVGPathElementImpl::svgCurveToQuadraticSmooth(double x, double y, bool abs)
+{
+ if(abs)
+ pathSegList()->appendItem(createSVGPathSegCurvetoQuadraticSmoothAbs(x, y));
+ else
+ pathSegList()->appendItem(createSVGPathSegCurvetoQuadraticSmoothRel(x, y));
+}
+
+void SVGPathElementImpl::svgArcTo(double x, double y, double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag, bool abs)
+{
+ if(abs)
+ pathSegList()->appendItem(createSVGPathSegArcAbs(x, y, r1, r2, angle, largeArcFlag, sweepFlag));
+ else
+ pathSegList()->appendItem(createSVGPathSegArcRel(x, y, r1, r2, angle, largeArcFlag, sweepFlag));
+}
+
+void SVGPathElementImpl::svgClosePath()
+{
+ pathSegList()->appendItem(createSVGPathSegClosePath());
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPathElementImpl::s_hashTable 3
+ d SVGPathElementImpl::D DontDelete|ReadOnly
+ pathLength SVGPathElementImpl::PathLength DontDelete|ReadOnly
+@end
+@namespace KSVG
+@begin SVGPathElementImplProto::s_hashTable 23
+ getTotalLength SVGPathElementImpl::GetTotalLength DontDelete|Function 0
+ getPointAtLength SVGPathElementImpl::GetPointAtLength DontDelete|Function 1
+ getPathSegAtLength SVGPathElementImpl::GetPathSegAtLength DontDelete|Function 1
+ createSVGPathSegClosePath SVGPathElementImpl::CreateSVGPathSegClosePath DontDelete|Function 0
+ createSVGPathSegMovetoAbs SVGPathElementImpl::CreateSVGPathSegMovetoAbs DontDelete|Function 2
+ createSVGPathSegMovetoRel SVGPathElementImpl::CreateSVGPathSegMovetoRel DontDelete|Function 2
+ createSVGPathSegLinetoAbs SVGPathElementImpl::CreateSVGPathSegLinetoAbs DontDelete|Function 2
+ createSVGPathSegLinetoRel SVGPathElementImpl::CreateSVGPathSegLinetoRel DontDelete|Function 2
+ createSVGPathSegArcAbs SVGPathElementImpl::CreateSVGPathSegArcAbs DontDelete|Function 7
+ createSVGPathSegArcRel SVGPathElementImpl::CreateSVGPathSegArcRel DontDelete|Function 7
+ createSVGPathSegCurvetoCubicAbs SVGPathElementImpl::CreateSVGPathSegCurvetoCubicAbs DontDelete|Function 6
+ createSVGPathSegCurvetoCubicRel SVGPathElementImpl::CreateSVGPathSegCurvetoCubicRel DontDelete|Function 6
+ createSVGPathSegCurvetoQuadraticAbs SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticAbs DontDelete|Function 4
+ createSVGPathSegCurvetoQuadraticRel SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticRel DontDelete|Function 4
+ createSVGPathSegLinetoHorizontalAbs SVGPathElementImpl::CreateSVGPathSegLinetoHorizontalAbs DontDelete|Function 1
+ createSVGPathSegLinetoHorizontalRel SVGPathElementImpl::CreateSVGPathSegLinetoHorizontalRel DontDelete|Function 1
+ createSVGPathSegLinetoVerticalAbs SVGPathElementImpl::CreateSVGPathSegLinetoVerticalAbs DontDelete|Function 1
+ createSVGPathSegLinetoVerticalRel SVGPathElementImpl::CreateSVGPathSegLinetoVerticalRel DontDelete|Function 1
+ createSVGPathSegCurvetoCubicAbs SVGPathElementImpl::CreateSVGPathSegCurvetoCubicAbs DontDelete|Function 4
+ createSVGPathSegCurvetoCubicRel SVGPathElementImpl::CreateSVGPathSegCurvetoCubicRel DontDelete|Function 4
+ createSVGPathSegCurvetoQuadraticAbs SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticAbs DontDelete|Function 2
+ createSVGPathSegCurvetoQuadraticRel SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticRel DontDelete|Function 2
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGPathElementImpl", SVGPathElementImplProto, SVGPathElementImplProtoFunc)
+
+Value SVGPathElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ //KSVG_CHECK_ATTRIBUTE
+
+ switch(token)
+ {
+ case PathLength:
+ return m_pathLength->cache(exec);
+ case D:
+// if(!attributeMode)
+ {
+ QString d;
+ unsigned int nrSegs = pathSegList()->numberOfItems();
+ SVGPathSegImpl *curseg = 0;
+ for(unsigned int i = 0; i < nrSegs; i++)
+ {
+ curseg = pathSegList()->getItem(i);
+ if(curseg)
+ d += curseg->toString() + " ";
+ }
+ return String(d);
+ }
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGPathElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case D:
+ {
+ pathSegList()->clear();
+ QString d = value.toString(exec).qstring();
+ parseSVG(d, false);
+ if(hasMarkers())
+ m_markerData = MarkerData(pathSegList());
+ break;
+ }
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+Value SVGPathElementImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGPathElementImpl)
+
+ switch(id)
+ {
+ case SVGPathElementImpl::GetTotalLength:
+ return Number(obj->getTotalLength());
+ case SVGPathElementImpl::GetPointAtLength:
+ return obj->getPointAtLength(args[0].toNumber(exec))->cache(exec);
+ case SVGPathElementImpl::GetPathSegAtLength:
+ return Number(obj->getPathSegAtLength(args[0].toNumber(exec)));
+ case SVGPathElementImpl::CreateSVGPathSegClosePath:
+ return obj->createSVGPathSegClosePath()->cache(exec);
+ case SVGPathElementImpl::CreateSVGPathSegMovetoAbs:
+ return obj->createSVGPathSegMovetoAbs(args[0].toNumber(exec), args[1].toNumber(exec))->cache(exec);
+ case SVGPathElementImpl::CreateSVGPathSegMovetoRel:
+ return obj->createSVGPathSegMovetoRel(args[0].toNumber(exec), args[1].toNumber(exec))->cache(exec);
+ case SVGPathElementImpl::CreateSVGPathSegLinetoAbs:
+ return obj->createSVGPathSegLinetoAbs(args[0].toNumber(exec), args[1].toNumber(exec))->cache(exec);
+ case SVGPathElementImpl::CreateSVGPathSegLinetoRel:
+ return obj->createSVGPathSegLinetoRel(args[0].toNumber(exec), args[1].toNumber(exec))->cache(exec);
+ case SVGPathElementImpl::CreateSVGPathSegCurvetoCubicAbs:
+ return obj->createSVGPathSegCurvetoCubicAbs(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec), args[3].toNumber(exec), args[4].toNumber(exec), args[5].toNumber(exec))->cache(exec);
+ case SVGPathElementImpl::CreateSVGPathSegCurvetoCubicRel:
+ return obj->createSVGPathSegCurvetoCubicRel(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec), args[3].toNumber(exec), args[4].toNumber(exec), args[5].toNumber(exec))->cache(exec);
+ case SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticAbs:
+ return obj->createSVGPathSegCurvetoQuadraticAbs(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec), args[3].toNumber(exec))->cache(exec);
+ case SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticRel:
+ return obj->createSVGPathSegCurvetoQuadraticRel(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec), args[3].toNumber(exec))->cache(exec);
+ case SVGPathElementImpl::CreateSVGPathSegArcAbs:
+ return obj->createSVGPathSegArcAbs(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec), args[3].toNumber(exec), args[4].toNumber(exec), args[5].toBoolean(exec), args[6].toBoolean(exec))->cache(exec);
+ case SVGPathElementImpl::CreateSVGPathSegArcRel:
+ return obj->createSVGPathSegArcRel(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec), args[3].toNumber(exec), args[4].toNumber(exec), args[5].toBoolean(exec), args[6].toBoolean(exec))->cache(exec);
+ case SVGPathElementImpl::CreateSVGPathSegLinetoHorizontalAbs:
+ return obj->createSVGPathSegLinetoHorizontalAbs(args[0].toNumber(exec))->cache(exec);
+ case SVGPathElementImpl::CreateSVGPathSegLinetoHorizontalRel:
+ return obj->createSVGPathSegLinetoHorizontalRel(args[0].toNumber(exec))->cache(exec);
+ case SVGPathElementImpl::CreateSVGPathSegLinetoVerticalAbs:
+ return obj->createSVGPathSegLinetoVerticalAbs(args[0].toNumber(exec))->cache(exec);
+ case SVGPathElementImpl::CreateSVGPathSegLinetoVerticalRel:
+ return obj->createSVGPathSegLinetoVerticalRel(args[0].toNumber(exec))->cache(exec);
+ case SVGPathElementImpl::CreateSVGPathSegCurvetoCubicSmoothAbs:
+ return obj->createSVGPathSegCurvetoCubicSmoothAbs(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec), args[3].toNumber(exec))->cache(exec);
+ case SVGPathElementImpl::CreateSVGPathSegCurvetoCubicSmoothRel:
+ return obj->createSVGPathSegCurvetoCubicSmoothRel(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec), args[3].toNumber(exec))->cache(exec);
+ case SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticSmoothAbs:
+ return obj->createSVGPathSegCurvetoQuadraticSmoothAbs(args[0].toNumber(exec), args[1].toNumber(exec))->cache(exec);
+ case SVGPathElementImpl::CreateSVGPathSegCurvetoQuadraticSmoothRel:
+ return obj->createSVGPathSegCurvetoQuadraticSmoothRel(args[0].toNumber(exec), args[1].toNumber(exec))->cache(exec);
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return Undefined();
+}
+
+SVGRectImpl *SVGPathElementImpl::getBBox()
+{
+ SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect();
+
+ if(m_item)
+ {
+ T2P::BezierPath *path = ownerDoc()->canvas()->toBezierPath(m_item);
+ if(path)
+ {
+ T2P::Point topLeft;
+ T2P::Point bottomRight;
+
+ path->boundingBox(&topLeft, &bottomRight);
+
+ ret->setX(topLeft.x());
+ ret->setY(topLeft.y());
+ ret->setWidth(bottomRight.x() - topLeft.x());
+ ret->setHeight(bottomRight.y() - topLeft.y());
+ }
+ }
+ return ret;
+}
+
+void SVGPathElementImpl::createItem(KSVGCanvas *c)
+{
+ if(!c)
+ c = ownerDoc()->canvas();
+
+ if(!m_item)
+ {
+ // TODO : this is a quick fix for this problem:
+ // d attribute encountered before marker attributes.
+ // Try to process the attributes in the right order, ie.
+ // d attr processing should be last.
+ if(hasMarkers() && m_markerData.numMarkers() == 0)
+ m_markerData = MarkerData(pathSegList());
+ m_item = c->createPath(this);
+ c->insert(m_item);
+ }
+}
+
+SVGPathElementImpl::MarkerData::MarkerData(SVGPathSegListImpl *path)
+{
+ unsigned int numSegments = path->numberOfItems();
+ double curx = 0;
+ double cury = 0;
+ int currentSubpathStartIndex = -1;
+ double previousQuadraticX1 = 0;
+ double previousQuadraticY1 = 0;
+ double previousCubicX2 = 0;
+ double previousCubicY2 = 0;
+
+ QValueVector<SegmentData> pathSegmentData(numSegments);
+
+ for(unsigned int i = 0; i < numSegments; i++)
+ {
+ SVGPathSegImpl *segment = path->getItem(i);
+ struct SegmentData data;
+
+ data.type = segment->pathSegType();
+
+ if(segment->pathSegType() == PATHSEG_MOVETO_ABS || segment->pathSegType() == PATHSEG_MOVETO_REL)
+ {
+ if(currentSubpathStartIndex >= 0)
+ {
+ // Finish the previous subpath.
+ for(unsigned int j = currentSubpathStartIndex; j < i; j++)
+ {
+ pathSegmentData[j].subpathStartIndex = currentSubpathStartIndex;
+ pathSegmentData[j].subpathEndIndex = i - 1;
+ pathSegmentData[j].subpathIsClosed = false;
+ }
+ }
+
+ currentSubpathStartIndex = i;
+ }
+ else if(segment->pathSegType() == PATHSEG_CLOSEPATH)
+ {
+ if(currentSubpathStartIndex >= 0)
+ {
+ SVGPathSegClosePathImpl *s = static_cast<SVGPathSegClosePathImpl *>(segment);
+
+ s->setX(pathSegmentData[currentSubpathStartIndex].startx + pathSegmentData[currentSubpathStartIndex].dx);
+ s->setY(pathSegmentData[currentSubpathStartIndex].starty + pathSegmentData[currentSubpathStartIndex].dy);
+
+ for(unsigned int j = currentSubpathStartIndex; j < i; j++)
+ {
+ pathSegmentData[j].subpathStartIndex = currentSubpathStartIndex;
+ pathSegmentData[j].subpathEndIndex = i;
+ pathSegmentData[j].subpathIsClosed = true;
+ }
+
+ data.subpathStartIndex = currentSubpathStartIndex;
+ data.subpathEndIndex = i;
+ data.subpathIsClosed = true;
+ }
+
+ currentSubpathStartIndex = i + 1;
+ }
+
+ switch(segment->pathSegType())
+ {
+ case PATHSEG_CURVETO_CUBIC_ABS:
+ {
+ SVGPathSegCurvetoCubicAbsImpl *s = static_cast<SVGPathSegCurvetoCubicAbsImpl *>(segment);
+ previousCubicX2 = s->x2();
+ previousCubicY2 = s->y2();
+ break;
+ }
+ case PATHSEG_CURVETO_CUBIC_REL:
+ {
+ SVGPathSegCurvetoCubicRelImpl *s = static_cast<SVGPathSegCurvetoCubicRelImpl *>(segment);
+ previousCubicX2 = curx + s->x2();
+ previousCubicY2 = cury + s->y2();
+ break;
+ }
+ case PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
+ {
+ SVGPathSegCurvetoCubicSmoothAbsImpl *s = static_cast<SVGPathSegCurvetoCubicSmoothAbsImpl *>(segment);
+ s->setPreviousX2(previousCubicX2);
+ s->setPreviousY2(previousCubicY2);
+ previousCubicX2 = s->x2();
+ previousCubicY2 = s->y2();
+ break;
+ }
+ case PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
+ {
+ SVGPathSegCurvetoCubicSmoothRelImpl *s = static_cast<SVGPathSegCurvetoCubicSmoothRelImpl *>(segment);
+ s->setPreviousAbsX2(previousCubicX2);
+ s->setPreviousAbsY2(previousCubicY2);
+ previousCubicX2 = curx + s->x2();
+ previousCubicY2 = cury + s->y2();
+ break;
+ }
+ case PATHSEG_CURVETO_QUADRATIC_ABS:
+ {
+ SVGPathSegCurvetoQuadraticAbsImpl *s = static_cast<SVGPathSegCurvetoQuadraticAbsImpl *>(segment);
+ previousQuadraticX1 = s->x1();
+ previousQuadraticY1 = s->y1();
+ break;
+ }
+ case PATHSEG_CURVETO_QUADRATIC_REL:
+ {
+ SVGPathSegCurvetoQuadraticRelImpl *s = static_cast<SVGPathSegCurvetoQuadraticRelImpl *>(segment);
+ previousQuadraticX1 = curx + s->x1();
+ previousQuadraticY1 = cury + s->y1();
+ break;
+ }
+ case PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
+ {
+ SVGPathSegCurvetoQuadraticSmoothAbsImpl *s = static_cast<SVGPathSegCurvetoQuadraticSmoothAbsImpl *>(segment);
+ s->setPreviousX1(previousQuadraticX1);
+ s->setPreviousY1(previousQuadraticY1);
+ previousQuadraticX1 = s->x1(curx);
+ previousQuadraticY1 = s->y1(cury);
+ break;
+ }
+ case PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
+ {
+ SVGPathSegCurvetoQuadraticSmoothRelImpl *s = static_cast<SVGPathSegCurvetoQuadraticSmoothRelImpl *>(segment);
+ s->setPreviousAbsX1(previousQuadraticX1);
+ s->setPreviousAbsY1(previousQuadraticY1);
+ previousQuadraticX1 = s->absX1(curx);
+ previousQuadraticY1 = s->absY1(cury);
+ break;
+ }
+ default:
+ previousCubicX2 = curx;
+ previousCubicY2 = cury;
+ previousQuadraticX1 = curx;
+ previousQuadraticY1 = cury;
+ break;
+ }
+
+ data.startx = curx;
+ data.starty = cury;
+
+ segment->getDeltasAndSlopes(curx, cury, &data.dx, &data.dy, &data.startSlope, &data.endSlope);
+
+ pathSegmentData[i] = data;
+
+ curx += data.dx;
+ cury += data.dy;
+ }
+
+ if(currentSubpathStartIndex >= 0)
+ {
+ // Finish the previous subpath.
+ for(unsigned int j = currentSubpathStartIndex; j < numSegments; j++)
+ {
+ pathSegmentData[j].subpathStartIndex = currentSubpathStartIndex;
+ pathSegmentData[j].subpathEndIndex = numSegments - 1;
+ pathSegmentData[j].subpathIsClosed = false;
+ }
+ }
+
+ m_markers.resize(numSegments);
+
+ for(unsigned int i = 0; i < numSegments; i++)
+ {
+ struct Marker marker;
+
+ marker.x = pathSegmentData[i].startx + pathSegmentData[i].dx;
+ marker.y = pathSegmentData[i].starty + pathSegmentData[i].dy;
+
+ double inSlope;
+ double outSlope;
+ bool haveInSlope = false;
+ bool haveOutSlope = false;
+
+ if(pathSegmentData[i].subpathStartIndex == i && pathSegmentData[i].subpathIsClosed)
+ {
+ // Spec: For closed subpaths, the marker for the initial vertex uses the end direction
+ // of the corresponding closepath for its incoming slope and the first segment's
+ // start slope for its outgoing slope.
+ haveInSlope = getEndSlope(pathSegmentData, pathSegmentData[i].subpathEndIndex, &inSlope);
+ haveOutSlope = getStartSlope(pathSegmentData, i + 1, &outSlope);
+ }
+ else if(pathSegmentData[i].type == PATHSEG_CLOSEPATH)
+ {
+ haveInSlope = getEndSlope(pathSegmentData, i, &inSlope);
+
+ // Spec: If the segment following a closepath is other than a moveto, the marker
+ // for the closepath uses the following segment's start direction as its
+ // outgoing direction.
+ if(i + 1 < numSegments && (pathSegmentData[i + 1].type != PATHSEG_MOVETO_ABS && pathSegmentData[i + 1].type != PATHSEG_MOVETO_REL))
+ haveOutSlope = getStartSlope(pathSegmentData, i + 1, &outSlope);
+ else
+ haveOutSlope = getStartSlope(pathSegmentData, pathSegmentData[i].subpathStartIndex, &outSlope);
+ }
+ else
+ {
+ haveOutSlope = getStartSlope(pathSegmentData, i + 1, &outSlope);
+ haveInSlope = getEndSlope(pathSegmentData, i, &inSlope);
+ }
+
+ if(!haveInSlope && !haveOutSlope)
+ {
+ outSlope = 0;
+ inSlope = 0;
+ }
+ else if(haveInSlope && !haveOutSlope)
+ outSlope = inSlope;
+ else if(!haveInSlope && haveOutSlope)
+ inSlope = outSlope;
+
+ double bisector = SVGAngleImpl::shortestArcBisector(inSlope, outSlope);
+ marker.angle = bisector;
+
+ m_markers[i] = marker;
+ }
+}
+
+bool SVGPathElementImpl::MarkerData::getStartSlope(QValueVector<SegmentData> segments, unsigned int i, double *pStartSlope)
+{
+ if(i > segments.count() - 1 || segments[i].type == PATHSEG_MOVETO_ABS || segments[i].type == PATHSEG_MOVETO_REL)
+ return false;
+ else
+ {
+ const double epsilon = DBL_EPSILON;
+
+ if(fabs(segments[i].dx) > epsilon || fabs(segments[i].dy) > epsilon)
+ {
+ *pStartSlope = segments[i].startSlope;
+ return true;
+ }
+ else
+ {
+ int subpathStartIndex = segments[i].subpathStartIndex;
+
+ for(int j = i - 1; j >= subpathStartIndex; j--)
+ {
+ if(segments[j].type == PATHSEG_MOVETO_ABS || segments[j].type == PATHSEG_MOVETO_REL)
+ return false;
+
+ if(fabs(segments[j].dx) > epsilon || fabs(segments[j].dy) > epsilon)
+ {
+ *pStartSlope = segments[j].endSlope;
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+}
+
+bool SVGPathElementImpl::MarkerData::getEndSlope(QValueVector<SegmentData> segments, unsigned int i, double *pEndSlope)
+{
+ if(i > segments.count() - 1 || segments[i].type == PATHSEG_MOVETO_ABS || segments[i].type == PATHSEG_MOVETO_REL)
+ return false;
+ else
+ {
+ const double epsilon = DBL_EPSILON;
+
+ if(fabs(segments[i].dx) > epsilon || fabs(segments[i].dy) > epsilon)
+ {
+ *pEndSlope = segments[i].endSlope;
+ return true;
+ }
+ else
+ {
+ int subpathEndIndex = segments[i].subpathEndIndex;
+
+ for(int j = i + 1; j <= subpathEndIndex; j++)
+ {
+ if(segments[j].type == PATHSEG_MOVETO_ABS || segments[j].type == PATHSEG_MOVETO_REL)
+ return false;
+
+ if(fabs(segments[j].dx) > epsilon || fabs(segments[j].dy) > epsilon)
+ {
+ *pEndSlope = segments[j].startSlope;
+ return true;
+ }
+ }
+
+ return false;
+ }
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathElementImpl.h b/ksvg/impl/SVGPathElementImpl.h
new file mode 100644
index 00000000..a9af56fc
--- /dev/null
+++ b/ksvg/impl/SVGPathElementImpl.h
@@ -0,0 +1,194 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathElementImpl_H
+#define SVGPathElementImpl_H
+
+#include <qvaluevector.h>
+
+#include "svgpathparser.h"
+
+#include "ksvg_lookup.h"
+
+#include "SVGShapeImpl.h"
+#include "SVGTestsImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGLangSpaceImpl.h"
+#include "SVGTransformableImpl.h"
+#include "SVGAnimatedPathDataImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+namespace KSVG
+{
+
+class SVGPointImpl;
+class SVGPathSegImpl;
+class SVGPathSegArcAbsImpl;
+class SVGPathSegArcRelImpl;
+class SVGAnimatedNumberImpl;
+class SVGPathSegClosePathImpl;
+class SVGPathSegLinetoAbsImpl;
+class SVGPathSegLinetoRelImpl;
+class SVGPathSegMovetoAbsImpl;
+class SVGPathSegMovetoRelImpl;
+class SVGPathSegCurvetoCubicAbsImpl;
+class SVGPathSegCurvetoCubicRelImpl;
+class SVGPathSegLinetoVerticalAbsImpl;
+class SVGPathSegLinetoVerticalRelImpl;
+class SVGPathSegLinetoHorizontalAbsImpl;
+class SVGPathSegLinetoHorizontalRelImpl;
+class SVGPathSegCurvetoQuadraticAbsImpl;
+class SVGPathSegCurvetoQuadraticRelImpl;
+class SVGPathSegCurvetoCubicSmoothAbsImpl;
+class SVGPathSegCurvetoCubicSmoothRelImpl;
+class SVGPathSegCurvetoQuadraticSmoothAbsImpl;
+class SVGPathSegCurvetoQuadraticSmoothRelImpl;
+class SVGPathElementImpl : public SVGShapeImpl,
+ public SVGTestsImpl,
+ public SVGLangSpaceImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGStylableImpl,
+ public SVGTransformableImpl,
+ public SVGAnimatedPathDataImpl,
+ public ::SVGPathParser
+{
+public:
+ SVGPathElementImpl(DOM::ElementImpl *impl);
+ virtual ~SVGPathElementImpl();
+
+ SVGAnimatedNumberImpl *pathLength() const;
+ double getTotalLength();
+ SVGPointImpl *getPointAtLength(double distance);
+ unsigned long getPathSegAtLength(double distance);
+
+ SVGPathSegClosePathImpl *createSVGPathSegClosePath();
+ SVGPathSegMovetoAbsImpl *createSVGPathSegMovetoAbs(double x, double y);
+ SVGPathSegMovetoRelImpl *createSVGPathSegMovetoRel(double x, double y);
+ SVGPathSegLinetoAbsImpl *createSVGPathSegLinetoAbs(double x, double y);
+ SVGPathSegLinetoRelImpl *createSVGPathSegLinetoRel(double x, double y);
+ SVGPathSegCurvetoCubicAbsImpl *createSVGPathSegCurvetoCubicAbs(double x, double y, double x1, double y1, double x2, double y2);
+ SVGPathSegCurvetoCubicRelImpl *createSVGPathSegCurvetoCubicRel(double x, double y, double x1, double y1, double x2, double y2);
+ SVGPathSegCurvetoQuadraticAbsImpl *createSVGPathSegCurvetoQuadraticAbs(double x, double y, double x1, double y1);
+ SVGPathSegCurvetoQuadraticRelImpl *createSVGPathSegCurvetoQuadraticRel(double x, double y, double x1, double y1);
+ SVGPathSegArcAbsImpl *createSVGPathSegArcAbs(double x, double y, double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag);
+ SVGPathSegArcRelImpl *createSVGPathSegArcRel(double x, double y, double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag);
+ SVGPathSegLinetoHorizontalAbsImpl *createSVGPathSegLinetoHorizontalAbs(double x);
+ SVGPathSegLinetoHorizontalRelImpl *createSVGPathSegLinetoHorizontalRel(double x);
+ SVGPathSegLinetoVerticalAbsImpl *createSVGPathSegLinetoVerticalAbs(double y);
+ SVGPathSegLinetoVerticalRelImpl *createSVGPathSegLinetoVerticalRel(double y);
+ SVGPathSegCurvetoCubicSmoothAbsImpl *createSVGPathSegCurvetoCubicSmoothAbs(double x, double y, double x2, double y2);
+ SVGPathSegCurvetoCubicSmoothRelImpl *createSVGPathSegCurvetoCubicSmoothRel(double x, double y, double x2, double y2);
+ SVGPathSegCurvetoQuadraticSmoothAbsImpl *createSVGPathSegCurvetoQuadraticSmoothAbs(double x, double y);
+ SVGPathSegCurvetoQuadraticSmoothRelImpl *createSVGPathSegCurvetoQuadraticSmoothRel(double x, double y);
+
+ virtual void createItem(KSVGCanvas *c = 0);
+
+ virtual SVGRectImpl *getBBox();
+
+ class MarkerData
+ {
+ public:
+ struct Marker
+ {
+ double x;
+ double y;
+ double angle;
+ };
+
+ MarkerData() {}
+ MarkerData(SVGPathSegListImpl *path);
+
+ const Marker& marker(unsigned int i) const { return m_markers[i]; }
+ unsigned int numMarkers() const { return m_markers.count(); }
+
+ private:
+ struct SegmentData
+ {
+ double startx;
+ double starty;
+ double dx;
+ double dy;
+ double startSlope;
+ double endSlope;
+ unsigned int subpathStartIndex;
+ unsigned int subpathEndIndex;
+ bool subpathIsClosed;
+ int type;
+ };
+
+ static bool getStartSlope(QValueVector<SegmentData> segments, unsigned int i, double *pStartSlope);
+ static bool getEndSlope(QValueVector<SegmentData> segments, unsigned int i, double *pEndSlope);
+
+ QValueVector<Marker> m_markers;
+ };
+
+ MarkerData markerData() const { return m_markerData; }
+
+private:
+ SVGAnimatedNumberImpl *m_pathLength;
+ MarkerData m_markerData;
+
+ virtual void svgMoveTo(double x1, double y1, bool closed, bool abs = true);
+ virtual void svgLineTo(double x1, double y1, bool abs = true);
+ virtual void svgLineToHorizontal(double x, bool abs = true);
+ virtual void svgLineToVertical(double y, bool abs = true);
+ virtual void svgCurveToCubic(double x1, double y1, double x2, double y2, double x, double y, bool abs = true);
+ virtual void svgCurveToCubicSmooth(double x, double y, double x2, double y2, bool abs = true);
+ virtual void svgCurveToQuadratic(double x, double y, double x1, double y1, bool abs = true);
+ virtual void svgCurveToQuadraticSmooth(double x, double y, bool abs = true);
+ virtual void svgArcTo(double x, double y, double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag, bool abs = true);
+ virtual void svgClosePath();
+
+public:
+ KSVG_GET
+ KSVG_PUT
+ KSVG_BRIDGE
+
+ enum
+ {
+ // Properties
+ D, PathLength,
+ // Functions
+ GetTotalLength, GetPointAtLength, GetPathSegAtLength,
+ CreateSVGPathSegClosePath, CreateSVGPathSegMovetoAbs, CreateSVGPathSegMovetoRel,
+ CreateSVGPathSegLinetoAbs, CreateSVGPathSegLinetoRel, CreateSVGPathSegCurvetoCubicAbs,
+ CreateSVGPathSegCurvetoCubicRel, CreateSVGPathSegCurvetoQuadraticAbs,
+ CreateSVGPathSegCurvetoQuadraticRel, CreateSVGPathSegArcAbs,
+ CreateSVGPathSegArcRel, CreateSVGPathSegLinetoHorizontalAbs,
+ CreateSVGPathSegLinetoHorizontalRel, CreateSVGPathSegLinetoVerticalAbs,
+ CreateSVGPathSegLinetoVerticalRel, CreateSVGPathSegCurvetoCubicSmoothAbs,
+ CreateSVGPathSegCurvetoCubicSmoothRel, CreateSVGPathSegCurvetoQuadraticSmoothAbs,
+ CreateSVGPathSegCurvetoQuadraticSmoothRel
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+KSVG_REGISTER_ELEMENT(SVGPathElementImpl, "path")
+
+}
+
+KSVG_DEFINE_PROTOTYPE(SVGPathElementImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGPathElementImplProtoFunc, SVGPathElementImpl)
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathSegArcImpl.cc b/ksvg/impl/SVGPathSegArcImpl.cc
new file mode 100644
index 00000000..9fb4190f
--- /dev/null
+++ b/ksvg/impl/SVGPathSegArcImpl.cc
@@ -0,0 +1,495 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <math.h>
+
+#include <kdebug.h>
+
+#include "SVGPathSegArcImpl.h"
+#include "SVGAngleImpl.h"
+
+using namespace KSVG;
+
+#include "SVGPathSegArcImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+static void getArcSlopes(bool relative, double curx, double cury, double angle, double x, double y, double r1, double r2, bool largeArcFlag, bool sweepFlag, double *pStartSlope, double *pEndSlope)
+{
+ double sin_th, cos_th;
+ double a00, a01, a10, a11;
+ double x0, y0, x1, y1, xc, yc;
+ double d, sfactor, sfactor_sq;
+ double th0, th1, th_arc;
+ int i, n_segs;
+
+ sin_th = sin(angle * (M_PI / 180.0));
+ cos_th = cos(angle * (M_PI / 180.0));
+
+ double dx;
+
+ if(!relative)
+ dx = (curx - x) / 2.0;
+ else
+ dx = -x / 2.0;
+
+ double dy;
+
+ if(!relative)
+ dy = (cury - y) / 2.0;
+ else
+ dy = -y / 2.0;
+
+ double _x1 = cos_th * dx + sin_th * dy;
+ double _y1 = -sin_th * dx + cos_th * dy;
+ double Pr1 = r1 * r1;
+ double Pr2 = r2 * r2;
+ double Px = _x1 * _x1;
+ double Py = _y1 * _y1;
+
+ // Spec : check if radii are large enough
+ double check = Px / Pr1 + Py / Pr2;
+ if(check > 1)
+ {
+ r1 = r1 * sqrt(check);
+ r2 = r2 * sqrt(check);
+ }
+
+ a00 = cos_th / r1;
+ a01 = sin_th / r1;
+ a10 = -sin_th / r2;
+ a11 = cos_th / r2;
+
+ x0 = a00 * curx + a01 * cury;
+ y0 = a10 * curx + a11 * cury;
+
+ if(!relative)
+ x1 = a00 * x + a01 * y;
+ else
+ x1 = a00 * (curx + x) + a01 * (cury + y);
+
+ if(!relative)
+ y1 = a10 * x + a11 * y;
+ else
+ y1 = a10 * (curx + x) + a11 * (cury + y);
+
+ /* (x0, y0) is current point in transformed coordinate space.
+ (x1, y1) is new point in transformed coordinate space.
+
+ The arc fits a unit-radius circle in this space.
+ */
+
+ d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
+
+ sfactor_sq = 1.0 / d - 0.25;
+
+ if(sfactor_sq < 0)
+ sfactor_sq = 0;
+
+ sfactor = sqrt(sfactor_sq);
+
+ if(sweepFlag == largeArcFlag)
+ sfactor = -sfactor;
+
+ xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
+ yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
+
+ /* (xc, yc) is center of the circle. */
+ th0 = atan2(y0 - yc, x0 - xc);
+ th1 = atan2(y1 - yc, x1 - xc);
+
+ th_arc = th1 - th0;
+ if(th_arc < 0 && sweepFlag)
+ th_arc += 2 * M_PI;
+ else if(th_arc > 0 && !sweepFlag)
+ th_arc -= 2 * M_PI;
+
+ n_segs = (int) (int) ceil(fabs(th_arc / (M_PI * 0.5 + 0.001)));
+
+ for(int step = 0; step < 2; step++)
+ {
+ i = step == 0 ? 0 : n_segs - 1;
+
+ double sin_th, cos_th;
+ double a00, a01, a10, a11;
+ double x1, y1, x2, y2, x3, y3;
+ double t;
+ double th_half;
+
+ double _th0 = th0 + i * th_arc / n_segs;
+ double _th1 = th0 + (i + 1) * th_arc / n_segs;
+
+ sin_th = sin(angle * (M_PI / 180.0));
+ cos_th = cos(angle * (M_PI / 180.0));
+
+ /* inverse transform compared with rsvg_path_arc */
+ a00 = cos_th * r1;
+ a01 = -sin_th * r2;
+ a10 = sin_th * r1;
+ a11 = cos_th * r2;
+
+ th_half = 0.5 * (_th1 - _th0);
+ t = (8.0 / 3.0) * sin(th_half * 0.5) * sin(th_half * 0.5) / sin(th_half);
+ x1 = xc + cos(_th0) - t * sin(_th0);
+ y1 = yc + sin(_th0) + t * cos(_th0);
+ x3 = xc + cos(_th1);
+ y3 = yc + sin(_th1);
+ x2 = x3 + t * sin(_th1);
+ y2 = y3 - t * cos(_th1);
+
+ double bezX1 = a00 * x1 + a01 * y1;
+ double bezY1 = a10 * x1 + a11 * y1;
+ double bezX2 = a00 * x2 + a01 * y2;
+ double bezY2 = a10 * x2 + a11 * y2;
+ double bezX = a00 * x3 + a01 * y3;
+ double bezY = a10 * x3 + a11 * y3;
+
+ if(step == 0)
+ *pStartSlope = SVGAngleImpl::todeg(atan2(bezY1 - cury, bezX1 - curx));
+ else
+ *pEndSlope = SVGAngleImpl::todeg(atan2(bezY - bezY2, bezX - bezX2));
+ }
+}
+
+SVGPathSegArcAbsImpl::SVGPathSegArcAbsImpl() : SVGPathSegImpl()
+{
+ KSVG_EMPTY_FLAGS
+}
+
+SVGPathSegArcAbsImpl::~SVGPathSegArcAbsImpl()
+{
+}
+
+void SVGPathSegArcAbsImpl::setX(double x)
+{
+ m_x = x;
+}
+
+double SVGPathSegArcAbsImpl::x() const
+{
+ return m_x;
+}
+
+void SVGPathSegArcAbsImpl::setY(double y)
+{
+ m_y = y;
+}
+
+double SVGPathSegArcAbsImpl::y() const
+{
+ return m_y;
+}
+
+void SVGPathSegArcAbsImpl::setR1(double r1)
+{
+ m_r1 = r1;
+}
+
+double SVGPathSegArcAbsImpl::r1() const
+{
+ return m_r1;
+}
+
+void SVGPathSegArcAbsImpl::setR2(double r2)
+{
+ m_r2 = r2;
+}
+
+double SVGPathSegArcAbsImpl::r2() const
+{
+ return m_r2;
+}
+
+void SVGPathSegArcAbsImpl::setAngle(double angle)
+{
+ m_angle = angle;
+}
+
+double SVGPathSegArcAbsImpl::angle() const
+{
+ return m_angle;
+}
+
+void SVGPathSegArcAbsImpl::setLargeArcFlag(bool largeArcFlag)
+{
+ m_largeArcFlag = largeArcFlag;
+}
+
+bool SVGPathSegArcAbsImpl::largeArcFlag() const
+{
+ return m_largeArcFlag;
+}
+
+void SVGPathSegArcAbsImpl::setSweepFlag(bool sweepFlag)
+{
+ m_sweepFlag = sweepFlag;
+}
+
+bool SVGPathSegArcAbsImpl::sweepFlag() const
+{
+ return m_sweepFlag;
+}
+
+void SVGPathSegArcAbsImpl::getDeltasAndSlopes(double curx, double cury, double *pDx, double *pDy, double *pStartSlope, double *pEndSlope) const
+{
+ double dx = x() - curx;
+ double dy = y() - cury;
+ double startSlope;
+ double endSlope;
+ getArcSlopes(false, curx, cury, angle(), x(), y(), r1(), r2(), largeArcFlag(), sweepFlag(), &startSlope, &endSlope);
+ *pDx = dx;
+ *pDy = dy;
+ *pStartSlope = startSlope;
+ *pEndSlope = endSlope;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPathSegArcAbsImpl::s_hashTable 11
+ x SVGPathSegArcAbsImpl::X DontDelete
+ y SVGPathSegArcAbsImpl::Y DontDelete
+ r1 SVGPathSegArcAbsImpl::R1 DontDelete
+ r2 SVGPathSegArcAbsImpl::R2 DontDelete
+ angle SVGPathSegArcAbsImpl::Angle DontDelete
+ largeArcFlag SVGPathSegArcAbsImpl::LargeArcFlag DontDelete
+ sweepFlag SVGPathSegArcAbsImpl::SweepFlag DontDelete
+@end
+*/
+
+Value SVGPathSegArcAbsImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case X:
+ return Number(x());
+ case Y:
+ return Number(y());
+ case R1:
+ return Number(r1());
+ case R2:
+ return Number(r2());
+ case Angle:
+ return Number(angle());
+ case LargeArcFlag:
+ return Boolean(largeArcFlag());
+ case SweepFlag:
+ return Boolean(sweepFlag());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGPathSegArcAbsImpl::putValueProperty(ExecState *exec, int token, const Value &value, int)
+{
+ switch(token)
+ {
+ case X:
+ m_x = value.toNumber(exec);
+ break;
+ case Y:
+ m_y = value.toNumber(exec);
+ break;
+ case R1:
+ m_r1 = value.toNumber(exec);
+ break;
+ case R2:
+ m_r2 = value.toNumber(exec);
+ break;
+ case Angle:
+ m_angle = value.toNumber(exec);
+ break;
+ case LargeArcFlag:
+ m_largeArcFlag = value.toBoolean(exec);
+ break;
+ case SweepFlag:
+ m_sweepFlag = value.toBoolean(exec);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+
+
+SVGPathSegArcRelImpl::SVGPathSegArcRelImpl() : SVGPathSegImpl()
+{
+ KSVG_EMPTY_FLAGS
+}
+
+SVGPathSegArcRelImpl::~SVGPathSegArcRelImpl()
+{
+}
+
+void SVGPathSegArcRelImpl::setX(double x)
+{
+ m_x = x;
+}
+
+double SVGPathSegArcRelImpl::x() const
+{
+ return m_x;
+}
+
+void SVGPathSegArcRelImpl::setY(double y)
+{
+ m_y = y;
+}
+
+double SVGPathSegArcRelImpl::y() const
+{
+ return m_y;
+}
+
+void SVGPathSegArcRelImpl::setR1(double r1)
+{
+ m_r1 = r1;
+}
+
+double SVGPathSegArcRelImpl::r1() const
+{
+ return m_r1;
+}
+
+void SVGPathSegArcRelImpl::setR2(double r2)
+{
+ m_r2 = r2;
+}
+
+double SVGPathSegArcRelImpl::r2() const
+{
+ return m_r2;
+}
+
+void SVGPathSegArcRelImpl::setAngle(double angle)
+{
+ m_angle = angle;
+}
+
+double SVGPathSegArcRelImpl::angle() const
+{
+ return m_angle;
+}
+
+void SVGPathSegArcRelImpl::setLargeArcFlag(bool largeArcFlag)
+{
+ m_largeArcFlag = largeArcFlag;
+}
+
+bool SVGPathSegArcRelImpl::largeArcFlag() const
+{
+ return m_largeArcFlag;
+}
+
+void SVGPathSegArcRelImpl::setSweepFlag(bool sweepFlag)
+{
+ m_sweepFlag = sweepFlag;
+}
+
+bool SVGPathSegArcRelImpl::sweepFlag() const
+{
+ return m_sweepFlag;
+}
+
+void SVGPathSegArcRelImpl::getDeltasAndSlopes(double curx, double cury, double *pDx, double *pDy, double *pStartSlope, double *pEndSlope) const
+{
+ double dx = x();
+ double dy = y();
+ double startSlope;
+ double endSlope;
+ getArcSlopes(true, curx, cury, angle(), x(), y(), r1(), r2(), largeArcFlag(), sweepFlag(), &startSlope, &endSlope);
+ *pDx = dx;
+ *pDy = dy;
+ *pStartSlope = startSlope;
+ *pEndSlope = endSlope;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPathSegArcRelImpl::s_hashTable 11
+ x SVGPathSegArcRelImpl::X DontDelete
+ y SVGPathSegArcRelImpl::Y DontDelete
+ r1 SVGPathSegArcRelImpl::R1 DontDelete
+ r2 SVGPathSegArcRelImpl::R2 DontDelete
+ angle SVGPathSegArcRelImpl::Angle DontDelete
+ largeArcFlag SVGPathSegArcRelImpl::LargeArcFlag DontDelete
+ sweepFlag SVGPathSegArcRelImpl::SweepFlag DontDelete
+@end
+*/
+
+Value SVGPathSegArcRelImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case X:
+ return Number(x());
+ case Y:
+ return Number(y());
+ case R1:
+ return Number(r1());
+ case R2:
+ return Number(r2());
+ case Angle:
+ return Number(angle());
+ case LargeArcFlag:
+ return Boolean(largeArcFlag());
+ case SweepFlag:
+ return Boolean(sweepFlag());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGPathSegArcRelImpl::putValueProperty(ExecState *exec, int token, const Value &value, int)
+{
+ switch(token)
+ {
+ case X:
+ m_x = value.toNumber(exec);
+ break;
+ case Y:
+ m_y = value.toNumber(exec);
+ break;
+ case R1:
+ m_r1 = value.toNumber(exec);
+ break;
+ case R2:
+ m_r2 = value.toNumber(exec);
+ break;
+ case Angle:
+ m_angle = value.toNumber(exec);
+ break;
+ case LargeArcFlag:
+ m_largeArcFlag = value.toBoolean(exec);
+ break;
+ case SweepFlag:
+ m_sweepFlag = value.toBoolean(exec);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathSegArcImpl.h b/ksvg/impl/SVGPathSegArcImpl.h
new file mode 100644
index 00000000..f0e375d6
--- /dev/null
+++ b/ksvg/impl/SVGPathSegArcImpl.h
@@ -0,0 +1,150 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathSegArcImpl_H
+#define SVGPathSegArcImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGPathSegImpl.h"
+
+namespace KSVG
+{
+
+class SVGPathSegArcAbsImpl : public SVGPathSegImpl
+{
+public:
+ SVGPathSegArcAbsImpl();
+ virtual ~SVGPathSegArcAbsImpl();
+
+ virtual unsigned short pathSegType() const { return PATHSEG_ARC_ABS; }
+ virtual DOM::DOMString pathSegTypeAsLetter() const { return "A"; }
+ virtual QString toString() const { return QString("A %1 %2 %3 %4 %5 %6 %7").arg(m_r1).arg(m_r2).arg(m_angle).arg(m_largeArcFlag).arg(m_sweepFlag).arg(m_x).arg(m_y); }
+
+ void setX(double x);
+ double x() const;
+
+ void setY(double y);
+ double y() const;
+
+ void setR1(double r1);
+ double r1() const;
+
+ void setR2(double r2);
+ double r2() const;
+
+ void setAngle(double angle);
+ double angle() const;
+
+ void setLargeArcFlag(bool largeArcFlag);
+ bool largeArcFlag() const;
+
+ void setSweepFlag(bool sweepFlag);
+ bool sweepFlag() const;
+
+ virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const;
+
+private:
+ double m_x;
+ double m_y;
+ double m_r1;
+ double m_r2;
+ double m_angle;
+
+ bool m_largeArcFlag : 1;
+ bool m_sweepFlag : 1;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ X, Y, R1, R2, Angle, LargeArcFlag, SweepFlag
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+
+class SVGPathSegArcRelImpl : public SVGPathSegImpl
+{
+public:
+ SVGPathSegArcRelImpl();
+ virtual ~SVGPathSegArcRelImpl();
+
+ virtual unsigned short pathSegType() const { return PATHSEG_ARC_REL; }
+ virtual DOM::DOMString pathSegTypeAsLetter() const { return "a"; }
+ virtual QString toString() const { return QString("a %1 %2 %3 %4 %5 %6 %7").arg(m_r1).arg(m_r2).arg(m_angle).arg(m_largeArcFlag).arg(m_sweepFlag).arg(m_x).arg(m_y); }
+
+ void setX(double x);
+ double x() const;
+
+ void setY(double y);
+ double y() const;
+
+ void setR1(double r1);
+ double r1() const;
+
+ void setR2(double r2);
+ double r2() const;
+
+ void setAngle(double angle);
+ double angle() const;
+
+ void setLargeArcFlag(bool largeArcFlag);
+ bool largeArcFlag() const;
+
+ void setSweepFlag(bool sweepFlag);
+ bool sweepFlag() const;
+
+ virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const;
+
+private:
+ double m_x;
+ double m_y;
+ double m_r1;
+ double m_r2;
+ double m_angle;
+
+ bool m_largeArcFlag : 1;
+ bool m_sweepFlag : 1;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ X, Y, R1, R2, Angle, LargeArcFlag, SweepFlag
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathSegClosePathImpl.cc b/ksvg/impl/SVGPathSegClosePathImpl.cc
new file mode 100644
index 00000000..c18e6027
--- /dev/null
+++ b/ksvg/impl/SVGPathSegClosePathImpl.cc
@@ -0,0 +1,46 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGPathSegClosePathImpl.h"
+#include "SVGAngleImpl.h"
+
+using namespace KSVG;
+
+SVGPathSegClosePathImpl::SVGPathSegClosePathImpl() : SVGPathSegImpl()
+{
+}
+
+SVGPathSegClosePathImpl::~SVGPathSegClosePathImpl()
+{
+}
+
+void SVGPathSegClosePathImpl::getDeltasAndSlopes(double curx, double cury, double *pdx, double *pdy, double *pstartSlope, double *pendSlope) const
+{
+ double dx = x() - curx;
+ double dy = y() - cury;
+ double startSlope = SVGAngleImpl::todeg(atan2(dy, dx));
+ double endSlope = startSlope;
+ *pdx = dx;
+ *pdy = dy;
+ *pstartSlope = startSlope;
+ *pendSlope = endSlope;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathSegClosePathImpl.h b/ksvg/impl/SVGPathSegClosePathImpl.h
new file mode 100644
index 00000000..c4cf63ce
--- /dev/null
+++ b/ksvg/impl/SVGPathSegClosePathImpl.h
@@ -0,0 +1,61 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathSegClosePathImpl_H
+#define SVGPathSegClosePathImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGPathSegImpl.h"
+
+namespace KSVG
+{
+
+class SVGPathSegClosePathImpl : public SVGPathSegImpl
+{
+public:
+ SVGPathSegClosePathImpl();
+ virtual ~SVGPathSegClosePathImpl();
+
+ virtual unsigned short pathSegType() const { return PATHSEG_CLOSEPATH; }
+ virtual DOM::DOMString pathSegTypeAsLetter() const { return "Z"; }
+ virtual QString toString() const { return "Z"; }
+
+ void setX(double x) { m_x = x; }
+ void setY(double y) { m_y = y; }
+
+ double x() const { return m_x; }
+ double y() const { return m_y; }
+
+ virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const;
+
+private:
+ double m_x;
+ double m_y;
+
+public:
+ KSVG_FORWARDGET
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathSegCurvetoCubicImpl.cc b/ksvg/impl/SVGPathSegCurvetoCubicImpl.cc
new file mode 100644
index 00000000..468b1fb3
--- /dev/null
+++ b/ksvg/impl/SVGPathSegCurvetoCubicImpl.cc
@@ -0,0 +1,325 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGPathSegCurvetoCubicImpl.h"
+#include "SVGAngleImpl.h"
+
+using namespace KSVG;
+
+#include "SVGPathSegCurvetoCubicImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+SVGPathSegCurvetoCubicAbsImpl::SVGPathSegCurvetoCubicAbsImpl() : SVGPathSegImpl()
+{
+ KSVG_EMPTY_FLAGS
+}
+
+SVGPathSegCurvetoCubicAbsImpl::~SVGPathSegCurvetoCubicAbsImpl()
+{
+}
+
+void SVGPathSegCurvetoCubicAbsImpl::setX(const double &x)
+{
+ m_x = x;
+}
+
+double SVGPathSegCurvetoCubicAbsImpl::x() const
+{
+ return m_x;
+}
+
+void SVGPathSegCurvetoCubicAbsImpl::setY(const double &y)
+{
+ m_y = y;
+}
+
+double SVGPathSegCurvetoCubicAbsImpl::y() const
+{
+ return m_y;
+}
+
+void SVGPathSegCurvetoCubicAbsImpl::setX1(const double &x1)
+{
+ m_x1 = x1;
+}
+
+double SVGPathSegCurvetoCubicAbsImpl::x1() const
+{
+ return m_x1;
+}
+
+void SVGPathSegCurvetoCubicAbsImpl::setY1(const double &y1)
+{
+ m_y1 = y1;
+}
+
+double SVGPathSegCurvetoCubicAbsImpl::y1() const
+{
+ return m_y1;
+}
+
+void SVGPathSegCurvetoCubicAbsImpl::setX2(const double &x2)
+{
+ m_x2 = x2;
+}
+
+double SVGPathSegCurvetoCubicAbsImpl::x2() const
+{
+ return m_x2;
+}
+
+void SVGPathSegCurvetoCubicAbsImpl::setY2(const double &y2)
+{
+ m_y2 = y2;
+}
+
+double SVGPathSegCurvetoCubicAbsImpl::y2() const
+{
+ return m_y2;
+}
+
+void SVGPathSegCurvetoCubicAbsImpl::getDeltasAndSlopes(double curx, double cury, double *pDx, double *pDy, double *pStartSlope, double *pEndSlope) const
+{
+ double dx = x() - curx;
+ double dy = y() - cury;
+ double startSlope = SVGAngleImpl::todeg(atan2(y1() - cury, x1() - curx));
+ double endSlope = SVGAngleImpl::todeg(atan2(y() - y2(), x() - x2()));
+ *pDx = dx;
+ *pDy = dy;
+ *pStartSlope = startSlope;
+ *pEndSlope = endSlope;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPathSegCurvetoCubicAbsImpl::s_hashTable 7
+ x SVGPathSegCurvetoCubicAbsImpl::X DontDelete
+ y SVGPathSegCurvetoCubicAbsImpl::Y DontDelete
+ x1 SVGPathSegCurvetoCubicAbsImpl::X1 DontDelete
+ y1 SVGPathSegCurvetoCubicAbsImpl::Y1 DontDelete
+ x2 SVGPathSegCurvetoCubicAbsImpl::X2 DontDelete
+ y2 SVGPathSegCurvetoCubicAbsImpl::Y2 DontDelete
+@end
+*/
+
+Value SVGPathSegCurvetoCubicAbsImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case X:
+ return Number(x());
+ case Y:
+ return Number(y());
+ case X1:
+ return Number(x1());
+ case Y1:
+ return Number(y1());
+ case X2:
+ return Number(x2());
+ case Y2:
+ return Number(y2());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGPathSegCurvetoCubicAbsImpl::putValueProperty(ExecState *exec, int token, const Value &value, int)
+{
+ switch(token)
+ {
+ case X:
+ m_x = value.toNumber(exec);
+ break;
+ case Y:
+ m_y = value.toNumber(exec);
+ break;
+ case X1:
+ m_x1 = value.toNumber(exec);
+ break;
+ case Y1:
+ m_y1 = value.toNumber(exec);
+ break;
+ case X2:
+ m_x2 = value.toNumber(exec);
+ break;
+ case Y2:
+ m_y2 = value.toNumber(exec);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+
+
+
+SVGPathSegCurvetoCubicRelImpl::SVGPathSegCurvetoCubicRelImpl() : SVGPathSegImpl()
+{
+ KSVG_EMPTY_FLAGS
+}
+
+SVGPathSegCurvetoCubicRelImpl::~SVGPathSegCurvetoCubicRelImpl()
+{
+}
+
+void SVGPathSegCurvetoCubicRelImpl::setX(const double &x)
+{
+ m_x = x;
+}
+
+double SVGPathSegCurvetoCubicRelImpl::x() const
+{
+ return m_x;
+}
+
+void SVGPathSegCurvetoCubicRelImpl::setY(const double &y)
+{
+ m_y = y;
+}
+
+double SVGPathSegCurvetoCubicRelImpl::y() const
+{
+ return m_y;
+}
+
+void SVGPathSegCurvetoCubicRelImpl::setX1(const double &x1)
+{
+ m_x1 = x1;
+}
+
+double SVGPathSegCurvetoCubicRelImpl::x1() const
+{
+ return m_x1;
+}
+
+void SVGPathSegCurvetoCubicRelImpl::setY1(const double &y1)
+{
+ m_y1 = y1;
+}
+
+double SVGPathSegCurvetoCubicRelImpl::y1() const
+{
+ return m_y1;
+}
+
+void SVGPathSegCurvetoCubicRelImpl::setX2(const double &x2)
+{
+ m_x2 = x2;
+}
+
+double SVGPathSegCurvetoCubicRelImpl::x2() const
+{
+ return m_x2;
+}
+
+void SVGPathSegCurvetoCubicRelImpl::setY2(const double &y2)
+{
+ m_y2 = y2;
+}
+
+double SVGPathSegCurvetoCubicRelImpl::y2() const
+{
+ return m_y2;
+}
+
+void SVGPathSegCurvetoCubicRelImpl::getDeltasAndSlopes(double curx, double cury, double *pDx, double *pDy, double *pStartSlope, double *pEndSlope) const
+{
+ Q_UNUSED(curx);
+ Q_UNUSED(cury);
+ double dx = x();
+ double dy = y();
+ double startSlope = SVGAngleImpl::todeg(atan2(y1(), x1()));
+ double endSlope = SVGAngleImpl::todeg(atan2(y() - y2(), x() - x2()));
+ *pDx = dx;
+ *pDy = dy;
+ *pStartSlope = startSlope;
+ *pEndSlope = endSlope;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPathSegCurvetoCubicRelImpl::s_hashTable 7
+ x SVGPathSegCurvetoCubicRelImpl::X DontDelete
+ y SVGPathSegCurvetoCubicRelImpl::Y DontDelete
+ x1 SVGPathSegCurvetoCubicRelImpl::X1 DontDelete
+ y1 SVGPathSegCurvetoCubicRelImpl::Y1 DontDelete
+ x2 SVGPathSegCurvetoCubicRelImpl::X2 DontDelete
+ y2 SVGPathSegCurvetoCubicRelImpl::Y2 DontDelete
+@end
+*/
+
+Value SVGPathSegCurvetoCubicRelImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case X:
+ return Number(x());
+ case Y:
+ return Number(y());
+ case X1:
+ return Number(x1());
+ case Y1:
+ return Number(y1());
+ case X2:
+ return Number(x2());
+ case Y2:
+ return Number(y2());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGPathSegCurvetoCubicRelImpl::putValueProperty(ExecState *exec, int token, const Value &value, int)
+{
+ switch(token)
+ {
+ case X:
+ m_x = value.toNumber(exec);
+ break;
+ case Y:
+ m_y = value.toNumber(exec);
+ break;
+ case X1:
+ m_x1 = value.toNumber(exec);
+ break;
+ case Y1:
+ m_y1 = value.toNumber(exec);
+ break;
+ case X2:
+ m_x2 = value.toNumber(exec);
+ break;
+ case Y2:
+ m_y2 = value.toNumber(exec);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathSegCurvetoCubicImpl.h b/ksvg/impl/SVGPathSegCurvetoCubicImpl.h
new file mode 100644
index 00000000..8f408f91
--- /dev/null
+++ b/ksvg/impl/SVGPathSegCurvetoCubicImpl.h
@@ -0,0 +1,139 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathSegCurvetoCubicImpl_H
+#define SVGPathSegCurvetoCubicImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGPathSegImpl.h"
+
+namespace KSVG
+{
+
+class SVGPathSegCurvetoCubicAbsImpl : public SVGPathSegImpl
+{
+public:
+ SVGPathSegCurvetoCubicAbsImpl();
+ virtual ~SVGPathSegCurvetoCubicAbsImpl();
+
+ virtual unsigned short pathSegType() const { return PATHSEG_CURVETO_CUBIC_ABS; }
+ virtual DOM::DOMString pathSegTypeAsLetter() const { return "C"; }
+ virtual QString toString() const { return QString("C %1 %2 %3 %4 %5 %6").arg(m_x1).arg(m_y1).arg(m_x2).arg(m_y2).arg(m_x).arg(m_y); }
+
+ void setX(const double &);
+ double x() const;
+
+ void setY(const double &);
+ double y() const;
+
+ void setX1(const double &);
+ double x1() const;
+
+ void setY1(const double &);
+ double y1() const;
+
+ void setX2(const double &);
+ double x2() const;
+
+ void setY2(const double &);
+ double y2() const;
+
+ virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const;
+
+private:
+ double m_x;
+ double m_y;
+ double m_x1;
+ double m_y1;
+ double m_x2;
+ double m_y2;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ X, Y, X1, Y1, X2, Y2
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+class SVGPathSegCurvetoCubicRelImpl : public SVGPathSegImpl
+{
+public:
+ SVGPathSegCurvetoCubicRelImpl();
+ virtual ~SVGPathSegCurvetoCubicRelImpl();
+
+ virtual unsigned short pathSegType() const { return PATHSEG_CURVETO_CUBIC_REL; }
+ virtual DOM::DOMString pathSegTypeAsLetter() const { return "c"; }
+ virtual QString toString() const { return QString("c %1 %2 %3 %4 %5 %6").arg(m_x1).arg(m_y1).arg(m_x2).arg(m_y2).arg(m_x).arg(m_y); }
+
+ void setX(const double &);
+ double x() const;
+
+ void setY(const double &);
+ double y() const;
+
+ void setX1(const double &);
+ double x1() const;
+
+ void setY1(const double &);
+ double y1() const;
+
+ void setX2(const double &);
+ double x2() const;
+
+ void setY2(const double &);
+ double y2() const;
+
+ virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const;
+
+private:
+ double m_x;
+ double m_y;
+ double m_x1;
+ double m_y1;
+ double m_x2;
+ double m_y2;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ X, Y, X1, Y1, X2, Y2
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathSegCurvetoCubicSmoothImpl.cc b/ksvg/impl/SVGPathSegCurvetoCubicSmoothImpl.cc
new file mode 100644
index 00000000..1d5c124a
--- /dev/null
+++ b/ksvg/impl/SVGPathSegCurvetoCubicSmoothImpl.cc
@@ -0,0 +1,298 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGPathSegCurvetoCubicSmoothImpl.h"
+#include "SVGAngleImpl.h"
+
+using namespace KSVG;
+
+#include "SVGPathSegCurvetoCubicSmoothImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+SVGPathSegCurvetoCubicSmoothAbsImpl::SVGPathSegCurvetoCubicSmoothAbsImpl() : SVGPathSegImpl()
+{
+ KSVG_EMPTY_FLAGS
+}
+
+SVGPathSegCurvetoCubicSmoothAbsImpl::~SVGPathSegCurvetoCubicSmoothAbsImpl()
+{
+}
+
+void SVGPathSegCurvetoCubicSmoothAbsImpl::setX(const double &x)
+{
+ m_x = x;
+}
+
+double SVGPathSegCurvetoCubicSmoothAbsImpl::x() const
+{
+ return m_x;
+}
+
+void SVGPathSegCurvetoCubicSmoothAbsImpl::setY(const double &y)
+{
+ m_y = y;
+}
+
+double SVGPathSegCurvetoCubicSmoothAbsImpl::y() const
+{
+ return m_y;
+}
+
+void SVGPathSegCurvetoCubicSmoothAbsImpl::setX2(const double &x2)
+{
+ m_x2 = x2;
+}
+
+double SVGPathSegCurvetoCubicSmoothAbsImpl::x2() const
+{
+ return m_x2;
+}
+
+void SVGPathSegCurvetoCubicSmoothAbsImpl::setY2(const double &y2)
+{
+ m_y2 = y2;
+}
+
+double SVGPathSegCurvetoCubicSmoothAbsImpl::y2() const
+{
+ return m_y2;
+}
+
+void SVGPathSegCurvetoCubicSmoothAbsImpl::setPreviousX2(double x2)
+{
+ m_previousX2 = x2;
+}
+
+void SVGPathSegCurvetoCubicSmoothAbsImpl::setPreviousY2(double y2)
+{
+ m_previousY2 = y2;
+}
+
+double SVGPathSegCurvetoCubicSmoothAbsImpl::x1(double curx) const
+{
+ return curx - (m_previousX2 - curx);
+}
+
+double SVGPathSegCurvetoCubicSmoothAbsImpl::y1(double cury) const
+{
+ return cury - (m_previousY2 - cury);
+}
+
+void SVGPathSegCurvetoCubicSmoothAbsImpl::getDeltasAndSlopes(double curx, double cury, double *pDx, double *pDy, double *pStartSlope, double *pEndSlope) const
+{
+ double dx = x() - curx;
+ double dy = y() - cury;
+ double startSlope = SVGAngleImpl::todeg(atan2(y1(cury) - cury, x1(curx) - curx));
+ double endSlope = SVGAngleImpl::todeg(atan2(y() - y2(), x() - x2()));
+ *pDx = dx;
+ *pDy = dy;
+ *pStartSlope = startSlope;
+ *pEndSlope = endSlope;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPathSegCurvetoCubicSmoothAbsImpl::s_hashTable 5
+ x SVGPathSegCurvetoCubicSmoothAbsImpl::X DontDelete
+ y SVGPathSegCurvetoCubicSmoothAbsImpl::Y DontDelete
+ x2 SVGPathSegCurvetoCubicSmoothAbsImpl::X2 DontDelete
+ y2 SVGPathSegCurvetoCubicSmoothAbsImpl::Y2 DontDelete
+@end
+*/
+
+Value SVGPathSegCurvetoCubicSmoothAbsImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case X:
+ return Number(x());
+ case Y:
+ return Number(y());
+ case X2:
+ return Number(x2());
+ case Y2:
+ return Number(y2());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGPathSegCurvetoCubicSmoothAbsImpl::putValueProperty(ExecState *exec, int token, const Value &value, int)
+{
+ switch(token)
+ {
+ case X:
+ m_x = value.toNumber(exec);
+ break;
+ case Y:
+ m_y = value.toNumber(exec);
+ break;
+ case X2:
+ m_x2 = value.toNumber(exec);
+ break;
+ case Y2:
+ m_y2 = value.toNumber(exec);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+
+
+SVGPathSegCurvetoCubicSmoothRelImpl::SVGPathSegCurvetoCubicSmoothRelImpl() : SVGPathSegImpl()
+{
+ KSVG_EMPTY_FLAGS
+}
+
+SVGPathSegCurvetoCubicSmoothRelImpl::~SVGPathSegCurvetoCubicSmoothRelImpl()
+{
+}
+
+void SVGPathSegCurvetoCubicSmoothRelImpl::setX(const double &x)
+{
+ m_x = x;
+}
+
+double SVGPathSegCurvetoCubicSmoothRelImpl::x() const
+{
+ return m_x;
+}
+
+void SVGPathSegCurvetoCubicSmoothRelImpl::setY(const double &y)
+{
+ m_y = y;
+}
+
+double SVGPathSegCurvetoCubicSmoothRelImpl::y() const
+{
+ return m_y;
+}
+
+void SVGPathSegCurvetoCubicSmoothRelImpl::setX2(const double &x2)
+{
+ m_x2 = x2;
+}
+
+double SVGPathSegCurvetoCubicSmoothRelImpl::x2() const
+{
+ return m_x2;
+}
+
+void SVGPathSegCurvetoCubicSmoothRelImpl::setY2(const double &y2)
+{
+ m_y2 = y2;
+}
+
+double SVGPathSegCurvetoCubicSmoothRelImpl::y2() const
+{
+ return m_y2;
+}
+
+void SVGPathSegCurvetoCubicSmoothRelImpl::setPreviousAbsX2(double x2)
+{
+ m_previousAbsX2 = x2;
+}
+
+void SVGPathSegCurvetoCubicSmoothRelImpl::setPreviousAbsY2(double y2)
+{
+ m_previousAbsY2 = y2;
+}
+
+double SVGPathSegCurvetoCubicSmoothRelImpl::absX1(double curx) const
+{
+ return curx - (m_previousAbsX2 - curx);
+}
+
+double SVGPathSegCurvetoCubicSmoothRelImpl::absY1(double cury) const
+{
+ return cury - (m_previousAbsY2 - cury);
+}
+
+void SVGPathSegCurvetoCubicSmoothRelImpl::getDeltasAndSlopes(double curx, double cury, double *pDx, double *pDy, double *pStartSlope, double *pEndSlope) const
+{
+ double dx = x();
+ double dy = y();
+ double startSlope = SVGAngleImpl::todeg(atan2(absY1(cury) - cury, absX1(curx) - curx));
+ double endSlope = SVGAngleImpl::todeg(atan2(y() - y2(), x() - x2()));
+ *pDx = dx;
+ *pDy = dy;
+ *pStartSlope = startSlope;
+ *pEndSlope = endSlope;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPathSegCurvetoCubicSmoothRelImpl::s_hashTable 5
+ x SVGPathSegCurvetoCubicSmoothRelImpl::X DontDelete
+ y SVGPathSegCurvetoCubicSmoothRelImpl::Y DontDelete
+ x2 SVGPathSegCurvetoCubicSmoothRelImpl::X2 DontDelete
+ y2 SVGPathSegCurvetoCubicSmoothRelImpl::Y2 DontDelete
+@end
+*/
+
+Value SVGPathSegCurvetoCubicSmoothRelImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case X:
+ return Number(x());
+ case Y:
+ return Number(y());
+ case X2:
+ return Number(x2());
+ case Y2:
+ return Number(y2());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGPathSegCurvetoCubicSmoothRelImpl::putValueProperty(ExecState *exec, int token, const Value &value, int)
+{
+ switch(token)
+ {
+ case X:
+ m_x = value.toNumber(exec);
+ break;
+ case Y:
+ m_y = value.toNumber(exec);
+ break;
+ case X2:
+ m_x2 = value.toNumber(exec);
+ break;
+ case Y2:
+ m_y2 = value.toNumber(exec);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathSegCurvetoCubicSmoothImpl.h b/ksvg/impl/SVGPathSegCurvetoCubicSmoothImpl.h
new file mode 100644
index 00000000..0def6514
--- /dev/null
+++ b/ksvg/impl/SVGPathSegCurvetoCubicSmoothImpl.h
@@ -0,0 +1,139 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathSegCurvetoCubicSmoothImpl_H
+#define SVGPathSegCurvetoCubicSmoothImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGPathSegImpl.h"
+
+namespace KSVG
+{
+
+class SVGPathSegCurvetoCubicSmoothAbsImpl : public SVGPathSegImpl
+{
+public:
+ SVGPathSegCurvetoCubicSmoothAbsImpl();
+ virtual ~SVGPathSegCurvetoCubicSmoothAbsImpl();
+
+ virtual unsigned short pathSegType() const { return PATHSEG_CURVETO_CUBIC_SMOOTH_ABS; }
+ virtual DOM::DOMString pathSegTypeAsLetter() const { return "S"; }
+ virtual QString toString() const { return QString("S %1 %2 %3 %4").arg(m_x2).arg(m_y2).arg(m_x).arg(m_y); }
+
+ void setX(const double &);
+ double x() const;
+
+ void setY(const double &);
+ double y() const;
+
+ void setX2(const double &);
+ double x2() const;
+
+ void setY2(const double &);
+ double y2() const;
+
+ void setPreviousX2(double x2);
+ void setPreviousY2(double y2);
+
+ double x1(double curx) const;
+ double y1(double cury) const;
+
+ virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const;
+
+private:
+ double m_x;
+ double m_y;
+ double m_x2;
+ double m_y2;
+ double m_previousX2;
+ double m_previousY2;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ X, Y, X2, Y2
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+class SVGPathSegCurvetoCubicSmoothRelImpl : public SVGPathSegImpl
+{
+public:
+ SVGPathSegCurvetoCubicSmoothRelImpl();
+ virtual ~SVGPathSegCurvetoCubicSmoothRelImpl();
+
+ virtual unsigned short pathSegType() const { return PATHSEG_CURVETO_CUBIC_SMOOTH_REL; }
+ virtual DOM::DOMString pathSegTypeAsLetter() const { return "s"; }
+ virtual QString toString() const { return QString("s %1 %2 %3 %4").arg(m_x2).arg(m_y2).arg(m_x).arg(m_y); }
+
+ void setX(const double &);
+ double x() const;
+
+ void setY(const double &);
+ double y() const;
+
+ void setX2(const double &);
+ double x2() const;
+
+ void setY2(const double &);
+ double y2() const;
+
+ void setPreviousAbsX2(double x2);
+ void setPreviousAbsY2(double y2);
+
+ double absX1(double curx) const;
+ double absY1(double cury) const;
+
+ virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const;
+
+private:
+ double m_x;
+ double m_y;
+ double m_x2;
+ double m_y2;
+ double m_previousAbsX2;
+ double m_previousAbsY2;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ X, Y, X2, Y2
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathSegCurvetoQuadraticImpl.cc b/ksvg/impl/SVGPathSegCurvetoQuadraticImpl.cc
new file mode 100644
index 00000000..e6199a21
--- /dev/null
+++ b/ksvg/impl/SVGPathSegCurvetoQuadraticImpl.cc
@@ -0,0 +1,260 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGPathSegCurvetoQuadraticImpl.h"
+#include "SVGAngleImpl.h"
+
+using namespace KSVG;
+
+#include "SVGPathSegCurvetoQuadraticImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+SVGPathSegCurvetoQuadraticAbsImpl::SVGPathSegCurvetoQuadraticAbsImpl() : SVGPathSegImpl()
+{
+ KSVG_EMPTY_FLAGS
+}
+
+SVGPathSegCurvetoQuadraticAbsImpl::~SVGPathSegCurvetoQuadraticAbsImpl()
+{
+}
+
+void SVGPathSegCurvetoQuadraticAbsImpl::setX(const double &x)
+{
+ m_x = x;
+}
+
+double SVGPathSegCurvetoQuadraticAbsImpl::x() const
+{
+ return m_x;
+}
+
+void SVGPathSegCurvetoQuadraticAbsImpl::setY(const double &y)
+{
+ m_y = y;
+}
+
+double SVGPathSegCurvetoQuadraticAbsImpl::y() const
+{
+ return m_y;
+}
+
+void SVGPathSegCurvetoQuadraticAbsImpl::setX1(const double &x1)
+{
+ m_x1 = x1;
+}
+
+double SVGPathSegCurvetoQuadraticAbsImpl::x1() const
+{
+ return m_x1;
+}
+
+void SVGPathSegCurvetoQuadraticAbsImpl::setY1(const double &y1)
+{
+ m_y1 = y1;
+}
+
+double SVGPathSegCurvetoQuadraticAbsImpl::y1() const
+{
+ return m_y1;
+}
+
+void SVGPathSegCurvetoQuadraticAbsImpl::getDeltasAndSlopes(double curx, double cury, double *pDx, double *pDy, double *pStartSlope, double *pEndSlope) const
+{
+ double dx = x() - curx;
+ double dy = y() - cury;
+ double startSlope = SVGAngleImpl::todeg(atan2(y1() - cury, x1() - curx));
+ double endSlope = SVGAngleImpl::todeg(atan2(y() - y1(), x() - x1()));
+ *pDx = dx;
+ *pDy = dy;
+ *pStartSlope = startSlope;
+ *pEndSlope = endSlope;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPathSegCurvetoQuadraticAbsImpl::s_hashTable 5
+ x SVGPathSegCurvetoQuadraticAbsImpl::X DontDelete
+ y SVGPathSegCurvetoQuadraticAbsImpl::Y DontDelete
+ x1 SVGPathSegCurvetoQuadraticAbsImpl::X1 DontDelete
+ y1 SVGPathSegCurvetoQuadraticAbsImpl::Y1 DontDelete
+@end
+*/
+
+Value SVGPathSegCurvetoQuadraticAbsImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case X:
+ return Number(x());
+ case Y:
+ return Number(y());
+ case X1:
+ return Number(x1());
+ case Y1:
+ return Number(y1());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGPathSegCurvetoQuadraticAbsImpl::putValueProperty(ExecState *exec, int token, const Value &value, int)
+{
+ switch(token)
+ {
+ case X:
+ m_x = value.toNumber(exec);
+ break;
+ case Y:
+ m_y = value.toNumber(exec);
+ break;
+ case X1:
+ m_x1 = value.toNumber(exec);
+ break;
+ case Y1:
+ m_y1 = value.toNumber(exec);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+
+
+SVGPathSegCurvetoQuadraticRelImpl::SVGPathSegCurvetoQuadraticRelImpl() : SVGPathSegImpl()
+{
+ KSVG_EMPTY_FLAGS
+}
+
+SVGPathSegCurvetoQuadraticRelImpl::~SVGPathSegCurvetoQuadraticRelImpl()
+{
+}
+
+void SVGPathSegCurvetoQuadraticRelImpl::setX(const double &x)
+{
+ m_x = x;
+}
+
+double SVGPathSegCurvetoQuadraticRelImpl::x() const
+{
+ return m_x;
+}
+
+void SVGPathSegCurvetoQuadraticRelImpl::setY(const double &y)
+{
+ m_y = y;
+}
+
+double SVGPathSegCurvetoQuadraticRelImpl::y() const
+{
+ return m_y;
+}
+
+void SVGPathSegCurvetoQuadraticRelImpl::setX1(const double &x1)
+{
+ m_x1 = x1;
+}
+
+double SVGPathSegCurvetoQuadraticRelImpl::x1() const
+{
+ return m_x1;
+}
+
+void SVGPathSegCurvetoQuadraticRelImpl::setY1(const double &y1)
+{
+ m_y1 = y1;
+}
+
+double SVGPathSegCurvetoQuadraticRelImpl::y1() const
+{
+ return m_y1;
+}
+
+void SVGPathSegCurvetoQuadraticRelImpl::getDeltasAndSlopes(double curx, double cury, double *pDx, double *pDy, double *pStartSlope, double *pEndSlope) const
+{
+ Q_UNUSED(curx);
+ Q_UNUSED(cury);
+ double dx = x();
+ double dy = y();
+ double startSlope = SVGAngleImpl::todeg(atan2(y1(), x1()));
+ double endSlope = SVGAngleImpl::todeg(atan2(y() - y1(), x() - x1()));
+ *pDx = dx;
+ *pDy = dy;
+ *pStartSlope = startSlope;
+ *pEndSlope = endSlope;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPathSegCurvetoQuadraticRelImpl::s_hashTable 5
+ x SVGPathSegCurvetoQuadraticRelImpl::X DontDelete
+ y SVGPathSegCurvetoQuadraticRelImpl::Y DontDelete
+ x1 SVGPathSegCurvetoQuadraticRelImpl::X1 DontDelete
+ y1 SVGPathSegCurvetoQuadraticRelImpl::Y1 DontDelete
+@end
+*/
+
+Value SVGPathSegCurvetoQuadraticRelImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case X:
+ return Number(x());
+ case Y:
+ return Number(y());
+ case X1:
+ return Number(x1());
+ case Y1:
+ return Number(y1());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGPathSegCurvetoQuadraticRelImpl::putValueProperty(ExecState *exec, int token, const Value &value, int)
+{
+ switch(token)
+ {
+ case X:
+ m_x = value.toNumber(exec);
+ break;
+ case Y:
+ m_y = value.toNumber(exec);
+ break;
+ case X1:
+ m_x1 = value.toNumber(exec);
+ break;
+ case Y1:
+ m_y1 = value.toNumber(exec);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathSegCurvetoQuadraticImpl.h b/ksvg/impl/SVGPathSegCurvetoQuadraticImpl.h
new file mode 100644
index 00000000..6fe9ef15
--- /dev/null
+++ b/ksvg/impl/SVGPathSegCurvetoQuadraticImpl.h
@@ -0,0 +1,123 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathSegCurvetoQuadraticImpl_H
+#define SVGPathSegCurvetoQuadraticImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGPathSegImpl.h"
+
+namespace KSVG
+{
+
+class SVGPathSegCurvetoQuadraticAbsImpl : public SVGPathSegImpl
+{
+public:
+ SVGPathSegCurvetoQuadraticAbsImpl();
+ virtual ~SVGPathSegCurvetoQuadraticAbsImpl();
+
+ virtual unsigned short pathSegType() const { return PATHSEG_CURVETO_QUADRATIC_ABS; }
+ virtual DOM::DOMString pathSegTypeAsLetter() const { return "Q"; }
+ virtual QString toString() const { return QString("Q %1 %2 %3 %4").arg(m_x1).arg(m_y1).arg(m_x).arg(m_y); }
+
+ void setX(const double &);
+ double x() const;
+
+ void setY(const double &);
+ double y() const;
+
+ void setX1(const double &);
+ double x1() const;
+
+ void setY1(const double &);
+ double y1() const;
+
+ virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const;
+
+private:
+ double m_x;
+ double m_y;
+ double m_x1;
+ double m_y1;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ X, Y, X1, Y1
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+class SVGPathSegCurvetoQuadraticRelImpl : public SVGPathSegImpl
+{
+public:
+ SVGPathSegCurvetoQuadraticRelImpl();
+ virtual ~SVGPathSegCurvetoQuadraticRelImpl();
+
+ virtual unsigned short pathSegType() const { return PATHSEG_CURVETO_QUADRATIC_REL; }
+ virtual DOM::DOMString pathSegTypeAsLetter() const { return "q"; }
+ virtual QString toString() const { return QString("q %1 %2 %3 %4").arg(m_x1).arg(m_y1).arg(m_x).arg(m_y); }
+
+ void setX(const double &);
+ double x() const;
+
+ void setY(const double &);
+ double y() const;
+
+ void setX1(const double &);
+ double x1() const;
+
+ void setY1(const double &);
+ double y1() const;
+
+ virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const;
+
+private:
+ double m_x;
+ double m_y;
+ double m_x1;
+ double m_y1;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ X, Y, X1, Y1
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathSegCurvetoQuadraticSmoothImpl.cc b/ksvg/impl/SVGPathSegCurvetoQuadraticSmoothImpl.cc
new file mode 100644
index 00000000..f8c141da
--- /dev/null
+++ b/ksvg/impl/SVGPathSegCurvetoQuadraticSmoothImpl.cc
@@ -0,0 +1,235 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGPathSegCurvetoQuadraticSmoothImpl.h"
+#include "SVGAngleImpl.h"
+
+using namespace KSVG;
+
+#include "SVGPathSegCurvetoQuadraticSmoothImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+SVGPathSegCurvetoQuadraticSmoothAbsImpl::SVGPathSegCurvetoQuadraticSmoothAbsImpl() : SVGPathSegImpl()
+{
+ KSVG_EMPTY_FLAGS
+}
+
+SVGPathSegCurvetoQuadraticSmoothAbsImpl::~SVGPathSegCurvetoQuadraticSmoothAbsImpl()
+{
+}
+
+void SVGPathSegCurvetoQuadraticSmoothAbsImpl::setX(const double &x)
+{
+ m_x = x;
+}
+
+double SVGPathSegCurvetoQuadraticSmoothAbsImpl::x() const
+{
+ return m_x;
+}
+
+void SVGPathSegCurvetoQuadraticSmoothAbsImpl::setY(const double &y)
+{
+ m_y = y;
+}
+
+double SVGPathSegCurvetoQuadraticSmoothAbsImpl::y() const
+{
+ return m_y;
+}
+
+void SVGPathSegCurvetoQuadraticSmoothAbsImpl::setPreviousX1(double x1)
+{
+ m_previousX1 = x1;
+}
+
+void SVGPathSegCurvetoQuadraticSmoothAbsImpl::setPreviousY1(double y1)
+{
+ m_previousY1 = y1;
+}
+
+double SVGPathSegCurvetoQuadraticSmoothAbsImpl::x1(double curx) const
+{
+ return curx - (m_previousX1 - curx);
+}
+
+double SVGPathSegCurvetoQuadraticSmoothAbsImpl::y1(double cury) const
+{
+ return cury - (m_previousY1 - cury);
+}
+
+void SVGPathSegCurvetoQuadraticSmoothAbsImpl::getDeltasAndSlopes(double curx, double cury, double *pDx, double *pDy, double *pStartSlope, double *pEndSlope) const
+{
+ double dx = x() - curx;
+ double dy = y() - cury;
+ double startSlope = SVGAngleImpl::todeg(atan2(y1(cury) - cury, x1(curx) - curx));
+ double endSlope = SVGAngleImpl::todeg(atan2(y() - y1(cury), x() - x1(curx)));
+ *pDx = dx;
+ *pDy = dy;
+ *pStartSlope = startSlope;
+ *pEndSlope = endSlope;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPathSegCurvetoQuadraticSmoothAbsImpl::s_hashTable 3
+ x SVGPathSegCurvetoQuadraticSmoothAbsImpl::X DontDelete
+ y SVGPathSegCurvetoQuadraticSmoothAbsImpl::Y DontDelete
+@end
+*/
+
+Value SVGPathSegCurvetoQuadraticSmoothAbsImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case X:
+ return Number(x());
+ case Y:
+ return Number(y());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGPathSegCurvetoQuadraticSmoothAbsImpl::putValueProperty(ExecState *exec, int token, const Value &value, int)
+{
+ switch(token)
+ {
+ case X:
+ m_x = value.toNumber(exec);
+ break;
+ case Y:
+ m_y = value.toNumber(exec);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+
+
+
+SVGPathSegCurvetoQuadraticSmoothRelImpl::SVGPathSegCurvetoQuadraticSmoothRelImpl() : SVGPathSegImpl()
+{
+ KSVG_EMPTY_FLAGS
+}
+
+SVGPathSegCurvetoQuadraticSmoothRelImpl::~SVGPathSegCurvetoQuadraticSmoothRelImpl()
+{
+}
+
+void SVGPathSegCurvetoQuadraticSmoothRelImpl::setX(const double &x)
+{
+ m_x = x;
+}
+
+double SVGPathSegCurvetoQuadraticSmoothRelImpl::x() const
+{
+ return m_x;
+}
+
+void SVGPathSegCurvetoQuadraticSmoothRelImpl::setY(const double &y)
+{
+ m_y = y;
+}
+
+double SVGPathSegCurvetoQuadraticSmoothRelImpl::y() const
+{
+ return m_y;
+}
+
+void SVGPathSegCurvetoQuadraticSmoothRelImpl::setPreviousAbsX1(double x1)
+{
+ m_previousAbsX1 = x1;
+}
+
+void SVGPathSegCurvetoQuadraticSmoothRelImpl::setPreviousAbsY1(double y1)
+{
+ m_previousAbsY1 = y1;
+}
+
+double SVGPathSegCurvetoQuadraticSmoothRelImpl::absX1(double curx) const
+{
+ return curx - (m_previousAbsX1 - curx);
+}
+
+double SVGPathSegCurvetoQuadraticSmoothRelImpl::absY1(double cury) const
+{
+ return cury - (m_previousAbsY1 - cury);
+}
+
+void SVGPathSegCurvetoQuadraticSmoothRelImpl::getDeltasAndSlopes(double curx, double cury, double *pDx, double *pDy, double *pStartSlope, double *pEndSlope) const
+{
+ double dx = x();
+ double dy = y();
+ double startSlope = SVGAngleImpl::todeg(atan2(absY1(cury) - cury, absX1(curx) - curx));
+ double endSlope = SVGAngleImpl::todeg(atan2(cury + y() - absY1(cury), curx + x() - absX1(curx)));
+ *pDx = dx;
+ *pDy = dy;
+ *pStartSlope = startSlope;
+ *pEndSlope = endSlope;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPathSegCurvetoQuadraticSmoothRelImpl::s_hashTable 3
+ x SVGPathSegCurvetoQuadraticSmoothRelImpl::X DontDelete
+ y SVGPathSegCurvetoQuadraticSmoothRelImpl::Y DontDelete
+@end
+*/
+
+Value SVGPathSegCurvetoQuadraticSmoothRelImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case X:
+ return Number(x());
+ case Y:
+ return Number(y());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGPathSegCurvetoQuadraticSmoothRelImpl::putValueProperty(ExecState *exec, int token, const Value &value, int)
+{
+ switch(token)
+ {
+ case X:
+ m_x = value.toNumber(exec);
+ break;
+ case Y:
+ m_y = value.toNumber(exec);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathSegCurvetoQuadraticSmoothImpl.h b/ksvg/impl/SVGPathSegCurvetoQuadraticSmoothImpl.h
new file mode 100644
index 00000000..dffa3355
--- /dev/null
+++ b/ksvg/impl/SVGPathSegCurvetoQuadraticSmoothImpl.h
@@ -0,0 +1,123 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathSegCurvetoQuadraticSmoothImpl_H
+#define SVGPathSegCurvetoQuadraticSmoothImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGPathSegImpl.h"
+
+namespace KSVG
+{
+
+class SVGPathSegCurvetoQuadraticSmoothAbsImpl : public SVGPathSegImpl
+{
+public:
+ SVGPathSegCurvetoQuadraticSmoothAbsImpl();
+ virtual ~SVGPathSegCurvetoQuadraticSmoothAbsImpl();
+
+ virtual unsigned short pathSegType() const { return PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS; }
+ virtual DOM::DOMString pathSegTypeAsLetter() const { return "T"; }
+ virtual QString toString() const { return QString("T %1 %2").arg(m_x).arg(m_y); }
+
+ void setX(const double &);
+ double x() const;
+
+ void setY(const double &);
+ double y() const;
+
+ void setPreviousX1(double x1);
+ void setPreviousY1(double y1);
+
+ double x1(double curx) const;
+ double y1(double cury) const;
+
+ virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const;
+
+private:
+ double m_x;
+ double m_y;
+ double m_previousX1;
+ double m_previousY1;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ X, Y
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+class SVGPathSegCurvetoQuadraticSmoothRelImpl : public SVGPathSegImpl
+{
+public:
+ SVGPathSegCurvetoQuadraticSmoothRelImpl();
+ virtual ~SVGPathSegCurvetoQuadraticSmoothRelImpl();
+
+ virtual unsigned short pathSegType() const { return PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL; }
+ virtual DOM::DOMString pathSegTypeAsLetter() const { return "t"; }
+ virtual QString toString() const { return QString("t %1 %2").arg(m_x).arg(m_y); }
+
+ void setX(const double &);
+ double x() const;
+
+ void setY(const double &);
+ double y() const;
+
+ void setPreviousAbsX1(double x1);
+ void setPreviousAbsY1(double y1);
+
+ double absX1(double curx) const;
+ double absY1(double cury) const;
+
+ virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const;
+
+private:
+ double m_x;
+ double m_y;
+ double m_previousAbsX1;
+ double m_previousAbsY1;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ X, Y
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathSegImpl.cc b/ksvg/impl/SVGPathSegImpl.cc
new file mode 100644
index 00000000..c1f2934d
--- /dev/null
+++ b/ksvg/impl/SVGPathSegImpl.cc
@@ -0,0 +1,107 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGPathSegImpl.h"
+
+using namespace KSVG;
+
+#include "SVGPathSegImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_cacheimpl.h"
+
+SVGPathSegImpl::SVGPathSegImpl()
+{
+}
+
+SVGPathSegImpl::~SVGPathSegImpl()
+{
+}
+
+void SVGPathSegImpl::getDeltasAndSlopes(double, double, double *dx, double *dy, double *startSlope, double *endSlope) const
+{
+ *dx = 0;
+ *dy = 0;
+ *startSlope = 0;
+ *endSlope = 0;
+}
+
+// Exma stuff
+
+/*
+@namespace KSVG
+@begin SVGPathSegImpl::s_hashTable 3
+ pathSegType SVGPathSegImpl::PathSegType DontDelete|ReadOnly
+ pathSegTypeAsLetter SVGPathSegImpl::PathSegTypeAsLetter DontDelete|ReadOnly
+@end
+*/
+
+Value SVGPathSegImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case PathSegType:
+ return Number(pathSegType());
+ case PathSegTypeAsLetter:
+ return String(pathSegTypeAsLetter().string());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+/*
+@namespace KSVG
+@begin SVGPathSegImplConstructor::s_hashTable 23
+ PATHSEG_UNKNOWN KSVG::PATHSEG_UNKNOWN DontDelete|ReadOnly
+ PATHSEG_CLOSEPATH KSVG::PATHSEG_CLOSEPATH DontDelete|ReadOnly
+ PATHSEG_MOVETO_ABS KSVG::PATHSEG_MOVETO_ABS DontDelete|ReadOnly
+ PATHSEG_MOVETO_REL KSVG::PATHSEG_MOVETO_REL DontDelete|ReadOnly
+ PATHSEG_LINETO_ABS KSVG::PATHSEG_LINETO_ABS DontDelete|ReadOnly
+ PATHSEG_LINETO_REL KSVG::PATHSEG_LINETO_REL DontDelete|ReadOnly
+ PATHSEG_CURVETO_CUBIC_ABS KSVG::PATHSEG_CURVETO_CUBIC_ABS DontDelete|ReadOnly
+ PATHSEG_CURVETO_CUBIC_REL KSVG::PATHSEG_CURVETO_CUBIC_REL DontDelete|ReadOnly
+ PATHSEG_CURVETO_QUADRATIC_ABS KSVG::PATHSEG_CURVETO_QUADRATIC_ABS DontDelete|ReadOnly
+ PATHSEG_CURVETO_QUADRATIC_REL KSVG::PATHSEG_CURVETO_QUADRATIC_REL DontDelete|ReadOnly
+ PATHSEG_ARC_ABS KSVG::PATHSEG_ARC_ABS DontDelete|ReadOnly
+ PATHSEG_ARC_REL KSVG::PATHSEG_ARC_REL DontDelete|ReadOnly
+ PATHSEG_LINETO_HORIZONTAL_ABS KSVG::PATHSEG_LINETO_HORIZONTAL_ABS DontDelete|ReadOnly
+ PATHSEG_LINETO_HORIZONTAL_REL KSVG::PATHSEG_LINETO_HORIZONTAL_REL DontDelete|ReadOnly
+ PATHSEG_LINETO_VERTICAL_ABS KSVG::PATHSEG_LINETO_VERTICAL_ABS DontDelete|ReadOnly
+ PATHSEG_LINETO_VERTICAL_REL KSVG::PATHSEG_LINETO_VERTICAL_REL DontDelete|ReadOnly
+ PATHSEG_CURVETO_CUBIC_SMOOTH_ABS KSVG::PATHSEG_CURVETO_CUBIC_SMOOTH_ABS DontDelete|ReadOnly
+ PATHSEG_CURVETO_CUBIC_SMOOTH_REL KSVG::PATHSEG_CURVETO_CUBIC_SMOOTH_REL DontDelete|ReadOnly
+ PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS KSVG::PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS DontDelete|ReadOnly
+ PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL KSVG::PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL DontDelete|ReadOnly
+@end
+*/
+
+Value SVGPathSegImplConstructor::getValueProperty(ExecState *, int token) const
+{
+ return Number(token);
+}
+
+Value KSVG::getSVGPathSegImplConstructor(ExecState *exec)
+{
+ return cacheGlobalBridge<SVGPathSegImplConstructor>(exec, "[[svgpathseg.constructor]]");
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathSegImpl.h b/ksvg/impl/SVGPathSegImpl.h
new file mode 100644
index 00000000..64d8b5b0
--- /dev/null
+++ b/ksvg/impl/SVGPathSegImpl.h
@@ -0,0 +1,75 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathSegImpl_H
+#define SVGPathSegImpl_H
+
+#include <dom/dom_misc.h>
+
+#include "ksvg_lookup.h"
+
+#include "SVGPathSeg.h"
+
+namespace KSVG
+{
+
+class SVGPathElementImpl;
+class SVGPathSegImpl : public DOM::DomShared
+{
+public:
+ SVGPathSegImpl();
+ virtual ~SVGPathSegImpl();
+
+ virtual unsigned short pathSegType() const { return PATHSEG_UNKNOWN; }
+ virtual DOM::DOMString pathSegTypeAsLetter() const { return ""; }
+ virtual QString toString() const { return ""; }
+
+ virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const;
+
+public:
+ KSVG_BASECLASS_GET
+
+ enum
+ {
+ // Properties
+ PathSegType, PathSegTypeAsLetter
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+
+};
+
+class SVGPathSegImplConstructor : public KJS::ObjectImp
+{
+public:
+ SVGPathSegImplConstructor(KJS::ExecState *) { }
+ KJS::Value getValueProperty(KJS::ExecState *, int token) const;
+
+ // no put - all read-only
+ KSVG_GET
+};
+
+KJS::Value getSVGPathSegImplConstructor(KJS::ExecState *exec);
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathSegLinetoHorizontalImpl.cc b/ksvg/impl/SVGPathSegLinetoHorizontalImpl.cc
new file mode 100644
index 00000000..e36e49de
--- /dev/null
+++ b/ksvg/impl/SVGPathSegLinetoHorizontalImpl.cc
@@ -0,0 +1,167 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGPathSegLinetoHorizontalImpl.h"
+#include "SVGAngleImpl.h"
+
+using namespace KSVG;
+
+#include "SVGPathSegLinetoHorizontalImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+SVGPathSegLinetoHorizontalAbsImpl::SVGPathSegLinetoHorizontalAbsImpl() : SVGPathSegImpl()
+{
+ KSVG_EMPTY_FLAGS
+}
+
+SVGPathSegLinetoHorizontalAbsImpl::~SVGPathSegLinetoHorizontalAbsImpl()
+{
+}
+
+void SVGPathSegLinetoHorizontalAbsImpl::setX(const double &x)
+{
+ m_x = x;
+}
+
+double SVGPathSegLinetoHorizontalAbsImpl::x() const
+{
+ return m_x;
+}
+
+void SVGPathSegLinetoHorizontalAbsImpl::getDeltasAndSlopes(double curx, double cury, double *pdx, double *pdy, double *pstartSlope, double *pendSlope) const
+{
+ Q_UNUSED(cury);
+ double dx = x() - curx;
+ double dy = 0;
+ double startSlope = SVGAngleImpl::todeg(atan2(dy, dx));
+ double endSlope = startSlope;
+ *pdx = dx;
+ *pdy = dy;
+ *pstartSlope = startSlope;
+ *pendSlope = endSlope;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPathSegLinetoHorizontalAbsImpl::s_hashTable 2
+ x SVGPathSegLinetoHorizontalAbsImpl::X DontDelete
+@end
+*/
+
+Value SVGPathSegLinetoHorizontalAbsImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case X:
+ return Number(x());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGPathSegLinetoHorizontalAbsImpl::putValueProperty(ExecState *exec, int token, const Value &value, int)
+{
+ switch(token)
+ {
+ case X:
+ m_x = value.toNumber(exec);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+
+
+
+
+SVGPathSegLinetoHorizontalRelImpl::SVGPathSegLinetoHorizontalRelImpl() : SVGPathSegImpl()
+{
+ KSVG_EMPTY_FLAGS
+}
+
+SVGPathSegLinetoHorizontalRelImpl::~SVGPathSegLinetoHorizontalRelImpl()
+{
+}
+
+void SVGPathSegLinetoHorizontalRelImpl::setX(const double &x)
+{
+ m_x = x;
+}
+
+double SVGPathSegLinetoHorizontalRelImpl::x() const
+{
+ return m_x;
+}
+
+void SVGPathSegLinetoHorizontalRelImpl::getDeltasAndSlopes(double curx, double cury, double *pdx, double *pdy, double *pstartSlope, double *pendSlope) const
+{
+ Q_UNUSED(curx);
+ Q_UNUSED(cury);
+ double dx = x();
+ double dy = 0;
+ double startSlope = SVGAngleImpl::todeg(atan2(dy, dx));
+ double endSlope = startSlope;
+ *pdx = dx;
+ *pdy = dy;
+ *pstartSlope = startSlope;
+ *pendSlope = endSlope;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPathSegLinetoHorizontalRelImpl::s_hashTable 2
+ x SVGPathSegLinetoHorizontalRelImpl::X DontDelete
+@end
+*/
+
+Value SVGPathSegLinetoHorizontalRelImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case X:
+ return Number(x());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGPathSegLinetoHorizontalRelImpl::putValueProperty(ExecState *exec, int token, const Value &value, int)
+{
+ switch(token)
+ {
+ case X:
+ m_x = value.toNumber(exec);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathSegLinetoHorizontalImpl.h b/ksvg/impl/SVGPathSegLinetoHorizontalImpl.h
new file mode 100644
index 00000000..020d29d7
--- /dev/null
+++ b/ksvg/impl/SVGPathSegLinetoHorizontalImpl.h
@@ -0,0 +1,99 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathSegLinetoHorizontalImpl_H
+#define SVGPathSegLinetoHorizontalImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGPathSegImpl.h"
+
+namespace KSVG
+{
+
+class SVGPathSegLinetoHorizontalAbsImpl : public SVGPathSegImpl
+{
+public:
+ SVGPathSegLinetoHorizontalAbsImpl();
+ virtual ~SVGPathSegLinetoHorizontalAbsImpl();
+
+ virtual unsigned short pathSegType() const { return PATHSEG_LINETO_HORIZONTAL_ABS; }
+ virtual DOM::DOMString pathSegTypeAsLetter() const { return "H"; }
+ virtual QString toString() const { return QString("H %1").arg(m_x); }
+
+ void setX(const double &);
+ double x() const;
+
+ virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const;
+
+private:
+ double m_x;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ X
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+class SVGPathSegLinetoHorizontalRelImpl : public SVGPathSegImpl
+{
+public:
+ SVGPathSegLinetoHorizontalRelImpl();
+ virtual ~SVGPathSegLinetoHorizontalRelImpl();
+
+ virtual unsigned short pathSegType() const { return PATHSEG_LINETO_HORIZONTAL_REL; }
+ virtual DOM::DOMString pathSegTypeAsLetter() const { return "h"; }
+ virtual QString toString() const { return QString("h %1").arg(m_x); }
+
+ void setX(const double &);
+ double x() const;
+
+ virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const;
+
+private:
+ double m_x;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ X
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathSegLinetoImpl.cc b/ksvg/impl/SVGPathSegLinetoImpl.cc
new file mode 100644
index 00000000..04203352
--- /dev/null
+++ b/ksvg/impl/SVGPathSegLinetoImpl.cc
@@ -0,0 +1,196 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGPathSegLinetoImpl.h"
+#include "SVGAngleImpl.h"
+
+using namespace KSVG;
+
+#include "SVGPathSegLinetoImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+SVGPathSegLinetoAbsImpl::SVGPathSegLinetoAbsImpl() : SVGPathSegImpl()
+{
+ KSVG_EMPTY_FLAGS
+}
+
+SVGPathSegLinetoAbsImpl::~SVGPathSegLinetoAbsImpl()
+{
+}
+
+void SVGPathSegLinetoAbsImpl::setX(const double &x)
+{
+ m_x = x;
+}
+
+double SVGPathSegLinetoAbsImpl::x() const
+{
+ return m_x;
+}
+
+void SVGPathSegLinetoAbsImpl::setY(const double &y)
+{
+ m_y = y;
+}
+
+double SVGPathSegLinetoAbsImpl::y() const
+{
+ return m_y;
+}
+
+void SVGPathSegLinetoAbsImpl::getDeltasAndSlopes(double curx, double cury, double *pdx, double *pdy, double *pstartSlope, double *pendSlope) const
+{
+ double dx = x() - curx;
+ double dy = y() - cury;
+ double startSlope = SVGAngleImpl::todeg(atan2(dy, dx));
+ double endSlope = startSlope;
+ *pdx = dx;
+ *pdy = dy;
+ *pstartSlope = startSlope;
+ *pendSlope = endSlope;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPathSegLinetoAbsImpl::s_hashTable 3
+ x SVGPathSegLinetoAbsImpl::X DontDelete
+ y SVGPathSegLinetoAbsImpl::Y DontDelete
+@end
+*/
+
+Value SVGPathSegLinetoAbsImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case X:
+ return Number(x());
+ case Y:
+ return Number(y());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGPathSegLinetoAbsImpl::putValueProperty(ExecState *exec, int token, const Value &value, int)
+{
+ switch(token)
+ {
+ case X:
+ m_x = value.toNumber(exec);
+ break;
+ case Y:
+ m_y = value.toNumber(exec);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+
+
+SVGPathSegLinetoRelImpl::SVGPathSegLinetoRelImpl() : SVGPathSegImpl()
+{
+ KSVG_EMPTY_FLAGS
+}
+
+SVGPathSegLinetoRelImpl::~SVGPathSegLinetoRelImpl()
+{
+}
+
+void SVGPathSegLinetoRelImpl::setX(const double &x)
+{
+ m_x = x;
+}
+
+double SVGPathSegLinetoRelImpl::x() const
+{
+ return m_x;
+}
+
+void SVGPathSegLinetoRelImpl::setY(const double &y)
+{
+ m_y = y;
+}
+
+double SVGPathSegLinetoRelImpl::y() const
+{
+ return m_y;
+}
+
+void SVGPathSegLinetoRelImpl::getDeltasAndSlopes(double curx, double cury, double *pdx, double *pdy, double *pstartSlope, double *pendSlope) const
+{
+ Q_UNUSED(curx);
+ Q_UNUSED(cury);
+ double dx = x();
+ double dy = y();
+ double startSlope = SVGAngleImpl::todeg(atan2(dy, dx));
+ double endSlope = startSlope;
+ *pdx = dx;
+ *pdy = dy;
+ *pstartSlope = startSlope;
+ *pendSlope = endSlope;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPathSegLinetoRelImpl::s_hashTable 3
+ x SVGPathSegLinetoRelImpl::X DontDelete
+ y SVGPathSegLinetoRelImpl::Y DontDelete
+@end
+*/
+
+Value SVGPathSegLinetoRelImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case X:
+ return Number(x());
+ case Y:
+ return Number(y());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGPathSegLinetoRelImpl::putValueProperty(ExecState *exec, int token, const Value &value, int)
+{
+ switch(token)
+ {
+ case X:
+ m_x = value.toNumber(exec);
+ break;
+ case Y:
+ m_y = value.toNumber(exec);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathSegLinetoImpl.h b/ksvg/impl/SVGPathSegLinetoImpl.h
new file mode 100644
index 00000000..3e315022
--- /dev/null
+++ b/ksvg/impl/SVGPathSegLinetoImpl.h
@@ -0,0 +1,107 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathSegLinetoImpl_H
+#define SVGPathSegLinetoImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGPathSegImpl.h"
+
+namespace KSVG
+{
+
+class SVGPathSegLinetoAbsImpl : public SVGPathSegImpl
+{
+public:
+ SVGPathSegLinetoAbsImpl();
+ virtual ~SVGPathSegLinetoAbsImpl();
+
+ virtual unsigned short pathSegType() const { return PATHSEG_LINETO_ABS; }
+ virtual DOM::DOMString pathSegTypeAsLetter() const { return "L"; }
+ virtual QString toString() const { return QString("L %1 %2").arg(m_x).arg(m_y); }
+
+ void setX(const double &);
+ double x() const;
+
+ void setY(const double &);
+ double y() const;
+
+ virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const;
+
+private:
+ double m_x;
+ double m_y;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ X, Y
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+class SVGPathSegLinetoRelImpl : public SVGPathSegImpl
+{
+public:
+ SVGPathSegLinetoRelImpl();
+ virtual ~SVGPathSegLinetoRelImpl();
+
+ virtual unsigned short pathSegType() const { return PATHSEG_LINETO_REL; }
+ virtual DOM::DOMString pathSegTypeAsLetter() const { return "l"; }
+ virtual QString toString() const { return QString("l %1 %2").arg(m_x).arg(m_y); }
+
+ void setX(const double &);
+ double x() const;
+
+ void setY(const double &);
+ double y() const;
+
+ virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const;
+
+private:
+ double m_x;
+ double m_y;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ X, Y
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathSegLinetoVerticalImpl.cc b/ksvg/impl/SVGPathSegLinetoVerticalImpl.cc
new file mode 100644
index 00000000..0eca1280
--- /dev/null
+++ b/ksvg/impl/SVGPathSegLinetoVerticalImpl.cc
@@ -0,0 +1,165 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGPathSegLinetoVerticalImpl.h"
+#include "SVGAngleImpl.h"
+
+using namespace KSVG;
+
+#include "SVGPathSegLinetoVerticalImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+SVGPathSegLinetoVerticalAbsImpl::SVGPathSegLinetoVerticalAbsImpl() : SVGPathSegImpl()
+{
+ KSVG_EMPTY_FLAGS
+}
+
+SVGPathSegLinetoVerticalAbsImpl::~SVGPathSegLinetoVerticalAbsImpl()
+{
+}
+
+void SVGPathSegLinetoVerticalAbsImpl::setY(const double &y)
+{
+ m_y = y;
+}
+
+double SVGPathSegLinetoVerticalAbsImpl::y() const
+{
+ return m_y;
+}
+
+void SVGPathSegLinetoVerticalAbsImpl::getDeltasAndSlopes(double curx, double cury, double *pdx, double *pdy, double *pstartSlope, double *pendSlope) const
+{
+ Q_UNUSED(curx);
+ double dx = 0;
+ double dy = y() - cury;
+ double startSlope = SVGAngleImpl::todeg(atan2(dy, dx));
+ double endSlope = startSlope;
+ *pdx = dx;
+ *pdy = dy;
+ *pstartSlope = startSlope;
+ *pendSlope = endSlope;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPathSegLinetoVerticalAbsImpl::s_hashTable 2
+ y SVGPathSegLinetoVerticalAbsImpl::Y DontDelete
+@end
+*/
+
+Value SVGPathSegLinetoVerticalAbsImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case Y:
+ return Number(y());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGPathSegLinetoVerticalAbsImpl::putValueProperty(ExecState *exec, int token, const Value &value, int)
+{
+ switch(token)
+ {
+ case Y:
+ m_y = value.toNumber(exec);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+
+
+SVGPathSegLinetoVerticalRelImpl::SVGPathSegLinetoVerticalRelImpl() : SVGPathSegImpl()
+{
+ KSVG_EMPTY_FLAGS
+}
+
+SVGPathSegLinetoVerticalRelImpl::~SVGPathSegLinetoVerticalRelImpl()
+{
+}
+
+void SVGPathSegLinetoVerticalRelImpl::setY(const double &y)
+{
+ m_y = y;
+}
+
+double SVGPathSegLinetoVerticalRelImpl::y() const
+{
+ return m_y;
+}
+
+void SVGPathSegLinetoVerticalRelImpl::getDeltasAndSlopes(double curx, double cury, double *pdx, double *pdy, double *pstartSlope, double *pendSlope) const
+{
+ Q_UNUSED(curx);
+ Q_UNUSED(cury);
+ double dx = 0;
+ double dy = y();
+ double startSlope = SVGAngleImpl::todeg(atan2(dy, dx));
+ double endSlope = startSlope;
+ *pdx = dx;
+ *pdy = dy;
+ *pstartSlope = startSlope;
+ *pendSlope = endSlope;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPathSegLinetoVerticalRelImpl::s_hashTable 2
+ y SVGPathSegLinetoVerticalRelImpl::Y DontDelete
+@end
+*/
+
+Value SVGPathSegLinetoVerticalRelImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case Y:
+ return Number(y());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGPathSegLinetoVerticalRelImpl::putValueProperty(ExecState *exec, int token, const Value &value, int)
+{
+ switch(token)
+ {
+ case Y:
+ m_y = value.toNumber(exec);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathSegLinetoVerticalImpl.h b/ksvg/impl/SVGPathSegLinetoVerticalImpl.h
new file mode 100644
index 00000000..c50906d9
--- /dev/null
+++ b/ksvg/impl/SVGPathSegLinetoVerticalImpl.h
@@ -0,0 +1,99 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathSegLinetoVerticalImpl_H
+#define SVGPathSegLinetoVerticalImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGPathSegImpl.h"
+
+namespace KSVG
+{
+
+class SVGPathSegLinetoVerticalAbsImpl : public SVGPathSegImpl
+{
+public:
+ SVGPathSegLinetoVerticalAbsImpl();
+ virtual~SVGPathSegLinetoVerticalAbsImpl();
+
+ virtual unsigned short pathSegType() const { return PATHSEG_LINETO_VERTICAL_ABS; }
+ virtual DOM::DOMString pathSegTypeAsLetter() const { return "V"; }
+ virtual QString toString() const { return QString("V %1").arg(m_y); }
+
+ void setY(const double &);
+ double y() const;
+
+ virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const;
+
+private:
+ double m_y;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ Y
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+class SVGPathSegLinetoVerticalRelImpl : public SVGPathSegImpl
+{
+public:
+ SVGPathSegLinetoVerticalRelImpl();
+ virtual ~SVGPathSegLinetoVerticalRelImpl();
+
+ virtual unsigned short pathSegType() const { return PATHSEG_LINETO_VERTICAL_REL; }
+ virtual DOM::DOMString pathSegTypeAsLetter() const { return "v"; }
+ virtual QString toString() const { return QString("v %1").arg(m_y); }
+
+ void setY(const double &);
+ double y() const;
+
+ virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const;
+
+private:
+ double m_y;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ Y
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathSegListImpl.cc b/ksvg/impl/SVGPathSegListImpl.cc
new file mode 100644
index 00000000..ee316938
--- /dev/null
+++ b/ksvg/impl/SVGPathSegListImpl.cc
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGPathSegListImpl.h"
+
+using namespace KSVG;
+
+#include "SVGPathSegListImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPathSegListImpl::s_hashTable 2
+ numberOfItems SVGListDefs::NumberOfItems DontDelete|ReadOnly
+@end
+@namespace KSVG
+@begin SVGPathSegListImplProto::s_hashTable 11
+ getItem SVGListDefs::GetItem DontDelete|Function 1
+ removeItem SVGListDefs::RemoveItem DontDelete|Function 1
+ appendItem SVGListDefs::AppendItem DontDelete|Function 1
+ initialize SVGListDefs::Initialize DontDelete|Function 1
+ insertItemBefore SVGListDefs::InsertItemBefore DontDelete|Function 2
+ replaceItem SVGListDefs::ReplaceItem DontDelete|Function 2
+ clear SVGListDefs::Clear DontDelete|Function 0
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGPathSegList", SVGPathSegListImplProto, SVGPathSegListImplProtoFunc)
+
+Value SVGPathSegListImpl::getValueProperty(ExecState *exec, int token) const
+{
+ return SVGList<SVGPathSegImpl>::getValueProperty(exec, token);
+}
+
+Value SVGPathSegListImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGPathSegListImpl)
+
+ return obj->call(exec, static_cast<SVGList<SVGPathSegImpl> *>(obj), args, id);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathSegListImpl.h b/ksvg/impl/SVGPathSegListImpl.h
new file mode 100644
index 00000000..ef9c8c6e
--- /dev/null
+++ b/ksvg/impl/SVGPathSegListImpl.h
@@ -0,0 +1,48 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathSegListImpl_H
+#define SVGPathSegListImpl_H
+
+#include "SVGList.h"
+
+#include "SVGPathSegImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGPathSegListImpl : public SVGList<SVGPathSegImpl>
+{
+public:
+ KSVG_GET
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+};
+
+}
+
+KSVG_DEFINE_PROTOTYPE(SVGPathSegListImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGPathSegListImplProtoFunc, SVGPathSegListImpl)
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathSegMovetoImpl.cc b/ksvg/impl/SVGPathSegMovetoImpl.cc
new file mode 100644
index 00000000..2eb64b41
--- /dev/null
+++ b/ksvg/impl/SVGPathSegMovetoImpl.cc
@@ -0,0 +1,196 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGPathSegMovetoImpl.h"
+#include "SVGAngleImpl.h"
+
+using namespace KSVG;
+
+#include "SVGPathSegMovetoImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+SVGPathSegMovetoAbsImpl::SVGPathSegMovetoAbsImpl() : SVGPathSegImpl()
+{
+ KSVG_EMPTY_FLAGS
+}
+
+SVGPathSegMovetoAbsImpl::~SVGPathSegMovetoAbsImpl()
+{
+}
+
+void SVGPathSegMovetoAbsImpl::setX(const double &x)
+{
+ m_x = x;
+}
+
+double SVGPathSegMovetoAbsImpl::x() const
+{
+ return m_x;
+}
+
+void SVGPathSegMovetoAbsImpl::setY(const double &y)
+{
+ m_y = y;
+}
+
+double SVGPathSegMovetoAbsImpl::y() const
+{
+ return m_y;
+}
+
+void SVGPathSegMovetoAbsImpl::getDeltasAndSlopes(double curx, double cury, double *pdx, double *pdy, double *pstartSlope, double *pendSlope) const
+{
+ double dx = x() - curx;
+ double dy = y() - cury;
+ double startSlope = 0;
+ double endSlope = 0;
+ *pdx = dx;
+ *pdy = dy;
+ *pstartSlope = startSlope;
+ *pendSlope = endSlope;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPathSegMovetoAbsImpl::s_hashTable 3
+ x SVGPathSegMovetoAbsImpl::X DontDelete
+ y SVGPathSegMovetoAbsImpl::Y DontDelete
+@end
+*/
+
+Value SVGPathSegMovetoAbsImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case X:
+ return Number(x());
+ case Y:
+ return Number(y());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGPathSegMovetoAbsImpl::putValueProperty(ExecState *exec, int token, const Value &value, int)
+{
+ switch(token)
+ {
+ case X:
+ m_x = value.toNumber(exec);
+ break;
+ case Y:
+ m_y = value.toNumber(exec);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+
+
+SVGPathSegMovetoRelImpl::SVGPathSegMovetoRelImpl() : SVGPathSegImpl()
+{
+ KSVG_EMPTY_FLAGS
+}
+
+SVGPathSegMovetoRelImpl::~SVGPathSegMovetoRelImpl()
+{
+}
+
+void SVGPathSegMovetoRelImpl::setX(const double &x)
+{
+ m_x = x;
+}
+
+double SVGPathSegMovetoRelImpl::x() const
+{
+ return m_x;
+}
+
+void SVGPathSegMovetoRelImpl::setY(const double &y)
+{
+ m_y = y;
+}
+
+double SVGPathSegMovetoRelImpl::y() const
+{
+ return m_y;
+}
+
+void SVGPathSegMovetoRelImpl::getDeltasAndSlopes(double curx, double cury, double *pdx, double *pdy, double *pstartSlope, double *pendSlope) const
+{
+ Q_UNUSED(curx);
+ Q_UNUSED(cury);
+ double dx = x();
+ double dy = y();
+ double startSlope = 0;
+ double endSlope = 0;
+ *pdx = dx;
+ *pdy = dy;
+ *pstartSlope = startSlope;
+ *pendSlope = endSlope;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPathSegMovetoRelImpl::s_hashTable 3
+ x SVGPathSegMovetoRelImpl::X DontDelete
+ y SVGPathSegMovetoRelImpl::Y DontDelete
+@end
+*/
+
+Value SVGPathSegMovetoRelImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case X:
+ return Number(x());
+ case Y:
+ return Number(y());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGPathSegMovetoRelImpl::putValueProperty(ExecState *exec, int token, const Value &value, int)
+{
+ switch(token)
+ {
+ case X:
+ m_x = value.toNumber(exec);
+ break;
+ case Y:
+ m_y = value.toNumber(exec);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPathSegMovetoImpl.h b/ksvg/impl/SVGPathSegMovetoImpl.h
new file mode 100644
index 00000000..dfbad355
--- /dev/null
+++ b/ksvg/impl/SVGPathSegMovetoImpl.h
@@ -0,0 +1,107 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPathSegMovetoImpl_H
+#define SVGPathSegMovetoImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGPathSegImpl.h"
+
+namespace KSVG
+{
+
+class SVGPathSegMovetoAbsImpl : public SVGPathSegImpl
+{
+public:
+ SVGPathSegMovetoAbsImpl();
+ virtual ~SVGPathSegMovetoAbsImpl();
+
+ virtual unsigned short pathSegType() const { return PATHSEG_MOVETO_ABS; }
+ virtual DOM::DOMString pathSegTypeAsLetter() const { return "M"; }
+ virtual QString toString() const { return QString("M %1 %2").arg(m_x).arg(m_y); }
+
+ void setX(const double &);
+ double x() const;
+
+ void setY(const double &);
+ double y() const;
+
+ virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const;
+
+private:
+ double m_x;
+ double m_y;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ X, Y
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+class SVGPathSegMovetoRelImpl : public SVGPathSegImpl
+{
+public:
+ SVGPathSegMovetoRelImpl();
+ virtual ~SVGPathSegMovetoRelImpl();
+
+ virtual unsigned short pathSegType() const { return PATHSEG_MOVETO_REL; }
+ virtual DOM::DOMString pathSegTypeAsLetter() const { return "m"; }
+ virtual QString toString() const { return QString("m %1 %2").arg(m_x).arg(m_y); }
+
+ void setX(const double &);
+ double x() const;
+
+ void setY(const double &);
+ double y() const;
+
+ virtual void getDeltasAndSlopes(double curx, double cury, double *dx, double *dy, double *startSlope, double *endSlope) const;
+
+private:
+ double m_x;
+ double m_y;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ X, Y
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPatternElementImpl.cc b/ksvg/impl/SVGPatternElementImpl.cc
new file mode 100644
index 00000000..0b591487
--- /dev/null
+++ b/ksvg/impl/SVGPatternElementImpl.cc
@@ -0,0 +1,509 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "SVGPatternElement.h"
+#include "SVGPatternElementImpl.h"
+
+#include "CanvasFactory.h"
+#include "KSVGCanvas.h"
+#include "CanvasItems.h"
+#include "SVGHelperImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGTransformListImpl.h"
+#include "SVGAnimatedTransformListImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGAnimatedEnumerationImpl.h"
+#include "SVGAnimatedStringImpl.h"
+#include "SVGUnitConverter.h"
+#include "SVGShapeImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGMatrixImpl.h"
+#include "SVGRectImpl.h"
+
+using namespace KSVG;
+
+#include "SVGPatternElementImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+
+QValueList<SVGPatternElementImpl *> SVGPatternElementImpl::m_patternElements;
+
+SVGPatternElementImpl::SVGPatternElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGURIReferenceImpl(), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGFitToViewBoxImpl(), SVGPaintServerImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_patternUnits = new SVGAnimatedEnumerationImpl();
+ m_patternUnits->ref();
+
+ m_patternContentUnits = new SVGAnimatedEnumerationImpl();
+ m_patternContentUnits->ref();
+
+ m_patternTransform = new SVGAnimatedTransformListImpl();
+ m_patternTransform->ref();
+
+ m_x = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this);
+ m_x->ref();
+
+ m_y = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this);
+ m_y->ref();
+
+ m_width = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this);
+ m_width->ref();
+
+ m_height = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this);
+ m_height->ref();
+
+ m_converter = new SVGUnitConverter();
+ m_converter->add(m_x);
+ m_converter->add(m_y);
+ m_converter->add(m_width);
+ m_converter->add(m_height);
+
+ m_patternElements.append(this);
+
+ m_canvas = 0;
+ m_location = this;
+
+ m_tileCache.setMaxTotalCost(1024 * 1024);
+}
+
+SVGPatternElementImpl::~SVGPatternElementImpl()
+{
+ if(m_patternUnits)
+ m_patternUnits->deref();
+ if(m_patternContentUnits)
+ m_patternContentUnits->deref();
+ if(m_patternTransform)
+ m_patternTransform->deref();
+ if(m_x)
+ m_x->deref();
+ if(m_y)
+ m_y->deref();
+ if(m_width)
+ m_width->deref();
+ if(m_height)
+ m_height->deref();
+ delete m_converter;
+ m_patternElements.remove(this);
+}
+
+SVGAnimatedEnumerationImpl *SVGPatternElementImpl::patternUnits() const
+{
+ return m_patternUnits;
+}
+
+SVGAnimatedEnumerationImpl *SVGPatternElementImpl::patternContentUnits() const
+{
+ return m_patternContentUnits;
+}
+
+SVGAnimatedTransformListImpl *SVGPatternElementImpl::patternTransform() const
+{
+ return m_patternTransform;
+}
+
+SVGAnimatedLengthImpl *SVGPatternElementImpl::x() const
+{
+ return m_x;
+}
+
+SVGAnimatedLengthImpl *SVGPatternElementImpl::y() const
+{
+ return m_y;
+}
+
+SVGAnimatedLengthImpl *SVGPatternElementImpl::width() const
+{
+ return m_width;
+}
+
+SVGAnimatedLengthImpl *SVGPatternElementImpl::height() const
+{
+ return m_height;
+}
+
+void SVGPatternElementImpl::createItem(KSVGCanvas *c)
+{
+ if(!c)
+ c = ownerDoc()->canvas();
+
+ if(!m_paintServer)
+ m_paintServer = c->createPaintServer(this);
+}
+
+void SVGPatternElementImpl::removeItem(KSVGCanvas *)
+{
+ delete m_paintServer;
+ m_paintServer = 0;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPatternElementImpl::s_hashTable 11
+ x SVGPatternElementImpl::X DontDelete|ReadOnly
+ y SVGPatternElementImpl::Y DontDelete|ReadOnly
+ width SVGPatternElementImpl::Width DontDelete|ReadOnly
+ height SVGPatternElementImpl::Height DontDelete|ReadOnly
+ patternUnits SVGPatternElementImpl::PatternUnits DontDelete|ReadOnly
+ patternContentUnits SVGPatternElementImpl::PatternContentUnits DontDelete|ReadOnly
+ patternTransform SVGPatternElementImpl::PatternTransform DontDelete|ReadOnly
+@end
+*/
+
+Value SVGPatternElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ KSVG_CHECK_ATTRIBUTE
+
+ switch(token)
+ {
+ case X:
+ if(!attributeMode)
+ return m_x->cache(exec);
+ else
+ return Number(m_x->baseVal()->value());
+ case Y:
+ if(!attributeMode)
+ return m_y->cache(exec);
+ else
+ return Number(m_y->baseVal()->value());
+ case Width:
+ if(!attributeMode)
+ return m_width->cache(exec);
+ else
+ return Number(m_width->baseVal()->value());
+ case Height:
+ if(!attributeMode)
+ return m_height->cache(exec);
+ else
+ return Number(m_height->baseVal()->value());
+ case PatternUnits:
+ if(!attributeMode)
+ return m_patternUnits->cache(exec);
+ else
+ return Number(m_patternUnits->baseVal());
+ case PatternContentUnits:
+ if(!attributeMode)
+ return m_patternContentUnits->cache(exec);
+ else
+ return Number(m_patternContentUnits->baseVal());
+ case PatternTransform:
+ //if(!attributeMode)
+ return m_patternTransform->cache(exec);
+ //else
+ // return Number(m_patternTransform->baseVal()->value());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGPatternElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case X:
+ converter()->modify(x(), value.toString(exec).qstring());
+ break;
+ case Y:
+ converter()->modify(y(), value.toString(exec).qstring());
+ break;
+ case Width:
+ converter()->modify(width(), value.toString(exec).qstring());
+ if(width()->baseVal()->value() < 0) // A negative value is an error
+ gotError(i18n("Negative value for attribute width of element <pattern> is illegal"));
+ break;
+ case Height:
+ converter()->modify(height(), value.toString(exec).qstring());
+ if(height()->baseVal()->value() < 0) // A negative value is an error
+ gotError(i18n("Negative value for attribute height of element <pattern> is illegal"));
+ break;
+ case PatternUnits:
+ if(value.toString(exec).qstring() == "userSpaceOnUse")
+ m_patternUnits->setBaseVal(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE);
+ else
+ m_patternUnits->setBaseVal(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
+ break;
+ case PatternContentUnits:
+ if(value.toString(exec).qstring() == "userSpaceOnUse")
+ m_patternContentUnits->setBaseVal(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE);
+ else
+ m_patternContentUnits->setBaseVal(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
+ break;
+ case PatternTransform:
+ m_patternTransform->baseVal()->clear();
+ SVGHelperImpl::parseTransformAttribute(m_patternTransform->baseVal(), value.toString(exec).qstring());
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+void SVGPatternElementImpl::setAttributes()
+{
+ SVGElementImpl::setAttributes();
+
+ // Spec: if attribute not specified, use a value of 0
+ if(KSVG_TOKEN_NOT_PARSED(X))
+ KSVG_SET_ALT_ATTRIBUTE(X, "0")
+
+ // Spec: if attribute not specified, use a value of 0
+ if(KSVG_TOKEN_NOT_PARSED(Y))
+ KSVG_SET_ALT_ATTRIBUTE(Y, "0")
+
+ // Spec: if attribute not specified, use objectBoundingBox
+ if(KSVG_TOKEN_NOT_PARSED(PatternUnits))
+ KSVG_SET_ALT_ATTRIBUTE(PatternUnits, "objectBoundingBox")
+
+ // Spec: If attribute not specified, use userSpaceOnUse
+ if(KSVG_TOKEN_NOT_PARSED(PatternContentUnits))
+ KSVG_SET_ALT_ATTRIBUTE(PatternContentUnits, "userSpaceOnUse")
+
+ // Spec: default value
+ if(KSVG_TOKEN_NOT_PARSED(PreserveAspectRatio))
+ KSVG_SET_ALT_ATTRIBUTE(PreserveAspectRatio, "xMidYMid meet")
+}
+
+void SVGPatternElementImpl::flushCachedTiles()
+{
+ QValueList<SVGPatternElementImpl *>::iterator it;
+
+ for(it = m_patternElements.begin(); it != m_patternElements.end(); it++)
+ {
+ SVGPatternElementImpl *pattern = *it;
+
+ if(pattern->paintServer())
+ pattern->paintServer()->resetFinalized();
+ }
+}
+
+QImage SVGPatternElementImpl::createTile(SVGShapeImpl *referencingElement, int imageWidth, int imageHeight)
+{
+ converter()->finalize(referencingElement, ownerSVGElement(), patternUnits()->baseVal());
+
+ QImage image(imageWidth, imageHeight, 32);
+ image.setAlphaBuffer(true);
+
+ if(m_canvas == 0)
+ {
+ m_canvas = CanvasFactory::self()->loadCanvas(image.width(), image.height());
+ m_canvas->setBackgroundColor(qRgba(0, 0, 0, 0));
+ }
+
+ m_canvas->setup(image.bits(), image.width(), image.height());
+
+ SVGMatrixImpl *baseMatrix = SVGSVGElementImpl::createSVGMatrix();
+
+ // Set the scale to map the tile onto the integral sized image
+ double xScale = static_cast<double>(imageWidth) / width()->baseVal()->value();
+ double yScale = static_cast<double>(imageHeight) / height()->baseVal()->value();
+
+ baseMatrix->scaleNonUniform(xScale, yScale);
+
+ if(hasAttribute("viewBox"))
+ {
+ SVGMatrixImpl *viewboxMatrix = viewBoxToViewTransform(width()->baseVal()->value(), height()->baseVal()->value());
+
+ baseMatrix->multiply(viewboxMatrix);
+ viewboxMatrix->deref();
+ }
+ else
+ {
+ if(patternContentUnits()->baseVal() == SVGPatternElement::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
+ {
+ // Get local coordinate bounding box
+ SVGRectImpl *rect = referencingElement->getBBox();
+
+ baseMatrix->translate(rect->qrect().x(), rect->qrect().y());
+ baseMatrix->scaleNonUniform(rect->qrect().width(), rect->qrect().height());
+ rect->deref();
+ }
+ }
+
+ for(DOM::Node node = m_location->firstChild(); !node.isNull(); node = node.nextSibling())
+ {
+ SVGElementImpl *element = ownerDoc()->getElementFromHandle(node.handle());
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(element);
+ SVGTestsImpl *tests = dynamic_cast<SVGTestsImpl *>(element);
+ SVGStylableImpl *style = dynamic_cast<SVGStylableImpl *>(element);
+
+ bool ok = tests ? tests->ok() : true;
+ if(element && shape && style && ok && style->getVisible() && style->getDisplay())
+ {
+ SVGLocatableImpl *locatable = dynamic_cast<SVGLocatableImpl *>(element);
+ if(locatable)
+ locatable->updateCachedScreenCTM(baseMatrix);
+
+ element->createItem(m_canvas);
+ if(shape->item())
+ {
+ shape->item()->setReferenced(true);
+ m_canvas->invalidate(shape->item(), true);
+ }
+ }
+ }
+
+ baseMatrix->deref();
+
+ m_canvas->update(float(1));
+
+ if(getOverflow())
+ {
+ QPtrList<CanvasItem> items = m_canvas->allItems();
+ QRect allItemsBBox;
+
+ QPtrListIterator<CanvasItem> it(items);
+ CanvasItem *item;
+
+ while((item = *it) != 0)
+ {
+ QRect bbox = item->bbox();
+ allItemsBBox |= bbox;
+ ++it;
+ }
+
+ if(allItemsBBox.left() < 0 || allItemsBBox.right() >= imageWidth || allItemsBBox.top() < 0 || allItemsBBox.bottom() >= imageHeight)
+ {
+ // Get the range in whole-tile units that covers the bounding box, where (0, 0) is the
+ // usual tile position.
+ int tileLeft = (allItemsBBox.left() - (imageWidth - 1)) / imageWidth;
+ int tileRight = allItemsBBox.right() / imageWidth;
+ int tileTop = (allItemsBBox.top() - (imageHeight - 1)) / imageHeight;
+ int tileBottom = allItemsBBox.bottom() / imageHeight;
+
+ for(int tileX = tileLeft; tileX <= tileRight; tileX++)
+ {
+ for(int tileY = tileTop; tileY <= tileBottom; tileY++)
+ {
+ if(tileX != 0 || tileY !=0)
+ {
+ QPoint panPoint(-(tileX * imageWidth), -(tileY * imageHeight));
+ m_canvas->update(panPoint, false);
+ }
+ }
+ }
+ }
+ }
+
+ for(DOM::Node node = m_location->firstChild(); !node.isNull(); node = node.nextSibling())
+ {
+ SVGElementImpl *element = ownerDoc()->getElementFromHandle(node.handle());
+
+ if(element)
+ element->removeItem(m_canvas);
+ }
+
+ return image;
+}
+
+void SVGPatternElementImpl::reference(const QString &href)
+{
+ // Copy attributes
+ SVGElementImpl *src = ownerSVGElement()->getElementById(href);
+
+ if(src)
+ {
+ SVGHelperImpl::copyAttributes(src, this);
+
+ // Spec: Change location to referenced element so we
+ // can take the children elements to render from there
+ if(m_location == this)
+ m_location = src;
+ }
+}
+
+void SVGPatternElementImpl::finalizePaintServer()
+{
+ // Clear out any cached tiles since we may be being refinalised after an image
+ // inside a pattern has finished loading.
+ m_tileCache.clear();
+
+ QString _href = SVGURIReferenceImpl::getTarget(href()->baseVal().string());
+ if(!_href.isEmpty())
+ reference(_href);
+}
+
+SVGPatternElementImpl::Tile SVGPatternElementImpl::createTile(SVGShapeImpl *referencingElement)
+{
+ converter()->finalize(referencingElement, ownerSVGElement(), patternUnits()->baseVal());
+
+ SVGTransformableImpl *transformable = dynamic_cast<SVGTransformableImpl *>(referencingElement);
+ SVGMatrixImpl *matrix = 0;
+ if(transformable)
+ matrix = transformable->getScreenCTM();
+ else
+ matrix = SVGSVGElementImpl::createSVGMatrix();
+
+ matrix->translate(x()->baseVal()->value(), y()->baseVal()->value());
+
+ SVGMatrixImpl *patTransform = patternTransform()->baseVal()->concatenate();
+ if(patTransform)
+ {
+ matrix->multiply(patTransform);
+ patTransform->deref();
+ }
+
+ double xScale, yScale;
+ matrix->removeScale(&xScale, &yScale);
+
+ double tileWidth = width()->baseVal()->value() * xScale;
+ double tileHeight = height()->baseVal()->value() * yScale;
+
+ int imageWidth = static_cast<int>(tileWidth + 0.5);
+ int imageHeight = static_cast<int>(tileHeight + 0.5);
+
+ Tile tile;
+
+ if(imageWidth > 0 && imageHeight > 0)
+ {
+ QSize size(imageWidth, imageHeight);
+ QImage image;
+
+ if(!m_tileCache.find(size, image))
+ {
+ image = createTile(referencingElement, imageWidth, imageHeight);
+ m_tileCache.insert(size, image, image.width() * image.height() * 4);
+ }
+
+ // Map integral tile dimensions onto its true size
+ double adjustXScale = tileWidth / imageWidth;
+ double adjustYScale = tileHeight / imageHeight;
+
+ matrix->scaleNonUniform(adjustXScale, adjustYScale);
+ QWMatrix screenToTile = matrix->qmatrix().invert();
+
+ tile = Tile(image, screenToTile);
+ }
+
+ matrix->deref();
+
+ return tile;
+}
+
diff --git a/ksvg/impl/SVGPatternElementImpl.h b/ksvg/impl/SVGPatternElementImpl.h
new file mode 100644
index 00000000..612fcfae
--- /dev/null
+++ b/ksvg/impl/SVGPatternElementImpl.h
@@ -0,0 +1,136 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPatternElementImpl_H
+#define SVGPatternElementImpl_H
+
+#include <qimage.h>
+#include <qwmatrix.h>
+
+#include "SVGTestsImpl.h"
+#include "SVGElementImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGLangSpaceImpl.h"
+#include "SVGURIReferenceImpl.h"
+#include "SVGFitToViewBoxImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+#include "SVGPaintServerImpl.h"
+#include "LRUCache.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGUnitConverter;
+class SVGAnimatedLengthImpl;
+class SVGAnimatedEnumerationImpl;
+class SVGAnimatedTransformListImpl;
+class SVGShapeImpl;
+class SVGPatternElementImpl : public SVGElementImpl,
+ public SVGURIReferenceImpl,
+ public SVGTestsImpl,
+ public SVGLangSpaceImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGStylableImpl,
+ public SVGFitToViewBoxImpl,
+ public SVGPaintServerImpl
+{
+public:
+ SVGPatternElementImpl(DOM::ElementImpl *);
+ virtual ~SVGPatternElementImpl();
+
+ SVGAnimatedEnumerationImpl *patternUnits() const;
+ SVGAnimatedEnumerationImpl *patternContentUnits() const;
+ SVGAnimatedTransformListImpl *patternTransform() const;
+ SVGAnimatedLengthImpl *x() const;
+ SVGAnimatedLengthImpl *y() const;
+ SVGAnimatedLengthImpl *width() const;
+ SVGAnimatedLengthImpl *height() const;
+
+ virtual void setAttributes();
+
+ virtual void createItem(KSVGCanvas *c = 0);
+ virtual void removeItem(KSVGCanvas *c);
+
+ SVGUnitConverter *converter() const { return m_converter; }
+
+ void reference(const QString &href);
+ void finalizePaintServer();
+
+ class Tile
+ {
+ public:
+ Tile() {}
+ Tile(const QImage& image, const QWMatrix& screenToTile) : m_image(image), m_screenToTile(screenToTile) {}
+
+ QImage image() const { return m_image; }
+ const QWMatrix& screenToTile() const { return m_screenToTile; }
+
+ private:
+ QImage m_image;
+ QWMatrix m_screenToTile;
+ };
+
+ Tile createTile(SVGShapeImpl *referencingElement);
+
+ static void flushCachedTiles();
+
+private:
+ QImage createTile(SVGShapeImpl *referencingElement, int imageWidth, int imageHeight);
+
+ SVGAnimatedEnumerationImpl *m_patternUnits;
+ SVGAnimatedEnumerationImpl *m_patternContentUnits;
+ SVGAnimatedTransformListImpl *m_patternTransform;
+ SVGAnimatedLengthImpl *m_x;
+ SVGAnimatedLengthImpl *m_y;
+ SVGAnimatedLengthImpl *m_width;
+ SVGAnimatedLengthImpl *m_height;
+
+ SVGUnitConverter *m_converter;
+
+ KSVGCanvas *m_canvas;
+ SVGElementImpl *m_location; // the referenced element
+ MinOneLRUCache<QSize, QImage> m_tileCache;
+
+ static QValueList<SVGPatternElementImpl *> m_patternElements;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+ KSVG_BRIDGE
+
+ enum
+ {
+ // Properties
+ X, Y, Width, Height, PatternUnits, PatternContentUnits, PatternTransform
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+KSVG_REGISTER_ELEMENT(SVGPatternElementImpl, "pattern")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPointImpl.cc b/ksvg/impl/SVGPointImpl.cc
new file mode 100644
index 00000000..c3697f58
--- /dev/null
+++ b/ksvg/impl/SVGPointImpl.cc
@@ -0,0 +1,108 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGPointImpl.h"
+#include "SVGSVGElementImpl.h"
+
+using namespace KSVG;
+
+#include "SVGPointImpl.lut.h"
+#include "ksvg_bridge.h"
+
+SVGPointImpl::SVGPointImpl() : DOM::DomShared()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_x = 0;
+ m_y = 0;
+}
+
+SVGPointImpl::~SVGPointImpl()
+{
+}
+
+void SVGPointImpl::setX(float x)
+{
+ m_x = x;
+}
+
+float SVGPointImpl::x() const
+{
+ return m_x;
+}
+
+void SVGPointImpl::setY(float y)
+{
+ m_y = y;
+}
+
+float SVGPointImpl::y() const
+{
+ return m_y;
+}
+
+SVGPointImpl *SVGPointImpl::matrixTransform(const SVGMatrixImpl &)
+{
+ SVGPointImpl *ret = SVGSVGElementImpl::createSVGPoint();
+ return ret;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPointImpl::s_hashTable 3
+ x SVGPointImpl::X DontDelete
+ y SVGPointImpl::Y DontDelete
+@end
+*/
+
+Value SVGPointImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case X:
+ return Number(x());
+ case Y:
+ return Number(y());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGPointImpl::putValueProperty(ExecState *exec, int token, const Value &value, int)
+{
+ switch(token)
+ {
+ case X:
+ m_x = value.toNumber(exec);
+ break;
+ case Y:
+ m_y = value.toNumber(exec);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPointImpl.h b/ksvg/impl/SVGPointImpl.h
new file mode 100644
index 00000000..55132cf3
--- /dev/null
+++ b/ksvg/impl/SVGPointImpl.h
@@ -0,0 +1,66 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPointImpl_H
+#define SVGPointImpl_H
+
+#include <dom/dom_misc.h>
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGMatrixImpl;
+class SVGPointImpl : public DOM::DomShared
+{
+public:
+ SVGPointImpl();
+ virtual ~SVGPointImpl();
+
+ void setX(float x);
+ float x() const;
+
+ void setY(float y);
+ float y() const;
+
+ SVGPointImpl *matrixTransform(const SVGMatrixImpl &matrix);
+
+private:
+ float m_x;
+ float m_y;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ X, Y
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
diff --git a/ksvg/impl/SVGPointListImpl.cc b/ksvg/impl/SVGPointListImpl.cc
new file mode 100644
index 00000000..34574b60
--- /dev/null
+++ b/ksvg/impl/SVGPointListImpl.cc
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGPointListImpl.h"
+
+using namespace KSVG;
+
+#include "SVGPointListImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPointListImpl::s_hashTable 2
+ numberOfItems SVGListDefs::NumberOfItems DontDelete|ReadOnly
+@end
+@namespace KSVG
+@begin SVGPointListImplProto::s_hashTable 11
+ getItem SVGListDefs::GetItem DontDelete|Function 1
+ removeItem SVGListDefs::RemoveItem DontDelete|Function 1
+ appendItem SVGListDefs::AppendItem DontDelete|Function 1
+ initialize SVGListDefs::Initialize DontDelete|Function 1
+ insertItemBefore SVGListDefs::InsertItemBefore DontDelete|Function 2
+ replaceItem SVGListDefs::ReplaceItem DontDelete|Function 2
+ clear SVGListDefs::Clear DontDelete|Function 0
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGPointList", SVGPointListImplProto, SVGPointListImplProtoFunc)
+
+Value SVGPointListImpl::getValueProperty(ExecState *exec, int token) const
+{
+ return SVGList<SVGPointImpl>::getValueProperty(exec, token);
+}
+
+Value SVGPointListImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGPointListImpl)
+
+ return obj->call(exec, static_cast<SVGList<SVGPointImpl> *>(obj), args, id);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPointListImpl.h b/ksvg/impl/SVGPointListImpl.h
new file mode 100644
index 00000000..61d93731
--- /dev/null
+++ b/ksvg/impl/SVGPointListImpl.h
@@ -0,0 +1,48 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPointListImpl_H
+#define SVGPointListImpl_H
+
+#include "SVGList.h"
+
+#include "SVGPointImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGPointListImpl : public SVGList<SVGPointImpl>
+{
+public:
+ KSVG_GET
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+};
+
+}
+
+KSVG_DEFINE_PROTOTYPE(SVGPointListImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGPointListImplProtoFunc, SVGPointListImpl)
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPolyElementImpl.cc b/ksvg/impl/SVGPolyElementImpl.cc
new file mode 100644
index 00000000..69ef57cd
--- /dev/null
+++ b/ksvg/impl/SVGPolyElementImpl.cc
@@ -0,0 +1,141 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <math.h>
+#include <cfloat>
+
+#include <kdebug.h>
+
+#include "SVGRectImpl.h"
+#include "SVGPointListImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGPolyElementImpl.h"
+#include "SVGAngleImpl.h"
+
+using namespace KSVG;
+
+SVGPolyElementImpl::SVGPolyElementImpl(DOM::ElementImpl *impl) : SVGShapeImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl(), SVGAnimatedPointsImpl()
+{
+}
+
+SVGPolyElementImpl::~SVGPolyElementImpl()
+{
+}
+
+SVGRectImpl *SVGPolyElementImpl::getBBox()
+{
+ SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect();
+
+ unsigned int nrPoints = points()->numberOfItems();
+ float minx, miny, maxx, maxy, tempx, tempy;
+ minx = points()->getItem(0)->x();
+ miny = points()->getItem(0)->y();
+ maxx = points()->getItem(0)->x();
+ maxy = points()->getItem(0)->y();
+
+ for(unsigned int i = 1; i < nrPoints; ++i)
+ {
+ tempx = points()->getItem(i)->x();
+ tempy = points()->getItem(i)->y();
+
+ if(tempx < minx)
+ minx = tempx;
+ if(tempx > maxx)
+ maxx = tempx;
+ if(tempy < miny)
+ miny = tempy;
+ if(tempy > maxy)
+ maxy = tempy;
+ }
+
+ ret->setX(minx);
+ ret->setY(miny);
+ ret->setWidth(maxx - minx);
+ ret->setHeight(maxy - miny);
+ return ret;
+}
+
+bool SVGPolyElementImpl::findOutSlope(unsigned int point, double *outSlope) const
+{
+ unsigned int nextPoint;
+
+ if(point == points()->numberOfItems() - 1)
+ {
+ if(m_isOpenPath)
+ return false;
+ else
+ nextPoint = 0;
+ }
+ else
+ nextPoint = point + 1;
+
+ if(point == nextPoint)
+ return false;
+
+ double x = points()->getItem(point)->x();
+ double y = points()->getItem(point)->y();
+ double nextX = points()->getItem(nextPoint)->x();
+ double nextY = points()->getItem(nextPoint)->y();
+ const double epsilon = DBL_EPSILON;
+
+ if(fabs(x - nextX) < epsilon && fabs(y - nextY) < epsilon)
+ return findOutSlope(nextPoint, outSlope);
+ else
+ {
+ double slope = SVGAngleImpl::todeg(atan2(nextY - y, nextX - x));
+ *outSlope = slope;
+ return true;
+ }
+}
+
+bool SVGPolyElementImpl::findInSlope(unsigned int point, double *inSlope) const
+{
+ unsigned int prevPoint;
+
+ if(point == 0)
+ {
+ if(m_isOpenPath)
+ return false;
+ else
+ prevPoint = points()->numberOfItems() - 1;
+ }
+ else
+ prevPoint = point - 1;
+
+ if(point == prevPoint)
+ return false;
+
+ double x = points()->getItem(point)->x();
+ double y = points()->getItem(point)->y();
+ double prevX = points()->getItem(prevPoint)->x();
+ double prevY = points()->getItem(prevPoint)->y();
+ const double epsilon = DBL_EPSILON;
+
+ if(fabs(x - prevX) < epsilon && fabs(y - prevY) < epsilon)
+ return findInSlope(prevPoint, inSlope);
+ else
+ {
+ double slope = SVGAngleImpl::todeg(atan2(y - prevY, x - prevX));
+ *inSlope = slope;
+ return true;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPolyElementImpl.h b/ksvg/impl/SVGPolyElementImpl.h
new file mode 100644
index 00000000..ded41d0c
--- /dev/null
+++ b/ksvg/impl/SVGPolyElementImpl.h
@@ -0,0 +1,70 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPolyElementImpl_H
+#define SVGPolyElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGShapeImpl.h"
+#include "SVGTestsImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGLangSpaceImpl.h"
+#include "SVGTransformableImpl.h"
+#include "SVGAnimatedPointsImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+namespace KSVG
+{
+
+class SVGPointListImpl;
+class SVGPolyElementImpl : public SVGShapeImpl,
+ public SVGTestsImpl,
+ public SVGLangSpaceImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGStylableImpl,
+ public SVGTransformableImpl,
+ public SVGAnimatedPointsImpl
+{
+public:
+ SVGPolyElementImpl(DOM::ElementImpl *);
+ virtual ~SVGPolyElementImpl();
+
+ virtual SVGRectImpl *getBBox();
+
+ virtual void drawMarkers() = 0;
+
+protected:
+ bool findOutSlope(unsigned int point, double *outSlope) const;
+ bool findInSlope(unsigned int point, double *inSlope) const;
+
+ bool m_isOpenPath;
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+ KSVG_NO_TAG_BRIDGE
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPolygonElementImpl.cc b/ksvg/impl/SVGPolygonElementImpl.cc
new file mode 100644
index 00000000..bf38ff37
--- /dev/null
+++ b/ksvg/impl/SVGPolygonElementImpl.cc
@@ -0,0 +1,88 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGPointListImpl.h"
+#include "SVGPolygonElementImpl.h"
+#include "SVGDocumentImpl.h"
+#include "KSVGCanvas.h"
+#include "SVGAngleImpl.h"
+
+using namespace KSVG;
+
+SVGPolygonElementImpl::SVGPolygonElementImpl(DOM::ElementImpl *impl) : SVGPolyElementImpl(impl)
+{
+ m_isOpenPath = false;
+}
+
+void SVGPolygonElementImpl::createItem(KSVGCanvas *c)
+{
+ if(!c)
+ c = ownerDoc()->canvas();
+
+ if(!m_item)
+ {
+ m_item = c->createPolygon(this);
+ c->insert(m_item);
+ }
+}
+
+void SVGPolygonElementImpl::drawMarkers()
+{
+ SVGPointListImpl *pts = points();
+ unsigned int nrPoints = pts->numberOfItems();
+
+ if(nrPoints > 0 && hasMarkers())
+ {
+ for(unsigned int i = 0; i < nrPoints; ++i)
+ {
+ double inSlope;
+ double outSlope;
+ bool haveInSlope = findInSlope(i, &inSlope);
+ bool haveOutSlope = findOutSlope(i, &outSlope);
+
+ if(!haveInSlope && haveOutSlope)
+ inSlope = outSlope;
+ else if(haveInSlope && !haveOutSlope)
+ outSlope = inSlope;
+ else if(!haveInSlope && !haveOutSlope)
+ {
+ inSlope = 0;
+ outSlope = 0;
+ }
+
+ double bisector = SVGAngleImpl::shortestArcBisector(inSlope, outSlope);
+
+ if(i == 0)
+ {
+ if(hasStartMarker())
+ doStartMarker(this, this, pts->getItem(i)->x(), pts->getItem(i)->y(), bisector);
+ if(hasEndMarker())
+ doEndMarker(this, this, pts->getItem(i)->x(), pts->getItem(i)->y(), bisector);
+ }
+ else
+ {
+ if(hasMidMarker())
+ doMidMarker(this, this, pts->getItem(i)->x(), pts->getItem(i)->y(), bisector);
+ }
+ }
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPolygonElementImpl.h b/ksvg/impl/SVGPolygonElementImpl.h
new file mode 100644
index 00000000..1c7e8c3b
--- /dev/null
+++ b/ksvg/impl/SVGPolygonElementImpl.h
@@ -0,0 +1,54 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPolygonElementImpl_H
+#define SVGPolygonElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGPolyElementImpl.h"
+#include "CanvasItems.h"
+
+namespace KSVG
+{
+
+class SVGPolygonElementImpl : public SVGPolyElementImpl, public MarkerHelper
+{
+public:
+ SVGPolygonElementImpl(DOM::ElementImpl *);
+ virtual ~SVGPolygonElementImpl() { }
+
+ virtual void createItem(KSVGCanvas *c = 0);
+
+ virtual void drawMarkers();
+
+public:
+ KSVG_BRIDGE
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+KSVG_REGISTER_ELEMENT(SVGPolygonElementImpl, "polygon")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPolylineElementImpl.cc b/ksvg/impl/SVGPolylineElementImpl.cc
new file mode 100644
index 00000000..9c95a928
--- /dev/null
+++ b/ksvg/impl/SVGPolylineElementImpl.cc
@@ -0,0 +1,100 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGPointListImpl.h"
+#include "SVGPolylineElementImpl.h"
+#include "SVGDocumentImpl.h"
+#include "KSVGCanvas.h"
+#include "SVGAngleImpl.h"
+
+using namespace KSVG;
+
+SVGPolylineElementImpl::SVGPolylineElementImpl(DOM::ElementImpl *impl) : SVGPolyElementImpl(impl)
+{
+ m_isOpenPath = true;
+}
+
+void SVGPolylineElementImpl::createItem(KSVGCanvas *c)
+{
+ if(!c)
+ c = ownerDoc()->canvas();
+
+ if(!m_item)
+ {
+ m_item = c->createPolyline(this);
+ c->insert(m_item);
+ }
+}
+
+void SVGPolylineElementImpl::drawMarkers()
+{
+ SVGPointListImpl *pts = points();
+ unsigned int nrPoints = pts->numberOfItems();
+
+ if(nrPoints > 0 && hasMarkers())
+ {
+ if(hasStartMarker())
+ {
+ double outSlope;
+
+ if(!findOutSlope(0, &outSlope))
+ outSlope = 0;
+
+ doStartMarker(this, this, pts->getItem(0)->x(), pts->getItem(0)->y(), outSlope);
+ }
+
+ if(hasMidMarker())
+ {
+ for(unsigned int i = 1; i < nrPoints - 1; ++i)
+ {
+ double inSlope;
+ double outSlope;
+ bool haveInSlope = findInSlope(i, &inSlope);
+ bool haveOutSlope = findOutSlope(i, &outSlope);
+
+ if(!haveInSlope && haveOutSlope)
+ inSlope = outSlope;
+ else if(haveInSlope && !haveOutSlope)
+ outSlope = inSlope;
+ else if(!haveInSlope && !haveOutSlope)
+ {
+ inSlope = 0;
+ outSlope = 0;
+ }
+
+ double bisector = SVGAngleImpl::shortestArcBisector(inSlope, outSlope);
+
+ doMidMarker(this, this, pts->getItem(i)->x(), pts->getItem(i)->y(), bisector);
+ }
+ }
+
+ if(hasEndMarker())
+ {
+ double inSlope;
+
+ if(!findInSlope(nrPoints - 1, &inSlope))
+ inSlope = 0;
+
+ doEndMarker(this, this, pts->getItem(nrPoints - 1)->x(), pts->getItem(nrPoints - 1)->y(), inSlope);
+ }
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPolylineElementImpl.h b/ksvg/impl/SVGPolylineElementImpl.h
new file mode 100644
index 00000000..c6ea5885
--- /dev/null
+++ b/ksvg/impl/SVGPolylineElementImpl.h
@@ -0,0 +1,54 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPolylineElementImpl_H
+#define SVGPolylineElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGPolyElementImpl.h"
+#include "CanvasItems.h"
+
+namespace KSVG
+{
+
+class SVGPolylineElementImpl : public SVGPolyElementImpl, public MarkerHelper
+{
+public:
+ SVGPolylineElementImpl(DOM::ElementImpl *);
+ virtual ~SVGPolylineElementImpl() { }
+
+ virtual void createItem(KSVGCanvas *c = 0);
+
+ virtual void drawMarkers();
+
+public:
+ KSVG_BRIDGE
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+KSVG_REGISTER_ELEMENT(SVGPolylineElementImpl, "polyline")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPreserveAspectRatioImpl.cc b/ksvg/impl/SVGPreserveAspectRatioImpl.cc
new file mode 100644
index 00000000..c8660e61
--- /dev/null
+++ b/ksvg/impl/SVGPreserveAspectRatioImpl.cc
@@ -0,0 +1,217 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include <qstring.h>
+#include <qstringlist.h>
+
+#include "SVGPreserveAspectRatio.h"
+
+#include "SVGMatrixImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGPreserveAspectRatioImpl.h"
+
+using namespace KSVG;
+
+#include "SVGPreserveAspectRatioImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_cacheimpl.h"
+
+SVGPreserveAspectRatioImpl::SVGPreserveAspectRatioImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_meetOrSlice = SVG_MEETORSLICE_UNKNOWN;
+ m_align = SVG_PRESERVEASPECTRATIO_UNKNOWN;
+}
+
+SVGPreserveAspectRatioImpl::~SVGPreserveAspectRatioImpl()
+{
+}
+
+void SVGPreserveAspectRatioImpl::setAlign(unsigned short align)
+{
+ m_align = align;
+}
+
+unsigned short SVGPreserveAspectRatioImpl::align() const
+{
+ return m_align;
+}
+
+void SVGPreserveAspectRatioImpl::setMeetOrSlice(unsigned short meetOrSlice)
+{
+ m_meetOrSlice = meetOrSlice;
+}
+
+unsigned short SVGPreserveAspectRatioImpl::meetOrSlice() const
+{
+ return m_meetOrSlice;
+}
+
+void SVGPreserveAspectRatioImpl::parsePreserveAspectRatio(const QString &str)
+{
+ // Spec: set the defaults
+ setAlign(SVG_PRESERVEASPECTRATIO_NONE);
+ setMeetOrSlice(SVG_MEETORSLICE_MEET);
+
+ QStringList params = QStringList::split(' ', str.simplifyWhiteSpace());
+
+ if(params[0].compare("none") == 0)
+ m_align = SVG_PRESERVEASPECTRATIO_NONE;
+ else if(params[0].compare("xMinYMin") == 0)
+ m_align = SVG_PRESERVEASPECTRATIO_XMINYMIN;
+ else if(params[0].compare("xMidYMin") == 0)
+ m_align = SVG_PRESERVEASPECTRATIO_XMIDYMIN;
+ else if(params[0].compare("xMaxYMin") == 0)
+ m_align = SVG_PRESERVEASPECTRATIO_XMAXYMIN;
+ else if(params[0].compare("xMinYMid") == 0)
+ m_align = SVG_PRESERVEASPECTRATIO_XMINYMID;
+ else if(params[0].compare("xMidYMid") == 0)
+ m_align = SVG_PRESERVEASPECTRATIO_XMIDYMID;
+ else if(params[0].compare("xMaxYMid") == 0)
+ m_align = SVG_PRESERVEASPECTRATIO_XMAXYMID;
+ else if(params[0].compare("xMinYMax") == 0)
+ m_align = SVG_PRESERVEASPECTRATIO_XMINYMAX;
+ else if(params[0].compare("xMidYMax") == 0)
+ m_align = SVG_PRESERVEASPECTRATIO_XMIDYMAX;
+ else if(params[0].compare("xMaxYMax") == 0)
+ m_align = SVG_PRESERVEASPECTRATIO_XMAXYMAX;
+
+ if(params[1].compare("slice") == 0)
+ m_meetOrSlice = SVG_MEETORSLICE_SLICE;
+ else
+ m_meetOrSlice = SVG_MEETORSLICE_MEET;
+}
+
+SVGMatrixImpl *SVGPreserveAspectRatioImpl::getCTM(float logicX, float logicY, float logicWidth, float logicHeight,
+ float /*physX*/, float /*physY*/, float physWidth, float physHeight)
+{
+ SVGMatrixImpl *temp = SVGSVGElementImpl::createSVGMatrix();
+
+ if(align() == SVG_PRESERVEASPECTRATIO_UNKNOWN)
+ return temp;
+
+ float vpar = logicWidth / logicHeight;
+ float svgar = physWidth / physHeight;
+
+ if(align() == SVG_PRESERVEASPECTRATIO_NONE)
+ {
+ temp->scaleNonUniform(physWidth / logicWidth, physHeight / logicHeight);
+ temp->translate(-logicX, -logicY);
+ }
+ else if(vpar < svgar && (meetOrSlice() == SVG_MEETORSLICE_MEET) || vpar >= svgar && (meetOrSlice() == SVG_MEETORSLICE_SLICE))
+ {
+ temp->scale(physHeight / logicHeight);
+
+ if(align() == SVG_PRESERVEASPECTRATIO_XMINYMIN || align() == SVG_PRESERVEASPECTRATIO_XMINYMID || align() == SVG_PRESERVEASPECTRATIO_XMINYMAX)
+ temp->translate(-logicX, -logicY);
+ else if(align() == SVG_PRESERVEASPECTRATIO_XMIDYMIN || align() == SVG_PRESERVEASPECTRATIO_XMIDYMID || align() == SVG_PRESERVEASPECTRATIO_XMIDYMAX)
+ temp->translate(-logicX - (logicWidth - physWidth * logicHeight / physHeight) / 2, -logicY);
+ else
+ temp->translate(-logicX - (logicWidth - physWidth * logicHeight / physHeight), -logicY);
+ }
+ else
+ {
+ temp->scale(physWidth / logicWidth);
+
+ if(align() == SVG_PRESERVEASPECTRATIO_XMINYMIN || align() == SVG_PRESERVEASPECTRATIO_XMIDYMIN || align() == SVG_PRESERVEASPECTRATIO_XMAXYMIN)
+ temp->translate(-logicX, -logicY);
+ else if(align() == SVG_PRESERVEASPECTRATIO_XMINYMID || align() == SVG_PRESERVEASPECTRATIO_XMIDYMID || align() == SVG_PRESERVEASPECTRATIO_XMAXYMID)
+ temp->translate(-logicX, -logicY - (logicHeight - physHeight * logicWidth / physWidth) / 2);
+ else
+ temp->translate(-logicX, -logicY - (logicHeight - physHeight * logicWidth / physWidth));
+ }
+
+ return temp;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGPreserveAspectRatioImpl::s_hashTable 3
+ align SVGPreserveAspectRatioImpl::Align DontDelete
+ meetOrSlice SVGPreserveAspectRatioImpl::MeetOrSlice DontDelete
+@end
+*/
+
+Value SVGPreserveAspectRatioImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case Align:
+ return Number(align());
+ case MeetOrSlice:
+ return Number(meetOrSlice());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return KJS::Undefined();
+ }
+}
+
+void SVGPreserveAspectRatioImpl::putValueProperty(ExecState *exec, int token, const KJS::Value &value, int)
+{
+ switch(token)
+ {
+ case Align:
+ m_align = static_cast<unsigned short>(value.toNumber(exec));
+ break;
+ case MeetOrSlice:
+ m_meetOrSlice = static_cast<unsigned short>(value.toNumber(exec));
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+/*
+@namespace KSVG
+@begin SVGPreserveAspectRatioImplConstructor::s_hashTable 17
+ SVG_PRESERVEASPECTRATIO_UNKNOWN KSVG::SVG_PRESERVEASPECTRATIO_UNKNOWN DontDelete|ReadOnly
+ SVG_PRESERVEASPECTRATIO_NONE KSVG::SVG_PRESERVEASPECTRATIO_NONE DontDelete|ReadOnly
+ SVG_PRESERVEASPECTRATIO_XMINYMIN KSVG::SVG_PRESERVEASPECTRATIO_XMINYMIN DontDelete|ReadOnly
+ SVG_PRESERVEASPECTRATIO_XMIDYMIN KSVG::SVG_PRESERVEASPECTRATIO_XMIDYMIN DontDelete|ReadOnly
+ SVG_PRESERVEASPECTRATIO_XMAXYMIN KSVG::SVG_PRESERVEASPECTRATIO_XMAXYMIN DontDelete|ReadOnly
+ SVG_PRESERVEASPECTRATIO_XMINYMID KSVG::SVG_PRESERVEASPECTRATIO_XMINYMID DontDelete|ReadOnly
+ SVG_PRESERVEASPECTRATIO_XMIDYMID KSVG::SVG_PRESERVEASPECTRATIO_XMIDYMID DontDelete|ReadOnly
+ SVG_PRESERVEASPECTRATIO_XMAXYMID KSVG::SVG_PRESERVEASPECTRATIO_XMAXYMID DontDelete|ReadOnly
+ SVG_PRESERVEASPECTRATIO_XMINYMAX KSVG::SVG_PRESERVEASPECTRATIO_XMINYMAX DontDelete|ReadOnly
+ SVG_PRESERVEASPECTRATIO_XMIDYMAX KSVG::SVG_PRESERVEASPECTRATIO_XMIDYMAX DontDelete|ReadOnly
+ SVG_PRESERVEASPECTRATIO_XMAXYMAX KSVG::SVG_PRESERVEASPECTRATIO_XMAXYMAX DontDelete|ReadOnly
+ SVG_MEETORSLICE_UNKNOWN KSVG::SVG_MEETORSLICE_UNKNOWN DontDelete|ReadOnly
+ SVG_MEETORSLICE_MEET KSVG::SVG_MEETORSLICE_MEET DontDelete|ReadOnly
+ SVG_MEETORSLICE_SLICE KSVG::SVG_MEETORSLICE_SLICE DontDelete|ReadOnly
+@end
+*/
+
+Value SVGPreserveAspectRatioImplConstructor::getValueProperty(ExecState *, int token) const
+{
+ return Number(token > SVG_PRESERVEASPECTRATIO_XMAXYMAX ? token - SVG_MEETORSLICE_UNKNOWN : token);
+}
+
+Value KSVG::getSVGPreserveAspectRatioImplConstructor(ExecState *exec)
+{
+ return cacheGlobalBridge<SVGPreserveAspectRatioImplConstructor>(exec, "[[svgpreserveaspectratio.constructor]]");
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGPreserveAspectRatioImpl.h b/ksvg/impl/SVGPreserveAspectRatioImpl.h
new file mode 100644
index 00000000..4a14a6b0
--- /dev/null
+++ b/ksvg/impl/SVGPreserveAspectRatioImpl.h
@@ -0,0 +1,84 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGPreserveAspectRatioImpl_H
+#define SVGPreserveAspectRatioImpl_H
+
+#include <dom/dom_misc.h>
+
+#include "ksvg_lookup.h"
+
+class QString;
+
+namespace KSVG
+{
+
+class SVGMatrixImpl;
+class SVGPreserveAspectRatioImpl : public DOM::DomShared
+{
+public:
+ SVGPreserveAspectRatioImpl();
+ virtual ~SVGPreserveAspectRatioImpl();
+
+ void setAlign(unsigned short);
+ unsigned short align() const;
+
+ void setMeetOrSlice(unsigned short);
+ unsigned short meetOrSlice() const;
+
+ void parsePreserveAspectRatio(const QString &);
+ SVGMatrixImpl *getCTM(float logicX, float logicY, float logicWidth, float logicHeight,
+ float physX, float physY, float physWidth, float physHeight);
+
+protected:
+ unsigned short m_align;
+ unsigned short m_meetOrSlice;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ Align, MeetOrSlice
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+class SVGPreserveAspectRatioImplConstructor : public KJS::ObjectImp
+{
+public:
+ SVGPreserveAspectRatioImplConstructor(KJS::ExecState *) { }
+ KJS::Value getValueProperty(KJS::ExecState *, int token) const;
+
+ // no put - all read-only
+ KSVG_GET
+};
+
+KJS::Value getSVGPreserveAspectRatioImplConstructor(KJS::ExecState *exec);
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGRadialGradientElementImpl.cc b/ksvg/impl/SVGRadialGradientElementImpl.cc
new file mode 100644
index 00000000..8d00cf15
--- /dev/null
+++ b/ksvg/impl/SVGRadialGradientElementImpl.cc
@@ -0,0 +1,216 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGGradientElement.h"
+#include "SVGRadialGradientElementImpl.h"
+
+#include "SVGDocumentImpl.h"
+#include "KSVGCanvas.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGUnitConverter.h"
+
+using namespace KSVG;
+
+#include "SVGRadialGradientElementImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+
+SVGRadialGradientElementImpl::SVGRadialGradientElementImpl(DOM::ElementImpl *impl) : SVGGradientElementImpl(impl)
+{
+ KSVG_EMPTY_FLAGS
+
+ m_cx = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this);
+ m_cx->ref();
+
+ m_cy = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this);
+ m_cy->ref();
+
+ m_r = new SVGAnimatedLengthImpl(LENGTHMODE_OTHER, this);
+ m_r->ref();
+
+ m_fx = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this);
+ m_fx->ref();
+
+ m_fy = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this);
+ m_fy->ref();
+
+ converter()->add(m_cx);
+ converter()->add(m_cy);
+ converter()->add(m_r);
+ converter()->add(m_fx);
+ converter()->add(m_fy);
+}
+
+SVGRadialGradientElementImpl::~SVGRadialGradientElementImpl()
+{
+ if(m_cx)
+ m_cx->deref();
+ if(m_cy)
+ m_cy->deref();
+ if(m_r)
+ m_r->deref();
+ if(m_fx)
+ m_fx->deref();
+ if(m_fy)
+ m_fy->deref();
+}
+
+SVGAnimatedLengthImpl *SVGRadialGradientElementImpl::cx() const
+{
+ return m_cx;
+}
+
+SVGAnimatedLengthImpl *SVGRadialGradientElementImpl::cy() const
+{
+ return m_cy;
+}
+
+SVGAnimatedLengthImpl *SVGRadialGradientElementImpl::r() const
+{
+ return m_r;
+}
+
+SVGAnimatedLengthImpl *SVGRadialGradientElementImpl::fx() const
+{
+ return m_fx;
+}
+
+SVGAnimatedLengthImpl *SVGRadialGradientElementImpl::fy() const
+{
+ return m_fy;
+}
+
+/*
+@namespace KSVG
+@begin SVGRadialGradientElementImpl::s_hashTable 7
+ cx SVGRadialGradientElementImpl::Cx DontDelete|ReadOnly
+ cy SVGRadialGradientElementImpl::Cy DontDelete|ReadOnly
+ r SVGRadialGradientElementImpl::R DontDelete|ReadOnly
+ fx SVGRadialGradientElementImpl::Fx DontDelete|ReadOnly
+ fy SVGRadialGradientElementImpl::Fy DontDelete|ReadOnly
+@end
+*/
+
+Value SVGRadialGradientElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ KSVG_CHECK_ATTRIBUTE
+
+ switch(token)
+ {
+ case Cx:
+ if(!attributeMode)
+ return m_cx->cache(exec);
+ else
+ return Number(m_cx->baseVal()->value());
+ case Cy:
+ if(!attributeMode)
+ return m_cy->cache(exec);
+ else
+ return Number(m_cy->baseVal()->value());
+ case R:
+ if(!attributeMode)
+ return m_r->cache(exec);
+ else
+ return Number(m_r->baseVal()->value());
+ case Fx:
+ if(!attributeMode)
+ return m_fx->cache(exec);
+ else
+ return Number(m_fx->baseVal()->value());
+ case Fy:
+ if(!attributeMode)
+ return m_fy->cache(exec);
+ else
+ return Number(m_fy->baseVal()->value());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGRadialGradientElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case Cx:
+ converter()->modify(cx(), value.toString(exec).qstring());
+ break;
+ case Cy:
+ converter()->modify(cy(), value.toString(exec).qstring());
+ break;
+ case R:
+ converter()->modify(r(), value.toString(exec).qstring());
+ break;
+ case Fx:
+ converter()->modify(fx(), value.toString(exec).qstring());
+ break;
+ case Fy:
+ converter()->modify(fy(), value.toString(exec).qstring());
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+void SVGRadialGradientElementImpl::setAttributes()
+{
+ SVGGradientElementImpl::setAttributes();
+
+ // Spec: no attribute, effect is af value 50% is specified
+ if(KSVG_TOKEN_NOT_PARSED(Cx))
+ KSVG_SET_ALT_ATTRIBUTE(Cx, "50%")
+
+ // Spec: no attribute, effect is af value 50% is specified
+ if(KSVG_TOKEN_NOT_PARSED(Cy))
+ KSVG_SET_ALT_ATTRIBUTE(Cy, "50%")
+
+ // Spec: no attribute, effect is af value 50% is specified
+ if(KSVG_TOKEN_NOT_PARSED(R))
+ KSVG_SET_ALT_ATTRIBUTE(R, "50%")
+}
+
+QMap<QString, DOM::DOMString> SVGRadialGradientElementImpl::gradientAttributes()
+{
+ setAttributes();
+
+ QMap<QString, DOM::DOMString> gradAttributes;
+ QDictIterator<DOM::DOMString> it(attributes());
+
+ for(; it.current(); ++it)
+ {
+ DOM::DOMString name = it.currentKey();
+ DOM::DOMString value = it.current()->string();
+
+ if(name == "gradientUnits" || name == "gradientTransform" || name == "spreadMethod" || name == "cx" || name == "cy" || name == "r" || name == "fx" || name == "fy")
+ {
+ gradAttributes.insert(name.string(), value.copy());
+ }
+ }
+
+ return gradAttributes;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGRadialGradientElementImpl.h b/ksvg/impl/SVGRadialGradientElementImpl.h
new file mode 100644
index 00000000..2f6c58c1
--- /dev/null
+++ b/ksvg/impl/SVGRadialGradientElementImpl.h
@@ -0,0 +1,76 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGRadialGradientElementImpl_H
+#define SVGRadialGradientElementImpl_H
+
+#include "SVGGradientElementImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedLengthImpl;
+class SVGRadialGradientElementImpl : public SVGGradientElementImpl
+{
+public:
+ SVGRadialGradientElementImpl(DOM::ElementImpl *);
+ virtual ~SVGRadialGradientElementImpl();
+
+ SVGAnimatedLengthImpl *cx() const;
+ SVGAnimatedLengthImpl *cy() const;
+ SVGAnimatedLengthImpl *r() const;
+ SVGAnimatedLengthImpl *fx() const;
+ SVGAnimatedLengthImpl *fy() const;
+
+ virtual void setAttributes();
+
+ virtual QMap<QString, DOM::DOMString> gradientAttributes();
+
+private:
+ SVGAnimatedLengthImpl *m_cx;
+ SVGAnimatedLengthImpl *m_cy;
+ SVGAnimatedLengthImpl *m_r;
+ SVGAnimatedLengthImpl *m_fx;
+ SVGAnimatedLengthImpl *m_fy;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+ KSVG_BRIDGE
+
+ enum
+ {
+ // Properties
+ Cx, Cy, R, Fx, Fy, Href
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+KSVG_REGISTER_ELEMENT(SVGRadialGradientElementImpl, "radialGradient")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGRectElementImpl.cc b/ksvg/impl/SVGRectElementImpl.cc
new file mode 100644
index 00000000..3dad7cbf
--- /dev/null
+++ b/ksvg/impl/SVGRectElementImpl.cc
@@ -0,0 +1,244 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "SVGRectImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGRectElementImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+
+#include "KSVGCanvas.h"
+#include "CanvasItem.h"
+
+using namespace KSVG;
+
+#include "SVGRectElementImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+
+SVGRectElementImpl::SVGRectElementImpl(DOM::ElementImpl *impl) : SVGShapeImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_x = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this);
+ m_x->ref();
+ m_x->baseVal()->setValueAsString("-1");
+
+ m_y = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this);
+ m_y->ref();
+ m_y->baseVal()->setValueAsString("-1");
+
+ m_width = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this);
+ m_width->ref();
+ m_width->baseVal()->setValueAsString("-1");
+
+ m_height = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this);
+ m_height->ref();
+ m_height->baseVal()->setValueAsString("-1");
+
+ m_rx = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this);
+ m_rx->ref();
+ m_rx->baseVal()->setValueAsString("-1");
+
+ m_ry = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this);
+ m_ry->ref();
+ m_ry->baseVal()->setValueAsString("-1");
+}
+
+SVGRectElementImpl::~SVGRectElementImpl()
+{
+ if(m_x)
+ m_x->deref();
+ if(m_y)
+ m_y->deref();
+ if(m_width)
+ m_width->deref();
+ if(m_height)
+ m_height->deref();
+ if(m_rx)
+ m_rx->deref();
+ if(m_ry)
+ m_ry->deref();
+}
+
+SVGAnimatedLengthImpl *SVGRectElementImpl::x()
+{
+ return m_x;
+}
+
+SVGAnimatedLengthImpl *SVGRectElementImpl::y()
+{
+ return m_y;
+}
+
+SVGAnimatedLengthImpl *SVGRectElementImpl::width()
+{
+ return m_width;
+}
+
+SVGAnimatedLengthImpl *SVGRectElementImpl::height()
+{
+ return m_height;
+}
+
+SVGAnimatedLengthImpl *SVGRectElementImpl::rx()
+{
+ return m_rx;
+}
+
+SVGAnimatedLengthImpl *SVGRectElementImpl::ry()
+{
+ return m_ry;
+}
+
+/*
+@namespace KSVG
+@begin SVGRectElementImpl::s_hashTable 7
+ x SVGRectElementImpl::X DontDelete|ReadOnly
+ y SVGRectElementImpl::Y DontDelete|ReadOnly
+ width SVGRectElementImpl::Width DontDelete|ReadOnly
+ height SVGRectElementImpl::Height DontDelete|ReadOnly
+ rx SVGRectElementImpl::Rx DontDelete|ReadOnly
+ ry SVGRectElementImpl::Ry DontDelete|ReadOnly
+@end
+*/
+
+Value SVGRectElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ KSVG_CHECK_ATTRIBUTE
+
+ switch(token)
+ {
+ case X:
+ if(!attributeMode)
+ return m_x->cache(exec);
+ else
+ return Number(m_x->baseVal()->value());
+ case Y:
+ if(!attributeMode)
+ return m_y->cache(exec);
+ else
+ return Number(m_y->baseVal()->value());
+ case Width:
+ if(!attributeMode)
+ return m_width->cache(exec);
+ else
+ return Number(m_width->baseVal()->value());
+ case Height:
+ if(!attributeMode)
+ return m_height->cache(exec);
+ else
+ return Number(m_height->baseVal()->value());
+ case Rx:
+ if(!attributeMode)
+ return m_rx->cache(exec);
+ else
+ return Number(m_rx->baseVal()->value());
+ case Ry:
+ if(!attributeMode)
+ return m_ry->cache(exec);
+ else
+ return Number(m_ry->baseVal()->value());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGRectElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case X:
+ x()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ case Y:
+ y()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ case Width:
+ width()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ if(width()->baseVal()->value() < 0) // A negative value is an error
+ gotError(i18n("Negative value for attribute width of element <rect> is illegal"));
+ break;
+ case Height:
+ height()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ if(height()->baseVal()->value() < 0) // A negative value is an error
+ gotError(i18n("Negative value for attribute height of element <rect> is illegal"));
+ break;
+ case Rx:
+ rx()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ if(rx()->baseVal()->value() < 0) // A negative value is an error
+ gotError(i18n("Negative value for attribute rx of element <rect> is illegal"));
+ break;
+ case Ry:
+ ry()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ if(ry()->baseVal()->value() < 0) // A negative value is an error
+ gotError(i18n("Negative value for attribute ry of element <rect> is illegal"));
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+SVGRectImpl *SVGRectElementImpl::getBBox()
+{
+ SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect();
+ ret->setX(m_x->baseVal()->value());
+ ret->setY(m_y->baseVal()->value());
+ ret->setWidth(m_width->baseVal()->value());
+ ret->setHeight(m_height->baseVal()->value());
+ return ret;
+}
+
+void SVGRectElementImpl::setAttributes()
+{
+ SVGElementImpl::setAttributes();
+
+ // Spec: if not specified, effect is as if a value of "0" were specified
+ if(KSVG_TOKEN_NOT_PARSED(X))
+ KSVG_SET_ALT_ATTRIBUTE(X, "0")
+
+ // Spec: if not specified, effect is as if a value of "0" were specified
+ if(KSVG_TOKEN_NOT_PARSED(Y))
+ KSVG_SET_ALT_ATTRIBUTE(Y, "0")
+}
+
+void SVGRectElementImpl::createItem(KSVGCanvas *c)
+{
+ if(!c)
+ c = ownerDoc()->canvas();
+
+ if(!m_item)
+ {
+ m_item = c->createRectangle(this);
+ c->insert(m_item);
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGRectElementImpl.h b/ksvg/impl/SVGRectElementImpl.h
new file mode 100644
index 00000000..690084d7
--- /dev/null
+++ b/ksvg/impl/SVGRectElementImpl.h
@@ -0,0 +1,90 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGRectElementImpl_H
+#define SVGRectElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGShapeImpl.h"
+#include "SVGTestsImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGLangSpaceImpl.h"
+#include "SVGTransformableImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+namespace KSVG
+{
+
+class SVGRectImpl;
+class SVGAnimatedLengthImpl;
+class SVGRectElementImpl : public SVGShapeImpl,
+ public SVGTestsImpl,
+ public SVGLangSpaceImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGStylableImpl,
+ public SVGTransformableImpl
+{
+public:
+ SVGRectElementImpl(DOM::ElementImpl *);
+ virtual ~SVGRectElementImpl();
+
+ SVGAnimatedLengthImpl *x();
+ SVGAnimatedLengthImpl *y();
+ SVGAnimatedLengthImpl *width();
+ SVGAnimatedLengthImpl *height();
+ SVGAnimatedLengthImpl *rx();
+ SVGAnimatedLengthImpl *ry();
+
+ virtual void createItem(KSVGCanvas *c = 0);
+ virtual void setAttributes();
+
+ virtual SVGRectImpl *getBBox();
+
+private:
+ SVGAnimatedLengthImpl *m_x;
+ SVGAnimatedLengthImpl *m_y;
+ SVGAnimatedLengthImpl *m_width;
+ SVGAnimatedLengthImpl *m_height;
+ SVGAnimatedLengthImpl *m_rx;
+ SVGAnimatedLengthImpl *m_ry;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+ KSVG_BRIDGE
+
+ enum
+ {
+ // Properties
+ X, Y, Width, Height, Rx, Ry
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+KSVG_REGISTER_ELEMENT(SVGRectElementImpl, "rect")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGRectImpl.cc b/ksvg/impl/SVGRectImpl.cc
new file mode 100644
index 00000000..1f6c0d51
--- /dev/null
+++ b/ksvg/impl/SVGRectImpl.cc
@@ -0,0 +1,157 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include <qrect.h>
+
+#include "SVGRectImpl.h"
+
+using namespace KSVG;
+
+#include "SVGRectImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+SVGRectImpl::SVGRectImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_x = 0;
+ m_y = 0;
+ m_width = 0;
+ m_height = 0;
+}
+
+SVGRectImpl::SVGRectImpl(const QRect &other)
+{
+ (*this) = other;
+}
+
+SVGRectImpl::~SVGRectImpl()
+{
+}
+
+void SVGRectImpl::setX(float x)
+{
+ m_x = x;
+}
+
+float SVGRectImpl::x() const
+{
+ return m_x;
+}
+
+void SVGRectImpl::setY(float y)
+{
+ m_y = y;
+}
+
+float SVGRectImpl::y() const
+{
+ return m_y;
+}
+
+void SVGRectImpl::setWidth(float width)
+{
+ m_width = width;
+}
+
+float SVGRectImpl::width() const
+{
+ return m_width;
+}
+
+void SVGRectImpl::setHeight(float height)
+{
+ m_height = height;
+}
+
+float SVGRectImpl::height() const
+{
+ return m_height;
+}
+
+QRect SVGRectImpl::qrect() const
+{
+ // ceil() so the integer rectangle contains the whole real one.
+ return QRect(int(m_x), int(m_y), int(ceil(m_width)), int(ceil(m_height)));
+}
+
+SVGRectImpl &SVGRectImpl::operator=(const QRect &other)
+{
+ m_x = other.x();
+ m_y = other.y();
+ m_width = other.width();
+ m_height = other.height();
+
+ return *this;
+}
+
+/*
+@namespace KSVG
+@begin SVGRectImpl::s_hashTable 5
+ x SVGRectImpl::X DontDelete
+ y SVGRectImpl::Y DontDelete
+ width SVGRectImpl::Width DontDelete
+ height SVGRectImpl::Height DontDelete
+@end
+*/
+
+Value SVGRectImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case X:
+ return Number(m_x);
+ case Y:
+ return Number(m_y);
+ case Width:
+ return Number(m_width);
+ case Height:
+ return Number(m_height);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGRectImpl::putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int)
+{
+ switch(token)
+ {
+ case X:
+ m_x = value.toNumber(exec);
+ break;
+ case Y:
+ m_y = value.toNumber(exec);
+ break;
+ case Width:
+ m_width = value.toNumber(exec);
+ break;
+ case Height:
+ m_height = value.toNumber(exec);
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGRectImpl.h b/ksvg/impl/SVGRectImpl.h
new file mode 100644
index 00000000..e0b0e889
--- /dev/null
+++ b/ksvg/impl/SVGRectImpl.h
@@ -0,0 +1,80 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGRectImpl_H
+#define SVGRectImpl_H
+
+#include <dom/dom_misc.h>
+
+#include "ksvg_lookup.h"
+
+class QRect;
+
+namespace KSVG
+{
+
+class SVGRectImpl : public DOM::DomShared
+{
+public:
+ SVGRectImpl();
+ SVGRectImpl(const QRect &);
+ virtual ~SVGRectImpl();
+
+ void setX(float x);
+ float x() const;
+
+ void setY(float y);
+ float y() const;
+
+ void setWidth(float width);
+ float width() const;
+
+ void setHeight(float height);
+ float height() const;
+
+ QRect qrect() const;
+
+ SVGRectImpl &operator=(const QRect &);
+
+private:
+ float m_x;
+ float m_y;
+ float m_width;
+ float m_height;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ X, Y, Width, Height
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGSVGElementImpl.cc b/ksvg/impl/SVGSVGElementImpl.cc
new file mode 100644
index 00000000..b54cf521
--- /dev/null
+++ b/ksvg/impl/SVGSVGElementImpl.cc
@@ -0,0 +1,982 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include <qtimer.h>
+#include <qstringlist.h>
+#include <qdatetime.h>
+
+#define USE_VALGRIND 0
+
+#if USE_VALGRIND
+#include <valgrind/calltree.h>
+#endif
+
+#include "SVGLength.h"
+
+#include "SVGRectImpl.h"
+#include "SVGAngleImpl.h"
+#include "SVGShapeImpl.h"
+#include "SVGPointImpl.h"
+#include "SVGNumberImpl.h"
+#include "SVGMatrixImpl.h"
+
+#include "SVGEventImpl.h"
+#include "SVGAElementImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGViewSpecImpl.h"
+#include "SVGTransformImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGAnimatedRectImpl.h"
+#include "SVGTransformListImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGAnimatedStringImpl.h"
+#include "SVGPreserveAspectRatioImpl.h"
+#include "SVGAnimatedTransformListImpl.h"
+#include "SVGAnimatedPreserveAspectRatioImpl.h"
+
+#include "CanvasItem.h"
+#include "KSVGCanvas.h"
+
+using namespace KSVG;
+
+#include "SVGSVGElementImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+
+SVGSVGElementImpl::SVGSVGElementImpl(DOM::ElementImpl *impl) : SVGContainerImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGLocatableImpl(), SVGFitToViewBoxImpl(), SVGZoomAndPanImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_x = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this);
+ m_x->ref();
+
+ m_y = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this);
+ m_y->ref();
+
+ m_width = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this);
+ m_width->ref();
+
+ m_height = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this);
+ m_height->ref();
+
+ m_viewport = SVGSVGElementImpl::createSVGRect();
+
+ m_currentTranslate = SVGSVGElementImpl::createSVGPoint();
+
+ m_currentView = new SVGViewSpecImpl();
+ m_currentView->ref();
+
+ m_currentScale = 1.0;
+
+ m_useCurrentView = false;
+
+ m_clip[0] = 0;
+ m_clip[1] = 0;
+ m_clip[2] = 0;
+ m_clip[3] = 0;
+
+ m_rootParentScreenCTM = 0;
+
+ m_localMatrix = SVGSVGElementImpl::createSVGMatrix();
+}
+
+SVGSVGElementImpl::~SVGSVGElementImpl()
+{
+ if(m_x)
+ m_x->deref();
+ if(m_y)
+ m_y->deref();
+ if(m_width)
+ m_width->deref();
+ if(m_height)
+ m_height->deref();
+ if(m_viewport)
+ m_viewport->deref();
+ if(m_currentTranslate)
+ m_currentTranslate->deref();
+ if(m_currentView)
+ m_currentView->deref();
+ if(m_rootParentScreenCTM)
+ m_rootParentScreenCTM->deref();
+ if(m_localMatrix)
+ m_localMatrix->deref();
+}
+
+bool SVGSVGElementImpl::isRootElement() const
+{
+ return ownerDoc()->rootElement() == this;
+}
+
+void SVGSVGElementImpl::setAttributes()
+{
+ SVGElementImpl::setAttributes();
+
+ // Spec: if not specified, effect is as if a value of "0" were specified
+ if(KSVG_TOKEN_NOT_PARSED(X))
+ KSVG_SET_ALT_ATTRIBUTE(X, "0")
+
+ // Spec: if not specified, effect is as if a value of "0" were specified
+ if(KSVG_TOKEN_NOT_PARSED(Y))
+ KSVG_SET_ALT_ATTRIBUTE(Y, "0")
+
+ // Spec: If the attribute is not specified, the effect is as if a value of "100%" were specified.
+ if(KSVG_TOKEN_NOT_PARSED(Width))
+ KSVG_SET_ALT_ATTRIBUTE(Width, "100%")
+
+ // Spec: If the attribute is not specified, the effect is as if a value of "100%" were specified.
+ if(KSVG_TOKEN_NOT_PARSED(Height))
+ KSVG_SET_ALT_ATTRIBUTE(Height, "100%")
+
+ // Spec: The contentScriptType should default to "text/ecmascript".
+ if(KSVG_TOKEN_NOT_PARSED(ContentScriptType))
+ KSVG_SET_ALT_ATTRIBUTE(ContentScriptType, "text/ecmascript")
+
+ // Spec: The contentStyleType should default to "text/css".
+ if(KSVG_TOKEN_NOT_PARSED(ContentStyleType))
+ KSVG_SET_ALT_ATTRIBUTE(ContentStyleType, "text/css")
+
+ if(m_useCurrentView)
+ {
+ parseViewBox(m_currentView->viewBoxString().string());
+ preserveAspectRatio()->baseVal()->parsePreserveAspectRatio(m_currentView->preserveAspectRatioString().string());
+ }
+
+ m_viewport->setX(x()->baseVal()->value());
+ m_viewport->setY(y()->baseVal()->value());
+ m_viewport->setWidth(width()->baseVal()->value());
+ m_viewport->setHeight(height()->baseVal()->value());
+
+ if(isRootElement() && ownerDoc()->parentImage() == 0)
+ {
+ if(ownerDoc()->canvas())
+ ownerDoc()->canvas()->setViewportDimension(int(ceil(width()->baseVal()->value() * currentScale())), int(ceil(height()->baseVal()->value() * currentScale())));
+
+ // Special case for outermost svg element:
+ // We need to register our id manually, because
+ // m_ownerSVGElement is 0 in SVGElementImpl::setAttributes (Niko)
+ if(!id().isNull())
+ addToIdMap(id().string(), this);
+ }
+}
+
+SVGAnimatedLengthImpl *SVGSVGElementImpl::x()
+{
+ return m_x;
+}
+
+SVGAnimatedLengthImpl *SVGSVGElementImpl::y()
+{
+ return m_y;
+}
+
+SVGAnimatedLengthImpl *SVGSVGElementImpl::width()
+{
+ return m_width;
+}
+
+SVGAnimatedLengthImpl *SVGSVGElementImpl::height()
+{
+ return m_height;
+}
+
+void SVGSVGElementImpl::setContentScriptType(const DOM::DOMString &contentScriptType)
+{
+ setAttribute("contentScriptType", contentScriptType);
+}
+
+DOM::DOMString SVGSVGElementImpl::contentScriptType() const
+{
+ return getAttribute("contentScriptType");
+}
+
+void SVGSVGElementImpl::setContentStyleType(const DOM::DOMString &contentStyleType)
+{
+ setAttribute("contentStyleType", contentStyleType);
+}
+
+DOM::DOMString SVGSVGElementImpl::contentStyleType() const
+{
+ return getAttribute("contentStyleType");
+}
+
+SVGRectImpl *SVGSVGElementImpl::viewport()
+{
+ return m_viewport;
+}
+
+SVGRectImpl *SVGSVGElementImpl::getBBox()
+{
+ SVGRectImpl *ret = new SVGRectImpl(getCTM()->qmatrix().invert().map(m_viewport->qrect()));
+ ret->ref();
+ return ret;
+}
+
+float SVGSVGElementImpl::pixelUnitToMillimeterX() const
+{
+ return ownerDoc()->screenPixelsPerMillimeterX();
+}
+
+float SVGSVGElementImpl::pixelUnitToMillimeterY() const
+{
+ return ownerDoc()->screenPixelsPerMillimeterY();
+}
+
+float SVGSVGElementImpl::screenPixelToMillimeterX() const
+{
+ return pixelUnitToMillimeterX();
+}
+
+float SVGSVGElementImpl::screenPixelToMillimeterY() const
+{
+ return pixelUnitToMillimeterY();
+}
+
+void SVGSVGElementImpl::setUseCurrentView(bool useCurrentView)
+{
+ m_useCurrentView = useCurrentView;
+}
+
+bool SVGSVGElementImpl::useCurrentView() const
+{
+ return m_useCurrentView;
+}
+
+SVGViewSpecImpl *SVGSVGElementImpl::currentView() const
+{
+ return m_currentView;
+}
+
+void SVGSVGElementImpl::setCurrentScale(float currentScale)
+{
+ if( m_currentScale != currentScale )
+ {
+ m_currentScale = currentScale;
+ invalidateCachedMatrices();
+
+ if(hasEventListener(SVGEvent::ZOOM_EVENT, true))
+ dispatchEvent(SVGEvent::ZOOM_EVENT, false, false);
+ }
+}
+
+float SVGSVGElementImpl::currentScale() const
+{
+ return m_currentScale;
+}
+
+void SVGSVGElementImpl::setCurrentTranslate(const QPoint &p)
+{
+ if(m_currentTranslate->x() != p.x() || m_currentTranslate->y() != p.y())
+ {
+ m_currentTranslate->setX(p.x());
+ m_currentTranslate->setY(p.y());
+ invalidateCachedMatrices();
+ if(hasEventListener(SVGEvent::SCROLL_EVENT, true))
+ dispatchEvent(SVGEvent::SCROLL_EVENT, false, false);
+ }
+}
+
+SVGPointImpl *SVGSVGElementImpl::currentTranslate()
+{
+ return m_currentTranslate;
+}
+
+unsigned long SVGSVGElementImpl::suspendRedraw(unsigned long)
+{
+ return 0;
+}
+
+void SVGSVGElementImpl::unsuspendRedraw(unsigned long)
+{
+}
+
+void SVGSVGElementImpl::unsuspendRedrawAll()
+{
+}
+
+void SVGSVGElementImpl::forceRedraw()
+{
+#if USE_VALGRIND
+ CALLTREE_ZERO_STATS();
+#endif
+
+ QTime timer;
+ timer.start();
+
+ if(ownerDoc() && ownerDoc()->canvas())
+ ownerDoc()->canvas()->update();
+
+ kdDebug(26000) << "forceRedraw in " << timer.elapsed()/1000.0 << " seconds" << endl;
+
+#if USE_VALGRIND
+ CALLTREE_DUMP_STATS();
+#endif
+}
+
+void SVGSVGElementImpl::pauseAnimations()
+{
+ if(!ownerDoc()->timeScheduler()->animationsPaused())
+ ownerDoc()->timeScheduler()->toggleAnimations();
+}
+
+void SVGSVGElementImpl::unpauseAnimations()
+{
+ if(ownerDoc()->timeScheduler()->animationsPaused())
+ ownerDoc()->timeScheduler()->toggleAnimations();
+}
+
+bool SVGSVGElementImpl::animationsPaused()
+{
+ return ownerDoc()->timeScheduler()->animationsPaused();
+}
+
+float SVGSVGElementImpl::getCurrentTime() const
+{
+ return ownerDoc()->timeScheduler()->elapsed();
+}
+
+void SVGSVGElementImpl::setCurrentTime(float)
+{
+}
+
+DOM::NodeList SVGSVGElementImpl::getIntersectionList(SVGRectImpl *, SVGElementImpl *)
+{
+ // TODO : implement me
+ return DOM::NodeList();
+}
+
+DOM::NodeList SVGSVGElementImpl::getEnclosureList(SVGRectImpl *rect, SVGElementImpl */*referenceElement*/)
+{
+ DOM::NodeList list;
+
+ DOM::Node node = firstChild();
+ for(; !node.isNull(); node = node.nextSibling())
+ {
+ SVGElementImpl *element = ownerDoc()->getElementFromHandle(node.handle());
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(element);
+ if(shape)
+ {
+ if(shape->isContainer())
+ // TODO : pass it on to container::getEnclosureList() which should return a NodeList
+ kdDebug() << "!shape" << endl;
+ else
+ {
+ // TODO : add the shape to list if the test succeeds
+ SVGRectImpl *current = shape->getBBox();
+ if(rect->qrect().contains(current->qrect(), true))
+ kdDebug() << "shape : " << element->nodeName().string() << " is fully enclosed" << endl;
+
+ current->deref();
+ }
+ }
+ }
+
+ return list;
+}
+
+bool SVGSVGElementImpl::checkIntersection(SVGElementImpl *element, SVGRectImpl *rect)
+{
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(element);
+ if(!shape)
+ return false;
+
+ SVGRectImpl *current = shape->getBBox();
+ bool result = rect->qrect().intersects(current->qrect());
+ current->deref();
+ return result;
+}
+
+bool SVGSVGElementImpl::checkEnclosure(SVGElementImpl *element, SVGRectImpl *rect)
+{
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(element);
+ if(!shape)
+ return false;
+
+ SVGRectImpl *current = shape->getBBox();
+ bool result = rect->qrect().contains(current->qrect());
+ current->deref();
+ return result;
+}
+
+void SVGSVGElementImpl::deSelectAll()
+{
+}
+
+SVGNumberImpl *SVGSVGElementImpl::createSVGNumber()
+{
+ // Spec: Creates an SVGNumber object outside of any document
+ // trees. The object is initialized to a value of zero.
+ SVGNumberImpl *ret = new SVGNumberImpl();
+ ret->ref();
+ return ret;
+}
+
+SVGLengthImpl *SVGSVGElementImpl::createSVGLength()
+{
+ // Spec: Creates an SVGLength object outside of any document
+ // trees. The object is initialized to the value of 0 user units.
+ SVGLengthImpl *ret = new SVGLengthImpl();
+ ret->ref();
+ return ret;
+}
+
+SVGAngleImpl *SVGSVGElementImpl::createSVGAngle()
+{
+ // Spec: Creates an SVGAngle object outside of any document
+ // trees. The object is initialized to the value 0 degrees (unitless).
+ SVGAngleImpl *ret = new SVGAngleImpl();
+ ret->ref();
+ return ret;
+}
+
+SVGPointImpl *SVGSVGElementImpl::createSVGPoint()
+{
+ // Spec: Creates an SVGPoint object outside of any document
+ // trees. The object is initialized to the point (0,0) in the user coordinate system.
+ SVGPointImpl *ret = new SVGPointImpl();
+ ret->ref();
+ return ret;
+}
+
+SVGMatrixImpl *SVGSVGElementImpl::createSVGMatrix()
+{
+ // Spec: Creates an SVGMatrix object outside of any document
+ // trees. The object is initialized to the identity matrix.
+ SVGMatrixImpl *ret = new SVGMatrixImpl(QWMatrix(1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F));
+ ret->ref();
+ return ret;
+}
+
+SVGRectImpl *SVGSVGElementImpl::createSVGRect()
+{
+ // Spec: Creates an SVGRect object outside of any document
+ // trees. The object is initialized such that all values are set to 0 user units.
+ SVGRectImpl *ret = new SVGRectImpl();
+ ret->ref();
+ return ret;
+}
+
+SVGTransformImpl *SVGSVGElementImpl::createSVGTransform()
+{
+ // Spec: Creates an SVGTransform object outside of any document
+ // trees. The object is initialized to an identity matrix transform (SVG_TRANSFORM_MATRIX).
+ SVGTransformImpl *transform = createSVGTransformFromMatrix(createSVGMatrix());
+
+ // createSVGMatrix already ref's the matrix, the SVGTransformImpl->setMatrix
+ // call also does this, prevent non deleting of the object by deref'ing (Niko)
+ transform->matrix()->deref();
+
+ return transform;
+}
+
+SVGTransformImpl *SVGSVGElementImpl::createSVGTransformFromMatrix(SVGMatrixImpl *mat)
+{
+ // Spec: Creates an SVGTransform object outside of any document
+ // trees. The object is initialized to the given matrix transform (i.e., SVG_TRANSFORM_MATRIX).
+ SVGTransformImpl *ret = new SVGTransformImpl();
+ ret->setMatrix(mat);
+ ret->ref();
+ return ret;
+}
+
+SVGElementImpl *SVGSVGElementImpl::getElementById(const DOM::DOMString &elementId)
+{
+ return m_map[elementId.string()];
+}
+
+void SVGSVGElementImpl::addToIdMap(const QString &id, SVGElementImpl *obj)
+{
+ m_map.insert(id, obj);
+}
+
+SVGMatrixImpl *SVGSVGElementImpl::getCTM()
+{
+ return viewBoxToViewTransform(width()->baseVal()->value(), height()->baseVal()->value());
+}
+
+const SVGMatrixImpl *SVGSVGElementImpl::localMatrix()
+{
+ // TODO: only update the matrix when needed and just return m_localMatrix
+
+ m_localMatrix->reset();
+
+ if(ownerSVGElement() == 0)
+ {
+ if(m_rootParentScreenCTM != 0)
+ m_localMatrix->copy(m_rootParentScreenCTM);
+
+ // We're the outermost svg element.
+ // Put the zoom scale and translate into the matrix.
+ m_localMatrix->translate(currentTranslate()->x(), currentTranslate()->y());
+ m_localMatrix->scale(currentScale());
+ }
+
+ // Apply viewport translation.
+ m_localMatrix->translate(x()->baseVal()->value(), y()->baseVal()->value());
+
+ // And viewbox.
+ SVGMatrixImpl *viewboxMatrix = viewBoxToViewTransform(width()->baseVal()->value(), height()->baseVal()->value());
+
+ m_localMatrix->multiply(viewboxMatrix);
+ viewboxMatrix->deref();
+
+ return m_localMatrix;
+}
+
+void SVGSVGElementImpl::setClip(const QString &clip)
+{
+ // TODO : this routine should probably be shared between all classes that establish new viewports (Rob)
+ if(!clip.startsWith("rect(") || !clip.endsWith(")"))
+ return;
+
+ QString work = clip.mid(5, clip.length() - 6);
+ QStringList substrings = QStringList::split(',', clip);
+ QStringList::ConstIterator it = substrings.begin();
+
+ if(m_clip[0])
+ m_clip[0]->deref();
+ m_clip[0] = SVGSVGElementImpl::createSVGLength();
+
+ if(*it != "auto")
+ m_clip[0]->setValueAsString(*it);
+ ++it;
+
+ if(m_clip[1])
+ m_clip[1]->deref();
+ m_clip[1] = SVGSVGElementImpl::createSVGLength();
+
+ if(*it != "auto")
+ m_clip[1]->setValueAsString(*it);
+ ++it;
+
+ if(m_clip[2])
+ m_clip[2]->deref();
+ m_clip[2] = SVGSVGElementImpl::createSVGLength();
+
+ if(*it != "auto")
+ m_clip[2]->setValueAsString(*it);
+ ++it;
+
+ if(m_clip[3])
+ m_clip[3]->deref();
+ m_clip[3] = SVGSVGElementImpl::createSVGLength();
+
+ if(*it != "auto")
+ m_clip[3]->setValueAsString(*it);
+}
+
+QRect SVGSVGElementImpl::clip()
+{
+ // Get viewport in user coordinates.
+ QRect v(0, 0, m_viewport->qrect().width(), m_viewport->qrect().height());
+
+ SVGMatrixImpl *ctm = getCTM();
+ QRect r = ctm->qmatrix().invert().mapRect(v);
+ ctm->deref();
+
+ if(m_clip[0])
+ r.setTop(static_cast<int>(r.top() + m_clip[0]->value()));
+ if(m_clip[1])
+ r.setRight(static_cast<int>(r.right() - m_clip[1]->value()));
+ if(m_clip[2])
+ r.setBottom(static_cast<int>(r.bottom() - m_clip[2]->value()));
+ if(m_clip[3])
+ r.setLeft(static_cast<int>(r.left() + m_clip[3]->value()));
+
+ return r;
+}
+
+void SVGSVGElementImpl::setRootParentScreenCTM(SVGMatrixImpl *screenCTM)
+{
+ if(m_rootParentScreenCTM != 0)
+ m_rootParentScreenCTM->deref();
+
+ m_rootParentScreenCTM = screenCTM;
+ screenCTM->ref();
+}
+
+bool SVGSVGElementImpl::prepareMouseEvent(const QPoint &p, const QPoint &a, SVGMouseEventImpl *mev)
+{
+ // mop: central bool var which turns to true once the current "mouseover" element has been found
+ bool ret = false, dorerender = false;
+ SVGElementImpl *elem = 0;
+
+ SVGMatrixImpl *ctm = getCTM();
+ QPoint userA = ctm->qmatrix().invert().map(a);
+ ctm->deref();
+
+ // Just check the lastTarget once (mop)
+ if(ownerDoc()->lastTarget())
+ {
+ elem = ownerDoc()->lastTarget();
+ ret = elem->prepareMouseEvent(p, userA, mev);
+
+ // mop: only proceed if element is not the current element anymore. rest is done in the lower part
+ if(!ret)
+ {
+ if(elem->hasEventListener(SVGEvent::MOUSEOUT_EVENT, false))
+ {
+ dorerender = true;
+ elem->setMouseOver(false);
+ elem->dispatchMouseEvent(SVGEvent::MOUSEOUT_EVENT, true, true, 0, mev->screenX(), mev->screenY(), mev->clientX(), mev->clientY(), mev->ctrlKey(), mev->altKey(), mev->shiftKey(), mev->metaKey(), mev->button(), elem);
+ }
+
+ if(elem->hasEventListener(SVGEvent::DOMFOCUSOUT_EVENT, false) && elem->focus())
+ {
+ dorerender = true;
+ elem->setFocus(false);
+ elem->dispatchEvent(SVGEvent::DOMFOCUSOUT_EVENT, true, true);
+ }
+
+ // mop: unset last target once we left it
+ ownerDoc()->setLastTarget(0);
+ }
+ }
+
+ // mop: DAMN...logic doesn't work :(
+ // we cant use the results of the above check because something like this
+ // _________
+ // | ____ |
+ // ||____| |
+ // |_________|
+ //
+ // wouldn't work because even if the mousepointer would be in the inner rect it would still be inside the bbox
+ // of the outer (assuming that the outer is the lastTarget). :(
+ ret = false;
+
+ // mop: just check for a node until the element where the mouse is over is found
+ // mop: "ret" can be set from the above stuff too...
+ // find the element here and do the event stuff in the lower part..much cleaner
+ CanvasItemList hits = ownerDoc()->canvas()->collisions(p, true);
+ for(CanvasItemList::Iterator it = hits.begin(); it != hits.end(); ++it)
+ {
+ elem = (*it)->element();
+ if(elem)
+ {
+ // Check if mouse is over a certain shape...
+ // mop: once an element has been found check eventlisteners and leave immediately
+ ret = elem->prepareMouseEvent(p, userA, mev);
+ if(ret) break;
+ }
+ }
+
+ // mop: has an element been found?
+ if(ret)
+ {
+ int events = mev->target()->getEventListeners(false);
+
+ // Dispatch mousemove, mousedown, mouseup and mouseclick events
+ bool cancel = (mev->id() != SVGEvent::MOUSEMOVE_EVENT);
+
+ if(events & 1 << mev->id())
+ {
+ mev->target()->dispatchMouseEvent(mev->id(), true, cancel, 0, mev->screenX(), mev->screenY(), mev->clientX(), mev->clientY(), mev->ctrlKey(), mev->altKey(), mev->shiftKey(), mev->metaKey(), mev->button(), elem);
+ dorerender = true; // mop: if it has the event then rerender
+ }
+
+ // If a mouse "moves" over a shape, it's also "over" the shape
+ if(mev->id() == SVGEvent::MOUSEMOVE_EVENT)
+ {
+ mev->target()->setMouseOver(true);
+ if(events & 1 << SVGEvent::MOUSEOVER_EVENT)
+ {
+ mev->target()->dispatchMouseEvent(SVGEvent::MOUSEOVER_EVENT, true, cancel, 0, mev->screenX(), mev->screenY(), mev->clientX(), mev->clientY(), mev->ctrlKey(), mev->altKey(), mev->shiftKey(), mev->metaKey(), mev->button(), elem);
+ dorerender = true;
+ }
+
+ }
+
+ // Also send an domactivate + focusin event on mouseup
+ bool dolinktest = true;
+ if(mev->id() == SVGEvent::MOUSEUP_EVENT)
+ {
+ mev->target()->setFocus(true);
+
+ if(events & 1 << SVGEvent::CLICK_EVENT)
+ {
+ dolinktest = mev->target()->dispatchEvent(SVGEvent::CLICK_EVENT, true, true);
+ dorerender = true;
+ }
+
+ if(events & 1 << SVGEvent::DOMACTIVATE_EVENT)
+ {
+ mev->target()->dispatchEvent(SVGEvent::DOMACTIVATE_EVENT, true, true);
+ dorerender = true;
+ }
+
+ if(events & 1 << SVGEvent::DOMFOCUSIN_EVENT)
+ {
+ mev->target()->dispatchEvent(SVGEvent::DOMFOCUSIN_EVENT, true, true);
+ dorerender = true;
+ }
+ }
+
+ // Hyperlink support
+ SVGAElementImpl* link=0;
+ if(dolinktest && !mev->defaultPrevented())
+ {
+ link = SVGAElementImpl::getLink(elem);
+ if(link)
+ {
+ mev->setURL(link->href()->baseVal());
+ emit ownerDoc()->gotURL(link->target()->baseVal().string());
+ }
+ }
+
+ // The mouse is over a shape, so we have a target..we need to register that for a mouseout
+ ownerDoc()->setLastTarget(mev->target());
+ }
+
+ // mop: all events may trigger changed style, add elements etc. this is definately needed :(
+ if(dorerender)
+ ownerDoc()->rerender();
+
+ return dorerender; // mop: some kind of event has been found and executed
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGSVGElementImpl::s_hashTable 23
+ x SVGSVGElementImpl::X DontDelete|ReadOnly
+ y SVGSVGElementImpl::Y DontDelete|ReadOnly
+ width SVGSVGElementImpl::Width DontDelete|ReadOnly
+ height SVGSVGElementImpl::Height DontDelete|ReadOnly
+ viewport SVGSVGElementImpl::Viewport DontDelete|ReadOnly
+ contentScriptType SVGSVGElementImpl::ContentScriptType DontDelete
+ contentStyleType SVGSVGElementImpl::ContentStyleType DontDelete
+ pixelUnitToMillimeterX SVGSVGElementImpl::PixelUnitToMillimeterX DontDelete|ReadOnly
+ pixelUnitToMillimeterY SVGSVGElementImpl::PixelUnitToMillimeterY DontDelete|ReadOnly
+ screenPixelToMillimeterX SVGSVGElementImpl::ScreenPixelToMillimeterX DontDelete|ReadOnly
+ screenPixelToMillimeterY SVGSVGElementImpl::ScreenPixelToMillimeterY DontDelete|ReadOnly
+ useCurrentView SVGSVGElementImpl::UseCurrentView DontDelete
+ currentScale SVGSVGElementImpl::CurrentScale DontDelete
+ currentTranslate SVGSVGElementImpl::CurrentTranslate DontDelete|ReadOnly
+ onunload SVGSVGElementImpl::OnUnload DontDelete
+ onerror SVGSVGElementImpl::OnError DontDelete
+ onresize SVGSVGElementImpl::OnResize DontDelete
+ onzoom SVGSVGElementImpl::OnZoom DontDelete
+ onscroll SVGSVGElementImpl::OnScroll DontDelete
+@end
+@namespace KSVG
+@begin SVGSVGElementImplProto::s_hashTable 29
+ createSVGNumber SVGSVGElementImpl::CreateSVGNumber DontDelete|Function 0
+ createSVGLength SVGSVGElementImpl::CreateSVGLength DontDelete|Function 0
+ createSVGAngle SVGSVGElementImpl::CreateSVGAngle DontDelete|Function 0
+ createSVGPoint SVGSVGElementImpl::CreateSVGPoint DontDelete|Function 0
+ createSVGMatrix SVGSVGElementImpl::CreateSVGMatrix DontDelete|Function 0
+ createSVGRect SVGSVGElementImpl::CreateSVGRect DontDelete|Function 0
+ createSVGTransform SVGSVGElementImpl::CreateSVGTransform DontDelete|Function 0
+ createSVGTransformFromMatrix SVGSVGElementImpl::CreateSVGTransformFromMatrix DontDelete|Function 1
+ suspendRedraw SVGSVGElementImpl::SuspendRedraw DontDelete|Function 1
+ unsuspendRedraw SVGSVGElementImpl::UnsuspendRedraw DontDelete|Function 1
+ unsuspendRedrawAll SVGSVGElementImpl::UnsuspendRedrawAll DontDelete|Function 0
+ forceRedraw SVGSVGElementImpl::ForceRedraw DontDelete|Function 0
+ pauseAnimations SVGSVGElementImpl::PauseAnimations DontDelete|Function 0
+ unpauseAnimations SVGSVGElementImpl::UnpauseAnimations DontDelete|Function 0
+ animationsPaused SVGSVGElementImpl::AnimationsPaused DontDelete|Function 0
+ getCurrentTime SVGSVGElementImpl::GetCurrentTime DontDelete|Function 0
+ setCurrentTime SVGSVGElementImpl::SetCurrentTime DontDelete|Function 1
+ getIntersectionList SVGSVGElementImpl::GetIntersectionList DontDelete|Function 2
+ getEnclosureList SVGSVGElementImpl::GetEnclosureList DontDelete|Function 2
+ checkIntersection SVGSVGElementImpl::CheckIntersection DontDelete|Function 2
+ checkEnclosure SVGSVGElementImpl::CheckEnclosure DontDelete|Function 2
+ deselectAll SVGSVGElementImpl::DeselectAll DontDelete|Function 0
+ getElementById SVGSVGElementImpl::GetElementById DontDelete|Function 1
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGSVGElement", SVGSVGElementImplProto, SVGSVGElementImplProtoFunc)
+
+Value SVGSVGElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ KSVG_CHECK_ATTRIBUTE
+
+ switch(token)
+ {
+ case X:
+ if(!attributeMode)
+ return m_x->cache(exec);
+ else
+ return Number(m_x->baseVal()->value());
+ case Y:
+ if(!attributeMode)
+ return m_y->cache(exec);
+ else
+ return Number(m_y->baseVal()->value());
+ case Width:
+ if(!attributeMode)
+ return m_width->cache(exec);
+ else
+ return Number(m_width->baseVal()->value());
+ case Height:
+ if(!attributeMode)
+ return m_height->cache(exec);
+ else
+ return Number(m_height->baseVal()->value());
+ case Viewport:
+ return m_viewport->cache(exec);
+ case ContentScriptType:
+ return String(contentScriptType().string());
+ case ContentStyleType:
+ return String(contentStyleType().string());
+ case PixelUnitToMillimeterX:
+ return Number(pixelUnitToMillimeterX());
+ case PixelUnitToMillimeterY:
+ return Number(pixelUnitToMillimeterY());
+ case ScreenPixelToMillimeterX:
+ return Number(screenPixelToMillimeterX());
+ case ScreenPixelToMillimeterY:
+ return Number(screenPixelToMillimeterY());
+ case UseCurrentView:
+ return Boolean(useCurrentView());
+ case CurrentScale:
+ return Number(currentScale());
+ case CurrentTranslate:
+ return m_currentTranslate->cache(exec);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGSVGElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int)
+{
+ switch(token)
+ {
+ case ContentScriptType:
+ setContentScriptType(value.toString(exec).string());
+ break;
+ case ContentStyleType:
+ setContentStyleType(value.toString(exec).string());
+ break;
+ case CurrentScale:
+ m_currentScale = value.toNumber(exec);
+ break;
+ case X:
+ x()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ case Y:
+ y()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ case Width:
+ width()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ case Height:
+ height()->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ case OnUnload:
+ // Spec: only applicable to outermost 'svg' elements
+ if(isRootElement())
+ setEventListener(SVGEvent::UNLOAD_EVENT, ownerDoc()->createEventListener(value.toString(exec).qstring()));
+ break;
+ case OnError:
+ setEventListener(SVGEvent::ERROR_EVENT, ownerDoc()->createEventListener(value.toString(exec).qstring()));
+ break;
+ case OnResize:
+ // Spec: only applicable to outermost 'svg' elements
+ if(isRootElement())
+ setEventListener(SVGEvent::RESIZE_EVENT, ownerDoc()->createEventListener(value.toString(exec).qstring()));
+ break;
+ case OnZoom:
+ // Spec: only applicable to outermost 'svg' elements
+ if(isRootElement())
+ setEventListener(SVGEvent::ZOOM_EVENT, ownerDoc()->createEventListener(value.toString(exec).qstring()));
+ break;
+ case OnScroll:
+ // Spec: only applicable to outermost 'svg' elements
+ if(isRootElement())
+ setEventListener(SVGEvent::SCROLL_EVENT, ownerDoc()->createEventListener(value.toString(exec).qstring()));
+ break;
+ default:
+ kdWarning() << k_funcinfo << "unhandled token " << token << endl;
+ }
+}
+
+Value SVGSVGElementImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGSVGElementImpl)
+
+ switch(id)
+ {
+ case SVGSVGElementImpl::CreateSVGNumber:
+ return obj->createSVGNumber()->cache(exec);
+ case SVGSVGElementImpl::CreateSVGLength:
+ return obj->createSVGLength()->cache(exec);
+ case SVGSVGElementImpl::CreateSVGAngle:
+ return obj->createSVGAngle()->cache(exec);
+ case SVGSVGElementImpl::CreateSVGPoint:
+ return obj->createSVGPoint()->cache(exec);
+ case SVGSVGElementImpl::CreateSVGMatrix:
+ return obj->createSVGMatrix()->cache(exec);
+ case SVGSVGElementImpl::CreateSVGRect:
+ return obj->createSVGRect()->cache(exec);
+ case SVGSVGElementImpl::CreateSVGTransform:
+ return obj->createSVGTransform()->cache(exec);
+ case SVGSVGElementImpl::CreateSVGTransformFromMatrix:
+ return obj->createSVGTransformFromMatrix(static_cast<KSVGBridge<SVGMatrixImpl> *>(args[0].imp())->impl())->cache(exec);
+ case SVGSVGElementImpl::GetElementById:
+ {
+ // Keep in sync with SVGDocumentImpl's version.
+ Value ret;
+
+ SVGElementImpl *element = obj->getElementById(args[0].toString(exec).string());
+
+ if(element)
+ ret = getDOMNode(exec, *element);
+ else
+ {
+ element = obj->ownerDoc()->recursiveSearch(*(obj->ownerDoc()), args[0].toString(exec).string());
+ if(!element)
+ return Null();
+
+ ret = getDOMNode(exec, *element);
+ }
+
+ return ret;
+ }
+ case SVGSVGElementImpl::GetCurrentTime:
+ return Number(obj->getCurrentTime());
+ case SVGSVGElementImpl::SetCurrentTime:
+ obj->setCurrentTime(args[0].toNumber(exec));
+ return Undefined();
+ case SVGSVGElementImpl::DeselectAll:
+ obj->deSelectAll();
+ return Undefined();
+ case SVGSVGElementImpl::PauseAnimations:
+ obj->pauseAnimations();
+ return Undefined();
+ case SVGSVGElementImpl::UnpauseAnimations:
+ obj->unpauseAnimations();
+ return Undefined();
+ case SVGSVGElementImpl::AnimationsPaused:
+ return Boolean(obj->animationsPaused());
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return Undefined();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGSVGElementImpl.h b/ksvg/impl/SVGSVGElementImpl.h
new file mode 100644
index 00000000..2405458e
--- /dev/null
+++ b/ksvg/impl/SVGSVGElementImpl.h
@@ -0,0 +1,198 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGSVGElementImpl_H
+#define SVGSVGElementImpl_H
+
+#include <dom/dom_string.h>
+
+#include <qmap.h>
+
+#include "SVGTestsImpl.h"
+#include "SVGElementImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGLocatableImpl.h"
+#include "SVGContainerImpl.h"
+#include "SVGLangSpaceImpl.h"
+#include "SVGZoomAndPanImpl.h"
+#include "SVGFitToViewBoxImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGPointImpl;
+class SVGAngleImpl;
+class SVGNumberImpl;
+class SVGLengthImpl;
+class SVGMatrixImpl;
+class SVGViewSpecImpl;
+class SVGTransformImpl;
+class SVGAnimatedLengthImpl;
+class SVGAnimationElementImpl;
+class SVGSVGElementImpl : public SVGContainerImpl,
+ public SVGTestsImpl,
+ public SVGLangSpaceImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGStylableImpl,
+ public SVGLocatableImpl,
+ public SVGFitToViewBoxImpl,
+ public SVGZoomAndPanImpl
+{
+public:
+ SVGSVGElementImpl(DOM::ElementImpl *);
+ virtual ~SVGSVGElementImpl();
+
+ bool isRootElement() const;
+
+ SVGAnimatedLengthImpl *x();
+ SVGAnimatedLengthImpl *y();
+ SVGAnimatedLengthImpl *width();
+ SVGAnimatedLengthImpl *height();
+
+ void setContentScriptType(const DOM::DOMString &);
+ DOM::DOMString contentScriptType() const;
+
+ void setContentStyleType(const DOM::DOMString &);
+ DOM::DOMString contentStyleType() const;
+
+ SVGRectImpl *viewport();
+ SVGRectImpl *getBBox();
+
+ float pixelUnitToMillimeterX() const;
+ float pixelUnitToMillimeterY() const;
+ float screenPixelToMillimeterX() const;
+ float screenPixelToMillimeterY() const;
+
+ void setUseCurrentView(bool);
+ bool useCurrentView() const;
+ SVGViewSpecImpl *currentView() const;
+
+ void setCurrentScale(float);
+ float currentScale() const;
+
+ SVGPointImpl *currentTranslate();
+ void setCurrentTranslate(const QPoint &p);
+
+ unsigned long suspendRedraw(unsigned long max_wait_milliseconds);
+ void unsuspendRedraw(unsigned long suspend_handle_id);
+ void unsuspendRedrawAll();
+ void forceRedraw();
+
+ void pauseAnimations();
+ void unpauseAnimations();
+
+ bool animationsPaused();
+
+ float getCurrentTime() const;
+ void setCurrentTime(float seconds);
+ DOM::NodeList getIntersectionList(SVGRectImpl *rect, SVGElementImpl *referenceElement);
+ DOM::NodeList getEnclosureList(SVGRectImpl *rect, SVGElementImpl *referenceElement);
+ bool checkIntersection(SVGElementImpl *element, SVGRectImpl *rect);
+ bool checkEnclosure(SVGElementImpl *element, SVGRectImpl *rect);
+ void deSelectAll();
+
+ // Static creators for svg primitives
+ static SVGNumberImpl *createSVGNumber();
+ static SVGLengthImpl *createSVGLength();
+ static SVGAngleImpl *createSVGAngle();
+ static SVGPointImpl *createSVGPoint();
+ static SVGMatrixImpl *createSVGMatrix();
+ static SVGRectImpl *createSVGRect();
+ static SVGTransformImpl *createSVGTransform();
+ static SVGTransformImpl *createSVGTransformFromMatrix(SVGMatrixImpl *matrix);
+
+ SVGElementImpl *getElementById(const DOM::DOMString &elementId);
+ void addToIdMap(const QString &id, SVGElementImpl *obj);
+
+ virtual SVGMatrixImpl *getCTM();
+ virtual const SVGMatrixImpl *localMatrix();
+
+ void setAttributes();
+
+ bool prepareMouseEvent(const QPoint &p, const QPoint &a, SVGMouseEventImpl *event);
+
+ virtual bool isContainer() const { return true; }
+
+ virtual void setClip(const QString &clip);
+ virtual QRect clip();
+
+ void setRootParentScreenCTM(SVGMatrixImpl *screenCTM);
+
+private:
+ SVGAnimatedLengthImpl *m_x;
+ SVGAnimatedLengthImpl *m_y;
+ SVGAnimatedLengthImpl *m_width;
+ SVGAnimatedLengthImpl *m_height;
+
+ SVGRectImpl *m_viewport;
+
+ bool m_useCurrentView;
+
+ SVGViewSpecImpl *m_currentView;
+
+ float m_currentScale;
+
+ SVGPointImpl *m_currentTranslate;
+
+ SVGLengthImpl *m_clip[4];
+
+ QMap<QString, SVGElementImpl *> m_map;
+
+ // Transformation provided by the 'parent' of the outermost svg element
+ SVGMatrixImpl *m_rootParentScreenCTM;
+
+ SVGMatrixImpl *m_localMatrix;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+ KSVG_BRIDGE
+
+ enum
+ {
+ // Properties
+ X, Y, Width, Height, ContentScriptType, ContentStyleType, Viewport,
+ PixelUnitToMillimeterX, PixelUnitToMillimeterY, ScreenPixelToMillimeterX, ScreenPixelToMillimeterY,
+ UseCurrentView, CurrentScale, CurrentTranslate, OnUnload, OnError, OnResize, OnZoom, OnScroll,
+ // Functions
+ CreateSVGNumber, CreateSVGLength, CreateSVGAngle, CreateSVGPoint, CreateSVGMatrix, CreateSVGRect, CreateSVGTransform,
+ CreateSVGTransformFromMatrix, SuspendRedraw, UnsuspendRedraw, UnsuspendRedrawAll, ForceRedraw,
+ PauseAnimations, UnpauseAnimations, AnimationsPaused, GetCurrentTime, SetCurrentTime,
+ GetIntersectionList, GetEnclosureList, CheckIntersection, CheckEnclosure,
+ DeselectAll, GetElementById
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+KSVG_REGISTER_ELEMENT(SVGSVGElementImpl, "svg")
+
+}
+
+KSVG_DEFINE_PROTOTYPE(SVGSVGElementImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGSVGElementImplProtoFunc, SVGSVGElementImpl)
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGScriptElementImpl.cc b/ksvg/impl/SVGScriptElementImpl.cc
new file mode 100644
index 00000000..9a211425
--- /dev/null
+++ b/ksvg/impl/SVGScriptElementImpl.cc
@@ -0,0 +1,185 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include <kio/job.h>
+#include <kfilterdev.h>
+#include <qbuffer.h>
+
+#include "SVGDocumentImpl.h"
+#include "SVGAnimatedStringImpl.h"
+#include "SVGScriptElementImpl.moc"
+
+using namespace KSVG;
+
+#include "SVGScriptElementImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+
+SVGScriptElementImpl::SVGScriptElementImpl(DOM::ElementImpl *impl) : QObject(), SVGElementImpl(impl), SVGURIReferenceImpl(), SVGExternalResourcesRequiredImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_job = 0;
+ m_added = false;
+}
+
+SVGScriptElementImpl::~SVGScriptElementImpl()
+{
+}
+
+void SVGScriptElementImpl::setType(const DOM::DOMString &type)
+{
+ setAttribute("type", type);
+}
+
+DOM::DOMString SVGScriptElementImpl::type() const
+{
+ return getAttribute("type");
+}
+
+void SVGScriptElementImpl::setAttributes()
+{
+ SVGElementImpl::setAttributes();
+
+ // Spec: provide a default type
+ if(KSVG_TOKEN_NOT_PARSED(Type))
+ KSVG_SET_ALT_ATTRIBUTE(Type, "text/ecmascript")
+
+ // Remote downloading
+ QString href = m_href->baseVal().string();
+
+ if(!href.isEmpty())
+ {
+ KURL url(ownerDoc()->baseUrl(), href);
+
+ if(m_job == 0)
+ m_job = KIO::get(url, false, false);
+
+ connect(m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), this, SLOT(slotData(KIO::Job *, const QByteArray &)));
+ connect(m_job, SIGNAL(result(KIO::Job *)), this, SLOT(slotResult(KIO::Job *)));
+ }
+}
+
+void SVGScriptElementImpl::slotData(KIO::Job *, const QByteArray &data)
+{
+ QDataStream dataStream(m_data, IO_WriteOnly | IO_Append);
+ dataStream.writeRawBytes(data.data(), data.size());
+}
+
+void SVGScriptElementImpl::slotResult(KIO::Job *)
+{
+ m_job = 0;
+
+ // Append a NULL terminator so we don't die
+ m_data.resize(m_data.size() + 1);
+ m_data[m_data.size() - 1] = '\0';
+
+ QBuffer buf(m_data);
+ QIODevice *dev = KFilterDev::device(&buf, "application/x-gzip", false);
+ QByteArray contents;
+ if(dev->open(IO_ReadOnly))
+ contents = dev->readAll();
+ delete dev;
+ m_text = QString::fromUtf8(contents.data());
+
+ m_data.resize(0);
+}
+
+bool SVGScriptElementImpl::canExecuteScript()
+{
+ if(!m_added)
+ {
+ m_added = true;
+ m_text += collectText();
+ }
+
+ if(m_text.isEmpty() && !getAttribute("href").isNull() && !getAttribute("href").string().isEmpty())
+ return false;
+
+ return true;
+}
+
+bool SVGScriptElementImpl::executeScript(DOM::Node node)
+{
+ return SVGScriptElementImpl::executeScript(node, ownerDoc(), m_text);
+}
+
+bool SVGScriptElementImpl::executeScript(DOM::Node node, SVGDocumentImpl *document, const QString &text)
+{
+#ifdef KJS_VERBOSE
+ kdDebug(6070) << "SVGScriptElementImpl::executeScript n=" << node.nodeName().string().latin1() << "(" << (node.isNull() ? 0 : node.nodeType()) << ") " << text << endl;
+#endif
+ KSVGEcma *ecmaEngine = document->ecmaEngine();
+
+ if(!ecmaEngine->initialized())
+ ecmaEngine->setup();
+
+ KJS::Value thisNode = node.isNull() ? ecmaEngine->globalObject() : getDOMNode(ecmaEngine->globalExec(), node);
+
+ KJS::UString code(text);
+ KJS::Completion comp = ecmaEngine->evaluate(code, thisNode);
+
+ // TODO: If that's needed find a better solution which
+ // doesn't cause endless loops if the func, specified in
+ // onerror="..." isn't yet available
+ // onerror support
+// if(comp.complType() == Throw)
+// document->rootElement()->dispatchEvent(SVGEventImpl::ERROR_EVENT, false, false);
+
+ return (comp.complType() == KJS::Normal) || (comp.complType() == KJS::ReturnValue);
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGScriptElementImpl::s_hashTable 2
+ type SVGScriptElementImpl::Type DontDelete
+@end
+*/
+
+Value SVGScriptElementImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case Type:
+ return String(type());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGScriptElementImpl::putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int)
+{
+ switch(token)
+ {
+ case Type:
+ setType(value.toString(exec).string());
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGScriptElementImpl.h b/ksvg/impl/SVGScriptElementImpl.h
new file mode 100644
index 00000000..95affee2
--- /dev/null
+++ b/ksvg/impl/SVGScriptElementImpl.h
@@ -0,0 +1,90 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGScriptElementImpl_H
+#define SVGScriptElementImpl_H
+
+#include <dom/dom_string.h>
+
+#include <kio/jobclasses.h>
+
+#include <qobject.h>
+
+#include "SVGElementImpl.h"
+#include "SVGURIReferenceImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGScriptElementImpl : public QObject,
+ public SVGElementImpl,
+ public SVGURIReferenceImpl,
+ public SVGExternalResourcesRequiredImpl
+{
+Q_OBJECT
+public:
+ SVGScriptElementImpl(DOM::ElementImpl *);
+ virtual ~SVGScriptElementImpl();
+
+ void setType(const DOM::DOMString &type);
+ DOM::DOMString type() const;
+
+ virtual void setAttributes();
+
+ bool canExecuteScript();
+ bool executeScript(DOM::Node node);
+
+ static bool executeScript(DOM::Node node, SVGDocumentImpl *document, const QString &text);
+
+private slots:
+ void slotData(KIO::Job *, const QByteArray &);
+ void slotResult(KIO::Job *);
+
+private:
+ KIO::TransferJob *m_job;
+ QByteArray m_data;
+ QString m_text;
+ bool m_added;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+ KSVG_BRIDGE
+
+ enum
+ {
+ // Properties
+ Type
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+KSVG_REGISTER_ELEMENT(SVGScriptElementImpl, "script")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGSetElementImpl.cc b/ksvg/impl/SVGSetElementImpl.cc
new file mode 100644
index 00000000..66460db9
--- /dev/null
+++ b/ksvg/impl/SVGSetElementImpl.cc
@@ -0,0 +1,48 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGDocumentImpl.h"
+#include "SVGSetElementImpl.h"
+
+using namespace KSVG;
+
+SVGSetElementImpl::SVGSetElementImpl(DOM::ElementImpl *impl) : SVGAnimationElementImpl(impl)
+{
+}
+
+SVGSetElementImpl::~SVGSetElementImpl()
+{
+}
+
+void SVGSetElementImpl::setAttributes()
+{
+ SVGAnimationElementImpl::setAttributes();
+
+ // Always create singleShot timers when used by <set> (Niko)
+ // Those are automatically deleted by the scheduler after timeout.
+ ownerDoc()->timeScheduler()->addTimer(this, int(getStartTime() * 1000.0));
+}
+
+void SVGSetElementImpl::handleTimerEvent()
+{
+ applyAttribute(getAttributeName(), getTo());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGSetElementImpl.h b/ksvg/impl/SVGSetElementImpl.h
new file mode 100644
index 00000000..ab9f5ec5
--- /dev/null
+++ b/ksvg/impl/SVGSetElementImpl.h
@@ -0,0 +1,54 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGSetElementImpl_H
+#define SVGSetElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGAnimationElementImpl.h"
+
+class QTimer;
+
+namespace KSVG
+{
+
+class SVGSetElementImpl : public SVGAnimationElementImpl
+{
+public:
+ SVGSetElementImpl(DOM::ElementImpl *);
+ virtual ~SVGSetElementImpl();
+
+ virtual void handleTimerEvent();
+ virtual void setAttributes();
+
+public:
+ KSVG_BRIDGE
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+KSVG_REGISTER_ELEMENT(SVGSetElementImpl, "set")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGShapeImpl.cc b/ksvg/impl/SVGShapeImpl.cc
new file mode 100644
index 00000000..68e89aaa
--- /dev/null
+++ b/ksvg/impl/SVGShapeImpl.cc
@@ -0,0 +1,162 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGPaint.h"
+
+#include "SVGRectImpl.h"
+#include "SVGEventImpl.h"
+#include "SVGShapeImpl.h"
+#include "SVGPaintImpl.h"
+#include "SVGMatrixImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGClipPathElementImpl.h"
+#include "SVGAnimatedLengthListImpl.h"
+
+#include "CanvasItem.h"
+#include "KSVGCanvas.h"
+
+using namespace KSVG;
+
+SVGShapeImpl::SVGShapeImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl)
+{
+ m_item = 0;
+}
+
+SVGShapeImpl::~SVGShapeImpl()
+{
+ if(hasChildNodes())
+ {
+ DOM::Node node = firstChild();
+ for(; !node.isNull(); node = node.nextSibling())
+ {
+ SVGShapeImpl *rend = dynamic_cast<SVGShapeImpl *>(ownerDoc()->getElementFromHandle(node.handle()));
+ if(rend)
+ rend->deref();
+ }
+ }
+}
+
+bool SVGShapeImpl::directRender()
+{
+ SVGShapeImpl *parent = dynamic_cast<SVGShapeImpl *>(ownerDoc()->getElementFromHandle(parentNode().handle()));
+ if(parent)
+ return parent->directRender();
+ else
+ return true;
+}
+
+SVGRectImpl *SVGShapeImpl::getBBox()
+{
+ SVGRectImpl *rect = SVGSVGElementImpl::createSVGRect();
+ return rect;
+}
+
+SVGRectImpl *SVGShapeImpl::getBBoxInternal()
+{
+ SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect();
+ if(m_item)
+ {
+ QRect r = m_item->bbox();
+ ret->setX(r.x());
+ ret->setY(r.y());
+ ret->setWidth(r.width());
+ ret->setHeight(r.height());
+ }
+ return ret;
+}
+
+bool SVGShapeImpl::prepareMouseEvent(const QPoint &p, const QPoint &, SVGMouseEventImpl *mev)
+{
+ // TODO : pointer-events should be stored here, not in SVGStylableImpl.
+ SVGStylableImpl *style = dynamic_cast<SVGStylableImpl *>(this);
+ if(!style || style->getPointerEvents() == PE_NONE)
+ return false;
+ bool testFill = false;
+ bool testStroke = false;
+ switch(style->getPointerEvents())
+ {
+ case PE_VISIBLE: testFill = testStroke = style->getVisible(); break;
+ case PE_VISIBLE_PAINTED: testStroke = style->getVisible() && style->isStroked();
+ case PE_VISIBLE_FILL: testFill = style->getVisible() && style->isFilled(); break;
+ case PE_VISIBLE_STROKE: testStroke = style->getVisible() && style->isStroked(); break;
+ case PE_PAINTED: testStroke = style->isStroked();
+ case PE_FILL: testFill = style->isFilled(); break;
+ case PE_STROKE: testStroke = style->isStroked(); break;
+ case PE_ALL:
+ default: testFill = testStroke = true;
+ };
+
+ if(testFill || testStroke)
+ {
+ if((testFill && m_item->fillContains(p)) || (testStroke && m_item->strokeContains(p)))
+ {
+ mev->setTarget(this);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void SVGShapeImpl::update(CanvasItemUpdate reason, int param1, int param2)
+{
+ if(m_item)
+ m_item->update(reason, param1, param2);
+}
+
+void SVGShapeImpl::invalidate(KSVGCanvas *c, bool recalc)
+{
+ if(m_item && c)
+ c->invalidate(m_item, recalc);
+}
+
+void SVGShapeImpl::setReferenced(bool referenced)
+{
+ if(m_item)
+ m_item->setReferenced(referenced);
+}
+
+void SVGShapeImpl::draw()
+{
+ if(m_item)
+ m_item->draw();
+}
+
+void SVGShapeImpl::blit(KSVGCanvas *c)
+{
+ SVGRectImpl *rect = getBBoxInternal();
+ c->blit(rect->qrect(), true);
+ rect->deref();
+}
+
+void SVGShapeImpl::removeItem(KSVGCanvas *c)
+{
+ if(m_item && c)
+ {
+ c->removeItem(m_item);
+ m_item = 0;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGShapeImpl.h b/ksvg/impl/SVGShapeImpl.h
new file mode 100644
index 00000000..ae183251
--- /dev/null
+++ b/ksvg/impl/SVGShapeImpl.h
@@ -0,0 +1,73 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGShapeImpl_H
+#define SVGShapeImpl_H
+
+#include "SVGElementImpl.h"
+#include "CanvasItem.h"
+
+class QPoint;
+
+namespace KSVG
+{
+
+class KSVGCanvas;
+
+class SVGRectImpl;
+class SVGMouseEventImpl;
+
+class SVGShapeImpl : public SVGElementImpl
+{
+public:
+ SVGShapeImpl(DOM::ElementImpl *);
+ virtual ~SVGShapeImpl();
+
+ virtual SVGRectImpl *getBBox();
+ virtual SVGRectImpl *getBBoxInternal();
+
+ virtual bool prepareMouseEvent(const QPoint &p, const QPoint &a, SVGMouseEventImpl *mev);
+
+ virtual bool directRender();
+ virtual bool isContainer() const { return false; }
+
+ virtual void update(CanvasItemUpdate reason, int param1 = 0, int param2 = 0);
+ virtual void invalidate(KSVGCanvas *c, bool recalc);
+ virtual void setReferenced(bool referenced);
+ virtual void draw();
+ virtual void blit(KSVGCanvas *);
+
+ virtual void removeItem(KSVGCanvas *c);
+
+ CanvasItem *item() { return m_item; }
+
+protected:
+ CanvasItem *m_item;
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGStopElementImpl.cc b/ksvg/impl/SVGStopElementImpl.cc
new file mode 100644
index 00000000..09761232
--- /dev/null
+++ b/ksvg/impl/SVGStopElementImpl.cc
@@ -0,0 +1,125 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+#include "SVGLengthImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGStopElementImpl.h"
+#include "SVGAnimatedNumberImpl.h"
+#include "SVGColorImpl.h"
+
+using namespace KSVG;
+
+#include "SVGStopElementImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+
+SVGStopElementImpl::SVGStopElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGStylableImpl(this)
+{
+ KSVG_EMPTY_FLAGS
+
+ m_offset = new SVGAnimatedNumberImpl();
+ m_offset->ref();
+
+ m_stopOpacity = 1;
+}
+
+SVGStopElementImpl::~SVGStopElementImpl()
+{
+ if(m_offset)
+ m_offset->deref();
+}
+
+SVGAnimatedNumberImpl *SVGStopElementImpl::offset() const
+{
+ return m_offset;
+}
+
+float SVGStopElementImpl::stopOpacity() const
+{
+ return m_stopOpacity;
+}
+
+
+/*
+@namespace KSVG
+@begin SVGStopElementImpl::s_hashTable 3
+ offset SVGStopElementImpl::Offset DontDelete|ReadOnly
+ stop-opacity SVGStopElementImpl::StopOpacity DontDelete|ReadOnly
+@end
+*/
+
+Value SVGStopElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ KSVG_CHECK_ATTRIBUTE
+
+ switch(token)
+ {
+ case Offset:
+ if(!attributeMode)
+ return m_offset->cache(exec);
+ else
+ return Number(m_offset->baseVal());
+ case StopOpacity:
+ if(!attributeMode)
+ return Undefined();
+ else
+ return Number(m_stopOpacity);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGStopElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case Offset:
+ float temp;
+ SVGLengthImpl::convertPercentageToFloat(value.toString(exec).qstring(), temp);
+ offset()->setBaseVal(temp);
+ break;
+ case StopOpacity:
+ {
+ SVGLengthImpl::convertPercentageToFloat(value.toString(exec).qstring(), m_stopOpacity);
+ break;
+ }
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+void SVGStopElementImpl::setAttributes()
+{
+ SVGElementImpl::setAttributes();
+
+ // Spec: if not set, specifiy 0
+ if(KSVG_TOKEN_NOT_PARSED(Offset))
+ KSVG_SET_ALT_ATTRIBUTE(Offset, "0")
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGStopElementImpl.h b/ksvg/impl/SVGStopElementImpl.h
new file mode 100644
index 00000000..369b7867
--- /dev/null
+++ b/ksvg/impl/SVGStopElementImpl.h
@@ -0,0 +1,70 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGStopElementImpl_H
+#define SVGStopElementImpl_H
+
+#include "SVGElementImpl.h"
+#include "SVGStylableImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedNumberImpl;
+class SVGStopElementImpl : public SVGElementImpl,
+ public SVGStylableImpl
+{
+public:
+ SVGStopElementImpl(DOM::ElementImpl *);
+ virtual ~SVGStopElementImpl();
+
+ SVGAnimatedNumberImpl *offset() const;
+ float stopOpacity() const;
+
+ virtual void setAttributes();
+
+private:
+ SVGAnimatedNumberImpl *m_offset;
+ float m_stopOpacity;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+ KSVG_BRIDGE
+
+ enum
+ {
+ // Properties
+ Offset, StopOpacity
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+KSVG_REGISTER_ELEMENT(SVGStopElementImpl, "stop")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGStringListImpl.cc b/ksvg/impl/SVGStringListImpl.cc
new file mode 100644
index 00000000..b70adfdd
--- /dev/null
+++ b/ksvg/impl/SVGStringListImpl.cc
@@ -0,0 +1,93 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGStringListImpl.h"
+
+using namespace KSVG;
+
+#include "SVGStringListImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SharedString::s_hashTable 2
+ dummy SharedString::Dummy DontDelete|ReadOnly
+@end
+*/
+
+/*
+@namespace KSVG
+@begin SVGStringListImpl::s_hashTable 2
+ numberOfItems SVGListDefs::NumberOfItems DontDelete|ReadOnly
+@end
+@namespace KSVG
+@begin SVGStringListImplProto::s_hashTable 11
+ getItem SVGListDefs::GetItem DontDelete|Function 1
+ removeItem SVGListDefs::RemoveItem DontDelete|Function 1
+ appendItem SVGListDefs::AppendItem DontDelete|Function 1
+ initialize SVGListDefs::Initialize DontDelete|Function 1
+ insertItemBefore SVGListDefs::InsertItemBefore DontDelete|Function 2
+ replaceItem SVGListDefs::ReplaceItem DontDelete|Function 2
+ clear SVGListDefs::Clear DontDelete|Function 0
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGStringList", SVGStringListImplProto, SVGStringListImplProtoFunc)
+
+Value SVGStringListImpl::getValueProperty(ExecState *exec, int token) const
+{
+ return SVGList<SharedString>::getValueProperty(exec, token);
+}
+
+Value SVGStringListImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGStringListImpl)
+
+ return obj->call(exec, static_cast<SVGList<SharedString> *>(obj), args, id);
+}
+
+QString SVGStringListImpl::join(const QString &seperator) const
+{
+ SVGStringListImpl *self = const_cast<SVGStringListImpl *>(this);
+
+ QString result;
+
+ if(!self->getItem(0))
+ return result;
+ else
+ result += self->getItem(0)->string();
+
+ for(unsigned int i = 1; i <= numberOfItems(); i++)
+ {
+ DOM::DOMString *string = self->getItem(i);
+
+ if(string)
+ result += seperator + string->string();
+ }
+
+ return result;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGStringListImpl.h b/ksvg/impl/SVGStringListImpl.h
new file mode 100644
index 00000000..7f69a3c9
--- /dev/null
+++ b/ksvg/impl/SVGStringListImpl.h
@@ -0,0 +1,82 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGStringListImpl_H
+#define SVGStringListImpl_H
+
+#include <dom/dom_string.h>
+
+#include "SVGList.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SharedString : public DOM::DomShared,
+ public DOM::DOMString
+{
+public:
+ SharedString() : DOM::DomShared(), DOM::DOMString() { }
+ SharedString(const QString &string) : DOM::DomShared(), DOM::DOMString(string) { }
+ SharedString(const SharedString &string) : DOM::DomShared(), DOM::DOMString(string) { }
+ SharedString(DOM::DOMString *string) : DOM::DomShared(), DOM::DOMString(string->implementation()) { }
+ virtual ~SharedString() { }
+
+public:
+ KSVG_GET
+
+ enum
+ {
+ // Properties
+ Dummy
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *, int token) const
+ {
+ switch(token)
+ {
+ case Dummy:
+ return KJS::Undefined();
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return KJS::Undefined();
+ }
+ }
+};
+
+class SVGStringListImpl : public SVGList<SharedString>
+{
+public:
+ KSVG_GET
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+
+ QString join(const QString &seperator) const;
+};
+
+}
+
+KSVG_DEFINE_PROTOTYPE(SVGStringListImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGStringListImplProtoFunc, SVGStringListImpl)
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGStylableImpl.cc b/ksvg/impl/SVGStylableImpl.cc
new file mode 100644
index 00000000..096ebf93
--- /dev/null
+++ b/ksvg/impl/SVGStylableImpl.cc
@@ -0,0 +1,1309 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include <qrect.h>
+
+#include "CanvasItem.h"
+#include "KSVGCanvas.h"
+
+#include "SVGPaint.h"
+#include "SVGColorImpl.h"
+#include "SVGPaintImpl.h"
+#include "SVGHelperImpl.h"
+#include "SVGLengthImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGStringListImpl.h"
+#include "SVGImageElementImpl.h"
+#include "SVGURIReferenceImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGColorProfileElementImpl.h"
+#include "SVGAnimatedLengthListImpl.h"
+
+using namespace KSVG;
+
+#include "SVGStylableImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+
+SVGStylableImpl::SVGStylableImpl(SVGElementImpl *object) : m_object(object)
+{
+ KSVG_EMPTY_FLAGS
+
+ // View propidx.html, if you want to verify those default values (Niko)
+ m_flags = SVG_STYLE_FLAG_NONE;
+
+ // Initialize all pointers to 0
+ // Important!
+ m_color = 0;
+ m_fillColor = 0;
+ m_stopColor = 0;
+ m_dashArray = 0;
+ m_dashOffset = 0;
+ m_strokeWidth = 0;
+ m_strokeColor = 0;
+ m_fontFamily = 0;
+
+ m_fillOpacity = 1;
+ m_strokeOpacity = 1;
+ m_opacity = 1;
+
+ // Special case, getFontSize() could be accessed
+ // _before_ processStyle() is called -> no default
+ // value for font-size yet -> crash
+ // SVGLengthImpl access it when parsing em/ex values (Niko)
+ m_fontSize = -1;
+}
+
+SVGStylableImpl::~SVGStylableImpl()
+{
+ if(m_strokeWidth)
+ m_strokeWidth->deref();
+ if(m_fontFamily)
+ m_fontFamily->deref();
+ if(m_strokeColor)
+ m_strokeColor->deref();
+ if(m_fillColor)
+ m_fillColor->deref();
+ if(m_color)
+ m_color->deref();
+ if(m_stopColor)
+ m_stopColor->deref();
+ if(m_dashOffset)
+ m_dashOffset->deref();
+ if(m_dashArray)
+ m_dashArray->deref();
+}
+
+void SVGStylableImpl::processStyle()
+{
+ SVGStylableImpl *parentStyle = 0;
+ if(m_object && m_object->ownerDoc())
+ parentStyle = dynamic_cast<SVGStylableImpl *>(m_object->ownerDoc()->getElementFromHandle((*m_object).parentNode().handle()));
+
+ // Spec: default "none"
+ if(~m_flags & SVG_STYLE_FLAG_STROKE)
+ {
+ m_strokeColor = new SVGPaintImpl(m_object);
+ m_strokeColor->ref();
+
+ SVGPaintImpl *strokeColor = 0L;
+ if(parentStyle)
+ strokeColor = parentStyle->getStrokeColor();
+
+ if(strokeColor)
+ *m_strokeColor = *strokeColor;
+ else
+ m_strokeColor->setPaint(SVG_PAINTTYPE_NONE);
+ }
+
+ // Spec: default "black"
+ if(~m_flags & SVG_STYLE_FLAG_FILL)
+ {
+ m_fillColor = new SVGPaintImpl(m_object);
+ m_fillColor->ref();
+
+ SVGPaintImpl *fillColor = 0;
+ if(parentStyle)
+ fillColor = parentStyle->getFillColor();
+
+ if(fillColor)
+ *m_fillColor = *fillColor;
+ else
+ m_fillColor->setRGBColor(DOM::DOMString("black"));
+ }
+
+ // Spec: no real default
+ if(~m_flags & SVG_STYLE_FLAG_COLOR)
+ {
+ m_color = new SVGColorImpl(m_object);
+ m_color->ref();
+ SVGColorImpl *color = 0;
+ if(parentStyle)
+ color = parentStyle->getColor();
+
+ if(color)
+ *m_color = *color;
+ }
+
+ // Spec: default sRGB
+ if(~m_flags & SVG_STYLE_FLAG_COLOR_INTERPOLATION)
+ {
+ if(parentStyle)
+ m_colorInterpolation = parentStyle->getColorInterpolation();
+ else
+ m_colorInterpolation = CI_SRGB;
+ }
+
+ // Spec: default "1"
+ if(~m_flags & SVG_STYLE_FLAG_STROKE_WIDTH)
+ {
+ m_strokeWidth = new SVGAnimatedLengthImpl(LENGTHMODE_OTHER, m_object);
+ m_strokeWidth->ref();
+
+ SVGAnimatedLengthImpl *strokeWidth = 0;
+ if(parentStyle)
+ strokeWidth = parentStyle->getStrokeWidth();
+
+ if(strokeWidth)
+ *m_strokeWidth = *strokeWidth;
+ else
+ m_strokeWidth->baseVal()->setValue(1.0);
+ }
+
+ // Spec: default "4"
+ if(~m_flags & SVG_STYLE_FLAG_STROKE_MITER_LIMIT)
+ {
+ if(parentStyle)
+ m_strokeMiterlimit = parentStyle->getStrokeMiterlimit();
+ else
+ m_strokeMiterlimit = 4;
+ }
+
+ // Spec: default "butt"
+ if(~m_flags & SVG_STYLE_FLAG_STROKE_LINE_CAP)
+ {
+ if(parentStyle)
+ m_capStyle = parentStyle->getCapStyle();
+ else
+ m_capStyle = PATH_STROKE_CAP_BUTT;
+ }
+
+ // Spec: default "miter"
+ if(~m_flags & SVG_STYLE_FLAG_STROKE_LINE_JOIN)
+ {
+ if(parentStyle)
+ m_joinStyle = parentStyle->getJoinStyle();
+ else
+ m_joinStyle = PATH_STROKE_JOIN_MITER;
+ }
+
+ // Spec: default "auto"
+ if(~m_flags & SVG_STYLE_FLAG_CURSOR)
+ {
+ if(parentStyle)
+ m_cursor = parentStyle->getCursor();
+ else
+ m_cursor = CURSOR_AUTO;
+ }
+
+ // Spec: default "visiblePainted"
+ if(~m_flags & SVG_STYLE_FLAG_POINTER_EVENTS)
+ {
+ if(parentStyle)
+ m_pointerEvents = parentStyle->getPointerEvents();
+ else
+ m_pointerEvents = PE_VISIBLE_PAINTED;
+ }
+
+ // Spec: default "0"
+ if(~m_flags & SVG_STYLE_FLAG_STROKE_DASH_OFFSET)
+ {
+ m_dashOffset = new SVGAnimatedLengthImpl(LENGTHMODE_OTHER, m_object);
+ m_dashOffset->ref();
+
+ SVGAnimatedLengthImpl *dashOffset = 0;
+ if(parentStyle)
+ dashOffset = parentStyle->getDashOffset();
+
+ if(dashOffset)
+ *m_dashOffset = *dashOffset;
+ else
+ m_dashOffset->baseVal()->setValue(0);
+ }
+
+ // Spec: default "none" -> 0 == empty dash array
+ if(~m_flags & SVG_STYLE_FLAG_STROKE_DASH_ARRAY)
+ {
+ SVGAnimatedLengthListImpl *dashArray = 0;
+ if(parentStyle)
+ dashArray = parentStyle->getDashArray();
+
+ if(dashArray)
+ {
+ if (!m_dashArray)
+ {
+ m_dashArray = new SVGAnimatedLengthListImpl();
+ m_dashArray->ref();
+ }
+ *m_dashArray = *dashArray;
+ }
+ else
+ m_dashArray = 0;
+ }
+
+ // Spec: default "1" -> 1 == Not opaque
+ if(~m_flags & SVG_STYLE_FLAG_FILL_OPACITY)
+ {
+ if(parentStyle)
+ m_fillOpacity = parentStyle->getFillOpacity();
+ else
+ m_fillOpacity = 1;
+ }
+
+ if(~m_flags & SVG_STYLE_FLAG_STROKE_OPACITY)
+ {
+ if(parentStyle)
+ m_strokeOpacity = parentStyle->getStrokeOpacity();
+ else
+ m_strokeOpacity = 1;
+ }
+
+ // Fake group opacity by multiplying by our parent's group opacity
+ if(~m_flags & SVG_STYLE_FLAG_OPACITY)
+ {
+ if(parentStyle)
+ m_opacity = parentStyle->getOpacity();
+ else
+ m_opacity = 1;
+ }
+ else
+ if(parentStyle)
+ m_opacity *= parentStyle->getOpacity();
+
+ if(~m_flags & SVG_STYLE_FLAG_CLIP_PATH)
+ m_clipPath = "";
+
+ if(~m_flags & SVG_STYLE_FLAG_MASK)
+ m_mask = "";
+
+ // Spec: default "nonzero"
+ if(~m_flags & SVG_STYLE_FLAG_FILL_RULE)
+ {
+ if(parentStyle)
+ m_fillRule = parentStyle->getFillRule();
+ else
+ m_fillRule = RULE_NONZERO;
+ }
+
+ if(~m_flags & SVG_STYLE_FLAG_CLIP_RULE)
+ {
+ if(parentStyle)
+ m_clipRule = parentStyle->getClipRule();
+ else
+ m_clipRule = RULE_NONZERO;
+ }
+
+ // Spec: default "hidden"
+ if(~m_flags & SVG_STYLE_FLAG_OVERFLOW)
+ {
+ if(parentStyle)
+ m_overflow = parentStyle->getOverflow();
+ else
+ m_overflow = false;
+ }
+
+ // We are not really, spec compatible here, we just
+ // define a bool, to indicate wheter an element should
+ // be rendered or not.
+ if(~m_flags & SVG_STYLE_FLAG_DISPLAY)
+ m_display = true;
+
+ if(~m_flags & SVG_STYLE_FLAG_VISIBILITY)
+ {
+ if(parentStyle)
+ m_visible = parentStyle->getVisible();
+ else
+ m_visible = true;
+ }
+
+ // Spec: default "medium"
+ if(~m_flags & SVG_STYLE_FLAG_FONT_SIZE)
+ {
+ if(parentStyle)
+ m_fontSize = parentStyle->getFontSize();
+ else
+ m_fontSize = fontSizeForText("medium");
+ }
+
+ // Spec: default "depends on user agent" -> "Arial" for SVG
+ if(~m_flags & SVG_STYLE_FLAG_FONT_FAMILY)
+ {
+ if(!m_fontFamily)
+ {
+ m_fontFamily = new SVGStringListImpl();
+ m_fontFamily->ref();
+ }
+
+ SVGStringListImpl *fontFamily = 0;
+ if(parentStyle)
+ fontFamily = parentStyle->getFontFamily();
+
+ if(fontFamily)
+ *m_fontFamily = *fontFamily;
+ else
+ {
+ SharedString *string = new SharedString("Arial");
+ string->ref();
+
+ m_fontFamily->appendItem(string);
+ }
+ }
+
+ // Spec: default "normal"
+ if(~m_flags & SVG_STYLE_FLAG_FONT_STYLE)
+ {
+ if(parentStyle)
+ m_fontStyle = parentStyle->getFontStyle();
+ else
+ m_fontStyle = FSNORMAL;
+ }
+
+ // Spec: default "normal"
+ if(~m_flags & SVG_STYLE_FLAG_FONT_WEIGHT)
+ {
+ if(parentStyle)
+ m_fontWeight = parentStyle->getFontWeight();
+ else
+ m_fontWeight = "normal";
+ }
+
+ // Spec: default "start"
+ if(~m_flags & SVG_STYLE_FLAG_TEXT_ANCHOR)
+ {
+ if(parentStyle)
+ m_textAnchor = parentStyle->getTextAnchor();
+ else
+ m_textAnchor = TASTART;
+ }
+
+ // Spec: default "LTR"
+ if(~m_flags & SVG_STYLE_FLAG_TEXT_DIRECTION)
+ {
+ if(parentStyle)
+ m_textDirection = parentStyle->getTextDirection();
+ else
+ m_textDirection = LTR;
+ }
+
+ // Spec: default "none"
+ if(~m_flags & SVG_STYLE_FLAG_TEXT_DECORATION)
+ {
+ if(parentStyle)
+ m_textDecoration = parentStyle->getTextDecoration();
+ else
+ m_textDecoration = TDNONE;
+ }
+
+ // Spec: default "baseline"
+ if(~m_flags & SVG_STYLE_FLAG_BASELINE_SHIFT)
+ {
+ if(parentStyle)
+ m_baselineShift = parentStyle->getBaselineShift();
+ else
+ m_baselineShift = "baseline";
+ }
+
+ // Spec: default "lr-tb", FIXME
+ if(~m_flags & SVG_STYLE_FLAG_TEXT_WRITING_MODE)
+ {
+ if(parentStyle)
+ m_textWritingMode = parentStyle->getTextWritingMode();
+ else
+ m_textWritingMode = LR;
+ }
+
+ // Spec: default "normal"
+ if(~m_flags & SVG_STYLE_FLAG_TEXT_UNICODE_BIDI)
+ {
+ if(parentStyle)
+ m_textUnicodeBidi = parentStyle->getTextUnicodeBidi();
+ else
+ m_textUnicodeBidi = UBNORMAL;
+ }
+
+ // Spec: default "auto"
+ if(~m_flags & SVG_STYLE_FLAG_GLYPH_ORIENTATION_VERTICAL)
+ {
+ if(parentStyle)
+ m_glyphOrientationVertical = parentStyle->getGlyphOrientationVertical();
+ else
+ m_glyphOrientationVertical = "auto";
+ }
+
+ // Spec: default "auto"
+ if(~m_flags & SVG_STYLE_FLAG_GLYPH_ORIENTATION_HORIZONTAL)
+ {
+ if(parentStyle)
+ m_glyphOrientationHorizontal = parentStyle->getGlyphOrientationHorizontal();
+ else
+ m_glyphOrientationHorizontal = "auto";
+ }
+
+ // Spec: default "normal"
+ if(~m_flags & SVG_STYLE_FLAG_LETTER_SPACING)
+ {
+ if(parentStyle)
+ m_letterSpacing = parentStyle->getLetterSpacing();
+ else
+ m_letterSpacing = "normal";
+ }
+
+ // Spec: default "normal"
+ if(~m_flags & SVG_STYLE_FLAG_WORD_SPACING)
+ {
+ if(parentStyle)
+ m_wordSpacing = parentStyle->getWordSpacing();
+ else
+ m_wordSpacing = "normal";
+ }
+
+ // Spec: default "black"
+ if(~m_flags & SVG_STYLE_FLAG_STOP)
+ {
+ m_stopColor = new SVGColorImpl(m_object);
+ m_stopColor->ref();
+
+ m_stopColor->setRGBColor(DOM::DOMString("black"));
+ }
+
+ // Spec: default "none"
+ if(~m_flags & SVG_STYLE_FLAG_MARKER_START)
+ {
+ if(parentStyle)
+ m_startMarker = parentStyle->getStartMarker();
+ else
+ m_startMarker = QString::null;
+ }
+
+ // Spec: default "none"
+ if(~m_flags & SVG_STYLE_FLAG_MARKER_MID)
+ {
+ if(parentStyle)
+ m_midMarker = parentStyle->getMidMarker();
+ else
+ m_midMarker = QString::null;
+ }
+
+ // Spec: default "none"
+ if(~m_flags & SVG_STYLE_FLAG_MARKER_END)
+ {
+ if(parentStyle)
+ m_endMarker = parentStyle->getEndMarker();
+ else
+ m_endMarker = QString::null;
+ }
+}
+
+bool SVGStylableImpl::isStroked() const
+{
+ if(!m_strokeColor)
+ return false;
+
+ return m_strokeColor->paintType() != SVG_PAINTTYPE_UNKNOWN &&
+ m_strokeColor->paintType() != SVG_PAINTTYPE_NONE &&
+ m_strokeColor->paintType() != SVG_PAINTTYPE_URI_NONE;
+}
+
+bool SVGStylableImpl::isFilled() const
+{
+ if(!m_fillColor)
+ return false;
+
+ return m_fillColor->paintType() != SVG_PAINTTYPE_UNKNOWN &&
+ m_fillColor->paintType() != SVG_PAINTTYPE_NONE &&
+ m_fillColor->paintType() != SVG_PAINTTYPE_URI_NONE;
+}
+
+QString SVGStylableImpl::extractUrlId(const QString &url)
+{
+ QString id;
+
+ if(url.startsWith("url(#"))
+ {
+ int idstart = url.find("#") + 1;
+ id = url.mid(idstart, url.length() - idstart - 1);
+ }
+ else
+ id = url;
+
+ return id;
+}
+
+void SVGStylableImpl::setMarkers(const QString &marker)
+{
+ setStartMarker(marker);
+ setMidMarker(marker);
+ setEndMarker(marker);
+}
+
+void SVGStylableImpl::setStartMarker(const QString &startMarker)
+{
+ if(startMarker.startsWith("url(#"))
+ {
+ int idstart = startMarker.find("#") + 1;
+ m_startMarker = startMarker.mid(idstart, startMarker.length() - idstart - 1);
+ }
+ else if(startMarker == "none")
+ m_startMarker = QString::null;
+}
+
+void SVGStylableImpl::setMidMarker(const QString &midMarker)
+{
+ if(midMarker.startsWith("url(#"))
+ {
+ int idstart = midMarker.find("#") + 1;
+ m_midMarker = midMarker.mid(idstart, midMarker.length() - idstart - 1);
+ }
+ else if(midMarker == "none")
+ m_midMarker = QString::null;
+}
+
+void SVGStylableImpl::setEndMarker(const QString &endMarker)
+{
+ if(endMarker.startsWith("url(#"))
+ {
+ int idstart = endMarker.find("#") + 1;
+ m_endMarker = endMarker.mid(idstart, endMarker.length() - idstart - 1);
+ }
+ else if(endMarker == "none")
+ m_endMarker = QString::null;
+}
+
+bool SVGStylableImpl::hasMarkers() const
+{
+ return !m_startMarker.isEmpty() || !m_midMarker.isEmpty() || !m_endMarker.isEmpty();
+}
+
+void SVGStylableImpl::setPaint(const QString &param, SVGPaintImpl *svgPaint)
+{
+ if(param.stripWhiteSpace() == "none")
+ svgPaint->setPaint(SVG_PAINTTYPE_NONE, DOM::DOMString(""), DOM::DOMString(""));
+ else if(SVGURIReferenceImpl::isUrl(param))
+ svgPaint->setUri(SVGURIReferenceImpl::getTarget(param));
+ else
+ setColor(param, svgPaint);
+}
+
+void SVGStylableImpl::setColor(const QString &param, SVGColorImpl *svgColor)
+{
+ if(param.stripWhiteSpace().startsWith("#"))
+ {
+ if(param.contains("icc-color"))
+ {
+ QString first = param.left(7);
+ QString last = param.right(param.length() - 8);
+
+ svgColor->setRGBColorICCColor(first, last);
+ }
+ else
+ {
+ QColor color;
+ color.setNamedColor(param.stripWhiteSpace());
+ svgColor->setRGBColor(color);
+ }
+ }
+ else if(param.stripWhiteSpace().startsWith("rgb("))
+ {
+ QString parse = param.stripWhiteSpace();
+ QStringList colors = QStringList::split(',', parse);
+ QString r = colors[0].right((colors[0].length() - 4));
+ QString g = colors[1];
+ QString b = colors[2].left((colors[2].length() - 1));
+
+ if(r.contains("%"))
+ {
+ r = r.left(r.length() - 1);
+ r = QString::number(int((double(255 * r.toDouble()) / 100.0)));
+ }
+
+ if(g.contains("%"))
+ {
+ g = g.left(g.length() - 1);
+ g = QString::number(int((double(255 * g.toDouble()) / 100.0)));
+ }
+
+ if(b.contains("%"))
+ {
+ b = b.left(b.length() - 1);
+ b = QString::number(int((double(255 * b.toDouble()) / 100.0)));
+ }
+
+ svgColor->setRGBColor(int(r.toFloat()), int(g.toFloat()), int(b.toFloat()));
+ }
+ else
+ {
+ if(param.stripWhiteSpace().lower() == "currentcolor")
+ svgColor->setColor(SVG_COLORTYPE_CURRENTCOLOR, DOM::DOMString(""), DOM::DOMString(""));
+ else
+ svgColor->setRGBColor(DOM::DOMString(param.stripWhiteSpace().lower()));
+ }
+}
+
+QRect SVGStylableImpl::clip()
+{
+ return QRect();
+}
+
+void SVGStylableImpl::setClip(const QString &)
+{
+}
+
+float SVGStylableImpl::fontSizeForText(const QString &value)
+{
+ float ret = -1;
+
+ // Spec: "On a computer screen a scaling factor of 1.2 is suggested between adjacent indexes"
+ const float factor = 1.2;
+
+ // Spec: "If the 'medium' font is 12pt, the 'large' font could be 14.4pt."
+ const float mediumFont = 12.0;
+
+ if(value == "xx-small")
+ ret = mediumFont - (3.0 * factor);
+ else if(value == "x-small")
+ ret = mediumFont - (2.0 * factor);
+ else if(value == "small")
+ ret = mediumFont - factor;
+ else if(value == "medium")
+ ret = mediumFont;
+ else if(value == "large")
+ ret = mediumFont + factor;
+ else if(value == "x-large")
+ ret = mediumFont + (2.0 * factor);
+ else if(value == "xx-large")
+ ret = mediumFont + (3.0 * factor);
+
+ return ret;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGStylableImpl::s_hashTable 47
+ className SVGStylableImpl::ClassName DontDelete|ReadOnly
+ style SVGStylableImpl::Style DontDelete|ReadOnly
+ stroke-width SVGStylableImpl::StrokeWidth DontDelete|ReadOnly
+ stroke-miterlimit SVGStylableImpl::StrokeMiterlimit DontDelete|ReadOnly
+ stroke-linecap SVGStylableImpl::StrokeLineCap DontDelete|ReadOnly
+ stroke-linejoin SVGStylableImpl::StrokeLineJoin DontDelete|ReadOnly
+ stroke SVGStylableImpl::Stroke DontDelete|ReadOnly
+ fill SVGStylableImpl::Fill DontDelete|ReadOnly
+ color SVGStylableImpl::Color DontDelete|ReadOnly
+ stop-color SVGStylableImpl::StopColor DontDelete|ReadOnly
+ font-size SVGStylableImpl::FontSize DontDelete|ReadOnly
+ font-family SVGStylableImpl::FontFamily DontDelete|ReadOnly
+ font-weight SVGStylableImpl::FontWeight DontDelete|ReadOnly
+ font-style SVGStylableImpl::FontStyle DontDelete|ReadOnly
+ text-decoration SVGStylableImpl::TextDecoration DontDelete|ReadOnly
+ text-anchor SVGStylableImpl::TextAnchor DontDelete|ReadOnly
+ direction SVGStylableImpl::Direction DontDelete|ReadOnly
+ writing-mode SVGStylableImpl::WritingMode DontDelete|ReadOnly
+ unicode-bidi SVGStylableImpl::UnicodeBidi DontDelete|ReadOnly
+ opacity SVGStylableImpl::Opacity DontDelete|ReadOnly
+ fill-opacity SVGStylableImpl::FillOpacity DontDelete|ReadOnly
+ stroke-opacity SVGStylableImpl::StrokeOpacity DontDelete|ReadOnly
+ clip-path SVGStylableImpl::ClipPath DontDelete|ReadOnly
+ marker-start SVGStylableImpl::MarkerStart DontDelete|ReadOnly
+ marker-mid SVGStylableImpl::MarkerMid DontDelete|ReadOnly
+ marker-end SVGStylableImpl::MarkerEnd DontDelete|ReadOnly
+ marker SVGStylableImpl::Marker DontDelete|ReadOnly
+ cursor SVGStylableImpl::Cursor DontDelete|ReadOnly
+ display SVGStylableImpl::Display DontDelete|ReadOnly
+ overflow SVGStylableImpl::Overflow DontDelete|ReadOnly
+ clip SVGStylableImpl::Clip DontDelete|ReadOnly
+ visibility SVGStylableImpl::Visibility DontDelete|ReadOnly
+ fill-rule SVGStylableImpl::FillRule DontDelete|ReadOnly
+ clip-rule SVGStylableImpl::ClipRule DontDelete|ReadOnly
+ stroke-dashoffset SVGStylableImpl::StrokeDashOffset DontDelete|ReadOnly
+ stroke-dasharray SVGStylableImpl::StrokeDashArray DontDelete|ReadOnly
+ color-profile SVGStylableImpl::ColorProfile DontDelete|ReadOnly
+ baseline-shift SVGStylableImpl::BaselineShift DontDelete|ReadOnly
+ letter-spacing SVGStylableImpl::LetterSpacing DontDelete|ReadOnly
+ word-spacing SVGStylableImpl::WordSpacing DontDelete|ReadOnly
+ pointer-events SVGStylableImpl::PointerEvents DontDelete|ReadOnly
+ glyph-orientation-vertical SVGStylableImpl::GlyphOrientationVertical DontDelete|ReadOnly
+ glyph-orientation-horizontal SVGStylableImpl::GlyphOrientationHorizontal DontDelete|ReadOnly
+ color-interpolation SVGStylableImpl::ColorInterpolation DontDelete|ReadOnly
+ mask SVGStylableImpl::Mask DontDelete|ReadOnly
+@end
+@namespace KSVG
+@begin SVGStylableImplProto::s_hashTable 2
+ getStyle SVGStylableImpl::GetStyle DontDelete|Function 0
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGStylable", SVGStylableImplProto, SVGStylableImplProtoFunc)
+
+Value SVGStylableImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ //case ClassName:
+ // return String(className().string());
+ case Style:
+ return String(m_object ? m_object->DOM::Element::getAttribute("style") : "");
+ case Visibility:
+ return String(m_visible ? "visible" : "hidden");
+ case Display:
+ return String(m_display ? "inline" : "none");
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGStylableImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ QString param = value.toString(exec).qstring();
+
+ if (param.isEmpty())
+ return;
+
+ bool redraw = false;
+ bool inherit = (param == "inherit");
+ int update = -1;
+
+ switch(token)
+ {
+ case Style:
+ {
+ if(!m_object)
+ return;
+
+ QStringList substyles = QStringList::split(';', param);
+ for(QStringList::Iterator it = substyles.begin(); it != substyles.end(); ++it)
+ {
+ QStringList substyle = QStringList::split(':', (*it));
+ m_object->setAttributeInternal(substyle[0].stripWhiteSpace(), substyle[1].stripWhiteSpace());
+ }
+ break;
+ }
+ case StrokeWidth:
+ if(m_flags & SVG_STYLE_FLAG_STROKE_WIDTH)
+ {
+ redraw = true;
+ update = UPDATE_LINEWIDTH;
+ }
+ if(inherit)
+ m_flags &= ~SVG_STYLE_FLAG_STROKE_WIDTH;
+ else
+ {
+ m_flags |= SVG_STYLE_FLAG_STROKE_WIDTH;
+
+ if(!m_strokeWidth)
+ {
+ m_strokeWidth = new SVGAnimatedLengthImpl(LENGTHMODE_OTHER, m_object);
+ m_strokeWidth->ref();
+ }
+
+ m_strokeWidth->baseVal()->setValueAsString(param);
+ }
+ break;
+ case StrokeMiterlimit:
+ m_flags |= SVG_STYLE_FLAG_STROKE_MITER_LIMIT;
+ if(!inherit)
+ m_strokeMiterlimit = param.toUInt();
+ break;
+ case StrokeLineCap:
+ m_flags |= SVG_STYLE_FLAG_STROKE_LINE_CAP;
+ if(param == "butt")
+ m_capStyle = PATH_STROKE_CAP_BUTT;
+ else if(param == "round")
+ m_capStyle = PATH_STROKE_CAP_ROUND;
+ else if(param == "square")
+ m_capStyle = PATH_STROKE_CAP_SQUARE;
+ break;
+ case StrokeLineJoin:
+ m_flags |= SVG_STYLE_FLAG_STROKE_LINE_JOIN;
+ if(param == "miter")
+ m_joinStyle = PATH_STROKE_JOIN_MITER;
+ else if(param == "round")
+ m_joinStyle = PATH_STROKE_JOIN_ROUND;
+ else if(param == "bevel")
+ m_joinStyle = PATH_STROKE_JOIN_BEVEL;
+ break;
+ case Stroke:
+ if(m_flags & SVG_STYLE_FLAG_STROKE)
+ redraw = true;
+ if(inherit)
+ m_flags &= ~SVG_STYLE_FLAG_STROKE;
+ else
+ {
+ m_flags |= SVG_STYLE_FLAG_STROKE;
+
+ if(!m_strokeColor)
+ {
+ m_strokeColor = new SVGPaintImpl(m_object);
+ m_strokeColor->ref();
+ }
+
+ setPaint(param, m_strokeColor);
+ }
+ break;
+ case Fill:
+ if(m_flags & SVG_STYLE_FLAG_FILL)
+ {
+ redraw = true;
+ update = UPDATE_STYLE;
+ }
+ if(inherit)
+ m_flags &= ~SVG_STYLE_FLAG_FILL;
+ else
+ {
+ m_flags |= SVG_STYLE_FLAG_FILL;
+
+ if(!m_fillColor)
+ {
+ m_fillColor = new SVGPaintImpl(m_object);
+ m_fillColor->ref();
+ }
+
+ setPaint(param, m_fillColor);
+ }
+ break;
+ case Color:
+ if(m_flags & SVG_STYLE_FLAG_COLOR)
+ redraw = true;
+ if(inherit)
+ m_flags &= ~SVG_STYLE_FLAG_COLOR;
+ else
+ {
+ m_flags |= SVG_STYLE_FLAG_COLOR;
+
+ if(!m_color)
+ {
+ m_color = new SVGColorImpl(m_object);
+ m_color->ref();
+ }
+ setColor(param, m_color);
+ }
+ break;
+ case StopColor:
+ m_flags |= SVG_STYLE_FLAG_STOP;
+
+ if(!m_stopColor)
+ {
+ m_stopColor = new SVGColorImpl(m_object);
+ m_stopColor->ref();
+ }
+
+ if(!inherit)
+ setColor(param, m_stopColor);
+ break;
+ case ColorInterpolation:
+ if(inherit)
+ m_flags &= ~SVG_STYLE_FLAG_COLOR_INTERPOLATION;
+ else
+ {
+ m_flags |= SVG_STYLE_FLAG_COLOR_INTERPOLATION;
+ if(param == "auto" || param == "sRGB")
+ m_colorInterpolation = CI_SRGB;
+ else
+ if(param == "linearRGB")
+ m_colorInterpolation = CI_LINEARRGB;
+ }
+ break;
+ case FontSize:
+ {
+ m_flags |= SVG_STYLE_FLAG_FONT_SIZE;
+ if(!inherit)
+ {
+ double temp = fontSizeForText(param);
+ if(temp != -1) // Is "absolute-size"
+ {
+ m_fontSize = temp;
+ break;
+ }
+
+ SVGLengthImpl *length = SVGSVGElementImpl::createSVGLength();
+ length->setContext(m_object);
+ length->setValueAsString(DOM::DOMString(param));
+ m_fontSize = length->value();
+ length->deref();
+ }
+ break;
+ }
+ case FontFamily:
+ m_flags |= SVG_STYLE_FLAG_FONT_FAMILY;
+
+ // Hacks
+ // #1 Replace "'" characters by ""
+ param = param.replace('\'', QString::null);
+ // #2 Replace "MS-Gothic" by "MS Gothic"
+ param = param.replace("MS-Gothic", "MS Gothic");
+ // #3 Replace "Helvetica" by "Arial"
+ param = param.replace("Helvetica", "Arial");
+ param = param.replace("helvetica", "Arial");
+
+ if(!m_fontFamily)
+ {
+ m_fontFamily = new SVGStringListImpl();
+ m_fontFamily->ref();
+ }
+
+ if(!inherit)
+ SVGHelperImpl::parseCommaSeperatedList(m_fontFamily, param);
+ break;
+ case FontWeight:
+ m_flags |= SVG_STYLE_FLAG_FONT_WEIGHT;
+ if(!inherit)
+ m_fontWeight = param;
+ break;
+ case FontStyle:
+ m_flags |= SVG_STYLE_FLAG_FONT_STYLE;
+ if(param == "normal")
+ m_fontStyle = FSNORMAL;
+ else if(param == "italic")
+ m_fontStyle = ITALIC;
+ else if(param == "oblique")
+ m_fontStyle = OBLIQUE;
+ break;
+ case TextDecoration:
+ m_flags |= SVG_STYLE_FLAG_TEXT_DECORATION;
+ if(param == "none")
+ m_textDecoration = TDNONE;
+ {
+ // CSS2 allows multiple decorations
+ m_textDecoration = TDNONE;
+ QStringList decorations = QStringList::split(' ', param);
+ for(QStringList::Iterator it = decorations.begin(); it != decorations.end(); ++it)
+ {
+ if(*it == "underline")
+ m_textDecoration |= UNDERLINE;
+ else if(*it == "overline")
+ m_textDecoration |= OVERLINE;
+ else if(*it == "line-through")
+ m_textDecoration |= LINE_THROUGH;
+ }
+ }
+ break;
+ case TextAnchor:
+ m_flags |= SVG_STYLE_FLAG_TEXT_ANCHOR;
+ if(param == "start")
+ m_textAnchor = TASTART;
+ else if(param == "middle")
+ m_textAnchor = TAMIDDLE;
+ else if(param == "end")
+ m_textAnchor = TAEND;
+ break;
+ case Direction:
+ m_flags |= SVG_STYLE_FLAG_TEXT_DIRECTION;
+ // Spec: direction is only processed when unicode-bidi
+ // is set to bidi-override or embedded
+ if(m_textUnicodeBidi == OVERRIDE ||
+ m_textUnicodeBidi == EMBED ||
+ m_textUnicodeBidi == UBNORMAL)
+ {
+ if(param == "rtl")
+ m_textDirection = RTL;
+ else if(param == "ltr")
+ m_textDirection = LTR;
+ }
+ break;
+ case WritingMode:
+ m_flags |= SVG_STYLE_FLAG_TEXT_WRITING_MODE;
+ if(param == "lr-tb" || param == "lr")
+ m_textWritingMode = LR;
+ else if(param == "rl-tb" || param == "rl")
+ m_textWritingMode = RL;
+ else if(param == "tb-lr" || param == "tb")
+ m_textWritingMode = TB;
+ break;
+ case UnicodeBidi:
+ m_flags |= SVG_STYLE_FLAG_TEXT_UNICODE_BIDI;
+ if(param == "normal")
+ m_textUnicodeBidi = UBNORMAL;
+ else if(param == "embed")
+ m_textUnicodeBidi = EMBED;
+ else if(param == "bidi-override")
+ m_textUnicodeBidi = OVERRIDE;
+ break;
+ case GlyphOrientationVertical:
+ m_flags |= SVG_STYLE_FLAG_GLYPH_ORIENTATION_VERTICAL;
+ m_glyphOrientationVertical = param;
+ break;
+ case GlyphOrientationHorizontal:
+ m_flags |= SVG_STYLE_FLAG_GLYPH_ORIENTATION_HORIZONTAL;
+ m_glyphOrientationHorizontal = param;
+ break;
+ case Opacity:
+ m_flags |= SVG_STYLE_FLAG_OPACITY;
+
+ if(!inherit)
+ {
+ SVGLengthImpl::convertPercentageToFloat(value.toString(exec).qstring(), m_opacity);
+ }
+ break;
+ case FillOpacity:
+ m_flags |= SVG_STYLE_FLAG_FILL_OPACITY;
+
+ if(!inherit)
+ {
+ SVGLengthImpl::convertPercentageToFloat(value.toString(exec).qstring(), m_fillOpacity);
+ }
+ break;
+ case StrokeOpacity:
+ m_flags |= SVG_STYLE_FLAG_STROKE_OPACITY;
+
+ if(!inherit)
+ {
+ SVGLengthImpl::convertPercentageToFloat(value.toString(exec).qstring(), m_strokeOpacity);
+ }
+ break;
+ case ClipPath:
+ m_flags |= SVG_STYLE_FLAG_CLIP_PATH;
+ if(!inherit)
+ m_clipPath = extractUrlId(param);
+ break;
+ case Mask:
+ m_flags |= SVG_STYLE_FLAG_MASK;
+ if(!inherit)
+ m_mask = extractUrlId(param);
+ break;
+ case MarkerStart:
+ m_flags |= SVG_STYLE_FLAG_MARKER_START;
+ if(!inherit)
+ setStartMarker(param);
+ break;
+ case MarkerMid:
+ m_flags |= SVG_STYLE_FLAG_MARKER_MID;
+ if(!inherit)
+ setMidMarker(param);
+ break;
+ case MarkerEnd:
+ m_flags |= SVG_STYLE_FLAG_MARKER_END;
+ if(!inherit)
+ setEndMarker(param);
+ break;
+ case Marker:
+ m_flags |= (SVG_STYLE_FLAG_MARKER_START | SVG_STYLE_FLAG_MARKER_MID | SVG_STYLE_FLAG_MARKER_END);
+ if(!inherit)
+ setMarkers(param);
+ break;
+ case PointerEvents:
+ m_flags |= SVG_STYLE_FLAG_POINTER_EVENTS;
+ if(param == "none")
+ m_pointerEvents = PE_NONE;
+ else if(param == "stroke")
+ m_pointerEvents = PE_STROKE;
+ else if(param == "fill")
+ m_pointerEvents = PE_FILL;
+ else if(param == "painted")
+ m_pointerEvents = PE_PAINTED;
+ else if(param == "visibleStroke")
+ m_pointerEvents = PE_VISIBLE_STROKE;
+ else if(param == "visibleFill")
+ m_pointerEvents = PE_VISIBLE_FILL;
+ else if(param == "visiblePainted")
+ m_pointerEvents = PE_VISIBLE_PAINTED;
+ else if(param == "visible")
+ m_pointerEvents = PE_VISIBLE;
+ else if(param == "all")
+ m_pointerEvents = PE_ALL;
+ break;
+ case Cursor:
+ m_flags |= SVG_STYLE_FLAG_CURSOR;
+ if(param == "auto")
+ m_cursor = CURSOR_AUTO;
+ else if(param == "crosshair")
+ m_cursor = CURSOR_CROSSHAIR;
+ else if(param == "default")
+ m_cursor = CURSOR_DEFAULT;
+ else if(param == "pointer")
+ m_cursor = CURSOR_POINTER;
+ else if(param == "move")
+ m_cursor = CURSOR_MOVE;
+ else if(param == "e-resize")
+ m_cursor = CURSOR_E_RESIZE;
+ else if(param == "ne-resize")
+ m_cursor = CURSOR_NE_RESIZE;
+ else if(param == "nw-resize")
+ m_cursor = CURSOR_NW_RESIZE;
+ else if(param == "n-resize")
+ m_cursor = CURSOR_N_RESIZE;
+ else if(param == "se-resize")
+ m_cursor = CURSOR_SE_RESIZE;
+ else if(param == "sw-resize")
+ m_cursor = CURSOR_SW_RESIZE;
+ else if(param == "s-resize")
+ m_cursor = CURSOR_S_RESIZE;
+ else if(param == "w-resize")
+ m_cursor = CURSOR_W_RESIZE;
+ else if(param == "text")
+ m_cursor = CURSOR_TEXT;
+ else if(param == "wait")
+ m_cursor = CURSOR_WAIT;
+ else if(param == "help")
+ m_cursor = CURSOR_HELP;
+ break;
+ case Display:
+ m_flags |= SVG_STYLE_FLAG_DISPLAY;
+
+ if(param == "none")
+ m_display = false;
+ else if(!inherit)
+ m_display = true;
+ break;
+ case Overflow:
+ m_flags |= SVG_STYLE_FLAG_OVERFLOW;
+ if(param == "hidden" || param == "scroll")
+ m_overflow = false;
+ else if(!inherit)
+ m_overflow = true;
+ break;
+ case Clip:
+ m_flags |= SVG_STYLE_FLAG_CLIP_PATH;
+ if(!inherit)
+ setClip(param);
+ break;
+ case Visibility:
+ if(m_flags & SVG_STYLE_FLAG_VISIBILITY)
+ redraw = true;
+ if(inherit)
+ m_flags &= ~SVG_STYLE_FLAG_COLOR;
+ else
+ {
+ m_flags |= SVG_STYLE_FLAG_VISIBILITY;
+
+ if(param == "visible")
+ m_visible = true;
+ else if(!inherit)
+ m_visible = false;
+
+ // Just a quick fix for the script-* files (Niko)
+ // Any better solution??
+ update = UPDATE_TRANSFORM;
+ redraw = true;
+ }
+ SVGHelperImpl::applyContainer<SVGStylableImpl>(this, Visibility, param);
+ break;
+ case FillRule:
+ m_flags |= SVG_STYLE_FLAG_FILL_RULE;
+ if(!inherit)
+ m_fillRule = (param == "evenodd" ? RULE_EVENODD : RULE_NONZERO);
+ break;
+ case ClipRule:
+ m_flags |= SVG_STYLE_FLAG_CLIP_RULE;
+ if(!inherit)
+ m_clipRule = (param == "evenodd" ? RULE_EVENODD : RULE_NONZERO);
+ break;
+ case StrokeDashOffset:
+ m_flags |= SVG_STYLE_FLAG_STROKE_DASH_OFFSET;
+
+ if(!m_dashOffset)
+ {
+ m_dashOffset = new SVGAnimatedLengthImpl(LENGTHMODE_OTHER, m_object);
+ m_dashOffset->ref();
+ }
+
+ if(!inherit)
+ m_dashOffset->baseVal()->setValueAsString(param);
+ break;
+ case StrokeDashArray:
+ {
+ m_flags |= SVG_STYLE_FLAG_STROKE_DASH_ARRAY;
+
+ if(!m_dashArray)
+ {
+ m_dashArray = new SVGAnimatedLengthListImpl();
+ m_dashArray->ref();
+ }
+ else
+ m_dashArray->baseVal()->clear();
+
+ if(param != "none" && !inherit)
+ SVGHelperImpl::parseLengthList(m_dashArray, param);
+ break;
+ }
+ case ColorProfile:
+ {
+ m_flags |= SVG_STYLE_FLAG_COLOR_PROFILE;
+ if(!inherit)
+ {
+ if(!m_object)
+ return;
+
+ SVGColorProfileElementImpl *handle = static_cast<SVGColorProfileElementImpl *>(m_object->ownerSVGElement()->getElementById(SVGURIReferenceImpl::getTarget(param)));
+ if(handle)
+ SVGImageElementImpl::applyColorProfile(handle, static_cast<SVGImageElementImpl *>(this));
+ }
+ break;
+ }
+ case BaselineShift:
+ {
+ m_flags |= SVG_STYLE_FLAG_BASELINE_SHIFT;
+ if(!inherit)
+ m_baselineShift = param;
+ break;
+ }
+ case LetterSpacing:
+ m_flags |= SVG_STYLE_FLAG_LETTER_SPACING;
+ case WordSpacing:
+ {
+ if(!inherit)
+ {
+ if(token == WordSpacing)
+ {
+ m_flags |= SVG_STYLE_FLAG_WORD_SPACING;
+ m_wordSpacing = param;
+ }
+ else
+ m_letterSpacing = param;
+ }
+ break;
+ }
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+
+ if(redraw)
+ {
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(m_object);
+ if(inherit)
+ processStyle();
+
+ if(shape && shape->item())
+ {
+ if(update > -1)
+ shape->item()->update(static_cast<CanvasItemUpdate>(update));
+ else if(m_object)
+ m_object->ownerDoc()->canvas()->invalidate(shape->item(), false);
+ }
+ }
+}
+
+Value SVGStylableImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &)
+{
+ KSVG_CHECK_THIS(SVGStylableImpl)
+
+ switch(id)
+ {
+ case SVGStylableImpl::GetStyle:
+ return Undefined();
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return Undefined();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGStylableImpl.h b/ksvg/impl/SVGStylableImpl.h
new file mode 100644
index 00000000..0a399a4c
--- /dev/null
+++ b/ksvg/impl/SVGStylableImpl.h
@@ -0,0 +1,327 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGStylableImpl_H
+#define SVGStylableImpl_H
+
+#include <qstring.h>
+#include <qstringlist.h>
+
+#include <dom/dom_string.h>
+
+#include "ksvg_lookup.h"
+
+class QRect;
+
+// from libart, but now no dependency
+typedef enum
+{
+ PATH_STROKE_JOIN_MITER,
+ PATH_STROKE_JOIN_ROUND,
+ PATH_STROKE_JOIN_BEVEL
+} PathStrokeJoinType;
+
+typedef enum
+{
+ PATH_STROKE_CAP_BUTT,
+ PATH_STROKE_CAP_ROUND,
+ PATH_STROKE_CAP_SQUARE
+} PathStrokeCapType;
+
+#define SVG_STYLE_FLAG_NONE 0x0000000000000ULL
+#define SVG_STYLE_FLAG_BASELINE_SHIFT 0x0000000000001ULL
+#define SVG_STYLE_FLAG_CLIP_PATH 0x0000000000002ULL
+#define SVG_STYLE_FLAG_CLIP_RULE 0x0000000000004ULL
+#define SVG_STYLE_FLAG_COLOR 0x0000000000008ULL
+#define SVG_STYLE_FLAG_COLOR_INTERPOLATION 0x0000000000010ULL
+#define SVG_STYLE_FLAG_COLOR_INTERPOLATION_FILTERS 0x0000000000020ULL
+#define SVG_STYLE_FLAG_COLOR_PROFILE 0x0000000000040ULL
+#define SVG_STYLE_FLAG_COLOR_RENDERING 0x0000000000080ULL
+#define SVG_STYLE_FLAG_CURSOR 0x0000000000100ULL
+#define SVG_STYLE_FLAG_DIRECTION 0x0000000000200ULL
+#define SVG_STYLE_FLAG_DISPLAY 0x0000000000400ULL
+#define SVG_STYLE_FLAG_FILL 0x0000000000800ULL
+#define SVG_STYLE_FLAG_FILL_OPACITY 0x0000000001000ULL
+#define SVG_STYLE_FLAG_FILL_RULE 0x0000000002000ULL
+#define SVG_STYLE_FLAG_FONT_FAMILY 0x0000000004000ULL
+#define SVG_STYLE_FLAG_FONT_SIZE 0x0000000008000ULL
+#define SVG_STYLE_FLAG_FONT_SIZE_ADJUST 0x0000000010000ULL
+#define SVG_STYLE_FLAG_FONT_STRETCH 0x0000000020000ULL
+#define SVG_STYLE_FLAG_FONT_STYLE 0x0000000040000ULL
+#define SVG_STYLE_FLAG_FONT_VARIANT 0x0000000080000ULL
+#define SVG_STYLE_FLAG_FONT_WEIGHT 0x0000000100000ULL
+#define SVG_STYLE_FLAG_GLYPH_ORIENTATION_HORIZONTAL 0x0000000200000ULL
+#define SVG_STYLE_FLAG_GLYPH_ORIENTATION_VERTICAL 0x0000000400000ULL
+#define SVG_STYLE_FLAG_IMAGE_RENDERING 0x0000000800000ULL
+#define SVG_STYLE_FLAG_KERNING 0x0000001000000ULL
+#define SVG_STYLE_FLAG_LETTER_SPACING 0x0000002000000ULL
+#define SVG_STYLE_FLAG_MARKER 0x0000004000000ULL
+#define SVG_STYLE_FLAG_MARKER_END 0x0000008000000ULL
+#define SVG_STYLE_FLAG_MARKER_MID 0x0000010000000ULL
+#define SVG_STYLE_FLAG_MARKER_START 0x0000020000000ULL
+#define SVG_STYLE_FLAG_OPACITY 0x0000040000000ULL
+#define SVG_STYLE_FLAG_POINTER_EVENTS 0x0000080000000ULL
+#define SVG_STYLE_FLAG_SHAPE_RENDERING 0x0000100000000ULL
+#define SVG_STYLE_FLAG_STOP 0x0000200000000ULL
+#define SVG_STYLE_FLAG_STROKE_DASH_ARRAY 0x0000400000000ULL
+#define SVG_STYLE_FLAG_STROKE_DASH_OFFSET 0x0000800000000ULL
+#define SVG_STYLE_FLAG_STROKE_LINE_CAP 0x0001000000000ULL
+#define SVG_STYLE_FLAG_STROKE_LINE_JOIN 0x0002000000000ULL
+#define SVG_STYLE_FLAG_STROKE_MITER_LIMIT 0x0004000000000ULL
+#define SVG_STYLE_FLAG_STROKE_OPACITY 0x0008000000000ULL
+#define SVG_STYLE_FLAG_STROKE 0x0010000000000ULL
+#define SVG_STYLE_FLAG_STROKE_WIDTH 0x0020000000000ULL
+#define SVG_STYLE_FLAG_TEXT_ANCHOR 0x0040000000000ULL
+#define SVG_STYLE_FLAG_TEXT_DECORATION 0x0080000000000ULL
+#define SVG_STYLE_FLAG_TEXT_DIRECTION 0x0100000000000ULL
+#define SVG_STYLE_FLAG_TEXT_RENDERING 0x0200000000000ULL
+#define SVG_STYLE_FLAG_TEXT_UNICODE_BIDI 0x0400000000000ULL
+#define SVG_STYLE_FLAG_TEXT_WRITING_MODE 0x0800000000000ULL
+#define SVG_STYLE_FLAG_VISIBILITY 0x1000000000000ULL
+#define SVG_STYLE_FLAG_WORD_SPACING 0x2000000000000ULL
+#define SVG_STYLE_FLAG_OVERFLOW 0x4000000000000ULL
+#define SVG_STYLE_FLAG_MASK 0x0008000000000000ULL
+
+//?#define SVG_STYLE_FLAG_MASK_INHERIT 0x0010000000000000ULL
+
+// Helper macros
+#define STYLE_GET(Return, Name, Member) \
+protected:\
+ Return Member;\
+public:\
+Return get ##Name () const { return Member; }
+
+#define STYLE_GET_OPTIM(Return, Name, Member, Optim) \
+protected:\
+ Return Member : Optim;\
+public:\
+Return get ##Name () const { return Member; }
+
+#define STYLE_HAS(Name, Member) \
+bool has##Name () { return ! Member .isEmpty(); }
+
+namespace KSVG
+{
+
+enum ECursor
+{
+ CURSOR_AUTO,
+ CURSOR_CROSSHAIR,
+ CURSOR_DEFAULT,
+ CURSOR_POINTER,
+ CURSOR_MOVE,
+ CURSOR_E_RESIZE,
+ CURSOR_NE_RESIZE,
+ CURSOR_N_RESIZE,
+ CURSOR_NW_RESIZE,
+ CURSOR_SE_RESIZE,
+ CURSOR_SW_RESIZE,
+ CURSOR_S_RESIZE,
+ CURSOR_W_RESIZE,
+ CURSOR_TEXT,
+ CURSOR_WAIT,
+ CURSOR_HELP
+};
+
+enum ETextDirection
+{
+ LTR, RTL
+};
+
+enum ETextDecoration
+{
+ TDNONE = 0, UNDERLINE = 1, OVERLINE = 2, LINE_THROUGH = 4
+};
+
+enum ETextAnchor
+{
+ TASTART, TAMIDDLE, TAEND
+};
+
+enum EUnicodeBidi
+{
+ UBNORMAL, EMBED, OVERRIDE, INHERIT
+};
+
+enum EFontStyle
+{
+ FSNORMAL, ITALIC, OBLIQUE
+};
+
+enum ETextWritingMode
+{
+ LR, RL, TB
+};
+
+enum EWindRule
+{
+ RULE_NONZERO,
+ RULE_EVENODD
+};
+
+enum EPointerEvents
+{
+ PE_NONE,
+ PE_STROKE,
+ PE_FILL,
+ PE_PAINTED,
+ PE_VISIBLE,
+ PE_VISIBLE_STROKE,
+ PE_VISIBLE_FILL,
+ PE_VISIBLE_PAINTED,
+ PE_ALL,
+ PE_INHERIT
+};
+
+enum EColorInterpolation
+{
+ CI_SRGB,
+ CI_LINEARRGB
+};
+
+class SVGColorImpl;
+class SVGPaintImpl;
+class SVGLengthImpl;
+class SVGAnimatedLengthImpl;
+class SVGAnimatedLengthListImpl;
+class SVGMatrixImpl;
+class SVGStringListImpl;
+class SVGElementImpl;
+class SVGStylableImpl
+{
+public:
+ SVGStylableImpl(SVGElementImpl *object);
+ virtual ~SVGStylableImpl();
+
+ static void setColor(const QString &, SVGColorImpl *);
+
+ STYLE_GET(SVGAnimatedLengthImpl *, DashOffset, m_dashOffset)
+ STYLE_GET(SVGAnimatedLengthListImpl *, DashArray, m_dashArray)
+ STYLE_GET(SVGPaintImpl *, StrokeColor, m_strokeColor)
+ STYLE_GET(SVGPaintImpl *, FillColor, m_fillColor)
+ STYLE_GET(SVGColorImpl *, StopColor, m_stopColor)
+ STYLE_GET(SVGColorImpl *, Color, m_color)
+ STYLE_GET(SVGAnimatedLengthImpl *, StrokeWidth, m_strokeWidth)
+ STYLE_GET(SVGStringListImpl *, FontFamily, m_fontFamily);
+ STYLE_GET(float, FontSize, m_fontSize)
+ STYLE_GET(QString, LetterSpacing, m_letterSpacing)
+ STYLE_GET(QString, WordSpacing, m_wordSpacing)
+ STYLE_GET(QString, FontWeight, m_fontWeight)
+ STYLE_GET(QString, ClipPath, m_clipPath)
+ STYLE_GET(QString, Mask, m_mask)
+ STYLE_GET(QString, StartMarker, m_startMarker)
+ STYLE_GET(QString, MidMarker, m_midMarker)
+ STYLE_GET(QString, EndMarker, m_endMarker)
+ STYLE_GET(QString, BaselineShift, m_baselineShift)
+ STYLE_GET(QString, GlyphOrientationVertical, m_glyphOrientationVertical)
+ STYLE_GET(QString, GlyphOrientationHorizontal, m_glyphOrientationHorizontal)
+ STYLE_GET(float, Opacity, m_opacity)
+ STYLE_GET(float, FillOpacity, m_fillOpacity)
+ STYLE_GET(float, StrokeOpacity, m_strokeOpacity)
+ STYLE_GET(unsigned int, StrokeMiterlimit, m_strokeMiterlimit)
+
+ STYLE_GET_OPTIM(EPointerEvents, PointerEvents, m_pointerEvents, 4)
+ STYLE_GET_OPTIM(ECursor, Cursor, m_cursor, 4)
+ STYLE_GET_OPTIM(EWindRule, FillRule, m_fillRule, 1)
+ STYLE_GET_OPTIM(EWindRule, ClipRule, m_clipRule, 1)
+ STYLE_GET_OPTIM(PathStrokeCapType, CapStyle, m_capStyle, 2)
+ STYLE_GET_OPTIM(PathStrokeJoinType, JoinStyle, m_joinStyle, 2)
+ STYLE_GET_OPTIM(ETextDirection, TextDirection, m_textDirection, 1)
+ STYLE_GET_OPTIM(unsigned int, TextDecoration, m_textDecoration, 3)
+ STYLE_GET_OPTIM(ETextAnchor, TextAnchor, m_textAnchor, 2)
+ STYLE_GET_OPTIM(EUnicodeBidi, TextUnicodeBidi, m_textUnicodeBidi, 2)
+ STYLE_GET_OPTIM(ETextWritingMode, TextWritingMode, m_textWritingMode, 2)
+ STYLE_GET_OPTIM(EFontStyle, FontStyle, m_fontStyle, 2)
+ STYLE_GET_OPTIM(bool, Overflow, m_overflow, 1)
+ STYLE_GET_OPTIM(bool, Visible, m_visible, 1)
+ STYLE_GET_OPTIM(bool, Display, m_display, 1)
+ STYLE_GET_OPTIM(EColorInterpolation, ColorInterpolation, m_colorInterpolation, 1)
+
+ STYLE_HAS(ClipPath, m_clipPath)
+ STYLE_HAS(Mask, m_mask)
+ STYLE_HAS(StartMarker, m_startMarker)
+ STYLE_HAS(MidMarker, m_midMarker)
+ STYLE_HAS(EndMarker, m_endMarker)
+
+ // Special "set" cases
+ void setStartMarker(const QString &);
+ void setMidMarker(const QString &);
+ void setEndMarker(const QString &);
+ void setMarkers(const QString &);
+
+ // Special "has" cases
+ bool hasMarkers() const;
+
+ // Special "is" cases
+ bool isStroked() const;
+ bool isFilled() const;
+
+ // Function which sets default values
+ void processStyle();
+
+ // Special virtual functions
+ virtual void setClip(const QString &clip);
+ virtual QRect clip();
+
+protected:
+ float fontSizeForText(const QString &);
+
+ SVGElementImpl *m_object;
+
+private:
+ void setPaint(const QString &, SVGPaintImpl *);
+ QString extractUrlId(const QString& string);
+
+ unsigned long long m_flags;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ ClassName, Style,
+ StrokeWidth, StrokeMiterlimit, StrokeLineCap, StrokeLineJoin,
+ Stroke, Fill, Color, StopColor, FontSize, FontFamily, FontWeight,
+ FontStyle, TextDecoration, TextAnchor, Direction, WritingMode,
+ UnicodeBidi, Opacity, FillOpacity, StrokeOpacity, ClipPath,
+ MarkerStart, MarkerMid, MarkerEnd, Marker, Cursor, Display,
+ Overflow, Clip, Visibility, FillRule, ClipRule,
+ StrokeDashOffset, StrokeDashArray, ColorProfile, BaselineShift,
+ LetterSpacing, WordSpacing, PointerEvents,
+ GlyphOrientationVertical, GlyphOrientationHorizontal,
+ ColorInterpolation, Mask,
+ // Functions
+ GetStyle
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+KSVG_DEFINE_PROTOTYPE(SVGStylableImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGStylableImplProtoFunc, SVGStylableImpl)
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGStyleElementImpl.cc b/ksvg/impl/SVGStyleElementImpl.cc
new file mode 100644
index 00000000..d826441b
--- /dev/null
+++ b/ksvg/impl/SVGStyleElementImpl.cc
@@ -0,0 +1,135 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGStyleElementImpl.h"
+
+using namespace KSVG;
+
+#include "SVGStyleElementImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+
+SVGStyleElementImpl::SVGStyleElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl)
+{
+ KSVG_EMPTY_FLAGS
+}
+
+SVGStyleElementImpl::~SVGStyleElementImpl()
+{
+}
+
+void SVGStyleElementImpl::setXmlspace(const DOM::DOMString &xmlspace)
+{
+ setAttribute("xml:space", xmlspace);
+}
+
+DOM::DOMString SVGStyleElementImpl::xmlspace() const
+{
+ return getAttribute("xml:space");
+}
+
+void SVGStyleElementImpl::setType(const DOM::DOMString &type)
+{
+ setAttribute("type", type);
+}
+
+DOM::DOMString SVGStyleElementImpl::type() const
+{
+ return getAttribute("type");
+}
+
+void SVGStyleElementImpl::setMedia(const DOM::DOMString &media)
+{
+ setAttribute("media", media);
+}
+
+DOM::DOMString SVGStyleElementImpl::media() const
+{
+ return getAttribute("media");
+}
+
+void SVGStyleElementImpl::setTitle(const DOM::DOMString &title)
+{
+ setAttribute("title", title);
+}
+
+DOM::DOMString SVGStyleElementImpl::title() const
+{
+ return getAttribute("title");
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGStyleElementImpl::s_hashTable 5
+ xmlspace SVGStyleElementImpl::Xmlspace DontDelete
+ type SVGStyleElementImpl::Type DontDelete
+ media SVGStyleElementImpl::Media DontDelete
+ title SVGStyleElementImpl::Title DontDelete
+@end
+*/
+
+Value SVGStyleElementImpl::getValueProperty(ExecState *, int token) const
+{
+ //KSVG_CHECK_ATTRIBUTE
+
+ switch(token)
+ {
+ case Xmlspace:
+ return String(xmlspace());
+ case Type:
+ return String(type());
+ case Media:
+ return String(media());
+ case Title:
+ return String(title());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGStyleElementImpl::putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int)
+{
+ switch(token)
+ {
+ case Xmlspace:
+ setXmlspace(value.toString(exec).string());
+ break;
+ case Type:
+ setType(value.toString(exec).string());
+ break;
+ case Media:
+ setMedia(value.toString(exec).string());
+ break;
+ case Title:
+ setTitle(value.toString(exec).string());
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ break;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGStyleElementImpl.h b/ksvg/impl/SVGStyleElementImpl.h
new file mode 100644
index 00000000..fcf7b152
--- /dev/null
+++ b/ksvg/impl/SVGStyleElementImpl.h
@@ -0,0 +1,72 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGStyleElementImpl_H
+#define SVGStyleElementImpl_H
+
+#include <dom/dom_string.h>
+
+#include "SVGElementImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGStyleElementImpl : public SVGElementImpl
+{
+public:
+ SVGStyleElementImpl(DOM::ElementImpl *);
+ virtual ~SVGStyleElementImpl();
+
+ void setXmlspace(const DOM::DOMString &xmlspace);
+ DOM::DOMString xmlspace() const;
+
+ void setType(const DOM::DOMString &type);
+ DOM::DOMString type() const;
+
+ void setMedia(const DOM::DOMString &media);
+ DOM::DOMString media() const;
+
+ void setTitle(const DOM::DOMString &title);
+ DOM::DOMString title() const;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+ KSVG_BRIDGE
+
+ enum
+ {
+ // Properties
+ Xmlspace, Type, Media, Title
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+KSVG_REGISTER_ELEMENT(SVGStyleElementImpl, "style")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGSwitchElementImpl.cc b/ksvg/impl/SVGSwitchElementImpl.cc
new file mode 100644
index 00000000..613a1982
--- /dev/null
+++ b/ksvg/impl/SVGSwitchElementImpl.cc
@@ -0,0 +1,58 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGDocumentImpl.h"
+#include "SVGSwitchElementImpl.h"
+#include "KSVGCanvas.h"
+
+using namespace KSVG;
+
+SVGSwitchElementImpl::SVGSwitchElementImpl(DOM::ElementImpl *impl) : SVGContainerImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl()
+{
+}
+
+SVGSwitchElementImpl::~SVGSwitchElementImpl()
+{
+}
+
+void SVGSwitchElementImpl::createItem(KSVGCanvas *c)
+{
+ if(!c)
+ c = ownerDoc()->canvas();
+
+ DOM::Node node = firstChild();
+ for(; !node.isNull(); node = node.nextSibling())
+ {
+ SVGElementImpl *element = ownerDoc()->getElementFromHandle(node.handle());
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(element);
+ SVGTestsImpl *tests = dynamic_cast<SVGTestsImpl *>(element);
+ SVGStylableImpl *style = dynamic_cast<SVGStylableImpl *>(element);
+
+ bool ok = tests ? tests->ok() : true;
+
+ if(element && shape && ok && style->getVisible() && style->getDisplay() && (shape->directRender() || !directRender()))
+ {
+ element->createItem(c);
+ break;
+ }
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGSwitchElementImpl.h b/ksvg/impl/SVGSwitchElementImpl.h
new file mode 100644
index 00000000..2b29d2a4
--- /dev/null
+++ b/ksvg/impl/SVGSwitchElementImpl.h
@@ -0,0 +1,62 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGSwitchElementImpl_H
+#define SVGSwitchElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGTestsImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGContainerImpl.h"
+#include "SVGLangSpaceImpl.h"
+#include "SVGTransformableImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+namespace KSVG
+{
+
+class SVGSwitchElementImpl : public SVGContainerImpl,
+ public SVGTestsImpl,
+ public SVGLangSpaceImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGStylableImpl,
+ public SVGTransformableImpl
+{
+public:
+ SVGSwitchElementImpl(DOM::ElementImpl *);
+ virtual ~SVGSwitchElementImpl();
+
+ virtual void createItem(KSVGCanvas *c = 0);
+ virtual bool isContainer() const { return true; }
+
+public:
+ KSVG_BRIDGE
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+KSVG_REGISTER_ELEMENT(SVGSwitchElementImpl, "switch")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGSymbolElementImpl.cc b/ksvg/impl/SVGSymbolElementImpl.cc
new file mode 100644
index 00000000..da0b5b90
--- /dev/null
+++ b/ksvg/impl/SVGSymbolElementImpl.cc
@@ -0,0 +1,106 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGRectImpl.h"
+#include "SVGMatrixImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGAnimatedRectImpl.h"
+#include "SVGSymbolElementImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGPreserveAspectRatioImpl.h"
+#include "SVGAnimatedPreserveAspectRatioImpl.h"
+#include "KSVGCanvas.h"
+
+using namespace KSVG;
+
+#include "SVGSymbolElementImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+
+SVGSymbolElementImpl::SVGSymbolElementImpl(DOM::ElementImpl *impl) : SVGShapeImpl(impl), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGFitToViewBoxImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_width = new SVGAnimatedLengthImpl(LENGTHMODE_WIDTH, this);
+ m_width->ref();
+
+ m_height = new SVGAnimatedLengthImpl(LENGTHMODE_HEIGHT, this);
+ m_height->ref();
+}
+
+SVGSymbolElementImpl::~SVGSymbolElementImpl()
+{
+ if(m_width)
+ m_width->deref();
+ if(m_height)
+ m_height->deref();
+}
+/*
+@namespace KSVG
+@begin SVGSymbolElementImpl::s_hashTable 3
+ width SVGSymbolElementImpl::Width DontDelete|ReadOnly
+ height SVGSymbolElementImpl::Height DontDelete|ReadOnly
+@end
+*/
+
+Value SVGSymbolElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ KSVG_CHECK_ATTRIBUTE
+
+ switch(token)
+ {
+ case Width:
+ if(!attributeMode)
+ return m_width->cache(exec);
+ else
+ return Number(m_width->baseVal()->value());
+ case Height:
+ if(!attributeMode)
+ return m_height->cache(exec);
+ else
+ return Number(m_height->baseVal()->value());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGSymbolElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case Width:
+ m_width->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ case Height:
+ m_height->baseVal()->setValueAsString(value.toString(exec).qstring());
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGSymbolElementImpl.h b/ksvg/impl/SVGSymbolElementImpl.h
new file mode 100644
index 00000000..19278ea0
--- /dev/null
+++ b/ksvg/impl/SVGSymbolElementImpl.h
@@ -0,0 +1,76 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGSymbolElementImpl_H
+#define SVGSymbolElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGShapeImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGLangSpaceImpl.h"
+#include "SVGFitToViewBoxImpl.h"
+#include "SVGTransformableImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+namespace KSVG
+{
+
+class SVGFitToViewBoxImpl;
+class SVGAnimatedLengthImpl;
+class SVGSymbolElementImpl : public SVGShapeImpl,
+ public SVGLangSpaceImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGStylableImpl,
+ public SVGFitToViewBoxImpl
+{
+public:
+ SVGSymbolElementImpl(DOM::ElementImpl *);
+ virtual ~SVGSymbolElementImpl();
+
+ virtual bool isContainer() const { return true; }
+ virtual bool directRender() { return false; }
+
+private:
+ SVGAnimatedLengthImpl *m_width;
+ SVGAnimatedLengthImpl *m_height;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+ KSVG_BRIDGE
+
+ enum
+ {
+ // Properties
+ Width, Height
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+KSVG_REGISTER_ELEMENT(SVGSymbolElementImpl, "symbol")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGTRefElementImpl.cc b/ksvg/impl/SVGTRefElementImpl.cc
new file mode 100644
index 00000000..c1c7e540
--- /dev/null
+++ b/ksvg/impl/SVGTRefElementImpl.cc
@@ -0,0 +1,76 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGTRefElementImpl.h"
+#include "SVGTextElementImpl.h"
+#include "SVGAnimatedStringImpl.h"
+
+#include "KSVGLoader.h"
+
+using namespace KSVG;
+
+SVGTRefElementImpl::SVGTRefElementImpl(DOM::ElementImpl *impl) : SVGTSpanElementImpl(impl), SVGURIReferenceImpl()
+{
+}
+
+SVGTRefElementImpl::~SVGTRefElementImpl()
+{
+}
+
+void SVGTRefElementImpl::setAttributes()
+{
+ SVGTSpanElementImpl::setAttributes();
+
+ DOM::DOMString _href = href()->baseVal();
+
+ if(!_href.isNull())
+ href()->setBaseVal(DOM::DOMString(SVGURIReferenceImpl::getTarget(_href.string())));
+
+ // get the text of the referenced element
+ QString text;
+
+ QString url = _href.string().stripWhiteSpace(), filename, id;
+ if(!SVGURIReferenceImpl::parseURIReference(url, filename, id))
+ return;
+
+ if(!filename.isEmpty()) // a reference into another svg
+ text = KSVGLoader::getCharacterData(KURL(ownerDoc()->baseUrl().path(), filename), id);
+ else
+ {
+ // a reference to an element in this svg
+ SVGElementImpl *target = ownerSVGElement()->getElementById(id);
+ SVGTextElementImpl *textTarget = dynamic_cast<SVGTextElementImpl *>(target);
+
+ if(textTarget)
+ text = textTarget->text();
+ }
+
+ text = handleText(text);
+
+ if(!text.isEmpty())
+ {
+ DOM::Text impl = static_cast<DOM::Document *>(ownerDoc())->createTextNode(text);
+ appendChild(impl);
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGTRefElementImpl.h b/ksvg/impl/SVGTRefElementImpl.h
new file mode 100644
index 00000000..60d82231
--- /dev/null
+++ b/ksvg/impl/SVGTRefElementImpl.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGTRefElementImpl_H
+#define SVGTRefElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGTSpanElementImpl.h"
+#include "SVGURIReferenceImpl.h"
+
+namespace KSVG
+{
+
+class SVGTRefElementImpl : public SVGTSpanElementImpl,
+ public SVGURIReferenceImpl
+{
+public:
+ SVGTRefElementImpl(DOM::ElementImpl *);
+ virtual ~SVGTRefElementImpl();
+ virtual void setAttributes();
+
+public:
+ KSVG_BRIDGE
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+KSVG_REGISTER_ELEMENT(SVGTRefElementImpl, "tref")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGTSpanElementImpl.cc b/ksvg/impl/SVGTSpanElementImpl.cc
new file mode 100644
index 00000000..7265c66e
--- /dev/null
+++ b/ksvg/impl/SVGTSpanElementImpl.cc
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <Glyph.h>
+
+#include "SVGDocumentImpl.h"
+#include "SVGTextElementImpl.h"
+#include "SVGTSpanElementImpl.h"
+#include "SVGAnimatedLengthListImpl.h"
+
+#include "KSVGCanvas.h"
+#include "KSVGTextChunk.h"
+
+using namespace KSVG;
+using namespace KJS;
+
+SVGTSpanElementImpl::SVGTSpanElementImpl(DOM::ElementImpl *impl) : SVGTextPositioningElementImpl(impl)
+{
+}
+
+SVGTSpanElementImpl::~SVGTSpanElementImpl()
+{
+}
+
+long SVGTSpanElementImpl::getNumberOfChars()
+{
+ return text().length();
+}
+
+QString SVGTSpanElementImpl::text()
+{
+ // Otherwhise some js scripts which require a child, don't work (Niko)
+ if(!hasChildNodes())
+ {
+ DOM::Text impl = static_cast<DOM::Document *>(ownerDoc())->createTextNode(DOM::DOMString(""));
+ appendChild(impl);
+ }
+
+ return textDirectionAwareText();
+}
+
+void SVGTSpanElementImpl::setAttributes()
+{
+ SVGTextPositioningElementImpl::setAttributes();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGTSpanElementImpl.h b/ksvg/impl/SVGTSpanElementImpl.h
new file mode 100644
index 00000000..26e4903d
--- /dev/null
+++ b/ksvg/impl/SVGTSpanElementImpl.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGTSpanElementImpl_H
+#define SVGTSpanElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGTextPositioningElementImpl.h"
+
+namespace KSVG
+{
+
+class SVGTSpanElementImpl : public SVGTextPositioningElementImpl
+{
+public:
+ SVGTSpanElementImpl(DOM::ElementImpl *);
+ virtual ~SVGTSpanElementImpl();
+
+ QString text();
+
+ virtual long getNumberOfChars();
+
+ virtual void setAttributes();
+
+public:
+ KSVG_BRIDGE
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+KSVG_REGISTER_ELEMENT(SVGTSpanElementImpl, "tspan")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGTestsImpl.cc b/ksvg/impl/SVGTestsImpl.cc
new file mode 100644
index 00000000..8bbccf80
--- /dev/null
+++ b/ksvg/impl/SVGTestsImpl.cc
@@ -0,0 +1,178 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <klocale.h>
+#include <kglobal.h>
+
+#include "SVGTestsImpl.h"
+#include "SVGStringListImpl.h"
+
+using namespace KSVG;
+
+#include "SVGTestsImpl.lut.h"
+
+SVGTestsImpl::SVGTestsImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_requiredFeatures = new SVGStringListImpl();
+ m_requiredFeatures->ref();
+
+ m_requiredExtensions = new SVGStringListImpl();
+ m_requiredExtensions->ref();
+
+ m_systemLanguage = new SVGStringListImpl();
+ m_systemLanguage->ref();
+}
+
+SVGTestsImpl::~SVGTestsImpl()
+{
+ if(m_requiredFeatures)
+ m_requiredFeatures->deref();
+ if(m_requiredExtensions)
+ m_requiredExtensions->deref();
+ if(m_systemLanguage)
+ m_systemLanguage->deref();
+}
+
+void SVGTestsImpl::parseRequiredFeatures(const QString &/*value*/)
+{
+ // FIXME
+}
+
+void SVGTestsImpl::parseRequiredExtensions(const QString &value)
+{
+ m_requiredExtensions->appendItem(new SharedString(value));
+}
+
+void SVGTestsImpl::parseSystemLanguage(const QString &value)
+{
+ m_systemLanguage->appendItem(new SharedString(value));
+}
+
+SVGStringListImpl *SVGTestsImpl::requiredFeatures() const
+{
+ return m_requiredFeatures;
+}
+
+SVGStringListImpl *SVGTestsImpl::requiredExtensions() const
+{
+ return m_requiredExtensions;
+}
+
+SVGStringListImpl *SVGTestsImpl::systemLanguage() const
+{
+ return m_systemLanguage;
+}
+
+bool SVGTestsImpl::ok()
+{
+ for(unsigned int i = 0;i < m_requiredExtensions->numberOfItems();i++)
+ {
+ // FIXME
+ return false;
+ }
+ for(unsigned int i = 0;i < m_systemLanguage->numberOfItems();i++)
+ {
+ QString value = m_systemLanguage->getItem(i)->string();
+ if(value.isEmpty() || value != (KGlobal::locale()->language()).left(2))
+ return false;
+ }
+ return true;
+}
+
+bool SVGTestsImpl::hasExtension(const DOM::DOMString &/*extension*/)
+{
+ return false;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGTestsImpl::s_hashTable 5
+ requiredFeatures SVGTestsImpl::RequiredFeatures DontDelete|ReadOnly
+ requiredExtensions SVGTestsImpl::RequiredExtensions DontDelete|ReadOnly
+ systemLanguage SVGTestsImpl::SystemLanguage DontDelete|ReadOnly
+@end
+@namespace KSVG
+@begin SVGTestsImplProto::s_hashTable 2
+ hasExtension SVGTestsImpl::HasExtension DontDelete|Function 1
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGTests", SVGTestsImplProto, SVGTestsImplProtoFunc)
+
+Value SVGTestsImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case RequiredFeatures:
+ return m_requiredFeatures->cache(exec);
+ case RequiredExtensions:
+ return m_requiredExtensions->cache(exec);
+ case SystemLanguage:
+ return m_systemLanguage->cache(exec);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGTestsImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case RequiredFeatures:
+ parseRequiredFeatures(value.toString(exec).qstring());
+ break;
+ case RequiredExtensions:
+ parseRequiredExtensions(value.toString(exec).qstring());
+ break;
+ case SystemLanguage:
+ parseSystemLanguage(value.toString(exec).qstring());
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+Value SVGTestsImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGTestsImpl)
+
+ switch(id)
+ {
+ case SVGTestsImpl::HasExtension:
+ return Boolean(obj->hasExtension(args[0].toString(exec).string()));
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return Undefined();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGTestsImpl.h b/ksvg/impl/SVGTestsImpl.h
new file mode 100644
index 00000000..c5b05a5f
--- /dev/null
+++ b/ksvg/impl/SVGTestsImpl.h
@@ -0,0 +1,77 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGTestsImpl_H
+#define SVGTestsImpl_H
+
+#include <dom/dom_string.h>
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGStringListImpl;
+class SVGTestsImpl
+{
+public:
+ SVGTestsImpl();
+ ~SVGTestsImpl();
+
+ void parseRequiredFeatures(const QString &value);
+ void parseRequiredExtensions(const QString &value);
+ void parseSystemLanguage(const QString &value);
+
+ SVGStringListImpl *requiredFeatures() const;
+ SVGStringListImpl *requiredExtensions() const;
+ SVGStringListImpl *systemLanguage() const;
+
+ bool ok();
+ bool hasExtension(const DOM::DOMString &extension);
+
+private:
+ SVGStringListImpl *m_requiredFeatures;
+ SVGStringListImpl *m_requiredExtensions;
+ SVGStringListImpl *m_systemLanguage;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ RequiredFeatures, RequiredExtensions, SystemLanguage,
+ // Functions
+ HasExtension
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+KSVG_DEFINE_PROTOTYPE(SVGTestsImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGTestsImplProtoFunc, SVGTestsImpl)
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGTextContentElementImpl.cc b/ksvg/impl/SVGTextContentElementImpl.cc
new file mode 100644
index 00000000..f51d8807
--- /dev/null
+++ b/ksvg/impl/SVGTextContentElementImpl.cc
@@ -0,0 +1,285 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "Glyph.h"
+
+#include "SVGStringListImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGTextContentElementImpl.h"
+#include "SVGTextElementImpl.h"
+#include "SVGAnimatedEnumerationImpl.h"
+#include "SVGDocumentImpl.h"
+
+using namespace KSVG;
+
+#include "SVGTextContentElementImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_cacheimpl.h"
+
+SVGTextContentElementImpl::SVGTextContentElementImpl(DOM::ElementImpl *impl) : SVGShapeImpl(impl), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this)
+{
+ KSVG_EMPTY_FLAGS
+
+ m_lengthAdjust = new SVGAnimatedEnumerationImpl();
+ m_lengthAdjust->ref();
+
+ // Spec: default value 'spacing'
+ m_lengthAdjust->setBaseVal(LENGTHADJUST_SPACING);
+
+ m_textLength = new SVGAnimatedLengthImpl();
+ m_textLength->baseVal()->setValueAsString("-1");
+ m_textLength->ref();
+}
+
+SVGTextContentElementImpl::~SVGTextContentElementImpl()
+{
+ if(m_lengthAdjust)
+ m_lengthAdjust->deref();
+ if(m_textLength)
+ m_textLength->deref();
+}
+
+QString SVGTextContentElementImpl::textDirectionAwareText()
+{
+ QString text;
+
+ if(hasChildNodes())
+ {
+ bool ltr = getTextDirection() == LTR;
+ DOM::Node node = ltr ? firstChild() : lastChild();
+
+ for(; !node.isNull(); node = ltr ? node.nextSibling() : node.previousSibling())
+ {
+ if(node.nodeType() == TEXT_NODE)
+ {
+ DOM::Text textNode = node;
+ QString temp = textNode.data().string();
+
+ if(!ltr)
+ {
+ QString convert = temp;
+
+ for(int i = temp.length(); i > 0; i--)
+ convert[temp.length() - i] = temp[i - 1];
+
+ text += convert;
+ }
+ else
+ text += temp;
+ }
+ else
+ return text;
+ }
+ }
+
+ return text;
+}
+
+T2P::GlyphLayoutParams *SVGTextContentElementImpl::layoutParams() const
+{
+ SVGStylableImpl *style = const_cast<SVGTextContentElementImpl *>(this);
+
+ T2P::GlyphLayoutParams *params = new T2P::GlyphLayoutParams();
+ params->setTb(style->getTextWritingMode() == TB);
+ params->setUseBidi(style->getTextUnicodeBidi() == UBNORMAL);
+ if(!dynamic_cast<SVGTextElementImpl *>(m_object)) // not allowed for <text>
+ params->setBaselineShift(style->getBaselineShift().latin1());
+
+ bool worked = true;
+ int deg = style->getGlyphOrientationVertical().toInt(&worked);
+ if(!worked)
+ params->setGlyphOrientationVertical(-90);
+ else
+ params->setGlyphOrientationVertical(deg);
+
+ worked = true;
+ deg = style->getGlyphOrientationHorizontal().toInt(&worked);
+ if(!worked)
+ params->setGlyphOrientationHorizontal(-90);
+ else
+ params->setGlyphOrientationHorizontal(deg);
+
+ SVGLengthImpl *length = new SVGLengthImpl(LENGTHMODE_OTHER, const_cast<SVGTextContentElementImpl *>(this));
+ length->ref();
+
+ if(style->getLetterSpacing() != "normal" && style->getLetterSpacing() != "inherit")
+ length->setValueAsString(DOM::DOMString(style->getLetterSpacing()));
+ params->setLetterSpacing(length->value());
+
+ if(style->getWordSpacing() != "normal" && style->getWordSpacing() != "inherit")
+ length->setValueAsString(DOM::DOMString(style->getWordSpacing()));
+ params->setWordSpacing(length->value());
+
+ length->deref();
+
+ return params;
+}
+
+SVGAnimatedLengthImpl *SVGTextContentElementImpl::textLength() const
+{
+ return m_textLength;
+}
+
+SVGAnimatedEnumerationImpl *SVGTextContentElementImpl::lengthAdjust() const
+{
+ return m_lengthAdjust;
+}
+
+long SVGTextContentElementImpl::getNumberOfChars()
+{
+ return 0;
+}
+
+float SVGTextContentElementImpl::getComputedTextLength()
+{
+ return 0.0;
+}
+
+/*
+float SVGTextContentElementImpl::getSubStringLength(const unsigned long &charnum,const unsigned long &nchars)
+{
+}
+
+SVGPoint SVGTextContentElementImpl::getStartPositionOfChar(const unsigned long &charnum)
+{
+}
+
+SVGPoint SVGTextContentElementImpl::getEndPositionOfChar(const unsigned long &charnum)
+{
+}
+
+SVGRect SVGTextContentElementImpl::getExtentOfChar(const unsigned long &charnum)
+{
+}
+
+float SVGTextContentElementImpl::getRotationOfChar(const unsigned long &charnum)
+{
+}
+
+long SVGTextContentElementImpl::getCharNumAtPosition(const SVGPoint &point)
+{
+}
+
+void SVGTextContentElementImpl::selectSubString(const unsigned long &charnum,const unsigned long &nchars)
+{
+}
+*/
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGTextContentElementImpl::s_hashTable 3
+ textLength SVGTextContentElementImpl::TextLength DontDelete|ReadOnly
+ lengthAdjust SVGTextContentElementImpl::LengthAdjust DontDelete|ReadOnly
+@end
+@namespace KSVG
+@begin SVGTextContentElementImplProto::s_hashTable 11
+ getNumberOfChars SVGTextContentElementImpl::GetNumberOfChars DontDelete|Function 0
+ getComputedTextLength SVGTextContentElementImpl::GetComputedTextLength DontDelete|Function 0
+ getSubStringLength SVGTextContentElementImpl::GetSubStringLength DontDelete|Function 2
+ getStartPositionOfChar SVGTextContentElementImpl::GetStartPositionOfChar DontDelete|Function 1
+ getEndPositionOfChar SVGTextContentElementImpl::GetEndPositionOfChar DontDelete|Function 1
+ getExtentOfChar SVGTextContentElementImpl::GetExtentOfChar DontDelete|Function 1
+ getRotationOfChar SVGTextContentElementImpl::GetRotationOfChar DontDelete|Function 1
+ getCharNumAtPosition SVGTextContentElementImpl::GetCharNumAtPosition DontDelete|Function 1
+ selectSubString SVGTextContentElementImpl::SelectSubString DontDelete|Function 2
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGTextContentElement", SVGTextContentElementImplProto, SVGTextContentElementImplProtoFunc)
+
+Value SVGTextContentElementImpl::getValueProperty(ExecState *, int token) const
+{
+ //KSVG_CHECK_ATTRIBUTE
+
+ switch(token)
+ {
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGTextContentElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case TextLength:
+ m_textLength->baseVal()->setValueAsString(value.toString(exec).string());
+ if(m_textLength->baseVal()->value() < 0) // A negative value is an error
+ gotError(i18n("Negative value for attribute textLength of element <text> is illegal"));
+ break;
+ case LengthAdjust:
+ {
+ QString temp = value.toString(exec).qstring();
+ if(temp == "spacingAndGlyphs")
+ m_lengthAdjust->setBaseVal(LENGTHADJUST_SPACINGANDGLYPHS);
+ else if(temp == "spacing")
+ m_lengthAdjust->setBaseVal(LENGTHADJUST_SPACING);
+ break;
+ }
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+Value SVGTextContentElementImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &)
+{
+ KSVG_CHECK_THIS(SVGTextContentElementImpl)
+
+ switch(id)
+ {
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return Undefined();
+}
+
+/*
+@namespace KSVG
+@begin SVGTextContentElementImplConstructor::s_hashTable 5
+ LENGTHADJUST_UNKNOWN KSVG::LENGTHADJUST_UNKNOWN DontDelete|ReadOnly
+ LENGTHADJUST_SPACING KSVG::LENGTHADJUST_SPACING DontDelete|ReadOnly
+ LENGTHADJUST_SPACINGANDGLYPHS KSVG::LENGTHADJUST_SPACINGANDGLYPHS DontDelete|ReadOnly
+@end
+*/
+
+Value SVGTextContentElementImplConstructor::getValueProperty(ExecState *, int token) const
+{
+ return Number(token);
+}
+
+Value KSVG::getSVGTextContentElementImplConstructor(ExecState *exec)
+{
+ return cacheGlobalBridge<SVGTextContentElementImplConstructor>(exec, "[[svgtextcontentelement.constructor]]");
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGTextContentElementImpl.h b/ksvg/impl/SVGTextContentElementImpl.h
new file mode 100644
index 00000000..26bbc041
--- /dev/null
+++ b/ksvg/impl/SVGTextContentElementImpl.h
@@ -0,0 +1,115 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGTextContentElementImpl_H
+#define SVGTextContentElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGShapeImpl.h"
+#include "SVGTestsImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGLangSpaceImpl.h"
+#include "SVGTextContentElement.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+namespace T2P
+{
+ class GlyphLayoutParams;
+}
+
+namespace KSVG
+{
+
+class SVGAnimatedLengthImpl;
+class SVGAnimatedEnumerationImpl;
+class SVGTextContentElementImpl : public SVGShapeImpl,
+ public SVGTestsImpl,
+ public SVGLangSpaceImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGStylableImpl
+{
+public:
+ SVGTextContentElementImpl(DOM::ElementImpl *impl);
+ virtual ~SVGTextContentElementImpl();
+
+ QString textDirectionAwareText();
+
+ virtual T2P::GlyphLayoutParams *layoutParams() const;
+
+ SVGAnimatedLengthImpl *textLength() const;
+ SVGAnimatedEnumerationImpl *lengthAdjust() const;
+
+ virtual long getNumberOfChars();
+ float getComputedTextLength();
+
+// float getSubStringLength(const unsigned long &charnum, const unsigned long &nchars);
+// SVGPoint getStartPositionOfChar(const unsigned long &charnum);
+// SVGPoint getEndPositionOfChar(const unsigned long &charnum);
+// SVGRect getExtentOfChar(const unsigned long &charnum);
+// float getRotationOfChar(const unsigned long &charnum);
+// long getCharNumAtPosition(const SVGPoint &point);
+// void selectSubString(const unsigned long &charnum, const unsigned long &nchars);
+
+private:
+ SVGAnimatedEnumerationImpl *m_lengthAdjust;
+ SVGAnimatedLengthImpl *m_textLength;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ TextLength, LengthAdjust,
+ // Functions
+ GetTextLength, GetLengthAdjust,
+ GetNumberOfChars, GetComputedTextLength,
+ GetSubStringLength, GetStartPositionOfChar,
+ GetEndPositionOfChar, GetExtentOfChar,
+ GetRotationOfChar, GetCharNumAtPosition,
+ SelectSubString
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+class SVGTextContentElementImplConstructor : public KJS::ObjectImp
+{
+public:
+ SVGTextContentElementImplConstructor(KJS::ExecState *) { }
+ KJS::Value getValueProperty(KJS::ExecState *, int token) const;
+
+ // no put - all read-only
+ KSVG_GET
+};
+
+KJS::Value getSVGTextContentElementImplConstructor(KJS::ExecState *exec);
+
+}
+
+KSVG_DEFINE_PROTOTYPE(SVGTextContentElementImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGTextContentElementImplProtoFunc, SVGTextContentElementImpl)
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGTextElementImpl.cc b/ksvg/impl/SVGTextElementImpl.cc
new file mode 100644
index 00000000..634c227d
--- /dev/null
+++ b/ksvg/impl/SVGTextElementImpl.cc
@@ -0,0 +1,124 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <Glyph.h>
+
+#include "SVGRectImpl.h"
+#include "SVGEventImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGTextElementImpl.h"
+
+#include "CanvasItem.h"
+#include "KSVGCanvas.h"
+
+using namespace KSVG;
+
+SVGTextElementImpl::SVGTextElementImpl(DOM::ElementImpl *impl) : SVGTextPositioningElementImpl(impl), SVGTransformableImpl()
+{
+ m_bboxX = 0;
+ m_bboxY = 0;
+
+ m_bboxWidth = 0;
+ m_bboxHeight = 0;
+}
+
+SVGTextElementImpl::~SVGTextElementImpl()
+{
+}
+
+long SVGTextElementImpl::getNumberOfChars()
+{
+ return text().length();
+}
+
+QString SVGTextElementImpl::text()
+{
+ // Otherwhise some js scripts which require a child, don't work (Niko)
+ if(!hasChildNodes())
+ {
+ DOM::Text impl = static_cast<DOM::Document *>(ownerDoc())->createTextNode(DOM::DOMString(""));
+ appendChild(impl);
+ }
+
+ return textDirectionAwareText();
+}
+
+SVGRectImpl *SVGTextElementImpl::getBBox()
+{
+ SVGRectImpl *ret = SVGSVGElementImpl::createSVGRect();
+ ret->setX(m_bboxX);
+ ret->setY(m_bboxY);
+ ret->setWidth(m_bboxWidth);
+ ret->setHeight(m_bboxHeight);
+ return ret;
+}
+
+void SVGTextElementImpl::createItem(KSVGCanvas *c )
+{
+ if(!c)
+ c = ownerDoc()->canvas();
+
+ if(!m_item)
+ {
+ m_item = c->createText(this);
+ // Set up bbox before insert(), as that may render the item
+ QRect rect = m_item->bbox();
+ m_bboxX = rect.x();
+ m_bboxY = rect.y();
+ m_bboxWidth = rect.width();
+ m_bboxHeight = rect.height();
+ c->insert(m_item);
+ }
+}
+
+bool SVGTextElementImpl::prepareMouseEvent(const QPoint &p, const QPoint &, SVGMouseEventImpl *mev)
+{
+ // TODO : pointer-events should be stored here, not in SVGStylableImpl.
+ SVGStylableImpl *style = dynamic_cast<SVGStylableImpl *>(this);
+ if(!style || style->getPointerEvents() == PE_NONE)
+ return false;
+ bool test = false;
+ switch(style->getPointerEvents())
+ {
+ case PE_VISIBLE: test = style->getVisible(); break;
+ case PE_VISIBLE_PAINTED: test = style->getVisible() && (style->isStroked() || style->isFilled()) ; break;
+ case PE_VISIBLE_FILL: test = style->getVisible() && style->isFilled(); break;
+ case PE_VISIBLE_STROKE: test = style->getVisible() && style->isStroked(); break;
+ case PE_PAINTED: test = style->isStroked() || style->isFilled(); break;
+ case PE_FILL: test = style->isFilled(); break;
+ case PE_STROKE: test = style->isStroked(); break;
+ case PE_ALL:
+ default: test = true;
+ };
+
+ if(test)
+ {
+ if(m_item->bbox().contains(p))
+ {
+ mev->setTarget(dynamic_cast<SVGElementImpl *>(this));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGTextElementImpl.h b/ksvg/impl/SVGTextElementImpl.h
new file mode 100644
index 00000000..e0c2ca8d
--- /dev/null
+++ b/ksvg/impl/SVGTextElementImpl.h
@@ -0,0 +1,65 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGTextElementImpl_H
+#define SVGTextElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGTransformableImpl.h"
+#include "SVGTextPositioningElementImpl.h"
+
+namespace KSVG
+{
+
+class SVGRectImpl;
+class SVGTextElementImpl : public SVGTextPositioningElementImpl,
+ public SVGTransformableImpl
+{
+public:
+ SVGTextElementImpl(DOM::ElementImpl *);
+ virtual ~SVGTextElementImpl();
+
+ QString text();
+
+ virtual long getNumberOfChars();
+
+ virtual void createItem(KSVGCanvas *c = 0);
+
+ virtual SVGRectImpl *getBBox();
+
+ virtual bool prepareMouseEvent(const QPoint &p, const QPoint &a, SVGMouseEventImpl *mev);
+
+private:
+ int m_bboxX, m_bboxY, m_bboxWidth, m_bboxHeight;
+
+public:
+ KSVG_BRIDGE
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+KSVG_REGISTER_ELEMENT(SVGTextElementImpl, "text")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGTextPathElementImpl.cc b/ksvg/impl/SVGTextPathElementImpl.cc
new file mode 100644
index 00000000..ec218046
--- /dev/null
+++ b/ksvg/impl/SVGTextPathElementImpl.cc
@@ -0,0 +1,240 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "Glyph.h"
+
+#include "SVGDocumentImpl.h"
+#include "SVGTextPathElement.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGTextPathElementImpl.h"
+#include "SVGAnimatedEnumerationImpl.h"
+
+using namespace KSVG;
+
+#include "SVGTextPathElementImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_ecma.h"
+#include "ksvg_cacheimpl.h"
+
+SVGTextPathElementImpl::SVGTextPathElementImpl(DOM::ElementImpl *impl) : SVGTextContentElementImpl(impl), SVGURIReferenceImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_startOffset = new SVGAnimatedLengthImpl();
+ m_startOffset->ref();
+
+ m_method = new SVGAnimatedEnumerationImpl();
+ m_method->ref();
+
+ m_spacing = new SVGAnimatedEnumerationImpl();
+ m_spacing->ref();
+}
+
+SVGTextPathElementImpl::~SVGTextPathElementImpl()
+{
+ if(m_startOffset)
+ m_startOffset->deref();
+ if(m_method)
+ m_method->deref();
+ if(m_spacing)
+ m_spacing->deref();
+}
+
+SVGAnimatedLengthImpl *SVGTextPathElementImpl::startOffset() const
+{
+ return m_startOffset;
+}
+
+SVGAnimatedEnumerationImpl *SVGTextPathElementImpl::method() const
+{
+ return m_method;
+}
+
+SVGAnimatedEnumerationImpl *SVGTextPathElementImpl::spacing() const
+{
+ return m_spacing;
+}
+
+QString SVGTextPathElementImpl::text()
+{
+ // Otherwhise some js scripts which require a child, don't work (Niko)
+ if(!hasChildNodes())
+ {
+ DOM::Text impl = static_cast<DOM::Document *>(ownerDoc())->createTextNode(DOM::DOMString(""));
+ appendChild(impl);
+ }
+
+ return textDirectionAwareText();
+}
+
+void SVGTextPathElementImpl::setAttributes()
+{
+ SVGElementImpl::setAttributes();
+
+ // Spec: if not specified, effect is as if a value of "0" were specified
+ if(KSVG_TOKEN_NOT_PARSED(StartOffset))
+ KSVG_SET_ALT_ATTRIBUTE(StartOffset, "0")
+
+ // Spec: if not specified, effect is as if a value of "align" were specified
+ if(KSVG_TOKEN_NOT_PARSED(Method))
+ KSVG_SET_ALT_ATTRIBUTE(Method, "align")
+
+ // Spec: if not specified, effect is as if a value of "exact" were specified
+ if(KSVG_TOKEN_NOT_PARSED(Spacing))
+ KSVG_SET_ALT_ATTRIBUTE(Spacing, "exact")
+}
+
+T2P::GlyphLayoutParams *SVGTextPathElementImpl::layoutParams() const
+{
+ T2P::GlyphLayoutParams *params = SVGTextContentElementImpl::layoutParams();
+ params->setTextPathStartOffset(startOffset()->baseVal()->value());
+ return params;
+}
+
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGTextPathElementImpl::s_hashTable 5
+ startOffset SVGTextPathElementImpl::StartOffset DontDelete|ReadOnly
+ method SVGTextPathElementImpl::Method DontDelete|ReadOnly
+ spacing SVGTextPathElementImpl::Spacing DontDelete|ReadOnly
+@end
+*/
+
+Value SVGTextPathElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ KSVG_CHECK_ATTRIBUTE
+
+ switch(token)
+ {
+ case StartOffset:
+ if(!attributeMode)
+ return m_startOffset->cache(exec);
+ else
+ return Number(m_startOffset->baseVal()->value());
+ case Method:
+ if(!attributeMode)
+ return m_method->cache(exec);
+ else
+ return Number(m_method->baseVal());
+ case Spacing:
+ if(!attributeMode)
+ return m_spacing->cache(exec);
+ else
+ return Number(m_spacing->baseVal());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGTextPathElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case StartOffset:
+ {
+ QString param = value.toString(exec).qstring();
+
+ if(param.endsWith("%"))
+ {
+ QString value = param.left(param.length() - 1);
+ bool ok = false;
+ double dValue = value.toDouble(&ok);
+ if(ok)
+ startOffset()->baseVal()->setValue(dValue / 100.0);
+ else
+ kdDebug() << "Couldn't parse startOffset: " << value << endl;
+ }
+ else
+ startOffset()->baseVal()->setValueAsString(value.toString(exec).qstring());
+
+ if(startOffset()->baseVal()->value() < 0) // A negative value is an error
+ gotError(i18n("Negative value for attribute startOffset of element <textPath> is illegal"));
+ break;
+ }
+ case Method:
+ {
+ QString param = value.toString(exec).qstring();
+
+ if(param == "align")
+ method()->setBaseVal(TEXTPATH_METHODTYPE_ALIGN);
+ else if(param == "stretch")
+ method()->setBaseVal(TEXTPATH_METHODTYPE_STRETCH);
+ else
+ method()->setBaseVal(TEXTPATH_METHODTYPE_UNKNOWN);
+
+ break;
+ }
+ case Spacing:
+ {
+ QString param = value.toString(exec).qstring();
+
+ if(param == "auto")
+ spacing()->setBaseVal(TEXTPATH_SPACINGTYPE_AUTO);
+ else if(param == "exact")
+ spacing()->setBaseVal(TEXTPATH_SPACINGTYPE_EXACT);
+ else
+ spacing()->setBaseVal(TEXTPATH_SPACINGTYPE_UNKNOWN);
+
+ break;
+ }
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// CONSTANTS
+
+/*
+@namespace KSVG
+@begin SVGTextPathElementImplConstructor::s_hashTable 7
+ TEXTPATH_METHODTYPE_UNKNOWN KSVG::TEXTPATH_METHODTYPE_UNKNOWN DontDelete|ReadOnly
+ TEXTPATH_METHODTYPE_ALIGN KSVG::TEXTPATH_METHODTYPE_ALIGN DontDelete|ReadOnly
+ TEXTPATH_METHODTYPE_STRETCH KSVG::TEXTPATH_METHODTYPE_STRETCH DontDelete|ReadOnly
+ TEXTPATH_SPACINGTYPE_UNKNOWN KSVG::TEXTPATH_SPACINGTYPE_UNKNOWN DontDelete|ReadOnly
+ TEXTPATH_SPACINGTYPE_AUTO KSVG::TEXTPATH_SPACINGTYPE_AUTO DontDelete|ReadOnly
+ TEXTPATH_SPACINGTYPE_EXACT KSVG::TEXTPATH_SPACINGTYPE_EXACT DontDelete|ReadOnly
+@end
+*/
+
+using namespace KJS;
+
+Value SVGTextPathElementImplConstructor::getValueProperty(ExecState *, int token) const
+{
+ return Number(token);
+}
+
+Value KSVG::getSVGTextPathElementImplConstructor(ExecState *exec)
+{
+ return cacheGlobalBridge<SVGTextPathElementImplConstructor>(exec, "[[svgtextpathelement.constructor]]");
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGTextPathElementImpl.h b/ksvg/impl/SVGTextPathElementImpl.h
new file mode 100644
index 00000000..8231f0cd
--- /dev/null
+++ b/ksvg/impl/SVGTextPathElementImpl.h
@@ -0,0 +1,84 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGTextPathElementImpl_H
+#define SVGTextPathElementImpl_H
+
+#include "SVGURIReferenceImpl.h"
+#include "SVGTextContentElementImpl.h"
+
+namespace KSVG
+{
+
+class SVGTextPathElementImpl : public SVGTextContentElementImpl,
+ public SVGURIReferenceImpl
+{
+public:
+ SVGTextPathElementImpl(DOM::ElementImpl *);
+ virtual ~SVGTextPathElementImpl();
+
+ QString text();
+
+ SVGAnimatedLengthImpl *startOffset() const;
+ SVGAnimatedEnumerationImpl *method() const;
+ SVGAnimatedEnumerationImpl *spacing() const;
+
+ virtual void setAttributes();
+ virtual T2P::GlyphLayoutParams *layoutParams() const;
+
+private:
+ SVGAnimatedLengthImpl *m_startOffset;
+ SVGAnimatedEnumerationImpl *m_method;
+ SVGAnimatedEnumerationImpl *m_spacing;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+ KSVG_BRIDGE
+
+ enum
+ {
+ // Properties
+ StartOffset, Method, Spacing
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+class SVGTextPathElementImplConstructor : public KJS::ObjectImp
+{
+public:
+ SVGTextPathElementImplConstructor(KJS::ExecState *) { }
+ KJS::Value getValueProperty(KJS::ExecState *, int token) const;
+
+ // no put - all read-only
+ KSVG_GET
+};
+
+KJS::Value getSVGTextPathElementImplConstructor(KJS::ExecState *exec);
+
+KSVG_REGISTER_ELEMENT(SVGTextPathElementImpl, "textPath")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGTextPositioningElementImpl.cc b/ksvg/impl/SVGTextPositioningElementImpl.cc
new file mode 100644
index 00000000..924fd091
--- /dev/null
+++ b/ksvg/impl/SVGTextPositioningElementImpl.cc
@@ -0,0 +1,198 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGHelperImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGAnimatedLengthListImpl.h"
+#include "SVGAnimatedNumberListImpl.h"
+#include "SVGTextPositioningElementImpl.h"
+
+using namespace KSVG;
+
+#include "SVGTextPositioningElementImpl.lut.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+
+SVGTextPositioningElementImpl::SVGTextPositioningElementImpl(DOM::ElementImpl *impl) : SVGTextContentElementImpl(impl)
+{
+ KSVG_EMPTY_FLAGS
+
+ m_x = new SVGAnimatedLengthListImpl();
+ m_x->ref();
+
+ m_y = new SVGAnimatedLengthListImpl();
+ m_y->ref();
+
+ m_dx = new SVGAnimatedLengthListImpl();
+ m_dx->ref();
+
+ m_dy = new SVGAnimatedLengthListImpl();
+ m_dy->ref();
+
+ m_rotate = new SVGAnimatedNumberListImpl();
+ m_rotate->ref();
+}
+
+SVGTextPositioningElementImpl::~SVGTextPositioningElementImpl()
+{
+ if(m_x)
+ m_x->deref();
+ if(m_y)
+ m_y->deref();
+ if(m_dx)
+ m_dx->deref();
+ if(m_dy)
+ m_dy->deref();
+ if(m_rotate)
+ m_rotate->deref();
+}
+
+SVGAnimatedLengthListImpl *SVGTextPositioningElementImpl::x()
+{
+ return m_x;
+}
+
+SVGAnimatedLengthListImpl *SVGTextPositioningElementImpl::y()
+{
+ return m_y;
+}
+
+SVGAnimatedLengthListImpl *SVGTextPositioningElementImpl::dx()
+{
+ return m_dx;
+}
+
+SVGAnimatedLengthListImpl *SVGTextPositioningElementImpl::dy()
+{
+ return m_dy;
+}
+
+SVGAnimatedNumberListImpl *SVGTextPositioningElementImpl::rotate()
+{
+ return m_rotate;
+}
+
+/*
+@namespace KSVG
+@begin SVGTextPositioningElementImpl::s_hashTable 7
+ x SVGTextPositioningElementImpl::X DontDelete|ReadOnly
+ y SVGTextPositioningElementImpl::Y DontDelete|ReadOnly
+ dx SVGTextPositioningElementImpl::Dx DontDelete|ReadOnly
+ dy SVGTextPositioningElementImpl::Dy DontDelete|ReadOnly
+ rotate SVGTextPositioningElementImpl::Rotate DontDelete|ReadOnly
+@end
+*/
+
+Value SVGTextPositioningElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ KSVG_CHECK_ATTRIBUTE
+
+ switch(token)
+ {
+ case X:
+ if(!attributeMode)
+ return m_x->cache(exec);
+ else
+ return Number(m_x->baseVal()->getItem(0)->value());
+ case Y:
+ if(!attributeMode)
+ return m_y->cache(exec);
+ else
+ return Number(m_y->baseVal()->getItem(0)->value());
+ case Dx:
+ if(!attributeMode)
+ return m_dx->cache(exec);
+ else
+ return Number(m_dx->baseVal()->getItem(0)->value());
+ case Dy:
+ if(!attributeMode)
+ return m_dy->cache(exec);
+ else
+ return Number(m_dy->baseVal()->getItem(0)->value());
+ case Rotate:
+ if(!attributeMode)
+ return m_rotate->cache(exec);
+ else
+ return Number(m_rotate->baseVal()->getItem(0)->value());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGTextPositioningElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case X:
+ x()->baseVal()->clear();
+ SVGHelperImpl::parseLengthList(x(), value.toString(exec).qstring(), LENGTHMODE_WIDTH, this);
+ break;
+ case Y:
+ y()->baseVal()->clear();
+ SVGHelperImpl::parseLengthList(y(), value.toString(exec).qstring(), LENGTHMODE_HEIGHT, this);
+ break;
+ case Dx:
+ dx()->baseVal()->clear();
+ SVGHelperImpl::parseLengthList(dx(), value.toString(exec).qstring(), LENGTHMODE_WIDTH, this);
+ break;
+ case Dy:
+ dy()->baseVal()->clear();
+ SVGHelperImpl::parseLengthList(dy(), value.toString(exec).qstring(), LENGTHMODE_HEIGHT, this);
+ break;
+ case Rotate:
+ {
+ rotate()->baseVal()->clear();
+
+ SVGNumberImpl *number = SVGSVGElementImpl::createSVGNumber();
+ number->setValue(value.toNumber(exec));
+ rotate()->baseVal()->appendItem(number);
+ break;
+ }
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+void SVGTextPositioningElementImpl::setAttributes()
+{
+ SVGElementImpl::setAttributes();
+
+ if(tagName() != "text")
+ return;
+
+ // Spec: If the attribute is not specified, the effect is as if a value of "0" were specified.
+ if(KSVG_TOKEN_NOT_PARSED(X))
+ KSVG_SET_ALT_ATTRIBUTE(X, "0")
+
+ // Spec: If the attribute is not specified, the effect is as if a value of "0" were specified.
+ if(KSVG_TOKEN_NOT_PARSED(Y))
+ KSVG_SET_ALT_ATTRIBUTE(Y, "0")
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGTextPositioningElementImpl.h b/ksvg/impl/SVGTextPositioningElementImpl.h
new file mode 100644
index 00000000..c80b48ff
--- /dev/null
+++ b/ksvg/impl/SVGTextPositioningElementImpl.h
@@ -0,0 +1,83 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGTextPositioningElementImpl_H
+#define SVGTextPositioningElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGTextContentElementImpl.h"
+
+namespace KJS
+{
+ class Value;
+ class Object;
+ class UString;
+ class ExecState;
+}
+
+namespace KSVG
+{
+
+class SVGShapeImpl;
+class GlyphLayoutParams;
+class SVGAnimatedLengthListImpl;
+class SVGAnimatedNumberListImpl;
+
+class SVGTextPositioningElementImpl : public SVGTextContentElementImpl
+{
+public:
+ SVGTextPositioningElementImpl(DOM::ElementImpl *impl);
+ virtual ~SVGTextPositioningElementImpl();
+
+ SVGAnimatedLengthListImpl *x();
+ SVGAnimatedLengthListImpl *y();
+ SVGAnimatedLengthListImpl *dx();
+ SVGAnimatedLengthListImpl *dy();
+ SVGAnimatedNumberListImpl *rotate();
+
+ virtual void setAttributes();
+
+private:
+ SVGAnimatedLengthListImpl *m_x;
+ SVGAnimatedLengthListImpl *m_y;
+ SVGAnimatedLengthListImpl *m_dx;
+ SVGAnimatedLengthListImpl *m_dy;
+ SVGAnimatedNumberListImpl *m_rotate;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ X, Y, Dx, Dy, Rotate
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGTimeScheduler.cc b/ksvg/impl/SVGTimeScheduler.cc
new file mode 100644
index 00000000..efff77ac
--- /dev/null
+++ b/ksvg/impl/SVGTimeScheduler.cc
@@ -0,0 +1,234 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "KSVGCanvas.h"
+#include "CanvasItem.h"
+#include "SVGShapeImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGTimeScheduler.moc"
+
+using namespace KSVG;
+
+SVGTimer::SVGTimer(QObject *scheduler, unsigned int ms, bool singleShot)
+{
+ m_ms = ms;
+ m_singleShot = singleShot;
+ m_timer = new QTimer(scheduler);
+}
+
+SVGTimer::~SVGTimer()
+{
+ delete m_timer;
+}
+
+bool SVGTimer::operator==(const QTimer *timer)
+{
+ return (m_timer == timer);
+}
+
+const QTimer *SVGTimer::qtimer() const
+{
+ return m_timer;
+}
+
+void SVGTimer::start(QObject *receiver, const char *member)
+{
+ QObject::connect(m_timer, SIGNAL(timeout()), receiver, member);
+ m_timer->start(m_ms, m_singleShot);
+}
+
+void SVGTimer::stop()
+{
+ m_timer->stop();
+}
+
+bool SVGTimer::isActive() const
+{
+ return m_timer->isActive();
+}
+
+unsigned int SVGTimer::ms() const
+{
+ return m_ms;
+}
+
+bool SVGTimer::singleShot() const
+{
+ return m_singleShot;
+}
+
+void SVGTimer::notifyAll()
+{
+ if(m_notifyList.isEmpty())
+ return;
+
+ QValueList<SVGElementImpl *> elements;
+ for(unsigned int i = m_notifyList.count();i > 0; i--)
+ {
+ SVGElementImpl *element = m_notifyList[i - 1];
+ if(!element)
+ continue;
+
+ SVGAnimationElementImpl *animation = dynamic_cast<SVGAnimationElementImpl *>(element);
+ if(animation)
+ {
+ animation->handleTimerEvent();
+
+ SVGElementImpl *target = animation->targetElement();
+ if(!elements.contains(target))
+ elements.append(target);
+ }
+ }
+
+ // Optimized update logic (to avoid 4 updates, on the same element)
+ QValueList<SVGElementImpl *>::iterator it2;
+ for(it2 = elements.begin(); it2 != elements.end(); ++it2)
+ {
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(*it2);
+ if(shape && shape->item())
+ shape->item()->update(UPDATE_TRANSFORM);
+ }
+}
+
+void SVGTimer::addNotify(SVGElementImpl *element)
+{
+ m_notifyList.append(element);
+}
+
+void SVGTimer::removeNotify(SVGElementImpl *element)
+{
+ m_notifyList.remove(element);
+
+ if(m_notifyList.isEmpty())
+ stop();
+}
+
+const unsigned int SVGTimeScheduler::staticTimerInterval = 15; // milliseconds
+
+SVGTimeScheduler::SVGTimeScheduler(SVGDocumentImpl *doc) : QObject(), m_doc(doc)
+{
+ // Create static interval timers but don't start it yet!
+ m_intervalTimer = new SVGTimer(this, staticTimerInterval, false);
+ m_creationTime.start();
+}
+
+SVGTimeScheduler::~SVGTimeScheduler()
+{
+ // Usually singleShot timers cleanup themselves, after usage
+ SVGTimerList::iterator it;
+ for(it = m_timerList.begin(); it != m_timerList.end(); ++it)
+ {
+ SVGTimer *svgTimer = *it;
+ delete svgTimer;
+ }
+ delete m_intervalTimer;
+}
+
+void SVGTimeScheduler::addTimer(SVGElementImpl *element, unsigned int ms)
+{
+ SVGTimer *svgTimer = new SVGTimer(this, ms, true);
+ svgTimer->addNotify(element);
+ m_timerList.append(svgTimer);
+}
+
+void SVGTimeScheduler::connectIntervalTimer(SVGElementImpl *element)
+{
+ m_intervalTimer->addNotify(element);
+}
+
+void SVGTimeScheduler::disconnectIntervalTimer(SVGElementImpl *element)
+{
+ m_intervalTimer->removeNotify(element);
+}
+
+void SVGTimeScheduler::startAnimations()
+{
+ SVGTimerList::iterator it;
+ for(it = m_timerList.begin(); it != m_timerList.end(); ++it)
+ {
+ SVGTimer *svgTimer = *it;
+ if(svgTimer && !svgTimer->isActive())
+ svgTimer->start(this, SLOT(slotTimerNotify()));
+ }
+}
+
+void SVGTimeScheduler::toggleAnimations()
+{
+ if(m_intervalTimer->isActive())
+ m_intervalTimer->stop();
+ else
+ m_intervalTimer->start(this, SLOT(slotTimerNotify()));
+}
+
+bool SVGTimeScheduler::animationsPaused() const
+{
+ return !m_intervalTimer->isActive();
+}
+
+void SVGTimeScheduler::slotTimerNotify()
+{
+ QTimer *senderTimer = const_cast<QTimer *>(static_cast<const QTimer *>(sender()));
+
+ SVGTimer *svgTimer = 0;
+ SVGTimerList::iterator it;
+ for(it = m_timerList.begin(); it != m_timerList.end(); ++it)
+ {
+ SVGTimer *cur = *it;
+ if(*cur == senderTimer)
+ {
+ svgTimer = cur;
+ break;
+ }
+ }
+
+ if(!svgTimer)
+ {
+ svgTimer = (*m_intervalTimer == senderTimer) ? m_intervalTimer : 0;
+
+ if(!svgTimer)
+ return;
+ }
+
+ svgTimer->notifyAll();
+
+ // Animations need direct updates
+ if(m_doc->canvas())
+ m_doc->canvas()->update();
+ emit m_doc->finishedRendering();
+
+ if(svgTimer->singleShot())
+ {
+ m_timerList.remove(svgTimer);
+ delete svgTimer;
+ }
+
+ // The singleShot timers of ie. <animate> with begin="3s" are notified
+ // by the previous call, and now all connections to the interval timer
+ // are created and now we just need to fire that timer (Niko)
+ if(svgTimer != m_intervalTimer && !m_intervalTimer->isActive())
+ m_intervalTimer->start(this, SLOT(slotTimerNotify()));
+}
+
+float SVGTimeScheduler::elapsed() const
+{
+ return float(m_creationTime.elapsed()) / 1000.0;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGTimeScheduler.h b/ksvg/impl/SVGTimeScheduler.h
new file mode 100644
index 00000000..ae4c6d37
--- /dev/null
+++ b/ksvg/impl/SVGTimeScheduler.h
@@ -0,0 +1,104 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGTimeScheduler_H
+#define SVGTimeScheduler_H
+
+#include <qtimer.h>
+#include <qdatetime.h>
+#include <qobject.h>
+#include <qvaluelist.h>
+
+#include "SVGElementImpl.h"
+#include "SVGAnimationElementImpl.h"
+
+namespace KSVG
+{
+
+typedef QValueList<SVGElementImpl *> SVGNotifyList;
+class SVGTimer
+{
+public:
+ SVGTimer(QObject *scheduler, unsigned int ms, bool singleShot);
+ ~SVGTimer();
+
+ bool operator==(const QTimer *timer);
+ const QTimer *qtimer() const;
+
+ void start(QObject *receiver, const char *member);
+ void stop();
+
+ bool isActive() const;
+
+ unsigned int ms() const;
+ bool singleShot() const;
+
+ void notifyAll();
+ void addNotify(SVGElementImpl *element);
+ void removeNotify(SVGElementImpl *element);
+
+private:
+ unsigned int m_ms;
+ bool m_invoked, m_singleShot;
+
+ QTimer *m_timer;
+ SVGNotifyList m_notifyList;
+};
+
+typedef QValueList<SVGTimer *> SVGTimerList;
+class SVGDocumentImpl;
+class SVGTimeScheduler : public QObject
+{
+Q_OBJECT
+public:
+ SVGTimeScheduler(SVGDocumentImpl *doc);
+ ~SVGTimeScheduler();
+
+ // Adds singleShot Timers
+ void addTimer(SVGElementImpl *element, unsigned int ms);
+
+ // (Dis-)Connects to interval timer with ms = 'staticTimerInterval'
+ void connectIntervalTimer(SVGElementImpl *element);
+ void disconnectIntervalTimer(SVGElementImpl *element);
+
+ void startAnimations();
+ void toggleAnimations();
+ bool animationsPaused() const;
+
+ // time elapsed in seconds after creation of this object
+ float elapsed() const;
+
+ static const unsigned int staticTimerInterval;
+
+private slots:
+ void slotTimerNotify();
+
+private:
+ SVGDocumentImpl *m_doc;
+ SVGTimerList m_timerList;
+ SVGTimer *m_intervalTimer;
+ QTime m_creationTime;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGTitleElementImpl.cc b/ksvg/impl/SVGTitleElementImpl.cc
new file mode 100644
index 00000000..5bfe2936
--- /dev/null
+++ b/ksvg/impl/SVGTitleElementImpl.cc
@@ -0,0 +1,39 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGDocumentImpl.h"
+#include "SVGTitleElementImpl.h"
+
+using namespace KSVG;
+
+SVGTitleElementImpl::SVGTitleElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGLangSpaceImpl(), SVGStylableImpl(this)
+{
+}
+
+SVGTitleElementImpl::~SVGTitleElementImpl()
+{
+}
+
+void SVGTitleElementImpl::createItem(KSVGCanvas *)
+{
+ emit ownerDoc()->gotTitle(collectText());
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGTitleElementImpl.h b/ksvg/impl/SVGTitleElementImpl.h
new file mode 100644
index 00000000..7c948842
--- /dev/null
+++ b/ksvg/impl/SVGTitleElementImpl.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGTitleElementImpl_H
+#define SVGTitleElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGElementImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGLangSpaceImpl.h"
+
+namespace KSVG
+{
+
+class SVGTitleElementImpl : public SVGElementImpl,
+ public SVGLangSpaceImpl,
+ public SVGStylableImpl
+{
+public:
+ SVGTitleElementImpl(DOM::ElementImpl *);
+ virtual ~SVGTitleElementImpl();
+
+ virtual void createItem(KSVGCanvas *c = 0);
+
+public:
+ KSVG_BRIDGE
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+KSVG_REGISTER_ELEMENT(SVGTitleElementImpl, "title")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGTransformImpl.cc b/ksvg/impl/SVGTransformImpl.cc
new file mode 100644
index 00000000..53ea9bf3
--- /dev/null
+++ b/ksvg/impl/SVGTransformImpl.cc
@@ -0,0 +1,240 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGTransform.h"
+
+#include "SVGMatrixImpl.h"
+#include "SVGTransformImpl.h"
+#include "SVGSVGElementImpl.h"
+
+using namespace KSVG;
+
+#include "SVGTransformImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_cacheimpl.h"
+
+SVGTransformImpl::SVGTransformImpl()
+{
+ m_matrix = SVGSVGElementImpl::createSVGMatrix();
+
+ m_type = SVG_TRANSFORM_UNKNOWN;
+ m_angle = 0;
+}
+
+SVGTransformImpl::~SVGTransformImpl()
+{
+ if(m_matrix)
+ m_matrix->deref();
+}
+
+unsigned short SVGTransformImpl::type() const
+{
+ return m_type;
+}
+
+SVGMatrixImpl *SVGTransformImpl::matrix() const
+{
+ return m_matrix;
+}
+
+double SVGTransformImpl::angle() const
+{
+ return m_angle;
+}
+
+void SVGTransformImpl::setMatrix(SVGMatrixImpl *matrix)
+{
+ if(!matrix)
+ return;
+
+ m_type = SVG_TRANSFORM_MATRIX;
+ m_angle = 0;
+
+ m_matrix->deref();
+ m_matrix = matrix;
+ m_matrix->ref();
+}
+
+void SVGTransformImpl::setTranslate(double tx, double ty)
+{
+ m_type = SVG_TRANSFORM_TRANSLATE;
+ m_angle = 0;
+ m_matrix->reset();
+ m_matrix->translate(tx, ty);
+}
+
+void SVGTransformImpl::setScale(double sx, double sy)
+{
+ m_type = SVG_TRANSFORM_SCALE;
+ m_angle = 0;
+ m_matrix->reset();
+ m_matrix->scaleNonUniform(sx, sy);
+}
+
+void SVGTransformImpl::setRotate(double angle, double cx, double cy)
+{
+ m_type = SVG_TRANSFORM_ROTATE;
+ // mop: evil...fix that...needed to make toString() work correctly
+ m_cx = cx;
+ m_cy = cy;
+ m_angle = angle;
+ m_matrix->reset();
+ m_matrix->translate(cx, cy);
+ m_matrix->rotate(angle);
+ m_matrix->translate(-cx, -cy);
+}
+
+void SVGTransformImpl::setSkewX(double angle)
+{
+ m_type = SVG_TRANSFORM_SKEWX;
+ m_angle = angle;
+ m_matrix->reset();
+ m_matrix->skewX(angle);
+}
+
+void SVGTransformImpl::setSkewY(double angle)
+{
+ m_type = SVG_TRANSFORM_SKEWY;
+ m_angle = angle;
+ m_matrix->reset();
+ m_matrix->skewY(angle);
+}
+
+QString SVGTransformImpl::toString() const
+{
+ switch (m_type)
+ {
+ case SVG_TRANSFORM_UNKNOWN:
+ return QString();
+ case SVG_TRANSFORM_MATRIX:
+ return QString("matrix(" + QString::number(m_matrix->a()) + " " + QString::number(m_matrix->b()) + " " + QString::number(m_matrix->c()) + " " + QString::number(m_matrix->d()) + " " + QString::number(m_matrix->e()) + " " + QString::number(m_matrix->f()) + ")");
+ case SVG_TRANSFORM_TRANSLATE:
+ return QString("translate(" + QString::number(m_matrix->e()) + " " + QString::number(m_matrix->f()) + ")");
+ case SVG_TRANSFORM_SCALE:
+ return QString("scale(" + QString::number(m_matrix->a()) + " " + QString::number(m_matrix->d()) + ")");
+ case SVG_TRANSFORM_ROTATE:
+ return QString("rotate(" + QString::number(m_angle) + " " + QString::number(m_cx) + " " + QString::number(m_cy) + ")");
+ case SVG_TRANSFORM_SKEWX:
+ return QString("skewX(" + QString::number(m_angle) + ")");
+ case SVG_TRANSFORM_SKEWY:
+ return QString("skewY(" + QString::number(m_angle) + ")");
+ default:
+ kdWarning() << "Unknown transform type " << m_type << endl;
+ return QString();
+ }
+}
+
+// ECMA binding
+
+/*
+@namespace KSVG
+@begin SVGTransformImpl::s_hashTable 5
+ type SVGTransformImpl::Type DontDelete|ReadOnly
+ matrix SVGTransformImpl::Matrix DontDelete|ReadOnly
+ angle SVGTransformImpl::Angle DontDelete|ReadOnly
+@end
+@namespace KSVG
+@begin SVGTransformImplProto::s_hashTable 7
+ setMatrix SVGTransformImpl::SetMatrix DontDelete|Function 1
+ setTranslate SVGTransformImpl::SetTranslate DontDelete|Function 2
+ setScale SVGTransformImpl::SetScale DontDelete|Function 2
+ setRotate SVGTransformImpl::SetRotate DontDelete|Function 3
+ setSkewX SVGTransformImpl::SetSkewX DontDelete|Function 1
+ setSkewY SVGTransformImpl::SetSkewY DontDelete|Function 1
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGTransform", SVGTransformImplProto, SVGTransformImplProtoFunc)
+
+Value SVGTransformImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case Type:
+ return Number(m_type);
+ case Matrix:
+ return m_matrix->cache(exec);
+ case Angle:
+ return Number(m_angle);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+Value SVGTransformImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGTransformImpl)
+
+ switch(id)
+ {
+ case SVGTransformImpl::SetMatrix:
+ obj->setMatrix(static_cast<KSVGBridge<SVGMatrixImpl> *>(args[0].imp())->impl());
+ break;
+ case SVGTransformImpl::SetTranslate:
+ obj->setTranslate(args[0].toNumber(exec), args[1].toNumber(exec));
+ break;
+ case SVGTransformImpl::SetScale:
+ obj->setScale(args[0].toNumber(exec), args[1].toNumber(exec));
+ break;
+ case SVGTransformImpl::SetRotate:
+ obj->setRotate(args[0].toNumber(exec), args[1].toNumber(exec), args[2].toNumber(exec));
+ break;
+ case SVGTransformImpl::SetSkewX:
+ obj->setSkewX(args[0].toNumber(exec));
+ break;
+ case SVGTransformImpl::SetSkewY:
+ obj->setSkewY(args[0].toNumber(exec));
+ break;
+ default:
+ kdWarning() << "Unhandled function id in " << k_funcinfo << " : " << id << endl;
+ break;
+ }
+
+ return Undefined();
+}
+
+/*
+@namespace KSVG
+@begin SVGTransformImplConstructor::s_hashTable 11
+ SVG_TRANSFORM_UNKNOWN KSVG::SVG_TRANSFORM_UNKNOWN DontDelete|ReadOnly
+ SVG_TRANSFORM_MATRIX KSVG::SVG_TRANSFORM_MATRIX DontDelete|ReadOnly
+ SVG_TRANSFORM_TRANSLATE KSVG::SVG_TRANSFORM_TRANSLATE DontDelete|ReadOnly
+ SVG_TRANSFORM_SCALE KSVG::SVG_TRANSFORM_SCALE DontDelete|ReadOnly
+ SVG_TRANSFORM_ROTATE KSVG::SVG_TRANSFORM_ROTATE DontDelete|ReadOnly
+ SVG_TRANSFORM_SKEWX KSVG::SVG_TRANSFORM_SKEWX DontDelete|ReadOnly
+ SVG_TRANSFORM_SKEWY KSVG::SVG_TRANSFORM_SKEWY DontDelete|ReadOnly
+@end
+*/
+
+Value SVGTransformImplConstructor::getValueProperty(ExecState *, int token) const
+{
+ return Number(token);
+}
+
+Value KSVG::getSVGTransformImplConstructor(ExecState *exec)
+{
+ return cacheGlobalBridge<SVGTransformImplConstructor>(exec, "[[svgtransform.constructor]]");
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGTransformImpl.h b/ksvg/impl/SVGTransformImpl.h
new file mode 100644
index 00000000..69d71b8f
--- /dev/null
+++ b/ksvg/impl/SVGTransformImpl.h
@@ -0,0 +1,99 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGTransformImpl_H
+#define SVGTransformImpl_H
+
+#include <dom/dom_misc.h>
+#include <dom/dom_string.h>
+
+#include "ksvg_lookup.h"
+
+class QString;
+
+namespace KSVG
+{
+
+class SVGMatrixImpl;
+class SVGTransformImpl : public DOM::DomShared
+{
+public:
+ SVGTransformImpl();
+ virtual ~SVGTransformImpl();
+
+ unsigned short type() const;
+
+ SVGMatrixImpl *matrix() const;
+
+ double angle() const;
+
+ void setMatrix(SVGMatrixImpl *);
+ void setTranslate(double, double);
+ void setScale(double, double);
+ void setRotate(double, double, double);
+ void setSkewX(double);
+ void setSkewY(double);
+
+ QString toString() const;
+
+private:
+ // mop: we have to store the optional rotate stuff :( anyone with a better solution please fix that ;)
+ double m_cx;
+ double m_cy;
+
+ unsigned short m_type;
+ SVGMatrixImpl *m_matrix;
+ double m_angle;
+
+public:
+ KSVG_GET
+
+ enum
+ {
+ // Properties
+ Type, Matrix, Angle,
+ // Functions
+ SetMatrix, SetTranslate, SetScale,
+ SetRotate, SetSkewX, SetSkewY
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+};
+
+class SVGTransformImplConstructor : public KJS::ObjectImp
+{
+public:
+ SVGTransformImplConstructor(KJS::ExecState *) { }
+ KJS::Value getValueProperty(KJS::ExecState *, int token) const;
+
+ // no put - all read-only
+ KSVG_GET
+};
+
+KJS::Value getSVGTransformImplConstructor(KJS::ExecState *exec);
+
+}
+
+KSVG_DEFINE_PROTOTYPE(SVGTransformImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGTransformImplProtoFunc, SVGTransformImpl)
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGTransformListImpl.cc b/ksvg/impl/SVGTransformListImpl.cc
new file mode 100644
index 00000000..5ecc16b6
--- /dev/null
+++ b/ksvg/impl/SVGTransformListImpl.cc
@@ -0,0 +1,103 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGMatrixImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGTransformListImpl.h"
+
+using namespace KSVG;
+
+#include "SVGTransformListImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGTransformListImpl::s_hashTable 2
+ numberOfItems SVGListDefs::NumberOfItems DontDelete|ReadOnly
+@end
+@namespace KSVG
+@begin SVGTransformListImplProto::s_hashTable 11
+ getItem SVGListDefs::GetItem DontDelete|Function 1
+ removeItem SVGListDefs::RemoveItem DontDelete|Function 1
+ appendItem SVGListDefs::AppendItem DontDelete|Function 1
+ initialize SVGListDefs::Initialize DontDelete|Function 1
+ insertItemBefore SVGListDefs::InsertItemBefore DontDelete|Function 2
+ replaceItem SVGListDefs::ReplaceItem DontDelete|Function 2
+ clear SVGListDefs::Clear DontDelete|Function 0
+@end
+*/
+
+KSVG_IMPLEMENT_PROTOTYPE("SVGTransformList", SVGTransformListImplProto, SVGTransformListImplProtoFunc)
+
+Value SVGTransformListImpl::getValueProperty(ExecState *exec, int token) const
+{
+ return SVGList<SVGTransformImpl>::getValueProperty(exec, token);
+}
+
+Value SVGTransformListImplProtoFunc::call(ExecState *exec, Object &thisObj, const List &args)
+{
+ KSVG_CHECK_THIS(SVGTransformListImpl)
+
+ return obj->call(exec, static_cast<SVGList<SVGTransformImpl> *>(obj), args, id);
+}
+
+SVGTransformImpl *SVGTransformListImpl::consolidate()
+{
+ SVGTransformImpl *trans = 0;
+
+ if(numberOfItems()>0)
+ {
+ trans = SVGSVGElementImpl::createSVGTransform();
+ SVGMatrixImpl *matrix = SVGSVGElementImpl::createSVGMatrix();
+
+ for(unsigned int i = 0; i < numberOfItems(); i++)
+ matrix->multiply(getItem(i)->matrix());
+
+ // Pedantic - sets type to MATRIX as per spec.
+ trans->setMatrix(matrix);
+ matrix->deref();
+ initialize(trans);
+ trans->ref();
+ }
+
+ return trans;
+}
+
+SVGMatrixImpl *SVGTransformListImpl::concatenate() const
+{
+ SVGMatrixImpl *matrix = 0;
+
+ if(numberOfItems()>0)
+ {
+ matrix = SVGSVGElementImpl::createSVGMatrix();
+
+ for(unsigned int i = 0; i < numberOfItems(); i++)
+ matrix->multiply(getItem(i)->matrix());
+ }
+
+ return matrix;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGTransformListImpl.h b/ksvg/impl/SVGTransformListImpl.h
new file mode 100644
index 00000000..d59c6046
--- /dev/null
+++ b/ksvg/impl/SVGTransformListImpl.h
@@ -0,0 +1,53 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGTransformListImpl_H
+#define SVGTransformListImpl_H
+
+#include "SVGList.h"
+
+#include "SVGTransformImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGTransformListImpl : public SVGList<SVGTransformImpl>
+{
+public:
+ KSVG_GET
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+
+ SVGTransformImpl *consolidate();
+
+ // Concatenate the transforms. Returns 0 if list is empty
+ SVGMatrixImpl *concatenate() const;
+};
+
+}
+
+KSVG_DEFINE_PROTOTYPE(SVGTransformListImplProto)
+KSVG_IMPLEMENT_PROTOFUNC(SVGTransformListImplProtoFunc, SVGTransformListImpl)
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGTransformableImpl.cc b/ksvg/impl/SVGTransformableImpl.cc
new file mode 100644
index 00000000..59dd904b
--- /dev/null
+++ b/ksvg/impl/SVGTransformableImpl.cc
@@ -0,0 +1,169 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGMatrixImpl.h"
+#include "SVGHelperImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGTransformableImpl.h"
+#include "SVGTransformListImpl.h"
+#include "SVGAnimatedTransformListImpl.h"
+#include "SVGElementImpl.h"
+#include "SVGDocumentImpl.h"
+
+using namespace KSVG;
+
+#include "SVGTransformableImpl.lut.h"
+#include "ksvg_bridge.h"
+
+SVGTransformableImpl::SVGTransformableImpl() : SVGLocatableImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_transform = new SVGAnimatedTransformListImpl();
+ m_transform->ref();
+
+ m_localMatrix = 0;
+}
+
+SVGTransformableImpl::SVGTransformableImpl(const SVGTransformableImpl &other) : SVGLocatableImpl()
+{
+ (*this) = other;
+}
+
+SVGTransformableImpl::~SVGTransformableImpl()
+{
+ if(m_transform)
+ m_transform->deref();
+ if(m_localMatrix)
+ m_localMatrix->deref();
+}
+
+SVGTransformableImpl &SVGTransformableImpl::operator=(const SVGTransformableImpl &other)
+{
+ SVGTransformListImpl *otherTransform = other.m_transform->baseVal();
+
+ // Concat computed values
+ for(unsigned int i = 0;i < otherTransform->numberOfItems(); i++)
+ {
+ SVGTransformImpl *trafo = otherTransform->getItem(i);
+ m_transform->baseVal()->insertItemBefore(SVGSVGElementImpl::createSVGTransformFromMatrix(trafo->matrix()), i);
+ }
+
+ return *this;
+}
+
+SVGAnimatedTransformListImpl *SVGTransformableImpl::transform() const
+{
+ return m_transform;
+}
+
+SVGMatrixImpl *SVGTransformableImpl::getCTM()
+{
+ SVGMatrixImpl *ctm = SVGSVGElementImpl::createSVGMatrix();
+
+ SVGElementImpl *element = dynamic_cast<SVGElementImpl *>(this);
+ Q_ASSERT(element);
+
+ DOM::Node parentNde = element->parentNode();
+
+ if(!parentNde.isNull() && parentNde.nodeType() != DOM::Node::DOCUMENT_NODE)
+ {
+ SVGElementImpl *parent = element->ownerDoc()->getElementFromHandle(parentNde.handle());
+ SVGLocatableImpl *locatableParent = dynamic_cast<SVGLocatableImpl *>(parent);
+
+ if(locatableParent)
+ {
+ SVGMatrixImpl *parentCTM = locatableParent->getCTM();
+ ctm->multiply(parentCTM);
+ parentCTM->deref();
+ }
+ }
+
+ if(m_localMatrix)
+ {
+ ctm->multiply(m_localMatrix);
+ }
+
+ return ctm;
+}
+
+void SVGTransformableImpl::updateLocalMatrix()
+{
+ if(m_transform->baseVal()->numberOfItems()>0)
+ {
+ if(m_localMatrix)
+ m_localMatrix->deref();
+
+ m_localMatrix = m_transform->baseVal()->concatenate();
+ }
+ else
+ {
+ if(m_localMatrix)
+ {
+ m_localMatrix->deref();
+ m_localMatrix = 0;
+ }
+ }
+
+ invalidateCachedMatrices();
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGTransformableImpl::s_hashTable 2
+ transform SVGTransformableImpl::Transform DontDelete
+@end
+*/
+
+Value SVGTransformableImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case Transform:
+ return m_transform->cache(exec);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGTransformableImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case Transform:
+ SVGHelperImpl::parseTransformAttribute(m_transform->baseVal(), value.toString(exec).qstring());
+ updateLocalMatrix();
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGTransformableImpl.h b/ksvg/impl/SVGTransformableImpl.h
new file mode 100644
index 00000000..edff5831
--- /dev/null
+++ b/ksvg/impl/SVGTransformableImpl.h
@@ -0,0 +1,77 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGTransformableImpl_H
+#define SVGTransformableImpl_H
+
+#include <qstring.h>
+
+#include "SVGLocatableImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGMatrixImpl;
+class SVGAnimatedTransformListImpl;
+
+class SVGTransformableImpl : public SVGLocatableImpl
+{
+public:
+ SVGTransformableImpl();
+ SVGTransformableImpl(const SVGTransformableImpl &);
+ virtual ~SVGTransformableImpl();
+
+ SVGTransformableImpl &operator=(const SVGTransformableImpl &);
+
+ SVGAnimatedTransformListImpl *transform() const;
+
+ virtual SVGMatrixImpl *getCTM();
+
+ // The local transformations concatenated together. 0 if
+ // there are no local transformations.
+ virtual const SVGMatrixImpl *localMatrix() { return m_localMatrix; }
+
+private:
+ SVGAnimatedTransformListImpl *m_transform;
+ SVGMatrixImpl *m_localMatrix;
+
+ void updateLocalMatrix();
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ Transform
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGURIReferenceImpl.cc b/ksvg/impl/SVGURIReferenceImpl.cc
new file mode 100644
index 00000000..a68b7442
--- /dev/null
+++ b/ksvg/impl/SVGURIReferenceImpl.cc
@@ -0,0 +1,135 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGURIReferenceImpl.h"
+#include "SVGAnimatedStringImpl.h"
+
+using namespace KSVG;
+
+#include "SVGURIReferenceImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+
+SVGURIReferenceImpl::SVGURIReferenceImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_href = new SVGAnimatedStringImpl();
+ m_href->ref();
+}
+
+SVGURIReferenceImpl::~SVGURIReferenceImpl()
+{
+ if(m_href)
+ m_href->deref();
+}
+
+SVGAnimatedStringImpl *SVGURIReferenceImpl::href() const
+{
+ return m_href;
+}
+
+bool SVGURIReferenceImpl::parseURIReference(const QString &urireference, QString &uri, QString &elementreference)
+{
+ int seperator = urireference.find("#");
+
+ if(seperator == -1)
+ return false;
+
+ uri = urireference.left(seperator);
+ elementreference = urireference.mid(seperator + 1);
+
+ return true;
+}
+
+bool SVGURIReferenceImpl::isUrl(const QString &url)
+{
+ QString temp = url.stripWhiteSpace();
+ return temp.startsWith("url(#") && temp.endsWith(")");
+}
+
+QString SVGURIReferenceImpl::getTarget(const QString &url)
+{
+ if(url.startsWith("url(")) // URI References, ie. fill:url(#target)
+ {
+ unsigned int start = url.find("#") + 1;
+ unsigned int end = url.findRev(")");
+
+ return url.mid(start, end - start);
+ }
+ else if(url.find("#") > -1) // format is #target
+ {
+ unsigned int start = url.find("#") + 1;
+
+ return url.mid(start, url.length() - start);
+ }
+ else // Normal Reference, ie. style="color-profile:changeColor"
+ return url;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGURIReferenceImpl::s_hashTable 2
+ href SVGURIReferenceImpl::Href DontDelete|ReadOnly
+@end
+*/
+
+Value SVGURIReferenceImpl::getValueProperty(ExecState *exec, int token) const
+{
+ switch(token)
+ {
+ case Href:
+ return m_href->cache(exec);
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGURIReferenceImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case Href:
+ {
+ if(m_href)
+ m_href->deref();
+
+ SVGAnimatedStringImpl *temp = new SVGAnimatedStringImpl();
+ temp->ref();
+ temp->setBaseVal(value.toString(exec).string());
+ m_href = temp;
+ break;
+ }
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGURIReferenceImpl.h b/ksvg/impl/SVGURIReferenceImpl.h
new file mode 100644
index 00000000..d6ee42c5
--- /dev/null
+++ b/ksvg/impl/SVGURIReferenceImpl.h
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGURIReferenceImpl_H
+#define SVGURIReferenceImpl_H
+
+#include "ksvg_lookup.h"
+
+class QString;
+
+namespace KSVG
+{
+
+class SVGAnimatedStringImpl;
+class SVGURIReferenceImpl
+{
+public:
+ SVGURIReferenceImpl();
+ ~SVGURIReferenceImpl();
+
+ SVGAnimatedStringImpl *href() const;
+ static QString getTarget(const QString &url);
+ static bool isUrl(const QString &url);
+ static bool parseURIReference(const QString &urireference, QString &uri, QString &elementreference);
+
+protected:
+ SVGAnimatedStringImpl *m_href;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ Href
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGUnitConverter.h b/ksvg/impl/SVGUnitConverter.h
new file mode 100644
index 00000000..90c95796
--- /dev/null
+++ b/ksvg/impl/SVGUnitConverter.h
@@ -0,0 +1,100 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGUnitConverter_H
+#define SVGUnitConverter_H
+
+#include <qptrdict.h>
+
+#include <dom/dom_string.h>
+
+#include "SVGUnitTypes.h"
+#include "SVGShapeImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+
+namespace KSVG
+{
+
+class SVGUnitConverter
+{
+public:
+ SVGUnitConverter() { m_dict.setAutoDelete(true); }
+ ~SVGUnitConverter() { }
+
+ void add(SVGAnimatedLengthImpl *obj)
+ {
+ UnitData *data = new UnitData();
+ data->valueAsString = QString::null;
+
+ m_dict.insert(obj, data);
+ }
+
+ void modify(SVGAnimatedLengthImpl *obj, const QString &value)
+ {
+ UnitData *data = m_dict.find(obj);
+
+ if(data)
+ data->valueAsString = value;
+ }
+
+ void finalize(SVGShapeImpl *bboxContext, SVGShapeImpl *userContext, unsigned short unitType)
+ {
+ bool user = (unitType == SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE);
+ bool bbox = (unitType == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
+
+ if(!user && !bbox) // Invalid unit type
+ return;
+
+ QPtrDictIterator<UnitData> it(m_dict);
+ for(; it.current(); ++it)
+ {
+ UnitData *data = it.current();
+
+ if(!data)
+ continue;
+
+ SVGAnimatedLengthImpl *obj = static_cast<SVGAnimatedLengthImpl *>(it.currentKey());
+
+ if(bbox)
+ obj->baseVal()->setBBoxContext(bboxContext);
+ else
+ obj->baseVal()->setBBoxContext(userContext);
+
+ if(user) // Just assign value, no conversion needed!
+ obj->baseVal()->setValueAsString(data->valueAsString);
+ else // Convert to objectBoundingBox
+ obj->baseVal()->setValueAsString(SVGLengthImpl::convertValToPercentage(data->valueAsString));
+ }
+ }
+
+private:
+ typedef struct
+ {
+ QString valueAsString; // Original value
+ } UnitData;
+
+ QPtrDict<UnitData> m_dict;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGUseElementImpl.cc b/ksvg/impl/SVGUseElementImpl.cc
new file mode 100644
index 00000000..3bd38a42
--- /dev/null
+++ b/ksvg/impl/SVGUseElementImpl.cc
@@ -0,0 +1,409 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include <qstring.h>
+
+#include "KSVGLoader.h"
+#include "KSVGCanvas.h"
+
+#include "SVGRectImpl.h"
+#include "SVGEventImpl.h"
+#include "SVGHelperImpl.h"
+#include "SVGMatrixImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGTransformImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGUseElementImpl.h"
+#include "SVGSymbolElementImpl.h"
+#include "SVGTransformListImpl.h"
+#include "SVGAnimatedStringImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGElementInstanceImpl.h"
+#include "SVGAnimatedTransformListImpl.h"
+
+using namespace KSVG;
+
+#include "SVGUseElementImpl.lut.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+
+SVGUseElementImpl::SVGUseElementImpl(DOM::ElementImpl *impl) : SVGShapeImpl(impl), SVGURIReferenceImpl(), SVGTestsImpl(), SVGLangSpaceImpl(), SVGExternalResourcesRequiredImpl(), SVGStylableImpl(this), SVGTransformableImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_x = new SVGAnimatedLengthImpl();
+ m_x->ref();
+
+ m_y = new SVGAnimatedLengthImpl();
+ m_y->ref();
+
+ m_width = new SVGAnimatedLengthImpl();
+ m_width->ref();
+
+ m_height = new SVGAnimatedLengthImpl();
+ m_height->ref();
+
+ m_instanceRoot = 0;
+}
+
+SVGUseElementImpl::~SVGUseElementImpl()
+{
+ if(m_x)
+ m_x->deref();
+ if(m_y)
+ m_y->deref();
+ if(m_width)
+ m_width->deref();
+ if(m_height)
+ m_height->deref();
+ if(m_instanceRoot)
+ m_instanceRoot->deref();
+}
+
+SVGAnimatedLengthImpl *SVGUseElementImpl::x() const
+{
+ return m_x;
+}
+
+SVGAnimatedLengthImpl *SVGUseElementImpl::y() const
+{
+ return m_y;
+}
+
+SVGAnimatedLengthImpl *SVGUseElementImpl::width() const
+{
+ return m_width;
+}
+
+SVGAnimatedLengthImpl *SVGUseElementImpl::height() const
+{
+ return m_height;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGUseElementImpl::s_hashTable 11
+ x SVGUseElementImpl::X DontDelete|ReadOnly
+ y SVGUseElementImpl::Y DontDelete|ReadOnly
+ width SVGUseElementImpl::Width DontDelete|ReadOnly
+ height SVGUseElementImpl::Height DontDelete|ReadOnly
+ href SVGUseElementImpl::Href DontDelete|ReadOnly
+ instanceRoot SVGUseElementImpl::InstanceRoot DontDelete|ReadOnly
+ animatedInstanceRoot SVGUseElementImpl::AnimatedInstanceRoot DontDelete|ReadOnly
+@end
+*/
+
+Value SVGUseElementImpl::getValueProperty(ExecState *exec, int token) const
+{
+ KSVG_CHECK_ATTRIBUTE
+
+ switch(token)
+ {
+ case X:
+ if(!attributeMode)
+ return m_x->cache(exec);
+ else
+ return Number(m_x->baseVal()->value());
+ case Y:
+ if(!attributeMode)
+ return m_y->cache(exec);
+ else
+ return Number(m_y->baseVal()->value());
+ case Width:
+ if(!attributeMode)
+ return m_width->cache(exec);
+ else
+ return Number(m_width->baseVal()->value());
+ case Height:
+ if(!attributeMode)
+ return m_height->cache(exec);
+ else
+ return Number(m_height->baseVal()->value());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGUseElementImpl::putValueProperty(ExecState *exec, int token, const Value &value, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case X:
+ x()->baseVal()->setValue(value.toNumber(exec));
+ break;
+ case Y:
+ y()->baseVal()->setValue(value.toNumber(exec));
+ break;
+ case Width:
+ width()->baseVal()->setValue(value.toNumber(exec));
+ break;
+ case Height:
+ height()->baseVal()->setValue(value.toNumber(exec));
+ break;
+ case Href:
+ {
+ QString url = value.toString(exec).qstring();
+ href()->setBaseVal(SVGURIReferenceImpl::getTarget(url));
+ break;
+ }
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+SVGRectImpl *SVGUseElementImpl::getBBox()
+{
+ if(m_instanceRoot)
+ {
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(m_instanceRoot->correspondingElement());
+ if(KSVG_TOKEN_NOT_PARSED(Width) && KSVG_TOKEN_NOT_PARSED(Height) && shape)
+ return shape->getBBox();
+ }
+
+ SVGRectImpl *ret = new SVGRectImpl();
+ ret->ref();
+ ret->setX(m_x->baseVal()->value());
+ ret->setY(m_y->baseVal()->value());
+ ret->setWidth(m_width->baseVal()->value());
+ ret->setHeight(m_height->baseVal()->value());
+ return ret;
+}
+
+SVGElementInstanceImpl *SVGUseElementImpl::instanceRoot() const
+{
+ return m_instanceRoot;
+}
+
+SVGElementInstanceImpl *SVGUseElementImpl::animatedInstanceRoot() const
+{
+ return m_animatedInstanceRoot;
+}
+
+void SVGUseElementImpl::createItem(KSVGCanvas *c)
+{
+ if(!m_instanceRoot)
+ {
+ // ownerSVGElement()->getElementById() is wrong here.
+ // It could reference elements from other documents when using getURL (Niko)
+ QString filename, id;
+ DOM::DOMString url = getAttribute("href");
+ if(!SVGURIReferenceImpl::parseURIReference(url.string(), filename, id))
+ return;
+
+ SVGElementImpl *orig;
+ if(!filename.isEmpty())
+ {
+ KURL fragmentUrl(ownerDoc()->baseUrl(), url.string());
+
+ id = fragmentUrl.ref();
+ fragmentUrl.setRef(QString::null);
+
+ orig = KSVGLoader::getSVGFragment(fragmentUrl, ownerDoc(), id);
+ }
+ else
+ {
+ orig = ownerDoc()->getElementByIdRecursive(ownerSVGElement(), href()->baseVal());
+
+ if(orig == 0)
+ {
+ // The document will try to create this item again once the parsing has finished.
+ ownerDoc()->addForwardReferencingUseElement(this);
+ }
+ }
+
+ if(orig == 0)
+ return;
+
+ setReferencedElement(orig);
+
+ // Create a parent, a <g>
+ SVGElementImpl *parent = 0;
+ DOM::Element impl = static_cast<DOM::Document *>(ownerDoc())->createElement("g");
+ parent = SVGDocumentImpl::createElement("g", impl, ownerDoc());
+ SVGElementImpl *clone = orig->cloneNode(true);
+
+ // Apply the use-correction
+ QString trans;
+ trans += " translate(";
+ trans += QString::number(x()->baseVal()->value());
+ trans += " ";
+ trans += QString::number(y()->baseVal()->value());
+ trans += ")";
+
+ // Apply the transform attribute and render the element
+ parent->setAttributeInternal("transform", trans);
+ parent->setAttribute("transform", trans);
+
+ // Apply width/height if symbol
+ if(dynamic_cast<SVGSymbolElementImpl *>(clone))
+ {
+ DOM::Element impl = static_cast<DOM::Document *>(ownerDoc())->createElement("svg");
+ SVGElementImpl *symbolSvg = SVGDocumentImpl::createElement("svg", impl, ownerDoc());
+
+ SVGHelperImpl::copyAttributes(orig, symbolSvg);
+
+ symbolSvg->setAttribute("width", getAttribute("width"));
+ symbolSvg->setAttributeInternal("width", getAttribute("width"));
+ symbolSvg->setAttribute("height", getAttribute("height"));
+ symbolSvg->setAttributeInternal("height", getAttribute("height"));
+ DOM::Node node = clone->firstChild();
+ for(; !node.isNull(); node = clone->firstChild())
+ symbolSvg->appendChild(node);
+
+ clone = symbolSvg;
+ }
+ else if(dynamic_cast<SVGSVGElementImpl *>(clone))
+ {
+ if(!getAttribute("width").isEmpty())
+ {
+ clone->setAttribute("width", getAttribute("width"));
+ clone->setAttributeInternal("width", getAttribute("width"));
+ }
+
+ if(!getAttribute("height").isEmpty())
+ {
+ clone->setAttribute("height", getAttribute("height"));
+ clone->setAttributeInternal("height", getAttribute("height"));
+ }
+ }
+
+ appendChild(*parent);
+ parent->appendChild(*clone);
+
+ setupSubtree(parent, ownerSVGElement(), viewportElement());
+
+ m_instanceRoot->setCorrespondingElement(clone);
+
+ dynamic_cast<SVGLocatableImpl *>(parent)->updateCachedScreenCTM(screenCTM());
+
+ // Redirect local ecma event handlers to the correspondingElement
+ QPtrListIterator<SVGRegisteredEventListener> it(eventListeners());
+ SVGRegisteredEventListener *eventListener;
+ while((eventListener = it.current()) != 0)
+ {
+ ++it;
+ clone->setEventListener(eventListener->id, eventListener->listener);
+ }
+ }
+
+ if(m_instanceRoot)
+ {
+ SVGElementImpl *element = m_instanceRoot->correspondingElement();
+ element->createItem(c);
+ }
+}
+
+void SVGUseElementImpl::removeItem(KSVGCanvas *c)
+{
+ if(m_instanceRoot)
+ {
+ SVGElementImpl *element = m_instanceRoot->correspondingElement();
+ element->removeItem(c);
+ }
+}
+
+void SVGUseElementImpl::setupSubtree(SVGElementImpl *element, SVGSVGElementImpl *ownerSVG, SVGElementImpl *viewport)
+{
+ element->setOwnerSVGElement(ownerSVG);
+ element->setViewportElement(viewport);
+ element->setAttributes();
+
+ SVGSVGElementImpl *thisSVG = dynamic_cast<SVGSVGElementImpl *>(element);
+
+ if(thisSVG != 0)
+ {
+ ownerSVG = thisSVG;
+ viewport = element;
+ }
+
+ DOM::Node child = element->firstChild();
+ for(; !child.isNull(); child = child.nextSibling())
+ {
+ SVGElementImpl *childElement = ownerDoc()->getElementFromHandle(child.handle());
+ if(childElement != 0)
+ setupSubtree(childElement, ownerSVG, viewport);
+ }
+}
+
+void SVGUseElementImpl::setReferencedElement(SVGElementImpl *referenced)
+{
+ if(!referenced)
+ return;
+
+ if(!m_instanceRoot)
+ {
+ m_instanceRoot = new SVGElementInstanceImpl();
+ m_instanceRoot->ref();
+ }
+
+ m_instanceRoot->setCorrespondingElement(referenced);
+}
+
+void SVGUseElementImpl::update(CanvasItemUpdate reason, int param1, int param2)
+{
+ if(m_instanceRoot)
+ {
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(m_instanceRoot->correspondingElement());
+ if(shape)
+ shape->update(reason, param1, param2);
+ }
+}
+
+void SVGUseElementImpl::invalidate(KSVGCanvas *c, bool recalc)
+{
+ if(m_instanceRoot)
+ {
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(m_instanceRoot->correspondingElement());
+ if(shape)
+ shape->invalidate(c, recalc);
+ }
+}
+
+void SVGUseElementImpl::setReferenced(bool referenced)
+{
+ if(m_instanceRoot)
+ {
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(m_instanceRoot->correspondingElement());
+ if(shape)
+ shape->setReferenced(referenced);
+ }
+}
+
+void SVGUseElementImpl::draw()
+{
+ if(m_instanceRoot)
+ {
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(m_instanceRoot->correspondingElement());
+ if(shape)
+ shape->draw();
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGUseElementImpl.h b/ksvg/impl/SVGUseElementImpl.h
new file mode 100644
index 00000000..02eb8d88
--- /dev/null
+++ b/ksvg/impl/SVGUseElementImpl.h
@@ -0,0 +1,101 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGUseElementImpl_H
+#define SVGUseElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGTestsImpl.h"
+#include "SVGShapeImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGLangSpaceImpl.h"
+#include "SVGURIReferenceImpl.h"
+#include "SVGTransformableImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+namespace KSVG
+{
+
+class SVGAnimatedLengthImpl;
+class SVGElementInstanceImpl;
+class SVGUseElementImpl : public SVGShapeImpl,
+ public SVGURIReferenceImpl,
+ public SVGTestsImpl,
+ public SVGLangSpaceImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGStylableImpl,
+ public SVGTransformableImpl
+{
+public:
+ SVGUseElementImpl(DOM::ElementImpl *);
+ virtual ~SVGUseElementImpl();
+
+ SVGAnimatedLengthImpl *x() const;
+ SVGAnimatedLengthImpl *y() const;
+ SVGAnimatedLengthImpl *width() const;
+ SVGAnimatedLengthImpl *height() const;
+
+ SVGElementInstanceImpl *instanceRoot() const;
+ SVGElementInstanceImpl *animatedInstanceRoot() const;
+
+ virtual void createItem(KSVGCanvas *c);
+ virtual void removeItem(KSVGCanvas *c);
+ virtual void update(CanvasItemUpdate reason, int param1, int param2);
+ virtual void invalidate(KSVGCanvas *c, bool recalc);
+ virtual void setReferenced(bool referenced);
+ virtual void draw();
+
+ virtual SVGRectImpl *getBBox();
+
+ void setReferencedElement(SVGElementImpl *);
+
+private:
+ SVGAnimatedLengthImpl *m_x;
+ SVGAnimatedLengthImpl *m_y;
+ SVGAnimatedLengthImpl *m_width;
+ SVGAnimatedLengthImpl *m_height;
+ SVGElementInstanceImpl *m_instanceRoot;
+ SVGElementInstanceImpl *m_animatedInstanceRoot;
+
+ void setupSubtree(SVGElementImpl *element, SVGSVGElementImpl *ownerSVG, SVGElementImpl *viewport);
+
+public:
+ KSVG_GET
+ KSVG_PUT
+ KSVG_BRIDGE
+
+ enum
+ {
+ // Properties
+ X, Y, Width, Height, Href, InstanceRoot, AnimatedInstanceRoot
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+KSVG_REGISTER_ELEMENT(SVGUseElementImpl, "use")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGVKernElementImpl.cc b/ksvg/impl/SVGVKernElementImpl.cc
new file mode 100644
index 00000000..b89d6e6f
--- /dev/null
+++ b/ksvg/impl/SVGVKernElementImpl.cc
@@ -0,0 +1,33 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGVKernElementImpl.h"
+
+using namespace KSVG;
+
+SVGVKernElementImpl::SVGVKernElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl)
+{
+}
+
+SVGVKernElementImpl::~SVGVKernElementImpl()
+{
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGVKernElementImpl.h b/ksvg/impl/SVGVKernElementImpl.h
new file mode 100644
index 00000000..c8302c35
--- /dev/null
+++ b/ksvg/impl/SVGVKernElementImpl.h
@@ -0,0 +1,46 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGVKernElementImpl_H
+#define SVGVKernElementImpl_H
+
+#include "ksvg_lookup.h"
+
+#include "SVGElementImpl.h"
+
+namespace KSVG
+{
+
+class SVGVKernElementImpl : public SVGElementImpl
+{
+public:
+ SVGVKernElementImpl(DOM::ElementImpl *impl);
+ virtual ~SVGVKernElementImpl();
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGViewElementImpl.cc b/ksvg/impl/SVGViewElementImpl.cc
new file mode 100644
index 00000000..a051fba0
--- /dev/null
+++ b/ksvg/impl/SVGViewElementImpl.cc
@@ -0,0 +1,94 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGStringListImpl.h"
+#include "SVGViewElementImpl.h"
+
+using namespace KSVG;
+
+#include "SVGViewElementImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_ecma.h"
+
+SVGViewElementImpl::SVGViewElementImpl(DOM::ElementImpl *impl) : SVGElementImpl(impl), SVGExternalResourcesRequiredImpl(), SVGFitToViewBoxImpl(), SVGZoomAndPanImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_viewTarget = new SVGStringListImpl();
+ m_viewTarget->ref();
+}
+
+SVGViewElementImpl::~SVGViewElementImpl()
+{
+ if(m_viewTarget)
+ m_viewTarget->deref();
+}
+
+SVGStringListImpl *SVGViewElementImpl::viewTarget() const
+{
+ return m_viewTarget;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGViewElementImpl::s_hashTable 2
+ viewTarget SVGViewElementImpl::ViewTarget DontDelete|ReadOnly
+@end
+*/
+
+Value SVGViewElementImpl::getValueProperty(ExecState *, int token) const
+{
+ //KSVG_CHECK_ATTRIBUTE
+
+ switch(token)
+ {
+ case ViewTarget:
+ // TODO
+ return Undefined();
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+void SVGViewElementImpl::putValueProperty(ExecState *, int token, const Value &, int attr)
+{
+ // This class has just ReadOnly properties, only with the Internal flag set
+ // it's allowed to modify those.
+ if(!(attr & KJS::Internal))
+ return;
+
+ switch(token)
+ {
+ case ViewTarget:
+ // TODO
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGViewElementImpl.h b/ksvg/impl/SVGViewElementImpl.h
new file mode 100644
index 00000000..8b8d7e0b
--- /dev/null
+++ b/ksvg/impl/SVGViewElementImpl.h
@@ -0,0 +1,70 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGViewElementImpl_H
+#define SVGViewElementImpl_H
+
+#include "SVGElementImpl.h"
+#include "SVGZoomAndPanImpl.h"
+#include "SVGFitToViewBoxImpl.h"
+#include "SVGExternalResourcesRequiredImpl.h"
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGStringListImpl;
+class SVGViewElementImpl : public SVGElementImpl,
+ public SVGExternalResourcesRequiredImpl,
+ public SVGFitToViewBoxImpl,
+ public SVGZoomAndPanImpl
+{
+public:
+ SVGViewElementImpl(DOM::ElementImpl *);
+ virtual ~SVGViewElementImpl();
+
+ SVGStringListImpl *viewTarget() const;
+
+private:
+ SVGStringListImpl *m_viewTarget;
+
+public:
+ KSVG_GET
+ KSVG_PUT
+ KSVG_BRIDGE
+
+ enum
+ {
+ // Properties
+ ViewTarget
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+KSVG_REGISTER_ELEMENT(SVGViewElementImpl, "view")
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGViewSpecImpl.cc b/ksvg/impl/SVGViewSpecImpl.cc
new file mode 100644
index 00000000..07412cc5
--- /dev/null
+++ b/ksvg/impl/SVGViewSpecImpl.cc
@@ -0,0 +1,98 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include <qstringlist.h>
+
+#include "SVGElementImpl.h"
+#include "SVGViewSpecImpl.h"
+#include "SVGTransformListImpl.h"
+
+using namespace KSVG;
+
+SVGViewSpecImpl::SVGViewSpecImpl() : SVGZoomAndPanImpl(), SVGFitToViewBoxImpl()
+{
+ m_transform = new SVGTransformListImpl();
+ m_transform->ref();
+
+ m_viewTarget = new SVGElementImpl(0);
+ m_viewTarget->ref();
+}
+
+SVGViewSpecImpl::~SVGViewSpecImpl()
+{
+ if(m_transform)
+ m_transform->deref();
+ if(m_viewTarget)
+ m_viewTarget->deref();
+}
+
+SVGTransformListImpl *SVGViewSpecImpl::transform() const
+{
+ return m_transform;
+}
+
+SVGElementImpl *SVGViewSpecImpl::viewTarget() const
+{
+ return m_viewTarget;
+}
+
+DOM::DOMString SVGViewSpecImpl::viewBoxString() const
+{
+ return m_viewBoxString;
+}
+
+DOM::DOMString SVGViewSpecImpl::preserveAspectRatioString() const
+{
+ return m_preserveAspectRatioString;
+}
+
+DOM::DOMString SVGViewSpecImpl::transformString() const
+{
+ return m_transformString;
+}
+
+DOM::DOMString SVGViewSpecImpl::viewTargetString() const
+{
+ return m_viewTargetString;
+}
+
+bool SVGViewSpecImpl::parseViewSpec(const QString &s)
+{
+ if(!s.startsWith("svgView("))
+ return false;
+
+ // remove 'svgView(' and ')'
+ QStringList subAttrs = QStringList::split(';', s.mid(8));
+
+ for(QStringList::ConstIterator it = subAttrs.begin() ; it != subAttrs.end(); ++it)
+ {
+ if((*it).startsWith("viewBox("))
+ m_viewBoxString = (*it).mid(8);
+ else if((*it).startsWith("zoomAndPan("))
+ parseZoomAndPan(DOM::DOMString((*it).mid(11)));
+ else if((*it).startsWith("preserveAspectRatio("))
+ m_preserveAspectRatioString = (*it).mid(20);
+ }
+ return true;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGViewSpecImpl.h b/ksvg/impl/SVGViewSpecImpl.h
new file mode 100644
index 00000000..f9e01e48
--- /dev/null
+++ b/ksvg/impl/SVGViewSpecImpl.h
@@ -0,0 +1,69 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGViewSpecImpl_H
+#define SVGViewSpecImpl_H
+
+#include <dom/dom_string.h>
+#include <dom/dom_misc.h>
+
+#include "ksvg_lookup.h"
+
+#include "SVGZoomAndPanImpl.h"
+#include "SVGFitToViewBoxImpl.h"
+
+namespace KSVG
+{
+
+class SVGElementImpl;
+class SVGTransformListImpl;
+class SVGViewSpecImpl : public DOM::DomShared, public SVGZoomAndPanImpl, public SVGFitToViewBoxImpl
+{
+public:
+ SVGViewSpecImpl();
+ virtual ~SVGViewSpecImpl();
+
+ SVGTransformListImpl *transform() const;
+ SVGElementImpl *viewTarget() const;
+ DOM::DOMString viewBoxString() const;
+ DOM::DOMString preserveAspectRatioString() const;
+ DOM::DOMString transformString() const;
+ DOM::DOMString viewTargetString() const;
+
+ bool parseViewSpec(const QString &);
+
+private:
+ SVGTransformListImpl *m_transform;
+ SVGElementImpl *m_viewTarget;
+ DOM::DOMString m_viewBoxString;
+ DOM::DOMString m_preserveAspectRatioString;
+ DOM::DOMString m_transformString;
+ DOM::DOMString m_viewTargetString;
+
+public:
+ KSVG_FORWARDGET
+ KSVG_FORWARDPUT
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGWindowImpl.cc b/ksvg/impl/SVGWindowImpl.cc
new file mode 100644
index 00000000..b19847a4
--- /dev/null
+++ b/ksvg/impl/SVGWindowImpl.cc
@@ -0,0 +1,187 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "SVGWindowImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGEvent.h"
+#include "KSVGCanvas.h"
+#include <ksvg_ecma.h>
+#include <ksvg_scriptinterpreter.h>
+
+#include <qstylesheet.h>
+
+#include <kurl.h>
+#include <kmessagebox.h>
+#include <kinputdialog.h>
+#include <klocale.h>
+
+using namespace KSVG;
+
+
+SVGWindowImpl::SVGWindowImpl()
+{
+ m_document = 0;
+}
+
+SVGWindowImpl::SVGWindowImpl(SVGDocumentImpl *doc)
+{
+ m_document = doc;
+ if(m_document)
+ m_document->ref();
+}
+
+SVGWindowImpl::~SVGWindowImpl()
+{
+ if(m_document)
+ m_document->deref();
+}
+
+/*StyleSheet SVGWindowImpl::defaultStyleSheet() const
+{
+ return m_defaultStyleSheet;
+}*/
+
+SVGDocumentImpl *SVGWindowImpl::document() const
+{
+ return m_document;
+}
+
+DOM::Event SVGWindowImpl::evt() const
+{
+ return KSVG::SVGEvent(m_document->ecmaEngine()->interpreter()->currentEvent());
+}
+
+long SVGWindowImpl::innerHeight() const
+{
+ return m_document ? int(m_document->canvas()->height()) : -1;
+}
+
+long SVGWindowImpl::innerWidth() const
+{
+ return m_document ? int(m_document->canvas()->width()) : -1;
+}
+
+void SVGWindowImpl::setSrc(const DOM::DOMString &/*src*/)
+{
+ // TODO : make KURL, load and parse doc
+}
+
+DOM::DOMString SVGWindowImpl::src() const
+{
+ if(!m_document)
+ return DOM::DOMString();
+ return m_document->baseUrl().prettyURL();
+}
+
+void SVGWindowImpl::clearInterval(long /*interval*/)
+{
+}
+
+void SVGWindowImpl::clearTimeout(long /*timeout*/)
+{
+}
+
+void SVGWindowImpl::getURL(const DOM::DOMString &/*uri*/, const DOM::EventListener &/*callback*/)
+{
+}
+
+/*DocumentFragment SVGWindowImpl::parseXML(const DOM::DOMString &source, const Document &document)
+{
+}*/
+
+void SVGWindowImpl::postURL(const DOM::DOMString &/*uri*/, const DOM::DOMString &/*data*/, const DOM::EventListener &/*callback*/, const DOM::DOMString &/*mimeType*/, const DOM::DOMString &/*contentEncoding*/)
+{
+}
+
+DOM::DOMString SVGWindowImpl::printNode(const DOM::Node &node, unsigned short level)
+{
+ QString ret;
+ if(node.isNull()) return ret;
+ SVGElementImpl *elem = m_document->getElementFromHandle(node.handle());
+ if(node.nodeType() == DOM::Node::DOCUMENT_NODE)
+ {
+ ret += "<\?xml version=\"1.0\" encoding=\"UTF-8\"\?><!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n" + printNode(node.firstChild()).string() + "\n";
+ }
+ else if(node.nodeType() == DOM::Node::TEXT_NODE)
+ {
+ printIndentation(ret, level);
+ ret += node.nodeValue().string();
+ }
+ else if(elem)
+ {
+ printIndentation(ret, level);
+ ret += "<" + elem->tagName().string();
+ // handle attrs
+ QDictIterator<DOM::DOMString> it(elem->attributes());
+ for(;it.current(); ++it)
+ ret += " " + it.currentKey() + "=\"" + it.current()->string() + '\"';
+ if(elem->firstChild().isNull()) // no children
+ ret += " />\n";
+ else // handle children
+ {
+ ret += ">\n";
+ for(DOM::Node child = node.firstChild();!child.isNull();child = child.nextSibling())
+ ret += printNode(child, level + 1).string();
+ printIndentation(ret, level);
+ ret += "</" + elem->tagName().string() + ">\n";
+ }
+ }
+ return ret;
+}
+
+void SVGWindowImpl::printIndentation(QString &ret, unsigned short level, unsigned short indent)
+{
+ for(int i = 0;i < indent * level;i++)
+ ret += " ";
+}
+
+long SVGWindowImpl::setInterval(const DOM::DOMString &/*code*/, const long &/*delay*/)
+{
+ return 0;
+}
+
+long SVGWindowImpl::setTimeout(const DOM::DOMString &/*code*/, const long &/*delay*/)
+{
+ return 0;
+}
+
+void SVGWindowImpl::alert(const DOM::DOMString &message, const QString &title)
+{
+ KMessageBox::error(0L, QStyleSheet::convertFromPlainText(message.string()), title);
+}
+
+bool SVGWindowImpl::confirm(const DOM::DOMString &message, const QString &title)
+{
+ return KMessageBox::warningContinueCancel(0L, QStyleSheet::convertFromPlainText(message.string()), title, KStdGuiItem::ok()) == KMessageBox::Continue;
+}
+
+DOM::DOMString SVGWindowImpl::prompt(const DOM::DOMString &message, const DOM::DOMString &_default, const QString &)
+{
+ bool ok;
+ QString str;
+ str = KInputDialog::getText(i18n("Prompt"), QStyleSheet::convertFromPlainText(message.string()), _default.string(), &ok);
+ if(ok)
+ return str;
+ else
+ return "";
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGWindowImpl.h b/ksvg/impl/SVGWindowImpl.h
new file mode 100644
index 00000000..0861809e
--- /dev/null
+++ b/ksvg/impl/SVGWindowImpl.h
@@ -0,0 +1,73 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGWindowImpl_H
+#define SVGWindowImpl_H
+
+#include <dom/dom_string.h>
+#include <dom/dom_node.h>
+#include <dom/dom_misc.h>
+#include <dom/dom2_events.h>
+
+namespace KSVG
+{
+class SVGDocumentImpl;
+
+class SVGWindowImpl : public DOM::DomShared
+{
+public:
+ SVGWindowImpl();
+ SVGWindowImpl(SVGDocumentImpl *doc);
+ virtual ~SVGWindowImpl();
+
+ //StyleSheet defaultStyleSheet() const;
+ SVGDocumentImpl *document() const;
+ DOM::Event evt() const;
+ long innerHeight() const;
+ long innerWidth() const;
+
+ void setSrc(const DOM::DOMString &src);
+ DOM::DOMString src() const;
+
+ void clearInterval(long interval);
+ void clearTimeout(long timeout);
+ void getURL(const DOM::DOMString &uri, const DOM::EventListener &callback);
+ //DocumentFragment parseXML(const DOM::DOMString &source, const Document &document);
+ void postURL(const DOM::DOMString &uri, const DOM::DOMString &data, const DOM::EventListener &callback, const DOM::DOMString &mimeType, const DOM::DOMString &contentEncoding);
+ DOM::DOMString printNode(const DOM::Node &node, unsigned short level = 0);
+ long setInterval(const DOM::DOMString &code, const long &delay);
+ long setTimeout(const DOM::DOMString &code, const long &delay);
+ static void alert(const DOM::DOMString &message, const QString &title = "SVG Window");
+ static bool confirm(const DOM::DOMString &message, const QString &title = "SVG Window");
+ static DOM::DOMString prompt(const DOM::DOMString &message, const DOM::DOMString &_default, const QString &title = "SVG Window");
+
+private:
+ void printIndentation(QString &ret, unsigned short level, unsigned short indent = 2);
+
+private:
+ //StyleSheet m_defaultStyleSheet;
+ SVGDocumentImpl *m_document;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGZoomAndPanImpl.cc b/ksvg/impl/SVGZoomAndPanImpl.cc
new file mode 100644
index 00000000..f3bf96ce
--- /dev/null
+++ b/ksvg/impl/SVGZoomAndPanImpl.cc
@@ -0,0 +1,112 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "SVGZoomAndPan.h"
+#include "SVGZoomAndPanImpl.h"
+
+using namespace KSVG;
+
+#include "SVGZoomAndPanImpl.lut.h"
+#include "ksvg_scriptinterpreter.h"
+#include "ksvg_bridge.h"
+#include "ksvg_cacheimpl.h"
+
+SVGZoomAndPanImpl::SVGZoomAndPanImpl()
+{
+ KSVG_EMPTY_FLAGS
+
+ m_zoomAndPan = SVG_ZOOMANDPAN_MAGNIFY;
+}
+
+SVGZoomAndPanImpl::~SVGZoomAndPanImpl()
+{
+}
+
+void SVGZoomAndPanImpl::setZoomAndPan(unsigned short zoomAndPan)
+{
+ m_zoomAndPan = zoomAndPan;
+}
+
+unsigned short SVGZoomAndPanImpl::zoomAndPan() const
+{
+ return m_zoomAndPan;
+}
+
+void SVGZoomAndPanImpl::parseZoomAndPan(const DOM::DOMString &attr)
+{
+ if(attr == "disable")
+ m_zoomAndPan = SVG_ZOOMANDPAN_DISABLE;
+}
+
+// Ecma stuff
+
+/*
+@namespace KSVG
+@begin SVGZoomAndPanImpl::s_hashTable 2
+ zoomAndPan SVGZoomAndPanImpl::ZoomAndPan DontDelete
+@end
+*/
+
+Value SVGZoomAndPanImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case ZoomAndPan:
+ return Number(zoomAndPan());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return KJS::Undefined();
+ }
+}
+
+void SVGZoomAndPanImpl::putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int)
+{
+ switch(token)
+ {
+ case ZoomAndPan:
+ parseZoomAndPan(value.toString(exec).string());
+ break;
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ }
+}
+
+/*
+@namespace KSVG
+@begin SVGZoomAndPanImplConstructor::s_hashTable 5
+ SVG_ZOOMANDPAN_UNKNOWN KSVG::SVG_ZOOMANDPAN_UNKNOWN DontDelete|ReadOnly
+ SVG_ZOOMANDPAN_DISABLE KSVG::SVG_ZOOMANDPAN_DISABLE DontDelete|ReadOnly
+ SVG_ZOOMANDPAN_MAGNIFY KSVG::SVG_ZOOMANDPAN_MAGNIFY DontDelete|ReadOnly
+@end
+*/
+
+Value SVGZoomAndPanImplConstructor::getValueProperty(ExecState *, int token) const
+{
+ return Number(token);
+}
+
+Value KSVG::getSVGZoomAndPanImplConstructor(ExecState *exec)
+{
+ return cacheGlobalBridge<SVGZoomAndPanImplConstructor>(exec, "[[svgzoomandpan.constructor]]");
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGZoomAndPanImpl.h b/ksvg/impl/SVGZoomAndPanImpl.h
new file mode 100644
index 00000000..ed7fef98
--- /dev/null
+++ b/ksvg/impl/SVGZoomAndPanImpl.h
@@ -0,0 +1,76 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGZoomAndPanImpl_H
+#define SVGZoomAndPanImpl_H
+
+#include <dom/dom_misc.h>
+#include <dom/dom_string.h>
+
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGZoomAndPanImpl
+{
+public:
+ SVGZoomAndPanImpl();
+ virtual ~SVGZoomAndPanImpl();
+
+ void setZoomAndPan(unsigned short zoomAndPan);
+ unsigned short zoomAndPan() const;
+
+ void parseZoomAndPan(const DOM::DOMString &attr);
+
+private:
+ unsigned short m_zoomAndPan;
+
+public:
+ KSVG_BASECLASS_GET
+ KSVG_PUT
+
+ enum
+ {
+ // Properties
+ ZoomAndPan
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+ void putValueProperty(KJS::ExecState *exec, int token, const KJS::Value &value, int attr);
+};
+
+class SVGZoomAndPanImplConstructor : public KJS::ObjectImp
+{
+public:
+ SVGZoomAndPanImplConstructor(KJS::ExecState *) { }
+ KJS::Value getValueProperty(KJS::ExecState *, int token) const;
+
+ // no put - all read-only
+ KSVG_GET
+};
+
+KJS::Value getSVGZoomAndPanImplConstructor(KJS::ExecState *exec);
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGZoomEventImpl.cc b/ksvg/impl/SVGZoomEventImpl.cc
new file mode 100644
index 00000000..448309f0
--- /dev/null
+++ b/ksvg/impl/SVGZoomEventImpl.cc
@@ -0,0 +1,111 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+#include "SVGRectImpl.h"
+#include "SVGPointImpl.h"
+#include "SVGZoomEventImpl.h"
+
+using namespace KSVG;
+
+#include "SVGZoomEventImpl.lut.h"
+#include "SVGSVGElementImpl.h"
+
+using namespace KJS;
+
+SVGZoomEventImpl::SVGZoomEventImpl(SVGEvent::EventId _id,
+ bool canBubbleArg,
+ bool cancelableArg,
+ DOM::AbstractView &viewArg,
+ long detailArg,
+ float previousScale, SVGPointImpl *previousTranslate,
+ float newScale, SVGPointImpl *newTranslate)
+: SVGUIEventImpl(_id, canBubbleArg, cancelableArg, viewArg, detailArg), m_previousScale( previousScale ), m_newScale( newScale )
+{
+ m_zoomRectScreen = SVGSVGElementImpl::createSVGRect();
+ m_previousTranslate = previousTranslate;
+ if(m_previousTranslate)
+ m_previousTranslate->ref();
+ m_newTranslate = newTranslate;
+ if(m_newTranslate)
+ m_newTranslate->ref();
+}
+
+SVGZoomEventImpl::~SVGZoomEventImpl()
+{
+ if(m_zoomRectScreen)
+ m_zoomRectScreen->deref();
+ if(m_previousTranslate)
+ m_previousTranslate->deref();
+ if(m_newTranslate)
+ m_newTranslate->deref();
+}
+
+SVGRectImpl *SVGZoomEventImpl::zoomRectScreen() const
+{
+ return m_zoomRectScreen;
+}
+
+float SVGZoomEventImpl::previousScale() const
+{
+ return m_previousScale;
+}
+
+SVGPointImpl *SVGZoomEventImpl::previousTranslate() const
+{
+ return m_previousTranslate;
+}
+
+float SVGZoomEventImpl::newScale() const
+{
+ return m_newScale;
+}
+
+SVGPointImpl *SVGZoomEventImpl::newTranslate() const
+{
+ return m_newTranslate;
+}
+
+/*
+@namespace KSVG
+@begin SVGZoomEventImpl::s_hashTable 7
+ zoomRectScreen SVGZoomEventImpl::ZoomRectScreen DontDelete|ReadOnly
+ previousScale SVGZoomEventImpl::PreviousScale DontDelete|ReadOnly
+ previousTranslate SVGZoomEventImpl::PreviousTranslate DontDelete|ReadOnly
+ newScale SVGZoomEventImpl::NewScale DontDelete|ReadOnly
+ newTranslate SVGZoomEventImpl::NewTranslate DontDelete|ReadOnly
+@end
+*/
+
+Value SVGZoomEventImpl::getValueProperty(ExecState *, int token) const
+{
+ switch(token)
+ {
+ case PreviousScale:
+ return Number(previousScale());
+ case NewScale:
+ return Number(newScale());
+ default:
+ kdWarning() << "Unhandled token in " << k_funcinfo << " : " << token << endl;
+ return Undefined();
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/SVGZoomEventImpl.h b/ksvg/impl/SVGZoomEventImpl.h
new file mode 100644
index 00000000..41706a37
--- /dev/null
+++ b/ksvg/impl/SVGZoomEventImpl.h
@@ -0,0 +1,77 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SVGZoomEventImpl_H
+#define SVGZoomEventImpl_H
+
+#include "SVGEventImpl.h"
+#include "ksvg_lookup.h"
+
+namespace KSVG
+{
+
+class SVGRectImpl;
+class SVGPointImpl;
+class SVGZoomEventImpl : public SVGUIEventImpl
+{
+public:
+ SVGZoomEventImpl(SVGEvent::EventId _id,
+ bool canBubbleArg,
+ bool cancelableArg,
+ DOM::AbstractView &viewArg,
+ long detailArg,
+ float previousScale, SVGPointImpl *previousTranslate,
+ float newScale, SVGPointImpl *newTranslate);
+ virtual ~SVGZoomEventImpl();
+
+ SVGRectImpl *zoomRectScreen() const;
+
+ float previousScale() const;
+ SVGPointImpl *previousTranslate() const;
+
+ float newScale() const;
+ SVGPointImpl *newTranslate() const;
+
+private:
+ SVGRectImpl *m_zoomRectScreen;
+
+ float m_previousScale;
+ SVGPointImpl *m_previousTranslate;
+
+ float m_newScale;
+ SVGPointImpl *m_newTranslate;
+
+public:
+ KSVG_GET
+
+ enum
+ {
+ // Properties
+ ZoomRectScreen, PreviousScale, PreviousTranslate, NewScale, NewTranslate
+ };
+
+ KJS::Value getValueProperty(KJS::ExecState *exec, int token) const;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/TODO b/ksvg/impl/TODO
new file mode 100644
index 00000000..8cfd4c4a
--- /dev/null
+++ b/ksvg/impl/TODO
@@ -0,0 +1,5 @@
+* cleanup SVGSVGElementImpl
+* cleanup SVGShapeImpl
+* fix SVGStringListImpl
+* attriubuteMode get() for SVGGlyphElementImpl
+* default attributes, ... for SVGGlyphElementImpl
diff --git a/ksvg/impl/generateddata.cpp b/ksvg/impl/generateddata.cpp
new file mode 100644
index 00000000..5a4b3d7b
--- /dev/null
+++ b/ksvg/impl/generateddata.cpp
@@ -0,0 +1,8899 @@
+#include <ksvg_lookup.h>
+#include <ksvg_ecma.h>
+#include <SVGZoomEventImpl.h>
+#include <SVGVKernElementImpl.h>
+#include <SVGList.h>
+#include <SVGTRefElementImpl.h>
+#include <SVGSVGElementImpl.h>
+#include <SVGFETurbulenceElementImpl.h>
+#include <SVGElementInstanceImpl.h>
+#include <SVGAnimateElementImpl.h>
+#include <SVGFEGaussianBlurElementImpl.h>
+#include <SVGZoomAndPanImpl.h>
+#include <SVGFEFuncRElementImpl.h>
+#include <SVGPathSegListImpl.h>
+#include <SVGFEFuncAElementImpl.h>
+#include <SVGFESpecularLightingElementImpl.h>
+#include <SVGComponentTransferFunctionElementImpl.h>
+#include <SVGICCColorImpl.h>
+#include <SVGFEPointLightElementImpl.h>
+#include <SVGMissingGlyphElementImpl.h>
+#include <SVGFontFaceFormatElementImpl.h>
+#include <SVGFontFaceUriElementImpl.h>
+#include <SVGFEMorphologyElementImpl.h>
+#include <SVGPaintServerImpl.h>
+#include <SVGStringListImpl.h>
+#include <SVGPolyElementImpl.h>
+#include <SVGLinearGradientElementImpl.h>
+#include <svgpathparser.h>
+#include <SVGTextPathElementImpl.h>
+#include <SVGNumberImpl.h>
+#include <SVGPathSegImpl.h>
+#include <SVGElementInstanceListImpl.h>
+#include <SVGAnimatedIntegerImpl.h>
+#include <SVGLocatableImpl.h>
+#include <SVGAngleImpl.h>
+#include <SVGAnimatedPreserveAspectRatioImpl.h>
+#include <SVGColorImpl.h>
+#include <SVGEllipseElementImpl.h>
+#include <SVGGlyphRefElementImpl.h>
+#include <SVGScriptElementImpl.h>
+#include <SVGDocumentImpl.h>
+#include <SVGAElementImpl.h>
+#include <SVGAltGlyphDefElementImpl.h>
+#include <SVGPathSegCurvetoQuadraticSmoothImpl.h>
+#include <SVGFontElementImpl.h>
+#include <SVGGElementImpl.h>
+#include <SVGPathSegLinetoImpl.h>
+#include <SVGForeignObjectElementImpl.h>
+#include <SVGAnimatedStringImpl.h>
+#include <SVGAnimatedTransformListImpl.h>
+#include <SVGPatternElementImpl.h>
+#include <SVGAltGlyphElementImpl.h>
+#include <SVGElementImpl.h>
+#include <SVGStylableImpl.h>
+#include <SVGCSSRuleImpl.h>
+#include <SVGFESpotLightElementImpl.h>
+#include <SVGPreserveAspectRatioImpl.h>
+#include <SVGColorProfileRuleImpl.h>
+#include <SVGContainerImpl.h>
+#include <SVGAnimateTransformElementImpl.h>
+#include <SVGMatrixImpl.h>
+#include <SVGEcma.h>
+#include <SVGAnimatedLengthListImpl.h>
+#include <SVGAnimatedAngleImpl.h>
+#include <SVGURIReferenceImpl.h>
+#include <SVGPolylineElementImpl.h>
+#include <SVGDefinitionSrcElementImpl.h>
+#include <SVGPathSegLinetoHorizontalImpl.h>
+#include <SVGCursorElementImpl.h>
+#include <SVGFitToViewBoxImpl.h>
+#include <SVGEventImpl.h>
+#include <SVGMetadataElementImpl.h>
+#include <SVGLengthImpl.h>
+#include <SVGTransformableImpl.h>
+#include <SVGLengthListImpl.h>
+#include <SVGTitleElementImpl.h>
+#include <SVGTSpanElementImpl.h>
+#include <SVGDescElementImpl.h>
+#include <SVGTextContentElementImpl.h>
+#include <SVGFEFuncBElementImpl.h>
+#include <SVGMPathElementImpl.h>
+#include <SVGDefsElementImpl.h>
+#include <SVGAnimateMotionElementImpl.h>
+#include <SVGStyleElementImpl.h>
+#include <SVGSwitchElementImpl.h>
+#include <SVGTransformListImpl.h>
+#include <SVGPointListImpl.h>
+#include <SVGFECompositeElementImpl.h>
+#include <SVGHKernElementImpl.h>
+#include <SVGFontFaceElementImpl.h>
+#include <SVGPathSegMovetoImpl.h>
+#include <SVGPathSegLinetoVerticalImpl.h>
+#include <SVGAnimatedLengthImpl.h>
+#include <SVGFEBlendElementImpl.h>
+#include <SVGLangSpaceImpl.h>
+#include <SVGRadialGradientElementImpl.h>
+#include <SVGAnimatedRectImpl.h>
+#include <SVGFilterPrimitiveStandardAttributesImpl.h>
+#include <SVGPathElementImpl.h>
+#include <SVGStopElementImpl.h>
+#include <SVGAnimateColorElementImpl.h>
+#include <SVGPathSegArcImpl.h>
+#include <SVGAnimatedPointsImpl.h>
+#include <SVGUseElementImpl.h>
+#include <SVGViewSpecImpl.h>
+#include <SVGFEMergeNodeElementImpl.h>
+#include <SVGHelperImpl.h>
+#include <SVGFEDiffuseLightingElementImpl.h>
+#include <SVGSymbolElementImpl.h>
+#include <SVGFEFloodElementImpl.h>
+#include <SVGAnimatedNumberListImpl.h>
+#include <SVGExternalResourcesRequiredImpl.h>
+#include <SVGFETileElementImpl.h>
+#include <SVGTextPositioningElementImpl.h>
+#include <SVGGlyphElementImpl.h>
+#include <SVGAnimatedBooleanImpl.h>
+#include <SVGSetElementImpl.h>
+#include <SVGFontFaceSrcElementImpl.h>
+#include <SVGTextElementImpl.h>
+#include <SVGFEMergeElementImpl.h>
+#include <SVGMarkerElementImpl.h>
+#include <SVGViewElementImpl.h>
+#include <SVGFEFuncGElementImpl.h>
+#include <SVGColorProfileElementImpl.h>
+#include <SVGGradientElementImpl.h>
+#include <SVGFEConvolveMatrixElementImpl.h>
+#include <SVGFontFaceNameElementImpl.h>
+#include <SVGLineElementImpl.h>
+#include <SVGUnitConverter.h>
+#include <SVGFEColorMatrixElementImpl.h>
+#include <SVGCircleElementImpl.h>
+#include <SVGTestsImpl.h>
+#include <SVGRectElementImpl.h>
+#include <SVGRectImpl.h>
+#include <SVGPolygonElementImpl.h>
+#include <SVGTimeScheduler.h>
+#include <SVGNumberListImpl.h>
+#include <SVGPathSegCurvetoCubicSmoothImpl.h>
+#include <SVGPointImpl.h>
+#include <SVGFEDistantLightElementImpl.h>
+#include <SVGPathSegCurvetoCubicImpl.h>
+#include <SVGFEComponentTransferElementImpl.h>
+#include <SVGWindowImpl.h>
+#include <SVGMaskElementImpl.h>
+#include <SVGShapeImpl.h>
+#include <SVGAnimatedEnumerationImpl.h>
+#include <SVGAnimatedPathDataImpl.h>
+#include <SVGFEOffsetElementImpl.h>
+#include <SVGPaintImpl.h>
+#include <SVGFilterElementImpl.h>
+#include <SVGImageElementImpl.h>
+#include <SVGAnimatedNumberImpl.h>
+#include <SVGAnimationElementImpl.h>
+#include <SVGFEDisplacementMapElementImpl.h>
+#include <SVGPathSegClosePathImpl.h>
+#include <SVGTransformImpl.h>
+#include <SVGFEImageElementImpl.h>
+#include <SVGPathSegCurvetoQuadraticImpl.h>
+#include <SVGClipPathElementImpl.h>
+
+using namespace KSVG;
+using namespace KJS;
+
+#include "ksvg_cacheimpl.h"
+
+// For all classes with generated data: the ClassInfo
+const DOM::DOMString SVGAElementImpl::s_tagName = "a";
+const ClassInfo SVGAElementImpl::s_classInfo = {"KSVG::SVGAElementImpl",0,&SVGAElementImpl::s_hashTable,0};
+const DOM::DOMString SVGAltGlyphDefElementImpl::s_tagName = "altGlyphDef";
+const ClassInfo SVGAltGlyphDefElementImpl::s_classInfo = {"KSVG::SVGAltGlyphDefElementImpl",0,0,0};
+const DOM::DOMString SVGAltGlyphElementImpl::s_tagName = "altGlyph";
+const ClassInfo SVGAltGlyphElementImpl::s_classInfo = {"KSVG::SVGAltGlyphElementImpl",0,0,0};
+const ClassInfo SVGAngleImpl::s_classInfo = {"KSVG::SVGAngleImpl",0,&SVGAngleImpl::s_hashTable,0};
+const ClassInfo SVGAngleImplConstructor::s_classInfo = {"KSVG::SVGAngleImplConstructor",0,&SVGAngleImplConstructor::s_hashTable,0};
+const DOM::DOMString SVGAnimateColorElementImpl::s_tagName = "animateColor";
+const ClassInfo SVGAnimateColorElementImpl::s_classInfo = {"KSVG::SVGAnimateColorElementImpl",0,0,0};
+const DOM::DOMString SVGAnimateElementImpl::s_tagName = "animate";
+const ClassInfo SVGAnimateElementImpl::s_classInfo = {"KSVG::SVGAnimateElementImpl",0,0,0};
+const DOM::DOMString SVGAnimateMotionElementImpl::s_tagName = "animateMotion";
+const ClassInfo SVGAnimateMotionElementImpl::s_classInfo = {"KSVG::SVGAnimateMotionElementImpl",0,0,0};
+const DOM::DOMString SVGAnimateTransformElementImpl::s_tagName = "animateTransform";
+const ClassInfo SVGAnimateTransformElementImpl::s_classInfo = {"KSVG::SVGAnimateTransformElementImpl",0,0,0};
+const ClassInfo SVGAnimatedAngleImpl::s_classInfo = {"KSVG::SVGAnimatedAngleImpl",0,&SVGAnimatedAngleImpl::s_hashTable,0};
+const ClassInfo SVGAnimatedBooleanImpl::s_classInfo = {"KSVG::SVGAnimatedBooleanImpl",0,&SVGAnimatedBooleanImpl::s_hashTable,0};
+const ClassInfo SVGAnimatedEnumerationImpl::s_classInfo = {"KSVG::SVGAnimatedEnumerationImpl",0,&SVGAnimatedEnumerationImpl::s_hashTable,0};
+const ClassInfo SVGAnimatedIntegerImpl::s_classInfo = {"KSVG::SVGAnimatedIntegerImpl",0,&SVGAnimatedIntegerImpl::s_hashTable,0};
+const ClassInfo SVGAnimatedLengthImpl::s_classInfo = {"KSVG::SVGAnimatedLengthImpl",0,&SVGAnimatedLengthImpl::s_hashTable,0};
+const ClassInfo SVGAnimatedLengthListImpl::s_classInfo = {"KSVG::SVGAnimatedLengthListImpl",0,&SVGAnimatedLengthListImpl::s_hashTable,0};
+const ClassInfo SVGAnimatedNumberImpl::s_classInfo = {"KSVG::SVGAnimatedNumberImpl",0,&SVGAnimatedNumberImpl::s_hashTable,0};
+const ClassInfo SVGAnimatedNumberListImpl::s_classInfo = {"KSVG::SVGAnimatedNumberListImpl",0,&SVGAnimatedNumberListImpl::s_hashTable,0};
+const ClassInfo SVGAnimatedPathDataImpl::s_classInfo = {"KSVG::SVGAnimatedPathDataImpl",0,&SVGAnimatedPathDataImpl::s_hashTable,0};
+const ClassInfo SVGAnimatedPointsImpl::s_classInfo = {"KSVG::SVGAnimatedPointsImpl",0,&SVGAnimatedPointsImpl::s_hashTable,0};
+const ClassInfo SVGAnimatedPreserveAspectRatioImpl::s_classInfo = {"KSVG::SVGAnimatedPreserveAspectRatioImpl",0,&SVGAnimatedPreserveAspectRatioImpl::s_hashTable,0};
+const ClassInfo SVGAnimatedRectImpl::s_classInfo = {"KSVG::SVGAnimatedRectImpl",0,&SVGAnimatedRectImpl::s_hashTable,0};
+const ClassInfo SVGAnimatedStringImpl::s_classInfo = {"KSVG::SVGAnimatedStringImpl",0,&SVGAnimatedStringImpl::s_hashTable,0};
+const ClassInfo SVGAnimatedTransformListImpl::s_classInfo = {"KSVG::SVGAnimatedTransformListImpl",0,&SVGAnimatedTransformListImpl::s_hashTable,0};
+const ClassInfo SVGAnimationElementImpl::s_classInfo = {"KSVG::SVGAnimationElementImpl",0,&SVGAnimationElementImpl::s_hashTable,0};
+const DOM::DOMString SVGCircleElementImpl::s_tagName = "circle";
+const ClassInfo SVGCircleElementImpl::s_classInfo = {"KSVG::SVGCircleElementImpl",0,&SVGCircleElementImpl::s_hashTable,0};
+const DOM::DOMString SVGClipPathElementImpl::s_tagName = "clipPath";
+const ClassInfo SVGClipPathElementImpl::s_classInfo = {"KSVG::SVGClipPathElementImpl",0,&SVGClipPathElementImpl::s_hashTable,0};
+const ClassInfo SVGColorImpl::s_classInfo = {"KSVG::SVGColorImpl",0,&SVGColorImpl::s_hashTable,0};
+const ClassInfo SVGColorImplConstructor::s_classInfo = {"KSVG::SVGColorImplConstructor",0,&SVGColorImplConstructor::s_hashTable,0};
+const DOM::DOMString SVGColorProfileElementImpl::s_tagName = "color-profile";
+const ClassInfo SVGColorProfileElementImpl::s_classInfo = {"KSVG::SVGColorProfileElementImpl",0,&SVGColorProfileElementImpl::s_hashTable,0};
+const ClassInfo SVGComponentTransferFunctionElementImpl::s_classInfo = {"KSVG::SVGComponentTransferFunctionElementImpl",0,0,0};
+const ClassInfo SVGContainerImpl::s_classInfo = {"KSVG::SVGContainerImpl",0,0,0};
+const ClassInfo SVGCursorElementImpl::s_classInfo = {"KSVG::SVGCursorElementImpl",0,&SVGCursorElementImpl::s_hashTable,0};
+const ClassInfo SVGDOMCharacterDataBridge::s_classInfo = {"KSVG::SVGDOMCharacterDataBridge",0,&SVGDOMCharacterDataBridge::s_hashTable,0};
+const ClassInfo SVGDOMDOMImplementationBridge::s_classInfo = {"KSVG::SVGDOMDOMImplementationBridge",0,&SVGDOMDOMImplementationBridge::s_hashTable,0};
+const ClassInfo SVGDOMDocumentFragmentBridge::s_classInfo = {"KSVG::SVGDOMDocumentFragmentBridge",0,&SVGDOMDocumentFragmentBridge::s_hashTable,0};
+const ClassInfo SVGDOMElementBridge::s_classInfo = {"KSVG::SVGDOMElementBridge",0,&SVGDOMElementBridge::s_hashTable,0};
+const ClassInfo SVGDOMNodeBridge::s_classInfo = {"KSVG::SVGDOMNodeBridge",0,&SVGDOMNodeBridge::s_hashTable,0};
+const ClassInfo SVGDOMNodeListBridge::s_classInfo = {"KSVG::SVGDOMNodeListBridge",0,&SVGDOMNodeListBridge::s_hashTable,0};
+const ClassInfo SVGDOMTextBridge::s_classInfo = {"KSVG::SVGDOMTextBridge",0,&SVGDOMTextBridge::s_hashTable,0};
+const ClassInfo SVGDefinitionSrcElementImpl::s_classInfo = {"KSVG::SVGDefinitionSrcElementImpl",0,0,0};
+const DOM::DOMString SVGDefsElementImpl::s_tagName = "defs";
+const ClassInfo SVGDefsElementImpl::s_classInfo = {"KSVG::SVGDefsElementImpl",0,0,0};
+const DOM::DOMString SVGDescElementImpl::s_tagName = "desc";
+const ClassInfo SVGDescElementImpl::s_classInfo = {"KSVG::SVGDescElementImpl",0,0,0};
+const ClassInfo SVGDocumentImpl::s_classInfo = {"KSVG::SVGDocumentImpl",0,&SVGDocumentImpl::s_hashTable,0};
+const ClassInfo SVGElementImpl::s_classInfo = {"KSVG::SVGElementImpl",0,&SVGElementImpl::s_hashTable,0};
+const DOM::DOMString SVGEllipseElementImpl::s_tagName = "ellipse";
+const ClassInfo SVGEllipseElementImpl::s_classInfo = {"KSVG::SVGEllipseElementImpl",0,&SVGEllipseElementImpl::s_hashTable,0};
+const ClassInfo SVGEventImpl::s_classInfo = {"KSVG::SVGEventImpl",0,&SVGEventImpl::s_hashTable,0};
+const ClassInfo SVGExternalResourcesRequiredImpl::s_classInfo = {"KSVG::SVGExternalResourcesRequiredImpl",0,&SVGExternalResourcesRequiredImpl::s_hashTable,0};
+const ClassInfo SVGFEBlendElementImpl::s_classInfo = {"KSVG::SVGFEBlendElementImpl",0,0,0};
+const ClassInfo SVGFEColorMatrixElementImpl::s_classInfo = {"KSVG::SVGFEColorMatrixElementImpl",0,0,0};
+const ClassInfo SVGFEComponentTransferElementImpl::s_classInfo = {"KSVG::SVGFEComponentTransferElementImpl",0,0,0};
+const ClassInfo SVGFECompositeElementImpl::s_classInfo = {"KSVG::SVGFECompositeElementImpl",0,0,0};
+const ClassInfo SVGFEConvolveMatrixElementImpl::s_classInfo = {"KSVG::SVGFEConvolveMatrixElementImpl",0,0,0};
+const ClassInfo SVGFEDiffuseLightingElementImpl::s_classInfo = {"KSVG::SVGFEDiffuseLightingElementImpl",0,0,0};
+const ClassInfo SVGFEDisplacementMapElementImpl::s_classInfo = {"KSVG::SVGFEDisplacementMapElementImpl",0,0,0};
+const ClassInfo SVGFEDistantLightElementImpl::s_classInfo = {"KSVG::SVGFEDistantLightElementImpl",0,0,0};
+const ClassInfo SVGFEFloodElementImpl::s_classInfo = {"KSVG::SVGFEFloodElementImpl",0,0,0};
+const ClassInfo SVGFEFuncAElementImpl::s_classInfo = {"KSVG::SVGFEFuncAElementImpl",0,0,0};
+const ClassInfo SVGFEFuncBElementImpl::s_classInfo = {"KSVG::SVGFEFuncBElementImpl",0,0,0};
+const ClassInfo SVGFEFuncGElementImpl::s_classInfo = {"KSVG::SVGFEFuncGElementImpl",0,0,0};
+const ClassInfo SVGFEFuncRElementImpl::s_classInfo = {"KSVG::SVGFEFuncRElementImpl",0,0,0};
+const ClassInfo SVGFEGaussianBlurElementImpl::s_classInfo = {"KSVG::SVGFEGaussianBlurElementImpl",0,0,0};
+const ClassInfo SVGFEImageElementImpl::s_classInfo = {"KSVG::SVGFEImageElementImpl",0,0,0};
+const ClassInfo SVGFEMergeElementImpl::s_classInfo = {"KSVG::SVGFEMergeElementImpl",0,0,0};
+const ClassInfo SVGFEMergeNodeElementImpl::s_classInfo = {"KSVG::SVGFEMergeNodeElementImpl",0,0,0};
+const ClassInfo SVGFEMorphologyElementImpl::s_classInfo = {"KSVG::SVGFEMorphologyElementImpl",0,0,0};
+const ClassInfo SVGFEOffsetElementImpl::s_classInfo = {"KSVG::SVGFEOffsetElementImpl",0,0,0};
+const ClassInfo SVGFEPointLightElementImpl::s_classInfo = {"KSVG::SVGFEPointLightElementImpl",0,0,0};
+const ClassInfo SVGFESpecularLightingElementImpl::s_classInfo = {"KSVG::SVGFESpecularLightingElementImpl",0,0,0};
+const ClassInfo SVGFESpotLightElementImpl::s_classInfo = {"KSVG::SVGFESpotLightElementImpl",0,0,0};
+const ClassInfo SVGFETileElementImpl::s_classInfo = {"KSVG::SVGFETileElementImpl",0,0,0};
+const ClassInfo SVGFETurbulenceElementImpl::s_classInfo = {"KSVG::SVGFETurbulenceElementImpl",0,0,0};
+const ClassInfo SVGFilterElementImpl::s_classInfo = {"KSVG::SVGFilterElementImpl",0,0,0};
+const ClassInfo SVGFitToViewBoxImpl::s_classInfo = {"KSVG::SVGFitToViewBoxImpl",0,&SVGFitToViewBoxImpl::s_hashTable,0};
+const ClassInfo SVGFontElementImpl::s_classInfo = {"KSVG::SVGFontElementImpl",0,0,0};
+const ClassInfo SVGFontFaceElementImpl::s_classInfo = {"KSVG::SVGFontFaceElementImpl",0,0,0};
+const ClassInfo SVGFontFaceFormatElementImpl::s_classInfo = {"KSVG::SVGFontFaceFormatElementImpl",0,0,0};
+const ClassInfo SVGFontFaceNameElementImpl::s_classInfo = {"KSVG::SVGFontFaceNameElementImpl",0,0,0};
+const ClassInfo SVGFontFaceSrcElementImpl::s_classInfo = {"KSVG::SVGFontFaceSrcElementImpl",0,0,0};
+const ClassInfo SVGFontFaceUriElementImpl::s_classInfo = {"KSVG::SVGFontFaceUriElementImpl",0,0,0};
+const ClassInfo SVGForeignObjectElementImpl::s_classInfo = {"KSVG::SVGForeignObjectElementImpl",0,&SVGForeignObjectElementImpl::s_hashTable,0};
+const DOM::DOMString SVGGElementImpl::s_tagName = "g";
+const ClassInfo SVGGElementImpl::s_classInfo = {"KSVG::SVGGElementImpl",0,0,0};
+const DOM::DOMString SVGGlyphElementImpl::s_tagName = "glyph";
+const ClassInfo SVGGlyphElementImpl::s_classInfo = {"KSVG::SVGGlyphElementImpl",0,&SVGGlyphElementImpl::s_hashTable,0};
+const DOM::DOMString SVGGlyphRefElementImpl::s_tagName = "glyphRef";
+const ClassInfo SVGGlyphRefElementImpl::s_classInfo = {"KSVG::SVGGlyphRefElementImpl",0,&SVGGlyphRefElementImpl::s_hashTable,0};
+const ClassInfo SVGGradientElementImpl::s_classInfo = {"KSVG::SVGGradientElementImpl",0,&SVGGradientElementImpl::s_hashTable,0};
+const ClassInfo SVGGradientElementImplConstructor::s_classInfo = {"KSVG::SVGGradientElementImplConstructor",0,&SVGGradientElementImplConstructor::s_hashTable,0};
+const ClassInfo SVGHKernElementImpl::s_classInfo = {"KSVG::SVGHKernElementImpl",0,0,0};
+const ClassInfo SVGICCColorImpl::s_classInfo = {"KSVG::SVGICCColorImpl",0,&SVGICCColorImpl::s_hashTable,0};
+const DOM::DOMString SVGImageElementImpl::s_tagName = "image";
+const ClassInfo SVGImageElementImpl::s_classInfo = {"KSVG::SVGImageElementImpl",0,&SVGImageElementImpl::s_hashTable,0};
+const ClassInfo SVGKeyEventImpl::s_classInfo = {"KSVG::SVGKeyEventImpl",0,&SVGKeyEventImpl::s_hashTable,0};
+const ClassInfo SVGLangSpaceImpl::s_classInfo = {"KSVG::SVGLangSpaceImpl",0,&SVGLangSpaceImpl::s_hashTable,0};
+const ClassInfo SVGLengthImpl::s_classInfo = {"KSVG::SVGLengthImpl",0,&SVGLengthImpl::s_hashTable,0};
+const ClassInfo SVGLengthImplConstructor::s_classInfo = {"KSVG::SVGLengthImplConstructor",0,&SVGLengthImplConstructor::s_hashTable,0};
+const ClassInfo SVGLengthListImpl::s_classInfo = {"KSVG::SVGLengthListImpl",0,&SVGLengthListImpl::s_hashTable,0};
+const DOM::DOMString SVGLineElementImpl::s_tagName = "line";
+const ClassInfo SVGLineElementImpl::s_classInfo = {"KSVG::SVGLineElementImpl",0,&SVGLineElementImpl::s_hashTable,0};
+const DOM::DOMString SVGLinearGradientElementImpl::s_tagName = "linearGradient";
+const ClassInfo SVGLinearGradientElementImpl::s_classInfo = {"KSVG::SVGLinearGradientElementImpl",0,&SVGLinearGradientElementImpl::s_hashTable,0};
+const ClassInfo SVGLocatableImpl::s_classInfo = {"KSVG::SVGLocatableImpl",0,&SVGLocatableImpl::s_hashTable,0};
+const ClassInfo SVGMPathElementImpl::s_classInfo = {"KSVG::SVGMPathElementImpl",0,0,0};
+const DOM::DOMString SVGMarkerElementImpl::s_tagName = "marker";
+const ClassInfo SVGMarkerElementImpl::s_classInfo = {"KSVG::SVGMarkerElementImpl",0,&SVGMarkerElementImpl::s_hashTable,0};
+const ClassInfo SVGMarkerElementImplConstructor::s_classInfo = {"KSVG::SVGMarkerElementImplConstructor",0,&SVGMarkerElementImplConstructor::s_hashTable,0};
+const DOM::DOMString SVGMaskElementImpl::s_tagName = "mask";
+const ClassInfo SVGMaskElementImpl::s_classInfo = {"KSVG::SVGMaskElementImpl",0,&SVGMaskElementImpl::s_hashTable,0};
+const ClassInfo SVGMatrixImpl::s_classInfo = {"KSVG::SVGMatrixImpl",0,&SVGMatrixImpl::s_hashTable,0};
+const ClassInfo SVGMetadataElementImpl::s_classInfo = {"KSVG::SVGMetadataElementImpl",0,0,0};
+const ClassInfo SVGMissingGlyphElementImpl::s_classInfo = {"KSVG::SVGMissingGlyphElementImpl",0,0,0};
+const ClassInfo SVGMouseEventImpl::s_classInfo = {"KSVG::SVGMouseEventImpl",0,&SVGMouseEventImpl::s_hashTable,0};
+const ClassInfo SVGMutationEventImpl::s_classInfo = {"KSVG::SVGMutationEventImpl",0,0,0};
+const ClassInfo SVGNumberImpl::s_classInfo = {"KSVG::SVGNumberImpl",0,&SVGNumberImpl::s_hashTable,0};
+const ClassInfo SVGNumberListImpl::s_classInfo = {"KSVG::SVGNumberListImpl",0,&SVGNumberListImpl::s_hashTable,0};
+const ClassInfo SVGPaintImpl::s_classInfo = {"KSVG::SVGPaintImpl",0,&SVGPaintImpl::s_hashTable,0};
+const ClassInfo SVGPaintImplConstructor::s_classInfo = {"KSVG::SVGPaintImplConstructor",0,&SVGPaintImplConstructor::s_hashTable,0};
+const DOM::DOMString SVGPathElementImpl::s_tagName = "path";
+const ClassInfo SVGPathElementImpl::s_classInfo = {"KSVG::SVGPathElementImpl",0,&SVGPathElementImpl::s_hashTable,0};
+const ClassInfo SVGPathSegArcAbsImpl::s_classInfo = {"KSVG::SVGPathSegArcAbsImpl",0,&SVGPathSegArcAbsImpl::s_hashTable,0};
+const ClassInfo SVGPathSegArcRelImpl::s_classInfo = {"KSVG::SVGPathSegArcRelImpl",0,&SVGPathSegArcRelImpl::s_hashTable,0};
+const ClassInfo SVGPathSegClosePathImpl::s_classInfo = {"KSVG::SVGPathSegClosePathImpl",0,0,0};
+const ClassInfo SVGPathSegCurvetoCubicAbsImpl::s_classInfo = {"KSVG::SVGPathSegCurvetoCubicAbsImpl",0,&SVGPathSegCurvetoCubicAbsImpl::s_hashTable,0};
+const ClassInfo SVGPathSegCurvetoCubicRelImpl::s_classInfo = {"KSVG::SVGPathSegCurvetoCubicRelImpl",0,&SVGPathSegCurvetoCubicRelImpl::s_hashTable,0};
+const ClassInfo SVGPathSegCurvetoCubicSmoothAbsImpl::s_classInfo = {"KSVG::SVGPathSegCurvetoCubicSmoothAbsImpl",0,&SVGPathSegCurvetoCubicSmoothAbsImpl::s_hashTable,0};
+const ClassInfo SVGPathSegCurvetoCubicSmoothRelImpl::s_classInfo = {"KSVG::SVGPathSegCurvetoCubicSmoothRelImpl",0,&SVGPathSegCurvetoCubicSmoothRelImpl::s_hashTable,0};
+const ClassInfo SVGPathSegCurvetoQuadraticAbsImpl::s_classInfo = {"KSVG::SVGPathSegCurvetoQuadraticAbsImpl",0,&SVGPathSegCurvetoQuadraticAbsImpl::s_hashTable,0};
+const ClassInfo SVGPathSegCurvetoQuadraticRelImpl::s_classInfo = {"KSVG::SVGPathSegCurvetoQuadraticRelImpl",0,&SVGPathSegCurvetoQuadraticRelImpl::s_hashTable,0};
+const ClassInfo SVGPathSegCurvetoQuadraticSmoothAbsImpl::s_classInfo = {"KSVG::SVGPathSegCurvetoQuadraticSmoothAbsImpl",0,&SVGPathSegCurvetoQuadraticSmoothAbsImpl::s_hashTable,0};
+const ClassInfo SVGPathSegCurvetoQuadraticSmoothRelImpl::s_classInfo = {"KSVG::SVGPathSegCurvetoQuadraticSmoothRelImpl",0,&SVGPathSegCurvetoQuadraticSmoothRelImpl::s_hashTable,0};
+const ClassInfo SVGPathSegImpl::s_classInfo = {"KSVG::SVGPathSegImpl",0,&SVGPathSegImpl::s_hashTable,0};
+const ClassInfo SVGPathSegImplConstructor::s_classInfo = {"KSVG::SVGPathSegImplConstructor",0,&SVGPathSegImplConstructor::s_hashTable,0};
+const ClassInfo SVGPathSegLinetoAbsImpl::s_classInfo = {"KSVG::SVGPathSegLinetoAbsImpl",0,&SVGPathSegLinetoAbsImpl::s_hashTable,0};
+const ClassInfo SVGPathSegLinetoHorizontalAbsImpl::s_classInfo = {"KSVG::SVGPathSegLinetoHorizontalAbsImpl",0,&SVGPathSegLinetoHorizontalAbsImpl::s_hashTable,0};
+const ClassInfo SVGPathSegLinetoHorizontalRelImpl::s_classInfo = {"KSVG::SVGPathSegLinetoHorizontalRelImpl",0,&SVGPathSegLinetoHorizontalRelImpl::s_hashTable,0};
+const ClassInfo SVGPathSegLinetoRelImpl::s_classInfo = {"KSVG::SVGPathSegLinetoRelImpl",0,&SVGPathSegLinetoRelImpl::s_hashTable,0};
+const ClassInfo SVGPathSegLinetoVerticalAbsImpl::s_classInfo = {"KSVG::SVGPathSegLinetoVerticalAbsImpl",0,&SVGPathSegLinetoVerticalAbsImpl::s_hashTable,0};
+const ClassInfo SVGPathSegLinetoVerticalRelImpl::s_classInfo = {"KSVG::SVGPathSegLinetoVerticalRelImpl",0,&SVGPathSegLinetoVerticalRelImpl::s_hashTable,0};
+const ClassInfo SVGPathSegListImpl::s_classInfo = {"KSVG::SVGPathSegListImpl",0,&SVGPathSegListImpl::s_hashTable,0};
+const ClassInfo SVGPathSegMovetoAbsImpl::s_classInfo = {"KSVG::SVGPathSegMovetoAbsImpl",0,&SVGPathSegMovetoAbsImpl::s_hashTable,0};
+const ClassInfo SVGPathSegMovetoRelImpl::s_classInfo = {"KSVG::SVGPathSegMovetoRelImpl",0,&SVGPathSegMovetoRelImpl::s_hashTable,0};
+const DOM::DOMString SVGPatternElementImpl::s_tagName = "pattern";
+const ClassInfo SVGPatternElementImpl::s_classInfo = {"KSVG::SVGPatternElementImpl",0,&SVGPatternElementImpl::s_hashTable,0};
+const ClassInfo SVGPointImpl::s_classInfo = {"KSVG::SVGPointImpl",0,&SVGPointImpl::s_hashTable,0};
+const ClassInfo SVGPointListImpl::s_classInfo = {"KSVG::SVGPointListImpl",0,&SVGPointListImpl::s_hashTable,0};
+const ClassInfo SVGPolyElementImpl::s_classInfo = {"KSVG::SVGPolyElementImpl",0,0,0};
+const DOM::DOMString SVGPolygonElementImpl::s_tagName = "polygon";
+const ClassInfo SVGPolygonElementImpl::s_classInfo = {"KSVG::SVGPolygonElementImpl",0,0,0};
+const DOM::DOMString SVGPolylineElementImpl::s_tagName = "polyline";
+const ClassInfo SVGPolylineElementImpl::s_classInfo = {"KSVG::SVGPolylineElementImpl",0,0,0};
+const ClassInfo SVGPreserveAspectRatioImpl::s_classInfo = {"KSVG::SVGPreserveAspectRatioImpl",0,&SVGPreserveAspectRatioImpl::s_hashTable,0};
+const ClassInfo SVGPreserveAspectRatioImplConstructor::s_classInfo = {"KSVG::SVGPreserveAspectRatioImplConstructor",0,&SVGPreserveAspectRatioImplConstructor::s_hashTable,0};
+const DOM::DOMString SVGRadialGradientElementImpl::s_tagName = "radialGradient";
+const ClassInfo SVGRadialGradientElementImpl::s_classInfo = {"KSVG::SVGRadialGradientElementImpl",0,&SVGRadialGradientElementImpl::s_hashTable,0};
+const DOM::DOMString SVGRectElementImpl::s_tagName = "rect";
+const ClassInfo SVGRectElementImpl::s_classInfo = {"KSVG::SVGRectElementImpl",0,&SVGRectElementImpl::s_hashTable,0};
+const ClassInfo SVGRectImpl::s_classInfo = {"KSVG::SVGRectImpl",0,&SVGRectImpl::s_hashTable,0};
+const DOM::DOMString SVGSVGElementImpl::s_tagName = "svg";
+const ClassInfo SVGSVGElementImpl::s_classInfo = {"KSVG::SVGSVGElementImpl",0,&SVGSVGElementImpl::s_hashTable,0};
+const DOM::DOMString SVGScriptElementImpl::s_tagName = "script";
+const ClassInfo SVGScriptElementImpl::s_classInfo = {"KSVG::SVGScriptElementImpl",0,&SVGScriptElementImpl::s_hashTable,0};
+const DOM::DOMString SVGSetElementImpl::s_tagName = "set";
+const ClassInfo SVGSetElementImpl::s_classInfo = {"KSVG::SVGSetElementImpl",0,0,0};
+const ClassInfo SVGShapeImpl::s_classInfo = {"KSVG::SVGShapeImpl",0,0,0};
+const DOM::DOMString SVGStopElementImpl::s_tagName = "stop";
+const ClassInfo SVGStopElementImpl::s_classInfo = {"KSVG::SVGStopElementImpl",0,&SVGStopElementImpl::s_hashTable,0};
+const ClassInfo SVGStringListImpl::s_classInfo = {"KSVG::SVGStringListImpl",0,&SVGStringListImpl::s_hashTable,0};
+const ClassInfo SVGStylableImpl::s_classInfo = {"KSVG::SVGStylableImpl",0,&SVGStylableImpl::s_hashTable,0};
+const DOM::DOMString SVGStyleElementImpl::s_tagName = "style";
+const ClassInfo SVGStyleElementImpl::s_classInfo = {"KSVG::SVGStyleElementImpl",0,&SVGStyleElementImpl::s_hashTable,0};
+const DOM::DOMString SVGSwitchElementImpl::s_tagName = "switch";
+const ClassInfo SVGSwitchElementImpl::s_classInfo = {"KSVG::SVGSwitchElementImpl",0,0,0};
+const DOM::DOMString SVGSymbolElementImpl::s_tagName = "symbol";
+const ClassInfo SVGSymbolElementImpl::s_classInfo = {"KSVG::SVGSymbolElementImpl",0,&SVGSymbolElementImpl::s_hashTable,0};
+const DOM::DOMString SVGTRefElementImpl::s_tagName = "tref";
+const ClassInfo SVGTRefElementImpl::s_classInfo = {"KSVG::SVGTRefElementImpl",0,0,0};
+const DOM::DOMString SVGTSpanElementImpl::s_tagName = "tspan";
+const ClassInfo SVGTSpanElementImpl::s_classInfo = {"KSVG::SVGTSpanElementImpl",0,0,0};
+const ClassInfo SVGTestsImpl::s_classInfo = {"KSVG::SVGTestsImpl",0,&SVGTestsImpl::s_hashTable,0};
+const ClassInfo SVGTextContentElementImpl::s_classInfo = {"KSVG::SVGTextContentElementImpl",0,&SVGTextContentElementImpl::s_hashTable,0};
+const ClassInfo SVGTextContentElementImplConstructor::s_classInfo = {"KSVG::SVGTextContentElementImplConstructor",0,&SVGTextContentElementImplConstructor::s_hashTable,0};
+const DOM::DOMString SVGTextElementImpl::s_tagName = "text";
+const ClassInfo SVGTextElementImpl::s_classInfo = {"KSVG::SVGTextElementImpl",0,0,0};
+const DOM::DOMString SVGTextPathElementImpl::s_tagName = "textPath";
+const ClassInfo SVGTextPathElementImpl::s_classInfo = {"KSVG::SVGTextPathElementImpl",0,&SVGTextPathElementImpl::s_hashTable,0};
+const ClassInfo SVGTextPathElementImplConstructor::s_classInfo = {"KSVG::SVGTextPathElementImplConstructor",0,&SVGTextPathElementImplConstructor::s_hashTable,0};
+const ClassInfo SVGTextPositioningElementImpl::s_classInfo = {"KSVG::SVGTextPositioningElementImpl",0,&SVGTextPositioningElementImpl::s_hashTable,0};
+const DOM::DOMString SVGTitleElementImpl::s_tagName = "title";
+const ClassInfo SVGTitleElementImpl::s_classInfo = {"KSVG::SVGTitleElementImpl",0,0,0};
+const ClassInfo SVGTransformImpl::s_classInfo = {"KSVG::SVGTransformImpl",0,&SVGTransformImpl::s_hashTable,0};
+const ClassInfo SVGTransformImplConstructor::s_classInfo = {"KSVG::SVGTransformImplConstructor",0,&SVGTransformImplConstructor::s_hashTable,0};
+const ClassInfo SVGTransformListImpl::s_classInfo = {"KSVG::SVGTransformListImpl",0,&SVGTransformListImpl::s_hashTable,0};
+const ClassInfo SVGTransformableImpl::s_classInfo = {"KSVG::SVGTransformableImpl",0,&SVGTransformableImpl::s_hashTable,0};
+const ClassInfo SVGUIEventImpl::s_classInfo = {"KSVG::SVGUIEventImpl",0,&SVGUIEventImpl::s_hashTable,0};
+const ClassInfo SVGURIReferenceImpl::s_classInfo = {"KSVG::SVGURIReferenceImpl",0,&SVGURIReferenceImpl::s_hashTable,0};
+const DOM::DOMString SVGUseElementImpl::s_tagName = "use";
+const ClassInfo SVGUseElementImpl::s_classInfo = {"KSVG::SVGUseElementImpl",0,&SVGUseElementImpl::s_hashTable,0};
+const ClassInfo SVGVKernElementImpl::s_classInfo = {"KSVG::SVGVKernElementImpl",0,0,0};
+const DOM::DOMString SVGViewElementImpl::s_tagName = "view";
+const ClassInfo SVGViewElementImpl::s_classInfo = {"KSVG::SVGViewElementImpl",0,&SVGViewElementImpl::s_hashTable,0};
+const ClassInfo SVGViewSpecImpl::s_classInfo = {"KSVG::SVGViewSpecImpl",0,0,0};
+const ClassInfo SVGZoomAndPanImpl::s_classInfo = {"KSVG::SVGZoomAndPanImpl",0,&SVGZoomAndPanImpl::s_hashTable,0};
+const ClassInfo SVGZoomAndPanImplConstructor::s_classInfo = {"KSVG::SVGZoomAndPanImplConstructor",0,&SVGZoomAndPanImplConstructor::s_hashTable,0};
+const ClassInfo SVGZoomEventImpl::s_classInfo = {"KSVG::SVGZoomEventImpl",0,&SVGZoomEventImpl::s_hashTable,0};
+const ClassInfo SharedString::s_classInfo = {"KSVG::SharedString",0,&SharedString::s_hashTable,0};
+
+bool SVGAElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGAElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGContainerImpl::hasProperty(p1,p2)) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ if(SVGTestsImpl::hasProperty(p1,p2)) return true;
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return true;
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGAElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGAElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGAElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGContainerImpl::hasProperty(p1,p2)) return SVGContainerImpl::get(p1,p2,p3);
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3);
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3);
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGAElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGAElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGAElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGContainerImpl::hasProperty(p1,p2)) {
+ SVGContainerImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) {
+ SVGLangSpaceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTestsImpl::hasProperty(p1,p2)) {
+ SVGTestsImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTransformableImpl::hasProperty(p1,p2)) {
+ SVGTransformableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) {
+ SVGURIReferenceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGAElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGAElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGAElementImpl>(p1,const_cast<SVGAElementImpl *>(this));
+}
+
+Value SVGAElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGAElementImpl,KSVGRWBridge<SVGAElementImpl> >(p1,const_cast<SVGAElementImpl *>(this)));
+}
+
+bool SVGAltGlyphDefElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGAltGlyphDefElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGAltGlyphDefElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGAltGlyphDefElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGAltGlyphDefElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGAltGlyphDefElementImpl>(p1,const_cast<SVGAltGlyphDefElementImpl *>(this));
+}
+
+Value SVGAltGlyphDefElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGAltGlyphDefElementImpl,KSVGRWBridge<SVGAltGlyphDefElementImpl> >(p1,const_cast<SVGAltGlyphDefElementImpl *>(this)));
+}
+
+bool SVGAltGlyphElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGTSpanElementImpl::hasProperty(p1,p2)) return true;
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGAltGlyphElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGTSpanElementImpl::hasProperty(p1,p2)) return SVGTSpanElementImpl::get(p1,p2,p3);
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGAltGlyphElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGTSpanElementImpl::hasProperty(p1,p2)) {
+ SVGTSpanElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) {
+ SVGURIReferenceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGAltGlyphElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGAltGlyphElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGAltGlyphElementImpl>(p1,const_cast<SVGAltGlyphElementImpl *>(this));
+}
+
+Value SVGAltGlyphElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGAltGlyphElementImpl,KSVGRWBridge<SVGAltGlyphElementImpl> >(p1,const_cast<SVGAltGlyphElementImpl *>(this)));
+}
+
+bool SVGAngleImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGAngleImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGAngleImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGAngleImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGAngleImplProtoFunc,SVGAngleImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGAngleImpl *SVGAngleImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGAngleImpl> *test = dynamic_cast<const KSVGBridge<SVGAngleImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGAngleImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGAngleImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ Q_UNUSED(p3);
+ return Undefined();
+}
+
+bool SVGAngleImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGAngleImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGAngleImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGAngleImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGAngleImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGAngleImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGAngleImpl,KSVGRWBridge<SVGAngleImpl> >(p1,const_cast<SVGAngleImpl *>(this)));
+}
+
+bool SVGAngleImplConstructor::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGAngleImplConstructor::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGAngleImplConstructor::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGAngleImplConstructor>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGAngleImplConstructor::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGAngleImplConstructor::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGAngleImplConstructor::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGAngleImplConstructor,KSVGBridge<SVGAngleImplConstructor> >(p1,const_cast<SVGAngleImplConstructor *>(this)));
+}
+
+bool SVGAnimateColorElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGAnimationElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGAnimateColorElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGAnimationElementImpl::hasProperty(p1,p2)) return SVGAnimationElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGAnimateColorElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGAnimationElementImpl::hasProperty(p1,p2)) {
+ SVGAnimationElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGAnimateColorElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGAnimateColorElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGAnimateColorElementImpl>(p1,const_cast<SVGAnimateColorElementImpl *>(this));
+}
+
+Value SVGAnimateColorElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGAnimateColorElementImpl,KSVGRWBridge<SVGAnimateColorElementImpl> >(p1,const_cast<SVGAnimateColorElementImpl *>(this)));
+}
+
+bool SVGAnimateElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGAnimationElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGAnimateElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGAnimationElementImpl::hasProperty(p1,p2)) return SVGAnimationElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGAnimateElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGAnimationElementImpl::hasProperty(p1,p2)) {
+ SVGAnimationElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGAnimateElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGAnimateElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGAnimateElementImpl>(p1,const_cast<SVGAnimateElementImpl *>(this));
+}
+
+Value SVGAnimateElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGAnimateElementImpl,KSVGRWBridge<SVGAnimateElementImpl> >(p1,const_cast<SVGAnimateElementImpl *>(this)));
+}
+
+bool SVGAnimateMotionElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGAnimationElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGAnimateMotionElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGAnimationElementImpl::hasProperty(p1,p2)) return SVGAnimationElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGAnimateMotionElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGAnimationElementImpl::hasProperty(p1,p2)) {
+ SVGAnimationElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGAnimateMotionElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGAnimateMotionElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGAnimateMotionElementImpl>(p1,const_cast<SVGAnimateMotionElementImpl *>(this));
+}
+
+Value SVGAnimateMotionElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGAnimateMotionElementImpl,KSVGRWBridge<SVGAnimateMotionElementImpl> >(p1,const_cast<SVGAnimateMotionElementImpl *>(this)));
+}
+
+bool SVGAnimateTransformElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGAnimationElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGAnimateTransformElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGAnimationElementImpl::hasProperty(p1,p2)) return SVGAnimationElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGAnimateTransformElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGAnimationElementImpl::hasProperty(p1,p2)) {
+ SVGAnimationElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGAnimateTransformElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGAnimateTransformElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGAnimateTransformElementImpl>(p1,const_cast<SVGAnimateTransformElementImpl *>(this));
+}
+
+Value SVGAnimateTransformElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGAnimateTransformElementImpl,KSVGRWBridge<SVGAnimateTransformElementImpl> >(p1,const_cast<SVGAnimateTransformElementImpl *>(this)));
+}
+
+bool SVGAnimatedAngleImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGAnimatedAngleImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGAnimatedAngleImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGAnimatedAngleImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGAnimatedAngleImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGAnimatedAngleImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGAnimatedAngleImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGAnimatedAngleImpl,KSVGBridge<SVGAnimatedAngleImpl> >(p1,const_cast<SVGAnimatedAngleImpl *>(this)));
+}
+
+bool SVGAnimatedBooleanImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGAnimatedBooleanImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGAnimatedBooleanImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGAnimatedBooleanImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGAnimatedBooleanImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+bool SVGAnimatedBooleanImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGAnimatedBooleanImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGAnimatedBooleanImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGAnimatedBooleanImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGAnimatedBooleanImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGAnimatedBooleanImpl,KSVGRWBridge<SVGAnimatedBooleanImpl> >(p1,const_cast<SVGAnimatedBooleanImpl *>(this)));
+}
+
+bool SVGAnimatedEnumerationImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGAnimatedEnumerationImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGAnimatedEnumerationImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGAnimatedEnumerationImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGAnimatedEnumerationImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+bool SVGAnimatedEnumerationImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGAnimatedEnumerationImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGAnimatedEnumerationImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGAnimatedEnumerationImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGAnimatedEnumerationImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGAnimatedEnumerationImpl,KSVGRWBridge<SVGAnimatedEnumerationImpl> >(p1,const_cast<SVGAnimatedEnumerationImpl *>(this)));
+}
+
+bool SVGAnimatedIntegerImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGAnimatedIntegerImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGAnimatedIntegerImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGAnimatedIntegerImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGAnimatedIntegerImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+bool SVGAnimatedIntegerImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGAnimatedIntegerImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGAnimatedIntegerImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGAnimatedIntegerImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGAnimatedIntegerImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGAnimatedIntegerImpl,KSVGRWBridge<SVGAnimatedIntegerImpl> >(p1,const_cast<SVGAnimatedIntegerImpl *>(this)));
+}
+
+bool SVGAnimatedLengthImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGAnimatedLengthImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGAnimatedLengthImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGAnimatedLengthImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGAnimatedLengthImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGAnimatedLengthImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGAnimatedLengthImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGAnimatedLengthImpl,KSVGBridge<SVGAnimatedLengthImpl> >(p1,const_cast<SVGAnimatedLengthImpl *>(this)));
+}
+
+bool SVGAnimatedLengthListImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGAnimatedLengthListImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGAnimatedLengthListImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGAnimatedLengthListImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGAnimatedLengthListImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGAnimatedLengthListImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGAnimatedLengthListImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGAnimatedLengthListImpl,KSVGBridge<SVGAnimatedLengthListImpl> >(p1,const_cast<SVGAnimatedLengthListImpl *>(this)));
+}
+
+bool SVGAnimatedNumberImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGAnimatedNumberImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGAnimatedNumberImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGAnimatedNumberImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGAnimatedNumberImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+bool SVGAnimatedNumberImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGAnimatedNumberImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGAnimatedNumberImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGAnimatedNumberImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGAnimatedNumberImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGAnimatedNumberImpl,KSVGRWBridge<SVGAnimatedNumberImpl> >(p1,const_cast<SVGAnimatedNumberImpl *>(this)));
+}
+
+bool SVGAnimatedNumberListImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGAnimatedNumberListImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGAnimatedNumberListImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGAnimatedNumberListImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGAnimatedNumberListImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGAnimatedNumberListImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGAnimatedNumberListImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGAnimatedNumberListImpl,KSVGBridge<SVGAnimatedNumberListImpl> >(p1,const_cast<SVGAnimatedNumberListImpl *>(this)));
+}
+
+bool SVGAnimatedPathDataImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGAnimatedPathDataImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGAnimatedPathDataImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGAnimatedPathDataImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGAnimatedPathDataImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGAnimatedPathDataImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGAnimatedPathDataImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGAnimatedPathDataImpl,KSVGBridge<SVGAnimatedPathDataImpl> >(p1,const_cast<SVGAnimatedPathDataImpl *>(this)));
+}
+
+bool SVGAnimatedPointsImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGAnimatedPointsImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGAnimatedPointsImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGAnimatedPointsImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGAnimatedPointsImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+bool SVGAnimatedPointsImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGAnimatedPointsImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGAnimatedPointsImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGAnimatedPointsImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGAnimatedPointsImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGAnimatedPointsImpl,KSVGRWBridge<SVGAnimatedPointsImpl> >(p1,const_cast<SVGAnimatedPointsImpl *>(this)));
+}
+
+bool SVGAnimatedPreserveAspectRatioImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGAnimatedPreserveAspectRatioImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGAnimatedPreserveAspectRatioImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGAnimatedPreserveAspectRatioImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGAnimatedPreserveAspectRatioImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGAnimatedPreserveAspectRatioImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGAnimatedPreserveAspectRatioImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGAnimatedPreserveAspectRatioImpl,KSVGBridge<SVGAnimatedPreserveAspectRatioImpl> >(p1,const_cast<SVGAnimatedPreserveAspectRatioImpl *>(this)));
+}
+
+bool SVGAnimatedRectImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGAnimatedRectImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGAnimatedRectImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGAnimatedRectImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGAnimatedRectImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGAnimatedRectImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGAnimatedRectImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGAnimatedRectImpl,KSVGBridge<SVGAnimatedRectImpl> >(p1,const_cast<SVGAnimatedRectImpl *>(this)));
+}
+
+bool SVGAnimatedStringImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGAnimatedStringImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGAnimatedStringImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGAnimatedStringImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGAnimatedStringImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+bool SVGAnimatedStringImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGAnimatedStringImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGAnimatedStringImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGAnimatedStringImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGAnimatedStringImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGAnimatedStringImpl,KSVGRWBridge<SVGAnimatedStringImpl> >(p1,const_cast<SVGAnimatedStringImpl *>(this)));
+}
+
+bool SVGAnimatedTransformListImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGAnimatedTransformListImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGAnimatedTransformListImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGAnimatedTransformListImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGAnimatedTransformListImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGAnimatedTransformListImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGAnimatedTransformListImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGAnimatedTransformListImpl,KSVGBridge<SVGAnimatedTransformListImpl> >(p1,const_cast<SVGAnimatedTransformListImpl *>(this)));
+}
+
+bool SVGAnimationElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGAnimationElementImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGAnimationElementImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGTestsImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGAnimationElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGAnimationElementImplProtoFunc,SVGAnimationElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGAnimationElementImpl *SVGAnimationElementImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGAnimationElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimationElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAnimateColorElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimateColorElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAnimateElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimateElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAnimateMotionElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimateMotionElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAnimateTransformElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimateTransformElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGSetElementImpl> *test = dynamic_cast<const KSVGBridge<SVGSetElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGAnimationElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGAnimationElementImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGAnimationElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGAnimationElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGAnimationElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTestsImpl::hasProperty(p1,p2)) {
+ SVGTestsImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGAnimationElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGAnimationElementImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGAnimationElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGAnimationElementImpl,KSVGRWBridge<SVGAnimationElementImpl> >(p1,const_cast<SVGAnimationElementImpl *>(this)));
+}
+
+bool SVGCircleElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGCircleElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true;
+ if(SVGShapeImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ if(SVGTestsImpl::hasProperty(p1,p2)) return true;
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGCircleElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGCircleElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGCircleElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3);
+ if(SVGShapeImpl::hasProperty(p1,p2)) return SVGShapeImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3);
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGCircleElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGCircleElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGCircleElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) {
+ SVGLangSpaceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGShapeImpl::hasProperty(p1,p2)) {
+ SVGShapeImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTestsImpl::hasProperty(p1,p2)) {
+ SVGTestsImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTransformableImpl::hasProperty(p1,p2)) {
+ SVGTransformableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGCircleElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGCircleElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGCircleElementImpl>(p1,const_cast<SVGCircleElementImpl *>(this));
+}
+
+Value SVGCircleElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGCircleElementImpl,KSVGRWBridge<SVGCircleElementImpl> >(p1,const_cast<SVGCircleElementImpl *>(this)));
+}
+
+bool SVGClipPathElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGClipPathElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGContainerImpl::hasProperty(p1,p2)) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ if(SVGTestsImpl::hasProperty(p1,p2)) return true;
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGClipPathElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGClipPathElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGClipPathElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGContainerImpl::hasProperty(p1,p2)) return SVGContainerImpl::get(p1,p2,p3);
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3);
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGClipPathElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGClipPathElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGClipPathElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGContainerImpl::hasProperty(p1,p2)) {
+ SVGContainerImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) {
+ SVGLangSpaceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTestsImpl::hasProperty(p1,p2)) {
+ SVGTestsImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTransformableImpl::hasProperty(p1,p2)) {
+ SVGTransformableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGClipPathElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGClipPathElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGClipPathElementImpl>(p1,const_cast<SVGClipPathElementImpl *>(this));
+}
+
+Value SVGClipPathElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGClipPathElementImpl,KSVGRWBridge<SVGClipPathElementImpl> >(p1,const_cast<SVGClipPathElementImpl *>(this)));
+}
+
+bool SVGColorImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGColorImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGColorImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGColorImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGColorImplProtoFunc,SVGColorImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGColorImpl *SVGColorImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGColorImpl> *test = dynamic_cast<const KSVGBridge<SVGColorImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPaintImpl> *test = dynamic_cast<const KSVGBridge<SVGPaintImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGColorImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGColorImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGColorImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGColorImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGColorImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGColorImpl,KSVGBridge<SVGColorImpl> >(p1,const_cast<SVGColorImpl *>(this)));
+}
+
+bool SVGColorImplConstructor::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGColorImplConstructor::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGColorImplConstructor::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGColorImplConstructor>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGColorImplConstructor::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGColorImplConstructor::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGColorImplConstructor::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGColorImplConstructor,KSVGBridge<SVGColorImplConstructor> >(p1,const_cast<SVGColorImplConstructor *>(this)));
+}
+
+bool SVGColorProfileElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGColorProfileElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGColorProfileElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGColorProfileElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGColorProfileElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGColorProfileElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGColorProfileElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGColorProfileElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) {
+ SVGURIReferenceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGColorProfileElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGColorProfileElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGColorProfileElementImpl>(p1,const_cast<SVGColorProfileElementImpl *>(this));
+}
+
+Value SVGColorProfileElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGColorProfileElementImpl,KSVGRWBridge<SVGColorProfileElementImpl> >(p1,const_cast<SVGColorProfileElementImpl *>(this)));
+}
+
+bool SVGComponentTransferFunctionElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGComponentTransferFunctionElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGComponentTransferFunctionElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGComponentTransferFunctionElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGComponentTransferFunctionElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGComponentTransferFunctionElementImpl,KSVGRWBridge<SVGComponentTransferFunctionElementImpl> >(p1,const_cast<SVGComponentTransferFunctionElementImpl *>(this)));
+}
+
+bool SVGContainerImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGShapeImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGContainerImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGShapeImpl::hasProperty(p1,p2)) return SVGShapeImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGContainerImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGShapeImpl::hasProperty(p1,p2)) {
+ SVGShapeImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGContainerImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGContainerImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGContainerImpl,KSVGRWBridge<SVGContainerImpl> >(p1,const_cast<SVGContainerImpl *>(this)));
+}
+
+bool SVGCursorElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGCursorElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGTestsImpl::hasProperty(p1,p2)) return true;
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGCursorElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGCursorElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGCursorElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3);
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGCursorElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGCursorElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGCursorElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTestsImpl::hasProperty(p1,p2)) {
+ SVGTestsImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) {
+ SVGURIReferenceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGCursorElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGCursorElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGCursorElementImpl,KSVGRWBridge<SVGCursorElementImpl> >(p1,const_cast<SVGCursorElementImpl *>(this)));
+}
+
+bool SVGDOMCharacterDataBridge::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGDOMCharacterDataBridge::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGDOMCharacterDataBridgeProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ if(SVGDOMNodeBridge::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGDOMCharacterDataBridge::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGDOMCharacterDataBridgeProtoFunc,SVGDOMCharacterDataBridge>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGDOMCharacterDataBridge *SVGDOMCharacterDataBridgeProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGDOMCharacterDataBridge> *test = dynamic_cast<const KSVGBridge<SVGDOMCharacterDataBridge> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGDOMTextBridge> *test = dynamic_cast<const KSVGBridge<SVGDOMTextBridge> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGDOMCharacterDataBridge::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGDOMCharacterDataBridgeProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ if(SVGDOMNodeBridge::hasProperty(p1,p2)) return SVGDOMNodeBridge::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGDOMCharacterDataBridge::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGDOMCharacterDataBridge>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGDOMCharacterDataBridge::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGDOMNodeBridge::hasProperty(p1,p2)) {
+ SVGDOMNodeBridge::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGDOMCharacterDataBridge::prototype(ExecState *p1) const
+{
+ if(p1) return SVGDOMCharacterDataBridgeProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGDOMCharacterDataBridge::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGDOMCharacterDataBridge,KSVGRWBridge<SVGDOMCharacterDataBridge> >(p1,const_cast<SVGDOMCharacterDataBridge *>(this)));
+}
+
+bool SVGDOMDOMImplementationBridge::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGDOMDOMImplementationBridge::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGDOMDOMImplementationBridgeProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGDOMDOMImplementationBridge::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGDOMDOMImplementationBridgeProtoFunc,SVGDOMDOMImplementationBridge>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGDOMDOMImplementationBridge *SVGDOMDOMImplementationBridgeProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGDOMDOMImplementationBridge> *test = dynamic_cast<const KSVGBridge<SVGDOMDOMImplementationBridge> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGDOMDOMImplementationBridge::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGDOMDOMImplementationBridgeProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ Q_UNUSED(p3);
+ return Undefined();
+}
+
+bool SVGDOMDOMImplementationBridge::put(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGDOMDOMImplementationBridge::prototype(ExecState *p1) const
+{
+ if(p1) return SVGDOMDOMImplementationBridgeProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGDOMDOMImplementationBridge::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGDOMDOMImplementationBridge,KSVGRWBridge<SVGDOMDOMImplementationBridge> >(p1,const_cast<SVGDOMDOMImplementationBridge *>(this)));
+}
+
+bool SVGDOMDocumentFragmentBridge::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGDOMDocumentFragmentBridge::s_hashTable,p2);
+ if(e) return true;
+ if(SVGDOMNodeBridge::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGDOMDocumentFragmentBridge::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGDOMDocumentFragmentBridge>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGDOMDocumentFragmentBridge::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGDOMNodeBridge::hasProperty(p1,p2)) return SVGDOMNodeBridge::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGDOMDocumentFragmentBridge::put(PUT_METHOD_ARGS)
+{
+ if(SVGDOMNodeBridge::hasProperty(p1,p2)) {
+ SVGDOMNodeBridge::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGDOMDocumentFragmentBridge::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGDOMDocumentFragmentBridge::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGDOMDocumentFragmentBridge,KSVGRWBridge<SVGDOMDocumentFragmentBridge> >(p1,const_cast<SVGDOMDocumentFragmentBridge *>(this)));
+}
+
+bool SVGDOMElementBridge::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGDOMElementBridge::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGDOMElementBridgeProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ if(SVGDOMNodeBridge::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGDOMElementBridge::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGDOMElementBridgeProtoFunc,SVGDOMElementBridge>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGDOMElementBridge *SVGDOMElementBridgeProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGDOMElementBridge> *test = dynamic_cast<const KSVGBridge<SVGDOMElementBridge> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAltGlyphDefElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAltGlyphDefElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAltGlyphElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAltGlyphElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAnimateColorElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimateColorElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAnimateElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimateElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAnimateMotionElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimateMotionElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAnimateTransformElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimateTransformElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAnimationElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimationElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGCircleElementImpl> *test = dynamic_cast<const KSVGBridge<SVGCircleElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGClipPathElementImpl> *test = dynamic_cast<const KSVGBridge<SVGClipPathElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGColorProfileElementImpl> *test = dynamic_cast<const KSVGBridge<SVGColorProfileElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGComponentTransferFunctionElementImpl> *test = dynamic_cast<const KSVGBridge<SVGComponentTransferFunctionElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGContainerImpl> *test = dynamic_cast<const KSVGBridge<SVGContainerImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGCursorElementImpl> *test = dynamic_cast<const KSVGBridge<SVGCursorElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGDefinitionSrcElementImpl> *test = dynamic_cast<const KSVGBridge<SVGDefinitionSrcElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGDefsElementImpl> *test = dynamic_cast<const KSVGBridge<SVGDefsElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGDescElementImpl> *test = dynamic_cast<const KSVGBridge<SVGDescElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGElementImpl> *test = dynamic_cast<const KSVGBridge<SVGElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGEllipseElementImpl> *test = dynamic_cast<const KSVGBridge<SVGEllipseElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEBlendElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEBlendElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEColorMatrixElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEColorMatrixElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEComponentTransferElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEComponentTransferElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFECompositeElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFECompositeElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEConvolveMatrixElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEConvolveMatrixElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEDiffuseLightingElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEDiffuseLightingElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEDisplacementMapElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEDisplacementMapElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEDistantLightElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEDistantLightElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEFloodElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEFloodElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEFuncAElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEFuncAElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEFuncBElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEFuncBElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEFuncGElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEFuncGElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEFuncRElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEFuncRElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEGaussianBlurElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEGaussianBlurElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEImageElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEImageElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEMergeElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEMergeElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEMergeNodeElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEMergeNodeElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEMorphologyElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEMorphologyElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEOffsetElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEOffsetElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEPointLightElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEPointLightElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFESpecularLightingElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFESpecularLightingElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFESpotLightElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFESpotLightElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFETileElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFETileElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFETurbulenceElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFETurbulenceElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFilterElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFilterElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFontElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFontElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFontFaceElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFontFaceElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFontFaceFormatElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFontFaceFormatElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFontFaceNameElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFontFaceNameElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFontFaceSrcElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFontFaceSrcElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFontFaceUriElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFontFaceUriElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGForeignObjectElementImpl> *test = dynamic_cast<const KSVGBridge<SVGForeignObjectElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGGElementImpl> *test = dynamic_cast<const KSVGBridge<SVGGElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGGlyphElementImpl> *test = dynamic_cast<const KSVGBridge<SVGGlyphElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGGlyphRefElementImpl> *test = dynamic_cast<const KSVGBridge<SVGGlyphRefElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGGradientElementImpl> *test = dynamic_cast<const KSVGBridge<SVGGradientElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGHKernElementImpl> *test = dynamic_cast<const KSVGBridge<SVGHKernElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGImageElementImpl> *test = dynamic_cast<const KSVGBridge<SVGImageElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGLineElementImpl> *test = dynamic_cast<const KSVGBridge<SVGLineElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGLinearGradientElementImpl> *test = dynamic_cast<const KSVGBridge<SVGLinearGradientElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGMPathElementImpl> *test = dynamic_cast<const KSVGBridge<SVGMPathElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGMarkerElementImpl> *test = dynamic_cast<const KSVGBridge<SVGMarkerElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGMaskElementImpl> *test = dynamic_cast<const KSVGBridge<SVGMaskElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGMetadataElementImpl> *test = dynamic_cast<const KSVGBridge<SVGMetadataElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGMissingGlyphElementImpl> *test = dynamic_cast<const KSVGBridge<SVGMissingGlyphElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPathElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPathElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPatternElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPatternElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPolyElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPolyElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPolygonElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPolygonElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPolylineElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPolylineElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGRadialGradientElementImpl> *test = dynamic_cast<const KSVGBridge<SVGRadialGradientElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGRectElementImpl> *test = dynamic_cast<const KSVGBridge<SVGRectElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGSVGElementImpl> *test = dynamic_cast<const KSVGBridge<SVGSVGElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGScriptElementImpl> *test = dynamic_cast<const KSVGBridge<SVGScriptElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGSetElementImpl> *test = dynamic_cast<const KSVGBridge<SVGSetElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGShapeImpl> *test = dynamic_cast<const KSVGBridge<SVGShapeImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGStopElementImpl> *test = dynamic_cast<const KSVGBridge<SVGStopElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGStyleElementImpl> *test = dynamic_cast<const KSVGBridge<SVGStyleElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGSwitchElementImpl> *test = dynamic_cast<const KSVGBridge<SVGSwitchElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGSymbolElementImpl> *test = dynamic_cast<const KSVGBridge<SVGSymbolElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTRefElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTRefElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTSpanElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTSpanElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTextContentElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextContentElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTextElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTextPathElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextPathElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTextPositioningElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextPositioningElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTitleElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTitleElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGUseElementImpl> *test = dynamic_cast<const KSVGBridge<SVGUseElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGVKernElementImpl> *test = dynamic_cast<const KSVGBridge<SVGVKernElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGViewElementImpl> *test = dynamic_cast<const KSVGBridge<SVGViewElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGDOMElementBridge::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGDOMElementBridgeProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ if(SVGDOMNodeBridge::hasProperty(p1,p2)) return SVGDOMNodeBridge::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGDOMElementBridge::put(PUT_METHOD_ARGS)
+{
+ if(SVGDOMNodeBridge::hasProperty(p1,p2)) {
+ SVGDOMNodeBridge::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGDOMElementBridge::prototype(ExecState *p1) const
+{
+ if(p1) return SVGDOMElementBridgeProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGDOMElementBridge::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGDOMElementBridge,KSVGRWBridge<SVGDOMElementBridge> >(p1,const_cast<SVGDOMElementBridge *>(this)));
+}
+
+bool SVGDOMNodeBridge::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGDOMNodeBridge::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGDOMNodeBridgeProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGDOMNodeBridge::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGDOMNodeBridgeProtoFunc,SVGDOMNodeBridge>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGDOMNodeBridge *SVGDOMNodeBridgeProtoFunc::cast(const ObjectImp *p1) const
+{
+ return KSVG::toNodeBridge(p1);
+}
+
+SVGDOMNodeBridge *KSVG::toNodeBridge(const ObjectImp *p1)
+{
+ { const KSVGBridge<SVGDOMNodeBridge> *test = dynamic_cast<const KSVGBridge<SVGDOMNodeBridge> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAltGlyphDefElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAltGlyphDefElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAltGlyphElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAltGlyphElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAnimateColorElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimateColorElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAnimateElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimateElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAnimateMotionElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimateMotionElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAnimateTransformElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimateTransformElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAnimationElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimationElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGCircleElementImpl> *test = dynamic_cast<const KSVGBridge<SVGCircleElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGClipPathElementImpl> *test = dynamic_cast<const KSVGBridge<SVGClipPathElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGColorProfileElementImpl> *test = dynamic_cast<const KSVGBridge<SVGColorProfileElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGComponentTransferFunctionElementImpl> *test = dynamic_cast<const KSVGBridge<SVGComponentTransferFunctionElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGContainerImpl> *test = dynamic_cast<const KSVGBridge<SVGContainerImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGCursorElementImpl> *test = dynamic_cast<const KSVGBridge<SVGCursorElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGDOMCharacterDataBridge> *test = dynamic_cast<const KSVGBridge<SVGDOMCharacterDataBridge> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGDOMDocumentFragmentBridge> *test = dynamic_cast<const KSVGBridge<SVGDOMDocumentFragmentBridge> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGDOMElementBridge> *test = dynamic_cast<const KSVGBridge<SVGDOMElementBridge> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGDOMTextBridge> *test = dynamic_cast<const KSVGBridge<SVGDOMTextBridge> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGDefinitionSrcElementImpl> *test = dynamic_cast<const KSVGBridge<SVGDefinitionSrcElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGDefsElementImpl> *test = dynamic_cast<const KSVGBridge<SVGDefsElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGDescElementImpl> *test = dynamic_cast<const KSVGBridge<SVGDescElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGDocumentImpl> *test = dynamic_cast<const KSVGBridge<SVGDocumentImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGElementImpl> *test = dynamic_cast<const KSVGBridge<SVGElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGEllipseElementImpl> *test = dynamic_cast<const KSVGBridge<SVGEllipseElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEBlendElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEBlendElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEColorMatrixElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEColorMatrixElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEComponentTransferElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEComponentTransferElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFECompositeElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFECompositeElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEConvolveMatrixElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEConvolveMatrixElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEDiffuseLightingElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEDiffuseLightingElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEDisplacementMapElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEDisplacementMapElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEDistantLightElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEDistantLightElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEFloodElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEFloodElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEFuncAElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEFuncAElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEFuncBElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEFuncBElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEFuncGElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEFuncGElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEFuncRElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEFuncRElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEGaussianBlurElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEGaussianBlurElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEImageElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEImageElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEMergeElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEMergeElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEMergeNodeElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEMergeNodeElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEMorphologyElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEMorphologyElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEOffsetElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEOffsetElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEPointLightElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEPointLightElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFESpecularLightingElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFESpecularLightingElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFESpotLightElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFESpotLightElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFETileElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFETileElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFETurbulenceElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFETurbulenceElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFilterElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFilterElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFontElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFontElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFontFaceElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFontFaceElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFontFaceFormatElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFontFaceFormatElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFontFaceNameElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFontFaceNameElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFontFaceSrcElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFontFaceSrcElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFontFaceUriElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFontFaceUriElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGForeignObjectElementImpl> *test = dynamic_cast<const KSVGBridge<SVGForeignObjectElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGGElementImpl> *test = dynamic_cast<const KSVGBridge<SVGGElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGGlyphElementImpl> *test = dynamic_cast<const KSVGBridge<SVGGlyphElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGGlyphRefElementImpl> *test = dynamic_cast<const KSVGBridge<SVGGlyphRefElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGGradientElementImpl> *test = dynamic_cast<const KSVGBridge<SVGGradientElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGHKernElementImpl> *test = dynamic_cast<const KSVGBridge<SVGHKernElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGImageElementImpl> *test = dynamic_cast<const KSVGBridge<SVGImageElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGLineElementImpl> *test = dynamic_cast<const KSVGBridge<SVGLineElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGLinearGradientElementImpl> *test = dynamic_cast<const KSVGBridge<SVGLinearGradientElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGMPathElementImpl> *test = dynamic_cast<const KSVGBridge<SVGMPathElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGMarkerElementImpl> *test = dynamic_cast<const KSVGBridge<SVGMarkerElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGMaskElementImpl> *test = dynamic_cast<const KSVGBridge<SVGMaskElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGMetadataElementImpl> *test = dynamic_cast<const KSVGBridge<SVGMetadataElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGMissingGlyphElementImpl> *test = dynamic_cast<const KSVGBridge<SVGMissingGlyphElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPathElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPathElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPatternElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPatternElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPolyElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPolyElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPolygonElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPolygonElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPolylineElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPolylineElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGRadialGradientElementImpl> *test = dynamic_cast<const KSVGBridge<SVGRadialGradientElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGRectElementImpl> *test = dynamic_cast<const KSVGBridge<SVGRectElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGSVGElementImpl> *test = dynamic_cast<const KSVGBridge<SVGSVGElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGScriptElementImpl> *test = dynamic_cast<const KSVGBridge<SVGScriptElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGSetElementImpl> *test = dynamic_cast<const KSVGBridge<SVGSetElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGShapeImpl> *test = dynamic_cast<const KSVGBridge<SVGShapeImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGStopElementImpl> *test = dynamic_cast<const KSVGBridge<SVGStopElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGStyleElementImpl> *test = dynamic_cast<const KSVGBridge<SVGStyleElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGSwitchElementImpl> *test = dynamic_cast<const KSVGBridge<SVGSwitchElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGSymbolElementImpl> *test = dynamic_cast<const KSVGBridge<SVGSymbolElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTRefElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTRefElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTSpanElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTSpanElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTextContentElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextContentElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTextElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTextPathElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextPathElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTextPositioningElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextPositioningElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTitleElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTitleElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGUseElementImpl> *test = dynamic_cast<const KSVGBridge<SVGUseElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGVKernElementImpl> *test = dynamic_cast<const KSVGBridge<SVGVKernElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGViewElementImpl> *test = dynamic_cast<const KSVGBridge<SVGViewElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGDOMNodeBridge::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGDOMNodeBridgeProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ Q_UNUSED(p3);
+ return Undefined();
+}
+
+bool SVGDOMNodeBridge::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGDOMNodeBridge>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGDOMNodeBridge::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGDOMNodeBridge::prototype(ExecState *p1) const
+{
+ if(p1) return SVGDOMNodeBridgeProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGDOMNodeBridge::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGDOMNodeBridge,KSVGRWBridge<SVGDOMNodeBridge> >(p1,const_cast<SVGDOMNodeBridge *>(this)));
+}
+
+bool SVGDOMNodeListBridge::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGDOMNodeListBridge::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGDOMNodeListBridgeProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGDOMNodeListBridge::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGDOMNodeListBridgeProtoFunc,SVGDOMNodeListBridge>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGDOMNodeListBridge *SVGDOMNodeListBridgeProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGDOMNodeListBridge> *test = dynamic_cast<const KSVGBridge<SVGDOMNodeListBridge> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGDOMNodeListBridge::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGDOMNodeListBridgeProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGDOMNodeListBridge::prototype(ExecState *p1) const
+{
+ if(p1) return SVGDOMNodeListBridgeProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGDOMNodeListBridge::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGDOMNodeListBridge,KSVGBridge<SVGDOMNodeListBridge> >(p1,const_cast<SVGDOMNodeListBridge *>(this)));
+}
+
+bool SVGDOMTextBridge::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGDOMTextBridge::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGDOMTextBridgeProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ if(SVGDOMCharacterDataBridge::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGDOMTextBridge::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGDOMTextBridgeProtoFunc,SVGDOMTextBridge>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGDOMTextBridge *SVGDOMTextBridgeProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGDOMTextBridge> *test = dynamic_cast<const KSVGBridge<SVGDOMTextBridge> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGDOMTextBridge::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGDOMTextBridgeProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ if(SVGDOMCharacterDataBridge::hasProperty(p1,p2)) return SVGDOMCharacterDataBridge::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGDOMTextBridge::put(PUT_METHOD_ARGS)
+{
+ if(SVGDOMCharacterDataBridge::hasProperty(p1,p2)) {
+ SVGDOMCharacterDataBridge::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGDOMTextBridge::prototype(ExecState *p1) const
+{
+ if(p1) return SVGDOMTextBridgeProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGDOMTextBridge::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGDOMTextBridge,KSVGRWBridge<SVGDOMTextBridge> >(p1,const_cast<SVGDOMTextBridge *>(this)));
+}
+
+bool SVGDefinitionSrcElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGDefinitionSrcElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGDefinitionSrcElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGDefinitionSrcElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGDefinitionSrcElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGDefinitionSrcElementImpl,KSVGRWBridge<SVGDefinitionSrcElementImpl> >(p1,const_cast<SVGDefinitionSrcElementImpl *>(this)));
+}
+
+bool SVGDefsElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGContainerImpl::hasProperty(p1,p2)) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ if(SVGTestsImpl::hasProperty(p1,p2)) return true;
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGDefsElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGContainerImpl::hasProperty(p1,p2)) return SVGContainerImpl::get(p1,p2,p3);
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3);
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGDefsElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGContainerImpl::hasProperty(p1,p2)) {
+ SVGContainerImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) {
+ SVGLangSpaceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTestsImpl::hasProperty(p1,p2)) {
+ SVGTestsImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTransformableImpl::hasProperty(p1,p2)) {
+ SVGTransformableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGDefsElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGDefsElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGDefsElementImpl>(p1,const_cast<SVGDefsElementImpl *>(this));
+}
+
+Value SVGDefsElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGDefsElementImpl,KSVGRWBridge<SVGDefsElementImpl> >(p1,const_cast<SVGDefsElementImpl *>(this)));
+}
+
+bool SVGDescElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGDescElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGDescElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) {
+ SVGLangSpaceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGDescElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGDescElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGDescElementImpl>(p1,const_cast<SVGDescElementImpl *>(this));
+}
+
+Value SVGDescElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGDescElementImpl,KSVGRWBridge<SVGDescElementImpl> >(p1,const_cast<SVGDescElementImpl *>(this)));
+}
+
+bool SVGDocumentImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGDocumentImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGDocumentImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ if(SVGDOMNodeBridge::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGDocumentImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGDocumentImplProtoFunc,SVGDocumentImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGDocumentImpl *SVGDocumentImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGDocumentImpl> *test = dynamic_cast<const KSVGBridge<SVGDocumentImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGDocumentImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGDocumentImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ if(SVGDOMNodeBridge::hasProperty(p1,p2)) return SVGDOMNodeBridge::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGDocumentImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGDocumentImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGDocumentImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGDOMNodeBridge::hasProperty(p1,p2)) {
+ SVGDOMNodeBridge::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGDocumentImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGDocumentImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGDocumentImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGDocumentImpl,KSVGRWBridge<SVGDocumentImpl> >(p1,const_cast<SVGDocumentImpl *>(this)));
+}
+
+bool SVGElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGElementImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGElementImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ if(SVGDOMElementBridge::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGElementImplProtoFunc,SVGElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGElementImpl *SVGElementImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGElementImpl> *test = dynamic_cast<const KSVGBridge<SVGElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAltGlyphDefElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAltGlyphDefElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAltGlyphElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAltGlyphElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAnimateColorElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimateColorElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAnimateElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimateElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAnimateMotionElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimateMotionElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAnimateTransformElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimateTransformElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAnimationElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimationElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGCircleElementImpl> *test = dynamic_cast<const KSVGBridge<SVGCircleElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGClipPathElementImpl> *test = dynamic_cast<const KSVGBridge<SVGClipPathElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGColorProfileElementImpl> *test = dynamic_cast<const KSVGBridge<SVGColorProfileElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGComponentTransferFunctionElementImpl> *test = dynamic_cast<const KSVGBridge<SVGComponentTransferFunctionElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGContainerImpl> *test = dynamic_cast<const KSVGBridge<SVGContainerImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGCursorElementImpl> *test = dynamic_cast<const KSVGBridge<SVGCursorElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGDefinitionSrcElementImpl> *test = dynamic_cast<const KSVGBridge<SVGDefinitionSrcElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGDefsElementImpl> *test = dynamic_cast<const KSVGBridge<SVGDefsElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGDescElementImpl> *test = dynamic_cast<const KSVGBridge<SVGDescElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGEllipseElementImpl> *test = dynamic_cast<const KSVGBridge<SVGEllipseElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEBlendElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEBlendElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEColorMatrixElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEColorMatrixElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEComponentTransferElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEComponentTransferElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFECompositeElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFECompositeElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEConvolveMatrixElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEConvolveMatrixElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEDiffuseLightingElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEDiffuseLightingElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEDisplacementMapElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEDisplacementMapElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEDistantLightElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEDistantLightElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEFloodElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEFloodElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEFuncAElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEFuncAElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEFuncBElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEFuncBElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEFuncGElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEFuncGElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEFuncRElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEFuncRElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEGaussianBlurElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEGaussianBlurElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEImageElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEImageElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEMergeElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEMergeElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEMergeNodeElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEMergeNodeElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEMorphologyElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEMorphologyElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEOffsetElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEOffsetElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEPointLightElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEPointLightElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFESpecularLightingElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFESpecularLightingElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFESpotLightElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFESpotLightElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFETileElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFETileElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFETurbulenceElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFETurbulenceElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFilterElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFilterElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFontElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFontElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFontFaceElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFontFaceElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFontFaceFormatElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFontFaceFormatElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFontFaceNameElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFontFaceNameElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFontFaceSrcElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFontFaceSrcElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFontFaceUriElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFontFaceUriElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGForeignObjectElementImpl> *test = dynamic_cast<const KSVGBridge<SVGForeignObjectElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGGElementImpl> *test = dynamic_cast<const KSVGBridge<SVGGElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGGlyphElementImpl> *test = dynamic_cast<const KSVGBridge<SVGGlyphElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGGlyphRefElementImpl> *test = dynamic_cast<const KSVGBridge<SVGGlyphRefElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGGradientElementImpl> *test = dynamic_cast<const KSVGBridge<SVGGradientElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGHKernElementImpl> *test = dynamic_cast<const KSVGBridge<SVGHKernElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGImageElementImpl> *test = dynamic_cast<const KSVGBridge<SVGImageElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGLineElementImpl> *test = dynamic_cast<const KSVGBridge<SVGLineElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGLinearGradientElementImpl> *test = dynamic_cast<const KSVGBridge<SVGLinearGradientElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGMPathElementImpl> *test = dynamic_cast<const KSVGBridge<SVGMPathElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGMarkerElementImpl> *test = dynamic_cast<const KSVGBridge<SVGMarkerElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGMaskElementImpl> *test = dynamic_cast<const KSVGBridge<SVGMaskElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGMetadataElementImpl> *test = dynamic_cast<const KSVGBridge<SVGMetadataElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGMissingGlyphElementImpl> *test = dynamic_cast<const KSVGBridge<SVGMissingGlyphElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPathElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPathElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPatternElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPatternElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPolyElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPolyElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPolygonElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPolygonElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPolylineElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPolylineElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGRadialGradientElementImpl> *test = dynamic_cast<const KSVGBridge<SVGRadialGradientElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGRectElementImpl> *test = dynamic_cast<const KSVGBridge<SVGRectElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGSVGElementImpl> *test = dynamic_cast<const KSVGBridge<SVGSVGElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGScriptElementImpl> *test = dynamic_cast<const KSVGBridge<SVGScriptElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGSetElementImpl> *test = dynamic_cast<const KSVGBridge<SVGSetElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGShapeImpl> *test = dynamic_cast<const KSVGBridge<SVGShapeImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGStopElementImpl> *test = dynamic_cast<const KSVGBridge<SVGStopElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGStyleElementImpl> *test = dynamic_cast<const KSVGBridge<SVGStyleElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGSwitchElementImpl> *test = dynamic_cast<const KSVGBridge<SVGSwitchElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGSymbolElementImpl> *test = dynamic_cast<const KSVGBridge<SVGSymbolElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTRefElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTRefElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTSpanElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTSpanElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTextContentElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextContentElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTextElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTextPathElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextPathElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTextPositioningElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextPositioningElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTitleElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTitleElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGUseElementImpl> *test = dynamic_cast<const KSVGBridge<SVGUseElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGVKernElementImpl> *test = dynamic_cast<const KSVGBridge<SVGVKernElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGViewElementImpl> *test = dynamic_cast<const KSVGBridge<SVGViewElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGElementImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ if(SVGDOMElementBridge::hasProperty(p1,p2)) return SVGDOMElementBridge::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGDOMElementBridge::hasProperty(p1,p2)) {
+ SVGDOMElementBridge::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGElementImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGElementImpl>(p1,const_cast<SVGElementImpl *>(this));
+}
+
+Value SVGElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGElementImpl,KSVGRWBridge<SVGElementImpl> >(p1,const_cast<SVGElementImpl *>(this)));
+}
+
+bool SVGEllipseElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGEllipseElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true;
+ if(SVGShapeImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ if(SVGTestsImpl::hasProperty(p1,p2)) return true;
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGEllipseElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGEllipseElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGEllipseElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3);
+ if(SVGShapeImpl::hasProperty(p1,p2)) return SVGShapeImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3);
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGEllipseElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGEllipseElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGEllipseElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) {
+ SVGLangSpaceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGShapeImpl::hasProperty(p1,p2)) {
+ SVGShapeImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTestsImpl::hasProperty(p1,p2)) {
+ SVGTestsImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTransformableImpl::hasProperty(p1,p2)) {
+ SVGTransformableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGEllipseElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGEllipseElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGEllipseElementImpl>(p1,const_cast<SVGEllipseElementImpl *>(this));
+}
+
+Value SVGEllipseElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGEllipseElementImpl,KSVGRWBridge<SVGEllipseElementImpl> >(p1,const_cast<SVGEllipseElementImpl *>(this)));
+}
+
+bool SVGEventImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGEventImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGEventImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGEventImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGEventImplProtoFunc,SVGEventImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGEventImpl *SVGEventImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGEventImpl> *test = dynamic_cast<const KSVGBridge<SVGEventImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGKeyEventImpl> *test = dynamic_cast<const KSVGBridge<SVGKeyEventImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGMouseEventImpl> *test = dynamic_cast<const KSVGBridge<SVGMouseEventImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGMutationEventImpl> *test = dynamic_cast<const KSVGBridge<SVGMutationEventImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGUIEventImpl> *test = dynamic_cast<const KSVGBridge<SVGUIEventImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGZoomEventImpl> *test = dynamic_cast<const KSVGBridge<SVGZoomEventImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGEventImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGEventImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGEventImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGEventImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGEventImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGEventImpl,KSVGBridge<SVGEventImpl> >(p1,const_cast<SVGEventImpl *>(this)));
+}
+
+bool SVGExternalResourcesRequiredImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGExternalResourcesRequiredImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGExternalResourcesRequiredImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGExternalResourcesRequiredImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGExternalResourcesRequiredImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+bool SVGExternalResourcesRequiredImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGExternalResourcesRequiredImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGExternalResourcesRequiredImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGExternalResourcesRequiredImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGExternalResourcesRequiredImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGExternalResourcesRequiredImpl,KSVGRWBridge<SVGExternalResourcesRequiredImpl> >(p1,const_cast<SVGExternalResourcesRequiredImpl *>(this)));
+}
+
+bool SVGFEBlendElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFEBlendElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFEBlendElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFEBlendElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFEBlendElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFEBlendElementImpl,KSVGRWBridge<SVGFEBlendElementImpl> >(p1,const_cast<SVGFEBlendElementImpl *>(this)));
+}
+
+bool SVGFEColorMatrixElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFEColorMatrixElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFEColorMatrixElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFEColorMatrixElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFEColorMatrixElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFEColorMatrixElementImpl,KSVGRWBridge<SVGFEColorMatrixElementImpl> >(p1,const_cast<SVGFEColorMatrixElementImpl *>(this)));
+}
+
+bool SVGFEComponentTransferElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFEComponentTransferElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFEComponentTransferElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFEComponentTransferElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFEComponentTransferElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFEComponentTransferElementImpl,KSVGRWBridge<SVGFEComponentTransferElementImpl> >(p1,const_cast<SVGFEComponentTransferElementImpl *>(this)));
+}
+
+bool SVGFECompositeElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFECompositeElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFECompositeElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFECompositeElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFECompositeElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFECompositeElementImpl,KSVGRWBridge<SVGFECompositeElementImpl> >(p1,const_cast<SVGFECompositeElementImpl *>(this)));
+}
+
+bool SVGFEConvolveMatrixElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFEConvolveMatrixElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFEConvolveMatrixElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFEConvolveMatrixElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFEConvolveMatrixElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFEConvolveMatrixElementImpl,KSVGRWBridge<SVGFEConvolveMatrixElementImpl> >(p1,const_cast<SVGFEConvolveMatrixElementImpl *>(this)));
+}
+
+bool SVGFEDiffuseLightingElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFEDiffuseLightingElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFEDiffuseLightingElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFEDiffuseLightingElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFEDiffuseLightingElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFEDiffuseLightingElementImpl,KSVGRWBridge<SVGFEDiffuseLightingElementImpl> >(p1,const_cast<SVGFEDiffuseLightingElementImpl *>(this)));
+}
+
+bool SVGFEDisplacementMapElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFEDisplacementMapElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFEDisplacementMapElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFEDisplacementMapElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFEDisplacementMapElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFEDisplacementMapElementImpl,KSVGRWBridge<SVGFEDisplacementMapElementImpl> >(p1,const_cast<SVGFEDisplacementMapElementImpl *>(this)));
+}
+
+bool SVGFEDistantLightElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFEDistantLightElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFEDistantLightElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFEDistantLightElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFEDistantLightElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFEDistantLightElementImpl,KSVGRWBridge<SVGFEDistantLightElementImpl> >(p1,const_cast<SVGFEDistantLightElementImpl *>(this)));
+}
+
+bool SVGFEFloodElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFEFloodElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFEFloodElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFEFloodElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFEFloodElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFEFloodElementImpl,KSVGRWBridge<SVGFEFloodElementImpl> >(p1,const_cast<SVGFEFloodElementImpl *>(this)));
+}
+
+bool SVGFEFuncAElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGComponentTransferFunctionElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFEFuncAElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGComponentTransferFunctionElementImpl::hasProperty(p1,p2)) return SVGComponentTransferFunctionElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFEFuncAElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGComponentTransferFunctionElementImpl::hasProperty(p1,p2)) {
+ SVGComponentTransferFunctionElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFEFuncAElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFEFuncAElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFEFuncAElementImpl,KSVGRWBridge<SVGFEFuncAElementImpl> >(p1,const_cast<SVGFEFuncAElementImpl *>(this)));
+}
+
+bool SVGFEFuncBElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGComponentTransferFunctionElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFEFuncBElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGComponentTransferFunctionElementImpl::hasProperty(p1,p2)) return SVGComponentTransferFunctionElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFEFuncBElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGComponentTransferFunctionElementImpl::hasProperty(p1,p2)) {
+ SVGComponentTransferFunctionElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFEFuncBElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFEFuncBElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFEFuncBElementImpl,KSVGRWBridge<SVGFEFuncBElementImpl> >(p1,const_cast<SVGFEFuncBElementImpl *>(this)));
+}
+
+bool SVGFEFuncGElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGComponentTransferFunctionElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFEFuncGElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGComponentTransferFunctionElementImpl::hasProperty(p1,p2)) return SVGComponentTransferFunctionElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFEFuncGElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGComponentTransferFunctionElementImpl::hasProperty(p1,p2)) {
+ SVGComponentTransferFunctionElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFEFuncGElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFEFuncGElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFEFuncGElementImpl,KSVGRWBridge<SVGFEFuncGElementImpl> >(p1,const_cast<SVGFEFuncGElementImpl *>(this)));
+}
+
+bool SVGFEFuncRElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGComponentTransferFunctionElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFEFuncRElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGComponentTransferFunctionElementImpl::hasProperty(p1,p2)) return SVGComponentTransferFunctionElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFEFuncRElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGComponentTransferFunctionElementImpl::hasProperty(p1,p2)) {
+ SVGComponentTransferFunctionElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFEFuncRElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFEFuncRElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFEFuncRElementImpl,KSVGRWBridge<SVGFEFuncRElementImpl> >(p1,const_cast<SVGFEFuncRElementImpl *>(this)));
+}
+
+bool SVGFEGaussianBlurElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFEGaussianBlurElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFEGaussianBlurElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFEGaussianBlurElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFEGaussianBlurElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFEGaussianBlurElementImpl,KSVGRWBridge<SVGFEGaussianBlurElementImpl> >(p1,const_cast<SVGFEGaussianBlurElementImpl *>(this)));
+}
+
+bool SVGFEImageElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFEImageElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFEImageElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) {
+ SVGLangSpaceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) {
+ SVGURIReferenceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFEImageElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFEImageElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFEImageElementImpl,KSVGRWBridge<SVGFEImageElementImpl> >(p1,const_cast<SVGFEImageElementImpl *>(this)));
+}
+
+bool SVGFEMergeElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFEMergeElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFEMergeElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFEMergeElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFEMergeElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFEMergeElementImpl,KSVGRWBridge<SVGFEMergeElementImpl> >(p1,const_cast<SVGFEMergeElementImpl *>(this)));
+}
+
+bool SVGFEMergeNodeElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFEMergeNodeElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFEMergeNodeElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFEMergeNodeElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFEMergeNodeElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFEMergeNodeElementImpl,KSVGRWBridge<SVGFEMergeNodeElementImpl> >(p1,const_cast<SVGFEMergeNodeElementImpl *>(this)));
+}
+
+bool SVGFEMorphologyElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFEMorphologyElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFEMorphologyElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFEMorphologyElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFEMorphologyElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFEMorphologyElementImpl,KSVGRWBridge<SVGFEMorphologyElementImpl> >(p1,const_cast<SVGFEMorphologyElementImpl *>(this)));
+}
+
+bool SVGFEOffsetElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFEOffsetElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFEOffsetElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFEOffsetElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFEOffsetElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFEOffsetElementImpl,KSVGRWBridge<SVGFEOffsetElementImpl> >(p1,const_cast<SVGFEOffsetElementImpl *>(this)));
+}
+
+bool SVGFEPointLightElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFEPointLightElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFEPointLightElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFEPointLightElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFEPointLightElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFEPointLightElementImpl,KSVGRWBridge<SVGFEPointLightElementImpl> >(p1,const_cast<SVGFEPointLightElementImpl *>(this)));
+}
+
+bool SVGFESpecularLightingElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFESpecularLightingElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFESpecularLightingElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFESpecularLightingElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFESpecularLightingElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFESpecularLightingElementImpl,KSVGRWBridge<SVGFESpecularLightingElementImpl> >(p1,const_cast<SVGFESpecularLightingElementImpl *>(this)));
+}
+
+bool SVGFESpotLightElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFESpotLightElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFESpotLightElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFESpotLightElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFESpotLightElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFESpotLightElementImpl,KSVGRWBridge<SVGFESpotLightElementImpl> >(p1,const_cast<SVGFESpotLightElementImpl *>(this)));
+}
+
+bool SVGFETileElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFETileElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFETileElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFETileElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFETileElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFETileElementImpl,KSVGRWBridge<SVGFETileElementImpl> >(p1,const_cast<SVGFETileElementImpl *>(this)));
+}
+
+bool SVGFETurbulenceElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFETurbulenceElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFETurbulenceElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFETurbulenceElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFETurbulenceElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFETurbulenceElementImpl,KSVGRWBridge<SVGFETurbulenceElementImpl> >(p1,const_cast<SVGFETurbulenceElementImpl *>(this)));
+}
+
+bool SVGFilterElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFilterElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFilterElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) {
+ SVGLangSpaceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) {
+ SVGURIReferenceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFilterElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFilterElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFilterElementImpl,KSVGRWBridge<SVGFilterElementImpl> >(p1,const_cast<SVGFilterElementImpl *>(this)));
+}
+
+bool SVGFitToViewBoxImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGFitToViewBoxImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGFitToViewBoxImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGFitToViewBoxImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGFitToViewBoxImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+bool SVGFitToViewBoxImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGFitToViewBoxImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGFitToViewBoxImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGFitToViewBoxImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFitToViewBoxImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFitToViewBoxImpl,KSVGRWBridge<SVGFitToViewBoxImpl> >(p1,const_cast<SVGFitToViewBoxImpl *>(this)));
+}
+
+bool SVGFontElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFontElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFontElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFontElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFontElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFontElementImpl,KSVGRWBridge<SVGFontElementImpl> >(p1,const_cast<SVGFontElementImpl *>(this)));
+}
+
+bool SVGFontFaceElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFontFaceElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFontFaceElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFontFaceElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFontFaceElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFontFaceElementImpl,KSVGRWBridge<SVGFontFaceElementImpl> >(p1,const_cast<SVGFontFaceElementImpl *>(this)));
+}
+
+bool SVGFontFaceFormatElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFontFaceFormatElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFontFaceFormatElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFontFaceFormatElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFontFaceFormatElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFontFaceFormatElementImpl,KSVGRWBridge<SVGFontFaceFormatElementImpl> >(p1,const_cast<SVGFontFaceFormatElementImpl *>(this)));
+}
+
+bool SVGFontFaceNameElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFontFaceNameElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFontFaceNameElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFontFaceNameElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFontFaceNameElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFontFaceNameElementImpl,KSVGRWBridge<SVGFontFaceNameElementImpl> >(p1,const_cast<SVGFontFaceNameElementImpl *>(this)));
+}
+
+bool SVGFontFaceSrcElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFontFaceSrcElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFontFaceSrcElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFontFaceSrcElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFontFaceSrcElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFontFaceSrcElementImpl,KSVGRWBridge<SVGFontFaceSrcElementImpl> >(p1,const_cast<SVGFontFaceSrcElementImpl *>(this)));
+}
+
+bool SVGFontFaceUriElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGFontFaceUriElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGFontFaceUriElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGFontFaceUriElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGFontFaceUriElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGFontFaceUriElementImpl,KSVGRWBridge<SVGFontFaceUriElementImpl> >(p1,const_cast<SVGFontFaceUriElementImpl *>(this)));
+}
+
+bool SVGForeignObjectElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGForeignObjectElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ if(SVGTestsImpl::hasProperty(p1,p2)) return true;
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGForeignObjectElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGForeignObjectElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGForeignObjectElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3);
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGForeignObjectElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) {
+ SVGLangSpaceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTestsImpl::hasProperty(p1,p2)) {
+ SVGTestsImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTransformableImpl::hasProperty(p1,p2)) {
+ SVGTransformableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGForeignObjectElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGForeignObjectElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGForeignObjectElementImpl,KSVGRWBridge<SVGForeignObjectElementImpl> >(p1,const_cast<SVGForeignObjectElementImpl *>(this)));
+}
+
+bool SVGGElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGContainerImpl::hasProperty(p1,p2)) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ if(SVGTestsImpl::hasProperty(p1,p2)) return true;
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGGElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGContainerImpl::hasProperty(p1,p2)) return SVGContainerImpl::get(p1,p2,p3);
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3);
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGGElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGContainerImpl::hasProperty(p1,p2)) {
+ SVGContainerImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) {
+ SVGLangSpaceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTestsImpl::hasProperty(p1,p2)) {
+ SVGTestsImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTransformableImpl::hasProperty(p1,p2)) {
+ SVGTransformableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGGElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGGElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGGElementImpl>(p1,const_cast<SVGGElementImpl *>(this));
+}
+
+Value SVGGElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGGElementImpl,KSVGRWBridge<SVGGElementImpl> >(p1,const_cast<SVGGElementImpl *>(this)));
+}
+
+bool SVGGlyphElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGGlyphElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGGlyphElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGGlyphElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGGlyphElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGGlyphElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGGlyphElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGGlyphElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGGlyphElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGGlyphElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGGlyphElementImpl>(p1,const_cast<SVGGlyphElementImpl *>(this));
+}
+
+Value SVGGlyphElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGGlyphElementImpl,KSVGRWBridge<SVGGlyphElementImpl> >(p1,const_cast<SVGGlyphElementImpl *>(this)));
+}
+
+bool SVGGlyphRefElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGGlyphRefElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGGlyphRefElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGGlyphRefElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGGlyphRefElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGGlyphRefElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGGlyphRefElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGGlyphRefElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) {
+ SVGURIReferenceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGGlyphRefElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGGlyphRefElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGGlyphRefElementImpl>(p1,const_cast<SVGGlyphRefElementImpl *>(this));
+}
+
+Value SVGGlyphRefElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGGlyphRefElementImpl,KSVGRWBridge<SVGGlyphRefElementImpl> >(p1,const_cast<SVGGlyphRefElementImpl *>(this)));
+}
+
+bool SVGGradientElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGGradientElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGGradientElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGGradientElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGGradientElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGGradientElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGGradientElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGGradientElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) {
+ SVGURIReferenceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGGradientElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGGradientElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGGradientElementImpl,KSVGRWBridge<SVGGradientElementImpl> >(p1,const_cast<SVGGradientElementImpl *>(this)));
+}
+
+bool SVGGradientElementImplConstructor::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGGradientElementImplConstructor::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGGradientElementImplConstructor::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGGradientElementImplConstructor>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGGradientElementImplConstructor::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGGradientElementImplConstructor::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGGradientElementImplConstructor::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGGradientElementImplConstructor,KSVGBridge<SVGGradientElementImplConstructor> >(p1,const_cast<SVGGradientElementImplConstructor *>(this)));
+}
+
+bool SVGHKernElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGHKernElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGHKernElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGHKernElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGHKernElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGHKernElementImpl,KSVGRWBridge<SVGHKernElementImpl> >(p1,const_cast<SVGHKernElementImpl *>(this)));
+}
+
+bool SVGICCColorImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGICCColorImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGICCColorImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGICCColorImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGICCColorImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGICCColorImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGICCColorImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGICCColorImpl,KSVGBridge<SVGICCColorImpl> >(p1,const_cast<SVGICCColorImpl *>(this)));
+}
+
+bool SVGImageElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGImageElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true;
+ if(SVGShapeImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ if(SVGTestsImpl::hasProperty(p1,p2)) return true;
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return true;
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGImageElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGImageElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGImageElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3);
+ if(SVGShapeImpl::hasProperty(p1,p2)) return SVGShapeImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3);
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3);
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGImageElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGImageElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGImageElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) {
+ SVGLangSpaceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGShapeImpl::hasProperty(p1,p2)) {
+ SVGShapeImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTestsImpl::hasProperty(p1,p2)) {
+ SVGTestsImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTransformableImpl::hasProperty(p1,p2)) {
+ SVGTransformableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) {
+ SVGURIReferenceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGImageElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGImageElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGImageElementImpl>(p1,const_cast<SVGImageElementImpl *>(this));
+}
+
+Value SVGImageElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGImageElementImpl,KSVGRWBridge<SVGImageElementImpl> >(p1,const_cast<SVGImageElementImpl *>(this)));
+}
+
+bool SVGKeyEventImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGKeyEventImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGKeyEventImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ if(SVGUIEventImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGKeyEventImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGKeyEventImplProtoFunc,SVGKeyEventImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGKeyEventImpl *SVGKeyEventImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGKeyEventImpl> *test = dynamic_cast<const KSVGBridge<SVGKeyEventImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGKeyEventImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGKeyEventImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ if(SVGUIEventImpl::hasProperty(p1,p2)) return SVGUIEventImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+Object SVGKeyEventImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGKeyEventImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGKeyEventImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGKeyEventImpl,KSVGBridge<SVGKeyEventImpl> >(p1,const_cast<SVGKeyEventImpl *>(this)));
+}
+
+bool SVGLangSpaceImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGLangSpaceImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGLangSpaceImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGLangSpaceImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGLangSpaceImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+bool SVGLangSpaceImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGLangSpaceImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGLangSpaceImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGLangSpaceImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGLangSpaceImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGLangSpaceImpl,KSVGRWBridge<SVGLangSpaceImpl> >(p1,const_cast<SVGLangSpaceImpl *>(this)));
+}
+
+bool SVGLengthImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGLengthImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGLengthImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGLengthImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGLengthImplProtoFunc,SVGLengthImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGLengthImpl *SVGLengthImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGLengthImpl> *test = dynamic_cast<const KSVGBridge<SVGLengthImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGLengthImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGLengthImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ Q_UNUSED(p3);
+ return Undefined();
+}
+
+bool SVGLengthImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGLengthImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGLengthImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGLengthImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGLengthImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGLengthImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGLengthImpl,KSVGRWBridge<SVGLengthImpl> >(p1,const_cast<SVGLengthImpl *>(this)));
+}
+
+bool SVGLengthImplConstructor::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGLengthImplConstructor::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGLengthImplConstructor::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGLengthImplConstructor>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGLengthImplConstructor::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGLengthImplConstructor::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGLengthImplConstructor::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGLengthImplConstructor,KSVGBridge<SVGLengthImplConstructor> >(p1,const_cast<SVGLengthImplConstructor *>(this)));
+}
+
+bool SVGLengthListImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGLengthListImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGLengthListImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGLengthListImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGLengthListImplProtoFunc,SVGLengthListImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGLengthListImpl *SVGLengthListImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGLengthListImpl> *test = dynamic_cast<const KSVGBridge<SVGLengthListImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGLengthListImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGLengthListImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGLengthListImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGLengthListImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGLengthListImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGLengthListImpl,KSVGBridge<SVGLengthListImpl> >(p1,const_cast<SVGLengthListImpl *>(this)));
+}
+
+bool SVGLineElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGLineElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true;
+ if(SVGShapeImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ if(SVGTestsImpl::hasProperty(p1,p2)) return true;
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGLineElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGLineElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGLineElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3);
+ if(SVGShapeImpl::hasProperty(p1,p2)) return SVGShapeImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3);
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGLineElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGLineElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGLineElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) {
+ SVGLangSpaceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGShapeImpl::hasProperty(p1,p2)) {
+ SVGShapeImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTestsImpl::hasProperty(p1,p2)) {
+ SVGTestsImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTransformableImpl::hasProperty(p1,p2)) {
+ SVGTransformableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGLineElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGLineElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGLineElementImpl>(p1,const_cast<SVGLineElementImpl *>(this));
+}
+
+Value SVGLineElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGLineElementImpl,KSVGRWBridge<SVGLineElementImpl> >(p1,const_cast<SVGLineElementImpl *>(this)));
+}
+
+bool SVGLinearGradientElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGLinearGradientElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGGradientElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGLinearGradientElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGLinearGradientElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGLinearGradientElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGGradientElementImpl::hasProperty(p1,p2)) return SVGGradientElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGLinearGradientElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGLinearGradientElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGLinearGradientElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGGradientElementImpl::hasProperty(p1,p2)) {
+ SVGGradientElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGLinearGradientElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGLinearGradientElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGLinearGradientElementImpl>(p1,const_cast<SVGLinearGradientElementImpl *>(this));
+}
+
+Value SVGLinearGradientElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGLinearGradientElementImpl,KSVGRWBridge<SVGLinearGradientElementImpl> >(p1,const_cast<SVGLinearGradientElementImpl *>(this)));
+}
+
+bool SVGLocatableImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGLocatableImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGLocatableImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGLocatableImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGLocatableImplProtoFunc,SVGLocatableImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGLocatableImpl *SVGLocatableImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGLocatableImpl> *test = dynamic_cast<const KSVGBridge<SVGLocatableImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGCircleElementImpl> *test = dynamic_cast<const KSVGBridge<SVGCircleElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGClipPathElementImpl> *test = dynamic_cast<const KSVGBridge<SVGClipPathElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGDefsElementImpl> *test = dynamic_cast<const KSVGBridge<SVGDefsElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGEllipseElementImpl> *test = dynamic_cast<const KSVGBridge<SVGEllipseElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGForeignObjectElementImpl> *test = dynamic_cast<const KSVGBridge<SVGForeignObjectElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGGElementImpl> *test = dynamic_cast<const KSVGBridge<SVGGElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGImageElementImpl> *test = dynamic_cast<const KSVGBridge<SVGImageElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGLineElementImpl> *test = dynamic_cast<const KSVGBridge<SVGLineElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPathElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPathElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPolyElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPolyElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPolygonElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPolygonElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPolylineElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPolylineElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGRectElementImpl> *test = dynamic_cast<const KSVGBridge<SVGRectElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGSVGElementImpl> *test = dynamic_cast<const KSVGBridge<SVGSVGElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGSwitchElementImpl> *test = dynamic_cast<const KSVGBridge<SVGSwitchElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTextElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTransformableImpl> *test = dynamic_cast<const KSVGBridge<SVGTransformableImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGUseElementImpl> *test = dynamic_cast<const KSVGBridge<SVGUseElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGLocatableImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGLocatableImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGLocatableImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGLocatableImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGLocatableImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGLocatableImpl,KSVGBridge<SVGLocatableImpl> >(p1,const_cast<SVGLocatableImpl *>(this)));
+}
+
+bool SVGMPathElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGMPathElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGMPathElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) {
+ SVGURIReferenceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGMPathElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGMPathElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGMPathElementImpl,KSVGRWBridge<SVGMPathElementImpl> >(p1,const_cast<SVGMPathElementImpl *>(this)));
+}
+
+bool SVGMarkerElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGMarkerElementImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGMarkerElementImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ if(SVGContainerImpl::hasProperty(p1,p2)) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) return true;
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGMarkerElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGMarkerElementImplProtoFunc,SVGMarkerElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGMarkerElementImpl *SVGMarkerElementImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGMarkerElementImpl> *test = dynamic_cast<const KSVGBridge<SVGMarkerElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGMarkerElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGMarkerElementImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ if(SVGContainerImpl::hasProperty(p1,p2)) return SVGContainerImpl::get(p1,p2,p3);
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) return SVGFitToViewBoxImpl::get(p1,p2,p3);
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGMarkerElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGMarkerElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGMarkerElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGContainerImpl::hasProperty(p1,p2)) {
+ SVGContainerImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) {
+ SVGFitToViewBoxImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) {
+ SVGLangSpaceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGMarkerElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGMarkerElementImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGMarkerElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGMarkerElementImpl>(p1,const_cast<SVGMarkerElementImpl *>(this));
+}
+
+Value SVGMarkerElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGMarkerElementImpl,KSVGRWBridge<SVGMarkerElementImpl> >(p1,const_cast<SVGMarkerElementImpl *>(this)));
+}
+
+bool SVGMarkerElementImplConstructor::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGMarkerElementImplConstructor::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGMarkerElementImplConstructor::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGMarkerElementImplConstructor>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGMarkerElementImplConstructor::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGMarkerElementImplConstructor::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGMarkerElementImplConstructor::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGMarkerElementImplConstructor,KSVGBridge<SVGMarkerElementImplConstructor> >(p1,const_cast<SVGMarkerElementImplConstructor *>(this)));
+}
+
+bool SVGMaskElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGMaskElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ if(SVGTestsImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGMaskElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGMaskElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGMaskElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGMaskElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGMaskElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGMaskElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) {
+ SVGLangSpaceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTestsImpl::hasProperty(p1,p2)) {
+ SVGTestsImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGMaskElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGMaskElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGMaskElementImpl>(p1,const_cast<SVGMaskElementImpl *>(this));
+}
+
+Value SVGMaskElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGMaskElementImpl,KSVGRWBridge<SVGMaskElementImpl> >(p1,const_cast<SVGMaskElementImpl *>(this)));
+}
+
+bool SVGMatrixImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGMatrixImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGMatrixImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGMatrixImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGMatrixImplProtoFunc,SVGMatrixImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGMatrixImpl *SVGMatrixImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGMatrixImpl> *test = dynamic_cast<const KSVGBridge<SVGMatrixImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGMatrixImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGMatrixImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ Q_UNUSED(p3);
+ return Undefined();
+}
+
+bool SVGMatrixImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGMatrixImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGMatrixImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGMatrixImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGMatrixImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGMatrixImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGMatrixImpl,KSVGRWBridge<SVGMatrixImpl> >(p1,const_cast<SVGMatrixImpl *>(this)));
+}
+
+bool SVGMetadataElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGMetadataElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGMetadataElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGMetadataElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGMetadataElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGMetadataElementImpl,KSVGRWBridge<SVGMetadataElementImpl> >(p1,const_cast<SVGMetadataElementImpl *>(this)));
+}
+
+bool SVGMissingGlyphElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGMissingGlyphElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGMissingGlyphElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGMissingGlyphElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGMissingGlyphElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGMissingGlyphElementImpl,KSVGRWBridge<SVGMissingGlyphElementImpl> >(p1,const_cast<SVGMissingGlyphElementImpl *>(this)));
+}
+
+bool SVGMouseEventImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGMouseEventImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGMouseEventImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ if(SVGUIEventImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGMouseEventImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGMouseEventImplProtoFunc,SVGMouseEventImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGMouseEventImpl *SVGMouseEventImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGMouseEventImpl> *test = dynamic_cast<const KSVGBridge<SVGMouseEventImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGMouseEventImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGMouseEventImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ if(SVGUIEventImpl::hasProperty(p1,p2)) return SVGUIEventImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+Object SVGMouseEventImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGMouseEventImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGMouseEventImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGMouseEventImpl,KSVGBridge<SVGMouseEventImpl> >(p1,const_cast<SVGMouseEventImpl *>(this)));
+}
+
+bool SVGMutationEventImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGEventImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGMutationEventImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGEventImpl::hasProperty(p1,p2)) return SVGEventImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+Object SVGMutationEventImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGMutationEventImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGMutationEventImpl,KSVGBridge<SVGMutationEventImpl> >(p1,const_cast<SVGMutationEventImpl *>(this)));
+}
+
+bool SVGNumberImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGNumberImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGNumberImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGNumberImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGNumberImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+bool SVGNumberImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGNumberImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGNumberImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGNumberImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGNumberImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGNumberImpl,KSVGRWBridge<SVGNumberImpl> >(p1,const_cast<SVGNumberImpl *>(this)));
+}
+
+bool SVGNumberListImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGNumberListImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGNumberListImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGNumberListImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGNumberListImplProtoFunc,SVGNumberListImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGNumberListImpl *SVGNumberListImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGNumberListImpl> *test = dynamic_cast<const KSVGBridge<SVGNumberListImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGNumberListImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGNumberListImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGNumberListImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGNumberListImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGNumberListImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGNumberListImpl,KSVGBridge<SVGNumberListImpl> >(p1,const_cast<SVGNumberListImpl *>(this)));
+}
+
+bool SVGPaintImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPaintImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGColorImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPaintImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPaintImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPaintImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGColorImpl::hasProperty(p1,p2)) return SVGColorImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+Object SVGPaintImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPaintImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPaintImpl,KSVGBridge<SVGPaintImpl> >(p1,const_cast<SVGPaintImpl *>(this)));
+}
+
+bool SVGPaintImplConstructor::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPaintImplConstructor::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGPaintImplConstructor::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPaintImplConstructor>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPaintImplConstructor::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGPaintImplConstructor::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPaintImplConstructor::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPaintImplConstructor,KSVGBridge<SVGPaintImplConstructor> >(p1,const_cast<SVGPaintImplConstructor *>(this)));
+}
+
+bool SVGPathElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPathElementImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGPathElementImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ if(SVGAnimatedPathDataImpl::hasProperty(p1,p2)) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true;
+ if(SVGShapeImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ if(SVGTestsImpl::hasProperty(p1,p2)) return true;
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPathElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGPathElementImplProtoFunc,SVGPathElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGPathElementImpl *SVGPathElementImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGPathElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPathElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGPathElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGPathElementImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ if(SVGAnimatedPathDataImpl::hasProperty(p1,p2)) return SVGAnimatedPathDataImpl::get(p1,p2,p3);
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3);
+ if(SVGShapeImpl::hasProperty(p1,p2)) return SVGShapeImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3);
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGPathElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGPathElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGPathElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) {
+ SVGLangSpaceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGShapeImpl::hasProperty(p1,p2)) {
+ SVGShapeImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTestsImpl::hasProperty(p1,p2)) {
+ SVGTestsImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTransformableImpl::hasProperty(p1,p2)) {
+ SVGTransformableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGPathElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGPathElementImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGPathElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGPathElementImpl>(p1,const_cast<SVGPathElementImpl *>(this));
+}
+
+Value SVGPathElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPathElementImpl,KSVGRWBridge<SVGPathElementImpl> >(p1,const_cast<SVGPathElementImpl *>(this)));
+}
+
+bool SVGPathSegArcAbsImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPathSegArcAbsImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPathSegArcAbsImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPathSegArcAbsImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPathSegArcAbsImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGPathSegArcAbsImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGPathSegArcAbsImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGPathSegArcAbsImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGPathSegArcAbsImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPathSegArcAbsImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPathSegArcAbsImpl,KSVGRWBridge<SVGPathSegArcAbsImpl> >(p1,const_cast<SVGPathSegArcAbsImpl *>(this)));
+}
+
+bool SVGPathSegArcRelImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPathSegArcRelImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPathSegArcRelImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPathSegArcRelImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPathSegArcRelImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGPathSegArcRelImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGPathSegArcRelImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGPathSegArcRelImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGPathSegArcRelImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPathSegArcRelImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPathSegArcRelImpl,KSVGRWBridge<SVGPathSegArcRelImpl> >(p1,const_cast<SVGPathSegArcRelImpl *>(this)));
+}
+
+bool SVGPathSegClosePathImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPathSegClosePathImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+Object SVGPathSegClosePathImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPathSegClosePathImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPathSegClosePathImpl,KSVGBridge<SVGPathSegClosePathImpl> >(p1,const_cast<SVGPathSegClosePathImpl *>(this)));
+}
+
+bool SVGPathSegCurvetoCubicAbsImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPathSegCurvetoCubicAbsImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPathSegCurvetoCubicAbsImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPathSegCurvetoCubicAbsImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPathSegCurvetoCubicAbsImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGPathSegCurvetoCubicAbsImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGPathSegCurvetoCubicAbsImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGPathSegCurvetoCubicAbsImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGPathSegCurvetoCubicAbsImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPathSegCurvetoCubicAbsImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPathSegCurvetoCubicAbsImpl,KSVGRWBridge<SVGPathSegCurvetoCubicAbsImpl> >(p1,const_cast<SVGPathSegCurvetoCubicAbsImpl *>(this)));
+}
+
+bool SVGPathSegCurvetoCubicRelImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPathSegCurvetoCubicRelImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPathSegCurvetoCubicRelImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPathSegCurvetoCubicRelImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPathSegCurvetoCubicRelImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGPathSegCurvetoCubicRelImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGPathSegCurvetoCubicRelImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGPathSegCurvetoCubicRelImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGPathSegCurvetoCubicRelImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPathSegCurvetoCubicRelImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPathSegCurvetoCubicRelImpl,KSVGRWBridge<SVGPathSegCurvetoCubicRelImpl> >(p1,const_cast<SVGPathSegCurvetoCubicRelImpl *>(this)));
+}
+
+bool SVGPathSegCurvetoCubicSmoothAbsImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPathSegCurvetoCubicSmoothAbsImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPathSegCurvetoCubicSmoothAbsImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPathSegCurvetoCubicSmoothAbsImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPathSegCurvetoCubicSmoothAbsImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGPathSegCurvetoCubicSmoothAbsImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGPathSegCurvetoCubicSmoothAbsImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGPathSegCurvetoCubicSmoothAbsImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGPathSegCurvetoCubicSmoothAbsImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPathSegCurvetoCubicSmoothAbsImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPathSegCurvetoCubicSmoothAbsImpl,KSVGRWBridge<SVGPathSegCurvetoCubicSmoothAbsImpl> >(p1,const_cast<SVGPathSegCurvetoCubicSmoothAbsImpl *>(this)));
+}
+
+bool SVGPathSegCurvetoCubicSmoothRelImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPathSegCurvetoCubicSmoothRelImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPathSegCurvetoCubicSmoothRelImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPathSegCurvetoCubicSmoothRelImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPathSegCurvetoCubicSmoothRelImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGPathSegCurvetoCubicSmoothRelImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGPathSegCurvetoCubicSmoothRelImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGPathSegCurvetoCubicSmoothRelImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGPathSegCurvetoCubicSmoothRelImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPathSegCurvetoCubicSmoothRelImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPathSegCurvetoCubicSmoothRelImpl,KSVGRWBridge<SVGPathSegCurvetoCubicSmoothRelImpl> >(p1,const_cast<SVGPathSegCurvetoCubicSmoothRelImpl *>(this)));
+}
+
+bool SVGPathSegCurvetoQuadraticAbsImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPathSegCurvetoQuadraticAbsImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPathSegCurvetoQuadraticAbsImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPathSegCurvetoQuadraticAbsImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPathSegCurvetoQuadraticAbsImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGPathSegCurvetoQuadraticAbsImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGPathSegCurvetoQuadraticAbsImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGPathSegCurvetoQuadraticAbsImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGPathSegCurvetoQuadraticAbsImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPathSegCurvetoQuadraticAbsImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPathSegCurvetoQuadraticAbsImpl,KSVGRWBridge<SVGPathSegCurvetoQuadraticAbsImpl> >(p1,const_cast<SVGPathSegCurvetoQuadraticAbsImpl *>(this)));
+}
+
+bool SVGPathSegCurvetoQuadraticRelImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPathSegCurvetoQuadraticRelImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPathSegCurvetoQuadraticRelImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPathSegCurvetoQuadraticRelImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPathSegCurvetoQuadraticRelImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGPathSegCurvetoQuadraticRelImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGPathSegCurvetoQuadraticRelImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGPathSegCurvetoQuadraticRelImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGPathSegCurvetoQuadraticRelImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPathSegCurvetoQuadraticRelImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPathSegCurvetoQuadraticRelImpl,KSVGRWBridge<SVGPathSegCurvetoQuadraticRelImpl> >(p1,const_cast<SVGPathSegCurvetoQuadraticRelImpl *>(this)));
+}
+
+bool SVGPathSegCurvetoQuadraticSmoothAbsImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPathSegCurvetoQuadraticSmoothAbsImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPathSegCurvetoQuadraticSmoothAbsImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPathSegCurvetoQuadraticSmoothAbsImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPathSegCurvetoQuadraticSmoothAbsImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGPathSegCurvetoQuadraticSmoothAbsImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGPathSegCurvetoQuadraticSmoothAbsImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGPathSegCurvetoQuadraticSmoothAbsImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGPathSegCurvetoQuadraticSmoothAbsImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPathSegCurvetoQuadraticSmoothAbsImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPathSegCurvetoQuadraticSmoothAbsImpl,KSVGRWBridge<SVGPathSegCurvetoQuadraticSmoothAbsImpl> >(p1,const_cast<SVGPathSegCurvetoQuadraticSmoothAbsImpl *>(this)));
+}
+
+bool SVGPathSegCurvetoQuadraticSmoothRelImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPathSegCurvetoQuadraticSmoothRelImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPathSegCurvetoQuadraticSmoothRelImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPathSegCurvetoQuadraticSmoothRelImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPathSegCurvetoQuadraticSmoothRelImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGPathSegCurvetoQuadraticSmoothRelImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGPathSegCurvetoQuadraticSmoothRelImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGPathSegCurvetoQuadraticSmoothRelImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGPathSegCurvetoQuadraticSmoothRelImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPathSegCurvetoQuadraticSmoothRelImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPathSegCurvetoQuadraticSmoothRelImpl,KSVGRWBridge<SVGPathSegCurvetoQuadraticSmoothRelImpl> >(p1,const_cast<SVGPathSegCurvetoQuadraticSmoothRelImpl *>(this)));
+}
+
+bool SVGPathSegImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPathSegImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGPathSegImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPathSegImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPathSegImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGPathSegImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPathSegImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPathSegImpl,KSVGBridge<SVGPathSegImpl> >(p1,const_cast<SVGPathSegImpl *>(this)));
+}
+
+bool SVGPathSegImplConstructor::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPathSegImplConstructor::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGPathSegImplConstructor::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPathSegImplConstructor>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPathSegImplConstructor::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGPathSegImplConstructor::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPathSegImplConstructor::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPathSegImplConstructor,KSVGBridge<SVGPathSegImplConstructor> >(p1,const_cast<SVGPathSegImplConstructor *>(this)));
+}
+
+bool SVGPathSegLinetoAbsImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPathSegLinetoAbsImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPathSegLinetoAbsImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPathSegLinetoAbsImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPathSegLinetoAbsImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGPathSegLinetoAbsImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGPathSegLinetoAbsImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGPathSegLinetoAbsImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGPathSegLinetoAbsImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPathSegLinetoAbsImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPathSegLinetoAbsImpl,KSVGRWBridge<SVGPathSegLinetoAbsImpl> >(p1,const_cast<SVGPathSegLinetoAbsImpl *>(this)));
+}
+
+bool SVGPathSegLinetoHorizontalAbsImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPathSegLinetoHorizontalAbsImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPathSegLinetoHorizontalAbsImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPathSegLinetoHorizontalAbsImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPathSegLinetoHorizontalAbsImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGPathSegLinetoHorizontalAbsImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGPathSegLinetoHorizontalAbsImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGPathSegLinetoHorizontalAbsImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGPathSegLinetoHorizontalAbsImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPathSegLinetoHorizontalAbsImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPathSegLinetoHorizontalAbsImpl,KSVGRWBridge<SVGPathSegLinetoHorizontalAbsImpl> >(p1,const_cast<SVGPathSegLinetoHorizontalAbsImpl *>(this)));
+}
+
+bool SVGPathSegLinetoHorizontalRelImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPathSegLinetoHorizontalRelImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPathSegLinetoHorizontalRelImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPathSegLinetoHorizontalRelImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPathSegLinetoHorizontalRelImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGPathSegLinetoHorizontalRelImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGPathSegLinetoHorizontalRelImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGPathSegLinetoHorizontalRelImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGPathSegLinetoHorizontalRelImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPathSegLinetoHorizontalRelImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPathSegLinetoHorizontalRelImpl,KSVGRWBridge<SVGPathSegLinetoHorizontalRelImpl> >(p1,const_cast<SVGPathSegLinetoHorizontalRelImpl *>(this)));
+}
+
+bool SVGPathSegLinetoRelImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPathSegLinetoRelImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPathSegLinetoRelImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPathSegLinetoRelImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPathSegLinetoRelImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGPathSegLinetoRelImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGPathSegLinetoRelImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGPathSegLinetoRelImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGPathSegLinetoRelImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPathSegLinetoRelImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPathSegLinetoRelImpl,KSVGRWBridge<SVGPathSegLinetoRelImpl> >(p1,const_cast<SVGPathSegLinetoRelImpl *>(this)));
+}
+
+bool SVGPathSegLinetoVerticalAbsImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPathSegLinetoVerticalAbsImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPathSegLinetoVerticalAbsImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPathSegLinetoVerticalAbsImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPathSegLinetoVerticalAbsImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGPathSegLinetoVerticalAbsImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGPathSegLinetoVerticalAbsImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGPathSegLinetoVerticalAbsImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGPathSegLinetoVerticalAbsImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPathSegLinetoVerticalAbsImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPathSegLinetoVerticalAbsImpl,KSVGRWBridge<SVGPathSegLinetoVerticalAbsImpl> >(p1,const_cast<SVGPathSegLinetoVerticalAbsImpl *>(this)));
+}
+
+bool SVGPathSegLinetoVerticalRelImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPathSegLinetoVerticalRelImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPathSegLinetoVerticalRelImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPathSegLinetoVerticalRelImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPathSegLinetoVerticalRelImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGPathSegLinetoVerticalRelImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGPathSegLinetoVerticalRelImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGPathSegLinetoVerticalRelImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGPathSegLinetoVerticalRelImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPathSegLinetoVerticalRelImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPathSegLinetoVerticalRelImpl,KSVGRWBridge<SVGPathSegLinetoVerticalRelImpl> >(p1,const_cast<SVGPathSegLinetoVerticalRelImpl *>(this)));
+}
+
+bool SVGPathSegListImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPathSegListImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGPathSegListImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPathSegListImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGPathSegListImplProtoFunc,SVGPathSegListImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGPathSegListImpl *SVGPathSegListImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGPathSegListImpl> *test = dynamic_cast<const KSVGBridge<SVGPathSegListImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGPathSegListImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGPathSegListImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGPathSegListImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGPathSegListImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPathSegListImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPathSegListImpl,KSVGBridge<SVGPathSegListImpl> >(p1,const_cast<SVGPathSegListImpl *>(this)));
+}
+
+bool SVGPathSegMovetoAbsImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPathSegMovetoAbsImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPathSegMovetoAbsImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPathSegMovetoAbsImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPathSegMovetoAbsImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGPathSegMovetoAbsImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGPathSegMovetoAbsImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGPathSegMovetoAbsImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGPathSegMovetoAbsImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPathSegMovetoAbsImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPathSegMovetoAbsImpl,KSVGRWBridge<SVGPathSegMovetoAbsImpl> >(p1,const_cast<SVGPathSegMovetoAbsImpl *>(this)));
+}
+
+bool SVGPathSegMovetoRelImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPathSegMovetoRelImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPathSegMovetoRelImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPathSegMovetoRelImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPathSegMovetoRelImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGPathSegImpl::hasProperty(p1,p2)) return SVGPathSegImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGPathSegMovetoRelImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGPathSegMovetoRelImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGPathSegMovetoRelImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGPathSegMovetoRelImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPathSegMovetoRelImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPathSegMovetoRelImpl,KSVGRWBridge<SVGPathSegMovetoRelImpl> >(p1,const_cast<SVGPathSegMovetoRelImpl *>(this)));
+}
+
+bool SVGPatternElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPatternElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) return true;
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ if(SVGTestsImpl::hasProperty(p1,p2)) return true;
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPatternElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPatternElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPatternElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) return SVGFitToViewBoxImpl::get(p1,p2,p3);
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3);
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGPatternElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGPatternElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGPatternElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) {
+ SVGFitToViewBoxImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) {
+ SVGLangSpaceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTestsImpl::hasProperty(p1,p2)) {
+ SVGTestsImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) {
+ SVGURIReferenceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGPatternElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGPatternElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGPatternElementImpl>(p1,const_cast<SVGPatternElementImpl *>(this));
+}
+
+Value SVGPatternElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPatternElementImpl,KSVGRWBridge<SVGPatternElementImpl> >(p1,const_cast<SVGPatternElementImpl *>(this)));
+}
+
+bool SVGPointImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPointImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGPointImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPointImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPointImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+bool SVGPointImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGPointImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGPointImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGPointImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPointImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPointImpl,KSVGRWBridge<SVGPointImpl> >(p1,const_cast<SVGPointImpl *>(this)));
+}
+
+bool SVGPointListImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPointListImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGPointListImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPointListImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGPointListImplProtoFunc,SVGPointListImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGPointListImpl *SVGPointListImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGPointListImpl> *test = dynamic_cast<const KSVGBridge<SVGPointListImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGPointListImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGPointListImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGPointListImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGPointListImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPointListImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPointListImpl,KSVGBridge<SVGPointListImpl> >(p1,const_cast<SVGPointListImpl *>(this)));
+}
+
+bool SVGPolyElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGAnimatedPointsImpl::hasProperty(p1,p2)) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true;
+ if(SVGShapeImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ if(SVGTestsImpl::hasProperty(p1,p2)) return true;
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPolyElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGAnimatedPointsImpl::hasProperty(p1,p2)) return SVGAnimatedPointsImpl::get(p1,p2,p3);
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3);
+ if(SVGShapeImpl::hasProperty(p1,p2)) return SVGShapeImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3);
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGPolyElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGAnimatedPointsImpl::hasProperty(p1,p2)) {
+ SVGAnimatedPointsImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) {
+ SVGLangSpaceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGShapeImpl::hasProperty(p1,p2)) {
+ SVGShapeImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTestsImpl::hasProperty(p1,p2)) {
+ SVGTestsImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTransformableImpl::hasProperty(p1,p2)) {
+ SVGTransformableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGPolyElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPolyElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPolyElementImpl,KSVGRWBridge<SVGPolyElementImpl> >(p1,const_cast<SVGPolyElementImpl *>(this)));
+}
+
+bool SVGPolygonElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGPolyElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPolygonElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGPolyElementImpl::hasProperty(p1,p2)) return SVGPolyElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGPolygonElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGPolyElementImpl::hasProperty(p1,p2)) {
+ SVGPolyElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGPolygonElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGPolygonElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGPolygonElementImpl>(p1,const_cast<SVGPolygonElementImpl *>(this));
+}
+
+Value SVGPolygonElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPolygonElementImpl,KSVGRWBridge<SVGPolygonElementImpl> >(p1,const_cast<SVGPolygonElementImpl *>(this)));
+}
+
+bool SVGPolylineElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGPolyElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGPolylineElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGPolyElementImpl::hasProperty(p1,p2)) return SVGPolyElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGPolylineElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGPolyElementImpl::hasProperty(p1,p2)) {
+ SVGPolyElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGPolylineElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGPolylineElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGPolylineElementImpl>(p1,const_cast<SVGPolylineElementImpl *>(this));
+}
+
+Value SVGPolylineElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPolylineElementImpl,KSVGRWBridge<SVGPolylineElementImpl> >(p1,const_cast<SVGPolylineElementImpl *>(this)));
+}
+
+bool SVGPreserveAspectRatioImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPreserveAspectRatioImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGPreserveAspectRatioImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPreserveAspectRatioImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPreserveAspectRatioImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+bool SVGPreserveAspectRatioImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGPreserveAspectRatioImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGPreserveAspectRatioImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGPreserveAspectRatioImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPreserveAspectRatioImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPreserveAspectRatioImpl,KSVGRWBridge<SVGPreserveAspectRatioImpl> >(p1,const_cast<SVGPreserveAspectRatioImpl *>(this)));
+}
+
+bool SVGPreserveAspectRatioImplConstructor::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGPreserveAspectRatioImplConstructor::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGPreserveAspectRatioImplConstructor::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGPreserveAspectRatioImplConstructor>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGPreserveAspectRatioImplConstructor::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGPreserveAspectRatioImplConstructor::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGPreserveAspectRatioImplConstructor::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGPreserveAspectRatioImplConstructor,KSVGBridge<SVGPreserveAspectRatioImplConstructor> >(p1,const_cast<SVGPreserveAspectRatioImplConstructor *>(this)));
+}
+
+bool SVGRadialGradientElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGRadialGradientElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGGradientElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGRadialGradientElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGRadialGradientElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGRadialGradientElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGGradientElementImpl::hasProperty(p1,p2)) return SVGGradientElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGRadialGradientElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGRadialGradientElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGRadialGradientElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGGradientElementImpl::hasProperty(p1,p2)) {
+ SVGGradientElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGRadialGradientElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGRadialGradientElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGRadialGradientElementImpl>(p1,const_cast<SVGRadialGradientElementImpl *>(this));
+}
+
+Value SVGRadialGradientElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGRadialGradientElementImpl,KSVGRWBridge<SVGRadialGradientElementImpl> >(p1,const_cast<SVGRadialGradientElementImpl *>(this)));
+}
+
+bool SVGRectElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGRectElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true;
+ if(SVGShapeImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ if(SVGTestsImpl::hasProperty(p1,p2)) return true;
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGRectElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGRectElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGRectElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3);
+ if(SVGShapeImpl::hasProperty(p1,p2)) return SVGShapeImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3);
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGRectElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGRectElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGRectElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) {
+ SVGLangSpaceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGShapeImpl::hasProperty(p1,p2)) {
+ SVGShapeImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTestsImpl::hasProperty(p1,p2)) {
+ SVGTestsImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTransformableImpl::hasProperty(p1,p2)) {
+ SVGTransformableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGRectElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGRectElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGRectElementImpl>(p1,const_cast<SVGRectElementImpl *>(this));
+}
+
+Value SVGRectElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGRectElementImpl,KSVGRWBridge<SVGRectElementImpl> >(p1,const_cast<SVGRectElementImpl *>(this)));
+}
+
+bool SVGRectImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGRectImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGRectImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGRectImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGRectImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+bool SVGRectImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGRectImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGRectImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGRectImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGRectImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGRectImpl,KSVGRWBridge<SVGRectImpl> >(p1,const_cast<SVGRectImpl *>(this)));
+}
+
+bool SVGSVGElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGSVGElementImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGSVGElementImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ if(SVGContainerImpl::hasProperty(p1,p2)) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) return true;
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true;
+ if(SVGLocatableImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ if(SVGTestsImpl::hasProperty(p1,p2)) return true;
+ if(SVGZoomAndPanImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGSVGElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGSVGElementImplProtoFunc,SVGSVGElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGSVGElementImpl *SVGSVGElementImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGSVGElementImpl> *test = dynamic_cast<const KSVGBridge<SVGSVGElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGSVGElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGSVGElementImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ if(SVGContainerImpl::hasProperty(p1,p2)) return SVGContainerImpl::get(p1,p2,p3);
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) return SVGFitToViewBoxImpl::get(p1,p2,p3);
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3);
+ if(SVGLocatableImpl::hasProperty(p1,p2)) return SVGLocatableImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3);
+ if(SVGZoomAndPanImpl::hasProperty(p1,p2)) return SVGZoomAndPanImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGSVGElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGSVGElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGSVGElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGContainerImpl::hasProperty(p1,p2)) {
+ SVGContainerImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) {
+ SVGFitToViewBoxImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) {
+ SVGLangSpaceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTestsImpl::hasProperty(p1,p2)) {
+ SVGTestsImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGZoomAndPanImpl::hasProperty(p1,p2)) {
+ SVGZoomAndPanImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGSVGElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGSVGElementImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGSVGElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGSVGElementImpl>(p1,const_cast<SVGSVGElementImpl *>(this));
+}
+
+Value SVGSVGElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGSVGElementImpl,KSVGRWBridge<SVGSVGElementImpl> >(p1,const_cast<SVGSVGElementImpl *>(this)));
+}
+
+bool SVGScriptElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGScriptElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGScriptElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGScriptElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGScriptElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGScriptElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGScriptElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGScriptElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) {
+ SVGURIReferenceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGScriptElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGScriptElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGScriptElementImpl>(p1,const_cast<SVGScriptElementImpl *>(this));
+}
+
+Value SVGScriptElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGScriptElementImpl,KSVGRWBridge<SVGScriptElementImpl> >(p1,const_cast<SVGScriptElementImpl *>(this)));
+}
+
+bool SVGSetElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGAnimationElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGSetElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGAnimationElementImpl::hasProperty(p1,p2)) return SVGAnimationElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGSetElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGAnimationElementImpl::hasProperty(p1,p2)) {
+ SVGAnimationElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGSetElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGSetElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGSetElementImpl>(p1,const_cast<SVGSetElementImpl *>(this));
+}
+
+Value SVGSetElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGSetElementImpl,KSVGRWBridge<SVGSetElementImpl> >(p1,const_cast<SVGSetElementImpl *>(this)));
+}
+
+bool SVGShapeImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGShapeImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGShapeImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGShapeImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGShapeImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGShapeImpl,KSVGRWBridge<SVGShapeImpl> >(p1,const_cast<SVGShapeImpl *>(this)));
+}
+
+bool SVGStopElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGStopElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGStopElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGStopElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGStopElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGStopElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGStopElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGStopElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGStopElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGStopElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGStopElementImpl>(p1,const_cast<SVGStopElementImpl *>(this));
+}
+
+Value SVGStopElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGStopElementImpl,KSVGRWBridge<SVGStopElementImpl> >(p1,const_cast<SVGStopElementImpl *>(this)));
+}
+
+bool SVGStringListImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGStringListImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGStringListImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGStringListImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGStringListImplProtoFunc,SVGStringListImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGStringListImpl *SVGStringListImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGStringListImpl> *test = dynamic_cast<const KSVGBridge<SVGStringListImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGStringListImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGStringListImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGStringListImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGStringListImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGStringListImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGStringListImpl,KSVGBridge<SVGStringListImpl> >(p1,const_cast<SVGStringListImpl *>(this)));
+}
+
+bool SVGStylableImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGStylableImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGStylableImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGStylableImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGStylableImplProtoFunc,SVGStylableImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGStylableImpl *SVGStylableImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGStylableImpl> *test = dynamic_cast<const KSVGBridge<SVGStylableImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAltGlyphElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAltGlyphElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGCircleElementImpl> *test = dynamic_cast<const KSVGBridge<SVGCircleElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGClipPathElementImpl> *test = dynamic_cast<const KSVGBridge<SVGClipPathElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGDefsElementImpl> *test = dynamic_cast<const KSVGBridge<SVGDefsElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGDescElementImpl> *test = dynamic_cast<const KSVGBridge<SVGDescElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGEllipseElementImpl> *test = dynamic_cast<const KSVGBridge<SVGEllipseElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEFloodElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEFloodElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFEImageElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFEImageElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFilterElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFilterElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGFontElementImpl> *test = dynamic_cast<const KSVGBridge<SVGFontElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGForeignObjectElementImpl> *test = dynamic_cast<const KSVGBridge<SVGForeignObjectElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGGElementImpl> *test = dynamic_cast<const KSVGBridge<SVGGElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGGlyphElementImpl> *test = dynamic_cast<const KSVGBridge<SVGGlyphElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGGlyphRefElementImpl> *test = dynamic_cast<const KSVGBridge<SVGGlyphRefElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGGradientElementImpl> *test = dynamic_cast<const KSVGBridge<SVGGradientElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGImageElementImpl> *test = dynamic_cast<const KSVGBridge<SVGImageElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGLineElementImpl> *test = dynamic_cast<const KSVGBridge<SVGLineElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGLinearGradientElementImpl> *test = dynamic_cast<const KSVGBridge<SVGLinearGradientElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGMarkerElementImpl> *test = dynamic_cast<const KSVGBridge<SVGMarkerElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGMaskElementImpl> *test = dynamic_cast<const KSVGBridge<SVGMaskElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGMissingGlyphElementImpl> *test = dynamic_cast<const KSVGBridge<SVGMissingGlyphElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPathElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPathElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPatternElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPatternElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPolyElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPolyElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPolygonElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPolygonElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPolylineElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPolylineElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGRadialGradientElementImpl> *test = dynamic_cast<const KSVGBridge<SVGRadialGradientElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGRectElementImpl> *test = dynamic_cast<const KSVGBridge<SVGRectElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGSVGElementImpl> *test = dynamic_cast<const KSVGBridge<SVGSVGElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGStopElementImpl> *test = dynamic_cast<const KSVGBridge<SVGStopElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGSwitchElementImpl> *test = dynamic_cast<const KSVGBridge<SVGSwitchElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGSymbolElementImpl> *test = dynamic_cast<const KSVGBridge<SVGSymbolElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTRefElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTRefElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTSpanElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTSpanElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTextContentElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextContentElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTextElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTextPathElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextPathElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTextPositioningElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextPositioningElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTitleElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTitleElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGUseElementImpl> *test = dynamic_cast<const KSVGBridge<SVGUseElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGStylableImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGStylableImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ Q_UNUSED(p3);
+ return Undefined();
+}
+
+bool SVGStylableImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGStylableImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGStylableImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGStylableImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGStylableImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGStylableImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGStylableImpl,KSVGRWBridge<SVGStylableImpl> >(p1,const_cast<SVGStylableImpl *>(this)));
+}
+
+bool SVGStyleElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGStyleElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGStyleElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGStyleElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGStyleElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGStyleElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGStyleElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGStyleElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGStyleElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGStyleElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGStyleElementImpl>(p1,const_cast<SVGStyleElementImpl *>(this));
+}
+
+Value SVGStyleElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGStyleElementImpl,KSVGRWBridge<SVGStyleElementImpl> >(p1,const_cast<SVGStyleElementImpl *>(this)));
+}
+
+bool SVGSwitchElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGContainerImpl::hasProperty(p1,p2)) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ if(SVGTestsImpl::hasProperty(p1,p2)) return true;
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGSwitchElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGContainerImpl::hasProperty(p1,p2)) return SVGContainerImpl::get(p1,p2,p3);
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3);
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGSwitchElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGContainerImpl::hasProperty(p1,p2)) {
+ SVGContainerImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) {
+ SVGLangSpaceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTestsImpl::hasProperty(p1,p2)) {
+ SVGTestsImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTransformableImpl::hasProperty(p1,p2)) {
+ SVGTransformableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGSwitchElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGSwitchElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGSwitchElementImpl>(p1,const_cast<SVGSwitchElementImpl *>(this));
+}
+
+Value SVGSwitchElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGSwitchElementImpl,KSVGRWBridge<SVGSwitchElementImpl> >(p1,const_cast<SVGSwitchElementImpl *>(this)));
+}
+
+bool SVGSymbolElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGSymbolElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) return true;
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true;
+ if(SVGShapeImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGSymbolElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGSymbolElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGSymbolElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) return SVGFitToViewBoxImpl::get(p1,p2,p3);
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3);
+ if(SVGShapeImpl::hasProperty(p1,p2)) return SVGShapeImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGSymbolElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGSymbolElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGSymbolElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) {
+ SVGFitToViewBoxImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) {
+ SVGLangSpaceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGShapeImpl::hasProperty(p1,p2)) {
+ SVGShapeImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGSymbolElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGSymbolElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGSymbolElementImpl>(p1,const_cast<SVGSymbolElementImpl *>(this));
+}
+
+Value SVGSymbolElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGSymbolElementImpl,KSVGRWBridge<SVGSymbolElementImpl> >(p1,const_cast<SVGSymbolElementImpl *>(this)));
+}
+
+bool SVGTRefElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGTSpanElementImpl::hasProperty(p1,p2)) return true;
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGTRefElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGTSpanElementImpl::hasProperty(p1,p2)) return SVGTSpanElementImpl::get(p1,p2,p3);
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGTRefElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGTSpanElementImpl::hasProperty(p1,p2)) {
+ SVGTSpanElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) {
+ SVGURIReferenceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGTRefElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGTRefElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGTRefElementImpl>(p1,const_cast<SVGTRefElementImpl *>(this));
+}
+
+Value SVGTRefElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGTRefElementImpl,KSVGRWBridge<SVGTRefElementImpl> >(p1,const_cast<SVGTRefElementImpl *>(this)));
+}
+
+bool SVGTSpanElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGTextPositioningElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGTSpanElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGTextPositioningElementImpl::hasProperty(p1,p2)) return SVGTextPositioningElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGTSpanElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGTextPositioningElementImpl::hasProperty(p1,p2)) {
+ SVGTextPositioningElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGTSpanElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGTSpanElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGTSpanElementImpl>(p1,const_cast<SVGTSpanElementImpl *>(this));
+}
+
+Value SVGTSpanElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGTSpanElementImpl,KSVGRWBridge<SVGTSpanElementImpl> >(p1,const_cast<SVGTSpanElementImpl *>(this)));
+}
+
+bool SVGTestsImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGTestsImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGTestsImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGTestsImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGTestsImplProtoFunc,SVGTestsImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGTestsImpl *SVGTestsImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGTestsImpl> *test = dynamic_cast<const KSVGBridge<SVGTestsImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAltGlyphElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAltGlyphElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAnimateColorElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimateColorElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAnimateElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimateElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAnimateMotionElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimateMotionElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAnimateTransformElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimateTransformElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAnimationElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAnimationElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGCircleElementImpl> *test = dynamic_cast<const KSVGBridge<SVGCircleElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGClipPathElementImpl> *test = dynamic_cast<const KSVGBridge<SVGClipPathElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGCursorElementImpl> *test = dynamic_cast<const KSVGBridge<SVGCursorElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGDefsElementImpl> *test = dynamic_cast<const KSVGBridge<SVGDefsElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGEllipseElementImpl> *test = dynamic_cast<const KSVGBridge<SVGEllipseElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGForeignObjectElementImpl> *test = dynamic_cast<const KSVGBridge<SVGForeignObjectElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGGElementImpl> *test = dynamic_cast<const KSVGBridge<SVGGElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGImageElementImpl> *test = dynamic_cast<const KSVGBridge<SVGImageElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGLineElementImpl> *test = dynamic_cast<const KSVGBridge<SVGLineElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGMaskElementImpl> *test = dynamic_cast<const KSVGBridge<SVGMaskElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPathElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPathElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPatternElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPatternElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPolyElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPolyElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPolygonElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPolygonElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGPolylineElementImpl> *test = dynamic_cast<const KSVGBridge<SVGPolylineElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGRectElementImpl> *test = dynamic_cast<const KSVGBridge<SVGRectElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGSVGElementImpl> *test = dynamic_cast<const KSVGBridge<SVGSVGElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGSetElementImpl> *test = dynamic_cast<const KSVGBridge<SVGSetElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGSwitchElementImpl> *test = dynamic_cast<const KSVGBridge<SVGSwitchElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTRefElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTRefElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTSpanElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTSpanElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTextContentElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextContentElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTextElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTextPathElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextPathElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTextPositioningElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextPositioningElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGUseElementImpl> *test = dynamic_cast<const KSVGBridge<SVGUseElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGTestsImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGTestsImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ Q_UNUSED(p3);
+ return Undefined();
+}
+
+bool SVGTestsImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGTestsImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGTestsImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGTestsImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGTestsImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGTestsImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGTestsImpl,KSVGRWBridge<SVGTestsImpl> >(p1,const_cast<SVGTestsImpl *>(this)));
+}
+
+bool SVGTextContentElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGTextContentElementImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGTextContentElementImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true;
+ if(SVGShapeImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ if(SVGTestsImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGTextContentElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGTextContentElementImplProtoFunc,SVGTextContentElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGTextContentElementImpl *SVGTextContentElementImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGTextContentElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextContentElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGAltGlyphElementImpl> *test = dynamic_cast<const KSVGBridge<SVGAltGlyphElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTRefElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTRefElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTSpanElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTSpanElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTextElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTextPathElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextPathElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGTextPositioningElementImpl> *test = dynamic_cast<const KSVGBridge<SVGTextPositioningElementImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGTextContentElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGTextContentElementImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3);
+ if(SVGShapeImpl::hasProperty(p1,p2)) return SVGShapeImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGTextContentElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGTextContentElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGTextContentElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) {
+ SVGLangSpaceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGShapeImpl::hasProperty(p1,p2)) {
+ SVGShapeImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTestsImpl::hasProperty(p1,p2)) {
+ SVGTestsImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGTextContentElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGTextContentElementImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGTextContentElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGTextContentElementImpl,KSVGRWBridge<SVGTextContentElementImpl> >(p1,const_cast<SVGTextContentElementImpl *>(this)));
+}
+
+bool SVGTextContentElementImplConstructor::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGTextContentElementImplConstructor::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGTextContentElementImplConstructor::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGTextContentElementImplConstructor>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGTextContentElementImplConstructor::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGTextContentElementImplConstructor::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGTextContentElementImplConstructor::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGTextContentElementImplConstructor,KSVGBridge<SVGTextContentElementImplConstructor> >(p1,const_cast<SVGTextContentElementImplConstructor *>(this)));
+}
+
+bool SVGTextElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGTextPositioningElementImpl::hasProperty(p1,p2)) return true;
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGTextElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGTextPositioningElementImpl::hasProperty(p1,p2)) return SVGTextPositioningElementImpl::get(p1,p2,p3);
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGTextElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGTextPositioningElementImpl::hasProperty(p1,p2)) {
+ SVGTextPositioningElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTransformableImpl::hasProperty(p1,p2)) {
+ SVGTransformableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGTextElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGTextElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGTextElementImpl>(p1,const_cast<SVGTextElementImpl *>(this));
+}
+
+Value SVGTextElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGTextElementImpl,KSVGRWBridge<SVGTextElementImpl> >(p1,const_cast<SVGTextElementImpl *>(this)));
+}
+
+bool SVGTextPathElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGTextPathElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGTextContentElementImpl::hasProperty(p1,p2)) return true;
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGTextPathElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGTextPathElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGTextPathElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGTextContentElementImpl::hasProperty(p1,p2)) return SVGTextContentElementImpl::get(p1,p2,p3);
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGTextPathElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGTextPathElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGTextPathElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGTextContentElementImpl::hasProperty(p1,p2)) {
+ SVGTextContentElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) {
+ SVGURIReferenceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGTextPathElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGTextPathElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGTextPathElementImpl>(p1,const_cast<SVGTextPathElementImpl *>(this));
+}
+
+Value SVGTextPathElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGTextPathElementImpl,KSVGRWBridge<SVGTextPathElementImpl> >(p1,const_cast<SVGTextPathElementImpl *>(this)));
+}
+
+bool SVGTextPathElementImplConstructor::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGTextPathElementImplConstructor::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGTextPathElementImplConstructor::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGTextPathElementImplConstructor>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGTextPathElementImplConstructor::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGTextPathElementImplConstructor::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGTextPathElementImplConstructor::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGTextPathElementImplConstructor,KSVGBridge<SVGTextPathElementImplConstructor> >(p1,const_cast<SVGTextPathElementImplConstructor *>(this)));
+}
+
+bool SVGTextPositioningElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGTextPositioningElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGTextContentElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGTextPositioningElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGTextPositioningElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGTextPositioningElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGTextContentElementImpl::hasProperty(p1,p2)) return SVGTextContentElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGTextPositioningElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGTextPositioningElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGTextPositioningElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGTextContentElementImpl::hasProperty(p1,p2)) {
+ SVGTextContentElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGTextPositioningElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGTextPositioningElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGTextPositioningElementImpl,KSVGRWBridge<SVGTextPositioningElementImpl> >(p1,const_cast<SVGTextPositioningElementImpl *>(this)));
+}
+
+bool SVGTitleElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGTitleElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGTitleElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) {
+ SVGLangSpaceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGTitleElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGTitleElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGTitleElementImpl>(p1,const_cast<SVGTitleElementImpl *>(this));
+}
+
+Value SVGTitleElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGTitleElementImpl,KSVGRWBridge<SVGTitleElementImpl> >(p1,const_cast<SVGTitleElementImpl *>(this)));
+}
+
+bool SVGTransformImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGTransformImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGTransformImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGTransformImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGTransformImplProtoFunc,SVGTransformImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGTransformImpl *SVGTransformImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGTransformImpl> *test = dynamic_cast<const KSVGBridge<SVGTransformImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGTransformImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGTransformImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGTransformImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGTransformImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGTransformImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGTransformImpl,KSVGBridge<SVGTransformImpl> >(p1,const_cast<SVGTransformImpl *>(this)));
+}
+
+bool SVGTransformImplConstructor::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGTransformImplConstructor::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGTransformImplConstructor::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGTransformImplConstructor>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGTransformImplConstructor::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGTransformImplConstructor::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGTransformImplConstructor::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGTransformImplConstructor,KSVGBridge<SVGTransformImplConstructor> >(p1,const_cast<SVGTransformImplConstructor *>(this)));
+}
+
+bool SVGTransformListImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGTransformListImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGTransformListImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGTransformListImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGTransformListImplProtoFunc,SVGTransformListImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGTransformListImpl *SVGTransformListImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGTransformListImpl> *test = dynamic_cast<const KSVGBridge<SVGTransformListImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGTransformListImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGTransformListImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGTransformListImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGTransformListImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGTransformListImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGTransformListImpl,KSVGBridge<SVGTransformListImpl> >(p1,const_cast<SVGTransformListImpl *>(this)));
+}
+
+bool SVGTransformableImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGTransformableImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGLocatableImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGTransformableImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGTransformableImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGTransformableImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGLocatableImpl::hasProperty(p1,p2)) return SVGLocatableImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGTransformableImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGTransformableImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGTransformableImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGTransformableImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGTransformableImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGTransformableImpl,KSVGRWBridge<SVGTransformableImpl> >(p1,const_cast<SVGTransformableImpl *>(this)));
+}
+
+bool SVGUIEventImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGUIEventImpl::s_hashTable,p2);
+ if(e) return true;
+ Object proto = SVGUIEventImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return true;
+ if(SVGEventImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGUIEventImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGet<SVGUIEventImplProtoFunc,SVGUIEventImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+SVGUIEventImpl *SVGUIEventImplProtoFunc::cast(const ObjectImp *p1) const
+{
+ { const KSVGBridge<SVGUIEventImpl> *test = dynamic_cast<const KSVGBridge<SVGUIEventImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGKeyEventImpl> *test = dynamic_cast<const KSVGBridge<SVGKeyEventImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGMouseEventImpl> *test = dynamic_cast<const KSVGBridge<SVGMouseEventImpl> * >(p1);
+ if(test) return test->impl(); }
+ { const KSVGBridge<SVGZoomEventImpl> *test = dynamic_cast<const KSVGBridge<SVGZoomEventImpl> * >(p1);
+ if(test) return test->impl(); }
+ return 0;
+}
+
+Value SVGUIEventImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Object proto = SVGUIEventImplProto::self(p1);
+ if(proto.hasProperty(p1,p2)) return proto.get(p1,p2);
+ if(SVGEventImpl::hasProperty(p1,p2)) return SVGEventImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+Object SVGUIEventImpl::prototype(ExecState *p1) const
+{
+ if(p1) return SVGUIEventImplProto::self(p1);
+ return Object::dynamicCast(Null());
+}
+
+Value SVGUIEventImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGUIEventImpl,KSVGBridge<SVGUIEventImpl> >(p1,const_cast<SVGUIEventImpl *>(this)));
+}
+
+bool SVGURIReferenceImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGURIReferenceImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGURIReferenceImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGURIReferenceImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGURIReferenceImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+bool SVGURIReferenceImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGURIReferenceImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGURIReferenceImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGURIReferenceImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGURIReferenceImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGURIReferenceImpl,KSVGRWBridge<SVGURIReferenceImpl> >(p1,const_cast<SVGURIReferenceImpl *>(this)));
+}
+
+bool SVGUseElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGUseElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return true;
+ if(SVGShapeImpl::hasProperty(p1,p2)) return true;
+ if(SVGStylableImpl::hasProperty(p1,p2)) return true;
+ if(SVGTestsImpl::hasProperty(p1,p2)) return true;
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return true;
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGUseElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGUseElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGUseElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) return SVGLangSpaceImpl::get(p1,p2,p3);
+ if(SVGShapeImpl::hasProperty(p1,p2)) return SVGShapeImpl::get(p1,p2,p3);
+ if(SVGStylableImpl::hasProperty(p1,p2)) return SVGStylableImpl::get(p1,p2,p3);
+ if(SVGTestsImpl::hasProperty(p1,p2)) return SVGTestsImpl::get(p1,p2,p3);
+ if(SVGTransformableImpl::hasProperty(p1,p2)) return SVGTransformableImpl::get(p1,p2,p3);
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) return SVGURIReferenceImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGUseElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGUseElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGUseElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGLangSpaceImpl::hasProperty(p1,p2)) {
+ SVGLangSpaceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGShapeImpl::hasProperty(p1,p2)) {
+ SVGShapeImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGStylableImpl::hasProperty(p1,p2)) {
+ SVGStylableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTestsImpl::hasProperty(p1,p2)) {
+ SVGTestsImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGTransformableImpl::hasProperty(p1,p2)) {
+ SVGTransformableImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGURIReferenceImpl::hasProperty(p1,p2)) {
+ SVGURIReferenceImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGUseElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGUseElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGUseElementImpl>(p1,const_cast<SVGUseElementImpl *>(this));
+}
+
+Value SVGUseElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGUseElementImpl,KSVGRWBridge<SVGUseElementImpl> >(p1,const_cast<SVGUseElementImpl *>(this)));
+}
+
+bool SVGVKernElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGVKernElementImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGVKernElementImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGVKernElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGVKernElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGVKernElementImpl,KSVGRWBridge<SVGVKernElementImpl> >(p1,const_cast<SVGVKernElementImpl *>(this)));
+}
+
+bool SVGViewElementImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGViewElementImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGElementImpl::hasProperty(p1,p2)) return true;
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return true;
+ if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) return true;
+ if(SVGZoomAndPanImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGViewElementImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGViewElementImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGViewElementImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) return SVGElementImpl::get(p1,p2,p3);
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) return SVGExternalResourcesRequiredImpl::get(p1,p2,p3);
+ if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) return SVGFitToViewBoxImpl::get(p1,p2,p3);
+ if(SVGZoomAndPanImpl::hasProperty(p1,p2)) return SVGZoomAndPanImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGViewElementImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGViewElementImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGViewElementImpl::putInParents(PUT_METHOD_ARGS)
+{
+ if(SVGElementImpl::hasProperty(p1,p2)) {
+ SVGElementImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGExternalResourcesRequiredImpl::hasProperty(p1,p2)) {
+ SVGExternalResourcesRequiredImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) {
+ SVGFitToViewBoxImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGZoomAndPanImpl::hasProperty(p1,p2)) {
+ SVGZoomAndPanImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGViewElementImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+ObjectImp *SVGViewElementImpl::bridge(ExecState *p1) const
+{
+ return new KSVGRWBridge<SVGViewElementImpl>(p1,const_cast<SVGViewElementImpl *>(this));
+}
+
+Value SVGViewElementImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGViewElementImpl,KSVGRWBridge<SVGViewElementImpl> >(p1,const_cast<SVGViewElementImpl *>(this)));
+}
+
+bool SVGViewSpecImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) return true;
+ if(SVGZoomAndPanImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGViewSpecImpl::get(GET_METHOD_ARGS) const
+{
+ if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) return SVGFitToViewBoxImpl::get(p1,p2,p3);
+ if(SVGZoomAndPanImpl::hasProperty(p1,p2)) return SVGZoomAndPanImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+bool SVGViewSpecImpl::put(PUT_METHOD_ARGS)
+{
+ if(SVGFitToViewBoxImpl::hasProperty(p1,p2)) {
+ SVGFitToViewBoxImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ if(SVGZoomAndPanImpl::hasProperty(p1,p2)) {
+ SVGZoomAndPanImpl::put(p1,p2,p3,p4);
+ return true;
+ }
+ return false;
+}
+
+Object SVGViewSpecImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGViewSpecImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGViewSpecImpl,KSVGRWBridge<SVGViewSpecImpl> >(p1,const_cast<SVGViewSpecImpl *>(this)));
+}
+
+bool SVGZoomAndPanImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGZoomAndPanImpl::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGZoomAndPanImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGZoomAndPanImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGZoomAndPanImpl::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+bool SVGZoomAndPanImpl::put(PUT_METHOD_ARGS)
+{
+ return lookupPut<SVGZoomAndPanImpl>(p1,p2,p3,p4,&s_hashTable,this);
+}
+
+bool SVGZoomAndPanImpl::putInParents(PUT_METHOD_ARGS)
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3); Q_UNUSED(p4);
+ return false;
+}
+
+Object SVGZoomAndPanImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGZoomAndPanImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGZoomAndPanImpl,KSVGRWBridge<SVGZoomAndPanImpl> >(p1,const_cast<SVGZoomAndPanImpl *>(this)));
+}
+
+bool SVGZoomAndPanImplConstructor::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGZoomAndPanImplConstructor::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SVGZoomAndPanImplConstructor::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGZoomAndPanImplConstructor>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGZoomAndPanImplConstructor::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SVGZoomAndPanImplConstructor::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGZoomAndPanImplConstructor::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGZoomAndPanImplConstructor,KSVGBridge<SVGZoomAndPanImplConstructor> >(p1,const_cast<SVGZoomAndPanImplConstructor *>(this)));
+}
+
+bool SVGZoomEventImpl::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SVGZoomEventImpl::s_hashTable,p2);
+ if(e) return true;
+ if(SVGUIEventImpl::hasProperty(p1,p2)) return true;
+ return false;
+}
+
+Value SVGZoomEventImpl::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SVGZoomEventImpl>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SVGZoomEventImpl::getInParents(GET_METHOD_ARGS) const
+{
+ if(SVGUIEventImpl::hasProperty(p1,p2)) return SVGUIEventImpl::get(p1,p2,p3);
+ return Undefined();
+}
+
+Object SVGZoomEventImpl::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SVGZoomEventImpl::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SVGZoomEventImpl,KSVGBridge<SVGZoomEventImpl> >(p1,const_cast<SVGZoomEventImpl *>(this)));
+}
+
+bool SharedString::hasProperty(ExecState *p1,const Identifier &p2) const
+{
+ const HashEntry *e = Lookup::findEntry(&SharedString::s_hashTable,p2);
+ if(e) return true;
+ Q_UNUSED(p1);
+ return false;
+}
+
+Value SharedString::get(GET_METHOD_ARGS) const
+{
+ return lookupGetValue<SharedString>(p1,p2,&s_hashTable,this,p3);
+}
+
+Value SharedString::getInParents(GET_METHOD_ARGS) const
+{
+ Q_UNUSED(p1); Q_UNUSED(p2); Q_UNUSED(p3);
+ return Undefined();
+}
+
+Object SharedString::prototype(ExecState *p1) const
+{
+ if(p1) return p1->interpreter()->builtinObjectPrototype();
+ return Object::dynamicCast(Null());
+}
+
+Value SharedString::cache(ExecState *p1) const
+{
+ return KJS::Value(cacheDOMObject<SharedString,KSVGBridge<SharedString> >(p1,const_cast<SharedString *>(this)));
+}
+
diff --git a/ksvg/impl/libs/Makefile.am b/ksvg/impl/libs/Makefile.am
new file mode 100644
index 00000000..76f41e24
--- /dev/null
+++ b/ksvg/impl/libs/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = xrgbrender art_support libtext2path
diff --git a/ksvg/impl/libs/art_support/Makefile.am b/ksvg/impl/libs/art_support/Makefile.am
new file mode 100644
index 00000000..4bf00dd7
--- /dev/null
+++ b/ksvg/impl/libs/art_support/Makefile.am
@@ -0,0 +1,4 @@
+noinst_LTLIBRARIES = libksvgart.la
+libksvgart_la_SOURCES = art_render_misc.c art_rgba_svp.c art_misc.c
+
+INCLUDES = $(LIBART_CFLAGS) $(all_includes)
diff --git a/ksvg/impl/libs/art_support/art_misc.c b/ksvg/impl/libs/art_support/art_misc.c
new file mode 100644
index 00000000..69b45306
--- /dev/null
+++ b/ksvg/impl/libs/art_support/art_misc.c
@@ -0,0 +1,1841 @@
+#include <libart_lgpl/art_vpath.h>
+#include <libart_lgpl/art_bpath.h>
+#include <libart_lgpl/art_misc.h>
+#include <libart_lgpl/art_affine.h>
+#include <libart_lgpl/art_svp_render_aa.h>
+
+#include "art_misc.h"
+
+extern double ceil(double x);
+extern double floor(double x);
+
+/**
+ * art_vpath_render_bez: Render a bezier segment into the vpath.
+ * @p_vpath: Where the pointer to the #ArtVpath structure is stored.
+ * @pn_points: Pointer to the number of points in *@p_vpath.
+ * @pn_points_max: Pointer to the number of points allocated.
+ * @x0: X coordinate of starting bezier point.
+ * @y0: Y coordinate of starting bezier point.
+ * @x1: X coordinate of first bezier control point.
+ * @y1: Y coordinate of first bezier control point.
+ * @x2: X coordinate of second bezier control point.
+ * @y2: Y coordinate of second bezier control point.
+ * @x3: X coordinate of ending bezier point.
+ * @y3: Y coordinate of ending bezier point.
+ * @flatness: Flatness control.
+ *
+ * Renders a bezier segment into the vector path, reallocating and
+ * updating *@p_vpath and *@pn_vpath_max as necessary. *@pn_vpath is
+ * incremented by the number of vector points added.
+ *
+ * This step includes (@x0, @y0) but not (@x3, @y3).
+ *
+ * The @flatness argument guides the amount of subdivision. The Adobe
+ * PostScript reference manual defines flatness as the maximum
+ * deviation between the any point on the vpath approximation and the
+ * corresponding point on the "true" curve, and we follow this
+ * definition here. A value of 0.25 should ensure high quality for aa
+ * rendering.
+ **/
+ void
+ksvg_art_vpath_render_bez (ArtVpath **p_vpath, int *pn, int *pn_max,
+ double x0, double y0,
+ double x1, double y1,
+ double x2, double y2,
+ double x3, double y3,
+ double flatness)
+{
+ double x3_0, y3_0;
+ double z3_0_dot;
+ double z1_dot, z2_dot;
+ double z1_perp, z2_perp;
+ double max_perp_sq;
+
+ double x_m, y_m;
+ double xa1, ya1;
+ double xa2, ya2;
+ double xb1, yb1;
+ double xb2, yb2;
+
+ /* It's possible to optimize this routine a fair amount.
+
+ First, once the _dot conditions are met, they will also be met in
+ all further subdivisions. So we might recurse to a different
+ routine that only checks the _perp conditions.
+
+ Second, the distance _should_ decrease according to fairly
+ predictable rules (a factor of 4 with each subdivision). So it might
+ be possible to note that the distance is within a factor of 4 of
+ acceptable, and subdivide once. But proving this might be hard.
+
+ Third, at the last subdivision, x_m and y_m can be computed more
+ expeditiously (as in the routine above).
+
+ Finally, if we were able to subdivide by, say 2 or 3, this would
+ allow considerably finer-grain control, i.e. fewer points for the
+ same flatness tolerance. This would speed things up downstream.
+
+ In any case, this routine is unlikely to be the bottleneck. It's
+ just that I have this undying quest for more speed...
+
+*/
+
+ x3_0 = x3 - x0;
+ y3_0 = y3 - y0;
+
+ /* z3_0_dot is dist z0-z3 squared */
+ z3_0_dot = x3_0 * x3_0 + y3_0 * y3_0;
+
+ /* todo: this test is far from satisfactory. */
+ if (z3_0_dot < 0.001)
+ goto nosubdivide;
+
+ /* we can avoid subdivision if:
+
+ z1 has distance no more than flatness from the z0-z3 line
+
+ z1 is no more z0'ward than flatness past z0-z3
+
+ z1 is more z0'ward than z3'ward on the line traversing z0-z3
+
+ and correspondingly for z2 */
+
+ /* perp is distance from line, multiplied by dist z0-z3 */
+ max_perp_sq = flatness * flatness * z3_0_dot;
+ z1_perp = (y1 - y0) * x3_0 - (x1 - x0) * y3_0;
+ if (z1_perp * z1_perp > max_perp_sq)
+ goto subdivide;
+
+ z2_perp = (y3 - y2) * x3_0 - (x3 - x2) * y3_0;
+ if (z2_perp * z2_perp > max_perp_sq)
+ goto subdivide;
+
+ z1_dot = (x1 - x0) * x3_0 + (y1 - y0) * y3_0;
+ if (z1_dot < 0 && z1_dot * z1_dot > max_perp_sq)
+ goto subdivide;
+
+ z2_dot = (x3 - x2) * x3_0 + (y3 - y2) * y3_0;
+ if (z2_dot < 0 && z2_dot * z2_dot > max_perp_sq)
+ goto subdivide;
+
+ if (z1_dot + z1_dot > z3_0_dot)
+ goto subdivide;
+
+ if (z2_dot + z2_dot > z3_0_dot)
+ goto subdivide;
+
+nosubdivide:
+ /* don't subdivide */
+ art_vpath_add_point (p_vpath, pn, pn_max,
+ ART_LINETO, x3, y3);
+ return;
+
+subdivide:
+
+ xa1 = (x0 + x1) * 0.5;
+ ya1 = (y0 + y1) * 0.5;
+ xa2 = (x0 + 2 * x1 + x2) * 0.25;
+ ya2 = (y0 + 2 * y1 + y2) * 0.25;
+ xb1 = (x1 + 2 * x2 + x3) * 0.25;
+ yb1 = (y1 + 2 * y2 + y3) * 0.25;
+ xb2 = (x2 + x3) * 0.5;
+ yb2 = (y2 + y3) * 0.5;
+ x_m = (xa2 + xb1) * 0.5;
+ y_m = (ya2 + yb1) * 0.5;
+#ifdef VERBOSE
+ printf ("%g,%g %g,%g %g,%g %g,%g\n", xa1, ya1, xa2, ya2,
+ xb1, yb1, xb2, yb2);
+#endif
+ ksvg_art_vpath_render_bez (p_vpath, pn, pn_max,
+ x0, y0, xa1, ya1, xa2, ya2, x_m, y_m, flatness);
+ ksvg_art_vpath_render_bez (p_vpath, pn, pn_max,
+ x_m, y_m, xb1, yb1, xb2, yb2, x3, y3, flatness);
+}
+
+#define RENDER_LEVEL 4
+#define RENDER_SIZE (1 << (RENDER_LEVEL))
+
+/**
+ * ksvg_art_bez_path_to_vec: Create vpath from bezier path.
+ * @bez: Bezier path.
+ * @flatness: Flatness control.
+ *
+ * Creates a vector path closely approximating the bezier path defined by
+ * @bez. The @flatness argument controls the amount of subdivision. In
+ * general, the resulting vpath deviates by at most @flatness pixels
+ * from the "ideal" path described by @bez.
+ *
+ * Return value: Newly allocated vpath.
+ **/
+ ArtVpath *
+ksvg_art_bez_path_to_vec(const ArtBpath *bez, double flatness)
+{
+ ArtVpath *vec;
+ int vec_n, vec_n_max;
+ int bez_index;
+ double x, y;
+
+ vec_n = 0;
+ vec_n_max = RENDER_SIZE;
+ vec = art_new (ArtVpath, vec_n_max);
+
+ /* Initialization is unnecessary because of the precondition that the
+ bezier path does not begin with LINETO or CURVETO, but is here
+ to make the code warning-free. */
+ x = 0;
+ y = 0;
+
+ bez_index = 0;
+ do
+ {
+#ifdef VERBOSE
+ printf ("%s %g %g\n",
+ bez[bez_index].code == ART_CURVETO ? "curveto" :
+ bez[bez_index].code == ART_LINETO ? "lineto" :
+ bez[bez_index].code == ART_MOVETO ? "moveto" :
+ bez[bez_index].code == ART_MOVETO_OPEN ? "moveto-open" :
+ "end", bez[bez_index].x3, bez[bez_index].y3);
+#endif
+ /* make sure space for at least one more code */
+ if (vec_n >= vec_n_max)
+ art_expand (vec, ArtVpath, vec_n_max);
+ switch (bez[bez_index].code)
+ {
+ case ART_MOVETO_OPEN:
+ case ART_MOVETO:
+ case ART_LINETO:
+ x = bez[bez_index].x3;
+ y = bez[bez_index].y3;
+ vec[vec_n].code = bez[bez_index].code;
+ vec[vec_n].x = x;
+ vec[vec_n].y = y;
+ vec_n++;
+ break;
+ case ART_END:
+ vec[vec_n].code = ART_END;
+ vec[vec_n].x = 0;
+ vec[vec_n].y = 0;
+ vec_n++;
+ break;
+ case ART_END2:
+ vec[vec_n].code = (ArtPathcode)ART_END2;
+ vec[vec_n].x = bez[bez_index].x3;
+ vec[vec_n].y = bez[bez_index].y3;
+ vec_n++;
+ break;
+ case ART_CURVETO:
+#ifdef VERBOSE
+ printf ("%g,%g %g,%g %g,%g %g,%g\n", x, y,
+ bez[bez_index].x1, bez[bez_index].y1,
+ bez[bez_index].x2, bez[bez_index].y2,
+ bez[bez_index].x3, bez[bez_index].y3);
+#endif
+ ksvg_art_vpath_render_bez (&vec, &vec_n, &vec_n_max,
+ x, y,
+ bez[bez_index].x1, bez[bez_index].y1,
+ bez[bez_index].x2, bez[bez_index].y2,
+ bez[bez_index].x3, bez[bez_index].y3,
+ flatness);
+ x = bez[bez_index].x3;
+ y = bez[bez_index].y3;
+ break;
+ }
+ }
+ while (bez[bez_index++].code != ART_END);
+ return vec;
+}
+
+/* Private functions for the rgb affine image compositors - primarily,
+* the determination of runs, eliminating the need for source image
+* bbox calculation in the inner loop. */
+
+/* Determine a "run", such that the inverse affine of all pixels from
+* (x0, y) inclusive to (x1, y) exclusive fit within the bounds
+* of the source image.
+*
+* Initial values of x0, x1, and result values stored in first two
+* pointer arguments.
+* */
+
+#define EPSILON 1e-6
+
+ void ksvg_art_rgb_affine_run (int *p_x0, int *p_x1, int y,
+ int src_width, int src_height,
+ const double affine[6])
+{
+ int x0, x1;
+ double z;
+ double x_intercept;
+ int xi;
+
+ x0 = *p_x0;
+ x1 = *p_x1;
+
+ /* do left and right edges */
+ if (affine[0] > EPSILON)
+ {
+ z = affine[2] * (y + 0.5) + affine[4];
+ x_intercept = -z / affine[0];
+ xi = ceil (x_intercept + EPSILON - 0.5);
+ if (xi > x0)
+ x0 = xi;
+ x_intercept = (-z + src_width) / affine[0];
+ xi = ceil (x_intercept - EPSILON - 0.5);
+ if (xi < x1)
+ x1 = xi;
+ }
+ else if (affine[0] < -EPSILON)
+ {
+ z = affine[2] * (y + 0.5) + affine[4];
+ x_intercept = (-z + src_width) / affine[0];
+ xi = ceil (x_intercept + EPSILON - 0.5);
+ if (xi > x0)
+ x0 = xi;
+ x_intercept = -z / affine[0];
+ xi = ceil (x_intercept - EPSILON - 0.5);
+ if (xi < x1)
+ x1 = xi;
+ }
+ else
+ {
+ z = affine[2] * (y + 0.5) + affine[4];
+ if (z < 0 || z >= src_width)
+ {
+ *p_x1 = *p_x0;
+ return;
+ }
+ }
+ /* do top and bottom edges */
+ if (affine[1] > EPSILON)
+ {
+ z = affine[3] * (y + 0.5) + affine[5];
+ x_intercept = -z / affine[1];
+ xi = ceil (x_intercept + EPSILON - 0.5);
+ if (xi > x0)
+ x0 = xi;
+ x_intercept = (-z + src_height) / affine[1];
+ xi = ceil (x_intercept - EPSILON - 0.5);
+ if (xi < x1)
+ x1 = xi;
+ }
+ else if (affine[1] < -EPSILON)
+ {
+ z = affine[3] * (y + 0.5) + affine[5];
+ x_intercept = (-z + src_height) / affine[1];
+ xi = ceil (x_intercept + EPSILON - 0.5);
+ if (xi > x0)
+ x0 = xi;
+ x_intercept = -z / affine[1];
+ xi = ceil (x_intercept - EPSILON - 0.5);
+ if (xi < x1)
+ x1 = xi;
+ }
+ else
+ {
+ z = affine[3] * (y + 0.5) + affine[5];
+ if (z < 0 || z >= src_height)
+ {
+ *p_x1 = *p_x0;
+ return;
+ }
+ }
+
+ *p_x0 = x0;
+ *p_x1 = x1;
+}
+
+/**
+ * ksvg_art_rgb_affine: Affine transform source RGB image and composite.
+ * @dst: Destination image RGB buffer.
+ * @x0: Left coordinate of destination rectangle.
+ * @y0: Top coordinate of destination rectangle.
+ * @x1: Right coordinate of destination rectangle.
+ * @y1: Bottom coordinate of destination rectangle.
+ * @dst_rowstride: Rowstride of @dst buffer.
+ * @src: Source image RGB buffer.
+ * @src_width: Width of source image.
+ * @src_height: Height of source image.
+ * @src_rowstride: Rowstride of @src buffer.
+ * @affine: Affine transform.
+ * @level: Filter level.
+ * @alphagamma: #ArtAlphaGamma for gamma-correcting the compositing.
+ * @alpha: Alpha, range 0..256.
+ *
+ * Affine transform the source image stored in @src, compositing over
+ * the area of destination image @dst specified by the rectangle
+ * (@x0, @y0) - (@x1, @y1). As usual in libart, the left and top edges
+ * of this rectangle are included, and the right and bottom edges are
+ * excluded.
+ *
+ * The @alphagamma parameter specifies that the alpha compositing be done
+ * in a gamma-corrected color space. Since the source image is opaque RGB,
+ * this argument only affects the edges. In the current implementation,
+ * it is ignored.
+ *
+ * The @level parameter specifies the speed/quality tradeoff of the
+ * image interpolation. Currently, only ART_FILTER_NEAREST is
+ * implemented.
+ *
+ * KSVG additions : we have changed this function to support an alpha level as well.
+* also we made sure compositing an rgba image over an rgb buffer works.
+**/
+ void ksvg_art_rgb_affine (art_u8 *dst, int x0, int y0, int x1, int y1, int dst_rowstride,
+ const art_u8 *src,
+ int src_width, int src_height, int src_rowstride,
+ const double affine[6],
+ ArtFilterLevel level,
+ ArtAlphaGamma *alphagamma,
+ int alpha)
+{
+ /* Note: this is a slow implementation, and is missing all filter
+ levels other than NEAREST. It is here for clarity of presentation
+ and to establish the interface. */
+ int x, y;
+ double inv[6];
+ art_u8 *dst_p, *dst_linestart;
+ const art_u8 *src_p;
+ ArtPoint pt, src_pt;
+ int src_x, src_y;
+ int run_x0, run_x1;
+
+ dst_linestart = dst;
+ art_affine_invert (inv, affine);
+
+ if(alpha == 255)
+ for (y = y0; y < y1; y++)
+ {
+ pt.y = y + 0.5;
+ run_x0 = x0;
+ run_x1 = x1;
+ ksvg_art_rgb_affine_run (&run_x0, &run_x1, y, src_width, src_height,
+ inv);
+ dst_p = dst_linestart + (run_x0 - x0) * 3;
+ for (x = run_x0; x < run_x1; x++)
+ {
+ pt.x = x + 0.5;
+ art_affine_point (&src_pt, &pt, inv);
+ src_x = floor (src_pt.x);
+ src_y = floor (src_pt.y);
+ src_p = src + (src_y * src_rowstride) + src_x * 4;
+ dst_p[0] = dst_p[0] + (((src_p[2] - dst_p[0]) * src_p[3] + 0x80) >> 8);
+ dst_p[1] = dst_p[1] + (((src_p[1] - dst_p[1]) * src_p[3] + 0x80) >> 8);
+ dst_p[2] = dst_p[2] + (((src_p[0] - dst_p[2]) * src_p[3] + 0x80) >> 8);
+ dst_p += 3;
+ }
+ dst_linestart += dst_rowstride;
+ }
+ else
+ for (y = y0; y < y1; y++)
+ {
+ pt.y = y + 0.5;
+ run_x0 = x0;
+ run_x1 = x1;
+ ksvg_art_rgb_affine_run (&run_x0, &run_x1, y, src_width, src_height,
+ inv);
+ dst_p = dst_linestart + (run_x0 - x0) * 3;
+ for (x = run_x0; x < run_x1; x++)
+ {
+ pt.x = x + 0.5;
+ art_affine_point (&src_pt, &pt, inv);
+ src_x = floor (src_pt.x);
+ src_y = floor (src_pt.y);
+ src_p = src + (src_y * src_rowstride) + src_x * 4;
+ dst_p[0] = dst_p[0] + (((src_p[2] - dst_p[0]) * alpha + 0x80) >> 8);
+ dst_p[1] = dst_p[1] + (((src_p[1] - dst_p[1]) * alpha + 0x80) >> 8);
+ dst_p[2] = dst_p[2] + (((src_p[0] - dst_p[2]) * alpha + 0x80) >> 8);
+ dst_p += 3;
+ }
+ dst_linestart += dst_rowstride;
+ }
+}
+
+
+typedef struct _ksvgArtRgbAffineClipAlphaData ksvgArtRgbAffineClipAlphaData;
+
+struct _ksvgArtRgbAffineClipAlphaData
+{
+ int alphatab[256];
+ art_u8 alpha;
+ art_u8 *dst;
+ int dst_rowstride;
+ int x0, x1;
+ double inv[6];
+ const art_u8 *src;
+ int src_width;
+ int src_height;
+ int src_rowstride;
+ const art_u8 *mask;
+ int y0;
+};
+
+static
+void ksvg_art_rgb_affine_clip_run(art_u8 *dst_p, int x0, int x1, int y, const double inv[6],
+ int alpha, const art_u8 *src, int src_rowstride, int src_width, int src_height)
+{
+ const art_u8 *src_p;
+ ArtPoint pt, src_pt;
+ int src_x, src_y;
+ int x;
+
+ if(alpha > 255)
+ alpha = 255;
+
+ pt.y = y;
+
+ for(x = x0; x < x1; x++)
+ {
+ pt.x = x;
+
+ art_affine_point(&src_pt, &pt, inv);
+
+ src_x = (int)(src_pt.x);
+ src_y = (int)(src_pt.y);
+
+ if(src_x >= 0 && src_x < src_width && src_y >= 0 && src_y < src_height)
+ {
+ int s;
+ int d;
+ int tmp;
+ int srcAlpha;
+
+ src_p = src + (src_y * src_rowstride) + src_x * 4;
+
+ srcAlpha = alpha * src_p[3] + 0x80;
+ srcAlpha = (srcAlpha + (srcAlpha >> 8)) >> 8;
+
+ d = *dst_p;
+ s = src_p[2];
+
+ tmp = srcAlpha * (s - d) + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ *dst_p++ = d + tmp;
+
+ d = *dst_p;
+ s = src_p[1];
+
+ tmp = srcAlpha * (s - d) + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ *dst_p++ = d + tmp;
+
+ d = *dst_p;
+ s = src_p[0];
+
+ tmp = srcAlpha * (s - d) + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ *dst_p++ = d + tmp;
+ }
+ else
+ dst_p += 3;
+ }
+}
+
+static void
+ksvg_art_rgb_affine_clip_callback (void *callback_data, int y,
+ int start, ArtSVPRenderAAStep *steps, int n_steps)
+{
+ ksvgArtRgbAffineClipAlphaData *data = (ksvgArtRgbAffineClipAlphaData *)callback_data;
+ art_u8 *linebuf;
+ int run_x0, run_x1;
+ art_u32 running_sum = start;
+ int x0, x1;
+ int k;
+ int *alphatab;
+ int alpha;
+
+ linebuf = data->dst;
+ x0 = data->x0;
+ x1 = data->x1;
+
+ alphatab = data->alphatab;
+
+ if(n_steps > 0)
+ {
+ run_x1 = steps[0].x;
+ if(run_x1 > x0)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgb_affine_clip_run(linebuf, x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+
+ for(k = 0; k < n_steps - 1; k++)
+ {
+ running_sum += steps[k].delta;
+ run_x0 = run_x1;
+ run_x1 = steps[k + 1].x;
+ if(run_x1 > run_x0)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgb_affine_clip_run(linebuf + (run_x0 - x0) * 3, run_x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+ }
+ running_sum += steps[k].delta;
+ if(x1 > run_x1)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgb_affine_clip_run(linebuf + (run_x1 - x0) * 3, run_x1, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+ }
+ else
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgb_affine_clip_run(linebuf, x0, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+
+ data->dst += data->dst_rowstride;
+}
+
+static
+void ksvg_art_rgb_affine_clip_mask_run(art_u8 *dst_p, const art_u8 *mask, int x0, int x1, int y, const double inv[6],
+ int alpha, const art_u8 *src, int src_rowstride, int src_width, int src_height)
+{
+ const art_u8 *src_p;
+ ArtPoint pt, src_pt;
+ int src_x, src_y;
+ int x;
+
+ if(alpha > 255)
+ alpha = 255;
+
+ pt.y = y;
+
+ for(x = x0; x < x1; x++)
+ {
+ pt.x = x;
+
+ art_affine_point(&src_pt, &pt, inv);
+
+ src_x = (int)(src_pt.x);
+ src_y = (int)(src_pt.y);
+
+ if(src_x >= 0 && src_x < src_width && src_y >= 0 && src_y < src_height)
+ {
+ int s;
+ int d;
+ int tmp;
+ int srcAlpha;
+
+ src_p = src + (src_y * src_rowstride) + src_x * 4;
+
+ srcAlpha = alpha * src_p[3] + 0x80;
+ srcAlpha = (srcAlpha + (srcAlpha >> 8)) >> 8;
+
+ srcAlpha = (srcAlpha * *mask++) + 0x80;
+ srcAlpha = (srcAlpha + (srcAlpha >> 8)) >> 8;
+
+ d = *dst_p;
+ s = src_p[2];
+
+ tmp = srcAlpha * (s - d) + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ *dst_p++ = d + tmp;
+
+ d = *dst_p;
+ s = src_p[1];
+
+ tmp = srcAlpha * (s - d) + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ *dst_p++ = d + tmp;
+
+ d = *dst_p;
+ s = src_p[0];
+
+ tmp = srcAlpha * (s - d) + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ *dst_p++ = d + tmp;
+ }
+ else
+ {
+ dst_p += 3;
+ mask++;
+ }
+ }
+}
+
+static void
+ksvg_art_rgb_affine_clip_mask_callback (void *callback_data, int y,
+ int start, ArtSVPRenderAAStep *steps, int n_steps)
+{
+ ksvgArtRgbAffineClipAlphaData *data = (ksvgArtRgbAffineClipAlphaData *)callback_data;
+ art_u8 *linebuf;
+ int run_x0, run_x1;
+ art_u32 running_sum = start;
+ int x0, x1;
+ int k;
+ int *alphatab;
+ int alpha;
+ const art_u8 *maskbuf;
+
+ linebuf = data->dst;
+ x0 = data->x0;
+ x1 = data->x1;
+
+ alphatab = data->alphatab;
+ maskbuf = data->mask + (y - data->y0) * (x1 - x0);
+
+ if(n_steps > 0)
+ {
+ run_x1 = steps[0].x;
+ if(run_x1 > x0)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgb_affine_clip_mask_run(linebuf, maskbuf, x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+
+ for(k = 0; k < n_steps - 1; k++)
+ {
+ running_sum += steps[k].delta;
+ run_x0 = run_x1;
+ run_x1 = steps[k + 1].x;
+ if(run_x1 > run_x0)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgb_affine_clip_mask_run(linebuf + (run_x0 - x0) * 3, maskbuf + (run_x0 - x0), run_x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+ }
+ running_sum += steps[k].delta;
+ if(x1 > run_x1)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgb_affine_clip_mask_run(linebuf + (run_x1 - x0) * 3, maskbuf + (run_x1 - x0), run_x1, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+ }
+ else
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgb_affine_clip_mask_run(linebuf, maskbuf, x0, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+
+ data->dst += data->dst_rowstride;
+}
+
+static
+void ksvg_art_rgba_affine_clip_run(art_u8 *dst_p, int x0, int x1, int y, const double inv[6],
+ int alpha, const art_u8 *src, int src_rowstride, int src_width, int src_height)
+{
+ const art_u8 *src_p;
+ ArtPoint pt, src_pt;
+ int src_x, src_y;
+ int x;
+
+ if(alpha > 255)
+ alpha = 255;
+
+ pt.y = y;
+
+ for(x = x0; x < x1; x++)
+ {
+ pt.x = x;
+
+ art_affine_point(&src_pt, &pt, inv);
+
+ src_x = (int)(src_pt.x);
+ src_y = (int)(src_pt.y);
+
+ if(src_x >= 0 && src_x < src_width && src_y >= 0 && src_y < src_height)
+ {
+ int s;
+ int d;
+ int tmp;
+ int srcAlpha;
+
+ src_p = src + (src_y * src_rowstride) + src_x * 4;
+
+ srcAlpha = alpha * src_p[3] + 0x80;
+ srcAlpha = (srcAlpha + (srcAlpha >> 8)) >> 8;
+
+ d = *dst_p;
+ s = src_p[2];
+
+ tmp = srcAlpha * (s - d) + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ *dst_p++ = d + tmp;
+
+ d = *dst_p;
+ s = src_p[1];
+
+ tmp = srcAlpha * (s - d) + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ *dst_p++ = d + tmp;
+
+ d = *dst_p;
+ s = src_p[0];
+
+ tmp = srcAlpha * (s - d) + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ *dst_p++ = d + tmp;
+
+ d = *dst_p;
+
+ tmp = srcAlpha * (255 - d) + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ *dst_p++ = d + tmp;
+ }
+ else
+ dst_p += 4;
+ }
+}
+
+static void
+ksvg_art_rgba_affine_clip_callback (void *callback_data, int y,
+ int start, ArtSVPRenderAAStep *steps, int n_steps)
+{
+ ksvgArtRgbAffineClipAlphaData *data = (ksvgArtRgbAffineClipAlphaData *)callback_data;
+ art_u8 *linebuf;
+ int run_x0, run_x1;
+ art_u32 running_sum = start;
+ int x0, x1;
+ int k;
+ int *alphatab;
+ int alpha;
+
+ linebuf = data->dst;
+ x0 = data->x0;
+ x1 = data->x1;
+
+ alphatab = data->alphatab;
+
+ if(n_steps > 0)
+ {
+ run_x1 = steps[0].x;
+ if(run_x1 > x0)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgba_affine_clip_run(linebuf, x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+
+ for(k = 0; k < n_steps - 1; k++)
+ {
+ running_sum += steps[k].delta;
+ run_x0 = run_x1;
+ run_x1 = steps[k + 1].x;
+ if(run_x1 > run_x0)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgba_affine_clip_run(linebuf + (run_x0 - x0) * 4, run_x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+ }
+ running_sum += steps[k].delta;
+ if(x1 > run_x1)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgba_affine_clip_run(linebuf + (run_x1 - x0) * 4, run_x1, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+ }
+ else
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgba_affine_clip_run(linebuf, x0, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+
+ data->dst += data->dst_rowstride;
+}
+
+static
+void ksvg_art_rgba_affine_clip_mask_run(art_u8 *dst_p, const art_u8 *mask, int x0, int x1, int y, const double inv[6],
+ int alpha, const art_u8 *src, int src_rowstride, int src_width, int src_height)
+{
+ const art_u8 *src_p;
+ ArtPoint pt, src_pt;
+ int src_x, src_y;
+ int x;
+
+ if(alpha > 255)
+ alpha = 255;
+
+ pt.y = y;
+
+ for(x = x0; x < x1; x++)
+ {
+ pt.x = x;
+
+ art_affine_point(&src_pt, &pt, inv);
+
+ src_x = (int)(src_pt.x);
+ src_y = (int)(src_pt.y);
+
+ if(src_x >= 0 && src_x < src_width && src_y >= 0 && src_y < src_height)
+ {
+ int s;
+ int d;
+ int tmp;
+ int srcAlpha;
+
+ src_p = src + (src_y * src_rowstride) + src_x * 4;
+
+ srcAlpha = alpha * src_p[3] + 0x80;
+ srcAlpha = (srcAlpha + (srcAlpha >> 8)) >> 8;
+
+ srcAlpha = (srcAlpha * *mask++) + 0x80;
+ srcAlpha = (srcAlpha + (srcAlpha >> 8)) >> 8;
+
+ d = *dst_p;
+ s = src_p[2];
+
+ tmp = srcAlpha * (s - d) + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ *dst_p++ = d + tmp;
+
+ d = *dst_p;
+ s = src_p[1];
+
+ tmp = srcAlpha * (s - d) + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ *dst_p++ = d + tmp;
+
+ d = *dst_p;
+ s = src_p[0];
+
+ tmp = srcAlpha * (s - d) + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ *dst_p++ = d + tmp;
+
+ d = *dst_p;
+
+ tmp = srcAlpha * (255 - d) + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ *dst_p++ = d + tmp;
+ }
+ else
+ {
+ dst_p += 4;
+ mask++;
+ }
+ }
+}
+
+static void
+ksvg_art_rgba_affine_clip_mask_callback (void *callback_data, int y,
+ int start, ArtSVPRenderAAStep *steps, int n_steps)
+{
+ ksvgArtRgbAffineClipAlphaData *data = (ksvgArtRgbAffineClipAlphaData *)callback_data;
+ art_u8 *linebuf;
+ int run_x0, run_x1;
+ art_u32 running_sum = start;
+ int x0, x1;
+ int k;
+ int *alphatab;
+ int alpha;
+ const art_u8 *maskbuf;
+
+ linebuf = data->dst;
+ x0 = data->x0;
+ x1 = data->x1;
+
+ alphatab = data->alphatab;
+ maskbuf = data->mask + (y - data->y0) * (x1 - x0);
+
+ if(n_steps > 0)
+ {
+ run_x1 = steps[0].x;
+ if(run_x1 > x0)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgba_affine_clip_mask_run(linebuf, maskbuf, x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+
+ for(k = 0; k < n_steps - 1; k++)
+ {
+ running_sum += steps[k].delta;
+ run_x0 = run_x1;
+ run_x1 = steps[k + 1].x;
+ if(run_x1 > run_x0)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgba_affine_clip_mask_run(linebuf + (run_x0 - x0) * 4, maskbuf + (run_x0 - x0), run_x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+ }
+ running_sum += steps[k].delta;
+ if(x1 > run_x1)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgba_affine_clip_mask_run(linebuf + (run_x1 - x0) * 4, maskbuf + (run_x1 - x0), run_x1, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+ }
+ else
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgba_affine_clip_mask_run(linebuf, maskbuf, x0, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+
+ data->dst += data->dst_rowstride;
+}
+
+/**
+ * ksvg_art_rgb_affine_clip: Affine transform source RGB image and composite, with clipping path.
+ * @svp: Clipping path.
+ * @dst: Destination image RGB buffer.
+ * @x0: Left coordinate of destination rectangle.
+ * @y0: Top coordinate of destination rectangle.
+ * @x1: Right coordinate of destination rectangle.
+ * @y1: Bottom coordinate of destination rectangle.
+ * @dst_rowstride: Rowstride of @dst buffer.
+ * @src: Source image RGB buffer.
+ * @src_width: Width of source image.
+ * @src_height: Height of source image.
+ * @src_rowstride: Rowstride of @src buffer.
+ * @affine: Affine transform.
+ * @level: Filter level.
+ * @alphagamma: #ArtAlphaGamma for gamma-correcting the compositing.
+ * @alpha: Alpha, range 0..256.
+ *
+ * Affine transform the source image stored in @src, compositing over
+ * the area of destination image @dst specified by the rectangle
+ * (@x0, @y0) - (@x1, @y1). As usual in libart, the left and top edges
+ * of this rectangle are included, and the right and bottom edges are
+ * excluded.
+ *
+ * The @alphagamma parameter specifies that the alpha compositing be done
+ * in a gamma-corrected color space. Since the source image is opaque RGB,
+ * this argument only affects the edges. In the current implementation,
+ * it is ignored.
+ *
+ * The @level parameter specifies the speed/quality tradeoff of the
+ * image interpolation. Currently, only ART_FILTER_NEAREST is
+ * implemented.
+ *
+ * KSVG additions : we have changed this function to support an alpha level as well.
+* also we made sure compositing an rgba image over an rgb buffer works.
+**/
+void ksvg_art_rgb_affine_clip(const ArtSVP *svp, art_u8 *dst, int x0, int y0, int x1, int y1, int dst_rowstride, int dst_channels,
+ const art_u8 *src,
+ int src_width, int src_height, int src_rowstride,
+ const double affine[6],
+ int alpha, const art_u8 *mask)
+{
+ ksvgArtRgbAffineClipAlphaData data;
+ int i;
+ int a, da;
+
+ data.alpha = alpha;
+
+ a = 0x8000;
+ da = (alpha * 66051 + 0x80) >> 8; /* 66051 equals 2 ^ 32 / (255 * 255) */
+
+ for(i = 0; i < 256; i++)
+ {
+ data.alphatab[i] = a >> 16;
+ a += da;
+ }
+
+ data.dst = dst;
+ data.dst_rowstride = dst_rowstride;
+ data.x0 = x0;
+ data.x1 = x1;
+ data.y0 = y0;
+ data.mask = mask;
+
+ art_affine_invert(data.inv, affine);
+
+ data.src = src;
+ data.src_width = src_width;
+ data.src_height = src_height;
+ data.src_rowstride = src_rowstride;
+
+ if(dst_channels == 3)
+ {
+ if(mask)
+ art_svp_render_aa(svp, x0, y0, x1, y1, ksvg_art_rgb_affine_clip_mask_callback, &data);
+ else
+ art_svp_render_aa(svp, x0, y0, x1, y1, ksvg_art_rgb_affine_clip_callback, &data);
+ }
+ else
+ {
+ if(mask)
+ art_svp_render_aa(svp, x0, y0, x1, y1, ksvg_art_rgba_affine_clip_mask_callback, &data);
+ else
+ art_svp_render_aa(svp, x0, y0, x1, y1, ksvg_art_rgba_affine_clip_callback, &data);
+ }
+}
+
+
+static
+void ksvg_art_rgb_texture_run(art_u8 *dst_p, int x0, int x1, int y, const double inv[6],
+ int alpha, const art_u8 *src, int src_rowstride, int src_width, int src_height)
+{
+ const art_u8 *src_p;
+ ArtPoint pt, src_pt;
+ int src_x, src_y;
+ int x;
+ int srcAlpha;
+
+ if(alpha > 255)
+ alpha = 255;
+
+ /* TODO: optimise and filter? */
+ pt.y = y + 0.5;
+
+ for(x = x0; x < x1; x++)
+ {
+ int s;
+ int d;
+ int tmp;
+ int tmp2;
+
+ pt.x = x + 0.5;
+
+ art_affine_point(&src_pt, &pt, inv);
+
+ src_x = (int)floor(src_pt.x);
+ src_y = (int)floor(src_pt.y);
+
+ if(src_x < 0)
+ {
+ /* Can't assume % behaviour with negative values */
+ src_x += ((src_x / -src_width) + 1) * src_width;
+ }
+
+ if(src_y < 0)
+ {
+ src_y += ((src_y / -src_height) + 1) * src_height;
+ }
+
+ src_x %= src_width;
+ src_y %= src_height;
+
+ src_p = src + (src_y * src_rowstride) + src_x * 4;
+
+ /* Pattern source is in RGBA format, premultiplied.
+ * alpha represents fill/stroke/group opacity.
+ *
+ * Multiply source alpha by 'alpha' then composite over.
+ * For each channel, d = d + alpha * (s - srcAlpha * d).
+ */
+
+ srcAlpha = src_p[3];
+
+ d = *dst_p;
+ s = *src_p++;
+
+ tmp = srcAlpha * d + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ tmp2 = alpha * (s - tmp) + 0x80;
+ tmp2 = (tmp2 + (tmp2 >> 8)) >> 8;
+
+ *dst_p++ = d + tmp2;
+
+ d = *dst_p;
+ s = *src_p++;
+
+ tmp = srcAlpha * d + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ tmp2 = alpha * (s - tmp) + 0x80;
+ tmp2 = (tmp2 + (tmp2 >> 8)) >> 8;
+
+ *dst_p++ = d + tmp2;
+
+ d = *dst_p;
+ s = *src_p++;
+
+ tmp = srcAlpha * d + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ tmp2 = alpha * (s - tmp) + 0x80;
+ tmp2 = (tmp2 + (tmp2 >> 8)) >> 8;
+
+ *dst_p++ = d + tmp2;
+ }
+}
+
+static void
+ksvg_art_rgb_texture_callback (void *callback_data, int y,
+ int start, ArtSVPRenderAAStep *steps, int n_steps)
+{
+ ksvgArtRgbAffineClipAlphaData *data = (ksvgArtRgbAffineClipAlphaData *)callback_data;
+ art_u8 *linebuf;
+ int run_x0, run_x1;
+ art_u32 running_sum = start;
+ int x0, x1;
+ int k;
+ int *alphatab;
+ int alpha;
+
+ linebuf = data->dst;
+ x0 = data->x0;
+ x1 = data->x1;
+
+ alphatab = data->alphatab;
+
+ if(n_steps > 0)
+ {
+ run_x1 = steps[0].x;
+ if(run_x1 > x0)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgb_texture_run(linebuf, x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+
+ for(k = 0; k < n_steps - 1; k++)
+ {
+ running_sum += steps[k].delta;
+ run_x0 = run_x1;
+ run_x1 = steps[k + 1].x;
+ if(run_x1 > run_x0)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgb_texture_run(linebuf + (run_x0 - x0) * 3, run_x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+ }
+ running_sum += steps[k].delta;
+ if(x1 > run_x1)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgb_texture_run(linebuf + (run_x1 - x0) * 3, run_x1, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+ }
+ else
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgb_texture_run(linebuf, x0, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+
+ data->dst += data->dst_rowstride;
+}
+
+static
+void ksvg_art_rgb_texture_mask_run(art_u8 *dst_p, const art_u8 *mask, int x0, int x1, int y, const double inv[6],
+ int alpha, const art_u8 *src, int src_rowstride, int src_width, int src_height)
+{
+ const art_u8 *src_p;
+ ArtPoint pt, src_pt;
+ int src_x, src_y;
+ int x;
+ int srcAlpha;
+
+ if(alpha > 255)
+ alpha = 255;
+
+ /* TODO: optimise and filter? */
+ pt.y = y + 0.5;
+
+ for(x = x0; x < x1; x++)
+ {
+ int s;
+ int d;
+ int am;
+ int tmp;
+ int tmp2;
+
+ pt.x = x + 0.5;
+
+ art_affine_point(&src_pt, &pt, inv);
+
+ src_x = (int)floor(src_pt.x);
+ src_y = (int)floor(src_pt.y);
+
+ if(src_x < 0)
+ {
+ /* Can't assume % behaviour with negative values */
+ src_x += ((src_x / -src_width) + 1) * src_width;
+ }
+
+ if(src_y < 0)
+ {
+ src_y += ((src_y / -src_height) + 1) * src_height;
+ }
+
+ src_x %= src_width;
+ src_y %= src_height;
+
+ src_p = src + (src_y * src_rowstride) + src_x * 4;
+
+ /* Pattern source is in RGBA format, premultiplied.
+ * alpha represents fill/stroke/group opacity.
+ *
+ * Multiply source alpha by 'alpha' and mask value then composite over.
+ * For each channel, d = d + alpha * mask * (s - srcAlpha * d).
+ */
+
+ am = (alpha * *mask++) + 0x80;
+ am = (am + (am >> 8)) >> 8;
+
+ srcAlpha = src_p[3];
+
+ d = *dst_p;
+ s = *src_p++;
+
+ tmp = srcAlpha * d + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ tmp2 = am * (s - tmp) + 0x80;
+ tmp2 = (tmp2 + (tmp2 >> 8)) >> 8;
+
+ *dst_p++ = d + tmp2;
+
+ d = *dst_p;
+ s = *src_p++;
+
+ tmp = srcAlpha * d + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ tmp2 = am * (s - tmp) + 0x80;
+ tmp2 = (tmp2 + (tmp2 >> 8)) >> 8;
+
+ *dst_p++ = d + tmp2;
+
+ d = *dst_p;
+ s = *src_p++;
+
+ tmp = srcAlpha * d + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ tmp2 = am * (s - tmp) + 0x80;
+ tmp2 = (tmp2 + (tmp2 >> 8)) >> 8;
+
+ *dst_p++ = d + tmp2;
+ }
+}
+
+static void
+ksvg_art_rgb_texture_mask_callback (void *callback_data, int y,
+ int start, ArtSVPRenderAAStep *steps, int n_steps)
+{
+ ksvgArtRgbAffineClipAlphaData *data = (ksvgArtRgbAffineClipAlphaData *)callback_data;
+ art_u8 *linebuf;
+ int run_x0, run_x1;
+ art_u32 running_sum = start;
+ int x0, x1;
+ int k;
+ int *alphatab;
+ int alpha;
+ const art_u8 *maskbuf;
+
+ linebuf = data->dst;
+ x0 = data->x0;
+ x1 = data->x1;
+
+ alphatab = data->alphatab;
+
+ maskbuf = data->mask + (y - data->y0) * (x1 - x0);
+
+ if(n_steps > 0)
+ {
+ run_x1 = steps[0].x;
+ if(run_x1 > x0)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgb_texture_mask_run(linebuf, maskbuf, x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+
+ for(k = 0; k < n_steps - 1; k++)
+ {
+ running_sum += steps[k].delta;
+ run_x0 = run_x1;
+ run_x1 = steps[k + 1].x;
+ if(run_x1 > run_x0)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgb_texture_mask_run(linebuf + (run_x0 - x0) * 3, maskbuf + (run_x0 - x0), run_x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+ }
+ running_sum += steps[k].delta;
+ if(x1 > run_x1)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgb_texture_mask_run(linebuf + (run_x1 - x0) * 3, maskbuf + (run_x1 - x0), run_x1, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+ }
+ else
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgb_texture_mask_run(linebuf, maskbuf, x0, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+
+ data->dst += data->dst_rowstride;
+}
+
+static
+void ksvg_art_rgba_texture_run(art_u8 *dst_p, int x0, int x1, int y, const double inv[6],
+ int alpha, const art_u8 *src, int src_rowstride, int src_width, int src_height)
+{
+ const art_u8 *src_p;
+ ArtPoint pt, src_pt;
+ int src_x, src_y;
+ int x;
+ int srcAlpha;
+
+ if(alpha > 255)
+ alpha = 255;
+
+ /* TODO: optimise and filter? */
+ pt.y = y + 0.5;
+
+ for(x = x0; x < x1; x++)
+ {
+ int s;
+ int d;
+ int tmp;
+ int tmp2;
+
+ pt.x = x + 0.5;
+
+ art_affine_point(&src_pt, &pt, inv);
+
+ src_x = (int)floor(src_pt.x);
+ src_y = (int)floor(src_pt.y);
+
+ if(src_x < 0)
+ {
+ /* Can't assume % behaviour with negative values */
+ src_x += ((src_x / -src_width) + 1) * src_width;
+ }
+
+ if(src_y < 0)
+ {
+ src_y += ((src_y / -src_height) + 1) * src_height;
+ }
+
+ src_x %= src_width;
+ src_y %= src_height;
+
+ src_p = src + (src_y * src_rowstride) + src_x * 4;
+
+ /* Pattern source is in RGBA format, premultiplied.
+ * alpha represents fill/stroke/group opacity.
+ *
+ * Multiply source alpha by 'alpha' then composite over.
+ * For each colour channel, d = d + alpha * (s - srcAlpha * d).
+ */
+
+ srcAlpha = src_p[3];
+
+ d = *dst_p;
+ s = *src_p++;
+
+ tmp = srcAlpha * d + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ tmp2 = alpha * (s - tmp) + 0x80;
+ tmp2 = (tmp2 + (tmp2 >> 8)) >> 8;
+
+ *dst_p++ = d + tmp2;
+
+ d = *dst_p;
+ s = *src_p++;
+
+ tmp = srcAlpha * d + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ tmp2 = alpha * (s - tmp) + 0x80;
+ tmp2 = (tmp2 + (tmp2 >> 8)) >> 8;
+
+ *dst_p++ = d + tmp2;
+
+ d = *dst_p;
+ s = *src_p++;
+
+ tmp = srcAlpha * d + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ tmp2 = alpha * (s - tmp) + 0x80;
+ tmp2 = (tmp2 + (tmp2 >> 8)) >> 8;
+
+ *dst_p++ = d + tmp2;
+
+ /* dstAlpha = dstAlpha + srcAlpha * alpha * (1 - dstAlpha) */
+ d = *dst_p;
+
+ tmp = srcAlpha * alpha + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ tmp2 = tmp * (255 - d) + 0x80;
+ tmp2 = (tmp2 + (tmp2 >> 8)) >> 8;
+
+ *dst_p++ = d + tmp2;
+ src_p++;
+ }
+}
+
+static void
+ksvg_art_rgba_texture_callback (void *callback_data, int y,
+ int start, ArtSVPRenderAAStep *steps, int n_steps)
+{
+ ksvgArtRgbAffineClipAlphaData *data = (ksvgArtRgbAffineClipAlphaData *)callback_data;
+ art_u8 *linebuf;
+ int run_x0, run_x1;
+ art_u32 running_sum = start;
+ int x0, x1;
+ int k;
+ int *alphatab;
+ int alpha;
+
+ linebuf = data->dst;
+ x0 = data->x0;
+ x1 = data->x1;
+
+ alphatab = data->alphatab;
+
+ if(n_steps > 0)
+ {
+ run_x1 = steps[0].x;
+ if(run_x1 > x0)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgba_texture_run(linebuf, x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+
+ for(k = 0; k < n_steps - 1; k++)
+ {
+ running_sum += steps[k].delta;
+ run_x0 = run_x1;
+ run_x1 = steps[k + 1].x;
+ if(run_x1 > run_x0)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgba_texture_run(linebuf + (run_x0 - x0) * 4, run_x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+ }
+ running_sum += steps[k].delta;
+ if(x1 > run_x1)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgba_texture_run(linebuf + (run_x1 - x0) * 4, run_x1, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+ }
+ else
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgba_texture_run(linebuf, x0, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+
+ data->dst += data->dst_rowstride;
+}
+
+static
+void ksvg_art_rgba_texture_mask_run(art_u8 *dst_p, const art_u8 *mask, int x0, int x1, int y, const double inv[6],
+ int alpha, const art_u8 *src, int src_rowstride, int src_width, int src_height)
+{
+ const art_u8 *src_p;
+ ArtPoint pt, src_pt;
+ int src_x, src_y;
+ int x;
+ int srcAlpha;
+
+ if(alpha > 255)
+ alpha = 255;
+
+ /* TODO: optimise and filter? */
+ pt.y = y + 0.5;
+
+ for(x = x0; x < x1; x++)
+ {
+ int s;
+ int d;
+ int am;
+ int tmp;
+ int tmp2;
+
+ pt.x = x + 0.5;
+
+ art_affine_point(&src_pt, &pt, inv);
+
+ src_x = (int)floor(src_pt.x);
+ src_y = (int)floor(src_pt.y);
+
+ if(src_x < 0)
+ {
+ /* Can't assume % behaviour with negative values */
+ src_x += ((src_x / -src_width) + 1) * src_width;
+ }
+
+ if(src_y < 0)
+ {
+ src_y += ((src_y / -src_height) + 1) * src_height;
+ }
+
+ src_x %= src_width;
+ src_y %= src_height;
+
+ src_p = src + (src_y * src_rowstride) + src_x * 4;
+
+ /* Pattern source is in RGBA format, premultiplied.
+ * alpha represents fill/stroke/group opacity.
+ *
+ * Multiply source alpha by 'alpha' and mask value then composite over.
+ * For each channel, d = d + alpha * mask * (s - srcAlpha * d).
+ */
+
+ am = (alpha * *mask++) + 0x80;
+ am = (am + (am >> 8)) >> 8;
+
+ srcAlpha = src_p[3];
+
+ d = *dst_p;
+ s = *src_p++;
+
+ tmp = srcAlpha * d + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ tmp2 = am * (s - tmp) + 0x80;
+ tmp2 = (tmp2 + (tmp2 >> 8)) >> 8;
+
+ *dst_p++ = d + tmp2;
+
+ d = *dst_p;
+ s = *src_p++;
+
+ tmp = srcAlpha * d + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ tmp2 = am * (s - tmp) + 0x80;
+ tmp2 = (tmp2 + (tmp2 >> 8)) >> 8;
+
+ *dst_p++ = d + tmp2;
+
+ d = *dst_p;
+ s = *src_p++;
+
+ tmp = srcAlpha * d + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ tmp2 = am * (s - tmp) + 0x80;
+ tmp2 = (tmp2 + (tmp2 >> 8)) >> 8;
+
+ *dst_p++ = d + tmp2;
+
+ /* dstAlpha = dstAlpha + srcAlpha * alpha * mask * (1 - dstAlpha) */
+ d = *dst_p;
+
+ tmp = srcAlpha * am + 0x80;
+ tmp = (tmp + (tmp >> 8)) >> 8;
+
+ tmp2 = tmp * (255 - d) + 0x80;
+ tmp2 = (tmp2 + (tmp2 >> 8)) >> 8;
+
+ *dst_p++ = d + tmp2;
+ src_p++;
+ }
+}
+
+static void
+ksvg_art_rgba_texture_mask_callback (void *callback_data, int y,
+ int start, ArtSVPRenderAAStep *steps, int n_steps)
+{
+ ksvgArtRgbAffineClipAlphaData *data = (ksvgArtRgbAffineClipAlphaData *)callback_data;
+ art_u8 *linebuf;
+ int run_x0, run_x1;
+ art_u32 running_sum = start;
+ int x0, x1;
+ int k;
+ int *alphatab;
+ int alpha;
+ const art_u8 *maskbuf;
+
+ linebuf = data->dst;
+ x0 = data->x0;
+ x1 = data->x1;
+
+ alphatab = data->alphatab;
+
+ maskbuf = data->mask + (y - data->y0) * (x1 - x0);
+
+ if(n_steps > 0)
+ {
+ run_x1 = steps[0].x;
+ if(run_x1 > x0)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgba_texture_mask_run(linebuf, maskbuf, x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+
+ for(k = 0; k < n_steps - 1; k++)
+ {
+ running_sum += steps[k].delta;
+ run_x0 = run_x1;
+ run_x1 = steps[k + 1].x;
+ if(run_x1 > run_x0)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgba_texture_mask_run(linebuf + (run_x0 - x0) * 4, maskbuf + (run_x0 - x0), run_x0, run_x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+ }
+ running_sum += steps[k].delta;
+ if(x1 > run_x1)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgba_texture_mask_run(linebuf + (run_x1 - x0) * 4, maskbuf + (run_x1 - x0), run_x1, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+ }
+ else
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ ksvg_art_rgba_texture_mask_run(linebuf, maskbuf, x0, x1, y, data->inv, alphatab[alpha], data->src, data->src_rowstride, data->src_width, data->src_height);
+ }
+
+ data->dst += data->dst_rowstride;
+}
+
+/**
+ * ksvg_art_rgb_texture: Affine transform source RGB image and composite, with clipping path.
+ * @svp: Clipping path.
+ * @dst: Destination image RGB buffer.
+ * @x0: Left coordinate of destination rectangle.
+ * @y0: Top coordinate of destination rectangle.
+ * @x1: Right coordinate of destination rectangle.
+ * @y1: Bottom coordinate of destination rectangle.
+ * @dst_rowstride: Rowstride of @dst buffer.
+ * @src: Source image RGB buffer.
+ * @src_width: Width of source image.
+ * @src_height: Height of source image.
+ * @src_rowstride: Rowstride of @src buffer.
+ * @affine: Affine transform.
+ * @level: Filter level.
+ * @alphagamma: #ArtAlphaGamma for gamma-correcting the compositing.
+ * @alpha: Alpha, range 0..256.
+ *
+ * Affine transform the source image stored in @src, compositing over
+ * the area of destination image @dst specified by the rectangle
+ * (@x0, @y0) - (@x1, @y1). As usual in libart, the left and top edges
+ * of this rectangle are included, and the right and bottom edges are
+ * excluded.
+ *
+ * The @alphagamma parameter specifies that the alpha compositing be done
+ * in a gamma-corrected color space. Since the source image is opaque RGB,
+ * this argument only affects the edges. In the current implementation,
+ * it is ignored.
+ *
+ * The @level parameter specifies the speed/quality tradeoff of the
+ * image interpolation. Currently, only ART_FILTER_NEAREST is
+ * implemented.
+ *
+ * KSVG additions : we have changed this function to support an alpha level as well.
+* also we made sure compositing an rgba image over an rgb buffer works.
+**/
+void ksvg_art_rgb_texture(const ArtSVP *svp, art_u8 *dst, int x0, int y0, int x1, int y1, int dst_rowstride,
+ int dst_channels,
+ const art_u8 *src,
+ int src_width, int src_height, int src_rowstride,
+ const double affine[6],
+ ArtFilterLevel level,
+ ArtAlphaGamma *alphaGamma,
+ int alpha,
+ const art_u8 *mask)
+{
+ ksvgArtRgbAffineClipAlphaData data;
+ int i;
+ int a, da;
+
+ data.alpha = alpha;
+
+ a = 0x8000;
+ da = (alpha * 66051 + 0x80) >> 8; /* 66051 equals 2 ^ 32 / (255 * 255) */
+
+ for(i = 0; i < 256; i++)
+ {
+ data.alphatab[i] = a >> 16;
+ a += da;
+ }
+
+ data.dst = dst;
+ data.dst_rowstride = dst_rowstride;
+ data.x0 = x0;
+ data.x1 = x1;
+
+ data.inv[0] = affine[0];
+ data.inv[1] = affine[1];
+ data.inv[2] = affine[2];
+ data.inv[3] = affine[3];
+ data.inv[4] = affine[4];
+ data.inv[5] = affine[5];
+
+ data.src = src;
+ data.src_width = src_width;
+ data.src_height = src_height;
+ data.src_rowstride = src_rowstride;
+
+ data.mask = mask;
+ data.y0 = y0;
+
+ if(mask)
+ {
+ if(dst_channels == 3)
+ art_svp_render_aa(svp, x0, y0, x1, y1, ksvg_art_rgb_texture_mask_callback, &data);
+ else
+ art_svp_render_aa(svp, x0, y0, x1, y1, ksvg_art_rgba_texture_mask_callback, &data);
+ }
+ else
+ {
+ if(dst_channels == 3)
+ art_svp_render_aa(svp, x0, y0, x1, y1, ksvg_art_rgb_texture_callback, &data);
+ else
+ art_svp_render_aa(svp, x0, y0, x1, y1, ksvg_art_rgba_texture_callback, &data);
+ }
+}
+
+/**
+ * ksvg_art_svp_move: moves an svp relatively to the current position.
+ * @svp: SVP to move.
+ * @dx: relative amount to move horizontally.
+ * @dy: relative amount to move vertically.
+ *
+ * Note : this function always moves the svp, not taking into account render buffer
+ * boundaries.
+ **/
+void ksvg_art_svp_move(ArtSVP *svp, int dx, int dy)
+{
+ int i, j;
+ ArtSVPSeg *seg;
+
+ if(dx == 0 && dy == 0) return;
+ for(i = 0;i < svp->n_segs;i++)
+ {
+ seg = &svp->segs[i];
+ for(j = 0;j < seg->n_points;j++)
+ {
+ seg->points[j].x += dx;
+ seg->points[j].y += dy;
+ }
+ seg->bbox.x0 += dx;
+ seg->bbox.y0 += dy;
+ seg->bbox.x1 += dx;
+ seg->bbox.y1 += dy;
+ }
+}
+
diff --git a/ksvg/impl/libs/art_support/art_misc.h b/ksvg/impl/libs/art_support/art_misc.h
new file mode 100644
index 00000000..52f09a63
--- /dev/null
+++ b/ksvg/impl/libs/art_support/art_misc.h
@@ -0,0 +1,79 @@
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __KSVG_ART_H__
+#define __KSVG_ART_H__
+
+#include <libart_lgpl/art_misc.h>
+#include <libart_lgpl/art_bpath.h>
+#include <libart_lgpl/art_vpath.h>
+#include <libart_lgpl/art_alphagamma.h>
+#include <libart_lgpl/art_filterlevel.h>
+#include <libart_lgpl/art_svp.h>
+
+#define ART_END2 10
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ void ksvg_art_vpath_render_bez (ArtVpath **p_vpath, int *pn, int *pn_max,
+ double x0, double y0,
+ double x1, double y1,
+ double x2, double y2,
+ double x3, double y3,
+ double flatness);
+
+ ArtVpath *ksvg_art_bez_path_to_vec(const ArtBpath *bez, double flatness);
+
+ void ksvg_art_rgb_affine_run (int *p_x0, int *p_x1, int y,
+ int src_width, int src_height,
+ const double affine[6]);
+
+ void ksvg_art_rgb_affine (art_u8 *dst, int x0, int y0, int x1, int y1, int dst_rowstride,
+ const art_u8 *src,
+ int src_width, int src_height, int src_rowstride,
+ const double affine[6],
+ ArtFilterLevel level,
+ ArtAlphaGamma *alphagamma,
+ int alpha);
+
+ void ksvg_art_rgb_affine_clip(const ArtSVP *svp, art_u8 *dst, int x0, int y0, int x1, int y1, int dst_rowstride, int dst_channels,
+ const art_u8 *src,
+ int src_width, int src_height, int src_rowstride,
+ const double affine[6],
+ int alpha, const art_u8 *mask);
+
+ void ksvg_art_rgb_texture(const ArtSVP *svp, art_u8 *dst, int x0, int y0, int x1, int y1, int dst_rowstride,
+ int dst_channels,
+ const art_u8 *src,
+ int src_width, int src_height, int src_rowstride,
+ const double affine[6],
+ ArtFilterLevel level,
+ ArtAlphaGamma *alphaGamma,
+ int alpha,
+ const art_u8 *mask);
+
+ void ksvg_art_svp_move(ArtSVP *svp, int dx, int dy);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/ksvg/impl/libs/art_support/art_render_misc.c b/ksvg/impl/libs/art_support/art_render_misc.c
new file mode 100644
index 00000000..1603da1e
--- /dev/null
+++ b/ksvg/impl/libs/art_support/art_render_misc.c
@@ -0,0 +1,774 @@
+/* This file is part of the KDE project.
+ * art_render_misc.c: Here I store some routines I feel should be in libart :)
+ *
+ * Copyright (C) 2001-2003 KSVG Team
+ *
+ * This code is adapted from :
+ *
+ * art_render_gradient.c: Gradient image source for modular rendering.
+ *
+ * Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 2000 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Authors: Raph Levien <raph@acm.org>
+ * Alexander Larsson <alla@lysator.liu.se>
+ */
+
+#include "config.h"
+#include "art_render_misc.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/* These are in KSVGHelper.cpp */
+int linearRGBFromsRGB(int sRGB8bit);
+int sRGBFromLinearRGB(int linearRGB8bit);
+
+typedef struct _ArtImageSourceGradRad ArtImageSourceGradRad;
+
+struct _ArtImageSourceGradRad {
+ ArtImageSource super;
+ const ArtKSVGGradientRadial *gradient;
+ double a;
+};
+
+#define EPSILON 1e-6
+
+/**
+ * art_ksvg_render_gradient_setpix: Set a gradient pixel.
+ * @render: The render object.
+ * @dst: Pointer to destination (where to store pixel).
+ * @n_stops: Number of stops in @stops.
+ * @stops: The stops for the gradient.
+ * @offset: The offset.
+ *
+ * @n_stops must be > 0.
+ *
+ * Sets a gradient pixel, storing it at @dst.
+ **/
+static void
+art_ksvg_render_gradient_setpix (ArtRender *render,
+ art_u8 *dst,
+ int n_stops, ArtGradientStop *stops,
+ double offset, ArtKSVGGradientInterpolation interpolation)
+{
+ int ix;
+ int j;
+ double off0, off1;
+ int n_ch = render->n_chan + 1;
+
+ for (ix = 0; ix < n_stops; ix++)
+ if (stops[ix].offset > offset)
+ break;
+ /* stops[ix - 1].offset < offset < stops[ix].offset */
+ if (ix > 0 && ix < n_stops)
+ {
+ off0 = stops[ix - 1].offset;
+ off1 = stops[ix].offset;
+ if (fabs (off1 - off0) > EPSILON)
+ {
+ double interp;
+
+ interp = (offset - off0) / (off1 - off0);
+ if(interpolation == ART_KSVG_LINEARRGB_INTERPOLATION)
+ {
+ for (j = 0; j < n_ch; j++)
+ {
+ int z0, z1;
+ int z;
+ int z0_8bit, z0_linearRGB_8bit;
+ int z1_8bit, z1_linearRGB_8bit;
+ int z_8bit, z_sRGB_8bit;
+
+ /* Note: Using explicit variables for intermediate steps since */
+ /* the ART_PIX macros reference the argument more than once. */
+ z0 = stops[ix - 1].color[j];
+ z0_8bit = ART_PIX_8_FROM_MAX(z0);
+ z0_linearRGB_8bit = linearRGBFromsRGB(z0_8bit);
+ z0 = ART_PIX_MAX_FROM_8(z0_linearRGB_8bit);
+
+ z1 = stops[ix].color[j];
+ z1_8bit = ART_PIX_8_FROM_MAX(z1);
+ z1_linearRGB_8bit = linearRGBFromsRGB(z1_8bit);
+ z1 = ART_PIX_MAX_FROM_8(z1_linearRGB_8bit);
+
+ z = floor (z0 + (z1 - z0) * interp + 0.5);
+ z_8bit = ART_PIX_8_FROM_MAX(z);
+ z_sRGB_8bit = sRGBFromLinearRGB(z_8bit);
+
+ if (render->buf_depth == 8)
+ dst[j] = z_sRGB_8bit;
+ else /* (render->buf_depth == 16) */
+ ((art_u16 *)dst)[j] = ART_PIX_MAX_FROM_8(z_sRGB_8bit);
+ }
+ }
+ else
+ {
+ /* sRGB interpolation */
+ for (j = 0; j < n_ch; j++)
+ {
+ int z0, z1;
+ int z;
+ z0 = stops[ix - 1].color[j];
+ z1 = stops[ix].color[j];
+ z = floor (z0 + (z1 - z0) * interp + 0.5);
+ if (render->buf_depth == 8)
+ dst[j] = ART_PIX_8_FROM_MAX (z);
+ else /* (render->buf_depth == 16) */
+ ((art_u16 *)dst)[j] = z;
+ }
+ }
+ return;
+ }
+ }
+ else if (ix == n_stops)
+ ix--;
+
+ for (j = 0; j < n_ch; j++)
+ {
+ int z;
+ z = stops[ix].color[j];
+ if (render->buf_depth == 8)
+ dst[j] = ART_PIX_8_FROM_MAX (z);
+ else /* (render->buf_depth == 16) */
+ ((art_u16 *)dst)[j] = z;
+ }
+}
+
+static void
+art_ksvg_render_gradient_radial_done (ArtRenderCallback *self, ArtRender *render)
+{
+ art_free (self);
+}
+
+static void
+art_ksvg_render_gradient_radial_render (ArtRenderCallback *self, ArtRender *render,
+ art_u8 *dest, int y)
+{
+ ArtImageSourceGradRad *z = (ArtImageSourceGradRad *)self;
+ const ArtKSVGGradientRadial *gradient = z->gradient;
+ int pixstride = (render->n_chan + 1) * (render->depth >> 3);
+ int x;
+ int x0 = render->x0;
+ int width = render->x1 - x0;
+ int n_stops = gradient->n_stops;
+ ArtGradientStop *stops = gradient->stops;
+ art_u8 *bufp = render->image_buf;
+ double fx = gradient->fx;
+ double fy = gradient->fy;
+ double dx, dy;
+ double *affine = gradient->affine;
+ double aff0 = affine[0];
+ double aff1 = affine[1];
+ const double a = z->a;
+ const double arecip = 1.0 / a;
+ double b, db;
+ double c, dc, ddc;
+ double b_a, db_a;
+ double rad, drad, ddrad;
+ ArtGradientSpread spread = gradient->spread;
+
+ dx = x0 * aff0 + y * affine[2] + affine[4] - fx;
+ dy = x0 * aff1 + y * affine[3] + affine[5] - fy;
+ b = dx * fx + dy * fy;
+ db = aff0 * fx + aff1 * fy;
+ c = dx * dx + dy * dy;
+ dc = 2 * aff0 * dx + aff0 * aff0 + 2 * aff1 * dy + aff1 * aff1;
+ ddc = 2 * aff0 * aff0 + 2 * aff1 * aff1;
+
+ b_a = b * arecip;
+ db_a = db * arecip;
+
+ rad = b_a * b_a + c * arecip;
+ drad = 2 * b_a * db_a + db_a * db_a + dc * arecip;
+ ddrad = 2 * db_a * db_a + ddc * arecip;
+
+ for (x = 0; x < width; x++)
+ {
+ double z;
+
+ if (rad > 0)
+ z = b_a + sqrt (rad);
+ else
+ z = b_a;
+
+ if (spread == ART_GRADIENT_REPEAT)
+ z = z - floor (z);
+ else if (spread == ART_GRADIENT_REFLECT)
+ {
+ double tmp;
+
+ tmp = z - 2 * floor (0.5 * z);
+ z = tmp > 1 ? 2 - tmp : tmp;
+ }
+
+ art_ksvg_render_gradient_setpix (render, bufp, n_stops, stops, z, gradient->interpolation);
+ bufp += pixstride;
+ b_a += db_a;
+ rad += drad;
+ drad += ddrad;
+ }
+}
+
+static void
+art_ksvg_render_gradient_radial_negotiate (ArtImageSource *self, ArtRender *render,
+ ArtImageSourceFlags *p_flags,
+ int *p_buf_depth, ArtAlphaType *p_alpha)
+{
+ self->super.render = art_ksvg_render_gradient_radial_render;
+ *p_flags = 0;
+ *p_buf_depth = render->depth;
+ *p_alpha = ART_ALPHA_SEPARATE;
+}
+
+/**
+ * art_ksvg_render_gradient_radial: Add a radial gradient image source.
+ * @render: The render object.
+ * @gradient: The radial gradient.
+ *
+ * Adds the radial gradient @gradient as the image source for rendering
+ * in the render object @render.
+ **/
+void
+art_ksvg_render_gradient_radial (ArtRender *render,
+ const ArtKSVGGradientRadial *gradient,
+ ArtFilterLevel level)
+{
+ ArtImageSourceGradRad *image_source = art_new (ArtImageSourceGradRad, 1);
+ double fx = gradient->fx;
+ double fy = gradient->fy;
+
+ image_source->super.super.render = NULL;
+ image_source->super.super.done = art_ksvg_render_gradient_radial_done;
+ image_source->super.negotiate = art_ksvg_render_gradient_radial_negotiate;
+
+ image_source->gradient = gradient;
+ /* todo: sanitycheck fx, fy? */
+ image_source->a = 1 - fx * fx - fy * fy;
+
+ art_render_add_image_source (render, &image_source->super);
+}
+
+
+/* Hack to find out how to define alloca on different platforms.
+ * Modified version of glib/galloca.h.
+ */
+
+#ifdef __GNUC__
+/* GCC does the right thing */
+ #undef alloca
+ #define alloca(size) __builtin_alloca (size)
+#elif defined (HAVE_ALLOCA_H)
+/* a native and working alloca.h is there */
+ #include <alloca.h>
+#else /* !__GNUC__ && !HAVE_ALLOCA_H */
+ #ifdef _MSC_VER
+ #include <malloc.h>
+ #define alloca _alloca
+ #else /* !_MSC_VER */
+ #ifdef _AIX
+ #pragma alloca
+ #else /* !_AIX */
+ #ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+ #endif /* !alloca */
+ #endif /* !_AIX */
+ #endif /* !_MSC_VER */
+#endif /* !__GNUC__ && !HAVE_ALLOCA_H */
+
+#undef DEBUG_SPEW
+
+typedef struct _ArtImageSourceGradLin ArtImageSourceGradLin;
+
+/* The stops will be copied right after this structure */
+struct _ArtImageSourceGradLin
+{
+ ArtImageSource super;
+ ArtKSVGGradientLinear gradient;
+ ArtGradientStop stops[1];
+};
+
+#ifndef MAX
+ #define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif /* MAX */
+
+#ifndef MIN
+ #define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif /* MIN */
+
+static void
+art_ksvg_rgba_gradient_run (art_u8 *buf,
+ art_u8 *color1,
+ art_u8 *color2,
+ int len)
+{
+ int i;
+ int r, g, b, a;
+ int dr, dg, db, da;
+
+#ifdef DEBUG_SPEW
+ printf ("gradient run from %3d %3d %3d %3d to %3d %3d %3d %3d in %d pixels\n",
+ color1[0], color1[1], color1[2], color1[3],
+ color2[0], color2[1], color2[2], color2[3],
+ len);
+#endif
+
+ r = (color1[0] << 16) + 0x8000;
+ g = (color1[1] << 16) + 0x8000;
+ b = (color1[2] << 16) + 0x8000;
+ a = (color1[3] << 16) + 0x8000;
+ dr = ((color2[0] - color1[0]) << 16) / len;
+ dg = ((color2[1] - color1[1]) << 16) / len;
+ db = ((color2[2] - color1[2]) << 16) / len;
+ da = ((color2[3] - color1[3]) << 16) / len;
+
+ for(i = 0; i < len; i++)
+ {
+ *buf++ = (r>>16);
+ *buf++ = (g>>16);
+ *buf++ = (b>>16);
+ *buf++ = (a>>16);
+
+ r += dr;
+ g += dg;
+ b += db;
+ a += da;
+ }
+}
+
+static void
+ksvg_calc_color_at (ArtGradientStop *stops,
+ int n_stops,
+ ArtGradientSpread spread,
+ double offset,
+ double offset_fraction,
+ int favor_start,
+ int ix,
+ art_u8 *color)
+{
+ double off0, off1;
+ int j;
+
+ if(spread == ART_GRADIENT_PAD)
+ {
+ if(offset < EPSILON)
+ {
+ color[0] = ART_PIX_8_FROM_MAX (stops[0].color[0]);
+ color[1] = ART_PIX_8_FROM_MAX (stops[0].color[1]);
+ color[2] = ART_PIX_8_FROM_MAX (stops[0].color[2]);
+ color[3] = ART_PIX_8_FROM_MAX (stops[0].color[3]);
+ return;
+ }
+ if(offset >= 1.0 - EPSILON)
+ {
+ color[0] = ART_PIX_8_FROM_MAX (stops[n_stops-1].color[0]);
+ color[1] = ART_PIX_8_FROM_MAX (stops[n_stops-1].color[1]);
+ color[2] = ART_PIX_8_FROM_MAX (stops[n_stops-1].color[2]);
+ color[3] = ART_PIX_8_FROM_MAX (stops[n_stops-1].color[3]);
+ return;
+ }
+ }
+
+ if(ix > 0 && ix < n_stops)
+ {
+ off0 = stops[ix - 1].offset;
+ off1 = stops[ix].offset;
+ if(fabs (off1 - off0) > EPSILON)
+ {
+ double interp;
+ double o;
+ o = offset_fraction;
+
+ if((fabs (o) < EPSILON) && (!favor_start))
+ o = 1.0;
+ else if((fabs (o-1.0) < EPSILON) && (favor_start))
+ o = 0.0;
+
+ /*
+ if (offset_fraction == 0.0 && !favor_start)
+ offset_fraction = 1.0;
+ */
+
+ interp = (o - off0) / (off1 - off0);
+ for(j = 0; j < 4; j++)
+ {
+ int z0, z1;
+ int z;
+ z0 = stops[ix - 1].color[j];
+ z1 = stops[ix].color[j];
+ z = floor (z0 + (z1 - z0) * interp + 0.5);
+ color[j] = ART_PIX_8_FROM_MAX (z);
+ }
+ return;
+ }
+ /* If offsets are too close to safely do the division, just
+ pick the ix color. */
+ color[0] = ART_PIX_8_FROM_MAX (stops[ix].color[0]);
+ color[1] = ART_PIX_8_FROM_MAX (stops[ix].color[1]);
+ color[2] = ART_PIX_8_FROM_MAX (stops[ix].color[2]);
+ color[3] = ART_PIX_8_FROM_MAX (stops[ix].color[3]);
+ return;
+ }
+
+ /*printf ("WARNING! bad ix %d in calc_color_at() [internal error]\n", ix);
+ assert (0);*/
+}
+
+static void
+art_ksvg_render_gradient_linear_render_8 (ArtRenderCallback *self,
+ ArtRender *render,
+ art_u8 *dest, int y)
+{
+ ArtImageSourceGradLin *z = (ArtImageSourceGradLin *)self;
+ const ArtKSVGGradientLinear *gradient = &(z->gradient);
+ int i;
+ int width = render->x1 - render->x0;
+ int len;
+ double offset, d_offset;
+ double offset_fraction;
+ int next_stop;
+ int ix;
+ art_u8 color1[4], color2[4];
+ int n_stops = gradient->n_stops;
+ int extra_stops;
+ ArtGradientStop *stops = gradient->stops;
+ ArtGradientStop *tmp_stops;
+ art_u8 *bufp = render->image_buf;
+ ArtGradientSpread spread = gradient->spread;
+
+#ifdef DEBUG_SPEW
+ printf ("x1: %d, x2: %d, y: %d\n", render->x0, render->x1, y);
+ printf ("spread: %d, stops:", gradient->spread);
+ for(i=0;i<n_stops;i++)
+ {
+ printf ("%f, ", gradient->stops[i].offset);
+ }
+ printf ("\n");
+ printf ("a: %f, b: %f, c: %f\n", gradient->a, gradient->b, gradient->c);
+#endif
+
+ offset = render->x0 * gradient->affine[0] + y * gradient->affine[2] + gradient->affine[4];
+ d_offset = gradient->affine[0];
+
+ /* We need to force the gradient to extend the whole 0..1 segment,
+ because the rest of the code doesn't handle partial gradients
+ correctly */
+ if((gradient->stops[0].offset > EPSILON /* == 0.0 */) ||
+ (gradient->stops[n_stops-1].offset < (1.0 - EPSILON)))
+ {
+ extra_stops = 0;
+ tmp_stops = stops = alloca (sizeof (ArtGradientStop) * (n_stops + 2));
+ if(gradient->stops[0].offset > EPSILON /* 0.0 */)
+ {
+ memcpy (tmp_stops, gradient->stops, sizeof (ArtGradientStop));
+ tmp_stops[0].offset = 0.0;
+ tmp_stops += 1;
+ extra_stops++;
+ }
+ memcpy (tmp_stops, gradient->stops, sizeof (ArtGradientStop) * n_stops);
+ if(gradient->stops[n_stops-1].offset < (1.0 - EPSILON))
+ {
+ tmp_stops += n_stops;
+ memcpy (tmp_stops, &gradient->stops[n_stops-1], sizeof (ArtGradientStop));
+ tmp_stops[0].offset = 1.0;
+ extra_stops++;
+ }
+ n_stops += extra_stops;
+
+
+#ifdef DEBUG_SPEW
+ printf ("start/stop modified stops:");
+ for(i=0;i<n_stops;i++)
+ {
+ printf ("%f, ", stops[i].offset);
+ }
+ printf ("\n");
+#endif
+
+ }
+
+ if(spread == ART_GRADIENT_REFLECT)
+ {
+ tmp_stops = stops;
+ stops = alloca (sizeof (ArtGradientStop) * n_stops * 2);
+ memcpy (stops, tmp_stops, sizeof (ArtGradientStop) * n_stops);
+
+ for(i = 0; i< n_stops; i++)
+ {
+ stops[n_stops * 2 - 1 - i].offset = (1.0 - stops[i].offset / 2.0);
+ memcpy (stops[n_stops * 2 - 1 - i].color, stops[i].color, sizeof (stops[i].color));
+ stops[i].offset = stops[i].offset / 2.0;
+ }
+
+ spread = ART_GRADIENT_REPEAT;
+ offset = offset / 2.0;
+ d_offset = d_offset / 2.0;
+
+ n_stops = 2 * n_stops;
+
+#ifdef DEBUG_SPEW
+ printf ("reflect modified stops:");
+ for(i=0;i<n_stops;i++)
+ {
+ printf ("%f, ", stops[i].offset);
+ }
+ printf ("\n");
+#endif
+ }
+
+ offset_fraction = offset - floor (offset);
+#ifdef DEBUG_SPEW
+ printf ("inital offset: %f, fraction: %f d_offset: %f\n", offset, offset_fraction, d_offset);
+#endif
+ /* ix is selected so that offset_fraction is
+ stops[ix-1] <= offset_fraction <= stops[ix]
+ If offset_fraction is equal to one of the edges, ix
+ is selected so the the section of the line extending
+ in the same direction as d_offset is between ix-1 and ix.
+ */
+ for(ix = 0; ix < n_stops; ix++)
+ if(stops[ix].offset > offset_fraction ||
+ (d_offset < 0.0 && fabs (stops[ix].offset - offset_fraction) < EPSILON))
+ break;
+ if(ix == 0)
+ ix = n_stops - 1;
+ else if(ix == n_stops)
+ ix = n_stops - 1;
+
+#ifdef DEBUG_SPEW
+ printf ("Initial ix: %d\n", ix);
+#endif
+#if 0
+ assert (ix > 0);
+ assert (ix < n_stops);
+ assert ((stops[ix-1].offset <= offset_fraction + EPSILON) ||
+ ((stops[ix].offset > (1.0 - EPSILON)) && (offset_fraction < EPSILON /* == 0.0*/)));
+ /*assert (offset_fraction <= stops[ix].offset);*/
+ /* FIXME: These asserts may be broken, it is for now
+ safer to not use them. Should be fixed!
+ See bug #121850
+ assert ((offset_fraction != stops[ix-1].offset) ||
+ (d_offset >= 0.0));
+ assert ((offset_fraction != stops[ix].offset) ||
+ (d_offset <= 0.0));
+ */
+#endif
+ while(width > 0)
+ {
+#ifdef DEBUG_SPEW
+ printf ("ix: %d\n", ix);
+ printf ("start offset: %f\n", offset);
+#endif
+ ksvg_calc_color_at (stops, n_stops,
+ spread,
+ offset,
+ offset_fraction,
+ (d_offset > -EPSILON),
+ ix,
+ color1);
+
+ if(d_offset > 0)
+ next_stop = ix;
+ else
+ next_stop = ix-1;
+
+#ifdef DEBUG_SPEW
+ printf ("next_stop: %d\n", next_stop);
+#endif
+ if(fabs (d_offset) > EPSILON)
+ {
+ double o;
+ o = offset_fraction;
+
+ if((fabs (o) <= EPSILON) && (ix == n_stops - 1))
+ o = 1.0;
+ else if((fabs (o-1.0) <= EPSILON) && (ix == 1))
+ o = 0.0;
+
+#ifdef DEBUG_SPEW
+ printf ("o: %f\n", o);
+#endif
+ len = (int)floor (fabs ((stops[next_stop].offset - o) / d_offset)) + 1;
+ len = MAX (len, 0);
+ len = MIN (len, width);
+ }
+ else
+ {
+ len = width;
+ }
+#ifdef DEBUG_SPEW
+ printf ("len: %d\n", len);
+#endif
+ if(len > 0)
+ {
+ offset = offset + (len-1) * d_offset;
+ offset_fraction = offset - floor (offset);
+#ifdef DEBUG_SPEW
+ printf ("end offset: %f, fraction: %f\n", offset, offset_fraction);
+#endif
+ ksvg_calc_color_at (stops, n_stops,
+ spread,
+ offset,
+ offset_fraction,
+ (d_offset < EPSILON),
+ ix,
+ color2);
+
+ art_ksvg_rgba_gradient_run (bufp,
+ color1,
+ color2,
+ len);
+ offset += d_offset;
+ offset_fraction = offset - floor (offset);
+ }
+
+ if(d_offset > 0)
+ {
+ do
+ {
+ ix++;
+ if(ix == n_stops)
+ ix = 1;
+ /* Note: offset_fraction can actually be one here on x86 machines that
+ does calculations with extended precision, but later rounds to 64bit.
+ This happens if the 80bit offset_fraction is larger than the
+ largest 64bit double that is less than one.
+ */
+ }
+ while(!((stops[ix-1].offset <= offset_fraction &&
+ offset_fraction < stops[ix].offset) ||
+ (ix == 1 && offset_fraction > (1.0 - EPSILON))));
+ }
+ else
+ {
+ do
+ {
+ ix--;
+ if(ix == 0)
+ ix = n_stops - 1;
+ }
+ while(!((stops[ix-1].offset < offset_fraction &&
+ offset_fraction <= stops[ix].offset) ||
+ (ix == n_stops - 1 && offset_fraction < EPSILON /* == 0.0*/)));
+ }
+
+ bufp += 4*len;
+ width -= len;
+ }
+}
+
+static void
+art_ksvg_render_gradient_linear_done (ArtRenderCallback *self, ArtRender *render)
+{
+ art_free (self);
+}
+
+static void
+art_ksvg_render_gradient_linear_render (ArtRenderCallback *self, ArtRender *render,
+ art_u8 *dest, int y)
+{
+ ArtImageSourceGradLin *z = (ArtImageSourceGradLin *)self;
+ const ArtKSVGGradientLinear *gradient = &(z->gradient);
+ int pixstride = (render->n_chan + 1) * (render->depth >> 3);
+ int x;
+ int width = render->x1 - render->x0;
+ double offset, d_offset;
+ double actual_offset;
+ int n_stops = gradient->n_stops;
+ ArtGradientStop *stops = gradient->stops;
+ art_u8 *bufp = render->image_buf;
+ ArtGradientSpread spread = gradient->spread;
+
+ offset = render->x0 * gradient->affine[0] + y * gradient->affine[2] + gradient->affine[4];
+ d_offset = gradient->affine[0];
+
+ for(x = 0; x < width; x++)
+ {
+ if(spread == ART_GRADIENT_PAD)
+ actual_offset = offset;
+ else if(spread == ART_GRADIENT_REPEAT)
+ actual_offset = offset - floor (offset);
+ else /* (spread == ART_GRADIENT_REFLECT) */
+ {
+ double tmp;
+
+ tmp = offset - 2 * floor (0.5 * offset);
+ actual_offset = tmp > 1 ? 2 - tmp : tmp;
+ }
+ art_ksvg_render_gradient_setpix (render, bufp, n_stops, stops, actual_offset, gradient->interpolation);
+ offset += d_offset;
+ bufp += pixstride;
+ }
+}
+
+static void
+art_ksvg_render_gradient_linear_negotiate (ArtImageSource *self, ArtRender *render,
+ ArtImageSourceFlags *p_flags,
+ int *p_buf_depth, ArtAlphaType *p_alpha)
+{
+ ArtImageSourceGradLin *z = (ArtImageSourceGradLin *)self;
+
+ if(render->depth == 8 &&
+ render->n_chan == 3 &&
+ z->gradient.interpolation == ART_KSVG_SRGB_INTERPOLATION)
+ {
+ /* The optimised renderer doesn't support linearRGB interpolation at the moment */
+ /* so we only use it for sRGB, which is more common anyway. */
+ self->super.render = art_ksvg_render_gradient_linear_render_8;
+ *p_flags = 0;
+ *p_buf_depth = 8;
+ *p_alpha = ART_ALPHA_SEPARATE;
+ return;
+ }
+
+ self->super.render = art_ksvg_render_gradient_linear_render;
+ *p_flags = 0;
+ *p_buf_depth = render->depth;
+ *p_alpha = ART_ALPHA_SEPARATE;
+}
+
+/**
+ * art_render_gradient_linear: Add a linear gradient image source.
+ * @render: The render object.
+ * @gradient: The linear gradient.
+ *
+ * Adds the linear gradient @gradient as the image source for rendering
+ * in the render object @render.
+ **/
+void
+art_ksvg_render_gradient_linear (ArtRender *render,
+ const ArtKSVGGradientLinear *gradient,
+ ArtFilterLevel level)
+{
+ ArtImageSourceGradLin *image_source = art_alloc (sizeof (ArtImageSourceGradLin) +
+ sizeof (ArtGradientStop) * (gradient->n_stops - 1));
+
+ image_source->super.super.render = NULL;
+ image_source->super.super.done = art_ksvg_render_gradient_linear_done;
+ image_source->super.negotiate = art_ksvg_render_gradient_linear_negotiate;
+
+ /* copy the gradient into the structure */
+ image_source->gradient = *gradient;
+ image_source->gradient.stops = image_source->stops;
+ memcpy (image_source->gradient.stops, gradient->stops, sizeof (ArtGradientStop) * gradient->n_stops);
+
+ art_render_add_image_source (render, &image_source->super);
+}
+
diff --git a/ksvg/impl/libs/art_support/art_render_misc.h b/ksvg/impl/libs/art_support/art_render_misc.h
new file mode 100644
index 00000000..d1f3690b
--- /dev/null
+++ b/ksvg/impl/libs/art_support/art_render_misc.h
@@ -0,0 +1,90 @@
+/* This file is part of the KDE project.
+ * art_render_misc.c: Here I store some routines I feel should be in libart :)
+ *
+ * Copyright (C) 2001-2002 KSVG Team
+ *
+ * This code is adapted from :
+ *
+ * art_render_gradient.h: Gradient image source for modular rendering.
+ *
+ * Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 2000 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Authors: Raph Levien <raph@acm.org>
+ * Alexander Larsson <alla@lysator.liu.se>
+ */
+
+#ifndef __ART_RENDER_MISC_H__
+#define __ART_RENDER_MISC_H__
+
+#ifdef LIBART_COMPILATION
+#include "art_filterlevel.h"
+#include "art_render.h"
+#include "art_render_gradient.h"
+#else
+#include <libart_lgpl/art_filterlevel.h>
+#include <libart_lgpl/art_render.h>
+#include <libart_lgpl/art_render_gradient.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef enum
+{
+ ART_KSVG_SRGB_INTERPOLATION,
+ ART_KSVG_LINEARRGB_INTERPOLATION
+} ArtKSVGGradientInterpolation;
+
+typedef struct _ArtKSVGGradientRadial ArtKSVGGradientRadial;
+
+struct _ArtKSVGGradientRadial {
+ double affine[6]; /* transforms user coordinates to unit circle */
+ double fx, fy; /* focal point in unit circle coords */
+ int n_stops;
+ ArtGradientSpread spread;
+ ArtGradientStop *stops;
+ ArtKSVGGradientInterpolation interpolation;
+};
+
+void
+art_ksvg_render_gradient_radial (ArtRender *render,
+ const ArtKSVGGradientRadial *gradient,
+ ArtFilterLevel level);
+
+typedef struct _ArtKSVGGradientLinear ArtKSVGGradientLinear;
+
+struct _ArtKSVGGradientLinear {
+ double affine[6]; /* transforms screen gradient vector to unit vector (1, 0) */
+ ArtGradientSpread spread;
+ int n_stops;
+ ArtGradientStop *stops;
+ ArtKSVGGradientInterpolation interpolation;
+};
+
+void
+art_ksvg_render_gradient_linear (ArtRender *render,
+ const ArtKSVGGradientLinear *gradient,
+ ArtFilterLevel level);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_RENDER_MISC_H__ */
diff --git a/ksvg/impl/libs/art_support/art_rgba_svp.c b/ksvg/impl/libs/art_support/art_rgba_svp.c
new file mode 100644
index 00000000..47c7d924
--- /dev/null
+++ b/ksvg/impl/libs/art_support/art_rgba_svp.c
@@ -0,0 +1,659 @@
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* Render a sorted vector path into an RGB buffer. */
+
+#include <X11/Xos.h>
+
+#include "art_rgba_svp.h"
+
+#include <libart_lgpl/art_svp.h>
+#include <libart_lgpl/art_svp_render_aa.h>
+#include <libart_lgpl/art_rgba.h>
+#include <libart_lgpl/art_rgb.h>
+
+/* RGBA renderers */
+
+typedef struct _ArtKSVGRgbaSVPAlphaData ArtKSVGRgbaSVPAlphaData;
+
+struct _ArtKSVGRgbaSVPAlphaData {
+ int alphatab[256];
+ art_u8 r, g, b, alpha;
+ art_u32 rgba;
+ art_u8 *buf;
+ art_u8 *mask;
+ int rowstride;
+ int x0, x1;
+ int y0;
+};
+
+/**
+ * art_rgba_fill_run: fill an RGBA buffer a solid RGB color.
+ * @buf: Buffer to fill.
+ * @r: Red, range 0..255.
+ * @g: Green, range 0..255.
+ * @b: Blue, range 0..255.
+ * @n: Number of RGB triples to fill.
+ *
+ * Fills a buffer with @n copies of the (@r, @g, @b) triple, solid
+ * alpha. Thus, locations @buf (inclusive) through @buf + 4 * @n
+ * (exclusive) are written.
+ **/
+static void
+art_ksvg_rgba_fill_run (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, int n)
+{
+ int i;
+#if X_BYTE_ORDER == X_BIG_ENDIAN
+ art_u32 src_rgba;
+#else
+ art_u32 src_abgr;
+#endif
+
+#if X_BYTE_ORDER == X_BIG_ENDIAN
+ src_rgba = (r << 24) | (g << 16) | (b << 8) | 255;
+#else
+ src_abgr = (255 << 24) | (b << 16) | (g << 8) | r;
+#endif
+ for(i = 0; i < n; i++)
+ {
+#if X_BYTE_ORDER == X_BIG_ENDIAN
+ ((art_u32 *)buf)[i] = src_rgba;
+#else
+ ((art_u32 *)buf)[i] = src_abgr;
+#endif
+ }
+}
+
+/**
+ * art_rgba_run_alpha: Render semitransparent color over RGBA buffer.
+ * @buf: Buffer for rendering.
+ * @r: Red, range 0..255.
+ * @g: Green, range 0..255.
+ * @b: Blue, range 0..255.
+ * @alpha: Alpha, range 0..255.
+ * @n: Number of RGB triples to render.
+ *
+ * Renders a sequential run of solid (@r, @g, @b) color over @buf with
+ * opacity @alpha. Note that the range of @alpha is 0..255, in contrast
+ * to art_rgb_run_alpha, which has a range of 0..256.
+ **/
+static void
+art_ksvg_rgba_run_alpha (art_u8 *buf, art_u8 r, art_u8 g, art_u8 b, int alpha, int n)
+{
+ int i;
+ int v;
+ int tmp;
+
+ if(alpha > 255)
+ alpha = 255;
+
+ for(i = 0; i < n; i++)
+ {
+ v = *buf;
+ tmp = (r - v) * alpha + 0x80;
+ *buf++ = v + ((tmp + (tmp >> 8)) >> 8);
+
+ v = *buf;
+ tmp = (g - v) * alpha + 0x80;
+ *buf++ = v + ((tmp + (tmp >> 8)) >> 8);
+
+ v = *buf;
+ tmp = (b - v) * alpha + 0x80;
+ *buf++ = v + ((tmp + (tmp >> 8)) >> 8);
+
+ v = *buf;
+ tmp = (255 - alpha) * v + 0x80;
+ *buf++ = alpha + ((tmp + (tmp >> 8)) >> 8);
+ }
+}
+
+static void
+art_ksvg_rgba_mask_run_alpha (art_u8 *buf, art_u8 *mask, art_u8 r, art_u8 g, art_u8 b, int alpha, int n)
+{
+ int i;
+ int v;
+ int am;
+ int tmp;
+
+ if(alpha > 255)
+ alpha = 255;
+
+ for(i = 0; i < n; i++)
+ {
+ am = (alpha * *mask++) + 0x80;
+ am = (am + (am >> 8)) >> 8;
+
+ v = *buf;
+ tmp = (r - v) * am + 0x80;
+ *buf++ = v + ((tmp + (tmp >> 8)) >> 8);
+
+ v = *buf;
+ tmp = (g - v) * am + 0x80;
+ *buf++ = v + ((tmp + (tmp >> 8)) >> 8);
+
+ v = *buf;
+ tmp = (b - v) * am + 0x80;
+ *buf++ = v + ((tmp + (tmp >> 8)) >> 8);
+
+ v = *buf;
+ tmp = (255 - am) * v + 0x80;
+ *buf++ = am + ((tmp + (tmp >> 8)) >> 8);
+ }
+}
+
+static void
+art_ksvg_rgba_svp_alpha_callback(void *callback_data, int y,
+ int start, ArtSVPRenderAAStep *steps, int n_steps)
+{
+ ArtKSVGRgbaSVPAlphaData *data = (ArtKSVGRgbaSVPAlphaData *)callback_data;
+ art_u8 *linebuf;
+ int run_x0, run_x1;
+ art_u32 running_sum = start;
+ int x0, x1;
+ int k;
+ art_u8 r, g, b;
+ int *alphatab;
+ int alpha;
+
+ linebuf = data->buf;
+ x0 = data->x0;
+ x1 = data->x1;
+
+ r = data->r;
+ g = data->g;
+ b = data->b;
+ alphatab = data->alphatab;
+
+ if (n_steps > 0)
+ {
+ run_x1 = steps[0].x;
+ if (run_x1 > x0)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if (alpha)
+ art_ksvg_rgba_run_alpha (linebuf,
+ r, g, b, alphatab[alpha],
+ run_x1 - x0);
+ }
+
+ for (k = 0; k < n_steps - 1; k++)
+ {
+ running_sum += steps[k].delta;
+ run_x0 = run_x1;
+ run_x1 = steps[k + 1].x;
+ if (run_x1 > run_x0)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if (alpha)
+ art_ksvg_rgba_run_alpha (linebuf + (run_x0 - x0) * 4,
+ r, g, b, alphatab[alpha],
+ run_x1 - run_x0);
+ }
+ }
+ running_sum += steps[k].delta;
+ if (x1 > run_x1)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if (alpha)
+ art_ksvg_rgba_run_alpha (linebuf + (run_x1 - x0) * 4,
+ r, g, b, alphatab[alpha],
+ x1 - run_x1);
+ }
+ }
+ else
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if (alpha)
+ art_ksvg_rgba_run_alpha (linebuf,
+ r, g, b, alphatab[alpha],
+ x1 - x0);
+ }
+
+ data->buf += data->rowstride;
+}
+
+static void
+art_ksvg_rgba_svp_alpha_opaque_callback(void *callback_data, int y,
+ int start,
+ ArtSVPRenderAAStep *steps, int n_steps)
+{
+ ArtKSVGRgbaSVPAlphaData *data = (ArtKSVGRgbaSVPAlphaData *)callback_data;
+ art_u8 *linebuf;
+ int run_x0, run_x1;
+ art_u32 running_sum = start;
+ int x0, x1;
+ int k;
+ art_u8 r, g, b;
+ art_u32 rgba;
+ int *alphatab;
+ int alpha;
+
+ linebuf = data->buf;
+ x0 = data->x0;
+ x1 = data->x1;
+
+ r = data->r;
+ g = data->g;
+ b = data->b;
+ rgba = data->rgba;
+ alphatab = data->alphatab;
+
+ if (n_steps > 0)
+ {
+ run_x1 = steps[0].x;
+ if (run_x1 > x0)
+ {
+ alpha = running_sum >> 16;
+ if (alpha)
+ {
+ if (alpha >= 255)
+ art_ksvg_rgba_fill_run (linebuf,
+ r, g, b,
+ run_x1 - x0);
+ else
+ art_ksvg_rgba_run_alpha (linebuf,
+ r, g, b, alphatab[alpha],
+ run_x1 - x0);
+ }
+ }
+
+ for (k = 0; k < n_steps - 1; k++)
+ {
+ running_sum += steps[k].delta;
+ run_x0 = run_x1;
+ run_x1 = steps[k + 1].x;
+ if (run_x1 > run_x0)
+ {
+ alpha = running_sum >> 16;
+ if (alpha)
+ {
+ if (alpha >= 255)
+ art_ksvg_rgba_fill_run (linebuf + (run_x0 - x0) * 4,
+ r, g, b,
+ run_x1 - run_x0);
+ else
+ art_ksvg_rgba_run_alpha (linebuf + (run_x0 - x0) * 4,
+ r, g, b, alphatab[alpha],
+ run_x1 - run_x0);
+ }
+ }
+ }
+ running_sum += steps[k].delta;
+ if (x1 > run_x1)
+ {
+ alpha = running_sum >> 16;
+ if (alpha)
+ {
+ if (alpha >= 255)
+ art_ksvg_rgba_fill_run (linebuf + (run_x1 - x0) * 4,
+ r, g, b,
+ x1 - run_x1);
+ else
+ art_ksvg_rgba_run_alpha (linebuf + (run_x1 - x0) * 4,
+ r, g, b, alphatab[alpha],
+ x1 - run_x1);
+ }
+ }
+ }
+ else
+ {
+ alpha = running_sum >> 16;
+ if (alpha)
+ {
+ if (alpha >= 255)
+ art_ksvg_rgba_fill_run (linebuf,
+ r, g, b,
+ x1 - x0);
+ else
+ art_ksvg_rgba_run_alpha (linebuf,
+ r, g, b, alphatab[alpha],
+ x1 - x0);
+ }
+ }
+ data->buf += data->rowstride;
+}
+
+static void
+art_ksvg_rgba_svp_alpha_mask_callback(void *callback_data, int y,
+ int start, ArtSVPRenderAAStep *steps, int n_steps)
+{
+ ArtKSVGRgbaSVPAlphaData *data = (ArtKSVGRgbaSVPAlphaData *)callback_data;
+ art_u8 *linebuf;
+ int run_x0, run_x1;
+ art_u32 running_sum = start;
+ int x0, x1;
+ int k;
+ art_u8 r, g, b;
+ int *alphatab;
+ int alpha;
+ art_u8 *maskbuf;
+
+ linebuf = data->buf;
+ x0 = data->x0;
+ x1 = data->x1;
+
+ r = data->r;
+ g = data->g;
+ b = data->b;
+ alphatab = data->alphatab;
+
+ maskbuf = data->mask + (y - data->y0) * (data->x1 - data->x0);
+
+ if(n_steps > 0)
+ {
+ run_x1 = steps[0].x;
+ if(run_x1 > x0)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ art_ksvg_rgba_mask_run_alpha (linebuf, maskbuf,
+ r, g, b, alphatab[alpha],
+ run_x1 - x0);
+ }
+
+ for(k = 0; k < n_steps - 1; k++)
+ {
+ running_sum += steps[k].delta;
+ run_x0 = run_x1;
+ run_x1 = steps[k + 1].x;
+ if(run_x1 > run_x0)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ art_ksvg_rgba_mask_run_alpha (linebuf + (run_x0 - x0) * 4, maskbuf + (run_x0 - x0),
+ r, g, b, alphatab[alpha],
+ run_x1 - run_x0);
+ }
+ }
+ running_sum += steps[k].delta;
+ if(x1 > run_x1)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ art_ksvg_rgba_mask_run_alpha (linebuf + (run_x1 - x0) * 4, maskbuf + (run_x1 - x0) ,
+ r, g, b, alphatab[alpha],
+ x1 - run_x1);
+ }
+ }
+ else
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ art_ksvg_rgba_mask_run_alpha (linebuf, maskbuf,
+ r, g, b, alphatab[alpha],
+ x1 - x0);
+ }
+
+ data->buf += data->rowstride;
+}
+
+/**
+ * art_rgb_svp_alpha: Alpha-composite sorted vector path over RGB buffer.
+ * @svp: The source sorted vector path.
+ * @x0: Left coordinate of destination rectangle.
+ * @y0: Top coordinate of destination rectangle.
+ * @x1: Right coordinate of destination rectangle.
+ * @y1: Bottom coordinate of destination rectangle.
+ * @rgba: Color in 0xRRGGBBAA format.
+ * @buf: Destination RGB buffer.
+ * @rowstride: Rowstride of @buf buffer.
+ * @alphagamma: #ArtAlphaGamma for gamma-correcting the compositing.
+ *
+ * Renders the shape specified with @svp over the @buf RGB buffer.
+ * @x1 - @x0 specifies the width, and @y1 - @y0 specifies the height,
+ * of the rectangle rendered. The new pixels are stored starting at
+ * the first byte of @buf. Thus, the @x0 and @y0 parameters specify
+ * an offset within @svp, and may be tweaked as a way of doing
+ * integer-pixel translations without fiddling with @svp itself.
+ *
+ * The @rgba argument specifies the color for the rendering. Pixels of
+ * entirely 0 winding number are left untouched. Pixels of entirely
+ * 1 winding number have the color @rgba composited over them (ie,
+ * are replaced by the red, green, blue components of @rgba if the alpha
+ * component is 0xff). Pixels of intermediate coverage are interpolated
+ * according to the rule in @alphagamma, or default to linear if
+ * @alphagamma is NULL.
+ **/
+void
+art_ksvg_rgba_svp_alpha(const ArtSVP *svp,
+ int x0, int y0, int x1, int y1,
+ art_u32 rgba,
+ art_u8 *buf, int rowstride,
+ ArtAlphaGamma *alphagamma,
+ art_u8 *mask)
+{
+ ArtKSVGRgbaSVPAlphaData data;
+ int r, g, b;
+ int i;
+ int a, da;
+ int alpha;
+
+ r = (rgba >> 24) & 0xff;
+ g = (rgba >> 16) & 0xff;
+ b = (rgba >> 8) & 0xff;
+ alpha = rgba & 0xff;
+
+ data.r = r;
+ data.g = g;
+ data.b = b;
+ data.alpha = alpha;
+ data.rgba = rgba;
+ data.mask = mask;
+
+ a = 0x8000;
+ da = (alpha * 66051 + 0x80) >> 8; /* 66051 equals 2 ^ 32 / (255 * 255) */
+
+ for (i = 0; i < 256; i++)
+ {
+ data.alphatab[i] = a >> 16;
+ a += da;
+ }
+
+ data.buf = buf;
+ data.rowstride = rowstride;
+ data.x0 = x0;
+ data.x1 = x1;
+ data.y0 = y0;
+
+ if(mask)
+ art_svp_render_aa (svp, x0, y0, x1, y1, art_ksvg_rgba_svp_alpha_mask_callback, &data);
+ else
+ {
+ if (alpha == 255)
+ art_svp_render_aa (svp, x0, y0, x1, y1, art_ksvg_rgba_svp_alpha_opaque_callback, &data);
+ else
+ art_svp_render_aa (svp, x0, y0, x1, y1, art_ksvg_rgba_svp_alpha_callback, &data);
+ }
+}
+
+/* RGB renderers */
+
+static void
+art_ksvg_rgb_mask_run_alpha(art_u8 *buf, art_u8 *mask, art_u8 r, art_u8 g, art_u8 b, int alpha, int n)
+{
+ int i;
+ int v;
+ int am;
+ int tmp;
+
+ if(alpha > 255)
+ alpha = 255;
+
+ for(i = 0; i < n; i++)
+ {
+ am = (alpha * *mask++) + 0x80;
+ am = (am + (am >> 8)) >> 8;
+
+ v = *buf;
+ tmp = (r - v) * am + 0x80;
+ *buf++ = v + ((tmp + (tmp >> 8)) >> 8);
+
+ v = *buf;
+ tmp = (g - v) * am + 0x80;
+ *buf++ = v + ((tmp + (tmp >> 8)) >> 8);
+
+ v = *buf;
+ tmp = (b - v) * am + 0x80;
+ *buf++ = v + ((tmp + (tmp >> 8)) >> 8);
+ }
+}
+
+static void
+art_ksvg_rgb_svp_alpha_mask_callback(void *callback_data, int y,
+ int start, ArtSVPRenderAAStep *steps, int n_steps)
+{
+ ArtKSVGRgbaSVPAlphaData *data = (ArtKSVGRgbaSVPAlphaData *)callback_data;
+ art_u8 *linebuf;
+ int run_x0, run_x1;
+ art_u32 running_sum = start;
+ int x0, x1;
+ int k;
+ art_u8 r, g, b;
+ int *alphatab;
+ int alpha;
+ art_u8 *maskbuf;
+
+ linebuf = data->buf;
+ x0 = data->x0;
+ x1 = data->x1;
+
+ r = data->r;
+ g = data->g;
+ b = data->b;
+ alphatab = data->alphatab;
+
+ maskbuf = data->mask + (y - data->y0) * (data->x1 - data->x0);
+
+ if(n_steps > 0)
+ {
+ run_x1 = steps[0].x;
+ if(run_x1 > x0)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ art_ksvg_rgb_mask_run_alpha (linebuf, maskbuf,
+ r, g, b, alphatab[alpha],
+ run_x1 - x0);
+ }
+
+ for(k = 0; k < n_steps - 1; k++)
+ {
+ running_sum += steps[k].delta;
+ run_x0 = run_x1;
+ run_x1 = steps[k + 1].x;
+ if(run_x1 > run_x0)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ art_ksvg_rgb_mask_run_alpha (linebuf + (run_x0 - x0) * 3, maskbuf + (run_x0 - x0),
+ r, g, b, alphatab[alpha],
+ run_x1 - run_x0);
+ }
+ }
+ running_sum += steps[k].delta;
+ if(x1 > run_x1)
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ art_ksvg_rgb_mask_run_alpha (linebuf + (run_x1 - x0) * 3, maskbuf + (run_x1 - x0) ,
+ r, g, b, alphatab[alpha],
+ x1 - run_x1);
+ }
+ }
+ else
+ {
+ alpha = (running_sum >> 16) & 0xff;
+ if(alpha)
+ art_ksvg_rgb_mask_run_alpha (linebuf, maskbuf,
+ r, g, b, alphatab[alpha],
+ x1 - x0);
+ }
+
+ data->buf += data->rowstride;
+}
+
+/**
+ * art_rgb_svp_alpha: Alpha-composite sorted vector path over RGB buffer.
+ * @svp: The source sorted vector path.
+ * @x0: Left coordinate of destination rectangle.
+ * @y0: Top coordinate of destination rectangle.
+ * @x1: Right coordinate of destination rectangle.
+ * @y1: Bottom coordinate of destination rectangle.
+ * @rgba: Color in 0xRRGGBBAA format.
+ * @buf: Destination RGB buffer.
+ * @rowstride: Rowstride of @buf buffer.
+ * @alphagamma: #ArtAlphaGamma for gamma-correcting the compositing.
+ *
+ * Renders the shape specified with @svp over the @buf RGB buffer.
+ * @x1 - @x0 specifies the width, and @y1 - @y0 specifies the height,
+ * of the rectangle rendered. The new pixels are stored starting at
+ * the first byte of @buf. Thus, the @x0 and @y0 parameters specify
+ * an offset within @svp, and may be tweaked as a way of doing
+ * integer-pixel translations without fiddling with @svp itself.
+ *
+ * The @rgba argument specifies the color for the rendering. Pixels of
+ * entirely 0 winding number are left untouched. Pixels of entirely
+ * 1 winding number have the color @rgba composited over them (ie,
+ * are replaced by the red, green, blue components of @rgba if the alpha
+ * component is 0xff). Pixels of intermediate coverage are interpolated
+ * according to the rule in @alphagamma, or default to linear if
+ * @alphagamma is NULL.
+ **/
+void
+art_ksvg_rgb_svp_alpha_mask(const ArtSVP *svp,
+ int x0, int y0, int x1, int y1,
+ art_u32 rgba,
+ art_u8 *buf, int rowstride,
+ ArtAlphaGamma *alphagamma,
+ art_u8 *mask)
+{
+ ArtKSVGRgbaSVPAlphaData data;
+ int r, g, b, alpha;
+ int i;
+ int a, da;
+
+ r = rgba >> 24;
+ g = (rgba >> 16) & 0xff;
+ b = (rgba >> 8) & 0xff;
+ alpha = rgba & 0xff;
+
+ data.r = r;
+ data.g = g;
+ data.b = b;
+ data.alpha = alpha;
+ data.mask = mask;
+
+ a = 0x8000;
+ da = (alpha * 66051 + 0x80) >> 8; /* 66051 equals 2 ^ 32 / (255 * 255) */
+
+ for(i = 0; i < 256; i++)
+ {
+ data.alphatab[i] = a >> 16;
+ a += da;
+ }
+
+ data.buf = buf;
+ data.rowstride = rowstride;
+ data.x0 = x0;
+ data.x1 = x1;
+ data.y0 = y0;
+
+ art_svp_render_aa(svp, x0, y0, x1, y1, art_ksvg_rgb_svp_alpha_mask_callback, &data);
+}
+
diff --git a/ksvg/impl/libs/art_support/art_rgba_svp.h b/ksvg/impl/libs/art_support/art_rgba_svp.h
new file mode 100644
index 00000000..b59096d4
--- /dev/null
+++ b/ksvg/impl/libs/art_support/art_rgba_svp.h
@@ -0,0 +1,57 @@
+/* Libart_LGPL - library of basic graphic primitives
+ * Copyright (C) 1998 Raph Levien
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __ART_RGBA_SVP_H__
+#define __ART_RGBA_SVP_H__
+
+/* Render a sorted vector path into an RGB buffer. */
+
+#ifdef LIBART_COMPILATION
+#include "art_alphagamma.h"
+#include "art_svp.h"
+#else
+#include <libart_lgpl/art_alphagamma.h>
+#include <libart_lgpl/art_svp.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+void
+art_ksvg_rgba_svp_alpha(const ArtSVP *svp,
+ int x0, int y0, int x1, int y1,
+ art_u32 rgba,
+ art_u8 *buf, int rowstride,
+ ArtAlphaGamma *alphagamma,
+ art_u8 *mask);
+
+void
+art_ksvg_rgb_svp_alpha_mask(const ArtSVP *svp,
+ int x0, int y0, int x1, int y1,
+ art_u32 rgba,
+ art_u8 *buf, int rowstride,
+ ArtAlphaGamma *alphagamma,
+ art_u8 *mask);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __ART_RGB_SVP_H__ */
diff --git a/ksvg/impl/libs/libtext2path/AUTHORS b/ksvg/impl/libs/libtext2path/AUTHORS
new file mode 100644
index 00000000..efa499dd
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/AUTHORS
@@ -0,0 +1 @@
+Nikolas Zimmermann <wildfox@kde.org>
diff --git a/ksvg/impl/libs/libtext2path/COPYING b/ksvg/impl/libs/libtext2path/COPYING
new file mode 100644
index 00000000..0b84a43f
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/ksvg/impl/libs/libtext2path/ChangeLog b/ksvg/impl/libs/libtext2path/ChangeLog
new file mode 100644
index 00000000..fad2a19b
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/ChangeLog
@@ -0,0 +1,2 @@
+Fri Jul 25 08:30:43 CEST 2003 - Nikolas Zimmermann <wildfox@kde.org>
+ o Initial Creation
diff --git a/ksvg/impl/libs/libtext2path/INSTALL b/ksvg/impl/libs/libtext2path/INSTALL
new file mode 100644
index 00000000..28fadaa7
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/INSTALL
@@ -0,0 +1,181 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made.
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
+
diff --git a/ksvg/impl/libs/libtext2path/Makefile.am b/ksvg/impl/libs/libtext2path/Makefile.am
new file mode 100644
index 00000000..c7f2f390
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/Makefile.am
@@ -0,0 +1,7 @@
+SUBDIRS = src
+DIST_SUBDIRS = src
+
+#pkgconfigdir = $(libdir)/pkgconfig
+#kgconfig_DATA = libtext2path-0.1.pc
+
+#EXTRA_DIST = autogen.sh
diff --git a/ksvg/impl/libs/libtext2path/NEWS b/ksvg/impl/libs/libtext2path/NEWS
new file mode 100644
index 00000000..8b137891
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/NEWS
@@ -0,0 +1 @@
+
diff --git a/ksvg/impl/libs/libtext2path/README b/ksvg/impl/libs/libtext2path/README
new file mode 100644
index 00000000..b9493b88
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/README
@@ -0,0 +1,4 @@
+libtext2path v0.1
+Nikolas Zimmermann <wildfox@kde.org>
+----------------------------------------------------------------------
+TODO: Write documentation! :)
diff --git a/ksvg/impl/libs/libtext2path/VERSION b/ksvg/impl/libs/libtext2path/VERSION
new file mode 100644
index 00000000..6c2cb464
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/VERSION
@@ -0,0 +1 @@
+libtext2path-0.1
diff --git a/ksvg/impl/libs/libtext2path/configure.in.in b/ksvg/impl/libs/libtext2path/configure.in.in
new file mode 100644
index 00000000..2198ab52
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/configure.in.in
@@ -0,0 +1,41 @@
+#AC_INIT(src/Converter.h)
+#AM_CONFIG_HEADER(config.h)
+
+dnl -----------------------------------------------
+dnl Package name and version number (user defined)
+dnl -----------------------------------------------
+GENERIC_LIBRARY_NAME=libtext2path-0.1
+
+# release versioning
+GENERIC_MAJOR_VERSION=0
+GENERIC_MINOR_VERSION=1
+GENERIC_MICRO_VERSION=0
+
+# API version (often = GENERIC_MAJOR_VERSION.GENERIC_MINOR_VERSION)
+GENERIC_API_VERSION=0.1
+AC_SUBST(GENERIC_API_VERSION)
+
+#shared library versioning
+GENERIC_LIBRARY_VERSION=0:1:0
+
+dnl --------------------------------
+dnl Package name and version number
+dnl --------------------------------
+AC_SUBST(GENERIC_LIBRARY_VERSION)
+
+AC_SUBST(GENERIC_LIBRARY_NAME)
+
+GENERIC_VERSION=$GENERIC_MAJOR_VERSION.$GENERIC_MINOR_VERSION.$GENERIC_MICRO_VERSION
+GENERIC_RELEASE=$GENERIC_MAJOR_VERSION.$GENERIC_MINOR_VERSION
+AC_SUBST(GENERIC_RELEASE)
+AC_SUBST(GENERIC_VERSION)
+
+
+dnl -----------------------------------------------
+dnl Checks for programs.
+dnl -----------------------------------------------
+
+dnl Check for fontconfig
+# PKG_CHECK_MODULES(DEPS, fontconfig >= 2.2.0)
+#AC_SUBST(DEPS_CFLAGS)
+#AC_SUBST(DEPS_LIBS)
diff --git a/ksvg/impl/libs/libtext2path/libtext2path.lsm b/ksvg/impl/libs/libtext2path/libtext2path.lsm
new file mode 100644
index 00000000..7407a0ff
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/libtext2path.lsm
@@ -0,0 +1,16 @@
+Begin4
+Title: libtext2path -- Some description
+Version: 0.1
+Entered-date: YYYY-MM-DD
+Description:
+Keywords: KDE3 Qt
+Author: Nikolas Zimmermann <wildfox@kde.org>
+Maintained-by: Nikolas Zimmermann <wildfox@kde.org>
+Home-page:
+Alternate-site:
+Primary-site: ftp://ftp.kde.org/pub/kde/unstable/apps/utils
+ xxxxxx libtext2path-0.1.tar.gz
+ xxx libtext2path-0.1.lsm
+Platform: Linux. Needs KDE 2.x
+Copying-policy: GPL
+End
diff --git a/ksvg/impl/libs/libtext2path/libtext2path.pc.in b/ksvg/impl/libs/libtext2path/libtext2path.pc.in
new file mode 100644
index 00000000..1d4b4210
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/libtext2path.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libtext2path
+Description: Converts FreeType glyphs to bezier paths
+Version: @VERSION@
+Libs: -L${libdir} -ltext2path
+Cflags: -I${includedir}/@GENERIC_LIBRARY_NAME@ -I${libdir}/@GENERIC_LIBRARY_NAME@/include
+
diff --git a/ksvg/impl/libs/libtext2path/libtext2path.spec b/ksvg/impl/libs/libtext2path/libtext2path.spec
new file mode 100644
index 00000000..e0c217bd
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/libtext2path.spec
@@ -0,0 +1,41 @@
+%define distversion %( perl -e 'Creating /home/nikoz/Projects/libtext2path/libtext2path.spec...=\<\>;/(\d+)\.(\d)\.?(\d)?/; print "".(||0)' /etc/*-release)
+Name: libtext2path
+Summary: libtext2path -- Some description
+Version: 0.1
+Release: %{_vendor}_%{distversion}
+Copyright: GPL
+Group: X11/KDE/Utilities
+Source: ftp://ftp.kde.org/pub/kde/unstable/apps/utils/%{name}-%{version}.tar.gz
+Packager: Nikolas Zimmermann <wildfox@kde.org>
+BuildRoot: /tmp/%{name}-%{version}
+Prefix: /usr/kde/cvs
+
+%description
+A long description
+
+%prep
+rm -rf $RPM_BUILD_ROOT
+%setup -n %{name}-%{version}
+CFLAGS="" CXXFLAGS="" ./configure --disable-debug --enable-final --prefix=%{prefix}
+
+%build
+# Setup for parallel builds
+numprocs=1
+if [ "" = "0" ]; then
+ numprocs=1
+fi
+
+make -j
+
+%install
+make install-strip DESTDIR=$RPM_BUILD_ROOT
+
+cd
+find . -type d | sed '1,2d;s,^\.,\%attr(-\,root\,root) \%dir ,' > /%{name}-master.list
+find . -type f -o -type l | sed 's|^\.||' >> $RPM_BUILD_DIR/%{name}-master.list
+
+%clean
+rm -rf $RPM_BUILD_DIR/%{name}-%{version}
+rm -rf $RPM_BUILD_DIR/-master.list
+
+%files -f $RPM_BUILD_DIR/%{name}-master.list
diff --git a/ksvg/impl/libs/libtext2path/src/Affine.cpp b/ksvg/impl/libs/libtext2path/src/Affine.cpp
new file mode 100644
index 00000000..d06b53bc
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/Affine.cpp
@@ -0,0 +1,174 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <math.h>
+
+#include "Point.h"
+#include "Affine.h"
+
+using namespace T2P;
+
+Affine::Affine()
+{
+ m_affine[0] = 1.0;
+ m_affine[1] = 0.0;
+ m_affine[2] = 0.0;
+ m_affine[3] = 1.0;
+ m_affine[4] = 0.0;
+ m_affine[5] = 0.0;
+}
+
+Affine::Affine(double affine[6])
+{
+ for(int i = 0; i < 6; i++)
+ m_affine[i] = affine[i];
+}
+
+Affine::Affine(const Affine &other)
+{
+ (*this) = other;
+}
+
+Affine::Affine(double m11, double m12, double m21, double m22, double dx, double dy)
+{
+ m_affine[0] = m11; m_affine[1] = m12; m_affine[2] = m21;
+ m_affine[3] = m22; m_affine[4] = dx; m_affine[5] = dy;
+}
+
+Affine::~Affine()
+{
+}
+
+Affine &Affine::operator*=(Affine &other)
+{
+ double d0 = m11() * other.m11() + m12() * other.m21();
+ double d1 = m11() * other.m12() + m12() * other.m22();
+ double d2 = m21() * other.m11() + m22() * other.m21();
+ double d3 = m21() * other.m12() + m22() * other.m22();
+ double d4 = dx() * other.m11() + dy() * other.m21() + other.dx();
+ double d5 = dx() * other.m12() + dy() * other.m22() + other.dy();
+
+ m_affine[0] = d0; m_affine[1] = d1; m_affine[2] = d2;
+ m_affine[3] = d3; m_affine[4] = d4; m_affine[5] = d5;
+
+ return *this;
+}
+
+Affine &Affine::operator=(const Affine &other)
+{
+ for(int i = 0; i < 6; i++)
+ m_affine[i] = other.m_affine[i];
+
+ return *this;
+}
+
+double &Affine::m11()
+{
+ return m_affine[0];
+}
+
+double &Affine::m12()
+{
+ return m_affine[1];
+}
+
+double &Affine::m21()
+{
+ return m_affine[2];
+}
+
+double &Affine::m22()
+{
+ return m_affine[3];
+}
+
+double &Affine::dx()
+{
+ return m_affine[4];
+}
+
+double &Affine::dy()
+{
+ return m_affine[5];
+}
+
+void Affine::scale(double s)
+{
+ scale(s, s);
+}
+
+void Affine::scale(double sx, double sy)
+{
+ m_affine[0] = sx;
+ m_affine[3] = sy;
+}
+
+void Affine::translate(const Point &point)
+{
+ m_affine[4] += point.x();
+ m_affine[5] += point.y();
+}
+
+void Affine::translate(double tx, double ty)
+{
+ m_affine[4] += tx * m_affine[0] + ty * m_affine[2];
+ m_affine[5] += tx * m_affine[1] + ty * m_affine[3];
+}
+
+void Affine::rotate(double angle)
+{
+ double sina = sin(angle);
+ double cosa = cos(angle);
+
+ double tm11 = cosa * m_affine[0] + sina * m_affine[2];
+ double tm12 = cosa * m_affine[1] + sina * m_affine[3];
+ double tm21 = -sina * m_affine[0] + cosa * m_affine[2];
+ double tm22 = -sina * m_affine[1] + cosa * m_affine[3];
+
+ m_affine[0] = tm11; m_affine[1] = tm12;
+ m_affine[2] = tm21; m_affine[3] = tm22;
+}
+
+void Affine::rotateAround(double angle, const Point &point)
+{
+ translate(point);
+ rotate(angle);
+ translate(point.invert());
+}
+
+void Affine::rotateAround(double angle, double cx, double cy)
+{
+ translate(-cx, -cy);
+ rotate(angle);
+ translate(cx, cy);
+}
+
+Point Affine::mapPoint(const Point &p) const
+{
+ return Point(p.x() * m_affine[0] + p.y() * m_affine[2] + m_affine[4],
+ p.x() * m_affine[1] + p.y() * m_affine[3] + m_affine[5]);
+}
+
+double *Affine::data()
+{
+ return m_affine;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/libs/libtext2path/src/Affine.h b/ksvg/impl/libs/libtext2path/src/Affine.h
new file mode 100644
index 00000000..c0f11e9b
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/Affine.h
@@ -0,0 +1,67 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef T2P_AFFINE_H
+#define T2P_AFFINE_H
+
+namespace T2P
+{
+ class Point;
+ class Affine
+ {
+ public:
+ Affine();
+ Affine(double affine[6]);
+ Affine(const Affine &other);
+ Affine(double m11, double m12, double m21, double m22, double dx, double dy);
+ ~Affine();
+
+ Affine &operator*=(Affine &other);
+ Affine &operator=(const Affine &other);
+
+ double &m11();
+ double &m12();
+ double &m21();
+ double &m22();
+ double &dx();
+ double &dy();
+
+ void scale(double s);
+ void scale(double sx, double sy);
+ void translate(const Point &point); // Assumes point is already transformed
+ void translate(double tx, double ty);
+
+ void rotate(double angle);
+ void rotateAround(double angle, const Point &point); // Assumes point is already transformed
+ void rotateAround(double angle, double cx, double cy);
+
+ Point mapPoint(const Point &p) const;
+
+ // Internal
+ double *data();
+
+ private:
+ double m_affine[6];
+ };
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/libs/libtext2path/src/BezierPath.h b/ksvg/impl/libs/libtext2path/src/BezierPath.h
new file mode 100644
index 00000000..1c357abd
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/BezierPath.h
@@ -0,0 +1,56 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef T2P_BEZIERPATH_H
+#define T2P_BEZIERPATH_H
+
+#include <list>
+
+namespace T2P
+{
+ class Point;
+ class BezierPath
+ {
+ public:
+ BezierPath() { }
+ virtual ~BezierPath() { }
+
+ /**
+ * Calculates the arclength from p0 to the point parametrized by 0 <= t <= 1.
+ */
+ virtual double length(double t = 1.0) = 0;
+
+ /**
+ * Calculates the point, the tangent vector and the normal vector for
+ * 0 <= t <= 1. The tangent vector and the normal vector are
+ * normalized (length=1).
+ */
+ virtual void pointTangentNormalAt(double t, Point *p = 0, Point *tn = 0, Point *n = 0) = 0;
+
+ /**
+ * Calculates the axis-aligned bounding box.
+ */
+ virtual void boundingBox(Point *topLeft, Point *bottomRight) = 0;
+ };
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/libs/libtext2path/src/Cache.h b/ksvg/impl/libs/libtext2path/src/Cache.h
new file mode 100644
index 00000000..a85fdf92
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/Cache.h
@@ -0,0 +1,156 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef T2P_CACHE_H
+#define T2P_CACHE_H
+
+#include <map>
+#include <string>
+#include <vector>
+#include <iostream>
+
+#include "myboost/shared_ptr.hpp"
+
+namespace T2P
+{
+ class CacheElement
+ {
+ public:
+ CacheElement(std::string key) : m_key(key), m_usage(0) { }
+ ~CacheElement() { }
+
+ std::string key() const { return m_key; }
+ int usage() const { return m_usage; }
+
+ void incUsage() { m_usage++; }
+
+ private:
+ std::string m_key;
+ int m_usage;
+ };
+
+ template<typename T>
+ class Cache
+ {
+ public:
+ typedef myboost::shared_ptr<T> SharedT;
+
+ Cache(int maxSize = 10) : m_size(0), m_maxSize(maxSize) { }
+ ~Cache() { clear(); }
+
+ // Number of elements in cache
+ int size() const { return m_size; }
+
+ // Maximum number of elements in cache
+ int maxSize() const { return m_maxSize; }
+
+ // Add new entry
+ void insert(const std::string &key, SharedT &value)
+ {
+ // TODO: Add real LRU logic, now i will just delete the less
+ // used item when inserting a new item would exceed maxSize
+ if(m_size == m_maxSize)
+ {
+ // Find less used item
+ typename std::map<SharedT, CacheElement *>::const_iterator it = m_cacheMap.begin();
+ int usage = (*it).second->usage(); std::string keyUsage = (*it).second->key();
+ for(it++; it != m_cacheMap.end(); ++it)
+ {
+ int curUsage = (*it).second->usage();
+ if(curUsage < usage)
+ {
+ usage = curUsage;
+ keyUsage = (*it).second->key();
+ }
+ }
+
+// std::cout << "[CACHE] Removing less used element with key: " << keyUsage << " (Used " << usage << " times!)" << std::endl;
+ remove(keyUsage);
+ }
+
+ m_size++;
+ m_entries.push_back(value);
+ m_cacheMap[value] = new CacheElement(key);
+ }
+
+ // Remove single entry
+ void remove(const std::string &key)
+ {
+ for(typename std::vector<SharedT>::iterator it = m_entries.begin(); it != m_entries.end(); ++it)
+ {
+ SharedT cur = *it;
+ if(m_cacheMap[cur]->key() == key)
+ {
+ m_size--;
+
+ typename std::map<SharedT, CacheElement *>::iterator cacheElement = m_cacheMap.find(cur);
+ m_cacheMap.erase(cacheElement);
+ delete cacheElement->second;
+ m_entries.erase(it); // Only valid to write because we don't go on here!
+ break; // Otherwhise the iterators _may_ be invalid!
+ }
+ }
+ }
+
+ // Remove all entries
+ void clear()
+ {
+ m_size = 0;
+ m_entries.clear();
+ m_cacheMap.clear();
+ }
+
+ // Lookup entry
+ SharedT find(const std::string &key)
+ {
+ for(typename std::vector<SharedT>::const_iterator it = m_entries.begin(); it != m_entries.end(); ++it)
+ {
+ SharedT cur = *it;
+ if(m_cacheMap[cur]->key() == key)
+ {
+ m_cacheMap[cur]->incUsage();
+ return cur;
+ }
+ }
+
+ return SharedT();
+ }
+
+ void dump()
+ {
+ std::cout << "[CACHE] " << size() << " of " << maxSize() << " Objects in the cache." << std::endl;
+
+ for(typename std::vector<SharedT>::iterator it = m_entries.begin(); it != m_entries.end(); ++it)
+ {
+ SharedT cur = *it;
+ std::cout << "[CACHE] - " << m_cacheMap[cur]->key() << " -> " << cur << " (Usage: " << m_cacheMap[cur]->usage() << ")" << std::endl;
+ }
+ }
+
+ private:
+ std::vector<SharedT> m_entries;
+ std::map<SharedT, CacheElement *> m_cacheMap;
+ int m_size, m_maxSize;
+ };
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/libs/libtext2path/src/Converter.cpp b/ksvg/impl/libs/libtext2path/src/Converter.cpp
new file mode 100644
index 00000000..7810b417
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/Converter.cpp
@@ -0,0 +1,505 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <math.h>
+
+#include "myboost/shared_ptr.hpp"
+#include <fontconfig/fontconfig.h>
+#include <fribidi/fribidi.h>
+#include <fribidi/fribidi_types.h>
+
+#include "Font.h"
+#include "Glyph.h"
+#include "Tools.h"
+#include "Rectangle.h"
+#include "Converter.h"
+#include "QtUnicode.h"
+#include "GlyphTracer.h"
+
+// Macros
+#define FT_TRUNC(x) ((x) >> 6)
+#define FT_TOFLOAT(x) ((x) * (1.0 / 64.0))
+#define FT_FROMFLOAT(x) ((int) floor ((x) * 64.0 + 0.5))
+
+const double deg2rad = 0.017453292519943295769; // pi/180
+
+using namespace T2P;
+
+// Font engine. The core component.
+Converter::Converter(GlyphTracer *tracer) : m_glyphTracer(tracer)
+{
+ m_init = false;
+ m_kerning = true;
+ m_library = 0;
+}
+
+Converter::~Converter()
+{
+ if(m_glyphTracer)
+ delete m_glyphTracer;
+
+ m_fontCache.clear();
+ m_glyphCache.clear();
+
+ // Close FreeType2 library
+ if(m_library)
+ FT_Done_FreeType(m_library);
+}
+
+void Converter::init()
+{
+ // Initialize FreeType2
+ m_init = (FT_Init_FreeType(&m_library) == 0);
+}
+
+bool Converter::ready()
+{
+ return m_init;
+}
+
+void Converter::setKerning(bool mode)
+{
+ m_kerning = mode;
+}
+
+// Lookup font in cache or create new font
+SharedFont Converter::requestFont(const FontVisualParams *params)
+{
+ std::string cacheKey = cacheFontKey(params);
+ SharedFont cached = m_fontCache.find(cacheKey);
+
+ // If not available in cache, create new one and cache it :)
+ if(cached)
+ {
+ delete params;
+ return cached;
+ }
+ else
+ {
+ // Create a new Font
+ SharedFont newFont(new Font(this));
+
+ // Load the font
+ if(!newFont->load(params))
+ {
+ delete params;
+ return SharedFont();
+ }
+
+ // Append to cache
+ m_fontCache.insert(cacheKey, newFont);
+ return newFont;
+ }
+}
+
+GlyphAffinePair *Converter::requestGlyph(GlyphRenderParams *params, Rectangle &bbox, Affine &affine, bool onlyLatin)
+{
+ // 1. Select glyph to have glyphIndex information,
+ // needed to generate the cache lookup key
+ selectGlyph(params);
+
+ SharedGlyph cached = m_glyphCache.find(cacheGlyphKey(params));
+
+ // If not available in cache, render new one and cache it :)
+ // If we're mixing ie. japanese and latin characters (TTB layout),
+ // then we also have to re-calculate the glyph again with the appropriate rotation matrix (Niko)
+ if(!cached || !onlyLatin)
+ cached = calcGlyph(params, affine, onlyLatin);
+
+ // Correct bezier path by setting up the correct scaling matrix
+ // and multiplying with the current glyph affine
+ double fontSize = params->font()->fontParams()->size();
+
+ T2P::Affine correctAffine;
+ correctAffine.scale(0.001 * fontSize, -0.001 * fontSize);
+ correctAffine *= affine;
+
+ // Get bbox information
+ Point p1(FT_TRUNC(cached->ftBbox()->xMin), FT_TRUNC(cached->ftBbox()->yMin));
+ Point p2(FT_TRUNC(cached->ftBbox()->xMax), FT_TRUNC(cached->ftBbox()->yMax));
+
+ bbox.setA(affine.mapPoint(p1));
+ bbox.setB(affine.mapPoint(p2));
+
+ return new GlyphAffinePair(cached.get(), correctAffine);
+}
+
+void Converter::selectGlyph(GlyphRenderParams *params)
+{
+ // 1. Select glyph + test if it exists
+ // |
+ // |-> if it doesn't exist, replace by a '?' and check if exists
+ // |-> if it does exist, use it!
+ params->setGlyphIndex(FT_Get_Char_Index(params->font()->fontFace(), (FT_ULong) params->character()));
+
+ if(params->glyphIndex() == 0)
+ params->setGlyphIndex(FT_Get_Char_Index(params->font()->fontFace(), '?'));
+
+ // 2. Load glyph into font's glyphSlot, according to the GlyphLayoutParams
+ int flags = FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP;
+
+ // 3. Don't pass FT_LOAD_VERTICAL_LAYOUT on TTB layouts when rendering
+ // a latin glyph because it needs to be rotated...
+ if(params->layout()->tb())
+ {
+ Script script;
+ SCRIPT_FOR_CHAR(script, params->character())
+ if(script != Latin || params->layout()->glyphOrientationVertical() == 0)
+ flags |= FT_LOAD_VERTICAL_LAYOUT;
+ }
+
+ FT_Error error = FT_Load_Glyph(params->font()->fontFace(), params->glyphIndex(), flags);
+ if(error)
+ params->setGlyphIndex(0);
+}
+
+SharedGlyph Converter::calcGlyph(const GlyphRenderParams *params, Affine &affine, bool onlyLatin)
+{
+ // 2. Apply kerning if needed
+ if(m_kerning && params->lastGlyph() != 0 && params->glyphIndex() != 0)
+ {
+ FT_Vector kerningVector;
+ double kx, ky;
+
+ FT_Get_Kerning(params->font()->fontFace(), params->lastGlyph(), params->glyphIndex(), ft_kerning_default, &kerningVector);
+
+ kx = FT_TRUNC(kerningVector.x);
+ ky = FT_TRUNC(kerningVector.y);
+
+ affine.dx() += kx + affine.m21() * ky;
+
+ // Only apply y kerning in TB mode
+ if(params->layout()->tb())
+ affine.dy() += kx + affine.m22() * ky;
+ }
+
+ // 3. Prepare path tracing
+ FT_OutlineGlyph ftGlyph;
+ FT_Get_Glyph(params->font()->fontFace()->glyph, reinterpret_cast<FT_Glyph *>(&ftGlyph));
+
+ // 3a. Prepare tracing matrix
+ Affine traceAffine;
+ traceAffine.scale(1000.0 / params->font()->fontFace()->units_per_EM);
+
+ // 3b. Enable character rotation, if needed
+ if(params->layout()->tb())
+ {
+ Script script;
+ SCRIPT_FOR_CHAR(script, params->character())
+ if(!onlyLatin && script == Latin)
+ {
+ FT_Matrix matrix;
+
+ double angle = deg2rad * params->layout()->glyphOrientationVertical();
+ matrix.xx = (FT_Fixed)( cos(angle) * 0x10000L);
+ matrix.xy = (FT_Fixed)(-sin(angle) * 0x10000L);
+ matrix.yx = (FT_Fixed)( sin(angle) * 0x10000L);
+ matrix.yy = (FT_Fixed)( cos(angle) * 0x10000L);
+
+ FT_Glyph_Transform(reinterpret_cast<FT_Glyph>(ftGlyph), &matrix, 0);
+ }
+ }
+
+ // 4. Begin path tracing
+ // - Setup glyphOutlineing glyph
+ // - Start tracing
+ // - Close path
+ FT_Outline *ftOut = &ftGlyph->outline;
+
+ SharedGlyph glyphOutline(new Glyph());
+ glyphOutline->setBezierPath(m_glyphTracer->allocBezierPath(ftOut->n_points * 2 + ftOut->n_contours + 1));
+ glyphOutline->setAffine(traceAffine);
+
+ FT_Outline_Decompose(ftOut, m_glyphTracer->outlineFuncs(), glyphOutline.get());
+
+ m_glyphTracer->closePath(glyphOutline.get());
+
+ // 5. Determine bounding box (aka "cbox")
+ FT_Glyph_Get_CBox(reinterpret_cast<FT_Glyph>(ftGlyph), ft_glyph_bbox_unscaled, glyphOutline->ftBbox());
+
+ // 6. Cache glyph!
+ m_glyphCache.insert(cacheGlyphKey(params), glyphOutline);
+
+ FT_Done_Glyph(reinterpret_cast<FT_Glyph>(ftGlyph));
+
+ return glyphOutline;
+}
+
+GlyphSet *Converter::calcString(Font *font, const unsigned short *text, unsigned int length, Affine &affine, const GlyphLayoutParams *params, BezierPath *bpath)
+{
+ unsigned short *bidi = 0;
+
+ // 0. Apply BiDi Rules
+ if(params->useBidi())
+ {
+ FriBidiCharType baseDir = FRIBIDI_TYPE_N;
+ FriBidiChar *unicodeIn = new FriBidiChar[length + 1];
+ FriBidiChar *unicodeOut = new FriBidiChar[length + 1];
+ bidi = new unsigned short[length + 1];
+
+ for(unsigned int i = 0; i < length; i++)
+ unicodeIn[i] = text[i];
+
+ fribidi_log2vis(unicodeIn, length, &baseDir, unicodeOut, 0, 0, 0);
+
+ for(unsigned int i = 0; i < length; i++)
+ bidi[i] = unicodeOut[i];
+
+ bidi[length] = 0;
+ delete []unicodeIn;
+ delete []unicodeOut;
+ }
+ else
+ bidi = const_cast<unsigned short *>(text);
+
+ // Detect character rotation if needed,
+ // probably working in 0.1% of the cases :/
+ Script script;
+ bool onlyLatin = true;
+ for(unsigned int i = 0; i < length; i++)
+ {
+ SCRIPT_FOR_CHAR(script, bidi[i])
+ if(script != Latin)
+ {
+ onlyLatin = false;
+ break;
+ }
+ }
+
+ // 1. Set initial font size
+ double fontSize = font->fontParams()->size();
+ FT_Set_Char_Size(font->fontFace(), FT_FROMFLOAT(fontSize), FT_FROMFLOAT(fontSize), 0, 0);
+
+ // 2. Compute positioning metrics
+ // - See http://www.freetype.org/freetype2/docs/tutorial/stepX.html (X = 1 or 2)
+ int pixelHeight = (int) (FT_TOFLOAT(font->fontFace()->size->metrics.ascender - font->fontFace()->size->metrics.descender) * affine.m22());
+ int pixelBaseline = (int) (FT_TOFLOAT(font->fontFace()->size->metrics.ascender) * affine.m22());
+ int pixelUnderlinePosition = (int) (((font->fontFace()->ascender - font->fontFace()->underline_position - font->fontFace()->underline_thickness / 2) * fontSize / font->fontFace()->units_per_EM) * affine.m22());
+ int pixelUnderlineThickness = T2PMAX(1, (int) ((font->fontFace()->underline_thickness * fontSize / font->fontFace()->units_per_EM) * affine.m22()));
+
+ // 3. Prepare needed variables for the rendering loop
+ // - rendering params (layout, font...)
+ // - bounding box (per glyph, overall)
+ // - glyph matrix (overall)
+ // - resulting glyph sets
+ GlyphRenderParams *renderParams = new GlyphRenderParams();
+ renderParams->setFont(font);
+ renderParams->setLayout(params);
+ renderParams->setLastGlyph(0);
+ renderParams->setGlyphIndex(0);
+
+ Affine glyphAffine(affine);
+ Rectangle bbox, currentBbox;
+ GlyphSet *result = new GlyphSet();
+
+ // Align to path start, if bpath != 0
+ Point pathPoint, pathTangent, pathNormal;
+ double pathLength = 0, pathAdvance = 0;
+ double startOffset = params->textPathStartOffset();
+
+ if(bpath)
+ {
+ pathLength = bpath->length();
+ bpath->pointTangentNormalAt(startOffset, &pathPoint, &pathTangent);
+
+ glyphAffine.dx() = pathPoint.x();
+ glyphAffine.dy() = pathPoint.y();
+ glyphAffine.rotate(atan2(pathTangent.y(), pathTangent.x()));
+
+ std::cout << "[T2P] Starting textPath at: " << pathPoint.x() << ", " << pathPoint.y() << std::endl;
+ }
+
+ // <tspan> elements can have different baseline-shift's
+ // baseline-shift support (Niko)
+ double baseline = 0;
+ if(!params->baselineShift().empty())
+ {
+ if(params->baselineShift() == "sub")
+ baseline += fontSize / 5 + 1;
+ else if(params->baselineShift() == "super")
+ baseline -= fontSize / 3 + 1;
+ else
+ {
+ std::string temp = params->baselineShift();
+ if(temp.find("%") > 0)
+ baseline -= (atof(temp.c_str()) / 100.0) * fontSize;
+ else
+ baseline -= atoi(temp.c_str());
+ }
+
+ if(!params->tb())
+ glyphAffine.translate(0, baseline);
+ else
+ glyphAffine.translate(-baseline, 0);
+ }
+
+ // 4. Enter main rendering loop
+ for(unsigned int i = 0; i < length; i++)
+ {
+ // 4a. Modify character to render
+ renderParams->setCharacter(bidi[i]);
+
+ // 4c. Get glyph outline
+ GlyphAffinePair *glyphOutline = requestGlyph(renderParams, currentBbox, glyphAffine, onlyLatin);
+ m_glyphTracer->correctGlyph(glyphOutline);
+
+ // 4d. Save advance values
+ result->m_glyphXAdvance.push_back((font->fontFace()->glyph->advance.x * fontSize / font->fontFace()->units_per_EM) * affine.m11());
+ result->m_glyphYAdvance.push_back((font->fontFace()->glyph->advance.y * fontSize / font->fontFace()->units_per_EM) * affine.m22());
+
+ // 4e. Misc
+ // - union current + overall bounding box
+ // - add glyph to list of glyphs
+ // - apply letter & word spacing
+ if(renderParams->glyphIndex() != 0)
+ {
+ // Remember last glyph for kerning
+ renderParams->setLastGlyph(renderParams->glyphIndex());
+
+ // Union current + overall bounding box
+ bbox.bboxUnion(bbox, currentBbox);
+
+ // Move glyph locations for the next glyph to be
+ // rendered apply letter & word spacing
+ bool addGlyph = true;
+ if(!params->tb())
+ {
+ if(bpath)
+ {
+ double advance = startOffset + (pathAdvance / pathLength);
+ if(advance < 0.0 || advance > 1.0) // dont render off-path glyphs
+ addGlyph = false;
+
+ pathAdvance += (result->m_glyphXAdvance.back() + params->letterSpacing() * affine.m11()) + ((bidi[(i + 1)] == ' ') ? params->wordSpacing() * affine.m11() : 0);
+
+ std::cout << "[T2P] Adjusting textPath advance: " << pathAdvance << " Path Length: " << pathLength << " StartOffset: " << startOffset << " Position in Path (relative 0-1): " << pathAdvance/pathLength << " Adjusted by offset: " << startOffset + (pathAdvance / pathLength) << std::endl;
+
+ bpath->pointTangentNormalAt(startOffset + (pathAdvance / pathLength), &pathPoint, &pathTangent, &pathNormal);
+
+ glyphAffine.m11() = affine.m11();
+ glyphAffine.m12() = affine.m12();
+ glyphAffine.m21() = affine.m21();
+ glyphAffine.m22() = affine.m22();
+ glyphAffine.dx() = pathPoint.x();
+ glyphAffine.dy() = pathPoint.y();
+
+ glyphAffine.rotateAround(atan2(pathTangent.y(), pathTangent.x()), Point(result->m_glyphXAdvance.back() / 2, result->m_glyphYAdvance.back() / 2));
+
+ std::cout << "[T2P] Aligning textPath to: " << pathPoint.x() << ", " << pathPoint.y() << std::endl;
+ if(!params->tb())
+ glyphAffine.translate(0, baseline);
+ else
+ glyphAffine.translate(-baseline, 0);
+ }
+ else
+ glyphAffine.dx() += (result->m_glyphXAdvance.back() + params->letterSpacing() * affine.m11()) + ((bidi[(i + 1)] == ' ') ? params->wordSpacing() * affine.m11() : 0);
+ }
+ else
+ {
+ double advy = result->m_glyphYAdvance.back();
+
+ Script script;
+ SCRIPT_FOR_CHAR(script, bidi[i])
+ if(!onlyLatin && script == Latin && params->glyphOrientationVertical() != 0)
+ advy = result->m_glyphXAdvance.back();
+
+ glyphAffine.dy() += (advy + params->letterSpacing() * affine.m22()) + ((bidi[(i + 1)] == ' ') ? params->wordSpacing() * affine.m22() : 0);
+ }
+
+ // Copy bezier path/affine pair
+ if(addGlyph)
+ {
+ result->m_set.push_back(glyphOutline);
+ result->m_glyphCount++;
+ }
+ else
+ delete glyphOutline;
+ }
+ }
+
+ // 5. Fill out resulting data structures
+ result->m_underlinePosition = pixelUnderlinePosition;
+ result->m_overlinePosition = pixelHeight - pixelUnderlinePosition;
+ result->m_strikeThroughPosition = (result->m_underlinePosition + result->m_overlinePosition) / 2;
+ result->m_pixelBaseline = pixelBaseline;
+ result->m_underlineThickness = pixelUnderlineThickness;
+
+ result->m_xpen = glyphAffine.dx() - affine.dx();
+ result->m_ypen = glyphAffine.dy() - affine.dy();
+
+ result->m_bboxX = T2PMAX(1, int(bbox.a().x()));
+ result->m_bboxY = T2PMAX(1, int(bbox.a().y() - int(pixelHeight / 2)));
+ result->m_height = T2PMAX(1, int(bbox.b().y() - bbox.a().y()));
+
+ // Correct bounding box information also on
+ // vertical layouts! (Niko)
+ if(!params->tb())
+ {
+ if(bpath)
+ result->m_width = int(pathAdvance);
+ else
+ result->m_width = T2PMAX(1, int(bbox.b().x() - bbox.a().x()));
+ }
+ else
+ result->m_width = T2PMAX(1, pixelHeight);
+
+ // 6. Cleanup memory
+ if(text != bidi)
+ delete []bidi;
+
+ delete renderParams;
+
+ // 7. Eventually, dump cache statistics
+ // m_glyphCache.dump();
+ // m_fontCache.dump();
+
+ return result;
+}
+
+std::string Converter::cacheFontKey(const FontVisualParams *params) const
+{
+ // TODO: Tune the key
+ std::string key;
+
+ key += Tools::joinList('|', const_cast<FontVisualParams *>(params)->fontList());
+ key += Tools::a2str(params->weight());
+ key += Tools::a2str(params->slant());
+ key += Tools::a2str(params->size());
+
+ // std::cout << "Font cache key: " << key << std::endl;
+ return key;
+}
+
+std::string Converter::cacheGlyphKey(const GlyphRenderParams *params) const
+{
+ // TODO: Tune the key
+ std::string key;
+
+ key += params->font()->fontFile();
+ key += Tools::a2str(params->character());
+ key += Tools::a2str(params->glyphIndex());
+ key += Tools::a2str(params->font()->fontParams()->size());
+ key += Tools::a2str(params->font()->fontParams()->weight());
+ key += Tools::a2str(params->font()->fontParams()->slant());
+
+ // std::cout << "Glyph cache key: " << key << std::endl;
+ return key;
+}
+// vim:ts=4:noet
diff --git a/ksvg/impl/libs/libtext2path/src/Converter.h b/ksvg/impl/libs/libtext2path/src/Converter.h
new file mode 100644
index 00000000..d6e19521
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/Converter.h
@@ -0,0 +1,94 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef T2P_CONVERTER_H
+#define T2P_CONVERTER_H
+
+#include "Cache.h"
+
+// FreeType 2 includes
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_OUTLINE_H
+#include FT_GLYPH_H
+
+namespace T2P
+{
+ class BezierPath;
+
+ class Font;
+ class Glyph;
+ class Affine;
+ class GlyphSet;
+ class Rectangle;
+ class GlyphTracer;
+ class GlyphAffinePair;
+ class FontVisualParams;
+ class GlyphLayoutParams;
+ class GlyphRenderParams;
+
+ typedef myboost::shared_ptr<Font> SharedFont;
+ typedef myboost::shared_ptr<Glyph> SharedGlyph;
+
+ class Converter
+ {
+ public:
+ Converter(GlyphTracer *tracer);
+ ~Converter();
+
+ // Is initialized?
+ void init();
+ bool ready();
+
+ // Kerning control
+ void setKerning(bool mode);
+
+ SharedFont requestFont(const FontVisualParams *params);
+ GlyphAffinePair *requestGlyph(GlyphRenderParams *params, Rectangle &bbox, Affine &affine, bool onlyLatin);
+
+ GlyphSet *calcString(Font *font, const unsigned short *text, unsigned int length, Affine &affine, const GlyphLayoutParams *params, BezierPath *bpath = 0);
+ SharedGlyph calcGlyph(const GlyphRenderParams *params, Affine &affine, bool onlyLatin);
+
+ void selectGlyph(GlyphRenderParams *params);
+
+ protected:
+ friend class Font;
+
+ // Internal
+ FT_Library library() { return m_library; }
+
+ private:
+ std::string cacheFontKey(const FontVisualParams *params) const;
+ std::string cacheGlyphKey(const GlyphRenderParams *params) const;
+
+ FT_Library m_library;
+
+ GlyphTracer *m_glyphTracer;
+
+ Cache<Glyph> m_glyphCache;
+ Cache<Font> m_fontCache;
+
+ bool m_init, m_kerning;
+ };
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/libs/libtext2path/src/Font.cpp b/ksvg/impl/libs/libtext2path/src/Font.cpp
new file mode 100644
index 00000000..1d6f7005
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/Font.cpp
@@ -0,0 +1,252 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <math.h>
+#include <iostream>
+#include <fontconfig/fontconfig.h>
+
+#include "Font.h"
+#include "Tools.h"
+#include "Converter.h"
+
+// Macros
+#define FT_TRUNC(x) ((x) >> 6)
+#define FT_TOFLOAT(x) ((x) * (1.0 / 64.0))
+#define FT_FROMFLOAT(x) ((int) floor ((x) * 64.0 + 0.5))
+
+using namespace T2P;
+
+FontVisualParams::FontVisualParams()
+{
+ m_size = 0.0;
+ m_slant = 0;
+ m_weight = 0;
+}
+
+FontVisualParams::FontVisualParams(const FontVisualParams &other)
+{
+ (*this) = other;
+}
+
+FontVisualParams::~FontVisualParams()
+{
+}
+
+FontVisualParams &FontVisualParams::operator=(const FontVisualParams &other)
+{
+ m_size = other.m_size;
+ m_slant = other.m_slant;
+ m_weight = other.m_weight;
+ m_fontList = other.m_fontList;
+
+ return *this;
+}
+
+void FontVisualParams::setWeight(int weight)
+{
+ m_weight = weight;
+}
+
+int FontVisualParams::weight() const
+{
+ return m_weight;
+}
+
+void FontVisualParams::setSlant(int slant)
+{
+ m_slant = slant;
+}
+
+int FontVisualParams::slant() const
+{
+ return m_slant;
+}
+
+void FontVisualParams::setSize(double size)
+{
+ m_size = size;
+}
+
+double FontVisualParams::size() const
+{
+ return m_size;
+}
+
+std::list<std::string> &FontVisualParams::fontList()
+{
+ return m_fontList;
+}
+
+// #####
+
+Font::Font(Converter *context) : m_context(context)
+{
+ m_ready = false;
+
+ m_fontFace = 0;
+ m_fontParams = 0;
+}
+
+Font::~Font()
+{
+ // Release font face
+ if(m_ready && m_fontFace)
+ {
+ // FIXME: Debug that!
+ //std::cout << "CALLING DONE FACE " << m_fontFace << std::endl;
+ FT_Done_Face(m_fontFace);
+ }
+
+ delete m_fontParams;
+}
+
+std::string Font::buildRequest(const FontVisualParams *fontParams, int &id)
+{
+ // Use FontConfig to locate & select fonts and use
+ // FreeType2 to open them
+ FcPattern *pattern;
+ std::string fileName;
+
+ pattern = FcPatternBuild(0,
+ FC_WEIGHT, FcTypeInteger, fontParams->weight(),
+ FC_SLANT, FcTypeInteger, fontParams->slant(),
+ FC_SIZE, FcTypeDouble, fontParams->size(),
+ NULL);
+
+ // Add multiple font names
+ std::list<std::string> &fontList = const_cast<FontVisualParams *>(fontParams)->fontList();
+
+ for(std::list<std::string>::const_iterator it = fontList.begin(); it != fontList.end(); ++it)
+ {
+ std::string string = *it;
+
+ if(!string.empty())
+ FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast<const FcChar8 *>(string.c_str()));
+ }
+
+ // Always load vertical layout
+ FcPatternAddBool(pattern, FC_VERTICAL_LAYOUT, true);
+
+ // Disable hinting
+ FcPatternAddBool(pattern, FC_HINTING, false);
+
+ // Perform the default font pattern modification operations.
+ FcDefaultSubstitute(pattern);
+ FcConfigSubstitute(FcConfigGetCurrent(), pattern, FcMatchPattern);
+
+ // Match the pattern!
+ FcResult result;
+ FcPattern *match = FcFontMatch(0, pattern, &result);
+
+ // Destroy pattern
+ FcPatternDestroy(pattern);
+
+ // Get index & filename
+ FcChar8 *temp;
+
+ if(match)
+ {
+ FcPattern *pattern = FcPatternDuplicate(match);
+
+ // Get index & filename
+ if(FcPatternGetString(pattern, FC_FILE, 0, &temp) != FcResultMatch ||
+ FcPatternGetInteger(pattern, FC_INDEX, 0, &id) != FcResultMatch)
+ {
+ std::cout << "Font::buildRequest(), could not load font file for requested font \"" << Tools::joinList('|', fontList) << "\"" << std::endl;
+ return fileName;
+ }
+
+ fileName = reinterpret_cast<const char *>(temp);
+
+ // Kill pattern
+ FcPatternDestroy(pattern);
+ }
+
+ // Kill pattern
+ FcPatternDestroy(match);
+
+ return fileName;
+}
+
+bool Font::load(const FontVisualParams *fontParams)
+{
+ // Build FontConfig request pattern
+ int id = -1;
+ std::string filename = Font::buildRequest(fontParams, id);
+
+ // Load font directly using FreeType2
+ std::cout << "Font::load(), loading " << filename << " for requested font \"" << Tools::joinList('|', const_cast<FontVisualParams *>(fontParams)->fontList()) << "\"" << std::endl;
+
+ FT_Error error = FT_New_Face(m_context->library(), filename.c_str(), id, &m_fontFace);
+ if(error)
+ {
+ std::cout << "Font::load(), could not load font. Aborting!" << std::endl;
+ return false;
+ }
+ if(!FT_IS_SCALABLE(m_fontFace))
+ {
+ std::cout << "Font::load(), font does not contain outlines. Aborting!" << std::endl;
+ FT_Done_Face(m_fontFace);
+ m_fontFace = 0;
+ return false;
+ }
+
+ // Choose unicode charmap
+ for(int charmap = 0; charmap < m_fontFace->num_charmaps; charmap++)
+ {
+ if(m_fontFace->charmaps[charmap]->encoding == ft_encoding_unicode)
+ {
+ FT_Error error = FT_Set_Charmap(m_fontFace, m_fontFace->charmaps[charmap]);
+
+ if(error)
+ {
+ std::cout << "Font::load(), unable to select unicode charmap. Aborting!" << std::endl;
+
+ FT_Done_Face(m_fontFace);
+ m_fontFace = 0;
+
+ return false;
+ }
+ }
+ }
+
+ m_fontParams = fontParams;
+ m_fontFile = filename;
+ m_ready = true;
+
+ return true;
+}
+
+FT_Face &Font::fontFace()
+{
+ return m_fontFace;
+}
+
+std::string Font::fontFile() const
+{
+ return m_fontFile;
+}
+
+const FontVisualParams *Font::fontParams() const
+{
+ return m_fontParams;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/libs/libtext2path/src/Font.h b/ksvg/impl/libs/libtext2path/src/Font.h
new file mode 100644
index 00000000..72844285
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/Font.h
@@ -0,0 +1,91 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef T2P_FONT_H
+#define T2P_FONT_H
+
+#include <list>
+#include <string>
+
+// FreeType 2 includes
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+namespace T2P
+{
+ class Converter;
+
+ class FontVisualParams
+ {
+ public:
+ FontVisualParams();
+ FontVisualParams(const FontVisualParams &other);
+ ~FontVisualParams();
+
+ FontVisualParams &operator=(const FontVisualParams &other);
+
+ void setWeight(int weight);
+ int weight() const;
+
+ void setSlant(int slant);
+ int slant() const;
+
+ void setSize(double size);
+ double size() const;
+
+ std::list<std::string> &fontList();
+
+ private:
+ int m_weight, m_slant;
+ double m_size;
+
+ std::list<std::string> m_fontList;
+ };
+
+ class Font
+ {
+ public:
+ Font(Converter *context);
+ ~Font();
+
+ // Build font loading request for FontConfig
+ static std::string buildRequest(const FontVisualParams *fontParams, int &id);
+
+ // Load it! :)
+ bool load(const FontVisualParams *fontParams);
+
+ FT_Face &fontFace();
+ std::string fontFile() const;
+ const FontVisualParams *fontParams() const;
+
+ private:
+ FT_Face m_fontFace;
+ std::string m_fontFile;
+
+ Converter *m_context;
+ const FontVisualParams *m_fontParams;
+
+ bool m_ready;
+ };
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/libs/libtext2path/src/Glyph.cpp b/ksvg/impl/libs/libtext2path/src/Glyph.cpp
new file mode 100644
index 00000000..5d172018
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/Glyph.cpp
@@ -0,0 +1,353 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <iostream>
+#include "Glyph.h"
+
+using namespace T2P;
+
+Glyph::Glyph()
+{
+ m_bezierPath = 0;
+}
+
+Glyph::~Glyph()
+{
+ delete m_bezierPath;
+ m_bezierPath = 0;
+}
+
+Affine &Glyph::affine()
+{
+ return m_affine;
+}
+
+void Glyph::setAffine(const Affine &affine)
+{
+ m_affine = affine;
+}
+
+const BezierPath *Glyph::bezierPath() const
+{
+ return const_cast<const BezierPath *>(m_bezierPath);
+}
+
+BezierPath *Glyph::modifiableBezierPath()
+{
+ return m_bezierPath;
+}
+
+void Glyph::setBezierPath(const BezierPath *bpath)
+{
+ m_bezierPath = const_cast<BezierPath *>(bpath);
+}
+
+FT_BBox *Glyph::ftBbox()
+{
+ return m_ftBbox;
+}
+
+// #####
+
+GlyphAffinePair::GlyphAffinePair(const Glyph *glyph, const Affine &affine)
+{
+ m_glyph = glyph;
+ m_affine = affine;
+ m_transformatedPath = 0;
+}
+
+GlyphAffinePair::~GlyphAffinePair()
+{
+ // The glyphs are shared and thus not deleted (Niko)
+ delete m_transformatedPath;
+}
+
+void GlyphAffinePair::setTransformatedPath(const BezierPath *path)
+{
+ m_transformatedPath = path;
+}
+
+const BezierPath *GlyphAffinePair::transformatedPath() const
+{
+ return m_transformatedPath;
+}
+
+const Glyph *GlyphAffinePair::glyph() const
+{
+ return m_glyph;
+}
+
+Affine &GlyphAffinePair::affine()
+{
+ return m_affine;
+}
+
+// #####
+
+GlyphSet::GlyphSet()
+{
+ m_glyphCount = 0;
+
+ m_bboxX = 0;
+ m_bboxY = 0;
+ m_width = 0;
+ m_height = 0;
+
+ m_xpen = 0;
+ m_ypen = 0;
+
+ m_underlinePosition = 0;
+ m_underlineThickness = 0;
+ m_overlinePosition = 0;
+ m_strikeThroughPosition = 0;
+ m_pixelBaseline = 0;
+}
+
+GlyphSet::~GlyphSet()
+{
+ m_set.clear();
+}
+
+std::vector<GlyphAffinePair *> &GlyphSet::set()
+{
+ return m_set;
+}
+
+std::list<float> GlyphSet::glyphXAdvance()
+{
+ return m_glyphXAdvance;
+}
+
+std::list<float> GlyphSet::glyphYAdvance()
+{
+ return m_glyphYAdvance;
+}
+
+unsigned int GlyphSet::glyphCount() const
+{
+ return m_glyphCount;
+}
+
+int GlyphSet::width() const
+{
+ return m_width;
+}
+
+int GlyphSet::height() const
+{
+ return m_height;
+}
+
+int GlyphSet::bboxX() const
+{
+ return m_bboxX;
+}
+
+int GlyphSet::bboxY() const
+{
+ return m_bboxY;
+}
+
+double GlyphSet::xpen() const
+{
+ return m_xpen;
+}
+
+double GlyphSet::ypen() const
+{
+ return m_ypen;
+}
+
+int GlyphSet::underlinePosition() const
+{
+ return m_underlinePosition;
+}
+
+int GlyphSet::underlineThickness() const
+{
+ return m_underlineThickness;
+}
+
+int GlyphSet::overlinePosition() const
+{
+ return m_overlinePosition;
+}
+
+int GlyphSet::strikeThroughPosition() const
+{
+ return m_strikeThroughPosition;
+}
+
+int GlyphSet::pixelBaseline() const
+{
+ return m_pixelBaseline;
+}
+
+// #####
+
+GlyphLayoutParams::GlyphLayoutParams()
+{
+}
+
+GlyphLayoutParams::~GlyphLayoutParams()
+{
+}
+
+bool GlyphLayoutParams::tb() const
+{
+ return m_tb;
+}
+
+void GlyphLayoutParams::setTb(bool tb)
+{
+ m_tb = tb;
+}
+
+bool GlyphLayoutParams::useBidi() const
+{
+ return m_useBidi;
+}
+
+void GlyphLayoutParams::setUseBidi(bool bidi)
+{
+ m_useBidi = bidi;
+}
+
+double GlyphLayoutParams::wordSpacing() const
+{
+ return m_wordSpacing;
+}
+
+void GlyphLayoutParams::setWordSpacing(double wordSpacing)
+{
+ m_wordSpacing = wordSpacing;
+}
+
+double GlyphLayoutParams::letterSpacing() const
+{
+ return m_letterSpacing;
+}
+
+void GlyphLayoutParams::setLetterSpacing(double letterSpacing)
+{
+ m_letterSpacing = letterSpacing;
+}
+
+std::string GlyphLayoutParams::baselineShift() const
+{
+ return m_baseline;
+}
+
+void GlyphLayoutParams::setBaselineShift(const std::string &baseline)
+{
+ m_baseline = baseline;
+}
+
+int GlyphLayoutParams::glyphOrientationVertical() const
+{
+ return m_glyphOrientationVertical;
+}
+
+void GlyphLayoutParams::setGlyphOrientationVertical(int orient)
+{
+ m_glyphOrientationVertical = orient;
+}
+
+int GlyphLayoutParams::glyphOrientationHorizontal() const
+{
+ return m_glyphOrientationHorizontal;
+}
+
+void GlyphLayoutParams::setGlyphOrientationHorizontal(int orient)
+{
+ m_glyphOrientationHorizontal = orient;
+}
+
+double GlyphLayoutParams::textPathStartOffset() const
+{
+ return m_textPathStartOffset;
+}
+
+void GlyphLayoutParams::setTextPathStartOffset(double offset)
+{
+ m_textPathStartOffset = offset;
+}
+
+// #####
+
+GlyphRenderParams::GlyphRenderParams()
+{
+}
+
+GlyphRenderParams::~GlyphRenderParams()
+{
+}
+
+Font *GlyphRenderParams::font() const
+{
+ return m_font;
+}
+
+void GlyphRenderParams::setFont(Font *font)
+{
+ m_font = font;
+}
+
+const GlyphLayoutParams *GlyphRenderParams::layout() const
+{
+ return m_layout;
+}
+
+void GlyphRenderParams::setLayout(const GlyphLayoutParams *layout)
+{
+ m_layout = layout;
+}
+
+unsigned int GlyphRenderParams::glyphIndex() const
+{
+ return m_glyphIndex;
+}
+
+void GlyphRenderParams::setGlyphIndex(unsigned int glyphIndex)
+{
+ m_glyphIndex = glyphIndex;
+}
+
+unsigned int GlyphRenderParams::lastGlyph() const
+{
+ return m_lastGlyph;
+}
+
+void GlyphRenderParams::setLastGlyph(unsigned int lastGlyph)
+{
+ m_lastGlyph = lastGlyph;
+}
+
+unsigned short GlyphRenderParams::character() const
+{
+ return m_character;
+}
+
+void GlyphRenderParams::setCharacter(unsigned short character)
+{
+ m_character = character;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/libs/libtext2path/src/Glyph.h b/ksvg/impl/libs/libtext2path/src/Glyph.h
new file mode 100644
index 00000000..b3bd3fb5
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/Glyph.h
@@ -0,0 +1,198 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef T2P_GLYPH_H
+#define T2P_GLYPH_H
+
+#include <list>
+#include <vector>
+#include <string>
+
+#include "Affine.h"
+#include "BezierPath.h"
+
+// FreeType 2 includes
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+namespace T2P
+{
+ class Font;
+
+ // Represent one single glyph in cache
+ class Glyph
+ {
+ public:
+ Glyph();
+ ~Glyph();
+
+ Affine &affine(); // Initial tracing affine
+ void setAffine(const Affine &affine);
+
+ const BezierPath *bezierPath() const; // Non-modifyable bezierPath belonging to this glyph
+ BezierPath *modifiableBezierPath(); // ONLY USED BY GLYPHTRACER, DO NOT USE SOMEWHERE ELSE!
+ void setBezierPath(const BezierPath *bpath);
+
+ FT_BBox *ftBbox();
+
+ private:
+ Affine m_affine;
+ FT_BBox m_ftBbox[4];
+ BezierPath *m_bezierPath;
+ };
+
+ // Is created for every character which needs to
+ // be rendered and has to be deleted by the "client"
+ class GlyphAffinePair
+ {
+ public:
+ GlyphAffinePair(const Glyph *glyph, const Affine &affine);
+ ~GlyphAffinePair();
+
+ void setTransformatedPath(const BezierPath *path);
+ const BezierPath *transformatedPath() const;
+
+ const Glyph *glyph() const;
+ Affine &affine();
+
+ private:
+ const Glyph *m_glyph;
+ const BezierPath *m_transformatedPath;
+ Affine m_affine;
+ };
+
+ class GlyphSet
+ {
+ public:
+ GlyphSet();
+ ~GlyphSet();
+
+ std::vector<GlyphAffinePair *> &set();
+ std::list<float> glyphXAdvance();
+ std::list<float> glyphYAdvance();
+
+ unsigned int glyphCount() const;
+
+ int width() const;
+ int height() const;
+
+ int bboxX() const;
+ int bboxY() const;
+
+ double xpen() const;
+ double ypen() const;
+
+ int underlinePosition() const;
+ int underlineThickness() const;
+ int overlinePosition() const;
+ int strikeThroughPosition() const;
+ int pixelBaseline() const;
+
+ private:
+ friend class Converter;
+ unsigned int m_glyphCount; // Number of glyphs in the set
+
+ int m_bboxX, m_bboxY; // Bounding box locations (x,y) + (x + width, y + width)
+ int m_width, m_height;
+
+ double m_xpen, m_ypen; // relative pen locations
+
+ int m_underlinePosition, m_underlineThickness, m_overlinePosition, m_strikeThroughPosition, m_pixelBaseline;
+
+ std::vector<GlyphAffinePair *> m_set; // Bezier paths in the set
+
+ std::list<float> m_glyphXAdvance; // List of advance values needed ie. for text paths
+ std::list<float> m_glyphYAdvance;
+ };
+
+ class GlyphLayoutParams
+ {
+ public:
+ GlyphLayoutParams();
+ ~GlyphLayoutParams();
+
+ bool tb() const;
+ void setTb(bool tb);
+
+ bool useBidi() const;
+ void setUseBidi(bool bidi);
+
+ double wordSpacing() const;
+ void setWordSpacing(double wordSpacing);
+
+ double letterSpacing() const;
+ void setLetterSpacing(double letterSpacing);
+
+ std::string baselineShift() const;
+ void setBaselineShift(const std::string &baseline);
+
+ int glyphOrientationVertical() const;
+ void setGlyphOrientationVertical(int orient);
+
+ int glyphOrientationHorizontal() const;
+ void setGlyphOrientationHorizontal(int orient);
+
+ // textOnPath specific stuff
+ double textPathStartOffset() const;
+ void setTextPathStartOffset(double offset);
+
+ private:
+ bool m_tb; // Top-To-Bottom or Bottom-To-Top ?
+ bool m_useBidi; // Use Bidi ?
+ double m_wordSpacing, m_letterSpacing; // word/character spacing
+ double m_textPathStartOffset; // range: 0.0 - 1.0; start offset in the path
+ int m_glyphOrientationVertical, m_glyphOrientationHorizontal; // Degrees...
+ std::string m_baseline; // baseline description, using same system as svg
+ };
+
+ class GlyphRenderParams
+ {
+ public:
+ GlyphRenderParams();
+ ~GlyphRenderParams();
+
+ Font *font() const;
+ void setFont(Font *font);
+
+ const GlyphLayoutParams *layout() const;
+ void setLayout(const GlyphLayoutParams *layout);
+
+ unsigned int glyphIndex() const;
+ void setGlyphIndex(unsigned int glyphIndex);
+
+ unsigned int lastGlyph() const;
+ void setLastGlyph(unsigned int lastGlyph);
+
+ unsigned short character() const;
+ void setCharacter(unsigned short character);
+
+ private:
+ Font *m_font;
+ const GlyphLayoutParams *m_layout; // Glyph layouting params
+
+ unsigned int m_glyphIndex; // 'character' index in font
+ unsigned int m_lastGlyph; // Kerning
+ unsigned short m_character; // Unicode glyph to process
+ };
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/libs/libtext2path/src/GlyphTracer.cpp b/ksvg/impl/libs/libtext2path/src/GlyphTracer.cpp
new file mode 100644
index 00000000..42457553
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/GlyphTracer.cpp
@@ -0,0 +1,76 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "GlyphTracer.h"
+
+using namespace T2P;
+
+GlyphTracer::GlyphTracer()
+{
+ m_moveTo = 0;
+ m_lineTo = 0;
+ m_conicBezier = 0;
+ m_cubicBezier = 0;
+ m_outlineMethods = 0;
+}
+
+GlyphTracer::~GlyphTracer()
+{
+ delete m_outlineMethods;
+}
+
+void GlyphTracer::setMoveto(FT_Outline_MoveToFunc funcPtr)
+{
+ m_moveTo = funcPtr;
+}
+
+void GlyphTracer::setLineto(FT_Outline_LineToFunc funcPtr)
+{
+ m_lineTo = funcPtr;
+}
+
+void GlyphTracer::setConicBezier(FT_Outline_ConicToFunc funcPtr)
+{
+ m_conicBezier = funcPtr;
+}
+
+void GlyphTracer::setCubicBezier(FT_Outline_CubicToFunc funcPtr)
+{
+ m_cubicBezier = funcPtr;
+}
+
+FT_Outline_Funcs *GlyphTracer::outlineFuncs()
+{
+ if(m_outlineMethods)
+ return m_outlineMethods;
+
+ FT_Outline_Funcs *ret = new FT_Outline_Funcs();
+ ret->move_to = m_moveTo;
+ ret->line_to = m_lineTo;
+ ret->conic_to = m_conicBezier;
+ ret->cubic_to = m_cubicBezier;
+ ret->shift = 0;
+ ret->delta = 0;
+
+ m_outlineMethods = ret;
+ return m_outlineMethods;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/libs/libtext2path/src/GlyphTracer.h b/ksvg/impl/libs/libtext2path/src/GlyphTracer.h
new file mode 100644
index 00000000..7607ecad
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/GlyphTracer.h
@@ -0,0 +1,65 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef T2P_GLYPHTRACER_H
+#define T2P_GLYPHTRACER_H
+
+// FreeType 2 includes
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+namespace T2P
+{
+ class Glyph;
+ class BezierPath;
+ class GlyphAffinePair;
+
+ class GlyphTracer
+ {
+ public:
+ GlyphTracer();
+ virtual ~GlyphTracer();
+
+ // Needs to be implemented
+ virtual void correctGlyph(GlyphAffinePair *glyphAffine) = 0;
+ virtual BezierPath *allocBezierPath(int size) = 0;
+ virtual void closePath(Glyph *glyph) = 0;
+
+ // FreeType glyph tracing functions
+ void setMoveto(FT_Outline_MoveToFunc funcPtr);
+ void setLineto(FT_Outline_LineToFunc funcPtr);
+ void setConicBezier(FT_Outline_ConicToFunc funcPtr);
+ void setCubicBezier(FT_Outline_CubicToFunc funcPtr);
+
+ FT_Outline_Funcs *outlineFuncs();
+
+ private:
+ FT_Outline_Funcs *m_outlineMethods;
+
+ FT_Outline_MoveToFunc m_moveTo;
+ FT_Outline_LineToFunc m_lineTo;
+ FT_Outline_ConicToFunc m_conicBezier;
+ FT_Outline_CubicToFunc m_cubicBezier;
+ };
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/libs/libtext2path/src/Makefile.am b/ksvg/impl/libs/libtext2path/src/Makefile.am
new file mode 100644
index 00000000..175e1a91
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/Makefile.am
@@ -0,0 +1,10 @@
+lib_LTLIBRARIES = libtext2path.la
+
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+INCLUDES = $(FRIBIDI_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) $(all_includes)
+
+libtext2path_includedir=$(includedir)/libtext2path-0.1
+libtext2path_include_HEADERS = BezierPath.h Glyph.h GlyphTracer.h
+
+libtext2path_la_SOURCES = Affine.cpp Rectangle.cpp Font.cpp Glyph.cpp GlyphTracer.cpp Converter.cpp QtUnicode.cpp
+libtext2path_la_LDFLAGS = $(FRIBIDI_LIBS) $(FONTCONFIG_LIBS)
diff --git a/ksvg/impl/libs/libtext2path/src/Point.h b/ksvg/impl/libs/libtext2path/src/Point.h
new file mode 100644
index 00000000..d95742a2
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/Point.h
@@ -0,0 +1,65 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef T2P_POINT_H
+#define T2P_POINT_H
+
+namespace T2P
+{
+ class Point
+ {
+ public:
+ Point() { m_x = 0.0; m_y = 0.0; }
+ Point(double x, double y) { m_x = x; m_y = y; }
+ Point &operator=(const Point &other) { m_x = other.x(); m_y = other.y(); return *this; }
+
+ friend inline Point operator+(const Point &, const Point &);
+ friend inline Point operator-(const Point &, const Point &);
+ friend inline Point operator*(const double &, const Point &);
+ friend inline Point operator*(const Point &, const double &);
+
+ double x() const { return m_x; }
+ double y() const { return m_y; }
+
+ void setX(double x) { m_x = x; }
+ void setY(double y) { m_y = y; }
+
+ const Point invert() const
+ {
+ Point temp;
+ temp.setX(-x());
+ temp.setY(-y());
+ return temp;
+ }
+
+ private:
+ double m_x;
+ double m_y;
+ };
+
+ inline Point operator+(const Point &p1, const Point &p2) { return Point(p1.m_x + p2.m_x, p1.m_y + p2.m_y); }
+ inline Point operator-(const Point &p1, const Point &p2) { return Point(p1.m_x - p2.m_x, p1.m_y - p2.m_y); }
+ inline Point operator*(const double &c, const Point &p) { return Point(p.m_x * c, p.m_y * c); }
+ inline Point operator*(const Point &p, const double &c) { return Point(p.m_x * c, p.m_y * c); }
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/libs/libtext2path/src/QtUnicode.cpp b/ksvg/impl/libs/libtext2path/src/QtUnicode.cpp
new file mode 100644
index 00000000..694ed5c7
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/QtUnicode.cpp
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+**
+** ???
+**
+** Copyright (C) 2002-2003 Trolltech AS. All rights reserved.
+**
+** This file is part of the kernel module of the Qt GUI Toolkit.
+**
+** This file may be distributed under the terms of the Q Public License
+** as defined by Trolltech AS of Norway and appearing in the file
+** LICENSE.QPL included in the packaging of this file.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
+** licenses may use this file in accordance with the Qt Commercial License
+** Agreement provided with the Software.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
+** information about Qt Commercial License Agreements.
+** See http://www.trolltech.com/qpl/ for QPL licensing information.
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact info@trolltech.com if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include "QtUnicode.h"
+
+using namespace T2P;
+// START OF GENERATED DATA
+
+// copied form qfont.h, as we can't include it in tools. Do not modify without
+// changing the script enum in qfont.h aswell.
+const unsigned char QtUnicode::otherScripts [120] = {
+#define SCRIPTS_02 0
+ 0xaf, Latin, 0xff, SpacingModifiers, // row 0x02, index 0
+#define SCRIPTS_03 4
+ 0x6f, CombiningMarks, 0xff, Greek, // row 0x03, index 4
+#define SCRIPTS_05 8
+ 0x2f, Cyrillic, 0x8f, Armenian, 0xff, Hebrew, // row 0x05, index 8
+#define SCRIPTS_07 14
+ 0x4f, Syriac, 0x7f, Unicode, 0xbf, Thaana,
+ 0xff, Unicode, // row 0x07, index 14
+#define SCRIPTS_10 22
+ 0x9f, Myanmar, 0xff, Georgian, // row 0x10, index 20
+#define SCRIPTS_13 26
+ 0x7f, Ethiopic, 0x9f, Unicode, 0xff, Cherokee, // row 0x13, index 24
+#define SCRIPTS_16 32
+ 0x7f, CanadianAboriginal, 0x9f, Ogham,
+ 0xff, Runic, // row 0x16 index 30
+#define SCRIPTS_17 38
+ 0x1f, Tagalog, 0x3f, Hanunoo, 0x5f, Buhid,
+ 0x7f, Tagbanwa, 0xff, Khmer, // row 0x17, index 36
+#define SCRIPTS_18 48
+ 0xaf, Mongolian, 0xff, Unicode, // row 0x18, index 46
+#define SCRIPTS_20 52
+ 0x0b, Unicode, 0x0d, UnknownScript, 0x6f, Unicode, 0x9f, NumberForms,
+ 0xab, CurrencySymbols, 0xac, Latin,
+ 0xcf, CurrencySymbols, 0xff, CombiningMarks, // row 0x20, index 50
+#define SCRIPTS_21 68
+ 0x4f, LetterlikeSymbols, 0x8f, NumberForms,
+ 0xff, MathematicalOperators, // row 0x21, index 62
+#define SCRIPTS_24 74
+ 0x5f, TechnicalSymbols, 0xff, EnclosedAndSquare, // row 0x24, index 68
+#define SCRIPTS_2e 78
+ 0x7f, Unicode, 0xff, Han, // row 0x2e, index 72
+#define SCRIPTS_30 82
+ 0x3f, Han, 0x9f, Hiragana, 0xff, Katakana, // row 0x30, index 76
+#define SCRIPTS_31 88
+ 0x2f, Bopomofo, 0x8f, Hangul, 0x9f, Han,
+ 0xff, Unicode, // row 0x31, index 82
+#define SCRIPTS_fb 96
+ 0x06, Latin, 0x1c, Unicode, 0x4f, Hebrew,
+ 0xff, Arabic, // row 0xfb, index 90
+#define SCRIPTS_fe 104
+ 0x1f, Unicode, 0x2f, CombiningMarks, 0x6f, Unicode,
+ 0xff, Arabic, // row 0xfe, index 98
+#define SCRIPTS_ff 112
+ 0x5e, Katakana, 0x60, Unicode, // row 0xff, index 106
+ 0x9f, KatakanaHalfWidth, 0xff, Unicode
+};
+
+// (uc-0x0900)>>7
+const unsigned char QtUnicode::indicScripts [] =
+{
+ Devanagari, Bengali,
+ Gurmukhi, Gujarati,
+ Oriya, Tamil,
+ Telugu, Kannada,
+ Malayalam, Sinhala,
+ Thai, Lao
+};
+
+
+// 0x80 + x: x is the offset into the otherScripts table
+const unsigned char QtUnicode::scriptTable[256] =
+{
+ Latin, Latin, 0x80+SCRIPTS_02, 0x80+SCRIPTS_03,
+ Cyrillic, 0x80+SCRIPTS_05, Arabic, 0x80+SCRIPTS_07,
+ Unicode, SCRIPTS_INDIC, SCRIPTS_INDIC, SCRIPTS_INDIC,
+ SCRIPTS_INDIC, SCRIPTS_INDIC, SCRIPTS_INDIC, Tibetan,
+
+ 0x80+SCRIPTS_10, Hangul, Ethiopic, 0x80+SCRIPTS_13,
+ CanadianAboriginal, CanadianAboriginal, 0x80+SCRIPTS_16, 0x80+SCRIPTS_17,
+ 0x80+SCRIPTS_18, Unicode, Unicode, Unicode,
+ Unicode, Unicode, Latin, Greek,
+
+ 0x80+SCRIPTS_20, 0x80+SCRIPTS_21, MathematicalOperators, TechnicalSymbols,
+ 0x80+SCRIPTS_24, GeometricSymbols, MiscellaneousSymbols, MiscellaneousSymbols,
+ Braille, Unicode, Unicode, Unicode,
+ Unicode, Unicode, 0x80+SCRIPTS_2e, Han,
+
+ 0x80+SCRIPTS_30, 0x80+SCRIPTS_31, EnclosedAndSquare, EnclosedAndSquare,
+ Han, Han, Han, Han,
+ Han, Han, Han, Han,
+ Han, Han, Han, Han,
+
+ Han, Han, Han, Han, Han, Han, Han, Han,
+ Han, Han, Han, Han, Han, Han, Han, Han,
+
+ Han, Han, Han, Han, Han, Han, Han, Han,
+ Han, Han, Han, Han, Han, Han, Han, Han,
+
+ Han, Han, Han, Han, Han, Han, Han, Han,
+ Han, Han, Han, Han, Han, Han, Han, Han,
+
+ Han, Han, Han, Han, Han, Han, Han, Han,
+ Han, Han, Han, Han, Han, Han, Han, Han,
+
+
+ Han, Han, Han, Han, Han, Han, Han, Han,
+ Han, Han, Han, Han, Han, Han, Han, Han,
+
+ Han, Han, Han, Han, Han, Han, Han, Han,
+ Han, Han, Han, Han, Han, Han, Han, Han,
+
+ Yi, Yi, Yi, Yi, Yi, Unicode, Unicode, Unicode,
+ Unicode, Unicode, Unicode, Unicode, Hangul, Hangul, Hangul, Hangul,
+
+ Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, Hangul,
+ Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, Hangul,
+
+ Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, Hangul,
+ Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, Hangul,
+
+ Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, Hangul, Hangul,
+ Unicode, Unicode, Unicode, Unicode, Unicode, Unicode, Unicode, Unicode,
+
+ Unicode, Unicode, Unicode, Unicode, Unicode, Unicode, Unicode, Unicode,
+ Unicode, Unicode, Unicode, Unicode, Unicode, Unicode, Unicode, Unicode,
+
+ Unicode, Unicode, Unicode, Unicode, Unicode, Unicode, Unicode, Unicode,
+ Unicode, Han, Han, 0x80+SCRIPTS_fb, Arabic, Arabic, 0x80+SCRIPTS_fe, 0x80+SCRIPTS_ff
+};
+
diff --git a/ksvg/impl/libs/libtext2path/src/QtUnicode.h b/ksvg/impl/libs/libtext2path/src/QtUnicode.h
new file mode 100644
index 00000000..41008500
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/QtUnicode.h
@@ -0,0 +1,149 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef T2P_QT_UNICODE_H
+#define T2P_QT_UNICODE_H
+
+namespace T2P
+{
+ enum Script
+ {
+ // European Alphabetic Scripts
+ Latin,
+ Greek,
+ Cyrillic,
+ Armenian,
+ Georgian,
+ Runic,
+ Ogham,
+ SpacingModifiers,
+ CombiningMarks,
+
+ // Middle Eastern Scripts
+ Hebrew,
+ Arabic,
+ Syriac,
+ Thaana,
+
+ // South and Southeast Asian Scripts
+ Devanagari,
+ Bengali,
+ Gurmukhi,
+ Gujarati,
+ Oriya,
+ Tamil,
+ Telugu,
+ Kannada,
+ Malayalam,
+ Sinhala,
+ Thai,
+ Lao,
+ Tibetan,
+ Myanmar,
+ Khmer,
+
+ // East Asian Scripts
+ Han,
+ Hiragana,
+ Katakana,
+ Hangul,
+ Bopomofo,
+ Yi,
+
+ // Additional Scripts
+ Ethiopic,
+ Cherokee,
+ CanadianAboriginal,
+ Mongolian,
+
+ // Symbols
+ CurrencySymbols,
+ LetterlikeSymbols,
+ NumberForms,
+ MathematicalOperators,
+ TechnicalSymbols,
+ GeometricSymbols,
+ MiscellaneousSymbols,
+ EnclosedAndSquare,
+ Braille,
+
+ Unicode,
+
+ // some scripts added in Unicode 3.2
+ Tagalog,
+ Hanunoo,
+ Buhid,
+ Tagbanwa,
+
+ KatakanaHalfWidth,
+
+ // End
+ NScripts,
+ UnknownScript = NScripts
+ };
+
+ class QtUnicode
+ {
+ public:
+ QtUnicode() { }
+ ~QtUnicode() { }
+
+ static int scriptForChar(unsigned short uc)
+ {
+ unsigned char script = QtUnicode::scriptTable[(uc >> 8)];
+ if(script >= QtUnicode::SCRIPTS_INDIC)
+ {
+ if(script == QtUnicode::SCRIPTS_INDIC)
+ script = QtUnicode::indicScripts[(uc - 0x0900) >> 7];
+ else
+ {
+ // 0x80 + SCRIPTS_xx
+ unsigned char index = script - 0x80;
+ unsigned char cell = uc & 0xff;
+ while(QtUnicode::otherScripts[index++] < cell)
+ index++;
+ script = QtUnicode::otherScripts[index];
+ }
+ }
+
+ return script;
+ }
+
+ private:
+ enum
+ {
+ SCRIPTS_INDIC = 0x7e
+ };
+
+ static const unsigned char otherScripts[];
+ static const unsigned char indicScripts[];
+ static const unsigned char scriptTable[];
+ };
+}
+
+#define SCRIPT_FOR_CHAR(script, c) \
+if(c < 0x100) \
+ script = T2P::Latin; \
+else \
+ script = (T2P::Script) QtUnicode::scriptForChar(c);
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/libs/libtext2path/src/Rectangle.cpp b/ksvg/impl/libs/libtext2path/src/Rectangle.cpp
new file mode 100644
index 00000000..ef59d6be
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/Rectangle.cpp
@@ -0,0 +1,102 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "Tools.h"
+#include "Rectangle.h"
+
+using namespace T2P;
+
+Rectangle::Rectangle()
+{
+}
+
+Rectangle::Rectangle(const Rectangle &other)
+{
+ (*this) = other;
+}
+
+Rectangle::Rectangle(const Point &a, const Point &b) : m_a(a), m_b(b)
+{
+}
+
+Rectangle::Rectangle(double x, double y, double width, double height)
+{
+ m_a = Point(x, y);
+ m_b = Point(x + width, y + height);
+}
+
+Rectangle::~Rectangle()
+{
+}
+
+Rectangle &Rectangle::operator=(const Rectangle &other)
+{
+ m_a = other.m_a;
+ m_b = other.m_b;
+
+ return *this;
+}
+
+Point Rectangle::a() const
+{
+ return m_a;
+}
+
+void Rectangle::setA(const Point &a)
+{
+ m_a = a;
+}
+
+Point Rectangle::b() const
+{
+ return m_b;
+}
+
+void Rectangle::setB(const Point &b)
+{
+ m_b = b;
+}
+
+void Rectangle::bboxUnion(const Rectangle &src1, const Rectangle &src2)
+{
+ double src1x0 = src1.a().x(), src1x1 = src1.b().x();
+ double src1y0 = src1.a().y(), src1y1 = src1.b().y();
+
+ double src2x0 = src2.a().x(), src2x1 = src2.b().x();
+ double src2y0 = src2.a().y(), src2y1 = src2.b().y();
+
+ if(src1x1 <= src1x0 || src1y1 <= src1y0) // Is src1 empty?
+ { // Copy src2 to dst
+ setA(Point(src2x0, src2y0));
+ setB(Point(src2x1, src2y1));
+ }
+ else if(src2x1 <= src2x0 || src2y1 <= src2y0) // Is src2 empty?
+ { // Copy src1 to dest
+ setA(Point(src1x0, src1y0));
+ setB(Point(src1x1, src1y1));
+ }
+ else
+ {
+ setA(Point(T2PMIN(src1x0, src2x0), T2PMIN(src1y0, src2y0)));
+ setB(Point(T2PMAX(src1x1, src2x1), T2PMAX(src1y1, src2y1)));
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/libs/libtext2path/src/Rectangle.h b/ksvg/impl/libs/libtext2path/src/Rectangle.h
new file mode 100644
index 00000000..1a5eeeb1
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/Rectangle.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef T2P_RECTANGLE_H
+#define T2P_RECTANGLE_H
+
+#include "Point.h"
+
+namespace T2P
+{
+ class Rectangle
+ {
+ public:
+ Rectangle();
+ Rectangle(const Rectangle &other);
+ Rectangle(const Point &a, const Point &b);
+ Rectangle(double x, double y, double width, double height);
+ ~Rectangle();
+
+ Rectangle &operator=(const Rectangle &other);
+
+ Point a() const;
+ void setA(const Point &a);
+
+ Point b() const;
+ void setB(const Point &b);
+
+ // Finds the smallest rectangle that includes src1 and src2.
+ void bboxUnion(const Rectangle &src1, const Rectangle &src2);
+
+ private:
+ Point m_a, m_b;
+ };
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/libs/libtext2path/src/Tools.h b/ksvg/impl/libs/libtext2path/src/Tools.h
new file mode 100644
index 00000000..c7753365
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/Tools.h
@@ -0,0 +1,85 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef T2P_TOOLS_H
+#define T2P_TOOLS_H
+
+#include <list>
+#include <string>
+#include <config.h>
+#ifdef HAVE_SSTREAM
+# include <sstream>
+#else
+# include <strstream>
+# define ostringstream ostrstream
+#endif
+
+#define T2PMAX(a, b) ((b) < (a) ? (a) : (b))
+#define T2PMIN(a, b) ((a) < (b) ? (a) : (b))
+
+namespace T2P
+{
+ class Tools
+ {
+ public:
+ static std::string joinList(char seperator, std::list<std::string> &list)
+ {
+ std::string result;
+
+ if(list.empty())
+ return result;
+
+ bool first = true;
+ for(std::list<std::string>::const_iterator it = list.begin(); it != list.end(); ++it)
+ {
+ std::string string = *it;
+
+ if(!string.empty())
+ {
+ if(!first)
+ result += seperator + string;
+ else
+ {
+ result += string;
+ first = false;
+ }
+ }
+ }
+
+ return result;
+ }
+
+ template<typename T>
+ static std::string a2str(T arg)
+ {
+ std::ostringstream buffer;
+ buffer << arg;
+ return buffer.str();
+ }
+ };
+}
+
+#ifdef ostringstream
+# undef ostringstream
+#endif
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/impl/libs/libtext2path/src/myboost/assert.hpp b/ksvg/impl/libs/libtext2path/src/myboost/assert.hpp
new file mode 100644
index 00000000..3f3c61c2
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/myboost/assert.hpp
@@ -0,0 +1,24 @@
+//
+// boost/assert.hpp - BOOST_ASSERT(expr)
+//
+// Copyright (c) 2001, 2002 Peter Dimov and Multi Media Ltd.
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+// Note: There are no include guards. This is intentional.
+//
+// See http://www.boost.org/libs/utility/assert.html for documentation.
+//
+
+#ifndef ASSERT_HPP
+#define ASSERT_HPP
+
+#undef BOOST_ASSERT
+
+# include <assert.h>
+# define BOOST_ASSERT(expr) assert(expr)
+
+#endif
diff --git a/ksvg/impl/libs/libtext2path/src/myboost/checked_delete.hpp b/ksvg/impl/libs/libtext2path/src/myboost/checked_delete.hpp
new file mode 100644
index 00000000..73afd5f5
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/myboost/checked_delete.hpp
@@ -0,0 +1,61 @@
+#ifndef BOOST_CHECKED_DELETE_HPP_INCLUDED
+#define BOOST_CHECKED_DELETE_HPP_INCLUDED
+
+//
+// boost/checked_delete.hpp
+//
+// Copyright (c) 1999, 2000, 2001, 2002 boost.org
+// Copyright (c) 2002, 2003 Peter Dimov
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+// See http://www.boost.org/libs/utility/checked_delete.html for documentation.
+//
+
+namespace myboost
+{
+
+// verify that types are complete for increased safety
+
+template<class T> inline void checked_delete(T * x)
+{
+ // Intel 7 accepts sizeof(incomplete) as 0 in system headers
+ typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
+ delete x;
+}
+
+template<class T> inline void checked_array_delete(T * x)
+{
+ typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
+ delete [] x;
+}
+
+template<class T> struct checked_deleter
+{
+ typedef void result_type;
+ typedef T * argument_type;
+
+ void operator()(T * x) const
+ {
+ // boost:: disables ADL
+ myboost::checked_delete(x);
+ }
+};
+
+template<class T> struct checked_array_deleter
+{
+ typedef void result_type;
+ typedef T * argument_type;
+
+ void operator()(T * x) const
+ {
+ myboost::checked_array_delete(x);
+ }
+};
+
+} // namespace myboost
+
+#endif // #ifndef BOOST_CHECKED_DELETE_HPP_INCLUDED
diff --git a/ksvg/impl/libs/libtext2path/src/myboost/lightweight_mutex.hpp b/ksvg/impl/libs/libtext2path/src/myboost/lightweight_mutex.hpp
new file mode 100644
index 00000000..10db127c
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/myboost/lightweight_mutex.hpp
@@ -0,0 +1,74 @@
+#ifndef BOOST_DETAIL_LWM_PTHREADS_HPP_INCLUDED
+#define BOOST_DETAIL_LWM_PTHREADS_HPP_INCLUDED
+
+//
+// boost/detail/lwm_pthreads.hpp
+//
+// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+
+#include <pthread.h>
+
+namespace myboost
+{
+
+namespace detail
+{
+
+class lightweight_mutex
+{
+private:
+
+ pthread_mutex_t m_;
+
+ lightweight_mutex(lightweight_mutex const &);
+ lightweight_mutex & operator=(lightweight_mutex const &);
+
+public:
+
+ lightweight_mutex()
+ {
+ pthread_mutex_init(&m_, 0);
+ }
+
+ ~lightweight_mutex()
+ {
+ pthread_mutex_destroy(&m_);
+ }
+
+ class scoped_lock;
+ friend class scoped_lock;
+
+ class scoped_lock
+ {
+ private:
+
+ pthread_mutex_t & m_;
+
+ scoped_lock(scoped_lock const &);
+ scoped_lock & operator=(scoped_lock const &);
+
+ public:
+
+ scoped_lock(lightweight_mutex & m): m_(m.m_)
+ {
+ pthread_mutex_lock(&m_);
+ }
+
+ ~scoped_lock()
+ {
+ pthread_mutex_unlock(&m_);
+ }
+ };
+};
+
+} // namespace detail
+
+} // namespace myboost
+
+#endif // #ifndef BOOST_DETAIL_LWM_PTHREADS_HPP_INCLUDED
diff --git a/ksvg/impl/libs/libtext2path/src/myboost/shared_count.hpp b/ksvg/impl/libs/libtext2path/src/myboost/shared_count.hpp
new file mode 100644
index 00000000..e8ec19a8
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/myboost/shared_count.hpp
@@ -0,0 +1,367 @@
+#ifndef BOOST_DETAIL_SHARED_COUNT_HPP_INCLUDED
+#define BOOST_DETAIL_SHARED_COUNT_HPP_INCLUDED
+
+//
+// detail/shared_count.hpp
+//
+// Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd.
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+
+#include "myboost/checked_delete.hpp"
+#include "myboost/throw_exception.hpp"
+#include "myboost/lightweight_mutex.hpp"
+
+#include <memory> // std::auto_ptr, std::allocator
+#include <functional> // std::less
+#include <exception> // std::exception
+#include <new> // std::bad_alloc
+#include <typeinfo> // std::type_info in get_deleter
+#include <cstddef> // std::size_t
+
+namespace myboost
+{
+
+class bad_weak_ptr: public std::exception
+{
+public:
+
+ virtual char const * what() const throw()
+ {
+ return "myboost::bad_weak_ptr";
+ }
+};
+
+namespace detail
+{
+
+class sp_counted_base
+{
+private:
+
+ typedef detail::lightweight_mutex mutex_type;
+
+public:
+
+ sp_counted_base(): use_count_(1), weak_count_(1)
+ {
+ }
+
+ virtual ~sp_counted_base() // nothrow
+ {
+ }
+
+ // dispose() is called when use_count_ drops to zero, to release
+ // the resources managed by *this.
+
+ virtual void dispose() = 0; // nothrow
+
+ // destruct() is called when weak_count_ drops to zero.
+
+ virtual void destruct() // nothrow
+ {
+ delete this;
+ }
+
+ virtual void * get_deleter(std::type_info const & ti) = 0;
+
+ void add_ref_copy()
+ {
+ mutex_type::scoped_lock lock(mtx_);
+ ++use_count_;
+ }
+
+ void add_ref_lock()
+ {
+ mutex_type::scoped_lock lock(mtx_);
+ if(use_count_ == 0) myboost::throw_exception(myboost::bad_weak_ptr());
+ ++use_count_;
+ }
+
+ void release() // nothrow
+ {
+ {
+ mutex_type::scoped_lock lock(mtx_);
+ long new_use_count = --use_count_;
+
+ if(new_use_count != 0) return;
+ }
+
+ dispose();
+ weak_release();
+ }
+
+ void weak_add_ref() // nothrow
+ {
+ mutex_type::scoped_lock lock(mtx_);
+ ++weak_count_;
+ }
+
+ void weak_release() // nothrow
+ {
+ long new_weak_count;
+
+ {
+ mutex_type::scoped_lock lock(mtx_);
+ new_weak_count = --weak_count_;
+ }
+
+ if(new_weak_count == 0)
+ {
+ destruct();
+ }
+ }
+
+ long use_count() const // nothrow
+ {
+ mutex_type::scoped_lock lock(mtx_);
+ return use_count_;
+ }
+
+private:
+
+ sp_counted_base(sp_counted_base const &);
+ sp_counted_base & operator= (sp_counted_base const &);
+
+ long use_count_; // #shared
+ long weak_count_; // #weak + (#shared != 0)
+
+ mutable mutex_type mtx_;
+};
+
+template<class P, class D> class sp_counted_base_impl: public sp_counted_base
+{
+private:
+
+ P ptr; // copy constructor must not throw
+ D del; // copy constructor must not throw
+
+ sp_counted_base_impl(sp_counted_base_impl const &);
+ sp_counted_base_impl & operator= (sp_counted_base_impl const &);
+
+ typedef sp_counted_base_impl<P, D> this_type;
+
+public:
+
+ // pre: initial_use_count <= initial_weak_count, d(p) must not throw
+
+ sp_counted_base_impl(P p, D d): ptr(p), del(d)
+ {
+ }
+
+ virtual void dispose() // nothrow
+ {
+ del(ptr);
+ }
+
+ virtual void * get_deleter(std::type_info const & ti)
+ {
+ return ti == typeid(D)? &del: 0;
+ }
+
+ void * operator new(std::size_t)
+ {
+ return std::allocator<this_type>().allocate(1, static_cast<this_type *>(0));
+ }
+
+ void operator delete(void * p)
+ {
+ std::allocator<this_type>().deallocate(static_cast<this_type *>(p), 1);
+ }
+};
+
+class weak_count;
+
+class shared_count
+{
+private:
+
+ sp_counted_base * pi_;
+
+ friend class weak_count;
+
+public:
+
+ shared_count(): pi_(0) // nothrow
+ {
+ }
+
+ template<class P, class D> shared_count(P p, D d): pi_(0)
+ {
+
+ try
+ {
+ pi_ = new sp_counted_base_impl<P, D>(p, d);
+ }
+ catch(...)
+ {
+ d(p); // delete p
+ throw;
+ }
+
+
+ pi_ = new sp_counted_base_impl<P, D>(p, d);
+
+ if(pi_ == 0)
+ {
+ d(p); // delete p
+ myboost::throw_exception(std::bad_alloc());
+ }
+ }
+
+ // auto_ptr<Y> is special cased to provide the strong guarantee
+
+ template<class Y>
+ explicit shared_count(std::auto_ptr<Y> & r): pi_(new sp_counted_base_impl< Y *, checked_deleter<Y> >(r.get(), checked_deleter<Y>()))
+ {
+ r.release();
+ }
+
+ ~shared_count() // nothrow
+ {
+ if(pi_ != 0) pi_->release();
+ }
+
+ shared_count(shared_count const & r): pi_(r.pi_) // nothrow
+ {
+ if(pi_ != 0) pi_->add_ref_copy();
+ }
+
+ explicit shared_count(weak_count const & r); // throws bad_weak_ptr when r.use_count() == 0
+
+ shared_count & operator= (shared_count const & r) // nothrow
+ {
+ sp_counted_base * tmp = r.pi_;
+ if(tmp != 0) tmp->add_ref_copy();
+ if(pi_ != 0) pi_->release();
+ pi_ = tmp;
+
+ return *this;
+ }
+
+ void swap(shared_count & r) // nothrow
+ {
+ sp_counted_base * tmp = r.pi_;
+ r.pi_ = pi_;
+ pi_ = tmp;
+ }
+
+ long use_count() const // nothrow
+ {
+ return pi_ != 0? pi_->use_count(): 0;
+ }
+
+ bool unique() const // nothrow
+ {
+ return use_count() == 1;
+ }
+
+ friend inline bool operator==(shared_count const & a, shared_count const & b)
+ {
+ return a.pi_ == b.pi_;
+ }
+
+ friend inline bool operator<(shared_count const & a, shared_count const & b)
+ {
+ return std::less<sp_counted_base *>()(a.pi_, b.pi_);
+ }
+
+ void * get_deleter(std::type_info const & ti) const
+ {
+ return pi_? pi_->get_deleter(ti): 0;
+ }
+};
+
+class weak_count
+{
+private:
+
+ sp_counted_base * pi_;
+
+ friend class shared_count;
+
+public:
+
+ weak_count(): pi_(0) // nothrow
+ {
+ }
+
+ weak_count(shared_count const & r): pi_(r.pi_) // nothrow
+ {
+ if(pi_ != 0) pi_->weak_add_ref();
+ }
+
+ weak_count(weak_count const & r): pi_(r.pi_) // nothrow
+ {
+ if(pi_ != 0) pi_->weak_add_ref();
+ }
+
+ ~weak_count() // nothrow
+ {
+ if(pi_ != 0) pi_->weak_release();
+ }
+
+ weak_count & operator= (shared_count const & r) // nothrow
+ {
+ sp_counted_base * tmp = r.pi_;
+ if(tmp != 0) tmp->weak_add_ref();
+ if(pi_ != 0) pi_->weak_release();
+ pi_ = tmp;
+
+ return *this;
+ }
+
+ weak_count & operator= (weak_count const & r) // nothrow
+ {
+ sp_counted_base * tmp = r.pi_;
+ if(tmp != 0) tmp->weak_add_ref();
+ if(pi_ != 0) pi_->weak_release();
+ pi_ = tmp;
+
+ return *this;
+ }
+
+ void swap(weak_count & r) // nothrow
+ {
+ sp_counted_base * tmp = r.pi_;
+ r.pi_ = pi_;
+ pi_ = tmp;
+ }
+
+ long use_count() const // nothrow
+ {
+ return pi_ != 0? pi_->use_count(): 0;
+ }
+
+ friend inline bool operator==(weak_count const & a, weak_count const & b)
+ {
+ return a.pi_ == b.pi_;
+ }
+
+ friend inline bool operator<(weak_count const & a, weak_count const & b)
+ {
+ return std::less<sp_counted_base *>()(a.pi_, b.pi_);
+ }
+};
+
+inline shared_count::shared_count(weak_count const & r): pi_(r.pi_)
+{
+ if(pi_ != 0)
+ {
+ pi_->add_ref_lock();
+ }
+ else
+ {
+ myboost::throw_exception(myboost::bad_weak_ptr());
+ }
+}
+
+} // namespace detail
+
+} // namespace myboost
+
+#endif // #ifndef BOOST_DETAIL_SHARED_COUNT_HPP_INCLUDED
diff --git a/ksvg/impl/libs/libtext2path/src/myboost/shared_ptr.hpp b/ksvg/impl/libs/libtext2path/src/myboost/shared_ptr.hpp
new file mode 100644
index 00000000..3f2fe30d
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/myboost/shared_ptr.hpp
@@ -0,0 +1,395 @@
+#ifndef BOOST_SHARED_PTR_HPP_INCLUDED
+#define BOOST_SHARED_PTR_HPP_INCLUDED
+
+// shared_ptr.hpp
+//
+// (C) Copyright Greg Colvin and Beman Dawes 1998, 1999.
+// Copyright (c) 2001, 2002, 2003 Peter Dimov
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+// See http://www.boost.org/libs/smart_ptr/shared_ptr.htm for documentation.
+//
+
+#include "myboost/assert.hpp"
+#include "myboost/checked_delete.hpp"
+#include "myboost/throw_exception.hpp"
+#include "myboost/shared_count.hpp"
+
+#include <memory> // for std::auto_ptr
+#include <algorithm> // for std::swap
+#include <functional> // for std::less
+#include <typeinfo> // for std::bad_cast
+#include <iosfwd> // for std::basic_ostream
+
+namespace myboost
+{
+
+template<class T> class weak_ptr;
+template<class T> class enable_shared_from_this;
+
+namespace detail
+{
+
+struct static_cast_tag {};
+struct const_cast_tag {};
+struct dynamic_cast_tag {};
+struct polymorphic_cast_tag {};
+
+template<class T> struct shared_ptr_traits
+{
+ typedef T & reference;
+};
+
+template<> struct shared_ptr_traits<void>
+{
+ typedef void reference;
+};
+
+template<> struct shared_ptr_traits<void const>
+{
+ typedef void reference;
+};
+
+template<> struct shared_ptr_traits<void volatile>
+{
+ typedef void reference;
+};
+
+template<> struct shared_ptr_traits<void const volatile>
+{
+ typedef void reference;
+};
+
+// enable_shared_from_this support
+
+template<class T, class Y> void sp_enable_shared_from_this(myboost::enable_shared_from_this<T> * pe, Y * px, shared_count const & pn)
+{
+ if(pe != 0) pe->_internal_weak_this._internal_assign(px, pn);
+}
+
+inline void sp_enable_shared_from_this(void const *, void const *, shared_count const &)
+{
+}
+
+} // namespace detail
+
+
+//
+// shared_ptr
+//
+// An enhanced relative of scoped_ptr with reference counted copy semantics.
+// The object pointed to is deleted when the last shared_ptr pointing to it
+// is destroyed or reset.
+//
+
+template<class T> class shared_ptr
+{
+private:
+
+ // Borland 5.5.1 specific workaround
+ typedef shared_ptr<T> this_type;
+
+public:
+
+ typedef T element_type;
+ typedef T value_type;
+ typedef T * pointer;
+ typedef typename detail::shared_ptr_traits<T>::reference reference;
+
+ shared_ptr(): px(0), pn() // never throws in 1.30+
+ {
+ }
+
+ template<class Y>
+ explicit shared_ptr(Y * p): px(p), pn(p, checked_deleter<Y>()) // Y must be complete
+ {
+ detail::sp_enable_shared_from_this(p, p, pn);
+ }
+
+ //
+ // Requirements: D's copy constructor must not throw
+ //
+ // shared_ptr will release p by calling d(p)
+ //
+
+ template<class Y, class D> shared_ptr(Y * p, D d): px(p), pn(p, d)
+ {
+ detail::sp_enable_shared_from_this(p, p, pn);
+ }
+
+// generated copy constructor, assignment, destructor are fine...
+// except that Borland C++ has a bug, and g++ with -Wsynth warns
+ shared_ptr & operator=(shared_ptr const & r) // never throws
+ {
+ px = r.px;
+ pn = r.pn; // shared_count::op= doesn't throw
+ return *this;
+ }
+
+ template<class Y>
+ explicit shared_ptr(weak_ptr<Y> const & r): pn(r.pn) // may throw
+ {
+ // it is now safe to copy r.px, as pn(r.pn) did not throw
+ px = r.px;
+ }
+
+ template<class Y>
+ shared_ptr(shared_ptr<Y> const & r): px(r.px), pn(r.pn) // never throws
+ {
+ }
+
+ template<class Y>
+ shared_ptr(shared_ptr<Y> const & r, detail::static_cast_tag): px(static_cast<element_type *>(r.px)), pn(r.pn)
+ {
+ }
+
+ template<class Y>
+ shared_ptr(shared_ptr<Y> const & r, detail::const_cast_tag): px(const_cast<element_type *>(r.px)), pn(r.pn)
+ {
+ }
+
+ template<class Y>
+ shared_ptr(shared_ptr<Y> const & r, detail::dynamic_cast_tag): px(dynamic_cast<element_type *>(r.px)), pn(r.pn)
+ {
+ if(px == 0) // need to allocate new counter -- the cast failed
+ {
+ pn = detail::shared_count();
+ }
+ }
+
+ template<class Y>
+ shared_ptr(shared_ptr<Y> const & r, detail::polymorphic_cast_tag): px(dynamic_cast<element_type *>(r.px)), pn(r.pn)
+ {
+ if(px == 0)
+ {
+ myboost::throw_exception(std::bad_cast());
+ }
+ }
+
+ template<class Y>
+ explicit shared_ptr(std::auto_ptr<Y> & r): px(r.get()), pn()
+ {
+ Y * tmp = r.get();
+ pn = detail::shared_count(r);
+ detail::sp_enable_shared_from_this(tmp, tmp, pn);
+ }
+
+ template<class Y>
+ shared_ptr & operator=(shared_ptr<Y> const & r) // never throws
+ {
+ px = r.px;
+ pn = r.pn; // shared_count::op= doesn't throw
+ return *this;
+ }
+
+ template<class Y>
+ shared_ptr & operator=(std::auto_ptr<Y> & r)
+ {
+ this_type(r).swap(*this);
+ return *this;
+ }
+
+ void reset() // never throws in 1.30+
+ {
+ this_type().swap(*this);
+ }
+
+ template<class Y> void reset(Y * p) // Y must be complete
+ {
+ BOOST_ASSERT(p == 0 || p != px); // catch self-reset errors
+ this_type(p).swap(*this);
+ }
+
+ template<class Y, class D> void reset(Y * p, D d)
+ {
+ this_type(p, d).swap(*this);
+ }
+
+ reference operator* () const // never throws
+ {
+ BOOST_ASSERT(px != 0);
+ return *px;
+ }
+
+ T * operator-> () const // never throws
+ {
+ BOOST_ASSERT(px != 0);
+ return px;
+ }
+
+ T * get() const // never throws
+ {
+ return px;
+ }
+
+ typedef T * (this_type::*unspecified_bool_type)() const;
+
+ operator unspecified_bool_type() const // never throws
+ {
+ return px == 0? 0: &this_type::get;
+ }
+
+ // operator! is redundant, but some compilers need it
+
+ bool operator! () const // never throws
+ {
+ return px == 0;
+ }
+
+ bool unique() const // never throws
+ {
+ return pn.unique();
+ }
+
+ long use_count() const // never throws
+ {
+ return pn.use_count();
+ }
+
+ void swap(shared_ptr<T> & other) // never throws
+ {
+ std::swap(px, other.px);
+ pn.swap(other.pn);
+ }
+
+ template<class Y> bool _internal_less(shared_ptr<Y> const & rhs) const
+ {
+ return pn < rhs.pn;
+ }
+
+ void * _internal_get_deleter(std::type_info const & ti) const
+ {
+ return pn.get_deleter(ti);
+ }
+
+// Tasteless as this may seem, making all members public allows member templates
+// to work in the absence of member template friends. (Matthew Langston)
+
+# if __GNUC__ >= 2 && __GNUC_MINOR__ >= 97
+private:
+
+ template<class Y> friend class shared_ptr;
+ template<class Y> friend class weak_ptr;
+#endif
+
+ T * px; // contained pointer
+ detail::shared_count pn; // reference counter
+
+}; // shared_ptr
+
+template<class T, class U> inline bool operator==(shared_ptr<T> const & a, shared_ptr<U> const & b)
+{
+ return a.get() == b.get();
+}
+
+template<class T, class U> inline bool operator!=(shared_ptr<T> const & a, shared_ptr<U> const & b)
+{
+ return a.get() != b.get();
+}
+
+#if __GNUC__ == 2 && __GNUC_MINOR__ <= 96
+
+// Resolve the ambiguity between our op!= and the one in rel_ops
+
+template<class T> inline bool operator!=(shared_ptr<T> const & a, shared_ptr<T> const & b)
+{
+ return a.get() != b.get();
+}
+
+#endif
+
+template<class T, class U> inline bool operator<(shared_ptr<T> const & a, shared_ptr<U> const & b)
+{
+ return a._internal_less(b);
+}
+
+template<class T> inline void swap(shared_ptr<T> & a, shared_ptr<T> & b)
+{
+ a.swap(b);
+}
+
+template<class T, class U> shared_ptr<T> static_pointer_cast(shared_ptr<U> const & r)
+{
+ return shared_ptr<T>(r, detail::static_cast_tag());
+}
+
+template<class T, class U> shared_ptr<T> const_pointer_cast(shared_ptr<U> const & r)
+{
+ return shared_ptr<T>(r, detail::const_cast_tag());
+}
+
+template<class T, class U> shared_ptr<T> dynamic_pointer_cast(shared_ptr<U> const & r)
+{
+ return shared_ptr<T>(r, detail::dynamic_cast_tag());
+}
+
+// shared_*_cast names are deprecated. Use *_pointer_cast instead.
+
+template<class T, class U> shared_ptr<T> shared_static_cast(shared_ptr<U> const & r)
+{
+ return shared_ptr<T>(r, detail::static_cast_tag());
+}
+
+template<class T, class U> shared_ptr<T> shared_dynamic_cast(shared_ptr<U> const & r)
+{
+ return shared_ptr<T>(r, detail::dynamic_cast_tag());
+}
+
+template<class T, class U> shared_ptr<T> shared_polymorphic_cast(shared_ptr<U> const & r)
+{
+ return shared_ptr<T>(r, detail::polymorphic_cast_tag());
+}
+
+template<class T, class U> shared_ptr<T> shared_polymorphic_downcast(shared_ptr<U> const & r)
+{
+ BOOST_ASSERT(dynamic_cast<T *>(r.get()) == r.get());
+ return shared_static_cast<T>(r);
+}
+
+// get_pointer() enables boost::mem_fn to recognize shared_ptr
+
+template<class T> inline T * get_pointer(shared_ptr<T> const & p)
+{
+ return p.get();
+}
+
+// operator<<
+
+
+template<class Y> std::ostream & operator<< (std::ostream & os, shared_ptr<Y> const & p)
+{
+ os << p.get();
+ return os;
+}
+
+
+// get_deleter (experimental)
+
+#if (defined(__GNUC__) && (__GNUC__ < 3)) || (defined(__EDG_VERSION__) && (__EDG_VERSION__ <= 238))
+
+// g++ 2.9x doesn't allow static_cast<X const *>(void *)
+// apparently EDG 2.38 also doesn't accept it
+
+template<class D, class T> D * get_deleter(shared_ptr<T> const & p)
+{
+ void const * q = p._internal_get_deleter(typeid(D));
+ return const_cast<D *>(static_cast<D const *>(q));
+}
+
+#else
+
+template<class D, class T> D * get_deleter(shared_ptr<T> const & p)
+{
+ return static_cast<D *>(p._internal_get_deleter(typeid(D)));
+}
+
+#endif
+
+} // namespace boost
+
+
+#endif // #ifndef BOOST_SHARED_PTR_HPP_INCLUDED
diff --git a/ksvg/impl/libs/libtext2path/src/myboost/throw_exception.hpp b/ksvg/impl/libs/libtext2path/src/myboost/throw_exception.hpp
new file mode 100644
index 00000000..dd32ec43
--- /dev/null
+++ b/ksvg/impl/libs/libtext2path/src/myboost/throw_exception.hpp
@@ -0,0 +1,30 @@
+#ifndef BOOST_THROW_EXCEPTION_HPP_INCLUDED
+#define BOOST_THROW_EXCEPTION_HPP_INCLUDED
+
+
+//
+// boost/throw_exception.hpp
+//
+// Copyright (c) 2002 Peter Dimov and Multi Media Ltd.
+//
+// Permission to copy, use, modify, sell and distribute this software
+// is granted provided this copyright notice appears in all copies.
+// This software is provided "as is" without express or implied
+// warranty, and with no claim as to its suitability for any purpose.
+//
+// http://www.boost.org/libs/utility/throw_exception.html
+//
+
+# include <exception>
+
+namespace myboost
+{
+
+template<class E> void throw_exception(E const & e)
+{
+ throw e;
+}
+
+} // namespace myboost
+
+#endif // #ifndef BOOST_THROW_EXCEPTION_HPP_INCLUDED
diff --git a/ksvg/impl/libs/xrgbrender/Makefile.am b/ksvg/impl/libs/xrgbrender/Makefile.am
new file mode 100644
index 00000000..1e9ebcc1
--- /dev/null
+++ b/ksvg/impl/libs/xrgbrender/Makefile.am
@@ -0,0 +1,5 @@
+INCLUDES = $(all_includes)
+
+noinst_LTLIBRARIES = libksvgxrgbrender.la
+
+libksvgxrgbrender_la_SOURCES = gdk-pixbuf-xlib.c gdk-pixbuf-xlib-drawable.c gdk-pixbuf-xlibrgb.c
diff --git a/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib-drawable.c b/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib-drawable.c
new file mode 100644
index 00000000..01f60976
--- /dev/null
+++ b/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib-drawable.c
@@ -0,0 +1,1137 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* GdkPixbuf library - convert X drawable information to RGB
+ *
+ * Copyright (C) 1999 Michael Zucchi
+ *
+ * Authors: Michael Zucchi <zucchi@zedzone.mmc.com.au>
+ * Cody Russell <bratsche@dfw.net>
+ * Federico Mena-Quintero <federico@gimp.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/* Ported to Xlib by John Harper <john@dcs.warwick.ac.uk> */
+
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include "gdk-pixbuf-xlib-private.h"
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#if (X_BYTE_ORDER == X_LITTLE_ENDIAN)
+#define LITTLE
+#endif
+#define d(x)
+
+
+
+static unsigned int mask_table[] = {
+ 0x00000000, 0x00000001, 0x00000003, 0x00000007,
+ 0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
+ 0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
+ 0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
+ 0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
+ 0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
+ 0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
+ 0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
+ 0xffffffff
+};
+
+
+/* color handling */
+
+typedef struct xlib_colormap_struct xlib_colormap;
+struct xlib_colormap_struct {
+ int size;
+ XColor *colors;
+ Visual *visual;
+ Colormap colormap;
+};
+
+
+/* from gdkvisual.c */
+static void
+visual_decompose_mask (unsigned long mask,
+ int *shift,
+ int *prec)
+{
+ *shift = 0;
+ *prec = 0;
+
+ while (!(mask & 0x1)) {
+ (*shift)++;
+ mask >>= 1;
+ }
+
+ while (mask & 0x1) {
+ (*prec)++;
+ mask >>= 1;
+ }
+}
+
+static int x_error;
+
+static int
+handle_x_error (Display *dpy, XErrorEvent *ev)
+{
+ x_error = 1;
+ return 0;
+}
+
+static int
+drawable_is_pixmap (Drawable d)
+{
+ /* copied from Imlib */
+
+ XErrorHandler errh;
+ XWindowAttributes wa;
+ int is_pixmap;
+
+ errh = XSetErrorHandler (handle_x_error);
+ x_error = 0;
+ XGetWindowAttributes (gdk_pixbuf_dpy, d, &wa);
+ XSync (gdk_pixbuf_dpy, False);
+ is_pixmap = x_error;
+ XSetErrorHandler (errh);
+
+ return is_pixmap;
+}
+
+
+
+/*
+ convert 1 bits-pixel data
+ no alpha
+*/
+static void
+rgb1 (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap)
+{
+ int xx, yy;
+ int width, height;
+ int bpl;
+ unsigned char *s;
+ register unsigned char data;
+ unsigned char *o;
+ unsigned char *srow = image->data, *orow = pixels;
+
+ d (printf ("1 bits/pixel\n"));
+
+ /* convert upto 8 pixels/time */
+ /* its probably not worth trying to make this run very fast, who uses
+ 1 bit displays anymore? */
+ width = image->width;
+ height = image->height;
+ bpl = image->bytes_per_line;
+
+ for (yy = 0; yy < height; yy++) {
+ s = srow;
+ o = orow;
+
+ for (xx = 0; xx < width; xx ++) {
+ data = srow[xx >> 3] >> (7 - (xx & 7)) & 1;
+ *o++ = colormap->colors[data].red;
+ *o++ = colormap->colors[data].green;
+ *o++ = colormap->colors[data].blue;
+ }
+ srow += bpl;
+ orow += rowstride;
+ }
+}
+
+/*
+ convert 1 bits/pixel data
+ with alpha
+*/
+static void
+rgb1a (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap)
+{
+ int xx, yy;
+ int width, height;
+ int bpl;
+ unsigned char *s;
+ register unsigned char data;
+ unsigned char *o;
+ unsigned char *srow = image->data, *orow = pixels;
+ unsigned int remap[2];
+
+ d (printf ("1 bits/pixel\n"));
+
+ /* convert upto 8 pixels/time */
+ /* its probably not worth trying to make this run very fast, who uses
+ 1 bit displays anymore? */
+ width = image->width;
+ height = image->height;
+ bpl = image->bytes_per_line;
+
+ for (xx = 0; xx < 2; xx++) {
+#ifdef LITTLE
+ remap[xx] = 0xff000000
+ | colormap->colors[xx].blue << 16
+ | colormap->colors[xx].green << 8
+ | colormap->colors[xx].red;
+#else
+ remap[xx] = 0xff
+ | colormap->colors[xx].red << 24
+ | colormap->colors[xx].green << 16
+ | colormap->colors[xx].blue << 8;
+#endif
+ }
+
+ for (yy = 0; yy < height; yy++) {
+ s = srow;
+ o = orow;
+
+ for (xx = 0; xx < width; xx ++) {
+ data = srow[xx >> 3] >> (7 - (xx & 7)) & 1;
+ *o++ = remap[data];
+ }
+ srow += bpl;
+ orow += rowstride;
+ }
+}
+
+/*
+ convert 8 bits/pixel data
+ no alpha
+*/
+static void
+rgb8 (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap)
+{
+ int xx, yy;
+ int width, height;
+ int bpl;
+ unsigned int mask;
+ register unsigned int data;
+ unsigned char *srow = image->data, *orow = pixels;
+ register unsigned char *s;
+ register unsigned char *o;
+
+ width = image->width;
+ height = image->height;
+ bpl = image->bytes_per_line;
+
+ d (printf ("8 bit, no alpha output\n"));
+
+ mask = mask_table[image->depth];
+
+ for (yy = 0; yy < height; yy++) {
+ s = srow;
+ o = orow;
+ for (xx = 0; xx < width; xx++) {
+ data = *s++ & mask;
+ *o++ = colormap->colors[data].red;
+ *o++ = colormap->colors[data].green;
+ *o++ = colormap->colors[data].blue;
+ }
+ srow += bpl;
+ orow += rowstride;
+ }
+}
+
+/*
+ convert 8 bits/pixel data
+ with alpha
+*/
+static void
+rgb8a (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap)
+{
+ int xx, yy;
+ int width, height;
+ int bpl;
+ unsigned int mask;
+ register unsigned int data;
+ unsigned int remap[256];
+ register unsigned char *s; /* read 2 pixels at once */
+ register unsigned int *o;
+ unsigned char *srow = image->data, *orow = pixels;
+
+ width = image->width;
+ height = image->height;
+ bpl = image->bytes_per_line;
+
+ d (printf ("8 bit, with alpha output\n"));
+
+ mask = mask_table[image->depth];
+
+ for (xx = 0; xx < colormap->size; xx++) {
+#ifdef LITTLE
+ remap[xx] = 0xff000000
+ | colormap->colors[xx].blue << 16
+ | colormap->colors[xx].green << 8
+ | colormap->colors[xx].red;
+#else
+ remap[xx] = 0xff
+ | colormap->colors[xx].red << 24
+ | colormap->colors[xx].green << 16
+ | colormap->colors[xx].blue << 8;
+#endif
+ }
+
+ for (yy = 0; yy < height; yy++) {
+ s = srow;
+ o = (unsigned int *) orow;
+ for (xx = 0; xx < width; xx ++) {
+ data = *s++ & mask;
+ *o++ = remap[data];
+ }
+ srow += bpl;
+ orow += rowstride;
+ }
+}
+
+/*
+ convert 16 bits/pixel data
+ no alpha
+ data in lsb format
+*/
+static void
+rgb565lsb (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap)
+{
+ int xx, yy;
+ int width, height;
+ int bpl;
+
+#ifdef LITTLE
+ register unsigned int *s; /* read 2 pixels at once */
+#else
+ register unsigned char *s; /* read 2 pixels at once */
+#endif
+ register unsigned short *o;
+ unsigned char *srow = image->data, *orow = pixels;
+
+ width = image->width;
+ height = image->height;
+ bpl = image->bytes_per_line;
+
+ for (yy = 0; yy < height; yy++) {
+#ifdef LITTLE
+ s = (unsigned int *) srow;
+#else
+ s = srow;
+#endif
+ o = (unsigned short *) orow;
+ for (xx = 1; xx < width; xx += 2) {
+ register unsigned int data;
+#ifdef LITTLE
+ data = *s++;
+ *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13
+ | (data & 0x7e0) << 5 | (data & 0x600) >> 1;
+ *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2
+ | (data & 0xf8000000) >> 16 | (data & 0xe0000000) >> 21;
+ *o++ = (data & 0x7e00000) >> 19 | (data & 0x6000000) >> 25
+ | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10;
+#else
+ /* swap endianness first */
+ data = s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24;
+ s += 4;
+ *o++ = (data & 0xf800) | (data & 0xe000) >> 5
+ | (data & 0x7e0) >> 3 | (data & 0x600) >> 9;
+ *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6
+ | (data & 0xf8000000) >> 24 | (data & 0xe0000000) >> 29;
+ *o++ = (data & 0x7e00000) >> 11 | (data & 0x6000000) >> 17
+ | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18;
+#endif
+ }
+ /* check for last remaining pixel */
+ if (width & 1) {
+ register unsigned short data;
+#ifdef LITTLE
+ data = *((short *) s);
+#else
+ data = *((short *) s);
+ data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
+#endif
+ ((char *) o)[0] = ((data >> 8) & 0xf8) | ((data >> 13) & 0x7);
+ ((char *) o)[1] = ((data >> 3) & 0xfc) | ((data >> 9) & 0x3);
+ ((char *) o)[2] = ((data << 3) & 0xf8) | ((data >> 2) & 0x7);
+ }
+ srow += bpl;
+ orow += rowstride;
+ }
+}
+
+/*
+ convert 16 bits/pixel data
+ no alpha
+ data in msb format
+*/
+static void
+rgb565msb (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap)
+{
+ int xx, yy;
+ int width, height;
+ int bpl;
+
+#ifdef LITTLE
+ register unsigned char *s; /* need to swap data order */
+#else
+ register unsigned int *s; /* read 2 pixels at once */
+#endif
+ register unsigned short *o;
+ unsigned char *srow = image->data, *orow = pixels;
+
+ width = image->width;
+ height = image->height;
+ bpl = image->bytes_per_line;
+
+ for (yy = 0; yy < height; yy++) {
+#ifdef LITTLE
+ s = srow;
+#else
+ s = (unsigned int *) srow;
+#endif
+ o = (unsigned short *) orow;
+ for (xx = 1; xx < width; xx += 2) {
+ register unsigned int data;
+#ifdef LITTLE
+ /* swap endianness first */
+ data = s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24;
+ s += 4;
+ *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13
+ | (data & 0x7e0) << 5 | (data & 0x600) >> 1;
+ *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2
+ | (data & 0xf8000000) >> 16 | (data & 0xe0000000) >> 21;
+ *o++ = (data & 0x7e00000) >> 19 | (data & 0x6000000) >> 25
+ | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10;
+#else
+ data = *s++;
+ *o++ = (data & 0xf800) | (data & 0xe000) >> 5
+ | (data & 0x7e0) >> 3 | (data & 0x600) >> 9;
+ *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6
+ | (data & 0xf8000000) >> 24 | (data & 0xe0000000) >> 29;
+ *o++ = (data & 0x7e00000) >> 11 | (data & 0x6000000) >> 17
+ | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18;
+#endif
+ }
+ /* check for last remaining pixel */
+ if (width & 1) {
+ register unsigned short data;
+#ifdef LITTLE
+ data = *((short *) s);
+ data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
+#else
+ data = *((short *) s);
+#endif
+ ((char *) o)[0] = ((data >> 8) & 0xf8) | ((data >> 13) & 0x7);
+ ((char *) o)[1] = ((data >> 3) & 0xfc) | ((data >> 9) & 0x3);
+ ((char *) o)[2] = ((data << 3) & 0xf8) | ((data >> 2) & 0x7);
+ }
+ srow += bpl;
+ orow += rowstride;
+ }
+}
+
+/*
+ convert 16 bits/pixel data
+ with alpha
+ data in lsb format
+*/
+static void
+rgb565alsb (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap)
+{
+ int xx, yy;
+ int width, height;
+ int bpl;
+
+#ifdef LITTLE
+ register unsigned short *s; /* read 1 pixels at once */
+#else
+ register unsigned char *s;
+#endif
+ register unsigned int *o;
+
+ unsigned char *srow = image->data, *orow = pixels;
+
+ width = image->width;
+ height = image->height;
+ bpl = image->bytes_per_line;
+
+ for (yy = 0; yy < height; yy++) {
+#ifdef LITTLE
+ s = (unsigned short *) srow;
+#else
+ s = (unsigned char *) srow;
+#endif
+ o = (unsigned int *) orow;
+ for (xx = 0; xx < width; xx ++) {
+ register unsigned int data;
+ /* rrrrrggg gggbbbbb -> rrrrrRRR ggggggGG bbbbbBBB aaaaaaaa */
+ /* little endian: aaaaaaaa bbbbbBBB ggggggGG rrrrrRRR */
+#ifdef LITTLE
+ data = *s++;
+ *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13
+ | (data & 0x7e0) << 5 | (data & 0x600) >> 1
+ | (data & 0x1f) << 19 | (data & 0x1c) << 14
+ | 0xff000000;
+#else
+ /* swap endianness first */
+ data = s[0] | s[1] << 8;
+ s += 2;
+ *o++ = (data & 0xf800) << 16 | (data & 0xe000) << 11
+ | (data & 0x7e0) << 13 | (data & 0x600) << 7
+ | (data & 0x1f) << 11 | (data & 0x1c) << 6
+ | 0xff;
+#endif
+ }
+ srow += bpl;
+ orow += rowstride;
+ }
+}
+
+/*
+ convert 16 bits/pixel data
+ with alpha
+ data in msb format
+*/
+static void
+rgb565amsb (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap)
+{
+ int xx, yy;
+ int width, height;
+ int bpl;
+
+#ifdef LITTLE
+ register unsigned char *s;
+#else
+ register unsigned short *s; /* read 1 pixels at once */
+#endif
+ register unsigned int *o;
+
+ unsigned char *srow = image->data, *orow = pixels;
+
+ width = image->width;
+ height = image->height;
+ bpl = image->bytes_per_line;
+
+ for (yy = 0; yy < height; yy++) {
+ s = srow;
+ o = (unsigned int *) orow;
+ for (xx = 0; xx < width; xx ++) {
+ register unsigned int data;
+ /* rrrrrggg gggbbbbb -> rrrrrRRR gggggg00 bbbbbBBB aaaaaaaa */
+ /* little endian: aaaaaaaa bbbbbBBB gggggg00 rrrrrRRR */
+#ifdef LITTLE
+ /* swap endianness first */
+ data = s[0] | s[1] << 8;
+ s += 2;
+ *o++ = (data & 0xf800) >> 8 | (data & 0xe000) >> 13
+ | (data & 0x7e0) << 5 | (data & 0x600) >> 1
+ | (data & 0x1f) << 19 | (data & 0x1c) << 14
+ | 0xff000000;
+#else
+ data = *s++;
+ *o++ = (data & 0xf800) << 16 | (data & 0xe000) << 11
+ | (data & 0x7e0) << 13 | (data & 0x600) << 7
+ | (data & 0x1f) << 11 | (data & 0x1c) << 6
+ | 0xff;
+#endif
+ }
+ srow += bpl;
+ orow += rowstride;
+ }
+}
+
+/*
+ convert 15 bits/pixel data
+ no alpha
+ data in lsb format
+*/
+static void
+rgb555lsb (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap)
+{
+ int xx, yy;
+ int width, height;
+ int bpl;
+
+#ifdef LITTLE
+ register unsigned int *s; /* read 2 pixels at once */
+#else
+ register unsigned char *s; /* read 2 pixels at once */
+#endif
+ register unsigned short *o;
+ unsigned char *srow = image->data, *orow = pixels;
+
+ width = image->width;
+ height = image->height;
+ bpl = image->bytes_per_line;
+
+ for (yy = 0; yy < height; yy++) {
+#ifdef LITTLE
+ s = (unsigned int *) srow;
+#else
+ s = srow;
+#endif
+ o = (unsigned short *) orow;
+ for (xx = 1; xx < width; xx += 2) {
+ register unsigned int data;
+#ifdef LITTLE
+ data = *s++;
+ *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12
+ | (data & 0x3e0) << 6 | (data & 0x380) << 1;
+ *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2
+ | (data & 0x7c000000) >> 15 | (data & 0x70000000) >> 20;
+ *o++ = (data & 0x3e00000) >> 18 | (data & 0x3800000) >> 23
+ | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10;
+#else
+ /* swap endianness first */
+ data = s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24;
+ s += 4;
+ *o++ = (data & 0x7c00) << 1 | (data & 0x7000) >> 4
+ | (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
+ *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6
+ | (data & 0x7c000000) >> 23 | (data & 0x70000000) >> 28;
+ *o++ = (data & 0x3e00000) >> 10 | (data & 0x3800000) >> 15
+ | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18;
+#endif
+ }
+ /* check for last remaining pixel */
+ if (width & 1) {
+ register unsigned short data;
+#ifdef LITTLE
+ data = *((short *) s);
+#else
+ data = *((short *) s);
+ data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
+#endif
+ ((char *) o)[0] = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12;
+ ((char *) o)[1] = (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
+ ((char *) o)[2] = (data & 0x1f) << 3 | (data & 0x1c) >> 2;
+ }
+ srow += bpl;
+ orow += rowstride;
+ }
+}
+
+/*
+ convert 15 bits/pixel data
+ no alpha
+ data in msb format
+*/
+static void
+rgb555msb (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap)
+{
+ int xx, yy;
+ int width, height;
+ int bpl;
+
+#ifdef LITTLE
+ register unsigned char *s; /* read 2 pixels at once */
+#else
+ register unsigned int *s; /* read 2 pixels at once */
+#endif
+ register unsigned short *o;
+ unsigned char *srow = image->data, *orow = pixels;
+
+ width = image->width;
+ height = image->height;
+ bpl = image->bytes_per_line;
+
+ for (yy = 0; yy < height; yy++) {
+ s = srow;
+ o = (unsigned short *) orow;
+ for (xx = 1; xx < width; xx += 2) {
+ register unsigned int data;
+#ifdef LITTLE
+ /* swap endianness first */
+ data = s[0] | s[1] << 8 | s[2] << 16 | s[3] << 24;
+ s += 4;
+ *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12
+ | (data & 0x3e0) << 6 | (data & 0x380) << 1;
+ *o++ = (data & 0x1f) << 3 | (data & 0x1c) >> 2
+ | (data & 0x7c000000) >> 15 | (data & 0x70000000) >> 20;
+ *o++ = (data & 0x3e00000) >> 18 | (data & 0x3800000) >> 23
+ | (data & 0x1f0000) >> 5 | (data & 0x1c0000) >> 10;
+#else
+ data = *s++;
+ *o++ = (data & 0x7c00) << 1 | (data & 0x7000) >> 4
+ | (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
+ *o++ = (data & 0x1f) << 11 | (data & 0x1c) << 6
+ | (data & 0x7c000000) >> 23 | (data & 0x70000000) >> 28;
+ *o++ = (data & 0x3e00000) >> 10 | (data & 0x3800000) >> 15
+ | (data & 0x1f0000) >> 13 | (data & 0x1c0000) >> 18;
+#endif
+ }
+ /* check for last remaining pixel */
+ if (width & 1) {
+ register unsigned short data;
+#ifdef LITTLE
+ data = *((short *) s);
+ data = ((data >> 8) & 0xff) | ((data & 0xff) << 8);
+#else
+ data = *((short *) s);
+#endif
+ ((char *) o)[0] = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12;
+ ((char *) o)[1] = (data & 0x3e0) >> 2 | (data & 0x380) >> 7;
+ ((char *) o)[2] = (data & 0x1f) << 3 | (data & 0x1c) >> 2;
+ }
+ srow += bpl;
+ orow += rowstride;
+ }
+}
+
+/*
+ convert 15 bits/pixel data
+ with alpha
+ data in lsb format
+*/
+static void
+rgb555alsb (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap)
+{
+ int xx, yy;
+ int width, height;
+ int bpl;
+
+#ifdef LITTLE
+ register unsigned short *s; /* read 1 pixels at once */
+#else
+ register unsigned char *s;
+#endif
+ register unsigned int *o;
+
+ unsigned char *srow = image->data, *orow = pixels;
+
+ width = image->width;
+ height = image->height;
+ bpl = image->bytes_per_line;
+
+ for (yy = 0; yy < height; yy++) {
+#ifdef LITTLE
+ s = (unsigned short *) srow;
+#else
+ s = srow;
+#endif
+ o = (unsigned int *) orow;
+ for (xx = 0; xx < width; xx++) {
+ register unsigned int data;
+ /* rrrrrggg gggbbbbb -> rrrrrRRR gggggGGG bbbbbBBB aaaaaaaa */
+ /* little endian: aaaaaaaa bbbbbBBB gggggGGG rrrrrRRR */
+#ifdef LITTLE
+ data = *s++;
+ *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12
+ | (data & 0x3e0) << 6 | (data & 0x380) << 1
+ | (data & 0x1f) << 19 | (data & 0x1c) << 14
+ | 0xff000000;
+#else
+ /* swap endianness first */
+ data = s[0] | s[1] << 8;
+ s += 2;
+ *o++ = (data & 0x7c00) << 17 | (data & 0x7000) << 12
+ | (data & 0x3e0) << 14 | (data & 0x380) << 9
+ | (data & 0x1f) << 11 | (data & 0x1c) << 6
+ | 0xff;
+#endif
+ }
+ srow += bpl;
+ orow += rowstride;
+ }
+}
+
+/*
+ convert 15 bits/pixel data
+ with alpha
+ data in msb format
+*/
+static void
+rgb555amsb (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap)
+{
+ int xx, yy;
+ int width, height;
+ int bpl;
+
+#ifdef LITTLE
+ register unsigned short *s; /* read 1 pixels at once */
+#else
+ register unsigned char *s;
+#endif
+ register unsigned int *o;
+
+ unsigned char *srow = image->data, *orow = pixels;
+
+ width = image->width;
+ height = image->height;
+ bpl = image->bytes_per_line;
+
+ for (yy = 0; yy < height; yy++) {
+#ifdef LITTLE
+ s = (unsigned short *) srow;
+#else
+ s = srow;
+#endif
+ o = (unsigned int *) orow;
+ for (xx = 0; xx < width; xx++) {
+ register unsigned int data;
+ /* rrrrrggg gggbbbbb -> rrrrrRRR gggggGGG bbbbbBBB aaaaaaaa */
+ /* little endian: aaaaaaaa bbbbbBBB gggggGGG rrrrrRRR */
+#ifdef LITTLE
+ /* swap endianness first */
+ data = s[0] | s[1] << 8;
+ s += 2;
+ *o++ = (data & 0x7c00) >> 7 | (data & 0x7000) >> 12
+ | (data & 0x3e0) << 6 | (data & 0x380) << 1
+ | (data & 0x1f) << 19 | (data & 0x1c) << 14
+ | 0xff000000;
+#else
+ data = *s++;
+ *o++ = (data & 0x7c00) << 17 | (data & 0x7000) << 12
+ | (data & 0x3e0) << 14 | (data & 0x380) << 9
+ | (data & 0x1f) << 11 | (data & 0x1c) << 6
+ | 0xff;
+#endif
+ }
+ srow += bpl;
+ orow += rowstride;
+ }
+}
+
+
+static void
+rgb888alsb (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap)
+{
+ int xx, yy;
+ int width, height;
+ int bpl;
+
+ unsigned char *s; /* for byte order swapping */
+ unsigned char *o;
+ unsigned char *srow = image->data, *orow = pixels;
+
+ width = image->width;
+ height = image->height;
+ bpl = image->bytes_per_line;
+
+ d (printf ("32 bits/pixel with alpha\n"));
+
+ /* lsb data */
+ for (yy = 0; yy < height; yy++) {
+ s = srow;
+ o = orow;
+ for (xx = 0; xx < width; xx++) {
+ *o++ = s[2];
+ *o++ = s[1];
+ *o++ = s[0];
+ *o++ = 0xff;
+ s += 4;
+ }
+ srow += bpl;
+ orow += rowstride;
+ }
+}
+
+static void
+rgb888lsb (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap)
+{
+ int xx, yy;
+ int width, height;
+ int bpl;
+
+ unsigned char *srow = image->data, *orow = pixels;
+ unsigned char *o, *s;
+
+ width = image->width;
+ height = image->height;
+ bpl = image->bytes_per_line;
+
+ d (printf ("32 bit, lsb, no alpha\n"));
+
+ for (yy = 0; yy < height; yy++) {
+ s = srow;
+ o = orow;
+ for (xx = 0; xx < width; xx++) {
+ *o++ = s[2];
+ *o++ = s[1];
+ *o++ = s[0];
+ s += 4;
+ }
+ srow += bpl;
+ orow += rowstride;
+ }
+}
+
+static void
+rgb888amsb (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap)
+{
+ int xx, yy;
+ int width, height;
+ int bpl;
+
+ unsigned char *srow = image->data, *orow = pixels;
+#ifdef LITTLE
+ unsigned int *o;
+ unsigned int *s;
+#else
+ unsigned char *s; /* for byte order swapping */
+ unsigned char *o;
+#endif
+
+ d (printf ("32 bit, msb, with alpha\n"));
+
+ width = image->width;
+ height = image->height;
+ bpl = image->bytes_per_line;
+
+ /* msb data */
+ for (yy = 0; yy < height; yy++) {
+#ifdef LITTLE
+ s = (unsigned int *) srow;
+ o = (unsigned int *) orow;
+#else
+ s = srow;
+ o = orow;
+#endif
+ for (xx = 0; xx < width; xx++) {
+#ifdef LITTLE
+ *o++ = s[1];
+ *o++ = s[2];
+ *o++ = s[3];
+ *o++ = 0xff;
+ s += 4;
+#else
+ *o++ = (*s << 8) | 0xff; /* untested */
+ s++;
+#endif
+ }
+ srow += bpl;
+ orow += rowstride;
+ }
+}
+
+static void
+rgb888msb (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *colormap)
+{
+ int xx, yy;
+ int width, height;
+ int bpl;
+
+ unsigned char *srow = image->data, *orow = pixels;
+ unsigned char *s;
+ unsigned char *o;
+
+ d (printf ("32 bit, msb, no alpha\n"));
+
+ width = image->width;
+ height = image->height;
+ bpl = image->bytes_per_line;
+
+ for (yy = 0; yy < height; yy++) {
+ s = srow;
+ o = orow;
+ for (xx = 0; xx < width; xx++) {
+ *o++ = s[1];
+ *o++ = s[2];
+ *o++ = s[3];
+ s += 4;
+ }
+ srow += bpl;
+ orow += rowstride;
+ }
+}
+
+/*
+ This should work correctly with any display/any endianness, but will probably
+ run quite slow
+*/
+static void
+convert_real_slow (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *cmap, int alpha)
+{
+ int xx, yy;
+ int width, height;
+ int bpl;
+ unsigned char *srow = image->data, *orow = pixels;
+ unsigned char *s;
+ unsigned char *o;
+ unsigned int pixel;
+ Visual *v;
+ unsigned char component;
+ int i;
+ int red_shift, red_prec, green_shift, green_prec, blue_shift, blue_prec;
+
+ width = image->width;
+ height = image->height;
+ bpl = image->bytes_per_line;
+ v = cmap->visual;
+
+ visual_decompose_mask (v->red_mask, &red_shift, &red_prec);
+ visual_decompose_mask (v->green_mask, &green_shift, &green_prec);
+ visual_decompose_mask (v->blue_mask, &blue_shift, &blue_prec);
+
+ d(printf("rgb mask/shift/prec = %x:%x:%x %d:%d:%d %d:%d:%d\n",
+ v->red_mask, v->green_mask, v->blue_mask,
+ red_shift, green_shift, blue_shift,
+ red_prec, green_prec, blue_prec));
+
+ for (yy = 0; yy < height; yy++) {
+ s = srow;
+ o = orow;
+ for (xx = 0; xx < width; xx++) {
+ pixel = XGetPixel (image, xx, yy);
+ switch (v->class) {
+ /* I assume this is right for static & greyscale's too? */
+ case StaticGray:
+ case GrayScale:
+ case StaticColor:
+ case PseudoColor:
+ *o++ = cmap->colors[pixel].red;
+ *o++ = cmap->colors[pixel].green;
+ *o++ = cmap->colors[pixel].blue;
+ break;
+ case TrueColor:
+ /* This is odd because it must sometimes shift left (otherwise
+ I'd just shift >> (*_shift - 8 + *_prec + <0-7>). This logic
+ should work for all bit sizes/shifts/etc. */
+ component = 0;
+ for (i = 24; i < 32; i += red_prec)
+ component |= ((pixel & v->red_mask) << (32 - red_shift - red_prec)) >> i;
+ *o++ = component;
+ component = 0;
+ for (i = 24; i < 32; i += green_prec)
+ component |= ((pixel & v->green_mask) << (32 - green_shift - green_prec)) >> i;
+ *o++ = component;
+ component = 0;
+ for (i = 24; i < 32; i += blue_prec)
+ component |= ((pixel & v->blue_mask) << (32 - blue_shift - blue_prec)) >> i;
+ *o++ = component;
+ break;
+ case DirectColor:
+ *o++ = cmap->colors[((pixel & v->red_mask) << (32 - red_shift - red_prec)) >> 24].red;
+ *o++ = cmap->colors[((pixel & v->green_mask) << (32 - green_shift - green_prec)) >> 24].green;
+ *o++ = cmap->colors[((pixel & v->blue_mask) << (32 - blue_shift - blue_prec)) >> 24].blue;
+ break;
+ }
+ if (alpha)
+ *o++ = 0xff;
+ }
+ srow += bpl;
+ orow += rowstride;
+ }
+}
+
+typedef void (* cfunc) (XImage *image, unsigned char *pixels, int rowstride, xlib_colormap *cmap);
+
+static cfunc convert_map[] = {
+ rgb1,rgb1,rgb1a,rgb1a,
+ rgb8,rgb8,rgb8a,rgb8a,
+ rgb555lsb,rgb555msb,rgb555alsb,rgb555amsb,
+ rgb565lsb,rgb565msb,rgb565alsb,rgb565amsb,
+ rgb888lsb,rgb888msb,rgb888alsb,rgb888amsb
+};
+
+/*
+ perform actual conversion
+
+ If we can, try and use the optimised code versions, but as a default
+ fallback, and always for direct colour, use the generic/slow but complete
+ conversion function.
+*/
+static void
+rgbconvert (XImage *image, unsigned char *pixels, int rowstride, int alpha, xlib_colormap *cmap)
+{
+ int index = (image->byte_order == MSBFirst) | (alpha != 0) << 1;
+ int bank=5; /* default fallback converter */
+ Visual *v = cmap->visual;
+
+ d(printf("masks = %x:%x:%x\n", v->red_mask, v->green_mask, v->blue_mask));
+ d(printf("image depth = %d, bpp = %d\n", image->depth, image->bits_per_pixel));
+
+ switch (v->class) {
+ /* I assume this is right for static & greyscale's too? */
+ case StaticGray:
+ case GrayScale:
+ case StaticColor:
+ case PseudoColor:
+ switch (image->bits_per_pixel) {
+ case 1:
+ bank = 0;
+ break;
+ case 8:
+ bank = 1;
+ break;
+ }
+ break;
+ case TrueColor:
+ switch (image->depth) {
+ case 15:
+ if (v->red_mask == 0x7c00 && v->green_mask == 0x3e0 && v->blue_mask == 0x1f
+ && image->bits_per_pixel == 16)
+ bank = 2;
+ break;
+ case 16:
+ if (v->red_mask == 0xf800 && v->green_mask == 0x7e0 && v->blue_mask == 0x1f
+ && image->bits_per_pixel == 16)
+ bank = 3;
+ break;
+ case 24:
+ case 32:
+ if (v->red_mask == 0xff0000 && v->green_mask == 0xff00 && v->blue_mask == 0xff
+ && image->bits_per_pixel == 32)
+ bank = 4;
+ break;
+ }
+ break;
+ case DirectColor:
+ /* always use the slow version */
+ break;
+ }
+
+ d(printf("converting using conversion function in bank %d\n", bank));
+
+ if (bank==5) {
+ convert_real_slow(image, pixels, rowstride, cmap, alpha);
+ } else {
+ index |= bank << 2;
+ (* convert_map[index]) (image, pixels, rowstride, cmap);
+ }
+}
+
+static int
+xlib_window_is_viewable (Window w)
+{
+ XWindowAttributes wa;
+
+ while (w != 0) {
+ Window parent, root, *children;
+ int nchildren;
+
+ XGetWindowAttributes (gdk_pixbuf_dpy, w, &wa);
+ if (wa.map_state != IsViewable)
+ return 0;
+
+ if (!XQueryTree (gdk_pixbuf_dpy, w, &root,
+ &parent, &children, &nchildren))
+ return 0;
+
+ if (nchildren > 0)
+ XFree (children);
+
+ if (parent == root)
+ return 1;
+
+ w = parent;
+ }
+
+ return 0;
+}
+
+static int
+xlib_window_get_origin (Window w, int *x, int *y)
+{
+ Window child;
+ return XTranslateCoordinates (gdk_pixbuf_dpy, w,
+ RootWindow (gdk_pixbuf_dpy,
+ gdk_pixbuf_screen),
+ 0, 0, x, y, &child);
+}
diff --git a/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib-private.h b/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib-private.h
new file mode 100644
index 00000000..f1113339
--- /dev/null
+++ b/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib-private.h
@@ -0,0 +1,30 @@
+/* GdkPixbuf library - Xlib header file
+ *
+ * Authors: John Harper <john@dcs.warwick.ac.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef GDK_PIXBUF_XLIB_PRIVATE_H
+#define GDK_PIXBUF_XLIB_PRIVATE_H
+
+#include "gdk-pixbuf-xlib.h"
+#include <X11/Xlib.h>
+
+extern Display *gdk_pixbuf_dpy;
+extern int gdk_pixbuf_screen;
+
+#endif
diff --git a/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib.c b/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib.c
new file mode 100644
index 00000000..8383246b
--- /dev/null
+++ b/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib.c
@@ -0,0 +1,46 @@
+/* GdkPixbuf library - Initialization functions
+ *
+ * Author: John Harper <john@dcs.warwick.ac.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <config.h>
+#include <X11/Xlib.h>
+/*#include <gdk-pixbuf/gdk-pixbuf-private.h>*/
+#include "gdk-pixbuf-xlib-private.h"
+
+Display *gdk_pixbuf_dpy = NULL;
+int gdk_pixbuf_screen = -1;
+
+/**
+ * gdk_pixbuf_xlib_init_with_depth:
+ * @display: X display to use.
+ * @screen_num: Screen number.
+ * @prefDepth: Preferred depth for XlibRGB.
+ *
+ * Similar to gdk_pixbuf_xlib_init(), but also lets you specify the preferred
+ * depth for XlibRGB if you do not want it to use the default depth it picks.
+ **/
+void
+gdk_pixbuf_xlib_init_with_depth (Display *display,
+ int screen_num, int prefDepth)
+{
+ xlib_rgb_init_with_depth (display, ScreenOfDisplay (display, screen_num),
+ prefDepth);
+ gdk_pixbuf_dpy = display;
+ gdk_pixbuf_screen = screen_num;
+}
diff --git a/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib.h b/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib.h
new file mode 100644
index 00000000..aa94c7c6
--- /dev/null
+++ b/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlib.h
@@ -0,0 +1,78 @@
+/* GdkPixbuf library - Xlib header file
+ *
+ * Authors: John Harper <john@dcs.warwick.ac.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef GDK_PIXBUF_XLIB_H
+#define GDK_PIXBUF_XLIB_H
+
+/* #include <gdk-pixbuf/gdk-pixbuf.h> */
+/* #include <gdk-pixbuf-xlib/gdk-pixbuf-xlibrgb.h> */
+#include <X11/Xlib.h>
+
+
+
+/* init */
+
+void gdk_pixbuf_xlib_init_with_depth (Display *display, int screen_num,
+ int prefDepth);
+
+
+
+/* render */
+/*
+void gdk_pixbuf_xlib_render_threshold_alpha (GdkPixbuf *pixbuf, Pixmap bitmap,
+ int src_x, int src_y,
+ int dest_x, int dest_y,
+ int width, int height,
+ int alpha_threshold);
+
+void gdk_pixbuf_xlib_render_to_drawable (GdkPixbuf *pixbuf,
+ Drawable drawable, GC gc,
+ int src_x, int src_y,
+ int dest_x, int dest_y,
+ int width, int height,
+ XlibRgbDither dither,
+ int x_dither, int y_dither);
+
+
+void gdk_pixbuf_xlib_render_to_drawable_alpha (GdkPixbuf *pixbuf,
+ Drawable drawable,
+ int src_x, int src_y,
+ int dest_x, int dest_y,
+ int width, int height,
+ GdkPixbufAlphaMode alpha_mode,
+ int alpha_threshold,
+ XlibRgbDither dither,
+ int x_dither, int y_dither);
+
+void gdk_pixbuf_xlib_render_pixmap_and_mask (GdkPixbuf *pixbuf,
+ Pixmap *pixmap_return,
+ Pixmap *mask_return,
+ int alpha_threshold);
+
+
+
+GdkPixbuf *gdk_pixbuf_xlib_get_from_drawable (GdkPixbuf *dest,
+ Drawable src,
+ Colormap cmap, Visual *visual,
+ int src_x, int src_y,
+ int dest_x, int dest_y,
+ int width, int height);
+*/
+#endif /* GDK_PIXBUF_XLIB_H */
diff --git a/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlibrgb.c b/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlibrgb.c
new file mode 100644
index 00000000..eb7e4cdf
--- /dev/null
+++ b/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlibrgb.c
@@ -0,0 +1,3425 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "MPL"); you may not use this file except in
+ * compliance with the MPL. You may obtain a copy of the MPL at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the MPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
+ * for the specific language governing rights and limitations under the
+ * MPL.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Library General Public License (the "LGPL"), in
+ * which case the provisions of the LGPL are applicable instead of
+ * those above. If you wish to allow use of your version of this file
+ * only under the terms of the LGPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the LGPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the LGPL.
+ */
+
+/*
+ * This code is derived from GdkRgb.
+ * For more information on GdkRgb, see http://www.levien.com/gdkrgb/
+ * Raph Levien <raph@acm.org>
+ */
+
+/* Ported by Christopher Blizzard to Xlib. With permission from the
+ * original authors and the copyright holders of this file, the
+ * contents of this file are also redistributable under the terms of
+ * the Mozilla Public license. For information about the Mozilla
+ * Public License, please see the license information at
+ * http://www.mozilla.org/MPL/ */
+
+/* This code is copyright the following authors:
+ * Raph Levien <raph@acm.org>
+ * Manish Singh <manish@gtk.org>
+ * Tim Janik <timj@gtk.org>
+ * Peter Mattis <petm@xcf.berkeley.edu>
+ * Spencer Kimball <spencer@xcf.berkeley.edu>
+ * Josh MacDonald <jmacd@xcf.berkeley.edu>
+ * Christopher Blizzard <blizzard@redhat.com>
+ * Owen Taylor <otaylor@redhat.com>
+ * Shawn T. Amundson <amundson@gtk.org>
+*/
+
+#include <math.h>
+
+#if HAVE_CONFIG_H
+# include <config.h>
+# if STDC_HEADERS
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+# endif
+#else
+# include <stdio.h>
+# include <stdlib.h>
+#endif
+
+#define ENABLE_GRAYSCALE
+
+/* include this before so that we can get endian definitions if
+ they are there... */
+
+#include "gdk-pixbuf-xlibrgb.h"
+#include "gdk-pixbuf-xlib-private.h"
+
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef MAX
+#define MAX(a, b) (((a) > (b)) ? (a) : (b))
+#endif
+
+typedef enum {
+ LSB_FIRST,
+ MSB_FIRST
+} ByteOrder;
+
+
+typedef struct _XlibRgbInfo XlibRgbInfo;
+
+typedef void (*XlibRgbConvFunc) (XImage *image,
+ int ax, int ay,
+ int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align,
+ XlibRgbCmap *cmap);
+
+/* Some of these fields should go, as they're not being used at all.
+ Globals should generally migrate into here - it's very likely that
+ we'll want to run more than one GdkRgbInfo context at the same time
+ (i.e. some but not all windows have privately installed
+ colormaps). */
+
+struct _XlibRgbInfo
+{
+ Display *display;
+ Screen *screen;
+ int screen_num;
+ XVisualInfo *x_visual_info;
+ Colormap cmap;
+ XColor *cmap_colors;
+ Visual *default_visualid;
+ Colormap default_colormap;
+
+ unsigned long *color_pixels;
+ unsigned long *gray_pixels;
+ unsigned long *reserved_pixels;
+
+ unsigned long red_shift;
+ unsigned long red_prec;
+ unsigned long blue_shift;
+ unsigned long blue_prec;
+ unsigned long green_shift;
+ unsigned long green_prec;
+
+ unsigned int nred_shades;
+ unsigned int ngreen_shades;
+ unsigned int nblue_shades;
+ unsigned int ngray_shades;
+ unsigned int nreserved;
+
+ unsigned int bpp;
+ unsigned int cmap_alloced;
+ double gamma_val;
+
+ /* Generally, the stage buffer is used to convert 32bit RGB, gray,
+ and indexed images into 24 bit packed RGB. */
+ unsigned char *stage_buf;
+
+ XlibRgbCmap *gray_cmap;
+
+ Bool dith_default;
+
+ Bool bitmap; /* set true if in 1 bit per pixel mode */
+ GC own_gc;
+
+ /* Convert functions */
+ XlibRgbConvFunc conv;
+ XlibRgbConvFunc conv_d;
+
+ XlibRgbConvFunc conv_32;
+ XlibRgbConvFunc conv_32_d;
+
+ XlibRgbConvFunc conv_gray;
+ XlibRgbConvFunc conv_gray_d;
+
+ XlibRgbConvFunc conv_indexed;
+ XlibRgbConvFunc conv_indexed_d;
+};
+
+static Bool xlib_rgb_install_cmap = FALSE;
+static int xlib_rgb_min_colors = 5 * 5 * 5;
+static Bool xlib_rgb_verbose = FALSE;
+
+#define IMAGE_WIDTH 256
+#define STAGE_ROWSTRIDE (IMAGE_WIDTH * 3)
+#define IMAGE_HEIGHT 64
+#define N_IMAGES 6
+
+static XlibRgbInfo *image_info = NULL;
+static XImage *static_image[N_IMAGES];
+static int static_image_idx;
+
+static unsigned char *colorcube;
+static unsigned char *colorcube_d;
+
+static unsigned long
+xlib_get_prec_from_mask(unsigned long val)
+{
+ unsigned long retval = 0;
+ unsigned int cur_bit = 0;
+ /* walk through the number, incrementing the value if
+ the bit in question is set. */
+ while (cur_bit < (sizeof(unsigned long) * 8)) {
+ if ((val >> cur_bit) & 0x1) {
+ retval++;
+ }
+ cur_bit++;
+ }
+ return retval;
+}
+
+static unsigned long
+xlib_get_shift_from_mask(unsigned long val)
+{
+ unsigned long cur_bit = 0;
+ /* walk through the number, looking for the first 1 */
+ while (cur_bit < (sizeof(unsigned long) * 8)) {
+ if ((val >> cur_bit) & 0x1) {
+ return cur_bit;
+ }
+ cur_bit++;
+ }
+ return cur_bit;
+}
+
+
+static int
+xlib_rgb_cmap_fail (const char *msg, Colormap cmap, unsigned long *pixels)
+{
+ unsigned long free_pixels[256];
+ int n_free;
+ int i;
+
+#ifdef VERBOSE
+ printf ("%s", msg);
+#endif
+ n_free = 0;
+ for (i = 0; i < 256; i++)
+ if (pixels[i] < 256)
+ free_pixels[n_free++] = pixels[i];
+
+ if (n_free)
+ XFreeColors(image_info->display,
+ cmap,
+ free_pixels,
+ n_free,
+ 0);
+ return 0;
+}
+
+static void
+xlib_rgb_make_colorcube (unsigned long *pixels, int nr, int ng, int nb)
+{
+ unsigned char rt[16], gt[16], bt[16];
+ int i;
+
+ colorcube = malloc(sizeof(unsigned char) * 4096);
+ memset(colorcube, 0, (sizeof(unsigned char) * 4096));
+ for (i = 0; i < 16; i++)
+ {
+ rt[i] = ng * nb * ((i * 17 * (nr - 1) + 128) >> 8);
+ gt[i] = nb * ((i * 17 * (ng - 1) + 128) >> 8);
+ bt[i] = ((i * 17 * (nb - 1) + 128) >> 8);
+ }
+
+ for (i = 0; i < 4096; i++)
+ {
+ colorcube[i] = pixels[rt[i >> 8] + gt[(i >> 4) & 0x0f] + bt[i & 0x0f]];
+#ifdef VERBOSE
+ printf ("%03x %02x %x %x %x\n", i, colorcube[i], rt[i >> 8], gt[(i >> 4) & 0x0f], bt[i & 0x0f]);
+#endif
+ }
+}
+
+/* this is the colorcube suitable for dithering */
+static void
+xlib_rgb_make_colorcube_d (unsigned long *pixels, int nr, int ng, int nb)
+{
+ int r, g, b;
+ int i;
+
+ colorcube_d = malloc(sizeof(unsigned char) * 512);
+ memset(colorcube_d, 0, (sizeof(unsigned char) * 512));
+ for (i = 0; i < 512; i++)
+ {
+ r = MIN (nr - 1, i >> 6);
+ g = MIN (ng - 1, (i >> 3) & 7);
+ b = MIN (nb - 1, i & 7);
+ colorcube_d[i] = pixels[(r * ng + g) * nb + b];
+ }
+}
+
+/* Try installing a color cube of the specified size.
+ Make the colorcube and return TRUE on success */
+static int
+xlib_rgb_try_colormap (int nr, int ng, int nb)
+{
+ int r, g, b;
+ int ri, gi, bi;
+ int r0, g0, b0;
+ Colormap cmap;
+ XVisualInfo *visual;
+ XColor *colors = NULL;
+ XColor color;
+ unsigned long pixels[256];
+ unsigned long junk[256];
+ int i;
+ int d2;
+ unsigned int colors_needed;
+ int idx;
+ int best[256];
+
+ if (nr * ng * nb < xlib_rgb_min_colors)
+ return FALSE;
+
+ if (image_info->cmap_alloced) {
+ cmap = image_info->cmap;
+ visual = image_info->x_visual_info;
+ }
+ else {
+ cmap = image_info->default_colormap;
+ visual = image_info->x_visual_info;
+ }
+ colors_needed = nr * ng * nb;
+ for (i = 0; i < 256; i++)
+ {
+ best[i] = 192;
+ pixels[i] = 256;
+ }
+
+#ifndef GAMMA
+ if (!xlib_rgb_install_cmap) {
+ /* go out and get the colors for this colormap. */
+ colors = malloc(sizeof(XColor) * visual->colormap_size);
+ for (i=0; i < visual->colormap_size; i++){
+ colors[i].pixel = i;
+ }
+ XQueryColors (image_info->display,
+ cmap,
+ colors, visual->colormap_size);
+ /* find color cube colors that are already present */
+ for (i = 0; i < MIN (256, visual->colormap_size); i++)
+ {
+ r = colors[i].red >> 8;
+ g = colors[i].green >> 8;
+ b = colors[i].blue >> 8;
+ ri = (r * (nr - 1) + 128) >> 8;
+ gi = (g * (ng - 1) + 128) >> 8;
+ bi = (b * (nb - 1) + 128) >> 8;
+ r0 = ri * 255 / (nr - 1);
+ g0 = gi * 255 / (ng - 1);
+ b0 = bi * 255 / (nb - 1);
+ idx = ((ri * nr) + gi) * nb + bi;
+ d2 = (r - r0) * (r - r0) + (g - g0) * (g - g0) + (b - b0) * (b - b0);
+ if (d2 < best[idx]) {
+ if (pixels[idx] < 256)
+ XFreeColors(image_info->display,
+ cmap,
+ pixels + idx,
+ 1, 0);
+ else
+ colors_needed--;
+ color.pixel = colors[i].pixel;
+ color.red = colors[i].red;
+ color.green = colors[i].green;
+ color.blue = colors[i].blue;
+ color.flags = 0;
+ if (!XAllocColor(image_info->display, cmap, &color))
+ return xlib_rgb_cmap_fail ("error allocating system color\n",
+ cmap, pixels);
+ pixels[idx] = color.pixel; /* which is almost certainly i */
+ best[idx] = d2;
+ }
+ }
+ }
+
+#endif
+
+ if (colors_needed)
+ {
+ if (!XAllocColorCells(image_info->display, cmap, 0, NULL, 0, junk, colors_needed))
+ {
+ char tmp_str[80];
+
+ sprintf (tmp_str,
+ "%d %d %d colormap failed (in XAllocColorCells)\n",
+ nr, ng, nb);
+ return xlib_rgb_cmap_fail (tmp_str, cmap, pixels);
+ }
+ XFreeColors(image_info->display, cmap, junk, (int)colors_needed, 0);
+ }
+
+ for (r = 0, i = 0; r < nr; r++)
+ for (g = 0; g < ng; g++)
+ for (b = 0; b < nb; b++, i++)
+ {
+ if (pixels[i] == 256)
+ {
+ color.red = r * 65535 / (nr - 1);
+ color.green = g * 65535 / (ng - 1);
+ color.blue = b * 65535 / (nb - 1);
+
+#ifdef GAMMA
+ color.red = 65535 * pow (color.red / 65535.0, 0.5);
+ color.green = 65535 * pow (color.green / 65535.0, 0.5);
+ color.blue = 65535 * pow (color.blue / 65535.0, 0.5);
+#endif
+
+ /* This should be a raw XAllocColor call */
+ if (!XAllocColor(image_info->display, cmap, &color))
+ {
+ char tmp_str[80];
+
+ sprintf (tmp_str, "%d %d %d colormap failed\n",
+ nr, ng, nb);
+ return xlib_rgb_cmap_fail (tmp_str,
+ cmap, pixels);
+ }
+ pixels[i] = color.pixel;
+ }
+#ifdef VERBOSE
+ printf ("%d: %lx\n", i, pixels[i]);
+#endif
+ }
+
+ image_info->nred_shades = nr;
+ image_info->ngreen_shades = ng;
+ image_info->nblue_shades = nb;
+ xlib_rgb_make_colorcube (pixels, nr, ng, nb);
+ xlib_rgb_make_colorcube_d (pixels, nr, ng, nb);
+ if (colors)
+ free(colors);
+ return TRUE;
+}
+
+/* Return TRUE on success. */
+static Bool
+xlib_rgb_do_colormaps (void)
+{
+ static const int sizes[][3] = {
+ /* { 6, 7, 6 }, */
+ { 6, 6, 6 },
+ { 6, 6, 5 },
+ { 6, 6, 4 },
+ { 5, 5, 5 },
+ { 5, 5, 4 },
+ { 4, 4, 4 },
+ { 4, 4, 3 },
+ { 3, 3, 3 },
+ { 2, 2, 2 }
+ };
+ static const int n_sizes = sizeof(sizes) / (3 * sizeof(int));
+ int i;
+
+ for (i = 0; i < n_sizes; i++)
+ if (xlib_rgb_try_colormap (sizes[i][0], sizes[i][1], sizes[i][2]))
+ return TRUE;
+ return FALSE;
+}
+
+/* Make a 2 x 2 x 2 colorcube */
+static void
+xlib_rgb_colorcube_222 (void)
+{
+ int i;
+ XColor color;
+ Colormap cmap;
+
+ if (image_info->cmap_alloced)
+ cmap = image_info->cmap;
+ else
+ cmap = image_info->default_colormap;
+
+ colorcube_d = malloc(sizeof(unsigned char) * 512);
+
+ for (i = 0; i < 8; i++)
+ {
+ color.red = ((i & 4) >> 2) * 65535;
+ color.green = ((i & 2) >> 1) * 65535;
+ color.blue = (i & 1) * 65535;
+ XAllocColor (image_info->display, cmap, &color);
+ colorcube_d[((i & 4) << 4) | ((i & 2) << 2) | (i & 1)] = color.pixel;
+ }
+}
+
+/**
+ * xlib_rgb_set_verbose:
+ * @verbose: %True to be verbose
+ *
+ * Enables/disables debug spew.
+ **/
+void
+xlib_rgb_set_verbose (Bool verbose)
+{
+ xlib_rgb_verbose = verbose;
+}
+
+/**
+ * xlib_rgb_set_install:
+ * @install: %True to install a colormap
+ *
+ * Sets whether we install an RGB colormap.
+ **/
+void
+xlib_rgb_set_install (Bool install)
+{
+ xlib_rgb_install_cmap = install;
+}
+
+/**
+ * xlib_rgb_set_min_colors:
+ * @min_colors: minimum colors to use
+ *
+ * Sets the minimum number of colors in the color cube.
+ **/
+void
+xlib_rgb_set_min_colors (int min_colors)
+{
+ xlib_rgb_min_colors = min_colors;
+}
+
+/* Return a "score" based on the following criteria (in hex):
+
+ x000 is the quality - 1 is 1bpp, 2 is 4bpp,
+ 4 is 8bpp,
+ 7 is 15bpp truecolor, 8 is 16bpp truecolor,
+ 9 is 24bpp truecolor.
+ 0x00 is the speed - 1 is the normal case,
+ 2 means faster than normal
+ 00x0 gets a point for being the system visual
+ 000x gets a point for being pseudocolor
+
+ A caveat: in the 8bpp modes, being the system visual seems to be
+ quite important. Thus, all of the 8bpp modes should be ranked at
+ the same speed.
+*/
+
+static unsigned int
+xlib_rgb_score_visual (XVisualInfo *visual)
+{
+ unsigned int quality, speed, pseudo, sys;
+ static const char* visual_names[] =
+ {
+ "static gray",
+ "grayscale",
+ "static color",
+ "pseudo color",
+ "true color",
+ "direct color",
+ };
+
+
+ quality = 0;
+ speed = 1;
+ sys = 0;
+ if (visual->class == TrueColor ||
+ visual->class == DirectColor)
+ {
+ if (visual->depth == 24)
+ {
+ quality = 9;
+ /* Should test for MSB visual here, and set speed if so. */
+ }
+ else if (visual->depth == 16)
+ quality = 8;
+ else if (visual->depth == 15)
+ quality = 7;
+ else if (visual->depth == 8)
+ quality = 4;
+ }
+ else if (visual->class == PseudoColor ||
+ visual->class == StaticColor)
+ {
+ if (visual->depth == 8)
+ quality = 4;
+ else if (visual->depth == 4)
+ quality = 2;
+ else if (visual->depth == 1)
+ quality = 1;
+ }
+ else if (visual->class == StaticGray
+#ifdef ENABLE_GRAYSCALE
+ || visual->class == GrayScale
+#endif
+ )
+ {
+ if (visual->depth == 8)
+ quality = 4;
+ else if (visual->depth == 4)
+ quality = 2;
+ else if (visual->depth == 1)
+ quality = 1;
+ }
+
+ if (quality == 0)
+ return 0;
+
+ sys = (visual->visualid == image_info->default_visualid->visualid);
+
+ pseudo = (visual->class == PseudoColor || visual->class == TrueColor);
+
+ if (xlib_rgb_verbose)
+ printf ("Visual 0x%x, type = %s, depth = %d, %ld:%ld:%ld%s; score=%x\n",
+ (int)visual->visualid,
+ visual_names[visual->class],
+ visual->depth,
+ visual->red_mask,
+ visual->green_mask,
+ visual->blue_mask,
+ sys ? " (system)" : "",
+ (quality << 12) | (speed << 8) | (sys << 4) | pseudo);
+
+ return (quality << 12) | (speed << 8) | (sys << 4) | pseudo;
+}
+
+static void
+xlib_rgb_choose_visual (void)
+{
+ XVisualInfo *visuals;
+ XVisualInfo *visual;
+ XVisualInfo *best_visual;
+ XVisualInfo *final_visual;
+ XVisualInfo template;
+ int num_visuals;
+ unsigned int score, best_score;
+ int cur_visual = 1;
+ int i;
+
+ template.screen = image_info->screen_num;
+ visuals = XGetVisualInfo(image_info->display, VisualScreenMask,
+ &template, &num_visuals);
+
+ best_visual = visuals;
+ best_score = xlib_rgb_score_visual (best_visual);
+
+ for (i = cur_visual; i < num_visuals; i++)
+ {
+ visual = &visuals[i];
+ score = xlib_rgb_score_visual (visual);
+ if (score > best_score)
+ {
+ best_score = score;
+ best_visual = visual;
+ }
+ }
+ /* make a copy of the visual so that we can free
+ the allocated visual list above. */
+ final_visual = malloc(sizeof(XVisualInfo));
+ memcpy(final_visual, best_visual, sizeof(XVisualInfo));
+ image_info->x_visual_info = final_visual;
+ XFree(visuals);
+ /* set up the shift and the precision for the red, green and blue.
+ this only applies to cool visuals like true color and direct color. */
+ if (image_info->x_visual_info->class == TrueColor ||
+ image_info->x_visual_info->class == DirectColor) {
+ image_info->red_shift = xlib_get_shift_from_mask(image_info->x_visual_info->red_mask);
+ image_info->red_prec = xlib_get_prec_from_mask(image_info->x_visual_info->red_mask);
+ image_info->green_shift = xlib_get_shift_from_mask(image_info->x_visual_info->green_mask);
+ image_info->green_prec = xlib_get_prec_from_mask(image_info->x_visual_info->green_mask);
+ image_info->blue_shift = xlib_get_shift_from_mask(image_info->x_visual_info->blue_mask);
+ image_info->blue_prec = xlib_get_prec_from_mask(image_info->x_visual_info->blue_mask);
+ }
+}
+
+static void
+xlib_rgb_choose_visual_for_xprint (int aDepth)
+{
+ XVisualInfo *visuals;
+ XVisualInfo *visual;
+ XVisualInfo *best_visual;
+ XVisualInfo *final_visual;
+ XVisualInfo template;
+ int num_visuals;
+ int cur_visual = 1;
+ int i;
+
+ XWindowAttributes win_att;
+ Status ret_stat;
+ Visual *root_visual;
+
+ ret_stat = XGetWindowAttributes(image_info->display,
+ RootWindow(image_info->display, image_info->screen_num),
+ &win_att);
+ root_visual = win_att.visual;
+ template.screen = image_info->screen_num;
+ visuals = XGetVisualInfo(image_info->display, VisualScreenMask,
+ &template, &num_visuals);
+
+ best_visual = visuals;
+ if (best_visual->visual != root_visual) {
+ for (i = cur_visual; i < num_visuals; i++) {
+ visual = &visuals[i];
+ if (visual->visual == root_visual) {
+ best_visual = visual;
+ break;
+ }
+ }
+ }
+ /* make a copy of the visual so that we can free
+ the allocated visual list above. */
+ final_visual = malloc(sizeof(XVisualInfo));
+ memcpy(final_visual, best_visual, sizeof(XVisualInfo));
+ image_info->x_visual_info = final_visual;
+ XFree(visuals);
+ /* set up the shift and the precision for the red, green and blue.
+ this only applies to cool visuals like true color and direct color. */
+ if (image_info->x_visual_info->class == TrueColor ||
+ image_info->x_visual_info->class == DirectColor) {
+ image_info->red_shift = xlib_get_shift_from_mask(image_info->x_visual_info->red_mask);
+ image_info->red_prec = xlib_get_prec_from_mask(image_info->x_visual_info->red_mask);
+ image_info->green_shift = xlib_get_shift_from_mask(image_info->x_visual_info->green_mask);
+ image_info->green_prec = xlib_get_prec_from_mask(image_info->x_visual_info->green_mask);
+ image_info->blue_shift = xlib_get_shift_from_mask(image_info->x_visual_info->blue_mask);
+ image_info->blue_prec = xlib_get_prec_from_mask(image_info->x_visual_info->blue_mask);
+ }
+}
+
+static void xlib_rgb_select_conv (XImage *image, ByteOrder byte_order);
+
+static void
+xlib_rgb_set_gray_cmap (Colormap cmap)
+{
+ int i;
+ XColor color;
+ int status;
+ unsigned long pixels[256];
+ int r, g, b, gray;
+
+ for (i = 0; i < 256; i++)
+ {
+ color.pixel = i;
+ color.red = i * 257;
+ color.green = i * 257;
+ color.blue = i * 257;
+ status = XAllocColor(image_info->display, cmap, &color);
+ pixels[i] = color.pixel;
+#ifdef VERBOSE
+ printf ("allocating pixel %d, %x %x %x, result %d\n",
+ color.pixel, color.red, color.green, color.blue, status);
+#endif
+ }
+
+ /* Now, we make fake colorcubes - we ultimately just use the pseudocolor
+ methods. */
+
+ colorcube = malloc(sizeof(unsigned char) * 4096);
+
+ for (i = 0; i < 4096; i++)
+ {
+ r = (i >> 4) & 0xf0;
+ r = r | r >> 4;
+ g = i & 0xf0;
+ g = g | g >> 4;
+ b = (i << 4 & 0xf0);
+ b = b | b >> 4;
+ gray = (g + ((r + b) >> 1)) >> 1;
+ colorcube[i] = pixels[gray];
+ }
+}
+
+/**
+ * xlib_rgb_init_with_depth:
+ * @display: X display to use.
+ * @screen: Screen to use.
+ * @prefDepth: Visual depth to use for color substitution tables. This must
+ * be one of the supported visual depths in the specified @display.
+ *
+ * Initializes the XlibRGB machinery with a particular depth you specify,
+ * instead of automatically picking the best depth in the display. This
+ * function or xlib_rgb_init() must be called before using any of the other
+ * functions in XlibRGB.
+ **/
+void
+xlib_rgb_init_with_depth (Display *display, Screen *screen, int prefDepth)
+{
+ int i;
+ static const int byte_order[1] = { 1 };
+
+ static int initialized = 0;
+
+ if (initialized)
+ {
+ return;
+ }
+
+ initialized = 1;
+
+#if X_BYTE_ORDER == X_BIG_ENDIAN
+ if (((char *)byte_order)[0] == 1) {
+ printf ("xlib_rgb_init: compiled for big endian, but this is a little endian machine.\n\n");
+ exit(1);
+ }
+#else
+ if (((char *)byte_order)[0] != 1) {
+ printf ("xlib_rgb_init: compiled for little endian, but this is a big endian machine.\n\n");
+ exit(1);
+ }
+#endif
+
+ if (image_info == NULL)
+ {
+ image_info = malloc(sizeof(XlibRgbInfo));
+ memset(image_info, 0, sizeof(XlibRgbInfo));
+
+ image_info->display = display;
+ image_info->screen = screen;
+ image_info->screen_num = XScreenNumberOfScreen(screen);
+ image_info->x_visual_info = NULL;
+ image_info->cmap = 0;
+ image_info->default_visualid = DefaultVisual(display, image_info->screen_num);
+ image_info->default_colormap = DefaultColormap(display, image_info->screen_num);
+
+ image_info->color_pixels = NULL;
+ image_info->gray_pixels = NULL;
+ image_info->reserved_pixels = NULL;
+
+ image_info->nred_shades = 6;
+ image_info->ngreen_shades = 6;
+ image_info->nblue_shades = 4;
+ image_info->ngray_shades = 24;
+ image_info->nreserved = 0;
+
+ image_info->bpp = 0;
+ image_info->cmap_alloced = FALSE;
+ image_info->gamma_val = 1.0;
+
+ image_info->stage_buf = NULL;
+
+ image_info->own_gc = 0;
+
+ image_info->red_shift = 0;
+ image_info->red_prec = 0;
+ image_info->green_shift = 0;
+ image_info->green_prec = 0;
+ image_info->blue_shift = 0;
+ image_info->blue_prec = 0;
+
+ if (prefDepth != -1)
+ xlib_rgb_choose_visual_for_xprint (prefDepth);
+ else
+ xlib_rgb_choose_visual ();
+
+ if ((image_info->x_visual_info->class == PseudoColor ||
+ image_info->x_visual_info->class == StaticColor) &&
+ image_info->x_visual_info->depth < 8 &&
+ image_info->x_visual_info->depth >= 3)
+ {
+ image_info->cmap = image_info->default_colormap;
+ xlib_rgb_colorcube_222 ();
+ }
+ else if (image_info->x_visual_info->class == PseudoColor)
+ {
+ if (xlib_rgb_install_cmap ||
+ image_info->x_visual_info->visualid != image_info->default_visualid->visualid)
+ {
+ image_info->cmap = XCreateColormap(image_info->display,
+ RootWindow(image_info->display, image_info->screen_num),
+ image_info->x_visual_info->visual,
+ AllocNone);
+ image_info->cmap_alloced = TRUE;
+ }
+ if (!xlib_rgb_do_colormaps ())
+ {
+ image_info->cmap = XCreateColormap(image_info->display,
+ RootWindow(image_info->display, image_info->screen_num),
+ image_info->x_visual_info->visual,
+ AllocNone);
+ image_info->cmap_alloced = TRUE;
+ xlib_rgb_do_colormaps ();
+ }
+ if (xlib_rgb_verbose)
+ printf ("color cube: %d x %d x %d\n",
+ image_info->nred_shades,
+ image_info->ngreen_shades,
+ image_info->nblue_shades);
+
+ if (!image_info->cmap_alloced)
+ image_info->cmap = image_info->default_colormap;
+ }
+#ifdef ENABLE_GRAYSCALE
+ else if (image_info->x_visual_info->class == GrayScale)
+ {
+ image_info->cmap = XCreateColormap(image_info->display,
+ RootWindow(image_info->display, image_info->screen_num),
+ image_info->x_visual_info->visual,
+ AllocNone);
+ xlib_rgb_set_gray_cmap (image_info->cmap);
+ image_info->cmap_alloced = TRUE;
+ }
+#endif
+ else
+ {
+ /* Always install colormap in direct color. */
+ if (image_info->x_visual_info->class != DirectColor &&
+ image_info->x_visual_info->visualid == image_info->default_visualid->visualid)
+ image_info->cmap = image_info->default_colormap;
+ else
+ {
+ image_info->cmap = XCreateColormap(image_info->display,
+ RootWindow(image_info->display, image_info->screen_num),
+ image_info->x_visual_info->visual,
+ AllocNone);
+ image_info->cmap_alloced = TRUE;
+ }
+ }
+
+ image_info->bitmap = (image_info->x_visual_info->depth == 1);
+
+ for (i = 0; i < N_IMAGES; i++) {
+ if (image_info->bitmap) {
+ /* Use malloc() instead of g_malloc since X will free() this mem */
+ static_image[i] = XCreateImage(image_info->display,
+ image_info->x_visual_info->visual,
+ 1,
+ XYBitmap,
+ 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT,
+ 8,
+ 0);
+ static_image[i]->data = malloc(IMAGE_WIDTH * IMAGE_HEIGHT >> 3);
+ static_image[i]->bitmap_bit_order = MSBFirst;
+ static_image[i]->byte_order = MSBFirst;
+ }
+ else {
+ static_image[i] = XCreateImage(image_info->display,
+ image_info->x_visual_info->visual,
+ (unsigned int)image_info->x_visual_info->depth,
+ ZPixmap,
+ 0, 0,
+ IMAGE_WIDTH,
+ IMAGE_HEIGHT,
+ 32, 0);
+ /* remove this when we are using shared memory.. */
+ static_image[i]->data = malloc((size_t)IMAGE_WIDTH * IMAGE_HEIGHT * image_info->x_visual_info->depth);
+ static_image[i]->bitmap_bit_order = MSBFirst;
+ static_image[i]->byte_order = MSBFirst;
+ }
+ }
+ /* ok, so apparently, image_info->bpp is actually
+ BYTES per pixel. What fun! */
+ switch (static_image[0]->bits_per_pixel) {
+ case 1:
+ case 8:
+ image_info->bpp = 1;
+ break;
+ case 16:
+ image_info->bpp = 2;
+ break;
+ case 24:
+ image_info->bpp = 3;
+ break;
+ case 32:
+ image_info->bpp = 4;
+ break;
+ }
+ xlib_rgb_select_conv (static_image[0], MSB_FIRST);
+ }
+}
+
+
+
+#if X_BYTE_ORDER == X_LITTLE_ENDIAN
+#define HAIRY_CONVERT_8
+#endif
+
+#ifdef HAIRY_CONVERT_8
+static void
+xlib_rgb_convert_8 (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ int x, y;
+ int bpl;
+ unsigned char *obuf, *obptr;
+ unsigned char *bptr, *bp2;
+ int r, g, b;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax;
+ for (y = 0; y < height; y++)
+ {
+ bp2 = bptr;
+ obptr = obuf;
+ if (((unsigned long)obuf | (unsigned long) bp2) & 3)
+ {
+ for (x = 0; x < width; x++)
+ {
+ r = *bp2++;
+ g = *bp2++;
+ b = *bp2++;
+ obptr[0] = colorcube[((r & 0xf0) << 4) |
+ (g & 0xf0) |
+ (b >> 4)];
+ obptr++;
+ }
+ }
+ else
+ {
+ for (x = 0; x < width - 3; x += 4)
+ {
+ unsigned int r1b0g0r0;
+ unsigned int g2r2b1g1;
+ unsigned int b3g3r3b2;
+
+ r1b0g0r0 = ((unsigned int *)bp2)[0];
+ g2r2b1g1 = ((unsigned int *)bp2)[1];
+ b3g3r3b2 = ((unsigned int *)bp2)[2];
+ ((unsigned int *)obptr)[0] =
+ colorcube[((r1b0g0r0 & 0xf0) << 4) |
+ ((r1b0g0r0 & 0xf000) >> 8) |
+ ((r1b0g0r0 & 0xf00000) >> 20)] |
+ (colorcube[((r1b0g0r0 & 0xf0000000) >> 20) |
+ (g2r2b1g1 & 0xf0) |
+ ((g2r2b1g1 & 0xf000) >> 12)] << 8) |
+ (colorcube[((g2r2b1g1 & 0xf00000) >> 12) |
+ ((g2r2b1g1 & 0xf0000000) >> 24) |
+ ((b3g3r3b2 & 0xf0) >> 4)] << 16) |
+ (colorcube[((b3g3r3b2 & 0xf000) >> 4) |
+ ((b3g3r3b2 & 0xf00000) >> 16) |
+ (b3g3r3b2 >> 28)] << 24);
+ bp2 += 12;
+ obptr += 4;
+ }
+ for (; x < width; x++)
+ {
+ r = *bp2++;
+ g = *bp2++;
+ b = *bp2++;
+ obptr[0] = colorcube[((r & 0xf0) << 4) |
+ (g & 0xf0) |
+ (b >> 4)];
+ obptr++;
+ }
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+#else
+static void
+xlib_rgb_convert_8 (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ int x, y;
+ int bpl;
+ unsigned char *obuf, *obptr;
+ unsigned char *bptr, *bp2;
+ int r, g, b;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax;
+ for (y = 0; y < height; y++)
+ {
+ bp2 = bptr;
+ obptr = obuf;
+ for (x = 0; x < width; x++)
+ {
+ r = *bp2++;
+ g = *bp2++;
+ b = *bp2++;
+ obptr[0] = colorcube[((r & 0xf0) << 4) |
+ (g & 0xf0) |
+ (b >> 4)];
+ obptr++;
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+#endif
+
+#if 1
+
+/* This dither table was generated by Raph Levien using patented
+ technology (US Patent 5,276,535). The dither table itself is in the
+ public domain. */
+
+#define DM_WIDTH 128
+#define DM_WIDTH_SHIFT 7
+#define DM_HEIGHT 128
+static const unsigned char DM[128][128] =
+{
+ { 0, 41, 23, 5, 17, 39, 7, 15, 62, 23, 40, 51, 31, 47, 9, 32, 52, 27, 57, 25, 6, 61, 27, 52, 37, 7, 40, 63, 18, 36, 10, 42, 25, 62, 45, 34, 20, 42, 37, 14, 35, 29, 50, 10, 61, 2, 40, 8, 37, 12, 58, 22, 5, 41, 10, 39, 0, 60, 11, 46, 2, 55, 38, 17, 36, 59, 13, 54, 37, 56, 8, 29, 16, 13, 63, 22, 41, 55, 7, 20, 49, 14, 23, 55, 37, 23, 19, 36, 15, 49, 23, 63, 30, 14, 38, 27, 53, 13, 22, 41, 19, 31, 7, 19, 50, 30, 49, 16, 3, 32, 56, 40, 29, 34, 8, 48, 19, 45, 4, 51, 12, 46, 35, 49, 16, 42, 12, 62 },
+ { 30, 57, 36, 54, 47, 34, 52, 27, 43, 4, 28, 7, 17, 36, 62, 13, 44, 7, 18, 48, 33, 21, 44, 14, 30, 47, 12, 33, 5, 55, 31, 58, 13, 30, 4, 17, 52, 10, 60, 26, 46, 0, 39, 27, 42, 22, 47, 25, 60, 32, 9, 38, 48, 17, 59, 30, 49, 18, 34, 25, 51, 19, 5, 48, 21, 8, 28, 46, 1, 32, 41, 19, 54, 47, 37, 18, 28, 11, 44, 30, 39, 56, 2, 33, 8, 42, 61, 28, 58, 8, 46, 9, 41, 4, 58, 7, 21, 48, 59, 10, 52, 14, 42, 57, 12, 25, 7, 53, 42, 24, 11, 50, 17, 59, 42, 2, 36, 60, 32, 17, 63, 29, 21, 7, 59, 32, 24, 39 },
+ { 22, 8, 16, 32, 3, 25, 13, 57, 18, 45, 58, 39, 55, 20, 5, 42, 23, 34, 63, 1, 51, 10, 58, 4, 60, 23, 53, 27, 44, 21, 3, 48, 8, 50, 43, 54, 27, 32, 5, 55, 21, 58, 12, 53, 6, 36, 14, 50, 17, 29, 53, 15, 24, 52, 7, 36, 13, 42, 4, 53, 9, 35, 61, 26, 56, 32, 49, 15, 62, 23, 6, 60, 2, 31, 4, 48, 58, 38, 15, 61, 5, 25, 47, 28, 50, 15, 7, 40, 3, 32, 33, 52, 25, 50, 35, 42, 61, 3, 28, 36, 23, 63, 4, 33, 46, 62, 36, 23, 60, 6, 54, 28, 4, 37, 23, 55, 25, 8, 42, 54, 14, 6, 56, 38, 19, 52, 4, 46 },
+ { 48, 53, 43, 12, 45, 63, 30, 37, 9, 34, 21, 1, 25, 47, 29, 58, 3, 54, 15, 39, 29, 17, 38, 35, 20, 43, 1, 49, 15, 59, 29, 39, 22, 35, 16, 23, 1, 47, 39, 18, 8, 44, 25, 31, 57, 19, 63, 4, 45, 3, 42, 61, 1, 31, 45, 20, 57, 29, 62, 21, 32, 41, 14, 44, 3, 39, 5, 34, 10, 43, 51, 35, 23, 52, 40, 10, 21, 1, 53, 18, 51, 43, 12, 62, 18, 54, 26, 51, 20, 57, 14, 1, 62, 16, 11, 18, 32, 39, 17, 44, 1, 48, 26, 37, 18, 2, 51, 14, 28, 45, 35, 18, 57, 13, 47, 11, 51, 20, 2, 39, 31, 47, 25, 1, 50, 11, 60, 7 },
+ { 18, 28, 1, 56, 21, 10, 51, 2, 46, 54, 14, 61, 11, 50, 13, 38, 19, 31, 45, 9, 55, 24, 47, 5, 54, 9, 62, 11, 35, 8, 51, 14, 57, 6, 63, 40, 58, 14, 51, 28, 62, 34, 15, 48, 1, 41, 30, 35, 55, 21, 34, 11, 49, 37, 8, 52, 4, 23, 15, 43, 1, 58, 11, 23, 53, 16, 55, 26, 58, 18, 27, 12, 45, 14, 25, 63, 42, 33, 27, 35, 9, 31, 21, 38, 1, 44, 34, 12, 48, 38, 21, 44, 29, 47, 26, 53, 1, 46, 54, 8, 59, 29, 11, 55, 22, 41, 33, 20, 39, 1, 48, 9, 44, 32, 5, 62, 29, 44, 57, 23, 10, 58, 34, 43, 15, 37, 26, 33 },
+ { 51, 38, 59, 24, 35, 42, 19, 60, 5, 32, 41, 26, 43, 33, 7, 53, 48, 11, 59, 23, 42, 2, 61, 30, 16, 40, 32, 24, 56, 41, 19, 33, 37, 26, 47, 9, 31, 22, 2, 45, 9, 54, 4, 37, 21, 52, 11, 23, 7, 57, 16, 25, 55, 18, 63, 27, 46, 39, 56, 10, 50, 37, 29, 47, 19, 63, 24, 9, 46, 2, 39, 60, 9, 57, 30, 7, 49, 11, 59, 3, 45, 57, 5, 60, 29, 22, 5, 60, 30, 9, 59, 18, 40, 6, 57, 36, 30, 12, 24, 34, 15, 40, 52, 6, 49, 9, 58, 4, 63, 12, 26, 61, 22, 53, 38, 16, 35, 14, 28, 50, 42, 17, 5, 28, 62, 20, 54, 12 },
+ { 26, 6, 31, 15, 49, 6, 38, 27, 22, 49, 16, 56, 2, 62, 30, 21, 0, 36, 28, 6, 49, 32, 13, 52, 26, 50, 19, 46, 3, 26, 62, 0, 53, 12, 29, 3, 53, 41, 60, 24, 38, 13, 58, 16, 43, 9, 59, 39, 46, 28, 44, 40, 2, 33, 13, 41, 16, 6, 47, 31, 26, 17, 57, 6, 38, 0, 42, 36, 29, 52, 20, 31, 48, 0, 34, 56, 20, 36, 23, 54, 14, 41, 24, 37, 10, 55, 46, 25, 16, 45, 36, 4, 55, 23, 15, 8, 50, 62, 5, 56, 44, 20, 13, 28, 59, 31, 24, 47, 31, 52, 37, 17, 40, 0, 26, 49, 3, 60, 7, 33, 0, 61, 53, 40, 8, 45, 2, 41 },
+ { 16, 63, 43, 4, 61, 24, 56, 13, 53, 8, 36, 12, 24, 41, 16, 46, 60, 26, 52, 39, 14, 57, 21, 37, 0, 45, 7, 59, 38, 17, 43, 10, 45, 20, 61, 43, 19, 11, 33, 17, 50, 32, 23, 61, 28, 49, 26, 0, 18, 51, 5, 60, 22, 58, 29, 0, 59, 34, 19, 62, 3, 52, 7, 44, 30, 59, 13, 50, 15, 62, 7, 17, 38, 22, 44, 15, 40, 4, 47, 28, 33, 17, 49, 16, 51, 40, 10, 56, 0, 53, 13, 49, 28, 38, 60, 21, 43, 19, 37, 27, 3, 51, 34, 39, 0, 45, 15, 43, 10, 21, 3, 55, 8, 33, 59, 10, 41, 18, 52, 24, 46, 20, 30, 13, 58, 22, 36, 57 },
+ { 50, 34, 11, 47, 29, 17, 44, 0, 33, 63, 28, 46, 52, 5, 57, 10, 42, 18, 4, 63, 20, 8, 44, 10, 56, 34, 14, 29, 5, 54, 23, 59, 32, 49, 7, 34, 49, 27, 56, 0, 42, 7, 46, 3, 40, 6, 54, 32, 62, 13, 36, 10, 47, 8, 35, 49, 24, 51, 12, 40, 22, 35, 60, 12, 22, 51, 33, 4, 40, 25, 43, 55, 5, 54, 12, 61, 26, 51, 8, 62, 0, 53, 7, 63, 2, 32, 19, 34, 42, 24, 31, 63, 2, 10, 45, 33, 0, 48, 9, 61, 22, 47, 8, 62, 18, 56, 7, 54, 27, 57, 46, 30, 50, 19, 45, 30, 56, 36, 22, 47, 11, 38, 3, 51, 32, 48, 18, 9 },
+ { 0, 21, 40, 19, 52, 9, 37, 48, 20, 40, 3, 18, 27, 38, 35, 22, 31, 56, 13, 35, 46, 28, 60, 40, 27, 18, 61, 50, 41, 30, 7, 36, 2, 25, 16, 57, 5, 15, 47, 29, 55, 19, 30, 52, 15, 34, 20, 12, 43, 30, 20, 54, 25, 44, 53, 12, 38, 5, 55, 27, 48, 15, 33, 27, 45, 8, 19, 28, 56, 11, 33, 49, 18, 36, 29, 2, 45, 16, 39, 19, 31, 43, 27, 35, 20, 52, 26, 6, 61, 11, 41, 17, 29, 51, 20, 56, 25, 32, 41, 17, 53, 31, 25, 14, 42, 23, 35, 16, 38, 6, 34, 12, 15, 62, 6, 21, 13, 1, 63, 9, 55, 27, 43, 25, 14, 4, 31, 55 },
+ { 44, 29, 61, 2, 35, 58, 26, 15, 60, 10, 51, 59, 14, 55, 8, 50, 2, 44, 25, 51, 1, 33, 16, 4, 48, 36, 2, 21, 12, 57, 48, 13, 51, 55, 40, 28, 37, 62, 8, 39, 12, 63, 36, 10, 59, 24, 56, 47, 9, 50, 41, 1, 32, 17, 6, 21, 61, 30, 9, 43, 1, 54, 41, 2, 54, 37, 48, 61, 1, 46, 21, 3, 58, 24, 50, 32, 60, 10, 57, 25, 46, 12, 59, 4, 45, 13, 57, 47, 27, 39, 5, 58, 47, 14, 35, 4, 52, 13, 60, 6, 36, 10, 45, 55, 4, 50, 29, 2, 61, 50, 25, 58, 44, 24, 36, 42, 54, 28, 40, 32, 16, 56, 6, 62, 46, 39, 60, 23 },
+ { 7, 48, 14, 54, 23, 40, 4, 45, 30, 22, 42, 32, 1, 44, 20, 29, 58, 8, 37, 19, 41, 54, 24, 58, 9, 53, 25, 46, 34, 16, 23, 38, 27, 11, 18, 1, 52, 21, 35, 22, 48, 5, 25, 45, 18, 38, 2, 27, 35, 4, 57, 15, 62, 39, 57, 28, 42, 16, 36, 60, 24, 18, 10, 63, 20, 5, 16, 23, 37, 14, 59, 27, 41, 8, 13, 42, 21, 35, 6, 50, 3, 38, 15, 48, 30, 39, 17, 3, 49, 14, 53, 33, 24, 7, 61, 44, 11, 39, 23, 49, 19, 58, 1, 32, 36, 12, 60, 41, 20, 13, 41, 4, 39, 1, 48, 8, 18, 51, 14, 44, 5, 37, 21, 34, 1, 26, 10, 37 },
+ { 53, 36, 27, 9, 50, 12, 32, 55, 2, 57, 7, 17, 48, 34, 63, 15, 40, 26, 62, 11, 49, 6, 31, 39, 22, 42, 6, 63, 1, 39, 60, 4, 42, 61, 32, 45, 24, 44, 2, 60, 16, 41, 53, 1, 33, 61, 49, 17, 63, 23, 45, 26, 33, 3, 23, 46, 2, 50, 20, 4, 45, 34, 49, 30, 39, 58, 44, 31, 53, 34, 6, 52, 30, 47, 63, 1, 53, 22, 42, 31, 58, 23, 54, 22, 61, 8, 36, 59, 22, 35, 21, 1, 55, 40, 27, 16, 30, 54, 2, 29, 43, 16, 39, 63, 21, 46, 26, 10, 48, 32, 19, 53, 30, 56, 26, 60, 33, 4, 61, 23, 49, 59, 15, 53, 19, 58, 42, 16 },
+ { 20, 5, 59, 46, 25, 62, 7, 19, 43, 25, 37, 61, 11, 24, 4, 54, 12, 52, 3, 32, 17, 61, 12, 47, 15, 55, 18, 31, 53, 28, 9, 50, 21, 6, 55, 9, 58, 14, 54, 26, 33, 7, 31, 58, 13, 21, 8, 42, 29, 6, 37, 11, 48, 52, 14, 60, 11, 39, 56, 32, 14, 58, 7, 26, 17, 4, 42, 8, 11, 47, 19, 38, 10, 17, 26, 37, 9, 55, 28, 13, 18, 40, 6, 33, 1, 43, 25, 11, 51, 7, 62, 43, 18, 37, 3, 57, 45, 9, 38, 58, 5, 52, 27, 7, 17, 53, 5, 57, 37, 2, 63, 9, 22, 15, 11, 38, 25, 45, 35, 0, 28, 10, 41, 30, 50, 8, 31, 57 },
+ { 49, 33, 16, 38, 1, 42, 51, 34, 53, 14, 28, 49, 30, 56, 36, 23, 43, 20, 38, 56, 22, 45, 28, 0, 62, 35, 26, 44, 11, 19, 52, 35, 44, 15, 30, 38, 10, 31, 40, 4, 46, 50, 20, 40, 27, 44, 51, 14, 56, 53, 19, 59, 7, 29, 41, 19, 35, 25, 8, 52, 22, 44, 13, 53, 50, 32, 61, 24, 56, 25, 63, 0, 45, 57, 33, 59, 16, 46, 4, 62, 50, 11, 60, 37, 52, 19, 55, 29, 37, 46, 13, 26, 48, 10, 50, 34, 21, 63, 26, 13, 42, 33, 22, 55, 35, 28, 43, 15, 24, 51, 27, 34, 46, 49, 58, 3, 52, 9, 57, 19, 48, 55, 3, 35, 12, 45, 24, 3 },
+ { 41, 11, 56, 28, 18, 31, 22, 10, 37, 6, 47, 13, 3, 41, 9, 46, 0, 48, 29, 6, 34, 10, 55, 37, 20, 8, 49, 3, 41, 59, 14, 25, 0, 63, 19, 47, 27, 51, 17, 57, 23, 10, 61, 6, 54, 3, 38, 31, 0, 22, 34, 43, 20, 55, 31, 0, 49, 63, 29, 38, 3, 62, 28, 40, 0, 22, 14, 35, 2, 48, 15, 43, 23, 14, 3, 29, 49, 20, 39, 34, 0, 44, 29, 9, 15, 47, 5, 42, 0, 31, 58, 5, 31, 61, 23, 15, 0, 47, 19, 50, 24, 3, 59, 11, 44, 0, 31, 59, 6, 42, 17, 60, 0, 39, 20, 31, 43, 17, 29, 40, 12, 25, 60, 22, 52, 15, 63, 29 },
+ { 20, 52, 8, 44, 62, 4, 59, 49, 17, 63, 21, 39, 60, 18, 52, 27, 33, 59, 14, 51, 59, 43, 24, 5, 51, 30, 57, 17, 32, 5, 37, 56, 48, 34, 42, 3, 60, 5, 36, 13, 43, 37, 18, 34, 25, 12, 59, 24, 47, 36, 11, 50, 3, 38, 9, 58, 16, 5, 43, 18, 47, 10, 37, 18, 59, 46, 29, 52, 40, 12, 34, 28, 56, 36, 53, 7, 43, 8, 24, 52, 26, 17, 56, 43, 24, 32, 63, 20, 57, 16, 22, 52, 36, 8, 41, 56, 29, 32, 54, 7, 35, 57, 14, 48, 20, 62, 13, 39, 53, 29, 8, 45, 13, 29, 7, 61, 14, 54, 6, 63, 38, 32, 18, 43, 2, 39, 6, 47 },
+ { 0, 58, 23, 35, 13, 46, 12, 39, 0, 31, 55, 24, 5, 35, 15, 61, 17, 5, 39, 25, 18, 2, 50, 33, 41, 13, 39, 23, 62, 46, 29, 12, 22, 8, 56, 25, 20, 49, 32, 62, 0, 56, 11, 46, 63, 42, 9, 16, 55, 5, 60, 15, 62, 26, 45, 21, 36, 51, 13, 57, 31, 24, 55, 6, 35, 9, 57, 5, 20, 60, 7, 51, 5, 19, 40, 25, 61, 32, 56, 12, 36, 48, 21, 2, 58, 12, 39, 28, 9, 50, 40, 12, 44, 18, 25, 49, 6, 38, 11, 62, 18, 46, 30, 9, 40, 25, 49, 19, 10, 36, 55, 22, 33, 52, 41, 18, 37, 27, 49, 21, 2, 46, 7, 53, 33, 61, 27, 35 },
+ { 41, 31, 5, 39, 51, 26, 33, 57, 27, 41, 9, 44, 54, 29, 48, 7, 44, 36, 57, 10, 31, 63, 16, 45, 11, 60, 1, 47, 7, 20, 43, 3, 58, 36, 13, 52, 39, 7, 15, 28, 22, 48, 30, 21, 1, 29, 49, 44, 27, 17, 40, 30, 24, 42, 12, 53, 33, 7, 47, 20, 1, 42, 11, 49, 25, 43, 17, 32, 45, 27, 41, 21, 31, 62, 11, 49, 2, 15, 42, 5, 63, 7, 41, 27, 49, 6, 54, 23, 46, 34, 2, 28, 54, 3, 59, 12, 46, 17, 42, 28, 40, 1, 37, 51, 5, 55, 2, 34, 47, 16, 3, 62, 47, 5, 23, 56, 1, 44, 12, 34, 51, 16, 57, 11, 25, 17, 54, 13 },
+ { 60, 26, 55, 18, 3, 60, 20, 6, 52, 15, 50, 19, 32, 11, 23, 53, 26, 21, 1, 47, 42, 27, 8, 58, 21, 27, 53, 36, 26, 54, 31, 50, 17, 30, 45, 1, 29, 59, 44, 53, 41, 4, 35, 58, 51, 19, 32, 4, 52, 34, 48, 8, 51, 5, 56, 2, 25, 61, 27, 38, 54, 27, 62, 21, 51, 1, 39, 62, 10, 50, 1, 58, 13, 47, 38, 18, 35, 54, 22, 51, 30, 19, 59, 34, 14, 32, 44, 4, 60, 15, 52, 62, 20, 43, 30, 35, 21, 60, 4, 52, 12, 24, 61, 18, 30, 42, 23, 61, 25, 50, 27, 38, 11, 59, 12, 35, 50, 30, 59, 24, 8, 42, 28, 37, 48, 9, 44, 21 },
+ { 10, 47, 15, 50, 30, 43, 8, 45, 29, 2, 36, 59, 1, 58, 41, 3, 63, 31, 54, 20, 13, 55, 35, 38, 4, 44, 15, 9, 61, 2, 14, 38, 61, 10, 23, 54, 18, 12, 24, 2, 14, 55, 16, 8, 38, 14, 41, 60, 10, 23, 1, 58, 32, 17, 28, 37, 41, 15, 3, 60, 15, 33, 4, 36, 16, 59, 28, 14, 23, 55, 37, 18, 44, 28, 2, 57, 30, 10, 27, 46, 14, 38, 3, 53, 21, 61, 17, 35, 10, 41, 26, 7, 33, 9, 57, 1, 53, 37, 26, 20, 56, 48, 9, 33, 58, 16, 37, 7, 45, 1, 57, 15, 32, 26, 42, 23, 7, 20, 4, 54, 31, 62, 22, 1, 59, 30, 4, 51 },
+ { 36, 2, 38, 11, 24, 36, 54, 22, 62, 47, 25, 8, 28, 45, 16, 38, 12, 43, 9, 37, 49, 3, 23, 52, 18, 30, 50, 33, 19, 42, 49, 26, 6, 40, 47, 35, 63, 38, 50, 33, 60, 26, 36, 47, 24, 57, 6, 26, 39, 63, 19, 44, 14, 46, 61, 9, 50, 30, 45, 23, 10, 50, 44, 8, 31, 54, 6, 46, 36, 4, 30, 54, 8, 52, 22, 41, 4, 60, 40, 0, 58, 24, 45, 10, 37, 1, 48, 30, 56, 17, 38, 48, 24, 47, 19, 39, 14, 8, 45, 32, 2, 34, 27, 44, 4, 52, 11, 56, 31, 21, 40, 19, 44, 51, 2, 63, 46, 58, 36, 43, 14, 5, 50, 38, 14, 56, 40, 23 },
+ { 61, 46, 32, 63, 54, 1, 14, 34, 12, 40, 18, 49, 37, 10, 61, 30, 51, 24, 60, 7, 29, 40, 62, 11, 46, 58, 6, 56, 24, 10, 34, 52, 21, 59, 16, 3, 27, 5, 20, 46, 9, 40, 7, 62, 2, 30, 53, 15, 48, 10, 28, 35, 54, 6, 21, 34, 18, 55, 7, 40, 57, 19, 26, 60, 41, 13, 24, 51, 19, 61, 9, 25, 34, 15, 63, 11, 45, 17, 20, 47, 33, 8, 31, 62, 43, 26, 53, 7, 24, 59, 0, 13, 55, 4, 62, 27, 51, 31, 63, 15, 58, 7, 54, 14, 46, 22, 28, 43, 12, 63, 8, 54, 5, 17, 39, 33, 15, 10, 27, 17, 47, 34, 19, 45, 27, 12, 33, 17 },
+ { 5, 28, 21, 7, 17, 48, 42, 58, 23, 4, 63, 14, 55, 21, 34, 5, 19, 0, 45, 17, 52, 15, 25, 32, 0, 22, 40, 13, 45, 62, 18, 0, 43, 11, 33, 55, 30, 42, 57, 19, 51, 31, 22, 43, 18, 45, 34, 0, 43, 31, 56, 3, 23, 40, 59, 0, 44, 13, 48, 35, 2, 32, 46, 0, 21, 48, 35, 3, 40, 32, 43, 59, 0, 48, 33, 26, 53, 36, 55, 12, 51, 16, 55, 5, 18, 29, 11, 39, 51, 19, 45, 31, 42, 21, 35, 6, 22, 47, 10, 38, 23, 50, 20, 36, 0, 60, 38, 4, 50, 35, 48, 34, 24, 57, 9, 53, 28, 48, 61, 0, 56, 24, 53, 3, 63, 6, 42, 57 },
+ { 13, 53, 45, 40, 58, 27, 6, 16, 38, 51, 33, 30, 43, 2, 47, 56, 40, 50, 33, 57, 27, 5, 47, 42, 60, 36, 16, 54, 28, 4, 37, 57, 28, 51, 22, 8, 45, 14, 6, 39, 0, 54, 11, 59, 28, 12, 50, 21, 61, 13, 19, 38, 49, 11, 25, 37, 58, 29, 22, 63, 14, 56, 12, 53, 30, 63, 9, 57, 26, 12, 47, 16, 23, 39, 50, 6, 31, 2, 25, 6, 28, 41, 36, 22, 50, 57, 42, 3, 34, 8, 28, 61, 11, 50, 16, 54, 41, 0, 55, 43, 5, 29, 41, 63, 25, 16, 53, 18, 26, 10, 21, 0, 61, 30, 41, 22, 3, 38, 20, 39, 29, 8, 41, 16, 36, 52, 22, 19 },
+ { 55, 34, 0, 25, 10, 32, 56, 44, 28, 0, 57, 7, 26, 53, 23, 8, 13, 35, 22, 12, 36, 60, 20, 8, 14, 29, 48, 2, 41, 49, 23, 13, 39, 7, 48, 58, 25, 53, 34, 62, 28, 16, 48, 4, 37, 56, 27, 5, 36, 52, 46, 7, 62, 33, 52, 11, 17, 53, 5, 28, 41, 24, 38, 17, 5, 39, 20, 45, 15, 56, 5, 38, 60, 8, 14, 57, 21, 48, 62, 39, 59, 13, 1, 60, 9, 32, 16, 63, 44, 25, 52, 15, 36, 2, 60, 29, 12, 33, 25, 17, 59, 45, 13, 8, 49, 32, 6, 40, 59, 29, 45, 37, 13, 47, 6, 55, 30, 45, 9, 52, 13, 59, 25, 47, 32, 1, 49, 30 },
+ { 9, 39, 14, 61, 49, 37, 3, 20, 50, 13, 41, 19, 46, 17, 38, 59, 28, 62, 4, 44, 54, 1, 34, 51, 55, 7, 63, 32, 21, 8, 56, 31, 62, 19, 36, 1, 41, 17, 24, 12, 42, 35, 25, 52, 20, 8, 44, 59, 25, 2, 22, 42, 16, 29, 4, 46, 20, 36, 43, 9, 51, 8, 49, 26, 58, 33, 54, 1, 37, 29, 52, 20, 27, 45, 19, 35, 42, 16, 10, 32, 20, 49, 46, 27, 40, 4, 47, 22, 13, 55, 4, 47, 26, 44, 23, 40, 58, 19, 48, 13, 31, 2, 57, 34, 42, 19, 61, 32, 14, 55, 5, 51, 26, 19, 58, 16, 49, 14, 62, 5, 33, 44, 21, 7, 60, 26, 11, 41 },
+ { 62, 24, 47, 29, 8, 19, 53, 11, 60, 24, 32, 61, 4, 55, 31, 2, 49, 16, 39, 9, 31, 24, 43, 17, 26, 38, 11, 25, 58, 43, 12, 35, 3, 46, 15, 32, 63, 4, 49, 56, 2, 60, 10, 32, 63, 17, 39, 12, 55, 30, 57, 9, 48, 55, 39, 24, 60, 2, 58, 31, 19, 61, 34, 3, 42, 11, 22, 46, 7, 61, 10, 42, 3, 55, 32, 1, 58, 28, 44, 54, 4, 34, 23, 15, 56, 20, 37, 58, 6, 30, 38, 18, 63, 9, 32, 5, 51, 3, 62, 37, 52, 18, 39, 23, 3, 51, 9, 47, 1, 23, 43, 15, 60, 35, 11, 40, 1, 36, 31, 26, 57, 2, 37, 54, 18, 44, 58, 16 },
+ { 5, 51, 3, 33, 43, 62, 21, 42, 35, 9, 48, 15, 36, 10, 22, 42, 20, 46, 26, 56, 50, 12, 59, 3, 48, 19, 45, 53, 1, 27, 47, 17, 52, 24, 56, 11, 51, 21, 37, 30, 20, 46, 14, 41, 1, 47, 33, 7, 41, 17, 35, 27, 20, 1, 14, 54, 26, 33, 18, 47, 1, 44, 14, 59, 16, 52, 28, 18, 49, 31, 25, 34, 63, 13, 51, 24, 9, 50, 3, 23, 38, 63, 7, 52, 29, 46, 11, 33, 50, 22, 57, 36, 1, 57, 49, 17, 39, 28, 9, 35, 6, 27, 53, 15, 55, 30, 24, 58, 36, 41, 11, 52, 32, 3, 44, 25, 62, 23, 51, 15, 42, 22, 50, 10, 39, 4, 31, 35 },
+ { 46, 22, 57, 17, 12, 39, 26, 5, 31, 59, 1, 45, 27, 62, 52, 7, 58, 33, 6, 18, 39, 22, 33, 41, 57, 5, 35, 18, 40, 16, 60, 5, 29, 42, 7, 39, 27, 44, 9, 47, 8, 26, 54, 22, 51, 29, 24, 49, 15, 61, 4, 51, 31, 63, 43, 6, 50, 8, 39, 12, 53, 37, 23, 30, 40, 6, 62, 43, 14, 53, 2, 49, 7, 36, 17, 41, 61, 37, 18, 56, 11, 18, 44, 35, 2, 19, 61, 0, 41, 14, 8, 30, 43, 12, 24, 46, 14, 54, 42, 21, 44, 61, 10, 46, 37, 11, 44, 7, 18, 63, 20, 29, 7, 49, 28, 54, 8, 43, 4, 48, 18, 63, 12, 29, 48, 24, 59, 20 },
+ { 13, 36, 28, 54, 35, 2, 56, 46, 16, 49, 22, 40, 11, 34, 14, 43, 29, 12, 63, 48, 2, 61, 7, 15, 28, 30, 50, 9, 61, 33, 38, 23, 54, 13, 61, 33, 3, 59, 16, 35, 58, 40, 5, 38, 13, 57, 3, 58, 37, 21, 45, 12, 39, 7, 35, 30, 13, 56, 22, 62, 27, 6, 55, 10, 48, 21, 33, 2, 38, 23, 40, 20, 44, 29, 59, 4, 26, 12, 33, 47, 28, 53, 31, 13, 59, 41, 27, 49, 26, 54, 45, 16, 53, 21, 35, 7, 59, 26, 11, 56, 1, 24, 33, 4, 28, 62, 21, 49, 31, 2, 56, 39, 24, 58, 13, 17, 37, 21, 56, 10, 38, 0, 34, 55, 15, 43, 1, 52 },
+ { 42, 9, 50, 6, 25, 60, 14, 38, 10, 29, 53, 18, 57, 3, 25, 51, 0, 53, 25, 17, 29, 37, 52, 46, 0, 62, 14, 37, 4, 50, 10, 44, 0, 46, 20, 25, 50, 19, 55, 0, 23, 31, 62, 34, 11, 45, 19, 32, 0, 53, 10, 59, 23, 47, 18, 60, 42, 28, 37, 3, 50, 15, 35, 44, 0, 51, 27, 60, 9, 57, 16, 58, 11, 22, 46, 15, 53, 48, 7, 42, 0, 60, 5, 49, 24, 54, 9, 17, 39, 5, 34, 62, 3, 40, 60, 31, 0, 47, 29, 16, 49, 39, 59, 17, 50, 0, 40, 13, 53, 38, 16, 46, 0, 42, 34, 60, 2, 53, 29, 31, 58, 46, 27, 6, 61, 8, 37, 28 },
+ { 0, 63, 21, 40, 45, 18, 51, 23, 63, 34, 6, 43, 28, 38, 55, 19, 40, 35, 8, 41, 54, 10, 21, 32, 39, 23, 53, 26, 55, 28, 22, 63, 30, 34, 9, 48, 6, 38, 29, 43, 49, 6, 18, 52, 27, 61, 9, 43, 28, 42, 33, 26, 56, 3, 51, 23, 0, 48, 16, 45, 32, 25, 63, 20, 57, 17, 42, 12, 35, 47, 5, 31, 39, 56, 6, 30, 34, 21, 61, 25, 14, 40, 22, 38, 15, 6, 36, 56, 20, 60, 25, 12, 51, 27, 10, 56, 42, 20, 36, 63, 32, 6, 21, 41, 12, 34, 60, 26, 5, 48, 27, 10, 62, 19, 6, 47, 39, 14, 45, 7, 24, 17, 41, 32, 23, 51, 19, 56 },
+ { 45, 31, 15, 59, 4, 33, 7, 47, 0, 41, 13, 61, 4, 47, 9, 23, 60, 14, 57, 31, 4, 45, 59, 6, 58, 10, 44, 20, 8, 42, 15, 6, 55, 17, 58, 31, 53, 12, 61, 10, 15, 57, 43, 2, 23, 35, 48, 14, 54, 6, 18, 49, 15, 38, 11, 34, 62, 9, 21, 58, 11, 41, 4, 31, 38, 8, 29, 55, 19, 36, 27, 52, 0, 25, 50, 43, 1, 39, 8, 55, 35, 51, 10, 30, 45, 62, 29, 2, 46, 10, 32, 48, 18, 38, 5, 22, 33, 8, 51, 3, 14, 44, 54, 25, 57, 30, 18, 52, 33, 22, 59, 28, 36, 52, 32, 21, 26, 50, 5, 55, 35, 60, 14, 54, 4, 40, 16, 33 },
+ { 27, 3, 49, 10, 30, 40, 55, 27, 57, 24, 52, 21, 32, 17, 60, 30, 5, 44, 27, 49, 19, 34, 13, 24, 43, 36, 3, 49, 31, 59, 37, 48, 26, 41, 2, 41, 14, 36, 21, 32, 40, 26, 13, 49, 55, 5, 16, 40, 25, 60, 36, 1, 63, 29, 17, 44, 25, 40, 52, 5, 29, 47, 54, 13, 46, 24, 60, 4, 51, 22, 63, 14, 45, 18, 12, 62, 17, 57, 19, 42, 3, 26, 58, 48, 1, 21, 40, 52, 23, 37, 44, 1, 29, 58, 43, 50, 15, 61, 19, 45, 58, 28, 7, 48, 2, 46, 8, 42, 3, 55, 8, 50, 12, 4, 55, 10, 63, 33, 20, 40, 11, 3, 46, 20, 48, 26, 61, 11 },
+ { 44, 56, 24, 36, 53, 19, 12, 37, 16, 44, 7, 36, 49, 54, 11, 37, 48, 21, 15, 1, 62, 25, 47, 56, 16, 18, 51, 12, 40, 1, 24, 11, 52, 16, 23, 59, 28, 1, 45, 53, 4, 60, 37, 21, 39, 30, 63, 20, 52, 10, 30, 45, 8, 41, 54, 4, 57, 7, 34, 55, 36, 18, 23, 59, 2, 48, 11, 32, 44, 1, 41, 8, 33, 54, 38, 23, 30, 46, 6, 29, 62, 18, 32, 16, 55, 34, 14, 11, 61, 7, 55, 16, 53, 13, 23, 2, 55, 37, 26, 10, 33, 23, 36, 16, 38, 22, 56, 15, 24, 43, 35, 17, 44, 40, 25, 46, 16, 1, 57, 25, 49, 36, 28, 62, 9, 35, 7, 53 },
+ { 17, 38, 8, 61, 1, 50, 26, 62, 3, 31, 56, 15, 1, 26, 40, 2, 34, 51, 56, 36, 42, 9, 38, 2, 29, 60, 32, 57, 19, 62, 34, 47, 4, 57, 39, 7, 44, 63, 24, 18, 46, 28, 8, 54, 1, 34, 7, 46, 3, 37, 50, 23, 57, 21, 13, 46, 31, 20, 43, 15, 1, 61, 8, 33, 37, 17, 56, 26, 15, 49, 24, 59, 28, 3, 56, 9, 52, 32, 13, 49, 10, 43, 5, 45, 8, 25, 59, 42, 28, 33, 19, 40, 8, 63, 35, 47, 25, 4, 40, 52, 1, 60, 12, 53, 63, 9, 29, 60, 37, 19, 1, 62, 31, 20, 58, 12, 41, 30, 43, 9, 18, 52, 22, 1, 39, 30, 58, 21 },
+ { 13, 47, 29, 18, 43, 34, 5, 48, 20, 42, 10, 45, 30, 58, 20, 63, 24, 11, 6, 28, 54, 14, 22, 52, 41, 7, 26, 5, 45, 15, 53, 13, 35, 27, 18, 50, 12, 33, 5, 56, 10, 17, 45, 24, 59, 15, 50, 26, 56, 13, 19, 5, 32, 52, 27, 36, 2, 61, 12, 26, 49, 40, 27, 52, 13, 50, 6, 39, 61, 34, 10, 37, 48, 20, 41, 27, 2, 36, 59, 24, 54, 33, 63, 20, 38, 50, 3, 17, 52, 4, 58, 27, 45, 21, 32, 11, 48, 17, 57, 20, 46, 38, 25, 43, 4, 34, 51, 6, 13, 45, 57, 26, 6, 48, 2, 35, 53, 23, 61, 34, 59, 6, 42, 56, 13, 51, 2, 41 },
+ { 32, 5, 55, 23, 58, 14, 22, 52, 29, 15, 61, 25, 51, 8, 43, 13, 53, 41, 46, 20, 3, 33, 63, 11, 48, 21, 54, 38, 28, 3, 30, 43, 21, 62, 9, 31, 55, 22, 51, 29, 37, 62, 32, 12, 42, 29, 41, 9, 33, 44, 62, 28, 43, 1, 59, 19, 48, 30, 51, 39, 24, 4, 58, 19, 42, 29, 22, 43, 3, 18, 53, 5, 13, 50, 16, 60, 45, 21, 7, 40, 15, 0, 26, 53, 13, 31, 43, 24, 47, 31, 15, 49, 2, 41, 6, 59, 29, 42, 9, 30, 14, 7, 49, 18, 31, 47, 20, 39, 49, 32, 11, 41, 54, 15, 61, 18, 7, 38, 4, 13, 44, 28, 15, 32, 45, 19, 27, 49 },
+ { 63, 34, 11, 39, 2, 45, 37, 8, 59, 39, 33, 4, 36, 17, 48, 5, 29, 18, 32, 61, 39, 50, 5, 27, 35, 0, 46, 12, 22, 49, 60, 6, 54, 0, 38, 49, 2, 42, 15, 40, 0, 47, 20, 51, 3, 57, 18, 61, 22, 0, 39, 16, 55, 12, 35, 8, 41, 22, 6, 59, 16, 45, 10, 36, 0, 62, 9, 54, 30, 58, 21, 43, 63, 31, 7, 35, 12, 48, 58, 28, 47, 37, 41, 9, 57, 20, 61, 0, 36, 11, 57, 35, 23, 52, 37, 18, 0, 62, 22, 55, 35, 62, 27, 54, 0, 15, 61, 28, 2, 59, 22, 9, 37, 27, 33, 51, 29, 48, 19, 50, 25, 37, 10, 57, 5, 37, 60, 8 },
+ { 20, 25, 46, 52, 31, 60, 12, 55, 0, 19, 11, 46, 62, 35, 23, 38, 57, 0, 55, 10, 16, 30, 58, 44, 17, 59, 29, 63, 42, 8, 36, 20, 33, 46, 16, 61, 25, 35, 8, 54, 26, 7, 58, 22, 34, 6, 47, 14, 53, 31, 48, 9, 37, 25, 49, 63, 16, 55, 45, 14, 34, 63, 21, 53, 25, 33, 46, 16, 35, 7, 46, 29, 0, 39, 25, 55, 22, 34, 18, 4, 56, 11, 23, 51, 28, 6, 39, 14, 62, 44, 19, 8, 60, 12, 56, 28, 50, 34, 39, 5, 51, 3, 41, 12, 57, 35, 10, 53, 25, 17, 52, 30, 47, 0, 43, 14, 5, 57, 31, 55, 0, 63, 47, 23, 54, 24, 14, 43 },
+ { 0, 57, 16, 6, 26, 19, 35, 28, 49, 42, 54, 26, 21, 1, 59, 27, 9, 47, 26, 44, 50, 22, 13, 40, 8, 37, 10, 34, 17, 56, 25, 58, 13, 27, 44, 9, 20, 58, 31, 17, 60, 36, 10, 41, 53, 25, 36, 39, 4, 24, 58, 17, 60, 4, 22, 38, 10, 32, 0, 50, 31, 7, 28, 47, 12, 57, 5, 26, 52, 23, 14, 40, 57, 17, 47, 5, 53, 1, 44, 31, 19, 60, 46, 2, 35, 48, 30, 54, 22, 5, 51, 39, 25, 31, 4, 43, 14, 9, 45, 16, 24, 44, 19, 29, 40, 23, 44, 7, 38, 42, 4, 63, 12, 54, 23, 59, 22, 42, 8, 15, 40, 21, 8, 34, 3, 41, 30, 50 },
+ { 39, 10, 48, 33, 41, 54, 5, 47, 23, 13, 32, 7, 52, 44, 14, 39, 58, 18, 35, 6, 37, 2, 60, 24, 55, 19, 53, 2, 51, 32, 1, 41, 51, 4, 40, 29, 47, 3, 52, 44, 13, 49, 28, 16, 1, 62, 11, 27, 52, 35, 5, 42, 29, 47, 14, 56, 28, 53, 26, 38, 9, 56, 40, 3, 38, 15, 41, 60, 1, 37, 50, 25, 11, 28, 61, 19, 42, 62, 10, 52, 39, 6, 32, 14, 58, 17, 7, 26, 42, 34, 27, 10, 54, 40, 20, 63, 26, 53, 21, 61, 32, 7, 59, 48, 3, 56, 18, 31, 58, 14, 49, 21, 36, 16, 45, 9, 36, 24, 62, 45, 27, 31, 53, 17, 49, 12, 62, 18 },
+ { 28, 59, 21, 58, 2, 16, 38, 9, 62, 3, 56, 41, 10, 31, 50, 4, 32, 52, 12, 63, 23, 46, 33, 31, 4, 48, 25, 43, 14, 23, 47, 11, 22, 55, 14, 60, 23, 37, 11, 39, 23, 2, 45, 56, 31, 43, 19, 55, 16, 46, 21, 51, 11, 33, 44, 2, 41, 18, 5, 52, 23, 44, 17, 60, 27, 49, 11, 32, 44, 10, 54, 2, 56, 33, 8, 38, 13, 29, 36, 16, 24, 63, 27, 51, 21, 43, 56, 12, 49, 3, 59, 48, 1, 15, 46, 7, 36, 2, 47, 11, 50, 27, 37, 13, 33, 8, 51, 46, 1, 34, 28, 40, 3, 33, 60, 29, 47, 1, 35, 11, 59, 42, 2, 60, 26, 46, 6, 35 },
+ { 4, 43, 9, 29, 36, 63, 24, 44, 20, 50, 30, 17, 60, 22, 16, 43, 25, 3, 42, 19, 51, 15, 8, 54, 42, 15, 61, 5, 39, 57, 18, 61, 31, 48, 34, 2, 50, 19, 57, 5, 63, 33, 19, 38, 13, 27, 48, 7, 32, 61, 2, 26, 58, 6, 24, 50, 13, 61, 42, 20, 62, 2, 35, 20, 51, 4, 62, 18, 23, 58, 20, 31, 43, 15, 51, 45, 26, 50, 4, 55, 45, 3, 35, 9, 38, 1, 32, 61, 20, 45, 17, 33, 24, 57, 29, 51, 22, 58, 38, 30, 15, 1, 54, 21, 63, 43, 26, 12, 24, 56, 8, 60, 50, 19, 5, 52, 13, 54, 17, 50, 4, 16, 36, 12, 32, 56, 22, 54 },
+ { 51, 25, 40, 53, 12, 49, 15, 57, 34, 7, 38, 47, 2, 36, 55, 8, 61, 30, 56, 7, 28, 59, 48, 11, 27, 35, 21, 45, 28, 36, 9, 38, 6, 16, 24, 63, 10, 32, 28, 43, 21, 53, 5, 60, 8, 57, 3, 45, 11, 37, 15, 54, 40, 20, 62, 36, 27, 34, 11, 48, 30, 15, 54, 8, 30, 42, 22, 34, 48, 13, 35, 63, 4, 37, 22, 2, 59, 9, 41, 23, 13, 41, 49, 18, 59, 24, 40, 5, 37, 30, 9, 61, 44, 6, 37, 11, 33, 17, 5, 55, 41, 60, 23, 39, 17, 5, 30, 62, 41, 16, 46, 25, 11, 56, 39, 26, 20, 38, 29, 39, 22, 52, 44, 20, 48, 1, 38, 14 },
+ { 15, 33, 2, 18, 44, 6, 27, 0, 32, 61, 25, 12, 58, 28, 40, 20, 47, 13, 34, 43, 38, 1, 23, 62, 40, 0, 51, 10, 63, 3, 52, 26, 44, 30, 45, 6, 41, 54, 0, 51, 12, 30, 46, 24, 49, 22, 40, 33, 63, 23, 43, 30, 9, 47, 0, 17, 54, 7, 57, 3, 37, 47, 24, 46, 13, 55, 7, 52, 2, 42, 6, 26, 49, 18, 60, 34, 16, 57, 33, 20, 61, 30, 8, 54, 14, 46, 12, 53, 16, 55, 38, 13, 22, 53, 18, 59, 46, 27, 43, 19, 32, 10, 45, 6, 49, 36, 52, 2, 20, 55, 6, 39, 32, 15, 44, 3, 58, 10, 63, 6, 56, 30, 7, 58, 9, 40, 19, 63 },
+ { 10, 47, 61, 23, 55, 31, 52, 42, 17, 45, 4, 51, 27, 6, 15, 53, 0, 49, 26, 10, 56, 18, 36, 6, 20, 58, 32, 30, 13, 49, 19, 56, 0, 59, 12, 53, 27, 17, 38, 25, 48, 9, 15, 36, 14, 30, 59, 17, 0, 50, 8, 58, 18, 56, 31, 45, 21, 41, 29, 19, 60, 6, 32, 59, 0, 36, 29, 39, 19, 59, 46, 12, 55, 30, 10, 47, 24, 3, 28, 48, 0, 55, 44, 27, 33, 4, 63, 29, 49, 0, 26, 50, 34, 2, 42, 14, 0, 62, 9, 56, 3, 52, 28, 34, 58, 9, 20, 48, 37, 32, 22, 53, 0, 62, 27, 49, 34, 46, 21, 33, 41, 14, 25, 37, 53, 29, 31, 45 },
+ { 56, 28, 7, 37, 11, 36, 20, 9, 54, 14, 39, 19, 34, 63, 45, 37, 24, 17, 60, 31, 21, 45, 53, 29, 47, 15, 7, 55, 40, 23, 34, 14, 42, 20, 37, 35, 15, 59, 7, 62, 34, 40, 59, 1, 51, 42, 10, 28, 54, 21, 35, 5, 38, 13, 36, 4, 59, 12, 39, 53, 15, 43, 9, 21, 39, 62, 16, 56, 25, 9, 32, 38, 0, 41, 14, 51, 40, 53, 43, 11, 37, 17, 5, 22, 57, 39, 19, 7, 42, 21, 60, 10, 31, 63, 25, 52, 30, 49, 36, 25, 48, 17, 61, 14, 22, 42, 29, 13, 60, 11, 47, 18, 35, 41, 7, 23, 4, 16, 51, 11, 0, 48, 61, 3, 17, 50, 5, 24 },
+ { 0, 42, 21, 49, 60, 3, 57, 40, 29, 48, 23, 56, 42, 11, 22, 5, 59, 39, 4, 50, 3, 41, 12, 57, 25, 50, 44, 18, 4, 46, 7, 62, 33, 50, 4, 56, 21, 32, 43, 18, 3, 23, 55, 34, 20, 4, 53, 38, 12, 46, 29, 52, 25, 61, 23, 51, 26, 46, 1, 34, 25, 57, 28, 51, 26, 11, 50, 3, 44, 28, 53, 21, 57, 27, 62, 6, 31, 19, 8, 63, 26, 59, 36, 47, 15, 29, 50, 25, 35, 47, 18, 41, 4, 48, 8, 40, 12, 23, 6, 44, 13, 40, 1, 31, 55, 0, 61, 43, 4, 50, 26, 58, 9, 53, 24, 61, 42, 55, 31, 43, 57, 20, 34, 27, 43, 8, 59, 39 },
+ { 18, 51, 30, 13, 26, 16, 46, 22, 2, 59, 8, 30, 1, 48, 33, 51, 29, 9, 46, 16, 62, 14, 33, 2, 38, 9, 27, 60, 37, 26, 53, 17, 28, 10, 24, 46, 2, 49, 8, 57, 29, 45, 6, 26, 62, 44, 18, 25, 61, 3, 42, 14, 49, 10, 43, 6, 17, 32, 63, 10, 49, 4, 40, 14, 45, 33, 22, 37, 12, 61, 5, 17, 43, 7, 23, 37, 15, 58, 49, 13, 39, 21, 10, 52, 1, 62, 9, 56, 12, 2, 58, 28, 36, 16, 56, 28, 56, 35, 20, 63, 24, 37, 51, 8, 45, 25, 16, 33, 27, 38, 2, 44, 13, 30, 17, 36, 12, 26, 5, 18, 28, 47, 13, 60, 23, 45, 13, 33 },
+ { 55, 4, 62, 34, 52, 38, 7, 63, 32, 37, 13, 53, 25, 62, 18, 12, 55, 41, 27, 35, 24, 49, 31, 52, 17, 63, 34, 1, 56, 12, 41, 2, 48, 58, 39, 16, 61, 27, 41, 52, 13, 19, 50, 39, 11, 31, 57, 6, 32, 40, 20, 55, 1, 28, 33, 57, 48, 8, 37, 22, 44, 18, 53, 1, 61, 5, 54, 16, 47, 36, 50, 24, 55, 34, 48, 45, 1, 30, 33, 46, 2, 50, 32, 42, 25, 34, 43, 21, 38, 52, 23, 45, 14, 54, 21, 4, 44, 16, 53, 29, 10, 47, 19, 57, 12, 54, 39, 10, 51, 15, 63, 21, 57, 40, 51, 1, 48, 57, 37, 62, 2, 38, 9, 52, 1, 35, 58, 22 },
+ { 36, 46, 10, 42, 1, 27, 43, 15, 50, 21, 45, 16, 41, 3, 35, 44, 20, 1, 57, 11, 55, 7, 43, 8, 22, 42, 13, 46, 21, 39, 31, 60, 22, 5, 29, 44, 11, 35, 20, 4, 36, 58, 32, 15, 47, 2, 36, 48, 16, 60, 8, 35, 44, 63, 16, 2, 40, 26, 55, 14, 58, 35, 24, 31, 19, 42, 31, 58, 1, 29, 10, 40, 2, 19, 12, 54, 22, 61, 7, 24, 56, 5, 28, 16, 54, 3, 15, 58, 6, 30, 8, 62, 1, 43, 31, 47, 7, 59, 1, 38, 58, 4, 34, 27, 38, 5, 31, 59, 7, 46, 30, 3, 34, 6, 28, 59, 20, 8, 32, 15, 53, 24, 55, 31, 19, 49, 11, 26 },
+ { 2, 24, 16, 58, 19, 55, 5, 35, 10, 61, 4, 28, 57, 24, 58, 7, 31, 47, 22, 38, 19, 28, 61, 36, 54, 5, 59, 29, 6, 52, 15, 11, 43, 36, 8, 54, 52, 1, 62, 25, 47, 9, 1, 60, 28, 53, 24, 14, 46, 27, 51, 22, 12, 24, 38, 53, 20, 11, 51, 3, 29, 7, 48, 63, 8, 49, 9, 21, 52, 14, 63, 32, 46, 60, 35, 4, 41, 16, 52, 35, 18, 42, 59, 7, 36, 61, 45, 27, 33, 51, 19, 39, 34, 11, 61, 18, 33, 41, 28, 15, 54, 22, 42, 3, 49, 21, 47, 18, 36, 23, 55, 19, 48, 24, 45, 10, 33, 44, 50, 40, 7, 35, 15, 41, 63, 6, 40, 54 },
+ { 62, 41, 32, 8, 47, 28, 60, 24, 44, 30, 38, 49, 9, 33, 14, 40, 50, 14, 60, 2, 54, 40, 0, 20, 25, 39, 16, 49, 24, 35, 57, 47, 19, 61, 33, 18, 23, 37, 13, 55, 31, 43, 22, 41, 17, 8, 42, 58, 0, 37, 5, 56, 31, 54, 7, 30, 60, 33, 42, 17, 59, 39, 12, 27, 38, 17, 35, 41, 27, 45, 20, 7, 25, 15, 29, 58, 27, 47, 11, 40, 14, 54, 23, 46, 19, 31, 11, 40, 13, 49, 5, 58, 24, 51, 26, 6, 50, 20, 49, 9, 32, 46, 17, 60, 14, 63, 24, 1, 57, 41, 9, 43, 14, 62, 16, 52, 3, 27, 14, 22, 61, 45, 4, 28, 9, 47, 29, 17 },
+ { 5, 50, 12, 53, 38, 18, 11, 51, 0, 55, 17, 6, 47, 54, 19, 63, 5, 26, 34, 45, 13, 30, 47, 58, 10, 48, 32, 3, 62, 9, 26, 0, 25, 14, 50, 3, 47, 30, 42, 16, 6, 63, 12, 49, 33, 55, 21, 10, 34, 63, 18, 41, 3, 47, 19, 43, 0, 49, 8, 28, 46, 20, 52, 0, 56, 24, 60, 3, 59, 5, 39, 57, 48, 52, 9, 38, 3, 21, 26, 60, 0, 32, 12, 38, 4, 48, 53, 0, 60, 15, 29, 44, 18, 10, 38, 57, 13, 60, 2, 26, 62, 7, 50, 29, 35, 8, 40, 53, 28, 12, 60, 33, 38, 5, 37, 29, 60, 39, 56, 0, 30, 18, 50, 34, 59, 25, 14, 44 },
+ { 20, 31, 60, 22, 3, 49, 33, 25, 40, 13, 34, 59, 22, 36, 0, 28, 37, 56, 8, 18, 51, 16, 4, 45, 27, 12, 53, 42, 18, 44, 51, 31, 55, 40, 28, 58, 7, 60, 10, 51, 27, 37, 24, 56, 5, 26, 44, 29, 50, 23, 45, 11, 34, 15, 59, 27, 13, 23, 62, 37, 4, 57, 15, 32, 42, 6, 47, 11, 30, 43, 23, 13, 0, 36, 18, 44, 63, 51, 37, 29, 49, 20, 57, 27, 62, 9, 24, 35, 23, 53, 37, 3, 42, 55, 0, 36, 23, 39, 31, 43, 17, 37, 24, 11, 52, 43, 19, 32, 5, 50, 26, 0, 56, 21, 54, 11, 19, 6, 47, 25, 59, 42, 12, 54, 21, 3, 38, 57 },
+ { 48, 0, 35, 27, 44, 14, 59, 7, 57, 46, 26, 2, 42, 12, 52, 43, 10, 27, 53, 42, 32, 62, 37, 21, 34, 61, 7, 23, 36, 4, 38, 12, 41, 5, 17, 45, 22, 27, 39, 21, 59, 0, 45, 18, 39, 62, 3, 38, 14, 7, 54, 26, 61, 39, 9, 52, 45, 36, 18, 50, 10, 34, 44, 22, 50, 14, 36, 55, 17, 34, 53, 62, 33, 26, 56, 6, 31, 12, 6, 53, 9, 44, 2, 50, 20, 40, 55, 17, 47, 7, 26, 63, 22, 32, 48, 16, 46, 8, 52, 12, 57, 41, 0, 56, 25, 3, 61, 14, 45, 35, 18, 44, 12, 46, 23, 42, 32, 51, 35, 10, 17, 36, 23, 1, 45, 52, 32, 10 },
+ { 37, 15, 43, 8, 63, 39, 21, 31, 16, 37, 19, 62, 30, 46, 17, 60, 21, 48, 1, 23, 6, 25, 11, 56, 1, 40, 30, 58, 15, 54, 21, 59, 9, 63, 35, 56, 11, 51, 2, 46, 34, 14, 53, 7, 30, 11, 51, 19, 60, 40, 30, 1, 24, 50, 20, 32, 3, 56, 5, 25, 31, 13, 61, 2, 29, 60, 25, 20, 51, 2, 27, 8, 18, 42, 10, 45, 21, 34, 43, 17, 62, 29, 41, 14, 34, 6, 30, 43, 2, 57, 33, 13, 45, 12, 27, 62, 4, 55, 21, 35, 5, 27, 45, 33, 16, 47, 30, 54, 22, 10, 51, 27, 63, 7, 49, 1, 58, 22, 15, 43, 53, 7, 57, 39, 27, 12, 61, 24 },
+ { 56, 51, 26, 56, 19, 2, 41, 54, 5, 52, 9, 48, 6, 23, 39, 4, 32, 15, 63, 35, 59, 49, 43, 15, 52, 19, 50, 9, 46, 33, 1, 29, 48, 20, 32, 1, 38, 33, 19, 54, 9, 32, 24, 48, 58, 35, 16, 48, 4, 52, 13, 57, 33, 5, 45, 59, 15, 29, 41, 55, 47, 39, 23, 53, 9, 40, 4, 57, 10, 44, 48, 40, 50, 14, 61, 24, 55, 1, 59, 22, 33, 8, 51, 25, 58, 46, 11, 59, 20, 41, 17, 51, 6, 56, 35, 25, 42, 30, 15, 58, 48, 18, 61, 9, 58, 39, 13, 2, 37, 59, 40, 2, 31, 16, 34, 41, 8, 30, 62, 3, 29, 48, 33, 5, 63, 16, 41, 7 },
+ { 22, 4, 46, 11, 33, 51, 29, 10, 62, 24, 43, 27, 15, 58, 50, 25, 54, 44, 9, 38, 18, 3, 29, 57, 32, 5, 26, 43, 17, 61, 24, 52, 8, 42, 23, 53, 15, 61, 7, 28, 57, 43, 4, 40, 20, 2, 43, 25, 32, 35, 21, 43, 17, 48, 10, 22, 38, 54, 11, 21, 1, 58, 16, 30, 48, 18, 46, 32, 38, 13, 22, 4, 59, 35, 2, 51, 30, 39, 15, 47, 4, 56, 13, 37, 1, 28, 16, 52, 32, 9, 61, 29, 38, 19, 3, 52, 10, 48, 1, 32, 11, 40, 20, 36, 6, 22, 49, 29, 55, 6, 20, 56, 36, 52, 19, 60, 26, 46, 18, 54, 40, 13, 20, 46, 35, 19, 49, 29 },
+ { 61, 17, 34, 53, 23, 6, 48, 35, 20, 40, 1, 56, 36, 29, 11, 34, 7, 41, 14, 30, 55, 20, 46, 8, 24, 38, 63, 2, 37, 10, 45, 14, 34, 49, 6, 13, 44, 25, 49, 41, 21, 12, 61, 15, 54, 29, 63, 12, 56, 8, 49, 2, 62, 36, 28, 61, 0, 25, 41, 63, 35, 8, 44, 6, 37, 62, 7, 21, 63, 28, 55, 31, 16, 24, 41, 19, 9, 57, 27, 36, 18, 42, 31, 62, 22, 55, 38, 4, 27, 47, 1, 40, 14, 54, 43, 20, 60, 23, 38, 63, 25, 51, 2, 53, 26, 63, 10, 42, 17, 34, 47, 25, 13, 5, 44, 11, 55, 2, 38, 27, 6, 60, 52, 25, 9, 55, 1, 40 },
+ { 8, 30, 58, 3, 42, 61, 17, 38, 13, 59, 32, 10, 54, 3, 51, 20, 61, 26, 57, 2, 46, 33, 12, 60, 41, 13, 48, 29, 55, 20, 39, 27, 57, 18, 62, 29, 55, 2, 31, 16, 37, 50, 26, 36, 6, 46, 9, 41, 27, 57, 23, 39, 26, 6, 51, 12, 31, 46, 7, 16, 27, 52, 19, 56, 26, 12, 33, 53, 1, 41, 8, 57, 46, 7, 54, 32, 47, 5, 49, 11, 60, 23, 5, 48, 10, 43, 19, 63, 35, 24, 49, 21, 59, 5, 31, 37, 14, 44, 7, 42, 6, 30, 46, 13, 44, 32, 19, 50, 4, 58, 8, 30, 62, 38, 28, 53, 21, 36, 13, 50, 21, 33, 15, 2, 44, 31, 14, 47 },
+ { 37, 13, 39, 16, 28, 9, 57, 0, 25, 49, 21, 45, 18, 47, 12, 42, 0, 49, 22, 39, 16, 53, 25, 36, 0, 52, 22, 16, 6, 60, 4, 51, 0, 26, 37, 47, 10, 36, 63, 5, 57, 0, 18, 59, 23, 33, 51, 19, 0, 44, 15, 11, 54, 17, 42, 35, 53, 18, 58, 33, 49, 4, 34, 42, 0, 50, 43, 25, 16, 49, 34, 20, 37, 28, 12, 63, 16, 38, 25, 44, 0, 40, 52, 17, 35, 3, 50, 14, 8, 53, 11, 36, 25, 45, 9, 62, 0, 54, 28, 17, 50, 55, 15, 24, 57, 0, 53, 34, 23, 41, 15, 45, 0, 49, 16, 4, 48, 9, 63, 45, 0, 42, 58, 37, 61, 22, 54, 26 },
+ { 0, 50, 21, 47, 54, 36, 27, 45, 52, 4, 34, 15, 63, 29, 37, 59, 17, 31, 6, 61, 28, 5, 48, 18, 59, 27, 34, 56, 44, 31, 35, 12, 41, 59, 16, 3, 40, 20, 50, 22, 30, 40, 52, 10, 45, 3, 59, 22, 37, 61, 29, 46, 31, 58, 2, 22, 9, 43, 3, 39, 14, 61, 24, 54, 15, 29, 11, 60, 39, 17, 5, 61, 0, 44, 50, 3, 31, 14, 58, 21, 54, 28, 15, 45, 60, 26, 33, 58, 44, 22, 60, 2, 57, 34, 49, 27, 18, 34, 21, 59, 29, 4, 36, 41, 8, 39, 28, 11, 62, 26, 53, 20, 35, 24, 59, 32, 29, 39, 24, 31, 57, 23, 11, 28, 5, 36, 11, 59 },
+ { 44, 32, 63, 5, 20, 12, 41, 7, 30, 61, 42, 8, 39, 5, 33, 8, 24, 53, 45, 11, 37, 58, 7, 44, 10, 50, 3, 40, 8, 22, 53, 19, 46, 9, 33, 52, 24, 58, 8, 44, 13, 47, 8, 34, 38, 30, 14, 47, 7, 34, 4, 55, 9, 19, 40, 49, 56, 26, 60, 21, 30, 45, 10, 19, 40, 58, 23, 36, 3, 52, 45, 23, 54, 13, 22, 42, 53, 45, 7, 33, 10, 36, 57, 6, 29, 12, 41, 0, 30, 15, 41, 30, 17, 7, 16, 53, 40, 56, 2, 39, 12, 61, 10, 52, 31, 60, 16, 45, 1, 37, 7, 61, 40, 10, 43, 17, 58, 7, 54, 14, 4, 51, 39, 49, 18, 56, 42, 20 },
+ { 14, 6, 24, 36, 56, 49, 22, 60, 18, 14, 23, 51, 26, 57, 21, 52, 41, 14, 35, 50, 19, 31, 40, 23, 33, 14, 63, 17, 32, 47, 7, 62, 23, 30, 56, 11, 42, 27, 14, 60, 35, 19, 28, 61, 17, 55, 25, 39, 53, 17, 42, 21, 38, 63, 25, 5, 14, 36, 12, 50, 1, 37, 59, 32, 2, 51, 6, 56, 27, 32, 11, 30, 38, 26, 60, 8, 26, 19, 62, 39, 50, 2, 21, 39, 53, 23, 56, 19, 49, 39, 5, 46, 55, 23, 42, 4, 31, 11, 47, 26, 45, 22, 48, 18, 21, 5, 48, 25, 57, 14, 47, 30, 3, 56, 12, 50, 1, 42, 19, 47, 35, 17, 8, 30, 45, 25, 4, 51 },
+ { 28, 58, 43, 1, 31, 8, 33, 2, 44, 55, 32, 1, 60, 12, 46, 27, 4, 62, 23, 1, 56, 13, 62, 2, 54, 36, 25, 51, 1, 57, 26, 42, 3, 49, 17, 38, 1, 48, 31, 4, 54, 3, 50, 24, 1, 49, 5, 63, 13, 27, 52, 1, 48, 13, 45, 33, 52, 30, 46, 20, 55, 28, 6, 48, 24, 38, 20, 47, 14, 62, 48, 9, 58, 4, 36, 30, 56, 1, 34, 12, 18, 63, 25, 48, 4, 16, 37, 7, 62, 10, 52, 28, 13, 50, 36, 63, 24, 51, 15, 58, 8, 33, 1, 38, 56, 35, 42, 9, 33, 51, 22, 18, 48, 32, 27, 37, 23, 61, 33, 11, 59, 29, 62, 1, 53, 10, 60, 33 },
+ { 12, 39, 17, 52, 26, 46, 53, 38, 25, 11, 48, 36, 16, 43, 2, 35, 55, 17, 39, 29, 43, 9, 28, 45, 20, 5, 46, 12, 42, 28, 13, 52, 36, 6, 60, 22, 54, 17, 62, 39, 25, 42, 15, 55, 44, 20, 31, 10, 35, 57, 24, 32, 29, 6, 59, 18, 7, 62, 3, 41, 10, 44, 16, 54, 13, 62, 31, 9, 41, 1, 21, 43, 18, 47, 15, 40, 11, 49, 28, 55, 46, 30, 8, 43, 32, 61, 28, 47, 25, 34, 21, 61, 32, 1, 20, 9, 46, 6, 35, 19, 41, 54, 27, 63, 14, 3, 51, 20, 62, 2, 38, 55, 8, 21, 63, 6, 46, 9, 26, 51, 3, 24, 43, 34, 16, 41, 18, 48 },
+ { 62, 23, 55, 9, 15, 62, 19, 13, 58, 40, 6, 30, 54, 19, 50, 31, 10, 44, 6, 59, 21, 47, 51, 15, 60, 39, 30, 54, 21, 61, 19, 33, 14, 29, 43, 11, 34, 45, 7, 21, 10, 56, 36, 6, 38, 11, 58, 42, 2, 47, 11, 60, 50, 16, 41, 28, 38, 23, 47, 17, 35, 63, 22, 33, 42, 5, 45, 17, 53, 35, 25, 56, 33, 6, 51, 19, 60, 23, 43, 15, 5, 40, 58, 13, 51, 1, 45, 11, 54, 3, 43, 8, 37, 48, 59, 29, 39, 21, 61, 43, 3, 31, 10, 44, 24, 29, 60, 12, 28, 40, 11, 25, 43, 52, 14, 41, 16, 57, 44, 20, 40, 55, 12, 21, 57, 27, 35, 2 },
+ { 37, 6, 31, 42, 40, 4, 29, 50, 0, 20, 63, 28, 9, 58, 14, 24, 63, 26, 48, 16, 34, 4, 32, 38, 23, 11, 58, 4, 37, 9, 45, 5, 63, 48, 26, 57, 2, 28, 32, 51, 46, 29, 13, 62, 27, 46, 28, 18, 50, 15, 40, 4, 19, 34, 54, 0, 53, 9, 26, 58, 28, 5, 49, 0, 57, 27, 19, 60, 29, 8, 59, 12, 37, 63, 24, 46, 3, 37, 6, 52, 26, 32, 20, 36, 9, 22, 59, 18, 35, 51, 14, 57, 17, 24, 12, 44, 56, 0, 30, 13, 59, 20, 49, 17, 54, 43, 6, 34, 46, 17, 58, 36, 0, 34, 29, 54, 25, 2, 36, 15, 60, 6, 37, 46, 4, 50, 9, 45 },
+ { 19, 59, 48, 3, 24, 60, 44, 22, 34, 51, 15, 45, 41, 5, 33, 47, 0, 37, 12, 55, 25, 54, 8, 57, 0, 47, 18, 34, 49, 15, 55, 24, 40, 20, 8, 35, 53, 13, 41, 18, 0, 59, 22, 33, 4, 52, 8, 60, 24, 36, 31, 56, 45, 26, 10, 43, 15, 56, 36, 4, 51, 14, 39, 30, 12, 55, 36, 2, 39, 49, 4, 44, 17, 0, 32, 13, 53, 35, 59, 17, 62, 0, 55, 24, 52, 38, 31, 6, 42, 19, 29, 40, 4, 54, 33, 5, 16, 27, 52, 37, 23, 55, 7, 37, 0, 39, 23, 49, 4, 53, 31, 15, 59, 10, 50, 4, 60, 34, 48, 7, 31, 49, 27, 14, 62, 22, 53, 29 },
+ { 46, 21, 14, 51, 36, 17, 7, 57, 10, 32, 3, 37, 22, 60, 39, 18, 56, 20, 42, 3, 36, 10, 44, 26, 41, 29, 53, 27, 2, 39, 30, 52, 0, 59, 15, 48, 23, 61, 6, 58, 37, 12, 40, 49, 16, 39, 20, 44, 0, 62, 8, 21, 3, 59, 23, 32, 49, 31, 12, 44, 22, 59, 18, 50, 24, 7, 43, 52, 15, 23, 41, 26, 51, 28, 55, 39, 21, 27, 10, 42, 12, 45, 27, 47, 3, 15, 63, 26, 55, 0, 60, 26, 45, 18, 62, 38, 58, 49, 8, 47, 4, 33, 46, 29, 57, 13, 56, 16, 59, 21, 5, 47, 23, 39, 18, 44, 13, 22, 28, 53, 19, 0, 58, 32, 41, 7, 26, 13 },
+ { 0, 56, 34, 28, 11, 55, 31, 47, 26, 41, 56, 13, 53, 28, 11, 49, 7, 52, 32, 61, 50, 22, 63, 17, 13, 56, 7, 19, 43, 62, 10, 21, 37, 32, 43, 4, 38, 19, 44, 25, 31, 54, 5, 23, 61, 30, 53, 12, 35, 22, 43, 53, 37, 48, 7, 62, 20, 2, 61, 41, 8, 34, 47, 9, 63, 34, 28, 10, 55, 33, 14, 57, 7, 47, 9, 61, 4, 49, 31, 50, 21, 38, 8, 16, 57, 44, 33, 5, 49, 36, 12, 50, 7, 34, 10, 25, 2, 22, 36, 15, 26, 61, 18, 9, 22, 46, 32, 8, 27, 37, 44, 30, 55, 3, 62, 24, 38, 56, 5, 45, 38, 24, 43, 10, 19, 54, 39, 61 },
+ { 41, 30, 8, 63, 43, 23, 38, 3, 62, 19, 8, 49, 25, 1, 58, 30, 23, 40, 9, 28, 18, 40, 6, 38, 49, 22, 35, 59, 8, 27, 50, 5, 56, 17, 11, 50, 30, 9, 55, 2, 51, 19, 34, 47, 9, 41, 6, 26, 48, 57, 14, 28, 17, 12, 39, 13, 37, 46, 25, 19, 54, 27, 1, 37, 16, 45, 20, 60, 1, 48, 20, 38, 31, 22, 42, 15, 19, 44, 1, 61, 6, 34, 56, 40, 29, 10, 20, 46, 13, 22, 41, 23, 59, 42, 30, 51, 45, 13, 63, 53, 42, 12, 51, 38, 62, 2, 26, 41, 50, 1, 61, 10, 19, 42, 31, 8, 49, 32, 12, 63, 9, 52, 16, 56, 36, 2, 31, 16 },
+ { 52, 5, 47, 20, 1, 53, 12, 50, 16, 35, 43, 21, 33, 43, 16, 44, 3, 59, 14, 46, 1, 30, 60, 33, 2, 45, 12, 42, 31, 47, 14, 33, 46, 25, 55, 27, 60, 36, 16, 42, 14, 46, 26, 1, 55, 15, 63, 32, 2, 38, 5, 47, 33, 61, 30, 52, 4, 57, 6, 38, 11, 43, 61, 24, 52, 3, 31, 22, 42, 10, 62, 3, 59, 11, 35, 57, 33, 54, 24, 14, 29, 48, 18, 2, 60, 41, 53, 24, 32, 62, 3, 53, 15, 1, 55, 17, 32, 40, 6, 31, 1, 40, 28, 5, 35, 52, 19, 63, 13, 33, 17, 41, 52, 26, 15, 57, 1, 20, 42, 17, 35, 27, 48, 5, 25, 50, 44, 11 },
+ { 35, 25, 38, 57, 33, 17, 40, 6, 59, 27, 54, 5, 61, 10, 52, 26, 36, 19, 51, 35, 57, 48, 11, 20, 54, 25, 61, 16, 1, 58, 24, 61, 3, 39, 7, 47, 1, 22, 49, 28, 63, 10, 58, 32, 17, 36, 45, 19, 51, 29, 59, 10, 50, 1, 23, 42, 18, 29, 51, 21, 56, 32, 14, 5, 40, 58, 47, 13, 54, 35, 29, 45, 18, 52, 26, 2, 38, 8, 46, 36, 58, 11, 52, 35, 17, 28, 1, 58, 9, 39, 17, 28, 37, 48, 20, 9, 57, 24, 50, 19, 58, 16, 48, 25, 43, 11, 35, 6, 45, 24, 56, 4, 36, 7, 47, 35, 52, 28, 59, 30, 2, 61, 21, 33, 63, 12, 18, 59 },
+ { 3, 49, 15, 10, 27, 61, 25, 45, 30, 0, 14, 47, 31, 38, 17, 62, 7, 55, 27, 4, 15, 24, 42, 52, 10, 34, 5, 51, 36, 18, 41, 11, 35, 21, 62, 13, 33, 57, 8, 35, 5, 40, 21, 43, 52, 3, 24, 56, 11, 16, 33, 25, 41, 20, 55, 8, 60, 35, 15, 48, 2, 57, 30, 49, 18, 25, 6, 39, 17, 57, 7, 25, 43, 5, 49, 16, 62, 22, 55, 4, 25, 43, 23, 7, 50, 11, 37, 48, 14, 51, 33, 57, 7, 27, 39, 46, 4, 29, 11, 43, 34, 56, 7, 60, 20, 54, 30, 57, 22, 49, 9, 33, 54, 14, 63, 23, 6, 43, 10, 40, 50, 13, 44, 8, 38, 33, 46, 23 },
+ { 55, 39, 22, 50, 44, 4, 36, 9, 52, 23, 37, 59, 21, 2, 46, 13, 31, 41, 11, 45, 62, 29, 6, 37, 19, 48, 30, 23, 44, 7, 53, 28, 54, 16, 41, 29, 44, 18, 52, 24, 60, 15, 48, 7, 27, 59, 9, 34, 42, 54, 7, 63, 4, 46, 31, 27, 45, 0, 40, 26, 34, 17, 37, 10, 53, 29, 36, 50, 2, 27, 51, 11, 61, 37, 23, 41, 30, 7, 18, 50, 39, 14, 63, 32, 45, 61, 19, 30, 25, 44, 2, 47, 23, 63, 11, 34, 59, 37, 60, 3, 22, 14, 44, 30, 15, 0, 47, 15, 3, 38, 61, 20, 27, 45, 11, 39, 51, 16, 55, 3, 22, 54, 29, 58, 1, 57, 6, 29 },
+ { 9, 17, 60, 2, 34, 56, 20, 62, 39, 12, 49, 6, 29, 56, 34, 48, 0, 58, 22, 38, 18, 43, 56, 0, 63, 14, 55, 3, 59, 31, 15, 45, 0, 49, 6, 58, 3, 38, 12, 45, 0, 37, 29, 57, 13, 39, 30, 49, 0, 23, 44, 36, 16, 57, 13, 54, 11, 24, 63, 9, 53, 7, 62, 42, 0, 59, 15, 23, 63, 34, 40, 16, 32, 0, 53, 12, 48, 28, 59, 33, 0, 53, 9, 27, 3, 22, 54, 5, 56, 9, 61, 13, 42, 14, 52, 19, 0, 21, 47, 27, 53, 36, 3, 50, 39, 58, 25, 40, 53, 28, 12, 50, 0, 59, 32, 2, 21, 34, 26, 46, 37, 7, 18, 47, 24, 14, 53, 42 },
+ { 61, 32, 13, 54, 29, 7, 46, 13, 28, 57, 18, 41, 53, 15, 9, 39, 24, 49, 33, 3, 53, 9, 26, 32, 40, 28, 46, 39, 25, 9, 56, 21, 63, 37, 26, 22, 51, 27, 17, 56, 31, 53, 4, 43, 22, 46, 12, 18, 60, 40, 20, 26, 50, 21, 39, 5, 49, 33, 16, 44, 22, 46, 20, 32, 24, 45, 8, 43, 12, 46, 4, 48, 56, 20, 29, 58, 3, 40, 10, 42, 31, 21, 47, 41, 56, 38, 15, 42, 36, 27, 20, 33, 55, 3, 26, 44, 31, 54, 12, 35, 9, 63, 28, 10, 21, 32, 9, 60, 17, 8, 43, 29, 40, 16, 36, 48, 60, 7, 57, 14, 62, 31, 42, 15, 36, 40, 20, 26 },
+ { 0, 37, 47, 23, 41, 18, 32, 48, 1, 35, 8, 25, 4, 26, 63, 20, 54, 8, 16, 61, 35, 23, 51, 15, 58, 7, 12, 20, 50, 34, 42, 4, 38, 10, 32, 47, 8, 60, 41, 20, 9, 25, 50, 19, 62, 1, 37, 56, 28, 8, 53, 11, 3, 58, 34, 43, 19, 60, 38, 4, 58, 31, 3, 51, 11, 55, 38, 30, 21, 58, 19, 26, 9, 44, 36, 13, 46, 20, 62, 24, 13, 60, 5, 28, 12, 34, 7, 59, 0, 53, 45, 6, 38, 30, 50, 7, 62, 16, 41, 5, 46, 18, 55, 42, 51, 5, 45, 23, 34, 48, 19, 58, 5, 25, 54, 19, 13, 41, 28, 21, 0, 49, 10, 60, 4, 51, 9, 45 },
+ { 19, 28, 6, 58, 10, 51, 4, 22, 55, 42, 60, 45, 34, 51, 42, 5, 30, 45, 27, 40, 13, 47, 4, 49, 21, 38, 60, 29, 2, 57, 17, 27, 52, 19, 61, 14, 30, 34, 2, 44, 63, 33, 11, 35, 16, 51, 25, 6, 14, 47, 31, 61, 37, 29, 18, 8, 52, 2, 28, 54, 13, 41, 15, 62, 35, 18, 2, 60, 6, 33, 41, 61, 31, 6, 56, 17, 34, 50, 6, 52, 44, 35, 16, 51, 59, 24, 48, 18, 31, 40, 16, 49, 21, 60, 17, 39, 10, 49, 32, 57, 24, 39, 1, 25, 18, 62, 37, 12, 56, 1, 37, 11, 52, 44, 9, 30, 47, 4, 51, 40, 55, 25, 34, 27, 56, 30, 32, 54 },
+ { 63, 40, 49, 15, 43, 26, 63, 38, 16, 20, 30, 12, 57, 14, 19, 60, 36, 12, 59, 2, 57, 17, 42, 31, 1, 44, 16, 35, 47, 11, 32, 48, 13, 43, 1, 39, 51, 12, 57, 23, 6, 40, 53, 3, 55, 31, 39, 60, 35, 44, 5, 15, 45, 1, 62, 41, 26, 14, 47, 22, 36, 27, 50, 9, 26, 47, 52, 28, 54, 16, 1, 13, 51, 39, 23, 63, 1, 30, 15, 26, 2, 57, 19, 37, 1, 44, 21, 50, 13, 63, 8, 24, 56, 1, 35, 25, 58, 20, 2, 28, 14, 51, 33, 59, 13, 30, 4, 49, 31, 24, 63, 26, 33, 3, 58, 38, 62, 24, 32, 8, 17, 45, 5, 48, 18, 3, 43, 11 },
+ { 21, 4, 24, 34, 59, 1, 37, 11, 53, 5, 47, 2, 22, 40, 32, 1, 24, 50, 21, 29, 38, 25, 63, 8, 55, 24, 53, 6, 62, 23, 59, 3, 54, 20, 58, 24, 5, 46, 15, 38, 48, 14, 27, 42, 23, 7, 46, 10, 17, 58, 25, 52, 23, 32, 49, 12, 55, 30, 40, 7, 59, 1, 56, 21, 39, 4, 23, 15, 37, 46, 55, 42, 21, 4, 48, 8, 45, 54, 37, 55, 32, 8, 46, 10, 30, 54, 4, 41, 25, 29, 36, 48, 11, 43, 14, 47, 5, 43, 53, 36, 61, 10, 45, 6, 41, 54, 27, 43, 16, 55, 6, 46, 18, 42, 23, 15, 1, 45, 12, 60, 37, 22, 62, 12, 39, 59, 16, 52 },
+ { 47, 35, 56, 7, 19, 46, 31, 50, 33, 24, 61, 35, 50, 7, 53, 44, 55, 6, 46, 10, 52, 5, 21, 43, 36, 10, 18, 41, 26, 37, 8, 29, 40, 36, 9, 49, 34, 26, 61, 21, 7, 59, 18, 62, 29, 54, 20, 32, 51, 0, 40, 10, 55, 6, 20, 36, 9, 61, 5, 51, 44, 19, 33, 43, 13, 57, 40, 63, 8, 24, 29, 10, 60, 34, 27, 40, 25, 18, 10, 42, 21, 49, 26, 62, 38, 12, 33, 61, 5, 57, 2, 19, 54, 28, 62, 22, 38, 31, 16, 7, 22, 47, 29, 17, 35, 8, 20, 51, 2, 40, 22, 50, 13, 61, 28, 53, 35, 20, 56, 30, 2, 53, 14, 41, 23, 34, 8, 31 },
+ { 12, 2, 42, 29, 52, 13, 21, 8, 55, 14, 41, 17, 28, 58, 23, 11, 17, 36, 31, 62, 17, 34, 50, 14, 28, 61, 33, 52, 2, 51, 17, 45, 7, 25, 62, 30, 18, 55, 0, 42, 30, 35, 45, 1, 12, 48, 3, 63, 21, 36, 30, 48, 19, 59, 43, 27, 46, 17, 34, 25, 12, 29, 53, 6, 48, 31, 11, 34, 49, 3, 36, 50, 19, 47, 14, 61, 11, 36, 58, 4, 60, 14, 39, 22, 6, 52, 15, 35, 17, 46, 31, 42, 9, 34, 3, 52, 12, 60, 26, 56, 40, 2, 53, 23, 57, 38, 62, 14, 36, 59, 10, 31, 39, 6, 49, 9, 41, 26, 5, 48, 43, 27, 33, 58, 1, 50, 25, 57 },
+ { 61, 37, 15, 61, 3, 39, 58, 43, 26, 0, 44, 10, 47, 3, 37, 63, 28, 43, 13, 39, 3, 57, 30, 59, 0, 48, 5, 43, 13, 22, 60, 33, 55, 15, 42, 4, 52, 10, 45, 13, 54, 4, 24, 49, 37, 26, 41, 14, 42, 9, 61, 13, 38, 23, 3, 53, 0, 58, 21, 42, 63, 10, 17, 61, 25, 0, 58, 28, 17, 44, 57, 12, 27, 0, 55, 5, 52, 28, 23, 47, 29, 0, 43, 17, 58, 28, 47, 23, 55, 10, 58, 23, 51, 40, 18, 33, 45, 0, 49, 8, 32, 61, 19, 48, 0, 26, 7, 47, 29, 18, 44, 0, 56, 34, 20, 59, 15, 51, 37, 18, 10, 52, 7, 20, 46, 9, 38, 17 },
+ { 6, 27, 48, 23, 45, 29, 5, 18, 38, 62, 27, 56, 20, 32, 15, 9, 48, 0, 54, 22, 45, 20, 7, 41, 23, 39, 19, 27, 58, 31, 44, 0, 12, 50, 23, 56, 20, 39, 32, 59, 16, 52, 33, 9, 57, 22, 6, 58, 28, 50, 24, 2, 56, 35, 16, 45, 32, 38, 15, 54, 2, 38, 46, 22, 35, 45, 20, 5, 52, 25, 7, 35, 59, 32, 22, 43, 38, 3, 51, 16, 34, 53, 32, 50, 3, 40, 8, 43, 0, 39, 27, 4, 14, 61, 8, 55, 15, 41, 20, 44, 27, 13, 39, 11, 46, 42, 54, 33, 4, 52, 23, 61, 14, 25, 43, 2, 33, 11, 63, 29, 61, 17, 40, 55, 22, 62, 28, 44 },
+ { 20, 54, 8, 56, 35, 10, 63, 31, 52, 12, 48, 6, 59, 41, 52, 33, 19, 58, 25, 49, 11, 37, 47, 12, 54, 15, 56, 35, 7, 47, 16, 53, 28, 34, 5, 37, 28, 8, 48, 3, 28, 38, 18, 61, 16, 43, 53, 32, 4, 17, 47, 27, 44, 8, 63, 10, 25, 49, 6, 37, 24, 52, 32, 3, 50, 12, 41, 56, 38, 14, 62, 20, 40, 16, 53, 31, 18, 63, 41, 9, 59, 7, 13, 25, 57, 20, 63, 26, 53, 18, 48, 62, 30, 46, 21, 25, 58, 29, 36, 4, 55, 34, 6, 60, 31, 16, 21, 12, 58, 38, 9, 29, 47, 7, 52, 30, 57, 44, 22, 0, 35, 45, 3, 31, 14, 36, 0, 51 },
+ { 42, 14, 33, 24, 16, 49, 40, 2, 22, 33, 16, 36, 25, 1, 21, 61, 38, 8, 33, 4, 62, 26, 29, 60, 6, 46, 30, 11, 63, 4, 36, 40, 19, 57, 46, 11, 41, 63, 22, 25, 58, 10, 46, 2, 34, 27, 11, 38, 56, 34, 12, 53, 18, 33, 41, 51, 13, 28, 60, 20, 47, 14, 29, 59, 16, 62, 8, 22, 32, 47, 9, 49, 2, 44, 7, 12, 45, 6, 20, 27, 45, 24, 62, 42, 36, 11, 33, 15, 37, 7, 32, 10, 37, 1, 35, 50, 6, 11, 63, 24, 52, 15, 50, 24, 3, 37, 56, 27, 34, 22, 49, 16, 36, 62, 17, 39, 4, 15, 54, 24, 50, 8, 58, 26, 49, 54, 11, 30 },
+ { 4, 59, 41, 1, 53, 12, 25, 45, 59, 7, 51, 39, 54, 14, 46, 4, 27, 53, 16, 44, 18, 51, 1, 32, 25, 2, 50, 40, 20, 54, 24, 9, 62, 2, 27, 60, 1, 17, 36, 50, 6, 40, 30, 55, 41, 19, 49, 1, 21, 60, 40, 5, 62, 1, 22, 30, 57, 4, 43, 31, 1, 55, 40, 7, 27, 37, 30, 54, 1, 19, 42, 30, 56, 26, 62, 49, 24, 57, 37, 56, 2, 39, 16, 5, 30, 55, 3, 49, 60, 23, 56, 44, 17, 52, 13, 42, 28, 48, 18, 45, 9, 37, 21, 41, 58, 10, 48, 1, 63, 5, 41, 57, 2, 24, 12, 48, 27, 42, 32, 46, 13, 38, 19, 34, 5, 41, 25, 60 },
+ { 39, 28, 21, 46, 32, 57, 36, 9, 19, 42, 4, 29, 11, 43, 30, 49, 13, 42, 35, 56, 9, 39, 15, 52, 36, 61, 18, 26, 45, 14, 31, 48, 21, 43, 14, 33, 49, 54, 14, 44, 21, 62, 13, 23, 8, 62, 15, 51, 44, 7, 30, 37, 20, 42, 56, 7, 39, 18, 50, 11, 61, 9, 19, 43, 57, 2, 48, 11, 39, 60, 28, 4, 37, 17, 35, 1, 33, 11, 31, 14, 48, 19, 35, 51, 46, 21, 44, 29, 12, 41, 2, 22, 58, 26, 54, 4, 59, 38, 2, 33, 57, 1, 63, 13, 28, 51, 15, 40, 18, 45, 8, 30, 43, 37, 54, 19, 8, 59, 21, 6, 60, 29, 55, 10, 63, 15, 47, 17 },
+ { 3, 50, 10, 62, 18, 5, 27, 49, 60, 23, 55, 18, 62, 24, 56, 10, 59, 28, 2, 23, 34, 59, 43, 20, 10, 42, 8, 49, 1, 37, 57, 6, 51, 29, 53, 7, 23, 31, 5, 32, 51, 0, 35, 54, 45, 31, 5, 26, 36, 24, 55, 15, 48, 29, 14, 48, 26, 60, 21, 41, 36, 26, 50, 33, 14, 44, 17, 24, 52, 15, 46, 23, 54, 6, 47, 21, 60, 50, 4, 53, 29, 61, 8, 23, 1, 60, 19, 6, 53, 16, 47, 34, 6, 39, 16, 31, 12, 20, 53, 22, 30, 43, 25, 46, 35, 6, 44, 32, 53, 26, 55, 19, 11, 59, 5, 33, 51, 1, 35, 53, 25, 3, 42, 23, 44, 32, 7, 53 },
+ { 22, 44, 37, 6, 26, 51, 38, 0, 34, 13, 31, 46, 3, 37, 6, 19, 40, 21, 47, 63, 12, 5, 29, 55, 22, 58, 34, 28, 60, 22, 11, 41, 17, 38, 9, 44, 59, 39, 56, 19, 11, 47, 25, 15, 3, 39, 57, 17, 61, 11, 46, 3, 58, 9, 54, 35, 2, 34, 8, 45, 15, 56, 5, 23, 53, 33, 63, 35, 4, 59, 10, 51, 13, 61, 29, 41, 15, 25, 43, 19, 40, 10, 54, 33, 41, 12, 38, 51, 31, 26, 61, 9, 30, 45, 24, 62, 49, 40, 10, 61, 14, 49, 5, 17, 54, 20, 60, 23, 3, 13, 35, 50, 32, 23, 46, 27, 38, 63, 16, 12, 39, 48, 18, 51, 1, 27, 56, 35 },
+ { 63, 15, 30, 55, 43, 14, 57, 17, 53, 44, 7, 48, 26, 50, 32, 60, 0, 53, 14, 31, 50, 24, 46, 0, 38, 13, 4, 52, 16, 45, 30, 59, 0, 25, 55, 35, 16, 10, 26, 42, 58, 29, 60, 38, 50, 22, 28, 47, 0, 50, 28, 19, 33, 39, 11, 44, 16, 52, 24, 59, 3, 38, 27, 51, 0, 21, 7, 42, 26, 34, 21, 40, 33, 18, 39, 3, 54, 38, 8, 59, 0, 44, 27, 15, 58, 28, 57, 9, 43, 0, 36, 50, 20, 59, 8, 34, 0, 27, 47, 7, 36, 19, 56, 32, 0, 38, 11, 29, 62, 47, 6, 61, 0, 41, 14, 56, 10, 23, 45, 31, 57, 8, 36, 13, 58, 38, 11, 19 },
+ { 0, 34, 12, 47, 21, 2, 40, 30, 11, 25, 61, 20, 40, 15, 35, 22, 45, 36, 7, 41, 17, 57, 9, 48, 32, 62, 44, 24, 35, 3, 54, 13, 33, 63, 19, 4, 48, 22, 62, 2, 37, 8, 33, 6, 20, 52, 9, 32, 43, 13, 39, 63, 25, 4, 49, 23, 62, 32, 9, 30, 48, 18, 63, 12, 46, 29, 58, 13, 48, 8, 57, 31, 0, 51, 9, 58, 12, 22, 47, 29, 35, 22, 49, 5, 46, 4, 34, 20, 63, 24, 56, 11, 41, 3, 51, 19, 56, 35, 17, 58, 28, 42, 9, 45, 59, 26, 51, 42, 17, 36, 25, 15, 53, 21, 44, 3, 30, 55, 5, 50, 21, 28, 61, 32, 6, 49, 28, 46 },
+ { 58, 42, 60, 4, 31, 59, 22, 63, 35, 38, 9, 54, 1, 57, 8, 51, 16, 58, 27, 53, 3, 38, 30, 15, 27, 6, 19, 56, 10, 50, 21, 36, 47, 5, 43, 28, 51, 32, 13, 46, 18, 54, 16, 43, 63, 12, 36, 59, 22, 34, 5, 52, 17, 59, 27, 41, 0, 19, 55, 37, 13, 43, 6, 34, 41, 10, 36, 55, 19, 44, 3, 16, 58, 27, 49, 25, 32, 62, 17, 55, 13, 63, 18, 52, 25, 37, 17, 48, 13, 32, 5, 46, 28, 37, 14, 43, 25, 5, 51, 39, 3, 52, 33, 22, 8, 40, 12, 4, 57, 9, 46, 39, 28, 58, 13, 62, 17, 42, 19, 36, 0, 47, 16, 43, 24, 21, 54, 13 },
+ { 25, 9, 23, 50, 36, 8, 45, 14, 3, 51, 16, 28, 44, 12, 42, 29, 4, 26, 10, 47, 22, 61, 18, 54, 51, 39, 46, 13, 41, 26, 58, 7, 18, 39, 12, 57, 15, 1, 52, 27, 41, 23, 48, 1, 27, 45, 18, 2, 57, 26, 55, 8, 43, 31, 6, 58, 14, 51, 40, 5, 61, 31, 24, 54, 17, 60, 22, 1, 39, 30, 53, 45, 36, 13, 43, 5, 45, 2, 37, 6, 34, 42, 2, 39, 10, 62, 7, 54, 40, 18, 60, 15, 52, 21, 63, 8, 55, 46, 15, 30, 23, 13, 62, 16, 50, 24, 58, 31, 48, 21, 34, 2, 49, 7, 31, 37, 26, 48, 9, 61, 40, 11, 52, 2, 60, 40, 4, 37 },
+ { 52, 28, 39, 16, 54, 19, 29, 55, 42, 20, 58, 33, 24, 63, 18, 55, 39, 62, 43, 34, 12, 40, 6, 35, 2, 25, 8, 62, 34, 1, 31, 42, 61, 27, 53, 24, 40, 61, 34, 8, 59, 4, 30, 56, 40, 6, 53, 42, 10, 48, 16, 37, 12, 46, 21, 36, 47, 11, 28, 45, 22, 10, 57, 2, 49, 31, 14, 44, 61, 11, 25, 6, 23, 63, 18, 36, 28, 56, 20, 51, 11, 48, 27, 56, 32, 22, 45, 30, 2, 42, 27, 39, 1, 44, 23, 31, 38, 22, 11, 61, 43, 54, 4, 47, 35, 2, 44, 16, 28, 54, 12, 62, 18, 43, 10, 52, 1, 58, 33, 15, 29, 56, 20, 34, 9, 30, 48, 17 },
+ { 46, 2, 56, 11, 41, 1, 49, 6, 27, 47, 2, 48, 5, 32, 37, 3, 13, 19, 32, 1, 55, 28, 60, 17, 43, 59, 32, 20, 49, 16, 55, 23, 14, 46, 2, 36, 6, 30, 20, 49, 12, 47, 35, 14, 21, 60, 29, 14, 35, 24, 46, 1, 56, 29, 53, 8, 33, 23, 56, 1, 35, 46, 20, 39, 26, 4, 53, 28, 17, 38, 60, 34, 48, 9, 55, 15, 46, 7, 41, 31, 60, 24, 16, 36, 1, 59, 19, 52, 35, 6, 55, 11, 59, 33, 7, 57, 4, 29, 48, 1, 19, 26, 37, 30, 18, 63, 37, 6, 59, 1, 40, 24, 56, 33, 46, 22, 35, 7, 24, 53, 39, 5, 26, 45, 55, 18, 62, 7 },
+ { 20, 60, 29, 34, 20, 62, 33, 52, 10, 36, 13, 60, 41, 21, 50, 27, 56, 49, 8, 51, 21, 45, 11, 48, 8, 23, 53, 3, 29, 44, 5, 52, 9, 32, 50, 17, 43, 56, 3, 38, 24, 10, 62, 25, 51, 9, 33, 49, 61, 7, 30, 62, 22, 19, 2, 42, 63, 5, 49, 18, 60, 15, 52, 7, 43, 56, 23, 50, 5, 50, 2, 20, 41, 30, 1, 52, 22, 61, 14, 26, 3, 43, 53, 7, 47, 28, 11, 14, 23, 58, 33, 25, 47, 13, 50, 17, 40, 54, 34, 60, 41, 6, 59, 14, 50, 7, 25, 55, 20, 42, 51, 8, 27, 4, 16, 60, 28, 50, 44, 3, 22, 49, 63, 12, 33, 1, 43, 31 },
+ { 36, 5, 46, 8, 44, 24, 13, 39, 25, 57, 31, 18, 8, 52, 10, 45, 6, 30, 36, 24, 63, 4, 33, 26, 57, 40, 15, 56, 37, 12, 40, 25, 37, 58, 11, 63, 21, 45, 16, 60, 31, 53, 18, 33, 3, 45, 23, 0, 20, 54, 40, 15, 50, 38, 60, 16, 25, 42, 29, 38, 7, 41, 25, 62, 18, 33, 8, 35, 42, 16, 32, 56, 12, 39, 59, 19, 34, 9, 49, 38, 57, 12, 21, 50, 14, 40, 61, 44, 50, 9, 49, 19, 3, 29, 35, 62, 12, 24, 7, 18, 52, 32, 10, 46, 21, 41, 32, 11, 36, 29, 14, 34, 60, 38, 54, 11, 41, 14, 19, 57, 32, 16, 7, 41, 51, 25, 14, 57 },
+ { 53, 18, 26, 50, 15, 58, 4, 63, 17, 43, 7, 40, 61, 35, 15, 41, 23, 60, 16, 38, 14, 42, 19, 50, 0, 31, 10, 46, 27, 63, 18, 60, 0, 20, 29, 39, 8, 26, 37, 5, 42, 0, 44, 39, 57, 17, 58, 41, 28, 37, 4, 32, 9, 44, 12, 31, 54, 10, 59, 14, 27, 53, 12, 36, 0, 47, 13, 63, 21, 58, 10, 24, 50, 27, 4, 26, 44, 53, 31, 0, 18, 42, 29, 33, 57, 4, 32, 26, 0, 38, 16, 61, 41, 53, 20, 0, 42, 44, 49, 27, 10, 56, 39, 0, 57, 15, 53, 49, 3, 61, 22, 47, 17, 5, 49, 26, 2, 63, 39, 10, 47, 27, 37, 23, 4, 59, 38, 10 },
+ { 23, 39, 61, 3, 37, 28, 48, 31, 0, 34, 51, 23, 2, 26, 58, 0, 53, 11, 46, 1, 57, 29, 52, 14, 37, 61, 21, 35, 2, 49, 7, 34, 47, 55, 4, 33, 54, 13, 58, 52, 19, 50, 22, 7, 13, 29, 36, 11, 51, 17, 60, 25, 55, 4, 34, 51, 0, 35, 20, 48, 32, 3, 51, 30, 59, 28, 40, 3, 46, 29, 54, 43, 7, 62, 47, 11, 39, 4, 23, 46, 55, 8, 63, 5, 25, 37, 18, 46, 21, 56, 31, 5, 36, 8, 45, 58, 26, 15, 2, 36, 47, 21, 29, 44, 25, 34, 3, 27, 43, 10, 52, 0, 45, 30, 24, 36, 43, 18, 34, 59, 0, 52, 61, 15, 44, 19, 30, 49 },
+ { 0, 27, 12, 43, 54, 9, 22, 53, 21, 46, 15, 55, 29, 47, 20, 33, 39, 28, 59, 35, 9, 44, 5, 24, 47, 7, 52, 17, 56, 22, 30, 42, 14, 26, 45, 18, 49, 1, 24, 34, 11, 27, 55, 32, 61, 47, 2, 56, 6, 44, 13, 47, 36, 27, 58, 22, 16, 47, 40, 4, 57, 38, 21, 45, 16, 9, 56, 26, 11, 38, 0, 22, 36, 17, 33, 57, 16, 30, 62, 15, 35, 40, 20, 45, 59, 10, 54, 8, 63, 13, 52, 27, 22, 57, 28, 12, 32, 51, 55, 22, 63, 4, 16, 54, 12, 62, 45, 19, 58, 13, 32, 40, 20, 56, 7, 57, 9, 54, 6, 29, 42, 21, 8, 55, 35, 47, 6, 41 },
+ { 56, 33, 58, 32, 19, 35, 42, 6, 59, 11, 38, 5, 49, 12, 62, 7, 52, 17, 5, 25, 54, 20, 61, 31, 54, 27, 41, 11, 44, 5, 59, 12, 36, 51, 10, 61, 28, 41, 48, 9, 43, 63, 5, 40, 20, 8, 49, 26, 34, 21, 58, 1, 18, 45, 7, 39, 61, 26, 8, 50, 23, 10, 63, 5, 55, 37, 19, 49, 52, 15, 59, 47, 13, 54, 1, 25, 42, 58, 10, 48, 3, 27, 50, 1, 17, 48, 34, 41, 16, 40, 2, 45, 10, 39, 17, 61, 5, 38, 19, 9, 41, 31, 60, 38, 5, 23, 36, 8, 30, 55, 24, 63, 12, 48, 14, 51, 31, 20, 45, 25, 12, 50, 32, 2, 28, 11, 62, 14 },
+ { 44, 16, 7, 48, 1, 62, 16, 50, 27, 33, 61, 25, 17, 44, 31, 14, 22, 43, 32, 48, 18, 40, 8, 36, 3, 16, 33, 62, 23, 38, 25, 53, 2, 21, 41, 6, 22, 15, 59, 29, 16, 37, 26, 15, 52, 42, 23, 15, 54, 39, 10, 30, 53, 11, 49, 24, 2, 43, 55, 17, 34, 44, 15, 31, 24, 44, 2, 32, 7, 35, 25, 5, 40, 45, 29, 51, 6, 21, 37, 52, 24, 60, 13, 31, 53, 23, 2, 28, 49, 24, 31, 60, 20, 51, 1, 34, 48, 14, 59, 33, 50, 1, 18, 33, 48, 60, 17, 51, 39, 6, 38, 2, 35, 29, 40, 23, 1, 62, 15, 53, 37, 17, 46, 57, 40, 51, 24, 22 },
+ { 5, 37, 52, 24, 45, 13, 40, 3, 45, 9, 19, 42, 56, 4, 37, 46, 56, 2, 63, 11, 51, 1, 49, 13, 59, 45, 39, 1, 48, 15, 58, 9, 46, 31, 54, 35, 57, 38, 3, 46, 56, 4, 47, 57, 1, 30, 38, 63, 3, 46, 28, 63, 41, 14, 33, 62, 19, 32, 13, 28, 61, 1, 53, 42, 11, 60, 22, 62, 27, 42, 61, 31, 19, 8, 61, 12, 32, 55, 2, 18, 33, 12, 43, 36, 9, 62, 30, 55, 6, 58, 35, 7, 43, 29, 54, 23, 43, 30, 3, 25, 11, 45, 52, 28, 7, 14, 42, 1, 22, 50, 16, 53, 19, 59, 4, 46, 33, 41, 4, 35, 58, 5, 26, 13, 20, 2, 34, 54 },
+ { 30, 63, 21, 10, 26, 55, 29, 59, 23, 39, 53, 1, 36, 24, 59, 27, 10, 34, 23, 38, 30, 60, 22, 42, 28, 19, 9, 57, 30, 19, 43, 33, 13, 63, 3, 19, 11, 50, 31, 20, 14, 34, 10, 35, 17, 59, 7, 31, 19, 25, 50, 5, 20, 57, 29, 6, 52, 41, 4, 46, 20, 37, 26, 17, 49, 6, 39, 18, 53, 14, 3, 49, 57, 23, 34, 48, 14, 41, 28, 38, 56, 6, 58, 25, 39, 19, 43, 15, 37, 11, 47, 18, 53, 4, 37, 9, 62, 21, 53, 40, 57, 24, 13, 40, 56, 26, 47, 31, 59, 25, 45, 27, 10, 43, 21, 61, 13, 27, 48, 9, 23, 43, 31, 62, 38, 59, 9, 47 },
+ { 25, 4, 40, 60, 34, 6, 18, 36, 8, 57, 12, 30, 49, 14, 6, 54, 41, 16, 50, 6, 43, 15, 34, 4, 53, 24, 50, 35, 4, 51, 7, 55, 28, 24, 39, 44, 60, 7, 25, 62, 42, 53, 24, 61, 28, 45, 52, 12, 48, 37, 9, 35, 43, 3, 37, 48, 12, 58, 30, 52, 9, 59, 6, 57, 33, 29, 48, 4, 37, 45, 20, 34, 10, 39, 0, 60, 22, 45, 8, 63, 21, 42, 14, 49, 3, 56, 11, 46, 21, 61, 0, 42, 25, 13, 63, 17, 36, 8, 46, 16, 6, 35, 63, 0, 21, 37, 4, 57, 9, 34, 5, 61, 48, 32, 8, 37, 54, 17, 56, 30, 60, 0, 50, 16, 7, 29, 42, 17 },
+ { 32, 50, 15, 48, 2, 43, 52, 25, 47, 16, 32, 63, 21, 52, 40, 19, 0, 61, 29, 58, 20, 56, 26, 46, 12, 55, 6, 22, 62, 32, 17, 40, 0, 49, 34, 8, 27, 32, 48, 0, 21, 39, 5, 44, 12, 6, 22, 40, 0, 57, 16, 60, 23, 17, 54, 22, 36, 15, 24, 39, 19, 34, 47, 23, 0, 54, 13, 51, 24, 9, 55, 16, 52, 27, 44, 20, 4, 54, 26, 49, 0, 30, 46, 16, 29, 51, 34, 4, 52, 28, 33, 15, 57, 39, 26, 49, 0, 56, 27, 31, 48, 20, 43, 29, 53, 11, 46, 19, 41, 13, 55, 18, 0, 57, 26, 51, 2, 44, 6, 38, 14, 40, 22, 45, 36, 53, 3, 57 },
+ { 44, 12, 37, 28, 22, 57, 11, 38, 0, 51, 9, 41, 4, 29, 11, 47, 33, 45, 12, 26, 3, 36, 9, 63, 31, 16, 38, 44, 14, 47, 25, 61, 20, 58, 15, 47, 17, 57, 13, 36, 9, 51, 18, 29, 50, 36, 54, 20, 61, 27, 32, 13, 53, 44, 9, 27, 0, 63, 45, 2, 56, 10, 14, 43, 41, 28, 58, 11, 35, 60, 30, 41, 6, 63, 11, 51, 37, 32, 15, 10, 35, 53, 5, 61, 22, 7, 26, 59, 23, 9, 44, 48, 21, 3, 51, 32, 24, 41, 12, 61, 2, 55, 9, 15, 35, 58, 28, 15, 62, 30, 37, 23, 42, 29, 11, 17, 35, 24, 63, 20, 52, 28, 8, 55, 11, 23, 47, 19 },
+ { 0, 56, 8, 53, 14, 31, 61, 20, 55, 28, 62, 18, 35, 60, 25, 57, 7, 23, 39, 54, 47, 17, 43, 0, 40, 59, 29, 2, 56, 10, 37, 5, 43, 11, 29, 52, 1, 23, 54, 41, 59, 30, 55, 1, 62, 15, 33, 4, 43, 10, 47, 39, 1, 31, 40, 60, 49, 33, 7, 55, 26, 50, 31, 61, 8, 18, 21, 32, 44, 1, 25, 47, 18, 36, 30, 23, 59, 7, 40, 59, 27, 19, 38, 32, 44, 54, 40, 17, 38, 60, 27, 6, 35, 55, 10, 14, 44, 5, 50, 17, 38, 26, 42, 50, 18, 3, 44, 52, 2, 49, 7, 52, 15, 46, 62, 39, 55, 10, 31, 48, 3, 58, 33, 18, 61, 34, 13, 59 },
+ { 39, 27, 63, 20, 35, 41, 4, 45, 26, 5, 38, 13, 44, 2, 50, 17, 37, 52, 2, 13, 28, 58, 24, 51, 21, 8, 34, 48, 27, 42, 18, 51, 31, 56, 5, 36, 38, 44, 4, 17, 26, 11, 38, 23, 42, 8, 56, 39, 24, 51, 5, 56, 21, 59, 14, 6, 18, 42, 22, 35, 16, 37, 3, 25, 39, 46, 63, 5, 50, 17, 58, 8, 55, 3, 50, 12, 43, 17, 47, 2, 51, 9, 62, 12, 1, 35, 13, 50, 1, 37, 12, 51, 19, 29, 46, 59, 22, 58, 33, 45, 22, 60, 10, 32, 61, 39, 8, 33, 25, 36, 20, 60, 38, 4, 21, 5, 28, 45, 12, 18, 42, 11, 49, 1, 27, 40, 6, 30 },
+ { 24, 16, 42, 1, 50, 10, 48, 17, 33, 43, 24, 48, 21, 55, 31, 42, 10, 21, 63, 35, 49, 6, 33, 13, 41, 53, 10, 20, 60, 6, 53, 26, 12, 41, 22, 60, 14, 28, 63, 33, 49, 3, 45, 16, 48, 26, 14, 46, 18, 30, 35, 26, 8, 50, 29, 51, 25, 57, 12, 47, 53, 9, 62, 20, 54, 2, 36, 15, 40, 28, 33, 13, 38, 24, 46, 1, 29, 56, 33, 20, 44, 24, 41, 26, 57, 20, 63, 8, 30, 55, 5, 41, 62, 8, 34, 2, 37, 10, 19, 6, 37, 1, 53, 23, 5, 27, 58, 22, 43, 12, 50, 26, 9, 34, 54, 32, 49, 1, 59, 37, 22, 46, 25, 36, 51, 15, 54, 46 },
+ { 52, 7, 45, 33, 26, 58, 14, 60, 7, 54, 3, 58, 8, 34, 14, 5, 59, 30, 18, 44, 8, 22, 48, 62, 3, 26, 55, 38, 23, 16, 39, 1, 62, 24, 49, 9, 53, 19, 46, 7, 19, 60, 31, 58, 2, 34, 53, 7, 59, 2, 62, 42, 46, 19, 36, 11, 44, 4, 38, 28, 1, 43, 32, 51, 12, 29, 56, 22, 52, 2, 62, 49, 22, 60, 14, 35, 63, 5, 25, 57, 14, 53, 4, 46, 18, 31, 42, 22, 47, 20, 58, 31, 16, 43, 23, 54, 30, 42, 52, 57, 29, 49, 30, 13, 45, 48, 16, 55, 6, 63, 1, 44, 14, 58, 19, 47, 15, 24, 51, 34, 6, 55, 5, 63, 20, 41, 21, 9 },
+ { 30, 62, 18, 55, 5, 23, 39, 29, 49, 30, 15, 36, 28, 46, 60, 25, 39, 46, 4, 32, 61, 40, 15, 30, 36, 45, 14, 2, 49, 33, 57, 45, 18, 32, 3, 45, 30, 2, 35, 52, 40, 27, 13, 21, 38, 63, 20, 28, 37, 23, 16, 10, 13, 55, 2, 62, 21, 32, 60, 17, 58, 23, 5, 40, 16, 48, 7, 45, 10, 26, 43, 19, 6, 31, 52, 21, 39, 16, 48, 9, 37, 28, 36, 55, 7, 48, 3, 59, 15, 45, 25, 1, 53, 13, 47, 7, 62, 15, 4, 25, 12, 41, 18, 60, 38, 11, 34, 19, 39, 31, 29, 56, 23, 42, 3, 27, 60, 41, 8, 16, 61, 29, 43, 9, 32, 2, 60, 34 },
+ { 3, 38, 13, 37, 52, 44, 2, 19, 12, 42, 63, 19, 40, 1, 20, 50, 12, 55, 15, 56, 27, 1, 54, 11, 57, 18, 32, 63, 44, 4, 29, 13, 37, 61, 35, 16, 42, 57, 12, 22, 6, 55, 43, 10, 50, 5, 44, 11, 48, 52, 34, 58, 28, 41, 38, 30, 7, 52, 11, 49, 30, 14, 45, 27, 59, 34, 21, 38, 32, 58, 11, 36, 56, 42, 9, 41, 3, 54, 31, 42, 0, 60, 16, 11, 39, 24, 52, 33, 6, 36, 10, 40, 32, 60, 26, 20, 39, 28, 47, 34, 63, 8, 54, 3, 24, 56, 0, 51, 13, 47, 16, 40, 7, 35, 52, 11, 36, 4, 57, 30, 39, 13, 18, 50, 58, 28, 12, 48 },
+ { 57, 24, 49, 21, 10, 31, 61, 36, 56, 0, 22, 53, 11, 56, 32, 7, 36, 27, 41, 9, 46, 19, 34, 42, 25, 7, 50, 9, 28, 21, 54, 8, 50, 7, 27, 59, 10, 25, 48, 62, 37, 0, 33, 58, 25, 18, 32, 61, 0, 15, 45, 5, 50, 3, 23, 55, 47, 17, 40, 6, 60, 34, 53, 8, 41, 0, 61, 13, 54, 4, 46, 28, 0, 17, 48, 27, 58, 13, 23, 61, 33, 21, 50, 30, 62, 8, 14, 29, 56, 27, 61, 49, 17, 2, 44, 11, 51, 0, 59, 17, 40, 20, 32, 47, 36, 21, 42, 28, 60, 4, 54, 10, 59, 17, 30, 62, 21, 43, 26, 48, 0, 56, 36, 25, 8, 44, 39, 17 },
+ { 10, 42, 4, 59, 27, 47, 8, 23, 51, 32, 45, 6, 37, 26, 48, 43, 62, 0, 21, 53, 38, 12, 51, 5, 60, 47, 24, 37, 59, 15, 35, 47, 22, 55, 0, 50, 21, 40, 6, 29, 15, 52, 24, 8, 41, 55, 13, 29, 40, 56, 24, 31, 19, 33, 61, 15, 0, 35, 24, 42, 21, 2, 19, 57, 24, 15, 30, 50, 20, 25, 40, 16, 57, 34, 61, 8, 29, 45, 6, 49, 11, 47, 2, 44, 19, 57, 38, 50, 12, 42, 21, 4, 35, 52, 28, 56, 23, 36, 13, 45, 4, 52, 27, 14, 6, 62, 9, 45, 21, 37, 25, 46, 33, 49, 0, 44, 7, 53, 13, 19, 53, 31, 3, 47, 15, 56, 22, 51 },
+ { 35, 28, 53, 32, 1, 16, 54, 40, 9, 17, 25, 58, 14, 59, 3, 22, 16, 51, 31, 5, 23, 58, 28, 17, 35, 20, 0, 42, 11, 52, 3, 31, 41, 17, 43, 13, 32, 54, 18, 60, 32, 45, 17, 49, 2, 36, 51, 22, 7, 36, 9, 63, 48, 12, 46, 26, 43, 28, 63, 13, 48, 37, 51, 33, 5, 47, 55, 9, 42, 63, 7, 51, 24, 12, 37, 19, 55, 34, 18, 38, 15, 28, 54, 34, 5, 43, 22, 0, 48, 14, 54, 24, 58, 9, 38, 5, 32, 55, 21, 30, 49, 9, 59, 43, 30, 51, 35, 26, 7, 53, 2, 22, 14, 27, 57, 18, 38, 24, 33, 45, 10, 41, 20, 60, 37, 5, 32, 0 },
+ { 63, 19, 15, 40, 62, 35, 14, 28, 46, 61, 4, 49, 35, 10, 29, 54, 33, 8, 45, 62, 37, 1, 43, 55, 10, 52, 61, 30, 19, 40, 25, 62, 11, 38, 27, 58, 36, 3, 46, 8, 39, 4, 62, 28, 47, 20, 4, 54, 47, 27, 43, 1, 21, 38, 8, 58, 10, 54, 4, 56, 9, 26, 12, 39, 60, 27, 18, 37, 1, 31, 35, 5, 45, 50, 2, 43, 26, 1, 59, 23, 56, 40, 7, 26, 58, 17, 32, 63, 25, 39, 7, 31, 45, 19, 63, 15, 48, 8, 37, 61, 16, 34, 1, 56, 18, 3, 15, 58, 49, 32, 63, 41, 55, 5, 40, 22, 50, 6, 59, 2, 63, 23, 52, 11, 26, 61, 44, 23 },
+ { 11, 56, 46, 6, 22, 43, 58, 3, 34, 21, 38, 30, 18, 44, 52, 13, 41, 57, 17, 28, 14, 49, 25, 7, 33, 39, 26, 6, 56, 48, 1, 20, 56, 5, 46, 9, 19, 51, 30, 25, 56, 21, 35, 14, 57, 42, 16, 33, 10, 57, 17, 59, 41, 25, 53, 37, 20, 40, 30, 18, 31, 62, 44, 22, 3, 44, 11, 48, 23, 53, 18, 60, 29, 22, 62, 15, 53, 47, 10, 41, 3, 19, 52, 36, 13, 46, 10, 35, 3, 61, 41, 16, 1, 50, 26, 42, 18, 46, 2, 25, 54, 20, 39, 23, 47, 31, 41, 12, 38, 17, 8, 19, 31, 48, 12, 61, 9, 54, 29, 35, 15, 38, 6, 43, 34, 14, 7, 47 },
+ { 39, 2, 33, 26, 53, 8, 18, 50, 41, 12, 53, 1, 63, 24, 19, 39, 2, 24, 47, 10, 60, 38, 19, 63, 48, 4, 15, 45, 32, 14, 60, 36, 29, 53, 23, 63, 34, 12, 61, 1, 43, 11, 53, 30, 1, 26, 60, 45, 23, 39, 3, 29, 12, 50, 4, 16, 51, 3, 45, 36, 50, 1, 16, 54, 35, 14, 57, 30, 58, 9, 46, 14, 41, 10, 32, 38, 4, 30, 21, 51, 32, 63, 25, 1, 60, 27, 53, 18, 51, 22, 28, 55, 34, 12, 40, 3, 60, 29, 57, 41, 6, 44, 11, 53, 8, 61, 24, 57, 1, 28, 44, 59, 36, 3, 34, 25, 41, 31, 16, 44, 22, 47, 28, 58, 1, 49, 54, 29 },
+ { 58, 25, 50, 13, 38, 30, 60, 24, 6, 57, 27, 42, 9, 45, 6, 61, 30, 50, 4, 34, 29, 3, 46, 13, 22, 42, 58, 28, 9, 39, 23, 44, 7, 15, 44, 2, 40, 15, 47, 41, 23, 37, 7, 59, 38, 11, 34, 6, 62, 14, 52, 35, 55, 19, 32, 61, 33, 24, 57, 6, 22, 59, 29, 7, 49, 25, 40, 3, 17, 39, 27, 52, 0, 55, 16, 57, 24, 61, 36, 6, 29, 12, 48, 39, 20, 44, 6, 40, 33, 5, 48, 10, 57, 36, 22, 51, 33, 9, 24, 12, 62, 29, 50, 35, 14, 43, 5, 33, 47, 52, 13, 23, 10, 51, 56, 16, 46, 1, 49, 4, 61, 9, 52, 18, 31, 21, 36, 17 },
+ { 19, 42, 9, 48, 2, 44, 11, 37, 48, 20, 33, 16, 55, 35, 49, 15, 37, 20, 59, 16, 53, 22, 56, 31, 50, 11, 34, 54, 16, 51, 4, 49, 33, 53, 21, 28, 56, 24, 31, 9, 52, 16, 48, 24, 44, 13, 51, 20, 31, 49, 18, 6, 34, 2, 44, 14, 47, 8, 15, 43, 13, 41, 33, 52, 20, 61, 7, 51, 34, 62, 4, 20, 36, 33, 43, 8, 46, 13, 53, 17, 45, 42, 9, 31, 52, 11, 30, 56, 13, 59, 17, 44, 27, 6, 62, 11, 43, 17, 49, 38, 26, 2, 16, 27, 58, 21, 54, 18, 26, 5, 35, 61, 43, 27, 7, 39, 14, 58, 37, 55, 20, 33, 13, 40, 62, 10, 55, 5 },
+ { 51, 14, 61, 29, 59, 20, 55, 31, 0, 49, 11, 60, 3, 26, 22, 56, 0, 40, 12, 43, 41, 8, 36, 0, 17, 57, 24, 2, 46, 26, 61, 18, 0, 38, 12, 59, 6, 49, 3, 57, 19, 63, 5, 33, 18, 54, 28, 56, 0, 43, 26, 46, 63, 27, 56, 22, 27, 54, 38, 28, 63, 24, 10, 45, 0, 31, 42, 21, 12, 25, 44, 49, 59, 6, 26, 50, 3, 34, 27, 59, 0, 35, 62, 16, 4, 58, 47, 0, 43, 24, 37, 2, 54, 20, 46, 31, 0, 56, 34, 5, 55, 45, 60, 37, 0, 40, 10, 38, 63, 46, 15, 20, 0, 53, 21, 62, 30, 11, 24, 27, 40, 0, 57, 26, 3, 45, 27, 35 },
+};
+
+#else
+#define DM_WIDTH 8
+#define DM_WIDTH_SHIFT 3
+#define DM_HEIGHT 8
+static const unsigned char DM[8][8] =
+{
+ { 0, 32, 8, 40, 2, 34, 10, 42 },
+ { 48, 16, 56, 24, 50, 18, 58, 26 },
+ { 12, 44, 4, 36, 14, 46, 6, 38 },
+ { 60, 28, 52, 20, 62, 30, 54, 22 },
+ { 3, 35, 11, 43, 1, 33, 9, 41 },
+ { 51, 19, 59, 27, 49, 17, 57, 25 },
+ { 15, 47, 7, 39, 13, 45, 5, 37 },
+ { 63, 31, 55, 23, 61, 29, 53, 21 }
+};
+#endif
+
+static unsigned int *DM_565 = NULL;
+
+static void
+xlib_rgb_preprocess_dm_565 (void)
+{
+ int i;
+ unsigned int dith;
+
+ if (DM_565 == NULL)
+ {
+ DM_565 = malloc(sizeof(unsigned int) * DM_WIDTH * DM_HEIGHT);
+ for (i = 0; i < DM_WIDTH * DM_HEIGHT; i++)
+ {
+ dith = DM[0][i] >> 3;
+ DM_565[i] = (dith << 20) | dith | (((7 - dith) >> 1) << 10);
+#ifdef VERBOSE
+ printf ("%i %x %x\n", i, dith, DM_565[i]);
+#endif
+ }
+ }
+}
+
+static void
+xlib_rgb_convert_8_d666 (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ int x, y;
+ int bpl;
+ unsigned char *obuf, *obptr;
+ unsigned char *bptr, *bp2;
+ int r, g, b;
+ const unsigned char *dmp;
+ int dith;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax;
+ for (y = 0; y < height; y++)
+ {
+ dmp = DM[(y_align + y) & (DM_HEIGHT - 1)];
+ bp2 = bptr;
+ obptr = obuf;
+ for (x = 0; x < width; x++)
+ {
+ r = *bp2++;
+ g = *bp2++;
+ b = *bp2++;
+ dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) | 7;
+ r = ((r * 5) + dith) >> 8;
+ g = ((g * 5) + (262 - dith)) >> 8;
+ b = ((b * 5) + dith) >> 8;
+ obptr[0] = colorcube_d[(r << 6) | (g << 3) | b];
+ obptr++;
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+
+static void
+xlib_rgb_convert_8_d (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align,
+ XlibRgbCmap *cmap)
+{
+ int x, y;
+ int bpl;
+ unsigned char *obuf, *obptr;
+ unsigned char *bptr, *bp2;
+ int r, g, b;
+ const unsigned char *dmp;
+ int dith;
+ int rs, gs, bs;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ rs = image_info->nred_shades - 1;
+ gs = image_info->ngreen_shades - 1;
+ bs = image_info->nblue_shades - 1;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax;
+ for (y = 0; y < height; y++)
+ {
+ dmp = DM[(y_align + y) & (DM_HEIGHT - 1)];
+ bp2 = bptr;
+ obptr = obuf;
+ for (x = 0; x < width; x++)
+ {
+ r = *bp2++;
+ g = *bp2++;
+ b = *bp2++;
+ dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) | 7;
+ r = ((r * rs) + dith) >> 8;
+ g = ((g * gs) + (262 - dith)) >> 8;
+ b = ((b * bs) + dith) >> 8;
+ obptr[0] = colorcube_d[(r << 6) | (g << 3) | b];
+ obptr++;
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+
+static void
+xlib_rgb_convert_8_indexed (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ int x, y;
+ int bpl;
+ unsigned char *obuf, *obptr;
+ unsigned char *bptr, *bp2;
+ unsigned char c;
+ unsigned char *lut;
+
+ lut = cmap->lut;
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax;
+ for (y = 0; y < height; y++)
+ {
+ bp2 = bptr;
+ obptr = obuf;
+ for (x = 0; x < width; x++)
+ {
+ c = *bp2++;
+ obptr[0] = lut[c];
+ obptr++;
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+
+static void
+xlib_rgb_convert_gray8 (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ int x, y;
+ int bpl;
+ unsigned char *obuf, *obptr;
+ unsigned char *bptr, *bp2;
+ int r, g, b;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax;
+ for (y = 0; y < height; y++)
+ {
+ bp2 = bptr;
+ obptr = obuf;
+ for (x = 0; x < width; x++)
+ {
+ r = *bp2++;
+ g = *bp2++;
+ b = *bp2++;
+ obptr[0] = (g + ((b + r) >> 1)) >> 1;
+ obptr++;
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+
+static void
+xlib_rgb_convert_gray8_gray (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ int y;
+ int bpl;
+ unsigned char *obuf;
+ unsigned char *bptr;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax;
+ for (y = 0; y < height; y++)
+ {
+ memcpy (obuf, bptr, (unsigned int)width);
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+
+#if X_BYTE_ORDER == X_LITTLE_ENDIAN
+#define HAIRY_CONVERT_565
+#endif
+
+#ifdef HAIRY_CONVERT_565
+/* Render a 24-bit RGB image in buf into the GdkImage, without dithering.
+ This assumes native byte ordering - what should really be done is to
+ check whether static_image->byte_order is consistent with the _ENDIAN
+ config flag, and if not, use a different function.
+
+ This one is even faster than the one below - its inner loop loads 3
+ words (i.e. 4 24-bit pixels), does a lot of shifting and masking,
+ then writes 2 words. */
+static void
+xlib_rgb_convert_565 (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ int x, y;
+ unsigned char *obuf, *obptr;
+ int bpl;
+ unsigned char *bptr, *bp2;
+ unsigned char r, g, b;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax * 2;
+ for (y = 0; y < height; y++)
+ {
+ bp2 = bptr;
+ obptr = obuf;
+ if (((unsigned long)obuf | (unsigned long) bp2) & 3)
+ {
+ for (x = 0; x < width; x++)
+ {
+ r = *bp2++;
+ g = *bp2++;
+ b = *bp2++;
+ ((unsigned short *)obptr)[0] = ((r & 0xf8) << 8) |
+ ((g & 0xfc) << 3) |
+ (b >> 3);
+ obptr += 2;
+ }
+ }
+ else
+ {
+ for (x = 0; x < width - 3; x += 4)
+ {
+ unsigned int r1b0g0r0;
+ unsigned int g2r2b1g1;
+ unsigned int b3g3r3b2;
+
+ r1b0g0r0 = ((unsigned int *)bp2)[0];
+ g2r2b1g1 = ((unsigned int *)bp2)[1];
+ b3g3r3b2 = ((unsigned int *)bp2)[2];
+ ((unsigned int *)obptr)[0] =
+ ((r1b0g0r0 & 0xf8) << 8) |
+ ((r1b0g0r0 & 0xfc00) >> 5) |
+ ((r1b0g0r0 & 0xf80000) >> 19) |
+ (r1b0g0r0 & 0xf8000000) |
+ ((g2r2b1g1 & 0xfc) << 19) |
+ ((g2r2b1g1 & 0xf800) << 5);
+ ((unsigned int *)obptr)[1] =
+ ((g2r2b1g1 & 0xf80000) >> 8) |
+ ((g2r2b1g1 & 0xfc000000) >> 21) |
+ ((b3g3r3b2 & 0xf8) >> 3) |
+ ((b3g3r3b2 & 0xf800) << 16) |
+ ((b3g3r3b2 & 0xfc0000) << 3) |
+ ((b3g3r3b2 & 0xf8000000) >> 11);
+ bp2 += 12;
+ obptr += 8;
+ }
+ for (; x < width; x++)
+ {
+ r = *bp2++;
+ g = *bp2++;
+ b = *bp2++;
+ ((unsigned short *)obptr)[0] = ((r & 0xf8) << 8) |
+ ((g & 0xfc) << 3) |
+ (b >> 3);
+ obptr += 2;
+ }
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+#else
+/* Render a 24-bit RGB image in buf into the GdkImage, without dithering.
+ This assumes native byte ordering - what should really be done is to
+ check whether static_image->byte_order is consistent with the _ENDIAN
+ config flag, and if not, use a different function.
+
+ This routine is faster than the one included with Gtk 1.0 for a number
+ of reasons:
+
+ 1. Shifting instead of lookup tables (less memory traffic).
+
+ 2. Much less register pressure, especially because shifts are
+ in the code.
+
+ 3. A memcpy is avoided (i.e. the transfer function).
+
+ 4. On big-endian architectures, byte swapping is avoided.
+
+ That said, it wouldn't be hard to make it even faster - just make an
+ inner loop that reads 3 words (i.e. 4 24-bit pixels), does a lot of
+ shifting and masking, then writes 2 words.
+*/
+static void
+xlib_rgb_convert_565 (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ int x, y;
+ unsigned char *obuf;
+ int bpl;
+ unsigned char *bptr, *bp2;
+ unsigned char r, g, b;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax * 2;
+ for (y = 0; y < height; y++)
+ {
+ bp2 = bptr;
+ for (x = 0; x < width; x++)
+ {
+ r = *bp2++;
+ g = *bp2++;
+ b = *bp2++;
+ ((unsigned short *)obuf)[x] = ((r & 0xf8) << 8) |
+ ((g & 0xfc) << 3) |
+ (b >> 3);
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+#endif
+
+#ifdef HAIRY_CONVERT_565
+static void
+xlib_rgb_convert_565_gray (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ int x, y;
+ unsigned char *obuf, *obptr;
+ int bpl;
+ unsigned char *bptr, *bp2;
+ unsigned char g;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax * 2;
+ for (y = 0; y < height; y++)
+ {
+ bp2 = bptr;
+ obptr = obuf;
+ if (((unsigned long)obuf | (unsigned long) bp2) & 3)
+ {
+ for (x = 0; x < width; x++)
+ {
+ g = *bp2++;
+ ((unsigned short *)obptr)[0] = ((g & 0xf8) << 8) |
+ ((g & 0xfc) << 3) |
+ (g >> 3);
+ obptr += 2;
+ }
+ }
+ else
+ {
+ for (x = 0; x < width - 3; x += 4)
+ {
+ unsigned int g3g2g1g0;
+
+ g3g2g1g0 = ((unsigned int *)bp2)[0];
+ ((unsigned int *)obptr)[0] =
+ ((g3g2g1g0 & 0xf8) << 8) |
+ ((g3g2g1g0 & 0xfc) << 3) |
+ ((g3g2g1g0 & 0xf8) >> 3) |
+ (g3g2g1g0 & 0xf800) << 16 |
+ ((g3g2g1g0 & 0xfc00) << 11) |
+ ((g3g2g1g0 & 0xf800) << 5);
+ ((unsigned int *)obptr)[1] =
+ ((g3g2g1g0 & 0xf80000) >> 8) |
+ ((g3g2g1g0 & 0xfc0000) >> 13) |
+ ((g3g2g1g0 & 0xf80000) >> 19) |
+ (g3g2g1g0 & 0xf8000000) |
+ ((g3g2g1g0 & 0xfc000000) >> 5) |
+ ((g3g2g1g0 & 0xf8000000) >> 11);
+ bp2 += 4;
+ obptr += 8;
+ }
+ for (; x < width; x++)
+ {
+ g = *bp2++;
+ ((unsigned short *)obptr)[0] = ((g & 0xf8) << 8) |
+ ((g & 0xfc) << 3) |
+ (g >> 3);
+ obptr += 2;
+ }
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+#else
+static void
+xlib_rgb_convert_565_gray (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ int x, y;
+ unsigned char *obuf;
+ int bpl;
+ unsigned char *bptr, *bp2;
+ unsigned char g;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax * 2;
+ for (y = 0; y < height; y++)
+ {
+ bp2 = bptr;
+ for (x = 0; x < width; x++)
+ {
+ g = *bp2++;
+ ((unsigned short *)obuf)[x] = ((g & 0xf8) << 8) |
+ ((g & 0xfc) << 3) |
+ (g >> 3);
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+#endif
+
+static void
+xlib_rgb_convert_565_br (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ int x, y;
+ unsigned char *obuf;
+ int bpl;
+ unsigned char *bptr, *bp2;
+ unsigned char r, g, b;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax * 2;
+ for (y = 0; y < height; y++)
+ {
+ bp2 = bptr;
+ for (x = 0; x < width; x++)
+ {
+ r = *bp2++;
+ g = *bp2++;
+ b = *bp2++;
+ /* final word is:
+ g4 g3 g2 b7 b6 b5 b4 b3 r7 r6 r5 r4 r3 g7 g6 g5
+ */
+ ((unsigned short *)obuf)[x] = (r & 0xf8) |
+ ((g & 0xe0) >> 5) |
+ ((g & 0x1c) << 11) |
+ ((b & 0xf8) << 5);
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+
+/* Thanks to Ray Lehtiniemi for a patch that resulted in a ~25% speedup
+ in this mode. */
+#ifdef HAIRY_CONVERT_565
+static void
+xlib_rgb_convert_565_d (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ /* Now this is what I'd call some highly tuned code! */
+ int x, y;
+ unsigned char *obuf, *obptr;
+ int bpl;
+ unsigned char *bptr, *bp2;
+
+ width += x_align;
+ height += y_align;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax * 2;
+ for (y = y_align; y < height; y++)
+ {
+ unsigned int *dmp = DM_565 + ((y & (DM_HEIGHT - 1)) << DM_WIDTH_SHIFT);
+ bp2 = bptr;
+ obptr = obuf;
+ if (((unsigned long)obuf | (unsigned long) bp2) & 3)
+ {
+ for (x = x_align; x < width; x++)
+ {
+ int rgb = *bp2++ << 20;
+ rgb += *bp2++ << 10;
+ rgb += *bp2++;
+ rgb += dmp[x & (DM_WIDTH - 1)];
+ rgb += 0x10040100
+ - ((rgb & 0x1e0001e0) >> 5)
+ - ((rgb & 0x00070000) >> 6);
+
+ ((unsigned short *)obptr)[0] =
+ ((rgb & 0x0f800000) >> 12) |
+ ((rgb & 0x0003f000) >> 7) |
+ ((rgb & 0x000000f8) >> 3);
+ obptr += 2;
+ }
+ }
+ else
+ {
+ for (x = x_align; x < width - 3; x += 4)
+ {
+ unsigned int r1b0g0r0;
+ unsigned int g2r2b1g1;
+ unsigned int b3g3r3b2;
+ unsigned int rgb02, rgb13;
+
+ r1b0g0r0 = ((unsigned int *)bp2)[0];
+ g2r2b1g1 = ((unsigned int *)bp2)[1];
+ b3g3r3b2 = ((unsigned int *)bp2)[2];
+ rgb02 =
+ ((r1b0g0r0 & 0xff) << 20) +
+ ((r1b0g0r0 & 0xff00) << 2) +
+ ((r1b0g0r0 & 0xff0000) >> 16) +
+ dmp[x & (DM_WIDTH - 1)];
+ rgb02 += 0x10040100
+ - ((rgb02 & 0x1e0001e0) >> 5)
+ - ((rgb02 & 0x00070000) >> 6);
+ rgb13 =
+ ((r1b0g0r0 & 0xff000000) >> 4) +
+ ((g2r2b1g1 & 0xff) << 10) +
+ ((g2r2b1g1 & 0xff00) >> 8) +
+ dmp[(x + 1) & (DM_WIDTH - 1)];
+ rgb13 += 0x10040100
+ - ((rgb13 & 0x1e0001e0) >> 5)
+ - ((rgb13 & 0x00070000) >> 6);
+ ((unsigned int *)obptr)[0] =
+ ((rgb02 & 0x0f800000) >> 12) |
+ ((rgb02 & 0x0003f000) >> 7) |
+ ((rgb02 & 0x000000f8) >> 3) |
+ ((rgb13 & 0x0f800000) << 4) |
+ ((rgb13 & 0x0003f000) << 9) |
+ ((rgb13 & 0x000000f8) << 13);
+ rgb02 =
+ ((g2r2b1g1 & 0xff0000) << 4) +
+ ((g2r2b1g1 & 0xff000000) >> 14) +
+ (b3g3r3b2 & 0xff) +
+ dmp[(x + 2) & (DM_WIDTH - 1)];
+ rgb02 += 0x10040100
+ - ((rgb02 & 0x1e0001e0) >> 5)
+ - ((rgb02 & 0x00070000) >> 6);
+ rgb13 =
+ ((b3g3r3b2 & 0xff00) << 12) +
+ ((b3g3r3b2 & 0xff0000) >> 6) +
+ ((b3g3r3b2 & 0xff000000) >> 24) +
+ dmp[(x + 3) & (DM_WIDTH - 1)];
+ rgb13 += 0x10040100
+ - ((rgb13 & 0x1e0001e0) >> 5)
+ - ((rgb13 & 0x00070000) >> 6);
+ ((unsigned int *)obptr)[1] =
+ ((rgb02 & 0x0f800000) >> 12) |
+ ((rgb02 & 0x0003f000) >> 7) |
+ ((rgb02 & 0x000000f8) >> 3) |
+ ((rgb13 & 0x0f800000) << 4) |
+ ((rgb13 & 0x0003f000) << 9) |
+ ((rgb13 & 0x000000f8) << 13);
+ bp2 += 12;
+ obptr += 8;
+ }
+ for (; x < width; x++)
+ {
+ int rgb = *bp2++ << 20;
+ rgb += *bp2++ << 10;
+ rgb += *bp2++;
+ rgb += dmp[x & (DM_WIDTH - 1)];
+ rgb += 0x10040100
+ - ((rgb & 0x1e0001e0) >> 5)
+ - ((rgb & 0x00070000) >> 6);
+
+ ((unsigned short *)obptr)[0] =
+ ((rgb & 0x0f800000) >> 12) |
+ ((rgb & 0x0003f000) >> 7) |
+ ((rgb & 0x000000f8) >> 3);
+ obptr += 2;
+ }
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+#else
+static void
+xlib_rgb_convert_565_d (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ int x, y;
+ unsigned char *obuf;
+ int bpl;
+ unsigned char *bptr;
+
+ width += x_align;
+ height += y_align;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + (ax - x_align) * 2;
+
+ for (y = y_align; y < height; y++)
+ {
+ unsigned int *dmp = DM_565 + ((y & (DM_HEIGHT - 1)) << DM_WIDTH_SHIFT);
+ unsigned char *bp2 = bptr;
+
+ for (x = x_align; x < width; x++)
+ {
+ int rgb = *bp2++ << 20;
+ rgb += *bp2++ << 10;
+ rgb += *bp2++;
+ rgb += dmp[x & (DM_WIDTH - 1)];
+ rgb += 0x10040100
+ - ((rgb & 0x1e0001e0) >> 5)
+ - ((rgb & 0x00070000) >> 6);
+
+ ((unsigned short *)obuf)[x] =
+ ((rgb & 0x0f800000) >> 12) |
+ ((rgb & 0x0003f000) >> 7) |
+ ((rgb & 0x000000f8) >> 3);
+ }
+
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+#endif
+
+static void
+xlib_rgb_convert_555 (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ int x, y;
+ unsigned char *obuf;
+ int bpl;
+ unsigned char *bptr, *bp2;
+ unsigned char r, g, b;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax * 2;
+ for (y = 0; y < height; y++)
+ {
+ bp2 = bptr;
+ for (x = 0; x < width; x++)
+ {
+ r = *bp2++;
+ g = *bp2++;
+ b = *bp2++;
+ ((unsigned short *)obuf)[x] = ((r & 0xf8) << 7) |
+ ((g & 0xf8) << 2) |
+ (b >> 3);
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+
+static void
+xlib_rgb_convert_555_br (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ int x, y;
+ unsigned char *obuf;
+ int bpl;
+ unsigned char *bptr, *bp2;
+ unsigned char r, g, b;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax * 2;
+ for (y = 0; y < height; y++)
+ {
+ bp2 = bptr;
+ for (x = 0; x < width; x++)
+ {
+ r = *bp2++;
+ g = *bp2++;
+ b = *bp2++;
+ /* final word is:
+ g5 g4 g3 b7 b6 b5 b4 b3 0 r7 r6 r5 r4 r3 g7 g6
+ */
+ ((unsigned short *)obuf)[x] = ((r & 0xf8) >> 1) |
+ ((g & 0xc0) >> 6) |
+ ((g & 0x18) << 10) |
+ ((b & 0xf8) << 5);
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+
+static void
+xlib_rgb_convert_888_msb (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ int y;
+ unsigned char *obuf;
+ int bpl;
+ unsigned char *bptr;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax * 3;
+ for (y = 0; y < height; y++)
+ {
+ memcpy (obuf, bptr, (unsigned int)(width + width + width));
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+
+/* todo: optimize this */
+#if X_BYTE_ORDER == X_LITTLE_ENDIAN
+#define HAIRY_CONVERT_888
+#endif
+
+#ifdef HAIRY_CONVERT_888
+static void
+xlib_rgb_convert_888_lsb (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ int x, y;
+ unsigned char *obuf, *obptr;
+ int bpl;
+ unsigned char *bptr, *bp2;
+ int r, g, b;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax * 3;
+ for (y = 0; y < height; y++)
+ {
+ bp2 = bptr;
+ obptr = obuf;
+ if (((unsigned long)obuf | (unsigned long) bp2) & 3)
+ {
+ for (x = 0; x < width; x++)
+ {
+ r = bp2[0];
+ g = bp2[1];
+ b = bp2[2];
+ *obptr++ = b;
+ *obptr++ = g;
+ *obptr++ = r;
+ bp2 += 3;
+ }
+ }
+ else
+ {
+ for (x = 0; x < width - 3; x += 4)
+ {
+ unsigned int r1b0g0r0;
+ unsigned int g2r2b1g1;
+ unsigned int b3g3r3b2;
+
+ r1b0g0r0 = ((unsigned int *)bp2)[0];
+ g2r2b1g1 = ((unsigned int *)bp2)[1];
+ b3g3r3b2 = ((unsigned int *)bp2)[2];
+ ((unsigned int *)obptr)[0] =
+ (r1b0g0r0 & 0xff00) |
+ ((r1b0g0r0 & 0xff0000) >> 16) |
+ (((g2r2b1g1 & 0xff00) | (r1b0g0r0 & 0xff)) << 16);
+ ((unsigned int *)obptr)[1] =
+ (g2r2b1g1 & 0xff0000ff) |
+ ((r1b0g0r0 & 0xff000000) >> 16) |
+ ((b3g3r3b2 & 0xff) << 16);
+ ((unsigned int *)obptr)[2] =
+ (((g2r2b1g1 & 0xff0000) | (b3g3r3b2 & 0xff000000)) >> 16) |
+ ((b3g3r3b2 & 0xff00) << 16) |
+ ((b3g3r3b2 & 0xff0000));
+ bp2 += 12;
+ obptr += 12;
+ }
+ for (; x < width; x++)
+ {
+ r = bp2[0];
+ g = bp2[1];
+ b = bp2[2];
+ *obptr++ = b;
+ *obptr++ = g;
+ *obptr++ = r;
+ bp2 += 3;
+ }
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+#else
+static void
+xlib_rgb_convert_888_lsb (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ int x, y;
+ unsigned char *obuf;
+ int bpl;
+ unsigned char *bptr, *bp2;
+ int r, g, b;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax * 3;
+ for (y = 0; y < height; y++)
+ {
+ bp2 = bptr;
+ for (x = 0; x < width; x++)
+ {
+ r = bp2[0];
+ g = bp2[1];
+ b = bp2[2];
+ obuf[x * 3] = b;
+ obuf[x * 3 + 1] = g;
+ obuf[x * 3 + 2] = r;
+ bp2 += 3;
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+#endif
+
+/* convert 24-bit packed to 32-bit unpacked */
+/* todo: optimize this */
+static void
+xlib_rgb_convert_0888 (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ int x, y;
+ unsigned char *obuf;
+ int bpl;
+ unsigned char *bptr, *bp2;
+ int r, g, b;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax * 4;
+ for (y = 0; y < height; y++)
+ {
+ bp2 = bptr;
+ for (x = 0; x < width; x++)
+ {
+ r = bp2[0];
+ g = bp2[1];
+ b = bp2[2];
+ ((unsigned int *)obuf)[x] = (r << 16) | (g << 8) | b;
+ bp2 += 3;
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+
+static void
+xlib_rgb_convert_0888_br (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ int x, y;
+ unsigned char *obuf;
+ int bpl;
+ unsigned char *bptr, *bp2;
+ int r, g, b;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax * 4;
+ for (y = 0; y < height; y++)
+ {
+ bp2 = bptr;
+ for (x = 0; x < width; x++)
+ {
+ r = bp2[0];
+ g = bp2[1];
+ b = bp2[2];
+ ((unsigned int *)obuf)[x] = (b << 24) | (g << 16) | (r << 8);
+ bp2 += 3;
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+
+static void
+xlib_rgb_convert_8880_br (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ int x, y;
+ unsigned char *obuf;
+ int bpl;
+ unsigned char *bptr, *bp2;
+ int r, g, b;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax * 4;
+ for (y = 0; y < height; y++)
+ {
+ bp2 = bptr;
+ for (x = 0; x < width; x++)
+ {
+ r = bp2[0];
+ g = bp2[1];
+ b = bp2[2];
+ ((unsigned int *)obuf)[x] = (b << 16) | (g << 8) | r;
+ bp2 += 3;
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+
+/* Generic truecolor/directcolor conversion function. Slow, but these
+ are oddball modes. */
+static void
+xlib_rgb_convert_truecolor_lsb (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align,
+ XlibRgbCmap *cmap)
+{
+ int x, y;
+ unsigned char *obuf, *obptr;
+ int bpl;
+ unsigned char *bptr, *bp2;
+ int r, g, b;
+ int r_right, r_left;
+ int g_right, g_left;
+ int b_right, b_left;
+ int bpp;
+ unsigned int pixel;
+ int i;
+
+ r_right = 8 - image_info->red_prec;
+ r_left = image_info->red_shift;
+ g_right = 8 - image_info->green_prec;
+ g_left = image_info->green_shift;
+ b_right = 8 - image_info->blue_prec;
+ b_left = image_info->blue_shift;
+ bpp = image_info->bpp;
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax * bpp;
+ for (y = 0; y < height; y++)
+ {
+ obptr = obuf;
+ bp2 = bptr;
+ for (x = 0; x < width; x++)
+ {
+ r = bp2[0];
+ g = bp2[1];
+ b = bp2[2];
+ pixel = ((r >> r_right) << r_left) |
+ ((g >> g_right) << g_left) |
+ ((b >> b_right) << b_left);
+ for (i = 0; i < bpp; i++)
+ {
+ *obptr++ = pixel & 0xff;
+ pixel >>= 8;
+ }
+ bp2 += 3;
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+
+static void
+xlib_rgb_convert_truecolor_lsb_d (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align,
+ XlibRgbCmap *cmap)
+{
+ int x, y;
+ unsigned char *obuf, *obptr;
+ int bpl;
+ unsigned char *bptr, *bp2;
+ int r, g, b;
+ int r_right, r_left, r_prec;
+ int g_right, g_left, g_prec;
+ int b_right, b_left, b_prec;
+ int bpp;
+ unsigned int pixel;
+ int i;
+ int dith;
+ int r1, g1, b1;
+ const unsigned char *dmp;
+
+ r_right = 8 - image_info->red_prec;
+ r_left = image_info->red_shift;
+ r_prec = image_info->red_prec;
+ g_right = 8 - image_info->green_prec;
+ g_left = image_info->green_shift;
+ g_prec = image_info->green_prec;
+ b_right = 8 - image_info->blue_prec;
+ b_left = image_info->blue_shift;
+ b_prec = image_info->blue_prec;
+ bpp = image_info->bpp;
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax * bpp;
+ for (y = 0; y < height; y++)
+ {
+ dmp = DM[(y_align + y) & (DM_HEIGHT - 1)];
+ obptr = obuf;
+ bp2 = bptr;
+ for (x = 0; x < width; x++)
+ {
+ r = bp2[0];
+ g = bp2[1];
+ b = bp2[2];
+ dith = dmp[(x_align + x) & (DM_WIDTH - 1)] << 2;
+ r1 = r + (dith >> r_prec);
+ g1 = g + ((252 - dith) >> g_prec);
+ b1 = b + (dith >> b_prec);
+ pixel = (((r1 - (r1 >> r_prec)) >> r_right) << r_left) |
+ (((g1 - (g1 >> g_prec)) >> g_right) << g_left) |
+ (((b1 - (b1 >> b_prec)) >> b_right) << b_left);
+ for (i = 0; i < bpp; i++)
+ {
+ *obptr++ = pixel & 0xff;
+ pixel >>= 8;
+ }
+ bp2 += 3;
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+
+static void
+xlib_rgb_convert_truecolor_msb (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align,
+ XlibRgbCmap *cmap)
+{
+ int x, y;
+ unsigned char *obuf, *obptr;
+ int bpl;
+ unsigned char *bptr, *bp2;
+ int r, g, b;
+ int r_right, r_left;
+ int g_right, g_left;
+ int b_right, b_left;
+ int bpp;
+ unsigned int pixel;
+ int shift, shift_init;
+
+ r_right = 8 - image_info->red_prec;
+ r_left = image_info->red_shift;
+ g_right = 8 - image_info->green_prec;
+ g_left = image_info->green_shift;
+ b_right = 8 - image_info->blue_prec;
+ b_left = image_info->blue_shift;
+ bpp = image_info->bpp;
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax * bpp;
+ shift_init = (bpp - 1) << 3;
+ for (y = 0; y < height; y++)
+ {
+ obptr = obuf;
+ bp2 = bptr;
+ for (x = 0; x < width; x++)
+ {
+ r = bp2[0];
+ g = bp2[1];
+ b = bp2[2];
+ pixel = ((r >> r_right) << r_left) |
+ ((g >> g_right) << g_left) |
+ ((b >> b_right) << b_left);
+ for (shift = shift_init; shift >= 0; shift -= 8)
+ {
+ *obptr++ = (pixel >> shift) & 0xff;
+ }
+ bp2 += 3;
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+
+static void
+xlib_rgb_convert_truecolor_msb_d (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align,
+ XlibRgbCmap *cmap)
+{
+ int x, y;
+ unsigned char *obuf, *obptr;
+ int bpl;
+ unsigned char *bptr, *bp2;
+ int r, g, b;
+ int r_right, r_left, r_prec;
+ int g_right, g_left, g_prec;
+ int b_right, b_left, b_prec;
+ int bpp;
+ unsigned int pixel;
+ int shift, shift_init;
+ int dith;
+ int r1, g1, b1;
+ const unsigned char *dmp;
+
+ r_right = 8 - image_info->red_prec;
+ r_left = image_info->red_shift;
+ r_prec = image_info->red_prec;
+ g_right = 8 - image_info->green_prec;
+ g_left = image_info->green_shift;
+ g_prec = image_info->green_prec;
+ b_right = 8 - image_info->blue_prec;
+ b_left = image_info->blue_shift;
+ b_prec = image_info->blue_prec;
+ bpp = image_info->bpp;
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax * bpp;
+ shift_init = (bpp - 1) << 3;
+ for (y = 0; y < height; y++)
+ {
+ dmp = DM[(y_align + y) & (DM_HEIGHT - 1)];
+ obptr = obuf;
+ bp2 = bptr;
+ for (x = 0; x < width; x++)
+ {
+ r = bp2[0];
+ g = bp2[1];
+ b = bp2[2];
+ dith = dmp[(x_align + x) & (DM_WIDTH - 1)] << 2;
+ r1 = r + (dith >> r_prec);
+ g1 = g + ((252 - dith) >> g_prec);
+ b1 = b + (dith >> b_prec);
+ pixel = (((r1 - (r1 >> r_prec)) >> r_right) << r_left) |
+ (((g1 - (g1 >> g_prec)) >> g_right) << g_left) |
+ (((b1 - (b1 >> b_prec)) >> b_right) << b_left);
+ for (shift = shift_init; shift >= 0; shift -= 8)
+ {
+ *obptr++ = (pixel >> shift) & 0xff;
+ }
+ bp2 += 3;
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+
+/* This actually works for depths from 3 to 7 */
+static void
+xlib_rgb_convert_4 (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align,
+ XlibRgbCmap *cmap)
+{
+ int x, y;
+ int bpl;
+ unsigned char *obuf, *obptr;
+ unsigned char *bptr, *bp2;
+ int r, g, b;
+ const unsigned char *dmp;
+ int dith;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax;
+ for (y = 0; y < height; y++)
+ {
+ dmp = DM[(y_align + y) & (DM_HEIGHT - 1)];
+ bp2 = bptr;
+ obptr = obuf;
+ for (x = 0; x < width; x += 1)
+ {
+ r = *bp2++;
+ g = *bp2++;
+ b = *bp2++;
+ dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) | 3;
+ obptr[0] = colorcube_d[(((r + dith) & 0x100) >> 2) |
+ (((g + 258 - dith) & 0x100) >> 5) |
+ (((b + dith) & 0x100) >> 8)];
+ obptr++;
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+
+/* This actually works for depths from 3 to 7 */
+static void
+xlib_rgb_convert_gray4 (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ int x, y;
+ int bpl;
+ unsigned char *obuf, *obptr;
+ unsigned char *bptr, *bp2;
+ int r, g, b;
+ int shift;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax;
+ shift = 9 - image_info->x_visual_info->depth;
+ for (y = 0; y < height; y++)
+ {
+ bp2 = bptr;
+ obptr = obuf;
+ for (x = 0; x < width; x++)
+ {
+ r = *bp2++;
+ g = *bp2++;
+ b = *bp2++;
+ obptr[0] = (g + ((b + r) >> 1)) >> shift;
+ obptr++;
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+
+static void
+xlib_rgb_convert_gray4_pack (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ int x, y;
+ int bpl;
+ unsigned char *obuf, *obptr;
+ unsigned char *bptr, *bp2;
+ int r, g, b;
+ int shift;
+ unsigned char pix0, pix1;
+ /* todo: this is hardcoded to big-endian. Make endian-agile. */
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + (ax >> 1);
+ shift = 9 - image_info->x_visual_info->depth;
+ for (y = 0; y < height; y++)
+ {
+ bp2 = bptr;
+ obptr = obuf;
+ for (x = 0; x < width; x += 2)
+ {
+ r = *bp2++;
+ g = *bp2++;
+ b = *bp2++;
+ pix0 = (g + ((b + r) >> 1)) >> shift;
+ r = *bp2++;
+ g = *bp2++;
+ b = *bp2++;
+ pix1 = (g + ((b + r) >> 1)) >> shift;
+ obptr[0] = (pix0 << 4) | pix1;
+ obptr++;
+ }
+ if (width & 1)
+ {
+ r = *bp2++;
+ g = *bp2++;
+ b = *bp2++;
+ pix0 = (g + ((b + r) >> 1)) >> shift;
+ obptr[0] = (pix0 << 4);
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+
+/* This actually works for depths from 3 to 7 */
+static void
+xlib_rgb_convert_gray4_d (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ int x, y;
+ int bpl;
+ unsigned char *obuf, *obptr;
+ unsigned char *bptr, *bp2;
+ int r, g, b;
+ const unsigned char *dmp;
+ int prec, right;
+ int gray;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + ax;
+ prec = image_info->x_visual_info->depth;
+ right = 8 - prec;
+ for (y = 0; y < height; y++)
+ {
+ bp2 = bptr;
+ obptr = obuf;
+ dmp = DM[(y_align + y) & (DM_HEIGHT - 1)];
+ for (x = 0; x < width; x++)
+ {
+ r = *bp2++;
+ g = *bp2++;
+ b = *bp2++;
+ gray = (g + ((b + r) >> 1)) >> 1;
+ gray += (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) >> prec;
+ obptr[0] = (gray - (gray >> prec)) >> right;
+ obptr++;
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+
+static void
+xlib_rgb_convert_gray4_d_pack (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ int x, y;
+ int bpl;
+ unsigned char *obuf, *obptr;
+ unsigned char *bptr, *bp2;
+ int r, g, b;
+ const unsigned char *dmp;
+ int prec, right;
+ int gray;
+ unsigned char pix0, pix1;
+ /* todo: this is hardcoded to big-endian. Make endian-agile. */
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + (ax >> 1);
+ prec = image_info->x_visual_info->depth;
+ right = 8 - prec;
+ for (y = 0; y < height; y++)
+ {
+ bp2 = bptr;
+ obptr = obuf;
+ dmp = DM[(y_align + y) & (DM_HEIGHT - 1)];
+ for (x = 0; x < width; x += 2)
+ {
+ r = *bp2++;
+ g = *bp2++;
+ b = *bp2++;
+ gray = (g + ((b + r) >> 1)) >> 1;
+ gray += (dmp[(x_align + x) & (DM_WIDTH - 1)] << 2) >> prec;
+ pix0 = (gray - (gray >> prec)) >> right;
+ r = *bp2++;
+ g = *bp2++;
+ b = *bp2++;
+ gray = (g + ((b + r) >> 1)) >> 1;
+ gray += (dmp[(x_align + x + 1) & (DM_WIDTH - 1)] << 2) >> prec;
+ pix1 = (gray - (gray >> prec)) >> right;
+ obptr[0] = (pix0 << 4) | pix1;
+ obptr++;
+ }
+ if (width & 1)
+ {
+ r = *bp2++;
+ g = *bp2++;
+ b = *bp2++;
+ gray = (g + ((b + r) >> 1)) >> 1;
+ gray += (dmp[(x_align + x + 1) & (DM_WIDTH - 1)] << 2) >> prec;
+ pix0 = (gray - (gray >> prec)) >> right;
+ obptr[0] = (pix0 << 4);
+ }
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+
+static void
+xlib_rgb_convert_1 (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align,
+ XlibRgbCmap *cmap)
+{
+ int x, y;
+ int bpl;
+ unsigned char *obuf, *obptr;
+ unsigned char *bptr, *bp2;
+ int r, g, b;
+ const unsigned char *dmp;
+ int dith;
+ unsigned char byte;
+
+ bptr = buf;
+ bpl = image->bytes_per_line;
+ obuf = ((unsigned char *)image->data) + ay * bpl + (ax >> 3);
+ byte = 0; /* unnecessary, but it keeps gcc from complaining */
+ for (y = 0; y < height; y++)
+ {
+ dmp = DM[(y_align + y) & (DM_HEIGHT - 1)];
+ bp2 = bptr;
+ obptr = obuf;
+ for (x = 0; x < width; x++)
+ {
+ r = *bp2++;
+ g = *bp2++;
+ b = *bp2++;
+ dith = (dmp[(x_align + x) & (DM_WIDTH - 1)] << 4) | 4;
+ byte += byte + (r + g + g + b + dith > 1020);
+ if ((x & 7) == 7)
+ {
+ obptr[0] = byte;
+ obptr++;
+ }
+ }
+ if (x & 7)
+ obptr[0] = byte << (8 - (x & 7));
+ bptr += rowstride;
+ obuf += bpl;
+ }
+}
+
+/* Returns a pointer to the stage buffer. */
+static unsigned char *
+xlib_rgb_ensure_stage (void)
+{
+ if (image_info->stage_buf == NULL)
+ image_info->stage_buf = malloc (IMAGE_HEIGHT * STAGE_ROWSTRIDE);
+ return image_info->stage_buf;
+}
+
+/* This is slow. Speed me up, please. */
+static void
+xlib_rgb_32_to_stage (unsigned char *buf, int rowstride, int width, int height)
+{
+ int x, y;
+ unsigned char *pi_start, *po_start;
+ unsigned char *pi, *po;
+
+ pi_start = buf;
+ po_start = xlib_rgb_ensure_stage ();
+ for (y = 0; y < height; y++)
+ {
+ pi = pi_start;
+ po = po_start;
+ for (x = 0; x < width; x++)
+ {
+ *po++ = *pi++;
+ *po++ = *pi++;
+ *po++ = *pi++;
+ pi++;
+ }
+ pi_start += rowstride;
+ po_start += STAGE_ROWSTRIDE;
+ }
+}
+
+/* Generic 32bit RGB conversion function - convert to 24bit packed, then
+ go from there. */
+static void
+xlib_rgb_convert_32_generic (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ xlib_rgb_32_to_stage (buf, rowstride, width, height);
+
+ (*image_info->conv) (image, ax, ay, width, height,
+ image_info->stage_buf, STAGE_ROWSTRIDE,
+ x_align, y_align, cmap);
+}
+
+/* Generic 32bit RGB conversion function - convert to 24bit packed, then
+ go from there. */
+static void
+xlib_rgb_convert_32_generic_d (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ xlib_rgb_32_to_stage (buf, rowstride, width, height);
+
+ (*image_info->conv_d) (image, ax, ay, width, height,
+ image_info->stage_buf, STAGE_ROWSTRIDE,
+ x_align, y_align, cmap);
+}
+
+/* This is slow. Speed me up, please. */
+static void
+xlib_rgb_gray_to_stage (unsigned char *buf, int rowstride, int width, int height)
+{
+ int x, y;
+ unsigned char *pi_start, *po_start;
+ unsigned char *pi, *po;
+ unsigned char gray;
+
+ pi_start = buf;
+ po_start = xlib_rgb_ensure_stage ();
+ for (y = 0; y < height; y++)
+ {
+ pi = pi_start;
+ po = po_start;
+ for (x = 0; x < width; x++)
+ {
+ gray = *pi++;
+ *po++ = gray;
+ *po++ = gray;
+ *po++ = gray;
+ }
+ pi_start += rowstride;
+ po_start += STAGE_ROWSTRIDE;
+ }
+}
+
+/* Generic gray conversion function - convert to 24bit packed, then go
+ from there. */
+static void
+xlib_rgb_convert_gray_generic (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ xlib_rgb_gray_to_stage (buf, rowstride, width, height);
+
+ (*image_info->conv) (image, ax, ay, width, height,
+ image_info->stage_buf, STAGE_ROWSTRIDE,
+ x_align, y_align, cmap);
+}
+
+static void
+xlib_rgb_convert_gray_generic_d (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ xlib_rgb_gray_to_stage (buf, rowstride, width, height);
+
+ (*image_info->conv_d) (image, ax, ay, width, height,
+ image_info->stage_buf, STAGE_ROWSTRIDE,
+ x_align, y_align, cmap);
+}
+
+/* Render grayscale using indexed method. */
+static void
+xlib_rgb_convert_gray_cmap (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ (*image_info->conv_indexed) (image, ax, ay, width, height,
+ buf, rowstride,
+ x_align, y_align, image_info->gray_cmap);
+}
+
+#if 0
+static void
+xlib_rgb_convert_gray_cmap_d (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ (*image_info->conv_indexed_d) (image, ax, ay, width, height,
+ buf, rowstride,
+ x_align, y_align, image_info->gray_cmap);
+}
+#endif
+
+/* This is slow. Speed me up, please. */
+static void
+xlib_rgb_indexed_to_stage (unsigned char *buf, int rowstride, int width, int height,
+ XlibRgbCmap *cmap)
+{
+ int x, y;
+ unsigned char *pi_start, *po_start;
+ unsigned char *pi, *po;
+ int rgb;
+
+ pi_start = buf;
+ po_start = xlib_rgb_ensure_stage ();
+ for (y = 0; y < height; y++)
+ {
+ pi = pi_start;
+ po = po_start;
+ for (x = 0; x < width; x++)
+ {
+ rgb = cmap->colors[*pi++];
+ *po++ = rgb >> 16;
+ *po++ = (rgb >> 8) & 0xff;
+ *po++ = rgb & 0xff;
+ }
+ pi_start += rowstride;
+ po_start += STAGE_ROWSTRIDE;
+ }
+}
+
+/* Generic gray conversion function - convert to 24bit packed, then go
+ from there. */
+static void
+xlib_rgb_convert_indexed_generic (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align, XlibRgbCmap *cmap)
+{
+ xlib_rgb_indexed_to_stage (buf, rowstride, width, height, cmap);
+
+ (*image_info->conv) (image, ax, ay, width, height,
+ image_info->stage_buf, STAGE_ROWSTRIDE,
+ x_align, y_align, cmap);
+}
+
+static void
+xlib_rgb_convert_indexed_generic_d (XImage *image,
+ int ax, int ay, int width, int height,
+ unsigned char *buf, int rowstride,
+ int x_align, int y_align,
+ XlibRgbCmap *cmap)
+{
+ xlib_rgb_indexed_to_stage (buf, rowstride, width, height, cmap);
+
+ (*image_info->conv_d) (image, ax, ay, width, height,
+ image_info->stage_buf, STAGE_ROWSTRIDE,
+ x_align, y_align, cmap);
+}
+
+/* Select a conversion function based on the visual and a
+ representative image. */
+static void
+xlib_rgb_select_conv (XImage *image, ByteOrder byte_order)
+{
+ int depth, byterev;
+ int vtype; /* visual type */
+ int bpp; /* bits per pixel - from the visual */
+ unsigned int red_mask, green_mask, blue_mask;
+ XlibRgbConvFunc conv, conv_d;
+ XlibRgbConvFunc conv_32, conv_32_d;
+ XlibRgbConvFunc conv_gray, conv_gray_d;
+ XlibRgbConvFunc conv_indexed, conv_indexed_d;
+ Bool mask_rgb, mask_bgr;
+
+ depth = image_info->x_visual_info->depth;
+ bpp = image->bits_per_pixel;
+ if (xlib_rgb_verbose)
+ printf ("Chose visual 0x%x, image bpp=%d, %s first\n",
+ (int)image_info->x_visual_info->visual->visualid,
+ bpp, byte_order == LSB_FIRST ? "lsb" : "msb");
+
+#if X_BYTE_ORDER == X_BIG_ENDIAN
+ byterev = (byte_order == LSB_FIRST);
+#else
+ byterev = (byte_order == MSB_FIRST);
+#endif
+
+ vtype = image_info->x_visual_info->class;
+ if (vtype == DirectColor)
+ vtype = TrueColor;
+
+ red_mask = image_info->x_visual_info->red_mask;
+ green_mask = image_info->x_visual_info->green_mask;
+ blue_mask = image_info->x_visual_info->blue_mask;
+
+ mask_rgb = red_mask == 0xff0000 && green_mask == 0xff00 && blue_mask == 0xff;
+ mask_bgr = red_mask == 0xff && green_mask == 0xff00 && blue_mask == 0xff0000;
+
+ conv = NULL;
+ conv_d = NULL;
+
+ conv_32 = xlib_rgb_convert_32_generic;
+ conv_32_d = xlib_rgb_convert_32_generic_d;
+
+ conv_gray = xlib_rgb_convert_gray_generic;
+ conv_gray_d = xlib_rgb_convert_gray_generic_d;
+
+ conv_indexed = xlib_rgb_convert_indexed_generic;
+ conv_indexed_d = xlib_rgb_convert_indexed_generic_d;
+
+ image_info->dith_default = FALSE;
+
+ if (image_info->bitmap)
+ conv = xlib_rgb_convert_1;
+ else if (bpp == 16 && depth == 16 && !byterev &&
+ red_mask == 0xf800 && green_mask == 0x7e0 && blue_mask == 0x1f)
+ {
+ conv = xlib_rgb_convert_565;
+ conv_d = xlib_rgb_convert_565_d;
+ conv_gray = xlib_rgb_convert_565_gray;
+ xlib_rgb_preprocess_dm_565 ();
+ }
+ else if (bpp == 16 && depth == 16 &&
+ vtype == TrueColor&& byterev &&
+ red_mask == 0xf800 && green_mask == 0x7e0 && blue_mask == 0x1f)
+ conv = xlib_rgb_convert_565_br;
+
+ else if (bpp == 16 && depth == 15 &&
+ vtype == TrueColor && !byterev &&
+ red_mask == 0x7c00 && green_mask == 0x3e0 && blue_mask == 0x1f)
+ conv = xlib_rgb_convert_555;
+
+ else if (bpp == 16 && depth == 15 &&
+ vtype == TrueColor && byterev &&
+ red_mask == 0x7c00 && green_mask == 0x3e0 && blue_mask == 0x1f)
+ conv = xlib_rgb_convert_555_br;
+
+ /* I'm not 100% sure about the 24bpp tests - but testing will show*/
+ else if (bpp == 24 && depth == 24 && vtype == TrueColor &&
+ ((mask_rgb && byte_order == LSB_FIRST) ||
+ (mask_bgr && byte_order == MSB_FIRST)))
+ conv = xlib_rgb_convert_888_lsb;
+ else if (bpp == 24 && depth == 24 && vtype == TrueColor &&
+ ((mask_rgb && byte_order == MSB_FIRST) ||
+ (mask_bgr && byte_order == LSB_FIRST)))
+ conv = xlib_rgb_convert_888_msb;
+#if X_BYTE_ORDER == X_BIG_ENDIAN
+ else if (bpp == 32 && depth == 24 && vtype == TrueColor &&
+ (mask_rgb && byte_order == LSB_FIRST))
+ conv = xlib_rgb_convert_0888_br;
+ else if (bpp == 32 && depth == 24 && vtype == TrueColor &&
+ (mask_rgb && byte_order == MSB_FIRST))
+ conv = xlib_rgb_convert_0888;
+ else if (bpp == 32 && depth == 24 && vtype == TrueColor &&
+ (mask_bgr && byte_order == MSB_FIRST))
+ conv = xlib_rgb_convert_8880_br;
+#else
+ else if (bpp == 32 && depth == 24 && vtype == TrueColor &&
+ (mask_rgb && byte_order == MSB_FIRST))
+ conv = xlib_rgb_convert_0888_br;
+ else if (bpp == 32 && (depth == 32 || depth == 24) && vtype == TrueColor &&
+ (mask_rgb && byte_order == LSB_FIRST))
+ conv = xlib_rgb_convert_0888;
+ else if (bpp == 32 && depth == 24 && vtype == TrueColor &&
+ (mask_bgr && byte_order == LSB_FIRST))
+ conv = xlib_rgb_convert_8880_br;
+#endif
+
+ else if (vtype == TrueColor && byte_order == LSB_FIRST)
+ {
+ conv = xlib_rgb_convert_truecolor_lsb;
+ conv_d = xlib_rgb_convert_truecolor_lsb_d;
+ }
+ else if (vtype == TrueColor && byte_order == MSB_FIRST)
+ {
+ conv = xlib_rgb_convert_truecolor_msb;
+ conv_d = xlib_rgb_convert_truecolor_msb_d;
+ }
+ else if (bpp == 8 && depth == 8 && (vtype == PseudoColor
+#ifdef ENABLE_GRAYSCALE
+ || vtype == GrayScale
+#endif
+ ))
+ {
+ image_info->dith_default = TRUE;
+ conv = xlib_rgb_convert_8;
+ if (vtype != GrayScale)
+ {
+ if (image_info->nred_shades == 6 &&
+ image_info->ngreen_shades == 6 &&
+ image_info->nblue_shades == 6)
+ conv_d = xlib_rgb_convert_8_d666;
+ else
+ conv_d = xlib_rgb_convert_8_d;
+ }
+ conv_indexed = xlib_rgb_convert_8_indexed;
+ conv_gray = xlib_rgb_convert_gray_cmap;
+ }
+ else if (bpp == 8 && depth == 8 && (vtype == StaticGray
+#ifdef not_ENABLE_GRAYSCALE
+ || vtype == GrayScale
+#endif
+ ))
+ {
+ conv = xlib_rgb_convert_gray8;
+ conv_gray = xlib_rgb_convert_gray8_gray;
+ }
+ else if (bpp == 8 && depth < 8 && depth >= 2 &&
+ (vtype == StaticGray
+ || vtype == GrayScale))
+ {
+ conv = xlib_rgb_convert_gray4;
+ conv_d = xlib_rgb_convert_gray4_d;
+ }
+ else if (bpp == 8 && depth < 8 && depth >= 3)
+ {
+ conv = xlib_rgb_convert_4;
+ }
+ else if (bpp == 4 && depth <= 4 && depth >= 2 &&
+ (vtype == StaticGray
+ || vtype == GrayScale))
+ {
+ conv = xlib_rgb_convert_gray4_pack;
+ conv_d = xlib_rgb_convert_gray4_d_pack;
+ }
+
+ if (conv_d == NULL)
+ conv_d = conv;
+
+ image_info->conv = conv;
+ image_info->conv_d = conv_d;
+
+ image_info->conv_32 = conv_32;
+ image_info->conv_32_d = conv_32_d;
+
+ image_info->conv_gray = conv_gray;
+ image_info->conv_gray_d = conv_gray_d;
+
+ image_info->conv_indexed = conv_indexed;
+ image_info->conv_indexed_d = conv_indexed_d;
+}
+
+static int horiz_idx;
+static int horiz_y = IMAGE_HEIGHT;
+static int vert_idx;
+static int vert_x = IMAGE_WIDTH;
+static int tile_idx;
+static int tile_x = IMAGE_WIDTH;
+static int tile_y1 = IMAGE_HEIGHT;
+static int tile_y2 = IMAGE_HEIGHT;
+
+#ifdef VERBOSE
+static int sincelast;
+#endif
+
+/* Defining NO_FLUSH can cause inconsistent screen updates, but is useful
+ for performance evaluation. */
+
+#undef NO_FLUSH
+
+static int
+xlib_rgb_alloc_scratch_image (void)
+{
+ if (static_image_idx == N_IMAGES)
+ {
+#ifndef NO_FLUSH
+ XFlush(image_info->display);
+#endif
+#ifdef VERBOSE
+ printf ("flush, %d puts since last flush\n", sincelast);
+ sincelast = 0;
+#endif
+ static_image_idx = 0;
+ horiz_y = IMAGE_HEIGHT;
+ vert_x = IMAGE_WIDTH;
+ tile_x = IMAGE_WIDTH;
+ tile_y1 = tile_y2 = IMAGE_HEIGHT;
+ }
+ return static_image_idx++;
+}
+
+static XImage *
+xlib_rgb_alloc_scratch (int width, int height, int *ax, int *ay)
+{
+ XImage *image;
+ int idx;
+
+ if (width >= (IMAGE_WIDTH >> 1))
+ {
+ if (height >= (IMAGE_HEIGHT >> 1))
+ {
+ idx = xlib_rgb_alloc_scratch_image ();
+ *ax = 0;
+ *ay = 0;
+ }
+ else
+ {
+ if (height + horiz_y > IMAGE_HEIGHT)
+ {
+ horiz_idx = xlib_rgb_alloc_scratch_image ();
+ horiz_y = 0;
+ }
+ idx = horiz_idx;
+ *ax = 0;
+ *ay = horiz_y;
+ horiz_y += height;
+ }
+ }
+ else
+ {
+ if (height >= (IMAGE_HEIGHT >> 1))
+ {
+ if (width + vert_x > IMAGE_WIDTH)
+ {
+ vert_idx = xlib_rgb_alloc_scratch_image ();
+ vert_x = 0;
+ }
+ idx = vert_idx;
+ *ax = vert_x;
+ *ay = 0;
+ /* using 3 and -4 would be slightly more efficient on 32-bit machines
+ with > 1bpp displays */
+ vert_x += (width + 7) & -8;
+ }
+ else
+ {
+ if (width + tile_x > IMAGE_WIDTH)
+ {
+ tile_y1 = tile_y2;
+ tile_x = 0;
+ }
+ if (height + tile_y1 > IMAGE_HEIGHT)
+ {
+ tile_idx = xlib_rgb_alloc_scratch_image ();
+ tile_x = 0;
+ tile_y1 = 0;
+ tile_y2 = 0;
+ }
+ if (height + tile_y1 > tile_y2)
+ tile_y2 = height + tile_y1;
+ idx = tile_idx;
+ *ax = tile_x;
+ *ay = tile_y1;
+ tile_x += (width + 7) & -8;
+ }
+ }
+ image = static_image[idx];
+#ifdef VERBOSE
+ printf ("index %d, x %d, y %d (%d x %d)\n", idx, *ax, *ay, width, height);
+ sincelast++;
+#endif
+ return image;
+}
+
+static void
+xlib_draw_rgb_image_core (Drawable drawable,
+ GC gc,
+ int x,
+ int y,
+ int width,
+ int height,
+ unsigned char *buf,
+ int pixstride,
+ int rowstride,
+ XlibRgbConvFunc conv,
+ XlibRgbCmap *cmap,
+ int xdith,
+ int ydith)
+{
+ int ay, ax;
+ int xs0, ys0;
+ XImage *image;
+ int width1, height1;
+ unsigned char *buf_ptr;
+
+ if (image_info->bitmap)
+ {
+ if (image_info->own_gc == 0)
+ {
+ XColor color;
+
+ image_info->own_gc = XCreateGC(image_info->display,
+ drawable,
+ 0, NULL);
+ color.pixel = WhitePixel(image_info->display,
+ image_info->screen_num);
+ XSetForeground(image_info->display, image_info->own_gc, color.pixel);
+ color.pixel = BlackPixel(image_info->display,
+ image_info->screen_num);
+ XSetBackground(image_info->display, image_info->own_gc, color.pixel);
+ }
+ gc = image_info->own_gc;
+ }
+ for (ay = 0; ay < height; ay += IMAGE_HEIGHT)
+ {
+ height1 = MIN (height - ay, IMAGE_HEIGHT);
+ for (ax = 0; ax < width; ax += IMAGE_WIDTH)
+ {
+ width1 = MIN (width - ax, IMAGE_WIDTH);
+ buf_ptr = buf + ay * rowstride + ax * pixstride;
+
+ image = xlib_rgb_alloc_scratch (width1, height1, &xs0, &ys0);
+
+ conv (image, xs0, ys0, width1, height1, buf_ptr, rowstride,
+ x + ax + xdith, y + ay + ydith, cmap);
+
+#ifndef DONT_ACTUALLY_DRAW
+ XPutImage(image_info->display, drawable, gc, image,
+ xs0, ys0, x + ax, y + ay, (unsigned int)width1, (unsigned int)height1);
+#endif
+ }
+ }
+}
+
+
+/**
+ * xlib_draw_rgb_image:
+ * @drawable: Destination drawable.
+ * @gc: A graphic context.
+ * @x: Leftmost coordinate of the destination rectangle.
+ * @y: Upper coordinate of the destination rectangle.
+ * @width: Width of the destination rectangle, in pixels.
+ * @height: Height of the destination rectangle, in pixels.
+ * @dith: Dithering method to use.
+ * @rgb_buf: Pointer to the pixel in the RGB buffer that corresponds to the
+ * upper-left corner of the rectangular region to render.
+ * @rowstride: Offset between pixel rows in the RGB buffer, in bytes.
+ *
+ * Renders an RGB buffer to a drawable. Pixels are specified as RGB triplets
+ * with 8 bits per channel. An image will thus look like an RGBRGBRGBRGB
+ * sequence of 8-bit values. This function does not let you specify dither
+ * offsets; applications that need to render partial regions of a buffer to
+ * build the final image should use xlib_draw_rgb_image_dithalign() instead.
+ **/
+void
+xlib_draw_rgb_image (Drawable drawable,
+ GC gc,
+ int x,
+ int y,
+ int width,
+ int height,
+ XlibRgbDither dith,
+ unsigned char *rgb_buf,
+ int rowstride)
+{
+ if (dith == XLIB_RGB_DITHER_NONE || (dith == XLIB_RGB_DITHER_NORMAL &&
+ !image_info->dith_default))
+ xlib_draw_rgb_image_core (drawable, gc, x, y, width, height,
+ rgb_buf, 3, rowstride, image_info->conv, NULL,
+ 0, 0);
+ else
+ xlib_draw_rgb_image_core (drawable, gc, x, y, width, height,
+ rgb_buf, 3, rowstride, image_info->conv_d, NULL,
+ 0, 0);
+}
+
+
+
+/**
+ * xlib_rgb_cmap_free:
+ * @cmap: An XlibRGB colormap.
+ *
+ * Frees an XlibRGB colormap.
+ **/
+void
+xlib_rgb_cmap_free (XlibRgbCmap *cmap)
+{
+ free (cmap);
+}
+
+/**
+ * xlib_draw_indexed_image:
+ * @drawable: FIXME
+ * @gc: FIXME
+ * @x: FIXME
+ * @y: FIXME
+ * @width: FIXME
+ * @height: FIXME
+ * @dith: FIXME
+ * @buf: FIXME
+ * @rowstride: FIXME
+ * @cmap: FIXME
+ *
+ * FIXME
+ **/
+void
+xlib_draw_indexed_image (Drawable drawable,
+ GC gc,
+ int x,
+ int y,
+ int width,
+ int height,
+ XlibRgbDither dith,
+ unsigned char *buf,
+ int rowstride,
+ XlibRgbCmap *cmap)
+{
+ if (dith == XLIB_RGB_DITHER_NONE || (dith == XLIB_RGB_DITHER_NORMAL &&
+ !image_info->dith_default))
+ xlib_draw_rgb_image_core (drawable, gc, x, y, width, height,
+ buf, 1, rowstride,
+ image_info->conv_indexed, cmap, 0, 0);
+ else
+ xlib_draw_rgb_image_core (drawable, gc, x, y, width, height,
+ buf, 1, rowstride,
+ image_info->conv_indexed_d, cmap, 0, 0);
+}
+
+/**
+ * xlib_rgb_ditherable:
+ *
+ * Queries whether XlibRGB supports dithering for its chosen visual.
+ *
+ * Return value: TRUE if dithering can be performed for the visual that XlibRGB
+ * is using, FALSE otherwise.
+ **/
+Bool
+xlib_rgb_ditherable (void)
+{
+ return (image_info->conv != image_info->conv_d);
+}
+
+/**
+ * xlib_rgb_get_cmap:
+ *
+ * Queries the X colormap that XlibRGB is using.
+ *
+ * Return value: An X colormap.
+ **/
+Colormap
+xlib_rgb_get_cmap (void)
+{
+ /* xlib_rgb_init (); */
+ if (image_info)
+ return image_info->cmap;
+ else
+ return 0;
+}
+
+/**
+ * xlib_rgb_get_visual:
+ *
+ * Queries the visual that XlibRGB is using.
+ *
+ * Return value: An X visual.
+ **/
+Visual *
+xlib_rgb_get_visual (void)
+{
+ /* xlib_rgb_init (); */
+ if (image_info)
+ return image_info->x_visual_info->visual;
+ else
+ return 0;
+}
+
+/**
+ * xlib_rgb_get_visual_info:
+ *
+ * Queries the visual info structure for the visual that XlibRGB is using.
+ *
+ * Return value: An XVisualInfo structure.
+ **/
+XVisualInfo *
+xlib_rgb_get_visual_info (void)
+{
+ /* xlib_rgb_init (); */
+ if (image_info)
+ return image_info->x_visual_info;
+ else
+ return 0;
+}
+
+/**
+ * xlib_rgb_get_depth:
+ *
+ * Queries the depth of the visual that XlibRGB is using.
+ *
+ * Return value: Bit depth.
+ **/
+int
+xlib_rgb_get_depth (void)
+{
+ XVisualInfo * v = xlib_rgb_get_visual_info();
+
+ if (v)
+ {
+ return v->depth;
+ }
+
+ return 0;
+}
+
+/**
+ * xlib_rgb_get_display:
+ *
+ * Queries the X display that XlibRGB is using.
+ *
+ * Return value: An X display.
+ **/
+Display *
+xlib_rgb_get_display (void)
+{
+ if (image_info)
+ return image_info->display;
+
+ return NULL;
+}
+
+/**
+ * xlib_rgb_get_screen:
+ *
+ * Queries the screen that XlibRGB is using.
+ *
+ * Return value: An X screen.
+ **/
+Screen *
+xlib_rgb_get_screen (void)
+{
+ if (image_info)
+ return image_info->screen;
+
+ return NULL;
+}
diff --git a/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlibrgb.h b/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlibrgb.h
new file mode 100644
index 00000000..afde174e
--- /dev/null
+++ b/ksvg/impl/libs/xrgbrender/gdk-pixbuf-xlibrgb.h
@@ -0,0 +1,145 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "MPL"); you may not use this file except in
+ * compliance with the MPL. You may obtain a copy of the MPL at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the MPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL
+ * for the specific language governing rights and limitations under the
+ * MPL.
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Library General Public License (the "LGPL"), in
+ * which case the provisions of the LGPL are applicable instead of
+ * those above. If you wish to allow use of your version of this file
+ * only under the terms of the LGPL and not to allow others to use
+ * your version of this file under the MPL, indicate your decision by
+ * deleting the provisions above and replace them with the notice and
+ * other provisions required by the LGPL. If you do not delete the
+ * provisions above, a recipient may use your version of this file
+ * under either the MPL or the LGPL.
+ */
+
+/*
+ * This code is derived from GdkRgb.
+ * For more information on GdkRgb, see http://www.levien.com/gdkrgb/
+ * Raph Levien <raph@acm.org>
+ */
+
+/* Ported by Christopher Blizzard to Xlib. With permission from the
+ * original authors of this file, the contents of this file are also
+ * redistributable under the terms of the Mozilla Public license. For
+ * information about the Mozilla Public License, please see the
+ * license information at http://www.mozilla.org/MPL/
+ */
+
+/* This code is copyright the following authors:
+ * Raph Levien <raph@acm.org>
+ * Manish Singh <manish@gtk.org>
+ * Tim Janik <timj@gtk.org>
+ * Peter Mattis <petm@xcf.berkeley.edu>
+ * Spencer Kimball <spencer@xcf.berkeley.edu>
+ * Josh MacDonald <jmacd@xcf.berkeley.edu>
+ * Christopher Blizzard <blizzard@redhat.com>
+ * Owen Taylor <otaylor@redhat.com>
+ * Shawn T. Amundson <amundson@gtk.org>
+*/
+
+
+#ifndef __XLIB_RGB_H__
+#define __XLIB_RGB_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xos.h>
+#include <X11/Intrinsic.h>
+
+
+typedef struct _XlibRgbCmap XlibRgbCmap;
+
+struct _XlibRgbCmap {
+ unsigned int colors[256];
+ unsigned char lut[256]; /* for 8-bit modes */
+};
+
+void
+xlib_rgb_init_with_depth (Display *display, Screen *screen, int prefDepth);
+
+typedef enum
+{
+ XLIB_RGB_DITHER_NONE,
+ XLIB_RGB_DITHER_NORMAL,
+ XLIB_RGB_DITHER_MAX
+} XlibRgbDither;
+
+void
+xlib_draw_rgb_image (Drawable drawable,
+ GC gc,
+ int x,
+ int y,
+ int width,
+ int height,
+ XlibRgbDither dith,
+ unsigned char *rgb_buf,
+ int rowstride);
+
+void
+xlib_rgb_cmap_free (XlibRgbCmap *cmap);
+
+void
+xlib_draw_indexed_image (Drawable drawable,
+ GC gc,
+ int x,
+ int y,
+ int width,
+ int height,
+ XlibRgbDither dith,
+ unsigned char *buf,
+ int rowstride,
+ XlibRgbCmap *cmap);
+
+/* Below are some functions which are primarily useful for debugging
+ and experimentation. */
+Bool
+xlib_rgb_ditherable (void);
+
+void
+xlib_rgb_set_verbose (Bool verbose);
+
+/* experimental colormap stuff */
+void
+xlib_rgb_set_install (Bool install);
+
+void
+xlib_rgb_set_min_colors (int min_colors);
+
+Colormap
+xlib_rgb_get_cmap (void);
+
+Visual *
+xlib_rgb_get_visual (void);
+
+XVisualInfo *
+xlib_rgb_get_visual_info (void);
+
+int
+xlib_rgb_get_depth (void);
+
+Display *
+xlib_rgb_get_display (void);
+
+Screen *
+xlib_rgb_get_screen (void);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+#endif /* __XLIB_RGB_H__ */
diff --git a/ksvg/impl/svgpathparser.cc b/ksvg/impl/svgpathparser.cc
new file mode 100644
index 00000000..0f7521e0
--- /dev/null
+++ b/ksvg/impl/svgpathparser.cc
@@ -0,0 +1,564 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002, 2003 The Karbon Developers
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "svgpathparser.h"
+#include <qstring.h>
+#include <math.h>
+
+// parses the number into parameter number
+const char *
+KSVG::getNumber( const char *ptr, double &number )
+{
+ int integer, exponent;
+ double decimal, frac;
+ int sign, expsign;
+
+ exponent = 0;
+ integer = 0;
+ frac = 1.0;
+ decimal = 0;
+ sign = 1;
+ expsign = 1;
+
+ // read the sign
+ if(*ptr == '+')
+ ptr++;
+ else if(*ptr == '-')
+ {
+ ptr++;
+ sign = -1;
+ }
+
+ // read the integer part
+ while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
+ integer = (integer * 10) + *(ptr++) - '0';
+ if(*ptr == '.') // read the decimals
+ {
+ ptr++;
+ while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
+ decimal += (*(ptr++) - '0') * (frac *= 0.1);
+ }
+
+ if(*ptr == 'e' || *ptr == 'E') // read the exponent part
+ {
+ ptr++;
+
+ // read the sign of the exponent
+ if(*ptr == '+')
+ ptr++;
+ else if(*ptr == '-')
+ {
+ ptr++;
+ expsign = -1;
+ }
+
+ exponent = 0;
+ while(*ptr != '\0' && *ptr >= '0' && *ptr <= '9')
+ {
+ exponent *= 10;
+ exponent += *ptr - '0';
+ ptr++;
+ }
+ }
+ number = integer + decimal;
+ number *= sign * pow( (double)10, double( expsign * exponent ) );
+
+ return ptr;
+}
+
+// parses the coord into parameter number and forwards to the next coord in the path data
+const char *
+SVGPathParser::getCoord( const char *ptr, double &number )
+{
+ ptr = KSVG::getNumber( ptr, number );
+ // skip the following space
+ if(*ptr == ' ')
+ ptr++;
+
+ return ptr;
+}
+
+void
+SVGPathParser::parseSVG( const QString &s, bool process )
+{
+ if(!s.isEmpty())
+ {
+ QString d = s;
+ d = d.replace(',', ' ');
+ d = d.simplifyWhiteSpace();
+ const char *ptr = d.latin1();
+ const char *end = d.latin1() + d.length() + 1;
+
+ double contrlx, contrly, curx, cury, subpathx, subpathy, tox, toy, x1, y1, x2, y2, xc, yc;
+ double px1, py1, px2, py2, px3, py3;
+ bool relative, closed = true;
+ char command = *(ptr++), lastCommand = ' ';
+
+ subpathx = subpathy = curx = cury = contrlx = contrly = 0.0;
+ while( ptr < end )
+ {
+ if( *ptr == ' ' )
+ ptr++;
+
+ relative = false;
+
+ //std::cout << "Command : " << command << std::endl;
+ switch( command )
+ {
+ case 'm':
+ relative = true;
+ case 'M':
+ {
+ ptr = getCoord( ptr, tox );
+ ptr = getCoord( ptr, toy );
+
+ if( process )
+ {
+ subpathx = curx = relative ? curx + tox : tox;
+ subpathy = cury = relative ? cury + toy : toy;
+
+ svgMoveTo( curx, cury, closed );
+ }
+ else
+ svgMoveTo( tox, toy, closed, !relative );
+ closed = false;
+ break;
+ }
+ case 'l':
+ relative = true;
+ case 'L':
+ {
+ ptr = getCoord( ptr, tox );
+ ptr = getCoord( ptr, toy );
+
+ if( process )
+ {
+ curx = relative ? curx + tox : tox;
+ cury = relative ? cury + toy : toy;
+
+ svgLineTo( curx, cury );
+ }
+ else
+ svgLineTo( tox, toy, !relative );
+ break;
+ }
+ case 'h':
+ {
+ ptr = getCoord( ptr, tox );
+ if( process )
+ {
+ curx = curx + tox;
+ svgLineTo( curx, cury );
+ }
+ else
+ svgLineToHorizontal( tox, false );
+ break;
+ }
+ case 'H':
+ {
+ ptr = getCoord( ptr, tox );
+ if( process )
+ {
+ curx = tox;
+ svgLineTo( curx, cury );
+ }
+ else
+ svgLineToHorizontal( tox );
+ break;
+ }
+ case 'v':
+ {
+ ptr = getCoord( ptr, toy );
+ if( process )
+ {
+ cury = cury + toy;
+ svgLineTo( curx, cury );
+ }
+ else
+ svgLineToVertical( toy, false );
+ break;
+ }
+ case 'V':
+ {
+ ptr = getCoord( ptr, toy );
+ if( process )
+ {
+ cury = toy;
+ svgLineTo( curx, cury );
+ }
+ else
+ svgLineToVertical( toy );
+ break;
+ }
+ case 'z':
+ case 'Z':
+ {
+ // reset curx, cury for next path
+ if( process )
+ {
+ curx = subpathx;
+ cury = subpathy;
+ }
+ closed = true;
+ svgClosePath();
+ break;
+ }
+ case 'c':
+ relative = true;
+ case 'C':
+ {
+ ptr = getCoord( ptr, x1 );
+ ptr = getCoord( ptr, y1 );
+ ptr = getCoord( ptr, x2 );
+ ptr = getCoord( ptr, y2 );
+ ptr = getCoord( ptr, tox );
+ ptr = getCoord( ptr, toy );
+
+ if( process )
+ {
+ px1 = relative ? curx + x1 : x1;
+ py1 = relative ? cury + y1 : y1;
+ px2 = relative ? curx + x2 : x2;
+ py2 = relative ? cury + y2 : y2;
+ px3 = relative ? curx + tox : tox;
+ py3 = relative ? cury + toy : toy;
+
+ svgCurveToCubic( px1, py1, px2, py2, px3, py3 );
+
+ contrlx = relative ? curx + x2 : x2;
+ contrly = relative ? cury + y2 : y2;
+ curx = relative ? curx + tox : tox;
+ cury = relative ? cury + toy : toy;
+ }
+ else
+ svgCurveToCubic( x1, y1, x2, y2, tox, toy, !relative );
+
+ break;
+ }
+ case 's':
+ relative = true;
+ case 'S':
+ {
+ ptr = getCoord( ptr, x2 );
+ ptr = getCoord( ptr, y2 );
+ ptr = getCoord( ptr, tox );
+ ptr = getCoord( ptr, toy );
+
+ if( process )
+ {
+ px1 = 2 * curx - contrlx;
+ py1 = 2 * cury - contrly;
+ px2 = relative ? curx + x2 : x2;
+ py2 = relative ? cury + y2 : y2;
+ px3 = relative ? curx + tox : tox;
+ py3 = relative ? cury + toy : toy;
+
+ svgCurveToCubic( px1, py1, px2, py2, px3, py3 );
+
+ contrlx = relative ? curx + x2 : x2;
+ contrly = relative ? cury + y2 : y2;
+ curx = relative ? curx + tox : tox;
+ cury = relative ? cury + toy : toy;
+ }
+ else
+ svgCurveToCubicSmooth( x2, y2, tox, toy, !relative );
+ break;
+ }
+ case 'q':
+ relative = true;
+ case 'Q':
+ {
+ ptr = getCoord( ptr, x1 );
+ ptr = getCoord( ptr, y1 );
+ ptr = getCoord( ptr, tox );
+ ptr = getCoord( ptr, toy );
+
+ if( process )
+ {
+ px1 = relative ? (curx + 2 * (x1 + curx)) * (1.0 / 3.0) : (curx + 2 * x1) * (1.0 / 3.0);
+ py1 = relative ? (cury + 2 * (y1 + cury)) * (1.0 / 3.0) : (cury + 2 * y1) * (1.0 / 3.0);
+ px2 = relative ? ((curx + tox) + 2 * (x1 + curx)) * (1.0 / 3.0) : (tox + 2 * x1) * (1.0 / 3.0);
+ py2 = relative ? ((cury + toy) + 2 * (y1 + cury)) * (1.0 / 3.0) : (toy + 2 * y1) * (1.0 / 3.0);
+ px3 = relative ? curx + tox : tox;
+ py3 = relative ? cury + toy : toy;
+
+ svgCurveToCubic( px1, py1, px2, py2, px3, py3 );
+
+ contrlx = relative ? curx + x1 : (tox + 2 * x1) * (1.0 / 3.0);
+ contrly = relative ? cury + y1 : (toy + 2 * y1) * (1.0 / 3.0);
+ curx = relative ? curx + tox : tox;
+ cury = relative ? cury + toy : toy;
+ }
+ else
+ svgCurveToQuadratic( x1, y1, tox, toy, !relative );
+ break;
+ }
+ case 't':
+ relative = true;
+ case 'T':
+ {
+ ptr = getCoord(ptr, tox);
+ ptr = getCoord(ptr, toy);
+
+ if( process )
+ {
+ xc = 2 * curx - contrlx;
+ yc = 2 * cury - contrly;
+
+ px1 = (curx + 2 * xc) * (1.0 / 3.0);
+ py1 = (cury + 2 * yc) * (1.0 / 3.0);
+ px2 = relative ? ((curx + tox) + 2 * xc) * (1.0 / 3.0) : (tox + 2 * xc) * (1.0 / 3.0);
+ py2 = relative ? ((cury + toy) + 2 * yc) * (1.0 / 3.0) : (toy + 2 * yc) * (1.0 / 3.0);
+ px3 = relative ? curx + tox : tox;
+ py3 = relative ? cury + toy : toy;
+
+ svgCurveToCubic( px1, py1, px2, py2, px3, py3 );
+
+ contrlx = xc;
+ contrly = yc;
+ curx = relative ? curx + tox : tox;
+ cury = relative ? cury + toy : toy;
+ }
+ else
+ svgCurveToQuadraticSmooth( tox, toy, !relative );
+ break;
+ }
+ case 'a':
+ relative = true;
+ case 'A':
+ {
+ bool largeArc, sweep;
+ double angle, rx, ry;
+ ptr = getCoord( ptr, rx );
+ ptr = getCoord( ptr, ry );
+ ptr = getCoord( ptr, angle );
+ ptr = getCoord( ptr, tox );
+ largeArc = tox == 1;
+ ptr = getCoord( ptr, tox );
+ sweep = tox == 1;
+ ptr = getCoord( ptr, tox );
+ ptr = getCoord( ptr, toy );
+
+ // Spec: radii are nonnegative numbers
+ rx = fabs(rx);
+ ry = fabs(ry);
+
+ if( process )
+ calculateArc( relative, curx, cury, angle, tox, toy, rx, ry, largeArc, sweep );
+ else
+ svgArcTo( tox, toy, rx, ry, angle, largeArc, sweep, !relative );
+ }
+ }
+
+ lastCommand = command;
+
+ if(*ptr == '+' || *ptr == '-' || (*ptr >= '0' && *ptr <= '9'))
+ {
+ // there are still coords in this command
+ if(command == 'M')
+ command = 'L';
+ else if(command == 'm')
+ command = 'l';
+ }
+ else
+ command = *(ptr++);
+
+ if( lastCommand != 'C' && lastCommand != 'c' &&
+ lastCommand != 'S' && lastCommand != 's' &&
+ lastCommand != 'Q' && lastCommand != 'q' &&
+ lastCommand != 'T' && lastCommand != 't')
+ {
+ contrlx = curx;
+ contrly = cury;
+ }
+ }
+ }
+}
+
+// This works by converting the SVG arc to "simple" beziers.
+// For each bezier found a svgToCurve call is done.
+// Adapted from Niko's code in kdelibs/kdecore/svgicons.
+// Maybe this can serve in some shared lib? (Rob)
+void
+SVGPathParser::calculateArc(bool relative, double &curx, double &cury, double angle, double x, double y, double r1, double r2, bool largeArcFlag, bool sweepFlag)
+{
+ double sin_th, cos_th;
+ double a00, a01, a10, a11;
+ double x0, y0, x1, y1, xc, yc;
+ double d, sfactor, sfactor_sq;
+ double th0, th1, th_arc;
+ int i, n_segs;
+
+ sin_th = sin(angle * (M_PI / 180.0));
+ cos_th = cos(angle * (M_PI / 180.0));
+
+ double dx;
+
+ if(!relative)
+ dx = (curx - x) / 2.0;
+ else
+ dx = -x / 2.0;
+
+ double dy;
+
+ if(!relative)
+ dy = (cury - y) / 2.0;
+ else
+ dy = -y / 2.0;
+
+ double _x1 = cos_th * dx + sin_th * dy;
+ double _y1 = -sin_th * dx + cos_th * dy;
+ double Pr1 = r1 * r1;
+ double Pr2 = r2 * r2;
+ double Px = _x1 * _x1;
+ double Py = _y1 * _y1;
+
+ // Spec : check if radii are large enough
+ double check = Px / Pr1 + Py / Pr2;
+ if(check > 1)
+ {
+ r1 = r1 * sqrt(check);
+ r2 = r2 * sqrt(check);
+ }
+
+ a00 = cos_th / r1;
+ a01 = sin_th / r1;
+ a10 = -sin_th / r2;
+ a11 = cos_th / r2;
+
+ x0 = a00 * curx + a01 * cury;
+ y0 = a10 * curx + a11 * cury;
+
+ if(!relative)
+ x1 = a00 * x + a01 * y;
+ else
+ x1 = a00 * (curx + x) + a01 * (cury + y);
+
+ if(!relative)
+ y1 = a10 * x + a11 * y;
+ else
+ y1 = a10 * (curx + x) + a11 * (cury + y);
+
+ /* (x0, y0) is current point in transformed coordinate space.
+ (x1, y1) is new point in transformed coordinate space.
+
+ The arc fits a unit-radius circle in this space.
+ */
+
+ d = (x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0);
+
+ sfactor_sq = 1.0 / d - 0.25;
+
+ if(sfactor_sq < 0)
+ sfactor_sq = 0;
+
+ sfactor = sqrt(sfactor_sq);
+
+ if(sweepFlag == largeArcFlag)
+ sfactor = -sfactor;
+
+ xc = 0.5 * (x0 + x1) - sfactor * (y1 - y0);
+ yc = 0.5 * (y0 + y1) + sfactor * (x1 - x0);
+
+ /* (xc, yc) is center of the circle. */
+ th0 = atan2(y0 - yc, x0 - xc);
+ th1 = atan2(y1 - yc, x1 - xc);
+
+ th_arc = th1 - th0;
+ if(th_arc < 0 && sweepFlag)
+ th_arc += 2 * M_PI;
+ else if(th_arc > 0 && !sweepFlag)
+ th_arc -= 2 * M_PI;
+
+ n_segs = (int) (int) ceil(fabs(th_arc / (M_PI * 0.5 + 0.001)));
+
+ for(i = 0; i < n_segs; i++)
+ {
+ {
+ double sin_th, cos_th;
+ double a00, a01, a10, a11;
+ double x1, y1, x2, y2, x3, y3;
+ double t;
+ double th_half;
+
+ double _th0 = th0 + i * th_arc / n_segs;
+ double _th1 = th0 + (i + 1) * th_arc / n_segs;
+
+ sin_th = sin(angle * (M_PI / 180.0));
+ cos_th = cos(angle * (M_PI / 180.0));
+
+ /* inverse transform compared with rsvg_path_arc */
+ a00 = cos_th * r1;
+ a01 = -sin_th * r2;
+ a10 = sin_th * r1;
+ a11 = cos_th * r2;
+
+ th_half = 0.5 * (_th1 - _th0);
+ t = (8.0 / 3.0) * sin(th_half * 0.5) * sin(th_half * 0.5) / sin(th_half);
+ x1 = xc + cos(_th0) - t * sin(_th0);
+ y1 = yc + sin(_th0) + t * cos(_th0);
+ x3 = xc + cos(_th1);
+ y3 = yc + sin(_th1);
+ x2 = x3 + t * sin(_th1);
+ y2 = y3 - t * cos(_th1);
+
+ svgCurveToCubic( a00 * x1 + a01 * y1, a10 * x1 + a11 * y1, a00 * x2 + a01 * y2, a10 * x2 + a11 * y2, a00 * x3 + a01 * y3, a10 * x3 + a11 * y3 );
+ }
+ }
+
+ if(!relative)
+ curx = x;
+ else
+ curx += x;
+
+ if(!relative)
+ cury = y;
+ else
+ cury += y;
+}
+
+void
+SVGPathParser::svgLineToHorizontal( double, bool )
+{
+}
+
+void
+SVGPathParser::svgLineToVertical( double, bool )
+{
+}
+
+void
+SVGPathParser::svgCurveToCubicSmooth( double, double, double, double, bool )
+{
+}
+
+void
+SVGPathParser::svgCurveToQuadratic( double, double, double, double, bool )
+{
+}
+
+void
+SVGPathParser::svgCurveToQuadraticSmooth( double, double, bool )
+{
+}
+
+void
+SVGPathParser::svgArcTo( double, double, double, double, double, bool, bool, bool )
+{
+}
diff --git a/ksvg/impl/svgpathparser.h b/ksvg/impl/svgpathparser.h
new file mode 100644
index 00000000..3a9495d0
--- /dev/null
+++ b/ksvg/impl/svgpathparser.h
@@ -0,0 +1,63 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002, 2003 The Karbon Developers
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __SVGPATHPARSER_H__
+#define __SVGPATHPARSER_H__
+
+class QString;
+
+namespace KSVG
+{
+ const char *getNumber( const char *, double & );
+}
+
+/**
+ * Parser for svg path data, contained in the d attribute.
+ *
+ * The parser delivers encountered commands and parameters by calling
+ * methods that correspond to those commands. Clients have to derive
+ * from this class and implement the abstract command methods.
+ *
+ * There are two operating modes. By default the parser just delivers unaltered
+ * svg path data commands and parameters. In the second mode, it will convert all
+ * relative coordinates to absolute ones, and convert all curves to cubic beziers.
+ */
+class SVGPathParser
+{
+public:
+ void parseSVG( const QString &d, bool process = false );
+
+ static const char *getCoord( const char *, double & );
+
+protected:
+ virtual void svgMoveTo( double x1, double y1, bool closed, bool abs = true ) = 0;
+ virtual void svgLineTo( double x1, double y1, bool abs = true ) = 0;
+ virtual void svgLineToHorizontal( double x, bool abs = true );
+ virtual void svgLineToVertical( double y, bool abs = true );
+ virtual void svgCurveToCubic( double x1, double y1, double x2, double y2, double x, double y, bool abs = true ) = 0;
+ virtual void svgCurveToCubicSmooth( double x, double y, double x2, double y2, bool abs = true );
+ virtual void svgCurveToQuadratic( double x, double y, double x1, double y1, bool abs = true );
+ virtual void svgCurveToQuadraticSmooth( double x, double y, bool abs = true );
+ virtual void svgArcTo( double x, double y, double r1, double r2, double angle, bool largeArcFlag, bool sweepFlag, bool abs = true );
+ virtual void svgClosePath() = 0;
+private:
+ void calculateArc( bool relative, double &curx, double &cury, double angle, double x, double y, double r1, double r2, bool largeArcFlag, bool sweepFlag );
+};
+
+#endif
diff --git a/ksvg/plugin/Makefile.am b/ksvg/plugin/Makefile.am
new file mode 100644
index 00000000..73202df4
--- /dev/null
+++ b/ksvg/plugin/Makefile.am
@@ -0,0 +1,29 @@
+SUBDIRS = backends .
+
+INCLUDES = $(FREETYPE_CFLAGS) -I$(top_srcdir)/ksvg -I$(top_srcdir)/ksvg/dom -I$(top_srcdir)/ksvg/impl -I$(top_srcdir)/ksvg/ecma -I$(top_srcdir)/ksvg/core -I$(top_srcdir)/ksvg/impl/libs/libtext2path/src $(all_includes)
+METASOURCES = AUTO
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+
+kde_module_LTLIBRARIES = libksvgplugin.la svgthumbnail.la
+
+libksvgplugin_la_SOURCES = ksvg_plugin.cpp ksvg_factory.cpp ksvg_widget.cpp
+libksvgplugin_la_LIBADD = ../libksvg.la
+libksvgplugin_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+
+ksvginclude_HEADERS = ksvg_plugin.h
+ksvgincludedir = $(includedir)/ksvg
+
+kde_services_DATA = ksvgplugin.desktop
+
+svgthumbnail_la_SOURCES = svgcreator.cpp
+svgthumbnail_la_LIBADD = ../libksvg.la
+svgthumbnail_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+
+services_DATA = svgthumbnail.desktop
+servicesdir = $(kde_servicesdir)
+
+partdir = $(kde_datadir)/ksvg
+part_DATA = ksvgplugin.rc
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp -o $(podir)/ksvgplugin.pot
diff --git a/ksvg/plugin/backends/Makefile.am b/ksvg/plugin/backends/Makefile.am
new file mode 100644
index 00000000..eb3c3089
--- /dev/null
+++ b/ksvg/plugin/backends/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = libart #agg
diff --git a/ksvg/plugin/backends/agg/AggCanvas.cpp b/ksvg/plugin/backends/agg/AggCanvas.cpp
new file mode 100644
index 00000000..245d36e1
--- /dev/null
+++ b/ksvg/plugin/backends/agg/AggCanvas.cpp
@@ -0,0 +1,130 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "AggCanvas.h"
+#include "SVGShapeImpl.h"
+#include "SVGPaintImpl.h"
+#include "SVGPaint.h"
+#include "SVGGradientElementImpl.h"
+#include "SVGLinearGradientElementImpl.h"
+#include "SVGRadialGradientElementImpl.h"
+#include "SVGPatternElementImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include <kdebug.h>
+
+#include "AggCanvasItems.h"
+#include "GlyphTracerAgg.h"
+
+#include "agg_vertex_iterator.h"
+#include "agg_bounding_rect.h"
+
+using namespace KSVG;
+
+AggCanvas::AggCanvas(unsigned int width, unsigned int height) : KSVGCanvas(width, height)
+{
+ m_fontContext = new T2P::Converter(new T2P::GlyphTracerAgg());
+}
+
+void AggCanvas::setRenderBufferSize(int w, int h)
+{
+ KSVGCanvas::setRenderBufferSize(w, h);
+ m_buf.attach(m_buffer, m_width, m_height, m_width * m_nrChannels);
+}
+
+void AggCanvas::setBuffer(unsigned char *buffer)
+{
+ KSVGCanvas::setBuffer(buffer);
+ m_buf.attach(m_buffer, m_width, m_height, m_width * m_nrChannels);
+}
+
+T2P::BezierPath *AggCanvas::toBezierPath(CanvasItem *item) const
+{
+ // Only handle AggPath items
+ return dynamic_cast<AggPath *>(item);
+}
+
+// drawing primitives
+CanvasItem *AggCanvas::createRectangle(SVGRectElementImpl *rect)
+{
+ return new AggRectangle(this, rect);
+}
+
+CanvasItem *AggCanvas::createEllipse(SVGEllipseElementImpl *ellipse)
+{
+ return new AggEllipse(this, ellipse);
+}
+
+CanvasItem *AggCanvas::createCircle(SVGCircleElementImpl *circle)
+{
+ return new AggCircle(this, circle);
+}
+
+CanvasItem *AggCanvas::createLine(SVGLineElementImpl *line)
+{
+ return new AggLine(this, line);
+}
+
+CanvasItem *AggCanvas::createPolyline(SVGPolylineElementImpl *poly)
+{
+ return new AggPolyline(this, poly);
+}
+
+CanvasItem *AggCanvas::createPolygon(SVGPolygonElementImpl *poly)
+{
+ return new AggPolygon(this, poly);
+}
+
+CanvasItem *AggCanvas::createPath(SVGPathElementImpl *path)
+{
+ return new AggPath(this, path);
+}
+
+CanvasItem *AggCanvas::createClipPath(SVGClipPathElementImpl *)
+{
+ return 0;
+}
+
+CanvasItem *AggCanvas::createImage(SVGImageElementImpl *image)
+{
+ return new AggImage(this, image);
+}
+
+CanvasItem *AggCanvas::createCanvasMarker(SVGMarkerElementImpl *marker)
+{
+ return new AggMarker(this, marker);
+}
+
+CanvasItem *AggCanvas::createText(SVGTextElementImpl *text)
+{
+ return new AggText(this, text);
+}
+
+CanvasPaintServer *AggCanvas::createPaintServer(SVGElementImpl *pserver)
+{
+ AggPaintServer *result = 0;
+ if(dynamic_cast<SVGLinearGradientElementImpl *>(pserver))
+ result = new AggLinearGradient(dynamic_cast<SVGLinearGradientElementImpl *>(pserver));
+ else if(dynamic_cast<SVGRadialGradientElementImpl *>(pserver))
+ result = new AggRadialGradient(dynamic_cast<SVGRadialGradientElementImpl *>(pserver));
+ else if(dynamic_cast<SVGPatternElementImpl *>(pserver))
+ result = new AggPattern(dynamic_cast<SVGPatternElementImpl *>(pserver));
+ return result;
+}
+
diff --git a/ksvg/plugin/backends/agg/AggCanvas.h b/ksvg/plugin/backends/agg/AggCanvas.h
new file mode 100644
index 00000000..9df7a826
--- /dev/null
+++ b/ksvg/plugin/backends/agg/AggCanvas.h
@@ -0,0 +1,77 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef AGGCANVAS_H
+#define AGGCANVAS_H
+
+#include "KSVGCanvas.h"
+
+#include "agg_basics.h"
+#include "agg_rendering_buffer.h"
+#include "agg_path_storage.h"
+#include "agg_rasterizer_scanline_aa.h"
+#include "agg_scanline_u.h"
+#include "agg_renderer_scanline.h"
+#include "agg_pixfmt_rgb24.h"
+
+namespace KSVG
+{
+
+class AggPaintServer;
+class SVGElementImpl;
+class AggCanvas : public KSVGCanvas
+{
+public:
+ AggCanvas(unsigned int width, unsigned int height);
+
+ virtual T2P::BezierPath *toBezierPath(CanvasItem *item) const;
+
+ // creating canvas items
+ virtual CanvasItem *createRectangle(SVGRectElementImpl *rect);
+ virtual CanvasItem *createEllipse(SVGEllipseElementImpl *ellipse);
+ virtual CanvasItem *createCircle(SVGCircleElementImpl *circle);
+ virtual CanvasItem *createLine(SVGLineElementImpl *line);
+ virtual CanvasItem *createPolyline(SVGPolylineElementImpl *poly);
+ virtual CanvasItem *createPolygon(SVGPolygonElementImpl *poly);
+ virtual CanvasItem *createPath(SVGPathElementImpl *path);
+ virtual CanvasItem *createClipPath(SVGClipPathElementImpl *clippath);
+ virtual CanvasItem *createImage(SVGImageElementImpl *image);
+ virtual CanvasItem *createCanvasMarker(SVGMarkerElementImpl *marker);
+ virtual CanvasItem *createText(SVGTextElementImpl *text);
+ virtual CanvasPaintServer *createPaintServer(SVGElementImpl *pserver);
+
+ virtual void setRenderBufferSize(int w, int h);
+
+ agg::rendering_buffer &buf() { return m_buf; }
+
+ float zoom() const { return m_zoom; }
+
+ agg::rasterizer_scanline_aa<> m_ras;
+
+protected:
+ virtual void setBuffer(unsigned char *buffer);
+
+protected:
+ agg::rendering_buffer m_buf;
+};
+
+};
+
+#endif
diff --git a/ksvg/plugin/backends/agg/AggCanvasFactory.cpp b/ksvg/plugin/backends/agg/AggCanvasFactory.cpp
new file mode 100644
index 00000000..439623ad
--- /dev/null
+++ b/ksvg/plugin/backends/agg/AggCanvasFactory.cpp
@@ -0,0 +1,45 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "AggCanvas.h"
+#include "AggCanvasFactory.h"
+
+using namespace KSVG;
+
+K_EXPORT_COMPONENT_FACTORY(libksvgrendereragg, AggCanvasFactory)
+
+AggCanvasFactory::AggCanvasFactory()
+{
+}
+
+AggCanvasFactory::~AggCanvasFactory()
+{
+}
+
+QObject *AggCanvasFactory::createObject(QObject *, const char *, const char *, const QStringList &args)
+{
+ unsigned int width = (*args.at(1)).toUInt();
+ unsigned int height = (*args.at(0)).toUInt();
+ return new AggCanvas(width, height);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/agg/AggCanvasFactory.h b/ksvg/plugin/backends/agg/AggCanvasFactory.h
new file mode 100644
index 00000000..9fb3ffbf
--- /dev/null
+++ b/ksvg/plugin/backends/agg/AggCanvasFactory.h
@@ -0,0 +1,45 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef AGGCANVASFACTORY_H
+#define AGGCANVASFACTORY_H
+
+#include <klibloader.h>
+
+#include "CanvasItem.h"
+#include "KSVGCanvas.h"
+
+namespace KSVG
+{
+
+class AggCanvasFactory : public KLibFactory
+{
+public:
+ AggCanvasFactory();
+ virtual ~AggCanvasFactory();
+
+ virtual QObject *createObject(QObject *parent = 0, const char *pname = 0, const char *name = "QObject", const QStringList &args = QStringList());
+};
+
+};
+
+#endif
+
+/// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/agg/AggCanvasItems.cpp b/ksvg/plugin/backends/agg/AggCanvasItems.cpp
new file mode 100644
index 00000000..4ceb6109
--- /dev/null
+++ b/ksvg/plugin/backends/agg/AggCanvasItems.cpp
@@ -0,0 +1,1747 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qimage.h>
+
+#include "SVGPaint.h"
+#include "SVGRectImpl.h"
+#include "SVGAngleImpl.h"
+#include "SVGPaintImpl.h"
+#include "SVGMatrixImpl.h"
+#include "SVGUnitTypes.h"
+#include "SVGHelperImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGPointListImpl.h"
+#include "SVGMarkerElement.h"
+#include "SVGMarkerElementImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGPathSegListImpl.h"
+#include "SVGAnimatedRectImpl.h"
+#include "SVGAnimatedAngleImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGPolygonElementImpl.h"
+#include "SVGClipPathElementImpl.h"
+#include "SVGPolylineElementImpl.h"
+#include "SVGStopElementImpl.h"
+#include "SVGGradientElement.h"
+#include "SVGGradientElementImpl.h"
+#include "SVGLinearGradientElementImpl.h"
+#include "SVGRadialGradientElementImpl.h"
+#include "SVGPatternElementImpl.h"
+#include "SVGAnimatedNumberImpl.h"
+#include "SVGAnimatedLengthListImpl.h"
+#include "SVGAnimatedEnumerationImpl.h"
+#include "SVGAnimatedStringImpl.h"
+#include "SVGPreserveAspectRatioImpl.h"
+#include "SVGAnimatedPreserveAspectRatioImpl.h"
+#include "SVGAnimatedTransformListImpl.h"
+#include "SVGTransformListImpl.h"
+#include "SVGUnitConverter.h"
+
+#include "Glyph.h"
+#include "Converter.h"
+#include "KSVGTextChunk.h"
+
+#include "agg_rasterizer_scanline_aa.h"
+#include "agg_scanline_u.h"
+#include "agg_scanline_p.h"
+#include "agg_bounding_rect.h"
+#include "agg_ellipse.h"
+#include "agg_span_image_filter_rgba32.h"
+#include "agg_color_rgba8.h"
+#include "agg_gray8.h"
+#include "agg_span_gradient.h"
+#include "agg_span_interpolator_linear.h"
+#include "agg_span_pattern_rgba32.h"
+#include "agg_renderer_scanline.h"
+
+#include "AggCanvas.h"
+#include "AggCanvasItems.h"
+
+extern "C"
+{
+/* These are in KSVGHelper.cpp */
+int linearRGBFromsRGB(int sRGB8bit);
+int sRGBFromLinearRGB(int linearRGB8bit);
+}
+
+struct color_function_profile
+{
+ color_function_profile() {}
+ color_function_profile(const agg::rgba8 *colors) :
+ m_colors(colors) {}
+
+ const agg::rgba8& operator [] (unsigned v) const
+ {
+ return m_colors[v];
+ }
+
+ const agg::rgba8 *m_colors;
+};
+
+using namespace KSVG;
+
+// agg2 helpers
+
+agg::vcgen_stroke::line_cap_e toAggLineCap(PathStrokeCapType cap)
+{
+ if(cap == PATH_STROKE_CAP_BUTT)
+ return agg::vcgen_stroke::butt_cap;
+ else if(cap == PATH_STROKE_CAP_ROUND)
+ return agg::vcgen_stroke::round_cap;
+ else
+ return agg::vcgen_stroke::square_cap;
+}
+
+template<class Source>
+stroke<Source>::stroke(Source& src, KSVG::SVGStylableImpl *style) : m_s(src)
+{
+ m_s.width(style->getStrokeWidth()->baseVal()->value());
+ m_s.line_join((agg::vcgen_stroke::line_join_e)style->getJoinStyle());
+ m_s.miter_limit(style->getStrokeMiterlimit());
+ m_s.line_cap(toAggLineCap(style->getCapStyle()));
+}
+
+template<class Source>
+dash_stroke<Source>::dash_stroke(Source& src, KSVG::SVGStylableImpl *style) : m_d(src), m_ds(m_d)
+{
+ unsigned int dashLength = style->getDashArray() ? style->getDashArray()->baseVal()->numberOfItems() : 0;
+ // there are dashes to be rendered
+ unsigned int count = (dashLength % 2) == 0 ? dashLength : dashLength * 2;
+ for(unsigned int i = 0; i < count; i += 2)
+ m_d.add_dash(style->getDashArray()->baseVal()->getItem(i % dashLength)->value(),
+ style->getDashArray()->baseVal()->getItem((i + 1) % dashLength)->value());
+ m_d.dash_start(style->getDashOffset()->baseVal()->value());
+ m_ds.width(style->getStrokeWidth()->baseVal()->value());
+ m_ds.line_join((agg::vcgen_stroke::line_join_e)style->getJoinStyle());
+ m_ds.miter_limit(style->getStrokeMiterlimit());
+ m_ds.line_cap(toAggLineCap(style->getCapStyle()));
+}
+
+template<class Source>
+dash_stroke_simple<Source>::dash_stroke_simple(Source& src, KSVG::SVGStylableImpl *style)
+{
+ //if(style->isStroked() && style->getStrokeWidth()->baseVal()->value() > 0)
+ //{
+ unsigned int dashLength = style->getDashArray() ? style->getDashArray()->baseVal()->numberOfItems() : 0;
+ if(dashLength > 0)
+ impl = new dash_stroke<Source>(src, style);
+ else
+ impl = new stroke<Source>(src, style);
+ //}
+ //else
+ //impl = 0;
+}
+
+void renderPathSolid(AggCanvas *canvas, const agg::rgba8 &color)
+{
+ agg::scanline_p8 sl;
+ if(canvas->nrChannels() == 3)
+ {
+ typedef agg::pixfmt_rgb24 pixfmt;
+ typedef agg::renderer_base<pixfmt> renderer_base;
+ typedef agg::renderer_scanline_p_solid<renderer_base> renderer_solid;
+
+ pixfmt pixf(canvas->buf());
+ renderer_base rb(pixf);
+ renderer_solid ren(rb);
+
+ ren.color(color);
+ canvas->m_ras.render(sl, ren);
+ }
+ else
+ {
+ typedef agg::pixfmt_rgba32 pixfmt;
+ typedef agg::renderer_base<pixfmt> renderer_base;
+ typedef agg::renderer_scanline_p_solid<renderer_base> renderer_solid;
+
+ pixfmt pixf(canvas->buf());
+ renderer_base rb(pixf);
+ renderer_solid ren(rb);
+
+ ren.color(color);
+ canvas->m_ras.render(sl, ren);
+ }
+}
+
+// #####
+
+BezierPathAggStroked::BezierPathAggStroked(SVGStylableImpl *style)
+: T2P::BezierPathAgg(), m_curved_trans_clipped(m_curved_trans), m_curved_stroked(m_curved, style), m_curved_stroked_trans(m_curved_stroked, m_transform), m_curved_stroked_trans_clipped(m_curved_stroked_trans), m_style(style)
+{
+}
+
+BezierPathAggStroked::BezierPathAggStroked(const T2P::BezierPathAgg &other, SVGStylableImpl *style)
+: T2P::BezierPathAgg(other), m_curved_trans_clipped(m_curved_trans), m_curved_stroked(m_curved, style), m_curved_stroked_trans(m_curved_stroked, m_transform), m_curved_stroked_trans_clipped(m_curved_stroked_trans), m_style(style)
+{
+}
+
+AggShape::AggShape(AggCanvas *c, SVGStylableImpl *style) : CanvasItem(), BezierPathAggStroked(style), m_canvas(c)
+{
+ m_context = NORMAL;
+ m_fillPainter = 0;
+ m_strokePainter = 0;
+}
+
+AggShape::~AggShape()
+{
+ freeSVPs();
+ delete m_fillPainter;
+ delete m_strokePainter;
+}
+
+QRect AggShape::bbox() const
+{
+ return m_bbox;
+}
+
+bool AggShape::fillContains(const QPoint &p)
+{
+ agg::rasterizer_scanline_aa<> ras;
+ ras.filling_rule(m_style->getFillRule() == RULE_EVENODD ? agg::fill_even_odd : agg::fill_non_zero);
+ ras.add_path(m_curved_trans);
+ bool b = ras.hit_test(p.x(), p.y());
+ return b;
+}
+
+bool AggShape::strokeContains(const QPoint &p)
+{
+ agg::rasterizer_scanline_aa<> ras;
+ ras.add_path(m_curved_stroked_trans);
+ bool b = ras.hit_test(p.x(), p.y());
+ return b;
+}
+
+void AggShape::update(CanvasItemUpdate reason, int param1, int param2)
+{
+ if(reason == UPDATE_STYLE)
+ {
+ if(!m_fillPainter || !m_strokePainter)
+ AggShape::init();
+ if(m_fillPainter)
+ m_fillPainter->update(m_style);
+ if(m_strokePainter)
+ m_strokePainter->update(m_style);
+ m_canvas->invalidate(this, false);
+ }
+ else if(reason == UPDATE_TRANSFORM)
+ {
+ freeSVPs();
+ init();
+ m_canvas->invalidate(this, true);
+ }
+ else if(reason == UPDATE_ZOOM)
+ init();
+ else if(reason == UPDATE_PAN)
+ {
+ agg::trans_affine mtx(1, 0, 0, 1, param1, param2);
+ m_transform *= mtx;
+ }
+ else if(reason == UPDATE_LINEWIDTH)
+ {
+ init();
+ m_canvas->invalidate(this, true);
+ }
+}
+
+void AggShape::draw(SVGShapeImpl *shape)
+{
+ if(!m_referenced && (!m_style->getVisible() || !m_style->getDisplay() || !shape->directRender()))
+ return;
+
+ //if(!m_strokeSVP && (!m_fillSVP || !m_style->isFilled()))
+ // init();
+ agg::rect cb;
+ if(m_canvas->nrChannels() == 3)
+ {
+ agg::pixfmt_rgb24 pixf(m_canvas->buf());
+ agg::renderer_base<agg::pixfmt_rgb24> rb(pixf);
+ cb = rb.clip_box();
+ }
+ else
+ {
+ agg::pixfmt_rgba32 pixf(m_canvas->buf());
+ agg::renderer_base<agg::pixfmt_rgba32> rb(pixf);
+ cb = rb.clip_box();
+ }
+
+ m_curved_trans_clipped.clip_box(cb.x1, cb.y1, cb.x2 + 1, cb.y2 + 1);
+ m_curved_stroked_trans_clipped.clip_box(cb.x1, cb.y1, cb.x2 + 1, cb.y2 + 1);
+
+ double x1, y1, x2, y2;
+ agg::bounding_rect(m_curved_trans, *this, 0, 1, &x1, &y1, &x2, &y2);
+ m_bbox = QRect(int(x1), int(y1), int(x2 - x1), int(y2 - y1));
+
+ m_curved.approximation_scale(pow(m_transform.scale(), 0.75));
+
+ if(m_fillPainter)
+ m_fillPainter->draw(m_canvas, m_curved_trans, m_style, shape);
+ if(m_strokePainter)
+ m_strokePainter->draw(m_canvas, m_curved_stroked_trans, m_style, shape);
+}
+
+bool AggShape::isVisible(SVGShapeImpl *shape)
+{
+ return m_referenced || (m_style->getVisible() && m_style->getDisplay() && shape->directRender());
+}
+
+void AggShape::calcSVPs(const SVGMatrixImpl *matrix)
+{
+ // transform
+ m_transform = agg::trans_affine(matrix->a(), matrix->b(), matrix->c(), matrix->d(), matrix->e(), matrix->f());
+
+ double x1, y1, x2, y2;
+ agg::bounding_rect(m_curved_trans, *this, 0, 1, &x1, &y1, &x2, &y2);
+ m_bbox = QRect(int(x1), int(y1), int(x2 - x1), int(y2 - y1));
+}
+
+void AggShape::init(const SVGMatrixImpl *)
+{
+}
+
+void AggShape::init()
+{
+ if(m_style->isFilled())
+ {
+ if(m_fillPainter == 0)
+ m_fillPainter = new AggFillPaintServer(m_style);
+ }
+ else
+ {
+ delete m_fillPainter;
+ m_fillPainter = 0;
+ }
+
+ // Spec: A zero value causes no stroke to be painted.
+ if(m_style->isStroked() && m_style->getStrokeWidth()->baseVal()->value() > 0)
+ {
+ if(m_strokePainter == 0)
+ m_strokePainter = new AggStrokePaintServer(m_style);
+ }
+ else
+ {
+ delete m_strokePainter;
+ m_strokePainter = 0;
+ }
+}
+
+void AggShape::freeSVPs()
+{
+ m_storage.remove_all();
+}
+
+// #####
+
+AggStrokePaintServer::AggStrokePaintServer(SVGStylableImpl *style)
+{
+ update(style);
+}
+
+void AggStrokePaintServer::update(SVGStylableImpl *style)
+{
+ if(style->getStrokeColor()->paintType() != SVG_PAINTTYPE_URI)
+ {
+ QColor qcolor;
+ if(style->getStrokeColor()->paintType() == SVG_PAINTTYPE_CURRENTCOLOR)
+ qcolor = style->getColor()->rgbColor().color();
+ else
+ qcolor = style->getStrokeColor()->rgbColor().color();
+
+ short opacity = static_cast<short>(style->getStrokeOpacity() * style->getOpacity() * 255);
+
+ // Spec: clamping
+ opacity = opacity < 0 ? 0 : opacity;
+ opacity = opacity > 255 ? 255 : opacity;
+
+ m_color = agg::rgba8(qcolor.red(), qcolor.green(), qcolor.blue());
+ m_color.opacity(style->getStrokeOpacity() * style->getOpacity());
+ }
+}
+
+template<class VertexSource>
+void AggStrokePaintServer::draw(AggCanvas *canvas, VertexSource &vs, SVGStylableImpl *style, SVGShapeImpl *shape)
+{
+ canvas->m_ras.reset();
+ if(style->getStrokeColor()->paintType() == SVG_PAINTTYPE_URI)
+ {
+ AggPaintServer *pserver = static_cast<AggPaintServer *>(SVGPaintServerImpl::paintServer(shape->ownerDoc(), style->getStrokeColor()->uri().string()));
+ if(!pserver) return;
+ pserver->setBBoxTarget(shape);
+
+ // TODO : Clipping
+ if(!pserver->finalized())
+ pserver->finalizePaintServer();
+ canvas->m_ras.add_path(vs);
+ pserver->render(canvas);
+ }
+ else
+ {
+ canvas->m_ras.add_path(vs);
+ renderPathSolid(canvas, m_color);
+ }
+}
+
+AggFillPaintServer::AggFillPaintServer(SVGStylableImpl *style)
+{
+ update(style);
+}
+
+void AggFillPaintServer::update(SVGStylableImpl *style)
+{
+ if(style->getFillColor()->paintType() != SVG_PAINTTYPE_URI)
+ {
+ QColor qcolor;
+ if(style->getFillColor()->paintType() == SVG_PAINTTYPE_CURRENTCOLOR)
+ qcolor = style->getColor()->rgbColor().color();
+ else
+ qcolor = style->getFillColor()->rgbColor().color();
+
+ short opacity = static_cast<short>(style->getFillOpacity() * style->getOpacity() * 255);
+
+ // Spec: clamping
+ opacity = opacity < 0 ? 0 : opacity;
+ opacity = opacity > 255 ? 255 : opacity;
+
+ m_color = agg::rgba8(qcolor.red(), qcolor.green(), qcolor.blue());
+ m_color.opacity(style->getFillOpacity() * style->getOpacity());
+ }
+}
+
+template<class VertexSource>
+void AggFillPaintServer::draw(AggCanvas *canvas, VertexSource &vs, SVGStylableImpl *style, SVGShapeImpl *shape)
+{
+ canvas->m_ras.reset();
+ if(style->getFillColor()->paintType() == SVG_PAINTTYPE_URI)
+ {
+ AggPaintServer *pserver = static_cast<AggPaintServer *>(SVGPaintServerImpl::paintServer(shape->ownerDoc(), style->getFillColor()->uri().string()));
+ if(!pserver) return;
+ pserver->setBBoxTarget(shape);
+
+ // TODO : Clipping
+ if(!pserver->finalized())
+ pserver->finalizePaintServer();
+ canvas->m_ras.add_path(vs);
+ pserver->render(canvas);
+ }
+ else
+ {
+ canvas->m_ras.filling_rule(style->getFillRule() == RULE_EVENODD ? agg::fill_even_odd : agg::fill_non_zero);
+ canvas->m_ras.add_path(vs);
+ renderPathSolid(canvas, m_color);
+ }
+}
+
+// #####
+
+AggRectangle::AggRectangle(AggCanvas *c, SVGRectElementImpl *rect)
+: AggShape(c, rect), m_rect(rect)
+{
+ init();
+}
+
+void AggRectangle::draw()
+{
+ if(isVisible())
+ AggShape::draw(m_rect);
+}
+
+bool AggRectangle::isVisible()
+{
+ // Spec: a value of zero disables rendering
+ return AggShape::isVisible(m_rect) && m_rect->width()->baseVal()->value() > 0 && m_rect->height()->baseVal()->value() > 0;
+}
+
+void AggRectangle::init()
+{
+ init(m_rect->screenCTM());
+}
+
+void AggRectangle::init(const SVGMatrixImpl *screenCTM)
+{
+ AggShape::init();
+ if(m_storage.total_vertices() == 0)
+ {
+ double x = m_rect->x()->baseVal()->value();
+ double y = m_rect->y()->baseVal()->value();
+ double width = m_rect->width()->baseVal()->value();
+ double height = m_rect->height()->baseVal()->value();
+ double rx = m_rect->rx()->baseVal()->value();
+ double ry = m_rect->ry()->baseVal()->value();
+
+ // Spec: If there is no rx or ry specified, draw a normal rect
+ if(rx == -1 && ry == -1)
+ {
+ m_storage.move_to(x, y);
+ m_storage.line_to(x + width, y);
+ m_storage.line_to(x + width, y + height);
+ m_storage.line_to(x, y + height);
+ }
+ else
+ {
+ int i = 0;
+
+ // Spec: If rx isn't specified, but ry, set rx to ry
+ if(rx == -1)
+ rx = ry;
+
+ // Spec: If ry isn't specified, but rx, set ry to rx
+ if(ry == -1)
+ ry = rx;
+
+ // Spec: If rx is greater than half of the width of the rectangle
+ // then set rx to half of the width
+ if(rx > width / 2)
+ rx = width / 2;
+
+ // Spec: If ry is greater than half of the height of the rectangle
+ // then set ry to half of the height
+ if(ry > height / 2)
+ ry = height / 2;
+
+ m_storage.move_to(x + rx, y);
+
+ i++;
+ m_storage.curve4(x + rx * (1 - 0.552), y, x, y + ry * (1 - 0.552), x, y + ry);
+ i++;
+ if(ry < height / 2)
+ {
+ m_storage.line_to(x, y + height - ry);
+ i++;
+ }
+ m_storage.curve4(x, y + height - ry * (1 - 0.552), x + rx * (1 - 0.552), y + height, x + rx, y + height);
+ i++;
+ if(rx < width / 2)
+ {
+ m_storage.line_to(x + width - rx, y + height);
+ i++;
+ }
+ m_storage.curve4(x + width - rx * (1 - 0.552), y + height, x + width, y + height - ry * (1 - 0.552), x + width, y + height - ry);
+ i++;
+ if(ry < height / 2)
+ {
+ m_storage.line_to(x + width, y + ry);
+ i++;
+ }
+ m_storage.curve4(x + width, y + ry * (1 - 0.552), x + width - rx * (1 - 0.552), y, x + width - rx, y);
+ i++;
+ if(rx < width / 2)
+ {
+ m_storage.line_to(x + rx, y);
+ i++;
+ }
+ }
+ m_storage.close_polygon();
+ }
+ //if(m_context == NORMAL)
+ calcSVPs(screenCTM);
+ //else
+ // calcClipSVP(vec, m_rect, screenCTM, &m_fillSVP);
+}
+
+// #####
+
+AggEllipse::AggEllipse(AggCanvas *c, SVGEllipseElementImpl *ellipse)
+: AggShape(c, ellipse), m_ellipse(ellipse)
+{
+ init();
+}
+
+void AggEllipse::draw()
+{
+ if(isVisible())
+ AggShape::draw(m_ellipse);
+}
+
+bool AggEllipse::isVisible()
+{
+ // Spec: dont render when rx and/or ry is zero
+ return AggShape::isVisible(m_ellipse) && m_ellipse->rx()->baseVal()->value() > 0 && m_ellipse->ry()->baseVal()->value() > 0;
+}
+
+void AggEllipse::init()
+{
+ init(m_ellipse->screenCTM());
+}
+
+void AggEllipse::init(const SVGMatrixImpl *screenCTM)
+{
+ AggShape::init();
+ if(m_storage.total_vertices() == 0)
+ {
+ double rx = m_ellipse->rx()->baseVal()->value();
+ double ry = m_ellipse->ry()->baseVal()->value();
+ double cx = m_ellipse->cx()->baseVal()->value();
+ double cy = m_ellipse->cy()->baseVal()->value();
+
+ agg::ellipse ell(cx, cy, rx, ry, 100);
+ ell.rewind(0);
+ double x, y;
+ unsigned int cmd;
+ while((cmd = ell.vertex(&x, &y)) != agg::path_cmd_stop)
+ m_storage.add_vertex(x, y, cmd);
+ m_storage.close_polygon();
+ }
+ //if(m_context == NORMAL)
+ calcSVPs(screenCTM);
+ //else
+ // calcClipSVP(vec2, m_ellipse, screenCTM, &m_fillSVP);
+}
+
+// #####
+
+AggCircle::AggCircle(AggCanvas *c, SVGCircleElementImpl *circle)
+: AggShape(c, circle), m_circle(circle)
+{
+ init();
+}
+
+void AggCircle::draw()
+{
+ if(isVisible())
+ AggShape::draw(m_circle);
+}
+
+bool AggCircle::isVisible()
+{
+ // Spec: a value of zero disables rendering
+ return AggShape::isVisible(m_circle) && m_circle->r()->baseVal()->value() > 0;
+}
+
+void AggCircle::init()
+{
+ init(m_circle->screenCTM());
+}
+
+void AggCircle::init(const SVGMatrixImpl *screenCTM)
+{
+ AggShape::init();
+ if(m_storage.total_vertices() == 0)
+ {
+ double r = m_circle->r()->baseVal()->value();
+ double cx = m_circle->cx()->baseVal()->value();
+ double cy = m_circle->cy()->baseVal()->value();
+
+ agg::ellipse ell(cx, cy, r, r, 100);
+ ell.rewind(0);
+ double x, y;
+ unsigned int cmd;
+ while((cmd = ell.vertex(&x, &y)) != agg::path_cmd_stop)
+ m_storage.add_vertex(x, y, cmd);
+ m_storage.close_polygon();
+ }
+ //if(m_context == NORMAL)
+ calcSVPs(screenCTM);
+ //else
+ // calcClipSVP(vec2, m_ellipse, screenCTM, &m_fillSVP);
+}
+
+// #####
+
+AggLine::AggLine(AggCanvas *c, SVGLineElementImpl *line)
+: AggShape(c, line), MarkerHelper(), m_line(line)
+{
+ init();
+}
+
+AggLine::~AggLine()
+{
+}
+
+void AggLine::draw()
+{
+ if(isVisible())
+ {
+ // transform ( zoom?)
+ //agg::trans_affine transform = m_transform;
+ //agg::trans_affine mtx(m_canvas->zoom(), 0, 0, m_canvas->zoom(), m_canvas->pan().x(), m_canvas->pan().y());
+ //m_transform *= mtx;
+ //m_curved.approximation_scale(pow(m_transform.scale(), 0.75));
+
+ if(m_style->isStroked())
+ {
+ m_canvas->m_ras.reset();
+ m_canvas->m_ras.add_path(m_curved_stroked_trans);
+ QColor qcolor;
+ if(m_style->getStrokeColor()->paintType() == SVG_PAINTTYPE_CURRENTCOLOR)
+ qcolor = m_style->getColor()->rgbColor().color();
+ else
+ qcolor = m_style->getStrokeColor()->rgbColor().color();
+ agg::rgba8 color(qcolor.red(), qcolor.green(), qcolor.blue());
+ color.opacity(m_style->getStrokeOpacity() * m_style->getOpacity());
+ renderPathSolid(m_canvas, color);
+ }
+ //m_transform = transform;
+
+ if(m_line->hasMarkers())
+ {
+ double x1 = m_line->x1()->baseVal()->value();
+ double y1 = m_line->y1()->baseVal()->value();
+ double x2 = m_line->x2()->baseVal()->value();
+ double y2 = m_line->y2()->baseVal()->value();
+ double slope = SVGAngleImpl::todeg(atan2(y2 - y1, x2 - x1));
+
+ if(m_line->hasStartMarker())
+ doStartMarker(m_line, m_line, x1, y1, slope);
+ if(m_line->hasEndMarker())
+ doEndMarker(m_line, m_line, x2, y2, slope);
+ }
+ }
+}
+
+bool AggLine::isVisible()
+{
+ return AggShape::isVisible(m_line);
+}
+
+void AggLine::init()
+{
+ init(m_line->screenCTM());
+}
+
+void AggLine::init(const SVGMatrixImpl *screenCTM)
+{
+ AggShape::init();
+ if(m_storage.total_vertices() == 0)
+ {
+ m_storage.move_to(m_line->x1()->baseVal()->value(), m_line->y1()->baseVal()->value());
+ // A subpath consisting of a moveto and lineto to the same exact location or a subpath consisting of a moveto
+ // and a closepath will be stroked only if the 'stroke-linecap' property is set to "round", producing a circle
+ // centered at the given point.
+ double x2 = m_line->x2()->baseVal()->value();
+ double y2 = m_line->y2()->baseVal()->value();
+ if(x2 == m_line->x1()->baseVal()->value() && y2 == m_line->y1()->baseVal()->value() && m_line->getCapStyle() == PATH_STROKE_CAP_ROUND)
+ m_storage.line_to(x2 + .5, y2);
+ else
+ m_storage.line_to(x2, y2);
+ }
+ //if(m_context == NORMAL)
+ calcSVPs(screenCTM);
+ //else
+ // calcClipSVP(polyline, m_poly, screenCTM, &m_fillSVP);
+}
+
+// #####
+AggPoly::AggPoly(AggCanvas *c, SVGPolyElementImpl *poly)
+: AggShape(c, poly), MarkerHelper(), m_poly(poly)
+{
+}
+
+AggPoly::~AggPoly()
+{
+}
+
+void AggPoly::init()
+{
+ init(m_poly->screenCTM());
+}
+
+void AggPoly::draw()
+{
+ if(isVisible())
+ {
+ AggShape::draw(m_poly);
+
+ if(m_poly->hasMarkers())
+ m_poly->drawMarkers();
+ }
+}
+
+bool AggPoly::isVisible()
+{
+ return AggShape::isVisible(m_poly);
+}
+
+// #####
+AggPolyline::AggPolyline(AggCanvas *c, SVGPolylineElementImpl *poly)
+: AggPoly(c, poly)
+{
+ AggPoly::init();
+}
+
+AggPolyline::~AggPolyline()
+{
+}
+
+void AggPolyline::init(const SVGMatrixImpl *screenCTM)
+{
+ AggShape::init();
+ if(m_storage.total_vertices() == 0)
+ {
+ unsigned int numberOfPoints = m_poly->points()->numberOfItems();
+
+ if(numberOfPoints < 1)
+ return;
+
+ m_storage.move_to(m_poly->points()->getItem(0)->x(), m_poly->points()->getItem(0)->y());
+
+ // A subpath consisting of a moveto and lineto to the same exact location or a subpath consisting of a moveto
+ // and a closepath will be stroked only if the 'stroke-linecap' property is set to "round", producing a circle
+ // centered at the given point.
+ if(numberOfPoints == 2)
+ {
+ double x1 = m_poly->points()->getItem(1)->x();
+ double y1 = m_poly->points()->getItem(1)->y();
+ if(x1 == m_poly->points()->getItem(0)->x() && y1 == m_poly->points()->getItem(0)->y() && m_poly->getCapStyle() == PATH_STROKE_CAP_ROUND)
+ m_storage.line_to(m_poly->points()->getItem(1)->x() + .5, m_poly->points()->getItem(1)->y());
+ else
+ m_storage.line_to(m_poly->points()->getItem(1)->x(), m_poly->points()->getItem(1)->y());
+ }
+ else
+ {
+ unsigned int index;
+ for(index = 1; index < numberOfPoints; index++)
+ m_storage.line_to(m_poly->points()->getItem(index)->x(), m_poly->points()->getItem(index)->y());
+ }
+ }
+ //if(m_context == NORMAL)
+ calcSVPs(screenCTM);
+ //else
+ // calcClipSVP(polyline, m_poly, screenCTM, &m_fillSVP);
+}
+
+// #####
+
+AggPolygon::AggPolygon(AggCanvas *c, SVGPolygonElementImpl *poly)
+: AggPoly(c, poly)
+{
+ AggPoly::init();
+}
+
+AggPolygon::~AggPolygon()
+{
+}
+
+void AggPolygon::init(const SVGMatrixImpl *screenCTM)
+{
+ AggShape::init();
+ if(m_storage.total_vertices() == 0)
+ {
+ int numberOfPoints = m_poly->points()->numberOfItems();
+
+ if(numberOfPoints < 1)
+ return;
+
+ m_storage.move_to(m_poly->points()->getItem(0)->x(), m_poly->points()->getItem(0)->y());
+
+ int index;
+ for(index = 1; index < numberOfPoints; index++)
+ m_storage.line_to(m_poly->points()->getItem(index)->x(), m_poly->points()->getItem(index)->y());
+
+ m_storage.line_to(m_poly->points()->getItem(0)->x(), m_poly->points()->getItem(0)->y());
+ m_storage.close_polygon();
+ }
+ //if(m_context == NORMAL)
+ calcSVPs(screenCTM);
+ //else
+ // calcClipSVP(polygon, m_poly, screenCTM, &m_fillSVP);
+}
+
+// #####
+
+AggPath::AggPath(AggCanvas *c, SVGPathElementImpl *path)
+: AggShape(c, path), SVGPathParser(), MarkerHelper(), m_path(path)
+{
+ init();
+}
+
+AggPath::~AggPath()
+{
+}
+
+void AggPath::draw()
+{
+ AggShape::draw(m_path);
+
+ if(m_path->hasMarkers())
+ {
+ SVGPathElementImpl::MarkerData markers = m_path->markerData();
+ int numMarkers = markers.numMarkers();
+
+ if(m_path->hasStartMarker())
+ doStartMarker(m_path, m_path, markers.marker(0).x, markers.marker(0).y, markers.marker(0).angle);
+
+ for(int i = 1; i < numMarkers - 1; i++)
+ {
+ if(m_path->hasMidMarker())
+ doMidMarker(m_path, m_path, markers.marker(i).x, markers.marker(i).y, markers.marker(i).angle);
+ }
+
+ if(m_path->hasEndMarker())
+ doEndMarker(m_path, m_path, markers.marker(numMarkers - 1).x, markers.marker(numMarkers - 1).y, markers.marker(numMarkers - 1).angle);
+ }
+}
+
+bool AggPath::isVisible()
+{
+ return AggShape::isVisible(m_path);
+}
+
+void AggPath::init()
+{
+ init(m_path->screenCTM());
+}
+
+void AggPath::init(const SVGMatrixImpl *screenCTM)
+{
+ AggShape::init();
+ if(m_storage.total_vertices() == 0)
+ {
+ if(!m_path->getAttribute("d").string().isEmpty())
+ {
+ m_storage.start_new_path();
+ parseSVG(m_path->getAttribute("d").string(), true);
+
+ // A subpath consisting of a moveto and lineto to the same exact location or a subpath consisting of a moveto
+ // and a closepath will be stroked only if the 'stroke-linecap' property is set to "round", producing a circle
+ // centered at the given point.
+ if(m_storage.total_vertices() == 2 && agg::is_line_to(m_storage.command(1)))
+ {
+ double x1, y1;
+ double x2, y2;
+ m_storage.vertex(0, &x1, &y1);
+ m_storage.vertex(1, &x2, &y2);
+ if(x1 == x2 && y1 == y2 && m_path->getCapStyle() == PATH_STROKE_CAP_ROUND)
+ m_storage.modify_vertex(1, x2 + .5, y2);
+ }
+ // TODO : handle filled paths that are not closed explicitly
+ }
+ }
+
+ // There are pure-moveto paths which reference paint servers *bah*
+ // Do NOT render them
+ bool dontrender = m_storage.total_vertices() == 1 && agg::is_move_to((*m_storage.begin()).cmd);
+ if(!dontrender && m_context == NORMAL)
+ calcSVPs(screenCTM);
+ //else
+ // calcClipSVP(ksvg_art_bez_path_to_vec(m_array.data(), 0.25), m_path, screenCTM, &m_fillSVP);
+}
+
+void AggPath::svgMoveTo(double x1, double y1, bool, bool)
+{
+ m_storage.move_to(x1, y1);
+}
+
+void AggPath::svgLineTo(double x1, double y1, bool)
+{
+ m_storage.line_to(x1, y1);
+}
+
+void AggPath::svgCurveToCubic(double x1, double y1, double x2, double y2, double x3, double y3, bool)
+{
+ m_storage.curve4(x1, y1, x2, y2, x3, y3);
+}
+
+void AggPath::svgClosePath()
+{
+ m_storage.close_polygon();
+}
+
+// #####
+
+AggMarker::AggMarker(AggCanvas *c, SVGMarkerElementImpl *marker)
+: CanvasMarker(marker), m_canvas(c)//, m_clippingRectangle(0)
+{
+}
+
+AggMarker::~AggMarker()
+{
+ //if(m_clippingRectangle)
+ // art_svp_free(m_clippingRectangle);
+}
+
+void AggMarker::init()
+{
+}
+
+void AggMarker::draw()
+{
+}
+
+void AggMarker::draw(SVGShapeImpl * /*obj*/, int /*x*/, int /*y*/, float /*lwidth*/, double /*angle*/)
+{
+}
+
+// #####
+
+AggImage::AggImage(AggCanvas *c, SVGImageElementImpl *image)
+: m_canvas(c), m_image(image)
+{
+}
+
+AggImage::~AggImage()
+{
+}
+
+void AggImage::draw()
+{
+ if(isVisible())
+ {
+ //KSVGPolygon clippingPolygon = m_image->clippingShape();
+
+ QImage *img = m_image->image();
+ if(!img) return;
+ QImage image = m_image->scaledImage();
+ agg::rendering_buffer source_buffer;
+ source_buffer.attach(image.bits(), image.width(), image.height(), image.width() * 4);
+
+ typedef agg::pixfmt_rgb24 pixfmt;
+ typedef agg::renderer_base<pixfmt> renderer_base;
+
+ pixfmt pixf(m_canvas->buf());
+ renderer_base rb(pixf);
+
+ typedef agg::span_interpolator_linear<> interpolator_type;
+ typedef agg::span_image_filter_rgba32_bilinear<agg::order_bgra32, interpolator_type> span_gen_type;
+ typedef agg::renderer_scanline_u<renderer_base, span_gen_type> renderer_type;
+ SVGMatrixImpl *ctm = m_image->scaledImageMatrix();
+ agg::trans_affine img_mtx(ctm->a(), ctm->b(), ctm->c(), ctm->d(), ctm->e(), ctm->f());
+ kdDebug() << "ctm->e() : " << ctm->e() << endl;
+ kdDebug() << "ctm->f() : " << ctm->f() << endl;
+ double x1 = 0;
+ double y1 = 0;
+ double x2 = image.width();
+ double y2 = image.height();
+ img_mtx.transform(&x1, &y1);
+ img_mtx.transform(&x2, &y2);
+ img_mtx.invert();
+
+ interpolator_type interpolator(img_mtx);
+ agg::span_allocator<agg::rgba8> sa;
+ span_gen_type sg(sa, source_buffer, agg::rgba(1, 1, 1, 0), interpolator);
+ renderer_type ri(rb, sg);
+
+ agg::scanline_u8 sl;
+
+ //rb.reset_clipping(true);
+ // Clip image against buffer
+ agg::path_storage viewp;
+ viewp.move_to(x1, y1);
+ viewp.line_to(x1, y2);
+ viewp.line_to(x2, y2);
+ viewp.line_to(x2, y1);
+ viewp.close_polygon();
+ m_canvas->m_ras.add_path(viewp);
+ m_canvas->m_ras.render(sl, ri);
+
+ ctm->deref();
+ }
+}
+
+bool AggImage::isVisible()
+{
+ return (m_referenced || (m_image->getVisible() && m_image->getDisplay() && m_image->directRender())) && m_image->image();
+}
+
+void AggImage::init()
+{
+}
+
+QRect AggImage::bbox() const
+{
+ QRect bbox(static_cast<int>(m_image->x()->baseVal()->value()),
+ static_cast<int>(m_image->y()->baseVal()->value()),
+ static_cast<int>(m_image->width()->baseVal()->value()),
+ static_cast<int>(m_image->height()->baseVal()->value()));
+
+
+ return SVGHelperImpl::fromUserspace(m_image, bbox);
+}
+
+// #####
+
+AggText::AggText(AggCanvas *c, SVGTextElementImpl *text)
+: CanvasText(text), m_canvas(c)
+{
+ init();
+ m_drawItems.setAutoDelete(true);
+}
+
+AggText::~AggText()
+{
+}
+
+bool AggText::fillContains(const QPoint &p)
+{
+ QPtrListIterator<SVPElement> it(m_drawItems);
+
+ SVPElement *fill = it.current();
+ while(fill)
+ {
+ if(fill->svp)
+ {
+ agg::rasterizer_scanline_aa<> ras;
+ ras.filling_rule(fill->element->getFillRule() == RULE_EVENODD ? agg::fill_even_odd : agg::fill_non_zero);
+ ras.add_path(fill->svp->m_curved_trans);
+ if(ras.hit_test(p.x(), p.y()))
+ return true;
+ }
+
+ fill = ++it;
+ }
+
+ return false;
+}
+
+bool AggText::strokeContains(const QPoint &p)
+{
+ QPtrListIterator<SVPElement> it(m_drawItems);
+
+ SVPElement *stroke = it.current();
+ while(stroke)
+ {
+ if(stroke->svp)
+ {
+ agg::rasterizer_scanline_aa<> ras;
+ ras.filling_rule(stroke->element->getFillRule() == RULE_EVENODD ? agg::fill_even_odd : agg::fill_non_zero);
+ ras.add_path(stroke->svp->m_curved_stroked_trans);
+ if(ras.hit_test(p.x(), p.y()))
+ return true;
+ }
+
+ stroke = ++it;
+ }
+
+ return false;
+}
+
+QRect AggText::bbox() const
+{
+ QRect result, rect;
+
+ QPtrListIterator<SVPElement> it(m_drawItems);
+
+ SVPElement *elem = it.current();
+ while(elem)
+ {
+ double x1, y1, x2, y2;
+ if(elem && elem->svp)
+ {
+ if(agg::bounding_rect(elem->svp->m_curved_trans, *this, 0, 1, &x1, &y1, &x2, &y2))
+ {
+ rect.setX(int(x1));
+ rect.setY(int(y1));
+ rect.setWidth(int(x2 - x1));
+ rect.setHeight(int(y2 - y1));
+
+ result = result.unite(rect);
+ }
+ }
+ elem = ++it;
+ }
+ return result;
+}
+
+void AggText::update(CanvasItemUpdate reason, int param1, int param2)
+{
+ if(reason == UPDATE_STYLE)
+ {
+ QPtrListIterator<SVPElement> it(m_drawItems);
+
+ SVPElement *svpelement = it.current();
+ SVGTextContentElementImpl *text;
+ while(svpelement)
+ {
+ text = svpelement->element;
+ if(svpelement->fillPainter)
+ svpelement->fillPainter->update(text);
+ if(svpelement->strokePainter)
+ svpelement->strokePainter->update(text);
+
+ svpelement = ++it;
+ }
+ m_canvas->invalidate(this, false);
+ }
+ else if(reason == UPDATE_TRANSFORM)
+ {
+ clearCurved();
+ init();
+ m_canvas->invalidate(this, true);
+ }
+ else if(reason == UPDATE_ZOOM)
+ {
+ clearCurved();
+ init();
+ }
+ else if(reason == UPDATE_PAN)
+ {
+ QPtrListIterator<SVPElement> it(m_drawItems);
+
+ SVPElement *svpelement = it.current();
+ T2P::BezierPathAgg *bpath;
+ while(svpelement)
+ {
+ bpath = svpelement->svp;
+ agg::trans_affine mtx(1, 0, 0, 1, param1, param2);
+ bpath->m_transform *= mtx;
+
+ svpelement = ++it;
+ }
+ }
+ /*
+ else if(reason == UPDATE_LINEWIDTH)
+ {
+ }*/
+}
+
+void AggText::draw()
+{
+ QPtrListIterator<SVPElement> it(m_drawItems);
+
+ SVPElement *svpelement = it.current();
+ BezierPathAggStroked *bpath;
+ SVGTextContentElementImpl *text;
+
+ while(svpelement)
+ {
+ bpath = svpelement->svp;
+ text = svpelement->element;
+ if(!text->getVisible() || !text->getDisplay() || !text->directRender())
+ return;
+
+ bpath->m_curved.approximation_scale(pow(bpath->m_transform.scale(), 1.25));
+
+ if(svpelement->fillPainter)
+ svpelement->fillPainter->draw(m_canvas, bpath->m_curved_trans, text, text);
+ if(svpelement->strokePainter)
+ svpelement->strokePainter->draw(m_canvas, bpath->m_curved_stroked_trans, text, text);
+
+ svpelement = ++it;
+ }
+}
+
+bool AggText::isVisible()
+{
+ bool foundVisible = false;
+ QPtrListIterator<SVPElement> it(m_drawItems);
+
+ SVPElement *svpelement = it.current();
+ SVGTextContentElementImpl *text;
+
+ while(svpelement)
+ {
+ text = svpelement->element;
+ if(text->getVisible() && text->getDisplay() && text->directRender())
+ {
+ foundVisible = true;
+ break;
+ }
+
+ svpelement = ++it;
+ }
+
+ return foundVisible;
+}
+
+void AggText::init()
+{
+ init(m_text->screenCTM());
+}
+
+void AggText::renderCallback(SVGTextContentElementImpl *element, const SVGMatrixImpl *screenCTM, T2P::GlyphSet *glyph, T2P::GlyphLayoutParams *params, double anchor) const
+{
+ for(unsigned int i = 0; i < glyph->glyphCount(); i++)
+ {
+ T2P::GlyphAffinePair *glyphAffine = glyph->set().at(i);
+ T2P::BezierPathAgg *bpath = const_cast<T2P::BezierPathAgg *>(static_cast<const T2P::BezierPathAgg *>(glyphAffine->transformatedPath()));
+
+ // text-anchor/baseline-shift support
+ if(!params->tb())
+ bpath->m_transform = agg::trans_affine(screenCTM->a(), screenCTM->b(), screenCTM->c(), screenCTM->d(), screenCTM->e() - anchor * screenCTM->a(), screenCTM->f());
+ else
+ bpath->m_transform = agg::trans_affine(screenCTM->a(), screenCTM->b(), screenCTM->c(), screenCTM->d(), screenCTM->e(), screenCTM->f() - anchor * screenCTM->d());
+
+ SVPElement *svpelement = new SVPElement();
+ svpelement->svp = new BezierPathAggStroked(*bpath, element);
+ svpelement->element = element;
+
+ if(element->isFilled())
+ svpelement->fillPainter = new AggFillPaintServer(element);
+
+ // Spec: A zero value causes no stroke to be painted.
+ if(element->isStroked() && element->getStrokeWidth()->baseVal()->value() > 0)
+ svpelement->strokePainter = new AggStrokePaintServer(element);
+ m_drawItems.append(svpelement);
+ }
+}
+
+void AggText::init(const SVGMatrixImpl *screenCTM)
+{
+ int curx = 0, cury = 0, endx = 0, endy = 0;
+ KSVGTextChunk *textChunk = CanvasText::createTextChunk(m_canvas, screenCTM, curx, cury, endx, endy);
+
+ if(textChunk->count() > 0)
+ CanvasText::createGlyphs(textChunk, m_canvas, screenCTM, curx, cury, endx, endy);
+
+ delete textChunk;
+}
+
+void AggText::clearCurved()
+{
+ m_drawItems.clear();
+ // TODO: Huh - nobody does anything with the *trans* objects?:
+}
+
+void AggText::addTextDecoration(SVGTextContentElementImpl *element, double x, double y, double width, double height) const
+{
+ if(element->isFilled() || element->isStroked())
+ {
+ // compute rect
+ BezierPathAggStroked *bpath = new BezierPathAggStroked(element);
+ bpath->m_storage.move_to(x, y);
+ bpath->m_storage.line_to(x + width, y);
+ bpath->m_storage.line_to(x + width, y + height);
+ bpath->m_storage.line_to(x, y + height);
+
+ const SVGMatrixImpl *mat = m_text->screenCTM();
+ bpath->m_transform = agg::trans_affine(mat->a(), mat->b(), mat->c(), mat->d(), mat->e(), mat->f());
+
+ SVPElement *svpelement = new SVPElement();
+ svpelement->svp = bpath;
+ svpelement->element = element;
+
+ if(element->isFilled())
+ svpelement->fillPainter = new AggFillPaintServer(element);
+
+ // Spec: A zero value causes no stroke to be painted.
+ if(element->isStroked() && element->getStrokeWidth()->baseVal()->value() > 0)
+ svpelement->strokePainter = new AggStrokePaintServer(element);
+
+ m_drawItems.append(svpelement);
+ }
+}
+
+AggText::SVPElement::~SVPElement()
+{
+ delete svp;
+ delete fillPainter;
+ delete strokePainter;
+}
+
+// ###
+
+AggGradient::AggGradient(SVGGradientElementImpl *gradient) : m_gradient(gradient)
+{
+}
+
+void AggGradient::parseGradientStops(SVGGradientElementImpl *gradient)
+{
+ bool srgb = m_gradient->getColorInterpolation() == CI_SRGB;
+ int r = 0, g = 0, b = 0, a = 255, r1 = 0, g1 = 0, b1 = 0, a1 = 255;
+ unsigned int end = 255;
+ float oldOffset = -1, newOffset = -1;
+ for(DOM::Node node = gradient->firstChild(); !node.isNull(); node = node.nextSibling())
+ {
+ SVGStopElementImpl *elem = dynamic_cast<SVGStopElementImpl *>(gradient->ownerDoc()->getElementFromHandle(node.handle()));
+ if(node.nodeName() == "stop" && elem)
+ {
+ oldOffset = newOffset;
+ newOffset = elem->offset()->baseVal();
+
+ // Spec: skip double offset specifications
+ if(oldOffset == newOffset)
+ continue;
+
+ //offsets++;
+
+ // Get color
+ QColor qStopColor;
+
+ if(elem->getStopColor()->colorType() == SVG_COLORTYPE_CURRENTCOLOR)
+ qStopColor = elem->getColor()->rgbColor().color();
+ else
+ qStopColor = elem->getStopColor()->rgbColor().color();
+
+ // Convert in an agg suitable form
+ QString tempName = qStopColor.name();
+ const char *str = tempName.latin1();
+
+ // We need to take into account fill/stroke opacity, if available (Rob)
+ float opacity = 1.0;
+ SVGStylableImpl *style = dynamic_cast<SVGStylableImpl *>(getBBoxTarget());
+ if(style)
+ opacity = style->getFillOpacity() * style->getOpacity();
+ int stopColor = 0;
+
+ for(int i = 1; str[i]; i++)
+ {
+ int hexval;
+ if(str[i] >= '0' && str[i] <= '9')
+ hexval = str[i] - '0';
+ else if (str[i] >= 'A' && str[i] <= 'F')
+ hexval = str[i] - 'A' + 10;
+ else if (str[i] >= 'a' && str[i] <= 'f')
+ hexval = str[i] - 'a' + 10;
+ else
+ break;
+
+ stopColor = (stopColor << 4) + hexval;
+ }
+
+ // Apply stop-opacity
+ opacity *= elem->stopOpacity();
+
+ // Get rgba color including stop-opacity
+ Q_UINT32 rgba = (stopColor << 8) | int(floor(int(opacity * 255.0) + 0.5));
+
+ // Convert from separated to premultiplied alpha
+ a = rgba & 0xff;
+ r = !srgb ? linearRGBFromsRGB((rgba >> 24)) : (rgba >> 24);
+ g = !srgb ? linearRGBFromsRGB(((rgba >> 16) & 0xff)) : (rgba >> 16) & 0xff;
+ b = !srgb ? linearRGBFromsRGB(((rgba >> 8) & 0xff)) : (rgba >> 8) & 0xff;
+
+ end = int(newOffset * 255);
+ // interpolate
+ unsigned int start = (oldOffset == -1) ? 0 : int(oldOffset * 255);
+ if(oldOffset == -1)
+ {
+ r1 = r;
+ g1 = g;
+ b1 = b;
+ a1 = a;
+ }
+ int diffr = r - r1;
+ int diffg = g - g1;
+ int diffb = b - b1;
+ int diffa = a - a1;
+ unsigned int nsteps = end - start;
+ for(unsigned int i = 0;i <= nsteps;i++)
+ {
+ double diff = double(i) / double(nsteps);
+ m_colorprofile[start + i].r = !srgb ? sRGBFromLinearRGB(int(r1 + diff * diffr)) : int(r1 + diff * diffr);
+ m_colorprofile[start + i].g = !srgb ? sRGBFromLinearRGB(int(g1 + diff * diffg)) : int(g1 + diff * diffg);
+ m_colorprofile[start + i].b = !srgb ? sRGBFromLinearRGB(int(b1 + diff * diffb)) : int(b1 + diff * diffb);
+ m_colorprofile[start + i].a = !srgb ? sRGBFromLinearRGB(int(a1 + diff * diffa)) : int(a1 + diff * diffa);
+ }
+ r1 = r;
+ g1 = g;
+ b1 = b;
+ a1 = a;
+ }
+ }
+ // last section
+ for(unsigned int i = end;i <= 255;i++)
+ {
+ m_colorprofile[i].r = r;
+ m_colorprofile[i].g = g;
+ m_colorprofile[i].b = b;
+ m_colorprofile[i].a = a;
+ }
+}
+
+void AggGradient::finalizePaintServer()
+{
+ parseGradientStops(m_gradient->stopsSource());
+
+ QString _href = SVGURIReferenceImpl::getTarget(m_gradient->href()->baseVal().string());
+ if(!_href.isEmpty())
+ reference(_href);
+
+ setFinalized();
+}
+
+void AggGradient::reference(const QString &/*href*/)
+{
+}
+
+void AggLinearGradient::render(AggCanvas *c)
+{
+ SVGLinearGradientElementImpl *linear = dynamic_cast<SVGLinearGradientElementImpl *>(m_gradient);
+
+ linear->converter()->finalize(getBBoxTarget(), linear->ownerSVGElement(), linear->gradientUnits()->baseVal());
+
+ double _x1 = linear->x1()->baseVal()->value();
+ double _y1 = linear->y1()->baseVal()->value();
+ double _x2 = linear->x2()->baseVal()->value();
+ double _y2 = linear->y2()->baseVal()->value();
+
+ // Adjust to gradient transform
+ SVGMatrixImpl *gradTrans = linear->gradientTransform()->baseVal()->concatenate();
+ if(gradTrans)
+ {
+ QWMatrix m = gradTrans->qmatrix();
+ m.map(_x1, _y1, &_x1, &_y1);
+ m.map(_x2, _y2, &_x2, &_y2);
+ gradTrans->deref();
+ }
+
+ // Get the basic bbox that will be the rendering area
+ SVGRectImpl *userBBox = getBBoxTarget()->getBBox();
+
+ // Compute x1, y1, x2 and y2
+ bool objectbbox = (linear->gradientUnits()->baseVal() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
+
+ // Respect current transformation matrix (so gradients zoom with...)
+ SVGTransformableImpl *transformable = dynamic_cast<SVGTransformableImpl *>(getBBoxTarget());
+ const SVGMatrixImpl *matrix = 0;
+ if(transformable)
+ matrix = transformable->screenCTM();
+
+ if(objectbbox)
+ {
+ _x1 += userBBox->x();
+ _y1 += userBBox->y();
+ _x2 += userBBox->x();
+ _y2 += userBBox->y();
+ }
+
+ userBBox->deref();
+
+ gradient_polymorphic_wrapper_base* gr_ptr = &m_linPad;
+ if(linear->spreadMethod()->baseVal() == SVG_SPREADMETHOD_REPEAT)
+ gr_ptr = &m_linRepeat;
+ else if(linear->spreadMethod()->baseVal() == SVG_SPREADMETHOD_REFLECT)
+ gr_ptr = &m_linReflect;
+
+ agg::trans_affine mtx_g1;
+ double dx = _x2 - _x1;
+ double dy = _y2 - _y1;
+ double angle = (atan2(dy, dx));
+ mtx_g1 *= agg::trans_affine_rotation(angle);
+ mtx_g1 *= agg::trans_affine_translation(_x1, _y1);
+ mtx_g1 *= agg::trans_affine(matrix->a(), matrix->b(), matrix->c(), matrix->d(), matrix->e(), matrix->f());
+ mtx_g1.invert();
+
+ double len = sqrt(dx * dx + dy * dy);
+ if(len > 0)
+ {
+ typedef agg::span_interpolator_linear<> interpolator_type;
+ typedef agg::span_gradient<agg::rgba8,
+ interpolator_type,
+ gradient_polymorphic_wrapper_base,
+ color_function_profile> gradient_span_gen;
+ typedef agg::span_allocator<gradient_span_gen::color_type> gradient_span_alloc;
+ color_function_profile colors(m_colorprofile);
+ gradient_span_alloc span_alloc;
+ interpolator_type inter(mtx_g1);
+ gradient_span_gen span_gen(span_alloc, inter, *gr_ptr, colors, 0, len);
+
+ agg::scanline_u8 sl;
+
+ if(c->nrChannels() == 3)
+ {
+ typedef agg::pixfmt_rgb24 pixfmt;
+ typedef agg::renderer_base<pixfmt> renderer_base;
+ typedef agg::renderer_scanline_u<renderer_base, gradient_span_gen> renderer_gradient;
+
+ pixfmt pixf(c->buf());
+ renderer_base rb(pixf);
+
+ renderer_gradient r1(rb, span_gen);
+ c->m_ras.render(sl, r1);
+ }
+ else
+ {
+ typedef agg::pixfmt_rgba32 pixfmt;
+ typedef agg::renderer_base<pixfmt> renderer_base;
+ typedef agg::renderer_scanline_u<renderer_base, gradient_span_gen> renderer_gradient;
+
+ pixfmt pixf(c->buf());
+ renderer_base rb(pixf);
+
+ renderer_gradient r1(rb, span_gen);
+ c->m_ras.render(sl, r1);
+ }
+ }
+}
+
+void AggRadialGradient::render(AggCanvas *c)
+{
+ SVGRadialGradientElementImpl *radial = dynamic_cast<SVGRadialGradientElementImpl *>(m_gradient);
+
+ radial->converter()->finalize(getBBoxTarget(), radial->ownerSVGElement(), radial->gradientUnits()->baseVal());
+
+ double _cx = radial->cx()->baseVal()->value();
+ double _cy = radial->cy()->baseVal()->value();
+ double _fx = radial->fx()->baseVal()->value();
+ double _fy = radial->fy()->baseVal()->value();
+ double _r = radial->r()->baseVal()->value();
+
+ // Get the basic bbox that will be the rendering area
+ SVGRectImpl *screenBBox = getBBoxTarget()->getBBoxInternal();
+
+ if(screenBBox->width() == 0 || screenBBox->height() == 0)
+ {
+ screenBBox->deref();
+ return;
+ }
+
+ screenBBox->deref();
+
+ // Compute x1, y1, x2 and y2
+ bool objectbbox = (radial->gradientUnits()->baseVal() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
+
+ SVGRectImpl *userBBox = getBBoxTarget()->getBBox();
+ float width = userBBox->width();
+ float height = userBBox->height();
+
+ if(objectbbox)
+ {
+ _cx += userBBox->x();
+ _cy += userBBox->y();
+ _fx += userBBox->x();
+ _fy += userBBox->y();
+ }
+
+ gradient_polymorphic_wrapper_base* gr_ptr = &m_radialPad;
+ if(radial->spreadMethod()->baseVal() == SVG_SPREADMETHOD_REPEAT)
+ gr_ptr = &m_radialRepeat;
+ else if(radial->spreadMethod()->baseVal() == SVG_SPREADMETHOD_REFLECT)
+ gr_ptr = &m_radialReflect;
+
+ agg::trans_affine mtx_g1;
+
+
+ // Adjust to gradient transform
+ SVGMatrixImpl *gradTrans = radial->gradientTransform()->baseVal()->concatenate();
+ if(gradTrans)
+ {
+ agg::trans_affine mtx;
+ QWMatrix m = gradTrans->qmatrix();
+ mtx = agg::trans_affine(m.m11(), m.m12(), m.m21(), m.m22(), m.dx(), m.dy());
+ gradTrans->deref();
+ mtx_g1 *= mtx;
+ }
+
+ userBBox->deref();
+
+ int diff = int(width - height); // allow slight tolerance
+ if(objectbbox && !(diff > -2 && diff < 2))
+ {
+ // make elliptical or circular depending on bbox aspect ratio
+ float ratioX = (width / height) * sqrt(2);
+ float ratioY = (height / width) * sqrt(2);
+ mtx_g1 *= agg::trans_affine_scaling((width > height) ? sqrt(2) : ratioX, (width > height) ? ratioY :sqrt(2));
+ }
+
+ mtx_g1 *= agg::trans_affine_translation(_cx, _cy);
+
+ // Respect current transformation matrix (so gradients zoom with...)
+ SVGTransformableImpl *transformable = dynamic_cast<SVGTransformableImpl *>(getBBoxTarget());
+ const SVGMatrixImpl *matrix = 0;
+ if(transformable)
+ matrix = transformable->screenCTM();
+
+ if(!matrix)
+ return;
+
+ mtx_g1 *= agg::trans_affine(matrix->a(), matrix->b(), matrix->c(), matrix->d(), matrix->e(), matrix->f());
+
+ mtx_g1.invert();
+
+ typedef agg::span_interpolator_linear<> interpolator_type;
+ typedef agg::span_gradient<agg::rgba8,
+ interpolator_type,
+ gradient_polymorphic_wrapper_base,
+ color_function_profile> gradient_span_gen;
+ typedef agg::span_allocator<gradient_span_gen::color_type> gradient_span_alloc;
+ color_function_profile colors(m_colorprofile);
+ gradient_span_alloc span_alloc;
+ interpolator_type inter(mtx_g1);
+ gradient_span_gen span_gen(span_alloc, inter, *gr_ptr, colors, 0, _r);
+
+ agg::scanline_u8 sl;
+ if(c->nrChannels() == 3)
+ {
+ typedef agg::pixfmt_rgb24 pixfmt;
+ typedef agg::renderer_base<pixfmt> renderer_base;
+ typedef agg::renderer_scanline_u<renderer_base, gradient_span_gen> renderer_gradient;
+
+ pixfmt pixf(c->buf());
+ renderer_base rb(pixf);
+
+ renderer_gradient r1(rb, span_gen);
+ c->m_ras.render(sl, r1);
+ }
+ else
+ {
+ typedef agg::pixfmt_rgba32 pixfmt;
+ typedef agg::renderer_base<pixfmt> renderer_base;
+ typedef agg::renderer_scanline_u<renderer_base, gradient_span_gen> renderer_gradient;
+
+ pixfmt pixf(c->buf());
+ renderer_base rb(pixf);
+
+ renderer_gradient r1(rb, span_gen);
+ c->m_ras.render(sl, r1);
+ }
+}
+
+AggPattern::AggPattern(SVGPatternElementImpl *pattern) : AggPaintServer(), m_pattern(pattern)
+{
+}
+
+void AggPattern::finalizePaintServer()
+{
+ m_pattern->finalizePaintServer();
+ setFinalized();
+}
+
+void AggPattern::reference(const QString &href)
+{
+ m_pattern->reference(href);
+}
+
+void AggPattern::render(AggCanvas *c)
+{
+ SVGPatternElementImpl::Tile tile = m_pattern->createTile(getBBoxTarget());
+
+ if(!tile.image().isNull())
+ {
+ QWMatrix m = tile.screenToTile();
+ double affine[6];
+
+ affine[0] = m.m11();
+ affine[1] = m.m12();
+ affine[2] = m.m21();
+ affine[3] = m.m22();
+ affine[4] = m.dx();
+ affine[5] = m.dy();
+
+ typedef agg::pixfmt_rgb24 pixfmt;
+ typedef agg::renderer_base<pixfmt> renderer_base;
+ typedef agg::renderer_scanline_p_solid<renderer_base> renderer_solid;
+
+ pixfmt pixf(c->buf());
+ renderer_base rb(pixf);
+ renderer_solid rs(rb);
+ //double width = c->buf().width();
+ //double height = c->buf().height();
+
+ typedef agg::span_pattern_rgba32<agg::order_rgba32> span_gen_type;
+ typedef agg::renderer_scanline_u<renderer_base, span_gen_type> renderer_type;
+
+ SVGRectImpl *screenBBox = getBBoxTarget()->getBBoxInternal();
+ double offset_x = affine[4];
+ double offset_y = affine[5];
+ screenBBox->deref();
+ agg::rendering_buffer m_pattern_rbuf;
+ m_pattern_rbuf.attach(tile.image().bits(), tile.image().width(), tile.image().height(), tile.image().width() * 4);
+ agg::span_allocator<agg::rgba8> sa;
+ span_gen_type sg(sa, m_pattern_rbuf, unsigned(offset_x), unsigned(offset_y));
+
+ renderer_type rp(rb, sg);
+
+ agg::scanline_u8 sl;
+ rs.color(agg::rgba(0,0,0));
+ c->m_ras.render(sl, rp);
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/agg/AggCanvasItems.h b/ksvg/plugin/backends/agg/AggCanvasItems.h
new file mode 100644
index 00000000..a8c242ec
--- /dev/null
+++ b/ksvg/plugin/backends/agg/AggCanvasItems.h
@@ -0,0 +1,500 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef AGGCANVASITEMS_H
+#define AGGCANVASITEMS_H
+
+#include "CanvasItem.h"
+#include "CanvasItems.h"
+#include "BezierPathAgg.h"
+
+#include "SVGPathElementImpl.h"
+#include "SVGPolyElementImpl.h"
+#include "SVGLineElementImpl.h"
+#include "SVGRectElementImpl.h"
+#include "SVGTextElementImpl.h"
+#include "SVGImageElementImpl.h"
+#include "SVGCircleElementImpl.h"
+#include "SVGEllipseElementImpl.h"
+
+#include "agg_basics.h"
+#include "agg_conv_transform.h"
+#include "agg_conv_curve.h"
+#include "agg_conv_dash.h"
+#include "agg_conv_stroke.h"
+#include "agg_conv_clip_polygon.h"
+#include "agg_span_gradient.h"
+
+#include "SVGBBoxTarget.h"
+
+// gradient helpers
+
+//------------------------------------------------------------------------
+class gradient_polymorphic_wrapper_base
+{
+public:
+ virtual int calculate(int x, int y, int) const = 0;
+};
+
+template<class GradientF>
+class gradient_polymorphic_wrapper : public gradient_polymorphic_wrapper_base
+{
+public:
+ virtual int calculate(int x, int y, int d) const
+ {
+ return m_gradient.calculate(x, y, d);
+ }
+private:
+ GradientF m_gradient;
+};
+
+class gradient_radial_repeat
+{
+public:
+ int calculate(int x, int y, int d) const
+ {
+ return int(sqrt(pow(x, 2) + pow(y, 2))) % d;
+ }
+};
+
+class gradient_radial_reflect
+{
+public:
+ int calculate(int x, int y, int d) const
+ {
+ int dist = int(sqrt(pow(x, 2) + pow(y, 2)));
+ if((dist / d) % 2 == 0)
+ return dist % d;
+ else
+ return d - (dist % d);
+ }
+};
+
+class gradient_linear_repeat
+{
+public:
+ int calculate(int x, int y, int d) const
+ {
+ return (x < 0) ? (d - (-x % d)) : (x % d);
+ }
+};
+
+class gradient_linear_reflect
+{
+public:
+ int calculate(int x, int y, int d) const
+ {
+ if((abs(x) / d) % 2 == 0)
+ return (x < 0) ? (-x % d) : (x % d);
+ else
+ return (x > 0) ? (d - (x % d)) : (d - (-x % d));
+ }
+};
+
+
+#define AGG_CLASS(Class, Type, Member) \
+class Agg##Class : public AggShape \
+{ \
+public: \
+ Agg##Class(AggCanvas *c, Type *Member); \
+ virtual ~Agg##Class() { } \
+ virtual void draw(); \
+ virtual bool isVisible(); \
+ virtual void init(); \
+ virtual void init(const SVGMatrixImpl *screenCTM); \
+ virtual SVGElementImpl *element() const { return m_##Member; } \
+protected: \
+ Type *m_##Member; \
+};
+
+class stroke_dash_base
+{
+public:
+ virtual ~stroke_dash_base() {}
+
+ virtual void rewind(unsigned) = 0;
+ virtual unsigned vertex(double*, double*) = 0;
+};
+
+template<class Source>
+class stroke : public stroke_dash_base
+{
+public:
+ typedef agg::conv_stroke<Source> stroke_type;
+
+ stroke(Source& src, KSVG::SVGStylableImpl *style);
+
+ void rewind(unsigned id) { m_s.rewind(id); }
+ unsigned vertex(double* x, double* y) { return m_s.vertex(x, y); }
+
+private:
+ stroke_type m_s;
+};
+
+template<class Source>
+class dash_stroke : public stroke_dash_base
+{
+public:
+ typedef agg::conv_dash<Source> dash_type;
+ typedef agg::conv_stroke<dash_type> dash_stroke_type;
+
+ dash_stroke(Source& src, KSVG::SVGStylableImpl *style);
+
+ void rewind(unsigned id) { m_ds.rewind(id); }
+ unsigned vertex(double* x, double* y) { return m_ds.vertex(x, y); }
+
+private:
+ dash_type m_d;
+ dash_stroke_type m_ds;
+};
+
+template<class Source>
+class dash_stroke_simple
+{
+public:
+ dash_stroke_simple(Source& src, KSVG::SVGStylableImpl *style);
+ ~dash_stroke_simple() { delete impl; }
+
+ void rewind(unsigned id) { impl->rewind(id); }
+ unsigned vertex(double* x, double* y) { return impl->vertex(x, y); }
+
+private:
+ stroke_dash_base *impl;
+};
+
+typedef dash_stroke_simple<curved> curved_stroked;
+typedef agg::conv_transform<curved_stroked> curved_stroked_trans;
+typedef agg::conv_clip_polygon<curved_stroked_trans> curved_stroked_trans_clipped;
+typedef agg::conv_clip_polygon<curved_trans> curved_trans_clipped;
+//typedef agg::conv_contour<curved_trans> curved_trans_contour;
+//typedef agg::conv_clip_polygon<curved_trans_contour> curved_trans_contour_clipped;
+
+namespace KSVG
+{
+ class SVGGradientElementImpl;
+ class SVGRadialGradientElementImpl;
+ class SVGLinearGradientElementImpl;
+ class SVGPatternElementImpl;
+
+ class AggPaintServer : public CanvasPaintServer
+ {
+ public:
+ AggPaintServer() : CanvasPaintServer() {}
+ virtual ~AggPaintServer() {}
+
+ virtual void finalizePaintServer() = 0;
+ virtual void reference(const QString &href) = 0;
+
+ virtual void render(AggCanvas *c) = 0;
+ };
+
+ class AggGradient : public AggPaintServer
+ {
+ public:
+ AggGradient(SVGGradientElementImpl *gradient);
+ virtual ~AggGradient() {}
+
+ void parseGradientStops(SVGGradientElementImpl *gradient);
+
+ virtual void finalizePaintServer();
+ virtual void reference(const QString &href);
+
+ protected:
+ SVGGradientElementImpl *m_gradient;
+ agg::rgba8 m_colorprofile[256];
+ };
+
+ class AggLinearGradient : public AggGradient
+ {
+ public:
+ AggLinearGradient(SVGLinearGradientElementImpl *linear) : AggGradient(linear) {}
+
+ virtual void render(AggCanvas *c);
+
+ protected:
+ gradient_polymorphic_wrapper<agg::gradient_x> m_linPad;
+ gradient_polymorphic_wrapper<gradient_linear_repeat> m_linRepeat;
+ gradient_polymorphic_wrapper<gradient_linear_reflect> m_linReflect;
+ };
+
+ class AggRadialGradient : public AggGradient
+ {
+ public:
+ AggRadialGradient(SVGRadialGradientElementImpl *radial) : AggGradient(radial) {}
+
+ virtual void render(AggCanvas *c);
+
+ protected:
+ gradient_polymorphic_wrapper<agg::gradient_circle> m_radialPad;
+ gradient_polymorphic_wrapper<gradient_radial_repeat> m_radialRepeat;
+ gradient_polymorphic_wrapper<gradient_radial_reflect> m_radialReflect;
+ };
+
+ class AggPattern : public AggPaintServer
+ {
+ public:
+ AggPattern(SVGPatternElementImpl *pattern);
+ virtual ~AggPattern() {}
+
+ virtual void finalizePaintServer();
+ virtual void reference(const QString &);
+
+ virtual void render(AggCanvas *c);
+
+ protected:
+ SVGPatternElementImpl *m_pattern;
+ };
+
+ class AggCanvas;
+
+ class AggFillPaintServer
+ {
+ public:
+ AggFillPaintServer(SVGStylableImpl *style);
+ void update(SVGStylableImpl *style);
+ template<class VertexSource>
+ void draw(AggCanvas *canvas, VertexSource &vs, SVGStylableImpl *style, SVGShapeImpl *shape);
+
+ private:
+ agg::rgba8 m_color;
+ };
+
+ class AggStrokePaintServer
+ {
+ public:
+ AggStrokePaintServer(SVGStylableImpl *style);
+ void update(SVGStylableImpl *style);
+ template<class VertexSource>
+ void draw(AggCanvas *canvas, VertexSource &vs, SVGStylableImpl *style, SVGShapeImpl *shape);
+
+ private:
+ agg::rgba8 m_color;
+ };
+
+ class BezierPathAggStroked : public T2P::BezierPathAgg
+ {
+ public:
+ BezierPathAggStroked(SVGStylableImpl *style);
+ BezierPathAggStroked(const T2P::BezierPathAgg &other, SVGStylableImpl *style);
+
+ curved_trans_clipped m_curved_trans_clipped;
+ curved_stroked m_curved_stroked;
+ curved_stroked_trans m_curved_stroked_trans;
+ curved_stroked_trans_clipped m_curved_stroked_trans_clipped;
+ SVGStylableImpl *m_style;
+ };
+
+ class AggShape : public CanvasItem, public BezierPathAggStroked
+ {
+ public:
+ AggShape(AggCanvas *c, SVGStylableImpl *style);
+ virtual ~AggShape();
+
+ virtual QRect bbox() const;
+ virtual bool fillContains(const QPoint &p);
+ virtual bool strokeContains(const QPoint &p);
+ virtual void update(CanvasItemUpdate reason, int param1 = 0, int param2 = 0);
+ void draw(SVGShapeImpl *shape);
+ void calcSVPs(const SVGMatrixImpl *matrix);
+ virtual void init();
+ virtual void init(const SVGMatrixImpl *);
+ bool isVisible(SVGShapeImpl *shape);
+
+ void setRenderContext(RenderContext context) { m_context = context; }
+
+ agg::path_storage &storage() { return m_storage; }
+ agg::trans_affine &transform() { return m_transform; }
+
+ protected:
+ void freeSVPs();
+
+ RenderContext m_context;
+ AggCanvas *m_canvas;
+ QRect m_bbox;
+ AggFillPaintServer *m_fillPainter;
+ AggStrokePaintServer *m_strokePainter;
+ };
+
+ AGG_CLASS(Rectangle, SVGRectElementImpl, rect)
+ AGG_CLASS(Ellipse, SVGEllipseElementImpl, ellipse)
+ AGG_CLASS(Circle, SVGCircleElementImpl, circle)
+
+ class AggLine : public AggShape, public MarkerHelper
+ {
+ public:
+ AggLine(AggCanvas *c, SVGLineElementImpl *line);
+ virtual ~AggLine();
+
+ virtual void draw();
+ virtual bool isVisible();
+ virtual void init();
+ virtual void init(const SVGMatrixImpl *screenCTM);
+
+ virtual SVGElementImpl *element() const { return m_line; }
+
+ protected:
+ SVGLineElementImpl *m_line;
+ };
+
+ class AggPoly : public AggShape, public MarkerHelper
+ {
+ public:
+ AggPoly(AggCanvas *c, SVGPolyElementImpl *poly);
+ virtual ~AggPoly();
+
+ virtual void draw();
+ virtual bool isVisible();
+ virtual void init();
+ virtual void init(const SVGMatrixImpl *screenCTM) = 0;
+
+ virtual SVGElementImpl *element() const { return m_poly; }
+
+ protected:
+ SVGPolyElementImpl *m_poly;
+
+ };
+ class AggPolyline : public AggPoly
+ {
+ public:
+ AggPolyline(AggCanvas *c, SVGPolylineElementImpl *poly);
+ virtual ~AggPolyline();
+
+ virtual void init(const SVGMatrixImpl *screenCTM);
+ };
+
+ class AggPolygon : public AggPoly
+ {
+ public:
+ AggPolygon(AggCanvas *c, SVGPolygonElementImpl *poly);
+ virtual ~AggPolygon();
+
+ virtual void init(const SVGMatrixImpl *screenCTM);
+ };
+
+ class AggPath : public AggShape, public ::SVGPathParser, public MarkerHelper
+ {
+ public:
+ AggPath(AggCanvas *c, SVGPathElementImpl *path);
+ virtual ~AggPath();
+
+ virtual void draw();
+ virtual bool isVisible();
+ virtual void init();
+ virtual void init(const SVGMatrixImpl *screenCTM);
+
+ virtual SVGElementImpl *element() const { return m_path; }
+
+ protected:
+ SVGPathElementImpl *m_path;
+
+ virtual void svgMoveTo(double x1, double y1, bool closed, bool abs = true);
+ virtual void svgLineTo(double x1, double y1, bool abs = true);
+ virtual void svgCurveToCubic(double x1, double y1, double x2, double y2, double x, double y, bool abs = true);
+ virtual void svgClosePath();
+ };
+
+ class AggMarker : public CanvasMarker
+ {
+ public:
+ AggMarker(AggCanvas *c, SVGMarkerElementImpl *marker);
+ virtual ~AggMarker();
+
+ virtual QRect bbox() const { return QRect(); }
+ virtual bool fillContains(const QPoint &) { return true; }
+ virtual bool strokeContains(const QPoint &) { return true; }
+ virtual void update(CanvasItemUpdate, int = 0, int = 0) { }
+ virtual void init();
+ virtual void draw();
+ virtual bool isVisible() { return false; }
+
+ void draw(SVGShapeImpl *obj, int x, int y, float lwidth = 1.0, double angle = 0.0);
+ //const ArtSVP *clippingRectangle() const { return m_clippingRectangle; }
+
+ protected:
+ AggCanvas *m_canvas;
+ //ArtSVP *m_clippingRectangle;
+ };
+
+ class AggImage : public CanvasItem
+ {
+ public:
+ AggImage(AggCanvas *c, SVGImageElementImpl *image);
+ virtual ~AggImage();
+
+ virtual QRect bbox() const;
+ virtual bool fillContains(const QPoint &) { return true; }
+ virtual bool strokeContains(const QPoint &) { return true; }
+ virtual void update(CanvasItemUpdate, int = 0, int = 0) { }
+ virtual void init();
+ virtual void draw();
+ virtual bool isVisible();
+
+ virtual SVGElementImpl *element() const { return m_image; }
+
+ protected:
+ AggCanvas *m_canvas;
+ SVGImageElementImpl *m_image;
+ };
+
+ class AggText : public CanvasText
+ {
+ public:
+ AggText(AggCanvas *c, SVGTextElementImpl *text);
+ virtual ~AggText();
+
+ virtual QRect bbox() const;
+ virtual bool fillContains(const QPoint &p);
+ virtual bool strokeContains(const QPoint &p);
+ virtual void update(CanvasItemUpdate, int param1 = 0, int param2 = 0);
+ virtual void draw();
+ virtual bool isVisible();
+ virtual void init();
+ virtual void init(const SVGMatrixImpl *screenCTM);
+
+ virtual void renderCallback(SVGTextContentElementImpl *element, const SVGMatrixImpl *screenCTM, T2P::GlyphSet *glyph, T2P::GlyphLayoutParams *params, double anchor) const;
+
+ virtual void addTextDecoration(SVGTextContentElementImpl *element, double x, double y, double w, double h) const;
+
+ unsigned operator [](unsigned) const { return 0; }
+
+ protected:
+ AggCanvas *m_canvas;
+
+ private:
+ void clearCurved();
+ class SVPElement
+ {
+ public:
+ SVPElement() { svp = 0; element = 0; fillPainter = 0; strokePainter = 0; }
+ ~SVPElement();
+
+ BezierPathAggStroked *svp;
+ SVGTextContentElementImpl *element;
+ AggFillPaintServer *fillPainter;
+ AggStrokePaintServer *strokePainter;
+ };
+
+ mutable QPtrList<SVPElement> m_drawItems;
+ };
+};
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/agg/BezierPathAgg.cpp b/ksvg/plugin/backends/agg/BezierPathAgg.cpp
new file mode 100644
index 00000000..10a75c1c
--- /dev/null
+++ b/ksvg/plugin/backends/agg/BezierPathAgg.cpp
@@ -0,0 +1,126 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <math.h>
+#include "Point.h"
+#include "BezierPathAgg.h"
+
+#include <kdebug.h>
+
+#include <agg_basics.h>
+#include <agg_bounding_rect.h>
+
+using namespace T2P;
+
+double BezierPathAgg::length(double t)
+{
+ if(m_length < 0.0)
+ {
+ double total = 0.0;
+ double x = 0.0, y = 0.0;
+ double x2, y2;
+ unsigned cmd;
+ unsigned int id = 0;
+ m_curved_trans.rewind(id);
+ while(!agg::is_stop(cmd = m_curved_trans.vertex(&x2, &y2)))
+ {
+ if(agg::is_move_to(cmd))
+ {
+ x = x2;
+ y = y2;
+ }
+ else if(agg::is_line_to(cmd))
+ {
+ double dx = x, dy = y;
+ dx = x2 - dx;
+ dy = y2 - dy;
+ total += sqrt(pow(dx, 2) + pow(dy, 2));
+ x = x2;
+ y = y2;
+ }
+ }
+ return total * t;
+ }
+ else
+ return m_length * t;
+}
+
+void BezierPathAgg::pointTangentNormalAt(double t, Point *p, Point *tn, Point *n)
+{
+ double totallen = length(t);
+ double total = 0.0;
+ double x = 0.0, y = 0.0;
+ double x2, y2;
+ unsigned cmd;
+ unsigned int id = 0;
+ m_curved_trans.rewind(id);
+ while(!agg::is_stop(cmd = m_curved_trans.vertex(&x2, &y2)))
+ {
+ if(agg::is_move_to(cmd))
+ {
+ x = x2;
+ y = y2;
+ }
+ else if(agg::is_line_to(cmd))
+ {
+ double dx = x, dy = y;
+ x = x2;
+ y = y2;
+ dx = x - dx;
+ dy = y - dy;
+ double seg_len = sqrt(pow(dx, 2) + pow(dy, 2));
+ total += seg_len;
+ if(total >= totallen)
+ {
+ double fract = 1 - (totallen - (total - seg_len)) / seg_len;
+ if(p)
+ {
+ p->setX(x - dx * fract);
+ p->setY(y - dy * fract);
+ }
+ if(tn)
+ {
+ //kdDebug() << k_funcinfo << "dx : " << dx << endl;
+ //kdDebug() << k_funcinfo << "dy : " << dy << endl;
+ tn->setX(dx);
+ tn->setY(dy);
+ }
+ if(n)
+ {
+ // Calculate vector product of "binormal" x tangent
+ // (0,0,1) x (dx,dy,0), which is simply (dy,-dx,0).
+ n->setX(dy);
+ n->setY(-dx);
+ }
+ return;
+ }
+ }
+ }
+}
+
+void BezierPathAgg::boundingBox(Point *topLeft, Point *bottomRight)
+{
+ double x1, y1, x2, y2;
+ agg::bounding_rect(m_curved, *this, 0, 1, &x1, &y1, &x2, &y2);
+ *topLeft = Point(x1, y1);
+ *bottomRight = Point(x2, y2);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/agg/BezierPathAgg.h b/ksvg/plugin/backends/agg/BezierPathAgg.h
new file mode 100644
index 00000000..21451aa9
--- /dev/null
+++ b/ksvg/plugin/backends/agg/BezierPathAgg.h
@@ -0,0 +1,83 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef T2P_BEZIERPATH_AGG_H
+#define T2P_BEZIERPATH_AGG_H
+
+#include <agg_curves.h>
+#include <agg_conv_curve.h>
+#include <agg_conv_stroke.h>
+#include <agg_path_storage.h>
+#include <agg_conv_transform.h>
+
+#include "Affine.h"
+#include "BezierPath.h"
+
+typedef agg::conv_curve<agg::path_storage> curved;
+typedef agg::conv_transform<curved> curved_trans;
+
+namespace T2P
+{
+ class BezierPathAgg : public BezierPath
+ {
+ public:
+ BezierPathAgg() : BezierPath(),
+ m_curved(m_storage), m_curved_trans(m_curved, m_transform)
+ {
+ m_length = -1;
+ }
+
+ ~BezierPathAgg() {}
+
+ BezierPathAgg(const BezierPathAgg &other) : BezierPath(), m_storage(other.m_storage),
+ m_curved(m_storage), m_curved_trans(m_curved, m_transform)
+ {
+ m_transform = other.m_transform;
+ m_length = other.m_length;
+ }
+
+ void copy_from(const agg::path_storage &ps, Affine &affine)
+ {
+ for(unsigned i = 0; i < ps.total_vertices(); i++)
+ {
+ double x, y;
+ unsigned cmd = ps.vertex(i, &x, &y);
+ m_storage.add_vertex(affine.dx() + x * affine.m11() + y * affine.m21(),
+ affine.dy() + x * affine.m12() + y * affine.m22(), cmd);
+ }
+ }
+
+ unsigned operator [](unsigned) { return 0; }
+
+ virtual double length(double t = 1.0);
+ virtual void pointTangentNormalAt(double t, Point *p = 0, Point *tn = 0, Point *n = 0);
+ virtual void boundingBox(Point *topLeft, Point *bottomRight);
+
+ agg::path_storage m_storage;
+ curved m_curved;
+ curved_trans m_curved_trans;
+ agg::trans_affine m_transform;
+ double m_length;
+ };
+};
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/agg/GlyphTracerAgg.cpp b/ksvg/plugin/backends/agg/GlyphTracerAgg.cpp
new file mode 100644
index 00000000..39b00146
--- /dev/null
+++ b/ksvg/plugin/backends/agg/GlyphTracerAgg.cpp
@@ -0,0 +1,113 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <iostream>
+
+#include "Glyph.h"
+#include "Point.h"
+#include "BezierPathAgg.h"
+#include "GlyphTracerAgg.h"
+
+using namespace T2P;
+
+int traceMoveto(FT_Vector *to, void *obj)
+{
+ Glyph *glyph = reinterpret_cast<Glyph *>(obj);
+ Affine &affine = glyph->affine();
+ BezierPathAgg *bpath = static_cast<BezierPathAgg *>(glyph->modifiableBezierPath());
+ Point p = affine.mapPoint(Point(to->x, to->y));
+ bpath->m_storage.move_to(p.x(), p.y());
+ return 0;
+}
+
+int traceLineto(FT_Vector *to, void *obj)
+{
+ Glyph *glyph = reinterpret_cast<Glyph *>(obj);
+ Affine &affine = glyph->affine();
+ BezierPathAgg *bpath = static_cast<BezierPathAgg *>(glyph->modifiableBezierPath());
+ Point p = affine.mapPoint(Point(to->x, to->y));
+ bpath->m_storage.line_to(p.x(), p.y());
+ return 0;
+}
+
+int traceConicBezier(FT_Vector *control, FT_Vector *to, void *obj)
+{
+ Glyph *glyph = reinterpret_cast<Glyph *>(obj);
+ Affine &affine = glyph->affine();
+ BezierPathAgg *bpath = static_cast<BezierPathAgg *>(glyph->modifiableBezierPath());
+ Point c = affine.mapPoint(Point(control->x, control->y));
+ Point p = affine.mapPoint(Point(to->x, to->y));
+
+ double sx, sy;
+ bpath->m_storage.vertex(bpath->m_storage.total_vertices() - 1, &sx, &sy);
+ bpath->m_storage.curve4(c.x() - (c.x() - sx) / 3, c.y() - (c.y() - sy) / 3,
+ c.x() + (p.x() - c.x()) / 3, c.y() + (p.y() - c.y()) / 3, p.x(), p.y());
+
+ return 0;
+}
+
+int traceCubicBezier(FT_Vector *control1, FT_Vector *control2, FT_Vector *to, void *obj)
+{
+ Glyph *glyph = reinterpret_cast<Glyph *>(obj);
+ Affine &affine = glyph->affine();
+ BezierPathAgg *bpath = static_cast<BezierPathAgg *>(glyph->modifiableBezierPath());
+ Point p = affine.mapPoint(Point(to->x, to->y));
+ Point c1 = affine.mapPoint(Point(control1->x, control1->y));
+ Point c2 = affine.mapPoint(Point(control2->x, control2->y));
+ bpath->m_storage.curve4(c1.x(), c1.y(), c2.x(), c2.y(), p.x(), p.y());
+ return 0;
+}
+
+GlyphTracerAgg::GlyphTracerAgg() : GlyphTracer()
+{
+ setMoveto(*traceMoveto);
+ setLineto(*traceLineto);
+ setConicBezier(*traceConicBezier);
+ setCubicBezier(*traceCubicBezier);
+}
+
+GlyphTracerAgg::~GlyphTracerAgg()
+{
+}
+
+void GlyphTracerAgg::correctGlyph(GlyphAffinePair *glyphAffine)
+{
+
+ // Take bezier path belonging to glyph (Note: that one is _UNMODIFIABLE_, once calculated)
+ const BezierPathAgg *path = static_cast<const BezierPathAgg *>(glyphAffine->glyph()->bezierPath());
+
+ BezierPathAgg *transformatedPath = static_cast<BezierPathAgg *>(allocBezierPath(0));
+ Affine &affine = glyphAffine->affine();
+ transformatedPath->copy_from(path->m_storage, affine);
+ glyphAffine->setTransformatedPath(transformatedPath);
+}
+
+BezierPath *GlyphTracerAgg::allocBezierPath(int)
+{
+ return new BezierPathAgg();
+}
+
+void GlyphTracerAgg::closePath(Glyph *glyph)
+{
+ BezierPathAgg *bpath = static_cast<BezierPathAgg *>(glyph->modifiableBezierPath());
+ bpath->m_storage.close_polygon();
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/agg/GlyphTracerAgg.h b/ksvg/plugin/backends/agg/GlyphTracerAgg.h
new file mode 100644
index 00000000..5fb24d4b
--- /dev/null
+++ b/ksvg/plugin/backends/agg/GlyphTracerAgg.h
@@ -0,0 +1,49 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef T2P_GLYPHTRACER_AGG_H
+#define T2P_GLYPHTRACER_AGG_H
+
+#include "GlyphTracer.h"
+
+// FreeType 2 includes
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+namespace T2P
+{
+ class Glyph;
+ class BezierPath;
+
+ class GlyphTracerAgg : public GlyphTracer
+ {
+ public:
+ GlyphTracerAgg();
+ ~GlyphTracerAgg();
+
+ virtual void correctGlyph(GlyphAffinePair *glyphAffine);
+ virtual BezierPath *allocBezierPath(int size);
+ virtual void closePath(Glyph *glyph);
+ };
+};
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/agg/Makefile.am b/ksvg/plugin/backends/agg/Makefile.am
new file mode 100644
index 00000000..4e883809
--- /dev/null
+++ b/ksvg/plugin/backends/agg/Makefile.am
@@ -0,0 +1,15 @@
+kde_module_LTLIBRARIES = libksvgrendereragg.la
+
+# Damn agg2 has no configuration querying possibility!
+AGG_CFLAGS = -I/cvs/agg2/include/
+AGG_LIBS = /cvs/agg2/src/libagg.a
+
+libksvgrendereragg_la_SOURCES = BezierPathAgg.cpp GlyphTracerAgg.cpp AggCanvas.cpp AggCanvasItems.cpp AggCanvasFactory.cpp
+libksvgrendereragg_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+libksvgrendereragg_la_LIBADD = ../../../libksvg.la $(AGG_LIBS)
+libksvgrendereragg_la_METASOURCES = AUTO
+
+kde_services_DATA = ksvgaggcanvas.desktop
+
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+INCLUDES = $(KDE_INCLUDES) $(AGG_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) -I$(top_srcdir)/ksvg/dom -I$(top_srcdir)/ksvg/impl -I$(top_srcdir)/ksvg/ecma -I$(top_srcdir)/ksvg/core -I$(top_srcdir)/ksvg/impl/libs/art_support -I$(top_srcdir)/ksvg/impl/libs/libtext2path/src $(all_includes)
diff --git a/ksvg/plugin/backends/agg/ksvgaggcanvas.desktop b/ksvg/plugin/backends/agg/ksvgaggcanvas.desktop
new file mode 100644
index 00000000..ac51836b
--- /dev/null
+++ b/ksvg/plugin/backends/agg/ksvgaggcanvas.desktop
@@ -0,0 +1,101 @@
+[Desktop Entry]
+Type=Service
+ServiceTypes=KSVG/Renderer
+X-KDE-Library=libksvgrendereragg
+X-KSVG-InternalName=agg
+Name=KSVG Rendering Backend - Anti Grain Geometry
+Name[ar]=خلفية رسم ل KSVG - هندسة Anti Grain
+Name[bs]=KSVG renderiranje - Anti Grain Geometry
+Name[ca]=Representació en segon pla de KSVG - Geometria anti gra
+Name[cs]=Vykreslovací nástroj KSVG - Anti Grain Geometry
+Name[cy]=Ôl-wyneb Llunio KSVG - Geometreg Wrth-Raen
+Name[da]=Underliggende program for KSVG-visning - antikorn geometri
+Name[de]=KSVG-Darstellungsmodul - Antikörnungs-Geometrie
+Name[el]= Σύστημα υποστήριξης αποτύπωσης του KSVG - Anti Grain Geometry
+Name[es]=Motor de procesado de KSVG - Geometría suavizada
+Name[et]=KSVG renderdamise taustarakendus - teralisusevastane geomeetria (AGG)
+Name[eu]=KSVG errendatze programa - Anti Grain geometriarekin
+Name[fa]=پایانۀ پشتیبانی پرداخت KSVG - هندسۀ ضد ذره
+Name[fi]=KSVG-piirtäjän taustaohjelma - sileä geometria
+Name[fr]=Moteur de rendu KSVG - Anti Grain Geometry
+Name[gl]=Mecanismo de Interpretación KSVG - Xeometría Anti-gran
+Name[he]=מנוע רינדור KSVG
+Name[hi]=के-एसवीजी रेंडरिंग बैकएण्ड- एन्टी ग्रेन ज्यामिती
+Name[hu]=KSVG megjelenítő motor - AGG (Anti Grain Geometry)
+Name[is]=KSVG teiknari - Anti Grain Geometry
+Name[it]=Backend KSVG per il rendering - Geometrie senza sgranature
+Name[ja]=KSVG レンダリングバックエンド - Anti Grain Geometry
+Name[kk]=KSVG кескіндеу бағдарламасы - қиыршықтыққа қарсы геометриясы
+Name[km]=កម្មវិធី​សម្រាប់​បង្ហាញ KSVG - រាង​មិន​គ្រើម
+Name[lt]=KSVG atkūrimo programinė sąsaja - Anti Grain geometrija
+Name[ms]=Tepi Belakang KSVG - Geometri Anti Bijian
+Name[nb]=Modul for KSVG-tegning – antikorngeometri
+Name[nds]=KSVG-Dorstellhölper - Antigrissel-Geometrie
+Name[ne]=KSVG रेन्डरिङ ब्याकइन्ड - एन्टि ग्रेन ज्योमेट्रि
+Name[nl]=KSVG weergavecomponent - Anti Grain Geometry
+Name[nn]=Modul for KSVG-teikning – antikorngeometri
+Name[pl]=Narzędzie do renderowania KSVG - nieziarnista geometria
+Name[pt]=Infra-Estrutura de Desenho do KSVG - Geometria Anti-Grão
+Name[pt_BR]=Estrutura de Renderização do KSVG - Geometria Anti-Grain
+Name[ro]=Motor de randare KSVG - Anti Grain Geometry
+Name[ru]=Движок отрисовки KSVG - противозернистая геометрия
+Name[sk]=Nástroj pre zobrazovanie KSVG - antigranularitná geometria
+Name[sl]=Izrisovalnik KSVG - Protizrnska geometrija
+Name[sr]=KSVG-ов позадински систем за рендеровање — Противзрнаста геометрија
+Name[sr@Latn]=KSVG-ov pozadinski sistem za renderovanje — Protivzrnasta geometrija
+Name[sv]=KSVG-uppritningsmodul - geometri mot korninghet
+Name[ta]=KSVG வழங்கும் பின் அமைப்பு - ஆன்டி க்ரேன் ஜியோமெட்ரி
+Name[tg]=Лағжандаи тасовироти KSVG - геометрияи мутақобили гандумӣ
+Name[tr]=KSVG Derleme Aracı - Taneciksiz Geometri
+Name[uk]=Інтерфейс відтворення KSVG - AGG
+Name[zh_CN]=KSVG 渲染后端 - 反增长几何形状
+Name[zh_HK]=KSVG 合成後端 - Anti Grain Geometry
+Name[zh_TW]=KSVG 上色後端介面 - Anti Grain Geometry
+Comment=New, unstable ksvg rendering backend
+Comment[bs]=Novi, nestabilni ksvg renderiranje backend
+Comment[ca]=Nou, inestable representador en segon pla de ksvg
+Comment[cs]=Nový, nestabilní vykreslovací nástroj KSVG
+Comment[cy]=Ôl-wyneb llunio ksvg newydd, ansad
+Comment[da]=Nyt, ustabilt underliggende program til ksvg-visning
+Comment[de]=Neues, unausgereiftes KSVG-Darstellungsmodul
+Comment[el]=Νέο υπό ανάπτυξη σύστημα υποστήριξης αποτύπωσης
+Comment[es]=Nuevo motor de procesado de ksvg, inestable
+Comment[et]=Uus ebastabiilne ksvg renderdamise taustarakendus
+Comment[eu]=Berria, ksvg errendatze programa ezegonkorra
+Comment[fa]=جدید، پایانۀ پشتیبانی ناپایدار پرداخت ksvg
+Comment[fi]=Uusi epävakaa ksvg-piirtäjän taustaohjelma
+Comment[fr]=Nouveau moteur de rendu KSVG instable
+Comment[gl]=Novo e inestábel mecanismo de interpretación ksvg
+Comment[he]=חדש, מנוע רינדור לא יציב עבור KSVG
+Comment[hi]=नया, अस्थिर के-एसवीजी रेंडरिंग बैकएण्ड
+Comment[hu]=Új, még nem teljesen kiforrott megjelenítőmotor a KSVG-hez
+Comment[is]=Nýr og óstöðugur ksvg teiknari
+Comment[it]=Nuovo, instabile backend di KSVG per il rendering
+Comment[ja]=新しく、まだ開発途上の ksvg レンダリングバックエンド
+Comment[kk]=Жаңа, әлі тұрақсыз KSVG кескіндеу бағдарламасы
+Comment[km]=កម្មវិធី​សម្រាប់​បង្ហាញ ksvg ថ្មី​តែ​មិន​សូវ​ឋិតថេរ
+Comment[lt]=Nauja, nestabili ksvg atkūrimo programinė sąsaja
+Comment[ms]=Tepi Belakang Menrealisasi ksvg yang baru dan tidak stabil
+Comment[nb]=Ny og ustabil modul for ksvg-tegning
+Comment[nds]=Nieg, nich stevig KSVG-Dorstellhölper
+Comment[ne]=नयाँ, अस्थिर ksvg रेन्डरिङ ब्याकइन्ड
+Comment[nl]=Nieuwe, niet stabiele KSVG weergavecomponent
+Comment[nn]=Ny og ustabil modul for ksvg-teikning
+Comment[pl]=Nowe, niestabilne, narzędzie do renderowania KSVG
+Comment[pt]=Uma infra-estrutura de desenho do ksvg, nova e instável
+Comment[pt_BR]=Nova e instável estrutura de renderização do ksvg
+Comment[ro]=Motor de randare KSVG nou, netestat suficient
+Comment[ru]=Новый, нестабильный движок прорисовки ksvg
+Comment[sk]=Nová, nestabilná verzia nástroja pre zobrazovanie ksvg
+Comment[sl]=Nov, nestabilen izrisovalnik KSVG
+Comment[sr]=Нов, нестабилан KSVG-ов позадински систем за рендеровање
+Comment[sr@Latn]=Nov, nestabilan KSVG-ov pozadinski sistem za renderovanje
+Comment[sv]=Ny, instabil KSVG-uppritningsmodul
+Comment[ta]=புதிய, நிலையில்லாத ksvg வழங்கும் பின் அமைப்பு
+Comment[tg]=Лағжандаи ғайриустувори тасовироти ksvg-и нав
+Comment[tr]=Yeni, stabil olmayan ksvg derleme aracı
+Comment[uk]=Новий, нестабільний інтерфейс відтворення KSVG
+Comment[zh_CN]=新的不稳定的 ksvg 渲染后端
+Comment[zh_HK]=新但不穩定的 ksvg 合成後端
+Comment[zh_TW]=新的,不穩定的 ksvg 上色後端介面
+author=Rob Buis <buis@kde.org>
diff --git a/ksvg/plugin/backends/libart/BezierPathLibart.cpp b/ksvg/plugin/backends/libart/BezierPathLibart.cpp
new file mode 100644
index 00000000..fb163952
--- /dev/null
+++ b/ksvg/plugin/backends/libart/BezierPathLibart.cpp
@@ -0,0 +1,160 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <math.h>
+#include "Point.h"
+#include "BezierPathLibart.h"
+
+#include <kdebug.h>
+
+#include <libart_lgpl/art_bpath.h>
+#include <libart_lgpl/art_vpath.h>
+#include <libart_lgpl/art_vpath_bpath.h>
+
+using namespace T2P;
+
+BezierPathLibart::BezierPathLibart() : BezierPath()
+{
+ m_array.resize(0);
+ m_length = -1;
+}
+
+BezierPathLibart::BezierPathLibart(ArtBpath *other) : BezierPath()
+{
+ int i = 0;
+ for(;other[i].code != ART_END; i++)
+ {
+ ensureSpace(m_array, i)
+ m_array[i] = other[i];
+ }
+ ensureSpace(m_array, i)
+ m_array[i].code = ART_END;
+}
+
+BezierPathLibart::~BezierPathLibart()
+{
+}
+
+double BezierPathLibart::length(double t)
+{
+ if(m_length < 0.0)
+ {
+ double total = 0.0;
+ // We cheat a bit...
+ ArtVpath *vpath = art_bez_path_to_vec(m_array.data(), 0.25);
+ double x = 0.0, y = 0.0;
+ for(int i = 0; vpath[i].code != ART_END; i++)
+ {
+ if(vpath[i].code == ART_MOVETO)
+ {
+ x = vpath[i].x;
+ y = vpath[i].y;
+ }
+ else if(vpath[i].code == ART_LINETO)
+ {
+ double dx = x, dy = y;
+ x = vpath[i].x;
+ y = vpath[i].y;
+ dx = x - dx;
+ dy = y - dy;
+ total += sqrt(pow(dx, 2) + pow(dy, 2));
+ }
+ }
+ art_free(vpath);
+ return total * t;
+ }
+ else
+ return m_length * t;
+}
+
+void BezierPathLibart::pointTangentNormalAt(double t, Point *p, Point *tn, Point *n)
+{
+ double totallen = length(t);
+ // We cheat a bit...
+ ArtVpath *vpath = art_bez_path_to_vec(m_array.data(), 0.25);
+ double total = 0.0;
+ double x = 0.0, y = 0.0;
+ for(int i = 0; vpath[i].code != ART_END; i++)
+ {
+ if(vpath[i].code == ART_MOVETO)
+ {
+ x = vpath[i].x;
+ y = vpath[i].y;
+ }
+ else if(vpath[i].code == ART_LINETO)
+ {
+ double dx = x, dy = y;
+ x = vpath[i].x;
+ y = vpath[i].y;
+ dx = x - dx;
+ dy = y - dy;
+ double seg_len = sqrt(pow(dx, 2) + pow(dy, 2));
+ total += seg_len;
+ if(total >= totallen)
+ {
+ double fract = 1 - (totallen - (total - seg_len)) / seg_len;
+ if(p)
+ {
+ p->setX(x - dx * fract);
+ p->setY(y - dy * fract);
+ }
+ // Calculate tangent
+ if(tn)
+ {
+ tn->setX(dx);
+ tn->setY(dy);
+ }
+ // Calculate normal vector.
+ if(n)
+ {
+ // Calculate vector product of "binormal" x tangent
+ // (0,0,1) x (dx,dy,0), which is simply (dy,-dx,0).
+ n->setX(dy);
+ n->setY(-dx);
+ }
+ return;
+ }
+ }
+ }
+ art_free(vpath);
+}
+
+void BezierPathLibart::boundingBox(Point *topLeft, Point *bottomRight)
+{
+ if(m_array.count() > 0)
+ {
+ // We cheat a bit...
+ ArtVpath *vpath = art_bez_path_to_vec(m_array.data(), 0.25);
+
+ ArtDRect rect;
+ art_vpath_bbox_drect(vpath, &rect);
+ art_free(vpath);
+
+ *topLeft = Point(rect.x0, rect.y0);
+ *bottomRight = Point(rect.x1, rect.y1);
+ }
+ else
+ {
+ *topLeft = Point(0, 0);
+ *bottomRight = Point(0, 0);
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/libart/BezierPathLibart.h b/ksvg/plugin/backends/libart/BezierPathLibart.h
new file mode 100644
index 00000000..a6dfd2b9
--- /dev/null
+++ b/ksvg/plugin/backends/libart/BezierPathLibart.h
@@ -0,0 +1,52 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef T2P_BEZIERPATH_LIBART_H
+#define T2P_BEZIERPATH_LIBART_H
+
+#include "BezierPath.h"
+#include <qmemarray.h>
+
+class _ArtBpath;
+
+#define ensureSpace(vec, index) if((int)vec.size() == index) vec.resize(index + 1);
+
+namespace T2P
+{
+ class BezierPathLibart : public BezierPath
+ {
+ public:
+ BezierPathLibart();
+ BezierPathLibart(_ArtBpath *other);
+ ~BezierPathLibart();
+
+ virtual double length(double t = 1.0);
+ virtual void pointTangentNormalAt(double t, Point *p = 0, Point *tn = 0, Point *n = 0);
+ virtual void boundingBox(Point *topLeft, Point *bottomRight);
+
+ // Don't make those private members, these are all internal anyway...
+ QMemArray<_ArtBpath> m_array;
+ double m_length;
+ };
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/libart/GlyphTracerLibart.cpp b/ksvg/plugin/backends/libart/GlyphTracerLibart.cpp
new file mode 100644
index 00000000..b034c6e6
--- /dev/null
+++ b/ksvg/plugin/backends/libart/GlyphTracerLibart.cpp
@@ -0,0 +1,177 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <iostream>
+
+#include <kdebug.h>
+
+#include "Glyph.h"
+#include "Point.h"
+#include "BezierPathLibart.h"
+#include "GlyphTracerLibart.h"
+
+#include <libart_lgpl/art_bpath.h>
+
+#include <config.h>
+
+#ifdef HAVE_FREETYPE_2_2_x
+ #define FT_VECTOR_PARAMETER const FT_Vector
+#else
+ #define FT_VECTOR_PARAMETER FT_Vector
+#endif
+
+using namespace T2P;
+
+int traceMoveto(FT_VECTOR_PARAMETER *to, void *obj)
+{
+ Glyph *glyph = reinterpret_cast<Glyph *>(obj);
+ Affine &affine = glyph->affine();
+ BezierPathLibart *path = static_cast<BezierPathLibart *>(glyph->modifiableBezierPath());
+ Point p = affine.mapPoint(Point(to->x, to->y));
+
+ int index = path->m_array.count();
+ if(index == 0 ||
+ p.x() != path->m_array[index - 1].x3 ||
+ p.y() != path->m_array[index - 1].y3)
+ {
+ path->m_array.resize(index + 1);
+ path->m_array[index].code = ART_MOVETO;
+ path->m_array[index].x3 = p.x();
+ path->m_array[index].y3 = p.y();
+ }
+
+ return 0;
+}
+
+int traceLineto(FT_VECTOR_PARAMETER *to, void *obj)
+{
+ Glyph *glyph = reinterpret_cast<Glyph *>(obj);
+ Affine &affine = glyph->affine();
+ BezierPathLibart *path = static_cast<BezierPathLibart *>(glyph->modifiableBezierPath());
+ Point p = affine.mapPoint(Point(to->x, to->y));
+
+ int index = path->m_array.count();
+ ArtBpath *last = &path->m_array[index - 1];
+
+ if((p.x() != last->x3) || (p.y() != last->y3))
+ {
+ path->m_array.resize(index + 1);
+ path->m_array[index].code = ART_LINETO;
+ path->m_array[index].x3 = p.x();
+ path->m_array[index].y3 = p.y();
+ }
+
+ return 0;
+}
+
+int traceConicBezier(FT_VECTOR_PARAMETER *control, FT_VECTOR_PARAMETER *to, void *obj)
+{
+ Glyph *glyph = reinterpret_cast<Glyph *>(obj);
+ Affine &affine = glyph->affine();
+ BezierPathLibart *path = static_cast<BezierPathLibart *>(glyph->modifiableBezierPath());
+
+ int index = path->m_array.count();
+ if(!(index > 0))
+ return -1;
+
+ path->m_array.resize(index + 1);
+ ArtBpath *s = &path->m_array[index - 1];
+ ArtBpath *e = &path->m_array[index];
+
+ e->code = ART_CURVETO;
+
+ Point c = affine.mapPoint(Point(control->x, control->y));
+ Point p = affine.mapPoint(Point(to->x, to->y));
+ e->x3 = p.x();
+ e->y3 = p.y();
+
+ path->m_array[index].x1 = c.x() - (c.x() - s->x3) / 3;
+ path->m_array[index].y1 = c.y() - (c.y() - s->y3) / 3;
+ path->m_array[index].x2 = c.x() + (e->x3 - c.x()) / 3;
+ path->m_array[index].y2 = c.y() + (e->y3 - c.y()) / 3;
+
+ return 0;
+}
+
+int traceCubicBezier(FT_VECTOR_PARAMETER *control1, FT_VECTOR_PARAMETER *control2, FT_VECTOR_PARAMETER *to, void *obj)
+{
+ Glyph *glyph = reinterpret_cast<Glyph *>(obj);
+ Affine &affine = glyph->affine();
+ BezierPathLibart *path = static_cast<BezierPathLibart *>(glyph->modifiableBezierPath());
+
+ Point p = affine.mapPoint(Point(to->x, to->y));
+ Point c1 = affine.mapPoint(Point(control1->x, control1->y));
+ Point c2 = affine.mapPoint(Point(control2->x, control2->y));
+
+ int index = path->m_array.count();
+ path->m_array.resize(index + 1);
+ path->m_array[index].code = ART_CURVETO;
+ path->m_array[index].x1 = c1.x();
+ path->m_array[index].y1 = c1.y();
+ path->m_array[index].x2 = c2.x();
+ path->m_array[index].y2 = c2.y();
+ path->m_array[index].x3 = p.x();
+ path->m_array[index].y3 = p.y();
+
+ return 0;
+}
+
+GlyphTracerLibart::GlyphTracerLibart() : GlyphTracer()
+{
+ setMoveto(*traceMoveto);
+ setLineto(*traceLineto);
+ setConicBezier(*traceConicBezier);
+ setCubicBezier(*traceCubicBezier);
+}
+
+GlyphTracerLibart::~GlyphTracerLibart()
+{
+}
+
+void GlyphTracerLibart::correctGlyph(GlyphAffinePair *glyphAffine)
+{
+ // Take bezier path belonging to glyph (Note: that one is _UNMODIFIABLE_, once calculated)
+ const BezierPathLibart *path = static_cast<const BezierPathLibart *>(glyphAffine->glyph()->bezierPath());
+
+ // Create a new empty path with the same size
+ ArtBpath *transformed = art_bpath_affine_transform(path->m_array.data(), glyphAffine->affine().data());
+ BezierPathLibart *transformatedPath = new BezierPathLibart(transformed);
+ art_free(transformed);
+ glyphAffine->setTransformatedPath(transformatedPath);
+}
+
+BezierPath *GlyphTracerLibart::allocBezierPath(int)
+{
+ BezierPathLibart *bpath = new BezierPathLibart();
+ //if(size != 0)
+ // bpath->m_array.resize(size);
+
+ return bpath;
+}
+
+void GlyphTracerLibart::closePath(Glyph *glyph)
+{
+ BezierPathLibart *path = static_cast<BezierPathLibart *>(glyph->modifiableBezierPath());
+ int index = path->m_array.count();
+ path->m_array.resize(index + 1);
+ path->m_array[index].code = ART_END;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/libart/GlyphTracerLibart.h b/ksvg/plugin/backends/libart/GlyphTracerLibart.h
new file mode 100644
index 00000000..39b87490
--- /dev/null
+++ b/ksvg/plugin/backends/libart/GlyphTracerLibart.h
@@ -0,0 +1,50 @@
+/*
+ Copyright (C) 2003 Nikolas Zimmermann <wildfox@kde.org>
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef T2P_GLYPHTRACER_LIBART_H
+#define T2P_GLYPHTRACER_LIBART_H
+
+#include "GlyphTracer.h"
+
+// FreeType 2 includes
+#include <ft2build.h>
+#include FT_FREETYPE_H
+
+namespace T2P
+{
+ class Glyph;
+ class BezierPath;
+ class GlyphAffinePair;
+
+ class GlyphTracerLibart : public GlyphTracer
+ {
+ public:
+ GlyphTracerLibart();
+ virtual ~GlyphTracerLibart();
+
+ virtual void correctGlyph(GlyphAffinePair *glyphAffine);
+ virtual BezierPath *allocBezierPath(int size);
+ virtual void closePath(Glyph *glyph);
+ };
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/libart/LibartCanvas.cpp b/ksvg/plugin/backends/libart/LibartCanvas.cpp
new file mode 100644
index 00000000..5697b623
--- /dev/null
+++ b/ksvg/plugin/backends/libart/LibartCanvas.cpp
@@ -0,0 +1,425 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "LibartCanvas.h"
+#include "SVGMatrixImpl.h"
+#include "SVGRectImpl.h"
+#include "SVGPaintImpl.h"
+#include "SVGShapeImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGStringListImpl.h"
+#include "SVGPatternElementImpl.h"
+#include "SVGGradientElementImpl.h"
+#include "SVGLinearGradientElementImpl.h"
+#include "SVGRadialGradientElementImpl.h"
+#include "SVGClipPathElementImpl.h"
+#include "SVGTextPositioningElementImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGAnimatedLengthListImpl.h"
+#include "SVGAnimatedEnumerationImpl.h"
+#include "SVGMarkerElementImpl.h"
+#include "SVGMaskElementImpl.h"
+
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kgenericfactory.h>
+
+#include "SVGPaint.h"
+
+#include <qdatetime.h>
+#include <qstring.h>
+#include <qimage.h>
+
+#include "KSVGHelper.h"
+#include "KSVGTextChunk.h"
+#include "LibartCanvasItems.h"
+
+#include <libart_lgpl/art_rgb.h>
+#include <libart_lgpl/art_affine.h>
+#include <libart_lgpl/art_alphagamma.h>
+#include <libart_lgpl/art_rgb_svp.h>
+#include <libart_lgpl/art_svp.h>
+#include <libart_lgpl/art_svp_ops.h>
+#include <libart_lgpl/art_svp_intersect.h>
+#include <libart_lgpl/art_rect_svp.h>
+#include <libart_lgpl/art_svp_vpath.h>
+
+#include <libs/art_support/art_misc.h>
+#include <libs/art_support/art_rgba_svp.h>
+
+#include <Font.h>
+#include "BezierPathLibart.h"
+#include "GlyphTracerLibart.h"
+
+#include <fontconfig/fontconfig.h>
+
+ArtSVP *art_svp_from_rect(int x0, int y0, int x1, int y1)
+{
+ ArtVpath vpath[] =
+ {
+ { ART_MOVETO, x0, y0 },
+ { ART_LINETO, x0, y1 },
+ { ART_LINETO, x1, y1 },
+ { ART_LINETO, x1, y0 },
+ { ART_LINETO, x0, y0 },
+ { ART_END, 0, 0}
+ };
+
+ return art_svp_from_vpath(vpath);
+}
+
+ArtSVP *art_svp_from_irect(ArtIRect *bbox)
+{
+ return art_svp_from_rect(bbox->x0, bbox->y0, bbox->x1, bbox->y1);
+}
+
+ArtSVP *art_svp_from_qrect(const QRect& rect)
+{
+ return art_svp_from_rect(rect.left(), rect.top(), rect.right() + 1, rect.bottom() + 1);
+}
+
+using namespace KSVG;
+
+LibartCanvas::LibartCanvas(unsigned int width, unsigned int height) : KSVGCanvas(width, height)
+{
+ m_fontContext = new T2P::Converter(new T2P::GlyphTracerLibart());
+}
+
+T2P::BezierPath *LibartCanvas::toBezierPath(CanvasItem *item) const
+{
+ LibartPath *path = dynamic_cast<LibartPath *>(item);
+ if(!path)
+ return 0;
+
+ // Only handle LibartPath items
+ //T2P::BezierPathLibart *result = new T2P::BezierPathLibart(path->m_array.data());
+ return path;
+}
+
+// drawing primitives
+CanvasItem *LibartCanvas::createRectangle(SVGRectElementImpl *rect)
+{
+ return new LibartRectangle(this, rect);
+}
+
+CanvasItem *LibartCanvas::createEllipse(SVGEllipseElementImpl *ellipse)
+{
+ return new LibartEllipse(this, ellipse);
+}
+
+CanvasItem *LibartCanvas::createCircle(SVGCircleElementImpl *circle)
+{
+ return new LibartCircle(this, circle);
+}
+
+CanvasItem *LibartCanvas::createLine(SVGLineElementImpl *line)
+{
+ return new LibartLine(this, line);
+}
+
+CanvasItem *LibartCanvas::createPolyline(SVGPolylineElementImpl *poly)
+{
+ return new LibartPolyline(this, poly);
+}
+
+CanvasItem *LibartCanvas::createPolygon(SVGPolygonElementImpl *poly)
+{
+ return new LibartPolygon(this, poly);
+}
+
+CanvasItem *LibartCanvas::createPath(SVGPathElementImpl *path)
+{
+ return new LibartPath(this, path);
+}
+
+CanvasItem *LibartCanvas::createClipPath(SVGClipPathElementImpl *clippath)
+{
+ CanvasClipPath *result = new LibartClipPath(this, clippath);
+ QString index = clippath->id().string();
+ m_clipPaths.insert(index, result);
+ return result;
+}
+
+CanvasItem *LibartCanvas::createImage(SVGImageElementImpl *image)
+{
+ return new LibartImage(this, image);
+}
+
+CanvasItem *LibartCanvas::createCanvasMarker(SVGMarkerElementImpl *marker)
+{
+ return new LibartMarker(this, marker);
+}
+
+CanvasItem *LibartCanvas::createText(SVGTextElementImpl *text)
+{
+ return new LibartText(this, text);
+}
+
+CanvasPaintServer *LibartCanvas::createPaintServer(SVGElementImpl *pserver)
+{
+ LibartPaintServer *result;
+ if(dynamic_cast<SVGLinearGradientElementImpl *>(pserver))
+ result = new LibartLinearGradient(dynamic_cast<SVGLinearGradientElementImpl *>(pserver));
+ else if(dynamic_cast<SVGRadialGradientElementImpl *>(pserver))
+ result = new LibartRadialGradient(dynamic_cast<SVGRadialGradientElementImpl *>(pserver));
+ else if(dynamic_cast<SVGPatternElementImpl *>(pserver))
+ result = new LibartPattern(dynamic_cast<SVGPatternElementImpl *>(pserver));
+ return result;
+}
+
+void LibartCanvas::drawImage(QImage image, SVGStylableImpl *style, const SVGMatrixImpl *matrix, const KSVGPolygon& clippingPolygon)
+{
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(style);
+
+ if(shape)
+ {
+ if(image.depth() != 32)
+ image = image.convertDepth(32);
+
+ ArtSVP *imageBorder = svpFromPolygon(clippingPolygon);
+ ArtSVP *clipSvp = clipSingleSVP(imageBorder, shape);
+
+ ArtDRect bbox;
+ art_drect_svp(&bbox, clipSvp);
+
+ // clamp to viewport
+ int x0 = int(bbox.x0);
+ int y0 = int(bbox.y0);
+
+ // Use inclusive coords for x1/y1 for clipToBuffer
+ int x1 = int(ceil(bbox.x1)) - 1;
+ int y1 = int(ceil(bbox.y1)) - 1;
+
+ if(x0 < int(m_width) && y0 < int(m_height) && x1 >= 0 && y1 >= 0)
+ {
+ clipToBuffer(x0, y0, x1, y1);
+
+ QRect screenBBox(x0, y0, x1 - x0 + 1, y1 - y0 + 1);
+
+ QByteArray mask = SVGMaskElementImpl::maskRectangle(shape, screenBBox);
+
+ double affine[6];
+ KSVGHelper::matrixToAffine(matrix, affine);
+
+ ksvg_art_rgb_affine_clip(clipSvp, m_buffer + x0 * nrChannels() + y0 * rowStride(), x0, y0, x1 + 1, y1 + 1, rowStride(), nrChannels(), image.bits(), image.width(), image.height(), image.width() * 4, affine, int(style->getOpacity() * 255), (const art_u8 *)mask.data());
+ }
+
+ art_svp_free(imageBorder);
+ art_svp_free(clipSvp);
+ }
+}
+
+ArtSVP *LibartCanvas::clippingRect(const QRect &rect, const SVGMatrixImpl *ctm)
+{
+ ArtVpath *vec = allocVPath(6);
+ // Order of points in clipping rectangle must be counter-clockwise
+ bool flip = ((ctm->a() * ctm->d()) < (ctm->b() * ctm->c()));
+
+ vec[0].code = ART_MOVETO;
+ vec[0].x = rect.x();
+ vec[0].y = rect.y();
+
+ vec[1].code = ART_LINETO;
+ vec[1].x = rect.x() + (flip ? rect.width() : 0);
+ vec[1].y = rect.y() + (flip ? 0 : rect.height());
+
+ vec[2].code = ART_LINETO;
+ vec[2].x = rect.x() + rect.width();
+ vec[2].y = rect.y() + rect.height();
+
+ vec[3].code = ART_LINETO;
+ vec[3].x = rect.x() + (flip ? 0 : rect.width());
+ vec[3].y = rect.y() + (flip ? rect.height() : 0);
+
+ vec[4].code = ART_LINETO;
+ vec[4].x = rect.x();
+ vec[4].y = rect.y();
+
+ vec[5].code = ART_END;
+
+ double affine[6];
+ KSVGHelper::matrixToAffine(ctm, affine);
+
+ ArtVpath *temp = art_vpath_affine_transform(vec, affine);
+ art_free(vec);
+
+ ArtSVP *result = art_svp_from_vpath(temp);
+ art_free(temp);
+ return result;
+}
+
+ArtSVP *LibartCanvas::clipSingleSVP(ArtSVP *svp, SVGShapeImpl *shape)
+{
+ ArtSVP *clippedSvp = copy_svp(svp);
+ SVGStylableImpl *style = dynamic_cast<SVGStylableImpl *>(shape);
+
+ if(style)
+ {
+ QString clipPathRef = style->getClipPath();
+
+ if(!clipPathRef.isEmpty())
+ {
+ CanvasClipPath *clipPath = m_clipPaths[clipPathRef];
+
+ if(clipPath)
+ {
+ LibartClipPath *lclip = dynamic_cast<LibartClipPath *>(clipPath);
+ reinterpret_cast<SVGClipPathElementImpl *>(clipPath->element())->setBBoxTarget(shape);
+
+ lclip->init();
+
+ if(lclip->clipSVP())
+ {
+ ArtSVP *s = art_svp_intersect(lclip->clipSVP(), clippedSvp);
+ art_svp_free(clippedSvp);
+ clippedSvp = s;
+ }
+ }
+ }
+ }
+
+ SVGSVGElementImpl *svg = dynamic_cast<SVGSVGElementImpl *>(shape);
+
+ // Clip outer svg, unless width and height not set
+ if(svg && (!svg->isRootElement() || !svg->getAttribute("width").isEmpty() || !svg->getAttribute("height").isEmpty()) && !svg->getOverflow())
+ {
+ ArtSVP *svgClip = clippingRect(svg->clip(), svg->screenCTM());
+ ArtSVP *s = art_svp_intersect(svgClip, clippedSvp);
+ art_svp_free(clippedSvp);
+ art_svp_free(svgClip);
+ clippedSvp = s;
+ }
+
+ if(dynamic_cast<SVGPatternElementImpl *>(shape) != 0)
+ {
+ // TODO: inherit clipping paths into tile space
+ }
+ else if(dynamic_cast<SVGMarkerElementImpl *>(shape) != 0)
+ {
+ SVGMarkerElementImpl *marker = static_cast<SVGMarkerElementImpl *>(shape);
+
+ if(!marker->clipShape().isEmpty())
+ {
+ ArtSVP *clipShape = svpFromPolygon(marker->clipShape());
+ ArtSVP *s = art_svp_intersect(clipShape, clippedSvp);
+ art_svp_free(clipShape);
+ art_svp_free(clippedSvp);
+ clippedSvp = s;
+ }
+
+ // TODO: inherit clipping paths into marker space
+ }
+ else
+ {
+ SVGElementImpl *element = dynamic_cast<SVGElementImpl *>(shape);
+ DOM::Node parentNode = element->parentNode();
+
+ if(!parentNode.isNull())
+ {
+ SVGElementImpl *parent = element->ownerDoc()->getElementFromHandle(parentNode.handle());
+
+ if(parent)
+ {
+ SVGShapeImpl *parentShape = dynamic_cast<SVGShapeImpl *>(parent);
+
+ if(parentShape)
+ {
+ // Clip against ancestor clipping paths
+ ArtSVP *parentClippedSvp = clipSingleSVP(clippedSvp, parentShape);
+ art_svp_free(clippedSvp);
+ clippedSvp = parentClippedSvp;
+ }
+ }
+ }
+ }
+
+ return clippedSvp;
+}
+
+void LibartCanvas::drawSVP(ArtSVP *svp, art_u32 color, QByteArray mask, QRect screenBBox)
+{
+ int x0 = screenBBox.left();
+ int y0 = screenBBox.top();
+ int x1 = screenBBox.right();
+ int y1 = screenBBox.bottom();
+
+ if(m_nrChannels == 3)
+ {
+ if(mask.data())
+ art_ksvg_rgb_svp_alpha_mask(svp, x0, y0, x1 + 1, y1 + 1, color, m_buffer + x0 * 3 + y0 * 3 * m_width, m_width * 3, 0, (art_u8 *)mask.data());
+ else
+ art_rgb_svp_alpha(svp, x0, y0, x1 + 1, y1 + 1, color, m_buffer + x0 * 3 + y0 * 3 * m_width, m_width * 3, 0);
+ }
+ else
+ art_ksvg_rgba_svp_alpha(svp, x0, y0, x1 + 1, y1 + 1, color, m_buffer + x0 * 4 + y0 * 4 * m_width, m_width * 4, 0, (art_u8 *)mask.data());
+}
+
+ArtSVP *LibartCanvas::copy_svp(const ArtSVP *svp)
+{
+ // No API to copy an SVP so do so without accessing the data structure directly.
+ ArtVpath *vec = allocVPath(1);
+
+ vec[0].code = ART_END;
+
+ ArtSVP *empty = art_svp_from_vpath(vec);
+ art_free(vec);
+
+ ArtSVP *result = art_svp_union(empty, svp);
+ art_svp_free(empty);
+
+ return result;
+}
+
+ArtSVP *LibartCanvas::svpFromPolygon(const KSVGPolygon& polygon)
+{
+ if(polygon.numPoints() > 2)
+ {
+ ArtVpath *points = new ArtVpath[polygon.numPoints() + 2];
+
+ points[0].code = ART_MOVETO;
+ points[0].x = polygon.point(0).x();
+ points[0].y = polygon.point(0).y();
+
+ unsigned int i;
+
+ for(i = 1; i < polygon.numPoints(); i++)
+ {
+ points[i].code = ART_LINETO;
+ points[i].x = polygon.point(i).x();
+ points[i].y = polygon.point(i).y();
+ }
+
+ points[i].code = ART_LINETO;
+ points[i].x = polygon.point(0).x();
+ points[i].y = polygon.point(0).y();
+
+ points[i + 1].code = ART_END;
+
+ ArtSVP *svp = art_svp_from_vpath(points);
+ delete [] points;
+
+ return svp;
+ }
+ else
+ return 0;
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/libart/LibartCanvas.h b/ksvg/plugin/backends/libart/LibartCanvas.h
new file mode 100644
index 00000000..e0da1682
--- /dev/null
+++ b/ksvg/plugin/backends/libart/LibartCanvas.h
@@ -0,0 +1,84 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef LIBARTCANVAS_H
+#define LIBARTCANVAS_H
+
+#include "CanvasItem.h"
+#include "KSVGCanvas.h"
+
+#include <libart_lgpl/art_svp.h>
+#include <libart_lgpl/art_vpath.h>
+#include <libart_lgpl/art_config.h>
+
+#include <Glyph.h>
+#include <Converter.h>
+#include "GlyphTracerLibart.h"
+
+class QString;
+class QImage;
+
+struct _ArtSVP;
+
+namespace KSVG
+{
+
+class LibartPaintServer;
+class SVGElementImpl;
+class SVGStylableImpl;
+class SVGSVGElementImpl;
+class KSVGPolygon;
+class LibartCanvas : public KSVGCanvas
+{
+public:
+ LibartCanvas(unsigned int width, unsigned int height);
+
+ void drawSVP(_ArtSVP *svp, art_u32 color, QByteArray mask, QRect screenBBox);
+ void drawImage(QImage image, SVGStylableImpl *style, const SVGMatrixImpl *matrix, const KSVGPolygon& clippingPolygon);
+
+ virtual T2P::BezierPath *toBezierPath(CanvasItem *item) const;
+
+ // creating canvas items
+ virtual CanvasItem *createRectangle(SVGRectElementImpl *rect);
+ virtual CanvasItem *createEllipse(SVGEllipseElementImpl *ellipse);
+ virtual CanvasItem *createCircle(SVGCircleElementImpl *circle);
+ virtual CanvasItem *createLine(SVGLineElementImpl *line);
+ virtual CanvasItem *createPolyline(SVGPolylineElementImpl *poly);
+ virtual CanvasItem *createPolygon(SVGPolygonElementImpl *poly);
+ virtual CanvasItem *createPath(SVGPathElementImpl *path);
+ virtual CanvasItem *createClipPath(SVGClipPathElementImpl *clippath);
+ virtual CanvasItem *createImage(SVGImageElementImpl *image);
+ virtual CanvasItem *createCanvasMarker(SVGMarkerElementImpl *marker);
+ virtual CanvasItem *createText(SVGTextElementImpl *text);
+ virtual CanvasPaintServer *createPaintServer(SVGElementImpl *pserver);
+
+ _ArtSVP *clippingRect(const QRect &rect, const SVGMatrixImpl *ctm);
+ _ArtSVP *svpFromPolygon(const KSVGPolygon& polygon);
+
+ static ArtSVP *copy_svp(const ArtSVP *svp);
+
+ _ArtSVP *clipSingleSVP(_ArtSVP *svp, SVGShapeImpl *clipShape);
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/libart/LibartCanvasFactory.cpp b/ksvg/plugin/backends/libart/LibartCanvasFactory.cpp
new file mode 100644
index 00000000..48d37f05
--- /dev/null
+++ b/ksvg/plugin/backends/libart/LibartCanvasFactory.cpp
@@ -0,0 +1,45 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kdebug.h>
+
+#include "LibartCanvas.h"
+#include "LibartCanvasFactory.h"
+
+using namespace KSVG;
+
+K_EXPORT_COMPONENT_FACTORY(libksvgrendererlibart, LibartCanvasFactory)
+
+LibartCanvasFactory::LibartCanvasFactory()
+{
+}
+
+LibartCanvasFactory::~LibartCanvasFactory()
+{
+}
+
+QObject *LibartCanvasFactory::createObject(QObject *, const char *, const char *, const QStringList &args)
+{
+ int width = (*args.at(1)).toInt();
+ int height = (*args.at(0)).toInt();
+ return new LibartCanvas(width, height);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/libart/LibartCanvasFactory.h b/ksvg/plugin/backends/libart/LibartCanvasFactory.h
new file mode 100644
index 00000000..5b3ed0b3
--- /dev/null
+++ b/ksvg/plugin/backends/libart/LibartCanvasFactory.h
@@ -0,0 +1,45 @@
+/*
+ Copyright (C) 2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef LIBARTCANVASFACTORY_H
+#define LIBARTCANVASFACTORY_H
+
+#include <klibloader.h>
+
+#include "CanvasItem.h"
+#include "KSVGCanvas.h"
+
+namespace KSVG
+{
+
+class LibartCanvasFactory : public KLibFactory
+{
+public:
+ LibartCanvasFactory();
+ virtual ~LibartCanvasFactory();
+
+ virtual QObject *createObject(QObject *parent = 0, const char *pname = 0, const char *name = "QObject", const QStringList &args = QStringList());
+};
+
+}
+
+#endif
+
+/// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/libart/LibartCanvasItems.cpp b/ksvg/plugin/backends/libart/LibartCanvasItems.cpp
new file mode 100644
index 00000000..5dd97be1
--- /dev/null
+++ b/ksvg/plugin/backends/libart/LibartCanvasItems.cpp
@@ -0,0 +1,2209 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <cfloat>
+
+#include <qimage.h>
+#include <qwmatrix.h>
+
+#include "SVGPaint.h"
+#include "SVGRectImpl.h"
+#include "SVGAngleImpl.h"
+#include "SVGPaintImpl.h"
+#include "SVGUnitTypes.h"
+#include "SVGHelperImpl.h"
+#include "SVGDocumentImpl.h"
+#include "SVGPointListImpl.h"
+#include "SVGMarkerElement.h"
+#include "SVGMarkerElementImpl.h"
+#include "SVGSVGElementImpl.h"
+#include "SVGPathSegListImpl.h"
+#include "SVGAnimatedRectImpl.h"
+#include "SVGAnimatedStringImpl.h"
+#include "SVGImageElementImpl.h"
+#include "SVGAnimatedAngleImpl.h"
+#include "SVGAnimatedLengthImpl.h"
+#include "SVGPolygonElementImpl.h"
+#include "SVGClipPathElementImpl.h"
+#include "SVGPolylineElementImpl.h"
+#include "SVGAnimatedLengthListImpl.h"
+#include "SVGAnimatedNumberImpl.h"
+#include "SVGAnimatedEnumerationImpl.h"
+#include "SVGPreserveAspectRatioImpl.h"
+#include "SVGAnimatedPreserveAspectRatioImpl.h"
+#include "SVGGradientElementImpl.h"
+#include "SVGGradientElement.h"
+#include "SVGLinearGradientElementImpl.h"
+#include "SVGRadialGradientElementImpl.h"
+#include "SVGPatternElementImpl.h"
+#include "SVGPatternElement.h"
+#include "SVGStopElementImpl.h"
+#include "SVGStylableImpl.h"
+#include "SVGAnimatedTransformListImpl.h"
+#include "SVGTransformListImpl.h"
+#include "SVGUnitConverter.h"
+#include "SVGTextPathElementImpl.h"
+#include "SVGMaskElementImpl.h"
+
+#include "KSVGHelper.h"
+#include "LibartCanvasItems.h"
+#include "KSVGTextChunk.h"
+
+#include "art_misc.h"
+#include "art_render_misc.h"
+#include "BezierPathLibart.h"
+#include "Point.h"
+
+#include <dom/dom_node.h>
+
+
+#include <libart_lgpl/art_vpath.h>
+#include <libart_lgpl/art_bpath.h>
+#include <libart_lgpl/art_affine.h>
+#include <libart_lgpl/art_svp_ops.h>
+#include <libart_lgpl/art_svp_point.h>
+#include <libart_lgpl/art_vpath_svp.h>
+#include <libart_lgpl/art_svp_intersect.h>
+#include <libart_lgpl/art_svp_vpath.h>
+#include <libart_lgpl/art_svp_vpath_stroke.h>
+#include <libart_lgpl/art_rect_svp.h>
+#include <libart_lgpl/art_vpath_dash.h>
+#include <libart_lgpl/art_render.h>
+#include <libart_lgpl/art_rect_svp.h>
+#include <libart_lgpl/art_render_gradient.h>
+#include <libart_lgpl/art_render_svp.h>
+#include <libart_lgpl/art_render_mask.h>
+
+using namespace KSVG;
+
+LibartShape::LibartShape(LibartCanvas *c, SVGStylableImpl *style) : m_canvas(c), m_style(style)
+{
+ m_fillSVP = 0;
+ m_strokeSVP = 0;
+ m_fillPainter = 0;
+ m_strokePainter = 0;
+}
+
+LibartShape::~LibartShape()
+{
+ freeSVPs();
+ delete m_fillPainter;
+ delete m_strokePainter;
+}
+
+QRect LibartShape::bbox() const
+{
+ QRect rect;
+ if(m_strokeSVP || m_fillSVP)
+ {
+ ArtIRect *irect = new ArtIRect();
+ ArtVpath *vpath = art_vpath_from_svp(m_strokeSVP ? m_strokeSVP : m_fillSVP);
+ art_vpath_bbox_irect(vpath, irect);
+ art_free(vpath);
+
+ rect.setX(irect->x0);
+ rect.setY(irect->y0);
+ rect.setWidth(irect->x1 - irect->x0);
+ rect.setHeight(irect->y1 - irect->y0);
+
+ delete irect;
+ }
+
+ return rect;
+}
+
+bool LibartShape::isVisible(SVGShapeImpl *shape)
+{
+ return m_referenced || (m_style->getVisible() && m_style->getDisplay() && shape->directRender());
+}
+
+bool LibartShape::fillContains(const QPoint &p)
+{
+ if(m_fillSVP)
+ return art_svp_point_wind(m_fillSVP, p.x(), p.y()) != 0;
+ else
+ return false;
+}
+
+bool LibartShape::strokeContains(const QPoint &p)
+{
+ if(m_strokeSVP)
+ return art_svp_point_wind(m_strokeSVP, p.x(), p.y()) != 0;
+ else
+ return false;
+}
+
+void LibartShape::update(CanvasItemUpdate reason, int param1, int param2)
+{
+ if(reason == UPDATE_STYLE)
+ {
+ if(!m_fillPainter || !m_strokePainter)
+ LibartShape::init();
+ if(m_fillPainter)
+ m_fillPainter->update(m_style);
+ if(m_strokePainter)
+ m_strokePainter->update(m_style);
+ m_canvas->invalidate(this, false);
+ }
+ else if(reason == UPDATE_TRANSFORM)
+ {
+ reset();
+ m_canvas->invalidate(this, true);
+ }
+ else if(reason == UPDATE_ZOOM)
+ reset();
+ else if(reason == UPDATE_PAN)
+ {
+ if(m_fillSVP)
+ ksvg_art_svp_move(m_fillSVP, param1, param2);
+ if(m_strokeSVP)
+ ksvg_art_svp_move(m_strokeSVP, param1, param2);
+ }
+ else if(reason == UPDATE_LINEWIDTH)
+ {
+ if(m_strokeSVP)
+ {
+ art_svp_free(m_strokeSVP);
+ m_strokeSVP = 0;
+ }
+ init();
+ m_canvas->invalidate(this, true);
+ }
+}
+
+void LibartShape::draw(SVGShapeImpl *shape)
+{
+ if(!m_referenced && (!m_style->getVisible() || !m_style->getDisplay() || !shape->directRender()))
+ return;
+
+ bool fillOk = m_fillSVP && m_style->isFilled();
+ bool strokeOk = m_strokeSVP && m_style->isStroked() && m_style->getStrokeWidth()->baseVal()->value() > 0; // Spec: A zero value causes no stroke to be painted.
+
+ if(fillOk || strokeOk)
+ {
+ if(m_fillPainter && m_fillSVP)
+ m_fillPainter->draw(m_canvas, m_fillSVP, m_style, shape);
+
+ if(m_strokePainter && m_strokeSVP)
+ m_strokePainter->draw(m_canvas, m_strokeSVP, m_style, shape);
+ }
+}
+
+void LibartShape::init(const SVGMatrixImpl *)
+{
+}
+
+void LibartPainter::update(SVGStylableImpl *style)
+{
+ if(paintType(style) != SVG_PAINTTYPE_URI)
+ {
+ QColor qcolor;
+ if(paintType(style) == SVG_PAINTTYPE_CURRENTCOLOR)
+ qcolor = style->getColor()->rgbColor().color();
+ else
+ qcolor = color(style);
+
+ short _opacity = static_cast<short>(opacity(style) * 255 + 0.5);
+
+ // Spec: clamping
+ _opacity = _opacity < 0 ? 0 : _opacity;
+ _opacity = _opacity > 255 ? 255 : _opacity;
+
+ m_color = KSVGHelper::toArtColor(qcolor, _opacity);
+ }
+}
+
+void LibartPainter::draw(LibartCanvas *canvas, _ArtSVP *svp, SVGStylableImpl *style, SVGShapeImpl *shape)
+{
+ ArtSVP *clippedSvp = canvas->clipSingleSVP(svp, shape);
+
+ // Clipping
+ ArtDRect bbox;
+ art_drect_svp(&bbox, clippedSvp);
+
+ // clamp to viewport
+ int x0 = int(bbox.x0);
+ int y0 = int(bbox.y0);
+
+ // Use inclusive coords for x1/y1 for clipToBuffer
+ int x1 = int(ceil(bbox.x1)) - 1;
+ int y1 = int(ceil(bbox.y1)) - 1;
+
+ if(x0 < int(canvas->width()) && y0 < int(canvas->height()) && x1 > -1 && y1 > -1)
+ {
+ canvas->clipToBuffer(x0, y0, x1, y1);
+
+ QRect screenBBox(x0, y0, x1 - x0 + 1, y1 - y0 + 1);
+
+ QByteArray mask = SVGMaskElementImpl::maskRectangle(shape, screenBBox);
+
+ if(paintType(style) == SVG_PAINTTYPE_URI)
+ {
+ LibartPaintServer *pserver = static_cast<LibartPaintServer *>(SVGPaintServerImpl::paintServer(shape->ownerDoc(), paintUri(style)));
+
+ if(pserver)
+ {
+ pserver->setBBoxTarget(shape);
+ if(!pserver->finalized())
+ pserver->finalizePaintServer();
+ pserver->render(canvas, clippedSvp, opacity(style), mask, screenBBox);
+ }
+ }
+ else
+ canvas->drawSVP(clippedSvp, m_color, mask, screenBBox);
+ }
+
+ art_svp_free(clippedSvp);
+}
+
+LibartStrokePainter::LibartStrokePainter(SVGStylableImpl *style)
+{
+ update(style);
+}
+
+LibartFillPainter::LibartFillPainter(SVGStylableImpl *style)
+{
+ update(style);
+}
+
+void LibartShape::init()
+{
+ if(m_style->isFilled())
+ {
+ if(m_fillPainter == 0)
+ m_fillPainter = new LibartFillPainter(m_style);
+ }
+ else
+ {
+ delete m_fillPainter;
+ m_fillPainter = 0;
+ }
+
+ // Spec: A zero value causes no stroke to be painted.
+ if(m_style->isStroked() && m_style->getStrokeWidth()->baseVal()->value() > 0)
+ {
+ if(m_strokePainter == 0)
+ m_strokePainter = new LibartStrokePainter(m_style);
+ }
+ else
+ {
+ delete m_strokePainter;
+ m_strokePainter = 0;
+ }
+}
+
+void LibartShape::initClipItem()
+{
+ init();
+}
+
+ArtSVP *LibartShape::clipSVP()
+{
+ return m_fillSVP;
+}
+
+void LibartShape::freeSVPs()
+{
+ if(m_fillSVP)
+ art_svp_free(m_fillSVP);
+ if(m_strokeSVP)
+ art_svp_free(m_strokeSVP);
+
+ m_fillSVP = 0;
+ m_strokeSVP = 0;
+}
+
+void LibartShape::calcClipSVP(ArtVpath *vec, SVGStylableImpl *style, const SVGMatrixImpl *matrix, _ArtSVP **clipSVP)
+{
+ double affine[6];
+ KSVGHelper::matrixToAffine(matrix, affine);
+
+ if(!style)
+ {
+ art_free(vec);
+ return;
+ }
+
+ ArtVpath *vtemp = art_vpath_affine_transform(vec, affine);
+ art_free(vec);
+ vec = vtemp;
+
+ ArtSVP *temp;
+ ArtSvpWriter *swr;
+ temp = art_svp_from_vpath(vec);
+
+ if(style->getClipRule() == RULE_EVENODD)
+ swr = art_svp_writer_rewind_new(ART_WIND_RULE_ODDEVEN);
+ else
+ swr = art_svp_writer_rewind_new(ART_WIND_RULE_NONZERO);
+
+ art_svp_intersector(temp, swr);
+ *clipSVP = art_svp_writer_rewind_reap(swr);
+
+ art_svp_free(temp);
+ art_free(vec);
+}
+
+void LibartShape::calcSVPs(ArtVpath *vec, SVGStylableImpl *style, const SVGMatrixImpl *matrix, ArtSVP **strokeSVP, ArtSVP **fillSVP)
+{
+ if(style)
+ {
+ double affine[6];
+ KSVGHelper::matrixToAffine(matrix, affine);
+
+ ArtVpath *temp = art_vpath_affine_transform(vec, affine);
+ art_free(vec);
+ vec = temp;
+ calcSVPInternal(vec, style, affine, strokeSVP, fillSVP);
+ }
+ else
+ art_free(vec);
+}
+
+void LibartShape::calcSVPs(ArtBpath *bpath, SVGStylableImpl *style, const SVGMatrixImpl *matrix, ArtSVP **strokeSVP, ArtSVP **fillSVP)
+{
+ if(style)
+ {
+ double affine[6];
+ KSVGHelper::matrixToAffine(matrix, affine);
+
+ ArtBpath *temp = art_bpath_affine_transform(bpath, affine);
+ ArtVpath *vec = ksvg_art_bez_path_to_vec(temp, 0.25);
+ art_free(temp);
+ calcSVPInternal(vec, style, affine, strokeSVP, fillSVP);
+ }
+}
+
+void LibartShape::calcSVPInternal(ArtVpath *vec, SVGStylableImpl *style, double *affine, ArtSVP **strokeSVP, ArtSVP **fillSVP)
+{
+ ArtSVP *svp;
+
+ // Filling
+ {
+ ArtSvpWriter *swr;
+ ArtSVP *temp;
+ temp = art_svp_from_vpath(vec);
+
+ if(style->getFillRule() == RULE_EVENODD)
+ swr = art_svp_writer_rewind_new(ART_WIND_RULE_ODDEVEN);
+ else
+ swr = art_svp_writer_rewind_new(ART_WIND_RULE_NONZERO);
+
+ art_svp_intersector(temp, swr);
+ svp = art_svp_writer_rewind_reap(swr);
+
+ *fillSVP = svp;
+ art_svp_free(temp);
+ }
+
+ // Stroking
+ if(style->isStroked() || style->getStrokeColor()->paintType() == SVG_PAINTTYPE_URI)
+ {
+ double ratio = art_affine_expansion(affine);
+
+ unsigned int dashLength;
+ if(style->getDashArray() && (dashLength = style->getDashArray()->baseVal()->numberOfItems()) > 0)
+ {
+ // HACK: libart will hang in art_vpath_dash() if passed an array with only zeroes.
+ bool allZeroes = true;
+
+ // there are dashes to be rendered
+ ArtVpathDash dash;
+ dash.offset = int(style->getDashOffset()->baseVal()->value()) * ratio;
+ dash.n_dash = dashLength;
+ double *dashes = new double[dashLength];
+ for(unsigned int i = 0; i < dashLength; i++)
+ {
+ dashes[i] = style->getDashArray()->baseVal()->getItem(i)->value() * ratio;
+ if(dashes[i] != 0.0)
+ allZeroes = false;
+ }
+ dash.dash = dashes;
+
+ if(!allZeroes)
+ {
+ // get the dashed VPath and use that for the stroke render operation
+ ArtVpath *vec2 = art_vpath_dash(vec, &dash);
+ art_free(vec);
+ vec = vec2;
+ }
+
+ // reset the dashes
+ delete [] dashes;
+ }
+
+ double penWidth = style->getStrokeWidth()->baseVal()->value() * ratio;
+ svp = art_svp_vpath_stroke(vec, (ArtPathStrokeJoinType)style->getJoinStyle(), (ArtPathStrokeCapType)style->getCapStyle(), penWidth, style->getStrokeMiterlimit(), 0.25);
+
+ *strokeSVP = svp;
+ }
+ art_free(vec);
+}
+
+// #####
+
+LibartRectangle::LibartRectangle(LibartCanvas *c, SVGRectElementImpl *rect)
+: LibartShape(c, rect), m_rect(rect)
+{
+ init();
+}
+
+void LibartRectangle::draw()
+{
+ if(isVisible())
+ LibartShape::draw(m_rect);
+}
+
+bool LibartRectangle::isVisible()
+{
+ // Spec: a value of zero disables rendering
+ return LibartShape::isVisible(m_rect) && m_rect->width()->baseVal()->value() > 0 && m_rect->height()->baseVal()->value() > 0;
+}
+
+void LibartRectangle::init()
+{
+ init(m_rect->screenCTM());
+}
+
+void LibartRectangle::init(const SVGMatrixImpl *screenCTM)
+{
+ LibartShape::init();
+ double x = m_rect->x()->baseVal()->value();
+ double y = m_rect->y()->baseVal()->value();
+ double width = m_rect->width()->baseVal()->value();
+ double height = m_rect->height()->baseVal()->value();
+ double rx = m_rect->rx()->baseVal()->value();
+ double ry = m_rect->ry()->baseVal()->value();
+
+ // Spec: If there is no rx or ry specified, draw a normal rect
+ if(rx == -1 && ry == -1)
+ {
+ ArtVpath *vec = allocVPath(6);
+
+ vec[0].code = ART_MOVETO;
+ vec[0].x = x;
+ vec[0].y = y;
+
+ vec[1].code = ART_LINETO;
+ vec[1].x = x;
+ vec[1].y = y + height;
+
+ vec[2].code = ART_LINETO;
+ vec[2].x = x + width;
+ vec[2].y = y + height;
+
+ vec[3].code = ART_LINETO;
+ vec[3].x = x + width;
+ vec[3].y = y;
+
+ vec[4].code = ART_LINETO;
+ vec[4].x = x;
+ vec[4].y = y;
+
+ vec[5].code = ART_END;
+
+ if(m_context == NORMAL)
+ calcSVPs(vec, m_rect, screenCTM, &m_strokeSVP, &m_fillSVP);
+ else
+ calcClipSVP(vec, m_rect, screenCTM, &m_fillSVP);
+ }
+ else
+ {
+ ArtVpath *res;
+ ArtBpath *vec = allocBPath(10);
+
+ int i = 0;
+
+ // Spec: If rx isn't specified, but ry, set rx to ry
+ if(rx == -1)
+ rx = ry;
+
+ // Spec: If ry isn't specified, but rx, set ry to rx
+ if(ry == -1)
+ ry = rx;
+
+ // Spec: If rx is greater than half of the width of the rectangle
+ // then set rx to half of the width
+ if(rx > width / 2)
+ rx = width / 2;
+
+ // Spec: If ry is greater than half of the height of the rectangle
+ // then set ry to half of the height
+ if(ry > height / 2)
+ ry = height / 2;
+
+ vec[i].code = ART_MOVETO_OPEN;
+ vec[i].x3 = x + rx;
+ vec[i].y3 = y;
+
+ i++;
+
+ vec[i].code = ART_CURVETO;
+ vec[i].x1 = x + rx * (1 - 0.552);
+ vec[i].y1 = y;
+ vec[i].x2 = x;
+ vec[i].y2 = y + ry * (1 - 0.552);
+ vec[i].x3 = x;
+ vec[i].y3 = y + ry;
+
+ i++;
+
+ if(ry < height / 2)
+ {
+ vec[i].code = ART_LINETO;
+ vec[i].x3 = x;
+ vec[i].y3 = y + height - ry;
+
+ i++;
+ }
+ vec[i].code = ART_CURVETO;
+ vec[i].x1 = x;
+ vec[i].y1 = y + height - ry * (1 - 0.552);
+ vec[i].x2 = x + rx * (1 - 0.552);
+ vec[i].y2 = y + height;
+ vec[i].x3 = x + rx;
+ vec[i].y3 = y + height;
+
+ i++;
+
+ if(rx < width / 2)
+ {
+ vec[i].code = ART_LINETO;
+ vec[i].x3 = x + width - rx;
+ vec[i].y3 = y + height;
+
+ i++;
+ }
+
+ vec[i].code = ART_CURVETO;
+ vec[i].x1 = x + width - rx * (1 - 0.552);
+ vec[i].y1 = y + height;
+ vec[i].x2 = x + width;
+ vec[i].y2 = y + height - ry * (1 - 0.552);
+ vec[i].x3 = x + width;
+
+ vec[i].y3 = y + height - ry;
+
+ i++;
+
+ if(ry < height / 2)
+ {
+ vec[i].code = ART_LINETO;
+ vec[i].x3 = x + width;
+ vec[i].y3 = y + ry;
+
+ i++;
+ }
+ vec[i].code = ART_CURVETO;
+ vec[i].x1 = x + width;
+ vec[i].y1 = y + ry * (1 - 0.552);
+ vec[i].x2 = x + width - rx * (1 - 0.552);
+ vec[i].y2 = y;
+ vec[i].x3 = x + width - rx;
+ vec[i].y3 = y;
+
+ i++;
+
+ if(rx < width / 2)
+ {
+ vec[i].code = ART_LINETO;
+ vec[i].x3 = x + rx;
+ vec[i].y3 = y;
+
+ i++;
+ }
+
+ vec[i].code = ART_END;
+
+ res = ksvg_art_bez_path_to_vec(vec, 0.25);
+ if(m_context == NORMAL)
+ calcSVPs(res, m_rect, screenCTM, &m_strokeSVP, &m_fillSVP);
+ else
+ calcClipSVP(res, m_rect, screenCTM, &m_fillSVP);
+ art_free(vec);
+ }
+}
+
+// #####
+
+LibartEllipse::LibartEllipse(LibartCanvas *c, SVGEllipseElementImpl *ellipse)
+: LibartShape(c, ellipse), m_ellipse(ellipse)
+{
+ init();
+}
+
+void LibartEllipse::draw()
+{
+ if(isVisible())
+ LibartShape::draw(m_ellipse);
+}
+
+bool LibartEllipse::isVisible()
+{
+ // Spec: dont render when rx and/or ry is zero
+ return LibartShape::isVisible(m_ellipse) && m_ellipse->rx()->baseVal()->value() > 0 && m_ellipse->ry()->baseVal()->value() > 0;
+}
+
+void LibartEllipse::init()
+{
+ init(m_ellipse->screenCTM());
+}
+
+void LibartEllipse::init(const SVGMatrixImpl *screenCTM)
+{
+ LibartShape::init();
+ ArtBpath *temp = allocBPath(6);
+
+ double x1, y1, x2, y2, x3, y3;
+ double len = 0.55228474983079356;
+ double rx = m_ellipse->rx()->baseVal()->value();
+ double ry = m_ellipse->ry()->baseVal()->value();
+ double cx = m_ellipse->cx()->baseVal()->value();
+ double cy = m_ellipse->cy()->baseVal()->value();
+ double cos4[] = {1.0, 0.0, -1.0, 0.0, 1.0};
+ double sin4[] = {0.0, 1.0, 0.0, -1.0, 0.0};
+ int i = 0;
+
+ temp[i].code = ART_MOVETO;
+ temp[i].x3 = cx + rx;
+ temp[i].y3 = cy;
+
+ i++;
+
+ while(i < 5)
+ {
+ x1 = cos4[i-1] + len * cos4[i];
+ y1 = sin4[i-1] + len * sin4[i];
+ x2 = cos4[i] + len * cos4[i-1];
+ y2 = sin4[i] + len * sin4[i-1];
+ x3 = cos4[i];
+ y3 = sin4[i];
+
+ temp[i].code = ART_CURVETO;
+ temp[i].x1 = cx + x1 * rx;
+ temp[i].y1 = cy + y1 * ry;
+ temp[i].x2 = cx + x2 * rx;
+ temp[i].y2 = cy + y2 * ry;
+ temp[i].x3 = cx + x3 * rx;
+ temp[i].y3 = cy + y3 * ry;
+
+ i++;
+ }
+
+ temp[i].code = ART_END;
+
+ if(m_context == NORMAL)
+ calcSVPs(temp, m_ellipse, screenCTM, &m_strokeSVP, &m_fillSVP);
+ else
+ calcClipSVP(ksvg_art_bez_path_to_vec(temp, 0.25), m_ellipse, screenCTM, &m_fillSVP);
+ art_free(temp);
+}
+
+// #####
+
+LibartCircle::LibartCircle(LibartCanvas *c, SVGCircleElementImpl *circle)
+: LibartShape(c, circle), m_circle(circle)
+{
+ init();
+}
+
+void LibartCircle::draw()
+{
+ // Spec: a value of zero disables rendering
+ if(isVisible())
+ LibartShape::draw(m_circle);
+}
+
+bool LibartCircle::isVisible()
+{
+ // Spec: dont render when rx and/or ry is zero
+ return LibartShape::isVisible(m_circle) && m_circle->r()->baseVal()->value() > 0;
+}
+
+void LibartCircle::init()
+{
+ init(m_circle->screenCTM());
+}
+
+void LibartCircle::init(const SVGMatrixImpl *screenCTM)
+{
+ LibartShape::init();
+ ArtBpath *temp = allocBPath(6);
+
+ double x1, y1, x2, y2, x3, y3;
+ double len = 0.55228474983079356;
+ double r = m_circle->r()->baseVal()->value();
+ double cx = m_circle->cx()->baseVal()->value();
+ double cy = m_circle->cy()->baseVal()->value();
+ double cos4[] = {1.0, 0.0, -1.0, 0.0, 1.0};
+ double sin4[] = {0.0, 1.0, 0.0, -1.0, 0.0};
+ int i = 0;
+
+ temp[i].code = ART_MOVETO;
+ temp[i].x3 = cx + r;
+ temp[i].y3 = cy;
+
+ i++;
+
+ while(i < 5)
+ {
+ x1 = cos4[i-1] + len * cos4[i];
+ y1 = sin4[i-1] + len * sin4[i];
+ x2 = cos4[i] + len * cos4[i-1];
+ y2 = sin4[i] + len * sin4[i-1];
+ x3 = cos4[i];
+ y3 = sin4[i];
+
+ temp[i].code = ART_CURVETO;
+ temp[i].x1 = cx + x1 * r;
+ temp[i].y1 = cy + y1 * r;
+ temp[i].x2 = cx + x2 * r;
+ temp[i].y2 = cy + y2 * r;
+ temp[i].x3 = cx + x3 * r;
+ temp[i].y3 = cy + y3 * r;
+
+ i++;
+ }
+
+ temp[i].code = ART_END;
+
+ if(m_context == NORMAL)
+ calcSVPs(temp, m_circle, screenCTM, &m_strokeSVP, &m_fillSVP);
+ else
+ calcClipSVP(ksvg_art_bez_path_to_vec(temp, 0.25), m_circle, screenCTM, &m_fillSVP);
+ art_free(temp);
+}
+
+// #####
+
+LibartLine::LibartLine(LibartCanvas *c, SVGLineElementImpl *line)
+: LibartShape(c, line), MarkerHelper(), m_line(line)
+{
+ init();
+}
+
+LibartLine::~LibartLine()
+{
+}
+
+void LibartLine::draw()
+{
+ LibartShape::draw(m_line);
+
+ if(m_line->hasMarkers())
+ {
+ double x1 = m_line->x1()->baseVal()->value();
+ double y1 = m_line->y1()->baseVal()->value();
+ double x2 = m_line->x2()->baseVal()->value();
+ double y2 = m_line->y2()->baseVal()->value();
+ double slope = SVGAngleImpl::todeg(atan2(y2 - y1, x2 - x1));
+
+ if(m_line->hasStartMarker())
+ doStartMarker(m_line, m_line, x1, y1, slope);
+ if(m_line->hasEndMarker())
+ doEndMarker(m_line, m_line, x2, y2, slope);
+ }
+}
+
+bool LibartLine::isVisible()
+{
+ return LibartShape::isVisible(m_line);
+}
+
+void LibartLine::init()
+{
+ init(m_line->screenCTM());
+}
+
+void LibartLine::init(const SVGMatrixImpl *screenCTM)
+{
+ LibartShape::init();
+ ArtVpath *vec;
+
+ vec = allocVPath(3);
+
+ vec[0].code = ART_MOVETO_OPEN;
+ vec[0].x = m_line->x1()->baseVal()->value();
+ vec[0].y = m_line->y1()->baseVal()->value();
+
+ vec[1].code = ART_LINETO;
+ vec[1].x = m_line->x2()->baseVal()->value();
+ vec[1].y = m_line->y2()->baseVal()->value();
+
+ // A subpath consisting of a moveto and lineto to the same exact location or a subpath consisting of a moveto
+ // and a closepath will be stroked only if the 'stroke-linecap' property is set to "round", producing a circle
+ // centered at the given point.
+ if(vec[1].x == vec[0].x && vec[1].y == vec[0].y && m_line->getCapStyle() == PATH_STROKE_CAP_ROUND)
+ vec[1].x += .5;
+
+ vec[2].code = ART_END;
+
+ if(m_context == NORMAL)
+ {
+ calcSVPs(vec, m_line, screenCTM, &m_strokeSVP, &m_fillSVP);
+ art_svp_free(m_fillSVP);
+ m_fillSVP = 0;
+ }
+ else
+ calcClipSVP(vec, m_line, screenCTM, &m_fillSVP);
+}
+
+// #####
+LibartPoly::LibartPoly(LibartCanvas *c, SVGPolyElementImpl *poly)
+: LibartShape(c, poly), MarkerHelper(), m_poly(poly)
+{
+}
+
+LibartPoly::~LibartPoly()
+{
+}
+
+void LibartPoly::init()
+{
+ init(m_poly->screenCTM());
+}
+
+void LibartPoly::draw()
+{
+ LibartShape::draw(m_poly);
+
+ if(m_poly->hasMarkers())
+ m_poly->drawMarkers();
+}
+
+bool LibartPoly::isVisible()
+{
+ return LibartShape::isVisible(m_poly);
+}
+
+// #####
+LibartPolyline::LibartPolyline(LibartCanvas *c, SVGPolylineElementImpl *poly)
+: LibartPoly(c, poly)
+{
+ LibartPoly::init();
+}
+
+LibartPolyline::~LibartPolyline()
+{
+}
+
+void LibartPolyline::init(const SVGMatrixImpl *screenCTM)
+{
+ LibartShape::init();
+ unsigned int numberOfPoints = m_poly->points()->numberOfItems();
+
+ if(numberOfPoints < 1)
+ return;
+
+ ArtVpath *polyline = allocVPath(2 + numberOfPoints);
+
+ polyline[0].code = ART_MOVETO_OPEN;
+ polyline[0].x = m_poly->points()->getItem(0)->x();
+ polyline[0].y = m_poly->points()->getItem(0)->y();
+
+ unsigned int index;
+ for(index = 1; index < numberOfPoints; index++)
+ {
+ polyline[index].code = ART_LINETO;
+ polyline[index].x = m_poly->points()->getItem(index)->x();
+ polyline[index].y = m_poly->points()->getItem(index)->y();
+ }
+
+ // A subpath consisting of a moveto and lineto to the same exact location or a subpath consisting of a moveto
+ // and a closepath will be stroked only if the 'stroke-linecap' property is set to "round", producing a circle
+ // centered at the given point.
+ if(numberOfPoints == 2 && polyline[1].x == polyline[0].x && polyline[1].y == polyline[0].y && m_poly->getCapStyle() == PATH_STROKE_CAP_ROUND)
+ polyline[1].x += .5;
+
+
+ if(m_poly->isFilled()) // if the polyline must be filled, inform libart that it should not be closed.
+ {
+ polyline[index].code = (ArtPathcode) ART_END2;
+ polyline[index].x = m_poly->points()->getItem(0)->x();
+ polyline[index++].y = m_poly->points()->getItem(0)->y();
+ }
+
+ polyline[index].code = ART_END;
+ if(m_context == NORMAL)
+ calcSVPs(polyline, m_poly, screenCTM, &m_strokeSVP, &m_fillSVP);
+ else
+ calcClipSVP(polyline, m_poly, screenCTM, &m_fillSVP);
+}
+
+// #####
+
+LibartPolygon::LibartPolygon(LibartCanvas *c, SVGPolygonElementImpl *poly)
+: LibartPoly(c, poly)
+{
+ LibartPoly::init();
+}
+
+LibartPolygon::~LibartPolygon()
+{
+}
+
+void LibartPolygon::init(const SVGMatrixImpl *screenCTM)
+{
+ LibartShape::init();
+ unsigned int numberOfPoints = m_poly->points()->numberOfItems();
+
+ if(numberOfPoints < 1)
+ return;
+
+ ArtVpath *polygon = allocVPath(2 + numberOfPoints);
+
+ polygon[0].code = ART_MOVETO;
+ polygon[0].x = m_poly->points()->getItem(0)->x();
+ polygon[0].y = m_poly->points()->getItem(0)->y();
+
+ unsigned int index;
+ for(index = 1; index < numberOfPoints; index++)
+ {
+ polygon[index].code = ART_LINETO;
+ polygon[index].x = m_poly->points()->getItem(index)->x();
+ polygon[index].y = m_poly->points()->getItem(index)->y();
+ }
+
+ polygon[index].code = ART_LINETO;
+ polygon[index].x = m_poly->points()->getItem(0)->x();
+ polygon[index].y = m_poly->points()->getItem(0)->y();
+
+ index++;
+ polygon[index].code = ART_END;
+
+ if(m_context == NORMAL)
+ calcSVPs(polygon, m_poly, screenCTM, &m_strokeSVP, &m_fillSVP);
+ else
+ calcClipSVP(polygon, m_poly, screenCTM, &m_fillSVP);
+}
+
+// #####
+
+LibartPath::LibartPath(LibartCanvas *c, SVGPathElementImpl *path)
+: LibartShape(c, path), MarkerHelper(), T2P::BezierPathLibart(), ::SVGPathParser(), m_path(path)
+{
+ reset();
+}
+
+LibartPath::~LibartPath()
+{
+}
+
+void LibartPath::reset()
+{
+ m_array.resize(0);
+ LibartShape::reset();
+}
+
+void LibartPath::draw()
+{
+ LibartShape::draw(m_path);
+
+ if(m_path->hasMarkers())
+ {
+ SVGPathElementImpl::MarkerData markers = m_path->markerData();
+ int numMarkers = markers.numMarkers();
+
+ if(m_path->hasStartMarker())
+ doStartMarker(m_path, m_path, markers.marker(0).x, markers.marker(0).y, markers.marker(0).angle);
+
+ for(int i = 1; i < numMarkers - 1; i++)
+ {
+ if(m_path->hasMidMarker())
+ doMidMarker(m_path, m_path, markers.marker(i).x, markers.marker(i).y, markers.marker(i).angle);
+ }
+
+ if(m_path->hasEndMarker())
+ doEndMarker(m_path, m_path, markers.marker(numMarkers - 1).x, markers.marker(numMarkers - 1).y, markers.marker(numMarkers - 1).angle);
+ }
+}
+
+bool LibartPath::isVisible()
+{
+ return LibartShape::isVisible(m_path);
+}
+
+void LibartPath::init()
+{
+ init(m_path->screenCTM());
+}
+
+void LibartPath::init(const SVGMatrixImpl *screenCTM)
+{
+ LibartShape::init();
+ if(m_array.count() > 0)
+ {
+ if(m_context == NORMAL)
+ calcSVPs(m_array.data(), m_path, screenCTM, &m_strokeSVP, &m_fillSVP);
+ else
+ calcClipSVP(ksvg_art_bez_path_to_vec(m_array.data(), 0.25), m_path, screenCTM, &m_fillSVP);
+ }
+ else if(!m_path->getAttribute("d").string().isEmpty())
+ {
+ parseSVG(m_path->getAttribute("d").string(), true);
+
+ int index = m_array.count();
+ double curx = m_array[index - 1].x3;
+ double cury = m_array[index - 1].y3;
+
+ // Find last subpath
+ int find = -1;
+ for(int i = index - 1; i >= 0; i--)
+ {
+ if(m_array[i].code == ART_MOVETO_OPEN || m_array[i].code == ART_MOVETO)
+ {
+ find = i;
+ break;
+ }
+ }
+
+ // Fix a problem where the .svg file used floats as values... (sofico.svg)
+ if(curx != m_array[find].x3 && cury != m_array[find].y3)
+ {
+ if((int) curx == (int) m_array[find].x3 && (int) cury == (int) m_array[find].y3)
+ {
+ ensureSpace(m_array, index)
+
+ m_array[index].code = ART_LINETO;
+ m_array[index].x3 = m_array[find].x3;
+ m_array[index].y3 = m_array[find].y3;
+
+ curx = m_array[find].x3;
+ cury = m_array[find].y3;
+
+ index++;
+ }
+ }
+
+ // handle filled paths that are not closed explicitly
+ if(m_path->getFillColor()->paintType() != SVG_PAINTTYPE_NONE)
+ {
+ if((int) curx != (int) m_array[find].x3 || (int) cury != (int) m_array[find].y3)
+ {
+ ensureSpace(m_array, index)
+
+ m_array[index].code = (ArtPathcode)ART_END2;
+ m_array[index].x3 = m_array[find].x3;
+ m_array[index].y3 = m_array[find].y3;
+
+ curx = m_array[find].x3;
+ cury = m_array[find].y3;
+
+ index++;
+ }
+ }
+
+ // close
+ ensureSpace(m_array, index)
+
+ m_array[index].code = ART_END;
+
+ // A subpath consisting of a moveto and lineto to the same exact location or a subpath consisting of a moveto
+ // and a closepath will be stroked only if the 'stroke-linecap' property is set to "round", producing a circle
+ // centered at the given point.
+ if(index == 2 && m_array[1].code == ART_LINETO && m_array[1].x3 == m_array[0].x3 && m_array[1].y3 == m_array[0].y3 && m_path->getCapStyle() == PATH_STROKE_CAP_ROUND)
+ m_array[1].x3 += .5;
+
+ // There are pure-moveto paths which reference paint servers *bah*
+ // Do NOT render them
+ bool render = false;
+ for(int i = index; i >= 0; i--)
+ {
+ if(m_array[i].code != ART_MOVETO_OPEN && m_array[i].code != ART_MOVETO && !(m_array[i].code >= ART_END))
+ {
+ render = true;
+ break;
+ }
+ }
+
+ if(render && m_context == NORMAL)
+ calcSVPs(m_array.data(), m_path, screenCTM, &m_strokeSVP, &m_fillSVP);
+ else
+ calcClipSVP(ksvg_art_bez_path_to_vec(m_array.data(), 0.25), m_path, screenCTM, &m_fillSVP);
+ }
+}
+
+void LibartPath::svgMoveTo(double x1, double y1, bool closed, bool)
+{
+ int index = m_array.count();
+
+ if(index > 0 && !closed)
+ {
+ // Find last subpath
+ int find = -1;
+ for(int i = index - 1; i >= 0; i--)
+ {
+ if(m_array[i].code == ART_MOVETO_OPEN || m_array[i].code == ART_MOVETO)
+ {
+ find = i;
+ break;
+ }
+ }
+
+ ensureSpace(m_array, index)
+
+ m_array[index].code = (ArtPathcode) ART_END2;
+ m_array[index].x3 = m_array[find].x3;
+ m_array[index].y3 = m_array[find].y3;
+
+ index++;
+ }
+
+ ensureSpace(m_array, index)
+
+ m_array[index].code = (index == 0) ? ART_MOVETO : ART_MOVETO_OPEN;
+ m_array[index].x3 = x1;
+ m_array[index].y3 = y1;
+}
+
+void LibartPath::svgLineTo(double x1, double y1, bool)
+{
+ int index = m_array.count();
+
+ ensureSpace(m_array, index)
+
+ m_array[index].code = ART_LINETO;
+ m_array[index].x3 = x1;
+ m_array[index].y3 = y1;
+}
+
+void LibartPath::svgCurveToCubic(double x1, double y1, double x2, double y2, double x3, double y3, bool)
+{
+ int index = m_array.count();
+
+ ensureSpace(m_array, index)
+
+ m_array[index].code = ART_CURVETO;
+ m_array[index].x1 = x1;
+ m_array[index].y1 = y1;
+ m_array[index].x2 = x2;
+ m_array[index].y2 = y2;
+ m_array[index].x3 = x3;
+ m_array[index].y3 = y3;
+}
+
+void LibartPath::svgClosePath()
+{
+ int index = m_array.count();
+ double curx = m_array[index - 1].x3;
+ double cury = m_array[index - 1].y3;
+
+ int find = -1;
+ for(int i = index - 1; i >= 0; i--)
+ {
+ if(m_array[i].code == ART_MOVETO_OPEN || m_array[i].code == ART_MOVETO)
+ {
+ find = i;
+ break;
+ }
+ }
+
+ if(find != -1)
+ {
+ if(m_array[find].x3 != curx || m_array[find].y3 != cury)
+ {
+ ensureSpace(m_array, index)
+
+ m_array[index].code = ART_LINETO;
+ m_array[index].x3 = m_array[find].x3;
+ m_array[index].y3 = m_array[find].y3;
+ }
+ }
+}
+
+// #####
+
+LibartClipPath::LibartClipPath(LibartCanvas *c, SVGClipPathElementImpl *clipPath)
+: CanvasClipPath(clipPath), m_canvas(c)
+{
+ m_clipSVP = 0;
+ m_clipItems.setAutoDelete(true);
+}
+
+LibartClipPath::~LibartClipPath()
+{
+ if(m_clipSVP)
+ art_svp_free(m_clipSVP);
+}
+
+void LibartClipPath::update(CanvasItemUpdate, int, int)
+{
+ if(m_clipSVP)
+ art_svp_free(m_clipSVP);
+ m_clipSVP = 0;
+}
+
+void LibartClipPath::init()
+{
+ SVGMatrixImpl *clipMatrix = 0;
+
+ // Start with referencing element's coordinate system
+ SVGLocatableImpl *locatableReferrer = dynamic_cast<SVGLocatableImpl *>(m_clipPath->getBBoxTarget());
+ if(locatableReferrer)
+ clipMatrix = locatableReferrer->getScreenCTM();
+ else
+ clipMatrix = SVGSVGElementImpl::createSVGMatrix();
+
+ if(m_clipPath->clipPathUnits()->baseVal() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX && m_clipPath->getBBoxTarget())
+ {
+ SVGRectImpl *rect = m_clipPath->getBBoxTarget()->getBBox();
+
+ clipMatrix->translate(rect->qrect().x(), rect->qrect().y());
+ clipMatrix->scaleNonUniform(rect->qrect().width(), rect->qrect().height());
+
+ rect->deref();
+ }
+
+ // Add transformations on the clipPath element itself
+ if(m_clipPath->localMatrix())
+ clipMatrix->multiply(m_clipPath->localMatrix());
+
+ if(m_clipSVP)
+ {
+ art_svp_free(m_clipSVP);
+ m_clipSVP = 0;
+ }
+
+ DOM::Node node = m_clipPath->firstChild();
+ for(; !node.isNull(); node = node.nextSibling())
+ {
+ SVGElementImpl *element = m_clipPath->ownerDoc()->getElementFromHandle(node.handle());
+ SVGShapeImpl *shape = dynamic_cast<SVGShapeImpl *>(element);
+ SVGTestsImpl *tests = dynamic_cast<SVGTestsImpl *>(element);
+
+ bool ok = tests ? tests->ok() : true;
+
+ if(element && shape && ok && !shape->isContainer())
+ {
+ LibartClipItem *clipElement = dynamic_cast<LibartClipItem *>(shape->item());
+
+ if(dynamic_cast<LibartText *>(shape->item()))
+ {
+ // The cast to a clipElement above is failing when it is valid. But only
+ // in the plugin - svgdisplay works fine. What's going on? (Adrian)
+ clipElement = dynamic_cast<LibartText *>(shape->item());
+ }
+
+ if(clipElement)
+ {
+ clipElement->setRenderContext(CLIPPING);
+
+ // Push coordinate system down to children.
+ SVGLocatableImpl *locatable = dynamic_cast<SVGLocatableImpl *>(shape);
+ if(locatable)
+ locatable->updateCachedScreenCTM(clipMatrix);
+
+ clipElement->initClipItem();
+
+ ArtSVP *one = clipElement->clipSVP();
+ if(!one)
+ break;
+
+ if(m_clipSVP == 0)
+ m_clipSVP = LibartCanvas::copy_svp(one);
+ else
+ {
+ ArtSVP *svp_union = art_svp_union(m_clipSVP, one);
+ art_svp_free(m_clipSVP);
+ m_clipSVP = svp_union;
+ }
+ }
+ }
+ }
+
+ clipMatrix->deref();
+}
+
+void LibartClipPath::draw()
+{
+}
+
+ArtSVP *LibartClipPath::clipSVP()
+{
+ return m_clipSVP;
+}
+
+// #####
+
+LibartImage::LibartImage(LibartCanvas *c, SVGImageElementImpl *image)
+: m_canvas(c), m_image(image)
+{
+}
+
+LibartImage::~LibartImage()
+{
+}
+
+void LibartImage::draw()
+{
+ if(isVisible())
+ {
+ SVGMatrixImpl *ctm = m_image->scaledImageMatrix();
+ QImage image = m_image->scaledImage();
+ KSVGPolygon clippingPolygon = m_image->clippingShape();
+
+ m_canvas->drawImage(image, m_image, ctm, clippingPolygon);
+
+ ctm->deref();
+ }
+}
+
+bool LibartImage::isVisible()
+{
+ return (m_referenced || (m_image->getVisible() && m_image->getDisplay() && m_image->directRender())) && m_image->image();
+}
+
+void LibartImage::init()
+{
+}
+
+QRect LibartImage::bbox() const
+{
+ QRect bbox(static_cast<int>(m_image->x()->baseVal()->value()),
+ static_cast<int>(m_image->y()->baseVal()->value()),
+ static_cast<int>(m_image->width()->baseVal()->value()),
+ static_cast<int>(m_image->height()->baseVal()->value()));
+
+
+ return SVGHelperImpl::fromUserspace(m_image, bbox);
+}
+
+// #####
+
+LibartMarker::LibartMarker(LibartCanvas *c, SVGMarkerElementImpl *marker)
+: CanvasMarker(marker), m_canvas(c)
+{
+}
+
+LibartMarker::~LibartMarker()
+{
+}
+
+void LibartMarker::init()
+{
+}
+
+void LibartMarker::draw()
+{
+}
+
+// #####
+
+LibartText::LibartText(LibartCanvas *c, SVGTextElementImpl *text)
+: CanvasText(text), m_canvas(c)
+{
+ m_drawFillItems.setAutoDelete(true);
+ m_drawStrokeItems.setAutoDelete(true);
+ m_fillPainters.setAutoDelete(true);
+ m_strokePainters.setAutoDelete(true);
+
+ init();
+}
+
+LibartText::~LibartText()
+{
+ clearSVPs();
+}
+
+LibartText::SVPElement::~SVPElement()
+{
+ if(svp)
+ art_svp_free(svp);
+}
+
+QRect LibartText::bbox() const
+{
+ QRect result, rect;
+
+ QPtrListIterator<SVPElement> it1(m_drawFillItems);
+ QPtrListIterator<SVPElement> it2(m_drawStrokeItems);
+
+ SVPElement *fill = it1.current(), *stroke = it2.current();
+ while(fill != 0 || stroke != 0)
+ {
+ ArtIRect *irect = new ArtIRect();
+ ArtVpath *vpath = art_vpath_from_svp((stroke && stroke->svp) ? stroke->svp : fill->svp);
+ art_vpath_bbox_irect(vpath, irect);
+ art_free(vpath);
+
+ rect.setX(irect->x0);
+ rect.setY(irect->y0);
+ rect.setWidth(irect->x1 - irect->x0);
+ rect.setHeight(irect->y1 - irect->y0);
+
+ delete irect;
+
+ result = result.unite(rect);
+
+ fill = ++it1;
+ stroke = ++it2;
+ }
+ return result;
+}
+
+bool LibartText::fillContains(const QPoint &p)
+{
+ QPtrListIterator<SVPElement> it(m_drawFillItems);
+
+ SVPElement *fill = it.current();
+ while(fill && fill->svp)
+ {
+ if(fill->svp && art_svp_point_wind(fill->svp, p.x(), p.y()) != 0)
+ return true;
+
+ fill = ++it;
+ }
+
+ return false;
+}
+
+bool LibartText::strokeContains(const QPoint &p)
+{
+ QPtrListIterator<SVPElement> it(m_drawStrokeItems);
+
+ SVPElement *stroke = it.current();
+ while(stroke && stroke->svp)
+ {
+ if(stroke->svp && art_svp_point_wind(stroke->svp, p.x(), p.y()) != 0)
+ return true;
+
+ stroke = ++it;
+ }
+
+ return false;
+}
+
+void LibartText::update(CanvasItemUpdate reason, int param1, int param2)
+{
+ if(reason == UPDATE_STYLE)
+ {
+ QPtrListIterator<SVPElement> it1(m_drawFillItems);
+ QPtrListIterator<SVPElement> it2(m_drawStrokeItems);
+ SVPElement *fill = it1.current(), *stroke = it2.current();
+ while(fill != 0 || stroke != 0)
+ {
+ SVGTextContentElementImpl *text = fill ? fill->element : stroke->element;
+
+ bool fillOk = fill && fill->svp && text->isFilled();
+ bool strokeOk = stroke && stroke->svp && text->isStroked() && text->getStrokeWidth()->baseVal()->value() > 0; // Spec: A zero value causes no stroke to be painted.
+ if(fillOk || strokeOk)
+ {
+ if(m_fillPainters.find(text))
+ m_fillPainters[text]->update(text);
+
+ if(m_strokePainters.find(text))
+ m_strokePainters[text]->update(text);
+ }
+ fill = ++it1;
+ stroke = ++it2;
+ }
+ m_canvas->invalidate(this, false);
+ }
+ else if(reason == UPDATE_TRANSFORM)
+ {
+ clearSVPs();
+ init();
+ m_canvas->invalidate(this, true);
+ }
+ else if(reason == UPDATE_ZOOM)
+ {
+ clearSVPs();
+ init();
+ }
+ else if(reason == UPDATE_PAN)
+ {
+ QPtrListIterator<SVPElement> it1(m_drawFillItems);
+ QPtrListIterator<SVPElement> it2(m_drawStrokeItems);
+
+ double affine[6];
+ KSVGHelper::matrixToAffine(m_text->screenCTM(), affine);
+
+ SVPElement *fill = it1.current(), *stroke = it2.current();
+ while(fill != 0 || stroke != 0)
+ {
+ SVGTextContentElementImpl *text = fill ? fill->element : stroke->element;
+
+ bool fillOk = fill && fill->svp && text->isFilled();
+ bool strokeOk = stroke && stroke->svp && text->isStroked() && text->getStrokeWidth()->baseVal()->value() > 0; // Spec: A zero value causes no stroke to be painted.
+
+ if(fillOk)
+ ksvg_art_svp_move(fill->svp, param1, param2);
+ if(strokeOk)
+ ksvg_art_svp_move(stroke->svp, param1, param2);
+ fill = ++it1;
+ stroke = ++it2;
+ }
+ }
+ /*
+ else if(reason == UPDATE_LINEWIDTH)
+ {
+ }*/
+}
+
+void LibartText::draw()
+{
+ QPtrListIterator<SVPElement> it1(m_drawFillItems);
+ QPtrListIterator<SVPElement> it2(m_drawStrokeItems);
+
+ SVPElement *fill = it1.current(), *stroke = it2.current();
+ while(fill != 0 || stroke != 0)
+ {
+ SVGTextContentElementImpl *text = fill ? fill->element : stroke->element;
+ if(!text || !text->getVisible() || !text->getDisplay() || !text->directRender())
+ return;
+
+ bool fillOk = fill && fill->svp && text->isFilled();
+ bool strokeOk = stroke && stroke->svp && text->isStroked() && text->getStrokeWidth()->baseVal()->value() > 0; // Spec: A zero value causes no stroke to be painted.
+
+ if(fillOk || strokeOk)
+ {
+ if(fillOk && m_fillPainters.find(text))
+ m_fillPainters[text]->draw(m_canvas, fill->svp, text, text);
+
+ if(strokeOk && m_strokePainters.find(text))
+ m_strokePainters[text]->draw(m_canvas, stroke->svp, text, text);
+ }
+ fill = ++it1;
+ stroke = ++it2;
+ }
+}
+
+bool LibartText::isVisible()
+{
+ bool foundVisible = false;
+ QPtrListIterator<SVPElement> it1(m_drawFillItems);
+ QPtrListIterator<SVPElement> it2(m_drawStrokeItems);
+
+ SVPElement *fill = it1.current(), *stroke = it2.current();
+ while(fill != 0 || stroke != 0)
+ {
+ SVGTextContentElementImpl *text = fill ? fill->element : stroke->element;
+ if(text && text->getVisible() && text->getDisplay() && text->directRender())
+ {
+ foundVisible = true;
+ break;
+ }
+
+ fill = ++it1;
+ stroke = ++it2;
+ }
+
+ return foundVisible;
+}
+
+void LibartText::init()
+{
+ init(m_text->screenCTM());
+}
+
+void LibartText::renderCallback(SVGTextContentElementImpl *element, const SVGMatrixImpl *screenCTM, T2P::GlyphSet *glyph, T2P::GlyphLayoutParams *params, double anchor) const
+{
+ unsigned int glyphCount = glyph->glyphCount(); // Don't call it n times in the for loop
+ for(unsigned int i = 0; i < glyphCount; i++)
+ {
+ T2P::GlyphAffinePair *glyphAffine = glyph->set()[i];
+ ArtBpath *bezier = static_cast<const T2P::BezierPathLibart *>(glyphAffine->transformatedPath())->m_array.data();
+ ArtBpath *result = bezier;
+
+ // text-anchor support
+ if(anchor != 0)
+ {
+ double correct[6];
+
+ if(!params->tb())
+ art_affine_translate(correct, -anchor, 0);
+ else
+ art_affine_translate(correct, 0, -anchor);
+
+ ArtBpath *temp = art_bpath_affine_transform(result, correct);
+ //art_free(result);
+ result = temp;
+ }
+
+ ArtSVP *fillSVP = 0, *strokeSVP = 0;
+
+ if(m_context == NORMAL)
+ LibartShape::calcSVPs(result, m_text, screenCTM, &strokeSVP, &fillSVP);
+ else
+ LibartShape::calcClipSVP(ksvg_art_bez_path_to_vec(result, 0.25), m_text, screenCTM, &fillSVP);
+
+ SVPElement *fillElement = new SVPElement();
+ fillElement->svp = fillSVP;
+ fillElement->element = element;
+
+ SVPElement *strokeElement = new SVPElement();
+ strokeElement->svp = strokeSVP;
+ strokeElement->element = element;
+
+ m_drawFillItems.append(fillElement);
+ m_drawStrokeItems.append(strokeElement);
+
+ if(!m_fillPainters.find(element) && element->isFilled())
+ m_fillPainters.insert(element, new LibartFillPainter(element));
+
+ // Spec: A zero value causes no stroke to be painted.
+ if(!m_strokePainters.find(element) && element->isStroked() && element->getStrokeWidth()->baseVal()->value() > 0)
+ m_strokePainters.insert(element, new LibartStrokePainter(element));
+ }
+}
+
+void LibartText::init(const SVGMatrixImpl *screenCTM)
+{
+ int curx = 0, cury = 0, endx = 0, endy = 0;
+ KSVGTextChunk *textChunk = CanvasText::createTextChunk(m_canvas, screenCTM, curx, cury, endx, endy);
+
+ if(textChunk->count() > 0)
+ CanvasText::createGlyphs(textChunk, m_canvas, screenCTM, curx, cury, endx, endy);
+
+ delete textChunk;
+}
+
+void LibartText::clearSVPs()
+{
+ m_drawFillItems.clear();
+ m_drawStrokeItems.clear();
+ m_fillPainters.clear();
+ m_strokePainters.clear();
+}
+
+void LibartText::addTextDecoration(SVGTextContentElementImpl *element, double x, double y, double width, double height) const
+{
+ if(m_text->isFilled() || m_text->isStroked())
+ {
+ // compute rect svp
+ ArtVpath *vec = allocVPath(6);
+
+ vec[0].code = ART_MOVETO;
+ vec[0].x = x;
+ vec[0].y = y;
+
+ vec[1].code = ART_LINETO;
+ vec[1].x = x;
+ vec[1].y = y + height;
+
+ vec[2].code = ART_LINETO;
+ vec[2].x = x + width;
+ vec[2].y = y + height;
+
+ vec[3].code = ART_LINETO;
+ vec[3].x = x + width;
+ vec[3].y = y;
+
+ vec[4].code = ART_LINETO;
+ vec[4].x = x;
+ vec[4].y = y;
+
+ vec[5].code = ART_END;
+ double affine[6];
+ KSVGHelper::matrixToAffine(m_text->screenCTM(), affine);
+
+ ArtVpath *temp = art_vpath_affine_transform(vec, affine);
+ art_free(vec);
+ vec = temp;
+
+ if(m_text->isFilled())
+ {
+ ArtSvpWriter *swr;
+ ArtSVP *temp = art_svp_from_vpath(vec);
+
+ swr = art_svp_writer_rewind_new(ART_WIND_RULE_ODDEVEN);
+
+ art_svp_intersector(temp, swr);
+ ArtSVP *fillSVP = art_svp_writer_rewind_reap(swr);
+
+ SVPElement *fillElement = new SVPElement();
+ fillElement->svp = fillSVP;
+ fillElement->element = element;
+
+ m_drawFillItems.append(fillElement);
+
+ if(!m_fillPainters.find(element) && element->isFilled())
+ m_fillPainters.insert(element, new LibartFillPainter(element));
+
+ art_svp_free(temp);
+ }
+ // Stroking
+ if(m_text->isStroked() || m_text->getStrokeColor()->paintType() == SVG_PAINTTYPE_URI)
+ {
+ double ratio = art_affine_expansion(affine);
+ ArtSVP *strokeSVP = art_svp_vpath_stroke(vec, (ArtPathStrokeJoinType)m_text->getJoinStyle(), (ArtPathStrokeCapType)m_text->getCapStyle(), m_text->getStrokeWidth()->baseVal()->value() * ratio, m_text->getStrokeMiterlimit(), 0.25);
+
+ SVPElement *strokeElement = new SVPElement();
+ strokeElement->svp = strokeSVP;
+ strokeElement->element = element;
+
+ m_drawStrokeItems.append(strokeElement);
+
+ // Spec: A zero value causes no stroke to be painted.
+ if(!m_strokePainters.find(element) && element->isStroked() && element->getStrokeWidth()->baseVal()->value() > 0)
+ m_strokePainters.insert(element, new LibartStrokePainter(element));
+ }
+ art_free(vec);
+ }
+}
+
+void LibartText::initClipItem()
+{
+ init();
+}
+
+ArtSVP *LibartText::clipSVP()
+{
+ ArtSVP *svp = 0;
+ QPtrListIterator<SVPElement> it(m_drawFillItems);
+
+ SVPElement *fill = it.current();
+ while(fill && fill->svp)
+ {
+ if(svp == 0)
+ svp = LibartCanvas::copy_svp(fill->svp);
+ else
+ {
+ ArtSVP *svp_union = art_svp_union(svp, fill->svp);
+ art_svp_free(svp);
+ svp = svp_union;
+ }
+
+ fill = ++it;
+ }
+
+ return svp;
+}
+
+ArtRender *LibartPaintServer::createRenderer(QRect bbox, KSVGCanvas *c)
+{
+ int x0 = bbox.x();
+ int y0 = bbox.y();
+ int x1 = bbox.right();
+ int y1 = bbox.bottom();
+
+ c->clipToBuffer(x0, y0, x1, y1);
+
+ // Note: We always pass 3 for the number of channels since the ART_ALPHA parameter
+ // adds the alpha channel when present.
+ ArtRender *render = 0;
+ render = art_render_new(QMIN(x0, x1),
+ QMIN(y0, y1),
+ QMAX(x0, x1) + 1,
+ QMAX(y0, y1) + 1,
+ c->renderingBuffer() + x0 * c->nrChannels() + y0 * c->rowStride(),
+ c->rowStride(), 3, 8,
+ c->nrChannels() == 3 ? ART_ALPHA_NONE : ART_ALPHA_PREMUL, 0);
+
+ return render;
+}
+
+void LibartGradient::parseGradientStops(SVGGradientElementImpl *gradient)
+{
+ const double epsilon = DBL_EPSILON;
+
+ for(DOM::Node node = gradient->firstChild(); !node.isNull(); node = node.nextSibling())
+ {
+ SVGStopElementImpl *elem = dynamic_cast<SVGStopElementImpl *>(m_gradient->ownerDoc()->getElementFromHandle(node.handle()));
+ if(elem)
+ {
+ m_stops.resize(m_stops.size() + 1);
+
+ ArtGradientStop *stop = &(m_stops[m_stops.size() - 1]);
+
+ stop->offset = elem->offset()->baseVal();
+
+ // Spec: clamp range to 0 to 1
+ if(stop->offset < epsilon)
+ stop->offset = 0;
+ else if(stop->offset > 1 - epsilon)
+ stop->offset = 1;
+
+ // Spec: if offset is less than previous offset, set it to the previous offset
+ if(m_stops.size() > 1 && stop->offset < (stop - 1)->offset + epsilon)
+ stop->offset = (stop - 1)->offset;
+
+ // Get color
+ QColor qStopColor;
+
+ if(elem->getStopColor()->colorType() == SVG_COLORTYPE_CURRENTCOLOR)
+ qStopColor = elem->getColor()->rgbColor().color();
+ else
+ qStopColor = elem->getStopColor()->rgbColor().color();
+
+ // Convert in a libart suitable form
+ QString tempName = qStopColor.name();
+ const char *str = tempName.latin1();
+
+ int stopColor = 0;
+
+ for(int i = 1; str[i]; i++)
+ {
+ int hexval;
+ if(str[i] >= '0' && str[i] <= '9')
+ hexval = str[i] - '0';
+ else if (str[i] >= 'A' && str[i] <= 'F')
+ hexval = str[i] - 'A' + 10;
+ else if (str[i] >= 'a' && str[i] <= 'f')
+ hexval = str[i] - 'a' + 10;
+ else
+ break;
+
+ stopColor = (stopColor << 4) + hexval;
+ }
+
+ // Apply stop-opacity
+ float opacity = elem->stopOpacity();
+
+ // Get rgba color including stop-opacity
+ Q_UINT32 rgba = (stopColor << 8) | int(opacity * 255.0 + 0.5);
+ Q_UINT32 r, g, b, a;
+
+ a = rgba & 0xff;
+ r = (rgba >> 24) & 0xff;
+ g = (rgba >> 16) & 0xff;
+ b = (rgba >> 8) & 0xff;
+
+ stop->color[0] = ART_PIX_MAX_FROM_8(r);
+ stop->color[1] = ART_PIX_MAX_FROM_8(g);
+ stop->color[2] = ART_PIX_MAX_FROM_8(b);
+ stop->color[3] = ART_PIX_MAX_FROM_8(a);
+ }
+ }
+}
+
+void LibartGradient::finalizePaintServer()
+{
+ parseGradientStops(m_gradient->stopsSource());
+
+ QString _href = SVGURIReferenceImpl::getTarget(m_gradient->href()->baseVal().string());
+ if(!_href.isEmpty())
+ reference(_href);
+
+ setFinalized();
+}
+
+void LibartGradient::reference(const QString &)
+{
+}
+
+void LibartLinearGradient::render(KSVGCanvas *c, ArtSVP *svp, float opacity, QByteArray mask, QRect screenBBox)
+{
+ if(!m_stops.isEmpty())
+ {
+ m_linear->converter()->finalize(getBBoxTarget(), m_linear->ownerSVGElement(), m_linear->gradientUnits()->baseVal());
+
+ ArtKSVGGradientLinear *linear = art_new(ArtKSVGGradientLinear, 1);
+
+ if(m_linear->spreadMethod()->baseVal() == SVG_SPREADMETHOD_REPEAT)
+ linear->spread = ART_GRADIENT_REPEAT;
+ else if(m_linear->spreadMethod()->baseVal() == SVG_SPREADMETHOD_REFLECT)
+ linear->spread = ART_GRADIENT_REFLECT;
+ else
+ linear->spread = ART_GRADIENT_PAD;
+
+ linear->interpolation = m_linear->getColorInterpolation() == CI_SRGB ? ART_KSVG_SRGB_INTERPOLATION : ART_KSVG_LINEARRGB_INTERPOLATION;
+
+ ArtRender *render = createRenderer(screenBBox, c);
+
+ double _x1 = m_linear->x1()->baseVal()->value();
+ double _y1 = m_linear->y1()->baseVal()->value();
+ double _x2 = m_linear->x2()->baseVal()->value();
+ double _y2 = m_linear->y2()->baseVal()->value();
+
+ // Respect current transformation matrix (so gradients zoom with...)
+ SVGTransformableImpl *transformable = dynamic_cast<SVGTransformableImpl *>(getBBoxTarget());
+ SVGMatrixImpl *matrix = 0;
+ if(transformable)
+ matrix = transformable->getScreenCTM();
+ else
+ matrix = SVGSVGElementImpl::createSVGMatrix();
+
+ const double epsilon = DBL_EPSILON;
+
+ if(m_linear->gradientUnits()->baseVal() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
+ {
+ // Here we're undoing the unit-converter's work because putting the
+ // bounding box transform into the matrix here lets the gradient transform
+ // sit at the right point in the chain to work with bounding box coordinates. It
+ // also removes the need for code to generate the 'not perpendicular to gradient vector' effect.
+ SVGRectImpl *userBbox = getBBoxTarget()->getBBox();
+
+ double width = userBbox->width();
+ double height = userBbox->height();
+
+ // Catch case of width or height of zero, which can be the case for lines.
+ if(width < epsilon)
+ width = 1;
+ if(height < epsilon)
+ height = 1;
+
+ _x1 /= width;
+ _y1 /= height;
+ _x2 /= width;
+ _y2 /= height;
+
+ matrix->translate(userBbox->x(), userBbox->y());
+ matrix->scaleNonUniform(width, height);
+
+ userBbox->deref();
+ }
+
+ // Adjust to gradient transform
+ SVGMatrixImpl *gradTrans = m_linear->gradientTransform()->baseVal()->concatenate();
+ if(gradTrans)
+ {
+ matrix->multiply(gradTrans);
+ gradTrans->deref();
+ }
+
+ double dx = _x2 - _x1;
+ double dy = _y2 - _y1;
+
+ if(fabs(dx) < epsilon && fabs(dy) < epsilon)
+ {
+ // Lines can generate (0, 0) with bbox coords.
+ dx = 1;
+ dy = 0;
+ }
+
+ double angle = atan2(dy, dx);
+ double length = sqrt(dx * dx + dy * dy);
+
+ const double pi = 3.14159265358979323846;
+
+ matrix->translate(_x1, _y1);
+ matrix->scale(length);
+ matrix->rotate(angle * 180.0 / pi);
+
+ double affine[6];
+
+ KSVGHelper::matrixToAffine(matrix, affine);
+ art_affine_invert(linear->affine, affine);
+
+ matrix->deref();
+
+ QMemArray<ArtGradientStop> stops = m_stops;
+ stops.detach();
+
+ for(unsigned int i = 0; i < stops.size(); i++)
+ stops[i].color[3] = ArtPixMaxDepth(stops[i].color[3] * opacity + 0.5);
+
+ if(m_linear->x1()->baseVal()->valueInSpecifiedUnits() == m_linear->x2()->baseVal()->valueInSpecifiedUnits()
+ && m_linear->y1()->baseVal()->valueInSpecifiedUnits() == m_linear->y2()->baseVal()->valueInSpecifiedUnits())
+ {
+ // Spec: If x1 == x2 and y1 == y2, paint the area in a single colour, using the colour
+ // of the last stop.
+ //
+ // Using valueInSpecifiedUnits() so that we are comparing the values before possible
+ // conversion to bounding box units by the converter.
+ if(stops.size() > 1)
+ {
+ stops[0] = stops[stops.size() - 1];
+ stops.resize(1);
+ }
+ }
+
+ linear->stops = &(stops[0]);
+ linear->n_stops = stops.size();
+
+ art_render_svp(render, svp);
+ art_ksvg_render_gradient_linear(render, linear, ART_FILTER_HYPER);
+
+ if(mask.data())
+ art_render_mask(render, screenBBox.left(), screenBBox.top(), screenBBox.right() + 1, screenBBox.bottom() + 1,
+ (const art_u8 *)mask.data(), screenBBox.width());
+
+ art_render_invoke(render);
+
+ art_free(linear);
+ }
+}
+
+void LibartRadialGradient::render(KSVGCanvas *c, ArtSVP *svp, float opacity, QByteArray mask, QRect screenBBox)
+{
+ if(!m_stops.isEmpty())
+ {
+ m_radial->converter()->finalize(getBBoxTarget(), m_radial->ownerSVGElement(), m_radial->gradientUnits()->baseVal());
+
+ ArtKSVGGradientRadial *radial = art_new(ArtKSVGGradientRadial, 1);
+
+ if(m_radial->spreadMethod()->baseVal() == SVG_SPREADMETHOD_REPEAT)
+ radial->spread = ART_GRADIENT_REPEAT;
+ else if(m_radial->spreadMethod()->baseVal() == SVG_SPREADMETHOD_REFLECT)
+ radial->spread = ART_GRADIENT_REFLECT;
+ else
+ radial->spread = ART_GRADIENT_PAD;
+
+ radial->interpolation = m_radial->getColorInterpolation() == CI_SRGB ? ART_KSVG_SRGB_INTERPOLATION : ART_KSVG_LINEARRGB_INTERPOLATION;
+
+ ArtRender *render = createRenderer(screenBBox, c);
+
+ // Respect current transformation matrix (so gradients zoom with...)
+ SVGTransformableImpl *transformable = dynamic_cast<SVGTransformableImpl *>(getBBoxTarget());
+ SVGMatrixImpl *matrix = 0;
+ if(transformable)
+ matrix = transformable->getScreenCTM();
+ else
+ matrix = SVGSVGElementImpl::createSVGMatrix();
+
+ double _cx = m_radial->cx()->baseVal()->value();
+ double _cy = m_radial->cy()->baseVal()->value();
+ double _r = m_radial->r()->baseVal()->value();
+
+ double _fx;
+ double _fy;
+
+ // Spec: If attribute fx is not specified, fx will coincide with cx.
+ if(m_radial->getAttribute("fx").isEmpty())
+ _fx = _cx;
+ else
+ _fx = m_radial->fx()->baseVal()->value();
+
+ // Spec: If attribute fy is not specified, fy will coincide with cy.
+ if(m_radial->getAttribute("fy").isEmpty())
+ _fy = _cy;
+ else
+ _fy = m_radial->fy()->baseVal()->value();
+
+ const double epsilon = DBL_EPSILON;
+
+ if(m_radial->gradientUnits()->baseVal() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
+ {
+ // Here we're undoing the unit-converter's work because putting the
+ // bounding box transform into the matrix here lets the gradient transform
+ // sit at the right point in the chain to work with bounding box coordinates.
+ // It also produces the elliptical shape due to the non-uniform scaling.
+ SVGRectImpl *userBBox = getBBoxTarget()->getBBox();
+
+ double width = userBBox->width();
+ double height = userBBox->height();
+
+ // Catch case of width or height of zero, which can be the case for lines.
+ if(width < epsilon)
+ width = 1;
+ if(height < epsilon)
+ height = 1;
+
+ _cx /= width;
+ _cy /= height;
+ _fx /= width;
+ _fy /= height;
+ _r /= (sqrt(width * width + height * height) / 1.4142135623731);
+
+ matrix->translate(userBBox->x(), userBBox->y());
+ matrix->scaleNonUniform(width, height);
+
+ userBBox->deref();
+ }
+
+ // Adjust to gradient transforms
+ SVGMatrixImpl *transform = m_radial->gradientTransform()->baseVal()->concatenate();
+
+ if(transform)
+ {
+ matrix->multiply(transform);
+ transform->deref();
+ }
+
+ double fx = (_fx - _cx) / _r;
+ double fy = (_fy - _cy) / _r;
+
+ if(fx * fx + fy * fy > 0.99)
+ {
+ // Spec: If (fx, fy) lies outside the circle defined by (cx, cy) and r, set (fx, fy)
+ // to the point of intersection of the line through (fx, fy) and the circle.
+ //
+ // Note: We need to keep (fx, fy) inside the unit circle in order for
+ // libart to render the gradient correctly.
+ double angle = atan2(fy, fx);
+ fx = cos(angle) * 0.99;
+ fy = sin(angle) * 0.99;
+ }
+
+ radial->fx = fx;
+ radial->fy = fy;
+
+ matrix->translate(_cx, _cy);
+ matrix->scale(_r);
+
+ double affine[6];
+
+ KSVGHelper::matrixToAffine(matrix, affine);
+ art_affine_invert(radial->affine, affine);
+
+ matrix->deref();
+
+ QMemArray<ArtGradientStop> stops = m_stops;
+ stops.detach();
+
+ for(unsigned int i = 0; i < stops.size(); i++)
+ stops[i].color[3] = ArtPixMaxDepth(stops[i].color[3] * opacity + 0.5);
+
+ radial->stops = &(stops[0]);
+ radial->n_stops = stops.size();
+
+ art_render_svp(render, svp);
+ art_ksvg_render_gradient_radial(render, radial, ART_FILTER_HYPER);
+
+ if(mask.data())
+ art_render_mask(render, screenBBox.left(), screenBBox.top(), screenBBox.right() + 1, screenBBox.bottom() + 1,
+ (const art_u8 *)mask.data(), screenBBox.width());
+
+ art_render_invoke(render);
+
+ art_free(radial);
+ }
+}
+
+LibartPattern::LibartPattern(SVGPatternElementImpl *pattern)
+ : m_pattern(pattern)
+{
+}
+
+void LibartPattern::finalizePaintServer()
+{
+ m_pattern->finalizePaintServer();
+ setFinalized();
+}
+
+void LibartPattern::reference(const QString &href)
+{
+ m_pattern->reference(href);
+}
+
+void LibartPattern::render(KSVGCanvas *c, ArtSVP *svp, float opacity, QByteArray mask, QRect screenBBox)
+{
+ SVGPatternElementImpl::Tile tile = m_pattern->createTile(getBBoxTarget());
+
+ if(!tile.image().isNull())
+ {
+ QWMatrix m = tile.screenToTile();
+ double affine[6];
+
+ affine[0] = m.m11();
+ affine[1] = m.m12();
+ affine[2] = m.m21();
+ affine[3] = m.m22();
+ affine[4] = m.dx();
+ affine[5] = m.dy();
+
+ int alpha = int(opacity * 255 + 0.5);
+
+ ksvg_art_rgb_texture(svp, c->renderingBuffer() + screenBBox.x() * c->nrChannels() + screenBBox.y() * c->rowStride(), screenBBox.left(), screenBBox.top(), screenBBox.right() + 1, screenBBox.bottom() + 1, c->rowStride(), c->nrChannels(), tile.image().bits(), tile.image().width(), tile.image().height(), tile.image().width() * 4, affine, ART_FILTER_NEAREST, 0L, alpha, (art_u8 *)mask.data());
+ }
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/backends/libart/LibartCanvasItems.h b/ksvg/plugin/backends/libart/LibartCanvasItems.h
new file mode 100644
index 00000000..c62224e5
--- /dev/null
+++ b/ksvg/plugin/backends/libart/LibartCanvasItems.h
@@ -0,0 +1,414 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ aint with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef LIBARTCANVASITEMS_H
+#define LIBARTCANVASITEMS_H
+
+#include <qptrlist.h>
+
+#include "CanvasItems.h"
+#include "LibartCanvas.h"
+#include "BezierPathLibart.h"
+
+#include "SVGPathElementImpl.h"
+#include "SVGPolyElementImpl.h"
+#include "SVGLineElementImpl.h"
+#include "SVGRectElementImpl.h"
+#include "SVGTextElementImpl.h"
+#include "SVGCircleElementImpl.h"
+#include "SVGEllipseElementImpl.h"
+
+// Helpers
+#define allocVPath(n) art_new(ArtVpath, n)
+#define allocBPath(n) art_new(ArtBpath, n)
+
+#define LIBART_CLASS(Class, Type, Member) \
+class Libart##Class : public LibartShape \
+{ \
+public: \
+ Libart##Class(LibartCanvas *c, Type *Member); \
+ virtual ~Libart##Class() { } \
+ virtual void draw(); \
+ virtual bool isVisible(); \
+ virtual void init(); \
+ virtual void init(const SVGMatrixImpl *screenCTM); \
+ virtual SVGElementImpl *element() const { return m_##Member; } \
+protected: \
+ Type *m_##Member; \
+};
+
+struct _ArtSVP;
+struct _ArtBpath;
+struct _ArtRender;
+struct _ArtGradientStop;
+
+namespace KSVG
+{
+ class SVGImageElementImpl;
+ class SVGGradientElementImpl;
+ class SVGRadialGradientElementImpl;
+ class SVGLinearGradientElementImpl;
+ class SVGPatternElementImpl;
+
+ class LibartPaintServer : public CanvasPaintServer
+ {
+ public:
+ LibartPaintServer() : CanvasPaintServer() {}
+ virtual ~LibartPaintServer() {}
+
+ virtual void render(KSVGCanvas *c, _ArtSVP *svp, float opacity, QByteArray mask, QRect screenBBox) = 0;
+
+ _ArtRender *createRenderer(QRect rect, KSVGCanvas *c);
+ };
+
+ class LibartGradient : public LibartPaintServer
+ {
+ public:
+ LibartGradient(SVGGradientElementImpl *gradient) : m_gradient(gradient) {}
+ virtual ~LibartGradient() {}
+
+ void parseGradientStops(SVGGradientElementImpl *gradient);
+
+ virtual void finalizePaintServer();
+ virtual void reference(const QString &href);
+
+ protected:
+ SVGGradientElementImpl *m_gradient;
+ QMemArray<_ArtGradientStop> m_stops;
+ };
+
+ class LibartLinearGradient : public LibartGradient
+ {
+ public:
+ LibartLinearGradient(SVGLinearGradientElementImpl *linear) : LibartGradient(linear), m_linear(linear) {}
+
+ virtual void render(KSVGCanvas *c, _ArtSVP *svp, float opacity, QByteArray mask, QRect screenBBox);
+
+ protected:
+ SVGLinearGradientElementImpl *m_linear;
+ };
+
+ class LibartRadialGradient : public LibartGradient
+ {
+ public:
+ LibartRadialGradient(SVGRadialGradientElementImpl *radial) : LibartGradient(radial), m_radial(radial) {}
+
+ virtual void render(KSVGCanvas *c, _ArtSVP *svp, float opacity, QByteArray mask, QRect screenBBox);
+
+ protected:
+ SVGRadialGradientElementImpl *m_radial;
+ };
+
+ class LibartPattern : public LibartPaintServer
+ {
+ public:
+ LibartPattern(SVGPatternElementImpl *pattern);
+ virtual ~LibartPattern() {}
+
+ virtual void finalizePaintServer();
+ virtual void reference(const QString &href);
+
+ virtual void render(KSVGCanvas *c, _ArtSVP *svp, float opacity, QByteArray mask, QRect screenBBox);
+
+ protected:
+ SVGPatternElementImpl *m_pattern;
+ };
+
+ class LibartPainter
+ {
+ public:
+ LibartPainter() { m_color = 0; }
+ virtual ~LibartPainter() {}
+
+ void update(SVGStylableImpl *style);
+ void draw(LibartCanvas *canvas, _ArtSVP *svp, SVGStylableImpl *style, SVGShapeImpl *shape);
+
+ virtual float opacity(SVGStylableImpl *style) const = 0;
+ virtual unsigned short paintType(SVGStylableImpl *style) const = 0;
+ virtual QString paintUri(SVGStylableImpl *style) const = 0;
+ virtual QRgb color(SVGStylableImpl *style) const = 0;
+
+ protected:
+ art_u32 m_color;
+ };
+
+ class LibartFillPainter : public LibartPainter
+ {
+ public:
+ LibartFillPainter(SVGStylableImpl *style);
+
+ float opacity(SVGStylableImpl *style) const { return style->getFillOpacity() * style->getOpacity(); }
+ unsigned short paintType(SVGStylableImpl *style) const { return style->getFillColor()->paintType(); }
+ QString paintUri(SVGStylableImpl *style) const { return style->getFillColor()->uri().string(); }
+ QRgb color(SVGStylableImpl *style) const { return style->getFillColor()->rgbColor().color(); }
+ };
+
+ class LibartStrokePainter : public LibartPainter
+ {
+ public:
+ LibartStrokePainter(SVGStylableImpl *style);
+
+ float opacity(SVGStylableImpl *style) const { return style->getStrokeOpacity() * style->getOpacity(); }
+ unsigned short paintType(SVGStylableImpl *style) const { return style->getStrokeColor()->paintType(); }
+ QString paintUri(SVGStylableImpl *style) const { return style->getStrokeColor()->uri().string(); }
+ QRgb color(SVGStylableImpl *style) const { return style->getStrokeColor()->rgbColor().color(); }
+ };
+
+ class LibartClipItem
+ {
+ public:
+ LibartClipItem() { m_context = NORMAL; }
+ virtual ~LibartClipItem() {}
+
+ virtual void initClipItem() = 0;
+ void setRenderContext(RenderContext context) { m_context = context; }
+ virtual ArtSVP *clipSVP() = 0;
+
+ protected:
+ RenderContext m_context;
+ };
+
+ class LibartShape : public CanvasItem, public LibartClipItem
+ {
+ public:
+ LibartShape(LibartCanvas *c, SVGStylableImpl *style);
+ virtual ~LibartShape();
+
+ virtual QRect bbox() const;
+ virtual bool fillContains(const QPoint &p);
+ virtual bool strokeContains(const QPoint &p);
+ virtual void update(CanvasItemUpdate reason, int param1 = 0, int param2 = 0);
+ void draw(SVGShapeImpl *shape);
+ bool isVisible(SVGShapeImpl *shape);
+
+ virtual void init();
+ virtual void init(const SVGMatrixImpl *);
+ virtual void reset() { freeSVPs(); init(); }
+
+ void initClipItem();
+ ArtSVP *clipSVP();
+
+ static void calcClipSVP(ArtVpath *vec, SVGStylableImpl *style, const SVGMatrixImpl *matrix, _ArtSVP **clipSVP);
+ static void calcSVPs(ArtVpath *vec, SVGStylableImpl *style, const SVGMatrixImpl *matrix, _ArtSVP **strokeSVP, _ArtSVP **fillSVP);
+ static void calcSVPs(_ArtBpath *bpath, SVGStylableImpl *style, const SVGMatrixImpl *matrix, _ArtSVP **strokeSVP, _ArtSVP **fillSVP);
+
+ protected:
+ void freeSVPs();
+ static void calcSVPInternal(ArtVpath *vec, SVGStylableImpl *style, double *affine, ArtSVP **strokeSVP, ArtSVP **fillSVP);
+
+ _ArtSVP *m_fillSVP;
+ _ArtSVP *m_strokeSVP;
+ LibartFillPainter *m_fillPainter;
+ LibartStrokePainter *m_strokePainter;
+ LibartCanvas *m_canvas;
+ SVGStylableImpl *m_style;
+ };
+
+ LIBART_CLASS(Rectangle, SVGRectElementImpl, rect)
+ LIBART_CLASS(Ellipse, SVGEllipseElementImpl, ellipse)
+ LIBART_CLASS(Circle, SVGCircleElementImpl, circle)
+
+ class LibartLine : public LibartShape, public MarkerHelper
+ {
+ public:
+ LibartLine(LibartCanvas *c, SVGLineElementImpl *line);
+ virtual ~LibartLine();
+
+ virtual void draw();
+ virtual bool isVisible();
+ virtual void init();
+ virtual void init(const SVGMatrixImpl *screenCTM);
+
+ virtual SVGElementImpl *element() const { return m_line; }
+
+ protected:
+ SVGLineElementImpl *m_line;
+ };
+
+ class LibartPoly : public LibartShape, public MarkerHelper
+ {
+ public:
+ LibartPoly(LibartCanvas *c, SVGPolyElementImpl *poly);
+ virtual ~LibartPoly();
+
+ virtual void draw();
+ virtual bool isVisible();
+ virtual void init();
+ virtual void init(const SVGMatrixImpl *screenCTM) = 0;
+
+ virtual SVGElementImpl *element() const { return m_poly; }
+
+ protected:
+ SVGPolyElementImpl *m_poly;
+
+ };
+ class LibartPolyline : public LibartPoly
+ {
+ public:
+ LibartPolyline(LibartCanvas *c, SVGPolylineElementImpl *poly);
+ virtual ~LibartPolyline();
+
+ virtual void init(const SVGMatrixImpl *screenCTM);
+ };
+
+ class LibartPolygon : public LibartPoly
+ {
+ public:
+ LibartPolygon(LibartCanvas *c, SVGPolygonElementImpl *poly);
+ virtual ~LibartPolygon();
+
+ virtual void init(const SVGMatrixImpl *screenCTM);
+ };
+
+ class LibartPath : public LibartShape, public MarkerHelper, public T2P::BezierPathLibart, public ::SVGPathParser
+ {
+ public:
+ LibartPath(LibartCanvas *c, SVGPathElementImpl *path);
+ virtual ~LibartPath();
+
+ virtual void draw();
+ virtual bool isVisible();
+ virtual void reset();
+ virtual void init();
+ virtual void init(const SVGMatrixImpl *screenCTM);
+
+ virtual SVGElementImpl *element() const { return m_path; }
+
+ protected:
+ friend class LibartCanvas;
+ SVGPathElementImpl *m_path;
+
+ virtual void svgMoveTo(double x1, double y1, bool closed, bool abs = true);
+ virtual void svgLineTo(double x1, double y1, bool abs = true);
+ virtual void svgCurveToCubic(double x1, double y1, double x2, double y2, double x, double y, bool abs = true);
+ virtual void svgClosePath();
+ };
+
+ class LibartClipPath : public CanvasClipPath
+ {
+ public:
+ LibartClipPath(LibartCanvas *c, SVGClipPathElementImpl *clipPath);
+ virtual ~LibartClipPath();
+
+ virtual QRect bbox() const { return QRect(); }
+ virtual bool fillContains(const QPoint &) { return true; }
+ virtual bool strokeContains(const QPoint &) { return true; }
+ virtual void update(CanvasItemUpdate, int param1 = 0, int param2 = 0);
+ virtual void init();
+ virtual void draw();
+ virtual bool isVisible() { return false; }
+
+ _ArtSVP *clipSVP();
+
+ protected:
+ LibartCanvas *m_canvas;
+ _ArtSVP *m_clipSVP;
+
+ QPtrList<CanvasItem> m_clipItems;
+ };
+
+ class LibartImage : public CanvasItem
+ {
+ public:
+ LibartImage(LibartCanvas *c, SVGImageElementImpl *image);
+ virtual ~LibartImage();
+
+ virtual QRect bbox() const;
+ virtual bool fillContains(const QPoint &) { return true; }
+ virtual bool strokeContains(const QPoint &) { return true; }
+ virtual void update(CanvasItemUpdate, int = 0, int = 0) { }
+ virtual void init();
+ virtual void draw();
+ virtual bool isVisible();
+
+ // We can't include SVGImageElementImpl.h here
+ // because of compiliation errors (X11 headers!)
+ virtual SVGElementImpl *element() const { return reinterpret_cast<SVGElementImpl *>(m_image); }
+
+ protected:
+ LibartCanvas *m_canvas;
+ SVGImageElementImpl *m_image;
+ };
+
+ class LibartMarker : public CanvasMarker
+ {
+ public:
+ LibartMarker(LibartCanvas *c, SVGMarkerElementImpl *marker);
+ virtual ~LibartMarker();
+
+ virtual QRect bbox() const { return QRect(); }
+ virtual bool fillContains(const QPoint &) { return true; }
+ virtual bool strokeContains(const QPoint &) { return true; }
+ virtual void update(CanvasItemUpdate, int = 0, int = 0) { }
+ virtual void init();
+ virtual void draw();
+ virtual bool isVisible() { return false; }
+
+ protected:
+ LibartCanvas *m_canvas;
+ };
+
+ class LibartText : public CanvasText, public LibartClipItem
+ {
+ public:
+ LibartText(LibartCanvas *c, SVGTextElementImpl *text);
+ virtual ~LibartText();
+
+ virtual QRect bbox() const;
+ virtual bool fillContains(const QPoint &p);
+ virtual bool strokeContains(const QPoint &p);
+ virtual void update(CanvasItemUpdate reason, int param1 = 0, int param2 = 0);
+ virtual void draw();
+ virtual bool isVisible();
+ virtual void init();
+ virtual void init(const SVGMatrixImpl *screenCTM);
+
+ virtual void renderCallback(SVGTextContentElementImpl *element, const SVGMatrixImpl *screenCTM, T2P::GlyphSet *glyph, T2P::GlyphLayoutParams *params, double anchor) const;
+ virtual void addTextDecoration(SVGTextContentElementImpl *element, double x, double y, double w, double h) const;
+
+ void initClipItem();
+ ArtSVP *clipSVP();
+
+ protected:
+ LibartCanvas *m_canvas;
+
+ private:
+ void clearSVPs();
+
+ class SVPElement
+ {
+ public:
+ SVPElement() { svp = 0; element = 0; }
+ ~SVPElement();
+
+ _ArtSVP *svp;
+ SVGTextContentElementImpl *element;
+ };
+
+ // renderCallback() is const.
+ mutable QPtrList<SVPElement> m_drawFillItems;
+ mutable QPtrList<SVPElement> m_drawStrokeItems;
+ mutable QPtrDict<LibartFillPainter> m_fillPainters;
+ mutable QPtrDict<LibartStrokePainter> m_strokePainters;
+ };
+}
+
+#endif
+
diff --git a/ksvg/plugin/backends/libart/Makefile.am b/ksvg/plugin/backends/libart/Makefile.am
new file mode 100644
index 00000000..b3f4ea5b
--- /dev/null
+++ b/ksvg/plugin/backends/libart/Makefile.am
@@ -0,0 +1,11 @@
+kde_module_LTLIBRARIES = libksvgrendererlibart.la
+
+libksvgrendererlibart_la_SOURCES = BezierPathLibart.cpp GlyphTracerLibart.cpp LibartCanvas.cpp LibartCanvasItems.cpp LibartCanvasFactory.cpp
+libksvgrendererlibart_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+libksvgrendererlibart_la_LIBADD = ../../../libksvg.la
+libksvgrendererlibart_la_METASOURCES = AUTO
+
+kde_services_DATA = ksvglibartcanvas.desktop
+
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+INCLUDES = $(LIBART_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) -I$(top_srcdir)/ksvg/dom -I$(top_srcdir)/ksvg/impl -I$(top_srcdir)/ksvg/ecma -I$(top_srcdir)/ksvg/core -I$(top_srcdir)/ksvg/impl/libs/art_support -I$(top_srcdir)/ksvg/impl/libs/libtext2path/src $(KDE_INCLUDES) $(all_includes)
diff --git a/ksvg/plugin/backends/libart/ksvglibartcanvas.desktop b/ksvg/plugin/backends/libart/ksvglibartcanvas.desktop
new file mode 100644
index 00000000..af6f3a6c
--- /dev/null
+++ b/ksvg/plugin/backends/libart/ksvglibartcanvas.desktop
@@ -0,0 +1,101 @@
+[Desktop Entry]
+Type=Service
+ServiceTypes=KSVG/Renderer
+X-KDE-Library=libksvgrendererlibart
+X-KSVG-InternalName=libart
+Name=KSVG Rendering Backend - Libart
+Name[ar]=خلفية الرسم ل KSVG - Libart
+Name[bs]=KSVG renderiranje - Libart
+Name[ca]=Representació en segon pla de KSVG - Biblioteca d'imatges
+Name[cs]=Vykreslovací nástroj KSVG - Libart
+Name[cy]=Ôl-wyneb Llunio KSVG - Libart
+Name[da]=Underliggende program til KSVG-visning - Libart
+Name[de]=KSVG-Darstellungsmodul - Libart
+Name[el]=Σύστημα υποστήριξης αποτύπωσης του KSVG - Libart
+Name[es]=Motor de procesado de KSVG - Libart
+Name[et]=KSVG renderdamise taustarakendus - Libart
+Name[eu]=KSVG errendatze programa - Libart
+Name[fa]=پایانۀ پشتیبانی پرداخت KSVG - Libart
+Name[fi]=KSVG-piirtäjän taustaohjelma - Libart
+Name[fr]=Moteur de rendu KSVG - Libart
+Name[ga]=Inneall Rindreála KSVG - Libart
+Name[gl]=Mecanismo de Interpretación KSVG - Libart
+Name[hi]=के-एसवीजी रेंडरिंग बैकएण्ड- लिबआर्ट
+Name[hu]=KSVG megjelenítőmotor - Libart
+Name[is]=KSVG teiknari - Libart
+Name[it]=Backend di KSVG per il rendering - Libart
+Name[ja]=KSVG レンダリングバックエンド - Libart
+Name[kk]=KSVG кескіндеу бағдарламасы - Libart
+Name[km]=កម្មវិធី​សម្រាប់​បង្ហាញ KSVG - Libart
+Name[lt]=KSVG atkūrimo programinė sąsaja - Libart
+Name[ms]=Tepi Belakang Menrealisasi KSVG - Libart
+Name[nb]=Modul for KSVG-tegning – Libart
+Name[nds]=KSVG-Dorstellhölper - Libart
+Name[ne]=KSVG रेन्डरिङ ब्याकइन्ड - लिबर्ट
+Name[nl]=KSVG weergavecomponent - Libart
+Name[nn]=Modul for KSVG-teikning – Libart
+Name[pl]=Narzędzie do renderowania KSVG - Libart
+Name[pt]=Infra-Estrutura de Desenho do KSVG - Libart
+Name[pt_BR]=Estrutura de KSVG Rendering Backend - Libart
+Name[ro]=Motor de randare KSVG - Libart
+Name[ru]=Движок отрисовки KSVG - Libart
+Name[sk]=Nástroj pre zobrazovanie KSVG - libart
+Name[sl]=Izrisovalnik KSVG - Libart
+Name[sr]=KSVG-ов позадински систем за рендеровање — Libart
+Name[sr@Latn]=KSVG-ov pozadinski sistem za renderovanje — Libart
+Name[sv]=KSVG-uppritningsmodul - konstbibliotek
+Name[ta]=KSVG வழங்கும் பின் அமைப்பு - லிபார்ட்
+Name[tg]=Лағжандаи тасовироти KSVG - Libart
+Name[tr]=KSVG Derleme Aracı - Libart
+Name[uk]=Інтерфейс відтворення KSVG - Libart
+Name[zh_CN]=KSVG 渲染后端 - Libart
+Name[zh_HK]=KSVG 合成後端 - Libart
+Name[zh_TW]=KSVG 上色後端介面 - Libart
+Comment=Mature ksvg rendering backend
+Comment[ar]=خلفية الرسم لksvg البالغة
+Comment[bs]=Zreli ksvg rendering backend
+Comment[ca]=Representador madur en segon pla de ksvg
+Comment[cs]=Vyspělý vykreslovací nástroj KSVG
+Comment[cy]=Ôl-wyneb llunio ksvg aeddfed
+Comment[da]=Modent underliggende program til ksvg-visning
+Comment[de]=Ausgereiftes KSVG-Darstellungsmodul
+Comment[el]=Ώριμο σύστημα υποστήριξης αποτύπωσης του KSVG
+Comment[es]=Motor de procesado de ksvg tradicional
+Comment[et]=Kasutamisküps ksvg renderdamise taustarakendus
+Comment[eu]=ksvg errendatze programa egonkorra
+Comment[fa]=پایانۀ پشتیبانی کامل پرداخت ksvg
+Comment[fi]=Kypsä ksvg-piirtäjän taustaohjelma
+Comment[fr]=Moteur de rendu KSVG mature
+Comment[gl]=Mecanismo de interpretación maduro ksvg
+Comment[hi]=परिपक्व के-एसवीजी रेंडरिंग बैकएण्ड
+Comment[hu]=Egy kiforrott megjelenítőmotor a KSVG-hez
+Comment[is]=Reyndur ksvg teiknari
+Comment[it]=Maturo backend di KSVG per il rendering
+Comment[ja]=成熟した ksvg レンダリングバックエンド
+Comment[kk]=Баяғы, жетілірдірген, KSVG кескіндеу бағдарламасы
+Comment[km]=កម្មវិធី​សម្រាប់​បង្ហាញ ksvg ចាស់ៗ
+Comment[lt]=Išvystyta ksvg atkūrimo programinė sąsaja
+Comment[ms]=Tepi belakang menrealisasi ksvg matang
+Comment[nb]=Velutviklet modul for ksvg-tegning
+Comment[nds]=Reep KSVG-Dorstellhölper
+Comment[ne]=पूर्ण विकसित ksvg रेन्डरिङ ब्याकइन्ड
+Comment[nl]=Volgroeide KSVG weergavecomponent
+Comment[nn]=Velutvikla modul for ksvg-teikning
+Comment[pl]=Dopracowane narzędzie do renderowania KSVG
+Comment[pt]=Uma infra-estrutura de desenho do ksvg mais madura
+Comment[pt_BR]=Estrutura de renderização madura do ksvg
+Comment[ro]=Motor de randare KSVG matur
+Comment[ru]=Старый движок отрисовки ksvg
+Comment[sk]=Stabilný nástroj pre zobrazovanie ksvg
+Comment[sl]=Zrel izrisovalnik KSVG
+Comment[sr]=Стари KSVG-ов позадински систем за рендеровање
+Comment[sr@Latn]=Stari KSVG-ov pozadinski sistem za renderovanje
+Comment[sv]=Mogen KSVG-uppritningsmodul
+Comment[ta]=முழுமையான ksvg வழங்கும் பின் அமைப்பு
+Comment[tg]=Лағжандаи тасовироти кӯҳнаи ksvg
+Comment[tr]=Tamamlanmış ksvg derleme aracı
+Comment[uk]=Стабільний інтерфейс відтворення KSVG
+Comment[zh_CN]=稳定的 ksvg 渲染后端
+Comment[zh_HK]=成熟的 ksvg 合成後端
+Comment[zh_TW]=成熟的 ksvg 上色後端介面
+author=Nikolas Zimmermann <wildfox@kde.org>
diff --git a/ksvg/plugin/ksvg_factory.cpp b/ksvg/plugin/ksvg_factory.cpp
new file mode 100644
index 00000000..b231783c
--- /dev/null
+++ b/ksvg/plugin/ksvg_factory.cpp
@@ -0,0 +1,100 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kaboutdata.h>
+#include <kinstance.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+
+#include "ksvg_plugin.h"
+#include "ksvg_factory.moc"
+
+#include <kdebug.h>
+#include <qstringlist.h>
+#include <qregexp.h>
+
+extern "C"
+{
+ void *init_libksvgplugin()
+ {
+ KGlobal::locale()->insertCatalogue("ksvgplugin");
+ return new KSVGPluginFactory();
+ }
+}
+
+KInstance *KSVGPluginFactory::s_instance = 0;
+KAboutData *KSVGPluginFactory::s_about = 0;
+
+KSVGPluginFactory::KSVGPluginFactory(QObject *parent, const char *name) : KParts::Factory(parent, name)
+{
+}
+
+KSVGPluginFactory::~KSVGPluginFactory()
+{
+ delete s_instance;
+ s_instance = 0;
+ delete s_about;
+
+ s_about = 0;
+}
+
+KParts::Part *KSVGPluginFactory::createPartObject(QWidget *parentWidget, const char *wname, QObject *parent, const char *name, const char *, const QStringList &args)
+{
+ // Get the width and height of the <embed>
+ // TODO : <object>
+ unsigned int width = 0, height = 0;
+ bool dummy;
+ QRegExp r1("(WIDTH)(\\s*=\\s*\")(\\d+)(\\w*)(\")");
+ QRegExp r2("(HEIGHT)(\\s*=\\s*\")(\\d+)(\\w*)(\")");
+ for(QValueListConstIterator<QString> it = args.begin(); it != args.end(); ++it)
+ {
+ if(r1.search(*it) > -1)
+ width = r1.cap(3).toUInt(&dummy);
+ if(r2.search(*it) > -1)
+ height = r2.cap(3).toUInt(&dummy);
+ }
+
+ return new KSVGPlugin(parentWidget, wname, parent, name, width, height);
+}
+
+KInstance *KSVGPluginFactory::instance()
+{
+ if(!s_instance)
+ {
+ s_about = new KAboutData("ksvg", I18N_NOOP("KSVG"), "0.1", "KSVG\nFreedom for veKtors",KAboutData::License_GPL_V2,"(c) 2001-2003, The KSVG Team",0,"http://svg.kde.org");
+ s_about->addAuthor("Rob Buis", 0, "buis@kde.org");
+ s_about->addAuthor("Nikolas Zimmermann", 0, "wildfox@kde.org");
+ s_about->addCredit("Adrian Page", 0);
+ s_about->addCredit("Andreas Streichardt", 0, "mop@spaceregents.de");
+ s_instance = new KInstance(s_about);
+ }
+
+ return s_instance;
+}
+
+KSVGPluginBrowserExtension::KSVGPluginBrowserExtension(KSVGPlugin *parent)
+: KParts::BrowserExtension(parent, "KSVGPlugin BrowserExtension")
+{
+}
+
+KSVGPluginBrowserExtension::~KSVGPluginBrowserExtension()
+{
+}
diff --git a/ksvg/plugin/ksvg_factory.h b/ksvg/plugin/ksvg_factory.h
new file mode 100644
index 00000000..b462c782
--- /dev/null
+++ b/ksvg/plugin/ksvg_factory.h
@@ -0,0 +1,58 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSVGFactory_H
+#define KSVGFactory_H
+
+#include <kparts/factory.h>
+#include <kparts/browserextension.h>
+
+class KAboutData;
+class KInstance;
+
+class KSVGPluginFactory : public KParts::Factory
+{
+Q_OBJECT
+public:
+ KSVGPluginFactory(QObject *parent = 0, const char *name = 0);
+ virtual ~KSVGPluginFactory();
+
+ virtual KParts::Part *createPartObject(QWidget *parentWidget = 0, const char *widgetName = 0, QObject *parent = 0, const char *name = 0, const char *classname = "KParts::Part", const QStringList &args = QStringList());
+
+ static KInstance *instance();
+
+private:
+ static KInstance *s_instance;
+ static KAboutData *s_about;
+};
+
+class KSVGPluginBrowserExtension : public KParts::BrowserExtension
+{
+Q_OBJECT
+friend class KSVGPlugin;
+
+public:
+ KSVGPluginBrowserExtension(KSVGPlugin *parent);
+ virtual ~KSVGPluginBrowserExtension();
+};
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/ksvg_plugin.cpp b/ksvg/plugin/ksvg_plugin.cpp
new file mode 100644
index 00000000..37e0a0dd
--- /dev/null
+++ b/ksvg/plugin/ksvg_plugin.cpp
@@ -0,0 +1,417 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <krun.h>
+#include <kdebug.h>
+#include <kaction.h>
+#include <kfiledialog.h>
+#include <klocale.h>
+#include <ktempfile.h>
+#include <ksimpleconfig.h>
+#include <kaboutapplication.h>
+
+#include "ksvg_widget.h"
+#include "ksvg_factory.h"
+#include "ksvg_plugin.moc"
+
+#include "KSVGCanvas.h"
+#include "KSVGLoader.h"
+#include "CanvasFactory.h"
+#include "DocumentFactory.h"
+
+#include "SVGDocument.h"
+#include "SVGWindowImpl.h"
+#include "SVGZoomAndPan.h"
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+
+#include <qimage.h>
+
+using namespace KSVG;
+
+#define DEFAULT_WIDTH 400
+#define DEFAULT_HEIGHT 400
+#define ZOOM_FACTOR 1.2
+
+struct KSVGPlugin::Private
+{
+ KSVGWidget *window;
+ KSVGPluginBrowserExtension *extension;
+
+ KAction *zoomInAction;
+ KAction *zoomOutAction;
+ KAction *zoomResetAction;
+ KAction *stopAnimationsAction;
+ KAction *viewSourceAction;
+ KAction *viewMemoryAction;
+ KAction *aboutApp;
+ KAction *saveToPNG;
+ KToggleAction *fontKerningAction;
+ KToggleAction *progressiveAction;
+ KSelectAction *renderingBackendAction;
+
+ QString description;
+
+ QPoint panPoint;
+ float zoomFactor;
+
+ SVGDocumentImpl *doc;
+ KSVGCanvas *canvas;
+ QPixmap *backgroundPixmap;
+ KAboutApplication *aboutKSVG;
+
+ unsigned int width;
+ unsigned int height;
+};
+
+KSVGPlugin::KSVGPlugin(QWidget *wparent, const char *, QObject *parent, const char *name, unsigned int width, unsigned int height) : KParts::ReadOnlyPart(parent, name)
+{
+ kdDebug(26003) << "KSVGPlugin::KSVGPlugin" << endl;
+ setInstance(KSVGPluginFactory::instance());
+
+ ksvgd = new KSVGPlugin::Private();
+
+ ksvgd->width = width;
+ ksvgd->height = height;
+
+ ksvgd->zoomFactor = 1.0;
+
+ ksvgd->doc = 0;
+
+ ksvgd->window = new KSVGWidget(this, wparent, "Rendering Widget");
+ connect(ksvgd->window, SIGNAL(browseURL(const QString &)), this, SLOT(browseURL(const QString &)));
+ ksvgd->window->show();
+
+ KParts::Part::setWidget(ksvgd->window);
+
+ ksvgd->extension = new KSVGPluginBrowserExtension(this);
+
+ ksvgd->backgroundPixmap = new QPixmap(width > 0 ? width : DEFAULT_WIDTH, height > 0 ? height : DEFAULT_HEIGHT);
+ ksvgd->backgroundPixmap->fill();
+
+ ksvgd->canvas = KSVG::CanvasFactory::self()->loadCanvas(width > 0 ? width : DEFAULT_WIDTH, height > 0 ? height : DEFAULT_HEIGHT);
+ if(!ksvgd->canvas)
+ return;
+
+ ksvgd->canvas->setup(ksvgd->backgroundPixmap, ksvgd->window);
+
+ ksvgd->zoomInAction = KStdAction::zoomIn(this, SLOT(slotZoomIn()), actionCollection());
+ ksvgd->zoomOutAction = KStdAction::zoomOut(this, SLOT(slotZoomOut()), actionCollection());
+ ksvgd->zoomResetAction = new KAction(i18n("Zoom &Reset"), "viewmag", this, SLOT(slotZoomReset()), actionCollection(), "zoom_reset");
+ ksvgd->stopAnimationsAction = new KAction(i18n("&Stop Animations"), "stop", Key_Escape, this, SLOT(slotStop()), actionCollection(), "stop_anims");
+ ksvgd->viewSourceAction = new KAction(i18n("View &Source"), "document2", Key_F6, this, SLOT(slotViewSource()), actionCollection(), "view_source");
+ ksvgd->viewMemoryAction = new KAction(i18n("View &Memory"), "document2", Key_F7, this, SLOT(slotViewMemory()), actionCollection(), "view_memory");
+ ksvgd->saveToPNG = new KAction(i18n("Save to PNG..."), "save", 0, this, SLOT(slotSaveToPNG()), actionCollection(), "save_to_png");
+// ksvgd->aboutApp = KStdAction::aboutApp(this, SLOT(slotAboutKSVG()), actionCollection());//, "KSVG");
+ ksvgd->aboutApp = new KAction(i18n("About KSVG"), "vectorgfx", 0, this, SLOT(slotAboutKSVG()), actionCollection(), "help_about_app");
+ ksvgd->fontKerningAction = new KToggleAction(i18n("Use Font &Kerning"), "viewmagfit", Key_F8, this, SLOT(slotFontKerning()), actionCollection(), "font_kerning");
+ ksvgd->progressiveAction = new KToggleAction(i18n("Use &Progressive Rendering"), "", Key_F9, this, SLOT(slotProgressiveRendering()), actionCollection(), "progressive");
+
+ KSimpleConfig config("ksvgpluginrc", true);
+ config.setGroup("Rendering");
+ ksvgd->fontKerningAction->setChecked(config.readBoolEntry("FontKerning", true));
+ ksvgd->progressiveAction->setChecked(config.readBoolEntry("ProgressiveRendering", true));
+
+ ksvgd->renderingBackendAction = new KSelectAction(i18n("Rendering &Backend"), 0, this, SLOT(slotRenderingBackend()), actionCollection(), "rendering_backend");
+
+ QStringList items;
+ QPtrList<KSVG::CanvasInfo> canvasList = KSVG::CanvasFactory::self()->canvasList();
+ QPtrListIterator<KSVG::CanvasInfo> it(canvasList);
+ KSVG::CanvasInfo *canvasInfo = 0;
+ while((canvasInfo = it.current()) != 0)
+ {
+ items << canvasInfo->name;
+ ++it;
+ }
+
+ ksvgd->renderingBackendAction->setItems(items);
+ ksvgd->renderingBackendAction->setCurrentItem(KSVG::CanvasFactory::self()->itemInList(ksvgd->canvas));
+
+ ksvgd->aboutKSVG = new KAboutApplication(KSVGPluginFactory::instance()->aboutData(), wparent);
+
+ setXMLFile("ksvgplugin.rc");
+}
+
+KSVGPlugin::~KSVGPlugin()
+{
+ kdDebug(26003) << "KSVGPlugin::~KSVGPlugin" << endl;
+
+ if(ksvgd->doc && ksvgd->doc->rootElement())
+ ksvgd->doc->rootElement()->pauseAnimations();
+
+ KSVG::CanvasFactory::self()->cleanup();
+ delete ksvgd->extension;
+
+ if(ksvgd->doc)
+ ksvgd->doc->detach();
+
+ delete ksvgd->canvas;
+ delete ksvgd->backgroundPixmap;
+ delete ksvgd;
+}
+
+SVGDocumentImpl *KSVGPlugin::docImpl()
+{
+ return ksvgd->doc;
+}
+
+SVGDocument KSVGPlugin::document()
+{
+ return SVGDocument(ksvgd->doc);
+}
+
+void KSVGPlugin::reset()
+{
+ if(ksvgd->canvas)
+ ksvgd->canvas->reset();
+
+ ksvgd->zoomFactor = 1;
+ ksvgd->window->reset();
+ ksvgd->panPoint = QPoint(0, 0);
+}
+
+bool KSVGPlugin::openURL(const KURL &url)
+{
+ m_url = url;
+
+ if(!url.prettyURL().isEmpty())
+ {
+ reset();
+
+ DocumentFactory *docFactory = DocumentFactory::self();
+
+ // when embedded, stick to passed width and height
+ ksvgd->doc = docFactory->requestDocumentImpl((ksvgd->width > 0 && ksvgd->height > 0));
+
+ ksvgd->doc->attach(ksvgd->canvas);
+ ksvgd->doc->addToDocumentDict(ksvgd->doc->handle(), ksvgd->doc);
+ ksvgd->doc->setReferrer(ksvgd->extension->urlArgs().metaData()["referrer"]);
+
+ connect(ksvgd->doc, SIGNAL(finishedParsing(bool, const QString &)), this, SLOT(slotParsingFinished(bool, const QString &)));
+ connect(ksvgd->doc, SIGNAL(finishedRendering()), this, SLOT(slotRenderingFinished()));
+ connect(ksvgd->doc, SIGNAL(gotDescription(const QString &)), this, SLOT(slotSetDescription(const QString &)));
+ connect(ksvgd->doc, SIGNAL(gotTitle(const QString &)), this, SLOT(slotSetTitle(const QString &)));
+ connect(ksvgd->doc, SIGNAL(gotURL(const QString &)), this, SLOT(slotGotURL(const QString &)));
+ connect(ksvgd->window, SIGNAL(redraw(const QRect &)), this, SLOT(slotRedraw(const QRect &)));
+
+ ksvgd->backgroundPixmap->fill();
+ bitBlt(ksvgd->window, 0, 0, ksvgd->backgroundPixmap, 0, 0, ksvgd->backgroundPixmap->width(), ksvgd->backgroundPixmap->height());
+ ksvgd->zoomFactor = 1;
+
+ emit started(0);
+ ksvgd->doc->open(url);
+ emit completed();
+ }
+ else
+ return false;
+
+ return true;
+}
+
+void KSVGPlugin::browseURL(const QString &url)
+{
+ ksvgd->doc->rootElement()->pauseAnimations();
+ KParts::URLArgs args;
+ args.frameName = "_self";
+ emit ksvgd->extension->openURLRequest(KURL(m_url, url), args);
+}
+
+void KSVGPlugin::slotRedraw(const QRect &r)
+{
+ if(ksvgd->window->width() != ksvgd->backgroundPixmap->width() ||
+ ksvgd->window->height() != ksvgd->backgroundPixmap->height())
+ {
+ ksvgd->backgroundPixmap->resize(ksvgd->window->width(), ksvgd->window->height());
+
+ if(ksvgd->doc && ksvgd->doc->canvas())
+ {
+ ksvgd->doc->canvas()->resize(ksvgd->window->width(), ksvgd->window->height());
+ ksvgd->doc->canvas()->blit();
+ }
+ }
+
+ bitBlt(ksvgd->window, r.x(), r.y(), ksvgd->backgroundPixmap, r.x(), r.y(), r.width(), r.height());
+}
+
+void KSVGPlugin::slotViewSource()
+{
+ KTempFile temp;
+ *temp.textStream() << KSVGLoader::getUrl(m_url, true) << endl;
+ KRun::runURL(KURL(temp.name()), "text/plain", true);
+}
+
+void KSVGPlugin::slotViewMemory()
+{
+ KTempFile temp;
+ *temp.textStream() << ksvgd->doc->window()->printNode(*ksvgd->doc).string() << endl;
+ KRun::runURL(KURL(temp.name()), "text/plain", true);
+}
+
+void KSVGPlugin::slotFontKerning()
+{
+ KSimpleConfig config("ksvgpluginrc", false);
+ config.setGroup("Rendering");
+ config.writeEntry("FontKerning", ksvgd->fontKerningAction->isChecked());
+
+ if(ksvgd->doc)
+ {
+ SVGSVGElementImpl *root = ksvgd->doc->rootElement();
+ if(!root)
+ return;
+
+ ksvgd->doc->canvas()->fontContext()->setKerning(ksvgd->fontKerningAction->isChecked());
+ update();
+ }
+}
+
+void KSVGPlugin::slotProgressiveRendering()
+{
+ KSimpleConfig config("ksvgpluginrc", false);
+ config.setGroup("Rendering");
+ config.writeEntry("ProgressiveRendering", ksvgd->progressiveAction->isChecked());
+}
+
+void KSVGPlugin::slotRenderingBackend()
+{
+ KSimpleConfig config("ksvgpluginrc", false);
+ config.setGroup("Canvas");
+ config.writeEntry("ActiveCanvas", KSVG::CanvasFactory::self()->internalNameFor(ksvgd->renderingBackendAction->currentText()));
+ config.sync();
+ KSVG::CanvasFactory::self()->deleteCanvas(ksvgd->canvas);
+ ksvgd->canvas = KSVG::CanvasFactory::self()->loadCanvas(ksvgd->width > 0 ? ksvgd->width : DEFAULT_WIDTH, ksvgd->height > 0 ? ksvgd->height : DEFAULT_HEIGHT);
+ if(!ksvgd->canvas)
+ return;
+
+ ksvgd->canvas->setup(ksvgd->backgroundPixmap, ksvgd->window);
+ openURL(m_url);
+}
+
+void KSVGPlugin::slotAboutKSVG()
+{
+ ksvgd->aboutKSVG->show();
+}
+
+void KSVGPlugin::slotStop()
+{
+ if(ksvgd->doc->rootElement()->animationsPaused())
+ ksvgd->doc->rootElement()->unpauseAnimations();
+ else
+ ksvgd->doc->rootElement()->pauseAnimations();
+}
+
+void KSVGPlugin::slotParsingFinished(bool error, const QString &errorDesc)
+{
+ emit completed();
+
+ if(error)
+ {
+ kdDebug(26003) << "Finished with error : " << errorDesc << endl;
+ emit setStatusBarText(errorDesc);
+ }
+ else
+ kdDebug(26003) << "Finished without errors!" << endl;
+}
+
+void KSVGPlugin::slotRenderingFinished()
+{
+ bitBlt(ksvgd->window, 0, 0, ksvgd->backgroundPixmap, 0, 0, ksvgd->canvas->width(), ksvgd->canvas->height());
+}
+
+void KSVGPlugin::slotZoomIn()
+{
+ ksvgd->zoomFactor *= ZOOM_FACTOR;
+ update();
+}
+
+void KSVGPlugin::slotZoomOut()
+{
+ ksvgd->zoomFactor *= (1.0 / ZOOM_FACTOR);
+ update();
+}
+
+void KSVGPlugin::slotZoomReset()
+{
+ ksvgd->zoomFactor = 1.0;
+ update();
+}
+
+void KSVGPlugin::slotSaveToPNG()
+{
+ if(ksvgd && ksvgd->backgroundPixmap)
+ {
+ QImage img = ksvgd->backgroundPixmap->convertToImage();
+ QString filename = KFileDialog::getSaveFileName();
+ if(!filename.isEmpty())
+ img.save(filename, "PNG");
+ }
+}
+
+void KSVGPlugin::setPanPoint(const QPoint &translate)
+{
+ ksvgd->panPoint = translate;
+ update();
+}
+
+void KSVGPlugin::update()
+{
+ if(ksvgd->doc)
+ {
+ SVGSVGElementImpl *root = ksvgd->doc->rootElement();
+ if(!root || root->zoomAndPan() != SVG_ZOOMANDPAN_MAGNIFY)
+ return;
+
+ ksvgd->backgroundPixmap->fill();
+
+ bool zoomChanged = ksvgd->zoomFactor != root->currentScale();
+ root->setCurrentScale(ksvgd->zoomFactor);
+ root->setCurrentTranslate(ksvgd->panPoint);
+
+ ksvgd->doc->syncCachedMatrices();
+
+ if(zoomChanged)
+ ksvgd->doc->canvas()->update(ksvgd->zoomFactor);
+ else
+ ksvgd->doc->canvas()->update(ksvgd->panPoint);
+
+ // Fixes drawing glitches
+ slotRedraw(QRect(0, 0, ksvgd->backgroundPixmap->width(), ksvgd->backgroundPixmap->height()));
+ }
+}
+
+void KSVGPlugin::slotSetDescription(const QString &desc)
+{
+ ksvgd->description = desc;
+ emit setStatusBarText(i18n("Description: %1").arg(desc));
+}
+
+void KSVGPlugin::slotSetTitle(const QString &title)
+{
+ emit setWindowCaption(title);
+}
+
+void KSVGPlugin::slotGotURL(const QString &text)
+{
+ if(text.isNull() && !ksvgd->description.isEmpty())
+ emit setStatusBarText(i18n("Description: %1").arg(ksvgd->description));
+ else
+ emit setStatusBarText(text);
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/ksvg_plugin.h b/ksvg/plugin/ksvg_plugin.h
new file mode 100644
index 00000000..87286be9
--- /dev/null
+++ b/ksvg/plugin/ksvg_plugin.h
@@ -0,0 +1,87 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSVGPlugin_H
+#define KSVGPlugin_H
+
+#include <qobject.h>
+#include <kparts/part.h>
+
+namespace KSVG
+{
+ class SVGDocument;
+ class SVGDocumentImpl;
+ class SVGDescElementImpl;
+ class SVGTitleElementImpl;
+}
+
+class KSVGPlugin : public KParts::ReadOnlyPart
+{
+Q_OBJECT
+public:
+ KSVGPlugin(QWidget *parentWidget, const char *wname, QObject *parent, const char *name, unsigned int width = 0, unsigned int height = 0);
+ virtual ~KSVGPlugin();
+
+ virtual bool openFile() { return false; }
+ virtual bool openURL(const KURL &url);
+
+ KSVG::SVGDocument document();
+ KSVG::SVGDocumentImpl *docImpl();
+
+ void reset();
+ void setPanPoint(const QPoint &translate);
+ void update();
+ void setPopupActive(bool);
+
+signals:
+ void gotHyperlink(const QString &);
+ void gotHyperlinkCoordinate(const QRect &);
+
+public slots:
+ void slotRedraw(const QRect &);
+
+private slots:
+ void browseURL(const QString &url);
+ void slotStop();
+ void slotViewSource();
+ void slotViewMemory();
+ void slotFontKerning();
+ void slotProgressiveRendering();
+ void slotRenderingBackend();
+ void slotZoomIn();
+ void slotZoomOut();
+ void slotZoomReset();
+ void slotAboutKSVG();
+ void slotSaveToPNG();
+
+ void slotParsingFinished(bool error, const QString &errorDesc);
+ void slotRenderingFinished();
+ void slotSetDescription(const QString &);
+ void slotSetTitle(const QString &);
+ void slotGotURL(const QString &);
+
+private:
+ class Private;
+ Private *ksvgd;
+};
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/ksvg_widget.cpp b/ksvg/plugin/ksvg_widget.cpp
new file mode 100644
index 00000000..073e60a5
--- /dev/null
+++ b/ksvg/plugin/ksvg_widget.cpp
@@ -0,0 +1,267 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <kcursor.h>
+#include <kpopupmenu.h>
+#include <kxmlguifactory.h>
+#include "ksvg_widget.moc"
+
+#include "ksvg_plugin.h"
+#include "SVGDocumentImpl.h"
+#include "SVGSVGElementImpl.h"
+
+KSVGWidget::KSVGWidget(KSVGPlugin *part, QWidget *parent, const char *name)
+: QWidget(parent, name), m_part(part)
+{
+ setMouseTracking(true);
+ setFocusPolicy(WheelFocus);
+
+ setBackgroundMode(NoBackground);
+
+ reset();
+}
+
+KSVGWidget::~KSVGWidget()
+{
+}
+
+KSVGPlugin *KSVGWidget::part() const
+{
+ return m_part;
+}
+
+void KSVGWidget::reset()
+{
+ m_oldPanningPos.setX(0);
+ m_oldPanningPos.setY(0);
+ m_panningPos.setX(0);
+ m_panningPos.setY(0);
+}
+
+void KSVGWidget::paintEvent(QPaintEvent *e)
+{
+ emit redraw(e->rect());
+}
+
+KSVG::SVGMouseEventImpl *KSVGWidget::newMouseEvent(KSVG::SVGEvent::EventId id, QMouseEvent *event)
+{
+ DOM::AbstractView temp;
+
+ int clientX = event->x();
+ int clientY = event->y();
+
+ if(part()->docImpl() && part()->docImpl()->rootElement())
+ {
+ clientX = int(clientX / part()->docImpl()->rootElement()->currentScale());
+ clientY = int(clientY / part()->docImpl()->rootElement()->currentScale());
+ }
+
+ int button = 0;
+ if(event->stateAfter() & Qt::LeftButton)
+ button = 1;
+ else if(event->stateAfter() & Qt::MidButton)
+ button = 2;
+ else if(event->stateAfter() & Qt::RightButton)
+ button = 3;
+
+ KSVG::SVGMouseEventImpl *mev = new KSVG::SVGMouseEventImpl(id, // type
+ true, // canBubbleArg
+ true, // cancelableArg
+ temp, // view
+ 0, // detail
+ event->globalX(), //screenXArg
+ event->globalY(), // screenYArg,
+ clientX, // clientXArg
+ clientY, // clientYArg
+ (event->state() & Qt::ControlButton), // ctrlKeyArg
+ (event->state() & Qt::AltButton), // altKeyArg
+ (event->state() & Qt::ShiftButton), // shiftKeyArg
+ (event->state() & Qt::MetaButton), // metaKeyArg
+ button, // buttonArg
+ 0);
+
+ mev->ref();
+
+ return mev;
+}
+
+void KSVGWidget::mouseMoveEvent(QMouseEvent *event)
+{
+ if(event->state() & QMouseEvent::ControlButton && event->state() & QMouseEvent::LeftButton)
+ {
+ if(m_panningPos.isNull())
+ m_panningPos = event->pos();
+ else
+ part()->setPanPoint(m_oldPanningPos - (m_panningPos - event->pos()));
+
+ return;
+ }
+ else if(event->state() & QMouseEvent::ControlButton)
+ return;
+
+ KSVG::SVGMouseEventImpl *mev = newMouseEvent(KSVG::SVGEvent::MOUSEMOVE_EVENT, event);
+
+ if(part()->docImpl() && part()->docImpl()->rootElement())
+ part()->docImpl()->rootElement()->prepareMouseEvent(event->pos(), event->pos(), mev);
+
+ if(mev->target() && mev->url().string().isEmpty())
+ {
+ KSVG::SVGElementImpl *target = const_cast<KSVG::SVGElementImpl *>(mev->target());
+ KSVG::SVGStylableImpl *style = dynamic_cast<KSVG::SVGStylableImpl *>(target);
+
+ if(!style)
+ {
+ setCursor(KCursor::arrowCursor());
+ return;
+ }
+
+ switch(style->getCursor())
+ {
+ case KSVG::CURSOR_CROSSHAIR:
+ setCursor(KCursor::crossCursor());
+ break;
+ case KSVG::CURSOR_POINTER:
+ setCursor(KCursor::handCursor());
+ break;
+ case KSVG::CURSOR_MOVE:
+ setCursor(KCursor::sizeAllCursor());
+ break;
+ case KSVG::CURSOR_E_RESIZE:
+ case KSVG::CURSOR_W_RESIZE:
+ setCursor(KCursor::sizeHorCursor());
+ break;
+ case KSVG::CURSOR_N_RESIZE:
+ case KSVG::CURSOR_S_RESIZE:
+ setCursor(KCursor::sizeVerCursor());
+ break;
+ case KSVG::CURSOR_NW_RESIZE:
+ case KSVG::CURSOR_SE_RESIZE:
+ setCursor(KCursor::sizeFDiagCursor());
+ break;
+ case KSVG::CURSOR_NE_RESIZE:
+ case KSVG::CURSOR_SW_RESIZE:
+ setCursor(KCursor::sizeBDiagCursor());
+ break;
+ case KSVG::CURSOR_TEXT:
+ setCursor(KCursor::ibeamCursor());
+ break;
+ case KSVG::CURSOR_WAIT:
+ setCursor(KCursor::waitCursor());
+ break;
+ case KSVG::CURSOR_HELP:
+ setCursor(KCursor::whatsThisCursor());
+ break;
+ default:
+ setCursor(KCursor::arrowCursor());
+ }
+ }
+ else if(mev->url().string().isEmpty())
+ setCursor(KCursor::arrowCursor());
+
+ if(!mev->url().string().isEmpty())
+ setCursor(KCursor::handCursor());
+
+ mev->deref();
+}
+
+void KSVGWidget::mousePressEvent(QMouseEvent *event)
+{
+ if(event->state() & QMouseEvent::ControlButton)
+ return;
+
+ if(event->button() == RightButton)
+ {
+ if(part() && part()->factory())
+ {
+ QPopupMenu *popup = static_cast<QPopupMenu *>(part()->factory()->container("popupmenu", part()));
+ if(popup)
+ popup->popup(event->globalPos());
+ }
+ }
+
+ KSVG::SVGMouseEventImpl *mev = newMouseEvent(KSVG::SVGEvent::MOUSEDOWN_EVENT, event);
+
+ if(part()->docImpl() && part()->docImpl()->rootElement())
+ part()->docImpl()->rootElement()->prepareMouseEvent(event->pos(), event->pos(), mev);
+
+ mev->deref();
+}
+
+void KSVGWidget::mouseReleaseEvent(QMouseEvent *event)
+{
+ if(!m_panningPos.isNull())
+ {
+ m_oldPanningPos = m_oldPanningPos - (m_panningPos - event->pos());
+ m_panningPos.setX(0);
+ m_panningPos.setY(0);
+ }
+
+ if(event->state() & QMouseEvent::ControlButton)
+ return;
+
+ KSVG::SVGMouseEventImpl *mev = newMouseEvent(KSVG::SVGEvent::MOUSEUP_EVENT, event);
+
+ if(part()->docImpl() && part()->docImpl()->rootElement())
+ part()->docImpl()->rootElement()->prepareMouseEvent(event->pos(), event->pos(), mev);
+
+ if(!mev->url().string().isEmpty())
+ {
+ QString url = mev->url().string();
+ if(url.startsWith("#"))
+ url.prepend(part()->docImpl()->baseUrl().prettyURL());
+ emit browseURL(url);
+ }
+
+ mev->deref();
+}
+
+void KSVGWidget::keyPressEvent(QKeyEvent *ke)
+{
+ if(ke->stateAfter() & QMouseEvent::ControlButton)
+ {
+ setCursor(KCursor::sizeAllCursor());
+ return;
+ }
+
+ if(part()->docImpl()->lastTarget())
+ part()->docImpl()->lastTarget()->dispatchKeyEvent(ke);
+}
+
+void KSVGWidget::keyReleaseEvent(QKeyEvent *ke)
+{
+ if(ke->state() & QMouseEvent::ControlButton)
+ {
+ setCursor(KCursor::arrowCursor());
+ return;
+ }
+
+ if(part()->docImpl()->lastTarget())
+ part()->docImpl()->lastTarget()->dispatchKeyEvent(ke);
+}
+
+void KSVGWidget::resizeEvent(QResizeEvent *e)
+{
+ if(part()->docImpl() && part()->docImpl()->rootElement())
+ part()->docImpl()->rootElement()->dispatchEvent(KSVG::SVGEvent::RESIZE_EVENT, true, false);
+
+ emit redraw(QRect(0, 0, e->size().width(), e->size().height()));
+}
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/ksvg_widget.h b/ksvg/plugin/ksvg_widget.h
new file mode 100644
index 00000000..3cd94849
--- /dev/null
+++ b/ksvg/plugin/ksvg_widget.h
@@ -0,0 +1,68 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSVGWidget_H
+#define KSVGWidget_H
+
+#include <qwidget.h>
+
+#include <kpopupmenu.h>
+
+#include <SVGEventImpl.h>
+
+class KSVGPlugin;
+class KSVGWidget : public QWidget
+{
+Q_OBJECT
+public:
+ KSVGWidget(KSVGPlugin *part, QWidget *parent, const char *name);
+ virtual ~KSVGWidget();
+
+ KSVGPlugin *part() const;
+
+ void reset();
+
+protected:
+ virtual void paintEvent(QPaintEvent *);
+
+ virtual void mouseMoveEvent(QMouseEvent *);
+ virtual void mousePressEvent(QMouseEvent *);
+ virtual void mouseReleaseEvent(QMouseEvent *);
+
+ virtual void keyPressEvent(QKeyEvent *);
+ virtual void keyReleaseEvent(QKeyEvent *);
+
+ virtual void resizeEvent(QResizeEvent *);
+
+signals:
+ void browseURL(const QString &);
+ void redraw(const QRect &);
+
+private:
+ KSVG::SVGMouseEventImpl *newMouseEvent(KSVG::SVGEvent::EventId id, QMouseEvent *event);
+
+ QPoint m_panningPos;
+ QPoint m_oldPanningPos;
+ KSVGPlugin *m_part;
+};
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/plugin/ksvgplugin.desktop b/ksvg/plugin/ksvgplugin.desktop
new file mode 100644
index 00000000..9eaffdc7
--- /dev/null
+++ b/ksvg/plugin/ksvgplugin.desktop
@@ -0,0 +1,85 @@
+[Desktop Entry]
+Name=KSVGPlugin
+Name[ar]=برنامج KSVGPlugin
+Name[ca]=Connector KSVG
+Name[cy]=AtegynKSVG
+Name[el]=Πρόσθετο KSVG
+Name[eo]=Vektorgrafiko-kromaĵo
+Name[eu]=KSVGPlugina
+Name[fr]=Module SVG
+Name[hi]=के-एसवीजी-प्लगइन
+Name[hu]=KSVG bővítőmodul
+Name[is]=KSVGÍforrit
+Name[lv]=KSVGIespraudnis
+Name[ne]=KSVG प्लगइन
+Name[pl]=Wtyczka KSVG
+Name[ro]=Modul KSVG
+Name[sv]=KSVG-insticksprogram
+Name[ta]=KSVGசொருகுப்பொருள்
+Name[tr]=KSVG Eklentisi
+Name[xh]=Iplagi efakiweyo ye KSVG
+Name[zu]=Iplagi efakiweyo ye KSVG
+Icon=vectorgfx
+MimeType=image/svg+xml;image/svg
+Comment=Scalable Vector Graphics Viewer
+Comment[ar]=عارض الرسومات الثابتة القابلة للقياس
+Comment[az]=Miqyaslı Vektor Qrafikaları Nümayişçisi
+Comment[bs]=Scalable Vector Graphics preglednik
+Comment[ca]=Visualitzador de gràfics vectorials escalables (SVG)
+Comment[cs]=Prohlížeč pro formát Scalable Vector Graphics (SVG)
+Comment[cy]=Gwelydd Graffeg Fector Graddedig
+Comment[da]=Fremviser af skalerbar vektorgrafik
+Comment[de]=Betrachter für skalierbare Vektorgraphiken
+Comment[el]=Προβολέας διανυσματικών γραφικών
+Comment[eo]=Rigardilo por pligrandigeblaj vektorgrafikoj
+Comment[es]=Visor de gráficos vectoriales escalables (SVG)
+Comment[et]=Skaleeritava vektorgraafika (SVG) näitaja
+Comment[eu]=Scalable Vector Graphics ikustailua
+Comment[fa]=مشاهده‌گر نگاره‌‌‌‌‌سازی مقیاس‌پذیر برداری
+Comment[fi]=Scalable Vector Graphics -näytin
+Comment[fr]=Afficheur d'images au format Graphisme vectoriel échelonnable (SVG)
+Comment[ga]=Amharcán SVG (Scalable Vector Graphics)
+Comment[gl]=Visor de gráficos vectoriais escalables
+Comment[hi]=स्केलेबल वेक्टर ग्राफिक्स प्रदर्शक
+Comment[hr]=Preglednik SVG datoteka
+Comment[hu]=SVG-megjelenítő
+Comment[is]=Scalable Vector Graphics (SVG) myndbirtir
+Comment[it]=Visore di file SVG
+Comment[ja]=SVG (スケーラブルベクトルグラフィックス) ビューア
+Comment[kk]=SVG файлдарды қарау
+Comment[km]=កម្មវិធី​មើល​ក្រាហ្វិក​វ៉ិចទ័រ​មាន​មាត្រដ្ឋាន
+Comment[lt]=Kintamo dydžio vektorinė grafika
+Comment[lv]=Mērogojamas Vektoru Grafikas Skatītājs
+Comment[ms]=Pemapar Grafik Vektor Boleh Skala
+Comment[mt]=Werrej tas-"Scalable Vector Graphics"
+Comment[nb]=Framvisningsprogram for SVG-bilde («Scalable Vector Graphics»)
+Comment[nds]=Kieker för skaleerbor Vektorgrafiken
+Comment[ne]=मापनयोग्य भेक्टर ग्राफिक्स दर्शक
+Comment[nl]=Scalable Vector Graphics-weergaveprogramma
+Comment[nn]=Framvisingsprogram for SVG-grafikk («Scalable Vector Graphics»)
+Comment[pl]=Przeglądarka dla plików SVG (skalowalnej grafiki wektorowej)
+Comment[pt]=Visualizador de Gráficos Vectoriais Escaláveis (SVG)
+Comment[pt_BR]=Visualizador de Vetores Escaláveis
+Comment[ro]=Vizualizor SVG
+Comment[ru]=Просмотр SVG
+Comment[sk]=Prehliadač pre škálovateľnú vektorovú grafiku SVG
+Comment[sl]=Pregledovalnik skalabilne vektorske grafike
+Comment[sr]=Приказивач скалабилне векторске графике
+Comment[sr@Latn]=Prikazivač skalabilne vektorske grafike
+Comment[sv]=Visning av skalbar vektorgrafik
+Comment[ta]=அளவிடக்கூடிய வெக்டார் சித்திரங்கள் காட்சி
+Comment[tg]=Намоиши SVG
+Comment[tr]=Boyutlandırılabilir Vektör Grafik Gösterici
+Comment[uk]=Переглядач векторної графіки
+Comment[uz]=SVG koʻruvchi
+Comment[uz@cyrillic]=SVG кўрувчи
+Comment[ven]=Muvhono wa girafiki wa scalable vector
+Comment[xh]=Umboniseli wemizobo olinganiselwayo onesalathiso
+Comment[zh_CN]=可缩放矢量图查看器
+Comment[zh_HK]=可縮放向量圖形(SVG)檢視器
+Comment[zh_TW]=可調整的向量圖形檢視器
+Comment[zu]=Umbonisi wemidwebo Onenani Elibalekayo
+Type=Service
+ServiceTypes=KParts/ReadOnlyPart,Browser/View
+X-KDE-Library=libksvgplugin
+InitialPreference=11
diff --git a/ksvg/plugin/ksvgplugin.rc b/ksvg/plugin/ksvgplugin.rc
new file mode 100644
index 00000000..a689f4d8
--- /dev/null
+++ b/ksvg/plugin/ksvgplugin.rc
@@ -0,0 +1,35 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="KSVGPlugin" version="2">
+<MenuBar>
+ <Menu name="settings"><text>&amp;Settings</text>
+ <Separator/>
+ <Action name="view_zoom_in" />
+ <Action name="view_zoom_out" />
+ <Action name="stop_anims"/>
+ <Action name="view_source"/>
+ <Action name="font_kerning"/>
+ <Action name="rendering_backend"/>
+ <Action name="progressive"/>
+ </Menu>
+</MenuBar>
+<Toolbar name="ksvgToolBar">
+ <Action name="view_zoom_in" />
+ <Action name="view_zoom_out" />
+ <Action name="stop_anims"/>
+ <Action name="view_source"/>
+ <Action name="view_memory"/>
+ <Action name="font_kerning"/>
+</Toolbar>
+<Menu name="popupmenu">
+ <Action name="view_zoom_in" />
+ <Action name="view_zoom_out" />
+ <Action name="zoom_reset" />
+ <Action name="stop_anims"/>
+ <Action name="view_source"/>
+ <Separator weakSeparator="1" />
+ <Action name="view_memory"/>
+ <Action name="save_to_png"/>
+ <Separator weakSeparator="1" />
+ <Action name="help_about_app"/>
+</Menu>
+</kpartgui>
diff --git a/ksvg/plugin/svgcreator.cpp b/ksvg/plugin/svgcreator.cpp
new file mode 100644
index 00000000..c6689c9a
--- /dev/null
+++ b/ksvg/plugin/svgcreator.cpp
@@ -0,0 +1,92 @@
+/*
+ Copyright (c) 2001 Malte Starostik <malte@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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// $Id$
+
+#include <time.h>
+
+#include <qpixmap.h>
+#include <qimage.h>
+
+#include "KSVGCanvas.h"
+#include "CanvasFactory.h"
+
+#include <kapplication.h>
+
+#include "SVGSVGElementImpl.h"
+#include "SVGDocumentImpl.h"
+
+#include "svgcreator.moc"
+
+extern "C"
+{
+ ThumbCreator *new_creator()
+ {
+ return new SVGCreator;
+ }
+}
+
+SVGCreator::SVGCreator()
+{
+}
+
+SVGCreator::~SVGCreator()
+{
+}
+
+bool SVGCreator::create(const QString &path, int width, int height, QImage &img)
+{
+ KSVG::SVGDocumentImpl *doc = new KSVG::SVGDocumentImpl(false, true);
+ doc->ref();
+
+ QPixmap pix(width, height);
+ pix.fill(Qt::white);
+
+ KSVG::KSVGCanvas *c = KSVG::CanvasFactory::self()->loadCanvas(width, height);
+ c->setup(&pix, &pix);
+
+ doc->attach(c);
+ connect(doc, SIGNAL(finishedRendering()), SLOT(slotFinished()));
+ doc->open( KURL::fromPathOrURL(path));
+
+ m_finished = false;
+
+ while(!m_finished)
+ kapp->processOneEvent();
+
+ doc->deref();
+
+ img = pix.convertToImage();
+
+ delete c;
+
+ return true;
+}
+
+void SVGCreator::slotFinished()
+{
+ m_finished = true;
+}
+
+ThumbCreator::Flags SVGCreator::flags() const
+{
+ return DrawFrame;
+}
+
+// vim: ts=4 sw=4 noet
diff --git a/ksvg/plugin/svgcreator.h b/ksvg/plugin/svgcreator.h
new file mode 100644
index 00000000..ad1b8f30
--- /dev/null
+++ b/ksvg/plugin/svgcreator.h
@@ -0,0 +1,45 @@
+/*
+ Copyright (c) 2001 Malte Starostik <malte@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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// $Id$
+
+#ifndef __svgcreator_h__
+#define __svgcreator_h__
+
+#include <kio/thumbcreator.h>
+
+class SVGCreator : public QObject, public ThumbCreator
+{
+ Q_OBJECT
+public:
+ SVGCreator();
+ virtual ~SVGCreator();
+ virtual bool create(const QString &path, int width, int height, QImage &img);
+ virtual Flags flags() const;
+
+private slots:
+ void slotFinished();
+
+private:
+ bool m_finished;
+};
+
+#endif
+
+// vim: ts=4 sw=4 noet
diff --git a/ksvg/plugin/svgthumbnail.desktop b/ksvg/plugin/svgthumbnail.desktop
new file mode 100644
index 00000000..47fed23b
--- /dev/null
+++ b/ksvg/plugin/svgthumbnail.desktop
@@ -0,0 +1,52 @@
+[Desktop Entry]
+Type=Service
+Name=Scalable Vector Graphics
+Name[ar]=رسومات ثابتة قابلة للقياس
+Name[az]=Miqyaslı Vektor Qrafikaları
+Name[ca]=Gràfics vectorials escalables (SVG)
+Name[cy]=Graffeg Fector Graddedig
+Name[da]=Skalerbar vektorgrafik
+Name[de]=Skalierbare Vektorgraphiken
+Name[el]=Διανυσματικά γραφικά
+Name[eo]=Vektorgrafikoj
+Name[es]=Gráficos vectoriales escalables (SVG)
+Name[et]=Skaleeritav vektorgraafika (SVG)
+Name[fa]=نگاره‌سازی مقیاس‌پذیر برداری
+Name[fr]=Graphisme vectoriel échelonnable (SVG)
+Name[gl]=Gráficos vectoriais escalables
+Name[hi]=स्केलेबल वेक्टर ग्राफिक्स
+Name[hu]=SVG
+Name[it]=Grafica vettoriale riscalabile
+Name[ja]=SVG (スケーラブルベクトルグラフィックス)
+Name[kk]=SVG сызбалы суреттер
+Name[km]=ក្រាហ្វិក​វ៉ិចទ័រ​មាន​មាត្រដ្ឋាន
+Name[lt]=Kintamo dydžio vektorinė grafika
+Name[lv]=Mērogojama Vektoru Grafika
+Name[ms]=Grafik Vektor Boleh Skala
+Name[nds]=Skaleerbor Vektorgrafiken
+Name[ne]=मापनयोग्य भेक्टर ग्राफिक्स
+Name[pl]=Skalowalna Grafika Wektorowa
+Name[pt]=SVG - Gráficos Vectoriais Escaláveis
+Name[pt_BR]=Vetores Escaláveis
+Name[ro]=Grafică vectorială scalabilă (SVG)
+Name[ru]=Векторные рисунки (.svg)
+Name[sl]=Skalabilna vektorska grafika
+Name[sr]=Скалабилна векторска графика (SVG)
+Name[sr@Latn]=Skalabilna vektorska grafika (SVG)
+Name[sv]=Skalbar vektorgrafik
+Name[ta]=அளவிடக்கூடிய வெக்டார் சித்திரங்கள்
+Name[tg]=Расмҳои вектории масштабкунанда (SVG)
+Name[tr]=Boyutlandırılabilir Vektör Grafiği
+Name[uk]=Масштабовна векторна графіка
+Name[ven]=Dzigirafiki ya vekitha ya Scalable
+Name[xh]=Imizobo elinganiselwayo enesalathisi
+Name[zh_CN]=可缩放矢量图
+Name[zh_HK]=可縮放向量圖形(SVG)
+Name[zh_TW]=可調整的向量圖形
+Name[zu]=Imidwebo Enenani Elibalekayo
+Icon=thumbnail
+MimeTypes=image/svg+xml
+X-KDE-Library=svgthumbnail
+ServiceTypes=ThumbCreator
+InitialPreference=5
+CacheThumbnail=true
diff --git a/ksvg/scripts/COPYRIGHTS b/ksvg/scripts/COPYRIGHTS
new file mode 100644
index 00000000..bcb24052
--- /dev/null
+++ b/ksvg/scripts/COPYRIGHTS
@@ -0,0 +1,19 @@
+/*
+ Copyright (C) 2001-2003 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
diff --git a/ksvg/scripts/ECMACHECK b/ksvg/scripts/ECMACHECK
new file mode 100755
index 00000000..955ea81d
--- /dev/null
+++ b/ksvg/scripts/ECMACHECK
@@ -0,0 +1,25 @@
+#!/bin/bash
+TESTSUITE=test/official/1.0 # Nikos setting
+ECMATESTS=test/ecma
+konqueror $TESTSUITE/script-eventDom-BE-01.svg
+konqueror $TESTSUITE/script-uiEvents-BE-02.svg
+konqueror $TESTSUITE/dom-core-BE-01.svg
+konqueror $TESTSUITE/dom-eventListener-BE-04.svg
+konqueror $TESTSUITE/dom-featureString-BE-03.svg
+konqueror $TESTSUITE/dom-svg-BE-02.svg
+konqueror $TESTSUITE/extend-multiNS-BE-01.svg
+konqueror $TESTSUITE/interact-onload-BE-07.svg
+konqueror $TESTSUITE/interact-bubble-BE-04.svg
+konqueror $TESTSUITE/interact-pEvents-BE-05.svg
+konqueror $TESTSUITE/interact-pEvents-BE-06.svg
+konqueror $ECMATESTS/broken.svg
+konqueror $ECMATESTS/circle.svg
+konqueror $ECMATESTS/clock.svg
+konqueror $ECMATESTS/bbox/bbox-circle.svg
+konqueror $ECMATESTS/bbox/bbox-ellipse.svg
+konqueror $ECMATESTS/bbox/bbox-line.svg
+konqueror $ECMATESTS/bbox/bbox-path.svg
+konqueror $ECMATESTS/bbox/bbox-path2.svg
+konqueror $ECMATESTS/bbox/bbox-polygon.svg
+konqueror $ECMATESTS/bbox/bbox-polyline.svg
+konqueror $ECMATESTS/bbox/bbox-rect.svg
diff --git a/ksvg/scripts/OPENREF b/ksvg/scripts/OPENREF
new file mode 100755
index 00000000..f8fbecb0
--- /dev/null
+++ b/ksvg/scripts/OPENREF
@@ -0,0 +1,9 @@
+#!/bin/bash
+pid=`dcopstart konqueror --profile filemanagement`
+loc=`pwd`/$1
+sleep 1
+dcop $pid konqueror-mainwindow#1 openURL ${loc}svg
+sleep 1
+dcop $pid qt/KXMLGUILClient-KActionCollection/splitviewh activate
+sleep 1
+dcop $pid konqueror-mainwindow#1 openURL ${loc}png
diff --git a/ksvg/scripts/README b/ksvg/scripts/README
new file mode 100644
index 00000000..17130216
--- /dev/null
+++ b/ksvg/scripts/README
@@ -0,0 +1,16 @@
+This document explains how to generate a SVG C++ header/sourcefile pair :
+
+1. go to dir idl
+2. copy the svg.idl file to the classname you want to generate, for example SVGRect
+3. edit the newly created file to only include the class info, delete the rest
+4. run ../gen.sh classname (without extension) to generate the pair
+
+Caveats:
+1. all inheritance specification must be on the same line
+2. no support yet for exceptions, comments
+3. this works for mawk 1.3.3, with slight adjustments it should run for
+ other awk implementations
+
+07-07-2001
+Rob Buis.
+
diff --git a/ksvg/scripts/add_static.pl b/ksvg/scripts/add_static.pl
new file mode 100644
index 00000000..9a88c00f
--- /dev/null
+++ b/ksvg/scripts/add_static.pl
@@ -0,0 +1,42 @@
+# Add #include "ksvg_lookup.h", GENERATEDDATA and ELEMENTDATA to all headers passed as argument
+# Usage: perl -w -i.bak add_static.pl *.h
+my $added_ksvg_lookup = 0;
+#my $added_staticdata = 0;
+my $inclass=0;
+my $bracelevel=0;
+my $class_bracelevel;
+my $has_staticdata=0;
+while (<>) {
+ $added_ksvg_lookup=0 if (/\#ifndef/); # this while loop runs over multiple files...
+ $added_ksvg_lookup=1 if (/\#include \"ksvg_lookup.h\"/); # already there
+ if (!$added_ksvg_lookup) {
+ if (/^\s*\#\s*include/ || /^namespace/ || /^class/) {
+ $added_ksvg_lookup = 1;
+ print '#include "ksvg_lookup.h"' . "\n";
+ }
+ }
+ if ( /^class/ && !/;/ ) {
+ die if $inclass;
+ $inclass=1;
+ $class_bracelevel=$bracelevel;
+ $has_staticdata=0;
+ }
+ if ( /{/ ) {
+ $bracelevel++;
+ die if /{.*{/; # not handled currently
+ }
+ if ( /}/ ) {
+ $bracelevel--;
+ die if /}.*}/; # not handled currently
+ }
+ $has_staticdata = 1 if ( $inclass && /GENERATEDDATA/ );
+ if ( $inclass && ($class_bracelevel == $bracelevel) && /};/ ) {
+ print "public:\n\tGENERATEDDATA\n" if ( !$has_staticdata );
+ $inclass=0;
+ # $added_staticdata=1;
+ }
+ print;
+}
+die "still in class!" if ($inclass);
+die "bracelevel != 0!" if ($bracelevel);
+#die "found no class where to add GENERATEDDATA!" if (!$added_staticdata);
diff --git a/ksvg/scripts/check_hashtablesize.pl b/ksvg/scripts/check_hashtablesize.pl
new file mode 100755
index 00000000..d22e3f30
--- /dev/null
+++ b/ksvg/scripts/check_hashtablesize.pl
@@ -0,0 +1,224 @@
+# Script to check hashtable sizes.
+# Copyright 2002 Nikolas Zimmermann <wildfox@kde.org>
+
+my $input = shift;
+my $calcMode = 0;
+
+# Check incoming arguments
+if(length($input) > 0) {
+ $calcMode = $input;
+} else {
+ print "Usage:\n";
+ print "perl check_hashtablesize.pl [0/1/2]\n\n";
+ print "Show...\n";
+ print "0) all hashtables of prototype definitions\n";
+ print "1) all hashtables of non-prototype definitions\n";
+ print "2) all hashtables of svg*constructor definitions\n";
+ exit(-1);
+}
+
+# Test if a number is prime or not
+sub calcPrime
+{
+ my $start = shift;
+ my $dividecount = 0;
+
+ for(my $i = $start - 1; $i > 0; --$i)
+ {
+ my $result = $start / $i;
+
+ if($result == int($result)) {
+ $dividecount++;
+ }
+ }
+
+ if($dividecount == 1) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+# Find the next prime number
+sub findNextPrime
+{
+ my $start = shift;
+ my $i = $start + 1;
+ my $found = 0;
+
+ while($found == 0)
+ {
+ if(calcPrime($i)) {
+ $found = 1;
+ } else {
+ $i++;
+ }
+ }
+
+ return $i;
+}
+
+# Common routine for calculating hashtable sizes
+sub calcSize
+{
+ my $calc = shift;
+ my $save = shift;
+ my $minus = shift;
+
+ my @temp = split(/\n/, $calc);
+
+ foreach(@temp) {
+ my $process = $_;
+ $process =~ s/\s+/ /g;
+
+ my @line = split(/ /, $process);
+ my $class = substr($line[1], 0, index($line[1], ":") - $minus);
+
+ $$save{$class} = $line[2];
+ }
+}
+
+# Go to impl dir
+chdir "../impl";
+
+# Global counters
+my %counterwork;
+my %counter1;
+my %counter2;
+my %counter3;
+
+# Read hashtable size
+my $readSize1 = `find -type f | xargs grep -I DontDelete | grep -v KSVG:: | grep Function`;
+my $readSize2 = `find -type f | xargs grep -I DontDelete | grep -v KSVG:: | grep -v Function`;
+my $readSize3 = `find -type f | xargs grep -I DontDelete | grep KSVG::`;
+
+my @result1 = split(/.\//, $readSize1);
+my @result2 = split(/.\//, $readSize2);
+my @result3 = split(/.\//, $readSize3);
+
+# Calculate hashtable size
+# calcSize1 = print out all prototype hashtables
+# calcSize2 = print out all non-prototype hashtables
+# calcSize3 = print out all svg*constructors hashtables
+my $calcSize1 = `find -type f | xargs grep -I s_hashTable | grep \@begin | grep -v generateddata | grep -v Constructor | grep -v Impl:: | grep -v Bridge::`;
+my $calcSize2 = `find -type f | xargs grep -I s_hashTable | grep \@begin | grep -v generateddata | grep -v Constructor | grep -v Proto::`;
+my $calcSize3 = `find -type f | xargs grep -I s_hashTable | grep \@begin | grep -v generateddata | grep Constructor`;
+
+# Bring in suitable form
+calcSize($calcSize1, \%counter1, 5);
+calcSize($calcSize2, \%counter2, 0);
+calcSize($calcSize3, \%counter3, 11);
+
+# Helper
+my $lastclass = "";
+
+print "Classname\t\t\t\t'H.S. File'\t\t'H.S. Calculated'\tIs 'H.S. File' prime?\tDo they differ?\n";
+print "-------------------------------------------------------------------------------------------------------------------------------\n";
+
+my @useresult;
+if($calcMode == 0) {
+ @useresult = @result1;
+} elsif($calcMode == 1) {
+ @useresult = @result2;
+} else {
+ @useresult = @result3;
+}
+
+foreach(@useresult) {
+ my $line = $_;
+ $line =~ s/\s+/ /g;
+
+ if($line ne "") {
+ my @middle = split(/ /, $line);
+ my $class = substr($middle[2], 0, index($middle[2], ":"));
+
+ # Special case for lists and svg*constructors
+ if($class eq "SVGListDefs" || $calcMode == 2)
+ {
+ my $temp = $middle[0];
+
+ if($calcMode != 2) {
+ $temp =~ s/.cc://;
+ $class = $temp;
+ } else {
+ $temp =~ s/.cc//;
+ $class = substr($temp, 0, index($temp, ":"));
+ }
+ }
+
+ if($class eq $lastclass) {
+ $counterwork{$class}++;
+ }
+ else {
+ $counterwork{$class} = 1;
+
+ if($lastclass ne "") {
+ my $len = length($lastclass);
+
+ my $string = $lastclass;
+
+ # Ugly hack with those numbers, anyone
+ # got a better idea?
+ if($len < 11) {
+ $string .= "\t\t\t\t\t";
+ } elsif($len < 16) {
+ $string .= "\t\t\t\t";
+ } elsif($len < 24) {
+ $string .= "\t\t\t";
+ } elsif($len < 32) {
+ $string .= "\t\t";
+ } else {
+ $string .= "\t";
+ }
+
+ my $combine;
+
+ if($calcMode == 0) {
+ $combine = $counter1{$lastclass};
+ } elsif($calcMode == 1) {
+ $combine = $counter2{$lastclass};
+ } else {
+ $combine = $counter3{$lastclass};
+ }
+
+ if($combine eq 0 || $combine eq "") {
+ $combine = "-";
+ }
+
+ $string .= $combine;
+ $string .= "\t\t\t";
+
+ # Find next prime
+ my $next = findNextPrime($counterwork{$lastclass});
+
+ $string .= $next;
+ $string .= "\t\t\t";
+
+ # Is 'H.S. File' a prime?
+ my $calc = calcPrime($combine);
+ if($calc == 0) {
+ $string .= "NO!";
+ } else {
+ $string .= "Yes";
+ }
+
+ $string .= "\t\t\t";
+
+ if($combine != $next) {
+ $string .= "YES!";
+ } else {
+ $string .= "No";
+ }
+
+ $string .= "\n";
+
+ print $string;
+ }
+ }
+
+ $lastclass = $class;
+ }
+}
+
+# Go back! :)
+chdir "../scripts";
diff --git a/ksvg/scripts/gen.sh b/ksvg/scripts/gen.sh
new file mode 100755
index 00000000..d608385b
--- /dev/null
+++ b/ksvg/scripts/gen.sh
@@ -0,0 +1,51 @@
+# try to find an appropriate awk interpreter
+if which mawk > /dev/null 2>&1; then
+ cmd_awk=`which mawk`;
+else
+ if which awk > /dev/null 2>&1; then
+ cmd_awk=`which awk`;
+ else
+ echo "No suitable AWK interpreter found. Aborting."
+ exit 1
+ fi
+fi
+
+# make them
+touch $1.h
+touch $1.cc
+
+#start with copyright notices
+cat ../COPYRIGHTS > $1.h
+cat ../COPYRIGHTS > $1.cc
+
+# add define for multiple include problem
+echo "" >> $1.h
+echo "#ifndef $1_H" >> $1.h
+echo "#define $1_H" >> $1.h
+echo "" >> $1.h
+echo "namespace KSVG" >> $1.h
+echo "{" >> $1.h
+echo "" >> $1.h
+
+#include in .cc + namespace
+echo "" >> $1.cc
+echo "#include \"$1.h\"" >> $1.cc
+echo "#include \"$1Impl.h\"" >> $1.cc
+echo "" >> $1.cc
+echo "using namespace KSVG;" >> $1.cc
+echo "" >> $1.cc
+
+#go go go
+$cmd_awk -f ../makeheader $1
+$cmd_awk -f ../makecc $1
+
+#add end of define
+echo "};" >> $1.h
+echo "" >> $1.h
+echo "#endif" >> $1.h
+echo "" >> $1.h
+
+echo "// vim:ts=4:noet" >> $1.h
+echo "// vim:ts=4:noet" >> $1.cc
+
+#done I hope
diff --git a/ksvg/scripts/generate.pl b/ksvg/scripts/generate.pl
new file mode 100755
index 00000000..a9419dcc
--- /dev/null
+++ b/ksvg/scripts/generate.pl
@@ -0,0 +1,69 @@
+#!/usr/bin/perl -w
+
+my $kalyptusdir = "../../../kdebindings/kalyptus";
+
+use File::Basename;
+
+my $here = `pwd`;
+chomp $here;
+my $outdir = $here . "/generate.pl.tmpdir";
+my $finaloutdir = $here;
+
+## Note: outdir and finaloutdir should NOT be the same dir!
+
+if (! -d $outdir) { mkdir $outdir; }
+
+mkdir $finaloutdir unless (-d $finaloutdir);
+
+
+# Need to cd to kalyptus's directory so that perl finds Ast.pm etc.
+chdir "$kalyptusdir" or die "Couldn't go to $kalyptusdir (edit script to change dir)\n";
+
+# Find out which header files we need to parse
+my %excludes = (
+);
+
+# List headers, and exclude the ones listed above
+my @headers = ();
+my $incdir=$here;
+opendir (INCS, $incdir) or die "Couldn't find $incdir";
+foreach $filename (readdir(INCS)) {
+ $entry = $incdir."/".$filename;
+ if ( ( -e $entry or -l $entry ) # A real file or a symlink
+ && ( ! -d _ ) ) # Not a symlink to a dir though
+ {
+ push(@headers, $entry)
+ if ( !defined $excludes{$filename} # Not excluded
+ && $filename =~ /\.h$/ ); # Not a backup file etc. Only headers.
+ }
+}
+closedir INCS;
+
+# Launch kalyptus
+system "perl kalyptus @ARGV -fECMA --name=ksvg --outputdir=$outdir @headers";
+my $exit = $? >> 8;
+exit $exit if ($exit);
+
+# Generate diff for generateddata.cpp
+if ( -e "$finaloutdir/generateddata.cpp" ) {
+ system "diff -u $finaloutdir/generateddata.cpp $outdir/generateddata.cpp > $outdir/generateddata.cpp.diff";
+}
+
+# Copy changed or new files to finaloutdir
+#opendir (OUT, $outdir) or die "Couldn't opendir $outdir";
+#foreach $filename (readdir(OUT)) {
+my $filename = "generateddata.cpp";
+ #next if ( -d "$outdir/$filename" ); # only files, not dirs
+ my $docopy = 1;
+ if ( -f "$finaloutdir/$filename" ) {
+ # How can I do a fast file compare in perl?
+ system "cmp -s $outdir/$filename $finaloutdir/$filename";
+ $docopy = ($?>>8); # 0 if files identical, 1 if different
+ }
+ if ($docopy) {
+ #print STDERR "Updating $filename...\n";
+ system "cp -f $outdir/$filename $finaloutdir/$filename";
+ }
+
+# Delete outdir
+system "rm -rf $outdir";
diff --git a/ksvg/scripts/genimpl.sh b/ksvg/scripts/genimpl.sh
new file mode 100755
index 00000000..5a0742d2
--- /dev/null
+++ b/ksvg/scripts/genimpl.sh
@@ -0,0 +1,49 @@
+# try to find an appropriate awk interpreter
+if which mawk > /dev/null 2>&1; then
+ cmd_awk=`which mawk`;
+else
+ if which awk > /dev/null 2>&1; then
+ cmd_awk=`which awk`;
+ else
+ echo "No suitable AWK interpreter found. Aborting."
+ exit 1
+ fi
+fi
+
+# you cant touch this
+touch $1Impl.h
+touch $1Impl.cc
+
+#start with copyright notices
+cat ../COPYRIGHTS > $1Impl.h
+cat ../COPYRIGHTS > $1Impl.cc
+
+# add define for multiple include problem
+echo "" >> $1Impl.h
+echo "#ifndef $1Impl_H" >> $1Impl.h
+echo "#define $1Impl_H" >> $1Impl.h
+
+# namespace
+echo "" >> $1Impl.h
+echo "namespace KSVG" >> $1Impl.h
+echo "{" >> $1Impl.h
+
+#include in .cc + namespace
+echo "" >> $1Impl.cc
+echo "#include \"$1Impl.h\"" >> $1Impl.cc
+echo "" >> $1Impl.cc
+echo "using namespace KSVG;" >> $1Impl.cc
+echo "" >> $1Impl.cc
+
+#go go go
+$cmd_awk -f ../makeimpl $1
+
+#add end of define
+echo "};" >> $1Impl.h
+echo "" >> $1Impl.h
+echo "#endif" >> $1Impl.h
+echo "" >> $1Impl.h
+echo "// vim:ts=4:noet" >> $1Impl.h
+
+echo "// vim:ts=4:noet" >> $1Impl.cc
+#done I hope
diff --git a/ksvg/scripts/getjs.php b/ksvg/scripts/getjs.php
new file mode 100755
index 00000000..5f300fe9
--- /dev/null
+++ b/ksvg/scripts/getjs.php
@@ -0,0 +1,390 @@
+#!/usr/local/bin/php
+<?
+/*
+ Copyright (C) 2002 KSVG Team
+ This file is part of the KDE project
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+class ecma_class
+{
+ var $properties; // array of properties
+ var $functions; // array of functions $functions[0][0]="geturl"; $functions[0][1]="2";
+ var $constants; // array of functions
+ var $class; // classname
+ var $params;
+ var $readonly;
+
+ function ecma_class($name)
+ {
+ $this->class=$name;
+ $this->functions=array();
+ $this->properties=array();
+ $this->constants=array();
+ $this->parmas=array();
+ }
+
+ function add_content($content)
+ {
+ if ($content->type==0)
+ {
+ if (!in_array($content->name,$this->properties))
+ {
+ $this->properties[]=$content->name;
+ $this->readonly[$content->name]=$content->readonly;
+ }
+ }
+ elseif ($content->type==1)
+ {
+ if (!in_array($content->name,$this->functions))
+ {
+ $this->functions[]=$content->name;
+ $this->params[$content->name]=$content->params;
+ }
+ }
+ elseif ($content->type==2)
+ {
+ if (!in_array($content->name,$this->constants))
+ $this->constants[]=$content->name;
+ }
+ }
+
+ function to_text()
+ {
+ $headline=$this->class." (".(sizeof($this->properties))." Properties and ".(sizeof($this->functions))." Functions and ".(sizeof($this->constants))." Constants)";
+ echo($headline."\n");
+ echo("====================");
+ echo("\n\n");
+
+
+ echo("Properties\n");
+ echo("----------\n");
+ for ($i=0;$i<sizeof($this->properties);$i++)
+ {
+ echo($this->properties[$i]."\n");
+ }
+
+ echo("\n");
+ echo("Functions\n");
+ echo("----------\n");
+ for ($i=0;$i<sizeof($this->functions);$i++)
+ {
+ echo($this->functions[$i]."\n");
+ }
+
+ echo("\n");
+ echo("Constants\n");
+ echo("----------\n");
+ for ($i=0;$i<sizeof($this->constants);$i++)
+ {
+ echo($this->constants[$i]."\n");
+ }
+
+ echo("\n%%%%%%%%%%%%%%%%%%%%%%%%\n\n");
+ }
+
+ function to_html()
+ {
+ echo("<a name=\"".$this->class."\"></a>");
+ echo("<a href=\"#toc\">Back to Index</a>");
+ echo("<table border=\"1\" style=\"border-width: medium; border-collapse: collapse\">\n");
+ echo("<tr><td colspan=\"3\"><h2 style=\"text-align: left\">".$this->class."</h2></td></tr>\n");
+
+ if (sizeof($this->functions)>0)
+ {
+ echo("<tr><td colspan=\"3\"><h3>Functions</h3></td></tr>\n");
+
+ for ($i=0;$i<sizeof($this->functions);$i++)
+ {
+ echo("<tr><td width=\"20\">&nbsp</td><td>".$this->functions[$i]."</td><td>".$this->params[$this->functions[$i]]." Parameter(s)</td></tr>\n");
+ }
+ }
+
+ if (sizeof($this->properties)>0)
+ {
+ echo("<tr><td colspan=\"3\"><h3>Properties</h3></td></tr>\n");
+
+ for ($i=0;$i<sizeof($this->properties);$i++)
+ {
+ if ($this->readonly[$this->properties[$i]])
+ $readonly="Property is ReadOnly";
+ else
+ $readonly="Property is ReadWrite";
+
+ echo("<tr><td width=\"20\">&nbsp</td><td>".$this->properties[$i]."</td><td>$readonly</td></tr>\n");
+ }
+ }
+
+ if (sizeof($this->constants)>0)
+ {
+ echo("<tr><td colspan=\"3\"><h3>Constants</h3></td></tr>\n");
+
+ for ($i=0;$i<sizeof($this->constants);$i++)
+ {
+ echo("<tr><td width=\"20\">&nbsp</td><td>".$this->constants[$i]."</td></tr>\n");
+ }
+ }
+ echo("</table><br><br>");
+ }
+
+ function to_svg(&$x,&$y)
+ {
+ $xtemp=$x+50;
+ $ytemp=$y+50;
+
+ echo("<text x=\"$xtemp\" y=\"$ytemp\">".$this->class."</text>");
+
+ $ytemp+=10;
+
+ if (sizeof($this->functions)>0)
+ {
+ echo("<text x=\"".$xtemp."\" y=\"".($ytemp)."\">Functions</text>\n");
+
+ $ytemp+=10;
+
+ for ($i=0;$i<sizeof($this->functions);$i++)
+ {
+ echo("<text x=\"".($xtemp+20)."\" y=\"".($ytemp)."\">".$this->functions[$i]." with ".$this->params[$this->functions[$i]]." Parameter(s)</text>\n");
+ $ytemp+=10;
+ }
+ }
+
+ if (sizeof($this->properties)>0)
+ {
+ echo("<text x=\"".$xtemp."\" y=\"".($ytemp)."\">Properties</text>\n");
+
+ $ytemp+=10;
+
+ for ($i=0;$i<sizeof($this->properties);$i++)
+ {
+ if ($this->readonly[$this->properties[$i]])
+ $readonly="Property is ReadOnly";
+ else
+ $readonly="Property is ReadWrite";
+
+ echo("<text x=\"".($xtemp+20)."\" y=\"".$ytemp."\">".$this->properties[$i]." $readonly</text>\n");
+ $ytemp+=10;
+ }
+ }
+
+ if (sizeof($this->constants)>0)
+ {
+ echo("<text x=\"".$xtemp."\" y=\"".$ytemp."\">Constants</text>\n");
+
+ $ytemp+=10;
+
+ for ($i=0;$i<sizeof($this->constants);$i++)
+ {
+ echo("<text x=\"".($xtemp+20)."\" y=\"".$ytemp."\">".$this->constants[$i]."</text>\n");
+ $ytemp+=10;
+ }
+ }
+ $x=$xtemp+200;
+ }
+}
+
+class kalyptus_result
+{
+ var $class;
+ var $type; // 0 = Property ; 1 = Function ; 2 = Constant
+ var $name;
+ var $params;
+ var $readonly;
+
+ function kalyptus_result($class,$type,$name,$params=0)
+ {
+ $this->class=$class;
+ $this->type=$type;
+ $this->name=$name;
+ $this->params=$params;
+ }
+
+ function setReadOnly($value)
+ {
+ $this->readonly=$value;
+ }
+}
+
+function parse_kalyptus($line,&$fp,&$last_constructor)
+{
+ if (preg_match("/^[ \t^#]*([a-zA-Z_]*)[ \t]*KSVG::.*DontDelete/",$line,$match))
+ {
+ if (DEBUG) fputs($fp,"MATCH => Constant ".$match[1]." in class ".$match[2]."\n");
+ return new kalyptus_result($last_constructor,2,$match[1]);
+ }
+ elseif (preg_match("/^[ \t^#]*([a-zA-Z_]*)[ \t]*([a-zA-Z_]*)::.*Function ([0-9])/",$line,$match))
+ {
+ if (DEBUG) fputs($fp,"MATCH => Function ".$match[1]." in class ".$match[2]."\n");
+ return new kalyptus_result($match[2],1,$match[1],$match[3]);
+ }
+ elseif (preg_match("/^[ \t^#]*([a-zA-Z_]*)[ \t]*([a-zA-Z_]*)::.*DontDelete\|ReadOnly/",$line,$match))
+ {
+ if (DEBUG) fputs($fp,"MATCH => Property ".$match[1]." in class ".$match[2]."\n");
+ $property=new kalyptus_result($match[2],0,$match[1]);
+ $property->setReadOnly(true);
+ return $property;
+ }
+ elseif (preg_match("/^[ \t^#]*([a-zA-Z_]*)[ \t]*([a-zA-Z_]*)::.*DontDelete/",$line,$match))
+ {
+ if (DEBUG) fputs($fp,"MATCH => Property ".$match[1]." in class ".$match[2]."\n");
+ $property=new kalyptus_result($match[2],0,$match[1]);
+ $property->setReadOnly(false);
+ return $property;
+ }
+ elseif (preg_match("/^[ \t@begin^#]*([a-zA-Z_]*)Constructor::s_hashTable.*/",$line,$match))
+ {
+ if (DEBUG) fputs($fp,"Constructor => ".$match[1]."\n");
+ $last_constructor=$match[1];
+ return false;
+ }
+ else
+ {
+ if (DEBUG) fputs($fp,"Ignored => ".$line."\n");
+ return false;
+ }
+}
+
+function do_output($output,$ecma_classes)
+{
+ ksort($ecma_classes);
+
+ reset($ecma_classes);
+
+ switch($output)
+ {
+ case "txt":
+ foreach ($ecma_classes as $classname => $obj)
+ {
+ $obj->to_text();
+ }
+ break;
+ case "svg":
+ echo("<svg width=\"100%\" height=\"100%\">\n");
+
+ $x=0;
+ $y=0;
+
+ foreach ($ecma_classes as $classname => $obj)
+ {
+ $obj->to_svg($x,$y);
+ }
+ echo("</svg>");
+ break;
+ default:
+ echo("<html>\n<body>\n");
+
+ echo("<a name=\"toc\"><h1>Contents</h1></a><br>\n");
+
+ foreach ($ecma_classes as $classname => $obj)
+ {
+ echo("<a href=\"#".$classname."\">$classname</a><br>\n");
+ }
+
+ echo("<hr>\n");
+
+ foreach ($ecma_classes as $classname => $obj)
+ {
+ $obj->to_html();
+ }
+ echo("</body>\n</html>");
+ }
+}
+
+function searchKalyptusCode($file,&$fp)
+{
+ global $ecma_classes;
+
+ ob_start();
+ readfile($file);
+ $content=ob_get_contents();
+ ob_end_clean();
+
+ if (preg_match("/@begin(.*)@end/s",$content,$matches)) // FIXME broken....if several @end's are there it takes always the last
+ {
+ if (DEBUG) fputs($fp,"Found ".(sizeof($matches)-1)." Matches in ".$file."\n");
+ for ($i=1;$i<sizeof($matches);$i++)
+ {
+ if (DEBUG) fputs($fp,"Checking ".$i.". Match\n");
+ $lines=explode("\n",$matches[$i]);
+ for ($j=0;$j<sizeof($lines);$j++)
+ {
+ $result=parse_kalyptus($lines[$j],$fp,$last_constructor);
+ if ($result)
+ $results[]=$result;
+ }
+ }
+
+ for ($i=0;$i<sizeof($results);$i++)
+ {
+ if ($ecma_classes[$results[$i]->class])
+ $ecma_classes[$results[$i]->class]->add_content($results[$i]);
+ else
+ {
+ $ecma_classes[$results[$i]->class]=new ecma_class($results[$i]->class);
+ $ecma_classes[$results[$i]->class]->add_content($results[$i]);
+ }
+ }
+ }
+}
+
+function crawlFiles($path)
+{
+ global $ecma_classes;
+
+ $fp=fopen("php://stderr","w+");
+
+ if ($dir = @opendir($path))
+ {
+ while (($file = readdir($dir)) !== false)
+ {
+ if (($file!=".") && ($file!=".."))
+ {
+ if (is_dir($path."/".$file))
+ {
+ fputs($fp,"Entering directory ".$file."\n");
+ crawlFiles($path."/".$file);
+ fputs($fp,"Leaving directory ".$file."\n");
+ }
+ elseif (is_file($path."/".$file) && preg_match("/^[A-Za-z0-9_]+(\.cc|\.cpp|\.h|\.hpp)$/",$file))
+ {
+ fputs($fp,"\tchecking $file\n");
+ searchKalyptusCode($path."/".$file,$fp);
+ }
+ }
+ }
+ closedir($dir);
+ }
+}
+
+define(DEBUG,0);
+
+$ecma_classes=array();
+
+$ksvg_path="../";
+
+$path=basename(realpath($ksvg_path));
+
+if ($path!="ksvg")
+{
+ echo "Execute it in base ksvg dir please :S\n";
+ return false;
+}
+
+crawlFiles($ksvg_path);
+
+do_output($argv[1],$ecma_classes);
+?>
diff --git a/ksvg/scripts/idl/svg.idl b/ksvg/scripts/idl/svg.idl
new file mode 100644
index 00000000..9b5ea3db
--- /dev/null
+++ b/ksvg/scripts/idl/svg.idl
@@ -0,0 +1,1756 @@
+// File: svg.idl
+#ifndef _SVG_IDL_
+#define _SVG_IDL_
+
+
+// For access to DOM2 core
+#include "dom.idl"
+
+// For access to DOM2 events
+#include "events.idl"
+
+// For access to those parts from DOM2 CSS OM used by SVG DOM.
+#include "css.idl"
+
+// For access to those parts from DOM2 Views OM used by SVG DOM.
+#include "views.idl"
+
+// For access to the SMIL OM used by SVG DOM.
+#include "smil.idl"
+
+#pragma prefix "dom.w3c.org"
+#pragma javaPackage "org.w3c.dom"
+module svg
+{
+ typedef dom::DOMString DOMString;
+ typedef dom::DOMException DOMException;
+ typedef dom::Element Element;
+ typedef dom::Document Document;
+ typedef dom::NodeList NodeList;
+
+ // Predeclarations
+ interface SVGElement;
+ interface SVGLangSpace;
+ interface SVGExternalResourcesRequired;
+ interface SVGTests;
+ interface SVGFitToViewBox;
+ interface SVGZoomAndPan;
+ interface SVGViewSpec;
+ interface SVGURIReference;
+ interface SVGPoint;
+ interface SVGMatrix;
+ interface SVGPreserveAspectRatio;
+ interface SVGAnimatedPreserveAspectRatio;
+ interface SVGTransformList;
+ interface SVGAnimatedTransformList;
+ interface SVGTransform;
+ interface SVGICCColor;
+ interface SVGColor;
+ interface SVGPaint;
+ interface SVGTransformable;
+ interface SVGDocument;
+ interface SVGSVGElement;
+ interface SVGElementInstance;
+ interface SVGElementInstanceList;
+
+
+ exception SVGException {
+ unsigned short code;
+ };
+
+ // SVGExceptionCode
+ const unsigned short SVG_WRONG_TYPE_ERR = 0;
+ const unsigned short SVG_INVALID_VALUE_ERR = 1;
+ const unsigned short SVG_MATRIX_NOT_INVERTABLE = 2;
+
+ interface SVGElement : Element {
+ attribute DOMString id;
+ // raises DOMException on setting
+ attribute DOMString xmlbase;
+ // raises DOMException on setting
+ readonly attribute SVGSVGElement ownerSVGElement;
+ readonly attribute SVGElement viewportElement;
+ };
+
+ interface SVGAnimatedBoolean {
+
+ attribute boolean baseVal;
+ // raises DOMException on setting
+ readonly attribute boolean animVal;
+ };
+
+ interface SVGAnimatedString {
+
+ attribute DOMString baseVal;
+ // raises DOMException on setting
+ readonly attribute DOMString animVal;
+ };
+
+ interface SVGStringList {
+
+ readonly attribute unsigned long numberOfItems;
+
+ void clear ( )
+ raises( DOMException );
+ DOMString initialize ( in DOMString newItem )
+ raises( DOMException, SVGException );
+ DOMString getItem ( in unsigned long index )
+ raises( DOMException );
+ DOMString insertItemBefore ( in DOMString newItem, in unsigned long index )
+ raises( DOMException, SVGException );
+ DOMString replaceItem ( in DOMString newItem, in unsigned long index )
+ raises( DOMException, SVGException );
+ DOMString removeItem ( in unsigned long index )
+ raises( DOMException );
+ DOMString appendItem ( in DOMString newItem )
+ raises( DOMException, SVGException );
+ };
+
+ interface SVGAnimatedEnumeration {
+
+ attribute unsigned short baseVal;
+ // raises DOMException on setting
+ readonly attribute unsigned short animVal;
+ };
+
+ interface SVGAnimatedInteger {
+
+ attribute long baseVal;
+ // raises DOMException on setting
+ readonly attribute long animVal;
+ };
+
+ interface SVGNumber {
+
+ attribute float value;
+ // raises DOMException on setting
+ };
+
+ interface SVGAnimatedNumber {
+
+ attribute float baseVal;
+ // raises DOMException on setting
+ readonly attribute float animVal;
+ };
+
+ interface SVGNumberList {
+
+ readonly attribute unsigned long numberOfItems;
+
+ void clear ( )
+ raises( DOMException );
+ SVGNumber initialize ( in SVGNumber newItem )
+ raises( DOMException, SVGException );
+ SVGNumber getItem ( in unsigned long index )
+ raises( DOMException );
+ SVGNumber insertItemBefore ( in SVGNumber newItem, in unsigned long index )
+ raises( DOMException, SVGException );
+ SVGNumber replaceItem ( in SVGNumber newItem, in unsigned long index )
+ raises( DOMException, SVGException );
+ SVGNumber removeItem ( in unsigned long index )
+ raises( DOMException );
+ SVGNumber appendItem ( in SVGNumber newItem )
+ raises( DOMException, SVGException );
+ };
+
+ interface SVGAnimatedNumberList {
+
+ readonly attribute SVGNumberList baseVal;
+ readonly attribute SVGNumberList animVal;
+ };
+
+ interface SVGLength {
+
+ // Length Unit Types
+ const unsigned short SVG_LENGTHTYPE_UNKNOWN = 0;
+ const unsigned short SVG_LENGTHTYPE_NUMBER = 1;
+ const unsigned short SVG_LENGTHTYPE_PERCENTAGE = 2;
+ const unsigned short SVG_LENGTHTYPE_EMS = 3;
+ const unsigned short SVG_LENGTHTYPE_EXS = 4;
+ const unsigned short SVG_LENGTHTYPE_PX = 5;
+ const unsigned short SVG_LENGTHTYPE_CM = 6;
+ const unsigned short SVG_LENGTHTYPE_MM = 7;
+ const unsigned short SVG_LENGTHTYPE_IN = 8;
+ const unsigned short SVG_LENGTHTYPE_PT = 9;
+ const unsigned short SVG_LENGTHTYPE_PC = 10;
+
+ readonly attribute unsigned short unitType;
+ attribute float value;
+ // raises DOMException on setting
+ attribute float valueInSpecifiedUnits;
+ // raises DOMException on setting
+ attribute DOMString valueAsString;
+ // raises DOMException on setting
+
+ void newValueSpecifiedUnits ( in unsigned short unitType, in float valueInSpecifiedUnits );
+ void convertToSpecifiedUnits ( in unsigned short unitType );
+ };
+
+ interface SVGAnimatedLength {
+
+ readonly attribute SVGLength baseVal;
+ readonly attribute SVGLength animVal;
+ };
+
+ interface SVGLengthList {
+
+ readonly attribute unsigned long numberOfItems;
+
+ void clear ( )
+ raises( DOMException );
+ SVGLength initialize ( in SVGLength newItem )
+ raises( DOMException, SVGException );
+ SVGLength getItem ( in unsigned long index )
+ raises( DOMException );
+ SVGLength insertItemBefore ( in SVGLength newItem, in unsigned long index )
+ raises( DOMException, SVGException );
+ SVGLength replaceItem ( in SVGLength newItem, in unsigned long index )
+ raises( DOMException, SVGException );
+ SVGLength removeItem ( in unsigned long index )
+ raises( DOMException );
+ SVGLength appendItem ( in SVGLength newItem )
+ raises( DOMException, SVGException );
+ };
+
+ interface SVGAnimatedLengthList {
+
+ readonly attribute SVGLengthList baseVal;
+ readonly attribute SVGLengthList animVal;
+ };
+
+ interface SVGAngle {
+
+ // Angle Unit Types
+ const unsigned short SVG_ANGLETYPE_UNKNOWN = 0;
+ const unsigned short SVG_ANGLETYPE_UNSPECIFIED = 1;
+ const unsigned short SVG_ANGLETYPE_DEG = 2;
+ const unsigned short SVG_ANGLETYPE_RAD = 3;
+ const unsigned short SVG_ANGLETYPE_GRAD = 4;
+
+ readonly attribute unsigned short unitType;
+ attribute float value;
+ // raises DOMException on setting
+ attribute float valueInSpecifiedUnits;
+ // raises DOMException on setting
+ attribute DOMString valueAsString;
+ // raises DOMException on setting
+
+ void newValueSpecifiedUnits ( in unsigned short unitType, in float valueInSpecifiedUnits );
+ void convertToSpecifiedUnits ( in unsigned short unitType );
+ };
+
+ interface SVGAnimatedAngle {
+
+ readonly attribute SVGAngle baseVal;
+ readonly attribute SVGAngle animVal;
+ };
+
+ interface SVGColor : css::CSSValue {
+ // Color Types
+ const unsigned short SVG_COLORTYPE_UNKNOWN = 0;
+ const unsigned short SVG_COLORTYPE_RGBCOLOR = 1;
+ const unsigned short SVG_COLORTYPE_RGBCOLOR_ICCCOLOR = 2;
+ const unsigned short SVG_COLORTYPE_CURRENTCOLOR = 3;
+
+ readonly attribute unsigned short colorType;
+ readonly attribute css::RGBColor rgbColor;
+ readonly attribute SVGICCColor iccColor;
+
+ void setRGBColor ( in DOMString rgbColor )
+ raises( SVGException );
+ void setRGBColorICCColor ( in DOMString rgbColor, in DOMString iccColor )
+ raises( SVGException );
+ void setColor ( in unsigned short colorType, in DOMString rgbColor, in DOMString iccColor )
+ raises( SVGException );
+ };
+
+ interface SVGICCColor {
+
+ attribute DOMString colorProfile;
+ // raises DOMException on setting
+ readonly attribute SVGNumberList colors;
+ };
+
+ interface SVGRect {
+
+ attribute float x;
+ // raises DOMException on setting
+ attribute float y;
+ // raises DOMException on setting
+ attribute float width;
+ // raises DOMException on setting
+ attribute float height;
+ // raises DOMException on setting
+ };
+
+ interface SVGAnimatedRect {
+
+ readonly attribute SVGRect baseVal;
+ readonly attribute SVGRect animVal;
+ };
+
+ interface SVGUnitTypes {
+
+ // Unit Types
+ const unsigned short SVG_UNIT_TYPE_UNKNOWN = 0;
+ const unsigned short SVG_UNIT_TYPE_USERSPACEONUSE = 1;
+ const unsigned short SVG_UNIT_TYPE_OBJECTBOUNDINGBOX = 2;
+ };
+
+ interface SVGStylable {
+
+ readonly attribute SVGAnimatedString className;
+ readonly attribute css::CSSStyleDeclaration style;
+
+ css::CSSValue getPresentationAttribute ( in DOMString name );
+ };
+
+ interface SVGLocatable {
+
+ readonly attribute SVGElement nearestViewportElement;
+ readonly attribute SVGElement farthestViewportElement;
+
+ SVGRect getBBox ( );
+ SVGMatrix getCTM ( );
+ SVGMatrix getScreenCTM ( );
+ SVGMatrix getTransformToElement ( in SVGElement element )
+ raises( SVGException );
+ };
+
+ interface SVGTransformable : SVGLocatable {
+ readonly attribute SVGAnimatedTransformList transform;
+ };
+
+ interface SVGTests {
+
+ readonly attribute SVGStringList requiredFeatures;
+ readonly attribute SVGStringList requiredExtensions;
+ readonly attribute SVGStringList systemLanguage;
+
+ boolean hasExtension ( in DOMString extension );
+ };
+
+ interface SVGLangSpace {
+
+ attribute DOMString xmllang;
+ // raises DOMException on setting
+ attribute DOMString xmlspace;
+ // raises DOMException on setting
+ };
+
+ interface SVGExternalResourcesRequired {
+
+ readonly attribute SVGAnimatedBoolean externalResourcesRequired;
+ };
+
+ interface SVGFitToViewBox {
+
+ readonly attribute SVGAnimatedRect viewBox;
+ readonly attribute SVGAnimatedPreserveAspectRatio preserveAspectRatio;
+ };
+
+ interface SVGZoomAndPan {
+
+ // Zoom and Pan Types
+ const unsigned short SVG_ZOOMANDPAN_UNKNOWN = 0;
+ const unsigned short SVG_ZOOMANDPAN_DISABLE = 1;
+ const unsigned short SVG_ZOOMANDPAN_MAGNIFY = 2;
+
+ attribute unsigned short zoomAndPan;
+ // raises DOMException on setting
+ };
+
+ interface SVGViewSpec :
+ SVGZoomAndPan,
+ SVGFitToViewBox {
+
+ readonly attribute SVGTransformList transform;
+ readonly attribute SVGElement viewTarget;
+ readonly attribute DOMString viewBoxString;
+ readonly attribute DOMString preserveAspectRatioString;
+ readonly attribute DOMString transformString;
+ readonly attribute DOMString viewTargetString;
+ };
+
+ interface SVGURIReference {
+
+ readonly attribute SVGAnimatedString href;
+ };
+
+ interface SVGCSSRule : css::CSSRule {
+ // Additional CSS RuleType to support ICC color specifications
+ const unsigned short COLOR_PROFILE_RULE = 7;
+ };
+
+ interface SVGRenderingIntent {
+
+ // Rendering Intent Types
+ const unsigned short RENDERING_INTENT_UNKNOWN = 0;
+ const unsigned short RENDERING_INTENT_AUTO = 1;
+ const unsigned short RENDERING_INTENT_PERCEPTUAL = 2;
+ const unsigned short RENDERING_INTENT_RELATIVE_COLORIMETRIC = 3;
+ const unsigned short RENDERING_INTENT_SATURATION = 4;
+ const unsigned short RENDERING_INTENT_ABSOLUTE_COLORIMETRIC = 5;
+ };
+
+ interface SVGDocument :
+ Document,
+ events::DocumentEvent {
+
+ readonly attribute DOMString title;
+ readonly attribute DOMString referrer;
+ readonly attribute DOMString domain;
+ readonly attribute DOMString URL;
+ readonly attribute SVGSVGElement rootElement;
+ };
+
+ interface SVGSVGElement :
+ SVGElement,
+ SVGTests,
+ SVGLangSpace,
+ SVGExternalResourcesRequired,
+ SVGStylable,
+ SVGLocatable,
+ SVGFitToViewBox,
+ SVGZoomAndPan,
+ events::EventTarget,
+ events::DocumentEvent,
+ css::ViewCSS,
+ css::DocumentCSS {
+
+ readonly attribute SVGAnimatedLength x;
+ readonly attribute SVGAnimatedLength y;
+ readonly attribute SVGAnimatedLength width;
+ readonly attribute SVGAnimatedLength height;
+ attribute DOMString contentScriptType;
+ // raises DOMException on setting
+ attribute DOMString contentStyleType;
+ // raises DOMException on setting
+ readonly attribute SVGRect viewport;
+ readonly attribute float pixelUnitToMillimeterX;
+ readonly attribute float pixelUnitToMillimeterY;
+ readonly attribute float screenPixelToMillimeterX;
+ readonly attribute float screenPixelToMillimeterY;
+ attribute boolean useCurrentView;
+ // raises DOMException on setting
+ readonly attribute SVGViewSpec currentView;
+ attribute float currentScale;
+ // raises DOMException on setting
+ readonly attribute SVGPoint currentTranslate;
+
+ unsigned long suspendRedraw ( in unsigned long max_wait_milliseconds );
+ void unsuspendRedraw ( in unsigned long suspend_handle_id )
+ raises( DOMException );
+ void unsuspendRedrawAll ( );
+ void forceRedraw ( );
+ void pauseAnimations ( );
+ void unpauseAnimations ( );
+ boolean animationsPaused ( );
+ float getCurrentTime ( );
+ void setCurrentTime ( in float seconds );
+ NodeList getIntersectionList ( in SVGRect rect, in SVGElement referenceElement );
+ NodeList getEnclosureList ( in SVGRect rect, in SVGElement referenceElement );
+ boolean checkIntersection ( in SVGElement element, in SVGRect rect );
+ boolean checkEnclosure ( in SVGElement element, in SVGRect rect );
+ void deselectAll ( );
+ SVGNumber createSVGNumber ( );
+ SVGLength createSVGLength ( );
+ SVGAngle createSVGAngle ( );
+ SVGPoint createSVGPoint ( );
+ SVGMatrix createSVGMatrix ( );
+ SVGRect createSVGRect ( );
+ SVGTransform createSVGTransform ( );
+ SVGTransform createSVGTransformFromMatrix ( in SVGMatrix matrix );
+ Element getElementById ( in DOMString elementId );
+ };
+
+ interface SVGGElement :
+ SVGElement,
+ SVGTests,
+ SVGLangSpace,
+ SVGExternalResourcesRequired,
+ SVGStylable,
+ SVGTransformable,
+ events::EventTarget {};
+
+ interface SVGDefsElement :
+ SVGElement,
+ SVGTests,
+ SVGLangSpace,
+ SVGExternalResourcesRequired,
+ SVGStylable,
+ SVGTransformable,
+ events::EventTarget {};
+
+ interface SVGDescElement :
+ SVGElement,
+ SVGLangSpace,
+ SVGStylable {};
+
+ interface SVGTitleElement :
+ SVGElement,
+ SVGLangSpace,
+ SVGStylable {};
+
+ interface SVGSymbolElement :
+ SVGElement,
+ SVGLangSpace,
+ SVGExternalResourcesRequired,
+ SVGStylable,
+ SVGFitToViewBox,
+ events::EventTarget {};
+
+ interface SVGUseElement :
+ SVGElement,
+ SVGURIReference,
+ SVGTests,
+ SVGLangSpace,
+ SVGExternalResourcesRequired,
+ SVGStylable,
+ SVGTransformable,
+ events::EventTarget {
+
+ readonly attribute SVGAnimatedLength x;
+ readonly attribute SVGAnimatedLength y;
+ readonly attribute SVGAnimatedLength width;
+ readonly attribute SVGAnimatedLength height;
+ readonly attribute SVGElementInstance instanceRoot;
+ readonly attribute SVGElementInstance animatedInstanceRoot;
+ };
+
+ interface SVGElementInstance : events::EventTarget {
+ readonly attribute SVGElement correspondingElement;
+ readonly attribute SVGUseElement correspondingUseElement;
+ readonly attribute SVGElementInstance parentNode;
+ readonly attribute SVGElementInstanceList childNodes;
+ readonly attribute SVGElementInstance firstChild;
+ readonly attribute SVGElementInstance lastChild;
+ readonly attribute SVGElementInstance previousSibling;
+ readonly attribute SVGElementInstance nextSibling;
+ };
+
+ interface SVGElementInstanceList {
+
+ readonly attribute unsigned long length;
+
+ SVGElementInstance item ( in unsigned long index );
+ };
+
+ interface SVGImageElement :
+ SVGElement,
+ SVGURIReference,
+ SVGTests,
+ SVGLangSpace,
+ SVGExternalResourcesRequired,
+ SVGStylable,
+ SVGTransformable,
+ events::EventTarget {
+
+ readonly attribute SVGAnimatedLength x;
+ readonly attribute SVGAnimatedLength y;
+ readonly attribute SVGAnimatedLength width;
+ readonly attribute SVGAnimatedLength height;
+ readonly attribute SVGAnimatedPreserveAspectRatio preserveAspectRatio;
+ };
+
+ interface SVGSwitchElement :
+ SVGElement,
+ SVGTests,
+ SVGLangSpace,
+ SVGExternalResourcesRequired,
+ SVGStylable,
+ SVGTransformable,
+ events::EventTarget {};
+
+ interface GetSVGDocument {
+
+ SVGDocument getSVGDocument ( )
+ raises( DOMException );
+ };
+
+ interface SVGStyleElement : SVGElement {
+ attribute DOMString xmlspace;
+ // raises DOMException on setting
+ attribute DOMString type;
+ // raises DOMException on setting
+ attribute DOMString media;
+ // raises DOMException on setting
+ attribute DOMString title;
+ // raises DOMException on setting
+ };
+
+ interface SVGPoint {
+
+ attribute float x;
+ // raises DOMException on setting
+ attribute float y;
+ // raises DOMException on setting
+
+ SVGPoint matrixTransform ( in SVGMatrix matrix );
+ };
+
+ interface SVGPointList {
+
+ readonly attribute unsigned long numberOfItems;
+
+ void clear ( )
+ raises( DOMException );
+ SVGPoint initialize ( in SVGPoint newItem )
+ raises( DOMException, SVGException );
+ SVGPoint getItem ( in unsigned long index )
+ raises( DOMException );
+ SVGPoint insertItemBefore ( in SVGPoint newItem, in unsigned long index )
+ raises( DOMException, SVGException );
+ SVGPoint replaceItem ( in SVGPoint newItem, in unsigned long index )
+ raises( DOMException, SVGException );
+ SVGPoint removeItem ( in unsigned long index )
+ raises( DOMException );
+ SVGPoint appendItem ( in SVGPoint newItem )
+ raises( DOMException, SVGException );
+ };
+
+ interface SVGMatrix {
+
+ attribute float a;
+ // raises DOMException on setting
+ attribute float b;
+ // raises DOMException on setting
+ attribute float c;
+ // raises DOMException on setting
+ attribute float d;
+ // raises DOMException on setting
+ attribute float e;
+ // raises DOMException on setting
+ attribute float f;
+ // raises DOMException on setting
+
+ SVGMatrix multiply ( in SVGMatrix secondMatrix );
+ SVGMatrix inverse ( )
+ raises( SVGException );
+ SVGMatrix translate ( in float x, in float y );
+ SVGMatrix scale ( in float scaleFactor );
+ SVGMatrix scaleNonUniform ( in float scaleFactorX, in float scaleFactorY );
+ SVGMatrix rotate ( in float angle );
+ SVGMatrix rotateFromVector ( in float x, in float y )
+ raises( SVGException );
+ SVGMatrix flipX ( );
+ SVGMatrix flipY ( );
+ SVGMatrix skewX ( in float angle );
+ SVGMatrix skewY ( in float angle );
+ };
+
+ interface SVGTransform {
+
+ // Transform Types
+ const unsigned short SVG_TRANSFORM_UNKNOWN = 0;
+ const unsigned short SVG_TRANSFORM_MATRIX = 1;
+ const unsigned short SVG_TRANSFORM_TRANSLATE = 2;
+ const unsigned short SVG_TRANSFORM_SCALE = 3;
+ const unsigned short SVG_TRANSFORM_ROTATE = 4;
+ const unsigned short SVG_TRANSFORM_SKEWX = 5;
+ const unsigned short SVG_TRANSFORM_SKEWY = 6;
+
+ readonly attribute unsigned short type;
+ readonly attribute SVGMatrix matrix;
+ readonly attribute float angle;
+
+ void setMatrix ( in SVGMatrix matrix );
+ void setTranslate ( in float tx, in float ty );
+ void setScale ( in float sx, in float sy );
+ void setRotate ( in float angle, in float cx, in float cy );
+ void setSkewX ( in float angle );
+ void setSkewY ( in float angle );
+ };
+
+ interface SVGTransformList {
+
+ readonly attribute unsigned long numberOfItems;
+
+ void clear ( )
+ raises( DOMException );
+ SVGTransform initialize ( in SVGTransform newItem )
+ raises( DOMException, SVGException );
+ SVGTransform getItem ( in unsigned long index )
+ raises( DOMException );
+ SVGTransform insertItemBefore ( in SVGTransform newItem, in unsigned long index )
+ raises( DOMException, SVGException );
+ SVGTransform replaceItem ( in SVGTransform newItem, in unsigned long index )
+ raises( DOMException, SVGException );
+ SVGTransform removeItem ( in unsigned long index )
+ raises( DOMException );
+ SVGTransform appendItem ( in SVGTransform newItem )
+ raises( DOMException, SVGException );
+ SVGTransform createSVGTransformFromMatrix ( in SVGMatrix matrix );
+ SVGTransform consolidate ( );
+ };
+
+ interface SVGAnimatedTransformList {
+
+ readonly attribute SVGTransformList baseVal;
+ readonly attribute SVGTransformList animVal;
+ };
+
+ interface SVGPreserveAspectRatio {
+
+ // Alignment Types
+ const unsigned short SVG_PRESERVEASPECTRATIO_UNKNOWN = 0;
+ const unsigned short SVG_PRESERVEASPECTRATIO_NONE = 1;
+ const unsigned short SVG_PRESERVEASPECTRATIO_XMINYMIN = 2;
+ const unsigned short SVG_PRESERVEASPECTRATIO_XMIDYMIN = 3;
+ const unsigned short SVG_PRESERVEASPECTRATIO_XMAXYMIN = 4;
+ const unsigned short SVG_PRESERVEASPECTRATIO_XMINYMID = 5;
+ const unsigned short SVG_PRESERVEASPECTRATIO_XMIDYMID = 6;
+ const unsigned short SVG_PRESERVEASPECTRATIO_XMAXYMID = 7;
+ const unsigned short SVG_PRESERVEASPECTRATIO_XMINYMAX = 8;
+ const unsigned short SVG_PRESERVEASPECTRATIO_XMIDYMAX = 9;
+ const unsigned short SVG_PRESERVEASPECTRATIO_XMAXYMAX = 10;
+ // Meet-or-slice Types
+ const unsigned short SVG_MEETORSLICE_UNKNOWN = 0;
+ const unsigned short SVG_MEETORSLICE_MEET = 1;
+ const unsigned short SVG_MEETORSLICE_SLICE = 2;
+
+ attribute unsigned short align;
+ // raises DOMException on setting
+ attribute unsigned short meetOrSlice;
+ // raises DOMException on setting
+ };
+
+ interface SVGAnimatedPreserveAspectRatio {
+
+ readonly attribute SVGPreserveAspectRatio baseVal;
+ readonly attribute SVGPreserveAspectRatio animVal;
+ };
+
+ interface SVGPathSeg {
+
+ // Path Segment Types
+ const unsigned short PATHSEG_UNKNOWN = 0;
+ const unsigned short PATHSEG_CLOSEPATH = 1;
+ const unsigned short PATHSEG_MOVETO_ABS = 2;
+ const unsigned short PATHSEG_MOVETO_REL = 3;
+ const unsigned short PATHSEG_LINETO_ABS = 4;
+ const unsigned short PATHSEG_LINETO_REL = 5;
+ const unsigned short PATHSEG_CURVETO_CUBIC_ABS = 6;
+ const unsigned short PATHSEG_CURVETO_CUBIC_REL = 7;
+ const unsigned short PATHSEG_CURVETO_QUADRATIC_ABS = 8;
+ const unsigned short PATHSEG_CURVETO_QUADRATIC_REL = 9;
+ const unsigned short PATHSEG_ARC_ABS = 10;
+ const unsigned short PATHSEG_ARC_REL = 11;
+ const unsigned short PATHSEG_LINETO_HORIZONTAL_ABS = 12;
+ const unsigned short PATHSEG_LINETO_HORIZONTAL_REL = 13;
+ const unsigned short PATHSEG_LINETO_VERTICAL_ABS = 14;
+ const unsigned short PATHSEG_LINETO_VERTICAL_REL = 15;
+ const unsigned short PATHSEG_CURVETO_CUBIC_SMOOTH_ABS = 16;
+ const unsigned short PATHSEG_CURVETO_CUBIC_SMOOTH_REL = 17;
+ const unsigned short PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS = 18;
+ const unsigned short PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL = 19;
+
+ readonly attribute unsigned short pathSegType;
+ readonly attribute DOMString pathSegTypeAsLetter;
+ };
+
+ interface SVGPathSegClosePath : SVGPathSeg {};
+
+ interface SVGPathSegMovetoAbs : SVGPathSeg {
+ attribute float x;
+ // raises DOMException on setting
+ attribute float y;
+ // raises DOMException on setting
+ };
+
+ interface SVGPathSegMovetoRel : SVGPathSeg {
+ attribute float x;
+ // raises DOMException on setting
+ attribute float y;
+ // raises DOMException on setting
+ };
+
+ interface SVGPathSegLinetoAbs : SVGPathSeg {
+ attribute float x;
+ // raises DOMException on setting
+ attribute float y;
+ // raises DOMException on setting
+ };
+
+ interface SVGPathSegLinetoRel : SVGPathSeg {
+ attribute float x;
+ // raises DOMException on setting
+ attribute float y;
+ // raises DOMException on setting
+ };
+
+ interface SVGPathSegCurvetoCubicAbs : SVGPathSeg {
+ attribute float x;
+ // raises DOMException on setting
+ attribute float y;
+ // raises DOMException on setting
+ attribute float x1;
+ // raises DOMException on setting
+ attribute float y1;
+ // raises DOMException on setting
+ attribute float x2;
+ // raises DOMException on setting
+ attribute float y2;
+ // raises DOMException on setting
+ };
+
+ interface SVGPathSegCurvetoCubicRel : SVGPathSeg {
+ attribute float x;
+ // raises DOMException on setting
+ attribute float y;
+ // raises DOMException on setting
+ attribute float x1;
+ // raises DOMException on setting
+ attribute float y1;
+ // raises DOMException on setting
+ attribute float x2;
+ // raises DOMException on setting
+ attribute float y2;
+ // raises DOMException on setting
+ };
+
+ interface SVGPathSegCurvetoQuadraticAbs : SVGPathSeg {
+ attribute float x;
+ // raises DOMException on setting
+ attribute float y;
+ // raises DOMException on setting
+ attribute float x1;
+ // raises DOMException on setting
+ attribute float y1;
+ // raises DOMException on setting
+ };
+
+ interface SVGPathSegCurvetoQuadraticRel : SVGPathSeg {
+ attribute float x;
+ // raises DOMException on setting
+ attribute float y;
+ // raises DOMException on setting
+ attribute float x1;
+ // raises DOMException on setting
+ attribute float y1;
+ // raises DOMException on setting
+ };
+
+ interface SVGPathSegArcAbs : SVGPathSeg {
+ attribute float x;
+ // raises DOMException on setting
+ attribute float y;
+ // raises DOMException on setting
+ attribute float r1;
+ // raises DOMException on setting
+ attribute float r2;
+ // raises DOMException on setting
+ attribute float angle;
+ // raises DOMException on setting
+ attribute boolean largeArcFlag;
+ // raises DOMException on setting
+ attribute boolean sweepFlag;
+ // raises DOMException on setting
+ };
+
+ interface SVGPathSegArcRel : SVGPathSeg {
+ attribute float x;
+ // raises DOMException on setting
+ attribute float y;
+ // raises DOMException on setting
+ attribute float r1;
+ // raises DOMException on setting
+ attribute float r2;
+ // raises DOMException on setting
+ attribute float angle;
+ // raises DOMException on setting
+ attribute boolean largeArcFlag;
+ // raises DOMException on setting
+ attribute boolean sweepFlag;
+ // raises DOMException on setting
+ };
+
+ interface SVGPathSegLinetoHorizontalAbs : SVGPathSeg {
+ attribute float x;
+ // raises DOMException on setting
+ };
+
+ interface SVGPathSegLinetoHorizontalRel : SVGPathSeg {
+ attribute float x;
+ // raises DOMException on setting
+ };
+
+ interface SVGPathSegLinetoVerticalAbs : SVGPathSeg {
+ attribute float y;
+ // raises DOMException on setting
+ };
+
+ interface SVGPathSegLinetoVerticalRel : SVGPathSeg {
+ attribute float y;
+ // raises DOMException on setting
+ };
+
+ interface SVGPathSegCurvetoCubicSmoothAbs : SVGPathSeg {
+ attribute float x;
+ // raises DOMException on setting
+ attribute float y;
+ // raises DOMException on setting
+ attribute float x2;
+ // raises DOMException on setting
+ attribute float y2;
+ // raises DOMException on setting
+ };
+
+ interface SVGPathSegCurvetoCubicSmoothRel : SVGPathSeg {
+ attribute float x;
+ // raises DOMException on setting
+ attribute float y;
+ // raises DOMException on setting
+ attribute float x2;
+ // raises DOMException on setting
+ attribute float y2;
+ // raises DOMException on setting
+ };
+
+ interface SVGPathSegCurvetoQuadraticSmoothAbs : SVGPathSeg {
+ attribute float x;
+ // raises DOMException on setting
+ attribute float y;
+ // raises DOMException on setting
+ };
+
+ interface SVGPathSegCurvetoQuadraticSmoothRel : SVGPathSeg {
+ attribute float x;
+ // raises DOMException on setting
+ attribute float y;
+ // raises DOMException on setting
+ };
+
+ interface SVGPathSegList {
+
+ readonly attribute unsigned long numberOfItems;
+
+ void clear ( )
+ raises( DOMException );
+ SVGPathSeg initialize ( in SVGPathSeg newItem )
+ raises( DOMException, SVGException );
+ SVGPathSeg getItem ( in unsigned long index )
+ raises( DOMException );
+ SVGPathSeg insertItemBefore ( in SVGPathSeg newItem, in unsigned long index )
+ raises( DOMException, SVGException );
+ SVGPathSeg replaceItem ( in SVGPathSeg newItem, in unsigned long index )
+ raises( DOMException, SVGException );
+ SVGPathSeg removeItem ( in unsigned long index )
+ raises( DOMException );
+ SVGPathSeg appendItem ( in SVGPathSeg newItem )
+ raises( DOMException, SVGException );
+ };
+
+ interface SVGAnimatedPathData {
+
+ readonly attribute SVGPathSegList pathSegList;
+ readonly attribute SVGPathSegList normalizedPathSegList;
+ readonly attribute SVGPathSegList animatedPathSegList;
+ readonly attribute SVGPathSegList animatedNormalizedPathSegList;
+ };
+
+ interface SVGPathElement :
+ SVGElement,
+ SVGTests,
+ SVGLangSpace,
+ SVGExternalResourcesRequired,
+ SVGStylable,
+ SVGTransformable,
+ events::EventTarget,
+ SVGAnimatedPathData {
+
+ readonly attribute SVGAnimatedNumber pathLength;
+
+ float getTotalLength ( );
+ SVGPoint getPointAtLength ( in float distance );
+ unsigned long getPathSegAtLength ( in float distance );
+ SVGPathSegClosePath createSVGPathSegClosePath ( );
+ SVGPathSegMovetoAbs createSVGPathSegMovetoAbs ( in float x, in float y );
+ SVGPathSegMovetoRel createSVGPathSegMovetoRel ( in float x, in float y );
+ SVGPathSegLinetoAbs createSVGPathSegLinetoAbs ( in float x, in float y );
+ SVGPathSegLinetoRel createSVGPathSegLinetoRel ( in float x, in float y );
+ SVGPathSegCurvetoCubicAbs createSVGPathSegCurvetoCubicAbs ( in float x, in float y, in float x1, in float y1, in float x2, in float y2 );
+ SVGPathSegCurvetoCubicRel createSVGPathSegCurvetoCubicRel ( in float x, in float y, in float x1, in float y1, in float x2, in float y2 );
+ SVGPathSegCurvetoQuadraticAbs createSVGPathSegCurvetoQuadraticAbs ( in float x, in float y, in float x1, in float y1 );
+ SVGPathSegCurvetoQuadraticRel createSVGPathSegCurvetoQuadraticRel ( in float x, in float y, in float x1, in float y1 );
+ SVGPathSegArcAbs createSVGPathSegArcAbs ( in float x, in float y, in float r1, in float r2, in float angle, in boolean largeArcFlag, in boolean sweepFlag );
+ SVGPathSegArcRel createSVGPathSegArcRel ( in float x, in float y, in float r1, in float r2, in float angle, in boolean largeArcFlag, in boolean sweepFlag );
+ SVGPathSegLinetoHorizontalAbs createSVGPathSegLinetoHorizontalAbs ( in float x );
+ SVGPathSegLinetoHorizontalRel createSVGPathSegLinetoHorizontalRel ( in float x );
+ SVGPathSegLinetoVerticalAbs createSVGPathSegLinetoVerticalAbs ( in float y );
+ SVGPathSegLinetoVerticalRel createSVGPathSegLinetoVerticalRel ( in float y );
+ SVGPathSegCurvetoCubicSmoothAbs createSVGPathSegCurvetoCubicSmoothAbs ( in float x, in float y, in float x2, in float y2 );
+ SVGPathSegCurvetoCubicSmoothRel createSVGPathSegCurvetoCubicSmoothRel ( in float x, in float y, in float x2, in float y2 );
+ SVGPathSegCurvetoQuadraticSmoothAbs createSVGPathSegCurvetoQuadraticSmoothAbs ( in float x, in float y );
+ SVGPathSegCurvetoQuadraticSmoothRel createSVGPathSegCurvetoQuadraticSmoothRel ( in float x, in float y );
+ };
+
+ interface SVGRectElement :
+ SVGElement,
+ SVGTests,
+ SVGLangSpace,
+ SVGExternalResourcesRequired,
+ SVGStylable,
+ SVGTransformable,
+ events::EventTarget {
+
+ readonly attribute SVGAnimatedLength x;
+ readonly attribute SVGAnimatedLength y;
+ readonly attribute SVGAnimatedLength width;
+ readonly attribute SVGAnimatedLength height;
+ readonly attribute SVGAnimatedLength rx;
+ readonly attribute SVGAnimatedLength ry;
+ };
+
+ interface SVGCircleElement :
+ SVGElement,
+ SVGTests,
+ SVGLangSpace,
+ SVGExternalResourcesRequired,
+ SVGStylable,
+ SVGTransformable,
+ events::EventTarget {
+
+ readonly attribute SVGAnimatedLength cx;
+ readonly attribute SVGAnimatedLength cy;
+ readonly attribute SVGAnimatedLength r;
+ };
+
+ interface SVGEllipseElement :
+ SVGElement,
+ SVGTests,
+ SVGLangSpace,
+ SVGExternalResourcesRequired,
+ SVGStylable,
+ SVGTransformable,
+ events::EventTarget {
+
+ readonly attribute SVGAnimatedLength cx;
+ readonly attribute SVGAnimatedLength cy;
+ readonly attribute SVGAnimatedLength rx;
+ readonly attribute SVGAnimatedLength ry;
+ };
+
+ interface SVGLineElement :
+ SVGElement,
+ SVGTests,
+ SVGLangSpace,
+ SVGExternalResourcesRequired,
+ SVGStylable,
+ SVGTransformable,
+ events::EventTarget {
+
+ readonly attribute SVGAnimatedLength x1;
+ readonly attribute SVGAnimatedLength y1;
+ readonly attribute SVGAnimatedLength x2;
+ readonly attribute SVGAnimatedLength y2;
+ };
+
+ interface SVGAnimatedPoints {
+
+ readonly attribute SVGPointList points;
+ readonly attribute SVGPointList animatedPoints;
+ };
+
+ interface SVGPolylineElement :
+ SVGElement,
+ SVGTests,
+ SVGLangSpace,
+ SVGExternalResourcesRequired,
+ SVGStylable,
+ SVGTransformable,
+ events::EventTarget,
+ SVGAnimatedPoints {};
+
+ interface SVGPolygonElement :
+ SVGElement,
+ SVGTests,
+ SVGLangSpace,
+ SVGExternalResourcesRequired,
+ SVGStylable,
+ SVGTransformable,
+ events::EventTarget,
+ SVGAnimatedPoints {};
+
+ interface SVGTextContentElement :
+ SVGElement,
+ SVGTests,
+ SVGLangSpace,
+ SVGExternalResourcesRequired,
+ SVGStylable,
+ events::EventTarget {
+
+ // lengthAdjust Types
+ const unsigned short LENGTHADJUST_UNKNOWN = 0;
+ const unsigned short LENGTHADJUST_SPACING = 1;
+ const unsigned short LENGTHADJUST_SPACINGANDGLYPHS = 2;
+
+ readonly attribute SVGAnimatedLength textLength;
+ readonly attribute SVGAnimatedEnumeration lengthAdjust;
+
+ long getNumberOfChars ( );
+ float getComputedTextLength ( );
+ float getSubStringLength ( in unsigned long charnum, in unsigned long nchars )
+ raises( DOMException );
+ SVGPoint getStartPositionOfChar ( in unsigned long charnum )
+ raises( DOMException );
+ SVGPoint getEndPositionOfChar ( in unsigned long charnum )
+ raises( DOMException );
+ SVGRect getExtentOfChar ( in unsigned long charnum )
+ raises( DOMException );
+ float getRotationOfChar ( in unsigned long charnum )
+ raises( DOMException );
+ long getCharNumAtPosition ( in SVGPoint point );
+ void selectSubString ( in unsigned long charnum, in unsigned long nchars )
+ raises( DOMException );
+ };
+
+ interface SVGTextPositioningElement : SVGTextContentElement {
+ readonly attribute SVGAnimatedLengthList x;
+ readonly attribute SVGAnimatedLengthList y;
+ readonly attribute SVGAnimatedLengthList dx;
+ readonly attribute SVGAnimatedLengthList dy;
+ readonly attribute SVGAnimatedNumberList rotate;
+ };
+
+ interface SVGTextElement :
+ SVGTextPositioningElement,
+ SVGTransformable {};
+
+ interface SVGTSpanElement : SVGTextPositioningElement {};
+
+ interface SVGTRefElement :
+ SVGTextPositioningElement,
+ SVGURIReference {};
+
+ interface SVGTextPathElement :
+ SVGTextContentElement,
+ SVGURIReference {
+
+ // textPath Method Types
+ const unsigned short TEXTPATH_METHODTYPE_UNKNOWN = 0;
+ const unsigned short TEXTPATH_METHODTYPE_ALIGN = 1;
+ const unsigned short TEXTPATH_METHODTYPE_STRETCH = 2;
+ // textPath Spacing Types
+ const unsigned short TEXTPATH_SPACINGTYPE_UNKNOWN = 0;
+ const unsigned short TEXTPATH_SPACINGTYPE_AUTO = 1;
+ const unsigned short TEXTPATH_SPACINGTYPE_EXACT = 2;
+
+ readonly attribute SVGAnimatedLength startOffset;
+ readonly attribute SVGAnimatedEnumeration method;
+ readonly attribute SVGAnimatedEnumeration spacing;
+ };
+
+ interface SVGAltGlyphElement :
+ SVGTextPositioningElement,
+ SVGURIReference {
+
+ attribute DOMString glyphRef;
+ // raises DOMException on setting
+ attribute DOMString format;
+ // raises DOMException on setting
+ };
+
+ interface SVGAltGlyphDefElement : SVGElement {};
+
+ interface SVGAltGlyphItemElement : SVGElement {};
+
+ interface SVGGlyphRefElement :
+ SVGElement,
+ SVGURIReference,
+ SVGStylable {
+
+ attribute DOMString glyphRef;
+ // raises DOMException on setting
+ attribute DOMString format;
+ // raises DOMException on setting
+ attribute float x;
+ // raises DOMException on setting
+ attribute float y;
+ // raises DOMException on setting
+ attribute float dx;
+ // raises DOMException on setting
+ attribute float dy;
+ // raises DOMException on setting
+ };
+
+ interface SVGPaint : SVGColor {
+ // Paint Types
+ const unsigned short SVG_PAINTTYPE_UNKNOWN = 0;
+ const unsigned short SVG_PAINTTYPE_RGBCOLOR = 1;
+ const unsigned short SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR = 2;
+ const unsigned short SVG_PAINTTYPE_NONE = 101;
+ const unsigned short SVG_PAINTTYPE_CURRENTCOLOR = 102;
+ const unsigned short SVG_PAINTTYPE_URI_NONE = 103;
+ const unsigned short SVG_PAINTTYPE_URI_CURRENTCOLOR = 104;
+ const unsigned short SVG_PAINTTYPE_URI_RGBCOLOR = 105;
+ const unsigned short SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR = 106;
+ const unsigned short SVG_PAINTTYPE_URI = 107;
+
+ readonly attribute unsigned short paintType;
+ readonly attribute DOMString uri;
+
+ void setUri ( in DOMString uri );
+ void setPaint ( in unsigned short paintType, in DOMString uri, in DOMString rgbColor, in DOMString iccColor )
+ raises( SVGException );
+ };
+
+ interface SVGMarkerElement :
+ SVGElement,
+ SVGLangSpace,
+ SVGExternalResourcesRequired,
+ SVGStylable,
+ SVGFitToViewBox {
+
+ // Marker Unit Types
+ const unsigned short SVG_MARKERUNITS_UNKNOWN = 0;
+ const unsigned short SVG_MARKERUNITS_USERSPACEONUSE = 1;
+ const unsigned short SVG_MARKERUNITS_STROKEWIDTH = 2;
+ // Marker Orientation Types
+ const unsigned short SVG_MARKER_ORIENT_UNKNOWN = 0;
+ const unsigned short SVG_MARKER_ORIENT_AUTO = 1;
+ const unsigned short SVG_MARKER_ORIENT_ANGLE = 2;
+
+ readonly attribute SVGAnimatedLength refX;
+ readonly attribute SVGAnimatedLength refY;
+ readonly attribute SVGAnimatedEnumeration markerUnits;
+ readonly attribute SVGAnimatedLength markerWidth;
+ readonly attribute SVGAnimatedLength markerHeight;
+ readonly attribute SVGAnimatedEnumeration orientType;
+ readonly attribute SVGAnimatedAngle orientAngle;
+
+ void setOrientToAuto ( );
+ void setOrientToAngle ( in SVGAngle angle );
+ };
+
+ interface SVGColorProfileElement :
+ SVGElement,
+ SVGURIReference,
+ SVGRenderingIntent {
+
+ attribute DOMString local;
+ // raises DOMException on setting
+ attribute DOMString name;
+ // raises DOMException on setting
+ attribute unsigned short renderingIntent;
+ // raises DOMException on setting
+ };
+
+ interface SVGColorProfileRule :
+ SVGCSSRule,
+ SVGRenderingIntent {
+
+ attribute DOMString src;
+ // raises DOMException on setting
+ attribute DOMString name;
+ // raises DOMException on setting
+ attribute unsigned short renderingIntent;
+ // raises DOMException on setting
+ };
+
+ interface SVGGradientElement :
+ SVGElement,
+ SVGURIReference,
+ SVGExternalResourcesRequired,
+ SVGStylable,
+ SVGUnitTypes {
+
+ // Spread Method Types
+ const unsigned short SVG_SPREADMETHOD_UNKNOWN = 0;
+ const unsigned short SVG_SPREADMETHOD_PAD = 1;
+ const unsigned short SVG_SPREADMETHOD_REFLECT = 2;
+ const unsigned short SVG_SPREADMETHOD_REPEAT = 3;
+
+ readonly attribute SVGAnimatedEnumeration gradientUnits;
+ readonly attribute SVGAnimatedTransformList gradientTransform;
+ readonly attribute SVGAnimatedEnumeration spreadMethod;
+ };
+
+ interface SVGLinearGradientElement : SVGGradientElement {
+ readonly attribute SVGAnimatedLength x1;
+ readonly attribute SVGAnimatedLength y1;
+ readonly attribute SVGAnimatedLength x2;
+ readonly attribute SVGAnimatedLength y2;
+ };
+
+ interface SVGRadialGradientElement : SVGGradientElement {
+ readonly attribute SVGAnimatedLength cx;
+ readonly attribute SVGAnimatedLength cy;
+ readonly attribute SVGAnimatedLength r;
+ readonly attribute SVGAnimatedLength fx;
+ readonly attribute SVGAnimatedLength fy;
+ };
+
+ interface SVGStopElement :
+ SVGElement,
+ SVGStylable {
+
+ readonly attribute SVGAnimatedNumber offset;
+ };
+
+ interface SVGPatternElement :
+ SVGElement,
+ SVGURIReference,
+ SVGTests,
+ SVGLangSpace,
+ SVGExternalResourcesRequired,
+ SVGStylable,
+ SVGFitToViewBox,
+ SVGUnitTypes {
+
+ readonly attribute SVGAnimatedEnumeration patternUnits;
+ readonly attribute SVGAnimatedEnumeration patternContentUnits;
+ readonly attribute SVGAnimatedTransformList patternTransform;
+ readonly attribute SVGAnimatedLength x;
+ readonly attribute SVGAnimatedLength y;
+ readonly attribute SVGAnimatedLength width;
+ readonly attribute SVGAnimatedLength height;
+ };
+
+ interface SVGClipPathElement :
+ SVGElement,
+ SVGTests,
+ SVGLangSpace,
+ SVGExternalResourcesRequired,
+ SVGStylable,
+ SVGTransformable,
+ SVGUnitTypes {
+
+ readonly attribute SVGAnimatedEnumeration clipPathUnits;
+ };
+
+ interface SVGMaskElement :
+ SVGElement,
+ SVGTests,
+ SVGLangSpace,
+ SVGExternalResourcesRequired,
+ SVGStylable,
+ SVGUnitTypes {
+
+ readonly attribute SVGAnimatedEnumeration maskUnits;
+ readonly attribute SVGAnimatedEnumeration maskContentUnits;
+ readonly attribute SVGAnimatedLength x;
+ readonly attribute SVGAnimatedLength y;
+ readonly attribute SVGAnimatedLength width;
+ readonly attribute SVGAnimatedLength height;
+ };
+
+ interface SVGFilterElement :
+ SVGElement,
+ SVGURIReference,
+ SVGLangSpace,
+ SVGExternalResourcesRequired,
+ SVGStylable,
+ SVGUnitTypes {
+
+ readonly attribute SVGAnimatedEnumeration filterUnits;
+ readonly attribute SVGAnimatedEnumeration primitiveUnits;
+ readonly attribute SVGAnimatedLength x;
+ readonly attribute SVGAnimatedLength y;
+ readonly attribute SVGAnimatedLength width;
+ readonly attribute SVGAnimatedLength height;
+ readonly attribute SVGAnimatedInteger filterResX;
+ readonly attribute SVGAnimatedInteger filterResY;
+
+ void setFilterRes ( in unsigned long filterResX, in unsigned long filterResY );
+ };
+
+ interface SVGFilterPrimitiveStandardAttributes {
+
+ readonly attribute SVGAnimatedLength x;
+ readonly attribute SVGAnimatedLength y;
+ readonly attribute SVGAnimatedLength width;
+ readonly attribute SVGAnimatedLength height;
+ readonly attribute SVGAnimatedString result;
+ };
+
+ interface SVGFEBlendElement :
+ SVGElement,
+ SVGFilterPrimitiveStandardAttributes {
+
+ // Blend Mode Types
+ const unsigned short SVG_FEBLEND_MODE_UNKNOWN = 0;
+ const unsigned short SVG_FEBLEND_MODE_NORMAL = 1;
+ const unsigned short SVG_FEBLEND_MODE_MULTIPLY = 2;
+ const unsigned short SVG_FEBLEND_MODE_SCREEN = 3;
+ const unsigned short SVG_FEBLEND_MODE_DARKEN = 4;
+ const unsigned short SVG_FEBLEND_MODE_LIGHTEN = 5;
+
+ readonly attribute SVGAnimatedString in1;
+ readonly attribute SVGAnimatedString in2;
+ readonly attribute SVGAnimatedEnumeration mode;
+ };
+
+ interface SVGFEColorMatrixElement :
+ SVGElement,
+ SVGFilterPrimitiveStandardAttributes {
+
+ // Color Matrix Types
+ const unsigned short SVG_FECOLORMATRIX_TYPE_UNKNOWN = 0;
+ const unsigned short SVG_FECOLORMATRIX_TYPE_MATRIX = 1;
+ const unsigned short SVG_FECOLORMATRIX_TYPE_SATURATE = 2;
+ const unsigned short SVG_FECOLORMATRIX_TYPE_HUEROTATE = 3;
+ const unsigned short SVG_FECOLORMATRIX_TYPE_LUMINANCETOALPHA = 4;
+
+ readonly attribute SVGAnimatedString in1;
+ readonly attribute SVGAnimatedEnumeration type;
+ readonly attribute SVGAnimatedNumberList values;
+ };
+
+ interface SVGFEComponentTransferElement :
+ SVGElement,
+ SVGFilterPrimitiveStandardAttributes {
+
+ readonly attribute SVGAnimatedString in1;
+ };
+
+ interface SVGComponentTransferFunctionElement : SVGElement {
+ // Component Transfer Types
+ const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_UNKNOWN = 0;
+ const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY = 1;
+ const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_TABLE = 2;
+ const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE = 3;
+ const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_LINEAR = 4;
+ const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_GAMMA = 5;
+
+ readonly attribute SVGAnimatedEnumeration type;
+ readonly attribute SVGAnimatedNumberList tableValues;
+ readonly attribute SVGAnimatedNumber slope;
+ readonly attribute SVGAnimatedNumber intercept;
+ readonly attribute SVGAnimatedNumber amplitude;
+ readonly attribute SVGAnimatedNumber exponent;
+ readonly attribute SVGAnimatedNumber offset;
+ };
+
+ interface SVGFEFuncRElement : SVGComponentTransferFunctionElement {};
+
+ interface SVGFEFuncGElement : SVGComponentTransferFunctionElement {};
+
+ interface SVGFEFuncBElement : SVGComponentTransferFunctionElement {};
+
+ interface SVGFEFuncAElement : SVGComponentTransferFunctionElement {};
+
+ interface SVGFECompositeElement :
+ SVGElement,
+ SVGFilterPrimitiveStandardAttributes {
+
+ // Composite Operators
+ const unsigned short SVG_FECOMPOSITE_OPERATOR_UNKNOWN = 0;
+ const unsigned short SVG_FECOMPOSITE_OPERATOR_OVER = 1;
+ const unsigned short SVG_FECOMPOSITE_OPERATOR_IN = 2;
+ const unsigned short SVG_FECOMPOSITE_OPERATOR_OUT = 3;
+ const unsigned short SVG_FECOMPOSITE_OPERATOR_ATOP = 4;
+ const unsigned short SVG_FECOMPOSITE_OPERATOR_XOR = 5;
+ const unsigned short SVG_FECOMPOSITE_OPERATOR_ARITHMETIC = 6;
+
+ readonly attribute SVGAnimatedString in1;
+ readonly attribute SVGAnimatedString in2;
+ readonly attribute SVGAnimatedEnumeration operator;
+ readonly attribute SVGAnimatedNumber k1;
+ readonly attribute SVGAnimatedNumber k2;
+ readonly attribute SVGAnimatedNumber k3;
+ readonly attribute SVGAnimatedNumber k4;
+ };
+
+ interface SVGFEConvolveMatrixElement :
+ SVGElement,
+ SVGFilterPrimitiveStandardAttributes {
+
+ // Edge Mode Values
+ const unsigned short SVG_EDGEMODE_UNKNOWN = 0;
+ const unsigned short SVG_EDGEMODE_DUPLICATE = 1;
+ const unsigned short SVG_EDGEMODE_WRAP = 2;
+ const unsigned short SVG_EDGEMODE_NONE = 3;
+
+ readonly attribute SVGAnimatedInteger orderX;
+ readonly attribute SVGAnimatedInteger orderY;
+ readonly attribute SVGAnimatedNumberList kernelMatrix;
+ readonly attribute SVGAnimatedNumber divisor;
+ readonly attribute SVGAnimatedNumber bias;
+ readonly attribute SVGAnimatedInteger targetX;
+ readonly attribute SVGAnimatedInteger targetY;
+ readonly attribute SVGAnimatedEnumeration edgeMode;
+ readonly attribute SVGAnimatedLength kernelUnitLengthX;
+ readonly attribute SVGAnimatedLength kernelUnitLengthY;
+ readonly attribute SVGAnimatedBoolean preserveAlpha;
+ };
+
+ interface SVGFEDiffuseLightingElement :
+ SVGElement,
+ SVGStylable,
+ SVGFilterPrimitiveStandardAttributes {
+
+ readonly attribute SVGAnimatedString in1;
+ readonly attribute SVGAnimatedNumber surfaceScale;
+ readonly attribute SVGAnimatedNumber diffuseConstant;
+ };
+
+ interface SVGFEDistantLightElement : SVGElement {
+ readonly attribute SVGAnimatedNumber azimuth;
+ readonly attribute SVGAnimatedNumber elevation;
+ };
+
+ interface SVGFEPointLightElement : SVGElement {
+ readonly attribute SVGAnimatedNumber x;
+ readonly attribute SVGAnimatedNumber y;
+ readonly attribute SVGAnimatedNumber z;
+ };
+
+ interface SVGFESpotLightElement : SVGElement {
+ readonly attribute SVGAnimatedNumber x;
+ readonly attribute SVGAnimatedNumber y;
+ readonly attribute SVGAnimatedNumber z;
+ readonly attribute SVGAnimatedNumber pointsAtX;
+ readonly attribute SVGAnimatedNumber pointsAtY;
+ readonly attribute SVGAnimatedNumber pointsAtZ;
+ readonly attribute SVGAnimatedNumber specularExponent;
+ readonly attribute SVGAnimatedNumber limitingConeAngle;
+ };
+
+ interface SVGFEDisplacementMapElement :
+ SVGElement,
+ SVGFilterPrimitiveStandardAttributes {
+
+ // Channel Selectors
+ const unsigned short SVG_CHANNEL_UNKNOWN = 0;
+ const unsigned short SVG_CHANNEL_R = 1;
+ const unsigned short SVG_CHANNEL_G = 2;
+ const unsigned short SVG_CHANNEL_B = 3;
+ const unsigned short SVG_CHANNEL_A = 4;
+
+ readonly attribute SVGAnimatedString in1;
+ readonly attribute SVGAnimatedString in2;
+ readonly attribute SVGAnimatedNumber scale;
+ readonly attribute SVGAnimatedEnumeration xChannelSelector;
+ readonly attribute SVGAnimatedEnumeration yChannelSelector;
+ };
+
+ interface SVGFEFloodElement :
+ SVGElement,
+ SVGStylable,
+ SVGFilterPrimitiveStandardAttributes {
+
+ readonly attribute SVGAnimatedString in1;
+ };
+
+ interface SVGFEGaussianBlurElement :
+ SVGElement,
+ SVGFilterPrimitiveStandardAttributes {
+
+ readonly attribute SVGAnimatedString in1;
+ readonly attribute SVGAnimatedNumber stdDeviationX;
+ readonly attribute SVGAnimatedNumber stdDeviationY;
+
+ void setStdDeviation ( in float stdDeviationX, in float stdDeviationY );
+ };
+
+ interface SVGFEImageElement :
+ SVGElement,
+ SVGURIReference,
+ SVGLangSpace,
+ SVGExternalResourcesRequired,
+ SVGStylable,
+ SVGFilterPrimitiveStandardAttributes {};
+
+ interface SVGFEMergeElement :
+ SVGElement,
+ SVGFilterPrimitiveStandardAttributes {};
+
+ interface SVGFEMergeNodeElement : SVGElement {
+ readonly attribute SVGAnimatedString in1;
+ };
+
+ interface SVGFEMorphologyElement :
+ SVGElement,
+ SVGFilterPrimitiveStandardAttributes {
+
+ // Morphology Operators
+ const unsigned short SVG_MORPHOLOGY_OPERATOR_UNKNOWN = 0;
+ const unsigned short SVG_MORPHOLOGY_OPERATOR_ERODE = 1;
+ const unsigned short SVG_MORPHOLOGY_OPERATOR_DILATE = 2;
+
+ readonly attribute SVGAnimatedString in1;
+ readonly attribute SVGAnimatedEnumeration operator;
+ readonly attribute SVGAnimatedLength radiusX;
+ readonly attribute SVGAnimatedLength radiusY;
+ };
+
+ interface SVGFEOffsetElement :
+ SVGElement,
+ SVGFilterPrimitiveStandardAttributes {
+
+ readonly attribute SVGAnimatedString in1;
+ readonly attribute SVGAnimatedNumber dx;
+ readonly attribute SVGAnimatedNumber dy;
+ };
+
+ interface SVGFESpecularLightingElement :
+ SVGElement,
+ SVGStylable,
+ SVGFilterPrimitiveStandardAttributes {
+
+ readonly attribute SVGAnimatedString in1;
+ readonly attribute SVGAnimatedNumber surfaceScale;
+ readonly attribute SVGAnimatedNumber specularConstant;
+ readonly attribute SVGAnimatedNumber specularExponent;
+ };
+
+ interface SVGFETileElement :
+ SVGElement,
+ SVGFilterPrimitiveStandardAttributes {
+
+ readonly attribute SVGAnimatedString in1;
+ };
+
+ interface SVGFETurbulenceElement :
+ SVGElement,
+ SVGFilterPrimitiveStandardAttributes {
+
+ // Turbulence Types
+ const unsigned short SVG_TURBULENCE_TYPE_UNKNOWN = 0;
+ const unsigned short SVG_TURBULENCE_TYPE_FRACTALNOISE = 1;
+ const unsigned short SVG_TURBULENCE_TYPE_TURBULENCE = 2;
+ // Stitch Options
+ const unsigned short SVG_STITCHTYPE_UNKNOWN = 0;
+ const unsigned short SVG_STITCHTYPE_STITCH = 1;
+ const unsigned short SVG_STITCHTYPE_NOSTITCH = 2;
+
+ readonly attribute SVGAnimatedNumber baseFrequencyX;
+ readonly attribute SVGAnimatedNumber baseFrequencyY;
+ readonly attribute SVGAnimatedInteger numOctaves;
+ readonly attribute SVGAnimatedNumber seed;
+ readonly attribute SVGAnimatedEnumeration stitchTiles;
+ readonly attribute SVGAnimatedEnumeration type;
+ };
+
+ interface SVGCursorElement :
+ SVGElement,
+ SVGURIReference,
+ SVGTests,
+ SVGExternalResourcesRequired {
+
+ readonly attribute SVGAnimatedLength x;
+ readonly attribute SVGAnimatedLength y;
+ };
+
+ interface SVGAElement :
+ SVGElement,
+ SVGURIReference,
+ SVGTests,
+ SVGLangSpace,
+ SVGExternalResourcesRequired,
+ SVGStylable,
+ SVGTransformable,
+ events::EventTarget {
+
+ readonly attribute SVGAnimatedString target;
+ };
+
+ interface SVGViewElement :
+ SVGElement,
+ SVGExternalResourcesRequired,
+ SVGFitToViewBox,
+ SVGZoomAndPan {
+
+ readonly attribute SVGStringList viewTarget;
+ };
+
+ interface SVGScriptElement :
+ SVGElement,
+ SVGURIReference,
+ SVGExternalResourcesRequired {
+
+ attribute DOMString type;
+ // raises DOMException on setting
+ };
+
+ interface SVGEvent : events::Event {};
+
+ interface SVGZoomEvent : events::UIEvent {
+ readonly attribute SVGRect zoomRectScreen;
+ readonly attribute float previousScale;
+ readonly attribute SVGPoint previousTranslate;
+ readonly attribute float newScale;
+ readonly attribute SVGPoint newTranslate;
+ };
+
+ interface SVGAnimationElement :
+ SVGElement,
+ SVGTests,
+ SVGExternalResourcesRequired,
+ smil::ElementTimeControl,
+ events::EventTarget {
+
+ readonly attribute SVGElement targetElement;
+
+ float getStartTime ( );
+ float getCurrentTime ( );
+ float getSimpleDuration ( )
+ raises( DOMException );
+ };
+
+ interface SVGAnimateElement : SVGAnimationElement {};
+
+ interface SVGSetElement : SVGAnimationElement {};
+
+ interface SVGAnimateMotionElement : SVGAnimationElement {};
+
+ interface SVGMPathElement :
+ SVGElement,
+ SVGURIReference,
+ SVGExternalResourcesRequired {};
+
+ interface SVGAnimateColorElement : SVGAnimationElement {};
+
+ interface SVGAnimateTransformElement : SVGAnimationElement {};
+
+ interface SVGFontElement :
+ SVGElement,
+ SVGExternalResourcesRequired,
+ SVGStylable {};
+
+ interface SVGGlyphElement :
+ SVGElement,
+ SVGStylable {};
+
+ interface SVGMissingGlyphElement :
+ SVGElement,
+ SVGStylable {};
+
+ interface SVGHKernElement : SVGElement {};
+
+ interface SVGVKernElement : SVGElement {};
+
+ interface SVGFontFaceElement : SVGElement {};
+
+ interface SVGFontFaceSrcElement : SVGElement {};
+
+ interface SVGFontFaceUriElement : SVGElement {};
+
+ interface SVGFontFaceFormatElement : SVGElement {};
+
+ interface SVGFontFaceNameElement : SVGElement {};
+
+ interface SVGDefinitionSrcElement : SVGElement {};
+
+ interface SVGMetadataElement : SVGElement {};
+
+ interface SVGForeignObjectElement :
+ SVGElement,
+ SVGTests,
+ SVGLangSpace,
+ SVGExternalResourcesRequired,
+ SVGStylable,
+ SVGTransformable,
+ events::EventTarget {
+
+ readonly attribute SVGAnimatedLength x;
+ readonly attribute SVGAnimatedLength y;
+ readonly attribute SVGAnimatedLength width;
+ readonly attribute SVGAnimatedLength height;
+ };
+
+
+};
+
+#endif // _SVG_IDL_ \ No newline at end of file
diff --git a/ksvg/scripts/makecc b/ksvg/scripts/makecc
new file mode 100644
index 00000000..29a28b93
--- /dev/null
+++ b/ksvg/scripts/makecc
@@ -0,0 +1,211 @@
+function printg( a )
+{
+ printf a >> FILENAME ".cc"
+}
+function doFunc( a )
+{
+ gsub("attribute", "", $0)
+ nr = split($0, b, " ")
+ # do method
+ i = 1
+ nrparams = 0
+ rettype = b[1]
+ while ( i < nr && b[i + 1] != "(" )
+ {
+ printg( b[i++] )
+ printg( " " )
+ }
+ printg( clas "::" )
+ method = b[i]
+ while ( i < nr && b[i + 1] != ");" )
+ {
+ if( b[i] == "in" )
+ {
+ if( b[i + 1] != "float" && match( b[i + 1], "unsigned") == 0)
+ {
+ float = "ok"
+ printg( "const " )
+ }
+ else
+ float = "bad"
+ i++
+ while ( i + 1 < nr && b[i + 1] != "in" && b[i + 1] != ");" )
+ {
+ printg( b[i++] " " )
+ }
+ param[nrparams++] = b[i]
+ if( float == "ok" )
+ printg( "&" b[i++] )
+ else
+ printg( b[i++] )
+ if( i < nr ) printg( " " )
+ }
+ else
+ printg( b[i++] )
+ }
+ printg( ")\n{\n" );
+ if( rettype != "void" )
+ {
+ printg( "\tif(!impl) return ; // FIXME\n" )
+ printg( "\treturn impl->" method "(" )
+ }
+ else
+ printg( "\tif(impl)\n\t\timpl->" method "(" )
+ k = 0
+ while( k < nrparams )
+ {
+ printg( param[k++] )
+ if( k < nrparams ) printg( " " )
+ }
+ printg( ");\n" )
+ printg( "}\n\n" );
+}
+
+function doAttr( a, class )
+{
+ sub( ";", "", a)
+ sub( "\r", "", a)
+ gsub("attribute", "", a)
+ nr = split(a, b, " ")
+
+ # do put method
+ printg( "void " clas "::set" )
+ printg( toupper( substr( b[nr], 1, 1) ) )
+ printg( substr( b[nr], 2) "(" )
+ i = 1
+ if( b[i] != "float" && match( b[i], "unsigned") == 0)
+ {
+ float = "ok"
+ printg( "const " )
+ }
+ else
+ float = "bad"
+ while ( i < nr )
+ {
+ printg( b[i++] )
+ if( i < nr ) printg( " " )
+ }
+ if( float == "ok" )
+ printg( " &" b[nr] ")\n{\n" )
+ else
+ printg( " " b[nr] ")\n{\n" )
+ printg( "\tif(impl)\n\t\timpl->set")
+ printg( toupper( substr( b[nr], 1, 1) ) )
+ printg( substr( b[nr], 2) "(" )
+ printg( b[nr] ");\n}\n\n" )
+
+ # do get method
+ i = 1
+ while ( i < nr )
+ {
+ printg( b[i++] " " )
+ }
+ $temp = b[nr]
+ printg( clas "::" $temp "() const\n{\n" )
+ printg( "\tif(!impl) return ; // FIXME\n\treturn impl->" )
+ printg( substr( b[nr], 1) "(" )
+ printg( ");\n}\n\n" )
+}
+
+function doReadonlyAttr( a, class )
+{
+ gsub("readonly attribute", "", $0)
+ nr = split($0, b, " ")
+
+ # do get method
+ i = 1
+ while ( i < nr )
+ {
+ printg( b[i++] " " )
+ }
+ sub( ";", "", b[nr])
+ sub( "\r", "", b[nr])
+ $temp = b[nr]
+ printg( clas "::" $temp "() const\n{\n" )
+ printg( "\tif(!impl) return ; // FIXME\n\treturn impl->" )
+ printg( substr( b[nr], 1) "(" )
+ printg( ");\n}\n\n" )
+}
+{
+ sub("boolean", "bool", $0)
+ if(/interface /)
+ {
+ gsub(" interface ", "", $0)
+ gsub(": ", ": public ", $0)
+ gsub(",", ", public", $0)
+ gsub("{", "\n{", $0)
+ sub( ";", "", $0 )
+ sub( "\r", "", $0 )
+ nr = split($0, b, " ")
+ clas = b[1]
+ #printg( "// " clas " specification\n\n\n" )
+ printg( clas "::" clas "()" )
+ if( nr > 2 )
+ {
+ i = 2
+ sub( ":", " : ", b[i] )
+ while ( i < nr )
+ {
+ sub( "public", "", b[i] )
+ sub( ",", "(), ", b[i] )
+ printg( b[i++] )
+ }
+ printg( "()" )
+ }
+ printg( "\n{\n\timpl = new " clas "Impl();\n\timpl->ref();\n}\n\n" )
+ printg( clas "::" clas "(const " clas " &other)" )
+ if( nr > 2 )
+ {
+ i = 2
+ while ( i < nr )
+ printg( b[i++] )
+
+ printg( "(), impl(0)" )
+ }
+ else
+ printg( " : impl(0)" )
+ printg( "\n{\n\t(*this) = other;\n}\n\n" )
+ printg( clas " &" clas "::operator =(const " clas " &other)\n{\n\tif(impl == other.impl)\n\t\treturn *this;\n\n\tif(impl)\n\t\timpl->deref();\n\n\timpl = other.impl;\n\n\tif(impl)\n\t\timpl->ref();\n\n\treturn *this;\n}\n\n" )
+ printg( clas "::" clas "(" clas "Impl *other)" )
+ if( nr > 2 )
+ {
+ i = 2
+ while ( i < nr )
+ printg( b[i++] )
+
+ printg( "()" )
+ }
+ printg( "\n{\n\timpl = other;\n\tif(impl)\n\t\timpl->ref();\n}\n\n" )
+ printg( clas "::~" clas "()\n{\n\tif(impl)\n\t\timpl->deref();\n}\n\n" )
+ }
+ else if(/readonly attribute/)
+ {
+ doReadonlyAttr( $0, $class )
+ }
+ else if(/attribute /)
+ {
+ doAttr( $0, $class )
+ }
+ else if(/raises/)
+ {
+ }
+ else if(/\)/)
+ {
+ doFunc( $0 );
+ }
+ else if(/};/)
+ {
+ }
+ else if(/ = /)
+ {
+ }
+ #else if(//)
+ #{
+ # # end of class
+ # printf $0;
+ #}
+}
+# END
+# {
+# print "};";
+# }
diff --git a/ksvg/scripts/makeheader b/ksvg/scripts/makeheader
new file mode 100644
index 00000000..f8594690
--- /dev/null
+++ b/ksvg/scripts/makeheader
@@ -0,0 +1,164 @@
+function printg( a )
+{
+ printf a >> FILENAME ".h"
+}
+function doFunc( a )
+{
+ gsub("attribute", "", $0)
+ nr = split($0, b, " ")
+ printg( "\t" )
+ # do method
+ i = 1
+ while ( i < nr && b[i + 1] != "(" )
+ {
+ printg( b[i++] )
+ printg( " " )
+ }
+ while ( i < nr && b[i + 1] != ");" )
+ {
+ if( b[i] == "in" )
+ {
+ if( b[i + 1] != "float" && b[i + 1] != "unsigned" && b[i+1] != "short" && b[i+1] != "bool" )
+ {
+ float = "ok"
+ printg( "const " )
+ }
+ else
+ float = "bad"
+ i++
+ while ( i + 1 < nr && b[i + 1] != "in" && b[i + 1] != ");" )
+ {
+ printg( b[i++] " " )
+ #if( b[ i ] != ");" ) printg( " " )
+ }
+ if( float == "ok" )
+ printg( "&" b[i++] )
+ else
+ printg( b[i++] )
+ if( i < nr ) printg( " " )
+ }
+ else
+ printg( b[i++] )
+ }
+ printg( ");\n" );
+}
+
+function doAttr( a, class )
+{
+ sub( ";", "", a)
+ sub( "\r", "", a)
+ gsub("attribute", "", a)
+ nr = split(a, b, " ")
+
+ # do put method
+ printg( "\tvoid set" )
+ printg( toupper( substr( b[nr], 1, 1) ) )
+ printg( substr( b[nr], 2) "(" )
+ i = 1
+ if( b[i] != "float" && b[i] != "unsigned" && b[i] != "short" && b[i] != "bool" )
+ #if( b[i] != "float" && match( b[i], "unsigned") == 0)
+ {
+ float = "ok"
+ printg( "const " )
+ }
+ else
+ float = "bad"
+ while ( i < nr )
+ {
+ printg( b[i++] )
+ if( i < nr ) printg( " " )
+ }
+ if( float == "ok" )
+ printg( " &" )
+ else
+ printg( " " )
+
+ printg( b[nr] ");\n" )
+
+ # do get method
+ printg("\t")
+ i = 1
+ while ( i < nr )
+ {
+ printg( b[i++] " " )
+ }
+ $temp = b[nr]
+ printg( $temp "() const;" )
+ printg( "\n\n" )
+}
+
+function doReadonlyAttr( a, class )
+{
+ gsub("readonly attribute", "", $0)
+ nr = split($0, b, " ")
+
+ # do get method
+ i = 1
+ printg("\t")
+ while ( i < nr )
+ {
+ printg( b[i++] " " )
+ }
+ sub( ";", "", b[nr])
+ sub( "\r", "", b[nr])
+ $temp = b[nr]
+ printg( $temp "() const;" )
+ printg( "\n" )
+}
+{
+ sub("boolean", "bool", $0); # to shut up frerich :P
+ if(/interface /)
+ {
+ gsub(" interface ", "", $0)
+ gsub(": ", ": public ", $0)
+ gsub(",", ", public", $0)
+ gsub("{", "\n{", $0)
+ sub( ";", "", $0 )
+ sub( "\r", "", $0 )
+ nr = split($0, b, " ")
+ clas = b[1]
+ printg( "class " clas "Impl;" )
+ printg( "\nclass " )
+ printg( $0 )
+ printg( "\npublic:\n" )
+ printg( "\t" clas "();\n" )
+ printg( "\t" clas "(const " clas " &other);\n" )
+ printg( "\t" clas " &operator=(const " clas " &other);\n" )
+ printg( "\t" clas "(" clas "Impl *other);\n" )
+ printg( "\tvirtual ~" clas "();\n\n" )
+ #printg( "\tbool isNull() const { return !impl; }\n" )
+ }
+ else if(/readonly attribute/)
+ {
+ doReadonlyAttr( $0, $class )
+ }
+ else if(/attribute /)
+ {
+ doAttr( $0, $class )
+ }
+ else if(/raises/)
+ {
+ }
+ else if(/\)/)
+ {
+ doFunc( $0 );
+ }
+ else if(/};/)
+ {
+ printg( "private:\n\t" clas "Impl *impl;\n};\n\n" );
+ }
+ else if(/ = /)
+ {
+ sub( "\r", "", $0 )
+ printg( $0 "\n" );
+ }
+ #else if(//)
+ #{
+ # # end of class
+ # printf $0;
+ #}
+}
+# END
+# {
+# print "};";
+# }
diff --git a/ksvg/scripts/makeimpl b/ksvg/scripts/makeimpl
new file mode 100644
index 00000000..fb5ab8f5
--- /dev/null
+++ b/ksvg/scripts/makeimpl
@@ -0,0 +1,440 @@
+function printtoctor( aa )
+{
+ ctor = ctor aa
+}
+function printtodtor( aa )
+{
+ dtor = dtor aa
+}
+function printtofunc( aa )
+{
+ fun = fun aa
+}
+function printp( a )
+{
+ #printf a >> "PRIVATE"
+ private = private a
+}
+function printg( a )
+{
+ printf a >> FILENAME "Impl.h"
+}
+function printh( a )
+{
+ printf a >> FILENAME "Impl.cc"
+}
+function doFuncCC( a, class )
+{
+ gsub("attribute", "", $0)
+ nr = split($0, b, " ")
+ # do method
+ i = 1
+ while ( i < nr && b[i + 1] != "(" )
+ {
+ var = b[i++]
+ if(match(var, "SVG") != 0 )
+ printtofunc( var "Impl " )
+ else
+ printtofunc( var " " )
+ }
+ printtofunc( class "::" );
+ while ( i < nr && b[i + 1] != ");" )
+ {
+ if( b[i] == "in" )
+ {
+ if(b[i + 1] != "float" && b[i + 1] != "unsigned" && b[i+1] != "short" && b[i+1] != "bool" )
+ #if(b[i + 1] != "float" && match(b[i + 1], "unsigned") == 0)
+ {
+ float = "ok"
+ printtofunc( "const " )
+ }
+ else
+ {
+ float = "bad"
+ }
+ i++
+ while ( i + 1 < nr && b[i + 1] != "in" && b[i + 1] != ");" )
+ {
+ var = b[i++]
+ if(match(var, "SVG") != 0 )
+ printtofunc( var "Impl " )
+ else
+ printtofunc( var " " )
+ }
+ if( float == "ok")
+ {
+ printtofunc( "&" b[i++] )
+ }
+ else
+ {
+ printtofunc( b[i++] )
+ }
+ if( i < nr ) printtofunc( " " )
+ }
+ else
+ printtofunc( b[i++] )
+ }
+ printtofunc( ")\n{\n}\n\n" );
+}
+
+function doFunc( a )
+{
+ gsub("attribute", "", $0)
+ nr = split($0, b, " ")
+ printg( "\t" )
+ # do method
+ i = 1
+ while ( i < nr && b[i + 1] != "(" )
+ {
+ var = b[i++]
+ if(match(var, "SVG") != 0 )
+ printg( var "Impl " )
+ else
+ printg( var " " )
+ }
+ while ( i < nr && b[i + 1] != ");" )
+ {
+ if( b[i] == "in" )
+ {
+ if(b[i + 1] != "float" && b[i + 1] != "unsigned" && b[i+1] != "short" && b[i+1] != "bool" )
+ {
+ float = "ok"
+ printg( "const " )
+ }
+ else
+ {
+ float = "bad"
+ }
+ i++
+ while ( i + 1 < nr && b[i + 1] != "in" && b[i + 1] != ");" )
+ {
+ var = b[i++]
+ if(match(var, "SVG") != 0 )
+ printg( var "Impl " )
+ else
+ printg( var " " )
+ }
+ if( float == "ok")
+ {
+ if( b[ i ] != "in" ) printg( "&" b[i++] )
+ }
+ else
+ {
+ if( b[ i ] != "in" ) printg( b[i++] )
+ }
+ if( i < nr ) printg( " " )
+ }
+ else
+ printg( b[i++] )
+ }
+ printg( ");\n" );
+}
+
+function doAttr( a, class )
+{
+ sub( ";", "", a)
+ sub( "\r", "", a)
+ gsub("attribute", "", a)
+ nr = split(a, b, " ")
+
+ # do put method
+ printg( "\tvoid set" )
+ printg( toupper( substr( b[nr], 1, 1) ) )
+ printg( substr( b[nr], 2) "(" )
+ i = 1
+ if(b[i] != "float" && b[i] != "unsigned" && b[i] != "short" && b[i] != "bool" )
+ {
+ float = "ok"
+ printg( "const " )
+ }
+ else
+ {
+ float = "bad"
+ }
+ while ( i < nr )
+ {
+ var = b[i++]
+ if(match(var, "SVG") != 0 )
+ printg( var "Impl" )
+ else
+ printg( var )
+ if( i < nr ) printg( " " )
+ }
+ if( float == "ok")
+ printg( " &" )
+ else
+ printg( " " )n
+ printg( b[nr] ");\n" )
+
+ # do put method .cc
+ printtofunc( "void " clas "::set" )
+ printtofunc( toupper( substr( b[nr], 1, 1) ) )
+ printtofunc( substr( b[nr], 2) "(" )
+ i = 1
+ if(b[i] != "float" && b[i] != "unsigned" && b[i] != "short" && b[i] != "bool" )
+ {
+ float = "ok"
+ printtofunc( "const " )
+ }
+ else
+ {
+ float = "bad"
+ }
+ while ( i < nr )
+ {
+ var = b[i++]
+ if(match(var, "SVG") != 0 )
+ printtofunc( var "Impl" )
+ else
+ printtofunc( var )
+ if( i < nr ) printtofunc( " " )
+ }
+ if( float == "ok")
+ printtofunc( " &" )
+ else
+ printtofunc( " " )
+ printtofunc( b[nr] ")\n{\n\tm_" b[nr] " = " b[nr] ";\n}\n\n" )
+
+
+ # do get method .h
+ i = 1
+ printg( "\t" )
+ while ( i < nr )
+ {
+ var = b[i++]
+ if(match(var, "SVG") != 0 )
+ printg( var "Impl *" )
+ else
+ printg( var " " )
+ }
+ sub( ";", "", b[nr])
+ sub( "\r", "", b[nr])
+ $temp = b[nr]
+ printg( $temp "() const;\n" )
+
+ # do get method .cc
+ i = 1
+ while ( i < nr )
+ {
+ var = b[i++]
+ if(match(var, "SVG") != 0 )
+ printtofunc( var "Impl *" )
+ else
+ printtofunc( var " " )
+ }
+ sub( ";", "", b[nr])
+ sub( "\r", "", b[nr])
+ $temp = b[nr]
+ printtofunc( clas "::" $temp "() const\n{\n\treturn m_" $temp )
+ printtofunc( ";\n}\n\n" )
+
+ # do var
+ i = 1
+ printp( "\t" )
+ while ( i < nr )
+ {
+ var = b[i++]
+ if(match(var, "SVG") != 0 )
+ {
+ var = var "Impl"
+ printp( var " *" )
+ }
+ else
+ printp( var " " )
+ }
+ printp( "m_" )
+ #printp( toupper( substr( b[nr], 1, 1) ) )
+ printp( substr( b[nr], 1) ";\n" )
+
+ #add to ctor + dtor
+ if(match(var, "SVG") != 0)
+ {
+ printtoctor("\tm_" substr( b[nr], 1) " = new " var "();\n" )
+ printtoctor("\tm_" substr( b[nr], 1) "->ref();\n\n" )
+ printtodtor("\tif(m_" substr( b[nr], 1) ")\n" )
+ printtodtor("\t\tm_" substr( b[nr], 1) "->deref();\n\n" )
+ }
+}
+
+function doReadonlyAttr( a, class )
+{
+ gsub("readonly attribute", "", $0)
+ nr = split($0, b, " ")
+
+ # do get method .h
+ i = 1
+ printg( "\t" )
+ while ( i < nr )
+ {
+ var = b[i++]
+ if(match(var, "SVG") != 0 )
+ printg( var "Impl *" )
+ else
+ printg( var " " )
+ }
+ sub( ";", "", b[nr])
+ sub( "\r", "", b[nr])
+ $temp = b[nr]
+ printg( $temp "() const;\n" )
+
+ # do get method .cc
+ i = 1
+ while ( i < nr )
+ {
+ var = b[i++]
+ if(match(var, "SVG") != 0 )
+ printtofunc( var "Impl *" )
+ else
+ printtofunc( var " " )
+ }
+ sub( ";", "", b[nr])
+ sub( "\r", "", b[nr])
+ $temp = b[nr]
+ printtofunc( clas "::" $temp "() const\n{\n\treturn m_" $temp )
+ printtofunc( ";\n}\n\n" )
+
+ # do var
+ i = 1
+ printp( "\t" )
+ while ( i < nr )
+ {
+ var = b[i++]
+ if(match(var, "SVG") != 0 )
+ {
+ var = var "Impl"
+ printp( var " *" )
+ }
+ else
+ printp( var " " )
+ }
+ printp( "m_" )
+ printp( substr( b[nr], 1) ";\n" )
+
+ #add to ctor + dtor
+ if(match(var, "SVG") != 0)
+ {
+ printtoctor("\tm_" substr( b[nr], 1) " = new " var "();\n" )
+ printtoctor("\tm_" substr( b[nr], 1) "->ref();\n\n" )
+ printtodtor("\tif(m_" substr( b[nr], 1) ")\n" )
+ printtodtor("\t\tm_" substr( b[nr], 1) "->deref();\n\n" )
+ }
+}
+{
+ sub("boolean", "bool", $0); # to shut up frerich :P
+ # Frerich: Thank you :-)
+ if(/interface /)
+ {
+ private = "\nprivate:\n";
+ gsub(" interface ", "", $0)
+ gsub(": ", ": public ", $0)
+ gsub(",", ", public", $0)
+ gsub("{", "\n{", $0)
+ sub( ";", "", $0 )
+ sub( "\r", "", $0 )
+ printg( "\nclass " )
+ #printg( $0 )
+ #printg( "\npublic:\n" )
+ nr = split($0, b, " ")
+ clas = b[1] "Impl"
+ printg( clas " " )
+ i = 2
+ while ( i < nr )
+ {
+ if(match(b[i], "SVG") != 0 )
+ {
+ if(match(b[i], ",") != 0)
+ sub( ",", "Impl," , b[i])
+ else
+ b[i] = b[i] "Impl"
+ }
+ printg( b[i++] " " )
+ }
+ printg( "\n{\npublic:\n" )
+ printg( "\t" clas "();\n" )
+ #printg( "\t" clas "(const " clas " &other)" )
+ #if( nr > 2 )
+ #{
+ # i = 2
+ # sub( ":", " : ", b[i] )
+ # while ( i < nr )
+ # {
+ # sub( "public", "", b[i] )
+ # sub( ",", "(), ", b[i] )
+ # printg( b[i++] )
+ # }
+ # printg( "()" )
+ #}
+ #printg( " { *this = other; }\n" )
+
+ printg( "\tvirtual ~" clas "();\n\n" )
+ #printg( "\t" clas " &operator=(const " clas " &other);\n\n" )
+
+ # CC part
+ #printh( "// " b[1] " implementation \n\n" )
+ printtoctor( clas "::" clas "()" )
+ if( nr > 2 )
+ {
+ i = 2
+ sub( ":", " : ", b[i] )
+ while ( i < nr )
+ {
+ sub( "public", "",b[i] )
+ sub( ",", "(), ", b[i] )
+ printtoctor( b[i++] )
+ }
+
+ printtoctor( "()" )
+ }
+ printtoctor( "\n{\n" )
+
+ printtodtor( clas "::~" clas "()\n{\n" )
+ #printh( clas " &" clas "::operator =(const " clas " &other)\n{\n\treturn *this;\n}\n\n" )
+
+ }
+ else if(/readonly attribute/)
+ {
+ doReadonlyAttr( $0, $class )
+ }
+ else if(/attribute /)
+ {
+ doAttr( $0, $class )
+ }
+ else if(/raises/)
+ {
+ }
+ else if(/\)/)
+ {
+ doFuncCC( $0, clas );
+ doFunc( $0 );
+ }
+ else if(/};/)
+ {
+ printg(private)
+ printg( "};\n\n" );
+
+ printh( "\n" ctor )
+ printh( "}\n\n" )
+ ctor = ""
+
+ printh( dtor )
+ printh( "}\n\n" )
+ dtor = ""
+
+ printh( fun )
+ fun = ""
+ }
+ else if(/ = /)
+ {
+# sub( "\r", "", $0 )
+# printg( $0 "\n" );
+ }
+ #else if(//)
+ #{
+ # # end of class
+ # printf $0;
+ #}
+}
+# END
+# {
+# print "};";
+# }
diff --git a/ksvg/test/Makefile.am b/ksvg/test/Makefile.am
new file mode 100644
index 00000000..7b2d8286
--- /dev/null
+++ b/ksvg/test/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = external
diff --git a/ksvg/test/Units.svg b/ksvg/test/Units.svg
new file mode 100644
index 00000000..f3a8569b
--- /dev/null
+++ b/ksvg/test/Units.svg
@@ -0,0 +1,43 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg width="400px" height="200px" viewBox="0 0 4000 2000"
+xmlns="http://www.w3.org/2000/svg">
+<title>Example Units</title>
+<desc>Illustrates various units options</desc>
+
+<!-- Frame the picture -->
+<rect x="5" y="5" width="3990" height="1990"
+fill="none" stroke="blue" stroke-width="10"/>
+<g fill="blue" stroke="red" font-family="Verdana" font-size="150">
+<!-- Absolute unit specifiers -->
+<g transform="translate(400,0)">
+<text x="-50" y="300" fill="black" stroke="none">Abs. units:</text>
+<rect x="0" y="400" width="4in" height="2in" stroke-width=".4in"/>
+<rect x="0" y="750" width="384" height="192" stroke-width="38.4"/>
+<g transform="scale(2)">
+<rect x="0" y="600" width="4in" height="2in" stroke-width=".4in"/>
+</g>
+</g>
+
+<!-- Relative unit specifiers -->
+<g transform="translate(1600,0)">
+<text x="-50" y="300" fill="black" stroke="none">Rel. units:</text>
+<rect x="0" y="400" width="2.5em" height="1.25em" stroke-width=".25em"/>
+<rect x="0" y="750" width="375" height="187.5" stroke-width="37.5"/>
+<g transform="scale(2)">
+<rect x="0" y="600" width="2.5em" height="1.25em" stroke-width=".25em"/>
+</g>
+</g>
+<!-- Percentages -->
+<g transform="translate(2800,0)">
+<text x="-50" y="300" fill="black" stroke="none">Percentages:</text>
+<rect x="0" y="400" width="10%" height="10%" stroke-width="1%"/>
+<rect x="0" y="750" width="400" height="200" stroke-width="31.62"/>
+<g transform="scale(2)">
+<rect x="0" y="600" width="10%" height="10%" stroke-width="1%"/>
+</g>
+</g>
+</g>
+</svg>
+
diff --git a/ksvg/test/W3C_TESTSUITE_1.1 b/ksvg/test/W3C_TESTSUITE_1.1
new file mode 100644
index 00000000..b0766355
--- /dev/null
+++ b/ksvg/test/W3C_TESTSUITE_1.1
@@ -0,0 +1,227 @@
+Testsuite-Check v1.1 FULL
+-----------------
+
+http://www.w3.org/Graphics/SVG/Test/20021112/htmlframe/full-index.html
+
+- = none working
+o = half working
+x = fully working
+c = crashed
+p = could not check
+e = crash on destruction
+
+[ANIMATION]
+animate-elem-02-t -
+animate-elem-03-t -
+animate-elem-04-t -
+animate-elem-05-t -
+animate-elem-06-t -
+animate-elem-07-t -
+animate-elem-08-t -
+animate-elem-09-t -
+animate-elem-10-t -
+animate-elem-11-t -
+animate-elem-12-t -
+animate-elem-13-t -
+animate-elem-14-t -
+animate-elem-15-t -
+animate-elem-16-t -
+animate-elem-17-t -
+animate-elem-18-t -
+animate-elem-19-t -
+animate-elem-20-t -
+animate-elem-21-t -
+animate-elem-22-b -
+animate-elem-23-t -
+animate-elem-24-t -
+animate-elem-25-t -
+animate-elem-26-t -
+animate-elem-27-t -
+animate-elem-28-t -
+animate-elem-29-b -
+
+[COLOR]
+color-prof-01-f x crashes when embedded
+color-prop-01-b x
+color-prop-02-f x
+color-prop-03-t x
+
+[COORDS]
+coords-trans-01-b x
+coords-trans-02-t x
+coords-trans-03-t x
+coords-trans-04-t x
+coords-trans-05-t x
+coords-trans-06-t x
+coords-units-01-b x Pattern is a bit off but size is ok
+coords-units-02-b o
+coords-units-03-b x
+coords-viewattr-01-b x
+
+[EXTEND]
+extend-namespace-01-f x
+
+[FILTERS]
+filters-blend-01-b -
+filters-color-01-b -
+filters-composite-01-b -
+filters-comptran-01-b -
+filters-conv-01-f -
+filters-diffuse-01-f -
+filters-displace-01-f -
+filters-example-01-b -
+filters-gauss-01-b -
+filters-image-01-b -
+filters-light-01-f -
+filters-morph-01-f -
+filters-offset-01-b -
+filters-specular-01-f -
+filters-tile-01-b -
+
+[FONTS]
+fonts-elem-01-t o SVG Font doesn't work
+fonts-elem-02-t - looks really strange
+fonts-elem-03-t o SVG Font doesn't work
+fonts-elem-04-t o SVG Font doesn't work
+
+[INTERACT]
+interact-cursor-01-b o
+interact-dom-01-t x
+interact-events-01-t x
+interact-order-01-t x
+interact-order-02-t o same as above
+interact-order-03-t o
+interact-zoom-01-t -
+
+[LINKING]
+linking-a-01-b x doesn't work when embedded?!
+linking-a-02-b x "
+linking-a-03-t x "
+linking-a-04-t x
+linking-uri-01-b -
+linking-uri-02-b -
+linking-uri-03-t x
+
+[MASKING]
+masking-mask-01-b -
+masking-opacity-01-b o
+masking-path-01-b x
+masking-path-02-b x
+masking-path-03-t x
+masking-path-04-b o
+masking-path-05-f x
+
+[METADATA]
+metadata-example-01-b x
+
+[PAINTING]
+painting-fill-01-t x
+painting-fill-02-t x
+painting-fill-03-t x
+painting-fill-04-t x
+painting-marker-01-f o Not every element drawn...hmm
+painting-marker-02-f o same
+painting-render-01-b o linearRGB wrong
+painting-stroke-01-t x
+painting-stroke-02-t x
+painting-stroke-03-t x
+painting-stroke-04-t x
+
+[PATHS]
+paths-data-01-t x
+paths-data-02-t x
+paths-data-03-f x
+paths-data-04-t x
+paths-data-05-t x
+paths-data-06-t x
+paths-data-07-t x
+
+[PSERVERS]
+pservers-grad-01-b x
+pservers-grad-02-b x
+pservers-grad-03-b x
+pservers-grad-04-b x
+pservers-grad-05-b o partially wrong colors
+pservers-grad-06-b o no transformations to the pattern
+pservers-grad-07-b x
+pservers-grad-08-b x
+pservers-grad-09-b x
+pservers-grad-10-b x
+pservers-grad-11-b x
+pservers-grad-12-b x
+pservers-pattern-01-b o patternpositioning
+
+[RENDER]
+render-elems-01-t x
+render-elems-02-t x
+render-elems-03-t x
+render-elems-06-t x
+render-elems-07-t x
+render-elems-08-t x
+render-groups-01-b - badly broken..
+render-groups-03-t o SVG font
+render-groups-04-b -
+
+[SCRIPT]
+script-handle-01-t x
+script-handle-02-t x
+script-handle-03-t x
+script-handle-04-t x
+
+[SHAPES]
+shapes-circle-01-t x
+shapes-ellipse-01-t x
+shapes-line-01-t x
+shapes-polygon-01-t x
+shapes-polyline-01-t x
+shapes-rect-01-t x
+
+[STRUCT]
+struct-cond-01-t x
+struct-cond-02-t x
+struct-defs-01-t x
+struct-dom-01-t x Reference PNG wrong?!
+struct-dom-02-t x everything false. but text says thats ok
+struct-dom-03-t x same
+struct-dom-04-t x same
+struct-dom-05-t x same
+struct-dom-06-t x
+struct-frag-01-t x empty image
+struct-group-01-t x
+struct-group-02-t x
+struct-image-01-t o SVG Image dimensions wrong
+struct-image-02-t x
+struct-image-03-t o no gamma correction
+struct-symbol-01-b -
+
+[STYLING]
+styling-css-01-t - no <style> supported
+styling-css-02-t -
+styling-css-03-t -
+styling-inherit-01-b o
+styling-pres-01-t -
+
+[TEXT]
+text-align-01-b x
+text-align-02-b o STRANGE (!)
+text-align-03-b x
+text-align-04-b o "end text on path" displays
+text-align-05-b - wrong for vertical text
+text-align-06-b -
+text-altglyph-01-b -
+text-deco-01-b o Colors of lines
+text-fonts-01-t c
+text-fonts-02-t c
+text-intro-01-t o just polish? missing fonts?
+text-intro-02-b o ltr doesn't work + font missing?
+text-intro-03-b - looks more than strange
+text-intro-04-t o see 1
+text-path-01-b - no textpath
+text-spacing-01-b x
+text-text-01-b o textlength mostly wrong
+text-text-03-b x
+text-tref-01-b -
+text-tselect-01-b - no textselection
+text-tspan-01-b x
+text-ws-01-t c
+text-ws-02-t c
diff --git a/ksvg/test/ZVON-TEST-PASSED b/ksvg/test/ZVON-TEST-PASSED
new file mode 100644
index 00000000..81cb6d52
--- /dev/null
+++ b/ksvg/test/ZVON-TEST-PASSED
@@ -0,0 +1,168 @@
+Testsuite-Check
+-----------------
+
+- = none working
+o = half working
+x = fully working
+c = crashed
+p = could not check
+e = crash on destruction
+
+http://www.zvon.org/HowTo/Output/category_SVG.html
+
+Group 1: [Animation]
+animation-add-BE-09.svg: -
+animation-extRef-BE-13.svg: -
+animation-href-BE-02.svg: -
+animation-inherit-BE-10.svg: -
+animation-motion-BE-11.svg: -
+animation-motion-BE-12.svg: -
+animation-overall-BE-01.svg: -
+animation-targAtt-BE-04.svg: -
+animation-targElt-BE-03.svg: -
+animation-timing-BE-05.svg: -
+animation-values-BE-06.svg: -
+animation-values-BE-07.svg: -
+animation-values-BE-08.svg: -
+
+Group 2: [Color] - 21.09.2003
+color-colorProf-BE-03.svg: x
+color-datatypes-BE-01.svg: x
+color-property-BE-02.svg: x
+
+Group 3: [Coordinates] - 21.09.2003
+coords-transforms-BE-02.svg: x
+coords-units-BE-01.svg: x
+coords-unitsProc-BE-04.svg: x
+coords-unitsProc-BE-05.svg: x
+coords-viewBox-BE-03.svg: x
+
+Group 4: [DOM] - 21.09.2003
+dom-core-BE-01.svg: x
+dom-eventListener-BE-04.svg: x
+dom-featureString-BE-03.svg: x
+dom-svg-BE-02.svg: x
+
+Group 5: [Extending SVG] - 21.09.2003
+extend-multiNS-BE-01.svg: x
+
+Group 6: [Filters]
+TODO
+
+Group 7: [Fonts] - 21.09.2003
+fonts-fontElement-BE-01.svg: o FONTS SUPPORT MISSING
+
+Group 8: [Gradient Patterns] - 21.09.2003
+gradPatt-linearGr-BE-01.svg: x
+gradPatt-linearGr-BE-02.svg: x
+gradPatt-linearGr-BE-03.svg: x
+gradPatt-pattern-BE-07.svg: x
+gradPatt-radialGr-BE-04.svg: x
+gradPatt-radialGr-BE-05.svg: x
+gradPatt-referenc-BE-08.svg: x
+gradPatt-stop-BE-06.svg: x
+gradPatt-stop-BE-10.svg: x
+gradPatt-transfrm-BE-09.svg: x
+
+Group 9: [Interactive] - 21.09.2003
+interact-onload-BE-07.svg: x
+interact-bubble-BE-04.svg: o
+interact-cursor-BE-08.svg: o CSS
+interact-pEvents-BE-05.svg: x
+interact-pEvents-BE-06.svg: x
+interact-zoomPan-BE-01.svg: x
+interact-zoomPan-BE-02.svg: x
+
+Group 10: [Linking] - 21.09.2003
+linking-inBound-BE-03.svg x
+linking-outBound-BE-01.svg o
+linking-view-BE-04.svg o
+linking-view-BE-05.svg o
+linking-xlinkAttr-BE-02.svg x
+
+Group 11: [Masking] - 21.09.2003
+masking-clipPath-BE-01.svg: x
+masking-clipPath-BE-02.svg: x
+masking-clipPath-BE-08.svg: x
+masking-clipRule-BE-03.svg: x
+masking-groupOpac-BE-04.svg: x
+masking-mask-BE-05.svg: x
+masking-mask-BE-06.svg: x
+masking-property-BE-07.svg: x
+masking-vportClip-BE-09.svg: x
+
+Group 12: [Metadata] - 21.09.2003
+metadata-sample-BE-01.svg: x PLANE REFERENCE IMAGE LOOKS WRONG - WE MATCH BATIK'S OUTPUT
+
+Group 13: [Misc] - 21.09.2003
+
+Group 14: [Paint] - 21.09.2003
+paint-colIntProp-BE-05.svg: x
+paint-fill-BE-01.svg: x
+paint-inherit-BE-06.svg: x
+paint-markers-BE-03.svg: x
+paint-markers-BE-04.svg: x
+paint-stroke-BE-02.svg: x
+
+Group 15: [Paths] - 21.09.2003
+path-curves-BE-02.svg: x
+path-curves-BE-03.svg: x
+path-curves-BE-04.svg: x
+path-lines-BE-01.svg: x
+
+Group 16: [Rendering] - 21.09.2003
+rendering-orderGr-BE-01.svg: x
+rendering-shape-BE-03.svg: x
+rendering-text-BE-02.svg: x
+
+Group 17: [Script] - 21.09.2003
+script-eventDom-BE-01.svg: x
+script-uiEvents-BE-02.svg: x
+
+Group 18: [Shapes] - 21.09.2003
+shapes-circle-BE-03.svg: x
+shapes-ellipse-BE-02.svg: x
+shapes-line-BE-04.svg: x
+shapes-polygon-BE-05.svg: x
+shapes-polyline-BE-06.svg: x
+shapes-rect-BE-01.svg: x
+
+Group 19: [Structure] - 21.09.2003
+structure-allElem-BE-09.svg: x
+structure-basicG-BE-03.svg: x
+structure-empty-BE-01.svg: x
+structure-defs-BE-04.svg: x
+structure-extRef-BE-10.svg: o CSS SUPPORT MISSING
+structure-image-BE-06.svg: x
+structure-imggamma-BE-11.svg: x
+structure-lang-BE-08.svg: x
+structure-nested-BE-02.svg: x
+structure-switch-BE-07.svg: x
+structure-symbol-BE-05.svg: x
+
+Group 20: [Style] - 21.09.2003
+style-selector-BE-01.svg: o
+style-selector-BE-02.svg: o
+style-selector-BE-03.svg: o
+
+Group 21: [Text] - 29.09.2003
+text-alignment-BE-10.svg: x
+text-alignment-BE-11.svg: x
+text-altGlyph-BE-07.svg: o FONTS SUPPORT MISSING
+text-decoration-BE-12.svg: x
+text-extTref-BE-18.svg: x
+text-font-BE-15.svg: x
+text-font-BE-16.svg: x
+text-i18n-BE-09.svg: x
+text-selection-BE-13.svg: o SELECTION NOT DONE YET
+text-spacing-BE-14.svg: x
+text-textAnchor-BE-05.svg: x BROKEN BECAUSE OF TEXT ON PATH
+text-text-BE-01.svg: x
+text-textLength-BE-17.svg: x
+text-textOnPath-BE-03.svg: x IN GENERAL TEXTPATH GLYPHS CAN BE BETTER ALIGNED
+text-tref-BE-04.svg: x
+text-tspan-BE-02.svg: x
+text-whiteSpace-BE-06.svg: x
+
+Group 22: [Transformations]
+TODO
diff --git a/ksvg/test/amflag.svg b/ksvg/test/amflag.svg
new file mode 100644
index 00000000..83e6dddb
--- /dev/null
+++ b/ksvg/test/amflag.svg
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<svg viewBox="0 0 2000 600" width="10cm" height="5cm">
+<g transform="translate(10 60)">
+ <defs>
+ <rect id="r" width="900" height="40" style="fill:#dd0000"/>
+ <rect id="w" width="900" height="40" style="fill:white"/>
+ <polygon id="s" style="fill:white;fill-rule:nonzero;"
+ points="0,-14 8.229,11.326 -13.315,-4.326 13.315,-4.326 -8.229,11.326">
+ <animateTransform attributeName="transform" type="rotate" values="0;360" dur="3s" repeatDur="indefinite" />
+ </polygon>
+ <g id="6">
+ <use xlink:href="#s" x="20"/>
+ <use xlink:href="#s" x="90"/>
+ <use xlink:href="#s" x="150"/>
+ <use xlink:href="#s" x="210"/>
+ <use xlink:href="#s" x="270"/>
+ <use xlink:href="#s" x="330"/>
+ </g>
+ <g id="5">
+ <use xlink:href="#s" x="60"/>
+ <use xlink:href="#s" x="120"/>
+ <use xlink:href="#s" x="180"/>
+ <use xlink:href="#s" x="240"/>
+ <use xlink:href="#s" x="300"/>
+ </g>
+ </defs>
+ <use xlink:href="#r"/>
+ <use xlink:href="#w" y="40"/>
+ <use xlink:href="#r" y="80"/>
+ <use xlink:href="#w" y="120"/>
+ <use xlink:href="#r" y="160"/>
+ <use xlink:href="#w" y="200"/>
+ <use xlink:href="#r" y="240"/>
+ <use xlink:href="#w" y="280"/>
+ <use xlink:href="#r" y="320"/>
+ <use xlink:href="#w" y="360"/>
+ <use xlink:href="#r" y="400"/>
+ <use xlink:href="#w" y="440"/>
+ <use xlink:href="#r" y="480"/>
+ <rect id="b" width="360" height="280" style="fill:#000088"/>
+ <rect id="border" width="900" height="520" style="fill:none;stroke:black;stroke-width:0.85"/>
+ <g transform="translate(4.5 0)">
+ <use xlink:href="#6" y="20"/>
+ <use xlink:href="#5" y="50"/>
+ <use xlink:href="#6" y="80"/>
+ <use xlink:href="#5" y="110"/>
+ <use xlink:href="#6" y="140"/>
+ <use xlink:href="#5" y="170"/>
+ <use xlink:href="#6" y="200"/>
+ <use xlink:href="#5" y="230"/>
+ <use xlink:href="#6" y="260"/>
+ </g>
+</g>
+</svg>
diff --git a/ksvg/test/animskew.svg b/ksvg/test/animskew.svg
new file mode 100644
index 00000000..ab2a13f9
--- /dev/null
+++ b/ksvg/test/animskew.svg
@@ -0,0 +1,44 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20001102//EN"
+ "http://www.w3.org/TR/2000/CR-SVG-20001102/DTD/svg-20001102.dtd">
+<svg width="10cm" height="5cm">
+ <desc>Animated skew + animated attributes ksvg-testcase</desc>
+
+ <g style="stroke:black; stroke-width:5" id="animskewg">
+ <line id="l1" x1="3cm" x2="6cm" y1="-1cm" y2="-1cm"/>
+
+ <line id="l2" x1="-1cm" x2="-1cm" y1="0.5cm" y2="4.5cm"/>
+ <line id="l3" x1="11cm" x2="11cm" y1="0.5cm" y2="4.5cm"/>
+
+ <line id="l4" x1="3cm" x2="6cm" y1="6cm" y2="6cm"/>
+ </g>
+
+ <animate xlink:href="#l1" attributeName="y1" begin="1s"
+ dur="5s" from="-1cm" to="0.5cm"/>
+ <animate xlink:href="#l1" attributeName="y2" begin="1s"
+ dur="5s" from="-1cm" to="0.5cm"/>
+
+ <animate xlink:href="#l2" attributeName="x1" begin="1s"
+ dur="5s" from="-1cm" to="3cm"/>
+ <animate xlink:href="#l2" attributeName="x2" begin="1s"
+ dur="5s" from="-1cm" to="3cm"/>
+
+ <animate xlink:href="#l3" attributeName="x1" begin="1s"
+ dur="5s" from="11cm" to="6cm"/>
+ <animate xlink:href="#l3" attributeName="x2" begin="1s"
+ dur="5s" from="11cm" to="6cm"/>
+
+ <animate xlink:href="#l4" attributeName="y1" begin="1s"
+ dur="5s" from="6cm" to="4.5cm"/>
+ <animate xlink:href="#l4" attributeName="y2" begin="1s"
+ dur="5s" from="6cm" to="4.5cm"/>
+
+ <animateTransform xlink:href="#animskewg" attributeName="transform" begin="7s"
+ dur="2s" type="skewX" from="0" to="10"/>
+ <animateTransform xlink:href="#animskewg" attributeName="transform" begin="9s"
+ dur="2s" type="skewX" from="10" to="0"/>
+ <animateTransform xlink:href="#animskewg" attributeName="transform" begin="11s"
+ dur="2s" type="skewX" from="0" to="-10"/>
+ <animateTransform xlink:href="#animskewg" attributeName="transform" begin="13s"
+ dur="2s" type="skewX" from="-10" to="0"/>
+</svg>
diff --git a/ksvg/test/arabic.svg b/ksvg/test/arabic.svg
new file mode 100644
index 00000000..71bbe0e6
--- /dev/null
+++ b/ksvg/test/arabic.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg width="10000" height="100">
+<text x="10" y="10">
+Big string of Arabic:
+</text>
+<text x="10" y="80" font-family="Arial" font-size="72">
+وقد بدأ ثلاث من أكثر المؤسسات تقدما في شبكة اكسيون برامجها كمنظمات لاتسعى للربح، ثم تحولت في السنوات الخمسالماضية إلى مؤسسات مالية منظمة، وباتتجزءا من النظام المالي في بلدانها،ولكنها تتخصص في خدمة قطاع المشروعاتالصغيرة. وأحد أكثر هذه المؤسسات نجاحاهو »بانكوسول« في بوليفيا.
+</text>
+</svg>
diff --git a/ksvg/test/butterfly.svg b/ksvg/test/butterfly.svg
new file mode 100644
index 00000000..eca71841
--- /dev/null
+++ b/ksvg/test/butterfly.svg
@@ -0,0 +1,11 @@
+<!-- This is a slightly modified version of a sample that shipped with
+ JASC's WebDraw (www.jasc.com) -->
+<svg xmlns="http://www.w3.org/2000/svg">
+ <path style="stroke-width:1;fill:rgb(246,127,0);stroke:none"
+ d="M204.33 139.83 C196.33 133.33 206.68 132.82 206.58 132.58 C192.33 97.08 169.35 81.41 167.58 80.58 C162.12 78.02 159.48 78.26 160.45 76.97 C161.41 75.68 167.72 79.72 168.58 80.33 C193.83 98.33 207.58 132.33 207.58 132.33 C207.58 132.33 209.33 133.33 209.58 132.58 C219.58 103.08 239.58 87.58 246.33 81.33 C253.08 75.08 256.63 74.47 247.33 81.58 C218.58 103.58 210.34 132.23 210.83 132.33 C222.33 134.83 211.33 140.33 211.83 139.83 C214.85 136.81 214.83 145.83 214.83 145.83 C214.83 145.83 231.83 110.83 298.33 66.33 C302.43 63.59 445.83 -14.67 395.83 80.83 C393.24 85.79 375.83 105.83 375.83 105.83 C375.83 105.83 377.33 114.33 371.33 121.33 C370.3 122.53 367.83 134.33 361.83 140.83 C360.14 142.67 361.81 139.25 361.83 140.83 C362.33 170.83 337.76 170.17 339.33 170.33 C348.83 171.33 350.19 183.66 350.33 183.83 C355.83 190.33 353.83 191.83 355.83 194.83 C366.63 211.02 355.24 210.05 356.83 212.83 C360.83 219.83 355.99 222.72 357.33 224.83 C360.83 230.33 354.75 233.84 354.83 235.33 C355.33 243.83 349.67 240.73 349.83 244.33 C350.33 255.33 346.33 250.83 343.83 254.83 C336.33 266.83 333.46 262.38 332.83 263.83 C329.83 270.83 325.81 269.15 324.33 270.83 C320.83 274.83 317.33 274.83 315.83 276.33 C308.83 283.33 304.86 278.39 303.83 278.83 C287.83 285.83 280.33 280.17 277.83 280.33 C270.33 280.83 271.48 279.67 269.33 277.83 C237.83 250.83 219.33 211.83 215.83 206.83 C214.4 204.79 211.35 193.12 212.33 195.83 C214.33 201.33 213.33 250.33 207.83 250.33 C202.33 250.33 201.83 204.33 205.33 195.83 C206.43 193.16 204.4 203.72 201.79 206.83 C196.33 213.33 179.5 250.83 147.59 277.83 C145.42 279.67 146.58 280.83 138.98 280.33 C136.46 280.17 128.85 285.83 112.65 278.83 C111.61 278.39 107.58 283.33 100.49 276.33 C98.97 274.83 95.43 274.83 91.88 270.83 C90.39 269.15 86.31 270.83 83.27 263.83 C82.64 262.38 79.73 266.83 72.13 254.83 C69.6 250.83 65.54 255.33 66.05 244.33 C66.22 240.73 60.48 243.83 60.99 235.33 C61.08 233.84 54.91 230.33 58.45 224.83 C59.81 222.72 54.91 219.83 58.96 212.83 C60.57 210.05 49.04 211.02 59.97 194.83 C62 191.83 59.97 190.33 65.54 183.83 C65.69 183.66 67.06 171.33 76.69 170.33 C78.28 170.17 53.39 170.83 53.9 140.83 C53.92 139.25 55.61 142.67 53.9 140.83 C47.82 134.33 45.32 122.53 44.27 121.33 C38.19 114.33 39.71 105.83 39.71 105.83 C39.71 105.83 22.08 85.79 19.46 80.83 C-31.19 -14.67 114.07 63.59 118.22 66.33 C185.58 110.83 202 145.83 202 145.83 C202 145.83 202.36 143.28 203 141.83 C203.64 140.39 204.56 140.02 204.33 139.83 z"/>
+ <path style="stroke-width:1;fill:rgb(0,0,0);stroke:none"
+ d="M203.62 139.62 C195.62 133.12 205.96 132.6 205.87 132.37 C191.62 96.87 168.64 81.2 166.87 80.37 C161.41 77.81 158.77 78.05 159.73 76.76 C160.69 75.47 167.01 79.51 167.87 80.12 C193.12 98.12 206.87 132.12 206.87 132.12 C206.87 132.12 208.62 133.12 208.87 132.37 C218.87 102.87 238.87 87.37 245.62 81.12 C252.37 74.87 255.92 74.26 246.62 81.37 C217.87 103.37 209.63 132.01 210.12 132.12 C221.62 134.62 210.62 140.12 211.12 139.62 C214.14 136.6 214.12 145.62 214.12 145.62 C214.12 145.62 231.12 110.62 297.62 66.12 C301.71 63.38 445.12 -14.88 395.12 80.62 C392.53 85.57 375.12 105.62 375.12 105.62 C375.12 105.62 376.62 114.12 370.62 121.12 C369.59 122.32 367.12 134.12 361.12 140.62 C359.43 142.46 361.09 139.04 361.12 140.62 C361.62 170.62 337.05 169.96 338.62 170.12 C348.12 171.12 349.47 183.45 349.62 183.62 C355.12 190.12 353.12 191.62 355.12 194.62 C365.91 210.81 354.53 209.84 356.12 212.62 C360.12 219.62 355.28 222.51 356.62 224.62 C360.12 230.12 354.03 233.62 354.12 235.12 C354.62 243.62 348.96 240.52 349.12 244.12 C349.62 255.12 345.62 250.62 343.12 254.62 C335.62 266.62 332.74 262.17 332.12 263.62 C329.12 270.62 325.09 268.94 323.62 270.62 C320.12 274.62 316.62 274.62 315.12 276.12 C308.12 283.12 304.15 278.17 303.12 278.62 C287.12 285.62 279.62 279.95 277.12 280.12 C269.62 280.62 270.77 279.46 268.62 277.62 C237.12 250.62 218.62 211.62 215.12 206.62 C213.69 204.57 210.63 192.91 211.62 195.62 C213.62 201.12 212.62 250.12 207.12 250.12 C201.62 250.12 201.12 204.12 204.62 195.62 C205.72 192.95 203.69 203.5 201.08 206.62 C195.62 213.12 178.79 250.62 146.88 277.62 C144.71 279.46 145.87 280.62 138.27 280.12 C135.75 279.95 128.14 285.62 111.94 278.62 C110.9 278.17 106.87 283.12 99.78 276.12 C98.26 274.62 94.72 274.62 91.17 270.62 C89.68 268.94 85.6 270.62 82.56 263.62 C81.93 262.17 79.01 266.62 71.42 254.62 C68.88 250.62 64.83 255.12 65.34 244.12 C65.51 240.52 59.77 243.62 60.27 235.12 C60.36 233.62 54.2 230.12 57.74 224.62 C59.1 222.51 54.2 219.62 58.25 212.62 C59.86 209.84 48.33 210.81 59.26 194.62 C61.29 191.62 59.26 190.12 64.83 183.62 C64.98 183.45 66.35 171.12 75.98 170.12 C77.57 169.96 52.68 170.62 53.18 140.62 C53.21 139.04 54.9 142.46 53.18 140.62 C47.11 134.12 44.6 122.32 43.56 121.12 C37.48 114.12 39 105.62 39 105.62 C39 105.62 21.37 85.57 18.74 80.62 C-31.9 -14.88 113.36 63.38 117.51 66.12 C184.87 110.62 201.29 145.62 201.29 145.62 C201.29 145.62 201.65 143.07 202.29 141.62 C202.93 140.18 203.85 139.81 203.62 139.62 zM242.12 153.12 C245.16 153.02 251.35 156.17 255.12 155.12 C280.55 148.06 328.44 154.56 331.62 155.62 C343.62 159.62 351.62 131.12 326.12 131.12 C294.59 131.12 301.12 129.12 280.12 126.12 C278.34 125.87 252.6 135.42 228.62 149.12 C225.12 151.12 227.12 153.62 242.12 153.12 zM223.12 148.12 C225.66 148.4 238.12 139.62 277.12 124.12 C279.49 123.18 279.62 118.12 300.62 108.62 C301.99 108 300.12 104.62 314.62 92.62 C321.79 86.69 297.12 87.62 291.62 88.62 C286.12 89.62 272.62 100.62 272.62 100.62 C272.62 100.62 287.8 88.55 282.62 90.12 C271.12 93.62 241.12 126.62 231.12 140.62 C221.12 154.62 247.62 116.62 254.12 110.62 C260.62 104.62 204.62 146.12 223.12 148.12 zM335.62 128.62 C350.14 131.53 348.62 110.12 341.12 109.12 C329.55 107.58 307.51 108.3 301.12 110.62 C284.62 116.62 280.29 122.65 281.62 123.12 C310.12 133.12 330.62 127.62 335.62 128.62 zM335.12 106.62 C341.04 107.36 351.12 109.62 351.62 101.62 C351.87 97.6 365.62 104.62 368.62 105.12 C371.1 105.53 358.12 100.33 353.62 97.12 C350.12 94.62 349.51 91.76 349.12 91.62 C317.12 80.12 303.62 107.12 303.62 107.12 C303.62 107.12 331.12 106.12 335.12 106.62 zM400.62 62.62 C395.62 54.62 386.66 57.08 383.62 53.62 C369.12 37.12 335.54 58.28 363.12 56.12 C395.12 53.62 401.21 63.57 400.62 62.62 zM376.62 66.62 C390.13 66.62 396.12 72.62 395.12 71.62 C388.12 64.62 382.12 66.12 380.62 64.12 C371.7 52.23 345.12 64.62 347.12 67.62 C349.12 70.62 373.12 66.62 376.62 66.62 zM330.12 76.12 C309.12 81.12 318.12 88.62 320.62 88.12 C340.05 84.24 334.5 75.08 330.12 76.12 zM340.62 52.12 C331.12 53.12 330.48 70.43 335.12 67.12 C342.12 62.12 350.12 51.12 340.62 52.12 zM315.62 75.62 C329.62 70.12 319.12 67.62 314.62 68.12 C310.12 68.62 306.79 75.45 308.12 78.12 C311.12 84.12 312.91 76.69 315.62 75.62 zM359.62 121.12 C364.12 118.62 358.62 112.62 354.62 115.12 C350.62 117.62 355.12 123.62 359.62 121.12 zM350.12 78.62 C361.89 90.39 366.62 84.12 369.12 83.12 C377.24 79.87 386.12 88.62 384.62 87.12 C377.34 79.84 372.62 81.12 371.62 79.62 C364.01 68.2 352.66 75.44 350.12 75.62 C343.12 76.12 334.43 81.03 337.62 80.12 C341.12 79.12 348.62 77.12 350.12 78.62 zM383.62 44.12 C390.62 39.12 381.4 37.85 379.62 38.12 C373.12 39.12 376.62 49.12 383.62 44.12 zM224.62 181.12 C230.12 187.62 291.62 285.12 282.12 252.62 C280.83 248.2 285.62 266.12 291.12 256.12 C292.66 253.32 301.27 253.03 274.62 208.62 C273.12 206.12 252.62 198.12 232.12 175.62 C229.02 172.21 220.05 175.72 224.62 181.12 zM280.12 215.62 C284.62 222.62 295.81 246.07 296.62 249.62 C299.12 260.62 306.12 248.12 307.62 248.62 C320.78 253.01 311.12 241.12 310.12 238.12 C300.95 210.62 279.62 213.12 279.62 213.12 C279.62 213.12 275.62 208.62 280.12 215.62 zM253.62 256.12 C266.26 274.09 271.12 267.12 273.62 265.12 C281.32 258.96 232.34 196.14 229.12 192.12 C225.12 187.12 225.12 215.62 253.62 256.12 zM300.12 219.12 C306.62 224.12 313.86 245.19 317.62 244.62 C327.62 243.12 321.62 234.62 324.12 236.12 C326.62 237.62 331.62 234.95 330.12 232.12 C317.62 208.62 298.12 216.12 298.12 216.12 C298.12 216.12 293.62 214.12 300.12 219.12 zM235.62 168.62 C216.12 168.62 282.12 222.62 301.12 212.12 C305.06 209.94 296.12 208.62 297.62 197.12 C297.9 195.02 284.12 191.12 284.12 178.12 C284.12 173.88 276.2 172.12 251.12 172.12 C246.62 172.12 256.03 168.62 235.62 168.62 zM307.62 213.62 C325.89 215.65 330.23 229.8 332.62 228.12 C361.12 208.12 309.89 199.96 300.62 201.12 C296.62 201.62 303.12 213.12 307.62 213.62 zM238.62 164.12 C242.12 166.62 254.12 176.62 292.62 168.12 C294.09 167.8 263.62 167.62 259.62 166.62 C255.62 165.62 236.25 162.43 238.62 164.12 zM305.12 198.62 C342.62 207.62 332.72 201.36 334.12 200.62 C342.62 196.12 333.33 195.23 334.62 193.62 C338.83 188.36 327.62 185.12 304.12 182.62 C298.56 182.03 287.54 179.27 287.12 180.12 C283.62 187.12 300.33 197.47 305.12 198.62 zM311.12 182.12 C343.62 187.62 323.23 177.43 323.62 177.12 C335.12 168.12 297.12 168.12 297.12 168.12 C297.12 168.12 280.79 172 281.12 172.62 C285.62 181.12 307.15 181.45 311.12 182.12 zM249.62 253.62 C249.62 253.62 220.62 207.12 226.62 188.12 C227.83 184.31 213.62 165.62 220.12 197.12 C220.22 197.61 218.89 190.43 216.62 187.12 C214.35 183.81 211.18 184.9 213.12 194.62 C218.01 219.05 249.62 253.62 249.62 253.62 zM289.12 83.62 C296.62 81.62 293.12 79.12 288.62 78.12 C284.12 77.12 281.62 85.62 289.12 83.62 zM187.4 149.12 C163.12 135.42 137.04 125.87 135.23 126.12 C113.96 129.12 120.58 131.12 88.64 131.12 C62.81 131.12 70.91 159.62 83.07 155.62 C86.29 154.56 134.8 148.06 160.56 155.12 C164.37 156.17 170.65 153.02 173.73 153.12 C188.92 153.62 190.95 151.12 187.4 149.12 zM161.57 110.62 C168.15 116.62 195 154.62 184.87 140.62 C174.74 126.62 144.35 93.62 132.7 90.12 C127.46 88.55 142.83 100.62 142.83 100.62 C142.83 100.62 129.16 89.62 123.58 88.62 C118.01 87.62 93.03 86.69 100.29 92.62 C114.97 104.62 113.08 108 114.47 108.62 C135.74 118.12 135.87 123.18 138.27 124.12 C177.78 139.62 190.4 148.4 192.97 148.12 C211.71 146.12 154.99 104.62 161.57 110.62 zM133.71 123.12 C135.07 122.65 130.68 116.62 113.96 110.62 C107.49 108.3 85.16 107.58 73.44 109.12 C65.85 110.12 64.31 131.53 79.01 128.62 C84.08 127.62 104.84 133.12 133.71 123.12 zM111.43 107.12 C111.43 107.12 97.75 80.12 65.34 91.62 C64.95 91.76 64.33 94.62 60.78 97.12 C56.23 100.33 43.08 105.53 45.59 105.12 C48.63 104.62 62.55 97.6 62.81 101.62 C63.31 109.62 73.53 107.36 79.52 106.62 C83.57 106.12 111.43 107.12 111.43 107.12 zM51.16 56.12 C79.09 58.28 45.08 37.12 30.39 53.62 C27.31 57.08 18.24 54.62 13.17 62.62 C12.57 63.57 18.74 53.62 51.16 56.12 zM67.37 67.62 C69.39 64.62 42.47 52.23 33.43 64.12 C31.91 66.12 25.83 64.62 18.74 71.62 C17.73 72.62 23.8 66.62 37.48 66.62 C41.03 66.62 65.34 70.62 67.37 67.62 zM84.59 76.12 C105.86 81.12 96.74 88.62 94.21 88.12 C74.53 84.24 80.15 75.08 84.59 76.12 zM79.52 67.12 C84.22 70.43 83.57 53.12 73.95 52.12 C64.33 51.12 72.43 62.12 79.52 67.12 zM106.87 78.12 C108.22 75.45 104.84 68.62 100.29 68.12 C95.73 67.62 85.09 70.12 99.27 75.62 C102.02 76.69 103.83 84.12 106.87 78.12 zM59.77 115.12 C55.72 112.62 50.14 118.62 54.7 121.12 C59.26 123.62 63.82 117.62 59.77 115.12 zM76.99 80.12 C80.22 81.03 71.42 76.12 64.33 75.62 C61.75 75.44 50.26 68.2 42.55 79.62 C41.53 81.12 36.75 79.84 29.38 87.12 C27.86 88.62 36.85 79.87 45.08 83.12 C47.61 84.12 52.41 90.39 64.33 78.62 C65.85 77.12 73.44 79.12 76.99 80.12 zM34.44 38.12 C32.64 37.85 23.3 39.12 30.39 44.12 C37.48 49.12 41.03 39.12 34.44 38.12 zM183.86 175.62 C163.09 198.12 142.32 206.12 140.8 208.62 C113.81 253.03 122.53 253.32 124.09 256.12 C129.66 266.12 134.52 248.2 133.21 252.62 C123.58 285.12 185.88 187.62 191.45 181.12 C196.08 175.72 187 172.21 183.86 175.62 zM135.74 213.12 C135.74 213.12 114.13 210.62 104.84 238.12 C103.83 241.12 94.05 253.01 107.38 248.62 C108.9 248.12 115.99 260.62 118.52 249.62 C119.34 246.07 130.68 222.62 135.23 215.62 C139.79 208.62 135.74 213.12 135.74 213.12 zM186.89 192.12 C183.64 196.14 134.02 258.96 141.82 265.12 C144.35 267.12 149.27 274.09 162.08 256.12 C190.95 215.62 190.95 187.12 186.89 192.12 zM117 216.12 C117 216.12 97.25 208.62 84.59 232.12 C83.06 234.95 88.13 237.62 90.66 236.12 C93.2 234.62 87.12 243.12 97.25 244.62 C101.06 245.19 108.39 224.12 114.97 219.12 C121.56 214.12 117 216.12 117 216.12 zM164.61 172.12 C139.2 172.12 131.18 173.88 131.18 178.12 C131.18 191.12 117.23 195.02 117.51 197.12 C119.03 208.62 109.97 209.94 113.96 212.12 C133.21 222.62 200.06 168.62 180.31 168.62 C159.64 168.62 169.17 172.12 164.61 172.12 zM114.47 201.12 C105.08 199.96 53.18 208.12 82.05 228.12 C84.47 229.8 88.87 215.65 107.38 213.62 C111.94 213.12 118.52 201.62 114.47 201.12 zM156 166.62 C151.95 167.62 121.09 167.8 122.57 168.12 C161.57 176.62 173.73 166.62 177.27 164.12 C179.67 162.43 160.05 165.62 156 166.62 zM128.14 180.12 C127.71 179.27 116.55 182.03 110.92 182.62 C87.12 185.12 75.76 188.36 80.03 193.62 C81.33 195.23 71.92 196.12 80.53 200.62 C81.95 201.36 71.92 207.62 109.91 198.62 C114.76 197.47 131.69 187.12 128.14 180.12 zM134.22 172.62 C134.56 172 118.01 168.12 118.01 168.12 C118.01 168.12 79.52 168.12 91.17 177.12 C91.57 177.43 70.91 187.62 103.83 182.12 C107.86 181.45 129.66 181.12 134.22 172.62 zM203.1 194.62 C205.07 184.9 201.85 183.81 199.56 187.12 C197.26 190.43 195.91 197.61 196.01 197.12 C202.6 165.62 188.21 184.31 189.43 188.12 C195.5 207.12 166.13 253.62 166.13 253.62 C166.13 253.62 198.15 219.05 203.1 194.62 zM126.62 78.12 C122.06 79.12 118.52 81.62 126.12 83.62 C133.71 85.62 131.18 77.12 126.62 78.12 z"/>
+ <path style="stroke-width:1;fill:rgb(255,246,227);stroke:none"
+ d="M363.73 85.73 C359.27 86.29 355.23 86.73 354.23 81.23 C353.23 75.73 355.73 73.73 363.23 75.73 C370.73 77.73 375.73 84.23 363.73 85.73 zM327.23 89.23 C327.23 89.23 308.51 93.65 325.73 80.73 C333.73 74.73 334.23 79.73 334.73 82.73 C335.48 87.2 327.23 89.23 327.23 89.23 zM384.23 48.73 C375.88 47.06 376.23 42.23 385.23 40.23 C386.7 39.91 389.23 49.73 384.23 48.73 zM389.23 48.73 C391.73 48.23 395.73 49.23 396.23 52.73 C396.73 56.23 392.73 58.23 390.23 56.23 C387.73 54.23 386.73 49.23 389.23 48.73 zM383.23 59.73 C385.73 58.73 393.23 60.23 392.73 63.23 C392.23 66.23 386.23 66.73 383.73 65.23 C381.23 63.73 380.73 60.73 383.23 59.73 zM384.23 77.23 C387.23 74.73 390.73 77.23 391.73 78.73 C392.73 80.23 387.73 82.23 386.23 82.73 C384.73 83.23 381.23 79.73 384.23 77.23 zM395.73 40.23 C395.73 40.23 399.73 40.23 398.73 41.73 C397.73 43.23 394.73 43.23 394.73 43.23 zM401.73 49.23 C401.73 49.23 405.73 49.23 404.73 50.73 C403.73 52.23 400.73 52.23 400.73 52.23 zM369.23 97.23 C369.23 97.23 374.23 99.23 373.23 100.73 C372.23 102.23 370.73 104.73 367.23 101.23 C363.73 97.73 369.23 97.23 369.23 97.23 zM355.73 116.73 C358.73 114.23 362.23 116.73 363.23 118.23 C364.23 119.73 359.23 121.73 357.73 122.23 C356.23 122.73 352.73 119.23 355.73 116.73 zM357.73 106.73 C360.73 104.23 363.23 107.73 364.23 109.23 C365.23 110.73 361.23 111.73 359.73 112.23 C358.23 112.73 354.73 109.23 357.73 106.73 zM340.73 73.23 C337.16 73.43 331.23 71.73 340.23 65.73 C348.55 60.19 348.23 61.73 348.73 64.73 C349.48 69.2 344.3 73.04 340.73 73.23 zM310.23 82.23 C310.23 82.23 306.73 79.23 313.73 73.23 C321.33 66.73 320.23 69.23 320.73 72.23 C321.48 76.7 310.23 82.23 310.23 82.23 zM341.23 55.73 C341.23 55.73 347.23 54.73 346.23 56.23 C345.23 57.73 342.73 63.23 339.23 59.73 C335.73 56.23 341.23 55.73 341.23 55.73 zM374.73 86.23 C376.11 86.23 377.23 87.36 377.23 88.73 C377.23 90.11 376.11 91.23 374.73 91.23 C373.36 91.23 372.23 90.11 372.23 88.73 C372.23 87.36 373.36 86.23 374.73 86.23 zM369.73 110.73 C371.11 110.73 372.23 111.86 372.23 113.23 C372.23 114.61 371.11 115.73 369.73 115.73 C368.36 115.73 367.23 114.61 367.23 113.23 C367.23 111.86 368.36 110.73 369.73 110.73 zM365.73 120.73 C367.11 120.73 368.23 121.86 368.23 123.23 C368.23 124.61 367.11 125.73 365.73 125.73 C364.36 125.73 363.23 124.61 363.23 123.23 C363.23 121.86 364.36 120.73 365.73 120.73 zM349.73 127.23 C351.11 127.23 352.23 128.36 352.23 129.73 C352.23 131.11 351.11 132.23 349.73 132.23 C348.36 132.23 347.23 131.11 347.23 129.73 C347.23 128.36 348.36 127.23 349.73 127.23 zM358.23 128.73 C359.61 128.73 362.23 130.86 362.23 132.23 C362.23 133.61 359.61 133.73 358.23 133.73 C356.86 133.73 355.73 132.61 355.73 131.23 C355.73 129.86 356.86 128.73 358.23 128.73 zM382.23 89.73 C383.61 89.73 384.73 90.86 384.73 92.23 C384.73 93.61 383.61 94.73 382.23 94.73 C380.86 94.73 379.73 93.61 379.73 92.23 C379.73 90.86 380.86 89.73 382.23 89.73 zM395.73 66.23 C397.11 66.23 398.23 67.36 398.23 68.73 C398.23 70.11 397.11 71.23 395.73 71.23 C394.36 71.23 393.23 70.11 393.23 68.73 C393.23 67.36 394.36 66.23 395.73 66.23 zM300.73 74.23 C303.05 75.16 314.23 67.73 310.73 66.73 C307.23 65.73 298.23 73.23 300.73 74.23 zM319.73 61.23 C322.23 61.73 329.73 58.73 326.23 57.73 C322.73 56.73 317.09 60.71 319.73 61.23 zM271.73 91.73 C277.23 88.73 292.73 81.23 285.23 82.23 C277.73 83.23 267.01 94.31 271.73 91.73 zM364.23 42.23 C366.73 42.73 374.23 39.73 370.73 38.73 C367.23 37.73 361.59 41.71 364.23 42.23 zM292.23 78.73 C294.73 79.23 299.73 76.73 296.23 75.73 C292.73 74.73 289.59 78.21 292.23 78.73 zM355.23 141.23 C356.61 141.23 357.73 142.86 357.73 144.23 C357.73 145.61 357.11 145.73 355.73 145.73 C354.36 145.73 353.23 144.61 353.23 143.23 C353.23 141.86 353.86 141.23 355.23 141.23 zM347.73 140.73 C349.11 140.73 351.23 141.36 351.23 142.73 C351.23 144.11 348.61 143.73 347.23 143.73 C345.86 143.73 344.73 142.61 344.73 141.23 C344.73 139.86 346.36 140.73 347.73 140.73 zM349.73 155.23 C351.11 155.23 353.73 157.36 353.73 158.73 C353.73 160.11 351.11 160.23 349.73 160.23 C348.36 160.23 347.23 159.11 347.23 157.73 C347.23 156.36 348.36 155.23 349.73 155.23 zM337.73 175.73 C341.73 174.73 341.73 176.73 342.73 180.23 C343.73 183.73 350.8 195.11 339.23 181.23 C336.73 178.23 333.73 176.73 337.73 175.73 zM349.73 187.73 C351.11 187.73 352.23 188.86 352.23 190.23 C352.23 191.61 351.11 192.73 349.73 192.73 C348.36 192.73 347.23 191.61 347.23 190.23 C347.23 188.86 348.36 187.73 349.73 187.73 zM352.23 196.73 C353.61 196.73 354.73 197.86 354.73 199.23 C354.73 200.61 353.61 201.73 352.23 201.73 C350.86 201.73 349.73 200.61 349.73 199.23 C349.73 197.86 350.86 196.73 352.23 196.73 zM352.4 205.73 C353.77 205.73 355.73 208.86 355.73 210.23 C355.73 211.61 354.61 212.73 353.23 212.73 C351.86 212.73 349.07 211.11 349.07 209.73 C349.07 208.36 351.02 205.73 352.4 205.73 zM353.73 221.73 C355.11 221.73 354.73 221.86 354.73 223.23 C354.73 224.61 354.61 223.73 353.23 223.73 C351.86 223.73 352.23 224.61 352.23 223.23 C352.23 221.86 352.36 221.73 353.73 221.73 zM340.23 188.73 C341.61 188.73 341.23 188.86 341.23 190.23 C341.23 191.61 341.11 190.73 339.73 190.73 C338.36 190.73 338.73 191.61 338.73 190.23 C338.73 188.86 338.86 188.73 340.23 188.73 zM343.23 201.23 C344.61 201.23 344.23 201.36 344.23 202.73 C344.23 204.11 344.44 207.73 343.07 207.73 C341.69 207.73 341.73 204.11 341.73 202.73 C341.73 201.36 341.86 201.23 343.23 201.23 zM346.73 215.23 C348.11 215.23 347.73 215.36 347.73 216.73 C347.73 218.11 347.61 217.23 346.23 217.23 C344.86 217.23 345.23 218.11 345.23 216.73 C345.23 215.36 345.36 215.23 346.73 215.23 zM340.57 228.73 C341.94 228.73 341.73 228.86 341.73 230.23 C341.73 231.61 341.44 230.73 340.07 230.73 C338.69 230.73 339.23 231.61 339.23 230.23 C339.23 228.86 339.19 228.73 340.57 228.73 zM349.4 232.07 C350.77 232.07 352.07 234.02 352.07 235.4 C352.07 236.77 349.11 239.23 347.73 239.23 C346.36 239.23 346.73 240.11 346.73 238.73 C346.73 237.36 348.02 232.07 349.4 232.07 zM343.73 246.4 C345.11 246.4 347.4 246.02 347.4 247.4 C347.4 248.77 344.11 251.23 342.73 251.23 C341.36 251.23 341.73 252.11 341.73 250.73 C341.73 249.36 342.36 246.4 343.73 246.4 zM335.23 239.23 C336.61 239.23 336.23 239.36 336.23 240.73 C336.23 242.11 336.11 241.23 334.73 241.23 C333.36 241.23 333.73 242.11 333.73 240.73 C333.73 239.36 333.86 239.23 335.23 239.23 zM332.73 258.4 C334.11 258.4 335.4 260.02 335.4 261.4 C335.4 262.77 333.11 262.23 331.73 262.23 C330.36 262.23 330.73 263.11 330.73 261.73 C330.73 260.36 331.36 258.4 332.73 258.4 zM324.4 263.73 C325.77 263.73 325.07 265.36 325.07 266.73 C325.07 268.11 320.11 271.23 318.73 271.23 C317.36 271.23 317.73 272.11 317.73 270.73 C317.73 269.36 323.02 263.73 324.4 263.73 zM325.23 247.73 C326.61 247.73 326.23 247.86 326.23 249.23 C326.23 250.61 326.11 249.73 324.73 249.73 C323.36 249.73 323.73 250.61 323.73 249.23 C323.73 247.86 323.86 247.73 325.23 247.73 zM313.23 256.23 C314.61 256.23 319.07 258.02 319.07 259.4 C319.07 260.77 313.44 263.07 312.07 263.07 C310.69 263.07 309.73 260.77 309.73 259.4 C309.73 258.02 311.86 256.23 313.23 256.23 zM300.23 260.73 C301.61 260.73 301.23 260.86 301.23 262.23 C301.23 263.61 301.11 262.73 299.73 262.73 C298.36 262.73 298.73 263.61 298.73 262.23 C298.73 260.86 298.86 260.73 300.23 260.73 zM308.23 272.73 C309.61 272.73 309.23 272.86 309.23 274.23 C309.23 275.61 309.11 274.73 307.73 274.73 C306.36 274.73 306.73 275.61 306.73 274.23 C306.73 272.86 306.86 272.73 308.23 272.73 zM305.23 273.73 C306.61 273.73 306.23 273.86 306.23 275.23 C306.23 276.61 306.11 275.73 304.73 275.73 C303.36 275.73 303.73 276.61 303.73 275.23 C303.73 273.86 303.86 273.73 305.23 273.73 zM293.73 274.07 C294.65 274.07 295.73 275.48 295.73 276.4 C295.73 277.32 295.65 276.73 294.73 276.73 C293.82 276.73 291.4 277.98 291.4 277.07 C291.4 276.15 292.82 274.07 293.73 274.07 zM296.73 276.73 C297.65 276.73 297.4 276.82 297.4 277.73 C297.4 278.65 297.32 278.07 296.4 278.07 C295.48 278.07 295.73 278.65 295.73 277.73 C295.73 276.82 295.82 276.73 296.73 276.73 zM291.4 263.73 C292.32 263.73 293.73 267.15 293.73 268.07 C293.73 268.98 290.65 268.73 289.73 268.73 C288.82 268.73 287.4 265.98 287.4 265.07 C287.4 264.15 290.48 263.73 291.4 263.73 zM280.07 274.73 C281.44 274.73 281.23 274.86 281.23 276.23 C281.23 277.61 280.94 276.73 279.57 276.73 C278.19 276.73 278.73 277.61 278.73 276.23 C278.73 274.86 278.69 274.73 280.07 274.73 zM277.07 267.73 C278.44 267.73 276.4 271.02 276.4 272.4 C276.4 273.77 271.94 274.23 270.57 274.23 C269.19 274.23 271.73 272.44 271.73 271.07 C271.73 269.69 275.69 267.73 277.07 267.73 zM52.23 84.9 C56.7 85.46 60.73 85.9 61.73 80.4 C62.73 74.9 60.23 72.9 52.73 74.9 C45.23 76.9 40.23 83.4 52.23 84.9 zM88.73 88.4 C88.73 88.4 107.45 92.81 90.23 79.9 C82.23 73.9 81.73 78.9 81.23 81.9 C80.49 86.37 88.73 88.4 88.73 88.4 zM31.73 47.9 C40.08 46.23 39.73 41.4 30.73 39.4 C29.27 39.07 26.73 48.9 31.73 47.9 zM26.73 47.9 C24.23 47.4 20.23 48.4 19.73 51.9 C19.23 55.4 23.23 57.4 25.73 55.4 C28.23 53.4 29.23 48.4 26.73 47.9 zM32.73 58.9 C30.23 57.9 22.73 59.4 23.23 62.4 C23.73 65.4 29.73 65.9 32.23 64.4 C34.73 62.9 35.23 59.9 32.73 58.9 zM31.73 76.4 C28.73 73.9 25.23 76.4 24.23 77.9 C23.23 79.4 28.23 81.4 29.73 81.9 C31.23 82.4 34.73 78.9 31.73 76.4 zM20.23 39.4 C20.23 39.4 16.23 39.4 17.23 40.9 C18.23 42.4 21.23 42.4 21.23 42.4 zM14.23 48.4 C14.23 48.4 10.23 48.4 11.23 49.9 C12.23 51.4 15.23 51.4 15.23 51.4 zM46.73 96.4 C46.73 96.4 41.73 98.4 42.73 99.9 C43.73 101.4 45.23 103.9 48.73 100.4 C52.23 96.9 46.73 96.4 46.73 96.4 zM60.23 115.9 C57.23 113.4 53.73 115.9 52.73 117.4 C51.73 118.9 56.73 120.9 58.23 121.4 C59.73 121.9 63.23 118.4 60.23 115.9 zM58.23 105.9 C55.23 103.4 52.73 106.9 51.73 108.4 C50.73 109.9 54.73 110.9 56.23 111.4 C57.73 111.9 61.23 108.4 58.23 105.9 zM75.23 72.4 C78.8 72.6 84.73 70.9 75.73 64.9 C67.41 59.35 67.73 60.9 67.23 63.9 C66.49 68.37 71.66 72.2 75.23 72.4 zM105.73 81.4 C105.73 81.4 109.23 78.4 102.23 72.4 C94.64 65.89 95.73 68.4 95.23 71.4 C94.49 75.87 105.73 81.4 105.73 81.4 zM74.73 54.9 C74.73 54.9 68.73 53.9 69.73 55.4 C70.73 56.9 73.23 62.4 76.73 58.9 C80.23 55.4 74.73 54.9 74.73 54.9 zM41.23 85.4 C39.86 85.4 38.73 86.53 38.73 87.9 C38.73 89.28 39.86 90.4 41.23 90.4 C42.61 90.4 43.73 89.28 43.73 87.9 C43.73 86.53 42.61 85.4 41.23 85.4 zM46.23 109.9 C44.86 109.9 43.73 111.03 43.73 112.4 C43.73 113.78 44.86 114.9 46.23 114.9 C47.61 114.9 48.73 113.78 48.73 112.4 C48.73 111.03 47.61 109.9 46.23 109.9 zM50.23 119.9 C48.86 119.9 47.73 121.03 47.73 122.4 C47.73 123.78 48.86 124.9 50.23 124.9 C51.61 124.9 52.73 123.78 52.73 122.4 C52.73 121.03 51.61 119.9 50.23 119.9 zM66.23 126.4 C64.86 126.4 63.73 127.53 63.73 128.9 C63.73 130.28 64.86 131.4 66.23 131.4 C67.61 131.4 68.73 130.28 68.73 128.9 C68.73 127.53 67.61 126.4 66.23 126.4 zM57.73 127.9 C56.36 127.9 53.73 130.03 53.73 131.4 C53.73 132.78 56.36 132.9 57.73 132.9 C59.11 132.9 60.23 131.78 60.23 130.4 C60.23 129.03 59.11 127.9 57.73 127.9 zM33.73 88.9 C32.36 88.9 31.23 90.03 31.23 91.4 C31.23 92.78 32.36 93.9 33.73 93.9 C35.11 93.9 36.23 92.78 36.23 91.4 C36.23 90.03 35.11 88.9 33.73 88.9 zM20.23 65.4 C18.86 65.4 17.73 66.53 17.73 67.9 C17.73 69.28 18.86 70.4 20.23 70.4 C21.61 70.4 22.73 69.28 22.73 67.9 C22.73 66.53 21.61 65.4 20.23 65.4 zM115.23 73.4 C112.91 74.33 101.73 66.9 105.23 65.9 C108.73 64.9 117.73 72.4 115.23 73.4 zM96.23 60.4 C93.73 60.9 86.23 57.9 89.73 56.9 C93.23 55.9 98.87 59.87 96.23 60.4 zM144.23 90.9 C138.73 87.9 123.23 80.4 130.73 81.4 C138.23 82.4 148.96 93.48 144.23 90.9 zM51.73 41.4 C49.23 41.9 41.73 38.9 45.23 37.9 C48.73 36.9 54.37 40.87 51.73 41.4 zM123.73 77.9 C121.23 78.4 116.23 75.9 119.73 74.9 C123.23 73.9 126.37 77.37 123.73 77.9 zM60.73 140.4 C59.36 140.4 58.23 142.03 58.23 143.4 C58.23 144.78 58.86 144.9 60.23 144.9 C61.61 144.9 62.73 143.78 62.73 142.4 C62.73 141.03 62.11 140.4 60.73 140.4 zM68.23 139.9 C66.86 139.9 64.73 140.53 64.73 141.9 C64.73 143.28 67.36 142.9 68.73 142.9 C70.11 142.9 71.23 141.78 71.23 140.4 C71.23 139.03 69.61 139.9 68.23 139.9 zM66.23 154.4 C64.86 154.4 62.23 156.53 62.23 157.9 C62.23 159.28 64.86 159.4 66.23 159.4 C67.61 159.4 68.73 158.28 68.73 156.9 C68.73 155.53 67.61 154.4 66.23 154.4 zM78.23 174.9 C74.23 173.9 74.23 175.9 73.23 179.4 C72.23 182.9 65.17 194.28 76.73 180.4 C79.23 177.4 82.23 175.9 78.23 174.9 zM66.23 186.9 C64.86 186.9 63.73 188.02 63.73 189.4 C63.73 190.77 64.86 191.9 66.23 191.9 C67.61 191.9 68.73 190.77 68.73 189.4 C68.73 188.02 67.61 186.9 66.23 186.9 zM63.73 195.9 C62.36 195.9 61.23 197.02 61.23 198.4 C61.23 199.77 62.36 200.9 63.73 200.9 C65.11 200.9 66.23 199.77 66.23 198.4 C66.23 197.02 65.11 195.9 63.73 195.9 zM63.57 204.9 C62.19 204.9 60.23 208.02 60.23 209.4 C60.23 210.77 61.36 211.9 62.73 211.9 C64.11 211.9 66.9 210.27 66.9 208.9 C66.9 207.52 64.94 204.9 63.57 204.9 zM62.23 220.9 C60.86 220.9 61.23 221.02 61.23 222.4 C61.23 223.77 61.36 222.9 62.73 222.9 C64.11 222.9 63.73 223.77 63.73 222.4 C63.73 221.02 63.61 220.9 62.23 220.9 zM75.73 187.9 C74.36 187.9 74.73 188.02 74.73 189.4 C74.73 190.77 74.86 189.9 76.23 189.9 C77.61 189.9 77.23 190.77 77.23 189.4 C77.23 188.02 77.11 187.9 75.73 187.9 zM72.73 200.4 C71.36 200.4 71.73 200.52 71.73 201.9 C71.73 203.27 71.53 206.9 72.9 206.9 C74.28 206.9 74.23 203.27 74.23 201.9 C74.23 200.52 74.11 200.4 72.73 200.4 zM69.23 214.4 C67.86 214.4 68.23 214.52 68.23 215.9 C68.23 217.27 68.36 216.4 69.73 216.4 C71.11 216.4 70.73 217.27 70.73 215.9 C70.73 214.52 70.61 214.4 69.23 214.4 zM75.4 227.9 C74.03 227.9 74.23 228.02 74.23 229.4 C74.23 230.77 74.53 229.9 75.9 229.9 C77.28 229.9 76.73 230.77 76.73 229.4 C76.73 228.02 76.78 227.9 75.4 227.9 zM66.57 231.23 C65.19 231.23 63.9 233.19 63.9 234.57 C63.9 235.94 66.86 238.4 68.23 238.4 C69.61 238.4 69.23 239.27 69.23 237.9 C69.23 236.52 67.94 231.23 66.57 231.23 zM72.23 245.57 C70.86 245.57 68.57 245.19 68.57 246.57 C68.57 247.94 71.86 250.4 73.23 250.4 C74.61 250.4 74.23 251.27 74.23 249.9 C74.23 248.52 73.61 245.57 72.23 245.57 zM80.73 238.4 C79.36 238.4 79.73 238.52 79.73 239.9 C79.73 241.27 79.86 240.4 81.23 240.4 C82.61 240.4 82.23 241.27 82.23 239.9 C82.23 238.52 82.11 238.4 80.73 238.4 zM83.23 257.57 C81.86 257.57 80.57 259.19 80.57 260.57 C80.57 261.94 82.86 261.4 84.23 261.4 C85.61 261.4 85.23 262.27 85.23 260.9 C85.23 259.52 84.61 257.57 83.23 257.57 zM91.57 262.9 C90.19 262.9 90.9 264.52 90.9 265.9 C90.9 267.27 95.86 270.4 97.23 270.4 C98.61 270.4 98.23 271.27 98.23 269.9 C98.23 268.52 92.94 262.9 91.57 262.9 zM90.73 246.9 C89.36 246.9 89.73 247.02 89.73 248.4 C89.73 249.77 89.86 248.9 91.23 248.9 C92.61 248.9 92.23 249.77 92.23 248.4 C92.23 247.02 92.11 246.9 90.73 246.9 zM102.73 255.4 C101.36 255.4 96.9 257.19 96.9 258.57 C96.9 259.94 102.53 262.23 103.9 262.23 C105.28 262.23 106.23 259.94 106.23 258.57 C106.23 257.19 104.11 255.4 102.73 255.4 zM115.73 259.9 C114.36 259.9 114.73 260.02 114.73 261.4 C114.73 262.77 114.86 261.9 116.23 261.9 C117.61 261.9 117.23 262.77 117.23 261.4 C117.23 260.02 117.11 259.9 115.73 259.9 zM107.73 271.9 C106.36 271.9 106.73 272.02 106.73 273.4 C106.73 274.77 106.86 273.9 108.23 273.9 C109.61 273.9 109.23 274.77 109.23 273.4 C109.23 272.02 109.11 271.9 107.73 271.9 zM110.73 272.9 C109.36 272.9 109.73 273.02 109.73 274.4 C109.73 275.77 109.86 274.9 111.23 274.9 C112.61 274.9 112.23 275.77 112.23 274.4 C112.23 273.02 112.11 272.9 110.73 272.9 zM122.23 273.23 C121.32 273.23 120.23 274.65 120.23 275.57 C120.23 276.48 120.32 275.9 121.23 275.9 C122.15 275.9 124.57 277.15 124.57 276.23 C124.57 275.32 123.15 273.23 122.23 273.23 zM119.23 275.9 C118.32 275.9 118.57 275.98 118.57 276.9 C118.57 277.82 118.65 277.23 119.57 277.23 C120.48 277.23 120.23 277.82 120.23 276.9 C120.23 275.98 120.15 275.9 119.23 275.9 zM124.57 262.9 C123.65 262.9 122.23 266.32 122.23 267.23 C122.23 268.15 125.32 267.9 126.23 267.9 C127.15 267.9 128.57 265.15 128.57 264.23 C128.57 263.32 125.48 262.9 124.57 262.9 zM135.9 273.9 C134.53 273.9 134.73 274.02 134.73 275.4 C134.73 276.77 135.03 275.9 136.4 275.9 C137.78 275.9 137.23 276.77 137.23 275.4 C137.23 274.02 137.28 273.9 135.9 273.9 zM138.9 266.9 C137.53 266.9 139.57 270.19 139.57 271.57 C139.57 272.94 144.03 273.4 145.4 273.4 C146.78 273.4 144.23 271.61 144.23 270.23 C144.23 268.86 140.28 266.9 138.9 266.9 zM211 134.8 C209.63 134.8 209.83 134.93 209.83 136.3 C209.83 137.68 210.13 136.8 211.5 136.8 C212.88 136.8 212.33 137.68 212.33 136.3 C212.33 134.93 212.38 134.8 211 134.8 zM205.5 134.8 C204.13 134.8 204.33 134.93 204.33 136.3 C204.33 137.68 204.63 136.8 206 136.8 C207.38 136.8 206.83 137.68 206.83 136.3 C206.83 134.93 206.88 134.8 205.5 134.8 zM211 143.8 C209.63 143.8 209.83 143.93 209.83 145.3 C209.83 146.68 210.13 145.8 211.5 145.8 C212.88 145.8 212.33 146.68 212.33 145.3 C212.33 143.93 212.38 143.8 211 143.8 zM204.9 143.7 C203.53 143.7 203.73 143.83 203.73 145.2 C203.73 146.58 204.03 145.7 205.4 145.7 C206.78 145.7 206.23 146.58 206.23 145.2 C206.23 143.83 206.28 143.7 204.9 143.7 zM213 154.3 C211.63 154.3 212 155.43 212 156.8 C212 158.18 212.42 161.3 213.8 161.3 C215.17 161.3 214.33 157.18 214.33 155.8 C214.33 154.43 214.38 154.3 213 154.3 zM204 154.3 C202.63 154.3 202.6 155.53 202.6 156.9 C202.6 158.28 201.63 161.5 203 161.5 C204.38 161.5 204.8 157.68 204.8 156.3 C204.8 154.93 205.38 154.3 204 154.3 z"/>
+<!-- Generated by Jasc WebDraw PR4(tm) on 06/07/01 12:18:39 -->
+</svg>
diff --git a/ksvg/test/chem1.svg b/ksvg/test/chem1.svg
new file mode 100644
index 00000000..3ce82439
--- /dev/null
+++ b/ksvg/test/chem1.svg
@@ -0,0 +1,189 @@
+<?xml version="1.0"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG December 1999//EN" "http://www.w3.org/Graphics/SVG/SVG-19991203.dtd" [
+ <!ENTITY st0 "fill:#8C1788;stroke:none;">
+ <!ENTITY st1 "fill:#202020;">
+ <!ENTITY st2 "font-size:0.5;">
+ <!ENTITY st3 "fill:#FF00FF;">
+ <!ENTITY st4 "fill-rule:nonzero;fill:#FFFFFF;stroke:#000000;stroke-width:0.11677;stroke-miterlimit:10;">
+ <!ENTITY st5 "fill:#CF4629;">
+ <!ENTITY st6 "fill:none;stroke:none;">
+ <!ENTITY st7 "font-family:'Helvetica';">
+ <!ENTITY st8 "fill:#727272;">
+ <!ENTITY st9 "fill:#0FF0FF;">
+]>
+
+<svg xmlns="http://www.w3.org/2000/svg"
+ xmlns:html="http://www.w3.org/1999/xhtml" >
+ <g id="Layer_x0020_1" transform="translate(20,20) scale(4)">
+ <g style="&st4;">
+ <g>
+ <!--path id="clip1" style="&st6;" d="M0,144.99951V0h117v144.99951H0z"/-->
+ <!--g style="clip-path:url(#clip1);"-->
+ <g>
+ <path style="&st9;" d="M68.37207,6.72461c0-0.96582-0.78418-1.74951-1.75-1.74951s-1.75,0.78369-1.75,1.74951c0,0.96631,0.78418,1.75,1.75,1.75s1.75-0.78369,1.75-1.75z"/>
+ <path d="M67.49805,7.30713c-0.0459-0.04053-0.12402-0.02832-0.17383,0.02832c-0.05078,0.05615-0.05371,0.13525-0.00879,0.17578l2.00684,2.08496l0.47363-0.53125l-2.29785-1.75781z"/>
+ <path style="&st9;" d="M57.05566,134.40479c0-1.01172-0.82129-1.83301-1.8335-1.83301c-1.01172,0-1.83301,0.82129-1.83301,1.83301s0.82129,1.83301,1.83301,1.83301c1.01221,0,1.8335-0.82129,1.8335-1.83301z"/>
+ <path d="M56.08496,133.62451c-0.0498,0.03809-0.04883,0.12305,0.00244,0.18945c0.05078,0.06641,0.13281,0.08887,0.18262,0.05078l2.64746-1.76562l-0.43896-0.57324l-2.39355,2.09863z"/>
+ <path style="&st9;" d="M88.39062,2.28467c0-1.02002-0.82812-1.84814-1.84863-1.84814c-1.01953,0-1.84766,0.82812-1.84766,1.84814c0,1.02051,0.82812,1.84863,1.84766,1.84863c1.02051,0,1.84863-0.82812,1.84863-1.84863z"/>
+ <path d="M85.7041,3.48047c0.03711-0.04297,0.00977-0.12793-0.06152-0.18994s-0.15918-0.07764-0.19629-0.03467l-2.63672,2.77246l0.51074,0.44531l2.38379-2.99316z"/>
+ <path style="&st9;" d="M23.02002,91.68506c0-1.03711-0.84131-1.87793-1.87793-1.87793c-1.03613,0-1.87744,0.84082-1.87744,1.87793c0,1.03613,0.84131,1.87695,1.87744,1.87695c1.03662,0,1.87793-0.84082,1.87793-1.87695z"/>
+ <path d="M20.74463,91.28857c0.03662,0.05664,0.11572,0.07227,0.17627,0.0332c0.06055-0.03809,0.07959-0.11621,0.04297-0.17383l-0.54785-1.36328l-0.68018,0.43652l1.00879,1.06738z"/>
+ <path style="&st8;" d="M72.99902,10.20459c0-1.3335-1.08301-2.41602-2.41699-2.41602s-2.41602,1.08252-2.41602,2.41602c0,1.33398,1.08203,2.4165,2.41602,2.4165s2.41699-1.08252,2.41699-2.4165z"/>
+ <path d="M72.83887,9.51709c-0.02637,0.00537-0.02441,0.10938,0.00293,0.23145s0.07129,0.2168,0.09668,0.21094l6.54395-1.41309l-0.12793-0.5625l-6.51562,1.5332z"/>
+ <path d="M69.47461,11.83203c0.03809-0.04492,0.00879-0.13232-0.06543-0.1958c-0.07324-0.06396-0.16504-0.0791-0.20312-0.03467l-3.63867,3.96191l0.54102,0.46533l3.36621-4.19678z"/>
+ <path style="&st9;" d="M99.99707,82.92529c0-1.06836-0.86621-1.93555-1.93457-1.93555s-1.93555,0.86719-1.93555,1.93555c0,1.06738,0.86719,1.93457,1.93555,1.93457s1.93457-0.86719,1.93457-1.93457z"/>
+ <path d="M98.41504,83.6958c-0.01953-0.06738-0.09473-0.10449-0.16895-0.08398c-0.07422,0.02148-0.11816,0.09375-0.09863,0.16113l0.24609,1.84863l0.78809-0.22559l-0.7666-1.7002z"/>
+ <path style="&st9;" d="M75.6582,142.68506c0-1.08008-0.87598-1.95605-1.95605-1.95605c-1.0791,0-1.95605,0.87598-1.95605,1.95605c0,1.0791,0.87695,1.95605,1.95605,1.95605c1.08008,0,1.95605-0.87695,1.95605-1.95605z"/>
+ <path d="M72.75391,141.15967c0.02148,0.04785,0.11914,0.05078,0.21777,0.00586c0.09863-0.04395,0.16113-0.11914,0.13965-0.16699l-1.51172-3.70898l-0.61621,0.27734l1.77051,3.59277z"/>
+ <path style="&st8;" d="M84.22949,7.68506c0-1.37305-1.11426-2.4873-2.4873-2.4873s-2.4873,1.11426-2.4873,2.4873c0,1.37256,1.11426,2.4873,2.4873,2.4873s2.4873-1.11475,2.4873-2.4873z"/>
+ <path d="M82.93945,8.58936c-0.05176-0.04688-0.13965-0.03418-0.19727,0.02881s-0.0625,0.15186-0.01074,0.19873l2.6123,2.72949l0.5498-0.60205l-2.9541-2.35498z"/>
+ <path style="&st8;" d="M62.40918,130.80518c0-1.38379-1.12305-2.50684-2.50684-2.50684s-2.50635,1.12305-2.50635,2.50684c0,1.38281,1.12256,2.50586,2.50635,2.50586s2.50684-1.12305,2.50684-2.50586z"/>
+ <path d="M62.30273,131.57373c-0.03027-0.01367-0.0957,0.07031-0.14648,0.18555s-0.06738,0.21973-0.03809,0.23242l5.85156,2.66406l0.24805-0.56152l-5.91504-2.52051z"/>
+ <path d="M58.9292,128.90186c0.02197,0.04883,0.12061,0.05273,0.2207,0.00781s0.16309-0.12109,0.14111-0.16992l-2.21924-5.30664l-0.63574,0.28516l2.49316,5.18359z"/>
+ <path style="&st9;" d="M113.86035,98.04443c0-1.10254-0.89453-1.99805-1.99805-1.99805s-1.99805,0.89551-1.99805,1.99805c0,1.10352,0.89453,1.99902,1.99805,1.99902s1.99805-0.89551,1.99805-1.99902z"/>
+ <path d="M110.7041,97.55322c0.05957,0.03516,0.14551,0.00195,0.19043-0.0752c0.0459-0.07715,0.03418-0.16797-0.02539-0.20312l-2.26562-1.62012l-0.40527,0.68262l2.50586,1.21582z"/>
+ <path style="&st9;" d="M57.85059,19.20459c0-1.11963-0.90869-2.02832-2.02832-2.02832s-2.02832,0.90869-2.02832,2.02832c0,1.12012,0.90869,2.02881,2.02832,2.02881s2.02832-0.90869,2.02832-2.02881z"/>
+ <path d="M57.68164,18.58301c-0.02979,0.00635-0.03174,0.11572-0.00439,0.24365c0.02734,0.12744,0.07373,0.22607,0.10352,0.21973l4.29736-0.84814l-0.12891-0.59961l-4.26758,0.98438z"/>
+ <path style="&st8;" d="M72.93555,135.36475c0-1.43164-1.16211-2.59277-2.59277-2.59277c-1.43164,0-2.59375,1.16113-2.59375,2.59277s1.16211,2.59375,2.59375,2.59375c1.43066,0,2.59277-1.16211,2.59277-2.59375z"/>
+ <path d="M71.625,134.17725c-0.05469,0.04297-0.05273,0.13867,0.00586,0.21289s0.15039,0.09961,0.20508,0.05664l3.47168-2.41797l-0.50586-0.64453l-3.17676,2.79297z"/>
+ <path style="&st9;" d="M49.8418,118.08447c0-1.13672-0.92285-2.05859-2.05957-2.05859s-2.05957,0.92188-2.05957,2.05859s0.92285,2.05957,2.05957,2.05957s2.05957-0.92285,2.05957-2.05957z"/>
+ <path d="M49.67188,118.56982c-0.0332-0.01465-0.10205,0.06934-0.15283,0.18848c-0.05127,0.11816-0.06543,0.22559-0.03174,0.24023l3.85693,1.75586l0.25244-0.58789l-3.9248-1.59668z"/>
+ <path style="&st9;" d="M102.2832,55.20459c0-1.1377-0.92285-2.06104-2.06055-2.06104s-2.06152,0.92334-2.06152,2.06104c0,1.13818,0.92383,2.06152,2.06152,2.06152s2.06055-0.92334,2.06055-2.06152z"/>
+ <path style="&st8;" d="M22.31787,89.40479c0-1.44434-1.17188-2.61523-2.61572-2.61523s-2.61572,1.1709-2.61572,2.61523S18.2583,92.021,19.70215,92.021s2.61572-1.17188,2.61572-2.61621z"/>
+ <path style="&st9;" d="M34.979,77.16455c0-1.14648-0.93018-2.07617-2.07666-2.07617s-2.07715,0.92969-2.07715,2.07617s0.93066,2.07715,2.07715,2.07715s2.07666-0.93066,2.07666-2.07715z"/>
+ <path d="M31.479,78.20459c0.05176-0.03027,0.04834-0.13184-0.00781-0.22754c-0.05566-0.0957-0.14307-0.14844-0.19434-0.11816l-3.21875,1.69141l0.37158,0.63379l3.04932-1.97949z"/>
+ <path d="M20.94287,87.3501c-0.03174,0.04004,0.01807,0.13281,0.11084,0.20605c0.09277,0.07422,0.19385,0.10254,0.22559,0.0625l3.7085-4.43262l-0.54932-0.43848l-3.49561,4.60254z"/>
+ <path d="M17.84473,90.65283c0.0498-0.03027,0.04346-0.13184-0.01465-0.22754s-0.14551-0.14941-0.19531-0.11914l-4.71777,2.66797l0.38184,0.62988l4.5459-2.95117z"/>
+ <path style="&st8;" d="M67.20117,17.40479c0-1.4458-1.17285-2.61914-2.61914-2.61914c-1.44531,0-2.61914,1.17334-2.61914,2.61914s1.17383,2.61914,2.61914,2.61914c1.44629,0,2.61914-1.17334,2.61914-2.61914z"/>
+ <path d="M65.69141,18.29102c-0.05273-0.05078-0.14648-0.03906-0.20801,0.02588c-0.0625,0.06543-0.06934,0.15918-0.01562,0.20947l2.45117,2.69922l0.58984-0.62061l-2.81738-2.31396z"/>
+ <path style="&st8;" d="M58.49414,121.44482c0-1.47461-1.19727-2.67188-2.67188-2.67188s-2.67139,1.19727-2.67139,2.67188s1.19678,2.67188,2.67139,2.67188s2.67188-1.19727,2.67188-2.67188z"/>
+ <path d="M57.06348,120.23389c-0.05664,0.0459-0.05371,0.14355,0.00684,0.21777c0.06006,0.0752,0.15479,0.09961,0.21143,0.05371l3.3374-2.36133l-0.5293-0.65918l-3.02637,2.74902z"/>
+ <path style="&st9;" d="M8.02734,100.92529c0-1.17383-0.95166-2.12598-2.125-2.12598s-2.12549,0.95215-2.12549,2.12598c0,1.17285,0.95215,2.125,2.12549,2.125s2.125-0.95215,2.125-2.125z"/>
+ <path d="M6.94287,99.27393c-0.03271,0.04004,0.01709,0.13477,0.11182,0.21191c0.09424,0.07617,0.19727,0.10547,0.23047,0.06543l2.50293-2.87012l-0.55225-0.44727l-2.29297,3.04004z"/>
+ <path style="&st8;" d="M101.82227,86.5249c0-1.47949-1.2002-2.67969-2.67969-2.67969s-2.68066,1.2002-2.68066,2.67969s1.20117,2.67969,2.68066,2.67969s2.67969-1.2002,2.67969-2.67969z"/>
+ <path d="M101.0625,88.31689c-0.0127-0.01367-0.10938,0.05469-0.2168,0.15234c-0.10742,0.09863-0.18359,0.18945-0.1709,0.20312l4.23047,4.68164l0.44824-0.41016l-4.29102-4.62695z"/>
+ <path d="M97.52441,85.80322c0.06348,0.03809,0.1543,0.00195,0.2041-0.08008c0.0498-0.08105,0.03906-0.17871-0.02344-0.2168L94.43457,83.229l-0.44238,0.73047l3.53223,1.84375z"/>
+ <path style="&st5;" d="M71.26758,89.76514c0-2.03418-1.65137-3.68555-3.68555-3.68555s-3.68457,1.65137-3.68457,3.68555s1.65039,3.68457,3.68457,3.68457s3.68555-1.65039,3.68555-3.68457z"/>
+ <path d="M69.43164,86.68994c-0.02051,0.0293,0.05273,0.11523,0.16309,0.19336c0.11035,0.07715,0.21582,0.11719,0.23633,0.08789l9.1748-12.85645l-0.55664-0.3916l-9.01758,12.9668z"/>
+ <path d="M65.94727,91.87061c0.04688-0.05176,0.02148-0.14941-0.05469-0.2168c-0.07715-0.06738-0.17676-0.08008-0.22266-0.02734l-7.76562,8.41016l0.66699,0.58984l7.37598-8.75586z"/>
+ <path style="&st8;" d="M109.66602,95.16455c0-1.50293-1.2207-2.72266-2.72363-2.72266s-2.72363,1.21973-2.72363,2.72266c0,1.50391,1.2207,2.72363,2.72363,2.72363s2.72363-1.21973,2.72363-2.72363z"/>
+ <path d="M107.43359,96.19775c-0.02344-0.0752-0.1084-0.11523-0.19141-0.08984s-0.13184,0.10645-0.1084,0.18164l0.46387,2.55176l0.88281-0.27051l-1.04688-2.37305z"/>
+ <path style="&st5;" d="M71.94629,50.04492c0-2.07812-1.68652-3.76416-3.76367-3.76416c-2.07812,0-3.76465,1.68604-3.76465,3.76416c0,2.07764,1.68652,3.76416,3.76465,3.76416c2.07715,0,3.76367-1.68652,3.76367-3.76416z"/>
+ <path d="M70.42773,53.0083c-0.01367-0.02197-0.12402,0.02344-0.24512,0.10156s-0.20703,0.15918-0.19336,0.18164l8.56543,13.39551l0.55176-0.35498L70.42773,53.0083z"/>
+ <path d="M66.82422,47.43457c0.02832,0.06201,0.13184,0.07617,0.23145,0.03125c0.10059-0.04443,0.15918-0.13086,0.13184-0.19287l-4.70801-11.14893l-0.79883,0.35547l5.14355,10.95508z"/>
+ <path style="&st8;" d="M29.06299,81.12451c0-1.52344-1.23682-2.76074-2.76074-2.76074s-2.76074,1.2373-2.76074,2.76074c0,1.52441,1.23682,2.76074,2.76074,2.76074s2.76074-1.23633,2.76074-2.76074z"/>
+ <path d="M25.68555,80.34521c0.04004,0.06934,0.13135,0.09082,0.20459,0.04883c0.07275-0.04199,0.1001-0.13184,0.06006-0.20117l-0.67041-1.81543l-0.82666,0.47559l1.23242,1.49219z"/>
+ <path style="&st8;" d="M89.5459,12.24463c0-1.52539-1.23828-2.76318-2.76367-2.76318s-2.76367,1.23779-2.76367,2.76318s1.23828,2.76367,2.76367,2.76367s2.76367-1.23828,2.76367-2.76367z"/>
+ <path d="M89.35352,11.47852c-0.0293,0.00635-0.0293,0.125,0.00195,0.26416c0.03125,0.13965,0.08008,0.24707,0.11035,0.24072l3.95312-0.80664l-0.1416-0.63965l-3.92383,0.94141z"/>
+ <path d="M85.49414,14.1123c0.04395-0.05078,0.01074-0.15137-0.07324-0.22461c-0.08496-0.07324-0.18945-0.09131-0.2334-0.04102l-3.31934,3.52246l0.61133,0.52979l3.01465-3.78662z"/>
+ <path style="&st8;" d="M13.85498,94.56494c0-1.54199-1.25098-2.79297-2.79248-2.79297s-2.79297,1.25098-2.79297,2.79297c0,1.54102,1.25146,2.79199,2.79297,2.79199s2.79248-1.25098,2.79248-2.79199z"/>
+ <path d="M10.5127,93.86475c0.04199,0.06934,0.13477,0.08984,0.20703,0.04492c0.07275-0.04395,0.09717-0.13477,0.05518-0.2041l-0.65137-1.70215l-0.82324,0.50293l1.2124,1.3584z"/>
+ <path style="&st9;" d="M97.65918,10.32471c0-1.23486-1.00195-2.23682-2.2373-2.23682c-1.23438,0-2.23633,1.00195-2.23633,2.23682s1.00195,2.2373,2.23633,2.2373c1.23535,0,2.2373-1.00244,2.2373-2.2373z"/>
+ <path style="&st9;" d="M115.66895,41.5249c0-1.24023-1.00586-2.24707-2.24707-2.24707c-1.24023,0-2.24707,1.00684-2.24707,2.24707s1.00684,2.24707,2.24707,2.24707c1.24121,0,2.24707-1.00684,2.24707-2.24707z"/>
+ <path d="M112.09375,42.71924c0.05664-0.03857,0.0498-0.14697-0.01465-0.24219s-0.16309-0.14111-0.21875-0.10303l-2.70703,1.59717l0.45703,0.67334l2.4834-1.92529z"/>
+ <path style="&st8;" d="M79.42871,130.56494c0-1.57129-1.27539-2.84668-2.84668-2.84668s-2.84668,1.27539-2.84668,2.84668s1.27539,2.84668,2.84668,2.84668s2.84668-1.27539,2.84668-2.84668z"/>
+ <path d="M79.1582,131.3833c-0.03418-0.01465-0.10742,0.08105-0.16309,0.21289c-0.05664,0.13281-0.0752,0.25098-0.04102,0.26562l3.49707,1.58594l0.27148-0.63379l-3.56445-1.43066z"/>
+ <path d="M75.30371,128.38428c0.02539,0.05469,0.1377,0.05859,0.25098,0.00684c0.11426-0.05176,0.18555-0.13867,0.16016-0.19434l-1.98535-4.7627l-0.71484,0.3252l2.28906,4.625z"/>
+ <path style="&st8;" d="M102.71973,53.40479c0-1.57715-1.28027-2.85742-2.85742-2.85742s-2.85742,1.28027-2.85742,2.85742c0,1.57764,1.28027,2.85742,2.85742,2.85742s2.85742-1.27979,2.85742-2.85742z"/>
+ <path d="M101.53906,51.37939c-0.03516,0.03711,0.01367,0.14258,0.10938,0.23535s0.20312,0.1377,0.23926,0.10059l3.89062-3.84033l-0.53809-0.52002l-3.70117,4.02441z"/>
+ <path d="M98.10059,54.92871c0.05664-0.03857,0.04785-0.14844-0.01855-0.24512s-0.16699-0.14355-0.22266-0.10498l-4.06445,2.55713l0.46875,0.68066l3.83691-2.8877z"/>
+ <path style="&st3;" d="M85.8623,70.32471c0-2.53906-2.06055-4.6001-4.59961-4.6001c-2.54004,0-4.60059,2.06104-4.60059,4.6001c0,2.53955,2.06055,4.60059,4.60059,4.60059c2.53906,0,4.59961-2.06104,4.59961-4.60059z"/>
+ <path d="M84.55664,73.45508c-0.01465-0.0166-0.11914,0.0542-0.23242,0.15869c-0.11328,0.10352-0.19238,0.20215-0.17773,0.21875l6.2666,6.88965l0.4873-0.44922l-6.34375-6.81787z"/>
+ <path d="M84.00879,67.03271c-0.03516,0.0376,0.01562,0.14258,0.11426,0.23486s0.20703,0.13721,0.24121,0.09961l5.99219-6.18408l-0.55566-0.52148l-5.79199,6.37109z"/>
+ <path style="&st9;" d="M14.67041,41.5249c0-1.26318-1.02539-2.28809-2.28809-2.28809c-1.26318,0-2.28809,1.0249-2.28809,2.28809c0,1.2627,1.0249,2.28809,2.28809,2.28809c1.2627,0,2.28809-1.02539,2.28809-2.28809z"/>
+ <path d="M14.04004,42.93994c-0.03516-0.04053-0.14551-0.00195-0.24609,0.08594s-0.15381,0.19141-0.11865,0.23193l1.99561,2.4917l0.56641-0.49463l-2.19727-2.31494z"/>
+ <path style="&st8;" d="M72.28125,21.96484c0-1.6001-1.29883-2.89844-2.89941-2.89844c-1.59961,0-2.89844,1.29834-2.89844,2.89844s1.29883,2.89844,2.89844,2.89844c1.60059,0,2.89941-1.29834,2.89941-2.89844z"/>
+ <path d="M72.09961,21.1416c-0.0293,0.00732-0.02539,0.13184,0.00879,0.27832s0.08691,0.25977,0.11621,0.25293l5.67578-1.26514l-0.15625-0.66699l-5.64453,1.40088z"/>
+ <path d="M68.0459,24.01025c0.04395-0.05225,0.00488-0.15723-0.08594-0.23438c-0.0918-0.07715-0.20215-0.09766-0.24609-0.04541l-4.8916,5.4707l0.6543,0.55225l4.56934-5.74316z"/>
+ <path style="&st9;" d="M86.93359,133.92529c0-1.27637-1.03516-2.31152-2.31152-2.31152c-1.27539,0-2.31152,1.03516-2.31152,2.31152c0,1.27539,1.03613,2.31055,2.31152,2.31055c1.27637,0,2.31152-1.03516,2.31152-2.31055z"/>
+ <path style="&st8;" d="M64.75195,116.64502c0-1.61719-1.3125-2.92969-2.92969-2.92969s-2.9292,1.3125-2.9292,2.92969s1.31201,2.92871,2.9292,2.92871s2.92969-1.31152,2.92969-2.92871z"/>
+ <path d="M64.53711,117.51416c-0.0332-0.01465-0.10938,0.08398-0.16895,0.21973c-0.05957,0.13672-0.08203,0.25879-0.04785,0.27344l5.17285,2.37109l0.28516-0.64941l-5.24121-2.21484z"/>
+ <path d="M60.58301,114.38135c0.02539,0.05566,0.14062,0.05957,0.25781,0.00684s0.19238-0.14062,0.16699-0.19727l-3.0293-7.21191l-0.75195,0.33594l3.35645,7.06641z"/>
+ <path style="&st8;" d="M95.60449,82.56494c0-1.62402-1.31738-2.94238-2.94238-2.94238c-1.62402,0-2.94238,1.31836-2.94238,2.94238s1.31836,2.94238,2.94238,2.94238c1.625,0,2.94238-1.31836,2.94238-2.94238z"/>
+ <path d="M93.15137,83.81689c-0.02441-0.08008-0.11621-0.12402-0.20703-0.09668c-0.08984,0.02734-0.14258,0.11426-0.11816,0.19531l0.40527,2.46875l0.94531-0.28516l-1.02539-2.28223z"/>
+ <path style="&st8;" d="M83.62988,19.44482c0-1.63818-1.3291-2.96777-2.96777-2.96777c-1.6377,0-2.96777,1.32959-2.96777,2.96777s1.33008,2.96777,2.96777,2.96777c1.63867,0,2.96777-1.32959,2.96777-2.96777z"/>
+ <path d="M82.08105,20.38965c-0.06348-0.05322-0.16797-0.0332-0.2334,0.04541c-0.06641,0.07812-0.06836,0.18457-0.00488,0.23779l1.46582,1.60498l0.60449-0.71777l-1.83203-1.17041z"/>
+ <path style="&st8;" d="M20.83447,47.64502c0-1.68506-1.36768-3.05225-3.05225-3.05225s-3.05176,1.36719-3.05176,3.05225c0,1.68457,1.36719,3.05176,3.05176,3.05176s3.05225-1.36719,3.05225-3.05176z"/>
+ <path style="&st1;" d="M19.8042,49.51807c-0.03662-0.04199-0.15088-0.00195-0.25439,0.08936c-0.104,0.09131-0.1582,0.19922-0.12109,0.24121l2.2085,2.72461l0.58838-0.51709l-2.42139-2.53809z"/>
+ <path style="&st8;" d="M110.41211,45.60498c0-1.65039-1.33984-2.98975-2.99023-2.98975c-1.64941,0-2.98926,1.33936-2.98926,2.98975c0,1.6499,1.33984,2.98926,2.98926,2.98926c1.65039,0,2.99023-1.33936,2.99023-2.98926z"/>
+ <path style="&st8;" d="M75.39551,121.20459c0-1.66309-1.35059-3.0127-3.01367-3.0127c-1.66211,0-3.0127,1.34961-3.0127,3.0127s1.35059,3.0127,3.0127,3.0127c1.66309,0,3.01367-1.34961,3.01367-3.0127z"/>
+ <path d="M73.81348,119.86377c-0.06543,0.04785-0.06543,0.1582-0.00098,0.24707c0.06543,0.08887,0.1709,0.12207,0.23633,0.07422l2.12207-1.22656l-0.54395-0.74316l-1.81348,1.64844z"/>
+ <path style="&st8;" d="M111.41406,99.96436c0-1.67285-1.3584-3.03125-3.03223-3.03125c-1.67285,0-3.03125,1.3584-3.03125,3.03125c0,1.67383,1.3584,3.03223,3.03125,3.03223c1.67383,0,3.03223-1.3584,3.03223-3.03223z"/>
+ <path d="M110.65625,101.93896c-0.01465-0.01562-0.12402,0.06152-0.24512,0.17188c-0.12109,0.11133-0.20703,0.21387-0.19238,0.22949l2.4248,2.71387l0.50586-0.46289l-2.49316-2.65234z"/>
+ <path d="M106.6582,99.12744c0.07227,0.04199,0.1748,0.00098,0.22852-0.0918c0.05469-0.09277,0.04102-0.20215-0.03027-0.24414l-2.83887-1.99805l-0.48535,0.82422l3.12598,1.50977z"/>
+ <path style="&st8;" d="M95.11914,58.9248c0-1.6875-1.36914-3.05713-3.05664-3.05713s-3.05762,1.36963-3.05762,3.05713s1.37012,3.05713,3.05762,3.05713s3.05664-1.36963,3.05664-3.05713z"/>
+ <path style="&st9;" d="M116.93457,106.56494c0-1.34277-1.08984-2.43262-2.43262-2.43262c-1.3418,0-2.43164,1.08984-2.43164,2.43262s1.08984,2.43262,2.43164,2.43262c1.34277,0,2.43262-1.08984,2.43262-2.43262z"/>
+ <path style="&st8;" d="M27.46826,77.76514c0-1.7041-1.38232-3.08691-3.08594-3.08691s-3.08643,1.38281-3.08643,3.08691c0,1.70312,1.38281,3.08594,3.08643,3.08594s3.08594-1.38281,3.08594-3.08594z"/>
+ <path d="M25.86279,75.39404c-0.03564,0.04688,0.02637,0.1543,0.13867,0.23926s0.23291,0.11621,0.26855,0.06836l4.82275-6.09912l-0.66553-0.50488l-4.56445,6.29639z"/>
+ <path d="M22.2793,79.37939c0.05762-0.03613,0.04736-0.15723-0.02344-0.26953c-0.07031-0.1123-0.1748-0.17383-0.23242-0.13672l-4.06689,2.33594l0.4585,0.72754l3.86426-2.65723z"/>
+ <path style="&st8;" d="M26.95459,54.48486c0-1.75098-1.42139-3.17188-3.17236-3.17188s-3.17188,1.4209-3.17188,3.17188s1.4209,3.17188,3.17188,3.17188s3.17236-1.4209,3.17236-3.17188z"/>
+ <path d="M25.95117,56.47363c-0.03809-0.04297-0.15625-0.00049-0.26416,0.09473c-0.10742,0.09521-0.16357,0.20752-0.12549,0.25049l4.57275,5.39355l0.61963-0.5498l-4.80273-5.18896z"/>
+ <path style="&st8;" d="M12.26025,91.56494c0-1.72168-1.39697-3.11816-3.11816-3.11816c-1.7207,0-3.11768,1.39648-3.11768,3.11816c0,1.7207,1.39697,3.11816,3.11768,3.11816c1.72119,0,3.11816-1.39746,3.11816-3.11816z"/>
+ <path d="M10.77344,89.09131c-0.0376,0.04688,0.02197,0.15723,0.13281,0.24512c0.11084,0.08887,0.23145,0.12207,0.26904,0.0752l3.16455-3.71484l-0.64795-0.51758l-2.91846,3.91211z"/>
+ <path d="M7.09814,93.03662c0.05957-0.03711,0.05176-0.1582-0.01807-0.27148c-0.06934-0.1123-0.17383-0.1748-0.2334-0.1377L4.2583,93.99365L4.70996,94.729l2.38818-1.69238z"/>
+ <path style="&st3;" d="M60.89648,103.08447c0-2.80078-2.27295-5.07422-5.07422-5.07422s-5.07471,2.27344-5.07471,5.07422c0,2.80176,2.27344,5.0752,5.07471,5.0752s5.07422-2.27344,5.07422-5.0752z"/>
+ <path d="M53.60547,99.36084c0.03174,0.0625,0.15576,0.06348,0.27637,0.00098c0.12012-0.06152,0.19238-0.16211,0.16016-0.22461l-5.39795-11.04492l-0.83105,0.4248l5.79248,10.84375z"/>
+ <path d="M53.7251,106.08252c0.05127-0.06543,0.01709-0.17871-0.07666-0.25195c-0.09375-0.07422-0.21143-0.08105-0.26318-0.01465l-3.91992,4.53125l0.77979,0.61426l3.47998-4.87891z"/>
+ <path style="&st3;" d="M65.5957,32.64502c0-2.81201-2.28125-5.09424-5.09375-5.09424c-2.81152,0-5.09375,2.28223-5.09375,5.09424c0,2.81152,2.28223,5.09375,5.09375,5.09375c2.8125,0,5.09375-2.28223,5.09375-5.09375z"/>
+ <path d="M57.31836,35.60352c0.05566-0.0459,0.03076-0.16748-0.05566-0.27051c-0.08594-0.10303-0.20068-0.14941-0.25635-0.10303l-9.36182,7.51514L48.25,43.4707l9.06836-7.86719z"/>
+ <path d="M59.23535,29.1123c0.02197,0.0791,0.13525,0.1167,0.25293,0.08398c0.11719-0.03271,0.19482-0.12402,0.17236-0.20312l-1.22705-5.38574l-0.94336,0.26465l1.74512,5.24023z"/>
+ <path style="&st9;" d="M87.14648,22.80469c0-1.39307-1.13086-2.52393-2.52441-2.52393c-1.39258,0-2.52344,1.13086-2.52344,2.52393c0,1.39355,1.13086,2.52393,2.52344,2.52393c1.39355,0,2.52441-1.13037,2.52441-2.52393z"/>
+ <path style="&st9;" d="M79.72754,117.60498c0-1.40527-1.14062-2.54492-2.54492-2.54492c-1.40527,0-2.54492,1.13965-2.54492,2.54492c0,1.4043,1.13965,2.54492,2.54492,2.54492c1.4043,0,2.54492-1.14062,2.54492-2.54492z"/>
+ <path style="&st9;" d="M35.35547,114.96436c0-1.41992-1.15283-2.57227-2.57324-2.57227s-2.57324,1.15234-2.57324,2.57227c0,1.4209,1.15283,2.57324,2.57324,2.57324s2.57324-1.15234,2.57324-2.57324z"/>
+ <path d="M34.12598,115.25146c-0.08643-0.03027-0.18604,0.02734-0.22217,0.12891c-0.03613,0.10254,0.00488,0.20996,0.09131,0.24023l1.45068,0.85547l0.34619-0.97559l-1.66602-0.24902z"/>
+ <path style="&st8;" d="M97.47168,87.60498c0-1.79395-1.45508-3.25-3.24902-3.25s-3.25,1.45605-3.25,3.25s1.45605,3.25,3.25,3.25c1.79395-0.00098,3.24902-1.45605,3.24902-3.25z"/>
+ <path d="M96.51758,89.7417c-0.01562-0.01758-0.13379,0.06543-0.2627,0.18457c-0.12891,0.11816-0.2207,0.22852-0.20508,0.24609l3.46973,3.84375l0.54199-0.49805l-3.54395-3.77637z"/>
+ <path d="M92.25293,86.81396c0.0791,0.04297,0.1875-0.00391,0.24219-0.10352c0.05469-0.10059,0.03516-0.2168-0.04297-0.25977l-1.58105-1.20605l-0.48535,0.88379l1.86719,0.68555z"/>
+ <path style="&st9;" d="M5.24561,95.5249c0-1.42578-1.15723-2.58301-2.5835-2.58301c-1.42578,0-2.58301,1.15723-2.58301,2.58301s1.15723,2.58301,2.58301,2.58301c1.42627,0,2.5835-1.15723,2.5835-2.58301z"/>
+ <path style="&st8;" d="M19.12451,83.16455c0-1.80078-1.46143-3.26172-3.26221-3.26172s-3.26221,1.46094-3.26221,3.26172s1.46143,3.2627,3.26221,3.2627s3.26221-1.46191,3.26221-3.2627z"/>
+ <path style="&st3;" d="M38.89893,65.64502c0-2.9126-2.36377-5.27686-5.27686-5.27686c-2.9126,0-5.27637,2.36426-5.27637,5.27686s2.36377,5.27637,5.27637,5.27637c2.91309,0,5.27686-2.36377,5.27686-5.27637z"/>
+ <path d="M36.62598,69.51123c-0.03027-0.04443-0.16064-0.00977-0.29248,0.07764c-0.13135,0.0874-0.21387,0.19482-0.18408,0.23975l7.32324,11.26367l0.72119-0.48047l-7.56787-11.10059z"/>
+ <path d="M35.7998,61.1416c-0.02783,0.05029,0.05908,0.15234,0.19385,0.22852c0.13525,0.07617,0.26807,0.09717,0.2959,0.04736l6.67822-11.53174l-0.76807-0.43262L35.7998,61.1416z"/>
+ <path style="&st8;" d="M105.31738,96.12451c0-1.81836-1.47656-3.29395-3.29492-3.29395s-3.29492,1.47559-3.29492,3.29395c0,1.81934,1.47656,3.29492,3.29492,3.29492s3.29492-1.47559,3.29492-3.29492z"/>
+ <path d="M102.56934,97.44092c-0.02734-0.09082-0.13086-0.14062-0.23047-0.11035c-0.10059,0.0293-0.16016,0.12793-0.13281,0.21777l0.03711,1.34473l1.03125-0.30762l-0.70508-1.14453z"/>
+ <path style="&st8;" d="M110.38477,43.08496c0-1.83398-1.48828-3.32227-3.32227-3.32227s-3.32227,1.48828-3.32227,3.32227c0,1.8335,1.48828,3.32227,3.32227,3.32227s3.32227-1.48877,3.32227-3.32227z"/>
+ <path d="M109.02051,40.78271c-0.04199,0.04297,0.01367,0.16553,0.125,0.27393c0.11035,0.10791,0.23438,0.16064,0.27637,0.11768l2.10449-1.94092l-0.6123-0.59961l-1.89355,2.14893z"/>
+ <path d="M104.98828,44.84521c0.06641-0.04395,0.05957-0.17139-0.01562-0.28467s-0.18945-0.16943-0.25586-0.12549l-3.4541,2.01025l0.52637,0.79541l3.19922-2.39551z"/>
+ <path style="&st8;" d="M95.09082,56.16504c0-1.87109-1.51758-3.38916-3.38867-3.38916c-1.87012,0-3.38867,1.51807-3.38867,3.38916c0,1.87061,1.51855,3.38867,3.38867,3.38867c1.87109,0,3.38867-1.51807,3.38867-3.38867z"/>
+ <path d="M93.60547,53.72705c-0.04199,0.04395,0.01465,0.16895,0.12793,0.2793c0.11328,0.10986,0.24023,0.16309,0.2832,0.11914l3.22949-3.10693l-0.63184-0.61377l-3.00879,3.32227z"/>
+ <path d="M89.49902,57.80322c0.07031-0.04395,0.06738-0.17334-0.00488-0.28906c-0.07324-0.11572-0.18945-0.17383-0.25879-0.12988l-2.12793,1.05859l0.51562,0.81982l1.87598-1.45947z"/>
+ <path style="&st9;" d="M115.6582,37.20459c0-1.49902-1.2168-2.71582-2.71582-2.71582s-2.71582,1.2168-2.71582,2.71582c0,1.49951,1.2168,2.71582,2.71582,2.71582s2.71582-1.21631,2.71582-2.71582z"/>
+ <path style="&st9;" d="M91.92383,84.96436c0-1.5127-1.22852-2.74121-2.74121-2.74121c-1.51367,0-2.74219,1.22852-2.74219,2.74121c0,1.51367,1.22852,2.74219,2.74219,2.74219c1.5127,0,2.74121-1.22852,2.74121-2.74219z"/>
+ <path style="&st8;" d="M40.81055,116.64502c0-1.91504-1.55371-3.46875-3.46826-3.46875s-3.46826,1.55371-3.46826,3.46875c0,1.91406,1.55371,3.46777,3.46826,3.46777s3.46826-1.55371,3.46826-3.46777z"/>
+ <path d="M40.43652,115.104c-0.02148,0.00781,0.01318,0.1582,0.07764,0.33496c0.06445,0.17773,0.13428,0.31543,0.15576,0.30762l4.53174-1.59375l-0.26709-0.7334l-4.49805,1.68457z"/>
+ <path d="M35.93115,118.5415c0.06104-0.07031,0.03271-0.19531-0.06348-0.2793c-0.0957-0.08496-0.22363-0.09668-0.28467-0.02734l-2.31934,2.18652l0.7959,0.7002l1.87158-2.58008z"/>
+ <path style="&st8;" d="M60.83105,21.24463c0-1.96973-1.59912-3.56787-3.56885-3.56787s-3.56836,1.59814-3.56836,3.56787s1.59863,3.56836,3.56836,3.56836s3.56885-1.59863,3.56885-3.56836z"/>
+ <path style="&st1;" d="M56.28857,18.94678c0.02832,0.08887,0.15088,0.12891,0.27441,0.08984s0.20068-0.14307,0.17236-0.23193l-0.29102-1.88672l-1.00586,0.32031l0.8501,1.7085z"/>
+ <path style="&st8;" d="M51.8916,112.56494c0-1.9375-1.57227-3.50879-3.50928-3.50879s-3.50928,1.57129-3.50928,3.50879c0,1.93652,1.57227,3.50879,3.50928,3.50879s3.50928-1.57227,3.50928-3.50879z"/>
+ <path d="M50.04199,113.08154c-0.09229-0.03809-0.20264,0.01855-0.24658,0.125c-0.04346,0.10742-0.00439,0.22461,0.08789,0.2627l1.98291,1.19922l0.43115-1.05469l-2.25537-0.53223z"/>
+ <path style="&st9;" d="M17.08887,80.88525c0-1.53906-1.24854-2.78711-2.78662-2.78711s-2.78662,1.24805-2.78662,2.78711c0,1.53809,1.24854,2.78613,2.78662,2.78613s2.78662-1.24805,2.78662-2.78613z"/>
+ <path style="&st8;" d="M102.66309,48.36475c0-1.94336-1.57715-3.52051-3.52051-3.52051s-3.52051,1.57715-3.52051,3.52051s1.57715,3.521,3.52051,3.521s3.52051-1.57764,3.52051-3.521z"/>
+ <path style="&st5;" d="M51.19336,84.60498c0-2.67773-2.17334-4.85156-4.85107-4.85156s-4.85107,2.17383-4.85107,4.85156s2.17334,4.85059,4.85107,4.85059s4.85107-2.17285,4.85107-4.85059z"/>
+ <path style="&st9;" d="M105.90332,99.84521c0-1.54688-1.25488-2.80078-2.80078-2.80078s-2.80078,1.25391-2.80078,2.80078c0,1.5459,1.25488,2.80078,2.80078,2.80078s2.80078-1.25488,2.80078-2.80078z"/>
+ <path style="&st9;" d="M88.27539,60.00488c0-1.55322-1.25977-2.81348-2.81348-2.81348c-1.55273,0-2.81348,1.26025-2.81348,2.81348c0,1.55273,1.26074,2.81348,2.81348,2.81348c1.55371,0,2.81348-1.26074,2.81348-2.81348z"/>
+ <path style="&st5;" d="M49.66162,45.72461c0-2.69336-2.18604-4.87939-4.87939-4.87939s-4.87939,2.18604-4.87939,4.87939c0,2.69385,2.18604,4.87988,4.87939,4.87988s4.87939-2.18604,4.87939-4.87988z"/>
+ <path style="&st9;" d="M26.45752,125.64502c0-1.60938-1.30615-2.91504-2.91504-2.91504c-1.60938,0-2.91553,1.30566-2.91553,2.91504s1.30615,2.91504,2.91553,2.91504c1.60889,0,2.91504-1.30566,2.91504-2.91504z"/>
+ <path d="M26.06885,124.36475c-0.02539,0.00879,0.00781,0.16797,0.07324,0.35449c0.06543,0.1875,0.13916,0.33301,0.16406,0.32422l2.37109-0.77148l-0.27344-0.7832l-2.33496,0.87598z"/>
+ <path style="&st8;" d="M58.88086,14.64502c0-2.08594-1.69287-3.77881-3.77832-3.77881c-2.08594,0-3.77881,1.69287-3.77881,3.77881c0,2.08545,1.69287,3.77832,3.77881,3.77832c2.08545,0,3.77832-1.69287,3.77832-3.77832z"/>
+ <path d="M54.13379,12.19873c0.02979,0.09424,0.16016,0.13721,0.29053,0.0957c0.13037-0.04102,0.21191-0.15137,0.18164-0.24561l-0.12354-1.40381l-1.05518,0.33447l0.70654,1.21924z"/>
+ <path style="&st8;" d="M35.77246,122.64502c0-2.04785-1.66211-3.70996-3.70996-3.70996c-2.04834,0-3.71045,1.66211-3.71045,3.70996s1.66211,3.70996,3.71045,3.70996c2.04785,0,3.70996-1.66211,3.70996-3.70996z"/>
+ <path d="M33.83447,123.15283c-0.09814-0.03809-0.21338,0.02344-0.25781,0.1377s-0.00049,0.2373,0.09766,0.27539l1.80908,1.10547l0.43311-1.11523l-2.08203-0.40332z"/>
+ <path style="&st9;" d="M101.77441,46.56494c0-1.65186-1.34082-2.99219-2.99219-2.99219s-2.99219,1.34033-2.99219,2.99219c0,1.65137,1.34082,2.9917,2.99219,2.9917s2.99219-1.34033,2.99219-2.9917z"/>
+ <path style="&st8;" d="M57.5791,114.84521c0-2.09668-1.70117-3.79688-3.79688-3.79688s-3.79688,1.7002-3.79688,3.79688c0,2.0957,1.70117,3.79688,3.79688,3.79688s3.79688-1.70117,3.79688-3.79688z"/>
+ <path d="M57.23242,113.26318c-0.03027,0.01074,0.00049,0.1748,0.06836,0.36523c0.06738,0.19043,0.14697,0.33594,0.17725,0.3252l2.18604-0.70605l-0.29102-0.81738l-2.14062,0.83301z"/>
+ <path d="M52.31934,116.99463c0.06641-0.07617,0.03467-0.21289-0.0708-0.30469c-0.10547-0.09277-0.24512-0.10449-0.31201-0.02832l-2.03076,1.84375l0.86865,0.75684l1.54492-2.26758z"/>
+ <path style="&st9;" d="M65.3457,111.84521c0-1.68066-1.36328-3.04395-3.04297-3.04395c-1.68066,0-3.04395,1.36328-3.04395,3.04395c0,1.67969,1.36328,3.04297,3.04395,3.04297c1.67969,0,3.04297-1.36328,3.04297-3.04297z"/>
+ <path style="&st9;" d="M56.37695,8.76465c0-1.69678-1.37744-3.07422-3.07471-3.07422s-3.07471,1.37744-3.07471,3.07422c0,1.69727,1.37744,3.07471,3.07471,3.07471s3.07471-1.37744,3.07471-3.07471z"/>
+ <path style="&st8;" d="M41.57275,124.80518c0-2.20312-1.7876-3.99023-3.99023-3.99023s-3.99072,1.78711-3.99072,3.99023c0,2.20215,1.78809,3.99023,3.99072,3.99023s3.99023-1.78809,3.99023-3.99023z"/>
+ <path d="M41.16113,123.15869c-0.02637,0.00879,0.01074,0.18164,0.08301,0.38477c0.07227,0.2041,0.15234,0.36133,0.17871,0.35254l3.51953-1.18652l-0.30127-0.84863l-3.47998,1.29785z"/>
+ <path d="M35.95752,127.05322c0.07178-0.0791,0.04053-0.22363-0.06885-0.32129c-0.10938-0.09863-0.25586-0.11328-0.32715-0.0332l-1.09717,0.72852l0.88818,0.79688l0.60498-1.1709z"/>
+ <path style="&st8;" d="M52.53418,120.96436c0-2.22559-1.80615-4.03125-4.03174-4.03125c-2.22607,0-4.03223,1.80566-4.03223,4.03125c0,2.22656,1.80615,4.03223,4.03223,4.03223c2.22559,0,4.03174-1.80566,4.03174-4.03223z"/>
+ <path d="M50.55957,121.4585c-0.10693-0.04004-0.23145,0.02832-0.27832,0.15332c-0.04688,0.12402,0.00195,0.25781,0.10889,0.29785l0.71191,0.68848l0.44629-1.18945l-0.98877,0.0498z"/>
+ <path style="&st9;" d="M36.68945,129.48486c0-1.8252-1.48145-3.30762-3.30713-3.30762s-3.30713,1.48242-3.30713,3.30762s1.48145,3.30762,3.30713,3.30762s3.30713-1.48242,3.30713-3.30762z"/>
+ <path style="&st9;" d="M56.18604,122.5249c0-1.85742-1.50684-3.36426-3.36377-3.36426s-3.36377,1.50684-3.36377,3.36426c0,1.85645,1.50684,3.36426,3.36377,3.36426s3.36377-1.50781,3.36377-3.36426z"/>
+ </g>
+ </g>
+ </g>
+ </g>
+</svg>
+
diff --git a/ksvg/test/colortest.svg b/ksvg/test/colortest.svg
new file mode 100644
index 00000000..a237e591
--- /dev/null
+++ b/ksvg/test/colortest.svg
@@ -0,0 +1,18 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010719//EN"
+ "http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd">
+<svg width="8cm" height="3cm" viewBox="0 0 800 300">
+ <rect x="1" y="1" width="798" height="298"
+ fill="none" stroke="blue" stroke-width="2" />
+ <rect id="RectElement" x="300" y="100" width="300" height="100"
+ fill="rgb(0,0,255)" stroke="rgb(128,0,0)" stroke-width="0.7cm">
+
+ <animateColor attributeName="fill" attributeType="CSS"
+ from="rgb(0,0,255)" to="rgb(128,0,0)"
+ begin="1s" dur="6s" fill="freeze" />
+ <animateColor attributeName="stroke" attributeType="CSS"
+ from="rgb(128,0,0)" to="rgb(0,0,255)"
+ begin="1s" dur="6s" fill="freeze" />
+
+ </rect>
+</svg>
diff --git a/ksvg/test/dashes.svg b/ksvg/test/dashes.svg
new file mode 100644
index 00000000..f11c043e
--- /dev/null
+++ b/ksvg/test/dashes.svg
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg width="525" height="500" >
+<text x="5" y="20" style="font-size:22">Stroke Option: line dashing</text>
+ <g style="shape-rendering:default; stroke-width:14; stroke:#0000FF" >
+ <path d="M50, 50h200" style="stroke-linecap:round; stroke-dasharray:30 30" />
+ <path d="M50,100h200" style="stroke-linecap:square; stroke-dasharray:30 30" />
+ <path d="M50,150h200" style="stroke-linecap:butt; stroke-dasharray:30 30" />
+ <path d="M50,200h200" style="stroke-linecap:butt; stroke-dasharray:30 5" />
+ <path d="M50,250h200" style="stroke-linecap:butt; stroke-dasharray:5 5" />
+ <path d="M50,300h200" style="stroke-linecap:butt; stroke-dasharray:15 15" />
+ <path d="M50,350h200" style="stroke-linecap:butt; stroke-dasharray:10 15" />
+ <path d="M50,400h200" style="stroke-linecap:butt; stroke-dasharray:20 5 10 5" />
+ </g>
+
+ <g style="shape-rendering:default; stroke-width:6; stroke:#008000" >
+ <path d="M300, 50h200" style="stroke-linecap:round; stroke-dasharray:30 20 15 20" />
+ <path d="M300,100h200" style="stroke-linecap:square; stroke-dasharray:30 20 15 20" />
+ <path d="M300,150h200" style="stroke-linecap:butt; stroke-dasharray:10 5 20 5" />
+ <path d="M300,200h200" style="stroke-linecap:butt; stroke-dasharray:40 5 25 5" />
+ <path d="M300,250h200" style="stroke-linecap:butt; stroke-dasharray:5 5" />
+ <path d="M300,300h200" style="stroke-linecap:butt; stroke-dasharray:15 15" />
+ <path d="M300,350h200" style="stroke-linecap:butt; stroke-dasharray:10 15" />
+ <path d="M300,400h200" style="stroke-linecap:butt; stroke-dasharray:20 5 10 5" />
+ </g>
+</svg>
+
+
+
+
+
+
diff --git a/ksvg/test/ecma/bbox/bbox-circle.svg b/ksvg/test/ecma/bbox/bbox-circle.svg
new file mode 100644
index 00000000..10ff5e3c
--- /dev/null
+++ b/ksvg/test/ecma/bbox/bbox-circle.svg
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg id="svg-root" width="450" height="450" onload="gen_buttons(evt, 6)">
+ <script xlink:href="bbox.js"/>
+ <g>
+ <circle id="test-0" cx="100" cy="140" r="50" fill="none" stroke="black" />
+ <circle id="test-1" cx="220" cy="140" r="35" fill="red" stroke="black" />
+ <circle id="test-2" cx="340" cy="140" r="20" fill="black" stroke="lime" stroke-width="4" />
+ <circle id="test-3" cx="100" cy="260" r="20" stroke="lime" fill="yellow" stroke-width="4" />
+ <circle id="test-4" cx="220" cy="260" r="35" stroke="none" fill="blue" />
+ <circle id="test-5" cx="340" cy="260" r="50" stroke="red" fill="none" stroke-width="10" />
+ </g>
+</svg>
diff --git a/ksvg/test/ecma/bbox/bbox-ellipse.svg b/ksvg/test/ecma/bbox/bbox-ellipse.svg
new file mode 100644
index 00000000..0fccee5b
--- /dev/null
+++ b/ksvg/test/ecma/bbox/bbox-ellipse.svg
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg id="svg-root" width="450" height="450" onload="gen_buttons(evt, 7)">
+ <script xlink:href="bbox.js"/>
+ <g>
+ <ellipse id="test-0" fill="none" stroke="#000000" cx="50" cy="135" rx="30" ry="50"/>
+ <ellipse id="test-1" fill="red" cx="160" cy="135" rx="30" ry="50"/>
+ <ellipse id="test-2" fill="none" stroke="#000000" cx="270" cy="140" rx="35" ry="35"/>
+ <ellipse id="test-3" fill="red" cx="370" cy="140" rx="35" ry="35"/>
+ <ellipse id="test-4" fill="none" stroke="#0000FF" stroke-width="8" cx="50" cy="310" rx="30" ry="50"/>
+ <ellipse id="test-5" fill="#00FF00" stroke="#0000FF" stroke-width="8" cx="160" cy="310" rx="30" ry="50"/>
+ <ellipse id="test-6" fill="#00FF00" stroke="#0000FF" stroke-width="8" cx="330" cy="310" rx="70" ry="40"/>
+ </g>
+</svg>
diff --git a/ksvg/test/ecma/bbox/bbox-line.svg b/ksvg/test/ecma/bbox/bbox-line.svg
new file mode 100644
index 00000000..b9caf551
--- /dev/null
+++ b/ksvg/test/ecma/bbox/bbox-line.svg
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg id="svg-root" width="450" height="450" onload="gen_buttons(evt, 4)">
+ <script xlink:href="bbox.js"/>
+ <g>
+ <g id="test-0" transform="translate(0,20)">
+ <line x1="37.5" y1="137" x2="112.5" y2="50" fill="none" stroke="black" stroke-width="1" />
+ <line x1="112.5" y1="137" x2="187.5" y2="50" fill="none" stroke="red" stroke-width="5" />
+ <line x1="187.5" y1="137" x2="262.5" y2="50" fill="none" stroke="green" stroke-width="7.5" />
+ <line x1="262.5" y1="137" x2="337.5" y2="50" fill="none" stroke="blue" stroke-width="10" />
+ <line x1="337.5" y1="137" x2="412.5" y2="50" fill="none" stroke="fuchsia" stroke-width="12.5" />
+ </g>
+ <g id="test-1" stroke="black" stroke-width="1" transform="translate(0,20)">
+ <line x1="125" y1="200" x2="175" y2="200"/>
+ <line x1="175" y1="200" x2="175" y2="250"/>
+ <line x1="175" y1="250" x2="225" y2="250"/>
+ <line x1="225" y1="250" x2="225" y2="200"/>
+ <line x1="225" y1="200" x2="275" y2="200"/>
+ </g>
+ <g id="test-2" stroke="blue" stroke-width="10" transform="translate(0,20)">
+ <line x1="25" y1="300" x2="75" y2="300"/>
+ <line x1="75" y1="300" x2="75" y2="350"/>
+ <line x1="75" y1="350" x2="125" y2="350"/>
+ <line x1="125" y1="350" x2="125" y2="300"/>
+ <line x1="125" y1="300" x2="175" y2="300"/>
+ </g>
+ <g id="test-3" stroke-width="10" transform="translate(0,20)">
+ <line x1="275" y1="350" x2="325" y2="350" stroke="black" />
+ <line x1="325" y1="300" x2="375" y2="300" stroke="fuchsia" />
+ <line x1="225" y1="300" x2="275" y2="300" stroke="blue" />
+ <line x1="275" y1="300" x2="275" y2="350" stroke="green" />
+ <line x1="325" y1="350" x2="325" y2="300" stroke="red" />
+ </g>
+ </g>
+</svg>
diff --git a/ksvg/test/ecma/bbox/bbox-path.svg b/ksvg/test/ecma/bbox/bbox-path.svg
new file mode 100644
index 00000000..bdfd24fe
--- /dev/null
+++ b/ksvg/test/ecma/bbox/bbox-path.svg
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg id="svg-root" width="450" height="450" onload="gen_buttons(evt, 8)">
+ <script xlink:href="bbox.js"/>
+ <g transform="translate(0,50)">
+ <path id="test-0" fill="#FF0000" stroke="#00C000" d=" M 250 130 C 185 130 150 80 150 80 S 115 25 50 25 m 0 105 c 65 0 100 -50 100 -50 s 35 -55 100 -55 "/>
+ <path id="test-1" fill="none" stroke="#000000" d=" M 300 90 c 0 30 7 50 50 0 c 43 -50 50 -30 50 0 c 0 83 -68 -34 -90 -30 C 300 60 300 90 300 90 z "/>
+ <path id="test-2" fill="none" stroke="#000000" d=" M 100 170 C 120 170 180 170 200 170 Z "/>
+ <path id="test-3" fill="#00C000" stroke="none" d=" M 25 360 C 60 360 80 275 75 260 c -5 15 15 100 50 100 Z "/>
+ <path id="test-4" fill="none" stroke="#000000" d=" m 200 300 c 50 -40 50 -100 25 -100 s -25 60 25 100 "/>
+ <path id="test-5" fill="#0000FF" stroke="#000000" d=" M 320 160 C 380 150 420 190 410 250 "/>
+ <path id="test-6" fill="#FFFF00" stroke="#000000" d=" M 360 280 c 0 20 -16 36 -36 36 s -36 -16 -36 -36 s 16 -36 36 -36 s 36 16 36 36 z "/>
+ <path id="test-7" fill="#F0F0F0" stroke="#FF0000" d=" m 340 425 c -40 -60 95 -100 80 0 z "/>
+ </g>
+</svg>
diff --git a/ksvg/test/ecma/bbox/bbox-path2.svg b/ksvg/test/ecma/bbox/bbox-path2.svg
new file mode 100644
index 00000000..988641a1
--- /dev/null
+++ b/ksvg/test/ecma/bbox/bbox-path2.svg
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg id="svg-root" width="450" height="480" onload="gen_buttons(evt, 7)">
+ <script xlink:href="bbox.js"/>
+ <g transform="translate(0,70)">
+ <path id="test-0" fill="none" stroke="#0000FF" stroke-width="3" d=" M 15 20 Q 30 120 130 30 M 180 80 q -75 -100 -163 -60 z "/>
+ <path id="test-1" fill="#FFFF00" stroke="#CF0000" d=" m 350 130 q -100 -80 50 -120 z m 70 0 q 50 -150 -80 -90 Z "/>
+ <path id="test-2" fill="none" stroke="#00FFFF" d=" M 215 115 Q 225 0 295 45 Z "/>
+ <path id="test-3" fill="#00C000" stroke="#000000" d=" M 200 200 Q 250 300 300 200 T 250 150 Q 120 120 200 200 z "/>
+ <path id="test-4" fill="#CF0000" stroke="none" d=" M 60 100 Q -40 150 60 200 Q 160 150 60 100 z "/>
+ <path id="test-5" fill="none" stroke="#FF0000" d=" M 15 320 q 25 -100 50 0 t 50 0 t 50 0 t 50 0 t 50 0 z "/>
+ <path id="test-6" fill="#0000C0" stroke="#00CF00" stroke-width="2" d=" M 350 300 q -100 50 0 50 Q 250 350 350 400 q 100 -50 0 -50 Q 450 350 350 300 z "/>
+ </g>
+</svg>
diff --git a/ksvg/test/ecma/bbox/bbox-polygon.svg b/ksvg/test/ecma/bbox/bbox-polygon.svg
new file mode 100644
index 00000000..025bdeb5
--- /dev/null
+++ b/ksvg/test/ecma/bbox/bbox-polygon.svg
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg id="svg-root" width="450" height="450" onload="gen_buttons(evt, 6)">
+ <script xlink:href="bbox.js"/>
+ <g>
+ <polygon id="test-0" fill="none" stroke="#000000" points="59,75,95,93,108,135,82,169,39,170,11,137,19,95"/>
+ <polygon id="test-1" fill="red" points="179,75,218,93,228,135,202,169,159,170,131,137,139,95,179,75"/>
+ <polygon id="test-2" fill="blue" stroke="black" stroke-width="6" points="350,75 375,110 410,125 375,140 350,175 325,150 290,125 325,100,350,75"/>
+ <polygon id="test-3" fill="none" stroke="#0000FF" stroke-width="8" points="59,225,98,243,108,285,82,319,39,320,11,287,19,245,59,225"/>
+ <polygon id="test-4" fill="#00FF00" stroke="#0000FF" stroke-width="8" points="179,225,218,243,228,285,202,319,159,320,131,287,139,245"/>
+ <polygon id="test-5" fill="none" stroke="#00FF00" stroke-width="8" points="270,265 300,285 320,265 340,285 280,320 390,320 420,280 280,225"/>
+ </g>
+</svg>
diff --git a/ksvg/test/ecma/bbox/bbox-polyline.svg b/ksvg/test/ecma/bbox/bbox-polyline.svg
new file mode 100644
index 00000000..c60321da
--- /dev/null
+++ b/ksvg/test/ecma/bbox/bbox-polyline.svg
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg id="svg-root" width="450" height="450" onload="gen_buttons(evt, 6)">
+ <script xlink:href="bbox.js"/>
+ <g>
+ <polyline id="test-0" fill="none" stroke="#000000" points="10,80,35,180,60,80,85,180,110,80,135,180"/>
+ <polyline id="test-1" fill="none" stroke="blue" stroke-width="8" points="220,80,267,114,249,170,190,170,172,114,220,80"/>
+ <polyline id="test-2" fill="blue" stroke="#00FF00" stroke-width="4" points="310,80,335,180,360,80,385,180,410,80,435,180"/>
+ <polyline id="test-3" fill="none" stroke="red" stroke-width="8" points="59,225,98,243,108,285,82,319,39,320,11,287,19,245"/>
+ <polyline id="test-4" fill="#00FF00" stroke="#0000FF" stroke-width="8" points="189,225,228,243,238,285,212,319,169,320,141,287,149,245"/>
+ <polyline id="test-5" fill="#FF00FF" stroke="none" stroke-width="8" points="270,265 300,285 320,265 340,285 280,320 390,320 420,280 280,225"/>
+ </g>
+</svg>
diff --git a/ksvg/test/ecma/bbox/bbox-rect.svg b/ksvg/test/ecma/bbox/bbox-rect.svg
new file mode 100644
index 00000000..b35285ec
--- /dev/null
+++ b/ksvg/test/ecma/bbox/bbox-rect.svg
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg id="svg-root" width="450" height="450" onload="gen_buttons(evt, 8)">
+ <script xlink:href="bbox.js"/>
+ <g>
+ <rect id="test-0" fill="none" stroke="#000000" x="30" y="86" width="50" height="100"/>
+ <rect id="test-1" fill="red" x="130" y="86" width="50" height="100"/>
+ <rect id="test-2" fill="none" stroke="#000000" x="250" y="86" width="50" height="100" rx="30"/>
+ <rect id="test-3" fill="red" x="350" y="86" width="50" height="100" rx="30"/>
+ <rect id="test-4" fill="none" stroke="#0000FF" stroke-width="8" x="30" y="266" width="50" height="100"/>
+ <rect id="test-5" fill="#00FF00" stroke="#0000FF" stroke-width="8" x="130" y="266" width="50" height="100"/>
+ <rect id="test-6" fill="none" stroke="#0000FF" stroke-width="8" x="250" y="266" width="50" height="100" rx="30" ry="50"/>
+ <rect id="test-7" fill="#00FF00" x="350" y="266" width="50" height="100" rx="30" ry="50"/>
+ </g>
+</svg>
diff --git a/ksvg/test/ecma/bbox/bbox.js b/ksvg/test/ecma/bbox/bbox.js
new file mode 100644
index 00000000..2d692694
--- /dev/null
+++ b/ksvg/test/ecma/bbox/bbox.js
@@ -0,0 +1,103 @@
+function clear_test(evt, number)
+{
+ for(var i = 0; i < number; i++)
+ {
+ var element = evt.target.getOwnerDocument().getElementById("bbox" + (i + 1));
+ element.getParentNode().removeChild(element);
+ }
+}
+
+function bbox_loop(drawit, number)
+{
+ var doc = evt.target.getOwnerDocument();
+
+ for(var i = 0; i < number; i++)
+ {
+ var shape = doc.getElementById("test-" + i);
+ var bbox = shape.getBBox();
+
+ if(drawit == "true")
+ {
+ draw_it(doc, bbox, shape, i + 1);
+ }
+ else
+ {
+ do_string(bbox, i + 1);
+ }
+ }
+}
+
+function do_string(shape, number)
+{
+ var string = "\nShape " + number + "\nX = " + shape.x + "\nY = " + shape.y + "\nW = " + shape.width + "\nH = " + shape.height;
+ alert(string);
+}
+
+function draw_it(doc, bbox, shape, number)
+{
+ var element = doc.createElement("rect");
+ element.setAttribute("x", bbox.x);
+ element.setAttribute("y", bbox.y);
+ element.setAttribute("width", bbox.width);
+ element.setAttribute("height", bbox.height);
+ element.setAttribute("fill", "none");
+ element.setAttribute("stroke", "red");
+ element.setAttribute("stroke-width", "3");
+ element.setAttribute("id", "bbox" + number);
+
+ shape.getParentNode().appendChild(element);
+}
+
+function gen_buttons(evt, number)
+{
+ var doc = evt.target.getOwnerDocument();
+ var main = doc.getElementById("svg-root");
+
+ var aone = doc.createElement("a");
+ var atwo = doc.createElement("a");
+ var athree = doc.createElement("a");
+
+ var rect = doc.createElement("rect");
+ var text = doc.createElement("text");
+
+ aone.setAttribute("onclick", "bbox_loop('false'," + number + ")");
+
+ atwo.setAttribute("onclick", "bbox_loop('true'," + number + ")");
+ atwo.setAttribute("transform", "translate(0,22)");
+
+ athree.setAttribute("onclick", "clear_test(evt," + number + ")");
+ athree.setAttribute("transform", "translate(0,44)");
+
+ rect.setAttribute("x", "0");
+ rect.setAttribute("y", "0");
+ rect.setAttribute("width", "110");
+ rect.setAttribute("height", "20");
+
+ text.setAttribute("x", "0");
+ text.setAttribute("y", "15");
+ text.setAttribute("fill", "white");
+
+ // First button
+ aone.appendChild(rect.cloneNode(1));
+ var aonetext = text.cloneNode(1);
+ aonetext.appendChild(doc.createTextNode("Calculate bbox"));
+ aone.appendChild(aonetext);
+
+ main.appendChild(aone);
+
+ // Second button
+ atwo.appendChild(rect.cloneNode(1));
+ var atwotext = text.cloneNode(1);
+ atwotext.appendChild(doc.createTextNode("Draw bbox"));
+ atwo.appendChild(atwotext);
+
+ main.appendChild(atwo);
+
+ // Third button
+ athree.appendChild(rect.cloneNode(1));
+ var athreetext = text.cloneNode(1);
+ athreetext.appendChild(doc.createTextNode("Clear bbox drawing"));
+ athree.appendChild(athreetext);
+
+ main.appendChild(athree);
+}
diff --git a/ksvg/test/ecma/broken.svg b/ksvg/test/ecma/broken.svg
new file mode 100644
index 00000000..82eb021e
--- /dev/null
+++ b/ksvg/test/ecma/broken.svg
@@ -0,0 +1,30 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010719//EN"
+ "http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd">
+<svg width="6cm" height="5cm" viewBox="0 0 600 500">
+ <desc>Example script01 - invoke an ECMAScript function from an onclick event
+ </desc>
+ <!-- ECMAScript to change the radius with each click -->
+ <script type="text/ecmascript"> <![CDATA[
+ function circle_click(evt) {
+ var circle = evt.target;
+ var currentRadius = circle.r.baseVal.value;
+ if (currentRadius == 100)
+ circle.r.baseVal.value = currentRadius*2;
+ else
+ circle.r.baseVal.value = currentRadius*0.5;
+ }
+ ]]> </script>
+
+ <!-- Outline the drawing area with a blue line -->
+ <rect x="1" y="1" width="598" height="498" fill="none" stroke="blue"/>
+
+ <!-- Act on each click event -->
+ <circle onclick="circle_click(evt)" cx="300" cy="225" r="100"
+ fill="red"/>
+
+ <text x="300" y="480"
+ font-family="Verdana" font-size="35" text-anchor="middle">
+ Click on circle to change its size
+ </text>
+</svg>
diff --git a/ksvg/test/ecma/circle.svg b/ksvg/test/ecma/circle.svg
new file mode 100644
index 00000000..e9b198c3
--- /dev/null
+++ b/ksvg/test/ecma/circle.svg
@@ -0,0 +1,38 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg width="6cm" height="5cm" viewBox="0 0 600 500" onload="foobar(evt)">
+ <script type="text/ecmascript"> <![CDATA[
+ function foobar(evt)
+ {
+ var circle = evt.getTarget().ownerDocument.getElementById('moo');
+
+ var id = circle.id; // Should call SVGElementImpl::getValueProperty
+
+ var name = circle; // Should call toString()
+
+ var nodeName = circle.nodeName;
+
+ var prop = circle.cx; // Should call SVGCircleElementImpl::getValueProperty
+
+ alert('NODENAME: ' + nodeName + '\nID: ' + id + '\nNAME: ' + name + '\nPROP: ' + prop.baseVal.value);
+ }
+
+ function click(evt)
+ {
+ var circle = evt.target;
+
+ var id = circle.id; // Should call SVGElementImpl::getValueProperty
+
+ var name = circle; // Should call toString()
+
+ var nodeName = circle.nodeName;
+
+ var prop = circle.cx; // Should call SVGCircleElementImpl::getValueProperty
+
+ alert('NODENAME: ' + nodeName + '\nID: ' + id + '\nNAME: ' + name + '\nPROP: ' + prop.baseVal.value);
+ }
+
+ ]]> </script>
+
+ <circle id="moo" onclick="click(evt)" cx="300" cy="225" r="100" fill="red"/>
+</svg>
diff --git a/ksvg/test/ecma/clock.svg b/ksvg/test/ecma/clock.svg
new file mode 100644
index 00000000..906f1303
--- /dev/null
+++ b/ksvg/test/ecma/clock.svg
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="200px" height="280px">
+ <g transform="translate(100,100) rotate(-90)">
+ <circle r="100" fill="white" strok="black" stroke-width="2px"/>
+
+ <g style="stroke-linecap: round; stroke: black; stroke-width: 2px;">
+ <line x1="100" y1="0" x2="90" y2="0" />
+ <line x1="87" y1="50" x2="78" y2="45" />
+ <line x1="50" y1="87" x2="45" y2="78" />
+ <line x1="0" y1="100" x2="0" y2="90" />
+ <line x1="-50" y1="87" x2="-45" y2="78" />
+ <line x1="-87" y1="50" x2="-78" y2="45" />
+ <line x1="-100" y1="0" x2="-90" y2="0" />
+ <line x1="-87" y1="-50" x2="-78" y2="-45"/>
+ <line x1="-50" y1="-87" x2="-45" y2="-78"/>
+ <line x1="0" y1="-100" x2="0" y2="-90"/>
+ <line x1="50" y1="-87" x2="45" y2="-78"/>
+ <line x1="87" y1="-50" x2="78" y2="-45"/>
+ <line id="hourhand" stroke-width="8px" stroke="blue" x1="0" y1="0" x2="0" y2="40"/>
+ <line id="minutehand" stroke-width="5px" stroke="green" x1="0" y1="0" x2="0" y2="65"/>
+ <line id="secondhand" stroke-width="2px" stroke="red" x1="0" y1="0" x2="0" y2="90"/>
+ </g>
+ </g>
+ <text id="datetext" x="10" y="250">test</text>
+
+ <script type="text/javascript">
+ var sHand = document.getElementById('secondhand');
+ var mHand = document.getElementById('minutehand');
+ var hHand = document.getElementById('hourhand');
+ var digital = document.getElementById('datetext');
+
+ function updateSeconds() {
+ var angle = (new Date()).getSeconds() * Math.PI/30;
+
+ if (angle == 0)
+ updateMinutes();
+
+ sHand.setAttribute('x2', 90 * Math.cos(angle));
+ sHand.setAttribute('y2', 90 * Math.sin(angle));
+
+ var d = (new Date()).toUTCString();
+ digital.firstChild.data = d;
+ }
+
+ function updateMinutes() {
+ var angle = (new Date()).getMinutes() * Math.PI/30;
+
+ if (angle == 0)
+ updateHours();
+
+ mHand.setAttribute('x2', 65 * Math.cos(angle));
+ mHand.setAttribute('y2', 65 * Math.sin(angle));
+ }
+
+ function updateHours() {
+ var angle = (new Date()).getHours() * Math.PI/6;
+ hHand.setAttribute('x2', 40 * Math.cos(angle));
+ hHand.setAttribute('y2', 40 * Math.sin(angle));
+ }
+ updateSeconds();
+ updateMinutes();
+ updateHours();
+ setInterval('updateSeconds()', 1000);
+
+ </script>
+</svg>
diff --git a/ksvg/test/ecma/dom01.svg b/ksvg/test/ecma/dom01.svg
new file mode 100644
index 00000000..d5b98937
--- /dev/null
+++ b/ksvg/test/ecma/dom01.svg
@@ -0,0 +1,40 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+ "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg width="4cm" height="2cm" viewBox="0 0 400 200"
+ onload="StartAnimation(evt)"
+ xmlns="http://www.w3.org/2000/svg">
+
+ <script type="text/ecmascript"><![CDATA[
+ var timevalue = 0;
+ var timer_increment = 50;
+ var max_time = 5000;
+ var text_element;
+ function StartAnimation(evt) {
+ text_element = evt.target.ownerDocument.getElementById("TextElement");
+ ShowAndGrowElement();
+ }
+ function ShowAndGrowElement() {
+ timevalue = timevalue + timer_increment;
+ if (timevalue > max_time)
+ return;
+
+ // Scale the text string gradually until it is 20 times larger
+ scalefactor = (timevalue * 20.) / max_time * 40;
+ text_element.setAttribute("transform", "scale(" + scalefactor + ")");
+ // Make the string more opaque
+ opacityfactor = timevalue / max_time;
+// text_element.setAttribute("opacity", opacityfactor);
+
+ // Call ShowAndGrowElement again <timer_increment> milliseconds later.
+// setTimeout("ShowAndGrowElement()", timer_increment)
+ }
+ window.ShowAndGrowElement = ShowAndGrowElement
+ ]]></script>
+ <rect x="1" y="1" width="398" height="198"
+ fill="none" stroke="blue" stroke-width="2"/>
+
+ <g transform="translate(50,150)" fill="red" font-size="7">
+ <text id="TextElement">SVG</text>
+ </g>
+</svg>
diff --git a/ksvg/test/external/Makefile.am b/ksvg/test/external/Makefile.am
new file mode 100644
index 00000000..77f763ac
--- /dev/null
+++ b/ksvg/test/external/Makefile.am
@@ -0,0 +1,13 @@
+INCLUDES = $(FREETYPE_CFLAGS) -I$(top_srcdir)/ksvg -I$(top_srcdir)/ksvg/dom -I$(top_srcdir)/ksvg/impl -I$(top_srcdir)/ksvg/ecma -I$(top_srcdir)/ksvg/core -I$(top_srcdir)/ksvg/impl/libs/libtext2path/src $(all_includes)
+METASOURCES = AUTO
+KDE_CXXFLAGS = $(USE_EXCEPTIONS)
+
+bin_PROGRAMS = svgdisplay printnodetest
+
+svgdisplay_SOURCES = SVGTestWidget.cc svgdisplay.cc
+svgdisplay_LDADD = $(LIB_KDECORE) ../../libksvg.la
+svgdisplay_LDFLAGS = $(KDE_RPATH) $(all_libraries)
+
+printnodetest_SOURCES = printnodetest.cpp
+printnodetest_LDADD = $(LIB_KDECORE) ../../libksvg.la
+printnodetest_LDFLAGS = $(KDE_RPATH) $(all_libraries)
diff --git a/ksvg/test/external/SVGTestWidget.cc b/ksvg/test/external/SVGTestWidget.cc
new file mode 100644
index 00000000..b954e94b
--- /dev/null
+++ b/ksvg/test/external/SVGTestWidget.cc
@@ -0,0 +1,206 @@
+// Very small test app to look at ksvg performance without konqueror overhead (Rob)
+
+#include "SVGTestWidget.moc"
+#include "DocumentFactory.h"
+#include "CanvasFactory.h"
+#include "SVGCircleElement.h"
+#include "SVGAnimatedLength.h"
+#include "SVGLength.h"
+#include "SVGSVGElement.h"
+#include "SVGEventImpl.h"
+#include "KSVGCanvas.h"
+#include "CanvasItem.h"
+#include <kcursor.h>
+
+using namespace KSVG;
+
+SVGTestWidget::SVGTestWidget(const KURL &url)
+{
+ setBackgroundColor(Qt::white);
+ setMouseTracking(true);
+ setFocusPolicy(WheelFocus);
+
+ m_doc = DocumentFactory::self()->requestDocument(this, SLOT(slotRenderingFinished()));
+ if(!m_doc)
+ return;
+
+ resize(450, 450);
+ m_canvas = CanvasFactory::self()->loadCanvas(450, 450);
+ if(!m_canvas)
+ return;
+
+ m_canvas->setup(this, this);
+
+ if(!DocumentFactory::self()->attachCanvas(m_canvas, m_doc))
+ return;
+
+ if(!DocumentFactory::self()->startParsing(m_doc, url))
+ return;
+}
+
+SVGTestWidget::~SVGTestWidget()
+{
+ delete m_canvas;
+ delete m_doc;
+}
+
+void SVGTestWidget::slotRenderingFinished()
+{
+ QRect rect(0, 0, width(), height());
+ m_canvas->blit(rect, true);
+
+ SVGElement test = m_doc->rootElement().getElementById("test");
+ if(test.nodeName() == "circle")
+ {
+ SVGCircleElement c = dom_cast(SVGCircleElement, test);
+ c.r().baseVal().setValue(150);
+ c.setAttribute("fill", "blue");
+ }
+}
+
+void SVGTestWidget::paintEvent(QPaintEvent *event)
+{
+ m_canvas->update();
+ m_canvas->blit(event->rect(), true);
+}
+
+void SVGTestWidget::resizeEvent(QResizeEvent *event)
+{
+ int w = event->size().width();
+ int h = event->size().height();
+
+ m_canvas->resize(w, h);
+ resize(w, h);
+ m_canvas->blit();
+}
+/*
+KSVG::SVGMouseEventImpl *newMouseEvent(SVGDocument *doc, KSVG::SVGEventImpl::EventId id, QMouseEvent *event)
+{
+ DOM::AbstractView temp;
+
+ int clientX = event->x();
+ int clientY = event->y();
+
+ if(doc && doc->rootElement())
+ {
+ clientX = int(clientX / doc->rootElement()->currentScale());
+ clientY = int(clientY / doc->rootElement()->currentScale());
+ }
+
+ int button = 0;
+ if(event->stateAfter() & Qt::LeftButton)
+ button = 1;
+ else if(event->stateAfter() & Qt::MidButton)
+ button = 2;
+ else if(event->stateAfter() & Qt::RightButton)
+ button = 3;
+
+ KSVG::SVGMouseEventImpl *mev = new KSVG::SVGMouseEventImpl(id, // type
+ true, // canBubbleArg
+ true, // cancelableArg
+ temp, // view
+ 0, // detail
+ event->globalX(), //screenXArg
+ event->globalY(), // screenYArg,
+ clientX, // clientXArg
+ clientY, // clientYArg
+ (event->state() & Qt::ControlButton), // ctrlKeyArg
+ (event->state() & Qt::AltButton), // altKeyArg
+ (event->state() & Qt::ShiftButton), // shiftKeyArg
+ (event->state() & Qt::MetaButton), // metaKeyArg
+ button, // buttonArg
+ 0);
+
+ mev->ref();
+
+ return mev;
+}
+
+void SVGTestWidget::mouseMoveEvent(QMouseEvent *event)
+{
+ if(event->state() & QMouseEvent::ControlButton && event->state() & QMouseEvent::LeftButton)
+ {
+ if(m_panningPos.isNull())
+ m_panningPos = event->pos();
+ else
+ {
+ QPoint panPoint = m_oldPanningPos - (m_panningPos - event->pos());
+ m_doc->rootElement()->setCurrentTranslate(panPoint);
+// m_doc->syncCachedMatrices(); FIXME
+ m_canvas->update(panPoint);
+ }
+ return;
+ }
+ else if(event->state() & QMouseEvent::ControlButton)
+ return;
+}
+
+void SVGTestWidget::mousePressEvent(QMouseEvent *event)
+{
+ if(event->state() & QMouseEvent::ControlButton)
+ return;
+
+ KSVG::SVGMouseEventImpl *mev = newMouseEvent(m_doc, KSVG::SVGEventImpl::MOUSEDOWN_EVENT, event);
+
+ if(m_doc && m_doc->rootElement())
+ m_doc->rootElement()->prepareMouseEvent(event->pos(), event->pos(), mev);
+ mev->deref();
+}
+
+void SVGTestWidget::mouseReleaseEvent(QMouseEvent *event)
+{
+ if(!m_panningPos.isNull())
+ {
+ m_oldPanningPos = m_oldPanningPos - (m_panningPos - event->pos());
+ m_panningPos.setX(0);
+ m_panningPos.setY(0);
+ }
+
+ if(event->state() & QMouseEvent::ControlButton)
+ return;
+
+ // only simulate mouse clicks for now
+ KSVG::SVGMouseEventImpl *mev = newMouseEvent(m_doc, KSVG::SVGEventImpl::MOUSEUP_EVENT, event);
+
+ if(m_doc && m_doc->rootElement())
+ m_doc->rootElement()->prepareMouseEvent(event->pos(), event->pos(), mev);
+ mev->deref();
+}
+
+void SVGTestWidget::keyPressEvent(QKeyEvent *event)
+{
+ if(event->stateAfter() & QMouseEvent::ControlButton)
+ {
+ setCursor(KCursor::sizeAllCursor());
+ return;
+ }
+}
+
+void SVGTestWidget::keyReleaseEvent(QKeyEvent *event)
+{
+ if(event->state() & QMouseEvent::ControlButton)
+ {
+ setCursor(KCursor::arrowCursor());
+ return;
+ }
+ SVGSVGElementImpl *root = m_doc->rootElement();
+ if(!root) return;
+ if(event->key() == Qt::Key_Minus)
+ {
+ erase(0, 0, m_canvas->width(), m_canvas->height());
+ float zoomFactor = root->currentScale() / 1.2;
+ root->setCurrentScale(zoomFactor);
+ m_doc->syncCachedMatrices();
+ m_canvas->update(zoomFactor);
+ }
+ else if(event->key() == Qt::Key_Plus)
+ {
+ float zoomFactor = root->currentScale() * 1.2;
+ root->setCurrentScale(zoomFactor);
+ m_doc->syncCachedMatrices();
+ m_canvas->update(zoomFactor);
+ }
+}
+*/
+
+// vim:ts=4:noet
diff --git a/ksvg/test/external/SVGTestWidget.h b/ksvg/test/external/SVGTestWidget.h
new file mode 100644
index 00000000..10ece576
--- /dev/null
+++ b/ksvg/test/external/SVGTestWidget.h
@@ -0,0 +1,37 @@
+#ifndef _SVGTESTWIDGET_H
+#define _SVGTESTWIDGET_H
+
+#include <qwidget.h>
+#include <qobject.h>
+#include "SVGDocument.h"
+#include "KSVGCanvas.h"
+
+class SVGTestWidget : public QWidget
+{
+Q_OBJECT
+public:
+ SVGTestWidget(const KURL &url);
+ ~SVGTestWidget();
+
+private slots:
+ void slotRenderingFinished();
+
+protected:
+ virtual void paintEvent(QPaintEvent *event);
+ virtual void resizeEvent(QResizeEvent *event);
+/* virtual void mousePressEvent(QMouseEvent *event);
+ virtual void mouseReleaseEvent(QMouseEvent *event);
+ virtual void keyPressEvent(QKeyEvent *event);
+ virtual void keyReleaseEvent(QKeyEvent *event);
+ virtual void mouseMoveEvent(QMouseEvent *event);
+*/
+private:
+ QPoint m_panningPos;
+ QPoint m_oldPanningPos;
+
+ KSVG::SVGDocument *m_doc;
+ KSVG::KSVGCanvas *m_canvas;
+};
+
+#endif
+
diff --git a/ksvg/test/external/printnodetest.cpp b/ksvg/test/external/printnodetest.cpp
new file mode 100644
index 00000000..b2547e7f
--- /dev/null
+++ b/ksvg/test/external/printnodetest.cpp
@@ -0,0 +1,63 @@
+#include <DocumentFactory.h>
+#include <SVGSVGElement.h>
+#include <SVGDocument.h>
+#include <SVGWindow.h>
+
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+#include <kaboutdata.h>
+#include <kdebug.h>
+
+#include "printnodetest.moc"
+
+using namespace KSVG;
+
+static KCmdLineOptions options[] =
+{
+ { "+URL", I18N_NOOP("SVG file to open"), 0 },
+ KCmdLineLastOption
+};
+
+Worker::Worker(const KURL &url)
+{
+ m_doc = DocumentFactory::self()->requestDocument(this, SLOT(slotParsingFinished(bool, const QString &)));
+
+ if(!m_doc)
+ return;
+
+ if(!DocumentFactory::self()->startParsing(m_doc, url))
+ return;
+}
+
+Worker::~Worker()
+{
+ delete m_doc;
+}
+
+void Worker::slotParsingFinished(bool, const QString &)
+{
+ SVGWindow win = m_doc->window();
+ SVGSVGElement root = m_doc->rootElement();
+
+ kdDebug() << win.printNode(root).string() << endl;
+ exit(0);
+}
+
+int main(int argc, char **argv)
+{
+ KAboutData *about = new KAboutData("KSVG printNode test app", I18N_NOOP("KSVG test"), "0.1", I18N_NOOP("KSVG printNode test app"));
+ KCmdLineArgs::init(argc, argv, about);
+ KCmdLineArgs::addCmdLineOptions(options);
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ if(args->count() == 0)
+ {
+ args->usage();
+ return -1;
+ }
+
+ KApplication a(argc, argv);
+ (void) new Worker(args->url(0));
+ return a.exec();
+}
+
diff --git a/ksvg/test/external/printnodetest.h b/ksvg/test/external/printnodetest.h
new file mode 100644
index 00000000..e95a46a9
--- /dev/null
+++ b/ksvg/test/external/printnodetest.h
@@ -0,0 +1,32 @@
+#ifndef PRINTNODETEST_H
+#define PRINTNODETEST_H
+
+#include <kurl.h>
+#include <qobject.h>
+
+namespace KSVG
+{
+
+class SVGDocument;
+class Worker : public QObject
+{
+Q_OBJECT
+public:
+ Worker(const KURL &url);
+ ~Worker();
+
+private slots:
+ void slotParsingFinished(bool error, const QString &errorDesc);
+
+private:
+ // It's not allowed to store a m_doc object here,
+ // because it's ctor is called before we can setup
+ // our 'DocumentFactory', in that case it'll just crash (Niko)
+ SVGDocument *m_doc;
+};
+
+}
+
+#endif
+
+// vim:ts=4:noet
diff --git a/ksvg/test/external/svgdisplay.cc b/ksvg/test/external/svgdisplay.cc
new file mode 100644
index 00000000..662fb542
--- /dev/null
+++ b/ksvg/test/external/svgdisplay.cc
@@ -0,0 +1,32 @@
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+#include <kaboutdata.h>
+#include "SVGTestWidget.h"
+
+static KCmdLineOptions options[] =
+{
+ { "+URL", I18N_NOOP("SVG file to open"), 0 },
+ KCmdLineLastOption
+};
+
+int main(int argc, char **argv)
+{
+
+ KAboutData *about = new KAboutData( "KSVG test app", I18N_NOOP("KSVG test"), "0.1", I18N_NOOP("KSVG standalone test app") );
+ KCmdLineArgs::init(argc, argv, about);
+ KCmdLineArgs::addCmdLineOptions( options );
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ if(args->count() == 0)
+ {
+ args->usage();
+ return 0;
+ }
+ KURL url = args->url(0);
+ KApplication a( argc, argv );
+ SVGTestWidget *w = new SVGTestWidget(url);
+ a.setMainWidget(w);
+ w->show();
+
+ return a.exec();
+}
diff --git a/ksvg/test/fonttest.svg b/ksvg/test/fonttest.svg
new file mode 100644
index 00000000..29a0ecc3
--- /dev/null
+++ b/ksvg/test/fonttest.svg
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg width="800" height="1000" onload="init(evt)">
+<g id="insert">
+</g>
+
+<script language="JavaScript">
+var FAM1 = "Arial";
+var FAM2 = "LucidaSansUnicode";
+var FAM3 = "MS-Gothic";
+
+var entry_y = 10;
+var entry_dy = 16;
+
+var entry1_x = 10;
+var entry2_x = 100;
+var entry3_x = 190;
+var entry_end = entry2_x + entry3_x + 30;
+
+var entry1_count = entry_y;
+var entry2_count = entry_y;
+var entry3_count = entry_y;
+
+var doc, insert;
+
+function draw_grid(one, two)
+{
+ var element = doc.createElement("line");
+ element.x1.baseVal.value = Math.floor(one);
+ element.y1.baseVal.value = Math.floor(two) + (entry_dy / 2) - 4;
+ element.x2.baseVal.value = Math.floor(one) + entry_end;
+ element.y2.baseVal.value = Math.floor(two) + (entry_dy / 2) - 4;
+ element.setAttribute("style", "stroke-width:1px; stroke:black; opacity:0.5");
+
+ insert.appendChild(element);
+}
+
+function entry(text, one, two, what)
+{
+ var element = doc.createElement("text");
+
+ use = FAM1;
+ if(what == 1)
+ {
+ use = FAM2;
+ }
+ else if(what == 2)
+ {
+ use = FAM3;
+ }
+
+ element.x.baseVal.getItem(0).value = one;
+ element.y.baseVal.getItem(0).value = two;
+ element.firstChild.data = text;
+ element.setAttribute("font-family", use);
+ element.setAttribute("font-size", "12");
+
+ insert.appendChild(element);
+
+ return entry_dy;
+}
+
+function entry1(text)
+{
+ draw_grid(entry1_x, entry1_count);
+
+ entry1_count += entry(text, entry1_x, entry1_count, 0);
+}
+
+function entry2(text, what)
+{
+ entry2_count += entry(text, entry2_x, entry2_count, what);
+}
+
+function entry3(text, what)
+{
+ entry3_count += entry(text, entry3_x, entry3_count, what);
+}
+
+function init(evt)
+{
+ var target = evt.target;
+ doc = target.ownerDocument;
+
+ insert = doc.getElementById("insert");
+
+ entry1("Arabic", 0); entry2("", 0); entry3("السلام عليكم ", 0);
+ entry1("Bengali", 0); entry2("বাঙ্লা", 0); entry3("ষাগতোম", 0); // Which lang?
+ entry1("Burmese", 0); entry2("", 0); entry3("မ္ရန္မာ", 0); // Which lang?
+ entry1("Cherokee", 0); entry2("ᏣᎳᎩ", 0); entry3("ᎣᏏᏲ", 0); // Which lang?
+ entry1("Czech", 0); entry2("česky", 0); entry3("Dobrý den", 0);
+ entry1("Danish", 0); entry2("Dansk", 0); entry3("Hej, Goddag", 0);
+ entry1("English", 0); entry2("", 0); entry3("Hello", 0);
+ entry1("Esperanto", 0); entry2("", 0); entry3("Saluton", 0);
+ entry1("Estonian", 0); entry2("", 0); entry3("Tere, Tervist", 0);
+ entry1("Finnish", 0); entry2("Suomi", 0); entry3("Hei", 0);
+ entry1("French", 0); entry2("Français", 0); entry3("Bonjour, Salut", 0);
+ entry1("German", 0); entry2("Deutsch Nord", 0); entry3("Guten Tag", 0);
+ entry1("German", 0); entry2("Deutsch Süd", 0); entry3("Grüß Gott", 0);
+ entry1("Georgian", 0); entry2("ქართველი", 0); entry3("გამარჯობა", 0); // Which lang?
+ entry1("Gujarati", 0); entry2("", 0); entry3("ગુજરાતિ", 0); // Which lang?
+ entry1("Greek", 0); entry2("Ελληνικά", 0); entry3("Γειά σας", 0);
+ entry1("Hebrew", 1); entry2("", 1); entry3("שלום", 1);
+ entry1("Hindi", 0); entry2("", 0); entry3("नमस्ते, नमस्कार।", 0); // Which lang?
+ entry1("Italiano", 0); entry2("", 0); entry3("Ciao, Buon giorno", 0);
+ entry1("ɪŋglɪʃ", 1); entry2("", 1); entry3("hɛləʊ", 1); // Which lang here?
+ entry1("Maltese", 1); entry2("", 1); entry3("Ċaw, Saħħa", 1);
+ entry1("Nederlands", 0); entry2("", 0); entry3("Hallo, Dag", 0);
+ entry1("Norwegian", 0); entry2("Norsk", 0); entry3("Hei, God dag", 0);
+ entry1("Punjabi", 0); entry2("", 0); entry3("ੁਪੁਂਜਾਬਿ", 0); // Which lang?
+ entry1("Polish", 0); entry2("", 0); entry3("Dzień dobry, Hej", 0);
+ entry1("Russian", 0); entry2("Русский", 0); entry3("Здравствуйте!", 0);
+ entry1("Slovak", 0); entry2("", 0); entry3("Dobrý deň", 0);
+ entry1("Spanish", 1); entry2("Español", 1); entry3("‎¡Hola!‎", 1);
+ entry1("Swedish", 0); entry2("Svenska", 0); entry3("Hej, Goddag", 0);
+ entry1("Thai", 0); entry2("ภาษาไทย", 0); entry3("สวัสดีครับ, สวัสดีค่ะ", 0); // Which lang?
+ entry1("Turkish", 0); entry2("Türkçe", 0); entry3("Merhaba", 0);
+ entry1("Vietnamese", 0); entry2("Tiếng Việt", 0); entry3("Xin Chào", 0);
+ entry1("Yiddish", 1); entry2("ײַדישע", 1); entry3("דאָס הײַזעלע ", 1);
+ entry1("Japanese", 2); entry2("日本語", 2); entry3("こんにちは, コンニチハ", 2);
+ entry1("Chinese", 2); entry2("中文,普通话,汉语", 2); entry3("你好", 2);
+ entry1("Cantonese", 2); entry2("粵語,廣東話", 2); entry3("早晨, 你好", 2);
+ entry1("Korean", 0); entry2("한글", 0); entry3("안녕하세요, 안녕하십니까", 0); // Which lang?
+}
+</script>
+</svg>
diff --git a/ksvg/test/keytest.svg b/ksvg/test/keytest.svg
new file mode 100644
index 00000000..57c7b639
--- /dev/null
+++ b/ksvg/test/keytest.svg
@@ -0,0 +1,25 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20001102//EN"
+ "http://www.w3.org/TR/2000/CR-SVG-20001102/DTD/svg-20001102.dtd">
+<svg id="hans" width="600" height="600">
+<script language="javascript">
+<![CDATA[
+
+function keytest(evt)
+{
+ alert(evt.keyVal);
+ alert(evt.virtKeyVal);
+ alert(evt.outputString);
+/*
+ evt.initmodifier(DOM_VK_LEFT_ALT,false);
+ alert(evt.checkmodifier(DOM_VK_LEFT_ALT));
+ evt.initmodifier(DOM_VK_LEFT_ALT,true);
+ alert(evt.checkmodifier(DOM_VK_LEFT_ALT));
+ alert(evt.target);*/
+}
+
+]]>
+</script>
+<rect id="jo" onkeydown="keytest(evt)" x="0" y="0" width="50" height="100" style="fill: red"/>
+<rect onkeyup="keytest(evt)" x="60" y="0" width="50" height="100" style="fill: red"/>
+</svg>
diff --git a/ksvg/test/lion.svg b/ksvg/test/lion.svg
new file mode 100644
index 00000000..972e158a
--- /dev/null
+++ b/ksvg/test/lion.svg
@@ -0,0 +1,160 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="15cm" height="15cm">
+<g transform="rotate(10) scale (1) translate (100,10)">
+<g style = "fill: #f2cc99" >
+ <polygon points = " 69,18 82,8 99,3 118,5 135,12 149,21 156,13 165,9 177,13 183,28 180,50 164,91 155,107 154,114 151,121 141,127 139,136 155,206 157,251 126,342 133,357 128,376 83,376 75,368 67,350 61,350 53,369 4,369 2,361 5,354 12,342 16,321 4,257 4,244 7,218 9,179 26,127 43,93 32,77 30,70 24,67 16,49 17,35 18,23 30,12 40,7 53,7 62,12"/>
+</g>
+<g style = "fill: #e5b27f" >
+ <polygon points = " 142,79 136,74 138,82 133,78 133,84 127,78 128,85 124,80 125,87 119,82 119,90 125,99 125,96 128,100 128,94 131,98 132,93 135,97 136,93 138,97 139,94 141,98 143,94 144,85"/>
+</g>
+<g style = "fill: #eb8080" >
+ <polygon points = " 127,101 132,100 137,99 144,101 143,105 135,110"/>
+</g>
+<g style = "fill: #f2cc99" >
+ <polygon points = " 178,229 157,248 139,296 126,349 137,356 158,357 183,342 212,332 235,288 235,261 228,252 212,250 188,251"/>
+</g>
+<g style = "fill: #9c826b" >
+ <polygon points = " 56,229 48,241 48,250 57,281 63,325 71,338 81,315 76,321 79,311 83,301 75,308 80,298 73,303 76,296 71,298 74,292 69,293 74,284 78,278 71,278 74,274 68,273 70,268 66,267 68,261 60,266 62,259 65,253 57,258 59,251 55,254 55,248 60,237 54,240 58,234 54,236"/>
+ <polygon points = " 74,363 79,368 81,368 85,362 89,363 92,370 96,373 101,372 108,361 110,371 113,373 116,371 120,358 122,363 123,371 126,371 129,367 132,357 135,361 130,376 127,377 94,378 84,376 76,371"/>
+ <polygon points = " 212,250 219,251 228,258 236,270 235,287 225,304 205,332 177,343 171,352 158,357 166,352 168,346 168,339 165,333 155,327 155,323 161,320 165,316 169,316 167,312 171,313 168,308 173,309 170,306 177,306 175,308 177,311 174,311 176,316 171,315 174,319 168,320 168,323 175,327 179,332 183,326 184,332 189,323 190,328 194,320 194,325 199,316 201,320 204,313 206,316 208,310 211,305 219,298 226,288 229,279 228,266 224,259 217,253"/>
+ <polygon points = " 151,205 151,238 149,252 141,268 128,282 121,301 130,300 126,313 118,324 116,337 120,346 133,352 133,340 137,333 145,329 156,327 153,319 153,291 157,271 170,259 178,277 193,250 174,216"/>
+ <polygon points = " 78,127 90,142 95,155 108,164 125,167 139,175 150,206 152,191 141,140 121,148 100,136"/>
+ <polygon points = " 21,58 35,63 38,68 32,69 42,74 40,79 47,80 54,83 45,94 34,81 32,73 24,66"/>
+ <polygon points = " 71,34 67,34 66,27 59,24 54,17 48,17 39,22 30,26 28,31 31,39 38,46 29,45 36,54 41,61 41,70 50,69 54,71 55,58 67,52 76,43 76,39 68,44"/>
+ <polygon points = " 139,74 141,83 143,89 144,104 148,104 155,106 154,86 157,77 155,72 150,77 144,77"/>
+ <polygon points = " 105,44 102,53 108,58 111,62 112,55"/>
+ <polygon points = " 141,48 141,54 144,58 139,62 137,66 136,59 137,52"/>
+ <polygon points = " 98,135 104,130 105,134 108,132 108,135 112,134 113,137 116,136 116,139 119,139 124,141 128,140 133,138 140,133 139,140 126,146 104,144"/>
+ <polygon points = " 97,116 103,119 103,116 111,118 116,117 122,114 127,107 135,111 142,107 141,114 145,118 149,121 145,125 140,124 127,121 113,125 100,124"/>
+ <polygon points = " 147,33 152,35 157,34 153,31 160,31 156,28 161,28 159,24 163,25 163,21 165,22 170,23 167,17 172,21 174,18 175,23 176,22 177,28 177,33 174,37 176,39 174,44 171,49 168,53 164,57 159,68 156,70 154,60 150,51 146,43 144,35"/>
+ <polygon points = " 85,72 89,74 93,75 100,76 105,75 102,79 94,79 88,76"/>
+ <polygon points = " 86,214 79,221 76,232 82,225 78,239 82,234 78,245 81,243 79,255 84,250 84,267 87,254 90,271 90,257 95,271 93,256 95,249 92,252 93,243 89,253 89,241 86,250 87,236 83,245 87,231 82,231 90,219 84,221"/>
+</g>
+<g style = "fill: #ffcc7f" >
+ <polygon points = " 93,68 96,72 100,73 106,72 108,66 105,63 100,62"/>
+ <polygon points = " 144,64 142,68 142,73 146,74 150,73 154,64 149,62"/>
+</g>
+<g style = "fill: #9c826b" >
+ <polygon points = " 57,91 42,111 52,105 41,117 53,112 46,120 53,116 50,124 57,119 55,127 61,122 60,130 67,126 66,134 71,129 72,136 77,130 76,137 80,133 82,138 86,135 96,135 94,129 86,124 83,117 77,123 79,117 73,120 75,112 68,116 71,111 65,114 69,107 63,110 68,102 61,107 66,98 61,103 63,97 57,99"/>
+ <polygon points = " 83,79 76,79 67,82 75,83 65,88 76,87 65,92 76,91 68,96 77,95 70,99 80,98 72,104 80,102 76,108 85,103 92,101 87,98 93,96 86,94 91,93 85,91 93,89 99,89 105,93 107,85 102,82 92,80"/>
+ <polygon points = " 109,77 111,83 109,89 113,94 117,90 117,81 114,78"/>
+ <polygon points = " 122,128 127,126 134,127 136,129 134,130 130,128 124,129"/>
+ <polygon points = " 78,27 82,32 80,33 82,36 78,37 82,40 78,42 81,46 76,47 78,49 74,50 82,52 87,50 83,48 91,46 86,45 91,42 88,40 92,37 86,34 90,31 86,29 89,26"/>
+ <polygon points = " 82,17 92,20 79,21 90,25 81,25 94,28 93,26 101,30 101,26 107,33 108,28 111,40 113,34 115,45 117,39 119,54 121,46 124,58 126,47 129,59 130,49 134,58 133,44 137,48 133,37 137,40 133,32 126,20 135,26 132,19 138,23 135,17 142,18 132,11 116,6 94,6 78,11 92,12 80,14 90,16"/>
+ <polygon points = " 142,234 132,227 124,223 115,220 110,225 118,224 127,229 135,236 122,234 115,237 113,242 121,238 139,243 121,245 111,254 95,254 102,244 104,235 110,229 100,231 104,224 113,216 122,215 132,217 141,224 145,230 149,240"/>
+ <polygon points = " 115,252 125,248 137,249 143,258 134,255 125,254"/>
+ <polygon points = " 114,212 130,213 140,219 147,225 144,214 137,209 128,207"/>
+ <polygon points = " 102,263 108,258 117,257 131,258 116,260 109,265"/>
+ <polygon points = " 51,241 35,224 40,238 23,224 31,242 19,239 28,247 17,246 25,250 37,254 39,263 44,271 47,294 48,317 51,328 60,351 60,323 53,262 47,246"/>
+ <polygon points = " 2,364 9,367 14,366 18,355 20,364 26,366 31,357 35,364 39,364 42,357 47,363 53,360 59,357 54,369 7,373"/>
+ <polygon points = " 7,349 19,345 25,339 18,341 23,333 28,326 23,326 27,320 23,316 25,311 20,298 15,277 12,264 9,249 10,223 3,248 5,261 15,307 17,326 11,343"/>
+ <polygon points = " 11,226 15,231 25,236 18,227"/>
+ <polygon points = " 13,214 19,217 32,227 23,214 16,208 15,190 24,148 31,121 24,137 14,170 8,189"/>
+ <polygon points = " 202,254 195,258 199,260 193,263 197,263 190,268 196,268 191,273 188,282 200,272 194,272 201,266 197,265 204,262 200,258 204,256"/>
+</g>
+<g style = "fill: #845433" >
+ <polygon points = " 151,213 165,212 179,225 189,246 187,262 179,275 176,263 177,247 171,233 163,230 165,251 157,264 146,298 145,321 133,326 143,285 154,260 153,240"/>
+ <polygon points = " 91,132 95,145 97,154 104,148 107,155 109,150 111,158 115,152 118,159 120,153 125,161 126,155 133,164 132,154 137,163 137,152 142,163 147,186 152,192 148,167 141,143 124,145 105,143"/>
+</g>
+<g style = "fill: #9c826b" >
+ <polygon points = " 31,57 23,52 26,51 20,44 23,42 21,36 22,29 25,23 24,32 30,43 26,41 30,50 26,48"/>
+ <polygon points = " 147,21 149,28 155,21 161,16 167,14 175,15 173,11 161,9"/>
+ <polygon points = " 181,39 175,51 169,57 171,65 165,68 165,75 160,76 162,91 171,71 180,51"/>
+ <polygon points = " 132,346 139,348 141,346 142,341 147,342 143,355 133,350"/>
+ <polygon points = " 146,355 151,352 155,348 157,343 160,349 151,356 147,357"/>
+ <polygon points = " 99,266 100,281 94,305 86,322 78,332 72,346 73,331 91,291"/>
+ <polygon points = " 20,347 32,342 45,340 54,345 45,350 42,353 38,350 31,353 29,356 23,350 19,353 15,349"/>
+ <polygon points = " 78,344 86,344 92,349 88,358 84,352"/>
+ <polygon points = " 93,347 104,344 117,345 124,354 121,357 116,351 112,351 108,355 102,351"/>
+</g>
+<g style = "fill: #000000" >
+ <polygon points = " 105,12 111,18 113,24 113,29 119,34 116,23 112,16"/>
+ <polygon points = " 122,27 125,34 127,43 128,34 125,29"/>
+ <polygon points = " 115,13 122,19 122,15 113,10"/>
+</g>
+<g style = "fill: #ffe5b2" >
+ <polygon points = " 116,172 107,182 98,193 98,183 90,199 89,189 84,207 88,206 87,215 95,206 93,219 91,230 98,216 97,226 104,214 112,209 104,208 113,202 126,200 139,207 132,198 142,203 134,192 142,195 134,187 140,185 130,181 136,177 126,177 125,171 116,180"/>
+ <polygon points = " 74,220 67,230 67,221 59,235 63,233 60,248 70,232 65,249 71,243 67,256 73,250 69,262 73,259 71,267 76,262 72,271 78,270 76,275 82,274 78,290 86,279 86,289 92,274 88,275 87,264 82,270 82,258 77,257 78,247 73,246 77,233 72,236"/>
+ <polygon points = " 133,230 147,242 148,250 145,254 138,247 129,246 142,245 138,241 128,237 137,238"/>
+ <polygon points = " 133,261 125,261 116,263 111,267 125,265"/>
+ <polygon points = " 121,271 109,273 103,279 99,305 92,316 85,327 83,335 89,340 97,341 94,336 101,336 96,331 103,330 97,327 108,325 99,322 109,321 100,318 110,317 105,314 110,312 107,310 113,308 105,306 114,303 105,301 115,298 107,295 115,294 108,293 117,291 109,289 117,286 109,286 118,283 112,281 118,279 114,278 119,276 115,274"/>
+ <polygon points = " 79,364 74,359 74,353 76,347 80,351 83,356 82,360"/>
+ <polygon points = " 91,363 93,356 97,353 103,355 105,360 103,366 99,371 94,368"/>
+ <polygon points = " 110,355 114,353 118,357 117,363 113,369 111,362"/>
+ <polygon points = " 126,354 123,358 124,367 126,369 129,361 129,357"/>
+ <polygon points = " 30,154 24,166 20,182 23,194 29,208 37,218 41,210 41,223 46,214 46,227 52,216 52,227 61,216 59,225 68,213 73,219 70,207 77,212 69,200 77,202 70,194 78,197 68,187 76,182 64,182 58,175 58,185 53,177 50,186 46,171 44,182 39,167 36,172 36,162 30,166"/>
+ <polygon points = " 44,130 41,137 45,136 43,150 48,142 48,157 53,150 52,164 60,156 61,169 64,165 66,175 70,167 74,176 77,168 80,183 85,172 90,182 93,174 98,181 99,173 104,175 105,169 114,168 102,163 95,157 94,166 90,154 87,162 82,149 75,159 72,148 68,155 67,143 62,148 62,138 58,145 56,133 52,142 52,128 49,134 47,125"/>
+ <polygon points = " 13,216 19,219 36,231 22,223 16,222 22,227 12,224 13,220 16,220"/>
+ <polygon points = " 10,231 14,236 25,239 27,237 19,234"/>
+ <polygon points = " 9,245 14,242 25,245 13,245"/>
+ <polygon points = " 33,255 26,253 18,254 25,256 18,258 27,260 18,263 27,265 19,267 29,270 21,272 29,276 21,278 30,281 22,283 31,287 24,288 32,292 23,293 34,298 26,299 37,303 32,305 39,309 33,309 39,314 34,314 40,318 34,317 40,321 34,321 41,326 33,326 40,330 33,332 39,333 33,337 42,337 54,341 49,337 52,335 47,330 50,330 45,325 49,325 45,321 48,321 45,316 46,306 45,286 43,274 36,261"/>
+ <polygon points = " 7,358 9,351 14,351 17,359 11,364"/>
+ <polygon points = " 44,354 49,351 52,355 49,361"/>
+ <polygon points = " 32,357 37,353 40,358 36,361"/>
+ <polygon points = " 139,334 145,330 154,330 158,334 154,341 152,348 145,350 149,340 147,336 141,339 139,345 136,342 136,339"/>
+ <polygon points = " 208,259 215,259 212,255 220,259 224,263 225,274 224,283 220,292 208,300 206,308 203,304 199,315 197,309 195,318 193,313 190,322 190,316 185,325 182,318 180,325 172,321 178,320 176,313 186,312 180,307 188,307 184,303 191,302 186,299 195,294 187,290 197,288 192,286 201,283 194,280 203,277 198,275 207,271 200,269 209,265 204,265 212,262"/>
+ <polygon points = " 106,126 106,131 109,132 111,134 115,132 115,135 119,133 118,137 123,137 128,137 133,134 136,130 136,127 132,124 118,128 112,128 106,126 106,126 106,126"/>
+ <polygon points = " 107,114 101,110 98,102 105,97 111,98 119,102 121,108 118,112 113,115"/>
+ <polygon points = " 148,106 145,110 146,116 150,118 152,111 151,107"/>
+ <polygon points = " 80,55 70,52 75,58 63,57 72,61 57,61 67,66 57,67 62,69 54,71 61,73 54,77 63,78 53,85 60,84 56,90 69,84 63,82 75,76 70,75 77,72 72,71 78,69 72,66 81,67 78,64 82,63 80,60 86,62"/>
+ <polygon points = " 87,56 91,52 96,50 102,56 98,56 92,60"/>
+ <polygon points = " 85,68 89,73 98,76 106,74 96,73 91,70"/>
+ <polygon points = " 115,57 114,64 111,64 115,75 122,81 122,74 126,79 126,74 131,78 130,72 133,77 131,68 126,61 119,57"/>
+ <polygon points = " 145,48 143,53 147,59 151,59 150,55"/>
+ <polygon points = " 26,22 34,15 43,10 52,10 59,16 47,15 32,22"/>
+ <polygon points = " 160,19 152,26 149,34 154,33 152,30 157,30 155,26 158,27 157,23 161,23"/>
+</g>
+<g style = "fill: #000000" >
+ <polygon points = " 98,117 105,122 109,122 105,117 113,120 121,120 130,112 128,108 123,103 123,99 128,101 132,106 135,109 142,105 142,101 145,101 145,91 148,101 145,105 136,112 135,116 143,124 148,120 150,122 142,128 133,122 121,125 112,126 103,125 100,129 96,124"/>
+ <polygon points = " 146,118 152,118 152,115 149,115"/>
+ <polygon points = " 148,112 154,111 154,109 149,109"/>
+ <polygon points = " 106,112 108,115 114,116 118,114"/>
+ <polygon points = " 108,108 111,110 116,110 119,108"/>
+ <polygon points = " 106,104 109,105 117,106 115,104"/>
+ <polygon points = " 50,25 41,26 34,33 39,43 49,58 36,51 47,68 55,69 54,59 61,57 74,46 60,52 67,42 57,48 61,40 54,45 60,36 59,29 48,38 52,30 47,32"/>
+ <polygon points = " 147,34 152,41 155,49 161,53 157,47 164,47 158,43 168,44 159,40 164,37 169,37 164,33 169,34 165,28 170,30 170,25 173,29 175,27 176,32 173,36 175,39 172,42 172,46 168,49 170,55 162,57 158,63 155,58 153,50 149,46"/>
+ <polygon points = " 155,71 159,80 157,93 157,102 155,108 150,101 149,93 154,101 152,91 151,83 155,79"/>
+ <polygon points = " 112,78 115,81 114,91 112,87 113,82"/>
+ <polygon points = " 78,28 64,17 58,11 47,9 36,10 28,16 21,26 18,41 20,51 23,61 33,65 28,68 37,74 36,81 43,87 48,90 43,100 40,98 39,90 31,80 30,72 22,71 17,61 14,46 16,28 23,17 33,9 45,6 54,6 65,12"/>
+ <polygon points = " 67,18 76,9 87,5 101,2 118,3 135,8 149,20 149,26 144,19 132,12 121,9 105,7 89,8 76,14 70,20"/>
+ <polygon points = " 56,98 48,106 56,103 47,112 56,110 52,115 57,113 52,121 62,115 58,123 65,119 63,125 69,121 68,127 74,125 74,129 79,128 83,132 94,135 93,129 85,127 81,122 76,126 75,121 71,124 71,117 66,121 66,117 62,117 64,112 60,113 60,110 57,111 61,105 57,107 60,101 55,102"/>
+ <polygon points = " 101,132 103,138 106,134 106,139 112,136 111,142 115,139 114,143 119,142 125,145 131,142 135,138 140,134 140,129 143,135 145,149 150,171 149,184 145,165 141,150 136,147 132,151 131,149 126,152 125,150 121,152 117,148 111,152 110,148 105,149 104,145 98,150 96,138 94,132 94,130 98,132"/>
+ <polygon points = " 41,94 32,110 23,132 12,163 6,190 7,217 5,236 3,247 9,230 12,211 12,185 18,160 26,134 35,110 43,99"/>
+ <polygon points = " 32,246 41,250 50,257 52,267 53,295 53,323 59,350 54,363 51,365 44,366 42,360 40,372 54,372 59,366 62,353 71,352 75,335 73,330 66,318 68,302 64,294 67,288 63,286 63,279 59,275 58,267 56,262 50,247 42,235 44,246 32,236 35,244"/>
+ <polygon points = " 134,324 146,320 159,322 173,327 179,337 179,349 172,355 158,357 170,350 174,343 170,333 163,328 152,326 134,329"/>
+ <polygon points = " 173,339 183,334 184,338 191,329 194,332 199,323 202,325 206,318 209,320 213,309 221,303 228,296 232,289 234,279 233,269 230,262 225,256 219,253 208,252 198,252 210,249 223,250 232,257 237,265 238,277 238,291 232,305 221,323 218,335 212,342 200,349 178,348"/>
+ <polygon points = " 165,296 158,301 156,310 156,323 162,324 159,318 162,308 162,304"/>
+ <polygon points = " 99,252 105,244 107,234 115,228 121,228 131,235 122,233 113,235 109,246 121,239 133,243 121,243 110,251"/>
+ <polygon points = " 117,252 124,247 134,249 136,253 126,252"/>
+ <polygon points = " 117,218 132,224 144,233 140,225 132,219 117,218 117,218 117,218"/>
+ <polygon points = " 122,212 134,214 143,221 141,213 132,210"/>
+ <polygon points = " 69,352 70,363 76,373 86,378 97,379 108,379 120,377 128,378 132,373 135,361 133,358 132,366 127,375 121,374 121,362 119,367 117,374 110,376 110,362 107,357 106,371 104,375 97,376 90,375 90,368 86,362 83,364 86,369 85,373 78,370 73,362 71,351"/>
+ <polygon points = " 100,360 96,363 99,369 102,364"/>
+ <polygon points = " 115,360 112,363 114,369 117,364"/>
+ <polygon points = " 127,362 125,364 126,369 128,365"/>
+ <polygon points = " 5,255 7,276 11,304 15,320 13,334 6,348 2,353 0,363 5,372 12,374 25,372 38,372 44,369 42,367 36,368 31,369 30,360 27,368 20,370 16,361 15,368 10,369 3,366 3,359 6,352 11,348 17,331 19,316 12,291 9,274"/>
+ <polygon points = " 10,358 7,362 10,366 11,362"/>
+ <polygon points = " 25,357 22,360 24,366 27,360"/>
+ <polygon points = " 37,357 34,361 36,365 38,361"/>
+ <polygon points = " 49,356 46,359 47,364 50,360"/>
+ <polygon points = " 130,101 132,102 135,101 139,102 143,103 142,101 137,100 133,100"/>
+ <polygon points = " 106,48 105,52 108,56 109,52"/>
+ <polygon points = " 139,52 139,56 140,60 142,58 141,56"/>
+ <polygon points = " 25,349 29,351 30,355 33,350 37,348 42,351 45,347 49,345 44,343 36,345"/>
+ <polygon points = " 98,347 105,351 107,354 109,349 115,349 120,353 118,349 113,346 104,346"/>
+ <polygon points = " 83,348 87,352 87,357 89,351 87,348"/>
+ <polygon points = " 155,107 163,107 170,107 186,108 175,109 155,109"/>
+ <polygon points = " 153,114 162,113 175,112 192,114 173,114 154,115"/>
+ <polygon points = " 152,118 164,120 180,123 197,129 169,123 151,120"/>
+ <polygon points = " 68,109 87,106 107,106 106,108 88,108"/>
+ <polygon points = " 105,111 95,112 79,114 71,116 85,115 102,113"/>
+ <polygon points = " 108,101 98,99 87,99 78,99 93,100 105,102"/>
+ <polygon points = " 85,63 91,63 97,60 104,60 108,62 111,69 112,75 110,74 108,71 103,73 106,69 105,65 103,64 103,67 102,70 99,70 97,66 94,67 97,72 88,67 84,66"/>
+ <polygon points = " 140,74 141,66 144,61 150,61 156,62 153,70 150,73 152,65 150,65 151,68 149,71 146,71 144,66 143,70 143,74"/>
+ <polygon points = " 146,20 156,11 163,9 172,9 178,14 182,18 184,32 182,42 182,52 177,58 176,67 171,76 165,90 157,105 160,92 164,85 168,78 167,73 173,66 172,62 175,59 174,55 177,53 180,46 181,29 179,21 173,13 166,11 159,13 153,18 148,23"/>
+ <polygon points = " 150,187 148,211 150,233 153,247 148,267 135,283 125,299 136,292 131,313 122,328 122,345 129,352 133,359 133,367 137,359 148,356 140,350 131,347 129,340 132,332 140,328 137,322 140,304 154,265 157,244 155,223 161,220 175,229 186,247 185,260 176,275 178,287 185,277 188,261 196,253 189,236 174,213"/>
+ <polygon points = " 147,338 142,341 143,345 141,354 147,343"/>
+ <polygon points = " 157,342 156,349 150,356 157,353 163,346 162,342"/>
+ <polygon points = " 99,265 96,284 92,299 73,339 73,333 87,300"/>
+</g>
+</g>
+</svg>
diff --git a/ksvg/test/opacity.svg b/ksvg/test/opacity.svg
new file mode 100644
index 00000000..fa2b20e2
--- /dev/null
+++ b/ksvg/test/opacity.svg
@@ -0,0 +1,41 @@
+<svg width="600" height="200">
+ <!-- adapted from example opacity01 in SVG candidate recommendation 2 Aug 2000 -->
+ <path style="fill:#008" d="M50 50 L50 150 550 150 550 50z"/>
+ <g transform="translate(100,50)" style="opacity:1">
+ <path style="fill:#f00; opacity:1" d="M-30 0 L-10 20 10 0 -10 -20z"/>
+ <path style="fill:#0f0; opacity:1" d="M-10 0 L10 20 30 0 10 -20z"/>
+ </g>
+ <g transform="translate(200,50)" style="opacity:0.5">
+ <path style="fill:#f00; opacity:1" d="M-30 0 L-10 20 10 0 -10 -20z"/>
+ <path style="fill:#0f0; opacity:1" d="M-10 0 L10 20 30 0 10 -20z"/>
+ </g>
+ <g transform="translate(300,50)" style="opacity:1">
+ <path style="fill:#f00; opacity:0.5" d="M-30 0 L-10 20 10 0 -10 -20z"/>
+ <path style="fill:#0f0; opacity:0.5" d="M-10 0 L10 20 30 0 10 -20z"/>
+ </g>
+ <g transform="translate(400,50)" style="opacity:0.5">
+ <path style="fill:#f00; opacity:0.5" d="M-30 0 L-10 20 10 0 -10 -20z"/>
+ <path style="fill:#0f0; opacity:0.5" d="M-10 0 L10 20 30 0 10 -20z"/>
+ </g>
+
+ <g transform="translate(100,150)" style="opacity:1; stroke-width:5; stroke:#000">
+ <path style="fill:#f00; opacity:1" d="M-30 0 L-10 20 10 0 -10 -20z"/>
+ <path style="fill:#0f0; opacity:1" d="M-10 0 L10 20 30 0 10 -20z"/>
+ </g>
+ <g transform="translate(200,150)" style="opacity:0.5; stroke-width:5; stroke:#000">
+ <path style="fill:#f00; opacity:1" d="M-30 0 L-10 20 10 0 -10 -20z"/>
+ <path style="fill:#0f0; opacity:1" d="M-10 0 L10 20 30 0 10 -20z"/>
+ </g>
+ <g transform="translate(300,150)" style="opacity:1; stroke-width:5; stroke:#000">
+ <path style="fill:#f00; opacity:0.5" d="M-30 0 L-10 20 10 0 -10 -20z"/>
+ <path style="fill:#0f0; opacity:0.5" d="M-10 0 L10 20 30 0 10 -20z"/>
+ </g>
+ <g transform="translate(400,150)" style="opacity:0.5; stroke-width:5; stroke:#000">
+ <path style="fill:#f00; opacity:0.5" d="M-30 0 L-10 20 10 0 -10 -20z"/>
+ <path style="fill:#0f0; opacity:0.5" d="M-10 0 L10 20 30 0 10 -20z"/>
+ </g>
+ <g transform="translate(500,150)" style="opacity:1; stroke-width:5; stroke:#000">
+ <path style="fill:#f00; fill-opacity:0.5; stroke-opacity:0.5" d="M-30 0 L-10 20 10 0 -10 -20z"/>
+ <path style="fill:#0f0; fill-opacity:0.5; stroke-opacity:0.5" d="M-10 0 L10 20 30 0 10 -20z"/>
+ </g>
+</svg>
diff --git a/ksvg/test/physics-motor.svg b/ksvg/test/physics-motor.svg
new file mode 100644
index 00000000..9956ad8e
--- /dev/null
+++ b/ksvg/test/physics-motor.svg
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20001102//EN" "http://www.w3.org/TR/2000/CR-SVG-20001102/DTD/svg-20001102.dtd">
+
+<!-- Copyright 2002 Nikolas Zimmermann <wildfox@kde.org> -->
+<!-- "Der Gleichstrommotor" -->
+
+<svg width="650" height="850">
+ <title>physics-motor</title>
+ <desc>Der Gleichstrommotor</desc>
+
+ <defs>
+ <!-- Rotor Parts -->
+ <g id="rotor-p1">
+ <path d="M 300 350 C 300 320 400 320 400 350 z"/>
+ <rect x="320" y="350" width="60" height="74"/>
+
+ </g>
+
+ <g id="rotor-p2">
+ <path d="M 300 500 C 300 530 400 530 400 500 z"/>
+ <rect x="320" y="424" width="60" height="76"/>
+ </g>
+
+ <!-- Stator -->
+ <g id="stator">
+ <rect x="310" y="300" width="100" height="30" style="fill:red"/>
+ <rect x="310" y="540" width="100" height="30" style="fill:green"/>
+ </g>
+
+ <!-- Rotor -->
+ <g id="rotor">
+ <use x="10" y="10" xlink:href="#rotor-p2" style="fill:green;stroke:black"/>
+ <use x="10" y="10" xlink:href="#rotor-p1" style="fill:red;stroke:black"/>
+
+ <circle cx="360" cy="435" r="6" style="fill:black"/>
+ </g>
+ </defs>
+
+ <use xlink:href="#stator"/>
+ <use id="animate" xlink:href="#rotor"/>
+
+ <animateTransform xlink:href="#animate" begin="2s" dur="3s" attributeName="transform" type="rotate" from="0, 360, 435" to="360, 360, 435" repeatDur="indefinite"/>
+</svg>
diff --git a/ksvg/test/poly.svg b/ksvg/test/poly.svg
new file mode 100644
index 00000000..6c2938f9
--- /dev/null
+++ b/ksvg/test/poly.svg
@@ -0,0 +1,12 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20001102//EN"
+ "http://www.w3.org/TR/2000/CR-SVG-20001102/DTD/svg-20001102.dtd">
+<svg width="210mm" height="297mm" >
+ <polygon width="61.2" x="121.5" y="108" points="182.7,135 182.7,108 121.5,108 121.5,135 182.7,135 " height="27" transform="matrix(1 0 0 1 0 0)" style="fill:none ; stroke:#000000;stroke-width:0.9" />
+ <polygon width="61.2" x="247.5" y="108" points="308.7,135 308.7,108 247.5,108 247.5,135 308.7,135 " height="27" transform="matrix(1 0 0 1 0 0)" style="fill:none ; stroke:#000000;stroke-width:0.9" />
+ <polygon width="61.2" x="193.5" y="184.5" points="254.7,211.5 254.7,184.5 193.5,184.5 193.5,211.5 254.7,211.5 " height="27" transform="matrix(1 0 0 1 0 0)" style="fill:none ; stroke:#000000;stroke-width:0.9" />
+ <polygon width="90" x="180" y="261" points="270,288 270,261 180,261 180,288 270,288 " height="27" transform="matrix(1 0 0 1 0 0)" style="fill:none ; stroke:#000000;stroke-width:0.9" />
+ <polyline points="153,135 216,184.5 " transform="matrix(1 0 0 1 0 0)" style="fill:none ; stroke:#000000;stroke-width:0.9" />
+ <polyline points="279,135 229.5,184.5 " transform="matrix(1 0 0 1 0 0)" style="fill:none ; stroke:#000000;stroke-width:0.9" />
+ <polyline points="225,211.5 225,261 " transform="matrix(1 0 0 1 0 0)" style="fill:none ; stroke:#000000;stroke-width:0.9" />
+</svg>
diff --git a/ksvg/test/shapes-rect-trans.svg b/ksvg/test/shapes-rect-trans.svg
new file mode 100644
index 00000000..fb919312
--- /dev/null
+++ b/ksvg/test/shapes-rect-trans.svg
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20001102//EN" "http://www.w3.org/TR/2000/CR-SVG-20001102/DTD/svg-20001102.dtd">
+
+<!--======================================================================-->
+<!--= Copyright 2000 World Wide Web Consortium, (Massachusetts =-->
+<!--= Institute of Technology, Institut National de Recherche en =-->
+<!--= Informatique et en Automatique, Keio University). All Rights =-->
+<!--= Reserved. See http://www.w3.org/Consortium/Legal/. =-->
+<!--======================================================================-->
+<!-- ===================================================================== -->
+<!-- -->
+<!-- shapes-rect-BE-01.svg -->
+<!-- -->
+<!-- Test that viewer has the basic capability to handle the <rect> -->
+<!-- element. -->
+<!-- -->
+<!-- Author : Kelvin R. Lawrence, 3-Feb-2000 -->
+<!-- -->
+<!-- History: -->
+<!-- 3-Feb-2000, KRL, Serial#1 created. Matches 20000202 SVG spec. -->
+<!-- 27-Feb-2000, LH, Serial#2, fix TC name, formatting, create .XML -->
+<!-- 12-Mar-2000, LH, fix test-framing rect; ser#3 -->
+<!-- 03-Aug-2000, LH: update DOCTYPE for CR DTD, 20000802; ser# . -->
+<!-- -->
+<!-- ===================================================================== -->
+<!--======================================================================-->
+<!--= Note. After October 2000, revision history is kept as CVS 'commit' =-->
+<!--= log messages, and therefore is no longer in the preceding preamble.=-->
+<!--======================================================================-->
+<svg id="svg-root" width="450" height="450">
+ <title id="test-title">shapes-rect-BE-01</title>
+ <desc id="test-desc">Test that viewer has the basic capability to handle the &lt;rect&gt; element.</desc>
+ <!--======================================================================-->
+ <!--Content of Test Case follows... =====================-->
+ <!--======================================================================-->
+ <g id="test-body-content">
+ <!-- ====================================================================== -->
+ <!-- First of all draw two simple rectangles. One stroked , one filled. -->
+ <!-- ====================================================================== -->
+ <text style="font-family:Helvetica;font-size:12;" x="160" y="14">Basic rectangles</text>
+ <text style="font-family:Helvetica;font-size:12;" x="82" y="60">width=50</text>
+ <text style="font-family:Helvetica;font-size:12;" x="78" y="76">height=100</text>
+ <rect id="Simple-rect-no-fill" style="fill:none;stroke:#000000" x="0" y="0" width="50" height="100" transform="skewX(0.1);translate(30,86)" />
+ <rect id="Simple-rect-filled" style="fill:red" x="130" y="86" width="50" height="100" />
+ <text style="font-family:Helvetica;font-size:12;" x="36" y="202">stroked</text>
+ <text style="font-family:Helvetica;font-size:12;" x="142" y="202">filled</text>
+ <!-- ====================================================================== -->
+ <!-- Second set of rectangles this time with rounded corners. -->
+ <!-- ====================================================================== -->
+ <text style="font-family:Helvetica;font-size:12;" x="302" y="50">width=50</text>
+ <text style="font-family:Helvetica;font-size:12;" x="298" y="66">height=100</text>
+ <text style="font-family:Helvetica;font-size:12;" x="310" y="82">rx=30</text>
+ <rect id="Simple-round-rect-no-fill" style="fill:none;stroke:#000000" x="250" y="86" width="50" height="100" rx="30"/>
+ <rect id="Simple-round-rect-filled" style="fill:red" x="350" y="86" width="50" height="100" rx="30"/>
+ <text style="font-family:Helvetica;font-size:12;" x="256" y="202">stroked</text>
+ <text style="font-family:Helvetica;font-size:12;" x="362" y="202">filled</text>
+ <!-- ====================================================================== -->
+ <!-- Third set of rectangles. -->
+ <!-- ====================================================================== -->
+ <text style="font-family:Helvetica;font-size:12;" x="82" y="230">width=50</text>
+ <text style="font-family:Helvetica;font-size:12;" x="78" y="246">height=100</text>
+ <rect id="rect-03" style="fill:none;stroke:#0000FF;stroke-width:8" x="30" y="266" width="50" height="100" transform="scale(0.5, 0.2)" />
+ <rect id="rect-04" style="fill:#00FF00;stroke:#0000FF;stroke-width:8" x="130" y="266" width="50" height="100" transform="rotate(25)" />
+ <text style="font-family:Helvetica;font-size:12;" x="36" y="382">stroked</text>
+ <text style="font-family:Helvetica;font-size:12;" x="118" y="382">filled &amp; stroked</text>
+ <!-- ====================================================================== -->
+ <!-- Fourth set of rectangles. -->
+ <!-- ====================================================================== -->
+ <text style="font-family:Helvetica;font-size:12;" x="302" y="230">width=50</text>
+ <text style="font-family:Helvetica;font-size:12;" x="298" y="246">height=100</text>
+ <text style="font-family:Helvetica;font-size:12;" x="296" y="262">rx=30 ry=50</text>
+ <rect id="rect-05" style="fill:none;stroke:#0000FF;stroke-width:8" x="250" y="266" width="50" height="100" rx="30" ry="50"/>
+ <rect id="rect-06" style="fill:#00FF00" x="350" y="266" width="50" height="100" rx="30" ry="50"/>
+ <text style="font-family:Helvetica;font-size:12;" x="256" y="382">stroked</text>
+ <text style="font-family:Helvetica;font-size:12;" x="362" y="382">filled</text>
+ </g>
+ <!--======================================================================-->
+ <!--Legend and frame: Title, suite and SVG document serialization====-->
+ <!--======================================================================-->
+ <g id="test-legend" style="fill:black;font-family:Helvetica;font-size:10">
+ <rect x="10" y="390" width="275" height="50" style="fill:none;stroke:#000000" transform="rotate(25)" />
+ <path style="fill:none;stroke:#000000" d="M10 405 h275 M205 405 v35 M10 426 h195 M205 422 h80"/>
+ <text x="25" y="401">Scalable Vector Graphics (SVG) Conformance Suite</text>
+ <a xlink:href="copyright-documents-19990405.html">
+ <text x="12" y="437" style="fill:blue">Copyright 2000 W3C. All Rights Reserved.</text>
+ </a>
+ <text style="font-size:12" x="35" y="420">shapes-rect-BE-01</text>
+ <text style="font-size:10" x="210" y="417">$Revision$</text>
+ <text style="font-size:10" x="210" y="435">Release 2.0</text>
+ <rect id="test-frame" x="1" y="1" width="448" height="448" style="fill:none; stroke:#000000"/>
+ </g>
+</svg>
diff --git a/ksvg/test/tiger.svg b/ksvg/test/tiger.svg
new file mode 100644
index 00000000..f2c13913
--- /dev/null
+++ b/ksvg/test/tiger.svg
@@ -0,0 +1,722 @@
+<svg>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
+ <path d="M-122.304 84.285C-122.304 84.285 -122.203 86.179 -123.027 86.16C-123.851 86.141 -140.305 38.066 -160.833 40.309C-160.833 40.309 -143.05 32.956 -122.304 84.285z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
+ <path d="M-118.774 81.262C-118.774 81.262 -119.323 83.078 -120.092 82.779C-120.86 82.481 -119.977 31.675 -140.043 26.801C-140.043 26.801 -120.82 25.937 -118.774 81.262z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
+ <path d="M-91.284 123.59C-91.284 123.59 -89.648 124.55 -90.118 125.227C-90.589 125.904 -139.763 113.102 -149.218 131.459C-149.218 131.459 -145.539 112.572 -91.284 123.59z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
+ <path d="M-94.093 133.801C-94.093 133.801 -92.237 134.197 -92.471 134.988C-92.704 135.779 -143.407 139.121 -146.597 159.522C-146.597 159.522 -149.055 140.437 -94.093 133.801z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
+ <path d="M-98.304 128.276C-98.304 128.276 -96.526 128.939 -96.872 129.687C-97.218 130.435 -147.866 126.346 -153.998 146.064C-153.998 146.064 -153.646 126.825 -98.304 128.276z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
+ <path d="M-109.009 110.072C-109.009 110.072 -107.701 111.446 -108.34 111.967C-108.979 112.488 -152.722 86.634 -166.869 101.676C-166.869 101.676 -158.128 84.533 -109.009 110.072z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
+ <path d="M-116.554 114.263C-116.554 114.263 -115.098 115.48 -115.674 116.071C-116.25 116.661 -162.638 95.922 -174.992 112.469C-174.992 112.469 -168.247 94.447 -116.554 114.263z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
+ <path d="M-119.154 118.335C-119.154 118.335 -117.546 119.343 -118.036 120.006C-118.526 120.669 -167.308 106.446 -177.291 124.522C-177.291 124.522 -173.066 105.749 -119.154 118.335z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
+ <path d="M-108.42 118.949C-108.42 118.949 -107.298 120.48 -107.999 120.915C-108.7 121.35 -148.769 90.102 -164.727 103.207C-164.727 103.207 -153.862 87.326 -108.42 118.949z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
+ <path d="M-128.2 90C-128.2 90 -127.6 91.8 -128.4 92C-129.2 92.2 -157.8 50.2 -177.001 57.8C-177.001 57.8 -161.8 46 -128.2 90z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
+ <path d="M-127.505 96.979C-127.505 96.979 -126.53 98.608 -127.269 98.975C-128.007 99.343 -164.992 64.499 -182.101 76.061C-182.101 76.061 -169.804 61.261 -127.505 96.979z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
+ <path d="M-127.62 101.349C-127.62 101.349 -126.498 102.88 -127.199 103.315C-127.9 103.749 -167.969 72.502 -183.927 85.607C-183.927 85.607 -173.062 69.726 -127.62 101.349z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000">
+ <path d="M-129.83 103.065C-129.327 109.113 -128.339 115.682 -126.6 118.801C-126.6 118.801 -130.2 131.201 -121.4 144.401C-121.4 144.401 -121.8 151.601 -120.2 154.801C-120.2 154.801 -116.2 163.201 -111.4 164.001C-107.516 164.648 -98.793 167.717 -88.932 169.121C-88.932 169.121 -71.8 183.201 -75 196.001C-75 196.001 -75.4 212.401 -79 214.001C-79 214.001 -67.4 202.801 -77 219.601L-81.4 238.401C-81.4 238.401 -55.8 216.801 -71.4 235.201L-81.4 261.201C-81.4 261.201 -61.8 242.801 -69 251.201L-72.2 260.001C-72.2 260.001 -29 232.801 -59.8 262.401C-59.8 262.401 -51.8 258.801 -47.4 261.601C-47.4 261.601 -40.6 260.401 -41.4 262.001C-41.4 262.001 -62.2 272.401 -65.8 290.801C-65.8 290.801 -57.4 280.801 -60.6 291.601L-60.2 303.201C-60.2 303.201 -56.2 281.601 -56.6 319.201C-56.6 319.201 -37.4 301.201 -49 322.001L-49 338.801C-49 338.801 -33.8 322.401 -40.2 335.201C-40.2 335.201 -30.2 326.401 -34.2 341.601C-34.2 341.601 -35 352.001 -30.6 340.801C-30.6 340.801 -14.6 310.201 -20.6 336.401C-20.6 336.401 -21.4 355.601 -16.6 340.801C-16.6 340.801 -16.2 351.201 -7 358.401C-7 358.401 -8.2 307.601 4.6 343.601L8.6 360.001C8.6 360.001 11.4 350.801 11 345.601C11 345.601 25.8 329.201 19 353.601C19 353.601 34.2 330.801 31 344.001C31 344.001 23.4 360.001 25 364.801C25 364.801 41.8 330.001 43 328.401C43 328.401 41 370.802 51.8 334.801C51.8 334.801 57.4 346.801 54.6 351.201C54.6 351.201 62.6 343.201 61.8 340.001C61.8 340.001 66.4 331.801 69.2 345.401C69.2 345.401 71 354.801 72.6 351.601C72.6 351.601 76.6 375.602 77.8 352.801C77.8 352.801 79.4 339.201 72.2 327.601C72.2 327.601 73 324.401 70.2 320.401C70.2 320.401 83.8 342.001 76.6 313.201C76.6 313.201 87.801 321.201 89.001 321.201C89.001 321.201 75.4 298.001 84.2 302.801C84.2 302.801 79 292.401 97.001 304.401C97.001 304.401 81 288.401 98.601 298.001C98.601 298.001 106.601 304.401 99.001 294.401C99.001 294.401 84.6 278.401 106.601 296.401C106.601 296.401 118.201 312.801 119.001 315.601C119.001 315.601 109.001 286.401 104.601 283.601C104.601 283.601 113.001 247.201 154.201 262.801C154.201 262.801 161.001 280.001 165.401 261.601C165.401 261.601 178.201 255.201 189.401 282.801C189.401 282.801 193.401 269.201 192.601 266.401C192.601 266.401 199.401 267.601 198.601 266.401C198.601 266.401 211.801 270.801 213.001 270.001C213.001 270.001 219.801 276.801 220.201 273.201C220.201 273.201 229.401 276.001 227.401 272.401C227.401 272.401 236.201 288.001 236.601 291.601L239.001 277.601L241.001 280.401C241.001 280.401 242.601 272.801 241.801 271.601C241.001 270.401 261.801 278.401 266.601 299.201L268.601 307.601C268.601 307.601 274.601 292.801 273.001 288.801C273.001 288.801 278.201 289.601 278.601 294.001C278.601 294.001 282.601 270.801 277.801 264.801C277.801 264.801 282.201 264.001 283.401 267.601L283.401 260.401C283.401 260.401 290.601 261.201 290.601 258.801C290.601 258.801 295.001 254.801 297.001 259.601C297.001 259.601 284.601 224.401 303.001 243.601C303.001 243.601 310.201 254.401 306.601 235.601C303.001 216.801 299.001 215.201 303.801 214.801C303.801 214.801 304.601 211.201 302.601 209.601C300.601 208.001 303.801 209.601 303.801 209.601C303.801 209.601 308.601 213.601 303.401 191.601C303.401 191.601 309.801 193.201 297.801 164.001C297.801 164.001 300.601 161.601 296.601 153.201C296.601 153.201 304.601 157.601 307.401 156.001C307.401 156.001 307.001 154.401 303.801 150.401C303.801 150.401 282.201 95.6 302.601 117.601C302.601 117.601 314.451 131.151 308.051 108.351C308.051 108.351 298.94 84.341 299.717 80.045L-129.83 103.065z"/>
+ </g>
+ <g style="fill: #cc7226; stroke:#000000">
+ <path d="M299.717 80.245C300.345 80.426 302.551 81.55 303.801 83.2C303.801 83.2 310.601 94 305.401 75.6C305.401 75.6 296.201 46.8 305.001 58C305.001 58 311.001 65.2 307.801 51.6C303.936 35.173 301.401 28.8 301.401 28.8C301.401 28.8 313.001 33.6 286.201 -6L295.001 -2.4C295.001 -2.4 275.401 -42 253.801 -47.2L245.801 -53.2C245.801 -53.2 284.201 -91.2 271.401 -128C271.401 -128 264.601 -133.2 255.001 -124C255.001 -124 248.601 -119.2 242.601 -120.8C242.601 -120.8 211.801 -119.6 209.801 -119.6C207.801 -119.6 173.001 -156.8 107.401 -139.2C107.401 -139.2 102.201 -137.2 97.801 -138.4C97.801 -138.4 79.4 -154.4 30.6 -131.6C30.6 -131.6 20.6 -129.6 19 -129.6C17.4 -129.6 14.6 -129.6 6.6 -123.2C-1.4 -116.8 -1.8 -116 -3.8 -114.4C-3.8 -114.4 -20.2 -103.2 -25 -102.4C-25 -102.4 -36.6 -96 -41 -86L-44.6 -84.8C-44.6 -84.8 -46.2 -77.6 -46.6 -76.4C-46.6 -76.4 -51.4 -72.8 -52.2 -67.2C-52.2 -67.2 -61 -61.2 -60.6 -56.8C-60.6 -56.8 -62.2 -51.6 -63 -46.8C-63 -46.8 -70.2 -42 -69.4 -39.2C-69.4 -39.2 -77 -25.2 -75.8 -18.4C-75.8 -18.4 -82.2 -18.8 -85 -16.4C-85 -16.4 -85.8 -11.6 -87.4 -11.2C-87.4 -11.2 -90.2 -10 -87.8 -6C-87.8 -6 -89.4 -3.2 -89.8 -1.6C-89.8 -1.6 -89 1.2 -93.4 6.8C-93.4 6.8 -99.8 25.6 -97.8 30.8C-97.8 30.8 -97.4 35.6 -100.2 37.2C-100.2 37.2 -103.8 36.8 -95.4 48.8C-95.4 48.8 -94.6 50 -97.8 52.4C-97.8 52.4 -115 56 -117.4 72.4C-117.4 72.4 -131 87.2 -131 92.4C-131 94.705 -130.729 97.852 -130.03 102.465C-130.03 102.465 -130.6 110.801 -103 111.601C-75.4 112.401 299.717 80.245 299.717 80.245z"/>
+ </g>
+ <g style="fill: #cc7226">
+ <path d="M-115.6 102.6C-140.6 63.2 -126.2 119.601 -126.2 119.601C-117.4 154.001 12.2 116.401 12.2 116.401C12.2 116.401 181.001 86 192.201 82C203.401 78 298.601 84.4 298.601 84.4L293.001 67.6C228.201 21.2 209.001 44.4 195.401 40.4C181.801 36.4 184.201 46 181.001 46.8C177.801 47.6 138.601 22.8 132.201 23.6C125.801 24.4 100.459 0.649 115.401 32.4C131.401 66.4 57 71.6 40.2 60.4C23.4 49.2 47.4 78.8 47.4 78.8C65.8 98.8 31.4 82 31.4 82C-3 69.2 -27 94.8 -30.2 95.6C-33.4 96.4 -38.2 99.6 -39 93.2C-39.8 86.8 -47.31 70.099 -79 96.4C-99 113.001 -112.8 91 -112.8 91L-115.6 102.6z"/>
+ </g>
+ <g style="fill: #e87f3a">
+ <path d="M133.51 25.346C127.11 26.146 101.743 2.407 116.71 34.146C133.31 69.346 58.31 73.346 41.51 62.146C24.709 50.946 48.71 80.546 48.71 80.546C67.11 100.546 32.709 83.746 32.709 83.746C-1.691 70.946 -25.691 96.546 -28.891 97.346C-32.091 98.146 -36.891 101.346 -37.691 94.946C-38.491 88.546 -45.87 72.012 -77.691 98.146C-98.927 115.492 -112.418 94.037 -112.418 94.037L-115.618 104.146C-140.618 64.346 -125.546 122.655 -125.546 122.655C-116.745 157.056 13.509 118.146 13.509 118.146C13.509 118.146 182.31 87.746 193.51 83.746C204.71 79.746 299.038 86.073 299.038 86.073L293.51 68.764C228.71 22.364 210.31 46.146 196.71 42.146C183.11 38.146 185.51 47.746 182.31 48.546C179.11 49.346 139.91 24.546 133.51 25.346z"/>
+ </g>
+ <g style="fill: #ea8c4d">
+ <path d="M134.819 27.091C128.419 27.891 103.685 3.862 118.019 35.891C134.219 72.092 59.619 75.092 42.819 63.892C26.019 52.692 50.019 82.292 50.019 82.292C68.419 102.292 34.019 85.492 34.019 85.492C-0.381 72.692 -24.382 98.292 -27.582 99.092C-30.782 99.892 -35.582 103.092 -36.382 96.692C-37.182 90.292 -44.43 73.925 -76.382 99.892C-98.855 117.983 -112.036 97.074 -112.036 97.074L-115.636 105.692C-139.436 66.692 -124.891 125.71 -124.891 125.71C-116.091 160.11 14.819 119.892 14.819 119.892C14.819 119.892 183.619 89.492 194.819 85.492C206.019 81.492 299.474 87.746 299.474 87.746L294.02 69.928C229.219 23.528 211.619 47.891 198.019 43.891C184.419 39.891 186.819 49.491 183.619 50.292C180.419 51.092 141.219 26.291 134.819 27.091z"/>
+ </g>
+ <g style="fill: #ec9961">
+ <path d="M136.128 28.837C129.728 29.637 104.999 5.605 119.328 37.637C136.128 75.193 60.394 76.482 44.128 65.637C27.328 54.437 51.328 84.037 51.328 84.037C69.728 104.037 35.328 87.237 35.328 87.237C0.928 74.437 -23.072 100.037 -26.272 100.837C-29.472 101.637 -34.272 104.837 -35.072 98.437C-35.872 92.037 -42.989 75.839 -75.073 101.637C-98.782 120.474 -111.655 100.11 -111.655 100.11L-115.655 107.237C-137.455 70.437 -124.236 128.765 -124.236 128.765C-115.436 163.165 16.128 121.637 16.128 121.637C16.128 121.637 184.928 91.237 196.129 87.237C207.329 83.237 299.911 89.419 299.911 89.419L294.529 71.092C229.729 24.691 212.929 49.637 199.329 45.637C185.728 41.637 188.128 51.237 184.928 52.037C181.728 52.837 142.528 28.037 136.128 28.837z"/>
+ </g>
+ <g style="fill: #eea575">
+ <path d="M137.438 30.583C131.037 31.383 106.814 7.129 120.637 39.383C137.438 78.583 62.237 78.583 45.437 67.383C28.637 56.183 52.637 85.783 52.637 85.783C71.037 105.783 36.637 88.983 36.637 88.983C2.237 76.183 -21.763 101.783 -24.963 102.583C-28.163 103.383 -32.963 106.583 -33.763 100.183C-34.563 93.783 -41.548 77.752 -73.763 103.383C-98.709 122.965 -111.273 103.146 -111.273 103.146L-115.673 108.783C-135.473 73.982 -123.582 131.819 -123.582 131.819C-114.782 166.22 17.437 123.383 17.437 123.383C17.437 123.383 186.238 92.983 197.438 88.983C208.638 84.983 300.347 91.092 300.347 91.092L295.038 72.255C230.238 25.855 214.238 51.383 200.638 47.383C187.038 43.383 189.438 52.983 186.238 53.783C183.038 54.583 143.838 29.783 137.438 30.583z"/>
+ </g>
+ <g style="fill: #f1b288">
+ <path d="M138.747 32.328C132.347 33.128 106.383 9.677 121.947 41.128C141.147 79.928 63.546 80.328 46.746 69.128C29.946 57.928 53.946 87.528 53.946 87.528C72.346 107.528 37.946 90.728 37.946 90.728C3.546 77.928 -20.454 103.528 -23.654 104.328C-26.854 105.128 -31.654 108.328 -32.454 101.928C-33.254 95.528 -40.108 79.665 -72.454 105.128C-98.636 125.456 -110.891 106.183 -110.891 106.183L-115.691 110.328C-133.691 77.128 -122.927 134.874 -122.927 134.874C-114.127 169.274 18.746 125.128 18.746 125.128C18.746 125.128 187.547 94.728 198.747 90.728C209.947 86.728 300.783 92.764 300.783 92.764L295.547 73.419C230.747 27.019 215.547 53.128 201.947 49.128C188.347 45.128 190.747 54.728 187.547 55.528C184.347 56.328 145.147 31.528 138.747 32.328z"/>
+ </g>
+ <g style="fill: #f3bf9c">
+ <path d="M140.056 34.073C133.655 34.873 107.313 11.613 123.255 42.873C143.656 82.874 64.855 82.074 48.055 70.874C31.255 59.674 55.255 89.274 55.255 89.274C73.655 109.274 39.255 92.474 39.255 92.474C4.855 79.674 -19.145 105.274 -22.345 106.074C-25.545 106.874 -30.345 110.074 -31.145 103.674C-31.945 97.274 -38.668 81.578 -71.145 106.874C-98.564 127.947 -110.509 109.219 -110.509 109.219L-115.709 111.874C-131.709 81.674 -122.273 137.929 -122.273 137.929C-113.473 172.329 20.055 126.874 20.055 126.874C20.055 126.874 188.856 96.474 200.056 92.474C211.256 88.474 301.22 94.437 301.22 94.437L296.056 74.583C231.256 28.183 216.856 54.874 203.256 50.874C189.656 46.873 192.056 56.474 188.856 57.274C185.656 58.074 146.456 33.273 140.056 34.073z"/>
+ </g>
+ <g style="fill: #f5ccb0">
+ <path d="M141.365 35.819C134.965 36.619 107.523 13.944 124.565 44.619C146.565 84.219 66.164 83.819 49.364 72.619C32.564 61.419 56.564 91.019 56.564 91.019C74.964 111.019 40.564 94.219 40.564 94.219C6.164 81.419 -17.836 107.019 -21.036 107.819C-24.236 108.619 -29.036 111.819 -29.836 105.419C-30.636 99.019 -37.227 83.492 -69.836 108.619C-98.491 130.438 -110.127 112.256 -110.127 112.256L-115.727 113.419C-130.128 85.019 -121.618 140.983 -121.618 140.983C-112.818 175.384 21.364 128.619 21.364 128.619C21.364 128.619 190.165 98.219 201.365 94.219C212.565 90.219 301.656 96.11 301.656 96.11L296.565 75.746C231.765 29.346 218.165 56.619 204.565 52.619C190.965 48.619 193.365 58.219 190.165 59.019C186.965 59.819 147.765 35.019 141.365 35.819z"/>
+ </g>
+ <g style="fill: #f8d8c4">
+ <path d="M142.674 37.565C136.274 38.365 108.832 15.689 125.874 46.365C147.874 85.965 67.474 85.565 50.674 74.365C33.874 63.165 57.874 92.765 57.874 92.765C76.274 112.765 41.874 95.965 41.874 95.965C7.473 83.165 -16.527 108.765 -19.727 109.565C-22.927 110.365 -27.727 113.565 -28.527 107.165C-29.327 100.765 -35.786 85.405 -68.527 110.365C-98.418 132.929 -109.745 115.293 -109.745 115.293L-115.745 114.965C-129.346 88.564 -120.963 144.038 -120.963 144.038C-112.163 178.438 22.673 130.365 22.673 130.365C22.673 130.365 191.474 99.965 202.674 95.965C213.874 91.965 302.093 97.783 302.093 97.783L297.075 76.91C232.274 30.51 219.474 58.365 205.874 54.365C192.274 50.365 194.674 59.965 191.474 60.765C188.274 61.565 149.074 36.765 142.674 37.565z"/>
+ </g>
+ <g style="fill: #fae5d7">
+ <path d="M143.983 39.31C137.583 40.11 110.529 17.223 127.183 48.11C149.183 88.91 68.783 87.31 51.983 76.11C35.183 64.91 59.183 94.51 59.183 94.51C77.583 114.51 43.183 97.71 43.183 97.71C8.783 84.91 -15.217 110.51 -18.417 111.31C-21.618 112.11 -26.418 115.31 -27.218 108.91C-28.018 102.51 -34.346 87.318 -67.218 112.11C-98.345 135.42 -109.363 118.329 -109.363 118.329L-115.764 116.51C-128.764 92.51 -120.309 147.093 -120.309 147.093C-111.509 181.493 23.983 132.11 23.983 132.11C23.983 132.11 192.783 101.71 203.983 97.71C215.183 93.71 302.529 99.456 302.529 99.456L297.583 78.074C232.783 31.673 220.783 60.11 207.183 56.11C193.583 52.11 195.983 61.71 192.783 62.51C189.583 63.31 150.383 38.51 143.983 39.31z"/>
+ </g>
+ <g style="fill: #fcf2eb">
+ <path d="M145.292 41.055C138.892 41.855 112.917 18.411 128.492 49.855C149.692 92.656 70.092 89.056 53.292 77.856C36.492 66.656 60.492 96.256 60.492 96.256C78.892 116.256 44.492 99.456 44.492 99.456C10.092 86.656 -13.908 112.256 -17.108 113.056C-20.308 113.856 -25.108 117.056 -25.908 110.656C-26.708 104.256 -32.905 89.232 -65.908 113.856C-98.273 137.911 -108.982 121.365 -108.982 121.365L-115.782 118.056C-128.582 94.856 -119.654 150.147 -119.654 150.147C-110.854 184.547 25.292 133.856 25.292 133.856C25.292 133.856 194.093 103.456 205.293 99.456C216.493 95.456 302.965 101.128 302.965 101.128L298.093 79.237C233.292 32.837 222.093 61.856 208.493 57.856C194.893 53.855 197.293 63.456 194.093 64.256C190.892 65.056 151.692 40.255 145.292 41.055z"/>
+ </g>
+ <g style="fill: #ffffff">
+ <path d="M-115.8 119.601C-128.6 97.6 -119 153.201 -119 153.201C-110.2 187.601 26.6 135.601 26.6 135.601C26.6 135.601 195.401 105.2 206.601 101.2C217.801 97.2 303.401 102.8 303.401 102.8L298.601 80.4C233.801 34 223.401 63.6 209.801 59.6C196.201 55.6 198.601 65.2 195.401 66C192.201 66.8 153.001 42 146.601 42.8C140.201 43.6 114.981 19.793 129.801 51.6C152.028 99.307 69.041 89.227 54.6 79.6C37.8 68.4 61.8 98 61.8 98C80.2 118.001 45.8 101.2 45.8 101.2C11.4 88.4 -12.6 114.001 -15.8 114.801C-19 115.601 -23.8 118.801 -24.6 112.401C-25.4 106 -31.465 91.144 -64.6 115.601C-98.2 140.401 -108.6 124.401 -108.6 124.401L-115.8 119.601z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-74.2 149.601C-74.2 149.601 -81.4 161.201 -60.6 174.401C-60.6 174.401 -59.2 175.801 -77.2 171.601C-77.2 171.601 -83.4 169.601 -85 159.201C-85 159.201 -89.8 154.801 -94.6 149.201C-99.4 143.601 -74.2 149.601 -74.2 149.601z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M65.8 102C65.8 102 83.498 128.821 82.9 133.601C81.6 144.001 81.4 153.601 84.6 157.601C87.801 161.601 96.601 194.801 96.601 194.801C96.601 194.801 96.201 196.001 108.601 158.001C108.601 158.001 120.201 142.001 100.201 123.601C100.201 123.601 65 94.8 65.8 102z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-54.2 176.401C-54.2 176.401 -43 183.601 -57.4 214.801L-51 212.401C-51 212.401 -51.8 223.601 -55 226.001L-47.8 222.801C-47.8 222.801 -43 230.801 -47 235.601C-47 235.601 -30.2 243.601 -31 250.001C-31 250.001 -24.6 242.001 -28.6 235.601C-32.6 229.201 -39.8 233.201 -39 214.801L-47.8 218.001C-47.8 218.001 -42.2 209.201 -42.2 202.801L-50.2 205.201C-50.2 205.201 -34.731 178.623 -45.4 177.201C-51.4 176.401 -54.2 176.401 -54.2 176.401z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-21.8 193.201C-21.8 193.201 -19 188.801 -21.8 189.601C-24.6 190.401 -55.8 205.201 -61.8 214.801C-61.8 214.801 -27.4 190.401 -21.8 193.201z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-11.4 201.201C-11.4 201.201 -8.6 196.801 -11.4 197.601C-14.2 198.401 -45.4 213.201 -51.4 222.801C-51.4 222.801 -17 198.401 -11.4 201.201z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M1.8 186.001C1.8 186.001 4.6 181.601 1.8 182.401C-1 183.201 -32.2 198.001 -38.2 207.601C-38.2 207.601 -3.8 183.201 1.8 186.001z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-21.4 229.601C-21.4 229.601 -21.4 223.601 -24.2 224.401C-27 225.201 -63 242.801 -69 252.401C-69 252.401 -27 226.801 -21.4 229.601z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-20.2 218.801C-20.2 218.801 -19 214.001 -21.8 214.801C-23.8 214.801 -50.2 226.401 -56.2 236.001C-56.2 236.001 -26.6 214.401 -20.2 218.801z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-34.6 266.401L-44.6 274.001C-44.6 274.001 -34.2 266.401 -30.6 267.601C-30.6 267.601 -37.4 278.801 -38.2 284.001C-38.2 284.001 -27.8 271.201 -22.2 271.601C-22.2 271.601 -14.6 272.001 -14.6 282.801C-14.6 282.801 -9 272.401 -5.8 272.801C-5.8 272.801 -4.6 279.201 -5.8 286.001C-5.8 286.001 -1.8 278.401 2.2 280.001C2.2 280.001 8.6 278.001 7.8 289.601C7.8 289.601 7.8 300.001 7 302.801C7 302.801 12.6 276.401 15 276.001C15 276.001 23 274.801 27.8 283.601C27.8 283.601 23.8 276.001 28.6 278.001C28.6 278.001 39.4 279.601 42.6 286.401C42.6 286.401 35.8 274.401 41.4 277.601C41.4 277.601 48.2 277.601 49.4 284.001C49.4 284.001 57.8 305.201 59.8 306.801C59.8 306.801 52.2 285.201 53.8 285.201C53.8 285.201 51.8 273.201 57 288.001C57 288.001 53.8 274.001 59.4 274.801C65 275.601 69.4 285.601 77.8 283.201C77.8 283.201 87.401 288.801 89.401 219.601L-34.6 266.401z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-29.8 173.601C-29.8 173.601 -15 167.601 25 173.601C25 173.601 32.2 174.001 39 165.201C45.8 156.401 72.6 149.201 79 151.201L88.601 157.601L89.401 158.801C89.401 158.801 101.801 169.201 102.201 176.801C102.601 184.401 87.801 232.401 78.2 248.401C68.6 264.401 59 276.801 39.8 274.401C39.8 274.401 19 270.401 -6.6 274.401C-6.6 274.401 -35.8 272.801 -38.6 264.801C-41.4 256.801 -27.4 241.601 -27.4 241.601C-27.4 241.601 -23 233.201 -24.2 218.801C-25.4 204.401 -25 176.401 -29.8 173.601z"/>
+ </g>
+ <g style="fill: #e5668c">
+ <path d="M-7.8 175.601C0.6 194.001 -29 259.201 -29 259.201C-31 260.801 -16.34 266.846 -6.2 264.401C4.746 261.763 45 266.001 45 266.001C68.6 250.401 81.4 206.001 81.4 206.001C81.4 206.001 91.801 182.001 74.2 178.801C56.6 175.601 -7.8 175.601 -7.8 175.601z"/>
+ </g>
+ <g style="fill: #b23259">
+ <path d="M-9.831 206.497C-6.505 193.707 -4.921 181.906 -7.8 175.601C-7.8 175.601 54.6 182.001 65.8 161.201C70.041 153.326 84.801 184.001 84.4 193.601C84.4 193.601 21.4 208.001 6.6 196.801L-9.831 206.497z"/>
+ </g>
+ <g style="fill: #a5264c">
+ <path d="M-5.4 222.801C-5.4 222.801 -3.4 230.001 -5.8 234.001C-5.8 234.001 -7.4 234.801 -8.6 235.201C-8.6 235.201 -7.4 238.801 -1.4 240.401C-1.4 240.401 0.6 244.801 3 245.201C5.4 245.601 10.2 251.201 14.2 250.001C18.2 248.801 29.4 244.801 29.4 244.801C29.4 244.801 35 241.601 43.8 245.201C43.8 245.201 46.175 244.399 46.6 240.401C47.1 235.701 50.2 232.001 52.2 230.001C54.2 228.001 63.8 215.201 62.6 214.801C61.4 214.401 -5.4 222.801 -5.4 222.801z"/>
+ </g>
+ <g style="fill: #ff727f; stroke:#000000">
+ <path d="M-9.8 174.401C-9.8 174.401 -12.6 196.801 -9.4 205.201C-6.2 213.601 -7 215.601 -7.8 219.601C-8.6 223.601 -4.2 233.601 1.4 239.601L13.4 241.201C13.4 241.201 28.6 237.601 37.8 240.401C37.8 240.401 46.794 241.744 50.2 226.801C50.2 226.801 55 220.401 62.2 217.601C69.4 214.801 76.6 173.201 72.6 165.201C68.6 157.201 54.2 152.801 38.2 168.401C22.2 184.001 20.2 167.201 -9.8 174.401z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-8.2 249.201C-8.2 249.201 -9 247.201 -13.4 246.801C-13.4 246.801 -35.8 243.201 -44.2 230.801C-44.2 230.801 -51 225.201 -46.6 236.801C-46.6 236.801 -36.2 257.201 -29.4 260.001C-29.4 260.001 -13 264.001 -8.2 249.201z"/>
+ </g>
+ <g style="fill: #cc3f4c">
+ <path d="M71.742 185.229C72.401 177.323 74.354 168.709 72.6 165.201C66.154 152.307 49.181 157.695 38.2 168.401C22.2 184.001 20.2 167.201 -9.8 174.401C-9.8 174.401 -11.545 188.364 -10.705 198.376C-10.705 198.376 26.6 186.801 27.4 192.401C27.4 192.401 29 189.201 38.2 189.201C47.4 189.201 70.142 188.029 71.742 185.229z"/>
+ </g>
+ <g style="stroke:#a51926; stroke-width:2">
+ <path d="M28.6 175.201C28.6 175.201 33.4 180.001 29.8 189.601C29.8 189.601 15.4 205.601 17.4 219.601"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-19.4 260.001C-19.4 260.001 -23.8 247.201 -15 254.001C-15 254.001 -10.2 256.001 -11.4 257.601C-12.6 259.201 -18.2 263.201 -19.4 260.001z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-14.36 261.201C-14.36 261.201 -17.88 250.961 -10.84 256.401C-10.84 256.401 -6.419 258.849 -7.96 259.281C-12.52 260.561 -7.96 263.121 -14.36 261.201z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-9.56 261.201C-9.56 261.201 -13.08 250.961 -6.04 256.401C-6.04 256.401 -1.665 258.711 -3.16 259.281C-6.52 260.561 -3.16 263.121 -9.56 261.201z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-2.96 261.401C-2.96 261.401 -6.48 251.161 0.56 256.601C0.56 256.601 4.943 258.933 3.441 259.481C0.48 260.561 3.441 263.321 -2.96 261.401z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M3.52 261.321C3.52 261.321 0 251.081 7.041 256.521C7.041 256.521 10.881 258.121 9.921 259.401C8.961 260.681 9.921 263.241 3.52 261.321z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M10.2 262.001C10.2 262.001 5.4 249.601 14.6 256.001C14.6 256.001 19.4 258.001 18.2 259.601C17 261.201 18.2 264.401 10.2 262.001z"/>
+ </g>
+ <g style="stroke:#a5264c; stroke-width:2">
+ <path d="M-18.2 244.801C-18.2 244.801 -5 242.001 1 245.201C1 245.201 7 246.401 8.2 246.001C9.4 245.601 12.6 245.201 12.6 245.201"/>
+ </g>
+ <g style="stroke:#a5264c; stroke-width:2">
+ <path d="M15.8 253.601C15.8 253.601 27.8 240.001 39.8 244.401C46.816 246.974 45.8 243.601 46.6 240.801C47.4 238.001 47.6 233.801 52.6 230.801"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M33 237.601C33 237.601 29 226.801 26.2 239.601C23.4 252.401 20.2 256.001 18.6 258.801C18.6 258.801 18.6 264.001 27 263.601C27 263.601 37.8 263.201 38.2 260.401C38.6 257.601 37 246.001 33 237.601z"/>
+ </g>
+ <g style="stroke:#a5264c; stroke-width:2">
+ <path d="M47 244.801C47 244.801 50.6 242.401 53 243.601"/>
+ </g>
+ <g style="stroke:#a5264c; stroke-width:2">
+ <path d="M53.5 228.401C53.5 228.401 56.4 223.501 61.2 222.701"/>
+ </g>
+ <g style="fill: #b2b2b2">
+ <path d="M-25.8 265.201C-25.8 265.201 -7.8 268.401 -3.4 266.801C-3.4 266.801 5.4 266.801 -3 268.801C-3 268.801 -15.8 268.801 -23.8 267.601C-23.8 267.601 -35.4 262.001 -25.8 265.201z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-11.8 172.001C-11.8 172.001 5.8 172.001 7.8 172.801C7.8 172.801 15 203.601 11.4 211.201C11.4 211.201 10.2 214.001 7.4 208.401C7.4 208.401 -11 175.601 -14.2 173.601C-17.4 171.601 -13 172.001 -11.8 172.001z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-88.9 169.301C-88.9 169.301 -80 171.001 -67.4 173.601C-67.4 173.601 -62.6 196.001 -59.4 200.801C-56.2 205.601 -59.8 205.601 -63.4 202.801C-67 200.001 -81.8 186.001 -83.8 181.601C-85.8 177.201 -88.9 169.301 -88.9 169.301z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-67.039 173.818C-67.039 173.818 -61.239 175.366 -60.23 177.581C-59.222 179.795 -61.432 183.092 -61.432 183.092C-61.432 183.092 -62.432 186.397 -63.634 184.235C-64.836 182.072 -67.708 174.412 -67.039 173.818z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-67 173.601C-67 173.601 -63.4 178.801 -59.8 178.801C-56.2 178.801 -55.818 178.388 -53 179.001C-48.4 180.001 -48.8 178.001 -42.2 179.201C-39.56 179.681 -37 178.801 -34.2 180.001C-31.4 181.201 -28.2 180.401 -27 178.401C-25.8 176.401 -21 172.201 -21 172.201C-21 172.201 -33.8 174.001 -36.6 174.801C-36.6 174.801 -59 176.001 -67 173.601z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-22.4 173.801C-22.4 173.801 -28.85 177.301 -29.25 179.701C-29.65 182.101 -24 185.801 -24 185.801C-24 185.801 -21.25 190.401 -20.65 188.001C-20.05 185.601 -21.6 174.201 -22.4 173.801z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-59.885 179.265C-59.885 179.265 -52.878 190.453 -52.661 179.242C-52.661 179.242 -52.104 177.984 -53.864 177.962C-59.939 177.886 -58.418 173.784 -59.885 179.265z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-52.707 179.514C-52.707 179.514 -44.786 190.701 -45.422 179.421C-45.422 179.421 -45.415 179.089 -47.168 178.936C-51.915 178.522 -51.57 174.004 -52.707 179.514z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-45.494 179.522C-45.494 179.522 -37.534 190.15 -38.203 180.484C-38.203 180.484 -38.084 179.251 -39.738 178.95C-43.63 178.244 -43.841 174.995 -45.494 179.522z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-38.618 179.602C-38.618 179.602 -30.718 191.163 -30.37 181.382C-30.37 181.382 -28.726 180.004 -30.472 179.782C-36.29 179.042 -35.492 174.588 -38.618 179.602z"/>
+ </g>
+ <g style="fill: #e5e5b2">
+ <path d="M-74.792 183.132L-82.45 181.601C-85.05 176.601 -87.15 170.451 -87.15 170.451C-87.15 170.451 -80.8 171.451 -68.3 174.251C-68.3 174.251 -67.424 177.569 -65.952 183.364L-74.792 183.132z"/>
+ </g>
+ <g style="fill: #e5e5b2">
+ <path d="M-9.724 178.47C-11.39 175.964 -12.707 174.206 -13.357 173.8C-16.37 171.917 -12.227 172.294 -11.098 172.294C-11.098 172.294 5.473 172.294 7.356 173.047C7.356 173.047 7.88 175.289 8.564 178.68C8.564 178.68 -1.524 176.67 -9.724 178.47z"/>
+ </g>
+ <g style="fill: #cc7226">
+ <path d="M43.88 40.321C71.601 44.281 97.121 8.641 98.881 -1.04C100.641 -10.72 90.521 -22.6 90.521 -22.6C91.841 -25.68 87.001 -39.76 81.721 -49C76.441 -58.24 60.54 -57.266 43 -58.24C27.16 -59.12 8.68 -35.8 7.36 -34.04C6.04 -32.28 12.2 6.001 13.52 11.721C14.84 17.441 12.2 43.841 12.2 43.841C46.44 34.741 16.16 36.361 43.88 40.321z"/>
+ </g>
+ <g style="fill: #ea8e51">
+ <path d="M8.088 -33.392C6.792 -31.664 12.84 5.921 14.136 11.537C15.432 17.153 12.84 43.073 12.84 43.073C45.512 34.193 16.728 35.729 43.944 39.617C71.161 43.505 96.217 8.513 97.945 -0.992C99.673 -10.496 89.737 -22.16 89.737 -22.16C91.033 -25.184 86.281 -39.008 81.097 -48.08C75.913 -57.152 60.302 -56.195 43.08 -57.152C27.528 -58.016 9.384 -35.12 8.088 -33.392z"/>
+ </g>
+ <g style="fill: #efaa7c">
+ <path d="M8.816 -32.744C7.544 -31.048 13.48 5.841 14.752 11.353C16.024 16.865 13.48 42.305 13.48 42.305C44.884 33.145 17.296 35.097 44.008 38.913C70.721 42.729 95.313 8.385 97.009 -0.944C98.705 -10.272 88.953 -21.72 88.953 -21.72C90.225 -24.688 85.561 -38.256 80.473 -47.16C75.385 -56.064 60.063 -55.125 43.16 -56.064C27.896 -56.912 10.088 -34.44 8.816 -32.744z"/>
+ </g>
+ <g style="fill: #f4c6a8">
+ <path d="M9.544 -32.096C8.296 -30.432 14.12 5.761 15.368 11.169C16.616 16.577 14.12 41.537 14.12 41.537C43.556 32.497 17.864 34.465 44.072 38.209C70.281 41.953 94.409 8.257 96.073 -0.895C97.737 -10.048 88.169 -21.28 88.169 -21.28C89.417 -24.192 84.841 -37.504 79.849 -46.24C74.857 -54.976 59.824 -54.055 43.24 -54.976C28.264 -55.808 10.792 -33.76 9.544 -32.096z"/>
+ </g>
+ <g style="fill: #f9e2d3">
+ <path d="M10.272 -31.448C9.048 -29.816 14.76 5.681 15.984 10.985C17.208 16.289 14.76 40.769 14.76 40.769C42.628 31.849 18.432 33.833 44.136 37.505C69.841 41.177 93.505 8.129 95.137 -0.848C96.769 -9.824 87.385 -20.84 87.385 -20.84C88.609 -23.696 84.121 -36.752 79.225 -45.32C74.329 -53.888 59.585 -52.985 43.32 -53.888C28.632 -54.704 11.496 -33.08 10.272 -31.448z"/>
+ </g>
+ <g style="fill: #ffffff">
+ <path d="M44.2 36.8C69.4 40.4 92.601 8 94.201 -0.8C95.801 -9.6 86.601 -20.4 86.601 -20.4C87.801 -23.2 83.4 -36 78.6 -44.4C73.8 -52.8 59.346 -51.914 43.4 -52.8C29 -53.6 12.2 -32.4 11 -30.8C9.8 -29.2 15.4 5.6 16.6 10.8C17.8 16 15.4 40 15.4 40C40.9 31.4 19 33.2 44.2 36.8z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M90.601 2.8C90.601 2.8 62.8 10.4 51.2 8.8C51.2 8.8 35.4 2.2 26.6 24C26.6 24 23 31.2 21 33.2C19 35.2 90.601 2.8 90.601 2.8z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M94.401 0.6C94.401 0.6 65.4 12.8 55.4 12.4C55.4 12.4 39 7.8 30.6 22.4C30.6 22.4 22.2 31.6 19 33.2C19 33.2 18.6 34.8 25 30.8L35.4 36C35.4 36 50.2 45.6 59.8 29.6C59.8 29.6 63.8 18.4 63.8 16.4C63.8 14.4 85 8.8 86.601 8.4C88.201 8 94.801 3.8 94.401 0.6z"/>
+ </g>
+ <g style="fill: #99cc32">
+ <path d="M47 36.514C40.128 36.514 31.755 32.649 31.755 26.4C31.755 20.152 40.128 13.887 47 13.887C53.874 13.887 59.446 18.952 59.446 25.2C59.446 31.449 53.874 36.514 47 36.514z"/>
+ </g>
+ <g style="fill: #659900">
+ <path d="M43.377 19.83C38.531 20.552 33.442 22.055 33.514 21.839C35.054 17.22 41.415 13.887 47 13.887C51.296 13.887 55.084 15.865 57.32 18.875C57.32 18.875 52.004 18.545 43.377 19.83z"/>
+ </g>
+ <g style="fill: #ffffff">
+ <path d="M55.4 19.6C55.4 19.6 51 16.4 51 18.6C51 18.6 54.6 23 55.4 19.6z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M45.4 27.726C42.901 27.726 40.875 25.7 40.875 23.2C40.875 20.701 42.901 18.675 45.4 18.675C47.9 18.675 49.926 20.701 49.926 23.2C49.926 25.7 47.9 27.726 45.4 27.726z"/>
+ </g>
+ <g style="fill: #cc7226">
+ <path d="M-58.6 14.4C-58.6 14.4 -61.8 -6.8 -59.4 -11.2C-59.4 -11.2 -48.6 -21.2 -49 -24.8C-49 -24.8 -49.4 -42.8 -50.6 -43.6C-51.8 -44.4 -59.4 -50.4 -65.4 -44C-65.4 -44 -75.8 -26 -75 -19.6L-75 -17.6C-75 -17.6 -82.6 -18 -84.2 -16C-84.2 -16 -85.4 -10.8 -86.6 -10.4C-86.6 -10.4 -89.4 -8 -87.4 -5.2C-87.4 -5.2 -89.4 -2.8 -89 1.2L-81.4 5.2C-81.4 5.2 -79.4 19.6 -68.6 24.8C-63.764 27.129 -60.6 20.4 -58.6 14.4z"/>
+ </g>
+ <g style="fill: #ffffff">
+ <path d="M-59.6 12.56C-59.6 12.56 -62.48 -6.52 -60.32 -10.48C-60.32 -10.48 -50.6 -19.48 -50.96 -22.72C-50.96 -22.72 -51.32 -38.92 -52.4 -39.64C-53.48 -40.36 -60.32 -45.76 -65.72 -40C-65.72 -40 -75.08 -23.8 -74.36 -18.04L-74.36 -16.24C-74.36 -16.24 -81.2 -16.6 -82.64 -14.8C-82.64 -14.8 -83.72 -10.12 -84.8 -9.76C-84.8 -9.76 -87.32 -7.6 -85.52 -5.08C-85.52 -5.08 -87.32 -2.92 -86.96 0.68L-80.12 4.28C-80.12 4.28 -78.32 17.24 -68.6 21.92C-64.248 24.015 -61.4 17.96 -59.6 12.56z"/>
+ </g>
+ <g style="fill: #eb955c">
+ <path d="M-51.05 -42.61C-52.14 -43.47 -59.63 -49.24 -65.48 -43C-65.48 -43 -75.62 -25.45 -74.84 -19.21L-74.84 -17.26C-74.84 -17.26 -82.25 -17.65 -83.81 -15.7C-83.81 -15.7 -84.98 -10.63 -86.15 -10.24C-86.15 -10.24 -88.88 -7.9 -86.93 -5.17C-86.93 -5.17 -88.88 -2.83 -88.49 1.07L-81.08 4.97C-81.08 4.97 -79.13 19.01 -68.6 24.08C-63.886 26.35 -60.8 19.79 -58.85 13.94C-58.85 13.94 -61.97 -6.73 -59.63 -11.02C-59.63 -11.02 -49.1 -20.77 -49.49 -24.28C-49.49 -24.28 -49.88 -41.83 -51.05 -42.61z"/>
+ </g>
+ <g style="fill: #f2b892">
+ <path d="M-51.5 -41.62C-52.48 -42.54 -59.86 -48.08 -65.56 -42C-65.56 -42 -75.44 -24.9 -74.68 -18.82L-74.68 -16.92C-74.68 -16.92 -81.9 -17.3 -83.42 -15.4C-83.42 -15.4 -84.56 -10.46 -85.7 -10.08C-85.7 -10.08 -88.36 -7.8 -86.46 -5.14C-86.46 -5.14 -88.36 -2.86 -87.98 0.94L-80.76 4.74C-80.76 4.74 -78.86 18.42 -68.6 23.36C-64.006 25.572 -61 19.18 -59.1 13.48C-59.1 13.48 -62.14 -6.66 -59.86 -10.84C-59.86 -10.84 -49.6 -20.34 -49.98 -23.76C-49.98 -23.76 -50.36 -40.86 -51.5 -41.62z"/>
+ </g>
+ <g style="fill: #f8dcc8">
+ <path d="M-51.95 -40.63C-52.82 -41.61 -60.09 -46.92 -65.64 -41C-65.64 -41 -75.26 -24.35 -74.52 -18.43L-74.52 -16.58C-74.52 -16.58 -81.55 -16.95 -83.03 -15.1C-83.03 -15.1 -84.14 -10.29 -85.25 -9.92C-85.25 -9.92 -87.84 -7.7 -85.99 -5.11C-85.99 -5.11 -87.84 -2.89 -87.47 0.81L-80.44 4.51C-80.44 4.51 -78.59 17.83 -68.6 22.64C-64.127 24.794 -61.2 18.57 -59.35 13.02C-59.35 13.02 -62.31 -6.59 -60.09 -10.66C-60.09 -10.66 -50.1 -19.91 -50.47 -23.24C-50.47 -23.24 -50.84 -39.89 -51.95 -40.63z"/>
+ </g>
+ <g style="fill: #ffffff">
+ <path d="M-59.6 12.46C-59.6 12.46 -62.48 -6.52 -60.32 -10.48C-60.32 -10.48 -50.6 -19.48 -50.96 -22.72C-50.96 -22.72 -51.32 -38.92 -52.4 -39.64C-53.16 -40.68 -60.32 -45.76 -65.72 -40C-65.72 -40 -75.08 -23.8 -74.36 -18.04L-74.36 -16.24C-74.36 -16.24 -81.2 -16.6 -82.64 -14.8C-82.64 -14.8 -83.72 -10.12 -84.8 -9.76C-84.8 -9.76 -87.32 -7.6 -85.52 -5.08C-85.52 -5.08 -87.32 -2.92 -86.96 0.68L-80.12 4.28C-80.12 4.28 -78.32 17.24 -68.6 21.92C-64.248 24.015 -61.4 17.86 -59.6 12.46z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-62.7 6.2C-62.7 6.2 -84.3 -4 -85.2 -4.8C-85.2 -4.8 -76.1 3.4 -75.3 3.4C-74.5 3.4 -62.7 6.2 -62.7 6.2z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-79.8 0C-79.8 0 -61.4 3.6 -61.4 8C-61.4 10.912 -61.643 24.331 -67 22.8C-75.4 20.4 -71.8 6 -79.8 0z"/>
+ </g>
+ <g style="fill: #99cc32">
+ <path d="M-71.4 3.8C-71.4 3.8 -62.422 5.274 -61.4 8C-60.8 9.6 -60.137 17.908 -65.6 19C-70.152 19.911 -72.382 9.69 -71.4 3.8z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M14.595 46.349C14.098 44.607 15.409 44.738 17.2 44.2C19.2 43.6 31.4 39.8 32.2 37.2C33 34.6 46.2 39 46.2 39C48 39.8 52.4 42.4 52.4 42.4C57.2 43.6 63.8 44 63.8 44C66.2 45 69.6 47.8 69.6 47.8C84.2 58 96.601 50.8 96.601 50.8C116.601 44.2 110.601 27 110.601 27C107.601 18 110.801 14.6 110.801 14.6C111.001 10.8 118.201 17.2 118.201 17.2C120.801 21.4 121.601 26.4 121.601 26.4C129.601 37.6 126.201 19.8 126.201 19.8C126.401 18.8 123.601 15.2 123.601 14C123.601 12.8 121.801 9.4 121.801 9.4C118.801 6 121.201 -1 121.201 -1C123.001 -14.8 120.801 -13 120.801 -13C119.601 -14.8 110.401 -4.8 110.401 -4.8C108.201 -1.4 102.201 0.2 102.201 0.2C99.401 2 96.001 0.6 96.001 0.6C93.401 0.2 87.801 7.2 87.801 7.2C90.601 7 93.001 11.4 95.401 11.6C97.801 11.8 99.601 9.2 101.201 8.6C102.801 8 105.601 13.8 105.601 13.8C106.001 16.4 100.401 21.2 100.401 21.2C100.001 25.8 98.401 24.2 98.401 24.2C95.401 23.6 94.201 27.4 93.201 32C92.201 36.6 88.001 37 88.001 37C86.401 44.4 85.2 41.4 85.2 41.4C85 35.8 79 41.6 79 41.6C77.8 43.6 73.2 41.4 73.2 41.4C66.4 39.4 68.8 37.4 68.8 37.4C70.6 35.2 81.8 37.4 81.8 37.4C84 35.8 76 31.8 76 31.8C75.4 30 76.4 25.6 76.4 25.6C77.6 22.4 84.4 16.8 84.4 16.8C93.801 15.6 91.001 14 91.001 14C84.801 8.8 79 16.4 79 16.4C76.8 22.6 59.4 37.6 59.4 37.6C54.6 41 57.2 34.2 53.2 37.6C49.2 41 28.6 32 28.6 32C17.038 30.807 14.306 46.549 10.777 43.429C10.777 43.429 16.195 51.949 14.595 46.349z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M209.401 -120C209.401 -120 183.801 -112 181.001 -93.2C181.001 -93.2 178.601 -70.4 199.001 -52.8C199.001 -52.8 199.401 -46.4 201.401 -43.2C201.401 -43.2 199.801 -38.4 218.601 -46L245.801 -54.4C245.801 -54.4 252.201 -56.8 257.401 -65.6C262.601 -74.4 277.801 -93.2 274.201 -118.4C274.201 -118.4 275.401 -129.6 269.401 -130C269.401 -130 261.001 -131.6 253.801 -124C253.801 -124 247.001 -120.8 244.601 -121.2L209.401 -120z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M264.022 -120.99C264.022 -120.99 266.122 -129.92 261.282 -125.08C261.282 -125.08 254.242 -119.36 246.761 -119.36C246.761 -119.36 232.241 -117.16 227.841 -103.96C227.841 -103.96 223.881 -77.12 231.801 -71.4C231.801 -71.4 236.641 -63.92 243.681 -70.52C250.722 -77.12 266.222 -107.35 264.022 -120.99z"/>
+ </g>
+ <g style="fill: #323232">
+ <path d="M263.648 -120.632C263.648 -120.632 265.738 -129.376 260.986 -124.624C260.986 -124.624 254.074 -119.008 246.729 -119.008C246.729 -119.008 232.473 -116.848 228.153 -103.888C228.153 -103.888 224.265 -77.536 232.041 -71.92C232.041 -71.92 236.793 -64.576 243.705 -71.056C250.618 -77.536 265.808 -107.24 263.648 -120.632z"/>
+ </g>
+ <g style="fill: #666666">
+ <path d="M263.274 -120.274C263.274 -120.274 265.354 -128.832 260.69 -124.168C260.69 -124.168 253.906 -118.656 246.697 -118.656C246.697 -118.656 232.705 -116.536 228.465 -103.816C228.465 -103.816 224.649 -77.952 232.281 -72.44C232.281 -72.44 236.945 -65.232 243.729 -71.592C250.514 -77.952 265.394 -107.13 263.274 -120.274z"/>
+ </g>
+ <g style="fill: #999999">
+ <path d="M262.9 -119.916C262.9 -119.916 264.97 -128.288 260.394 -123.712C260.394 -123.712 253.738 -118.304 246.665 -118.304C246.665 -118.304 232.937 -116.224 228.777 -103.744C228.777 -103.744 225.033 -78.368 232.521 -72.96C232.521 -72.96 237.097 -65.888 243.753 -72.128C250.41 -78.368 264.98 -107.02 262.9 -119.916z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M262.526 -119.558C262.526 -119.558 264.586 -127.744 260.098 -123.256C260.098 -123.256 253.569 -117.952 246.633 -117.952C246.633 -117.952 233.169 -115.912 229.089 -103.672C229.089 -103.672 225.417 -78.784 232.761 -73.48C232.761 -73.48 237.249 -66.544 243.777 -72.664C250.305 -78.784 264.566 -106.91 262.526 -119.558z"/>
+ </g>
+ <g style="fill: #ffffff">
+ <path d="M262.151 -119.2C262.151 -119.2 264.201 -127.2 259.801 -122.8C259.801 -122.8 253.401 -117.6 246.601 -117.6C246.601 -117.6 233.401 -115.6 229.401 -103.6C229.401 -103.6 225.801 -79.2 233.001 -74C233.001 -74 237.401 -67.2 243.801 -73.2C250.201 -79.2 264.151 -106.8 262.151 -119.2z"/>
+ </g>
+ <g style="fill: #992600">
+ <path d="M50.6 84C50.6 84 30.2 64.8 22.2 64C22.2 64 -12.2 60 -27 78C-27 78 -9.4 57.6 18.2 63.2C18.2 63.2 -3.4 58.8 -15.8 62C-15.8 62 -32.6 62 -42.2 76L-45 80.8C-45 80.8 -41 66 -22.6 60C-22.6 60 0.2 55.2 11 60C11 60 -10.6 53.2 -20.6 55.2C-20.6 55.2 -51 52.8 -63.8 79.2C-63.8 79.2 -59.8 64.8 -45 57.6C-45 57.6 -31.4 48.8 -11 51.6C-11 51.6 3.4 54.8 8.6 57.2C13.8 59.6 12.6 56.8 4.2 52C4.2 52 -1.4 42 -15.4 42.4C-15.4 42.4 -58.2 46 -68.6 58C-68.6 58 -55 46.8 -44.6 44C-44.6 44 -22.2 36 -13.8 36.8C-13.8 36.8 11 37.8 18.6 33.8C18.6 33.8 7.4 38.8 10.6 42C13.8 45.2 20.6 52.8 20.6 54C20.6 55.2 44.8 77.3 48.4 81.7L50.6 84z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M189 278C189 278 173.5 241.5 161 232C161 232 187 248 190.5 266C190.5 266 190.5 276 189 278z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M236 285.5C236 285.5 209.5 230.5 191 206.5C191 206.5 234.5 244 239.5 270.5L240 276L237 273.5C237 273.5 236.5 282.5 236 285.5z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M292.5 237C292.5 237 230 177.5 228.5 175C228.5 175 289 241 292 248.5C292 248.5 290 239.5 292.5 237z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M104 280.5C104 280.5 123.5 228.5 142.5 251C142.5 251 157.5 261 157 264C157 264 153 257.5 135 258C135 258 116 255 104 280.5z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M294.5 153C294.5 153 249.5 124.5 242 123C230.193 120.639 291.5 152 296.5 162.5C296.5 162.5 298.5 160 294.5 153z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M143.801 259.601C143.801 259.601 164.201 257.601 171.001 250.801L175.401 254.401L193.001 216.001L196.601 221.201C196.601 221.201 211.001 206.401 210.201 198.401C209.401 190.401 223.001 204.401 223.001 204.401C223.001 204.401 222.201 192.801 229.401 199.601C229.401 199.601 227.001 184.001 235.401 192.001C235.401 192.001 224.864 161.844 247.401 187.601C253.001 194.001 248.601 187.201 248.601 187.201C248.601 187.201 222.601 139.201 244.201 153.601C244.201 153.601 246.201 130.801 245.001 126.401C243.801 122.001 241.801 99.6 237.001 94.4C232.201 89.2 237.401 87.6 243.001 92.8C243.001 92.8 231.801 68.8 245.001 80.8C245.001 80.8 241.401 65.6 237.001 62.8C237.001 62.8 231.401 45.6 246.601 56.4C246.601 56.4 242.201 44 239.001 40.8C239.001 40.8 227.401 13.2 234.601 18L239.001 21.6C239.001 21.6 232.201 7.6 238.601 12C245.001 16.4 245.001 16 245.001 16C245.001 16 223.801 -17.2 244.201 0.4C244.201 0.4 236.042 -13.518 232.601 -20.4C232.601 -20.4 213.801 -40.8 228.201 -34.4L233.001 -32.8C233.001 -32.8 224.201 -42.8 216.201 -44.4C208.201 -46 218.601 -52.4 225.001 -50.4C231.401 -48.4 247.001 -40.8 247.001 -40.8C247.001 -40.8 259.801 -22 263.801 -21.6C263.801 -21.6 243.801 -29.2 249.801 -21.2C249.801 -21.2 264.201 -7.2 257.001 -7.6C257.001 -7.6 251.001 -0.4 255.801 8.4C255.801 8.4 237.342 -9.991 252.201 15.6L259.001 32C259.001 32 234.601 7.2 245.801 29.2C245.801 29.2 263.001 52.8 265.001 53.2C267.001 53.6 271.401 62.4 271.401 62.4L267.001 60.4L272.201 69.2C272.201 69.2 261.001 57.2 267.001 70.4L272.601 84.8C272.601 84.8 252.201 62.8 265.801 92.4C265.801 92.4 249.401 87.2 258.201 104.4C258.201 104.4 256.601 120.401 257.001 125.601C257.401 130.801 258.601 159.201 254.201 167.201C249.801 175.201 260.201 194.401 262.201 198.401C264.201 202.401 267.801 213.201 259.001 204.001C250.201 194.801 254.601 200.401 256.601 209.201C258.601 218.001 264.601 233.601 263.801 239.201C263.801 239.201 262.601 240.401 259.401 236.801C259.401 236.801 244.601 214.001 246.201 228.401C246.201 228.401 245.001 236.401 241.801 245.201C241.801 245.201 238.601 256.001 238.601 247.201C238.601 247.201 235.401 230.401 232.601 238.001C229.801 245.601 226.201 251.601 223.401 254.001C220.601 256.401 215.401 233.601 214.201 244.001C214.201 244.001 202.201 231.601 197.401 248.001L185.801 264.401C185.801 264.401 185.401 252.001 184.201 258.001C184.201 258.001 154.201 264.001 143.801 259.601z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M109.401 -97.2C109.401 -97.2 97.801 -105.2 93.801 -104.8C89.801 -104.4 121.401 -113.6 162.601 -86C162.601 -86 167.401 -83.2 171.001 -83.6C171.001 -83.6 174.201 -81.2 171.401 -77.6C171.401 -77.6 162.601 -68 173.801 -56.8C173.801 -56.8 192.201 -50 186.601 -58.8C186.601 -58.8 197.401 -54.8 199.801 -50.8C202.201 -46.8 201.001 -50.8 201.001 -50.8C201.001 -50.8 194.601 -58 188.601 -63.2C188.601 -63.2 183.401 -65.2 180.601 -73.6C177.801 -82 175.401 -92 179.801 -95.2C179.801 -95.2 175.801 -90.8 176.601 -94.8C177.401 -98.8 181.001 -102.4 182.601 -102.8C184.201 -103.2 200.601 -119 207.401 -119.4C207.401 -119.4 198.201 -118 195.201 -119C192.201 -120 165.601 -131.4 159.601 -132.6C159.601 -132.6 142.801 -139.2 154.801 -137.2C154.801 -137.2 190.601 -133.4 208.801 -120.2C208.801 -120.2 201.601 -128.6 183.201 -135.6C183.201 -135.6 161.001 -148.2 125.801 -143.2C125.801 -143.2 108.001 -140 100.201 -138.2C100.201 -138.2 97.601 -138.8 97.001 -139.2C96.401 -139.6 84.6 -148.6 57 -141.6C57 -141.6 40 -137 31.4 -132.2C31.4 -132.2 16.2 -131 12.6 -127.8C12.6 -127.8 -6 -113.2 -8 -112.4C-10 -111.6 -21.4 -104 -22.2 -103.6C-22.2 -103.6 2.4 -110.2 4.8 -112.6C7.2 -115 24.6 -117.6 27 -116.2C29.4 -114.8 37.8 -115.4 28.2 -114.8C28.2 -114.8 103.801 -100 104.601 -98C105.401 -96 109.401 -97.2 109.401 -97.2z"/>
+ </g>
+ <g style="fill: #cc7226">
+ <path d="M180.801 -106.4C180.801 -106.4 170.601 -113.8 168.601 -113.8C166.601 -113.8 154.201 -124 150.001 -123.6C145.801 -123.2 133.601 -133.2 106.201 -125C106.201 -125 105.601 -127 109.201 -127.8C109.201 -127.8 115.601 -130 116.001 -130.6C116.001 -130.6 136.201 -134.8 143.401 -131.2C143.401 -131.2 152.601 -128.6 158.801 -122.4C158.801 -122.4 170.001 -119.2 173.201 -120.2C173.201 -120.2 182.001 -118 182.401 -116.2C182.401 -116.2 188.201 -113.2 186.401 -110.6C186.401 -110.6 186.801 -109 180.801 -106.4z"/>
+ </g>
+ <g style="fill: #cc7226">
+ <path d="M168.33 -108.509C169.137 -107.877 170.156 -107.779 170.761 -106.97C170.995 -106.656 170.706 -106.33 170.391 -106.233C169.348 -105.916 168.292 -106.486 167.15 -105.898C166.748 -105.691 166.106 -105.873 165.553 -106.022C163.921 -106.463 162.092 -106.488 160.401 -105.8C158.416 -106.929 156.056 -106.345 153.975 -107.346C153.917 -107.373 153.695 -107.027 153.621 -107.054C150.575 -108.199 146.832 -107.916 144.401 -110.2C141.973 -110.612 139.616 -111.074 137.188 -111.754C135.37 -112.263 133.961 -113.252 132.341 -114.084C130.964 -114.792 129.507 -115.314 127.973 -115.686C126.11 -116.138 124.279 -116.026 122.386 -116.546C122.293 -116.571 122.101 -116.227 122.019 -116.254C121.695 -116.362 121.405 -116.945 121.234 -116.892C119.553 -116.37 118.065 -117.342 116.401 -117C115.223 -118.224 113.495 -117.979 111.949 -118.421C108.985 -119.269 105.831 -117.999 102.801 -119C106.914 -120.842 111.601 -119.61 115.663 -121.679C117.991 -122.865 120.653 -121.763 123.223 -122.523C123.71 -122.667 124.401 -122.869 124.801 -122.2C124.935 -122.335 125.117 -122.574 125.175 -122.546C127.625 -121.389 129.94 -120.115 132.422 -119.049C132.763 -118.903 133.295 -119.135 133.547 -118.933C135.067 -117.717 137.01 -117.82 138.401 -116.6C140.099 -117.102 141.892 -116.722 143.621 -117.346C143.698 -117.373 143.932 -117.032 143.965 -117.054C145.095 -117.802 146.25 -117.531 147.142 -117.227C147.48 -117.112 148.143 -116.865 148.448 -116.791C149.574 -116.515 150.43 -116.035 151.609 -115.852C151.723 -115.834 151.908 -116.174 151.98 -116.146C153.103 -115.708 154.145 -115.764 154.801 -114.6C154.936 -114.735 155.101 -114.973 155.183 -114.946C156.21 -114.608 156.859 -113.853 157.96 -113.612C158.445 -113.506 159.057 -112.88 159.633 -112.704C162.025 -111.973 163.868 -110.444 166.062 -109.549C166.821 -109.239 167.697 -109.005 168.33 -108.509z"/>
+ </g>
+ <g style="fill: #cc7226">
+ <path d="M91.696 -122.739C89.178 -124.464 86.81 -125.57 84.368 -127.356C84.187 -127.489 83.827 -127.319 83.625 -127.441C82.618 -128.05 81.73 -128.631 80.748 -129.327C80.209 -129.709 79.388 -129.698 78.88 -129.956C76.336 -131.248 73.707 -131.806 71.2 -133C71.882 -133.638 73.004 -133.394 73.6 -134.2C73.795 -133.92 74.033 -133.636 74.386 -133.827C76.064 -134.731 77.914 -134.884 79.59 -134.794C81.294 -134.702 83.014 -134.397 84.789 -134.125C85.096 -134.078 85.295 -133.555 85.618 -133.458C87.846 -132.795 90.235 -133.32 92.354 -132.482C93.945 -131.853 95.515 -131.03 96.754 -129.755C97.006 -129.495 96.681 -129.194 96.401 -129C96.789 -129.109 97.062 -128.903 97.173 -128.59C97.257 -128.351 97.257 -128.049 97.173 -127.81C97.061 -127.498 96.782 -127.397 96.408 -127.346C95.001 -127.156 96.773 -128.536 96.073 -128.088C94.8 -127.274 95.546 -125.868 94.801 -124.6C94.521 -124.794 94.291 -125.012 94.401 -125.4C94.635 -124.878 94.033 -124.588 93.865 -124.272C93.48 -123.547 92.581 -122.132 91.696 -122.739z"/>
+ </g>
+ <g style="fill: #cc7226">
+ <path d="M59.198 -115.391C56.044 -116.185 52.994 -116.07 49.978 -117.346C49.911 -117.374 49.688 -117.027 49.624 -117.054C48.258 -117.648 47.34 -118.614 46.264 -119.66C45.351 -120.548 43.693 -120.161 42.419 -120.648C42.095 -120.772 41.892 -121.284 41.591 -121.323C40.372 -121.48 39.445 -122.429 38.4 -123C40.736 -123.795 43.147 -123.764 45.609 -124.148C45.722 -124.166 45.867 -123.845 46 -123.845C46.136 -123.845 46.266 -124.066 46.4 -124.2C46.595 -123.92 46.897 -123.594 47.154 -123.848C47.702 -124.388 48.258 -124.198 48.798 -124.158C48.942 -124.148 49.067 -123.845 49.2 -123.845C49.336 -123.845 49.467 -124.156 49.6 -124.156C49.736 -124.155 49.867 -123.845 50 -123.845C50.136 -123.845 50.266 -124.066 50.4 -124.2C51.092 -123.418 51.977 -123.972 52.799 -123.793C53.837 -123.566 54.104 -122.418 55.178 -122.12C59.893 -120.816 64.03 -118.671 68.393 -116.584C68.7 -116.437 68.91 -116.189 68.8 -115.8C69.067 -115.8 69.38 -115.888 69.57 -115.756C70.628 -115.024 71.669 -114.476 72.366 -113.378C72.582 -113.039 72.253 -112.632 72.02 -112.684C67.591 -113.679 63.585 -114.287 59.198 -115.391z"/>
+ </g>
+ <g style="fill: #cc7226">
+ <path d="M45.338 -71.179C43.746 -72.398 43.162 -74.429 42.034 -76.221C41.82 -76.561 42.094 -76.875 42.411 -76.964C42.971 -77.123 43.514 -76.645 43.923 -76.443C45.668 -75.581 47.203 -74.339 49.2 -74.2C51.19 -71.966 55.45 -71.581 55.457 -68.2C55.458 -67.341 54.03 -68.259 53.6 -67.4C51.149 -68.403 48.76 -68.3 46.38 -69.767C45.763 -70.148 46.093 -70.601 45.338 -71.179z"/>
+ </g>
+ <g style="fill: #cc7226">
+ <path d="M17.8 -123.756C17.935 -123.755 24.966 -123.522 24.949 -123.408C24.904 -123.099 17.174 -122.05 16.81 -122.22C16.646 -122.296 9.134 -119.866 9 -120C9.268 -120.135 17.534 -123.756 17.8 -123.756z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M33.2 -114C33.2 -114 18.4 -112.2 14 -111C9.6 -109.8 -9 -102.2 -12 -100.2C-12 -100.2 -25.4 -94.8 -42.4 -74.8C-42.4 -74.8 -34.8 -78.2 -32.6 -81C-32.6 -81 -19 -93.6 -19.2 -91C-19.2 -91 -7 -99.6 -7.6 -97.4C-7.6 -97.4 16.8 -108.6 14.8 -105.4C14.8 -105.4 36.4 -110 35.4 -108C35.4 -108 54.2 -103.6 51.4 -103.4C51.4 -103.4 45.6 -102.2 52 -98.6C52 -98.6 48.6 -94.2 43.2 -98.2C37.8 -102.2 40.8 -100 35.8 -99C35.8 -99 33.2 -98.2 28.6 -102.2C28.6 -102.2 23 -106.8 14.2 -103.2C14.2 -103.2 -16.4 -90.6 -18.4 -90C-18.4 -90 -22 -87.2 -24.4 -83.6C-24.4 -83.6 -30.2 -79.2 -33.2 -77.8C-33.2 -77.8 -46 -66.2 -47.2 -64.8C-47.2 -64.8 -50.6 -59.6 -51.4 -59.2C-51.4 -59.2 -45 -63 -43 -65C-43 -65 -29 -75 -23.6 -75.8C-23.6 -75.8 -19.2 -78.8 -18.4 -80.2C-18.4 -80.2 -4 -89.4 0.2 -89.4C0.2 -89.4 9.4 -84.2 11.8 -91.2C11.8 -91.2 17.6 -93 23.2 -91.8C23.2 -91.8 26.4 -94.4 25.6 -96.6C25.6 -96.6 27.2 -98.4 28.2 -94.6C28.2 -94.6 31.6 -91 36.4 -93C36.4 -93 40.4 -93.2 38.4 -90.8C38.4 -90.8 34 -87 22.2 -86.8C22.2 -86.8 9.8 -86.2 -6.6 -78.6C-6.6 -78.6 -36.4 -68.2 -45.6 -57.8C-45.6 -57.8 -52 -49 -57.4 -47.8C-57.4 -47.8 -63.2 -47 -69.2 -39.6C-69.2 -39.6 -59.4 -45.4 -50.4 -45.4C-50.4 -45.4 -46.4 -47.8 -50.2 -44.2C-50.2 -44.2 -53.8 -36.6 -52.2 -31.2C-52.2 -31.2 -52.8 -26 -53.6 -24.4C-53.6 -24.4 -61.4 -11.6 -61.4 -9.2C-61.4 -6.8 -60.2 3 -59.8 3.6C-59.4 4.2 -60.8 2 -57 4.4C-53.2 6.8 -50.4 8.4 -49.6 11.2C-48.8 14 -51.6 5.8 -51.8 4C-52 2.2 -56.2 -5 -55.4 -7.4C-55.4 -7.4 -54.4 -6.4 -53.6 -5C-53.6 -5 -54.2 -5.6 -53.6 -9.2C-53.6 -9.2 -52.8 -14.4 -51.4 -17.6C-50 -20.8 -48 -24.6 -47.6 -25.4C-47.2 -26.2 -47.2 -32 -45.8 -29.4L-42.4 -26.8C-42.4 -26.8 -45.2 -29.4 -43 -31.6C-43 -31.6 -44 -37.2 -42.2 -39.8C-42.2 -39.8 -35.2 -48.2 -33.6 -49.2C-32 -50.2 -33.4 -49.8 -33.4 -49.8C-33.4 -49.8 -27.4 -54 -33.2 -52.4C-33.2 -52.4 -37.2 -50.8 -40.2 -50.8C-40.2 -50.8 -47.8 -48.8 -43.8 -53C-39.8 -57.2 -29.8 -62.6 -26 -62.4L-25.2 -60.8L-14 -63.2L-15.2 -62.4C-15.2 -62.4 -15.4 -62.6 -11.2 -63C-7 -63.4 -1.2 -62 0.2 -63.8C1.6 -65.6 5 -66.6 4.6 -65.2C4.2 -63.8 4 -61.8 4 -61.8C4 -61.8 9 -67.6 8.4 -65.4C7.8 -63.2 -0.4 -58 -1.8 -51.8L8.6 -60L12.2 -63C12.2 -63 15.8 -60.8 16 -62.4C16.2 -64 20.8 -69.8 22 -69.6C23.2 -69.4 25.2 -72.2 25 -69.6C24.8 -67 32.4 -61.6 32.4 -61.6C32.4 -61.6 35.6 -63.4 37 -62C38.4 -60.6 42.6 -81.8 42.6 -81.8L67.6 -92.4L111.201 -95.8L94.201 -102.6L33.2 -114z"/>
+ </g>
+ <g style="stroke:#4c0000; stroke-width:2">
+ <path d="M51.4 85C51.4 85 36.4 68.2 28 65.6C28 65.6 14.6 58.8 -10 66.6"/>
+ </g>
+ <g style="stroke:#4c0000; stroke-width:2">
+ <path d="M24.8 64.2C24.8 64.2 -0.4 56.2 -15.8 60.4C-15.8 60.4 -34.2 62.4 -42.6 76.2"/>
+ </g>
+ <g style="stroke:#4c0000; stroke-width:2">
+ <path d="M21.2 63C21.2 63 4.2 55.8 -10.6 53.6C-10.6 53.6 -27.2 51 -43.8 58.2C-43.8 58.2 -56 64.2 -61.4 74.4"/>
+ </g>
+ <g style="stroke:#4c0000; stroke-width:2">
+ <path d="M22.2 63.4C22.2 63.4 6.8 52.4 5.8 51C5.8 51 -1.2 40 -14.2 39.6C-14.2 39.6 -35.6 40.4 -52.8 48.4"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M20.895 54.407C22.437 55.87 49.4 84.8 49.4 84.8C84.6 121.401 56.6 87.2 56.6 87.2C49 82.4 39.8 63.6 39.8 63.6C38.6 60.8 53.8 70.8 53.8 70.8C57.8 71.6 71.4 90.8 71.4 90.8C64.6 88.4 69.4 95.6 69.4 95.6C72.2 97.6 92.601 113.201 92.601 113.201C96.201 117.201 100.201 118.801 100.201 118.801C114.201 113.601 107.801 126.801 107.801 126.801C110.201 133.601 115.801 122.001 115.801 122.001C127.001 105.2 110.601 107.601 110.601 107.601C80.6 110.401 73.8 94.4 73.8 94.4C71.4 92 80.2 94.4 80.2 94.4C88.601 96.4 73 82 73 82C75.4 82 84.6 88.8 84.6 88.8C95.001 98 97.001 96 97.001 96C115.001 87.2 125.401 94.8 125.401 94.8C127.401 96.4 121.801 103.2 123.401 108.401C125.001 113.601 129.801 126.001 129.801 126.001C127.401 127.601 127.801 138.401 127.801 138.401C144.601 161.601 135.001 159.601 135.001 159.601C119.401 159.201 134.201 166.801 134.201 166.801C137.401 168.801 146.201 176.001 146.201 176.001C143.401 174.801 141.801 180.001 141.801 180.001C146.601 184.001 143.801 188.801 143.801 188.801C137.801 190.001 136.601 194.001 136.601 194.001C143.401 202.001 133.401 202.401 133.401 202.401C137.001 206.801 132.201 218.801 132.201 218.801C127.401 218.801 121.001 224.401 121.001 224.401C123.401 229.201 113.001 234.801 113.001 234.801C104.601 236.401 107.401 243.201 107.401 243.201C99.401 249.201 97.001 265.201 97.001 265.201C96.201 275.601 93.801 278.801 99.001 276.801C104.201 274.801 103.401 262.401 103.401 262.401C98.601 246.801 141.401 230.801 141.401 230.801C145.401 229.201 146.201 224.001 146.201 224.001C148.201 224.401 157.001 232.001 157.001 232.001C164.601 243.201 165.001 234.001 165.001 234.001C166.201 230.401 164.601 224.401 164.601 224.401C170.601 202.801 156.601 196.401 156.601 196.401C146.601 162.801 160.601 171.201 160.601 171.201C163.401 176.801 174.201 182.001 174.201 182.001L177.801 179.601C176.201 174.801 184.601 168.801 184.601 168.801C187.401 175.201 193.401 167.201 193.401 167.201C197.001 142.801 209.401 157.201 209.401 157.201C213.401 158.401 214.601 151.601 214.601 151.601C218.201 141.201 214.601 127.601 214.601 127.601C218.201 127.201 227.801 133.201 227.801 133.201C230.601 129.601 221.401 112.801 225.401 115.201C229.401 117.601 233.801 119.201 233.801 119.201C234.601 117.201 224.601 104.801 224.601 104.801C220.201 102 215.001 81.6 215.001 81.6C222.201 85.2 212.201 70 212.201 70C212.201 66.8 218.201 55.6 218.201 55.6C217.401 48.8 218.201 49.2 218.201 49.2C221.001 50.4 229.001 52 222.201 45.6C215.401 39.2 223.001 34.4 223.001 34.4C227.401 31.6 213.801 32 213.801 32C208.601 27.6 209.001 23.6 209.001 23.6C217.001 25.6 202.601 11.2 200.201 7.6C197.801 4 207.401 -1.2 207.401 -1.2C220.601 -4.8 209.001 -8 209.001 -8C189.401 -7.6 200.201 -18.4 200.201 -18.4C206.201 -18 204.601 -20.4 204.601 -20.4C199.401 -21.6 189.801 -28 189.801 -28C185.801 -31.6 189.401 -30.8 189.401 -30.8C206.201 -29.6 177.401 -40.8 177.401 -40.8C185.401 -40.8 167.401 -51.2 167.401 -51.2C165.401 -52.8 162.201 -60.4 162.201 -60.4C156.201 -65.6 151.401 -72.4 151.401 -72.4C151.001 -76.8 146.201 -81.6 146.201 -81.6C134.601 -95.2 129.001 -94.8 129.001 -94.8C114.201 -98.4 109.001 -97.6 109.001 -97.6L56.2 -93.2C29.8 -80.4 37.6 -59.4 37.6 -59.4C44 -51 53.2 -54.8 53.2 -54.8C57.8 -61 69.4 -58.8 69.4 -58.8C89.801 -55.6 87.201 -59.2 87.201 -59.2C84.801 -63.8 68.6 -70 68.4 -70.6C68.2 -71.2 59.4 -74.6 59.4 -74.6C56.4 -75.8 52 -85 52 -85C48.8 -88.4 64.6 -82.6 64.6 -82.6C63.4 -81.6 70.8 -77.6 70.8 -77.6C88.201 -78.6 98.801 -67.8 98.801 -67.8C109.601 -51.2 109.801 -59.4 109.801 -59.4C112.601 -68.8 100.801 -90 100.801 -90C101.201 -92 109.401 -85.4 109.401 -85.4C110.801 -87.4 111.601 -81.6 111.601 -81.6C111.801 -79.2 115.601 -71.2 115.601 -71.2C118.401 -58.2 122.001 -65.6 122.001 -65.6L126.601 -56.2C128.001 -53.6 122.001 -46 122.001 -46C121.801 -43.2 122.601 -43.4 117.001 -35.8C111.401 -28.2 114.801 -23.8 114.801 -23.8C113.401 -17.2 122.201 -17.6 122.201 -17.6C124.801 -15.4 128.201 -15.4 128.201 -15.4C130.001 -13.4 132.401 -14 132.401 -14C134.001 -17.8 140.201 -15.8 140.201 -15.8C141.601 -18.2 149.801 -18.6 149.801 -18.6C150.801 -21.2 151.201 -22.8 154.601 -23.4C158.001 -24 133.401 -67 133.401 -67C139.801 -67.8 131.601 -80.2 131.601 -80.2C129.401 -86.8 140.801 -72.2 143.001 -70.8C145.201 -69.4 146.201 -67.2 144.601 -67.4C143.001 -67.6 141.201 -65.4 142.601 -65.2C144.001 -65 157.001 -50 160.401 -39.8C163.801 -29.6 169.801 -25.6 176.001 -19.6C182.201 -13.6 181.401 10.6 181.401 10.6C181.001 19.4 187.001 30 187.001 30C189.001 33.8 184.801 52 184.801 52C182.801 54.2 184.201 55 184.201 55C185.201 56.2 192.001 69.4 192.001 69.4C190.201 69.2 193.801 72.8 193.801 72.8C199.001 78.8 192.601 75.8 192.601 75.8C186.601 74.2 193.601 84 193.601 84C194.801 85.8 185.801 81.2 185.801 81.2C176.601 80.6 188.201 87.8 188.201 87.8C196.801 95 185.401 90.6 185.401 90.6C180.801 88.8 184.001 95.6 184.001 95.6C187.201 97.2 204.401 104.2 204.401 104.2C204.801 108.001 201.801 113.001 201.801 113.001C202.201 117.001 200.001 120.401 200.001 120.401C198.801 128.601 198.201 129.401 198.201 129.401C194.001 129.601 186.601 143.401 186.601 143.401C184.801 146.001 174.601 158.001 174.601 158.001C172.601 165.001 154.601 157.801 154.601 157.801C148.001 161.201 150.001 157.801 150.001 157.801C149.601 155.601 154.401 149.601 154.401 149.601C161.401 147.001 158.801 136.201 158.801 136.201C162.801 134.801 151.601 132.001 151.801 130.801C152.001 129.601 157.801 128.201 157.801 128.201C165.801 126.201 161.401 123.801 161.401 123.801C160.801 119.801 163.801 114.201 163.801 114.201C175.401 113.401 163.801 97.2 163.801 97.2C153.001 89.6 152.001 83.8 152.001 83.8C164.601 75.6 156.401 63.2 156.601 59.6C156.801 56 158.001 34.4 158.001 34.4C156.001 28.2 153.001 14.6 153.001 14.6C155.201 9.4 162.601 -3.2 162.601 -3.2C165.401 -7.4 174.201 -12.2 172.001 -15.2C169.801 -18.2 162.001 -16.4 162.001 -16.4C154.201 -17.8 154.801 -12.6 154.801 -12.6C153.201 -11.6 152.401 -6.6 152.401 -6.6C151.68 1.333 142.801 7.6 142.801 7.6C131.601 13.8 140.801 17.8 140.801 17.8C146.801 24.4 137.001 24.6 137.001 24.6C126.001 22.8 134.201 33 134.201 33C145.001 45.8 142.001 48.6 142.001 48.6C131.801 49.6 144.401 58.8 144.401 58.8C144.401 58.8 143.601 56.8 143.801 58.6C144.001 60.4 147.001 64.6 147.801 66.6C148.601 68.6 144.601 68.8 144.601 68.8C145.201 78.4 129.801 74.2 129.801 74.2C129.801 74.2 129.801 74.2 128.201 74.4C126.601 74.6 115.401 73.8 109.601 71.6C103.801 69.4 97.001 69.4 97.001 69.4C97.001 69.4 93.001 71.2 85.4 71C77.8 70.8 69.8 73.6 69.8 73.6C65.4 73.2 74 68.8 74.2 69C74.4 69.2 80 63.6 72 64.2C50.203 65.835 39.4 55.6 39.4 55.6C37.4 54.2 34.8 51.4 34.8 51.4C24.8 49.4 36.2 63.8 36.2 63.8C37.4 65.2 36 66.2 36 66.2C35.2 64.6 27.4 59.2 27.4 59.2C24.589 58.227 23.226 56.893 20.895 54.407z"/>
+ </g>
+ <g style="fill: #4c0000">
+ <path d="M-3 42.8C-3 42.8 8.6 48.4 11.2 51.2C13.8 54 27.8 65.4 27.8 65.4C27.8 65.4 22.4 63.4 19.8 61.6C17.2 59.8 6.4 51.6 6.4 51.6C6.4 51.6 2.6 45.6 -3 42.8z"/>
+ </g>
+ <g style="fill: #99cc32">
+ <path d="M-61.009 11.603C-60.672 11.455 -61.196 8.743 -61.4 8.2C-62.422 5.474 -71.4 4 -71.4 4C-71.627 5.365 -71.682 6.961 -71.576 8.599C-71.576 8.599 -66.708 14.118 -61.009 11.603z"/>
+ </g>
+ <g style="fill: #659900">
+ <path d="M-61.009 11.403C-61.458 11.561 -61.024 8.669 -61.2 8.2C-62.222 5.474 -71.4 3.9 -71.4 3.9C-71.627 5.265 -71.682 6.861 -71.576 8.499C-71.576 8.499 -67.308 13.618 -61.009 11.403z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-65.4 11.546C-66.025 11.546 -66.531 10.406 -66.531 9C-66.531 7.595 -66.025 6.455 -65.4 6.455C-64.775 6.455 -64.268 7.595 -64.268 9C-64.268 10.406 -64.775 11.546 -65.4 11.546z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-65.4 9z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-111 109.601C-111 109.601 -116.6 119.601 -91.8 113.601C-91.8 113.601 -77.8 112.401 -75.4 110.001C-74.2 110.801 -65.834 113.734 -63 114.401C-56.2 116.001 -47.8 106 -47.8 106C-47.8 106 -43.2 95.5 -40.4 95.5C-37.6 95.5 -40.8 97.1 -40.8 97.1C-40.8 97.1 -47.4 107.201 -47 108.801C-47 108.801 -52.2 128.801 -68.2 129.601C-68.2 129.601 -84.35 130.551 -83 136.401C-83 136.401 -74.2 134.001 -71.8 136.401C-71.8 136.401 -61 136.001 -69 142.401L-75.8 154.001C-75.8 154.001 -75.66 157.919 -85.8 154.401C-95.6 151.001 -105.9 138.101 -105.9 138.101C-105.9 138.101 -121.85 123.551 -111 109.601z"/>
+ </g>
+ <g style="fill: #e59999">
+ <path d="M-112.2 113.601C-112.2 113.601 -114.2 123.201 -77.4 112.801C-77.4 112.801 -73 112.801 -70.6 113.601C-68.2 114.401 -56.2 117.201 -54.2 116.001C-54.2 116.001 -61.4 129.601 -73 128.001C-73 128.001 -86.2 129.601 -85.8 134.401C-85.8 134.401 -81.8 141.601 -77 144.001C-77 144.001 -74.2 146.401 -74.6 149.601C-75 152.801 -77.8 154.401 -79.8 155.201C-81.8 156.001 -85 152.801 -86.6 152.801C-88.2 152.801 -96.6 146.401 -101 141.601C-105.4 136.801 -113.8 124.801 -113.4 122.001C-113 119.201 -112.2 113.601 -112.2 113.601z"/>
+ </g>
+ <g style="fill: #b26565">
+ <path d="M-109 131.051C-106.4 135.001 -103.2 139.201 -101 141.601C-96.6 146.401 -88.2 152.801 -86.6 152.801C-85 152.801 -81.8 156.001 -79.8 155.201C-77.8 154.401 -75 152.801 -74.6 149.601C-74.2 146.401 -77 144.001 -77 144.001C-80.066 142.468 -82.806 138.976 -84.385 136.653C-84.385 136.653 -84.2 139.201 -89.4 138.401C-94.6 137.601 -99.8 134.801 -101.4 131.601C-103 128.401 -105.4 126.001 -103.8 129.601C-102.2 133.201 -99.8 136.801 -98.2 137.201C-96.6 137.601 -97 138.801 -99.4 138.401C-101.8 138.001 -104.6 137.601 -109 132.401z"/>
+ </g>
+ <g style="fill: #992600">
+ <path d="M-111.6 110.001C-111.6 110.001 -109.8 96.4 -108.6 92.4C-108.6 92.4 -109.4 85.6 -107 81.4C-104.6 77.2 -102.6 71 -99.6 65.6C-96.6 60.2 -96.4 56.2 -92.4 54.6C-88.4 53 -82.4 44.4 -79.6 43.4C-76.8 42.4 -77 43.2 -77 43.2C-77 43.2 -70.2 28.4 -56.6 32.4C-56.6 32.4 -72.8 29.6 -57 20.2C-57 20.2 -61.8 21.3 -58.5 14.3C-56.299 9.632 -56.8 16.4 -67.8 28.2C-67.8 28.2 -72.8 36.8 -78 39.8C-83.2 42.8 -95.2 49.8 -96.4 53.6C-97.6 57.4 -100.8 63.2 -102.8 64.8C-104.8 66.4 -107.6 70.6 -108 74C-108 74 -109.2 78 -110.6 79.2C-112 80.4 -112.2 83.6 -112.2 85.6C-112.2 87.6 -114.2 90.4 -114 92.8C-114 92.8 -113.2 111.801 -113.6 113.801L-111.6 110.001z"/>
+ </g>
+ <g style="fill: #ffffff">
+ <path d="M-120.2 114.601C-120.2 114.601 -122.2 113.201 -126.6 119.201C-126.6 119.201 -119.3 152.201 -119.3 153.601C-119.3 153.601 -118.2 151.501 -119.5 144.301C-120.8 137.101 -121.7 124.401 -121.7 124.401L-120.2 114.601z"/>
+ </g>
+ <g style="fill: #992600">
+ <path d="M-98.6 54C-98.6 54 -116.2 57.2 -115.8 86.4L-116.6 111.201C-116.6 111.201 -117.8 85.6 -119 84C-120.2 82.4 -116.2 71.2 -119.4 77.2C-119.4 77.2 -133.4 91.2 -125.4 112.401C-125.4 112.401 -123.9 115.701 -126.9 111.101C-126.9 111.101 -131.5 98.5 -130.4 92.1C-130.4 92.1 -130.2 89.9 -128.3 87.1C-128.3 87.1 -119.7 75.4 -117 73.1C-117 73.1 -115.2 58.7 -99.8 53.5C-99.8 53.5 -94.1 51.2 -98.6 54z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M40.8 -12.2C41.46 -12.554 41.451 -13.524 42.031 -13.697C43.18 -14.041 43.344 -15.108 43.862 -15.892C44.735 -17.211 44.928 -18.744 45.51 -20.235C45.782 -20.935 45.809 -21.89 45.496 -22.55C44.322 -25.031 43.62 -27.48 42.178 -29.906C41.91 -30.356 41.648 -31.15 41.447 -31.748C40.984 -33.132 39.727 -34.123 38.867 -35.443C38.579 -35.884 39.104 -36.809 38.388 -36.893C37.491 -36.998 36.042 -37.578 35.809 -36.552C35.221 -33.965 36.232 -31.442 37.2 -29C36.418 -28.308 36.752 -27.387 36.904 -26.62C37.614 -23.014 36.416 -19.662 35.655 -16.188C35.632 -16.084 35.974 -15.886 35.946 -15.824C34.724 -13.138 33.272 -10.693 31.453 -8.312C30.695 -7.32 29.823 -6.404 29.326 -5.341C28.958 -4.554 28.55 -3.588 28.8 -2.6C25.365 0.18 23.115 4.025 20.504 7.871C20.042 8.551 20.333 9.76 20.884 10.029C21.697 10.427 22.653 9.403 23.123 8.557C23.512 7.859 23.865 7.209 24.356 6.566C24.489 6.391 24.31 5.972 24.445 5.851C27.078 3.504 28.747 0.568 31.2 -1.8C33.15 -2.129 34.687 -3.127 36.435 -4.14C36.743 -4.319 37.267 -4.07 37.557 -4.265C39.31 -5.442 39.308 -7.478 39.414 -9.388C39.464 -10.272 39.66 -11.589 40.8 -12.2z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M31.959 -16.666C32.083 -16.743 31.928 -17.166 32.037 -17.382C32.199 -17.706 32.602 -17.894 32.764 -18.218C32.873 -18.434 32.71 -18.814 32.846 -18.956C35.179 -21.403 35.436 -24.427 34.4 -27.4C35.424 -28.02 35.485 -29.282 35.06 -30.129C34.207 -31.829 34.014 -33.755 33.039 -35.298C32.237 -36.567 30.659 -37.811 29.288 -36.508C28.867 -36.108 28.546 -35.321 28.824 -34.609C28.888 -34.446 29.173 -34.3 29.146 -34.218C29.039 -33.894 28.493 -33.67 28.487 -33.398C28.457 -31.902 27.503 -30.391 28.133 -29.062C28.905 -27.433 29.724 -25.576 30.4 -23.8C29.166 -21.684 30.199 -19.235 28.446 -17.358C28.31 -17.212 28.319 -16.826 28.441 -16.624C28.733 -16.138 29.139 -15.732 29.625 -15.44C29.827 -15.319 30.175 -15.317 30.375 -15.441C30.953 -15.803 31.351 -16.29 31.959 -16.666z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M94.771 -26.977C96.16 -25.185 96.45 -22.39 94.401 -21C94.951 -17.691 98.302 -19.67 100.401 -20.2C100.292 -20.588 100.519 -20.932 100.802 -20.937C101.859 -20.952 102.539 -21.984 103.601 -21.8C104.035 -23.357 105.673 -24.059 106.317 -25.439C108.043 -29.134 107.452 -33.407 104.868 -36.653C104.666 -36.907 104.883 -37.424 104.759 -37.786C104.003 -39.997 101.935 -40.312 100.001 -41C98.824 -44.875 98.163 -48.906 96.401 -52.6C94.787 -52.85 94.089 -54.589 92.752 -55.309C91.419 -56.028 90.851 -54.449 90.892 -53.403C90.899 -53.198 91.351 -52.974 91.181 -52.609C91.105 -52.445 90.845 -52.334 90.845 -52.2C90.846 -52.065 91.067 -51.934 91.201 -51.8C90.283 -50.98 88.86 -50.503 88.565 -49.358C87.611 -45.648 90.184 -42.523 91.852 -39.322C92.443 -38.187 91.707 -36.916 90.947 -35.708C90.509 -35.013 90.617 -33.886 90.893 -33.03C91.645 -30.699 93.236 -28.96 94.771 -26.977z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M57.611 -8.591C56.124 -6.74 52.712 -4.171 55.629 -2.243C55.823 -2.114 56.193 -2.11 56.366 -2.244C58.387 -3.809 60.39 -4.712 62.826 -5.294C62.95 -5.323 63.224 -4.856 63.593 -5.017C65.206 -5.72 67.216 -5.662 68.4 -7C72.167 -6.776 75.732 -7.892 79.123 -9.2C80.284 -9.648 81.554 -10.207 82.755 -10.709C84.131 -11.285 85.335 -12.213 86.447 -13.354C86.58 -13.49 86.934 -13.4 87.201 -13.4C87.161 -14.263 88.123 -14.39 88.37 -15.012C88.462 -15.244 88.312 -15.64 88.445 -15.742C90.583 -17.372 91.503 -19.39 90.334 -21.767C90.049 -22.345 89.8 -22.963 89.234 -23.439C88.149 -24.35 87.047 -23.496 86 -23.8C85.841 -23.172 85.112 -23.344 84.726 -23.146C83.867 -22.707 82.534 -23.292 81.675 -22.854C80.313 -22.159 79.072 -21.99 77.65 -21.613C77.338 -21.531 76.56 -21.627 76.4 -21C76.266 -21.134 76.118 -21.368 76.012 -21.346C74.104 -20.95 72.844 -20.736 71.543 -19.044C71.44 -18.911 70.998 -19.09 70.839 -18.955C69.882 -18.147 69.477 -16.913 68.376 -16.241C68.175 -16.118 67.823 -16.286 67.629 -16.157C66.983 -15.726 66.616 -15.085 65.974 -14.638C65.645 -14.409 65.245 -14.734 65.277 -14.99C65.522 -16.937 66.175 -18.724 65.6 -20.6C67.677 -23.12 70.194 -25.069 72 -27.8C72.015 -29.966 72.707 -32.112 72.594 -34.189C72.584 -34.382 72.296 -35.115 72.17 -35.462C71.858 -36.316 72.764 -37.382 71.92 -38.106C70.516 -39.309 69.224 -38.433 68.4 -37C66.562 -36.61 64.496 -35.917 62.918 -37.151C61.911 -37.938 61.333 -38.844 60.534 -39.9C59.549 -41.202 59.884 -42.638 59.954 -44.202C59.96 -44.33 59.645 -44.466 59.645 -44.6C59.646 -44.735 59.866 -44.866 60 -45C59.294 -45.626 59.019 -46.684 58 -47C58.305 -48.092 57.629 -48.976 56.758 -49.278C54.763 -49.969 53.086 -48.057 51.194 -47.984C50.68 -47.965 50.213 -49.003 49.564 -49.328C49.132 -49.544 48.428 -49.577 48.066 -49.311C47.378 -48.807 46.789 -48.693 46.031 -48.488C44.414 -48.052 43.136 -46.958 41.656 -46.103C40.171 -45.246 39.216 -43.809 38.136 -42.489C37.195 -41.337 37.059 -38.923 38.479 -38.423C40.322 -37.773 41.626 -40.476 43.592 -40.15C43.904 -40.099 44.11 -39.788 44 -39.4C44.389 -39.291 44.607 -39.52 44.8 -39.8C45.658 -38.781 46.822 -38.444 47.76 -37.571C48.73 -36.667 50.476 -37.085 51.491 -36.088C53.02 -34.586 52.461 -31.905 54.4 -30.6C53.814 -29.287 53.207 -28.01 52.872 -26.583C52.59 -25.377 53.584 -24.18 54.795 -24.271C56.053 -24.365 56.315 -25.124 56.8 -26.2C57.067 -25.933 57.536 -25.636 57.495 -25.42C57.038 -23.033 56.011 -21.04 55.553 -18.609C55.494 -18.292 55.189 -18.09 54.8 -18.2C54.332 -14.051 50.28 -11.657 47.735 -8.492C47.332 -7.99 47.328 -6.741 47.737 -6.338C49.14 -4.951 51.1 -6.497 52.8 -7C53.013 -8.206 53.872 -9.148 55.204 -9.092C55.46 -9.082 55.695 -9.624 56.019 -9.754C56.367 -9.892 56.869 -9.668 57.155 -9.866C58.884 -11.061 60.292 -12.167 62.03 -13.356C62.222 -13.487 62.566 -13.328 62.782 -13.436C63.107 -13.598 63.294 -13.985 63.617 -14.17C63.965 -14.37 64.207 -14.08 64.4 -13.8C63.754 -13.451 63.75 -12.494 63.168 -12.292C62.393 -12.024 61.832 -11.511 61.158 -11.064C60.866 -10.871 60.207 -11.119 60.103 -10.94C59.505 -9.912 58.321 -9.474 57.611 -8.591z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M2.2 -58C2.2 -58 -7.038 -60.872 -18.2 -35.2C-18.2 -35.2 -20.6 -30 -23 -28C-25.4 -26 -36.6 -22.4 -38.6 -18.4L-49 -2.4C-49 -2.4 -34.2 -18.4 -31 -20.8C-31 -20.8 -23 -29.2 -26.2 -22.4C-26.2 -22.4 -40.2 -11.6 -39 -2.4C-39 -2.4 -44.6 12 -45.4 14C-45.4 14 -29.4 -18 -27 -19.2C-24.6 -20.4 -23.4 -20.4 -24.6 -16.8C-25.8 -13.2 -26.2 3.2 -29 5.2C-29 5.2 -21 -15.2 -21.8 -18.4C-21.8 -18.4 -18.6 -22 -16.2 -16.8L-17.4 -0.8L-13 11.2C-13 11.2 -15.4 0 -13.8 -15.6C-13.8 -15.6 -15.8 -26 -11.8 -20.4C-7.8 -14.8 1.8 -8.8 1.8 -4C1.8 -4 -3.4 -21.6 -12.6 -26.4L-16.6 -20.4L-17.8 -22.4C-17.8 -22.4 -21.4 -23.2 -17 -30C-12.6 -36.8 -13 -37.6 -13 -37.6C-13 -37.6 -6.6 -30.4 -5 -30.4C-5 -30.4 8.2 -38 9.4 -13.6C9.4 -13.6 16.2 -28 7 -34.8C7 -34.8 -7.8 -36.8 -6.6 -42L0.6 -54.4C4.2 -59.6 2.6 -56.8 2.6 -56.8z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-17.8 -41.6C-17.8 -41.6 -30.6 -41.6 -33.8 -36.4L-41 -26.8C-41 -26.8 -23.8 -36.8 -19.8 -38C-15.8 -39.2 -17.8 -41.6 -17.8 -41.6z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-57.8 -35.2C-57.8 -35.2 -59.8 -34 -60.2 -31.2C-60.6 -28.4 -63 -28 -62.2 -25.2C-61.4 -22.4 -59.4 -20 -59.4 -24C-59.4 -28 -57.8 -30 -57 -31.2C-56.2 -32.4 -54.6 -36.8 -57.8 -35.2z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-66.6 26C-66.6 26 -75 22 -78.2 18.4C-81.4 14.8 -80.948 19.966 -85.8 19.6C-91.647 19.159 -90.6 3.2 -90.6 3.2L-94.6 10.8C-94.6 10.8 -95.8 25.2 -87.8 22.8C-83.893 21.628 -82.6 23.2 -84.2 24C-85.8 24.8 -78.6 25.2 -81.4 26.8C-84.2 28.4 -69.8 23.2 -72.2 33.6L-66.6 26z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-79.2 40.4C-79.2 40.4 -94.6 44.8 -98.2 35.2C-98.2 35.2 -103 37.6 -100.8 40.6C-98.6 43.6 -97.4 44 -97.4 44C-97.4 44 -92 45.2 -92.6 46C-93.2 46.8 -95.6 50.2 -95.6 50.2C-95.6 50.2 -85.4 44.2 -79.2 40.4z"/>
+ </g>
+ <g style="fill: #ffffff">
+ <path d="M149.201 118.601C148.774 120.735 147.103 121.536 145.201 122.201C143.284 121.243 140.686 118.137 138.801 120.201C138.327 119.721 137.548 119.661 137.204 118.999C136.739 118.101 137.011 117.055 136.669 116.257C136.124 114.985 135.415 113.619 135.601 112.201C137.407 111.489 138.002 109.583 137.528 107.82C137.459 107.563 137.03 107.366 137.23 107.017C137.416 106.694 137.734 106.467 138.001 106.2C137.866 106.335 137.721 106.568 137.61 106.548C137 106.442 137.124 105.805 137.254 105.418C137.839 103.672 139.853 103.408 141.201 104.6C141.457 104.035 141.966 104.229 142.401 104.2C142.351 103.621 142.759 103.094 142.957 102.674C143.475 101.576 145.104 102.682 145.901 102.07C146.977 101.245 148.04 100.546 149.118 101.149C150.927 102.162 152.636 103.374 153.835 105.115C154.41 105.949 154.65 107.23 154.592 108.188C154.554 108.835 153.173 108.483 152.83 109.412C152.185 111.16 154.016 111.679 154.772 113.017C154.97 113.366 154.706 113.67 154.391 113.768C153.98 113.896 153.196 113.707 153.334 114.16C154.306 117.353 151.55 118.031 149.201 118.601z"/>
+ </g>
+ <g style="fill: #ffffff">
+ <path d="M139.6 138.201C139.593 136.463 137.992 134.707 139.201 133.001C139.336 133.135 139.467 133.356 139.601 133.356C139.736 133.356 139.867 133.135 140.001 133.001C141.496 135.217 145.148 136.145 145.006 138.991C144.984 139.438 143.897 140.356 144.801 141.001C142.988 142.349 142.933 144.719 142.001 146.601C140.763 146.315 139.551 145.952 138.401 145.401C138.753 143.915 138.636 142.231 139.456 140.911C139.89 140.213 139.603 139.134 139.6 138.201z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-26.6 129.201C-26.6 129.201 -43.458 139.337 -29.4 124.001C-20.6 114.401 -10.6 108.801 -10.6 108.801C-10.6 108.801 -0.2 104.4 3.4 103.2C7 102 22.2 96.8 25.4 96.4C28.6 96 38.2 92 45 96C51.8 100 59.8 104.4 59.8 104.4C59.8 104.4 43.4 96 39.8 98.4C36.2 100.8 29 100.4 23 103.6C23 103.6 8.2 108.001 5 110.001C1.8 112.001 -8.6 123.601 -10.2 122.801C-11.8 122.001 -9.8 121.601 -8.6 118.801C-7.4 116.001 -9.4 114.401 -17.4 120.801C-25.4 127.201 -26.6 129.201 -26.6 129.201z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-19.195 123.234C-19.195 123.234 -17.785 110.194 -9.307 111.859C-9.307 111.859 -1.081 107.689 1.641 105.721C1.641 105.721 9.78 104.019 11.09 103.402C29.569 94.702 44.288 99.221 44.835 98.101C45.381 96.982 65.006 104.099 68.615 108.185C69.006 108.628 58.384 102.588 48.686 100.697C40.413 99.083 18.811 100.944 7.905 106.48C4.932 107.989 -4.013 113.773 -6.544 113.662C-9.075 113.55 -19.195 123.234 -19.195 123.234z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-23 148.801C-23 148.801 -38.2 146.401 -21.4 144.801C-21.4 144.801 -3.4 142.801 0.6 137.601C0.6 137.601 14.2 128.401 17 128.001C19.8 127.601 49.8 120.401 50.2 118.001C50.6 115.601 56.2 115.601 57.8 116.401C59.4 117.201 58.6 118.401 55.8 119.201C53 120.001 21.8 136.401 15.4 137.601C9 138.801 -2.6 146.401 -7.4 147.601C-12.2 148.801 -23 148.801 -23 148.801z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-3.48 141.403C-3.48 141.403 -12.062 140.574 -3.461 139.755C-3.461 139.755 5.355 136.331 7.403 133.668C7.403 133.668 14.367 128.957 15.8 128.753C17.234 128.548 31.194 124.861 31.399 123.633C31.604 122.404 65.67 109.823 70.09 113.013C73.001 115.114 63.1 113.437 53.466 117.847C52.111 118.467 18.258 133.054 14.981 133.668C11.704 134.283 5.765 138.174 3.307 138.788C0.85 139.403 -3.48 141.403 -3.48 141.403z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-11.4 143.601C-11.4 143.601 -6.2 143.201 -7.4 144.801C-8.6 146.401 -11 145.601 -11 145.601L-11.4 143.601z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-18.6 145.201C-18.6 145.201 -13.4 144.801 -14.6 146.401C-15.8 148.001 -18.2 147.201 -18.2 147.201L-18.6 145.201z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-29 146.801C-29 146.801 -23.8 146.401 -25 148.001C-26.2 149.601 -28.6 148.801 -28.6 148.801L-29 146.801z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-36.6 147.601C-36.6 147.601 -31.4 147.201 -32.6 148.801C-33.8 150.401 -36.2 149.601 -36.2 149.601L-36.6 147.601z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M1.8 108.001C1.8 108.001 6.2 108.001 5 109.601C3.8 111.201 0.6 110.801 0.6 110.801L1.8 108.001z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-8.2 113.601C-8.2 113.601 -1.694 111.46 -4.2 114.801C-5.4 116.401 -7.8 115.601 -7.8 115.601L-8.2 113.601z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-19.4 118.401C-19.4 118.401 -14.2 118.001 -15.4 119.601C-16.6 121.201 -19 120.401 -19 120.401L-19.4 118.401z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-27 124.401C-27 124.401 -21.8 124.001 -23 125.601C-24.2 127.201 -26.6 126.401 -26.6 126.401L-27 124.401z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-33.8 129.201C-33.8 129.201 -28.6 128.801 -29.8 130.401C-31 132.001 -33.4 131.201 -33.4 131.201L-33.8 129.201z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M5.282 135.598C5.282 135.598 12.203 135.066 10.606 137.195C9.009 139.325 5.814 138.26 5.814 138.26L5.282 135.598z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M15.682 130.798C15.682 130.798 22.603 130.266 21.006 132.395C19.409 134.525 16.214 133.46 16.214 133.46L15.682 130.798z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M26.482 126.398C26.482 126.398 33.403 125.866 31.806 127.995C30.209 130.125 27.014 129.06 27.014 129.06L26.482 126.398z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M36.882 121.598C36.882 121.598 43.803 121.066 42.206 123.195C40.609 125.325 37.414 124.26 37.414 124.26L36.882 121.598z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M9.282 103.598C9.282 103.598 16.203 103.066 14.606 105.195C13.009 107.325 9.014 107.06 9.014 107.06L9.282 103.598z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M19.282 100.398C19.282 100.398 26.203 99.866 24.606 101.995C23.009 104.125 18.614 103.86 18.614 103.86L19.282 100.398z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-3.4 140.401C-3.4 140.401 1.8 140.001 0.6 141.601C-0.6 143.201 -3 142.401 -3 142.401L-3.4 140.401z"/>
+ </g>
+ <g style="fill: #992600">
+ <path d="M-76.6 41.2C-76.6 41.2 -81 50 -81.4 53.2C-81.4 53.2 -80.6 44.4 -79.4 42.4C-78.2 40.4 -76.6 41.2 -76.6 41.2z"/>
+ </g>
+ <g style="fill: #992600">
+ <path d="M-95 55.2C-95 55.2 -98.2 69.6 -97.8 72.4C-97.8 72.4 -99 60.8 -98.6 59.6C-98.2 58.4 -95 55.2 -95 55.2z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-74.2 -19.4L-74.4 -16.2L-76.6 -16C-76.6 -16 -62.4 -3.4 -61.8 4.2C-61.8 4.2 -61 -4 -74.2 -19.4z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-70.216 -18.135C-70.647 -18.551 -70.428 -19.296 -70.836 -19.556C-71.645 -20.072 -69.538 -20.129 -69.766 -20.845C-70.149 -22.051 -69.962 -22.072 -70.084 -23.348C-70.141 -23.946 -69.553 -25.486 -69.168 -25.926C-67.722 -27.578 -69.046 -30.51 -67.406 -32.061C-67.102 -32.35 -66.726 -32.902 -66.441 -33.32C-65.782 -34.283 -64.598 -34.771 -63.648 -35.599C-63.33 -35.875 -63.531 -36.702 -62.962 -36.61C-62.248 -36.495 -61.007 -36.625 -61.052 -35.784C-61.165 -33.664 -62.494 -31.944 -63.774 -30.276C-63.323 -29.572 -63.781 -28.937 -64.065 -28.38C-65.4 -25.76 -65.211 -22.919 -65.385 -20.079C-65.39 -19.994 -65.697 -19.916 -65.689 -19.863C-65.336 -17.528 -64.752 -15.329 -63.873 -13.1C-63.507 -12.17 -63.036 -11.275 -62.886 -10.348C-62.775 -9.662 -62.672 -8.829 -63.08 -8.124C-61.045 -5.234 -62.354 -2.583 -61.185 0.948C-60.978 1.573 -59.286 3.487 -59.749 3.326C-62.262 2.455 -62.374 2.057 -62.551 1.304C-62.697 0.681 -63.027 -0.696 -63.264 -1.298C-63.328 -1.462 -63.499 -3.346 -63.577 -3.468C-65.09 -5.85 -63.732 -5.674 -65.102 -8.032C-66.53 -8.712 -67.496 -9.816 -68.619 -10.978C-68.817 -11.182 -67.674 -11.906 -67.855 -12.119C-68.947 -13.408 -70.1 -14.175 -69.764 -15.668C-69.609 -16.358 -69.472 -17.415 -70.216 -18.135z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-73.8 -16.4C-73.8 -16.4 -73.4 -9.6 -71 -8C-68.6 -6.4 -69.8 -7.2 -73 -8.4C-76.2 -9.6 -75 -10.4 -75 -10.4C-75 -10.4 -77.8 -10 -75.4 -8C-73 -6 -69.4 -3.6 -71 -3.6C-72.6 -3.6 -80.2 -7.6 -80.2 -10.4C-80.2 -13.2 -81.2 -17.3 -81.2 -17.3C-81.2 -17.3 -80.1 -18.1 -75.3 -18C-75.3 -18 -73.9 -17.3 -73.8 -16.4z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-74.6 2.2C-74.6 2.2 -83.12 -0.591 -101.6 2.8C-101.6 2.8 -92.569 0.722 -73.8 3C-63.5 4.25 -74.6 2.2 -74.6 2.2z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-72.502 2.129C-72.502 2.129 -80.748 -1.389 -99.453 0.392C-99.453 0.392 -90.275 -0.897 -71.774 2.995C-61.62 5.131 -72.502 2.129 -72.502 2.129z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-70.714 2.222C-70.714 2.222 -78.676 -1.899 -97.461 -1.514C-97.461 -1.514 -88.213 -2.118 -70.052 3.14C-60.086 6.025 -70.714 2.222 -70.714 2.222z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-69.444 2.445C-69.444 2.445 -76.268 -1.862 -93.142 -2.96C-93.142 -2.96 -84.803 -2.79 -68.922 3.319C-60.206 6.672 -69.444 2.445 -69.444 2.445z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M45.84 12.961C45.84 12.961 44.91 13.605 45.124 12.424C45.339 11.243 73.547 -1.927 77.161 -1.677C77.161 -1.677 46.913 11.529 45.84 12.961z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M42.446 13.6C42.446 13.6 41.57 14.315 41.691 13.121C41.812 11.927 68.899 -3.418 72.521 -3.452C72.521 -3.452 43.404 12.089 42.446 13.6z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M39.16 14.975C39.16 14.975 38.332 15.747 38.374 14.547C38.416 13.348 58.233 -2.149 68.045 -4.023C68.045 -4.023 50.015 4.104 39.16 14.975z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M36.284 16.838C36.284 16.838 35.539 17.532 35.577 16.453C35.615 15.373 53.449 1.426 62.28 -0.26C62.28 -0.26 46.054 7.054 36.284 16.838z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M4.6 164.801C4.6 164.801 -10.6 162.401 6.2 160.801C6.2 160.801 24.2 158.801 28.2 153.601C28.2 153.601 41.8 144.401 44.6 144.001C47.4 143.601 63.8 140.001 64.2 137.601C64.6 135.201 70.6 132.801 72.2 133.601C73.8 134.401 73.8 143.601 71 144.401C68.2 145.201 49.4 152.401 43 153.601C36.6 154.801 25 162.401 20.2 163.601C15.4 164.801 4.6 164.801 4.6 164.801z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M77.6 127.401C77.6 127.401 74.6 129.001 73.4 131.601C73.4 131.601 67 142.201 52.8 145.401C52.8 145.401 29.8 154.401 22 156.401C22 156.401 8.6 161.401 1.2 160.601C1.2 160.601 -5.8 160.801 0.4 162.401C0.4 162.401 20.6 160.401 24 158.601C24 158.601 39.6 153.401 42.6 150.801C45.6 148.201 63.8 143.201 66 141.201C68.2 139.201 78 130.801 77.6 127.401z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M18.882 158.911C18.882 158.911 24.111 158.685 22.958 160.234C21.805 161.784 19.357 160.91 19.357 160.91L18.882 158.911z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M11.68 160.263C11.68 160.263 16.908 160.037 15.756 161.586C14.603 163.136 12.155 162.263 12.155 162.263L11.68 160.263z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M1.251 161.511C1.251 161.511 6.48 161.284 5.327 162.834C4.174 164.383 1.726 163.51 1.726 163.51L1.251 161.511z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-6.383 162.055C-6.383 162.055 -1.154 161.829 -2.307 163.378C-3.46 164.928 -5.908 164.054 -5.908 164.054L-6.383 162.055z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M35.415 151.513C35.415 151.513 42.375 151.212 40.84 153.274C39.306 155.336 36.047 154.174 36.047 154.174L35.415 151.513z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M45.73 147.088C45.73 147.088 51.689 143.787 51.155 148.849C50.885 151.405 46.362 149.749 46.362 149.749L45.73 147.088z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M54.862 144.274C54.862 144.274 62.021 140.573 60.287 146.035C59.509 148.485 55.493 146.935 55.493 146.935L54.862 144.274z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M64.376 139.449C64.376 139.449 68.735 134.548 69.801 141.21C70.207 143.748 65.008 142.11 65.008 142.11L64.376 139.449z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M26.834 155.997C26.834 155.997 32.062 155.77 30.91 157.32C29.757 158.869 27.308 157.996 27.308 157.996L26.834 155.997z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M62.434 34.603C62.434 34.603 61.708 35.268 61.707 34.197C61.707 33.127 79.191 19.863 88.034 18.479C88.034 18.479 71.935 25.208 62.434 34.603z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M65.4 98.4C65.4 98.4 87.401 120.801 96.601 124.401C96.601 124.401 105.801 135.601 101.801 161.601C101.801 161.601 98.601 169.201 95.401 148.401C95.401 148.401 98.601 123.201 87.401 139.201C87.401 139.201 79 129.301 85.4 129.601C85.4 129.601 88.601 131.601 89.001 130.001C89.401 128.401 81.4 114.801 64.2 100.4C47 86 65.4 98.4 65.4 98.4z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M7 137.201C7 137.201 6.8 135.401 8.6 136.201C10.4 137.001 104.601 143.201 136.201 167.201C136.201 167.201 91.001 144.001 7 137.201z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M17.4 132.801C17.4 132.801 17.2 131.001 19 131.801C20.8 132.601 157.401 131.601 181.001 164.001C181.001 164.001 159.001 138.801 17.4 132.801z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M29 128.801C29 128.801 28.8 127.001 30.6 127.801C32.4 128.601 205.801 115.601 229.401 148.001C229.401 148.001 219.801 122.401 29 128.801z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M39 124.001C39 124.001 38.8 122.201 40.6 123.001C42.4 123.801 164.601 85.2 188.201 117.601C188.201 117.601 174.801 93 39 124.001z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-19 146.801C-19 146.801 -19.2 145.001 -17.4 145.801C-15.6 146.601 2.2 148.801 4.2 187.601C4.2 187.601 -3 145.601 -19 146.801z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-27.8 148.401C-27.8 148.401 -28 146.601 -26.2 147.401C-24.4 148.201 -10.2 143.601 -13 182.401C-13 182.401 -11.8 147.201 -27.8 148.401z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-35.8 148.801C-35.8 148.801 -36 147.001 -34.2 147.801C-32.4 148.601 -17 149.201 -29.4 171.601C-29.4 171.601 -19.8 147.601 -35.8 148.801z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M11.526 104.465C11.526 104.465 11.082 106.464 12.631 105.247C28.699 92.622 61.141 33.72 116.826 28.086C116.826 28.086 78.518 15.976 11.526 104.465z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M22.726 102.665C22.726 102.665 21.363 101.472 23.231 100.847C25.099 100.222 137.541 27.72 176.826 35.686C176.826 35.686 149.719 28.176 22.726 102.665z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M1.885 108.767C1.885 108.767 1.376 110.366 3.087 109.39C12.062 104.27 15.677 47.059 59.254 45.804C59.254 45.804 26.843 31.09 1.885 108.767z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-18.038 119.793C-18.038 119.793 -19.115 121.079 -17.162 120.825C-6.916 119.493 14.489 78.222 58.928 83.301C58.928 83.301 26.962 68.955 -18.038 119.793z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-6.8 113.667C-6.8 113.667 -7.611 115.136 -5.742 114.511C4.057 111.237 17.141 66.625 61.729 63.078C61.729 63.078 27.603 55.135 -6.8 113.667z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-25.078 124.912C-25.078 124.912 -25.951 125.954 -24.369 125.748C-16.07 124.669 1.268 91.24 37.264 95.354C37.264 95.354 11.371 83.734 -25.078 124.912z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-32.677 130.821C-32.677 130.821 -33.682 131.866 -32.091 131.748C-27.923 131.439 2.715 98.36 21.183 113.862C21.183 113.862 9.168 95.139 -32.677 130.821z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M36.855 98.898C36.855 98.898 35.654 97.543 37.586 97.158C39.518 96.774 160.221 39.061 198.184 51.927C198.184 51.927 172.243 41.053 36.855 98.898z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M3.4 163.201C3.4 163.201 3.2 161.401 5 162.201C6.8 163.001 22.2 163.601 9.8 186.001C9.8 186.001 19.4 162.001 3.4 163.201z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M13.8 161.601C13.8 161.601 13.6 159.801 15.4 160.601C17.2 161.401 35 163.601 37 202.401C37 202.401 29.8 160.401 13.8 161.601z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M20.6 160.001C20.6 160.001 20.4 158.201 22.2 159.001C24 159.801 48.6 163.201 72.2 195.601C72.2 195.601 36.6 158.801 20.6 160.001z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M28.225 157.972C28.225 157.972 27.788 156.214 29.678 156.768C31.568 157.322 52.002 155.423 90.099 189.599C90.099 189.599 43.924 154.656 28.225 157.972z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M38.625 153.572C38.625 153.572 38.188 151.814 40.078 152.368C41.968 152.922 76.802 157.423 128.499 192.399C128.499 192.399 54.324 150.256 38.625 153.572z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-1.8 142.001C-1.8 142.001 -2 140.201 -0.2 141.001C1.6 141.801 55 144.401 85.4 171.201C85.4 171.201 50.499 146.426 -1.8 142.001z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-11.8 146.001C-11.8 146.001 -12 144.201 -10.2 145.001C-8.4 145.801 16.2 149.201 39.8 181.601C39.8 181.601 4.2 144.801 -11.8 146.001z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M49.503 148.962C49.503 148.962 48.938 147.241 50.864 147.655C52.79 148.068 87.86 150.004 141.981 181.098C141.981 181.098 64.317 146.704 49.503 148.962z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M57.903 146.562C57.903 146.562 57.338 144.841 59.264 145.255C61.19 145.668 96.26 147.604 150.381 178.698C150.381 178.698 73.317 143.904 57.903 146.562z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M67.503 141.562C67.503 141.562 66.938 139.841 68.864 140.255C70.79 140.668 113.86 145.004 203.582 179.298C203.582 179.298 82.917 138.904 67.503 141.562z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-43.8 148.401C-43.8 148.401 -38.6 148.001 -39.8 149.601C-41 151.201 -43.4 150.401 -43.4 150.401L-43.8 148.401z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-13 162.401C-13 162.401 -7.8 162.001 -9 163.601C-10.2 165.201 -12.6 164.401 -12.6 164.401L-13 162.401z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-21.8 162.001C-21.8 162.001 -16.6 161.601 -17.8 163.201C-19 164.801 -21.4 164.001 -21.4 164.001L-21.8 162.001z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-117.169 150.182C-117.169 150.182 -112.124 151.505 -113.782 152.624C-115.439 153.744 -117.446 152.202 -117.446 152.202L-117.169 150.182z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-115.169 140.582C-115.169 140.582 -110.124 141.905 -111.782 143.024C-113.439 144.144 -115.446 142.602 -115.446 142.602L-115.169 140.582z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-122.369 136.182C-122.369 136.182 -117.324 137.505 -118.982 138.624C-120.639 139.744 -122.646 138.202 -122.646 138.202L-122.369 136.182z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-42.6 211.201C-42.6 211.201 -44.2 211.201 -48.2 213.201C-50.2 213.201 -61.4 216.801 -67 226.801C-67 226.801 -54.6 217.201 -42.6 211.201z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M45.116 303.847C45.257 304.105 45.312 304.525 45.604 304.542C46.262 304.582 47.495 304.883 47.37 304.247C46.522 299.941 45.648 295.004 41.515 293.197C40.876 292.918 39.434 293.331 39.36 294.215C39.233 295.739 39.116 297.088 39.425 298.554C39.725 299.975 41.883 299.985 42.8 298.601C43.736 300.273 44.168 302.116 45.116 303.847z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M34.038 308.581C34.786 309.994 34.659 311.853 36.074 312.416C36.814 312.71 38.664 311.735 38.246 310.661C37.444 308.6 37.056 306.361 35.667 304.55C35.467 304.288 35.707 303.755 35.547 303.427C34.953 302.207 33.808 301.472 32.4 301.801C31.285 304.004 32.433 306.133 33.955 307.842C34.091 307.994 33.925 308.37 34.038 308.581z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-5.564 303.391C-5.672 303.014 -5.71 302.551 -5.545 302.23C-5.014 301.197 -4.221 300.075 -4.558 299.053C-4.906 297.997 -6.022 298.179 -6.672 298.748C-7.807 299.742 -7.856 301.568 -8.547 302.927C-8.743 303.313 -8.692 303.886 -9.133 304.277C-9.607 304.698 -10.047 306.222 -9.951 306.793C-9.898 307.106 -10.081 317.014 -9.859 316.751C-9.24 316.018 -6.19 306.284 -6.121 305.392C-6.064 304.661 -5.332 304.196 -5.564 303.391z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-31.202 296.599C-28.568 294.1 -25.778 291.139 -26.22 287.427C-26.336 286.451 -28.111 286.978 -28.298 287.824C-29.1 291.449 -31.139 294.11 -33.707 296.502C-35.903 298.549 -37.765 304.893 -38 305.401C-34.303 300.145 -32.046 297.399 -31.202 296.599z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-44.776 290.635C-44.253 290.265 -44.555 289.774 -44.338 289.442C-43.385 287.984 -42.084 286.738 -42.066 285C-42.063 284.723 -42.441 284.414 -42.776 284.638C-43.053 284.822 -43.395 284.952 -43.503 285.082C-45.533 287.531 -46.933 290.202 -48.376 293.014C-48.559 293.371 -49.703 297.862 -49.39 297.973C-49.151 298.058 -47.431 293.877 -47.221 293.763C-45.958 293.077 -45.946 291.462 -44.776 290.635z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-28.043 310.179C-27.599 309.31 -26.023 308.108 -26.136 307.219C-26.254 306.291 -25.786 304.848 -26.698 305.536C-27.955 306.484 -31.404 307.833 -31.674 313.641C-31.7 314.212 -28.726 311.519 -28.043 310.179z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-13.6 293.001C-13.2 292.333 -12.492 292.806 -12.033 292.543C-11.385 292.171 -10.774 291.613 -10.482 290.964C-9.512 288.815 -7.743 286.995 -7.6 284.601C-9.091 283.196 -9.77 285.236 -10.4 286.201C-11.723 284.554 -12.722 286.428 -14.022 286.947C-14.092 286.975 -14.305 286.628 -14.38 286.655C-15.557 287.095 -16.237 288.176 -17.235 288.957C-17.406 289.091 -17.811 288.911 -17.958 289.047C-18.61 289.65 -19.583 289.975 -19.863 290.657C-20.973 293.364 -24.113 295.459 -26 303.001C-25.619 303.91 -21.488 296.359 -21.001 295.661C-20.165 294.465 -20.047 297.322 -18.771 296.656C-18.72 296.629 -18.534 296.867 -18.4 297.001C-18.206 296.721 -17.988 296.492 -17.6 296.601C-17.6 296.201 -17.734 295.645 -17.533 295.486C-16.296 294.509 -16.38 293.441 -15.6 292.201C-15.142 292.99 -14.081 292.271 -13.6 293.001z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M46.2 347.401C46.2 347.401 53.6 327.001 49.2 315.801C49.2 315.801 60.6 337.401 56 348.601C56 348.601 55.6 338.201 51.6 333.201C51.6 333.201 47.6 346.001 46.2 347.401z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M31.4 344.801C31.4 344.801 36.8 336.001 28.8 317.601C28.8 317.601 28 338.001 21.2 349.001C21.2 349.001 35.4 328.801 31.4 344.801z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M21.4 342.801C21.4 342.801 21.2 322.801 21.6 319.801C21.6 319.801 17.8 336.401 7.6 346.001C7.6 346.001 22 334.001 21.4 342.801z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M11.8 310.801C11.8 310.801 17.8 324.401 7.8 342.801C7.8 342.801 14.2 330.601 9.4 323.601C9.4 323.601 12 320.201 11.8 310.801z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-7.4 342.401C-7.4 342.401 -8.4 326.801 -6.6 324.601C-6.6 324.601 -6.4 318.201 -6.8 317.201C-6.8 317.201 -2.8 311.001 -2.6 318.401C-2.6 318.401 -1.2 326.201 1.6 330.801C1.6 330.801 5.2 336.201 5 342.601C5 342.601 -5 312.401 -7.4 342.401z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-11 314.801C-11 314.801 -17.6 325.601 -19.4 344.601C-19.4 344.601 -20.8 338.401 -17 324.001C-17 324.001 -12.8 308.601 -11 314.801z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-32.8 334.601C-32.8 334.601 -27.8 329.201 -26.4 324.201C-26.4 324.201 -22.8 308.401 -29.2 317.001C-29.2 317.001 -29 325.001 -37.2 332.401C-37.2 332.401 -32.4 330.001 -32.8 334.601z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-38.6 329.601C-38.6 329.601 -35.2 312.201 -34.4 311.401C-34.4 311.401 -32.6 308.001 -35.4 311.201C-35.4 311.201 -44.2 330.401 -48.2 337.001C-48.2 337.001 -40.2 327.801 -38.6 329.601z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-44.4 313.001C-44.4 313.001 -32.8 290.601 -54.6 316.401C-54.6 316.401 -43.6 306.601 -44.4 313.001z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-59.8 298.401C-59.8 298.401 -55 279.601 -52.4 279.801C-52.4 279.801 -44.2 270.801 -50.8 281.401C-50.8 281.401 -56.8 291.001 -56.2 300.801C-56.2 300.801 -56.8 291.201 -59.8 298.401z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M270.5 287C270.5 287 258.5 277 256 273.5C256 273.5 269.5 292 269.5 299C269.5 299 272 291.5 270.5 287z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M276 265C276 265 255 250 251.5 242.5C251.5 242.5 278 272 278 276.5C278 276.5 278.5 267.5 276 265z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M293 111C293 111 281 103 279.5 105C279.5 105 290 111.5 292.5 120C292.5 120 291 111 293 111z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M301.5 191.5L284 179.5C284 179.5 303 196.5 303.5 200.5L301.5 191.5z"/>
+ </g>
+ <g style="stroke:#000000">
+ <path d="M-89.25 169L-67.25 173.75"/>
+ </g>
+ <g style="stroke:#000000">
+ <path d="M-39 331C-39 331 -39.5 327.5 -48.5 338"/>
+ </g>
+ <g style="stroke:#000000">
+ <path d="M-33.5 336C-33.5 336 -31.5 329.5 -38 334"/>
+ </g>
+ <g style="stroke:#000000">
+ <path d="M20.5 344.5C20.5 344.5 22 333.5 10.5 346.5"/>
+ </g>
+</svg>
diff --git a/ksvg/test/tiger2.svg b/ksvg/test/tiger2.svg
new file mode 100644
index 00000000..1cb123e6
--- /dev/null
+++ b/ksvg/test/tiger2.svg
@@ -0,0 +1,725 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+ <g transform="translate(200,200)">
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
+ <path d="M-122.304 84.285C-122.304 84.285 -122.203 86.179 -123.027 86.16C-123.851 86.141 -140.305 38.066 -160.833 40.309C-160.833 40.309 -143.05 32.956 -122.304 84.285z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
+ <path d="M-118.774 81.262C-118.774 81.262 -119.323 83.078 -120.092 82.779C-120.86 82.481 -119.977 31.675 -140.043 26.801C-140.043 26.801 -120.82 25.937 -118.774 81.262z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
+ <path d="M-91.284 123.59C-91.284 123.59 -89.648 124.55 -90.118 125.227C-90.589 125.904 -139.763 113.102 -149.218 131.459C-149.218 131.459 -145.539 112.572 -91.284 123.59z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
+ <path d="M-94.093 133.801C-94.093 133.801 -92.237 134.197 -92.471 134.988C-92.704 135.779 -143.407 139.121 -146.597 159.522C-146.597 159.522 -149.055 140.437 -94.093 133.801z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
+ <path d="M-98.304 128.276C-98.304 128.276 -96.526 128.939 -96.872 129.687C-97.218 130.435 -147.866 126.346 -153.998 146.064C-153.998 146.064 -153.646 126.825 -98.304 128.276z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
+ <path d="M-109.009 110.072C-109.009 110.072 -107.701 111.446 -108.34 111.967C-108.979 112.488 -152.722 86.634 -166.869 101.676C-166.869 101.676 -158.128 84.533 -109.009 110.072z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
+ <path d="M-116.554 114.263C-116.554 114.263 -115.098 115.48 -115.674 116.071C-116.25 116.661 -162.638 95.922 -174.992 112.469C-174.992 112.469 -168.247 94.447 -116.554 114.263z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
+ <path d="M-119.154 118.335C-119.154 118.335 -117.546 119.343 -118.036 120.006C-118.526 120.669 -167.308 106.446 -177.291 124.522C-177.291 124.522 -173.066 105.749 -119.154 118.335z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
+ <path d="M-108.42 118.949C-108.42 118.949 -107.298 120.48 -107.999 120.915C-108.7 121.35 -148.769 90.102 -164.727 103.207C-164.727 103.207 -153.862 87.326 -108.42 118.949z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
+ <path d="M-128.2 90C-128.2 90 -127.6 91.8 -128.4 92C-129.2 92.2 -157.8 50.2 -177.001 57.8C-177.001 57.8 -161.8 46 -128.2 90z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
+ <path d="M-127.505 96.979C-127.505 96.979 -126.53 98.608 -127.269 98.975C-128.007 99.343 -164.992 64.499 -182.101 76.061C-182.101 76.061 -169.804 61.261 -127.505 96.979z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.172">
+ <path d="M-127.62 101.349C-127.62 101.349 -126.498 102.88 -127.199 103.315C-127.9 103.749 -167.969 72.502 -183.927 85.607C-183.927 85.607 -173.062 69.726 -127.62 101.349z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000">
+ <path d="M-129.83 103.065C-129.327 109.113 -128.339 115.682 -126.6 118.801C-126.6 118.801 -130.2 131.201 -121.4 144.401C-121.4 144.401 -121.8 151.601 -120.2 154.801C-120.2 154.801 -116.2 163.201 -111.4 164.001C-107.516 164.648 -98.793 167.717 -88.932 169.121C-88.932 169.121 -71.8 183.201 -75 196.001C-75 196.001 -75.4 212.401 -79 214.001C-79 214.001 -67.4 202.801 -77 219.601L-81.4 238.401C-81.4 238.401 -55.8 216.801 -71.4 235.201L-81.4 261.201C-81.4 261.201 -61.8 242.801 -69 251.201L-72.2 260.001C-72.2 260.001 -29 232.801 -59.8 262.401C-59.8 262.401 -51.8 258.801 -47.4 261.601C-47.4 261.601 -40.6 260.401 -41.4 262.001C-41.4 262.001 -62.2 272.401 -65.8 290.801C-65.8 290.801 -57.4 280.801 -60.6 291.601L-60.2 303.201C-60.2 303.201 -56.2 281.601 -56.6 319.201C-56.6 319.201 -37.4 301.201 -49 322.001L-49 338.801C-49 338.801 -33.8 322.401 -40.2 335.201C-40.2 335.201 -30.2 326.401 -34.2 341.601C-34.2 341.601 -35 352.001 -30.6 340.801C-30.6 340.801 -14.6 310.201 -20.6 336.401C-20.6 336.401 -21.4 355.601 -16.6 340.801C-16.6 340.801 -16.2 351.201 -7 358.401C-7 358.401 -8.2 307.601 4.6 343.601L8.6 360.001C8.6 360.001 11.4 350.801 11 345.601C11 345.601 25.8 329.201 19 353.601C19 353.601 34.2 330.801 31 344.001C31 344.001 23.4 360.001 25 364.801C25 364.801 41.8 330.001 43 328.401C43 328.401 41 370.802 51.8 334.801C51.8 334.801 57.4 346.801 54.6 351.201C54.6 351.201 62.6 343.201 61.8 340.001C61.8 340.001 66.4 331.801 69.2 345.401C69.2 345.401 71 354.801 72.6 351.601C72.6 351.601 76.6 375.602 77.8 352.801C77.8 352.801 79.4 339.201 72.2 327.601C72.2 327.601 73 324.401 70.2 320.401C70.2 320.401 83.8 342.001 76.6 313.201C76.6 313.201 87.801 321.201 89.001 321.201C89.001 321.201 75.4 298.001 84.2 302.801C84.2 302.801 79 292.401 97.001 304.401C97.001 304.401 81 288.401 98.601 298.001C98.601 298.001 106.601 304.401 99.001 294.401C99.001 294.401 84.6 278.401 106.601 296.401C106.601 296.401 118.201 312.801 119.001 315.601C119.001 315.601 109.001 286.401 104.601 283.601C104.601 283.601 113.001 247.201 154.201 262.801C154.201 262.801 161.001 280.001 165.401 261.601C165.401 261.601 178.201 255.201 189.401 282.801C189.401 282.801 193.401 269.201 192.601 266.401C192.601 266.401 199.401 267.601 198.601 266.401C198.601 266.401 211.801 270.801 213.001 270.001C213.001 270.001 219.801 276.801 220.201 273.201C220.201 273.201 229.401 276.001 227.401 272.401C227.401 272.401 236.201 288.001 236.601 291.601L239.001 277.601L241.001 280.401C241.001 280.401 242.601 272.801 241.801 271.601C241.001 270.401 261.801 278.401 266.601 299.201L268.601 307.601C268.601 307.601 274.601 292.801 273.001 288.801C273.001 288.801 278.201 289.601 278.601 294.001C278.601 294.001 282.601 270.801 277.801 264.801C277.801 264.801 282.201 264.001 283.401 267.601L283.401 260.401C283.401 260.401 290.601 261.201 290.601 258.801C290.601 258.801 295.001 254.801 297.001 259.601C297.001 259.601 284.601 224.401 303.001 243.601C303.001 243.601 310.201 254.401 306.601 235.601C303.001 216.801 299.001 215.201 303.801 214.801C303.801 214.801 304.601 211.201 302.601 209.601C300.601 208.001 303.801 209.601 303.801 209.601C303.801 209.601 308.601 213.601 303.401 191.601C303.401 191.601 309.801 193.201 297.801 164.001C297.801 164.001 300.601 161.601 296.601 153.201C296.601 153.201 304.601 157.601 307.401 156.001C307.401 156.001 307.001 154.401 303.801 150.401C303.801 150.401 282.201 95.6 302.601 117.601C302.601 117.601 314.451 131.151 308.051 108.351C308.051 108.351 298.94 84.341 299.717 80.045L-129.83 103.065z"/>
+ </g>
+ <g style="fill: #cc7226; stroke:#000000">
+ <path d="M299.717 80.245C300.345 80.426 302.551 81.55 303.801 83.2C303.801 83.2 310.601 94 305.401 75.6C305.401 75.6 296.201 46.8 305.001 58C305.001 58 311.001 65.2 307.801 51.6C303.936 35.173 301.401 28.8 301.401 28.8C301.401 28.8 313.001 33.6 286.201 -6L295.001 -2.4C295.001 -2.4 275.401 -42 253.801 -47.2L245.801 -53.2C245.801 -53.2 284.201 -91.2 271.401 -128C271.401 -128 264.601 -133.2 255.001 -124C255.001 -124 248.601 -119.2 242.601 -120.8C242.601 -120.8 211.801 -119.6 209.801 -119.6C207.801 -119.6 173.001 -156.8 107.401 -139.2C107.401 -139.2 102.201 -137.2 97.801 -138.4C97.801 -138.4 79.4 -154.4 30.6 -131.6C30.6 -131.6 20.6 -129.6 19 -129.6C17.4 -129.6 14.6 -129.6 6.6 -123.2C-1.4 -116.8 -1.8 -116 -3.8 -114.4C-3.8 -114.4 -20.2 -103.2 -25 -102.4C-25 -102.4 -36.6 -96 -41 -86L-44.6 -84.8C-44.6 -84.8 -46.2 -77.6 -46.6 -76.4C-46.6 -76.4 -51.4 -72.8 -52.2 -67.2C-52.2 -67.2 -61 -61.2 -60.6 -56.8C-60.6 -56.8 -62.2 -51.6 -63 -46.8C-63 -46.8 -70.2 -42 -69.4 -39.2C-69.4 -39.2 -77 -25.2 -75.8 -18.4C-75.8 -18.4 -82.2 -18.8 -85 -16.4C-85 -16.4 -85.8 -11.6 -87.4 -11.2C-87.4 -11.2 -90.2 -10 -87.8 -6C-87.8 -6 -89.4 -3.2 -89.8 -1.6C-89.8 -1.6 -89 1.2 -93.4 6.8C-93.4 6.8 -99.8 25.6 -97.8 30.8C-97.8 30.8 -97.4 35.6 -100.2 37.2C-100.2 37.2 -103.8 36.8 -95.4 48.8C-95.4 48.8 -94.6 50 -97.8 52.4C-97.8 52.4 -115 56 -117.4 72.4C-117.4 72.4 -131 87.2 -131 92.4C-131 94.705 -130.729 97.852 -130.03 102.465C-130.03 102.465 -130.6 110.801 -103 111.601C-75.4 112.401 299.717 80.245 299.717 80.245z"/>
+ </g>
+ <g style="fill: #cc7226">
+ <path d="M-115.6 102.6C-140.6 63.2 -126.2 119.601 -126.2 119.601C-117.4 154.001 12.2 116.401 12.2 116.401C12.2 116.401 181.001 86 192.201 82C203.401 78 298.601 84.4 298.601 84.4L293.001 67.6C228.201 21.2 209.001 44.4 195.401 40.4C181.801 36.4 184.201 46 181.001 46.8C177.801 47.6 138.601 22.8 132.201 23.6C125.801 24.4 100.459 0.649 115.401 32.4C131.401 66.4 57 71.6 40.2 60.4C23.4 49.2 47.4 78.8 47.4 78.8C65.8 98.8 31.4 82 31.4 82C-3 69.2 -27 94.8 -30.2 95.6C-33.4 96.4 -38.2 99.6 -39 93.2C-39.8 86.8 -47.31 70.099 -79 96.4C-99 113.001 -112.8 91 -112.8 91L-115.6 102.6z"/>
+ </g>
+ <g style="fill: #e87f3a">
+ <path d="M133.51 25.346C127.11 26.146 101.743 2.407 116.71 34.146C133.31 69.346 58.31 73.346 41.51 62.146C24.709 50.946 48.71 80.546 48.71 80.546C67.11 100.546 32.709 83.746 32.709 83.746C-1.691 70.946 -25.691 96.546 -28.891 97.346C-32.091 98.146 -36.891 101.346 -37.691 94.946C-38.491 88.546 -45.87 72.012 -77.691 98.146C-98.927 115.492 -112.418 94.037 -112.418 94.037L-115.618 104.146C-140.618 64.346 -125.546 122.655 -125.546 122.655C-116.745 157.056 13.509 118.146 13.509 118.146C13.509 118.146 182.31 87.746 193.51 83.746C204.71 79.746 299.038 86.073 299.038 86.073L293.51 68.764C228.71 22.364 210.31 46.146 196.71 42.146C183.11 38.146 185.51 47.746 182.31 48.546C179.11 49.346 139.91 24.546 133.51 25.346z"/>
+ </g>
+ <g style="fill: #ea8c4d">
+ <path d="M134.819 27.091C128.419 27.891 103.685 3.862 118.019 35.891C134.219 72.092 59.619 75.092 42.819 63.892C26.019 52.692 50.019 82.292 50.019 82.292C68.419 102.292 34.019 85.492 34.019 85.492C-0.381 72.692 -24.382 98.292 -27.582 99.092C-30.782 99.892 -35.582 103.092 -36.382 96.692C-37.182 90.292 -44.43 73.925 -76.382 99.892C-98.855 117.983 -112.036 97.074 -112.036 97.074L-115.636 105.692C-139.436 66.692 -124.891 125.71 -124.891 125.71C-116.091 160.11 14.819 119.892 14.819 119.892C14.819 119.892 183.619 89.492 194.819 85.492C206.019 81.492 299.474 87.746 299.474 87.746L294.02 69.928C229.219 23.528 211.619 47.891 198.019 43.891C184.419 39.891 186.819 49.491 183.619 50.292C180.419 51.092 141.219 26.291 134.819 27.091z"/>
+ </g>
+ <g style="fill: #ec9961">
+ <path d="M136.128 28.837C129.728 29.637 104.999 5.605 119.328 37.637C136.128 75.193 60.394 76.482 44.128 65.637C27.328 54.437 51.328 84.037 51.328 84.037C69.728 104.037 35.328 87.237 35.328 87.237C0.928 74.437 -23.072 100.037 -26.272 100.837C-29.472 101.637 -34.272 104.837 -35.072 98.437C-35.872 92.037 -42.989 75.839 -75.073 101.637C-98.782 120.474 -111.655 100.11 -111.655 100.11L-115.655 107.237C-137.455 70.437 -124.236 128.765 -124.236 128.765C-115.436 163.165 16.128 121.637 16.128 121.637C16.128 121.637 184.928 91.237 196.129 87.237C207.329 83.237 299.911 89.419 299.911 89.419L294.529 71.092C229.729 24.691 212.929 49.637 199.329 45.637C185.728 41.637 188.128 51.237 184.928 52.037C181.728 52.837 142.528 28.037 136.128 28.837z"/>
+ </g>
+ <g style="fill: #eea575">
+ <path d="M137.438 30.583C131.037 31.383 106.814 7.129 120.637 39.383C137.438 78.583 62.237 78.583 45.437 67.383C28.637 56.183 52.637 85.783 52.637 85.783C71.037 105.783 36.637 88.983 36.637 88.983C2.237 76.183 -21.763 101.783 -24.963 102.583C-28.163 103.383 -32.963 106.583 -33.763 100.183C-34.563 93.783 -41.548 77.752 -73.763 103.383C-98.709 122.965 -111.273 103.146 -111.273 103.146L-115.673 108.783C-135.473 73.982 -123.582 131.819 -123.582 131.819C-114.782 166.22 17.437 123.383 17.437 123.383C17.437 123.383 186.238 92.983 197.438 88.983C208.638 84.983 300.347 91.092 300.347 91.092L295.038 72.255C230.238 25.855 214.238 51.383 200.638 47.383C187.038 43.383 189.438 52.983 186.238 53.783C183.038 54.583 143.838 29.783 137.438 30.583z"/>
+ </g>
+ <g style="fill: #f1b288">
+ <path d="M138.747 32.328C132.347 33.128 106.383 9.677 121.947 41.128C141.147 79.928 63.546 80.328 46.746 69.128C29.946 57.928 53.946 87.528 53.946 87.528C72.346 107.528 37.946 90.728 37.946 90.728C3.546 77.928 -20.454 103.528 -23.654 104.328C-26.854 105.128 -31.654 108.328 -32.454 101.928C-33.254 95.528 -40.108 79.665 -72.454 105.128C-98.636 125.456 -110.891 106.183 -110.891 106.183L-115.691 110.328C-133.691 77.128 -122.927 134.874 -122.927 134.874C-114.127 169.274 18.746 125.128 18.746 125.128C18.746 125.128 187.547 94.728 198.747 90.728C209.947 86.728 300.783 92.764 300.783 92.764L295.547 73.419C230.747 27.019 215.547 53.128 201.947 49.128C188.347 45.128 190.747 54.728 187.547 55.528C184.347 56.328 145.147 31.528 138.747 32.328z"/>
+ </g>
+ <g style="fill: #f3bf9c">
+ <path d="M140.056 34.073C133.655 34.873 107.313 11.613 123.255 42.873C143.656 82.874 64.855 82.074 48.055 70.874C31.255 59.674 55.255 89.274 55.255 89.274C73.655 109.274 39.255 92.474 39.255 92.474C4.855 79.674 -19.145 105.274 -22.345 106.074C-25.545 106.874 -30.345 110.074 -31.145 103.674C-31.945 97.274 -38.668 81.578 -71.145 106.874C-98.564 127.947 -110.509 109.219 -110.509 109.219L-115.709 111.874C-131.709 81.674 -122.273 137.929 -122.273 137.929C-113.473 172.329 20.055 126.874 20.055 126.874C20.055 126.874 188.856 96.474 200.056 92.474C211.256 88.474 301.22 94.437 301.22 94.437L296.056 74.583C231.256 28.183 216.856 54.874 203.256 50.874C189.656 46.873 192.056 56.474 188.856 57.274C185.656 58.074 146.456 33.273 140.056 34.073z"/>
+ </g>
+ <g style="fill: #f5ccb0">
+ <path d="M141.365 35.819C134.965 36.619 107.523 13.944 124.565 44.619C146.565 84.219 66.164 83.819 49.364 72.619C32.564 61.419 56.564 91.019 56.564 91.019C74.964 111.019 40.564 94.219 40.564 94.219C6.164 81.419 -17.836 107.019 -21.036 107.819C-24.236 108.619 -29.036 111.819 -29.836 105.419C-30.636 99.019 -37.227 83.492 -69.836 108.619C-98.491 130.438 -110.127 112.256 -110.127 112.256L-115.727 113.419C-130.128 85.019 -121.618 140.983 -121.618 140.983C-112.818 175.384 21.364 128.619 21.364 128.619C21.364 128.619 190.165 98.219 201.365 94.219C212.565 90.219 301.656 96.11 301.656 96.11L296.565 75.746C231.765 29.346 218.165 56.619 204.565 52.619C190.965 48.619 193.365 58.219 190.165 59.019C186.965 59.819 147.765 35.019 141.365 35.819z"/>
+ </g>
+ <g style="fill: #f8d8c4">
+ <path d="M142.674 37.565C136.274 38.365 108.832 15.689 125.874 46.365C147.874 85.965 67.474 85.565 50.674 74.365C33.874 63.165 57.874 92.765 57.874 92.765C76.274 112.765 41.874 95.965 41.874 95.965C7.473 83.165 -16.527 108.765 -19.727 109.565C-22.927 110.365 -27.727 113.565 -28.527 107.165C-29.327 100.765 -35.786 85.405 -68.527 110.365C-98.418 132.929 -109.745 115.293 -109.745 115.293L-115.745 114.965C-129.346 88.564 -120.963 144.038 -120.963 144.038C-112.163 178.438 22.673 130.365 22.673 130.365C22.673 130.365 191.474 99.965 202.674 95.965C213.874 91.965 302.093 97.783 302.093 97.783L297.075 76.91C232.274 30.51 219.474 58.365 205.874 54.365C192.274 50.365 194.674 59.965 191.474 60.765C188.274 61.565 149.074 36.765 142.674 37.565z"/>
+ </g>
+ <g style="fill: #fae5d7">
+ <path d="M143.983 39.31C137.583 40.11 110.529 17.223 127.183 48.11C149.183 88.91 68.783 87.31 51.983 76.11C35.183 64.91 59.183 94.51 59.183 94.51C77.583 114.51 43.183 97.71 43.183 97.71C8.783 84.91 -15.217 110.51 -18.417 111.31C-21.618 112.11 -26.418 115.31 -27.218 108.91C-28.018 102.51 -34.346 87.318 -67.218 112.11C-98.345 135.42 -109.363 118.329 -109.363 118.329L-115.764 116.51C-128.764 92.51 -120.309 147.093 -120.309 147.093C-111.509 181.493 23.983 132.11 23.983 132.11C23.983 132.11 192.783 101.71 203.983 97.71C215.183 93.71 302.529 99.456 302.529 99.456L297.583 78.074C232.783 31.673 220.783 60.11 207.183 56.11C193.583 52.11 195.983 61.71 192.783 62.51C189.583 63.31 150.383 38.51 143.983 39.31z"/>
+ </g>
+ <g style="fill: #fcf2eb">
+ <path d="M145.292 41.055C138.892 41.855 112.917 18.411 128.492 49.855C149.692 92.656 70.092 89.056 53.292 77.856C36.492 66.656 60.492 96.256 60.492 96.256C78.892 116.256 44.492 99.456 44.492 99.456C10.092 86.656 -13.908 112.256 -17.108 113.056C-20.308 113.856 -25.108 117.056 -25.908 110.656C-26.708 104.256 -32.905 89.232 -65.908 113.856C-98.273 137.911 -108.982 121.365 -108.982 121.365L-115.782 118.056C-128.582 94.856 -119.654 150.147 -119.654 150.147C-110.854 184.547 25.292 133.856 25.292 133.856C25.292 133.856 194.093 103.456 205.293 99.456C216.493 95.456 302.965 101.128 302.965 101.128L298.093 79.237C233.292 32.837 222.093 61.856 208.493 57.856C194.893 53.855 197.293 63.456 194.093 64.256C190.892 65.056 151.692 40.255 145.292 41.055z"/>
+ </g>
+ <g style="fill: #ffffff">
+ <path d="M-115.8 119.601C-128.6 97.6 -119 153.201 -119 153.201C-110.2 187.601 26.6 135.601 26.6 135.601C26.6 135.601 195.401 105.2 206.601 101.2C217.801 97.2 303.401 102.8 303.401 102.8L298.601 80.4C233.801 34 223.401 63.6 209.801 59.6C196.201 55.6 198.601 65.2 195.401 66C192.201 66.8 153.001 42 146.601 42.8C140.201 43.6 114.981 19.793 129.801 51.6C152.028 99.307 69.041 89.227 54.6 79.6C37.8 68.4 61.8 98 61.8 98C80.2 118.001 45.8 101.2 45.8 101.2C11.4 88.4 -12.6 114.001 -15.8 114.801C-19 115.601 -23.8 118.801 -24.6 112.401C-25.4 106 -31.465 91.144 -64.6 115.601C-98.2 140.401 -108.6 124.401 -108.6 124.401L-115.8 119.601z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-74.2 149.601C-74.2 149.601 -81.4 161.201 -60.6 174.401C-60.6 174.401 -59.2 175.801 -77.2 171.601C-77.2 171.601 -83.4 169.601 -85 159.201C-85 159.201 -89.8 154.801 -94.6 149.201C-99.4 143.601 -74.2 149.601 -74.2 149.601z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M65.8 102C65.8 102 83.498 128.821 82.9 133.601C81.6 144.001 81.4 153.601 84.6 157.601C87.801 161.601 96.601 194.801 96.601 194.801C96.601 194.801 96.201 196.001 108.601 158.001C108.601 158.001 120.201 142.001 100.201 123.601C100.201 123.601 65 94.8 65.8 102z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-54.2 176.401C-54.2 176.401 -43 183.601 -57.4 214.801L-51 212.401C-51 212.401 -51.8 223.601 -55 226.001L-47.8 222.801C-47.8 222.801 -43 230.801 -47 235.601C-47 235.601 -30.2 243.601 -31 250.001C-31 250.001 -24.6 242.001 -28.6 235.601C-32.6 229.201 -39.8 233.201 -39 214.801L-47.8 218.001C-47.8 218.001 -42.2 209.201 -42.2 202.801L-50.2 205.201C-50.2 205.201 -34.731 178.623 -45.4 177.201C-51.4 176.401 -54.2 176.401 -54.2 176.401z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-21.8 193.201C-21.8 193.201 -19 188.801 -21.8 189.601C-24.6 190.401 -55.8 205.201 -61.8 214.801C-61.8 214.801 -27.4 190.401 -21.8 193.201z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-11.4 201.201C-11.4 201.201 -8.6 196.801 -11.4 197.601C-14.2 198.401 -45.4 213.201 -51.4 222.801C-51.4 222.801 -17 198.401 -11.4 201.201z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M1.8 186.001C1.8 186.001 4.6 181.601 1.8 182.401C-1 183.201 -32.2 198.001 -38.2 207.601C-38.2 207.601 -3.8 183.201 1.8 186.001z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-21.4 229.601C-21.4 229.601 -21.4 223.601 -24.2 224.401C-27 225.201 -63 242.801 -69 252.401C-69 252.401 -27 226.801 -21.4 229.601z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-20.2 218.801C-20.2 218.801 -19 214.001 -21.8 214.801C-23.8 214.801 -50.2 226.401 -56.2 236.001C-56.2 236.001 -26.6 214.401 -20.2 218.801z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-34.6 266.401L-44.6 274.001C-44.6 274.001 -34.2 266.401 -30.6 267.601C-30.6 267.601 -37.4 278.801 -38.2 284.001C-38.2 284.001 -27.8 271.201 -22.2 271.601C-22.2 271.601 -14.6 272.001 -14.6 282.801C-14.6 282.801 -9 272.401 -5.8 272.801C-5.8 272.801 -4.6 279.201 -5.8 286.001C-5.8 286.001 -1.8 278.401 2.2 280.001C2.2 280.001 8.6 278.001 7.8 289.601C7.8 289.601 7.8 300.001 7 302.801C7 302.801 12.6 276.401 15 276.001C15 276.001 23 274.801 27.8 283.601C27.8 283.601 23.8 276.001 28.6 278.001C28.6 278.001 39.4 279.601 42.6 286.401C42.6 286.401 35.8 274.401 41.4 277.601C41.4 277.601 48.2 277.601 49.4 284.001C49.4 284.001 57.8 305.201 59.8 306.801C59.8 306.801 52.2 285.201 53.8 285.201C53.8 285.201 51.8 273.201 57 288.001C57 288.001 53.8 274.001 59.4 274.801C65 275.601 69.4 285.601 77.8 283.201C77.8 283.201 87.401 288.801 89.401 219.601L-34.6 266.401z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-29.8 173.601C-29.8 173.601 -15 167.601 25 173.601C25 173.601 32.2 174.001 39 165.201C45.8 156.401 72.6 149.201 79 151.201L88.601 157.601L89.401 158.801C89.401 158.801 101.801 169.201 102.201 176.801C102.601 184.401 87.801 232.401 78.2 248.401C68.6 264.401 59 276.801 39.8 274.401C39.8 274.401 19 270.401 -6.6 274.401C-6.6 274.401 -35.8 272.801 -38.6 264.801C-41.4 256.801 -27.4 241.601 -27.4 241.601C-27.4 241.601 -23 233.201 -24.2 218.801C-25.4 204.401 -25 176.401 -29.8 173.601z"/>
+ </g>
+ <g style="fill: #e5668c">
+ <path d="M-7.8 175.601C0.6 194.001 -29 259.201 -29 259.201C-31 260.801 -16.34 266.846 -6.2 264.401C4.746 261.763 45 266.001 45 266.001C68.6 250.401 81.4 206.001 81.4 206.001C81.4 206.001 91.801 182.001 74.2 178.801C56.6 175.601 -7.8 175.601 -7.8 175.601z"/>
+ </g>
+ <g style="fill: #b23259">
+ <path d="M-9.831 206.497C-6.505 193.707 -4.921 181.906 -7.8 175.601C-7.8 175.601 54.6 182.001 65.8 161.201C70.041 153.326 84.801 184.001 84.4 193.601C84.4 193.601 21.4 208.001 6.6 196.801L-9.831 206.497z"/>
+ </g>
+ <g style="fill: #a5264c">
+ <path d="M-5.4 222.801C-5.4 222.801 -3.4 230.001 -5.8 234.001C-5.8 234.001 -7.4 234.801 -8.6 235.201C-8.6 235.201 -7.4 238.801 -1.4 240.401C-1.4 240.401 0.6 244.801 3 245.201C5.4 245.601 10.2 251.201 14.2 250.001C18.2 248.801 29.4 244.801 29.4 244.801C29.4 244.801 35 241.601 43.8 245.201C43.8 245.201 46.175 244.399 46.6 240.401C47.1 235.701 50.2 232.001 52.2 230.001C54.2 228.001 63.8 215.201 62.6 214.801C61.4 214.401 -5.4 222.801 -5.4 222.801z"/>
+ </g>
+ <g style="fill: #ff727f; stroke:#000000">
+ <path d="M-9.8 174.401C-9.8 174.401 -12.6 196.801 -9.4 205.201C-6.2 213.601 -7 215.601 -7.8 219.601C-8.6 223.601 -4.2 233.601 1.4 239.601L13.4 241.201C13.4 241.201 28.6 237.601 37.8 240.401C37.8 240.401 46.794 241.744 50.2 226.801C50.2 226.801 55 220.401 62.2 217.601C69.4 214.801 76.6 173.201 72.6 165.201C68.6 157.201 54.2 152.801 38.2 168.401C22.2 184.001 20.2 167.201 -9.8 174.401z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-8.2 249.201C-8.2 249.201 -9 247.201 -13.4 246.801C-13.4 246.801 -35.8 243.201 -44.2 230.801C-44.2 230.801 -51 225.201 -46.6 236.801C-46.6 236.801 -36.2 257.201 -29.4 260.001C-29.4 260.001 -13 264.001 -8.2 249.201z"/>
+ </g>
+ <g style="fill: #cc3f4c">
+ <path d="M71.742 185.229C72.401 177.323 74.354 168.709 72.6 165.201C66.154 152.307 49.181 157.695 38.2 168.401C22.2 184.001 20.2 167.201 -9.8 174.401C-9.8 174.401 -11.545 188.364 -10.705 198.376C-10.705 198.376 26.6 186.801 27.4 192.401C27.4 192.401 29 189.201 38.2 189.201C47.4 189.201 70.142 188.029 71.742 185.229z"/>
+ </g>
+ <g style="stroke:#a51926; stroke-width:2">
+ <path d="M28.6 175.201C28.6 175.201 33.4 180.001 29.8 189.601C29.8 189.601 15.4 205.601 17.4 219.601"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-19.4 260.001C-19.4 260.001 -23.8 247.201 -15 254.001C-15 254.001 -10.2 256.001 -11.4 257.601C-12.6 259.201 -18.2 263.201 -19.4 260.001z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-14.36 261.201C-14.36 261.201 -17.88 250.961 -10.84 256.401C-10.84 256.401 -6.419 258.849 -7.96 259.281C-12.52 260.561 -7.96 263.121 -14.36 261.201z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-9.56 261.201C-9.56 261.201 -13.08 250.961 -6.04 256.401C-6.04 256.401 -1.665 258.711 -3.16 259.281C-6.52 260.561 -3.16 263.121 -9.56 261.201z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-2.96 261.401C-2.96 261.401 -6.48 251.161 0.56 256.601C0.56 256.601 4.943 258.933 3.441 259.481C0.48 260.561 3.441 263.321 -2.96 261.401z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M3.52 261.321C3.52 261.321 0 251.081 7.041 256.521C7.041 256.521 10.881 258.121 9.921 259.401C8.961 260.681 9.921 263.241 3.52 261.321z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M10.2 262.001C10.2 262.001 5.4 249.601 14.6 256.001C14.6 256.001 19.4 258.001 18.2 259.601C17 261.201 18.2 264.401 10.2 262.001z"/>
+ </g>
+ <g style="stroke:#a5264c; stroke-width:2">
+ <path d="M-18.2 244.801C-18.2 244.801 -5 242.001 1 245.201C1 245.201 7 246.401 8.2 246.001C9.4 245.601 12.6 245.201 12.6 245.201"/>
+ </g>
+ <g style="stroke:#a5264c; stroke-width:2">
+ <path d="M15.8 253.601C15.8 253.601 27.8 240.001 39.8 244.401C46.816 246.974 45.8 243.601 46.6 240.801C47.4 238.001 47.6 233.801 52.6 230.801"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M33 237.601C33 237.601 29 226.801 26.2 239.601C23.4 252.401 20.2 256.001 18.6 258.801C18.6 258.801 18.6 264.001 27 263.601C27 263.601 37.8 263.201 38.2 260.401C38.6 257.601 37 246.001 33 237.601z"/>
+ </g>
+ <g style="stroke:#a5264c; stroke-width:2">
+ <path d="M47 244.801C47 244.801 50.6 242.401 53 243.601"/>
+ </g>
+ <g style="stroke:#a5264c; stroke-width:2">
+ <path d="M53.5 228.401C53.5 228.401 56.4 223.501 61.2 222.701"/>
+ </g>
+ <g style="fill: #b2b2b2">
+ <path d="M-25.8 265.201C-25.8 265.201 -7.8 268.401 -3.4 266.801C-3.4 266.801 5.4 266.801 -3 268.801C-3 268.801 -15.8 268.801 -23.8 267.601C-23.8 267.601 -35.4 262.001 -25.8 265.201z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-11.8 172.001C-11.8 172.001 5.8 172.001 7.8 172.801C7.8 172.801 15 203.601 11.4 211.201C11.4 211.201 10.2 214.001 7.4 208.401C7.4 208.401 -11 175.601 -14.2 173.601C-17.4 171.601 -13 172.001 -11.8 172.001z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-88.9 169.301C-88.9 169.301 -80 171.001 -67.4 173.601C-67.4 173.601 -62.6 196.001 -59.4 200.801C-56.2 205.601 -59.8 205.601 -63.4 202.801C-67 200.001 -81.8 186.001 -83.8 181.601C-85.8 177.201 -88.9 169.301 -88.9 169.301z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-67.039 173.818C-67.039 173.818 -61.239 175.366 -60.23 177.581C-59.222 179.795 -61.432 183.092 -61.432 183.092C-61.432 183.092 -62.432 186.397 -63.634 184.235C-64.836 182.072 -67.708 174.412 -67.039 173.818z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-67 173.601C-67 173.601 -63.4 178.801 -59.8 178.801C-56.2 178.801 -55.818 178.388 -53 179.001C-48.4 180.001 -48.8 178.001 -42.2 179.201C-39.56 179.681 -37 178.801 -34.2 180.001C-31.4 181.201 -28.2 180.401 -27 178.401C-25.8 176.401 -21 172.201 -21 172.201C-21 172.201 -33.8 174.001 -36.6 174.801C-36.6 174.801 -59 176.001 -67 173.601z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-22.4 173.801C-22.4 173.801 -28.85 177.301 -29.25 179.701C-29.65 182.101 -24 185.801 -24 185.801C-24 185.801 -21.25 190.401 -20.65 188.001C-20.05 185.601 -21.6 174.201 -22.4 173.801z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-59.885 179.265C-59.885 179.265 -52.878 190.453 -52.661 179.242C-52.661 179.242 -52.104 177.984 -53.864 177.962C-59.939 177.886 -58.418 173.784 -59.885 179.265z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-52.707 179.514C-52.707 179.514 -44.786 190.701 -45.422 179.421C-45.422 179.421 -45.415 179.089 -47.168 178.936C-51.915 178.522 -51.57 174.004 -52.707 179.514z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-45.494 179.522C-45.494 179.522 -37.534 190.15 -38.203 180.484C-38.203 180.484 -38.084 179.251 -39.738 178.95C-43.63 178.244 -43.841 174.995 -45.494 179.522z"/>
+ </g>
+ <g style="fill: #ffffcc; stroke:#000000; stroke-width:0.5">
+ <path d="M-38.618 179.602C-38.618 179.602 -30.718 191.163 -30.37 181.382C-30.37 181.382 -28.726 180.004 -30.472 179.782C-36.29 179.042 -35.492 174.588 -38.618 179.602z"/>
+ </g>
+ <g style="fill: #e5e5b2">
+ <path d="M-74.792 183.132L-82.45 181.601C-85.05 176.601 -87.15 170.451 -87.15 170.451C-87.15 170.451 -80.8 171.451 -68.3 174.251C-68.3 174.251 -67.424 177.569 -65.952 183.364L-74.792 183.132z"/>
+ </g>
+ <g style="fill: #e5e5b2">
+ <path d="M-9.724 178.47C-11.39 175.964 -12.707 174.206 -13.357 173.8C-16.37 171.917 -12.227 172.294 -11.098 172.294C-11.098 172.294 5.473 172.294 7.356 173.047C7.356 173.047 7.88 175.289 8.564 178.68C8.564 178.68 -1.524 176.67 -9.724 178.47z"/>
+ </g>
+ <g style="fill: #cc7226">
+ <path d="M43.88 40.321C71.601 44.281 97.121 8.641 98.881 -1.04C100.641 -10.72 90.521 -22.6 90.521 -22.6C91.841 -25.68 87.001 -39.76 81.721 -49C76.441 -58.24 60.54 -57.266 43 -58.24C27.16 -59.12 8.68 -35.8 7.36 -34.04C6.04 -32.28 12.2 6.001 13.52 11.721C14.84 17.441 12.2 43.841 12.2 43.841C46.44 34.741 16.16 36.361 43.88 40.321z"/>
+ </g>
+ <g style="fill: #ea8e51">
+ <path d="M8.088 -33.392C6.792 -31.664 12.84 5.921 14.136 11.537C15.432 17.153 12.84 43.073 12.84 43.073C45.512 34.193 16.728 35.729 43.944 39.617C71.161 43.505 96.217 8.513 97.945 -0.992C99.673 -10.496 89.737 -22.16 89.737 -22.16C91.033 -25.184 86.281 -39.008 81.097 -48.08C75.913 -57.152 60.302 -56.195 43.08 -57.152C27.528 -58.016 9.384 -35.12 8.088 -33.392z"/>
+ </g>
+ <g style="fill: #efaa7c">
+ <path d="M8.816 -32.744C7.544 -31.048 13.48 5.841 14.752 11.353C16.024 16.865 13.48 42.305 13.48 42.305C44.884 33.145 17.296 35.097 44.008 38.913C70.721 42.729 95.313 8.385 97.009 -0.944C98.705 -10.272 88.953 -21.72 88.953 -21.72C90.225 -24.688 85.561 -38.256 80.473 -47.16C75.385 -56.064 60.063 -55.125 43.16 -56.064C27.896 -56.912 10.088 -34.44 8.816 -32.744z"/>
+ </g>
+ <g style="fill: #f4c6a8">
+ <path d="M9.544 -32.096C8.296 -30.432 14.12 5.761 15.368 11.169C16.616 16.577 14.12 41.537 14.12 41.537C43.556 32.497 17.864 34.465 44.072 38.209C70.281 41.953 94.409 8.257 96.073 -0.895C97.737 -10.048 88.169 -21.28 88.169 -21.28C89.417 -24.192 84.841 -37.504 79.849 -46.24C74.857 -54.976 59.824 -54.055 43.24 -54.976C28.264 -55.808 10.792 -33.76 9.544 -32.096z"/>
+ </g>
+ <g style="fill: #f9e2d3">
+ <path d="M10.272 -31.448C9.048 -29.816 14.76 5.681 15.984 10.985C17.208 16.289 14.76 40.769 14.76 40.769C42.628 31.849 18.432 33.833 44.136 37.505C69.841 41.177 93.505 8.129 95.137 -0.848C96.769 -9.824 87.385 -20.84 87.385 -20.84C88.609 -23.696 84.121 -36.752 79.225 -45.32C74.329 -53.888 59.585 -52.985 43.32 -53.888C28.632 -54.704 11.496 -33.08 10.272 -31.448z"/>
+ </g>
+ <g style="fill: #ffffff">
+ <path d="M44.2 36.8C69.4 40.4 92.601 8 94.201 -0.8C95.801 -9.6 86.601 -20.4 86.601 -20.4C87.801 -23.2 83.4 -36 78.6 -44.4C73.8 -52.8 59.346 -51.914 43.4 -52.8C29 -53.6 12.2 -32.4 11 -30.8C9.8 -29.2 15.4 5.6 16.6 10.8C17.8 16 15.4 40 15.4 40C40.9 31.4 19 33.2 44.2 36.8z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M90.601 2.8C90.601 2.8 62.8 10.4 51.2 8.8C51.2 8.8 35.4 2.2 26.6 24C26.6 24 23 31.2 21 33.2C19 35.2 90.601 2.8 90.601 2.8z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M94.401 0.6C94.401 0.6 65.4 12.8 55.4 12.4C55.4 12.4 39 7.8 30.6 22.4C30.6 22.4 22.2 31.6 19 33.2C19 33.2 18.6 34.8 25 30.8L35.4 36C35.4 36 50.2 45.6 59.8 29.6C59.8 29.6 63.8 18.4 63.8 16.4C63.8 14.4 85 8.8 86.601 8.4C88.201 8 94.801 3.8 94.401 0.6z"/>
+ </g>
+ <g style="fill: #99cc32">
+ <path d="M47 36.514C40.128 36.514 31.755 32.649 31.755 26.4C31.755 20.152 40.128 13.887 47 13.887C53.874 13.887 59.446 18.952 59.446 25.2C59.446 31.449 53.874 36.514 47 36.514z"/>
+ </g>
+ <g style="fill: #659900">
+ <path d="M43.377 19.83C38.531 20.552 33.442 22.055 33.514 21.839C35.054 17.22 41.415 13.887 47 13.887C51.296 13.887 55.084 15.865 57.32 18.875C57.32 18.875 52.004 18.545 43.377 19.83z"/>
+ </g>
+ <g style="fill: #ffffff">
+ <path d="M55.4 19.6C55.4 19.6 51 16.4 51 18.6C51 18.6 54.6 23 55.4 19.6z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M45.4 27.726C42.901 27.726 40.875 25.7 40.875 23.2C40.875 20.701 42.901 18.675 45.4 18.675C47.9 18.675 49.926 20.701 49.926 23.2C49.926 25.7 47.9 27.726 45.4 27.726z"/>
+ </g>
+ <g style="fill: #cc7226">
+ <path d="M-58.6 14.4C-58.6 14.4 -61.8 -6.8 -59.4 -11.2C-59.4 -11.2 -48.6 -21.2 -49 -24.8C-49 -24.8 -49.4 -42.8 -50.6 -43.6C-51.8 -44.4 -59.4 -50.4 -65.4 -44C-65.4 -44 -75.8 -26 -75 -19.6L-75 -17.6C-75 -17.6 -82.6 -18 -84.2 -16C-84.2 -16 -85.4 -10.8 -86.6 -10.4C-86.6 -10.4 -89.4 -8 -87.4 -5.2C-87.4 -5.2 -89.4 -2.8 -89 1.2L-81.4 5.2C-81.4 5.2 -79.4 19.6 -68.6 24.8C-63.764 27.129 -60.6 20.4 -58.6 14.4z"/>
+ </g>
+ <g style="fill: #ffffff">
+ <path d="M-59.6 12.56C-59.6 12.56 -62.48 -6.52 -60.32 -10.48C-60.32 -10.48 -50.6 -19.48 -50.96 -22.72C-50.96 -22.72 -51.32 -38.92 -52.4 -39.64C-53.48 -40.36 -60.32 -45.76 -65.72 -40C-65.72 -40 -75.08 -23.8 -74.36 -18.04L-74.36 -16.24C-74.36 -16.24 -81.2 -16.6 -82.64 -14.8C-82.64 -14.8 -83.72 -10.12 -84.8 -9.76C-84.8 -9.76 -87.32 -7.6 -85.52 -5.08C-85.52 -5.08 -87.32 -2.92 -86.96 0.68L-80.12 4.28C-80.12 4.28 -78.32 17.24 -68.6 21.92C-64.248 24.015 -61.4 17.96 -59.6 12.56z"/>
+ </g>
+ <g style="fill: #eb955c">
+ <path d="M-51.05 -42.61C-52.14 -43.47 -59.63 -49.24 -65.48 -43C-65.48 -43 -75.62 -25.45 -74.84 -19.21L-74.84 -17.26C-74.84 -17.26 -82.25 -17.65 -83.81 -15.7C-83.81 -15.7 -84.98 -10.63 -86.15 -10.24C-86.15 -10.24 -88.88 -7.9 -86.93 -5.17C-86.93 -5.17 -88.88 -2.83 -88.49 1.07L-81.08 4.97C-81.08 4.97 -79.13 19.01 -68.6 24.08C-63.886 26.35 -60.8 19.79 -58.85 13.94C-58.85 13.94 -61.97 -6.73 -59.63 -11.02C-59.63 -11.02 -49.1 -20.77 -49.49 -24.28C-49.49 -24.28 -49.88 -41.83 -51.05 -42.61z"/>
+ </g>
+ <g style="fill: #f2b892">
+ <path d="M-51.5 -41.62C-52.48 -42.54 -59.86 -48.08 -65.56 -42C-65.56 -42 -75.44 -24.9 -74.68 -18.82L-74.68 -16.92C-74.68 -16.92 -81.9 -17.3 -83.42 -15.4C-83.42 -15.4 -84.56 -10.46 -85.7 -10.08C-85.7 -10.08 -88.36 -7.8 -86.46 -5.14C-86.46 -5.14 -88.36 -2.86 -87.98 0.94L-80.76 4.74C-80.76 4.74 -78.86 18.42 -68.6 23.36C-64.006 25.572 -61 19.18 -59.1 13.48C-59.1 13.48 -62.14 -6.66 -59.86 -10.84C-59.86 -10.84 -49.6 -20.34 -49.98 -23.76C-49.98 -23.76 -50.36 -40.86 -51.5 -41.62z"/>
+ </g>
+ <g style="fill: #f8dcc8">
+ <path d="M-51.95 -40.63C-52.82 -41.61 -60.09 -46.92 -65.64 -41C-65.64 -41 -75.26 -24.35 -74.52 -18.43L-74.52 -16.58C-74.52 -16.58 -81.55 -16.95 -83.03 -15.1C-83.03 -15.1 -84.14 -10.29 -85.25 -9.92C-85.25 -9.92 -87.84 -7.7 -85.99 -5.11C-85.99 -5.11 -87.84 -2.89 -87.47 0.81L-80.44 4.51C-80.44 4.51 -78.59 17.83 -68.6 22.64C-64.127 24.794 -61.2 18.57 -59.35 13.02C-59.35 13.02 -62.31 -6.59 -60.09 -10.66C-60.09 -10.66 -50.1 -19.91 -50.47 -23.24C-50.47 -23.24 -50.84 -39.89 -51.95 -40.63z"/>
+ </g>
+ <g style="fill: #ffffff">
+ <path d="M-59.6 12.46C-59.6 12.46 -62.48 -6.52 -60.32 -10.48C-60.32 -10.48 -50.6 -19.48 -50.96 -22.72C-50.96 -22.72 -51.32 -38.92 -52.4 -39.64C-53.16 -40.68 -60.32 -45.76 -65.72 -40C-65.72 -40 -75.08 -23.8 -74.36 -18.04L-74.36 -16.24C-74.36 -16.24 -81.2 -16.6 -82.64 -14.8C-82.64 -14.8 -83.72 -10.12 -84.8 -9.76C-84.8 -9.76 -87.32 -7.6 -85.52 -5.08C-85.52 -5.08 -87.32 -2.92 -86.96 0.68L-80.12 4.28C-80.12 4.28 -78.32 17.24 -68.6 21.92C-64.248 24.015 -61.4 17.86 -59.6 12.46z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-62.7 6.2C-62.7 6.2 -84.3 -4 -85.2 -4.8C-85.2 -4.8 -76.1 3.4 -75.3 3.4C-74.5 3.4 -62.7 6.2 -62.7 6.2z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-79.8 0C-79.8 0 -61.4 3.6 -61.4 8C-61.4 10.912 -61.643 24.331 -67 22.8C-75.4 20.4 -71.8 6 -79.8 0z"/>
+ </g>
+ <g style="fill: #99cc32">
+ <path d="M-71.4 3.8C-71.4 3.8 -62.422 5.274 -61.4 8C-60.8 9.6 -60.137 17.908 -65.6 19C-70.152 19.911 -72.382 9.69 -71.4 3.8z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M14.595 46.349C14.098 44.607 15.409 44.738 17.2 44.2C19.2 43.6 31.4 39.8 32.2 37.2C33 34.6 46.2 39 46.2 39C48 39.8 52.4 42.4 52.4 42.4C57.2 43.6 63.8 44 63.8 44C66.2 45 69.6 47.8 69.6 47.8C84.2 58 96.601 50.8 96.601 50.8C116.601 44.2 110.601 27 110.601 27C107.601 18 110.801 14.6 110.801 14.6C111.001 10.8 118.201 17.2 118.201 17.2C120.801 21.4 121.601 26.4 121.601 26.4C129.601 37.6 126.201 19.8 126.201 19.8C126.401 18.8 123.601 15.2 123.601 14C123.601 12.8 121.801 9.4 121.801 9.4C118.801 6 121.201 -1 121.201 -1C123.001 -14.8 120.801 -13 120.801 -13C119.601 -14.8 110.401 -4.8 110.401 -4.8C108.201 -1.4 102.201 0.2 102.201 0.2C99.401 2 96.001 0.6 96.001 0.6C93.401 0.2 87.801 7.2 87.801 7.2C90.601 7 93.001 11.4 95.401 11.6C97.801 11.8 99.601 9.2 101.201 8.6C102.801 8 105.601 13.8 105.601 13.8C106.001 16.4 100.401 21.2 100.401 21.2C100.001 25.8 98.401 24.2 98.401 24.2C95.401 23.6 94.201 27.4 93.201 32C92.201 36.6 88.001 37 88.001 37C86.401 44.4 85.2 41.4 85.2 41.4C85 35.8 79 41.6 79 41.6C77.8 43.6 73.2 41.4 73.2 41.4C66.4 39.4 68.8 37.4 68.8 37.4C70.6 35.2 81.8 37.4 81.8 37.4C84 35.8 76 31.8 76 31.8C75.4 30 76.4 25.6 76.4 25.6C77.6 22.4 84.4 16.8 84.4 16.8C93.801 15.6 91.001 14 91.001 14C84.801 8.8 79 16.4 79 16.4C76.8 22.6 59.4 37.6 59.4 37.6C54.6 41 57.2 34.2 53.2 37.6C49.2 41 28.6 32 28.6 32C17.038 30.807 14.306 46.549 10.777 43.429C10.777 43.429 16.195 51.949 14.595 46.349z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M209.401 -120C209.401 -120 183.801 -112 181.001 -93.2C181.001 -93.2 178.601 -70.4 199.001 -52.8C199.001 -52.8 199.401 -46.4 201.401 -43.2C201.401 -43.2 199.801 -38.4 218.601 -46L245.801 -54.4C245.801 -54.4 252.201 -56.8 257.401 -65.6C262.601 -74.4 277.801 -93.2 274.201 -118.4C274.201 -118.4 275.401 -129.6 269.401 -130C269.401 -130 261.001 -131.6 253.801 -124C253.801 -124 247.001 -120.8 244.601 -121.2L209.401 -120z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M264.022 -120.99C264.022 -120.99 266.122 -129.92 261.282 -125.08C261.282 -125.08 254.242 -119.36 246.761 -119.36C246.761 -119.36 232.241 -117.16 227.841 -103.96C227.841 -103.96 223.881 -77.12 231.801 -71.4C231.801 -71.4 236.641 -63.92 243.681 -70.52C250.722 -77.12 266.222 -107.35 264.022 -120.99z"/>
+ </g>
+ <g style="fill: #323232">
+ <path d="M263.648 -120.632C263.648 -120.632 265.738 -129.376 260.986 -124.624C260.986 -124.624 254.074 -119.008 246.729 -119.008C246.729 -119.008 232.473 -116.848 228.153 -103.888C228.153 -103.888 224.265 -77.536 232.041 -71.92C232.041 -71.92 236.793 -64.576 243.705 -71.056C250.618 -77.536 265.808 -107.24 263.648 -120.632z"/>
+ </g>
+ <g style="fill: #666666">
+ <path d="M263.274 -120.274C263.274 -120.274 265.354 -128.832 260.69 -124.168C260.69 -124.168 253.906 -118.656 246.697 -118.656C246.697 -118.656 232.705 -116.536 228.465 -103.816C228.465 -103.816 224.649 -77.952 232.281 -72.44C232.281 -72.44 236.945 -65.232 243.729 -71.592C250.514 -77.952 265.394 -107.13 263.274 -120.274z"/>
+ </g>
+ <g style="fill: #999999">
+ <path d="M262.9 -119.916C262.9 -119.916 264.97 -128.288 260.394 -123.712C260.394 -123.712 253.738 -118.304 246.665 -118.304C246.665 -118.304 232.937 -116.224 228.777 -103.744C228.777 -103.744 225.033 -78.368 232.521 -72.96C232.521 -72.96 237.097 -65.888 243.753 -72.128C250.41 -78.368 264.98 -107.02 262.9 -119.916z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M262.526 -119.558C262.526 -119.558 264.586 -127.744 260.098 -123.256C260.098 -123.256 253.569 -117.952 246.633 -117.952C246.633 -117.952 233.169 -115.912 229.089 -103.672C229.089 -103.672 225.417 -78.784 232.761 -73.48C232.761 -73.48 237.249 -66.544 243.777 -72.664C250.305 -78.784 264.566 -106.91 262.526 -119.558z"/>
+ </g>
+ <g style="fill: #ffffff">
+ <path d="M262.151 -119.2C262.151 -119.2 264.201 -127.2 259.801 -122.8C259.801 -122.8 253.401 -117.6 246.601 -117.6C246.601 -117.6 233.401 -115.6 229.401 -103.6C229.401 -103.6 225.801 -79.2 233.001 -74C233.001 -74 237.401 -67.2 243.801 -73.2C250.201 -79.2 264.151 -106.8 262.151 -119.2z"/>
+ </g>
+ <g style="fill: #992600">
+ <path d="M50.6 84C50.6 84 30.2 64.8 22.2 64C22.2 64 -12.2 60 -27 78C-27 78 -9.4 57.6 18.2 63.2C18.2 63.2 -3.4 58.8 -15.8 62C-15.8 62 -32.6 62 -42.2 76L-45 80.8C-45 80.8 -41 66 -22.6 60C-22.6 60 0.2 55.2 11 60C11 60 -10.6 53.2 -20.6 55.2C-20.6 55.2 -51 52.8 -63.8 79.2C-63.8 79.2 -59.8 64.8 -45 57.6C-45 57.6 -31.4 48.8 -11 51.6C-11 51.6 3.4 54.8 8.6 57.2C13.8 59.6 12.6 56.8 4.2 52C4.2 52 -1.4 42 -15.4 42.4C-15.4 42.4 -58.2 46 -68.6 58C-68.6 58 -55 46.8 -44.6 44C-44.6 44 -22.2 36 -13.8 36.8C-13.8 36.8 11 37.8 18.6 33.8C18.6 33.8 7.4 38.8 10.6 42C13.8 45.2 20.6 52.8 20.6 54C20.6 55.2 44.8 77.3 48.4 81.7L50.6 84z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M189 278C189 278 173.5 241.5 161 232C161 232 187 248 190.5 266C190.5 266 190.5 276 189 278z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M236 285.5C236 285.5 209.5 230.5 191 206.5C191 206.5 234.5 244 239.5 270.5L240 276L237 273.5C237 273.5 236.5 282.5 236 285.5z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M292.5 237C292.5 237 230 177.5 228.5 175C228.5 175 289 241 292 248.5C292 248.5 290 239.5 292.5 237z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M104 280.5C104 280.5 123.5 228.5 142.5 251C142.5 251 157.5 261 157 264C157 264 153 257.5 135 258C135 258 116 255 104 280.5z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M294.5 153C294.5 153 249.5 124.5 242 123C230.193 120.639 291.5 152 296.5 162.5C296.5 162.5 298.5 160 294.5 153z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M143.801 259.601C143.801 259.601 164.201 257.601 171.001 250.801L175.401 254.401L193.001 216.001L196.601 221.201C196.601 221.201 211.001 206.401 210.201 198.401C209.401 190.401 223.001 204.401 223.001 204.401C223.001 204.401 222.201 192.801 229.401 199.601C229.401 199.601 227.001 184.001 235.401 192.001C235.401 192.001 224.864 161.844 247.401 187.601C253.001 194.001 248.601 187.201 248.601 187.201C248.601 187.201 222.601 139.201 244.201 153.601C244.201 153.601 246.201 130.801 245.001 126.401C243.801 122.001 241.801 99.6 237.001 94.4C232.201 89.2 237.401 87.6 243.001 92.8C243.001 92.8 231.801 68.8 245.001 80.8C245.001 80.8 241.401 65.6 237.001 62.8C237.001 62.8 231.401 45.6 246.601 56.4C246.601 56.4 242.201 44 239.001 40.8C239.001 40.8 227.401 13.2 234.601 18L239.001 21.6C239.001 21.6 232.201 7.6 238.601 12C245.001 16.4 245.001 16 245.001 16C245.001 16 223.801 -17.2 244.201 0.4C244.201 0.4 236.042 -13.518 232.601 -20.4C232.601 -20.4 213.801 -40.8 228.201 -34.4L233.001 -32.8C233.001 -32.8 224.201 -42.8 216.201 -44.4C208.201 -46 218.601 -52.4 225.001 -50.4C231.401 -48.4 247.001 -40.8 247.001 -40.8C247.001 -40.8 259.801 -22 263.801 -21.6C263.801 -21.6 243.801 -29.2 249.801 -21.2C249.801 -21.2 264.201 -7.2 257.001 -7.6C257.001 -7.6 251.001 -0.4 255.801 8.4C255.801 8.4 237.342 -9.991 252.201 15.6L259.001 32C259.001 32 234.601 7.2 245.801 29.2C245.801 29.2 263.001 52.8 265.001 53.2C267.001 53.6 271.401 62.4 271.401 62.4L267.001 60.4L272.201 69.2C272.201 69.2 261.001 57.2 267.001 70.4L272.601 84.8C272.601 84.8 252.201 62.8 265.801 92.4C265.801 92.4 249.401 87.2 258.201 104.4C258.201 104.4 256.601 120.401 257.001 125.601C257.401 130.801 258.601 159.201 254.201 167.201C249.801 175.201 260.201 194.401 262.201 198.401C264.201 202.401 267.801 213.201 259.001 204.001C250.201 194.801 254.601 200.401 256.601 209.201C258.601 218.001 264.601 233.601 263.801 239.201C263.801 239.201 262.601 240.401 259.401 236.801C259.401 236.801 244.601 214.001 246.201 228.401C246.201 228.401 245.001 236.401 241.801 245.201C241.801 245.201 238.601 256.001 238.601 247.201C238.601 247.201 235.401 230.401 232.601 238.001C229.801 245.601 226.201 251.601 223.401 254.001C220.601 256.401 215.401 233.601 214.201 244.001C214.201 244.001 202.201 231.601 197.401 248.001L185.801 264.401C185.801 264.401 185.401 252.001 184.201 258.001C184.201 258.001 154.201 264.001 143.801 259.601z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M109.401 -97.2C109.401 -97.2 97.801 -105.2 93.801 -104.8C89.801 -104.4 121.401 -113.6 162.601 -86C162.601 -86 167.401 -83.2 171.001 -83.6C171.001 -83.6 174.201 -81.2 171.401 -77.6C171.401 -77.6 162.601 -68 173.801 -56.8C173.801 -56.8 192.201 -50 186.601 -58.8C186.601 -58.8 197.401 -54.8 199.801 -50.8C202.201 -46.8 201.001 -50.8 201.001 -50.8C201.001 -50.8 194.601 -58 188.601 -63.2C188.601 -63.2 183.401 -65.2 180.601 -73.6C177.801 -82 175.401 -92 179.801 -95.2C179.801 -95.2 175.801 -90.8 176.601 -94.8C177.401 -98.8 181.001 -102.4 182.601 -102.8C184.201 -103.2 200.601 -119 207.401 -119.4C207.401 -119.4 198.201 -118 195.201 -119C192.201 -120 165.601 -131.4 159.601 -132.6C159.601 -132.6 142.801 -139.2 154.801 -137.2C154.801 -137.2 190.601 -133.4 208.801 -120.2C208.801 -120.2 201.601 -128.6 183.201 -135.6C183.201 -135.6 161.001 -148.2 125.801 -143.2C125.801 -143.2 108.001 -140 100.201 -138.2C100.201 -138.2 97.601 -138.8 97.001 -139.2C96.401 -139.6 84.6 -148.6 57 -141.6C57 -141.6 40 -137 31.4 -132.2C31.4 -132.2 16.2 -131 12.6 -127.8C12.6 -127.8 -6 -113.2 -8 -112.4C-10 -111.6 -21.4 -104 -22.2 -103.6C-22.2 -103.6 2.4 -110.2 4.8 -112.6C7.2 -115 24.6 -117.6 27 -116.2C29.4 -114.8 37.8 -115.4 28.2 -114.8C28.2 -114.8 103.801 -100 104.601 -98C105.401 -96 109.401 -97.2 109.401 -97.2z"/>
+ </g>
+ <g style="fill: #cc7226">
+ <path d="M180.801 -106.4C180.801 -106.4 170.601 -113.8 168.601 -113.8C166.601 -113.8 154.201 -124 150.001 -123.6C145.801 -123.2 133.601 -133.2 106.201 -125C106.201 -125 105.601 -127 109.201 -127.8C109.201 -127.8 115.601 -130 116.001 -130.6C116.001 -130.6 136.201 -134.8 143.401 -131.2C143.401 -131.2 152.601 -128.6 158.801 -122.4C158.801 -122.4 170.001 -119.2 173.201 -120.2C173.201 -120.2 182.001 -118 182.401 -116.2C182.401 -116.2 188.201 -113.2 186.401 -110.6C186.401 -110.6 186.801 -109 180.801 -106.4z"/>
+ </g>
+ <g style="fill: #cc7226">
+ <path d="M168.33 -108.509C169.137 -107.877 170.156 -107.779 170.761 -106.97C170.995 -106.656 170.706 -106.33 170.391 -106.233C169.348 -105.916 168.292 -106.486 167.15 -105.898C166.748 -105.691 166.106 -105.873 165.553 -106.022C163.921 -106.463 162.092 -106.488 160.401 -105.8C158.416 -106.929 156.056 -106.345 153.975 -107.346C153.917 -107.373 153.695 -107.027 153.621 -107.054C150.575 -108.199 146.832 -107.916 144.401 -110.2C141.973 -110.612 139.616 -111.074 137.188 -111.754C135.37 -112.263 133.961 -113.252 132.341 -114.084C130.964 -114.792 129.507 -115.314 127.973 -115.686C126.11 -116.138 124.279 -116.026 122.386 -116.546C122.293 -116.571 122.101 -116.227 122.019 -116.254C121.695 -116.362 121.405 -116.945 121.234 -116.892C119.553 -116.37 118.065 -117.342 116.401 -117C115.223 -118.224 113.495 -117.979 111.949 -118.421C108.985 -119.269 105.831 -117.999 102.801 -119C106.914 -120.842 111.601 -119.61 115.663 -121.679C117.991 -122.865 120.653 -121.763 123.223 -122.523C123.71 -122.667 124.401 -122.869 124.801 -122.2C124.935 -122.335 125.117 -122.574 125.175 -122.546C127.625 -121.389 129.94 -120.115 132.422 -119.049C132.763 -118.903 133.295 -119.135 133.547 -118.933C135.067 -117.717 137.01 -117.82 138.401 -116.6C140.099 -117.102 141.892 -116.722 143.621 -117.346C143.698 -117.373 143.932 -117.032 143.965 -117.054C145.095 -117.802 146.25 -117.531 147.142 -117.227C147.48 -117.112 148.143 -116.865 148.448 -116.791C149.574 -116.515 150.43 -116.035 151.609 -115.852C151.723 -115.834 151.908 -116.174 151.98 -116.146C153.103 -115.708 154.145 -115.764 154.801 -114.6C154.936 -114.735 155.101 -114.973 155.183 -114.946C156.21 -114.608 156.859 -113.853 157.96 -113.612C158.445 -113.506 159.057 -112.88 159.633 -112.704C162.025 -111.973 163.868 -110.444 166.062 -109.549C166.821 -109.239 167.697 -109.005 168.33 -108.509z"/>
+ </g>
+ <g style="fill: #cc7226">
+ <path d="M91.696 -122.739C89.178 -124.464 86.81 -125.57 84.368 -127.356C84.187 -127.489 83.827 -127.319 83.625 -127.441C82.618 -128.05 81.73 -128.631 80.748 -129.327C80.209 -129.709 79.388 -129.698 78.88 -129.956C76.336 -131.248 73.707 -131.806 71.2 -133C71.882 -133.638 73.004 -133.394 73.6 -134.2C73.795 -133.92 74.033 -133.636 74.386 -133.827C76.064 -134.731 77.914 -134.884 79.59 -134.794C81.294 -134.702 83.014 -134.397 84.789 -134.125C85.096 -134.078 85.295 -133.555 85.618 -133.458C87.846 -132.795 90.235 -133.32 92.354 -132.482C93.945 -131.853 95.515 -131.03 96.754 -129.755C97.006 -129.495 96.681 -129.194 96.401 -129C96.789 -129.109 97.062 -128.903 97.173 -128.59C97.257 -128.351 97.257 -128.049 97.173 -127.81C97.061 -127.498 96.782 -127.397 96.408 -127.346C95.001 -127.156 96.773 -128.536 96.073 -128.088C94.8 -127.274 95.546 -125.868 94.801 -124.6C94.521 -124.794 94.291 -125.012 94.401 -125.4C94.635 -124.878 94.033 -124.588 93.865 -124.272C93.48 -123.547 92.581 -122.132 91.696 -122.739z"/>
+ </g>
+ <g style="fill: #cc7226">
+ <path d="M59.198 -115.391C56.044 -116.185 52.994 -116.07 49.978 -117.346C49.911 -117.374 49.688 -117.027 49.624 -117.054C48.258 -117.648 47.34 -118.614 46.264 -119.66C45.351 -120.548 43.693 -120.161 42.419 -120.648C42.095 -120.772 41.892 -121.284 41.591 -121.323C40.372 -121.48 39.445 -122.429 38.4 -123C40.736 -123.795 43.147 -123.764 45.609 -124.148C45.722 -124.166 45.867 -123.845 46 -123.845C46.136 -123.845 46.266 -124.066 46.4 -124.2C46.595 -123.92 46.897 -123.594 47.154 -123.848C47.702 -124.388 48.258 -124.198 48.798 -124.158C48.942 -124.148 49.067 -123.845 49.2 -123.845C49.336 -123.845 49.467 -124.156 49.6 -124.156C49.736 -124.155 49.867 -123.845 50 -123.845C50.136 -123.845 50.266 -124.066 50.4 -124.2C51.092 -123.418 51.977 -123.972 52.799 -123.793C53.837 -123.566 54.104 -122.418 55.178 -122.12C59.893 -120.816 64.03 -118.671 68.393 -116.584C68.7 -116.437 68.91 -116.189 68.8 -115.8C69.067 -115.8 69.38 -115.888 69.57 -115.756C70.628 -115.024 71.669 -114.476 72.366 -113.378C72.582 -113.039 72.253 -112.632 72.02 -112.684C67.591 -113.679 63.585 -114.287 59.198 -115.391z"/>
+ </g>
+ <g style="fill: #cc7226">
+ <path d="M45.338 -71.179C43.746 -72.398 43.162 -74.429 42.034 -76.221C41.82 -76.561 42.094 -76.875 42.411 -76.964C42.971 -77.123 43.514 -76.645 43.923 -76.443C45.668 -75.581 47.203 -74.339 49.2 -74.2C51.19 -71.966 55.45 -71.581 55.457 -68.2C55.458 -67.341 54.03 -68.259 53.6 -67.4C51.149 -68.403 48.76 -68.3 46.38 -69.767C45.763 -70.148 46.093 -70.601 45.338 -71.179z"/>
+ </g>
+ <g style="fill: #cc7226">
+ <path d="M17.8 -123.756C17.935 -123.755 24.966 -123.522 24.949 -123.408C24.904 -123.099 17.174 -122.05 16.81 -122.22C16.646 -122.296 9.134 -119.866 9 -120C9.268 -120.135 17.534 -123.756 17.8 -123.756z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M33.2 -114C33.2 -114 18.4 -112.2 14 -111C9.6 -109.8 -9 -102.2 -12 -100.2C-12 -100.2 -25.4 -94.8 -42.4 -74.8C-42.4 -74.8 -34.8 -78.2 -32.6 -81C-32.6 -81 -19 -93.6 -19.2 -91C-19.2 -91 -7 -99.6 -7.6 -97.4C-7.6 -97.4 16.8 -108.6 14.8 -105.4C14.8 -105.4 36.4 -110 35.4 -108C35.4 -108 54.2 -103.6 51.4 -103.4C51.4 -103.4 45.6 -102.2 52 -98.6C52 -98.6 48.6 -94.2 43.2 -98.2C37.8 -102.2 40.8 -100 35.8 -99C35.8 -99 33.2 -98.2 28.6 -102.2C28.6 -102.2 23 -106.8 14.2 -103.2C14.2 -103.2 -16.4 -90.6 -18.4 -90C-18.4 -90 -22 -87.2 -24.4 -83.6C-24.4 -83.6 -30.2 -79.2 -33.2 -77.8C-33.2 -77.8 -46 -66.2 -47.2 -64.8C-47.2 -64.8 -50.6 -59.6 -51.4 -59.2C-51.4 -59.2 -45 -63 -43 -65C-43 -65 -29 -75 -23.6 -75.8C-23.6 -75.8 -19.2 -78.8 -18.4 -80.2C-18.4 -80.2 -4 -89.4 0.2 -89.4C0.2 -89.4 9.4 -84.2 11.8 -91.2C11.8 -91.2 17.6 -93 23.2 -91.8C23.2 -91.8 26.4 -94.4 25.6 -96.6C25.6 -96.6 27.2 -98.4 28.2 -94.6C28.2 -94.6 31.6 -91 36.4 -93C36.4 -93 40.4 -93.2 38.4 -90.8C38.4 -90.8 34 -87 22.2 -86.8C22.2 -86.8 9.8 -86.2 -6.6 -78.6C-6.6 -78.6 -36.4 -68.2 -45.6 -57.8C-45.6 -57.8 -52 -49 -57.4 -47.8C-57.4 -47.8 -63.2 -47 -69.2 -39.6C-69.2 -39.6 -59.4 -45.4 -50.4 -45.4C-50.4 -45.4 -46.4 -47.8 -50.2 -44.2C-50.2 -44.2 -53.8 -36.6 -52.2 -31.2C-52.2 -31.2 -52.8 -26 -53.6 -24.4C-53.6 -24.4 -61.4 -11.6 -61.4 -9.2C-61.4 -6.8 -60.2 3 -59.8 3.6C-59.4 4.2 -60.8 2 -57 4.4C-53.2 6.8 -50.4 8.4 -49.6 11.2C-48.8 14 -51.6 5.8 -51.8 4C-52 2.2 -56.2 -5 -55.4 -7.4C-55.4 -7.4 -54.4 -6.4 -53.6 -5C-53.6 -5 -54.2 -5.6 -53.6 -9.2C-53.6 -9.2 -52.8 -14.4 -51.4 -17.6C-50 -20.8 -48 -24.6 -47.6 -25.4C-47.2 -26.2 -47.2 -32 -45.8 -29.4L-42.4 -26.8C-42.4 -26.8 -45.2 -29.4 -43 -31.6C-43 -31.6 -44 -37.2 -42.2 -39.8C-42.2 -39.8 -35.2 -48.2 -33.6 -49.2C-32 -50.2 -33.4 -49.8 -33.4 -49.8C-33.4 -49.8 -27.4 -54 -33.2 -52.4C-33.2 -52.4 -37.2 -50.8 -40.2 -50.8C-40.2 -50.8 -47.8 -48.8 -43.8 -53C-39.8 -57.2 -29.8 -62.6 -26 -62.4L-25.2 -60.8L-14 -63.2L-15.2 -62.4C-15.2 -62.4 -15.4 -62.6 -11.2 -63C-7 -63.4 -1.2 -62 0.2 -63.8C1.6 -65.6 5 -66.6 4.6 -65.2C4.2 -63.8 4 -61.8 4 -61.8C4 -61.8 9 -67.6 8.4 -65.4C7.8 -63.2 -0.4 -58 -1.8 -51.8L8.6 -60L12.2 -63C12.2 -63 15.8 -60.8 16 -62.4C16.2 -64 20.8 -69.8 22 -69.6C23.2 -69.4 25.2 -72.2 25 -69.6C24.8 -67 32.4 -61.6 32.4 -61.6C32.4 -61.6 35.6 -63.4 37 -62C38.4 -60.6 42.6 -81.8 42.6 -81.8L67.6 -92.4L111.201 -95.8L94.201 -102.6L33.2 -114z"/>
+ </g>
+ <g style="stroke:#4c0000; stroke-width:2">
+ <path d="M51.4 85C51.4 85 36.4 68.2 28 65.6C28 65.6 14.6 58.8 -10 66.6"/>
+ </g>
+ <g style="stroke:#4c0000; stroke-width:2">
+ <path d="M24.8 64.2C24.8 64.2 -0.4 56.2 -15.8 60.4C-15.8 60.4 -34.2 62.4 -42.6 76.2"/>
+ </g>
+ <g style="stroke:#4c0000; stroke-width:2">
+ <path d="M21.2 63C21.2 63 4.2 55.8 -10.6 53.6C-10.6 53.6 -27.2 51 -43.8 58.2C-43.8 58.2 -56 64.2 -61.4 74.4"/>
+ </g>
+ <g style="stroke:#4c0000; stroke-width:2">
+ <path d="M22.2 63.4C22.2 63.4 6.8 52.4 5.8 51C5.8 51 -1.2 40 -14.2 39.6C-14.2 39.6 -35.6 40.4 -52.8 48.4"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M20.895 54.407C22.437 55.87 49.4 84.8 49.4 84.8C84.6 121.401 56.6 87.2 56.6 87.2C49 82.4 39.8 63.6 39.8 63.6C38.6 60.8 53.8 70.8 53.8 70.8C57.8 71.6 71.4 90.8 71.4 90.8C64.6 88.4 69.4 95.6 69.4 95.6C72.2 97.6 92.601 113.201 92.601 113.201C96.201 117.201 100.201 118.801 100.201 118.801C114.201 113.601 107.801 126.801 107.801 126.801C110.201 133.601 115.801 122.001 115.801 122.001C127.001 105.2 110.601 107.601 110.601 107.601C80.6 110.401 73.8 94.4 73.8 94.4C71.4 92 80.2 94.4 80.2 94.4C88.601 96.4 73 82 73 82C75.4 82 84.6 88.8 84.6 88.8C95.001 98 97.001 96 97.001 96C115.001 87.2 125.401 94.8 125.401 94.8C127.401 96.4 121.801 103.2 123.401 108.401C125.001 113.601 129.801 126.001 129.801 126.001C127.401 127.601 127.801 138.401 127.801 138.401C144.601 161.601 135.001 159.601 135.001 159.601C119.401 159.201 134.201 166.801 134.201 166.801C137.401 168.801 146.201 176.001 146.201 176.001C143.401 174.801 141.801 180.001 141.801 180.001C146.601 184.001 143.801 188.801 143.801 188.801C137.801 190.001 136.601 194.001 136.601 194.001C143.401 202.001 133.401 202.401 133.401 202.401C137.001 206.801 132.201 218.801 132.201 218.801C127.401 218.801 121.001 224.401 121.001 224.401C123.401 229.201 113.001 234.801 113.001 234.801C104.601 236.401 107.401 243.201 107.401 243.201C99.401 249.201 97.001 265.201 97.001 265.201C96.201 275.601 93.801 278.801 99.001 276.801C104.201 274.801 103.401 262.401 103.401 262.401C98.601 246.801 141.401 230.801 141.401 230.801C145.401 229.201 146.201 224.001 146.201 224.001C148.201 224.401 157.001 232.001 157.001 232.001C164.601 243.201 165.001 234.001 165.001 234.001C166.201 230.401 164.601 224.401 164.601 224.401C170.601 202.801 156.601 196.401 156.601 196.401C146.601 162.801 160.601 171.201 160.601 171.201C163.401 176.801 174.201 182.001 174.201 182.001L177.801 179.601C176.201 174.801 184.601 168.801 184.601 168.801C187.401 175.201 193.401 167.201 193.401 167.201C197.001 142.801 209.401 157.201 209.401 157.201C213.401 158.401 214.601 151.601 214.601 151.601C218.201 141.201 214.601 127.601 214.601 127.601C218.201 127.201 227.801 133.201 227.801 133.201C230.601 129.601 221.401 112.801 225.401 115.201C229.401 117.601 233.801 119.201 233.801 119.201C234.601 117.201 224.601 104.801 224.601 104.801C220.201 102 215.001 81.6 215.001 81.6C222.201 85.2 212.201 70 212.201 70C212.201 66.8 218.201 55.6 218.201 55.6C217.401 48.8 218.201 49.2 218.201 49.2C221.001 50.4 229.001 52 222.201 45.6C215.401 39.2 223.001 34.4 223.001 34.4C227.401 31.6 213.801 32 213.801 32C208.601 27.6 209.001 23.6 209.001 23.6C217.001 25.6 202.601 11.2 200.201 7.6C197.801 4 207.401 -1.2 207.401 -1.2C220.601 -4.8 209.001 -8 209.001 -8C189.401 -7.6 200.201 -18.4 200.201 -18.4C206.201 -18 204.601 -20.4 204.601 -20.4C199.401 -21.6 189.801 -28 189.801 -28C185.801 -31.6 189.401 -30.8 189.401 -30.8C206.201 -29.6 177.401 -40.8 177.401 -40.8C185.401 -40.8 167.401 -51.2 167.401 -51.2C165.401 -52.8 162.201 -60.4 162.201 -60.4C156.201 -65.6 151.401 -72.4 151.401 -72.4C151.001 -76.8 146.201 -81.6 146.201 -81.6C134.601 -95.2 129.001 -94.8 129.001 -94.8C114.201 -98.4 109.001 -97.6 109.001 -97.6L56.2 -93.2C29.8 -80.4 37.6 -59.4 37.6 -59.4C44 -51 53.2 -54.8 53.2 -54.8C57.8 -61 69.4 -58.8 69.4 -58.8C89.801 -55.6 87.201 -59.2 87.201 -59.2C84.801 -63.8 68.6 -70 68.4 -70.6C68.2 -71.2 59.4 -74.6 59.4 -74.6C56.4 -75.8 52 -85 52 -85C48.8 -88.4 64.6 -82.6 64.6 -82.6C63.4 -81.6 70.8 -77.6 70.8 -77.6C88.201 -78.6 98.801 -67.8 98.801 -67.8C109.601 -51.2 109.801 -59.4 109.801 -59.4C112.601 -68.8 100.801 -90 100.801 -90C101.201 -92 109.401 -85.4 109.401 -85.4C110.801 -87.4 111.601 -81.6 111.601 -81.6C111.801 -79.2 115.601 -71.2 115.601 -71.2C118.401 -58.2 122.001 -65.6 122.001 -65.6L126.601 -56.2C128.001 -53.6 122.001 -46 122.001 -46C121.801 -43.2 122.601 -43.4 117.001 -35.8C111.401 -28.2 114.801 -23.8 114.801 -23.8C113.401 -17.2 122.201 -17.6 122.201 -17.6C124.801 -15.4 128.201 -15.4 128.201 -15.4C130.001 -13.4 132.401 -14 132.401 -14C134.001 -17.8 140.201 -15.8 140.201 -15.8C141.601 -18.2 149.801 -18.6 149.801 -18.6C150.801 -21.2 151.201 -22.8 154.601 -23.4C158.001 -24 133.401 -67 133.401 -67C139.801 -67.8 131.601 -80.2 131.601 -80.2C129.401 -86.8 140.801 -72.2 143.001 -70.8C145.201 -69.4 146.201 -67.2 144.601 -67.4C143.001 -67.6 141.201 -65.4 142.601 -65.2C144.001 -65 157.001 -50 160.401 -39.8C163.801 -29.6 169.801 -25.6 176.001 -19.6C182.201 -13.6 181.401 10.6 181.401 10.6C181.001 19.4 187.001 30 187.001 30C189.001 33.8 184.801 52 184.801 52C182.801 54.2 184.201 55 184.201 55C185.201 56.2 192.001 69.4 192.001 69.4C190.201 69.2 193.801 72.8 193.801 72.8C199.001 78.8 192.601 75.8 192.601 75.8C186.601 74.2 193.601 84 193.601 84C194.801 85.8 185.801 81.2 185.801 81.2C176.601 80.6 188.201 87.8 188.201 87.8C196.801 95 185.401 90.6 185.401 90.6C180.801 88.8 184.001 95.6 184.001 95.6C187.201 97.2 204.401 104.2 204.401 104.2C204.801 108.001 201.801 113.001 201.801 113.001C202.201 117.001 200.001 120.401 200.001 120.401C198.801 128.601 198.201 129.401 198.201 129.401C194.001 129.601 186.601 143.401 186.601 143.401C184.801 146.001 174.601 158.001 174.601 158.001C172.601 165.001 154.601 157.801 154.601 157.801C148.001 161.201 150.001 157.801 150.001 157.801C149.601 155.601 154.401 149.601 154.401 149.601C161.401 147.001 158.801 136.201 158.801 136.201C162.801 134.801 151.601 132.001 151.801 130.801C152.001 129.601 157.801 128.201 157.801 128.201C165.801 126.201 161.401 123.801 161.401 123.801C160.801 119.801 163.801 114.201 163.801 114.201C175.401 113.401 163.801 97.2 163.801 97.2C153.001 89.6 152.001 83.8 152.001 83.8C164.601 75.6 156.401 63.2 156.601 59.6C156.801 56 158.001 34.4 158.001 34.4C156.001 28.2 153.001 14.6 153.001 14.6C155.201 9.4 162.601 -3.2 162.601 -3.2C165.401 -7.4 174.201 -12.2 172.001 -15.2C169.801 -18.2 162.001 -16.4 162.001 -16.4C154.201 -17.8 154.801 -12.6 154.801 -12.6C153.201 -11.6 152.401 -6.6 152.401 -6.6C151.68 1.333 142.801 7.6 142.801 7.6C131.601 13.8 140.801 17.8 140.801 17.8C146.801 24.4 137.001 24.6 137.001 24.6C126.001 22.8 134.201 33 134.201 33C145.001 45.8 142.001 48.6 142.001 48.6C131.801 49.6 144.401 58.8 144.401 58.8C144.401 58.8 143.601 56.8 143.801 58.6C144.001 60.4 147.001 64.6 147.801 66.6C148.601 68.6 144.601 68.8 144.601 68.8C145.201 78.4 129.801 74.2 129.801 74.2C129.801 74.2 129.801 74.2 128.201 74.4C126.601 74.6 115.401 73.8 109.601 71.6C103.801 69.4 97.001 69.4 97.001 69.4C97.001 69.4 93.001 71.2 85.4 71C77.8 70.8 69.8 73.6 69.8 73.6C65.4 73.2 74 68.8 74.2 69C74.4 69.2 80 63.6 72 64.2C50.203 65.835 39.4 55.6 39.4 55.6C37.4 54.2 34.8 51.4 34.8 51.4C24.8 49.4 36.2 63.8 36.2 63.8C37.4 65.2 36 66.2 36 66.2C35.2 64.6 27.4 59.2 27.4 59.2C24.589 58.227 23.226 56.893 20.895 54.407z"/>
+ </g>
+ <g style="fill: #4c0000">
+ <path d="M-3 42.8C-3 42.8 8.6 48.4 11.2 51.2C13.8 54 27.8 65.4 27.8 65.4C27.8 65.4 22.4 63.4 19.8 61.6C17.2 59.8 6.4 51.6 6.4 51.6C6.4 51.6 2.6 45.6 -3 42.8z"/>
+ </g>
+ <g style="fill: #99cc32">
+ <path d="M-61.009 11.603C-60.672 11.455 -61.196 8.743 -61.4 8.2C-62.422 5.474 -71.4 4 -71.4 4C-71.627 5.365 -71.682 6.961 -71.576 8.599C-71.576 8.599 -66.708 14.118 -61.009 11.603z"/>
+ </g>
+ <g style="fill: #659900">
+ <path d="M-61.009 11.403C-61.458 11.561 -61.024 8.669 -61.2 8.2C-62.222 5.474 -71.4 3.9 -71.4 3.9C-71.627 5.265 -71.682 6.861 -71.576 8.499C-71.576 8.499 -67.308 13.618 -61.009 11.403z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-65.4 11.546C-66.025 11.546 -66.531 10.406 -66.531 9C-66.531 7.595 -66.025 6.455 -65.4 6.455C-64.775 6.455 -64.268 7.595 -64.268 9C-64.268 10.406 -64.775 11.546 -65.4 11.546z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-65.4 9z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-111 109.601C-111 109.601 -116.6 119.601 -91.8 113.601C-91.8 113.601 -77.8 112.401 -75.4 110.001C-74.2 110.801 -65.834 113.734 -63 114.401C-56.2 116.001 -47.8 106 -47.8 106C-47.8 106 -43.2 95.5 -40.4 95.5C-37.6 95.5 -40.8 97.1 -40.8 97.1C-40.8 97.1 -47.4 107.201 -47 108.801C-47 108.801 -52.2 128.801 -68.2 129.601C-68.2 129.601 -84.35 130.551 -83 136.401C-83 136.401 -74.2 134.001 -71.8 136.401C-71.8 136.401 -61 136.001 -69 142.401L-75.8 154.001C-75.8 154.001 -75.66 157.919 -85.8 154.401C-95.6 151.001 -105.9 138.101 -105.9 138.101C-105.9 138.101 -121.85 123.551 -111 109.601z"/>
+ </g>
+ <g style="fill: #e59999">
+ <path d="M-112.2 113.601C-112.2 113.601 -114.2 123.201 -77.4 112.801C-77.4 112.801 -73 112.801 -70.6 113.601C-68.2 114.401 -56.2 117.201 -54.2 116.001C-54.2 116.001 -61.4 129.601 -73 128.001C-73 128.001 -86.2 129.601 -85.8 134.401C-85.8 134.401 -81.8 141.601 -77 144.001C-77 144.001 -74.2 146.401 -74.6 149.601C-75 152.801 -77.8 154.401 -79.8 155.201C-81.8 156.001 -85 152.801 -86.6 152.801C-88.2 152.801 -96.6 146.401 -101 141.601C-105.4 136.801 -113.8 124.801 -113.4 122.001C-113 119.201 -112.2 113.601 -112.2 113.601z"/>
+ </g>
+ <g style="fill: #b26565">
+ <path d="M-109 131.051C-106.4 135.001 -103.2 139.201 -101 141.601C-96.6 146.401 -88.2 152.801 -86.6 152.801C-85 152.801 -81.8 156.001 -79.8 155.201C-77.8 154.401 -75 152.801 -74.6 149.601C-74.2 146.401 -77 144.001 -77 144.001C-80.066 142.468 -82.806 138.976 -84.385 136.653C-84.385 136.653 -84.2 139.201 -89.4 138.401C-94.6 137.601 -99.8 134.801 -101.4 131.601C-103 128.401 -105.4 126.001 -103.8 129.601C-102.2 133.201 -99.8 136.801 -98.2 137.201C-96.6 137.601 -97 138.801 -99.4 138.401C-101.8 138.001 -104.6 137.601 -109 132.401z"/>
+ </g>
+ <g style="fill: #992600">
+ <path d="M-111.6 110.001C-111.6 110.001 -109.8 96.4 -108.6 92.4C-108.6 92.4 -109.4 85.6 -107 81.4C-104.6 77.2 -102.6 71 -99.6 65.6C-96.6 60.2 -96.4 56.2 -92.4 54.6C-88.4 53 -82.4 44.4 -79.6 43.4C-76.8 42.4 -77 43.2 -77 43.2C-77 43.2 -70.2 28.4 -56.6 32.4C-56.6 32.4 -72.8 29.6 -57 20.2C-57 20.2 -61.8 21.3 -58.5 14.3C-56.299 9.632 -56.8 16.4 -67.8 28.2C-67.8 28.2 -72.8 36.8 -78 39.8C-83.2 42.8 -95.2 49.8 -96.4 53.6C-97.6 57.4 -100.8 63.2 -102.8 64.8C-104.8 66.4 -107.6 70.6 -108 74C-108 74 -109.2 78 -110.6 79.2C-112 80.4 -112.2 83.6 -112.2 85.6C-112.2 87.6 -114.2 90.4 -114 92.8C-114 92.8 -113.2 111.801 -113.6 113.801L-111.6 110.001z"/>
+ </g>
+ <g style="fill: #ffffff">
+ <path d="M-120.2 114.601C-120.2 114.601 -122.2 113.201 -126.6 119.201C-126.6 119.201 -119.3 152.201 -119.3 153.601C-119.3 153.601 -118.2 151.501 -119.5 144.301C-120.8 137.101 -121.7 124.401 -121.7 124.401L-120.2 114.601z"/>
+ </g>
+ <g style="fill: #992600">
+ <path d="M-98.6 54C-98.6 54 -116.2 57.2 -115.8 86.4L-116.6 111.201C-116.6 111.201 -117.8 85.6 -119 84C-120.2 82.4 -116.2 71.2 -119.4 77.2C-119.4 77.2 -133.4 91.2 -125.4 112.401C-125.4 112.401 -123.9 115.701 -126.9 111.101C-126.9 111.101 -131.5 98.5 -130.4 92.1C-130.4 92.1 -130.2 89.9 -128.3 87.1C-128.3 87.1 -119.7 75.4 -117 73.1C-117 73.1 -115.2 58.7 -99.8 53.5C-99.8 53.5 -94.1 51.2 -98.6 54z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M40.8 -12.2C41.46 -12.554 41.451 -13.524 42.031 -13.697C43.18 -14.041 43.344 -15.108 43.862 -15.892C44.735 -17.211 44.928 -18.744 45.51 -20.235C45.782 -20.935 45.809 -21.89 45.496 -22.55C44.322 -25.031 43.62 -27.48 42.178 -29.906C41.91 -30.356 41.648 -31.15 41.447 -31.748C40.984 -33.132 39.727 -34.123 38.867 -35.443C38.579 -35.884 39.104 -36.809 38.388 -36.893C37.491 -36.998 36.042 -37.578 35.809 -36.552C35.221 -33.965 36.232 -31.442 37.2 -29C36.418 -28.308 36.752 -27.387 36.904 -26.62C37.614 -23.014 36.416 -19.662 35.655 -16.188C35.632 -16.084 35.974 -15.886 35.946 -15.824C34.724 -13.138 33.272 -10.693 31.453 -8.312C30.695 -7.32 29.823 -6.404 29.326 -5.341C28.958 -4.554 28.55 -3.588 28.8 -2.6C25.365 0.18 23.115 4.025 20.504 7.871C20.042 8.551 20.333 9.76 20.884 10.029C21.697 10.427 22.653 9.403 23.123 8.557C23.512 7.859 23.865 7.209 24.356 6.566C24.489 6.391 24.31 5.972 24.445 5.851C27.078 3.504 28.747 0.568 31.2 -1.8C33.15 -2.129 34.687 -3.127 36.435 -4.14C36.743 -4.319 37.267 -4.07 37.557 -4.265C39.31 -5.442 39.308 -7.478 39.414 -9.388C39.464 -10.272 39.66 -11.589 40.8 -12.2z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M31.959 -16.666C32.083 -16.743 31.928 -17.166 32.037 -17.382C32.199 -17.706 32.602 -17.894 32.764 -18.218C32.873 -18.434 32.71 -18.814 32.846 -18.956C35.179 -21.403 35.436 -24.427 34.4 -27.4C35.424 -28.02 35.485 -29.282 35.06 -30.129C34.207 -31.829 34.014 -33.755 33.039 -35.298C32.237 -36.567 30.659 -37.811 29.288 -36.508C28.867 -36.108 28.546 -35.321 28.824 -34.609C28.888 -34.446 29.173 -34.3 29.146 -34.218C29.039 -33.894 28.493 -33.67 28.487 -33.398C28.457 -31.902 27.503 -30.391 28.133 -29.062C28.905 -27.433 29.724 -25.576 30.4 -23.8C29.166 -21.684 30.199 -19.235 28.446 -17.358C28.31 -17.212 28.319 -16.826 28.441 -16.624C28.733 -16.138 29.139 -15.732 29.625 -15.44C29.827 -15.319 30.175 -15.317 30.375 -15.441C30.953 -15.803 31.351 -16.29 31.959 -16.666z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M94.771 -26.977C96.16 -25.185 96.45 -22.39 94.401 -21C94.951 -17.691 98.302 -19.67 100.401 -20.2C100.292 -20.588 100.519 -20.932 100.802 -20.937C101.859 -20.952 102.539 -21.984 103.601 -21.8C104.035 -23.357 105.673 -24.059 106.317 -25.439C108.043 -29.134 107.452 -33.407 104.868 -36.653C104.666 -36.907 104.883 -37.424 104.759 -37.786C104.003 -39.997 101.935 -40.312 100.001 -41C98.824 -44.875 98.163 -48.906 96.401 -52.6C94.787 -52.85 94.089 -54.589 92.752 -55.309C91.419 -56.028 90.851 -54.449 90.892 -53.403C90.899 -53.198 91.351 -52.974 91.181 -52.609C91.105 -52.445 90.845 -52.334 90.845 -52.2C90.846 -52.065 91.067 -51.934 91.201 -51.8C90.283 -50.98 88.86 -50.503 88.565 -49.358C87.611 -45.648 90.184 -42.523 91.852 -39.322C92.443 -38.187 91.707 -36.916 90.947 -35.708C90.509 -35.013 90.617 -33.886 90.893 -33.03C91.645 -30.699 93.236 -28.96 94.771 -26.977z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M57.611 -8.591C56.124 -6.74 52.712 -4.171 55.629 -2.243C55.823 -2.114 56.193 -2.11 56.366 -2.244C58.387 -3.809 60.39 -4.712 62.826 -5.294C62.95 -5.323 63.224 -4.856 63.593 -5.017C65.206 -5.72 67.216 -5.662 68.4 -7C72.167 -6.776 75.732 -7.892 79.123 -9.2C80.284 -9.648 81.554 -10.207 82.755 -10.709C84.131 -11.285 85.335 -12.213 86.447 -13.354C86.58 -13.49 86.934 -13.4 87.201 -13.4C87.161 -14.263 88.123 -14.39 88.37 -15.012C88.462 -15.244 88.312 -15.64 88.445 -15.742C90.583 -17.372 91.503 -19.39 90.334 -21.767C90.049 -22.345 89.8 -22.963 89.234 -23.439C88.149 -24.35 87.047 -23.496 86 -23.8C85.841 -23.172 85.112 -23.344 84.726 -23.146C83.867 -22.707 82.534 -23.292 81.675 -22.854C80.313 -22.159 79.072 -21.99 77.65 -21.613C77.338 -21.531 76.56 -21.627 76.4 -21C76.266 -21.134 76.118 -21.368 76.012 -21.346C74.104 -20.95 72.844 -20.736 71.543 -19.044C71.44 -18.911 70.998 -19.09 70.839 -18.955C69.882 -18.147 69.477 -16.913 68.376 -16.241C68.175 -16.118 67.823 -16.286 67.629 -16.157C66.983 -15.726 66.616 -15.085 65.974 -14.638C65.645 -14.409 65.245 -14.734 65.277 -14.99C65.522 -16.937 66.175 -18.724 65.6 -20.6C67.677 -23.12 70.194 -25.069 72 -27.8C72.015 -29.966 72.707 -32.112 72.594 -34.189C72.584 -34.382 72.296 -35.115 72.17 -35.462C71.858 -36.316 72.764 -37.382 71.92 -38.106C70.516 -39.309 69.224 -38.433 68.4 -37C66.562 -36.61 64.496 -35.917 62.918 -37.151C61.911 -37.938 61.333 -38.844 60.534 -39.9C59.549 -41.202 59.884 -42.638 59.954 -44.202C59.96 -44.33 59.645 -44.466 59.645 -44.6C59.646 -44.735 59.866 -44.866 60 -45C59.294 -45.626 59.019 -46.684 58 -47C58.305 -48.092 57.629 -48.976 56.758 -49.278C54.763 -49.969 53.086 -48.057 51.194 -47.984C50.68 -47.965 50.213 -49.003 49.564 -49.328C49.132 -49.544 48.428 -49.577 48.066 -49.311C47.378 -48.807 46.789 -48.693 46.031 -48.488C44.414 -48.052 43.136 -46.958 41.656 -46.103C40.171 -45.246 39.216 -43.809 38.136 -42.489C37.195 -41.337 37.059 -38.923 38.479 -38.423C40.322 -37.773 41.626 -40.476 43.592 -40.15C43.904 -40.099 44.11 -39.788 44 -39.4C44.389 -39.291 44.607 -39.52 44.8 -39.8C45.658 -38.781 46.822 -38.444 47.76 -37.571C48.73 -36.667 50.476 -37.085 51.491 -36.088C53.02 -34.586 52.461 -31.905 54.4 -30.6C53.814 -29.287 53.207 -28.01 52.872 -26.583C52.59 -25.377 53.584 -24.18 54.795 -24.271C56.053 -24.365 56.315 -25.124 56.8 -26.2C57.067 -25.933 57.536 -25.636 57.495 -25.42C57.038 -23.033 56.011 -21.04 55.553 -18.609C55.494 -18.292 55.189 -18.09 54.8 -18.2C54.332 -14.051 50.28 -11.657 47.735 -8.492C47.332 -7.99 47.328 -6.741 47.737 -6.338C49.14 -4.951 51.1 -6.497 52.8 -7C53.013 -8.206 53.872 -9.148 55.204 -9.092C55.46 -9.082 55.695 -9.624 56.019 -9.754C56.367 -9.892 56.869 -9.668 57.155 -9.866C58.884 -11.061 60.292 -12.167 62.03 -13.356C62.222 -13.487 62.566 -13.328 62.782 -13.436C63.107 -13.598 63.294 -13.985 63.617 -14.17C63.965 -14.37 64.207 -14.08 64.4 -13.8C63.754 -13.451 63.75 -12.494 63.168 -12.292C62.393 -12.024 61.832 -11.511 61.158 -11.064C60.866 -10.871 60.207 -11.119 60.103 -10.94C59.505 -9.912 58.321 -9.474 57.611 -8.591z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M2.2 -58C2.2 -58 -7.038 -60.872 -18.2 -35.2C-18.2 -35.2 -20.6 -30 -23 -28C-25.4 -26 -36.6 -22.4 -38.6 -18.4L-49 -2.4C-49 -2.4 -34.2 -18.4 -31 -20.8C-31 -20.8 -23 -29.2 -26.2 -22.4C-26.2 -22.4 -40.2 -11.6 -39 -2.4C-39 -2.4 -44.6 12 -45.4 14C-45.4 14 -29.4 -18 -27 -19.2C-24.6 -20.4 -23.4 -20.4 -24.6 -16.8C-25.8 -13.2 -26.2 3.2 -29 5.2C-29 5.2 -21 -15.2 -21.8 -18.4C-21.8 -18.4 -18.6 -22 -16.2 -16.8L-17.4 -0.8L-13 11.2C-13 11.2 -15.4 0 -13.8 -15.6C-13.8 -15.6 -15.8 -26 -11.8 -20.4C-7.8 -14.8 1.8 -8.8 1.8 -4C1.8 -4 -3.4 -21.6 -12.6 -26.4L-16.6 -20.4L-17.8 -22.4C-17.8 -22.4 -21.4 -23.2 -17 -30C-12.6 -36.8 -13 -37.6 -13 -37.6C-13 -37.6 -6.6 -30.4 -5 -30.4C-5 -30.4 8.2 -38 9.4 -13.6C9.4 -13.6 16.2 -28 7 -34.8C7 -34.8 -7.8 -36.8 -6.6 -42L0.6 -54.4C4.2 -59.6 2.6 -56.8 2.6 -56.8z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-17.8 -41.6C-17.8 -41.6 -30.6 -41.6 -33.8 -36.4L-41 -26.8C-41 -26.8 -23.8 -36.8 -19.8 -38C-15.8 -39.2 -17.8 -41.6 -17.8 -41.6z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-57.8 -35.2C-57.8 -35.2 -59.8 -34 -60.2 -31.2C-60.6 -28.4 -63 -28 -62.2 -25.2C-61.4 -22.4 -59.4 -20 -59.4 -24C-59.4 -28 -57.8 -30 -57 -31.2C-56.2 -32.4 -54.6 -36.8 -57.8 -35.2z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-66.6 26C-66.6 26 -75 22 -78.2 18.4C-81.4 14.8 -80.948 19.966 -85.8 19.6C-91.647 19.159 -90.6 3.2 -90.6 3.2L-94.6 10.8C-94.6 10.8 -95.8 25.2 -87.8 22.8C-83.893 21.628 -82.6 23.2 -84.2 24C-85.8 24.8 -78.6 25.2 -81.4 26.8C-84.2 28.4 -69.8 23.2 -72.2 33.6L-66.6 26z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-79.2 40.4C-79.2 40.4 -94.6 44.8 -98.2 35.2C-98.2 35.2 -103 37.6 -100.8 40.6C-98.6 43.6 -97.4 44 -97.4 44C-97.4 44 -92 45.2 -92.6 46C-93.2 46.8 -95.6 50.2 -95.6 50.2C-95.6 50.2 -85.4 44.2 -79.2 40.4z"/>
+ </g>
+ <g style="fill: #ffffff">
+ <path d="M149.201 118.601C148.774 120.735 147.103 121.536 145.201 122.201C143.284 121.243 140.686 118.137 138.801 120.201C138.327 119.721 137.548 119.661 137.204 118.999C136.739 118.101 137.011 117.055 136.669 116.257C136.124 114.985 135.415 113.619 135.601 112.201C137.407 111.489 138.002 109.583 137.528 107.82C137.459 107.563 137.03 107.366 137.23 107.017C137.416 106.694 137.734 106.467 138.001 106.2C137.866 106.335 137.721 106.568 137.61 106.548C137 106.442 137.124 105.805 137.254 105.418C137.839 103.672 139.853 103.408 141.201 104.6C141.457 104.035 141.966 104.229 142.401 104.2C142.351 103.621 142.759 103.094 142.957 102.674C143.475 101.576 145.104 102.682 145.901 102.07C146.977 101.245 148.04 100.546 149.118 101.149C150.927 102.162 152.636 103.374 153.835 105.115C154.41 105.949 154.65 107.23 154.592 108.188C154.554 108.835 153.173 108.483 152.83 109.412C152.185 111.16 154.016 111.679 154.772 113.017C154.97 113.366 154.706 113.67 154.391 113.768C153.98 113.896 153.196 113.707 153.334 114.16C154.306 117.353 151.55 118.031 149.201 118.601z"/>
+ </g>
+ <g style="fill: #ffffff">
+ <path d="M139.6 138.201C139.593 136.463 137.992 134.707 139.201 133.001C139.336 133.135 139.467 133.356 139.601 133.356C139.736 133.356 139.867 133.135 140.001 133.001C141.496 135.217 145.148 136.145 145.006 138.991C144.984 139.438 143.897 140.356 144.801 141.001C142.988 142.349 142.933 144.719 142.001 146.601C140.763 146.315 139.551 145.952 138.401 145.401C138.753 143.915 138.636 142.231 139.456 140.911C139.89 140.213 139.603 139.134 139.6 138.201z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-26.6 129.201C-26.6 129.201 -43.458 139.337 -29.4 124.001C-20.6 114.401 -10.6 108.801 -10.6 108.801C-10.6 108.801 -0.2 104.4 3.4 103.2C7 102 22.2 96.8 25.4 96.4C28.6 96 38.2 92 45 96C51.8 100 59.8 104.4 59.8 104.4C59.8 104.4 43.4 96 39.8 98.4C36.2 100.8 29 100.4 23 103.6C23 103.6 8.2 108.001 5 110.001C1.8 112.001 -8.6 123.601 -10.2 122.801C-11.8 122.001 -9.8 121.601 -8.6 118.801C-7.4 116.001 -9.4 114.401 -17.4 120.801C-25.4 127.201 -26.6 129.201 -26.6 129.201z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-19.195 123.234C-19.195 123.234 -17.785 110.194 -9.307 111.859C-9.307 111.859 -1.081 107.689 1.641 105.721C1.641 105.721 9.78 104.019 11.09 103.402C29.569 94.702 44.288 99.221 44.835 98.101C45.381 96.982 65.006 104.099 68.615 108.185C69.006 108.628 58.384 102.588 48.686 100.697C40.413 99.083 18.811 100.944 7.905 106.48C4.932 107.989 -4.013 113.773 -6.544 113.662C-9.075 113.55 -19.195 123.234 -19.195 123.234z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-23 148.801C-23 148.801 -38.2 146.401 -21.4 144.801C-21.4 144.801 -3.4 142.801 0.6 137.601C0.6 137.601 14.2 128.401 17 128.001C19.8 127.601 49.8 120.401 50.2 118.001C50.6 115.601 56.2 115.601 57.8 116.401C59.4 117.201 58.6 118.401 55.8 119.201C53 120.001 21.8 136.401 15.4 137.601C9 138.801 -2.6 146.401 -7.4 147.601C-12.2 148.801 -23 148.801 -23 148.801z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-3.48 141.403C-3.48 141.403 -12.062 140.574 -3.461 139.755C-3.461 139.755 5.355 136.331 7.403 133.668C7.403 133.668 14.367 128.957 15.8 128.753C17.234 128.548 31.194 124.861 31.399 123.633C31.604 122.404 65.67 109.823 70.09 113.013C73.001 115.114 63.1 113.437 53.466 117.847C52.111 118.467 18.258 133.054 14.981 133.668C11.704 134.283 5.765 138.174 3.307 138.788C0.85 139.403 -3.48 141.403 -3.48 141.403z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-11.4 143.601C-11.4 143.601 -6.2 143.201 -7.4 144.801C-8.6 146.401 -11 145.601 -11 145.601L-11.4 143.601z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-18.6 145.201C-18.6 145.201 -13.4 144.801 -14.6 146.401C-15.8 148.001 -18.2 147.201 -18.2 147.201L-18.6 145.201z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-29 146.801C-29 146.801 -23.8 146.401 -25 148.001C-26.2 149.601 -28.6 148.801 -28.6 148.801L-29 146.801z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-36.6 147.601C-36.6 147.601 -31.4 147.201 -32.6 148.801C-33.8 150.401 -36.2 149.601 -36.2 149.601L-36.6 147.601z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M1.8 108.001C1.8 108.001 6.2 108.001 5 109.601C3.8 111.201 0.6 110.801 0.6 110.801L1.8 108.001z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-8.2 113.601C-8.2 113.601 -1.694 111.46 -4.2 114.801C-5.4 116.401 -7.8 115.601 -7.8 115.601L-8.2 113.601z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-19.4 118.401C-19.4 118.401 -14.2 118.001 -15.4 119.601C-16.6 121.201 -19 120.401 -19 120.401L-19.4 118.401z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-27 124.401C-27 124.401 -21.8 124.001 -23 125.601C-24.2 127.201 -26.6 126.401 -26.6 126.401L-27 124.401z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-33.8 129.201C-33.8 129.201 -28.6 128.801 -29.8 130.401C-31 132.001 -33.4 131.201 -33.4 131.201L-33.8 129.201z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M5.282 135.598C5.282 135.598 12.203 135.066 10.606 137.195C9.009 139.325 5.814 138.26 5.814 138.26L5.282 135.598z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M15.682 130.798C15.682 130.798 22.603 130.266 21.006 132.395C19.409 134.525 16.214 133.46 16.214 133.46L15.682 130.798z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M26.482 126.398C26.482 126.398 33.403 125.866 31.806 127.995C30.209 130.125 27.014 129.06 27.014 129.06L26.482 126.398z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M36.882 121.598C36.882 121.598 43.803 121.066 42.206 123.195C40.609 125.325 37.414 124.26 37.414 124.26L36.882 121.598z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M9.282 103.598C9.282 103.598 16.203 103.066 14.606 105.195C13.009 107.325 9.014 107.06 9.014 107.06L9.282 103.598z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M19.282 100.398C19.282 100.398 26.203 99.866 24.606 101.995C23.009 104.125 18.614 103.86 18.614 103.86L19.282 100.398z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-3.4 140.401C-3.4 140.401 1.8 140.001 0.6 141.601C-0.6 143.201 -3 142.401 -3 142.401L-3.4 140.401z"/>
+ </g>
+ <g style="fill: #992600">
+ <path d="M-76.6 41.2C-76.6 41.2 -81 50 -81.4 53.2C-81.4 53.2 -80.6 44.4 -79.4 42.4C-78.2 40.4 -76.6 41.2 -76.6 41.2z"/>
+ </g>
+ <g style="fill: #992600">
+ <path d="M-95 55.2C-95 55.2 -98.2 69.6 -97.8 72.4C-97.8 72.4 -99 60.8 -98.6 59.6C-98.2 58.4 -95 55.2 -95 55.2z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-74.2 -19.4L-74.4 -16.2L-76.6 -16C-76.6 -16 -62.4 -3.4 -61.8 4.2C-61.8 4.2 -61 -4 -74.2 -19.4z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-70.216 -18.135C-70.647 -18.551 -70.428 -19.296 -70.836 -19.556C-71.645 -20.072 -69.538 -20.129 -69.766 -20.845C-70.149 -22.051 -69.962 -22.072 -70.084 -23.348C-70.141 -23.946 -69.553 -25.486 -69.168 -25.926C-67.722 -27.578 -69.046 -30.51 -67.406 -32.061C-67.102 -32.35 -66.726 -32.902 -66.441 -33.32C-65.782 -34.283 -64.598 -34.771 -63.648 -35.599C-63.33 -35.875 -63.531 -36.702 -62.962 -36.61C-62.248 -36.495 -61.007 -36.625 -61.052 -35.784C-61.165 -33.664 -62.494 -31.944 -63.774 -30.276C-63.323 -29.572 -63.781 -28.937 -64.065 -28.38C-65.4 -25.76 -65.211 -22.919 -65.385 -20.079C-65.39 -19.994 -65.697 -19.916 -65.689 -19.863C-65.336 -17.528 -64.752 -15.329 -63.873 -13.1C-63.507 -12.17 -63.036 -11.275 -62.886 -10.348C-62.775 -9.662 -62.672 -8.829 -63.08 -8.124C-61.045 -5.234 -62.354 -2.583 -61.185 0.948C-60.978 1.573 -59.286 3.487 -59.749 3.326C-62.262 2.455 -62.374 2.057 -62.551 1.304C-62.697 0.681 -63.027 -0.696 -63.264 -1.298C-63.328 -1.462 -63.499 -3.346 -63.577 -3.468C-65.09 -5.85 -63.732 -5.674 -65.102 -8.032C-66.53 -8.712 -67.496 -9.816 -68.619 -10.978C-68.817 -11.182 -67.674 -11.906 -67.855 -12.119C-68.947 -13.408 -70.1 -14.175 -69.764 -15.668C-69.609 -16.358 -69.472 -17.415 -70.216 -18.135z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-73.8 -16.4C-73.8 -16.4 -73.4 -9.6 -71 -8C-68.6 -6.4 -69.8 -7.2 -73 -8.4C-76.2 -9.6 -75 -10.4 -75 -10.4C-75 -10.4 -77.8 -10 -75.4 -8C-73 -6 -69.4 -3.6 -71 -3.6C-72.6 -3.6 -80.2 -7.6 -80.2 -10.4C-80.2 -13.2 -81.2 -17.3 -81.2 -17.3C-81.2 -17.3 -80.1 -18.1 -75.3 -18C-75.3 -18 -73.9 -17.3 -73.8 -16.4z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-74.6 2.2C-74.6 2.2 -83.12 -0.591 -101.6 2.8C-101.6 2.8 -92.569 0.722 -73.8 3C-63.5 4.25 -74.6 2.2 -74.6 2.2z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-72.502 2.129C-72.502 2.129 -80.748 -1.389 -99.453 0.392C-99.453 0.392 -90.275 -0.897 -71.774 2.995C-61.62 5.131 -72.502 2.129 -72.502 2.129z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-70.714 2.222C-70.714 2.222 -78.676 -1.899 -97.461 -1.514C-97.461 -1.514 -88.213 -2.118 -70.052 3.14C-60.086 6.025 -70.714 2.222 -70.714 2.222z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-69.444 2.445C-69.444 2.445 -76.268 -1.862 -93.142 -2.96C-93.142 -2.96 -84.803 -2.79 -68.922 3.319C-60.206 6.672 -69.444 2.445 -69.444 2.445z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M45.84 12.961C45.84 12.961 44.91 13.605 45.124 12.424C45.339 11.243 73.547 -1.927 77.161 -1.677C77.161 -1.677 46.913 11.529 45.84 12.961z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M42.446 13.6C42.446 13.6 41.57 14.315 41.691 13.121C41.812 11.927 68.899 -3.418 72.521 -3.452C72.521 -3.452 43.404 12.089 42.446 13.6z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M39.16 14.975C39.16 14.975 38.332 15.747 38.374 14.547C38.416 13.348 58.233 -2.149 68.045 -4.023C68.045 -4.023 50.015 4.104 39.16 14.975z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M36.284 16.838C36.284 16.838 35.539 17.532 35.577 16.453C35.615 15.373 53.449 1.426 62.28 -0.26C62.28 -0.26 46.054 7.054 36.284 16.838z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M4.6 164.801C4.6 164.801 -10.6 162.401 6.2 160.801C6.2 160.801 24.2 158.801 28.2 153.601C28.2 153.601 41.8 144.401 44.6 144.001C47.4 143.601 63.8 140.001 64.2 137.601C64.6 135.201 70.6 132.801 72.2 133.601C73.8 134.401 73.8 143.601 71 144.401C68.2 145.201 49.4 152.401 43 153.601C36.6 154.801 25 162.401 20.2 163.601C15.4 164.801 4.6 164.801 4.6 164.801z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M77.6 127.401C77.6 127.401 74.6 129.001 73.4 131.601C73.4 131.601 67 142.201 52.8 145.401C52.8 145.401 29.8 154.401 22 156.401C22 156.401 8.6 161.401 1.2 160.601C1.2 160.601 -5.8 160.801 0.4 162.401C0.4 162.401 20.6 160.401 24 158.601C24 158.601 39.6 153.401 42.6 150.801C45.6 148.201 63.8 143.201 66 141.201C68.2 139.201 78 130.801 77.6 127.401z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M18.882 158.911C18.882 158.911 24.111 158.685 22.958 160.234C21.805 161.784 19.357 160.91 19.357 160.91L18.882 158.911z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M11.68 160.263C11.68 160.263 16.908 160.037 15.756 161.586C14.603 163.136 12.155 162.263 12.155 162.263L11.68 160.263z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M1.251 161.511C1.251 161.511 6.48 161.284 5.327 162.834C4.174 164.383 1.726 163.51 1.726 163.51L1.251 161.511z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-6.383 162.055C-6.383 162.055 -1.154 161.829 -2.307 163.378C-3.46 164.928 -5.908 164.054 -5.908 164.054L-6.383 162.055z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M35.415 151.513C35.415 151.513 42.375 151.212 40.84 153.274C39.306 155.336 36.047 154.174 36.047 154.174L35.415 151.513z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M45.73 147.088C45.73 147.088 51.689 143.787 51.155 148.849C50.885 151.405 46.362 149.749 46.362 149.749L45.73 147.088z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M54.862 144.274C54.862 144.274 62.021 140.573 60.287 146.035C59.509 148.485 55.493 146.935 55.493 146.935L54.862 144.274z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M64.376 139.449C64.376 139.449 68.735 134.548 69.801 141.21C70.207 143.748 65.008 142.11 65.008 142.11L64.376 139.449z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M26.834 155.997C26.834 155.997 32.062 155.77 30.91 157.32C29.757 158.869 27.308 157.996 27.308 157.996L26.834 155.997z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M62.434 34.603C62.434 34.603 61.708 35.268 61.707 34.197C61.707 33.127 79.191 19.863 88.034 18.479C88.034 18.479 71.935 25.208 62.434 34.603z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M65.4 98.4C65.4 98.4 87.401 120.801 96.601 124.401C96.601 124.401 105.801 135.601 101.801 161.601C101.801 161.601 98.601 169.201 95.401 148.401C95.401 148.401 98.601 123.201 87.401 139.201C87.401 139.201 79 129.301 85.4 129.601C85.4 129.601 88.601 131.601 89.001 130.001C89.401 128.401 81.4 114.801 64.2 100.4C47 86 65.4 98.4 65.4 98.4z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M7 137.201C7 137.201 6.8 135.401 8.6 136.201C10.4 137.001 104.601 143.201 136.201 167.201C136.201 167.201 91.001 144.001 7 137.201z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M17.4 132.801C17.4 132.801 17.2 131.001 19 131.801C20.8 132.601 157.401 131.601 181.001 164.001C181.001 164.001 159.001 138.801 17.4 132.801z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M29 128.801C29 128.801 28.8 127.001 30.6 127.801C32.4 128.601 205.801 115.601 229.401 148.001C229.401 148.001 219.801 122.401 29 128.801z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M39 124.001C39 124.001 38.8 122.201 40.6 123.001C42.4 123.801 164.601 85.2 188.201 117.601C188.201 117.601 174.801 93 39 124.001z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-19 146.801C-19 146.801 -19.2 145.001 -17.4 145.801C-15.6 146.601 2.2 148.801 4.2 187.601C4.2 187.601 -3 145.601 -19 146.801z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-27.8 148.401C-27.8 148.401 -28 146.601 -26.2 147.401C-24.4 148.201 -10.2 143.601 -13 182.401C-13 182.401 -11.8 147.201 -27.8 148.401z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-35.8 148.801C-35.8 148.801 -36 147.001 -34.2 147.801C-32.4 148.601 -17 149.201 -29.4 171.601C-29.4 171.601 -19.8 147.601 -35.8 148.801z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M11.526 104.465C11.526 104.465 11.082 106.464 12.631 105.247C28.699 92.622 61.141 33.72 116.826 28.086C116.826 28.086 78.518 15.976 11.526 104.465z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M22.726 102.665C22.726 102.665 21.363 101.472 23.231 100.847C25.099 100.222 137.541 27.72 176.826 35.686C176.826 35.686 149.719 28.176 22.726 102.665z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M1.885 108.767C1.885 108.767 1.376 110.366 3.087 109.39C12.062 104.27 15.677 47.059 59.254 45.804C59.254 45.804 26.843 31.09 1.885 108.767z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-18.038 119.793C-18.038 119.793 -19.115 121.079 -17.162 120.825C-6.916 119.493 14.489 78.222 58.928 83.301C58.928 83.301 26.962 68.955 -18.038 119.793z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-6.8 113.667C-6.8 113.667 -7.611 115.136 -5.742 114.511C4.057 111.237 17.141 66.625 61.729 63.078C61.729 63.078 27.603 55.135 -6.8 113.667z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-25.078 124.912C-25.078 124.912 -25.951 125.954 -24.369 125.748C-16.07 124.669 1.268 91.24 37.264 95.354C37.264 95.354 11.371 83.734 -25.078 124.912z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-32.677 130.821C-32.677 130.821 -33.682 131.866 -32.091 131.748C-27.923 131.439 2.715 98.36 21.183 113.862C21.183 113.862 9.168 95.139 -32.677 130.821z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M36.855 98.898C36.855 98.898 35.654 97.543 37.586 97.158C39.518 96.774 160.221 39.061 198.184 51.927C198.184 51.927 172.243 41.053 36.855 98.898z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M3.4 163.201C3.4 163.201 3.2 161.401 5 162.201C6.8 163.001 22.2 163.601 9.8 186.001C9.8 186.001 19.4 162.001 3.4 163.201z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M13.8 161.601C13.8 161.601 13.6 159.801 15.4 160.601C17.2 161.401 35 163.601 37 202.401C37 202.401 29.8 160.401 13.8 161.601z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M20.6 160.001C20.6 160.001 20.4 158.201 22.2 159.001C24 159.801 48.6 163.201 72.2 195.601C72.2 195.601 36.6 158.801 20.6 160.001z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M28.225 157.972C28.225 157.972 27.788 156.214 29.678 156.768C31.568 157.322 52.002 155.423 90.099 189.599C90.099 189.599 43.924 154.656 28.225 157.972z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M38.625 153.572C38.625 153.572 38.188 151.814 40.078 152.368C41.968 152.922 76.802 157.423 128.499 192.399C128.499 192.399 54.324 150.256 38.625 153.572z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-1.8 142.001C-1.8 142.001 -2 140.201 -0.2 141.001C1.6 141.801 55 144.401 85.4 171.201C85.4 171.201 50.499 146.426 -1.8 142.001z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M-11.8 146.001C-11.8 146.001 -12 144.201 -10.2 145.001C-8.4 145.801 16.2 149.201 39.8 181.601C39.8 181.601 4.2 144.801 -11.8 146.001z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M49.503 148.962C49.503 148.962 48.938 147.241 50.864 147.655C52.79 148.068 87.86 150.004 141.981 181.098C141.981 181.098 64.317 146.704 49.503 148.962z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M57.903 146.562C57.903 146.562 57.338 144.841 59.264 145.255C61.19 145.668 96.26 147.604 150.381 178.698C150.381 178.698 73.317 143.904 57.903 146.562z"/>
+ </g>
+ <g style="fill: #ffffff; stroke:#000000; stroke-width:0.1">
+ <path d="M67.503 141.562C67.503 141.562 66.938 139.841 68.864 140.255C70.79 140.668 113.86 145.004 203.582 179.298C203.582 179.298 82.917 138.904 67.503 141.562z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-43.8 148.401C-43.8 148.401 -38.6 148.001 -39.8 149.601C-41 151.201 -43.4 150.401 -43.4 150.401L-43.8 148.401z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-13 162.401C-13 162.401 -7.8 162.001 -9 163.601C-10.2 165.201 -12.6 164.401 -12.6 164.401L-13 162.401z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-21.8 162.001C-21.8 162.001 -16.6 161.601 -17.8 163.201C-19 164.801 -21.4 164.001 -21.4 164.001L-21.8 162.001z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-117.169 150.182C-117.169 150.182 -112.124 151.505 -113.782 152.624C-115.439 153.744 -117.446 152.202 -117.446 152.202L-117.169 150.182z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-115.169 140.582C-115.169 140.582 -110.124 141.905 -111.782 143.024C-113.439 144.144 -115.446 142.602 -115.446 142.602L-115.169 140.582z"/>
+ </g>
+ <g style="fill: #000000">
+ <path d="M-122.369 136.182C-122.369 136.182 -117.324 137.505 -118.982 138.624C-120.639 139.744 -122.646 138.202 -122.646 138.202L-122.369 136.182z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-42.6 211.201C-42.6 211.201 -44.2 211.201 -48.2 213.201C-50.2 213.201 -61.4 216.801 -67 226.801C-67 226.801 -54.6 217.201 -42.6 211.201z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M45.116 303.847C45.257 304.105 45.312 304.525 45.604 304.542C46.262 304.582 47.495 304.883 47.37 304.247C46.522 299.941 45.648 295.004 41.515 293.197C40.876 292.918 39.434 293.331 39.36 294.215C39.233 295.739 39.116 297.088 39.425 298.554C39.725 299.975 41.883 299.985 42.8 298.601C43.736 300.273 44.168 302.116 45.116 303.847z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M34.038 308.581C34.786 309.994 34.659 311.853 36.074 312.416C36.814 312.71 38.664 311.735 38.246 310.661C37.444 308.6 37.056 306.361 35.667 304.55C35.467 304.288 35.707 303.755 35.547 303.427C34.953 302.207 33.808 301.472 32.4 301.801C31.285 304.004 32.433 306.133 33.955 307.842C34.091 307.994 33.925 308.37 34.038 308.581z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-5.564 303.391C-5.672 303.014 -5.71 302.551 -5.545 302.23C-5.014 301.197 -4.221 300.075 -4.558 299.053C-4.906 297.997 -6.022 298.179 -6.672 298.748C-7.807 299.742 -7.856 301.568 -8.547 302.927C-8.743 303.313 -8.692 303.886 -9.133 304.277C-9.607 304.698 -10.047 306.222 -9.951 306.793C-9.898 307.106 -10.081 317.014 -9.859 316.751C-9.24 316.018 -6.19 306.284 -6.121 305.392C-6.064 304.661 -5.332 304.196 -5.564 303.391z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-31.202 296.599C-28.568 294.1 -25.778 291.139 -26.22 287.427C-26.336 286.451 -28.111 286.978 -28.298 287.824C-29.1 291.449 -31.139 294.11 -33.707 296.502C-35.903 298.549 -37.765 304.893 -38 305.401C-34.303 300.145 -32.046 297.399 -31.202 296.599z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-44.776 290.635C-44.253 290.265 -44.555 289.774 -44.338 289.442C-43.385 287.984 -42.084 286.738 -42.066 285C-42.063 284.723 -42.441 284.414 -42.776 284.638C-43.053 284.822 -43.395 284.952 -43.503 285.082C-45.533 287.531 -46.933 290.202 -48.376 293.014C-48.559 293.371 -49.703 297.862 -49.39 297.973C-49.151 298.058 -47.431 293.877 -47.221 293.763C-45.958 293.077 -45.946 291.462 -44.776 290.635z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-28.043 310.179C-27.599 309.31 -26.023 308.108 -26.136 307.219C-26.254 306.291 -25.786 304.848 -26.698 305.536C-27.955 306.484 -31.404 307.833 -31.674 313.641C-31.7 314.212 -28.726 311.519 -28.043 310.179z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-13.6 293.001C-13.2 292.333 -12.492 292.806 -12.033 292.543C-11.385 292.171 -10.774 291.613 -10.482 290.964C-9.512 288.815 -7.743 286.995 -7.6 284.601C-9.091 283.196 -9.77 285.236 -10.4 286.201C-11.723 284.554 -12.722 286.428 -14.022 286.947C-14.092 286.975 -14.305 286.628 -14.38 286.655C-15.557 287.095 -16.237 288.176 -17.235 288.957C-17.406 289.091 -17.811 288.911 -17.958 289.047C-18.61 289.65 -19.583 289.975 -19.863 290.657C-20.973 293.364 -24.113 295.459 -26 303.001C-25.619 303.91 -21.488 296.359 -21.001 295.661C-20.165 294.465 -20.047 297.322 -18.771 296.656C-18.72 296.629 -18.534 296.867 -18.4 297.001C-18.206 296.721 -17.988 296.492 -17.6 296.601C-17.6 296.201 -17.734 295.645 -17.533 295.486C-16.296 294.509 -16.38 293.441 -15.6 292.201C-15.142 292.99 -14.081 292.271 -13.6 293.001z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M46.2 347.401C46.2 347.401 53.6 327.001 49.2 315.801C49.2 315.801 60.6 337.401 56 348.601C56 348.601 55.6 338.201 51.6 333.201C51.6 333.201 47.6 346.001 46.2 347.401z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M31.4 344.801C31.4 344.801 36.8 336.001 28.8 317.601C28.8 317.601 28 338.001 21.2 349.001C21.2 349.001 35.4 328.801 31.4 344.801z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M21.4 342.801C21.4 342.801 21.2 322.801 21.6 319.801C21.6 319.801 17.8 336.401 7.6 346.001C7.6 346.001 22 334.001 21.4 342.801z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M11.8 310.801C11.8 310.801 17.8 324.401 7.8 342.801C7.8 342.801 14.2 330.601 9.4 323.601C9.4 323.601 12 320.201 11.8 310.801z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-7.4 342.401C-7.4 342.401 -8.4 326.801 -6.6 324.601C-6.6 324.601 -6.4 318.201 -6.8 317.201C-6.8 317.201 -2.8 311.001 -2.6 318.401C-2.6 318.401 -1.2 326.201 1.6 330.801C1.6 330.801 5.2 336.201 5 342.601C5 342.601 -5 312.401 -7.4 342.401z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-11 314.801C-11 314.801 -17.6 325.601 -19.4 344.601C-19.4 344.601 -20.8 338.401 -17 324.001C-17 324.001 -12.8 308.601 -11 314.801z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-32.8 334.601C-32.8 334.601 -27.8 329.201 -26.4 324.201C-26.4 324.201 -22.8 308.401 -29.2 317.001C-29.2 317.001 -29 325.001 -37.2 332.401C-37.2 332.401 -32.4 330.001 -32.8 334.601z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-38.6 329.601C-38.6 329.601 -35.2 312.201 -34.4 311.401C-34.4 311.401 -32.6 308.001 -35.4 311.201C-35.4 311.201 -44.2 330.401 -48.2 337.001C-48.2 337.001 -40.2 327.801 -38.6 329.601z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-44.4 313.001C-44.4 313.001 -32.8 290.601 -54.6 316.401C-54.6 316.401 -43.6 306.601 -44.4 313.001z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M-59.8 298.401C-59.8 298.401 -55 279.601 -52.4 279.801C-52.4 279.801 -44.2 270.801 -50.8 281.401C-50.8 281.401 -56.8 291.001 -56.2 300.801C-56.2 300.801 -56.8 291.201 -59.8 298.401z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M270.5 287C270.5 287 258.5 277 256 273.5C256 273.5 269.5 292 269.5 299C269.5 299 272 291.5 270.5 287z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M276 265C276 265 255 250 251.5 242.5C251.5 242.5 278 272 278 276.5C278 276.5 278.5 267.5 276 265z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M293 111C293 111 281 103 279.5 105C279.5 105 290 111.5 292.5 120C292.5 120 291 111 293 111z"/>
+ </g>
+ <g style="fill: #cccccc">
+ <path d="M301.5 191.5L284 179.5C284 179.5 303 196.5 303.5 200.5L301.5 191.5z"/>
+ </g>
+ <g style="stroke:#000000">
+ <path d="M-89.25 169L-67.25 173.75"/>
+ </g>
+ <g style="stroke:#000000">
+ <path d="M-39 331C-39 331 -39.5 327.5 -48.5 338"/>
+ </g>
+ <g style="stroke:#000000">
+ <path d="M-33.5 336C-33.5 336 -31.5 329.5 -38 334"/>
+ </g>
+ <g style="stroke:#000000">
+ <path d="M20.5 344.5C20.5 344.5 22 333.5 10.5 346.5"/>
+ </g>
+</g>
+</svg>
+
diff --git a/ksvg/test/tigert.svg b/ksvg/test/tigert.svg
new file mode 100644
index 00000000..a8656d04
--- /dev/null
+++ b/ksvg/test/tigert.svg
@@ -0,0 +1,388 @@
+<svg width="20cm" height="20cm" >
+ <g id="g2072"
+ style="fill: #000000"> <path
+ d="M303.898 424.298C299.743 413.438 297.099 401.727 289.828 392.379C281.708 384.07 275.096 373.115 265.089 366.976C256.116 362.254 247.049 357.628 236.568 356.588C235.245 357.816 234.017 356.115 232.696 355.834C231.47 356.683 230.901 358.193 230.239 359.516L227.69 356.588C226.275 357.344 226.842 359.798 224.763 359.516C216.831 353.282 209.089 347.144 198.323 347.523C187.745 349.601 177.642 352.622 169.709 361.122C166.498 363.105 166.498 368.205 161.775 367.164C152.617 371.037 143.174 376.798 137.128 385.769C127.215 397.005 120.133 409.376 117.109 423.355C112.387 436.007 114.655 451.493 110.121 464.15C108.611 473.213 109.934 482.186 110.783 490.684C112.2 493.801 112.578 497.391 114.655 500.222C116.261 510.419 117.394 520.809 121.641 529.875C123.53 537.429 119.659 548.951 129.385 551.689C130.425 552.538 131.748 550.744 132.599 552.351C132.88 552.066 133.161 551.499 133.731 551.406C134.644 564.975 138.955 577.446 140.36 590.69C134.497 594.154 129.989 601.837 128.254 606.949C126.975 613.065 127.705 624.78 134.46 631.14C143.042 637.349 147.802 644.14 156.111 648.862C168.01 660.381 179.058 674.642 193.979 681.345C203.14 684.745 211.922 690.697 222.308 689.938C231.184 692.679 238.929 687.955 246.764 687.014C255.076 682.949 263.858 676.153 268.107 667.464C273.208 658.684 284.634 651.6 280.573 639.793C280.196 638.569 280.386 637.905 279.63 636.867C280.103 631.107 280.386 625.914 278.024 620.816C278.31 617.034 273.681 615.242 274.435 611.275C285.39 595.884 296.535 580.584 300.688 562.359C301.163 555.749 302.387 550.272 303.239 543.474C303.804 530.818 304.09 516.561 302.955 504.564L303.898 503.811C304.94 500.412 304.56 496.352 305.883 492.95C313.72 471.043 310.037 445.733 303.898 424.298z"
+ id="path2073">
+ </path>
+
+ </g>
+ <g
+ id="g2074"
+ style="fill: #e2c78c"> <path
+ d="M213.716 352.432C217.307 354.888 220.325 357.532 223.442 360.837C224.197 360.46 224.954 362.162 225.237 360.65L226.18 361.97C227.69 361.405 226.842 359.423 227.69 358.384C228.54 359.516 229.675 360.65 231.092 360.837C231.94 359.798 231.659 358.003 232.696 357.249C235.908 359.61 241.195 357.532 244.5 359.516C251.679 360.837 257.343 365.653 264.238 367.636C269.524 372.076 275.284 376.798 279.44 382.651C283.783 386.711 287.469 391.907 291.148 396.629C297.574 405.034 299.179 415.231 302.766 424.767C305.599 429.775 304.56 436.386 307.015 441.485C308.149 448.094 309.563 455.082 309.281 461.692L309.756 462.166C309.188 469.721 309.281 477.747 307.015 484.357C307.015 487.378 305.315 490.211 305.032 493.422C303.994 495.69 303.616 498.43 303.239 500.695C304.183 490.874 297.287 481.62 296.44 471.231C296.535 462.354 297.099 453.381 296.815 444.695C295.684 441.39 295.495 437.613 294.36 434.308C290.019 419.008 280.292 405.6 268.296 393.986C258.571 386.148 248.279 378.97 236.382 376.043C234.868 376.134 232.883 375.57 232.223 377.365C228.352 375.097 224.197 372.831 220.515 370.562C218.813 370.469 217.776 370.092 216.456 369.716C217.114 370.943 219.288 370.753 220.515 371.698C223.348 374.058 227.501 375.191 230.714 377.647C225.992 377.269 221.554 378.592 219.098 382.651C215.886 379.724 212.109 373.871 206.916 375.57C188.217 379.348 183.402 406.827 162.72 405.504C157.718 405.504 153.371 401.727 151.578 397.385C156.677 399.744 163.57 400.218 167.915 395.968C176.224 388.413 181.606 376.517 193.507 376.043C193.791 375.759 194.073 375.57 193.979 375.097C192.846 374.248 191.426 376.043 190.578 374.436C184.063 377.837 177.263 382.275 172.92 388.98C174.997 382.934 177.073 375.191 184.25 372.831C184.441 372.453 185.196 372.266 184.912 371.698C182.081 370.469 180.57 373.587 178.304 375.097C171.502 381.802 173.203 393.702 162.909 397.385C158.851 399.273 155.165 396.249 151.105 395.968C148.934 396.817 151.011 399.179 151.578 400.5L155.259 404.183L146.573 406.827C128.819 420.615 137.98 445.828 142.324 463.015C141.095 461.977 139.866 461.127 138.453 460.561C137.128 462.26 138.923 464.338 138.642 466.415C136.089 475.103 130.614 482.469 128.726 491.344C128.63 495.878 127.876 500.883 128.44 505.697C124.853 501.545 122.964 496.352 121.925 490.968C120.698 491.817 120.511 493.989 120.32 495.029C118.904 494.084 117.674 490.78 115.789 491.817C116.825 492.856 113.898 494.084 115.127 495.69C114.844 496.162 114.37 495.878 113.994 495.878C113.237 493.046 110.971 490.211 112.2 487.095C109.084 476.328 110.858 465.023 113.692 454.635C116.335 435.935 117.109 415.609 127.781 400.312C131.748 391.813 139.396 385.106 145.721 378.119C150.349 373.587 156.015 371.602 161.306 368.77L162.909 368.77C159.981 373.209 156.394 377.269 152.05 380.574C151.767 381.518 152.995 381.895 153.371 382.651C153.844 382.747 154.033 382.369 154.315 382.181L154.315 380.574C159.511 375.57 163.476 369.148 168.86 364.71C169.425 364.048 169.616 363.105 169.519 362.444C174.715 357.816 180 352.906 186.517 352.056C191.145 350.45 196.057 347.523 201.25 349.317C205.687 349.033 210.031 350.262 213.716 352.432z"
+ id="path2075">
+ </path>
+
+ </g>
+ <g
+ id="g2076"
+ style="fill: #000000"> <path
+ d="M207.768 359.234C208.521 359.704 209.653 359.423 210.503 359.516C210.503 360.178 209.466 360.366 208.9 360.837C205.309 359.516 200.496 360.837 197.188 358.856C189.068 356.966 182.647 363.388 177.642 366.976C181.419 360.744 187.369 356.401 194.166 355.172C199.076 356.306 203.894 356.21 207.768 359.234z"
+ id="path2077">
+ </path>
+
+ </g>
+ <g
+ id="g2078"
+ style="fill: #b6ab70"> <path
+ d="M201.439 357.44C202.478 358.1 203.799 358.003 204.648 359.045C200.021 359.234 195.489 356.588 190.767 357.912L184.722 360.65C186.517 358.193 189.257 357.722 191.523 356.306C194.263 356.588 198.417 356.401 201.439 357.44z"
+ id="path2079">
+ </path>
+
+ </g>
+ <g
+ id="g2080"
+ style="fill: #000000"> <path
+ d="M215.982 370.187C213.81 370.187 212.206 368.205 209.843 369.242C210.788 368.393 212.678 368.393 214.188 369.054C214.943 369.148 215.606 369.526 215.982 370.187z"
+ id="path2081">
+ </path>
+
+ </g>
+ <g
+ id="g2082"
+ style="fill: #b6ab70"> <path
+ d="M217.965 383.502C217.208 384.354 216.17 387.185 214.376 386.43C209.938 383.974 205.405 380.197 199.834 381.708L195.772 382.841C200.307 379.632 204.745 375.853 210.788 376.986C213.242 379.062 216.359 380.385 217.965 383.502z"
+ id="path2083">
+ </path>
+
+ </g>
+ <g
+ id="g2084"
+ style="fill: #edd6c9"> <path
+ d="M264.238 392.568L267.635 394.834C274.812 402.388 282.273 410.038 286.9 418.821C293.227 431.002 297.193 444.789 295.684 459.616C293.701 470.759 296.815 480.958 300.688 490.211C300.972 494.461 302.671 498.711 301.351 502.96C303.746 523.207 302.653 544.205 298.934 562.359C296.452 574.47 292.122 580.646 287.341 590.137C282.809 595.899 279.157 602.776 274.626 608.537C272.644 601.643 277.458 595.223 275.758 588.14L272.831 589.935C272.452 587.195 275.477 585.402 274.435 582.944L270.091 585.212C270.468 583.136 271.037 581.151 272.169 579.357C272.263 579.829 271.885 580.584 272.644 580.868C276.325 578.415 278.401 574.543 278.685 570.291C278.401 565.665 275.758 561.227 271.885 558.961C266.503 557.732 259.422 559.62 256.494 553.481C255.549 552.632 256.778 550.839 255.172 550.272C253.754 550.084 252.812 550.839 251.96 551.879C250.354 549.894 249.978 546.683 250.827 544.228C249.409 543.568 247.522 544.984 246.106 545.74C244.312 547.25 242.234 549.045 241.762 551.215C241.386 551.689 240.722 551.406 240.158 551.406L239.31 550.554C238.173 550.839 238.268 552.066 237.702 552.822C235.529 553.388 233.735 546.683 232.223 551.689L232.223 552.16C228.258 553.293 226.558 544.417 222.308 548.288C222.687 550.554 221.741 552.916 220.515 554.804C219.853 553.861 218.813 553.01 217.965 552.16C217.019 552.916 217.307 554.71 216.456 555.749C214.471 559.62 210.222 561.322 206.443 561.414C204.556 561.792 203.14 560.752 201.439 560.752C200.212 558.961 198.984 556.882 199.173 554.804C198.605 554.71 198.795 555.749 198.323 555.088C192.087 560.282 185.668 567.176 182.835 575.013C181.703 578.128 181.231 581.529 182.457 584.739L185.102 582.002C178.585 596.921 181.231 616.186 188.973 630.069L179.719 624.402C172.543 617.981 167.253 610.144 161.588 602.4C161.682 601.736 161.494 601.077 160.925 600.606C159.793 600.983 159.511 602.209 159.981 603.156C166.592 610.426 171.502 619.869 179.908 626.196C183.497 627.897 186.707 630.444 190.106 632.618C190.957 634.978 192.657 637.813 195.299 638.661C195.396 638.094 195.112 636.773 195.586 636.018C197.472 636.206 198.605 638.094 200.307 638.661C207.954 646.12 218.813 645.837 227.501 650.75C228.634 650.369 227.975 648.955 228.164 648.009C230.997 649.806 233.735 651.6 236.568 653.394L238.173 650.75L239.777 652.259C241.572 651.314 242.99 649.521 244.312 647.725C250.262 644.611 256.87 639.51 259.422 632.997C259.422 633.565 259.706 634.037 260.176 634.411C262.16 634.037 262.633 631.576 263.955 630.54C267.071 627.048 270.468 624.214 272.169 620.15C278.881 634.152 263.364 648.485 256.022 655.942C248.467 663.78 238.552 670.579 227.69 667.748C224.481 668.124 223.16 667.182 219.853 666.992C211.072 667.087 203.516 661.328 195.586 657.927C193.222 655.658 190.294 654.243 187.369 653.015C171.03 645.837 161.775 629.786 148.839 617.604C146.573 613.732 144.497 609.766 141.191 606.271C141.756 599.377 141.945 592.201 141.381 585.684C138.264 574.543 135.618 563.019 135.526 551.028C137.223 553.671 136.564 557.638 139.584 559.62C140.152 558.299 138.642 556.789 138.264 555.275C138.264 550.178 134.201 546.683 133.258 541.961C129.481 532.613 132.88 522.885 131.179 512.688C130.142 512.026 130.614 510.044 128.913 510.231C127.025 511.081 129.859 512.31 128.251 513.347C130.234 517.691 122.305 521.09 128.065 524.679C127.876 529.401 128.819 534.123 131.179 538.088C132.408 541.302 132.219 545.172 134.106 548.006C134.106 549.327 133.447 550.178 132.312 550.744C128.913 551.028 125.796 549.045 124.381 546.021C122.586 541.489 123.155 535.446 123.058 530.818C118.904 521.658 117.487 511.459 115.789 501.357C115.789 500.412 115.599 499.279 116.45 498.617C115.315 498.144 115.599 496.065 116.261 495.216C116.353 494.651 117.204 494.271 117.394 493.612C119.189 494.933 119.281 497.294 120.98 498.899C115.504 503.432 120.886 512.026 120.792 518.543C121.076 518.826 121.263 519.298 121.641 519.298L122.115 518.826C120.98 513.065 119.659 506.928 120.511 500.883C121.36 498.899 122.775 500.788 123.909 500.695C125.324 503.903 128.065 506.736 129.573 509.76C130.804 508.911 130.234 506.549 130.046 505.228C129.01 492.762 132.69 481.146 139.584 471.418L140.056 463.96L143.644 465.563C143.929 461.127 141.661 457.064 140.717 452.815C136.564 438.652 133.731 418.349 147.516 407.96C151.294 407.582 154.22 405.128 158.378 405.693C161.682 406.732 164.987 407.206 168.386 406.636C176.885 404.088 183.402 396.156 189.444 389.451C190.014 389.545 190.578 389.735 191.239 389.641C191.335 386.711 194.734 387.847 196.435 386.901C200.115 387.092 204.178 386.901 206.254 390.585C208.144 389.074 209.653 386.711 212.297 386.901C212.678 388.693 214.753 387.185 215.511 388.318C217.307 386.618 218.719 384.635 221.176 383.502C220.043 380.953 223.442 380.385 224.763 379.251C227.596 379.062 231.184 378.309 233.356 380.385C233.735 380.007 234.49 380.103 234.49 379.441C234.49 378.874 233.452 378.592 233.828 377.837C238.835 377.08 243.649 379.441 247.899 381.708C253.567 385.203 259.137 388.035 264.238 392.568z"
+ id="path2085">
+ </path>
+
+ </g>
+ <g
+ id="g2086"
+ style="fill: #b6ab70"> <path
+ d="M210.977 385.769C209.466 386.807 207.768 387.279 206.443 388.693C203.14 385.203 197.568 386.052 193.317 386.24C194.546 383.22 199.362 382.841 202.384 382.181C205.405 382.934 208.614 383.408 210.977 385.769z"
+ id="path2087">
+ </path>
+
+ </g>
+ <g
+ id="g2088"
+ style="fill: #000000"> <path
+ d="M212.771 419.102L212.771 419.576C208.994 418.443 205.217 418.725 200.967 419.294C200.776 419.198 200.307 418.537 200.776 418.159C204.837 417.688 208.806 418.063 212.771 419.102z"
+ id="path2089">
+ </path>
+
+ </g>
+ <g
+ id="g2090"
+ style="fill: #000000"> <path
+ d="M210.503 427.887L210.503 428.356C201.911 427.319 192.94 425.903 184.722 428.83C184.628 427.981 185.574 427.887 186.046 427.507C193.033 426.092 199.928 426.47 206.916 427.035L210.503 427.887z"
+ id="path2091">
+ </path>
+
+ </g>
+ <g
+ id="g2092"
+ style="fill: #000000"> <path
+ d="M226.842 441.957L226.842 442.429C218.53 444.036 212.206 438.652 204.178 439.691L204.648 438.842C212.583 438.462 219.098 442.429 226.842 441.957z"
+ id="path2093">
+ </path>
+
+ </g>
+ <g
+ id="g2094"
+ style="fill: #000000"> <path
+ d="M269.619 443.092L269.619 443.751C267.447 442.148 263.387 443.184 260.555 442.9C259.61 443.562 259.137 443.28 257.911 443.374C258.288 442.523 259.706 442.148 260.838 441.957C263.955 443.374 267.071 441.012 269.619 443.092z"
+ id="path2095">
+ </path>
+
+ </g>
+ <g
+ id="g2096"
+ style="fill: #000000"> <path
+ d="M207.768 444.223C217.87 446.771 230.524 449.323 240.158 444.695L241.291 444.695L241.291 445.166C238.647 446.112 236.001 447.812 233.168 447.906C223.063 449.984 213.337 445.074 203.234 445.166C194.354 442.9 185.384 445.45 176.981 447.906L174.715 449.039L174.902 448.094C184.347 444.885 195.207 441.767 205.781 444.695L207.768 444.223z"
+ id="path2097">
+ </path>
+
+ </g>
+ <g
+ id="g2098"
+ style="fill: #000000"> <path
+ d="M289.642 470.949C292.003 473.025 292.378 476.328 293.227 478.692C290.68 479.73 290.961 476.328 289.356 475.292C288.033 472.457 285.202 474.064 283.029 474.346C275.19 472.457 269.053 477.464 262.819 480.769L261.688 479.636C258.477 480.862 255.076 481.712 252.433 484.545C252.056 484.263 251.11 484.451 251.11 483.696L251.11 482.563C249.978 482.373 248.845 483.602 247.708 484.17C248.09 481.995 246.576 479.164 249.032 477.747C252.433 474.913 256.209 472.931 260.176 471.231L260.367 472.551C268.677 469.532 277.739 473.025 286.239 469.624C287.75 469.248 288.602 470.285 289.642 470.949z"
+ id="path2099">
+ </path>
+
+ </g>
+ <g
+ id="g2100"
+ style="fill: #777777"> <path
+ d="M290.488 473.971L291.148 475.765C289.735 474.631 288.791 472.457 286.616 472.363C282.179 474.913 275.57 471.798 271.037 475.103L263.575 479.354L262.16 478.504C258.665 479.541 255.265 480.958 252.244 483.225C252.056 482.563 252.621 481.62 251.772 481.146L248.845 482.091C248.183 480.674 248.94 478.692 250.354 477.747C252.998 475.574 255.833 474.064 258.761 472.837C258.571 473.401 257.815 473.783 258.099 474.631C259.61 475.007 260.648 473.121 262.16 473.025C265.653 473.309 269.147 471.514 272.169 472.837C278.685 474.064 285.958 466.793 290.488 473.971z"
+ id="path2101">
+ </path>
+
+ </g>
+ <g
+ id="g2102"
+ style="fill: #000000"> <path
+ d="M184.25 475.765C185.857 472.649 188.312 476.707 190.389 477.369C192.562 476.99 194.073 472.837 196.718 475.765C198.131 476.328 199.267 475.481 200.588 476.426C201.157 477.275 201.157 478.692 201.439 479.354C199.076 477.275 198.131 484.076 195.112 481.62C193.979 483.98 191.712 482.373 189.918 482.563C188.407 482.657 186.8 479.825 185.857 482.091C180.758 477.747 173.392 477.179 166.592 477.369C163.665 479.258 160.361 481.995 157.054 483.884L152.995 487.567C153.467 483.037 158.566 479.354 161.306 475.292C166.878 470.949 174.997 474.064 181.324 474.631L184.25 475.765z"
+ id="path2103">
+ </path>
+
+ </g>
+ <g
+ id="g2104"
+ style="fill: #777777"> <path
+ d="M183.308 476.614C184.347 476.14 185.384 477.747 186.046 476.236C188.217 476.426 189.444 479.541 191.9 478.219L194.166 475.952C195.772 476.99 197.852 476.707 199.643 477.085C199.267 478.692 197.852 480.391 196.435 480.958L195.299 479.354C193.791 479.636 194.453 481.712 192.846 482.091C190.578 481.43 187.839 481.808 186.235 479.354C183.402 480.486 180.662 477.464 177.453 477.559C172.92 476.802 167.253 474.913 163.57 478.219C163.005 479.825 161.398 479.73 160.173 480.486L155.259 484.357C156.677 482.091 159.793 478.504 162.437 475.765C164.326 475.858 165.933 474.064 167.915 473.971C172.637 475.197 178.868 474.064 183.308 476.614z"
+ id="path2105">
+ </path>
+
+ </g>
+ <g
+ id="g2106"
+ style="fill: #000000"> <path
+ d="M281.708 490.684C281.988 491.062 282.841 490.874 282.558 491.629C280.765 491.344 278.212 491.44 276.42 490.495C270.091 495.312 260.459 493.046 253.567 495.878C250.543 497.011 247.522 496.352 245.443 494.084C246.295 491.44 248.75 488.7 251.297 487.285C248.09 487.756 244.122 488.606 242.234 492.101C239.685 495.312 240.533 499.938 239.777 503.811C239.31 509.948 242.141 515.142 243.367 520.809C248.279 524.585 256.682 529.024 254.888 536.956C254.132 538.939 254.038 541.489 251.486 542.34C251.205 541.111 253.377 540.45 253.567 538.939C254.699 536.39 254.606 532.517 252.904 530.159C251.017 526.474 247.428 525.908 244.975 523.075C244.405 524.398 246.201 525.908 244.312 526.474C243.935 524.02 243.273 521.658 242.045 519.486C239.31 511.365 237.324 500.125 241.101 492.101C244.975 487.475 250.449 484.923 256.778 485.301C265.558 483.98 274.151 487.095 281.708 490.684z"
+ id="path2107">
+ </path>
+
+ </g>
+ <g
+ id="g2108"
+ style="fill: #ffffff"> <path
+ d="M261.688 488.228C261.688 489.08 260.555 489.268 259.894 489.549C258.947 490.022 259.042 488.796 258.571 488.418C258.383 487.095 259.987 487.946 260.367 487.095C261.026 487.002 261.5 487.756 261.688 488.228z"
+ id="path2109">
+ </path>
+
+ </g>
+ <g
+ id="g2110"
+ style="fill: #000000"> <path
+ d="M203.988 488.89C205.122 489.173 206.443 490.495 207.575 489.361C209.37 490.59 212.206 489.457 213.242 492.101C214.376 497.766 210.788 502.865 207.768 507.21C209.653 502.394 213.716 498.144 212.109 492.101C210.788 491.156 208.994 490.968 207.575 491.156C207.768 493.328 206.351 495.404 204.648 496.162C198.605 496.448 192.562 498.711 186.991 495.878C182.081 496.728 178.018 493.422 173.582 495.216C169.331 495.312 165.838 497.956 161.306 496.823C165.838 495.502 171.22 495.404 175.187 492.289C183.497 490.59 191.335 486.246 200.307 487.567C201.157 488.985 202.762 488.418 203.988 488.89z"
+ id="path2111">
+ </path>
+
+ </g>
+ <g
+ id="g2112"
+ style="fill: #dddddd"> <path
+ d="M274.909 490.022C271.885 491.344 269.053 493.14 265.558 493.234C266.032 491.344 267.635 489.08 266.032 487.285C269.147 487.756 271.793 489.361 274.909 490.022z"
+ id="path2113">
+ </path>
+
+ </g>
+ <g
+ id="g2114"
+ style="fill: #dddddd"> <path
+ d="M256.022 493.422C254.038 495.029 250.543 495.974 247.899 494.557C247.618 493.895 246.576 494.179 246.957 493.234C248.653 490.495 251.679 489.361 254.227 487.946C253.19 490.211 255.076 492.007 256.022 493.422z"
+ id="path2115">
+ </path>
+
+ </g>
+ <g
+ id="g2116"
+ style="fill: #dddddd"> <path
+ d="M206.254 491.344C205.973 492.856 205.5 494.461 203.988 495.216L202.102 495.69C203.423 495.029 204.272 493.707 204.178 492.289C204.272 491.817 204.084 491.44 203.704 491.156C201.816 491.344 202.854 493.612 201.25 494.084C198.417 494.651 195.868 495.878 193.317 495.216C194.263 493.895 194.263 492.101 194.166 490.211C197.472 488.512 200.399 489.741 203.234 490.211L206.254 491.344z"
+ id="path2117">
+ </path>
+
+ </g>
+ <g
+ id="g2118"
+ style="fill: #ffffff"> <path
+ d="M188.312 490.211C188.407 491.062 188.217 491.726 187.65 492.289C187.178 492.385 186.8 492.194 186.517 491.817C186.613 490.874 186.991 489.835 188.312 490.211z"
+ id="path2119">
+ </path>
+
+ </g>
+ <g
+ id="g2120"
+ style="fill: #dddddd"> <path
+ d="M179.719 492.289C179.247 492.762 179.53 493.518 179.437 494.084C178.207 493.989 177.073 493.328 175.847 493.895C176.51 492.95 178.304 492.575 179.719 492.289z"
+ id="path2121">
+ </path>
+
+ </g>
+ <g
+ id="g2122"
+ style="fill: #edd6c9"> <path
+ d="M123.058 498.899C120.886 499.279 121.454 496.255 121.641 495.029C121.925 496.448 122.775 497.484 123.058 498.899z"
+ id="path2123">
+ </path>
+
+ </g>
+ <g
+ id="g2124"
+ style="fill: #000000"> <path
+ d="M243.367 498.144C244.5 502.113 247.994 505.322 251.772 506.832C247.522 507.022 244.594 502.582 242.897 499.279L242.897 498.144L243.367 498.144z"
+ id="path2125">
+ </path>
+
+ </g>
+ <g
+ id="g2126"
+ style="fill: #ffffff"> <path
+ d="M129.859 513.633L130.046 514.292L129.859 513.633z"
+ id="path2127">
+ </path>
+
+ </g>
+ <g
+ id="g2128"
+ style="fill: #edd6c9"> <path
+ d="M130.046 532.423C128.251 529.024 131.936 523.734 127.781 521.752C127.403 519.77 129.197 518.069 130.046 516.275C130.708 520.902 129.764 527.797 130.046 532.423z"
+ id="path2129">
+ </path>
+
+ </g>
+ <g
+ id="g2130"
+ style="fill: #000000"> <path
+ d="M213.904 527.229C210.315 527.797 208.806 531.952 208.049 535.161C207.768 538.752 209.089 541.772 211.638 544.228C213.242 545.644 215.414 545.644 217.307 546.211L217.307 547.157C213.056 547.061 209.653 543.943 207.575 540.356C206.254 536.106 207.672 531.952 209.843 528.551C210.882 527.797 214.093 524.208 213.904 527.229z"
+ id="path2131">
+ </path>
+
+ </g>
+ <g
+ id="g2132"
+ style="fill: #000000"> <path
+ d="M146.195 531.479C145.158 541.302 147.233 551.499 151.389 560.091C146.101 552.16 144.497 541.489 145.721 531.479L146.195 531.479z"
+ id="path2133">
+ </path>
+
+ </g>
+ <g
+ id="g2134"
+ style="fill: #000000"> <path
+ d="M244.5 538.28C245.917 538.28 247.994 537.239 249.504 538.28C248.279 540.546 244.5 539.601 243.179 541.489C240.63 541.489 239.968 544.795 237.702 545.55C234.49 548.477 230.997 545.928 227.501 545.362C224.386 545.078 223.536 540.072 220.043 541.489C218.152 540.167 217.87 544.039 215.982 542.151C215.606 541.207 214.471 540.263 215.037 539.224C218.53 536.2 221.835 540.64 224.763 541.961C226.937 545.55 232.223 546.211 236.096 545.74C240.346 542.623 244.219 538.939 245.443 533.746L246.106 533.746L244.5 538.28z"
+ id="path2135">
+ </path>
+
+ </g>
+ <g
+ id="g2136"
+ style="fill: #000000"> <path
+ d="M289.356 560.752C288.129 557.921 289.735 554.992 289.828 552.16C290.584 549.139 290.868 545.74 292.757 543.474C291.245 548.571 290.112 555.088 289.356 560.752z"
+ id="path2137">
+ </path>
+
+ </g>
+ <g
+ id="g2138"
+ style="fill: #8e8e8e"> <path
+ d="M251.96 553.955L254.227 551.689C255.358 556.031 259.894 559.339 264.426 559.81C267.353 559.339 271.037 559.526 273.491 561.414C275.664 564.532 277.648 567.648 277.176 571.804C276.607 574.258 275.758 576.808 273.776 578.415C273.019 578.035 274.34 575.863 272.644 576.333C269.715 579.545 268.677 584.364 269.242 588.14C271.037 587.573 271.037 585.307 273.019 585.025C272.169 586.533 270.942 590.122 272.357 592.482L274.626 590.216C275.853 597.205 271.413 603.439 273.491 610.613C272.927 611.088 272.736 611.654 272.831 612.408C273.019 612.597 273.208 612.977 273.491 612.882C273.776 613.446 273.113 613.353 272.831 613.542C272.075 620.908 266.126 627.235 260.838 632.332C259.706 631.862 261.31 630.731 260.176 630.069C258.477 631.483 258.099 633.372 257.627 635.26C253.281 642.628 244.975 644.423 239.968 650.75L238.647 649.146C237.418 649.332 237.134 650.652 236.382 651.408C233.452 650.183 229.675 648.009 227.312 645.272C226.463 646.218 226.937 647.633 226.842 648.862C218.438 644.798 208.144 644.705 201.25 637.529C199.362 636.867 197.472 635.545 196.245 633.753C194.734 633.846 195.016 635.828 193.791 636.018C186.613 624.309 181.606 611.181 182.835 596.545C183.778 591.349 184.347 585.968 187.65 581.811C187.462 581.248 188.03 580.303 187.178 580.017C185.762 580.491 184.159 580.773 183.119 582.002C183.213 572.463 189.444 564.908 196.245 557.825L198.323 556.411C198.323 556.789 198.04 557.354 198.513 557.544L199.173 557.544C198.984 559.054 199.928 560.66 201.25 561.886C205.592 562.642 210.127 563.019 213.904 560.282C215.982 558.489 217.493 556.315 218.719 554.427C219.853 555.182 219.288 556.694 220.043 557.544C221.647 554.898 223.536 551.973 223.914 548.477C227.69 549.421 229.294 552.916 232.223 555.275C233.735 554.804 233.641 553.199 234.301 552.16C235.15 553.388 236.664 553.955 237.889 554.617C239.023 554.332 239.023 553.199 239.31 552.351C240.158 552.822 241.478 553.388 242.234 552.538C243.367 549.705 246.013 546.118 249.223 545.55C248.371 548.856 249.601 551.782 251.96 553.955z"
+ id="path2139">
+ </path>
+
+ </g>
+ <g
+ id="g2140"
+ style="fill: #000000"> <path
+ d="M262.16 563.868L261.026 566.42C258.854 564.813 255.457 566.608 252.621 565.759C251.486 566.043 250.639 563.211 249.978 565.003C250.449 565.665 249.978 566.42 249.504 566.895C247.808 566.988 246.485 565.853 245.161 565.003C244.69 566.136 244.312 567.176 243.839 568.213C242.705 568.403 241.386 567.932 240.158 567.741C238.552 564.436 237.324 568.213 235.623 568.877C234.397 569.252 234.775 567.741 234.113 567.271L229.769 569.348L229.294 570.009C228.731 569.348 229.203 568.119 228.445 567.554C225.705 570.385 221.271 570.291 217.776 571.614L217.587 568.877C213.527 572.369 208.144 572.463 203.704 575.013C202.949 573.787 204.648 572.653 203.704 571.424C203.649 571.502 203.595 571.589 203.541 571.671L203.541 571.524C200.425 573.223 195.299 577.184 193.979 580.491C193.883 582.85 192.087 585.684 193.791 587.667C194.64 585.59 195.396 583.418 197.188 581.623C198.131 581.057 199.267 580.303 200.307 580.681C200.307 582.472 200.212 584.457 201.25 585.684C201.911 585.212 202.194 584.173 203.045 583.606C204.272 581.435 206.632 582.286 208.71 582.002C208.427 584.832 208.144 588.612 209.843 591.067C210.599 589.651 210.977 588.045 212.109 586.817C213.148 588.14 213.43 590.404 215.321 590.878C216.831 589.273 218.152 585.872 220.703 586.346C222.215 588.516 224.009 591.635 227.031 591.54C228.731 592.013 230.239 590.878 231.374 589.555C231.659 590.404 232.412 591.067 233.356 591.067C239.777 588.328 246.957 589.651 252.433 584.739L253.754 587.953C257.154 588.801 259.61 591.729 263.292 591.54L263.575 590.69C262.254 588.421 260.555 585.968 260.555 583.418C261.875 584.457 264.048 584.929 265.558 584.081C266.503 581.905 264.897 579.545 265.089 577.09C264.993 575.863 263.67 574.919 263.955 573.88L266.692 573.692C267.353 572.182 265.94 570.67 266.692 569.158L267.164 570.291C268.107 569.915 267.259 568.877 267.827 568.403C269.999 568.119 271.603 569.726 272.644 571.143C272.644 564.719 263.575 570.103 262.16 563.868z"
+ id="path2141">
+ </path>
+
+ </g>
+ <g
+ id="g2142"
+ style="fill: #eca6a3"> <path
+ d="M257.44 566.895C252.433 570.952 246.764 573.692 240.63 575.013C236.096 576.526 231.847 574.258 227.312 574.352C224.009 575.013 221.176 573.219 217.965 573.219C220.703 570.952 224.954 571.33 227.975 569.348C228.352 570.198 228.071 571.33 229.107 571.804C230.147 569.822 231.659 571.897 232.979 571.804C237.134 571.71 242.141 571.614 245.161 568.403L245.443 566.895C247.049 567.271 248.75 568.877 250.354 567.741C250.924 565.288 254.227 567.46 255.833 567.082C256.4 567.082 256.778 566.702 257.44 566.895z"
+ id="path2143">
+ </path>
+
+ </g>
+ <g
+ id="g2144"
+ style="fill: #edd6c9"> <path
+ d="M242.045 569.158C240.253 569.822 238.552 570.573 236.382 570.291L238.363 568.027C239.685 568.119 240.441 569.726 242.045 569.158z"
+ id="path2145">
+ </path>
+
+ </g>
+ <g
+ id="g2146"
+ style="fill: #000000"> <path
+ d="M172.92 570.479C174.619 576.147 172.071 583.514 176.036 588.14C170.748 583.041 174.241 574.73 171.313 568.403C172.071 568.684 172.543 569.726 172.92 570.479z"
+ id="path2147">
+ </path>
+
+ </g>
+ <g
+ id="g2148"
+ style="fill: #eca6a3"> <path
+ d="M246.576 581.151C243.557 582.002 240.06 583.231 237.041 582.757C228.919 581.151 220.043 579.168 214.376 573.88C222.875 574.919 229.485 576.333 238.173 577.09C244.69 574.73 251.679 573.88 256.966 568.684C255.457 573.598 252.527 580.208 246.576 581.151z"
+ id="path2149">
+ </path>
+
+ </g>
+ <g
+ id="g2150"
+ style="fill: #edd6c9"> <path
+ d="M234.49 570.479C233.544 570.479 232.507 570.67 231.847 569.822C232.412 568.877 233.641 568.591 234.301 569.536C234.775 569.726 234.49 570.198 234.49 570.479z"
+ id="path2151">
+ </path>
+
+ </g>
+ <g
+ id="g2152"
+ style="fill: #eca6a3"> <path
+ d="M216.456 572.935C215.321 572.841 214.279 572.369 213.056 572.558C214.188 572.086 215.414 571.71 216.456 570.67L216.456 572.935z"
+ id="path2153">
+ </path>
+
+ </g>
+ <g
+ id="g2154"
+ style="fill: #000000"> <path
+ d="M228.826 598.812C228.634 600.699 228.164 603.909 229.294 605.798C230.524 603.909 232.883 601.549 234.963 601.077C235.245 602.4 234.207 604.289 234.49 605.798C236.001 605.987 236.757 603.156 238.647 603.53C238.268 606.365 236.282 609.671 237.702 612.882C238.739 615.715 239.115 618.928 240.911 621.474C236.664 618.928 237.889 613.353 236.382 609.198L237.515 604.948C236.282 605.233 235.057 607.027 234.49 608.347C233.641 606.933 233.356 604.57 233.828 602.682C231.94 602.965 230.428 604.948 229.959 606.933C230.239 607.498 229.675 607.782 229.578 608.065L229.107 608.065C228.164 605.328 226.937 601.736 228.445 598.812L228.826 598.812z"
+ id="path2155">
+ </path>
+
+ </g>
+ <g
+ id="g2156"
+ style="fill: #000000"> <path
+ d="M265.371 616.281C264.707 617.981 263.955 619.775 263.292 621.285C262.912 618.736 264.897 616.751 265.089 614.204C264.803 608.631 263.764 603.062 259.042 599.754L259.422 598.999C265.371 602.776 266.313 610.426 265.371 616.281z"
+ id="path2157">
+ </path>
+
+ </g>
+ <g
+ id="g2158"
+ style="fill: #000000"> <path
+ d="M226.558 599.282C220.043 605.609 216.644 613.826 218.248 623.08L219.098 623.93C219.002 624.402 218.53 624.119 218.248 624.214C217.307 623.178 216.737 621.474 217.307 620.344C216.831 612.502 220.515 605.328 225.705 599.282L226.558 599.282z"
+ id="path2159">
+ </path>
+
+ </g>
+ <g
+ id="g2160"
+ style="fill: #000000"> <path
+ d="M206.916 605.139C203.327 609.103 202.384 614.392 202.571 619.678L202.384 612.408C204.46 608.631 206.351 604.289 210.031 601.549C210.503 603.345 207.768 603.439 206.916 605.139z"
+ id="path2161">
+ </path>
+
+ </g>
+ <g
+ id="g2162"
+ style="fill: #000000"> <path
+ d="M250.354 608.065C250.924 610.048 251.394 612.597 250.827 614.485C250.543 611.088 249.693 607.216 247.428 604.948C249.317 604.854 249.693 606.933 250.354 608.065z"
+ id="path2163">
+ </path>
+
+ </g>
+ <g
+ id="g2164"
+ style="fill: #edd6c9"> <path
+ d="M265.497 572.982L262.478 572.791C262.194 572.886 261.627 573.266 261.817 573.738C264.46 576.381 265.405 580.063 264.364 583.652C262.569 584.03 261.154 583.275 259.832 582.52C258.89 583.182 259.832 584.218 259.832 585.069C261.438 586.864 261.249 588.94 261.817 590.922C259.267 590.17 256.623 588.658 254.545 587.052L254.828 586.393L253.695 585.919C251.239 583.463 255.204 581.858 255.961 579.782C255.773 579.402 255.393 579.686 255.017 579.591C251.428 586.864 243.778 588.089 236.697 588.847C235.279 589.32 233.39 590.829 232.163 589.601C230.843 585.731 229.235 592.342 226.685 590.735C224.514 590.735 223.099 588.658 221.682 587.052C220.737 586.58 221.682 585.164 221.022 584.786C218.378 585.258 216.394 587.997 214.504 589.792L214.033 589.32C212.806 588.185 213.274 585.919 212.238 585.069C211.766 586.58 210.16 587.619 209.499 589.13C208.461 586.864 209.026 583.369 209.499 580.916C206.1 581.199 203.362 581.009 201.093 583.937C199.866 582.615 201.472 581.292 201.379 579.782C198.829 579.309 195.715 581.102 194.107 582.991C194.019 579.076 199.398 575.568 202.461 573.121C201.981 574.338 201.788 575.754 202.228 577.136C205.251 575.626 208.084 572.323 211.766 573.925C219.037 580.16 229.142 583.275 238.963 584.125C243.401 582.52 248.785 583.087 252.275 579.119C256.055 575.72 255.961 570.338 259.362 567.127L261.154 568.259C262.004 567.882 261.627 567.033 262.098 566.467C263.043 567.6 265.122 567.789 266.16 568.921C264.177 569.677 266.067 571.849 265.497 572.982z"
+ id="path2165">
+ </path>
+
+ </g>
+ <g
+ id="g2166"
+ style="fill: #3c0300"> <path
+ d="M274.737 615.47C277.006 619.721 278.608 624.253 278.988 629.259C280.497 635.963 276.06 640.873 273.603 646.256C272.565 648.709 270.205 650.6 269.449 653.243L269.92 653.243C273.509 648.523 276.06 643.421 278.799 638.322L280.593 641.723C282.197 653.526 269.828 660.986 264.918 670.524C260.949 677.893 253.302 683.085 246.124 686.104C238.948 687.524 232.374 690.411 225.008 688.709C214.335 690.221 205.989 684.501 197.019 681.857C192.768 680.631 189.275 677.985 185.402 675.909C180.68 672.224 176.526 667.88 172.465 663.726C165.034 656.621 158.772 648.239 149.424 643.045C145.648 639.171 141.664 635.577 137.417 631.896C135.052 630.762 133.665 628.904 132.153 626.634C128.28 620.78 127.888 608.866 128.801 607.131C129.805 604.027 135.284 594.641 140.254 591.2C140.681 595.533 140.793 599.946 140.356 604.516L139.225 605.273C142.34 609.143 145.459 613.485 147.817 617.926C161.322 631.239 171.048 648.789 188.707 655.307C191.823 656.721 195.468 660.335 198.966 661.093C206.236 665.908 214.3 667.599 222.988 668.447C233.374 670.998 243.755 668.147 251.402 661.631C260.44 652.685 273.417 642.385 274.737 627.933C275.398 623.213 270.392 619.153 273.792 614.998L274.737 615.47z"
+ id="path2167">
+ </path>
+
+ </g>
+
+ </g>
+
+</svg>
diff --git a/ksvg/test/tux.svg b/ksvg/test/tux.svg
new file mode 100644
index 00000000..4b5981e1
--- /dev/null
+++ b/ksvg/test/tux.svg
@@ -0,0 +1,298 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG August 1999//EN"
+"http://www.w3.org/Graphics/SVG/SVG-19990812.dtd">
+<svg
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/Graphics/SVG/SVG-19991203.dtd"
+ width = "595.7"
+ height = "841.89"
+ sodipodi:docname="/home/lauris/src/sodipodi/samples/tux.svg"
+ sodipodi:docbase="/home/lauris/src/sodipodi/samples/"
+ transform="matrix (1.0 0.0 0.0 -1.0 0.0 841.889764)"
+ id="svg2">
+ <g id="g3"> <path
+ transform="matrix(1.000000 0.000000 0.000000 1.000000 -188.771027 11.293993)"
+ id="path4"
+ style="stroke-width:1; stroke:none; fill-opacity:100%; fill:#ffffff; "
+ d="M 344.427 534.692 L 396.057 616.976 L 463.014 650.858 L 564.66 617.783 L 625.97 522.591 L 619.517 433.852 L 569.5 322.526 L 546.106 278.157 L 421.065 279.77 L 414.611 317.686 L 371.049 391.096 L 342.007 470.961 L 344.427 534.692 z ">
+ </path>
+ <g
+ transform="matrix(1.000000 0.000000 0.000000 1.000000 107.656192 -154.860742)"
+ id="g5"> <g
+ id="g6"
+ style="fill: #c1c1bf"> <path
+ id="path7"
+ d="M329.336 727.552C315.224 726.328 304.136 715.816 303.128 694.936C306.368 639.496 309.608 582.112 271.232 545.104C265.256 499.024 244.016 482.104 234.008 452.512L218.24 441.208L237.104 411.688L245.168 411.904L323.936 571.168L340.424 651.448L329.336 727.552z">
+ </path>
+
+ </g>
+ <g
+ id="g8"
+ style="fill: #c1c1bf"> <path
+ id="path9"
+ d="M136.232 439.696C133.856 455.248 132.56 470.512 134.792 485.272C118.376 507.592 105.92 530.128 104.48 553.312C92.024 586.504 62.432 614.584 67.544 680.104C84.176 697.456 107.432 713.584 127.376 730.36C152.432 751.312 137.528 778.96 102.248 772.408C94.4 763.768 76.616 709.624 42.92 676.288L49.544 632.584L81.368 547.408L120.968 484.048L125.36 456.688L119.816 386.776L124.424 361.216L136.232 439.696L136.232 439.696z">
+ </path>
+
+ </g>
+ <g
+ id="g10"
+ style="fill: #c1c1bf"> <path
+ id="path11"
+ d="M115.64 341.416C116.576 336.376 117.8 331.624 119.312 327.16L121.688 342.784L115.64 341.416z">
+ </path>
+
+ </g>
+ <g
+ id="g12"
+ style="fill: #c1c1bf"> <path
+ id="path13"
+ d="M120.968 500.464C108.368 523.792 103.976 546.256 132.92 550.216C117.008 553.888 97.208 568.648 77.192 593.488L77.624 543.016L101.456 503.272L120.968 500.464z">
+ </path>
+
+ </g>
+ <g
+ id="g14"
+ style="fill: #c1c1bf"> <path
+ id="path15"
+ d="M-33.256 818.488C10.52 838.144 41.408 837.064 69.272 850.96C91.304 862.552 113.552 861.184 126.944 847.144C138.32 832.456 146.744 831.736 163.52 830.224C190.952 828.568 217.736 828.28 241.928 830.8L269.576 833.032C269.072 864.064 328.04 867.88 345.392 844.336C366.344 819.424 395.144 808.264 419.84 790.192L289.304 725.536C255.824 806.464 131.048 827.632 113.768 763.264L-33.256 818.488z">
+ </path>
+
+ </g>
+ <g
+ id="g16"
+ style="fill: #c1c1bf"> <path
+ id="path17"
+ d="M286.424 711.568C273.824 711.496 260.936 715.6 261.944 732.16L266.192 776.44L304.424 756.64L286.424 711.568z">
+ </path>
+
+ </g>
+ <g
+ id="g18"
+ style="fill: #000000"> <path
+ id="path19"
+ d="M-37.36 821.224C7.136 840.88 38.6 839.728 66.968 853.696C89.36 865.216 111.968 863.92 125.648 849.808C137.24 835.192 145.808 834.472 162.872 832.96C190.736 831.232 218.024 831.016 242.648 833.464L270.728 835.768C270.224 866.8 330.272 870.544 347.912 847C369.224 822.088 398.528 811 423.656 792.856L290.816 728.272C256.76 809.128 129.824 830.296 112.256 766L-37.36 821.224z">
+ </path>
+
+ </g>
+ <g
+ id="g20"
+ style="fill: #b77200"> <path
+ id="path21"
+ d="M382.328 691.984C403.64 698.968 389.888 720.28 400.76 732.52C405.44 742.888 415.304 752.032 431.792 760.528C459.368 774.424 426.248 799.336 392.768 812.08C351.944 825.616 344.024 862.912 299.312 851.896C283.112 846.496 278.36 831.808 278.864 809.128C284.264 762.76 277.784 730.432 278.792 698.824C278.72 686.152 283.544 684.64 307.232 687.952C310.04 726.328 352.376 727.336 382.328 691.984z">
+ </path>
+
+ </g>
+ <g
+ id="g22"
+ style="fill: #f2b700"> <path
+ id="path23"
+ d="M339.632 826.624C371.6 814.312 403.856 798.112 429.848 782.128C437.84 777.448 438.92 765.928 427.688 762.328C403.352 748.504 390.104 731.224 392.912 708.76C393.344 700.912 383.696 692.56 381.104 700.048C359.864 771.472 291.32 767.656 300.752 696.952C301.256 694.864 301.76 692.776 302.264 690.76C289.952 688.24 285.2 690.976 285.776 700.408L295.28 806.608C297.656 830.8 317.312 836.128 339.632 826.624z">
+ </path>
+
+ </g>
+ <g
+ id="g24"
+ style="fill: #000000"> <path
+ id="path25"
+ d="M354.464 537.544C379.16 569.8 404.432 651.088 384.416 691.552C360.944 737.776 307.808 743.248 305.504 695.8C308.816 639.64 311.984 581.536 273.68 544.096C267.704 497.368 246.392 480.232 236.384 450.28L203.12 426.088L133.568 435.088C130.76 452.152 129.104 468.784 131.552 484.912C115.064 507.376 102.608 530.056 101.168 553.312C88.712 586.648 59.12 614.944 64.232 680.752C80.864 698.248 104.12 714.448 124.064 731.296C149.12 752.392 135.512 776.296 100.232 769.672C78.848 746.056 56.744 722.872 35.288 699.328C12.392 683.056 3.896 662.176 27.368 630.496C43.424 609.04 47.96 562.456 62 543.664C74.312 525.16 92.24 508.6 105.272 490.096C112.184 477.928 114.344 468.568 113.264 454.456L110.312 369.136C108.368 307.216 142.424 274.24 189.8 275.248C243.512 275.752 287.576 312.472 288.152 378.28C292.688 410.32 283.256 428.68 308.672 474.472C334.52 522.712 338.552 520.12 354.464 537.544z">
+ </path>
+
+ </g>
+ <g
+ id="g26"
+ style="fill: #c1c1bf"> <path
+ id="path27"
+ d="M261.296 503.632L263.528 512.2C257.696 501.688 250.712 483.616 241.928 475.696C239.264 473.536 235.808 473.608 233.72 475.624C222.056 486.928 193.112 510.112 169.928 507.088C152.072 505.288 134.648 493.264 130.832 480.232C128.816 470.872 129.752 463.168 130.976 455.32L240.704 453.52C238.472 463.168 253.088 487 261.296 503.632z">
+ </path>
+
+ </g>
+ <g
+ id="g28"
+ style="fill: #c1c1bf"> <path
+ id="path29"
+ d="M143.144 363.232C154.088 363.232 163.88 376.84 163.808 395.632C163.736 408.232 155.528 411.472 149.336 417.016C146.6 419.536 145.952 433.144 142.568 433.144C131.696 433.144 123.488 413.776 123.488 395.632C123.488 377.56 132.272 363.232 143.144 363.232z">
+ </path>
+
+ </g>
+ <g
+ id="g30"
+ style="fill: #ffffff"> <path
+ id="path31"
+ d="M144.368 375.04C154.088 375.04 160.856 379.936 161.648 391.312C162.224 399.16 160.136 411.76 154.664 414.424C152.144 415.648 143.432 426.664 140.408 426.52C128.096 425.944 125 402.112 125.936 390.736C126.8 379.36 134.72 375.04 144.368 375.04z">
+ </path>
+
+ </g>
+ <g
+ id="g32"
+ style="fill: #000000"> <path
+ id="path33"
+ d="M141.848 382.672C148.544 382.096 154.736 389.728 155.6 399.664C156.464 409.6 151.64 418.24 144.944 418.816C138.248 419.392 132.056 411.76 131.192 401.752C130.328 391.816 135.152 383.248 141.848 382.672z">
+ </path>
+
+ </g>
+ <g
+ id="g34"
+ style="fill: #c1c1bf"> <path
+ id="path35"
+ d="M151.064 397.288C151.424 399.088 149.408 400.024 148.832 398.224C148.256 395.992 146.888 393.328 145.088 391.168C143.936 389.872 145.088 388.432 146.528 389.44C149.048 391.528 150.488 394.12 151.064 397.288z">
+ </path>
+
+ </g>
+ <g
+ id="g36"
+ style="fill: #c1c1bf"> <path
+ id="path37"
+ d="M216.944 360.712C232.712 360.712 245.6 377.416 245.6 397.792C245.6 418.24 232.712 434.872 216.944 434.872C201.176 434.872 188.432 418.24 188.432 397.792C188.432 377.416 201.176 360.712 216.944 360.712z">
+ </path>
+
+ </g>
+ <g
+ id="g38"
+ style="fill: #ffffff"> <path
+ id="path39"
+ d="M224.792 374.968C235.664 378.856 241.928 387.424 242.72 396.568C243.656 407.08 239.408 418.96 230.264 425.944C227.672 427.888 197.72 416.08 195.992 411.616C193.4 405.208 191.816 392.896 193.76 385.624C194.552 382.744 197.216 378.568 201.176 376.336C207.44 372.808 216.656 372.088 224.792 374.968z">
+ </path>
+
+ </g>
+ <g
+ id="g40"
+ style="fill: #000000"> <path
+ id="path41"
+ d="M216.872 380.944C225.584 380.944 232.712 389.296 232.712 399.448C232.712 409.672 225.584 418.024 216.872 418.024C208.16 418.024 201.032 409.672 201.032 399.448C201.032 389.296 208.16 380.944 216.872 380.944z">
+ </path>
+
+ </g>
+ <g
+ id="g42"
+ style="fill: #c1c1bf"> <path
+ id="path43"
+ d="M227.096 392.392C228.104 394.048 226.448 395.776 225.224 394.12C223.784 392.104 221.408 389.944 218.888 388.432C217.232 387.568 217.808 385.624 219.68 386.2C222.92 387.28 225.368 389.368 227.096 392.392z">
+ </path>
+
+ </g>
+ <g
+ id="g44"
+ style="fill: #b77200"> <path
+ id="path45"
+ d="M164.96 404.488C172.376 402.328 184.112 403.048 192.248 404.632C200.384 406.792 222.056 418.24 245.024 430.696C247.976 432.208 248.84 437.104 245.024 438.688C239.12 439.12 249.272 453.664 238.904 458.848C223.352 462.88 198.44 485.992 186.128 487.864C179.288 489.376 172.232 489.592 164.6 487.864C140.552 482.968 134.216 455.608 122.912 450.064C119.816 446.824 121.4 441.208 122.408 440.056C123.632 434.224 149.696 406.216 164.96 404.488z">
+ </path>
+
+ </g>
+ <g
+ id="g46"
+ style="fill: #f2b700"> <path
+ id="path47"
+ d="M185.408 405.856C198.44 407.296 226.088 423.928 239.408 430.624C242.72 432.424 242.504 437.824 239.552 438.688C236.384 440.488 235.448 438.256 232.928 437.896C228.896 435.736 222.272 440.92 217.016 444.88C186.704 467.776 180.656 465.256 156.176 462.664C147.68 460.576 142.136 457.984 139.688 455.968C141.488 445.888 160.496 407.656 166.76 406.792C168.344 404.704 179.936 404.632 185.408 405.856z">
+ </path>
+
+ </g>
+ <g
+ id="g48"
+ style="fill: #b77200"> <path
+ id="path49"
+ d="M190.664 412.048L193.76 413.416C196.064 414.712 193.256 418.168 190.736 417.088L186.2 415.504C183.536 413.272 186.704 410.104 190.664 412.048z">
+ </path>
+
+ </g>
+ <g
+ id="g50"
+ style="fill: #b77200"> <path
+ id="path51"
+ d="M268.568 452.368C273.032 454.384 279.224 457.192 282.536 460.144C285.488 464.104 286.784 468.064 286.424 472.024C285.776 474.544 284.12 476.344 281.24 477.424C277.856 478.216 273.68 477.424 271.376 474.112C269.864 471.448 265.256 462.16 263.96 460.576C262.232 457.12 261.944 454.456 262.88 452.368C264.032 451.288 266.048 451 268.568 452.368z">
+ </path>
+
+ </g>
+ <g
+ id="g52"
+ style="fill: #c1c1bf"> <path
+ id="path53"
+ d="M273.752 461.584C275.48 462.376 277.928 463.456 279.224 464.68C280.376 466.264 280.88 467.776 280.736 469.36C280.52 470.296 279.8 471.016 278.72 471.448C277.352 471.808 275.768 471.448 274.832 470.152C274.256 469.144 272.456 465.472 271.952 464.824C271.232 463.456 271.088 462.448 271.448 461.584C271.952 461.152 272.744 461.08 273.752 461.584z">
+ </path>
+
+ </g>
+ <g
+ id="g54"
+ style="fill: #b77200"> <path
+ id="path55"
+ d="M238.616 358.552C239.048 359.2 238.976 359.776 238.4 360.28C237.896 360.784 237.176 360.712 236.24 360.208L231.632 356.248C231.056 355.744 230.912 354.952 231.272 354.088C232.28 353.44 233.144 353.44 233.936 354.088L238.616 358.552z">
+ </path>
+
+ </g>
+ <g
+ id="g56"
+ style="fill: #b77200"> <path
+ id="path57"
+ d="M235.592 305.992C239.624 308.224 240.848 313.912 238.184 318.592C235.592 323.2 230.12 325.144 226.016 322.84C221.984 320.536 220.76 314.92 223.424 310.24C226.016 305.56 231.488 303.688 235.592 305.992z">
+ </path>
+
+ </g>
+ <g
+ id="g58"
+ style="fill: #b77200"> <path
+ id="path59"
+ d="M374.912 680.536C378.296 683.128 373.256 687.376 371.024 686.296C369.152 685.648 367.784 683.488 366.92 682.408C366.128 681.184 366.2 679.168 366.92 678.448C367.712 677.44 369.728 677.656 371.024 678.52C372.32 679.168 373.616 679.888 374.912 680.536z">
+ </path>
+
+ </g>
+ <g
+ id="g60"
+ style="fill: #b77200"> <path
+ id="path61"
+ d="M297.44 551.512C338.984 572.896 350 611.56 332.072 664.192C330.992 666.64 334.16 668.368 335.24 666.064C354.824 610.336 341.432 571.312 299.024 548.56C296.864 547.552 295.28 550.432 297.44 551.512z">
+ </path>
+
+ </g>
+ <g
+ id="g62"
+ style="fill: #b77200"> <path
+ id="path63"
+ d="M72.008 569.512C38.312 627.256 38.096 662.68 62.504 681.328C63.728 682.264 64.448 680.032 63.296 679.168C36.296 655.48 48.896 615.52 74.168 570.88C74.888 569.584 72.512 568.432 72.008 569.512z">
+ </path>
+
+ </g>
+ <g
+ id="g64"
+ style="fill: #c1c1bf"> <path
+ id="path65"
+ d="M289.376 586.864C289.232 589.168 288.368 589.528 286.424 587.368C279.8 575.848 235.088 551.44 213.344 548.704C209.24 547.264 209.456 545.392 213.488 544.816C229.184 544.816 241.28 537.904 254.96 537.904C258.704 538.048 262.304 539.488 264.392 541.648C269.504 544.96 288.08 570.592 289.376 586.864z">
+ </path>
+
+ </g>
+ <g
+ id="g66"
+ style="fill: #c1c1bf"> <path
+ id="path67"
+ d="M180.152 546.832C180.872 550.792 163.808 545.68 164.744 556.696C165.032 559.72 160.496 561.376 160.64 556.696C160.64 548.272 161.072 548.416 152.72 546.832C151.208 546.76 151.352 544.528 152.72 544.816L152.72 544.816C158.696 546.472 166.76 542.872 166.4 538.84C166.256 537.472 168.56 537.688 168.488 538.84C167.984 545.248 181.664 542.152 180.152 546.832z">
+ </path>
+
+ </g>
+ <g
+ id="g68"
+ style="fill: #c1c1bf"> <path
+ id="path69"
+ d="M151.568 705.376C151.64 708.328 148.76 707.68 148.544 705.592C140.192 680.536 143.72 618.832 151.856 598.96C152.432 596.08 156.248 596.944 155.744 598.96C147.104 635.464 147.248 673.048 151.568 705.376z">
+ </path>
+
+ </g>
+ <g
+ id="g70"
+ style="fill: #b77200"> <path
+ id="path71"
+ d="M51.704 684.424C75.68 707.824 91.376 743.248 114.632 775.288C148.472 816.04 121.472 858.304 66.464 845.56C38.888 835.192 -0.784 836.344 -32.68 825.832C-55.072 820.36 -55.864 809.272 -44.416 787.6C-40.384 773.776 -40.024 751.312 -43.768 732.592C-45.784 718.408 -39.232 710.488 -24.112 708.832L-24.112 708.832C-11.296 708.688 6.56 713.872 16.28 686.44C23.552 673.336 40.976 672.976 51.704 684.424z">
+ </path>
+
+ </g>
+ <g
+ id="g72"
+ style="fill: #f2b700"> <path
+ id="path73"
+ d="M24.632 699.04C23.84 680.968 39.32 677.296 49.688 688.312C68.192 710.992 85.112 736.048 100.376 764.992C124.712 804.16 104.624 842.68 67.904 828.064C49.688 817.84 6.128 813.304 -17.344 809.128C-33.04 807.832 -35.128 797.608 -29.152 791.848C-20.944 782.416 -20.08 759.808 -27.856 740.512C-35.56 728.56 -21.088 715.384 -9.712 720.856C0.8 727.048 25.64 713.08 24.632 699.04z">
+ </path>
+
+ </g>
+
+ </g>
+
+ </g>
+
+</svg>
diff --git a/ksvg/test/tux2.svg b/ksvg/test/tux2.svg
new file mode 100644
index 00000000..7c43187f
--- /dev/null
+++ b/ksvg/test/tux2.svg
@@ -0,0 +1,287 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG August 1999//EN"
+"http://www.w3.org/Graphics/SVG/SVG-19990812.dtd">
+<svg
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns="http://www.w3.org/Graphics/SVG/SVG-19991203.dtd"
+ width = "595.7"
+ height = "841.89"
+ sodipodi:docname="/home/lauris/src/sodipodi/samples/tux.svg"
+ sodipodi:docbase="/home/lauris/src/sodipodi/samples/"
+ transform="matrix (1.0 0.0 0.0 -1.0 0.0 841.889764)"
+ id="svg2">
+ <g
+ id="g6"
+ style="fill: #c1c1bf"> <path
+ id="path7"
+ d="M329.336 727.552C315.224 726.328 304.136 715.816 303.128 694.936C306.368 639.496 309.608 582.112 271.232 545.104C265.256 499.024 244.016 482.104 234.008 452.512L218.24 441.208L237.104 411.688L245.168 411.904L323.936 571.168L340.424 651.448L329.336 727.552z">
+ </path>
+
+ </g>
+ <g
+ id="g8"
+ style="fill: #c1c1bf"> <path
+ id="path9"
+ d="M136.232 439.696C133.856 455.248 132.56 470.512 134.792 485.272C118.376 507.592 105.92 530.128 104.48 553.312C92.024 586.504 62.432 614.584 67.544 680.104C84.176 697.456 107.432 713.584 127.376 730.36C152.432 751.312 137.528 778.96 102.248 772.408C94.4 763.768 76.616 709.624 42.92 676.288L49.544 632.584L81.368 547.408L120.968 484.048L125.36 456.688L119.816 386.776L124.424 361.216L136.232 439.696L136.232 439.696z">
+ </path>
+
+ </g>
+ <g
+ id="g10"
+ style="fill: #c1c1bf"> <path
+ id="path11"
+ d="M115.64 341.416C116.576 336.376 117.8 331.624 119.312 327.16L121.688 342.784L115.64 341.416z">
+ </path>
+
+ </g>
+ <g
+ id="g12"
+ style="fill: #c1c1bf"> <path
+ id="path13"
+ d="M120.968 500.464C108.368 523.792 103.976 546.256 132.92 550.216C117.008 553.888 97.208 568.648 77.192 593.488L77.624 543.016L101.456 503.272L120.968 500.464z">
+ </path>
+
+ </g>
+ <g
+ id="g14"
+ style="fill: #c1c1bf"> <path
+ id="path15"
+ d="M-33.256 818.488C10.52 838.144 41.408 837.064 69.272 850.96C91.304 862.552 113.552 861.184 126.944 847.144C138.32 832.456 146.744 831.736 163.52 830.224C190.952 828.568 217.736 828.28 241.928 830.8L269.576 833.032C269.072 864.064 328.04 867.88 345.392 844.336C366.344 819.424 395.144 808.264 419.84 790.192L289.304 725.536C255.824 806.464 131.048 827.632 113.768 763.264L-33.256 818.488z">
+ </path>
+
+ </g>
+ <g
+ id="g16"
+ style="fill: #c1c1bf"> <path
+ id="path17"
+ d="M286.424 711.568C273.824 711.496 260.936 715.6 261.944 732.16L266.192 776.44L304.424 756.64L286.424 711.568z">
+ </path>
+
+ </g>
+ <g
+ id="g18"
+ style="fill: #000000"> <path
+ id="path19"
+ d="M-37.36 821.224C7.136 840.88 38.6 839.728 66.968 853.696C89.36 865.216 111.968 863.92 125.648 849.808C137.24 835.192 145.808 834.472 162.872 832.96C190.736 831.232 218.024 831.016 242.648 833.464L270.728 835.768C270.224 866.8 330.272 870.544 347.912 847C369.224 822.088 398.528 811 423.656 792.856L290.816 728.272C256.76 809.128 129.824 830.296 112.256 766L-37.36 821.224z">
+ </path>
+
+ </g>
+ <g
+ id="g20"
+ style="fill: #b77200"> <path
+ id="path21"
+ d="M382.328 691.984C403.64 698.968 389.888 720.28 400.76 732.52C405.44 742.888 415.304 752.032 431.792 760.528C459.368 774.424 426.248 799.336 392.768 812.08C351.944 825.616 344.024 862.912 299.312 851.896C283.112 846.496 278.36 831.808 278.864 809.128C284.264 762.76 277.784 730.432 278.792 698.824C278.72 686.152 283.544 684.64 307.232 687.952C310.04 726.328 352.376 727.336 382.328 691.984z">
+ </path>
+
+ </g>
+ <g
+ id="g22"
+ style="fill: #f2b700"> <path
+ id="path23"
+ d="M339.632 826.624C371.6 814.312 403.856 798.112 429.848 782.128C437.84 777.448 438.92 765.928 427.688 762.328C403.352 748.504 390.104 731.224 392.912 708.76C393.344 700.912 383.696 692.56 381.104 700.048C359.864 771.472 291.32 767.656 300.752 696.952C301.256 694.864 301.76 692.776 302.264 690.76C289.952 688.24 285.2 690.976 285.776 700.408L295.28 806.608C297.656 830.8 317.312 836.128 339.632 826.624z">
+ </path>
+
+ </g>
+ <g
+ id="g24"
+ style="fill: #000000"> <path
+ id="path25"
+ d="M354.464 537.544C379.16 569.8 404.432 651.088 384.416 691.552C360.944 737.776 307.808 743.248 305.504 695.8C308.816 639.64 311.984 581.536 273.68 544.096C267.704 497.368 246.392 480.232 236.384 450.28L203.12 426.088L133.568 435.088C130.76 452.152 129.104 468.784 131.552 484.912C115.064 507.376 102.608 530.056 101.168 553.312C88.712 586.648 59.12 614.944 64.232 680.752C80.864 698.248 104.12 714.448 124.064 731.296C149.12 752.392 135.512 776.296 100.232 769.672C78.848 746.056 56.744 722.872 35.288 699.328C12.392 683.056 3.896 662.176 27.368 630.496C43.424 609.04 47.96 562.456 62 543.664C74.312 525.16 92.24 508.6 105.272 490.096C112.184 477.928 114.344 468.568 113.264 454.456L110.312 369.136C108.368 307.216 142.424 274.24 189.8 275.248C243.512 275.752 287.576 312.472 288.152 378.28C292.688 410.32 283.256 428.68 308.672 474.472C334.52 522.712 338.552 520.12 354.464 537.544z">
+ </path>
+
+ </g>
+ <g
+ id="g26"
+ style="fill: #c1c1bf"> <path
+ id="path27"
+ d="M261.296 503.632L263.528 512.2C257.696 501.688 250.712 483.616 241.928 475.696C239.264 473.536 235.808 473.608 233.72 475.624C222.056 486.928 193.112 510.112 169.928 507.088C152.072 505.288 134.648 493.264 130.832 480.232C128.816 470.872 129.752 463.168 130.976 455.32L240.704 453.52C238.472 463.168 253.088 487 261.296 503.632z">
+ </path>
+
+ </g>
+ <g
+ id="g28"
+ style="fill: #c1c1bf"> <path
+ id="path29"
+ d="M143.144 363.232C154.088 363.232 163.88 376.84 163.808 395.632C163.736 408.232 155.528 411.472 149.336 417.016C146.6 419.536 145.952 433.144 142.568 433.144C131.696 433.144 123.488 413.776 123.488 395.632C123.488 377.56 132.272 363.232 143.144 363.232z">
+ </path>
+
+ </g>
+ <g
+ id="g30"
+ style="fill: #ffffff"> <path
+ id="path31"
+ d="M144.368 375.04C154.088 375.04 160.856 379.936 161.648 391.312C162.224 399.16 160.136 411.76 154.664 414.424C152.144 415.648 143.432 426.664 140.408 426.52C128.096 425.944 125 402.112 125.936 390.736C126.8 379.36 134.72 375.04 144.368 375.04z">
+ </path>
+
+ </g>
+ <g
+ id="g32"
+ style="fill: #000000"> <path
+ id="path33"
+ d="M141.848 382.672C148.544 382.096 154.736 389.728 155.6 399.664C156.464 409.6 151.64 418.24 144.944 418.816C138.248 419.392 132.056 411.76 131.192 401.752C130.328 391.816 135.152 383.248 141.848 382.672z">
+ </path>
+
+ </g>
+ <g
+ id="g34"
+ style="fill: #c1c1bf"> <path
+ id="path35"
+ d="M151.064 397.288C151.424 399.088 149.408 400.024 148.832 398.224C148.256 395.992 146.888 393.328 145.088 391.168C143.936 389.872 145.088 388.432 146.528 389.44C149.048 391.528 150.488 394.12 151.064 397.288z">
+ </path>
+
+ </g>
+ <g
+ id="g36"
+ style="fill: #c1c1bf"> <path
+ id="path37"
+ d="M216.944 360.712C232.712 360.712 245.6 377.416 245.6 397.792C245.6 418.24 232.712 434.872 216.944 434.872C201.176 434.872 188.432 418.24 188.432 397.792C188.432 377.416 201.176 360.712 216.944 360.712z">
+ </path>
+
+ </g>
+ <g
+ id="g38"
+ style="fill: #ffffff"> <path
+ id="path39"
+ d="M224.792 374.968C235.664 378.856 241.928 387.424 242.72 396.568C243.656 407.08 239.408 418.96 230.264 425.944C227.672 427.888 197.72 416.08 195.992 411.616C193.4 405.208 191.816 392.896 193.76 385.624C194.552 382.744 197.216 378.568 201.176 376.336C207.44 372.808 216.656 372.088 224.792 374.968z">
+ </path>
+
+ </g>
+ <g
+ id="g40"
+ style="fill: #000000"> <path
+ id="path41"
+ d="M216.872 380.944C225.584 380.944 232.712 389.296 232.712 399.448C232.712 409.672 225.584 418.024 216.872 418.024C208.16 418.024 201.032 409.672 201.032 399.448C201.032 389.296 208.16 380.944 216.872 380.944z">
+ </path>
+
+ </g>
+ <g
+ id="g42"
+ style="fill: #c1c1bf"> <path
+ id="path43"
+ d="M227.096 392.392C228.104 394.048 226.448 395.776 225.224 394.12C223.784 392.104 221.408 389.944 218.888 388.432C217.232 387.568 217.808 385.624 219.68 386.2C222.92 387.28 225.368 389.368 227.096 392.392z">
+ </path>
+
+ </g>
+ <g
+ id="g44"
+ style="fill: #b77200"> <path
+ id="path45"
+ d="M164.96 404.488C172.376 402.328 184.112 403.048 192.248 404.632C200.384 406.792 222.056 418.24 245.024 430.696C247.976 432.208 248.84 437.104 245.024 438.688C239.12 439.12 249.272 453.664 238.904 458.848C223.352 462.88 198.44 485.992 186.128 487.864C179.288 489.376 172.232 489.592 164.6 487.864C140.552 482.968 134.216 455.608 122.912 450.064C119.816 446.824 121.4 441.208 122.408 440.056C123.632 434.224 149.696 406.216 164.96 404.488z">
+ </path>
+
+ </g>
+ <g
+ id="g46"
+ style="fill: #f2b700"> <path
+ id="path47"
+ d="M185.408 405.856C198.44 407.296 226.088 423.928 239.408 430.624C242.72 432.424 242.504 437.824 239.552 438.688C236.384 440.488 235.448 438.256 232.928 437.896C228.896 435.736 222.272 440.92 217.016 444.88C186.704 467.776 180.656 465.256 156.176 462.664C147.68 460.576 142.136 457.984 139.688 455.968C141.488 445.888 160.496 407.656 166.76 406.792C168.344 404.704 179.936 404.632 185.408 405.856z">
+ </path>
+
+ </g>
+ <g
+ id="g48"
+ style="fill: #b77200"> <path
+ id="path49"
+ d="M190.664 412.048L193.76 413.416C196.064 414.712 193.256 418.168 190.736 417.088L186.2 415.504C183.536 413.272 186.704 410.104 190.664 412.048z">
+ </path>
+
+ </g>
+ <g
+ id="g50"
+ style="fill: #b77200"> <path
+ id="path51"
+ d="M268.568 452.368C273.032 454.384 279.224 457.192 282.536 460.144C285.488 464.104 286.784 468.064 286.424 472.024C285.776 474.544 284.12 476.344 281.24 477.424C277.856 478.216 273.68 477.424 271.376 474.112C269.864 471.448 265.256 462.16 263.96 460.576C262.232 457.12 261.944 454.456 262.88 452.368C264.032 451.288 266.048 451 268.568 452.368z">
+ </path>
+
+ </g>
+ <g
+ id="g52"
+ style="fill: #c1c1bf"> <path
+ id="path53"
+ d="M273.752 461.584C275.48 462.376 277.928 463.456 279.224 464.68C280.376 466.264 280.88 467.776 280.736 469.36C280.52 470.296 279.8 471.016 278.72 471.448C277.352 471.808 275.768 471.448 274.832 470.152C274.256 469.144 272.456 465.472 271.952 464.824C271.232 463.456 271.088 462.448 271.448 461.584C271.952 461.152 272.744 461.08 273.752 461.584z">
+ </path>
+
+ </g>
+ <g
+ id="g54"
+ style="fill: #b77200"> <path
+ id="path55"
+ d="M238.616 358.552C239.048 359.2 238.976 359.776 238.4 360.28C237.896 360.784 237.176 360.712 236.24 360.208L231.632 356.248C231.056 355.744 230.912 354.952 231.272 354.088C232.28 353.44 233.144 353.44 233.936 354.088L238.616 358.552z">
+ </path>
+
+ </g>
+ <g
+ id="g56"
+ style="fill: #b77200"> <path
+ id="path57"
+ d="M235.592 305.992C239.624 308.224 240.848 313.912 238.184 318.592C235.592 323.2 230.12 325.144 226.016 322.84C221.984 320.536 220.76 314.92 223.424 310.24C226.016 305.56 231.488 303.688 235.592 305.992z">
+ </path>
+
+ </g>
+ <g
+ id="g58"
+ style="fill: #b77200"> <path
+ id="path59"
+ d="M374.912 680.536C378.296 683.128 373.256 687.376 371.024 686.296C369.152 685.648 367.784 683.488 366.92 682.408C366.128 681.184 366.2 679.168 366.92 678.448C367.712 677.44 369.728 677.656 371.024 678.52C372.32 679.168 373.616 679.888 374.912 680.536z">
+ </path>
+
+ </g>
+ <g
+ id="g60"
+ style="fill: #b77200"> <path
+ id="path61"
+ d="M297.44 551.512C338.984 572.896 350 611.56 332.072 664.192C330.992 666.64 334.16 668.368 335.24 666.064C354.824 610.336 341.432 571.312 299.024 548.56C296.864 547.552 295.28 550.432 297.44 551.512z">
+ </path>
+
+ </g>
+ <g
+ id="g62"
+ style="fill: #b77200"> <path
+ id="path63"
+ d="M72.008 569.512C38.312 627.256 38.096 662.68 62.504 681.328C63.728 682.264 64.448 680.032 63.296 679.168C36.296 655.48 48.896 615.52 74.168 570.88C74.888 569.584 72.512 568.432 72.008 569.512z">
+ </path>
+
+ </g>
+ <g
+ id="g64"
+ style="fill: #c1c1bf"> <path
+ id="path65"
+ d="M289.376 586.864C289.232 589.168 288.368 589.528 286.424 587.368C279.8 575.848 235.088 551.44 213.344 548.704C209.24 547.264 209.456 545.392 213.488 544.816C229.184 544.816 241.28 537.904 254.96 537.904C258.704 538.048 262.304 539.488 264.392 541.648C269.504 544.96 288.08 570.592 289.376 586.864z">
+ </path>
+
+ </g>
+ <g
+ id="g66"
+ style="fill: #c1c1bf"> <path
+ id="path67"
+ d="M180.152 546.832C180.872 550.792 163.808 545.68 164.744 556.696C165.032 559.72 160.496 561.376 160.64 556.696C160.64 548.272 161.072 548.416 152.72 546.832C151.208 546.76 151.352 544.528 152.72 544.816L152.72 544.816C158.696 546.472 166.76 542.872 166.4 538.84C166.256 537.472 168.56 537.688 168.488 538.84C167.984 545.248 181.664 542.152 180.152 546.832z">
+ </path>
+
+ </g>
+ <g
+ id="g68"
+ style="fill: #c1c1bf"> <path
+ id="path69"
+ d="M151.568 705.376C151.64 708.328 148.76 707.68 148.544 705.592C140.192 680.536 143.72 618.832 151.856 598.96C152.432 596.08 156.248 596.944 155.744 598.96C147.104 635.464 147.248 673.048 151.568 705.376z">
+ </path>
+
+ </g>
+ <g
+ id="g70"
+ style="fill: #b77200"> <path
+ id="path71"
+ d="M51.704 684.424C75.68 707.824 91.376 743.248 114.632 775.288C148.472 816.04 121.472 858.304 66.464 845.56C38.888 835.192 -0.784 836.344 -32.68 825.832C-55.072 820.36 -55.864 809.272 -44.416 787.6C-40.384 773.776 -40.024 751.312 -43.768 732.592C-45.784 718.408 -39.232 710.488 -24.112 708.832L-24.112 708.832C-11.296 708.688 6.56 713.872 16.28 686.44C23.552 673.336 40.976 672.976 51.704 684.424z">
+ </path>
+
+ </g>
+ <g
+ id="g72"
+ style="fill: #f2b700"> <path
+ id="path73"
+ d="M24.632 699.04C23.84 680.968 39.32 677.296 49.688 688.312C68.192 710.992 85.112 736.048 100.376 764.992C124.712 804.16 104.624 842.68 67.904 828.064C49.688 817.84 6.128 813.304 -17.344 809.128C-33.04 807.832 -35.128 797.608 -29.152 791.848C-20.944 782.416 -20.08 759.808 -27.856 740.512C-35.56 728.56 -21.088 715.384 -9.712 720.856C0.8 727.048 25.64 713.08 24.632 699.04z">
+ </path>
+
+ </g>
+
+
+</svg>
diff --git a/ksvg/test/xlink.svg b/ksvg/test/xlink.svg
new file mode 100644
index 00000000..452eaa44
--- /dev/null
+++ b/ksvg/test/xlink.svg
@@ -0,0 +1,13 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010719//EN"
+ "http://www.w3.org/TR/2001/PR-SVG-20010719/DTD/svg10.dtd">
+<svg width="5cm" height="5cm">
+ <desc>Link test
+ </desc>
+ <a xlink:href="http://www.w3.org">
+ <ellipse cx="2.5cm" cy="1.5cm" rx="2cm" ry="1cm" fill="red" />
+
+ <circle cx="1.5cm" cy="0.5cm" r="0.5cm" fill="green"/>
+ </a>
+</svg>
+
diff --git a/kuickshow/AUTHORS b/kuickshow/AUTHORS
new file mode 100644
index 00000000..9e0745fb
--- /dev/null
+++ b/kuickshow/AUTHORS
@@ -0,0 +1 @@
+Carsten Pfeiffer <pfeiffer@kde.org>
diff --git a/kuickshow/BUGS b/kuickshow/BUGS
new file mode 100644
index 00000000..511b33ee
--- /dev/null
+++ b/kuickshow/BUGS
@@ -0,0 +1,3 @@
+kdelibs issues:
+- The filefinder doesn't work when using the splitted view
+- in the detailed view, the filefinder can't highlight files during typing.
diff --git a/kuickshow/COPYING b/kuickshow/COPYING
new file mode 100644
index 00000000..0b84a43f
--- /dev/null
+++ b/kuickshow/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/kuickshow/ChangeLog b/kuickshow/ChangeLog
new file mode 100644
index 00000000..55a198b2
--- /dev/null
+++ b/kuickshow/ChangeLog
@@ -0,0 +1,921 @@
+<pre>
+Fri Mar 31 02:04:21 2006 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * fixed one of the most long-standing bugs: non-local browsing
+ (i.e. you can browse remote directories like local ones now, flipping
+ through the images with PageUp/Down etc., including pre-loading
+ images)
+ Browsing through /media should work now, but can be improved by
+ not"downloading" from there. Framework to do this is there, though.
+
+ * also allow saving to remote URLs
+
+ * fixed image not being completely maximized when opening image in
+ fullscreen mode
+ * performance improvement
+
+ * layed groundwork for fixing #48812 and #101986
+
+ * make sure all temporary files get deleted
+
+Wed Feb 22 16:02:58 2006 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * make autohide-cursor finally work
+
+Wed Feb 22 02:14:24 2006 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/kuickshow.cpp, imagewindow.*
+ remove nextSlideRequested() and prevSlideRequested() patch, you
+ can already navigate with PageUp/Down. The arrow-keys are used for
+ scrolling.
+
+Wed Feb 22 01:31:54 2006 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/kuickshow.cpp (KuickShow):
+ warn before loading >= 10 images at once from the commandline
+
+Wed Feb 22 01:03:07 2006 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imagewindow.cpp (rotated):
+ auto-scale image on rotation
+
+Wed Feb 22 00:01:02 2006 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * add a warning messagebox when zooming to larger than
+ 4 * desktop area size. The "4*" is configurable in
+ [GeneralConfiguration]
+ MaximumZoomFactorByDesktop=4.0
+
+
+Sun Jan 8 09:47:39 2006 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * fix crash when deleting the last image without having a browser
+
+Sat Jan 7 23:27:32 2006 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * fix deleting images from image window and browser!
+
+ * support moving to trash and make that the default
+
+ * refactor delayed execution of events/actions (for when the browser window needs to
+ be loaded lazily)
+
+Sat Jan 7 22:36:25 2006 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imagewindow.cpp (addAlternativeShortcut):
+ use F5 as default shortcut for "Reload image", keep Enter as alternative
+
+Sat Jan 7 22:33:30 2006 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/aboutwidget.cpp:
+ fixed crash (right-clicking on about widget)
+
+ * made the about widget not always-on-top, but a modal widget,
+ which prevents error messages from being hidden below the about
+ widget (i.e. when clicking the homepage link while being offline)
+
+Sat Aug 25 02:58:31 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imagewindow.cpp (init):
+ mouse-wheel can switch between images now, per request of
+ Bill Benken <bilben1@home.com>
+
+ * also fixed the KStdAccel::save() and close() accels not working
+ in the image window
+
+Sat Aug 4 03:37:50 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * now completely smooth, flicker-free switching between images
+ and zooming
+
+ * Reverted again to current kde-common/admin stuff
+
+ * added quit-button to toolbar (also makes Ctrl-Q work)
+
+ * made ChangeLog readable by KHelpCenter
+
+ * commented out benchmark debug output
+
+ * added support for objprelink in the specfile
+ (copy the tarball to your rpm-dir/SOURCES and rpm -ba kuickshow.spec)
+
+ * Fixed some bugs coming from kdelibs 2.1.x vs. 2.2 handling
+ Thanks a lot to Robert Charbonneau <etriaph@kdesktop.org>
+ and another anonymous helper from #kde for testing and useful
+ feedback.
+
+ * Added patch from Adrian Schroeter <adrian@suse.de> to make it
+ work with autoconf 2.5x -- Thanks!
+
+Wed Jul 11 17:19:38 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/filewidget.cpp (initActions):
+ adopt to KDirOperator's contextmenu (i.e. don't add the "Properties..."
+ entry when it's already present)
+
+ * src/imagewindow.cpp:
+ show image size in the caption
+
+ * reverted to admin/* files from KuickShow 0.8 so that users of older
+ KDE versions can compile it again.
+
+ * cleaned up Imlib configure check
+
+ * made background color in viewer configurable
+
+ * added delete-action again for users of older kdelibs
+
+ * fixed some bugs in the filefinder widget
+
+Wed Jul 4 01:06:58 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imagewindow.cpp (printImage):
+ Grmbl. Really fixed printing. It even works now :)
+
+Tue Jul 3 3:04:18 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * Oups, the behavior of QPrinter::printCommand() has changed.
+ It returns a null String by default now :-O Fixed.
+
+Tue Jun 27 15:44:28 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imagewindow.cpp:
+ added KTempFile patch from Kevin Lo <kevlo@kde.org>
+
+Tue May 29 15:20:34 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imagewindow.cpp (updateAccel):
+ changed accels:
+ shift-accel is now for removing brightness/contrast/gamma
+
+ removed delete action, now provided by kfile
+
+Thu Apr 19 23:16:12 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * Integrated Multihead patch from Evan Edwards <evan@onepaper.com>
+ who was also so kind, to set up a homepage for KuickShow, as well
+ as a Sourceforge account. See kuickshow.sourceforge.net for details.
+
+ Thanks a lot, Evan!
+
+ Added handcursor from qwertz <kraftw@gmx.de>, thanks a lot!
+
+ * src/imlibwidget.cpp (getKuimage):
+ hopefully fixed crash reported by Alexxx and linuxphreak:
+ reorder the kuickimage and file-lists when returning a cached image
+
+Tue Mar 13 03:16:24 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * added lots of translations from the translation team.
+ I need to add a KAboutDialog somewhere to give them credit
+ for their excellent work!
+
+Fri Mar 9 21:50:12 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/kuickshow.cpp (eventFilter):
+ call our parent class' eventFilter if we don't stop the event
+ -> moving/rearranging the toolbar works :)
+
+ * caption fixes, show the url in the caption
+
+ * save the visible images on SM shutdown and restore them on restore
+
+ * src/imlibwidget.cpp:
+ don't delete this from closeEvent, WDestructiveClose does it better
+ -> sessionmanagement works
+
+ * defaultswidget.cpp:
+ fix typo found by qwertz
+
+ * add icon for delete, as suggested by Florian
+
+Thu Mar 8 13:29:17 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imagewindow.cpp (mouseReleaseEvent):
+ zooming should work properly now:
+ - the window size is kept
+ - scrolling the zoomed image works correctly
+ - the rubber band sort of works (maybe even as good as in 0.6.7)
+ - respect maxWidth and maxHeight during zoom with the rubberband
+
+ added different icon for image window
+
+ * src/kuickshow.cpp
+ go into window mode when pressing space in fullscreen mode to show
+ the browser (always-on-top issue)
+
+ * src/filewidget.cpp
+ some more ensureItemVisible()
+
+ * installation/spec files fixes
+
+ * added im_palette.pal
+
+Wed Mar 7 21:25:15 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * doc/en/index.html:
+ updated english documentation
+
+ * src/imagewindow.cpp
+ set our nice icon so that kicker can show it in the taskbar for
+ example. Thanks to Florian for the hint :)
+
+ * i18n fix ( -> degrees), and s/-90/270/, another one from Florian
+
+ * resizeOptimal(): if we don't resize because we already have the right
+ size, call centerImage()
+
+ * zooming with the mouse works again (still not completely right tho:
+ - the rubber band is missing
+ - the size/scrolling does not always match the real imagesize
+
+ * src/filewidget.cpp:
+ ensureItemVisible() in the browser when browsing with PageUp/PageDown
+
+ * src/kuickshow.cpp:
+ disable the slideshow action when a slideshow is running
+
+Wed Mar 7 01:39:34 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/kuickshow.cpp (readProperties):
+ clear the diroperators history stack on startup
+
+ * src/imagewindow.cpp:
+ update the accelerators when applying new configuration
+ (delete the old and create a new KAccel, setKeyDict() doesn't
+ work in our case
+
+ * use QWidget::x11Display() for later multihead support)
+
+ * general cleanup. hmm, this could be added to every entry
+ in the last days, I guess :}
+
+ * added workaround for relative paths not working in the filefinder
+ relative _files_ don't work yet, tho.
+
+ * documentation written for the upcoming 0.8pre release
+
+Mon Mar 5 13:07:59 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imagewindow.cpp (init):
+ Maximize and close shortcuts, as proposed by Crocodile on IRC.
+
+ * WDestructiveClose in ImlibWidget and close(true) everywhere
+
+Mon Mar 5 00:12:45 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/kuickshow.cpp (slotReplayEvent):
+ going to the next/previous/... image now also works when started with
+ an image on the commandline (== no browser available)
+ Tricky thing: after creating the browser, we can't simply go on,
+ because the browser doesn't have any files at all (async listing).
+ So we save the pageUp/pageDown event and replay it when the browser
+ is ready.
+
+ * fixed Space needed to be hit twice to show the initial browser
+
+ * src/kuickshow.cpp, src/filewidget.cpp (eventFilter)
+ deleting files works from the filebrowser again, not only from the
+ image window
+
+ * Makefile.am
+ build as KLM (kdeinit-loadable-module) to speed up startup
+
+ * hah! Adding two lines makes browsing about twice as fast :)
+ Well, equally as fast as the KDE1 version at least ;) The new caching
+ system set the dirty flag wrongly at one place, so the pixmap was
+ effectively rendered twice per image.
+
+Sun Mar 4 20:33:44 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/kuickshow.cpp (initGUI):
+ open only one window item in toolbar is honored properly now
+ (replaced the checkbox in the configdialog)
+
+ * don't pass the KKeyEntryMap to all the image windows, this doesn't
+ work (and it also crashes after doing it a second time).
+ Thanks to Florian Hacker for the bugreport :)
+
+ * save the view properties of KDirOperator
+
+ * statusbar looks a bit better now (no fixed size entries anymore)
+
+ * src/kuickio.cpp (deleteFile):
+ deletion of directories works, now
+
+ * src/imdata.cpp, kuickdata.cpp:
+ better handling of default values
+
+Sun Mar 4 13:57:52 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imagewindow.cpp (setFullscreen):
+ hack around QWidget::move() resizing us -> we just ignore that
+ resizeEvent. Gives less flicker when switching into window-mode.
+
+ * initial fullscreen mode works again as well (hacking around a kwin
+ "limitation")
+
+Sun Mar 4 10:50:23 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/kuickconfigdlg.cpp (KuickConfigDialog):
+ Keyboard shortcuts configurable for browser and image viewer
+
+ * don't check mimetype in isImage() at the moment, people won't have
+ mimetypes for .eim and .psd probably
+
+ * removed unused EditDialog
+
+ * Added auto-hide cursor in viewer (doesn't work properly tho)
+
+Sat Mar 3 02:00:41 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imagewindow.cpp (resizeOptimal):
+ Honor the window manager decoration in window mode. Now always the
+ entire window including decoration is visible, no matter how large the
+ image is.
+
+ * Fixed a scrolling bug when the window was exactly as large as the
+ desktop (only in fullscreen mode)
+
+ * don't go to the next image when cancelling a deletion of a file or
+ deletion fails
+
+ * some cleanup
+
+Thu Mar 1 03:49:11 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/kuickshow.cpp (showImage):
+ positioning is fixed now. Removed processEvents() after move(),
+ we don't seem to need this anymore. Actually, this was the cause
+ for bogus geometries.
+
+Thu Mar 1 02:15:49 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imagewindow.cpp, src/imlibwidget.cpp:
+ upScale/downScale mostly works. Some WindowManager positioning
+ problems are left.
+
+Tue Feb 27 23:30:11 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/kuickshow.cpp (viewerDeleted):
+ Fixed crash when the only image on the commandline couldn't be loaded
+
+Sun Feb 25 23:22:30 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * config-dialog works now, everything is saved, loaded and resetting
+ defaults works, too. All the layout management rewritten (was still
+ Qt 1.x style). Default Image modifications work, including the preview.
+ Only need a nice preview image now :)
+
+ * src/imlibwidget.*:
+ fixed setFlipMode()
+
+ * src/filewidget.cpp (eventFilter):
+ fixed filefinder completion on first character
+ filefinder enters directory/opens image upon return now
+
+ * added nice new calibrate.png from qwertz, thanks!
+
+Wed Jan 10 23:39:14 2001 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * lots of work... getting closer. Commandline handling is really
+ fixed now %-} Handles multiple files just fine. The filefinder
+ sort of works now (only the sort-order is not considered, this
+ could get hairy, I'm afraid). Added browsing actions to toolbar
+ and shortcuts. Works quite nicely.
+
+Fri Nov 3 14:32:53 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imagewindow.cpp (setFullscreen):
+ cool, no need to workaround kwin's auto-maximization needed,
+ setMinimumSize() does it! Thanks Matthias Ettrich!
+
+Fri Nov 3 13:23:41 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/*:
+ some cleanups here and there
+ fixed commandline handling (dirs, files, absolute, relative)
+ made KURLWidget use KURLLabel (and fixed KURLLabel bugs)
+
+Fri Nov 3 01:49:57 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/*: some more work on the KDE2 port/integration. Workarounds for
+ kwin's auto-maximization added. Fullscreen works. Moving images inside
+ the window works properly again. NETWM/KWin handling is better now.
+ Also better handling of non-loadable files.
+
+ Will make it a kdeinit-loadable module (KLM) for fast startup-times
+ later.
+
+ Finally using it again reminds me how fast it is compared to, erm, the
+ other viewers :)
+
+Thu Aug 31 01:48:55 2000 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/*: started reworking/rewriting the whole stuff to make it KDE2
+ ready. Now I have to pay for rewriting so much of kdelibs/kfile...
+ The good thing is: it's mostly about removing stuff from KuickShow
+ because the functionality is already in libkfile, now :)
+
+Tue Sep 28 10:35:39 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/kuickshow.cpp (resizeEvent):
+ ahh, fixed a seldom-happening segfault: when "preload images" was
+ turned on and kuickshow was started with an image as parameter (so that
+ the filebrowser was not shown in the beginning), it would segfault
+ in KuickShow::resizeEvent(). I even got a bugreport about such a
+ segfault a while ago, but I couldn't reproduce it and neither did the
+ reporter answer to my mail.
+ Anyway, this is fixed now.
+
+ * src/imagewindow.cpp (dragEnterEvent):
+ implemented preliminary drag/drop support from Konqueror
+
+Sat Sep 25 18:30:32 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imagewindow.cpp (saveImage):
+ (hopefully, untested) fixed bug, that an image was not saved with the
+ current size - the original size was used. Thanks for the report (and
+ for some other suggestions) go to Hugo Lopes <hugolopes@netc.pt>
+
+ * src/imlibwidget.cpp:
+ lots of other changes, fixes, there's no sense mentioning them all, as
+ a lot of stuff is being rewritten/restructured and many things have to
+ be fixed.
+
+Tue Sep 14 23:57:18 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imagewindow.cpp:
+ Ok, finally I took the time to restructure ImlibWidget.
+ Now there is a simple ImlibWidget, that can load and show images
+ and there is the powerful ImageWindow, that can do all the stuff, the
+ previous ImlibWidget did.
+ There is a nice object-oriented wrapper around ImlibImages named
+ KuickImage - I hated all those C-functions everywhere.
+
+ Additionally, the ImageWindow has fully configurable key-bindings.
+
+ And thanks to Vitor Fernandes <vitor_fernandes@SoftHome.net>
+ I got a Brazilian/Portuguese translation for KuickShow
+
+Tue Jul 27 20:32:09 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imlibwidget.cpp (setBusyCursor):
+ loading an image from disk could take quite some time (e.g. on NFS),
+ so show a busy cursor during that operation, too.
+
+Thu Jul 22 21:26:11 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imlibwidget.cpp (preloadImage):
+ Argh, fixed segfault - don't free the cached image, when it is the
+ current shown image as well (imCache == im). Occured when switching
+ back and forth between two images
+
+Fri Jul 16 13:09:07 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/kfileview.cpp (refresh):
+ Oh well, thanks to Robert Hamberger <Robert.Hamberger@AUDI.DE>, I
+ fixed another (hopefully last, for the next time) segfault. SIGSEGV
+ happened, when opening the about-dialog, NOT giving the focus back
+ to the filebrowser and then pressing the "show-hidden-files-button"
+ twice.
+
+ * src/kuickconfigdlg.cpp (keyPressEvent):
+ fixed bug: pressing escape in config dialog didn't reenable the
+ toolbar button to open the dialog
+
+ * src/imlibwidget.cpp (autoRender):
+ LOTS of updates, the new configuration dialog sort of works now
+ - all image manipulations can be daisychained now, just call
+ setAutoRender( false ) and call updateImage() to apply (render)
+ configuration dialog makes use of this to show the settings in an
+ example image
+ - new and nice about dialog, also based on ImlibWidget :o)
+
+
+Wed Jul 7 01:09:14 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imlibwidget.cpp (loadImageInternal):
+ Applied patch from Thorsten Scheuermann <uddn@rz.uni-karlsruhe.de>
+ (autoscale images to screensize) - thanks!
+
+Mon Jul 5 15:27:05 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/kuickconfigdlg.cpp (closeEvent):
+ Eieiei, introduced closeEvent() in configdialog, which just emits
+ cancelButtonPressed() - otherwise the Toolbarbutton wouldn't get
+ reenabled. Thanks to Thorsten Scheuermann for the bugreport!
+
+ * src/kuickshow.cpp (deleteFile):
+ Uh oh, I really thought there were no segfaults in 0.6.6...
+ Thanks go to Vadim Zaliva, who proved me wrong :-} Just fixed that
+ core-dump, when trying to delete a directory.
+
+Fri Jul 2 14:27:08 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/kuickshow.cpp (initGUI):
+ moved some code around to delay creating the filebrowser and reading
+ the directory contents. If you give a filename on the commandline as
+ parameter, kuickshow will load the filebrowser first, when you really
+ want to.
+
+ * src/imlibwidget.cpp (desktopWidth):
+ kuickhow now honors the panel and window-frame-size when displaying
+ images in window-mode - the imagesize is properly adjusted in
+ auto-shrink mode
+
+ * src/imlibwidget.cpp (showImageOriginalSize):
+ fixed bug in window-mode: displaying image with "o" (original size)
+ didn't resize the window, if necessary
+
+ * src/kuickshow.cpp (eventFilter):
+ Bugfix: when did I have that crazy idea to set the palette to black
+ in the filebrowser??? In certain cases, I got an almost completely
+ black Messagebox...
+
+ * src/kfileview.cpp (removeItem):
+ oups... segfault fixed: removing the very first item in the
+ filebrowser caused crash
+
+Sat Jun 26 22:47:05 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/fileview.cpp (changeDirDialog):
+ goto-dialog (ctrl-g) accepts ~ and replaces it with your homedirectory
+ I love ideas, that can be implemented in half a minute :o)
+
+Mon May 31 12:08:41 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imlibwidget.cpp (setFullscreen):
+ Save and restore the geometry when switching between fullscreen and
+ window mode. Much nicer now :o)
+
+ * src/kuickshow.cpp (showImage):
+ Honor kpanel's placement, when showing the first image. Don't just move
+ it to (0,0), but use KWM::geometry().
+
+ * src/imlibwidget.cpp (showImageOriginalSize):
+ implemented Shortcut "o" to show image in the original size. Useful when
+ autoscaling is active and you want the original size (e.g. scaled text
+ is hardly readable).
+
+Mon May 31 02:24:56 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * updated polish translation, many thanks to Krzysztof P. Jasiutowicz
+
+ * added german documentation, many thanks to Robert Hamberger,
+ who also enlargened the TODO-list :-P
+
+Fri May 28 11:48:46 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imlibwidget.cpp (mouseMoveEvent, mouseReleaseEvent):
+ several cleanups (replaced bool shiftPressed with the appropriate
+ QEvent::state() & ShiftButton in the eventhandlers)
+
+ * fixed bug: Shift + MousePress + MouseRelease without moving the mouse
+ moved the image to the lower right corner
+
+ * implemented "close image on doubleclick", as suggested by Ralph
+ Bernecker. Also put Close into popupmenu.
+
+ * improved cache of preloaded image, now stores the actual rendered
+ Pixmap -> a preloaded image shows almost before you press "next image"
+ ;-) It can't get faster now. I only could cache more than one pixmap...
+ hmm, maybe later
+
+ * updated documentation
+
+Tue May 18 21:19:32 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/kfileview.cpp (refresh):
+ sorting does somehow work. Some code seems to be duplicated in
+ KFileInfoContents and KDir - both offer sorting. However, both
+ don't work 100% :-/ Anyway, if you have KDE 1.1.1, sorting should
+ work, it is disabled for earlier releases, as there was a segfault
+ problem in kfile (nobody ever seemed to use KFileInfoContent's sorting,
+ so that was never realized).
+
+ * src/kfileview.cpp, src/fileview.cpp:
+ some minor fixlets: always try to highlight the last active file,
+ whenever the directory contents are updated
+
+ * src/kuickconfigdlg.cpp (several):
+ changed the two KIntLineEdits to more appropriate QSpinBoxes
+
+ * src/imlibwidget.cpp (setFullscreen, several),
+ * src/kuickshow.cpp (several)
+ FINALLY got the fullscreen/kpanel thing together
+ KDE 1.1 introduced KWM::staysOnTop, but unfortunately "on top" meant
+ "below kpanel". Since KDE 1.1.1, on top means on top :o) Even more
+ unfortunately, this revealed several problems with focus handling and
+ other widgets on top of the "top"-widget. So I used a timer, check
+ the focusevents and tell kwm when to make us the top widget, and when
+ not.
+
+ * src/imlibwidget.cpp, src/kuickshow.cpp
+ improved handling of multiple windows - always the window which last
+ had the focus will load new images
+
+ * src/kuickdata.cpp, src/kuickconfigdlg.cpp, src/kuickshow.cpp
+ configurable: open all images in one window, or open a new window
+
+Sat Apr 17 18:43:03 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/kuickshow.cpp (setToolbarPosition):
+ added methods to (re)store the toolbar position
+
+ * src/imlibwidget.cpp:
+ changed fullscreen code to use the current (and hopefully final) way
+ KWM does "stayOnTop"
+
+ * src/kuickdata.cpp:
+ updated file filters (Photoshop psd and bmp)
+
+ * src/kfileview.cpp:
+ changed the kdir behavior, so that the browser displays files
+ altogether at once, not incrementally. This also let me (finally,
+ yippeee :-P) highlight the last direcory, where you came from.
+ And reading directories is a bit faster now, too.
+
+Sun Feb 21 16:02:44 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imlibwidget.cpp (zoomImage):
+ added minimum and maximum sizes for zooming images (thanks to
+ Robert Hamberger for the idea (and for some funny emails :-P))
+
+ * src/kwm-workaround.h (keepOnTop):
+ added Matthias' workaround for "always on top"-problem in fullscreen
+ mode, which was introduced with KWM-changes just before KDE 1.1
+ ... too bad it doesn't work :-/ Gotta spend some time finding out, why
+
+ * src/kuickshow.cpp (showImage):
+ always move the first opened image-window to 0x0 (top left)
+ (thanks to Andreas Gelezun for the idea)
+
+Thu Feb 4 11:40:50 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * doc/en/index.html:
+ updated documentation
+
+Wed Feb 3 22:43:32 1999 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/kuickshow.cpp (KuickShow):
+ implemented deletion of files (delete/shift-delete/popupmenu)
+
+ fixed quite a few buglets with keyboard navigation (pageUp didn't
+ halt when a directory was found). pageUp/down and the like shall only
+ select files.
+
+ worked around kwm-bug (resize doesn't work properly after
+ KWM::setDecoration( noDecoration )
+
+Tue Dec 29 16:55:11 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/kuickshow.cpp, imlibwidget.cpp, kfileview.*:
+ fixed updating of directory in statusbar and filename in caption of
+ imlibwidget
+
+ fileview is prepared to support sorting and filtering
+
+ added toggle showing hidden files (accessible via toolbar)
+
+ added Home-Button in toolbar to change to home directory
+
+Wed Nov 18 15:40:46 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imlibwidget.cpp (mouseMoveEvent):
+
+ fixed cursor not being reset to arrorCursor, when shift-key was
+ released during resize ( == abort resizing )
+
+Wed Nov 18 15:09:36 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/kuickshow.cpp (saveSettings):
+
+ size of the browserwindow is now saved and restored on next start
+
+Mon Nov 9 23:16:32 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * hopefully fixed autoconf stuff, which was broken at least on SunOS
+ Now tries to detect imlib-config and links against
+ `imlib-config --libs`. If this doesn't work, it links against
+ every graphics lib of libgif, libjpeg, libtiff and libpng, that
+ is available.
+ Another little bug is fixed, any changes (contrast/brightness/gamma)
+ were not saved when using "save as"
+
+Sat Nov 7 15:22:18 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imlibwidget.cpp
+ added changing of brightness, contrast and gamma via keyboard and popup menu
+ added saving image
+ the factor, how much brightness/contrast/gamma you change with one click is
+ only editable in configfile, no dialog, yet.
+
+Sat Nov 7 12:57:48 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * acinclude.m4 (ac_imlib_config):
+ added some configure-stuff to use `imlib-config' to determine the libs
+ to be linked against.
+
+Sun Oct 11 23:58:46 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imlibwidget.cpp (loadImageInternal):
+ added configuration option to not override the color palette
+ useful for 8bit displays
+
+ * src/kuickshow.cpp:
+ fixed segfault when imlib can't load image
+ (don't preload the next image, then)
+
+Wed Sep 30 19:39:15 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * acinclude.m4, configure.in:
+ Added a configure-check for Imlib. Still incomplete (does NOT
+ check for all those other libs as libgif, libjpeg, libz, ...),
+ but at least finds libImlibs which are too old.
+
+ src/kuickshow.cpp (about):
+ about dialog is centered, now
+
+Fri Sep 25 19:32:13 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imlibwidget.cpp (keyPressEvent):
+ Now behavior of scrolling/zooming with mouse is fixed:
+ pressing left mousebutton and moving the mouse will move the image
+ (only if it image is larger than current window)
+
+ Pressing Shift, left mousebutton and moving the mouse will zoom into
+ the image. Releasing Shift-button before mousebutton will abort zooming
+
+Thu Sep 24 02:41:26 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imlibwidget.cpp (mouseReleaseEvent):
+ Ahh, finally I got "zoom inside image with mouse" working perfectly.
+ A rectangle is painted and this rectangle is zoomed and centered.
+ Not the very best solution, tho, as imlib is zooming the entire
+ image, not only the selected part... guess how long it can take for
+ bigger images.
+ Gotta find another solution later, creating a new imlib image with
+ just the selected part.
+
+Tue Sep 22 21:05:58 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imlibwidget.cpp (preloadImage):
+ Added preloading facility. Fills the cache with the next image, so it
+ will pop up almost instantaneously, when pressing PageUp/Down.
+ Configurable via dialog.
+
+Mon Sep 21 16:29:56 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/kuickshow.cpp (eventFilter):
+ Added "Enter-key", that reloads current image (so all zoom/move stuff
+ is restored to original settings).
+
+Sun Sep 20 19:04:23 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/kfileview.cpp (prev):
+ whoops, fixed a segfault, when trying to get a kfileinfo of index -1.
+ I shouldn't check, whether an unsigned int is smaller than 0, which it
+ actually was. Now uses int.
+
+Sun Sep 20 13:35:00 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imlibwidget.cpp (closeEvent):
+ reverted to override closeEvent() and changed every occurrence of
+ close( true ) to close( false ), as closeEvent now explicitely
+ deletes itself.
+ This was due to windowmanagers close-button, which should delete widget
+
+Sun Sep 20 03:08:45 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/kuickshow.cpp (printImage):
+ added preliminary support for printing
+
+Sat Sep 19 01:40:22 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imlibwidget.cpp (rotate):
+ added rotate-routine to - doh - rotate an image
+
+Fri Sep 18 01:08:46 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imlibwidget.cpp (scrollImage):
+ Now changes cursor when attempting to move the image with the mouse
+ Also, image can be moved now, when in window mode and window is
+ larger than desktop
+
+Thu Sep 17 17:25:11 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imlibwidget.cpp (setPopupMenu):
+ the fix for the popupmenu also let me finally delete it without
+ segfault :o)
+
+Thu Sep 17 13:13:09 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/kuickconfigdlg.cpp (KuickConfigDialog):
+ enlargened maxCache lineedit and changed tooltip
+
+ * src/imlibconfig.cpp
+ changed default value for maxCache from 0 to 10000 (10megs)
+
+ * src/imlibwidget.cpp (scrollImage):
+ restricted scrolling so that you can move the image only
+ if it doesn't fit onto the screen.
+ You can't move the image out of the screen anymore.
+
+ Also fixed a segfault (ugh) in viewerMenu->popup(), as it was
+ initialized in the wrong place (now in initImlib()).
+
+
+Thu Sep 17 00:11:53 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imlibwidget.cpp (loadImage):
+ re-enabled Imlib_destroy_image()
+ Found another value in imlib configuration struct, pixmapcachesize
+ which I wasn't aware of. Now limiting imlib's cache really works :o))
+ I'm really happy now :-) Running out of Ram and even Swap is not too
+ funny ;o)
+
+Tue Sep 15 20:28:49 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imlibwidget.cpp (centerImage):
+ fixed images not centering when larger than screen and in fullscreen
+ mode.
+
+
+Tue Sep 15 14:06:27 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imlibwidget.cpp (mouseMoveEvent):
+ scrolling the image with the mouse is now possible. Didn't expect
+ scrolling would be so smooth :o)
+ Also added a popupmenu (ImlibWidget::setPopupmenu( bool )) for
+ the basic features like zoom and flip image
+
+Mon Sep 14 16:20:30 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/fileview.cpp/.h
+ * src/kfileview.cpp/.h
+ * src/kuickshow.cpp
+ added "change directory" possibility. A dialog asks for a directory
+ and the fileview is being updated. Either accessible via the
+ popupmenu, or via Ctrl-g (goto)
+
+ * src/kuickshow.cpp (KuickShow):
+ once again optimized commandline parsing
+
+Mon Sep 14 13:24:40 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * funny, I added lots of stuff, moved some other stuff around and
+ the result is a binary about 30k smaller than before :-D
+
+ * src/fileview.cpp (findCompletion):
+ *strike* now even filecompletion works :-) If you hit some keys
+ on your keyboard, while in the filebrowser, a small edit window pops
+ up in the bottom-right corner. Just type in the first chars of the
+ filename of the image you want to see, and it will be highlighted.
+
+ * src/kuickshow.cpp, src/imlibwidget.h/.cpp:
+ Cool. Now, I have only one ImlibData object, so I share imlib's
+ cache between all open windows. This does not only speed things
+ up quite a bit, but also reduced memory usage with multiple open
+ windows.
+ ImlibWidget therefore has a new constructor, where you can pass the
+ pointer to the ImlibData object.
+
+ * src/imlibwidget.cpp (ImlibWidget):
+ now creates an ImlibConfig object itself, when none has been given
+ in the contructor
+
+Sun Sep 13 23:28:31 1998 Carsten Pfeiffer <pfeiffer@kde.org>
+
+ * src/imlibwidget.cpp (renderImage):
+ Don't destroy images ( Imlib_destroy_image() ) anymore. This boosts
+ browsing a LOT. Showing cached images is almosts instantaneous now!
+ Hope there's no sideeffect on this :-}
+
+ * src/kuickshow.cpp (eventFilter):
+ space toggles show()ing and hide()ing the browser now.
+ If started with image as parameter, kuickshow doesn't show
+ the browser, hit space to show it.
+
+ * src/fileview.h (class FileView):
+ findCompletion() is now public, so that I can tell the browser
+ to highlight the file, supplied via commandline.
+
+
+History:
+--------
+- found that xemacs can create much better changelogs :o)
+- hacked a lot of goodies into KuickShow, several configuration options
+- decided to have a look at the Xlib stuff and found out, how to map
+ an Imlib image onto any QWidget - this is cool :o)
+- too bad, it was not very reliable and it was a mess, too
+- with my Xlib non-knowledge, found a way to "swallow" an Imlib image
+ onto a QWidget - imagine how happy I was :o)
+- if Kopacz got Imlib to work, I could do that, too :-P
+- end of August 98, saw Adam Kopacz' release of qiv (quick image viewer)
+ damn, this was my name (kiv, kuick image viewer) :o(
+- first tries to use Imlib to display on Qt/KDE widgets in April 98,
+ too bad, it didn't work :o(
+- first hack of kview to use a filebrowser in January
+- had the idea for such an app about December 97
+</pre>
diff --git a/kuickshow/Makefile.am b/kuickshow/Makefile.am
new file mode 100644
index 00000000..e53fd831
--- /dev/null
+++ b/kuickshow/Makefile.am
@@ -0,0 +1,8 @@
+SUBDIRS = src misc pics
+
+kuickshow-package:
+ @export CVSROOT=`cat CVS/Root`; \
+ kuickdir=$$PWD; \
+ kuickver=`cat src/version.h | grep define | cut -f3 -d' ' | sed -e 's/"//g'`; \
+ cd /tmp; \
+ cvs2dist `dirname $$kuickdir` kuickshow --remove-hidden --version $$kuickver $$kuickdir/TODO $$kuickdir/BUGS $$kuickdir/kuickshow.lsm $$kuickdir/kuickshow.spec $$kuickshow/../Makefile.cvs
diff --git a/kuickshow/README b/kuickshow/README
new file mode 100644
index 00000000..e6167514
--- /dev/null
+++ b/kuickshow/README
@@ -0,0 +1,8 @@
+KuickShow v0.8
+Carsten Pfeiffer <pfeiffer@kde.org>
+----------------------------------------------------------------------
+KuickShow is a very fast and comfortable imageviewer, somewhat inspired
+by ACDSee (early versions :)
+
+See http://devel-home.kde.org/~pfeiffer/kuickshow/ for updated versions,
+see ChangeLog for what has changed.
diff --git a/kuickshow/TODO b/kuickshow/TODO
new file mode 100644
index 00000000..0f75ec1c
--- /dev/null
+++ b/kuickshow/TODO
@@ -0,0 +1,24 @@
+toolbar in imageviewer
+
+- Ctrl-S = Save current, Shift-Ctrl-S = Filedialog
+
+- allow to split browser into subwindows (multiple browsers)
+- mouse-usage better (e.g. left button = next image, middle button = previous
+ image, all configurable)
+- anim-gif support (QMovie perhaps)
+- cropping images (via Imlib_clone_scaled_image & Imlib_crop_and_clone_image())
+- thumbnail view, treeview
+- menubar (same as popupmenu) (abschaltbar) (mac-mode!)
+
+- configure-dialog: offer a directory to copy files to -> one click copies to it
+- rename/delete into popupmenu of imagewindow
+
+- if image not readable -> no nagscreen, jump to next image
+- network transparency with kio
+
+- small preview in browser window
+- bookmarks?
+- generate wallpaper (background desktop image)
+- display more image information (resolution, color depth, image comments...)
+- better slideshow (randomize, pause/continue, reverse, ...)
+- what else?
diff --git a/kuickshow/configure.in.bot b/kuickshow/configure.in.bot
new file mode 100644
index 00000000..ef8aaf93
--- /dev/null
+++ b/kuickshow/configure.in.bot
@@ -0,0 +1,9 @@
+if test -z "$LIB_IMLIB"; then
+ echo ""
+ echo "You're missing Imlib 1.x. The graphics browser/viewer KuickShow"
+ echo "won't be compiled without Imlib."
+ echo "You can download it from"
+ echo "http://freshmeat.net/redir/imlib/4385/url_tgz/imlib-1.9.10.tar.gz"
+ echo ""
+ all_tests=bad
+fi
diff --git a/kuickshow/configure.in.in b/kuickshow/configure.in.in
new file mode 100644
index 00000000..fb1f0432
--- /dev/null
+++ b/kuickshow/configure.in.in
@@ -0,0 +1,69 @@
+#MIN_CONFIG
+
+#AM_INIT_AUTOMAKE(kuickshow,0.8.2)
+
+# my own additions to KDE's version
+#
+# checking for Imlib...
+
+AC_DEFUN([KDE_FIND_IMLIB_CONFIG],
+ [AC_MSG_CHECKING([for imlib-config])
+
+imlib_config_given=NO
+ac_imlib_config=""
+
+AC_ARG_WITH(imlib-config,
+AC_HELP_STRING([--with-imlib-config=DIR],[directory where "imlib-config" is located]),
+[ ac_imlib_config="$withval/imlib-config"
+ imlib_config_given=yes
+])
+
+if test "$imlib_config_given" = "yes"; then
+ if test ! -r $ac_imlib_config; then
+ AC_MSG_RESULT(wrong file specified)
+ ac_imlib_config=""
+ else
+ AC_MSG_RESULT($ac_imlib_config)
+ LIB_IMLIB=`$ac_imlib_config --libs`
+ AC_SUBST(LIB_IMLIB)
+ fi
+else
+ ac_imlib_config=`which imlib-config 2>/dev/null`
+ if test -z "$ac_imlib_config"; then
+ AC_MSG_RESULT(no)
+ else
+ dummy=`echo "$ac_imlib_config" | grep '/imlib-config'`
+ if test -z "$dummy"; then
+ AC_MSG_RESULT(no)
+ ac_imlib_config=""
+ else
+ LIB_IMLIB=`$ac_imlib_config --libs`
+ IMLIB_CFLAGS=`$ac_imlib_config --cflags`
+ imlib_config=`echo "$LIB_IMLIB" | grep lImlib`
+ if test -z "$imlib_config"; then
+ AC_MSG_RESULT(no)
+ ac_imlib_config=""
+ else
+ AC_SUBST(LIB_IMLIB)
+ AC_SUBST(IMLIB_CFLAGS)
+ AC_MSG_RESULT($ac_imlib_config)
+ fi
+ fi
+ fi
+fi
+
+])
+
+dnl #### now some kuickshow stuff ###
+dnl Check if Imlib is installed properly
+KDE_PKG_CHECK_MODULES(IMLIB, imlib >= 1.9.10,
+ LIB_IMLIB=$IMLIB_LIBS
+ AC_SUBST(LIB_IMLIB)
+,
+KDE_FIND_IMLIB_CONFIG
+)
+
+if test -z "$LIB_IMLIB"; then
+dnl AC_MSG_ERROR([You need to install Imlib 1.x, e.g. http://freshmeat.net/redir/imlib/4385/url_tgz/imlib-1.9.10.tar.gz if your distributor doesn't have a package])
+ DO_NOT_COMPILE="$DO_NOT_COMPILE kuickshow"
+fi
diff --git a/kuickshow/kuickshow.lsm b/kuickshow/kuickshow.lsm
new file mode 100644
index 00000000..4872440c
--- /dev/null
+++ b/kuickshow/kuickshow.lsm
@@ -0,0 +1,18 @@
+Begin3
+Title: KuickShow
+Version: 0.8.5
+Entered-date: August 2001
+Description: KuickShow is a very fast image viewer, that lets you easily
+ browse large galleries. A builtin filebrowser and manager
+ is also available. Usage is somewhat inspired by ACDSee.
+Keywords: KDE Qt Graphics Images Imageviewer Imlib
+Author: Carsten Pfeiffer <pfeiffer@kde.org>
+Maintained-by: Carsten Pfeiffer <pfeiffer@kde.org>
+Home-page: http://devel-home.kde.org/~pfeiffer/kuickshow/
+Alternate-site: ftp://ftp.kde.org/pub/kde/stable/apps/graphics/
+Primary-site: http://devel-home.kde.org/~pfeiffer/kuickshow/
+ xxxxxx kuickshow-0.8.5.tar.gz
+ xxx kuickshow-0.8.5.lsm
+Platform: Unix. Needs Qt >= 3.0.4, KDE (kdelibs) >= 3.0 and Imlib 1.x
+Copying-policy: GPL
+End
diff --git a/kuickshow/kuickshow.spec b/kuickshow/kuickshow.spec
new file mode 100644
index 00000000..0fcba9ea
--- /dev/null
+++ b/kuickshow/kuickshow.spec
@@ -0,0 +1,69 @@
+%define version 0.8.5
+%define release 1
+%define serial 1
+%define prefix /opt/kde3
+
+Name: kuickshow
+Summary: KuickShow -- A very fast image viewer/browser
+Version: %{version}
+Release: %{release}
+Serial: %{serial}
+Source: http://devel-home.kde.org/~pfeiffer/kuickshow/kuickshow-%{version}.tar.gz
+URL: http://devel-home.kde.org/~pfeiffer/kuickshow/
+Copyright: GPL
+Packager: Carsten Pfeiffer <pfeiffer@kde.org>
+Group: X11/KDE/Graphics
+BuildRoot: /tmp/kuickshow-%{version}-root
+Prefix: %{prefix}
+
+%description
+KuickShow is a very fast image viewer, that lets you easily
+browse large galleries. A builtin filebrowser and manager
+is also available. Usage is somewhat inspired by ACDSee.
+It supports many fileformats, e.g. jpeg, gif, png, psd, bmp,
+tiff, xpm, xbm, xcf, eim, ...
+
+KuickShow has a nice user interface, that allows you to browse large amounts
+of images in a short time. It can zoom, mirror, rotate images, adjust
+brightness, contrast and gamma and can do a slideshow, of course.
+It is fully configurable through dialogs.
+
+Besides that, it offers a nice filebrowser with basic filemanager capabilities
+like renaming, deleting, creating directories, ...
+
+Install with '--prefix $KDEDIR' unless you have the kde-config program.
+
+%prep
+rm -rf $RPM_BUILD_ROOT
+
+%setup -n kuickshow-%{version}
+
+%build
+PREFIX=""
+which kde-config || PREFIX=%{prefix}
+if test -z "$PREFIX"; then
+ PREFIX=`kde-config --prefix`
+fi
+
+export KDEDIR="$PREFIX"
+CXXFLAGS="$RPM_OPT_FLAGS -fno-exceptions -pipe" LDFLAGS=-s ./configure --prefix="$PREFIX" --enable-final --disable-debug
+mkdir -p $RPM_BUILD_ROOT
+make
+
+%install
+make install DESTDIR=$RPM_BUILD_ROOT
+
+cd $RPM_BUILD_ROOT
+
+find . -type d | sed '1,2d;s,^\.,\%attr(-\,root\,root) \%dir ,' > $RPM_BUILD_DIR/file.list.%{name}
+
+find . -type f | sed 's,^\.,\%attr(-\,root\,root) ,' >> $RPM_BUILD_DIR/file.list.%{name}
+
+find . -type l | sed 's,^\.,\%attr(-\,root\,root) ,' >> $RPM_BUILD_DIR/file.list.%{name}
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+rm -f $RPM_BUILD_DIR/file.list.%{name}
+
+%files -f ../file.list.%{name}
+
diff --git a/kuickshow/misc/Makefile.am b/kuickshow/misc/Makefile.am
new file mode 100644
index 00000000..caea8ab1
--- /dev/null
+++ b/kuickshow/misc/Makefile.am
@@ -0,0 +1,2 @@
+pal_DATA = im_palette.pal
+paldir = $(kde_datadir)/kuickshow
diff --git a/kuickshow/misc/im_palette.pal b/kuickshow/misc/im_palette.pal
new file mode 100644
index 00000000..9a243f73
--- /dev/null
+++ b/kuickshow/misc/im_palette.pal
@@ -0,0 +1,64 @@
+0x0 0x0 0x0
+0xff 0xff 0xff
+0xff 0x0 0x0
+0xff 0xff 0x0
+0x0 0xff 0x0
+0x0 0x0 0xff
+0x0 0xff 0xff
+0x99 0x99 0x99
+0xff 0x88 0x0
+0x88 0x0 0x0
+0x0 0x88 0x88
+0x88 0x88 0x0
+0xff 0xcc 0x97
+0xbb 0xbb 0xbb
+0x9f 0x6b 0x42
+0x55 0x55 0x55
+0xdd 0xdd 0xdd
+0x77 0x77 0x77
+0x33 0x33 0x33
+0xcc 0x0 0x0
+0xff 0x44 0x0
+0xff 0xcc 0x0
+0xcc 0xcc 0x0
+0x60 0x60 0x0
+0x0 0x43 0x0
+0x0 0x7f 0x0
+0x0 0xcc 0x0
+0x0 0x44 0x44
+0x0 0x0 0x44
+0x0 0x0 0x88
+0xef 0xb1 0x7b
+0xdf 0x98 0x5f
+0xbf 0x87 0x56
+0x7f 0x57 0x26
+0x5f 0x39 0xc
+0x3f 0x1c 0x0
+0x21 0x0 0x0
+0x0 0x43 0x87
+0x2d 0x70 0xaf
+0x5a 0x9e 0xd7
+0x87 0xcc 0xff
+0xff 0xe0 0xba
+0x21 0x43 0xf
+0x3d 0x5d 0x25
+0x59 0x78 0x3a
+0x75 0x93 0x4f
+0x91 0xae 0x64
+0xad 0xc8 0x7a
+0xf0 0xa8 0xef
+0xd0 0x88 0xd0
+0xaf 0x66 0xaf
+0x8e 0x44 0x8e
+0x6d 0x22 0x6d
+0x4b 0x0 0x4b
+0xff 0xc0 0xbc
+0xff 0x93 0x91
+0xff 0x66 0x67
+0xd8 0xf2 0xbf
+0xff 0xc9 0x68
+0xff 0x96 0x67
+0xa5 0x60 0xff
+0x51 0xff 0x99
+0x3f 0xa5 0x63
+0x98 0x90 0x67
diff --git a/kuickshow/pics/Makefile.am b/kuickshow/pics/Makefile.am
new file mode 100644
index 00000000..198327f8
--- /dev/null
+++ b/kuickshow/pics/Makefile.am
@@ -0,0 +1,7 @@
+# Add all of your pixmaps here
+pics_DATA = calibrate.png kuickshow-day.jpg kuickshow-night.jpg logo.png \
+ imageviewer-medium.png imageviewer-small.png handcursor.png \
+ ksslide.png about.png
+
+# This is where it will all be installed
+picsdir = $(kde_datadir)/kuickshow/pics
diff --git a/kuickshow/pics/about.png b/kuickshow/pics/about.png
new file mode 100644
index 00000000..a5468c1d
--- /dev/null
+++ b/kuickshow/pics/about.png
Binary files differ
diff --git a/kuickshow/pics/arrows.png b/kuickshow/pics/arrows.png
new file mode 100644
index 00000000..f1d4d51c
--- /dev/null
+++ b/kuickshow/pics/arrows.png
Binary files differ
diff --git a/kuickshow/pics/calibrate.png b/kuickshow/pics/calibrate.png
new file mode 100644
index 00000000..ca5296df
--- /dev/null
+++ b/kuickshow/pics/calibrate.png
Binary files differ
diff --git a/kuickshow/pics/handcursor.png b/kuickshow/pics/handcursor.png
new file mode 100644
index 00000000..61af7bd7
--- /dev/null
+++ b/kuickshow/pics/handcursor.png
Binary files differ
diff --git a/kuickshow/pics/imageviewer-medium.png b/kuickshow/pics/imageviewer-medium.png
new file mode 100644
index 00000000..8b2ce5cb
--- /dev/null
+++ b/kuickshow/pics/imageviewer-medium.png
Binary files differ
diff --git a/kuickshow/pics/imageviewer-small.png b/kuickshow/pics/imageviewer-small.png
new file mode 100644
index 00000000..cb9dddce
--- /dev/null
+++ b/kuickshow/pics/imageviewer-small.png
Binary files differ
diff --git a/kuickshow/pics/ksslide.png b/kuickshow/pics/ksslide.png
new file mode 100644
index 00000000..b7109e14
--- /dev/null
+++ b/kuickshow/pics/ksslide.png
Binary files differ
diff --git a/kuickshow/pics/kuickshow-day.jpg b/kuickshow/pics/kuickshow-day.jpg
new file mode 100644
index 00000000..b257e429
--- /dev/null
+++ b/kuickshow/pics/kuickshow-day.jpg
Binary files differ
diff --git a/kuickshow/pics/kuickshow-night.jpg b/kuickshow/pics/kuickshow-night.jpg
new file mode 100644
index 00000000..f755c2e4
--- /dev/null
+++ b/kuickshow/pics/kuickshow-night.jpg
Binary files differ
diff --git a/kuickshow/pics/logo.png b/kuickshow/pics/logo.png
new file mode 100644
index 00000000..7e2305a4
--- /dev/null
+++ b/kuickshow/pics/logo.png
Binary files differ
diff --git a/kuickshow/src/Makefile.am b/kuickshow/src/Makefile.am
new file mode 100644
index 00000000..57c92388
--- /dev/null
+++ b/kuickshow/src/Makefile.am
@@ -0,0 +1,31 @@
+## Makefile.am for kuickshow
+
+bin_PROGRAMS =
+lib_LTLIBRARIES =
+kdeinit_LTLIBRARIES = kuickshow.la
+
+# set the include path for X, qt and KDE
+INCLUDES = $(all_includes)
+KDE_CXXFLAGS = $(IMLIB_CFLAGS)
+METASOURCES = AUTO
+
+kuickshow_la_LDFLAGS = $(all_libraries) -module -avoid-version
+kuickshow_la_LIBADD = $(LIB_KDEPRINT) $(LIB_IMLIB)
+kuickshow_la_SOURCES = kuickshow.cpp \
+ aboutwidget.cpp generalwidget.cpp kuickconfigdlg.cpp main.cpp \
+ defaultswidget.cpp imagewindow.cpp kuickdata.cpp \
+ imdata.cpp filefinder.cpp kurlwidget.cpp filewidget.cpp \
+ kuick.cpp imlibwidget.cpp slideshowwidget.cpp printing.cpp \
+ kuickfile.cpp kuickimage.cpp filecache.cpp
+
+# if you "make distclean", this files get removed. If you want to remove
+# them while "make clean", use CLEANFILES
+DISTCLEANFILES = $(METASOURCES)
+
+messages:
+ $(XGETTEXT) *.cpp *.h -o $(podir)/kuickshow.pot
+
+KDE_ICON = kuickshow
+
+ # this is where the kdelnk file will go
+xdg_apps_DATA = kuickshow.desktop
diff --git a/kuickshow/src/aboutwidget.cpp b/kuickshow/src/aboutwidget.cpp
new file mode 100644
index 00000000..2ae41102
--- /dev/null
+++ b/kuickshow/src/aboutwidget.cpp
@@ -0,0 +1,95 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998-2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qdatetime.h>
+#include <qevent.h>
+#include <qglobal.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+
+#include <kwin.h>
+#include <kstandarddirs.h>
+
+#include "imlibwidget.h"
+#include "kurlwidget.h"
+#include "version.h"
+
+#include "aboutwidget.h"
+
+AboutWidget::AboutWidget( QWidget *parent, const char *name )
+ : QVBox( parent, name, Qt::WShowModal )
+{
+ KWin::setType( winId(), NET::Override );
+ KWin::setState( winId(), NET::SkipTaskbar );
+
+ setFrameStyle( WinPanel | Raised );
+
+ QGroupBox *gBox = new QGroupBox( 1, Horizontal, this);
+ gBox->setGeometry( 10, 10, width()-20, height()-20 );
+ gBox->setAlignment( AlignHCenter );
+ gBox->installEventFilter( this );
+
+ gBox->setPalette( QPalette( QColor( white ) ) );
+ gBox->setBackgroundMode( PaletteBackground );
+
+ int hour = QTime::currentTime().hour();
+ QString file;
+
+ if ( hour >= 10 && hour < 16 )
+ file = locate("appdata", "pics/kuickshow-day.jpg");
+ else
+ file = locate("appdata", "pics/kuickshow-night.jpg");
+
+ QLabel *authors = new QLabel("Kuickshow " KUICKSHOWVERSION
+ " was brought to you by", gBox);
+ authors->setAlignment( AlignCenter );
+
+ m_homepage = new KURLWidget("Carsten Pfeiffer", gBox);
+ m_homepage->setURL( "http://devel-home.kde.org/~pfeiffer/kuickshow/" );
+ m_homepage->setAlignment( AlignCenter );
+
+ QLabel *copy = new QLabel("(C) 1998-2006", gBox);
+ copy->setAlignment( AlignCenter );
+
+ ImlibWidget *im = new ImlibWidget( 0L, gBox, "KuickShow Logo" );
+ if ( im->loadImage( file ) )
+ im->setFixedSize( im->width(), im->height() );
+ else {
+ delete im;
+ im = 0L;
+ qWarning( "KuickShow: about-image not found/unreadable." );
+ }
+}
+
+AboutWidget::~AboutWidget()
+{
+}
+
+bool AboutWidget::eventFilter( QObject *o, QEvent *e )
+{
+ if ( e->type() == QEvent::MouseButtonPress ) {
+ QMouseEvent *ev = static_cast<QMouseEvent*>( e );
+ if ( !m_homepage->geometry().contains( ev->pos() ) ) {
+ deleteLater();
+ return true;
+ }
+ }
+
+ return QVBox::eventFilter( o, e );
+}
+#include "aboutwidget.moc"
diff --git a/kuickshow/src/aboutwidget.h b/kuickshow/src/aboutwidget.h
new file mode 100644
index 00000000..b9bc79d1
--- /dev/null
+++ b/kuickshow/src/aboutwidget.h
@@ -0,0 +1,43 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998-2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef ABOUTWIDGET_H
+#define ABOUTWIDGET_H
+
+#include <qevent.h>
+#include <qvbox.h>
+
+class KURLWidget;
+
+class AboutWidget : public QVBox
+{
+ Q_OBJECT
+
+public:
+ AboutWidget(QWidget *parent = 0, const char *name = 0);
+
+protected:
+ ~AboutWidget();
+ bool eventFilter( QObject*, QEvent * );
+
+private:
+ KURLWidget *m_homepage;
+
+};
+
+#endif
diff --git a/kuickshow/src/defaultswidget.cpp b/kuickshow/src/defaultswidget.cpp
new file mode 100644
index 00000000..69807251
--- /dev/null
+++ b/kuickshow/src/defaultswidget.cpp
@@ -0,0 +1,282 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998-2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qcheckbox.h>
+#include <qgroupbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qvgroupbox.h>
+
+#include <kcombobox.h>
+#include <kdialog.h>
+#include <klocale.h>
+#include <knuminput.h>
+#include <kstandarddirs.h>
+
+#include "imlibwidget.h"
+#include "defaultswidget.h"
+
+DefaultsWidget::DefaultsWidget( QWidget *parent, const char *name)
+ : QWidget( parent, name )
+{
+ imFiltered = 0L;
+
+ cbEnableMods = new QCheckBox( i18n("Apply default image modifications"), this );
+ connect( cbEnableMods, SIGNAL( toggled(bool) ), SLOT( enableWidgets(bool) ));
+
+ // create all the widgets
+
+ gbScale = new QGroupBox( i18n("Scaling"), this );
+ gbScale->setColumnLayout( 0, Qt::Horizontal );
+
+ cbDownScale = new QCheckBox( i18n("Shrink image to screen size, if larger"),
+ gbScale, "shrinktoscreen" );
+
+ cbUpScale = new QCheckBox( i18n("Scale image to screen size, if smaller, up to factor:"), gbScale, "upscale checkbox" );
+
+ sbMaxUpScaleFactor = new KIntNumInput( gbScale, "upscale factor" );
+ sbMaxUpScaleFactor->setRange( 1, 100, 1, false );
+
+ connect(cbUpScale, SIGNAL( toggled(bool)), sbMaxUpScaleFactor,
+ SLOT( setEnabled(bool) ));
+
+ // --
+
+ gbGeometry = new QGroupBox( i18n("Geometry"), this );
+ gbGeometry->setColumnLayout( 0, Qt::Horizontal );
+
+ cbFlipVertically = new QCheckBox( i18n("Flip vertically"), gbGeometry );
+
+ cbFlipHorizontally = new QCheckBox( i18n("Flip horizontally"), gbGeometry );
+
+ lbRotate = new QLabel( i18n("Rotate image:"), gbGeometry );
+
+ comboRotate = new KComboBox( gbGeometry, "rotate combobox" );
+ comboRotate->insertItem( i18n("0 Degrees") );
+ comboRotate->insertItem( i18n("90 Degrees") );
+ comboRotate->insertItem( i18n("180 Degrees") );
+ comboRotate->insertItem( i18n("270 Degrees") );
+
+ // --
+
+ gbAdjust = new QVGroupBox( i18n("Adjustments"), this );
+
+ sbBrightness = new KIntNumInput( gbAdjust, "brightness spinbox" );
+ sbBrightness->setRange( -256, 256, 1, true );
+ sbBrightness->setLabel( i18n("Brightness:"), AlignVCenter );
+
+ sbContrast = new KIntNumInput( sbBrightness, 0,gbAdjust, 10,
+ "contrast spinbox");
+ sbContrast->setRange( -256, 256, 1, true );
+ sbContrast->setLabel( i18n("Contrast:"), AlignVCenter );
+
+ sbGamma = new KIntNumInput( sbContrast, 0, gbAdjust, 10, "gamma spinbox" );
+ sbGamma->setRange( -256, 256, 1, true );
+ sbGamma->setLabel( i18n("Gamma:"), AlignVCenter );
+
+ // --
+
+ gbPreview = new QGroupBox( i18n("Preview"), this );
+ gbPreview->setAlignment( AlignCenter );
+
+ lbImOrig = new QLabel( i18n("Original"), gbPreview );
+ imOrig = new ImlibWidget( 0L, gbPreview, "original image" );
+
+ lbImFiltered = new QLabel( i18n("Modified"), gbPreview );
+ imFiltered = new ImlibWidget( 0L, imOrig->getImlibData(), gbPreview, "" );
+ connect( imFiltered, SIGNAL( destroyed() ), SLOT( slotNoImage() ));
+
+ ////
+ ////////////////
+
+
+ // layout management
+ QVBoxLayout *mainLayout = new QVBoxLayout( this, 0,
+ KDialog::spacingHint(), "main layout" );
+
+ QVBoxLayout *gbScaleLayout = new QVBoxLayout( gbScale->layout(),
+ KDialog::spacingHint());
+ QVBoxLayout *gbGeometryLayout = new QVBoxLayout(gbGeometry->layout(),
+ KDialog::spacingHint());
+ QGridLayout *gbPreviewLayout = new QGridLayout(gbPreview, 2, 3, 0,
+ KDialog::spacingHint());
+
+ QHBoxLayout *scaleLayout = new QHBoxLayout();
+ QHBoxLayout *rotateLayout = new QHBoxLayout();
+
+ mainLayout->addWidget( cbEnableMods );
+ mainLayout->addWidget( gbScale );
+ QHBoxLayout *hl = new QHBoxLayout();
+ hl->addWidget( gbGeometry );
+ hl->addWidget( gbAdjust );
+ mainLayout->addLayout( hl );
+ mainLayout->addWidget( gbPreview );
+ mainLayout->addStretch();
+
+ // --
+
+ gbScaleLayout->addWidget( cbDownScale );
+ gbScaleLayout->addLayout( scaleLayout );
+
+ scaleLayout->addWidget( cbUpScale );
+ scaleLayout->addWidget( sbMaxUpScaleFactor );
+
+ // --
+
+ gbGeometryLayout->addWidget( cbFlipVertically, 0, AlignLeft );
+ gbGeometryLayout->addWidget( cbFlipHorizontally, 0, AlignLeft );
+ gbGeometryLayout->addLayout( rotateLayout, 0 );
+
+ rotateLayout->addWidget( lbRotate, 0, AlignLeft );
+ rotateLayout->addWidget( comboRotate, 0, AlignLeft );
+
+ // --
+
+ gbPreviewLayout->setMargin( 10 );
+ gbPreviewLayout->setSpacing( KDialog::spacingHint() );
+ gbPreviewLayout->addWidget( lbImOrig, 0, 0, AlignCenter );
+ gbPreviewLayout->addWidget( imOrig, 1, 0, AlignCenter | AlignTop );
+ gbPreviewLayout->addWidget( lbImFiltered, 0, 2, AlignCenter );
+ gbPreviewLayout->addWidget( imFiltered, 1, 2, AlignCenter | AlignTop );
+
+
+ ////
+ ////////////////
+
+ // connect them all to the update slot
+ connect( cbDownScale, SIGNAL( clicked() ), SLOT( updatePreview() ));
+ connect( cbUpScale, SIGNAL( clicked() ), SLOT( updatePreview() ));
+ connect( cbFlipVertically, SIGNAL( clicked() ), SLOT( updatePreview() ));
+ connect( cbFlipHorizontally, SIGNAL( clicked() ), SLOT( updatePreview() ));
+ connect( sbMaxUpScaleFactor, SIGNAL( valueChanged(int) ), SLOT( updatePreview() ));
+ connect( sbBrightness, SIGNAL( valueChanged(int) ), SLOT( updatePreview() ));
+ connect( sbContrast, SIGNAL( valueChanged(int) ), SLOT( updatePreview() ));
+ connect( sbGamma, SIGNAL( valueChanged(int) ), SLOT( updatePreview() ));
+
+ connect( comboRotate, SIGNAL( activated(int) ), SLOT( updatePreview() ));
+
+
+ QString filename = locate( "data", "kuickshow/pics/calibrate.png" );
+ if ( !imOrig->loadImage( filename ) )
+ imOrig = 0L; // FIXME - display some errormessage!
+ if ( !imFiltered->loadImage( filename ) )
+ imFiltered = 0L; // FIXME - display some errormessage!
+
+ loadSettings( *kdata );
+
+ if ( imOrig )
+ imOrig->setFixedSize( imOrig->size() );
+ if ( imFiltered )
+ imFiltered->setFixedSize( imFiltered->size() );
+
+ mainLayout->activate();
+}
+
+
+DefaultsWidget::~DefaultsWidget()
+{
+ // those need to be deleted in the right order, as imFiltered
+ // references ImlibData from imOrig
+ delete imFiltered;
+ delete imOrig;
+}
+
+void DefaultsWidget::loadSettings( const KuickData& data )
+{
+ cbDownScale->setChecked( data.downScale );
+ cbUpScale->setChecked( data.upScale );
+ sbMaxUpScaleFactor->setValue( data.maxUpScale );
+
+ cbFlipVertically->setChecked( data.flipVertically );
+ cbFlipHorizontally->setChecked( data.flipHorizontally );
+
+ comboRotate->setCurrentItem( data.rotation );
+
+ ImData *id = data.idata;
+
+ sbBrightness->setValue( id->brightness );
+ sbContrast->setValue( id->contrast );
+ sbGamma->setValue( id->gamma );
+
+ cbEnableMods->setChecked( data.isModsEnabled );
+ enableWidgets( data.isModsEnabled );
+
+ updatePreview();
+}
+
+void DefaultsWidget::applySettings( KuickData& data )
+{
+ data.isModsEnabled = cbEnableMods->isChecked();
+
+ data.downScale = cbDownScale->isChecked();
+ data.upScale = cbUpScale->isChecked();
+ data.maxUpScale = sbMaxUpScaleFactor->value();
+
+ data.flipVertically = cbFlipVertically->isChecked();
+ data.flipHorizontally = cbFlipHorizontally->isChecked();
+
+ data.rotation = currentRotation();
+
+ ImData *id = data.idata;
+
+ id->brightness = sbBrightness->value();
+ id->contrast = sbContrast->value();
+ id->gamma = sbGamma->value();
+}
+
+void DefaultsWidget::updatePreview()
+{
+ if ( !imFiltered )
+ return;
+
+ imFiltered->setAutoRender( false );
+
+ int flipMode = cbFlipHorizontally->isChecked() ? FlipHorizontal : FlipNone;
+ flipMode |= cbFlipVertically->isChecked() ? FlipVertical : FlipNone;
+ imFiltered->setFlipMode( flipMode );
+
+ Rotation rotation = cbEnableMods->isChecked() ? currentRotation() : ROT_0;
+ imFiltered->setRotation( rotation );
+
+ imFiltered->setBrightness( sbBrightness->value() );
+ imFiltered->setContrast( sbContrast->value() );
+ imFiltered->setGamma( sbGamma->value() );
+
+ imFiltered->updateImage();
+ imFiltered->setAutoRender( true );
+}
+
+
+void DefaultsWidget::enableWidgets( bool enable )
+{
+ gbScale->setEnabled( enable );
+ sbMaxUpScaleFactor->setEnabled( enable & cbUpScale->isChecked() );
+
+ gbGeometry->setEnabled( enable );
+ gbAdjust->setEnabled( enable );
+ gbPreview->setEnabled( enable );
+ updatePreview();
+}
+
+
+Rotation DefaultsWidget::currentRotation() const
+{
+ return (Rotation) comboRotate->currentItem();
+}
+
+#include "defaultswidget.moc"
diff --git a/kuickshow/src/defaultswidget.h b/kuickshow/src/defaultswidget.h
new file mode 100644
index 00000000..3febb098
--- /dev/null
+++ b/kuickshow/src/defaultswidget.h
@@ -0,0 +1,73 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998-2003 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef DEFAULTSWIDGET_H
+#define DEFAULTSWIDGET_H
+
+#include "kuickdata.h"
+
+class ImlibWidget;
+class ImData;
+
+class QCheckBox;
+class QLabel;
+
+class KComboBox;
+class KIntNumInput;
+
+class DefaultsWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ DefaultsWidget( QWidget *parent, const char *name );
+ ~DefaultsWidget();
+
+ void loadSettings( const KuickData& data );
+ void applySettings( KuickData& data );
+
+private:
+ Rotation currentRotation() const;
+
+ QCheckBox *cbEnableMods;
+
+ QGroupBox *gbScale;
+ QCheckBox *cbUpScale, *cbDownScale;
+ KIntNumInput *sbMaxUpScaleFactor;
+
+ QGroupBox *gbAdjust;
+ KIntNumInput *sbBrightness, *sbContrast, *sbGamma;
+
+ QGroupBox *gbGeometry;
+ QLabel *lbRotate;
+ KComboBox *comboRotate;
+ QCheckBox *cbFlipVertically, *cbFlipHorizontally;
+
+ QGroupBox *gbPreview;
+ QLabel *lbImOrig, *lbImFiltered;
+ ImlibWidget *imOrig, *imFiltered;
+
+
+private slots:
+ void updatePreview();
+ void slotNoImage() { imFiltered = 0L; }
+ void enableWidgets( bool );
+
+};
+
+#endif
diff --git a/kuickshow/src/filecache.cpp b/kuickshow/src/filecache.cpp
new file mode 100644
index 00000000..c1c1affe
--- /dev/null
+++ b/kuickshow/src/filecache.cpp
@@ -0,0 +1,83 @@
+#include <unistd.h>
+
+#include <qstring.h>
+
+#include <kdebug.h>
+#include <kstandarddirs.h>
+#include <ktempdir.h>
+
+#include "filecache.h"
+
+FileCache * FileCache::s_self;
+
+FileCache::FileCache()
+ : m_limit( 0 ),
+ m_tempDir( 0L )
+{
+ m_files.setAutoDelete( true );
+ m_files.setMaxCost( 100 ); // good default? ### make configurable?
+}
+
+FileCache::~FileCache()
+{
+ delete m_tempDir;
+}
+
+void FileCache::shutdown()
+{
+ if ( s_self )
+ {
+ delete s_self;
+ s_self = 0L;
+ }
+}
+
+FileCache * FileCache::self()
+{
+ if ( !s_self )
+ s_self = new FileCache();
+ return s_self;
+}
+
+KuickFile * FileCache::getFile( const KURL& url )
+{
+ QString urlString = url.prettyURL();
+ KuickFile *file = m_files.find( urlString );
+ if ( !file ) {
+ file = new KuickFile( url );
+ m_files.insert( urlString, file );
+ }
+
+ return file;
+}
+
+QString FileCache::tempDir()
+{
+ if ( !m_tempDir ) {
+ m_tempDir = createTempDir();
+
+ if ( !m_tempDir ) {
+ kdWarning() << "Unable to create temporary directory for KuickShow" << endl;
+ return QString::null;
+ }
+ }
+
+ return m_tempDir->name();
+}
+
+
+KTempDir * FileCache::createTempDir()
+{
+ QString tmpName = QString::fromLatin1( KGlobal::instance()->instanceName() );
+ tmpName.append( QString::number( getpid() ) );
+ QString dirName = locateLocal( "tmp", tmpName );
+ KTempDir *dir = new KTempDir( dirName );
+ dir->setAutoDelete( true );
+ if ( dir->status() != 0L )
+ {
+ delete dir;
+ return 0L;
+ }
+
+ return dir;
+}
diff --git a/kuickshow/src/filecache.h b/kuickshow/src/filecache.h
new file mode 100644
index 00000000..16e53261
--- /dev/null
+++ b/kuickshow/src/filecache.h
@@ -0,0 +1,47 @@
+/****************************************************************************
+** $Id: .emacs,v 1.3 2006/02/20 15:06:53 gis Exp $
+**
+** Created : 2006
+**
+** Copyright (C) 2006 Carsten Pfeiffer <pfeiffer@kde.org>
+**
+****************************************************************************/
+
+#ifndef FILECACHE_H
+#define FILECACHE_H
+
+#include <qcache.h>
+
+#include "kuickfile.h"
+
+class KTempDir;
+
+class FileCache
+{
+public:
+ static FileCache * self();
+ static void shutdown();
+
+ KuickFile * getFile( const KURL& url );
+ void setLimit( int numFiles );
+ int getLimit() const { return m_limit; }
+
+ /**
+ * @return the temporary directory or QString::null if none available
+ */
+ QString tempDir();
+
+private:
+ static FileCache *s_self;
+ FileCache();
+ ~FileCache();
+
+ KTempDir * createTempDir();
+ QCache<KuickFile> m_files;
+
+ int m_limit;
+ KTempDir *m_tempDir;
+
+};
+
+#endif // FILECACHE_H
diff --git a/kuickshow/src/filefinder.cpp b/kuickshow/src/filefinder.cpp
new file mode 100644
index 00000000..9dda0046
--- /dev/null
+++ b/kuickshow/src/filefinder.cpp
@@ -0,0 +1,99 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998-2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qkeycode.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <kcompletionbox.h>
+#include <kurlcompletion.h>
+
+#include "filefinder.h"
+
+FileFinder::FileFinder( QWidget *parent, const char *name )
+ : KLineEdit( parent, name )
+{
+ // make this widget just as large, as the font is + 8 Pixels
+ int height = fontMetrics().height() + 8;
+ setFixedSize( 150, height );
+ setFrame( true );
+
+ setHandleSignals( true ); // we want the completionbox signals
+ completionBox()->setTabHandling( true );
+
+ connect( completionBox(), SIGNAL( userCancelled(const QString&) ),
+ SLOT( hide() ));
+ connect( completionBox(), SIGNAL( activated( const QString& ) ),
+ SLOT( slotAccept( const QString& )));
+ connect( this, SIGNAL( returnPressed( const QString& )),
+ SLOT( slotAccept( const QString& ) ));
+
+ KURLCompletion *comp = new KURLCompletion();
+ comp->setReplaceHome( true );
+ comp->setReplaceEnv( true );
+ setCompletionObject( comp, false );
+ setAutoDeleteCompletionObject( true );
+ setFocusPolicy( ClickFocus );
+
+ KConfig *config = KGlobal::config();
+ KConfigGroupSaver cs( config, "GeneralConfiguration" );
+ setCompletionMode( (KGlobalSettings::Completion)
+ config->readNumEntry( "FileFinderCompletionMode",
+ KGlobalSettings::completionMode()));
+}
+
+FileFinder::~FileFinder()
+{
+ KConfig *config = KGlobal::config();
+ KConfigGroupSaver cs( config, "GeneralConfiguration" );
+ config->writeEntry( "FileFinderCompletionMode", completionMode() );
+}
+
+void FileFinder::focusOutEvent( QFocusEvent *e )
+{
+ if ( e->reason() != QFocusEvent::Popup )
+ hide();
+}
+
+void FileFinder::keyPressEvent( QKeyEvent *e )
+{
+ int key = e->key();
+ if ( key == Key_Escape ) {
+ hide();
+ e->accept();
+ }
+
+ else {
+ KLineEdit::keyPressEvent( e );
+ }
+}
+
+void FileFinder::hide()
+{
+ KLineEdit::hide();
+ parentWidget()->setFocus();
+}
+
+void FileFinder::slotAccept( const QString& dir )
+{
+ hide();
+ emit enterDir( dir );
+}
+
+#include "filefinder.moc"
diff --git a/kuickshow/src/filefinder.h b/kuickshow/src/filefinder.h
new file mode 100644
index 00000000..f75c69a4
--- /dev/null
+++ b/kuickshow/src/filefinder.h
@@ -0,0 +1,54 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998-2003 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef FILEFINDER_H
+#define FILEFINDER_H
+
+#include <qevent.h>
+
+#include <klineedit.h>
+
+class KURLCompletion;
+
+class FileFinder : public KLineEdit
+{
+ Q_OBJECT
+
+public:
+ FileFinder( QWidget *parent=0, const char *name=0 );
+ ~FileFinder();
+
+ KURLCompletion *completion() {
+ return static_cast<KURLCompletion*>( completionObject() );
+ }
+
+ virtual void hide();
+
+signals:
+ void enterDir( const QString& );
+
+protected:
+ virtual void focusOutEvent( QFocusEvent * );
+ virtual void keyPressEvent( QKeyEvent * );
+
+private slots:
+ void slotAccept( const QString& );
+
+};
+
+#endif // FILEFINDER_H
diff --git a/kuickshow/src/filewidget.cpp b/kuickshow/src/filewidget.cpp
new file mode 100644
index 00000000..d4b99f0a
--- /dev/null
+++ b/kuickshow/src/filewidget.cpp
@@ -0,0 +1,464 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998-2003 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qkeycode.h>
+
+#include <kdeversion.h>
+#include <kglobal.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include <kpopupmenu.h>
+#include <kpropertiesdialog.h>
+#include <kurlcompletion.h>
+
+#include "filefinder.h"
+#include "filewidget.h"
+#include "kuickdata.h"
+#include "kuickshow.h"
+
+#ifdef KeyPress
+#undef KeyPress
+#endif
+
+FileWidget::FileWidget( const KURL& url, QWidget *parent, const char *name )
+ : KDirOperator( url, parent, name ),
+ m_validCompletion( false ),
+ m_fileFinder( 0L )
+{
+ setEnableDirHighlighting( true );
+
+#if KDE_VERSION >= 310
+ setViewConfig( KGlobal::config(), "Filebrowser" );
+#endif
+ readConfig( KGlobal::config(), "Filebrowser" );
+ setView( KFile::Default );
+
+ // setOnlyDoubleClickSelectsFiles( true );
+ reloadConfiguration();
+
+ completionObject()->setCompletionMode( KGlobalSettings::CompletionAuto );
+ dirCompletionObject()->setCompletionMode( KGlobalSettings::CompletionAuto);
+
+ slotViewChanged();
+ connect( this, SIGNAL( viewChanged( KFileView * )),
+ SLOT( slotViewChanged() ));
+
+ connect( dirLister(), SIGNAL( clear() ), SLOT( slotItemsCleared() ));
+ connect( dirLister(), SIGNAL( deleteItem( KFileItem * ) ),
+ SLOT( slotItemDeleted( KFileItem *) ));
+
+ connect( this, SIGNAL( fileHighlighted( const KFileItem * )),
+ SLOT( slotHighlighted( const KFileItem * )));
+
+ connect( this, SIGNAL(urlEntered(const KURL&)),
+ SLOT( slotURLEntered( const KURL& )));
+
+ // should actually be KDirOperator's job!
+ connect( this, SIGNAL( finishedLoading() ), SLOT( slotFinishedLoading() ));
+}
+
+FileWidget::~FileWidget()
+{
+ delete m_fileFinder;
+}
+
+void FileWidget::initActions()
+{
+ int index = 0;
+ KActionCollection *coll = actionCollection();
+ KActionSeparator *sep = new KActionSeparator( coll, "kuicksep" );
+ KActionMenu *menu = static_cast<KActionMenu*>( coll->action("popupMenu") );
+
+ menu->insert( coll->action("kuick_showInOtherWindow"), index++ );
+ menu->insert( coll->action("kuick_showInSameWindow"), index++ );
+ menu->insert( coll->action("kuick_showFullscreen"), index++ );
+ menu->insert( sep, index++ );
+
+ // support for older kdelibs, remove somewhen...
+ if ( coll->action("kuick_delete") )
+ menu->insert( coll->action("kuick_delete"), 9 );
+
+ // properties dialog is now in kfile, but not at the right position,
+ // so we move it to the real bottom
+ menu->remove( coll->action( "properties" ) );
+
+ QPopupMenu *pMenu = menu->popupMenu();
+ int lastItemId = pMenu->idAt( pMenu->count() - 1 );
+ QMenuItem *mItem = pMenu->findItem( lastItemId );
+ if ( mItem && !mItem->isSeparator() )
+ menu->insert( sep );
+
+ // those at the bottom
+ menu->insert( coll->action("kuick_print") );
+ menu->insert( sep );
+ menu->insert( coll->action("properties") );
+}
+
+void FileWidget::reloadConfiguration()
+{
+ if ( kdata->fileFilter != nameFilter() ) {
+ // At first, our list must have folders
+ QStringList mimes;
+ mimes.append("inode/directory");
+
+ // Then, all the images!
+ KMimeType::List l = KMimeType::allMimeTypes();
+ for (KMimeType::List::iterator it = l.begin(); it != l.end(); ++it)
+ if ((*it)->name().startsWith( "image/" ))
+ mimes.append( (*it)->name() );
+
+ // Ok, show what we've done
+ setMimeFilter (mimes);
+ updateDir();
+ }
+}
+
+bool FileWidget::hasFiles() const
+{
+ return (numFiles() > 0);
+}
+
+void FileWidget::activatedMenu( const KFileItem *item, const QPoint& pos )
+{
+ bool image = isImage( item );
+ actionCollection()->action("kuick_showInSameWindow")->setEnabled( image );
+ actionCollection()->action("kuick_showInOtherWindow")->setEnabled( image );
+ actionCollection()->action("kuick_showFullscreen")->setEnabled( image );
+ actionCollection()->action("kuick_print")->setEnabled( image );
+ actionCollection()->action("properties")->setEnabled( item );
+
+ bool hasSelection = (item != 0L);
+ if ( actionCollection()->action("kuick_delete") )
+ actionCollection()->action("kuick_delete")->setEnabled( hasSelection );
+
+ KDirOperator::activatedMenu( item, pos );
+}
+
+void FileWidget::findCompletion( const QString& text )
+{
+ if ( text.at(0) == '/' || text.at(0) == '~' ||
+ text.find('/') != -1 ) {
+ QString t = m_fileFinder->completion()->makeCompletion( text );
+
+ if (m_fileFinder->completionMode() == KGlobalSettings::CompletionPopup ||
+ m_fileFinder->completionMode() == KGlobalSettings::CompletionPopupAuto)
+ m_fileFinder->setCompletedItems(
+ m_fileFinder->completion()->allMatches() );
+ else
+ if ( !t.isNull() )
+ m_fileFinder->setCompletedText( t );
+
+ return;
+ }
+
+ QString file = makeDirCompletion( text );
+ if ( file.isNull() )
+ file = makeCompletion( text );
+
+ m_validCompletion = !file.isNull();
+
+ if ( m_validCompletion )
+ KDirOperator::setCurrentItem( file );
+}
+
+bool FileWidget::eventFilter( QObject *o, QEvent *e )
+{
+ if ( e->type() == QEvent::KeyPress ) {
+ QKeyEvent *k = static_cast<QKeyEvent*>( e );
+
+ if ( (k->state() & (ControlButton | AltButton)) == 0 ) {
+ int key = k->key();
+ if ( actionCollection()->action("delete")->shortcut().contains( key ) )
+ {
+ k->accept();
+ KFileItem *item = getCurrentItem( false );
+ if ( item ) {
+ KFileItemList list;
+ list.append( item );
+ del( list, (k->state() & ShiftButton) == 0 );
+ }
+ return true;
+ }
+
+ const QString& text = k->text();
+ if ( !text.isEmpty() && text.unicode()->isPrint() ) {
+ k->accept();
+
+ if ( !m_fileFinder ) {
+ m_fileFinder = new FileFinder( this, "file finder" );
+ connect( m_fileFinder, SIGNAL( completion(const QString&)),
+ SLOT( findCompletion( const QString& )));
+ connect( m_fileFinder,
+ SIGNAL( enterDir( const QString& ) ),
+ SLOT( slotReturnPressed( const QString& )));
+ m_fileFinder->move( width() - m_fileFinder->width(),
+ height() - m_fileFinder->height() );
+ }
+
+ bool first = m_fileFinder->isHidden();
+
+ m_fileFinder->setText( text );
+ m_fileFinder->raise();
+ m_fileFinder->show();
+ m_fileFinder->setFocus();
+ if ( first )
+ findCompletion( text );
+
+ return true;
+ }
+ }
+
+ k->ignore();
+ }
+ return KDirOperator::eventFilter( o, e );
+}
+
+
+// KIO::NetAccess::stat() does NOT give us the right mimetype, while
+// KIO::NetAccess::mimetype() does. So we have this hacklet to tell
+// showImage that the KFileItem is really an image.
+#define IS_IMAGE 5
+#define MY_TYPE 55
+
+bool FileWidget::isImage( const KFileItem *item )
+{
+// return item && !item->isDir();
+ if ( item )
+ {
+ return item->isReadable() && item->mimetype().startsWith( "image/") ||
+ item->extraData( (void*) MY_TYPE ) == (void*) IS_IMAGE;
+ }
+ return false;
+}
+
+void FileWidget::setImage( KFileItem& item, bool enable )
+{
+ if ( enable )
+ item.setExtraData( (void*) MY_TYPE, (void*) IS_IMAGE );
+ else
+ item.removeExtraData( (void*) MY_TYPE );
+}
+
+KFileItem * FileWidget::gotoFirstImage()
+{
+ KFileItemListIterator it( *(fileView()->items()) );
+
+ while ( it.current() ) {
+ if ( isImage( it.current() ) ) {
+ setCurrentItem( it.current() );
+ return it.current();
+ }
+ ++it;
+ }
+
+ return 0L;
+}
+
+KFileItem * FileWidget::gotoLastImage()
+{
+ KFileItemListIterator it( *(fileView()->items()) );
+ it.toLast();
+
+ while ( it.current() ) {
+ if ( isImage( it.current() ) ) {
+ setCurrentItem( it.current() );
+ return it.current();
+ }
+ --it;
+ }
+
+ return 0L;
+}
+
+KFileItem * FileWidget::getNext( bool go )
+{
+ KFileItem *item = getItem( Next, true );
+ if ( item ) {
+ if ( go )
+ setCurrentItem( item );
+ return item;
+ }
+
+ return 0L;
+}
+
+KFileItem * FileWidget::getPrevious( bool go )
+{
+ KFileItem *item = getItem( Previous, true );
+ if ( item ) {
+ if ( go )
+ setCurrentItem( item );
+ return item;
+ }
+
+ return 0L;
+}
+
+// returns 0L when there is no previous/next item/image
+// this sucks! Use KFileView::currentFileItem() when implemented
+KFileItem * FileWidget::getItem( WhichItem which, bool onlyImage ) const
+{
+ KFileItemListIterator it( *(fileView()->items()) );
+
+ while ( it.current() ) { // find the iterator to the current item
+ if ( it.current()->url() == m_currentURL )
+ break;
+
+ ++it;
+ }
+
+ if ( it.current() ) {
+ switch ( which ) {
+ case Previous: {
+ --it;
+ while ( it.current() ) {
+ if ( isImage( it.current() ) || !onlyImage )
+ return it.current();
+ --it;
+ }
+ return 0L; // no previous item / image
+ }
+
+ case Next: {
+ ++it;
+ while ( it.current() ) {
+ if ( isImage( it.current() ) || !onlyImage )
+ return it.current();
+ ++it;
+ }
+ return 0L; // no further item / image
+ }
+
+ case Current:
+ default:
+ return it.current();
+ }
+ }
+
+ return 0L;
+}
+
+void FileWidget::slotViewChanged()
+{
+ fileView()->widget()->installEventFilter( this );
+}
+
+void FileWidget::slotItemsCleared()
+{
+ m_currentURL = QString::null;
+}
+
+void FileWidget::slotItemDeleted( KFileItem *item )
+{
+ KFileItem *current = getCurrentItem( false );
+ if ( item != current ) {
+ return; // all ok, we already have a new current item
+ }
+
+ KFileItem *next = getNext();
+ if ( !next )
+ next = getPrevious();
+
+ if ( next )
+ m_currentURL = next->url().url();
+}
+
+void FileWidget::slotHighlighted( const KFileItem *item )
+{
+ m_currentURL = item->url().url();
+}
+
+void FileWidget::slotReturnPressed( const QString& t )
+{
+ // we need a / at the end, otherwise replacedPath() will cut off the dir,
+ // assuming it is a filename
+ QString text = t;
+ if ( text.at( text.length()-1 ) != '/' )
+ text += '/';
+
+ if ( text.at(0) == '/' || text.at(0) == '~' ) {
+ QString dir = m_fileFinder->completion()->replacedPath( text );
+
+ KURL url;
+ url.setPath( dir );
+ setURL( url, true );
+ }
+
+ else if ( text.find('/') != (int) text.length() -1 ) { // relative path
+ QString dir = m_fileFinder->completion()->replacedPath( text );
+ KURL u( url(), dir );
+ setURL( u, true );
+ }
+
+ else if ( m_validCompletion ) {
+ KFileItem *item = getCurrentItem( true );
+
+ if ( item ) {
+ if ( item->isDir() )
+ setURL( item->url(), true );
+ else
+ emit fileSelected( item );
+ }
+ }
+}
+
+void FileWidget::setCurrentItem( const KFileItem *item )
+{
+ if ( item ) {
+ fileView()->setCurrentItem( item );
+ fileView()->ensureItemVisible( item );
+ }
+}
+
+void FileWidget::setInitialItem( const QString& filename )
+{
+ m_initialName = filename;
+}
+
+void FileWidget::slotURLEntered( const KURL& url )
+{
+ if ( m_fileFinder )
+ m_fileFinder->completion()->setDir( url.path() );
+}
+
+void FileWidget::slotFinishedLoading()
+{
+ KFileItem *current = getCurrentItem( false );
+ if ( !m_initialName.isEmpty() )
+ setCurrentItem( m_initialName );
+ else if ( !current )
+ setCurrentItem( view()->items()->getFirst() );
+
+ m_initialName = QString::null;
+ emit finished();
+}
+
+QSize FileWidget::sizeHint() const
+{
+ return QSize( 300, 300 );
+}
+
+void FileWidget::resizeEvent( QResizeEvent *e )
+{
+ KDirOperator::resizeEvent( e );
+ if ( m_fileFinder )
+ m_fileFinder->move( width() - m_fileFinder->width(),
+ height() - m_fileFinder->height() );
+}
+
+#include "filewidget.moc"
diff --git a/kuickshow/src/filewidget.h b/kuickshow/src/filewidget.h
new file mode 100644
index 00000000..a785fd85
--- /dev/null
+++ b/kuickshow/src/filewidget.h
@@ -0,0 +1,98 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998-2003 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef FILEWIDGET_H
+#define FILEWIDGET_H
+
+#include <qevent.h>
+
+#include <kdiroperator.h>
+
+class FileFinder;
+class KFileItem;
+
+class FileWidget : public KDirOperator
+{
+ Q_OBJECT
+
+public:
+ enum WhichItem { Previous, Next, Current };
+
+ FileWidget( const KURL& url, QWidget *parent = 0L, const char *name = 0L );
+ ~FileWidget();
+
+ bool hasFiles() const;
+ void reloadConfiguration();
+
+ void setInitialItem( const QString& filename );
+
+ KFileItem *getCurrentItem( bool onlyImage ) const {
+ return getItem( Current, onlyImage );
+ }
+
+ void setCurrentItem( const KFileItem * );
+ void setCurrentItem( const QString& filename ) {
+ KDirOperator::setCurrentItem( filename );
+ }
+
+ KFileItem * gotoFirstImage();
+ KFileItem * gotoLastImage();
+ KFileItem * getNext( bool go=true );
+ KFileItem * getPrevious( bool go=true );
+
+
+ KFileItem *getItem( WhichItem which, bool onlyImage ) const;
+
+ static bool isImage( const KFileItem * );
+ static void setImage( KFileItem& item, bool enable );
+
+ void initActions();
+
+signals:
+ void finished();
+
+protected:
+ virtual bool eventFilter( QObject *o, QEvent * );
+ virtual void resizeEvent( QResizeEvent * );
+ virtual void activatedMenu( const KFileItem *, const QPoint& );
+ virtual QSize sizeHint() const;
+
+private slots:
+ void slotReturnPressed( const QString& text );
+ void findCompletion( const QString& );
+ void slotViewChanged();
+
+ void slotItemsCleared();
+ void slotItemDeleted( KFileItem * );
+ void slotHighlighted( const KFileItem * );
+
+ void slotURLEntered( const KURL& url );
+ void slotFinishedLoading();
+
+private:
+ KFileView * fileView() const { return (KFileView*) view(); }
+
+ bool m_validCompletion;
+ FileFinder *m_fileFinder;
+ QString m_currentURL;
+ QString m_initialName;
+
+};
+
+
+#endif // FILEWIDGET_H
diff --git a/kuickshow/src/generalwidget.cpp b/kuickshow/src/generalwidget.cpp
new file mode 100644
index 00000000..3b718d69
--- /dev/null
+++ b/kuickshow/src/generalwidget.cpp
@@ -0,0 +1,163 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998-2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qcheckbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qtooltip.h>
+#include <qvgroupbox.h>
+
+#include <kapplication.h>
+#include <kcolorbutton.h>
+#include <kdialog.h>
+#include <kiconloader.h>
+#include <klineedit.h>
+#include <klocale.h>
+#include <knuminput.h>
+#include <kurllabel.h>
+
+#include "generalwidget.h"
+
+GeneralWidget::GeneralWidget( QWidget *parent, const char *name )
+ : QWidget( parent, name )
+{
+ QVBoxLayout *layout = new QVBoxLayout( this );
+ layout->setSpacing( KDialog::spacingHint() );
+
+ QPixmap pixmap = UserIcon( "logo" );
+ KURLLabel *logo = new KURLLabel( this );
+ logo->setURL( "http://devel-home.kde.org/~pfeiffer/kuickshow/" );
+ logo->setPixmap( pixmap );
+ logo->setFixedSize( pixmap.size() );
+ logo->setTipText( i18n( "Open KuickShow Website" ) );
+ logo->setUseTips( true );
+
+ connect( logo, SIGNAL( leftClickedURL( const QString & ) ),
+ SLOT( slotURLClicked( const QString & ) ) );
+
+ layout->addWidget( logo, 0, AlignRight );
+
+ cbFullscreen = new QCheckBox( i18n("Fullscreen mode"), this, "boscreen" );
+
+ cbPreload = new QCheckBox( i18n("Preload next image"), this, "preload");
+ cbLastdir = new QCheckBox( i18n("Remember last folder"), this, "restart_lastdir");
+
+ QGridLayout *gridLayout = new QGridLayout( 2, 2 );
+ gridLayout->setSpacing( KDialog::spacingHint() );
+ QLabel *l0 = new QLabel( i18n("Background color:"), this );
+ colorButton = new KColorButton( this );
+
+ QLabel *l1 = new QLabel( i18n("Show only files with extension: "), this, "label" );
+ editFilter = new KLineEdit( this, "filteredit" );
+
+ gridLayout->addWidget( l0, 0, 0 );
+ gridLayout->addWidget( colorButton, 0, 1 );
+ gridLayout->addWidget( l1, 1, 0 );
+ gridLayout->addWidget( editFilter, 1, 1 );
+
+ layout->addWidget( cbFullscreen );
+ layout->addWidget( cbPreload );
+ layout->addWidget( cbLastdir );
+ layout->addLayout( gridLayout );
+
+ ////////////////////////////////////////////////////////////////////////
+
+ QVGroupBox *gbox2 = new QVGroupBox( i18n("Quality/Speed"),
+ this, "qualitybox" );
+ layout->addWidget( gbox2 );
+ layout->addStretch();
+
+ cbSmoothScale = new QCheckBox( i18n("Smooth scaling"), gbox2, "smoothscale" );
+ cbFastRender = new QCheckBox( i18n("Fast rendering"), gbox2, "fastrender" );
+ cbDither16bit = new QCheckBox( i18n("Dither in HiColor (15/16bit) modes"),
+ gbox2, "dither16bit" );
+
+ cbDither8bit = new QCheckBox( i18n("Dither in LowColor (<=8bit) modes"),
+ gbox2, "dither8bit" );
+
+ cbOwnPalette = new QCheckBox( i18n("Use own color palette"),
+ gbox2, "pal");
+ connect( cbOwnPalette, SIGNAL( clicked() ), this, SLOT( useOwnPalette() ) );
+
+ cbFastRemap = new QCheckBox( i18n("Fast palette remapping"), gbox2, "remap");
+
+ maxCacheSpinBox = new KIntNumInput( gbox2, "editmaxcache" );
+ maxCacheSpinBox->setLabel( i18n("Maximum cache size: "), AlignVCenter );
+ maxCacheSpinBox->setSuffix( i18n( " MB" ) );
+ maxCacheSpinBox->setSpecialValueText( i18n( "Unlimited" ) );
+ maxCacheSpinBox->setRange( 0, 400, 1 );
+
+ loadSettings( *kdata );
+ cbFullscreen->setFocus();
+}
+
+GeneralWidget::~GeneralWidget()
+{
+}
+
+void GeneralWidget::slotURLClicked( const QString & url )
+{
+ kapp->invokeBrowser( url );
+}
+
+void GeneralWidget::loadSettings( const KuickData& data )
+{
+ ImData *idata = data.idata;
+
+ colorButton->setColor( data.backgroundColor );
+ editFilter->setText( data.fileFilter );
+ cbFullscreen->setChecked( data.fullScreen );
+ cbPreload->setChecked( data.preloadImage );
+ cbLastdir->setChecked( data.startInLastDir );
+ cbFastRemap->setChecked( idata->fastRemap );
+ cbOwnPalette->setChecked( idata->ownPalette );
+ cbSmoothScale->setChecked( idata->smoothScale );
+ cbFastRender->setChecked( idata->fastRender );
+ cbDither16bit->setChecked( idata->dither16bit );
+ cbDither8bit->setChecked( idata->dither8bit );
+ maxCacheSpinBox->setValue( idata->maxCache / 1024 );
+
+ useOwnPalette(); // enable/disable remap-checkbox
+}
+
+void GeneralWidget::applySettings( KuickData& data)
+{
+ ImData *idata = data.idata;
+
+ data.backgroundColor = colorButton->color();
+ data.fileFilter = editFilter->text();
+ data.fullScreen = cbFullscreen->isChecked();
+ data.preloadImage = cbPreload->isChecked();
+ data.startInLastDir = cbLastdir->isChecked();
+
+ idata->smoothScale = cbSmoothScale->isChecked();
+ idata->fastRemap = cbFastRemap->isChecked();
+ idata->ownPalette = cbOwnPalette->isChecked();
+ idata->fastRender = cbFastRender->isChecked();
+ idata->dither16bit = cbDither16bit->isChecked();
+ idata->dither8bit = cbDither8bit->isChecked();
+
+ idata->maxCache = (uint) maxCacheSpinBox->value() * 1024;
+}
+
+void GeneralWidget::useOwnPalette()
+{
+ cbFastRemap->setEnabled( cbOwnPalette->isChecked() );
+}
+
+#include "generalwidget.moc"
diff --git a/kuickshow/src/generalwidget.h b/kuickshow/src/generalwidget.h
new file mode 100644
index 00000000..e39eef18
--- /dev/null
+++ b/kuickshow/src/generalwidget.h
@@ -0,0 +1,62 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998-2003 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef GENERALWIDGET_H
+#define GENERALWIDGET_H
+
+#include <qwidget.h>
+
+#include "kuickdata.h"
+
+class QCheckBox;
+class KColorButton;
+class KLineEdit;
+class KIntNumInput;
+
+
+class GeneralWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ GeneralWidget( QWidget *parent, const char *name );
+ ~GeneralWidget();
+
+ void loadSettings( const KuickData& data );
+ void applySettings( KuickData& data );
+
+private:
+ QCheckBox *cbFullscreen, *cbActiveWindow, *cbPreload, *cbLastdir;
+ QCheckBox *cbSmoothScale, *cbFastRemap, *cbFastRender;
+ QCheckBox *cbDither16bit, *cbDither8bit, *cbOwnPalette;
+
+ KLineEdit *editFilter;
+ KIntNumInput *maxCacheSpinBox;
+
+ KIntNumInput *sbMaxWidth, *sbMaxHeight;
+ KIntNumInput *sbZoomFactor;
+
+ KColorButton *colorButton;
+
+private slots:
+ void useOwnPalette();
+ void slotURLClicked( const QString & );
+
+};
+
+#endif
diff --git a/kuickshow/src/hi16-app-kuickshow.png b/kuickshow/src/hi16-app-kuickshow.png
new file mode 100644
index 00000000..9f764485
--- /dev/null
+++ b/kuickshow/src/hi16-app-kuickshow.png
Binary files differ
diff --git a/kuickshow/src/hi22-app-kuickshow.png b/kuickshow/src/hi22-app-kuickshow.png
new file mode 100644
index 00000000..d8750f31
--- /dev/null
+++ b/kuickshow/src/hi22-app-kuickshow.png
Binary files differ
diff --git a/kuickshow/src/hi32-app-kuickshow.png b/kuickshow/src/hi32-app-kuickshow.png
new file mode 100644
index 00000000..e70e573e
--- /dev/null
+++ b/kuickshow/src/hi32-app-kuickshow.png
Binary files differ
diff --git a/kuickshow/src/imagewindow.cpp b/kuickshow/src/imagewindow.cpp
new file mode 100644
index 00000000..c63a3c67
--- /dev/null
+++ b/kuickshow/src/imagewindow.cpp
@@ -0,0 +1,1251 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998-2006 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <stdlib.h>
+
+#include <qcheckbox.h>
+#include <qcursor.h>
+#include <qdrawutil.h>
+#include <qfileinfo.h>
+#include <qkeycode.h>
+#include <qpainter.h>
+#include <qpen.h>
+#include <qpopupmenu.h>
+
+#ifdef KDE_USE_FINAL
+#undef GrayScale
+#undef Color
+#endif
+#include <qrect.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qtimer.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kcursor.h>
+#include <kdebug.h>
+#include <kdeversion.h>
+#ifdef KDE_USE_FINAL
+#undef Unsorted
+#endif
+#include <kfiledialog.h>
+#include <kiconloader.h>
+#include <kimageeffect.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kprinter.h>
+#include <kpropertiesdialog.h>
+#include <kstdaccel.h>
+#include <kstdguiitem.h>
+#include <kstandarddirs.h>
+#include <kglobalsettings.h>
+#include <ktempfile.h>
+#include <kwin.h>
+#include <netwm.h>
+#include <kurldrag.h>
+#include <kio/netaccess.h>
+
+#include "filecache.h"
+#include "imagewindow.h"
+#include "kuick.h"
+#include "kuickdata.h"
+#include "kuickfile.h"
+#include "kuickimage.h"
+#include "printing.h"
+
+
+#undef GrayScale
+
+QCursor *ImageWindow::s_handCursor = 0L;
+
+ImageWindow::ImageWindow( ImData *_idata, ImlibData *id, QWidget *parent,
+ const char *name )
+ : ImlibWidget( _idata, id, parent, name )
+{
+ init();
+}
+
+ImageWindow::ImageWindow( ImData *_idata, QWidget *parent, const char *name )
+ : ImlibWidget( _idata, parent, name )
+{
+ init();
+}
+
+ImageWindow::~ImageWindow()
+{
+}
+
+
+void ImageWindow::init()
+{
+ setFocusPolicy( QWidget::StrongFocus );
+
+ KCursor::setAutoHideCursor( this, true, true );
+ KCursor::setHideCursorDelay( 1500 );
+
+ // give the image window a different WM_CLASS
+ XClassHint hint;
+ hint.res_name = const_cast<char*>( kapp->name() );
+ hint.res_class = const_cast<char*>( "ImageWindow" );
+ XSetClassHint( x11Display(), winId(), &hint );
+
+ viewerMenu = 0L;
+ gammaMenu = 0L;
+ brightnessMenu = 0L;
+ contrastMenu = 0L;
+
+
+ m_actions = new KActionCollection( this );
+
+ if ( !s_handCursor ) {
+ QString file = locate( "appdata", "pics/handcursor.png" );
+ if ( !file.isEmpty() )
+ s_handCursor = new QCursor( file );
+ else
+ s_handCursor = new QCursor( arrowCursor );
+ }
+
+ setupActions();
+ imageCache->setMaxImages( kdata->maxCachedImages );
+
+ transWidget = 0L;
+ myIsFullscreen = false;
+
+ xpos = 0, ypos = 0;
+ m_numHeads = ScreenCount( x11Display() );
+
+ setAcceptDrops( true );
+ setBackgroundColor( kdata->backgroundColor );
+
+ static QPixmap imageIcon = UserIcon( "imageviewer-medium" );
+ static QPixmap miniImageIcon = UserIcon( "imageviewer-small" );
+ KWin::setIcons( winId(), imageIcon, miniImageIcon );
+}
+
+void ImageWindow::updateActions()
+{
+ m_actions->readShortcutSettings();
+}
+
+void ImageWindow::setupActions()
+{
+ new KAction( i18n("Show Next Image"), KStdAccel::next(),
+ this, SLOT( slotRequestNext() ),
+ m_actions, "next_image" );
+ new KAction( i18n("Show Previous Image"), KStdAccel::prior(),
+ this, SLOT( slotRequestPrevious() ),
+ m_actions, "previous_image" );
+
+ new KAction( i18n("Delete Image"), SHIFT + Key_Delete,
+ this, SLOT( imageDelete() ),
+ m_actions, "delete_image" );
+ new KAction( i18n("Move Image to Trash"), Key_Delete,
+ this, SLOT( imageTrash() ),
+ m_actions, "trash_image" );
+
+ new KAction( i18n("Zoom In"), Key_Plus,
+ this, SLOT( zoomIn() ),
+ m_actions, "zoom_in" );
+ new KAction( i18n("Zoom Out"), Key_Minus,
+ this, SLOT( zoomOut() ),
+ m_actions, "zoom_out" );
+ new KAction( i18n("Restore Original Size"), Key_O,
+ this, SLOT( showImageOriginalSize() ),
+ m_actions, "original_size" );
+ new KAction( i18n("Maximize"), Key_M,
+ this, SLOT( maximize() ),
+ m_actions, "maximize" );
+
+ new KAction( i18n("Rotate 90 Degrees"), Key_9,
+ this, SLOT( rotate90() ),
+ m_actions, "rotate90" );
+ new KAction( i18n("Rotate 180 Degrees"), Key_8,
+ this, SLOT( rotate180() ),
+ m_actions, "rotate180" );
+ new KAction( i18n("Rotate 270 Degrees"), Key_7,
+ this, SLOT( rotate270() ),
+ m_actions, "rotate270" );
+
+ new KAction( i18n("Flip Horizontally"), Key_Asterisk,
+ this, SLOT( flipHoriz() ),
+ m_actions, "flip_horicontally" );
+ new KAction( i18n("Flip Vertically"), Key_Slash,
+ this, SLOT( flipVert() ),
+ m_actions, "flip_vertically" );
+
+ new KAction( i18n("Print Image..."), KStdAccel::print(),
+ this, SLOT( printImage() ),
+ m_actions, "print_image" );
+ KStdAction::saveAs( this, SLOT( saveImage() ),
+ m_actions, "save_image_as" );
+
+ KStdAction::close( this, SLOT( close() ),
+ m_actions, "close_image" );
+ // --------
+ new KAction( i18n("More Brightness"), Key_B,
+ this, SLOT( moreBrightness() ),
+ m_actions, "more_brightness" );
+ new KAction( i18n("Less Brightness"), SHIFT + Key_B,
+ this, SLOT( lessBrightness() ),
+ m_actions, "less_brightness" );
+ new KAction( i18n("More Contrast"), Key_C,
+ this, SLOT( moreContrast() ),
+ m_actions, "more_contrast" );
+ new KAction( i18n("Less Contrast"), SHIFT + Key_C,
+ this, SLOT( lessContrast() ),
+ m_actions, "less_contrast" );
+ new KAction( i18n("More Gamma"), Key_G,
+ this, SLOT( moreGamma() ),
+ m_actions, "more_gamma" );
+ new KAction( i18n("Less Gamma"), SHIFT + Key_G,
+ this, SLOT( lessGamma() ),
+ m_actions, "less_gamma" );
+
+ // --------
+ new KAction( i18n("Scroll Up"), Key_Up,
+ this, SLOT( scrollUp() ),
+ m_actions, "scroll_up" );
+ new KAction( i18n("Scroll Down"), Key_Down,
+ this, SLOT( scrollDown() ),
+ m_actions, "scroll_down" );
+ new KAction( i18n("Scroll Left"), Key_Left,
+ this, SLOT( scrollLeft() ),
+ m_actions, "scroll_left" );
+ new KAction( i18n("Scroll Right"), Key_Right,
+ this, SLOT( scrollRight() ),
+ m_actions, "scroll_right" );
+ // --------
+ new KAction( i18n("Pause Slideshow"), Key_P,
+ this, SLOT( pauseSlideShow() ),
+ m_actions, "kuick_slideshow_pause" );
+
+ KAction *fullscreenAction = KStdAction::fullScreen(this, SLOT( toggleFullscreen() ), m_actions, 0 );
+
+ KAction *reloadAction = new KAction( i18n("Reload Image"), KStdAccel::shortcut(KStdAccel::Reload),
+ this, SLOT( reload() ),
+ m_actions, "reload_image" );
+
+ new KAction( i18n("Properties"), ALT + Key_Return,
+ this, SLOT( slotProperties() ),
+ m_actions, "properties" );
+
+ m_actions->readShortcutSettings();
+
+ // Unfortunately there is no KAction::setShortcutDefault() :-/
+ // so add Key_Return as fullscreen shortcut _after_ readShortcutSettings()
+ addAlternativeShortcut(fullscreenAction, Key_Return);
+ addAlternativeShortcut(reloadAction, Key_Enter);
+}
+
+void ImageWindow::addAlternativeShortcut(KAction *action, int key)
+{
+ KShortcut cut( action->shortcut() );
+ if (cut == action->shortcutDefault()) {
+ cut.append(KKey(key));
+ action->setShortcut(cut);
+ }
+}
+
+void ImageWindow::showWindow()
+{
+ if ( myIsFullscreen )
+ showFullScreen();
+ else
+ showNormal();
+}
+
+void ImageWindow::setFullscreen( bool enable )
+{
+ xpos = 0; ypos = 0;
+
+// if ( enable && !myIsFullscreen ) { // set Fullscreen
+// showFullScreen();
+// }
+// else if ( !enable && myIsFullscreen ) { // go into window mode
+// showNormal();
+// }
+
+ myIsFullscreen = enable;
+// centerImage(); // ### really necessary (multihead!)
+}
+
+
+void ImageWindow::updateGeometry( int imWidth, int imHeight )
+{
+// qDebug("::updateGeometry: %i, %i", imWidth, imHeight);
+ // XMoveWindow( x11Display(), win, 0, 0 );
+ XResizeWindow( x11Display(), win, imWidth, imHeight );
+
+ if ( imWidth != width() || imHeight != height() ) {
+ if ( myIsFullscreen ) {
+ centerImage();
+ }
+ else { // window mode
+ // XMoveWindow( x11Display(), win, 0, 0 );
+ resizeOptimal( imWidth, imHeight ); // also centers the image
+ }
+ }
+ else { // image size == widget size
+ xpos = 0; ypos = 0;
+ XMoveWindow( x11Display(), win, 0, 0 );
+ }
+
+ updateCursor();
+
+ QString caption = i18n( "Filename (Imagewidth x Imageheight)",
+ "%3 (%1 x %2)" );
+ caption = caption.arg( m_kuim->originalWidth() ).
+ arg( m_kuim->originalHeight() ).arg( m_kuim->url().prettyURL() );
+ setCaption( kapp->makeStdCaption( caption ) );
+}
+
+
+void ImageWindow::centerImage()
+{
+ int w, h;
+ if ( myIsFullscreen )
+ {
+ QRect desktopRect = KGlobalSettings::desktopGeometry( this );
+ w = desktopRect.width();
+ h = desktopRect.height();
+ }
+ else
+ {
+ w = width();
+ h = height();
+ }
+
+ xpos = w/2 - imageWidth()/2;
+ ypos = h/2 - imageHeight()/2;
+
+ XMoveWindow( x11Display(), win, xpos, ypos );
+
+ // Modified by Evan for his Multi-Head (2 screens)
+ // This should center on the first head
+// if ( myIsFullscreen && m_numHeads > 1 && ((m_numHeads % 2) == 0) )
+// xpos = ((width()/m_numHeads) / 2) - imageWidth()/2;
+// else
+// xpos = width()/2 - imageWidth()/2;
+
+// ypos = height()/2 - imageHeight()/2;
+// XMoveWindow( x11Display(), win, xpos, ypos );
+}
+
+
+void ImageWindow::scrollImage( int x, int y, bool restrict )
+{
+ xpos += x;
+ ypos += y;
+
+ int cwlocal = width();
+ int chlocal = height();
+
+ int iw = imageWidth();
+ int ih = imageHeight();
+
+ if ( myIsFullscreen || width() > desktopWidth() )
+ cwlocal = desktopWidth();
+
+ if ( myIsFullscreen || height() > desktopHeight() )
+ chlocal = desktopHeight();
+
+ if ( restrict ) { // don't allow scrolling in certain cases
+ if ( x != 0 ) { // restrict x-movement
+ if ( iw <= cwlocal )
+ xpos -= x; // restore previous position
+ else if ( (xpos <= 0) && (xpos + iw <= cwlocal) )
+ xpos = cwlocal - iw;
+ else if ( (xpos + iw >= cwlocal) && xpos >= 0 )
+ xpos = 0;
+ }
+
+ if ( y != 0 ) { // restrict y-movement
+ if ( ih <= chlocal )
+ ypos -= y;
+ else if ( (ypos <= 0) && (ypos + ih <= chlocal) )
+ ypos = chlocal - ih;
+ else if ( (ypos + ih >= chlocal) && ypos >= 0 )
+ ypos = 0;
+ }
+ }
+
+ XMoveWindow( x11Display(), win, xpos, ypos );
+ XClearArea( x11Display(), win, xpos, ypos, iw, ih, false );
+ showImage();
+}
+
+
+// image loading performs:
+// ---------------------
+// loadImageInternal();
+// reset image mods
+// load image from disk / get from cache
+// loaded(); // apply modifications, scale
+// render pixmap
+//
+// updateWidget();
+// XUnmapWindow();
+// XSetWindowBackgroundPixmap()
+// resize window to fit image size, center image
+// XClearWindow(); // repaint
+// XMapWindow(), XSync();
+//
+bool ImageWindow::showNextImage( const KURL& url )
+{
+ KuickFile *file = FileCache::self()->getFile( url );
+ switch ( file->waitForDownload( this ) ) {
+ case KuickFile::ERROR:
+ {
+ QString tmp = i18n("Unable to download the image from %1.").arg(url.prettyURL());
+ emit sigImageError( file, tmp );
+ return false;
+ }
+ case KuickFile::CANCELED:
+ return false; // just abort, no error message
+ default:
+ break; // go on...
+ }
+
+ return showNextImage( file );
+}
+
+bool ImageWindow::showNextImage( KuickFile *file )
+{
+ if ( !loadImage( file ) ) {
+ QString tmp = i18n("Unable to load the image %1.\n"
+ "Perhaps the file format is unsupported or "
+ "your Imlib is not installed properly.").arg(file->url().prettyURL());
+ emit sigImageError( file, tmp );
+ return false;
+ }
+
+ else {
+ // updateWidget( true ); // already called from loadImage()
+ if ( !isVisible() )
+ showWindow();
+
+ showImage();
+ return true;
+ }
+}
+
+void ImageWindow::reload()
+{
+ showNextImage( currentFile() );
+}
+
+void ImageWindow::pauseSlideShow()
+{
+ emit pauseSlideShowSignal();
+}
+
+void ImageWindow::addBrightness( int factor )
+{
+ if ( factor == 0 )
+ return;
+
+ int oldValue = mod.brightness - ImlibOffset;
+ setBrightness( oldValue + (idata->brightnessFactor * (int) factor) );
+}
+
+void ImageWindow::addContrast( int factor )
+{
+ if ( factor == 0 )
+ return;
+
+ int oldValue = mod.contrast - ImlibOffset;
+ setContrast( oldValue + (idata->contrastFactor * (int) factor) );
+}
+
+void ImageWindow::addGamma( int factor )
+{
+ if ( factor == 0 )
+ return;
+
+ int oldValue = mod.gamma - ImlibOffset;
+ setGamma( oldValue + (idata->gammaFactor * (int) factor) );
+}
+
+
+////////////
+////
+// slots for keyboard/popupmenu actions
+
+
+void ImageWindow::scrollUp()
+{
+ scrollImage( 0, 20 * kdata->scrollSteps );
+}
+
+void ImageWindow::scrollDown()
+{
+ scrollImage( 0, - 20 * kdata->scrollSteps );
+}
+
+void ImageWindow::scrollLeft()
+{
+ scrollImage( 20 * kdata->scrollSteps, 0 );
+}
+
+void ImageWindow::scrollRight()
+{
+ scrollImage( - 20 * kdata->scrollSteps, 0 );
+}
+
+///
+
+void ImageWindow::zoomIn()
+{
+ zoomImage( kdata->zoomSteps );
+}
+
+void ImageWindow::zoomOut()
+{
+ Q_ASSERT( kdata->zoomSteps != 0 );
+ zoomImage( 1.0 / kdata->zoomSteps );
+}
+
+///
+
+void ImageWindow::moreBrightness()
+{
+ addBrightness( kdata->brightnessSteps );
+}
+
+void ImageWindow::moreContrast()
+{
+ addContrast( kdata->contrastSteps );
+}
+
+void ImageWindow::moreGamma()
+{
+ addGamma( kdata->gammaSteps );
+}
+
+
+void ImageWindow::lessBrightness()
+{
+ addBrightness( - kdata->brightnessSteps );
+}
+
+void ImageWindow::lessContrast()
+{
+ addContrast( - kdata->contrastSteps );
+}
+
+void ImageWindow::lessGamma()
+{
+ addGamma( - kdata->gammaSteps );
+}
+
+void ImageWindow::imageDelete()
+{
+ emit deleteImage(this);
+}
+
+void ImageWindow::imageTrash()
+{
+ emit trashImage(this);
+}
+
+///
+
+
+
+
+/////////////
+////
+// event handlers
+
+void ImageWindow::wheelEvent( QWheelEvent *e )
+{
+ e->accept();
+ static const int WHEEL_DELTA = 120;
+ int delta = e->delta();
+
+ if ( delta == 0 )
+ return;
+
+ int steps = delta / WHEEL_DELTA;
+ emit requestImage( this, -steps );
+}
+
+void ImageWindow::keyPressEvent( QKeyEvent *e )
+{
+ uint key = e->key();
+
+ if ( key == Key_Shift )
+ updateCursor( ZoomCursor );
+
+ if ( key == Key_Escape || KStdAccel::close().contains( KKey( e ) ) )
+ close( true );
+ else if ( KStdAccel::save().contains( KKey( e ) ) )
+ saveImage();
+
+ else {
+ e->ignore();
+ return;
+ }
+
+ e->accept();
+}
+
+void ImageWindow::keyReleaseEvent( QKeyEvent *e )
+{
+ if ( e->state() & ShiftButton ) { // Shift-key released
+ updateCursor();
+ if ( transWidget ) {
+ delete transWidget;
+ transWidget = 0L;
+ }
+ }
+
+ e->accept();
+}
+
+void ImageWindow::mousePressEvent( QMouseEvent *e )
+{
+ xmove = e->x(); // for moving the image with the mouse
+ ymove = e->y();
+
+ xzoom = xmove; // for zooming with the mouse
+ yzoom = ymove;
+
+ xposPress = xmove;
+ yposPress = ymove;
+
+ if ( e->button() == LeftButton ) {
+ if ( e->state() & ShiftButton )
+ updateCursor( ZoomCursor );
+ else
+ updateCursor( MoveCursor );
+ }
+
+ ImlibWidget::mousePressEvent( e );
+}
+
+void ImageWindow::contextMenuEvent( QContextMenuEvent *e )
+{
+ e->accept();
+
+ if ( !viewerMenu )
+ setPopupMenu();
+
+ viewerMenu->popup( e->globalPos() );
+}
+
+void ImageWindow::updateCursor( KuickCursor cursor )
+{
+ switch ( cursor )
+ {
+ case ZoomCursor:
+ setCursor( arrowCursor ); // need a magnify-cursor
+ break;
+ case MoveCursor:
+ setCursor( *s_handCursor );
+ break;
+ case DefaultCursor:
+ default:
+ if ( isCursorHidden() )
+ return;
+
+ if ( imageWidth() > width() || imageHeight() > height() )
+ setCursor( *s_handCursor );
+ else
+ setCursor( arrowCursor );
+ break;
+ }
+}
+
+void ImageWindow::mouseMoveEvent( QMouseEvent *e )
+{
+ if ( !(e->state() & LeftButton) ) { // only handle LeftButton actions
+ return;
+ }
+
+ if ( e->state() & ShiftButton ) {
+
+ if ( !transWidget ) {
+ transWidget = new QWidget( this );
+ transWidget->setGeometry( 0, 0, width(), height() );
+ transWidget->setBackgroundMode( NoBackground );
+ }
+
+ transWidget->hide();
+ QPainter p( transWidget );
+ // really required?
+ p.eraseRect( transWidget->rect() );
+ transWidget->show();
+ qApp->processOneEvent();
+
+ int width = e->x() - xposPress;
+ int height = e->y() - yposPress;
+
+ if ( width < 0 ) {
+ width = abs( width );
+ xzoom = e->x();
+ }
+
+ if ( height < 0 ) {
+ height = abs( height );
+ yzoom = e->y();
+ }
+
+ QPen pen( Qt::white, 1, DashLine );
+ p.setPen( pen ); // for drawing white dashed line
+ p.drawRect( xzoom, yzoom, width, height );
+ p.setPen( DotLine ); // defaults to black dotted line pen
+ p.drawRect( xzoom, yzoom, width, height );
+ p.flush();
+ }
+
+ else { // move the image
+ // scrolling with mouse
+ uint xtmp = e->x();
+ uint ytmp = e->y();
+ scrollImage( xtmp - xmove, ytmp - ymove );
+ xmove = xtmp;
+ ymove = ytmp;
+ }
+}
+
+void ImageWindow::mouseReleaseEvent( QMouseEvent *e )
+{
+ updateCursor();
+
+ if ( transWidget ) {
+ // destroy the transparent widget, used for showing the rectangle (zoom)
+ delete transWidget;
+ transWidget = 0L;
+ }
+
+ // only proceed if shift-Key is still pressed
+ if ( !(e->button() == LeftButton && e->state() & ShiftButton) )
+ return;
+
+ int neww, newh, topX, topY, botX, botY;
+ float factor, factorx, factory;
+
+ // zoom into the selected area
+ uint x = e->x();
+ uint y = e->y();
+
+ if ( xposPress == x || yposPress == y )
+ return;
+
+ if ( xposPress > x ) {
+ topX = x;
+ botX = xposPress;
+ }
+ else {
+ topX = xposPress;
+ botX = x;
+ }
+
+ if ( yposPress > y ) {
+ topY = y;
+ botY = yposPress;
+ }
+ else {
+ topY = yposPress;
+ botY = y;
+ }
+
+ neww = botX - topX;
+ newh = botY - topY;
+
+ factorx = ((float) width() / (float) neww);
+ factory = ((float) height() / (float) newh);
+
+ if ( factorx < factory ) // use the smaller factor
+ factor = factorx;
+ else factor = factory;
+
+ uint w = 0; // shut up compiler!
+ uint h = 0;
+ w = (uint) ( factor * (float) imageWidth() );
+ h = (uint) ( factor * (float) imageHeight() );
+
+ if ( !canZoomTo( w, h ) )
+ return;
+
+ int xtmp = - (int) (factor * abs(xpos - topX) );
+ int ytmp = - (int) (factor * abs(ypos - topY) );
+
+ // if image has different ratio (width()/height()), center it
+ int xcenter = (width() - (int) (neww * factor)) / 2;
+ int ycenter = (height() - (int) (newh * factor)) / 2;
+
+ xtmp += xcenter;
+ ytmp += ycenter;
+
+ m_kuim->resize( w, h, idata->smoothScale ? KuickImage::SMOOTH : KuickImage::FAST );
+ XResizeWindow( x11Display(), win, w, h );
+ updateWidget( false );
+
+ xpos = xtmp; ypos = ytmp;
+
+ XMoveWindow( x11Display(), win, xpos, ypos );
+ scrollImage( 1, 1, true ); // unrestricted scrolling
+}
+
+
+void ImageWindow::focusInEvent( QFocusEvent *ev )
+{
+ ImlibWidget::focusInEvent( ev );
+ emit sigFocusWindow( this );
+}
+
+
+void ImageWindow::resizeEvent( QResizeEvent *e )
+{
+ ImlibWidget::resizeEvent( e );
+
+ centerImage();
+ updateCursor();
+}
+
+
+void ImageWindow::dragEnterEvent( QDragEnterEvent *e )
+{
+ // if ( e->provides( "image/*" ) ) // can't do this right now with Imlib
+ if ( e->provides( "text/uri-list" ) )
+ e->accept();
+ else
+ e->ignore();
+}
+
+
+void ImageWindow::dropEvent( QDropEvent *e )
+{
+ // FIXME - only preliminary drop-support for now
+ KURL::List list;
+ if ( KURLDrag::decode( e, list ) && !list.isEmpty()) {
+ QString tmpFile;
+ const KURL &url = list.first();
+ if (KIO::NetAccess::download( url, tmpFile, this ) )
+ {
+ loadImage( tmpFile );
+ KIO::NetAccess::removeTempFile( tmpFile );
+ }
+ updateWidget();
+ e->accept();
+ }
+ else
+ e->ignore();
+}
+
+
+////////////////////
+/////////
+// misc stuff
+
+void ImageWindow::setPopupMenu()
+{
+ viewerMenu = new QPopupMenu( this );
+
+ m_actions->action("next_image")->plug( viewerMenu );
+ m_actions->action("previous_image")->plug( viewerMenu );
+ viewerMenu->insertSeparator();
+
+ brightnessMenu = new QPopupMenu( viewerMenu );
+ m_actions->action("more_brightness")->plug(brightnessMenu);
+ m_actions->action("less_brightness")->plug(brightnessMenu);
+
+ contrastMenu = new QPopupMenu( viewerMenu );
+ m_actions->action("more_contrast")->plug(contrastMenu);
+ m_actions->action("less_contrast")->plug(contrastMenu);
+
+ gammaMenu = new QPopupMenu( viewerMenu );
+ m_actions->action("more_gamma")->plug(gammaMenu);
+ m_actions->action("less_gamma")->plug(gammaMenu);
+
+ m_actions->action("zoom_in")->plug( viewerMenu );
+ m_actions->action("zoom_out")->plug( viewerMenu );
+ m_actions->action("original_size")->plug( viewerMenu );
+ m_actions->action("maximize")->plug( viewerMenu );
+
+ viewerMenu->insertSeparator();
+ m_actions->action("rotate90")->plug( viewerMenu );
+ m_actions->action("rotate180")->plug( viewerMenu );
+ m_actions->action("rotate270")->plug( viewerMenu );
+
+ viewerMenu->insertSeparator();
+ m_actions->action("flip_vertically")->plug( viewerMenu );
+ m_actions->action("flip_horicontally")->plug( viewerMenu );
+ viewerMenu->insertSeparator();
+ viewerMenu->insertItem( i18n("Brightness"), brightnessMenu );
+ viewerMenu->insertItem( i18n("Contrast"), contrastMenu );
+ viewerMenu->insertItem( i18n("Gamma"), gammaMenu );
+ viewerMenu->insertSeparator();
+
+ m_actions->action("delete_image")->plug( viewerMenu );
+ m_actions->action("print_image")->plug( viewerMenu );
+ m_actions->action("save_image_as")->plug( viewerMenu );
+ m_actions->action("properties")->plug( viewerMenu );
+
+ viewerMenu->insertSeparator();
+ m_actions->action("close_image")->plug( viewerMenu );
+}
+
+void ImageWindow::printImage()
+{
+ if ( !m_kuim )
+ return;
+
+ if ( !Printing::printImage( *this, this ) )
+ {
+ KMessageBox::sorry( this, i18n("Unable to print the image."),
+ i18n("Printing Failed") );
+ }
+}
+
+void ImageWindow::saveImage()
+{
+ if ( !m_kuim )
+ return;
+
+ KuickData tmp;
+ QCheckBox *keepSize = new QCheckBox( i18n("Keep original image size"), 0L);
+ keepSize->setChecked( true );
+ KFileDialog dlg( m_saveDirectory, tmp.fileFilter, this, "filedialog", true
+#if KDE_VERSION >= 310
+ ,keepSize
+#endif
+ );
+
+ QString selection = m_saveDirectory.isEmpty() ?
+ m_kuim->url().url() :
+ m_kuim->url().fileName();
+ dlg.setOperationMode( KFileDialog::Saving );
+ dlg.setMode( KFile::File );
+ dlg.setSelection( selection );
+ dlg.setCaption( i18n("Save As") );
+ if ( dlg.exec() == QDialog::Accepted )
+ {
+ KURL url = dlg.selectedURL();
+ if ( url.isValid() )
+ {
+ if ( !saveImage( url, keepSize->isChecked() ) )
+ {
+ QString tmp = i18n("Couldn't save the file.\n"
+ "Perhaps the disk is full, or you don't "
+ "have write permission to the file.");
+ KMessageBox::sorry( this, tmp, i18n("File Saving Failed"));
+ }
+ else
+ {
+ if ( url.equals( m_kuim->url() )) {
+ Imlib_apply_modifiers_to_rgb( id, m_kuim->imlibImage() );
+ }
+ }
+ }
+ }
+
+ QString lastDir = dlg.baseURL().path(+1);
+ if ( lastDir != m_saveDirectory )
+ m_saveDirectory = lastDir;
+
+#if KDE_VERSION < 310
+ delete keepSize;
+#endif
+}
+
+bool ImageWindow::saveImage( const KURL& dest, bool keepOriginalSize )
+{
+ int w = keepOriginalSize ? m_kuim->originalWidth() : m_kuim->width();
+ int h = keepOriginalSize ? m_kuim->originalHeight() : m_kuim->height();
+ if ( m_kuim->absRotation() == ROT_90 || m_kuim->absRotation() == ROT_270 )
+ qSwap( w, h );
+
+ ImlibImage *saveIm = Imlib_clone_scaled_image( id, m_kuim->imlibImage(),
+ w, h );
+ bool success = false;
+
+ QString saveFile;
+ if ( dest.isLocalFile() )
+ saveFile = dest.path();
+ else
+ {
+ QString extension = QFileInfo( dest.fileName() ).extension();
+ if ( !extension.isEmpty() )
+ extension.prepend( '.' );
+
+ KTempFile tmpFile( QString::null, extension );
+ if ( tmpFile.status() != 0 )
+ return false;
+ tmpFile.close();
+ if ( tmpFile.status() != 0 )
+ return false;
+ saveFile = tmpFile.name();
+ }
+
+ if ( saveIm )
+ {
+ Imlib_apply_modifiers_to_rgb( id, saveIm );
+ success = Imlib_save_image( id, saveIm,
+ QFile::encodeName( saveFile ).data(),
+ NULL );
+ if ( success && !dest.isLocalFile() )
+ {
+ if ( isFullscreen() )
+ toggleFullscreen(); // otherwise upload window would block us invisibly
+ success = KIO::NetAccess::upload( saveFile, dest, const_cast<ImageWindow*>( this ) );
+ }
+
+ Imlib_kill_image( id, saveIm );
+ }
+
+ return success;
+}
+
+void ImageWindow::toggleFullscreen()
+{
+ setFullscreen( !myIsFullscreen );
+ showWindow();
+}
+
+void ImageWindow::loaded( KuickImage *kuim )
+{
+ if ( !kdata->isModsEnabled ) {
+ // ### BUG: should be "restorePreviousSize"
+ kuim->restoreOriginalSize();
+ }
+ else
+ {
+ autoRotate( kuim );
+ autoScale( kuim );
+ }
+}
+
+// upscale/downscale depending on configuration
+void ImageWindow::autoScale( KuickImage *kuim )
+{
+ int newW = kuim->originalWidth();
+ int newH = kuim->originalHeight();
+
+ QSize s = maxImageSize();
+ int mw = s.width();
+ int mh = s.height();
+
+ if ( kuim->absRotation() == ROT_90 || kuim->absRotation() == ROT_270 )
+ qSwap( newW, newH );
+
+ bool doIt = false;
+
+ if ( kdata->upScale )
+ {
+ if ( (newW < mw) && (newH < mh) )
+ {
+ doIt = true;
+
+ float ratio1, ratio2;
+ int maxUpScale = kdata->maxUpScale;
+
+ ratio1 = (float) mw / (float) newW;
+ ratio2 = (float) mh / (float) newH;
+ ratio1 = (ratio1 < ratio2) ? ratio1 : ratio2;
+ if ( maxUpScale > 0 )
+ ratio1 = (ratio1 < maxUpScale) ? ratio1 : maxUpScale;
+ newH = (int) ((float) newH * ratio1);
+ newW = (int) ((float) newW * ratio1);
+ }
+ }
+
+ if ( kdata->downScale )
+ {
+ // eventually set width and height to the best/max possible screen size
+ if ( (newW > mw) || (newH > mh) )
+ {
+ doIt = true;
+
+ if ( newW > mw )
+ {
+ float ratio = (float) newW / (float) newH;
+ newW = mw;
+ newH = (int) ((float) newW / ratio);
+ }
+
+ // the previously calculated "h" might be larger than screen
+ if ( newH > mh ) {
+ float ratio = (float) newW / (float) newH;
+ newH = mh;
+ newW = (int) ((float) newH * ratio);
+ }
+ }
+ }
+
+ if ( doIt )
+ kuim->resize( newW, newH, idata->smoothScale ? KuickImage::SMOOTH : KuickImage::FAST );
+}
+
+// only called when kdata->isModsEnabled is true
+bool ImageWindow::autoRotate( KuickImage *kuim )
+{
+ if ( kdata->autoRotation && ImlibWidget::autoRotate( kuim ) )
+ return true;
+
+ else // rotation by metadata not available or not configured
+ {
+ // only apply default mods to newly loaded images
+
+ // ### actually we should have a dirty flag ("neverManuallyFlipped")
+ if ( kuim->flipMode() == FlipNone )
+ {
+ int flipMode = 0;
+ if ( kdata->flipVertically )
+ flipMode |= FlipVertical;
+ if ( kdata->flipHorizontally )
+ flipMode |= FlipHorizontal;
+
+ kuim->flipAbs( flipMode );
+ }
+
+ if ( kuim->absRotation() == ROT_0 )
+ kuim->rotateAbs( kdata->rotation );
+ }
+
+ return true;
+}
+
+int ImageWindow::desktopWidth( bool totalScreen ) const
+{
+ if ( myIsFullscreen || totalScreen )
+ {
+ return KGlobalSettings::desktopGeometry(topLevelWidget()).width();
+ } else
+ return Kuick::workArea().width();
+}
+
+
+int ImageWindow::desktopHeight( bool totalScreen ) const
+{
+ if ( myIsFullscreen || totalScreen ) {
+ return KGlobalSettings::desktopGeometry(topLevelWidget()).height();
+ } else {
+ return Kuick::workArea().height();
+ }
+}
+
+QSize ImageWindow::maxImageSize() const
+{
+ if ( myIsFullscreen ) {
+ return KGlobalSettings::desktopGeometry(topLevelWidget()).size();
+ }
+ else {
+ return Kuick::workArea().size() - Kuick::frameSize( winId() );
+ }
+}
+
+void ImageWindow::resizeOptimal( int w, int h )
+{
+ QSize s = maxImageSize();
+ int mw = s.width();
+ int mh = s.height();
+ int neww = (w >= mw) ? mw : w;
+ int newh = (h >= mh) ? mh : h;
+
+ if ( neww == width() && newh == height() )
+ centerImage();
+ else
+ resize( neww, newh ); // also centers the image
+}
+
+void ImageWindow::maximize()
+{
+ if ( !m_kuim )
+ return;
+
+ bool oldUpscale = kdata->upScale;
+ bool oldDownscale = kdata->downScale;
+
+ kdata->upScale = true;
+ kdata->downScale = true;
+
+ autoScale( m_kuim );
+ updateWidget( true );
+
+ if ( !myIsFullscreen )
+ resizeOptimal( imageWidth(), imageHeight() );
+
+ kdata->upScale = oldUpscale;
+ kdata->downScale = oldDownscale;
+}
+
+bool ImageWindow::canZoomTo( int newWidth, int newHeight )
+{
+ if ( !ImlibWidget::canZoomTo( newWidth, newHeight ) )
+ return false;
+
+ QSize desktopSize = KGlobalSettings::desktopGeometry(topLevelWidget()).size();
+
+ int desktopArea = desktopSize.width() * desktopSize.height();
+ int imageArea = newWidth * newHeight;
+
+ if ( imageArea > desktopArea * kdata->maxZoomFactor )
+ {
+ return KMessageBox::warningContinueCancel(
+ this,
+ i18n("You are about to view a very large image (%1 x %2 pixels), which can be very resource-consuming and even make your computer hang.\nDo you want to continue?")
+ .arg( newWidth ).arg( newHeight ),
+ QString::null,
+ KStdGuiItem::cont(),
+ "ImageWindow_confirm_very_large_window"
+ ) == KMessageBox::Continue;
+ }
+
+ return true;
+}
+
+void ImageWindow::rotated( KuickImage *kuim, int rotation )
+{
+ if ( !m_kuim )
+ return;
+
+ ImlibWidget::rotated( kuim, rotation );
+
+ if ( rotation == ROT_90 || rotation == ROT_270 )
+ autoScale( kuim ); // ### BUG: only autoScale when configured!
+}
+
+void ImageWindow::slotProperties()
+{
+ (void) new KPropertiesDialog( currentFile()->url(), this, "props dialog", true );
+}
+
+void ImageWindow::setBusyCursor()
+{
+ // avoid busy cursor in fullscreen mode
+ if ( !isFullscreen() )
+ ImlibWidget::setBusyCursor();
+}
+
+void ImageWindow::restoreCursor()
+{
+ // avoid busy cursor in fullscreen mode
+ if ( !isFullscreen() )
+ ImlibWidget::restoreCursor();
+}
+
+bool ImageWindow::isCursorHidden() const
+{
+ return cursor().shape() == Qt::BlankCursor;
+}
+
+#include "imagewindow.moc"
diff --git a/kuickshow/src/imagewindow.h b/kuickshow/src/imagewindow.h
new file mode 100644
index 00000000..4a823a0a
--- /dev/null
+++ b/kuickshow/src/imagewindow.h
@@ -0,0 +1,176 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998-2003 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef IMAGEWINDOW_H
+#define IMAGEWINDOW_H
+
+#include <qevent.h>
+
+#include <kaction.h>
+#include <kurl.h>
+
+#include "imlibwidget.h"
+
+class QCursor;
+class QPopupMenu;
+class QRect;
+class QString;
+class QTimer;
+class QWidget;
+
+class KuickFile;
+
+class ImageWindow : public ImlibWidget
+{
+ Q_OBJECT
+
+public:
+ ImageWindow( ImData *_idata, ImlibData *id, QWidget *parent=0,
+ const char *name=0 );
+ ImageWindow( ImData *_idata=0, QWidget *parent=0, const char *name=0 );
+
+ bool showNextImage( KuickFile * file );
+ bool showNextImage( const KURL& url );
+ void scrollImage( int, int, bool restrict=true );
+ void setFullscreen( bool );
+ bool isFullscreen() const { return myIsFullscreen; }
+
+ void addBrightness( int );
+ void addContrast( int );
+ void addGamma( int );
+
+ void updateActions();
+
+ KActionCollection * actionCollection() const { return m_actions; }
+
+ /**
+ * Resizes image to @p w, @p h, but takes into account the workarea, so
+ * it won't ever get a bigger size than the workarea.
+ */
+ void resizeOptimal( int w, int h );
+ void autoScale( KuickImage *kuim );
+ virtual bool autoRotate( KuickImage *kuim );
+
+ bool saveImage( const KURL& dest, bool keepOriginalSize );
+
+public slots:
+ void zoomIn();
+ void zoomOut();
+ void moreBrightness();
+ void lessBrightness();
+ void moreContrast();
+ void lessContrast();
+ void moreGamma();
+ void lessGamma();
+ void scrollUp();
+ void scrollDown();
+ void scrollLeft();
+ void scrollRight();
+ void printImage();
+ void toggleFullscreen();
+ void maximize();
+ void imageDelete();
+ void imageTrash();
+
+signals:
+ void sigFocusWindow( ImageWindow * );
+ // go advance images back/forth
+ void requestImage( ImageWindow *, int advance );
+ void deleteImage(ImageWindow *viewer);
+ void trashImage(ImageWindow *viewer);
+
+protected:
+ ~ImageWindow(); // deletes itself, just call close( true );
+
+ void init();
+ void centerImage();
+ void addAlternativeShortcut( KAction *action, int key );
+ virtual void updateGeometry( int imWidth, int imHeight );
+ virtual void loaded( KuickImage * );
+ virtual bool canZoomTo( int newWidth, int newHeight );
+ virtual void rotated( KuickImage *kuim, int rotation );
+
+ virtual void wheelEvent( QWheelEvent * );
+ virtual void keyPressEvent( QKeyEvent * );
+ virtual void keyReleaseEvent( QKeyEvent * );
+ virtual void mousePressEvent( QMouseEvent * );
+ virtual void mouseReleaseEvent( QMouseEvent * );
+ virtual void mouseMoveEvent( QMouseEvent * );
+ virtual void focusInEvent( QFocusEvent * );
+ virtual void resizeEvent( QResizeEvent * );
+ virtual void dragEnterEvent( QDragEnterEvent * );
+ virtual void dropEvent( QDropEvent * );
+ virtual void contextMenuEvent( QContextMenuEvent * );
+
+ void showWindow();
+ enum KuickCursor { DefaultCursor = 0, ZoomCursor, MoveCursor };
+ void updateCursor( KuickCursor cursor = DefaultCursor );
+
+ // popupmenu entries
+ uint itemViewerZoomMax, itemViewerZoomOrig, itemViewerZoomIn;
+ uint itemViewerZoomOut, itemViewerFlipH, itemViewerProps;
+ uint itemRotate90, itemRotate180, itemRotate270;
+ uint itemViewerFlipV, itemViewerPrint;
+ uint itemViewerSave, itemViewerClose;
+ uint itemBrightnessPlus, itemBrightnessMinus;
+ uint itemContrastPlus, itemContrastMinus;
+ uint itemGammaPlus, itemGammaMinus;
+
+
+ uint xmove, ymove; // used for scrolling the image with the mouse
+ int xpos, ypos; // top left corner of the image
+ int xzoom, yzoom; // used for zooming the image with the mouse
+ uint xposPress, yposPress;
+
+
+ QPopupMenu *viewerMenu, *gammaMenu, *brightnessMenu, *contrastMenu;
+ QWidget *transWidget;
+
+
+protected slots:
+ void saveImage();
+ void slotRequestNext() { emit requestImage( this, +1 ); }
+ void slotRequestPrevious() { emit requestImage( this, -1 ); }
+ void reload();
+ void slotProperties();
+ void pauseSlideShow();
+ virtual void setBusyCursor();
+ virtual void restoreCursor();
+
+signals:
+ void pauseSlideShowSignal();
+
+private:
+ int desktopWidth( bool totalScreen = false ) const;
+ int desktopHeight( bool totalScreen = false ) const;
+ QSize maxImageSize() const;
+ void setupActions();
+ void setPopupMenu();
+ bool isCursorHidden() const;
+
+ bool myIsFullscreen;
+ int m_numHeads;
+ QString m_saveDirectory;
+
+ KActionCollection *m_actions;
+
+ static QCursor * s_handCursor;
+};
+
+
+#endif // IMAGEWINDOW_H
diff --git a/kuickshow/src/imdata.cpp b/kuickshow/src/imdata.cpp
new file mode 100644
index 00000000..a2e89283
--- /dev/null
+++ b/kuickshow/src/imdata.cpp
@@ -0,0 +1,92 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998-2001 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <stdlib.h>
+
+#include <kconfig.h>
+
+#include "imdata.h"
+
+
+ImData::ImData()
+{
+ ownPalette = true;
+ fastRemap = true;
+ fastRender = true;
+ dither16bit = false;
+ dither8bit = true;
+ smoothScale = false;
+ maxCache = 10240;
+
+ gamma = 0;
+ brightness = 0;
+ contrast = 0;
+
+ gammaFactor = 10;
+ brightnessFactor = 10;
+ contrastFactor = 10;
+}
+
+
+void ImData::load( KConfig *kc )
+{
+ ImData def;
+
+ kc->setGroup( "ImlibConfiguration" );
+
+ ownPalette = kc->readBoolEntry( "UseOwnPalette", def.ownPalette );
+ fastRemap = kc->readBoolEntry( "FastRemapping", def.fastRemap );
+ fastRender = kc->readBoolEntry( "FastRendering", def.fastRender );
+ dither16bit = kc->readBoolEntry( "Dither16Bit", def.dither16bit );
+ dither8bit = kc->readBoolEntry( "Dither8Bit", def.dither8bit );
+ smoothScale = kc->readBoolEntry( "SmoothScaling", def.smoothScale );
+
+ maxCache = kc->readNumEntry( "MaxCacheSize", 10240 );
+
+ gamma = kc->readNumEntry( "GammaDefault", 0 );
+ brightness = kc->readNumEntry( "BrightnessDefault", 0 );
+ contrast = kc->readNumEntry( "ContrastDefault", 0 );
+
+ gammaFactor = abs( kc->readNumEntry( "GammaFactor", 10 ) );
+ brightnessFactor = abs( kc->readNumEntry( "BrightnessFactor", 10 ) );
+ contrastFactor = abs( kc->readNumEntry( "ContrastFactor", 10 ) );
+}
+
+
+void ImData::save( KConfig *kc )
+{
+ kc->setGroup( "ImlibConfiguration" );
+
+ kc->writeEntry( "UseOwnPalette", ownPalette );
+ kc->writeEntry( "FastRemapping", fastRemap );
+ kc->writeEntry( "FastRendering", fastRender );
+ kc->writeEntry( "Dither16Bit", dither16bit );
+ kc->writeEntry( "Dither8Bit", dither8bit );
+ kc->writeEntry( "MaxCacheSize", maxCache );
+ kc->writeEntry( "SmoothScaling", smoothScale );
+
+ kc->writeEntry( "GammaDefault", gamma );
+ kc->writeEntry( "BrightnessDefault", brightness );
+ kc->writeEntry( "ContrastDefault", contrast );
+
+ kc->writeEntry( "GammaFactor", gammaFactor );
+ kc->writeEntry( "BrightnessFactor", brightnessFactor );
+ kc->writeEntry( "ContrastFactor", contrastFactor );
+
+ kc->sync();
+}
diff --git a/kuickshow/src/imdata.h b/kuickshow/src/imdata.h
new file mode 100644
index 00000000..c6dc6a5c
--- /dev/null
+++ b/kuickshow/src/imdata.h
@@ -0,0 +1,57 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998,1999,2000,2001 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef IMBLIBCONFIG_H
+#define IMBLIBCONFIG_H
+
+class KConfig;
+class ImData
+{
+public:
+ ImData();
+ ~ImData() {};
+
+ void load( KConfig *kc );
+ void save( KConfig *kc );
+
+ // new stuff..........
+
+ int gamma;
+ int brightness;
+ int contrast;
+
+ // -----------------------
+
+ bool ownPalette :1;
+ bool fastRemap :1;
+ bool fastRender :1;
+ bool dither16bit :1;
+ bool dither8bit :1;
+ bool smoothScale :1;
+
+
+ uint gammaFactor;
+ uint brightnessFactor;
+ uint contrastFactor;
+
+ uint maxCache;
+
+};
+
+
+#endif
diff --git a/kuickshow/src/imlibwidget.cpp b/kuickshow/src/imlibwidget.cpp
new file mode 100644
index 00000000..5b5cb84b
--- /dev/null
+++ b/kuickshow/src/imlibwidget.cpp
@@ -0,0 +1,715 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998-2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kuickdata.h"
+
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include <qcolor.h>
+#include <qfile.h>
+#include <qglobal.h>
+#include <qimage.h>
+#include <qobject.h>
+#include <qpalette.h>
+
+#include <kcursor.h>
+#include <kdebug.h>
+#include <kfilemetainfo.h>
+#include <kimageio.h>
+
+#include "filecache.h"
+#include "kuickfile.h"
+#include "kuickimage.h"
+#include "imlibwidget.h"
+
+const int ImlibWidget::ImlibOffset = 256;
+
+ImlibWidget::ImlibWidget( ImData *_idata, QWidget *parent, const char *name ) :
+ QWidget( parent, name, WDestructiveClose )
+{
+ idata = _idata;
+ deleteImData = false;
+ deleteImlibData = true;
+
+ if ( !idata ) { // if no imlib configuration was given, create one ourself
+ idata = new ImData;
+ deleteImData = true;
+ }
+
+ ImlibInitParams par;
+
+ // PARAMS_PALETTEOVERRIDE taken out because of segfault in imlib :o(
+ par.flags = ( PARAMS_REMAP | PARAMS_VISUALID |
+ PARAMS_FASTRENDER | PARAMS_HIQUALITY | PARAMS_DITHER |
+ PARAMS_IMAGECACHESIZE | PARAMS_PIXMAPCACHESIZE );
+
+ Visual* defaultvis = DefaultVisual(x11Display(), x11Screen());
+
+ par.paletteoverride = idata->ownPalette ? 1 : 0;
+ par.remap = idata->fastRemap ? 1 : 0;
+ par.fastrender = idata->fastRender ? 1 : 0;
+ par.hiquality = idata->dither16bit ? 1 : 0;
+ par.dither = idata->dither8bit ? 1 : 0;
+ par.visualid = defaultvis->visualid;
+ uint maxcache = idata->maxCache;
+
+ // 0 == no cache
+ par.imagecachesize = maxcache * 1024;
+ par.pixmapcachesize = maxcache * 1024;
+
+ id = Imlib_init_with_params( x11Display(), &par );
+
+ init();
+}
+
+
+ImlibWidget::ImlibWidget( ImData *_idata, ImlibData *_id, QWidget *parent,
+ const char *name )
+ : QWidget( parent, name, WDestructiveClose )
+{
+ id = _id;
+ idata = _idata;
+ deleteImData = false;
+ deleteImlibData = false;
+
+ if ( !idata ) {
+ idata = new ImData;
+ deleteImData = true;
+ }
+
+ init();
+}
+
+
+void ImlibWidget::init()
+{
+ int w = 1; // > 0 for XCreateWindow
+ int h = 1;
+ myBackgroundColor = Qt::black;
+ m_kuim = 0L;
+ m_kuickFile = 0L;
+
+ if ( !id )
+ qFatal("ImlibWidget: Imlib not initialized, aborting.");
+
+ setAutoRender( true );
+
+ setPalette( QPalette( myBackgroundColor ));
+ setBackgroundMode( PaletteBackground );
+
+ imageCache = new ImageCache( id, 4 ); // cache 4 images (FIXME?)
+ connect( imageCache, SIGNAL( sigBusy() ), SLOT( setBusyCursor() ));
+ connect( imageCache, SIGNAL( sigIdle() ), SLOT( restoreCursor() ));
+
+ win = XCreateSimpleWindow(x11Display(), winId(), 0,0,w,h,0,0,0);
+}
+
+ImlibWidget::~ImlibWidget()
+{
+ delete imageCache;
+ if ( deleteImlibData && id ) free ( id );
+ if ( win ) XDestroyWindow( x11Display(), win );
+ if ( deleteImData ) delete idata;
+}
+
+KURL ImlibWidget::url() const
+{
+ if ( m_kuickFile )
+ return m_kuickFile->url();
+
+ return KURL();
+}
+
+KuickFile * ImlibWidget::currentFile() const
+{
+ return m_kuickFile;
+}
+
+// tries to load "file" and returns the according KuickImage *
+// or 0L if unsuccessful
+// Note that the given file MUST already be downloaded prior to calling this function
+KuickImage * ImlibWidget::loadImageInternal( KuickFile * file )
+{
+ assert( file->isAvailable() );
+
+ // apply default image modifications
+ mod.brightness = idata->brightness + ImlibOffset;
+ mod.contrast = idata->contrast + ImlibOffset;
+ mod.gamma = idata->gamma + ImlibOffset;
+
+ KuickImage *kuim = imageCache->getKuimage( file, mod );
+ if ( !kuim ) {// couldn't load file, maybe corrupt or wrong format
+ kdWarning() << "ImlibWidget: can't load image " << file->url().prettyURL() << endl;
+ return 0L;
+ }
+
+ loaded( kuim ); // maybe upscale/downscale/rotate in subclasses
+
+ return kuim;
+}
+
+// overridden in subclass
+void ImlibWidget::loaded( KuickImage * )
+{
+}
+
+bool ImlibWidget::loadImage( const KURL& url )
+{
+ return loadImage( FileCache::self()->getFile( url ));
+}
+
+bool ImlibWidget::loadImage( KuickFile * file )
+{
+ if ( file->waitForDownload( this ) != KuickFile::OK)
+ return false;
+
+ KuickImage *kuim = loadImageInternal( file );
+ // FIXME - check everywhere if we have a kuim or not!
+
+ if ( kuim ) {
+ m_kuim = kuim;
+ autoUpdate( true ); // -> updateWidget() -> updateGeometry()
+ m_kuickFile = file;
+ return true;
+ }
+
+ return false;
+}
+
+
+bool ImlibWidget::cacheImage( const KURL& url )
+{
+// qDebug("cache image: %s", url.url().latin1());
+ KuickFile *file = FileCache::self()->getFile( url );
+ if ( file->isAvailable() )
+ return cacheImage( file );
+ else {
+ if ( !file->download() ) {
+ return false;
+ }
+ connect( file, SIGNAL( downloaded( KuickFile * )), SLOT( cacheImage( KuickFile * )) );
+ return true; // optimistic
+ }
+}
+
+bool ImlibWidget::cacheImage( KuickFile * file )
+{
+// qDebug("cache image: %s", file->url().url().latin1());
+ KuickImage *kuim = loadImageInternal( file );
+ if ( kuim ) {
+ kuim->renderPixmap();
+ return true;
+ }
+ return false;
+}
+
+
+void ImlibWidget::showImage()
+{
+ XMapWindow( x11Display(), win );
+ XSync( x11Display(), False );
+}
+
+
+// -256..256
+void ImlibWidget::setBrightness( int factor )
+{
+ mod.brightness = factor + ImlibOffset;
+ setImageModifier();
+
+ autoUpdate();
+}
+
+
+// -256..256
+void ImlibWidget::setContrast( int factor )
+{
+ mod.contrast = factor + ImlibOffset;
+ setImageModifier();
+
+ autoUpdate();
+}
+
+
+// -256..256
+void ImlibWidget::setGamma( int factor )
+{
+ mod.gamma = factor + ImlibOffset;
+ setImageModifier();
+
+ autoUpdate();
+}
+
+
+Rotation ImlibWidget::rotation() const
+{
+ return m_kuim ? m_kuim->absRotation() : ROT_0;
+}
+
+FlipMode ImlibWidget::flipMode() const
+{
+ return m_kuim ? m_kuim->flipMode() : FlipNone;
+}
+
+void ImlibWidget::zoomImage( float factor )
+{
+ if ( factor == 1 || factor == 0 || !m_kuim )
+ return;
+
+ int newWidth = (int) (factor * (float) m_kuim->width());
+ int newHeight = (int) (factor * (float) m_kuim->height());
+
+ if ( canZoomTo( newWidth, newHeight ) )
+ {
+ m_kuim->resize( newWidth, newHeight, idata->smoothScale ? KuickImage::SMOOTH : KuickImage::FAST );
+ autoUpdate( true );
+ }
+}
+
+bool ImlibWidget::canZoomTo( int newWidth, int newHeight )
+{
+ if ( newWidth <= 2 || newHeight <= 2 ) // minimum size for an image is 2x2 pixels
+ return false;
+
+ return true;
+}
+
+
+void ImlibWidget::showImageOriginalSize()
+{
+ if ( !m_kuim )
+ return;
+
+ m_kuim->restoreOriginalSize();
+ autoUpdate( true );
+
+ showImage();
+}
+
+bool ImlibWidget::autoRotate( KuickImage *kuim )
+{
+ KFileMetaInfo metadatas( kuim->file().localFile() );
+ if ( !metadatas.isValid() )
+ return false;
+
+ KFileMetaInfoItem metaitem = metadatas.item("Orientation");
+ if ( !metaitem.isValid()
+#if QT_VERSION >= 0x030100
+ || metaitem.value().isNull()
+#endif
+ )
+ return false;
+
+
+ switch ( metaitem.value().toInt() )
+ {
+ // Orientation:
+ // 1: normal
+ // 2: flipped horizontally
+ // 3: ROT 180
+ // 4: flipped vertically
+ // 5: ROT 90 -> flip horizontally
+ // 6: ROT 90
+ // 7: ROT 90 -> flip vertically
+ // 8: ROT 270
+
+ case 1:
+ default:
+ kuim->rotateAbs( ROT_0 );
+ break;
+ case 2:
+ kuim->flipAbs( FlipHorizontal );
+ break;
+ case 3:
+ kuim->rotateAbs( ROT_180 );
+ break;
+ case 4:
+ kuim->flipAbs( FlipVertical );
+ break;
+ case 5:
+ kuim->rotateAbs( ROT_90 );
+ kuim->flipAbs( FlipHorizontal );
+ break;
+ case 6:
+ kuim->rotateAbs( ROT_90 );
+ break;
+ case 7:
+ kuim->rotateAbs( ROT_90 );
+ kuim->flipAbs( FlipVertical );
+ break;
+ case 8:
+ kuim->rotateAbs( ROT_270 );
+ break;
+ }
+
+ return true;
+}
+
+
+void ImlibWidget::setRotation( Rotation rot )
+{
+ if ( m_kuim )
+ {
+ if ( m_kuim->rotateAbs( rot ) )
+ autoUpdate( true );
+ }
+}
+
+
+// slots connected to Accels and popupmenu
+void ImlibWidget::rotate90()
+{
+ if ( !m_kuim )
+ return;
+
+ m_kuim->rotate( ROT_90 );
+ rotated( m_kuim, ROT_90 );
+ autoUpdate( true );
+}
+
+void ImlibWidget::rotate180()
+{
+ if ( !m_kuim )
+ return;
+
+ m_kuim->rotate( ROT_180 );
+ rotated( m_kuim, ROT_180 );
+ autoUpdate();
+}
+
+void ImlibWidget::rotate270()
+{
+ if ( !m_kuim )
+ return;
+
+ m_kuim->rotate( ROT_270 );
+ rotated( m_kuim, ROT_270 );
+ autoUpdate( true );
+}
+
+
+// should this go into a subclass?
+void ImlibWidget::flipHoriz()
+{
+ if ( !m_kuim )
+ return;
+
+ m_kuim->flip( FlipHorizontal );
+ autoUpdate();
+}
+
+void ImlibWidget::flipVert()
+{
+ if ( !m_kuim )
+ return;
+
+ m_kuim->flip( FlipVertical );
+ autoUpdate();
+}
+// end slots
+
+
+void ImlibWidget::setFlipMode( int mode )
+{
+ if ( !m_kuim )
+ return;
+
+ if ( m_kuim->flipAbs( mode ) )
+ autoUpdate();
+}
+
+
+void ImlibWidget::updateWidget( bool geometryUpdate )
+{
+ if ( !m_kuim )
+ return;
+
+// if ( geometryUpdate )
+// XUnmapWindow( x11Display(), win );// remove the old image -> no flicker
+
+ XSetWindowBackgroundPixmap( x11Display(), win, m_kuim->pixmap() );
+
+ if ( geometryUpdate )
+ updateGeometry( m_kuim->width(), m_kuim->height() );
+
+ XClearWindow( x11Display(), win );
+
+ showImage();
+}
+
+
+// here we just use the size of m_kuim, may be overridden in subclass
+void ImlibWidget::updateGeometry( int w, int h )
+{
+ XMoveWindow( x11Display(), win, 0, 0 ); // center?
+ XResizeWindow( x11Display(), win, w, h );
+ resize( w, h );
+}
+
+
+void ImlibWidget::closeEvent( QCloseEvent *e )
+{
+ e->accept();
+ QWidget::closeEvent( e );
+}
+
+
+void ImlibWidget::setBackgroundColor( const QColor& color )
+{
+ myBackgroundColor = color;
+ setPalette( QPalette( myBackgroundColor ));
+ repaint( false); // FIXME - false? necessary at all?
+}
+
+const QColor& ImlibWidget::backgroundColor() const
+{
+ return myBackgroundColor;
+}
+
+
+void ImlibWidget::setImageModifier()
+{
+ if ( !m_kuim )
+ return;
+
+ Imlib_set_image_modifier( id, m_kuim->imlibImage(), &mod );
+ m_kuim->setDirty( true );
+}
+
+int ImlibWidget::imageWidth() const
+{
+ return m_kuim ? m_kuim->width() : 0;
+}
+
+int ImlibWidget::imageHeight() const
+{
+ return m_kuim ? m_kuim->height() : 0;
+}
+
+void ImlibWidget::setBusyCursor()
+{
+ if ( ownCursor() )
+ m_oldCursor = cursor();
+ else
+ m_oldCursor = QCursor();
+
+ setCursor( KCursor::waitCursor() );
+}
+
+void ImlibWidget::restoreCursor()
+{
+ if ( cursor().shape() == KCursor::waitCursor().shape() ) // only if nobody changed the cursor in the meantime!
+ setCursor( m_oldCursor );
+}
+
+// Reparenting a widget in Qt in fact means destroying the old X window of the widget
+// and creating a new one. And since the X window used for the Imlib image is a child
+// of this widget's X window, destroying this widget's X window would mean also
+// destroying the Imlib image X window. Therefore it needs to be temporarily reparented
+// away and reparented back to the new X window.
+// Reparenting may happen e.g. when doing the old-style (non-NETWM) fullscreen changes.
+void ImlibWidget::reparent( QWidget* parent, WFlags f, const QPoint& p, bool showIt )
+{
+ XWindowAttributes attr;
+ XGetWindowAttributes( x11Display(), win, &attr );
+ XUnmapWindow( x11Display(), win );
+ XReparentWindow( x11Display(), win, attr.root, 0, 0 );
+ QWidget::reparent( parent, f, p, showIt );
+ XReparentWindow( x11Display(), win, winId(), attr.x, attr.y );
+ if( attr.map_state != IsUnmapped )
+ XMapWindow( x11Display(), win );
+}
+
+void ImlibWidget::rotated( KuickImage *, int )
+{
+}
+
+//----------
+
+
+// uhh ugly, we have two lists to map from filename to KuickImage :-/
+ImageCache::ImageCache( ImlibData *id, int maxImages )
+{
+ myId = id;
+ idleCount = 0;
+ myMaxImages = maxImages;
+ kuickList.setAutoDelete( true );
+ fileList.clear();
+ kuickList.clear();
+}
+
+
+ImageCache::~ImageCache()
+{
+ kuickList.clear();
+ fileList.clear();
+}
+
+
+void ImageCache::setMaxImages( int maxImages )
+{
+ myMaxImages = maxImages;
+ int count = kuickList.count();
+ while ( count > myMaxImages ) {
+ kuickList.removeLast();
+ fileList.remove( fileList.fromLast() );
+ count--;
+ }
+}
+
+void ImageCache::slotBusy()
+{
+ if ( idleCount == 0 )
+ emit sigBusy();
+
+ idleCount++;
+}
+
+void ImageCache::slotIdle()
+{
+ idleCount--;
+
+ if ( idleCount == 0 )
+ emit sigIdle();
+}
+
+
+KuickImage * ImageCache::getKuimage( KuickFile * file,
+ ImlibColorModifier mod )
+{
+ if ( !file )
+ return 0L;
+
+ assert( file->isAvailable() ); // debug build
+ if ( file->waitForDownload( 0L ) != KuickFile::OK ) // and for users
+ return 0L;
+
+ KuickImage *kuim = 0L;
+ int index = fileList.findIndex( file );
+ if ( index != -1 ) {
+ if ( index == 0 )
+ kuim = kuickList.at( 0 );
+
+ // need to reorder the lists, otherwise we might delete the current
+ // image when a new one is cached and the current one is the last!
+ else {
+ kuim = kuickList.take( index );
+ kuickList.insert( 0, kuim );
+ fileList.remove( file );
+ fileList.prepend( file );
+ }
+
+ return kuim;
+ }
+
+ if ( !kuim ) {
+ slotBusy();
+
+// #ifndef NDEBUG
+// struct timeval tms1, tms2;
+// gettimeofday( &tms1, NULL );
+// #endif
+
+ ImlibImage *im = Imlib_load_image( myId,
+ QFile::encodeName( file->localFile() ).data() );
+
+// #ifndef NDEBUG
+// gettimeofday( &tms2, NULL );
+// qDebug("*** LOADING image: %s, took %ld ms", file.latin1(),
+// (tms2.tv_usec - tms1.tv_usec)/1000);
+// #endif
+
+ slotIdle();
+ if ( !im ) {
+ slotBusy();
+ im = loadImageWithQt( file->localFile() );
+ slotIdle();
+ if ( !im )
+ return 0L;
+ }
+
+ Imlib_set_image_modifier( myId, im, &mod );
+ kuim = new KuickImage( file, im, myId );
+ connect( kuim, SIGNAL( startRendering() ), SLOT( slotBusy() ));
+ connect( kuim, SIGNAL( stoppedRendering() ), SLOT( slotIdle() ));
+
+ kuickList.insert( 0, kuim );
+ fileList.prepend( file );
+ }
+
+ if ( kuickList.count() > (uint) myMaxImages ) {
+// qDebug(":::: now removing from cache: %s", (*fileList.fromLast()).latin1());
+ kuickList.removeLast();
+ fileList.remove( fileList.fromLast() );
+ }
+
+ return kuim;
+}
+
+
+// Note: the returned image's filename will not be the real filename (which it usually
+// isn't anyway, according to Imlib's sources).
+ImlibImage * ImageCache::loadImageWithQt( const QString& fileName ) const
+{
+ kdDebug() << "Trying to load " << fileName << " with KImageIO..." << endl;
+
+ KImageIO::registerFormats();
+
+ QImage image( fileName );
+ if ( image.isNull() )
+ return 0L;
+ if ( image.depth() != 32 ) {
+ image.setAlphaBuffer(false);
+ image = image.convertDepth(32);
+
+ if ( image.isNull() )
+ return 0L;
+ }
+
+ // convert to 24 bpp (discard alpha)
+ int numPixels = image.width() * image.height();
+ const int NUM_BYTES_NEW = 3; // 24 bpp
+ uchar *newImageData = new uchar[numPixels * NUM_BYTES_NEW];
+ uchar *newData = newImageData;
+
+ int w = image.width();
+ int h = image.height();
+
+ for (int y = 0; y < h; y++) {
+ QRgb *scanLine = reinterpret_cast<QRgb *>( image.scanLine(y) );
+ for (int x = 0; x < w; x++) {
+ const QRgb& pixel = scanLine[x];
+ *(newData++) = qRed(pixel);
+ *(newData++) = qGreen(pixel);
+ *(newData++) = qBlue(pixel);
+ }
+ }
+
+ ImlibImage *im = Imlib_create_image_from_data( myId, newImageData, NULL,
+ image.width(), image.height() );
+
+ delete[] newImageData;
+
+ return im;
+}
+
+#include "imlibwidget.moc"
diff --git a/kuickshow/src/imlibwidget.h b/kuickshow/src/imlibwidget.h
new file mode 100644
index 00000000..5f6e89e1
--- /dev/null
+++ b/kuickshow/src/imlibwidget.h
@@ -0,0 +1,187 @@
+/****************************************************************************
+** $Id$
+**
+** ImlibWidget: maps an Xlib window with Imlib's contents on a QWidget
+**
+** Created : 98
+**
+** Copyright (C) 1998-2001 by Carsten Pfeiffer. All rights reserved.
+**
+****************************************************************************/
+
+#ifndef IMLIBWIDGET_H
+#define IMLIBWIDGET_H
+
+#include <qvariant.h>
+
+#include <qcursor.h>
+#include <qevent.h>
+#include <qptrlist.h>
+#include <qtimer.h>
+#include <qwidget.h>
+
+#include <kurl.h>
+
+// #include those AFTER Qt-includes!
+#include <Imlib.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+// #include <X11/extensions/shape.h>
+
+#include "imdata.h"
+#include "kuickdata.h"
+
+class KuickFile;
+class KuickImage;
+
+class ImageCache : public QObject
+{
+ Q_OBJECT
+
+public:
+ ImageCache( ImlibData *id, int maxImages=1 );
+ ~ImageCache();
+
+ void setMaxImages( int maxImages );
+ int maxImages() const { return myMaxImages; }
+
+ KuickImage * getKuimage( KuickFile * file, ImlibColorModifier );
+
+private:
+ ImlibImage * loadImageWithQt( const QString& filename ) const;
+
+ int myMaxImages;
+ QValueList<KuickFile*>fileList;
+ QPtrList<KuickImage> kuickList;
+ // QPtrList<ImlibImage> imList;
+ ImlibData * myId;
+ int idleCount;
+
+private slots:
+ void slotBusy();
+ void slotIdle();
+
+signals:
+ void sigBusy();
+ void sigIdle();
+
+};
+
+
+// ------------------------------------------
+
+class QColor;
+
+class ImlibWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+
+ ImlibWidget( ImData *_idata=0, QWidget *parent=0, const char *name=0 );
+ ImlibWidget( ImData *_idata, ImlibData *id, QWidget *parent=0,
+ const char *name=0 );
+ virtual ~ImlibWidget();
+
+ KURL url() const;
+ KuickFile * currentFile() const;
+ bool loadImage( KuickFile * file );
+ bool loadImage( const KURL& url );
+ bool cacheImage(const KURL& url );
+ void zoomImage( float );
+ void setBrightness( int );
+ void setContrast( int );
+ void setGamma( int );
+ void setRotation( Rotation );
+ void setFlipMode( int mode );
+
+ int brightness() const; // ### no impl!
+ int contrast() const; // ### no impl!
+ int gamma() const; // ### no impl!
+ Rotation rotation() const;
+ FlipMode flipMode() const;
+
+ int imageWidth() const;
+ int imageHeight() const;
+
+ void setAutoRender( bool enable ) { isAutoRendering = enable;}
+ bool isAutoRenderEnabled() const { return isAutoRendering; }
+ void setMaxImageCache( int );
+ int maxImageCache() const { return myMaxImageCache; }
+ const QColor& backgroundColor() const;
+ void setBackgroundColor( const QColor& );
+
+ /**
+ * @return true if auto-rotation is not possible, e.g. because no metadata
+ * about orientation is available
+ */
+ virtual bool autoRotate( KuickImage *kuim );
+
+ ImlibData* getImlibData() const { return id; }
+
+ virtual void reparent( QWidget* parent, WFlags f, const QPoint& p, bool showIt = FALSE );
+
+public slots:
+ void rotate90();
+ void rotate270();
+ void rotate180();
+ void flipHoriz();
+ void flipVert();
+ void showImageOriginalSize();
+ inline void updateImage() { updateWidget( true ); }
+
+
+protected:
+ KuickImage * loadImageInternal( KuickFile * file );
+ void showImage();
+ void setImageModifier();
+ void rotate( int );
+ void updateWidget( bool geometryUpdate=true );
+ virtual void updateGeometry( int width, int height );
+ virtual void loaded( KuickImage * );
+ virtual bool canZoomTo( int newWidth, int newHeight );
+ virtual void rotated( KuickImage *kuim, int rotation );
+
+ void closeEvent( QCloseEvent * );
+
+ inline void autoUpdate( bool geometryUpdate=false ) {
+ if ( isAutoRendering )
+ updateWidget( geometryUpdate );
+ }
+
+ bool stillResizing, deleteImData, deleteImlibData;
+ bool imlibModifierChanged;
+
+ KuickImage *m_kuim;
+ ImageCache *imageCache;
+ ImlibData *id;
+ ImData *idata;
+ Window win;
+ ImlibColorModifier mod;
+
+ KuickFile *m_kuickFile;
+ QCursor m_oldCursor;
+
+ static const int ImlibOffset;
+
+
+private:
+ void init();
+ bool isAutoRendering;
+ int myMaxImageCache;
+ QColor myBackgroundColor;
+
+
+protected slots:
+ bool cacheImage( KuickFile *file );
+ virtual void setBusyCursor();
+ virtual void restoreCursor();
+
+
+signals:
+ void sigImageError( const KuickFile * file, const QString& );
+
+};
+
+
+#endif
diff --git a/kuickshow/src/kuick.cpp b/kuickshow/src/kuick.cpp
new file mode 100644
index 00000000..43eadb50
--- /dev/null
+++ b/kuickshow/src/kuick.cpp
@@ -0,0 +1,4 @@
+#include "kuick.h"
+
+Kuick * Kuick::s_self = 0L;
+QSize Kuick::s_frameSize;
diff --git a/kuickshow/src/kuick.h b/kuickshow/src/kuick.h
new file mode 100644
index 00000000..bc86d5d2
--- /dev/null
+++ b/kuickshow/src/kuick.h
@@ -0,0 +1,70 @@
+/* This file is part of the KDE project
+ Copyright (C) 2000,2001,2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KUICKGLOBALS_H
+#define KUICKGLOBALS_H
+
+#include <qrect.h>
+#include <qsize.h>
+
+#include <kwin.h>
+#include <kwinmodule.h>
+
+class Kuick
+{
+public:
+ static QRect workArea() {
+ return self()->winModule.workArea();
+ }
+
+ static QSize frameSize( WId win = 0L ) {
+ if ( win ) {
+ KWin::WindowInfo info = KWin::windowInfo(win, NET::WMKDEFrameStrut | NET::WMGeometry);
+ int wborder = info.frameGeometry().width() - info.geometry().width();
+ int hborder = info.frameGeometry().height() - info.geometry().height();
+
+ if ( wborder || hborder ) { // we get a 0,0 border when not shown
+ s_frameSize.setWidth( wborder );
+ s_frameSize.setHeight( hborder );
+ }
+ }
+
+ if ( !s_frameSize.isValid() )
+ return QSize( 0, 0 );
+
+ return s_frameSize;
+ }
+
+ static Kuick * self() {
+ if ( !s_self ) {
+ s_self = new Kuick;
+ }
+ return s_self;
+ }
+
+ KWinModule winModule;
+
+private:
+ Kuick() {}
+ static Kuick * s_self;
+
+ static QSize s_frameSize;
+};
+
+
+#endif // KUICKGLOBALS_H
diff --git a/kuickshow/src/kuickconfigdlg.cpp b/kuickshow/src/kuickconfigdlg.cpp
new file mode 100644
index 00000000..6ece8883
--- /dev/null
+++ b/kuickshow/src/kuickconfigdlg.cpp
@@ -0,0 +1,99 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998-2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#ifdef index
+#undef index
+#endif
+#include "kuickconfigdlg.h"
+
+#include <qkeycode.h>
+#include <qvbox.h>
+
+#include <kaccel.h>
+#include <kconfig.h>
+#include <kglobal.h>
+#include <klocale.h>
+
+#include "imagewindow.h"
+#include "defaultswidget.h"
+#include "generalwidget.h"
+#include "slideshowwidget.h"
+
+#include "kuickdata.h"
+
+
+KuickConfigDialog::KuickConfigDialog( KActionCollection *_coll, QWidget *parent,
+ const char *name, bool modal )
+ : KDialogBase( Tabbed, i18n("Configure"),
+ Help | Default | Ok | Apply | Cancel, Ok,
+ parent, name, modal )
+{
+ coll = _coll;
+ QVBox *box = addVBoxPage( i18n("&General") );
+ generalWidget = new GeneralWidget( box, "general widget" );
+
+ box = addVBoxPage( i18n("&Modifications") );
+ defaultsWidget = new DefaultsWidget( box, "defaults widget" );
+
+ box = addVBoxPage( i18n("&Slideshow") );
+ slideshowWidget = new SlideShowWidget( box, "slideshow widget" );
+
+ box = addVBoxPage( i18n("&Viewer Shortcuts") );
+
+ imageWindow = new ImageWindow(); // just to get the accel...
+ imageWindow->hide();
+
+ imageKeyChooser = new KKeyChooser( imageWindow->actionCollection(), box );
+
+ box = addVBoxPage( i18n("Bro&wser Shortcuts") );
+ browserKeyChooser = new KKeyChooser( coll, box );
+
+ connect( this, SIGNAL( defaultClicked() ), SLOT( resetDefaults() ));
+}
+
+KuickConfigDialog::~KuickConfigDialog()
+{
+ imageWindow->close( true );
+}
+
+void KuickConfigDialog::applyConfig()
+{
+ generalWidget->applySettings( *kdata );
+ defaultsWidget->applySettings( *kdata );
+ slideshowWidget->applySettings( *kdata );
+
+ imageKeyChooser->save();
+ browserKeyChooser->save();
+
+ KGlobal::config()->sync();
+}
+
+
+void KuickConfigDialog::resetDefaults()
+{
+ KuickData data;
+ generalWidget->loadSettings( data );
+ defaultsWidget->loadSettings( data );
+ slideshowWidget->loadSettings( data );
+
+ imageKeyChooser->allDefault();
+ browserKeyChooser->allDefault();
+}
+
+#include "kuickconfigdlg.moc"
diff --git a/kuickshow/src/kuickconfigdlg.h b/kuickshow/src/kuickconfigdlg.h
new file mode 100644
index 00000000..884d91dc
--- /dev/null
+++ b/kuickshow/src/kuickconfigdlg.h
@@ -0,0 +1,58 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998-2003 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KUICKCONFIGDLG_H
+#define KUICKCONFIGDLG_H
+
+#include <qevent.h>
+
+#include <kkeydialog.h>
+
+#include <kdialogbase.h>
+
+class GeneralWidget;
+class DefaultsWidget;
+class SlideShowWidget;
+class ImageWindow;
+
+class KuickConfigDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ KuickConfigDialog( KActionCollection *coll, QWidget *parent=0,
+ const char *name=0, bool modal=true);
+ ~KuickConfigDialog();
+
+ void applyConfig();
+
+private slots:
+ void resetDefaults();
+
+private:
+ DefaultsWidget *defaultsWidget;
+ GeneralWidget *generalWidget;
+ SlideShowWidget *slideshowWidget;
+ KKeyChooser *imageKeyChooser, *browserKeyChooser;
+ KActionCollection *coll;
+
+ ImageWindow *imageWindow;
+
+};
+
+#endif
diff --git a/kuickshow/src/kuickdata.cpp b/kuickshow/src/kuickdata.cpp
new file mode 100644
index 00000000..c6aa47c2
--- /dev/null
+++ b/kuickshow/src/kuickdata.cpp
@@ -0,0 +1,177 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998-2003 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <stdlib.h>
+
+#include <qcolor.h>
+#include <kconfig.h>
+#include <kglobal.h>
+
+#include "kuickdata.h"
+
+
+KuickData::KuickData()
+{
+ fileFilter = "*.jpeg *.jpg *.gif *.xpm *.ppm *.pgm *.pbm *.pnm *.png *.bmp *.psd *.eim *.tif *.tiff *.xcf";// *.mng";
+ slideDelay = 3000;
+ slideshowCycles = 1;
+ slideshowFullscreen = true;
+ slideshowStartAtFirst = true;
+
+ preloadImage = true;
+
+ isModsEnabled = true;
+ fullScreen = false;
+ autoRotation = true;
+ downScale = true;
+ upScale = false;
+ flipVertically = false;
+ flipHorizontally = false;
+
+ maxUpScale = 3;
+ rotation = ROT_0;
+
+ brightnessSteps = 1;
+ contrastSteps = 1;
+ gammaSteps = 1;
+ scrollSteps = 1;
+ zoomSteps = 1.5;
+
+ maxZoomFactor = 4.0;
+
+ maxCachedImages = 4;
+ backgroundColor = Qt::black;
+
+ startInLastDir = true;
+
+ idata = new ImData;
+}
+
+KuickData::~KuickData()
+{
+ delete idata;
+}
+
+
+void KuickData::load()
+{
+ KConfig *kc = KGlobal::config();
+
+ KuickData def;
+
+ kc->setGroup( "GeneralConfiguration" );
+ fileFilter = kc->readEntry( "FileFilter", def.fileFilter );
+ slideDelay = kc->readNumEntry( "SlideShowDelay", def.slideDelay );
+ slideshowCycles = kc->readUnsignedNumEntry( "SlideshowCycles", 1 );
+ slideshowFullscreen = kc->readBoolEntry( "SlideshowFullscreen", true );
+ slideshowStartAtFirst = kc->readBoolEntry("SlideshowStartAtFirst", true );
+
+ preloadImage = kc->readBoolEntry( "PreloadNextImage", def.preloadImage );
+
+ fullScreen = kc->readBoolEntry( "Fullscreen", def.fullScreen);
+ autoRotation = kc->readBoolEntry( "AutoRotation", def.autoRotation);
+ downScale = kc->readBoolEntry( "ShrinkToScreenSize", def.downScale );
+ upScale = kc->readBoolEntry( "ZoomToScreenSize", def.upScale );
+ flipVertically = kc->readBoolEntry( "FlipVertically", def.flipVertically );
+ flipHorizontally = kc->readBoolEntry( "FlipHorizontally",
+ def.flipHorizontally );
+ maxUpScale = kc->readNumEntry( "MaxUpscale Factor", def.maxUpScale );
+ rotation = (Rotation) kc->readNumEntry( "Rotation", def.rotation );
+
+ isModsEnabled = kc->readBoolEntry( "ApplyDefaultModifications",
+ def.isModsEnabled );
+
+ brightnessSteps = kc->readNumEntry("BrightnessStepSize",def.brightnessSteps);
+ contrastSteps = kc->readNumEntry("ContrastStepSize", def.contrastSteps);
+ gammaSteps = kc->readNumEntry("GammaStepSize", def.gammaSteps);
+ scrollSteps = kc->readNumEntry("ScrollingStepSize", def.scrollSteps);
+ zoomSteps = kc->readDoubleNumEntry("ZoomStepSize", def.zoomSteps);
+
+ maxZoomFactor = kc->readDoubleNumEntry( "MaximumZoomFactorByDesktop", def.maxZoomFactor );
+
+ maxCachedImages = kc->readUnsignedNumEntry( "MaxCachedImages",
+ def.maxCachedImages );
+ backgroundColor = kc->readColorEntry( "BackgroundColor", &Qt::black );
+
+ startInLastDir = kc->readBoolEntry( "StartInLastDir", true);
+
+ idata->load( kc );
+
+ // compatibility with KuickShow <= 0.8.3
+ switch ( rotation )
+ {
+ case 90:
+ rotation = ROT_90;
+ break;
+ case 180:
+ rotation = ROT_180;
+ break;
+ case 270:
+ rotation = ROT_270;
+ break;
+ default:
+ if ( (rotation < ROT_0) || (rotation > ROT_270) )
+ rotation = ROT_0;
+ break;
+ }
+}
+
+
+void KuickData::save()
+{
+ KConfig *kc = KGlobal::config();
+ kc->setGroup( "GeneralConfiguration" );
+
+ kc->writeEntry( "FileFilter", fileFilter );
+ kc->writeEntry( "SlideShowDelay", slideDelay );
+ kc->writeEntry( "SlideshowCycles", slideshowCycles );
+ kc->writeEntry( "SlideshowFullscreen", slideshowFullscreen );
+ kc->writeEntry( "SlideshowStartAtFirst", slideshowStartAtFirst );
+
+ kc->writeEntry( "PreloadNextImage", preloadImage );
+
+ kc->writeEntry( "Fullscreen", fullScreen );
+ kc->writeEntry( "AutoRotation", autoRotation );
+ kc->writeEntry( "ShrinkToScreenSize", downScale );
+ kc->writeEntry( "ZoomToScreenSize", upScale );
+ kc->writeEntry( "FlipVertically", flipVertically );
+ kc->writeEntry( "FlipHorizontally", flipHorizontally );
+ kc->writeEntry( "MaxUpscale Factor", maxUpScale );
+ kc->writeEntry( "Rotation", rotation );
+
+ kc->writeEntry( "ApplyDefaultModifications", isModsEnabled );
+
+
+ kc->writeEntry( "BrightnessStepSize", brightnessSteps );
+ kc->writeEntry( "ContrastStepSize", contrastSteps );
+ kc->writeEntry( "GammaStepSize", gammaSteps );
+
+ kc->writeEntry( "ScrollingStepSize", scrollSteps );
+ kc->writeEntry( "ZoomStepSize", zoomSteps );
+
+ kc->writeEntry( "MaximumZoomFactorByDesktop", maxZoomFactor );
+
+ kc->writeEntry( "MaxCachedImages", maxCachedImages );
+ kc->writeEntry( "BackgroundColor", backgroundColor );
+
+ kc->writeEntry( "StartInLastDir", startInLastDir );
+
+ idata->save( kc );
+
+ kc->sync();
+}
diff --git a/kuickshow/src/kuickdata.h b/kuickshow/src/kuickdata.h
new file mode 100644
index 00000000..d05b3e99
--- /dev/null
+++ b/kuickshow/src/kuickdata.h
@@ -0,0 +1,86 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998-2003 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KUICKDATA_H
+#define KUICKDATA_H
+
+#include <qcolor.h>
+#include <qstring.h>
+
+#include "imdata.h"
+
+class KConfig;
+
+// values are also used as combobox index defaultswidget.*
+enum Rotation { ROT_0=0, ROT_90=1, ROT_180=2, ROT_270=3 };
+
+// hmm, global declaration for now
+enum FlipMode { FlipNone = 0, FlipHorizontal = 1, FlipVertical = 2 };
+
+class KuickData
+{
+public:
+ KuickData();
+ ~KuickData();
+
+ void load();
+ void save();
+
+
+ ImData *idata;
+
+ QString fileFilter;
+ uint slideDelay;
+ uint slideshowCycles;
+ bool slideshowFullscreen :1;
+ bool slideshowStartAtFirst :1;
+
+ int brightnessSteps;
+ int contrastSteps;
+ int gammaSteps;
+
+ int scrollSteps;
+ float zoomSteps;
+
+ bool startInLastDir :1;
+
+ bool preloadImage :1;
+ bool autoRotation :1;
+ bool fullScreen :1;
+
+ // default image modifications
+ bool isModsEnabled :1;
+
+ bool flipVertically :1;
+ bool flipHorizontally :1;
+ bool downScale :1;
+ bool upScale :1;
+ int maxUpScale;
+ float maxZoomFactor;
+ uint maxCachedImages;
+ Rotation rotation;
+
+ QColor backgroundColor;
+
+
+};
+
+
+extern KuickData* kdata;
+
+#endif
diff --git a/kuickshow/src/kuickfile.cpp b/kuickshow/src/kuickfile.cpp
new file mode 100644
index 00000000..1dd259d6
--- /dev/null
+++ b/kuickshow/src/kuickfile.cpp
@@ -0,0 +1,194 @@
+#include <qfile.h>
+
+#include <kdebug.h>
+#include <kdeversion.h>
+#include <kinstance.h>
+#include <klocale.h>
+#include <kprogress.h>
+#include <kio/job.h>
+#include <kio/netaccess.h>
+#include <ktempfile.h>
+
+#include "filecache.h"
+#include "kuickfile.h"
+
+KuickFile::KuickFile(const KURL& url)
+ : QObject(),
+ m_url( url ),
+ m_job( 0L ),
+ m_progress( 0L ),
+ m_currentProgress( 0 )
+{
+ if ( m_url.isLocalFile())
+ m_localFile = m_url.path();
+ else {
+ const KURL& mostLocal = KIO::NetAccess::mostLocalURL( m_url, 0L );
+ if ( mostLocal.isValid() && mostLocal.isLocalFile() )
+ m_localFile = mostLocal.path();
+ }
+}
+
+KuickFile::~KuickFile()
+{
+ delete m_job;
+
+ if ( hasDownloaded() )
+ QFile::remove( m_localFile );
+}
+
+QString KuickFile::localFile() const
+{
+ // Note: never call isAvailable() from here, directly or indirectly
+
+ if ( isDownloading() )
+ return QString::null;
+
+ return m_localFile;
+}
+
+bool KuickFile::hasDownloaded() const
+{
+ return !m_url.isLocalFile() && isAvailable() && m_job != 0L;
+}
+
+// ### need an API for refreshing the file?
+bool KuickFile::download()
+{
+ if ( m_url.isLocalFile() || isAvailable() )
+ return true;
+
+ if ( isDownloading() )
+ return true;
+
+ // reinitialize
+ m_localFile = QString::null;
+ m_currentProgress = 0;
+
+
+ QString ext;
+ QString fileName = m_url.fileName();
+ int extIndex = fileName.findRev('.');
+ if ( extIndex > 0 )
+ ext = fileName.mid( extIndex + 1 );
+
+ QString tempDir = FileCache::self()->tempDir();
+ KTempFile tempFile( tempDir, ext );
+ tempFile.setAutoDelete( tempDir.isNull() ); // in case there is no proper tempdir, make sure to delete those files!
+ if ( tempFile.status() != 0 )
+ return false;
+
+ tempFile.close();
+ if ( tempFile.status() != 0 )
+ return false;
+
+ KURL destURL;
+ destURL.setPath( tempFile.name() );
+
+ m_job = KIO::file_copy( m_url, destURL, -1, true, false, false ); // handling progress ourselves
+ m_job->setAutoErrorHandlingEnabled( true );
+ connect( m_job, SIGNAL( result( KIO::Job * )), SLOT( slotResult( KIO::Job * ) ));
+ connect( m_job, SIGNAL( percent( KIO::Job *, unsigned long )), SLOT( slotProgress( KIO::Job *, unsigned long ) ));
+
+ // TODO: generify background/foreground downloading?
+
+ return m_job != 0L;
+}
+
+KuickFile::DownloadStatus KuickFile::waitForDownload( QWidget *parent )
+{
+ if ( isAvailable() )
+ return OK;
+
+ if ( !isDownloading() ) {
+ if ( !download() )
+ return ERROR;
+ }
+
+ KProgressDialog *dialog = new KProgressDialog( parent );
+ dialog->setModal( true );
+ dialog->setCaption( i18n("Downloading %1...").arg( m_url.fileName() ) );
+ dialog->setLabel( i18n("Please wait while downloading\n%1").arg( m_url.prettyURL() ));
+ dialog->setAllowCancel( true );
+ dialog->setAutoClose( true );
+
+ m_progress = dialog->progressBar();
+ m_progress->setTotalSteps( 100 ); // percent
+ m_progress->setProgress( m_currentProgress );
+ dialog->exec();
+ bool canceled = dialog->wasCancelled();
+ delete dialog;
+ m_progress = 0L;
+
+ if ( canceled && m_job ) {
+ m_job->kill();
+ m_job = 0L;
+ m_currentProgress = 0;
+ }
+ // ### when aborted, remove KuickImage from FileCache?
+
+ if ( canceled )
+ return CANCELED;
+
+ if ( !isAvailable() )
+ return ERROR;
+
+ // ### use custom progress dialog with OK, SKIP, CANCEL?
+ return OK;
+}
+
+void KuickFile::slotResult( KIO::Job *job )
+{
+ if (job != m_job) { // huh?
+ return;
+ }
+
+ m_job = 0L;
+
+ if ( job->error() != 0 ) {
+ m_currentProgress = 0;
+
+ if ( job->error() != KIO::ERR_USER_CANCELED )
+ kdWarning() << "ERROR: KuickFile::slotResult: " << job->errorString() << endl;
+
+ QString canceledFile = static_cast<KIO::FileCopyJob*>(job)->destURL().path();
+ QFile::remove( canceledFile );
+ m_progress->topLevelWidget()->hide();
+ }
+ else {
+ m_localFile = static_cast<KIO::FileCopyJob*>(job)->destURL().path();
+ emit downloaded( this ); // before closing the progress dialog
+
+ if ( m_progress ) {
+ m_progress->setProgress( 100 );
+#define BUGGY_VERSION KDE_MAKE_VERSION(3,5,2)
+ if ( KDE::version() <= BUGGY_VERSION ) {
+ m_progress->topLevelWidget()->hide(); // ### workaround broken KProgressDialog
+ }
+ }
+ }
+}
+
+void KuickFile::slotProgress( KIO::Job *job, unsigned long percent )
+{
+ if (job != m_job) { // huh?
+ return;
+ }
+
+ m_currentProgress = percent;
+
+ if ( !m_progress )
+ return;
+
+ // only set 100% in slotResult. Otherwise, the progress dialog would be closed
+ // before slotResult() is called.
+ if ( percent >= 100 )
+ percent = 99;
+
+ m_progress->setProgress( (int) percent );
+}
+
+bool operator==( const KuickFile& first, const KuickFile& second ) {
+ return first.url().equals( second.url() );
+}
+
+#include "kuickfile.moc"
diff --git a/kuickshow/src/kuickfile.h b/kuickshow/src/kuickfile.h
new file mode 100644
index 00000000..957db6ee
--- /dev/null
+++ b/kuickshow/src/kuickfile.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+** $Id: .emacs,v 1.3 2002/02/20 15:06:53 gis Exp $
+**
+** Created : 2006
+**
+** Copyright (C) 2006 Carsten Pfeiffer <pfeiffer@kde.org>
+**
+****************************************************************************/
+
+#ifndef KUICKFILE_H
+#define KUICKFILE_H
+
+#include <qobject.h>
+#include <qstring.h>
+
+#include <kurl.h>
+#include <kprogress.h>
+
+namespace KIO {
+ class Job;
+ class FileCopyJob;
+}
+
+class KuickFile : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum DownloadStatus
+ {
+ OK = 1,
+ CANCELED,
+ ERROR
+ };
+
+ KuickFile(const KURL& url);
+
+ /**
+ * Cleans up resources and removes any temporary file, if available.
+ */
+ ~KuickFile();
+
+ const KURL& url() const { return m_url; }
+
+
+ QString localFile() const;
+
+ bool download();
+
+ /**
+ * @return true if download is in progress
+ */
+ bool isDownloading() const { return m_job != 0L; }
+
+ /**
+ * @return true if a local file is available, that is,
+ * @ref #localFile will return a non-empty name
+ * ### HERE ADD mostlylocal thing!
+ */
+ bool isAvailable() const { return !localFile().isEmpty(); }
+
+ /**
+ * @return true if @ref #isAvailable() returns true AND @ref #url() is a remote URL,
+ * i.e. the file really has been downloaded.
+ */
+ bool hasDownloaded() const;
+
+ /**
+ * Opens a modal dialog window, blocking user interaction until the download
+ * has finished. If the file is already available, this function will return true
+ * immediately.
+ * @return true when the download has finished or false when the user aborted the dialog
+ */
+ KuickFile::DownloadStatus waitForDownload( QWidget *parent );
+
+// bool needsDownload();
+
+signals:
+ /**
+ * Signals that download has finished for that file. Will only be emitted for non-local files!
+ */
+ void downloaded( KuickFile * );
+
+private slots:
+ void slotResult( KIO::Job *job );
+ void slotProgress( KIO::Job *job, unsigned long percent );
+
+private:
+ KURL m_url;
+ QString m_localFile;
+ KIO::FileCopyJob *m_job;
+ KProgress *m_progress;
+ int m_currentProgress;
+
+};
+
+bool operator==( const KuickFile& first, const KuickFile& second );
+
+#endif // KUICKFILE_H
diff --git a/kuickshow/src/kuickglobals.h b/kuickshow/src/kuickglobals.h
new file mode 100644
index 00000000..4ea2ff3c
--- /dev/null
+++ b/kuickshow/src/kuickglobals.h
@@ -0,0 +1,33 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001,2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KUICKGLOBALS_H
+#define KUICKGLOBALS_H
+
+#include <kwinmodule.h>
+
+class KuickGlobals
+{
+public:
+ KWinModule winModule;
+
+
+};
+
+
+#endif // KUICKGLOBALS_H
diff --git a/kuickshow/src/kuickimage.cpp b/kuickshow/src/kuickimage.cpp
new file mode 100644
index 00000000..29e5de1c
--- /dev/null
+++ b/kuickshow/src/kuickimage.cpp
@@ -0,0 +1,527 @@
+#include "kuickimage.h"
+
+KuickImage::KuickImage( const KuickFile * file, ImlibImage *im, ImlibData *id)
+ : QObject( 0L, 0L )
+{
+ myFile = file;
+ myOrigIm = 0L;
+ myIm = im;
+ myId = id;
+ myPixmap = 0L;
+ myWidth = im->rgb_width;
+ myHeight = im->rgb_height;
+ myIsDirty = true;
+
+ myOrigWidth = myWidth;
+ myOrigHeight = myHeight;
+ myRotation = ROT_0;
+ myFlipMode = FlipNone;
+}
+
+KuickImage::~KuickImage()
+{
+ if ( myPixmap )
+ Imlib_free_pixmap( myId, myPixmap );
+
+ if ( myOrigIm )
+ {
+ Imlib_destroy_image( myId, myOrigIm );
+ Imlib_kill_image( myId, myIm ); // kill scaled image (### really? analyze!)
+ }
+ else
+ Imlib_destroy_image( myId, myIm );
+}
+
+
+Pixmap& KuickImage::pixmap()
+{
+ if ( myIsDirty )
+ renderPixmap();
+
+ return myPixmap;
+}
+
+
+void KuickImage::renderPixmap()
+{
+ if ( !myIsDirty )
+ return;
+
+// qDebug("### rendering: %s", myFilename.latin1());
+
+ if ( myPixmap )
+ Imlib_free_pixmap( myId, myPixmap );
+
+ emit startRendering();
+
+// #ifndef NDEBUG
+// struct timeval tms1, tms2;
+// gettimeofday( &tms1, NULL );
+// #endif
+
+ Imlib_render( myId, myIm, myWidth, myHeight );
+ myPixmap = Imlib_move_image( myId, myIm );
+
+// #ifndef NDEBUG
+// gettimeofday( &tms2, NULL );
+// qDebug("*** rendering image: %s, took %ld ms", myFilename.latin1(),
+// (tms2.tv_usec - tms1.tv_usec)/1000);
+// #endif
+
+ emit stoppedRendering();
+
+ myIsDirty = false;
+}
+
+
+void KuickImage::rotate( Rotation rot )
+{
+ if ( rot == ROT_180 ) { // rotate 180 degrees
+ Imlib_flip_image_horizontal( myId, myIm );
+ Imlib_flip_image_vertical( myId, myIm );
+ }
+
+ else if ( rot == ROT_90 || rot == ROT_270 ) {
+ qSwap( myWidth, myHeight );
+ Imlib_rotate_image( myId, myIm, -1 );
+
+ if ( rot == ROT_90 ) // rotate 90 degrees
+ Imlib_flip_image_horizontal( myId, myIm );
+ else if ( rot == ROT_270 ) // rotate 270 degrees
+ Imlib_flip_image_vertical( myId, myIm );
+ }
+
+ myRotation = (Rotation) ((myRotation + rot) % 4);
+ myIsDirty = true;
+}
+
+
+bool KuickImage::rotateAbs( Rotation rot )
+{
+ if ( myRotation == rot )
+ return false;
+
+ int diff = rot - myRotation;
+ bool clockWise = (diff > 0);
+
+ switch( abs(diff) ) {
+ case ROT_90:
+ rotate( clockWise ? ROT_90 : ROT_270 );
+ break;
+ case ROT_180:
+ rotate( ROT_180 );
+ break;
+ case ROT_270:
+ rotate( clockWise ? ROT_270 : ROT_90 );
+ break;
+ }
+
+ return true;
+}
+
+void KuickImage::flip( FlipMode flipMode )
+{
+ if ( flipMode & FlipHorizontal )
+ Imlib_flip_image_horizontal( myId, myIm );
+ if ( flipMode & FlipVertical )
+ Imlib_flip_image_vertical( myId, myIm );
+
+ myFlipMode = (FlipMode) (myFlipMode ^ flipMode);
+ myIsDirty = true;
+}
+
+bool KuickImage::flipAbs( int mode )
+{
+ if ( myFlipMode == mode )
+ return false;
+
+ bool changed = false;
+
+ if ( ((myFlipMode & FlipHorizontal) && !(mode & FlipHorizontal)) ||
+ (!(myFlipMode & FlipHorizontal) && (mode & FlipHorizontal)) ) {
+ Imlib_flip_image_horizontal( myId, myIm );
+ changed = true;
+ }
+
+ if ( ((myFlipMode & FlipVertical) && !(mode & FlipVertical)) ||
+ (!(myFlipMode & FlipVertical) && (mode & FlipVertical)) ) {
+ Imlib_flip_image_vertical( myId, myIm );
+ changed = true;
+ }
+
+ if ( changed ) {
+ myFlipMode = (FlipMode) mode;
+ myIsDirty = true;
+ return true;
+ }
+
+ return false;
+}
+
+
+void KuickImage::restoreOriginalSize()
+{
+ if (myWidth == myOrigWidth && myHeight == myOrigHeight)
+ return;
+
+// qDebug("-- restoreOriginalSize");
+
+ if ( myOrigIm != 0L )
+ {
+ Imlib_destroy_image( myId, myIm );
+ myIm = myOrigIm;
+ myOrigIm = 0L;
+ }
+
+ myWidth = myOrigWidth;
+ myHeight = myOrigHeight;
+ myIsDirty = true;
+
+ if ( myRotation == ROT_90 || myRotation == ROT_270 )
+ qSwap( myWidth, myHeight );
+}
+
+void KuickImage::resize( int width, int height, KuickImage::ResizeMode mode )
+{
+ if ( myWidth == width && myHeight == height )
+ return;
+
+ if ( mode == KuickImage::SMOOTH )
+ {
+ if ( !smoothResize( width, height ) )
+ fastResize( width, height );
+ }
+ else
+ {
+ fastResize( width, height );
+ }
+}
+
+
+void KuickImage::fastResize( int width, int height )
+{
+// qDebug("-- fastResize: %i x %i", width, height );
+
+ // lazy resizing (only done when rendering pixmap)
+ myWidth = width;
+ myHeight = height;
+ myIsDirty = true;
+}
+
+bool KuickImage::smoothResize( int newWidth, int newHeight )
+{
+// qDebug("-- smoothResize: %i x %i", newWidth, newHeight);
+
+ QImage *image = newQImage();
+ // Note: QImage::ScaleMin seems to have a bug (off-by-one, sometimes results in width being 1 pixel too small)
+ QImage scaledImage = image->smoothScale(newWidth, newHeight, QImage::ScaleFree);
+
+ delete image;
+
+
+ ImlibImage *newIm = toImage( myId, scaledImage );
+ if ( newIm )
+ {
+ if ( myOrigIm == 0 )
+ myOrigIm = myIm;
+
+ myIm = newIm;
+ myWidth = newWidth;
+ myHeight = newHeight;
+ myIsDirty = true;
+ return true;
+ }
+
+ return false;
+}
+
+QImage * KuickImage::newQImage() const
+{
+ ImlibImage *im;
+
+// qDebug("-- newQImage");
+
+ if ( myOrigIm != 0L && myRotation == ROT_0 && myFlipMode == FlipNone )
+ {
+ // use original image if no other modifications have been applied
+ // ### use orig image always and reapply mods?
+ im = myOrigIm;
+ }
+ else
+ {
+ im = myIm;
+ }
+
+ int w = im->rgb_width;
+ int h = im->rgb_height;
+
+ QImage *image = new QImage( w, h, 32 );
+ uchar *rgb = im->rgb_data;
+ QRgb **destImageData = reinterpret_cast<QRgb**>( image->jumpTable() );
+
+
+ int byteIndex = 0;
+ int destLineIndex = 0;
+ int destByteIndex = 0;
+ for ( int pixel = 0; pixel < (w * h); pixel++ )
+ {
+ if ( pixel != 0 && (pixel % w) == 0 )
+ {
+ destLineIndex++;
+ destByteIndex = 0;
+ }
+
+ uchar r = rgb[byteIndex++];
+ uchar g = rgb[byteIndex++];
+ uchar b = rgb[byteIndex++];
+
+ QRgb rgbPixel = qRgb( r, g, b );
+ destImageData[destLineIndex][destByteIndex++] = rgbPixel;
+ }
+
+ return image;
+}
+
+ImlibImage * KuickImage::toImage( ImlibData *id, QImage& image )
+{
+ if ( image.isNull() )
+ return 0L;
+
+ if ( image.depth() != 32 )
+ {
+ image.setAlphaBuffer(false);
+ image = image.convertDepth(32);
+
+ if ( image.isNull() )
+ return 0L;
+ }
+
+ // convert to 24 bpp (discard alpha)
+ int numPixels = image.width() * image.height();
+ const int NUM_BYTES_NEW = 3; // 24 bpp
+ uchar *newImageData = new uchar[numPixels * NUM_BYTES_NEW];
+ uchar *newData = newImageData;
+
+ int w = image.width();
+ int h = image.height();
+
+ for (int y = 0; y < h; y++) {
+ QRgb *scanLine = reinterpret_cast<QRgb *>( image.scanLine(y) );
+ for (int x = 0; x < w; x++) {
+ const QRgb& pixel = scanLine[x];
+ *(newData++) = qRed(pixel);
+ *(newData++) = qGreen(pixel);
+ *(newData++) = qBlue(pixel);
+ }
+ }
+
+ ImlibImage *im = Imlib_create_image_from_data( id, newImageData, NULL,
+ image.width(), image.height() );
+
+ delete [] newImageData;
+
+ return im;
+}
+
+
+#if 0
+bool KuickImage::smoothResize( int newWidth, int newHeight )
+{
+ int numPixels = newWidth * newHeight;
+ const int NUM_BYTES_NEW = 3; // 24 bpp
+ uchar *newImageData = new uchar[numPixels * NUM_BYTES_NEW];
+
+ // ### endianness
+ // myIm : old image, old size
+
+
+ /////////////////////////////////////////////////
+// int w = myOrigWidth; //myViewport.width();
+ //int h = myOrigHeight; //myViewport.height();
+
+ //QImage dst(w, h, myIm->depth(), myIm->numColors(), myIm->bitOrder());
+
+ //QRgb *scanline;
+
+ int basis_ox, basis_oy, basis_xx, basis_yy;
+
+ // ### we only scale with a fixed factor for x and y anyway
+ double scalex = newWidth / (double) myOrigWidth;
+ double scaley = newHeight / (double) myOrigHeight;
+
+// basis_ox=(int) (myViewport.left() * 4096.0 / scalex);
+// basis_oy=(int) (myViewport.top() * 4096.0 / scaley);
+ basis_ox = 0;
+ basis_oy = 0;
+ basis_xx = (int) (4096.0 / scalex);
+ basis_yy = (int) (4096.0 / scaley);
+
+ //qDebug("Basis: (%d, %d), (%d, 0), (0, %d)", basis_ox, basis_oy, basis_xx, basis_yy);
+
+ int x2, y2;
+
+ int max_x2 = (myOrigWidth << 12);
+ int max_y2 = (myOrigHeight << 12);
+
+// QRgb background = idata->backgroundColor.rgb();
+
+// QRgb **imdata = (QRgb **) myIm->jumpTable();
+// QRgb *imdata = reinterpret_cast<QRgb*>( myIm->rgb_data );
+ uchar *imdata = myIm->rgb_data;
+
+
+ int y = 0;
+
+
+// for (;;) //fill the top of the target pixmap with the background color
+// {
+// y2 = basis_oy + y * basis_yy;
+//
+// if ((y2 >= 0 && (y2 >> 12) < myIm->height()) || y >= h)
+// break;
+//
+// scanline = (QRgb*) dst.scanLine(y);
+// for (int i = 0; i < w; i++)
+// *(scanline++) = background; //qRgb(0,255,0);
+// y++;
+// }
+
+ for (; y < newHeight; y++)
+ {
+// scanline = (QRgb*) dst.scanLine(y);
+
+ x2 = basis_ox;
+ y2 = basis_oy + y * basis_yy;
+
+ if (y2 >= max_y2)
+ break;
+
+ int x = 0;
+
+// while ((x2 < 0 || (x2 >> 12) >= myIm->width()) && x < w) //fill the left of the target pixmap with the background color
+// {
+// *(scanline++) = background; //qRgb(0,0,255);
+// x2 += basis_xx;
+// x++;
+// }
+
+ int top = y2 >> 12;
+ int bottom = top + 1;
+ if (bottom >= myOrigHeight)
+ bottom--;
+
+// for (; x < w; x++)
+ for (; x < newWidth; x++) // ### myOrigWidth orig
+ {
+ int left = x2 >> 12;
+ int right = left + 1;
+
+ if (right >= myOrigWidth)
+ right = myOrigWidth - 1;
+
+ unsigned int wx = x2 & 0xfff; //12 bits of precision for reasons which will become clear
+ unsigned int wy = y2 & 0xfff; //12 bits of precision
+
+ unsigned int iwx = 0xfff - wx;
+ unsigned int iwy = 0xfff - wy;
+
+ QRgb tl = 0, tr = 0, bl = 0, br = 0;
+ int ind = 0;
+ ind = (left + top * myOrigWidth) * 3;
+ tl = (imdata[ind] << 16);
+ tl |= (imdata[ind + 1] << 8);
+ tl |= (imdata[ind + 2] << 0);
+ int bar = imdata[ind + 2] << 8;
+ bar = qBlue(bar);
+
+ ind = (right + top * myOrigWidth) * 3;
+ tr = (imdata[ind] << 16);
+ tr |= (imdata[ind + 1] << 8);
+ tr |= (imdata[ind + 2] << 0);
+ bar = imdata[ind + 2] << 8;
+
+ ind = (left + bottom * myOrigWidth) * 3;
+ bl = (imdata[ind] << 16);
+ bl |= (imdata[ind + 1] << 8);
+ bl |= (imdata[ind + 2] << 0);
+ bar = imdata[ind + 2] << 8;
+
+ ind = (right + bottom * myOrigWidth) * 3;
+ br = (imdata[ind] << 16);
+ br |= (imdata[ind + 1] << 8);
+ br |= (imdata[ind + 2] << 0);
+// tl=imdata[top][left];
+// tr=imdata[top][right];
+// bl=imdata[bottom][left];
+// br=imdata[bottom][right];
+
+ /*
+ tl=getValidPixel(myIm, left, top, x, y); //these calls are expensive
+ tr=getValidPixel(myIm, right, top, x, y); //use them to debug segfaults in this function
+ bl=getValidPixel(myIm, left, bottom, x, y);
+ br=getValidPixel(myIm, right, bottom, x, y);
+ */
+
+ unsigned int r = (unsigned int) (qRed(tl) * iwx * iwy + qRed(tr) * wx* iwy + qRed(bl) * iwx * wy + qRed(br) * wx * wy); // NB 12+12+8 == 32
+ unsigned int g = (unsigned int) (qGreen(tl) * iwx * iwy + qGreen(tr) * wx * iwy + qGreen(bl) * iwx * wy + qGreen(br) * wx * wy);
+ unsigned int b = (unsigned int) (qBlue(tl) * iwx * iwy + qBlue(tr) * wx * iwy + qBlue(bl) * iwx * wy + qBlue(br) * wx * wy);
+
+ // ### endianness
+ //we're actually off by one in 255 here! (254 instead of 255)
+ int foo = r >> 24;
+ foo = g >> 24;
+ foo = b >> 24;
+ newImageData[(y * newWidth * 3) + (x * 3) + 0] = (r >> 24);
+ newImageData[(y * newWidth * 3) + (x * 3) + 1] = (g >> 24);
+ newImageData[(y * newWidth * 3) + (x * 3) + 2] = (b >> 24);
+// *(scanline++) = qRgb(r >> 24, g >> 24, b >> 24); //we're actually off by one in 255 here
+
+ x2 += basis_xx;
+
+ if (x2 > max_x2)
+ {
+ x++;
+ break;
+ }
+
+ }
+
+// while (x < w) //fill the right of each scanline with the background colour
+// {
+// *(scanline++) = background; //qRgb(255,0,0);
+// x++;
+// }
+ }
+
+// for (;;) //fill the bottom of the target pixmap with the background color
+// {
+// y2 = basis_oy + y * basis_yy;
+//
+// if (y >= h)
+// break;
+//
+// scanline = (QRgb*) dst.scanLine(y);
+// for (int i = 0; i < w; i++)
+// *(scanline++) = background; //qRgb(255,255,0);
+// y++;
+// }
+
+ // ### keep orig image somewhere but delete all scaled images!
+ ImlibImage *newIm = Imlib_create_image_from_data( myId, newImageData, NULL,
+ newWidth, newHeight );
+ delete[] newImageData;
+
+ if ( newIm )
+ {
+ myScaledIm = newIm;
+ myIsDirty = true;
+ myWidth = newWidth;
+ myHeight = newHeight;
+ }
+
+ return myIm != 0L;
+// return dst.copy();
+}
+#endif
+
+#include "kuickimage.moc"
diff --git a/kuickshow/src/kuickimage.h b/kuickshow/src/kuickimage.h
new file mode 100644
index 00000000..745facf4
--- /dev/null
+++ b/kuickshow/src/kuickimage.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+** $Id: .emacs,v 1.3 2002/02/20 15:06:53 gis Exp $
+**
+** Created : 2002
+**
+** Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@kde.org>
+**
+****************************************************************************/
+
+#ifndef KUICKIMAGE_H
+#define KUICKIMAGE_H
+
+#include <qimage.h>
+#include <qobject.h>
+
+#include <kurl.h>
+
+#include "kuickdata.h"
+#include "kuickfile.h"
+
+// #include those AFTER Qt-includes!
+#include <Imlib.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+// #include <X11/extensions/shape.h>
+
+
+class KuickImage : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum ResizeMode { FAST, SMOOTH };
+
+ KuickImage( const KuickFile * file, ImlibImage *im, ImlibData *id );
+ ~KuickImage();
+
+ int width() const { return myWidth; }
+ int height() const { return myHeight; }
+ int originalWidth() const { return myOrigWidth; }
+ int originalHeight() const { return myOrigHeight; }
+
+ void resize( int width, int height, KuickImage::ResizeMode mode );
+ void restoreOriginalSize();
+ void rotate( Rotation rot );
+ bool rotateAbs( Rotation rot );
+ void flip( FlipMode flipMode );
+ bool flipAbs( int mode );
+ ImlibImage * imlibImage() const { return myIm; }
+ Pixmap& pixmap();
+ void renderPixmap();
+// const QString& filename() const { return myFilename;}
+ const KuickFile& file() const { return *myFile; }
+ const KURL& url() const { return myFile->url(); }
+
+ void setDirty( bool d ) { myIsDirty = d; }
+ bool isDirty() const { return myIsDirty; }
+ Rotation absRotation() const { return myRotation; }
+ FlipMode flipMode() const { return myFlipMode; }
+
+ static ImlibImage * toImage( ImlibData *id, QImage& image );
+
+private:
+ void fastResize( int newWidth, int newHeight );
+ bool smoothResize( int width, int height );
+ /**
+ * Note: caller must delete it!
+ */
+ QImage * newQImage() const;
+
+ const KuickFile * myFile;
+
+ int myWidth;
+ int myHeight;
+ ImlibImage * myOrigIm;
+ ImlibImage * myIm;
+ ImlibData * myId;
+ Pixmap myPixmap;
+ bool myIsDirty;
+
+ int myOrigWidth;
+ int myOrigHeight;
+ Rotation myRotation;
+ FlipMode myFlipMode;
+
+signals:
+ void startRendering();
+ void stoppedRendering();
+};
+
+
+#endif // KUICKIMAGE_H
diff --git a/kuickshow/src/kuickshow.cpp b/kuickshow/src/kuickshow.cpp
new file mode 100644
index 00000000..7e8718fb
--- /dev/null
+++ b/kuickshow/src/kuickshow.cpp
@@ -0,0 +1,1443 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998-2006 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <stdio.h>
+#include <assert.h>
+
+#include <qdir.h>
+#include <qdesktopwidget.h>
+#include <qdialog.h>
+#include <qglobal.h>
+#include <qkeycode.h>
+#include <qlayout.h>
+#include <qsize.h>
+#include <qstring.h>
+
+#include <kaboutdata.h>
+#include <kaccel.h>
+#include <kaction.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kconfig.h>
+#include <kcursor.h>
+#include <kdeversion.h>
+#include <kfiledialog.h>
+#include <kfilemetainfo.h>
+#include <kglobal.h>
+#include <khelpmenu.h>
+#include <kiconloader.h>
+#include <kio/netaccess.h>
+#include <klocale.h>
+#include <kmenubar.h>
+#include <kmessagebox.h>
+#include <kpopupmenu.h>
+#include <kprotocolinfo.h>
+#include <kpropertiesdialog.h>
+#include <kprotocolinfo.h>
+#include <kstatusbar.h>
+#include <kstdaction.h>
+#include <kstandarddirs.h>
+#include <kstartupinfo.h>
+#include <ktoolbar.h>
+#include <kurlcombobox.h>
+#include <kurlcompletion.h>
+#include <kurldrag.h>
+#include <kwin.h>
+#include <kstdguiitem.h>
+
+#include <kdebug.h>
+
+#include "aboutwidget.h"
+#include "filewidget.h"
+#include "filecache.h"
+#include "imdata.h"
+#include "imagewindow.h"
+#include "imlibwidget.h"
+#include "kuick.h"
+#include "kuickfile.h"
+
+#ifdef index
+#undef index
+#endif
+
+#include "kuickconfigdlg.h"
+#include "kuickdata.h"
+#include "kuickshow.h"
+#include "version.h"
+
+#ifdef KeyPress
+#undef KeyPress
+#endif
+
+KuickData* kdata;
+
+static const int URL_ITEM = 0;
+static const int META_ITEM = 1;
+
+QValueList<ImageWindow*> KuickShow::s_viewers;
+
+KuickShow::KuickShow( const char *name )
+ : KMainWindow( 0L, name ),
+ m_slideshowCycle( 1 ),
+ fileWidget( 0L ),
+ dialog( 0L ),
+ id( 0L ),
+ m_viewer( 0L ),
+ oneWindowAction( 0L ),
+ m_accel( 0L ),
+ m_delayedRepeatItem( 0L ),
+ m_slideShowStopped(false)
+{
+ aboutWidget = 0L;
+ kdata = new KuickData;
+ kdata->load();
+
+ initImlib();
+ resize( 400, 500 );
+
+ m_slideTimer = new QTimer( this );
+ connect( m_slideTimer, SIGNAL( timeout() ), SLOT( nextSlide() ));
+
+
+ KConfig *kc = KGlobal::config();
+
+ bool isDir = false; // true if we get a directory on the commandline
+
+ // parse commandline options
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ // files to display
+ // either a directory to display, an absolute path, a relative path, or a URL
+ KURL startDir;
+ startDir.setPath( QDir::currentDirPath() + '/' );
+
+ int numArgs = args->count();
+ if ( numArgs >= 10 )
+ {
+ // Even though the 1st i18n string will never be used, it needs to exist for plural handling - mhunter
+ if ( KMessageBox::warningYesNo(
+ this,
+ i18n("Do you really want to display this 1 image at the same time? This might be quite resource intensive and could overload your computer.<br>If you choose %1, only the first image will be shown.",
+ "Do you really want to display these %n images at the same time? This might be quite resource intensive and could overload your computer.<br>If you choose %1, only the first image will be shown.", numArgs).arg(KStdGuiItem::no().plainText()),
+ i18n("Display Multiple Images?"))
+ != KMessageBox::Yes )
+ {
+ numArgs = 1;
+ }
+ }
+
+ for ( int i = 0; i < numArgs; i++ ) {
+ KURL url = args->url( i );
+ KFileItem item( KFileItem::Unknown, KFileItem::Unknown, url, false );
+
+ // for remote URLs, we don't know if it's a file or directory, but
+ // FileWidget::isImage() should correct in most cases.
+ // For non-local non-images, we just assume directory.
+
+ if ( FileWidget::isImage( &item ) )
+ {
+ showImage( &item, true, false, true ); // show in new window, not fullscreen-forced and move to 0,0
+// showImage( &item, true, false, false ); // show in new window, not fullscreen-forced and not moving to 0,0
+ }
+ else if ( item.isDir() )
+ {
+ startDir = url;
+ isDir = true;
+ }
+
+ // need to check remote files
+ else if ( !url.isLocalFile() )
+ {
+ KMimeType::Ptr mime = KMimeType::findByURL( url );
+ QString name = mime->name();
+ if ( name == "application/octet-stream" ) // unknown -> stat()
+ name = KIO::NetAccess::mimetype( url, this );
+
+ // text/* is a hack for bugs.kde.org-attached-images urls.
+ // The real problem here is that NetAccess::mimetype does a HTTP HEAD, which doesn't
+ // always return the right mimetype. The rest of KDE start a get() instead....
+ if ( name.startsWith( "image/" ) || name.startsWith( "text/" ) )
+ {
+ FileWidget::setImage( item, true );
+ showImage( &item, true, false, true );
+ }
+ else // assume directory, KDirLister will tell us if we can't list
+ {
+ startDir = url;
+ isDir = true;
+ }
+ }
+ // else // we don't handle local non-images
+ }
+
+ if ( (kdata->startInLastDir && args->count() == 0) || args->isSet( "lastfolder" )) {
+ kc->setGroup( "SessionSettings");
+ startDir = kc->readPathEntry( "CurrentDirectory", startDir.url() );
+ }
+
+ if ( s_viewers.isEmpty() || isDir ) {
+ initGUI( startDir );
+ if (!kapp->isRestored()) // during session management, readProperties() will show()
+ show();
+ }
+
+ else { // don't show browser, when image on commandline
+ hide();
+ KStartupInfo::appStarted();
+ }
+}
+
+
+KuickShow::~KuickShow()
+{
+ saveSettings();
+
+ if ( m_viewer )
+ m_viewer->close( true );
+
+ FileCache::shutdown();
+ free( id );
+ kapp->quit();
+
+ delete kdata;
+}
+
+// TODO convert to use xmlui file
+void KuickShow::initGUI( const KURL& startDir )
+{
+ KURL startURL( startDir );
+ if ( !KProtocolInfo::supportsListing( startURL ) )
+ startURL = KURL();
+
+ fileWidget = new FileWidget( startURL, this, "MainWidget" );
+ setFocusProxy( fileWidget );
+
+ KActionCollection *coll = fileWidget->actionCollection();
+
+ redirectDeleteAndTrashActions(coll);
+
+ connect( fileWidget, SIGNAL( fileSelected( const KFileItem * ) ),
+ this, SLOT( slotSelected( const KFileItem * ) ));
+
+ connect( fileWidget, SIGNAL( fileHighlighted( const KFileItem * )),
+ this, SLOT( slotHighlighted( const KFileItem * ) ));
+
+ connect( fileWidget, SIGNAL( urlEntered( const KURL& )),
+ this, SLOT( dirSelected( const KURL& )) );
+
+
+ fileWidget->setAcceptDrops(true);
+ connect( fileWidget, SIGNAL( dropped( const KFileItem *, QDropEvent *, const KURL::List & )),
+ this, SLOT( slotDropped( const KFileItem *, QDropEvent *, const KURL::List &)) );
+
+ // setup actions
+ KAction *open = KStdAction::open( this, SLOT( slotOpenURL() ),
+ coll, "openURL" );
+
+ KAction *print = KStdAction::print( this, SLOT( slotPrint() ),
+ coll, "kuick_print" );
+ print->setText( i18n("Print Image...") );
+
+ KAction *configure = new KAction( i18n("Configure %1...").arg( KGlobal::instance()->aboutData()->programName() ), "configure",
+ KShortcut(),
+ this, SLOT( configuration() ),
+ coll, "kuick_configure" );
+ KAction *slide = new KAction( i18n("Start Slideshow" ), "ksslide",
+ KShortcut( Key_F2 ),
+ this, SLOT( startSlideShow() ),
+ coll, "kuick_slideshow" );
+ KAction *about = new KAction( i18n( "About KuickShow" ), "about",
+ KShortcut(),
+ this, SLOT( about() ), coll, "about" );
+
+ oneWindowAction = new KToggleAction( i18n("Open Only One Image Window"),
+ "window_new",
+ KShortcut( CTRL+Key_N ), coll,
+ "kuick_one window" );
+
+ m_toggleBrowserAction = new KToggleAction( i18n("Show File Browser"), KShortcut( Key_Space ), coll, "toggleBrowser" );
+ m_toggleBrowserAction->setCheckedState(i18n("Hide File Browser"));
+ connect( m_toggleBrowserAction, SIGNAL( toggled( bool ) ),
+ SLOT( toggleBrowser() ));
+
+ KAction *showInOther = new KAction( i18n("Show Image"), KShortcut(),
+ this, SLOT( slotShowInOtherWindow() ),
+ coll, "kuick_showInOtherWindow" );
+ KAction *showInSame = new KAction( i18n("Show Image in Active Window"),
+ KShortcut(),
+ this, SLOT( slotShowInSameWindow() ),
+ coll, "kuick_showInSameWindow" );
+ KAction *showFullscreen = new KAction( i18n("Show Image in Fullscreen Mode"),
+ KShortcut(), this, SLOT( slotShowFullscreen() ),
+ coll, "kuick_showFullscreen" );
+
+ KAction *quit = KStdAction::quit( this, SLOT(slotQuit()), coll, "quit");
+
+ // remove QString::null parameter -- ellis
+ coll->readShortcutSettings( QString::null );
+ m_accel = coll->accel();
+
+ // menubar
+ KMenuBar *mBar = menuBar();
+ QPopupMenu *fileMenu = new QPopupMenu( mBar, "file" );
+ open->plug( fileMenu );
+ showInOther->plug( fileMenu );
+ showInSame->plug( fileMenu );
+ showFullscreen->plug( fileMenu );
+ fileMenu->insertSeparator();
+ slide->plug( fileMenu );
+ print->plug( fileMenu );
+ fileMenu->insertSeparator();
+ quit->plug( fileMenu );
+
+ QPopupMenu *editMenu = new QPopupMenu( mBar, "edit" );
+ coll->action("mkdir")->plug( editMenu );
+ coll->action("delete")->plug( editMenu );
+ editMenu->insertSeparator();
+ coll->action("properties")->plug( editMenu );
+
+
+ // remove the Sorting submenu (and the separator below)
+ // from the main contextmenu
+ KActionMenu *sortingMenu = static_cast<KActionMenu*>( coll->action("sorting menu"));
+ KActionMenu *mainActionMenu = static_cast<KActionMenu*>( coll->action("popupMenu"));
+ QPopupMenu *mainPopup = mainActionMenu->popupMenu();
+ int sortingIndex = mainPopup->indexOf( sortingMenu->itemId( 0 ) );
+ int separatorId = mainPopup->idAt( sortingIndex + 1 );
+ QMenuItem *separatorItem = mainPopup->findItem( separatorId );
+ if ( separatorItem && separatorItem->isSeparator() )
+ mainPopup->removeItem( separatorId );
+ mainActionMenu->remove( sortingMenu );
+
+ // add the sorting menu and a separator into the View menu
+ KActionMenu *viewActionMenu = static_cast<KActionMenu*>( coll->action("view menu"));
+ viewActionMenu->popupMenu()->insertSeparator( 0 );
+ sortingMenu->plug( viewActionMenu->popupMenu(), 0 ); // on top of the menu
+
+
+ QPopupMenu *settingsMenu = new QPopupMenu( mBar, "settings" );
+ configure->plug( settingsMenu );
+
+ mBar->insertItem( i18n("&File"), fileMenu );
+ mBar->insertItem( i18n("&Edit"), editMenu );
+ viewActionMenu->plug( mBar );
+ mBar->insertItem( i18n("&Settings"), settingsMenu );
+
+ // toolbar
+ KToolBar *tBar = toolBar();
+ tBar->setText( i18n( "Main Toolbar" ) );
+
+ coll->action("up")->plug( tBar );
+ coll->action("back")->plug( tBar );
+ coll->action("forward")->plug( tBar );
+ coll->action("home")->plug( tBar );
+ coll->action("reload")->plug( tBar );
+
+ tBar->insertSeparator();
+
+ coll->action( "short view" )->plug( tBar );
+ coll->action( "detailed view" )->plug( tBar );
+ coll->action( "preview")->plug( tBar );
+
+ tBar->insertSeparator();
+ configure->plug( tBar );
+ slide->plug( tBar );
+ tBar->insertSeparator();
+ oneWindowAction->plug( tBar );
+ print->plug( tBar );
+ tBar->insertSeparator();
+ about->plug( tBar );
+
+ QPopupMenu *help = helpMenu( QString::null, false );
+ mBar->insertItem( KStdGuiItem::help().text() , help );
+
+
+ KStatusBar* sBar = statusBar();
+ sBar->insertItem( " ", URL_ITEM, 10 );
+ sBar->insertItem( " ", META_ITEM, 2 );
+ sBar->setItemAlignment(URL_ITEM, QLabel::AlignVCenter | QLabel::AlignLeft);
+
+ fileWidget->setFocus();
+
+ KConfig *kc = KGlobal::config();
+ kc->setGroup("SessionSettings");
+ bool oneWindow = kc->readBoolEntry("OpenImagesInActiveWindow", true );
+ oneWindowAction->setChecked( oneWindow );
+
+ tBar->show();
+
+ // Address box in address tool bar
+ KToolBar *addressToolBar = toolBar( "address_bar" );
+ const int ID_ADDRESSBAR = 1;
+
+ cmbPath = new KURLComboBox( KURLComboBox::Directories,
+ true, addressToolBar, "address_combo_box" );
+ KURLCompletion *cmpl = new KURLCompletion( KURLCompletion::DirCompletion );
+ cmbPath->setCompletionObject( cmpl );
+ cmbPath->setAutoDeleteCompletionObject( true );
+
+ addressToolBar->insertWidget( ID_ADDRESSBAR, 1, cmbPath);
+ addressToolBar->setItemAutoSized( ID_ADDRESSBAR );
+
+ connect( cmbPath, SIGNAL( urlActivated( const KURL& )),
+ this, SLOT( slotSetURL( const KURL& )));
+ connect( cmbPath, SIGNAL( returnPressed()),
+ this, SLOT( slotURLComboReturnPressed()));
+
+
+ fileWidget->initActions();
+ fileWidget->clearHistory();
+ dirSelected( fileWidget->url() );
+
+ setCentralWidget( fileWidget );
+ setupGUI( KMainWindow::Save );
+
+ coll->action( "reload" )->setShortcut( KStdAccel::reload() );
+ coll->action( "short view" )->setShortcut(Key_F6);
+ coll->action( "detailed view" )->setShortcut(Key_F7);
+ coll->action( "show hidden" )->setShortcut(Key_F8);
+ coll->action( "mkdir" )->setShortcut(Key_F10);
+ coll->action( "preview" )->setShortcut(Key_F11);
+ coll->action( "separate dirs" )->setShortcut(Key_F12);
+}
+
+void KuickShow::redirectDeleteAndTrashActions(KActionCollection *coll)
+{
+ KAction *action = coll->action("delete");
+ if (action)
+ {
+ action->disconnect(fileWidget);
+ connect(action, SIGNAL(activated()), this, SLOT(slotDeleteCurrentImage()));
+ }
+
+ action = coll->action("trash");
+ if (action)
+ {
+ action->disconnect(fileWidget);
+ connect(action, SIGNAL(activated()), this, SLOT(slotTrashCurrentImage()));
+ }
+}
+
+void KuickShow::slotSetURL( const KURL& url )
+{
+ fileWidget->setURL( url, true );
+}
+
+void KuickShow::slotURLComboReturnPressed()
+{
+ KURL where = KURL::fromPathOrURL( cmbPath->currentText() );
+ slotSetURL( where );
+}
+
+void KuickShow::viewerDeleted()
+{
+ ImageWindow *viewer = (ImageWindow*) sender();
+ s_viewers.remove( viewer );
+ if ( viewer == m_viewer )
+ m_viewer = 0L;
+
+ if ( !haveBrowser() && s_viewers.isEmpty() ) {
+ saveSettings();
+ FileCache::shutdown();
+ ::exit(0);
+ }
+
+ else if ( haveBrowser() ) {
+ setActiveWindow();
+ // This setFocus() call causes problems in the combiview (always the
+ // directory view on the left gets the focus, which is not desired)
+ // fileWidget->setFocus();
+ }
+
+ if ( fileWidget )
+ // maybe a slideshow was stopped --> enable the action again
+ fileWidget->actionCollection()->action("kuick_slideshow")->setEnabled( true );
+
+ m_slideTimer->stop();
+}
+
+
+void KuickShow::slotHighlighted( const KFileItem *fi )
+{
+ KFileItem *item = const_cast<KFileItem *>( fi );
+ statusBar()->changeItem( item->getStatusBarInfo(), URL_ITEM );
+ bool image = FileWidget::isImage( fi );
+
+ QString meta;
+ if ( image )
+ {
+ KFileMetaInfo info = item->metaInfo();
+ if ( info.isValid() )
+ {
+ meta = info.item( KFileMimeTypeInfo::Size ).string();
+ KFileMetaInfoGroup group = info.group( "Technical" );
+ if ( group.isValid() )
+ {
+ QString bpp = group.item( "BitDepth" ).string();
+ if ( !bpp.isEmpty() )
+ meta.append( ", " ).append( bpp );
+ }
+ }
+ }
+ statusBar()->changeItem( meta, META_ITEM );
+
+ fileWidget->actionCollection()->action("kuick_print")->setEnabled( image );
+ fileWidget->actionCollection()->action("kuick_showInSameWindow")->setEnabled( image );
+ fileWidget->actionCollection()->action("kuick_showInOtherWindow")->setEnabled( image );
+ fileWidget->actionCollection()->action("kuick_showFullscreen")->setEnabled( image );
+}
+
+void KuickShow::dirSelected( const KURL& url )
+{
+ if ( url.isLocalFile() )
+ setCaption( url.path() );
+ else
+ setCaption( url.prettyURL() );
+
+ cmbPath->setURL( url );
+ statusBar()->changeItem( url.prettyURL(), URL_ITEM );
+}
+
+void KuickShow::slotSelected( const KFileItem *item )
+{
+ showImage( item, !oneWindowAction->isChecked() );
+}
+
+// downloads item if necessary
+void KuickShow::showFileItem( ImageWindow * /*view*/,
+ const KFileItem * /*item*/ )
+{
+
+}
+
+bool KuickShow::showImage( const KFileItem *fi,
+ bool newWindow, bool fullscreen, bool moveToTopLeft )
+{
+ newWindow |= !m_viewer;
+ fullscreen |= (newWindow && kdata->fullScreen);
+ if ( FileWidget::isImage( fi ) ) {
+
+ if ( newWindow ) {
+ m_viewer = new ImageWindow( kdata->idata, id, 0L, "image window" );
+ m_viewer->setFullscreen( fullscreen );
+ s_viewers.append( m_viewer );
+
+ connect( m_viewer, SIGNAL( destroyed() ), SLOT( viewerDeleted() ));
+ connect( m_viewer, SIGNAL( sigFocusWindow( ImageWindow *) ),
+ this, SLOT( slotSetActiveViewer( ImageWindow * ) ));
+ connect( m_viewer, SIGNAL( sigImageError(const KuickFile *, const QString& ) ),
+ this, SLOT( messageCantLoadImage(const KuickFile *, const QString &) ));
+ connect( m_viewer, SIGNAL( requestImage( ImageWindow *, int )),
+ this, SLOT( slotAdvanceImage( ImageWindow *, int )));
+ connect( m_viewer, SIGNAL( pauseSlideShowSignal() ),
+ this, SLOT( pauseSlideShow() ) );
+ connect( m_viewer, SIGNAL (deleteImage (ImageWindow *)),
+ this, SLOT (slotDeleteCurrentImage (ImageWindow *)));
+ connect( m_viewer, SIGNAL (trashImage (ImageWindow *)),
+ this, SLOT (slotTrashCurrentImage (ImageWindow *)));
+ if ( s_viewers.count() == 1 && moveToTopLeft ) {
+ // we have to move to 0x0 before showing _and_
+ // after showing, otherwise we get some bogus geometry()
+ m_viewer->move( Kuick::workArea().topLeft() );
+ }
+
+ m_viewer->installEventFilter( this );
+ }
+
+ // for some strange reason, m_viewer sometimes changes during the
+ // next few lines of code, so as a workaround, we use safeViewer here.
+ // This happens when calling KuickShow with two or more remote-url
+ // arguments on the commandline, where the first one is loaded properly
+ // and the second isn't (e.g. because it is a pdf or something else,
+ // Imlib can't load).
+ ImageWindow *safeViewer = m_viewer;
+
+// file->waitForDownload( this );
+// QString filename;
+// KIO::NetAccess::download(fi->url(), filename, this);
+
+ if ( !safeViewer->showNextImage( fi->url() ) ) {
+ m_viewer = safeViewer;
+ safeViewer->close( true ); // couldn't load image, close window
+ }
+ else {
+// safeViewer->setFullscreen( fullscreen );
+
+ if ( newWindow ) {
+// safeViewer->show();
+
+ if ( !fullscreen && s_viewers.count() == 1 && moveToTopLeft ) {
+ // the WM might have moved us after showing -> strike back!
+ // move the first image to 0x0 workarea coord
+ safeViewer->move( Kuick::workArea().topLeft() );
+ }
+ }
+
+ if ( kdata->preloadImage && fileWidget ) {
+ KFileItem *item = 0L; // don't move cursor
+ item = fileWidget->getItem( FileWidget::Next, true );
+ if ( item )
+ safeViewer->cacheImage( item->url() );
+ }
+
+ m_viewer = safeViewer;
+ return true;
+ } // m_viewer created successfully
+ } // isImage
+
+ return false;
+}
+
+void KuickShow::slotDeleteCurrentImage()
+{
+ performDeleteCurrentImage(fileWidget);
+}
+
+void KuickShow::slotTrashCurrentImage()
+{
+ performTrashCurrentImage(fileWidget);
+}
+
+void KuickShow::slotDeleteCurrentImage(ImageWindow *viewer)
+{
+ if (!fileWidget) {
+ delayAction(new DelayedRepeatEvent(viewer, DelayedRepeatEvent::DeleteCurrentFile, 0L));
+ return;
+ }
+ performDeleteCurrentImage(viewer);
+}
+
+void KuickShow::slotTrashCurrentImage(ImageWindow *viewer)
+{
+ if (!fileWidget) {
+ delayAction(new DelayedRepeatEvent(viewer, DelayedRepeatEvent::TrashCurrentFile, 0L));
+ return;
+ }
+ performTrashCurrentImage(viewer);
+}
+
+void KuickShow::performDeleteCurrentImage(QWidget *parent)
+{
+ assert(fileWidget != 0L);
+
+ KFileItemList list;
+ KFileItem *item = fileWidget->getCurrentItem(false);
+ list.append (item);
+
+ if (KMessageBox::warningContinueCancel(
+ parent,
+ i18n("<qt>Do you really want to delete\n <b>'%1'</b>?</qt>").arg(item->url().pathOrURL()),
+ i18n("Delete File"),
+ KStdGuiItem::del(),
+ "Kuick_delete_current_image")
+ != KMessageBox::Continue)
+ {
+ return;
+ }
+
+ tryShowNextImage();
+ fileWidget->del(list, false, false);
+}
+
+void KuickShow::performTrashCurrentImage(QWidget *parent)
+{
+ assert(fileWidget != 0L);
+
+ KFileItemList list;
+ KFileItem *item = fileWidget->getCurrentItem(false);
+ if (!item) return;
+
+ list.append (item);
+
+ if (KMessageBox::warningContinueCancel(
+ parent,
+ i18n("<qt>Do you really want to trash\n <b>'%1'</b>?</qt>").arg(item->url().pathOrURL()),
+ i18n("Trash File"),
+ KGuiItem(i18n("to trash", "&Trash"),"edittrash"),
+ "Kuick_trash_current_image")
+ != KMessageBox::Continue)
+ {
+ return;
+ }
+
+ tryShowNextImage();
+ fileWidget->trash(list, parent, false, false);
+}
+
+void KuickShow::tryShowNextImage()
+{
+ // move to next file item even if we have no viewer
+ KFileItem *next = fileWidget->getNext(true);
+ if (!next)
+ next = fileWidget->getPrevious(true);
+
+ // ### why is this necessary at all? Why does KDirOperator suddenly re-read the
+ // entire directory after a file was deleted/trashed!? (KDirNotify is the reason)
+ if (!m_viewer)
+ return;
+
+ if (next)
+ showImage(next, false);
+ else
+ {
+ if (!haveBrowser())
+ {
+ // ### when simply calling toggleBrowser(), this main window is completely messed up
+ QTimer::singleShot(0, this, SLOT(toggleBrowser()));
+ }
+ m_viewer->deleteLater();
+ }
+}
+
+void KuickShow::startSlideShow()
+{
+ KFileItem *item = kdata->slideshowStartAtFirst ?
+ fileWidget->gotoFirstImage() :
+ fileWidget->getCurrentItem(false);
+
+ if ( item ) {
+ m_slideshowCycle = 1;
+ fileWidget->actionCollection()->action("kuick_slideshow")->setEnabled( false );
+ showImage( item, !oneWindowAction->isChecked(),
+ kdata->slideshowFullscreen );
+ if(kdata->slideDelay)
+ m_slideTimer->start( kdata->slideDelay );
+ }
+}
+
+void KuickShow::pauseSlideShow()
+{
+ if(m_slideShowStopped) {
+ if(kdata->slideDelay)
+ m_slideTimer->start( kdata->slideDelay );
+ m_slideShowStopped = false;
+ }
+ else {
+ m_slideTimer->stop();
+ m_slideShowStopped = true;
+ }
+}
+
+void KuickShow::nextSlide()
+{
+ if ( !m_viewer ) {
+ m_slideshowCycle = 1;
+ fileWidget->actionCollection()->action("kuick_slideshow")->setEnabled( true );
+ return;
+ }
+
+ KFileItem *item = fileWidget->getNext( true );
+ if ( !item ) { // last image
+ if ( m_slideshowCycle < kdata->slideshowCycles
+ || kdata->slideshowCycles == 0 ) {
+ item = fileWidget->gotoFirstImage();
+ if ( item ) {
+ nextSlide( item );
+ m_slideshowCycle++;
+ return;
+ }
+ }
+
+ m_viewer->close( true );
+ fileWidget->actionCollection()->action("kuick_slideshow")->setEnabled( true );
+ return;
+ }
+
+ nextSlide( item );
+}
+
+void KuickShow::nextSlide( KFileItem *item )
+{
+ m_viewer->showNextImage( item->url() );
+ if(kdata->slideDelay)
+ m_slideTimer->start( kdata->slideDelay );
+}
+
+
+// prints the selected files in the filebrowser
+void KuickShow::slotPrint()
+{
+ const KFileItemList *items = fileWidget->selectedItems();
+ if ( !items )
+ return;
+
+ KFileItemListIterator it( *items );
+
+ // don't show the image, just print
+ ImageWindow *iw = new ImageWindow( 0, id, this, "printing image" );
+ KFileItem *item;
+ while ( (item = it.current()) ) {
+ if (FileWidget::isImage( item ) && iw->loadImage( item->url() ))
+ iw->printImage();
+ ++it;
+ }
+
+ iw->close( true );
+}
+
+void KuickShow::slotShowInOtherWindow()
+{
+ showImage( fileWidget->getCurrentItem( false ), true );
+}
+
+void KuickShow::slotShowInSameWindow()
+{
+ showImage( fileWidget->getCurrentItem( false ), false );
+}
+
+void KuickShow::slotShowFullscreen()
+{
+ showImage( fileWidget->getCurrentItem( false ), false, true );
+}
+
+void KuickShow::slotDropped( const KFileItem *, QDropEvent *, const KURL::List &urls)
+{
+ KURL::List::ConstIterator it = urls.begin();
+ for ( ; it != urls.end(); ++it )
+ {
+ KFileItem item( KFileItem::Unknown, KFileItem::Unknown, *it );
+ if ( FileWidget::isImage( &item ) )
+ showImage( &item, true );
+ else
+ fileWidget->setURL( *it, true );
+ }
+}
+
+// try to init the WM border as it is 0,0 when the window is not shown yet.
+void KuickShow::show()
+{
+ KMainWindow::show();
+ (void) Kuick::frameSize( winId() );
+}
+
+void KuickShow::slotAdvanceImage( ImageWindow *view, int steps )
+{
+ KFileItem *item = 0L; // to be shown
+ KFileItem *item_next = 0L; // to be cached
+
+ if ( steps == 0 )
+ return;
+
+ // the viewer might not be available yet. Factor this out somewhen.
+ if ( !fileWidget ) {
+ if ( m_delayedRepeatItem )
+ return;
+
+ delayAction(new DelayedRepeatEvent( view, DelayedRepeatEvent::AdvanceViewer, new int(steps) ));
+ return;
+ }
+
+ if ( steps > 0 ) {
+ for ( int i = 0; i < steps; i++ )
+ item = fileWidget->getNext( true );
+ item_next = fileWidget->getNext( false );
+ }
+
+ else if ( steps < 0 ) {
+ for ( int i = steps; i < 0; i++ )
+ item = fileWidget->getPrevious( true );
+ item_next = fileWidget->getPrevious( false );
+ }
+
+ if ( FileWidget::isImage( item ) ) {
+// QString filename;
+// KIO::NetAccess::download(item->url(), filename, this);
+ view->showNextImage( item->url() );
+ if (m_slideTimer->isActive() && kdata->slideDelay)
+ m_slideTimer->start( kdata->slideDelay );
+
+ if ( kdata->preloadImage && item_next ) { // preload next image
+ if ( FileWidget::isImage( item_next ) )
+ view->cacheImage( item_next->url() );
+ }
+
+ }
+}
+
+bool KuickShow::eventFilter( QObject *o, QEvent *e )
+{
+ if ( m_delayedRepeatItem ) // we probably need to install an eventFilter over
+ {
+ return true; // kapp, to make it really safe
+ }
+
+ bool ret = false;
+ int eventType = e->type();
+ QKeyEvent *k = 0L;
+ if ( eventType == QEvent::KeyPress )
+ k = static_cast<QKeyEvent *>( e );
+
+ if ( k ) {
+ if ( KStdAccel::quit().contains( KKey( k ) ) ) {
+ saveSettings();
+ deleteAllViewers();
+ FileCache::shutdown();
+ ::exit(0);
+ }
+ else if ( KStdAccel::help().contains( KKey( k ) ) ) {
+ appHelpActivated();
+ return true;
+ }
+ }
+
+
+ ImageWindow *window = dynamic_cast<ImageWindow*>( o );
+
+ if ( window ) {
+ // The XWindow used to display Imlib's image is being resized when
+ // switching images, causing enter- and leaveevents for this
+ // ImageWindow, leading to the cursor being unhidden. So we simply
+ // don't pass those events to KCursor to prevent that.
+ if ( eventType != QEvent::Leave && eventType != QEvent::Enter )
+ KCursor::autoHideEventFilter( o, e );
+
+ m_viewer = window;
+ QString img;
+ KFileItem *item = 0L; // the image to be shown
+ KFileItem *item_next = 0L; // the image to be cached
+
+ if ( k ) { // keypress
+ ret = true;
+ int key = k->key();
+
+ // Key_Shift shouldn't load the browser in nobrowser mode, it
+ // is used for zooming in the imagewindow
+ // Key_Alt shouldn't either - otherwise Alt+F4 doesn't work, the
+ // F4 gets eaten (by NetAccess' modal dialog maybe?)
+
+ if ( !fileWidget )
+ {
+ if ( key != Key_Escape && key != Key_Shift && key != Key_Alt )
+ {
+ KuickFile *file = m_viewer->currentFile();
+// QFileInfo fi( m_viewer->filename() );
+// start.setPath( fi.dirPath( true ) );
+ initGUI( file->url().upURL() );
+
+ // the fileBrowser will list the start-directory
+ // asynchronously so we can't immediately continue. There
+ // is no current-item and no next-item (actually no item
+ // at all). So we tell the browser the initial
+ // current-item and wait for it to tell us when it's ready.
+ // Then we will replay this KeyEvent.
+ delayedRepeatEvent( m_viewer, k );
+
+ // OK, once again, we have a problem with the now async and
+ // sync KDirLister :( If the startDir is already cached by
+ // KDirLister, we won't ever get that finished() signal
+ // because it is emitted before we can connect(). So if
+ // our dirlister has a rootFileItem, we assume the
+ // directory is read already and simply call
+ // slotReplayEvent() without the need for the finished()
+ // signal.
+
+ // see slotAdvanceImage() for similar code
+ if ( fileWidget->dirLister()->isFinished() )
+ {
+ if ( fileWidget->dirLister()->rootItem() )
+ {
+ fileWidget->setCurrentItem( file->url().fileName() );
+ QTimer::singleShot( 0, this, SLOT( slotReplayEvent()));
+ }
+ else // finished, but no root-item -- probably an error, kill repeat-item!
+ {
+ abortDelayedEvent();
+ }
+ }
+ else // not finished yet
+ {
+ fileWidget->setInitialItem( file->url().fileName() );
+ connect( fileWidget, SIGNAL( finished() ),
+ SLOT( slotReplayEvent() ));
+ }
+
+ return true;
+ }
+
+ return KMainWindow::eventFilter( o, e );
+ }
+
+ // we definitely have a fileWidget here!
+
+ KKey kkey( k );
+ if ( key == Key_Home || KStdAccel::home().contains( kkey ) )
+ {
+ item = fileWidget->gotoFirstImage();
+ item_next = fileWidget->getNext( false );
+ }
+
+ else if ( key == Key_End || KStdAccel::end().contains( kkey ) )
+ {
+ item = fileWidget->gotoLastImage();
+ item_next = fileWidget->getPrevious( false );
+ }
+
+ else if ( fileWidget->actionCollection()->action("delete")->shortcut().contains( key ))
+ {
+ kdDebug() << "WOW, deletion happens here!" << endl;
+// KFileItem *cur = fileWidget->getCurrentItem( false );
+ (void) fileWidget->getCurrentItem( false );
+ item = fileWidget->getNext( false ); // don't move
+ if ( !item )
+ item = fileWidget->getPrevious( false );
+ KFileItem it( KFileItem::Unknown, KFileItem::Unknown,
+ m_viewer->url() );
+ KFileItemList list;
+ list.append( &it );
+ if ( fileWidget->del(list, window,
+ (k->state() & ShiftButton) == 0) == 0L )
+ return true; // aborted deletion
+
+ // ### check failure asynchronously and restore old item?
+ fileWidget->setCurrentItem( item );
+ }
+
+ else if ( m_toggleBrowserAction->shortcut().contains( key ) )
+ {
+ toggleBrowser();
+ return true; // don't pass keyEvent
+ }
+
+ else
+ ret = false;
+
+
+ if ( FileWidget::isImage( item ) ) {
+// QString filename;
+// KIO::NetAccess::download(item->url(), filename, this);
+ m_viewer->showNextImage( item->url() );
+
+ if ( kdata->preloadImage && item_next ) { // preload next image
+ if ( FileWidget::isImage( item_next ) )
+ m_viewer->cacheImage( item_next->url() );
+ }
+
+ ret = true; // don't pass keyEvent
+ }
+ } // keyPressEvent on ImageWindow
+
+
+ // doubleclick closes image window
+ // and shows browser when last window closed via doubleclick
+ else if ( eventType == QEvent::MouseButtonDblClick )
+ {
+ QMouseEvent *ev = static_cast<QMouseEvent*>( e );
+ if ( ev->button() == LeftButton )
+ {
+ if ( s_viewers.count() == 1 )
+ {
+ if ( !fileWidget )
+ {
+// KURL start;
+// QFileInfo fi( window->filename() );
+// start.setPath( fi.dirPath( true ) );
+ initGUI( window->currentFile()->url().fileName() );
+ }
+ show();
+ raise();
+ }
+
+ window->close( true );
+
+ ev->accept();
+ ret = true;
+ }
+ }
+
+ } // isA ImageWindow
+
+
+ if ( ret )
+ return true;
+
+ return KMainWindow::eventFilter( o, e );
+}
+
+void KuickShow::configuration()
+{
+ if ( !m_accel ) {
+ KURL start;
+ start.setPath( QDir::homeDirPath() );
+ initGUI( KURL::fromPathOrURL( QDir::homeDirPath() ) );
+ }
+
+ dialog = new KuickConfigDialog( fileWidget->actionCollection(), 0L,
+ "dialog", false );
+ dialog->resize( 540, 510 );
+ dialog->setIcon( kapp->miniIcon() );
+
+ connect( dialog, SIGNAL( okClicked() ),
+ this, SLOT( slotConfigApplied() ) );
+ connect( dialog, SIGNAL( applyClicked() ),
+ this, SLOT( slotConfigApplied() ) );
+ connect( dialog, SIGNAL( finished() ),
+ this, SLOT( slotConfigClosed() ) );
+
+ fileWidget->actionCollection()->action( "kuick_configure" )->setEnabled( false );
+ dialog->show();
+}
+
+
+void KuickShow::slotConfigApplied()
+{
+ dialog->applyConfig();
+
+ initImlib();
+ kdata->save();
+
+ ImageWindow *viewer;
+ QValueListIterator<ImageWindow*> it = s_viewers.begin();
+ while ( it != s_viewers.end() ) {
+ viewer = *it;
+ viewer->updateActions();
+ ++it;
+ }
+
+ fileWidget->reloadConfiguration();
+}
+
+
+void KuickShow::slotConfigClosed()
+{
+ dialog->delayedDestruct();
+ fileWidget->actionCollection()->action( "kuick_configure" )->setEnabled( true );
+}
+
+void KuickShow::about()
+{
+ if ( !aboutWidget )
+ aboutWidget = new AboutWidget( 0L, "about" );
+
+ aboutWidget->adjustSize();
+
+#if KDE_VERSION >= 310
+ KDialog::centerOnScreen( aboutWidget );
+#else
+// Not fixed because it must be dead code now.
+ QDesktopWidget *desktop = QApplication::desktop();
+ int screen = desktop->screenNumber( aboutWidget );
+ if ( screen == -1 )
+ screen = desktop->primaryScreen();
+
+ QRect r = desktop->screenGeometry( screen );
+ aboutWidget->move( r.center().x() - aboutWidget->width()/2,
+ r.center().y() - aboutWidget->height()/2 );
+#endif
+
+ aboutWidget->show();
+}
+
+// ------ sessionmanagement - load / save current directory -----
+void KuickShow::readProperties( KConfig *kc )
+{
+ assert( fileWidget ); // from SM, we should always have initGUI on startup
+ QString dir = kc->readPathEntry( "CurrentDirectory" );
+ if ( !dir.isEmpty() ) {
+ fileWidget->setURL( KURL::fromPathOrURL( dir ), true );
+ fileWidget->clearHistory();
+ }
+
+ const KURL& listedURL = fileWidget->url();
+ QStringList images = kc->readPathListEntry( "Images shown" );
+ QStringList::Iterator it;
+ bool hasCurrentURL = false;
+
+ for ( it = images.begin(); it != images.end(); ++it ) {
+ KFileItem item( KFileItem::Unknown, KFileItem::Unknown, KURL::fromPathOrURL( *it ), false );
+ if ( item.isReadable() )
+ if ( showImage( &item, true ) ) {
+ // Set the current URL in the file widget, if possible
+ if ( !hasCurrentURL && listedURL.isParentOf( item.url() ))
+ fileWidget->setInitialItem( item.url().fileName() );
+ hasCurrentURL = true;
+ }
+ }
+
+ bool visible = kc->readBoolEntry( "Browser visible", false );
+ if ( visible || s_viewers.isEmpty() )
+ show();
+}
+
+void KuickShow::saveProperties( KConfig *kc )
+{
+ kc->writeEntry( "Browser visible", fileWidget && fileWidget->isVisible() );
+ if (fileWidget)
+ kc->writePathEntry( "CurrentDirectory", fileWidget->url().url() );
+
+ QStringList urls;
+ QValueListIterator<ImageWindow*> it;
+ for ( it = s_viewers.begin(); it != s_viewers.end(); ++it )
+ {
+ const KURL& url = (*it)->currentFile()->url();
+ if ( url.isLocalFile() )
+ urls.append( url.path() );
+ else
+ urls.append( url.prettyURL() ); // ### check if writePathEntry( prettyURL ) works!
+ }
+
+ kc->writePathEntry( "Images shown", urls );
+}
+
+// --------------------------------------------------------------
+
+void KuickShow::saveSettings()
+{
+ KConfig *kc = KGlobal::config();
+
+ kc->setGroup("SessionSettings");
+ if ( oneWindowAction )
+ kc->writeEntry( "OpenImagesInActiveWindow", oneWindowAction->isChecked() );
+
+ if ( fileWidget ) {
+ kc->writePathEntry( "CurrentDirectory", fileWidget->url().prettyURL() ); // ### was url().url()
+ fileWidget->writeConfig( kc, "Filebrowser" );
+ }
+
+ kc->sync();
+}
+
+
+void KuickShow::messageCantLoadImage( const KuickFile *, const QString& message )
+{
+ m_viewer->clearFocus();
+ KMessageBox::information( m_viewer, message, i18n("Error"), "kuick_cant_load_image" );
+}
+
+void KuickShow::initImlib()
+{
+ ImData *idata = kdata->idata;
+ ImlibInitParams par;
+ initImlibParams( idata, &par );
+
+ id = Imlib_init_with_params( x11Display(), &par );
+ if ( !id ) {
+ initImlibParams( idata, &par );
+
+ qWarning("*** KuickShow: Whoops, can't initialize imlib, trying my own palettefile now.");
+ QString paletteFile = locate( "data", "kuickshow/im_palette.pal" );
+ // ### - does the qstrdup() cure the segfault in imlib eventually?
+ char *file = qstrdup( paletteFile.local8Bit() );
+ par.palettefile = file;
+ par.flags |= PARAMS_PALETTEFILE;
+
+ qWarning("Palettefile: %s", par.palettefile );
+
+ id = Imlib_init_with_params( x11Display(), &par );
+
+ if ( !id ) {
+ QString tmp = i18n("Unable to initialize \"Imlib\".\n"
+ "Start kuickshow from the command line "
+ "and look for error messages.\n"
+ "The program will now quit.");
+ KMessageBox::error( this, tmp, i18n("Fatal Imlib Error") );
+
+ FileCache::shutdown();
+ ::exit(1);
+ }
+ }
+}
+
+
+void KuickShow::initImlibParams( ImData *idata, ImlibInitParams *par )
+{
+ par->flags = ( PARAMS_REMAP | PARAMS_VISUALID | PARAMS_SHAREDMEM | PARAMS_SHAREDPIXMAPS |
+ PARAMS_FASTRENDER | PARAMS_HIQUALITY | PARAMS_DITHER |
+ PARAMS_IMAGECACHESIZE | PARAMS_PIXMAPCACHESIZE );
+
+ Visual* defaultvis = DefaultVisual(x11Display(), x11Screen());
+
+ par->paletteoverride = idata->ownPalette ? 1 : 0;
+ par->remap = idata->fastRemap ? 1 : 0;
+ par->fastrender = idata->fastRender ? 1 : 0;
+ par->hiquality = idata->dither16bit ? 1 : 0;
+ par->dither = idata->dither8bit ? 1 : 0;
+ par->sharedmem = 1;
+ par->sharedpixmaps = 1;
+ par->visualid = defaultvis->visualid;
+ uint maxcache = idata->maxCache;
+
+ // 0 == no cache
+ par->imagecachesize = maxcache * 1024;
+ par->pixmapcachesize = maxcache * 1024;
+}
+
+bool KuickShow::haveBrowser() const
+{
+ return fileWidget && fileWidget->isVisible();
+}
+
+void KuickShow::delayedRepeatEvent( ImageWindow *w, QKeyEvent *e )
+{
+ m_delayedRepeatItem = new DelayedRepeatEvent( w, new QKeyEvent( *e ) );
+}
+
+void KuickShow::abortDelayedEvent()
+{
+ delete m_delayedRepeatItem;
+ m_delayedRepeatItem = 0L;
+}
+
+void KuickShow::slotReplayEvent()
+{
+ disconnect( fileWidget, SIGNAL( finished() ),
+ this, SLOT( slotReplayEvent() ));
+
+ DelayedRepeatEvent *e = m_delayedRepeatItem;
+ m_delayedRepeatItem = 0L; // otherwise, eventFilter aborts
+
+ eventFilter( e->viewer, e->event );
+ delete e;
+
+ // ### WORKAROUND for QIconView bug in Qt <= 3.0.3 at least
+ if ( fileWidget && fileWidget->view() ) {
+ QWidget *widget = fileWidget->view()->widget();
+ if ( widget->inherits( "QIconView" ) || widget->child(0, "QIconView" ) ){
+ fileWidget->setSorting( fileWidget->sorting() );
+ }
+ }
+ // --------------------------------------------------------------
+}
+
+void KuickShow::replayAdvance(DelayedRepeatEvent *event)
+{
+ // ### WORKAROUND for QIconView bug in Qt <= 3.0.3 at least
+ // Sigh. According to qt-bugs, they won't fix this bug ever. So you can't
+ // rely on sorting to be correct before the QIconView has been show()n.
+ if ( fileWidget && fileWidget->view() ) {
+ QWidget *widget = fileWidget->view()->widget();
+ if ( widget->inherits( "QIconView" ) || widget->child(0, "QIconView" ) ){
+ fileWidget->setSorting( fileWidget->sorting() );
+ }
+ }
+ // --------------------------------------------------------------
+
+ slotAdvanceImage( event->viewer, *(int *) (event->data) );
+}
+
+void KuickShow::delayAction(DelayedRepeatEvent *event)
+{
+ if (m_delayedRepeatItem)
+ return;
+
+ m_delayedRepeatItem = event;
+
+ KURL url = event->viewer->currentFile()->url();
+// QFileInfo fi( event->viewer->filename() );
+// start.setPath( fi.dirPath( true ) );
+ initGUI( url.upURL() );
+
+ // see eventFilter() for explanation and similar code
+ if ( fileWidget->dirLister()->isFinished() &&
+ fileWidget->dirLister()->rootItem() )
+ {
+ fileWidget->setCurrentItem( url.fileName() );
+ QTimer::singleShot( 0, this, SLOT( doReplay()));
+ }
+ else
+ {
+ fileWidget->setInitialItem( url.fileName() );
+ connect( fileWidget, SIGNAL( finished() ),
+ SLOT( doReplay() ));
+ }
+}
+
+void KuickShow::doReplay()
+{
+ if (!m_delayedRepeatItem)
+ return;
+
+ disconnect( fileWidget, SIGNAL( finished() ),
+ this, SLOT( doReplay() ));
+
+ switch (m_delayedRepeatItem->action)
+ {
+ case DelayedRepeatEvent::DeleteCurrentFile:
+ performDeleteCurrentImage((QWidget *) m_delayedRepeatItem->data);
+ break;
+ case DelayedRepeatEvent::TrashCurrentFile:
+ performTrashCurrentImage((QWidget *) m_delayedRepeatItem->data);
+ break;
+ case DelayedRepeatEvent::AdvanceViewer:
+ replayAdvance(m_delayedRepeatItem);
+ break;
+ default:
+ kdWarning() << "doReplay: unknown action -- ignoring: " << m_delayedRepeatItem->action << endl;
+ break;
+ }
+
+ delete m_delayedRepeatItem;
+ m_delayedRepeatItem = 0L;
+}
+
+void KuickShow::toggleBrowser()
+{
+ if ( !haveBrowser() ) {
+ if ( m_viewer && m_viewer->isFullscreen() )
+ m_viewer->setFullscreen( false );
+ fileWidget->resize( size() ); // ### somehow fileWidget isn't resized!?
+ show();
+ raise();
+ KWin::activateWindow( winId() ); // ### this should not be necessary
+// setFocus();
+ }
+ else if ( !s_viewers.isEmpty() )
+ hide();
+}
+
+void KuickShow::slotOpenURL()
+{
+ KFileDialog dlg(QString::null, kdata->fileFilter, this, "filedialog", true);
+ dlg.setMode( KFile::Files | KFile::Directory );
+ dlg.setCaption( i18n("Select Files or Folder to Open") );
+
+ if ( dlg.exec() == QDialog::Accepted )
+ {
+ KURL::List urls = dlg.selectedURLs();
+ KURL::List::ConstIterator it = urls.begin();
+ for ( ; it != urls.end(); ++it )
+ {
+ KFileItem item( KFileItem::Unknown, KFileItem::Unknown, *it );
+ if ( FileWidget::isImage( &item ) )
+ showImage( &item, true );
+ else
+ fileWidget->setURL( *it, true );
+ }
+ }
+}
+
+void KuickShow::deleteAllViewers()
+{
+ QValueListIterator<ImageWindow*> it = s_viewers.begin();
+ for ( ; it != s_viewers.end(); ++it ) {
+ (*it)->disconnect( SIGNAL( destroyed() ), this, SLOT( viewerDeleted() ));
+ (*it)->close( true );
+ }
+
+ s_viewers.clear();
+ m_viewer = 0L;
+}
+
+KActionCollection * KuickShow::actionCollection() const
+{
+ if ( fileWidget )
+ return fileWidget->actionCollection();
+
+ return KMainWindow::actionCollection();
+}
+
+#include "kuickshow.moc"
diff --git a/kuickshow/src/kuickshow.desktop b/kuickshow/src/kuickshow.desktop
new file mode 100644
index 00000000..b2e2ee37
--- /dev/null
+++ b/kuickshow/src/kuickshow.desktop
@@ -0,0 +1,93 @@
+[Desktop Entry]
+Name=Kuickshow
+Name[af]=Vinnig-vertoon
+Name[ar]=عرض سريع
+Name[eo]=Rapidmontrilo
+Name[fr]=KuickShow
+Name[hi]=क्विक-शो
+Name[it]=KuickShow
+Name[ko]=K퀵쇼
+Name[ne]=क्विकशो
+Name[pt_BR]=KRápida Exibição
+Name[ta]=விரைவுகாட்சி
+Name[th]=ดูภาพด่วน - K
+Name[ven]=Musumbedzo wa kuick
+Name[zh_TW]=Kuickshow 快秀
+Name[zu]=I Kuickshow
+Exec=kuickshow %i %m -caption "%c" %U
+Icon=kuickshow
+Type=Application
+MimeType=image/gif;image/x-xpm;image/x-xbm;image/jpeg;image/png;image/tiff;image/x-bmp;image/x-psd;image/x-eim;image/x-portable-bitmap;image/x-portable-pixmap;image/x-portable-greymap;
+DocPath=kuickshow/index.html
+Terminal=false
+InitialPreference=6
+
+GenericName=Image Viewer
+GenericName[af]=Beeld Aansig
+GenericName[ar]=عارض صور
+GenericName[bg]=Преглед на изображения
+GenericName[br]=Gweler ar skeudennoù
+GenericName[bs]=Preglednik slika
+GenericName[ca]=Visualitzador d'imatges
+GenericName[cs]=Prohlížeč obrázků
+GenericName[cy]=Gwelydd Delweddau
+GenericName[da]=Billedfremviser
+GenericName[de]=Bildbetrachter
+GenericName[el]=Προβολέας εικόνων
+GenericName[eo]=Bildorigardilo
+GenericName[es]=Visor de imágenes
+GenericName[et]=Pildifailide näitaja
+GenericName[eu]=Irudi ikustailua
+GenericName[fa]=مشاهده‌گر تصویر
+GenericName[fi]=Kuvannäytin
+GenericName[fr]=Afficheur d'images
+GenericName[ga]=Amharcán Íomhánna
+GenericName[gl]=Visor de imaxes
+GenericName[he]=מציג תמונות
+GenericName[hi]=छवि प्रदर्शक
+GenericName[hr]=Preglednik slika
+GenericName[hu]=Képnézegető
+GenericName[is]=Myndaskoðari
+GenericName[it]=Visore di immagini
+GenericName[ja]=画像ビューア
+GenericName[kk]=Кескіндерді қарау
+GenericName[km]=កម្មវិធី​មើល​រូបភាព
+GenericName[lt]=Paveikslėlių žiūriklis
+GenericName[lv]=Attēlu Skatītājs
+GenericName[ms]=Paparan Imej
+GenericName[mt]=Werrej tal-istampi
+GenericName[nb]=Bildefremviser
+GenericName[nds]=Bildkieker
+GenericName[ne]=छवि दर्शक
+GenericName[nl]=Afbeeldingenweergaveprogramma
+GenericName[nn]=Biletvisar
+GenericName[nso]=Molebeledi wa Ponagalo
+GenericName[pa]=ਚਿੱਤਰ ਦਰਸ਼ਕ
+GenericName[pl]=Przeglądarka obrazków
+GenericName[pt]=Visualizador de Imagens
+GenericName[pt_BR]=Visualizador de Imagens
+GenericName[ro]=Vizualizor de imagini
+GenericName[ru]=Просмотр изображений
+GenericName[rw]=Mugaraza Shusho
+GenericName[se]=Govvačájeheaddji
+GenericName[sk]=Prehliadač obrázkov
+GenericName[sl]=Pregledovalnik slik
+GenericName[sr]=Приказивач слика
+GenericName[sr@Latn]=Prikazivač slika
+GenericName[sv]=Bildvisare
+GenericName[ta]=பிம்ப காட்சி
+GenericName[tg]=Намоиши тасвирот
+GenericName[th]=เครื่องมือแสดงภาพ
+GenericName[tr]=Resim Göstericisi
+GenericName[uk]=Переглядач зображень
+GenericName[uz]=Rasm koʻruvchi
+GenericName[uz@cyrillic]=Расм кўрувчи
+GenericName[ven]=Tshivhoni tsha Mutaleli
+GenericName[wa]=Håyneu d' imådjes
+GenericName[xh]=Umboniseli Womfanekiso
+GenericName[zh_CN]=图片查看程序
+GenericName[zh_HK]=圖像檢視器
+GenericName[zh_TW]=影像檢視程式
+GenericName[zu]=Umbonisi Womfanekiso
+X-DCOP-ServiceType=Multi
+Categories=Qt;KDE;Graphics;
diff --git a/kuickshow/src/kuickshow.h b/kuickshow/src/kuickshow.h
new file mode 100644
index 00000000..d6239b64
--- /dev/null
+++ b/kuickshow/src/kuickshow.h
@@ -0,0 +1,178 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998-2006 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KUICKSHOW_H
+#define KUICKSHOW_H
+
+#include <qevent.h>
+#include <qguardedptr.h>
+#include <qstring.h>
+#include <qvaluelist.h>
+
+#include <kfileitem.h>
+#include <kmainwindow.h>
+#include <kurl.h>
+
+#include <Imlib.h>
+
+#include "aboutwidget.h"
+
+class FileWidget;
+class ImageWindow;
+class ImData;
+class KuickConfigDialog;
+
+class KAccel;
+class KConfig;
+class KToggleAction;
+class AboutWidget;
+
+class KURL;
+class KURLComboBox;
+
+class KuickFile;
+
+class DelayedRepeatEvent
+{
+public:
+ DelayedRepeatEvent( ImageWindow *view, QKeyEvent *ev ) {
+ viewer = view;
+ event = ev;
+ }
+ DelayedRepeatEvent( ImageWindow *view, int action, void *data ) {
+ this->viewer = view;
+ this->action = action;
+ this->data = data;
+ this->event = 0L;
+ }
+
+ ~DelayedRepeatEvent() {
+ delete event;
+ }
+
+ enum Action
+ {
+ DeleteCurrentFile,
+ TrashCurrentFile,
+ AdvanceViewer
+ };
+
+ ImageWindow *viewer;
+ QKeyEvent *event;
+ int action;
+ void *data;
+};
+
+
+class KuickShow : public KMainWindow
+{
+ Q_OBJECT
+
+public:
+ KuickShow( const char *name=0 );
+ ~KuickShow();
+
+ virtual void show();
+ static QValueList<ImageWindow*> s_viewers;
+
+ // overridden to make KDCOPActionProxy work -- all our actions are not
+ // in the mainwindow's collection, but in the filewidget's.
+ virtual KActionCollection* actionCollection() const;
+
+
+protected:
+ virtual void readProperties( KConfig * );
+ void initImlibParams( ImData *, ImlibInitParams * );
+ void tryShowNextImage();
+
+private slots:
+ void toggleBrowser();
+ void slotQuit() { delete this; }
+ void slotPrint();
+ void slotConfigApplied();
+ void slotConfigClosed();
+ void messageCantLoadImage( const KuickFile * file, const QString& message);
+ bool showImage(const KFileItem *, bool newWindow = false,
+ bool fullscreen = false, bool moveToTopLeft = true );
+ void showFileItem( ImageWindow *, const KFileItem * );
+ void slotHighlighted( const KFileItem * );
+ void slotSelected( const KFileItem * );
+ void dirSelected( const KURL& );
+ void configuration();
+ void about();
+ void startSlideShow();
+ void pauseSlideShow();
+ void nextSlide();
+ void nextSlide( KFileItem *item );
+ void viewerDeleted();
+ void slotDropped( const KFileItem *, QDropEvent *, const KURL::List &);
+ void slotSetActiveViewer( ImageWindow *i ) { m_viewer = i; }
+ void slotAdvanceImage( ImageWindow *, int steps );
+
+ void slotShowInSameWindow();
+ void slotShowInOtherWindow();
+ void slotShowFullscreen();
+
+ void slotReplayEvent();
+ void slotOpenURL();
+ void slotSetURL( const KURL& );
+ void slotURLComboReturnPressed();
+// void invalidateImages( const KFileItemList& items );
+ void slotDeleteCurrentImage(ImageWindow *viewer);
+ void slotTrashCurrentImage(ImageWindow *viewer);
+ void slotDeleteCurrentImage();
+ void slotTrashCurrentImage();
+
+ void doReplay();
+
+private:
+ void initGUI( const KURL& startDir );
+ bool eventFilter( QObject *, QEvent * );
+ void initImlib();
+ void saveProperties( KConfig * );
+ void saveSettings();
+ bool haveBrowser() const;
+ void delayedRepeatEvent( ImageWindow *, QKeyEvent * );
+ void abortDelayedEvent();
+ void deleteAllViewers();
+ void redirectDeleteAndTrashActions(KActionCollection *coll);
+
+ void delayAction(DelayedRepeatEvent *event);
+ void replayAdvance(DelayedRepeatEvent *event);
+
+ void performDeleteCurrentImage(QWidget *parent);
+ void performTrashCurrentImage(QWidget *parent);
+
+ uint viewItem, renameItem, deleteItem, printItem;
+ uint m_slideshowCycle;
+
+ FileWidget *fileWidget;
+ KURLComboBox *cmbPath;
+ KuickConfigDialog *dialog;
+ ImlibData *id;
+ ImageWindow *m_viewer;
+ KToggleAction *oneWindowAction;
+ KAccel *m_accel;
+ DelayedRepeatEvent *m_delayedRepeatItem;
+ QTimer *m_slideTimer;
+ bool m_slideShowStopped;
+ KToggleAction *m_toggleBrowserAction;
+ QGuardedPtr<AboutWidget> aboutWidget;
+};
+
+#endif
diff --git a/kuickshow/src/kurlwidget.cpp b/kuickshow/src/kurlwidget.cpp
new file mode 100644
index 00000000..0a23fa3a
--- /dev/null
+++ b/kuickshow/src/kurlwidget.cpp
@@ -0,0 +1,42 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998,1999,2000 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qtooltip.h>
+
+#include <kurl.h>
+#include <krun.h>
+
+#include "kurlwidget.h"
+
+KURLWidget::KURLWidget(const QString& text, QWidget *parent, const char *name)
+ : KURLLabel( parent, name )
+{
+ setText( text );
+ connect( this, SIGNAL( leftClickedURL() ), SLOT( run() ));
+ setUseTips( true );
+}
+
+void KURLWidget::run()
+{
+ KURL ku( url() );
+ if ( ku.isValid() ) {
+ (void) new KRun( ku, this );
+ }
+}
+
+#include "kurlwidget.moc"
diff --git a/kuickshow/src/kurlwidget.h b/kuickshow/src/kurlwidget.h
new file mode 100644
index 00000000..2f35e009
--- /dev/null
+++ b/kuickshow/src/kurlwidget.h
@@ -0,0 +1,36 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998,1999,2000 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KURLWIDGET_H
+#define KURLWIDGET_H
+
+#include <kurllabel.h>
+
+class KURLWidget : public KURLLabel
+{
+ Q_OBJECT
+
+public:
+ KURLWidget( const QString& text, QWidget *, const char *name=0 );
+
+protected slots:
+ virtual void run();
+
+};
+
+#endif
diff --git a/kuickshow/src/main.cpp b/kuickshow/src/main.cpp
new file mode 100644
index 00000000..dfb462f0
--- /dev/null
+++ b/kuickshow/src/main.cpp
@@ -0,0 +1,66 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998-2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qstring.h>
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "kuickshow.h"
+#include "version.h"
+
+static KCmdLineOptions options[] =
+{
+ { "lastfolder", I18N_NOOP("Start in the last visited folder, not the "
+ "current working folder."), 0 },
+ { "d", 0, 0 }, // short option for --lastdir
+ { "+[files]", I18N_NOOP("Optional image filenames/urls to show"), 0 },
+ KCmdLineLastOption
+};
+
+extern "C" KDE_EXPORT int kdemain(int argc, char **argv)
+{
+ KAboutData about(
+ "kuickshow", I18N_NOOP( "KuickShow" ), KUICKSHOWVERSION,
+ I18N_NOOP("A fast and versatile image viewer" ),
+ KAboutData::License_GPL, "(c) 1998-2006, Carsten Pfeiffer",
+ 0 /*text*/, "http://devel-home.kde.org/~pfeiffer/" );
+
+ about.addAuthor( "Carsten Pfeiffer", 0, "pfeiffer@kde.org",
+ "http://devel-home.kde.org/~pfeiffer/" );
+ about.addCredit( "Rober Hamberger", 0, "rh474@bingo-ev.de" );
+ about.addCredit( "Thorsten Scheuermann", 0, "uddn@rz.uni-karlsruhe.de" );
+
+ KCmdLineArgs::init( argc, argv, &about );
+ KCmdLineArgs::addCmdLineOptions( options );
+
+ KApplication app;
+
+ if ( app.isRestored() ) {
+ (new KuickShow())->restore( 1, false ); // don't show automatically
+ }
+ else {
+ KuickShow *k = new KuickShow( "kuickshow" );
+ app.setMainWidget( k );
+ }
+
+ return app.exec();
+}
diff --git a/kuickshow/src/mainwidget.cpp b/kuickshow/src/mainwidget.cpp
new file mode 100644
index 00000000..caa6700c
--- /dev/null
+++ b/kuickshow/src/mainwidget.cpp
@@ -0,0 +1,43 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998,1999 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "fileview.h"
+#include "kuickdata.h"
+#include "mainwidget.h"
+
+
+MainWidget::MainWidget( QString startDir, QWidget *parent,
+ const char *name ) : QWidget ( parent, name )
+{
+ box = new FileView( startDir, true, (QDir::Dirs | QDir::Files),
+ this, "fileview" );
+}
+
+
+MainWidget::~MainWidget()
+{
+
+}
+
+
+// for now, no layout managers
+void MainWidget::resizeEvent( QResizeEvent * )
+{
+ box->resize( width(), height() );
+}
+#include "mainwidget.moc"
diff --git a/kuickshow/src/mainwidget.h b/kuickshow/src/mainwidget.h
new file mode 100644
index 00000000..36285dd8
--- /dev/null
+++ b/kuickshow/src/mainwidget.h
@@ -0,0 +1,47 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef MAINWIDGET_H
+#define MAINWIDGET_H
+
+#include <qevent.h>
+#include <qstring.h>
+#include <qwidget.h>
+
+class FileView;
+
+class MainWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ MainWidget( QString, QWidget *parent, const char *name=0L);
+ ~MainWidget();
+
+ FileView* getFileBox() { return box; }
+
+protected:
+ virtual void resizeEvent( QResizeEvent * );
+
+private:
+ FileView *box;
+
+};
+
+
+#endif
diff --git a/kuickshow/src/printing.cpp b/kuickshow/src/printing.cpp
new file mode 100644
index 00000000..be57ca7f
--- /dev/null
+++ b/kuickshow/src/printing.cpp
@@ -0,0 +1,338 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qcheckbox.h>
+#include <qfont.h>
+#include <qfontmetrics.h>
+#include <qgrid.h>
+#include <qhbox.h>
+#include <qlayout.h>
+#include <qimage.h>
+#include <kimageeffect.h>
+#include <qpaintdevicemetrics.h>
+#include <qpainter.h>
+#include <qradiobutton.h>
+#include <qvbuttongroup.h>
+#include <qcolor.h>
+
+#include <kcombobox.h>
+#include <kdialog.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kglobalsettings.h>
+#include <knuminput.h>
+#include <kprinter.h>
+#include <ktempfile.h>
+
+#include "imagewindow.h"
+#include "printing.h"
+#include "version.h"
+
+bool Printing::printImage( ImageWindow& imageWin, QWidget *parent )
+{
+ QString imageURL = imageWin.url().prettyURL();
+ KPrinter printer;
+ printer.setDocName( imageURL );
+ printer.setCreator( "KuickShow-" KUICKSHOWVERSION );
+
+ KPrinter::addDialogPage( new KuickPrintDialogPage( parent, "kuick page"));
+
+ if ( printer.setup( parent, i18n("Print %1").arg(printer.docName().section('/', -1)) ) )
+ {
+ KTempFile tmpFile( QString::null, ".png" );
+ if ( tmpFile.status() == 0 )
+ {
+ tmpFile.setAutoDelete( true );
+ if ( imageWin.saveImage( tmpFile.name(), true ) )
+ return printImageWithQt( tmpFile.name(), printer,
+ imageURL );
+ }
+
+ return false;
+ }
+
+ return true; // user aborted
+}
+
+bool Printing::printImageWithQt( const QString& filename, KPrinter& printer,
+ const QString& originalFileName )
+{
+ QImage image( filename );
+ if ( image.isNull() ) {
+ kdWarning() << "Can't load image: " << filename << " for printing.\n";
+ return false;
+ }
+
+ QPainter p;
+ p.begin( &printer );
+
+ QPaintDeviceMetrics metrics( &printer );
+ p.setFont( KGlobalSettings::generalFont() );
+ QFontMetrics fm = p.fontMetrics();
+
+ int w = metrics.width();
+ int h = metrics.height();
+
+ QString t = "true";
+ QString f = "false";
+
+ // Black & white print?
+ if ( printer.option( "app-kuickshow-blackwhite" ) != f) {
+ image = image.convertDepth( 1, Qt::MonoOnly | Qt::ThresholdDither | Qt::AvoidDither );
+ }
+
+ int filenameOffset = 0;
+ bool printFilename = printer.option( "app-kuickshow-printFilename" ) != f;
+ if ( printFilename ) {
+ filenameOffset = fm.lineSpacing() + 14;
+ h -= filenameOffset; // filename goes into one line!
+ }
+
+ //
+ // shrink image to pagesize, if necessary
+ //
+ bool shrinkToFit = (printer.option( "app-kuickshow-shrinkToFit" ) != f);
+ QSize imagesize = image.size();
+ if ( shrinkToFit && (image.width() > w || image.height() > h) ) {
+ imagesize.scale( w, h, QSize::ScaleMin );
+ }
+
+
+ //
+ // align image
+ //
+ bool ok = false;
+ int alignment = printer.option("app-kuickshow-alignment").toInt( &ok );
+ if ( !ok )
+ alignment = Qt::AlignCenter; // default
+
+ int x = 0;
+ int y = 0;
+
+ // ### need a GUI for this in KuickPrintDialogPage!
+ // x - alignment
+ if ( alignment & Qt::AlignHCenter )
+ x = (w - imagesize.width())/2;
+ else if ( alignment & Qt::AlignLeft )
+ x = 0;
+ else if ( alignment & Qt::AlignRight )
+ x = w - imagesize.width();
+
+ // y - alignment
+ if ( alignment & Qt::AlignVCenter )
+ y = (h - imagesize.height())/2;
+ else if ( alignment & Qt::AlignTop )
+ y = 0;
+ else if ( alignment & Qt::AlignBottom )
+ y = h - imagesize.height();
+
+ //
+ // perform the actual drawing
+ //
+ p.drawImage( QRect( x, y, imagesize.width(), imagesize.height()), image );
+
+ if ( printFilename )
+ {
+ QString fname = minimizeString( originalFileName, fm, w );
+ if ( !fname.isEmpty() )
+ {
+ int fw = fm.width( fname );
+ int x = (w - fw)/2;
+ int y = metrics.height() - filenameOffset/2;
+ p.drawText( x, y, fname );
+ }
+ }
+
+ p.end();
+
+ return true;
+}
+
+QString Printing::minimizeString( QString text, const QFontMetrics&
+ metrics, int maxWidth )
+{
+ if ( text.length() <= 5 )
+ return QString::null; // no sense to cut that tiny little string
+
+ bool changed = false;
+ while ( metrics.width( text ) > maxWidth )
+ {
+ int mid = text.length() / 2;
+ text.remove( mid, 2 ); // remove 2 characters in the middle
+ changed = true;
+ }
+
+ if ( changed ) // add "..." in the middle
+ {
+ int mid = text.length() / 2;
+ if ( mid <= 5 ) // sanity check
+ return QString::null;
+
+ text.replace( mid - 1, 3, "..." );
+ }
+
+ return text;
+}
+
+
+///////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+
+
+KuickPrintDialogPage::KuickPrintDialogPage( QWidget *parent, const char *name )
+ : KPrintDialogPage( parent, name )
+{
+ setTitle( i18n("Image Settings") );
+
+ QVBoxLayout *layout = new QVBoxLayout( this );
+ layout->setMargin( KDialog::marginHint() );
+ layout->setSpacing( KDialog::spacingHint() );
+
+ m_addFileName = new QCheckBox( i18n("Print fi&lename below image"), this);
+ m_addFileName->setChecked( true );
+ layout->addWidget( m_addFileName );
+
+ m_blackwhite = new QCheckBox ( i18n("Print image in &black and white"), this);
+ m_blackwhite->setChecked( false );
+ layout->addWidget (m_blackwhite );
+
+ QVButtonGroup *group = new QVButtonGroup( i18n("Scaling"), this );
+ group->setRadioButtonExclusive( true );
+ layout->addWidget( group );
+ // m_shrinkToFit = new QRadioButton( i18n("Shrink image to &fit, if necessary"), group );
+ m_shrinkToFit = new QCheckBox( i18n("Shrink image to &fit, if necessary"), group );
+ m_shrinkToFit->setChecked( true );
+
+ QWidget *widget = new QWidget( group );
+ QGridLayout *grid = new QGridLayout( widget, 3, 3 );
+ grid->addColSpacing( 0, 30 );
+ grid->setColStretch( 0, 0 );
+ grid->setColStretch( 1, 1 );
+ grid->setColStretch( 2, 10 );
+
+ m_scale = new QRadioButton( i18n("Print e&xact size: "), widget );
+ m_scale->setEnabled( false ); // ###
+ grid->addMultiCellWidget( m_scale, 0, 0, 0, 1 );
+ group->insert( m_scale );
+ connect( m_scale, SIGNAL( toggled( bool )), SLOT( toggleScaling( bool )));
+
+ m_units = new KComboBox( false, widget, "unit combobox" );
+ grid->addWidget( m_units, 0, 2, AlignLeft );
+ m_units->insertItem( i18n("Millimeters") );
+ m_units->insertItem( i18n("Centimeters") );
+ m_units->insertItem( i18n("Inches") );
+
+ m_width = new KIntNumInput( widget, "exact width" );
+ grid->addWidget( m_width, 1, 1 );
+ m_width->setLabel( i18n("&Width:" ) );
+ m_width->setMinValue( 1 );
+
+ m_height = new KIntNumInput( widget, "exact height" );
+ grid->addWidget( m_height, 2, 1 );
+ m_height->setLabel( i18n("&Height:" ) );
+ m_height->setMinValue( 1 );
+}
+
+KuickPrintDialogPage::~KuickPrintDialogPage()
+{
+}
+
+void KuickPrintDialogPage::getOptions( QMap<QString,QString>& opts,
+ bool /*incldef*/ )
+{
+ QString t = "true";
+ QString f = "false";
+
+// ### opts["app-kuickshow-alignment"] = ;
+ opts["app-kuickshow-printFilename"] = m_addFileName->isChecked() ? t : f;
+ opts["app-kuickshow-blackwhite"] = m_blackwhite->isChecked() ? t : f;
+ opts["app-kuickshow-shrinkToFit"] = m_shrinkToFit->isChecked() ? t : f;
+ opts["app-kuickshow-scale"] = m_scale->isChecked() ? t : f;
+ opts["app-kuickshow-scale-unit"] = m_units->currentText();
+ opts["app-kuickshow-scale-width-pixels"] = QString::number( scaleWidth() );
+ opts["app-kuickshow-scale-height-pixels"] = QString::number( scaleHeight() );
+}
+
+void KuickPrintDialogPage::setOptions( const QMap<QString,QString>& opts )
+{
+ QString t = "true";
+ QString f = "false";
+
+ m_addFileName->setChecked( opts["app-kuickshow-printFilename"] != f );
+ // This sound strange, but if I copy the code on the line above, the checkbox
+ // was always checked. And this isn't the wanted behavior. So, with this works.
+ // KPrint magic ;-)
+ m_blackwhite->setChecked ( false );
+ m_shrinkToFit->setChecked( opts["app-kuickshow-shrinkToFit"] != f );
+ m_scale->setChecked( opts["app-kuickshow-scale"] == t );
+
+ m_units->setCurrentItem( opts["app-kuickshow-scale-unit"] );
+
+ bool ok;
+ int val = opts["app-kuickshow-scale-width-pixels"].toInt( &ok );
+ if ( ok )
+ setScaleWidth( val );
+ val = opts["app-kuickshow-scale-height-pixels"].toInt( &ok );
+ if ( ok )
+ setScaleHeight( val );
+
+ if ( m_scale->isChecked() == m_shrinkToFit->isChecked() )
+ m_shrinkToFit->setChecked( !m_scale->isChecked() );
+
+ // ### re-enable when implementednn
+ toggleScaling( false && m_scale->isChecked() );
+}
+
+void KuickPrintDialogPage::toggleScaling( bool enable )
+{
+ m_width->setEnabled( enable );
+ m_height->setEnabled( enable );
+ m_units->setEnabled( enable );
+}
+
+int KuickPrintDialogPage::scaleWidth() const
+{
+ return fromUnitToPixels( m_width->value() );
+}
+
+int KuickPrintDialogPage::scaleHeight() const
+{
+ return fromUnitToPixels( m_height->value() );
+}
+
+void KuickPrintDialogPage::setScaleWidth( int pixels )
+{
+ m_width->setValue( (int) pixelsToUnit( pixels ) );
+}
+
+void KuickPrintDialogPage::setScaleHeight( int pixels )
+{
+ m_width->setValue( (int) pixelsToUnit( pixels ) );
+}
+
+int KuickPrintDialogPage::fromUnitToPixels( float /*value*/ ) const
+{
+ return 1; // ###
+}
+
+float KuickPrintDialogPage::pixelsToUnit( int /*pixels*/ ) const
+{
+ return 1.0; // ###
+}
+
+#include "printing.moc"
diff --git a/kuickshow/src/printing.h b/kuickshow/src/printing.h
new file mode 100644
index 00000000..eb679f7e
--- /dev/null
+++ b/kuickshow/src/printing.h
@@ -0,0 +1,85 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef PRINTING_H
+#define PRINTING_H
+
+#include <qfontmetrics.h>
+#include <qstring.h>
+
+#include <kdeprint/kprintdialogpage.h>
+
+class QCheckBox;
+class QRadioButton;
+class KComboBox;
+class KPrinter;
+class KIntNumInput;
+
+class ImageWindow;
+
+
+class Printing
+{
+public:
+ static bool printImage( ImageWindow& imageWin, QWidget *parent = 0L);
+ static bool printImageWithQt( const QString& filename, KPrinter& printer,
+ const QString& originalFileName );
+
+private:
+ static void addConfigPages();
+ static QString minimizeString( QString text, const QFontMetrics& metrics,
+ int maxWidth );
+
+};
+
+class KuickPrintDialogPage : public KPrintDialogPage
+{
+ Q_OBJECT
+
+public:
+ KuickPrintDialogPage( QWidget *parent = 0L, const char *name = 0 );
+ ~KuickPrintDialogPage();
+
+ virtual void getOptions(QMap<QString,QString>& opts, bool incldef = false);
+ virtual void setOptions(const QMap<QString,QString>& opts);
+
+private slots:
+ void toggleScaling( bool enable );
+
+private:
+ // return values in pixels!
+ int scaleWidth() const;
+ int scaleHeight() const;
+
+ void setScaleWidth( int pixels );
+ void setScaleHeight( int pixels );
+
+ int fromUnitToPixels( float val ) const;
+ float pixelsToUnit( int pixels ) const;
+
+ QCheckBox *m_shrinkToFit;
+ QRadioButton *m_scale;
+ KIntNumInput *m_width;
+ KIntNumInput *m_height;
+ KComboBox *m_units;
+ QCheckBox *m_addFileName;
+ QCheckBox *m_blackwhite;
+
+};
+
+#endif // PRINTING_H
diff --git a/kuickshow/src/slideshowwidget.cpp b/kuickshow/src/slideshowwidget.cpp
new file mode 100644
index 00000000..447b996e
--- /dev/null
+++ b/kuickshow/src/slideshowwidget.cpp
@@ -0,0 +1,80 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qcheckbox.h>
+#include <qlayout.h>
+
+#include <kdialog.h>
+#include <klocale.h>
+#include <knuminput.h>
+
+#include "slideshowwidget.h"
+
+
+SlideShowWidget::SlideShowWidget( QWidget *parent, const char *name )
+ : QWidget( parent, name )
+{
+// setTitle( i18n("Slideshow") );
+
+ QVBoxLayout *layout = new QVBoxLayout( this );
+ layout->setSpacing( KDialog::spacingHint() );
+
+ m_fullScreen = new QCheckBox( i18n("Switch to &full-screen"), this );
+ m_startWithCurrent = new QCheckBox( i18n("S&tart with current image"), this);
+
+ m_delayTime = new KIntNumInput( this, "delay time" );
+ m_delayTime->setLabel( i18n("De&lay between slides:") );
+ m_delayTime->setSuffix( i18n(" sec") );
+ m_delayTime->setRange( 0, 60 * 60 ); // 1 hour
+ m_delayTime->setSpecialValueText( i18n("Wait for key") );
+
+ m_cycles = new KIntNumInput( m_delayTime, 1, this );
+ m_cycles->setLabel( i18n("&Iterations (0 = infinite):") );
+ m_cycles->setSpecialValueText( i18n("infinite") );
+ m_cycles->setRange( 0, 500 );
+
+ layout->addWidget( m_fullScreen );
+ layout->addWidget( m_startWithCurrent );
+ layout->addWidget( m_delayTime );
+ layout->addWidget( m_cycles );
+ layout->addStretch( 1 );
+
+ loadSettings( *kdata );
+}
+
+SlideShowWidget::~SlideShowWidget()
+{
+}
+
+void SlideShowWidget::loadSettings( const KuickData& data )
+{
+ m_delayTime->setValue( data.slideDelay / 1000 );
+ m_cycles->setValue( data.slideshowCycles );
+ m_fullScreen->setChecked( data.slideshowFullscreen );
+ m_startWithCurrent->setChecked( !data.slideshowStartAtFirst );
+}
+
+void SlideShowWidget::applySettings( KuickData& data )
+{
+ data.slideDelay = m_delayTime->value() * 1000;
+ data.slideshowCycles = m_cycles->value();
+ data.slideshowFullscreen = m_fullScreen->isChecked();
+ data.slideshowStartAtFirst = !m_startWithCurrent->isChecked();
+}
+
+#include "slideshowwidget.moc"
diff --git a/kuickshow/src/slideshowwidget.h b/kuickshow/src/slideshowwidget.h
new file mode 100644
index 00000000..c651103d
--- /dev/null
+++ b/kuickshow/src/slideshowwidget.h
@@ -0,0 +1,44 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Carsten Pfeiffer <pfeiffer@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, version 2.
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SLIDESHOWWIDGET_H
+#define SLIDESHOWWIDGET_H
+
+#include "kuickdata.h"
+
+class QCheckBox;
+class KIntNumInput;
+
+class SlideShowWidget : public QWidget
+{
+ Q_OBJECT
+public:
+ SlideShowWidget( QWidget *parent, const char *name );
+ ~SlideShowWidget();
+
+ virtual void loadSettings( const KuickData& data );
+ virtual void applySettings( KuickData& data );
+
+private:
+ KIntNumInput *m_delayTime;
+ KIntNumInput *m_cycles;
+ QCheckBox *m_fullScreen;
+ QCheckBox *m_startWithCurrent;
+};
+
+#endif // SLIDESHOWWIDGET_H
diff --git a/kuickshow/src/version.h b/kuickshow/src/version.h
new file mode 100644
index 00000000..2465967f
--- /dev/null
+++ b/kuickshow/src/version.h
@@ -0,0 +1,3 @@
+#ifndef KUICKSHOWVERSION
+#define KUICKSHOWVERSION "0.8.13"
+#endif
diff --git a/kview/AUTHORS b/kview/AUTHORS
new file mode 100644
index 00000000..63f21e88
--- /dev/null
+++ b/kview/AUTHORS
@@ -0,0 +1,4 @@
+
+Written by Sirtaj Singh Kang <taj@kde.org>
+KOM/OpenParts integration done by Simon Hausmann
+Rewritten by Matthias Kretz (current Maintainer)
diff --git a/kview/ChangeLog b/kview/ChangeLog
new file mode 100644
index 00000000..e24c55e2
--- /dev/null
+++ b/kview/ChangeLog
@@ -0,0 +1,98 @@
+2003-10-06 Matthias Kretz <kretz@kde.org>
+
+ * config/plugins/kviewpluginsconfig.cpp:
+ Don't show an empty config page in the pluginselector (there are no
+ KView plugins with config options, yet).
+
+2003-09-27 Matthias Kretz <kretz@kde.org>
+
+ * config/kviewconfmodules.cpp:
+ Call sync() in save() on the KConfig object.
+
+2003-08-19 Matthias Kretz <kretz@kde.org>
+
+ * kview.cpp:
+ Use boundImageTo instead of ugly hack.
+ * kview.{h.cpp}:
+ New method loadFromStdin().
+ * main.cpp:
+ If args is - load image from stdin.
+ * Makefile.am:
+ remove kviewviewer files from messages target
+ * Makefile.am:
+ remove kviewcanvas files from messages target
+
+2003-07-11 Matthias Kretz <kretz@kde.org>
+
+ * kviewviewer/kviewviewer.cpp:
+ Use KMimeType::findByFileContent if KImageIO::type fails to
+ get the type.
+
+2003-06-14 Matthias Kretz <kretz@kde.org>
+
+ * kimageviewer/canvas.h:
+ New method boundImageTo( QSize ). Makes fit image to widget
+ size a lot nicer.
+ * kview.cpp, kviewviewer/kviewviewer.cpp:
+ Use the new boundImageTo() method.
+
+2003-05-01 Matthias Kretz <kretz@kde.org>
+
+ * kview.cpp:
+ New method loadFromStdin() that reads the image from stdin
+ into a QByteArray constructs a QImage and passes that to
+ KImageViewer::Viewer::newImage().
+ * main.cpp:
+ Check for args-url(0) being "-" and open image from stdin
+ then.
+
+2003-04-10 Matthias Kretz <kretz@kde.org>
+
+ * modules/presenter/kviewpresenter.cpp:
+ Allow drops of KURLDrags on the main view, too. This is done
+ by the KViewPresenter installing an event filter on the
+ m_pViewer->widget() and handling them just like the drops on
+ the image list.
+
+2003-04-03 Matthias Kretz <kretz@kde.org>
+
+ * modules/presenter/kviewpresenter.cpp:
+ s/QUriDrag/KURLDrag/
+
+2003-03-09 Matthias Kretz <kretz@kde.org>
+
+ * modules/effects/kvieweffects.cpp:
+ Initialize m_intensity and m_lastintensity.
+
+2003-03-07 Matthias Kretz <kretz@kde.org>
+
+ * modules/effects/kvieweffects.{cpp,h,rc}:
+ New effect: "Change Intensity". Uses KImageEffect::intensity()
+ with configurable, guess what, intensity.
+ Added helper function workImage() to copy the canvas' image
+ into m_image and create a detached QImage to apply the effect
+ on.
+ * modules/effects/kvieweffects.cpp:
+ Call setModified( true ) on the Viewer so that saving the
+ image will work correctly
+ * modules/effects/kvieweffects.{cpp,h,rc}:
+ New effect: "Blend Color". Uses KImageEffect::blend() with
+ configurable color and opacity.
+
+2003-03-06 Matthias Kretz <kretz@kde.org>
+
+ * modules/effects/*:
+ New module: KViewEffects. I implemented a simple gamma
+ correction filter using KIconEffect::toGamma().
+ * kview.desktop:
+ Changed MimeType field to support pbm, pnm, ppm and pgm.
+ Is the image/x-png still needed?
+
+2003-03-04 Matthias Kretz <kretz@kde.org>
+
+ * TODO:
+ added the architectural thoughts I had today
+ * ChangeLog:
+ started a ChangeLog (like you can see)
+
+# vim: sw=4 ts=4 tw=80 noet
diff --git a/kview/Makefile.am b/kview/Makefile.am
new file mode 100644
index 00000000..2acb3133
--- /dev/null
+++ b/kview/Makefile.am
@@ -0,0 +1,25 @@
+SUBDIRS = kimageviewer . config kviewcanvas kviewviewer modules photobook
+
+INCLUDES = -I$(top_srcdir)/kview $(all_includes)
+
+METASOURCES = AUTO
+
+bin_PROGRAMS =
+lib_LTLIBRARIES =
+kdeinit_LTLIBRARIES = kview.la
+
+noinst_HEADERS = kview.h
+
+kview_la_SOURCES = kview.cpp main.cpp
+kview_la_LDFLAGS = $(KDE_RPATH) $(all_libraries) -module -avoid-version
+kview_la_LIBADD = $(LIB_KPARTS) $(LIB_KUTILS)
+
+xdg_apps_DATA = kview.desktop
+
+KDE_ICON = kview
+
+rcdir = $(kde_datadir)/kview
+rc_DATA = kviewui.rc
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp *.h -o $(podir)/kview.pot
diff --git a/kview/TODO b/kview/TODO
new file mode 100644
index 00000000..e8515db1
--- /dev/null
+++ b/kview/TODO
@@ -0,0 +1,73 @@
+- regression: did the last change from bmeyer break resize handling when the
+ statusbar is shown/hidden? How can it be fixed if not reverted?
+
+- KView Canvas Widget
+ - alpha blending
+ - faster zooming (how? perhaphs I can create smaller pixmaps and only the ones visible are
+ really calculated and shown)
+ - partial loading
+
+- Configuration Dlg
+
+- Printing
+ - Gibt es einen Befehl, mit dem man z.B. Fotogre 9x13 bzw. 10x15 eingeben
+ kann? (option in printing dialog to select photo size 9x13, 10x15)
+ - print in original size (look at dpi info in image file if present and
+ allow the user to override the value)
+
+- Architectural stuff
+ - Add "playlist" to the imageviewer interface:
+ The Viewer should support, somehow, that a list of images is to be shown as
+ a slideshow. Plugins can then work with that "playlist" instead of messing
+ around with internals like the presenter plugin does.
+ - This would make preloading (and caching) the images possible.
+ - Caching: currently the canvas doesn't do anything with files while the
+ viewer only calls QImage( QByteArray ) or QImage( filename ). Therefor the
+ Viewer has to cache the loading of images while the canvas would have to
+ cache the zoomed images and pixmaps.
+ It would be no problem to make the canvas work on files and bytearrays
+ (with the additional way of passing QImages) and make the Viewer only use
+ the Canvas' functionality in working with images. The Viewer would
+ basically rely on the canvas for most of the work.
+
+- Effects Plugin:
+ - Good enough for now, but if this plugin should support more effects I
+ should think about creating an interface for effect classes:
+ Something like:
+ class Effect
+ {
+ QString dialogTitle() const = 0;
+ QWidget * dialogWidget() = 0;
+ /* @returns whether @ref applyEffect() would create the same image as
+ * last time or a changed one */
+ bool changed() const = 0;
+ void applyEffect( QImage & ) = 0;
+ };
+ - Brightness Adjustment
+ - Greyscale conversion
+ - Smoothing
+
+- Image info
+
+- Handle resizing of the image area using an event filter? Instead of calling
+ handleResize() everywhere it could resize the image area this would always
+ call the function when the image area resizes (if it works).
+
+- show modified state in titlebar
+
+- new config option to set KView into read-only mode: remove all edit
+ functionality and use the ReadOnly KPart. This disables the annoying question
+ whether you want to save changes when all you wanted to do was to look at the
+ image from a different angle :-)
+
+- If an image is deleted but hasn't changed in the viewer it might happen that
+ you can't save the file again.
+ KView should stat the file and if it's deleted save it regardless of whether
+ the image was modified or not.
+
+- move the configuration of resize handling into a menu and remove it from the
+ configuration dialog (or should it be kept - dunno)
+
+- config option to always rotate the image so that it's shown with maximum size
+
+# vim: sw=4 ts=4 tw=80
diff --git a/kview/config/Makefile.am b/kview/config/Makefile.am
new file mode 100644
index 00000000..84f5aabd
--- /dev/null
+++ b/kview/config/Makefile.am
@@ -0,0 +1,21 @@
+SUBDIRS = . plugins
+INCLUDES = $(all_includes)
+
+METASOURCES = AUTO
+
+kde_module_LTLIBRARIES = kcm_kviewgeneralconfig.la
+
+noinst_HEADERS = kviewconfmodules.h
+
+kcm_kviewgeneralconfig_la_SOURCES = kviewconfmodules.cpp
+kcm_kviewgeneralconfig_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kcm_kviewgeneralconfig_la_LIBADD = $(LIB_KDEUI)
+
+kcm_kviewgeneralconfig_DATA = kviewgeneralconfig.desktop
+kcm_kviewgeneralconfigdir = $(kde_servicesdir)/kconfiguredialog
+
+kviewappdatadir = $(kde_datadir)/kview
+kviewappdata_DATA = kview.setdlg
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp *.h -o $(podir)/kcm_kviewgeneralconfig.pot
diff --git a/kview/config/kview.setdlg b/kview/config/kview.setdlg
new file mode 100644
index 00000000..99347b8f
--- /dev/null
+++ b/kview/config/kview.setdlg
@@ -0,0 +1,219 @@
+[Viewer]
+Name=Viewer
+Name[ar]=العارض
+Name[bg]=Визуализатор
+Name[br]=Gweler
+Name[bs]=Preglednik
+Name[ca]=Visualitzador
+Name[cs]=Prohlížeč
+Name[cy]=Gwelydd
+Name[da]=Fremviser
+Name[de]=Betrachter
+Name[el]=Προβολέας
+Name[eo]=Rigardilo
+Name[es]=Visor
+Name[et]=Näitaja
+Name[eu]=Ikustailua
+Name[fa]=مشاهده‌گر
+Name[fi]=Näytin
+Name[fr]=Afficheur
+Name[gl]=Visor
+Name[he]=מציג
+Name[hi]=प्रदर्शक
+Name[hu]=Nézegető
+Name[is]=Birtir
+Name[it]=Visore
+Name[ja]=ビューア
+Name[kk]=Кескінді қарау
+Name[km]=កម្មវិធី​មើល
+Name[lt]=Žiūriklis
+Name[ms]=Pemapar
+Name[nb]=Fremviser
+Name[nds]=Kieker
+Name[ne]=दर्शक
+Name[nl]=Weergaveprogramma
+Name[nn]=Framvisar
+Name[pa]=ਦਰਸ਼ਕ
+Name[pl]=Przeglądarka obrazków
+Name[pt]=Visualizador
+Name[pt_BR]=Visualizador
+Name[ro]=Vizualizor
+Name[ru]=Просмотрщик
+Name[se]=Čájeheaddji
+Name[sk]=Prehliadač
+Name[sl]=Pregledovalnik
+Name[sr]=Приказивач
+Name[sr@Latn]=Prikazivač
+Name[sv]=Visning
+Name[ta]=காட்சி
+Name[tg]=Намоишгар
+Name[tr]=Görüntüleyici
+Name[uk]=Переглядач
+Name[uz]=Koʻruvchi
+Name[uz@cyrillic]=Кўрувчи
+Name[wa]=Håyneu
+Name[zh_CN]=查看器
+Name[zh_HK]=檢視器
+Comment=This is the configuration for the part of KView that can be reused by other applications (meaning that the settings will also affect the KView part that gets embedded into Konqueror or other applications).
+Comment[ar]=هذه الإعدادات هي لجزء برنامج KView الذي يدمج في داخل متصفح Konqueror والبرامج الأخرى
+Comment[bg]=Настройване на модулите на KView, които могат да бъдат използвани в другите програми. Това означава, че настройките ще имат ефект навсякъде, където се използва съответния модул.
+Comment[bs]=Ovo je konfiguracija dijela KView-a kojeg mogu koristiti druge aplikacije (što znači da će se ove postavke takođe odraziti na KView dio koji se ugrađuje u Konqueror i druge aplikacije).
+Comment[ca]=Aquesta és la configuració de la part de KView que es pot reutilitzar per altres aplicacions (vol dir que els paràmetres també afectaran la part KView que està incrustada dins el Konqueror o altres aplicacions).
+Comment[cs]=Toto je konfigurace komponenty KView, kterou lze použít v jiným aplikacích. To znamená, že nastavení ovlivní také aplikace, které tuto komponentu používají, např. Konqueror.
+Comment[da]=Dette er indstillingen for den del af KView der kan genbruges af andre programmer (hvilket detyder at opsætningen også vil påvirke den KView-part der bliver indlejret i Konqueror eller andre programmer).
+Comment[de]=Dies sind die Einstellungen für die KView-Komponente, die von anderen Anwendungen verwendet werden kann. Das bedeutet, dass diese Einstellungen auch die KView-Komponente betreffen, die in Konqueror und andere Anwendungen eingebettet wird.
+Comment[el]=Αυτή είναι η ρύθμιση του τμήματος του KView που μπορεί να χρησιμοποιηθεί και από άλλες εφαρμογές (που σημαίνει ότι οι ρυθμίσεις θα επηρεάσουν επίσης το τμήμα του KView που ενσωματώνεται στον Konqueror ή σε άλλες εφαρμογές).
+Comment[es]=Esta la configuración para la parte de KView que puede ser reutilizada por otras aplicaciones (teniendo en consideración que las preferencias también afectarán a la parte incrustada en Konqueror o en otras aplicaciones).
+Comment[et]=Siin saab seadistada KView seda osa, mida saavad kasutada ka teised rakendused (see tähendab, et siinmääratu mõjutab ka seda, mida teeb Konquerori või muudesse rakendustesse põimitud KView komponent).
+Comment[eu]=Hau da KView-en beste aplikazioek aprobetxa dezaketenaren konfigurazioa (hau da, ezarpen hauek Konqueror-ek edo beste aplikazioek erabiltzen duten KView-en zatietan eragingo dute)
+Comment[fa]= این پیکربندی برای جزئی از KView است که می‌توان آن را توسط کاربردهای دیگر مجدداً استفاده کرد )یعنی این که تنظیمات هم بر جزئی از KView که در Konqueror یا کاربردهای دیگر نهفته می‌‌شود، اثر می‌گذارد).
+Comment[fi]=Nämä asetukset ovat KView-ohjelman osalle, jota voidaan käyttää muissa sovelluksissa (asetukset vaikuttavat KView-sovellukseen, joka upotetaan eri ohjelmiin, kuten Konqueroriin)
+Comment[fr]=C'est la configuration pour la partie de KView qui peut être réutilisée par les autres applications (ce qui signifie que les réglages affecteront aussi le composant KView qui est intégré dans Konqueror ou les autres applications).
+Comment[gl]=Esta é a configuración para as partes de KView que poden ser rempregadas por otras aplicacións (Isto é que as configuracións que afectán a KView tamén o farán coa parte deste integrada en Konqueror ou noutras aplicaccións).
+Comment[hu]=Ezek a KView beágyazható, más alkalmazásokban felhasználható változatának beállításai (tehát a beállítások kihatással vannak a Konquerorba és más alkalmazásokba beágyazott megjelenítőkre).
+Comment[is]=Þetta eru stillingar þess hluta KView sem önnur forrit geta notað (sem þýðir að þessar stillingar hafa einnig áhrif á KView hlutann sem er byggður inn í Konqueror og önnur forrit).
+Comment[it]=Questa è la configurazione per il componente di KView riutilizzabile da altre applicazioni (cioè le impostazioni avranno effetto per il componente KView integrabile in Konqueror e altre applicazioni).
+Comment[ja]=これは他のアプリケーションでも利用される、KView の一部分の設定です。(この設定は Konqueror や他のアプリケーションに埋め込まれる KView にも影響を与えます)
+Comment[kk]=Бұл басқа бағдарламалар қолдана алатын KView бөлшегінің баптауы (баптаулары Konqueror не басқа қолданбалардың құрамына ендірілетін KView бөлшегіне де тиісті).
+Comment[km]=នេះ​ជា​ការ​កំណត់​រចនាសម្ព័ន្ធ សម្រាប់​ផ្នែក​របស់ KView ដែល​អាច​ត្រូវ​បាន​ប្រើ​ម្ដង​ទៀត​ដោយ​កម្មវិធី​ផ្សេង​ទៀត (មាន​ន័យ​ថា ផ្នែក KView ដែល​បាន​បង្កប់​នៅ​ក្នុង Konqueror ឬ កម្មវិធី​ផ្សេង​ទៀត) ។
+Comment[lt]=Tai yra KView konfigūracija, kuri gali būti naudojama ir kitų programų (tai yra, šie nustatymai taip pat bus naudojami ir KView programiniam moduliui, įterpiamam į Konqueror ir kitas programas).
+Comment[ms]=Ini ialah konfigurasi sebahagian KView yang boleh diguna semula oleh aplikasi lain (bermakna seting juga akan memberikan kesan kepada bahagian KPapar yang dibenamkan dalam Konqueror atau aplikasi lain).
+Comment[nb]=Dette er oppsettet av den delen av KView som kan gjenbrukes i andre programmer. (Innstillingene her vil påvirke den KView-modulen som blir bygd inn i Konqueror eller andre programmer.)
+Comment[nds]=Dit sünd de Instellen för de KView-Komponent, de sik ok vun anner Programmen bruken lett. Dat bedüüdt, dat disse Instellen ok de KView-Komponent bedraapt, de in Konqueror oder anner Programmen inbett sünd.
+Comment[ne]=अन्य अनुप्रयोगद्वारा पुन: प्रयोग गर्न सक्ने केडीई दर्शकको भागका लागि यो कन्फिगरेसन हो ( अन्य अनुप्रयोग वा कन्क्वेररमा सम्मिलित के दर्शकको भागलाई पनि प्रभाव पार्ने सेटिङ भन्ने बुझिन्छ )
+Comment[nl]=Dit zijn de instellingen van het onderdeel van KView dat ook door andere toepassingen gebruikt kan worden. Deze instellingen betreffen dus ook de KView Part zoals die in Konqueror of andere toepassingen kan worden ingebed.
+Comment[nn]=Dette er oppsettet av den delen av KView som kan brukast opp att i andre program. (Innstillingane her vil påverka den KView-modulen som vert bygd inn i Konqueror eller andre program.)
+Comment[pl]=To jest konfiguracja osadzonej części KView, która może być osadzana w innych programach (co oznacza, że te ustawienia będą dotyczyć również części KView osadzonej w Konquerorze lub innych programach).
+Comment[pt]=Esta é a configuração da componente do KView que poderá ser usada pelas outras aplicações (o que significa que a configuração também irá afectar a componente do KView que está incorporada no Konqueror e noutras aplicações).
+Comment[pt_BR]=Esta é a configuração para o componente do KView que pode ser reutilizado por outras aplicações (o que significa que todas as configurações afetarão também o componente do KView que obtém a integração junto com o Konqueror e outras aplicações).
+Comment[ro]=Aceasta este configurarea pentru partea KView care poate fi reutilizată de alte aplicaţii. Setările afectează acea parte de KView care este înglobată în Konqueror sau alte aplicaţii.
+Comment[ru]=Настройки компонента KView, который используется другими приложениями (устанавливают поведение компонента, внедрённого в Konqueror или другие приложения).
+Comment[sk]=Toto je konfigurácia pre KView, ktorý je možné použiť vo viacerých aplikáciách (takže zmeny tohto nastavenia sa prejavia vo všetkých aplikáciách, ktoré by KView použili, ako je Konqueror alebo iné).
+Comment[sl]=To so nastavitve za del KView, ki ga lahko uporabijo tudi drugi programi (kar pomeni, da nastavitve veljajo tudi za del KView, ki je vključen v Konqueror in druge programe).
+Comment[sr]=Ово је подешавање за део KView-а који могу користити и други програми (што значи да ће поставке утицати и на KView-ов део који се уграђује у Konqueror и друге програме).
+Comment[sr@Latn]=Ovo je podešavanje za deo KView-a koji mogu koristiti i drugi programi (što znači da će postavke uticati i na KView-ov deo koji se ugrađuje u Konqueror i druge programe).
+Comment[sv]=Det här är inställningen av den del av Kview som kan återanvändas av flera program (vilket betyder att inställningarna också påverkar Kview-delen som bäddas in i Konqueror eller andra program).
+Comment[ta]=இது கேகாட்சியின் பகுதிக்கான வடிவமைப்பு. இதை மற்ற பயன்பாடுகளுக்காக திரும்ப பயன்படுத்தலாம். அந்த அமைப்புகள் கேகாட்சி பகுதியை பாதிக்கும். அந்த அமைப்புகள் கான்கொரர் அல்லது மற்ற பயன்பாடுகளிலும் பொதிந்துவிடும்.
+Comment[tg]=Танзимоти қисмати KView, ки бо дигар барномаҳо (рафтори қисматро, ки ба дохили Konqueror ҷорӣ шудааст ё дигар барномаҳоро низ танзим мекунад) истифода мешавад.
+Comment[tr]=Bu KView'in diğer programlar tarafından tekrar kullanılabilecek ayarlarıdır (Bu KView'in Konqueror veya diğer programlar altında çalışan gömülü parçalarını da etkiler).
+Comment[uk]=Це параметри складової KView, які можуть бути використані багатьма програмами (тобто, зміни значень цих параметрів будуть впливати на складову KView вмонтовану у Konqueror та інші програми).
+Comment[zh_CN]=这是可被其它应用程序重用的 KView 部分的配置(这意味着,这里的设置也会影响嵌入到 Konqueror 或其它应用程序中的 KView 部分)。
+Comment[zh_HK]=這是可復用於其他應用程式的 KView 設定的一部份(意即設置會同時影響嵌入到 Konqueror 或其他應用程式的 KView 部份)。
+Comment[zh_TW]=這部份的 KView 設定可被其他應用程式一起使用,(也就是說這裡的設定也會影響其他應用程式)。
+Weight=1
+[Application]
+Name=Application
+Name[ar]=التطبيق
+Name[az]=Proqram
+Name[bg]=Програма
+Name[br]=Arload
+Name[bs]=Program
+Name[ca]=Aplicació
+Name[cs]=Aplikace
+Name[cy]=Cymhwysiad
+Name[da]=Program
+Name[de]=Anwendung
+Name[el]=Εφαρμογή
+Name[eo]=Aplikaĵo
+Name[es]=Aplicación
+Name[et]=Rakendus
+Name[eu]=Aplikazioa
+Name[fa]=کاربرد
+Name[fi]=Sovellus
+Name[ga]=Feidhmchlár
+Name[gl]=Aplicación
+Name[he]=יישום
+Name[hi]=अनुप्रयोग
+Name[hr]=Program
+Name[hu]=Alkalmazás
+Name[id]=Aplikasi
+Name[is]=Forrit
+Name[it]=Applicazione
+Name[ja]=アプリケーション
+Name[kk]=Қолданба
+Name[km]=កម្មវិធី
+Name[lt]=Programa
+Name[lv]=Aplikācija
+Name[mk]=Апликација
+Name[ms]=Aplikasi
+Name[mt]=Programm
+Name[nb]=Program
+Name[nds]=Programm
+Name[ne]=अनुप्रयोग
+Name[nl]=Toepassing
+Name[nn]=Program
+Name[pa]=ਕਾਰਜ
+Name[pl]=Program
+Name[pt]=Aplicação
+Name[pt_BR]=Aplicativo
+Name[ro]=Aplicaţie
+Name[ru]=Приложение
+Name[rw]=Porogaramu
+Name[se]=Prográmma
+Name[sk]=Aplikácia
+Name[sl]=Program
+Name[sr]=Програм
+Name[sr@Latn]=Program
+Name[sv]=Program
+Name[ta]=பயன்பாடு
+Name[tg]=Барнома
+Name[th]=แอพพลิเคชัน
+Name[tr]=Uygulama
+Name[uk]=Програма
+Name[uz]=Dastur
+Name[uz@cyrillic]=Дастур
+Name[ven]=Apulifikhesheni
+Name[wa]=Programe
+Name[xh]=Isicelo
+Name[zh_CN]=应用程序
+Name[zh_HK]=應用程式
+Name[zh_TW]=應用程式
+Name[zu]=Isicelo
+Comment=Here you can set options that are special for the KView application when running stand-alone. What you change in here will not affect other applications.
+Comment[ar]=هنا يمكنك اختار الاختيارات الخاصة بتطبيق KView المستقل. أي تغيير هنا لن يؤثر على التطبيقات الأخرى.
+Comment[bg]=Настройване на самостоятелната програма KView. Това означава, че настройките ще имат ефект само за програмата KView и останалите програми, които ползват същите модули, няма да бъдат повлияни.
+Comment[bs]=Ovdje možete podesiti opcije koje su specifične za KView samostalnu aplikaciju. Ono što ovdje promijenite se neće odraziti na druge aplikacije.
+Comment[ca]=Aquí podeu establir les opcions específiques de l'aplicació KView quan s'executa autonomament. El que es canviï aquí no afectarà a les altres aplicacions.
+Comment[cs]=Zde vidíte možnosti, které jsou specifické pro samostatnou aplikaci KView. Změny zde neovlivní ostatní aplikace.
+Comment[cy]=Yma gallwch osod dewisiadau sy'n arbennig i'r cymhwysiad KGweld tra'n rhedeg yn arunigol. Ni fydd y newidiadau a wneir yma yn effeithio cymwysiadau eraill.
+Comment[da]=Her kan du sætte de valgmuligheder der er specielle for KView-programmet når det køres alenestående. Det du ændrer her vil ikke påvirke andre programmer.
+Comment[de]=Hier können Sie Einstellungen festlegen, die nur für die Anwendung KView gelten. Hier vorgenommene Änderungen betreffen keine andere Anwendung.
+Comment[el]=Εδώ μπορείτε να ορίσετε επιλογές που αφορούν την εφαρμογή KView όταν εκτελείται μόνη της. Ότι αλλάξετε εδώ δε θα επηρεάσει άλλες εφαρμογές.
+Comment[es]=Aquí puede establecer las opciones para KView cuando este se ejecute de modo independiente. Los cambios realizados aquí no afectarán a otras aplicaciones.
+Comment[et]=Siin saab määrata seadistusi, mis toimivad ainult siis, kui KView on käivitatud iseseisva rakendusena. Siinmääratav ei mõjuta seda, kuidas KView komponent toimib muudes rakendustes.
+Comment[eu]=Hemen KView-erako bereziak diren aukerak ezar ditzakezu. Hemen alda dezakezunak ez du eraginik izanen beste aplikazioetan
+Comment[fa]=در اینجا هنگام اجرای خوداتکا می‌توانید گزینه‌هایی را که برای کاربرد KView ویژه هستند را تنظیم کنید. آنچه در اینجا تغییر می‌دهید بر کاربردهای دیگر اثر نمی‌گذارد.
+Comment[fi]=Tästä voidaan asettaa omia asetuksia erilliselle KView-sovellukselle. Nämä asetukset eivät vaikuta muihin sovelluksiin.
+Comment[fr]=Ici, vous pouvez déterminer les options spéciales pour l'application KView lorsqu'elle fonctionne isolément. Ce que vous changez ici n'affectera pas les autres applications.
+Comment[gl]=Elixe aquí as opcións especiais para KView cando funciona por si mesma. O que cambies neste lugar non afectará a outras aplicacións.
+Comment[hu]=Itt a KView önállóan futtatható változatára érvényes beállításokat lehet módosítani. Ezek a beállítások tehát nem befolyásolják más alkalmazások működését.
+Comment[is]=Hér getur þú stillt eiginleika KView forritsins þegar það keyrir eitt og sér. Stillingar hér hafa engin áhrif á önnur forrit.
+Comment[it]=Qui puoi impostare le opzioni che riguardano l'applicazione KView quando è eseguita da sola. Quello che cambi qui non ha effetto in altre applicazioni.
+Comment[ja]=ここではスタンドアロンで実行される KView 用のオプションを設定します。ここでの変更は他のアプリケーションに影響を及ぼしません。
+Comment[kk]=Бұл жеке-дара KView қолданбаның баптауы. Басқа қолданбаларға бұның әсері жоқ.
+Comment[km]=នៅ​ទីនេះ អ្នក​អាច​កំណត់​ជម្រើស​ពិសេសៗ​សម្រាប់​កម្មវិធី KView នៅ​ពេល​វា​រត់​តែ​ឯង ។ អ្វី​ដែល​អ្នក​ផ្លាស់ប្ដូរ​នៅ​ទីនេះ នឹង​មិន​ប៉ះពាល់​ដល់​កម្មវិធី​ផ្សេង​ទៀត​ឡើយ ។
+Comment[lt]=Čia galite nustatyti parinktis, kurios bus naudojamos tik tuo atveju, jei KView veikia kaip nepriklausoma programa. Čia atlikti pakeitimai nepakeis kitų programų darbo.
+Comment[ms]=Di sini anda boleh set opsyen yang khas kepada aplikasi KView apabila dilancar secara tunggal. Apa yang anda ubah di sini tidak akan memberikan kesan kepada aplikasi lain.
+Comment[nb]=Her finner du innstillinger som bare påvirker KView som frittstående program. Disse innstillingene har ingenting å si for andre programmer.
+Comment[nds]=Hier laat sik de Instellen fastleggen, de bloots för dat KView-Enkelprogramm gellt. Wat Du hier ännerst, bedröppt keen anner Programmen.
+Comment[ne]=यहाँ तपाईँले स्यान्ड अलोन चलिरहेको बेलामा केडीई दृश्य अनुप्रयोगका लागि विशेष विकल्प सेट गर्न सक्नुहुन्छ । तपाईँको यहाँको परिवर्तनले अन्य अनुप्रयोगलाई प्रभाव पार्ने छैन ।
+Comment[nl]=Deze instellingen gelden alleen voor de KView-toepassing op zichzelf. Wat u hier instelt heeft geen invloed op andere toepassingen.
+Comment[nn]=Her finn du innstillingar som berre påverkar KView som frittståande program. Desse innstillingane har ingenting å seia for andre program.
+Comment[pl]=Tutaj można zmienić ustawienia, które będą używane, gdy KView jest uruchamiane jako oddzielny program. Zmiany dokonane tutaj nie będą miały wpływu na inne programy.
+Comment[pt]=Aqui você poderá definir as opções que são específicas para a aplicação KView quando corre autonomamente. O que você alterar aqui não irá afectar as outras aplicações.
+Comment[pt_BR]=Aqui você pode configurar as opções que são especiais para o KView, quando estiver rodando independentemente. O que você mudar aqui não afetará outras aplicações.
+Comment[ro]=Aici puteţi seta opţiuni care sînt specifice aplicaţiei KView de sine stătătoare. Cînd le modificaţi celelalte aplicaţii nu vor fi afectate.
+Comment[ru]=Настройки приложения KView, запущенного отдельно. Эти настройки не касаются других приложений, в которые внедряется компонент KView.
+Comment[sk]=Tu môžete nastaviť voľby, ktoré sú špeciálne pre samostatnú aplikáciu KView. Čo zmeníte tu neovplyvní ostatné aplikácie.
+Comment[sl]=Tu lahko nastavite možnosti, ki so posebne samo za program KView, ko teče samostojno. Kar spremenite tu, se ne bo poznalo v drugih programih.
+Comment[sr]=Овде можете поставити опције које су посебне за програм KView, када се он извршава самостално. Оно што овде промените неће утицати на друге програме.
+Comment[sr@Latn]=Ovde možete postaviti opcije koje su posebne za program KView, kada se on izvršava samostalno. Ono što ovde promenite neće uticati na druge programe.
+Comment[sv]=Här kan du ställa in alternativ som bara gäller för Kview-programmet när det körs själv. Det du ändrar här påverkar inte andra program.
+Comment[ta]=தனியான இயக்கத்தின்போது கேகாட்சிக்கான விசேஷ தேர்வுகளை இங்கே அமைக்கலாம். நீங்கள் இங்கே செய்யும் மாற்றங்கள் மற்ற பயன்பாடுகளை பாதிக்காது.
+Comment[tg]=Танзимоти барномаи KView, ки ҷудо оғоз шуда буд. Ин танзимотҳо дигар барномаҳоро, ки дар он қисмати KView дохил мешавад дар бар намегирад.
+Comment[tr]=Burada KView programı yanlız (standalone) çalışırken özel olan seçeneklerinizi belirleyebilirsiniz. Burada yaptığınız değişiklikler diğer programları etkilemeyecektir.
+Comment[uk]=Тут ви можете встановити значення параметрів для програми KView, коли вона виконується окремо. Зміни тут не будуть впливати на інші програми.
+Comment[zh_CN]=您可在此设定 KView 应用程序以独立形式运行时的特殊选项。您在此所在的更改不会影响其它应用程序。
+Comment[zh_HK]=在此你可設定專用於當獨立使用的 KView 應用程式的選項。你在此更改不會影響其他應用程式。
+Comment[zh_TW]=您可以在此設定 KView 應用程式單獨執行時的選項。您在這裡的設定不會影響其他應用程式。
+Weight=5
diff --git a/kview/config/kviewconfmodules.cpp b/kview/config/kviewconfmodules.cpp
new file mode 100644
index 00000000..23f6a1ef
--- /dev/null
+++ b/kview/config/kviewconfmodules.cpp
@@ -0,0 +1,90 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002-2003 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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 "kviewconfmodules.h"
+
+#include <qlayout.h>
+#include <qvbuttongroup.h>
+#include <qradiobutton.h>
+
+#include <klocale.h>
+#include <kdialog.h>
+#include <kglobal.h>
+#include <kconfig.h>
+#include <kgenericfactory.h>
+#include <qwhatsthis.h>
+
+typedef KGenericFactory<KViewGeneralConfig, QWidget> KViewGeneralConfigFactory;
+K_EXPORT_COMPONENT_FACTORY( kcm_kviewgeneralconfig, KViewGeneralConfigFactory( "kcm_kviewgeneralconfig" ) )
+
+KViewGeneralConfig::KViewGeneralConfig( QWidget * parent, const char * /*name*/, const QStringList & args )
+ : KCModule( KViewGeneralConfigFactory::instance(), parent, args )
+{
+ QBoxLayout * layout = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
+
+ m_pResizeGroup = new QVButtonGroup( i18n( "Resizing" ), this );
+ m_pResizeGroup->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) );
+ connect( m_pResizeGroup, SIGNAL( clicked( int ) ), this, SLOT( resizeChanged( int ) ) );
+ layout->addWidget( m_pResizeGroup );
+
+ ( void )new QRadioButton( i18n( "Only resize window" ), m_pResizeGroup );
+ ( void )new QRadioButton( i18n( "Resize image to fit window" ), m_pResizeGroup );
+ ( void )new QRadioButton( i18n( "Don't resize anything" ), m_pResizeGroup );
+ QWhatsThis::add( new QRadioButton( i18n( "Best fit" ), m_pResizeGroup ),
+ i18n( "<p>KView will resize the window to fit the image. The image will never be scaled up but if it is too large for the screen the image will be scaled down.</p>" ) );
+
+ load();
+}
+
+KViewGeneralConfig::~KViewGeneralConfig()
+{
+}
+
+void KViewGeneralConfig::save()
+{
+ KConfigGroup cfgGroup( KGlobal::config(), "KView General" );
+ m_savedPosition = m_pResizeGroup->id( m_pResizeGroup->selected() );
+ cfgGroup.writeEntry( "Resize Mode", m_savedPosition );
+ emit changed( false );
+ KGlobal::config()->sync();
+}
+
+void KViewGeneralConfig::load()
+{
+ KConfigGroup cfgGroup( KGlobal::config(), "KView General" );
+ int m_savedPosition = cfgGroup.readNumEntry( "Resize Mode", 2 );
+ if( m_savedPosition < 0 || m_savedPosition > 3 )
+ m_savedPosition = 2;
+ m_pResizeGroup->setButton( m_savedPosition );
+ emit changed( false );
+}
+
+void KViewGeneralConfig::defaults()
+{
+ m_pResizeGroup->setButton( 2 );
+ emit changed( ( 2 != m_savedPosition ) );
+}
+
+void KViewGeneralConfig::resizeChanged( int pos )
+{
+ emit changed( ( pos != m_savedPosition ) );
+}
+
+// vim:sw=4:ts=4
+
+#include "kviewconfmodules.moc"
diff --git a/kview/config/kviewconfmodules.h b/kview/config/kviewconfmodules.h
new file mode 100644
index 00000000..d064b386
--- /dev/null
+++ b/kview/config/kviewconfmodules.h
@@ -0,0 +1,47 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002-2003 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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 KVIEWCONFMODULES_H
+#define KVIEWCONFMODULES_H
+
+#include <kcmodule.h>
+
+class QVButtonGroup;
+
+class KViewGeneralConfig : public KCModule
+{
+ Q_OBJECT
+ public:
+ KViewGeneralConfig( QWidget * parent, const char * name = 0, const QStringList & args = QStringList() );
+ ~KViewGeneralConfig();
+
+ virtual void load();
+ virtual void save();
+ virtual void defaults();
+
+ private slots:
+ void resizeChanged( int );
+
+ private:
+ QVButtonGroup * m_pResizeGroup;
+ int m_savedPosition;
+};
+
+// vim:sw=4:ts=4
+
+#endif // KVIEWCONFMODULES_H
diff --git a/kview/config/kviewgeneralconfig.desktop b/kview/config/kviewgeneralconfig.desktop
new file mode 100644
index 00000000..acb6f625
--- /dev/null
+++ b/kview/config/kviewgeneralconfig.desktop
@@ -0,0 +1,131 @@
+[Desktop Entry]
+Icon=kview
+Type=Service
+ServiceTypes=KCModule
+
+X-KDE-ModuleType=Library
+X-KDE-Library=kviewgeneralconfig
+X-KDE-FactoryName=KViewGeneralConfigFactory
+X-KDE-ParentApp=kview
+X-KDE-ParentComponents=kview
+X-KDE-Weight=5
+X-KDE-CfgDlgHierarchy=Application
+
+Name=Application
+Name[ar]=التطبيق
+Name[az]=Proqram
+Name[bg]=Програма
+Name[br]=Arload
+Name[bs]=Program
+Name[ca]=Aplicació
+Name[cs]=Aplikace
+Name[cy]=Cymhwysiad
+Name[da]=Program
+Name[de]=Anwendung
+Name[el]=Εφαρμογή
+Name[eo]=Aplikaĵo
+Name[es]=Aplicación
+Name[et]=Rakendus
+Name[eu]=Aplikazioa
+Name[fa]=کاربرد
+Name[fi]=Sovellus
+Name[ga]=Feidhmchlár
+Name[gl]=Aplicación
+Name[he]=יישום
+Name[hi]=अनुप्रयोग
+Name[hr]=Program
+Name[hu]=Alkalmazás
+Name[id]=Aplikasi
+Name[is]=Forrit
+Name[it]=Applicazione
+Name[ja]=アプリケーション
+Name[kk]=Қолданба
+Name[km]=កម្មវិធី
+Name[lt]=Programa
+Name[lv]=Aplikācija
+Name[mk]=Апликација
+Name[ms]=Aplikasi
+Name[mt]=Programm
+Name[nb]=Program
+Name[nds]=Programm
+Name[ne]=अनुप्रयोग
+Name[nl]=Toepassing
+Name[nn]=Program
+Name[pa]=ਕਾਰਜ
+Name[pl]=Program
+Name[pt]=Aplicação
+Name[pt_BR]=Aplicativo
+Name[ro]=Aplicaţie
+Name[ru]=Приложение
+Name[rw]=Porogaramu
+Name[se]=Prográmma
+Name[sk]=Aplikácia
+Name[sl]=Program
+Name[sr]=Програм
+Name[sr@Latn]=Program
+Name[sv]=Program
+Name[ta]=பயன்பாடு
+Name[tg]=Барнома
+Name[th]=แอพพลิเคชัน
+Name[tr]=Uygulama
+Name[uk]=Програма
+Name[uz]=Dastur
+Name[uz@cyrillic]=Дастур
+Name[ven]=Apulifikhesheni
+Name[wa]=Programe
+Name[xh]=Isicelo
+Name[zh_CN]=应用程序
+Name[zh_HK]=應用程式
+Name[zh_TW]=應用程式
+Name[zu]=Isicelo
+Comment=Configuration for the standalone Version of KView
+Comment[ar]=اعدادات الاصدار المستقل من KView
+Comment[bg]=Настройки на главната програма
+Comment[bs]=Postavke za samostalnu verziju KView
+Comment[ca]=Configuració per a la versió independent de KView
+Comment[cs]=Nastavení samostatné verze KView
+Comment[cy]=Ffurfweddiad ar gyfer y fersiwn arunigol o KGweld
+Comment[da]=Indstilling af den alenestående udgave af KView
+Comment[de]=Einstellungen für die Anwendung KView
+Comment[el]=Ρύθμιση της standalone έκδοσης του KView
+Comment[eo]=Agordo por la aŭtonoma versio de KView
+Comment[es]=Configuración para la versión independiente de KView
+Comment[et]=KView iseseisva versiooni seadistus
+Comment[eu]=KView programaren konfigurazioa
+Comment[fa]=پیکربندی برای نسخۀ خوداتکای KView
+Comment[fi]=Asetukset itsenäiselle versiolle KView-ohjelmasta
+Comment[fr]=Configuration de la version isolée de KView
+Comment[gl]=Configuración para a versión «standalone» de KView
+Comment[he]=הגדרות עבור הגרסה העצמאית של KView
+Comment[hi]= के-व्यू के स्टैण्डएलोन संस्करण के लिए कॉन्फ़िगरेशन
+Comment[hu]=A KView önállóan futtatható verziójának beállításai
+Comment[is]=Stillingar fyrir KView
+Comment[it]=Configurazione di KView
+Comment[ja]=スタンドアロンバージョンの KView の設定
+Comment[kk]=KView бағдарламасының жеке-дара нұсқасының баптаулары
+Comment[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ​សម្រាប់​កំណែ​កម្មវិធី KView រត់​តែ​ឯង
+Comment[lt]=KView kaip nepriklausomos programos konfigūravimas
+Comment[ms]=Konfigurasi untuk Versi tunggal bagi KView
+Comment[nb]=Oppsett av den frittstående utgaven av KView
+Comment[nds]=Instellen för de Enkelverschoon vun KView
+Comment[ne]=केडीई दृश्यको स्यान्डअलोन संस्करणाका लागि कन्फिगरेसन
+Comment[nl]=Instellingen voor KView op zichzelf
+Comment[nn]=Oppsett av den frittståande utgåva av KView
+Comment[pl]=Konfiguracja KView jako osobnego programu
+Comment[pt]=Configuração da versão independente do KView
+Comment[pt_BR]=Configuração para visão independente do KView
+Comment[ro]=Configurare pentru versiunea de sine stătătoare a KView
+Comment[ru]=Настройка самостоятельного приложения KView
+Comment[se]=Heivet KView:a oktosaš veršuvnna
+Comment[sk]=Konfigurácia pre samostatnú verziu KView
+Comment[sl]=Nastavitve za samostojno različico KView
+Comment[sr]=Подешавање за самосталну верзију KView-а
+Comment[sr@Latn]=Podešavanje za samostalnu verziju KView-a
+Comment[sv]=Inställning för fristående version av Kview
+Comment[ta]=கேகாட்சியின் தனிப் பதிப்புக்கான வடிவமைப்பு
+Comment[tg]=Танзимоти барномаи мустақили KView
+Comment[tr]=KView programının yanlız sürümünün ayarları
+Comment[uk]=Налаштування KView, як окремої програми
+Comment[zh_CN]=KView 标准版本的配置
+Comment[zh_HK]=獨立版本的 KView 的設定
+Comment[zh_TW]= KView 單獨執行版本的設定
diff --git a/kview/config/plugins/Makefile.am b/kview/config/plugins/Makefile.am
new file mode 100644
index 00000000..d2169a9d
--- /dev/null
+++ b/kview/config/plugins/Makefile.am
@@ -0,0 +1,17 @@
+INCLUDES = $(all_includes)
+
+METASOURCES = AUTO
+
+kde_module_LTLIBRARIES = kcm_kviewpluginsconfig.la
+
+noinst_HEADERS = kviewpluginsconfig.h
+
+kcm_kviewpluginsconfig_la_SOURCES = kviewpluginsconfig.cpp
+kcm_kviewpluginsconfig_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kcm_kviewpluginsconfig_la_LIBADD = $(LIB_KUTILS)
+
+kcm_kviewpluginsconfig_DATA = kviewpluginsconfig.desktop
+kcm_kviewpluginsconfigdir = $(kde_servicesdir)/kconfiguredialog
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp *.h -o $(podir)/kcm_kviewpluginsconfig.pot
diff --git a/kview/config/plugins/kviewpluginsconfig.cpp b/kview/config/plugins/kviewpluginsconfig.cpp
new file mode 100644
index 00000000..e093366c
--- /dev/null
+++ b/kview/config/plugins/kviewpluginsconfig.cpp
@@ -0,0 +1,46 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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 "kviewpluginsconfig.h"
+
+#include <kpluginselector.h>
+#include <kgenericfactory.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <ksimpleconfig.h>
+#include <kplugininfo.h>
+
+typedef KGenericFactory<KViewPluginsConfig, QWidget> KViewPluginsConfigFactory;
+K_EXPORT_COMPONENT_FACTORY( kcm_kviewpluginsconfig, KViewPluginsConfigFactory( "kcm_kviewpluginsconfig" ) )
+
+KViewPluginsConfig::KViewPluginsConfig( QWidget * parent, const char *, const QStringList & args )
+ : KSettings::PluginPage( KViewPluginsConfigFactory::instance(), parent, args )
+{
+ m_config = new KSimpleConfig( "kviewrc" );
+ pluginSelector()->addPlugins( QString::fromAscii( "kview" ), i18n( "Application" ), QString::null, m_config );
+ pluginSelector()->setShowEmptyConfigPage( false );
+}
+
+KViewPluginsConfig::~KViewPluginsConfig()
+{
+ delete m_config;
+}
+
+// vim: sw=4 ts=4 noet
+
+#include "kviewpluginsconfig.moc"
diff --git a/kview/config/plugins/kviewpluginsconfig.desktop b/kview/config/plugins/kviewpluginsconfig.desktop
new file mode 100644
index 00000000..492b962c
--- /dev/null
+++ b/kview/config/plugins/kviewpluginsconfig.desktop
@@ -0,0 +1,118 @@
+[Desktop Entry]
+Icon=plugin
+Type=Service
+ServiceTypes=KCModule
+
+X-KDE-ModuleType=Library
+X-KDE-Library=kviewpluginsconfig
+X-KDE-FactoryName=KViewPluginsConfigFactory
+X-KDE-ParentApp=kview
+X-KDE-ParentComponents=kview
+X-KDE-Weight=6
+X-KDE-CfgDlgHierarchy=Application
+
+Name=Plugins
+Name[ar]=البرامج المساعدة
+Name[bg]=Приставки
+Name[br]=Lugantoù
+Name[bs]=Dodaci
+Name[ca]=Connectors
+Name[cs]=Moduly
+Name[cy]=Ategion
+Name[da]=Plugin
+Name[de]=Module
+Name[el]=Πρόσθετα
+Name[eo]=Kromaĵoj
+Name[es]=Extensiones
+Name[et]=Pluginad
+Name[eu]=Pluginak
+Name[fa]=وصله‌ها
+Name[fi]=Liitännäiset
+Name[fr]=Modules externes
+Name[ga]=Breiseáin
+Name[he]=תוספים
+Name[hi]=प्लगइन्स
+Name[hr]=Umetci
+Name[hu]=Bővítőmodulok
+Name[is]=Íforrit
+Name[it]=Plugin
+Name[ja]=プラグイン
+Name[kk]=Плагин модулі
+Name[km]=កម្មវិធី​ជំនួយ
+Name[lt]=Priedai
+Name[ms]=Plugin
+Name[nb]=Programtillegg
+Name[nds]=Modulen
+Name[ne]=प्लगइन
+Name[nn]=Programtillegg
+Name[pa]=ਪਲੱਗਿੰਨ
+Name[pl]=Wtyczki
+Name[pt]='Plugins'
+Name[ro]=Module
+Name[ru]=Модули
+Name[rw]=Amacomeka
+Name[se]=Lassemoduvllat
+Name[sk]=Moduly
+Name[sl]=Vstavki
+Name[sr]=Прикључци
+Name[sr@Latn]=Priključci
+Name[sv]=Insticksprogram
+Name[ta]=சொருகுப்பொருள்
+Name[tg]=Модулҳо
+Name[tr]=Eklentiler
+Name[uk]=Втулки
+Name[uz]=Plaginlar
+Name[uz@cyrillic]=Плагинлар
+Name[wa]=Tchôke-divins
+Name[zh_CN]=插件
+Name[zh_HK]=插件
+Name[zh_TW]=外掛程式
+Comment=Choose and Configure Your Plugins
+Comment[bg]=Избор и настройване на приставки
+Comment[br]=Dibabit ha kefluniut ho lugentoù
+Comment[bs]=Izaberite i podesite vaše dodatke
+Comment[ca]=Escolliu i configureu els connectors
+Comment[cs]=Zvolte a nastavte si moduly
+Comment[da]=Vælg og indstil dine plugin
+Comment[de]=Auswahl und Einrichtung der Module
+Comment[el]=Επιλέξτε και ρυθμίστε τα πρόσθετα σας
+Comment[eo]=Elektu kaj agordu viajn kromprogramojn
+Comment[es]=Seleccione y configure sus extensiones
+Comment[et]=Pluginate valimine ja seadistamine
+Comment[eu]=Aukeratu eta konfigurau zure pluginak
+Comment[fa]=وصله‌های خود را انتخاب و پیکربندی کنید
+Comment[fi]=Valitse ja muokkaa liitännäisten asetuksia
+Comment[fr]=Choisissez et configurez vos modules externes
+Comment[gl]=Elexir e Configurar as súas Extensións
+Comment[he]=בחר והגדר את התוספים שלך
+Comment[hu]=Bővítőmodulok kiválasztása, beállítása
+Comment[is]=Velja og stilla íforrit
+Comment[it]=Scegli e configura i tuoi plugin
+Comment[ja]=プラグインを選択して設定します
+Comment[kk]=Плагин модулін таңдап алып баптау
+Comment[km]=ជ្រើស និង​កំណត់​រចនាសម្ព័ន្ធ​កម្មវិធី​ជំនួយ​របស់​អ្នក
+Comment[lt]=Pasirinkite ir konfigūruokite priedus
+Comment[ms]=Pilih dan Konfigur Plugin Anda
+Comment[nb]=Velg og sett opp programtilleggene
+Comment[nds]=Dien Modulen utsöken un instellen
+Comment[ne]=तपाईँको प्लगइन रोज्नुहोस् र कन्फिगर गर्नुहोस्
+Comment[nl]=Kies uw plugins en stel ze in
+Comment[nn]=Vel og set opp programtillegga
+Comment[pl]=Wybór i konfiguracja wtyczek
+Comment[pt]=Escolha e Configure os 'Plugins'
+Comment[pt_BR]=Escolha e Configure os Seus Plugins
+Comment[ro]=Alegeţi şi configuraţi modulele dumneavoastră
+Comment[ru]=Выберите и настройте модули
+Comment[sk]=Vyberte a nastavte si moduly
+Comment[sl]=Izberite in nastavite vstavke
+Comment[sr]=Изаберите и подесите ваше прикључке
+Comment[sr@Latn]=Izaberite i podesite vaše priključke
+Comment[sv]=Välj och anpassa insticksprogram
+Comment[ta]=சொருகுப்பொருள்களைத் தேர்ந்தெடுத்து வடிவமைக்கவும்
+Comment[tr]=Eklentilerinizi Seçin ve Yapılandırın:
+Comment[uk]=Виберіть та налаштуйте ваші втулки
+Comment[uz]=Plaginlarni tanlash va moslash
+Comment[uz@cyrillic]=Плагинларни танлаш ва мослаш
+Comment[zh_CN]=选择并配置您的插件
+Comment[zh_HK]=選擇及設定你的插件
+Comment[zh_TW]=選擇並設定您的外掛程式
diff --git a/kview/config/plugins/kviewpluginsconfig.h b/kview/config/plugins/kviewpluginsconfig.h
new file mode 100644
index 00000000..815a4de7
--- /dev/null
+++ b/kview/config/plugins/kviewpluginsconfig.h
@@ -0,0 +1,38 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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 KVIEWPLUGINSCONFIG_H
+#define KVIEWPLUGINSCONFIG_H
+
+#include <ksettings/pluginpage.h>
+
+class KConfig;
+
+class KViewPluginsConfig : public KSettings::PluginPage
+{
+ Q_OBJECT
+ public:
+ KViewPluginsConfig( QWidget * parent, const char * name = 0, const QStringList & args = QStringList() );
+ ~KViewPluginsConfig();
+ private:
+ KConfig * m_config;
+};
+
+// vim: sw=4 ts=4 noet
+
+#endif // KVIEWPLUGINSCONFIG_H
diff --git a/kview/hi16-app-kview.png b/kview/hi16-app-kview.png
new file mode 100644
index 00000000..f4b40e4a
--- /dev/null
+++ b/kview/hi16-app-kview.png
Binary files differ
diff --git a/kview/hi22-app-kview.png b/kview/hi22-app-kview.png
new file mode 100644
index 00000000..5c2169b3
--- /dev/null
+++ b/kview/hi22-app-kview.png
Binary files differ
diff --git a/kview/hi32-app-kview.png b/kview/hi32-app-kview.png
new file mode 100644
index 00000000..b4f7def8
--- /dev/null
+++ b/kview/hi32-app-kview.png
Binary files differ
diff --git a/kview/hi48-app-kview.png b/kview/hi48-app-kview.png
new file mode 100644
index 00000000..7791f9da
--- /dev/null
+++ b/kview/hi48-app-kview.png
Binary files differ
diff --git a/kview/kimageviewer/Makefile.am b/kview/kimageviewer/Makefile.am
new file mode 100644
index 00000000..c451ac33
--- /dev/null
+++ b/kview/kimageviewer/Makefile.am
@@ -0,0 +1,18 @@
+# $Id$
+
+lib_LTLIBRARIES = libkimageviewer.la
+
+noinst_HEADERS = canvas.h viewer.h
+
+libkimageviewer_la_SOURCES = canvas.cpp viewer.cpp
+libkimageviewer_la_LDFLAGS = $(all_libraries) -no-undefined -version-info 0:0
+libkimageviewer_la_LIBADD = $(LIB_KPARTS)
+
+INCLUDES = $(all_includes)
+
+# kimageviewerinclude_HEADERS = canvas.h viewer.h
+# kimageviewerincludedir = $(includedir)/kimageviewer
+
+METASOURCES = AUTO
+
+kde_servicetypes_DATA = kimageviewercanvas.desktop kimageviewer.desktop
diff --git a/kview/kimageviewer/canvas.cpp b/kview/kimageviewer/canvas.cpp
new file mode 100644
index 00000000..9b2c987b
--- /dev/null
+++ b/kview/kimageviewer/canvas.cpp
@@ -0,0 +1,35 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001-2002 Matthias Kretz <kretz@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+// $Id$
+
+#include "canvas.h"
+
+namespace KImageViewer
+{
+ Canvas::Canvas()
+ : m_iBlendEffect( 0 )
+ {
+ }
+
+ Canvas::~Canvas()
+ {
+ }
+} //namespace
+
+// vim: sw=4 ts=4
diff --git a/kview/kimageviewer/canvas.h b/kview/kimageviewer/canvas.h
new file mode 100644
index 00000000..61b565b4
--- /dev/null
+++ b/kview/kimageviewer/canvas.h
@@ -0,0 +1,348 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001-2002 Matthias Kretz <kretz@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+// $Id$
+
+#ifndef KIMAGEVIEWER_CANVAS_H
+#define KIMAGEVIEWER_CANVAS_H
+
+class QColor;
+class QSize;
+class QImage;
+class QRect;
+class QPoint;
+class QWidget;
+
+#include <qstring.h>
+#include <qobjectdefs.h>
+#include <kdemacros.h>
+namespace KImageViewer
+{
+
+/**
+ * An image canvas widget
+ *
+ * @author Matthias Kretz <kretz@kde.org>
+ *
+ * You'll find an implementation in kdegraphics (KView). You may
+ * still use this interface in your program but it will only work
+ * if you have an implementation installed.
+ *
+ * This is what you have to do to get an image canvas embedded in
+ * your program:
+ *
+ * <pre>
+ QWidget * widget = KParts::ComponentFactory::createInstanceFromQuery<QWidget>( "KImageViewer/Canvas", QString::null, this );
+ m_canvas = static_cast<KImageViewer::Canvas *>( widget->qt_cast( "KImageViewer::Canvas" ) );
+ if( ! ( widget && m_canvas ) )
+ {
+ KMessageBox::error( this, "Could not find the Canvas!" );
+ kapp->quit();
+ }
+ setCentralWidget( widget );
+ connect( widget, SIGNAL( contextPress( const QPoint & ) ), SLOT( mySlot( const QPoint & ) ) );
+ connect( m_canvas->widget(), SIGNAL( contextPress( const QPoint & ) ), SLOT( mySlot( const QPoint & ) ) );
+ </pre>
+ *
+ * You can't connect signals or slots using KImageViewer::Canvas, because this interface
+ * doesn't inherit from QObject. But you can cast to QWidget and use that instead (or just
+ * keep the original pointer to QWidget around, like shown in the example).
+ *
+ * This interface is not guaranteed to be kept binary or source compatible
+ * until it's finished. So if you're using this interface please get in contact
+ * with me.
+ */
+class KDE_EXPORT Canvas
+{
+ public:
+ /**
+ * set the background color of the canvas
+ */
+ virtual void setBgColor( const QColor & ) = 0;
+
+ /**
+ * returns the current background color
+ */
+ virtual const QColor & bgColor() const = 0;
+
+ /**
+ * the depth of the contained image
+ */
+ virtual int imageDepth() const = 0;
+
+ /**
+ * the size of the unzoomed image
+ */
+ virtual QSize imageSize() const = 0;
+
+ /**
+ * the size of the zoomed (current) image
+ */
+ virtual QSize currentSize() const = 0;
+
+ /**
+ * returns the zoom factor
+ */
+ virtual double zoom() const = 0;
+
+ /**
+ * @return The current (unzoomed) image
+ * Take care that the canas may delete the image so you probably need to
+ * make a copy of the image if you want to keep it around.
+ */
+ virtual const QImage * image() const = 0;
+
+ /**
+ * Scrolls the content so that the point (x, y) is in the top-left corner.
+ */
+ virtual void setXYOffset( int x, int y ) = 0;
+
+ /**
+ * Returns the leftmost visible X coordinate of the image.
+ */
+ virtual int xOffset() const = 0;
+
+ /**
+ * Returns the topmost visible Y coordinate of the image.
+ */
+ virtual int yOffset() const = 0;
+
+ /**
+ * Returns whether to use fast or smooth scaling
+ */
+ virtual bool fastScale() const = 0;
+
+ /**
+ * Return whether the image should always be centered.
+ */
+ virtual bool centered() const = 0;
+
+ /**
+ * Return the selected rectangle. If nothing is selected the rectangle is
+ * empty but doesn't have to be null.
+ */
+ virtual QRect selection() const = 0;
+
+ /**
+ * Returns whether the aspect ratio of the image is kept
+ */
+ virtual bool keepAspectRatio() const = 0;
+
+ /**
+ * @return the number of available blend effects
+ */
+ virtual unsigned int numOfBlendEffects() const { return 0; }
+
+ /**
+ * @return the description of the blend effect
+ */
+ virtual QString blendEffectDescription( unsigned int ) const { return QString::null; }
+
+ /**
+ * Sets the blending effect used to create a transition between images
+ */
+ virtual void setBlendEffect( unsigned int idx ) { m_iBlendEffect = idx; }
+
+ /**
+ * @return the current blend effect index
+ */
+ virtual unsigned int blendEffect() const { return m_iBlendEffect; }
+
+ /**
+ * @return the current maximum image size
+ */
+ virtual const QSize & maximumImageSize() const = 0;
+
+ /**
+ * @return the current minimum image size
+ */
+ virtual const QSize & minimumImageSize() const = 0;
+
+ /**
+ * @return a pointer to the QWidget interface of this object
+ */
+ virtual QWidget * widget() = 0;
+
+ signals:
+ /**
+ * a mouse button was pressed and a context menu should be openend
+ */
+ virtual void contextPress( const QPoint & ) = 0;
+
+ /**
+ * the size of the image has changed (a new image was loaded, or the
+ * image was zoomed or cropped)
+ *
+ * it passes the new size of the image
+ */
+ virtual void imageSizeChanged( const QSize & ) = 0;
+
+ /**
+ * The zoom of the image has changed.
+ */
+ virtual void zoomChanged( double zoom ) = 0;
+
+ /**
+ * The selection has changed. Connect to this signal if you want to
+ * do something with a selection of the image (e.g. crop).
+ */
+ virtual void selectionChanged( const QRect & ) = 0;
+
+ /**
+ * Emitted when an image is finished being shown. If a blend effect is being used
+ * the signal is emitted when the effect is finished.
+ */
+ virtual void showingImageDone() = 0;
+
+ /**
+ * This signal is emitted whenever the canvas changes between image/no-image. For
+ * example, if someone calls @ref clear() hasImage( false ) is emitted if an image
+ * was shown before.
+ */
+ virtual void hasImage( bool ) = 0;
+
+ /**
+ * Some methods of the canvas not only change the way the image is shown (e.g. zoom)
+ * but also change the image itself (e.g. rotation) - @ref image() returns something
+ * different. If such a change happens this signal is emitted.
+ * It is not emitted when a new image is set with the @ref setImage() methods.
+ */
+ virtual void imageChanged() = 0;
+
+ /**
+ * The current mouse cursor position on the image.
+ */
+ virtual void cursorPos( const QPoint & ) = 0;
+
+ public slots:
+ /**
+ * Set if the image should always be centered if the canvas is
+ * bigger than the image.
+ */
+ virtual void setCentered( bool ) = 0;
+
+ /**
+ * Give the canvas a new image to show. The zoom level is kept.
+ */
+ virtual void setImage( const QImage & ) = 0;
+
+ /**
+ * Give the canvas a new image to show.
+ *
+ * You have to pass the size the image should have when it appears
+ * on screen.
+ */
+ virtual void setImage( const QImage &, const QSize & ) = 0;
+
+ /**
+ * Set the zoom to be used when showing the image.
+ */
+ virtual void setZoom( double ) = 0;
+
+ /**
+ * Fit the image into the requested width and height.
+ */
+ virtual void boundImageTo( const QSize & size ) = 0;
+
+ /**
+ * Set the maximum size of the image. If this is set the image will
+ * never exceed this size.
+ *
+ * If you set this to 0x0 the image size may be as big as possible
+ */
+ virtual void setMaximumImageSize( const QSize & ) = 0;
+
+ /**
+ * Set the minimum size of the image. If this is set the image will
+ * never be smaller than this size.
+ *
+ * If you set this to 0x0 the image size can be as small as possible
+ */
+ virtual void setMinimumImageSize( const QSize & ) = 0;
+
+ /**
+ * Resize the image to the given size. It will keep the aspect ratio
+ * as long as keepAspectRatio is true (default). The image will be as
+ * large as possible within the given constraints.
+ */
+ virtual void resizeImage( const QSize & ) = 0;
+
+ /**
+ * Hides the scrollbars of the canvas. It's still possible to scroll
+ * by moving the image with the mouse.
+ */
+ virtual void hideScrollbars( bool ) = 0;
+
+ /**
+ * Changes the zoom behaviour: Normally the aspect ratio of the image
+ * won't change, but if you want to allow it you may do.
+ */
+ virtual void setKeepAspectRatio( bool ) = 0;
+
+ /**
+ * If the canvas supports different methods for scaling you may
+ * switch between fast and smooth scaling.
+ *
+ * It defaults to smooth scaling.
+ */
+ virtual void setFastScale( bool ) = 0;
+
+ /**
+ * clears the canvas (no image loaded)
+ */
+ virtual void clear() = 0;
+
+ /**
+ * flip the image horizontally
+ *
+ * @param change If set to true the internal image will be changed, else
+ * only the shown image changes and @ref image() still returns
+ * the same as before this call.
+ */
+ virtual void flipHorizontal( bool change = false ) = 0;
+
+ /**
+ * flip the image vertically
+ *
+ * @param change If set to true the internal image will be changed, else
+ * only the shown image changes and @ref image() still returns
+ * the same as before this call.
+ */
+ virtual void flipVertical( bool change = false ) = 0;
+
+ /**
+ * rotate the image a degrees counterclockwise
+ *
+ * @param angle The angle in degrees that the image should be rotated.
+ * @param change If set to true the internal image will be changed, else
+ * only the shown image changes and @ref image() still returns
+ * the same as before this call.
+ */
+ virtual void rotate( double angle, bool change = false ) = 0;
+
+ protected:
+ Canvas();
+ virtual ~Canvas();
+ unsigned int m_iBlendEffect;
+
+}; //class Canvas
+} //namespace KImageViewer
+
+// vim:sw=4:ts=4
+
+#endif // KIMAGEVIEWER_CANVAS_H
diff --git a/kview/kimageviewer/kimageviewer.desktop b/kview/kimageviewer/kimageviewer.desktop
new file mode 100644
index 00000000..6a5c1287
--- /dev/null
+++ b/kview/kimageviewer/kimageviewer.desktop
@@ -0,0 +1,63 @@
+[Desktop Entry]
+Type=ServiceType
+X-KDE-ServiceType=KImageViewer/Viewer
+X-KDE-Derived=KParts/ReadWritePart
+Icon=image
+Comment=Embeddable Image Viewer Component
+Comment[af]=Inlegbare Beeld Aansig Komponent
+Comment[ar]=مكون عارض الصور القابل للدمج
+Comment[bg]=Модул за преглед на изображения
+Comment[br]=Parzh gweler skeudennoù enframmus
+Comment[bs]=Ugradiva komponenta za pregled slika
+Comment[ca]=Component visualitzador d'imatges encastable
+Comment[cs]=Komponenta pro zobrazování obrázků
+Comment[cy]=Cydran Mewnadeiladadwy Gwelydd Delweddau
+Comment[da]=Indlejrbar billedviserkomponent
+Comment[de]=Einbettungsfähige Bildbetrachter-Komponente
+Comment[el]=Ενσωματώσιμο συστατικό προβολέα εικόνων
+Comment[eo]=Enkonstruebla bildrigardilo
+Comment[es]=Componente empotrable para visualizar imágenes
+Comment[et]=Põimitav pildifailide näitaja komponent
+Comment[eu]=Irudi ikustailu txertagarri osagaia
+Comment[fa]=مؤلفۀ مشاهده‌گر تصویر نهفته‌شده
+Comment[fi]=Upotettava kuviennäyttökomponentti
+Comment[fr]=Composant afficheur d'images incorporable
+Comment[gl]=Componente de visualización integrable
+Comment[he]=רכיב מציג תמונות בר־הטבעה
+Comment[hi]=एम्बेडेबल छवि प्रदर्शक अवयव
+Comment[hr]=Umetljiva komponenta za gledanje slika
+Comment[hu]=Beágyazható képnézegető komponens
+Comment[is]=Ívefjanleg myndsjá
+Comment[it]=Componente integrabile per la visione di immagini
+Comment[ja]=埋め込み可能な画像ビューアコンポーネント
+Comment[kk]=Ендірілетін кескін қарау компоненті
+Comment[km]=សមាសភាគ​របស់​កម្មវិធី​មើល​រូបភាព​ដែល​អាច​បង្កប់​បាន
+Comment[lt]=Įdedamas piešinių peržiūros komponentas
+Comment[ms]=Komponen Pemapar Imej Boleh Benam
+Comment[nb]=Inkluderbar bildevisningskomponent
+Comment[nds]=Inbettbor Bildkiekerkomponent
+Comment[ne]=सम्मिलित छवि दर्शक अवयव
+Comment[nl]=Ingebed weergavecomponent voor afbeeldingen
+Comment[nn]=Inkluderbart komponent for biletvising
+Comment[nso]=Seripa seo se Robatsegago sa Molebeledi wa Ponagalo
+Comment[pl]=Składnik do przeglądania obrazków
+Comment[pt]=Componente Embebida de Visualização de Imagens
+Comment[pt_BR]=Componente Integrado do Visualizador de Imagens
+Comment[ro]=Componentă înglobată de vizualizare imagini
+Comment[ru]=Встраиваемый компонент просмотра изображений
+Comment[se]=Vuojuhanláhkái govvačájehanoassi
+Comment[sk]=Vložiteľný komponent prehliadač obrázkov
+Comment[sl]=Vključen dodatek za pregled slik
+Comment[sr]=Уградива компонента приказивача слика
+Comment[sr@Latn]=Ugradiva komponenta prikazivača slika
+Comment[sv]=Inbäddningsbar bildvisande komponent
+Comment[ta]=பொதிந்த பிம்ப காட்சி பகுதி
+Comment[tg]=Қисмати дар дохилсозандаи намоиши тасвирот
+Comment[tr]=Gömülebilir Resim Görüntüleme Bileşeni
+Comment[uk]=Вмонтовний компонент перегляду зображень
+Comment[ven]=Tshipida tsha muvhoni wa tshifanyiso tsho dzheniswaho
+Comment[xh]=Ingxenye Yombonisi Womfanekiso Olungisiweyo
+Comment[zh_CN]=可嵌入的图像查看器组件
+Comment[zh_HK]=可嵌入的圖像檢視器元件
+Comment[zh_TW]=可嵌入的影像檢視器元件
+Comment[zu]=Ilunga Lombukisi Wesithombe Esixubeneyo
diff --git a/kview/kimageviewer/kimageviewercanvas.desktop b/kview/kimageviewer/kimageviewercanvas.desktop
new file mode 100644
index 00000000..fa084475
--- /dev/null
+++ b/kview/kimageviewer/kimageviewercanvas.desktop
@@ -0,0 +1,60 @@
+[Desktop Entry]
+Type=ServiceType
+X-KDE-ServiceType=KImageViewer/Canvas
+Comment=Embeddable Image Viewer Canvas (widget that shows an image)
+Comment[af]=Inlegbare Beeld Aansig Kanvas (gui-element wat vertoon 'n Beeld)
+Comment[ar]= مساحة رسم لعرض الصور قابلة للدمج (كائن يعرض صورة)
+Comment[bg]=Модул за преглед на изображения (полето, в което се показва самото изображение)
+Comment[bs]=Ugradiva pozadina za pregled slika (grafički element koji prikazuje slike)
+Comment[ca]=Llenç visualitzador d'imatges encastable (estri que mostra una imatge)
+Comment[cs]=Pohltitelná komponenta pro zobrazování obrázků
+Comment[cy]=Cynfas Mewnadeiladadwy Gwelydd Delweddau (celfigyn sy'n dangos delwedd)
+Comment[da]=Indlejrbar billedviserlærred (kontrol der viser et billede)
+Comment[de]=Einbettungsfähiges Bildbetrachtermodul (Bildschirmausschnitt, der ein Bild anzeigt)
+Comment[el]=Ενσωματώσιμος Καμβάς Προβολής Εικόνων (γραφικό συστατικό που εμφανίζει μία εικόνα)
+Comment[eo]=Enkonstruebla bildrigardilo kromaĵo
+Comment[es]=Componente empotrable para visualizar lienzos (widget que muestra una imagen)
+Comment[et]=Põimitavad pildifailide näitaja lõuendid (element, mis näitab pilti)
+Comment[eu]=Irudi ikustailu txertagarriren ohila (irudi bat erakuts dezakeen tresnatxoa)
+Comment[fa]=صفحۀ مجازی مشاهده‌گر تصویر نهفته‌‌شده )عنصری که یک تصویر را نمایش می‌دهد)
+Comment[fi]=Upotettava kuviennäyttökomponentti (käyttöliittymäelementti joka näyttää kuvan)
+Comment[fr]=Composant afficheur d'images incorporable (widget qui affiche une image)
+Comment[gl]=Visor de imaxes integrado (complemento que amosa unha imaxe)
+Comment[he]=רכיב מציג תמונות בר־הטבעה (פריט המציג תמונה)
+Comment[hi]=एम्बेडेबल छवि प्रदर्शक केनवास (विजेट जो छवि दिखाता है)
+Comment[hr]=Umetljivo platno za pregled slika (widget koji pokazuje sliku)
+Comment[hu]=Beágyazható képnézegető objektum (képmegjelenítő)
+Comment[is]=Ívefjanleg myndsjá (græja sem birtir mynd)
+Comment[it]=Componente integrabile per la visione di immagini (widget che mostra un'immagine)
+Comment[ja]=埋め込み可能な画像ビューアキャンバス (画像を表示するウィジェット)
+Comment[kk]=Кескін қарауға арналған ендірілетін өріс (кескінді көрсететін бөлшегі)
+Comment[km]=ផ្នែក​របស់​កម្មវិធី​មើល​រូបភាព​ដែល​អាច​បង្កប់​បាន (ផ្នែក​ដែល​បង្ហាញ​រូបភាព)
+Comment[lt]=Įdedamas piešinių peržiūros paveikslas (valdiklis, kuris rodo paveikslėlį)
+Comment[ms]=Kanvas Pemapar Imej Boleh Benam (widget yang memaparkan imej)
+Comment[nb]=Inkluderbare bildevisningskomponenter (skjermelement som viser et bilde)
+Comment[nds]=Inbettbor Bildkieker-Rahmen (Element, dat en Bild wiest)
+Comment[ne]=सम्मिलित छवि दर्शक क्यानभास (छवि देखाउने विजेट)
+Comment[nl]=Ingebed weergave-canvas (widget die een afbeelding toont)
+Comment[nn]=Inkluderbart lerret for biletvising (skjermelement som viser eit bilete)
+Comment[nso]=Canvas yeo e Robatsegago ya Molebeledi wa Ponagalo (widget yeo e bontshago ponagalo)
+Comment[pl]=Obszar do przeglądania obrazków (wnętrze okienka, które pokazuje obrazek)
+Comment[pt]=Área de Visualização Embebida de Imagens (um item que mostra uma imagem)
+Comment[pt_BR]=Componente Integrado do Visualizador Canvas (componente que exibe uma imagem)
+Comment[ro]=Componentă înglobată de vizualizare imagini (widget)
+Comment[ru]=Встраиваемый элемент просмотра изображений (просмотр изображения в виджете)
+Comment[se]=Vuojuhahtti govvačájehanliinni (áhtá mii čájeha gova)
+Comment[sk]=Vložiteľný komponent prehliadač obrázkov (prvok, ktorý zobrazuje obrázky)
+Comment[sl]=Vključljivo platno za pregled slik (gradnik, ki prikaže sliko)
+Comment[sr]=Уградиво платно приказивача слика (контрола која показује слику)
+Comment[sr@Latn]=Ugradivo platno prikazivača slika (kontrola koja pokazuje sliku)
+Comment[sv]=Inbäddningsbar bildvisande duk (komponent som visar en bild)
+Comment[ta]=பொதிந்த பிம்ப காட்சி திரைவடிவம்(சாளரம் ஒரு பிம்பத்தை காட்டுகிறது)
+Comment[tg]=Ҷузъи дар дохилсозандаи намоиши тасвирот (намоиши тасвирот дар виджет)
+Comment[tr]=Gömülebilir Resim Görüntüleme Penceresi
+Comment[uk]=Вмонтовний компонент полотна перегляду зображень (віджет, що малює зображення)
+Comment[ven]=Muvhala wa muvhoni wa tshifanyiso tsho dzheniswaho (tshishumiswa tsha vhuthogwa tshine tsha sumbedza tshifanyiso)
+Comment[xh]=Iseyile Yombonisi Womfanekiso Olungisiweyo (widget ebonisa umfanekiso)
+Comment[zh_CN]=可嵌入的图像查看画布(显示图像的部件)
+Comment[zh_HK]=可嵌入的圖像檢視器畫布(顯示圖像的器件)
+Comment[zh_TW]=可嵌入的影像檢視器畫布(顯示影像的界面工具)
+Comment[zu]=Inkalivasi Yombukisi Wesithombe Esixubeneyo (i-widget ekhombisa isithombe)
diff --git a/kview/kimageviewer/viewer.cpp b/kview/kimageviewer/viewer.cpp
new file mode 100644
index 00000000..a74e0de9
--- /dev/null
+++ b/kview/kimageviewer/viewer.cpp
@@ -0,0 +1,36 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Matthias Kretz <kretz@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+// $Id$
+
+#include "viewer.h"
+
+namespace KImageViewer
+{
+ Viewer::Viewer( QObject * parent, const char * name )
+ : KParts::ReadWritePart( parent, name )
+ {
+ }
+
+ Viewer::~Viewer()
+ {
+ }
+} //namespace
+
+#include "viewer.moc"
+// vim: sw=4 ts=4
diff --git a/kview/kimageviewer/viewer.h b/kview/kimageviewer/viewer.h
new file mode 100644
index 00000000..647fd9ba
--- /dev/null
+++ b/kview/kimageviewer/viewer.h
@@ -0,0 +1,99 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001-2002 Matthias Kretz <kretz@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+
+*/
+// $Id$
+
+#ifndef KIMAGEVIEWER_VIEWER_H
+#define KIMAGEVIEWER_VIEWER_H
+
+#include <kparts/part.h>
+#include <kdemacros.h>
+namespace KParts
+{
+ class BrowserExtension;
+}
+
+namespace KImageViewer
+{
+ class Canvas;
+
+/**
+ * An image viewer KPart
+ *
+ * @author Matthias Kretz <kretz@kde.org>
+ *
+ * You'll find an implementation in kdegraphics (KView). You may
+ * still use this interface in your program but it will only work
+ * if you have an implementation installed
+ *
+ * WARNING: This interface is not guaranteed to be kept binary or source compatible
+ * until it's finished. So if you're using this interface please get in contact
+ * with me.
+ */
+class KDE_EXPORT Viewer : public KParts::ReadWritePart
+{
+ Q_OBJECT
+ public:
+ Viewer( QObject * parent = 0, const char * name = 0 );
+
+ virtual ~Viewer();
+
+ /**
+ * Return the canvas this viewer is using. The interface of the
+ * canvas is defined in kimageviewer/canvas.h
+ */
+ virtual Canvas * canvas() const = 0;
+
+ /**
+ * If the Viewer wants to be configurable
+ */
+ //virtual void createConfigurationDialogPages() = 0;
+
+ /**
+ * A pointer to the Browser Extension (if available). You should always
+ * check whether this returns a valid pointer.
+ */
+ virtual KParts::BrowserExtension * browserExtension() const { return 0; }
+
+ public slots:
+ /**
+ * Set a new Image. Close the old one and change the caption and file
+ * name and url and whatnot accordingly.
+ * So if you want to display a new image (not change the one shown) this
+ * is the method to use. Else take a look at Canvas::setImage().
+ */
+ virtual void newImage( const QImage & ) = 0;
+
+ /**
+ * Tell the view to reload the current image. The host for this view
+ * should make an Action available for reloading.
+ */
+ virtual void reload() = 0;
+
+ signals:
+ /**
+ * Emitted when the viewer opens a new image
+ */
+ void imageOpened( const KURL & );
+
+}; //class Viewer
+} //namespace KImageViewer
+
+// vim:sw=4:ts=4
+
+#endif // KIMAGEVIEWER_VIEWER_H
diff --git a/kview/kview.cpp b/kview/kview.cpp
new file mode 100644
index 00000000..a9af213e
--- /dev/null
+++ b/kview/kview.cpp
@@ -0,0 +1,698 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001-2003 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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 "kview.h"
+#include "kimageviewer/viewer.h"
+#include "kimageviewer/canvas.h"
+
+#include <ksettings/dialog.h>
+#include <ksettings/dispatcher.h>
+#include <kurl.h>
+#include <klibloader.h>
+#include <kmessagebox.h>
+#include <kparts/componentfactory.h>
+#include <kparts/plugin.h>
+#include <kparts/part.h>
+#include <kapplication.h>
+#include <kaction.h>
+#include <kstdaction.h>
+#include <kimageio.h>
+#include <kfiledialog.h>
+#include <klocale.h>
+#include <kwinmodule.h>
+#include <kmenubar.h>
+#include <kstatusbar.h>
+#include <kdebug.h>
+#include <kedittoolbar.h>
+#include <kstdaccel.h>
+#include <kprogress.h>
+
+#include <qimage.h>
+#include <qsize.h>
+#include <qscrollbar.h>
+#include <qstyle.h>
+#include <qclipboard.h>
+#include <qdragobject.h>
+#include <qvaluelist.h>
+#include <qtimer.h>
+#include <qdockarea.h>
+
+#include <assert.h>
+#include <kplugininfo.h>
+
+KView::KView()
+ : KParts::MainWindow( 0, "KView" )
+ , m_pViewer( 0 )
+ , m_pCanvas( 0 )
+ , m_pWinModule( new KWinModule( this, KWinModule::INFO_DESKTOP ) )
+ , m_bImageSizeChangedBlocked( false )
+ , m_bFullscreen( false )
+{
+ KParts::ReadWritePart * part = KParts::ComponentFactory::createPartInstanceFromLibrary<KParts::ReadWritePart>(
+ "libkviewviewer", this, "KViewViewer Widget", this, "KImageViewer Part" );
+ if( part )
+ {
+ m_pViewer = static_cast<KImageViewer::Viewer *>( part );
+ if( m_pViewer )
+ m_pCanvas = m_pViewer->canvas();
+ }
+
+ kdDebug( 4600 ) << "m_pViewer = " << m_pViewer << endl;
+
+ if( m_pCanvas )
+ {
+ setupActions( part );
+
+ setCentralWidget( part->widget() );
+
+ setStandardToolBarMenuEnabled( true );
+
+ connect( part->widget(), SIGNAL( imageSizeChanged( const QSize & ) ),
+ SLOT( imageSizeChanged( const QSize & ) ) );
+ connect( part->widget(), SIGNAL( selectionChanged( const QRect & ) ),
+ SLOT( selectionChanged( const QRect & ) ) );
+ connect( part->widget(), SIGNAL( contextPress( const QPoint & ) ),
+ SLOT( contextPress( const QPoint & ) ) );
+
+ connect( QApplication::clipboard(), SIGNAL( dataChanged() ),
+ SLOT( clipboardDataChanged() ) );
+
+ connect( m_pViewer, SIGNAL( started( KIO::Job * ) ),
+ this, SLOT( jobStarted( KIO::Job * ) ) );
+ connect( m_pViewer, SIGNAL( completed() ),
+ this, SLOT( jobCompleted() ) );
+ connect( m_pViewer, SIGNAL( completed( bool ) ),
+ this, SLOT( jobCompleted( bool ) ) );
+ connect( m_pViewer, SIGNAL( canceled( const QString & ) ),
+ this, SLOT( jobCanceled( const QString & ) ) );
+ connect( m_pViewer, SIGNAL( imageOpened( const KURL & ) ),
+ m_paRecent, SLOT( addURL( const KURL & ) ) );
+
+ connect( m_pCanvas->widget(), SIGNAL( cursorPos( const QPoint & ) ), SLOT( cursorPos( const QPoint & ) ) );
+
+ m_paRecent->loadEntries( KGlobal::config() );
+ if (!initialGeometrySet())
+ resize(500, 350);
+ readSettings();
+ m_pViewer->widget()->installEventFilter( this );
+
+ // reload configuration when it's changed by the conf dlg
+ KSettings::Dispatcher::self()->registerInstance( instance(), this, SLOT( readSettings() ) );
+
+ setPluginLoadingMode( LoadPluginsIfEnabled );
+ createGUI( part );
+
+ // create status bar (hidden by default)
+ statusBar()->insertItem( "", STATUSBAR_SPEED_ID, 0, true );
+ statusBar()->setItemFixed( STATUSBAR_SPEED_ID,
+ 8 + fontMetrics().width( i18n( "%1/s" ).arg( KIO::convertSize( 999000 ) ) ) );
+ statusBar()->insertItem( "", STATUSBAR_CURSOR_ID, 0, true );
+ statusBar()->setItemFixed( STATUSBAR_CURSOR_ID, 8 + fontMetrics().width( "8888, 8888" ) );
+ statusBar()->insertItem( "", STATUSBAR_SIZE_ID, 0, true );
+ statusBar()->setItemFixed( STATUSBAR_SIZE_ID, 8 + fontMetrics().width( "8888 x 8888" ) );
+
+ statusBar()->insertItem( QString::null, STATUSBAR_SELECTION_ID );
+
+ m_pProgressBar = new KProgress( statusBar() );
+ m_pProgressBar->setFixedSize( 140, fontMetrics().height() );
+ statusBar()->addWidget( m_pProgressBar, 0, true );
+ m_pProgressBar->hide();
+
+ setAutoSaveSettings();
+ m_paShowMenubar->setChecked( ! menuBar()->isHidden() );
+
+ // show progress info dialog if the statusbar is hidden
+ m_pViewer->setProgressInfoEnabled( statusBar()->isHidden() );
+
+ // set small minimum size
+ setMinimumSize( 0, 0 );
+ }
+ else
+ {
+ KMessageBox::error( this, i18n( "An error occurred while loading the KViewViewer KPart. Check your installation." ) );
+ QTimer::singleShot( 0, kapp, SLOT( quit() ) );
+ }
+}
+
+KView::~KView()
+{
+ saveSettings( KGlobal::config() );
+ KGlobal::config()->sync();
+}
+
+void KView::load( const KURL & url )
+{
+ if( m_pViewer )
+ {
+ m_pViewer->openURL( url );
+ if( url.isLocalFile() )
+ {
+ // XXX: this code is what
+ //KRecentDirs::add( QString::fromLatin1( ":load_image" ), url.directory() );
+ // would do:
+ QString directory = url.directory();
+ QString key = QString::fromLatin1( "load_image" );
+ KConfig * config = KGlobal::config();
+
+ config->setGroup( QString::fromLatin1( "Recent Dirs" ) );
+ QStringList result = config->readPathListEntry( key );
+ // make sure the dir is first in history
+ result.remove( directory );
+ result.prepend( directory );
+ while( result.count() > 3 )
+ result.remove( result.fromLast() );
+ config->writePathEntry( key, result );
+ config->sync();
+ }
+ }
+}
+
+void KView::loadFromStdin()
+{
+ if( m_pViewer )
+ {
+ QFile file;
+ file.open( IO_ReadOnly, stdin );
+ QImage image( file.readAll() );
+ file.close();
+ m_pViewer->newImage( image );
+ }
+}
+
+QSize KView::sizeForCentralWidgetSize( QSize size )
+{
+ // add size of the dockareas
+ kdDebug( 4600 ) << "sizeForCentralWidgetSize " << size << endl;
+ size.rheight() += topDock()->height() + bottomDock()->height();
+ size.rwidth() += leftDock()->width() + rightDock()->width() - 2;
+ kdDebug( 4600 ) << "added Dockareas: " << size << endl;
+ KStatusBar * sb = statusBar();
+ size.rheight() += sb->isHidden() ? 0 : sb->height();
+ kdDebug( 4600 ) << "added Statusbar: " << size << endl;
+ KMenuBar * mb = menuBar();
+ if( ! mb->isHidden() )
+ {
+ size.rheight() += mb->heightForWidth( width() );
+ if( style().styleHint( QStyle::SH_MainWindow_SpaceBelowMenuBar, this ) )
+ size.rheight() += dockWindowsMovable() ? 1 : 2;
+ }
+ kdDebug( 4600 ) << "added Menubar: " << size << endl;
+ return size;
+}
+
+bool KView::queryClose()
+{
+ return m_pViewer->closeURL();
+}
+
+void KView::saveProperties( KConfig * /*config*/ )
+{
+ // save session data:
+ // What URL is currently open
+ // somehow the plugins have to get a chance to store their data
+}
+
+void KView::readProperties( KConfig * /*config*/ )
+{
+ // read session data
+}
+
+void KView::saveSettings( KConfig * config )
+{
+ // write settings to config/kviewrc
+ kdDebug( 4600 ) << k_funcinfo << endl;
+ m_paRecent->saveEntries( config );
+}
+
+void KView::readSettings() // KConfig * config )
+{
+ // read settings from config/kviewrc
+ kdDebug( 4600 ) << k_funcinfo << endl;
+ KConfigGroup cfgGroup( KGlobal::config(), "KView General" );
+ m_nResizeMode = cfgGroup.readNumEntry( "Resize Mode", 2 );
+ kdDebug( 4600 ) << "m_nResizeMode = " << m_nResizeMode << endl;
+ loadPlugins();
+}
+
+bool KView::eventFilter( QObject * obj, QEvent * ev )
+{
+ if( obj == m_pViewer->widget() && ev->type() == QEvent::Resize )
+ {
+ if( m_nResizeMode == ResizeImage )
+ handleResize();
+ }
+ return KParts::MainWindow::eventFilter( obj, ev );
+}
+
+void KView::imageSizeChanged( const QSize & /*size*/ )
+{
+ QSize size = m_pCanvas->imageSize();
+ statusBar()->changeItem( QString( "%1 x %2" ).arg( size.width() ).arg( size.height() ), STATUSBAR_SIZE_ID );
+ handleResize();
+}
+
+void KView::selectionChanged( const QRect & rect )
+{
+ kdDebug( 4600 ) << k_funcinfo << rect << endl;
+ if( rect.isNull() )
+ statusBar()->changeItem( QString::null, STATUSBAR_SELECTION_ID );
+ else
+ statusBar()->changeItem( QString( "%1, %2 - %3 x %4" ).arg( rect.x() ).arg( rect.y() ).arg( rect.width() ).arg( rect.height() ), STATUSBAR_SELECTION_ID );
+ action( "crop" )->setEnabled( ! rect.isNull() );
+}
+
+void KView::contextPress( const QPoint & point )
+{
+ QPopupMenu * pop = ( QPopupMenu* )factory()->container( "popupmenu", this );
+ pop->popup( point );
+}
+
+void KView::slotOpenFile()
+{
+ KURL url = KFileDialog::getImageOpenURL( ":load_image", this );
+ load( url );
+}
+
+void KView::slotOpenRecent( const KURL & url )
+{
+ load( url );
+}
+
+void KView::slotClose()
+{
+ if( m_pViewer->closeURL() )
+ m_pCanvas->clear();
+}
+
+void KView::slotCopy()
+{
+ QClipboard *cb = QApplication::clipboard();
+ cb->setSelectionMode( false );
+
+ QRect selectarea = m_pCanvas->selection();
+ if( selectarea.isEmpty() )
+ {
+ kdDebug( 4600 ) << k_funcinfo << " copy whole image" << endl;
+ cb->setImage( *m_pCanvas->image() );
+ }
+ else
+ {
+ kdDebug( 4600 ) << k_funcinfo << " copy selected area of image" << endl;
+ cb->setImage( m_pCanvas->image()->copy( selectarea ) );
+ }
+}
+
+void KView::slotPaste()
+{
+ // Get QImage from clipboard and create a new image.
+ QClipboard *cb = QApplication::clipboard();
+ QImage img = cb->image();
+ if( ! img.isNull() )
+ m_pViewer->newImage( img );
+}
+
+void KView::slotCrop()
+{
+ QRect selectarea = m_pCanvas->selection();
+ kdDebug( 4600 ) << "Crop following area: " << selectarea.x() << ", " << selectarea.y() << ", " << selectarea.width() << ", " << selectarea.height() << endl;
+
+ if( selectarea.isNull() )
+ return;
+ const QImage * origimg = m_pCanvas->image();
+ if( origimg == 0 )
+ return;
+
+ m_pCanvas->setImage( origimg->copy( selectarea ) );
+ m_pViewer->setModified( true );
+}
+
+void KView::slotUpdateFullScreen( bool set )
+{
+ m_bFullscreen = set;
+ if( set )
+ { // switch to FullScreen mode
+ saveMainWindowSettings( KGlobal::config(), "nonFullScreen MainWindow" );
+ showFullScreen();
+ applyMainWindowSettings( KGlobal::config(), "FullScreen MainWindow" );
+ m_paShowMenubar->setChecked( ! menuBar()->isHidden() );
+ }
+ else
+ { // leave FullScreen mode
+ saveMainWindowSettings( KGlobal::config(), "FullScreen MainWindow" );
+ showNormal();
+ applyMainWindowSettings( KGlobal::config(), "nonFullScreen MainWindow" );
+ m_paShowMenubar->setChecked( ! menuBar()->isHidden() );
+ handleResize();
+ }
+}
+
+void KView::slotToggleMenubar()
+{
+ if( menuBar()->isVisible() )
+ menuBar()->hide();
+ else
+ menuBar()->show();
+ handleResize();
+}
+
+void KView::slotPreferences()
+{
+ // construct KCD for KView app
+ static KSettings::Dialog * dlg = 0;
+ if( ! dlg )
+ {
+ dlg = new KSettings::Dialog( this );
+ //dlg = new KConfigureDialog( KConfigureDialog::Configurable, this );
+ //dlg->addPluginInfos( KPluginInfo::fromKPartsInstanceName( instance()->instanceName(), KGlobal::config(), "KParts Plugins" ) );
+ }
+ dlg->show();
+}
+
+void KView::slotConfigureToolbars()
+{
+ saveMainWindowSettings( KGlobal::config(), "MainWindow" );
+ KEditToolbar dlg( factory() );
+ connect( &dlg, SIGNAL( newToolbarConfig() ), SLOT( slotNewToolbarConfig() ) );
+ dlg.exec();
+}
+
+void KView::slotNewToolbarConfig()
+{
+ applyMainWindowSettings( KGlobal::config(), "MainWindow" );
+}
+
+void KView::reloadConfig()
+{
+ readSettings(); //KGlobal::config() );
+}
+
+void KView::enableAction( const char * name, bool b )
+{
+ KAction * a = actionCollection()->action( name );
+ if( a )
+ a->setEnabled( b );
+ else
+ kdWarning( 4600 ) << k_funcinfo << " unknown action" << endl;
+}
+
+void KView::clipboardDataChanged()
+{
+ QClipboard * cb = QApplication::clipboard();
+ cb->setSelectionMode( false );
+ bool hasImage = QImageDrag::canDecode( cb->data( QClipboard::Clipboard ) );
+ m_paPaste->setEnabled( hasImage );
+}
+
+void KView::jobStarted( KIO::Job * job )
+{
+ if( job )
+ {
+ connect( job, SIGNAL( percent( KIO::Job *, unsigned long ) ), this, SLOT( loadingProgress( KIO::Job *, unsigned long ) ) );
+ connect( job, SIGNAL( speed( KIO::Job *, unsigned long ) ), this, SLOT( speedProgress( KIO::Job *, unsigned long ) ) );
+ //connect( job, SIGNAL( infoMessage( KIO::Job *, const QString & ) ), this, SLOT() );
+ loadingProgress( job, 0 );
+ speedProgress( job, 0 );
+ }
+}
+
+void KView::jobCompleted()
+{
+ jobCompleted( false );
+}
+
+void KView::jobCompleted( bool /*hasPending*/ )
+{
+ loadingProgress( 0, 101 );
+ statusBar()->changeItem( "", STATUSBAR_SPEED_ID );
+}
+
+void KView::jobCanceled( const QString & errorMsg )
+{
+ statusBar()->message( errorMsg );
+ jobCompleted();
+}
+
+void KView::loadingProgress( KIO::Job *, unsigned long percent )
+{
+ if( percent > 100 )
+ {
+ m_pProgressBar->hide();
+ return;
+ }
+
+ if( ! m_pProgressBar->isVisible() )
+ m_pProgressBar->show();
+
+ m_pProgressBar->setValue( percent );
+}
+
+void KView::speedProgress( KIO::Job *, unsigned long bytesPerSecond )
+{
+ QString sizeStr;
+
+ if( bytesPerSecond > 0 )
+ sizeStr = i18n( "%1/s" ).arg( KIO::convertSize( bytesPerSecond ) );
+ else
+ sizeStr = i18n( "Stalled" );
+
+ statusBar()->changeItem( sizeStr, STATUSBAR_SPEED_ID );
+}
+
+void KView::slotSetStatusBarText( const QString & msg )
+{
+ kdDebug( 4600 ) << k_funcinfo << endl;
+ statusBar()->message( msg );
+ if( statusBar()->isHidden() )
+ KMessageBox::information( this, msg );
+}
+
+void KView::cursorPos( const QPoint & pos )
+{
+ statusBar()->changeItem( QString( "%1, %2" ).arg( pos.x() ).arg( pos.y() ), STATUSBAR_CURSOR_ID );
+}
+
+void KView::setupActions( QObject * partobject )
+{
+ // File
+ KStdAction::open( this, SLOT( slotOpenFile() ), actionCollection() );
+ m_paRecent = KStdAction::openRecent( this, SLOT( slotOpenRecent( const KURL & ) ), actionCollection() );
+ KAction * aClose = KStdAction::close( this, SLOT( slotClose() ), actionCollection() );
+ aClose->setEnabled( false );
+ connect( m_pViewer->widget(), SIGNAL( hasImage( bool ) ), aClose, SLOT( setEnabled( bool ) ) );
+
+ QObject * extension = partobject->child( 0, "KParts::BrowserExtension", false );
+ if( extension )
+ {
+ QStrList slotNames = extension->metaObject()->slotNames();
+ if( slotNames.contains( "print()" ) )
+ KStdAction::print( extension, SLOT( print() ), actionCollection(), "print" );
+ if( slotNames.contains( "del()" ) )
+ ( void )new KAction( i18n( "&Delete" ), "editdelete", SHIFT+Key_Delete,
+ extension, SLOT( del() ), actionCollection(), "del" );
+ connect( extension, SIGNAL( enableAction( const char *, bool ) ), SLOT( enableAction( const char *, bool ) ) );
+ }
+ KStdAction::quit( this, SLOT( close() ), actionCollection() );
+
+ // Edit
+ KAction * aCopy = KStdAction::copy( this, SLOT( slotCopy() ), actionCollection() );
+ aCopy->setEnabled( false );
+ connect( m_pViewer->widget(), SIGNAL( hasImage( bool ) ), aCopy, SLOT( setEnabled( bool ) ) );
+ m_paPaste = KStdAction::paste( this, SLOT( slotPaste() ), actionCollection() );
+ clipboardDataChanged(); //enable or disable paste
+ KAction * aCrop = new KAction( i18n( "Cr&op" ), Key_C, this, SLOT( slotCrop() ), actionCollection(), "crop" );
+ aCrop->setEnabled( false );
+
+ KAction * aReload = new KAction( i18n( "&Reload" ), "reload", KStdAccel::shortcut( KStdAccel::Reload ), partobject,
+ SLOT( reload() ), actionCollection(), "reload" );
+ aReload->setEnabled( false );
+ connect( m_pViewer->widget(), SIGNAL( hasImage( bool ) ), aReload, SLOT( setEnabled( bool ) ) );
+
+ // Settings
+ m_paShowMenubar = KStdAction::showMenubar( this, SLOT( slotToggleMenubar() ), actionCollection() );
+ createStandardStatusBarAction();
+ m_paShowStatusBar = ::qt_cast<KToggleAction*>( action( "options_show_statusbar" ) );
+ if( m_paShowStatusBar )
+ connect( m_paShowStatusBar, SIGNAL( toggled( bool ) ), SLOT( statusbarToggled( bool ) ) );
+ m_paShowFullScreen = KStdAction::fullScreen( 0, 0, actionCollection(), this );
+ connect( m_paShowFullScreen, SIGNAL( toggled( bool )), this, SLOT( slotUpdateFullScreen( bool )));
+ KStdAction::preferences( this, SLOT( slotPreferences() ), actionCollection() );
+ KStdAction::keyBindings(guiFactory(), SLOT(configureShortcuts()),
+actionCollection());
+ KStdAction::configureToolbars( this, SLOT( slotConfigureToolbars() ), actionCollection() );
+}
+
+void KView::handleResize()
+{
+ if( m_bImageSizeChangedBlocked )
+ return;
+ m_bImageSizeChangedBlocked = true;
+ setUpdatesEnabled( false );
+ switch( m_nResizeMode )
+ {
+ case ResizeWindow:
+ fitWindowToImage();
+ fitWindowToImage();
+ break;
+ case ResizeImage:
+ m_pCanvas->boundImageTo( m_pViewer->widget()->size() );
+ break;
+ case BestFit:
+ QSize imageSize = m_pCanvas->imageSize();
+ if( imageSize.isEmpty() )
+ return;
+
+ // Compare the image size and the maximum available space in the
+ // display canvas i.e. will the image fit without resizing ?
+ QSize maxCanvas = maxCanvasSize();
+ if( ( maxCanvas.height() >= imageSize.height() )
+ && ( maxCanvas.width() >= imageSize.width() ) )
+ {
+ //Image can be displayed at full size
+ m_pCanvas->setZoom( 1.0 );
+ }
+ else
+ {
+ // Image is too big for the available canvas.
+ m_pCanvas->boundImageTo( maxCanvas );
+ }
+ // We assume the displayed image size has changed and we must resize
+ // the window around it (using the code for ResizeWindow).
+ fitWindowToImage();
+ fitWindowToImage();
+ break;
+ }
+ setUpdatesEnabled( true );
+ m_bImageSizeChangedBlocked = false;
+}
+
+void KView::fitWindowToImage()
+{
+ if( m_bFullscreen ) // don't do anything in fullscreen mode
+ return;
+
+ bool centeredOrig = m_pCanvas->centered();
+ m_pCanvas->setCentered( false );
+
+ QSize imagesize = m_pCanvas->currentSize();
+ if( imagesize.isEmpty() )
+ return;
+
+ QSize winsize = sizeForCentralWidgetSize( imagesize );
+ QRect workarea = m_pWinModule->workArea();
+
+ QScrollBar * sb = new QScrollBar( Qt::Horizontal, this );
+ int scrollbarwidth = sb->height();
+ delete sb;
+
+ if( winsize.width() > workarea.width() )
+ {
+ winsize.setWidth( workarea.width() );
+ winsize.rheight() += scrollbarwidth;
+ if( winsize.height() > workarea.height() )
+ winsize.setHeight( workarea.height() );
+ }
+ else if( winsize.height() > workarea.height() )
+ {
+ winsize.setHeight( workarea.height() );
+ winsize.rwidth() += scrollbarwidth;
+ if( winsize.width() > workarea.width() )
+ winsize.setWidth( workarea.width() );
+ }
+
+ QRect winrect( geometry() );
+ winrect.setSize( winsize );
+
+ int xdiff = winrect.x() + winrect.width() - workarea.x() - workarea.width();
+ int ydiff = winrect.y() + winrect.height() - workarea.y() - workarea.height();
+
+ if( xdiff > 0 )
+ {
+ winrect.rLeft() -= xdiff;
+ winrect.rRight() -= xdiff;
+ }
+ if( ydiff > 0 )
+ {
+ winrect.rTop() -= ydiff;
+ winrect.rBottom() -= ydiff;
+ }
+
+ setGeometry( winrect );
+
+ m_pCanvas->setCentered( centeredOrig );
+}
+
+QSize KView::barSize( int mainwinwidth, BarSizeFrom from )
+{
+ int height = 0;
+ int width = 0;
+ if( toolBar()->isVisibleTo( this ) )
+ {
+ switch( toolBar()->barPos() )
+ {
+ case KToolBar::Top:
+ case KToolBar::Bottom:
+ height += toolBar()->height();
+ break;
+ case KToolBar::Left:
+ case KToolBar::Right:
+ width += toolBar()->width();
+ break;
+ case KToolBar::Flat:
+ height += kapp->style().pixelMetric( QStyle::PM_DockWindowHandleExtent );
+ break;
+ case KToolBar::Floating:
+ break;
+ case KToolBar::Unmanaged:
+ break;
+ }
+ }
+ if( menuBar()->isVisibleTo( this ) && ( ! menuBar()->isTopLevelMenu() ) )
+ height += menuBar()->heightForWidth( mainwinwidth + ( ( from == FromImageSize ) ? width : 0 ) );
+ if( statusBar()->isVisibleTo( this ) )
+ height += statusBar()->height();
+
+ return QSize( width, height );
+}
+
+QSize KView::maxCanvasSize()
+{
+ QSize workarea = m_pWinModule->workArea().size();
+ QSize framesize = frameSize() - size();
+ QSize maxcanvassize = workarea - framesize - barSize( workarea.width() - framesize.width(), FromWidgetSize );
+ kdDebug( 4600 ) << "maxcanvassize = " << maxcanvassize.width() << "x" << maxcanvassize.height() << endl;
+ return maxcanvassize;
+}
+
+
+void KView::loadPlugins()
+{
+ createGUI( 0 );
+ createShellGUI( false );
+ createGUI( m_pViewer );
+}
+
+void KView::statusbarToggled( bool sbvisible )
+{
+ kdDebug( 4600 ) << k_funcinfo << sbvisible << endl;
+ m_pViewer->setProgressInfoEnabled( !sbvisible );
+}
+
+// vim:sw=4:ts=4
+
+#include "kview.moc"
+
diff --git a/kview/kview.desktop b/kview/kview.desktop
new file mode 100644
index 00000000..55b28991
--- /dev/null
+++ b/kview/kview.desktop
@@ -0,0 +1,95 @@
+[Desktop Entry]
+Type=Application
+Exec=kview -caption "%c" %i %m %U
+Icon=kview
+Path=
+DocPath=kview/index.html
+Terminal=false
+GenericName=Image Viewer
+GenericName[af]=Beeld Aansig
+GenericName[ar]=عارض صور
+GenericName[bg]=Преглед на изображения
+GenericName[br]=Gweler ar skeudennoù
+GenericName[bs]=Preglednik slika
+GenericName[ca]=Visualitzador d'imatges
+GenericName[cs]=Prohlížeč obrázků
+GenericName[cy]=Gwelydd Delweddau
+GenericName[da]=Billedfremviser
+GenericName[de]=Bildbetrachter
+GenericName[el]=Προβολέας εικόνων
+GenericName[eo]=Bildorigardilo
+GenericName[es]=Visor de imágenes
+GenericName[et]=Pildifailide näitaja
+GenericName[eu]=Irudi ikustailua
+GenericName[fa]=مشاهده‌گر تصویر
+GenericName[fi]=Kuvannäytin
+GenericName[fr]=Afficheur d'images
+GenericName[ga]=Amharcán Íomhánna
+GenericName[gl]=Visor de imaxes
+GenericName[he]=מציג תמונות
+GenericName[hi]=छवि प्रदर्शक
+GenericName[hr]=Preglednik slika
+GenericName[hu]=Képnézegető
+GenericName[is]=Myndaskoðari
+GenericName[it]=Visore di immagini
+GenericName[ja]=画像ビューア
+GenericName[kk]=Кескіндерді қарау
+GenericName[km]=កម្មវិធី​មើល​រូបភាព
+GenericName[lt]=Paveikslėlių žiūriklis
+GenericName[lv]=Attēlu Skatītājs
+GenericName[ms]=Paparan Imej
+GenericName[mt]=Werrej tal-istampi
+GenericName[nb]=Bildefremviser
+GenericName[nds]=Bildkieker
+GenericName[ne]=छवि दर्शक
+GenericName[nl]=Afbeeldingenweergaveprogramma
+GenericName[nn]=Biletvisar
+GenericName[nso]=Molebeledi wa Ponagalo
+GenericName[pa]=ਚਿੱਤਰ ਦਰਸ਼ਕ
+GenericName[pl]=Przeglądarka obrazków
+GenericName[pt]=Visualizador de Imagens
+GenericName[pt_BR]=Visualizador de Imagens
+GenericName[ro]=Vizualizor de imagini
+GenericName[ru]=Просмотр изображений
+GenericName[rw]=Mugaraza Shusho
+GenericName[se]=Govvačájeheaddji
+GenericName[sk]=Prehliadač obrázkov
+GenericName[sl]=Pregledovalnik slik
+GenericName[sr]=Приказивач слика
+GenericName[sr@Latn]=Prikazivač slika
+GenericName[sv]=Bildvisare
+GenericName[ta]=பிம்ப காட்சி
+GenericName[tg]=Намоиши тасвирот
+GenericName[th]=เครื่องมือแสดงภาพ
+GenericName[tr]=Resim Göstericisi
+GenericName[uk]=Переглядач зображень
+GenericName[uz]=Rasm koʻruvchi
+GenericName[uz@cyrillic]=Расм кўрувчи
+GenericName[ven]=Tshivhoni tsha Mutaleli
+GenericName[wa]=Håyneu d' imådjes
+GenericName[xh]=Umboniseli Womfanekiso
+GenericName[zh_CN]=图片查看程序
+GenericName[zh_HK]=圖像檢視器
+GenericName[zh_TW]=影像檢視程式
+GenericName[zu]=Umbonisi Womfanekiso
+MimeType=image/gif;image/x-xpm;image/x-xbm;image/jpeg;image/x-bmp;image/png;image/x-ico;image/x-portable-bitmap;image/x-portable-pixmap;image/x-portable-greymap;image/tiff;image/jp2;
+Name=KView
+Name[af]=K-bekyk
+Name[ar]=برنامج KView
+Name[cy]=KGweld
+Name[eo]=Rigardilo
+Name[hi]=के-व्यू
+Name[hr]=Preglednik slika
+Name[lv]=KSkatīt
+Name[ne]=केडीई दर्शक
+Name[pl]=Przeglądarka obrazków
+Name[pt_BR]=KVisualização
+Name[sv]=Kview
+Name[ta]=கேகாட்சி
+Name[th]=ดูภาพ - K
+Name[ven]=U vhona ha K
+Name[zh_TW]=KView 檢視器
+InitialPreference=3
+X-KDE-StartupNotify=true
+X-DCOP-ServiceType=Multi
+Categories=Qt;KDE;Graphics;
diff --git a/kview/kview.h b/kview/kview.h
new file mode 100644
index 00000000..0f523efc
--- /dev/null
+++ b/kview/kview.h
@@ -0,0 +1,124 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001-2003 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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 KVIEW_H
+#define KVIEW_H
+
+#include <config.h>
+
+#include <kapplication.h>
+#include <kparts/mainwindow.h>
+
+namespace KParts {
+ class ReadWritePart;
+}
+namespace KImageViewer {
+ class Canvas;
+ class Viewer;
+}
+class QSize;
+class QRect;
+class KAction;
+class KToggleAction;
+class KRecentFilesAction;
+class KWinModule;
+class QStringList;
+class KProgress;
+
+class KView : public KParts::MainWindow
+{
+ Q_OBJECT
+ public:
+ KView();
+ virtual ~KView();
+ void load( const KURL & url );
+ void loadFromStdin();
+ QSize sizeForCentralWidgetSize( QSize );
+ KImageViewer::Viewer * viewer() const { return m_pViewer; }
+
+ protected:
+ bool queryClose();
+ void saveProperties( KConfig * );
+ void readProperties( KConfig * );
+ void saveSettings( KConfig * );
+
+ virtual bool eventFilter( QObject *, QEvent * );
+
+ protected slots:
+ void readSettings(); //KConfig * );
+ void imageSizeChanged( const QSize & );
+ void selectionChanged( const QRect & );
+ void contextPress( const QPoint & );
+ void slotOpenFile();
+ void slotOpenRecent( const KURL & );
+ void slotClose();
+ void slotCopy();
+ void slotPaste();
+ void slotCrop();
+ void slotUpdateFullScreen( bool );
+ void slotToggleMenubar();
+ void slotPreferences();
+ void slotConfigureToolbars();
+ void slotNewToolbarConfig();
+ void reloadConfig();
+ void enableAction( const char *, bool );
+ void clipboardDataChanged();
+ void jobStarted( KIO::Job * );
+ void jobCompleted();
+ void jobCompleted( bool );
+ void jobCanceled( const QString & );
+ void loadingProgress( KIO::Job *, unsigned long );
+ void speedProgress( KIO::Job *, unsigned long );
+ void slotSetStatusBarText( const QString & );
+ void cursorPos( const QPoint & ); // write the cursor pos to the statusbar
+ void loadPlugins();
+ void statusbarToggled( bool );
+
+ private:
+ enum BarSizeFrom { FromImageSize, FromWidgetSize };
+ enum ResizeMode { ResizeWindow = 0, ResizeImage = 1, NoResize = 2, BestFit = 3 };
+ enum StatusBarItem { STATUSBAR_SPEED_ID, STATUSBAR_CURSOR_ID, STATUSBAR_SIZE_ID, STATUSBAR_SELECTION_ID };
+ void setupActions( QObject * );
+ void handleResize();
+ void fitWindowToImage();
+ QSize barSize( int, BarSizeFrom );
+ QSize maxCanvasSize();
+
+ KImageViewer::Viewer * m_pViewer;
+ KImageViewer::Canvas * m_pCanvas;
+ KWinModule * m_pWinModule;
+
+ // Actions:
+ KAction * m_paOpenFile;
+ KAction * m_paPaste;
+ KRecentFilesAction * m_paRecent;
+ KAction * m_paQuit;
+ KToggleFullScreenAction * m_paShowFullScreen;
+ KToggleAction * m_paShowMenubar;
+ KToggleAction * m_paShowStatusBar;
+
+ int m_nResizeMode;
+ bool m_bImageSizeChangedBlocked;
+ bool m_bFullscreen;
+
+ KProgress * m_pProgressBar;
+};
+
+// vim:sw=4:ts=4
+
+#endif // KVIEW_H
diff --git a/kview/kviewcanvas/ChangeLog b/kview/kviewcanvas/ChangeLog
new file mode 100644
index 00000000..1edb3529
--- /dev/null
+++ b/kview/kviewcanvas/ChangeLog
@@ -0,0 +1,18 @@
+2003-09-27 Matthias Kretz <kretz@kde.org>
+
+ * config/confmodules.cpp:
+ Call m_config->sync() in save() and use a real KConfig object instead of
+ a KSimpleConfig.
+ * kimagecanvas.cpp:
+ Renamed readSettings to loadSettings and call it in the ctor.
+
+2003-08-19 Matthias Kretz <kretz@kde.org>
+
+ * kimagecanvas.cpp:
+ Fix checkBounds() to always keep the aspect ratio.
+ Create the factory with it's own KInstance.
+ * kimagecanvas.{h,cpp}:
+ New method boundImageTo( QSize ). Fits the image into the
+ requested width and height.
+
+# vim: sw=4 ts=4 tw=80 noet
diff --git a/kview/kviewcanvas/Makefile.am b/kview/kviewcanvas/Makefile.am
new file mode 100644
index 00000000..27e45d9f
--- /dev/null
+++ b/kview/kviewcanvas/Makefile.am
@@ -0,0 +1,18 @@
+SUBDIRS = config test
+
+kde_module_LTLIBRARIES = libkviewcanvas.la
+INCLUDES = -I$(top_srcdir)/kview $(all_includes)
+
+noinst_HEADERS = kimageholder.h kimagecanvas.h
+
+libkviewcanvas_la_SOURCES = kimageholder.cpp kimagecanvas.cpp
+libkviewcanvas_la_LDFLAGS = $(all_libraries) -module -no-undefined -avoid-version
+libkviewcanvas_la_LIBADD = $(LIB_KPARTS) $(LIB_KDEPRINT) $(LIB_KUTILS) \
+ $(top_builddir)/kview/kimageviewer/libkimageviewer.la
+
+METASOURCES = AUTO
+
+kde_services_DATA = kviewcanvas.desktop
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp *.h -o $(podir)/kviewcanvas.pot
diff --git a/kview/kviewcanvas/config/Makefile.am b/kview/kviewcanvas/config/Makefile.am
new file mode 100644
index 00000000..b22a1ad5
--- /dev/null
+++ b/kview/kviewcanvas/config/Makefile.am
@@ -0,0 +1,16 @@
+kde_module_LTLIBRARIES = kcm_kviewcanvasconfig.la
+INCLUDES = $(all_includes)
+
+noinst_HEADERS = confmodules.h
+
+kcm_kviewcanvasconfig_la_SOURCES = generalconfigwidget.ui confmodules.cpp
+kcm_kviewcanvasconfig_la_LDFLAGS = $(KDE_RPATH) $(all_libraries) -module -avoid-version
+kcm_kviewcanvasconfig_la_LIBADD = $(LIB_KDEUI)
+
+kcm_kviewcanvasconfig_DATA = kviewcanvasconfig.desktop
+kcm_kviewcanvasconfigdir = $(kde_servicesdir)/kconfiguredialog
+
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp *.h -o $(podir)/kcm_kviewcanvasconfig.pot
diff --git a/kview/kviewcanvas/config/confmodules.cpp b/kview/kviewcanvas/config/confmodules.cpp
new file mode 100644
index 00000000..c5e47dac
--- /dev/null
+++ b/kview/kviewcanvas/config/confmodules.cpp
@@ -0,0 +1,145 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002-2003 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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 "confmodules.h"
+#include "generalconfigwidget.h"
+#include "defaults.h"
+
+#include <qlayout.h>
+#include <qcheckbox.h>
+#include <qframe.h>
+
+#include <klocale.h>
+#include <ksimpleconfig.h>
+#include <kcolorbutton.h>
+#include <klistview.h>
+#include <knuminput.h>
+#include <kgenericfactory.h>
+
+typedef KGenericFactory<KViewCanvasConfig, QWidget> KViewCanvasConfigFactory;
+K_EXPORT_COMPONENT_FACTORY( kcm_kviewcanvasconfig, KViewCanvasConfigFactory( "kcm_kviewcanvasconfig" ) )
+
+KViewCanvasConfig::KViewCanvasConfig( QWidget * parent, const char *, const QStringList & args )
+ : KCModule( KViewCanvasConfigFactory::instance(), parent, args )
+ , m_config( new KConfig( "kviewcanvasrc" ) )
+{
+ QBoxLayout * layout = new QVBoxLayout( this );
+ layout->setAutoAdd( true );
+
+ m_pWidget = new GeneralConfigWidget( this );
+ m_pWidget->m_pMinWidth ->setRange( 1, 200 );
+ m_pWidget->m_pMinHeight->setRange( 1, 200 );
+ m_pWidget->m_pMaxWidth ->setRange( 1, 10000 );
+ m_pWidget->m_pMaxHeight->setRange( 1, 10000 );
+
+ // clear m_items
+ m_items.clear();
+
+ for( unsigned int i = 1; i <= Defaults::numOfBlendEffects; ++i )
+ {
+ QCheckListItem * item = new QCheckListItem( m_pWidget->m_pListView, i18n( Defaults::blendEffectDescription[ i ] ), QCheckListItem::CheckBox );
+ m_items.append( item );
+ }
+
+ connect( m_pWidget->m_pListView, SIGNAL( clicked( QListViewItem * ) ), this, SLOT( configChanged() ) );
+ connect( m_pWidget->m_pListView, SIGNAL( spacePressed( QListViewItem * ) ), this, SLOT( configChanged() ) );
+
+ connect( m_pWidget->m_pSmoothScaling, SIGNAL( toggled( bool ) ), this, SLOT( configChanged() ) );
+ connect( m_pWidget->m_pKeepRatio, SIGNAL( toggled( bool ) ), this, SLOT( configChanged() ) );
+ connect( m_pWidget->m_pCenterImage, SIGNAL( toggled( bool ) ), this, SLOT( configChanged() ) );
+ connect( m_pWidget->m_bgColor, SIGNAL( changed( const QColor & ) ), this, SLOT( configChanged() ) );
+ connect( m_pWidget->m_pMinWidth, SIGNAL( valueChanged( int ) ), this, SLOT( configChanged() ) );
+ connect( m_pWidget->m_pMaxWidth, SIGNAL( valueChanged( int ) ), this, SLOT( configChanged() ) );
+ connect( m_pWidget->m_pMinHeight, SIGNAL( valueChanged( int ) ), this, SLOT( configChanged() ) );
+ connect( m_pWidget->m_pMaxHeight, SIGNAL( valueChanged( int ) ), this, SLOT( configChanged() ) );
+
+ load();
+}
+
+KViewCanvasConfig::~KViewCanvasConfig()
+{
+}
+
+void KViewCanvasConfig::save()
+{
+ KConfigGroup cfgGroup( m_config, "Settings" );
+ cfgGroup.writeEntry( "Smooth Scaling", m_pWidget->m_pSmoothScaling->isChecked() );
+ cfgGroup.writeEntry( "Keep Aspect Ratio", m_pWidget->m_pKeepRatio->isChecked() );
+ cfgGroup.writeEntry( "Center Image", m_pWidget->m_pCenterImage->isChecked() );
+
+ cfgGroup.writeEntry( "Background Color", m_pWidget->m_bgColor->color() );
+
+ cfgGroup.writeEntry( "Minimum Width" , m_pWidget->m_pMinWidth->value() );
+ cfgGroup.writeEntry( "Minimum Height", m_pWidget->m_pMinHeight->value() );
+ cfgGroup.writeEntry( "Maximum Width" , m_pWidget->m_pMaxWidth->value() );
+ cfgGroup.writeEntry( "Maximum Height", m_pWidget->m_pMaxHeight->value() );
+
+ KConfigGroup cfgGroup2( m_config, "Blend Effects" );
+ QCheckListItem *item = m_items.first();
+ for( int i = 1; item; item = m_items.next(), ++i )
+ cfgGroup2.writeEntry( QString::number( i ), item->isOn() );
+ m_config->sync();
+}
+
+void KViewCanvasConfig::load()
+{
+ KConfigGroup cfgGroup( m_config, "Settings" );
+ m_pWidget->m_pSmoothScaling->setChecked( cfgGroup.readBoolEntry( "Smooth Scaling", Defaults::smoothScaling ) );
+ m_pWidget->m_pKeepRatio->setChecked( cfgGroup.readBoolEntry( "Keep Aspect Ratio", Defaults::keepAspectRatio ) );
+ m_pWidget->m_pCenterImage->setChecked( cfgGroup.readBoolEntry( "Center Image", Defaults::centerImage ) );
+
+ m_pWidget->m_bgColor->setColor( cfgGroup.readColorEntry( "Background Color", &Defaults::bgColor ) );
+
+ m_pWidget->m_pMinWidth ->setValue( cfgGroup.readNumEntry( "Minimum Width" , Defaults::minSize.width() ) );
+ m_pWidget->m_pMinHeight->setValue( cfgGroup.readNumEntry( "Minimum Height", Defaults::minSize.height() ) );
+ m_pWidget->m_pMaxWidth ->setValue( cfgGroup.readNumEntry( "Maximum Width" , Defaults::maxSize.width() ) );
+ m_pWidget->m_pMaxHeight->setValue( cfgGroup.readNumEntry( "Maximum Height", Defaults::maxSize.height() ) );
+
+ KConfigGroup cfgGroup2( m_config, "Blend Effects" );
+ QCheckListItem * item = m_items.first();
+ for( int i = 1; item; item = m_items.next(), ++i )
+ item->setOn( cfgGroup2.readBoolEntry( QString::number( i ), false ) );
+}
+
+void KViewCanvasConfig::defaults()
+{
+ m_pWidget->m_pSmoothScaling->setChecked( Defaults::smoothScaling );
+ m_pWidget->m_pKeepRatio->setChecked( Defaults::keepAspectRatio );
+ m_pWidget->m_pCenterImage->setChecked( Defaults::centerImage );
+
+ m_pWidget->m_bgColor->setColor( Defaults::bgColor );
+
+ m_pWidget->m_pMinWidth ->setValue( Defaults::minSize.width() );
+ m_pWidget->m_pMinHeight->setValue( Defaults::minSize.height() );
+ m_pWidget->m_pMaxWidth ->setValue( Defaults::maxSize.width() );
+ m_pWidget->m_pMaxHeight->setValue( Defaults::maxSize.height() );
+
+ QCheckListItem * item = m_items.first();
+ for( int i = 1; item; item = m_items.next(), ++i )
+ item->setOn( false );
+ emit changed( true );
+}
+
+void KViewCanvasConfig::configChanged()
+{
+ emit changed( true );
+}
+
+// vim:sw=4:ts=4
+
+#include "confmodules.moc"
diff --git a/kview/kviewcanvas/config/confmodules.h b/kview/kviewcanvas/config/confmodules.h
new file mode 100644
index 00000000..f7dfe262
--- /dev/null
+++ b/kview/kviewcanvas/config/confmodules.h
@@ -0,0 +1,51 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002-2003 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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 CONFMODULES_H
+#define CONFMODULES_H
+
+#include <kcmodule.h>
+#include <qptrlist.h>
+
+class GeneralConfigWidget;
+class QCheckListItem;
+class KConfig;
+
+class KViewCanvasConfig : public KCModule
+{
+ Q_OBJECT
+ public:
+ KViewCanvasConfig( QWidget * parent, const char * name = 0, const QStringList & args = QStringList() );
+ ~KViewCanvasConfig();
+
+ void load();
+ void save();
+ void defaults();
+
+ private slots:
+ void configChanged();
+
+ private:
+ KConfig * m_config;
+ GeneralConfigWidget * m_pWidget;
+ QPtrList<QCheckListItem> m_items;
+};
+
+// vim:sw=4:ts=4
+
+#endif // CONFMODULES_H
diff --git a/kview/kviewcanvas/config/defaults.h b/kview/kviewcanvas/config/defaults.h
new file mode 100644
index 00000000..0a92d651
--- /dev/null
+++ b/kview/kviewcanvas/config/defaults.h
@@ -0,0 +1,46 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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 DEFAULTS_H
+#define DEFAULTS_H
+
+#include <klocale.h>
+#include <qsize.h>
+#include <qcolor.h>
+
+namespace Defaults {
+ static const bool smoothScaling = false;
+ static const bool keepAspectRatio = true;
+ static const bool centerImage = true;
+ static const QColor bgColor( Qt::black );
+ static const QSize minSize( 1, 1 );
+ static const QSize maxSize( 10000, 10000 );
+ static const unsigned int numOfBlendEffects = 4;
+ static const char * blendEffectDescription[ 6 ] = {
+ I18N_NOOP( "No Blending" ),
+ I18N_NOOP( "Wipe From Left" ),
+ I18N_NOOP( "Wipe From Right" ),
+ I18N_NOOP( "Wipe From Top" ),
+ I18N_NOOP( "Wipe From Bottom" ),
+ I18N_NOOP( "Alpha Blend" )
+ };
+}
+
+#endif // DEFAULTS_H
+
+// vim: sw=4 ts=4
diff --git a/kview/kviewcanvas/config/generalconfigwidget.ui b/kview/kviewcanvas/config/generalconfigwidget.ui
new file mode 100644
index 00000000..b4646381
--- /dev/null
+++ b/kview/kviewcanvas/config/generalconfigwidget.ui
@@ -0,0 +1,300 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>GeneralConfigWidget</class>
+<author>Matthias Kretz &lt;kretz@kde.org&gt;</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>GeneralConfigWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>398</width>
+ <height>327</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QLayoutWidget" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>Layout4</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KIntNumInput" row="0" column="1">
+ <property name="name">
+ <cstring>m_pMinHeight</cstring>
+ </property>
+ <property name="label">
+ <string>Minimum height:</string>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="maxValue">
+ <number>200</number>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The height of the image shown will not get smaller than the size you enter here.
+A value of 10 would cause a 1x1 image to be stretched vertically by a factor of 10.</string>
+ </property>
+ </widget>
+ <widget class="KIntNumInput" row="1" column="1">
+ <property name="name">
+ <cstring>m_pMaxHeight</cstring>
+ </property>
+ <property name="label">
+ <string>Maximum height:</string>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="maxValue">
+ <number>100000</number>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The height of the image shown will not get bigger than the size you enter here.
+A value of 100 would cause a 1000x1000 image to be compressed vertically by a factor of 0.1.</string>
+ </property>
+ </widget>
+ <widget class="KIntNumInput" row="0" column="0">
+ <property name="name">
+ <cstring>m_pMinWidth</cstring>
+ </property>
+ <property name="label">
+ <string>Minimum width:</string>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="maxValue">
+ <number>200</number>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The width of the image shown will not get smaller than the size you enter here.
+A value of 10 would cause a 1x1 image to be stretched horizontally by a factor of 10.</string>
+ </property>
+ </widget>
+ <widget class="KIntNumInput" row="1" column="0">
+ <property name="name">
+ <cstring>m_pMaxWidth</cstring>
+ </property>
+ <property name="label">
+ <string>Maximum width:</string>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ <property name="maxValue">
+ <number>100000</number>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>The width of the image shown will not get bigger than the size you enter here.
+A value of 100 would cause a 1000x1000 image to be compressed horizontally by a factor of 0.1.</string>
+ </property>
+ </widget>
+ <spacer row="1" column="2">
+ <property name="name">
+ <cstring>Spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="0" column="2">
+ <property name="name">
+ <cstring>Spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+ </widget>
+ <widget class="QLayoutWidget" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>TextLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Choose which blend effects should be used:</string>
+ </property>
+ </widget>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>Effect</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_pListView</cstring>
+ </property>
+ <property name="selectionMode" stdset="0">
+ <enum>NoSelection</enum>
+ </property>
+ <property name="fullWidth">
+ <bool>true</bool>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>Every effect selected may be used to create a transition effect between the images. If you select multiple effects they will be chosen randomly.</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QLayoutWidget" row="0" column="0">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_pSmoothScaling</cstring>
+ </property>
+ <property name="text">
+ <string>Use smooth scaling (high quality but slower)</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_pKeepRatio</cstring>
+ </property>
+ <property name="text">
+ <string>Keep aspect ratio</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>If this is checked KView will always try to keep the aspect ratio. That means if the width is scaled with a factor x, the height is scaled with the same factor.</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>m_pCenterImage</cstring>
+ </property>
+ <property name="text">
+ <string>Center image</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QGroupBox" row="0" column="1">
+ <property name="name">
+ <cstring>groupBox3</cstring>
+ </property>
+ <property name="title">
+ <string>&amp;Background Color</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KColorButton">
+ <property name="name">
+ <cstring>m_bgColor</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>0</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>32</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer9</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>151</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ </grid>
+</widget>
+<tabstops>
+ <tabstop>m_pSmoothScaling</tabstop>
+ <tabstop>m_pKeepRatio</tabstop>
+ <tabstop>m_pCenterImage</tabstop>
+ <tabstop>m_pMinWidth</tabstop>
+ <tabstop>m_pMinHeight</tabstop>
+ <tabstop>m_pMaxWidth</tabstop>
+ <tabstop>m_pMaxHeight</tabstop>
+ <tabstop>m_pListView</tabstop>
+</tabstops>
+<includes>
+ <include location="global" impldecl="in implementation">kdialog.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/>
+<includehints>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>klistview.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kview/kviewcanvas/config/kviewcanvasconfig.desktop b/kview/kviewcanvas/config/kviewcanvasconfig.desktop
new file mode 100644
index 00000000..7ce31c64
--- /dev/null
+++ b/kview/kviewcanvas/config/kviewcanvasconfig.desktop
@@ -0,0 +1,118 @@
+[Desktop Entry]
+Icon=kview
+Type=Service
+ServiceTypes=KCModule
+
+X-KDE-ModuleType=Library
+X-KDE-Library=kviewcanvasconfig
+X-KDE-FactoryName=KViewCanvasConfigFactory
+X-KDE-ParentApp=kview
+X-KDE-ParentComponents=kviewcanvas
+X-KDE-Weight=1
+X-KDE-CfgDlgHierarchy=Viewer
+
+Name=Viewer
+Name[ar]=العارض
+Name[bg]=Визуализатор
+Name[br]=Gweler
+Name[bs]=Preglednik
+Name[ca]=Visualitzador
+Name[cs]=Prohlížeč
+Name[cy]=Gwelydd
+Name[da]=Fremviser
+Name[de]=Betrachter
+Name[el]=Προβολέας
+Name[eo]=Rigardilo
+Name[es]=Visor
+Name[et]=Näitaja
+Name[eu]=Ikustailua
+Name[fa]=مشاهده‌گر
+Name[fi]=Näytin
+Name[fr]=Afficheur
+Name[gl]=Visor
+Name[he]=מציג
+Name[hi]=प्रदर्शक
+Name[hu]=Nézegető
+Name[is]=Birtir
+Name[it]=Visore
+Name[ja]=ビューア
+Name[kk]=Кескінді қарау
+Name[km]=កម្មវិធី​មើល
+Name[lt]=Žiūriklis
+Name[ms]=Pemapar
+Name[nb]=Fremviser
+Name[nds]=Kieker
+Name[ne]=दर्शक
+Name[nl]=Weergaveprogramma
+Name[nn]=Framvisar
+Name[pa]=ਦਰਸ਼ਕ
+Name[pl]=Przeglądarka obrazków
+Name[pt]=Visualizador
+Name[pt_BR]=Visualizador
+Name[ro]=Vizualizor
+Name[ru]=Просмотрщик
+Name[se]=Čájeheaddji
+Name[sk]=Prehliadač
+Name[sl]=Pregledovalnik
+Name[sr]=Приказивач
+Name[sr@Latn]=Prikazivač
+Name[sv]=Visning
+Name[ta]=காட்சி
+Name[tg]=Намоишгар
+Name[tr]=Görüntüleyici
+Name[uk]=Переглядач
+Name[uz]=Koʻruvchi
+Name[uz@cyrillic]=Кўрувчи
+Name[wa]=Håyneu
+Name[zh_CN]=查看器
+Name[zh_HK]=檢視器
+Comment=General KViewCanvas Configuration
+Comment[ar]=اعدادات KViewCanvas العامة
+Comment[bg]=Общи настройки на визуализатора (KViewCanvas)
+Comment[bs]=Opšte KViewCanvas postavke
+Comment[ca]=Configuració general de KViewCanvas
+Comment[cs]=Obecné nastavení KView
+Comment[cy]=Ffurfweddiad Cyffredinol KGweldCynfas
+Comment[da]=Generel indstilling af KViewCanvas
+Comment[de]=Allgemeine Einstellungen für KViewCanvas
+Comment[el]=Γενική ρύθμιση του KViewCanvas
+Comment[eo]=Ĝenerala Agordo de KViewCanvas
+Comment[es]=Configuración general de KViewCanvas
+Comment[et]=KView lõuendite üldine seadistus
+Comment[eu]=KViewCanvas konfigurazio orokorra
+Comment[fa]=پیکربندی عمومی KViewCanvas
+Comment[fi]=Yleiset KViewCanvas -asetukset
+Comment[fr]=Configuration générale de KViewCanvas
+Comment[gl]=Configuración xeral de KViewCanvas
+Comment[he]=הגדרות KViewCanvas כלליות
+Comment[hi]=सामान्य के-व्यू-केनवास कॉन्फ़िगरेशन
+Comment[hu]=A KViewCanvas általános beállításai
+Comment[is]=Almennar stillingar KViewCanvas
+Comment[it]=Configurazione generale per KViewCanvas
+Comment[ja]=KViewCanvas の一般的な設定
+Comment[kk]=KViewCanvas өрісінің жалпы баптаулары
+Comment[km]=ការ​កំណត់​រចនាសម្ព័ន្ធ​ទូទៅ​សម្រាប់ KViewCanvas
+Comment[lt]=Bendrasis KViewCanvas konfigūravimas
+Comment[ms]=Konfigurasi KViewCanvas Umum
+Comment[nb]=Generelt oppsett av KViewCanvas
+Comment[nds]=Allgemeen Instellen för KViewCanvas
+Comment[ne]=साधारण केडीई दृश्य क्यानभास कन्फिगरेसन
+Comment[nl]=Algemene KViewCanvas instellingen
+Comment[nn]=Generelt oppsett av KViewCanvas
+Comment[pl]=Ogólna konfiguracja KViewCanvas
+Comment[pt]=Configuração Geral do KViewCanvas
+Comment[pt_BR]=Configuração Geral do Canvas com o KView
+Comment[ro]=Configurare KViewCanvas general
+Comment[ru]=Общая настройка KViewCanvas
+Comment[sk]=Všeobecné nastavenie KViewCanvas
+Comment[sl]=Splošne nastavitve KViewCanvas
+Comment[sr]=Општа подешавања за KViewCanvas
+Comment[sr@Latn]=Opšta podešavanja za KViewCanvas
+Comment[sv]=Allmän inställning av Kviews duk
+Comment[ta]=பொதுவான கேகாட்சி சித்திரவடிவ வடிவமைப்பு
+Comment[tg]=Танзимоти умумии KViewCanvas
+Comment[tr]=Genel KView Ekran Ayarları
+Comment[uk]=Загальні параметри KViewCanvas
+Comment[zh_CN]=KViewCanvas 常规配置
+Comment[zh_HK]=一般 KViewCanvas 設定
+Comment[zh_TW]=一般 KViewCanvas 設定
diff --git a/kview/kviewcanvas/kimagecanvas.cpp b/kview/kviewcanvas/kimagecanvas.cpp
new file mode 100644
index 00000000..6c54850f
--- /dev/null
+++ b/kview/kviewcanvas/kimagecanvas.cpp
@@ -0,0 +1,953 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001-2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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 "kimagecanvas.h"
+#include "kimageholder.h"
+#include "version.h"
+#include "config/defaults.h"
+
+#include <qcolor.h>
+#include <qimage.h>
+#include <qapplication.h>
+#include <qwmatrix.h>
+#include <qtimer.h>
+
+#include <kpixmap.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <ksettings/dispatcher.h>
+#include <kconfig.h>
+
+#define KIMAGECANVAS_WIPESIZE 5
+
+const int MOUSECURSORHIDETIME = 3000;
+
+//extern bool qt_use_xrender;
+
+typedef KGenericFactory<KImageCanvas> KImageCanvasFactory;
+K_EXPORT_COMPONENT_FACTORY( libkviewcanvas,
+ KImageCanvasFactory( "kviewcanvas" ) )
+
+KImageCanvas::KImageCanvas( QWidget * parent, const char * name, const QStringList & )
+ : QScrollView( parent, name, WResizeNoErase | WStaticContents )
+ , m_client( 0 )
+ , m_oldClient( 0 )
+ , m_image( 0 )
+ , m_imageTransformed( 0 )
+ , m_pixmap( 0 )
+ , m_pTimer( new QTimer( this, "KImageCanvas/Timer" ) )
+ , m_maxsize( Defaults::maxSize )
+ , m_minsize( Defaults::minSize )
+ , m_currentsize( 0, 0 )
+ , m_zoom( 1.0 )
+ , m_fastscale( ! Defaults::smoothScaling )
+ , m_keepaspectratio( Defaults::keepAspectRatio )
+ , m_bImageChanged( false )
+ , m_bSizeChanged( false )
+ , m_bNeedNewPixmap( false )
+ , m_bCentered( Defaults::centerImage )
+ , m_bImageUpdateScheduled( false )
+ , m_bNewImage( false )
+ , m_iBlendTimerId( 0 )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ setFrameStyle( QFrame::NoFrame );
+ setResizePolicy( QScrollView::Manual );
+ setMinimumSize( 0, 0 );
+ setBgColor( Defaults::bgColor );
+
+ connect( this, SIGNAL( imageChanged() ), this, SLOT( slotImageChanged() ) );
+ connect( m_pTimer, SIGNAL( timeout() ), this, SLOT( hideCursor() ) );
+
+ KSettings::Dispatcher::self()->registerInstance(
+ KImageCanvasFactory::instance(), this,
+ SLOT( loadSettings() ) );
+
+ viewport()->setFocusProxy( this );
+ clear();
+
+ QWidget::setMouseTracking( true );
+ viewport()->setMouseTracking( true );
+ m_cursor.setShape( Qt::CrossCursor );
+ viewport()->setCursor( m_cursor );
+ m_pTimer->start( MOUSECURSORHIDETIME, true );
+
+ loadSettings();
+}
+
+KImageCanvas::~KImageCanvas()
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ delete m_image; m_image = 0;
+ delete m_pixmap; m_pixmap = 0;
+}
+
+void KImageCanvas::setBgColor( const QColor & color )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ viewport()->setPaletteBackgroundColor( color );
+ if( m_client )
+ m_client->setPaletteBackgroundColor( color );
+}
+
+const QColor & KImageCanvas::bgColor() const
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ return viewport()->paletteBackgroundColor();
+}
+
+int KImageCanvas::imageDepth() const
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( ! m_image )
+ return 0;
+
+ return m_image->depth();
+}
+
+QSize KImageCanvas::imageSize() const
+{
+ //kdDebug( 4620 ) << k_funcinfo << endl;
+ if( ! m_image )
+ return QSize( 0, 0 );
+
+ return m_matrix.isIdentity() ? m_image->size() : m_matrix.mapRect( QRect( QPoint(), m_image->size() ) ).size();
+}
+
+QSize KImageCanvas::currentSize() const
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( ! m_image )
+ return QSize( 0, 0 );
+
+ return m_currentsize;
+}
+
+const QImage * KImageCanvas::image() const
+{
+ if( m_imageTransformed )
+ return m_imageTransformed;
+ return m_image;
+}
+
+QRect KImageCanvas::selection() const
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( m_client )
+ return m_selection;
+ else
+ return QRect();
+}
+
+void KImageCanvas::setCentered( bool centered )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( m_bCentered != centered )
+ {
+ m_bCentered = centered;
+ center();
+ }
+}
+
+void KImageCanvas::setImage( const QImage & newimage )
+{
+ bool emitHasImage = m_image ? false : true;
+ m_matrix.reset();
+ matrixChanged();
+ delete m_image;
+ m_image = new QImage( newimage );
+ m_bNewImage = true;
+ // don't emit the signal here - call the slot directly
+ slotImageChanged();
+
+ sizeFromZoom( m_zoom );
+ updateImage();
+ if( emitHasImage && m_image )
+ emit hasImage( true );
+}
+
+void KImageCanvas::setImage( const QImage & newimage, const QSize & size )
+{
+ kdDebug( 4620 ) << k_funcinfo << size << endl;
+ bool emitHasImage = m_image ? false : true;
+ m_matrix.reset();
+ matrixChanged();
+ delete m_image;
+ m_image = new QImage( newimage );
+ m_bNewImage = true;
+ // don't emit the signal here - call the slot directly
+ slotImageChanged();
+
+ resizeImage( size );
+ updateImage();
+ if( emitHasImage && m_image )
+ emit hasImage( true );
+}
+
+void KImageCanvas::setZoom( double zoom )
+{
+ kdDebug( 4620 ) << k_funcinfo << zoom << endl;
+ if( m_image == 0 )
+ return;
+
+ if( zoom > 0.0 && m_zoom != zoom )
+ {
+ m_zoom = zoom;
+ sizeFromZoom( m_zoom );
+ emit zoomChanged( m_zoom );
+ updateImage();
+ }
+}
+
+void KImageCanvas::boundImageTo( const QSize & size )
+{
+ bool keepAspectRatio = m_keepaspectratio;
+ m_keepaspectratio = true;
+ resizeImage( size );
+ m_keepaspectratio = keepAspectRatio;
+}
+
+void KImageCanvas::setMaximumImageSize( const QSize & maxsize )
+{
+ kdDebug( 4620 ) << k_funcinfo << maxsize << endl;
+ if( ( ! m_minsize.isEmpty() ) &&
+ ( maxsize.width() < m_minsize.width() || maxsize.height() < m_minsize.height() ) )
+ {
+ kdWarning( 4620 ) << "the new maximum image size is smaller than the minimum size" << endl;
+ return;
+ }
+
+ m_maxsize = maxsize;
+
+ resizeImage( m_currentsize );
+}
+
+void KImageCanvas::setMinimumImageSize( const QSize & minsize )
+{
+ kdDebug( 4620 ) << k_funcinfo << minsize << endl;
+ if( ( ! m_maxsize.isEmpty() ) &&
+ ( minsize.width() > m_maxsize.width() || minsize.height() > m_maxsize.height() ) )
+ {
+ kdWarning( 4620 ) << "the new minimum image size is greater than the maximum size" << endl;
+ return;
+ }
+
+ m_minsize = minsize;
+
+ resizeImage( m_currentsize );
+}
+
+void KImageCanvas::resizeImage( const QSize & newsize )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( m_image == 0 )
+ return;
+
+ QSize size = newsize;
+
+ // check that it fits into min and max sizes
+ checkBounds( size );
+
+ // calculate the new zoom factor
+ zoomFromSize( size );
+
+ if( size != m_currentsize )
+ {
+ m_currentsize = size;
+ sizeChanged();
+
+ updateImage();
+ }
+}
+
+void KImageCanvas::hideScrollbars( bool hidden )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( hidden )
+ {
+ setVScrollBarMode( AlwaysOff );
+ setHScrollBarMode( AlwaysOff );
+ }
+ else
+ {
+ setVScrollBarMode( Auto );
+ setHScrollBarMode( Auto );
+ }
+}
+
+void KImageCanvas::setKeepAspectRatio( bool aspect )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ m_keepaspectratio = aspect;
+}
+
+unsigned int KImageCanvas::numOfBlendEffects() const
+{
+ return Defaults::numOfBlendEffects;
+}
+
+QString KImageCanvas::blendEffectDescription( unsigned int idx ) const
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ switch( idx )
+ {
+ case NoBlending:
+ kdWarning( 4620 ) << k_funcinfo << " shouldn't be called with an index of 0 - That's always not really defined\n";
+ return i18n( Defaults::blendEffectDescription[ 0 ] );
+ case AlphaBlend:
+ return i18n( Defaults::blendEffectDescription[ 5 ] );
+ case WipeFromLeft:
+ return i18n( Defaults::blendEffectDescription[ 1 ] );
+ case WipeFromRight:
+ return i18n( Defaults::blendEffectDescription[ 2 ] );
+ case WipeFromTop:
+ return i18n( Defaults::blendEffectDescription[ 3 ] );
+ case WipeFromBottom:
+ return i18n( Defaults::blendEffectDescription[ 4 ] );
+ }
+ kdError( 4620 ) << "Effect description for effect with index " << idx << " doesn't exist\n";
+ return QString::null;
+}
+
+bool KImageCanvas::eventFilter( QObject * obj, QEvent * ev )
+{
+ if( ( obj == m_client || obj == m_oldClient ) && ev->type() == QEvent::MouseMove )
+ mouseMoveEvent( static_cast<QMouseEvent*>( ev ) );
+ return QScrollView::eventFilter( obj, ev );
+}
+
+void KImageCanvas::setFastScale( bool fastscale )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ m_fastscale = fastscale;
+ if( m_fastscale )
+ {
+ // wo do scaling with a matrix now, so the m_imageTransformed isn't needed anymore
+ delete m_imageTransformed;
+ m_imageTransformed = 0;
+ }
+ else
+ {
+ matrixChanged(); // set the flag to dirty so that a new m_imageTransformed will be created
+ // else we very relyably get a crash
+ }
+ updateImage();
+}
+
+void KImageCanvas::clear()
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ bool emitHasImage = m_image ? true : false;
+ delete m_image;
+ m_image = 0;
+ m_currentsize -= m_currentsize; //zero size
+ if( m_client )
+ m_client->clear();
+ if( emitHasImage && ! m_image )
+ emit hasImage( false );
+}
+
+void KImageCanvas::flipHorizontal( bool change )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( m_image == 0 )
+ return;
+
+ if( change )
+ {
+ QWMatrix matrix( 1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F );
+ *m_image = m_image->xForm( matrix );
+ emit imageChanged();
+ }
+ else
+ {
+ m_matrix.scale( 1.0, -1.0 );
+ matrixChanged();
+ }
+ // size didn't change
+ updateImage();
+}
+
+void KImageCanvas::flipVertical( bool change )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( m_image == 0 )
+ return;
+
+ if( change )
+ {
+ QWMatrix matrix( -1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F );
+ *m_image = m_image->xForm( matrix );
+ emit imageChanged();
+ }
+ else
+ {
+ m_matrix.scale( -1.0, 1.0 );
+ matrixChanged();
+ }
+ // size didn't change
+ updateImage();
+}
+
+void KImageCanvas::rotate( double a, bool change )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( m_image == 0 )
+ return;
+
+ if( change )
+ {
+ QWMatrix matrix;
+ matrix.rotate( a );
+ *m_image = m_image->xForm( matrix );
+ emit imageChanged();
+ }
+ else
+ {
+ m_matrix.rotate( a );
+ matrixChanged();
+ }
+ //adjust m_currentsize
+ sizeFromZoom( m_zoom );
+ updateImage();
+}
+
+void KImageCanvas::checkBounds( QSize & newsize )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( m_keepaspectratio )
+ {
+ // check that the new size has the same aspect ratio the original image had
+ QSize origsize = imageSize();
+ double x1 = double( origsize.height() ) / double( newsize.height() );
+ double x2 = double( origsize.width() ) / double( newsize.width() );
+ if( ( newsize * x1 != origsize ) || ( newsize * x2 != origsize ) )
+ {
+ // not OK
+ kdDebug( 4620 ) << "checkBounds: the aspect ratio wasn't kept changing from " << newsize << endl;
+ // the user want's that the aspect ratio doesn't change. The
+ // question is: make it larger or smaller?
+ // we make it smaller (we depend on that in boundImageTo)
+ newsize = origsize / KMAX( x1, x2 );
+ kdDebug( 4620 ) << "checkBounds: to " << newsize << endl;
+ }
+ }
+ if( ( ! m_maxsize.isEmpty() ) &&
+ ( newsize.width() > m_maxsize.width() || newsize.height() > m_maxsize.height() ) )
+ {
+ kdDebug( 4620 ) << "checkBounds: the new size is bigger than the max size" << endl;
+ if( m_keepaspectratio )
+ {
+ double x1 = double( m_maxsize.height() ) / double( newsize.height() );
+ double x2 = double( m_maxsize.width() ) / double( newsize.width() );
+ double x = KMIN( x1, x2 );//( x1 > x2 ) ? x2 : x1;
+ newsize *= x;
+ }
+ else
+ newsize = newsize.boundedTo( m_maxsize );
+ }
+ if( ( ! m_minsize.isEmpty() ) &&
+ ( newsize.width() < m_minsize.width() || newsize.height() < m_minsize.height() ) )
+ {
+ kdDebug( 4620 ) << "checkBounds: the new size is smaller than the min size" << endl;
+ if( m_keepaspectratio )
+ {
+ double x1 = double( m_minsize.height() ) / double( newsize.height() );
+ double x2 = double( m_minsize.width() ) / double( newsize.width() );
+ double x = KMAX( x1, x2 );//( x1 > x2 ) ? x1 : x2;
+ newsize *= x;
+ }
+ else
+ newsize = newsize.expandedTo( m_minsize );
+ }
+ // if it still won't fit we have a problem: we can't keep the aspect ratio or we have
+ // to violate the min/max settings
+ if( ( ! m_maxsize.isEmpty() ) &&
+ ( newsize.width() > m_maxsize.width() || newsize.height() > m_maxsize.height() ) )
+ {
+ kdDebug( 4620 ) << "checkBounds: Sorry, I can't keep the aspect ratio." << endl;
+ newsize = newsize.boundedTo( m_maxsize );
+ }
+}
+
+void KImageCanvas::zoomFromSize( const QSize & newsize )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( ! m_image )
+ return;
+
+ QSize originalsize = imageSize();
+ double widthzoom = double( newsize.width() ) / double( originalsize.width() );
+ double heightzoom = double( newsize.height() ) / double( originalsize.height() );
+ double zoom = ( widthzoom + heightzoom ) / 2;
+ if( zoom != m_zoom )
+ {
+ m_zoom = zoom;
+ emit zoomChanged( m_zoom );
+ }
+}
+
+void KImageCanvas::sizeFromZoom( double zoom )
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( ! m_image )
+ return;
+
+ QSize newsize = zoom * imageSize();
+ kdDebug( 4620 ) << "change size from " << imageSize() << " to " << newsize << endl;
+ resizeImage( newsize );
+}
+
+void KImageCanvas::updateImage()
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( ! m_bImageUpdateScheduled )
+ QTimer::singleShot( 0, this, SLOT( slotUpdateImage() ) );
+ m_bImageUpdateScheduled = true;
+}
+
+void KImageCanvas::slotUpdateImage()
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ m_bImageUpdateScheduled = false;
+ if( m_image == 0 )
+ return;
+
+ //only update if something was changed
+ if( m_bImageChanged || m_bSizeChanged || m_bMatrixChanged )
+ {
+ kdDebug( 4620 ) << "actually updating the image now" << endl;
+ QApplication::setOverrideCursor( WaitCursor );
+ if( m_bNewImage || ! m_client )
+ {
+ finishNewClient();
+ m_oldClient = m_client;
+ m_client = createNewClient();
+ }
+ m_client->setImage( pixmap() );
+
+ if( m_bSizeChanged || m_bNewImage )
+ {
+ QSize sh = m_client->sizeHint();
+ if( ! sh.isValid() )
+ sh = QSize( 0, 0 );
+ m_client->resize( sh );
+ resizeContents( sh.width(), sh.height() );
+ center();
+ }
+ QRect drawRect = m_client->drawRect();
+ switch( m_iBlendEffect )
+ {
+ case NoBlending:
+ break;
+ case AlphaBlend:
+ break;
+ case WipeFromLeft:
+ drawRect.setRight( KIMAGECANVAS_WIPESIZE + contentsX() );
+ m_client->setDrawRect( drawRect );
+ break;
+ case WipeFromRight:
+ drawRect.rLeft() += KMIN( drawRect.width() - KIMAGECANVAS_WIPESIZE, contentsX() + visibleWidth() );
+ m_client->setDrawRect( drawRect );
+ break;
+ case WipeFromTop:
+ drawRect.setBottom( KIMAGECANVAS_WIPESIZE + contentsY() );
+ m_client->setDrawRect( drawRect );
+ break;
+ case WipeFromBottom:
+ drawRect.setTop( KMIN( drawRect.height() - KIMAGECANVAS_WIPESIZE, contentsY() + visibleHeight() ) );
+ m_client->setDrawRect( drawRect );
+ break;
+ }
+ m_client->update();
+ m_iBlendTimerId = startTimer( 5 );
+ QApplication::restoreOverrideCursor();
+ }
+
+ m_bNewImage = false;
+ m_bImageChanged = false;
+ m_bSizeChanged = false;
+ m_bMatrixChanged = false;
+}
+
+void KImageCanvas::mouseMoveEvent( QMouseEvent * )
+{
+ if( m_cursor.shape() == Qt::BlankCursor )
+ {
+ m_cursor.setShape( Qt::CrossCursor );
+ viewport()->setCursor( m_cursor );
+ if( m_client )
+ m_client->setCursor( m_cursor );
+ }
+ m_pTimer->start( MOUSECURSORHIDETIME, true );
+}
+
+
+void KImageCanvas::resizeEvent( QResizeEvent * ev )
+{
+ kdDebug( 4620 ) << "KImageCanvas resized to " << ev->size() << endl;
+ QScrollView::resizeEvent( ev );
+ center();
+}
+
+void KImageCanvas::contentsMousePressEvent( QMouseEvent * ev )
+{
+ if ( ev->button() == RightButton )
+ emit contextPress( ev->globalPos() );
+ QScrollView::contentsMousePressEvent( ev );
+}
+
+void KImageCanvas::contentsWheelEvent( QWheelEvent * ev )
+{
+ //kdDebug( 4620 ) << k_funcinfo << endl;
+ // Ctrl+Wheelmouse changes the zoom.
+ // Wheelmouse scrolls around
+ if ( ev->state() & ControlButton )
+ {
+ int delta = ev->delta() / 120;
+ double zoom = m_zoom;
+ // make zoom a value of 1/16, 1/15, 1/14, .. , 1/2, 1, 2, 3, .. , 15, 16
+ bool done = false;
+ for( int i = 15; i > 0; --i )
+ {
+ if( zoom <= ( 1.0 / i ) )
+ {
+ if( zoom < ( 1.0 / ( i + 0.5 ) ) )
+ zoom = ( 1.0 / ( i + 1 ) );
+ else
+ zoom = ( 1.0 / i );
+ done = true;
+ // zoom = 1/16, 1/15, .. , 1/2, 1
+ double x = 1.0 / zoom - delta;
+ if( x == 0 )
+ zoom = 2.0;
+ else
+ zoom = 1.0 / x;
+ break;
+ }
+ }
+ if( ! done )
+ for( int i = 2; i < 17; ++i )
+ {
+ if( zoom < (double)i )
+ {
+ if( zoom < ( i - 0.5 ) )
+ zoom = i - 1.0;
+ else
+ zoom = (double)i;
+ done = true;
+ // zoom = 1, 2, .., 15, 16
+ zoom = zoom + delta;
+ if( zoom < 0.9 )
+ zoom = 0.5;
+ break;
+ }
+ }
+ if( ! done )
+ {
+ zoom = 16.0;
+ zoom = zoom + delta;
+ if( zoom > 16.0 )
+ zoom = 16.0;
+ }
+ kdDebug( 4620 ) << "Mousewheel: oldzoom = " << m_zoom << " newzoom = " << zoom << endl;
+ ev->accept();
+ bool oldscale = fastScale();
+ setFastScale( true );
+ setZoom( zoom );
+ setFastScale( oldscale );
+ }
+ else
+ QScrollView::contentsWheelEvent( ev );
+}
+
+void KImageCanvas::keyPressEvent( QKeyEvent * ev )
+{
+ //kdDebug( 4620 ) << k_funcinfo << endl;
+ switch( ev->key() )
+ {
+ case Key_Down:
+ ev->accept();
+ verticalScrollBar()->addLine();
+ break;
+ case Key_Up:
+ ev->accept();
+ verticalScrollBar()->subtractLine();
+ break;
+ case Key_Left:
+ ev->accept();
+ horizontalScrollBar()->subtractLine();
+ break;
+ case Key_Right:
+ ev->accept();
+ horizontalScrollBar()->addLine();
+ break;
+ case Key_PageUp:
+ ev->accept();
+ verticalScrollBar()->subtractPage();
+ break;
+ case Key_PageDown:
+ ev->accept();
+ verticalScrollBar()->addPage();
+ break;
+ default:
+ ev->ignore();
+ break;
+ }
+}
+
+void KImageCanvas::timerEvent( QTimerEvent * ev )
+{
+ if( ev->timerId() == m_iBlendTimerId )
+ {
+ QRect drawRect = m_client->drawRect();
+ switch( m_iBlendEffect )
+ {
+ case NoBlending:
+ finishNewClient();
+ break;
+ case AlphaBlend:
+ finishNewClient();
+ //if( qt_use_xrender )
+ //{
+ //}
+ //else
+ //{
+ //kdWarning( 4620 ) << "no XRender" << endl;
+ //finishNewClient();
+ //}
+ break;
+ case WipeFromLeft:
+ drawRect.rRight() += KIMAGECANVAS_WIPESIZE;
+ m_client->setDrawRect( drawRect );
+ m_client->update( drawRect.right() - KIMAGECANVAS_WIPESIZE, 0, KIMAGECANVAS_WIPESIZE, m_client->height() );
+ if( drawRect.right() >= contentsX() + visibleWidth() )
+ finishNewClient();
+ break;
+ case WipeFromRight:
+ drawRect.rLeft() -= KIMAGECANVAS_WIPESIZE;
+ m_client->setDrawRect( drawRect );
+ m_client->update( drawRect.left(), 0, KIMAGECANVAS_WIPESIZE, m_client->height() );
+ if( drawRect.left() <= contentsX() )
+ finishNewClient();
+ break;
+ case WipeFromTop:
+ drawRect.rBottom() += KIMAGECANVAS_WIPESIZE;
+ m_client->setDrawRect( drawRect );
+ m_client->update( 0, drawRect.bottom() - KIMAGECANVAS_WIPESIZE, m_client->width(), KIMAGECANVAS_WIPESIZE );
+ if( drawRect.bottom() >= contentsY() + visibleHeight() )
+ finishNewClient();
+ break;
+ case WipeFromBottom:
+ drawRect.rTop() -= KIMAGECANVAS_WIPESIZE;
+ m_client->setDrawRect( drawRect );
+ m_client->update( 0, drawRect.top(), m_client->width(), KIMAGECANVAS_WIPESIZE );
+ if( drawRect.top() <= contentsY() )
+ finishNewClient();
+ break;
+ default:
+ kdFatal( 4620 ) << "unknown Blend Effect" << endl;
+ break;
+ }
+ }
+ else
+ killTimer( ev->timerId() );
+}
+
+void KImageCanvas::hideCursor()
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ m_cursor.setShape( Qt::BlankCursor );
+ viewport()->setCursor( m_cursor );
+ if( m_client )
+ m_client->setCursor( m_cursor );
+}
+
+const KPixmap KImageCanvas::pixmap()
+{
+ kdDebug( 4620 ) << k_funcinfo << ( m_bNeedNewPixmap ? "convert from Image" : "use old copy" ) << endl;
+ // create a new Pixmap in m_pixmap if needed
+ if( m_bNeedNewPixmap )
+ {
+ // only do it again if requested
+ m_bNeedNewPixmap = false;
+ // ok, the old one may go now
+ delete m_pixmap;
+
+ // if smoothscaling is wanted and the transformation matrix or the image
+ // itself changed...
+ if( ! m_fastscale && ( m_bMatrixChanged || m_bImageChanged ) )
+ {
+ delete m_imageTransformed;
+ // we create a new image transformed by the matrix
+ m_imageTransformed = new QImage( m_matrix.isIdentity() ? *m_image : m_image->xForm( m_matrix ) );
+ kdDebug( 4620 ) << "Size of m_image: " << m_image->size() << endl;
+ kdDebug( 4620 ) << "Size of m_imageTransformed: " << m_imageTransformed->size() << endl;
+ }
+ // smoothScale or fast scaling via m_matrix
+ m_pixmap = new KPixmap();
+ m_pixmap->convertFromImage( m_fastscale ? *m_image : m_imageTransformed->smoothScale( m_currentsize ), KPixmap::ColorOnly );
+ }
+ if( m_fastscale )
+ {
+ // fast scaling is needed so we need to scale now
+ QWMatrix matrix( m_matrix );
+ matrix.scale( m_zoom, m_zoom );
+ if( ! matrix.isIdentity() )
+ return m_pixmap->xForm( matrix );
+ }
+ return *m_pixmap;
+}
+
+void KImageCanvas::slotImageChanged()
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ m_bImageChanged = true;
+ m_bNeedNewPixmap = true;
+}
+
+void KImageCanvas::loadSettings()
+{
+ KConfigGroup cfgGroup( KImageCanvasFactory::instance()->config(),
+ "Settings" );
+ setFastScale( ! cfgGroup.readBoolEntry( "Smooth Scaling", ! fastScale() ) );
+ setKeepAspectRatio( cfgGroup.readBoolEntry( "Keep Aspect Ratio",
+ keepAspectRatio() ) );
+ setCentered( cfgGroup.readBoolEntry( "Center Image", centered() ) );
+
+ setBgColor( cfgGroup.readColorEntry( "Background Color", &bgColor() ) );
+
+ setMinimumImageSize( QSize( cfgGroup.readNumEntry( "Minimum Width",
+ minimumImageSize().width() ), cfgGroup.readNumEntry(
+ "Minimum Height", minimumImageSize().height() ) ) );
+ setMaximumImageSize( QSize( cfgGroup.readNumEntry( "Maximum Width",
+ maximumImageSize().width() ), cfgGroup.readNumEntry(
+ "Maximum Height", maximumImageSize().height() ) ) );
+
+ KConfigGroup blendConfig( KImageCanvasFactory::instance()->config(),
+ "Blend Effects" );
+ /* TODO
+ m_vEffects.clear();
+ for( unsigned int i = 1; i <= numOfBlendEffects(); ++i )
+ {
+ if( blendConfig.readBoolEntry( QString::number( i ), false ) )
+ m_vEffects.push_back( i );
+ }
+ // and now tell the canvas what blend effect to use
+ switchBlendEffect();
+ */
+}
+
+void KImageCanvas::selected( const QRect & rect )
+{
+ //kdDebug( 4620 ) << k_funcinfo << rect << endl;
+ m_selection = rect;
+ if( ! m_selection.isNull() )
+ {
+ m_selection.setTop( int( ( m_selection.top() + 0.5 ) / m_zoom ) );
+ m_selection.setLeft( int( ( m_selection.left() + 0.5 ) / m_zoom ) );
+ m_selection.setRight( int( ( m_selection.right() + 0.5 ) / m_zoom ) );
+ m_selection.setBottom( int( ( m_selection.bottom() + 0.5 ) / m_zoom ) );
+ }
+ //kdDebug( 4620 ) << "m_selection = " << m_selection << endl;
+ emit selectionChanged( m_selection );
+}
+
+void KImageCanvas::mapCursorPos( const QPoint & pos )
+{
+ QPoint mapped( static_cast<int>( ( pos.x() + 0.5 ) / m_zoom ), static_cast<int>( ( pos.y() + 0.5 ) / m_zoom ) );
+ //kdDebug( 4620 ) << k_funcinfo << pos << " -> " << mapped << endl;
+ emit cursorPos( mapped );
+}
+
+void KImageCanvas::sizeChanged()
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ m_bSizeChanged = true;
+ if( ! m_fastscale )
+ m_bNeedNewPixmap = true;
+ emit imageSizeChanged( m_currentsize );
+}
+
+void KImageCanvas::matrixChanged()
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ m_bMatrixChanged = true;
+ m_bNeedNewPixmap = true;
+}
+
+void KImageCanvas::center()
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ if( m_bCentered && m_client )
+ {
+ int x = 0;
+ int y = 0;
+
+ int scrollbarwidth = ( height() >= m_currentsize.height() ) ? 0 : verticalScrollBar()->width();
+ int scrollbarheight = ( width() - scrollbarwidth >= m_currentsize.width() ) ? 0 : horizontalScrollBar()->height();
+ scrollbarwidth = ( height() - scrollbarheight >= m_currentsize.height() ) ? 0 : verticalScrollBar()->width();
+
+ int availheight = height() - scrollbarheight;
+ int availwidth = width() - scrollbarwidth;
+
+ if( availwidth > m_currentsize.width() )
+ x = ( availwidth - m_currentsize.width() ) / 2;
+ if( availheight > m_currentsize.height() )
+ y = ( availheight - m_currentsize.height() ) / 2;
+
+ kdDebug( 4620 ) << "center with left top at " << x << ", " << y << endl;
+ moveChild( m_client, x, y );
+ }
+}
+
+void KImageCanvas::finishNewClient()
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ killTimer( m_iBlendTimerId );
+ if( m_client )
+ m_client->setDrawRect( m_client->rect() );
+ delete m_oldClient;
+ m_oldClient = 0;
+ emit showingImageDone();
+}
+
+KImageHolder * KImageCanvas::createNewClient()
+{
+ kdDebug( 4620 ) << k_funcinfo << endl;
+ KImageHolder * client = new KImageHolder( viewport() );
+ client->setMinimumSize( 0, 0 );
+ client->setMouseTracking( true );
+ client->installEventFilter( this );
+ setFocusProxy( client );
+ client->setFocusPolicy( QWidget::StrongFocus );
+ client->setFocus();
+
+ addChild( client, 0, 0 );
+
+ connect( client, SIGNAL( contextPress( const QPoint& ) ), SIGNAL( contextPress( const QPoint& ) ) );
+ connect( client, SIGNAL( cursorPos( const QPoint & ) ), SLOT( mapCursorPos( const QPoint & ) ) );
+ connect( client, SIGNAL( selected( const QRect & ) ), SLOT( selected( const QRect & ) ) );
+ connect( client, SIGNAL( wannaScroll( int, int ) ), SLOT( scrollBy( int, int ) ) );
+
+ return client;
+}
+
+#include "kimagecanvas.moc"
+
+// vim:sw=4:ts=4
diff --git a/kview/kviewcanvas/kimagecanvas.h b/kview/kviewcanvas/kimagecanvas.h
new file mode 100644
index 00000000..8a0bffda
--- /dev/null
+++ b/kview/kviewcanvas/kimagecanvas.h
@@ -0,0 +1,366 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001-2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+
+*/
+// $Id$
+
+#ifndef _KIMAGECANVAS_H
+#define _KIMAGECANVAS_H
+
+#include "kimageviewer/canvas.h"
+
+#include <qscrollview.h>
+#include <qwmatrix.h>
+#include <qcursor.h>
+#include <qrect.h>
+
+#include <kdemacros.h>
+
+class KImageHolder;
+class QColor;
+class QImage;
+class KPixmap;
+
+/**
+ * @short KViewCanvas
+ * @author Matthias Kretz <kretz@kde.org>
+ * @version $Id$
+ */
+class KDE_EXPORT KImageCanvas : public QScrollView, public KImageViewer::Canvas
+{
+ Q_OBJECT
+ public:
+ /**
+ * KImageCanvas Constructor
+ */
+ KImageCanvas( QWidget * parent, const char * name, const QStringList & args );
+
+ /**
+ * KImageCanvas Destructor
+ */
+ virtual ~KImageCanvas();
+
+ /**
+ * set the background color of the canvas
+ */
+ void setBgColor( const QColor & );
+
+ /**
+ * returns the current background color
+ */
+ const QColor & bgColor() const;
+
+ /**
+ * the depth of the contained image
+ */
+ int imageDepth() const;
+
+ /**
+ * the size of the unzoomed image
+ */
+ QSize imageSize() const;
+
+ /**
+ * the size of the zoomed (current) image
+ */
+ QSize currentSize() const;
+
+ /**
+ * returns the zoom factor
+ */
+ double zoom() const { return m_zoom; }
+
+ /**
+ * returns the current (unzoomed) image
+ */
+ const QImage * image() const;
+
+ /**
+ * Scrolls the content so that the point (x, y) is in the top-left corner.
+ */
+ void setXYOffset( int x, int y ) { setContentsPos( x, y ); }
+
+ /**
+ * Returns the leftmost visible X coordinate of the image.
+ */
+ int xOffset() const { return contentsX(); }
+
+ /**
+ * Returns the topmost visible Y coordinate of the image.
+ */
+ int yOffset() const { return contentsY(); }
+
+ /**
+ * Returns whether to use fast or smooth scaling
+ */
+ bool fastScale() const { return m_fastscale; }
+
+ /**
+ * Return whether the image should always be centered.
+ */
+ bool centered() const { return m_bCentered; }
+
+ /**
+ * Return the selected rectangle
+ */
+ QRect selection() const;
+
+ /**
+ * Returns whether the aspect ratio of the image is kept
+ */
+ bool keepAspectRatio() const { return m_keepaspectratio; }
+
+ /**
+ * @return the number of available blend effects
+ */
+ unsigned int numOfBlendEffects() const;
+
+ /**
+ * @return the description of the blend effect
+ */
+ QString blendEffectDescription( unsigned int ) const;
+
+ /**
+ * @return the current maximum image size
+ */
+ const QSize & maximumImageSize() const { return m_maxsize; }
+
+ /**
+ * @return the current minimum image size
+ */
+ const QSize & minimumImageSize() const { return m_minsize; }
+
+ /**
+ * @return a pointer to the QWidget interface of this object
+ */
+ QWidget * widget() { return static_cast<QWidget *>( this ); }
+
+ bool eventFilter( QObject *, QEvent * );
+
+ signals:
+ /**
+ * a mouse button was pressed and a context menu should be openend
+ */
+ void contextPress( const QPoint& );
+
+ /**
+ * the size of the image has changed (a new image was loaded, or the
+ * image was zoomed or cropped)
+ *
+ * it passes the new size of the image
+ */
+ void imageSizeChanged( const QSize & );
+
+ /**
+ * The zoom of the image has changed.
+ */
+ void zoomChanged( double zoom );
+
+ /**
+ * The selection has changed. Connect to this signal if you want to
+ * do something with a selection of the image (e.g. crop).
+ */
+ void selectionChanged( const QRect & );
+
+ /**
+ * Emitted when an image is finished being shown. If a blend effect is being used
+ * the signal is emitted when the effect is finished.
+ */
+ void showingImageDone();
+
+ /**
+ * This signal is emitted whenever the canvas changes between image/no-image. For
+ * example, if someone calls @ref clear() hasImage( false ) is emitted if an image
+ * was shown before.
+ */
+ void hasImage( bool );
+
+ /**
+ * Some methods of the canvas not only change the way the image is shown (e.g. zoom)
+ * but also change the image itself (e.g. rotation) - @ref image() returns something
+ * different. If such a change happens this signal is emitted.
+ * It is not emitted when a new image is set with the @ref setImage() methods.
+ */
+ void imageChanged();
+
+ /**
+ * The current mouse cursor position on the image.
+ */
+ void cursorPos( const QPoint & );
+
+ public slots:
+ /**
+ * Set if the image should always be centered if the canvas is
+ * bigger than the image.
+ */
+ void setCentered( bool );
+
+ /**
+ * give the canvas a new image to show. The zoom level is kept.
+ */
+ void setImage( const QImage & );
+
+ /**
+ * Give the canvas a new image to show.
+ *
+ * You have to pass the size the image should have when it appears
+ * on screen.
+ */
+ void setImage( const QImage &, const QSize & );
+
+ /**
+ * set the zoom to be used when showing the image
+ */
+ void setZoom( double );
+
+ /**
+ * Fit the image into the requested width and height.
+ */
+ void boundImageTo( const QSize & size );
+
+ /**
+ * Set the maximum size of the image. If this is set the image will
+ * never exceed this size.
+ *
+ * If you set this to 0x0 the image size may be as big as possible
+ */
+ void setMaximumImageSize( const QSize & );
+
+ /**
+ * Set the minimum size of the image. If this is set the image will
+ * never be smaller than this size.
+ *
+ * If you set this to 0x0 the image size can be as small as possible
+ */
+ void setMinimumImageSize( const QSize & );
+
+ /**
+ * Resize the image to the given size. It will keep the aspect ratio
+ * as long as keepAspectRatio is true (default). The image will be as
+ * large as possible within the given constraints.
+ */
+ void resizeImage( const QSize & );
+
+ /**
+ * Hides the scrollbars of the canvas. It's still possible to scroll
+ * by moving the image with the mouse.
+ */
+ void hideScrollbars( bool );
+
+ /**
+ * Changes the zoom behaviour: Normally the aspect ratio of the image
+ * won't change, but if you want to allow it you may do.
+ */
+ void setKeepAspectRatio( bool );
+
+ /**
+ * If the canvas supports different methods for scaling you may
+ * switch between fast and smooth scaling.
+ *
+ * It defaults to smooth scaling.
+ */
+ void setFastScale( bool );
+
+ /**
+ * clears the canvas (no image loaded)
+ */
+ void clear();
+
+ /**
+ * flip the image horizontally
+ */
+ void flipHorizontal( bool change = false );
+
+ /**
+ * flip the image vertically
+ */
+ void flipVertical( bool change = false );
+
+ /**
+ * rotate the image a degrees counterclockwise
+ */
+ void rotate( double a, bool change = false );
+
+ protected:
+ void checkBounds( QSize & newsize );
+ void zoomFromSize( const QSize & );
+ void sizeFromZoom( double );
+ void updateImage();
+
+ void mouseMoveEvent( QMouseEvent * );
+ void resizeEvent( QResizeEvent * );
+ void contentsMousePressEvent( QMouseEvent * );
+ void contentsWheelEvent( QWheelEvent * );
+ void keyPressEvent( QKeyEvent * );
+ void timerEvent( QTimerEvent * );
+
+ protected slots:
+ void slotUpdateImage();
+ void hideCursor();
+ void slotImageChanged();
+ void loadSettings();
+
+ private slots:
+ void selected( const QRect & ); // map rect to unzoomed rect
+ void mapCursorPos( const QPoint & );
+
+ private:
+ enum BlendEffect {
+ NoBlending = 0,
+ WipeFromLeft = 1,
+ WipeFromRight = 2,
+ WipeFromTop = 3,
+ WipeFromBottom = 4,
+ AlphaBlend = 5
+ };
+ const KPixmap pixmap();
+ void sizeChanged();
+ void matrixChanged();
+ void center();
+ void finishNewClient();
+ KImageHolder * createNewClient();
+
+ KImageHolder * m_client;
+ KImageHolder * m_oldClient;
+ QImage * m_image; //unzoomed copy of the current image
+ QImage * m_imageTransformed; //xForm( m_matrix ) copy of the current image
+ KPixmap * m_pixmap; //copy of the current pixmap (if ( m_fastscale ) it's unzoomed else it's m_imageTransformed.smoothScale()d)
+
+ QTimer * m_pTimer; // timer for single shot to hide the cursor
+ QCursor m_cursor; // the cursor show in the canvas (for auto-hiding)
+
+ QWMatrix m_matrix; // the current transformation matrix
+ QSize m_maxsize, m_minsize;
+ QSize m_currentsize;
+
+ double m_zoom;
+ bool m_fastscale;
+ bool m_keepaspectratio;
+ bool m_bImageChanged;
+ bool m_bSizeChanged;
+ bool m_bMatrixChanged;
+ bool m_bNeedNewPixmap;
+ bool m_bCentered;
+ bool m_bImageUpdateScheduled;
+ bool m_bNewImage;
+ int m_iBlendTimerId;
+
+ QRect m_selection; //unzoomed selection rect
+};
+
+// vim:sw=4:ts=4
+
+#endif // _KIMAGECANVAS_H
diff --git a/kview/kviewcanvas/kimageholder.cpp b/kview/kviewcanvas/kimageholder.cpp
new file mode 100644
index 00000000..9009c7fc
--- /dev/null
+++ b/kview/kviewcanvas/kimageholder.cpp
@@ -0,0 +1,371 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001-2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+
+*/
+
+//$Id$
+
+#include <assert.h>
+
+#include <qcolor.h>
+#include <qwidget.h>
+#include <qimage.h>
+#include <qpainter.h>
+#include <qpen.h>
+#include <qmovie.h>
+#include <qpixmap.h>
+
+#include <kpixmap.h>
+#include <kdebug.h>
+
+#include "kimageholder.h"
+
+KImageHolder::KImageHolder( QWidget * parent, const char * name )
+ : QWidget( parent, name, Qt::WResizeNoErase | Qt::WRepaintNoErase )
+ , m_selected( false )
+ , m_bSelecting( false )
+ , m_scrollTimerId( 0 )
+ , m_xOffset( 0 )
+ , m_yOffset( 0 )
+ , m_pen( new QPen( QColor( 255, 255, 255 ), 0, DashLine ) )
+ , m_pPixmap( 0 )
+ , m_pDoubleBuffer( 0 )
+ , m_pCheckboardPixmap( 0 )
+{
+ setBackgroundMode( QWidget::NoBackground );
+}
+
+KImageHolder::~KImageHolder()
+{
+ delete m_pen;
+ delete m_pPixmap;
+ delete m_pDoubleBuffer;
+ delete m_pCheckboardPixmap;
+ m_pen = 0;
+ m_pPixmap = 0;
+ m_pDoubleBuffer = 0;
+ m_pCheckboardPixmap = 0;
+}
+
+void KImageHolder::mousePressEvent( QMouseEvent *ev )
+{
+ //kdDebug( 4620 ) << k_funcinfo << " ev->state() = " << ev->state() << endl;
+ // if the right mouse button is pressed emit the contextPress signal
+ if ( ev->button() == RightButton )
+ {
+ emit contextPress( mapToGlobal( ev->pos() ) );
+ return;
+ }
+
+ if( m_pPixmap == 0 )
+ return;
+
+ if( ev->button() == LeftButton || ev->button() == MidButton )
+ {
+ m_scrollpos = ev->globalPos();
+ m_selectionStartPoint = ev->pos();
+ }
+}
+
+void KImageHolder::mouseMoveEvent( QMouseEvent *ev )
+{
+ //FIXME: when scrolling the cursorpos shouldn't change
+ if( this->rect().contains( ev->pos(), false ) )
+ emit cursorPos( ev->pos() );
+ //kdDebug( 4620 ) << k_funcinfo << " ev->state() = " << ev->state() << endl;
+ if( ev->state() & LeftButton || ev->state() & MidButton )
+ {
+ // scroll when a modifier and left button or the middle button is pressed
+ if( ev->state() & AltButton || ev->state() & ControlButton || ev->state() & ShiftButton || ev->state() & MidButton )
+ {
+ QPoint difference = m_scrollpos - ev->globalPos();
+ emit wannaScroll( difference.x(), difference.y() );
+ }
+ else // create a selection
+ {
+ QWidget * parentwidget = ( QWidget* )parent();
+ if( ! m_bSelecting )
+ {
+ m_bSelecting = true;
+ if( m_selected ) {
+ // remove old rubberband
+ eraseSelect();
+ m_selected = false;
+ }
+
+ m_selection.setLeft( m_selectionStartPoint.x() );
+ m_selection.setRight( m_selectionStartPoint.x() );
+ m_selection.setTop( m_selectionStartPoint.y() );
+ m_selection.setBottom( m_selectionStartPoint.y() );
+ }
+ // currently called only on drag,
+ // so assume a selection has been started
+ bool erase = m_selected;
+
+ if( !m_selected )
+ m_selected = true;
+
+ // Autoscrolling:
+ // For every pixel the mouse leaves the image canvas the canvas
+ // should scroll faster. The scrolling should be independent from
+ // the mouse movement. Therefor I need a timer to do the scroll
+ // movement:
+ // e.g.: m_xOffset=-1 => scroll to the left 1 px per 50ms
+ // -2 => scroll to the left 2 px per 50ms
+ // 2 => scroll to the right 2 px per 50ms
+ // ...
+ m_xOffset = mapTo( parentwidget, ev->pos() ).x();
+ m_yOffset = mapTo( parentwidget, ev->pos() ).y();
+ if( m_xOffset > 0 )
+ {
+ m_xOffset -= parentwidget->width();
+ if( m_xOffset < 0 )
+ m_xOffset = 0;
+ }
+ if( m_yOffset > 0 )
+ {
+ m_yOffset -= parentwidget->height();
+ if( m_yOffset < 0 )
+ m_yOffset = 0;
+ }
+ if( m_scrollTimerId != 0 && m_xOffset == 0 && m_yOffset == 0 )
+ {
+ killTimer( m_scrollTimerId );
+ m_scrollTimerId = 0;
+ }
+ else if( m_scrollTimerId == 0 && ( m_xOffset != 0 || m_yOffset != 0 ) )
+ m_scrollTimerId = startTimer( 50 );
+
+ int r = ev->x() < width() ? ( ev->x() < 0 ? 0 : ev->x() ) : width() - 1;
+ int b = ev->y() < height() ? ( ev->y() < 0 ? 0 : ev->y() ) : height() - 1;
+
+ if( r != m_selection.right() || b != m_selection.bottom() )
+ {
+ if( erase )
+ eraseSelect();
+
+ m_selection.setRight( r );
+ m_selection.setBottom( b );
+ emit selected( m_selection.normalize() );
+
+ QPainter painter( this );
+ drawSelect( painter );
+ }
+ }
+ m_scrollpos = ev->globalPos();
+ m_selectionStartPoint = ev->pos();
+ }
+}
+
+void KImageHolder::mouseReleaseEvent( QMouseEvent * ev )
+{
+ if( m_bSelecting )
+ {
+ m_xOffset = m_yOffset = 0;
+ if( m_scrollTimerId != 0 )
+ {
+ killTimer( m_scrollTimerId );
+ m_scrollTimerId = 0;
+ }
+ }
+ if( ev->state() & LeftButton || ev->state() & MidButton )
+ if( m_bSelecting )
+ m_bSelecting = false;
+ else
+ clearSelection();
+}
+
+void KImageHolder::drawSelect( QPainter & painter )
+{
+ painter.save();
+ painter.setRasterOp( XorROP );
+ painter.setPen( *m_pen );
+ painter.drawRect( m_selection.normalize() );
+ painter.restore();
+}
+
+void KImageHolder::eraseSelect()
+{
+ QRegion r( m_selection.normalize() );
+ QRect inner = m_selection.normalize();
+ inner.rLeft() += 1;
+ inner.rTop() += 1;
+ inner.rRight() -= 1;
+ inner.rBottom() -= 1;
+ r -= inner;
+
+ QMemArray<QRect> rects = r.rects();
+
+ if( m_pDoubleBuffer )
+ for( unsigned int i = 0; i < rects.size(); ++i )
+ bitBlt( this, rects[ i ].topLeft(), m_pDoubleBuffer, rects[ i ], CopyROP );
+ else
+ for( unsigned int i = 0; i < rects.size(); ++i )
+ bitBlt( this, rects[ i ].topLeft(), m_pPixmap, rects[ i ], CopyROP );
+}
+
+void KImageHolder::clearSelection()
+{
+ if( m_selected )
+ {
+ eraseSelect();
+ m_selected = false;
+ }
+ m_selection.setSize( QSize( 0, 0 ) );
+ emit selected( m_selection );
+}
+
+void KImageHolder::setImage( const KPixmap & pix )
+{
+ clearSelection();
+
+ setPixmap( pix );
+}
+
+void KImageHolder::setImage( const QImage & image )
+{
+ clearSelection();
+ kdDebug( 4620 ) << "converting Image to Pixmap" << endl;
+ KPixmap pix( image );
+
+ setPixmap( pix );
+}
+
+void KImageHolder::setImage( const QMovie & /*movie*/ )
+{
+ clearSelection();
+ //setMovie( movie );
+ kdWarning( 4620 ) << "setImage( QMovie ) not implemented" << endl;
+}
+
+void KImageHolder::clear()
+{
+ delete m_pPixmap;
+ m_pPixmap = 0;
+ delete m_pDoubleBuffer;
+ m_pDoubleBuffer = 0;
+ hide();
+ clearSelection();
+}
+
+QRect KImageHolder::selection() const
+{
+ if( m_selected )
+ return m_selection.normalize();
+ else
+ return QRect();
+}
+
+QSize KImageHolder::sizeHint() const
+{
+ if( m_pPixmap )
+ return m_pPixmap->size();
+ return QSize( 0, 0 );
+}
+
+void KImageHolder::paintEvent( QPaintEvent *ev )
+{
+ QPainter painter( this );
+ painter.setClipRegion( ev->region().intersect( m_drawRect ) );
+ if( m_pPixmap )
+ {
+ if( m_pPixmap->mask() )
+ {
+ if( ! m_pDoubleBuffer )
+ {
+ m_pDoubleBuffer = new KPixmap( m_pPixmap->size() );
+ QPainter p( m_pDoubleBuffer );
+ p.drawTiledPixmap( m_pDoubleBuffer->rect(), checkboardPixmap() );
+ p.end();
+ bitBlt( m_pDoubleBuffer, QPoint( 0, 0 ), m_pPixmap, m_pPixmap->rect() );
+ }
+ painter.drawPixmap( 0, 0, *m_pDoubleBuffer );
+ }
+ else
+ painter.drawPixmap( 0, 0, *m_pPixmap );
+ }
+ if( m_selected )
+ drawSelect( painter );
+}
+
+void KImageHolder::timerEvent( QTimerEvent * ev )
+{
+ if( ev->timerId() != m_scrollTimerId )
+ return;
+
+ emit wannaScroll( m_xOffset, m_yOffset );
+}
+
+void KImageHolder::setPixmap( const KPixmap & pixmap )
+{
+ kdDebug( 4620 ) << k_funcinfo << " " << pixmap.width() << 'x' << pixmap.height() << endl;
+ delete m_pPixmap;
+ delete m_pDoubleBuffer;
+ m_pDoubleBuffer = 0;
+ m_pPixmap = new KPixmap( pixmap );
+ m_drawRect = m_pPixmap->rect();
+ show();
+}
+
+const KPixmap & KImageHolder::checkboardPixmap()
+{
+ if( ! m_pCheckboardPixmap )
+ {
+ const char * xpm[] = {
+ "32 32 2 1",
+ " c #666666",
+ "X c #999999",
+ " XXXXXXXXXXXXXXXX",
+ " XXXXXXXXXXXXXXXX",
+ " XXXXXXXXXXXXXXXX",
+ " XXXXXXXXXXXXXXXX",
+ " XXXXXXXXXXXXXXXX",
+ " XXXXXXXXXXXXXXXX",
+ " XXXXXXXXXXXXXXXX",
+ " XXXXXXXXXXXXXXXX",
+ " XXXXXXXXXXXXXXXX",
+ " XXXXXXXXXXXXXXXX",
+ " XXXXXXXXXXXXXXXX",
+ " XXXXXXXXXXXXXXXX",
+ " XXXXXXXXXXXXXXXX",
+ " XXXXXXXXXXXXXXXX",
+ " XXXXXXXXXXXXXXXX",
+ " XXXXXXXXXXXXXXXX",
+ "XXXXXXXXXXXXXXXX ",
+ "XXXXXXXXXXXXXXXX ",
+ "XXXXXXXXXXXXXXXX ",
+ "XXXXXXXXXXXXXXXX ",
+ "XXXXXXXXXXXXXXXX ",
+ "XXXXXXXXXXXXXXXX ",
+ "XXXXXXXXXXXXXXXX ",
+ "XXXXXXXXXXXXXXXX ",
+ "XXXXXXXXXXXXXXXX ",
+ "XXXXXXXXXXXXXXXX ",
+ "XXXXXXXXXXXXXXXX ",
+ "XXXXXXXXXXXXXXXX ",
+ "XXXXXXXXXXXXXXXX ",
+ "XXXXXXXXXXXXXXXX ",
+ "XXXXXXXXXXXXXXXX ",
+ "XXXXXXXXXXXXXXXX ",
+ };
+ m_pCheckboardPixmap = new KPixmap( xpm );
+ }
+ return *m_pCheckboardPixmap;
+}
+
+#include "kimageholder.moc"
+
+// vim:sw=4:ts=4
diff --git a/kview/kviewcanvas/kimageholder.h b/kview/kviewcanvas/kimageholder.h
new file mode 100644
index 00000000..780ce372
--- /dev/null
+++ b/kview/kviewcanvas/kimageholder.h
@@ -0,0 +1,105 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001-2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+
+*/
+// $Id$
+
+#ifndef _KIMAGEHOLDER_H
+#define _KIMAGEHOLDER_H
+
+#include <qwidget.h>
+class QRect;
+class QPainter;
+class QPen;
+class QPixmap;
+class KPixmap;
+class QPoint;
+
+/**
+ * @short Image widget
+ * @version $Id$
+ */
+class KImageHolder : public QWidget
+{
+ Q_OBJECT
+ public:
+ KImageHolder( QWidget *parent = 0, const char * name = 0 );
+
+ virtual ~KImageHolder();
+
+ void clearSelection();
+
+ void setImage( const KPixmap & );
+ void setImage( const QImage & );
+ void setImage( const QMovie & );
+
+ /**
+ * clears the ImageHolder
+ */
+ void clear();
+
+ /**
+ * the selected rect
+ */
+ QRect selection() const;
+
+ QSize sizeHint() const;
+
+ void setDrawRect( const QRect & rect ) { m_drawRect = rect; }
+ const QRect & drawRect() const { return m_drawRect; }
+
+ signals:
+ void contextPress( const QPoint& );
+ void selected( const QRect & );
+ void wannaScroll( int dx, int dy );
+ void cursorPos( const QPoint & );
+
+ protected:
+ void mousePressEvent( QMouseEvent * );
+ void mouseMoveEvent( QMouseEvent * );
+ void mouseReleaseEvent( QMouseEvent * );
+ void paintEvent( QPaintEvent * );
+ virtual void timerEvent( QTimerEvent * );
+
+ private:
+ void drawSelect( QPainter & );
+ void eraseSelect();
+
+ void setPixmap( const KPixmap & );
+
+ private:
+ QRect m_selection;
+ QRect m_drawRect;
+ QPoint m_scrollpos;
+ QPoint m_selectionStartPoint;
+
+ const KPixmap & checkboardPixmap();
+
+ bool m_selected;
+ bool m_bSelecting;
+ int m_scrollTimerId;
+ int m_xOffset, m_yOffset;
+
+ QPen *m_pen;
+
+ KPixmap * m_pPixmap;
+ KPixmap * m_pDoubleBuffer;
+ KPixmap * m_pCheckboardPixmap;
+};
+
+// vim:sw=4:ts=4
+
+#endif // _KIMAGEHOLDER_H
diff --git a/kview/kviewcanvas/kviewcanvas.desktop b/kview/kviewcanvas/kviewcanvas.desktop
new file mode 100644
index 00000000..ecc7ddfd
--- /dev/null
+++ b/kview/kviewcanvas/kviewcanvas.desktop
@@ -0,0 +1,63 @@
+[Desktop Entry]
+Type=Service
+Name=KView Image Viewer Widget
+Name[af]=K-bekyk Beeld Aansig Gui-element
+Name[ar]=كائن عارض الصور KView
+Name[br]=Widget gweler skeudennoù KView
+Name[bs]=KView predglednik slika - grafički element
+Name[ca]=Estri visualitzador d'imatges KView
+Name[cs]=Komponenta prohlížeče obrázků KView
+Name[cy]=Celfigyn Gwelydd Delweddau KGweld
+Name[da]=KView-billedviserkontrol
+Name[de]=KView Bildanzeige-Bildschirmausschnitt
+Name[el]=Γραφικό συστατικό προβολέα εικόνων του KView
+Name[eo]=Bildrigardilo fenestro
+Name[es]=Widget visor de imágenes de KView
+Name[et]=KView pildifailide näitaja element
+Name[eu]=KView irudi ikustailu botoia
+Name[fa]=عنصر مشاهده‌گر تصویر KView
+Name[fi]=KView-kuviennäyttökomponentti
+Name[fr]=Widget visualisateur d'images KView
+Name[gl]=Complemento do visor de Imaxes KView
+Name[he]=פריט מציג תמונות ל־KView
+Name[hi]=के-व्यू छवि प्रदर्शक विजेट
+Name[hr]=KView widget za pregled slika
+Name[hu]=KView képnézegető grafikus elem
+Name[is]=KView myndbirtigræja
+Name[it]=Widget visore immagini KView
+Name[ja]=KView 画像ビューアウィジェット
+Name[kk]=KView кескінді көрсететін бөлшегі
+Name[km]=ធាតុ​ក្រាហ្វិក​កម្មវិធី​មើល​រូបភាព KView
+Name[lt]=KView paveikslėlių žiūriklio valdiklis
+Name[ms]=Widget Pemapar Imej KView
+Name[nb]=KView bilde-fremviserelement
+Name[nds]=KView-Bildkiekrahmen
+Name[ne]=केडीई दृश्य छवि दर्शक विजेट
+Name[nl]=KView afbeeldingwidget
+Name[nn]=KView biletvisarelement
+Name[nso]=KView Widget ya Molebeledi wa Ponagalo
+Name[pl]=Okienko przeglądarki obrazków KView
+Name[pt]=Elemento de Visualização de Imagens do KView
+Name[pt_BR]=Componente de Visualização de Imagens do KVisualização
+Name[ro]=Widget vizualizare imagini KView
+Name[ru]=Виджет с просмотром изображения KView
+Name[se]=KView govvačájehanáhta
+Name[sk]=Prvok prehliadača obrázkov KView
+Name[sl]=Gradnik pregledovalnika slik KView
+Name[sr]=KView, контрола за приказ слика
+Name[sr@Latn]=KView, kontrola za prikaz slika
+Name[sv]=Kview bildvisande komponent
+Name[ta]=கேகாட்சி பிம்பக் காட்சி சாளரம்
+Name[tg]=Виджет бо намоиши тасвироти KView
+Name[tr]=KView Resim Görüntüleme Parçacığı
+Name[uk]=Віджет переглядача зображень KView
+Name[ven]=Tshishumiswa tsha vhuthogwa tsha muvhoni wa tshifanyiso tsha mbonalelo ya K
+Name[wa]=Ahesse håyneu d' imådjes KView
+Name[xh]=Widget Yombonisi Womfanekiso we KView
+Name[zh_CN]=KView 图像查看器部件
+Name[zh_HK]=KView 圖像檢視器器件
+Name[zh_TW]=KView 影像檢視器界面工具
+Name[zu]=I-widget Yombukisi Wesithombe se-KView
+X-KDE-Library=libkviewcanvas
+InitialPreference=2
+ServiceTypes=KImageViewer/Canvas
diff --git a/kview/kviewcanvas/test/Makefile.am b/kview/kviewcanvas/test/Makefile.am
new file mode 100644
index 00000000..1fc3e92c
--- /dev/null
+++ b/kview/kviewcanvas/test/Makefile.am
@@ -0,0 +1,9 @@
+INCLUDES = -I$(top_srcdir)/kview $(all_includes)
+
+METASOURCES = AUTO
+
+check_PROGRAMS = test
+
+test_SOURCES = main.cpp test.cpp
+test_LDFLAGS = $(KDE_RPATH) $(all_libraries)
+test_LDADD = $(LIB_KPARTS) $(top_builddir)/kview/kimageviewer/libkimageviewer.la
diff --git a/kview/kviewcanvas/test/main.cpp b/kview/kviewcanvas/test/main.cpp
new file mode 100644
index 00000000..360fdefd
--- /dev/null
+++ b/kview/kviewcanvas/test/main.cpp
@@ -0,0 +1,51 @@
+#include "test.h"
+#include <kapplication.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+
+static const char description[] =
+ I18N_NOOP("A KDE KPart Application");
+
+static const char version[] = "v0.1";
+
+static KCmdLineOptions options[] =
+{
+ { "+[URL]", I18N_NOOP( "Image to open" ), 0 },
+ KCmdLineLastOption
+};
+
+int main(int argc, char **argv)
+{
+ KAboutData about("kimageviewertest", I18N_NOOP("KImageViewerTest"), version, description, KAboutData::License_GPL, "(C) 2001 Matthias Kretz", 0, 0, "kretz@kde.org");
+ about.addAuthor( "Matthias Kretz", 0, "kretz@kde.org" );
+ KCmdLineArgs::init(argc, argv, &about);
+ KCmdLineArgs::addCmdLineOptions( options );
+ KApplication app;
+
+ if (app.isRestored())
+ RESTORE(KImageViewerTest)
+ else
+ {
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ if ( args->count() == 0 )
+ {
+ KImageViewerTest *widget = new KImageViewerTest;
+ widget->show();
+ }
+ else
+ {
+ int i = 0;
+ for (; i < args->count(); i++ )
+ {
+ KImageViewerTest *widget = new KImageViewerTest;
+ widget->show();
+ widget->load( args->url( i ) );
+ }
+ }
+ args->clear();
+ }
+
+ return app.exec();
+}
diff --git a/kview/kviewcanvas/test/test.cpp b/kview/kviewcanvas/test/test.cpp
new file mode 100644
index 00000000..8422f944
--- /dev/null
+++ b/kview/kviewcanvas/test/test.cpp
@@ -0,0 +1,46 @@
+/*
+ * kimageviewertest.cpp
+ *
+ * Copyright (c) 2001 Matthias Kretz <kretz@kde.org>
+ */
+#include "test.h"
+#include <kimageviewer/canvas.h>
+
+#include <kurl.h>
+#include <klibloader.h>
+#include <kmessagebox.h>
+#include <kparts/componentfactory.h>
+
+#include <qimage.h>
+
+KImageViewerTest::KImageViewerTest()
+ : KParts::MainWindow( 0L, "KImageViewerTest" )
+{
+ QWidget * widget = KParts::ComponentFactory::createInstanceFromQuery<QWidget>(
+ "KImageViewer/Canvas", QString::null, this );
+ if( widget )
+ {
+ m_part = dynamic_cast<KImageViewer::Canvas *>( widget );
+ setCentralWidget( widget );
+ }
+ else
+ {
+ KMessageBox::error(this, "Could not find our Part!");
+ kapp->quit();
+ }
+}
+
+KImageViewerTest::~KImageViewerTest()
+{
+}
+
+void KImageViewerTest::load(const KURL& url)
+{
+ QImage image( url.fileName() );
+ if( m_part )
+ m_part->setImage( image );
+ else
+ KMessageBox::error(this, "can't load the file");
+}
+
+#include "test.moc"
diff --git a/kview/kviewcanvas/test/test.h b/kview/kviewcanvas/test/test.h
new file mode 100644
index 00000000..b6a85188
--- /dev/null
+++ b/kview/kviewcanvas/test/test.h
@@ -0,0 +1,25 @@
+#ifndef KIMAGEVIEWERTEST_H
+#define KIMAGEVIEWERTEST_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kapplication.h>
+#include <kparts/mainwindow.h>
+
+namespace KImageViewer { class Canvas; };
+
+class KImageViewerTest : public KParts::MainWindow
+{
+ Q_OBJECT
+public:
+ KImageViewerTest();
+ virtual ~KImageViewerTest();
+ void load(const KURL& url);
+
+private:
+ KImageViewer::Canvas *m_part;
+};
+
+#endif // KIMAGEVIEWERTEST_H
diff --git a/kview/kviewui.rc b/kview/kviewui.rc
new file mode 100644
index 00000000..a444bcc4
--- /dev/null
+++ b/kview/kviewui.rc
@@ -0,0 +1,50 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="KView" version="12">
+ <MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <DefineGroup name="open_merge_group" append="open_merge"/>
+ <DefineGroup name="save_merge_group" append="save_merge"/>
+ <Action name="print" append="print_merge"/>
+ <!--<Merge /> This creates an extra separator in the file menu-->
+ </Menu>
+ <Menu name="edit"><text>&amp;Edit</text>
+ <Action name="crop" />
+ <Action name="reload" />
+ <Separator />
+ <Action name="del" />
+ <Merge />
+ </Menu>
+ <Merge />
+ <Menu name="settings"><text>&amp;Settings</text>
+ <DefineGroup name="show_merge_group" append="show_merge" />
+ <Separator append="show_merge"/>
+ </Menu>
+ <Menu name="help"><text>&amp;Help</text>
+ <DefineGroup name="about_merge_group" append="about_merge"/>
+ </Menu>
+ </MenuBar>
+ <ToolBar name="mainToolBar" noMerge="1"><text>Main Toolbar</text>
+ <Action name="file_open"/>
+ <Action name="file_save"/>
+ <Action name="print"/>
+ <Action name="file_print_preview"/>
+ <Separator/>
+ <Action name="edit_undo"/>
+ <Action name="edit_redo"/>
+ <Action name="edit_cut"/>
+ <Action name="edit_copy"/>
+ <Action name="edit_paste"/>
+ <Separator/>
+ <Action name="reload"/>
+ </ToolBar>
+ <Menu name="popupmenu">
+ <Action name="file_open"/>
+ <DefineGroup name="file_group"/>
+ <Separator/>
+ <Action name="options_show_menubar"/>
+ <Action name="fullscreen"/>
+ <Separator/>
+ <Action name="del"/>
+ <Merge/>
+ </Menu>
+</kpartgui>
diff --git a/kview/kviewviewer/ChangeLog b/kview/kviewviewer/ChangeLog
new file mode 100644
index 00000000..e76a70cd
--- /dev/null
+++ b/kview/kviewviewer/ChangeLog
@@ -0,0 +1,68 @@
+2003-10-06 Matthias Kretz <kretz@kde.org>
+
+ * config/kviewviewerpluginsconfig.cpp:
+ Don't show an empty config page in the pluginselector (there are no
+ KView plugins with config options, yet).
+
+2003-08-22 Matthias Kretz <kretz@kde.org>
+
+ * confmodules.*
+ moved to kviewcanvas/config
+ * generalconfigwidget.ui
+ moved to kviewcanvas/config
+
+2003-08-19 Matthias Kretz <kretz@kde.org>
+
+ * kviewvieweriface.h:
+ Everything is gone, let's see if this interface will stay
+ around...
+ * Makefile.am:
+ Added own messages target
+ * kviewviewer.{h,cpp}:
+ Remove image cache again. It's making more problems than it's
+ worth. The speedup is minimal. A real speedup would probably be
+ to preload images and/or cache the QPixmaps.
+ Problems I had: At some point no new image would be shown
+ anymore. Also the memory usage was too high and the kernel
+ does disk caching anyway, so the QImage caching is just a
+ minor optimization.
+
+2003-04-03 Matthias Kretz <kretz@kde.org>
+
+ * kviewviewer.cpp:
+ s/QUriDrag/KURLDrag/
+
+2003-03-11 Matthias Kretz <kretz@kde.org>
+
+ * kviewviewer.cpp:
+ uhm, fix a biiiig memory leak: the cache wasn't deleted on
+ part destruction
+
+2003-03-06 Matthias Kretz <kretz@kde.org>
+
+ * kviewviewer.desktop:
+ Changed MimeType field to support pbm, pnm, ppm and pgm. And
+ added the image/jp2 type.
+ Name change: Image Viewer Part -> KView Image Viewer. Somehow
+ the part needs to be identified with KView.
+
+2003-03-04 Matthias Kretz <kretz@kde.org>
+
+ * kviewvieweriface.h:
+ New interface header. This is probably going to be KView
+ specific stuff or become a DCOP interface (or both) have to
+ look into that some more...
+ It has only one method so far: setCacheSize( uint ) for
+ setting the maximum size of the QImage cache of the viewer.
+ * kviewviewer.cpp:
+ Cache QImages in a QCache.
+ This introduces a few problems: If a newer version is
+ available on file the cache will be used because the
+ modification time isn't checked.
+ Also the watching of files doesn't work anymore if the image
+ is loaded from the cache.
+ * kviewviewer.{cpp,h,rc}, kviewviewer_ro.rc:
+ added "rotate clockwise" and changed icon of CCW (patch by
+ Adriaan de Groot)
+
+# vim: sw=4 ts=4 tw=80 noet
diff --git a/kview/kviewviewer/Makefile.am b/kview/kviewviewer/Makefile.am
new file mode 100644
index 00000000..0aa490ec
--- /dev/null
+++ b/kview/kviewviewer/Makefile.am
@@ -0,0 +1,21 @@
+SUBDIRS = test config
+
+kde_module_LTLIBRARIES = libkviewviewer.la
+INCLUDES = -I$(top_srcdir)/kview $(all_includes)
+
+noinst_HEADERS = kviewkonqextension.h kviewviewer.h
+
+libkviewviewer_la_SOURCES = printimagesettings.ui imagesettings.cpp kviewkonqextension.cpp kviewviewer.cpp
+libkviewviewer_la_LDFLAGS = $(all_libraries) -avoid-version -module -no-undefined
+libkviewviewer_la_LIBADD = $(LIB_KDEPRINT) $(LIB_KUTILS) \
+ $(top_builddir)/kview/kimageviewer/libkimageviewer.la
+
+METASOURCES = AUTO
+
+kde_services_DATA = kviewviewer.desktop
+
+partdir = $(kde_datadir)/kviewviewer
+part_DATA = kviewviewer.rc kviewviewer_ro.rc kviewpopup.rc
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp *.h -o $(podir)/kviewviewer.pot
diff --git a/kview/kviewviewer/config/Makefile.am b/kview/kviewviewer/config/Makefile.am
new file mode 100644
index 00000000..fe65e613
--- /dev/null
+++ b/kview/kviewviewer/config/Makefile.am
@@ -0,0 +1,17 @@
+INCLUDES = $(all_includes)
+
+METASOURCES = AUTO
+
+kde_module_LTLIBRARIES = kcm_kviewviewerpluginsconfig.la
+
+noinst_HEADERS = kviewviewerpluginsconfig.h
+
+kcm_kviewviewerpluginsconfig_la_SOURCES = kviewviewerpluginsconfig.cpp
+kcm_kviewviewerpluginsconfig_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kcm_kviewviewerpluginsconfig_la_LIBADD = $(LIB_KUTILS)
+
+kcm_kviewviewerpluginsconfig_DATA = kviewviewerpluginsconfig.desktop
+kcm_kviewviewerpluginsconfigdir = $(kde_servicesdir)/kconfiguredialog
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp *.h -o $(podir)/kcm_kviewviewerpluginsconfig.pot
diff --git a/kview/kviewviewer/config/kviewviewerpluginsconfig.cpp b/kview/kviewviewer/config/kviewviewerpluginsconfig.cpp
new file mode 100644
index 00000000..04b9e982
--- /dev/null
+++ b/kview/kviewviewer/config/kviewviewerpluginsconfig.cpp
@@ -0,0 +1,48 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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 "kviewviewerpluginsconfig.h"
+
+#include <kpluginselector.h>
+#include <kgenericfactory.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <ksimpleconfig.h>
+#include <kplugininfo.h>
+
+#include <qstring.h>
+
+typedef KGenericFactory<KViewViewerPluginsConfig, QWidget> KViewViewerPluginsConfigFactory;
+K_EXPORT_COMPONENT_FACTORY( kcm_kviewviewerpluginsconfig, KViewViewerPluginsConfigFactory( "kcm_kviewviewerpluginsconfig" ) )
+
+KViewViewerPluginsConfig::KViewViewerPluginsConfig( QWidget * parent, const char *, const QStringList & args )
+ : KSettings::PluginPage( KViewViewerPluginsConfigFactory::instance(), parent, args )
+{
+ m_config = new KSimpleConfig( "kviewviewerrc" );
+ pluginSelector()->addPlugins( QString::fromAscii( "kviewviewer" ), i18n( "Viewer" ), QString::null, m_config );
+ pluginSelector()->setShowEmptyConfigPage( false );
+}
+
+KViewViewerPluginsConfig::~KViewViewerPluginsConfig()
+{
+ delete m_config;
+}
+
+// vim: sw=4 ts=4 noet
+
+#include "kviewviewerpluginsconfig.moc"
diff --git a/kview/kviewviewer/config/kviewviewerpluginsconfig.desktop b/kview/kviewviewer/config/kviewviewerpluginsconfig.desktop
new file mode 100644
index 00000000..d2faedfd
--- /dev/null
+++ b/kview/kviewviewer/config/kviewviewerpluginsconfig.desktop
@@ -0,0 +1,118 @@
+[Desktop Entry]
+Icon=plugin
+Type=Service
+ServiceTypes=KCModule
+
+X-KDE-ModuleType=Library
+X-KDE-Library=kviewviewerpluginsconfig
+X-KDE-FactoryName=KViewViewerPluginsConfigFactory
+X-KDE-ParentApp=kview
+X-KDE-ParentComponents=kviewviewer
+X-KDE-Weight=2
+X-KDE-CfgDlgHierarchy=Viewer
+
+Name=Plugins
+Name[ar]=البرامج المساعدة
+Name[bg]=Приставки
+Name[br]=Lugantoù
+Name[bs]=Dodaci
+Name[ca]=Connectors
+Name[cs]=Moduly
+Name[cy]=Ategion
+Name[da]=Plugin
+Name[de]=Module
+Name[el]=Πρόσθετα
+Name[eo]=Kromaĵoj
+Name[es]=Extensiones
+Name[et]=Pluginad
+Name[eu]=Pluginak
+Name[fa]=وصله‌ها
+Name[fi]=Liitännäiset
+Name[fr]=Modules externes
+Name[ga]=Breiseáin
+Name[he]=תוספים
+Name[hi]=प्लगइन्स
+Name[hr]=Umetci
+Name[hu]=Bővítőmodulok
+Name[is]=Íforrit
+Name[it]=Plugin
+Name[ja]=プラグイン
+Name[kk]=Плагин модулі
+Name[km]=កម្មវិធី​ជំនួយ
+Name[lt]=Priedai
+Name[ms]=Plugin
+Name[nb]=Programtillegg
+Name[nds]=Modulen
+Name[ne]=प्लगइन
+Name[nn]=Programtillegg
+Name[pa]=ਪਲੱਗਿੰਨ
+Name[pl]=Wtyczki
+Name[pt]='Plugins'
+Name[ro]=Module
+Name[ru]=Модули
+Name[rw]=Amacomeka
+Name[se]=Lassemoduvllat
+Name[sk]=Moduly
+Name[sl]=Vstavki
+Name[sr]=Прикључци
+Name[sr@Latn]=Priključci
+Name[sv]=Insticksprogram
+Name[ta]=சொருகுப்பொருள்
+Name[tg]=Модулҳо
+Name[tr]=Eklentiler
+Name[uk]=Втулки
+Name[uz]=Plaginlar
+Name[uz@cyrillic]=Плагинлар
+Name[wa]=Tchôke-divins
+Name[zh_CN]=插件
+Name[zh_HK]=插件
+Name[zh_TW]=外掛程式
+Comment=Choose and Configure Your Plugins
+Comment[bg]=Избор и настройване на приставки
+Comment[br]=Dibabit ha kefluniut ho lugentoù
+Comment[bs]=Izaberite i podesite vaše dodatke
+Comment[ca]=Escolliu i configureu els connectors
+Comment[cs]=Zvolte a nastavte si moduly
+Comment[da]=Vælg og indstil dine plugin
+Comment[de]=Auswahl und Einrichtung der Module
+Comment[el]=Επιλέξτε και ρυθμίστε τα πρόσθετα σας
+Comment[eo]=Elektu kaj agordu viajn kromprogramojn
+Comment[es]=Seleccione y configure sus extensiones
+Comment[et]=Pluginate valimine ja seadistamine
+Comment[eu]=Aukeratu eta konfigurau zure pluginak
+Comment[fa]=وصله‌های خود را انتخاب و پیکربندی کنید
+Comment[fi]=Valitse ja muokkaa liitännäisten asetuksia
+Comment[fr]=Choisissez et configurez vos modules externes
+Comment[gl]=Elexir e Configurar as súas Extensións
+Comment[he]=בחר והגדר את התוספים שלך
+Comment[hu]=Bővítőmodulok kiválasztása, beállítása
+Comment[is]=Velja og stilla íforrit
+Comment[it]=Scegli e configura i tuoi plugin
+Comment[ja]=プラグインを選択して設定します
+Comment[kk]=Плагин модулін таңдап алып баптау
+Comment[km]=ជ្រើស និង​កំណត់​រចនាសម្ព័ន្ធ​កម្មវិធី​ជំនួយ​របស់​អ្នក
+Comment[lt]=Pasirinkite ir konfigūruokite priedus
+Comment[ms]=Pilih dan Konfigur Plugin Anda
+Comment[nb]=Velg og sett opp programtilleggene
+Comment[nds]=Dien Modulen utsöken un instellen
+Comment[ne]=तपाईँको प्लगइन रोज्नुहोस् र कन्फिगर गर्नुहोस्
+Comment[nl]=Kies uw plugins en stel ze in
+Comment[nn]=Vel og set opp programtillegga
+Comment[pl]=Wybór i konfiguracja wtyczek
+Comment[pt]=Escolha e Configure os 'Plugins'
+Comment[pt_BR]=Escolha e Configure os Seus Plugins
+Comment[ro]=Alegeţi şi configuraţi modulele dumneavoastră
+Comment[ru]=Выберите и настройте модули
+Comment[sk]=Vyberte a nastavte si moduly
+Comment[sl]=Izberite in nastavite vstavke
+Comment[sr]=Изаберите и подесите ваше прикључке
+Comment[sr@Latn]=Izaberite i podesite vaše priključke
+Comment[sv]=Välj och anpassa insticksprogram
+Comment[ta]=சொருகுப்பொருள்களைத் தேர்ந்தெடுத்து வடிவமைக்கவும்
+Comment[tr]=Eklentilerinizi Seçin ve Yapılandırın:
+Comment[uk]=Виберіть та налаштуйте ваші втулки
+Comment[uz]=Plaginlarni tanlash va moslash
+Comment[uz@cyrillic]=Плагинларни танлаш ва мослаш
+Comment[zh_CN]=选择并配置您的插件
+Comment[zh_HK]=選擇及設定你的插件
+Comment[zh_TW]=選擇並設定您的外掛程式
diff --git a/kview/kviewviewer/config/kviewviewerpluginsconfig.h b/kview/kviewviewer/config/kviewviewerpluginsconfig.h
new file mode 100644
index 00000000..4f2b30ab
--- /dev/null
+++ b/kview/kviewviewer/config/kviewviewerpluginsconfig.h
@@ -0,0 +1,38 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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 KVIEWVIEWERPLUGINSCONFIG_H
+#define KVIEWVIEWERPLUGINSCONFIG_H
+
+#include <ksettings/pluginpage.h>
+
+class KConfig;
+
+class KViewViewerPluginsConfig : public KSettings::PluginPage
+{
+ Q_OBJECT
+ public:
+ KViewViewerPluginsConfig( QWidget * parent, const char * name = 0, const QStringList & args = QStringList() );
+ ~KViewViewerPluginsConfig();
+ private:
+ KConfig * m_config;
+};
+
+// vim: sw=4 ts=4 noet
+
+#endif // KVIEWVIEWERPLUGINSCONFIG_H
diff --git a/kview/kviewviewer/imagesettings.cpp b/kview/kviewviewer/imagesettings.cpp
new file mode 100644
index 00000000..4f483db7
--- /dev/null
+++ b/kview/kviewviewer/imagesettings.cpp
@@ -0,0 +1,73 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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 "imagesettings.h"
+
+#include <qcheckbox.h>
+#include <qlayout.h>
+
+#include <klocale.h>
+#include <kdialog.h>
+
+ImageSettings::ImageSettings( QWidget * parent, const char * name )
+ : KPrintDialogPage( parent, name )
+ , m_pFitImage( 0 )
+{
+ setTitle( i18n( "Image Settings" ) );
+
+ QBoxLayout * layout = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
+ m_pFitImage = new QCheckBox( i18n( "Fit image to page size" ), this );
+ m_pFitImage->setChecked( true );
+ layout->addWidget( m_pFitImage );
+ m_pCenter = new QCheckBox( i18n( "Center image on page" ), this );
+ m_pCenter->setChecked( true );
+ layout->addWidget( m_pCenter );
+ layout->insertStretch( -1, 0 );
+}
+
+ImageSettings::~ImageSettings()
+{
+}
+
+void ImageSettings::setOptions( const QMap<QString, QString> & opts )
+{
+ m_pFitImage->setChecked( opts[ "app-kviewviewer-fitimage" ] == "1" );
+ m_pCenter->setChecked( opts[ "app-kviewviewer-center" ] == "1" );
+}
+
+void ImageSettings::getOptions( QMap<QString, QString> & opts, bool include_def )
+{
+ if( m_pFitImage->isChecked() )
+ opts[ "app-kviewviewer-fitimage" ] = "1";
+ else if( include_def )
+ opts[ "app-kviewviewer-fitimage" ] = "0";
+
+ if( m_pCenter->isChecked() )
+ opts[ "app-kviewviewer-center" ] = "1";
+ else if( include_def )
+ opts[ "app-kviewviewer-center" ] = "0";
+}
+
+bool ImageSettings::isValid( QString & /*msg*/ )
+{
+ return true;
+}
+
+#include "imagesettings.moc"
+
+// vim:sw=4:ts=4
diff --git a/kview/kviewviewer/imagesettings.h b/kview/kviewviewer/imagesettings.h
new file mode 100644
index 00000000..5d7bf88e
--- /dev/null
+++ b/kview/kviewviewer/imagesettings.h
@@ -0,0 +1,45 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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 IMAGESETTINGS_H
+#define IMAGESETTINGS_H
+
+#include <kdeprint/kprintdialogpage.h>
+
+class QCheckBox;
+
+class ImageSettings : public KPrintDialogPage
+{
+ Q_OBJECT
+ public:
+ ImageSettings( QWidget * parent = 0, const char * name = 0 );
+ ~ImageSettings();
+
+ void setOptions( const QMap<QString, QString> & opts );
+ void getOptions( QMap<QString, QString> & opts, bool include_def = false );
+ bool isValid( QString & msg );
+
+ private:
+ QCheckBox * m_pFitImage;
+ QCheckBox * m_pCenter;
+};
+
+// vim:sw=4:ts=4
+
+#endif // IMAGESETTINGS_H
+
diff --git a/kview/kviewviewer/kviewkonqextension.cpp b/kview/kviewviewer/kviewkonqextension.cpp
new file mode 100644
index 00000000..40876b7c
--- /dev/null
+++ b/kview/kviewviewer/kviewkonqextension.cpp
@@ -0,0 +1,105 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 Simon Hausmann <hausmann@kde.org>
+ 2001 Matthias Kretz <kretz@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 "kviewkonqextension.h"
+#include "kviewviewer.h"
+#include "kimageviewer/canvas.h"
+#include "imagesettings.h"
+
+#include <qpainter.h>
+#include <qimage.h>
+#include <qpaintdevicemetrics.h>
+
+#include <kprinter.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+
+KViewKonqExtension::KViewKonqExtension( KImageViewer::Canvas * canvas,
+ KViewViewer *parent, const char *name )
+ : KParts::BrowserExtension( parent, name ),
+ m_pViewer( parent ),
+ m_pCanvas( canvas )
+{
+ KGlobal::locale()->insertCatalogue("kview");
+}
+
+void KViewKonqExtension::setXYOffset( int x, int y )
+{
+ m_pCanvas->setXYOffset( x, y );
+}
+
+int KViewKonqExtension::xOffset()
+{
+ return m_pCanvas->xOffset();
+}
+
+int KViewKonqExtension::yOffset()
+{
+ return m_pCanvas->yOffset();
+}
+
+void KViewKonqExtension::print()
+{
+ if( ! m_pCanvas->image() )
+ {
+ kdError( 4610 ) << "No image to print" << endl;
+ return;
+ }
+
+ KPrinter printer;//( true, QPrinter::ScreenResolution );
+ printer.addDialogPage( new ImageSettings );
+ printer.setDocName( "KView: " + m_pViewer->url().fileName( false ) );
+
+ if ( !printer.setup( ((KViewViewer *)parent())->widget(), i18n("Print %1").arg(m_pViewer->url().fileName( false )) ) )
+ return;
+
+ QPainter painter;
+ painter.begin( &printer );
+
+ QPaintDeviceMetrics metrics( painter.device() );
+ kdDebug( 4610 ) << "metrics: " << metrics.width() << "x" << metrics.height() << endl;
+ QPoint pos( 0, 0 );
+
+ QImage imagetoprint;
+ if( printer.option( "app-kviewviewer-fitimage" ) == "1" )
+ imagetoprint = m_pCanvas->image()->smoothScale( metrics.width(), metrics.height(), QImage::ScaleMin );
+ else
+ imagetoprint = *m_pCanvas->image();
+
+ if( printer.option( "app-kviewviewer-center" ) == "1" )
+ {
+ pos.setX( ( metrics.width() - imagetoprint.width() ) / 2 );
+ pos.setY( ( metrics.height() - imagetoprint.height() ) / 2 );
+ }
+
+ painter.drawImage( pos, imagetoprint );
+ painter.end();
+}
+
+void KViewKonqExtension::del()
+{
+ m_pViewer->slotDel();
+}
+
+// vim:sw=4:ts=4
+
+#include "kviewkonqextension.moc"
+
diff --git a/kview/kviewviewer/kviewkonqextension.h b/kview/kviewviewer/kviewkonqextension.h
new file mode 100644
index 00000000..b7692f31
--- /dev/null
+++ b/kview/kviewviewer/kviewkonqextension.h
@@ -0,0 +1,52 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 Simon Hausmann <hausmann@kde.org>
+ 2001 Matthias Kretz <kretz@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 __kviewkonqextension_h__
+#define __kviewkonqextension_h__
+
+#include <kparts/browserextension.h>
+
+namespace KImageViewer { class Canvas; }
+class KViewViewer;
+
+class KViewKonqExtension: public KParts::BrowserExtension
+{
+ friend class KViewViewer; // it can emit our signals
+ Q_OBJECT
+ public:
+ KViewKonqExtension( KImageViewer::Canvas *, KViewViewer *parent, const char *name = 0 );
+ virtual ~KViewKonqExtension() {}
+
+ virtual void setXYOffset( int x, int y );
+ virtual int xOffset();
+ virtual int yOffset();
+
+ public slots:
+ // Automatically detected by konqueror and kview
+ void print();
+ void del();
+
+ private:
+ KViewViewer * m_pViewer;
+ KImageViewer::Canvas * m_pCanvas;
+};
+
+// vim:sw=4:ts=4
+
+#endif
diff --git a/kview/kviewviewer/kviewpopup.rc b/kview/kviewviewer/kviewpopup.rc
new file mode 100644
index 00000000..ad4ece69
--- /dev/null
+++ b/kview/kviewviewer/kviewpopup.rc
@@ -0,0 +1,7 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="kview_popup" version="1">
+ <Menu name="popupmenu">
+ <Separator />
+ <Action name="saveimageas" />
+ </Menu>
+</kpartgui>
diff --git a/kview/kviewviewer/kviewviewer.cpp b/kview/kviewviewer/kviewviewer.cpp
new file mode 100644
index 00000000..bab325ec
--- /dev/null
+++ b/kview/kviewviewer/kviewviewer.cpp
@@ -0,0 +1,883 @@
+/* This file is part of the KDE project
+
+ Copyright (C) 1999 Simon Hausmann <hausmann@kde.org>
+ 2001-2003 Matthias Kretz <kretz@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 "kviewviewer.h"
+#include "kimageviewer/canvas.h"
+#include "version.h"
+
+#include <ksettings/dispatcher.h>
+
+#include <unistd.h>
+#include <assert.h>
+
+#include <qbuffer.h>
+#include <qlayout.h>
+#include <qvbox.h>
+#include <qlabel.h>
+#include <qregexp.h>
+
+#include <kpushbutton.h>
+#include <kpassivepopup.h>
+#include <kdebug.h>
+#include <kio/job.h>
+#include <kxmlguifactory.h>
+#include <kfiledialog.h>
+#include <kparts/genericfactory.h>
+#include <kparts/componentfactory.h>
+#include <kparts/plugin.h>
+#include <kmessagebox.h>
+#include <ktempfile.h>
+#include <kapplication.h>
+#include <kimageio.h>
+#include <kstdaccel.h>
+#include <kdirwatch.h>
+#include <kurldrag.h>
+#include <krecentdocument.h>
+
+typedef KParts::GenericFactory<KViewViewer> KViewViewerFactory;
+K_EXPORT_COMPONENT_FACTORY( libkviewviewer, KViewViewerFactory )
+
+KViewViewer::KViewViewer( QWidget *parentWidget, const char * /*widgetName*/,
+ QObject *parent, const char *name, const QStringList & )
+ : KImageViewer::Viewer( parent, name )
+ , m_pParentWidget( parentWidget )
+ , m_pJob( 0 )
+ , m_pExtension( 0 )
+ , m_pCanvas( 0 )
+ , m_pTempFile( 0 )
+ , m_pBuffer( 0 )
+ , m_pFileWatch( new KDirWatch( this ) )
+{
+ KImageIO::registerFormats();
+
+ QWidget * widget = KParts::ComponentFactory::createInstanceFromQuery<QWidget>(
+ "KImageViewer/Canvas", QString::null, m_pParentWidget );
+ m_pCanvas = static_cast<KImageViewer::Canvas *>( widget->qt_cast( "KImageViewer::Canvas" ) );
+ kdDebug( 4610 ) << "KImageViewer::Canvas at " << m_pCanvas << endl;
+ if( ! ( widget && m_pCanvas ) )
+ {
+ if( ! widget )
+ KMessageBox::error( m_pParentWidget, i18n( "Unable to find a suitable Image Canvas. This probably means that KView was not installed properly." ) );
+ else
+ KMessageBox::error( m_pParentWidget, i18n( "Accessing the KImageViewer interface of the Image Canvas failed. Something in your setup is broken (a component claims to be a KImageViewer::Canvas but it is not)." ) );
+ }
+ else
+ {
+ // create the extension before the plugins are loaded, because plugins might want to use it
+ m_pExtension = new KViewKonqExtension( m_pCanvas, this );
+
+ setPluginLoadingMode( LoadPluginsIfEnabled );
+ setInstance( KViewViewerFactory::instance() );
+
+ // m_url isn't set from ReadOnlyPart so we set it here to the CWD
+ m_url = QDir::currentDirPath() + "/";
+ m_sCaption = i18n( "Title caption when no image loaded", "no image loaded" );
+
+ setWidget( widget );
+
+ // Drag and Drop for the Canvas
+ widget->setAcceptDrops( true );
+ widget->installEventFilter( this );
+
+ setupActions();
+
+ if( isReadWrite() )
+ setXMLFile( "kviewviewer.rc" );
+ else
+ setXMLFile( "kviewviewer_ro.rc" );
+
+ connect( widget, SIGNAL( contextPress( const QPoint & ) ),
+ this, SLOT( slotPopupMenu( const QPoint & ) ) );
+ connect( widget, SIGNAL( zoomChanged( double ) ),
+ this, SLOT( zoomChanged( double ) ) );
+ connect( widget, SIGNAL( showingImageDone() ),
+ this, SLOT( switchBlendEffect() ) );
+ connect( widget, SIGNAL( hasImage( bool ) ),
+ this, SLOT( hasImage( bool ) ) );
+ connect( widget, SIGNAL( imageChanged() ),
+ this, SLOT( setModified() ) );
+
+ connect( m_pFileWatch, SIGNAL( dirty( const QString & ) ),
+ this, SLOT( slotFileDirty( const QString & ) ) );
+
+ KSettings::Dispatcher::self()->registerInstance( instance(), this, SLOT( readSettings() ) );
+
+ // by default disable progress info (so it won't open the dialog in Konqueror)
+ setProgressInfoEnabled( false );
+
+ m_popupDoc = KXMLGUIFactory::readConfigFile( "kviewpopup.rc", true, instance() );
+
+ KConfigGroup cfgGroup( instance()->config(), "Settings" );
+ bool hideBars = cfgGroup.readBoolEntry( "hideScrollbars", false );
+ m_pCanvas->hideScrollbars( hideBars );
+ m_paShowScrollbars->setChecked( ! hideBars );
+ m_vEffects.resize( m_pCanvas->numOfBlendEffects() );
+
+ readSettings();
+ }
+}
+
+KViewViewer::~KViewViewer()
+{
+ kdDebug( 4610 ) << k_funcinfo << endl;
+
+ writeSettings();
+ instance()->config()->sync();
+
+ /*abortLoad(); //just in case
+ if( isModified() && isReadWrite() )
+ {
+ int res = m_url.isEmpty() ?
+ KMessageBox::warningYesNo( widget(),
+ i18n( "This is a new document.\nDo you want to save it ?" ),
+ QString::null, KStdGuiItem::saveAs(), KStdGuiItem::discard() ):
+ KMessageBox::warningYesNo( widget(),
+ i18n( "The document has been modified.\nDo you want to save it ?" ),
+ QString::null, KStdGuiItem::saveAs(), KStdGuiItem::dontSave() );
+
+ if( res == KMessageBox::Yes )
+ {
+ KURL url = KFileDialog::getSaveURL();
+ if( ! url.isEmpty() )
+ saveAs( url );
+ }
+ }
+ ReadOnlyPart::closeURL();*/
+
+ abortLoad();
+ delete m_pTempFile;
+ delete m_pBuffer;
+}
+
+KAboutData * KViewViewer::createAboutData()
+{
+ KAboutData * aboutData = new KAboutData( "kviewviewer", I18N_NOOP( "KView" ),
+ KVIEW_VERSION, I18N_NOOP( "KDE Image Viewer Part" ),
+ KAboutData::License_GPL,
+ I18N_NOOP("(c) 1997-2002, The KView Developers") );
+ aboutData->addAuthor( "Matthias Kretz", I18N_NOOP( "Maintainer" ), "kretz@kde.org" );
+ aboutData->addAuthor( "Sirtaj Singh Kang", I18N_NOOP( "started it all" ), "taj@kde.org" );
+ aboutData->addAuthor( "Simon Hausmann", 0, "hausmann@kde.org" );
+ return aboutData;
+}
+
+void KViewViewer::setReadWrite( bool readwrite )
+{
+ KImageViewer::Viewer::setReadWrite( readwrite );
+ if( readwrite )
+ setXMLFile( "kviewviewer.rc" );
+ else
+ setXMLFile( "kviewviewer_ro.rc" );
+}
+
+bool KViewViewer::saveAs( const KURL & kurl )
+{
+ kdDebug( 4610 ) << k_funcinfo << endl;
+ if( !kurl.isValid() )
+ return KParts::ReadWritePart::saveAs( kurl ); // sets m_bClosing = false
+
+ // if the image wasn't modified and should be saved in the same format we just copy the file - no need
+ // to lose some quality or information by calling QImage::save()
+ if( ! ( isModified() && isReadWrite() ) && m_mimeType == m_newMimeType )
+ {
+ kdDebug( 4610 ) << "copy image from " << m_file << " to " << kurl.prettyURL() << endl;
+
+ KIO::Job * job = KIO::copy( KURL( m_file ), kurl, isProgressInfoEnabled() );
+ emit started( job );
+ connect( job, SIGNAL( result( KIO::Job * ) ),
+ this, SLOT( slotResultSaveAs( KIO::Job * ) ) );
+ return true;
+ }
+ kdDebug( 4610 ) << "call KParts::ReadWritePart::saveAs( " << kurl.prettyURL() << " )" << endl;
+
+ bool ret = KParts::ReadWritePart::saveAs( kurl );
+ if( ret == false )
+ KMessageBox::error( m_pParentWidget, i18n( "The image could not be saved to disk. A possible causes is that you don't have permission to write to that file." ) );
+ return ret;
+}
+
+void KViewViewer::setModified( bool modified )
+{
+ m_paSave->setEnabled( modified );
+ KImageViewer::Viewer::setModified( modified );
+}
+
+bool KViewViewer::openURL( const KURL & url )
+{
+ kdDebug( 4610 ) << k_funcinfo << endl;
+ if ( !url.isValid() )
+ {
+ kdWarning( 4610 ) << "malformed URL " << url.prettyURL() << endl;
+ return false;
+ }
+ if ( !closeURL() )
+ {
+ kdDebug( 4610 ) << "closeURL didn't work out" << endl;
+ return false;
+ }
+ setModified( false );
+ m_url = url;
+ m_mimeType = m_pExtension->urlArgs().serviceType; // if this fails to
+ // find the right mime type it'll be determined in openFile()
+ if ( m_url.isLocalFile() )
+ {
+ emit started( 0 );
+ m_file = m_url.path();
+ kdDebug( 4610 ) << "open local file " << m_file << endl;
+ bool ret = openFile();
+ if( ret )
+ {
+ m_sCaption = m_url.prettyURL();
+ emit setWindowCaption( m_sCaption );
+ emit completed();
+ }
+ return ret;
+ }
+ else
+ {
+ m_sCaption = m_url.prettyURL();
+ emit setWindowCaption( m_sCaption );
+ m_bTemp = true;
+ // Use same extension as remote file. This is important for mimetype-determination (e.g. koffice)
+ QString extension;
+ QString fileName = url.fileName();
+ int extensionPos = fileName.findRev( '.' );
+ if ( extensionPos != -1 )
+ extension = fileName.mid( extensionPos ); // keep the '.'
+ delete m_pTempFile;
+ m_pTempFile = new KTempFile( QString::null, extension );
+ m_file = m_pTempFile->name();
+
+ m_pJob = KIO::get( m_url, m_pExtension->urlArgs().reload, isProgressInfoEnabled() );
+ emit started( m_pJob );
+ connect( m_pJob, SIGNAL( result( KIO::Job * ) ), SLOT( slotJobFinished ( KIO::Job * ) ) );
+ connect( m_pJob, SIGNAL( data( KIO::Job *, const QByteArray & ) ), SLOT( slotData( KIO::Job *, const QByteArray & ) ) );
+ return true;
+ }
+}
+
+bool KViewViewer::closeURL()
+{
+ kdDebug( 4610 ) << k_funcinfo << endl;
+ abortLoad();
+ QString file = m_file;
+ bool ret = KParts::ReadWritePart::closeURL();
+ if( ret )
+ if( ! file.isEmpty() )
+ {
+ kdDebug( 4610 ) << "remove " << file << " from KDirWatch\n";
+ m_pFileWatch->removeFile( file );
+ }
+ return ret;
+}
+
+void KViewViewer::newImage( const QImage & newimg )
+{
+ if( closeURL() )
+ {
+ m_url = "";
+ m_file = QString::null;
+ m_sCaption = i18n( "Title caption when new image selected", "new image" );
+ m_pCanvas->setImage( newimg );
+ if( isReadWrite() )
+ setModified( true );
+ }
+}
+
+void KViewViewer::reload()
+{
+ kdDebug( 4610 ) << k_funcinfo << endl;
+
+ if( isReadWrite() && isModified() )
+ if( ! queryClose() )
+ return;
+
+ //load from file
+ QImage image( m_file );
+ m_pCanvas->setImage( image );
+ setModified( false );
+}
+
+bool KViewViewer::eventFilter( QObject * o, QEvent * e )
+{
+ KImageViewer::Canvas * canvas = static_cast<KImageViewer::Canvas*>( o->qt_cast( "KImageViewer::Canvas" ) );
+ if( canvas )
+ {
+ // intercept drops onto the Canvas
+ switch( e->type() )
+ {
+ case QEvent::DragEnter:
+ {
+ QDragEnterEvent * ev = static_cast<QDragEnterEvent*>( e );
+ kdDebug( 4610 ) << "DragEnter Event in the Canvas: " << endl;
+ for( int i = 0; ev->format( i ); ++i )
+ kdDebug( 4610 ) << " - " << ev->format( i ) << endl;
+ ev->accept( KURLDrag::canDecode( ev ) || QImageDrag::canDecode( ev ) );
+ return true;
+ }
+ case QEvent::Drop:
+ {
+ QDropEvent * ev = static_cast<QDropEvent*>( e );
+ kdDebug( 4610 ) << "Drop Event in the Canvas" << endl;
+ QStringList l;
+ QImage image;
+ if( KURLDrag::decodeToUnicodeUris( ev, l ) )
+ openURL( KURL( l.first() ) );
+ else if( QImageDrag::decode( ev, image ) )
+ newImage( image );
+ return true;
+ }
+ default:
+ break;
+ }
+ }
+ return KImageViewer::Viewer::eventFilter( o, e );
+}
+
+void KViewViewer::abortLoad()
+{
+ if ( m_pJob )
+ {
+ m_pJob->kill();
+ m_pJob = 0;
+ }
+}
+
+bool KViewViewer::openFile()
+{
+ //m_pCanvas->setMaximumImageSize( QSize( widget()->width(), widget()->height() ) );
+ if( m_pBuffer )
+ {
+ kdDebug( 4610 ) << k_funcinfo << " load from buffer\n";
+ //load from buffer
+ m_pBuffer->close();
+ if( m_pTempFile )
+ {
+ m_pTempFile->dataStream()->writeRawBytes( m_pBuffer->buffer().data(), m_pBuffer->buffer().size() );
+ m_pTempFile->close();
+ }
+
+ // determine Mime Type
+ if( m_mimeType.isNull() )
+ {
+ m_mimeType = KImageIO::mimeType( m_url.fileName() );
+ kdDebug( 4610 ) << "MimeType: " << m_mimeType << endl;
+ if( m_mimeType.isNull() )
+ {
+ m_mimeType = KMimeType::findByContent( m_pBuffer->buffer() )->name();
+ kdDebug( 4610 ) << "MimeType: " << m_mimeType << endl;
+ }
+ }
+
+ QImage image( m_pBuffer->buffer() );
+ delete m_pBuffer;
+ m_pBuffer = 0;
+ if( ! image.isNull() )
+ {
+ QSize size = image.size();
+ m_pCanvas->setImage( image, size );
+ }
+ else
+ {
+ emit setStatusBarText( i18n( "Unknown image format: %1" ).arg( m_url.prettyURL() ) );
+ return false;
+ }
+ }
+ else
+ { //load from local file
+ kdDebug( 4610 ) << k_funcinfo << " load from file: " << m_file << endl;
+ if( ! QFile::exists( m_file ) )
+ {
+ emit setStatusBarText( i18n( "No such file: %1" ).arg( m_file ) );
+ return false;
+ }
+ if( QImage::imageFormat( m_file ) == 0 )
+ {
+ emit setStatusBarText( i18n( "Unknown image format: %1" ).arg( m_file ) );
+ return false;
+ }
+ // determine Mime Type
+ if( m_mimeType.isNull() )
+ {
+ m_mimeType = KImageIO::mimeType( m_file );
+ kdDebug( 4610 ) << "MimeType: " << m_mimeType << endl;
+ }
+
+ //load from file
+ QImage image( m_file );
+ QSize size = image.size();
+ m_pCanvas->setImage( image, size );
+ }
+ m_pFileWatch->addFile( m_file );
+ emit imageOpened( m_url );
+ return true;
+}
+
+bool KViewViewer::saveFile()
+{
+ kdDebug( 4610 ) << k_funcinfo << endl;
+ // two possibilities:
+ //
+ // 1. The image should be saved as an exact copy of the loaded one (this
+ // is useful if you downloaded an image from the net and want to save it
+ // locally) - this can happen only in saveAs() so only 2. applies here:
+ //
+ // 2. The image should be saved in a different format or was modified, so
+ // that copying isn't possible anymore.
+
+ const QImage * image = m_pCanvas->image();
+ if( ! image )
+ return false;
+
+ if( ! m_newMimeType.isNull() )
+ {
+ m_mimeType = m_newMimeType;
+ m_newMimeType = QString::null;
+ }
+ QString type = KImageIO::typeForMime( m_mimeType );
+ kdDebug( 4610 ) << "save m_pCanvas->image() to " << m_file << " as " << type << endl;
+ int quality = 100; // TODO: ask user for quality. Keep it at 100 so that our
+ // users don't lose quality when working with KView.
+
+ m_pFileWatch->removeFile( m_file );
+ bool ret = image->save( m_file, type.latin1(), quality );
+ m_pFileWatch->addFile( m_file );
+ return ret;
+}
+
+void KViewViewer::setupActions()
+{
+ m_paZoomIn = new KAction( i18n( "Zoom In" ), "viewmag+", KStdAccel::shortcut( KStdAccel::ZoomIn ), this,
+ SLOT( slotZoomIn() ), actionCollection(), "zoomin" );
+ m_paZoomOut = new KAction( i18n( "Zoom Out" ), "viewmag-", KStdAccel::shortcut( KStdAccel::ZoomOut ), this,
+ SLOT( slotZoomOut() ), actionCollection(), "zoomout" );
+
+ m_paZoom = new KSelectAction( i18n( "Zoom" ), "viewmag", 0, actionCollection(), "view_zoom" );
+ connect( m_paZoom, SIGNAL( activated( const QString & ) ), this, SLOT( setZoom( const QString & ) ) );
+ m_paZoom->setEditable( true );
+ m_paZoom->clear();
+ m_paZoom->setItems( QStringList::split( '|', "20%|25%|33%|50%|75%|100%|125%|150%|200%|250%|300%|350%|400%|450%|500%" ) );
+ m_paZoom->setCurrentItem( 5 );
+
+ m_paFlipMenu = new KActionMenu( i18n( "&Flip" ), actionCollection(), "flip" );
+ m_paFlipV = new KAction( i18n( "&Vertical" ), Key_V, this, SLOT( slotFlipV() ), actionCollection(), "flip_vertical" );
+ m_paFlipH = new KAction( i18n( "&Horizontal" ), Key_H, this, SLOT( slotFlipH() ), actionCollection(), "flip_horizontal" );
+ m_paFlipMenu->insert( m_paFlipV );
+ m_paFlipMenu->insert( m_paFlipH );
+
+ m_paRotateCCW = new KAction( i18n( "Ro&tate Counter-Clockwise" ), "rotate_ccw", 0, this,
+ SLOT( slotRotateCCW() ), actionCollection(), "rotateCCW" );
+ m_paRotateCW = new KAction( i18n( "Rotate Clockwise" ), "rotate_cw", 0, this,
+ SLOT( slotRotateCW() ), actionCollection(), "rotateCW" );
+ m_paSave = KStdAction::save( this, SLOT( slotSave() ), actionCollection() );
+ m_paSave->setEnabled( false );
+ m_paSaveAs = KStdAction::saveAs( this, SLOT( slotSaveAs() ), actionCollection() );
+
+ m_paFitToWin = new KAction( i18n( "Fit Image to Window" ), 0, 0, this,
+ SLOT( slotFitToWin() ), actionCollection(), "fittowin" );
+ m_paZoomIn->setEnabled( false );
+ m_paZoomOut->setEnabled( false );
+ m_paZoom->setEnabled( false );
+ m_paRotateCCW->setEnabled( false );
+ m_paRotateCW->setEnabled( false );
+ m_paSaveAs->setEnabled( false );
+ m_paFitToWin->setEnabled( false );
+ m_paFlipMenu->setEnabled( false );
+ m_paFlipV->setEnabled( false );
+ m_paFlipH->setEnabled( false );
+ connect( widget(), SIGNAL( hasImage( bool ) ), m_paZoomIn, SLOT( setEnabled( bool ) ) );
+ connect( widget(), SIGNAL( hasImage( bool ) ), m_paZoomOut, SLOT( setEnabled( bool ) ) );
+ connect( widget(), SIGNAL( hasImage( bool ) ), m_paZoom, SLOT( setEnabled( bool ) ) );
+ connect( widget(), SIGNAL( hasImage( bool ) ), m_paRotateCCW, SLOT( setEnabled( bool ) ) );
+ connect( widget(), SIGNAL( hasImage( bool ) ), m_paRotateCW, SLOT( setEnabled( bool ) ) );
+ connect( widget(), SIGNAL( hasImage( bool ) ), m_paSaveAs, SLOT( setEnabled( bool ) ) );
+ connect( widget(), SIGNAL( hasImage( bool ) ), m_paFitToWin, SLOT( setEnabled( bool ) ) );
+ connect( widget(), SIGNAL( hasImage( bool ) ), m_paFlipMenu, SLOT( setEnabled( bool ) ) );
+ connect( widget(), SIGNAL( hasImage( bool ) ), m_paFlipV, SLOT( setEnabled( bool ) ) );
+ connect( widget(), SIGNAL( hasImage( bool ) ), m_paFlipH, SLOT( setEnabled( bool ) ) );
+
+ m_paShowScrollbars = new KToggleAction( i18n( "Show Scrollbars" ), 0, this, SLOT( slotToggleScrollbars() ),
+ actionCollection(), "show_scrollbars" );
+ m_paShowScrollbars->setCheckedState(i18n("Hide Scrollbars"));
+}
+
+void KViewViewer::guiActivateEvent( KParts::GUIActivateEvent * event )
+{
+ ReadWritePart::guiActivateEvent( event );
+ bool enabled = m_pCanvas->image() ? true : false;
+ emit m_pExtension->enableAction( "del", enabled );
+ emit m_pExtension->enableAction( "print", enabled );
+ if( ! enabled )
+ {
+ m_sCaption = i18n( "Title caption when no image loaded", "no image loaded" );
+ emit setWindowCaption( m_sCaption );
+ }
+}
+
+void KViewViewer::readSettings()
+{
+ KConfigGroup cfgGroup( instance()->config(), "Settings" );
+ m_pCanvas->setFastScale( ! cfgGroup.readBoolEntry( "Smooth Scaling", ! m_pCanvas->fastScale() ) );
+ m_pCanvas->setKeepAspectRatio( cfgGroup.readBoolEntry( "Keep Aspect Ratio", m_pCanvas->keepAspectRatio() ) );
+ m_pCanvas->setCentered( cfgGroup.readBoolEntry( "Center Image", m_pCanvas->centered() ) );
+
+ m_pCanvas->setBgColor( cfgGroup.readColorEntry( "Background Color", &m_pCanvas->bgColor() ) );
+
+ m_pCanvas->setMinimumImageSize( QSize( cfgGroup.readNumEntry( "Minimum Width", m_pCanvas->minimumImageSize().width() ),
+ cfgGroup.readNumEntry( "Minimum Height", m_pCanvas->minimumImageSize().height() ) ) );
+ m_pCanvas->setMaximumImageSize( QSize( cfgGroup.readNumEntry( "Maximum Width", m_pCanvas->maximumImageSize().width() ),
+ cfgGroup.readNumEntry( "Maximum Height", m_pCanvas->maximumImageSize().height() ) ) );
+
+ KConfigGroup blendConfig( instance()->config(), "Blend Effects" );
+ m_vEffects.clear();
+ for( unsigned int i = 1; i <= m_pCanvas->numOfBlendEffects(); ++i )
+ {
+ if( blendConfig.readBoolEntry( QString::number( i ), false ) )
+ m_vEffects.push_back( i );
+ }
+ // and now tell the canvas what blend effect to use
+ switchBlendEffect();
+ loadPlugins();
+}
+
+void KViewViewer::writeSettings()
+{
+ KConfigGroup cfgGroup( instance()->config(), "Settings" );
+ cfgGroup.writeEntry( "hideScrollbars", ! m_paShowScrollbars->isChecked() );
+}
+
+void KViewViewer::zoomChanged( double zoom )
+{
+ kdDebug( 4610 ) << k_funcinfo << endl;
+ emit setWindowCaption( m_sCaption + QString( " (%1%)" ).arg( zoom * 100, 0, 'f', 0 ) );
+ updateZoomMenu( zoom );
+}
+
+void KViewViewer::slotJobFinished( KIO::Job * job )
+{
+ assert( job == m_pJob );
+ m_pJob = 0;
+ if (job->error())
+ emit canceled( job->errorString() );
+ else
+ {
+ openFile();
+ emit completed();
+ }
+}
+
+void KViewViewer::slotData( KIO::Job *, const QByteArray & data )
+{
+ if( ! m_pBuffer )
+ {
+ m_pBuffer = new QBuffer();
+ m_pBuffer->open( IO_ReadWrite );
+ }
+ m_pBuffer->writeBlock( data.data(), data.size() );
+
+ //show partial image XXX: is this really the way to do it?
+ //No. :) It takes forever like this.
+ //OK. So I really have to look at khtml...
+ //later...
+ //m_pCanvas->setImage( QImage( m_pBuffer->buffer() ) );
+}
+
+void KViewViewer::slotSave()
+{
+ kdDebug( 4610 ) << k_funcinfo << endl;
+ if( ! save() )
+ KMessageBox::error( m_pParentWidget, i18n( "The image could not be saved to disk. A possible causes is that you don't have permission to write to that file." ) );
+}
+
+void KViewViewer::slotSaveAs()
+{
+ kdDebug( 4610 ) << k_funcinfo << endl;
+ KFileDialog dlg( QString::null, QString::null, widget(), "filedialog", true );
+ dlg.setMimeFilter( KImageIO::mimeTypes( KImageIO::Writing ) );
+ dlg.setSelection( m_url.fileName() );
+ dlg.setCaption( i18n( "Save As" ) );
+ dlg.setOperationMode( KFileDialog::Saving );
+ dlg.exec();
+ KURL url = dlg.selectedURL();
+ m_newMimeType = dlg.currentMimeFilter();
+ if( m_newMimeType.isEmpty() )
+ m_newMimeType = KImageIO::mimeType( url.path() );
+ kdDebug( 4610 ) << k_funcinfo << "m_newMimeType = " << m_newMimeType << endl;
+ if( url.isValid() )
+ KRecentDocument::add( url );
+ saveAs( url );
+}
+
+void KViewViewer::slotZoomIn()
+{
+ double zoom = m_pCanvas->zoom() * 1.1;
+ if (zoom < 0.01) zoom=0.01 ;
+ m_pCanvas->setZoom( zoom );
+}
+
+void KViewViewer::slotZoomOut()
+{
+ double zoom = m_pCanvas->zoom() / 1.1;
+ if (zoom < 0.01) zoom=0.01 ;
+ m_pCanvas->setZoom( zoom );
+}
+
+void KViewViewer::setZoom( const QString & newZoom )
+{
+ kdDebug( 4610 ) << k_funcinfo << newZoom << endl;
+ double zoom;
+ QString z = newZoom;
+ z.remove( z.find( '%' ), 1 );
+ if( newZoom == "33%" )
+ zoom = 1.0 / 3.0;
+ else
+ zoom = KGlobal::locale()->readNumber( z ) / 100;
+
+ m_pCanvas->setZoom( zoom );
+}
+
+void KViewViewer::updateZoomMenu( double zoom )
+{
+ QStringList lst;
+ if( zoom > 0.0 )
+ {
+ //lst << i18n( "Maxpect" );
+ QValueList<int> list;
+ QString z;
+ int val;
+ bool ok;
+ QStringList itemsList = m_paZoom->items();
+ for( QStringList::Iterator it = itemsList.begin(); it != itemsList.end(); ++it )
+ {
+ z = ( *it ).replace( QRegExp( "%" ), "" );
+ z = z.simplifyWhiteSpace();
+ val = z.toInt( &ok );
+ if( ok && val > 0 && list.contains( val ) == 0 )
+ list << val;
+ }
+ val = QString::number( zoom * 100, 'f', 0 ).toInt(); // round/lround from math.h doesn't work - dunno
+ if( list.contains( val ) == 0 )
+ list.append( val );
+
+ qHeapSort( list );
+
+ for( QValueList<int>::Iterator it = list.begin(); it != list.end(); ++it )
+ lst << QString::number( *it ) + '%';
+ m_paZoom->setItems( lst );
+ }
+
+ // first look if it's a new value (not in the list yet)
+ QString z = QString( "%1%" ).arg( zoom * 100, 0, 'f', 0 );
+ QStringList items = m_paZoom->items();
+ int idx = items.findIndex( z );
+ if( -1 == idx )
+ {
+ // not found XXX: remove when done
+ kdDebug( 4610 ) << "zoom value not in the list: " << z << endl;
+ kdDebug( 4610 ) << "here's the list:\n- " << items.join( "\n- " ) << endl;
+ }
+ else
+ {
+ // already in the list
+ kdDebug( 4610 ) << "zoom value already in the list: " << z << endl;
+ // make that one selected
+ m_paZoom->setCurrentItem( idx );
+ }
+}
+
+void KViewViewer::slotFlipH()
+{
+ m_pCanvas->flipVertical( isReadWrite() );
+}
+
+void KViewViewer::slotFlipV()
+{
+ m_pCanvas->flipHorizontal( isReadWrite() );
+}
+
+void KViewViewer::slotRotateCCW()
+{
+ m_pCanvas->rotate( -90.0, isReadWrite() );
+}
+
+void KViewViewer::slotRotateCW()
+{
+ m_pCanvas->rotate( 90.0, isReadWrite() );
+}
+
+void KViewViewer::slotFitToWin()
+{
+ m_pCanvas->boundImageTo( widget()->size() );
+}
+
+void KViewViewer::slotDel()
+{
+ //just in case m_url get's modified while closing
+ KURL urltodel = m_url;
+ if( closeURL() )
+ {
+ setModified( false );
+ KIO::file_delete( urltodel );
+ m_pCanvas->clear();
+ }
+}
+
+class PopupGUIClient : public KXMLGUIClient
+{
+ public:
+ PopupGUIClient( KInstance *inst, const QString &doc )
+ {
+ setInstance( inst );
+ setXML( doc );
+ }
+};
+
+void KViewViewer::slotPopupMenu( const QPoint &pos )
+{
+ KXMLGUIClient *popupGUIClient = new PopupGUIClient( instance(), m_popupDoc );
+
+ (void) new KAction( i18n( "Save Image As..." ), 0, this, SLOT( slotSaveAs() ),
+ popupGUIClient->actionCollection(), "saveimageas" );
+
+ // ### HACK treat the image as dir to get the back/fwd/reload buttons (Simon)
+ emit m_pExtension->popupMenu( popupGUIClient, pos, m_url, m_mimeType, S_IFDIR );
+
+ delete popupGUIClient;
+}
+
+void KViewViewer::slotResultSaveAs( KIO::Job *job )
+{
+ if ( job->error() )
+ {
+ emit canceled( job->errorString() );
+ //job->showErrorDialog( widget() );
+ }
+ else
+ {
+ emit completed();
+ KIO::CopyJob * cjob = ::qt_cast<KIO::CopyJob*>( job );
+ if( cjob )
+ {
+ m_url = cjob->destURL();
+ m_sCaption = m_url.prettyURL();
+ }
+ else
+ m_sCaption = "";
+ emit setWindowCaption( m_sCaption );
+ }
+
+ // Now we have to delete the tempfile if it exists and if the current
+ // image position is on the local HD. If it's somewhere else we keep the
+ // tempfile in case the user calls saveAs() again.
+ if( m_url.isLocalFile() )
+ {
+ if( m_bTemp )
+ {
+ unlink( QFile::encodeName( m_file ) );
+ m_bTemp = false;
+ }
+ m_file = m_url.path();
+ }
+}
+
+void KViewViewer::slotFileDirty( const QString & )
+{
+ if( isModified() && isReadWrite() )
+ {
+ KPassivePopup * pop = new KPassivePopup( m_pParentWidget );
+ QVBox * vb = pop->standardView( i18n( "Load changed image? - %1" ).arg( kapp->aboutData()->programName() ),
+ QString::null, kapp->miniIcon() );
+ ( void )new QLabel( i18n( "The image %1 which you have modified has changed on disk.\n"
+ "Do you want to reload the file and lose your changes?\n"
+ "If you don't and subsequently save the image, you will lose the\n"
+ "changes that have already been saved." ).arg( url().fileName() ), vb );
+ QWidget * hb = new QWidget( vb );
+ QHBoxLayout * layout = new QHBoxLayout( hb );
+ layout->addItem( new QSpacerItem( 0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum ) );
+ KPushButton * yes = new KPushButton( i18n("Reload"), hb );
+ layout->addWidget( yes );
+ layout->addItem( new QSpacerItem( 0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum ) );
+ KPushButton * no = new KPushButton( i18n("Do Not Reload"), hb );
+ layout->addWidget( no );
+ layout->addItem( new QSpacerItem( 0, 0, QSizePolicy::Minimum, QSizePolicy::Minimum ) );
+ connect( yes, SIGNAL( clicked() ), this, SLOT( slotReloadUnmodified() ) );
+ connect( yes, SIGNAL( clicked() ), pop, SLOT( hide() ) );
+ connect( no, SIGNAL( clicked() ), pop, SLOT( hide() ) );
+ pop->setView( vb );
+ pop->setTimeout( 0 );
+ pop->setAutoDelete( true );
+ pop->show();
+ kdDebug( 4610 ) << "popup returned\n";
+ }
+ else
+ reload();
+}
+
+void KViewViewer::slotReloadUnmodified()
+{
+ setModified( false );
+ reload();
+ kdDebug( 4610 ) << "reload done\n";
+}
+
+void KViewViewer::slotToggleScrollbars()
+{
+ m_pCanvas->hideScrollbars( ! m_paShowScrollbars->isChecked() );
+}
+
+void KViewViewer::loadPlugins()
+{
+ KImageViewer::Viewer::loadPlugins( this, this, instance() );
+ if( factory() )
+ {
+ QPtrList<KParts::Plugin> plugins = KParts::Plugin::pluginObjects( this );
+ KParts::Plugin * plugin;
+ for( plugin = plugins.first(); plugin; plugin = plugins.next() )
+ factory()->addClient( plugin );
+ }
+}
+
+void KViewViewer::switchBlendEffect()
+{
+ if( m_vEffects.empty() )
+ m_pCanvas->setBlendEffect( 0 );
+ else
+ {
+ unsigned int num = KApplication::random() % m_vEffects.size();
+ m_pCanvas->setBlendEffect( m_vEffects[ num ] );
+ }
+}
+
+void KViewViewer::hasImage( bool b )
+{
+ emit m_pExtension->enableAction( "del", b );
+ emit m_pExtension->enableAction( "print", b );
+ if( ! b )
+ {
+ m_sCaption = i18n( "Title caption when no image loaded", "No Image Loaded" );
+ emit setWindowCaption( m_sCaption );
+ }
+}
+
+// vim:sw=4:ts=4
+
+#include "kviewviewer.moc"
+
diff --git a/kview/kviewviewer/kviewviewer.desktop b/kview/kviewviewer/kviewviewer.desktop
new file mode 100644
index 00000000..2961fb65
--- /dev/null
+++ b/kview/kviewviewer/kviewviewer.desktop
@@ -0,0 +1,118 @@
+[Desktop Entry]
+Type=Service
+Icon=kview
+Comment=KDE Image Viewer Part
+Comment[af]=Kde Beeld Aansig Deel
+Comment[ar]=عارض جزء الصور ل KDE
+Comment[br]=Perzh gweler skeudennoù KDE
+Comment[bs]=KDE Part - Preglednik slika
+Comment[ca]=Peça de KDE visualitzadora d'imatges
+Comment[cs]=Komponenta prohlížeče obrázků KDE
+Comment[cy]=Rhan Gwelydd Delweddau KDE
+Comment[da]=KDE Billedviser-part
+Comment[de]=KDE Bildbetrachter-Komponente (KPart)
+Comment[el]=Part προβολέα εικόνων του KDE
+Comment[eo]=KDE-bildorigardilo parto
+Comment[es]=Parte de visor de imágenes de KDE
+Comment[et]=KDE pildifailide näitaja komponent
+Comment[eu]=KDE irudi ikustailearen zatia
+Comment[fa]=جزء مشاهده‌گر تصویر KDE
+Comment[fi]=KDE:n kuvannäyttökomponentti
+Comment[fr]=Composant d'affichage d'images de KDE
+Comment[gl]=Visor de imaxes integrado do KDE
+Comment[he]=רכיב מציג תמונות ל־KDE
+Comment[hi]=केडीई छवि प्रदर्शक पार्ट
+Comment[hr]=KDE komponenta za pregledavanje slika
+Comment[hu]=KDE képnézegető objektum
+Comment[is]=Myndbirtir KDE
+Comment[it]=Componente KDE per la visione di immagini
+Comment[ja]=KDE 画像ビューアパート
+Comment[kk]=KDE кескінді қарау құралының бөлшегі
+Comment[km]=ផ្នែក​របស់​កម្មវិធី​មើល​រូបភាព KDE
+Comment[lt]=KDE paveikslėlių žiūriklio dalis
+Comment[ms]=Bahagian Pemapar Imej KDE
+Comment[nb]=KDE-bildefremviserdel
+Comment[nds]=Bildkieker-Komponent för KDE
+Comment[ne]=KDE छवि दर्शक भाग
+Comment[nl]=KDE's weergavecomponent (Part) voor afbeeldingen
+Comment[nn]=Biletvisardel for KDE
+Comment[nso]=Seripa sa Molebeledi wa Ponagalo sa KDE
+Comment[pa]=KDE ਚਿੱਤਰ ਦਰਸ਼ਕ ਭਾਗ
+Comment[pl]=Składnik do przeglądarka obrazków KDE
+Comment[pt]=Componente de Visualização de Imagens do KDE
+Comment[pt_BR]=Parte do Visualizador de Imagens do KDE
+Comment[ro]=Componentă KDE de vizualizare imagini
+Comment[ru]=Компонент KDE просмотра изображений
+Comment[se]=KDE:a govvačájehanoassi
+Comment[sk]=Part KDE Prehliadač obrázkov
+Comment[sl]=Del pregledovalnika slik KDE
+Comment[sr]=KDE-ов део за приказивање слика
+Comment[sr@Latn]=KDE-ov deo za prikazivanje slika
+Comment[sv]=KDE:s bildvisningsdel
+Comment[ta]=கேடிஇ பகுதி பிம்பக் காட்சி
+Comment[tg]=Қисмати KDE-и намоиши тасвирот
+Comment[tr]=KDE Resim Göstericisi Kısmı
+Comment[uk]=Складова KDE переглядача зображень
+Comment[ven]=Tshipida tsha muvhoni wa tshifanyiso tsha KDE
+Comment[xh]=Iqhekeza Lombonisi Womfanekiso we KDE
+Comment[zh_CN]=KDE 图像查看器组件
+Comment[zh_HK]=KDE 圖像檢視器組件
+Comment[zh_TW]=KDE 影像檢視器組件
+Comment[zu]=Ingxenye Yombukisi Wesithombe se-KDE
+MimeType=image/gif;image/x-xpm;image/x-xbm;image/jpeg;image/x-bmp;image/png;image/x-ico;image/x-portable-bitmap;image/x-portable-pixmap;image/x-portable-greymap;image/tiff;image/jp2
+Name=KView Image Viewer
+Name[ar]=عارض KView للصور
+Name[br]=Gweler skeudennoù KView
+Name[bs]=KView predglednik slika
+Name[ca]=Visualitzador d'imatges KView
+Name[cs]=Prohlížeč obrázků KView
+Name[cy]=Celfigyn Gwelydd Delweddau KGweld
+Name[da]=KView-billedfremviser
+Name[de]=Bildbetrachter KView
+Name[el]=Προβολέας εικόνων KView
+Name[eo]=KView-Bildrigardilo
+Name[es]=Visor de imágenes de KView
+Name[et]=KView pildifailide näitaja
+Name[eu]=KView irudi ikustailea
+Name[fa]=مشاهده‌گر تصویر KView
+Name[fi]=KView-kuvannäytin
+Name[fr]=Visualisateur d'images KView
+Name[gl]=Visor de imaxes KView
+Name[he]=מציג תמונות KView
+Name[hi]=के-व्यू छवि प्रदर्शक
+Name[hu]=KView képnézegető
+Name[is]=KView myndbirtirinn
+Name[it]=Visore di immagini KView
+Name[ja]=KView 画像ビューア
+Name[kk]=KView кескінді қарау құралы
+Name[km]=កម្មវិធី​មើល​រូបភាព KView
+Name[lt]=KView paveikslėlių žiūryklė
+Name[ms]=Pemapar Imej KView
+Name[nb]=Bildeviseren KView
+Name[nds]=Bildkieker KView
+Name[ne]=केडीई दृश्य छवि दर्शक
+Name[nl]=KView afbeeldingenweergave
+Name[nn]=Biletvisaren KView
+Name[pa]=KView ਚਿੱਤਰ ਦਰਸ਼ਕ
+Name[pl]=Przeglądarka obrazków KView
+Name[pt]=Visualizador de Imagens KView
+Name[pt_BR]=Visualizador de Imagens do KVisualização
+Name[ro]=Vizualizor imagini KView
+Name[ru]=Программа просмотра изображений KView
+Name[se]=KView govvačájeheaddji
+Name[sk]=Prehliadač obrázkov KView
+Name[sl]=Pregledovalnik slik KView
+Name[sr]=KView, приказивач слика
+Name[sr@Latn]=KView, prikazivač slika
+Name[sv]=Kview bildvisning
+Name[ta]=கேகாட்சி பிம்பக் காட்சி
+Name[tg]=Барномаи намоиши тасвироти KView
+Name[tr]=KView Resim Görüntüleyici
+Name[uk]=Переглядач зображень KView
+Name[wa]=KView Håyneu d' imådjes
+Name[zh_CN]=KView 图像查看器
+Name[zh_HK]=KView 圖像檢視器
+Name[zh_TW]=KView 影像檢視器
+ServiceTypes=KImageViewer/Viewer,KParts/ReadWritePart,Browser/View
+InitialPreference=3
+X-KDE-Library=libkviewviewer
diff --git a/kview/kviewviewer/kviewviewer.h b/kview/kviewviewer/kviewviewer.h
new file mode 100644
index 00000000..4c5f13a0
--- /dev/null
+++ b/kview/kviewviewer/kviewviewer.h
@@ -0,0 +1,145 @@
+/* This file is part of the KDE project
+ Copyright (C) 1999 Simon Hausmann <hausmann@kde.org>
+ 2001-2002 Matthias Kretz <kretz@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 __kviewviewer_h__
+#define __kviewviewer_h__
+
+#include "kimageviewer/viewer.h"
+#include "kviewkonqextension.h"
+
+#include <qvaluevector.h>
+#include "kviewvieweriface.h"
+#include <kdemacros.h>
+
+namespace KImageViewer { class Canvas; }
+namespace KIO { class Job; }
+
+class KTempFile;
+class KAction;
+class KActionMenu;
+class KToggleAction;
+class KSelectAction;
+class KAboutData;
+class QBuffer;
+class QSize;
+class KDirWatch;
+template<class T>
+class QCache;
+
+class KDE_EXPORT KViewViewer : public KImageViewer::Viewer, public KViewViewerIface
+{
+ Q_OBJECT
+ friend class KViewKonqExtension;
+
+ public:
+ KViewViewer( QWidget * parentWidget, const char * widgetName,
+ QObject * parent, const char * name, const QStringList & );
+ virtual ~KViewViewer();
+
+ KImageViewer::Canvas * canvas() const { return m_pCanvas; }
+ static KAboutData * createAboutData();
+ virtual void setReadWrite( bool readwrite = true );
+ KParts::BrowserExtension * browserExtension() const { return m_pExtension; }
+
+ bool saveAs( const KURL & );
+ void setModified( bool );
+
+ public slots:
+ virtual bool openURL( const KURL & );
+ virtual bool closeURL();
+ virtual void newImage( const QImage & );
+ virtual void reload();
+
+ protected:
+ bool eventFilter( QObject *, QEvent * ); // for DnD
+ void abortLoad();
+ virtual bool openFile();
+ virtual bool saveFile();
+
+ virtual void setupActions();
+ void guiActivateEvent( KParts::GUIActivateEvent * );
+
+ void writeSettings();
+
+ protected slots:
+ void readSettings();
+ void zoomChanged( double );
+ void slotJobFinished( KIO::Job * );
+ void slotData( KIO::Job *, const QByteArray & );
+
+ void slotSave();
+ void slotSaveAs();
+ void slotZoomIn();
+ void slotZoomOut();
+ void setZoom( const QString & );
+ void updateZoomMenu( double zoom );
+ void slotFlipH();
+ void slotFlipV();
+ void slotRotateCCW();
+ void slotRotateCW();
+ void slotFitToWin();
+ void slotDel();
+
+ void slotPopupMenu( const QPoint & );
+ void slotResultSaveAs( KIO::Job * );
+
+ void slotFileDirty( const QString & );
+ void slotReloadUnmodified();
+
+ void slotToggleScrollbars();
+
+ void loadPlugins();
+
+ void switchBlendEffect();
+ void hasImage( bool );
+
+ private:
+ QWidget * m_pParentWidget;
+ KIO::Job * m_pJob;
+ KViewKonqExtension * m_pExtension;
+ KImageViewer::Canvas * m_pCanvas;
+ KTempFile * m_pTempFile;
+ QBuffer * m_pBuffer;
+ KDirWatch * m_pFileWatch;
+
+ // Actions:
+ KAction * m_paZoomIn;
+ KAction * m_paZoomOut;
+ KSelectAction * m_paZoom;
+ KActionMenu * m_paFlipMenu;
+ KAction * m_paFlipH;
+ KAction * m_paFlipV;
+ KAction * m_paRotateCCW;
+ KAction * m_paRotateCW;
+ KAction * m_paSave;
+ KAction * m_paSaveAs;
+ KAction * m_paFitToWin;
+ KToggleAction * m_paShowScrollbars;
+
+ QString m_popupDoc;
+ QString m_mimeType;
+ QString m_newMimeType;
+ QString m_sCaption;
+
+ QValueVector<unsigned int> m_vEffects;
+};
+
+// vim:sw=4:ts=4
+
+#endif
diff --git a/kview/kviewviewer/kviewviewer.rc b/kview/kviewviewer/kviewviewer.rc
new file mode 100644
index 00000000..cc36070b
--- /dev/null
+++ b/kview/kviewviewer/kviewviewer.rc
@@ -0,0 +1,36 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="KViewViewer Part" version="6">
+ <MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="file_save" group="save_merge_group"/>
+ <Action name="file_save_as" group="save_merge_group"/>
+ </Menu>
+ <Menu name="edit"><text>&amp;Edit</text>
+ <Action name="flip"/>
+ <Action name="rotateCCW"/>
+ <Action name="rotateCW"/>
+ </Menu>
+ <Menu name="view"><text>&amp;View</text>
+ <Action name="zoomin"/>
+ <Action name="view_zoom"/>
+ <Action name="zoomout"/>
+ <Separator/>
+ <Action name="fittowin"/>
+ </Menu>
+ <Menu name="settings"><text>&amp;Settings</text>
+ <Action name="show_scrollbars" group="show_merge_group" />
+ </Menu>
+ </MenuBar>
+ <ToolBar name="mainToolBar"><text>Main Toolbar</text>
+ <Action name="file_save_as"/>
+ <Action name="zoomin"/>
+ <Action name="view_zoom"/>
+ <Action name="zoomout"/>
+ <Action name="rotateCCW"/>
+ <Action name="rotateCW"/>
+ </ToolBar>
+ <Menu name="popupmenu">
+ <Separator/>
+ <Action name="saveimageas" group="file_group"/>
+ </Menu>
+</kpartgui>
diff --git a/kview/kviewviewer/kviewviewer_ro.rc b/kview/kviewviewer/kviewviewer_ro.rc
new file mode 100644
index 00000000..f266217c
--- /dev/null
+++ b/kview/kviewviewer/kviewviewer_ro.rc
@@ -0,0 +1,34 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="KViewViewer Part" version="7">
+ <MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="file_save_as" group="save_merge_group"/>
+ </Menu>
+ <Menu name="view"><text>&amp;View</text>
+ <Action name="zoomin"/>
+ <Action name="view_zoom"/>
+ <Action name="zoomout"/>
+ <Separator/>
+ <Action name="fittowin"/>
+ <Separator/>
+ <Action name="flip"/>
+ <Action name="rotateCCW"/>
+ <Action name="rotateCW"/>
+ </Menu>
+ <Menu name="settings"><text>&amp;Settings</text>
+ <Action name="show_scrollbars" group="show_merge_group" />
+ </Menu>
+ </MenuBar>
+ <ToolBar name="mainToolBar"><text>Main Toolbar</text>
+ <Action name="file_save_as"/>
+ <Action name="zoomin"/>
+ <Action name="view_zoom"/>
+ <Action name="zoomout"/>
+ <Action name="rotateCCW"/>
+ <Action name="rotateCW"/>
+ </ToolBar>
+ <Menu name="popupmenu">
+ <Separator/>
+ <Action name="saveimageas" group="file_group"/>
+ </Menu>
+</kpartgui>
diff --git a/kview/kviewviewer/kviewvieweriface.h b/kview/kviewviewer/kviewvieweriface.h
new file mode 100644
index 00000000..19a56232
--- /dev/null
+++ b/kview/kviewviewer/kviewvieweriface.h
@@ -0,0 +1,30 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+
+*/
+// $Id$
+
+#ifndef KVIEWVIEWERIFACE_H
+#define KVIEWVIEWERIFACE_H
+
+class KViewViewerIface
+{
+};
+
+#endif // KVIEWVIEWERIFACE_H
+
+// vim: sw=4 ts=4
diff --git a/kview/kviewviewer/printimagesettings.ui b/kview/kviewviewer/printimagesettings.ui
new file mode 100644
index 00000000..4944ef3c
--- /dev/null
+++ b/kview/kviewviewer/printimagesettings.ui
@@ -0,0 +1,190 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>PrintImageSettings</class>
+<author>Matthias Kretz &lt;kretz@kde.org&gt;</author>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>PrintImageSettings</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>167</width>
+ <height>223</height>
+ </rect>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout4</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout3</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="title">
+ <string>Image Size</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton1</cstring>
+ </property>
+ <property name="text">
+ <string>Fit to page size</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton2</cstring>
+ </property>
+ <property name="text">
+ <string>9x13</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton3</cstring>
+ </property>
+ <property name="text">
+ <string>10x15</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioButton4</cstring>
+ </property>
+ <property name="text">
+ <string>Manual</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout1</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KIntSpinBox">
+ <property name="name">
+ <cstring>kIntSpinBox1</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>x</string>
+ </property>
+ </widget>
+ <widget class="KIntSpinBox">
+ <property name="name">
+ <cstring>kIntSpinBox2</cstring>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>checkBox1</cstring>
+ </property>
+ <property name="text">
+ <string>Center on page</string>
+ </property>
+ </widget>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </vbox>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+</widget>
+<includes>
+ <include location="global" impldecl="in implementation">kdialog.h</include>
+</includes>
+<layoutdefaults spacing="6" margin="11"/>
+<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/>
+<includehints>
+ <includehint>qwidget.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+</includehints>
+</UI>
diff --git a/kview/kviewviewer/test/Makefile.am b/kview/kviewviewer/test/Makefile.am
new file mode 100644
index 00000000..605435cc
--- /dev/null
+++ b/kview/kviewviewer/test/Makefile.am
@@ -0,0 +1,9 @@
+INCLUDES = -I$(top_srcdir)/kview $(all_includes)
+
+METASOURCES = AUTO
+
+check_PROGRAMS = test
+
+test_SOURCES = main.cpp test.cpp
+test_LDFLAGS = $(KDE_RPATH) $(all_libraries)
+test_LDADD = $(LIB_KPARTS)
diff --git a/kview/kviewviewer/test/main.cpp b/kview/kviewviewer/test/main.cpp
new file mode 100644
index 00000000..95910126
--- /dev/null
+++ b/kview/kviewviewer/test/main.cpp
@@ -0,0 +1,51 @@
+#include "test.h"
+#include <kapplication.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+
+static const char description[] =
+ I18N_NOOP("KView Viewer Part Test");
+
+static const char version[] = "v0.1";
+
+static KCmdLineOptions options[] =
+{
+ { "+[URL]", I18N_NOOP( "Image to open" ), 0 },
+ KCmdLineLastOption
+};
+
+int main(int argc, char **argv)
+{
+ KAboutData about("kviewviewertest", I18N_NOOP("KView Viewer Test"), version, description, KAboutData::License_GPL, "(C) 2001 Matthias Kretz", 0, 0, "kretz@kde.org");
+ about.addAuthor( "Matthias Kretz", 0, "kretz@kde.org" );
+ KCmdLineArgs::init(argc, argv, &about);
+ KCmdLineArgs::addCmdLineOptions( options );
+ KApplication app;
+
+ if (app.isRestored())
+ RESTORE(Test)
+ else
+ {
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ if ( args->count() == 0 )
+ {
+ Test *widget = new Test;
+ widget->show();
+ }
+ else
+ {
+ int i = 0;
+ for (; i < args->count(); i++ )
+ {
+ Test *widget = new Test;
+ widget->show();
+ widget->load( args->url( i ) );
+ }
+ }
+ args->clear();
+ }
+
+ return app.exec();
+}
diff --git a/kview/kviewviewer/test/test.cpp b/kview/kviewviewer/test/test.cpp
new file mode 100644
index 00000000..d4659e6c
--- /dev/null
+++ b/kview/kviewviewer/test/test.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2001 Matthias Kretz <kretz@kde.org>
+ */
+
+#include "test.h"
+#include <kimageviewer/viewer.h>
+
+#include <kurl.h>
+#include <klibloader.h>
+#include <kmessagebox.h>
+#include <kparts/componentfactory.h>
+#include <kapplication.h>
+
+#include <qimage.h>
+
+Test::Test()
+ : KParts::MainWindow( 0, "KView Viewer Test" ),
+ m_part( 0 )
+{
+ m_part = KParts::ComponentFactory::createPartInstanceFromQuery<KParts::ReadWritePart>(
+ "image/jpeg", "Name == 'Image Viewer Part'", this, 0, this );
+ if( m_part )
+ {
+ setCentralWidget( m_part->widget() );
+ createGUI( m_part );
+ }
+ else
+ {
+ KMessageBox::error(this, "Could not find our Part!");
+ kapp->quit();
+ }
+}
+
+Test::~Test()
+{
+}
+
+void Test::load(const KURL& url)
+{
+ m_part->openURL( url );
+}
+
+#include "test.moc"
diff --git a/kview/kviewviewer/test/test.h b/kview/kviewviewer/test/test.h
new file mode 100644
index 00000000..82777090
--- /dev/null
+++ b/kview/kviewviewer/test/test.h
@@ -0,0 +1,25 @@
+#ifndef KIMAGEVIEWERTEST_H
+#define KIMAGEVIEWERTEST_H
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <kapplication.h>
+#include <kparts/mainwindow.h>
+
+namespace KParts { class ReadWritePart; }
+
+class Test : public KParts::MainWindow
+{
+ Q_OBJECT
+public:
+ Test();
+ virtual ~Test();
+ void load(const KURL& url);
+
+private:
+ KParts::ReadWritePart * m_part;
+};
+
+#endif // KIMAGEVIEWERTEST_H
diff --git a/kview/main.cpp b/kview/main.cpp
new file mode 100644
index 00000000..e84bc65d
--- /dev/null
+++ b/kview/main.cpp
@@ -0,0 +1,70 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001-2003 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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 "kview.h"
+#include "version.h"
+#include <kapplication.h>
+#include <kaboutdata.h>
+#include <kcmdlineargs.h>
+#include <klocale.h>
+
+static const char description[] = I18N_NOOP( "KDE Image Viewer" );
+
+static KCmdLineOptions options[] =
+{
+ { "+[URL]", I18N_NOOP( "Image to open" ), 0 },
+ KCmdLineLastOption
+};
+
+extern "C" KDE_EXPORT int kdemain( int argc, char ** argv )
+{
+ KAboutData about( "kview", I18N_NOOP( "KView" ),
+ KVIEW_VERSION, description,
+ KAboutData::License_GPL,
+ I18N_NOOP( "(c) 1997-2002, The KView Developers" ) );
+ about.addAuthor( "Matthias Kretz", I18N_NOOP( "Maintainer" ), "kretz@kde.org" );
+ about.addAuthor( "Sirtaj Singh Kang", I18N_NOOP( "started it all" ), "taj@kde.org" );
+ about.addAuthor( "Simon Hausmann", 0, "hausmann@kde.org" );
+ KCmdLineArgs::init( argc, argv, &about );
+ KCmdLineArgs::addCmdLineOptions( options );
+ KApplication app;
+
+ if( app.isRestored() )
+ RESTORE( KView )
+ else
+ {
+ KCmdLineArgs * args = KCmdLineArgs::parsedArgs();
+
+ KView * kview = new KView;
+ kview->show();
+ // only load image in first url - there's no way I can think of
+ // to tell the presenter plugin to add those urls to it's list
+ if( args->count() > 0 )
+ {
+ if( args->url( 0 ) == QString( "-" ) )
+ kview->loadFromStdin();
+ else
+ kview->load( args->url( 0 ) );
+ }
+ args->clear();
+ }
+
+ return app.exec();
+}
+
+// vim:sw=4:ts=4
diff --git a/kview/modules/Makefile.am b/kview/modules/Makefile.am
new file mode 100644
index 00000000..cfd6a400
--- /dev/null
+++ b/kview/modules/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = scanner presenter browser effects
diff --git a/kview/modules/NAMING b/kview/modules/NAMING
new file mode 100644
index 00000000..d70532ad
--- /dev/null
+++ b/kview/modules/NAMING
@@ -0,0 +1,4 @@
+KView plugins
+=============
+Name: kview_<modulename>.la
+LDFLAGS: -module $(KDE_PLUGIN)
diff --git a/kview/modules/README b/kview/modules/README
new file mode 100644
index 00000000..74c229c0
--- /dev/null
+++ b/kview/modules/README
@@ -0,0 +1,52 @@
+How to write a plugin for KView
+===============================
+
+There are two different kinds of plugins for KView that you may write: KPart
+plugins for KView or the KView KPart (KViewViewer).
+
+
+Writing the Plugin
+==================
+
+You have to derive your plugin from KParts::Plugin and install the rc file under
+the directory "data" (KDEDIR/share/apps/ usually)+"instancename/kpartplugins/"
+(where instancename can be either kview or kviewviewer). If you install it under
+kviewviewer the plugin will be loaded for the KPart (meaning it get's loaded in
+e.g. Konqueror). If you install it under kview it only get's loaded when
+starting the KView application.
+
+The parent that is passed on to your plugin will be a KImageViewer::Viewer
+interface (which is also a KParts::ReadWritePart) if you make it a KViewViewer
+plugin, else you'll be passed a pointer to KView (take a look at the template
+plugin to see how to get to the KImageViewer::Viewer interface).
+
+
+Plugin Desktop file
+===================
+
+Now you need to write a .desktop file for your plugin, containing the name,
+a comment, author, email and plugin name.
+
+Here's a start:
+------------------------------------------------------------------------------
+[Desktop Entry]
+Name=Coolplugin
+Comment=This is a very cool plugin doing foo and bar
+Type=Plugin
+
+[X-KDE Plugin Info]
+Author=Matthias Kretz
+Email=kretz@kde.org
+PluginName=kviewcool
+Version=1.0
+------------------------------------------------------------------------------
+
+The "PluginName" entry needs to be the same as the name attribut in your .rc
+file (<kpartplugin name="kviewcool" library="kview_coolplugin">).
+
+
+Examples
+========
+
+There are a few modules already in the original KView sources. Just take a look
+at kdegraphics/kview/modules/*.
diff --git a/kview/modules/browser/Makefile.am b/kview/modules/browser/Makefile.am
new file mode 100644
index 00000000..001eefd0
--- /dev/null
+++ b/kview/modules/browser/Makefile.am
@@ -0,0 +1,15 @@
+INCLUDES = -I$(top_srcdir)/kview $(all_includes)
+
+kde_module_LTLIBRARIES = kview_browserplugin.la
+
+kview_browserplugin_la_SOURCES = kmyfileitemlist.cpp kviewbrowser.cpp
+kview_browserplugin_la_LIBADD = $(LIB_KFILE) $(LIB_KPARTS) -lkdeprint
+kview_browserplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+
+plugdir = $(kde_datadir)/kviewviewer/kpartplugins
+plug_DATA = kviewbrowser.desktop kviewbrowser.rc
+
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp *.h -o $(podir)/kviewbrowserplugin.pot
diff --git a/kview/modules/browser/kmyfileitemlist.cpp b/kview/modules/browser/kmyfileitemlist.cpp
new file mode 100644
index 00000000..534e0876
--- /dev/null
+++ b/kview/modules/browser/kmyfileitemlist.cpp
@@ -0,0 +1,41 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+
+*/
+// $Id$
+
+#include "kmyfileitemlist.h"
+#include <kfileitem.h>
+
+KMyFileItemList::KMyFileItemList() {}
+KMyFileItemList::KMyFileItemList( const QPtrList<KFileItem> & l ) : QPtrList<KFileItem>( l ) {}
+
+KMyFileItemList & KMyFileItemList::operator=( const QPtrList<KFileItem> & l )
+{
+ return (KMyFileItemList &)QPtrList<KFileItem>::operator=( l );
+}
+
+int KMyFileItemList::compareItems( QPtrCollection::Item item1, QPtrCollection::Item item2 )
+{
+ KFileItem * fileitem1 = static_cast<KFileItem *>( item1 );
+ KFileItem * fileitem2 = static_cast<KFileItem *>( item2 );
+ if( fileitem1->name() == fileitem2->name() )
+ return 0;
+ else if( fileitem1->name() > fileitem2->name() )
+ return 1;
+ else
+ return -1;
+}
diff --git a/kview/modules/browser/kmyfileitemlist.h b/kview/modules/browser/kmyfileitemlist.h
new file mode 100644
index 00000000..052fce53
--- /dev/null
+++ b/kview/modules/browser/kmyfileitemlist.h
@@ -0,0 +1,39 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+
+*/
+// $Id$
+
+#ifndef __kmyfileitemlist_h__
+#define __kmyfileitemlist_h__
+
+#include <qptrlist.h>
+class KFileItem;
+
+class KMyFileItemList : public QPtrList<KFileItem>
+{
+ public:
+ KMyFileItemList();
+ KMyFileItemList( const QPtrList<KFileItem> & );
+ KMyFileItemList & operator=( const QPtrList<KFileItem> & );
+
+ protected:
+ virtual int compareItems( QPtrCollection::Item item1, QPtrCollection::Item item2 );
+};
+
+// vim:sw=4:ts=4
+
+#endif
diff --git a/kview/modules/browser/kviewbrowser.cpp b/kview/modules/browser/kviewbrowser.cpp
new file mode 100644
index 00000000..6da318b7
--- /dev/null
+++ b/kview/modules/browser/kviewbrowser.cpp
@@ -0,0 +1,179 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+
+*/
+// $Id$
+
+#include "kviewbrowser.h"
+#include "kmyfileitemlist.h"
+
+#include <qcursor.h>
+
+#include <kdirlister.h>
+#include <kaction.h>
+#include <klocale.h>
+#include <kgenericfactory.h>
+#include <kdebug.h>
+#include <kimageviewer/viewer.h>
+#include <kimageviewer/canvas.h>
+#include <kparts/browserextension.h>
+#include <kapplication.h>
+#include <kimageio.h>
+
+typedef KGenericFactory<KViewBrowser> KViewBrowserFactory;
+K_EXPORT_COMPONENT_FACTORY( kview_browserplugin, KViewBrowserFactory( "kviewbrowserplugin" ) )
+
+KViewBrowser::KViewBrowser( QObject* parent, const char* name, const QStringList & )
+ : Plugin( parent, name )
+ , m_pDirLister( 0 )
+ , m_pFileItemList( 0 )
+ , m_bShowCurrent( false )
+{
+ m_pViewer = static_cast<KImageViewer::Viewer *>( parent );
+ if( m_pViewer )
+ {
+ m_paBack = KStdAction::back ( this, SLOT( slotBack() ), actionCollection(), "previous_image" );
+ m_paBack->setShortcut( SHIFT+Key_Left );
+ m_paForward = KStdAction::forward( this, SLOT( slotForward() ), actionCollection(), "next_image" );
+ m_paForward->setShortcut( SHIFT+Key_Right );
+ m_pExtension = m_pViewer->browserExtension();
+ }
+ else
+ kdWarning( 4630 ) << "no KImageViewer interface found - the browser plugin won't work" << endl;
+}
+
+KViewBrowser::~KViewBrowser()
+{
+ delete m_pDirLister;
+ delete m_pFileItemList;
+}
+
+void KViewBrowser::openURL(const KURL &u)
+{
+ if (m_pViewer)
+ {
+ // Opening new URL resets zoom, so remember it.
+ double oldZoom = m_pViewer->canvas()->zoom();
+ m_pViewer->openURL(u);
+ m_pViewer->canvas()->setZoom(oldZoom);
+ }
+ if( m_pExtension )
+ {
+ emit m_pExtension->setLocationBarURL( u.prettyURL() );
+ }
+}
+
+void KViewBrowser::slotBack()
+{
+ setupDirLister();
+ if( ! m_pFileItemList )
+ return;
+
+ KFileItem * item = m_pFileItemList->prev();
+ if( ! item )
+ item = m_pFileItemList->last();
+ if( item )
+ {
+ kdDebug( 4630 ) << item->url().prettyURL() << endl;
+ openURL( item->url() );
+ }
+ else
+ kdDebug( 4630 ) << "no file found" << endl;
+ m_bShowCurrent = false;
+}
+
+void KViewBrowser::slotForward()
+{
+ setupDirLister();
+ if( ! m_pFileItemList )
+ return;
+
+ KFileItem * item = m_bShowCurrent ? m_pFileItemList->current() : m_pFileItemList->next();
+ if( ! item )
+ item = m_pFileItemList->first();
+ if( item )
+ {
+ kdDebug( 4630 ) << item->url().prettyURL() << endl;
+ openURL( item->url() );
+ }
+ else
+ kdDebug( 4630 ) << "no file found" << endl;
+ m_bShowCurrent = false;
+}
+
+void KViewBrowser::slotNewItems( const KFileItemList & items )
+{
+ kdDebug( 4630 ) << k_funcinfo << endl;
+ delete m_pFileItemList;
+ m_pFileItemList = new KMyFileItemList( items );
+ m_pFileItemList->sort();
+
+ // set the current pointer on the currently open image
+ KFileItem * item = m_pFileItemList->first();
+ for( ; item; item = m_pFileItemList->next() )
+ if( item->url() == m_pViewer->url() )
+ break;
+}
+
+void KViewBrowser::slotDeleteItem( KFileItem * item )
+{
+ bool setToFirst = false;
+ if( m_pFileItemList->current() == item )
+ {
+ // The current image is being removed
+ // we have to take care, that the next slotForward call returns the new current item
+ m_bShowCurrent = true;
+
+ if( m_pFileItemList->getLast() == item )
+ // The the current image is the last image - wrap around to the first
+ setToFirst = true;
+ }
+
+ m_pFileItemList->remove( item );
+
+ if( setToFirst )
+ ( void )m_pFileItemList->first();
+}
+
+void KViewBrowser::setupDirLister()
+{
+ if( ! m_pDirLister )
+ {
+ kdDebug( 4630 ) << "create new KDirLister" << endl;
+ m_pDirLister = new KDirLister();
+ m_pDirLister->setMimeFilter( KImageIO::mimeTypes( KImageIO::Reading ) );
+ m_pDirLister->setShowingDotFiles( true );
+ connect( m_pDirLister, SIGNAL( newItems( const KFileItemList & ) ), SLOT( slotNewItems( const KFileItemList & ) ) );
+ connect( m_pDirLister, SIGNAL( deleteItem( KFileItem * ) ), SLOT( slotDeleteItem( KFileItem * ) ) );
+ }
+ if( m_pDirLister->url() != KURL( m_pViewer->url().directory( true, false ) ) )
+ {
+ QApplication::setOverrideCursor( WaitCursor );
+ QString url = m_pViewer->url().prettyURL();
+ int pos = url.findRev( "/" );
+ url = url.left( (unsigned int)pos );
+ kdDebug( 4630 ) << "open KDirLister for " << url << endl;
+ m_pDirLister->openURL( KURL( url ));
+ while( ! m_pDirLister->isFinished() )
+ kapp->processEvents();
+ //while( ! m_pFileItemList )
+ //kapp->processEvents();
+ QApplication::restoreOverrideCursor();
+ }
+}
+
+// vim:sw=4:ts=4:cindent
+#include "kviewbrowser.moc"
diff --git a/kview/modules/browser/kviewbrowser.desktop b/kview/modules/browser/kviewbrowser.desktop
new file mode 100644
index 00000000..a5b66bcc
--- /dev/null
+++ b/kview/modules/browser/kviewbrowser.desktop
@@ -0,0 +1,130 @@
+[Desktop Entry]
+Icon=browser
+Type=Service
+ServiceTypes=KPluginInfo
+
+X-KDE-PluginInfo-Author=Matthias Kretz
+X-KDE-PluginInfo-Email=kretz@kde.org
+X-KDE-PluginInfo-Name=kviewbrowser
+X-KDE-PluginInfo-Category=General
+X-KDE-PluginInfo-Version=1.0
+X-KDE-PluginInfo-License=GPL
+X-KDE-PluginInfo-EnabledByDefault=true
+
+Name=Browser
+Name[af]=Blaaier
+Name[ar]=المتصفح
+Name[bg]=Браузър
+Name[br]=Furcher
+Name[bs]=Preglednik
+Name[ca]=Fullejador
+Name[cs]=Prohlížeč
+Name[cy]=Porydd
+Name[el]=Περιηγητής
+Name[eo]=Trair-Rigardilo
+Name[es]=Navegador
+Name[et]=Sirvija
+Name[eu]=Nabegatzailea
+Name[fa]=مرورگر
+Name[fi]=Selain
+Name[fr]=Navigateur
+Name[ga]=Brabhsálaí
+Name[gl]=Explorador
+Name[he]=דפדפן
+Name[hi]=ब्राउज़र
+Name[hr]=Preglednik
+Name[hu]=Böngésző
+Name[is]=Flakkari
+Name[ja]=ブラウザ
+Name[kk]=Шолғыш
+Name[km]=កម្មវិធី​រុករក
+Name[lt]=Naršyklė
+Name[ms]=Pelayar
+Name[nb]=Leser
+Name[nds]=Kieker
+Name[ne]=ब्राउजर
+Name[nl]=Bladeren
+Name[nn]=Snøgglesar
+Name[nso]=Seinyakisi
+Name[pa]=ਝਲਕਾਰਾ
+Name[pl]=Przeglądarka
+Name[pt]=Navegador
+Name[pt_BR]=Navegador
+Name[ro]=Navigator
+Name[ru]=Просмотр
+Name[se]=Bláđđejeaddji
+Name[sk]=Prehliadač
+Name[sl]=Brskalnik
+Name[sr]=Прегледач
+Name[sr@Latn]=Pregledač
+Name[sv]=Bläddrare
+Name[ta]=உலாவி
+Name[tg]=Воқеъанигор
+Name[tr]=Tarayıcı
+Name[uk]=Навігатор
+Name[uz]=Brauzer
+Name[uz@cyrillic]=Браузер
+Name[ven]=Burausa
+Name[wa]=Foyteuse
+Name[xh]=Umkhangeli wencwadi
+Name[zh_CN]=浏览器
+Name[zh_HK]=瀏覽器
+Name[zh_TW]=瀏覽器
+Name[zu]=Umcingi
+Comment=Enables you to browse through all of the images in the current directory.
+Comment[af]=Aktiveer jy na blaai deur alle van die beelde in die huidige gids.
+Comment[ar]=يمكنك من تصفَح كل الصور في الدليل الحالي.
+Comment[bg]=Преглед на изображенията в текущата директория
+Comment[bs]=Omogućuje vam da pregledate sve slike u trenutnom direktoriju.
+Comment[ca]=Us permet navegar entre totes les imatges del directori actual.
+Comment[cs]=Umožňuje procházet všechny obrázky v aktuálním adresáři.
+Comment[cy]=Alluogi i chi bori drwy pob delwedd yn y cyfeiriadur cyfredol.
+Comment[da]=Lader dig gennemse alle billederne i denne mappe.
+Comment[de]=Ermöglicht das Durchsehen der Bilder im aktuellen Ordner.
+Comment[el]=Σας επιτρέπει να περιηγηθείτε σε όλες τις εικόνες στον τρέχον κατάλογο.
+Comment[eo]=Permesas al vi povas trarigardi ĉiujn bildojn en la nuna dosierujo.
+Comment[es]=Le permite navegar por todas las imágenes del directorio actual.
+Comment[et]=Võimaldab sirvida aktiivse kataloogi kõiki pilte.
+Comment[eu]=Uneko direktorioko irudien artean nabigatzen uzten dizu.
+Comment[fa]=برای مرور تمام تصاویر موجود در فهرست راهنمای جاری شما را توانا می‌کند.
+Comment[fi]=Mahdollistaa nykyisessä kansiossa olevien kuvien selailun
+Comment[fr]=Permet de naviguer parmi les images dans le dossier courant.
+Comment[gl]=Permítelle navegar a través de todas as imaxes no directorio actual.
+Comment[he]=מאפשר לך לעיין בכל התמונות שבספריה הנוכחית
+Comment[hi]=मौज़ूदा डिरेक्ट्री के सभी छवियों को ब्राउज़ करने में आपको सक्षम बनाता है.
+Comment[hu]=Lehetővé teszi az aktuális könyvtárban található képek áttekintését, böngészését.
+Comment[is]=Gerir þér kleyft að flakka í öllum myndunum í þessari möppu.
+Comment[it]=Permette di navigare tra le immagini nella directory corrente.
+Comment[ja]=現在のディレクトリのすべての画像をブラウズできるようになります。
+Comment[kk]=Назардағы қапшықтағы барлық кескіндерді шолу құралы.
+Comment[km]=អាច​ឲ្យ​អ្នក​រកមើល​រូបភាព​ទាំងអស់ នៅ​ក្នុង​ថត​បច្ចុប្បន្ន ។
+Comment[lt]=Leidžia jums naršyti visuose paveikslėliuose esamame aplanke.
+Comment[ms]=Membolehkan anda melayar semua imej dalam direktori semasa.
+Comment[nb]=Lar deg bla gjennom alle bildene i den gjeldende katalogen.
+Comment[nds]=Dörkieken vun all Biller binnen den aktuellen Orner.
+Comment[ne]=हालको डाइरेक्टरिमा छविको सबै तिर ब्राउज गर्न तपाईँलाई सक्षम पार्दछ ।
+Comment[nl]=Hiermee kunt u door alle afbeeldingen in de huidige map bladeren.
+Comment[nn]=Let deg bla gjennom alle bileta i ein katalog.
+Comment[nso]=Ego dumelela go inyakisa kago diponagalo kamoka kago tshupetso ya bjale.
+Comment[pl]=Pozwala na przeglądanie wszystkich obrazków w bieżącym katalogu.
+Comment[pt]=Permite-lhe navegar por todas as imagens na directoria actual.
+Comment[pt_BR]=Habilita você a navegar por todas as imagens no diretório atual.
+Comment[ro]=Vă permite să navigaţi prin toate imaginile din directorul curent.
+Comment[ru]=Просмотр всех изображений в текущей папке.
+Comment[se]=Diktá du bláđđet buot govaid čađa dán ozus.
+Comment[sk]=Umožňuje prechádzať mezi obrázkami v aktuálnom priečinku.
+Comment[sl]=Omogoča vam brskanje po vseh slikah v trenutni mapi.
+Comment[sr]=Омогућава вам да прегледате све слике у текућем директоријуму
+Comment[sr@Latn]=Omogućava vam da pregledate sve slike u tekućem direktorijumu
+Comment[sv]=Låter dig bläddra igenom alla bilder i den aktuella katalogen.
+Comment[ta]=நடப்பு அடைவில் உள்ள பிம்பங்களை எல்லாம் பார்க்க முடியும்.
+Comment[tg]=Намоиши тамоми тасвирот дар каталоги ҷорӣ.
+Comment[tr]=Bulunduğunuz dizindeki tüm resimler arasında gezinmenizi sağlar.
+Comment[uk]=Дозволяє навігацію всіх зображень в поточному каталозі.
+Comment[ven]=Ini konisa u tshimbidza kha zwifanyiso zwothe kha tsumbavhulwo ya zwino.
+Comment[wa]=Vos permete di foyter dins totes les imådjes do ridant do moumint.
+Comment[xh]=Ikuvumela ukuba ukwazi ukukhangela yonke imifanekiso kulawulo lwangoku.
+Comment[zh_CN]=使您能够浏览当前目录中的所有图像。
+Comment[zh_HK]=讓您瀏覽當前目錄的所有圖像。
+Comment[zh_TW]=讓您瀏覽目前目錄的所有影像。
+Comment[zu]=Ikuvumela ukuba ucinge ngokwedlulela izithombe ohlwini lwamafayela lwamanje.
diff --git a/kview/modules/browser/kviewbrowser.h b/kview/modules/browser/kviewbrowser.h
new file mode 100644
index 00000000..3ed918b6
--- /dev/null
+++ b/kview/modules/browser/kviewbrowser.h
@@ -0,0 +1,62 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+
+*/
+// $Id$
+
+#ifndef __kviewbrowser_h
+#define __kviewbrowser_h
+
+#include <kparts/plugin.h>
+#include <kfileitem.h>
+
+namespace KImageViewer { class Viewer; }
+
+namespace KParts { class BrowserExtension; }
+class KAction;
+class KDirLister;
+class KMyFileItemList;
+
+class KViewBrowser : public KParts::Plugin
+{
+ Q_OBJECT
+public:
+ KViewBrowser( QObject* parent, const char* name, const QStringList & );
+ virtual ~KViewBrowser();
+
+private slots:
+ void slotBack();
+ void slotForward();
+
+ void slotNewItems( const KFileItemList & );
+ void slotDeleteItem( KFileItem * item );
+
+private:
+ void setupDirLister();
+ void openURL(const KURL &);
+
+ KImageViewer::Viewer * m_pViewer;
+ KDirLister * m_pDirLister;
+ KMyFileItemList * m_pFileItemList;
+ KParts::BrowserExtension * m_pExtension;
+ bool m_bShowCurrent;
+
+ KAction * m_paBack;
+ KAction * m_paForward;
+};
+
+// vim:sw=4:ts=4:cindent
+#endif
diff --git a/kview/modules/browser/kviewbrowser.rc b/kview/modules/browser/kviewbrowser.rc
new file mode 100644
index 00000000..9a57cabb
--- /dev/null
+++ b/kview/modules/browser/kviewbrowser.rc
@@ -0,0 +1,18 @@
+<!DOCTYPE kpartgui>
+<kpartplugin name="kviewbrowser" library="kview_browserplugin">
+ <MenuBar>
+ <Menu name="tools"><Text>&amp;Tools</Text>
+ <Action name="previous_image"/>
+ <Action name="next_image"/>
+ </Menu>
+ </MenuBar>
+ <ToolBar name="extraToolBar">
+ <text>Extra Toolbar</text>
+ <Action name="previous_image"/>
+ <Action name="next_image"/>
+ </ToolBar>
+ <Menu name="popupmenu">
+ <Action name="previous_image"/>
+ <Action name="next_image"/>
+ </Menu>
+</kpartplugin>
diff --git a/kview/modules/effects/Makefile.am b/kview/modules/effects/Makefile.am
new file mode 100644
index 00000000..64205856
--- /dev/null
+++ b/kview/modules/effects/Makefile.am
@@ -0,0 +1,15 @@
+INCLUDES = -I$(top_srcdir)/kview $(all_includes)
+
+kde_module_LTLIBRARIES = kview_effectsplugin.la
+
+kview_effectsplugin_la_SOURCES = kvieweffects.cpp
+kview_effectsplugin_la_LIBADD = $(LIB_KFILE) $(LIB_KPARTS) -lkdeprint
+kview_effectsplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+
+plugdir = $(kde_datadir)/kview/kpartplugins
+plug_DATA = kvieweffects.desktop kvieweffects.rc
+
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp *.h -o $(podir)/kvieweffectsplugin.pot
diff --git a/kview/modules/effects/kvieweffects.cpp b/kview/modules/effects/kvieweffects.cpp
new file mode 100644
index 00000000..9295c876
--- /dev/null
+++ b/kview/modules/effects/kvieweffects.cpp
@@ -0,0 +1,244 @@
+/* This file is in the public domain */
+
+// $Id$
+
+#include "kvieweffects.h"
+
+#include <qobjectlist.h>
+
+#include <kaction.h>
+#include <klocale.h>
+#include <kgenericfactory.h>
+#include <kdebug.h>
+#include <kimageviewer/viewer.h>
+#include <kimageviewer/canvas.h>
+#include <kdialogbase.h>
+#include <knuminput.h>
+#include <kiconeffect.h>
+#include <qvbox.h>
+#include <kcolorbutton.h>
+#include <kimageeffect.h>
+#include <qlabel.h>
+#include <assert.h>
+
+typedef KGenericFactory<KViewEffects> KViewEffectsFactory;
+K_EXPORT_COMPONENT_FACTORY( kview_effectsplugin, KViewEffectsFactory( "kvieweffectsplugin" ) )
+
+KViewEffects::KViewEffects( QObject* parent, const char* name, const QStringList & )
+ : Plugin( parent, name )
+ , m_gamma( 0.5 ), m_lastgamma( -1.0 )
+ , m_opacity( 50 ), m_lastopacity( -1 )
+ , m_intensity( 50 ), m_lastintensity( -1 )
+ , m_color( white )
+ , m_image( 0 )
+{
+ QObjectList * viewerList = parent->queryList( 0, "KImageViewer Part", false, false );
+ m_pViewer = static_cast<KImageViewer::Viewer *>( viewerList->getFirst() );
+ delete viewerList;
+ if( m_pViewer )
+ {
+ KAction * gammaaction = new KAction( i18n( "&Gamma Correction..." ), 0, 0,
+ this, SLOT( gamma() ),
+ actionCollection(), "plugin_effects_gamma" );
+ KAction * blendaction = new KAction( i18n( "&Blend Color..." ), 0, 0,
+ this, SLOT( blend() ),
+ actionCollection(), "plugin_effects_blend" );
+ KAction * intensityaction = new KAction( i18n( "Change &Intensity (Brightness)..." ), 0, 0,
+ this, SLOT( intensity() ),
+ actionCollection(), "plugin_effects_intensity" );
+ gammaaction->setEnabled( m_pViewer->canvas()->image() != 0 );
+ blendaction->setEnabled( m_pViewer->canvas()->image() != 0 );
+ intensityaction->setEnabled( m_pViewer->canvas()->image() != 0 );
+ connect( m_pViewer->widget(), SIGNAL( hasImage( bool ) ), gammaaction, SLOT( setEnabled( bool ) ) );
+ connect( m_pViewer->widget(), SIGNAL( hasImage( bool ) ), blendaction, SLOT( setEnabled( bool ) ) );
+ connect( m_pViewer->widget(), SIGNAL( hasImage( bool ) ), intensityaction, SLOT( setEnabled( bool ) ) );
+ }
+ else
+ kdWarning( 4630 ) << "no KImageViewer interface found - the effects plugin won't work" << endl;
+}
+
+KViewEffects::~KViewEffects()
+{
+ // no need to delete m_image here since it will always be NULL at this
+ // point.
+ assert( m_image == 0 );
+}
+
+void KViewEffects::intensity()
+{
+ KDialogBase dlg( m_pViewer->widget(), "Intensity Dialog", true /*modal*/, i18n( "Change Intensity" ), KDialogBase::Ok | KDialogBase::Try | KDialogBase::Cancel );
+ connect( &dlg, SIGNAL( tryClicked() ), this, SLOT( applyIntensity() ) );
+
+ QVBox * vbox = new QVBox( &dlg );
+ vbox->setSpacing( KDialog::spacingHint() );
+ dlg.setMainWidget( vbox );
+ KIntNumInput * percent = new KIntNumInput( vbox, "Intensity Input" );
+ percent->setRange( 0, 100, 1, true );
+ percent->setValue( m_intensity );
+ percent->setLabel( i18n( "&Intensity:" ) );
+ percent->setSuffix( QString::fromAscii( "%" ) );
+ connect( percent, SIGNAL( valueChanged( int ) ), this, SLOT( setIntensity( int ) ) );
+
+ int result = dlg.exec();
+ if( result == QDialog::Accepted )
+ {
+ applyIntensity();
+ m_pViewer->setModified( true );
+ }
+ else
+ if( m_image )
+ m_pViewer->canvas()->setImage( *m_image );
+ m_lastintensity = -1;
+ delete m_image;
+ m_image = 0;
+}
+
+void KViewEffects::setIntensity( int intensity )
+{
+ m_intensity = intensity;
+}
+
+void KViewEffects::applyIntensity()
+{
+ kdDebug( 4630 ) << k_funcinfo << endl;
+ if( m_intensity == m_lastintensity )
+ return; // nothing to do
+
+ QImage * work = workImage();
+ if( work )
+ {
+ KImageEffect::intensity( *work, m_intensity * 0.01 );
+ m_pViewer->canvas()->setImage( *work );
+ delete work;
+ m_lastintensity = m_intensity;
+ }
+}
+
+void KViewEffects::blend()
+{
+ KDialogBase dlg( m_pViewer->widget(), "Blend Color Dialog", true /*modal*/, i18n( "Blend Color" ), KDialogBase::Ok | KDialogBase::Try | KDialogBase::Cancel );
+ connect( &dlg, SIGNAL( tryClicked() ), this, SLOT( applyBlend() ) );
+
+ QVBox * vbox = new QVBox( &dlg );
+ vbox->setSpacing( KDialog::spacingHint() );
+ dlg.setMainWidget( vbox );
+ KIntNumInput * opacity = new KIntNumInput( vbox, "Opacity Input" );
+ opacity->setRange( 0, 100, 1, true );
+ opacity->setValue( m_opacity );
+ opacity->setLabel( i18n( "O&pacity:" ) );
+ opacity->setSuffix( QString::fromAscii( "%" ) );
+ connect( opacity, SIGNAL( valueChanged( int ) ), this, SLOT( setOpacity( int ) ) );
+ QLabel * label = new QLabel( i18n( "Blend c&olor:" ), vbox );
+ KColorButton * color = new KColorButton( m_color, vbox, "Color Input Button" );
+ label->setBuddy( color );
+ connect( color, SIGNAL( changed( const QColor & ) ), this, SLOT( setColor( const QColor & ) ) );
+
+ int result = dlg.exec();
+ if( result == QDialog::Accepted )
+ {
+ applyBlend();
+ m_pViewer->setModified( true );
+ }
+ else
+ if( m_image )
+ m_pViewer->canvas()->setImage( *m_image );
+ m_lastopacity = -1;
+ delete m_image;
+ m_image = 0;
+}
+
+void KViewEffects::setOpacity( int opacity )
+{
+ m_opacity = opacity;
+}
+
+void KViewEffects::setColor( const QColor & color )
+{
+ m_color = color;
+}
+
+void KViewEffects::applyBlend()
+{
+ if( m_opacity == m_lastopacity )
+ return; // nothing to do
+
+ QImage * work = workImage();
+ if( work )
+ {
+ KImageEffect::blend( m_color, *work, m_opacity * 0.01 );
+ m_pViewer->canvas()->setImage( *work );
+ delete work;
+ m_lastopacity = m_opacity;
+ }
+}
+
+void KViewEffects::gamma()
+{
+ KDialogBase dlg( m_pViewer->widget(), "Gamma Correction Dialog", true /*modal*/, i18n( "Gamma Correction" ), KDialogBase::Ok | KDialogBase::Try | KDialogBase::Cancel );
+ connect( &dlg, SIGNAL( tryClicked() ), this, SLOT( applyGammaCorrection() ) );
+
+ // create dialog
+ KDoubleNumInput * gammavalue = new KDoubleNumInput( 0.0, 1.0, 0.5, 0.01, 4, &dlg, "Gamma value input" );
+ gammavalue->setRange( 0.0, 1.0, 0.01, true );
+ connect( gammavalue, SIGNAL( valueChanged( double ) ), this, SLOT( setGammaValue( double ) ) );
+ gammavalue->setLabel( i18n( "Gamma value:" ) );
+ dlg.setMainWidget( gammavalue );
+
+ int result = dlg.exec();
+ if( result == QDialog::Accepted )
+ {
+ // apply gamma correction
+ applyGammaCorrection();
+ m_pViewer->setModified( true );
+ }
+ else
+ {
+ if( m_image )
+ m_pViewer->canvas()->setImage( *m_image );
+ }
+ m_lastgamma = -1;
+ delete m_image;
+ m_image = 0;
+}
+
+void KViewEffects::setGammaValue( double gamma )
+{
+ m_gamma = gamma;
+ kdDebug( 4630 ) << "m_gamma = " << m_gamma << endl;
+ // TODO: show effect on the fly if requested
+}
+
+void KViewEffects::applyGammaCorrection()
+{
+ if( m_gamma == m_lastgamma )
+ return; // nothing to do
+
+ QImage * corrected = workImage();
+ if( corrected )
+ {
+ KIconEffect::toGamma( *corrected, m_gamma );
+ m_pViewer->canvas()->setImage( *corrected );
+ delete corrected;
+ m_lastgamma = m_gamma;
+ }
+}
+
+inline QImage * KViewEffects::workImage()
+{
+ if( ! m_image )
+ {
+ const QImage * canvasimage = m_pViewer->canvas()->image();
+ if( canvasimage )
+ m_image = new QImage( *canvasimage );
+ }
+ if( m_image )
+ {
+ QImage * changed = new QImage( *m_image );
+ changed->detach();
+ return changed;
+ }
+ return 0;
+}
+
+// vim:sw=4:ts=4:cindent
+#include "kvieweffects.moc"
diff --git a/kview/modules/effects/kvieweffects.desktop b/kview/modules/effects/kvieweffects.desktop
new file mode 100644
index 00000000..1f13781d
--- /dev/null
+++ b/kview/modules/effects/kvieweffects.desktop
@@ -0,0 +1,119 @@
+[Desktop Entry]
+Icon=effects
+Type=Service
+ServiceTypes=KPluginInfo
+
+X-KDE-PluginInfo-Author=Matthias Kretz
+X-KDE-PluginInfo-Email=kretz@kde.org
+X-KDE-PluginInfo-Name=kvieweffects
+X-KDE-PluginInfo-Version=0.1
+X-KDE-PluginInfo-License=GPL
+X-KDE-PluginInfo-EnabledByDefault=false
+
+Name=Effects
+Name[ar]=مؤثرات
+Name[bg]=Ефекти
+Name[bs]=Efekti
+Name[ca]=Efectes
+Name[cs]=Efekty
+Name[cy]=Effeithiau
+Name[da]=Effekter
+Name[de]=Effekte
+Name[el]=Εφέ
+Name[eo]=Efektoj
+Name[es]=Efectos
+Name[et]=Efektid
+Name[eu]=Efectuak
+Name[fa]=اثرها
+Name[fi]=Tehosteet
+Name[fr]=Effets
+Name[ga]=Maisíochtaí
+Name[gl]=Efectos
+Name[he]=אפקטים
+Name[hi]=प्रभाव
+Name[hu]=Effektusok
+Name[is]=Brellur
+Name[it]=Effetti
+Name[ja]=効果
+Name[kk]=Эффекттері
+Name[km]=បែបផែន
+Name[lt]=Efektai
+Name[ms]=Kesan
+Name[nb]=Effekter
+Name[nds]=Effekten
+Name[ne]=असर
+Name[nl]=Effecten
+Name[nn]=Effektar
+Name[pa]=ਪ੍ਰਭਾਵ
+Name[pl]=Efekty
+Name[pt]=Efeitos
+Name[pt_BR]=Efeitos
+Name[ro]=Efecte
+Name[ru]=Эффекты
+Name[sk]=Efekty
+Name[sl]=Učinki
+Name[sr]=Ефекти
+Name[sr@Latn]=Efekti
+Name[sv]=Effekter
+Name[ta]=விளைவுகள்
+Name[tg]=Воситаҳо
+Name[tr]=Efektler
+Name[uk]=Ефекти
+Name[uz]=Effektlar
+Name[uz@cyrillic]=Эффектлар
+Name[wa]=Efets
+Name[zh_CN]=特效
+Name[zh_HK]=效果
+Name[zh_TW]=特效
+Comment=Provides some image effects
+Comment[ar]=يقدم بعض مؤثرات الصور
+Comment[bg]=Визуални ефекти при зареждане на изображенията
+Comment[bs]=Pruža neke efekte za slike
+Comment[ca]=Proporciona alguns efectes d'imatges
+Comment[cs]=Poskytuje několik efektů pro obrázky
+Comment[cy]=Darparu rhai effeithiau delwedd
+Comment[da]=Sørger for nogle billedeffekter
+Comment[de]=Stellt einige Bildverarbeitungseffekte zur Verfügung
+Comment[el]=Παρέχει μερικά εφέ εικόνας
+Comment[eo]=Provizas kelkajn bildefektojn
+Comment[es]=Proporciona alguno efectos para imágenes
+Comment[et]=Mõned pildiefektid
+Comment[eu]=Irudi efektu batzuk eskuratzen ditu
+Comment[fa]=برخی اثرهای تصویر را فراهم می‌کند
+Comment[fi]=Tarjoaa joitain kuvatehosteita
+Comment[fr]=Fournit des effets sur les images
+Comment[gl]=Proporciona algúns efectos para as imaxes
+Comment[he]=מספק מספר אפקטים עבור תמונות
+Comment[hi]=छवि में प्रभाव उत्पन्न करता है
+Comment[hu]=Képeffektusok használata
+Comment[is]=Býður uppá ýmsar myndbrellur
+Comment[it]=Fornisce alcuni effetti per le immagini
+Comment[ja]=画像効果を提供します
+Comment[kk]=Кескіндердің кейбір эффектерін іске асыру
+Comment[km]=ផ្ដល់​នូវ​បែបផែន​រូបភាព​មួយ​ចំនួន
+Comment[lt]=Prideda kai kuriuos paveikslėlių efektus
+Comment[ms]=Menyediakan beberapa kesan imej
+Comment[nb]=Utfører noen effekter på bilder
+Comment[nds]=Stellt en poor Bildeffekten praat
+Comment[ne]=केही छवि असर प्रदान गर्दछ
+Comment[nl]=Biedt enkele effecten om afbeeldingen te bewerken
+Comment[nn]=Utfører nokre effektar på bilete
+Comment[pl]=Dodaje kilka efektów do obrazków
+Comment[pt]=Fornece alguns efeitos de imagem
+Comment[pt_BR]=Fornece alguns efeitos de imagem
+Comment[ro]=Oferă unele efecte pentru imagini
+Comment[ru]=Некоторые эффекты обработки изображений
+Comment[sk]=Poskytuje niektoré efekty pre obrázky
+Comment[sl]=Prinaša nekaj učinkov za slike
+Comment[sr]=Пружа неке сликовне ефекте
+Comment[sr@Latn]=Pruža neke slikovne efekte
+Comment[sv]=Tillhandahåller vissa bildeffekter
+Comment[ta]=சில பிம்ப விளைவுகளை தருகிறது
+Comment[tg]=Якчанд воситаҳои коркарди тасвирот
+Comment[tr]=Resim efektleri oluşturur
+Comment[uk]=Надає деякі ефекти зображень
+Comment[uz]=Rasm effektlari
+Comment[uz@cyrillic]=Расм эффектлари
+Comment[zh_CN]=提供某些图像特效
+Comment[zh_HK]=提供一些圖像效果
+Comment[zh_TW]=提供影像特效
diff --git a/kview/modules/effects/kvieweffects.h b/kview/modules/effects/kvieweffects.h
new file mode 100644
index 00000000..0bf92a8e
--- /dev/null
+++ b/kview/modules/effects/kvieweffects.h
@@ -0,0 +1,46 @@
+/* This file is in the public domain */
+
+// $Id$
+
+#ifndef KVIEWEFFECTS_H
+#define KVIEWEFFECTS_H
+
+#include <kparts/plugin.h>
+#include <qcolor.h>
+
+namespace KImageViewer { class Viewer; }
+
+class KViewEffects : public KParts::Plugin
+{
+ Q_OBJECT
+public:
+ KViewEffects( QObject* parent, const char* name, const QStringList & );
+ virtual ~KViewEffects();
+
+private slots:
+ void intensity();
+ void setIntensity( int );
+ void applyIntensity();
+
+ void blend();
+ void setOpacity( int );
+ void setColor( const QColor & );
+ void applyBlend();
+
+ void gamma();
+ void setGammaValue( double );
+ void applyGammaCorrection();
+
+private:
+ QImage * workImage();
+
+ KImageViewer::Viewer * m_pViewer;
+ double m_gamma, m_lastgamma;
+ int m_opacity, m_lastopacity;
+ int m_intensity, m_lastintensity;
+ QColor m_color;
+ QImage * m_image;
+};
+
+// vim:sw=4:ts=4:cindent
+#endif // KVIEWEFFECTS_H
diff --git a/kview/modules/effects/kvieweffects.rc b/kview/modules/effects/kvieweffects.rc
new file mode 100644
index 00000000..d0c4eda6
--- /dev/null
+++ b/kview/modules/effects/kvieweffects.rc
@@ -0,0 +1,10 @@
+<!DOCTYPE kpartgui>
+<kpartplugin name="kvieweffects" library="kview_effectsplugin" version="2">
+ <MenuBar>
+ <Menu name="effects"><Text>Effe&amp;cts</Text>
+ <Action name="plugin_effects_gamma"/>
+ <Action name="plugin_effects_blend"/>
+ <Action name="plugin_effects_intensity"/>
+ </Menu>
+ </MenuBar>
+</kpartplugin>
diff --git a/kview/modules/presenter/DESIGN b/kview/modules/presenter/DESIGN
new file mode 100644
index 00000000..11d77121
--- /dev/null
+++ b/kview/modules/presenter/DESIGN
@@ -0,0 +1,42 @@
+Presenter Plugin:
+- Features:
+ - a playlist with image infos:
+ - possibly get info from KFileMetaInfo
+ - image infos are readable for the user
+ - image infos for the program
+ - keeps track of images that were opened
+ - new action to load multiple files into the 'playlist'
+ - shuffle functions:
+ - shuffle the playlist
+ - load a random picture from the list (don't show the same image
+ again, though)
+ - order the items in the list via DnD
+ - order items alphabetically
+ - slideshow:
+ - configurable interval between images (in msecs)
+ - blending effects (put those effects in the imagecanvas)
+ - optionally keep image size <= canvas size
+ - preload next image (optionally)
+
+- Implementation:
+ - Playlist:
+ - KListView
+ - Items:
+ - derived from KListViewItem
+ - load Info in the background
+ - keep local copy of downloaded files
+ - delete local copy on destruction
+ - API:
+ QImage * image();
+ KURL url();
+ QString file(); //returns local filename or QString::null
+ - when loading an item from the playlist first ask for a
+ QImage, if that's not available ask for a local file, if
+ that's also not available take the url.
+ - API:
+ QImage * image();
+ QString file();
+ KURL url();
+ void setRandom(bool);
+ void randomizeList();
+ void orderAlphabetically();
diff --git a/kview/modules/presenter/Makefile.am b/kview/modules/presenter/Makefile.am
new file mode 100644
index 00000000..905bd1fc
--- /dev/null
+++ b/kview/modules/presenter/Makefile.am
@@ -0,0 +1,17 @@
+SUBDIRS = .
+
+INCLUDES = -I$(top_srcdir)/kview $(all_includes)
+
+kde_module_LTLIBRARIES = kview_presenterplugin.la
+
+kview_presenterplugin_la_SOURCES = imagelistitem.cpp imagelistdialog.ui kviewpresenter.cpp
+kview_presenterplugin_la_LIBADD = $(LIB_KIO) $(LIB_KPARTS)
+kview_presenterplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+
+plugdir = $(kde_datadir)/kview/kpartplugins
+plug_DATA = kviewpresenter.desktop kviewpresenter.rc
+
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp *.h -o $(podir)/kviewpresenterplugin.pot
diff --git a/kview/modules/presenter/config/Makefile.am b/kview/modules/presenter/config/Makefile.am
new file mode 100644
index 00000000..8c212e7f
--- /dev/null
+++ b/kview/modules/presenter/config/Makefile.am
@@ -0,0 +1,17 @@
+INCLUDES = $(all_includes)
+
+kde_module_LTLIBRARIES = kcm_kviewpresenterconfig.la
+
+noinst_HEADERS = kviewpresenterconfig.h
+
+kcm_kviewpresenterconfig_la_SOURCES = kviewpresenterconfig.cpp
+kcm_kviewpresenterconfig_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kcm_kviewpresenterconfig_la_LIBADD = $(LIB_KUTILS)
+
+kcm_kviewpresenterconfig_DATA = kviewpresenterconfig.desktop
+kcm_kviewpresenterconfigdir = $(kde_servicesdir)/kconfiguredialog
+
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp *.h -o $(podir)/kcm_kviewpresenterconfig.pot
diff --git a/kview/modules/presenter/config/kviewpresenterconfig.cpp b/kview/modules/presenter/config/kviewpresenterconfig.cpp
new file mode 100644
index 00000000..92dd8627
--- /dev/null
+++ b/kview/modules/presenter/config/kviewpresenterconfig.cpp
@@ -0,0 +1,72 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002-2003 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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 "kviewpresenterconfig.h"
+
+#include <qlayout.h>
+#include <qcheckbox.h>
+#include <qframe.h>
+
+#include <klocale.h>
+#include <kdialog.h>
+#include <kglobal.h>
+#include <kconfig.h>
+#include <kgenericfactory.h>
+
+typedef KGenericFactory<KViewPresenterConfig, QWidget> KViewPresenterConfigFactory;
+K_EXPORT_COMPONENT_FACTORY( kcm_kviewpresenterconfig, KViewPresenterConfigFactory( "kcm_kviewpresenterconfig" ) )
+
+KViewPresenterConfig::KViewPresenterConfig( QWidget * parent, const char *, const QStringList & args )
+ : KCModule( KViewPresenterConfigFactory::instance(), parent, args )
+{
+ QBoxLayout * layout = new QVBoxLayout( this, KDialog::marginHint(), KDialog::spacingHint() );
+ layout->setAutoAdd( true );
+
+ m_pCheckBox = new QCheckBox( "This is only for testing...", this );
+ connect( m_pCheckBox, SIGNAL( clicked() ), this, SLOT( checkChanged() ) );
+}
+
+KViewPresenterConfig::~KViewPresenterConfig()
+{
+}
+
+void KViewPresenterConfig::checkChanged()
+{
+ if( m_pCheckBox->isChecked() )
+ emit changed( true );
+ else
+ emit changed( false );
+}
+
+void KViewPresenterConfig::load()
+{
+ emit changed( false );
+}
+
+void KViewPresenterConfig::save()
+{
+ emit changed( false );
+}
+
+void KViewPresenterConfig::defaults()
+{
+}
+
+// vim:sw=4:ts=4
+
+#include "kviewpresenterconfig.moc"
diff --git a/kview/modules/presenter/config/kviewpresenterconfig.desktop b/kview/modules/presenter/config/kviewpresenterconfig.desktop
new file mode 100644
index 00000000..77bb3481
--- /dev/null
+++ b/kview/modules/presenter/config/kviewpresenterconfig.desktop
@@ -0,0 +1,120 @@
+[Desktop Entry]
+Icon=kpresenter
+Type=Service
+ServiceTypes=KCModule
+
+X-KDE-ModuleType=Library
+X-KDE-Library=kviewpresenterconfig
+X-KDE-FactoryName=KViewPresenterConfigFactory
+X-KDE-ParentComponents=kviewpresenter
+
+Name=Name
+Name[ar]=اسم
+Name[bg]=Име
+Name[br]=Anv
+Name[bs]=Ime
+Name[ca]=Nom
+Name[cy]=Enw
+Name[da]=Navn
+Name[el]=Όνομα
+Name[eo]=Nomo
+Name[es]=Nombre
+Name[et]=Nimi
+Name[eu]=Izena
+Name[fa]=نام
+Name[fi]=Nimi
+Name[fr]=Nom
+Name[ga]=Ainm
+Name[gl]=Nome
+Name[he]=שם
+Name[hi]=नाम
+Name[hu]=Név
+Name[is]=Heiti
+Name[it]=Nome
+Name[ja]=名前
+Name[kk]=Атауы
+Name[km]=ឈ្មោះ
+Name[lt]=Pavadinimas
+Name[ms]=Nama
+Name[nb]=Navn
+Name[nds]=Naam
+Name[ne]=नाम
+Name[nl]=Naam
+Name[nn]=Namn
+Name[pa]=ਨਾਂ
+Name[pl]=Nazwa
+Name[pt]=Nome
+Name[pt_BR]=Nome
+Name[ro]=Nume
+Name[ru]=Имя
+Name[se]=Namma
+Name[sk]=Meno
+Name[sl]=Ime
+Name[sr]=Име
+Name[sr@Latn]=Ime
+Name[sv]=Namn
+Name[ta]=பெயர்
+Name[tg]=Ном
+Name[uk]=Назва
+Name[uz]=Nomi
+Name[uz@cyrillic]=Номи
+Name[wa]=No
+Name[zh_CN]=名称
+Name[zh_HK]=名稱
+Name[zh_TW]=名稱
+Comment=Comment
+Comment[ar]=تعليق
+Comment[bg]=Коментар
+Comment[br]=Askelenn
+Comment[bs]=Komentar
+Comment[ca]=Comentari
+Comment[cy]=Sylwad
+Comment[da]=Kommentar
+Comment[de]=Kommentar
+Comment[el]=Σχόλιο
+Comment[eo]=Komento
+Comment[es]=Comentario
+Comment[et]=Kommentaar
+Comment[eu]=Iruzkina
+Comment[fa]=توضیح
+Comment[fi]=Kommentti
+Comment[fr]=Commentaire
+Comment[ga]=Nóta
+Comment[gl]=Comentario
+Comment[he]=הערה
+Comment[hi]=टिप्पणी
+Comment[hu]=Megjegyzés
+Comment[is]=Athugasemd
+Comment[it]=Commento
+Comment[ja]=コメント
+Comment[kk]=Түсініктемесі
+Comment[km]=សេចក្ដី​អធិប្បាយ
+Comment[lt]=Komentaras
+Comment[ms]=Komen
+Comment[nb]=Kommentar
+Comment[nds]=Kommentar
+Comment[ne]=टिप्पणी
+Comment[nl]=Omschrijving
+Comment[nn]=Kommentar
+Comment[pa]=ਟਿੱਪਣੀ
+Comment[pl]=Komentarz
+Comment[pt]=Comentário
+Comment[pt_BR]=Comentário
+Comment[ro]=Comentariu
+Comment[ru]=Комментарий
+Comment[se]=Kommeanta
+Comment[sk]=Komentár
+Comment[sl]=Komentar
+Comment[sr]=Коментар
+Comment[sr@Latn]=Komentar
+Comment[sv]=Kommentar
+Comment[ta]=குறிப்பு
+Comment[tg]=Эзоҳ
+Comment[tr]=Açıklama
+Comment[uk]=Коментар
+Comment[uz]=Izoh
+Comment[uz@cyrillic]=Изоҳ
+Comment[wa]=Rawete
+Comment[zh_CN]=注释
+Comment[zh_HK]=註解
+Comment[zh_TW]=註解
diff --git a/kview/modules/presenter/config/kviewpresenterconfig.h b/kview/modules/presenter/config/kviewpresenterconfig.h
new file mode 100644
index 00000000..c839690a
--- /dev/null
+++ b/kview/modules/presenter/config/kviewpresenterconfig.h
@@ -0,0 +1,46 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002-2003 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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 KVIEWPRESENTERCONFIG_H
+#define KVIEWPRESENTERCONFIG_H
+
+#include <kcmodule.h>
+
+class QCheckBox;
+
+class KViewPresenterConfig : public KCModule
+{
+ Q_OBJECT
+ public:
+ KViewPresenterConfig( QWidget * parent, const char * name = 0, const QStringList & args = QStringList() );
+ ~KViewPresenterConfig();
+
+ virtual void load();
+ virtual void save();
+ virtual void defaults();
+
+ private slots:
+ void checkChanged();
+
+ private:
+ QCheckBox * m_pCheckBox;
+};
+
+// vim:sw=4:ts=4
+
+#endif // KVIEWPRESENTERCONFIG_H
diff --git a/kview/modules/presenter/imagelistdialog.ui b/kview/modules/presenter/imagelistdialog.ui
new file mode 100644
index 00000000..66d9e9b5
--- /dev/null
+++ b/kview/modules/presenter/imagelistdialog.ui
@@ -0,0 +1,289 @@
+<!DOCTYPE UI><UI version="3.2" stdsetdef="1">
+<class>ImageListDialog</class>
+<author>Matthias Kretz &lt;kretz@kde.org&gt;</author>
+<widget class="KDialog">
+ <property name="name">
+ <cstring>ImageListDialog</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>724</width>
+ <height>409</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Image List</string>
+ </property>
+ <property name="acceptDrops">
+ <bool>true</bool>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KListView">
+ <column>
+ <property name="text">
+ <string>URL</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Size</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Dimensions</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>m_pListView</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>400</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="acceptDrops">
+ <bool>true</bool>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <property name="showSortIndicator">
+ <bool>true</bool>
+ </property>
+ <property name="fullWidth">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout4</cstring>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_pPrevious</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Previous</string>
+ </property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_pNext</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Next</string>
+ </property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_pShuffle</cstring>
+ </property>
+ <property name="text">
+ <string>Shu&amp;ffle</string>
+ </property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_pSlideshow</cstring>
+ </property>
+ <property name="text">
+ <string>Start &amp;Slideshow</string>
+ </property>
+ <property name="toggleButton">
+ <bool>true</bool>
+ </property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="KIntNumInput">
+ <property name="name">
+ <cstring>m_pInterval</cstring>
+ </property>
+ <property name="label">
+ <string>Slideshow interval:</string>
+ </property>
+ <property name="value">
+ <number>5000</number>
+ </property>
+ <property name="suffix">
+ <string> ms</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>This is the interval the program will wait before showing the next image in the slideshow.</string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>MinimumExpanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>80</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_pCloseAll</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Close All</string>
+ </property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>Layout4</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_pSave</cstring>
+ </property>
+ <property name="text">
+ <string>Sa&amp;ve List...</string>
+ </property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="KPushButton">
+ <property name="name">
+ <cstring>m_pLoad</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Load List...</string>
+ </property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+ </widget>
+ </hbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>m_pListView</sender>
+ <signal>aboutToMove()</signal>
+ <receiver>ImageListDialog</receiver>
+ <slot>noSort()</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="global" impldecl="in declaration">kdialog.h</include>
+ <include location="global" impldecl="in implementation">kdebug.h</include>
+ <include location="global" impldecl="in implementation">kimageviewer/viewer.h</include>
+ <include location="global" impldecl="in implementation">kio/netaccess.h</include>
+ <include location="global" impldecl="in implementation">kurl.h</include>
+ <include location="global" impldecl="in implementation">kfiledialog.h</include>
+ <include location="global" impldecl="in implementation">qstring.h</include>
+ <include location="global" impldecl="in implementation">kmessagebox.h</include>
+ <include location="local" impldecl="in implementation">imagelistitem.h</include>
+ <include location="local" impldecl="in implementation">imagelistdialog.ui.h</include>
+</includes>
+<forwards>
+ <forward>class KURL</forward>
+</forwards>
+<slots>
+ <slot access="private" specifier="non virtual">init()</slot>
+ <slot specifier="non virtual">noSort()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/>
+<includehints>
+ <includehint>kdialog.h</includehint>
+ <includehint>klistview.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+ <includehint>kpushbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kview/modules/presenter/imagelistdialog.ui.h b/kview/modules/presenter/imagelistdialog.ui.h
new file mode 100644
index 00000000..ce97754e
--- /dev/null
+++ b/kview/modules/presenter/imagelistdialog.ui.h
@@ -0,0 +1,23 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you wish to add, delete or rename slots use Qt Designer which will
+** update this file, preserving your code. Create an init() slot in place of
+** a constructor, and a destroy() slot in place of a destructor.
+*****************************************************************************/
+
+void ImageListDialog::init()
+{
+ kdDebug( 4630 ) << k_funcinfo << endl;
+ m_pInterval->setRange( 0, 60000, 1000 );
+ noSort();
+}
+
+
+void ImageListDialog::noSort()
+{
+ kdDebug( 4630 ) << k_funcinfo << endl;
+ m_pListView->setSorting( 1000 );
+}
+
+
diff --git a/kview/modules/presenter/imagelistitem.cpp b/kview/modules/presenter/imagelistitem.cpp
new file mode 100644
index 00000000..4236dfe7
--- /dev/null
+++ b/kview/modules/presenter/imagelistitem.cpp
@@ -0,0 +1,82 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+
+*/
+
+// $Id$
+
+#include "imagelistitem.h"
+
+#include <qimage.h>
+
+#include <klistview.h>
+
+ImageListItem::ImageListItem( KListView * parent, const KURL & url )
+ : KListViewItem( parent, parent->lastItem(), url.prettyURL() )
+ , m_pImage( 0 )
+ , m_filename( QString::null )
+ , m_url( url )
+{
+ setDragEnabled( true );
+ if( m_url.isLocalFile() )
+ {
+ m_filename = m_url.path();
+ }
+ else
+ {
+ // download file
+ /*
+ QString extension;
+ QString fileName = m_url.fileName();
+ int extensionPos = fileName.findRev( '.' );
+ if ( extensionPos != -1 )
+ extension = fileName.mid( extensionPos ); // keep the '.'
+ delete m_pTempFile;
+ m_pTempFile = new KTempFile( QString::null, extension );
+ m_filename = m_pTempFile->name();
+
+ m_pJob = KIO::get( m_url, m_pExtension->urlArgs().reload, false );
+ */
+ }
+}
+
+ImageListItem::~ImageListItem()
+{
+ if( ! m_url.isLocalFile() )
+ {
+ // remove downloaded tempfile
+ //KIO::NetAccess::removeTempFile( m_filename );
+ }
+}
+
+const QImage * ImageListItem::image() const
+{
+ return m_pImage;
+}
+
+const QString & ImageListItem::file() const
+{
+ if( m_url.isLocalFile() )
+ return QString::null;
+ return m_filename;
+}
+
+const KURL & ImageListItem::url() const
+{
+ return m_url;
+}
+
+// vim:sw=4:ts=4
diff --git a/kview/modules/presenter/imagelistitem.h b/kview/modules/presenter/imagelistitem.h
new file mode 100644
index 00000000..63761af8
--- /dev/null
+++ b/kview/modules/presenter/imagelistitem.h
@@ -0,0 +1,49 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+
+*/
+
+// $Id$
+
+#ifndef IMAGELISTITEM_H
+#define IMAGELISTITEM_H
+
+#include <klistview.h>
+#include <kurl.h>
+#include <qstring.h>
+
+class QImage;
+
+class ImageListItem : public KListViewItem
+{
+ public:
+ ImageListItem( KListView * parent, const KURL & url );
+ ~ImageListItem();
+
+ const QImage * image() const;
+ const QString & file() const;
+ const KURL & url() const;
+
+ virtual int rtti() const { return 48294; }
+
+ private:
+ QImage * m_pImage;
+ QString m_filename;
+ KURL m_url;
+};
+
+// vim:sw=4:ts=4
+#endif // IMAGELISTITEM_H
diff --git a/kview/modules/presenter/kviewpresenter.cpp b/kview/modules/presenter/kviewpresenter.cpp
new file mode 100644
index 00000000..bbc5e8eb
--- /dev/null
+++ b/kview/modules/presenter/kviewpresenter.cpp
@@ -0,0 +1,492 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+
+*/
+
+/* $Id$ */
+
+#include "kviewpresenter.h"
+#include "imagelistdialog.h"
+#include "imagelistitem.h"
+
+#include <qvbox.h>
+#include <qobjectlist.h>
+#include <qsignalslotimp.h>
+#include <qtimer.h>
+#include <qevent.h>
+#include <qdragobject.h>
+#include <qstringlist.h>
+
+#include <kpushbutton.h>
+#include <kapplication.h>
+#include <kaction.h>
+#include <klocale.h>
+#include <kgenericfactory.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <kiconloader.h>
+#include <knuminput.h>
+#include <kfiledialog.h>
+#include <kimageio.h>
+#include <kimageviewer/viewer.h>
+#include <kimageviewer/canvas.h>
+#include <kio/netaccess.h>
+#include <kmessagebox.h>
+#include <ktempfile.h>
+#include <kurldrag.h>
+
+typedef KGenericFactory<KViewPresenter> KViewPresenterFactory;
+K_EXPORT_COMPONENT_FACTORY( kview_presenterplugin, KViewPresenterFactory( "kviewpresenterplugin" ) )
+
+KViewPresenter::KViewPresenter( QObject* parent, const char* name, const QStringList & )
+ : Plugin( parent, name )
+ , m_pImageList( new ImageListDialog() )
+ , m_paFileOpen( 0 )
+ , m_bDontAdd( false )
+ , m_pCurrentItem( 0 )
+ , m_pSlideshowTimer( new QTimer( this ) )
+{
+ kdDebug( 4630 ) << k_funcinfo << endl;
+ m_imagelist.setAutoDelete( true );
+
+ QObjectList * viewerList = parent->queryList( 0, "KImageViewer Part", false, false );
+ m_pViewer = static_cast<KImageViewer::Viewer *>( viewerList->getFirst() );
+ delete viewerList;
+ if( m_pViewer )
+ {
+ ( void ) new KAction( i18n( "&Image List..." ), 0, 0,
+ this, SLOT( slotImageList() ),
+ actionCollection(), "plugin_presenter_imageList" );
+ m_paSlideshow = new KToggleAction( i18n( "Start &Slideshow" ), Key_S, actionCollection(), "plugin_presenter_slideshow" );
+ ( void ) new KAction( i18n( "&Previous Image in List" ), "previous", ALT+Key_Left,
+ this, SLOT( prev() ),
+ actionCollection(), "plugin_presenter_prev" );
+ ( void ) new KAction( i18n( "&Next Image in List" ), "next", ALT+Key_Right,
+ this, SLOT( next() ),
+ actionCollection(), "plugin_presenter_next" );
+
+ connect( m_paSlideshow, SIGNAL( toggled( bool ) ), m_pImageList->m_pSlideshow, SLOT( setOn( bool ) ) );
+ connect( m_pImageList->m_pSlideshow, SIGNAL( toggled( bool ) ), m_paSlideshow, SLOT( setChecked( bool ) ) );
+
+ // search for file_open action
+ KXMLGUIClient * parentClient = static_cast<KXMLGUIClient*>( parent->qt_cast( "KXMLGUIClient" ) );
+ if( parentClient )
+ {
+ m_paFileOpen = parentClient->actionCollection()->action( "file_open" );
+ m_paFileClose = parentClient->actionCollection()->action( "file_close" );
+ }
+ if( m_paFileClose )
+ connect( m_paFileClose, SIGNAL( activated() ), this, SLOT( slotClose() ) );
+ if( m_paFileOpen )
+ {
+ disconnect( m_paFileOpen, SIGNAL( activated() ), parent, SLOT( slotOpenFile() ) );
+ connect( m_paFileOpen, SIGNAL( activated() ), this, SLOT( slotOpenFiles() ) );
+ }
+ else
+ {
+ (void) new KAction( i18n( "Open &Multiple Files..." ), "queue", CTRL+SHIFT+Key_O,
+ this, SLOT( slotOpenFiles() ),
+ actionCollection(), "plugin_presenter_openFiles" );
+ }
+ connect( m_pViewer, SIGNAL( imageOpened( const KURL & ) ),
+ SLOT( slotImageOpened( const KURL & ) ) );
+ }
+ else
+ kdWarning( 4630 ) << "no KImageViewer interface found - the presenter plugin won't work" << endl;
+
+ //( void )new KViewPresenterConfModule( this );
+
+ connect( m_pImageList->m_pListView, SIGNAL( executed( QListViewItem* ) ),
+ this, SLOT( changeItem( QListViewItem* ) ) );
+ connect( m_pImageList->m_pPrevious, SIGNAL( clicked() ),
+ this, SLOT( prev() ) );
+ connect( m_pImageList->m_pNext, SIGNAL( clicked() ),
+ this, SLOT( next() ) );
+ connect( m_pImageList->m_pListView, SIGNAL( spacePressed( QListViewItem* ) ),
+ this, SLOT( changeItem( QListViewItem* ) ) );
+ connect( m_pImageList->m_pListView, SIGNAL( returnPressed( QListViewItem* ) ),
+ this, SLOT( changeItem( QListViewItem* ) ) );
+ connect( m_pImageList->m_pSlideshow, SIGNAL( toggled( bool ) ),
+ this, SLOT( slideshow( bool ) ) );
+ connect( m_pImageList->m_pInterval, SIGNAL( valueChanged( int ) ),
+ this, SLOT( setSlideshowInterval( int ) ) );
+ connect( m_pImageList->m_pShuffle, SIGNAL( clicked() ),
+ this, SLOT( shuffle() ) );
+ connect( m_pImageList->m_pLoad, SIGNAL( clicked() ),
+ this, SLOT( loadList() ) );
+ connect( m_pImageList->m_pSave, SIGNAL( clicked() ),
+ this, SLOT( saveList() ) );
+ connect( m_pImageList->m_pCloseAll, SIGNAL( clicked() ),
+ this, SLOT( closeAll() ) );
+
+ // allow drop on the dialog
+ m_pImageList->installEventFilter( this );
+ m_pImageList->m_pListView->installEventFilter( this );
+ m_pImageList->m_pListView->viewport()->installEventFilter( this );
+
+ // grab drops on the main view
+ m_pViewer->widget()->installEventFilter( this );
+
+ connect( m_pSlideshowTimer, SIGNAL( timeout() ),
+ this, SLOT( next() ) );
+}
+
+KViewPresenter::~KViewPresenter()
+{
+ kdDebug( 4630 ) << k_funcinfo << endl;
+ if( m_paFileOpen )
+ {
+ disconnect( m_paFileOpen, SIGNAL( activated() ), this, SLOT( slotOpenFiles() ) );
+ // If the parent() doesn't exist we either leave the "File Open" action
+ // in an unusable state or KView was just shutting down and therefor we
+ // can ignore this. I've only seen the second one happening and to get
+ // rid of the QObject::connect warning we do the parent() check.
+ if( parent() )
+ connect( m_paFileOpen, SIGNAL( activated() ), parent(), SLOT( slotOpenFile() ) );
+ }
+}
+
+bool KViewPresenter::eventFilter( QObject *obj, QEvent *ev )
+{
+ if( obj == m_pImageList || obj == m_pImageList->m_pListView || obj == m_pImageList->m_pListView->viewport() || obj == m_pViewer->widget() )
+ {
+ switch( ev->type() )
+ {
+ case QEvent::DragEnter:
+ case QEvent::DragMove:
+ {
+ // drag enter event in the image list
+ //kdDebug( 4630 ) << "DragEnterEvent in the image list: " << obj->className() << endl;
+ QDragEnterEvent * e = static_cast<QDragEnterEvent*>( ev );
+ //for( int i = 0; e->format( i ); ++i )
+ //kdDebug( 4630 ) << " - " << e->format( i ) << endl;
+ if( KURLDrag::canDecode( e ) )// || QImageDrag::canDecode( e ) )
+ {
+ e->accept();
+ return true;
+ }
+ }
+ case QEvent::Drop:
+ {
+ // drop event in the image list
+ kdDebug( 4630 ) << "DropEvent in the image list: " << obj->className() << endl;
+ QDropEvent * e = static_cast<QDropEvent*>( ev );
+ QStringList l;
+ //QImage image;
+ if( KURLDrag::decodeToUnicodeUris( e, l ) )
+ {
+ for( QStringList::const_iterator it = l.begin(); it != l.end(); ++it )
+ {
+ ImageInfo * info = new ImageInfo( KURL( *it ) );
+ if( ! m_imagelist.contains( info ) )
+ {
+ m_imagelist.inSort( info );
+ ( void )new ImageListItem( m_pImageList->m_pListView, KURL( *it ) );
+ }
+ else
+ delete info;
+ }
+ return true;
+ }
+ //else if( QImageDrag::decode( e, image ) )
+ //newImage( image );
+ }
+ default: // do nothing
+ break;
+ }
+ }
+ return KParts::Plugin::eventFilter( obj, ev );
+}
+
+void KViewPresenter::slotImageOpened( const KURL & url )
+{
+ kdDebug( 4630 ) << k_funcinfo << endl;
+ if( ! m_bDontAdd )
+ {
+ kdDebug( 4630 ) << k_funcinfo << "imagelist:" << endl;
+ ImageInfo * info = new ImageInfo( url );
+ if( ! m_imagelist.contains( info ) )
+ {
+ m_imagelist.inSort( info );
+ QListViewItem * item = new ImageListItem( m_pImageList->m_pListView, url );
+ makeCurrent( item );
+ }
+ else
+ delete info;
+ }
+}
+
+void KViewPresenter::slotImageList()
+{
+ kdDebug( 4630 ) << k_funcinfo << endl;
+ m_pImageList->show();
+}
+
+void KViewPresenter::slotOpenFiles()
+{
+ kdDebug( 4630 ) << k_funcinfo << endl;
+ KURL::List urls = KFileDialog::getOpenURLs( ":load_image", KImageIO::pattern( KImageIO::Reading ), m_pViewer->widget() );
+
+ if( urls.isEmpty() )
+ return;
+
+ KURL::List::Iterator it = urls.begin();
+ m_pViewer->openURL( *it );
+ for( ++it; it != urls.end(); ++it )
+ {
+ ImageInfo * info = new ImageInfo( *it );
+ if( ! m_imagelist.contains( info ) )
+ {
+ m_imagelist.inSort( info );
+ ( void )new ImageListItem( m_pImageList->m_pListView, *it );
+ }
+ else
+ delete info;
+ }
+}
+
+void KViewPresenter::slotClose()
+{
+ QListViewItem * next = m_pCurrentItem->itemBelow() ? m_pCurrentItem->itemBelow() : m_pImageList->m_pListView->firstChild();
+ if( next == m_pCurrentItem )
+ next = 0;
+
+ ImageInfo info( m_pCurrentItem->url() );
+ m_imagelist.remove( &info );
+ delete m_pCurrentItem;
+ m_pCurrentItem = 0;
+
+ if( next )
+ changeItem( next );
+}
+
+void KViewPresenter::changeItem( QListViewItem * qitem )
+{
+ kdDebug( 4630 ) << k_funcinfo << endl;
+ if( qitem->rtti() == 48294 )
+ {
+ ImageListItem * item = static_cast<ImageListItem*>( qitem );
+ if( ! item->url().isEmpty() )
+ {
+ if( item->url().isLocalFile() && ! QFile::exists( item->url().path() ) )
+ {
+ kdDebug( 4630 ) << "file doesn't exist. removed." << endl;
+ ImageInfo info( item->url() );
+ m_imagelist.remove( &info );
+ if( m_pCurrentItem == item )
+ {
+ QListViewItem * next = m_pCurrentItem->itemBelow() ? m_pCurrentItem->itemBelow() : m_pImageList->m_pListView->firstChild();
+ if( next->rtti() != 48294 )
+ kdWarning( 4630 ) << "unknown ListView item" << endl;
+ else
+ m_pCurrentItem = static_cast<ImageListItem*>( next );
+
+ if( m_pCurrentItem == item )
+ m_pCurrentItem = 0; // don't create a dangling pointer
+ delete item;
+ if( m_pCurrentItem )
+ changeItem( m_pCurrentItem );
+ }
+ else
+ {
+ delete item;
+ next();
+ }
+ return;
+ }
+ kdDebug( 4630 ) << "got url" << endl;
+ makeCurrent( qitem );
+
+ bool dontadd = m_bDontAdd;
+ m_bDontAdd = true;
+ m_pViewer->openURL( item->url() );
+ m_bDontAdd = dontadd;
+ }
+ else
+ kdWarning( 4630 ) << "got nothing" << endl;
+ }
+ else
+ kdWarning( 4630 ) << "unknown ListView item" << endl;
+}
+
+void KViewPresenter::prev()
+{
+ kdDebug( 4630 ) << k_funcinfo << endl;
+ if( m_pCurrentItem )
+ {
+ QListViewItem * prev = m_pCurrentItem->itemAbove() ? m_pCurrentItem->itemAbove() : m_pImageList->m_pListView->lastItem();
+ if( prev )
+ changeItem( prev );
+ }
+}
+
+void KViewPresenter::next()
+{
+ kdDebug( 4630 ) << k_funcinfo << endl;
+ if( m_pCurrentItem )
+ {
+ QListViewItem * next = m_pCurrentItem->itemBelow() ? m_pCurrentItem->itemBelow() : m_pImageList->m_pListView->firstChild();
+ if( next )
+ changeItem( next );
+ }
+}
+
+void KViewPresenter::makeCurrent( QListViewItem * item )
+{
+ if( m_pCurrentItem )
+ m_pCurrentItem->setPixmap( 0, QPixmap() );
+ if( item->rtti() != 48294 )
+ kdWarning( 4630 ) << "unknown ListView item" << endl;
+ else
+ {
+ m_pCurrentItem = static_cast<ImageListItem*>( item );
+ m_pCurrentItem->setPixmap( 0, KGlobal::iconLoader()->loadIcon( "1rightarrow", KIcon::Small ) );
+ m_pImageList->m_pListView->ensureItemVisible( m_pCurrentItem );
+ }
+}
+
+void KViewPresenter::slideshow( bool running )
+{
+ if( running )
+ {
+ m_pSlideshowTimer->start( m_pImageList->m_pInterval->value() );
+ actionCollection()->action( "plugin_presenter_slideshow" )->setText( i18n( "Stop &Slideshow" ) );
+ m_pImageList->m_pSlideshow->setText( i18n( "Stop &Slideshow" ) );
+ }
+ else
+ {
+ m_pSlideshowTimer->stop();
+ actionCollection()->action( "plugin_presenter_slideshow" )->setText( i18n( "Start &Slideshow" ) );
+ m_pImageList->m_pSlideshow->setText( i18n( "Start &Slideshow" ) );
+ }
+}
+
+void KViewPresenter::setSlideshowInterval( int msec )
+{
+ if( m_pSlideshowTimer->isActive() )
+ m_pSlideshowTimer->changeInterval( msec );
+}
+
+void KViewPresenter::shuffle()
+{
+ m_pImageList->noSort();
+ KListView * listview = m_pImageList->m_pListView;
+ QPtrList<QListViewItem> items;
+ for( QListViewItem * item = listview->firstChild(); item; item = listview->firstChild() )
+ {
+ items.append( item );
+ listview->takeItem( item );
+ }
+ while( ! items.isEmpty() )
+ listview->insertItem( items.take( KApplication::random() % items.count() ) );
+}
+
+void KViewPresenter::closeAll()
+{
+ m_imagelist.clear();
+ m_pImageList->m_pListView->clear();
+ m_pCurrentItem = 0;
+ if( m_pViewer->closeURL() )
+ m_pViewer->canvas()->clear();
+}
+
+void KViewPresenter::loadList()
+{
+ KURL url = KFileDialog::getOpenURL( ":load_list", QString::null, m_pImageList );
+ if( url.isEmpty() )
+ return;
+
+ QString tempfile;
+ if( ! KIO::NetAccess::download( url, tempfile, m_pViewer->widget() ) )
+ {
+ KMessageBox::error( m_pImageList, i18n( "Could not load\n%1" ).arg( url.prettyURL() ) );
+ return;
+ }
+ QFile file( tempfile );
+ if( file.open( IO_ReadOnly ) )
+ {
+ QTextStream t( &file );
+ if( t.readLine() == "[KView Image List]" )
+ {
+ //clear old image list
+ closeAll();
+
+ QStringList list;
+ if( ! t.eof() )
+ m_pViewer->openURL( KURL( t.readLine() ) );
+ while( ! t.eof() )
+ {
+ KURL url ( t.readLine() );
+ ImageInfo * info = new ImageInfo( url );
+ if( ! m_imagelist.contains( info ) )
+ {
+ m_imagelist.inSort( info );
+ ( void )new ImageListItem( m_pImageList->m_pListView, url );
+ }
+ else
+ delete info;
+ }
+ }
+ else
+ {
+ KMessageBox::error( m_pImageList, i18n( "Wrong format\n%1" ).arg( url.prettyURL() ) );
+ }
+ file.close();
+ }
+ KIO::NetAccess::removeTempFile( tempfile );
+}
+
+void KViewPresenter::saveList()
+{
+ KURL url = KFileDialog::getSaveURL( ":save_list", QString::null, m_pImageList );
+
+ if( url.isEmpty() )
+ return;
+
+ QString tempfile;
+ if( url.isLocalFile() )
+ tempfile = url.path();
+ else
+ {
+ KTempFile ktempf;
+ tempfile = ktempf.name();
+ }
+
+ QFile file( tempfile );
+ if( file.open( IO_WriteOnly ) )
+ {
+ QTextStream t( &file );
+ // write header
+ t << "[KView Image List]" << endl;
+ QListViewItem * item = m_pImageList->m_pListView->firstChild();
+ while( item )
+ {
+ if( item->rtti() == 48294 )
+ t << static_cast<ImageListItem*>( item )->url().url() << endl;
+ item = item->itemBelow();
+ }
+ file.close();
+
+ if( ! url.isLocalFile() )
+ {
+ KIO::NetAccess::upload( tempfile, url, m_pViewer->widget() );
+ KIO::NetAccess::removeTempFile( tempfile );
+ }
+ }
+}
+
+// vim:sw=4:ts=4
+#include "kviewpresenter.moc"
diff --git a/kview/modules/presenter/kviewpresenter.desktop b/kview/modules/presenter/kviewpresenter.desktop
new file mode 100644
index 00000000..7059caba
--- /dev/null
+++ b/kview/modules/presenter/kviewpresenter.desktop
@@ -0,0 +1,118 @@
+[Desktop Entry]
+Icon=presenter
+Type=Service
+ServiceTypes=KPluginInfo
+
+X-KDE-PluginInfo-Author=Matthias Kretz
+X-KDE-PluginInfo-Email=kretz@kde.org
+X-KDE-PluginInfo-Name=kviewpresenter
+X-KDE-PluginInfo-Version=1.1
+X-KDE-PluginInfo-License=GPL
+X-KDE-PluginInfo-EnabledByDefault=true
+
+Name=Presenter
+Name[ar]=المقدّم
+Name[bg]=Презентация
+Name[br]=Emginniger
+Name[bs]=Prezentator
+Name[ca]=Presentador
+Name[cs]=Prezentace
+Name[cy]=Cyflwynydd
+Name[de]=Präsentationsprogramm
+Name[el]=Παρουσιαστής
+Name[eo]=Prezentilo
+Name[et]=Esitleja
+Name[eu]=Aurkezlea
+Name[fa]=ارائه‌کننده
+Name[fi]=Esitysohjelma
+Name[fr]=Présentateur
+Name[ga]=Láithreoir
+Name[gl]=Escaparate
+Name[he]=מצגות
+Name[hi]=प्रस्तुतकर्ता
+Name[hr]=Prezentator
+Name[hu]=Bemutató
+Name[it]=Presentazione
+Name[ja]=プレゼンタ
+Name[kk]=Презентатор
+Name[km]=កម្មវិធី​បង្ហាញ
+Name[lt]=Pristatytojas
+Name[ms]=Penyampai
+Name[nds]=Präsentatschoonprogramm
+Name[ne]=प्रस्तोता
+Name[nl]=Presentatieprogramma
+Name[nso]=Mohlagisi
+Name[pa]=ਪੇਸ਼ਕਾਰ
+Name[pl]=Prezenter
+Name[pt]=Apresentador
+Name[pt_BR]=Apresentador
+Name[ro]=Prezentare
+Name[ru]=Презентатор
+Name[sk]=Vytvorenie prezentácie
+Name[sl]=Predstavitelj
+Name[sr]=Презентер
+Name[sr@Latn]=Prezenter
+Name[sv]=Presentationer
+Name[ta]=வழங்குபவர்
+Name[tg]=Презентатор
+Name[tr]=Sunum Aracı
+Name[ven]=Mulanguli
+Name[xh]=Umbonisi
+Name[zh_CN]=演示板
+Name[zh_HK]=簡報器
+Name[zh_TW]=簡報
+Name[zu]=Umnikeli
+Comment=Creates an imagelist and enables you to create a slideshow
+Comment[ar]=ينشئ قائمة صور ويمكنك من استعراض الصور تلقائيا
+Comment[bg]=Създаване на списък с изображения и слайдшоу от тях
+Comment[bs]=Pravi listu slika i omogućuje vam da napravite slide show
+Comment[ca]=Crea una llista d'imatges i us permet crear un passi de diapositives
+Comment[cs]=Vytvoří seznam obrázků a umožní vám z nich vytvořit slideshow.
+Comment[cy]=Creu rhestr delweddau ac alluogi i chi greu sioe haenluniau
+Comment[da]=Laver en billedliste og giver dig muligheden for at lave et diasshow
+Comment[de]=Erzeugt eine Bilderliste und ermöglicht das Erstellen von Diashows
+Comment[el]=Δημιουργεί μια λίστα εικόνων και σας επιτρέπει να δημιουργήσετε μια προβολή σλάιντ
+Comment[es]=Crea una lista de imágenes ofreciendole la posibilidad de crear una animación de diapositivas
+Comment[et]=Loob piltide nimekirja ja laseb selle põhjal luua slaidiseansi
+Comment[eu]=Irudi-zerrenda bat sortzen du eta diapositiba-aurkezpena egiten du
+Comment[fa]=یک فهرست تصویر ایجاد می‌کند و شما را قادر به ایجاد یک نمایش اسلاید می‌کند
+Comment[fi]=Luo kuvalistan ja mahdollistaa esityksen luomisen
+Comment[fr]=Crée une liste d'images et vous permet de créer un diaporama
+Comment[gl]=Crea unha lista de imaxes e permite crear unha moviola
+Comment[he]=יוצר רשימת תמונות ומאפשר לך ליצור מצגת שקופיות
+Comment[hi]=एक छवि-सूची बनाता है तथा आपको एक स्लाइड-शो तैयार करने में सक्षम बनाता है
+Comment[hu]=Képsorozat összeállítását és bemutatását teszi lehetővé
+Comment[is]=Býr til myndlista og gerir þér kleyft að búa til myndsýningu
+Comment[it]=Crea una lista di immagini e permette di creare una presentazione
+Comment[ja]=画像リストを作成し、スライドショーを作成します
+Comment[kk]=Слайд-шоу көрсетуге кескіндер тізімін дайындау
+Comment[km]=បង្កើត​បញ្ជី​រូបភាព ហើយ​អាច​ឲ្យ​អ្នក​បង្កើត​ជា​ការ​បញ្ចាំង​ស្លាយ
+Comment[lt]=Sukuria paveikslėlių sąrašą ir leidžia jums sukurti skaidrių peržiūrą
+Comment[ms]=Cipta senarai imej dan membolehkan anda mencipta tayangan slaid
+Comment[nb]=Oppretter en bildeliste og lar deg lage en lysbildeserie
+Comment[nds]=Stellt en Bildlist op un lett Di en Diaschau opstellen
+Comment[ne]=छवि सूची सिर्जना गर्दछ र तपाईँलाई स्लाइड प्रर्दशन सिर्जना गर्न सक्षम पार्दछ
+Comment[nl]=Maakt een afbeeldingenlijst waarmee u een diashow kunt maken
+Comment[nn]=Lagar ei biletliste du kan bruka til framvising
+Comment[nso]=Hlagisa palo ya ponagalo gape ego dumelela go hlagisa slidesshow
+Comment[pl]=Tworzy listę obrazków i umożliwia tworzenie z niej pokazu slajdów
+Comment[pt]=Cria uma lista de imagens e permite-lhe criar uma apresentação
+Comment[pt_BR]=Cria uma lista de imagens e habilita você a criar uma exibição de slides
+Comment[ro]=Creează o listă de imagini şi vă permite să reallizaţi o succesiune de imagini
+Comment[ru]=Создание галерей изображений и просмотр их в качестве слайдов
+Comment[se]=Ráhkada govvalisttu ja diktá du ráhkadit govvačájeheami
+Comment[sk]=Vytvorí zoznam obrázok a umožní z nich vytvoriť prezentáciu
+Comment[sl]=Ustvari seznam slik in vam omogoča ustvariti predstavitev
+Comment[sr]=Прави листу слика и омогућава вам да направите слајд-шоу
+Comment[sr@Latn]=Pravi listu slika i omogućava vam da napravite slajd-šou
+Comment[sv]=Skapar en bildlista och ger dig möjlighet att göra ett bildspel
+Comment[ta]=திரைக் காட்சிக்கான பிம்ப பட்டியலை உருவாக்கலாம்
+Comment[tg]=Эҷоди нигористони тасвирот ва намоиши онҳо ҳамчун слайд
+Comment[tr]=Bir resim listesi oluşturur ve slayt gösterisi yapmanıza olanak tanır
+Comment[uk]=Створює список зображень та дозволяє створювати презентацію слайдів
+Comment[ven]=Iita mutevhe wa tshifanyiso ya dovha yani tendela uita tsumbedzo ya tshilaidi
+Comment[xh]=Yenza uluhlu lwemifanekiso ekuvumela ukwazi ukwenza umboniso wotyibiliko
+Comment[zh_CN]=创建图像列表,并能为您创建幻灯片
+Comment[zh_HK]=建立圖像清單並讓您能建立幻燈片式放映
+Comment[zh_TW]=建立影像清單並讓您能建立幻燈片式放映
+Comment[zu]=Idala uhlu lwesithombe futhi ikuvumela wena ukuba udale umbukiso wesithombe esishibilikayo
diff --git a/kview/modules/presenter/kviewpresenter.h b/kview/modules/presenter/kviewpresenter.h
new file mode 100644
index 00000000..29fc106b
--- /dev/null
+++ b/kview/modules/presenter/kviewpresenter.h
@@ -0,0 +1,103 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+
+*/
+
+/* $Id$ */
+
+#ifndef __kviewpresenter_h
+#define __kviewpresenter_h
+
+#include <kparts/plugin.h>
+#include <kurl.h>
+
+#include <qsortedlist.h>
+
+namespace KImageViewer { class Viewer; }
+
+class ImageListDialog;
+class ImageListItem;
+class QListViewItem;
+class QTimer;
+class KToggleAction;
+class KAction;
+
+class KViewPresenter : public KParts::Plugin
+{
+ Q_OBJECT
+public:
+ KViewPresenter( QObject* parent, const char* name, const QStringList & );
+ virtual ~KViewPresenter();
+
+protected:
+ struct ImageInfo
+ {
+ KURL url;
+ ImageInfo( const KURL & url )
+ : url( url )
+ {
+ }
+ bool operator==( const ImageInfo & i1 )
+ {
+ return url.prettyURL() == i1.url.prettyURL();
+ }
+ bool operator!=( const ImageInfo & i1 )
+ {
+ return url.prettyURL() == i1.url.prettyURL();
+ }
+ bool operator>( const ImageInfo & i1 )
+ {
+ return url.prettyURL() > i1.url.prettyURL();
+ }
+ bool operator<( const ImageInfo & i1 )
+ {
+ return url.prettyURL() < i1.url.prettyURL();
+ }
+ };
+ bool eventFilter( QObject *, QEvent * );
+
+private slots:
+ void slotImageOpened( const KURL & );
+ void slotImageList();
+ void slotOpenFiles();
+ void slotClose();
+ void changeItem( QListViewItem * );
+ void prev();
+ void next();
+ void slideshow( bool );
+ void setSlideshowInterval( int );
+ void shuffle();
+ void closeAll();
+ void loadList();
+ void saveList();
+
+private:
+ void makeCurrent( QListViewItem * );
+
+ KImageViewer::Viewer * m_pViewer;
+ ImageListDialog * m_pImageList;
+ KToggleAction * m_paSlideshow;
+ KAction * m_paFileOpen;
+ KAction * m_paFileClose;
+
+ QSortedList<ImageInfo> m_imagelist;
+ bool m_bDontAdd;
+ ImageListItem * m_pCurrentItem;
+ QTimer * m_pSlideshowTimer;
+};
+
+// vim:sw=4:ts=4:cindent
+#endif
diff --git a/kview/modules/presenter/kviewpresenter.rc b/kview/modules/presenter/kviewpresenter.rc
new file mode 100644
index 00000000..92879d02
--- /dev/null
+++ b/kview/modules/presenter/kviewpresenter.rc
@@ -0,0 +1,20 @@
+<!DOCTYPE kpartgui>
+<kpartplugin name="kviewpresenter" library="kview_presenterplugin" version="3">
+ <MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="plugin_presenter_openFiles" group="open_merge_group"/>
+ </Menu>
+ <Menu name="view"><text>&amp;View</text>
+ </Menu>
+
+ <Menu name="go_document"><Text>&amp;Go</Text>
+ <Action name="plugin_presenter_imageList"/>
+ <Action name="plugin_presenter_slideshow"/>
+ <Action name="plugin_presenter_prev"/>
+ <Action name="plugin_presenter_next"/>
+ </Menu>
+ </MenuBar>
+ <Menu name="popupmenu">
+ <Action name="plugin_presenter_slideshow"/>
+ </Menu>
+</kpartplugin>
diff --git a/kview/modules/presenter/kviewpresenterconfmodule.cpp b/kview/modules/presenter/kviewpresenterconfmodule.cpp
new file mode 100644
index 00000000..a39ea378
--- /dev/null
+++ b/kview/modules/presenter/kviewpresenterconfmodule.cpp
@@ -0,0 +1,60 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+
+*/
+
+// $Id$
+
+#include "kviewpresenterconfmodule.h"
+
+#include <qlayout.h>
+#include <qcheckbox.h>
+#include <qframe.h>
+
+#include <klocale.h>
+#include <kdialog.h>
+#include <kglobal.h>
+#include <kconfig.h>
+
+KViewPresenterConfModule::KViewPresenterConfModule( QObject * parent )
+ : KPreferencesModule( "kviewpresenter", parent, "KView Presenter Config Module" )
+{
+}
+
+KViewPresenterConfModule::~KViewPresenterConfModule()
+{
+}
+
+void KViewPresenterConfModule::applyChanges()
+{
+ emit configChanged();
+}
+
+void KViewPresenterConfModule::reset()
+{
+}
+
+void KViewPresenterConfModule::createPage( QFrame * page )
+{
+ QBoxLayout * layout = new QVBoxLayout( page, KDialog::marginHint(), KDialog::spacingHint() );
+ layout->setAutoAdd( true );
+
+ m_pCheckBox = new QCheckBox( "This is only for testing...", page );
+}
+
+// vim:sw=4:ts=4
+
+#include "kviewpresenterconfmodule.moc"
diff --git a/kview/modules/presenter/kviewpresenterconfmodule.h b/kview/modules/presenter/kviewpresenterconfmodule.h
new file mode 100644
index 00000000..dd7e5cf2
--- /dev/null
+++ b/kview/modules/presenter/kviewpresenterconfmodule.h
@@ -0,0 +1,49 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+
+*/
+
+// $Id$
+
+#ifndef KVIEWPRESENTERCONFMODULE_H
+#define KVIEWPRESENTERCONFMODULE_H
+
+#include "kpreferencesmodule.h"
+
+class QCheckBox;
+
+class KViewPresenterConfModule : public KPreferencesModule
+{
+ Q_OBJECT
+ public:
+ KViewPresenterConfModule( QObject * parent );
+ ~KViewPresenterConfModule();
+
+ signals:
+ void configChanged();
+
+ protected:
+ virtual void applyChanges();
+ virtual void reset();
+ virtual void createPage( QFrame * page );
+
+ private:
+ QCheckBox * m_pCheckBox;
+};
+
+// vim:sw=4:ts=4
+
+#endif // KVIEWPRESENTERCONFMODULE_H
diff --git a/kview/modules/scale/Makefile.am b/kview/modules/scale/Makefile.am
new file mode 100644
index 00000000..39442781
--- /dev/null
+++ b/kview/modules/scale/Makefile.am
@@ -0,0 +1,15 @@
+INCLUDES = -I$(top_srcdir)/kview $(all_includes)
+
+kde_module_LTLIBRARIES = kview_scale.la
+
+kview_scale_la_SOURCES = kfloatspinbox.cpp scaledlg.cpp kview_scale.cpp
+kview_scale_la_LIBADD = $(LIB_KFILE) $(LIB_KPARTS) -lkdeprint
+kview_scale_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+
+plugdir = $(kde_datadir)/kviewviewer/kpartplugins
+plug_DATA = kview_scale.rc kview_scale.desktop
+
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp *.h -o $(podir)/kview_scale.pot
diff --git a/kview/modules/scale/kfloatspinbox.cpp b/kview/modules/scale/kfloatspinbox.cpp
new file mode 100644
index 00000000..e5ce8465
--- /dev/null
+++ b/kview/modules/scale/kfloatspinbox.cpp
@@ -0,0 +1,116 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+
+*/
+
+// $Id$
+
+#include "kfloatspinbox.h"
+
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+#include <qaccessible.h>
+#endif
+
+#include <knumvalidator.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kdebug.h>
+
+int pow( int a, int b )
+{
+ int ret = 1;
+ for( int i = 0; i < b; ++i )
+ ret *= a;
+ return ret;
+}
+
+KFloatSpinBox::KFloatSpinBox( float minValue, float maxValue, float step, unsigned int precision, QWidget * parent, const char * name )
+ : QSpinBox( parent, name )
+ , m_doselection( true )
+{
+ setRange( minValue, maxValue, step, precision );
+ connect( this, SIGNAL( valueChanged( int ) ), this, SLOT( slotValueChanged( int ) ) );
+}
+
+KFloatSpinBox::~KFloatSpinBox()
+{
+}
+
+void KFloatSpinBox::setRange( float minValue, float maxValue, float step, unsigned int precision )
+{
+ m_factor = pow( 10, precision );
+ m_min = (int)( minValue * m_factor );
+ m_max = (int)( maxValue * m_factor );
+ m_step = (int)( step * m_factor );
+ QSpinBox::setRange( m_min, m_max );
+ setSteps( m_step, m_step * 10 );
+ if( precision == 0 )
+ setValidator( new KIntValidator( m_min, m_max, this, 10, "KFloatValidator::KIntValidator" ) );
+ else
+ setValidator( new KFloatValidator( minValue, maxValue, true, this, "KFloatSpinBox::KFloatValidator" ) );
+}
+
+float KFloatSpinBox::value() const
+{
+ float ret = (float)QSpinBox::value() / m_factor;
+ kdDebug( 4630 ) << ret << endl;
+ return ret;
+}
+
+void KFloatSpinBox::setValue( float value )
+{
+ QSpinBox::setValue( (int)( value * m_factor ) );
+}
+
+void KFloatSpinBox::setValueBlocking( float value )
+{
+ m_doselection = false;
+ blockSignals( true );
+ KFloatSpinBox::setValue( value );
+ blockSignals( false );
+ m_doselection = true;
+}
+
+QString KFloatSpinBox::mapValueToText( int value )
+{
+ return KGlobal::locale()->formatNumber( (float)value / (float)m_factor, 4 );
+}
+
+int KFloatSpinBox::mapTextToValue( bool * ok )
+{
+ return (int)( m_factor * KGlobal::locale()->readNumber( text(), ok ) );
+}
+
+void KFloatSpinBox::valueChange()
+{
+ if( m_doselection )
+ QSpinBox::valueChange();
+ else
+ {
+ updateDisplay();
+ emit valueChanged( value() );
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::ValueChanged );
+#endif
+ }
+}
+
+void KFloatSpinBox::slotValueChanged( int )
+{
+ emit valueChanged( value() );
+}
+
+#include "kfloatspinbox.moc"
diff --git a/kview/modules/scale/kfloatspinbox.h b/kview/modules/scale/kfloatspinbox.h
new file mode 100644
index 00000000..9407a0f1
--- /dev/null
+++ b/kview/modules/scale/kfloatspinbox.h
@@ -0,0 +1,64 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+
+*/
+
+// $Id$
+
+#ifndef __kfloatspinbox_h_
+#define __kfloatspinbox_h_
+
+#include <qspinbox.h>
+
+class KFloatSpinBox : public QSpinBox
+{
+ Q_OBJECT
+ public:
+ KFloatSpinBox( float minValue, float maxValue, float step, unsigned int precision, QWidget * parent = 0, const char * name = 0 );
+ virtual ~KFloatSpinBox();
+
+ void setRange( float minValue, float maxValue, float step, unsigned int precision );
+ void setRangeBlocking( float minValue, float maxValue, float step, unsigned int precision );
+
+ float value() const;
+
+ public slots:
+ virtual void setValue( float value );
+ /**
+ * differs from the above in that it will block all signals
+ */
+ virtual void setValueBlocking( float value );
+
+ protected:
+ virtual QString mapValueToText( int value );
+ virtual int mapTextToValue( bool * ok );
+ virtual void valueChange();
+
+ signals:
+ void valueChanged( float value );
+
+ private slots:
+ void slotValueChanged( int value );
+
+ private:
+ int m_factor;
+ int m_min;
+ int m_max;
+ int m_step;
+ bool m_doselection;
+};
+
+#endif
diff --git a/kview/modules/scale/kview_scale.cpp b/kview/modules/scale/kview_scale.cpp
new file mode 100644
index 00000000..aa8dec82
--- /dev/null
+++ b/kview/modules/scale/kview_scale.cpp
@@ -0,0 +1,180 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+
+*/
+
+/* $Id$ */
+
+#include "kview_scale.h"
+#include "scaledlg.h"
+
+#include <qimage.h>
+#include <qvbox.h>
+
+#include <kaction.h>
+#include <klocale.h>
+#include <kgenericfactory.h>
+#include <kdebug.h>
+#include <kimageviewer/viewer.h>
+#include <kimageviewer/canvas.h>
+#include <kdialogbase.h>
+
+typedef KGenericFactory<KViewScale> KViewScaleFactory;
+K_EXPORT_COMPONENT_FACTORY( kview_scale, KViewScaleFactory( "kview_scale" ) )
+
+KViewScale::KViewScale( QObject* parent, const char* name, const QStringList & )
+ : Plugin( parent, name )
+ , m_pViewer( 0 )
+ , m_pCanvas( 0 )
+{
+ m_pViewer = static_cast<KImageViewer::Viewer *>( parent );
+ if( m_pViewer )
+ {
+ kdDebug( 4630 ) << "m_pViewer->canvas() = " << m_pViewer->canvas() << endl;
+ m_pCanvas = m_pViewer->canvas();
+
+ (void) new KAction( i18n( "&Scale Image..." ), 0, 0,
+ this, SLOT( slotScaleDlg() ),
+ actionCollection(), "plugin_scale" );
+ }
+ else
+ kdWarning( 4630 ) << "no KImageViewer interface found - the scale plugin won't work" << endl;
+}
+
+KViewScale::~KViewScale()
+{
+}
+
+void KViewScale::slotScaleDlg()
+{
+ kdDebug( 4630 ) << k_funcinfo << endl;
+ KDialogBase dlg( m_pViewer->widget(), "KView scale dialog", true, i18n( "Scale Image" ), KDialogBase::Ok|KDialogBase::Cancel );
+ ScaleDlg widget( m_pCanvas->imageSize(), dlg.makeVBoxMainWidget() );
+#if 0
+ QVBox * layout = dlg.makeVBoxMainWidget();
+
+ QGroupBox * pixelgroup = new QGroupBox( i18n( "Pixel Dimensions" ), layout );
+ QGridLayout * pixelgroupgrid = new QGridLayout( pixelgroup, 1, 1, 0, KDialog::spacingHint() );
+ pixelgroupgrid->setSpacing( KDialog::spacingHint() );
+ pixelgroupgrid->setMargin( KDialog::marginHint() );
+ QLabel * label;
+ QSize imagesize = m_pCanvas->imageSize();
+
+ // show original width
+ label = new QLabel( i18n( "Original width:" ), pixelgroup );
+ label->setAlignment( QLabel::AlignRight );
+ pixelgroupgrid->addWidget( label, 0, 0 );
+ pixelgroupgrid->addWidget( new QLabel( QString::number( imagesize.width() ), pixelgroup ), 0, 1 );
+ label = new QLabel( i18n( "Height:" ), pixelgroup );
+ label->setAlignment( QLabel::AlignRight );
+ pixelgroupgrid->addWidget( label, 1, 0 );
+ pixelgroupgrid->addWidget( new QLabel( QString::number( imagesize.height() ), pixelgroup ), 1, 1 );
+
+ pixelgroupgrid->addRowSpacing( 2, KDialog::spacingHint() );
+
+ label = new QLabel( i18n( "New width:" ), pixelgroup );
+ label->setAlignment( QLabel::AlignRight );
+ pixelgroupgrid->addWidget( label, 3, 0 );
+ label = new QLabel( i18n( "Height:" ), pixelgroup );
+ label->setAlignment( QLabel::AlignRight );
+ pixelgroupgrid->addWidget( label, 4, 0 );
+ QSpinBox * newwidth = new QSpinBox( 1, 100000, 1, pixelgroup );
+ pixelgroupgrid->addWidget( newwidth, 3, 1 );
+ QSpinBox * newheight = new QSpinBox( 1, 100000, 1, pixelgroup );
+ pixelgroupgrid->addWidget( newheight, 4, 1 );
+ KComboBox * newsizeunit = new KComboBox( pixelgroup );
+ newsizeunit->insertItem( i18n( "px" ) );
+ newsizeunit->insertItem( i18n( "%" ) );
+ pixelgroupgrid->addMultiCellWidget( newsizeunit, 3, 4, 2, 2, Qt::AlignVCenter );
+
+ pixelgroupgrid->addRowSpacing( 5, KDialog::spacingHint() );
+
+ label = new QLabel( i18n( "Ratio X:" ), pixelgroup );
+ label->setAlignment( QLabel::AlignRight );
+ pixelgroupgrid->addWidget( label, 6, 0 );
+ label = new QLabel( i18n( "Y:" ), pixelgroup );
+ label->setAlignment( QLabel::AlignRight );
+ pixelgroupgrid->addWidget( label, 7, 0 );
+ QSpinBox * ratiox = new QSpinBox( pixelgroup );
+ ratiox->setValidator( new QDoubleValidator( 0.0001, 10000, 4, ratiox ) );
+ pixelgroupgrid->addWidget( ratiox, 6, 1 );
+ QSpinBox * ratioy = new QSpinBox( pixelgroup );
+ ratioy->setValidator( new QDoubleValidator( 0.0001, 10000, 4, ratioy ) );
+ pixelgroupgrid->addWidget( ratioy, 7, 1 );
+ pixelgroupgrid->addMultiCellWidget( new QCheckBox( i18n( "Link" ), pixelgroup ), 6, 7, 2, 2, Qt::AlignVCenter );
+
+ QGroupBox * printgroup = new QGroupBox( i18n( "Print Size && Display Units" ), layout );
+ QGridLayout * printgroupgrid = new QGridLayout( printgroup, 1, 1, 0, KDialog::spacingHint() );
+ printgroupgrid->setSpacing( KDialog::spacingHint() );
+ printgroupgrid->setMargin( KDialog::marginHint() );
+
+ label = new QLabel( i18n( "New width:" ), printgroup );
+ label->setAlignment( QLabel::AlignRight );
+ printgroupgrid->addWidget( label, 0, 0 );
+ label = new QLabel( i18n( "Height:" ), printgroup );
+ label->setAlignment( QLabel::AlignRight );
+ printgroupgrid->addWidget( label, 1, 0 );
+ QSpinBox * newwidth2 = new QSpinBox( printgroup );
+ printgroupgrid->addWidget( newwidth2, 0, 1 );
+ QSpinBox * newheight2 = new QSpinBox( printgroup );
+ printgroupgrid->addWidget( newheight2, 1, 1 );
+ KComboBox * newsizeunit2 = new KComboBox( printgroup );
+ newsizeunit2->insertItem( i18n( "in" ) );
+ newsizeunit2->insertItem( i18n( "mm" ) );
+ printgroupgrid->addMultiCellWidget( newsizeunit2, 0, 1, 2, 2, Qt::AlignVCenter );
+
+ printgroupgrid->addRowSpacing( 2, KDialog::spacingHint() );
+
+ label = new QLabel( i18n( "Resolution X:" ), printgroup );
+ label->setAlignment( QLabel::AlignRight );
+ printgroupgrid->addWidget( label, 3, 0 );
+ label = new QLabel( i18n( "Y:" ), printgroup );
+ label->setAlignment( QLabel::AlignRight );
+ printgroupgrid->addWidget( label, 4, 0 );
+ QSpinBox * resx = new QSpinBox( printgroup );
+ printgroupgrid->addWidget( resx, 3, 1 );
+ QSpinBox * resy = new QSpinBox( printgroup );
+ printgroupgrid->addWidget( resy, 4, 1 );
+ printgroupgrid->addMultiCellWidget( new QCheckBox( i18n( "Link" ), printgroup ), 3, 4, 2, 2, Qt::AlignVCenter );
+ //KComboBox * newsizeunit2 = new KComboBox( printgroup );
+ //newsizeunit2->insertItem( i18n( "in" ) );
+ //newsizeunit2->insertItem( i18n( "mm" ) );
+ //printgroupgrid->addMultiCellWidget( newsizeunit2, 0, 1, 2, 2, Qt::AlignVCenter );
+#endif
+
+ dlg.exec();
+}
+
+void KViewScale::slotScale()
+{
+ // retrieve current image
+ kdDebug( 4630 ) << "m_pCanvas = " << m_pCanvas << endl;
+ const QImage * image = m_pCanvas->image();
+ kdDebug( 4630 ) << "image pointer retrieved" << endl;
+ if( image )
+ {
+ // scale
+ QImage newimage = image->smoothScale( 50, 50 );
+ // put back (modified)
+ m_pCanvas->setImage( newimage );
+ m_pViewer->setModified( true );
+ }
+ else
+ kdDebug( 4630 ) << "no image to scale" << endl;
+}
+
+// vim:sw=4:ts=4:cindent
+#include "kview_scale.moc"
diff --git a/kview/modules/scale/kview_scale.desktop b/kview/modules/scale/kview_scale.desktop
new file mode 100644
index 00000000..6dd11c40
--- /dev/null
+++ b/kview/modules/scale/kview_scale.desktop
@@ -0,0 +1,127 @@
+[Desktop Entry]
+Name=Scale
+Name[af]=Skaal
+Name[ar]=تكبير أو تصغير
+Name[bg]=Мащабиране
+Name[br]=Skeulaet
+Name[bs]=Skaliraj
+Name[ca]=Escala
+Name[cs]=Změna měřítka
+Name[cy]=Graddfa
+Name[da]=Skala
+Name[de]=Skalierer
+Name[el]=Κλιμάκωση
+Name[eo]=Grandecŝanĝo
+Name[et]=Skaleerija
+Name[eu]=Eskalatu
+Name[fa]=مقیاس
+Name[fi]=Skaalaa
+Name[fr]=Échelle
+Name[ga]=Scála
+Name[gl]=Redimensionar
+Name[he]=קנה מידה
+Name[hi]=स्केल
+Name[hr]=Skala
+Name[hu]=Nagyítás
+Name[is]=Skala
+Name[it]=Riscala
+Name[ja]=スケール
+Name[kk]=Масштабтау
+Name[km]=ធ្វើ​មាត្រដ្ឋាន
+Name[lt]=Mąstelis
+Name[ms]=Skala
+Name[nb]=Skaler
+Name[nds]=Grött-Topasser
+Name[ne]=स्केल
+Name[nl]=Schaalprogramma
+Name[nn]=Skaler
+Name[nso]=Sekala
+Name[pa]=ਸਕੇਲ
+Name[pl]=Skala
+Name[pt]=Redimensionamento
+Name[pt_BR]=Escala
+Name[ro]=Scalare
+Name[ru]=Масштабирование
+Name[se]=Skále
+Name[sk]=Škálovač
+Name[sl]=Raztegni
+Name[sr]=Скалирање
+Name[sr@Latn]=Skaliranje
+Name[sv]=Skala
+Name[ta]=அளவுக்கோல்
+Name[tg]=Масштабонӣ
+Name[tr]=Oranla
+Name[uk]=Масштаб
+Name[ven]=Tshikeili
+Name[wa]=Al schåle
+Name[xh]=Isikali
+Name[zh_CN]=缩放
+Name[zh_HK]=縮放
+Name[zh_TW]=縮放
+Name[zu]=Isikali
+Comment=Filter to scale the image
+Comment[af]=Filter na skaal die beeld
+Comment[ar]=فلتر لتكبير أو تصغير الصورة
+Comment[bg]=Филтър за мащабиране на изображения
+Comment[bs]=Filter za skaliranje slike
+Comment[ca]=Filtre per escalar la imatge
+Comment[cs]=Filtr ke změně měřítka obrázku
+Comment[cy]=Hidl i raddio'r ddelwedd
+Comment[da]=Filter til at skalere billedet
+Comment[de]=Ein Filter zum Skalieren von Bildern
+Comment[el]=Φίλτρο για την κλιμάκωση της εικόνας
+Comment[eo]=por ŝanĝi la grandecon de la bildo
+Comment[es]=Filtro para cambiar la escala de una imagen
+Comment[et]=Filter piltide skaleerimiseks
+Comment[eu]=Eskalatu irudia
+Comment[fa]=پالایه برای مقیاس کردن تصویر
+Comment[fi]=Suodatin kuvan skaalaamiseen
+Comment[fr]=Filtre pour zoomer une image
+Comment[gl]=Filtro para redimensionar a imaxe
+Comment[he]=מסנן לשינוי קנה המידה של התמונה
+Comment[hi]=छवि का आकार बदलने का फ़िल्टर
+Comment[hr]=Filter za promjenu veličine slike
+Comment[hu]=Képméretező szűrő
+Comment[is]=Sía sem skalar myndina
+Comment[it]=Filtro per ridimensionare l'immagine
+Comment[ja]=画像をスケールするフィルタ
+Comment[kk]=Кескідерді масштабтау сүзгісі
+Comment[km]=តម្រងធ្វើ​មាត្រដ្ឋាន​រូបភាព
+Comment[lt]=Filtras paveikslėliui didinti ar mažinti
+Comment[ms]=Tapis untuk menskalakan imej
+Comment[nb]=Filter for skalering av bildet
+Comment[nds]=En Filter för't Topassen vun de Bildgrött
+Comment[ne]=छवि मापन गर्न फिल्टर
+Comment[nl]=Filter om de afbeelding te schalen
+Comment[nn]=Filter for skalering av biletet
+Comment[nso]=Sesekodi sago kala ponagalo
+Comment[pl]=Filtr do skalowania obrazków
+Comment[pt]=Um filtro para escalar a imagem
+Comment[pt_BR]=Filtro para escalar a imagem
+Comment[ro]=Filtru de scalat imaginea
+Comment[ru]=Фильтр для масштабирования изображений
+Comment[se]=Silli mii skálere govaid
+Comment[sk]=Filter pre zväčšenie obrázku
+Comment[sl]=Filter za raztegovanje slike
+Comment[sr]=Филтер за промену величине слике
+Comment[sr@Latn]=Filter za promenu veličine slike
+Comment[sv]=Filter för att skala bilden
+Comment[ta]=பிம்பத்தை மாற்றும் வடிகட்டி
+Comment[tg]=Филтр барои масштабонии тасвирот
+Comment[tr]=Resmi oranlamak için filtre
+Comment[uk]=Фільтр для масштабування зображення
+Comment[ven]=Faela yau kala tshifanyiso
+Comment[wa]=Passete po mete l' imådje al schåle
+Comment[xh]=Icebo lokucoca ulwelo lokukala umfanekiso
+Comment[zh_CN]=缩放图像的滤镜
+Comment[zh_HK]=用來縮放影像的過濾器
+Comment[zh_TW]=用來縮放影像的濾鏡
+Comment[zu]=Hluza isithombe esikaleni
+Type=Plugin
+
+[X-KDE Plugin Info]
+Author=Matthias Kretz
+Email=kretz@kde.org
+PluginName=kview_scale
+Category=Filter
+Version=0.1
diff --git a/kview/modules/scale/kview_scale.h b/kview/modules/scale/kview_scale.h
new file mode 100644
index 00000000..2022f0ac
--- /dev/null
+++ b/kview/modules/scale/kview_scale.h
@@ -0,0 +1,48 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+
+*/
+
+/* $Id$ */
+
+#ifndef __kview_scale_h
+#define __kview_scale_h
+
+#include <kparts/plugin.h>
+
+namespace KImageViewer {
+ class Viewer;
+ class Canvas;
+}
+
+class KViewScale : public KParts::Plugin
+{
+ Q_OBJECT
+public:
+ KViewScale( QObject* parent, const char* name, const QStringList & );
+ virtual ~KViewScale();
+
+private slots:
+ void slotScaleDlg();
+ void slotScale();
+
+private:
+ KImageViewer::Viewer * m_pViewer;
+ KImageViewer::Canvas * m_pCanvas;
+};
+
+// vim:sw=4:ts=4:cindent
+#endif
diff --git a/kview/modules/scale/kview_scale.rc b/kview/modules/scale/kview_scale.rc
new file mode 100644
index 00000000..2f952be5
--- /dev/null
+++ b/kview/modules/scale/kview_scale.rc
@@ -0,0 +1,14 @@
+<!DOCTYPE kpartgui>
+<kpartplugin name="kview_scale" library="kview_scale">
+ <MenuBar>
+ <Menu name="image"><Text>&amp;Image</Text>
+ <Action name="plugin_scale"/>
+ </Menu>
+ </MenuBar>
+ <!--
+ <ToolBar name="extraToolBar">
+ <text>&amp;Extra Toolbar</text>
+ <Action name="plugin_scale"/>
+ </ToolBar>
+ -->
+</kpartplugin>
diff --git a/kview/modules/scale/scaledlg.cpp b/kview/modules/scale/scaledlg.cpp
new file mode 100644
index 00000000..997be86d
--- /dev/null
+++ b/kview/modules/scale/scaledlg.cpp
@@ -0,0 +1,311 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+
+*/
+
+// $Id$
+
+#include "scaledlg.h"
+
+#include <qvbox.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qspinbox.h>
+#include <qcheckbox.h>
+#include <qgroupbox.h>
+#include <qsize.h>
+
+#include <kdebug.h>
+#include <kcombobox.h>
+#include <klocale.h>
+#include <kdialog.h>
+#include "kfloatspinbox.h"
+#include <kglobal.h>
+
+#define ONEINCHINMM 2.54
+
+ScaleDlg::ScaleDlg( const QSize & origsize, QVBox * parent, const char * name )
+ : QObject( parent, name )
+ , m_origsize( origsize )
+ , m_newsizeunit( 0 )
+ , m_newsizeunit2( 0 )
+ , m_resolutionunit( 0 )
+ , m_newwidth( origsize.width() )
+ , m_newheight( origsize.height() )
+ , m_resx( 72 )
+ , m_resy( 72 )
+{
+ QGroupBox * pixelgroup = new QGroupBox( i18n( "Pixel Dimensions" ), parent );
+ QGroupBox * printgroup = new QGroupBox( i18n( "Print Size && Display Units" ), parent );
+
+ QGridLayout * pixelgroupgrid = new QGridLayout( pixelgroup, 1, 1,
+ KDialog::marginHint(), KDialog::spacingHint() );
+ QGridLayout * printgroupgrid = new QGridLayout( printgroup, 1, 1,
+ KDialog::marginHint(), KDialog::spacingHint() );
+
+ QLabel * label;
+
+ pixelgroupgrid->addRowSpacing( 0, KDialog::spacingHint() );
+
+ label = new QLabel( i18n( "Original width:" ), pixelgroup );
+ label->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) );
+ pixelgroupgrid->addWidget( label, 1, 0 );
+ label = new QLabel( i18n( "Height:" ), pixelgroup );
+ label->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) );
+ pixelgroupgrid->addWidget( label, 2, 0 );
+
+ pixelgroupgrid->addRowSpacing( 3, KDialog::spacingHint() );
+
+ label = new QLabel( i18n( "New width:" ), pixelgroup );
+ label->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) );
+ pixelgroupgrid->addWidget( label, 4, 0 );
+ label = new QLabel( i18n( "Height:" ), pixelgroup );
+ label->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) );
+ pixelgroupgrid->addWidget( label, 5, 0 );
+
+ pixelgroupgrid->addRowSpacing( 6, KDialog::spacingHint() );
+
+ label = new QLabel( i18n( "Ratio X:" ), pixelgroup );
+ label->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) );
+ pixelgroupgrid->addWidget( label, 7, 0 );
+ label = new QLabel( i18n( "Y:" ), pixelgroup );
+ label->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) );
+ pixelgroupgrid->addWidget( label, 8, 0 );
+
+ printgroupgrid->addRowSpacing( 0, KDialog::spacingHint() );
+
+ label = new QLabel( i18n( "New width:" ), printgroup );
+ label->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) );
+ printgroupgrid->addWidget( label, 1, 0 );
+ label = new QLabel( i18n( "Height:" ), printgroup );
+ label->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) );
+ printgroupgrid->addWidget( label, 2, 0 );
+
+ printgroupgrid->addRowSpacing( 3, KDialog::spacingHint() );
+
+ label = new QLabel( i18n( "Resolution X:" ), printgroup );
+ label->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) );
+ printgroupgrid->addWidget( label, 4, 0 );
+ label = new QLabel( i18n( "Y:" ), printgroup );
+ label->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) );
+ printgroupgrid->addWidget( label, 5, 0 );
+
+ m_pOldWidth = new QLabel( QString::number( origsize.width() ), pixelgroup );
+ m_pOldWidth->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) );
+ pixelgroupgrid->addWidget( m_pOldWidth, 1, 1 );
+ m_pOldHeight = new QLabel( QString::number( origsize.height() ), pixelgroup );
+ m_pOldHeight->setAlignment( int( QLabel::AlignVCenter | QLabel::AlignRight ) );
+ pixelgroupgrid->addWidget( m_pOldHeight, 2, 1 );
+
+ m_pNewWidth = new KFloatSpinBox( 1.0, 100000.0, 10.0, 0, pixelgroup );
+ pixelgroupgrid->addWidget( m_pNewWidth, 4, 1 );
+ m_pNewHeight = new KFloatSpinBox( 1.0, 100000.0, 10.0, 0, pixelgroup );
+ pixelgroupgrid->addWidget( m_pNewHeight, 5, 1 );
+
+ m_pNewSizeUnit = new KComboBox( pixelgroup );
+ m_pNewSizeUnit->insertItem( i18n( "px" ) );
+ m_pNewSizeUnit->insertItem( i18n( "%" ) );
+ pixelgroupgrid->addMultiCellWidget( m_pNewSizeUnit, 4, 5, 2, 2, Qt::AlignVCenter );
+
+ m_pRatioX = new KFloatSpinBox( 0.0001, 10000.0, 0.1, 4, pixelgroup );
+ pixelgroupgrid->addWidget( m_pRatioX, 7, 1 );
+ m_pRatioY = new KFloatSpinBox( 0.0001, 10000.0, 0.1, 4, pixelgroup );
+ pixelgroupgrid->addWidget( m_pRatioY, 8, 1 );
+
+ m_pLinkRatio = new QCheckBox( i18n( "Link" ), pixelgroup );
+ pixelgroupgrid->addMultiCellWidget( m_pLinkRatio, 7, 8, 2, 2, Qt::AlignVCenter );
+
+ m_pNewWidth2 = new KFloatSpinBox( 0.0001, 10000.0, 0.1, 4, printgroup );
+ printgroupgrid->addWidget( m_pNewWidth2, 1, 1 );
+ m_pNewHeight2 = new KFloatSpinBox( 0.0001, 10000.0, 0.1, 4, printgroup );
+ printgroupgrid->addWidget( m_pNewHeight2, 2, 1 );
+
+ m_pNewSizeUnit2 = new KComboBox( printgroup );
+ m_pNewSizeUnit2->insertItem( i18n( "in" ) );
+ m_pNewSizeUnit2->insertItem( i18n( "mm" ) );
+ printgroupgrid->addMultiCellWidget( m_pNewSizeUnit2, 1, 2, 2, 2, Qt::AlignVCenter );
+
+ m_pResolutionX = new KFloatSpinBox( 0.0001, 6000.0, 1.0, 4, printgroup );
+ printgroupgrid->addWidget( m_pResolutionX, 4, 1 );
+ m_pResolutionY = new KFloatSpinBox( 0.0001, 6000.0, 1.0, 4, printgroup );
+ printgroupgrid->addWidget( m_pResolutionY, 5, 1 );
+
+ m_pLinkResolution = new QCheckBox( i18n( "Link" ), printgroup );
+ printgroupgrid->addMultiCellWidget( m_pLinkResolution, 4, 5, 2, 2, Qt::AlignVCenter );
+ m_pResolutionUnit = new KComboBox( printgroup );
+ m_pResolutionUnit->insertItem( i18n( "pixels/in" ) );
+ m_pResolutionUnit->insertItem( i18n( "pixels/mm" ) );
+ printgroupgrid->addMultiCellWidget( m_pResolutionUnit, 6, 6, 1, 2, Qt::AlignLeft );
+
+ m_pNewWidth->setValue( m_origsize.width() );
+ m_pNewHeight->setValue( m_origsize.height() );
+
+ m_newsizeunit = 0;
+ m_newsizeunit2 = 0;
+ m_resolutionunit = 0;
+
+ connect( m_pNewWidth, SIGNAL( valueChanged( float ) ), SLOT( slotNewWidth( float ) ) );
+ connect( m_pNewHeight, SIGNAL( valueChanged( float ) ), SLOT( slotNewHeight( float ) ) );
+ connect( m_pNewWidth2, SIGNAL( valueChanged( float ) ), SLOT( slotNewWidth2( float ) ) );
+ connect( m_pNewHeight2, SIGNAL( valueChanged( float ) ), SLOT( slotNewHeight2( float ) ) );
+ connect( m_pResolutionX, SIGNAL( valueChanged( float ) ), SLOT( slotResolutionX( float ) ) );
+ connect( m_pResolutionY, SIGNAL( valueChanged( float ) ), SLOT( slotResolutionY( float ) ) );
+
+ connect( m_pNewSizeUnit, SIGNAL( activated( int ) ), SLOT( slotChangeNewSizeUnit( int ) ) );
+ connect( m_pNewSizeUnit2, SIGNAL( activated( int ) ), SLOT( slotChangeNewSizeUnit2( int ) ) );
+ connect( m_pResolutionUnit, SIGNAL( activated( int ) ), SLOT( slotChangeResolutionUnit( int ) ) );
+}
+
+ScaleDlg::~ScaleDlg()
+{
+}
+
+void ScaleDlg::slotNewWidth( float newval )
+{
+ float newwidth;
+ switch( m_newsizeunit )
+ {
+ case 0: // Pixel
+ newwidth = newval;
+ break;
+ case 1: // Percent
+ newwidth = newval / 100.0 * m_origsize.width();
+ break;
+ default:
+ kdError( 4630 ) << "unknown unit\n";
+ break;
+ }
+
+ m_newwidth = newwidth;
+ m_pNewWidth2->setValueBlocking( m_newwidth / m_resx / ( m_newsizeunit2 ? ONEINCHINMM : 1 ) );
+ m_pRatioX->setValueBlocking( m_newwidth / m_origsize.width() );
+ if( m_pLinkRatio->isChecked() )
+ {
+ m_newheight = m_newwidth / m_origsize.width() * m_origsize.height();
+ m_pNewHeight->setValueBlocking( m_newheight * ( m_newsizeunit ? 100.0 / m_origsize.height() : 1 ) );
+ m_pRatioY->setValueBlocking( m_newheight / m_origsize.height() );
+ m_pNewHeight2->setValueBlocking( m_newheight / m_resy / ( m_newsizeunit2 ? ONEINCHINMM : 1 ) );
+ }
+}
+
+void ScaleDlg::slotNewHeight( float newval )
+{
+}
+
+void ScaleDlg::slotNewWidth2( float newval )
+{
+}
+
+void ScaleDlg::slotNewHeight2( float newval )
+{
+}
+
+void ScaleDlg::slotResolutionX( float newval )
+{
+}
+
+void ScaleDlg::slotResolutionY( float newval )
+{
+}
+
+void ScaleDlg::slotChangeNewSizeUnit( int index )
+{
+ if( m_newsizeunit == index )
+ return;
+
+ m_newsizeunit = index;
+
+ switch( m_newsizeunit )
+ {
+ case 0:
+ // Pixel
+ m_pNewWidth->setRange( 1.0, 100000.0, 10.0, 0 );
+ m_pNewHeight->setRange( 1.0, 100000.0, 10.0, 0 );
+ m_pNewWidth->setValueBlocking( m_newwidth );
+ m_pNewHeight->setValueBlocking( m_newheight );
+ break;
+ case 1:
+ // Percent
+ m_pNewWidth->setRange( 0.0001, 100000.0, 0.1, 4 );
+ m_pNewHeight->setRange( 0.0001, 100000.0, 0.1, 4 );
+ m_pNewWidth->setValueBlocking( m_newwidth * 100.0 / m_origsize.width() );
+ m_pNewHeight->setValueBlocking( m_newheight * 100.0 / m_origsize.height() );
+ break;
+ default:
+ kdError( 4630 ) << "change to unknown unit\n";
+ break;
+ }
+}
+
+void ScaleDlg::slotChangeNewSizeUnit2( int index )
+{
+ if( m_newsizeunit2 == index )
+ return;
+
+ m_newsizeunit2 = index;
+
+ switch( m_newsizeunit2 )
+ {
+ case 0:
+ // Inch
+ m_pNewWidth2->setRange( 0.0001, 10000.0, 0.1, 4 );
+ m_pNewHeight2->setRange( 0.0001, 10000.0, 0.1, 4 );
+ m_pNewWidth2->setValueBlocking( m_newwidth / m_resx );
+ m_pNewHeight2->setValueBlocking( m_newheight / m_resy );
+ break;
+ case 1:
+ // Millimeter
+ m_pNewWidth2->setRange( 0.0002, 25400.0, 0.1, 4 );
+ m_pNewHeight2->setRange( 0.0002, 25400.0, 0.1, 4 );
+ m_pNewWidth2->setValueBlocking( m_newwidth / m_resx / ONEINCHINMM );
+ m_pNewHeight2->setValueBlocking( m_newheight / m_resy / ONEINCHINMM );
+ break;
+ default:
+ kdError( 4630 ) << "change to unknown unit\n";
+ break;
+ }
+}
+
+void ScaleDlg::slotChangeResolutionUnit( int index )
+{
+ if( m_resolutionunit == index )
+ return;
+
+ m_resolutionunit = index;
+
+ switch( m_resolutionunit )
+ {
+ case 0:
+ // Pixels per Inch
+ m_pResolutionX->setRange( 0.0002, 25400.0, 0.1, 4 );
+ m_pResolutionY->setRange( 0.0002, 25400.0, 0.1, 4 );
+ m_pResolutionX->setValueBlocking( m_resx );
+ m_pResolutionY->setValueBlocking( m_resy );
+ break;
+ case 1:
+ // Pixels per Millimeter
+ m_pResolutionX->setRange( 0.0001, 10000.0, 0.1, 4 );
+ m_pResolutionY->setRange( 0.0001, 10000.0, 0.1, 4 );
+ m_pResolutionX->setValueBlocking( m_resx / ONEINCHINMM );
+ m_pResolutionY->setValueBlocking( m_resy / ONEINCHINMM );
+ break;
+ default:
+ kdError( 4630 ) << "change to unknown unit\n";
+ break;
+ }
+}
+
+#include "scaledlg.moc"
diff --git a/kview/modules/scale/scaledlg.h b/kview/modules/scale/scaledlg.h
new file mode 100644
index 00000000..ac5a6c44
--- /dev/null
+++ b/kview/modules/scale/scaledlg.h
@@ -0,0 +1,78 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+
+*/
+
+// $Id$
+
+#ifndef __scaledlg_h_
+#define __scaledlg_h_
+
+#include <qobject.h>
+
+class QLabel;
+class KFloatSpinBox;
+class KComboBox;
+class QCheckBox;
+class QVBox;
+class QSize;
+
+class ScaleDlg : public QObject
+{
+ Q_OBJECT
+ public:
+ ScaleDlg( const QSize & originalsize, QVBox * parent, const char * name = 0 );
+ ~ScaleDlg();
+
+ private slots:
+ void slotNewWidth( float );
+ void slotNewHeight( float );
+ void slotNewWidth2( float );
+ void slotNewHeight2( float );
+ void slotResolutionX( float );
+ void slotResolutionY( float );
+ void slotChangeNewSizeUnit( int );
+ void slotChangeNewSizeUnit2( int );
+ void slotChangeResolutionUnit( int );
+
+ private:
+ QSize m_origsize;
+ int m_newsizeunit;
+ int m_newsizeunit2;
+ int m_resolutionunit;
+
+ float m_newwidth, m_newheight; // in Pixel
+ float m_resx, m_resy; // in dpi
+
+ QLabel * m_pOldWidth;
+ QLabel * m_pOldHeight;
+ KFloatSpinBox * m_pNewWidth;
+ KFloatSpinBox * m_pNewHeight;
+ KComboBox * m_pNewSizeUnit;
+ KFloatSpinBox * m_pRatioX;
+ KFloatSpinBox * m_pRatioY;
+ QCheckBox * m_pLinkRatio;
+
+ KFloatSpinBox * m_pNewWidth2;
+ KFloatSpinBox * m_pNewHeight2;
+ KComboBox * m_pNewSizeUnit2;
+ KFloatSpinBox * m_pResolutionX;
+ KFloatSpinBox * m_pResolutionY;
+ QCheckBox * m_pLinkResolution;
+ KComboBox * m_pResolutionUnit;
+};
+
+#endif
diff --git a/kview/modules/scanner/Makefile.am b/kview/modules/scanner/Makefile.am
new file mode 100644
index 00000000..83a22b32
--- /dev/null
+++ b/kview/modules/scanner/Makefile.am
@@ -0,0 +1,15 @@
+INCLUDES = -I$(top_srcdir)/kview $(all_includes)
+
+kde_module_LTLIBRARIES = kview_scannerplugin.la
+
+kview_scannerplugin_la_SOURCES = kviewscanner.cpp
+kview_scannerplugin_la_LIBADD = $(LIB_KFILE) $(LIB_KPARTS) -lkdeprint
+kview_scannerplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+
+plugdir = $(kde_datadir)/kview/kpartplugins
+plug_DATA = kviewscanner.desktop kviewscanner.rc
+
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp *.h -o $(podir)/kviewscannerplugin.pot
diff --git a/kview/modules/scanner/kviewscanner.cpp b/kview/modules/scanner/kviewscanner.cpp
new file mode 100644
index 00000000..d1f96e5f
--- /dev/null
+++ b/kview/modules/scanner/kviewscanner.cpp
@@ -0,0 +1,96 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+
+*/
+
+// $Id$
+
+#include "kviewscanner.h"
+
+#include <qimage.h>
+#include <qobjectlist.h>
+
+#include <kaction.h>
+#include <kinstance.h>
+#include <klocale.h>
+#include <kgenericfactory.h>
+#include <kscan.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <kimageviewer/viewer.h>
+
+typedef KGenericFactory<KViewScanner> KViewScannerFactory;
+K_EXPORT_COMPONENT_FACTORY( kview_scannerplugin, KViewScannerFactory( "kviewscannerplugin" ) )
+
+KViewScanner::KViewScanner( QObject* parent, const char* name,
+ const QStringList & )
+ : Plugin( parent, name ),
+ m_pScandlg( 0 ),
+ m_pViewer( 0 )
+{
+ QObjectList * viewerList = parent->queryList( 0, "KImageViewer Part", false, false );
+ m_pViewer = static_cast<KImageViewer::Viewer *>( viewerList->getFirst() );
+ delete viewerList;
+ if( m_pViewer )
+ {
+ (void) new KAction( i18n( "&Scan Image..." ), "scanner", 0,
+ this, SLOT( slotScan() ),
+ actionCollection(), "plugin_scan" );
+ }
+ else
+ kdWarning( 4630 ) << "no KImageViewer interface found - the scanner plugin won't work" << endl;
+}
+
+KViewScanner::~KViewScanner()
+{
+}
+
+void KViewScanner::slotScan()
+{
+ if( ! m_pScandlg )
+ {
+ m_pScandlg = KScanDialog::getScanDialog();
+ if( m_pScandlg )
+ {
+ m_pScandlg->setMinimumSize( 300, 300 );
+
+ connect( m_pScandlg, SIGNAL( finalImage( const QImage &, int ) ),
+ this, SLOT( slotImgScanned( const QImage & ) ) );
+ }
+ else
+ {
+ KMessageBox::sorry( 0L,
+ i18n( "You do not appear to have SANE support, or your scanner "
+ "is not attached properly. Please check these items before "
+ "scanning again." ),
+ i18n( "No Scan-Service Available" ) );
+ kdDebug( 4630 ) << "*** No Scan-service available, aborting!" << endl;
+ return;
+ }
+ }
+
+ if( m_pScandlg->setup() )
+ m_pScandlg->show();
+}
+
+void KViewScanner::slotImgScanned( const QImage & img )
+{
+ kdDebug( 4630 ) << "received an image from the scanner" << endl;
+ m_pViewer->newImage( img );
+}
+
+// vim:sw=4:ts=4:cindent
+#include "kviewscanner.moc"
diff --git a/kview/modules/scanner/kviewscanner.desktop b/kview/modules/scanner/kviewscanner.desktop
new file mode 100644
index 00000000..99abe5ff
--- /dev/null
+++ b/kview/modules/scanner/kviewscanner.desktop
@@ -0,0 +1,127 @@
+[Desktop Entry]
+Icon=scanner
+Type=Service
+ServiceTypes=KPluginInfo
+
+X-KDE-PluginInfo-Author=Matthias Kretz
+X-KDE-PluginInfo-Email=kretz@kde.org
+X-KDE-PluginInfo-Name=kviewscanner
+X-KDE-PluginInfo-Version=1.0
+X-KDE-PluginInfo-License=GPL
+X-KDE-PluginInfo-EnabledByDefault=false
+
+Name=Scanner
+Name[af]=Skandeerder
+Name[ar]=الماسح الضوئي
+Name[bg]=Скенер
+Name[br]=Eiltreser
+Name[bs]=Skener
+Name[ca]=Escàner
+Name[cy]=Sganiwr
+Name[da]=Skanner
+Name[el]=Σαρωτής
+Name[eo]=Skanilo
+Name[et]=Skänner
+Name[eu]=Eskanerra
+Name[fa]=پویشگر
+Name[fi]=Skanneri
+Name[fo]=Ljóslesari
+Name[ga]=Scanóir
+Name[gl]=Escáner
+Name[he]=סורק
+Name[hi]=स्कैनर
+Name[hr]=Skener
+Name[hu]=Lapolvasó
+Name[is]=Skanni
+Name[ja]=スキャナ
+Name[kk]=Сканер
+Name[km]=ម៉ាស៊ីន​ស្កេន
+Name[lt]=Skaneris
+Name[ms]=Pengimbas
+Name[nb]=Skanner
+Name[nds]=Bildinleser
+Name[ne]=स्क्यानर
+Name[nl]=Scanprogramma
+Name[nn]=Skannar
+Name[nso]=Selebeledi
+Name[pa]=ਸਕੈਨਰ
+Name[pl]=Skaner
+Name[pt]=Digitalizador
+Name[pt_BR]=Digitalizador
+Name[ro]=Scaner
+Name[ru]=Сканер
+Name[se]=Skánner
+Name[sk]=Skener
+Name[sl]=Skener
+Name[sr]=Скенер
+Name[sr@Latn]=Skener
+Name[sv]=Bildläsare
+Name[ta]=வருடி
+Name[tg]=Сканер
+Name[tr]=Tarayıcı
+Name[uk]=Сканер
+Name[uz]=Skanner
+Name[uz@cyrillic]=Сканнер
+Name[ven]=Tshinanguludzi
+Name[wa]=Sicanrece
+Name[xh]=Umvavanyi
+Name[zh_CN]=扫描仪
+Name[zh_HK]=掃描器
+Name[zh_TW]=掃描器
+Name[zu]=Umhloli
+Comment=Open images from your scanner into KView
+Comment[af]=Open beelde van jou skandeerder binnein K-bekyk
+Comment[ar]=يفتح الصور الموجودة على ماسحك الضوئي في برنامج KView
+Comment[bg]=Сканиране и отваряне на изображения от скенера
+Comment[bs]=Otvara slike sa skenera u KView
+Comment[ca]=Obre les imatges de l'escàner a KView
+Comment[cs]=Otevírá obrázky ze skeneru do KView
+Comment[cy]=Agor delweddau oddiwrth eich sganiwr yn KGweld
+Comment[da]=åbn billeder fra din skanner til KView
+Comment[de]=Lädt Bilder vom Scanner in KView
+Comment[el]=Ανοίξτε εικόνες από το σαρωτή σας στο KView
+Comment[es]=Abre imágenes desde su escáner en KView
+Comment[et]=Avab skaneeritud pilte rakendusega KView
+Comment[eu]=Zure eskanerretik irudiak KView-en erakusten ditu
+Comment[fa]=باز کردن تصاویر از پویشگرتان در KView
+Comment[fi]=Avaa kuvan skannerilta KView-ohjelmaan
+Comment[fr]=Ouvre des images de votre scanner dans KView
+Comment[gl]=Obre as imaxes do teu escáner en KView
+Comment[he]=פתיחת תמונות מהסורק שלך ב־KView
+Comment[hi]=आपके स्कैनर से के-व्यू में छवि खोलता है
+Comment[hu]=Kép beolvasása lapolvasóról a KView-ba
+Comment[is]=Senda myndir frá skannanum í KView
+Comment[it]=Apre le immagini provenienti dallo scanner in KView
+Comment[ja]=スキャナから画像を開き KView に転送します
+Comment[kk]=Сканерден KView-ға кескінді түсіру
+Comment[km]=បើក​រូបភាព​ពី​ម៉ាស៊ីន​ស្កេន​របស់​អ្នក​ក្នុង KView
+Comment[lt]=Atveria paveikslėlius iš Jūsų skanerio į KView
+Comment[ms]=Buka imej dari pengimbas anda ke dalam KView
+Comment[nb]=Åpner bilder fra skanneren til KView
+Comment[nds]=Haalt Biller vun Dien Inleser na KView
+Comment[ne]=तपाईँको स्क्यानरबाट केडीई दृश्य भित्र छवि खोल्नुहोस्
+Comment[nl]=Scan afbeeldingen rechtstreeks in KView
+Comment[nn]=Opnar bilete frå skannaren i KView
+Comment[nso]=Bula diponagalo gotswa go selebeledi sa gago goya kago KView
+Comment[pl]=Otwiera obrazki ze skanera w przeglądarce KView
+Comment[pt]=Abrir as imagens do seu 'scanner' no KView
+Comment[pt_BR]=Abre imagens do seu digitalizador no KVisualização
+Comment[ro]=Deschide imagini din scaner în KView
+Comment[ru]=Сканирование изображений в KView
+Comment[se]=Rahpá govaid skánneris KView:as
+Comment[sk]=Otvorí obrázky z vášho skeneru v KView
+Comment[sl]=Odpre sliko iz vašega skenerja v KView
+Comment[sr]=Отвара слике из вашег скенера у KView-у
+Comment[sr@Latn]=Otvara slike iz vašeg skenera u KView-u
+Comment[sv]=Öppnar bilder från bildläsaren i Kview
+Comment[ta]= கேகாட்சியின் வருடியில் இருந்து பிம்பங்களைத் திற
+Comment[tg]=Сканеронии тасвирот дар KView
+Comment[tr]=Tarayıcıdan KView'a resim gönderin
+Comment[uk]=Відкриває зображення з вашого сканера в KView
+Comment[ven]=Vulani zwifanyiso ubva kha tshinanguludzi uya kha mbonalelo ya K
+Comment[wa]=Drovi des imådjes di vosse sicanrece avou KView
+Comment[xh]=Vula imifanekiso evela kumvavanyisi wakho kwi KView
+Comment[zh_CN]=从您的扫描仪中打开图像至 KView
+Comment[zh_HK]=從您的掃描器開啟圖像至 KView
+Comment[zh_TW]=從您的掃描器開啟影像至 KView
+Comment[zu]=Vula izithombe ezisuka kumhloli wakho kwi-KView
diff --git a/kview/modules/scanner/kviewscanner.h b/kview/modules/scanner/kviewscanner.h
new file mode 100644
index 00000000..cdb32d67
--- /dev/null
+++ b/kview/modules/scanner/kviewscanner.h
@@ -0,0 +1,50 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Matthias Kretz <kretz@kde.org>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation.
+
+ 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.
+
+*/
+
+// $Id$
+
+#ifndef __kviewscanner_h
+#define __kviewscanner_h
+
+#include <kparts/plugin.h>
+#include <klibloader.h>
+
+class KURL;
+class KScanDialog;
+namespace KImageViewer { class Viewer; }
+
+class KViewScanner : public KParts::Plugin
+{
+ Q_OBJECT
+public:
+ KViewScanner( QObject* parent, const char* name, const QStringList & );
+ virtual ~KViewScanner();
+
+//public slots:
+
+private slots:
+ void slotScan();
+ void slotImgScanned( const QImage & );
+
+private:
+ KScanDialog * m_pScandlg;
+ KImageViewer::Viewer * m_pViewer;
+};
+
+// vim:sw=4:ts=4:cindent
+#endif
diff --git a/kview/modules/scanner/kviewscanner.rc b/kview/modules/scanner/kviewscanner.rc
new file mode 100644
index 00000000..43e60593
--- /dev/null
+++ b/kview/modules/scanner/kviewscanner.rc
@@ -0,0 +1,12 @@
+<!DOCTYPE kpartgui>
+<kpartplugin name="kviewscanner" library="kview_scannerplugin">
+ <MenuBar>
+ <Menu name="tools"><Text>&amp;Tools</Text>
+ <Action name="plugin_scan"/>
+ </Menu>
+ </MenuBar>
+ <ToolBar name="extraToolBar">
+ <text>Extra Toolbar</text>
+ <Action name="plugin_scan"/>
+ </ToolBar>
+</kpartplugin>
diff --git a/kview/modules/template/Makefile.am b/kview/modules/template/Makefile.am
new file mode 100644
index 00000000..29ddc94c
--- /dev/null
+++ b/kview/modules/template/Makefile.am
@@ -0,0 +1,15 @@
+INCLUDES = -I$(top_srcdir)/kview $(all_includes)
+
+kde_module_LTLIBRARIES = kview_templateplugin.la
+
+kview_templateplugin_la_SOURCES = kviewtemplate.cpp
+kview_templateplugin_la_LIBADD = $(LIB_KFILE) $(LIB_KPARTS) -lkdeprint
+kview_templateplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+
+plugdir = $(kde_datadir)/kview/kpartplugins
+plug_DATA = kviewtemplate.desktop kviewtemplate.rc
+
+METASOURCES = AUTO
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp *.h -o $(podir)/kviewtemplateplugin.pot
diff --git a/kview/modules/template/kviewtemplate.cpp b/kview/modules/template/kviewtemplate.cpp
new file mode 100644
index 00000000..c8c6dc9d
--- /dev/null
+++ b/kview/modules/template/kviewtemplate.cpp
@@ -0,0 +1,43 @@
+/* This file is in the public domain */
+
+// $Id$
+
+#include "kviewtemplate.h"
+
+#include <qobjectlist.h>
+
+#include <kaction.h>
+/*#include <klocale.h>*/
+#include <kgenericfactory.h>
+#include <kdebug.h>
+#include <kimageviewer/viewer.h>
+
+typedef KGenericFactory<KViewTemplate> KViewTemplateFactory;
+K_EXPORT_COMPONENT_FACTORY( kview_templateplugin, KViewTemplateFactory( "kviewtemplateplugin" ) )
+
+KViewTemplate::KViewTemplate( QObject* parent, const char* name, const QStringList & )
+ : Plugin( parent, name )
+{
+ QObjectList * viewerList = parent->queryList( 0, "KImageViewer Part", false, false );
+ m_pViewer = static_cast<KImageViewer::Viewer *>( viewerList->getFirst() );
+ delete viewerList;
+ if( m_pViewer )
+ {
+ (void) new KAction( /*i18n(*/ "&Do Something" /*)*/, 0, 0,
+ this, SLOT( yourSlot() ),
+ actionCollection(), "plugin_template" );
+ }
+ else
+ kdWarning( 4630 ) << "no KImageViewer interface found - the template plugin won't work" << endl;
+}
+
+KViewTemplate::~KViewTemplate()
+{
+}
+
+void KViewTemplate::yourSlot()
+{
+}
+
+// vim:sw=4:ts=4:cindent
+#include "kviewtemplate.moc"
diff --git a/kview/modules/template/kviewtemplate.desktop b/kview/modules/template/kviewtemplate.desktop
new file mode 100644
index 00000000..e1039d06
--- /dev/null
+++ b/kview/modules/template/kviewtemplate.desktop
@@ -0,0 +1,129 @@
+[Desktop Entry]
+Icon=mypluginicon
+Type=Service
+ServiceTypes=KPluginInfo
+
+X-KDE-PluginInfo-Author=Your Name
+X-KDE-PluginInfo-Email=Your@address
+X-KDE-PluginInfo-Name=kviewtemplate
+X-KDE-PluginInfo-Version=0.1
+X-KDE-PluginInfo-License=Public Domain
+X-KDE-PluginInfo-EnabledByDefault=true
+
+Name=Template
+Name[af]=Werkvoorbeeld
+Name[ar]=قالب
+Name[bg]=Шаблон
+Name[br]=Patrom
+Name[bs]=Šablon
+Name[ca]=Plantilla
+Name[cs]=Šablona
+Name[cy]=Patrymlun
+Name[da]=Skabelon
+Name[de]=Vorlage
+Name[el]=Πρότυπο
+Name[eo]=Ŝablono
+Name[es]=Plantilla
+Name[et]=Mallid
+Name[eu]=Txantiloia
+Name[fa]=قالب
+Name[fi]=Pohja
+Name[fr]=Modèle
+Name[ga]=Teimpléad
+Name[gl]=Modelo
+Name[he]=תבנית
+Name[hi]=टैम्प्लेट
+Name[hu]=Sablon
+Name[is]=Snið
+Name[it]=Modello
+Name[ja]=テンプレート
+Name[kk]=Үлгі
+Name[km]=ពុម្ព
+Name[lt]=Šablonas
+Name[ms]=Templat
+Name[nb]=Mal
+Name[nds]=Vörlaag
+Name[ne]=टेम्प्लेट
+Name[nl]=Sjabloon
+Name[nn]=Mal
+Name[nso]=Papiso
+Name[pl]=Wzorzec
+Name[pt]=Modelo
+Name[pt_BR]=Modelo
+Name[ro]=Model
+Name[ru]=Шаблон
+Name[se]=Málle
+Name[sk]=Šablóna
+Name[sl]=Predloga
+Name[sr]=Шаблон
+Name[sr@Latn]=Šablon
+Name[sv]=Mall
+Name[ta]=வார்ப்புரு
+Name[tg]=Қолиб
+Name[tr]=Şablon
+Name[uk]=Шаблон
+Name[uz]=Namuna
+Name[uz@cyrillic]=Намуна
+Name[wa]=Modele
+Name[zh_CN]=模板
+Name[zh_HK]=範本
+Name[zh_TW]=範本
+Name[zu]=i-template
+Comment=A longer description of what the plugin does
+Comment[af]='n langer beskrywing van wat die inplak doen
+Comment[ar]=وصف أطول عن عمل البرنامج المساعد
+Comment[bg]=Подробно описание на приставката
+Comment[bs]=Duži opis onoga što dodatak radi
+Comment[ca]=Una descripció més llarga del que fa l'endollat
+Comment[cs]=Zde by měl být delší popis modulu
+Comment[cy]=Disgrifiad hirach o beth mae'r ategyn yn ei wneud
+Comment[da]=En længere beskrivelse af hvad dette plugin gør
+Comment[de]=Hier sollte eine längere Beschreibung des Moduls stehen
+Comment[el]=Μια μεγαλύτερη περιγραφή για το τι κάνει το πρόσθετο
+Comment[eo]=Pli longa priskribo pri la kromaĵo
+Comment[es]=Una descripción más completa de la función del plugin
+Comment[et]=Pluginate tegevuse pikemad kirjeldused
+Comment[eu]=Pluginak egiten duenaren azalpen luzeagoa
+Comment[fa]=توصیفی طولانی‌تر از آنچه وصله انجام می‌دهد
+Comment[fi]=Pidempi kuvaus, mitä liitännäinen tekee
+Comment[fr]=Une plus longue description de ce que fait le module
+Comment[gl]=Unha descrición máis longa do que pode facer a extensión
+Comment[he]=תיאור מפורט יותר לגבי מה שהתוסף עושה
+Comment[hi]=प्लगइन के बारे में लंबा वर्णन कि वह क्या करता है
+Comment[hr]=Duži opis umetka
+Comment[hu]=Ez a bővítőmodul részletesebb leírása
+Comment[is]=hér ætti að vera smá lýsing á hvað þetta gerir
+Comment[it]=Una descrizione più lunga di quello che fa il plugin
+Comment[ja]=ここにより詳細なプラグインの記述をします
+Comment[kk]=Плагин модульдің түсініктемесі
+Comment[km]=សេចក្ដី​ពណ៌នា​វែង អំពី​មុខងារ​របស់​កម្មវិធី​ជំនួយ
+Comment[lt]=Ilgesnis aprašymas, ką daro priedas
+Comment[ms]=Huraian panjang tentang apa yang plugin lakukan
+Comment[nb]=En lengre beskrivelse av hva modulen gjør
+Comment[nds]=En länger Beschrieven vun't Könen vun dat Moduul
+Comment[ne]=प्लगइनले गर्ने कामको बारेमा लामो वर्णन
+Comment[nl]=Plaats hier een kleine omschrijving van uw plugin
+Comment[nn]=Ei lengre skildring av kva modulen gjer
+Comment[nso]=Thlaloso ye telele ya seo ya seo plugin ese dirago
+Comment[pl]=Dłuższy opis tego, co wtyczka robi
+Comment[pt]=Uma descrição mais extensa do que o 'plugin' faz
+Comment[pt_BR]= Uma descrição maior do que um plugin faz
+Comment[ro]=O descriere mai lungă a modulului
+Comment[ru]=А здесь должно быть описание модуля
+Comment[se]=Guhkkit čilgehus mii muitala maid lassemoduvla bargá
+Comment[sk]=Tu by mal byť popis, čo modul robí
+Comment[sl]=Daljši opis, kaj naredi ta vstavek
+Comment[sr]=Дужи опис чему прикључак служи
+Comment[sr@Latn]=Duži opis čemu priključak služi
+Comment[sv]=En längre beskrivningen av vad insticksprogrammet gör
+Comment[ta]= சொருகுப்பொருள் செய்த பணியின் நீண்ட வருணனை
+Comment[tg]=Дар инҷо бояд тасвироти модул бошад
+Comment[tr]=Eklentinin uzun açıklaması
+Comment[uk]=Докладний опис можливостей втулку
+Comment[ven]=Thalutshedzo khulwane ya ine plugin ya ita zwone
+Comment[wa]=On discrijhaedje pus complet di çou k' est fwait på tchôke-divins
+Comment[xh]=Inkcazelo ende echaza ukuba iplagi ezingaphakathi zenza ntoni na
+Comment[zh_CN]=这里应该填写插件功能详细一点的描述
+Comment[zh_HK]=這個插件的功用的較長描述
+Comment[zh_TW]=關於這個外掛程式的所做所為的較長描述
+Comment[zu]=incazelo ende yokuthi i-plugin yenzani
diff --git a/kview/modules/template/kviewtemplate.h b/kview/modules/template/kviewtemplate.h
new file mode 100644
index 00000000..1d158b05
--- /dev/null
+++ b/kview/modules/template/kviewtemplate.h
@@ -0,0 +1,27 @@
+/* This file is in the public domain */
+
+// $Id$
+
+#ifndef __kviewtemplate_h
+#define __kviewtemplate_h
+
+#include <kparts/plugin.h>
+
+namespace KImageViewer { class Viewer; }
+
+class KViewTemplate : public KParts::Plugin
+{
+ Q_OBJECT
+public:
+ KViewTemplate( QObject* parent, const char* name, const QStringList & );
+ virtual ~KViewTemplate();
+
+private slots:
+ void yourSlot();
+
+private:
+ KImageViewer::Viewer * m_pViewer;
+};
+
+// vim:sw=4:ts=4:cindent
+#endif
diff --git a/kview/modules/template/kviewtemplate.rc b/kview/modules/template/kviewtemplate.rc
new file mode 100644
index 00000000..03d51f57
--- /dev/null
+++ b/kview/modules/template/kviewtemplate.rc
@@ -0,0 +1,11 @@
+<!DOCTYPE kpartgui>
+<kpartplugin name="kviewtemplate" library="kview_templateplugin">
+ <MenuBar>
+ <Menu name="tools"><Text>&amp;Tools</Text>
+ <Action name="plugin_template"/>
+ </Menu>
+ </MenuBar>
+ <ToolBar name="extraToolBar">
+ <Action name="plugin_template"/>
+ </ToolBar>
+</kpartplugin>
diff --git a/kview/photobook/Makefile.am b/kview/photobook/Makefile.am
new file mode 100644
index 00000000..967a2def
--- /dev/null
+++ b/kview/photobook/Makefile.am
@@ -0,0 +1,19 @@
+
+INCLUDES = $(all_includes)
+
+kde_module_LTLIBRARIES = libphotobook.la
+
+libphotobook_la_SOURCES = photobook.cpp
+
+libphotobook_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries)
+libphotobook_la_LIBADD = $(LIB_KFILE) $(LIB_KPARTS)
+
+partrcdir = $(kde_servicesdir)
+partrc_DATA = photobook.desktop
+
+METASOURCES = AUTO
+
+KDE_ICON = photobook
+
+partdir = $(kde_datadir)/photobook
+part_DATA = photobookui.rc
diff --git a/kview/photobook/cr16-app-photobook.png b/kview/photobook/cr16-app-photobook.png
new file mode 100644
index 00000000..bfc9b9cc
--- /dev/null
+++ b/kview/photobook/cr16-app-photobook.png
Binary files differ
diff --git a/kview/photobook/cr22-app-photobook.png b/kview/photobook/cr22-app-photobook.png
new file mode 100644
index 00000000..915f3dba
--- /dev/null
+++ b/kview/photobook/cr22-app-photobook.png
Binary files differ
diff --git a/kview/photobook/photobook.cpp b/kview/photobook/photobook.cpp
new file mode 100644
index 00000000..082bfd49
--- /dev/null
+++ b/kview/photobook/photobook.cpp
@@ -0,0 +1,292 @@
+/*
+Copyright (c) 2004,2005 Charles Samuels <charles@kde.org>
+
+ This file is hereby licensed under the GNU General Public License version
+ 2 or later at your option.
+
+ This file is licensed under the Qt Public License version 1 with the
+ condition that the licensed will be governed under the Laws of California
+ (USA) instead of Norway. Disputes will be settled in Santa Clara county
+ courts.
+
+ This file is licensed under the following additional license. Be aware
+ that it is identical to the BSD license, except for the added clause 3:
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. By integrating this software into any other software codebase, you waive
+ all rights to any patents associated with the stated codebase.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include "photobook.h"
+
+#include <kparts/componentfactory.h>
+#include <kaction.h>
+#include <kstdaccel.h>
+#include <kstandarddirs.h>
+
+Previews::Previews(PhotoBook *parent, const QStringList &mimetypes)
+ : KFileIconView(parent, 0)
+{
+ mPhotoBook = parent;
+ mMimeTypes = mimetypes;
+
+ connect(&mDirLister, SIGNAL(clear()), SLOT(slotClearView()));
+ connect(&mDirLister, SIGNAL(completed()), SLOT(doneListing()));
+ connect(
+ &mDirLister, SIGNAL(newItems(const KFileItemList &)),
+ SLOT(insertNewFiles(const KFileItemList &))
+ );
+ connect(
+ signaler(), SIGNAL(fileSelected(const KFileItem*)),
+ SLOT(open(const KFileItem*))
+ );
+ connect(
+ &mDirLister, SIGNAL(deleteItem(KFileItem *)),
+ SLOT(removeItem(KFileItem *))
+ );
+
+ connect(
+ &mDirLister, SIGNAL( refreshItems( const KFileItemList& ) ),
+ SLOT( slotRefreshItems( const KFileItemList& ) )
+ );
+
+ setFixedWidth(128);
+}
+
+Previews::~Previews()
+{
+
+}
+
+
+void Previews::slotRefreshItems( const KFileItemList& items )
+{
+ KFileItemListIterator it( items );
+ for ( ; it.current(); ++it )
+ updateView( it.current() );
+}
+
+void Previews::slotClearView()
+{
+ clearView();
+}
+
+
+void Previews::insertNewFiles(const KFileItemList &items)
+{
+ addItemList(items);
+}
+
+void Previews::removeItem(KFileItem *item)
+{
+ KFileIconView::removeItem(item);
+}
+
+
+void Previews::go(const KFileItem *k)
+{
+ setSelected(k, true);
+ setCurrentItem(k);
+ ensureItemVisible(k);
+ open(k);
+ updateButton();
+}
+
+void Previews::updateButton()
+{
+ mPhotoBook->updateButton( ( nextItem(currentFileItem())!=0L ), ( prevItem(currentFileItem())!=0L ));
+}
+
+void Previews::openURL(const KURL &url)
+{
+ mDirLister.setMimeFilter(mMimeTypes);
+ mDirLister.openURL(url);
+}
+
+void Previews::open(const KFileItem *item)
+{
+ if (!item->isDir())
+ {
+ const KURL &u = item->url();
+ emit open(u);
+ updateButton();
+ }
+}
+
+void Previews::doneListing()
+{
+ // eep! -- this should not be necessary
+ QTimer::singleShot(0, this, SLOT(goToFirst()));
+}
+
+void Previews::goToFirst()
+{
+ if (firstFileItem())
+ go(firstFileItem());
+ else
+ updateButton();
+}
+
+
+
+PhotoBook::PhotoBook(QWidget *parent, PhotoBookPart *part, const char *name)
+ : QSplitter(parent, name)
+{
+
+ QStringList mimetypes;
+
+ KTrader::OfferList offers = KTrader::self()->query(
+ "KImageViewer/Viewer", "KParts/ReadOnlyPart",
+ "DesktopEntryName == 'kviewviewer'", QString::null
+ );
+
+ for (
+ KTrader::OfferList::Iterator i(offers.begin());
+ i != offers.end(); ++i
+ )
+ {
+ KService::Ptr service = *i;
+ mViewer = KParts::ComponentFactory::
+ createPartInstanceFromService<KParts::ReadOnlyPart>( service, this, 0, this );
+
+ // is this the correct way to get the supported mimetypes?
+ if (mViewer)
+ {
+ KSimpleConfig e(locate("services", service->desktopEntryPath()));
+ e.setGroup("Desktop Entry");
+ mimetypes = QStringList::split(';', e.readEntry("MimeType"));
+ break;
+ }
+ }
+
+
+ mList = new Previews(this, mimetypes);
+
+ mFit = mViewer->action("fittowin");
+
+ connect(mList, SIGNAL(open(const KURL&)), mViewer, SLOT(openURL(const KURL&)));
+ connect(mViewer, SIGNAL(completed()), mFit, SLOT(activate()));
+
+ part->insertChildClient(mViewer);
+}
+
+void PhotoBook::openURL(const KURL &url)
+{
+ mList->openURL(url);
+ mList->setIgnoreMaximumSize();
+ mList->showPreviews();
+}
+
+void PhotoBook::next()
+{
+ KFileItem *k = mList->nextItem(mList->currentFileItem());
+ if (k)
+ mList->go(k);
+}
+
+void PhotoBook::previous()
+{
+ KFileItem *k = mList->prevItem(mList->currentFileItem());
+ if (k)
+ mList->go(k);
+}
+
+
+void PhotoBook::updateButton( bool nextExist, bool previousExit)
+{
+ emit emitUpdateButton( nextExist, previousExit );
+}
+
+K_EXPORT_COMPONENT_FACTORY(libphotobook, PhotoBookFactory )
+
+PhotoBookPart::PhotoBookPart(
+ QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name,
+ const QStringList&
+ )
+ : KParts::ReadOnlyPart(parent, name)
+{
+ setInstance(PhotoBookFactory::instance());
+
+ new PhotoBookBrowserExtension(this);
+ bv = new PhotoBook(parentWidget, this, widgetName);
+ setWidget(bv);
+
+ connect(
+ bv, SIGNAL(emitUpdateButton(bool, bool)),
+ this, SLOT(slotUpdateButton(bool, bool))
+ );
+ m_pNextAction = KStdAction::next(bv, SLOT(next()), actionCollection(), "next");
+ m_pPreviousAction = KStdAction::prior(bv, SLOT(previous()), actionCollection(), "previous");
+
+ setXMLFile( "photobookui.rc" );
+
+}
+
+PhotoBookPart::~PhotoBookPart()
+{
+
+}
+
+
+void PhotoBookPart::slotUpdateButton( bool nextExit, bool previousExit)
+{
+ m_pPreviousAction->setEnabled( previousExit );
+ m_pNextAction->setEnabled( nextExit );
+}
+
+bool PhotoBookPart::openURL(const KURL &url)
+{
+ bv->openURL(url);
+ return true;
+}
+
+
+KAboutData* PhotoBookPart::createAboutData()
+{
+ return new KAboutData(
+ "photobook", I18N_NOOP("Photo Book"),
+ "1.0", I18N_NOOP("Easily browse a folder of photographs"),
+ KAboutData::License_GPL,
+ I18N_NOOP("Copyright (c) 2004,2005 Charles Samuels <charles@kde.org>")
+ );
+}
+
+bool PhotoBookPart::openFile()
+{
+ return true;
+}
+
+
+
+PhotoBookBrowserExtension::PhotoBookBrowserExtension(PhotoBookPart *p)
+ : KParts::BrowserExtension(p, "PhotoBookBrowserExtension")
+{
+
+}
+
+
+
+
+#include "photobook.moc"
+
diff --git a/kview/photobook/photobook.desktop b/kview/photobook/photobook.desktop
new file mode 100644
index 00000000..cb218a80
--- /dev/null
+++ b/kview/photobook/photobook.desktop
@@ -0,0 +1,131 @@
+[Desktop Entry]
+GenericName=Photobook
+GenericName[bg]=Фотоалбум
+GenericName[br]=Levr foto
+GenericName[ca]=Llibre de fotografies
+GenericName[da]=Fotoalbum
+GenericName[de]=Photobuch
+GenericName[es]=Libro de fotografías
+GenericName[et]=Fotoalbum
+GenericName[fa]=کتاب عکس
+GenericName[fi]=Valokuvakirja
+GenericName[fr]=Album photo
+GenericName[gl]=Libro de Fotografías
+GenericName[he]=ספר תמונות
+GenericName[hu]=Fényképalbum
+GenericName[is]=Myndabók
+GenericName[it]=Album fotografico
+GenericName[ja]=フォトブック
+GenericName[kk]=Фотоальбом
+GenericName[km]=សៀវភៅ​រូបថត
+GenericName[lt]=Fotoalbumas
+GenericName[ms]=Bukufoto
+GenericName[nb]=Fotoalbum
+GenericName[nds]=Fotoalbum
+GenericName[ne]=फोटो पुस्तक
+GenericName[nl]=Fotoboek
+GenericName[nn]=Fotoalbum
+GenericName[pa]=ਫੋਟੋ ਬੁੱਕ
+GenericName[pl]=Album ze zdjęciami
+GenericName[pt]=Álbum Fotográfico
+GenericName[pt_BR]=Álbum de Fotos
+GenericName[ro]=Colecţie de fotografii
+GenericName[sk]=Album fotiek
+GenericName[sl]=Album slik
+GenericName[sr]=Фотокњига
+GenericName[sr@Latn]=Fotoknjiga
+GenericName[sv]=Fotoalbum
+GenericName[ta]=புகைப்படப் புத்தகம்
+GenericName[tr]=Albüm
+GenericName[uz]=Rasmlar toʻplami
+GenericName[uz@cyrillic]=Расмлар тўплами
+GenericName[zh_HK]=照相簿
+
+MimeType=inode/directory
+Icon=photobook
+Name=Photobook
+Name[br]=Levr foto
+Name[ca]=Llibre de fotografies
+Name[da]=Fotoalbum
+Name[es]=Libro de fotografías
+Name[et]=Fotoalbum
+Name[fa]=کتاب عکس
+Name[fi]=Valokuvakirja
+Name[fr]=Album photo
+Name[gl]=Libro de Fotografías
+Name[he]=ספר תמונות
+Name[hu]=Fényképalbum
+Name[is]=Myndabók
+Name[it]=Album fotografico
+Name[kk]=Фотоальбом
+Name[km]=សៀវភៅ​រូបថត
+Name[lt]=Fotoalbumas
+Name[ms]=Bukufoto
+Name[nb]=Fotoalbum
+Name[ne]=फोटो पुस्तक
+Name[nl]=Fotoboek
+Name[nn]=Fotoalbum
+Name[pa]=ਫੋਟੋ ਬੁੱਕ
+Name[pl]=Album zdjęciowy
+Name[pt]=Álbum Fotográfico
+Name[pt_BR]=Álbum de Fotos
+Name[ro]=Colecţia de fotografii
+Name[sk]=Album fotiek
+Name[sr]=Фотокњига
+Name[sr@Latn]=Fotoknjiga
+Name[sv]=Fotoalbum
+Name[ta]=புகைப்படப் புத்தகம்
+Name[tr]=Albüm
+Name[uz]=Rasmlar toʻplami
+Name[uz@cyrillic]=Расмлар тўплами
+Name[zh_HK]=照相簿
+Comment=Easily browse a folder of photographs
+Comment[bg]=Колекциониране на снимки като във фотоалбум
+Comment[bs]=Jednostavno pregledajte direktorij sa fotografijama
+Comment[ca]=Mirar fàcilment una carpeta de fotografies
+Comment[cs]=Jednoduché prohlížení složek s fotkami
+Comment[da]=Mappe med fotografier, nem at gennemse
+Comment[de]=Auf einfache Weise einen Ordner nach Photos durchsuchen
+Comment[el]=Εύκολη περιήγηση σε ένα φάκελο φωτογραφιών
+Comment[es]=Vistazo rápido de una carpeta con fotografías
+Comment[et]=Fotode kausta mugav lehitsemine
+Comment[eu]=Arakatu argazki karpetak modu errazan
+Comment[fa]=مرور آسان پوشه‌ای از عکسها
+Comment[fi]=Selaile helpolla valokuvakansioita
+Comment[fr]=Naviguer facilement dans un dossier contenant des photos
+Comment[gl]=Explorar doadamente un cartafol de fotografías
+Comment[he]=דפדף בקלות בתיקייה המכילה תמונות
+Comment[hu]=Könyvtárba helyezett fényképek nézegetéséhez
+Comment[is]=Flettu á auðveldan hátt gegnum möppu með myndum
+Comment[it]=Sfoglia facilmente una cartella di fotografie
+Comment[ja]=写真を含むフォルダをブラウズ
+Comment[kk]=Қапшықтағы фотоларды шолу
+Comment[km]=រកមើល​ថត​រូបថត​យ៉ាង​ងាយស្រួល
+Comment[lt]=Lengvai naršykite fotografijų aplankus
+Comment[ms]=Layar folder fotograf dengan mudah
+Comment[nb]=Enkel lesing av mapper med bilder
+Comment[nds]=Op eenfache Oort en Foto-Orner dörkieken
+Comment[ne]=फोटोग्राफको फोल्डर सजिलै ब्राउज गर्नुहोस्
+Comment[nl]=Blader eenvoudig door een map met foto's
+Comment[nn]=Enkel vising av mapper med bilete
+Comment[pl]=Łatwe przeglądanie folderów ze zdjęciami
+Comment[pt]=Navegue facilmente numa pasta de fotografias
+Comment[pt_BR]=Navegue facilmente por uma pasta cheia de fotos
+Comment[ro]=Răsfoiţi cu uşurinţă un folder de fotografii
+Comment[ru]=Просмотр папок с фотографиями
+Comment[sk]=Jednoducho prehliada priečinky s fotografiami
+Comment[sl]=Zlahka brskajte po mapi s fotografijami
+Comment[sr]=Лако прегледајте фасциклу са сликама
+Comment[sr@Latn]=Lako pregledajte fasciklu sa slikama
+Comment[sv]=Bläddra enkelt i en katalog med fotografier
+Comment[ta]=புகைப்படங்களின் அடைவை சுலபமாக உலாவ
+Comment[tr]=Fotoğraflarla dolu bir dizini kolayca gez
+Comment[uk]=Простий перегляд тек з фотографіями
+Comment[zh_CN]=轻松浏览照片文件夹
+Comment[zh_HK]=容易地瀏覽資料夾的照片
+Comment[zh_TW]=輕易地瀏覽相片的資料夾
+ServiceTypes=KParts/ReadOnlyPart,Browser/View
+X-KDE-Library=libphotobook
+X-KDE-BrowserView-Args=DetailedList
+X-DCOP-ServiceType=Multi
+Type=Service
diff --git a/kview/photobook/photobook.h b/kview/photobook/photobook.h
new file mode 100644
index 00000000..3da5cf78
--- /dev/null
+++ b/kview/photobook/photobook.h
@@ -0,0 +1,140 @@
+/*
+Copyright (c) 2004 Charles Samuels <charles@kde.org>
+
+ This file is hereby licensed under the GNU General Public License version
+ 2 or later at your option.
+
+ This file is licensed under the Qt Public License version 1 with the
+ condition that the licensed will be governed under the Laws of California
+ (USA) instead of Norway. Disputes will be settled in Santa Clara county
+ courts.
+
+ This file is licensed under the following additional license. Be aware
+ that it is identical to the BSD license, except for the added clause 3:
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. By integrating this software into any other software codebase, you waive
+ all rights to any patents associated with the stated codebase.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef PHOTOBOOK_H
+#define PHOTOBOOK_H
+
+#include <qsplitter.h>
+#include <kfileiconview.h>
+#include <kdirlister.h>
+
+#include <kparts/part.h>
+#include <kparts/browserextension.h>
+#include <kparts/genericfactory.h>
+
+class Previews;
+class PhotoBookPart;
+
+class PhotoBook : public QSplitter
+{
+Q_OBJECT
+ Previews *mList;
+ KAction *mFit;
+ KParts::ReadOnlyPart *mViewer;
+
+public:
+ PhotoBook(QWidget *parent, PhotoBookPart *part, const char *name=0);
+ void openURL(const KURL &url);
+ void updateButton(bool, bool );
+
+public slots:
+ void next();
+ void previous();
+
+signals:
+ void emitUpdateButton( bool, bool );
+};
+
+class Previews : public KFileIconView
+{
+Q_OBJECT
+
+ KDirLister mDirLister;
+ PhotoBook *mPhotoBook;
+ QStringList mMimeTypes;
+
+public:
+ Previews(PhotoBook *parent, const QStringList &mimetypes);
+ ~Previews();
+ void openURL(const KURL &url);
+
+ PhotoBook *bv() { return mPhotoBook; }
+ void updateButton( );
+
+public slots:
+ void go(const KFileItem*);
+
+signals:
+ void open(const KURL & ki);
+
+private slots:
+ void insertNewFiles(const KFileItemList &);
+ void removeItem(KFileItem *item);
+ void open(const KFileItem*);
+ void doneListing();
+ void goToFirst();
+ void slotRefreshItems( const KFileItemList& items );
+ void slotClearView();
+};
+
+
+class PhotoBookPart : public KParts::ReadOnlyPart
+{
+Q_OBJECT
+ PhotoBook *bv;
+ KAction *m_pPreviousAction;
+ KAction *m_pNextAction;
+
+public:
+ PhotoBookPart(
+ QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name=0,
+ const QStringList& args = QStringList()
+ );
+ ~PhotoBookPart();
+
+ virtual bool openURL(const KURL &url);
+ static KAboutData* createAboutData();
+ virtual bool openFile();
+
+public slots:
+ void slotUpdateButton( bool nextExit, bool previousExit);
+};
+
+typedef KParts::GenericFactory<PhotoBookPart> PhotoBookFactory;
+
+class PhotoBookBrowserExtension : public KParts::BrowserExtension
+{
+Q_OBJECT
+public:
+ PhotoBookBrowserExtension(PhotoBookPart *p);
+};
+
+
+#endif
+
diff --git a/kview/photobook/photobookui.rc b/kview/photobook/photobookui.rc
new file mode 100644
index 00000000..fbc89f62
--- /dev/null
+++ b/kview/photobook/photobookui.rc
@@ -0,0 +1,14 @@
+<!DOCTYPE kpartplugin>
+<kpartplugin name="PhotoBook Part" library="libphotobook" version="2">
+<MenuBar>
+ <Menu name="view"><text>&amp;View</text>
+ <Action name="previous"/>
+ <Action name="next"/>
+ </Menu>
+</MenuBar>
+
+<Toolbar name="go"><text>Go</text>
+ <Action name="previous"/>
+ <Action name="next"/>
+</Toolbar>
+</kpartplugin>
diff --git a/kview/version.h b/kview/version.h
new file mode 100644
index 00000000..e4a147a5
--- /dev/null
+++ b/kview/version.h
@@ -0,0 +1,3 @@
+#ifndef KVIEW_VERSION
+#define KVIEW_VERSION KDE_VERSION_STRING
+#endif
diff --git a/kviewshell/DESIGN b/kviewshell/DESIGN
new file mode 100644
index 00000000..58c47f07
--- /dev/null
+++ b/kviewshell/DESIGN
@@ -0,0 +1,7 @@
+KViewShell, a KParts::MainWindow
+| Embeds a dlopened KViewPart_Iface, which is a KParts::ReadOnlyPart.
+| KViewPart is such a part.
+| | KViewPart embeds a dlopened KMultiPage, which is a KParts::ReadOnlyPart.
+| | (The widget is made a child widget, and the part is made a child XMLGUI client)
+| | KDVI provides a KMultiPage implementation, KDVIMultiPage.
+
diff --git a/kviewshell/Mainpage.dox b/kviewshell/Mainpage.dox
new file mode 100644
index 00000000..160f34e2
--- /dev/null
+++ b/kviewshell/Mainpage.dox
@@ -0,0 +1,92 @@
+/**
+@mainpage The KDE Graphics API Reference
+
+The kviewshell is a document viewing application contained in the
+kdegraphics package. It cannot load documents itself, but relies on
+plugins that support various document formats. Currently, there are
+plugins for TeX DVI, for FAX, and for AT&T's DJVU format. Some of the
+plugins come with clones of the kviewshell programm (kdvi, kfaxview)
+to maintain compatibility with older shell scripts.
+
+This document contains the kviewshell library API documentation. It is
+primarily aimed at programmers who wish to write plugins to the
+kviewshell application. It documents the few classes that the
+programmer will have to deal with.
+
+
+@section refimpl kviewshell Example Plugins and Reference Implementation
+
+Writing KDE libraries and the associated makefiles can be rather
+complicated. We have therefore provided a well-documented reference
+implementation, the FAX plugin. This is a fine example for a simple
+kviewshell plugin, and a very good starting point for your own
+implementation. It can be found in the kdegraphics source tree under
+<a
+href="http://websvn.kde.org/trunk/KDE/kdegraphics/kfaxview">kfaxview</a>. If
+you are looking for a plugin with more functionality, you might
+consider the DJVU plugin, contained in <a
+href="http://websvn.kde.org/trunk/KDE/kdegraphics/kviewshell/plugins/djvu">kviewshell/plugins/kdjview</a>.
+The DVI plugin is, for historical reasons, rather involved and cannot
+be recommended as an example.
+
+More information about the KDE architecture in form of tutorials,
+HOWTOs, and FAQs can be found at the <a
+href="http://developer.kde.org">KDE Developer's corner</a>.
+
+
+@section req Plugin Author's TODO List
+
+For a basic kviewshell plugin, you must as a minimum do the following:
+
+- Produce a KDE library that contains as a minimum implementations of
+two core classes, the KMultiPage and the DocumentRenderer classes. The
+DocumentRenderer class loads and renderes files, while the KMultiPage
+class provides plugin-specific GUI elements. The reference
+implementation contains a good example for a library that you can
+tailor to suit your needs.
+
+- If your file type is not known to KDE, then you need to provide a
+.desktop file for the mime type you wish to support. Search the KDE
+control center for "mime type" to get a list of known types. Since the
+list of mime types that are contained in the kdelibs package is quite
+long, it is quite likely that your file type is already known.
+
+- Provide one or more .desktop files that relate mime-types with your
+library. After the file is installed, the file dialog of the
+kviewshell application will show files that match the mime-types. The
+kviewshell will then use your library to load and display these
+files. Again, the reference implementation contains examples.
+
+With these data provided, you can produce a perfectly working
+plugin. To support more advanced features of your document format, you
+can optionally also do the following:
+
+- You can add GUI elements. This is most often done by providing an
+.rc-file file, and by calling setXMLFile() in the
+constructor. Re-implement KMultiPage::setFile() in order to update the
+GUI after a file was loaded or closed.
+
+- You can add pages to the preferences dialog by re-implementing
+KMultiPage::addConfigDialogs()
+
+- If your plugin offers functionality to modify the document
+(e.g. remove or add pages), you should re-implement
+KMultiPage::isModified() and KMultiPage::isModified().
+
+- If you have good code to convert your document to PostScript, you
+can improve printing performance tremendously if you re-implement
+KMultiPage::print().
+
+@section help Further information
+
+This document describes only the most basic methods of the most
+important classes used in kviewshell, which we expect to be of
+interest for authors of kviewshell plugins. If you need more advanced
+classes or functionalities, there is some chance that they are already
+implemented or can easily be provided. Thus, please do not hesitate to
+contact Stefan Kebekus <kebekus@kde.org> or Wilfried Huss
+<wilfried.huss@gmx.at>. No-one profits if you spend hours duplicating
+existing code.
+
+*/
+
diff --git a/kviewshell/Makefile.am b/kviewshell/Makefile.am
new file mode 100644
index 00000000..ccde5b59
--- /dev/null
+++ b/kviewshell/Makefile.am
@@ -0,0 +1,67 @@
+SUBDIRS = . pics plugins
+
+INCLUDES= $(all_includes)
+include_HEADERS = kmultipageInterface.h
+
+####### Files
+
+bin_PROGRAMS = kviewshell
+lib_LTLIBRARIES = libkmultipage.la
+kde_module_LTLIBRARIES = kviewerpart.la emptymultipagepart.la
+noinst_LTLIBRARIES = libifaces.la libkviewshell.la
+
+libifaces_la_SOURCES = kviewpart_iface.cpp
+
+kviewerpart_la_SOURCES = kviewpart.cpp pageSizeWidget_base.ui \
+ pageSizeWidget.cpp pageSizeDialog.cpp pageSize.cpp sizePreview.cpp \
+ zoom.cpp units.cpp kvsprefs.kcfgc \
+ optionDialogGUIWidget_base.ui optionDialogAccessibilityWidget.ui simplePageSize.cpp
+
+kviewerpart_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+kviewerpart_la_LIBADD = ./libifaces.la $(LIB_KFILE) -lkparts
+
+libkmultipage_la_SOURCES = kmultipage.cpp pageView.cpp marklist.cpp kmultipageInterface.skel \
+ units.cpp pageSize.cpp simplePageSize.cpp renderedDocumentPage.cpp renderedDocumentPagePixmap.cpp \
+ renderedDocumentPagePrinter.cpp documentPageCache.cpp documentWidget.cpp searchWidget.cpp \
+ selection.cpp documentRenderer.cpp history.cpp kvsprefs.kcfgc tableOfContents.cpp \
+ kprintDialogPage_pageoptions.cpp
+
+
+kde_kcfg_DATA = kviewshell.kcfg
+
+libkmultipage_la_LDFLAGS = $(all_libraries)
+libkmultipage_la_LIBADD = $(LIB_KFILE) -lkdeprint -lkparts
+
+emptymultipagepart_la_SOURCES = empty_multipage.cpp emptyRenderer.cpp
+emptymultipagepart_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) -module
+emptymultipagepart_la_LIBADD = -lkparts libkmultipage.la
+
+libkviewshell_la_SOURCES = kviewshell.cpp
+
+kviewshell_SOURCES = main.cpp
+kviewshell_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+kviewshell_LDADD = libkviewshell.la ./libifaces.la -lkparts
+
+kviewshellinclude_HEADERS = anchor.h bookmark.h pageView.h documentPageCache.h documentRenderer.h documentWidget.h \
+ history.h hyperlink.h kmultipage.h length.h pageNumber.h pageSize.h renderedDocumentPage.h renderedDocumentPagePixmap.h \
+ renderedDocumentPagePrinter.h selection.h simplePageSize.h textBox.h zoom.h zoomlimits.h
+kviewshellincludedir = $(includedir)/kviewshell
+
+
+METASOURCES = AUTO
+
+rc_DATA = kviewshell.rc
+rcdir = $(kde_datadir)/kviewshell
+partrc_DATA = kviewerpart.rc
+partrcdir = $(kde_datadir)/kviewerpart
+
+servicetype_DATA = kmultipage.desktop
+servicetypedir = $(kde_servicetypesdir)
+
+kde_services_DATA = emptymultipage.desktop
+
+messages: rc.cpp
+ $(XGETTEXT) *.cpp *.h -o $(podir)/kviewshell.pot
+
+
+include ../admin/Doxyfile.am
diff --git a/kviewshell/TODO b/kviewshell/TODO
new file mode 100644
index 00000000..840653c7
--- /dev/null
+++ b/kviewshell/TODO
@@ -0,0 +1,94 @@
+API
+===
+
+If we want developers of other applications to move over to
+kviewshell, we definitvely need a stable and mature API. Here are some
+things that I feel need to be implemented, at least in API (it is
+probably ok if we don't implement all of them right now).
+
+* documentRenderer. This class needs documentation. We need to specify
+what the documentRenderer actually does at what time, and what signals
+it emits at what time and what they mean. Things that come to my mind:
+
+- specify what drawPage actually does. In kdvi, drawPage is a highly
+asynchronous method, that either does nothing (e.g. if font are still
+being generated), or really draws a page. The behaviour must be
+specified, and I believe that for printing (see below) we would also
+need to provide for a synchronous way of rendering pages.
+
+- some document formats include ready-made thumbnails. We should have
+have a virtual function that makes thumbnails out of fully rendered
+pages, which can be overloaden if the author of a specific file format
+supports 'embedded thumbnails'
+
+- in the future we probably want to use threading to render pages in
+memory to improve the perceived speed of applications. Thus, we will
+have to specify what methods need to be implemented in a reentrant or
+thread-save manner. Probably we should provide infrastructure for
+that.
+
+- support for reading and writing hirachical bookmarks for document
+that support that
+
+- some document formats, such as dvi, allow to READ the position of
+characters, which allows for full-text search, copying of text,
+etc. Other formats, such djvu allow also WRITING of such
+information. The idea is that you produce a djvu file by scanning a
+certain document, and than later add the position and
+character-information by using e.g. OCR software. We should at least
+have support for that in the API, even if we don't implement an OCR
+interface right now.
+
+- dvi has the special feature that it supports source information and
+uses that to implement inverse and forward search functionality. We
+must somehow make sure that even these unusual features fit well into
+our framework without too much of an effort.
+
+* kmultipage
+
+- kviewshell should provide a print dialog (with the extra option that
+certain document formats can insert their own configuration pages). I
+find the print dialog of Acroread 6.0 in OSX very well done. Then we
+should have a default printing implementation that uses KPrinter, etc,
+to print the pages (this will be used e.g. by kfax), and we would need
+infrastructure for implementation which have their own way of
+producing PS file (such as dvi, where dvips is the preferred method to
+print).
+
+This may rise some important questions in documentRenderer API. For
+printing we would need a SYNCHRONOUS way of rendering pages to a
+qpainter object.
+
+
+
+DOCUMENTATION
+=============
+
+If we want developers of other applications to move over to
+kviewshell, we definitvely need a well-documented API, and some
+applications that demonstrate how everything works. In particular, we
+should have
+
+* lots of documentation, including API documentation and a tutorial on
+"How to implement a kmultipage"
+
+* an exteremely well-defined reference implementation for a trivial
+file format, either one that is actually useful (kfax, perhaps), or
+one that serves only demonstration purposes and that goes into the
+kdesdk module
+
+
+
+
+
+KVIEWSHELL APPLICATION
+======================
+
+* improve command line interface. The somewhat antique method of
+giving the library name in the command line should be replaced by a
+more modern method where kviewshell uses some kde wizardy
+(e.g. 'services') so that installed kmultipage implementations can
+announce what mime type they are supposed to handle, and kvieshell
+then loads them automatically
+
+
diff --git a/kviewshell/anchor.h b/kviewshell/anchor.h
new file mode 100644
index 00000000..f3faf13e
--- /dev/null
+++ b/kviewshell/anchor.h
@@ -0,0 +1,61 @@
+// -*- C++ -*-
+//
+// anchor.h
+//
+// Part of KVIEWSHELL - A framework for multipage text/gfx viewers
+//
+// (C) 2004-2005 Stefan Kebekus
+// Distributed under the GPL
+
+
+#ifndef ANCHOR_H
+#define ANCHOR_H
+
+#include "length.h"
+#include "pageNumber.h"
+
+
+/** \brief Page number and vertical position in physical coordinates
+
+This very simple class contains a page number and a vertical position
+in physical coordiantes. The vertical position is given by the
+distance from the top of the page. Anchors are completely independent
+of documents, there is no need for a document to exists that contains
+the given page, nor does the page number need to be valid.
+
+@author Stefan Kebekus <kebekus@kde.org>
+@version 1.0 0
+*/
+
+class Anchor {
+ public:
+ /** \brief Constructs an anchor that points to an invalid page */
+ Anchor() {page = 0;}
+
+ /** \brief Constructs an snchor that points to a given position on a
+ given page
+
+ The class contains no code to make sure in any way that the page
+ number pg exists, and that page pg, if it exists, is taller than
+ distance_from_top
+
+ @param pg number of the page
+ @param _distance_from_top distance from the top of the page
+ */
+ Anchor(const PageNumber& pg, const Length& _distance_from_top): page(pg), distance_from_top(_distance_from_top) {}
+
+ /** \brief quick validity check for anchors
+
+ @returns true if the page number is valid, and 0mm <= distance_from_top <= 2m
+ */
+ bool isValid() const {return page.isValid() && (0.0 <= distance_from_top.getLength_in_mm()) && (distance_from_top.getLength_in_mm() <= 2000.0);}
+
+ /** \brief Page number that this anchor point to */
+ PageNumber page;
+
+ /** \brief Distance from the top of the page in inch */
+ Length distance_from_top;
+};
+
+
+#endif
diff --git a/kviewshell/bookmark.h b/kviewshell/bookmark.h
new file mode 100644
index 00000000..1df245fb
--- /dev/null
+++ b/kviewshell/bookmark.h
@@ -0,0 +1,107 @@
+// -*- C++ -*-
+/***************************************************************************
+ * 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 _bookmarks_h_
+#define _bookmarks_h_
+
+#include "anchor.h"
+
+#include <qptrlist.h>
+#include <qstring.h>
+
+
+/** \brief Bookmark
+
+This class represents a bookmark. It contains the bookmark text, an
+anchor that represents the target of the bookmark, and a list of
+subordinate bookmarks.
+
+@warning The list of subordinate bookmarks owns its entries,
+i.e. autoDelete() is set to true. Thus, extra care must be taken when
+copying bookmarks. Otherwise, a segfault could result.
+*/
+
+class Bookmark {
+ public:
+ /** Default constructor.
+
+ Constructs an invalid bookmark with an empty bookMarkText and an
+ invalid position
+ */
+ Bookmark() {subordinateBookmarks.setAutoDelete(true);}
+
+ /** Constructs a bookmark with given a text and anchor
+
+ @param text name of the bookmark, as it appears in the GUI
+
+ @param pos an Anchor that specifies the position of the bookmark
+ */
+ Bookmark(const QString &text, const Anchor &pos) {
+ Bookmark();
+ bookmarkText = text;
+ position = pos;
+ }
+
+ /** Convenience funtion, behaves as Bookmark(const QString &text, const Anchor &pos)
+
+ @param text name of the bookmark, as it appears in the GUI
+
+ @param page number of the where the bookmark lives. Recall the
+ convention that '0' is an invalid page, the first page is '1'
+
+ @param distance_from_top position on the page, distance from
+ top of the page
+ */
+ Bookmark(const QString& text, const PageNumber& page, const Length& distance_from_top) {
+ Bookmark();
+ bookmarkText = text;
+ position.page = page;
+ position.distance_from_top = distance_from_top;
+ }
+
+ /** Label of the bookmark as it will appear in the GUI to the user,
+ such as "Section 1", "Theorem 12", etc. */
+ QString bookmarkText;
+
+ /** The anchor that specifies the position of the bookmark */
+ Anchor position;
+
+ /** List of subordinate bookmarks
+
+ Bookmarks generally come in trees, and some bookmarks can have
+ subordinate bookmarks. For instance, the bookmark that
+ respresents a chapter heading would have headings of subsections
+ as subordinate bookmarks. These are contained in this list.
+
+ @warning This list owns its entries, e.g. autoDelete() is set to
+ true. Thus, extra care must be taken when copying this
+ list. Otherwise, a segfault could result.
+ */
+ QPtrList<Bookmark> subordinateBookmarks;
+
+ // Returns true if the bookmark is valid, false otherwise. A
+ // bookmark is valid if the text is not empty and the anchor is
+ // valid.
+ bool isValid() const {return (!bookmarkText.isEmpty()) && position.isValid();}
+};
+
+
+#endif
diff --git a/kviewshell/documentPageCache.cpp b/kviewshell/documentPageCache.cpp
new file mode 100644
index 00000000..2c9a46a5
--- /dev/null
+++ b/kviewshell/documentPageCache.cpp
@@ -0,0 +1,337 @@
+//
+// Class: documentPageCache
+//
+// Cache that holds a number of pages in a document.
+// Part of KDVI- A previewer for TeX DVI files.
+//
+// (C) 2004 Stefan Kebekus. Distributed under the GPL.
+
+#include <config.h>
+
+#include <kdebug.h>
+#include <qapplication.h>
+
+#include "documentPageCache.h"
+#include "documentRenderer.h"
+#include "kvsprefs.h"
+#include "renderedDocumentPagePixmap.h"
+
+
+//#define documentPageCache_DEBUG
+
+
+DocumentPageCache::DocumentPageCache()
+ : maxMemory(2*16777216), LRUCache(maxMemory, 200)
+{
+ LRUCache.setAutoDelete(true);
+
+ resolutionInDPI = 0.0;
+ Length w,h;
+ w.setLength_in_mm(200);
+ h.setLength_in_mm(300);
+ userPreferredSize.setPageSize(w,h);
+ useDocumentSpecifiedSize = true;
+}
+
+
+DocumentPageCache::~DocumentPageCache()
+{
+}
+
+
+void DocumentPageCache::setRenderer(DocumentRenderer *_renderer)
+{
+ clear();
+ renderer = _renderer;
+}
+
+
+SimplePageSize DocumentPageCache::sizeOfPage(const PageNumber& page) const
+{
+ // Paranoid safety checks
+ if (!page.isValid()) {
+ kdError(1223) << "DocumentPageCache::sizeOfPage( " << page << ") called with invalid page number." << endl;
+ return SimplePageSize();
+ }
+ if (renderer.isNull()) {
+ kdError(1223) << "DocumentPageCache::sizeOfPage( " << page << ") called when no renderer was set." << endl;
+ return SimplePageSize();
+ }
+
+ SimplePageSize s = renderer->sizeOfPage(page);
+ if (!useDocumentSpecifiedSize)
+ s = userPreferredSize;
+
+ if (!s.isValid())
+ {
+ // If the size is invalid use the size of the first Page in the document
+ // as an estimate.
+ s = renderer->sizeOfPage(1);
+ if (!s.isValid())
+ s = userPreferredSize;
+ }
+
+ return s;
+}
+
+void DocumentPageCache::setResolution(double res)
+{
+ resolutionInDPI = res;
+}
+
+QSize DocumentPageCache::sizeOfPageInPixel(const PageNumber& pg) const
+{
+ // Paranoid safety checks
+ if (renderer.isNull()) {
+ kdError(1223) << "DocumentPageCache::sizeOfPageInPixel( " << pg << " ) called but no renderer was set" << endl;
+ return QSize();
+ }
+ if (!pg.isValid()) {
+ kdError(1223) << "DocumentPageCache::sizeOfPageInPixel( " << pg << " ) called with invalid argument" << endl;
+ return QSize();
+ }
+
+ SimplePageSize ps = sizeOfPage(pg);
+ if (ps.isValid())
+ return ps.sizeInPixel(resolutionInDPI);
+ return userPreferredSize.sizeInPixel(resolutionInDPI);
+}
+
+
+bool DocumentPageCache::isPageCached(const PageNumber& pageNumber, const QSize& size)
+{
+ // Paranoid checks
+ if (renderer.isNull()) {
+ kdError(1223) << "DocumentPageCache::isPageCached(..) called but no renderer was set" << endl;
+ return false;
+ }
+ if (!pageNumber.isValid()) {
+ kdError(1223) << "DocumentPageCache::isPageCached( " << pageNumber << " ) called, with invalid argument." << endl;
+ return false;
+ }
+ if (renderer->totalPages() < pageNumber) {
+ kdError(1223) << "DocumentPageCache::isPageCached( " << pageNumber
+ << " ) called but document contains only " << renderer->totalPages() << " pages." << endl;
+ return false;
+ }
+
+ QString key = createKey(pageNumber, size);
+
+ // Check if the page that we are looking for is in the cache.
+ // We are not accessing the page, so we don't want it to be moved into the front.
+ RenderedDocumentPagePixmap* page = LRUCache.find(key, false);
+
+ if (page)
+ return true;
+ else
+ return false;
+}
+
+QString DocumentPageCache::createKey(const PageNumber& pageNumber, const QSize& size)
+{
+ QString key;
+
+ key = QString::number(pageNumber) + ":" +
+ QString::number(size.width()) + ":" + QString::number(size.height());
+
+ return key;
+}
+
+QString DocumentPageCache::createKey(const PageNumber& pageNumber)
+{
+ QSize pageSize = sizeOfPageInPixel(pageNumber);
+
+ QString key;
+
+ key = QString::number(pageNumber) + ":" +
+ QString::number(pageSize.width()) + ":" + QString::number(pageSize.height());
+
+ return key;
+}
+
+bool DocumentPageCache::isPageCached(const PageNumber& pageNumber)
+{
+ // Paranoid checks
+ if (renderer.isNull()) {
+ kdError(1223) << "DocumentPageCache::isPageCached(..) called but no renderer was set" << endl;
+ return false;
+ }
+ if (!pageNumber.isValid()) {
+ kdError(1223) << "DocumentPageCache::isPageCached( " << pageNumber << " ) called, with invalid argument." << endl;
+ return false;
+ }
+ if (renderer->totalPages() < pageNumber) {
+ kdError(1223) << "DocumentPageCache::isPageCached( " << pageNumber
+ << " ) called but document contains only " << renderer->totalPages() << " pages." << endl;
+ return false;
+ }
+
+ return isPageCached(pageNumber, sizeOfPageInPixel(pageNumber));
+}
+
+RenderedDocumentPagePixmap* DocumentPageCache::getPage(const PageNumber& pageNr)
+{
+#ifdef DocumentPageCache_DEBUG
+ kdDebug(1223) << "DocumentPageCache::getPage( pageNr=" << pageNr << " )" << endl;
+#endif
+
+ // Paranoid checks
+ if (renderer.isNull()) {
+ kdError(1223) << "DocumentPageCache::getPage(..) called but no renderer was set" << endl;
+ return 0;
+ }
+ if (!pageNr.isValid()) {
+ kdError(1223) << "DocumentPageCache::getPage( " << pageNr << " ) called, with invalid argument." << endl;
+ return 0;
+ }
+ if (renderer->totalPages() < pageNr) {
+ kdError(1223) << "DocumentPageCache::getPage( " << pageNr << " ) called but document contains only " << renderer->totalPages() << " pages." << endl;
+ return 0;
+ }
+
+ // First check if the page that we are looking for is in the cache
+ RenderedDocumentPagePixmap* page;
+ page = LRUCache.find(createKey(pageNr));
+
+ if (page)
+ return page;
+
+ // The page was not found in the cache, so we have to make a new
+ // page and add this to the cache.
+ page = createDocumentPagePixmap();
+
+ // If that failed, issue an error message and quit.
+ if (page == 0) {
+ kdError(1223) << "DocumentPageCache::getPage(..) cannot allocate DocumentPage structure" << endl;
+ return 0;
+ }
+
+ // Now 'page' contains a point to a page structure that we can
+ // use. Add the page to the cache, and apply the renderer to the page.
+ page->setPageNumber(pageNr);
+ if (!renderer.isNull())
+ {
+ if (resolutionInDPI > 0.0)
+ {
+ page->resize(sizeOfPageInPixel(pageNr));
+ QApplication::setOverrideCursor( waitCursor );
+ renderer->drawPage(resolutionInDPI, page);
+ QApplication::restoreOverrideCursor();
+
+ // We always set the cache capacity to be at least n times the cost of the page we want to insert.
+ // Where n is the number of pages that can be visible at the same time at very high zoomlevels.
+ // n depends on the layout mode.
+ // If these pages are not all in the cache, scrolling the view becomes very slow, because for each
+ // paint event the pages need to be rerendered.
+ // We set n for each viewmode differently so that the user is able to reduce memory consuption by
+ // switching to a simpler viewmode like Single Page.
+ int n = 4;
+ switch (KVSPrefs::viewMode())
+ {
+ case KVSPrefs::EnumViewMode::SinglePage:
+ n = 1;
+ break;
+ case KVSPrefs::EnumViewMode::Continuous:
+ n = 2;
+ break;
+ default:
+ n = 4;
+ }
+ LRUCache.setMaxCost(QMAX(page->memory() * n, maxMemory));
+
+ if (!LRUCache.insert(createKey(pageNr), page, page->memory()))
+ {
+ kdError() << "DocumentPageCache::getPage(): inserting pagestructure into the cache failed.\n This should never happen. If you see this message, something is very wrong." << endl;
+ }
+ }
+ else
+ kdError(1223) << "DocumentPageCache::getPage() called, but no resolution or negative resolution was set" << endl;
+ }
+
+ return page;
+}
+
+
+RenderedDocumentPagePixmap* DocumentPageCache::createDocumentPagePixmap() const
+{
+ return new RenderedDocumentPagePixmap();
+}
+
+
+void DocumentPageCache::clear()
+{
+ LRUCache.clear();
+}
+
+
+void DocumentPageCache::setUserPreferredSize(const SimplePageSize& s)
+{
+ bool sizeChanged = !userPreferredSize.isNearlyEqual(s);
+ userPreferredSize = s;
+
+ if (sizeChanged)
+ emit(paperSizeChanged());
+}
+
+
+void DocumentPageCache::setUseDocumentSpecifiedSize(bool b)
+{
+ bool valChanged = (useDocumentSpecifiedSize == b);
+
+ useDocumentSpecifiedSize = b;
+ if (valChanged)
+ emit(paperSizeChanged());
+}
+
+
+QPixmap DocumentPageCache::createThumbnail(const PageNumber& pageNr, int width)
+{
+ // Paranoid checks
+ if (renderer.isNull()) {
+ kdError(1223) << "DocumentPageCache::createThumbnail(..) called but no renderer was set" << endl;
+ thumbnailPage.resize(0,0);
+ return thumbnailPage;
+ }
+ if (renderer->totalPages() < pageNr) {
+ kdError(1223) << "DocumentPageCache::createThumbnail( " << pageNr << ", width ) called but document contains only " << renderer->totalPages() << " pages." << endl;
+ thumbnailPage.resize(0,0);
+ return thumbnailPage;
+ }
+ if (!pageNr.isValid()) {
+ kdError(1223) << "DocumentPageCache::createThumbnail(..) called for page with invalid page specification" << endl;
+ thumbnailPage.resize(0,0);
+ return thumbnailPage;
+ }
+ if (!sizeOfPage().isValid()) {
+ kdError(1223) << "DocumentPageCache::createThumbnail(..) called for page with invalid size" << endl;
+ thumbnailPage.resize(0,0);
+ return thumbnailPage;
+ }
+
+ thumbnailPage.setPageNumber(pageNr);
+ thumbnailPage.resize(width, (int)(width/sizeOfPage(pageNr).aspectRatio() + 0.5 ) );
+ renderer->drawThumbnail((double)(width)/sizeOfPage(pageNr).width().getLength_in_inch(), &thumbnailPage);
+
+ if (KVSPrefs::changeColors() && KVSPrefs::renderMode() != KVSPrefs::EnumRenderMode::Paper)
+ {
+ return thumbnailPage.accessiblePixmap();
+ }
+ else
+ {
+ return thumbnailPage;
+ }
+}
+
+void DocumentPageCache::deselectText()
+{
+ userSelection.clear();
+ emit textSelected(false);
+}
+
+void DocumentPageCache::selectText(const TextSelection& selection)
+{
+ userSelection = selection;
+ emit textSelected(!userSelection.isEmpty());
+}
+
+#include "documentPageCache.moc"
diff --git a/kviewshell/documentPageCache.h b/kviewshell/documentPageCache.h
new file mode 100644
index 00000000..c885123a
--- /dev/null
+++ b/kviewshell/documentPageCache.h
@@ -0,0 +1,143 @@
+// -*- C++ -*-
+//
+// Class: documentPageCache
+//
+// Cache that holds a number of pages in a document.
+// Part of KDVI- A previewer for TeX DVI files.
+//
+// (C) 2004 Stefan Kebekus. Distributed under the GPL.
+
+#ifndef _documentpagecache_h_
+#define _documentpagecache_h_
+
+#include "renderedDocumentPagePixmap.h"
+#include "pageNumber.h"
+#include "pageSize.h"
+#include "selection.h"
+
+#include <qcache.h>
+#include <qguardedptr.h>
+#include <qobject.h>
+
+class DocumentRenderer;
+class QPixmap;
+class RenderedDocumentPage;
+
+
+class DocumentPageCache: public QObject
+{
+ Q_OBJECT
+
+ public:
+ DocumentPageCache();
+ virtual ~DocumentPageCache();
+
+ /** This method is used to name the DocumentRenderer, that the
+ documentPageCache uses to render the page. The renderer can be
+ used any time (e.g., triggered by an internal timer event), and
+ must not be deleted before either the DocumentRenderer is
+ deleted, or another renderer has been set. */
+ void setRenderer(DocumentRenderer *_renderer);
+
+ void setResolution(double res);
+ double getResolution() const {return resolutionInDPI;}
+
+ const TextSelection& selectedText() const { return userSelection; }
+
+ void deselectText();
+ void selectText(const TextSelection& selection);
+
+ /** Returns the size of page 'page'. If the document does not
+ specify a size (which happens, e.g., for some DVI-files), then
+ the userPreferredSize is returned. */
+ SimplePageSize sizeOfPage(const PageNumber& page = 1) const;
+
+ /** Returns the size of page 'page', in pixels, using the resolution
+ set with setResolution(). If the document does not specify a
+ size (which happens, e.g., for some DVI-files), the
+ userPreferredSize is used. */
+ QSize sizeOfPageInPixel(const PageNumber& page) const;
+
+ /** Returns a pointer to a documentPage structure, or 0, if the
+ documentPage could not be generated for some reason (e.g.,
+ because no renderer has been set). */
+ RenderedDocumentPagePixmap* getPage(const PageNumber& pageNr);
+
+ /** Checks if the given page is already in the cache. */
+ bool isPageCached(const PageNumber& pageNumber, const QSize& size);
+
+ /** Checks if the given page is already in the cache. Here we don't care about the size
+ of the page. */
+ bool isPageCached(const PageNumber& pageNumber);
+
+ /** Returns a "width" pixels width thumbnail of the given page. This
+ method returns an empty QPixmap if one of the arguments is
+ invalid, or if the page cannot be rendered for any reason. */
+ QPixmap createThumbnail(const PageNumber& pageNr, int width);
+
+ signals:
+ /** This signal is emitted when setUserPreferredSize() or
+ setUseUserPreferredSize() is called, and the page size
+ changes accordingly. */
+ void paperSizeChanged();
+
+ /** This signal is emitted when the text selection of the current
+ document changes. The argument is false if no text is selected, true
+ otherwise. */
+ void textSelected(bool);
+
+ public slots:
+ /** Clears the contents of the cache. */
+ void clear();
+
+ /** Sets the userPreferredSize, which is explained below */
+ void setUserPreferredSize(const SimplePageSize& t);
+ void setUseDocumentSpecifiedSize(bool);
+
+ protected:
+ /** This function creates new RenderedDocumentPagePixmap objects.
+ If a multipage implementation needs additional functionality overwrite
+ this function to create objects of a suitable subclass of RenderedDocumentPagePixmap.
+ */
+ virtual RenderedDocumentPagePixmap* createDocumentPagePixmap() const;
+
+ /** Creates the hashing key for the cache. */
+ QString createKey(const PageNumber& pageNumber, const QSize& size);
+
+ /** Creates the hashing function. The size of the page is calculated
+ based on the current resolution. */
+ QString createKey(const PageNumber& pageNumber);
+
+ QGuardedPtr<DocumentRenderer> renderer;
+
+ private:
+ /** The maximum of memory used by the cache. (32MB)
+ TODO: make this configurable, or detact an appropriate value at startup. */
+ Q_UINT32 maxMemory;
+
+ /** This field contains resolution of the display device. In
+ principle. In fact, kviewshell implements zooming by calling the
+ setResolution()-method with values that are not exactly the
+ resolution of the display, but multiplied with the zoom
+ factor. Bottom line: the documentRenderer should act as if this
+ field indeed contains resolution of the display device. Whene a
+ documentRenderer is constructed, this field is set to the actual
+ resolution to give a reasonable default value. */
+ double resolutionInDPI;
+
+ SimplePageSize userPreferredSize;
+ bool useDocumentSpecifiedSize;
+
+ TextSelection userSelection;
+
+
+ /** This list holds the cache. */
+ QCache<RenderedDocumentPagePixmap> LRUCache;
+
+ /** This is a dummy documentPage structure which is used internally
+ by the 'createThumbnail' method. */
+ RenderedDocumentPagePixmap thumbnailPage;
+};
+
+
+#endif
diff --git a/kviewshell/documentRenderer.cpp b/kviewshell/documentRenderer.cpp
new file mode 100644
index 00000000..f9837fa2
--- /dev/null
+++ b/kviewshell/documentRenderer.cpp
@@ -0,0 +1,133 @@
+//
+// Class: documentRenderer
+//
+// Abstract Widget for displaying document types
+// Needs to be implemented from the actual parts
+// using kviewshell
+// Part of KViewshell - A generic interface for document viewers.
+//
+// (C) 2004-2005 Wilfried Huss, Stefan Kebekus. Distributed under the GPL.
+
+#include <config.h>
+
+#include <kdebug.h>
+
+#include "documentRenderer.h"
+#include "renderedDocumentPage.h"
+
+
+DocumentRenderer::DocumentRenderer(QWidget* par)
+ : mutex(true), parentWidget(par), accessibilityBackground(false),
+ accessibilityBackgroundColor(QColor(255,255,255))
+{
+ numPages = 0;
+ _isModified = false;
+}
+
+
+DocumentRenderer::~DocumentRenderer()
+{
+ // Wait for all access to this DocumentRenderer to finish
+ QMutexLocker lock(&mutex);
+
+ clear();
+}
+
+
+void DocumentRenderer::clear()
+{
+ // Wait for all access to this DocumentRenderer to finish
+ QMutexLocker lock(&mutex);
+
+ numPages = 0;
+ pageSizes.clear();
+ anchorList.clear();
+ bookmarks.clear();
+ _isModified = false;
+}
+
+void DocumentRenderer::setAccessibleBackground(bool accessibleMode, const QColor& background)
+{
+ // Wait for all access to this DocumentRenderer to finish
+ QMutexLocker lock(&mutex);
+
+ accessibilityBackground = accessibleMode;
+ accessibilityBackgroundColor = background;
+}
+
+SimplePageSize DocumentRenderer::sizeOfPage(const PageNumber& page)
+{
+ // Wait for all access to this DocumentRenderer to finish
+ QMutexLocker locker(&mutex);
+
+ if (!page.isValid())
+ return SimplePageSize();
+ if (page > totalPages())
+ return SimplePageSize();
+ if (page > pageSizes.size())
+ return SimplePageSize();
+
+ return pageSizes[page-1];
+}
+
+
+void DocumentRenderer::drawThumbnail(double resolution, RenderedDocumentPage* page)
+{
+ // Wait for all access to this DocumentRenderer to finish
+ QMutexLocker locker(&mutex);
+
+ drawPage(resolution, page);
+}
+
+void DocumentRenderer::getText(RenderedDocumentPage* page)
+{
+ // We are only interrested in the textual data, so we can use a dummy value for the resolution.
+ drawPage(100.0, page);
+}
+
+bool DocumentRenderer::isValidFile(const QString&) const
+{
+ return true;
+}
+
+
+Anchor DocumentRenderer::parseReference(const QString &reference)
+{
+ // Wait for all access to this documentRenderer to finish
+ QMutexLocker locker(&mutex);
+
+ if (isEmpty())
+ return Anchor();
+
+ // If the reference is a number, which we'll interpret as a
+ // page number.
+ bool ok;
+ int page = reference.toInt(&ok);
+ if (ok == true)
+ {
+ if (page < 1)
+ page = 1;
+ if (page > totalPages())
+ page = totalPages();
+
+ return Anchor(page, Length());
+ }
+
+ // If the reference is not a number, return an empty anchor.
+ return Anchor();
+}
+
+Anchor DocumentRenderer::findAnchor(const QString &locallink)
+{
+ // Wait for all access to this DocumentRenderer to finish
+ QMutexLocker locker(&mutex);
+
+ QMap<QString,Anchor>::Iterator it = anchorList.find(locallink);
+ if (it != anchorList.end())
+ return *it;
+ else
+ return Anchor();
+}
+
+
+#include "documentRenderer.moc"
diff --git a/kviewshell/documentRenderer.h b/kviewshell/documentRenderer.h
new file mode 100644
index 00000000..a8a87410
--- /dev/null
+++ b/kviewshell/documentRenderer.h
@@ -0,0 +1,478 @@
+// -*- C++ -*-
+//
+// Class: documentRenderer
+//
+// Abstract class for rendering document types. Needs to be
+// subclassed by the actual parts using kviewshell. Part of
+// KViewshell - A generic interface for document viewers.
+//
+// (C) 2004-2005 Wilfried Huss, Stefan Kebekus. Distributed under the GPL.
+//
+
+#ifndef DOCUMENTRENDERER_H
+#define DOCUMENTRENDERER_H
+
+#include "bookmark.h"
+#include "pageNumber.h"
+#include "pageSize.h"
+
+#include <qguardedptr.h>
+#include <qcolor.h>
+#include <qmutex.h>
+#include <qobject.h>
+#include <qvaluevector.h>
+
+class Anchor;
+class KURL;
+class RenderedDocumentPage;
+
+
+/** \brief loads and renders documents
+
+This abstract class is one of the two core classes that must be
+implemented by all authors who write plugins for the kviewshell
+programm. It is responsible for document loading and rendering. As a
+minimum, the setFile() and drawPage() must be reimplemented.
+
+This documentation mentiones only the methods and members that are
+important for authors of plugins. For full documentation, consult the
+header file documentRenderer.h.
+
+@warning Future versions of kviewshell will use threading to keep the
+GUI responsive while pages are rendered. As a result, IT IS ABSOLUTELY
+NECESSARY that your implementation is THREAD-SAFE, if not, this can
+result in infrequent and very hard-to-find crashes of your
+programm. Use the member mutex to make your implemetation
+thread-safe.
+
+@author Wilfried Huss, Stefan Kebekus
+*/
+
+class DocumentRenderer : public QObject
+{
+ Q_OBJECT
+
+public:
+ /** \brief default constructor */
+ DocumentRenderer(QWidget* parent);
+
+ virtual ~DocumentRenderer();
+
+ /** \brief loading of files
+
+ This is a purely virtual method that must be re-implemented. It is
+ called when a file should be loaded. The implementation must then do
+ the following
+
+ - initialize internal data structures so the document pointed to by
+ 'fname' can be rendered quickly. It is not necessary actually load
+ the file; if the implementation choses to load only parts of a large
+ file and leave the rest on the disc, this is perfectly fine.
+
+ - return 'true' on success and 'false' on failure. Before 'false' is
+ returned, the method clear() should be called
+
+ When the method returns 'true', it is expected that
+
+ - the member _isModified is set to 'false'
+
+ - the member 'numPages' is either set to 0 if the document is empty,
+ or else to the number of page in the document
+
+ - the vector pageSizes *must* either be empty (e.g. if your file
+ format does not specify a page size), or must be of size
+ totalPages(), and contain the sizes of all pages in the document.
+
+ - the anchorList is filled with data; it is perfectly fine to leave
+ the anchorList empty, if your file format does not support anchors,
+ or if your document doesn't contain any.
+
+ - the list 'bookmarks' is filled with data; it is perfectly fine to
+ leave this list empty, if your file format does not support
+ bookmarks or if your document doesn't contain any.
+
+ - the method drawPage() works
+
+ @note It is perfectly possible that setFile() is called several
+ times in a row, with the same or with different filenames.
+
+ @warning The signal documentIsChanged() must not be emitted while
+ the method runs.
+
+ @warning Future versions of kviewshell will use threading to keep
+ the GUI responsive while pages are rendered. As a result, IT IS
+ ABSOLUTELY NECESSARY that your implementation is THREAD-SAFE, if
+ not, this can result in infrequent and very hard-to-find crashes of
+ your programm. Use the member mutex to make your implemetation
+ thread-safe.
+
+ @param fname name of the file to open. It is not guaranteed that the
+ file exists, that it is a file, or that it is readable.
+
+ @param base original URL of the file that was opened.
+
+ If the program that uses this documentRenderer was asked to open
+ http://www.kde.org/test.dvi.bz2, then the program would download the
+ file to a temporary file and decompress it, generating
+ e.g. /tmp/tmp.dvi. In that case, base would be
+ http://www.kde.org/test.dvi.bz2, and fname=/tmp/tmp.dvi. The base
+ can be used by the documentRenderer to handle relative URLs that
+ might be contained in a file. Otherwise, it can safely be ignored.
+
+ @returns 'true' on success and 'false' on failure. Even after this
+ method returns 'false' the class must act reasonably, i.e. by
+ clear()ing the document
+ */
+ virtual bool setFile(const QString &fname, const KURL &base) = 0;
+
+
+ /** \brief clearing the document renderer
+
+ This method clears the renderer, so that it represents an empty
+ document. The standard implementation doe the following:
+
+ - sets 'numPages' to zero
+
+ - clears the pageSizes and the anchorList
+
+ - sets _isModified to 'false'
+
+ Most authors of kviewshell-plugins will probably want to
+ re-implement this to clear internal data structures of their
+ implementations.
+
+ @warning Future versions of kviewshell will use threading to keep
+ the GUI responsive while pages are rendered. As a result, IT IS
+ ABSOLUTELY NECESSARY that your implementation is THREAD-SAFE, if
+ not, this can result in infrequent and very hard-to-find crashes of
+ your programm. Use the member mutex to make your implemetation
+ thread-safe.
+ */
+ virtual void clear();
+
+
+ /* Returns true if the current document contains 0 pages. */
+ bool isEmpty() const {return numPages == 0;}
+
+ /* Tells if the document was modified after is was loaded. */
+ bool isModified() const {return _isModified; }
+
+ /* Returns the number of pages in the document. This method can well
+ return 0, e.g. if no document has been loaded yet, or if the
+ current document is empty. */
+ PageNumber totalPages() const {return numPages; }
+
+ QPtrList<Bookmark> getBookmarks() const { return bookmarks; }
+
+ /* Returns the size of page 'page'. If the document is empty, if the
+ page specified is not a page of the document or if the document
+ does not specify a size (which happens, e.g., for some
+ DVI-files), then an invalid page size is returned. */
+ SimplePageSize sizeOfPage(const PageNumber& page);
+
+ /* Returns true if the document specifies page sizes, and false
+ otherwise. NOTE: the information returned by this method is not
+ always 100% reliable. Although unlikely, it is theoretically
+ possible that this method returns 'true', but still some of the
+ sizes returned by sizeOfPage() are invalid. */
+ bool hasSpecifiedPageSizes() const {return !pageSizes.isEmpty();}
+
+ /** rendering of documents
+
+ This purely virtual method is the most important method in the
+ DocumentRenderer class. It must be re-implemented by authors who
+ want to write plugins for the kviewshell program. The purpose of
+ this method is to render a graphical representation into a
+ documentPage structure. More specifically, the implementation needs
+ to
+
+ - call the documentPage::clear() on *page
+
+ and the do all of the following, in no particular order
+
+ - obtain the pointer to the QPaintDevice from the documentPage using
+ the documentPage::getPaintDevice() method and draw a graphical
+ representation of the page number page->getPageNumber() into the
+ QPaintDevice, using the given resolution. If the member
+ accessibilityBackground is true, the accessibilityBackgroundColor
+ should be used for a background color, if possible. Otherwise,
+ white should be used, if possible. If you need to compute the size
+ of the page in pixel, do this as follows:
+ @code
+ SimplePageSize psize = pageSizes[page->getPageNumber() - 1];
+ if (psize.isValid()) {
+ int width_in_pixel = resolution * psize.width().getLength_in_inch();
+ int height_in_pixel = resolution * psize.height().getLength_in_inch();
+
+ <...>
+ }
+ @endcode
+ Don't use page->height() or page->width() to calculate the sizes
+ ---KViewShell uses transformations e.g. to rotate the page, and
+ sets the argument 'resolution' accordingly; these changes are not
+ reflected in page->height() and page->width(). Similar problems
+ occur if KViewShell required a shrunken version of the page,
+ e.g. to print multiple pages on one sheet of paper.
+
+ - if your document contains hyperlinks, fill the
+ documentPage::hyperLinkList with HyperLinks, using pixel
+ coordinates for the coordinates in the Hyperlink::box member of
+ the Hyperlink. The Hyperlink::baseline member of the Hyperlink
+ can be ignored. The linkText member of the Hyperlink should either
+ be an absolute URL ("http://www.kde.org"), or be of the form
+ "#anch", where the string "anch" is contained in the anchorList.
+
+ - if your plugin supports full-text information, fill
+ documentPage::textLinkList with HyperLinks, using pixel
+ coordinates for the coordinates in the Hyperlink::box and
+ Hyperlink::baseline members of the Hyperlink. The entries in the
+ documentPage::textLinkList should have a natural ordering, "first
+ text first" (left-to-right, up-to-down for western languages,
+ right-to-left for hebrew, etc.). This is important so that text
+ selection with the mouse works properly, and only continuous
+ blocks of text can be selected.
+
+ @note This method is often called in a paintEvent, so that care must
+ be taken to return as soon as possible. No user interaction should
+ be done during the execution.
+
+ @note If your plugin supports full-text information, you probably
+ want to re-implement the method supportsTextSearch() below.
+
+ @warning As mentioned above, it may be tempting to compute the image
+ size in pixel, using page->height() and page->width(). DON'T DO
+ THAT. KViewShell uses transformations e.g. to rotate the page, and
+ sets the argument 'resolution' accordingly; these changes are not
+ reflected in page->height() and page->width(). Similar problems
+ occur if KViewShell required a shrunken version of the page, e.g. to
+ print multiple pages on one sheet of paper.
+
+ @warning The signal documentIsChanged() must not be emitted while the
+ method runs.
+
+ @warning Future versions of kviewshell will use threading to keep
+ the GUI responsive while pages are rendered. As a result, IT IS
+ ABSOLUTELY NECESSARY that your implementation is THREAD-SAFE, if
+ not, this can result in infrequent and very hard-to-find crashes of
+ your programm. Use the member mutex to make your implemetation
+ thread-safe.
+
+ @param resolution this argument contains the resolution of the
+ display device. In principle. In fact, kviewshell implements zooming
+ by using values that are not exactly the resolution of the display,
+ but multiplied with the zoom factor. Bottom line: the
+ DocumentRenderer should act as if this field indeed contains
+ resolution of the display device.
+
+ @param page pointer to a documentPage structure that this method
+ rendered into.
+
+ */
+ virtual void drawPage(double resolution, RenderedDocumentPage* page) = 0;
+
+ /** rendering of documents at thumbnail size
+
+ This method is used to draw thumbnails. The standared
+ implementations just calls 'drawPage' to do the job. Reimplement
+ this if the used fileformat has embedded thumbnails.
+
+ @warning Future versions of kviewshell will use threading to keep
+ the GUI responsive while pages are rendered. As a result, IT IS
+ ABSOLUTELY NECESSARY that your implementation is THREAD-SAFE, if
+ not, this can result in infrequent and very hard-to-find crashes of
+ your programm. Use the member mutex to make your implemetation
+ thread-safe.
+ */
+ virtual void drawThumbnail(double resolution, RenderedDocumentPage* page);
+
+ /** quick extraction of text information
+
+ This method returns the textinformation of the current page if available.
+ It is only called when the page pixmap is not of interest, so it is possible
+ to implement it much more efficiently then the drawPage() method.
+
+ The default implementation just calls drawPage().
+
+ @warning Future versions of kviewshell will use threading to keep
+ the GUI responsive while pages are rendered. As a result, IT IS
+ ABSOLUTELY NECESSARY that your implementation is THREAD-SAFE, if
+ not, this can result in infrequent and very hard-to-find crashes of
+ your programm. Use the member mutex to make your implemetation
+ thread-safe.
+
+ @param page pointer to a documentPage structure that this method rendered into.
+ */
+ virtual void getText(RenderedDocumentPage* page);
+
+ /** Flag to indicate if full text is supported
+
+ If your implementation of the drawPage() method supports full-text
+ information and writes to the documentPage::textLinkList, this
+ method should be re-implemented to return 'true'. The text-search
+ and text-selection utilities will then be enabled in the GUI.
+
+ The default implementation returns 'false'.
+ */
+ virtual bool supportsTextSearch() const {return false;}
+
+ /* This method will try to parse the reference part of the DVI
+ file's URL, (either a number, which is supposed to be a page
+ number, or src:(line)(filename)) and see if a corresponding
+ section of the DVI file can be found. If so, it returns an anchor
+ to that section. If not, it returns an invalid anchor.
+ */
+ virtual Anchor parseReference(const QString &reference);
+
+ /* Looks up a anchor in the "anchorList". Returns the anchor found,
+ or an invalid anchor otherwise.
+ */
+ Anchor findAnchor(const QString &);
+
+ /* Quick file validity check
+
+ This method is used internally, to check if a file is valid before
+ it is re-loaded. This is used e.g. by kdvi: when a the user TeXes a
+ file, the file changes immediately. If the 'watch file' option is
+ set, kdvi is informed immediately. At that time, however, the TeX
+ typesetting program still writes to the dvi file, and reloading must
+ be postphoned till TeX finishes, and the dvi file becomes vaild. If
+ such considerations are not an issue for you, this method does not
+ need to be re-implemented.
+
+ @warning Future versions of kviewshell will use threading to keep
+ the GUI responsive while pages are rendered. As a result, IT IS
+ ABSOLUTELY NECESSARY that your implementation is THREAD-SAFE, if
+ not, this can result in infrequent and very hard-to-find crashes of
+ your programm. Use the member mutex to make your implemetation
+ thread-safe.
+
+ @param fileName name of the file that should be checked for validity
+
+ @returns 'false' if the file 'fileName' is obviously invalid, and
+ true otherwise. The default implementation always returns
+ 'true'.
+ */
+ virtual bool isValidFile(const QString& fileName) const;
+
+ void setAccessibleBackground(bool accessibleMode, const QColor& background = QColor(255, 255, 255));
+
+signals:
+ /** signals that the document is changed
+
+ This signal can be emitted if the document or status of this class
+ changed internally so that all associated widgets should be
+ repainted. This could be emitted, e.g. if pages are removed from a
+ document, or if some preferences change that have some direct
+ influence on the way the document is rendered.
+
+ When this signal is emitted, the whole GUI setup is re-computed, and
+ all widgets are re-drawn. This can take considerable time.
+ */
+ void documentIsChanged();
+
+
+ /** sets text in the statusbar
+
+ This signal is emitted when the renderer needs to inform the user
+ via the status bar. Since the status bar is not always visible, and
+ since the duration that the message is shown is not quite specified,
+ this should not be used for important information. */
+ void setStatusBarText( const QString& );
+
+protected:
+ /** mutex used to make method thread-safe
+
+ This is a recursive mutex that must be used to make the public
+ methods of this class thread-safe. Future versions of kviewshell
+ will use threading to keep the GUI responsive while pages are
+ rendered. As a result, IT IS ABSOLUTELY NECESSARY that your
+ implementation is THREAD-SAFE, if not, this can result in infrequent
+ and very hard-to-find crashes of your programm.
+ */
+ QMutex mutex;
+
+
+ /** number of pages in the document
+
+ This member is set by the implementations of the setFile()
+ method. It is set to zero by the constructor and in clear().
+
+ @warning Only the constructor and the methods setFile() and clear()
+ may write to this member.
+ */
+ Q_UINT16 numPages;
+
+ /** page sizes
+
+ This vector contains the size of every page in the document. To
+ accomodate for file format that do not specify a page size, it is
+ explicitly allowed that this vector is empty, or that entries are
+ invalid page sizes. The values in this vector are set by the
+ setFile() method.
+
+ @note if the document does not specify page sizes, this vector
+ should --for performance reasons-- be empty, and not set to a large
+ number of invalid page sizes.
+
+ @warning Only the constructor and the methods setFile() and clear()
+ may write to this member.
+ */
+ QValueVector<SimplePageSize> pageSizes;
+
+ /** bookmarks
+
+ This (ordered!) list contains the bookmarks that are contained in
+ the document. The values in this vector are set by the setFile()
+ method, and cleared by the constructor and the clear() method.
+
+ @warning Only the constructor and the methods setFile() and clear()
+ may write to this member.
+ */
+ QPtrList<Bookmark> bookmarks;
+
+ /** map of anchors in a document.
+
+ This map contains the anchors that are contained in the
+ document. The values in this map are set by the setFile() method,
+ and cleared by the constructor and the clear() method.
+
+ @warning Only the constructor and the methods setFile() and clear()
+ may write to this member.
+ */
+ QMap<QString, Anchor> anchorList;
+
+ /** pointer to the parent widget
+
+ This pointer can be used by implementations e.g. to display error
+ messages. This pointer can well be zero.
+ */
+ QGuardedPtr<QWidget> parentWidget;
+
+ /** specifies if accessibilityBackgroundColor should be used
+
+ If true, the drawPage() and drawThumbnail() methods should use
+ accessibilityBackgroundColor as the backgroundcolor of the
+ pages.
+ */
+ bool accessibilityBackground;
+
+ /** background color, to be used for visibly impaired users
+
+ If accessibilityBackground is true, the drawPage() and
+ drawThumbnail() methods should use this color as the backgroundcolor
+ of the pages.
+ */
+ QColor accessibilityBackgroundColor;
+
+ /** Flag if document is modified
+
+ This flag indicates if the document was modified after it was
+ loaded. It is set to 'false' in the constructor, in the clear() and
+ setFile() method. It can be set to 'true' be methods that modify the
+ document (e.g. the deletePages() method of the djvu implementation
+ of this class).
+ */
+ bool _isModified;
+};
+
+#endif
diff --git a/kviewshell/documentWidget.cpp b/kviewshell/documentWidget.cpp
new file mode 100644
index 00000000..95b6f771
--- /dev/null
+++ b/kviewshell/documentWidget.cpp
@@ -0,0 +1,764 @@
+//
+// Class: DocumentWidget
+//
+// Widget for displaying TeX DVI files.
+// Part of KDVI- A previewer for TeX DVI files.
+//
+// (C) 2001 Stefan Kebekus
+// Copyright (C) 2004-2005 Wilfried Huss <Wilfried.Huss@gmx.at>
+// Distributed under the GPL
+//
+
+#include <config.h>
+
+#include <kaction.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kglobalsettings.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <qclipboard.h>
+#include <qcursor.h>
+#include <qimage.h>
+#include <qpainter.h>
+#include <qpixmap.h>
+
+#include "documentWidget.h"
+#include "pageView.h"
+#include "documentPageCache.h"
+#include "hyperlink.h"
+#include "renderedDocumentPagePixmap.h"
+#include "textBox.h"
+
+#include "kvsprefs.h"
+
+//#define DEBUG_DOCUMENTWIDGET
+
+const int DocumentWidget::bottom_right_corner[16] =
+ { 61, 71, 85, 95,
+ 71, 78, 89, 96,
+ 85, 89, 95, 98,
+ 95, 97, 98, 99 };
+
+const int DocumentWidget::bottom_left_corner[16] =
+ { 95, 85, 71, 61,
+ 97, 89, 78, 71,
+ 98, 95, 89, 85,
+ 99, 98, 96, 95 };
+
+const int DocumentWidget::shadow_strip[4] =
+ { 56, 67, 83, 94 };
+
+QColor DocumentWidget::backgroundColorForCorners;
+
+namespace {
+
+/** Holds the icon used as a overlay on pages which are not drawn yet. */
+QPixmap* busyIcon = 0;
+
+/** Internal storages used in the shadow drawing routines in the
+ drawContents method.*/
+QPixmap* URShadow = 0;
+QPixmap* BRShadow = 0;
+QPixmap* BLShadow = 0;
+
+} // namespace anon
+
+
+DocumentWidget::DocumentWidget(QWidget *parent, PageView *sv, DocumentPageCache *cache, const char *name )
+ : QWidget( parent, name ), indexOfUnderlinedLink(-1)
+{
+ moveTool = true;
+
+ selectionNeedsUpdating = false;
+
+ // Variables used in animation.
+ animationCounter = 0;
+ timerIdent = 0;
+ documentCache = cache;
+ scrollView = sv;
+
+ pixmapRequested = false;
+
+ scrollGuide = -1;
+
+ setMouseTracking(true);
+ setFocusPolicy(QWidget::ClickFocus);
+
+ connect(&clearStatusBarTimer, SIGNAL(timeout()), this, SLOT(clearStatusBar()));
+ setBackgroundMode(Qt::NoBackground);
+
+ if (!busyIcon)
+ {
+ busyIcon = new QPixmap(KGlobal::iconLoader()->loadIcon("gear", KIcon::NoGroup, KIcon::SizeMedium));
+
+ URShadow = new QPixmap();
+ BRShadow = new QPixmap();
+ BLShadow = new QPixmap();
+
+ URShadow->resize(4,4);
+ BRShadow->resize(4,4);
+ BLShadow->resize(4,4);
+ }
+}
+
+
+void DocumentWidget::setPageNumber(Q_UINT16 nr)
+{
+ pageNr = nr;
+
+ selectionNeedsUpdating = true;
+
+ // We have to reset this, because otherwise we might crash in the mouseMoveEvent
+ // After switching pages in SinglePageMode or OverviewMode.
+ indexOfUnderlinedLink = -1;
+
+ // Resize Widget if the size of the new page is different than the size of the old page.
+ QSize _pageSize = documentCache->sizeOfPageInPixel(pageNr);
+ if (_pageSize != pageSize())
+ {
+ setPageSize(_pageSize);
+ }
+ update();
+}
+
+QRect DocumentWidget::linkFlashRect()
+{
+ int width = pageSize().width()/(11 - animationCounter);
+ int height = pageSize().height()/(60 - 4 * animationCounter);
+ return QRect((pageSize().width()-width)/2, flashOffset - height/2, width, height);
+}
+
+void DocumentWidget::timerEvent( QTimerEvent *e )
+{
+ if (animationCounter == 0) {
+ killTimer(e->timerId());
+ timerIdent = startTimer(50); // Proceed with the animation in 1/10s intervals
+ }
+
+ animationCounter++;
+
+ QRect flashRect = linkFlashRect();
+ flashRect.addCoords(-1, -1, 1, 1);
+
+ if (animationCounter >= 10) {
+ killTimer(e->timerId());
+ timerIdent = 0;
+ animationCounter = 0;
+ }
+
+ repaint(flashRect, false);
+}
+
+
+void DocumentWidget::flash(int fo)
+{
+ if (timerIdent != 0)
+ {
+ killTimer(timerIdent);
+ // Delete old flash rectangle
+ animationCounter = 10;
+ QRect flashRect = linkFlashRect();
+ flashRect.addCoords(-1, -1, 1, 1);
+ repaint(flashRect, false);
+ }
+ animationCounter = 0;
+ flashOffset = fo;
+ timerIdent = startTimer(50); // Start the animation. The animation proceeds in 1/10s intervals
+}
+
+
+void DocumentWidget::paintEvent(QPaintEvent *e)
+{
+#ifdef DEBUG_DOCUMENTWIDGET
+ kdDebug(1223) << "DocumentWidget::paintEvent() called" << endl;
+#endif
+
+ // Check if this widget is really visible to the user. If not, there
+ // is nothing to do. Remark: if we don't do this, then under QT
+ // 3.2.3 the following happens: when the user changes the zoom
+ // value, all those widgets are updated which the user has EVER
+ // seen, not just those that are visible at the moment. If the
+ // document contains several thousand pages, it is easily possible
+ // that this means that a few hundred of these are re-painted (which
+ // takes substantial time) although perhaps only three widgets are
+ // visible and *should* be updated. I believe this is some error in
+ // QT, but I am not positive about that ---Stefan Kebekus.
+ if (!isVisible())
+ {
+ //kdDebug() << "widget of page " << pageNr << " is not visible. Abort rendering" << endl;
+ kapp->processEvents();
+ return;
+ }
+
+ QPainter p(this);
+ p.setClipRegion(e->region());
+
+ // Paint a black border around the widget
+ p.setRasterOp(Qt::CopyROP);
+ p.setBrush(NoBrush);
+ p.setPen(Qt::black);
+ QRect outlineRect = pageRect();
+ outlineRect.addCoords(-1, -1, 1, 1);
+ p.drawRect(outlineRect);
+
+ // Paint page shadow
+ QColor backgroundColor = colorGroup().mid();
+
+ // (Re-)generate the Pixmaps for the shadow corners, if necessary
+ if (backgroundColor != backgroundColorForCorners)
+ {
+ backgroundColorForCorners = backgroundColor;
+ QImage tmp(4, 4, 32);
+ for(int x=0; x<4; x++)
+ for(int y=0; y<4; y++)
+ tmp.setPixel(x, y, backgroundColor.light(bottom_right_corner[x+4*y]).rgb() );
+ BRShadow->convertFromImage(tmp);
+
+ for(int x=0; x<4; x++)
+ for(int y=0; y<4; y++)
+ tmp.setPixel(x, y, backgroundColor.light(bottom_left_corner[x+4*y]).rgb() );
+ BLShadow->convertFromImage(tmp);
+
+ URShadow->convertFromImage(tmp.mirror(true, true));
+ }
+
+ // Draw right and bottom shadows
+ for(int i=0; i<4; i++)
+ {
+ p.setPen(backgroundColor.light(shadow_strip[i]));
+ // Right shadow
+ p.drawLine(pageSize().width()+i+2, 8, pageSize().width()+i+2, pageSize().height()+2);
+ // Bottom shadow
+ p.drawLine(8, pageSize().height()+i+2, pageSize().width()+2, pageSize().height()+i+2);
+ }
+ // Draw shadow corners
+ p.drawPixmap(pageSize().width()+2, pageSize().height()+2, *BRShadow);
+ p.drawPixmap(4, pageSize().height()+2, *BLShadow);
+ p.drawPixmap(pageSize().width()+2, 4, *URShadow);
+
+ // Draw corners
+ p.fillRect(0, pageSize().height()+2, 4, 4, backgroundColor);
+ p.fillRect(pageSize().width()+2, 0, 4, 4, backgroundColor);
+
+ if (!documentCache->isPageCached(pageNr, pageSize()))
+ {
+ QRect destRect = e->rect().intersect(pageRect());
+ if (KVSPrefs::changeColors() && KVSPrefs::renderMode() == KVSPrefs::EnumRenderMode::Paper)
+ p.fillRect(destRect, KVSPrefs::paperColor());
+ else
+ p.fillRect(destRect, Qt::white);
+
+ // Draw busy indicator.
+ // Im not really sure if this is a good idea.
+ // While it is nice to see an indication that something is happening for pages which
+ // take long to redraw, it gets quite annoing for fast redraws.
+ // TODO: Disable or find something less distractiong.
+ p.drawPixmap(10, 10, *busyIcon);
+
+ if (!pixmapRequested)
+ {
+ // Request page pixmap.
+ pixmapRequested = true;
+ QTimer::singleShot(50, this, SLOT(delayedRequestPage()));
+ }
+ return;
+ }
+
+ RenderedDocumentPagePixmap *pageData = documentCache->getPage(pageNr);
+ if (pageData == 0) {
+#ifdef DEBUG_DOCUMENTWIDGET
+ kdDebug(1223) << "DocumentWidget::paintEvent: no documentPage generated" << endl;
+#endif
+ return;
+ }
+
+ QMemArray<QRect> damagedRects = e->region().rects();
+ for (unsigned int i = 0; i < damagedRects.count(); i++)
+ {
+ // Paint the page where it intersects with the damaged area.
+ QRect destRect = damagedRects[i].intersect(pageRect());
+
+ // The actual page starts at point (1,1) because of the outline.
+ // Therefore we need to shift the destination rectangle.
+ QRect pixmapRect = destRect;
+ pixmapRect.moveBy(-1,-1);
+
+ if (KVSPrefs::changeColors() && KVSPrefs::renderMode() != KVSPrefs::EnumRenderMode::Paper)
+ {
+ // Paint widget contents with accessibility changes.
+ bitBlt ( this, destRect.topLeft(), &pageData->accessiblePixmap(), pixmapRect, CopyROP);
+ }
+ else
+ {
+ // Paint widget contents
+ bitBlt ( this, destRect.topLeft(), pageData, pixmapRect, CopyROP);
+ }
+ }
+ // Underline hyperlinks
+ if (KVSPrefs::underlineLinks() == KVSPrefs::EnumUnderlineLinks::Enabled ||
+ KVSPrefs::underlineLinks() == KVSPrefs::EnumUnderlineLinks::OnlyOnHover)
+ {
+ int h = 2; // Height of line.
+ for(int i = 0; i < (int)pageData->hyperLinkList.size(); i++)
+ {
+ if (KVSPrefs::underlineLinks() == KVSPrefs::EnumUnderlineLinks::OnlyOnHover &&
+ i != indexOfUnderlinedLink)
+ continue;
+ int x = pageData->hyperLinkList[i].box.left();
+ int w = pageData->hyperLinkList[i].box.width();
+ int y = pageData->hyperLinkList[i].baseline;
+
+ QRect hyperLinkRect(x, y, w, h);
+ if (hyperLinkRect.intersects(e->rect()))
+ {
+#ifdef DEBUG_DOCUMENTWIDGET
+ kdDebug(1223) << "Underline hyperlink \"" << pageData->hyperLinkList[i].linkText << "\"" << endl;
+#endif
+ p.fillRect(x, y, w, h, KGlobalSettings::linkColor());
+ }
+ }
+ }
+
+ // Paint flashing frame, if appropriate
+ if (animationCounter > 0 && animationCounter < 10)
+ {
+ int gbChannel = 255 - (9-animationCounter)*28;
+ p.setPen(QPen(QColor(255, gbChannel, gbChannel), 3));
+ p.drawRect(linkFlashRect());
+ }
+
+ // Mark selected text.
+ TextSelection selection = documentCache->selectedText();
+ if ((selection.getPageNumber() != 0) && (selection.getPageNumber() == pageNr))
+ {
+ if (selectionNeedsUpdating)
+ {
+ //The zoom value has changed, therefore we need to recalculate
+ //the selected region.
+ selectedRegion = pageData->selectedRegion(selection);
+ selectionNeedsUpdating = false;
+ }
+
+ p.setPen(NoPen);
+ p.setBrush(white);
+ p.setRasterOp(Qt::XorROP);
+
+ QMemArray<QRect> selectionRects = selectedRegion.rects();
+
+ for (unsigned int i = 0; i < selectionRects.count(); i++)
+ p.drawRect(selectionRects[i]);
+ }
+
+ // Draw scroll Guide
+ if (scrollGuide >= 0)
+ {
+ // Don't draw over the page shadow
+ p.setClipRegion(e->region().intersect(pageRect()));
+ p.setRasterOp(Qt::CopyROP);
+ p.setPen(Qt::red);
+ p.drawLine(1, scrollGuide, pageSize().width(), scrollGuide);
+ }
+}
+
+void DocumentWidget::drawScrollGuide(int ycoord)
+{
+ //kdDebug() << "draw scroll guide for page " << pageNr << " at y = " << ycoord << endl;
+ scrollGuide = ycoord;
+ update(QRect(1, scrollGuide, pageSize().width(), 1));
+ QTimer::singleShot(1000, this, SLOT(clearScrollGuide()));
+}
+
+void DocumentWidget::clearScrollGuide()
+{
+ //kdDebug() << "clear scroll guide for page " << pageNr << " at y = " << scrollGuide << endl;
+ int temp = scrollGuide;
+ scrollGuide = -1;
+ update(QRect(1, temp, pageSize().width(), 1));
+}
+
+void DocumentWidget::select(const TextSelection& newSelection)
+{
+ // Get a pointer to the page contents
+ RenderedDocumentPage *pageData = documentCache->getPage(pageNr);
+ if (pageData == 0) {
+ kdDebug(1223) << "DocumentWidget::select() pageData for page #" << pageNr << " is empty" << endl;
+ return;
+ }
+
+ documentCache->selectText(newSelection);
+
+ selectedRegion = pageData->selectedRegion(documentCache->selectedText());
+ selectionNeedsUpdating = false;
+
+ update();
+}
+
+void DocumentWidget::selectAll()
+{
+ // pageNr == 0 indicated an invalid page (e.g. page number not yet
+ // set)
+ if (pageNr == 0)
+ return;
+
+ // Get a pointer to the page contents
+ RenderedDocumentPage *pageData = documentCache->getPage(pageNr);
+ if (pageData == 0) {
+ kdDebug(1223) << "DocumentWidget::selectAll() pageData for page #" << pageNr << " is empty" << endl;
+ return;
+ }
+
+ TextSelection selection;
+ // mark everything as selected
+ QString selectedText("");
+ for(unsigned int i = 0; i < pageData->textBoxList.size(); i++) {
+ selectedText += pageData->textBoxList[i].text;
+ selectedText += "\n";
+ }
+ selection.set(pageNr, 0, pageData->textBoxList.size()-1, selectedText);
+
+ selectedRegion = pageData->selectedRegion(selection);
+
+ documentCache->selectText(selection);
+
+ // Re-paint
+ update();
+}
+
+
+void DocumentWidget::mousePressEvent ( QMouseEvent * e )
+{
+#ifdef DEBUG_DOCUMENTWIDGET
+ kdDebug(1223) << "DocumentWidget::mousePressEvent(...) called" << endl;
+#endif
+
+ // Make sure the event is passed on to the higher-level widget;
+ // otherwise QT gets the coordinated in the mouse move events wrong
+ e->ignore();
+
+ // pageNr == 0 indicated an invalid page (e.g. page number not yet
+ // set)
+ if (pageNr == 0)
+ return;
+
+ // Get a pointer to the page contents
+ RenderedDocumentPage *pageData = documentCache->getPage(pageNr);
+ if (pageData == 0) {
+ kdDebug(1223) << "DocumentWidget::selectAll() pageData for page #" << pageNr << " is empty" << endl;
+ return;
+ }
+
+ // Check if the mouse is pressed on a regular hyperlink
+ if (e->button() == LeftButton) {
+ if (pageData->hyperLinkList.size() > 0)
+ for(unsigned int i = 0; i < pageData->hyperLinkList.size(); i++) {
+ if (pageData->hyperLinkList[i].box.contains(e->pos())) {
+ emit(localLink(pageData->hyperLinkList[i].linkText));
+ return;
+ }
+ }
+ if (moveTool)
+ setCursor(Qt::SizeAllCursor);
+ else
+ setCursor(Qt::IbeamCursor);
+ }
+
+ if (e->button() == RightButton || (!moveTool && e->button() == LeftButton))
+ {
+ setCursor(Qt::IbeamCursor);
+ // If Shift is not pressed clear the current selection,
+ // otherwise modify the existing selection.
+ if (!(e->state() & ShiftButton))
+ {
+ firstSelectedPoint = e->pos();
+ selectedRectangle = QRect();
+ selectedRegion = QRegion();
+ emit clearSelection();
+ }
+ }
+}
+
+
+void DocumentWidget::mouseReleaseEvent ( QMouseEvent *e )
+{
+ // Make sure the event is passed on to the higher-level widget;
+ // otherwise the mouse cursor in the centeringScrollview is wrong
+ e->ignore();
+
+ if (e->button() == RightButton || (!moveTool && e->button() == LeftButton))
+ {
+ // If the selectedRectangle is empty then there was only a single right click.
+ if (firstSelectedPoint == e->pos())
+ {
+ if (pageNr == 0)
+ return;
+
+ // Get a pointer to the page contents
+ RenderedDocumentPage* pageData = documentCache->getPage(pageNr);
+ if (pageData == 0)
+ {
+ kdDebug(1223) << "DocumentWidget::mouseReleaseEvent() pageData for page #" << pageNr << " is empty" << endl;
+ return;
+ }
+
+ TextSelection newTextSelection = pageData->select(firstSelectedPoint);
+ updateSelection(newTextSelection);
+ }
+ }
+
+ //Reset the cursor to the usual arrow if we use the move tool, and
+ // The textselection cursor if we use the selection tool.
+ setStandardCursor();
+}
+
+
+void DocumentWidget::mouseMoveEvent ( QMouseEvent * e )
+{
+#ifdef DEBUG_DOCUMENTWIDGET
+ kdDebug(1223) << "DocumentWidget::mouseMoveEvent(...) called" << endl;
+#endif
+
+
+ // pageNr == 0 indicated an invalid page (e.g. page number not yet
+ // set)
+ if (pageNr == 0)
+ return;
+
+ // Get a pointer to the page contents
+ RenderedDocumentPage *pageData = documentCache->getPage(pageNr);
+ if (pageData == 0) {
+ kdDebug(1223) << "DocumentWidget::selectAll() pageData for page #" << pageNr << " is empty" << endl;
+ return;
+ }
+
+ // If no mouse button pressed
+ if (e->state() == 0) {
+ // Remember the index of the underlined link.
+ int lastUnderlinedLink = indexOfUnderlinedLink;
+ // go through hyperlinks
+ for(unsigned int i = 0; i < pageData->hyperLinkList.size(); i++) {
+ if (pageData->hyperLinkList[i].box.contains(e->pos())) {
+ clearStatusBarTimer.stop();
+ setCursor(pointingHandCursor);
+ QString link = pageData->hyperLinkList[i].linkText;
+ if ( link.startsWith("#") )
+ link = link.remove(0,1);
+
+ emit setStatusBarText( i18n("Link to %1").arg(link) );
+
+ indexOfUnderlinedLink = i;
+ if (KVSPrefs::underlineLinks() == KVSPrefs::EnumUnderlineLinks::OnlyOnHover &&
+ indexOfUnderlinedLink != lastUnderlinedLink)
+ {
+ QRect newUnderline = pageData->hyperLinkList[i].box;
+ // Increase Rectangle so that the whole line really lines in it.
+ newUnderline.addCoords(0, 0, 0, 2);
+ // Redraw widget
+ update(newUnderline);
+
+ if (lastUnderlinedLink != -1 && lastUnderlinedLink < pageData->hyperLinkList.size())
+ {
+ // Erase old underline
+ QRect oldUnderline = pageData->hyperLinkList[lastUnderlinedLink].box;
+ oldUnderline.addCoords(0, 0, 0, 2);
+ update(oldUnderline);
+ }
+ }
+ return;
+ }
+ }
+ // Whenever we reach this the mouse hovers no link.
+ indexOfUnderlinedLink = -1;
+ if (KVSPrefs::underlineLinks() == KVSPrefs::EnumUnderlineLinks::OnlyOnHover &&
+ lastUnderlinedLink != -1 && lastUnderlinedLink < pageData->hyperLinkList.size())
+ {
+ // Erase old underline
+ QRect oldUnderline = pageData->hyperLinkList[lastUnderlinedLink].box;
+ // Increase Rectangle so that the whole line really lines in it.
+ oldUnderline.addCoords(0, 0, 0, 2);
+ // Redraw widget
+ update(oldUnderline);
+ }
+ // Cursor not over hyperlink? Then let the cursor be the usual arrow if we use the move tool, and
+ // The textselection cursor if we use the selection tool.
+ setStandardCursor();
+ }
+
+ if (!clearStatusBarTimer.isActive())
+ clearStatusBarTimer.start(200, true); // clear the statusbar after 200 msec.
+
+ // Left mouse button pressed -> Text scroll function
+ if ((e->state() & LeftButton) != 0 && moveTool)
+ {
+ // Pass the mouse event on to the owner of this widget ---under
+ // normal circumstances that is the centeringScrollView which will
+ // then scroll the scrollview contents
+ e->ignore();
+ }
+
+ // Right mouse button pressed -> Text copy function
+ if ((e->state() & RightButton) != 0 || (!moveTool && (e->state() & LeftButton != 0)))
+ {
+ if (selectedRectangle.isEmpty()) {
+ firstSelectedPoint = e->pos();
+ selectedRectangle.setRect(e->pos().x(),e->pos().y(),1,1);
+ } else {
+ int lx = e->pos().x() < firstSelectedPoint.x() ? e->pos().x() : firstSelectedPoint.x();
+ int rx = e->pos().x() > firstSelectedPoint.x() ? e->pos().x() : firstSelectedPoint.x();
+ int ty = e->pos().y() < firstSelectedPoint.y() ? e->pos().y() : firstSelectedPoint.y();
+ int by = e->pos().y() > firstSelectedPoint.y() ? e->pos().y() : firstSelectedPoint.y();
+ selectedRectangle.setCoords(lx,ty,rx,by);
+ }
+
+ // Now that we know the rectangle, we have to find out which words
+ // intersect it!
+ TextSelection newTextSelection = pageData->select(selectedRectangle);
+
+ updateSelection(newTextSelection);
+ }
+}
+
+void DocumentWidget::updateSelection(const TextSelection& newTextSelection)
+{
+ if (newTextSelection != documentCache->selectedText())
+ {
+ if (newTextSelection.isEmpty())
+ {
+ // Clear selection
+ documentCache->deselectText();
+ selectedRectangle = QRect();
+ selectedRegion = QRegion();
+ update();
+ }
+ else
+ {
+ if (pageNr == 0)
+ return;
+
+ // Get a pointer to the page contents
+ RenderedDocumentPage* pageData = documentCache->getPage(pageNr);
+ if (pageData == 0)
+ {
+ kdDebug(1223) << "DocumentWidget::mouseReleaseEvent() pageData for page #" << pageNr << " is empty" << endl;
+ return;
+ }
+
+ documentCache->selectText(newTextSelection);
+
+ QRegion newlySelectedRegion = pageData->selectedRegion(documentCache->selectedText());
+
+ // Compute the region that needs to be updated
+ QRegion updateRegion;
+ if(!selectedRegion.isEmpty())
+ {
+ updateRegion = newlySelectedRegion.eor(selectedRegion);
+ }
+ else
+ {
+ updateRegion = newlySelectedRegion;
+ }
+
+ selectedRegion = newlySelectedRegion;
+
+ QMemArray<QRect> rectangles = updateRegion.rects();
+ for (unsigned int i = 0; i < rectangles.count(); i++)
+ {
+ repaint(rectangles[i]);
+ }
+ }
+ }
+}
+
+
+void DocumentWidget::clearStatusBar()
+{
+ emit setStatusBarText( QString::null );
+}
+
+
+void DocumentWidget::delayedRequestPage()
+{
+ if (!isVisible())
+ {
+ // We only want to calculate the page pixmap for widgets that are currently visible.
+ // When we are fast scrolling thru the document many paint events are created, that
+ // are often not needed anymore at the time the eventloop executes them.
+
+ //kdDebug() << "delayedRequest: widget of page " << pageNr << " is not visible. Abort rendering" << endl;
+ pixmapRequested = false;
+ kapp->processEvents();
+ return;
+ }
+
+ documentCache->getPage(pageNr);
+ pixmapRequested = false;
+ update();
+
+ // If more widgets need updateing at the some time, the next line allows them to be
+ // displayed one after another. Widthout it all widgets are updated after all the rendering
+ // is completed. This is especially noticable in overview mode. After the change to a seperate
+ // rendering thread this will probably not be needed anymore.
+ kapp->processEvents();
+}
+
+QSize DocumentWidget::pageSize() const
+{
+ // Substract size of the shadow.
+ return size() - QSize(6, 6);
+}
+
+QRect DocumentWidget::pageRect() const
+{
+ QRect boundingRect = rect();
+ // Substract the shadow.
+ boundingRect.addCoords(1,1,-5,-5);
+ return boundingRect;
+}
+
+void DocumentWidget::setPageSize(const QSize& pageSize)
+{
+ // When the page size changes this means either the paper size
+ // has been changed, or the zoomlevel has been changed.
+ // If the zoomlevel changes we need to recalculate the selected
+ // region. We do this always, just to be on the safe side.
+ selectionNeedsUpdating = true;
+
+ // Add size of the shadow.
+ resize(pageSize + QSize(6,6));
+}
+
+void DocumentWidget::setPageSize(int width, int height)
+{
+ setPageSize(QSize(width, height));
+}
+
+
+void DocumentWidget::slotEnableMoveTool(bool enable)
+{
+ moveTool = enable;
+
+ setStandardCursor();
+}
+
+
+void DocumentWidget::setStandardCursor()
+{
+ if (moveTool)
+ {
+ setCursor(Qt::arrowCursor);
+ }
+ else
+ {
+ setCursor(Qt::IbeamCursor);
+ }
+}
+
+
+bool DocumentWidget::isVisible()
+{
+ QRect visibleRect(scrollView->contentsX(), scrollView->contentsY(), scrollView->visibleWidth(), scrollView->visibleHeight());
+ QRect widgetRect(scrollView->childX(this), scrollView->childY(this), width(), height());
+ return widgetRect.intersects(visibleRect);
+}
+
+#include "documentWidget.moc"
diff --git a/kviewshell/documentWidget.h b/kviewshell/documentWidget.h
new file mode 100644
index 00000000..50f2ee44
--- /dev/null
+++ b/kviewshell/documentWidget.h
@@ -0,0 +1,193 @@
+// -*- C++ -*-
+//
+// Class: documentWidet
+//
+// Widget for displaying TeX DVI files.
+// Part of KDVI- A previewer for TeX DVI files.
+//
+// (C) 2004 Stefan Kebekus.
+// Copyright (C) 2004-2005 Wilfried Huss <Wilfried.Huss@gmx.at>
+//
+// Distributed under the GPL.
+
+#ifndef _documentwidget_h_
+#define _documentwidget_h_
+
+#include "selection.h"
+
+#include <qregion.h>
+#include <qtimer.h>
+#include <qwidget.h>
+
+class DocumentPageCache;
+class PageView;
+class QMouseEvent;
+class QPaintEvent;
+
+
+/* DocumentWidget */
+
+class DocumentWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ DocumentWidget(QWidget *parent, PageView *sv, DocumentPageCache *cache, const char *name);
+
+ void setPageNumber(Q_UINT16 pageNr);
+ Q_UINT16 getPageNumber() const {return pageNr;}
+
+ /** Returns the size of the widget without the page shadow. */
+ QSize pageSize() const;
+ /** Returns the bounding rectangle of the widget without the page shadow. */
+ QRect pageRect() const;
+
+ /** Draw a red vertical line at y-coordinate ycoord. The line is removed again
+ after one second. This is used to make it easier to regain reading focus if
+ the whole page is scrolled up or down. */
+ void drawScrollGuide(int ycoord);
+
+ /** Checks if the page is currently visible in the PageView. */
+ bool isVisible();
+
+public slots:
+ void slotEnableMoveTool(bool enable);
+
+ void select(const TextSelection&);
+ void selectAll();
+ void flash(int);
+
+ /** Sets the size of the widget so that the page is of the given size.
+ The widget gets slightly bigger because of the page shadow. */
+ void setPageSize(const QSize&);
+ void setPageSize(int width, int height);
+
+signals:
+ /** Passed through to the top-level kpart. */
+ void setStatusBarText( const QString& );
+ void localLink( const QString& );
+
+ /** This signal is emitted when the widget resizes itself */
+ void resized();
+
+ /** This signal is emitted when the selection needs to be cleared. */
+ void clearSelection();
+
+protected:
+ virtual void paintEvent (QPaintEvent *);
+ virtual void mousePressEvent ( QMouseEvent * e );
+ virtual void mouseReleaseEvent (QMouseEvent *);
+
+ /** This method is used by the DocumentWidget to find out of the
+ mouse pointer hovers over a hyperlink, and to update the
+ statusbar accordingly. Scrolling with the left mouse button
+ pressed, and the text copy functions are also implemented here.
+ Re-implementations of this method should do the following:
+
+ 0) Immediately return if pageNr == 0, i.e. if no page number has
+ been set
+
+ 1) Call the standard implementation using
+
+ DocumentWidget::mouseMoveEvent(e);
+
+ 2) Ignore the QMouseEvent if a mouse button is pressed
+
+ 3) If no mouse button is pressed, analyze the mouse movement and
+ take appropriate actions. To set statusbar text, do
+
+ clearStatusBarTimer.stop();
+ emit setStatusBarText( i18n("Whatever string") );
+
+ To clear the statusbar, use the following code
+
+ if (!clearStatusBarTimer.isActive())
+ clearStatusBarTimer.start(200, true);
+
+ This clears the statusbar after 200 msec and avoids awful
+ flickering when the mouse is swiftly moved across various
+ areas in the widget.
+
+ */
+ virtual void mouseMoveEvent (QMouseEvent *);
+
+protected:
+ void updateSelection(const TextSelection& newTextSelection);
+
+ /** Methods and counters used for the animation to mark the target of
+ an hyperlink. */
+ int timerIdent;
+ void timerEvent( QTimerEvent *e );
+ int animationCounter;
+ int flashOffset;
+
+ Q_UINT16 pageNr;
+
+ /* This timer is used to delay clearing of the statusbar. Clearing
+ the statusbar is delayed to avoid awful flickering when the mouse
+ moves over a block of text that contains source hyperlinks. The
+ signal timeout() is connected to the method clearStatusBar() of
+ *this. */
+ QTimer clearStatusBarTimer;
+
+ /* Data structures used for marking text with the mouse */
+ QPoint firstSelectedPoint;
+ QRect selectedRectangle;
+
+ /** Pointer to the PageView that contains this
+ widget. This pointer is used in the re-implementation of the
+ paintEvent() method ---see the explanation there. */
+ PageView *scrollView;
+ DocumentPageCache *documentCache;
+
+ /** Currently selected Region */
+ QRegion selectedRegion;
+
+ /** This is set to the index of the link over which the mouse pointer currently resides,
+ and -1 if the no link is hovered.
+ Is used when "Underline Links" is set to "Only on Hover". */
+ int indexOfUnderlinedLink;
+
+ /** True if there is already a request for this page to the renderer. */
+ bool pixmapRequested;
+
+ /** Sets the cursor to an arrow if the move tool is selected, and to the text selection
+ cursor if the selection tool is active. */
+ virtual void setStandardCursor();
+
+private slots:
+ /** This slot emits the signal setStatusBarText(QString::null) to
+ clear the status bar. It is connected to the timeout slot of the
+ clearStatusBarTimer. */
+ void clearStatusBar();
+
+ void delayedRequestPage();
+
+ /** Hide the scroll guide. This slot is called one second after drawScrollGuide(). */
+ void clearScrollGuide();
+
+private:
+ QRect linkFlashRect();
+
+ /** If this variable is positive draw a vertical line at this y-coordinate. */
+ int scrollGuide;
+
+ /** Color used by in the shadow drawing to check if the background color has been changed. */
+ static QColor backgroundColorForCorners;
+
+ /** The following tables store grey values for roundish shadow
+ corners. They were shamelessly stolen from kdelibs/kdefx/kstyle.cpp. */
+ static const int bottom_right_corner[16];
+ static const int bottom_left_corner[16];
+ static const int shadow_strip[4];
+
+ bool moveTool;
+
+ /** If this is true the zoomlevel has changed and we need to update the
+ selected region. */
+ bool selectionNeedsUpdating;
+};
+
+
+
+#endif
diff --git a/kviewshell/emptyRenderer.cpp b/kviewshell/emptyRenderer.cpp
new file mode 100644
index 00000000..e89ffd6e
--- /dev/null
+++ b/kviewshell/emptyRenderer.cpp
@@ -0,0 +1,29 @@
+// ***************************************************************************
+//
+// 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 <config.h>
+
+#include "emptyRenderer.h"
+
+EmptyRenderer::EmptyRenderer(QWidget* parent)
+ : DocumentRenderer(parent)
+{
+}
+
+#include "emptyRenderer.moc"
diff --git a/kviewshell/emptyRenderer.h b/kviewshell/emptyRenderer.h
new file mode 100644
index 00000000..62fd46f7
--- /dev/null
+++ b/kviewshell/emptyRenderer.h
@@ -0,0 +1,41 @@
+// -*- C++ -*-
+// ***************************************************************************
+//
+// 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 _EMPTYRENDERER_H_
+#define _EMPTYRENDERER_H_
+
+#include "documentRenderer.h"
+
+class RenderedDocumentPage;
+
+
+class EmptyRenderer : public DocumentRenderer
+{
+ Q_OBJECT
+
+public:
+ EmptyRenderer(QWidget* parent);
+
+ virtual bool setFile(const QString &, const KURL &) { return false; }
+
+ void drawPage(double res, RenderedDocumentPage* page) { Q_UNUSED(res); Q_UNUSED(page); }
+};
+
+#endif
diff --git a/kviewshell/empty_multipage.cpp b/kviewshell/empty_multipage.cpp
new file mode 100644
index 00000000..39de90a3
--- /dev/null
+++ b/kviewshell/empty_multipage.cpp
@@ -0,0 +1,48 @@
+// ***************************************************************************
+//
+// 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 <config.h>
+
+#include <kglobal.h>
+#include <klocale.h>
+
+#include "empty_multipage.h"
+
+K_EXPORT_COMPONENT_FACTORY(emptymultipagepart, EmptyMultiPageFactory)
+
+EmptyMultiPage::EmptyMultiPage(QWidget* parentWidget, const char* widgetName, QObject* parent, const char* name,
+ const QStringList& args)
+ : KMultiPage(parentWidget, widgetName, parent, name), emptyRenderer(parentWidget)
+{
+ Q_UNUSED(args);
+ setInstance(EmptyMultiPageFactory::instance());
+
+ emptyRenderer.setName("Empty renderer");
+ setRenderer(&emptyRenderer);
+}
+
+KAboutData* EmptyMultiPage::createAboutData()
+{
+ return new KAboutData("emptymultipage", I18N_NOOP("Empty Multipage"),
+ "1.0", I18N_NOOP(""),
+ KAboutData::License_GPL,
+ I18N_NOOP("Copyright (c) 2005 Wilfried Huss"));
+}
+
+#include "empty_multipage.moc"
diff --git a/kviewshell/empty_multipage.h b/kviewshell/empty_multipage.h
new file mode 100644
index 00000000..92d824b7
--- /dev/null
+++ b/kviewshell/empty_multipage.h
@@ -0,0 +1,51 @@
+// -*- C++ -*-
+// ***************************************************************************
+//
+// 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 EMPTY_MULTIPAGE_H
+#define EMPTY_MULTIPAGE_H
+
+#include "kmultipage.h"
+#include "emptyRenderer.h"
+
+#include <kparts/genericfactory.h>
+
+
+class EmptyMultiPage : public KMultiPage
+{
+ Q_OBJECT
+
+public:
+ EmptyMultiPage(QWidget* parentWidget, const char* widgetName, QObject* parent, const char* name,
+ const QStringList& args = QStringList());
+
+ virtual QStringList fileFormats() const { return QString::null; }
+
+ /// opens a file
+ virtual bool openFile() { return false; }
+
+ static KAboutData* createAboutData();
+
+private:
+ EmptyRenderer emptyRenderer;
+};
+
+typedef KParts::GenericFactory<EmptyMultiPage> EmptyMultiPageFactory;
+
+#endif
diff --git a/kviewshell/emptymultipage.desktop b/kviewshell/emptymultipage.desktop
new file mode 100644
index 00000000..c2fef0e8
--- /dev/null
+++ b/kviewshell/emptymultipage.desktop
@@ -0,0 +1,29 @@
+[Desktop Entry]
+Type=Service
+Comment=
+Name=EmptyMultiPage
+Name[de]=Leere Mehrfachseite
+Name[el]=ΚενήΠολλαπλήΣελίδα
+Name[es]=Vaciado multipágina
+Name[fi]=TyhjäMoniSivu
+Name[fr]=Multi-page vide
+Name[gl]=MultiPáxinaBaleira
+Name[hu]=ÜresTöbbOldalas
+Name[it]=MultiPaginaVuota
+Name[nb]=Tom Flerside
+Name[nds]=Leddig Mehrfachsiet
+Name[ne]=रिक्त बहुपृष्ठ
+Name[nl]=LegeMultiPagina
+Name[nn]=Tom fleirside
+Name[pl]=Puste wielostronicowe
+Name[pt_BR]=MultiPáginas Vazias
+Name[ro]=Pagini multiple goale
+Name[sk]=EmprtyMultiPage
+Name[sv]=Tom flera sidor
+Name[ta]=காலியான பலபக்கம்
+Name[tr]=BoşÇokluSayfa
+Name[zh_HK]=空的多頁
+ServiceTypes=KViewShell/MultiPage
+X-KDE-Library=emptymultipagepart
+X-KDE-EmptyMultiPage=1
+X-KDE-MultiPageVersion=2
diff --git a/kviewshell/history.cpp b/kviewshell/history.cpp
new file mode 100644
index 00000000..a8765220
--- /dev/null
+++ b/kviewshell/history.cpp
@@ -0,0 +1,91 @@
+// history.cpp
+//
+// (C) 2001 Stefan Kebekus
+// Distributed under the GPL
+
+#include <config.h>
+
+#include <kdebug.h>
+
+#include "history.h"
+
+HistoryItem::HistoryItem(Q_UINT32 p, Q_UINT32 y)
+ : page(p), ypos(y)
+{
+}
+
+bool HistoryItem::operator== (const HistoryItem& item) const
+{
+ return page == item.page && ypos == item.ypos;
+}
+
+History::History()
+{
+}
+
+void History::add(Q_UINT32 page, Q_UINT32 ypos)
+{
+ HistoryItem item(page, ypos);
+
+ if (historyList.empty())
+ {
+ currentItem = historyList.append(item);
+ }
+ else
+ {
+ // Don't add the same item several times in a row
+ if (item == *currentItem)
+ return;
+
+ currentItem++;
+ if (currentItem == historyList.end())
+ {
+ currentItem = historyList.append(item);
+ }
+ else
+ {
+ currentItem = historyList.insert(currentItem, item);
+ }
+ // Delete items starting after currentItem to the end of the list.
+ QValueList<HistoryItem>::iterator deleteItemsStart = currentItem;
+ deleteItemsStart++;
+ historyList.erase(deleteItemsStart, historyList.end());
+
+ if (historyList.size() > HISTORYLENGTH)
+ historyList.pop_front();
+ }
+ emit backItem(currentItem != historyList.begin());
+ emit forwardItem(false);
+}
+
+HistoryItem* History::forward()
+{
+ if (historyList.empty() || currentItem == historyList.fromLast())
+ return 0;
+
+ currentItem++;
+ emit backItem(true);
+ emit forwardItem(currentItem != historyList.fromLast());
+ return &(*currentItem);
+}
+
+HistoryItem* History::back()
+{
+ if (historyList.empty() || currentItem == historyList.begin())
+ return 0;
+
+ currentItem--;
+ emit backItem(currentItem != historyList.begin());
+ emit forwardItem(true);
+ return &(*currentItem);
+}
+
+void History::clear()
+{
+ historyList.clear();
+ currentItem = historyList.begin();
+ emit backItem(false);
+ emit forwardItem(false);
+}
+
+#include "history.moc"
diff --git a/kviewshell/history.h b/kviewshell/history.h
new file mode 100644
index 00000000..2c651475
--- /dev/null
+++ b/kviewshell/history.h
@@ -0,0 +1,58 @@
+// -*- C++ -*-
+#ifndef history_h
+#define history_h
+
+// history.h
+//
+// (C) 2001 Stefan Kebekus
+// Distributed under the GPL
+
+#include <qobject.h>
+#include <qvaluelist.h>
+
+#define HISTORYLENGTH 10
+
+class HistoryItem
+{
+ public:
+ HistoryItem(Q_UINT32, Q_UINT32);
+ HistoryItem() {}
+
+ bool operator== (const HistoryItem& item) const;
+
+ Q_UINT32 page;
+ Q_UINT32 ypos;
+};
+
+inline
+bool operator!=(const HistoryItem& lhs, const HistoryItem& rhs)
+{
+ return !(lhs == rhs);
+}
+
+
+class History : public QObject
+{
+ Q_OBJECT
+
+public:
+ History();
+
+ void add(Q_UINT32 page, Q_UINT32 ypos);
+ void clear();
+
+ HistoryItem* forward();
+ HistoryItem* back();
+
+signals:
+ void backItem(bool);
+ void forwardItem(bool);
+
+private:
+ // List of history items. First item is the oldest.
+ QValueList<HistoryItem> historyList;
+
+ QValueList<HistoryItem>::iterator currentItem;
+};
+
+#endif
diff --git a/kviewshell/hyperlink.h b/kviewshell/hyperlink.h
new file mode 100644
index 00000000..bd07fef5
--- /dev/null
+++ b/kviewshell/hyperlink.h
@@ -0,0 +1,78 @@
+// -*- C++ -*-
+//
+// Class: hyperlink
+//
+// Part of KDVI- A previewer for TeX DVI files.
+//
+// (C) 2004-2005 Stefan Kebekus. Distributed under the GPL.
+
+#ifndef _hyperlink_h_
+#define _hyperlink_h_
+
+#include <qrect.h>
+#include <qstring.h>
+
+
+/** Represents a named, rectangular region in a rendered documentPage
+
+ This trivial class is used in the documentPage class to represent
+ a hyperlink in a rendered documentPage.
+
+ @author Stefan Kebekus <kebekus@kde.org>
+ @version 1.0.0
+*/
+
+class Hyperlink
+{
+public:
+ /** \brief Default Constructor
+
+ The default constructor leaves all fields uninitialized.
+ */
+ Hyperlink() {}
+
+ /** \brief Constructor
+
+ Trivial constructor leaves that initialized all members.
+
+ @param bl value for the baseline field
+ @param re value for the box
+ @param lT valus for the text field
+ */
+ Hyperlink(Q_UINT32 bl, const QRect& re, const QString& lT): baseline(bl), box(re), linkText(lT) {}
+
+ /** \brief Base line of a hyperlink
+
+ This field specifies the Y-coordinate of the base line of the
+ bounding box in the same coordinates that were used when the
+ associated documentPage was rendered by the
+ documentRenderer.drawPage() method. It is used to underline
+ hyperlinks in blue. Note that this field does generally differ from
+ the Y-coordinate of the bottom of the bounding box, e.g. if the text
+ in the box contains characters with underlengths, such as 'y', 'j'
+ or 'g'.
+ */
+ Q_UINT32 baseline;
+
+ /** \brief Bounding box of the text or hyperlink
+
+ This rectangle specifies where on the page the hyperlink is
+ found. It uses the same coordinates that were used when the
+ associated documentPage was rendered by the
+ documentRenderer.drawPage() method. The box is used to determine if
+ the mouse pointer hovers over the link.
+ */
+ QRect box;
+
+ /** \brief Name of the region
+
+ This field contains the name of the target,
+ e.g. "http://www.kde.org". If the Hyperlink class is used to
+ represent text, then the text is stored here.
+ */
+ QString linkText;
+};
+
+
+
+#endif
diff --git a/kviewshell/kmultipage.cpp b/kviewshell/kmultipage.cpp
new file mode 100644
index 00000000..b747ce0f
--- /dev/null
+++ b/kviewshell/kmultipage.cpp
@@ -0,0 +1,1976 @@
+#include <config.h>
+
+#include <kaction.h>
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kfiledialog.h>
+#include <kiconloader.h>
+#include <kio/job.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kprinter.h>
+#include <kstdaction.h>
+#include <qobject.h>
+#include <qlayout.h>
+#include <qpaintdevicemetrics.h>
+#include <qprogressdialog.h>
+#include <qsplitter.h>
+#include <qurl.h>
+#include <qtoolbox.h>
+#include <qvbox.h>
+
+#include "documentWidget.h"
+#include "marklist.h"
+#include "tableOfContents.h"
+#include "kprintDialogPage_pageoptions.h"
+#include "kvsprefs.h"
+#include "kmultipage.h"
+#include "pageNumber.h"
+#include "renderedDocumentPagePrinter.h"
+#include "searchWidget.h"
+#include "textBox.h"
+#include "zoomlimits.h"
+
+
+//#define DEBUG_KMULTIPAGE
+
+KMultiPage::KMultiPage(QWidget *parentWidget, const char *widgetName, QObject *parent, const char *name)
+ : DCOPObject("kmultipage"), KParts::ReadOnlyPart(parent, name)
+{
+ // For reasons which I don't understand, the initialization of the
+ // DCOPObject above does not work properly, the name is ignored. It
+ // works fine if we repeat the name here. -- Stefan Kebekus
+ // This is because of the virtual inheritance. Get rid of it (but it's BC, and this is a lib...) -- DF
+ setObjId("kmultipage");
+
+ parentWdg = parentWidget;
+ lastCurrentPage = 0;
+ timer_id = -1;
+ searchInProgress = false;
+
+ QVBox* verticalBox = new QVBox(parentWidget);
+ verticalBox->setFocusPolicy(QWidget::StrongFocus);
+ setWidget(verticalBox);
+
+ splitterWidget = new QSplitter(verticalBox, widgetName);
+ splitterWidget->setOpaqueResize(false);
+ splitterWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
+
+ // Create SideBar
+ sideBar = new QToolBox(splitterWidget, "sidebar");
+
+ // Create ContentsList
+ tableOfContents = new TableOfContents(sideBar);
+ sideBar->addItem(tableOfContents, QIconSet(SmallIcon("contents")), i18n("Contents"));
+
+ connect(tableOfContents, SIGNAL(gotoPage(const Anchor&)), this, SLOT(gotoPage(const Anchor&)));
+
+ // Create MarkList
+ _markList = new MarkList(sideBar, "marklist");
+ sideBar->addItem(_markList, QIconSet(SmallIcon("thumbnail")), i18n("Thumbnails"));
+
+ // Restore state of the sidebar
+ sideBar->setCurrentItem(sideBar->item(KVSPrefs::sideBarItem()));
+
+ splitterWidget->setResizeMode(sideBar, QSplitter::KeepSize);
+
+ connect(_markList, SIGNAL(selected(const PageNumber&)), this, SLOT(gotoPage(const PageNumber&)));
+
+ _scrollView = new PageView(splitterWidget, widgetName);
+
+ // Create Search Panel
+ searchWidget = new SearchWidget(verticalBox);
+ searchWidget->hide();
+ connect(searchWidget, SIGNAL(findNextText()), this, SLOT(findNextText()));
+ connect(searchWidget, SIGNAL(findPrevText()), this, SLOT(findPrevText()));
+
+ sideBar->setMinimumWidth(80);
+ sideBar->setMaximumWidth(300);
+
+ connect(_scrollView, SIGNAL(currentPageChanged(const PageNumber&)), this, SLOT(setCurrentPageNumber(const PageNumber&)));
+ connect(_scrollView, SIGNAL(viewSizeChanged(const QSize&)), scrollView(), SLOT(calculateCurrentPageNumber()));
+ connect(_scrollView, SIGNAL(wheelEventReceived(QWheelEvent *)), this, SLOT(wheelEvent(QWheelEvent*)));
+
+ connect(this, SIGNAL(enableMoveTool(bool)), _scrollView, SLOT(slotEnableMoveTool(bool)));
+
+ splitterWidget->setCollapsible(sideBar, false);
+ splitterWidget->setSizes(KVSPrefs::guiLayout());
+
+ connect(searchWidget, SIGNAL(searchEnabled(bool)), this, SIGNAL(searchEnabled(bool)));
+ connect(searchWidget, SIGNAL(stopSearch()), this, SLOT(stopSearch()));
+}
+
+
+KMultiPage::~KMultiPage()
+{
+ writeSettings();
+
+ if (timer_id != -1)
+ killTimer(timer_id);
+
+ delete pageCache;
+}
+
+void KMultiPage::readSettings()
+{
+}
+
+void KMultiPage::writeSettings()
+{
+ // Save TOC layout
+ tableOfContents->writeSettings();
+
+ KVSPrefs::setGuiLayout(splitterWidget->sizes());
+ // Save state of the sidebar
+ KVSPrefs::setSideBarItem(sideBar->indexOf(sideBar->currentItem()));
+ KVSPrefs::writeConfig();
+}
+
+QString KMultiPage::name_of_current_file()
+{
+ return m_file;
+}
+
+bool KMultiPage::is_file_loaded(const QString& filename)
+{
+ return (filename == m_file);
+}
+
+void KMultiPage::slotSave_defaultFilename()
+{
+ slotSave();
+}
+
+void KMultiPage::slotSave()
+{
+ // 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 (0, i18n("The file %1\nexists. Shall I overwrite that file?").arg(fileName),
+ i18n("Overwrite File"), i18n("Overwrite"));
+ if (r == KMessageBox::Cancel)
+ return;
+ }
+
+ KIO::Job *job = KIO::file_copy( KURL( m_file ), KURL( fileName ), 0600, true, false, true );
+ connect( job, SIGNAL( result( KIO::Job * ) ), this, SLOT( slotIOJobFinished ( KIO::Job * ) ) );
+
+ return;
+}
+
+
+void KMultiPage::setFile(bool)
+{
+ return;
+}
+
+
+bool KMultiPage::closeURL()
+{
+#ifdef DEBUG_KMULTIPAGE
+ kdDebug(1233) << "KMultiPage::closeURL()" << endl;
+#endif
+
+ if (renderer.isNull())
+ return false;
+
+ // Clear navigation history.
+ document_history.clear();
+
+ // Close the file.
+ renderer->setFile(QString::null, KURL());
+ renderer->clear();
+
+ // Delete Page Widgets.
+ widgetList.setAutoDelete(true);
+ widgetList.resize(0);
+ widgetList.setAutoDelete(false);
+
+ // Update ScrollView.
+ scrollView()->layoutPages();
+ enableActions(false);
+
+ // Clear Thumbnail List.
+ markList()->clear();
+
+ // Clear Table of Contents
+ tableOfContents->clear();
+
+ // Clear Status Bar
+ emit setStatusBarText(QString::null);
+
+ return true;
+}
+
+void KMultiPage::slotIOJobFinished ( KIO::Job *job )
+{
+ if ( job->error() )
+ job->showErrorDialog( 0L );
+}
+
+void KMultiPage::slotShowScrollbars(bool status)
+{
+ _scrollView->slotShowScrollbars(status);
+}
+
+void KMultiPage::slotShowSidebar(bool show)
+{
+ if (show)
+ sideBar->show();
+ else
+ sideBar->hide();
+}
+
+void KMultiPage::slotShowThumbnails(bool show)
+{
+ markList()->slotShowThumbnails(show);
+}
+
+void KMultiPage::slotSetFullPage(bool fullpage)
+{
+ _scrollView->setFullScreenMode(fullpage);
+ if (fullpage)
+ slotShowSidebar(false);
+}
+
+void KMultiPage::preferencesChanged()
+{
+ // We need to read the config options otherwise the KVSPrefs-object would
+ // not be syncronized between the kviewpart and the kmultipage.
+ KVSPrefs::self()->readConfig();
+
+ slotShowThumbnails(KVSPrefs::showThumbnails());
+
+ // if we are in overviewmode and the number of columns or rows has changed
+ if (scrollView()->overviewMode() &&
+ (scrollView()->getNrColumns() != KVSPrefs::overviewModeColumns() ||
+ scrollView()->getNrRows() != KVSPrefs::overviewModeRows()))
+ {
+ setViewMode(KVSPrefs::EnumViewMode::Overview);
+ }
+
+ if (KVSPrefs::changeColors() && KVSPrefs::renderMode() == KVSPrefs::EnumRenderMode::Paper)
+ renderer->setAccessibleBackground(true, KVSPrefs::paperColor());
+ else
+ renderer->setAccessibleBackground(false);
+
+ renderModeChanged();
+}
+
+void KMultiPage::setViewMode(int mode)
+{
+#ifdef DEBUG_KMULTIPAGE
+ kdDebug(1233) << "KMultiPage::setViewMode(" << mode << ")" << endl;
+#endif
+ // Save the current page number because when we are changing the columns
+ // and rows in the scrollview the currently shown Page probably out of view.
+ PageNumber currentPage = currentPageNumber();
+
+ // Save viewMode for future uses of KViewShell
+ switch (mode)
+ {
+ case KVSPrefs::EnumViewMode::SinglePage:
+ KVSPrefs::setViewMode(KVSPrefs::EnumViewMode::SinglePage);
+
+ // Don't do anything if the view mode is already set
+ if ((scrollView()->getNrColumns() == 1) && (scrollView()->getNrRows() == 1) && (scrollView()->isContinuous() == false))
+ return;
+
+ scrollView()->setNrColumns(1);
+ scrollView()->setNrRows(1);
+ scrollView()->setContinuousViewMode(false);
+ // We scroll the view to the top, so that top and not the bottom
+ // of the visible page is shown.
+ scrollView()->scrollTop();
+ break;
+ case KVSPrefs::EnumViewMode::ContinuousFacing:
+ KVSPrefs::setViewMode(KVSPrefs::EnumViewMode::ContinuousFacing);
+
+ // Don't do anything if the view mode is already set
+ if ((scrollView()->getNrColumns() == 2) && (scrollView()->getNrRows() == 1) && (scrollView()->isContinuous() == true))
+ return;
+
+ scrollView()->setNrColumns(2);
+ scrollView()->setNrRows(1);
+ scrollView()->setContinuousViewMode(true);
+ break;
+ case KVSPrefs::EnumViewMode::Overview:
+ KVSPrefs::setViewMode(KVSPrefs::EnumViewMode::Overview);
+
+ // Don't do anything if the view mode is already set
+ if ((scrollView()->getNrColumns() == KVSPrefs::overviewModeColumns()) && (scrollView()->getNrRows() == KVSPrefs::overviewModeRows()) && (scrollView()->isContinuous() == false))
+ return;
+
+ scrollView()->setNrColumns(KVSPrefs::overviewModeColumns());
+ scrollView()->setNrRows(KVSPrefs::overviewModeRows());
+ scrollView()->setContinuousViewMode(false);
+ // We scroll the view to the top, so that top and not the bottom
+ // of the visible tableau is shown.
+ scrollView()->scrollTop();
+ break;
+ default: //KVSPrefs::EnumViewMode::Continuous
+ KVSPrefs::setViewMode(KVSPrefs::EnumViewMode::Continuous);
+
+ // Don't do anything if the view mode is already set
+ if ((scrollView()->getNrColumns() == 1) && (scrollView()->getNrRows() == 1) && (scrollView()->isContinuous() == true))
+ return;
+
+ scrollView()->setNrColumns(1);
+ scrollView()->setNrRows(1);
+ scrollView()->setContinuousViewMode(true);
+ }
+ generateDocumentWidgets(currentPage);
+ KVSPrefs::writeConfig();
+ emit viewModeChanged();
+}
+
+void KMultiPage::initializePageCache()
+{
+ pageCache = new DocumentPageCache();
+}
+
+DocumentWidget* KMultiPage::createDocumentWidget()
+{
+ DocumentWidget* documentWidget = new DocumentWidget(scrollView()->viewport(), scrollView(), pageCache, "singlePageWidget");
+ connect(documentWidget, SIGNAL(clearSelection()), this, SLOT(clearSelection()));
+ connect(this, SIGNAL(enableMoveTool(bool)), documentWidget, SLOT(slotEnableMoveTool(bool)));
+ return documentWidget;
+}
+
+
+void KMultiPage::generateDocumentWidgets(const PageNumber& _startPage)
+{
+ PageNumber startPage = _startPage;
+#ifdef DEBUG_KMULTIPAGE
+ kdDebug(1233) << "KMultiPage::generateDocumentWidgets(" << startPage << ")" << endl;
+#endif
+
+ // Do nothing if no document is loaded.
+ if (getRenderer().isNull() || getRenderer()->isEmpty())
+ return;
+
+ // This function is only called with an invalid pagenumber, when
+ // the file has been loaded or reloaded.
+ bool reload = !startPage.isValid();
+
+ if (reload)
+ {
+ // Find the number of the current page, for later use.
+ startPage = currentPageNumber();
+ }
+
+ // Make sure that startPage is in the permissible range.
+ if (startPage < 1)
+ startPage = 1;
+ if (startPage > numberOfPages())
+ startPage = numberOfPages();
+
+ unsigned int tableauStartPage = startPage;
+
+ // Find out how many widgets are needed, and resize the widgetList accordingly.
+ widgetList.setAutoDelete(true);
+ Q_UINT16 oldwidgetListSize = widgetList.size();
+ if (numberOfPages() == 0)
+ widgetList.resize(0);
+ else
+ {
+ switch (KVSPrefs::viewMode())
+ {
+ case KVSPrefs::EnumViewMode::SinglePage:
+ widgetList.resize(1);
+ break;
+ case KVSPrefs::EnumViewMode::Overview:
+ {
+ // Calculate the number of pages shown in overview mode.
+ unsigned int visiblePages = KVSPrefs::overviewModeColumns() * KVSPrefs::overviewModeRows();
+ // Calculate the number of the first page in the tableau.
+ tableauStartPage = startPage - ((startPage - 1) % visiblePages);
+ // We cannot have more widgets then pages in the document.
+ visiblePages = QMIN(visiblePages, numberOfPages() - tableauStartPage + 1);
+ if (widgetList.size() != visiblePages)
+ widgetList.resize(visiblePages);
+ break;
+ }
+ default:
+ // In KVS_Continuous and KVS_ContinuousFacing all pages in the document are shown.
+ widgetList.resize(numberOfPages());
+ }
+ }
+ bool isWidgetListResized = (widgetList.size() != oldwidgetListSize);
+ widgetList.setAutoDelete(false);
+
+ // If the widgetList is empty, there is nothing left to do.
+ if (widgetList.size() == 0) {
+ scrollView()->addChild(&widgetList);
+ return;
+ }
+
+ // Allocate DocumentWidget structures so that all entries of
+ // widgetList point to a valid DocumentWidget.
+ DocumentWidget *documentWidget;
+ for(Q_UINT16 i=0; i<widgetList.size(); i++) {
+ documentWidget = widgetList[i];
+ if (documentWidget == 0) {
+ documentWidget = createDocumentWidget();
+
+ widgetList.insert(i, documentWidget);
+ documentWidget->show();
+
+ connect(documentWidget, SIGNAL(localLink(const QString &)), this, SLOT(handleLocalLink(const QString &)));
+ connect(documentWidget, SIGNAL(setStatusBarText(const QString&)), this, SIGNAL(setStatusBarText(const QString&)) );
+ }
+ }
+
+ // Set the page numbers for the newly allocated widgets. How this is
+ // done depends on the viewMode.
+ if (KVSPrefs::viewMode() == KVSPrefs::EnumViewMode::SinglePage) {
+ // In KVS_SinglePage mode, any number between 1 and the maximum
+ // number of pages is acceptable. If an acceptable value is found,
+ // nothing is done, and otherwise '1' is set as a default.
+ documentWidget = widgetList[0];
+ if (documentWidget != 0) { // Paranoia safety check
+ documentWidget->setPageNumber(startPage);
+ documentWidget->update();
+ } else
+ kdError(4300) << "Zero-Pointer in widgetList in KMultiPage::generateDocumentWidgets()" << endl;
+ } else {
+ // In all other modes, the widgets will be numbered continuously,
+ // starting from firstShownPage.
+ for(Q_UINT16 i=0; i<widgetList.size(); i++) {
+ documentWidget = widgetList[i];
+ if (documentWidget != 0) // Paranoia safety check
+ {
+ if (KVSPrefs::viewMode() == KVSPrefs::EnumViewMode::Overview)
+ documentWidget->setPageNumber(i+tableauStartPage);
+ else
+ documentWidget->setPageNumber(i+1);
+ }
+ else
+ kdError(4300) << "Zero-Pointer in widgetList in KMultiPage::generateDocumentWidgets()" << endl;
+ }
+ }
+
+ // Make the changes in the widgetList known to the scrollview. so
+ // that the scrollview may update its contents.
+ scrollView()->addChild(&widgetList);
+
+ // If the number of widgets has changed, or the viewmode has been changed the widget
+ // that displays the current page may not be visible anymore. Bring it back into focus.
+ if (isWidgetListResized || !reload)
+ gotoPage(startPage);
+}
+
+
+bool KMultiPage::gotoPage(const PageNumber& page)
+{
+ return gotoPage(page, 0, true);
+}
+
+
+bool KMultiPage::gotoPage(const PageNumber& page, int y, bool isLink)
+{
+#ifdef DEBUG_KMULTIPAGE
+ kdDebug(1233) << "KMultiPage::gotoPage()" << endl;
+#endif
+
+ if (widgetList.size() == 0) {
+ kdError(4300) << "KMultiPage::gotoPage(" << page << ", y) called, but widgetList is empty" << endl;
+ return false;
+ }
+
+ if (!page.isValid())
+ {
+ kdDebug(1223) << "KMultiPage::gotoPage(" << page << ") invalid pageNumber." << endl;
+ return false;
+ }
+
+ if (isLink)
+ document_history.add(page, y);
+
+ DocumentWidget* pageWidget;
+
+ // If we are in overview viewmode
+ if (KVSPrefs::viewMode() == KVSPrefs::EnumViewMode::Overview)
+ {
+ unsigned int visiblePages = KVSPrefs::overviewModeColumns() * KVSPrefs::overviewModeRows();
+ // Pagenumber of the first visibile Page in the current tableau
+ unsigned int firstPage = ((DocumentWidget*)widgetList[0])->getPageNumber();
+ // Pagenumber of the first page in the new tableau.
+ unsigned int tableauStartPage = page + 1 - (page % visiblePages);
+ // If these numbers arn't equal "page" is not in the current tableu.
+ if (firstPage != tableauStartPage) // widgets need to be updated
+ {
+ if ((numberOfPages() - tableauStartPage + 1 < visiblePages) || (widgetList.size() < visiblePages))
+ {
+ // resize widgetList
+ // the pages are also set correctly by "generateDocumentWidgets"
+ generateDocumentWidgets(tableauStartPage);
+ }
+ else
+ {
+ // "page" is not shown in the scrollview, so we have to switch widgets.
+ // Here we don't need to resize the widgetList.
+ for (unsigned int i = 0; i < widgetList.size(); i++)
+ {
+ pageWidget = (DocumentWidget*)(widgetList[i]);
+ if (pageWidget != 0)
+ pageWidget->setPageNumber(tableauStartPage + i);
+ }
+ scrollView()->layoutPages();
+ }
+ }
+ // move scrollview to "page".
+ // Make the widget pageWidget visible in the scrollview. Somehow this
+ // doesn't seem to trigger the signal contentsMoved in the
+ // QScrollview, so that we better call setCurrentPage() ourselves.
+ pageWidget = (DocumentWidget*)(widgetList[page % visiblePages]);
+
+ scrollView()->moveViewportToWidget(pageWidget, y);
+
+ // Set current page number.
+ setCurrentPageNumber(page);
+
+ return true;
+ }
+ else if (widgetList.size() == 1)
+ {
+ // If the widget list contains only a single element, then either
+ // the document contains only one page, or we are in "single page"
+ // view mode. In either case, we set the page number of the single
+ // widget to 'page'
+ pageWidget = (DocumentWidget*)(widgetList[0]);
+
+ // Paranoia security check
+ if (pageWidget == 0) {
+ kdError(4300) << "KMultiPage::goto_Page() called with widgetList.size() == 1, but widgetList[0] == 0" << endl;
+ return false;
+ }
+
+ if (pageCache->sizeOfPageInPixel(currentPageNumber()) == pageCache->sizeOfPageInPixel(page))
+ {
+ // We are rendering the page before we switch the widget to the new page.
+ // To make a smooth transition. We only do this if the size of the current and new page are equal,
+ // otherwise we would have to render the page twice, if autozoom is enabled.
+ pageCache->getPage(page);
+ }
+
+ pageWidget->setPageNumber(page);
+ scrollView()->layoutPages();
+ scrollView()->moveViewportToWidget(pageWidget, y);
+ } else {
+ // There are multiple widgets, then we are either in the
+ // "Continuous" or in the "Continouous-Facing" view mode. In that
+ // case, we find the widget which is supposed to display page
+ // 'page' and move the scrollview to make it visible
+
+ // Paranoia security checks
+ if (widgetList.size() < page) {
+ kdError(4300) << "KMultiPage::goto_Page(page,y ) called with widgetList.size()=" << widgetList.size() << ", and page=" << page << endl;
+ return false;
+ }
+ pageWidget = (DocumentWidget*)(widgetList[page-1]);
+ if (pageWidget == 0) {
+ kdError(4300) << "KMultiPage::goto_Page() called with widgetList.size() > 1, but widgetList[page] == 0" << endl;
+ return false;
+ }
+
+ scrollView()->moveViewportToWidget(pageWidget, y);
+ }
+
+ if (isLink && y != 0)
+ pageWidget->flash(y);
+
+ // Set current page number.
+ setCurrentPageNumber(page);
+ return true;
+}
+
+
+void KMultiPage::handleLocalLink(const QString &linkText)
+{
+#ifdef DEBUG_SPECIAL
+ kdDebug(4300) << "hit: local link to " << linkText << endl;
+#endif
+
+ if (renderer.isNull()) {
+ kdError(4300) << "KMultiPage::handleLocalLink( " << linkText << " ) called, but renderer==0" << endl;
+ return;
+ }
+
+ QString locallink;
+ if (linkText[0] == '#' )
+ locallink = linkText.mid(1); // Drop the '#' at the beginning
+ else
+ locallink = linkText;
+
+ Anchor anch = renderer->findAnchor(locallink);
+
+ if (anch.isValid())
+ gotoPage(anch);
+ else {
+ if (linkText[0] != '#' ) {
+ // We could in principle use KIO::Netaccess::run() here, but
+ // it is perhaps not a very good idea to allow a DVI-file to
+ // specify arbitrary commands, such as "rm -rvf /". Using
+ // the kfmclient seems to be MUCH safer.
+ QUrl DVI_Url(m_file);
+ QUrl Link_Url(DVI_Url, linkText, true);
+
+ QStringList args;
+ args << "openURL";
+ args << Link_Url.toString();
+ kapp->kdeinitExec("kfmclient", args);
+ }
+ }
+}
+
+void KMultiPage::setCurrentPageNumber(const PageNumber& page)
+{
+#ifdef DEBUG_KMULTIPAGE
+ kdDebug(1233) << "KMultiPage::setCurrentPageNumber()" << endl;
+#endif
+
+ if (page != currentPageNumber())
+ {
+ markList()->setCurrentPageNumber(page);
+ emit pageInfo(numberOfPages(), currentPageNumber());
+ }
+}
+
+PageNumber KMultiPage::currentPageNumber()
+{
+ return markList()->currentPageNumber();
+}
+
+void KMultiPage::doGoBack()
+{
+ HistoryItem *it = document_history.back();
+ if (it != 0)
+ gotoPage(it->page, it->ypos, false); // Do not add a history item.
+ else
+ kdDebug(4300) << "Faulty return -- bad history buffer" << endl;
+ return;
+}
+
+
+void KMultiPage::doGoForward()
+{
+ HistoryItem *it = document_history.forward();
+ if (it != 0)
+ gotoPage(it->page, it->ypos, false); // Do not add a history item.
+ else
+ kdDebug(4300) << "Faulty return -- bad history buffer" << endl;
+ return;
+}
+
+
+void KMultiPage::renderModeChanged()
+{
+ pageCache->clear();
+
+ generateDocumentWidgets();
+ scrollView()->layoutPages();
+
+ for (Q_UINT16 i=0; i < widgetList.size(); i++)
+ {
+ DocumentWidget* documentWidget = widgetList[i];
+ if (documentWidget == 0)
+ continue;
+
+ documentWidget->update();
+ }
+
+ markList()->repaintThumbnails();
+}
+
+
+void KMultiPage::repaintAllVisibleWidgets()
+{
+#ifdef DEBUG_KMULTIPAGE
+ kdDebug(1233) << "KMultiPage::repaintAllVisibleWidgets()" << endl;
+#endif
+
+ bool everResized = false;
+
+ // Go through the list of widgets and resize them, if necessary
+ for(Q_UINT16 i=0; i<widgetList.size(); i++)
+ {
+ DocumentWidget* documentWidget = widgetList[i];
+ if (documentWidget == 0)
+ continue;
+
+ // Resize, if necessary
+ QSize pageSize = pageCache->sizeOfPageInPixel(documentWidget->getPageNumber());
+ if (pageSize != documentWidget->pageSize())
+ {
+ documentWidget->setPageSize(pageSize);
+ everResized = true;
+ }
+ }
+
+ // If at least one widget was resized, all widgets should be
+ // re-aligned. This will automatically update all necessary
+ // widgets.
+ if (everResized == true)
+ scrollView()->layoutPages(true);
+}
+
+
+double KMultiPage::setZoom(double zoom)
+{
+#ifdef DEBUG_KMULTIPAGE
+ kdDebug(1233) << "KMultiPage::setZoom(" << zoom << ")" << endl;
+#endif
+
+ if (zoom < ZoomLimits::MinZoom/1000.0)
+ zoom = ZoomLimits::MinZoom/1000.0;
+ if (zoom > ZoomLimits::MaxZoom/1000.0)
+ zoom = ZoomLimits::MaxZoom/1000.0;
+
+ pageCache->setResolution(QPaintDevice::x11AppDpiX()*zoom);
+ emit zoomChanged();
+ return zoom;
+}
+
+
+void KMultiPage::print()
+{
+ // Paranoid safety checks
+ if (renderer.isNull())
+ return;
+ if (renderer->isEmpty())
+ return;
+
+ // Allocate the printer structure
+ KPrinter *printer = getPrinter();
+ if (printer == 0)
+ return;
+
+ // initialize the printer using the print dialog
+ if ( printer->setup(parentWdg, i18n("Print %1").arg(m_file.section('/', -1))) ) {
+ // Now do the printing.
+ QValueList<int> pageList = printer->pageList();
+ if (pageList.isEmpty())
+ printer->abort();
+ else {
+ printer->setCreator("kviewshell");
+ printer->setDocName(m_file);
+ RenderedDocumentPagePrinter rdpp(printer);
+
+ // Obtain papersize information that is required to perform
+ // the resizing and centering, if this is wanted by the user.
+ Length paperWidth, paperHeight;
+ QPaintDeviceMetrics pdm(printer);
+ paperWidth.setLength_in_mm(pdm.widthMM());
+ paperHeight.setLength_in_mm(pdm.heightMM());
+
+ QValueList<int>::ConstIterator it = pageList.begin();
+ while (true) {
+ SimplePageSize paper_s(paperWidth, paperHeight);
+
+ // Printing usually takes a while. This is to keep the GUI
+ // updated.
+ qApp->processEvents();
+
+ QPainter *paint = rdpp.getPainter();
+ if (paint != 0) {
+ // Before drawing the page, we figure out the zoom-value,
+ // taking the "page sizes and placement" options from the
+ // printer dialog into account
+ double factual_zoom = 1.0;
+
+ // Obtain pagesize information that is required to perform the
+ // resizing and centering, if this is wanted by the user.
+ SimplePageSize page_s = sizeOfPage(*it);
+
+ paint->save();
+
+ // Rotate the page, if appropriate. By default, page
+ // rotation is enabled. This is also hardcoded into
+ // KPrintDialogPage_PageOptions.cpp
+ if ((page_s.isPortrait() != paper_s.isPortrait()) && (printer->option( "kde-kviewshell-rotatepage" ) != "false")) {
+ paint->rotate(-90);
+ paint->translate(-printer->resolution()*paperHeight.getLength_in_inch(), 0.0);
+ paper_s = paper_s.rotate90();
+ }
+
+ double suggested_zoom = page_s.zoomToFitInto(paper_s);
+
+ // By default, "shrink page" and "expand page" are off. This
+ // is also hardcoded into KPrintDialogPage_PageOptions.cpp
+ if ((suggested_zoom < 1.0) && (printer->option( "kde-kviewshell-shrinkpage" ) == "true"))
+ factual_zoom = suggested_zoom;
+ if ((suggested_zoom > 1.0) && (printer->option( "kde-kviewshell-expandpage" ) == "true"))
+ factual_zoom = suggested_zoom;
+
+ Length delX, delY;
+ // By default, "center page" is on. This is also hardcoded
+ // into KPrintDialogPage_PageOptions.cpp
+ if (printer->option( "kde-kviewshell-centerpage" ) != "false") {
+ delX = (paper_s.width() - page_s.width()*factual_zoom)/2.0;
+ delY = (paper_s.height() - page_s.height()*factual_zoom)/2.0;
+ }
+
+ // Now draw the page.
+ rdpp.setPageNumber(*it);
+
+ double resolution = factual_zoom*printer->resolution();
+
+ paint->translate(resolution*delX.getLength_in_inch(), resolution*delY.getLength_in_inch());
+ renderer->drawPage(resolution, &rdpp);
+ paint->restore();
+ }
+ ++it;
+ if ((it == pageList.end()) || (printer->aborted() == true))
+ break;
+
+ printer->newPage();
+ }
+ // At this point the rdpp is destructed. The last page is then
+ // printed.
+ }
+ }
+ delete printer;
+}
+
+
+void KMultiPage::setRenderer(DocumentRenderer* _renderer)
+{
+ renderer = _renderer;
+
+ // Initialize documentPageCache.
+ initializePageCache();
+ pageCache->setRenderer(renderer);
+
+ _markList->setPageCache(pageCache);
+
+ // Clear widget list.
+ widgetList.resize(0);
+
+ // Relay signals.
+ connect(renderer, SIGNAL(setStatusBarText(const QString&)), this, SIGNAL(setStatusBarText(const QString&)));
+ connect(pageCache, SIGNAL(paperSizeChanged()), this, SLOT(renderModeChanged()));
+ connect(pageCache, SIGNAL(textSelected(bool)), this, SIGNAL(textSelected(bool)));
+ connect(renderer, SIGNAL(documentIsChanged()), this, SLOT(renderModeChanged()));
+ connect(this, SIGNAL(zoomChanged()), this, SLOT(repaintAllVisibleWidgets()));
+}
+
+
+void KMultiPage::updateWidgetSize(const PageNumber& pageNumber)
+{
+ for(Q_UINT16 i=0; i<widgetList.size(); i++)
+ {
+ DocumentWidget* documentWidget = widgetList[i];
+ if (documentWidget == 0)
+ continue;
+
+ if (documentWidget->getPageNumber() == pageNumber)
+ {
+ // Resize, if necessary
+ QSize pageSize = pageCache->sizeOfPageInPixel(documentWidget->getPageNumber());
+ if (pageSize != documentWidget->pageSize())
+ {
+ documentWidget->setPageSize(pageSize);
+ scrollView()->layoutPages();
+ }
+ // We have just one widget per page.
+ break;
+ }
+ }
+
+ // Update marklist
+ markList()->updateWidgetSize(pageNumber);
+}
+
+
+PageNumber KMultiPage::widestPage() const
+{
+ Length maxWidth;
+ PageNumber pageNumber = 1;
+
+ for (int i = 1; i <= numberOfPages(); i++)
+ {
+ Length width = pageCache->sizeOfPage(i).width();
+
+ if (width > maxWidth)
+ {
+ maxWidth = width;
+ pageNumber = i;
+ }
+ }
+
+ return pageNumber;
+}
+
+double KMultiPage::zoomForWidthColumns(unsigned int viewportWidth) const
+{
+ Length maxLeftColumnWidth;
+ Length maxRightColumnWidth;
+ Length maxWidth;
+
+ PageNumber widestPageLeft;
+ PageNumber widestPageRight;
+
+ for (int i = 1; i <= numberOfPages(); i++)
+ {
+ Length width = pageCache->sizeOfPage(i).width();
+
+ if ( i % 2 == 0) // page is in left column
+ {
+ if (width > maxLeftColumnWidth)
+ {
+ maxLeftColumnWidth = width;
+ widestPageLeft = i;
+ }
+ }
+
+ if ( i % 2 == 1) // page is in right column
+ {
+ if (width > maxRightColumnWidth)
+ maxRightColumnWidth = width;
+ widestPageRight = i;
+ }
+ }
+
+ double ratio = maxLeftColumnWidth / (maxLeftColumnWidth + maxRightColumnWidth);
+
+ // This number is the amount of space the left column should occupy in the viewport.
+ unsigned int leftTargetWidth = (unsigned int)(ratio * viewportWidth);
+
+ return pageCache->sizeOfPage(widestPageLeft).zoomForWidth(leftTargetWidth);
+}
+
+double KMultiPage::calculateFitToHeightZoomValue()
+{
+ PageNumber pageNumber = 1;
+
+ // See below, in the documentation of the method "calculatefitToWidthZoomLevel"
+ // for an explanation of the complicated calculation we are doing here.
+ int columns = scrollView()->getNrColumns();
+ int rows = scrollView()->getNrRows();
+ int continuousViewmode = scrollView()->isContinuous();
+ bool fullScreenMode = scrollView()->fullScreenMode();
+
+ if (columns == 1 && rows == 1 && !continuousViewmode) // single page mode
+ {
+ pageNumber = currentPageNumber();
+ if (!pageNumber.isValid())
+ pageNumber = 1;
+ }
+
+ int pageDistance = scrollView()->distanceBetweenPages();
+ if (columns == 1 && rows == 1 && !continuousViewmode && fullScreenMode)
+ {
+ // In Single Page Fullscreen Mode we want to fit the page to the
+ // window without a margin around it.
+ pageDistance = 0;
+ }
+
+ int targetViewportHeight = scrollView()->viewportSize(0,0).height();
+ int targetPageHeight = (targetViewportHeight - rows*pageDistance)/rows;
+ int targetPageWidth = (int)(targetPageHeight * pageCache->sizeOfPage(pageNumber).aspectRatio() );
+ int targetViewportWidth = targetPageWidth * columns + (columns+1)*pageDistance;
+ targetViewportHeight = scrollView()->viewportSize(targetViewportWidth, targetViewportHeight).height();
+ targetPageHeight = (targetViewportHeight - rows*pageDistance)/rows;
+
+ return pageCache->sizeOfPage(pageNumber).zoomForHeight(targetPageHeight);
+}
+
+
+double KMultiPage::calculateFitToWidthZoomValue()
+{
+ PageNumber pageNumber = 1;
+
+ int columns = scrollView()->getNrColumns();
+ int rows = scrollView()->getNrRows();
+ int continuousViewmode = scrollView()->isContinuous();
+ bool fullScreenMode = scrollView()->fullScreenMode();
+
+ if (columns == 1 && rows == 1 && !continuousViewmode) // single page mode
+ {
+ // To calculate the zoom level in single page mode we need the size
+ // of the current page. When a new document is opened this function
+ // is called while the currentPageNumber is invalid. We use the size
+ // of the first page of the document in this case.
+ pageNumber = currentPageNumber();
+ if (!pageNumber.isValid())
+ pageNumber = 1;
+ }
+
+ if (columns == 1 && rows == 1 && continuousViewmode) // continuous viewmode
+ {
+ pageNumber = widestPage();
+ if (!pageNumber.isValid())
+ pageNumber = 1;
+ }
+
+ // rows should be 1 for Single Page Viewmode,
+ // the number of Pages in Continuous Viewmode
+ // and number of Pages/2 in Continuous-Facing Viewmode
+ if (continuousViewmode)
+ rows = (int)(ceil(numberOfPages() / (double)columns));
+
+ int pageDistance = scrollView()->distanceBetweenPages();
+ if (columns == 1 && rows == 1 && !continuousViewmode && fullScreenMode)
+ {
+ // In Single Page Fullscreen Mode we want to fit the page to the
+ // window without a margin around it.
+ pageDistance = 0;
+ }
+ // There is a slight complication here... if we just take the width
+ // of the viewport and scale the contents by a factor x so that it
+ // fits the viewport exactly, then, depending on chosen papersize
+ // (landscape, etc.), the contents may be higher than the viewport
+ // and the QScrollview may or may not insert a scrollbar at the
+ // right. If the scrollbar appears, then the usable width of the
+ // viewport becomes smaller, and scaling by x does not really fit
+ // the (now smaller page) anymore.
+
+ // Calculate the width and height of the view, disregarding the
+ // possible complications with scrollbars, e.g. assuming the maximal
+ // space is available.
+
+ // width of the widget excluding possible scrollbars
+ int targetViewportWidth = scrollView()->viewportSize(0,0).width();
+
+ // maximal width of a single page
+ int targetPageWidth = (targetViewportWidth - (columns+1) * pageDistance) / columns;
+
+ // maximal height of a single page
+ int targetPageHeight = (int)(targetPageWidth/pageCache->sizeOfPage(pageNumber).aspectRatio());
+ // FIXME: this is only correct if all pages in the document have the same height
+ int targetViewportHeight = rows * targetPageHeight + (rows+1) * pageDistance;
+
+ // Think again, this time use only the area which is really
+ // acessible (which, in case that targetWidth targetHeight don't fit
+ // the viewport, is really smaller because of the scrollbars).
+ targetViewportWidth = scrollView()->viewportSize(targetViewportWidth, targetViewportHeight).width();
+
+ if (columns == 2 && continuousViewmode) // continuous facing
+ {
+ // TODO Generalize this for more than 2 columns
+ return zoomForWidthColumns(targetViewportWidth - (columns+1) * pageDistance);
+ }
+
+ // maximal width of a single page (now the scrollbars are taken into account)
+ targetPageWidth = (targetViewportWidth - (columns+1) * pageDistance) / columns;
+
+ return pageCache->sizeOfPage(pageNumber).zoomForWidth(targetPageWidth);
+}
+
+
+void KMultiPage::prevPage()
+{
+ Q_UINT8 cols = scrollView()->getNrColumns();
+ Q_UINT8 rows = scrollView()->getNrRows();
+
+ PageNumber np = 1;
+ if (cols*rows < currentPageNumber())
+ {
+ np = currentPageNumber() - cols*rows;
+ }
+
+ gotoPage(np);
+}
+
+
+void KMultiPage::nextPage()
+{
+ Q_UINT8 cols = scrollView()->getNrColumns();
+ Q_UINT8 rows = scrollView()->getNrRows();
+
+ PageNumber np = QMIN(currentPageNumber() + cols*rows, (Q_UINT16)numberOfPages());
+
+ gotoPage(np);
+}
+
+
+void KMultiPage::firstPage()
+{
+ gotoPage(1);
+}
+
+
+void KMultiPage::lastPage()
+{
+ gotoPage(numberOfPages());
+}
+
+
+void KMultiPage::scroll(Q_INT32 deltaInPixel)
+{
+ QScrollBar* scrollBar = scrollView()->verticalScrollBar();
+ if (scrollBar == 0) {
+ kdError(4300) << "KMultiPage::scroll called without scrollBar" << endl;
+ return;
+ }
+
+ if (deltaInPixel < 0) {
+ if (scrollBar->value() == scrollBar->minValue()) {
+ if ( (currentPageNumber() == 1) || (changePageDelayTimer.isActive()) )
+ return;
+
+ if (scrollView()->isContinuous())
+ return;
+
+ changePageDelayTimer.stop();
+ prevPage();
+
+ scrollView()->setContentsPos(scrollView()->contentsX(), scrollBar->maxValue());
+ return;
+ }
+ }
+
+ if (deltaInPixel > 0) {
+ if (scrollBar->value() == scrollBar->maxValue()) {
+ if ( (currentPageNumber() == numberOfPages()) || (changePageDelayTimer.isActive()) )
+ return;
+
+ if (scrollView()->isContinuous())
+ return;
+
+ changePageDelayTimer.stop();
+ nextPage();
+
+ scrollView()->setContentsPos(scrollView()->contentsX(), 0);
+ return;
+ }
+ }
+
+ scrollBar->setValue(scrollBar->value() + deltaInPixel);
+
+ if ( (scrollBar->value() == scrollBar->maxValue()) || (scrollBar->value() == scrollBar->minValue()) )
+ changePageDelayTimer.start(200,true);
+ else
+ changePageDelayTimer.stop();
+}
+
+
+void KMultiPage::scrollUp()
+{
+ QScrollBar* scrollBar = scrollView()->verticalScrollBar();
+ if (scrollBar == 0)
+ return;
+
+ scroll(-scrollBar->lineStep());
+}
+
+
+void KMultiPage::scrollDown()
+{
+ QScrollBar* scrollBar = scrollView()->verticalScrollBar();
+ if (scrollBar == 0)
+ return;
+
+ scroll(scrollBar->lineStep());
+}
+
+void KMultiPage::scrollLeft()
+{
+ QScrollBar* scrollBar = scrollView()->horizontalScrollBar();
+ if (scrollBar)
+ scrollBar->subtractLine();
+}
+
+
+void KMultiPage::scrollRight()
+{
+ QScrollBar* scrollBar = scrollView()->horizontalScrollBar();
+ if (scrollBar)
+ scrollBar->addLine();
+}
+
+
+void KMultiPage::scrollUpPage()
+{
+ QScrollBar* scrollBar = scrollView()->verticalScrollBar();
+ if (scrollBar)
+ scrollBar->subtractPage();
+}
+
+
+void KMultiPage::scrollDownPage()
+{
+ QScrollBar* scrollBar = scrollView()->verticalScrollBar();
+ if (scrollBar)
+ scrollBar->addPage();
+}
+
+
+void KMultiPage::scrollLeftPage()
+{
+ QScrollBar* scrollBar = scrollView()->horizontalScrollBar();
+ if (scrollBar)
+ scrollBar->subtractPage();
+}
+
+
+void KMultiPage::scrollRightPage()
+{
+ QScrollBar* scrollBar = scrollView()->horizontalScrollBar();
+ if (scrollBar)
+ scrollBar->addPage();
+}
+
+
+void KMultiPage::readDown()
+{
+ PageView* sv = scrollView();
+
+ if (sv->atBottom())
+ {
+ if (sv->isContinuous())
+ return;
+
+ if (currentPageNumber() == numberOfPages())
+ return;
+
+ nextPage();
+ sv->setContentsPos(sv->contentsX(), 0);
+ }
+ else
+ sv->readDown();
+}
+
+
+void KMultiPage::readUp()
+{
+ PageView* sv = scrollView();
+
+ if (sv->atTop())
+ {
+ if (sv->isContinuous())
+ return;
+
+ if (currentPageNumber() == 1)
+ return;
+
+ prevPage();
+ sv->setContentsPos(sv->contentsX(), sv->contentsHeight());
+ }
+ else
+ sv->readUp();
+}
+
+
+void KMultiPage::jumpToReference(const QString& reference)
+{
+ if (renderer.isNull())
+ return;
+
+ gotoPage(renderer->parseReference(reference));
+}
+
+
+void KMultiPage::gotoPage(const Anchor &a)
+{
+ if (!a.page.isValid() || (renderer.isNull()))
+ return;
+
+ gotoPage(a.page, (int)(a.distance_from_top.getLength_in_inch()*pageCache->getResolution() + 0.5), true);
+}
+
+
+void KMultiPage::gotoPage(const TextSelection& selection)
+{
+ if (selection.isEmpty())
+ {
+ kdError(4300) << "KMultiPage::gotoPage(...) called with empty TextSelection." << endl;
+ return;
+ }
+
+ RenderedDocumentPage* pageData = pageCache->getPage(selection.getPageNumber());
+
+ if (pageData == 0) {
+#ifdef DEBUG_DOCUMENTWIDGET
+ kdDebug(4300) << "DocumentWidget::paintEvent: no documentPage generated" << endl;
+#endif
+ return;
+ }
+
+ switch (widgetList.size())
+ {
+ case 0:
+ kdError(4300) << "KMultiPage::select() while widgetList is empty" << endl;
+ break;
+ case 1:
+ ((DocumentWidget*)widgetList[0])->select(selection);
+ break;
+ default:
+ if (widgetList.size() < currentPageNumber())
+ kdError(4300) << "KMultiPage::select() while widgetList.size()=" << widgetList.size() << "and currentPageNumber()=" << currentPageNumber() << endl;
+ else
+ ((DocumentWidget*)widgetList[selection.getPageNumber() - 1])->select(selection);
+ }
+
+ unsigned int y = pageData->textBoxList[selection.getSelectedTextStart()].box.top();
+ gotoPage(selection.getPageNumber(), y, false);
+}
+
+
+void KMultiPage::doSelectAll()
+{
+ switch( widgetList.size() ) {
+ case 0:
+ kdError(4300) << "KMultiPage::doSelectAll() while widgetList is empty" << endl;
+ break;
+ case 1:
+ ((DocumentWidget *)widgetList[0])->selectAll();
+ break;
+ default:
+ if (widgetList.size() < currentPageNumber())
+ kdError(4300) << "KMultiPage::doSelectAll() while widgetList.size()=" << widgetList.size() << "and currentPageNumber()=" << currentPageNumber() << endl;
+ else
+ ((DocumentWidget *)widgetList[currentPageNumber()-1])->selectAll();
+ }
+}
+
+
+
+void KMultiPage::showFindTextDialog()
+{
+ if ((renderer.isNull()) || (renderer->supportsTextSearch() == false))
+ return;
+
+ searchWidget->show();
+ searchWidget->setFocus();
+}
+
+void KMultiPage::stopSearch()
+{
+ if (searchInProgress)
+ {
+ // stop the search
+ searchInProgress = false;
+ }
+ else
+ searchWidget->hide();
+}
+
+void KMultiPage::findNextText()
+{
+#ifdef KDVI_MULTIPAGE_DEBUG
+ kdDebug(4300) << "KMultiPage::findNextText() called" << endl;
+#endif
+
+ searchInProgress = true;
+
+ // Used to remember if the documentPage we use is from the cache.
+ // If not we need to delete it manually to avoid a memory leak.
+ bool cachedPage = false;
+
+ QString searchText = searchWidget->getText();
+
+ if (searchText.isEmpty())
+ {
+ kdError(4300) << "KMultiPage::findNextText() called when search text was empty" << endl;
+ return;
+ }
+
+ bool case_sensitive = searchWidget->caseSensitive();
+
+ // Find the page and text position on the page where the search will
+ // start. If nothing is selected, we start at the beginning of the
+ // current page. Otherwise, start after the selected text. TODO:
+ // Optimize this to get a better 'user feeling'
+ Q_UINT16 startingPage;
+ Q_UINT16 startingTextItem;
+
+ TextSelection userSelection = pageCache->selectedText();
+ if (userSelection.isEmpty())
+ {
+ startingPage = currentPageNumber();
+ startingTextItem = 0;
+ }
+ else
+ {
+ startingPage = userSelection.getPageNumber();
+ startingTextItem = userSelection.getSelectedTextEnd()+1;
+ }
+
+ TextSelection foundSelection;
+
+ RenderedDocumentPagePixmap* searchPage = 0;
+
+ for(unsigned int i = 0; i < numberOfPages(); i++)
+ {
+ unsigned int pageNumber = (i + startingPage - 1) % numberOfPages() + 1;
+
+ if (!searchInProgress)
+ {
+ // Interrupt the search
+ setStatusBarText(i18n("Search interrupted"));
+ if (!cachedPage)
+ delete searchPage;
+ return;
+ }
+
+ if (i != 0)
+ {
+ setStatusBarText(i18n("Search page %1 of %2").arg(pageNumber).arg(numberOfPages()));
+ kapp->processEvents();
+ }
+
+ // Check if we already have a rendered version of the page in the cache. As we are only interested in the
+ // text we don't care about the page size.
+ if (pageCache->isPageCached(pageNumber))
+ {
+ // If the last search page used was created locally, we need to destroy it
+ if (!cachedPage)
+ delete searchPage;
+
+ searchPage = pageCache->getPage(pageNumber);
+ cachedPage = true;
+ }
+ else
+ {
+ // If the page is not in the cache we draw a small version of it, since this is faster.
+
+ // We only create a new searchPage if we need to, otherwise reuse the existing one.
+ if (!searchPage || cachedPage)
+ searchPage = new RenderedDocumentPagePixmap();
+
+ cachedPage = false;
+
+ searchPage->resize(1,1);
+ searchPage->setPageNumber(pageNumber);
+ renderer->getText(searchPage);
+ }
+
+ // If there is no text in the current page, try the next one.
+ if (searchPage->textBoxList.size() == 0)
+ continue;
+
+ foundSelection = searchPage->find(searchText, startingTextItem, case_sensitive);
+
+ if (foundSelection.isEmpty())
+ {
+ // In the next page, start search again at the beginning.
+ startingTextItem = 0;
+ clearSelection();
+
+ if (pageNumber == numberOfPages())
+ {
+ int answ = KMessageBox::questionYesNo(scrollView(),
+ i18n("<qt>The search string <strong>%1</strong> could not be found by the "
+ "end of the document. Should the search be restarted from the beginning "
+ "of the document?</qt>").arg(searchText),
+ i18n("Text Not Found"), KStdGuiItem::cont(), KStdGuiItem::cancel());
+
+ if (answ != KMessageBox::Yes)
+ {
+ setStatusBarText(QString::null);
+ searchInProgress = false;
+ if (!cachedPage)
+ delete searchPage;
+ return;
+ }
+ }
+ }
+ else
+ {
+ pageCache->selectText(foundSelection);
+ gotoPage(pageCache->selectedText());
+ setStatusBarText(QString::null);
+ searchInProgress = false;
+ if (!cachedPage)
+ delete searchPage;
+ return;
+ }
+ }
+
+ KMessageBox::sorry(scrollView(), i18n("<qt>The search string <strong>%1</strong> could not be found.</qt>").arg(searchText));
+ setStatusBarText(QString::null);
+ searchInProgress = false;
+ if (!cachedPage)
+ delete searchPage;
+}
+
+
+void KMultiPage::findPrevText()
+{
+#ifdef KDVI_MULTIPAGE_DEBUG
+ kdDebug(4300) << "KMultiPage::findPrevText() called" << endl;
+#endif
+
+ searchInProgress = true;
+
+ // Used to remember if the documentPage we use is from the cache.
+ // If not we need to delete it manually to avoid a memory leak.
+ bool cachedPage = false;
+
+ QString searchText = searchWidget->getText();
+
+ if (searchText.isEmpty())
+ {
+ kdError(4300) << "KMultiPage::findPrevText() called when search text was empty" << endl;
+ return;
+ }
+
+ bool case_sensitive = searchWidget->caseSensitive();
+
+ // Find the page and text position on the page where the search will
+ // start. If nothing is selected, we start at the beginning of the
+ // current page. Otherwise, start after the selected text. TODO:
+ // Optimize this to get a better 'user feeling'
+ unsigned int startingPage;
+ int startingTextItem;
+
+ TextSelection userSelection = pageCache->selectedText();
+ if (userSelection.isEmpty())
+ {
+ startingPage = currentPageNumber();
+ startingTextItem = -1;
+ }
+ else
+ {
+ startingPage = userSelection.getPageNumber();
+ startingTextItem = userSelection.getSelectedTextStart()-1;
+ }
+
+ TextSelection foundSelection;
+
+ RenderedDocumentPagePixmap* searchPage = 0;
+
+ for(unsigned int i = 0; i < numberOfPages(); i++)
+ {
+ int pageNumber = startingPage - i;
+ if (pageNumber <= 0)
+ pageNumber += numberOfPages();
+
+ if (!searchInProgress)
+ {
+ // Interrupt the search
+ setStatusBarText(i18n("Search interrupted"));
+ if (!cachedPage)
+ delete searchPage;
+ return;
+ }
+
+ if (i != 0)
+ {
+ setStatusBarText(i18n("Search page %1 of %2").arg(pageNumber).arg(numberOfPages()));
+ kapp->processEvents();
+ }
+
+ // Check if we already have a rendered version of the page in the cache. As we are only interested in the
+ // text we don't care about the page size.
+ if (pageCache->isPageCached(pageNumber))
+ {
+ // If the last search page used was created locally, we need to destroy it
+ if (!cachedPage)
+ delete searchPage;
+
+ searchPage = pageCache->getPage(pageNumber);
+ cachedPage = true;
+ }
+ else
+ {
+ // If the page is not in the cache we draw a small version of it, since this is faster.
+
+ // We only create a new searchPage if we need to, otherwise reuse the existing one.
+ if (!searchPage || cachedPage)
+ searchPage = new RenderedDocumentPagePixmap();
+
+ cachedPage = false;
+
+ searchPage->resize(1,1);
+ searchPage->setPageNumber(pageNumber);
+ renderer->getText(searchPage);
+ }
+
+ // If there is no text in the current page, try the next one.
+ if (searchPage->textBoxList.size() == 0)
+ continue;
+
+ foundSelection = searchPage->findRev(searchText, startingTextItem, case_sensitive);
+
+ if (foundSelection.isEmpty())
+ {
+ // In the next page, start search again at the beginning.
+ startingTextItem = -1;
+ clearSelection();
+
+ if (pageNumber == 1)
+ {
+ int answ = KMessageBox::questionYesNo(scrollView(),
+ i18n("<qt>The search string <strong>%1</strong> could not be found by the "
+ "beginning of the document. Should the search be restarted from the end "
+ "of the document?</qt>").arg(searchText),
+ i18n("Text Not Found"), KStdGuiItem::cont(), KStdGuiItem::cancel());
+
+ if (answ != KMessageBox::Yes)
+ {
+ setStatusBarText(QString::null);
+ searchInProgress = false;
+ if (!cachedPage)
+ delete searchPage;
+ return;
+ }
+ }
+ }
+ else
+ {
+ pageCache->selectText(foundSelection);
+ gotoPage(pageCache->selectedText());
+ setStatusBarText(QString::null);
+ searchInProgress = false;
+ if (!cachedPage)
+ delete searchPage;
+ return;
+ }
+ }
+
+ KMessageBox::sorry(scrollView(), i18n("<qt>The search string <strong>%1</strong> could not be found.</qt>").arg(searchText));
+ setStatusBarText(QString::null);
+ searchInProgress = false;
+ if (!cachedPage)
+ delete searchPage;
+}
+
+
+void KMultiPage::clearSelection()
+{
+ PageNumber page = pageCache->selectedText().getPageNumber();
+
+ if (!page.isValid())
+ return;
+
+ // Clear selection
+ pageCache->deselectText();
+
+ // Now we need to update the widget which contained the selection
+ switch(widgetList.size())
+ {
+ case 0:
+ kdError(4300) << "KMultiPage::clearSelection() while widgetList is empty" << endl;
+ break;
+ case 1:
+ widgetList[0]->update();
+ break;
+ default:
+ for (unsigned int i = 0; i < widgetList.size(); i++)
+ {
+ DocumentWidget* pageWidget = (DocumentWidget*)widgetList[i];
+ if (pageWidget->getPageNumber() == page)
+ {
+ pageWidget->update();
+ break;
+ }
+ }
+ }
+}
+
+void KMultiPage::copyText()
+{
+ pageCache->selectedText().copyText();
+}
+
+void KMultiPage::timerEvent( QTimerEvent * )
+{
+#ifdef KMULTIPAGE_DEBUG
+ kdDebug(4300) << "Timer Event " << endl;
+#endif
+ reload();
+}
+
+
+void KMultiPage::reload()
+{
+#ifdef KMULTIPAGE_DEBUG
+ kdDebug(4300) << "Reload file " << m_file << endl;
+#endif
+
+ if (renderer.isNull()) {
+ kdError() << "KMultiPage::reload() called, but no renderer was set" << endl;
+ return;
+ }
+
+ if (renderer->isValidFile(m_file)) {
+ pageCache->clear();
+ pageCache->deselectText();
+ document_history.clear();
+ emit setStatusBarText(i18n("Reloading file %1").arg(m_file));
+ Q_INT32 pg = currentPageNumber();
+
+ killTimer(timer_id);
+ timer_id = -1;
+ bool r = renderer->setFile(m_file, m_url);
+
+ generateDocumentWidgets();
+
+ // Set Table of Contents
+ tableOfContents->setContents(renderer->getBookmarks());
+
+ // Adjust number of widgets in the thumbnail sidebar
+ markList()->clear();
+ markList()->setNumberOfPages(numberOfPages(), KVSPrefs::showThumbnails());
+
+ setCurrentPageNumber(pg);
+ setFile(r);
+ emit setStatusBarText(QString::null);
+ } else {
+ if (timer_id == -1)
+ timer_id = startTimer(1000);
+ }
+}
+
+
+bool KMultiPage::openFile()
+{
+ if (renderer.isNull()) {
+ kdError(4300) << "KMultiPage::openFile() called when no renderer was set" << endl;
+ return false;
+ }
+
+ pageCache->deselectText();
+ document_history.clear();
+ pageCache->clear();
+ emit setStatusBarText(i18n("Loading file %1").arg(m_file));
+
+ bool r = renderer->setFile(m_file, m_url);
+
+ if (r) {
+ setCurrentPageNumber(1);
+ generateDocumentWidgets();
+
+ // Set number of widgets in the thumbnail sidebar
+ markList()->clear();
+ markList()->setNumberOfPages(numberOfPages(), KVSPrefs::showThumbnails());
+
+ QString reference = url().ref();
+ if (!reference.isEmpty())
+ gotoPage(renderer->parseReference(reference));
+
+ // Set Table of Contents
+ tableOfContents->setContents(renderer->getBookmarks());
+ } else
+ m_file = QString::null;
+
+
+ setFile(r);
+
+ // Clear Statusbar
+ emit setStatusBarText(QString::null);
+ return r;
+}
+
+
+bool KMultiPage::openURL(const QString &filename, const KURL &base_url)
+{
+ m_file = filename;
+ m_url = base_url;
+
+ bool success = openFile();
+ if (success)
+ setCurrentPageNumber(1);
+
+ return success;
+}
+
+
+void KMultiPage::enableActions(bool fileLoaded)
+{
+ Q_UNUSED(fileLoaded);
+}
+
+void KMultiPage::wheelEvent(QWheelEvent *e)
+{
+ QScrollBar *sb = scrollView()->verticalScrollBar();
+ if (sb == 0)
+ return;
+
+ // Zoom in/out
+ if (e->state() & ControlButton)
+ {
+ if (e->delta() < 0)
+ emit zoomOut();
+ else
+ emit zoomIn();
+ return;
+ }
+
+ Q_INT32 pxl = -(e->delta()*sb->lineStep())/60;
+ if (pxl == 0)
+ {
+ if (e->delta() > 0)
+ pxl = -1;
+ else
+ pxl = 1;
+ }
+
+ // Faster scrolling
+ if (e->state() & ShiftButton)
+ pxl *= 10;
+
+ scroll(pxl);
+}
+
+
+KPrinter *KMultiPage::getPrinter(bool enablePageSizeFeatures)
+{
+ // Allocate a new KPrinter structure, if necessary
+ KPrinter *printer = new KPrinter(true);
+ if (printer == 0) {
+ kdError(1223) << "KMultiPage::getPrinter(..): Cannot allocate new KPrinter structure" << endl;
+ return 0;
+ }
+
+ // Allocate a new KPrintDialogPage structure and add it to the
+ // printer, if the kmultipage implementation requests that
+ if (enablePageSizeFeatures == true) {
+ KPrintDialogPage_PageOptions *pageOptions = new KPrintDialogPage_PageOptions();
+ if (pageOptions == 0) {
+ kdError(1223) << "KMultiPage::getPrinter(..): Cannot allocate new KPrintDialogPage_PageOptions structure" << endl;
+ delete printer;
+ return 0;
+ }
+ printer->addDialogPage( pageOptions );
+ }
+
+ // Feed the printer with useful defaults and information.
+ printer->setPageSelection( KPrinter::ApplicationSide );
+ printer->setCurrentPage( currentPageNumber() );
+ printer->setMinMax( 1, numberOfPages() );
+ printer->setFullPage( true );
+
+ // If pages are marked, give a list of marked pages to the
+ // printer. We try to be smart and optimize the list by using ranges
+ // ("5-11") wherever possible. The user will be tankful for
+ // that. Complicated? Yeah, but that's life.
+ QValueList<int> selectedPageNo = selectedPages();
+ if (selectedPageNo.isEmpty() == true)
+ printer->setOption( "kde-range", "" );
+ else {
+ int commaflag = 0;
+ QString range;
+ QValueList<int>::ConstIterator it = selectedPageNo.begin();
+ do{
+ int val = *it;
+ if (commaflag == 1)
+ range += QString(", ");
+ else
+ commaflag = 1;
+ int endval = val;
+ if (it != selectedPageNo.end()) {
+ QValueList<int>::ConstIterator jt = it;
+ jt++;
+ do{
+ int val2 = *jt;
+ if (val2 == endval+1)
+ endval++;
+ else
+ break;
+ jt++;
+ } while( jt != selectedPageNo.end() );
+ it = jt;
+ } else
+ it++;
+ if (endval == val)
+ range += QString("%1").arg(val);
+ else
+ range += QString("%1-%2").arg(val).arg(endval);
+ } while (it != selectedPageNo.end() );
+ printer->setOption( "kde-range", range );
+ }
+
+ return printer;
+}
+
+void KMultiPage::doExportText()
+{
+ // Generate a suggestion for a reasonable file name
+ QString suggestedName = url().filename();
+ suggestedName = suggestedName.left(suggestedName.find(".")) + ".txt";
+
+ QString fileName = KFileDialog::getSaveFileName(suggestedName, i18n("*.txt|Plain Text (Latin 1) (*.txt)"), scrollView(), i18n("Export File As"));
+
+ if (fileName.isEmpty())
+ return;
+
+ QFileInfo finfo(fileName);
+ if (finfo.exists())
+ {
+ int r = KMessageBox::warningContinueCancel (scrollView(),
+ i18n("The file %1\nexists. Do you want to overwrite that file?").arg(fileName),
+ i18n("Overwrite File"), i18n("Overwrite"));
+
+ if (r == KMessageBox::Cancel)
+ return;
+ }
+
+ QFile textFile(fileName);
+ textFile.open(IO_WriteOnly);
+ QTextStream stream(&textFile);
+
+ QProgressDialog progress(i18n("Exporting to text..."), i18n("Abort"), renderer->totalPages(),
+ scrollView(), "export_text_progress", true);
+ progress.setMinimumDuration(300);
+
+ RenderedDocumentPagePixmap dummyPage;
+ dummyPage.resize(1, 1);
+
+ for(unsigned int page = 1; page <= renderer->totalPages(); page++)
+ {
+ progress.setProgress(page);
+ qApp->processEvents();
+
+ if (progress.wasCancelled())
+ break;
+
+ dummyPage.setPageNumber(page);
+ // We gracefully ignore any errors (bad file, etc.)
+ renderer->getText(&dummyPage);
+
+ for(unsigned int i = 0; i < dummyPage.textBoxList.size(); i++)
+ {
+ // We try to detect newlines
+ if (i > 0)
+ {
+ // Like all our textalgorithmns this currently assumes left to right text.
+ // TODO: make this more generic. But we first would need to guess the corrent
+ // orientation.
+ if (dummyPage.textBoxList[i].box.top() > dummyPage.textBoxList[i-1].box.bottom() &&
+ dummyPage.textBoxList[i].box.x() < dummyPage.textBoxList[i-1].box.x())
+ {
+ stream << "\n";
+ }
+ }
+ stream << dummyPage.textBoxList[i].text;
+ }
+
+ // Send newline after each page.
+ stream << "\n";
+ }
+
+ // Switch off the progress dialog, etc.
+ progress.setProgress(renderer->totalPages());
+ return;
+}
+
+void KMultiPage::slotEnableMoveTool(bool enable)
+{
+ emit enableMoveTool(enable);
+}
+
+#include "kmultipage.moc"
diff --git a/kviewshell/kmultipage.desktop b/kviewshell/kmultipage.desktop
new file mode 100644
index 00000000..2b4ac822
--- /dev/null
+++ b/kviewshell/kmultipage.desktop
@@ -0,0 +1,41 @@
+[Desktop Entry]
+Type=Service
+X-KDE-ServiceType=KViewShell/MultiPage
+Name=KViewShell MultiPage
+Name[da]=KViewShell Multiside
+Name[de]=KViewShell Mehrfachseiten
+Name[el]=Πολλαπλή σελίδα KViewShell
+Name[es]=Multipágina KViewShell
+Name[fi]=KViewShell MoniSivu
+Name[fr]=Multi-page KViewShell
+Name[gl]=KViewShell Multipáxina
+Name[hu]=KViewShell többoldalas
+Name[it]=MultiPagina KViewShell
+Name[kk]=Көпбетті KViewShell
+Name[ms]=PelbagaiMuka KViewShell
+Name[nb]=KViewShell Flerside
+Name[nds]=KViewShell för Mehrfachsieden
+Name[ne]=के दृश्य शेल बहुपृष्ठ
+Name[nl]=KViewShell MultiPagina
+Name[nn]=KViewShell-fleirside
+Name[pl]=Wielostronicowe dla KViewShell
+Name[pt]=KViewShell MultiPágina
+Name[pt_BR]=KViewShell - Múltiplas Páginas
+Name[ro]=KViewShell Pagini Multiple
+Name[ru]=Компонент MultiPage
+Name[sr]=KViewShell вишестрани
+Name[sr@Latn]=KViewShell višestrani
+Name[sv]=Kviewshell flera sidor
+Name[ta]=கேகாட்சிஓடு பலபக்கம்
+Name[tr]=KViewShell ÇokluSayfa
+Name[zh_CN]=KViewShell 多页
+Name[zh_HK]=KViewShell 多頁
+
+[PropertyDef::X-KDE-MimeTypes]
+Type=QString
+
+[PropertyDef::X-KDE-MultiPageVersion]
+Type=int
+
+[PropertyDef::X-KDE-EmptyMultiPage]
+Type=int
diff --git a/kviewshell/kmultipage.h b/kviewshell/kmultipage.h
new file mode 100644
index 00000000..7f24a809
--- /dev/null
+++ b/kviewshell/kmultipage.h
@@ -0,0 +1,650 @@
+// -*- C++ -*-
+#ifndef _KMULTIPAGE_H
+#define _KMULTIPAGE_H
+
+#include "pageView.h"
+#include "documentPageCache.h"
+#include "documentRenderer.h"
+#include "history.h"
+#include "kmultipageInterface.h"
+#include "marklist.h"
+
+#include <kparts/part.h>
+#include <qtimer.h>
+
+class Anchor;
+class DocumentWidget;
+class KConfigDialog;
+class KPrintDialogPage_PageOptions;
+class KPrinter;
+class PageView;
+class QPainter;
+class QSplitter;
+class QToolBox;
+class simplePageSize;
+class TableOfContents;
+class PageNumber;
+class SearchWidget;
+
+
+/** \brief This class provides plugin-specific GUI elements for kviewshell plugins
+
+@author Wilfried Huss, Stefan Kebekus
+
+ */
+
+// TODO remove virtual inheritance for KDE 4. It's the reason for the strange DCOPObject construction
+class KMultiPage : public KParts::ReadOnlyPart, virtual public kmultipageInterface
+{
+ Q_OBJECT
+
+public:
+ KMultiPage(QWidget *parentWidget, const char *widgetName, QObject *parent, const char *name);
+ virtual ~KMultiPage();
+
+ /* returns the scrollview used for the display */
+ virtual QWidget* mainWidget() {return _scrollView;}
+
+ /* Methods which are associated with the DCOP functionality of the
+ kmultipage. This method returns the file name (not the URL) of
+ the currently loaded file. */
+ QString name_of_current_file();
+
+ /* Methods which are associated with the DCOP functionality of the
+ kmultipage. This method can be implemented by the multipage,
+ e.g. to jump to a certain location. */
+ virtual ASYNC jumpToReference(const QString& /*reference*/);
+
+ /* Methods which are associated with the DCOP functionality of the
+ kmultipage. This method checks if a given file is loaded. */
+ bool is_file_loaded(const QString& filename);
+
+ /* Opens file and sets URL
+
+ This method does the same as openFile, but sets the m_url of the
+ kmultipage. This can be important, for the following reason:
+ assume that a DVI is or DJVU-file is located on a web server at
+ baseURL=http://www.x.x/x.dvi The file may refer to external
+ graphic files using relative links.
+
+ The file is downloaded by the kviewpart to a temporary file on
+ the hard disk, say /tmp/t.dvi. The kviewpart would then call this
+ method with filename=/tmp/t.dvi and baseURL=http://www.x.x/x.dvi,
+ so the DVI-renderer knows to interpret the link to t.jpg as
+ http://www.x.x/t.jpg, and will download the file from there.
+
+ @warning This method is virtual only for technical reasons. Do
+ not re-implement this method
+
+ @returns true on success, false on failure
+ */
+ virtual bool openURL(const QString &filename, const KURL &base_url);
+
+ /** Prints a document
+
+ This method prints a document. The default implementation offers
+ fairly good printer support, but printing with the default
+ implementation is usually quite slow as tremendous amounts of data
+ needs to be transferred to the printer. To limit the data sent to
+ the printer, this default implementation prints only at low
+ resolution and produces mediocre quality. This method can (and
+ should) therefore be re-implemented if you have good code to convert
+ your document to PostScript.
+
+ Example: If your document consists of a single A4 page that contains
+ a DJVU image of 30KB, then the default implementation would render
+ the image in 600dpi, i.e. in about 7000x5000 pixel, and then send
+ this huge graphics uncompressed to the printer. A smart
+ implementation, on the other hand, would send the DJVU-file directly
+ to the printer, together with a DJVU decoder, which is implemented
+ in PostScript and uses only a few KB of memory, making for less than
+ 40KB of data sent to the printer.
+
+ If you decide to re-implement this method, you need to decide if
+ your implementation will support the options offered by the "page
+ size & placement" tab of the print dialog. If these options are set,
+ pages that are smaller/larger than the printer's paper size will be
+ shrunk/enlarged and optionally centered on the paper.
+
+ If your implementation does not support the options, the following
+ code should be used:
+ @code
+ // Obtain a fully initialized KPrinter structure, and disable all
+ // entries in the "Page Size & Placement" tab of the printer dialog.
+ KPrinter *printer = getPrinter(false);
+ // Abort with an error message if no KPrinter could be initialized
+ if (printer == 0) {
+ kdError(4300) << "KPrinter not available" << endl;
+ return;
+ }
+
+ // Show the printer options dialog. Return immediately if the user
+ // aborts.
+ if (!printer->setup(parentWdg, i18n("Print %1").arg(m_file.section('/', -1)) )) {
+ delete printer;
+ return;
+ }
+
+ ... <Produce a PostScript file, with filename, say, tmpPSFile. You
+ can use all the features that KPrinter has to offer. Note that
+ printer->pageList() gives a list of pages to be printed, where "1"
+ denotes the first page, "2" the second, etc.> ...
+
+ printer->printFiles( QStringList(tmpPSFile), true );
+ delete printer;
+ @endcode
+
+ If your implementation does support the options, code must be
+ provided to support the KPrinter options
+ "kde-kviewshell-shrinkpage", "kde-kviewshell-expandpage",
+ "kde-kviewshell-centerpage" and "kde-kviewshell-rotatepage". It is
+ important to note that "kde-kviewshell-rotatepage" and
+ "kde-kviewshell-centerpage" should by default treated as "true",
+ while the other options should be "false" by default. The following
+ code sees to that:
+ @code
+ // Obtain a fully initialized KPrinter structure, and enable all
+ // entries in the "Page Size & Placement" tab of the printer dialog.
+ KPrinter *printer = getPrinter(true);
+ // Abort with an error message if no KPrinter could be initialized
+ if (printer == 0) {
+ kdError(4300) << "KPrinter not available" << endl;
+ return;
+ }
+
+ // Show the printer options dialog. Return immediately if the user
+ // aborts.
+ if (!printer->setup(parentWdg, i18n("Print %1").arg(m_file.section('/', -1)) )) {
+ delete printer;
+ return;
+ }
+
+ if (printer->option( "kde-kviewshell-shrinkpage" ) == "true")
+ <Shrink some pages to paper size, where necessary>
+ if (printer->option( "kde-kviewshell-expandpage" ) == "true")
+ <Expand some pages to paper size, where necessary>
+ if (printer->option( "kde-kviewshell-centerpage" ) != "false")
+ <Center pages on paper>
+ if (printer->option( "kde-kviewshell-rotatepage" ) != "false")
+ <rotate pages by 90 deg. counterclockwise, if paper orientation is different from pages orientation>
+
+ ... <Produce a PostScript file, with filename, say, tmpPSFile. You
+ can use all the features that KPrinter has to offer. Note that
+ printer->pageList() gives a list of pages to be printed, where "1"
+ denotes the first page, "2" the second, etc.> ...
+
+ printer->printFiles( QStringList(tmpPSFile), true );
+ delete printer;
+ @endcode
+
+ For more information, see the default implementation in the source
+ file kmultipage.cpp. You might also look at the documentation to
+ getPrinter().
+ */
+ virtual void print();
+
+
+ /* Returns true if the document specifies page sizes, and false
+ otherwise. NOTE: the information returned by this method is not
+ always 100% reliable. Although unlikely, it is theoretically
+ possible that this method returns 'true', but still some of the
+ sizes returned by sizeOfPage() are invalid. */
+ virtual bool hasSpecifiedPageSizes() const {return renderer && renderer->hasSpecifiedPageSizes();}
+
+ /* This methos is similar to openFile(). It is used when the "Watch
+ file" option is activated, and the file has changed on disk. It
+ differs from openFile() in two aspects: first, the file is
+ checked for validity with DVIRenderer.isValidFile(m_file) if the
+ file is invalid, a timer event is used to call the method again
+ after a brief pause. Secondly, when the GUI is updated, the
+ implementation does not jump to the first page, but tries to keep
+ the current page. */
+ virtual void reload();
+
+// Interface definition start ------------------------------------------------
+
+ /** list of supported file formats, for saving
+
+ This member must return the list of supported file formats for
+ saving. These strings returned must be in the format explained in
+ the documentation to KFileDialog::setFilter(), e.g. ""*.cpp *.cxx
+ *.c++|C++ Source Files". The use of mimetype-filters is allowed, but
+ discouraged. Among other penalties, if a multipage gives a
+ mimetype-filter, e.g. "application/x-dvi", the open file dialog in
+ kviewshell will not allow the user to see and select compressed
+ dvi-files.
+ */
+ virtual QStringList fileFormats() const = 0;
+
+ /// closes a file
+ virtual bool closeURL();
+
+ /* sets a zoom factor. The multipage implementation might refuse to
+ use a given zoom factor, even if it falls within the bounds given
+ by the constants MinZoom and MaxZoom which are defined in
+ zoomlimits.h. In that case, the multipage implementation chooses a
+ different zomm factor. The implementation returns the factor which
+ has actually been used. A default implementation is provided. */
+ virtual double setZoom(double z);
+
+ /** reads in settings. Reimplementations must call this. */
+ virtual void readSettings();
+
+ /** writes settings. Reimplementations must call this. */
+ virtual void writeSettings();
+
+ /** Flag to indicate that this implementation has support for textserach and selection */
+ virtual bool supportsTextSearch() const { return getRenderer() && getRenderer()->supportsTextSearch(); }
+
+ /** Flag to indicate the document was modified since last saved
+
+ KMultiPage implementations that offer functionality that
+ modifies the document (e.g. remove or insert pages) must
+ re-implement this method to return
+
+ @returns 'true' if the document was modified since it was last
+ saved
+ */
+ virtual bool isModified() const {return false;}
+
+ /* Returns the number of the first (i.e. top-left) page in the
+ display. Such a number cannot be reasonably assigned
+ (e.g. because the current document is empty, or because no
+ document has been loaded yet), the method returns "invalid page",
+ i.e. 0. */
+ virtual PageNumber currentPageNumber();
+
+ /* Returns the number of pages in the currently loaded document or
+ 0, if no document is loaded or if the document is empty */
+ PageNumber numberOfPages() const {return renderer.isNull() ? (PageNumber)0 : renderer->totalPages();}
+
+ /* List of pages selected in the sidebar
+
+ @returns a list with the numbers of the currently selected
+ pages. */
+ virtual QValueList<int> selectedPages() {return markList()->selectedPages();}
+
+ virtual History* history() { return &document_history; }
+
+ /** Add pages to the KViewshell's central preferences dialog
+
+ This method can be re-implemented to add documenttype specific
+ configuration pages to the central preferences dialog. The
+ documentation to KConfigDialog explains how to do that.
+
+ The default implementation does nothing.
+
+ @param configDialog a pointer to the KConfigDialog the dialog to
+ add pages to
+ */
+ virtual void addConfigDialogs(KConfigDialog* configDialog) { Q_UNUSED(configDialog); }
+
+
+ /* These methods calculate the Zoomfactor needed to fit the pages
+ into the current viewport. Note that the return value need *not*
+ be within the limits defined in "zoomLimits.h". If they are not,
+ this indicates that fitting to width or height is currently not
+ possible (e.g. because no document is loaded). The return value
+ should then be ignored and any operation that relies on the
+ return value should be aborted. */
+ virtual double calculateFitToWidthZoomValue();
+ virtual double calculateFitToHeightZoomValue();
+
+ /* Returns the number of columns into which the widgets are aligned. */
+ virtual Q_UINT8 getNrColumns() const { return _scrollView->getNrColumns(); }
+ virtual Q_UINT8 getNrRows() const { return _scrollView->getNrRows(); }
+
+ virtual bool overviewMode() const { return _scrollView->overviewMode(); }
+
+ // =========== Interface definition ends
+
+ /* ---------------------------------------------------------------------
+ The following methods export functions of the DocumentPageCache which
+ are currently needed by KViewPart. TODO: Clean this up again without
+ directly linking DocumentPageCache to the KViewPart. */
+
+ /* Returns the size of page 'page'. If the document does not
+ specify a size (which happens, e.g., for some DVI-files), then
+ the userPreferredSize is returned. */
+ virtual SimplePageSize sizeOfPage(const PageNumber& page = 1) const { return pageCache->sizeOfPage(page); }
+
+public slots:
+ /* Sets the userPreferredSize, which is explained below */
+ virtual void setUserPreferredSize(const SimplePageSize& t) { pageCache->setUserPreferredSize(t); }
+ virtual void setUseDocumentSpecifiedSize(bool b) { pageCache->setUseDocumentSpecifiedSize(b); }
+ // --------------------------------------------------------------------
+
+protected:
+ /** Update GUI after loading or closing of a file
+
+ This method is called by openFile() when a new file was loaded,
+ and by closeURL() when a file is closed so that the kmultipage
+ implementation can update its own GUI, enable/disable actions,
+ prepare info texts, etc. At the time the method is executed, the
+ file has already been loaded into the renderer using
+ renderer.setFile(), or closed using renderer.clear() and the
+ standard KMultiPage GUI is set up. The filename can be accessed
+ via m_file.
+
+ The default implementation does nothing.
+
+ @param success the return value of renderer.setFile() which
+ indicates if the file could be successfully loaded by the
+ renderer, or not. Note that setFile() is called even if the
+ renderer returned 'false', so that the implemtation can then
+ disable menu items, etc. */
+ virtual void setFile(bool success);
+
+ /* Creates new instances of DocumentWidget. If you need special
+ functionality and reimplement the DocumentWidget class, then you
+ should also reimplement this method to ensure that your new
+ DocumentWidgets will be used. This function is also the right
+ place to connect to signals emitted by DocumentWidget. */
+ virtual DocumentWidget* createDocumentWidget();
+
+ /* Used to enable/disable KActions of multiPage implementations.
+ enableActions(true) should be called whenever a file is
+ successfully loaded. enableActions(false) is called when the
+ file is closed. */
+ virtual void enableActions(bool);
+
+ /* Initializes all data structures that need to know the renderer.
+ This function must be called in the constructor of multipage
+ implementations. */
+ void setRenderer(DocumentRenderer*);
+
+ /** This function creates the page cache. If a multipage implementation needs
+ additional functionaly from the cache overwrite this function to create a
+ subclass of DocumentPageCache.
+ @warning This function is called by the constructor, never call it explicitly.
+ */
+ virtual void initializePageCache();
+
+ /* Returns a pointer to the renderer. */
+ virtual QGuardedPtr<DocumentRenderer> getRenderer() const { return renderer; }
+
+ PageView* scrollView() { return _scrollView; }
+
+ MarkList* markList() { return _markList; }
+
+ // The next two functions are used for the autozoom feature
+ // TODO optimize (the calculation of the widest page needs to be done only once
+ // per document, not everytime calculateFitToWidthZoomValue() is called)
+ PageNumber widestPage() const;
+
+ // TODO Generalize this for more than 2 columns
+ double zoomForWidthColumns(unsigned int viewportWidth) const;
+
+public slots:
+ virtual void doSelectAll();
+
+ virtual void clearSelection();
+
+ virtual void copyText();
+
+ /** Exports the document to a plain text file. */
+ virtual void doExportText();
+
+ /* Shows the "text search" dialog, if text search is supported by
+ the renderer. Otherwise, the method returns immediately. */
+ virtual void showFindTextDialog();
+
+
+ /* This method may be called after the text search dialog
+ 'findDialog' has been set up, and the user has entered a search
+ phrase. The method searches for the next occurence of the text,
+ starting from the beginning of the current page, or after the
+ currently selected text, if there is any. */
+ virtual void findNextText();
+
+ /* This method may be called after the text search dialog
+ 'findDialog' has been set up, and the user has entered a search
+ phrase. The method searches for the next occurence of the text,
+ starting from the end of the current page, or before the
+ currently selected text, if there is any. */
+ virtual void findPrevText();
+
+ /** Opens a file requestor and starts a basic copy KIO-Job. A
+ multipage implementation that wishes to offer saving in various
+ formats must re-implement this slot. */
+ virtual void slotSave();
+
+ /* The standard implementation just calls slotSave. */
+ virtual void slotSave_defaultFilename();
+
+ /* Initialize/Update PageWidgets, thumbnail list and bookmark list
+
+ This slot is called after a document was loaded, when the
+ document was modified (e.g. when pages were deleted), or the
+ rendering mode is changed (e.g. when a different accessibility
+ viewmode is selected). The following is done
+
+ - The page cache is cleared
+
+ - all page widgets as well as the thumbnails are updated.
+ */
+ void renderModeChanged();
+
+ /* Empties the page cache and --as the name suggests-- repaints all
+ visible widgets. */
+ void repaintAllVisibleWidgets();
+
+ /* Tells the multipage if scrollbars should be used. */
+ virtual void slotShowScrollbars(bool);
+
+ /* Show or hide the sidebar widget. */
+ virtual void slotShowSidebar(bool);
+
+ /* Show or hide thumbnails. */
+ virtual void slotShowThumbnails(bool);
+
+ /* Used internally. */
+ void slotIOJobFinished ( KIO::Job *job );
+
+ /* Switches to fullscreen mode and back. */
+ virtual void slotSetFullPage(bool fullpage);
+
+ virtual void setViewMode(int);
+
+ /* Is called if settings are changed in the configuration dialog.
+ If this method is reimplemented in a child class, it needs to be
+ called from there. */
+ virtual void preferencesChanged();
+
+ /* Page Navigation. */
+ virtual bool gotoPage(const PageNumber& page);
+ virtual void gotoPage(const Anchor& a);
+
+ virtual void prevPage();
+ virtual void nextPage();
+ virtual void firstPage();
+ virtual void lastPage();
+
+ virtual void scrollUp();
+ virtual void scrollDown();
+ virtual void scrollLeft();
+ virtual void scrollRight();
+
+ virtual void scrollUpPage();
+ virtual void scrollDownPage();
+ virtual void scrollLeftPage();
+ virtual void scrollRightPage();
+
+ virtual void readUp();
+ virtual void readDown();
+
+ virtual void doGoBack();
+ virtual void doGoForward();
+
+ /* Scrolls the main scrollview by deltaInPixel (positive values
+ scroll DOWN). If the user tries to scroll past the beginning or
+ the end of a page, then the method either returns without doing
+ anything (if the current page is the first or last page, resp, or
+ if the method is called within 200ms after the beg. or end of the
+ page was reached), or goes the the next/previous page. The delay
+ makes it a little easier for the user to scroll with the mouse
+ wheel or the keyboard without involuntarily moving to another
+ page. */
+ virtual void scroll(Q_INT32 deltaInPixel);
+
+ virtual void slotEnableMoveTool(bool enable);
+
+protected slots:
+ virtual bool gotoPage(const PageNumber& page, int y, bool isLink = true);
+
+ /* Make the selection visible */
+ void gotoPage(const TextSelection&);
+
+private slots:
+ void handleLocalLink(const QString &linkText);
+
+signals:
+ /** Emitted with argument "true" when the move tool is selected, and
+ with argument "false" if selection tool is selected. */
+ void enableMoveTool(bool enable);
+
+ /* Emitted when a page has been selected in the MarkList. */
+ void selected(const PageNumber& pageNumber);
+
+ /* Emitted to indicate the number of pages in the file and the
+ current page. The receiver will not change or update the display,
+ nor call the gotoPage()-method. */
+ void pageInfo(int nr, int currpg);
+
+ void askingToCheckActions();
+
+ /* emitted when a new preview is available */
+ void previewChanged(bool previewAvailable);
+
+ void viewModeChanged();
+
+ /* Emitted when the zoom of the pageview changes. */
+ void zoomChanged();
+
+ void zoomOut();
+ void zoomIn();
+
+ /* Emitted it the status of the text selection changes. */
+ void textSelected(bool);
+
+ void searchEnabled(bool);
+
+// Interface definition end --------------------------------------------------
+
+public slots:
+ virtual void generateDocumentWidgets(const PageNumber& startPage = PageNumber::invalidPage);
+
+ protected slots:
+ /* This is the slot where mouseWheel events are processed that come
+ from the multipage/scrollview. This method calles scroll, a
+ delta-value of 120 (i.e. one notch on a standard wheel mouse)
+ scrolls by two 'lines'. */
+ void wheelEvent(QWheelEvent *);
+
+protected:
+ /** Allocates and initializes a KPrinter structure
+
+ This method is used in implementations of the print() method. See
+ the documentation of print() for more information and for example
+ code. This method allocates and initializes a KPrinter
+ structure. The list of pages marked in the sidebar is already set in
+ the "kde-range" option in the KPrinter structure. In this option "1"
+ means: first page of the document, "2" the second, etc.
+
+ @param enablePageSizeFeatures Enables or diables the entries in the
+ "Page Size & Placement" tab of the print dialog.
+
+ @returns a pointer to a KPrinter, or 0 if no KPrinter could be
+ allocated.
+
+ @warning The KPrinter allocated is owned by the caller must be
+ deleted before the KMultiPage is deleted. Otherwise, a segfault will
+ occur.
+ */
+ KPrinter *getPrinter(bool enablePageSizeFeatures=true);
+
+
+ /** Pointer to the parent widget
+
+ This pointer is automatically set by the constructor.
+ */
+ QGuardedPtr<QWidget> parentWdg;
+
+ QPtrVector<DocumentWidget> widgetList;
+
+ History document_history;
+
+ /* Variable which is used internally by the method
+ currentPageNumber() to provide 'lazy' page numbers. */
+ PageNumber lastCurrentPage;
+
+ /* The pageCache caches already drawn "documentPages" and invokes
+ the renderer if the needed page is not available in the cache. */
+ DocumentPageCache* pageCache;
+
+private slots:
+ void setCurrentPageNumber(const PageNumber&);
+ void updateWidgetSize(const PageNumber&);
+
+ /* Interrupts a search if one is currently performed, otherwise
+ hide the search panel */
+ void stopSearch();
+
+private:
+ /* For internal use by the reload()-method. See the comments in
+ kmultipage.cpp, right before the timerEvent function. */
+ int timer_id;
+
+ /* For internal use the reload()-method. This is a dreadful
+ hack. The problem we adress with this timer event is the
+ following: the kviewshell has a KDirWatch object which looks at
+ the DVI file and calls reload() when the object has changed. That
+ works very nicely in principle, but in practise, when TeX runs
+ for several seconds over a complicated file, this does not work
+ at all. First, most of the time, while TeX is still writing, the
+ file is invalid. Thus, reload() is very often called when the DVI
+ file is bad. We solve this problem by checking the file first. If
+ the file is bad, we do not reload. Second, when the file finally
+ becomes good, it very often happens that KDirWatch does not
+ notify us anymore. Whether this is a bug or a side effect of a
+ feature of KDirWatch, I dare not say. We remedy that problem by
+ using a timer: when reload() was called on a bad file, we
+ automatically come back (via the timerEvent() function) every
+ second and check if the file became good. If so, we stop the
+ timer. It may well happen that KDirWatch calls us several times
+ while we are waiting for the file to become good, but that does
+ not do any harm. */
+ void timerEvent( QTimerEvent *e );
+
+ /* This method opens a file and sets up the GUI when the file is
+ loaded. It calls setFile() so that implementations of kmultipage
+ can update their own GUI. DO NOT REIMPLEMENT THIS METHOD. */
+ bool openFile();
+
+ /* Is set by setRenderer. */
+ QGuardedPtr<DocumentRenderer> renderer;
+
+ PageView *_scrollView;
+ SearchWidget* searchWidget;
+ QToolBox* sideBar;
+
+ MarkList* _markList;
+ TableOfContents* tableOfContents;
+
+ QSplitter* splitterWidget;
+
+ /* This timer is used to implement a brief delay when the user
+ scrolls past the beginning or the end of the page before a the
+ program moves to a new page. That way, it is a little easier for
+ the user to scroll with the mouse wheel or the keyboard without
+ involuntarily moving to another page. The timer is used in the
+ scroll() method. */
+ QTimer changePageDelayTimer;
+
+ // This is set to true while a text search is performed.
+ // If set to false the search is interrupted.
+ bool searchInProgress;
+};
+
+
+#endif
diff --git a/kviewshell/kmultipageInterface.h b/kviewshell/kmultipageInterface.h
new file mode 100644
index 00000000..0ad6e914
--- /dev/null
+++ b/kviewshell/kmultipageInterface.h
@@ -0,0 +1,18 @@
+// -*- C++ -*-
+#ifndef kmultipageINTERFACE_H
+#define kmultipageINTERFACE_H
+
+#include <dcopobject.h>
+
+class kmultipageInterface : virtual public DCOPObject
+{
+ K_DCOP
+
+ k_dcop:
+ virtual ASYNC jumpToReference(const QString& reference) = 0;
+ virtual QString name_of_current_file() = 0;
+ virtual bool is_file_loaded(const QString& filename) = 0;
+};
+
+#endif
+
diff --git a/kviewshell/kprintDialogPage_pageoptions.cpp b/kviewshell/kprintDialogPage_pageoptions.cpp
new file mode 100644
index 00000000..dbadd759
--- /dev/null
+++ b/kviewshell/kprintDialogPage_pageoptions.cpp
@@ -0,0 +1,166 @@
+// KPrintDialogPage_PageOptions.cpp
+//
+// Part of KVIEWSHELL - A framework for multipage text/gfx viewers
+//
+// (C) 2005 Stefan Kebekus
+// Distributed under the GPL
+
+// Add header files alphabetically
+
+#include <config.h>
+
+#include <klocale.h>
+#include <qbuttongroup.h>
+#include <qcheckbox.h>
+#include <qlayout.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+#include <kdebug.h>
+
+#include "kprintDialogPage_pageoptions.h"
+
+
+KPrintDialogPage_PageOptions::KPrintDialogPage_PageOptions( QWidget *parent, const char *name )
+ : KPrintDialogPage( parent, name )
+{
+ setTitle( i18n("Page Size & Placement") );
+
+ kprintDialogPage_pageoptions_baseLayout = 0;
+ checkBox_center = 0;
+ checkBox_rotate = 0;
+ checkBox_shrink = 0;
+ checkBox_expand = 0;
+
+ kprintDialogPage_pageoptions_baseLayout = new QVBoxLayout( this, 11, 6, "kprintDialogPage_pageoptions_baseLayout");
+ if (kprintDialogPage_pageoptions_baseLayout == 0) {
+ kdError(1223) << "KPrintDialogPage_PageOptions::KPrintDialogPage_PageOptions() cannot create layout" << endl;
+ return;
+ }
+
+ checkBox_center = new QCheckBox( this, "checkBox_center" );
+ if (checkBox_center != 0) {
+ checkBox_center->setText( i18n( "Center the page on paper" ) );
+ QToolTip::add( checkBox_center, i18n( "If this option is enabled, the pages are centered on the paper." ) );
+ QWhatsThis::add( checkBox_center, i18n( "<qt><p>If this option is enabled, the pages will be printed centered on the paper; this makes "
+ "more visually-appealing printouts.</p>"
+ "<p>If the option is not enabled, all pages will be placed in the top-left corner of the paper.</p></qt>" ) );
+ kprintDialogPage_pageoptions_baseLayout->addWidget( checkBox_center );
+ }
+
+ 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( "<qt><p>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.</p>"
+ "<p><b>Note:</b> 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.</p></qt>" ) );
+ kprintDialogPage_pageoptions_baseLayout->addWidget( checkBox_rotate );
+ }
+
+ QFrame *line = new QFrame( this, "line1" );
+ if (line != 0) {
+ line->setFrameShape( QFrame::HLine );
+ line->setFrameShadow( QFrame::Sunken );
+ line->setFrameShape( QFrame::HLine );
+ kprintDialogPage_pageoptions_baseLayout->addWidget( line );
+ }
+
+ checkBox_shrink = new QCheckBox( this, "checkBox_shrink" );
+ if (checkBox_shrink != 0) {
+ checkBox_shrink->setText( i18n( "Shrink oversized pages to fit paper size" ) );
+ QToolTip::add( checkBox_shrink, i18n( "If this option is enabled, large pages that would not fit the printer's paper size will be shrunk." ) );
+ QWhatsThis::add( checkBox_shrink, i18n( "<qt><p>If this option is enabled, large pages that would not fit the printer's paper size will be "
+ "shrunk so that edges won't be cut off during printing.</p>"
+ "<p><b>Note:</b> If this option is enabled, and if the pages in your document have different sizes, "
+ "then different pages might be shrunk by different scaling factors.</p></qt>" ) );
+ kprintDialogPage_pageoptions_baseLayout->addWidget( checkBox_shrink );
+ }
+
+ checkBox_expand = new QCheckBox( this, "checkBox_expand" );
+ if (checkBox_expand != 0) {
+ checkBox_expand->setText( i18n( "Expand small pages to fit paper size" ) );
+ QToolTip::add( checkBox_expand, i18n( "If this option is enabled, small pages will be enlarged so that they fit the printer's paper size." ) );
+ QWhatsThis::add( checkBox_expand, i18n( "<qt><p>If this option is enabled, small pages will be enlarged so that they fit the printer's "
+ "paper size.</p>"
+ "<p><b>Note:</b> If this option is enabled, and if the pages in your document have different sizes, "
+ "then different pages might be expanded by different scaling factors.</p></qt>" ) );
+ kprintDialogPage_pageoptions_baseLayout->addWidget( checkBox_expand );
+ }
+
+
+ resize( QSize(319, 166).expandedTo(minimumSizeHint()) );
+ clearWState( WState_Polished );
+}
+
+
+
+void KPrintDialogPage_PageOptions::getOptions( QMap<QString,QString>& opts, bool incldef )
+{
+ // Save options, taking default values into consideration: by
+ // default "center" is checked, "expand" and "shrink" are
+ // not. Warning: The default values are also coded into setOptions()
+ // and kmultipage::print(..).
+
+ if (checkBox_center != 0)
+ if ( incldef || !checkBox_center->isChecked() )
+ if (checkBox_center->isChecked())
+ opts[ "kde-kviewshell-centerpage" ] = "true";
+ else
+ opts[ "kde-kviewshell-centerpage" ] = "false";
+
+ if (checkBox_rotate != 0)
+ if ( incldef || !checkBox_rotate->isChecked() )
+ if (checkBox_rotate->isChecked())
+ opts[ "kde-kviewshell-rotatepage" ] = "true";
+ else
+ opts[ "kde-kviewshell-rotatepage" ] = "false";
+
+ if (checkBox_shrink != 0)
+ if ( incldef || checkBox_shrink->isChecked() )
+ if (checkBox_shrink->isChecked())
+ opts[ "kde-kviewshell-shrinkpage" ] = "true";
+ else
+ opts[ "kde-kviewshell-shrinkpage" ] = "false";
+
+ if (checkBox_expand != 0)
+ if ( incldef || checkBox_expand->isChecked() )
+ if (checkBox_expand->isChecked())
+ opts[ "kde-kviewshell-expandpage" ] = "true";
+ else
+ opts[ "kde-kviewshell-expandpage" ] = "false";
+}
+
+
+void KPrintDialogPage_PageOptions::setOptions( const QMap<QString,QString>& opts )
+{
+ // Sets the centering option. By default, this option is
+ // checked. Warning: All default values are also coded into
+ // getOptions() and kmultipage::print(..).
+ QString op = opts[ "kde-kviewshell-centerpage" ];
+ if (checkBox_center != 0)
+ checkBox_center->setChecked( op != "false" );
+
+ // same for rotation
+ op = opts[ "kde-kviewshell-rotatepage" ];
+ if (checkBox_rotate != 0)
+ checkBox_rotate->setChecked( op != "false" );
+
+ // Sets the shrink option. By default, this option is not checked
+ op = opts[ "kde-kviewshell-shrinkpage" ];
+ if (checkBox_shrink != 0)
+ checkBox_shrink->setChecked( op == "true" );
+
+ // Sets the expand option. By default, this option is not checked
+ op = opts[ "kde-kviewshell-expandpage" ];
+ if (checkBox_expand != 0)
+ checkBox_expand->setChecked( op == "true" );
+}
+
+
+bool KPrintDialogPage_PageOptions::isValid( QString& )
+{
+ return true;
+}
diff --git a/kviewshell/kprintDialogPage_pageoptions.h b/kviewshell/kprintDialogPage_pageoptions.h
new file mode 100644
index 00000000..0c274248
--- /dev/null
+++ b/kviewshell/kprintDialogPage_pageoptions.h
@@ -0,0 +1,43 @@
+// -*- C++ -*-
+// 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_PAGEOPTIONS_H
+#define KPRINTDIALOGPAGE_PAGEOPTIONS_H
+
+#include <kdeprint/kprintdialogpage.h>
+
+class QCheckBox;
+class QVBoxLayout;
+
+
+// This is a fairly standard KPrintDialogPage that allows the user to
+// chose page size & placement options: center page on paper, shrink
+// oversized pages, and expand small pages
+
+class KPrintDialogPage_PageOptions : public KPrintDialogPage
+{
+ public:
+ KPrintDialogPage_PageOptions( QWidget *parent = 0, const char *name = 0 );
+
+ void getOptions( QMap<QString,QString>& opts, bool incldef = false );
+ void setOptions( const QMap<QString,QString>& opts );
+ bool isValid( QString& msg );
+
+ QCheckBox* checkBox_center;
+ QCheckBox* checkBox_rotate;
+ QCheckBox* checkBox_shrink;
+ QCheckBox* checkBox_expand;
+
+ private:
+ QVBoxLayout* kprintDialogPage_pageoptions_baseLayout;
+};
+
+
+#endif // KPRINTDIALOGPAGE_PAGEOPTIONS_H
diff --git a/kviewshell/kviewerpart.rc b/kviewshell/kviewerpart.rc
new file mode 100644
index 00000000..856ca4e2
--- /dev/null
+++ b/kviewshell/kviewerpart.rc
@@ -0,0 +1,91 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="KViewPart" version="12">
+<MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="file_open"/>
+ <Action name="file_open_recent"/>
+ <Action name="file_save" group="save_merge"/>
+ <Action name="file_save_as" group="save_merge"/>
+ <Separator group="save_merge"/>
+ <Action name="file_print" group="print_merge"/>
+ <Menu name="export" group="print_merge"><text>Export As</text>
+ <Action name="export_text"/>
+ <DefineGroup name="export_merge" append="export_merge"/>
+ </Menu>
+ <Separator group="print_merge"/>
+ </Menu>
+ <Menu name="edit"><text>&amp;Edit</text>
+ <Action name="move_tool" group="tools_merge"/>
+ <Action name="selection_tool" group="tools_merge"/>
+ <Separator group="tools_merge"/>
+ <Action name="copy_text"/>
+ <Action name="edit_select_all"/>
+ <Action name="edit_deselect_all"/>
+ <Separator/>
+ <Action name="find"/>
+ <Action name="findnext"/>
+ <Action name="findprev"/>
+ <Merge/>
+ </Menu>
+ <Menu name="view"><text>&amp;View</text>
+ <Action name="viewmode"/>
+ <Merge/>
+ <Separator/>
+ <Action name="view_media"/>
+ <Action name="view_orientation"/>
+ <Action name="view_use_document_specified_size"/>
+ <Separator/>
+ <Action name="view_zoom_in"/>
+ <Action name="view_zoom_out"/>
+ <Separator/>
+ <Action name="view_fit_to_page"/>
+ <Action name="view_fit_to_width"/>
+ <Action name="view_fit_to_height"/>
+ </Menu>
+ <Menu name="go"><text>&amp;Go</text>
+ <Action name="go_goto_page"/>
+ <Separator/>
+ <Action name="go_previous"/>
+ <Action name="go_next"/>
+ <Separator/>
+ <Action name="go_first"/>
+ <Action name="go_last"/>
+ <Separator/>
+ <Action name="go_read_up"/>
+ <Action name="go_read_down"/>
+ <Separator/>
+ <Action name="go_back"/>
+ <Action name="go_forward"/>
+ </Menu>
+ <Menu name="settings">
+ <Action name="show_sidebar" group="settings_top"/>
+ <Action name="scrollbarHandling" group="settings_top"/>
+ <Action name="watch_file" group="additional_settings_merge"/>
+ <Action name="options_configure" group="configure_merge"/>
+ </Menu>
+ <Menu name="help"><text>&amp;Help</text>
+ <Action name="help_about_kviewshell" group="help_about"/>
+ </Menu>
+
+</MenuBar>
+<ToolBar name="mainToolBar">
+ <Action name="file_print"/>
+ <Separator/>
+ <Action name="go_first"/>
+ <Action name="go_previous"/>
+ <Action name="go_next"/>
+ <Action name="go_last"/>
+ <Action name="readDown"/>
+ <Separator/>
+ <Action name="view_zoom_in"/>
+ <Action name="view_zoom"/>
+ <Action name="view_zoom_out"/>
+ <Separator/>
+ <Action name="move_tool"/>
+ <Action name="selection_tool"/>
+ <Separator/>
+ <Action name="go_back"/>
+ <Action name="go_forward"/>
+</ToolBar>
+</kpartgui>
+
diff --git a/kviewshell/kviewpart.cpp b/kviewshell/kviewpart.cpp
new file mode 100644
index 00000000..ef21dca7
--- /dev/null
+++ b/kviewshell/kviewpart.cpp
@@ -0,0 +1,1632 @@
+#include <qfileinfo.h>
+#include <qhbox.h>
+#include <qlayout.h>
+#include <qscrollview.h>
+#include <qscrollbar.h>
+#include <qtimer.h>
+#include <qpainter.h>
+#include <qprinter.h>
+#include <qprintdialog.h>
+
+#include <kaboutdialog.h>
+#include <kaccel.h>
+#include <kaction.h>
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kconfigdialog.h>
+#include <kdebug.h>
+#include <kdirwatch.h>
+#include <kfiledialog.h>
+#include <kfilterbase.h>
+#include <kfilterdev.h>
+#include <kglobal.h>
+#include <kinstance.h>
+#include <kio/job.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+#include <kmimetype.h>
+#include <kparts/componentfactory.h>
+#include <kparts/genericfactory.h>
+#include <kparts/partmanager.h>
+#include <kprogress.h>
+#include <kstandarddirs.h>
+#include <kstdaction.h>
+#include <ktempfile.h>
+#include <ktrader.h>
+#include <kinputdialog.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <math.h>
+
+#include "kviewpart.h"
+#include "kmultipage.h"
+#include "pageSize.h"
+#include "pageSizeDialog.h"
+#include "zoomlimits.h"
+
+#include "optionDialogGUIWidget_base.h"
+#include "optionDialogAccessibilityWidget.h"
+
+#include "kvsprefs.h"
+
+#define MULTIPAGE_VERSION 2
+
+typedef KParts::GenericFactory<KViewPart> KViewPartFactory;
+K_EXPORT_COMPONENT_FACTORY(kviewerpart, KViewPartFactory)
+
+KViewPart::KViewPart(QWidget *parentWidget, const char *widgetName, QObject *parent,
+ const char *name, const QStringList& args)
+ : KViewPart_Iface(parent, name), showSidebar(0), saveAction(0), partManager(0),
+ multiPageLibrary(QString::null), aboutDialog(0)
+{
+ KGlobal::locale()->insertCatalogue("kviewshell");
+
+ tmpUnzipped = 0L;
+ pageChangeIsConnected = false;
+ setInstance(KViewPartFactory::instance());
+
+ watch = KDirWatch::self();
+ connect(watch, SIGNAL(dirty(const QString&)), this, SLOT(fileChanged(const QString&)));
+ watch->startScan();
+
+ mainWidget = new QHBox(parentWidget, widgetName);
+ mainWidget->setFocusPolicy(QWidget::StrongFocus);
+ setWidget(mainWidget);
+
+ // Setup part manager
+ partManager = new KParts::PartManager(parentWidget, "PartManager for kviewpart");
+ setManager(partManager);
+ // Don't switch to another part when pressing a mouse button
+ partManager->setActivationButtonMask(0);
+ // Without this the GUI-items of the KMultiPages are not merged
+ partManager->setAllowNestedParts(true);
+
+ connect(partManager, SIGNAL(activePartChanged(KParts::Part*)), this, SIGNAL(pluginChanged(KParts::Part*)));
+ partManager->addPart(this);
+
+ // create the displaying part
+
+ // Search for service
+ KTrader::OfferList offers;
+
+ if (!args.isEmpty())
+ {
+ // If a default MimeType is specified try to load a MultiPage supporting it.
+ QString defaultMimeType = args.first();
+ offers = KTrader::self()->query(
+ QString::fromLatin1("KViewShell/MultiPage" ),
+ QString("([X-KDE-MultiPageVersion] == %1) and "
+ "([X-KDE-MimeTypes] == '%2')").arg(MULTIPAGE_VERSION).arg(defaultMimeType));
+ }
+
+ // If no default MimeType is given or no MultiPage has been found, try to load the Empty MultiPage.
+ if (offers.isEmpty())
+ {
+ offers = KTrader::self()->query(
+ QString::fromLatin1("KViewShell/MultiPage" ),
+ QString("([X-KDE-MultiPageVersion] == %1) and "
+ "([X-KDE-EmptyMultiPage] == 1)").arg(MULTIPAGE_VERSION));
+ }
+
+ // If still no MultiPage has been found, report an error and abort.
+ if (offers.isEmpty())
+ {
+ KMessageBox::error(parentWidget, i18n("<qt>No MultiPage found.</qt>"));
+ // return;
+ }
+
+ KService::Ptr service = offers.first();
+ kdDebug(1223) << service->library() << endl;
+
+ // Try to load the multiPage
+ int error;
+ multiPage = static_cast<KMultiPage*>(KParts::ComponentFactory::createInstanceFromService<KParts::ReadOnlyPart>(service, mainWidget,
+ service->name().utf8(), QStringList(), &error ));
+
+ // If the loading of the MultiPage failed report and error and abort.
+ if (!multiPage) {
+ QString reason;
+ switch(error) {
+ case KParts::ComponentFactory::ErrNoServiceFound:
+ reason = i18n("<qt>No service implementing the given mimetype and fullfilling the given constraint expression can be found.</qt>");
+ break;
+ case KParts::ComponentFactory::ErrServiceProvidesNoLibrary:
+ reason = i18n("<qt>The specified service provides no shared library.</qt>");
+ break;
+ case KParts::ComponentFactory::ErrNoLibrary:
+ reason = i18n("<qt><p>The specified library <b>%1</b> could not be loaded. The error message returned was:</p>"
+ "<p><b>%2</b></p></qt>").arg(service->library()).arg(KLibLoader::self()->lastErrorMessage());
+ break;
+ case KParts::ComponentFactory::ErrNoFactory:
+ reason = i18n("<qt>The library does not export a factory for creating components.</qt>");
+ break;
+ case KParts::ComponentFactory::ErrNoComponent:
+ reason = i18n("<qt>The factory does not support creating components of the specified type.</qt>");
+ break;
+ }
+
+ QString text = i18n("<qt><p><b>Problem:</b> The document <b>%1</b> cannot be shown.</p>"
+ "<p><b>Reason:</b> The software component <b>%2</b> which is required to "
+ "display your files could not be initialized. This could point to "
+ "serious misconfiguration of your KDE system, or to damaged program files.</p>"
+ "<p><b>What you can do:</b> You could try to re-install the software packages in "
+ "question. If that does not help, you could file an error report, either to the "
+ "provider of your software (e.g. the vendor of your Linux distribution), or "
+ "directly to the authors of the software. The entry <b>Report Bug...</b> in the "
+ "<b>Help</b> menu helps you to contact the KDE programmers.</p></qt>").arg(m_file).arg(service->library());
+ QString caption = i18n("Error Initializing Software Component");
+ KMessageBox::detailedError(mainWidget, text, reason, caption);
+ emit setStatusBarText(QString::null);
+ return;
+ }
+ // Make the KViewPart the parent of the MultiPage.
+ // So the Partmanager treats it as a nested KPart.
+ insertChild(multiPage);
+
+ // Remember the name of the library.
+ multiPageLibrary = service->library();
+ // Add the multipage to the GUI.
+ partManager->addPart(multiPage);
+
+ exportTextAction = new KAction(i18n("Text..."), 0, this, SLOT(mp_exportText()), actionCollection(), "export_text");
+
+ // edit menu
+ findTextAction = KStdAction::find(this, SLOT(mp_showFindTextDialog()), actionCollection(), "find");
+ findNextAction = KStdAction::findNext(this, SLOT(mp_findNextText()), actionCollection(), "findnext");
+ findNextAction->setEnabled(false);
+ findPrevAction = KStdAction::findPrev(this, SLOT(mp_findPrevText()), actionCollection(), "findprev");
+ findPrevAction->setEnabled(false);
+
+ selectAllAction = KStdAction::selectAll(this, SLOT(mp_doSelectAll()), actionCollection(), "edit_select_all");
+
+ copyTextAction = KStdAction::copy(this, SLOT(mp_copyText()), actionCollection(), "copy_text");
+ copyTextAction->setEnabled(false);
+
+ deselectAction = KStdAction::deselect(this, SLOT(mp_clearSelection()), actionCollection(), "edit_deselect_all");
+ deselectAction->setEnabled(false);
+
+ saveAction = KStdAction::save(this, SLOT(mp_slotSave_defaultFilename()), actionCollection());
+
+ // settings menu
+ showSidebar = new KToggleAction (i18n("Show &Sidebar"), "show_side_panel", 0, this,
+ SLOT(slotShowSidebar()), actionCollection(), "show_sidebar");
+ showSidebar->setCheckedState(i18n("Hide &Sidebar"));
+ watchAct = new KToggleAction(i18n("&Watch File"), 0, 0, 0, actionCollection(), "watch_file");
+ scrollbarHandling = new KToggleAction (i18n("Show Scrollbars"), 0, 0, 0, actionCollection(), "scrollbarHandling");
+ scrollbarHandling->setCheckedState(i18n("Hide Scrollbars"));
+
+ // View modes
+ QStringList viewModes;
+ viewModes.append(i18n("Single Page"));
+ viewModes.append(i18n("Continuous"));
+ viewModes.append(i18n("Continuous - Facing"));
+ viewModes.append(i18n("Overview"));
+ viewModeAction = new KSelectAction (i18n("View Mode"), 0, 0, 0, actionCollection(), "viewmode");
+ viewModeAction->setItems(viewModes);
+
+ // Orientation menu
+ QStringList orientations;
+ orientations.append(i18n("Portrait"));
+ orientations.append(i18n("Landscape"));
+ orientation = new KSelectAction (i18n("Preferred &Orientation"), 0, 0, 0, actionCollection(), "view_orientation");
+ orientation->setItems(orientations);
+ connect(orientation, SIGNAL(activated (int)), &userRequestedPaperSize, SLOT(setOrientation(int)));
+
+ // Zoom Menu
+ zoom_action = new KSelectAction (i18n("&Zoom"), 0, 0, 0, actionCollection(), "view_zoom");
+ zoom_action->setEditable(true);
+ zoom_action->setItems(_zoomVal.zoomNames());
+
+ connect (&_zoomVal, SIGNAL(zoomNamesChanged(const QStringList &)), zoom_action, SLOT(setItems(const QStringList &)));
+ connect (&_zoomVal, SIGNAL(valNoChanged(int)), zoom_action, SLOT(setCurrentItem(int)));
+ connect (&_zoomVal, SIGNAL(zoomNameChanged(const QString &)), this, SIGNAL(zoomChanged(const QString &)) );
+ connect (zoom_action, SIGNAL(activated(const QString &)), this, SLOT(setZoomValue(const QString &)));
+ _zoomVal.setZoomValue(1.0); // should not be necessary @@@@
+ emit(zoomChanged("100%"));
+
+ // Paper Size Menu
+ media = new KSelectAction (i18n("Preferred Paper &Size"), 0, 0, 0, actionCollection(), "view_media");
+ QStringList items = userRequestedPaperSize.pageSizeNames();
+ items.prepend(i18n("Custom Size..."));
+ media->setItems(items);
+ connect (media, SIGNAL(activated(int)), this, SLOT(slotMedia(int)));
+
+ useDocumentSpecifiedSize = new KToggleAction(i18n("&Use Document Specified Paper Size"), 0, this, SLOT(slotShowSidebar()),
+ actionCollection(), "view_use_document_specified_size");
+
+ // Zoom Actions
+ zoomInAct = KStdAction::zoomIn (this, SLOT(zoomIn()), actionCollection());
+ zoomOutAct = KStdAction::zoomOut(this, SLOT(zoomOut()), actionCollection());
+
+ fitPageAct = new KToggleAction(i18n("&Fit to Page"), "view_fit_window", Key_P,
+ actionCollection(), "view_fit_to_page");
+ fitWidthAct = new KToggleAction(i18n("Fit to Page &Width"), "view_fit_width", Key_W,
+ actionCollection(), "view_fit_to_width");
+ fitHeightAct = new KToggleAction(i18n("Fit to Page &Height"), "view_fit_height", Key_H,
+ actionCollection(), "view_fit_to_height");
+
+ fitPageAct -> setExclusiveGroup("view_fit");
+ fitWidthAct -> setExclusiveGroup("view_fit");
+ fitHeightAct -> setExclusiveGroup("view_fit");
+
+ connect(fitPageAct, SIGNAL(toggled(bool)), this, SLOT(enableFitToPage(bool)));
+ connect(fitWidthAct, SIGNAL(toggled(bool)), this, SLOT(enableFitToWidth(bool)));
+ connect(fitHeightAct, SIGNAL(toggled(bool)), this, SLOT(enableFitToHeight(bool)));
+
+ // go menu
+ backAct = KStdAction::prior(this, SLOT(mp_prevPage()), actionCollection());
+ forwardAct = KStdAction::next(this, SLOT(mp_nextPage()), actionCollection());
+ startAct = KStdAction::firstPage(this, SLOT(mp_firstPage()), actionCollection());
+ endAct = KStdAction::lastPage(this, SLOT(mp_lastPage()), actionCollection());
+ gotoAct = KStdAction::gotoPage(this, SLOT(goToPage()), actionCollection());
+ gotoAct->setShortcut("CTRL+G");
+
+ readUpAct = new KAction(i18n("Read Up Document"), "up", SHIFT+Key_Space, this, SLOT(mp_readUp()), actionCollection(), "go_read_up");
+ readDownAct = new KAction(i18n("Read Down Document"), "down", Key_Space, this, SLOT(mp_readDown()), actionCollection(), "go_read_down");
+
+ printAction = KStdAction::print(this, SLOT(slotPrint()), actionCollection());
+
+ saveAsAction = KStdAction::saveAs(this, SLOT(mp_slotSave()), actionCollection());
+
+ // mode action
+ moveModeAction = new KRadioAction(i18n("&Move Tool"), "movetool", Key_F4, actionCollection(), "move_tool");
+ selectionModeAction = new KRadioAction(i18n("&Selection Tool"), "selectiontool", Key_F5, actionCollection(), "selection_tool");
+
+ moveModeAction->setExclusiveGroup("tools");
+ selectionModeAction->setExclusiveGroup("tools");
+
+ moveModeAction->setChecked(true);
+
+ connect(moveModeAction, SIGNAL(toggled(bool)), this, SLOT(slotEnableMoveTool(bool)));
+ //connect(selectionModeAction, SIGNAL(toggled(bool)), this, SLOT(slotEnableSelectionTool(bool)));
+
+ // history action
+ backAction = new KAction(i18n("&Back"), "1leftarrow", 0,
+ this, SLOT(mp_doGoBack()), actionCollection(), "go_back");
+ forwardAction = new KAction(i18n("&Forward"), "1rightarrow", 0,
+ this, SLOT(mp_doGoForward()), actionCollection(), "go_forward");
+
+ backAction->setEnabled(false);
+ forwardAction->setEnabled(false);
+
+
+ settingsAction = KStdAction::preferences(this, SLOT(doSettings()), actionCollection());
+
+ // We only show this menuitem if no default mimetype is set. This usually means kviewshell
+ // has been started by itself. Otherwise if KDVI or KFaxView has been started show the
+ // additional about information.
+ if (!args.isEmpty())
+ {
+ aboutAction = new KAction(i18n("About KViewShell"), "kviewshell", 0, this,
+ SLOT(aboutKViewShell()), actionCollection(), "help_about_kviewshell");
+ }
+
+ // keyboard accelerators
+ accel = new KAccel(mainWidget);
+ accel->insert(I18N_NOOP("Scroll Up"), Key_Up, this, SLOT(mp_scrollUp()));
+ accel->insert(I18N_NOOP("Scroll Down"), Key_Down, this, SLOT(mp_scrollDown()));
+ accel->insert(I18N_NOOP("Scroll Left"), Key_Left, this, SLOT(mp_scrollLeft()));
+ accel->insert(I18N_NOOP("Scroll Right"), Key_Right, this, SLOT(mp_scrollRight()));
+
+ accel->insert(I18N_NOOP("Scroll Up Page"), SHIFT+Key_Up, this, SLOT(mp_scrollUpPage()));
+ accel->insert(I18N_NOOP("Scroll Down Page"), SHIFT+Key_Down, this, SLOT(mp_scrollDownPage()));
+ accel->insert(I18N_NOOP("Scroll Left Page"), SHIFT+Key_Left, this, SLOT(mp_scrollLeftPage()));
+ accel->insert(I18N_NOOP("Scroll Right Page"), SHIFT+Key_Right, this, SLOT(mp_scrollRightPage()));
+
+ accel->readSettings();
+ readSettings();
+
+ m_extension = new KViewPartExtension(this);
+
+ setXMLFile("kviewerpart.rc");
+
+ initializeMultiPage();
+
+ // The page size dialog is constructed on first usage -- saves some
+ // memory when not used.
+ _pageSizeDialog = 0;
+
+ checkActions();
+ viewModeAction->setCurrentItem(KVSPrefs::viewMode());
+
+ // We disconnect because we dont want some FocusEvents to trigger a GUI update, which might mess
+ // with our menus.
+ disconnect(partManager, SIGNAL(activePartChanged(KParts::Part*)), this, SIGNAL(pluginChanged(KParts::Part*)));
+}
+
+KViewPart::~KViewPart()
+{
+ writeSettings();
+
+ // Without the next two lines, konqueror crashes when it is quit
+ // while displaying a DVI file. I don't really understand
+ // why... --Stefan.
+ if (manager() != 0)
+ manager()->removePart(this);
+
+ // Delete the partManager;
+ setManager(0);
+ delete partManager;
+
+ delete multiPage;
+ delete tmpUnzipped;
+}
+
+
+void KViewPart::initializeMultiPage()
+{
+ // Paper Size handling
+ multiPage->setUseDocumentSpecifiedSize(useDocumentSpecifiedSize->isChecked());
+ multiPage->setUserPreferredSize(userRequestedPaperSize);
+ connect(&userRequestedPaperSize, SIGNAL(sizeChanged(const SimplePageSize&)), multiPage, SLOT(setUserPreferredSize(const SimplePageSize&)));
+ connect(useDocumentSpecifiedSize, SIGNAL(toggled(bool)), multiPage, SLOT(setUseDocumentSpecifiedSize(bool)));
+
+
+ connect(scrollbarHandling, SIGNAL(toggled(bool)), multiPage, SLOT(slotShowScrollbars(bool)));
+
+ // connect to the multi page view
+ connect( this, SIGNAL(scrollbarStatusChanged(bool)), multiPage, SLOT(slotShowScrollbars(bool)));
+ connect( multiPage, SIGNAL(pageInfo(int, int)), this, SLOT(pageInfo(int, int)) );
+ connect( multiPage, SIGNAL(askingToCheckActions()), this, SLOT(checkActions()) );
+ connect( multiPage, SIGNAL( started( KIO::Job * ) ), this, SIGNAL( started( KIO::Job * ) ) );
+ connect( multiPage, SIGNAL( completed() ), this, SIGNAL( completed() ) );
+ connect( multiPage, SIGNAL( canceled( const QString & ) ), this, SIGNAL( canceled( const QString & ) ) );
+ connect( multiPage, SIGNAL( setStatusBarText( const QString& ) ), this, SLOT( setStatusBarTextFromMultiPage( const QString& ) ) );
+
+ connect( multiPage, SIGNAL(zoomIn()), this, SLOT(zoomIn()) );
+ connect( multiPage, SIGNAL(zoomOut()), this, SLOT(zoomOut()) );
+
+ // change the viewmode
+ connect(viewModeAction, SIGNAL(activated (int)), multiPage, SLOT(setViewMode(int)));
+
+ // Update zoomlevel on viewmode changes
+ connect(multiPage, SIGNAL(viewModeChanged()), this, SLOT(updateZoomLevel()));
+
+ // navigation history
+ connect(multiPage->history(), SIGNAL(backItem(bool)), backAction, SLOT(setEnabled(bool)));
+ connect(multiPage->history(), SIGNAL(forwardItem(bool)), forwardAction, SLOT(setEnabled(bool)));
+
+ // text selection
+ connect(multiPage, SIGNAL(textSelected(bool)), copyTextAction, SLOT(setEnabled(bool)));
+ connect(multiPage, SIGNAL(textSelected(bool)), deselectAction, SLOT(setEnabled(bool)));
+
+ // text search
+ connect(multiPage, SIGNAL(searchEnabled(bool)), findNextAction, SLOT(setEnabled(bool)));
+ connect(multiPage, SIGNAL(searchEnabled(bool)), findPrevAction, SLOT(setEnabled(bool)));
+
+ // allow parts to have a GUI, too :-)
+ // (will be merged automatically)
+ insertChildClient( multiPage );
+}
+
+void KViewPart::slotStartFitTimer()
+{
+ fitTimer.start(100, true);
+}
+
+
+QString KViewPart::pageSizeDescription()
+{
+ PageNumber nr = multiPage->currentPageNumber();
+ if (!nr.isValid())
+ return QString::null;
+ SimplePageSize ss = multiPage->sizeOfPage(nr);
+ if (!ss.isValid())
+ return QString::null;
+ pageSize s(ss);
+
+ QString size = " ";
+ if (s.formatNumber() == -1) {
+ if (KGlobal::locale()-> measureSystem() == KLocale::Metric)
+ size += QString("%1x%2 mm").arg(s.width().getLength_in_mm(), 0, 'f', 0).arg(s.height().getLength_in_mm(), 0, 'f', 0);
+ else
+ size += QString("%1x%2 in").arg(s.width().getLength_in_inch(), 0, 'g', 2).arg(s.height().getLength_in_inch(), 0, 'g', 2);
+ } else {
+ size += s.formatName() + "/";
+ if (s.getOrientation() == 0)
+ size += i18n("portrait");
+ else
+ size += i18n("landscape");
+ }
+ return size+" ";
+}
+
+
+void KViewPart::restoreDocument(const KURL &url, int page)
+{
+ if (openURL(url))
+ multiPage->gotoPage(page);
+}
+
+
+void KViewPart::saveDocumentRestoreInfo(KConfig* config)
+{
+ config->writePathEntry("URL", url().url());
+ if (multiPage->numberOfPages() > 0)
+ config->writeEntry("Page", multiPage->currentPageNumber());
+}
+
+
+void KViewPart::slotFileOpen()
+{
+ if ((!multiPage.isNull()) && (multiPage->isModified() == true)) {
+ int ans = KMessageBox::warningContinueCancel( 0,
+ i18n("Your document has been modified. Do you really want to open another document?"),
+ i18n("Warning - Document Was Modified"),KStdGuiItem::open());
+ if (ans == KMessageBox::Cancel)
+ return;
+ }
+
+ KURL url = KFileDialog::getOpenURL(QString::null, supportedMimeTypes().join(" "));
+
+ if (!url.isEmpty())
+ openURL(url);
+}
+
+QStringList KViewPart::supportedMimeTypes()
+{
+ QStringList supportedMimeTypes;
+
+ // Search for service
+ KTrader::OfferList offers = KTrader::self()->query(
+ QString::fromLatin1("KViewShell/MultiPage"),
+ QString("([X-KDE-MultiPageVersion] == %1)").arg(MULTIPAGE_VERSION)
+ );
+
+ if (!offers.isEmpty())
+ {
+ KTrader::OfferList::ConstIterator iterator = offers.begin();
+ KTrader::OfferList::ConstIterator end = offers.end();
+
+ for (; iterator != end; ++iterator)
+ {
+ KService::Ptr service = *iterator;
+ QString mimeType = service->property("X-KDE-MimeTypes").toString();
+ supportedMimeTypes << mimeType;
+
+ }
+ }
+
+ // The kviewshell is also able to read compressed files and to
+ // uncompress them on the fly.
+
+ // Check if this version of KDE supports bzip2
+ bool bzip2Available = (KFilterBase::findFilterByMimeType( "application/x-bzip2" ) != 0L);
+
+ supportedMimeTypes << "application/x-gzip";
+
+ if (bzip2Available)
+ {
+ supportedMimeTypes << "application/x-bzip2";
+ }
+
+ return supportedMimeTypes;
+}
+
+QStringList KViewPart::fileFormats() const
+{
+ // Compile a list of the supported filename patterns
+
+ // First we build a list of the mimetypes which are supported by the
+ // currently installed KMultiPage-Plugins.
+ QStringList supportedMimeTypes;
+ QStringList supportedPattern;
+
+ // Search for service
+ KTrader::OfferList offers = KTrader::self()->query(
+ QString::fromLatin1("KViewShell/MultiPage"),
+ QString("([X-KDE-MultiPageVersion] == %1)").arg(MULTIPAGE_VERSION)
+ );
+
+ if (!offers.isEmpty())
+ {
+ KTrader::OfferList::ConstIterator iterator = offers.begin();
+ KTrader::OfferList::ConstIterator end = offers.end();
+
+ for (; iterator != end; ++iterator)
+ {
+ KService::Ptr service = *iterator;
+ QString mimeType = service->property("X-KDE-MimeTypes").toString();
+ supportedMimeTypes << mimeType;
+
+ QStringList pattern = KMimeType::mimeType(mimeType)->patterns();
+ while(!pattern.isEmpty())
+ {
+ supportedPattern.append(pattern.front().stripWhiteSpace());
+ pattern.pop_front();
+ }
+ }
+ }
+
+ // The kviewshell is also able to read compressed files and to
+ // uncompress them on the fly. Thus, we modify the list of supported
+ // file formats which we obtain from the multipages to include
+ // compressed files like "*.dvi.gz". We add "*.dvi.bz2" if support
+ // for bzip2 is compiled into KDE.
+
+ // Check if this version of KDE supports bzip2
+ bool bzip2Available = (KFilterBase::findFilterByMimeType( "application/x-bzip2" ) != 0L);
+
+ QStringList compressedPattern;
+
+ for(QStringList::Iterator it = supportedPattern.begin(); it != supportedPattern.end(); ++it )
+ {
+ if ((*it).find(".gz", -3) == -1) // Paranoia safety check
+ compressedPattern.append(*it + ".gz");
+
+ if ((bzip2Available) && ((*it).find(".bz2", -4) == -1)) // Paranoia safety check
+ compressedPattern.append(*it + ".bz2");
+ }
+
+ while (!compressedPattern.isEmpty())
+ {
+ supportedPattern.append(compressedPattern.front());
+ compressedPattern.pop_front();
+ }
+
+ kdDebug(1223) << "Supported Pattern: " << supportedPattern << endl;
+
+ return supportedPattern;
+}
+
+
+void KViewPart::slotSetFullPage(bool fullpage)
+{
+ if (multiPage)
+ multiPage->slotSetFullPage(fullpage);
+ else
+ kdError(1223) << "KViewPart::slotSetFullPage() called without existing multipage" << endl;
+
+ // Restore normal view
+ if (fullpage == false)
+ {
+ slotShowSidebar();
+ multiPage->slotShowScrollbars(scrollbarHandling->isChecked());
+ }
+}
+
+
+void KViewPart::slotShowSidebar()
+{
+ bool show = showSidebar->isChecked();
+ multiPage->slotShowSidebar(show);
+}
+
+
+bool KViewPart::openFile()
+{
+ KURL tmpFileURL;
+
+ // We try to be error-tolerant about filenames. If the user calls us
+ // with something like "test", and we are using the DVI-part, we'll
+ // also look for "testdvi" and "test.dvi".
+ QFileInfo fi(m_file);
+ m_file = fi.absFilePath();
+
+ if (!fi.exists())
+ {
+ QStringList supportedPatterns = fileFormats();
+ QStringList endings;
+
+ for (QStringList::Iterator it = supportedPatterns.begin(); it != supportedPatterns.end(); ++it)
+ {
+ // Only consider patterns starting with "*."
+ if ((*it).find("*.") == 0)
+ {
+ // Remove first Letter from string
+ endings.append((*it).mid(2).stripWhiteSpace());
+ }
+ }
+ kdDebug(1223) << "Supported Endings: " << endings << endl;
+
+ // Now try to append the endings with and without "." to the given filename,
+ // and see if that gives a existing file.
+ for (QStringList::Iterator it = endings.begin(); it != endings.end(); ++it)
+ {
+ fi.setFile(m_file+(*it));
+ if (fi.exists())
+ {
+ m_file = m_file+(*it);
+ break;
+ }
+ fi.setFile(m_file+"."+(*it));
+ if (fi.exists())
+ {
+ m_file = m_file+"."+(*it);
+ break;
+ }
+ }
+
+ // If we still have not found a file. Show an error message and return.
+ if (!fi.exists())
+ {
+ KMessageBox::error(mainWidget, i18n("<qt>File <nobr><strong>%1</strong></nobr> does not exist.</qt>").arg(m_file));
+ emit setStatusBarText(QString::null);
+ return false;
+ }
+ m_url.setPath(QFileInfo(m_file).absFilePath());
+ }
+
+ // Set the window caption now, before we do any uncompression and generation of temporary files.
+ tmpFileURL.setPath(m_file);
+ emit setStatusBarText(i18n("Loading '%1'...").arg(tmpFileURL.prettyURL()));
+ emit setWindowCaption( tmpFileURL.prettyURL() ); // set Window caption WITHOUT the reference part!
+
+ // Check if the file is compressed
+ KMimeType::Ptr mimetype = KMimeType::findByPath( m_file );
+
+ if (( mimetype->name() == "application/x-gzip" ) || ( mimetype->name() == "application/x-bzip2" ) ||
+ ( mimetype->parentMimeType() == "application/x-gzip" ) ||
+ ( mimetype->parentMimeType() == "application/x-bzip2" ))
+ {
+ // The file is compressed. Make a temporary file, and store an uncompressed version there...
+ if (tmpUnzipped != 0L) // Delete old temporary file
+ delete tmpUnzipped;
+
+ tmpUnzipped = new KTempFile;
+ if (tmpUnzipped == 0L)
+ {
+ KMessageBox::error(mainWidget, i18n("<qt><strong>File Error!</strong> Could not create "
+ "temporary file.</qt>"));
+ emit setWindowCaption(QString::null);
+ emit setStatusBarText(QString::null);
+ return false;
+ }
+ tmpUnzipped->setAutoDelete(true);
+ if(tmpUnzipped->status() != 0)
+ {
+ KMessageBox::error(mainWidget, i18n("<qt><strong>File Error!</strong> Could not create temporary file "
+ "<nobr><strong>%1</strong></nobr>.</qt>").arg(strerror(tmpUnzipped->status())));
+ emit setWindowCaption(QString::null);
+ emit setStatusBarText(QString::null);
+ return false;
+ }
+
+ QIODevice* filterDev;
+ if (( mimetype->parentMimeType() == "application/x-gzip" ) ||
+ ( mimetype->parentMimeType() == "application/x-bzip2" ))
+ filterDev = KFilterDev::deviceForFile(m_file, mimetype->parentMimeType());
+ else
+ filterDev = KFilterDev::deviceForFile(m_file);
+ if (filterDev == 0L)
+ {
+ emit setWindowCaption(QString::null);
+ emit setStatusBarText(QString::null);
+ return false;
+ }
+ if(!filterDev->open(IO_ReadOnly))
+ {
+ KMessageBox::detailedError(mainWidget, i18n("<qt><strong>File Error!</strong> Could not open the file "
+ "<nobr><strong>%1</strong></nobr> for uncompression. "
+ "The file will not be loaded.</qt>").arg(m_file),
+ i18n("<qt>This error typically occurs if you do not have enough permissions to read the file. "
+ "You can check ownership and permissions if you right-click on the file in the Konqueror "
+ "file manager and then choose the 'Properties' menu.</qt>"));
+ emit setWindowCaption(QString::null);
+ delete filterDev;
+ emit setStatusBarText(QString::null);
+ return false;
+ }
+
+ KProgressDialog* prog = new KProgressDialog(0L, "uncompress-progress",
+ i18n("Uncompressing..."),
+ i18n("<qt>Uncompressing the file <nobr><strong>%1</strong></nobr>. Please wait.</qt>").arg(m_file));
+
+ prog->progressBar()->setTotalSteps((int) fi.size()/1024);
+ prog->progressBar()->setProgress(0);
+ prog->setMinimumDuration(250);
+
+ QByteArray buf(1024);
+ int read = 0, wrtn = 0;
+
+ bool progress_dialog_was_cancelled = false;
+ while ((read = filterDev->readBlock(buf.data(), buf.size())) > 0)
+ {
+ kapp->processEvents();
+ progress_dialog_was_cancelled = prog->wasCancelled();
+ if (progress_dialog_was_cancelled)
+ break;
+ prog->progressBar()->advance(1);
+
+ wrtn = tmpUnzipped->file()->writeBlock(buf.data(), read);
+ if(read != wrtn)
+ break;
+ }
+ delete filterDev;
+ delete prog;
+ tmpUnzipped->sync();
+
+ if (progress_dialog_was_cancelled) {
+ emit setStatusBarText(QString::null);
+ return false;
+ }
+
+ if ((read != 0) || (tmpUnzipped->file()->size() == 0))
+ {
+ KMessageBox::detailedError(mainWidget, i18n("<qt><strong>File Error!</strong> Could not uncompress "
+ "the file <nobr><strong>%1</strong></nobr>. The file will not be loaded.</qt>").arg( m_file ),
+ i18n("<qt>This error typically occurs if the file is corrupt. "
+ "If you want to be sure, try to decompress the file manually using command-line tools.</qt>"));
+ emit setWindowCaption(QString::null);
+ emit setStatusBarText(QString::null);
+ return false;
+ }
+ tmpUnzipped->close();
+
+ m_file = tmpUnzipped->name();
+ }
+
+ // Now call the openURL-method of the multipage and give it an URL
+ // pointing to the downloaded file.
+ tmpFileURL.setPath(m_file);
+ // Pass the reference part of the URL through to the multipage
+ tmpFileURL.setRef(m_url.ref());
+
+ mimetype = KMimeType::findByURL(tmpFileURL);
+
+ // Search for service
+ KTrader::OfferList offers = KTrader::self()->query(
+ QString::fromLatin1("KViewShell/MultiPage" ),
+ QString("([X-KDE-MultiPageVersion] == %1) and "
+ "([X-KDE-MimeTypes] == '%2')").arg(MULTIPAGE_VERSION).arg(mimetype->name()));
+
+ if (offers.isEmpty()) {
+ KMessageBox::detailedError(mainWidget, i18n("<qt>The document <b>%1</b> cannot be shown because "
+ "its file type is not supported.</qt>").arg(m_file),
+ i18n("<qt>The file has mime type <b>%1</b> which is not supported by "
+ "any of the installed KViewShell plugins.</qt>").arg(mimetype->name()));
+ emit setWindowCaption(QString::null);
+ emit setStatusBarText(QString::null);
+ return false;
+ }
+
+ KService::Ptr service = offers.first();
+
+ // The the new multiPage is different then the currently loaded one.
+ if (service->library() != multiPageLibrary)
+ {
+ // We write the settings before we load the new multipage, so
+ // that the new multipage gets the same settings than the
+ // currently loaded one.
+ writeSettings();
+
+ // Delete old config dialog
+ KConfigDialog* configDialog = KConfigDialog::exists("kviewshell_config");
+ delete configDialog;
+
+ KMultiPage* oldMultiPage = multiPage;
+
+ // Try to load the multiPage
+ int error;
+ multiPage = static_cast<KMultiPage*>(KParts::ComponentFactory::createInstanceFromService<KParts::ReadOnlyPart>(service, mainWidget,
+ service->name().utf8(), QStringList(), &error ));
+
+ if (multiPage.isNull()) {
+ QString reason;
+ switch(error) {
+ case KParts::ComponentFactory::ErrNoServiceFound:
+ reason = i18n("<qt>No service implementing the given mimetype and fullfilling the given constraint expression can be found.</qt>");
+ break;
+ case KParts::ComponentFactory::ErrServiceProvidesNoLibrary:
+ reason = i18n("<qt>The specified service provides no shared library.</qt>");
+ break;
+ case KParts::ComponentFactory::ErrNoLibrary:
+ reason = i18n("<qt><p>The specified library <b>%1</b> could not be loaded. The error message returned was:</p> <p><b>%2</b></p></qt>").arg(service->library()).arg(KLibLoader::self()->lastErrorMessage());
+ break;
+ case KParts::ComponentFactory::ErrNoFactory:
+ reason = i18n("<qt>The library does not export a factory for creating components.</qt>");
+ break;
+ case KParts::ComponentFactory::ErrNoComponent:
+ reason = i18n("<qt>The factory does not support creating components of the specified type.</qt>");
+ break;
+ }
+
+ QString text = i18n("<qt><p><b>Problem:</b> The document <b>%1</b> cannot be shown.</p>"
+ "<p><b>Reason:</b> The software "
+ "component <b>%2</b> which is required to display files of type <b>%3</b> could "
+ "not be initialized. This could point to serious misconfiguration of your KDE "
+ "system, or to damaged program files.</p>"
+ "<p><b>What you can do:</b> You could try to re-install the software packages in "
+ "question. If that does not help, you could file an error report, either to the "
+ "provider of your software (e.g. the vendor of your Linux distribution), or "
+ "directly to the authors of the software. The entry <b>Report Bug...</b> in the "
+ "<b>Help</b> menu helps you to contact the KDE programmers.</p></qt>").arg(m_file).arg(service->library()).arg(mimetype->name());
+ QString caption = i18n("Error Initializing Software Component");
+ if (reason.isEmpty())
+ KMessageBox::error(mainWidget, text, caption);
+ else
+ KMessageBox::detailedError(mainWidget, text, reason, caption);
+ emit setStatusBarText(QString::null);
+ return false;
+ }
+
+ // Remember the name of the part. So only need to switch if really necessary.
+ multiPageLibrary = service->library();
+
+ connect(partManager, SIGNAL(activePartChanged(KParts::Part*)), this, SIGNAL(pluginChanged(KParts::Part*)));
+
+ // Switch to the new multiPage
+ partManager->replacePart(oldMultiPage, multiPage);
+
+ delete oldMultiPage;
+
+ // The next line makes the plugin switch much more smooth. Without it the new document
+ // is at first show at a very small zoomlevel before the zoom switches to the right value.
+ // This makes the plugin switching actually slower.
+ // TODO: Get rid of this without causing nasty artifacts.
+ kapp->processEvents();
+ initializeMultiPage();
+ partManager->setActivePart(this);
+
+ // We disconnect because we dont want some FocusEvents to trigger a GUI update, which might mess
+ // with our menus.
+ disconnect(partManager, SIGNAL(activePartChanged(KParts::Part*)), this, SIGNAL(pluginChanged(KParts::Part*)));
+
+ readSettings();
+ }
+
+ // Set the multipage to the current viewmode.
+ multiPage->setViewMode(viewModeAction->currentItem());
+
+ // Load the URL
+ bool r = multiPage->openURL(m_file, m_url);
+ updateZoomLevel(); // @@@@@@@@@@@@@
+
+ // We disable the selection tool for plugins that dont support text.
+ // Currently this is only the fax plugin.
+ if (multiPage->supportsTextSearch())
+ {
+ selectionModeAction->setEnabled(true);
+ }
+ else
+ {
+ selectionModeAction->setEnabled(false);
+ moveModeAction->setChecked(true);
+ }
+ // Switch the new multipage to the right tool
+ slotEnableMoveTool(moveModeAction->isChecked());
+
+ if (r) {
+ // Add the file to the watchlist
+ watch->addFile( m_file );
+
+ // Notify the ViewShell about the newly opened file.
+ emit fileOpened();
+ } else {
+ m_url = QString::null;
+ emit setWindowCaption(QString::null);
+ }
+
+ checkActions();
+ emit zoomChanged(QString("%1%").arg((int)(_zoomVal.value()*100.0+0.5)));
+ emit setStatusBarText(QString::null);
+ return r;
+}
+
+
+void KViewPart::reload()
+{
+ multiPage->reload();
+}
+
+
+void KViewPart::fileChanged(const QString &file)
+{
+ if (file == m_file && watchAct->isChecked())
+ multiPage->reload();
+}
+
+
+bool KViewPart::closeURL_ask()
+{
+ if (multiPage.isNull())
+ return false;
+
+ if (multiPage->isModified() == true) {
+ int ans = KMessageBox::warningContinueCancel( 0,
+ i18n("Your document has been modified. Do you really want to close it?"),
+ i18n("Document Was Modified"), KStdGuiItem::close());
+ if (ans == KMessageBox::Cancel)
+ return false;
+ }
+
+ return closeURL();
+}
+
+
+bool KViewPart::closeURL()
+{
+ if (multiPage.isNull())
+ return false;
+
+ if( watch && !m_file.isEmpty() )
+ watch->removeFile( m_file );
+
+ KParts::ReadOnlyPart::closeURL();
+ multiPage->closeURL();
+ m_url = QString::null;
+ checkActions();
+ emit setWindowCaption("");
+
+ return true;
+}
+
+
+void KViewPart::slotMedia(int id)
+{
+ // If the user has chosen one of the 'known' paper sizes, set the
+ // user requested paper size to that value. Via signals and slots,
+ // this will update the menus, and also the GUI, if necessary.
+ if (id > 1) {
+ userRequestedPaperSize.setPageSize(media->currentText());
+ return;
+ }
+
+ // If the user has chosen "Custom paper size..", show the paper size
+ // dialog. Construct it, if necessary. The paper size dialog will
+ // know the address of userRequestedPaperSize and change this
+ // member, if the user clicks ok/accept. The signal/slot mechanism
+ // will then make sure that the necessary updates in the GUI are
+ // done.
+ if (_pageSizeDialog == 0) {
+ _pageSizeDialog = new pageSizeDialog(mainWidget, &userRequestedPaperSize);
+ if (_pageSizeDialog == 0) {
+ kdError(1223) << "Could not construct the page size dialog!" << endl;
+ return;
+ }
+ }
+
+ // Reset the "preferred paper size" menu. We don't want to have the
+ // "custom paper size" check if the user aborts the dialog.
+ checkActions();
+
+ // Set or update the paper size dialog to show the currently
+ // selected value.
+ _pageSizeDialog->setPageSize(userRequestedPaperSize.serialize());
+ _pageSizeDialog->show();
+}
+
+
+void KViewPart::pageInfo(int numpages, int currentpage)
+{
+ updateZoomLevel();
+
+ // ATTN: The string here must be the same as in setPage() below
+ QString pageString = i18n("Page %1 of %2").arg(currentpage).arg(numpages);
+ if (pageChangeIsConnected) {
+ emit pageChanged(pageString);
+ emit sizeChanged(pageSizeDescription());
+ } else
+ emit setStatusBarText(pageString);
+
+ checkActions();
+}
+
+
+void KViewPart::goToPage()
+{
+ bool ok = false;
+ int p = KInputDialog::getInteger(i18n("Go to Page"), i18n("Page:"),
+ multiPage->currentPageNumber(), 1, multiPage->numberOfPages(),
+ 1 /*step*/, &ok, mainWidget, "gotoDialog");
+ if (ok)
+ multiPage->gotoPage(p);
+}
+
+
+void KViewPart::disableZoomFit()
+{
+ if (fitPageAct -> isChecked())
+ {
+ fitPageAct -> setChecked(false);
+ enableFitToPage(false);
+ }
+ else if(fitWidthAct -> isChecked())
+ {
+ fitWidthAct -> setChecked(false);
+ enableFitToWidth(false);
+ }
+ else if (fitHeightAct -> isChecked())
+ {
+ fitHeightAct -> setChecked(false);
+ enableFitToHeight(false);
+ }
+}
+
+void KViewPart::zoomIn()
+{
+ disableZoomFit();
+
+ float oldVal = _zoomVal.value();
+ float newVal = _zoomVal.zoomIn();
+
+ if (oldVal != newVal)
+ _zoomVal.setZoomValue(multiPage->setZoom(_zoomVal.zoomIn()));
+}
+
+
+void KViewPart::zoomOut()
+{
+ disableZoomFit();
+
+ float oldVal = _zoomVal.value();
+ float newVal = _zoomVal.zoomOut();
+
+ if (oldVal != newVal)
+ _zoomVal.setZoomValue(multiPage->setZoom(_zoomVal.zoomOut()));
+}
+
+void KViewPart::updateZoomLevel()
+{
+ if (fitPageAct->isChecked())
+ {
+ fitToPage();
+ }
+ else if (fitWidthAct->isChecked())
+ {
+ fitToWidth();
+ }
+ else if (fitHeightAct->isChecked())
+ {
+ fitToHeight();
+ }
+ else
+ {
+ // Manuell Zoom
+ }
+}
+
+void KViewPart::enableFitToPage(bool enable)
+{
+ if (enable)
+ {
+ fitToPage();
+ connect(multiPage->mainWidget(), SIGNAL(viewSizeChanged(const QSize&)),
+ this, SLOT(slotStartFitTimer()));
+ connect(&fitTimer, SIGNAL(timeout()), SLOT(fitToPage()));
+ }
+ else
+ {
+ disconnect(multiPage->mainWidget(), SIGNAL(viewSizeChanged(const QSize&)),
+ this, SLOT(slotStartFitTimer()));
+ disconnect(&fitTimer, SIGNAL(timeout()), this, SLOT(fitToPage()));
+ }
+}
+
+void KViewPart::enableFitToWidth(bool enable)
+{
+ if (enable)
+ {
+ fitToWidth();
+ connect(multiPage->mainWidget(), SIGNAL(viewSizeChanged(const QSize&)),
+ this, SLOT(slotStartFitTimer()));
+ connect(&fitTimer, SIGNAL(timeout()), SLOT(fitToWidth()));
+ }
+ else
+ {
+ disconnect(multiPage->mainWidget(), SIGNAL(viewSizeChanged(const QSize&)),
+ this, SLOT(slotStartFitTimer()));
+ disconnect(&fitTimer, SIGNAL(timeout()), this, SLOT(fitToWidth()));
+ }
+}
+
+void KViewPart::enableFitToHeight(bool enable)
+{
+ if (enable)
+ {
+ fitToHeight();
+ connect(multiPage->mainWidget(), SIGNAL(viewSizeChanged(const QSize&)),
+ this, SLOT(slotStartFitTimer()));
+ connect(&fitTimer, SIGNAL(timeout()), SLOT(fitToHeight()));
+ }
+ else
+ {
+ disconnect(multiPage->mainWidget(), SIGNAL(viewSizeChanged(const QSize&)),
+ this, SLOT(slotStartFitTimer()));
+ disconnect(&fitTimer, SIGNAL(timeout()), this, SLOT(fitToHeight()));
+ }
+}
+
+
+void KViewPart::fitToPage()
+{
+ double z = QMIN(multiPage->calculateFitToHeightZoomValue(),
+ multiPage->calculateFitToWidthZoomValue());
+
+ // Check if the methods returned usable values. Values that are not
+ // within the limits indicate that fitting to width or height is
+ // currently not possible (e.g. because no document is
+ // loaded). In that case, we abort.
+ if ((z < ZoomLimits::MinZoom/1000.0) || (z > ZoomLimits::MaxZoom/1000.0))
+ return;
+
+ multiPage->setZoom(z);
+ _zoomVal.setZoomFitPage(z);
+}
+
+
+void KViewPart::fitToHeight()
+{
+ double z = multiPage->calculateFitToHeightZoomValue();
+
+ // Check if the method returned a usable value. Values that are not
+ // within the limits indicate that fitting to height is currently
+ // not possible (e.g. because no document is loaded). In that case,
+ // we abort.
+ if ((z < ZoomLimits::MinZoom/1000.0) || (z > ZoomLimits::MaxZoom/1000.0))
+ return;
+
+ multiPage->setZoom(z);
+ _zoomVal.setZoomFitHeight(z);
+}
+
+
+void KViewPart::fitToWidth()
+{
+ double z = multiPage->calculateFitToWidthZoomValue();
+
+ // Check if the method returned a usable value. Values that are not
+ // within the limits indicate that fitting to width is currently not
+ // possible (e.g. because no document is loaded). In that case, we
+ // abort.
+ if ((z < ZoomLimits::MinZoom/1000.0) || (z > ZoomLimits::MaxZoom/1000.0))
+ return;
+
+ multiPage->setZoom(z);
+ _zoomVal.setZoomFitWidth(z);
+}
+
+
+void KViewPart::setZoomValue(const QString &sval)
+{
+ if (sval == i18n("Fit to Page Width"))
+ {
+ fitWidthAct -> setChecked(true);
+ fitToWidth();
+ }
+ else if (sval == i18n("Fit to Page Height"))
+ {
+ fitHeightAct -> setChecked(true);
+ fitToHeight();
+ }
+ else if (sval == i18n("Fit to Page"))
+ {
+ fitPageAct -> setChecked(true);
+ fitToPage();
+ }
+ else
+ {
+ disableZoomFit();
+
+ float fval = _zoomVal.value();
+ _zoomVal.setZoomValue(sval);
+ if (fval != _zoomVal.value())
+ _zoomVal.setZoomValue(multiPage->setZoom(_zoomVal.value()));
+ }
+
+ mainWidget->setFocus();
+}
+
+
+void KViewPart::checkActions()
+{
+ if (multiPage.isNull())
+ return;
+
+ int currentPage = multiPage->currentPageNumber();
+ int numberOfPages = multiPage->numberOfPages();
+
+ bool doc = !url().isEmpty();
+
+ useDocumentSpecifiedSize->setEnabled(multiPage->hasSpecifiedPageSizes() );
+
+ if (multiPage->overviewMode())
+ {
+ int visiblePages = multiPage->getNrRows() *
+ multiPage->getNrColumns();
+
+ // firstVisiblePage is the smallest currently shown pagenumber.
+ int firstVisiblePage = currentPage - (currentPage % visiblePages);
+
+ backAct->setEnabled(doc && currentPage >= visiblePages);
+ forwardAct->setEnabled(doc && firstVisiblePage <= numberOfPages - visiblePages);
+
+ startAct->setEnabled(doc && firstVisiblePage > 1);
+ endAct->setEnabled(doc && firstVisiblePage + visiblePages < numberOfPages);
+ }
+ else
+ {
+ backAct->setEnabled(doc && currentPage > 1);
+ forwardAct->setEnabled(doc && currentPage < numberOfPages);
+
+ startAct->setEnabled(doc && currentPage > 1);
+ endAct->setEnabled(doc && currentPage < numberOfPages);
+ }
+
+ gotoAct->setEnabled(doc && numberOfPages > 1);
+ readDownAct->setEnabled(doc);
+ readUpAct->setEnabled(doc);
+
+ zoomInAct->setEnabled(doc);
+ zoomOutAct->setEnabled(doc);
+
+ fitPageAct->setEnabled(doc);
+ fitHeightAct->setEnabled(doc);
+ fitWidthAct->setEnabled(doc);
+
+ media->setEnabled(doc);
+ orientation->setEnabled(doc);
+
+ printAction->setEnabled(doc);
+
+ saveAction->setEnabled(multiPage->isModified());
+
+ saveAsAction->setEnabled(doc);
+
+ if (userRequestedPaperSize.formatNumber() != -1) {
+ orientation->setCurrentItem(userRequestedPaperSize.getOrientation());
+ orientation->setEnabled(true);
+ media->setCurrentItem(userRequestedPaperSize.formatNumber()+1);
+ } else {
+ orientation->setEnabled(false);
+ media->setCurrentItem(userRequestedPaperSize.formatNumber()-1);
+ }
+
+ bool textSearch = false;
+ if (doc && multiPage->supportsTextSearch())
+ textSearch = true;
+
+ exportTextAction->setEnabled(textSearch);
+ findTextAction->setEnabled(textSearch);
+ selectAllAction->setEnabled(textSearch);
+}
+
+
+void KViewPart::slotPrint()
+{
+ // TODO: REMOVE THIS METHOD
+ // @@@@@@@@@@@@@@@
+ multiPage->print();
+}
+
+
+void KViewPart::readSettings()
+{
+ showSidebar->setChecked(KVSPrefs::pageMarks());
+ slotShowSidebar();
+
+ watchAct->setChecked(KVSPrefs::watchFile());
+
+ // Read zoom value. Even if 'fitToPage' has been set above, there is
+ // no widget available right now, so setting a good default value
+ // from the configuration file is perhaps not a bad idea.
+ float _zoom = KVSPrefs::zoom();
+ if ( (_zoom < ZoomLimits::MinZoom/1000.0) || (_zoom > ZoomLimits::MaxZoom/1000.0)) {
+ kdWarning(1223) << "Illeagal zoom value of " << _zoom*100.0 << "% found in the preferences file. Setting zoom to 100%." << endl;
+ _zoom = 1.0;
+ }
+ _zoomVal.setZoomValue(multiPage->setZoom(_zoom));
+
+ // The value 'fitToPage' has several meanings: 1 is 'fit to page
+ // width', 2 is 'fit to page height', 3 is 'fit to page'. Other
+ // values indicate 'no fit to page'. Note: at the time this code is
+ // executed, the methods fitToWidth(), etc., do not work well at all
+ // (perhaps some data is not initialized yet)? For that reason, we
+ // do not call these methods, and load the last zoom-value from the
+ // configuration file below. The hope is that this value is not
+ // terribly wrong. If the user doesn't like it, it suffices to
+ // resize the window just a bit...
+ switch(KVSPrefs::fitToPage()) {
+ case KVSPrefs::EnumFitToPage::FitToPage:
+ fitPageAct->setChecked(true);
+ _zoomVal.setZoomFitPage(_zoom);
+ enableFitToPage(true);
+ break;
+ case KVSPrefs::EnumFitToPage::FitToPageWidth:
+ fitWidthAct->setChecked(true);
+ _zoomVal.setZoomFitWidth(_zoom);
+ enableFitToWidth(true);
+ break;
+ case KVSPrefs::EnumFitToPage::FitToPageHeight:
+ fitHeightAct->setChecked(true);
+ _zoomVal.setZoomFitHeight(_zoom);
+ enableFitToHeight(true);
+ break;
+ }
+
+ // Read Paper Size. and orientation. The GUI is updated
+ // automatically by the signals/slots mechanism whenever
+ // userRequestedPaperSize is changed.
+ userRequestedPaperSize.setPageSize(KVSPrefs::paperFormat());
+
+ // Check if scrollbars should be shown.
+ bool sbstatus = KVSPrefs::scrollbars();
+ scrollbarHandling->setChecked(sbstatus);
+ emit scrollbarStatusChanged(sbstatus);
+
+ // Check if document specified paper sizes should be shown. We do
+ // not need to take any action here, because this method is called
+ // only in the constructor of the KViewPart when no document is loaded.
+ useDocumentSpecifiedSize->setChecked(KVSPrefs::useDocumentSpecifiedSize());
+
+ multiPage->readSettings();
+}
+
+
+void KViewPart::writeSettings()
+{
+ KVSPrefs::setPageMarks(showSidebar->isChecked());
+ KVSPrefs::setWatchFile(watchAct->isChecked());
+ KVSPrefs::setZoom(_zoomVal.value());
+ KVSPrefs::setPaperFormat(userRequestedPaperSize.serialize());
+ KVSPrefs::setScrollbars(scrollbarHandling->isChecked());
+ KVSPrefs::setUseDocumentSpecifiedSize(useDocumentSpecifiedSize->isChecked());
+
+ if (!multiPage.isNull())
+ multiPage->writeSettings();
+
+ if (fitPageAct->isChecked())
+ KVSPrefs::setFitToPage(KVSPrefs::EnumFitToPage::FitToPage);
+ else if(fitWidthAct->isChecked())
+ KVSPrefs::setFitToPage(KVSPrefs::EnumFitToPage::FitToPageWidth);
+ else if (fitHeightAct->isChecked())
+ KVSPrefs::setFitToPage(KVSPrefs::EnumFitToPage::FitToPageHeight);
+ else
+ KVSPrefs::setFitToPage(KVSPrefs::EnumFitToPage::DontFit);
+
+ KVSPrefs::writeConfig();
+}
+
+
+void KViewPart::connectNotify ( const char *sig )
+{
+ if (QString(sig).contains("pageChanged"))
+ pageChangeIsConnected = true;
+}
+
+
+void KViewPart::setStatusBarTextFromMultiPage( const QString &msg )
+{
+ if (msg.isEmpty())
+ {
+ if (pageChangeIsConnected)
+ emit setStatusBarText(QString::null);
+ else
+ {
+ int currentPage = multiPage->currentPageNumber();
+ int numberOfPages = multiPage->numberOfPages();
+ emit setStatusBarText(i18n("Page %1 of %2").arg(currentPage).arg(numberOfPages));
+ }
+ }
+ else
+ emit setStatusBarText(msg);
+}
+
+KAboutData* KViewPart::createAboutData()
+{
+ return new KAboutData("kviewerpart", I18N_NOOP("Document Viewer Part"),
+ "0.6", I18N_NOOP(""),
+ KAboutData::License_GPL,
+ I18N_NOOP("Copyright (c) 2005 Wilfried Huss"));
+}
+
+void KViewPart::aboutKViewShell()
+{
+ if (aboutDialog == 0)
+ {
+ // Create Dialog
+ aboutDialog = new KAboutDialog(mainWidget, "about_kviewshell");
+ aboutDialog->setTitle(I18N_NOOP("KViewShell"));
+ aboutDialog->setVersion("0.6");
+ aboutDialog->setAuthor("Matthias Hoelzer-Kluepfel", QString::null, QString::null,
+ I18N_NOOP("Original Author"));
+
+ aboutDialog->addContributor("Matthias Hoelzer-Kluepfel", "mhk@caldera.de", QString::null,
+ I18N_NOOP("Framework"));
+ aboutDialog->addContributor("David Sweet", "dsweet@kde.org", "http://www.chaos.umd.edu/~dsweet",
+ I18N_NOOP("Former KGhostView Maintainer"));
+ aboutDialog->addContributor("Mark Donohoe", QString::null, QString::null,
+ I18N_NOOP("KGhostView Author"));
+ aboutDialog->addContributor("Markku Hihnala", QString::null, QString::null,
+ I18N_NOOP("Navigation widgets"));
+ aboutDialog->addContributor("David Faure", QString::null, QString::null,
+ I18N_NOOP("Basis for shell"));
+ aboutDialog->addContributor("Daniel Duley", QString::null, QString::null,
+ I18N_NOOP("Port to KParts"));
+ aboutDialog->addContributor("Espen Sand", QString::null, QString::null,
+ I18N_NOOP("Dialog boxes"));
+ aboutDialog->addContributor("Stefan Kebekus", "kebekus@kde.org", QString::null,
+ I18N_NOOP("DCOP-Interface, major improvements"));
+ aboutDialog->addContributor("Wilfried Huss", "Wilfried.Huss@gmx.at", QString::null,
+ I18N_NOOP("Interface enhancements"));
+ }
+ aboutDialog->show();
+}
+
+void KViewPart::doSettings()
+{
+ if (KConfigDialog::showDialog("kviewshell_config"))
+ return;
+
+ KConfigDialog* configDialog = new KConfigDialog(mainWidget, "kviewshell_config", KVSPrefs::self());
+
+ optionDialogGUIWidget_base* guiWidget = new optionDialogGUIWidget_base(mainWidget);
+ configDialog->addPage(guiWidget, i18n("User Interface"), "view_choose");
+
+ optionDialogAccessibilityWidget* accWidget = new optionDialogAccessibilityWidget(mainWidget);
+ configDialog->addPage(accWidget, i18n("Accessibility"), "access");
+
+ multiPage->addConfigDialogs(configDialog);
+
+ connect(configDialog, SIGNAL(settingsChanged()), this, SLOT(preferencesChanged()));
+ configDialog->show();
+}
+
+void KViewPart::preferencesChanged()
+{
+ multiPage->preferencesChanged();
+}
+
+void KViewPart::partActivateEvent( KParts::PartActivateEvent *ev )
+{
+ QApplication::sendEvent( multiPage, ev );
+}
+
+
+void KViewPart::guiActivateEvent( KParts::GUIActivateEvent *ev )
+{
+ QApplication::sendEvent( multiPage, ev );
+}
+
+
+void KViewPart::slotEnableMoveTool(bool enable)
+{
+ // Safety Check
+ if (multiPage.isNull())
+ return;
+
+ multiPage->slotEnableMoveTool(enable);
+}
+
+
+KViewPartExtension::KViewPartExtension(KViewPart *parent)
+ : KParts::BrowserExtension( parent, "KViewPartExtension")
+{
+}
+
+
+// KMultiPage Interface
+void KViewPart::mp_prevPage()
+{
+ multiPage->prevPage();
+}
+
+void KViewPart::mp_nextPage()
+{
+ multiPage->nextPage();
+}
+
+void KViewPart::mp_firstPage()
+{
+ multiPage->firstPage();
+}
+
+void KViewPart::mp_lastPage()
+{
+ multiPage->lastPage();
+}
+
+
+void KViewPart::mp_readUp()
+{
+ multiPage->readUp();
+}
+
+void KViewPart::mp_readDown()
+{
+ multiPage->readDown();
+}
+
+
+void KViewPart::mp_scrollUp()
+{
+ multiPage->scrollUp();
+}
+
+void KViewPart::mp_scrollDown()
+{
+ multiPage->scrollDown();
+}
+
+void KViewPart::mp_scrollLeft()
+{
+ multiPage->scrollLeft();
+}
+
+void KViewPart::mp_scrollRight()
+{
+ multiPage->scrollRight();
+}
+
+void KViewPart::mp_scrollUpPage()
+{
+ multiPage->scrollUpPage();
+}
+
+void KViewPart::mp_scrollDownPage()
+{
+ multiPage->scrollDownPage();
+}
+
+void KViewPart::mp_scrollLeftPage()
+{
+ multiPage->scrollLeftPage();
+}
+
+void KViewPart::mp_scrollRightPage()
+{
+ multiPage->scrollRightPage();
+}
+
+
+void KViewPart::mp_slotSave()
+{
+ multiPage->slotSave();
+}
+
+void KViewPart::mp_slotSave_defaultFilename()
+{
+ multiPage->slotSave_defaultFilename();
+}
+
+
+void KViewPart::mp_doGoBack()
+{
+ multiPage->doGoBack();
+}
+
+void KViewPart::mp_doGoForward()
+{
+ multiPage->doGoForward();
+}
+
+
+void KViewPart::mp_showFindTextDialog()
+{
+ multiPage->showFindTextDialog();
+}
+
+void KViewPart::mp_findNextText()
+{
+ multiPage->findNextText();
+}
+
+void KViewPart::mp_findPrevText()
+{
+ multiPage->findPrevText();
+}
+
+void KViewPart::mp_doSelectAll()
+{
+ multiPage->doSelectAll();
+}
+
+void KViewPart::mp_clearSelection()
+{
+ multiPage->clearSelection();
+}
+
+void KViewPart::mp_copyText()
+{
+ multiPage->copyText();
+}
+
+void KViewPart::mp_exportText()
+{
+ multiPage->doExportText();
+}
+
+#include "kviewpart.moc"
+
diff --git a/kviewshell/kviewpart.h b/kviewshell/kviewpart.h
new file mode 100644
index 00000000..f30b1109
--- /dev/null
+++ b/kviewshell/kviewpart.h
@@ -0,0 +1,252 @@
+// -*- C++ -*-
+#ifndef KVIEWPART_H
+#define KVIEWPART_H
+
+#include "kviewpart_iface.h"
+#include "pageSize.h"
+#include "zoom.h"
+
+#include <kparts/browserextension.h>
+#include <qtimer.h>
+
+class KAboutData;
+class KAboutDialog;
+class KAccel;
+class KAction;
+class KConfig;
+class KDirWatch;
+class KInstance;
+class KMultiPage;
+class KRadioAction;
+class KSelectAction;
+class KTempFile;
+class KToggleAction;
+class KURL;
+class KViewPartExtension;
+class QHBoxLayout;
+class pageSizeDialog;
+class QSize;
+
+
+class KViewPart : public KViewPart_Iface
+{
+ Q_OBJECT
+
+public:
+ KViewPart(QWidget *parentWidget, const char *widgetName, QObject *parent,
+ const char *name, const QStringList& args);
+ virtual ~KViewPart();
+
+ static KAboutData* createAboutData();
+
+ bool isValid() { return multiPage; }
+
+ /* This method calls closeURL(), but asks first ("The document was
+ modified. Do you really want to close?") if the document has been
+ modified after it has been loaded. */
+ virtual bool closeURL_ask();
+
+ /* Returns a description of the current page size, for use in the
+ statusbar of the kviewshell that embeds this KViewPart. */
+ QString pageSizeDescription();
+
+ /** Returns a list of mimetypes supported by the installed KViewShell plugins. */
+ virtual QStringList supportedMimeTypes();
+
+signals:
+ void zoomChanged(const QString &);
+ void pageChanged(const QString &);
+ void sizeChanged(const QString &);
+ void scrollbarStatusChanged(bool);
+ void fileOpened();
+
+ void pluginChanged(KParts::Part*);
+
+public slots:
+ void slotSetFullPage(bool fullpage);
+
+ virtual void slotFileOpen();
+ virtual bool closeURL();
+ virtual QStringList fileFormats() const;
+ void setStatusBarTextFromMultiPage(const QString &);
+
+ /** Calling this slot will cause the kmultipage to reload the file */
+ void reload();
+
+ void restoreDocument(const KURL &url, int page);
+ void saveDocumentRestoreInfo(KConfig* config);
+
+protected slots:
+ void slotShowSidebar();
+ void slotMedia (int);
+
+ void goToPage();
+
+ void zoomIn();
+ void zoomOut();
+
+ void disableZoomFit();
+ void updateZoomLevel();
+
+ void enableFitToPage(bool);
+ void enableFitToHeight(bool);
+ void enableFitToWidth(bool);
+
+ void fitToPage();
+ void fitToHeight();
+ void fitToWidth();
+
+ void slotPrint();
+
+ void fileChanged(const QString&);
+
+ // Connected to the QLineEdit in the toolbar.
+ void setZoomValue(const QString &);
+
+
+protected:
+ KToggleAction *showSidebar, *scrollbarHandling;
+ KSelectAction *orientation, *media, *zoom_action;
+
+ virtual bool openFile();
+
+ void connectNotify ( const char * );
+
+ void partActivateEvent( KParts::PartActivateEvent *ev );
+ void guiActivateEvent( KParts::GUIActivateEvent *ev );
+
+private slots:
+ void pageInfo(int numpages, int currentpage);
+ void checkActions();
+
+ void slotStartFitTimer();
+
+ void doSettings();
+ void preferencesChanged();
+
+ void aboutKViewShell();
+
+ void slotEnableMoveTool(bool enable);
+
+ // Relay signals to the multipage. We cannot connect to the
+ // slots of the multipage directly because than we would have
+ // to recreate the whole interface whenever a new multipage is loaded.
+ void mp_prevPage();
+ void mp_nextPage();
+ void mp_firstPage();
+ void mp_lastPage();
+
+ void mp_readUp();
+ void mp_readDown();
+
+ void mp_scrollUp();
+ void mp_scrollDown();
+ void mp_scrollLeft();
+ void mp_scrollRight();
+ void mp_scrollUpPage();
+ void mp_scrollDownPage();
+ void mp_scrollLeftPage();
+ void mp_scrollRightPage();
+
+ void mp_slotSave();
+ void mp_slotSave_defaultFilename();
+
+ void mp_doGoBack();
+ void mp_doGoForward();
+
+ void mp_showFindTextDialog();
+ void mp_findNextText();
+ void mp_findPrevText();
+
+ void mp_doSelectAll();
+ void mp_clearSelection();
+
+ void mp_copyText();
+
+ void mp_exportText();
+
+private:
+ void initializeMultiPage();
+
+ // This method reads the configuration file. It should only be
+ // called when no document is loaded.
+ void readSettings();
+ void writeSettings();
+
+ // The method openFile of this kviewpart can be called even if
+ // m_file points to a compressed file. In that case, the temporary
+ // file tmpUnzipped will be created and a decompressed copy of the
+ // file stored there.
+ KTempFile *tmpUnzipped;
+
+ KDirWatch *watch;
+ KAccel *accel;
+ KAction *zoomInAct, *zoomOutAct, *backAct, *forwardAct,
+ *startAct, *endAct, *gotoAct,
+ *saveAction, *saveAsAction, *printAction, *readUpAct, *readDownAct;
+ KAction *backAction;
+ KAction *forwardAction;
+ KAction *settingsAction;
+ KAction* aboutAction;
+ KToggleAction *watchAct,*useDocumentSpecifiedSize,
+ *fitPageAct, *fitHeightAct, *fitWidthAct;
+ KSelectAction* viewModeAction;
+
+ KRadioAction* moveModeAction;
+ KRadioAction* selectionModeAction;
+
+ KAction* exportTextAction;
+
+ KAction* copyTextAction;
+ KAction* selectAllAction;
+ KAction* deselectAction;
+ KAction* findTextAction;
+ KAction* findNextTextAction;
+ KAction* findPrevAction;
+ KAction* findNextAction;
+
+ KParts::PartManager* partManager;
+
+ QGuardedPtr<KMultiPage> multiPage;
+ // Name of the library of the currently loaded multiPage.
+ // Is used to check if it is really necessary to load a new MultiPage.
+ QString multiPageLibrary;
+
+ KViewPartExtension *m_extension;
+
+ bool pageChangeIsConnected;
+
+ QWidget *mainWidget;
+ QHBoxLayout* mainLayout;
+
+ /** This entry stores the paper size that the user has requested in
+ the preferences dialog. If that paper size is actually used or
+ not, depends on if the document specifies a paper size of its
+ own and if the user has chosen the option "use document
+ specified paper size if available" */
+ pageSize userRequestedPaperSize;
+
+ /** stores the current zoom value */
+ Zoom _zoomVal;
+ pageSizeDialog *_pageSizeDialog;
+
+ QTimer fitTimer;
+
+ KAboutDialog* aboutDialog;
+};
+
+
+class KViewPartExtension : public KParts::BrowserExtension
+{
+ Q_OBJECT
+ friend class KViewPart;
+
+public:
+
+ KViewPartExtension(KViewPart *parent);
+ virtual ~KViewPartExtension() {}
+
+};
+
+
+#endif
diff --git a/kviewshell/kviewpart_iface.cpp b/kviewshell/kviewpart_iface.cpp
new file mode 100644
index 00000000..b55f7ac1
--- /dev/null
+++ b/kviewshell/kviewpart_iface.cpp
@@ -0,0 +1,4 @@
+#include <config.h>
+
+#include "kviewpart_iface.h"
+#include "kviewpart_iface.moc"
diff --git a/kviewshell/kviewpart_iface.h b/kviewshell/kviewpart_iface.h
new file mode 100644
index 00000000..9e488f3e
--- /dev/null
+++ b/kviewshell/kviewpart_iface.h
@@ -0,0 +1,35 @@
+// -*- C++ -*-
+#ifndef KVIEWPART_IFACE_H
+#define KVIEWPART_IFACE_H
+
+#include <kparts/part.h>
+
+class QStringList;
+
+
+class KViewPart_Iface : public KParts::ReadOnlyPart
+{
+ Q_OBJECT
+public:
+ KViewPart_Iface(QObject *parent, const char *name)
+ : KParts::ReadOnlyPart(parent, name) {}
+
+ virtual ~KViewPart_Iface() {}
+
+ /* Returns a description of the current page size, for use in the
+ statusbar of the kviewshell that embeds this KViewPart. */
+ virtual QString pageSizeDescription() = 0;
+
+ /* This method calls closeURL(), but asks first ("The document was
+ modified. Do you really want to close?") if the document has been
+ modified after it has been loaded. */
+ virtual bool closeURL_ask() = 0;
+
+ virtual QStringList supportedMimeTypes() = 0;
+
+public slots:
+ virtual void slotSetFullPage(bool fullpage) = 0;
+ virtual QStringList fileFormats() const = 0;
+};
+
+#endif
diff --git a/kviewshell/kviewshell.cpp b/kviewshell/kviewshell.cpp
new file mode 100644
index 00000000..90e1e474
--- /dev/null
+++ b/kviewshell/kviewshell.cpp
@@ -0,0 +1,384 @@
+/*
+ * Parts of this file are
+ * Copyright 2003 Waldo Bastian <bastian@kde.org>
+ *
+ * These parts are free software; you can redistribute and/or modify
+ * them under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2.
+ */
+
+
+#include <qfileinfo.h>
+#include <qtimer.h>
+#include <qregexp.h>
+
+#include <kiconloader.h>
+#include <kstandarddirs.h>
+#include <kapplication.h>
+#include <kaction.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kmenubar.h>
+#include <klibloader.h>
+#include <kstdaction.h>
+#include <kedittoolbar.h>
+#include <kurldrag.h>
+#include <kparts/partmanager.h>
+#include <kmimetype.h>
+
+#include <kprogress.h>
+#include <qlabel.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "kviewpart_iface.h"
+#include <kstatusbar.h>
+#include <kkeydialog.h>
+#include "kviewshell.moc"
+
+
+#define StatusBar_ID_PageNr 1
+#define StatusBar_ID_PageSize 2
+#define StatusBar_ID_Zoom 3
+
+
+KViewShell::KViewShell(const QString& defaultMimeType)
+ : KParts::MainWindow()
+{
+ // create the viewer part
+
+ // Try to load
+ KLibFactory *factory = KLibLoader::self()->factory("kviewerpart");
+ if (factory) {
+ if (defaultMimeType == QString::null)
+ {
+ view = (KViewPart_Iface*) factory->create(this, "kviewerpart", "KViewPart");
+ }
+ else
+ {
+ QStringList args;
+ args << defaultMimeType;
+ view = (KViewPart_Iface*) factory->create(this, "kviewerpart", "KViewPart", args);
+ }
+ if (!view)
+ ::exit(-1);
+ } else {
+ KMessageBox::error(this, i18n("No viewing component found"));
+ ::exit(-1);
+ }
+
+ setCentralWidget(view->widget());
+
+ // file menu
+ KStdAction::open(view, SLOT(slotFileOpen()), actionCollection());
+ recent = KStdAction::openRecent (this, SLOT(openURL(const KURL &)), actionCollection());
+ reloadAction = new KAction(i18n("Reload"), "reload", CTRL + Key_R, view, SLOT(reload()), actionCollection(), "reload");
+ closeAction = KStdAction::close(this, SLOT(slotFileClose()), actionCollection());
+ KStdAction::quit (this, SLOT(slotQuit()), actionCollection());
+
+ connect(view, SIGNAL(fileOpened()), this, SLOT(addRecentFile()));
+
+ // view menu
+ fullScreenAction = KStdAction::fullScreen(this, SLOT(slotFullScreen()), actionCollection(), this, "fullscreen" );
+
+ // settings menu
+ createStandardStatusBarAction();
+
+ setStandardToolBarMenuEnabled(true);
+
+ KStdAction::keyBindings(this, SLOT(slotConfigureKeys()), actionCollection());
+ KStdAction::configureToolbars(this, SLOT(slotEditToolbar()), actionCollection());
+
+ // statusbar connects
+ connect( view, SIGNAL( zoomChanged(const QString &) ), this,SLOT( slotChangeZoomText(const QString &) ) );
+ connect( view, SIGNAL( pageChanged(const QString &) ), this,SLOT( slotChangePageText(const QString &) ) );
+ connect( view, SIGNAL( sizeChanged(const QString &) ), this,SLOT( slotChangeSizeText(const QString &) ) );
+
+ // Setup session management
+ connect( this, SIGNAL( restoreDocument(const KURL &, int) ), view, SLOT( restoreDocument(const KURL &, int)));
+ connect( this, SIGNAL( saveDocumentRestoreInfo(KConfig*) ), view, SLOT( saveDocumentRestoreInfo(KConfig*)));
+
+ setXMLFile( "kviewshell.rc" );
+ createGUI(view);
+ readSettings();
+ checkActions();
+ setAcceptDrops(true);
+
+ // If kviewshell is started when another instance of kviewshell runs
+ // in fullscreen mode, the menubar is switched off by default, which
+ // is a nasty surprise for the user: there is no way to access the
+ // menus. To avoid such complications, we switch the menubar on
+ // explicitly.
+ menuBar()->show();
+
+ // Add statusbar-widgets for zoom, pagenr and format
+ statusBar()->insertItem("", StatusBar_ID_PageNr, 0, true);
+ statusBar()->insertFixedItem("XXXX%", StatusBar_ID_Zoom, true);
+ statusBar()->changeItem("", StatusBar_ID_Zoom);
+ statusBar()->insertItem(view->pageSizeDescription(), StatusBar_ID_PageSize, 0, true);
+
+ connect( view, SIGNAL(pluginChanged(KParts::Part*)), this, SLOT(createGUI(KParts::Part*)));
+}
+
+
+void KViewShell::checkActions()
+{
+ bool doc = !view->url().isEmpty();
+
+ closeAction->setEnabled(doc);
+ reloadAction->setEnabled(doc);
+ fullScreenAction->setEnabled(doc);
+}
+
+
+KViewShell::~KViewShell()
+{
+ writeSettings();
+ delete view;
+}
+
+
+void KViewShell::slotQuit()
+{
+ // If we are to quit the application while we operate in fullscreen
+ // mode, we need to restore the visibility properties of the
+ // statusbar, toolbar and the menus because these properties are
+ // saved automatically ... and we don't want to start next time
+ // without having menus.
+ if (fullScreenAction->isChecked()) {
+ kdDebug() << "Switching off fullscreen mode before quitting the application" << endl;
+ showNormal();
+ if (isStatusBarShownInNormalMode)
+ statusBar()->show();
+ if (isToolBarShownInNormalMode)
+ toolBar()->show();
+ menuBar()->show();
+ view->slotSetFullPage(false);
+ }
+ kapp->closeAllWindows();
+ kapp->quit();
+}
+
+
+void KViewShell::readSettings()
+{
+ resize(600, 300); // default size if the config file specifies no size
+ setAutoSaveSettings( "General" ); // apply mainwindow settings (size, toolbars, etc.)
+
+ KConfig *config = kapp->config();
+ config->setGroup("General");
+
+ recent->loadEntries(config, "Recent Files");
+
+ // Constant source of annoyance in KDVI < 1.0: the 'recent-files'
+ // menu contains lots of files which don't exist (any longer). Thus,
+ // we'll sort out the non-existent files here.
+ QStringList items = recent->items();
+ for ( QStringList::Iterator it = items.begin(); it != items.end(); ++it ) {
+ KURL url(*it);
+ if (url.isLocalFile()) {
+ QFileInfo info(url.path());
+ if (!info.exists())
+ recent->removeURL(url);
+ }
+ }
+
+}
+
+
+void KViewShell::writeSettings()
+{
+ KConfig *config = kapp->config();
+ config->setGroup( "General" );
+ recent->saveEntries(config, "Recent Files");
+
+ config->sync();
+}
+
+
+void KViewShell::saveProperties(KConfig* config)
+{
+ // the 'config' object points to the session managed
+ // config file. anything you write here will be available
+ // later when this app is restored
+ emit saveDocumentRestoreInfo(config);
+}
+
+
+void KViewShell::readProperties(KConfig* config)
+{
+ // the 'config' object points to the session managed
+ // config file. this function is automatically called whenever
+ // the app is being restored. read in here whatever you wrote
+ // in 'saveProperties'
+ if (view)
+ {
+ KURL url (config->readPathEntry("URL"));
+ if (url.isValid())
+ emit restoreDocument(url, config->readNumEntry("Page", 1));
+ }
+}
+
+
+void KViewShell::addRecentFile()
+{
+ // Get the URL of the opened file from the kviewpart.
+ KURL actualURL = view->url();
+ // To store the URL in the list of recent files, we remove the
+ // reference part.
+ actualURL.setRef(QString::null);
+ recent->addURL(actualURL);
+ checkActions();
+}
+
+void KViewShell::openURL(const KURL& url)
+{
+ view->openURL(url);
+}
+
+void KViewShell::slotFullScreen()
+{
+ if (fullScreenAction->isChecked()) {
+ // In fullscreen mode, menu- tool- and statusbar are hidden. Save
+ // the visibility flags of these objects here, so that they can
+ // later be properly restored when we switch back to normal mode,
+ // or before we leave the application in slotQuit()
+ isStatusBarShownInNormalMode = statusBar()->isShown();
+ statusBar()->hide();
+ isToolBarShownInNormalMode = toolBar()->isShown();
+ toolBar()->hide();
+ menuBar()->hide();
+ view->slotSetFullPage(true);
+
+ // Go to fullscreen mode
+ showFullScreen();
+
+ KMessageBox::information(this, i18n("Use the Escape key to leave the fullscreen mode."), i18n("Entering Fullscreen Mode"), "leavingFullScreen");
+ } else {
+ showNormal();
+ if (isStatusBarShownInNormalMode)
+ statusBar()->show();
+ if (isToolBarShownInNormalMode)
+ toolBar()->show();
+ menuBar()->show();
+ view->slotSetFullPage(false);
+ }
+}
+
+
+void KViewShell::slotFileClose()
+{
+ view->closeURL_ask();
+
+ checkActions();
+}
+
+void KViewShell::slotConfigureKeys()
+{
+ KKeyDialog dlg( true, this );
+
+ dlg.insert( actionCollection() );
+ dlg.insert( view->actionCollection() );
+
+ dlg.configure();
+}
+
+void KViewShell::slotEditToolbar()
+{
+ saveMainWindowSettings( KGlobal::config(), autoSaveGroup() );
+ KEditToolbar dlg(factory());
+ connect( &dlg, SIGNAL( newToolbarConfig() ), SLOT( slotNewToolbarConfig() ) );
+ dlg.exec();
+}
+
+
+void KViewShell::slotNewToolbarConfig()
+{
+ applyMainWindowSettings( KGlobal::config(), autoSaveGroup() );
+}
+
+void KViewShell::dragEnterEvent(QDragEnterEvent *event)
+{
+ if (KURLDrag::canDecode(event))
+ {
+ KURL::List urls;
+ KURLDrag::decode(event, urls);
+ if (!urls.isEmpty())
+ {
+ KURL url = urls.first();
+
+ // Always try to open remote files
+ if (!url.isLocalFile())
+ {
+ event->accept();
+ return;
+ }
+
+ // For local files we only accept a drop, if we have a plugin for its
+ // particular mimetype
+ KMimeType::Ptr mimetype = KMimeType::findByURL(url);
+ kdDebug() << "[dragEnterEvent] Dragged URL is of type " << mimetype->comment() << endl;
+
+ // Safety check
+ if (view)
+ {
+ QStringList mimetypeList = view->supportedMimeTypes();
+ kdDebug() << "[dragEnterEvent] Supported mime types: " << mimetypeList << endl;
+
+ for (QStringList::Iterator it = mimetypeList.begin(); it != mimetypeList.end(); ++it)
+ {
+ if (mimetype->is(*it))
+ {
+ kdDebug() << "[dragEnterEvent] Found matching mimetype: " << *it << endl;
+ event->accept();
+ return;
+ }
+ }
+ kdDebug() << "[dragEnterEvent] no matching mimetype found" << endl;
+ }
+ }
+ event->ignore();
+ }
+}
+
+
+void KViewShell::dropEvent(QDropEvent *event)
+{
+ KURL::List urls;
+ if (KURLDrag::decode(event, urls) && !urls.isEmpty())
+ view->openURL(urls.first());
+}
+
+
+void KViewShell::keyPressEvent(QKeyEvent *event)
+{
+ // The Escape Key is used to return to normal mode from fullscreen
+ // mode
+ if ((event->key() == Qt::Key_Escape) && (fullScreenAction->isChecked())) {
+ showNormal();
+ return;
+ }
+ // If we can't use the key event, pass it on
+ event->ignore();
+}
+
+
+void KViewShell::slotChangePageText(const QString &message)
+{
+ statusBar()->changeItem(" "+message+" ",StatusBar_ID_PageNr);
+}
+
+
+void KViewShell::slotChangeSizeText(const QString &message)
+{
+ statusBar()->changeItem(" "+message+" ",StatusBar_ID_PageSize);
+}
+
+
+void KViewShell::slotChangeZoomText(const QString &message)
+{
+ statusBar()->changeItem(" "+message+" ",StatusBar_ID_Zoom);
+}
diff --git a/kviewshell/kviewshell.h b/kviewshell/kviewshell.h
new file mode 100644
index 00000000..c6aa0620
--- /dev/null
+++ b/kviewshell/kviewshell.h
@@ -0,0 +1,89 @@
+// -*- C++ -*-
+#ifndef KVIEWSHELL_H
+#define KVIEWSHELL_H
+
+#include <qstring.h>
+
+#include <kparts/mainwindow.h>
+
+class KRecentFilesAction;
+class KURL;
+class KViewPart_Iface;
+
+
+class QLabel;
+
+class KViewShell : public KParts::MainWindow
+{
+ Q_OBJECT
+
+public:
+ KStatusBar *statusbar;
+ KStatusBar *action;
+
+ KViewShell(const QString& defaultMimeType = QString::null);
+ virtual ~KViewShell();
+
+public slots:
+ void openURL(const KURL&);
+ void addRecentFile();
+
+
+protected slots:
+ void slotFullScreen();
+ void slotQuit();
+ void slotConfigureKeys();
+ void slotEditToolbar();
+ void slotFileClose();
+ void slotNewToolbarConfig();
+
+ void slotChangeZoomText(const QString &);
+ void slotChangePageText(const QString &);
+ void slotChangeSizeText(const QString &);
+
+signals:
+ void restoreDocument(const KURL &url, int page);
+ void saveDocumentRestoreInfo(KConfig* config);
+
+protected:
+ void readSettings();
+ void writeSettings();
+
+ /**
+ * This method is called when it is time for the app to save its
+ * properties for session management purposes.
+ */
+ void saveProperties(KConfig*);
+
+ /**
+ * This method is called when this app is restored. The KConfig
+ * object points to the session management config file that was saved
+ * with @ref saveProperties
+ */
+ void readProperties(KConfig*);
+
+ void checkActions();
+
+ void dragEnterEvent(QDragEnterEvent *event);
+ void dropEvent(QDropEvent *event);
+ void keyPressEvent(QKeyEvent * e);
+
+private:
+ KViewPart_Iface *view;
+
+ KRecentFilesAction *recent;
+ QString cwd;
+
+ KAction *closeAction, *reloadAction;
+ KToggleAction *fullScreenAction;
+
+ // In the attribute, the status of the statusbar (shown of hidden)
+ // is saved when the kviewshell switches to fullscreen mode. The
+ // statusbar can then be restored when the application returns to normal mode.
+ bool isStatusBarShownInNormalMode;
+ // ditto, for the toolbar
+ bool isToolBarShownInNormalMode;
+};
+
+
+#endif
diff --git a/kviewshell/kviewshell.kcfg b/kviewshell/kviewshell.kcfg
new file mode 100644
index 00000000..3114929c
--- /dev/null
+++ b/kviewshell/kviewshell.kcfg
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="kviewerpartrc" />
+ <group name="GUI" >
+ <entry key="PageMarks" type="Bool">
+ <default>true</default>
+ </entry>
+ <entry key="WatchFile" type="Bool">
+ <default>true</default>
+ </entry>
+ <entry key="Zoom" type="Double">
+ <default>1.0</default>
+ </entry>
+ <entry key="PaperFormat" type="String">
+ <default></default>
+ </entry>
+ <entry key="Scrollbars" type="Bool">
+ <default>true</default>
+ </entry>
+ <entry key="UseDocumentSpecifiedSize" type="Bool">
+ <default>true</default>
+ </entry>
+ <entry key="ViewMode" type="Enum">
+ <default>Continuous</default>
+ <choices>
+ <choice name="SinglePage" />
+ <choice name="Continuous" />
+ <choice name="ContinuousFacing" />
+ <choice name="Overview" />
+ </choices>
+ </entry>
+ <entry key="FitToPage" type="Enum">
+ <default>DontFit</default>
+ <choices>
+ <choice name="FitToPage" />
+ <choice name="FitToPageWidth" />
+ <choice name="FitToPageHeight" />
+ <choice name="DontFit" />
+ </choices>
+ </entry>
+ <entry key="OverviewModeColumns" type="Int">
+ <default>4</default>
+ </entry>
+ <entry key="OverviewModeRows" type="Int">
+ <default>2</default>
+ </entry>
+ <entry key="ShowThumbnails" type="Bool">
+ <default>true</default>
+ </entry>
+ <entry key="MaxThumbnailWidth" type="Int">
+ <default>200</default>
+ </entry>
+ <entry key="UnderlineLinks" type="Enum">
+ <default>Enabled</default>
+ <choices>
+ <choice name="Enabled" />
+ <choice name="Disabled" />
+ <choice name="OnlyOnHover" />
+ </choices>
+ <whatsthis>
+ &lt;qt&gt;
+ Controls how hyperlinks are underlined:
+ &lt;ul&gt;
+ &lt;li&gt;&lt;b&gt;UL_Enabled&lt;/b&gt;: Always underline links&lt;/li&gt;
+ &lt;li&gt;&lt;b&gt;UL_Disabled&lt;/b&gt;: Never underline links&lt;/li&gt;
+ &lt;li&gt;&lt;b&gt;UL_OnlyOnHover&lt;/b&gt;: Underline when the mouse is moved over the link&lt;/li&gt;
+ &lt;/ul&gt;
+ &lt;/qt&gt;
+ </whatsthis>
+ </entry>
+ <entry key="GuiLayout" type="IntList" />
+ <entry key="SideBarItem" type="Int">
+ <default>1</default>
+ </entry>
+ </group>
+ <group name="Accessibility" >
+ <entry key="PaperColor" type="Color" >
+ <default code="true" >Qt::white</default>
+ </entry>
+ <entry key="ChangeColors" type="Bool" >
+ <default>false</default>
+ </entry>
+ <entry key="RenderMode" type="Enum" >
+ <default>Inverted</default>
+ <choices>
+ <choice name="Inverted" />
+ <choice name="Paper" />
+ <choice name="pad_paper_color" />
+ <choice name="Recolor" />
+ <choice name="pad_fg_color" />
+ <choice name="pad_bg_color" />
+ <choice name="BlackWhite" />
+ </choices>
+ </entry>
+ <entry key="RecolorForeground" type="Color" >
+ <default code="true" >0x600000</default>
+ </entry>
+ <entry key="RecolorBackground" type="Color" >
+ <default code="true" >0xF0F0F0</default>
+ </entry>
+ <entry key="BWThreshold" type="UInt" >
+ <default>127</default>
+ <min>2</min>
+ <max>253</max>
+ </entry>
+ <entry key="BWContrast" type="UInt" >
+ <default>2</default>
+ <min>2</min>
+ <max>6</max>
+ </entry>
+ </group>
+</kcfg>
diff --git a/kviewshell/kviewshell.rc b/kviewshell/kviewshell.rc
new file mode 100644
index 00000000..480a868a
--- /dev/null
+++ b/kviewshell/kviewshell.rc
@@ -0,0 +1,37 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="KViewShell" version="5">
+<MenuBar>
+ <Menu name="file"><text>&amp;File</text>
+ <Action name="reload" append="open_merge" />
+ <DefineGroup name="save_merge" append="save_merge" />
+ <DefineGroup name="info_merge" append="save_merge"/>
+ <DefineGroup name="print_merge" append="save_merge" />
+ </Menu>
+ <Menu name="edit"><text>&amp;Edit</text>
+ <DefineGroup name="tools_merge"/>
+ </Menu>
+ <Menu name="view"><text>&amp;View</text>
+ <DefineGroup name="view_top"/>
+ </Menu>
+ <Menu name="go"><text>&amp;Go</text>
+ <DefineGroup name="go_top"/>
+ </Menu>
+ <Merge/>
+ <Menu name="settings"><text>&amp;Settings</text>
+ <DefineGroup name="settings_top" append="show_merge"/>
+ <Separator append="show_merge"/>
+ <DefineGroup name="additional_settings_merge" append="show_merge"/>
+ <DefineGroup name="configure_merge" append="configure_merge" />
+ <Merge/>
+ </Menu>
+ <Menu name="help"><text>&amp;Help</text>
+ <DefineGroup name="help_top"/>
+ <DefineGroup name="help_about"/>
+ </Menu>
+</MenuBar>
+<ToolBar name="mainToolBar">
+ <Action name="reload"/>
+</ToolBar>
+<StatusBar/>
+</kpartgui>
+
diff --git a/kviewshell/kvsprefs.kcfgc b/kviewshell/kvsprefs.kcfgc
new file mode 100644
index 00000000..c507ba3d
--- /dev/null
+++ b/kviewshell/kvsprefs.kcfgc
@@ -0,0 +1,5 @@
+# Code generation options for kconfig_compiler
+File=kviewshell.kcfg
+ClassName=KVSPrefs
+Singleton=true
+Mutators=true
diff --git a/kviewshell/length.h b/kviewshell/length.h
new file mode 100644
index 00000000..149c8a10
--- /dev/null
+++ b/kviewshell/length.h
@@ -0,0 +1,173 @@
+// -*- C++ -*-
+//
+// Class: length
+//
+// Part of KVIESHELL
+//
+// (C) 2005 Stefan Kebekus. Distributed under the GPL.
+
+
+#ifndef _length_h_
+#define _length_h_
+
+#define mm_per_cm 10.0
+#define mm_per_m 1000.0
+#define mm_per_inch 25.4
+#define mm_per_TeXPoint (2540.0/7227.0)
+#define mm_per_bigPoint (25.4/72.0)
+#define mm_per_pica (25.4/6.0)
+#define mm_per_didot (25.4*0.0148)
+#define mm_per_cicero (25.4*0.178)
+#define mm_per_scaledPoint (25.4/(72.27 * 65536.0))
+
+
+#include <math.h>
+
+/** @short Represents a phyical length
+
+ This class is used to represent a physical length. Its main purpose
+ it to help in the conversion of units, and to avoid confusion
+ about units. To avoid misunderstandings, there is no default
+ constructor so that this class needs to be explicitly initialized
+ with one of the functions below.
+
+ @warning Lengths are stored internally in mm. If you convert to
+ or from any other unit, expect floating point round-off errors.
+
+ @author Stefan Kebekus <kebekus@kde.org>
+ @version 1.0.0
+*/
+
+class Length
+{
+ public:
+ /** constructs a 'length = 0mm' object */
+ Length() {length_in_mm = 0;}
+
+ /** sets the length in millimeters */
+ void setLength_in_mm(double l) {length_in_mm = l;}
+
+ /** sets the length in centimeters */
+ void setLength_in_cm(double l) {length_in_mm = l*mm_per_cm;}
+
+ /** sets the length in meters */
+ void setLength_in_m(double l) {length_in_mm = l*mm_per_m;}
+
+ /** sets the length in inches */
+ void setLength_in_inch(double l) {length_in_mm = l*mm_per_inch;}
+
+ /** sets the length in TeX points */
+ void setLength_in_TeXPoints(double l) {length_in_mm = l*mm_per_TeXPoint;}
+
+ /** sets the length in big points (1/72 of an inch) */
+ void setLength_in_bigPoints(double l) {length_in_mm = l*mm_per_bigPoint;}
+
+ /** sets the length in picas (1/6 of an inch) */
+ void setLength_in_pica(double l) {length_in_mm = l*mm_per_pica;}
+
+ /** sets the length in didots (0.0148 inches) */
+ void setLength_in_didot(double l) {length_in_mm = l*mm_per_didot;}
+
+ /** sets the length in ciceros (0.178 inches) */
+ void setLength_in_cicero(double l) {length_in_mm = l*mm_per_cicero;}
+
+ /** sets the length in scaled points (1 scaled point = 65536 TeX points) */
+ void setLength_in_scaledPoints(double l) {length_in_mm = l*mm_per_scaledPoint;}
+
+
+ /** returns the length in millimeters */
+ double getLength_in_mm() const {return length_in_mm;}
+
+ /** returns the length in centimeters */
+ double getLength_in_cm() const {return length_in_mm/mm_per_cm;}
+
+ /** returns the length in meters */
+ double getLength_in_m() const {return length_in_mm/mm_per_m;}
+
+ /** returns the length in inches */
+ double getLength_in_inch() const {return length_in_mm/mm_per_inch;}
+
+ /** returns the length in TeX points */
+ double getLength_in_TeXPoints() const {return length_in_mm/mm_per_TeXPoint;}
+
+ /** returns the length in big points (1/72 of an inch) */
+ double getLength_in_bigPoints() const {return length_in_mm/mm_per_bigPoint;}
+
+ /** returns the length in picas (1/6 of an inch) */
+ double getLength_in_pica() const {return length_in_mm/mm_per_pica;}
+
+ /** returns the length in didots (0.0148 inches) */
+ double getLength_in_didot() const {return length_in_mm/mm_per_didot;}
+
+ /** returns the length in ciceros (0.178 inches) */
+ double getLength_in_cicero() const {return length_in_mm/mm_per_cicero;}
+
+ /** returns the length in scaled points (1 scaled point = 65536 TeX points) */
+ double getLength_in_scaledPoints() const {return length_in_mm/mm_per_scaledPoint;}
+
+ /** returns true is lengths differ by no more than 2mm */
+ bool isNearlyEqual(const Length &o) const {return fabs(length_in_mm-o.getLength_in_mm()) <= 2.0;}
+
+ /** Comparison of two lengthes */
+ bool operator > (const Length &o) const {return (length_in_mm > o.getLength_in_mm());}
+ bool operator < (const Length &o) const {return (length_in_mm < o.getLength_in_mm());}
+
+ /** Comparison of two lengthes */
+ bool operator >= (const Length &o) const {return (length_in_mm >= o.getLength_in_mm());}
+ bool operator <= (const Length &o) const {return (length_in_mm <= o.getLength_in_mm());}
+
+ /** Ratio of two lengthes
+
+ @warning There is no safeguared to prevent you from division by
+ zero. If the length in the denominator is near 0.0, a floating point
+ exception may occur.
+
+ @returns the ratio of the two lengthes as a double
+ */
+ double operator / (const Length &o) const {return (length_in_mm/o.getLength_in_mm());}
+
+ /** Sum of two lengthes
+
+ @returns the sum of the lengthes as a Length
+ */
+ Length operator + (const Length &o) const {Length r; r.length_in_mm = length_in_mm + o.length_in_mm; return r; }
+
+ /** Difference of two lengthes
+
+ @returns the difference of the lengthes as a Length
+ */
+ Length operator - (const Length &o) const {Length r; r.length_in_mm = length_in_mm - o.length_in_mm; return r; }
+
+ /** Division of a length
+
+ @warning There is no safeguared to prevent you from division by
+ zero. If the number in the denominator is near 0.0, a floating point
+ exception may occur.
+
+ @returns a fraction of the original length as a Length
+ */
+ Length operator / (const double l) const {Length r; r.length_in_mm = length_in_mm/l; return r; }
+
+ /** Multiplication of a length
+
+ @returns a multiplied length as a Length
+ */
+ Length operator * (const double l) const {Length r; r.length_in_mm = length_in_mm*l; return r; }
+
+ private:
+ /** Length in millimeters */
+ double length_in_mm;
+};
+
+#undef mm_per_cm
+#undef mm_per_m
+#undef mm_per_inch
+#undef mm_per_TeXPoint
+#undef mm_per_bigPoint
+#undef mm_per_pica
+#undef mm_per_didot
+#undef mm_per_cicero
+#undef mm_per_scaledPoint
+
+
+#endif
diff --git a/kviewshell/main.cpp b/kviewshell/main.cpp
new file mode 100644
index 00000000..c87cb07e
--- /dev/null
+++ b/kviewshell/main.cpp
@@ -0,0 +1,184 @@
+#include <config.h>
+
+#include <dcopclient.h>
+#include <dcopref.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kdebug.h>
+#include <kmimetype.h>
+#include <kurl.h>
+#include <klocale.h>
+#include <kaboutdata.h>
+#include <qdir.h>
+
+#include <stdlib.h>
+
+#include "kviewshell.h"
+
+
+static KCmdLineOptions options[] =
+{
+ { "u", 0, 0},
+ { "unique", I18N_NOOP("Check if the file is loaded in another kviewshell.\nIf it is, bring up the other kviewshell. Otherwise, load the file."), 0 },
+ { "m", 0, 0},
+ { "mimetype <mimetype>", I18N_NOOP("Loads a plugin which supports files of type <mimetype>,\nif one is installed."), 0 },
+ { "g", 0, 0},
+ { "goto <pagenumber>", I18N_NOOP("Navigate to this page"), 0 },
+ { "+file(s)", I18N_NOOP("Files to load"), 0 },
+ KCmdLineLastOption
+};
+
+
+static const char description[] = I18N_NOOP("Generic framework for viewer applications");
+
+
+int main(int argc, char **argv)
+{
+ KAboutData about ("kviewshell", I18N_NOOP("KViewShell"), "0.6",
+ description, KAboutData::License_GPL,
+ "(C) 2000, Matthias Hoelzer-Kluepfel\n"
+ "(C) 2004-2005, Wilfried Huss",
+ I18N_NOOP("Displays various document formats. "
+ "Based on original code from KGhostView."));
+ about.addAuthor ("Wilfried Huss", I18N_NOOP("Current Maintainer"),
+ "Wilfried.Huss@gmx.at");
+ about.addAuthor ("Matthias Hoelzer-Kluepfel", I18N_NOOP("Framework"),
+ "mhk@caldera.de");
+ about.addAuthor ("David Sweet",
+ I18N_NOOP("KGhostView Maintainer"),
+ "dsweet@kde.org",
+ "http://www.chaos.umd.edu/~dsweet");
+ about.addAuthor ("Mark Donohoe",
+ I18N_NOOP("KGhostView Author"));
+ about.addAuthor ("Markku Hihnala",
+ I18N_NOOP("Navigation widgets"));
+ about.addAuthor ("David Faure",
+ I18N_NOOP("Basis for shell"));
+ about.addAuthor ("Daniel Duley",
+ I18N_NOOP("Port to KParts"));
+ about.addAuthor ("Espen Sand",
+ I18N_NOOP("Dialog boxes"));
+ about.addAuthor ("Stefan Kebekus",
+ I18N_NOOP("DCOP-Interface, major improvements"),
+ "kebekus@kde.org");
+
+ KCmdLineArgs::init(argc, argv, &about);
+ KCmdLineArgs::addCmdLineOptions( options ); // Add my own options.
+ KApplication app;
+
+ // see if we are starting with session management
+ if (app.isRestored())
+ {
+ RESTORE(KViewShell);
+ }
+ else
+ {
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ if (args->isSet("unique")){
+ // With --unique, we need one argument.
+ if (args->count() < 1) {
+ args->usage();
+ exit(-1);
+ }
+
+ // Find the fully qualified file name of the file we are
+ // loading. Complain, if we are given a URL which does not point
+ // to a local file.
+ KURL url(args->url(0));
+
+ if (!args->url(0).isValid()) {
+ kdError(1223) << QString(I18N_NOOP("The URL %1 is not well-formed.")).arg(args->arg(0)) << endl;
+ return -1;
+ }
+
+ if (!args->url(0).isLocalFile()) {
+ kdError(1223) << QString(I18N_NOOP("The URL %1 does not point to a local file. You can only specify local "
+ "files if you are using the '--unique' option.")).arg(args->arg(0)) << endl;
+ return -1;
+ }
+
+ QString qualPath = QFileInfo(args->url(0).path()).absFilePath();
+
+ app.dcopClient()->attach();
+ QCString id = app.dcopClient()->registerAs("unique-kviewshell");
+ if (id.isNull())
+ kdError(1223) << "There was an error using dcopClient()->registerAs()." << endl;
+ QCStringList apps = app.dcopClient()->registeredApplications();
+ for ( QCStringList::Iterator it = apps.begin(); it != apps.end(); ++it )
+ {
+ if ((*it).find("kviewshell") == 0)
+ {
+ QByteArray data, replyData;
+ QCString replyType;
+ QDataStream arg(data, IO_WriteOnly);
+ bool result;
+ arg << qualPath.stripWhiteSpace();
+ if (!app.dcopClient()->call( *it, "kmultipage", "is_file_loaded(QString)", data, replyType, replyData))
+ kdError(1223) << "There was an error using DCOP." << endl;
+ else
+ {
+ QDataStream reply(replyData, IO_ReadOnly);
+ if (replyType == "bool")
+ {
+ reply >> result;
+ if (result == true)
+ {
+ if (app.dcopClient()->send(*it, "kmultipage", "jumpToReference(QString)", args->url(0).ref()) == true)
+ {
+ app.dcopClient()->detach();
+ return 0;
+ }
+ }
+ }
+ else
+ {
+ kdError(1223) << "The DCOP function 'doIt' returned an unexpected type of reply!";
+ }
+ }
+ }
+ }
+ }
+ app.dcopClient()->registerAs("kviewshell");
+ KViewShell* shell;
+
+ if (args->isSet("mimetype"))
+ {
+ shell = new KViewShell(args->getOption("mimetype"));
+ }
+ else if (args->count() > 0)
+ {
+ // If a url is given, we try to load a matching KViewShell plugin,
+ // so we don't have to load the empty plugin first.
+ KMimeType::Ptr mimetype = KMimeType::findByURL(args->url(0));
+ shell = new KViewShell(mimetype->name());
+ }
+ else
+ {
+ // Load the empty plugin
+ shell = new KViewShell();
+ }
+
+ // Show the main window before a file is loaded. This gives visual
+ // feedback to the user and (hopefully) reduces the perceived
+ // startup time.
+ shell->show();
+ app.processEvents();
+
+ if ( args->count() > 0 )
+ {
+ KURL url = args->url(0);
+ if (!url.hasRef() && args->isSet("goto"))
+ {
+ // If the url doesn't already has a reference part, add the
+ // argument of --goto to the url as reference, to make the
+ // KViewShell jump to this page.
+ QString reference = args->getOption("goto");
+ url.setHTMLRef(reference);
+ }
+ shell->openURL(url);
+ }
+ }
+
+ return app.exec();
+}
diff --git a/kviewshell/marklist.cpp b/kviewshell/marklist.cpp
new file mode 100644
index 00000000..8e39f619
--- /dev/null
+++ b/kviewshell/marklist.cpp
@@ -0,0 +1,616 @@
+/* This file is part of the KDE project
+ Copyright (C) 2004 Wilfried Huss <Wilfried.Huss@gmx.at>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <config.h>
+
+#include <qcheckbox.h>
+#include <qimage.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qtooltip.h>
+#include <qlabel.h>
+#include <qwhatsthis.h>
+#include <qpainter.h>
+#include <qtimer.h>
+
+#include <kapplication.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include <kpopupmenu.h>
+#include <kiconloader.h>
+#include <kdebug.h>
+
+#include "documentPageCache.h"
+#include "kvsprefs.h"
+#include "marklist.h"
+
+
+#include "marklist.moc"
+
+
+namespace {
+
+/** Holds the icon used as a overlay on pages which are not drawn yet. */
+QPixmap* waitIcon = 0;
+
+} // namespace anon
+
+
+/****** ThumbnailWidget ******/
+
+ThumbnailWidget::ThumbnailWidget(MarkListWidget* _parent, const PageNumber& _pageNumber, DocumentPageCache* _pageCache)
+ : QWidget(_parent), pageNumber(_pageNumber), pageCache(_pageCache), parent(_parent)
+{
+ setBackgroundMode(Qt::NoBackground);
+
+ needsUpdating = true;
+
+ if (!waitIcon)
+ {
+ waitIcon = new QPixmap(KGlobal::iconLoader()->loadIcon("gear", KIcon::NoGroup, KIcon::SizeMedium));
+ }
+}
+
+void ThumbnailWidget::paintEvent(QPaintEvent* e)
+{
+ // Only repaint if the widget is really visible. We need to check this because Qt
+ // sends paintEvents to all widgets that have ever been visible in the Scrollview
+ // whenever the ScrollView is resized. This also increases the percieved performance
+ // only thumbnails that are really needed are rendered.
+ if (!parent->isVisible())
+ {
+ //kdDebug() << "Abort Thumbnail drawing for page " << pageNumber << endl;
+ return;
+ }
+
+ QPainter p(this);
+ p.setClipRect(e->rect());
+
+ // Paint a black border around the widget
+ p.setRasterOp(Qt::CopyROP);
+ p.setBrush(NoBrush);
+ p.setPen(Qt::black);
+ p.drawRect(rect());
+
+ // Remove 1 pixel from all sides of the rectangle, to eliminate overdraw with
+ // the black border.
+ QRect thumbRect = rect();
+ thumbRect.addCoords(1,1,-1,-1);
+
+ // If the thumbnail is empty or has been marked for updating generate a new thumbnail.
+ if (thumbnail.isNull() || needsUpdating)
+ {
+ if (KVSPrefs::changeColors() && KVSPrefs::renderMode() == KVSPrefs::EnumRenderMode::Paper)
+ p.fillRect(thumbRect, KVSPrefs::paperColor());
+ else
+ p.fillRect(thumbRect, Qt::white);
+
+ // Draw busy indicator.
+ // Im not really sure if this is a good idea.
+ // While it is nice to see an indication that something is happening for pages which
+ // take long to redraw, it gets quite annoing for fast redraws.
+ // TODO: Disable or find something less distractiong.
+ p.drawPixmap(10, 10, *waitIcon);
+
+ QTimer::singleShot(50, this, SLOT(setThumbnail()));
+ return;
+ }
+
+ // Safety check
+ if (thumbnail.isNull())
+ {
+ kdDebug(1223) << "No Thumbnail for page " << pageNumber << " created." << endl;
+ return;
+ }
+
+
+ // The actual page starts at point (1,1) because of the outline.
+ // Therefore we need to shift the destination rectangle.
+ QRect pixmapRect = thumbRect;
+ pixmapRect.moveBy(-1,-1);
+
+ // Paint widget
+ bitBlt (this, thumbRect.topLeft(), &thumbnail, pixmapRect, CopyROP);
+}
+
+void ThumbnailWidget::resizeEvent(QResizeEvent*)
+{
+ thumbnail.resize(width(), height());
+ // Generate a new thumbnail in the next paintEvent.
+ needsUpdating = true;
+}
+
+void ThumbnailWidget::setThumbnail()
+{
+ if (!parent->isVisible())
+ {
+ // We only want to calculate the thumbnail for widgets that are currently visible.
+ // When we are fast scrolling thru the document. Many paint events are created, that
+ // are often not needed anymore at the time the eventloop executes them.
+ //kdDebug() << "Delayed request Abort Thumbnail drawing for page " << pageNumber << endl;
+ kapp->processEvents();
+ return;
+ }
+
+ needsUpdating = false;
+
+ // Draw Thumbnail
+ thumbnail = pageCache->createThumbnail(pageNumber, width() - 2);
+
+ if (thumbnail.height() != height() + 2)
+ setFixedHeight(thumbnail.height() + 2);
+
+ update();
+ kapp->processEvents();
+}
+
+
+/****** MarkListWidget ******/
+
+
+MarkListWidget::MarkListWidget(QWidget* _parent, MarkList* _markList, const PageNumber& _pageNumber,
+ DocumentPageCache* _pageCache, bool _showThumbnail)
+ : QWidget(_parent), showThumbnail(_showThumbnail), pageNumber(_pageNumber),
+ pageCache(_pageCache), markList(_markList)
+{
+ QBoxLayout* layout = new QVBoxLayout(this, margin);
+
+ thumbnailWidget = 0;
+ if (showThumbnail)
+ {
+ thumbnailWidget = new ThumbnailWidget(this, pageNumber, pageCache);
+ layout->addWidget(thumbnailWidget, 1, Qt::AlignTop);
+ }
+
+ QBoxLayout* bottomLayout = new QHBoxLayout(layout);
+
+ checkBox = new QCheckBox(QString::null, this );
+ checkBox->setFocusPolicy(QWidget::NoFocus);
+ QToolTip::add(checkBox, i18n("Select for printing"));
+ bottomLayout->addWidget(checkBox, 0, Qt::AlignAuto);
+
+ pageLabel = new QLabel(QString("%1").arg(pageNumber), this);
+ bottomLayout->addWidget(pageLabel, 1);
+
+ _backgroundColor = KGlobalSettings::baseColor();
+
+ // Alternate between colors.
+ if ((pageNumber % 2 == 0) && KGlobalSettings::alternateBackgroundColor().isValid())
+ _backgroundColor = KGlobalSettings::alternateBackgroundColor();
+
+ setPaletteBackgroundColor( _backgroundColor );
+
+ show();
+}
+
+bool MarkListWidget::isChecked() const
+{
+ return checkBox->isChecked();
+}
+
+void MarkListWidget::toggle()
+{
+ checkBox->toggle();
+}
+
+void MarkListWidget::setChecked( bool checked )
+{
+ checkBox->setChecked(checked);
+}
+
+void MarkListWidget::setSelected( bool selected )
+{
+ if (selected)
+ setPaletteBackgroundColor( QApplication::palette().active().highlight() );
+ else
+ setPaletteBackgroundColor( _backgroundColor );
+}
+
+int MarkListWidget::setNewWidth(int width)
+{
+ int height = QMAX(checkBox->height(), pageLabel->height()) + 2*margin;
+ if (showThumbnail)
+ {
+ // Calculate size of Thumbnail
+ int thumbnailWidth = QMIN(width, KVSPrefs::maxThumbnailWidth());
+ int thumbnailHeight = (int)((thumbnailWidth - 2*margin - 2) / pageCache->sizeOfPage(pageNumber).aspectRatio() + 0.5) + 2;
+
+ // Resize Thumbnail if necessary
+ if (thumbnailWidget->size() != QSize(thumbnailWidth, thumbnailHeight))
+ thumbnailWidget->setFixedSize(thumbnailWidth - 2*margin, thumbnailHeight);
+
+ height += thumbnailHeight + 2*margin;
+ }
+
+ setFixedSize(width, height);
+ return height;
+}
+
+bool MarkListWidget::isVisible()
+{
+ QRect visibleRect(markList->contentsX(), markList->contentsY(),
+ markList->visibleWidth(), markList->visibleHeight());
+ QRect widgetRect(markList->childX(this), markList->childY(this), width(), height());
+
+ if (widgetRect.intersects(visibleRect))
+ return true;
+
+ return false;
+}
+
+
+void MarkListWidget::mousePressEvent(QMouseEvent* e)
+{
+ // Select Page
+ if (e->button() == LeftButton)
+ {
+ emit selected(pageNumber);
+ }
+ else if (e->button() == RightButton)
+ {
+ emit showPopupMenu(pageNumber, e->globalPos());
+ }
+}
+
+
+/****** MarkList ******/
+
+
+MarkList::MarkList(QWidget* parent, const char* name)
+ : QScrollView(parent, name), clickedThumbnail(0), showThumbnails(true), contextMenu(0)
+{
+ currentPage = PageNumber::invalidPage;
+ widgetList.setAutoDelete(true);
+ setFocusPolicy( QWidget::StrongFocus );
+ //viewport()->setFocusPolicy( QWidget::WheelFocus );
+ setResizePolicy(QScrollView::Manual);
+
+ setVScrollBarMode(QScrollView::AlwaysOn);
+ setHScrollBarMode(QScrollView::AlwaysOff);
+
+ setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
+
+ viewport()->setBackgroundMode(Qt::PaletteBase);
+ enableClipper(true);
+}
+
+MarkList::~MarkList()
+{
+ delete contextMenu;
+}
+
+void MarkList::setPageCache(DocumentPageCache* _pageCache)
+{
+ pageCache = _pageCache;
+}
+
+QValueList<int> MarkList::selectedPages() const
+{
+ QValueList<int> list;
+ MarkListWidget* item;
+ for(unsigned int i = 0; i < widgetList.count(); i++)
+ {
+ item = widgetList[i];
+ if (item->isChecked())
+ list << (i + 1);
+ }
+ return list;
+}
+
+void MarkList::setNumberOfPages(int numberOfPages, bool _showThumbnails)
+{
+ showThumbnails = _showThumbnails;
+
+ widgetList.resize(numberOfPages);
+
+ int y = 0;
+
+ for (int page = 1; page <= numberOfPages; page++)
+ {
+ MarkListWidget* item = new MarkListWidget(viewport(), this, page, pageCache, showThumbnails);
+
+ connect(item, SIGNAL(selected(const PageNumber&)), this, SLOT(thumbnailSelected(const PageNumber&)));
+ connect(item, SIGNAL(showPopupMenu(const PageNumber&, const QPoint&)), this, SLOT(showPopupMenu(const PageNumber&, const QPoint&)));
+
+ widgetList.insert(page - 1, item);
+
+ int height = item->setNewWidth(visibleWidth());
+ addChild(item, 0, y);
+
+ y += height;
+ }
+ resizeContents(visibleWidth(), y);
+ viewport()->update();
+}
+
+void MarkList::thumbnailSelected(const PageNumber& pageNumber)
+{
+ // This variable is set to remember that the next call to setCurrentPageNumber
+ // has been initiated with a left click on the thumbnail of page pageNumber.
+ clickedThumbnail = pageNumber;
+ emit selected(pageNumber);
+}
+
+void MarkList::setCurrentPageNumber(const PageNumber& pageNumber)
+{
+ if (!pageNumber.isValid() || pageNumber > (int)widgetList.count())
+ {
+ clickedThumbnail = 0;
+ return;
+ }
+
+ if (currentPage == pageNumber)
+ return;
+
+ MarkListWidget* item;
+
+ // Clear old selection
+ if (currentPage.isValid() && currentPage <= (int)widgetList.count())
+ {
+ item = widgetList[currentPage - 1];
+ item->setSelected(false);
+ }
+
+ // Draw new selection
+ item = widgetList[pageNumber - 1];
+ item->setSelected(true);
+
+ // Make selected page visible if the current page has not been set with a mouseclick
+ // in the thumbnail list. (We use this because it is a bit confusing if the element that
+ // you have just clicked on, is scrolled away under the mouse cursor)
+ if (clickedThumbnail != pageNumber)
+ ensureVisible(childX(item), childY(item), 0, item->height());
+
+ clickedThumbnail = 0;
+
+ currentPage = pageNumber;
+}
+
+void MarkList::clear()
+{
+ currentPage = PageNumber::invalidPage;
+ widgetList.resize(0);
+}
+
+void MarkList::selectAll()
+{
+ MarkListWidget* item;
+ for (unsigned int i = 0; i < widgetList.count(); i++)
+ {
+ item = widgetList[i];
+ item->setChecked(true);
+ }
+}
+
+void MarkList::selectEven()
+{
+ MarkListWidget* item;
+ for (unsigned int i = 1; i < widgetList.count(); i = i + 2)
+ {
+ item = widgetList[i];
+ item->setChecked(true);
+ }
+}
+
+void MarkList::selectOdd()
+{
+ MarkListWidget* item;
+ for (unsigned int i = 0; i < widgetList.count(); i = i + 2)
+ {
+ item = widgetList[i];
+ item->setChecked(true);
+ }
+}
+
+void MarkList::toggleSelection()
+{
+ MarkListWidget* item;
+ for (unsigned int i = 0; i < widgetList.count(); i++)
+ {
+ item = widgetList[i];
+ item->toggle();
+ }
+}
+
+void MarkList::removeSelection()
+{
+ MarkListWidget* item;
+ for (unsigned int i = 0; i < widgetList.count(); i++)
+ {
+ item = widgetList[i];
+ item->setChecked(false);
+ }
+}
+
+void MarkList::viewportResizeEvent(QResizeEvent*)
+{
+ MarkListWidget* item;
+
+ int yold = contentsHeight();
+ int y = 0;
+
+ for (unsigned int i = 0; i < widgetList.count(); i++)
+ {
+ item = widgetList[i];
+ int height = item->setNewWidth(visibleWidth());
+ moveChild(item, 0, y);
+
+ y += height;
+ }
+ resizeContents(visibleWidth(), y);
+
+ // If the height of the content has changed
+ if (yold != contentsHeight())
+ {
+ // Make sure the selected item is still visible.
+ if (currentPage.isValid() && currentPage <= (int)widgetList.count())
+ {
+ item = widgetList[currentPage-1];
+ ensureVisible(childX(item), childY(item), 0, item->height());
+ }
+ }
+
+ viewport()->update();
+}
+
+
+void MarkList::updateWidgetSize(const PageNumber& pageNumber)
+{
+ // safety checks
+ if (!pageNumber.isValid() || pageNumber > widgetList.count())
+ {
+ kdError() << "MarkList::updateWidgetSize called with invalid pageNumber " << pageNumber << endl;
+ return;
+ }
+
+ MarkListWidget* item;
+
+ // Resize the changed widget
+ item = widgetList[pageNumber - 1];
+ int height = item->setNewWidth(visibleWidth());
+ int y = childY(item) + height;
+
+ // Move the rest of the widgets
+ for (unsigned int i = pageNumber; i < widgetList.count(); i++)
+ {
+ item = widgetList[i];
+ int height = item->height();
+ moveChild(item, 0, y);
+
+ y += height;
+ }
+ resizeContents(contentsWidth(), y);
+
+ viewport()->update();
+}
+
+void MarkList::mousePressEvent(QMouseEvent* e)
+{
+ if (e->button() == RightButton)
+ {
+ // We call showPopupMenu with an invalid pageNumber to indicate that
+ // the mouse does not point at a thumbnailWidget.
+ showPopupMenu(PageNumber::invalidPage, e->globalPos());
+ }
+}
+
+void MarkList::slotShowThumbnails(bool show)
+{
+ if (show != showThumbnails)
+ {
+ int numOfPages = widgetList.count();
+
+ if (numOfPages == 0)
+ return;
+
+ // Save current page.
+ PageNumber _currentPage = currentPage;
+
+ // Save page selections.
+ QValueVector<bool> selections;
+ selections.resize(widgetList.count());
+ for (unsigned int i = 0; i < widgetList.count(); i++)
+ selections[i] = widgetList[i]->isChecked();
+
+ // Rebuild thumbnail widgets.
+ clear();
+ setNumberOfPages(numOfPages, show);
+
+ // Restore current page.
+ setCurrentPageNumber(_currentPage);
+
+ // Restore page selections
+ for (unsigned int i = 0; i < widgetList.count(); i++)
+ widgetList[i]->setChecked(selections[i]);
+ }
+}
+
+
+void MarkList::repaintThumbnails()
+{
+ bool show = showThumbnails;
+ int numOfPages = widgetList.count();
+
+ // Rebuild thumbnail widgets.
+ clear();
+ setNumberOfPages(numOfPages, show);
+}
+
+
+void MarkList::showPopupMenu(const PageNumber& pageNumber, const QPoint& position)
+{
+ if (contextMenu == 0)
+ {
+ // Initialize Contextmenu
+ contextMenu = new KPopupMenu(this, "markListContext");
+
+ contextMenu->insertItem(i18n("Select &Current Page"), 0);
+ contextMenu->insertItem(i18n("Select &All Pages"), 1);
+ contextMenu->insertItem(i18n("Select &Even Pages"), 2);
+ contextMenu->insertItem(i18n("Select &Odd Pages"), 3);
+ contextMenu->insertItem(i18n("&Invert Selection"), 4);
+ contextMenu->insertItem(i18n("&Deselect All Pages"), 5);
+ }
+
+ if (widgetList.count() == 0)
+ {
+ for (int i = 0; i <= 5; i++)
+ contextMenu->setItemEnabled(i, false);
+ }
+ else
+ {
+ for (int i = 0; i <= 5; i++)
+ contextMenu->setItemEnabled(i, true);
+ }
+
+ // Only allow to select the current page if we got a valid pageNumber.
+ if (pageNumber.isValid() && pageNumber <= (int)widgetList.count())
+ contextMenu->setItemEnabled(0, true);
+ else
+ contextMenu->setItemEnabled(0, false);
+
+ // Show Contextmenu
+ switch(contextMenu->exec(position))
+ {
+ case 0:
+ widgetList[pageNumber - 1]->toggle();
+ break;
+
+ case 1:
+ selectAll();
+ break;
+
+ case 2:
+ selectEven();
+ break;
+
+ case 3:
+ selectOdd();
+ break;
+
+ case 4:
+ toggleSelection();
+ break;
+
+ case 5:
+ removeSelection();
+ break;
+ }
+}
+
diff --git a/kviewshell/marklist.h b/kviewshell/marklist.h
new file mode 100644
index 00000000..01458db3
--- /dev/null
+++ b/kviewshell/marklist.h
@@ -0,0 +1,186 @@
+// -*- C++ -*-
+/* This file is part of the KDE project
+ Copyright (C) 2004 Wilfried Huss <Wilfried.Huss@gmx.at>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef MARKLIST_H
+#define MARKLIST_H
+
+#include "pageNumber.h"
+
+#include <qpixmap.h>
+#include <qptrvector.h>
+#include <qscrollview.h>
+
+class QCheckBox;
+class QLabel;
+class KPopupMenu;
+
+class DocumentPageCache;
+
+class MarkList;
+class MarkListWidget;
+
+
+/****** ThumbnailWidget ******/
+
+
+class ThumbnailWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ ThumbnailWidget(MarkListWidget* parent_, const PageNumber& _pageNumber, DocumentPageCache*);
+
+private:
+ virtual void paintEvent(QPaintEvent*);
+ virtual void resizeEvent(QResizeEvent*);
+
+private slots:
+ void setThumbnail();
+
+private:
+ PageNumber pageNumber;
+
+ bool needsUpdating;
+
+ DocumentPageCache* pageCache;
+
+ MarkListWidget* parent;
+
+ QPixmap thumbnail;
+};
+
+
+/****** MarkListWidget ******/
+
+
+class MarkListWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ MarkListWidget(QWidget* _parent, MarkList*, const PageNumber& _pageNumber, DocumentPageCache*, bool _showThumbnail = true);
+
+ bool isChecked() const;
+
+ bool isVisible();
+
+public slots:
+ void toggle();
+ void setChecked( bool checked );
+
+ void setSelected( bool selected );
+
+ int setNewWidth(int width);
+
+signals:
+ /** Emitted when the Page is selected in the ThumbnailView. */
+ void selected(const PageNumber&);
+
+ /** Emitted on right click. */
+ void showPopupMenu(const PageNumber& pageNumber, const QPoint& position);
+
+protected:
+ virtual void mousePressEvent(QMouseEvent*);
+
+private:
+
+ bool showThumbnail;
+
+ ThumbnailWidget* thumbnailWidget;
+ QCheckBox* checkBox;
+ QLabel* pageLabel;
+ QColor _backgroundColor;
+
+ const PageNumber pageNumber;
+
+ DocumentPageCache* pageCache;
+
+ static const int margin = 5;
+
+ MarkList* markList;
+};
+
+
+/****** MarkList ******/
+
+
+class MarkList: public QScrollView
+{
+ Q_OBJECT
+
+public:
+ MarkList(QWidget* parent = 0, const char* name = 0);
+ virtual ~MarkList();
+
+ void setPageCache(DocumentPageCache*);
+
+ QValueList<int> selectedPages() const;
+
+ PageNumber currentPageNumber() { return currentPage; }
+
+ PageNumber numberOfPages() { return widgetList.count(); }
+
+ virtual QSize sizeHint() const { return QSize(); }
+
+public slots:
+ void setNumberOfPages(int numberOfPages, bool showThumbnails = true);
+
+ void thumbnailSelected(const PageNumber& pageNumber);
+ void setCurrentPageNumber(const PageNumber& pageNumber);
+
+ void clear();
+
+ void slotShowThumbnails(bool);
+ void repaintThumbnails();
+
+ void updateWidgetSize(const PageNumber&);
+
+protected:
+ virtual void viewportResizeEvent(QResizeEvent*);
+
+ virtual void mousePressEvent(QMouseEvent*);
+
+signals:
+ void selected(const PageNumber&);
+
+private slots:
+ void showPopupMenu(const PageNumber& pageNumber, const QPoint& position);
+
+ void selectAll();
+ void selectEven();
+ void selectOdd();
+ void toggleSelection();
+ void removeSelection();
+
+private:
+ QPtrVector<MarkListWidget> widgetList;
+
+ PageNumber currentPage;
+
+ PageNumber clickedThumbnail;
+
+ DocumentPageCache* pageCache;
+
+ bool showThumbnails;
+
+ KPopupMenu* contextMenu;
+};
+
+#endif
diff --git a/kviewshell/optionDialogAccessibilityWidget.ui b/kviewshell/optionDialogAccessibilityWidget.ui
new file mode 100644
index 00000000..43490028
--- /dev/null
+++ b/kviewshell/optionDialogAccessibilityWidget.ui
@@ -0,0 +1,528 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>optionDialogAccessibilityWidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>optionDialogAccessibilityWidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>487</width>
+ <height>384</height>
+ </rect>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>kcfg_ChangeColors</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Change &amp;Colors</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>warn</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="paletteForegroundColor">
+ <color>
+ <red>80</red>
+ <green>0</green>
+ <blue>0</blue>
+ </color>
+ </property>
+ <property name="text">
+ <string>Warning: these options can badly affect drawing speed.</string>
+ </property>
+ <property name="textFormat">
+ <enum>PlainText</enum>
+ </property>
+ </widget>
+ <widget class="QButtonGroup">
+ <property name="name">
+ <cstring>kcfg_RenderMode</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>5</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>NoFrame</enum>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <property name="title">
+ <string></string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioInverted</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Invert colors</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioNormal</cstring>
+ </property>
+ <property name="text">
+ <string>Change &amp;paper color</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer14_3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Paper color:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>kcfg_PaperColor</cstring>
+ </property>
+ </widget>
+ <widget class="KColorButton">
+ <property name="name">
+ <cstring>kcfg_PaperColor</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <spacer>
+ <property name="name">
+ <cstring>spacer7_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>30</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </hbox>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioRecolor</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Change dark and light colors</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <spacer row="1" column="3">
+ <property name="name">
+ <cstring>spacer12_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>48</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KColorButton" row="1" column="2">
+ <property name="name">
+ <cstring>kcfg_RecolorBackground</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer14_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="KColorButton" row="0" column="2">
+ <property name="name">
+ <cstring>kcfg_RecolorForeground</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <spacer row="0" column="3">
+ <property name="name">
+ <cstring>spacer12</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>48</width>
+ <height>21</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>textLabel3_2</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Light color:</string>
+ </property>
+ </widget>
+ <spacer row="0" column="0">
+ <property name="name">
+ <cstring>spacer14</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Dark color:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QRadioButton">
+ <property name="name">
+ <cstring>radioContrast</cstring>
+ </property>
+ <property name="text">
+ <string>Convert to &amp;black and white</string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout5</cstring>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="1" column="1">
+ <property name="name">
+ <cstring>textLabel2_2</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Contrast:</string>
+ </property>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer11_2</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <spacer row="0" column="0">
+ <property name="name">
+ <cstring>spacer11</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Fixed</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QSlider" row="1" column="2">
+ <property name="name">
+ <cstring>kcfg_BWContrast</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="pageStep">
+ <number>1</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QSlider" row="0" column="2">
+ <property name="name">
+ <cstring>kcfg_BWThreshold</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="pageStep">
+ <number>16</number>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Threshold:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+ </widget>
+ </vbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<connections>
+ <connection>
+ <sender>radioRecolor</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>textLabel3</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>radioRecolor</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_RecolorForeground</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>radioRecolor</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>textLabel3_2</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>radioRecolor</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_RecolorBackground</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>radioContrast</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>textLabel2</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>radioContrast</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_BWThreshold</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>radioNormal</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>textLabel1</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>radioNormal</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_PaperColor</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>radioContrast</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>textLabel2_2</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>radioContrast</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_BWContrast</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+ <connection>
+ <sender>kcfg_ChangeColors</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>kcfg_RenderMode</receiver>
+ <slot>setEnabled(bool)</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="global" impldecl="in implementation">kdialog.h</include>
+</includes>
+<layoutdefaults spacing="5" margin="11"/>
+<includehints>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+ <includehint>kcolorbutton.h</includehint>
+</includehints>
+</UI>
diff --git a/kviewshell/optionDialogGUIWidget_base.ui b/kviewshell/optionDialogGUIWidget_base.ui
new file mode 100644
index 00000000..cd8fba19
--- /dev/null
+++ b/kviewshell/optionDialogGUIWidget_base.ui
@@ -0,0 +1,148 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>optionDialogGUIWidget_base</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>optionDialogGUIWidget_base</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>349</width>
+ <height>174</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QComboBox" row="0" column="1">
+ <item>
+ <property name="text">
+ <string>Enabled</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Disabled</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Only on Hover</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>kcfg_UnderlineLinks</cstring>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;qt&gt;Controls how hyperlinks are underlined:
+&lt;ul&gt;
+&lt;li&gt;&lt;b&gt;Enabled&lt;/b&gt;: Always underline links&lt;/li&gt;
+&lt;li&gt;&lt;b&gt;Disabled&lt;/b&gt;: Never underline links&lt;/li&gt;
+&lt;li&gt;&lt;b&gt;Only on Hover&lt;/b&gt;: Underline when the mouse is moved over the link&lt;/li&gt;
+&lt;/ul&gt;&lt;/qt&gt;</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Underline links:</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>kcfg_ShowThumbnails</cstring>
+ </property>
+ <property name="text">
+ <string>Show &amp;thumbnail previews</string>
+ </property>
+ </widget>
+ <widget class="QGroupBox" row="2" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>groupBox1</cstring>
+ </property>
+ <property name="title">
+ <string>Overview Mode</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>rowLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Rows:</string>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="1" column="1">
+ <property name="name">
+ <cstring>kcfg_OverviewModeColumns</cstring>
+ </property>
+ <property name="maxValue">
+ <number>8</number>
+ </property>
+ <property name="minValue">
+ <number>3</number>
+ </property>
+ </widget>
+ <widget class="QSpinBox" row="0" column="1">
+ <property name="name">
+ <cstring>kcfg_OverviewModeRows</cstring>
+ </property>
+ <property name="maxValue">
+ <number>5</number>
+ </property>
+ <property name="minValue">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>columnLabel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Columns:</string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+</widget>
+<tabstops>
+ <tabstop>kcfg_OverviewModeRows</tabstop>
+ <tabstop>kcfg_OverviewModeColumns</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/kviewshell/pageNumber.h b/kviewshell/pageNumber.h
new file mode 100644
index 00000000..71ba3e50
--- /dev/null
+++ b/kviewshell/pageNumber.h
@@ -0,0 +1,65 @@
+// -*- C++ -*-
+//
+// pageNumber.h
+//
+// Part of KVIEWSHELL - A framework for multipage text/gfx viewers
+//
+// (C) 2004 Stefan Kebekus
+// Distributed under the GPL
+
+// Add header files alphabetically
+
+#ifndef PAGENUMBER_H
+#define PAGENUMBER_H
+
+#include <qglobal.h>
+
+
+/** \brief Class to represent a page number
+
+The class PageNumber is really nothing but an alias for Q_UINT16, and
+can be casted to and from Q_UINT16. It is used in kviewshell to remind
+the programmer of the convention that page numbers start at '1' (for
+'first page'), and that the value '0' means 'illegal page number' or
+'no page number'. Accordingly, the value '0' is also named
+PageNumber::invalidPage, and there is a trivial method isInvalid()
+that checks if the page number is 0.
+
+@author Stefan Kebekus <kebekus@kde.org>
+@version 1.0 0
+*/
+
+class PageNumber
+{
+ public:
+ enum pageNums {
+ invalidPage = 0 /*! Invalid page number */
+ };
+
+ /** The default constructor sets the page number to 'invalidPage' */
+ PageNumber() {pgNum = invalidPage;}
+
+ /** \brief Constructor that sets the page number
+
+ @param num page number that is set initially
+ */
+ PageNumber(Q_UINT16 num) {pgNum = num;}
+
+ /** \brief this method implements typecasts from Q_UINT16 */
+ PageNumber &operator=(const Q_UINT16 p) { pgNum = p; return *this; }
+
+ /** \brief This method implements typecasts to Q_UINT16 */
+ operator Q_UINT16() const { return pgNum; }
+
+ /** \brief Checks if the page number is invalid
+
+ @returns true, if pgNum != invalidPage, i.e., does not equal 0
+ */
+ bool isValid() const {return (pgNum != invalidPage);}
+
+ private:
+ /** \brief Single number that represents the page number */
+ Q_UINT16 pgNum;
+};
+
+#endif
diff --git a/kviewshell/pageSize.cpp b/kviewshell/pageSize.cpp
new file mode 100644
index 00000000..f52f01a4
--- /dev/null
+++ b/kviewshell/pageSize.cpp
@@ -0,0 +1,343 @@
+// pageSize.cpp
+//
+// Part of KVIEWSHELL - A framework for multipage text/gfx viewers
+//
+// (C) 2002-2003 Stefan Kebekus
+// Distributed under the GPL
+
+// Add header files alphabetically
+
+#include <config.h>
+
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <math.h>
+#include <qstringlist.h>
+
+#include "pageSize.h"
+#include "units.h"
+
+struct pageSizeItem
+{
+ const char *name;
+ float width; // in mm
+ float height; // in mm
+ const char *preferredUnit;
+};
+
+#define defaultMetricPaperSize 4 // Default paper size is "DIN A4"
+#define defaultImperialPaperSize 8 // Default paper size is "US Letter"
+
+static pageSizeItem staticList[] = { {"DIN A0", 841.0, 1189.0, "mm"},
+ {"DIN A1", 594.0, 841.0, "mm"},
+ {"DIN A2", 420.0, 594.0, "mm"},
+ {"DIN A3", 297.0, 420.0, "mm"},
+ {"DIN A4", 210.0, 297.0, "mm"},
+ {"DIN A5", 148.5, 210.0, "mm"},
+ {"DIN B4", 250.0, 353.0, "mm"},
+ {"DIN B5", 176.0, 250.0, "mm"},
+ {"US Letter", 215.9, 279.4, "in"},
+ {"US Legal", 215.9, 355.6, "in"},
+ {0, 0.0, 0.0, 0} // marks the end of the list.
+};
+
+
+pageSize::pageSize()
+{
+ currentSize = defaultPageSize();
+ pageWidth.setLength_in_mm(staticList[currentSize].width);
+ pageHeight.setLength_in_mm(staticList[currentSize].height);
+}
+
+
+pageSize::pageSize(const SimplePageSize& s)
+{
+ pageWidth = s.width();
+ pageHeight = s.height();
+
+ rectifySizes();
+ reconstructCurrentSize();
+}
+
+
+bool pageSize::setPageSize(const QString& name)
+{
+ // See if we can recognize the string
+ QString currentName;
+ for(int i=0; staticList[i].name != 0; i++) {
+ currentName = staticList[i].name;
+ if (currentName == name) {
+ currentSize = i;
+ // Set page width/height accordingly
+ pageWidth.setLength_in_mm(staticList[currentSize].width);
+ pageHeight.setLength_in_mm(staticList[currentSize].height);
+ emit(sizeChanged(*this));
+ return true;
+ }
+ }
+
+ // Check if the string contains 'x'. If yes, we assume it is of type
+ // "<number>x<number>". If yes, the first number is interpreted as
+ // the width in mm, the second as the height in mm
+ if (name.find('x') >= 0) {
+ bool wok, hok;
+ float pageWidth_tmp = name.section('x',0,0).toFloat(&wok);
+ float pageHeight_tmp = name.section('x',1,1).toFloat(&hok);
+ if (wok && hok) {
+ pageWidth.setLength_in_mm(pageWidth_tmp);
+ pageHeight.setLength_in_mm(pageHeight_tmp);
+
+ rectifySizes();
+ reconstructCurrentSize();
+ emit(sizeChanged(*this));
+ return true;
+ }
+ }
+
+ // Check if the string contains ','. If yes, we assume it is of type
+ // "<number><unit>,<number><uni>". The first number is supposed to
+ // be the width, the second the height.
+ if (name.find(',') >= 0) {
+ bool wok, hok;
+ float pageWidth_tmp = distance::convertToMM(name.section(',',0,0), &wok);
+ float pageHeight_tmp = distance::convertToMM(name.section(',',1,1), &hok);
+ if (wok && hok) {
+ pageWidth.setLength_in_mm(pageWidth_tmp);
+ pageHeight.setLength_in_mm(pageHeight_tmp);
+
+ rectifySizes();
+ reconstructCurrentSize();
+ emit(sizeChanged(*this));
+ return true;
+ }
+ }
+
+ // Last resource. Set the default, in case the string is
+ // unintelligible to us.
+ currentSize = defaultPageSize();
+ pageWidth.setLength_in_mm(staticList[currentSize].width);
+ pageHeight.setLength_in_mm(staticList[currentSize].height);
+ kdError(1223) << "pageSize::setPageSize: could not parse '" << name << "'. Using " << staticList[currentSize].name << " as a default." << endl;
+ emit(sizeChanged(*this));
+ return false;
+}
+
+
+void pageSize::setPageSize(double width, double height)
+{
+ SimplePageSize oldPage = *this;
+
+ pageWidth.setLength_in_mm(width);
+ pageHeight.setLength_in_mm(height);
+
+ rectifySizes();
+ reconstructCurrentSize();
+ if ( !isNearlyEqual(oldPage))
+ emit(sizeChanged(*this));
+}
+
+
+void pageSize::setPageSize(const QString& width, const QString& _widthUnits, const QString& height, const QString& _heightUnits)
+{
+ SimplePageSize oldPage = *this;
+
+ double w = width.toFloat();
+ double h = height.toFloat();
+
+ QString widthUnits = _widthUnits;
+ if ((widthUnits != "cm") && (widthUnits != "mm") && (widthUnits != "in")) {
+ kdError(1223) << "Unrecognized page width unit '" << widthUnits << "'. Assuming mm" << endl;
+ widthUnits = "mm";
+ }
+ pageWidth.setLength_in_mm(w);
+ if (widthUnits == "cm")
+ pageWidth.setLength_in_cm(w);
+ if (widthUnits == "in")
+ pageWidth.setLength_in_inch(w);
+
+ QString heightUnits = _heightUnits;
+ if ((heightUnits != "cm") && (heightUnits != "mm") && (heightUnits != "in")) {
+ kdError(1223) << "Unrecognized page height unit '" << widthUnits << "'. Assuming mm" << endl;
+ heightUnits = "mm";
+ }
+ pageHeight.setLength_in_mm(h);
+ if (heightUnits == "cm")
+ pageHeight.setLength_in_cm(h);
+ if (heightUnits == "in")
+ pageHeight.setLength_in_inch(h);
+
+ rectifySizes();
+ reconstructCurrentSize();
+ if ( !isNearlyEqual(oldPage))
+ emit(sizeChanged(*this));
+}
+
+
+pageSize &pageSize::operator= (const pageSize &src)
+{
+ SimplePageSize oldPage = *this;
+
+ currentSize = src.currentSize;
+ pageWidth = src.pageWidth;
+ pageHeight = src.pageHeight;
+
+ if ( !isNearlyEqual(oldPage))
+ emit(sizeChanged(*this));
+ return *this;
+}
+
+
+void pageSize::rectifySizes()
+{
+ // Now do some sanity checks to make sure that values are not
+ // outrageous. We allow values between 5cm and 50cm.
+ if (pageWidth.getLength_in_mm() < 50)
+ pageWidth.setLength_in_mm(50.0);
+ if (pageWidth.getLength_in_mm() > 1200)
+ pageWidth.setLength_in_mm(1200);
+ if (pageHeight.getLength_in_mm() < 50)
+ pageHeight.setLength_in_mm(50);
+ if (pageHeight.getLength_in_mm() > 1200)
+ pageHeight.setLength_in_mm(1200);
+ return;
+}
+
+
+QString pageSize::preferredUnit() const
+{
+ if (currentSize >= 0)
+ return staticList[currentSize].preferredUnit;
+
+ // User-defined size. Give a preferred unit depening on the locale.
+ if (KGlobal::locale()-> measureSystem() == KLocale::Metric)
+ return "mm";
+ else
+ return "in";
+}
+
+
+QString pageSize::widthString(const QString& unit) const
+{
+ QString answer = "--";
+
+ if (unit == "cm")
+ answer.setNum(pageWidth.getLength_in_cm());
+ if (unit == "mm")
+ answer.setNum(pageWidth.getLength_in_mm());
+ if (unit == "in")
+ answer.setNum(pageWidth.getLength_in_inch());
+
+ return answer;
+}
+
+
+QString pageSize::heightString(const QString& unit) const
+{
+ QString answer = "--";
+
+ if (unit == "cm")
+ answer.setNum(pageHeight.getLength_in_cm());
+ if (unit == "mm")
+ answer.setNum(pageHeight.getLength_in_mm());
+ if (unit == "in")
+ answer.setNum(pageHeight.getLength_in_inch());
+
+ return answer;
+}
+
+
+QStringList pageSize::pageSizeNames()
+{
+ QStringList names;
+
+ for(int i=0; staticList[i].name != 0; i++)
+ names << staticList[i].name;
+
+ return names;
+}
+
+
+QString pageSize::formatName() const
+{
+ if (currentSize >= 0)
+ return staticList[currentSize].name;
+ else
+ return QString::null;
+}
+
+
+int pageSize::getOrientation() const
+{
+ if (currentSize == -1) {
+ kdError(1223) << "pageSize::getOrientation: getOrientation called for page format that does not have a name." << endl;
+ return 0;
+ }
+
+ if (pageWidth.getLength_in_mm() == staticList[currentSize].width)
+ return 0;
+ else
+ return 1;
+}
+
+
+void pageSize::setOrientation(int orient)
+{
+ if (currentSize == -1) {
+ kdError(1223) << "pageSize::setOrientation: setOrientation called for page format that does not have a name." << endl;
+ return;
+ }
+
+ if (orient == 1) {
+ pageWidth.setLength_in_mm(staticList[currentSize].height);
+ pageHeight.setLength_in_mm(staticList[currentSize].width);
+ } else {
+ pageWidth.setLength_in_mm(staticList[currentSize].width);
+ pageHeight.setLength_in_mm(staticList[currentSize].height);
+ }
+ emit(sizeChanged(*this));
+}
+
+
+QString pageSize::serialize() const
+{
+ if ((currentSize >= 0) && (fabs(staticList[currentSize].height-pageHeight.getLength_in_mm()) <= 0.5))
+ return staticList[currentSize].name;
+ else
+ return QString("%1x%2").arg(pageWidth.getLength_in_mm()).arg(pageHeight.getLength_in_mm());
+}
+
+
+void pageSize::reconstructCurrentSize()
+{
+ for(int i=0; staticList[i].name != 0; i++) {
+ if ((fabs(staticList[i].width - pageWidth.getLength_in_mm()) <= 2) && (fabs(staticList[i].height - pageHeight.getLength_in_mm()) <= 2)) {
+ currentSize = i;
+ pageWidth.setLength_in_mm(staticList[currentSize].width);
+ pageHeight.setLength_in_mm(staticList[currentSize].height);
+ return;
+ }
+ if ((fabs(staticList[i].height - pageWidth.getLength_in_mm()) <= 2) && (fabs(staticList[i].width - pageHeight.getLength_in_mm()) <= 2)) {
+ currentSize = i;
+ pageWidth.setLength_in_mm(staticList[currentSize].height);
+ pageHeight.setLength_in_mm(staticList[currentSize].width);
+ return;
+ }
+ }
+ currentSize = -1;
+ return;
+}
+
+int pageSize::defaultPageSize()
+{
+ // FIXME: static_cast<QPrinter::PageSize>(KGlobal::locale()->pageSize())
+ // is the proper solution here. Then you can determine the values
+ // without using your hardcoded table too!
+ if (KGlobal::locale()-> measureSystem() == KLocale::Metric)
+ return defaultMetricPaperSize;
+ else
+ return defaultImperialPaperSize;
+}
+
+#include "pageSize.moc"
+
diff --git a/kviewshell/pageSize.h b/kviewshell/pageSize.h
new file mode 100644
index 00000000..5ba0194e
--- /dev/null
+++ b/kviewshell/pageSize.h
@@ -0,0 +1,280 @@
+// -*- C++ -*-
+//
+// pageSize.h
+//
+// Part of KVIEWSHELL - A framework for multipage text/gfx viewers
+//
+// (C) 2002-2005 Stefan Kebekus
+// Distributed under the GPL
+
+// Add header files alphabetically
+
+#ifndef PAGESIZE_H
+#define PAGESIZE_H
+
+#include "simplePageSize.h"
+
+#include <qobject.h>
+
+class QString;
+class QStringList;
+
+
+/* \brief This class represents physical page sizes.
+
+The main difference to the SimplePageSize class are the following.
+
+- This class knows about standard page sizes and accepts page sizes in
+ various formats, e.g. as a string "DIN A4", or by specifiying the
+ page width and height. Several units (inch, millimeters,
+ centimeters) are possible.
+
+- It is made sure that page width an hight are always in a resonable
+ range, which is currently set to 5cm .. 50cm
+
+- The default constructor provides a locale-depending default.
+
+@author Stefan Kebekus <kebekus@kde.org>
+@version 1.0.0
+*/
+
+class pageSize : public QObject, public SimplePageSize
+{
+Q_OBJECT
+
+public:
+ /** \brief Default constructor, initializes the pageSize with a
+ reasonable default
+
+ The default chosen depends on the locale. At the moment, A4 size
+ is chosen for countries with metric measurement system, and US
+ letter otherwise.
+ */
+ pageSize();
+
+ /** \brief Initializes the pageSize with a SimplePageSize. */
+ pageSize(const SimplePageSize&);
+
+ /** \brief List of standard pageSizes
+
+ This method returns the names of standard pageSizes,
+ e.g. "A4". These can be used, e.g., by a QComboBox to let the user
+ choose known sizes. The returned list is also a list of all possible
+ return values of the formatName() method explained below. If you
+ call pageSizeNames() more than once, it is guaranteed that the
+ same list of strings will be returned.
+
+ @returns QStringList that contains
+ */
+ QStringList pageSizeNames();
+
+ /** \brief Set page size by name.
+
+ Acceptable strings are
+
+ (1) a name from the list retured by pageSizeNames(), such as "DIN
+ A4"
+
+ (2) a string like "500x300", which describes a page of width 500mm
+ and height 300mm.
+
+ (3) a string like "3in, 4 cm". A number of different units,
+ including "in", "mm" and "cm", and a few typographical units are
+ recognized
+
+ If the name is not of these types, and error message is printed to
+ stderr using kdError() and a default value, which depends on the
+ locale, is set.
+
+ In any case, the values will be trimmed so as not to exceed the
+ minima/maxima of 5cm and 50cm, respectively. If the page size found
+ matches one of the standard sizes by an error of no more than 2mm,
+ the standard page size will be set. The signal sizeChanged() will
+ always be emitted.
+
+ @param name string that represents the page size
+
+ @returns 'True', if the parameter could be parsed, and 'false'
+ otherwise.
+ */
+ bool setPageSize(const QString& name);
+
+ /** \brief Set page size from width and height strings
+
+ Sets the page size to "width" and "height", given in the associated
+ units. Currently, "mm", "cm" and "in" are supported. If a unit is
+ not recognized, "mm" is siliently assumed, and error message is
+ printed to stderr using kdError(). If the page size set matches one
+ of the standard sizes by an error of no more than 2mm, the standard
+ page size will be set. If width or height does not contain a
+ number, the result is an undefined value. However, it is guaranteed
+ in any case that both width and height are between the minimal and
+ maximal possible values, i.e. in the range 5..50 cm. If the newly
+ set value differs from the old value by more that 2mm for width or
+ height, the signal sizeChanged() will be emitted
+
+ @param width string that represents the page width as a number,
+ e.g., " 300 "
+
+ @param widthUnits units for the width string. Currently "mm", "cm"
+ and "in" are allowed.
+
+ @param height string that represents the page height as a number,
+ e.g., " 300 "
+
+ @param heightUnits units for the height string. Currently "mm", "cm"
+ and "in" are allowed.
+ */
+ void setPageSize(const QString& width, const QString& widthUnits, const QString& height, const QString& heightUnits);
+
+ /** \brief Set page size
+
+ Sets the page size to "width" and "height", given in millimeter. If
+ the page size set matches one of the standard sizes by an error of
+ no more than 2mm, the standard page size will be set. Values are
+ trimmed so that both width and height are between the minimal and
+ maximal possible values, i.e. in the range 5..50 cm. If the newly
+ set value differs from the old value by more that 2mm for width or
+ height, the signal sizeChanged() will be emitted
+
+ @param width_in_mm page width in mm
+
+ @param height_in_mm page height in mm
+ */
+ virtual void setPageSize(double width_in_mm, double height_in_mm);
+
+ /** \brief Copy operator.
+
+ This operator will emit the signal sizeChanged() if one of the
+ dimensions of *this and src differ by more than two millimeters.
+ */
+ pageSize & operator= (const pageSize &src);
+
+ /** \brief Preferred unit for the current page size
+
+ @returns The name of the unit, one of "cm", "mm" or "in", which is
+ most commonly used with the current page format. For instance,
+ US Letter and US Legal are best given in inches, to avoid very
+ odd numbers. If the page format is unknown, returns a guess
+ based on the current locale. */
+ QString preferredUnit() const;
+
+ /** \brief Returns the page width as a string
+
+ @param unit The unit in which the page width shall be returned. This
+ must be one of "cm", "mm" or "in".
+
+ @returns a string containing a number, e.g. "3.1415", which gives the page
+ width in the given unit. If the unit is not recognized, the string "--" is returned.
+ */
+ QString widthString(const QString& unit) const;
+
+ /** \brief Returns the page height as a string
+
+ @param unit The unit in height the page width shall be
+ returned. This must be one of "cm", "mm" or "in".
+
+ @returns a string containing a number which gives the page height in
+ the given unit. If the unit is not recognized, the string "--" is
+ returned.
+ */
+ QString heightString(const QString& unit) const;
+
+ /** \brief Returns a name for the page size, if this is a standard
+ size
+
+ @warning This method does not take care of orientation, e.g. it
+ will return "DIN A4" if the page size is either 210x297 or
+ 297x210.
+
+ @returns A name for the current page size, if the format has a
+ name, or QString::null otherwise. If the result is not
+ QString::null, it is guaranteed to be one of the strings
+ returned by the pageSizeNames() method.
+ */
+ QString formatName() const;
+
+ /** \brief Returns an number for the page size, if this is a
+ standard size
+
+ @warning This method does not take care of orientation, e.g. it
+ will return the same value if the page size is either 210x297 or
+ 297x210.
+
+ @returns If the current format is one of the standard sizes, a
+ non-negative integer is returned, which is an index to the
+ QStringList returned by the pageSizeNames() method. If the
+ current format is none of the standard sizes, -1 is returned.
+ */
+ int formatNumber() const {return currentSize;}
+
+ /** \brief Gets orientation for standard sizes
+
+ If the pageSize is one of the standard sizes, i.e. formatNumber() !=
+ -1, this method can be used to get the orientation. If the pageSize
+ is not a standard size, this method prints an error message stderr
+ using kdError().
+
+ @returns 0 for 'portrait', or 1 for 'landscape'. If the size is none
+ of the standard sizes, an undefined value is returned.
+ */
+ int getOrientation() const;
+
+ /** \brief Returns a string that can be read by setPageSize(QString)
+
+ @returns This method returns a string like "210x297". The numbers
+ are page width and height in millimeters. The setPageSize(QString)
+ method will understand this output.
+ */
+ QString serialize() const;
+
+public slots:
+ /** \brief Sets orientation
+
+ If the pageSize is one of the standard sizes, i.e. formatNumber() !=
+ -1, this method can be used to set the orientation. If the pageSize
+ is not a standard size, this method prints an error message stderr
+ using kdError() and does nothing.
+
+ @param orient 0 sets 'portrait orientation', 1 sets 'landscape'
+ */
+ void setOrientation(int orient);
+
+signals:
+ /** \brief Signal emitted when the page sizes changes
+
+ emitted to indicate that the size changed. Not emitted immediately
+ after construction, when the constructor sets the default
+ size.
+
+ @param t a pointer to this
+ */
+ void sizeChanged(const SimplePageSize& t);
+
+private:
+ /** Makes sure that pageWidth and pageHeight are in the permissible
+ range and not, e.g., negative. */
+ void rectifySizes();
+
+ /** Tries to find one of the known sizes which matches pageWidth and
+ pageHeight, with an error margin of 2 millimeters. If found, the
+ value of 'currentsize' is set to point to the known size, and
+ pageWidth and pageHeight are set to the correct values for that
+ size. Otherwise, currentSize is set to -1 to indicate "custom
+ size". Note: this method does not take care of orientation,
+ e.g. the method will set 'currentsize' to point to "DIN A4" if
+ either the page size is 210x297 or 297x210. */
+ void reconstructCurrentSize();
+
+ /** Gives a default value for currentSize, which depends on the
+ locale. In countries with metric system, this will be "DIN A4",
+ in countries with the imperial system, "US Letter". */
+ int defaultPageSize();
+
+ /** Permissible range: 0--#Size_of_array staticList, or -1 to
+ indicate a "user defined setting". Other values may lead to a
+ segfault. */
+ int currentSize;
+};
+
+#endif
diff --git a/kviewshell/pageSizeDialog.cpp b/kviewshell/pageSizeDialog.cpp
new file mode 100644
index 00000000..3a64cbe3
--- /dev/null
+++ b/kviewshell/pageSizeDialog.cpp
@@ -0,0 +1,63 @@
+// pageSizeDialog.cpp
+//
+// Part of KVIEWSHELL - A framework for multipage text/gfx viewers
+//
+// (C) 2002-2003 Stefan Kebekus
+// Distributed under the GPL
+
+// Add header files alphabetically
+
+#include <config.h>
+
+#include <kapplication.h>
+#include <kcombobox.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qlineedit.h>
+#include <qvalidator.h>
+#include <qhbox.h>
+
+
+
+#include "pageSizeDialog.h"
+#include "pageSizeWidget.h"
+
+
+pageSizeDialog::pageSizeDialog( QWidget *parent, pageSize *userPrefdPageSize, const char *name, bool modal)
+ :KDialogBase( parent, name, modal, i18n("Page Size"), Ok|Apply|Cancel, Ok,
+ true )
+{
+ userPreferredPageSize = userPrefdPageSize;
+ pageSizeW = new pageSizeWidget(this, "PageSizeWidget");
+ pageSizeW->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)3, (QSizePolicy::SizeType)3, 0, 0,
+ pageSizeW->sizePolicy().hasHeightForWidth() ) );
+ setMainWidget(pageSizeW);
+}
+
+
+void pageSizeDialog::slotOk()
+{
+ if (userPreferredPageSize != 0)
+ *userPreferredPageSize = pageSizeW->pageSizeData();
+ accept();
+}
+
+
+void pageSizeDialog::slotApply()
+{
+ if (userPreferredPageSize != 0)
+ *userPreferredPageSize = pageSizeW->pageSizeData();
+}
+
+
+void pageSizeDialog::setPageSize(const QString& name)
+{
+ if (pageSizeW == 0)
+ return;
+ pageSizeW->setPageSize(name);
+}
+
+
+#include "pageSizeDialog.moc"
diff --git a/kviewshell/pageSizeDialog.h b/kviewshell/pageSizeDialog.h
new file mode 100644
index 00000000..17a4a0df
--- /dev/null
+++ b/kviewshell/pageSizeDialog.h
@@ -0,0 +1,52 @@
+// -*- C++ -*-
+/*
+ * pageSizeDialog, for kviewshell
+ * This file: Copyright (C) 2002-2003 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 _PAGESIZE_DIALOG_H_
+#define _PAGESIZE_DIALOG_H_
+
+#include <kdialogbase.h>
+
+class pageSizeWidget;
+class pageSize;
+
+class pageSizeDialog : public KDialogBase
+{
+ Q_OBJECT
+
+public:
+ // Constructs the page size Dialog. The pointer userPrefdPageSize
+ // points to a pageSize object which will be set the the chosen
+ // value whenever the user clicks on 'accept' or 'ok'. Programmers
+ // can then connect to the signal sizeChanged() of the object to be
+ // informed about the changes.
+ pageSizeDialog( QWidget *parent=0, pageSize *userPrefdPageSize=0, const char *name=0, bool modal=true);
+ void setPageSize(const QString&);
+
+protected slots:
+ virtual void slotOk();
+ virtual void slotApply();
+
+ private:
+ pageSizeWidget *pageSizeW;
+ pageSize *userPreferredPageSize;
+};
+
+
+#endif
diff --git a/kviewshell/pageSizeWidget.cpp b/kviewshell/pageSizeWidget.cpp
new file mode 100644
index 00000000..d485f3bb
--- /dev/null
+++ b/kviewshell/pageSizeWidget.cpp
@@ -0,0 +1,148 @@
+// pageSizeWidget.cpp
+//
+// Part of KVIEWSHELL - A framework for multipage text/gfx viewers
+//
+// (C) 2002-2003 Stefan Kebekus
+// Distributed under the GPL
+
+// Add header files alphabetically
+
+#include <config.h>
+
+#include <kcombobox.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <qlineedit.h>
+#include <qvalidator.h>
+
+#include "pageSize.h"
+#include "pageSizeWidget.h"
+#include "sizePreview.h"
+
+
+
+// Constructs a pageSizeWidget_base which is a child of 'parent', with
+// the name 'name' and widget flags set to 'f'.
+pageSizeWidget::pageSizeWidget( QWidget* parent, const char* name, WFlags fl )
+ : pageSizeWidget_base( parent, name, fl )
+{
+ connect(&chosenSize, SIGNAL(sizeChanged(const SimplePageSize&)), previewer, SLOT(setSize(const SimplePageSize&)));
+
+ // Set up the formatChoice QComboBox
+ formatChoice->insertItem(i18n("Custom Size"));
+ formatChoice->insertStringList(chosenSize.pageSizeNames());
+
+ // Activate the proper entry in the QComboBox
+ if (chosenSize.formatName().isNull()) {
+ orientationChoice->setEnabled(false);
+ formatChoice->setCurrentItem(0);
+ } else {
+ orientationChoice->setEnabled(true);
+ formatChoice->setCurrentText(chosenSize.formatName());
+ }
+ paperSize(formatChoice->currentItem());
+
+ connect(formatChoice, SIGNAL(activated(int)), this, SLOT(paperSize(int)));
+ connect(orientationChoice, SIGNAL(activated(int)), this, SLOT(orientationChanged(int)));
+
+ // Update the text fields when the user switches to a new unit, and
+ // when the "custom format" is NOT selected.
+ connect(widthUnits, SIGNAL(activated(int)), this, SLOT(unitsChanged(int)));
+ connect(heightUnits, SIGNAL(activated(int)), this, SLOT(unitsChanged(int)));
+
+ // Upate the chosen size whenever the user edits the input field.
+ connect(widthInput, SIGNAL(textChanged(const QString &)), this, SLOT(input(const QString &)));
+ connect(heightInput, SIGNAL(textChanged(const QString &)), this, SLOT(input(const QString &)));
+
+ // Allow entries between 0 and 1200. More filtering is done by the
+ // pageSize class, which silently ignores values which are out of
+ // range.
+ widthInput->setValidator(new QDoubleValidator(0.0, 1200.0, 1, this, "widthValidator"));
+ heightInput->setValidator(new QDoubleValidator(0.0, 1200.0, 1, this, "heightValidator"));
+}
+
+
+// Receives the output from the formatChoice combobox. A value of
+// "zero" means that the "custom paper size" has been chosen.
+void pageSizeWidget::paperSize(int index)
+{
+ widthInput->setEnabled(index == 0);
+ heightInput->setEnabled(index == 0);
+ orientationChoice->setEnabled(index != 0);
+
+ if (index != 0) {
+ chosenSize.setPageSize(formatChoice->currentText());
+ chosenSize.setOrientation(orientationChoice->currentItem());
+ }
+ widthUnits->setCurrentText(chosenSize.preferredUnit());
+ heightUnits->setCurrentText(chosenSize.preferredUnit());
+
+ fillTextFields();
+}
+
+
+void pageSizeWidget::setPageSize(const QString& sizeName)
+{
+ chosenSize.setPageSize(sizeName);
+
+ int index = chosenSize.formatNumber();
+
+ formatChoice->setCurrentItem(index+1);
+ widthInput->setEnabled(index == -1);
+ heightInput->setEnabled(index == -1);
+ orientationChoice->setEnabled(index != -1);
+
+ widthUnits->setCurrentText(chosenSize.preferredUnit());
+ heightUnits->setCurrentText(chosenSize.preferredUnit());
+
+ fillTextFields();
+}
+
+
+void pageSizeWidget::fillTextFields()
+{
+ // Warning! It is really necessary here to first generate both
+ // strings, and then call setText() on the input widgets. Reason?
+ // Calling setText() implicitly calls the input() method via the
+ // textChanged()-Signal of the QLineEdit widgets.
+ QString width = chosenSize.widthString(widthUnits->currentText());
+ QString height = chosenSize.heightString(heightUnits->currentText());
+
+ widthInput->setText(width);
+ heightInput->setText(height);
+}
+
+
+void pageSizeWidget::unitsChanged(int)
+{
+ // Update the text fields, i.e. show the current size in the proper
+ // units, but only if the "custom size" is NOT selected.
+ if (formatChoice->currentItem() != 0)
+ fillTextFields();
+ else
+ input(QString::null);
+}
+
+
+void pageSizeWidget::setOrientation(int ori)
+{
+ orientationChoice->setCurrentItem(ori);
+ orientationChanged();
+}
+
+
+void pageSizeWidget::orientationChanged(int orient)
+{
+ // Update the page preview
+ chosenSize.setOrientation(orient);
+}
+
+
+void pageSizeWidget::input(const QString &)
+{
+ chosenSize.setPageSize(widthInput->text(), widthUnits->currentText(), heightInput->text(), heightUnits->currentText());
+}
+
+
+
+#include "pageSizeWidget.moc"
diff --git a/kviewshell/pageSizeWidget.h b/kviewshell/pageSizeWidget.h
new file mode 100644
index 00000000..76cc0d02
--- /dev/null
+++ b/kviewshell/pageSizeWidget.h
@@ -0,0 +1,52 @@
+// -*- C++ -*-
+// pageSizeWidget.h
+//
+// Part of KVIEWSHELL - A framework for multipage text/gfx viewers
+//
+// (C) 2002 Stefan Kebekus
+// Distributed under the GPL
+
+// Add header files alphabetically
+
+#ifndef PAGESIZEWIDGET_H
+#define PAGESIZEWIDGET_H
+
+#include "pageSize.h"
+#include "pageSizeWidget_base.h"
+
+class QDoubleValidator;
+
+class pageSizeWidget : public pageSizeWidget_base
+{
+ Q_OBJECT
+
+public:
+ pageSizeWidget( QWidget* parent = 0, const char* name = 0, WFlags fl = 0 );
+
+ // Sets the page size. If the dialog is already shown, updates all
+ // the GUI. Accepts the same strings as input as the setPageSize()
+ // method of the pageSize() class.
+ void setPageSize(const QString&);
+
+ void setOrientation(int ori);
+
+ const pageSize &pageSizeData() const {return chosenSize;}
+
+protected slots:
+ void paperSize(int);
+ void fillTextFields();
+
+ // Dummy function, for convenience. Ignores the argument and calls
+ // the fillTextFields() slot.
+ void unitsChanged(int);
+ void orientationChanged(int = 0);
+ void input(const QString &);
+
+private:
+ pageSize chosenSize;
+
+ QDoubleValidator *widthValidator;
+ QDoubleValidator *heightValidator;
+};
+
+#endif // PAGESIZEWIDGET_H
diff --git a/kviewshell/pageSizeWidget_base.ui b/kviewshell/pageSizeWidget_base.ui
new file mode 100644
index 00000000..25cdc648
--- /dev/null
+++ b/kviewshell/pageSizeWidget_base.ui
@@ -0,0 +1,260 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>pageSizeWidget_base</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>pageSizeWidget_base</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>595</width>
+ <height>175</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>4</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string></string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>GroupBox5</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>Box</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="title">
+ <string>Page Format</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>TextLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Format:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>TextLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Width:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>TextLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Height:</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>widthInput</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Width of the chosen paper size in portrait orientation</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="3" column="1">
+ <property name="name">
+ <cstring>heightInput</cstring>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Height of the chosen paper size in portrait orientation</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="3" column="2">
+ <item>
+ <property name="text">
+ <string>cm</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>mm</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>in</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>heightUnits</cstring>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="2" column="2">
+ <item>
+ <property name="text">
+ <string>cm</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>mm</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>in</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>widthUnits</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>TextLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Orientation:</string>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="0" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>formatChoice</cstring>
+ </property>
+ </widget>
+ <widget class="KComboBox" row="1" column="1" rowspan="1" colspan="2">
+ <item>
+ <property name="text">
+ <string>Portrait</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Landscape</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>orientationChoice</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox">
+ <property name="name">
+ <cstring>GroupBox6</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>Box</enum>
+ </property>
+ <property name="lineWidth">
+ <number>1</number>
+ </property>
+ <property name="title">
+ <string>Page Preview</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="SizePreview">
+ <property name="name">
+ <cstring>previewer</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>3</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>250</width>
+ <height>50</height>
+ </size>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </hbox>
+</widget>
+<customwidgets>
+ <customwidget>
+ <class>SizePreview</class>
+ <header location="local">sizePreview.h</header>
+ <sizehint>
+ <width>-1</width>
+ <height>-1</height>
+ </sizehint>
+ <container>0</container>
+ <sizepolicy>
+ <hordata>7</hordata>
+ <verdata>7</verdata>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ <pixmap>image0</pixmap>
+ </customwidget>
+</customwidgets>
+<images>
+ <image name="image0">
+ <data format="PNG" length="1110">89504e470d0a1a0a0000000d4948445200000016000000160806000000c4b46c3b0000041d49444154388d8d95c18b1c4514c67fbb29e5b54ea05b26da1d36b08d09a6c508138cb8c13d647141163de49043bca9f1628eb9294810f24f88c15b728b07617358888785d980427290b4a8d00b19a8821da8228cf42316ac87eed9247ac95c9aeaeef9eaabdffb5ebf85f178ccfcf7f5b79fec07a7280a08a008f25ceb7c29e5da573716e65a0be3f198ef6f5ededff9b9e1b34faf90882092a1ea21428b9220ffbf46054055b19386ba6970ae6665b5e0d2c5eb0b066067bbe1f21757c88f5504eff0c192189081303a5582b16854fccce2fe041f00cdd0a8103b874556405476b62d972ec2c2b90ff3fd8df5cb946549d80b34aea15ccaa94625450e2d0e558b460b7371a734b5e027251a155545678ab62d7eea90b4c504078908c107acb354cb251b1f8f08b1c18631aabbb4d18211404804f22545863561d2f060fb34aa8a18d0086204e72c46a32292e1a796f278c1da7a859d8da9a737506db04d0a24103d8949480b214d3bbee952a05c1d536f9d2684160c744f048311543d459eb1b65ee1754cedae13a64abd5d6127053c9d0281f22d4f75c6a2118a5c09272d7ab740638bf4ef2dd2174032d0d8d04c6fe19c32bedd8bc65e342aa3f785e2784bfd6bc1bd9db24b05505616a4edd67d5a8c1801a03a9962754c504bf34b8986acfb9be91cac7d54315a15541b36b134f74bd2dc53940115a5381e087bc25c6f71be831a8baa234cc1ee3eeb74ed83116beb2b8849d108a3730e8ce27e2bfb82419a7b407ac7c222fd0e6280a8078ce64e47ef54ac9d5be9aaae0162e0de568a44a18d3df90845d919c4f01463406340a44f40efb43a99b371618488e2670d1a2d7ee6f1d3be39342104e937ed85fb86599c33e9ee0be9a004946259d8b858909880d59aa00daa0d3280b5f39e34074c4b3a5434029a76a9e9f5cc0163b5c80024158a1cfc4cb1d3061d5834066cb0a403c008599a70f6bc27b8d03106ea3ae91987278c5b143b015547224ab5e24185cd9b81665273e7b6e7cecd82ddbf8098002de94049737bc09828cf3036f31c3735c8b0e98eb704672f348c7f7c93cd1fb2ae905119ff54e0dff3542b0e9dd983dcea2cc5eea6cf303e74ec687af5c41b6fa38f5e203c7ec8e1238ef85831a214afef21060ea781ec68247b65c6916353cc8b73d1ae79354606af2a930709aa118da1636c274dd7e3774b884a79aa6b5711a538d33cf9c01c1c9b83bc6a1f55c91ccb23b05b1deb43a7decdaffefd2862f61366aa8449c69e33642f012f2bb208fa98eeda1f3346f076c8eeef19475e9be115423364f78f84105a8643d34d90cfbfdcd8cf872589a45dc7f54cf3134a36f4e495c23f9da8db15bccb708d4014f2ca512cb5d4f7c13e84300d5cff6eb39b202bab053bdb9674f0648609427d0f8402ddeac30f4fcd3ced3efc3b422d406c09b340bedc1571e1bfc3d44dc281634c5fe5e758e7395cfbe6d6c130fd17d92372d277c159b70000000049454e44ae426082</data>
+ </image>
+</images>
+<tabstops>
+ <tabstop>formatChoice</tabstop>
+ <tabstop>orientationChoice</tabstop>
+ <tabstop>widthInput</tabstop>
+ <tabstop>widthUnits</tabstop>
+ <tabstop>heightInput</tabstop>
+</tabstops>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>kcombobox.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>kcombobox.h</includehint>
+ <includehint>kcombobox.h</includehint>
+</includehints>
+</UI>
diff --git a/kviewshell/pageView.cpp b/kviewshell/pageView.cpp
new file mode 100644
index 00000000..c7813280
--- /dev/null
+++ b/kviewshell/pageView.cpp
@@ -0,0 +1,593 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Wilco Greven <greven@kde.org>
+ Copyright (C) 2002-2004 Stefan Kebekus <kebekus@kde.org>
+ Copyright (C) 2004-2005 Wilfried Huss <Wilfried.Huss@gmx.at>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <config.h>
+
+#include <kdebug.h>
+#include <qcursor.h>
+#include <qpainter.h>
+#include <qrect.h>
+#include <math.h>
+
+#include "pageView.h"
+#include "pageNumber.h"
+
+PageView::PageView( QWidget* parent, const char* name )
+ : QScrollView( parent, name, WStaticContents | WNoAutoErase)
+{
+ moveTool = true;
+
+ widgetList = 0;
+ viewport()->setFocusPolicy(QWidget::StrongFocus);
+
+ setResizePolicy(QScrollView::Manual);
+
+ setVScrollBarMode(QScrollView::Auto);
+ setHScrollBarMode(QScrollView::Auto);
+
+ viewport()->setBackgroundMode(Qt::NoBackground);
+
+ setResizePolicy(Manual);
+ setDragAutoScroll(false);
+
+ enableClipper(true);
+ nrCols = 1;
+ nrRows = 1;
+ continuousViewmode = true;
+ fullScreen = false;
+
+ connect(this, SIGNAL(contentsMoving(int, int)), this, SLOT(calculateCurrentPageNumber(int, int)));
+}
+
+
+void PageView::addChild( QPtrVector<DocumentWidget> *wdgList )
+{
+ if( wdgList == 0 ) {
+ kdError(1223) << "PageView::addChild(...) called with invalid arguments" << endl;
+ return;
+ }
+
+ widgetList = wdgList;
+ layoutPages();
+}
+
+
+bool PageView::atTop() const
+{
+ return verticalScrollBar()->value() == verticalScrollBar()->minValue();
+}
+
+
+bool PageView::atBottom() const
+{
+ return verticalScrollBar()->value() == verticalScrollBar()->maxValue();
+}
+
+
+bool PageView::readUp()
+{
+ if( atTop() )
+ return false;
+ else {
+ // Coordinate of the top of the viewport
+ int top = contentsY();
+
+ DocumentWidget* widget = 0;
+ // Find the widget(s) that intersect the top of the viewport
+ // TODO: It would be better to use a binary search.
+ for(Q_UINT16 i=0; i<widgetList->size(); i++)
+ {
+ widget = widgetList->at(i);
+ if (childY(widget) < top && childY(widget) + widget->height() > top)
+ {
+ // Draw scrollguide
+ widget->drawScrollGuide(top - childY(widget));
+ }
+ }
+
+ int newValue = QMAX( verticalScrollBar()->value() - (int)(height() * 0.9),
+ verticalScrollBar()->minValue() );
+ verticalScrollBar()->setValue( newValue );
+ return true;
+ }
+}
+
+
+bool PageView::readDown()
+{
+ if( atBottom() )
+ return false;
+ else {
+ // Coordinate of the bottom of the viewport
+ int bottom = contentsY() + visibleHeight();
+
+ DocumentWidget* widget = 0;
+ // Find the widget(s) that intersect the bottom of the viewport
+ // TODO: It would be better to use a binary search.
+ for(Q_UINT16 i=0; i<widgetList->size(); i++)
+ {
+ widget = widgetList->at(i);
+ if (childY(widget) < bottom && childY(widget) + widget->height() > bottom)
+ {
+ // Draw scrollguide
+ widget->drawScrollGuide(bottom - childY(widget));
+ }
+ }
+
+ int newValue = QMIN( verticalScrollBar()->value() + (int)(height() * 0.9),
+ verticalScrollBar()->maxValue() );
+ verticalScrollBar()->setValue( newValue );
+
+ return true;
+ }
+}
+
+
+void PageView::scrollRight()
+{
+ horizontalScrollBar()->addLine();
+}
+
+void PageView::scrollLeft()
+{
+ horizontalScrollBar()->subtractLine();
+}
+
+void PageView::scrollDown()
+{
+ verticalScrollBar()->addLine();
+}
+
+void PageView::scrollUp()
+{
+ verticalScrollBar()->subtractLine();
+}
+
+void PageView::scrollBottom()
+{
+ verticalScrollBar()->setValue( verticalScrollBar()->maxValue() );
+}
+
+void PageView::scrollTop()
+{
+ verticalScrollBar()->setValue( verticalScrollBar()->minValue() );
+}
+
+void PageView::keyPressEvent( QKeyEvent* e )
+{
+ switch ( e->key() ) {
+ case Key_Up:
+ scrollUp();
+ break;
+ case Key_Down:
+ scrollDown();
+ break;
+ case Key_Left:
+ scrollLeft();
+ break;
+ case Key_Right:
+ scrollRight();
+ break;
+ default:
+ e->ignore();
+ return;
+ }
+ e->accept();
+}
+
+void PageView::contentsMousePressEvent( QMouseEvent* e )
+{
+ if (e->button() == LeftButton)
+ {
+ if (moveTool)
+ {
+ setCursor(Qt::SizeAllCursor);
+ dragGrabPos = e->globalPos();
+ }
+ else
+ {
+ // we are in selection mode
+ }
+ }
+ else
+ {
+ setCursor(Qt::arrowCursor);
+ }
+}
+
+void PageView::contentsMouseReleaseEvent( QMouseEvent* )
+{
+ setCursor(Qt::arrowCursor);
+}
+
+void PageView::contentsMouseMoveEvent( QMouseEvent* e )
+{
+ QPoint newPos = e->globalPos();
+
+ if (e->state() == LeftButton && moveTool)
+ {
+ QPoint delta = dragGrabPos - newPos;
+ scrollBy(delta.x(), delta.y());
+ }
+ dragGrabPos = newPos;
+}
+
+void PageView::viewportResizeEvent( QResizeEvent* e )
+{
+ QScrollView::viewportResizeEvent( e );
+
+ if (!widgetList)
+ return;
+
+ layoutPages();
+
+ emit viewSizeChanged( viewport()->size() );
+}
+
+void PageView::setNrColumns( Q_UINT8 cols )
+{
+ nrCols = cols;
+}
+
+void PageView::setNrRows( Q_UINT8 rows )
+{
+ nrRows = rows;
+}
+
+void PageView::setContinuousViewMode(bool continuous)
+{
+ continuousViewmode = continuous;
+}
+
+bool PageView::singlePageFullScreenMode()
+{
+ return (nrCols == 1 && nrRows == 1 && !continuousViewmode && fullScreen);
+}
+
+void PageView::slotShowScrollbars(bool status)
+{
+ if (status == true) {
+ setVScrollBarMode(QScrollView::Auto);
+ setHScrollBarMode(QScrollView::Auto);
+ } else {
+ setVScrollBarMode(QScrollView::AlwaysOff);
+ setHScrollBarMode(QScrollView::AlwaysOff);
+ }
+}
+
+void PageView::setFullScreenMode(bool fullScreen)
+{
+ this -> fullScreen = fullScreen;
+ if (fullScreen == true)
+ {
+ setVScrollBarMode(QScrollView::AlwaysOff);
+ setHScrollBarMode(QScrollView::AlwaysOff);
+ oldFrameStyle = frameStyle();
+ setFrameStyle(QFrame::NoFrame);
+ backgroundColor = viewport()->paletteBackgroundColor();
+ if (singlePageFullScreenMode())
+ {
+ viewport()->setPaletteBackgroundColor( Qt::black ) ;
+ }
+ }
+ else
+ {
+ viewport()->setPaletteBackgroundColor( backgroundColor ) ;
+ setFrameStyle(oldFrameStyle);
+ }
+}
+
+void PageView::layoutPages(bool zoomChanged)
+{
+ // Paranoid safety check
+ if (widgetList == 0)
+ return;
+
+ // If there are no widgets, e.g. because the last widget has been
+ // removed, the matter is easy: set the contents size to 0. If there
+ // are no widgets because previously existing widgets were removed
+ // (we detect that by looking at the contentsWidth and -Height).
+ if (widgetList->isEmpty()) {
+ if ((contentsWidth() != 0) || (contentsHeight() != 0)) {
+ QScrollView::resizeContents(0,0);
+ }
+ return;
+ }
+
+ // Ok, now we are in a situation where we do have some widgets that
+ // shall be centered.
+ int distance = distanceBetweenWidgets;
+ if (singlePageFullScreenMode())
+ {
+ // In single page fullscreen mode we don't want a margin around the pages
+ distance = 0;
+ }
+
+ QMemArray<Q_UINT32> colWidth(nrCols);
+ for(Q_UINT8 i=0; i<colWidth.size(); i++)
+ colWidth[i] = 0;
+
+ Q_UINT16 numRows;
+ if(nrCols <= 2)
+ {
+ numRows = (widgetList->size()+2*nrCols-2) / nrCols;
+ }
+ else
+ {
+ numRows = (Q_INT16)ceil(((double)widgetList->size()) / nrCols);
+ }
+
+ QMemArray<Q_UINT32> rowHeight(numRows);
+ for(Q_UINT16 i=0; i<rowHeight.size(); i++)
+ rowHeight[i] = 0;
+
+ // Now find the widths and heights of the columns
+ for(Q_UINT16 i=0; i<widgetList->size(); i++)
+ {
+ Q_UINT8 col;
+ Q_UINT16 row;
+
+ if (nrCols == 2) {
+ // In two-column display, start with the right column
+ col = (i+1+nrCols) % nrCols;
+ row = (i+1+nrCols) / nrCols - 1;
+ } else {
+ col = (i+nrCols) % nrCols;
+ row = (i+nrCols) / nrCols - 1;
+ }
+
+ colWidth[col] = QMAX(colWidth[col], (Q_UINT32)widgetList->at(i)->pageSize().width());
+ rowHeight[row] = QMAX(rowHeight[row], (Q_UINT32)widgetList->at(i)->pageSize().height());
+ }
+
+ // Calculate the total width and height of the display
+ Q_UINT32 totalHeight = 0;
+ for(Q_UINT16 i=0; i<rowHeight.size(); i++)
+ totalHeight += rowHeight[i];
+
+ totalHeight += (numRows+1)*distance;
+ Q_UINT32 totalWidth = 0;
+ for(Q_UINT8 i=0; i<colWidth.size(); i++)
+ totalWidth += colWidth[i];
+
+ totalWidth += (nrCols+1)*distance;
+ QSize newViewportSize = viewportSize( totalWidth, totalHeight );
+ Q_UINT32 centeringLeft = 0;
+ if( (Q_UINT32)newViewportSize.width() > totalWidth )
+ centeringLeft = ( newViewportSize.width() - totalWidth )/2;
+ Q_UINT32 centeringTop = 0;
+ if( (Q_UINT32)newViewportSize.height() > totalHeight )
+ centeringTop = ( newViewportSize.height() - totalHeight)/2;
+
+ // Resize the viewport
+ if (((Q_UINT32)contentsWidth() != totalWidth) || ((Q_UINT32)contentsHeight() != totalHeight))
+ {
+ // Calculate the point in the coordinates of the contents which is currently at the center of the viewport.
+ QPoint midPoint = QPoint(visibleWidth() / 2 + contentsX(), visibleHeight() / 2 + contentsY());
+ double midPointRatioX = (double)(midPoint.x()) / contentsWidth();
+ double midPointRatioY = (double)(midPoint.y()) / contentsHeight();
+
+ resizeContents(totalWidth,totalHeight);
+
+ // If the zoom changed recenter the former midPoint
+ if (zoomChanged)
+ center((int)(contentsWidth() * midPointRatioX), (int)(contentsHeight() * midPointRatioY));
+ }
+
+ // Finally, calculate the left and top coordinates of each row and
+ // column, respectively
+ QMemArray<Q_UINT32> colLeft(nrCols);
+ colLeft[0] = distance;
+ for(Q_UINT8 i=1; i<colLeft.size(); i++)
+ colLeft[i] = colLeft[i-1]+colWidth[i-1]+distance;
+
+ QMemArray<Q_UINT32> rowTop(numRows);
+ rowTop[0] = distance;
+ for(Q_UINT16 i=1; i<rowTop.size(); i++)
+ rowTop[i] = rowTop[i-1]+rowHeight[i-1]+distance;
+
+ for(Q_UINT16 i=0; i<widgetList->size(); i++)
+ {
+ Q_UINT8 col;
+ Q_UINT16 row;
+ if (nrCols == 2)
+ {
+ // In two column-mode start with the right column.
+ col = (i+nrCols-1) % nrCols;
+ row = (i+nrCols-1) / nrCols;
+ }
+ else
+ {
+ col = (i+nrCols) % nrCols;
+ row = i / nrCols;
+ }
+ if (nrCols == 2)
+ {
+ // in 2-column mode right justify the first column, and leftjustify the second column
+ int width = widgetList->at(i)->width();
+ int left;
+ if (col == 0)
+ left = centeringLeft + colLeft[col] + colWidth[col]-width + distance/2;
+ else
+ left = centeringLeft + colLeft[col];
+ moveChild( widgetList->at(i), left, centeringTop+rowTop[row]);
+ }
+ else
+ {
+ // in single column and overview mode center the widgets
+ int widgetWidth = widgetList->at(i)->width();
+ int left = centeringLeft + colLeft[col] + ((int)colWidth[col]-widgetWidth)/2;
+ moveChild(widgetList->at(i), left, centeringTop+rowTop[row]);
+ }
+ }
+ calculateCurrentPageNumber();
+}
+
+
+void PageView::contentsWheelEvent ( QWheelEvent * e )
+{
+ emit(wheelEventReceived(e));
+}
+
+
+void PageView::moveViewportToWidget(QWidget* widget, int y)
+{
+ int verticalPos = 0;
+ int verticalPosTop = 0;
+
+ if (y != 0)
+ {
+ verticalPosTop = childY(widget) + y - visibleHeight()/2;
+ verticalPos = childY(widget) + y;
+ }
+ else
+ {
+ verticalPos = childY(widget) - distanceBetweenWidgets;
+ verticalPosTop = verticalPos;
+ }
+
+ if (nrCols == 1)
+ {
+ // In single column viewmodes, we change the vertical position only, to make it
+ // easier to work with high zoomlevels where not the whole pagewidth is visible.
+ // TODO: Smarter algorithm also for continuous facing viewmode.
+ int top = (int)(contentsY() + 0.1 * visibleHeight());
+ int bottom = (int)(contentsY() + 0.9 * visibleHeight());
+
+ // Move the viewport if the target is currently not visible, or lies at the edge
+ // of the viewport. If y = 0 always move the top of the targetpage to the top edge
+ // of the viewport.
+ if (verticalPos < top || verticalPos > bottom || y == 0)
+ {
+ setContentsPos(contentsX(), verticalPosTop);
+ }
+ }
+ else
+ {
+ setContentsPos(childX(widget) - distanceBetweenWidgets, verticalPosTop);
+ }
+}
+
+
+void PageView::viewportPaintEvent(QPaintEvent* e)
+{
+ // Region from which rectangles occupied by child widgets will by substracted.
+ QRegion backgroundArea(e->rect());
+
+ if (widgetList != 0)
+ {
+ for (unsigned int i = 0; i < widgetList->count(); i++)
+ {
+ DocumentWidget* item = widgetList->at(i);
+
+ // Check if the Widget needs to be updated.
+ if (!item->geometry().intersects(e->rect()))
+ continue;
+
+ QRect widgetGeometry = item->geometry();
+
+ // Draw the widget.
+ if (e->rect().intersects(widgetGeometry))
+ {
+ QRect widgetRect = e->rect().intersect(widgetGeometry);
+ widgetRect.moveBy(-widgetGeometry.left(), -widgetGeometry.top());
+
+ item->update(widgetRect);
+ }
+
+ // Substract the painted area.
+ backgroundArea -= widgetGeometry.intersect(e->rect());
+ }
+ }
+
+ // Paint the background.
+ QPainter p(viewport());
+
+ QMemArray<QRect> backgroundRects = backgroundArea.rects();
+
+ for (unsigned int i = 0; i < backgroundRects.count(); i++)
+ p.fillRect(backgroundRects[i], colorGroup().mid());
+}
+
+
+void PageView::calculateCurrentPageNumber(int x, int y)
+{
+ // Safety check
+ if (widgetList == 0)
+ return;
+
+ QRect viewportRect(x, y, visibleWidth(), visibleHeight());
+
+ //kdDebug() << "viewportRect(" << viewportRect.x() << ", " << viewportRect.y() << ", "
+ // << viewportRect.width() << ", " << viewportRect.height() << ")" << endl;
+
+ int maxVisiblePixels = 0;
+ DocumentWidget* _currentWidget = 0;
+
+ for (Q_UINT16 i = 0; i < widgetList->size(); i++)
+ {
+ DocumentWidget* documentWidget = widgetList->at(i);
+ // Safety check
+ if (documentWidget == 0)
+ continue;
+
+ // Check if the Widget is visible
+ int cx = childX(documentWidget);
+ int cy = childY(documentWidget);
+ QRect widgetRect(cx, cy, documentWidget->width(), documentWidget->height());
+ bool isVisible = widgetRect.intersects(viewportRect);
+
+ if (!isVisible)
+ continue;
+
+ // Calculate the number of visible pixels of the widget
+ QRect visibleRect = widgetRect.intersect(viewportRect);
+ int visiblePixels = visibleRect.width() * visibleRect.height();
+
+ //kdDebug() << visiblePixels << " pixels are visible of page " << documentWidget->getPageNumber() << endl;
+
+ // If a bigger part of this widget as of the previous widgets is visible make it the current widget.
+ if (maxVisiblePixels < visiblePixels)
+ {
+ maxVisiblePixels = visiblePixels;
+ _currentWidget = documentWidget;
+ }
+ }
+
+ // No page is visible
+ if (_currentWidget == 0)
+ return;
+
+ // Return the number of the current page
+ emit currentPageChanged(_currentWidget->getPageNumber());
+}
+
+void PageView::calculateCurrentPageNumber()
+{
+ calculateCurrentPageNumber(contentsX(), contentsY());
+}
+
+void PageView::slotEnableMoveTool(bool enable)
+{
+ moveTool = enable;
+}
+
+#include "pageView.moc"
diff --git a/kviewshell/pageView.h b/kviewshell/pageView.h
new file mode 100644
index 00000000..d87ae0ca
--- /dev/null
+++ b/kviewshell/pageView.h
@@ -0,0 +1,175 @@
+// -*- C++ -*-
+/* This file is part of the KDE project
+ Copyright (C) 2001 Wilco Greven <greven@kde.org>
+ Copyright (C) 2004-2005 Wilfried Huss <Wilfried.Huss@gmx.at>
+ Copyright (C) 2005 Stefan Kebekus <kebekus@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef PAGEVIEW_H
+#define PAGEVIEW_H
+
+#include "documentWidget.h"
+
+#include <qptrvector.h>
+#include <qscrollview.h>
+
+class PageNumber;
+
+/*
+ * PageView is a customized QScrollView, which can hold one
+ * page. This page will be centered on the viewport.
+ */
+class PageView : public QScrollView
+{
+ Q_OBJECT
+
+public:
+ PageView( QWidget* parent = 0, const char* name = 0 );
+ ~PageView() {}
+
+ void addChild( QPtrVector<DocumentWidget> *wdgList );
+
+ /** Sets the number of columns into which the widgets are
+ aligned. If nothing is set, '2' is the default. */
+ void setNrColumns( Q_UINT8 cols );
+ void setNrRows( Q_UINT8 rows );
+
+ void setContinuousViewMode(bool continuous);
+ bool fullScreenMode() { return fullScreen; }
+ bool singlePageFullScreenMode();
+ bool overviewMode() { return !continuousViewmode && (nrRows > 1 || nrCols > 1); }
+
+ /** Returns the number of columns into which the widgets are aligned.
+
+ This method returns the number of colums actually used to display
+ the widgets.
+
+ @warning This method need not return the number columns set in the
+ setViewMode() method. For instance, if the viewmode
+ KVSPrefs::EnumViewMode::ContinuousFacing is set, but there is only
+ one widget, then only one column is used, and the method returns
+ the number one.
+
+ If there aren't any widgets, the number 1 is returned.
+
+ @returns Number of columns used, or 1 if there aren't any
+ widgets. The number i returned always satisfies 1 <= i <= nrCols,
+ where nrCols is the private variable of the same nane.
+ */
+ Q_UINT8 getNrColumns() const { return (widgetList==0) ? 1 : QMIN(nrCols, QMAX(1, widgetList->size())); }
+
+ Q_UINT8 getNrRows() const { return nrRows; }
+ bool isContinuous() const { return continuousViewmode; }
+
+ /** Return true if the top resp. bottom of the page is visible. */
+ bool atTop() const;
+ bool atBottom() const;
+
+ /** Distance between pages in pixels (this is independent of
+ the zoom level). */
+ int distanceBetweenPages() { return distanceBetweenWidgets; }
+
+ /** Moves the viewport so that the widget is at the top left corner. */
+ void moveViewportToWidget(QWidget* widget, int y = 0);
+
+ bool isMoveToolEnabled() const { return moveTool; }
+
+public slots:
+ void calculateCurrentPageNumber();
+
+ bool readUp();
+ bool readDown();
+ void scrollUp();
+ void scrollDown();
+ void scrollRight();
+ void scrollLeft();
+ void scrollBottom();
+ void scrollTop();
+
+ void setFullScreenMode(bool fullScreen);
+ /** Turn the scrollbars on/off. */
+ void slotShowScrollbars(bool);
+
+ /** Set layout of the page widgets according to the current viewmode and zoomlevel.
+ Set zoomChanged = true if the the layout needs updateing because the zoomlevel has changed. */
+ void layoutPages(bool zoomChanged = false);
+
+ void slotEnableMoveTool(bool enable);
+
+signals:
+ void viewSizeChanged(const QSize& size);
+ void pageSizeChanged(const QSize& size);
+
+ void currentPageChanged(const PageNumber&);
+
+ /** This signal is emitted when the scrollView receives a mouse
+ wheel event. */
+ void wheelEventReceived( QWheelEvent * );
+
+protected:
+ void keyPressEvent( QKeyEvent* );
+
+ /** Reimplemented from QScrollView to make sure that the page is
+ centered when it fits in the viewport. */
+ void viewportResizeEvent( QResizeEvent* );
+ void viewportPaintEvent(QPaintEvent*);
+
+ /** Reimplemented from QScrollView, because the kviepart needs to
+ handle the wheel events itself. The wheel event is passed on by
+ emitting the singal "wheelEventReceived". Nothing else is done. */
+ void contentsWheelEvent ( QWheelEvent * );
+
+ void contentsMousePressEvent(QMouseEvent*);
+ void contentsMouseReleaseEvent(QMouseEvent*);
+ void contentsMouseMoveEvent(QMouseEvent*);
+
+private slots:
+ void calculateCurrentPageNumber(int x, int y);
+
+private:
+ /** Stores the mouse position between two mouse events. This is used
+ to implement the "grab and drag the viewport contents" feature. */
+ QPoint dragGrabPos;
+
+ QPtrVector<DocumentWidget>* widgetList;
+
+ /** Used internally by the centerContents()-method. Set with the
+ setNrColumns() method */
+ Q_UINT8 nrCols;
+ Q_UINT8 nrRows;
+
+ bool continuousViewmode;
+ bool fullScreen;
+
+ /** This int remembers the style of the frame of the centering
+ scrollview when fullscreen mode is switched on. It is then
+ restored when it is switched off. */
+ int oldFrameStyle;
+
+ /** color of the viewport's background. This is also
+ stored on entering the fullscreen mode. */
+ QColor backgroundColor;
+
+ /** Distance between pages in pixels
+ (this is independent of the zoom level). */
+ static const int distanceBetweenWidgets=10;
+
+ bool moveTool;
+};
+
+#endif
diff --git a/kviewshell/pics/Makefile.am b/kviewshell/pics/Makefile.am
new file mode 100644
index 00000000..80777a5d
--- /dev/null
+++ b/kviewshell/pics/Makefile.am
@@ -0,0 +1,3 @@
+SUBDIRS = icons
+
+KDE_ICON = kviewshell
diff --git a/kviewshell/pics/cr16-app-kviewshell.png b/kviewshell/pics/cr16-app-kviewshell.png
new file mode 100644
index 00000000..f9b15a18
--- /dev/null
+++ b/kviewshell/pics/cr16-app-kviewshell.png
Binary files differ
diff --git a/kviewshell/pics/cr32-app-kviewshell.png b/kviewshell/pics/cr32-app-kviewshell.png
new file mode 100644
index 00000000..abb2830e
--- /dev/null
+++ b/kviewshell/pics/cr32-app-kviewshell.png
Binary files differ
diff --git a/kviewshell/pics/cr48-app-kviewshell.png b/kviewshell/pics/cr48-app-kviewshell.png
new file mode 100644
index 00000000..6faaec42
--- /dev/null
+++ b/kviewshell/pics/cr48-app-kviewshell.png
Binary files differ
diff --git a/kviewshell/pics/icons/Makefile.am b/kviewshell/pics/icons/Makefile.am
new file mode 100644
index 00000000..f1dcd108
--- /dev/null
+++ b/kviewshell/pics/icons/Makefile.am
@@ -0,0 +1,3 @@
+kviewparticondir = $(kde_datadir)/kviewerpart/icons
+
+kviewparticon_ICON = AUTO
diff --git a/kviewshell/pics/icons/hi16-action-movetool.png b/kviewshell/pics/icons/hi16-action-movetool.png
new file mode 100644
index 00000000..11a69bdd
--- /dev/null
+++ b/kviewshell/pics/icons/hi16-action-movetool.png
Binary files differ
diff --git a/kviewshell/pics/icons/hi16-action-selectiontool.png b/kviewshell/pics/icons/hi16-action-selectiontool.png
new file mode 100644
index 00000000..d9a0eba6
--- /dev/null
+++ b/kviewshell/pics/icons/hi16-action-selectiontool.png
Binary files differ
diff --git a/kviewshell/pics/icons/hi22-action-movetool.png b/kviewshell/pics/icons/hi22-action-movetool.png
new file mode 100644
index 00000000..ccb0823c
--- /dev/null
+++ b/kviewshell/pics/icons/hi22-action-movetool.png
Binary files differ
diff --git a/kviewshell/pics/icons/hi22-action-selectiontool.png b/kviewshell/pics/icons/hi22-action-selectiontool.png
new file mode 100644
index 00000000..6d9a797b
--- /dev/null
+++ b/kviewshell/pics/icons/hi22-action-selectiontool.png
Binary files differ
diff --git a/kviewshell/pics/icons/hi32-action-movetool.png b/kviewshell/pics/icons/hi32-action-movetool.png
new file mode 100644
index 00000000..134c76d2
--- /dev/null
+++ b/kviewshell/pics/icons/hi32-action-movetool.png
Binary files differ
diff --git a/kviewshell/pics/icons/hi48-action-movetool.png b/kviewshell/pics/icons/hi48-action-movetool.png
new file mode 100644
index 00000000..8d51a696
--- /dev/null
+++ b/kviewshell/pics/icons/hi48-action-movetool.png
Binary files differ
diff --git a/kviewshell/plugins/Makefile.am b/kviewshell/plugins/Makefile.am
new file mode 100644
index 00000000..c81110a2
--- /dev/null
+++ b/kviewshell/plugins/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = 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 <kaction.h>
+#include <kdialogbase.h>
+#include <kfiledialog.h>
+#include <kparts/genericfactory.h>
+#include <kprinter.h>
+#include <ktempfile.h>
+#include "kvsprefs.h"
+#include <qapplication.h>
+#include <qpaintdevicemetrics.h>
+#include <qprinter.h>
+#include <qtooltip.h>
+
+#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<DjVuMultiPage> 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<int> 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("<qt><strong>File error.</strong> Unable to write to the specified file '%1'. The document is <strong>not</strong> saved.</qt>").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 <qstringlist.h>
+
+#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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
+ http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
+ <kcfgfile name="djvumultipagerc" />
+ <group name="djvu">
+ <entry key="RenderMode" type="Enum">
+ <default>Color</default>
+ <choices>
+ <choice name="Color" />
+ <choice name="BlackAndWhite" />
+ <choice name="Foreground" />
+ <choice name="Background" />
+ </choices>
+ </entry>
+ </group>
+</kcfg>
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 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui name="djvumultipage" version="3">
+ <MenuBar>
+
+ <Menu name="edit"><text>&amp;Edit</text>
+ <Separator/>
+ <Action name="delete_pages"/>
+ </Menu>
+
+ <Menu name="view"><text>&amp;View</text>
+ <Action name="render_mode"/>
+ </Menu>
+
+ </MenuBar>
+</kpartgui>
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 <kmessagebox.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <qfileinfo.h>
+#include <qimage.h>
+#include <qpainter.h>
+#include <kapp.h>
+
+#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<DjVuImage> 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<RenderedDocumentPagePixmap*>(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<GPixmap> 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<GBitmap> 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<DjVuTXT> 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("<qt><strong>File error.</strong> The specified file '%1' does not exist.</qt>").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("<qt><strong>File error.</strong> The specified file '%1' could not be loaded.</qt>").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<DjVuImage> djvuPage)
+{
+ GP<ByteStream> annotations = djvuPage->get_anno();
+ if (!(annotations && annotations->size()))
+ return;
+
+ GP<DjVuANT> ant = DjVuANT::create();
+
+ GP<IFFByteStream> iff = IFFByteStream::create(annotations);
+
+ GUTF8String chkid;
+
+ while (iff->get_chunk(chkid))
+ {
+ if (chkid == "ANTa")
+ {
+ ant->merge(*iff->get_bytestream());
+ }
+ else if (chkid == "ANTz")
+ {
+ GP<ByteStream> 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<GMapArea> 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; i<numPages; i++) {
+ // Keep the GUI updated
+ if (i%100 == 0)
+ kapp->processEvents();
+
+ GP<DjVuFile> 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<DjVuTXT> DjVuRenderer::getText(PageNumber pageNumber)
+{
+ GUTF8String chkid;
+
+ const GP<DjVuFile> file = document->get_djvu_file(pageNumber);
+ const GP<ByteStream> bs(file->get_text());
+ if (bs)
+ {
+ long int i=0;
+ const GP<IFFByteStream> iff(IFFByteStream::create(bs));
+ while (iff->get_chunk(chkid))
+ {
+ i++;
+ if (chkid == GUTF8String("TXTa"))
+ {
+ GP<DjVuTXT> txt = DjVuTXT::create();
+ txt->decode(iff->get_bytestream());
+ return txt;
+ }
+ else if (chkid == GUTF8String("TXTz"))
+ {
+ GP<DjVuTXT> txt = DjVuTXT::create();
+ GP<ByteStream> bsiff=BSByteStream::create(iff->get_bytestream());
+ txt->decode(bsiff);
+ return txt;
+ }
+ iff->close_chunk();
+ }
+ }
+ return 0;
+}
+
+void DjVuRenderer::fillInText(RenderedDocumentPage* page, const GP<DjVuTXT>& 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<DjVuFile> file, int& width, int& height, int& dpi)
+{
+ if (!file || !file->is_all_data_present())
+ return false;
+
+ const GP<ByteStream> pbs(file->get_djvu_bytestream(false, false));
+ const GP<IFFByteStream> 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<ByteStream> gbs = iff->get_bytestream();
+ GP<DjVuInfo> 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<ByteStream> 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<DjVuTXT> pageText = getText(pageNumber);
+
+ if (pageText)
+ {
+ GP<DjVuFile> 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<int> &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<ByteStream> obs = ByteStream::create(outname, "w");
+
+ QString pagename;
+ QValueList<int>::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<DjVuDocEditor> document_new = document;
+ document = 0;
+
+ // Delete pages
+ if (pdialog == 0) {
+ GList<int> 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 <kprogress.h>
+#include <qpixmap.h>
+
+#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<int> &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<DjVuImage> djvuPage);
+
+ bool getPageInfo(GP<DjVuFile> file, int& width, int& height, int& dpi);
+
+ GP<DjVuTXT> getText(PageNumber pageNumber);
+
+ void fillInText(RenderedDocumentPage* page, const GP<DjVuTXT>& text, DjVuTXT::Zone& zone, QSize& djvuPageSize);
+
+ GP<DjVuDocEditor> 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<ByteStream> 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 <klocale.h>
+#include <qlayout.h>
+#include <qcheckbox.h>
+#include <qcombobox.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+#include <kdebug.h>
+
+#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<QString,QString>& 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<QString,QString>& 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 <kdeprint/kprintdialogpage.h>
+
+
+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<QString,QString>& opts, bool incldef = false );
+ void setOptions( const QMap<QString,QString>& 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 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>kprintDialogPage_DJVUconversionoptions_basewidget</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>kprintDialogPage_DJVUconversionoptions_basewidget</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>548</width>
+ <height>126</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>PostScript language level:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Render mode:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="0" column="1">
+ <item>
+ <property name="text">
+ <string>Level 1 (almost obsolete)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Level 2 (default)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Level 3 (might print faster)</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>psLevel</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;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.&lt;/p&gt;
+&lt;p&gt;&lt;b&gt;Level 1:&lt;/b&gt; 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.&lt;/p&gt;
+&lt;p&gt;&lt;b&gt;Level 2:&lt;/b&gt; Level 2 PostScript files are much smaller and print much faster than Level 1 files. Level 2 files are supported by almost all printers.&lt;/p&gt;
+&lt;p&gt;&lt;b&gt;Level 3:&lt;/b&gt; 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.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="1" column="1">
+ <item>
+ <property name="text">
+ <string>Print Full Page (default)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Black &amp; White</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Foreground Only</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Background Only</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>renderMode</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>0</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string>&lt;p&gt;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.&lt;/p&gt;
+&lt;p&gt;&lt;b&gt;Print Full Page:&lt;/b&gt; The full page, including foreground and background will be printed, either in color or in grayscale.&lt;/p&gt;
+&lt;p&gt;&lt;b&gt;Black &amp; White:&lt;/b&gt; 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.&lt;/p&gt;
+&lt;p&gt;&lt;b&gt;Foreground Only:&lt;/b&gt; This option is useful if the background of the page is disturbing and affects the readability of the text.&lt;/p&gt;
+&lt;p&gt;&lt;b&gt;Background Only:&lt;/b&gt; Print only the background of the page.&lt;/p&gt;</string>
+ </property>
+ </widget>
+ <spacer row="2" column="1">
+ <property name="name">
+ <cstring>spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </grid>
+</widget>
+<layoutdefaults spacing="6" margin="0"/>
+</UI>
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 <klocale.h>
+#include <qbuttongroup.h>
+#include <qcheckbox.h>
+#include <qlayout.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+#include <kdebug.h>
+
+#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( "<qt><p>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.</p>"
+ "<p><b>Note:</b> 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.</p></qt>" ) );
+ 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( "<qt><p>If this option is enabled, all pages will be scaled to optimally fit the printer's "
+ "paper size.</p>"
+ "<p><b>Note:</b> 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.</p></qt>" ) );
+ kprintDialogPage_pageoptions_baseLayout->addWidget( checkBox_fitpage );
+ }
+
+ kprintDialogPage_pageoptions_baseLayout->addStretch();
+
+ resize( QSize(319, 166).expandedTo(minimumSizeHint()) );
+ clearWState( WState_Polished );
+}
+
+
+
+void KPrintDialogPage_DJVUPageOptions::getOptions( QMap<QString,QString>& 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<QString,QString>& 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 <kdeprint/kprintdialogpage.h>
+
+
+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<QString,QString>& opts, bool incldef = false );
+ void setOptions( const QMap<QString,QString>& 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<char>
+ByteStream::get_data(void)
+{
+ const int s=size();
+ if(s > 0)
+ {
+ TArray<char> data(0, s-1);
+ readat((char*)data, s, 0);
+ return data;
+ }else
+ {
+ TArray<char> 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 <string.h>
+
+#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 <eaf@geocities.com> -- 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<GString> 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 TYPE>
+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<TYPE>#. */
+ 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 <class TYPE> inline
+ArrayBaseT<TYPE>::operator TYPE* ()
+{
+ check();
+
+ ArrayRep * rep=(ArrayRep *) get();
+ return &((TYPE *) rep->data)[-rep->minlo];
+}
+
+#ifndef __MWERKS__ //MCW can't compile
+template <class TYPE> inline
+ArrayBaseT<TYPE>::operator const TYPE* ()
+{
+ const ArrayRep * rep=(const ArrayRep *) get();
+ return &((const TYPE *) rep->data)[-rep->minlo];
+}
+#endif
+
+template <class TYPE> inline
+ArrayBaseT<TYPE>::operator const TYPE* () const
+{
+ const ArrayRep * rep=(const ArrayRep *) get();
+ return &((const TYPE *) rep->data)[-rep->minlo];
+}
+
+template <class TYPE> inline TYPE&
+ArrayBaseT<TYPE>::operator[](int n)
+{
+ check();
+
+ ArrayRep * rep=(ArrayRep *) get();
+ if (n<rep->lobound || n>rep->hibound)
+ G_THROW( ERR_MSG("arrays.ill_sub") );
+ return ((TYPE *) rep->data)[n - rep->minlo];
+}
+
+template <class TYPE> inline const TYPE&
+ArrayBaseT<TYPE>::operator[](int n) const
+{
+ const ArrayRep * rep=(const ArrayRep *) get();
+ if (n<rep->lobound || n>rep->hibound)
+ G_THROW( ERR_MSG("arrays.ill_sub") );
+ return ((const TYPE *) rep->data)[n - rep->minlo];
+}
+
+template <class TYPE> inline void
+ArrayBaseT<TYPE>::ins(int n, const TYPE &val, unsigned int howmany)
+{
+ check();
+
+ ((ArrayRep *) get())->ins(n, &val, howmany);
+}
+
+template <class TYPE> void
+ArrayBaseT<TYPE>::sort()
+{
+ sort(lbound(), hbound());
+}
+
+template <class TYPE> void
+ArrayBaseT<TYPE>::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<TYPE># 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 TYPE>
+class TArray : public ArrayBaseT<TYPE> {
+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 <class TYPE> void
+TArray<TYPE>::destroy(void * data, int lo, int hi)
+{
+}
+
+template <class TYPE> void
+TArray<TYPE>::init1(void * data, int lo, int hi)
+{
+}
+
+template <class TYPE> void
+TArray<TYPE>::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 <class TYPE> void
+TArray<TYPE>::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<howmany;i++)
+ ((TYPE *) data)[where+i]=*(TYPE *) what;
+}
+
+template <class TYPE>
+TArray<TYPE>::TArray ()
+{
+ this->assign(new ArrayRep(sizeof(TYPE), destroy, init1,
+ init2, init2, insert));
+}
+
+template <class TYPE>
+TArray<TYPE>::TArray(int hi)
+{
+ this->assign(new ArrayRep(sizeof(TYPE), destroy, init1,
+ init2, init2, insert, hi));
+}
+
+template <class TYPE>
+TArray<TYPE>::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<TYPE># 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 TYPE>
+class DArray : public ArrayBaseT<TYPE> {
+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 <class TYPE> void
+DArray<TYPE>::destroy(void * data, int lo, int hi)
+{
+ if (data)
+ for(int i=lo;i<=hi;i++)
+ ((TYPE *) data)[i].TYPE::~TYPE();
+}
+
+template <class TYPE> void
+DArray<TYPE>::init1(void * data, int lo, int hi)
+{
+ if (data)
+ for(int i=lo;i<=hi;i++)
+ new ((void *) &((TYPE *) data)[i]) TYPE;
+}
+
+template <class TYPE> void
+DArray<TYPE>::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 <class TYPE> void
+DArray<TYPE>::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 <class TYPE> inline void
+DArray<TYPE>::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 <class TYPE> inline
+DArray<TYPE>::DArray ()
+{
+ this->assign(new ArrayRep(sizeof(TYPE), destroy, init1,
+ init2, copy, insert));
+}
+
+template <class TYPE> inline
+DArray<TYPE>::DArray(const int hi)
+{
+ this->assign(new ArrayRep(sizeof(TYPE), destroy, init1,
+ init2, copy, insert, hi));
+}
+
+template <class TYPE> inline
+DArray<TYPE>::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<GP<Dialog> ># or #DArray<GP<Button> >#.
+ 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<Dialog># and #GP<Button>#. In reality though,
+ all \Ref{GP} pointers have absolutely the same binary structure because
+ they are derived from \Ref{GPBase} class and do not add any variables
+ or virtual functions. That's why it's possible to instantiate \Ref{DArray}
+ only once for \Ref{GPBase} elements and then just cast types.
+
+ To implement this idea we have created this #DPArray<TYPE># class,
+ which can be used instead of #DArray<GP<TYPE> >#. It behaves absolutely
+ the same way as \Ref{DArray} but has one big advantage: overhead of
+ using #DPArray# with one more type is negligible.
+ */
+template <class TYPE>
+class DPArray : public DArray<GPBase> {
+public:
+ // -- CONSTRUCTORS
+ DPArray();
+ DPArray(int hibound);
+ DPArray(int lobound, int hibound);
+ DPArray(const DPArray<TYPE> &gc);
+ // -- DESTRUCTOR
+ virtual ~DPArray();
+ // -- ACCESS
+ GP<TYPE>& operator[](int n);
+ const GP<TYPE>& operator[](int n) const;
+ // -- CONVERSION
+ operator GP<TYPE>* ();
+
+#ifndef __MWERKS__ //MCW can't compile
+ operator const GP<TYPE>* ();
+#endif
+
+ operator const GP<TYPE>* () const;
+ // -- ALTERATION
+ void ins(int n, const GP<TYPE> &val, unsigned int howmany=1);
+ DPArray<TYPE>& operator= (const DPArray &ga);
+};
+
+template<class TYPE>
+DPArray<TYPE>::DPArray() {}
+
+template<class TYPE>
+DPArray<TYPE>::DPArray(int hibound) :
+ DArray<GPBase>(hibound) {}
+
+template<class TYPE>
+DPArray<TYPE>::DPArray(int lobound, int hibound) :
+ DArray<GPBase>(lobound, hibound) {}
+
+template<class TYPE>
+DPArray<TYPE>::DPArray(const DPArray<TYPE> &gc) :
+ DArray<GPBase>(gc) {}
+
+template<class TYPE>
+DPArray<TYPE>::~DPArray() {}
+
+template<class TYPE>
+inline GP<TYPE> &
+DPArray<TYPE>::operator[](int n)
+{
+ return (GP<TYPE> &) DArray<GPBase>::operator[](n);
+}
+
+template<class TYPE>
+inline const GP<TYPE> &
+DPArray<TYPE>::operator[](int n) const
+{
+ return (const GP<TYPE> &) DArray<GPBase>::operator[](n);
+}
+
+template<class TYPE>
+inline DPArray<TYPE>::operator GP<TYPE>* ()
+{
+ return (GP<TYPE> *) DArray<GPBase>::operator GPBase*();
+}
+
+#ifndef __MWERKS__ //MCW can't compile
+template<class TYPE>
+inline DPArray<TYPE>::operator const GP<TYPE>* ()
+{
+ return (const GP<TYPE> *) DArray<GPBase>::operator const GPBase*();
+}
+#endif
+
+template<class TYPE>
+inline DPArray<TYPE>::operator const GP<TYPE>* () const
+{
+ return (const GP<TYPE> *) DArray<GPBase>::operator const GPBase*();
+}
+
+template<class TYPE>
+inline void
+DPArray<TYPE>::ins(int n, const GP<TYPE> & val, unsigned int howmany)
+{
+ DArray<GPBase>::ins(n, val, howmany);
+}
+
+template<class TYPE>
+inline DPArray<TYPE> &
+DPArray<TYPE>::operator= (const DPArray &ga)
+{
+ DArray<GPBase>::operator=(ga);
+ return *this;
+}
+
+// ------------ THE END
+
+//@}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
+
diff --git a/kviewshell/plugins/djvu/libdjvu/BSByteStream.cpp b/kviewshell/plugins/djvu/libdjvu/BSByteStream.cpp
new file mode 100644
index 00000000..77334a45
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/BSByteStream.cpp
@@ -0,0 +1,465 @@
+//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: BSByteStream.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
+
+// - Author: Leon Bottou, 07/1998
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "BSByteStream.h"
+#undef BSORT_TIMER
+#ifdef BSORT_TIMER
+#include "GOS.h"
+#endif
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+class BSByteStream::Decode : public BSByteStream
+{
+public:
+ /** Creates a Static object for allocating the memory area of
+ length #sz# starting at address #buffer#. */
+ Decode(GP<ByteStream> bs);
+ ~Decode();
+ void init(void);
+ // Virtual functions
+ virtual size_t read(void *buffer, size_t sz);
+ virtual void flush(void);
+protected:
+ unsigned int decode(void);
+private:
+ bool eof;
+};
+
+// ========================================
+// --- Assertion
+
+#define ASSERT(expr) do{if(!(expr))G_THROW("assertion ("#expr") failed");}while(0)
+
+// ========================================
+// --- Construction
+
+BSByteStream::BSByteStream(GP<ByteStream> xbs)
+: offset(0), bptr(0), blocksize(0), size(0), bs(xbs),
+ gbs(xbs), gdata(data,0)
+{
+ // Initialize context array
+ memset(ctx, 0, sizeof(ctx));
+}
+
+BSByteStream::~BSByteStream() {}
+
+BSByteStream::Decode::Decode(GP<ByteStream> xbs)
+: BSByteStream(xbs), eof(false) {}
+
+void
+BSByteStream::Decode::init(void)
+{
+ gzp=ZPCodec::create(gbs,false,true);
+}
+
+BSByteStream::Decode::~Decode() {}
+
+GP<ByteStream>
+BSByteStream::create(GP<ByteStream> xbs)
+{
+ BSByteStream::Decode *rbs=new BSByteStream::Decode(xbs);
+ GP<ByteStream> retval=rbs;
+ rbs->init();
+ return retval;
+}
+
+void
+BSByteStream::Decode::flush()
+{
+ size = bptr = 0;
+}
+
+// ========================================
+// -- Decoding
+
+
+static int
+decode_raw(ZPCodec &zp, int bits)
+{
+ int n = 1;
+ const int m = (1<<bits);
+ while (n < m)
+ {
+ const int b = zp.decoder();
+ n = (n<<1) | b;
+ }
+ return n - m;
+}
+
+static inline int
+decode_binary(ZPCodec &zp, BitContext *ctx, int bits)
+{
+ int n = 1;
+ int m = (1<<bits);
+ ctx = ctx - 1;
+ while (n < m)
+ {
+ int b = zp.decoder(ctx[n]);
+ n = (n<<1) | b;
+ }
+ return n - m;
+}
+
+
+static inline void
+assignmtf(unsigned char xmtf[256])
+{
+ static const unsigned char mtf[256]={
+ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+ 0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+ 0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
+ 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
+ 0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
+ 0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
+ 0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
+ 0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
+ 0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
+ 0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
+ 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
+ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
+ 0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
+ 0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
+ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,
+ 0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
+ 0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
+ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,
+ 0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,
+ 0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
+ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
+ 0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF};
+ memcpy(xmtf,mtf,sizeof(mtf));
+}
+
+unsigned int
+BSByteStream::Decode::decode(void)
+{
+ /////////////////////////////////
+ //////////// Decode input stream
+
+ int i;
+ // Decode block size
+ ZPCodec &zp=*gzp;
+ size = decode_raw(zp, 24);
+ if (!size)
+ return 0;
+ if (size>MAXBLOCK*1024)
+ G_THROW( ERR_MSG("ByteStream.corrupt") );
+ // Allocate
+ if ((int)blocksize < size)
+ {
+ blocksize = size;
+ if (data)
+ {
+ gdata.resize(0);
+ }
+ }
+ if (! data)
+ gdata.resize(blocksize);
+ // Decode Estimation Speed
+ int fshift = 0;
+ if (zp.decoder())
+ {
+ fshift += 1;
+ if (zp.decoder())
+ fshift += 1;
+ }
+ // Prepare Quasi MTF
+ static const unsigned char xmtf[256]={
+ 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+ 0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
+ 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+ 0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
+ 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
+ 0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
+ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
+ 0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
+ 0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,
+ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,
+ 0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F,
+ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
+ 0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
+ 0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
+ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
+ 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
+ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
+ 0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
+ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
+ 0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
+ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,
+ 0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
+ 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
+ 0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
+ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,
+ 0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
+ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,
+ 0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
+ 0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
+ 0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF};
+ unsigned char mtf[256];
+ memcpy(mtf,xmtf,sizeof(xmtf));
+ unsigned int freq[FREQMAX];
+ memset(freq,0,sizeof(freq));
+ int fadd = 4;
+ // Decode
+ int mtfno = 3;
+ int markerpos = -1;
+ for (i=0; i<size; i++)
+ {
+ int ctxid = CTXIDS-1;
+ if (ctxid>mtfno) ctxid=mtfno;
+ BitContext *cx = ctx;
+ if (zp.decoder(cx[ctxid]))
+ { mtfno=0; data[i]=mtf[mtfno]; goto rotate; }
+ cx+=CTXIDS;
+ if (zp.decoder(cx[ctxid]))
+ { mtfno=1; data[i]=mtf[mtfno]; goto rotate; }
+ cx+=CTXIDS;
+ if (zp.decoder(cx[0]))
+ { mtfno=2+decode_binary(zp,cx+1,1); data[i]=mtf[mtfno]; goto rotate; }
+ cx+=1+1;
+ if (zp.decoder(cx[0]))
+ { mtfno=4+decode_binary(zp,cx+1,2); data[i]=mtf[mtfno]; goto rotate; }
+ cx+=1+3;
+ if (zp.decoder(cx[0]))
+ { mtfno=8+decode_binary(zp,cx+1,3); data[i]=mtf[mtfno]; goto rotate; }
+ cx+=1+7;
+ if (zp.decoder(cx[0]))
+ { mtfno=16+decode_binary(zp,cx+1,4); data[i]=mtf[mtfno]; goto rotate; }
+ cx+=1+15;
+ if (zp.decoder(cx[0]))
+ { mtfno=32+decode_binary(zp,cx+1,5); data[i]=mtf[mtfno]; goto rotate; }
+ cx+=1+31;
+ if (zp.decoder(cx[0]))
+ { mtfno=64+decode_binary(zp,cx+1,6); data[i]=mtf[mtfno]; goto rotate; }
+ cx+=1+63;
+ if (zp.decoder(cx[0]))
+ { mtfno=128+decode_binary(zp,cx+1,7); data[i]=mtf[mtfno]; goto rotate; }
+ mtfno=256;
+ data[i]=0;
+ markerpos=i;
+ continue;
+ // Rotate mtf according to empirical frequencies (new!)
+ rotate:
+ // Adjust frequencies for overflow
+ int k;
+ fadd = fadd + (fadd>>fshift);
+ if (fadd > 0x10000000)
+ {
+ fadd >>= 24;
+ freq[0] >>= 24;
+ freq[1] >>= 24;
+ freq[2] >>= 24;
+ freq[3] >>= 24;
+ for (k=4; k<FREQMAX; k++)
+ freq[k] = freq[k]>>24;
+ }
+ // Relocate new char according to new freq
+ unsigned int fc = fadd;
+ if (mtfno < FREQMAX)
+ fc += freq[mtfno];
+ for (k=mtfno; k>=FREQMAX; k--)
+ mtf[k] = mtf[k-1];
+ for (; k>0 && fc>=freq[k-1]; k--)
+ {
+ mtf[k] = mtf[k-1];
+ freq[k] = freq[k-1];
+ }
+ mtf[k] = data[i];
+ freq[k] = fc;
+ }
+
+
+ /////////////////////////////////
+ ////////// Reconstruct the string
+
+ if (markerpos<1 || markerpos>=size)
+ G_THROW( ERR_MSG("ByteStream.corrupt") );
+ // Allocate pointers
+ unsigned int *posn;
+ GPBuffer<unsigned int> gposn(posn,blocksize);
+ memset(posn, 0, sizeof(unsigned int)*size);
+ // Prepare count buffer
+ int count[256];
+ for (i=0; i<256; i++)
+ count[i] = 0;
+ // Fill count buffer
+ for (i=0; i<markerpos; i++)
+ {
+ unsigned char c = data[i];
+ posn[i] = (c<<24) | (count[c] & 0xffffff);
+ count[c] += 1;
+ }
+ for (i=markerpos+1; i<size; i++)
+ {
+ unsigned char c = data[i];
+ posn[i] = (c<<24) | (count[c] & 0xffffff);
+ count[c] += 1;
+ }
+ // Compute sorted char positions
+ int last = 1;
+ for (i=0; i<256; i++)
+ {
+ int tmp = count[i];
+ count[i] = last;
+ last += tmp;
+ }
+ // Undo the sort transform
+ i = 0;
+ last = size-1;
+ while (last>0)
+ {
+ unsigned int n = posn[i];
+ unsigned char c = (posn[i]>>24);
+ data[--last] = c;
+ i = count[c] + (n & 0xffffff);
+ }
+ // Free and check
+ if (i != markerpos)
+ G_THROW( ERR_MSG("ByteStream.corrupt") );
+ return size;
+}
+
+
+
+// ========================================
+// -- ByteStream interface
+
+
+
+long
+BSByteStream::tell() const
+{
+ return offset;
+}
+
+size_t
+BSByteStream::Decode::read(void *buffer, size_t sz)
+{
+ if (eof)
+ return 0;
+ // Loop
+ int copied = 0;
+ while (sz>0 && !eof)
+ {
+ // Decode if needed
+ if (!size)
+ {
+ bptr = 0;
+ if (! decode())
+ {
+ size = 1 ;
+ eof = true;
+ }
+ size -= 1;
+ }
+ // Compute remaining
+ int bytes = size;
+ if (bytes > (int)sz)
+ bytes = sz;
+ // Transfer
+ if (buffer && bytes)
+ {
+ memcpy(buffer, data+bptr, bytes);
+ buffer = (void*)((char*)buffer + bytes);
+ }
+ size -= bytes;
+ bptr += bytes;
+ sz -= bytes;
+ copied += bytes;
+ offset += bytes;
+ }
+ // Return copied bytes
+ return copied;
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/BSByteStream.h b/kviewshell/plugins/djvu/libdjvu/BSByteStream.h
new file mode 100644
index 00000000..6a985cdf
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/BSByteStream.h
@@ -0,0 +1,275 @@
+//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: BSByteStream.h,v 1.8 2003/11/07 22:08:20 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _BSBYTESTREAM_H
+#define _BSBYTESTREAM_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+/** @name BSByteStream.h
+
+ Files #"BSByteStream.h"# and #"BSByteStream.cpp"# implement a very compact
+ general purpose compressor based on the Burrows-Wheeler transform. The
+ utility program \Ref{bzz} provides a front-end for this class. Although
+ this compression model is not currently used in DjVu files, it may be used
+ in the future for encoding textual data chunks.
+
+ {\bf Algorithms} --- The Burrows-Wheeler transform (also named Block-Sorting)
+ is performed using a combination of the Karp-Miller-Rosenberg and the
+ Bentley-Sedgewick algorithms. This is comparable to (Sadakane, DCC 98)
+ with a slightly more flexible ranking scheme. Symbols are then ordered
+ according to a running estimate of their occurrence frequencies. The
+ symbol ranks are then coded using a simple fixed tree and the
+ \Ref{ZPCodec} binary adaptive coder.
+
+ {\bf Performances} --- The basic algorithm is mostly similar to those
+ implemented in well known compressors like #bzip# or #bzip2#
+ (\URL{http://www.muraroa.demon.co.uk}). The adaptive binary coder however
+ generates small differences. The adaptation noise may cost up to 5\% in
+ file size, but this penalty is usually offset by the benefits of
+ adaptation. This is good when processing large and highly structured
+ files like spreadsheet files. Compression and decompression speed is
+ about twice slower than #bzip2# but the sorting algorithms is more
+ robust. Unlike #bzip2# (as of August 1998), this code can compress half a
+ megabyte of "abababab...." in bounded time.
+
+ Here are some comparative results (in bits per character) obtained on the
+ Canterbury Corpus (\URL{http://corpus.canterbury.ac.nz}) as of August
+ 1998. The BSByteStream performance on the single spreadsheet file #Excl#
+ moves #bzz#'s weighted average ahead of much more sophisticated methods,
+ like Suzanne Bunton's #fsmxBest# system
+ \URL{http://corpus.canterbury.ac.nz/methodinfo/fsmx.html}. This result
+ will not last very long.
+
+ {\footnotesize
+ \begin{tabular}{lccccccccccccc}
+ & text & fax & Csrc & Excl & SPRC & tech
+ & poem & html & lisp & man & play & Weighted & Average \\
+ compress
+ & 3.27 & 0.97 & 3.56 & 2.41 & 4.21 & 3.06
+ & 3.38 & 3.68 & 3.90 & 4.43 & 3.51
+ & 2.55 & 3.31 \\
+ gzip -9
+ & 2.85 & 0.82 & 2.24 & 1.63 & 2.67 & 2.71
+ & 3.23 & 2.59 & 2.65 & 3.31 & 3.12
+ & 2.08 & 2.53 \\
+ bzip2 -9
+ & 2.27 & 0.78 & 2.18 & 1.01 & 2.70 & 2.02
+ & 2.42 & 2.48 & 2.79 & 3.33 & 2.53
+ & 1.54 & 2.23 \\
+ ppmd
+ & 2.31 & 0.99 & 2.11 & 1.08 & 2.68 & 2.19
+ & 2.48 & 2.38 & 2.43 & 3.00 & 2.53
+ & 1.65 & 2.20 \\
+ fsmx
+ & {\bf 2.10} & 0.79 & {\bf 1.89} & 1.48 & {\bf 2.52} & {\bf 1.84}
+ & {\bf 2.21} & {\bf 2.24} & {\bf 2.29} & {\bf 2.91} & {\bf 2.35}
+ & 1.63 & {\bf 2.06} \\
+ {\bf bzz}
+ & 2.25 & {\bf 0.76} & 2.13 & {\bf 0.78} & 2.67 & 2.00
+ & 2.40 & 2.52 & 2.60 & 3.19 & 2.52
+ & {\bf 1.44} & 2.16
+ \end{tabular}
+ }
+
+ Note that the DjVu people have several entries in this table. Program
+ #compress# was written some time ago by Joe Orost
+ (\URL{http://www.research.att.com/info/orost}). The #ppmc# method, (a
+ precursor of #ppmd#) was created by Paul Howard
+ (\URL{http://www.research.att.com/info/pgh}). The #bzz# program is just
+ below your eyes.
+
+ @author
+ L\'eon Bottou <leonb@research.att.com> -- Initial implementation\\
+ Andrei Erofeev <eaf@geocities.com> -- Improved Block Sorting algorithm.
+ @memo
+ Simple Burrows-Wheeler general purpose compressor.
+ @version
+ #$Id: BSByteStream.h,v 1.8 2003/11/07 22:08:20 leonb Exp $# */
+//@{
+
+
+#include "ByteStream.h"
+#include "GException.h"
+#include "ZPCodec.h"
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+/** Performs bzz compression/decompression.
+
+ Class #BSByteStream# defines a \Ref{ByteStream} which transparently
+ performs the BZZ compression/decompression. The constructor of class
+ \Ref{BSByteStream} takes another \Ref{ByteStream} as argument. Any data
+ written to the BSByteStream is compressed and written to this second
+ ByteStream. Any data read from the BSByteStream is internally generated by
+ decompressing data read from the second ByteStream.
+
+ Program \Ref{bzz} demonstrates how to use this class. All the hard work
+ is achieved by a simple ByteStream to ByteStream copy, as shown below.
+ \begin{verbatim}
+ GP<ByteStream> in=ByteStream::create(infile,"rb");
+ GP<ByteStream> out=ByteStream::create(outfile,"wb");
+ if (encoding) {
+ BSByteStream bsb(out, blocksize);
+ bsb.copy(*in);
+ } else {
+ BSByteStream bsb(in);
+ out->copy(bsb);
+ }
+ \end{verbatim}
+ Due to the block oriented nature of the Burrows-Wheeler transform, there
+ is a very significant latency between the data input and the data output.
+ You can use function #flush# to force data output at the expense of
+ compression efficiency.
+
+ You should never directly access a ByteStream object connected to a valid
+ BSByteStream object. The ByteStream object can be accessed again after the
+ destruction of the BSByteStream object. Note that the encoder always
+ flushes its internal buffers and writes a few final code bytes when the
+ BSByteStream object is destroyed. Note also that the decoder often reads
+ a few bytes beyond the last code byte written by the encoder. This lag
+ means that you must reposition the ByteStream after the destruction of the
+ BSByteStream object and before re-using the ByteStream object (see
+ \Ref{IFFByteStream}.)
+*/
+class BSByteStream : public ByteStream
+{
+public:
+// Limits on block sizes
+ enum { MINBLOCK=10, MAXBLOCK=4096 };
+
+// Sorting tresholds
+ enum { FREQMAX=4, CTXIDS=3 };
+
+ class Decode;
+ class Encode;
+protected:
+ BSByteStream(GP<ByteStream> bs);
+
+public:
+ /** Creates a BSByteStream.
+ The BSByteStream will be used for decompressing data.
+ \begin{description}
+ \item[Decompression]
+ The BSByteStream is created and the decompressor initializes. Chunks of
+ data will be read from ByteStream #bs# and decompressed into an internal
+ buffer. Function #read# can be used to access the decompressed data.
+ \end{description} */
+ static GP<ByteStream> create(GP<ByteStream> bs);
+
+ /** Constructs a BSByteStream.
+ The BSByteStream will be used for compressing data.
+ \begin{description}
+ \item[Compression]
+ Set #blocksize# to a positive number smaller than 4096 to
+ initialize the compressor. Data written to the BSByteStream will be
+ accumulated into an internal buffer. The buffered data will be
+ compressed and written to ByteStream #bs# whenever the buffer sizes
+ reaches the maximum value specified by argument #blocksize# (in
+ kilobytes). Using a larger block size usually increases the compression
+ ratio at the expense of computation time. There is no need however to
+ specify a block size larger than the total number of bytes to compress.
+ Setting #blocksize# to #1024# is a good starting point. A minimal block
+ size of 10 is silently enforced.
+ \end{description} */
+ static GP<ByteStream> create(GP<ByteStream> bs, const int blocksize);
+
+ // ByteStream Interface
+ ~BSByteStream();
+ virtual long tell(void) const;
+ virtual void flush(void) = 0;
+protected:
+ // Data
+ long offset;
+ int bptr;
+ unsigned int blocksize;
+ int size;
+ ByteStream *bs;
+ GP<ByteStream> gbs;
+ unsigned char *data;
+ GPBuffer<unsigned char> gdata;
+ // Coder
+ GP<ZPCodec> gzp;
+ BitContext ctx[300];
+private:
+ // Cancel C++ default stuff
+ BSByteStream(const BSByteStream &);
+ BSByteStream & operator=(const BSByteStream &);
+ BSByteStream(ByteStream *);
+ BSByteStream(ByteStream *, int);
+};
+
+//@}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/BSEncodeByteStream.cpp b/kviewshell/plugins/djvu/libdjvu/BSEncodeByteStream.cpp
new file mode 100644
index 00000000..9d5b726d
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/BSEncodeByteStream.cpp
@@ -0,0 +1,1010 @@
+//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: BSEncodeByteStream.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
+
+// - Author: Leon Bottou, 07/1998
+
+
+
+#include "BSByteStream.h"
+#include "GString.h"
+#undef BSORT_TIMER
+#ifdef BSORT_TIMER
+#include "GOS.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+// ========================================
+// --- Assertion
+
+#define ASSERT(expr) do{if(!(expr))G_THROW("assertion ("#expr") failed");}while(0)
+
+
+
+// ========================================
+// --- Global Definitions
+
+
+#ifdef OVERFLOW
+#undef OVERFLOW
+#endif
+// Overflow required when encoding
+static const int OVERFLOW=32;
+
+// Sorting tresholds
+static const int RANKSORT_THRESH=10;
+static const int QUICKSORT_STACK=512;
+static const int PRESORT_THRESH=10;
+static const int PRESORT_DEPTH=8;
+static const int RADIX_THRESH=32768;
+
+static const int FREQS0=100000;
+static const int FREQS1=1000000;
+
+// ========================================
+// -- Sorting Routines
+
+
+class _BSort // DJVU_CLASS
+{
+public:
+ ~_BSort();
+ _BSort(unsigned char *data, int size);
+ void run(int &markerpos);
+private:
+ // Members
+ int size;
+ unsigned char *data;
+ unsigned int *posn;
+ GPBuffer<unsigned int> gposn;
+ int *rank;
+ GPBuffer<int> grank;
+ // Helpers
+ inline int GT(int p1, int p2, int depth);
+ inline int GTD(int p1, int p2, int depth);
+ // -- final in-depth sort
+ void ranksort(int lo, int hi, int d);
+ // -- doubling sort
+ int pivot3r(int *rr, int lo, int hi);
+ void quicksort3r(int lo, int hi, int d);
+ // -- presort to depth PRESORT_DEPTH
+ unsigned char pivot3d(unsigned char *dd, int lo, int hi);
+ void quicksort3d(int lo, int hi, int d);
+ // -- radixsort
+ void radixsort16(void);
+ void radixsort8(void);
+};
+
+
+// blocksort -- the main entry point
+
+static void
+blocksort(unsigned char *data, int size, int &markerpos)
+{
+ _BSort bsort(data, size);
+ bsort.run(markerpos);
+}
+
+
+// _BSort construction
+
+_BSort::_BSort(unsigned char *xdata, int xsize)
+ : size(xsize), data(xdata), gposn(posn,xsize), grank(rank,xsize+1)
+{
+ ASSERT(size>0 && size<0x1000000);
+ rank[size] = -1;
+}
+
+_BSort::~_BSort()
+{
+}
+
+
+
+// GT -- compare suffixes using rank information
+
+inline int
+_BSort::GT(int p1, int p2, int depth)
+{
+ int r1, r2;
+ int twod = depth + depth;
+ while (1)
+ {
+ r1=rank[p1+depth]; r2=rank[p2+depth];
+ p1+=twod; p2+=twod;
+ if (r1!=r2)
+ return (r1>r2);
+ r1=rank[p1]; r2=rank[p2];
+ if (r1!=r2)
+ return (r1>r2);
+ r1=rank[p1+depth]; r2=rank[p2+depth];
+ p1+=twod; p2+=twod;
+ if (r1!=r2)
+ return (r1>r2);
+ r1=rank[p1]; r2=rank[p2];
+ if (r1!=r2)
+ return (r1>r2);
+ r1=rank[p1+depth]; r2=rank[p2+depth];
+ p1+=twod; p2+=twod;
+ if (r1!=r2)
+ return (r1>r2);
+ r1=rank[p1]; r2=rank[p2];
+ if (r1!=r2)
+ return (r1>r2);
+ r1=rank[p1+depth]; r2=rank[p2+depth];
+ p1+=twod; p2+=twod;
+ if (r1!=r2)
+ return (r1>r2);
+ r1=rank[p1]; r2=rank[p2];
+ if (r1!=r2)
+ return (r1>r2);
+ };
+}
+
+
+// _BSort::ranksort --
+// -- a simple insertion sort based on GT
+
+void
+_BSort::ranksort(int lo, int hi, int depth)
+{
+ int i,j;
+ for (i=lo+1; i<=hi; i++)
+ {
+ int tmp = posn[i];
+ for(j=i-1; j>=lo && GT(posn[j], tmp, depth); j--)
+ posn[j+1] = posn[j];
+ posn[j+1] = tmp;
+ }
+ for(i=lo;i<=hi;i++)
+ rank[posn[i]]=i;
+}
+
+// pivot -- return suitable pivot
+
+inline int
+_BSort::pivot3r(int *rr, int lo, int hi)
+{
+ int c1, c2, c3;
+ if (hi-lo > 256)
+ {
+ c1 = pivot3r(rr, lo, (6*lo+2*hi)/8);
+ c2 = pivot3r(rr, (5*lo+3*hi)/8, (3*lo+5*hi)/8);
+ c3 = pivot3r(rr, (2*lo+6*hi)/8, hi);
+ }
+ else
+ {
+ c1 = rr[posn[lo]];
+ c2 = rr[posn[(lo+hi)/2]];
+ c3 = rr[posn[hi]];
+ }
+ // Extract median
+ if (c1>c3)
+ { int tmp=c1; c1=c3; c3=tmp; }
+ if (c2<=c1)
+ return c1;
+ else if (c2>=c3)
+ return c3;
+ else
+ return c2;
+}
+
+
+// _BSort::quicksort3r -- Three way quicksort algorithm
+// Sort suffixes based on rank at pos+depth
+// The algorithm breaks into ranksort when size is
+// smaller than RANKSORT_THRESH
+
+static inline int
+mini(int a, int b)
+{
+ return (a<=b) ? a : b;
+}
+
+static inline void
+vswap(int i, int j, int n, unsigned int *x)
+{
+ while (n-- > 0)
+ { int tmp = x[i]; x[i++]=x[j]; x[j++]=tmp; }
+}
+
+void
+_BSort::quicksort3r(int lo, int hi, int depth)
+{
+ /* Initialize stack */
+ int slo[QUICKSORT_STACK];
+ int shi[QUICKSORT_STACK];
+ int sp = 1;
+ slo[0] = lo;
+ shi[0] = hi;
+ // Recursion elimination loop
+ while (--sp>=0)
+ {
+ lo = slo[sp];
+ hi = shi[sp];
+ // Test for insertion sort
+ if (hi-lo<RANKSORT_THRESH)
+ {
+ ranksort(lo, hi, depth);
+ }
+ else
+ {
+ int tmp;
+ int *rr=rank+depth;
+ int med = pivot3r(rr,lo,hi);
+ // -- positions are organized as follows:
+ // [lo..l1[ [l1..l[ ]h..h1] ]h1..hi]
+ // = < > =
+ int l1 = lo;
+ int h1 = hi;
+ while (rr[posn[l1]]==med && l1<h1) { l1++; }
+ while (rr[posn[h1]]==med && l1<h1) { h1--; }
+ int l = l1;
+ int h = h1;
+ // -- partition set
+ for (;;)
+ {
+ while (l<=h)
+ {
+ int c = rr[posn[l]] - med;
+ if (c > 0) break;
+ if (c == 0) { tmp=posn[l]; posn[l]=posn[l1]; posn[l1++]=tmp; }
+ l++;
+ }
+ while (l<=h)
+ {
+ int c = rr[posn[h]] - med;
+ if (c < 0) break;
+ if (c == 0) { tmp=posn[h]; posn[h]=posn[h1]; posn[h1--]=tmp; }
+ h--;
+ }
+ if (l>h) break;
+ tmp=posn[l]; posn[l]=posn[h]; posn[h]=tmp;
+ }
+ // -- reorganize as follows
+ // [lo..l1[ [l1..h1] ]h1..hi]
+ // < = >
+ tmp = mini(l1-lo, l-l1);
+ vswap(lo, l-tmp, tmp, posn);
+ l1 = lo + (l-l1);
+ tmp = mini(hi-h1, h1-h);
+ vswap(hi-tmp+1, h+1, tmp, posn);
+ h1 = hi - (h1-h);
+ // -- process segments
+ ASSERT(sp+2<QUICKSORT_STACK);
+ // ----- middle segment (=?) [l1, h1]
+ for(int i=l1;i<=h1;i++)
+ rank[posn[i]] = h1;
+ // ----- lower segment (<) [lo, l1[
+ if (l1 > lo)
+ {
+ for(int i=lo;i<l1;i++)
+ rank[posn[i]]=l1-1;
+ slo[sp]=lo;
+ shi[sp]=l1-1;
+ if (slo[sp] < shi[sp])
+ sp++;
+ }
+ // ----- upper segment (>) ]h1, hi]
+ if (h1 < hi)
+ {
+ slo[sp]=h1+1;
+ shi[sp]=hi;
+ if (slo[sp] < shi[sp])
+ sp++;
+ }
+ }
+ }
+}
+
+
+
+
+
+
+// GTD -- compare suffixes using data information
+// (up to depth PRESORT_DEPTH)
+
+inline int
+_BSort::GTD(int p1, int p2, int depth)
+{
+ unsigned char c1, c2;
+ p1+=depth; p2+=depth;
+ while (depth < PRESORT_DEPTH)
+ {
+ // Perform two
+ c1=data[p1]; c2=data[p2];
+ if (c1!=c2)
+ return (c1>c2);
+ c1=data[p1+1]; c2=data[p2+1];
+ p1+=2; p2+=2; depth+=2;
+ if (c1!=c2)
+ return (c1>c2);
+ }
+ if (p1<size && p2<size)
+ return 0;
+ return (p1<p2);
+}
+
+// pivot3d -- return suitable pivot
+
+inline unsigned char
+_BSort::pivot3d(unsigned char *rr, int lo, int hi)
+{
+ unsigned char c1, c2, c3;
+ if (hi-lo > 256)
+ {
+ c1 = pivot3d(rr, lo, (6*lo+2*hi)/8);
+ c2 = pivot3d(rr, (5*lo+3*hi)/8, (3*lo+5*hi)/8);
+ c3 = pivot3d(rr, (2*lo+6*hi)/8, hi);
+ }
+ else
+ {
+ c1 = rr[posn[lo]];
+ c2 = rr[posn[(lo+hi)/2]];
+ c3 = rr[posn[hi]];
+ }
+ // Extract median
+ if (c1>c3)
+ { int tmp=c1; c1=c3; c3=tmp; }
+ if (c2<=c1)
+ return c1;
+ else if (c2>=c3)
+ return c3;
+ else
+ return c2;
+}
+
+
+// _BSort::quicksort3d -- Three way quicksort algorithm
+// Sort suffixes based on strings until reaching
+// depth rank at pos+depth
+// The algorithm breaks into ranksort when size is
+// smaller than PRESORT_THRESH
+
+void
+_BSort::quicksort3d(int lo, int hi, int depth)
+{
+ /* Initialize stack */
+ int slo[QUICKSORT_STACK];
+ int shi[QUICKSORT_STACK];
+ int sd[QUICKSORT_STACK];
+ int sp = 1;
+ slo[0] = lo;
+ shi[0] = hi;
+ sd[0] = depth;
+ // Recursion elimination loop
+ while (--sp>=0)
+ {
+ lo = slo[sp];
+ hi = shi[sp];
+ depth = sd[sp];
+ // Test for insertion sort
+ if (depth >= PRESORT_DEPTH)
+ {
+ for (int i=lo; i<=hi; i++)
+ rank[posn[i]] = hi;
+ }
+ else if (hi-lo<PRESORT_THRESH)
+ {
+ int i,j;
+ for (i=lo+1; i<=hi; i++)
+ {
+ int tmp = posn[i];
+ for(j=i-1; j>=lo && GTD(posn[j], tmp, depth); j--)
+ posn[j+1] = posn[j];
+ posn[j+1] = tmp;
+ }
+ for(i=hi;i>=lo;i=j)
+ {
+ int tmp = posn[i];
+ rank[tmp] = i;
+ for (j=i-1; j>=lo && !GTD(tmp,posn[j],depth); j--)
+ rank[posn[j]] = i;
+ }
+ }
+ else
+ {
+ int tmp;
+ unsigned char *dd=data+depth;
+ unsigned char med = pivot3d(dd,lo,hi);
+ // -- positions are organized as follows:
+ // [lo..l1[ [l1..l[ ]h..h1] ]h1..hi]
+ // = < > =
+ int l1 = lo;
+ int h1 = hi;
+ while (dd[posn[l1]]==med && l1<h1) { l1++; }
+ while (dd[posn[h1]]==med && l1<h1) { h1--; }
+ int l = l1;
+ int h = h1;
+ // -- partition set
+ for (;;)
+ {
+ while (l<=h)
+ {
+ int c = (int)dd[posn[l]] - (int)med;
+ if (c > 0) break;
+ if (c == 0) { tmp=posn[l]; posn[l]=posn[l1]; posn[l1++]=tmp; }
+ l++;
+ }
+ while (l<=h)
+ {
+ int c = (int)dd[posn[h]] - (int)med;
+ if (c < 0) break;
+ if (c == 0) { tmp=posn[h]; posn[h]=posn[h1]; posn[h1--]=tmp; }
+ h--;
+ }
+ if (l>h) break;
+ tmp=posn[l]; posn[l]=posn[h]; posn[h]=tmp;
+ }
+ // -- reorganize as follows
+ // [lo..l1[ [l1..h1] ]h1..hi]
+ // < = >
+ tmp = mini(l1-lo, l-l1);
+ vswap(lo, l-tmp, tmp, posn);
+ l1 = lo + (l-l1);
+ tmp = mini(hi-h1, h1-h);
+ vswap(hi-tmp+1, h+1, tmp, posn);
+ h1 = hi - (h1-h);
+ // -- process segments
+ ASSERT(sp+3<QUICKSORT_STACK);
+ // ----- middle segment (=?) [l1, h1]
+ l = l1; h = h1;
+ if (med==0) // special case for marker [slow]
+ for (int i=l; i<=h; i++)
+ if ((int)posn[i]+depth == size-1)
+ {
+ tmp=posn[i]; posn[i]=posn[l]; posn[l]=tmp;
+ rank[tmp]=l++; break;
+ }
+ if (l<h)
+ { slo[sp] = l; shi[sp] = h; sd[sp++] = depth+1; }
+ else if (l==h)
+ { rank[posn[h]] = h; }
+ // ----- lower segment (<) [lo, l1[
+ l = lo;
+ h = l1-1;
+ if (l<h)
+ { slo[sp] = l; shi[sp] = h; sd[sp++] = depth; }
+ else if (l==h)
+ { rank[posn[h]] = h; }
+ // ----- upper segment (>) ]h1, hi]
+ l = h1+1;
+ h = hi;
+ if (l<h)
+ { slo[sp] = l; shi[sp] = h; sd[sp++] = depth; }
+ else if (l==h)
+ { rank[posn[h]] = h; }
+ }
+ }
+}
+
+
+
+
+// _BSort::radixsort8 -- 8 bit radix sort
+
+void
+_BSort::radixsort8(void)
+{
+ int i;
+ // Initialize frequency array
+ int lo[256], hi[256];
+ for (i=0; i<256; i++)
+ hi[i] = lo[i] = 0;
+ // Count occurences
+ for (i=0; i<size-1; i++)
+ hi[data[i]] ++;
+ // Compute positions (lo)
+ int last = 1;
+ for (i=0; i<256; i++)
+ {
+ lo[i] = last;
+ hi[i] = last + hi[i] - 1;
+ last = hi[i] + 1;
+ }
+ for (i=0; i<size-1; i++)
+ {
+ posn[ lo[data[i]]++ ] = i;
+ rank[ i ] = hi[data[i]];
+ }
+ // Process marker "$"
+ posn[0] = size-1;
+ rank[size-1] = 0;
+ // Extra element
+ rank[size] = -1;
+}
+
+
+// _BSort::radixsort16 -- 16 bit radix sort
+
+void
+_BSort::radixsort16(void)
+{
+ int i;
+ // Initialize frequency array
+ int *ftab;
+ GPBuffer<int> gftab(ftab,65536);
+ for (i=0; i<65536; i++)
+ ftab[i] = 0;
+ // Count occurences
+ unsigned char c1 = data[0];
+ for (i=0; i<size-1; i++)
+ {
+ unsigned char c2 = data[i+1];
+ ftab[(c1<<8)|c2] ++;
+ c1 = c2;
+ }
+ // Generate upper position
+ for (i=1;i<65536;i++)
+ ftab[i] += ftab[i-1];
+ // Fill rank array with upper bound
+ c1 = data[0];
+ for (i=0; i<size-2; i++)
+ {
+ unsigned char c2 = data[i+1];
+ rank[i] = ftab[(c1<<8)|c2];
+ c1 = c2;
+ }
+ // Fill posn array (backwards)
+ c1 = data[size-2];
+ for (i=size-3; i>=0; i--)
+ {
+ unsigned char c2 = data[i];
+ posn[ ftab[(c2<<8)|c1]-- ] = i;
+ c1 = c2;
+ }
+ // Fixup marker stuff
+ ASSERT(data[size-1]==0);
+ c1 = data[size-2];
+ posn[0] = size-1;
+ posn[ ftab[(c1<<8)] ] = size-2;
+ rank[size-1] = 0;
+ rank[size-2] = ftab[(c1<<8)];
+ // Extra element
+ rank[size] = -1;
+}
+
+
+
+// _BSort::run -- main sort loop
+
+void
+_BSort::run(int &markerpos)
+{
+ int lo, hi;
+ ASSERT(size>0);
+ ASSERT(data[size-1]==0);
+#ifdef BSORT_TIMER
+ long start = GOS::ticks();
+#endif
+ // Step 1: Radix sort
+ int depth = 0;
+ if (size > RADIX_THRESH)
+ {
+ radixsort16();
+ depth=2;
+ }
+ else
+ {
+ radixsort8();
+ depth=1;
+ }
+ // Step 2: Perform presort to depth PRESORT_DEPTH
+ for (lo=0; lo<size; lo++)
+ {
+ hi = rank[posn[lo]];
+ if (lo < hi)
+ quicksort3d(lo, hi, depth);
+ lo = hi;
+ }
+ depth = PRESORT_DEPTH;
+#ifdef BSORT_TIMER
+ long middle = GOS::ticks();
+#endif
+ // Step 3: Perform rank doubling
+ int again = 1;
+ while (again)
+ {
+ again = 0;
+ int sorted_lo = 0;
+ for (lo=0; lo<size; lo++)
+ {
+ hi = rank[posn[lo]&0xffffff];
+ if (lo == hi)
+ {
+ lo += (posn[lo]>>24) & 0xff;
+ }
+ else
+ {
+ if (hi-lo < RANKSORT_THRESH)
+ {
+ ranksort(lo, hi, depth);
+ }
+ else
+ {
+ again += 1;
+ while (sorted_lo < lo-1)
+ {
+ int step = mini(255, lo-1-sorted_lo);
+ posn[sorted_lo] = (posn[sorted_lo]&0xffffff) | (step<<24);
+ sorted_lo += step+1;
+ }
+ quicksort3r(lo, hi, depth);
+ sorted_lo = hi + 1;
+ }
+ lo = hi;
+ }
+ }
+ // Finish threading
+ while (sorted_lo < lo-1)
+ {
+ int step = mini(255, lo-1-sorted_lo);
+ posn[sorted_lo] = (posn[sorted_lo]&0xffffff) | (step<<24);
+ sorted_lo += step+1;
+ }
+ // Double depth
+ depth += depth;
+ }
+ // Step 4: Permute data
+ int i;
+ markerpos = -1;
+ for (i=0; i<size; i++)
+ rank[i] = data[i];
+ for (i=0; i<size; i++)
+ {
+ int j = posn[i] & 0xffffff;
+ if (j>0)
+ {
+ data[i] = rank[j-1];
+ }
+ else
+ {
+ data[i] = 0;
+ markerpos = i;
+ }
+ }
+ ASSERT(markerpos>=0 && markerpos<size);
+#ifdef BSORT_TIMER
+ long end = GOS::ticks();
+ DjVuPrintErrorUTF8("Sorting time: %d bytes in %ld + %ld = %ld ms\n",
+ size-1, middle-start, end-middle, end-start);
+#endif
+}
+
+
+// ========================================
+// -- Encoding
+
+static void
+encode_raw(ZPCodec &zp, int bits, int x)
+{
+ int n = 1;
+ int m = (1<<bits);
+ while (n < m)
+ {
+ x = (x & (m-1)) << 1;
+ int b = (x >> bits);
+ zp.encoder(b);
+ n = (n<<1) | b;
+ }
+}
+
+static inline void
+encode_binary(ZPCodec &zp, BitContext *ctx, int bits, int x)
+{
+ // Require 2^bits-1 contexts
+ int n = 1;
+ int m = (1<<bits);
+ ctx = ctx - 1;
+ while (n < m)
+ {
+ x = (x & (m-1)) << 1;
+ int b = (x >> bits);
+ zp.encoder(b, ctx[n]);
+ n = (n<<1) | b;
+ }
+}
+
+class BSByteStream::Encode : public BSByteStream
+{
+public:
+ /** Creates a Static object for allocating the memory area of
+ length #sz# starting at address #buffer#. */
+ Encode(GP<ByteStream> bs);
+ ~Encode();
+ void init(const int encoding);
+ // Virtual functions
+ virtual size_t write(const void *buffer, size_t sz);
+ virtual void flush(void);
+protected:
+ unsigned int encode(void);
+};
+
+unsigned int
+BSByteStream::Encode::encode()
+{
+ /////////////////////////////////
+ //////////// Block Sort Tranform
+
+ int markerpos = size-1;
+ blocksort(data,size,markerpos);
+
+ /////////////////////////////////
+ //////////// Encode Output Stream
+
+ // Header
+ ZPCodec &zp=*gzp;
+ encode_raw(zp, 24, size);
+ // Determine and Encode Estimation Speed
+ int fshift = 0;
+ if (size < FREQS0)
+ { fshift=0; zp.encoder(0); }
+ else if (size < FREQS1)
+ { fshift = 1; zp.encoder(1); zp.encoder(0); }
+ else
+ { fshift = 2; zp.encoder(1); zp.encoder(1); }
+ // MTF
+ unsigned char mtf[256];
+ unsigned char rmtf[256];
+ unsigned int freq[FREQMAX];
+ int m = 0;
+ for (m=0; m<256; m++)
+ mtf[m] = m;
+ for (m=0; m<256; m++)
+ rmtf[mtf[m]] = m;
+ int fadd = 4;
+ for (m=0; m<FREQMAX; m++)
+ freq[m] = 0;
+ // Encode
+ int i;
+ int mtfno = 3;
+ for (i=0; i<size; i++)
+ {
+ // Get MTF data
+ int c = data[i];
+ int ctxid = CTXIDS-1;
+ if (ctxid>mtfno) ctxid=mtfno;
+ mtfno = rmtf[c];
+ if (i==markerpos)
+ mtfno = 256;
+ // Encode using ZPCoder
+ int b;
+ BitContext *cx = ctx;
+ b = (mtfno==0);
+ zp.encoder(b, cx[ctxid]);
+ if (b) goto rotate; cx+=CTXIDS;
+ b = (mtfno==1);
+ zp.encoder(b, cx[ctxid]);
+ if (b) goto rotate; cx+=CTXIDS;
+ b = (mtfno<4);
+ zp.encoder(b, cx[0]);
+ if (b) { encode_binary(zp,cx+1,1,mtfno-2); goto rotate; }
+ cx+=1+1;
+ b = (mtfno<8);
+ zp.encoder(b, cx[0]);
+ if (b) { encode_binary(zp,cx+1,2,mtfno-4); goto rotate; }
+ cx+=1+3;
+ b = (mtfno<16);
+ zp.encoder(b, cx[0]);
+ if (b) { encode_binary(zp,cx+1,3,mtfno-8); goto rotate; }
+ cx+=1+7;
+ b = (mtfno<32);
+ zp.encoder(b, cx[0]);
+ if (b) { encode_binary(zp,cx+1,4,mtfno-16); goto rotate; }
+ cx+=1+15;
+ b = (mtfno<64);
+ zp.encoder(b, cx[0]);
+ if (b) { encode_binary(zp,cx+1,5,mtfno-32); goto rotate; }
+ cx+=1+31;
+ b = (mtfno<128);
+ zp.encoder(b, cx[0]);
+ if (b) { encode_binary(zp,cx+1,6,mtfno-64); goto rotate; }
+ cx+=1+63;
+ b = (mtfno<256);
+ zp.encoder(b, cx[0]);
+ if (b) { encode_binary(zp,cx+1,7,mtfno-128); goto rotate; }
+ continue;
+ // Rotate MTF according to empirical frequencies (new!)
+ rotate:
+ // Adjust frequencies for overflow
+ fadd = fadd + (fadd>>fshift);
+ if (fadd > 0x10000000)
+ {
+ fadd = fadd>>24;
+ freq[0] >>= 24;
+ freq[1] >>= 24;
+ freq[2] >>= 24;
+ freq[3] >>= 24;
+ for (int k=4; k<FREQMAX; k++)
+ freq[k] = freq[k]>>24;
+ }
+ // Relocate new char according to new freq
+ unsigned int fc = fadd;
+ if (mtfno < FREQMAX)
+ fc += freq[mtfno];
+ int k;
+ for (k=mtfno; k>=FREQMAX; k--)
+ {
+ mtf[k] = mtf[k-1];
+ rmtf[mtf[k]] = k;
+ }
+ for (; k>0 && fc>=freq[k-1]; k--)
+ {
+ mtf[k] = mtf[k-1];
+ freq[k] = freq[k-1];
+ rmtf[mtf[k]] = k;
+ }
+ mtf[k] = c;
+ freq[k] = fc;
+ rmtf[mtf[k]] = k;
+ }
+ // Terminate
+ return 0;
+}
+
+// ========================================
+// --- Construction
+
+BSByteStream::Encode::Encode(GP<ByteStream> xbs)
+: BSByteStream(xbs) {}
+
+void
+BSByteStream::Encode::init(const int xencoding)
+{
+ gzp=ZPCodec::create(gbs,true,true);
+ const int encoding=(xencoding<MINBLOCK)?MINBLOCK:xencoding;
+ if (encoding > MAXBLOCK)
+ G_THROW( ERR_MSG("ByteStream.blocksize") "\t" + GUTF8String(MAXBLOCK) );
+ // Record block size
+ blocksize = encoding * 1024;
+ // Initialize context array
+}
+
+BSByteStream::Encode::~Encode()
+{
+ // Flush
+ flush();
+ // Encode EOF marker
+ encode_raw(*gzp, 24, 0);
+ // Free allocated memory
+}
+
+GP<ByteStream>
+BSByteStream::create(GP<ByteStream> xbs,const int blocksize)
+{
+ BSByteStream::Encode *rbs=new BSByteStream::Encode(xbs);
+ GP<ByteStream> retval=rbs;
+ rbs->init(blocksize);
+ return retval;
+}
+
+// ========================================
+// -- ByteStream interface
+
+void
+BSByteStream::Encode::flush()
+{
+ if (bptr>0)
+ {
+ ASSERT(bptr<(int)blocksize);
+ memset(data+bptr, 0, OVERFLOW);
+ size = bptr+1;
+ encode();
+ }
+ size = bptr = 0;
+}
+
+size_t
+BSByteStream::Encode::write(const void *buffer, size_t sz)
+{
+ // Trivial checks
+ if (sz == 0)
+ return 0;
+ // Loop
+ int copied = 0;
+ while (sz > 0)
+ {
+ // Initialize
+ if (!data)
+ {
+ bptr = 0;
+ gdata.resize(blocksize+OVERFLOW);
+ }
+ // Compute remaining
+ int bytes = blocksize - 1 - bptr;
+ if (bytes > (int)sz)
+ bytes = sz;
+ // Store date (todo: rle)
+ memcpy(data+bptr, buffer, bytes);
+ buffer = (void*)((char*)buffer + bytes);
+ bptr += bytes;
+ sz -= bytes;
+ copied += bytes;
+ offset += bytes;
+ // Flush when needed
+ if (bptr + 1 >= (int)blocksize)
+ flush();
+ }
+ // return
+ return copied;
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/ByteStream.cpp b/kviewshell/plugins/djvu/libdjvu/ByteStream.cpp
new file mode 100644
index 00000000..011b348d
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/ByteStream.cpp
@@ -0,0 +1,1445 @@
+//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: ByteStream.cpp,v 1.18 2004/08/06 14:50:05 leonb Exp $
+// $Name: release_3_5_15 $
+
+// From: Leon Bottou, 1/31/2002
+// This file has very little to do with my initial implementation.
+// It has been practically rewritten by Lizardtech for i18n changes.
+// Our original implementation consisted of multiple classes.
+// <http://prdownloads.sourceforge.net/djvu/DjVu2_2b-src.tgz>.
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+// - Author: Leon Bottou, 04/1997
+
+#include "DjVuGlobal.h"
+#include "ByteStream.h"
+#include "GOS.h"
+#include "GURL.h"
+#include "DjVuMessage.h"
+#include <fcntl.h>
+#if defined(WIN32) || defined(__CYGWIN32__)
+# include <io.h>
+#endif
+
+#ifdef UNIX
+# ifndef HAS_MEMMAP
+# define HAS_MEMMAP 1
+# endif
+#endif
+
+#if defined(UNIX)
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <unistd.h>
+# include <errno.h>
+# ifdef HAS_MEMMAP
+# include <sys/mman.h>
+# endif
+#elif defined(macintosh)
+# include <unistd.h>
+_MSL_IMP_EXP_C int _dup(int);
+_MSL_IMP_EXP_C int _dup2(int,int);
+_MSL_IMP_EXP_C int _close(int);
+__inline int dup(int _a ) { return _dup(_a);}
+__inline int dup2(int _a, int _b ) { return _dup2(_a, _b);}
+#endif
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+const char *ByteStream::EndOfFile=ERR_MSG("EOF");
+
+/** ByteStream interface for stdio files.
+ The virtual member functions #read#, #write#, #tell# and #seek# are mapped
+ to the well known stdio functions #fread#, #fwrite#, #ftell# and #fseek#.
+ @see Unix man page fopen(3), fread(3), fwrite(3), ftell(3), fseek(3) */
+
+class ByteStream::Stdio : public ByteStream {
+public:
+ Stdio(void);
+
+ /** Constructs a ByteStream for accessing the file named #url#.
+ Arguments #url# and #mode# are similar to the arguments of the well
+ known stdio function #fopen#. In addition a url of #-# will be
+ interpreted as the standard output or the standard input according to
+ #mode#. This constructor will open a stdio file and construct a
+ ByteStream object accessing this file. Destroying the ByteStream object
+ will flush and close the associated stdio file. Returns an error code
+ if the stdio file cannot be opened. */
+ GUTF8String init(const GURL &url, const char * const mode);
+
+ /** Constructs a ByteStream for accessing the stdio file #f#.
+ Argument #mode# indicates the type of the stdio file, as in the
+ well known stdio function #fopen#. Destroying the ByteStream
+ object will not close the stdio file #f# unless closeme is true. */
+ GUTF8String init(FILE * const f, const char * const mode="rb", const bool closeme=false);
+
+ /** Initializes from stdio */
+ GUTF8String init(const char mode[]);
+
+ // Virtual functions
+ ~Stdio();
+ virtual size_t read(void *buffer, size_t size);
+ virtual size_t write(const void *buffer, size_t size);
+ virtual void flush(void);
+ virtual int seek(long offset, int whence = SEEK_SET, bool nothrow=false);
+ virtual long tell(void) const;
+private:
+ // Cancel C++ default stuff
+ Stdio(const Stdio &);
+ Stdio & operator=(const Stdio &);
+private:
+ // Implementation
+ bool can_read;
+ bool can_write;
+ bool must_close;
+protected:
+ FILE *fp;
+ long pos;
+};
+
+inline GUTF8String
+ByteStream::Stdio::init(FILE * const f,const char mode[],const bool closeme)
+{
+ fp=f;
+ must_close=closeme;
+ return init(mode);
+}
+
+
+/** ByteStream interface managing a memory buffer.
+ Class #ByteStream::Memory# manages a dynamically resizable buffer from
+ which data can be read or written. The buffer itself is organized as an
+ array of blocks of 4096 bytes. */
+
+class ByteStream::Memory : public ByteStream
+{
+public:
+ /** Constructs an empty ByteStream::Memory.
+ The buffer is initially empty. You must first use function #write#
+ to store data into the buffer, use function #seek# to rewind the
+ current position, and function #read# to read the data back. */
+ Memory();
+ /** Constructs a Memory by copying initial data. The
+ Memory buffer is initialized with #size# bytes copied from the
+ memory area pointed to by #buffer#. */
+ GUTF8String init(const void * const buffer, const size_t size);
+ // Virtual functions
+ ~Memory();
+ virtual size_t read(void *buffer, size_t size);
+ virtual size_t write(const void *buffer, size_t size);
+ virtual int seek(long offset, int whence=SEEK_SET, bool nothrow=false);
+ virtual long tell(void) const;
+ /** Erases everything in the Memory.
+ The current location is reset to zero. */
+ void empty();
+ /** Returns the total number of bytes contained in the buffer. Valid
+ offsets for function #seek# range from 0 to the value returned by this
+ function. */
+ virtual int size(void) const;
+ /** Returns a reference to the byte at offset #n#. This reference can be
+ used to read (as in #mbs[n]#) or modify (as in #mbs[n]=c#) the contents
+ of the buffer. */
+ char &operator[] (int n);
+ /** Copies all internal data into \Ref{TArray} and returns it */
+private:
+ // Cancel C++ default stuff
+ Memory(const Memory &);
+ Memory & operator=(const Memory &);
+ // Current position
+ int where;
+protected:
+ /** Reads data from a random position. This function reads at most #sz#
+ bytes at position #pos# into #buffer# and returns the actual number of
+ bytes read. The current position is unchanged. */
+ virtual size_t readat(void *buffer, size_t sz, int pos);
+ /** Number of bytes in internal buffer. */
+ int bsize;
+ /** Number of 4096 bytes blocks. */
+ int nblocks;
+ /** Pointers (possibly null) to 4096 bytes blocks. */
+ char **blocks;
+ /** Pointers (possibly null) to 4096 bytes blocks. */
+ GPBuffer<char *> gblocks;
+};
+
+
+
+inline int
+ByteStream::Memory::size(void) const
+{
+ return bsize;
+}
+
+inline char &
+ByteStream::Memory::operator[] (int n)
+{
+ return blocks[n>>12][n&0xfff];
+}
+
+
+
+/** Read-only ByteStream interface to a memory area.
+ Class #ByteStream::Static# implements a read-only ByteStream interface for a
+ memory area specified by the user at construction time. Calls to function
+ #read# directly access this memory area. The user must therefore make
+ sure that its content remain valid long enough. */
+
+class ByteStream::Static : public ByteStream
+{
+public:
+ class Allocate;
+ class Duplicate;
+ friend class Duplicate;
+
+ /** Creates a Static object for allocating the memory area of
+ length #sz# starting at address #buffer#. */
+ Static(const void * const buffer, const size_t sz);
+ ~Static();
+ // Virtual functions
+ virtual size_t read(void *buffer, size_t sz);
+ virtual int seek(long offset, int whence = SEEK_SET, bool nothrow=false);
+ virtual long tell(void) const;
+ /** Returns the total number of bytes contained in the buffer, file, etc.
+ Valid offsets for function #seek# range from 0 to the value returned
+ by this function. */
+ virtual int size(void) const;
+ virtual GP<ByteStream> duplicate(const size_t xsize) const;
+ /// Returns false, unless a subclass of ByteStream::Static
+ virtual bool is_static(void) const { return true; }
+protected:
+ const char *data;
+ int bsize;
+private:
+ int where;
+};
+
+ByteStream::Static::~Static() {}
+
+class ByteStream::Static::Allocate : public ByteStream::Static
+{
+public:
+ friend class ByteStream;
+protected:
+ char *buf;
+ GPBuffer<char> gbuf;
+public:
+ Allocate(const size_t size) : Static(0,size), gbuf(buf,size) { data=buf; }
+ virtual ~Allocate();
+};
+
+ByteStream::Static::Allocate::~Allocate() {}
+
+inline int
+ByteStream::Static::size(void) const
+{
+ return bsize;
+}
+
+class ByteStream::Static::Duplicate : public ByteStream::Static
+{
+protected:
+ GP<ByteStream> gbs;
+public:
+ Duplicate(const ByteStream::Static &bs, const size_t size);
+};
+
+ByteStream::Static::Duplicate::Duplicate(
+ const ByteStream::Static &bs, const size_t xsize)
+: ByteStream::Static(0,0)
+{
+ if(xsize&&(bs.bsize<bs.where))
+ {
+ const size_t bssize=(size_t)bs.bsize-(size_t)bs.where;
+ bsize=(size_t)((xsize>bssize)?bssize:xsize);
+ gbs=const_cast<ByteStream::Static *>(&bs);
+ data=bs.data+bs.where;
+ }
+}
+
+GP<ByteStream>
+ByteStream::Static::duplicate(const size_t xsize) const
+{
+ return new ByteStream::Static::Duplicate(*this,xsize);
+}
+
+#if HAS_MEMMAP
+/** Read-only ByteStream interface to a memmap area.
+ Class #MemoryMapByteStream# implements a read-only ByteStream interface
+ for a memory map to a file. */
+
+class MemoryMapByteStream : public ByteStream::Static
+{
+public:
+ MemoryMapByteStream(void);
+ virtual ~MemoryMapByteStream();
+private:
+ GUTF8String init(const int fd, const bool closeme);
+ GUTF8String init(FILE *const f,const bool closeme);
+ friend class ByteStream;
+};
+#endif
+
+//// CLASS BYTESTREAM
+
+
+ByteStream::~ByteStream()
+{
+}
+
+int
+ByteStream::scanf(const char *fmt, ...)
+{
+ G_THROW( ERR_MSG("ByteStream.not_implemented") ); // This is a place holder function.
+ return 0;
+}
+
+size_t
+ByteStream::read(void *buffer, size_t sz)
+{
+ G_THROW( ERR_MSG("ByteStream.cant_read") ); // Cannot read from a ByteStream created for writing
+ return 0;
+}
+
+size_t
+ByteStream::write(const void *buffer, size_t sz)
+{
+ G_THROW( ERR_MSG("ByteStream.cant_write") ); // Cannot write from a ByteStream created for reading
+ return 0;
+}
+
+void
+ByteStream::flush()
+{
+}
+
+int
+ByteStream::seek(long offset, int whence, bool nothrow)
+{
+ int nwhere = 0;
+ int ncurrent = tell();
+ switch (whence)
+ {
+ case SEEK_SET:
+ nwhere=0; break;
+ case SEEK_CUR:
+ nwhere=ncurrent; break;
+ case SEEK_END:
+ {
+ if(offset)
+ {
+ if (nothrow)
+ return -1;
+ G_THROW( ERR_MSG("ByteStream.backward") );
+ }
+ char buffer[1024];
+ int bytes;
+ while((bytes=read(buffer, sizeof(buffer))))
+ EMPTY_LOOP;
+ return 0;
+ }
+ default:
+ G_THROW( ERR_MSG("ByteStream.bad_arg") ); // Illegal argument in seek
+ }
+ nwhere += offset;
+ if (nwhere < ncurrent)
+ {
+ // Seeking backwards is not supported by this ByteStream
+ if (nothrow)
+ return -1;
+ G_THROW( ERR_MSG("ByteStream.backward") );
+ }
+ while (nwhere>ncurrent)
+ {
+ char buffer[1024];
+ const int xbytes=(ncurrent+(int)sizeof(buffer)>nwhere)
+ ?(nwhere - ncurrent):(int)sizeof(buffer);
+ const int bytes = read(buffer, xbytes);
+ ncurrent += bytes;
+ if (!bytes)
+ G_THROW( ByteStream::EndOfFile );
+ // Seeking works funny on this ByteStream (ftell() acts strange)
+ if (ncurrent!=tell())
+ G_THROW( ERR_MSG("ByteStream.seek") );
+ }
+ return 0;
+}
+
+size_t
+ByteStream::readall(void *buffer, size_t size)
+{
+ size_t total = 0;
+ while (size > 0)
+ {
+ int nitems = read(buffer, size);
+ // Replaced perror() below with G_THROW(). It still makes little sense
+ // as there is no guarantee, that errno is right. Still, throwing
+ // exception instead of continuing to loop is better.
+ // - eaf
+ if(nitems < 0)
+ G_THROW(strerror(errno)); // (No error in the DjVuMessageFile)
+ if (nitems == 0)
+ break;
+ total += nitems;
+ size -= nitems;
+ buffer = (void*)((char*)buffer + nitems);
+ }
+ return total;
+}
+
+size_t
+ByteStream::format(const char *fmt, ... )
+{
+ va_list args;
+ va_start(args, fmt);
+ const GUTF8String message(fmt,args);
+ return writestring(message);
+}
+
+size_t
+ByteStream::writestring(const GNativeString &s)
+{
+ int retval;
+ if(cp != UTF8)
+ {
+ retval=writall((const char *)s,s.length());
+ if(cp == AUTO)
+ cp=NATIVE; // Avoid mixing string types.
+ }else
+ {
+ const GUTF8String msg(s.getNative2UTF8());
+ retval=writall((const char *)msg,msg.length());
+ }
+ return retval;
+}
+
+size_t
+ByteStream::writestring(const GUTF8String &s)
+{
+ int retval;
+ if(cp != NATIVE)
+ {
+ retval=writall((const char *)s,s.length());
+ if(cp == AUTO)
+ cp=UTF8; // Avoid mixing string types.
+ }else
+ {
+ const GNativeString msg(s.getUTF82Native());
+ retval=writall((const char *)msg,msg.length());
+ }
+ return retval;
+}
+
+size_t
+ByteStream::writall(const void *buffer, size_t size)
+{
+ size_t total = 0;
+ while (size > 0)
+ {
+ size_t nitems = write(buffer, size);
+ if (nitems == 0)
+ G_THROW( ERR_MSG("ByteStream.write_error") ); // Unknown error in write
+ total += nitems;
+ size -= nitems;
+ buffer = (void*)((char*)buffer + nitems);
+ }
+ return total;
+}
+
+size_t
+ByteStream::copy(ByteStream &bsfrom, size_t size)
+{
+ size_t total = 0;
+ const size_t max_buffer_size=200*1024;
+ const size_t buffer_size=(size>0 && size<max_buffer_size)
+ ?size:max_buffer_size;
+ char *buffer;
+ GPBuffer<char> gbuf(buffer,buffer_size);
+ for(;;)
+ {
+ size_t bytes = buffer_size;
+ if (size>0 && bytes+total>size)
+ bytes = size - total;
+ if (bytes == 0)
+ break;
+ bytes = bsfrom.read((void*)buffer, bytes);
+ if (bytes == 0)
+ break;
+ writall((void*)buffer, bytes);
+ total += bytes;
+ }
+ return total;
+}
+
+
+void
+ByteStream::write8 (unsigned int card)
+{
+ unsigned char c[1];
+ c[0] = (card) & 0xff;
+ if (write((void*)c, sizeof(c)) != sizeof(c))
+ G_THROW(strerror(errno)); // (No error in the DjVuMessageFile)
+}
+
+void
+ByteStream::write16(unsigned int card)
+{
+ unsigned char c[2];
+ c[0] = (card>>8) & 0xff;
+ c[1] = (card) & 0xff;
+ if (writall((void*)c, sizeof(c)) != sizeof(c))
+ G_THROW(strerror(errno)); // (No error in the DjVuMessageFile)
+}
+
+void
+ByteStream::write24(unsigned int card)
+{
+ unsigned char c[3];
+ c[0] = (card>>16) & 0xff;
+ c[1] = (card>>8) & 0xff;
+ c[2] = (card) & 0xff;
+ if (writall((void*)c, sizeof(c)) != sizeof(c))
+ G_THROW(strerror(errno)); // (No error in the DjVuMessageFile)
+}
+
+void
+ByteStream::write32(unsigned int card)
+{
+ unsigned char c[4];
+ c[0] = (card>>24) & 0xff;
+ c[1] = (card>>16) & 0xff;
+ c[2] = (card>>8) & 0xff;
+ c[3] = (card) & 0xff;
+ if (writall((void*)c, sizeof(c)) != sizeof(c))
+ G_THROW(strerror(errno)); // (No error in the DjVuMessageFile)
+}
+
+unsigned int
+ByteStream::read8 ()
+{
+ unsigned char c[1];
+ if (readall((void*)c, sizeof(c)) != sizeof(c))
+ G_THROW( ByteStream::EndOfFile );
+ return c[0];
+}
+
+unsigned int
+ByteStream::read16()
+{
+ unsigned char c[2];
+ if (readall((void*)c, sizeof(c)) != sizeof(c))
+ G_THROW( ByteStream::EndOfFile );
+ return (c[0]<<8)+c[1];
+}
+
+unsigned int
+ByteStream::read24()
+{
+ unsigned char c[3];
+ if (readall((void*)c, sizeof(c)) != sizeof(c))
+ G_THROW( ByteStream::EndOfFile );
+ return (((c[0]<<8)+c[1])<<8)+c[2];
+}
+
+unsigned int
+ByteStream::read32()
+{
+ unsigned char c[4];
+ if (readall((void*)c, sizeof(c)) != sizeof(c))
+ G_THROW( ByteStream::EndOfFile );
+ return (((((c[0]<<8)+c[1])<<8)+c[2])<<8)+c[3];
+}
+
+
+
+//// CLASS ByteStream::Stdio
+
+ByteStream::Stdio::Stdio(void)
+: can_read(false),can_write(false),must_close(true),fp(0),pos(0)
+{}
+
+ByteStream::Stdio::~Stdio()
+{
+ if (fp && must_close)
+ fclose(fp);
+}
+
+GUTF8String
+ByteStream::Stdio::init(const char mode[])
+{
+ char const *mesg=0;
+ bool binary=false;
+ if(!fp)
+ must_close=false;
+ for (const char *s=mode; s && *s; s++)
+ {
+ switch(*s)
+ {
+ case 'r':
+ can_read=true;
+ if(!fp) fp=stdin;
+ break;
+ case 'w':
+ case 'a':
+ can_write=true;
+ if(!fp) fp=stdout;
+ break;
+ case '+':
+ can_read=can_write=true;
+ break;
+ case 'b':
+ binary=true;
+ break;
+ default:
+ mesg= ERR_MSG("ByteStream.bad_mode"); // Illegal mode in Stdio
+ }
+ }
+ if(binary && fp) {
+#if defined(__CYGWIN32__)
+ setmode(fileno(fp), O_BINARY);
+#elif defined(WIN32)
+ _setmode(_fileno(fp), _O_BINARY);
+#endif
+ }
+ GUTF8String retval;
+ if(!mesg)
+ {
+ tell();
+ }else
+ {
+ retval=mesg;
+ }
+ if(mesg &&(fp && must_close))
+ {
+ fclose(fp);
+ fp=0;
+ must_close=false;
+ }
+ return retval;
+}
+
+static FILE *
+urlfopen(const GURL &url,const char mode[])
+{
+#ifdef WIN32
+ FILE *retval=0;
+ const GUTF8String filename(url.UTF8Filename());
+ wchar_t *wfilename;
+ const size_t wfilename_size=filename.length()+1;
+ GPBuffer<wchar_t> gwfilename(wfilename,wfilename_size);
+ if(filename.ncopy(wfilename,wfilename_size) > 0)
+ {
+ const GUTF8String gmode(mode);
+ wchar_t *wmode;
+ const size_t wmode_size=gmode.length()+1;
+ GPBuffer<wchar_t> gwmode(wmode,wmode_size);
+ if(gmode.ncopy(wmode,wmode_size) > 0)
+ {
+ retval=_wfopen(wfilename,wmode);
+ }
+ }
+ return retval?retval:fopen((const char *)url.NativeFilename(),mode);
+#else
+ return fopen((const char *)url.NativeFilename(),mode);
+#endif
+}
+
+#ifdef UNIX
+static int
+urlopen(const GURL &url, const int mode, const int perm)
+{
+ return open((const char *)url.NativeFilename(),mode,perm);
+}
+#endif /* UNIX */
+
+GUTF8String
+ByteStream::Stdio::init(const GURL &url, const char mode[])
+{
+ GUTF8String retval;
+ if (url.fname() != "-")
+ {
+ fp = urlfopen(url,mode);
+ if (!fp)
+ {
+ // Failed to open '%s': %s
+ G_THROW( ERR_MSG("ByteStream.open_fail") "\t" + url.name()
+ +"\t"+GNativeString(strerror(errno)).getNative2UTF8());
+ }
+ }
+ return retval.length()?retval:init(mode);
+}
+
+size_t
+ByteStream::Stdio::read(void *buffer, size_t size)
+{
+ if (!can_read)
+ G_THROW( ERR_MSG("ByteStream.no_read") ); // Stdio not opened for reading
+ size_t nitems;
+ do
+ {
+ clearerr(fp);
+ nitems = fread(buffer, 1, size, fp);
+ if (nitems<=0 && ferror(fp))
+ {
+#ifdef EINTR
+ if (errno!=EINTR)
+#endif
+ G_THROW(strerror(errno)); // (No error in the DjVuMessageFile)
+ }
+ else
+ break;
+ } while(true);
+ pos += nitems;
+ return nitems;
+}
+
+size_t
+ByteStream::Stdio::write(const void *buffer, size_t size)
+{
+ if (!can_write)
+ G_THROW( ERR_MSG("ByteStream.no_write") ); // Stdio not opened for writing
+ size_t nitems;
+ do
+ {
+ clearerr(fp);
+ nitems = fwrite(buffer, 1, size, fp);
+ if (nitems<=0 && ferror(fp))
+ {
+#ifdef EINTR
+ if (errno!=EINTR)
+#endif
+ G_THROW(strerror(errno)); // (No error in the DjVuMessageFile)
+ }
+ else
+ break;
+ } while(true);
+ pos += nitems;
+ return nitems;
+}
+
+void
+ByteStream::Stdio::flush()
+{
+ if (fflush(fp) < 0)
+ G_THROW(strerror(errno)); // (No error in the DjVuMessageFile)
+}
+
+long
+ByteStream::Stdio::tell(void) const
+{
+ long x = ftell(fp);
+ if (x >= 0)
+ {
+ Stdio *sbs=const_cast<Stdio *>(this);
+ (sbs->pos) = x;
+ }else
+ {
+ x=pos;
+ }
+ return x;
+}
+
+int
+ByteStream::Stdio::seek(long offset, int whence, bool nothrow)
+{
+ if (whence==SEEK_SET && offset>=0 && offset==ftell(fp))
+ return 0;
+ clearerr(fp);
+ if (fseek(fp, offset, whence))
+ {
+ if (nothrow)
+ return -1;
+ G_THROW(strerror(errno)); // (No error in the DjVuMessageFile)
+ }
+ return tell();
+}
+
+
+
+
+///////// ByteStream::Memory
+
+ByteStream::Memory::Memory()
+ : where(0), bsize(0), nblocks(0), gblocks(blocks,0)
+{
+}
+
+GUTF8String
+ByteStream::Memory::init(void const * const buffer, const size_t sz)
+{
+ GUTF8String retval;
+ G_TRY
+ {
+ writall(buffer, sz);
+ where = 0;
+ }
+ G_CATCH(ex) // The only error that should be thrown is out of memory...
+ {
+ retval=ex.get_cause();
+ }
+ G_ENDCATCH;
+ return retval;
+}
+
+void
+ByteStream::Memory::empty()
+{
+ for (int b=0; b<nblocks; b++)
+ {
+ delete [] blocks[b];
+ blocks[b]=0;
+ }
+ bsize = 0;
+ where = 0;
+ nblocks = 0;
+}
+
+ByteStream::Memory::~Memory()
+{
+ empty();
+}
+
+size_t
+ByteStream::Memory::write(const void *buffer, size_t sz)
+{
+ int nsz = (int)sz;
+ if (nsz <= 0)
+ return 0;
+ // check memory
+ if ( (where+nsz) > ((bsize+0xfff)&~0xfff) )
+ {
+ // reallocate pointer array
+ if ( (where+nsz) > (nblocks<<12) )
+ {
+ const int old_nblocks=nblocks;
+ nblocks = (((where+nsz)+0xffff)&~0xffff) >> 12;
+ gblocks.resize(nblocks);
+ char const ** eblocks=(char const **)(blocks+old_nblocks);
+ for(char const * const * const new_eblocks=blocks+nblocks;
+ eblocks <new_eblocks; eblocks++)
+ {
+ *eblocks = 0;
+ }
+ }
+ // allocate blocks
+ for (int b=(where>>12); (b<<12)<(where+nsz); b++)
+ {
+ if (! blocks[b])
+ blocks[b] = new char[0x1000];
+ }
+ }
+ // write data to buffer
+ while (nsz > 0)
+ {
+ int n = (where|0xfff) + 1 - where;
+ n = ((nsz < n) ? nsz : n);
+ memcpy( (void*)&blocks[where>>12][where&0xfff], buffer, n);
+ buffer = (void*) ((char*)buffer + n);
+ where += n;
+ nsz -= n;
+ }
+ // adjust size
+ if (where > bsize)
+ bsize = where;
+ return sz;
+}
+
+size_t
+ByteStream::Memory::readat(void *buffer, size_t sz, int pos)
+{
+ if ((int) sz > bsize - pos)
+ sz = bsize - pos;
+ int nsz = (int)sz;
+ if (nsz <= 0)
+ return 0;
+ // read data from buffer
+ while (nsz > 0)
+ {
+ int n = (pos|0xfff) + 1 - pos;
+ n = ((nsz < n) ? nsz : n);
+ memcpy(buffer, (void*)&blocks[pos>>12][pos&0xfff], n);
+ buffer = (void*) ((char*)buffer + n);
+ pos += n;
+ nsz -= n;
+ }
+ return sz;
+}
+
+size_t
+ByteStream::Memory::read(void *buffer, size_t sz)
+{
+ sz = readat(buffer,sz,where);
+ where += sz;
+ return sz;
+}
+
+long
+ByteStream::Memory::tell(void) const
+{
+ return where;
+}
+
+int
+ByteStream::Memory::seek(long offset, int whence, bool nothrow)
+{
+ int nwhere = 0;
+ switch (whence)
+ {
+ case SEEK_SET: nwhere = 0; break;
+ case SEEK_CUR: nwhere = where; break;
+ case SEEK_END: nwhere = bsize; break;
+ default: G_THROW( ERR_MSG("bad_arg") "\tByteStream::Memory::seek()"); // Illegal argument in ByteStream::Memory::seek()
+ }
+ nwhere += offset;
+ if (nwhere<0)
+ G_THROW( ERR_MSG("ByteStream.seek_error2") ); // Attempt to seek before the beginning of the file
+ where = nwhere;
+ return 0;
+}
+
+
+
+/** This function has been moved into Arrays.cpp
+ In order to avoid dependencies from ByteStream.o
+ to Arrays.o */
+#ifdef DO_NOT_MOVE_GET_DATA_TO_ARRAYS_CPP
+TArray<char>
+ByteStream::get_data(void)
+{
+ TArray<char> data(0, size()-1);
+ readat((char*)data, size(), 0);
+ return data;
+}
+#endif
+
+
+///////// ByteStream::Static
+
+ByteStream::Static::Static(const void * const buffer, const size_t sz)
+ : data((const char *)buffer), bsize(sz), where(0)
+{
+}
+
+size_t
+ByteStream::Static::read(void *buffer, size_t sz)
+{
+ int nsz = (int)sz;
+ if (nsz > bsize - where)
+ nsz = bsize - where;
+ if (nsz <= 0)
+ return 0;
+ memcpy(buffer, data+where, nsz);
+ where += nsz;
+ return nsz;
+}
+
+int
+ByteStream::Static::seek(long offset, int whence, bool nothrow)
+{
+ int nwhere = 0;
+ switch (whence)
+ {
+ case SEEK_SET: nwhere = 0; break;
+ case SEEK_CUR: nwhere = where; break;
+ case SEEK_END: nwhere = bsize; break;
+ default: G_THROW("bad_arg\tByteStream::Static::seek()"); // Illegal argument to ByteStream::Static::seek()
+ }
+ nwhere += offset;
+ if (nwhere<0)
+ G_THROW( ERR_MSG("ByteStream.seek_error2") ); // Attempt to seek before the beginning of the file
+ where = nwhere;
+ return 0;
+}
+
+long
+ByteStream::Static::tell(void) const
+{
+ return where;
+}
+
+GP<ByteStream>
+ByteStream::create(void)
+{
+ return new Memory();
+}
+
+GP<ByteStream>
+ByteStream::create(void const * const buffer, const size_t size)
+{
+ Memory *mbs=new Memory();
+ GP<ByteStream> retval=mbs;
+ mbs->init(buffer,size);
+ return retval;
+}
+
+GP<ByteStream>
+ByteStream::create(const GURL &url,char const * const xmode)
+{
+ GP<ByteStream> retval;
+ const char *mode = ((xmode) ? xmode : "rb");
+#ifdef UNIX
+ if (!strcmp(mode,"rb"))
+ {
+ int fd = urlopen(url,O_RDONLY,0777);
+ if (fd >= 0)
+ {
+#if HAS_MEMMAP && defined(S_IFREG)
+ struct stat buf;
+ if ( (fstat(fd, &buf) >= 0) && (buf.st_mode & S_IFREG) )
+ {
+ MemoryMapByteStream *rb = new MemoryMapByteStream();
+ retval = rb;
+ GUTF8String errmessage = rb->init(fd,true);
+ if(errmessage.length())
+ retval=0;
+ }
+#endif
+ if (! retval)
+ {
+ FILE *f = fdopen(fd, mode);
+ if (f)
+ {
+ Stdio *sbs=new Stdio();
+ retval=sbs;
+ GUTF8String errmessage=sbs->init(f, mode, true);
+ if(errmessage.length())
+ retval=0;
+ }
+ }
+ if (! retval)
+ close(fd);
+ }
+ }
+#endif
+ if (! retval)
+ {
+ Stdio *sbs=new Stdio();
+ retval=sbs;
+ GUTF8String errmessage=sbs->init(url, mode);
+ if(errmessage.length())
+ G_THROW(errmessage);
+ }
+ return retval;
+}
+
+GP<ByteStream>
+ByteStream::create(char const * const mode)
+{
+ GP<ByteStream> retval;
+ Stdio *sbs=new Stdio();
+ retval=sbs;
+ GUTF8String errmessage=sbs->init(mode?mode:"rb");
+ if(errmessage.length())
+ {
+ G_THROW(errmessage);
+ }
+ return retval;
+}
+
+GP<ByteStream>
+ByteStream::create(const int fd,char const * const mode,const bool closeme)
+{
+ GP<ByteStream> retval;
+ const char *default_mode="rb";
+#if HAS_MEMMAP
+ if ( (!mode&&(fd!=0)&&(fd!=1)&&(fd!=2))
+ || (mode&&(GUTF8String("rb") == mode)))
+ {
+ MemoryMapByteStream *rb=new MemoryMapByteStream();
+ retval=rb;
+ GUTF8String errmessage=rb->init(fd,closeme);
+ if(errmessage.length())
+ {
+ retval=0;
+ }
+ }
+ if(!retval)
+#endif
+ {
+ int fd2 = fd;
+ FILE *f = 0;
+ if (fd == 0 && !closeme
+ && (!mode || mode[0]=='r') )
+ {
+ f=stdin;
+ default_mode = "r";
+ fd2=(-1);
+ }
+ else if (fd == 1 && !closeme
+ && (!mode || mode[0]=='a' || mode[0]=='w') )
+ {
+ default_mode = "a";
+ f=stdout;
+ fd2 = -1;
+ }
+ else if (fd == 2 && !closeme
+ && (!mode || mode[0]=='a' || mode[0]=='w') )
+ {
+ default_mode = "a";
+ f=stderr;
+ fd2 = -1;
+ }
+ else
+ {
+ if (! closeme)
+ fd2 = dup(fd);
+ f = fdopen(fd2,(char*)(mode?mode:default_mode));
+ }
+
+ if(!f)
+ {
+ if ( fd2 >= 0)
+ close(fd2);
+ G_THROW( ERR_MSG("ByteStream.open_fail2") );
+ }
+ Stdio *sbs=new Stdio();
+ retval=sbs;
+ GUTF8String errmessage=sbs->init(f,mode?mode:default_mode,(fd2>=0));
+ if(errmessage.length())
+ G_THROW(errmessage);
+ }
+ return retval;
+}
+
+GP<ByteStream>
+ByteStream::create(FILE * const f,char const * const mode,const bool closeme)
+{
+ GP<ByteStream> retval;
+#if HAS_MEMMAP
+ if (!mode || (GUTF8String("rb") == mode))
+ {
+ MemoryMapByteStream *rb=new MemoryMapByteStream();
+ retval=rb;
+ GUTF8String errmessage=rb->init(fileno(f),false);
+ if(errmessage.length())
+ {
+ retval=0;
+ }else
+ {
+ fclose(f);
+ }
+ }
+ if(!retval)
+#endif
+ {
+ Stdio *sbs=new Stdio();
+ retval=sbs;
+ GUTF8String errmessage=sbs->init(f,mode?mode:"rb",closeme);
+ if(errmessage.length())
+ {
+ G_THROW(errmessage);
+ }
+ }
+ return retval;
+}
+
+GP<ByteStream>
+ByteStream::create_static(const void * const buffer, size_t sz)
+{
+ return new Static(buffer, sz);
+}
+
+GP<ByteStream>
+ByteStream::duplicate(const size_t xsize) const
+{
+ GP<ByteStream> retval;
+ const long int pos=tell();
+ const int tsize=size();
+ ByteStream &self=*(const_cast<ByteStream *>(this));
+ if(tsize < 0 || pos < 0 || (unsigned int)tsize < 1+(unsigned int)pos)
+ {
+ retval=ByteStream::create();
+ retval->copy(self,xsize);
+ retval->seek(0L);
+ }else
+ {
+ const size_t s=(size_t)tsize-(size_t)pos;
+ const int size=(!xsize||(s<xsize))?s:xsize;
+ ByteStream::Static::Allocate *bs=new ByteStream::Static::Allocate(size);
+ retval=bs;
+ self.readall(bs->buf,size);
+ }
+ self.seek(pos,SEEK_SET,true);
+ return retval;
+}
+
+
+#if HAS_MEMMAP
+MemoryMapByteStream::MemoryMapByteStream(void)
+: ByteStream::Static(0,0)
+{}
+
+GUTF8String
+MemoryMapByteStream::init(FILE *const f,const bool closeme)
+{
+ GUTF8String retval;
+ retval=init(fileno(f),false);
+ if(closeme)
+ {
+ fclose(f);
+ }
+ return retval;
+}
+
+GUTF8String
+MemoryMapByteStream::init(const int fd,const bool closeme)
+{
+ GUTF8String retval;
+#if defined(PROT_READ) && defined(MAP_SHARED)
+ struct stat statbuf;
+ if(!fstat(fd,&statbuf))
+ {
+ if(statbuf.st_size)
+ {
+ bsize=statbuf.st_size;
+ data=(char *)mmap(0,statbuf.st_size,PROT_READ,MAP_SHARED,fd,0);
+ }
+ }else
+ {
+ if(closeme)
+ {
+ close(fd);
+ }
+ retval= ERR_MSG("ByteStream.open_fail2");
+ }
+#else
+ retval= ERR_MSG("ByteStream.open_fail2");
+#endif
+ if(closeme)
+ {
+ close(fd);
+ }
+ return retval;
+}
+
+MemoryMapByteStream::~MemoryMapByteStream()
+{
+ if(data)
+ {
+ munmap(const_cast<char *>(data),bsize);
+ }
+}
+
+#endif
+
+ByteStream::Wrapper::~Wrapper() {}
+
+
+GP<ByteStream>
+ByteStream::get_stdin(char const * const mode)
+{
+ static GP<ByteStream> gp = ByteStream::create(0,mode,false);
+ return gp;
+}
+
+GP<ByteStream>
+ByteStream::get_stdout(char const * const mode)
+{
+ static GP<ByteStream> gp = ByteStream::create(1,mode,false);
+ return gp;
+}
+
+GP<ByteStream>
+ByteStream::get_stderr(char const * const mode)
+{
+ static GP<ByteStream> gp = ByteStream::create(2,mode,false);
+ return gp;
+}
+
+
+/** Looks up the message and writes it to the specified stream. */
+void ByteStream::formatmessage( const char *fmt, ... )
+{
+ va_list args;
+ va_start(args, fmt);
+ const GUTF8String message(fmt,args);
+ writemessage( message );
+}
+
+/** Looks up the message and writes it to the specified stream. */
+void ByteStream::writemessage( const char *message )
+{
+ writestring( DjVuMessage::LookUpUTF8( message ) );
+}
+
+static void
+read_file(ByteStream &bs,char *&buffer,GPBuffer<char> &gbuffer)
+{
+ const int size=bs.size();
+ int pos=0;
+ if(size>0)
+ {
+ size_t readsize=size+1;
+ gbuffer.resize(readsize);
+ for(int i;readsize&&(i=bs.read(buffer+pos,readsize))>0;pos+=i,readsize-=i)
+ EMPTY_LOOP;
+ }else
+ {
+ const size_t readsize=32768;
+ gbuffer.resize(readsize);
+ for(int i;((i=bs.read(buffer+pos,readsize))>0);
+ gbuffer.resize((pos+=i)+readsize))
+ EMPTY_LOOP;
+ }
+ buffer[pos]=0;
+}
+
+GNativeString
+ByteStream::getAsNative(void)
+{
+ char *buffer;
+ GPBuffer<char> gbuffer(buffer);
+ read_file(*this,buffer,gbuffer);
+ return GNativeString(buffer);
+}
+
+GUTF8String
+ByteStream::getAsUTF8(void)
+{
+ char *buffer;
+ GPBuffer<char> gbuffer(buffer);
+ read_file(*this,buffer,gbuffer);
+ return GUTF8String(buffer);
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+
+void
+DjVuPrintErrorUTF8(const char *fmt, ... )
+{
+ G_TRY {
+ GP<ByteStream> errout = ByteStream::get_stderr();
+ if (errout)
+ {
+ errout->cp=ByteStream::NATIVE;
+ va_list args;
+ va_start(args, fmt);
+ const GUTF8String message(fmt,args);
+ errout->writestring(message);
+ }
+ // Need to catch all exceptions because these might be
+ // called from an outer exception handler (with prejudice)
+ } G_CATCH_ALL { } G_ENDCATCH;
+}
+
+void
+DjVuPrintErrorNative(const char *fmt, ... )
+{
+ G_TRY {
+ GP<ByteStream> errout = ByteStream::get_stderr();
+ if (errout)
+ {
+ errout->cp=ByteStream::NATIVE;
+ va_list args;
+ va_start(args, fmt);
+ const GNativeString message(fmt,args);
+ errout->writestring(message);
+ }
+ // Need to catch all exceptions because these might be
+ // called from an outer exception handler (with prejudice)
+ } G_CATCH_ALL { } G_ENDCATCH;
+}
+
+void
+DjVuPrintMessageUTF8(const char *fmt, ... )
+{
+ G_TRY {
+ GP<ByteStream> strout = ByteStream::get_stdout();
+ if (strout)
+ {
+ strout->cp=ByteStream::NATIVE;
+ va_list args;
+ va_start(args, fmt);
+ const GUTF8String message(fmt,args);
+ strout->writestring(message);
+ }
+ // Need to catch all exceptions because these might be
+ // called from an outer exception handler (with prejudice)
+ } G_CATCH_ALL { } G_ENDCATCH;
+}
+
+void
+DjVuPrintMessageNative(const char *fmt, ... )
+{
+ G_TRY {
+ GP<ByteStream> strout = ByteStream::get_stdout();
+ if (strout)
+ {
+ strout->cp=ByteStream::NATIVE;
+ va_list args;
+ va_start(args, fmt);
+ const GNativeString message(fmt,args);
+ strout->writestring(message);
+ }
+ // Need to catch all exceptions because these might be
+ // called from an outer exception handler (with prejudice)
+ } G_CATCH_ALL { } G_ENDCATCH;
+}
diff --git a/kviewshell/plugins/djvu/libdjvu/ByteStream.h b/kviewshell/plugins/djvu/libdjvu/ByteStream.h
new file mode 100644
index 00000000..7ecfd8b7
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/ByteStream.h
@@ -0,0 +1,416 @@
+//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: ByteStream.h,v 1.11 2003/11/07 22:08:20 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _BYTESTREAM_H
+#define _BYTESTREAM_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+/** @name ByteStream.h
+
+ Files #"ByteStream.h"# and #"ByteStream.cpp"# define input/output classes
+ similar in spirit to the well known C++ #iostream# classes. Class
+ \Ref{ByteStream} is an abstract base class for all byte streams. It
+ defines a virtual interface and also provides useful functions. These
+ files provide two subclasses. Class \Ref{ByteStream::Stdio} provides a
+ simple interface to the Ansi C buffered input/output functions. Class
+ \Ref{ByteStream::Memory} provides stream-like access to a dynamical array
+ maintained in memory. Class \Ref{ByteStream::Static} provides read-only
+ stream-like access to a user allocated data buffer.
+
+ {\bf Notes} --- These classes were partly written because we did not want to
+ depend on the standard C++ library. The main reason however is related to
+ the browser interface. We want to have a tight control over the
+ implementation of subclasses because we want to use a byte stream to
+ represent data passed by a web browser to a plugin. This operation
+ involves multi-threading issues that many implementations of the standard
+ C++ library would squarely ignore.
+
+ @memo
+ Input/output classes
+ @author
+ L\'eon Bottou <leonb@research.att.com> -- initial implementation\\
+ Andrei Erofeev <eaf@geocities.com> --
+
+// From: Leon Bottou, 1/31/2002
+// This file has very little to do with my initial implementation.
+// It has been practically rewritten by Lizardtech for i18n changes.
+// Our original implementation consisted of multiple classes.
+// <http://prdownloads.sourceforge.net/djvu/DjVu2_2b-src.tgz>.
+
+
+ @version
+ #$Id: ByteStream.h,v 1.11 2003/11/07 22:08:20 leonb Exp $# */
+//@{
+
+
+#include "Arrays.h"
+#include <stdio.h>
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+class GURL;
+class GUTF8String;
+class GNativeString;
+
+/** Abstract class for a stream of bytes. Class #ByteStream# represent an
+ object from which (resp. to which) bytes can be read (resp. written) as
+ with a regular file. Virtual functions #read# and #write# must implement
+ these two basic operations. In addition, function #tell# returns an
+ offset identifying the current position, and function #seek# may be used
+ to change the current position.
+
+ {\bf Note}. Both the copy constructor and the copy operator are declared
+ as private members. It is therefore not possible to make multiple copies
+ of instances of this class, as implied by the class semantic.
+*/
+class ByteStream : public GPEnabled
+{
+public:
+ class Stdio;
+ class Static;
+ class Memory;
+ class Wrapper;
+ enum codepage_type {RAW,AUTO,NATIVE,UTF8} cp;
+
+ /** @name Virtual Functions.
+ These functions are usually implemented by each subclass of #ByteStream#.
+ */
+ //@{
+public:
+ /** Virtual destructor. */
+ virtual ~ByteStream();
+ /** Reads data from a ByteStream. This function {\em must} be implemented
+ by each subclass of #ByteStream#. At most #size# bytes are read from
+ the ByteStream and stored in the memory area pointed to by #buffer#.
+ Function #read# returns immediately if #size# is zero. The actual number
+ of bytes read is returned. Function #read# returns a number of bytes
+ smaller than #size# if the end-of-file mark is reached before filling
+ the buffer. Subsequent invocations will always return value #0#.
+ Function #read# may also return a value greater than zero but smaller
+ than #size# for internal reasons. Programs must be ready to handle these
+ cases or use function \Ref{readall}. Exception \Ref{GException} is
+ thrown with a plain text error message whenever an error occurs. */
+ virtual size_t read(void *buffer, size_t size);
+ /** Writes data to a ByteStream. This function {\em must} be implemented by
+ each subclass of #ByteStream#. At most #size# bytes from buffer
+ #buffer# are written to the ByteStream. Function #write# returns
+ immediately if #size# is zero. The actual number of bytes written is
+ returned. Function #write# may also return a value greater than zero but
+ smaller than #size# for internal reasons. Programs must be ready to
+ handle these cases or use function \Ref{writall}. Exception
+ \Ref{GException} is thrown with a plain text error message whenever an
+ error occurs. */
+ virtual size_t write(const void *buffer, size_t size);
+ /** Returns the offset of the current position in the ByteStream. This
+ function {\em must} be implemented by each subclass of #ByteStream#. */
+ virtual long tell(void) const = 0;
+ /** Sets the current position for reading or writing the ByteStream. Class
+ #ByteStream# provides a default implementation able to seek forward by
+ calling function #read# until reaching the desired position. Subclasses
+ implementing better seek capabilities must override this default
+ implementation. The new current position is computed by applying
+ displacement #offset# to the position represented by argument
+ #whence#. The following values are recognized for argument #whence#:
+ \begin{description}
+ \item[#SEEK_SET#] Argument #offset# indicates the position relative to
+ the beginning of the ByteStream.
+ \item[#SEEK_CUR#] Argument #offset# is a signed displacement relative to
+ the current position.
+ \item[#SEEK_END#] Argument #offset# is a displacement relative to the end
+ of the file. It is then advisable to provide a negative value for #offset#.
+ \end{description}
+ Results are undefined whenever the new position is greater than the
+ total size of the ByteStream.
+
+ {\bf Error reporting}:
+ If #seek()# succeeds, #0# is returned. Otherwise it either returns
+ #-1# (if #nothrow# is set to #FALSE#) or throws the \Ref{GException}
+ exception. */
+ virtual int seek(long offset, int whence = SEEK_SET, bool nothrow=false);
+ /** Flushes all buffers in the ByteStream. Calling this function
+ guarantees that pending data have been actually written (i.e. passed to
+ the operating system). Class #ByteStream# provides a default
+ implementation which does nothing. */
+ virtual void flush(void);
+ //@}
+ /** @name Utility Functions.
+ Class #ByteStream# implements these functions using the virtual
+ interface functions only. All subclasses of #ByteStream# inherit these
+ functions. */
+ //@{
+public:
+ /** Reads data and blocks until everything has been read. This function is
+ essentially similar to function #read#. Unlike function #read# however,
+ function #readall# will never return a value smaller than #size# unless
+ an end-of-file mark is reached. This is implemented by repeatedly
+ calling function #read# until everything is read or until we reach an
+ end-of-file mark. Note that #read# and #readall# are equivalent when
+ #size# is one. */
+ size_t readall(void *buffer, size_t size);
+ /** Writes data and blocks until everything has been written. This function
+ is essentially similar to function #write#. Unlike function #write#
+ however, function #writall# will only return after all #size# bytes have
+ been written. This is implemented by repeatedly calling function
+ #write# until everything is written. Note that #write# and #writall#
+ are equivalent when #size# is one. */
+ size_t writall(const void *buffer, size_t size);
+ /** Copy data from another ByteStream. A maximum of #size# bytes are read
+ from the ByteStream #bsfrom# and are written to the ByteStream #*this#
+ at the current position. Less than #size# bytes may be written if an
+ end-of-file mark is reached on #bsfrom#. This function returns the
+ total number of bytes copied. Setting argument #size# to zero (the
+ default value) has a special meaning: the copying process will continue
+ until reaching the end-of-file mark on ByteStream #bsfrom#, regardless
+ of the number of bytes transferred. */
+ size_t copy(ByteStream &bsfrom, size_t size=0);
+ /** Create a new #ByteStream# that copies the data from this #ByteStream#
+ starting from the current position, upto #size# bytes. Setting the
+ #size# to zero means copy to the end-of-file mark. */
+ GP<ByteStream> duplicate(const size_t size=0) const;
+ /// Allows printf() type operations to a bytestream.
+ size_t format(const char *fmt, ... );
+ /// Allows scanf() type operations on a bytestream.
+ int scanf(const char *fmt, ... );
+ /** Writes the string as is, to the specified stream. */
+ size_t writestring(const GUTF8String &s);
+ /** Writes the string as is, to the specified stream. */
+ size_t writestring(const GNativeString &s);
+ /** Formats the message string, looks up the external representation
+ and writes it to the specified stream. */
+ void formatmessage( const char *fmt, ... );
+ /** Looks up the message and writes it to the specified stream. */
+ void writemessage( const char *message );
+ /** Writes a one-byte integer to a ByteStream. */
+ void write8 (unsigned int card8);
+ /** Writes a two-bytes integer to a ByteStream.
+ The integer most significant byte is written first,
+ regardless of the processor endianness. */
+ void write16(unsigned int card16);
+ /** Writes a three-bytes integer to a ByteStream.
+ The integer most significant byte is written first,
+ regardless of the processor endianness. */
+ void write24(unsigned int card24);
+ /** Writes a four-bytes integer to a ByteStream.
+ The integer most significant bytes are written first,
+ regardless of the processor endianness. */
+ void write32(unsigned int card32);
+ /** Reads a one-byte integer from a ByteStream. */
+ unsigned int read8 ();
+ /** Reads a two-bytes integer from a ByteStream.
+ The integer most significant byte is read first,
+ regardless of the processor endianness. */
+ unsigned int read16();
+ /** Reads a three-bytes integer from a ByteStream.
+ The integer most significant byte is read first,
+ regardless of the processor endianness. */
+ unsigned int read24();
+ /** Reads a four-bytes integer from a ByteStream.
+ The integer most significant bytes are read first,
+ regardless of the processor endianness. */
+ unsigned int read32();
+ /** Returns the total number of bytes contained in the buffer, file, etc.
+ Valid offsets for function #seek# range from 0 to the value returned
+ by this function. */
+ virtual int size(void) const;
+ /// Use at your own risk, only guarenteed to work for ByteStream::Memorys.
+ TArray<char> get_data(void);
+ /** Reads data from a random position. This function reads at most #sz#
+ bytes at position #pos# into #buffer# and returns the actual number of
+ bytes read. The current position is unchanged. */
+ virtual size_t readat(void *buffer, size_t sz, int pos);
+ /// Returns false, unless a subclass of ByteStream::Static
+ virtual bool is_static(void) const { return false; }
+ //@}
+protected:
+ ByteStream(void) : cp(AUTO) {};
+private:
+ // Cancel C++ default stuff
+ ByteStream(const ByteStream &);
+ ByteStream & operator=(const ByteStream &);
+public:
+ /** Constructs an empty Memory ByteStream. The buffer itself is organized
+ as an array of 4096 byte blocks. The buffer is initially empty. You
+ must first use function #write# to store data into the buffer, use
+ function #seek# to rewind the current position, and function #read# to
+ read the data back. */
+ static GP<ByteStream> create(void);
+ /** Constructs a Memory ByteStream by copying initial data. The
+ Memory buffer is initialized with #size# bytes copied from the
+ memory area pointed to by #buffer#. */
+ static GP<ByteStream> create(void const * const buffer, const size_t size);
+ /** Constructs a ByteStream for accessing the file named #url#.
+ Arguments #url# and #mode# are similar to the arguments of the well
+ known stdio function #fopen#. In addition a url of #-# will be
+ interpreted as the standard output or the standard input according to
+ #mode#. This constructor will open a stdio file and construct a
+ ByteStream object accessing this file. Destroying the ByteStream object
+ will flush and close the associated stdio file. Exception
+ \Ref{GException} is thrown with a plain text error message if the stdio
+ file cannot be opened. */
+ static GP<ByteStream> create(
+ const GURL &url, char const * const mode);
+ /** Same as the above, but uses stdin or stdout */
+ static GP<ByteStream> create( char const * const mode);
+
+ /** Constructs a ByteStream for accessing the stdio file #f#.
+ Argument #mode# indicates the type of the stdio file, as in the
+ well known stdio function #fopen#. Destroying the ByteStream
+ object will not close the stdio file #f# unless closeme is true. */
+ static GP<ByteStream> create(
+ const int fd, char const * const mode, const bool closeme);
+
+ /** Constructs a ByteStream for accessing the stdio file #f#.
+ Argument #mode# indicates the type of the stdio file, as in the
+ well known stdio function #fopen#. Destroying the ByteStream
+ object will not close the stdio file #f# unless closeme is true. */
+ static GP<ByteStream> create(
+ FILE * const f, char const * const mode, const bool closeme);
+ /** Creates a ByteStream object for allocating the memory area of
+ length #sz# starting at address #buffer#. This call impliments
+ a read-only ByteStream interface for a memory area specified by
+ the user at construction time. Calls to function #read# directly
+ access this memory area. The user must therefore make sure that its
+ content remain valid long enough. */
+ static GP<ByteStream> create_static(
+ void const * const buffer, const size_t size);
+
+ /** Easy access to preallocated stdin/stdout/stderr bytestreams */
+ static GP<ByteStream> get_stdin(char const * const mode=0);
+ static GP<ByteStream> get_stdout(char const * const mode=0);
+ static GP<ByteStream> get_stderr(char const * const mode=0);
+
+ /** This is the conventional name for EOF exceptions */
+ static const char *EndOfFile;
+ /** Returns the contents of the file as a GNativeString */
+ GNativeString getAsNative(void);
+ /** Returns the contents of the file as a GUTF8String */
+ GUTF8String getAsUTF8(void);
+};
+
+inline size_t
+ByteStream::readat(void *buffer, size_t sz, int pos)
+{
+ size_t retval;
+ long tpos=tell();
+ seek(pos, SEEK_SET, true);
+ retval=readall(buffer,sz);
+ seek(tpos, SEEK_SET, true);
+ return retval;
+}
+
+inline int
+ByteStream::size(void) const
+{
+ ByteStream *bs=const_cast<ByteStream *>(this);
+ int bsize=(-1);
+ long pos=tell();
+ if(bs->seek(0,SEEK_END,true))
+ {
+ bsize=(int)tell();
+ (void)(bs->seek(pos,SEEK_SET,false));
+ }
+ return bsize;
+}
+
+/** ByteStream::Wrapper implements wrapping bytestream. This is useful
+ for derived classes that take a GP<ByteStream> as a creation argument,
+ and the backwards compatible bytestreams. */
+class ByteStream::Wrapper : public ByteStream
+{
+protected:
+ GP<ByteStream> gbs;
+ ByteStream *bs;
+ Wrapper(void) : bs(0) {}
+ Wrapper(const GP<ByteStream> &xbs) : gbs(xbs), bs(xbs) {}
+public:
+ ~Wrapper();
+ ByteStream * operator & () const {return bs;}
+ ByteStream * operator & () {return bs;}
+ virtual size_t read(void *buffer, size_t size)
+ { return bs->read(buffer,size); }
+ virtual size_t write(const void *buffer, size_t size)
+ { return bs->write(buffer,size); }
+ virtual long tell(void) const
+ { return bs->tell(); }
+ virtual int seek(long offset, int whence = SEEK_SET, bool nothrow=false)
+ { return bs->seek(offset,whence,nothrow); }
+ virtual void flush(void)
+ { bs->flush(); }
+};
+
+
+//@}
+
+// ------------ THE END
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
+
diff --git a/kviewshell/plugins/djvu/libdjvu/DataPool.cpp b/kviewshell/plugins/djvu/libdjvu/DataPool.cpp
new file mode 100644
index 00000000..1190292e
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DataPool.cpp
@@ -0,0 +1,1837 @@
+//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: DataPool.cpp,v 1.11 2004/08/06 15:11:29 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "DataPool.h"
+#include "IFFByteStream.h"
+#include "GString.h"
+#include "GOS.h"
+#include "GURL.h"
+#include "debug.h"
+
+#ifndef macintosh
+# include <sys/types.h>
+#endif
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+const char * DataPool::Stop = ERR_MSG("STOP");
+
+static void
+// call_callback(void (* callback)(GP<GPEnabled> &), GP<GPEnabled> cl_data)
+call_callback(void (* callback)(void *), void *cl_data)
+{
+ G_TRY
+ {
+ if (callback)
+ callback(cl_data);
+ } G_CATCH_ALL {} G_ENDCATCH;
+}
+
+
+//****************************************************************************
+//****************************** OpenFiles ***********************************
+//****************************************************************************
+
+#define MAX_OPEN_FILES 15
+
+/** The purpose of this class is to limit the number of files open by
+ connected DataPools. Now, when a DataPool is connected to a file, it
+ doesn't necessarily has it open. Every time it needs access to data
+ it's supposed to ask this file for the ByteStream. It should
+ also inform the class when it's going to die (so that the file can
+ be closed). OpenFiles makes sure, that the number of open files
+ doesn't exceed MAX_OPEN_FILES. When it does, it looks for the oldest
+ file, closes it and asks all DataPools working with it to ZERO
+ their GP<> pointers. */
+class DataPool::OpenFiles_File : public GPEnabled
+{
+public:
+ GURL url;
+ GP<ByteStream> stream; // Stream connected to 'url'
+ GCriticalSection stream_lock;
+ GPList<DataPool> pools_list; // List of pools using this stream
+ GCriticalSection pools_lock;
+ unsigned long open_time; // Time when stream was open
+
+ int add_pool(GP<DataPool> &pool);
+ int del_pool(GP<DataPool> &pool);
+
+ OpenFiles_File(const GURL &url, GP<DataPool> &pool);
+ virtual ~OpenFiles_File(void);
+ void clear_stream(void);
+};
+
+class DataPool::OpenFiles : public GPEnabled
+{
+private:
+ static OpenFiles * global_ptr;
+
+ GPList<DataPool::OpenFiles_File> files_list;
+ GCriticalSection files_lock;
+public:
+ static OpenFiles * get(void);
+
+ // Opend the specified file if necessary (or finds an already open one)
+ // and returns it. The caller (pool) is stored in the list associated
+ // with the stream. Whenever OpenFiles decides, that this stream
+ // had better be closed, it will order every pool from the list to
+ // ZERO their references to it
+ GP<DataPool::OpenFiles_File> request_stream(const GURL &url, GP<DataPool> pool);
+ // If there are more than MAX_STREAM_FILES open, close the oldest.
+ void prune(void);
+ // Removes the pool from the list associated with the stream.
+ // If there is nobody else using this stream, the stream will
+ // be closed too.
+ void stream_released(GP<ByteStream> &stream, GP<DataPool> pool);
+
+ void close_all(void);
+};
+
+DataPool::OpenFiles * DataPool::OpenFiles::global_ptr;
+
+DataPool::OpenFiles_File::OpenFiles_File(const GURL &xurl, GP<DataPool> &pool) : url(xurl)
+{
+ DEBUG_MSG("DataPool::OpenFiles_File::OpenFiles_File(): Opening file '" << url << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ open_time=GOS::ticks();
+ stream=ByteStream::create(url,"rb");
+ add_pool(pool);
+}
+
+DataPool::OpenFiles_File::~OpenFiles_File(void)
+{
+ DEBUG_MSG("DataPool::OpenFiles_File::~OpenFiles_File(): Closing file '" << url << "'\n");
+ DEBUG_MAKE_INDENT(3);
+ clear_stream();
+}
+
+void
+DataPool::OpenFiles_File::clear_stream(void)
+{
+ GCriticalSectionLock lock(&pools_lock);
+ for(GPosition pos=pools_list;pos;++pos)
+ if(pools_list[pos])
+ pools_list[pos]->clear_stream(false);
+ pools_list.empty();
+}
+
+int
+DataPool::OpenFiles_File::add_pool(GP<DataPool> &pool)
+{
+ DEBUG_MSG("DataPool::OpenFiles_File::add_pool: pool=" << (void *) pool << "\n");
+ DEBUG_MAKE_INDENT(3);
+ GCriticalSectionLock lock(&pools_lock);
+ if (!pools_list.contains(pool))
+ pools_list.append(pool);
+ return pools_list.size();
+}
+
+int
+DataPool::OpenFiles_File::del_pool(GP<DataPool> &pool)
+{
+ DEBUG_MSG("DataPool::OpenFiles_File::del_pool: pool=" << (void *) pool << "\n");
+ DEBUG_MAKE_INDENT(3);
+ GCriticalSectionLock lock(&pools_lock);
+ GPosition pos;
+ if (pools_list.search(pool, pos))
+ pools_list.del(pos);
+ return pools_list.size();
+}
+
+inline DataPool::OpenFiles *
+DataPool::OpenFiles::get(void)
+{
+ DEBUG_MSG("DataPool::OpenFiles::get()\n");
+ DEBUG_MAKE_INDENT(3);
+ if (!global_ptr)
+ global_ptr=new OpenFiles();
+ return global_ptr;
+}
+
+void
+DataPool::OpenFiles::prune(void)
+{
+ DEBUG_MSG("DataPool::OpenFiles::prune(void): "<<files_list.size()<< "\n");
+ DEBUG_MAKE_INDENT(3);
+ while(files_list.size()>MAX_OPEN_FILES)
+ {
+ // Too many open files (streams). Get rid of the oldest one.
+ unsigned long oldest_time=GOS::ticks();
+ GPosition oldest_pos=files_list;
+ for(GPosition pos=files_list;pos;++pos)
+ {
+ if (files_list[pos]->open_time<oldest_time)
+ {
+ oldest_time=files_list[pos]->open_time;
+ oldest_pos=pos;
+ }
+ }
+ files_list[oldest_pos]->clear_stream();
+ files_list.del(oldest_pos);
+ }
+}
+
+// GP<ByteStream> & stream,
+// GCriticalSection ** stream_lock)
+GP<DataPool::OpenFiles_File>
+DataPool::OpenFiles::request_stream(const GURL &url, GP<DataPool> pool)
+{
+ DEBUG_MSG("DataPool::OpenFiles::request_stream(): url='" << url << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GP<DataPool::OpenFiles_File> file;
+
+ // Check: maybe the stream has already been open by request of
+ // another DataPool
+ GCriticalSectionLock lock(&files_lock);
+ for(GPosition pos=files_list;pos;++pos)
+ {
+ if (files_list[pos]->url==url)
+ {
+ DEBUG_MSG("found existing stream\n");
+ file=files_list[pos];
+ break;
+ }
+ }
+
+ // No? Open the stream, but check, that there are not
+ // too many streams open
+ if (!file)
+ {
+ file=new DataPool::OpenFiles_File(url, pool);
+ files_list.append(file);
+ prune();
+ }
+
+ file->add_pool(pool);
+ return file;
+}
+
+void
+DataPool::OpenFiles::stream_released(GP<ByteStream> &stream, GP<DataPool> pool)
+{
+ DEBUG_MSG("DataPool::OpenFiles::stream_release: stream="
+ << (void *)stream << " pool=" << (void *)pool << "\n");
+ DEBUG_MAKE_INDENT(3);
+ GCriticalSectionLock lock(&files_lock);
+ for(GPosition pos=files_list;pos;)
+ {
+ GPosition dpos = pos;
+ ++pos;
+ GP<DataPool::OpenFiles_File> f=files_list[dpos];
+ if ((ByteStream *)(f->stream) == (ByteStream *)stream)
+ if (f->del_pool(pool)==0)
+ files_list.del(dpos);
+ }
+}
+
+// This isn't really an accurate url. The files are not really
+// closed. Instead they are dereferenced from the data pool. If
+// a there is another reference to the respective bytestream, it
+// will remain open until dereferenced.
+void
+DataPool::OpenFiles::close_all(void)
+{
+ DEBUG_MSG("DataPool::OpenFiles::close_all\n");
+ DEBUG_MAKE_INDENT(3);
+ GCriticalSectionLock lock(&files_lock);
+ files_list.empty();
+}
+
+//****************************************************************************
+//******************************** FCPools ***********************************
+//****************************************************************************
+
+/** This class is used to maintain a list of DataPools connected to a file.
+ It's important to have this list if we want to do something with this file
+ like to modify it or just erase. Since any modifications of the file
+ will break DataPools directly connected to it, it would be nice to have
+ a mechanism for signaling all the related DataPools to read data into
+ memory. This is precisely the purpose of this class. */
+class FCPools
+{
+private:
+ GMap<GURL, GPList<DataPool> > map; // GMap<GUTF8String, GPList<DataPool>> in fact
+ GCriticalSection map_lock;
+
+ static FCPools * global_ptr;
+public:
+ static FCPools * get(void);
+ // Adds the <furl, pool> pair into the list
+ void add_pool(const GURL &furl, GP<DataPool> pool);
+ // Removes the <furl, pool> pair from the list
+ void del_pool(const GURL &furl, GP<DataPool> pool);
+ // Looks for the list of DataPools connected to 'furl' and makes
+ // each of them load the contents of the file into memory
+ void load_file(const GURL &url);
+ // Retrieve a local URL, if available.
+ GP<DataPool> get_pool(const GURL &url, int start, int length);
+ void clean(void);
+};
+
+void
+FCPools::clean(void)
+{
+ GCriticalSectionLock lock(&map_lock);
+ static int count=0;
+ if(! count++)
+ {
+ bool restart = true;
+ while (restart)
+ {
+ restart = false;
+ for (GPosition posmap = map; posmap; ++posmap)
+ {
+ GPList<DataPool> *lst;
+ lst = & map[posmap];
+ if (lst->isempty())
+ {
+ map.del(posmap);
+ restart = true;
+ break;
+ }
+ for (GPosition poslst = *lst; poslst; ++poslst)
+ if ((*lst)[poslst]->get_count() < 2)
+ {
+ lst->del(poslst);
+ restart = true;
+ break;
+ }
+ if (restart)
+ break;
+ }
+ }
+ }
+ --count;
+}
+
+void
+FCPools::add_pool(const GURL &url, GP<DataPool> pool)
+{
+ DEBUG_MSG("FCPools::add_pool: url='" << url << "' pool=" << (void *)pool << "\n");
+ DEBUG_MAKE_INDENT(3);
+ GCriticalSectionLock lock(&map_lock);
+
+ if (url.is_local_file_url())
+ {
+ GPList<DataPool> list;
+ GPosition pos(map.contains(url));
+ if (! pos)
+ {
+ map[url]=list;
+ pos=map.contains(url);
+ }
+ GPList<DataPool> &plist=map[pos];
+ if (!plist.contains(pool))
+ plist.append(pool);
+ }
+ clean();
+}
+
+GP<DataPool>
+FCPools::get_pool(const GURL &url, int start, int length)
+{
+ DEBUG_MSG("FCPools::get_pool: url='" << url << "\n");
+ DEBUG_MAKE_INDENT(3);
+ GP<DataPool> retval;
+ if (url.is_local_file_url())
+ {
+ GCriticalSectionLock lock(&map_lock);
+ GPosition pos(map.contains(url));
+ if (pos)
+ {
+ GPList<DataPool> &plist=map[pos];
+ for(pos=plist;pos;++pos)
+ {
+ DataPool &pool=*plist[pos];
+ if(start == pool.start && (length < 0 || (length == pool.length)))
+ {
+ retval=plist[pos];
+ break;
+ }
+ }
+ }
+ clean();
+ }
+ return retval;
+}
+
+void
+FCPools::del_pool(const GURL &url, GP<DataPool> pool)
+{
+ DEBUG_MSG("FCPools::del_pool: url='" << url << "' pool=" << (void *)pool << "\n");
+ DEBUG_MAKE_INDENT(3);
+ GCriticalSectionLock lock(&map_lock);
+
+ clean();
+ if (url.is_local_file_url())
+ {
+ GPosition pos;
+ if (map.contains(url, pos))
+ {
+ GPList<DataPool> &list=map[pos];
+ GPosition list_pos;
+ while(list.search(pool, list_pos))
+ list.del(list_pos);
+ if (list.isempty())
+ {
+ map.del(pos);
+ }
+ }
+ }
+}
+
+void
+FCPools::load_file(const GURL &url)
+{
+ DEBUG_MSG("FCPools::load_file: url='" << url << "'\n");
+ DEBUG_MAKE_INDENT(3);
+ GCriticalSectionLock lock(&map_lock);
+
+ clean();
+ if (url.is_local_file_url())
+ {
+ GPosition pos;
+ if (map.contains(url, pos))
+ {
+ // We make here a copy of the list because DataPool::load_file()
+ // will call FCPools::del_pool(), which will modify the list
+ GPList<DataPool> list=map[pos];
+ for(GPosition list_pos=list;list_pos;++list_pos)
+ list[list_pos]->load_file();
+ }
+ }
+}
+
+FCPools * FCPools::global_ptr;
+
+inline FCPools *
+FCPools::get(void)
+{
+ if (!global_ptr)
+ global_ptr=new FCPools();
+ return global_ptr;
+}
+
+//****************************************************************************
+//****************************** BlockList ***********************************
+//****************************************************************************
+
+// Since data can be added to the DataPool at any offset now, there may
+// be white spots, which contain illegal data. This class is to contain
+// the list of valid and invalid regions.
+// The class is basically a list of integers. Abs(integer)=size of the
+// block. If the integer is positive, data for the block is known.
+// Otherwise it's unkown.
+
+class DataPool::BlockList
+{
+ // See comments in .cpp file.
+private:
+ GCriticalSection lock;
+ GList<int> list;
+public:
+ BlockList() {};
+ void clear(void);
+ void add_range(int start, int length);
+ int get_bytes(int start, int length) const;
+ int get_range(int start, int length) const;
+friend class DataPool;
+};
+
+void
+DataPool::BlockList::clear(void)
+{
+ DEBUG_MSG("DataPool::BlockList::clear()\n");
+ DEBUG_MAKE_INDENT(3);
+ GCriticalSectionLock lk(&lock);
+ list.empty();
+}
+
+void
+DataPool::BlockList::add_range(int start, int length)
+ // Adds range of known data.
+{
+ DEBUG_MSG("DataPool::BlockList::add_range: start=" << start << " length=" << length << "\n");
+ DEBUG_MAKE_INDENT(3);
+ if (start<0)
+ G_THROW( ERR_MSG("DataPool.neg_start") );
+ if (length<=0)
+ G_THROW( ERR_MSG("DataPool.bad_length") );
+ if (length>0)
+ {
+ GCriticalSectionLock lk(&lock);
+
+ // Look thru existing zones, change their sign and split if
+ // necessary.
+ GPosition pos=list;
+ int block_start=0, block_end=0;
+ while(pos && block_start<start+length)
+ {
+ int size=list[pos];
+ block_end=block_start+abs(size);
+ if (size<0)
+ if (block_start<start)
+ {
+ if (block_end>start && block_end<=start+length)
+ {
+ list[pos]=-(start-block_start);
+ list.insert_after(pos, block_end-start);
+ ++pos;
+ block_start=start;
+ } else if (block_end>start+length)
+ {
+ list[pos]=-(start-block_start);
+ list.insert_after(pos, length);
+ ++pos;
+ list.insert_after(pos, -(block_end-(start+length)));
+ ++pos;
+ block_start=start+length;
+ }
+ } else if (block_start>=start && block_start<start+length)
+ {
+ if (block_end<=start+length) list[pos]=abs(size);
+ else
+ {
+ list[pos]=start+length-block_start;
+ list.insert_after(pos, -(block_end-(start+length)));
+ ++pos;
+ block_start=start+length;
+ }
+ }
+ block_start=block_end;
+ ++pos;
+ }
+ if (block_end<start)
+ {
+ list.append(-(start-block_end));
+ list.append(length);
+ } else if (block_end<start+length) list.append(start+length-block_end);
+
+ // Now merge adjacent areas with the same sign
+ pos=list;
+ while(pos)
+ {
+ GPosition pos1=pos; ++pos1;
+ while(pos1)
+ {
+ if (list[pos]<0 && list[pos1]>0 ||
+ list[pos]>0 && list[pos1]<0)
+ break;
+ list[pos]+=list[pos1];
+ GPosition this_pos=pos1;
+ ++pos1;
+ list.del(this_pos);
+ }
+ pos=pos1;
+ }
+ } // if (length>0)
+}
+
+int
+DataPool::BlockList::get_bytes(int start, int length) const
+ // Returns the number of bytes of data available in the range
+ // [start, start+length[. There may be holes between data chunks
+{
+ DEBUG_MSG("DataPool::BlockList::get_bytes: start=" << start << " length=" << length << "\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (length<0)
+ G_THROW( ERR_MSG("DataPool.bad_length") );
+
+ GCriticalSectionLock lk((GCriticalSection *) &lock);
+ int bytes=0;
+ int block_start=0, block_end=0;
+ for(GPosition pos=list;pos && block_start<start+length;++pos)
+ {
+ int size=list[pos];
+ block_end=block_start+abs(size);
+ if (size>0)
+ if (block_start<start)
+ {
+ if (block_end>=start && block_end<start+length)
+ bytes+=block_end-start;
+ else if (block_end>=start+length)
+ bytes+=length;
+ } else
+ {
+ if (block_end<=start+length)
+ bytes+=block_end-block_start;
+ else bytes+=start+length-block_start;
+ }
+ block_start=block_end;
+ }
+ return bytes;
+}
+
+int
+DataPool::BlockList::get_range(int start, int length) const
+ // Finds a range covering offset=start and returns the length
+ // of intersection of this range with [start, start+length[
+ // 0 is returned if nothing can be found
+{
+ DEBUG_MSG("DataPool::BlockList::get_range: start=" << start << " length=" << length << "\n");
+ DEBUG_MAKE_INDENT(3);
+ if (start<0)
+ G_THROW( ERR_MSG("DataPool.neg_start") );
+ if (length<=0)
+ G_THROW( ERR_MSG("DataPool.bad_length") );
+
+ GCriticalSectionLock lk((GCriticalSection *) &lock);
+ int block_start=0, block_end=0;
+ for(GPosition pos=list;pos && block_start<start+length;++pos)
+ {
+ int size=list[pos];
+ block_end=block_start+abs(size);
+ if (block_start<=start && block_end>start)
+ if (size<0) return -1;
+ else
+ if (block_end>start+length) return length;
+ else return block_end-start;
+ block_start=block_end;
+ }
+ return 0;
+}
+
+//****************************************************************************
+//******************************* DataPool ***********************************
+//****************************************************************************
+
+class DataPool::Reader : public GPEnabled
+{
+public:
+ GEvent event;
+ bool reenter_flag;
+ int offset;
+ int size;
+ Reader() : reenter_flag(false), offset(0), size(-1){};
+ Reader(int offset_in, int size_in=-1) :
+ reenter_flag(false), offset(offset_in), size(size_in) {};
+ virtual ~Reader() {};
+};
+
+class DataPool::Trigger : public GPEnabled
+{
+public:
+ GSafeFlags disabled;
+ int start, length;
+// void (* callback)(GP<GPEnabled> &);
+ void (* callback)(void *);
+// GP<GPEnabled> cl_data;
+ void *cl_data;
+
+ Trigger() : start(0), length(-1), callback(0), cl_data(0) {};
+ Trigger(int xstart, int xlength,
+// void (* xcallback)(GP<GPEnabled> &), GP<GPEnabled> xcl_data) :
+ void (* xcallback)(void *), void *xcl_data) :
+ start(xstart), length(xlength), callback(xcallback), cl_data(xcl_data) {};
+ virtual ~Trigger() {};
+};
+
+class DataPool::Counter
+{
+private:
+ int counter;
+ GCriticalSection lock;
+public:
+ Counter() : counter(0) {};
+ operator int(void) const;
+ void inc(void);
+ void dec(void);
+};
+
+#define DATAPOOL_INIT eof_flag(false),stop_flag(false), \
+ stop_blocked_flag(false), \
+ add_at(0),start(0),length(-1)
+
+void
+DataPool::init(void)
+{
+ DEBUG_MSG("DataPool::init(): Initializing\n");
+ DEBUG_MAKE_INDENT(3);
+ start=0; length=-1; add_at=0;
+ eof_flag=false;
+ stop_flag=false;
+ stop_blocked_flag=false;
+
+ active_readers=new Counter;
+ block_list=0;
+ G_TRY
+ {
+ block_list=new BlockList;
+ data=ByteStream::create();
+ }
+ G_CATCH_ALL
+ {
+ delete block_list;
+ block_list=0;
+ delete active_readers;
+ active_readers=0;
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+}
+
+DataPool::DataPool(void) : DATAPOOL_INIT {}
+
+GP<DataPool>
+DataPool::create(void)
+{
+ DEBUG_MSG("DataPool::DataPool()\n");
+ DEBUG_MAKE_INDENT(3);
+ DataPool *pool=new DataPool();
+
+ GP<DataPool> retval=pool;
+ pool->init();
+
+ // If we maintain the data ourselves, we want to interpret its
+ // IFF structure to predict its length
+ pool->add_trigger(0, 32, static_trigger_cb, pool);
+ return retval;
+}
+
+GP<DataPool>
+DataPool::create(const GP<ByteStream> &gstr)
+{
+ DEBUG_MSG("DataPool::create: str="<<(ByteStream *)gstr<<"\n");
+ DEBUG_MAKE_INDENT(3);
+ DataPool *pool=new DataPool();
+ GP<DataPool> retval=pool;
+ pool->init();
+
+ // It's nice to have IFF data analyzed in this case too.
+ pool->add_trigger(0, 32, static_trigger_cb, pool);
+
+ pool->data=gstr->duplicate();
+ pool->added_data(0,pool->data->size());
+// char buffer[1024];
+// int length;
+// while((length=str.read(buffer, 1024)))
+// pool->add_data(buffer, length);
+ pool->set_eof();
+ return retval;
+}
+
+GP<DataPool>
+DataPool::create(const GP<DataPool> & pool, int start, int length)
+{
+ DEBUG_MSG("DataPool::DataPool: pool=" << (void *)((DataPool *)pool) << " start=" << start << " length= " << length << "\n");
+ DEBUG_MAKE_INDENT(3);
+
+ DataPool *xpool=new DataPool();
+ GP<DataPool> retval=xpool;
+ xpool->init();
+ xpool->connect(pool, start, length);
+ return retval;
+}
+
+GP<DataPool>
+DataPool::create(const GURL &furl, int start, int length)
+{
+ DEBUG_MSG("DataPool::DataPool: furl='" << furl << "' start=" << start << " length= " << length << "\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GP<DataPool> retval=FCPools::get()->get_pool(furl,start,length);
+ if(! retval)
+ {
+ DataPool *pool=new DataPool();
+ retval=pool;
+ pool->init();
+ pool->connect(furl, start, length);
+ }
+ return retval;
+}
+
+void
+DataPool::clear_stream(const bool release)
+{
+ DEBUG_MSG("DataPool::clear_stream()\n");
+ DEBUG_MAKE_INDENT(3);
+ if(fstream)
+ {
+ GCriticalSectionLock lock1(&class_stream_lock);
+ GP<OpenFiles_File> f=fstream;
+ if(f)
+ {
+ GCriticalSectionLock lock2(&(f->stream_lock));
+ fstream=0;
+ if(release)
+ OpenFiles::get()->stream_released(f->stream, this);
+ }
+ }
+}
+
+DataPool::~DataPool(void)
+{
+ DEBUG_MSG("DataPool::~DataPool()\n");
+ DEBUG_MAKE_INDENT(3);
+
+ clear_stream(true);
+ if (furl.is_local_file_url())
+ {
+ FCPools::get()->del_pool(furl, this);
+ }
+
+ {
+ // Wait until the static_trigger_cb() exits
+ GCriticalSectionLock lock(&trigger_lock);
+ if (pool)
+ pool->del_trigger(static_trigger_cb, this);
+ del_trigger(static_trigger_cb, this);
+ }
+
+ if (pool)
+ {
+ GCriticalSectionLock lock(&triggers_lock);
+ for(GPosition pos=triggers_list;pos;++pos)
+ {
+ GP<Trigger> trigger=triggers_list[pos];
+ pool->del_trigger(trigger->callback, trigger->cl_data);
+ }
+ }
+ delete block_list;
+ delete active_readers;
+}
+
+void
+DataPool::connect(const GP<DataPool> & pool_in, int start_in, int length_in)
+{
+ DEBUG_MSG("DataPool::connect(): connecting to another DataPool\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (pool) G_THROW( ERR_MSG("DataPool.connected1") );
+ if (furl.is_local_file_url()) G_THROW( ERR_MSG("DataPool.connected2") );
+ if (start_in<0) G_THROW( ERR_MSG("DataPool.neg_start") );
+
+ pool=pool_in;
+ start=start_in;
+ length=length_in;
+
+ // The following will work for length<0 too
+ if (pool->has_data(start, length))
+ eof_flag=true;
+ else
+ pool->add_trigger(start, length, static_trigger_cb, this);
+
+ data=0;
+
+ wake_up_all_readers();
+
+ // Pass registered trigger callbacks to the DataPool
+ GCriticalSectionLock lock(&triggers_lock);
+ for(GPosition pos=triggers_list;pos;++pos)
+ {
+ GP<Trigger> t=triggers_list[pos];
+ int tlength=t->length;
+ if (tlength<0 && length>0)
+ tlength=length-t->start;
+ pool->add_trigger(start+t->start, tlength, t->callback, t->cl_data);
+ }
+}
+
+void
+DataPool::connect(const GURL &furl_in, int start_in, int length_in)
+{
+ DEBUG_MSG("DataPool::connect(): connecting to a file\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (pool)
+ G_THROW( ERR_MSG("DataPool.connected1") );
+ if (furl.is_local_file_url())
+ G_THROW( ERR_MSG("DataPool.connected2") );
+ if (start_in<0)
+ G_THROW( ERR_MSG("DataPool.neg_start") );
+
+
+ if (furl_in.name() == "-")
+ {
+ DEBUG_MSG("This is stdin => just read the data...\n");
+ DEBUG_MAKE_INDENT(3);
+ char buffer[1024];
+ int length;
+ GP<ByteStream> gstr=ByteStream::create(furl_in, "rb");
+ ByteStream &str=*gstr;
+ while((length=str.read(buffer, 1024)))
+ add_data(buffer, length);
+ set_eof();
+ } else if(furl_in.is_local_file_url())
+ {
+ // Open the stream (just in this function) too see if
+ // the file is accessible. In future we will be using 'OpenFiles'
+ // to request and release streams
+ GP<ByteStream> str=ByteStream::create(furl_in,"rb");
+ str->seek(0, SEEK_END);
+ int file_size=str->tell();
+
+ furl=furl_in;
+ start=start_in;
+ length=length_in;
+ if (start>=file_size)
+ length=0;
+ else if (length<0 || start+length>=file_size)
+ length=file_size-start;
+
+ eof_flag=true;
+
+ if(str->is_static())
+ {
+ data=str;
+ added_data(0,length);
+ }else
+ {
+ data=0;
+ }
+
+ FCPools::get()->add_pool(furl, this);
+
+ wake_up_all_readers();
+
+ // Call every trigger callback
+ GCriticalSectionLock lock(&triggers_lock);
+ for(GPosition pos=triggers_list;pos;++pos)
+ {
+ GP<Trigger> t=triggers_list[pos];
+ call_callback(t->callback, t->cl_data);
+ }
+ triggers_list.empty();
+ }
+}
+
+int
+DataPool::get_length(void) const
+{
+ // Not connected and length has been guessed
+ // Or connected to a file
+ // Or connected to a pool, but length was preset
+ int retval=(-1);
+ if (length>=0)
+ {
+ retval=length;
+ }else if (pool)
+ {
+ int plength=pool->get_length();
+ if (plength>=0)
+ retval=plength-start;
+ }
+ return retval;
+}
+
+int
+DataPool::get_size(int dstart, int dlength) const
+{
+ if (dlength<0 && length>0)
+ {
+ dlength=length-dstart;
+ if (dlength<0) return 0;
+ }
+
+ if (pool) return pool->get_size(start+dstart, dlength);
+ else if (furl.is_local_file_url())
+ {
+ if (start+dstart+dlength>length) return length-(start+dstart);
+ else return dlength;
+ } else
+ {
+ if (dlength<0)
+ {
+ GCriticalSectionLock lock((GCriticalSection *) &data_lock);
+ dlength=data->size()-dstart;
+ }
+ return (dlength<0)?0:(block_list->get_bytes(dstart, dlength));
+ }
+}
+
+void
+DataPool::add_data(const void * buffer, int size)
+ // This function adds data sequentially at 'add_at' position
+{
+ DEBUG_MSG("DataPool::add_data(): adding " << size << " bytes of data...\n");
+ DEBUG_MAKE_INDENT(3);
+
+ add_data(buffer, add_at, size);
+ add_at+=size;
+}
+
+void
+DataPool::add_data(const void * buffer, int offset, int size)
+{
+ DEBUG_MSG("DataPool::add_data(): adding " << size << " bytes at pos=" <<
+ offset << "...\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (furl.is_local_file_url() || pool)
+ G_THROW( ERR_MSG("DataPool.add_data") );
+
+ // Add data to the data storage
+ {
+ GCriticalSectionLock lock(&data_lock);
+ if (offset>data->size())
+ {
+ char ch=0;
+ data->seek(0, SEEK_END);
+ for(int i=data->size();i<offset;i++)
+ data->write(&ch, 1);
+ } else
+ {
+ data->seek(offset, SEEK_SET);
+ data->writall(buffer, size);
+ }
+ }
+
+ added_data(offset, size);
+}
+
+void
+DataPool::added_data(const int offset, const int size)
+{
+ // Modify map of blocks
+ block_list->add_range(offset, size);
+
+ // Wake up all threads, which may be waiting for this data
+ {
+ GCriticalSectionLock lock(&readers_lock);
+ for(GPosition pos=readers_list;pos;++pos)
+ {
+ GP<Reader> reader=readers_list[pos];
+ if (block_list->get_bytes(reader->offset, 1))
+ {
+ DEBUG_MSG("waking up reader: offset=" << reader->offset <<
+ ", size=" << reader->size << "\n");
+ DEBUG_MAKE_INDENT(3);
+ reader->event.set();
+ }
+ }
+ }
+
+ // And call triggers
+ check_triggers();
+
+ // Do not undo the following two lines. The reason why we need them
+ // here is the connected DataPools, which use 'length' (more exactly
+ // has_data()) to see if they have all data required. So, right after
+ // all data has been added to the master DataPool, but before EOF
+ // is set, the master and slave DataPools disagree regarding if
+ // all data is there or not. These two lines solve the problem
+ GCriticalSectionLock lock(&data_lock);
+ if (length>=0 && data->size()>=length)
+ set_eof();
+}
+
+bool
+DataPool::has_data(int dstart, int dlength)
+{
+ if (dlength<0 && length>0)
+ dlength=length-dstart;
+ return (pool?(pool->has_data(start+dstart, dlength))
+ :((furl.is_local_file_url())?(start+dstart+dlength<=length)
+ :((dlength<0)?is_eof()
+ :(block_list->get_bytes(dstart, dlength)==dlength))));
+}
+
+int
+DataPool::get_data(void * buffer, int offset, int sz)
+{
+ return get_data(buffer, offset, sz, 0);
+}
+
+class DataPool::Incrementor
+{
+private:
+ Counter & counter;
+public:
+ Incrementor(Counter & xcounter) : counter(xcounter) {counter.inc();}
+ ~Incrementor() {counter.dec();}
+};
+
+int
+DataPool::get_data(void * buffer, int offset, int sz, int level)
+{
+ DEBUG_MSG("DataPool::get_data()\n");
+ DEBUG_MAKE_INDENT(3);
+ Incrementor inc(*active_readers);
+
+ if (stop_flag)
+ G_THROW( DataPool::Stop );
+ if (stop_blocked_flag && !is_eof() &&
+ !has_data(offset, sz))
+ G_THROW( DataPool::Stop );
+
+ if (sz < 0)
+ G_THROW( ERR_MSG("DataPool.bad_size") );
+
+ if (! sz)
+ return 0;
+
+ if (pool)
+ {
+ DEBUG_MSG("DataPool::get_data(): from pool\n");
+ DEBUG_MAKE_INDENT(3);
+ int retval=0;
+ if (length>0 && offset+sz>length)
+ sz=length-offset;
+ if (sz<0)
+ sz=0;
+ for(;;)
+ {
+ // Ask the underlying (master) DataPool for data. Note, that
+ // master DataPool may throw the "DATA_POOL_REENTER" exception
+ // demanding all readers to restart. This happens when
+ // a DataPool in the chain of DataPools stops. All readers
+ // should return to the most upper level and then reenter the
+ // DataPools hierarchy. Some of them will be stopped by
+ // DataPool::Stop exception.
+ G_TRY
+ {
+ if(stop_flag||stop_blocked_flag&&!is_eof()&&!has_data(offset, sz))
+ G_THROW( DataPool::Stop );
+ retval=pool->get_data(buffer, start+offset, sz, level+1);
+ }
+ G_CATCH(exc)
+ {
+ pool->clear_stream(true);
+ if ((exc.get_cause() != GUTF8String( ERR_MSG("DataPool.reenter") ) ) || level)
+ G_RETHROW;
+ } G_ENDCATCH;
+ pool->clear_stream(true);
+ return retval;
+ }
+ }
+ else if(data && data->is_static() && eof_flag)
+ {
+ DEBUG_MSG("DataPool::get_data(): static\n");
+ DEBUG_MAKE_INDENT(3);
+ // We're not connected to anybody => handle the data
+ int size=block_list->get_range(offset, sz);
+ if (size>0)
+ {
+ // Hooray! Some data is there
+ GCriticalSectionLock lock(&data_lock);
+ data->seek(offset, SEEK_SET);
+ return data->readall(buffer, size);
+ }
+ return 0;
+ }
+ else if (furl.is_local_file_url())
+ {
+ DEBUG_MSG("DataPool::get_data(): from file\n");
+ DEBUG_MAKE_INDENT(3);
+ if (length>0 && offset+sz>length)
+ sz=length-offset;
+ if (sz<0)
+ sz=0;
+
+ GP<OpenFiles_File> f=fstream;
+ if (!f)
+ {
+ GCriticalSectionLock lock(&class_stream_lock);
+ f=fstream;
+ if(!f)
+ {
+ fstream=f=OpenFiles::get()->request_stream(furl, this);
+ }
+ }
+ GCriticalSectionLock lock2(&(f->stream_lock));
+ f->stream->seek(start+offset, SEEK_SET);
+ return f->stream->readall(buffer, sz);
+ }
+ else
+ {
+ DEBUG_MSG("DataPool::get_data(): direct\n");
+ DEBUG_MAKE_INDENT(3);
+ // We're not connected to anybody => handle the data
+ int size=block_list->get_range(offset, sz);
+ if (size>0)
+ {
+ // Hooray! Some data is there
+ GCriticalSectionLock lock(&data_lock);
+ data->seek(offset, SEEK_SET);
+ return data->readall(buffer, size);
+ }
+
+ // No data available.
+
+ // If there is no data and nothing else is expected, we can do
+ // two things: throw ByteStream::EndOfFile exception or return ZERO bytes.
+ // The exception is for the cases when the data flow has been
+ // terminated in the middle. ZERO bytes is for regular read() beyond
+ // the boundaries of legal data. The problem is to distinguish
+ // these two cases. We do it here with the help of analysis of the
+ // IFF structure of the data (which sets the 'length' variable).
+ // If we attempt to read beyond the [0, length[, ZERO bytes will be
+ // returned. Otherwise an ByteStream::EndOfFile exception will be thrown.
+ if (eof_flag)
+ {
+ if (length>0 && offset<length)
+ {
+ G_THROW( ByteStream::EndOfFile );
+ }
+ else
+ {
+ return 0;
+ }
+ }
+ // Some data is still expected => add this reader to the
+ // list of readers and call virtual wait_for_data()
+ DEBUG_MSG("DataPool::get_data(): There is no data in the pool.\n");
+ DEBUG_MSG("offset=" << offset << ", size=" << sz <<
+ ", data_size=" << data->size() << "\n");
+ GP<Reader> reader=new Reader(offset, sz);
+ G_TRY
+ {
+ {
+ GCriticalSectionLock slock(&readers_lock);
+ readers_list.append(reader);
+ }
+ wait_for_data(reader);
+ }
+ G_CATCH_ALL
+ {
+ {
+ GCriticalSectionLock slock(&readers_lock);
+ GPosition pos;
+ if (readers_list.search(reader, pos)) readers_list.del(pos);
+ }
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+
+ {
+ GCriticalSectionLock slock(&readers_lock);
+ GPosition pos;
+ if (readers_list.search(reader, pos)) readers_list.del(pos);
+ }
+
+ // This call to get_data() should return immediately as there MUST
+ // be data in the buffer after wait_for_data(reader) returns
+ // or eof_flag should be TRUE
+ return get_data(buffer, reader->offset, reader->size, level);
+ }
+ return 0;
+}
+
+void
+DataPool::wait_for_data(const GP<Reader> & reader)
+ // This function may NOT return until there is some data for the
+ // given reader in the internal buffer
+{
+ DEBUG_MSG("DataPool::wait_for_data(): waiting for data at offset=" << reader->offset <<
+ ", length=" << reader->size << "\n");
+ DEBUG_MAKE_INDENT(3);
+
+#if THREADMODEL==NOTHREADS
+ G_THROW( ERR_MSG("DataPool.no_threadless") );
+#else
+ for(;;)
+ {
+ if (stop_flag)
+ G_THROW( DataPool::Stop );
+ if (reader->reenter_flag)
+ G_THROW( ERR_MSG("DataPool.reenter") );
+ if (eof_flag || block_list->get_bytes(reader->offset, 1))
+ return;
+ if (pool || furl.is_local_file_url())
+ return;
+
+ if (stop_blocked_flag)
+ G_THROW( DataPool::Stop );
+
+ DEBUG_MSG("calling event.wait()...\n");
+ reader->event.wait();
+ }
+#endif
+
+ DEBUG_MSG("Got some data to read\n");
+}
+
+void
+DataPool::wake_up_all_readers(void)
+{
+ DEBUG_MSG("DataPool::wake_up_all_readers(): waking up all readers\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GCriticalSectionLock lock(&readers_lock);
+ for(GPosition pos=readers_list;pos;++pos)
+ readers_list[pos]->event.set();
+}
+
+void
+DataPool::set_eof(void)
+ // Has no effect on connected DataPools
+{
+ if (!furl.is_local_file_url() && !pool)
+ {
+ eof_flag=true;
+
+ // Can we set the length now?
+ if (length<0)
+ {
+ GCriticalSectionLock lock(&data_lock);
+ length=data->size();
+ }
+
+ // Wake up all readers to let them rescan the flags
+ wake_up_all_readers();
+
+ // Activate all trigger callbacks with negative threshold
+ check_triggers();
+ }
+}
+
+void
+DataPool::stop(bool only_blocked)
+{
+ DEBUG_MSG("DataPool::stop(): Stopping this and dependent DataPools, only_blocked="
+ << only_blocked << "\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (only_blocked) stop_blocked_flag=true;
+ else stop_flag=true;
+
+
+ wake_up_all_readers();
+
+ // Now let all readers, which already go thru to the master DataPool,
+ // come back and reenter. While reentering some of them will go
+ // thru this DataPool again and will be stopped (DataPool::Stop exception)
+ // Others (which entered the master DataPool thru other slave DataPools)
+ // will simply continue waiting for their data.
+ if (pool)
+ {
+ // This loop is necessary because there may be another thread, which
+ // is going down thru the DataPool chain and did not reach the
+ // lowest "master" DataPool yet. Since it didn't reach it yet,
+ // the "pool->restart_readers()" will not restart it. So we're going
+ // to continue issuing this command until we get rid of all
+ // "active_readers"
+ while(*active_readers)
+ {
+#if (THREADMODEL==COTHREADS) || (THREADMODEL==MACTHREADS)
+ GThread::yield();
+#endif
+ pool->restart_readers();
+ }
+ }
+}
+
+void
+DataPool::restart_readers(void)
+{
+ DEBUG_MSG("DataPool::restart_readers(): telling all readers to reenter\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GCriticalSectionLock slock(&readers_lock);
+ for(GPosition pos=readers_list;pos;++pos)
+ {
+ GP<Reader> reader=readers_list[pos];
+ reader->reenter_flag=true;
+ reader->event.set();
+ }
+
+ if (pool)
+ pool->restart_readers();
+}
+
+void
+DataPool::load_file(void)
+{
+ DEBUG_MSG("DataPool::load_file() called\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (pool)
+ {
+ DEBUG_MSG("passing the request down.\n");
+ pool->load_file();
+ } else if (furl.is_local_file_url())
+ {
+ DEBUG_MSG("loading the data from \""<<(const char *)furl<<"\".\n");
+
+ GCriticalSectionLock lock1(&class_stream_lock);
+ GP<OpenFiles_File> f=fstream;
+ if (!f)
+ {
+ fstream=f=OpenFiles::get()->request_stream(furl, this);
+ }
+ { // Scope to de-allocate lock2 before stream gets released
+ GCriticalSectionLock lock2(&(f->stream_lock));
+
+ data=ByteStream::create();
+ block_list->clear();
+ FCPools::get()->del_pool(furl, this);
+ furl=GURL();
+
+ const GP<ByteStream> gbs=f->stream;
+ gbs->seek(0, SEEK_SET);
+ data=gbs->duplicate();
+ added_data(0,data->size());
+ set_eof();
+// char buffer[1024];
+// int length;
+// while((length=f->stream->read(buffer, 1024)))
+// add_data(buffer, length);
+ // No need to set EOF. It should already be set.
+ OpenFiles::get()->stream_released(f->stream, this);
+ }
+ fstream=0;
+ } else { DEBUG_MSG("Not connected\n"); }
+}
+
+void
+DataPool::load_file(const GURL &url )
+{
+ FCPools::get()->load_file(url);
+}
+
+void
+DataPool::check_triggers(void)
+ // This function is for not connected DataPools only
+{
+ DEBUG_MSG("DataPool::check_triggers(): calling activated trigger callbacks.\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (!pool && !furl.is_local_file_url())
+ while(true)
+ {
+ GP<Trigger> trigger;
+
+ // First find a candidate (trigger, which needs to be called)
+ // Don't remove it from the list yet. del_trigger() should
+ // be able to find it if necessary and disable.
+ {
+ GCriticalSectionLock list_lock(&triggers_lock);
+ for(GPosition pos=triggers_list;pos;++pos)
+ {
+ GP<Trigger> t=triggers_list[pos];
+ if (is_eof() || t->length>=0 &&
+ block_list->get_bytes(t->start, t->length)==t->length)
+ {
+ trigger=t;
+ break;
+ }
+ }
+ }
+
+ if (trigger)
+ {
+ // Now check that the trigger is not disabled
+ // and lock the trigger->disabled lock for the duration
+ // of the trigger. This will block the del_trigger() and
+ // will postpone client's destruction (usually following
+ // the call to del_trigger())
+ {
+ GMonitorLock lock(&trigger->disabled);
+ if (!trigger->disabled)
+ call_callback(trigger->callback, trigger->cl_data);
+ }
+
+ // Finally - remove the trigger from the list.
+ GCriticalSectionLock list_lock(&triggers_lock);
+ for(GPosition pos=triggers_list;pos;++pos)
+ if (triggers_list[pos]==trigger)
+ {
+ triggers_list.del(pos);
+ break;
+ }
+ } else break;
+ }
+}
+
+void
+// DataPool::add_trigger(int thresh, void (* callback)(GP<GPEnabled> &), GP<GPEnabled> cl_data)
+DataPool::add_trigger(int thresh, void (* callback)(void *), void * cl_data)
+{
+ if (thresh>=0)
+ add_trigger(0, thresh+1, callback, cl_data);
+ else
+ add_trigger(0, -1, callback, cl_data);
+}
+
+void
+DataPool::add_trigger(int tstart, int tlength,
+// void (* callback)(GP<GPEnabled> &), GP<GPEnabled> cl_data)
+ void (* callback)(void *), void * cl_data)
+{
+ DEBUG_MSG("DataPool::add_trigger(): start=" << tstart <<
+ ", length=" << tlength << ", func=" << (void *) callback << "\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (callback)
+ {
+ if (is_eof())
+ {
+ call_callback(callback, cl_data);
+ }else
+ {
+ if (pool)
+ {
+ // We're connected to a DataPool
+ // Just pass the triggers down remembering it in the list
+ if (tlength<0 && length>0) tlength=length-tstart;
+ GP<Trigger> trigger=new Trigger(tstart, tlength, callback, cl_data);
+ pool->add_trigger(start+tstart, tlength, callback, cl_data);
+ GCriticalSectionLock lock(&triggers_lock);
+ triggers_list.append(trigger);
+ } else if (!furl.is_local_file_url())
+ {
+ // We're not connected to anything and maintain our own data
+ if (tlength>=0 && block_list->get_bytes(tstart, tlength)==tlength)
+ call_callback(callback, cl_data);
+ else
+ {
+ GCriticalSectionLock lock(&triggers_lock);
+ triggers_list.append(new Trigger(tstart, tlength, callback, cl_data));
+ }
+ }
+ }
+ }
+}
+
+void
+// DataPool::del_trigger(void (* callback)(GP<GPEnabled> &), GP<GPEnabled> cl_data)
+DataPool::del_trigger(void (* callback)(void *), void * cl_data)
+{
+ DEBUG_MSG("DataPool::del_trigger(): func=" << (void *) callback << "\n");
+ DEBUG_MAKE_INDENT(3);
+
+ for(;;)
+ {
+ GP<Trigger> trigger;
+ {
+ GCriticalSectionLock lock(&triggers_lock);
+ for(GPosition pos=triggers_list;pos;)
+ {
+ GP<Trigger> t=triggers_list[pos];
+ if (t->callback==callback && t->cl_data==cl_data)
+ {
+ trigger=t;
+ GPosition this_pos=pos;
+ ++pos;
+ triggers_list.del(this_pos);
+ break;
+ } else
+ ++pos;
+ }
+ }
+
+ // Above we removed the trigger from the list and unlocked the list
+ // Now we will disable it and will wait if necessary (if the
+ // trigger is currently being processed by check_triggers())
+ // check_triggers() locks the trigger for the duration of the
+ // trigger callback. Thus we will wait for the trigger callback
+ // to finish and avoid client's destruction.
+ if (trigger)
+ trigger->disabled=1;
+ else
+ break;
+ }
+
+ if (pool)
+ pool->del_trigger(callback, cl_data);
+}
+
+void
+// DataPool::static_trigger_cb(GP<GPEnabled> &cl_data)
+DataPool::static_trigger_cb(void *cl_data)
+{
+// GP<DataPool> d=(DataPool *)(GPEnabled *)cl_data;
+ GP<DataPool> d=(DataPool *)cl_data;
+ d->trigger_cb();
+}
+
+void
+DataPool::trigger_cb(void)
+ // This function may be triggered by the DataPool, which we're
+ // connected to, or by ourselves, if we're connected to nothing
+{
+ // Don't want to be destroyed while I'm here. Can't use GP<> life saver
+ // because it may be called from the constructor
+ GCriticalSectionLock lock(&trigger_lock);
+
+ DEBUG_MSG("DataPool::trigger_cb() called\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (pool)
+ {
+ // Connected to a pool
+ // We may be here when either EOF is set on the master DataPool
+ // Or when it may have learnt its length (from IFF or whatever)
+ if (pool->is_eof() || pool->has_data(start, length)) eof_flag=true;
+ } else if (!furl.is_local_file_url())
+ {
+ // Not connected to anything => Try to guess the length
+ if (length<0) analyze_iff();
+
+ // Failed to analyze? Check, maybe it's EOF already
+ if (length<0 && is_eof())
+ {
+ GCriticalSectionLock lock(&data_lock);
+ length=data->size();
+ }
+ }
+}
+
+void
+DataPool::analyze_iff(void)
+ // In order to display decode progress properly, we need to know
+ // the size of the data. It's trivial to figure it out if is_eof()
+ // is true. Otherwise we need to make a prediction. Luckily all
+ // DjVuFiles have IFF structure, which makes it possible to do it.
+ // If due to some reason we fail, the length will remain -1.
+{
+ DEBUG_MSG("DataPool::analyze_iff(): Trying to decode IFF structure of " << furl << ".\n");
+ DEBUG_MSG("in order to predict the DataPool's size\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GP<ByteStream> str=get_stream();
+
+ GP<IFFByteStream> giff=IFFByteStream::create(str);
+ IFFByteStream &iff=*giff;
+ GUTF8String chkid;
+ int size;
+ if ((size=iff.get_chunk(chkid)) && size>=0)
+ {
+ length=size+iff.tell()-4;
+ DEBUG_MSG("Got size=" << size << ", length=" << length << "\n");
+ }
+}
+
+
+//****************************************************************************
+//****************************** PoolByteStream ******************************
+//****************************************************************************
+
+// This is an internal ByteStream receiving data from the associated DataPool.
+// It's just a sequential interface, nothing more. All the job for data
+// retrieval, waiting and thread synchronization is done by DataPool
+
+class PoolByteStream : public ByteStream
+{
+public:
+ PoolByteStream(GP<DataPool> data_pool);
+ virtual ~PoolByteStream() {};
+
+ virtual size_t read(void *buffer, size_t size);
+ virtual size_t write(const void *buffer, size_t size);
+ virtual long tell(void) const ;
+ virtual int seek(long offset, int whence = SEEK_SET, bool nothrow=false);
+private:
+ // Don't make data_pool GP<>. The problem is that DataPool creates
+ // and soon destroys this ByteStream from the constructor. Since
+ // there are no other pointers to the DataPool created yet, it becomes
+ // destroyed immediately :(
+ DataPool * data_pool;
+ GP<DataPool> data_pool_lock;
+ long position;
+
+ char buffer[512];
+ size_t buffer_size;
+ size_t buffer_pos;
+
+ // Cancel C++ default stuff
+ PoolByteStream & operator=(const PoolByteStream &);
+};
+
+inline
+PoolByteStream::PoolByteStream(GP<DataPool> xdata_pool) :
+ data_pool(xdata_pool), position(0), buffer_size(0), buffer_pos(0)
+{
+ if (!data_pool)
+ G_THROW( ERR_MSG("DataPool.zero_DataPool") );
+
+ // Secure the DataPool if possible. If we're called from DataPool
+ // constructor (get_count()==0) there is no need to secure at all.
+ if (data_pool->get_count()) data_pool_lock=data_pool;
+}
+
+size_t
+PoolByteStream::read(void *data, size_t size)
+{
+ if (buffer_pos >= buffer_size) {
+ if (size >= sizeof(buffer)) {
+ // Direct read
+ size = data_pool->get_data(data, position, size);
+ position += size;
+ return size;
+ } else {
+ // Refill buffer
+ buffer_size = data_pool->get_data(buffer, position, sizeof(buffer));
+ buffer_pos=0;
+ }
+ }
+ if (buffer_pos + size >= buffer_size)
+ size = buffer_size - buffer_pos;
+ memcpy(data, buffer+buffer_pos, size);
+ buffer_pos += size;
+ position += size;
+ return size;
+}
+
+size_t
+PoolByteStream::write(const void *buffer, size_t size)
+{
+ G_THROW( ERR_MSG("not_implemented_n") "\tPoolByteStream::write()"); // PoolByteStream::write() is not implemented.
+ return 0; // For compiler not to bark
+}
+
+long
+PoolByteStream::tell(void) const
+{
+ return position;
+}
+
+int
+PoolByteStream::seek(long offset, int whence, bool nothrow)
+{
+ int retval=(-1);
+ switch(whence)
+ {
+ case SEEK_CUR:
+ offset+=position;
+ // fallthrough;
+ case SEEK_SET:
+ if(offset<position)
+ {
+ if((int)(offset+buffer_pos)>=(int)position)
+ {
+ buffer_pos-=position-offset;
+ }else
+ {
+ buffer_size=0;
+ }
+ position=offset;
+ }else if(offset>position)
+ {
+ buffer_pos+=(offset-position)-1;
+ position=offset-1;
+ unsigned char c;
+ if(read(&c,1)<1)
+ {
+ G_THROW( ByteStream::EndOfFile );
+ }
+ }
+ retval=0;
+ break;
+ case SEEK_END:
+ if(! nothrow)
+ G_THROW( ERR_MSG("DataPool.seek_backward") );
+ break;
+ }
+ return retval;
+}
+
+void
+DataPool::close_all(void)
+{
+ OpenFiles::get()->close_all();
+}
+
+
+GP<ByteStream>
+DataPool::get_stream(void)
+{
+ if(data && data->is_static())
+ {
+ GCriticalSectionLock lock(&data_lock);
+ data->seek(0, SEEK_SET);
+ return data->duplicate(length);
+ }else
+ {
+ return new PoolByteStream(this);
+ }
+}
+
+
+inline
+DataPool::Counter::operator int(void) const
+{
+ GCriticalSectionLock lk((GCriticalSection *) &lock);
+ int cnt=counter;
+ return cnt;
+}
+
+inline void
+DataPool::Counter::inc(void)
+{
+ GCriticalSectionLock lk(&lock);
+ counter++;
+}
+
+inline void
+DataPool::Counter::dec(void)
+{
+ GCriticalSectionLock lk(&lock);
+ counter--;
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DataPool.h b/kviewshell/plugins/djvu/libdjvu/DataPool.h
new file mode 100644
index 00000000..fb4bea4e
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DataPool.h
@@ -0,0 +1,627 @@
+//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: DataPool.h,v 1.10 2003/11/07 22:08:20 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _DATAPOOL_H
+#define _DATAPOOL_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+#include "GThreads.h"
+#include "GString.h"
+#include "GURL.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+class ByteStream;
+
+/** @name DataPool.h
+ Files #"DataPool.h"# and #"DataPool.cpp"# implement classes \Ref{DataPool}
+ and \Ref{DataRange} used by DjVu decoder to access data.
+
+ The main goal of class \Ref{DataPool} is to provide concurrent access
+ to the same data from many threads with a possibility to add data
+ from yet another thread. It is especially important in the case of the
+ Netscape plugin when data is not immediately available, but decoding
+ should be started as soon as possible. In this situation it is vital
+ to provide transparent access to the data from many threads possibly
+ blocking readers that try to access information that has not been
+ received yet.
+
+ When the data is local though, it can be accessed directly using
+ standard IO mechanism. To provide a uniform interface for decoding
+ routines, \Ref{DataPool} supports file mode as well.
+
+ @memo Thread safe data storage
+ @author Andrei Erofeev <eaf@geocities.com>
+ @version #$Id: DataPool.h,v 1.10 2003/11/07 22:08:20 leonb Exp $#
+*/
+
+//@{
+
+/** Thread safe data storage.
+ The purpose of #DataPool# is to provide a uniform interface for
+ accessing data from decoding routines running in a multi-threaded
+ environment. Depending on the mode of operation it may contain the
+ actual data, may be connected to another #DataPool# or may be mapped
+ to a file. Regardless of the mode, the class returns data in a
+ thread-safe way, blocking reading threads if there is no data of
+ interest available. This blocking is especially useful in the
+ networking environment (plugin) when there is a running decoding thread,
+ which wants to start decoding as soon as there is just one byte available
+ blocking if necessary.
+
+ Access to data in a #DataPool# may be direct (Using \Ref{get_data}()
+ function) or sequential (See \Ref{get_stream}() function).
+
+ If the #DataPool# is not connected to anything, that is it contains
+ some real data, this data can be added to it by means of two
+ \Ref{add_data}() functions. One of them adds data sequentially maintaining
+ the offset of the last block of data added by it. The other can store
+ data anywhere. Thus it's important to realize, that there may be "white
+ spots" in the data storage.
+
+ There is also a way to test if data is available for some given data
+ range (See \Ref{has_data}()). In addition to this mechanism, there are
+ so-called {\em trigger callbacks}, which are called, when there is
+ all data available for a given data range.
+
+ Let us consider all modes of operation in details:
+
+ \begin{enumerate}
+ \item {\bf Not connected #DataPool#}. In this mode the #DataPool#
+ contains some real data. As mentioned above, it may be added
+ by means of two functions \Ref{add_data}() operating independent
+ of each other and allowing to add data sequentially and
+ directly to any place of data storage. It's important to call
+ function \Ref{set_eof}() after all data has been added.
+
+ Functions like \Ref{get_data}() or \Ref{get_stream}() can
+ be used to obtain direct or sequential access to the data. As
+ long as \Ref{is_eof}() is #FALSE#, #DataPool# will block every
+ reader, which is trying to read unavailable data until it
+ really becomes available. But as soon as \Ref{is_eof}() is
+ #TRUE#, any attempt to read non-existing data will read #0# bytes.
+
+ Taking into account the fact, that #DataPool# was designed to
+ store DjVu files, which are in IFF formats, it becomes possible
+ to predict the size of the #DataPool# as soon as the first
+ #32# bytes have been added. This is invaluable for estimating
+ download progress. See function \Ref{get_length}() for details.
+ If this estimate fails (which means, that stored data is not
+ in IFF format), \Ref{get_length}() returns #-1#.
+
+ Triggers may be added and removed by means of \Ref{add_trigger}()
+ and \Ref{del_trigger}() functions. \Ref{add_trigger}() takes
+ a data range. As soon as all data in that data range is
+ available, the trigger callback will be called.
+
+ All trigger callbacks will be called when #EOF# condition
+ has been set.
+
+ \item {\bf #DataPool# connected to another #DataPool#}. In this
+ {\em slave} mode you can map a given #DataPool# to any offsets
+ range inside another #DataPool#. You can connect the slave
+ #DataPool# even if there is no data in the master #DataPool#.
+ Any \Ref{get_data}() request will be forwarded to the master
+ #DataPool#, and it will be responsible for blocking readers
+ trying to access unavailable data.
+
+ The usage of \Ref{add_data}() functions is prohibited for
+ connected #DataPool#s.
+
+ The offsets range used to map a slave #DataPool# can be fully
+ specified (both start offset and length are positive numbers)
+ or partially specified (the length is negative). In this mode
+ the slave #DataPool# is assumed to extend up to the end
+ of the master #DataPool#.
+
+ Triggers may be used with slave #DataPool#s as well as with
+ the master ones.
+
+ Calling \Ref{stop}() function of a slave will stop only the slave
+ (and any other slave connected to it), but not the master.
+
+ \Ref{set_eof}() function is meaningless for slaves. They obtain
+ the #ByteStream::EndOfFile# status from their master.
+
+ Depending on the offsets range passed to the constructor,
+ \Ref{get_length}() returns different values. If the length
+ passed to the constructor was positive, then it is returned
+ by \Ref{get_length}() all the time. Otherwise the value returned
+ is either #-1# if master's length is still unknown (it didn't
+ manage to parse IFF data yet) or it is calculated as
+ #masters_length-slave_start#.
+
+ \item {\bf #DataPool# connected to a file}. This mode is quite similar
+ to the case, when the #DataPool# is connected to another
+ #DataPool#. Similarly, the #DataPool# stores no data inside.
+ It just forwards all \Ref{get_data}() requests to the underlying
+ source (a file in this case). Thus these requests will never
+ block the reader. But they may return #0# if there is no data
+ available at the requested offset.
+
+ The usage of \Ref{add_data}() functions is meaningless and
+ is prohibited.
+
+ \Ref{is_eof}() function always returns #TRUE#. Thus \Ref{set_eof}()
+ us meaningless and does nothing.
+
+ \Ref{get_length}() function always returns the file size.
+
+ Calling \Ref{stop}() function will stop this #DataPool# and
+ any other slave connected to it.
+
+ Trigger callbacks passed through \Ref{add_trigger}() function
+ are called immediately.
+
+ This mode is useful to read and decode DjVu files without reading
+ and storing them in full in memory.
+ \end{enumerate}
+*/
+
+class DataPool : public GPEnabled
+{
+public: // Classes used internally by DataPool
+ // These are declared public to support buggy C++ compilers.
+ class Incrementor;
+ class Reader;
+ class Trigger;
+ class OpenFiles;
+ class OpenFiles_File;
+ class BlockList;
+ class Counter;
+protected:
+ DataPool(void);
+
+public:
+ /** @name Initialization */
+ //@{
+ /** Default creator. Will prepare #DataPool# for accepting data
+ added through functions \Ref{add_data}(). Use \Ref{connect}()
+ functions if you want to map this #DataPool# to another or
+ to a file. */
+ static GP<DataPool> create(void);
+
+ /** Creates and initialized the #DataPool# with data from stream #str#.
+ The constructor will read the stream's contents and add them
+ to the pool using the \Ref{add_data}() function. Afterwards it
+ will call \Ref{set_eof}() function, and no other data will be
+ allowed to be added to the pool. */
+ static GP<DataPool> create(const GP<ByteStream> & str);
+
+ /** Initializes the #DataPool# in slave mode and connects it
+ to the specified offsets range of the specified master #DataPool#.
+ It is equivalent to calling default constructor and function
+ \Ref{connect}().
+
+ @param master_pool Master #DataPool# providing data for this slave
+ @param start Beginning of the offsets range which the slave is
+ mapped into
+ @param length Length of the offsets range. If negative, the range
+ is assumed to extend up to the end of the master #DataPool#.
+ */
+ static GP<DataPool> create(const GP<DataPool> & master_pool, int start=0, int length=-1);
+
+ /** Initializes the #DataPool# in slave mode and connects it
+ to the specified offsets range of the specified file.
+ It is equivalent to calling default constructor and function
+ \Ref{connect}().
+ @param url Name of the file to connect to.
+ @param start Beginning of the offsets range which the #DataPool# is
+ mapped into
+ @param length Length of the offsets range. If negative, the range
+ is assumed to extend up to the end of the file.
+ */
+ static GP<DataPool> create(const GURL &url, int start=0, int length=-1);
+
+ virtual ~DataPool();
+
+ /** Switches the #DataPool# to slave mode and connects it to the
+ specified offsets range of the master #DataPool#.
+ @param master_pool Master #DataPool# providing data for this slave
+ @param start Beginning of the offsets range which the slave is
+ mapped into
+ @param length Length of the offsets range. If negative, the range
+ is assumed to extend up to the end of the master #DataPool#.
+ */
+ void connect(const GP<DataPool> & master_pool, int start=0, int length=-1);
+ /** Connects the #DataPool# to the specified offsets range of
+ the named #url#.
+ @param url Name of the file to connect to.
+ @param start Beginning of the offsets range which the #DataPool# is
+ mapped into
+ @param length Length of the offsets range. If negative, the range
+ is assumed to extend up to the end of the file.
+ */
+ void connect(const GURL &url, int start=0, int length=-1);
+ //@}
+
+ /** Tells the #DataPool# to stop serving readers.
+
+ If #only_blocked# flag is #TRUE# then only those requests will
+ be processed, which would not block. Any attempt to get non-existing
+ data would result in a #STOP# exception (instead of blocking until
+ data is available).
+
+ If #only_blocked# flag is #FALSE# then any further attempt to read
+ from this #DataPool# (as well as from any #DataPool# connected
+ to this one) will result in a #STOP# exception. */
+ void stop(bool only_blocked=false);
+
+ /** @name Adding data.
+ Please note, that these functions are for not connected #DataPool#s
+ only. You can not add data to a #DataPool#, which is connected
+ to another #DataPool# or to a file.
+ */
+ //@{
+ /** Appends the new block of data to the #DataPool#. There are two
+ \Ref{add_data}() functions available. One is for adding data
+ sequentially. It keeps track of the last byte position, which has
+ been stored {\bf by it} and always appends the next block after
+ this position. The other \Ref{add_data}() can store data anywhere.
+
+ The function will unblock readers waiting for data if this data
+ arrives with this block. It may also trigger some {\em trigger
+ callbacks}, which may have been added by means of \Ref{add_trigger}()
+ function.
+
+ {\bf Note:} After all the data has been added, it's necessary
+ to call \Ref{set_eof}() to tell the #DataPool# that nothing else
+ is expected.
+
+ {\bf Note:} This function may not be called if the #DataPool#
+ has been connected to something.
+
+ @param buffer data to append
+ @param size length of the {\em buffer}
+ */
+ void add_data(const void * buffer, int size);
+
+ /** Stores the specified block of data at the specified offset.
+ Like the function above this one can also unblock readers
+ waiting for data and engage trigger callbacks. The difference
+ is that {\bf this} function can store data anywhere.
+
+ {\bf Note:} After all the data has been added, it's necessary
+ to call \Ref{set_eof}() to tell the #DataPool# that nothing else
+ is expected.
+
+ {\bf Note:} This function may not be called if the #DataPool#
+ has been connected to something.
+
+ @param buffer data to store
+ @param offset where to store the data
+ @param size length of the {\em buffer} */
+ void add_data(const void * buffer, int offset, int size);
+
+ /** Tells the #DataPool# that all data has been added and nothing else
+ is anticipated. When #EOF# is true, any reader attempting to read
+ non existing data will not be blocked. It will either read #ZERO#
+ bytes or will get an #ByteStream::EndOfFile# exception (see \Ref{get_data}()).
+ Calling this function will also activate all registered trigger
+ callbacks.
+
+ {\bf Note:} This function is meaningless and does nothing
+ when the #DataPool# is connected to another #DataPool# or to
+ a file. */
+ void set_eof(void);
+ //@}
+
+ /** @name Accessing data.
+ These functions provide direct and sequential access to the
+ data of the #DataPool#. If the #DataPool# is not connected
+ (contains some real data) then it handles the requests itself.
+ Otherwise they are forwarded to the master #DataPool# or the file.
+ */
+ //@{
+ /** Attempts to return a block of data at the given #offset#
+ of the given #size#.
+
+ \begin{enumerate}
+ \item If the #DataPool# is connected to another #DataPool# or
+ to a file, the request will just be forwarded to them.
+ \item If the #DataPool# is not connected to anything and
+ some of the data requested is in the internal buffer,
+ the function copies available data to #buffer# and returns
+ immediately.
+
+ If there is no data available, and \Ref{is_eof}() returns
+ #FALSE#, the reader (and the thread) will be {\bf blocked}
+ until the data actually arrives. Please note, that since
+ the reader is blocked, it should run in a separate thread
+ so that other threads have a chance to call \Ref{add_data}().
+ If there is no data available, but \Ref{is_eof}() is #TRUE#
+ the behavior is different and depends on the #DataPool#'s
+ estimate of the file size:
+ \begin{itemize}
+ \item If #DataPool# learns from the IFF structure of the
+ data, that its size should be greater than it
+ really is, then any attempt to read non-existing
+ data in the range of {\em valid} offsets will
+ result in an #ByteStream::EndOfFile# exception. This is done to
+ indicate, that there was an error in adding data,
+ and the data requested is {\bf supposed} to be
+ there, but has actually not been added.
+ \item If #DataPool#'s expectations about the data size
+ coincide with the reality then any attempt to
+ read data beyond the legal range of offsets will
+ result in #ZERO# bytes returned.
+ \end{itemize}.
+ \end{enumerate}.
+
+ @param buffer Buffer to be filled with data
+ @param offset Offset in the #DataPool# to read data at
+ @param size Size of the {\em buffer}
+ @return The number of bytes actually read
+ @exception STOP The stream has been stopped
+ @exception EOF The requested data is not there and will not be added,
+ although it should have been.
+ */
+ int get_data(void * buffer, int offset, int size);
+
+ /** Returns a \Ref{ByteStream} to access contents of the #DataPool#
+ sequentially. By reading from the returned stream you basically
+ call \Ref{get_data}() function. Thus, everything said for it
+ remains true for the stream too. */
+ GP<ByteStream> get_stream(void);
+ //@}
+
+ /** @name State querying functions. */
+ //@{
+ /** Returns #TRUE# if this #DataPool# is connected to another #DataPool#
+ or to a file. */
+ bool is_connected(void) const;
+
+ /** Returns #TRUE# if all data available for offsets from
+ #start# till #start+length-1#. If #length# is negative, the
+ range is assumed to extend up to the end of the #DataPool#.
+ This function works both for connected and not connected #DataPool#s.
+ Once it returned #TRUE# for some offsets range, you can be
+ sure that the subsequent \Ref{get_data}() request will not block.
+ */
+ bool has_data(int start, int length);
+
+ /* Returns #TRUE# if no more data is planned to be added.
+
+ {\bf Note:} This function always returns #TRUE# when the #DataPool#
+ has been initialized with a file name. */
+ bool is_eof(void) const {return eof_flag;}
+
+ /** Returns the {\em length} of data in the #DataPool#. The value
+ returned depends on the mode of operation:
+ \begin{itemize}
+ \item If the #DataPool# is not connected to anything then
+ the length returned is either calculated by interpreting
+ the IFF structure of stored data (if successful) or
+ by calculating the real size of data after \Ref{set_eof}()
+ has been called. Otherwise it is #-1#.
+ \item If the #DataPool# is connected to a file, the length
+ is calculated basing on the length passed to the
+ \Ref{connect}() function and the file size.
+ \item If the #DataPool# is connected to a master #DataPool#,
+ the length is calculated basing on the value returned
+ by the master's #get_length()# function and the length
+ passed to the \Ref{connect}() function.
+ \end{itemize}. */
+ int get_length(void) const;
+ /** Returns the number of bytes of data available in this #DataPool#.
+ Contrary to the \Ref{get_length}() function, this one doesn't try
+ to interpret the IFF structure and predict the file length.
+ It just returns the number of bytes of data really available inside
+ the #DataPool#, if it contains data, or inside its range, if it's
+ connected to another #DataPool# or a file. */
+ int get_size(void) const {return get_size(0, -1);}
+ //@}
+
+ /** @name Trigger callbacks.
+ {\em Trigger callbacks} are special callbacks called when
+ all data for the given range of offsets has been made available.
+ Since reading unavailable data may result in a thread block,
+ which may be bad, the usage of {\em trigger callbacks} appears
+ to be a convenient way to signal availability of data.
+
+ You can add a trigger callback in two ways:
+ \begin{enumerate}
+ \item By specifying a range. This is the most general case
+ \item By providing just one {\em threshold}. In this case
+ the range is assumed to start from offset #ZERO# and
+ last for {\em threshold}+1 bytes.
+ \end{enumerate}
+ */
+ //@{
+ /** Associates the specified {\em trigger callback} with the
+ given data range.
+
+ {\bf Note:} The callback may be called immediately if all
+ data for the given range is already available or #EOF# is #TRUE#.
+
+ @param start The beginning of the range for which all data
+ should be available
+ @param length If the {\em length} is not negative then the callback
+ will be called when there is data available for every
+ offset from {\em start} to {\em start+length-1}.
+ If {\em thresh} is negative, the callback is called after
+ #EOF# condition has been set.
+ @param callback Function to call
+ @param cl_data Argument to pass to the callback when it's called. */
+ void add_trigger(int start, int length,
+// void (* callback)(GP<GPEnabled> &), GP<GPEnabled> cl_data);
+ void (* callback)(void *), void * cl_data);
+
+ /** Associates the specified {\em trigger callback} with the
+ specified threshold.
+
+ This function is a simplified version of the function above.
+ The callback will be called when there is data available for
+ every offset from #0# to #thresh#, if #thresh# is positive, or
+ when #EOF# condition has been set otherwise. */
+// void add_trigger(int thresh, void (* callback)(GP<GPEnabled> &), GP<GPEnabled> cl_data);
+ void add_trigger(int thresh, void (* callback)(void *), void * cl_data);
+
+ /** Use this function to unregister callbacks, which are no longer
+ needed. {\bf Note!} It's important to do it when the client
+ is about to be destroyed. */
+ void del_trigger(void (* callback)(void *), void * cl_data);
+// void del_trigger(void (* callback)(GP<GPEnabled> &), GP<GPEnabled> cl_data);
+ //@}
+
+ /** Loads data from the file into memory. This function is only useful
+ for #DataPool#s getting data from a file. It descends the #DataPool#s
+ hierarchy until it either reaches a file-connected #DataPool#
+ or #DataPool# containing the real data. In the latter case it
+ does nothing, in the first case it makes the #DataPool# read all
+ data from the file into memory and stop using the file.
+
+ This may be useful when you want to overwrite the file and leave
+ existing #DataPool#s with valid data. */
+ void load_file(void);
+ /** This function will make every #DataPool# in the program, which
+ is connected to a file, to load the file contents to the main
+ memory and close the file. This feature is important when you
+ want to do something with the file like remove or overwrite it
+ not affecting the rest of the program. */
+ static void load_file(const GURL &url);
+
+ /** This function will remove OpenFiles filelist. */
+ static void close_all(void);
+
+ // Internal. Used by 'OpenFiles'
+ void clear_stream(const bool release = true);
+
+ /** Useful in comparing data pools. Returns true if dirived from
+ same URL or bytestream. */
+ bool simple_compare(DataPool &pool) const;
+private:
+ bool eof_flag;
+ bool stop_flag;
+ bool stop_blocked_flag;
+
+ Counter *active_readers;
+
+ // Source or storage of data
+ GP<DataPool> pool;
+ GURL furl;
+ GP<OpenFiles_File> fstream;
+ GCriticalSection class_stream_lock;
+ GP<ByteStream> data;
+ GCriticalSection data_lock;
+ BlockList *block_list;
+ int add_at;
+ int start, length;
+
+ // List of readers waiting for data
+ GPList<Reader> readers_list;
+ GCriticalSection readers_lock;
+
+ // Triggers
+ GPList<Trigger> triggers_list; // List of passed or our triggers
+ GCriticalSection triggers_lock; // Lock for the list above
+ GCriticalSection trigger_lock; // Lock for static_trigger_cb()
+
+ void init(void);
+ void wait_for_data(const GP<Reader> & reader);
+ void wake_up_all_readers(void);
+ void check_triggers(void);
+ int get_data(void * buffer, int offset, int size, int level);
+ int get_size(int start, int length) const;
+ void restart_readers(void);
+
+// static void static_trigger_cb(GP<GPEnabled> &);
+ static void static_trigger_cb(void *);
+ void trigger_cb(void);
+ void analyze_iff(void);
+ void added_data(const int offset, const int size);
+public:
+ static const char *Stop;
+ friend class FCPools;
+};
+
+inline bool
+DataPool::simple_compare(DataPool &pool) const
+{
+ // return true if these pools are identical. False means they may or may
+ // not be identical.
+ return (this == &pool)
+ ||(furl.is_valid()&&!furl.is_empty()&&pool.furl.is_valid()&&(furl == pool.furl))
+ ||(data && (data == pool.data));
+}
+
+inline bool
+DataPool::is_connected(void) const
+{
+ return furl.is_local_file_url() || pool!=0;
+}
+
+//@}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVmDir.cpp b/kviewshell/plugins/djvu/libdjvu/DjVmDir.cpp
new file mode 100644
index 00000000..83f9df78
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVmDir.cpp
@@ -0,0 +1,839 @@
+//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: DjVmDir.cpp,v 1.10 2004/05/05 15:12:42 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "DjVmDir.h"
+#include "BSByteStream.h"
+#include "GURL.h"
+#include "debug.h"
+
+#include <ctype.h>
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+GP<DjVmDir::File>
+DjVmDir::File::create(const GUTF8String &load_name,
+ const GUTF8String &save_name, const GUTF8String &title,
+ const FILE_TYPE file_type)
+{
+ File *file_ptr=new File();
+ GP<File> file=file_ptr;
+ file_ptr->set_load_name(load_name);
+ file_ptr->set_save_name(save_name);
+ file_ptr->set_title(title);
+ file_ptr->flags=(file_type & TYPE_MASK);
+ return file;
+}
+
+const GUTF8String &
+DjVmDir::File::check_save_name(const bool xis_bundled)
+{
+ if(!xis_bundled && !valid_name)
+ {
+ GUTF8String retval=name.length()?name:id;
+ if(GUTF8String(GNativeString(retval)) != retval)
+ {
+ const_cast<bool &>(valid_name)=true;
+ char *buf;
+ GPBuffer<char> gbuf(buf,2*retval.length()+1);
+ char *s=buf;
+ int i=0;
+ for(char c=retval[i++];c;)
+ {
+ static const char hex[]="0123456789ABCDEF";
+ int len=retval.nextChar(i)-i;
+ if(len>1 || ((len == 1)&&(c&0x80)))
+ {
+ do
+ {
+ s++[0]=hex[(c>>4)&0xf];
+ s++[0]=hex[(c&0xf)];
+ c=retval[i++];
+ } while(c && ((--len) > 0));
+ }else
+ {
+ s++[0]=c;
+ c=retval[i++];
+ }
+ }
+ s++[0]=0;
+ oldname=retval;
+ name=buf;
+ }
+ const_cast<bool &>(valid_name)=true;
+ }
+ return *(name.length()?&name:&id);
+}
+
+const GUTF8String &
+DjVmDir::File::get_save_name(void) const
+{
+ return *(name.length()?&name:&id);
+}
+
+void
+DjVmDir::File::set_load_name(const GUTF8String &xid)
+{
+ GURL url=GURL::UTF8(xid);
+ if(!url.is_valid())
+ {
+ url=GURL::Filename::UTF8(xid);
+ }
+ id=url.fname();
+}
+
+void
+DjVmDir::File::set_save_name(const GUTF8String &xname)
+{
+ GURL url;
+ valid_name=false;
+ if(!xname.length())
+ {
+ GURL url=GURL::UTF8(id);
+ if(!url.is_valid())
+ {
+ name=id;
+ }else
+ {
+ name=url.fname();
+ }
+ }else
+ {
+ GURL url=GURL::UTF8(xname);
+ if(!url.is_valid())
+ {
+ url=GURL::Filename::UTF8(xname);
+ }
+ name=url.fname();
+ }
+ oldname="";
+}
+
+/* DjVmDir::File */
+
+DjVmDir::File::File(void) : offset(0), size(0), valid_name(false),
+ flags(0), page_num(-1) { }
+
+GUTF8String
+DjVmDir::File::get_str_type(void) const
+{
+ GUTF8String type;
+ switch(flags & TYPE_MASK)
+ {
+ case INCLUDE:
+ type="INCLUDE";
+ break;
+ case PAGE:
+ type="PAGE";
+ break;
+ case THUMBNAILS:
+ type="THUMBNAILS";
+ break;
+ case SHARED_ANNO:
+ type="SHARED_ANNO";
+ break;
+ default:
+ // Internal error: please modify DjVmDir::File::get_str_type()
+ // to contain all possible File types.
+ G_THROW( ERR_MSG("DjVmDir.get_str_type") );
+ }
+ return type;
+}
+
+
+const int DjVmDir::version=1;
+
+void
+DjVmDir::decode(const GP<ByteStream> &gstr)
+{
+ ByteStream &str=*gstr;
+ DEBUG_MSG("DjVmDir::decode(): decoding contents of 'DIRM' chunk...\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GCriticalSectionLock lock(&class_lock);
+
+ GPosition pos;
+
+ files_list.empty();
+ page2file.resize(-1);
+ name2file.empty();
+ id2file.empty();
+ title2file.empty();
+
+ int ver=str.read8();
+ bool bundled=(ver & 0x80)!=0;
+ ver&=0x7f;
+
+ DEBUG_MSG("DIRM version=" << ver << ", our version=" << version << "\n");
+ if (ver>version)
+ G_THROW( ERR_MSG("DjVmDir.version_error") "\t"
+ + GUTF8String(version) + "\t" + GUTF8String(ver));
+ // Unable to read DJVM directories of versions higher than xxx
+ // Data version number is yyy.
+ DEBUG_MSG("bundled directory=" << bundled << "\n");
+ DEBUG_MSG("reading the directory records...\n");
+ int files=str.read16();
+ DEBUG_MSG("number of files=" << files << "\n");
+
+ if (files)
+ {
+ DEBUG_MSG("reading offsets (and sizes for ver==0)\n");
+ for(int nfile=0;nfile<files;nfile++)
+ {
+ GP<File> file=new File();
+ files_list.append(file);
+ if (bundled)
+ {
+ file->offset=str.read32();
+ if (ver==0)
+ file->size=str.read24();
+ if (file->offset==0)
+ G_THROW( ERR_MSG("DjVmDir.no_indirect") );
+ } else
+ {
+ file->offset=file->size=0;
+ }
+ }
+
+ GP<ByteStream> gbs_str=BSByteStream::create(gstr);
+ ByteStream &bs_str=*gbs_str;
+ if (ver>0)
+ {
+ DEBUG_MSG("reading and decompressing sizes...\n");
+ for(GPosition pos=files_list;pos;++pos)
+ files_list[pos]->size=bs_str.read24();
+ }
+
+ DEBUG_MSG("reading and decompressing flags...\n");
+ for(pos=files_list;pos;++pos)
+ files_list[pos]->flags=bs_str.read8();
+
+ if (!ver)
+ {
+ DEBUG_MSG("converting flags from version 0...\n");
+ for(pos=files_list;pos;++pos)
+ {
+ unsigned char flags_0=files_list[pos]->flags;
+ unsigned char flags_1;
+ flags_1=(flags_0 & File::IS_PAGE_0)?(File::PAGE):(File::INCLUDE);
+ if (flags_0 & File::HAS_NAME_0)
+ flags_1|=File::HAS_NAME;
+ if (flags_0 & File::HAS_TITLE_0)
+ flags_1|=File::HAS_TITLE;
+ files_list[pos]->flags=flags_1;
+ }
+ }
+
+ DEBUG_MSG("reading and decompressing names...\n");
+ GTArray<char> strings;
+ char buffer[1024];
+ int length;
+ while((length=bs_str.read(buffer, 1024)))
+ {
+ int strings_size=strings.size();
+ strings.resize(strings_size+length-1);
+ memcpy((char*) strings+strings_size, buffer, length);
+ }
+ DEBUG_MSG("size of decompressed names block=" << strings.size() << "\n");
+
+ // Copy names into the files
+ const char * ptr=strings;
+ for(pos=files_list;pos;++pos)
+ {
+ GP<File> file=files_list[pos];
+
+ file->id=ptr;
+ ptr+=file->id.length()+1;
+ if (file->flags & File::HAS_NAME)
+ {
+ file->name=ptr;
+ ptr+=file->name.length()+1;
+ } else
+ {
+ file->name=file->id;
+ }
+ if (file->flags & File::HAS_TITLE)
+ {
+ file->title=ptr;
+ ptr+=file->title.length()+1;
+ } else
+ file->title=file->id;
+ /* msr debug: multipage file, file->title is null.
+ DEBUG_MSG(file->name << ", " << file->id << ", " << file->title << ", " <<
+ file->offset << ", " << file->size << ", " <<
+ file->is_page() << "\n"); */
+ }
+
+ // Check that there is only one file with SHARED_ANNO flag on
+ int shared_anno_cnt=0;
+ for(pos=files_list;pos;++pos)
+ {
+ if (files_list[pos]->is_shared_anno())
+ {
+ shared_anno_cnt++;
+ }
+ }
+ if (shared_anno_cnt>1)
+ G_THROW( ERR_MSG("DjVmDir.corrupt") );
+
+ // Now generate page=>file array for direct access
+ int pages=0;
+ for(pos=files_list;pos;++pos)
+ pages+=files_list[pos]->is_page() ? 1 : 0;
+ DEBUG_MSG("got " << pages << " pages\n");
+ page2file.resize(pages-1);
+ int page_num=0;
+ for(pos=files_list;pos;++pos)
+ {
+ GP<File> file=files_list[pos];
+ if (file->is_page())
+ {
+ page2file[page_num]=file;
+ file->page_num=page_num++;
+ }
+ }
+
+ // Generate name2file map
+ for(pos=files_list;pos;++pos)
+ {
+ GP<File> file=files_list[pos];
+ if (name2file.contains(file->name))
+ G_THROW( ERR_MSG("DjVmDir.dupl_name") "\t" + file->name );
+ name2file[file->name]=file;
+ }
+
+ // Generate id2file map
+ for(pos=files_list;pos;++pos)
+ {
+ GP<File> file=files_list[pos];
+ if (id2file.contains(file->id))
+ G_THROW( ERR_MSG("DjVmDir.dupl_id") "\t" + file->id);
+ id2file[file->id]=file;
+ }
+
+ // Generate title2file map
+ for(pos=files_list;pos;++pos)
+ {
+ GP<File> file=files_list[pos];
+ if (file->title.length())
+ {
+ if (title2file.contains(file->title))
+ G_THROW( ERR_MSG("DjVmDir.dupl_title") "\t" + file->title);
+ title2file[file->title]=file;
+ }
+ }
+ }
+}
+
+
+void
+DjVmDir::encode(const GP<ByteStream> &gstr, const bool do_rename) const
+{
+ bool bundled = true;
+ GPosition pos = files_list;
+ if (files_list.size() && !files_list[pos]->offset)
+ bundled = false;
+ for (pos=files_list; pos; ++pos)
+ if ( !bundled != !files_list[pos]->offset)
+ // There directory contains both indirect and bundled records.
+ G_THROW( ERR_MSG("DjVmDir.bad_dir") );
+ // Do the real work
+ encode(gstr, bundled, do_rename);
+}
+
+void
+DjVmDir::encode(const GP<ByteStream> &gstr, const bool bundled, const bool do_rename) const
+{
+ ByteStream &str=*gstr;
+ DEBUG_MSG("DjVmDir::encode(): encoding contents of the 'DIRM' chunk do_rename=" << do_rename << "\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+ GPosition pos;
+
+ DEBUG_MSG("encoding version number=" << version << ", bundled=" << bundled << "\n");
+ str.write8(version | ((int) bundled<< 7));
+
+ DEBUG_MSG("storing the number of records=" << files_list.size() << "\n");
+ str.write16(files_list.size());
+
+ if (files_list.size())
+ {
+ // Check that there is only one file with shared annotations
+ int shared_anno_cnt=0;
+ for (pos=files_list; pos; ++pos)
+ if (files_list[pos]->is_shared_anno())
+ shared_anno_cnt++;
+ if (shared_anno_cnt>1)
+ G_THROW( ERR_MSG("DjVmDir.multi_save") );
+
+ if (bundled)
+ {
+ // We need to store offsets uncompressed. That's because when
+ // we save a DjVmDoc, we first compress the DjVmDir with dummy
+ // offsets and after computing the real offsets we rewrite the
+ // DjVmDir, which should not change its size during this operation
+ DEBUG_MSG("storing offsets for every record\n");
+ for (pos=files_list; pos; ++pos)
+ {
+ GP<File> file=files_list[pos];
+ if (!file->offset)
+ // The directory contains record without offset
+ G_THROW( ERR_MSG("DjVmDir.bad_dir") );
+ str.write32(file->offset);
+ }
+ }
+
+ GP<ByteStream> gbs_str=BSByteStream::create(gstr, 50);
+ ByteStream &bs_str=*gbs_str;
+ DEBUG_MSG("storing and compressing sizes for every record\n");
+ for (pos=files_list; pos; ++pos)
+ {
+ const GP<File> file(files_list[pos]);
+ bs_str.write24(file->size);
+ }
+ DEBUG_MSG("storing and compressing flags for every record\n");
+ const bool xdo_rename=(do_rename||!bundled);
+ for(pos=files_list;pos;++pos)
+ {
+ const GP<File> file(files_list[pos]);
+ if(xdo_rename)
+ {
+ const GUTF8String new_id = file->name;
+ if (! new_id)
+ if(!file->oldname.length() || file->oldname == new_id)
+ file->flags &= ~File::HAS_NAME;
+ else
+ file->flags |= File::HAS_NAME;
+ }
+ else
+ {
+ if (!file->name.length() || file->name == file->id)
+ file->flags &= ~File::HAS_NAME;
+ else
+ file->flags |= File::HAS_NAME;
+ }
+ if (file->title.length() && (file->title!=file->id))
+ file->flags |= File::HAS_TITLE;
+ else
+ file->flags &= ~File::HAS_TITLE;
+
+ bs_str.write8(file->flags);
+ }
+
+ DEBUG_MSG("storing and compressing names...\n");
+ for(pos=files_list;pos;++pos)
+ {
+ GP<File> file=files_list[pos];
+ GUTF8String id;
+ GUTF8String name;
+ GUTF8String title;
+ if (xdo_rename)
+ {
+ id = file->name;
+ if (! id)
+ id = file->id;
+ if ((file->flags) & File::HAS_NAME)
+ name = file->oldname;
+ }
+ else
+ {
+ id=file->id;
+ if ((file->flags) & File::HAS_NAME)
+ name = file->name;
+ }
+ if ((file->flags) & File::HAS_TITLE)
+ title = file->title;
+ DEBUG_MSG("rename=" <<xdo_rename<<" id='" << id << "' name='" << name << "' title='" << title << "'\n");
+ bs_str.writestring(id);
+ bs_str.write8(0);
+ if (name.length())
+ {
+ bs_str.writestring(name);
+ bs_str.write8(0);
+ }
+ if (title.length())
+ {
+ bs_str.writestring(title);
+ bs_str.write8(0);
+ }
+ }
+ }
+ DEBUG_MSG("done\n");
+}
+
+GP<DjVmDir::File>
+DjVmDir::page_to_file(int page_num) const
+{
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+
+ return (page_num<page2file.size())?page2file[page_num]:(GP<DjVmDir::File>(0));
+}
+
+GP<DjVmDir::File>
+DjVmDir::name_to_file(const GUTF8String & name) const
+{
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+
+ GPosition pos;
+ return (name2file.contains(name, pos))?name2file[pos]:(GP<DjVmDir::File>(0));
+}
+
+GP<DjVmDir::File>
+DjVmDir::id_to_file(const GUTF8String &id) const
+{
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+
+ GPosition pos;
+ return (id2file.contains(id, pos))?id2file[pos]:(GP<DjVmDir::File>(0));
+}
+
+GP<DjVmDir::File>
+DjVmDir::title_to_file(const GUTF8String &title) const
+{
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+
+ GPosition pos;
+ return (title2file.contains(title, pos))?title2file[pos]:(GP<DjVmDir::File>(0));
+}
+
+GPList<DjVmDir::File>
+DjVmDir::get_files_list(void) const
+{
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+ return files_list;
+}
+
+int
+DjVmDir::get_files_num(void) const
+{
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+ return files_list.size();
+}
+
+int
+DjVmDir::get_pages_num(void) const
+{
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+ return page2file.size();
+}
+
+int
+DjVmDir::get_file_pos(const File * f) const
+{
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+ int cnt;
+ GPosition pos;
+ for(pos=files_list, cnt=0;pos&&(files_list[pos]!=f);++pos, cnt++)
+ continue;
+ return (pos)?cnt:(-1);
+}
+
+int
+DjVmDir::get_page_pos(int page_num) const
+{
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+
+ GP<File> file=page_to_file(page_num);
+ return (file)?get_file_pos(file):(-1);
+}
+
+GP<DjVmDir::File>
+DjVmDir::get_shared_anno_file(void) const
+{
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+
+ GP<File> file;
+ for(GPosition pos=files_list;pos;++pos)
+ {
+ GP<File> frec=files_list[pos];
+ if (frec->is_shared_anno())
+ {
+ file=frec;
+ break;
+ }
+ }
+ return file;
+}
+
+int
+DjVmDir::insert_file(const GP<File> & file, int pos_num)
+{
+ DEBUG_MSG("DjVmDir::insert_file(): name='" << file->name << "', pos=" << pos_num << "\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+
+ if (pos_num<0)
+ pos_num=files_list.size();
+
+ // Modify maps
+// if (! File::is_legal_id(file->id))
+// G_THROW( ERR_MSG("DjVmDir.bad_file") "\t" + file->id);
+ if (id2file.contains(file->id))
+ G_THROW( ERR_MSG("DjVmDir.dupl_id2") "\t" + file->id);
+ if (name2file.contains(file->name))
+ G_THROW( ERR_MSG("DjVmDir.dupl_name2") "\t" + file->name);
+ name2file[file->name]=file;
+ id2file[file->id]=file;
+ if (file->title.length())
+ {
+ if (title2file.contains(file->title)) // duplicate titles may become ok some day
+ G_THROW( ERR_MSG("DjVmDir.dupl_title2") "\t" + file->title);
+ title2file[file->title]=file;
+ }
+
+ // Make sure that there is no more than one file with shared annotations
+ if (file->is_shared_anno())
+ {
+ for(GPosition pos=files_list;pos;++pos)
+ if (files_list[pos]->is_shared_anno())
+ G_THROW( ERR_MSG("DjVmDir.multi_save2") );
+ }
+
+ // Add the file to the list
+ int cnt;
+ GPosition pos;
+ for(pos=files_list, cnt=0;pos&&(cnt!=pos_num);++pos, cnt++)
+ continue;
+ if (pos)
+ files_list.insert_before(pos, file);
+ else
+ files_list.append(file);
+
+ if (file->is_page())
+ {
+ // This file is also a page
+ // Count its number
+ int page_num=0;
+ for(pos=files_list;pos;++pos)
+ {
+ GP<File> &f=files_list[pos];
+ if (f==file)
+ break;
+ if (f->is_page())
+ page_num++;
+ }
+
+ int i;
+ page2file.resize(page2file.size());
+ for(i=page2file.size()-1;i>page_num;i--)
+ page2file[i]=page2file[i-1];
+ page2file[page_num]=file;
+ for(i=page_num;i<page2file.size();i++)
+ page2file[i]->page_num=i;
+ }
+ return pos_num;
+}
+
+void
+DjVmDir::delete_file(const GUTF8String &id)
+{
+ DEBUG_MSG("Deleting file with id='" << (const char *)id << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+
+ for(GPosition pos=files_list;pos;++pos)
+ {
+ GP<File> & f=files_list[pos];
+ if (id == f->id)
+ {
+ name2file.del(f->name);
+ id2file.del(f->id);
+ title2file.del(f->title);
+ if (f->is_page())
+ {
+ for(int page=0;page<page2file.size();page++)
+ {
+ if (page2file[page]==f)
+ {
+ int i;
+ for(i=page;i<page2file.size()-1;i++)
+ page2file[i]=page2file[i+1];
+ page2file.resize(page2file.size()-2);
+ for(i=page;i<page2file.size();i++)
+ page2file[i]->page_num=i;
+ break;
+ }
+ }
+ }
+ files_list.del(pos);
+ break;
+ }
+ }
+}
+
+void
+DjVmDir::set_file_name(const GUTF8String &id, const GUTF8String &name)
+{
+ DEBUG_MSG("DjVmDir::set_file_name(): id='" << id << "', name='" << name << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+
+ GPosition pos;
+
+ // First see, if the name is unique
+ for(pos=files_list;pos;++pos)
+ {
+ GP<File> file=files_list[pos];
+ if (file->id!=id && file->name==name)
+ G_THROW( ERR_MSG("DjVmDir.name_in_use") "\t" + GUTF8String(name));
+ }
+
+ // Check if ID is valid
+ if (!id2file.contains(id, pos))
+ G_THROW( ERR_MSG("DjVmDir.no_info") "\t" + GUTF8String(id));
+ GP<File> file=id2file[pos];
+ name2file.del(file->name);
+ file->name=name;
+ name2file[name]=file;
+}
+
+void
+DjVmDir::set_file_title(const GUTF8String &id, const GUTF8String &title)
+{
+ DEBUG_MSG("DjVmDir::set_file_title(): id='" << id << "', title='" << title << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+
+ GPosition pos;
+
+ // First see, if the title is unique
+ for(pos=files_list;pos;++pos)
+ {
+ GP<File> file=files_list[pos];
+ if (file->id!=id && file->title==title)
+ G_THROW( ERR_MSG("DjVmDir.title_in_use") "\t" + GUTF8String(title));
+ }
+
+ // Check if ID is valid
+ if (!id2file.contains(id, pos))
+ G_THROW( ERR_MSG("DjVmDir.no_info") "\t" + GUTF8String(id));
+ GP<File> file=id2file[pos];
+ title2file.del(file->title);
+ file->title=title;
+ title2file[title]=file;
+}
+
+GPList<DjVmDir::File>
+DjVmDir::resolve_duplicates(const bool save_as_bundled)
+{
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+ // Make sure all the filenames are unique.
+ GPosition pos;
+ GMap<GUTF8String,void *> save_map;
+ GMap<GUTF8String,GPList<DjVmDir::File> > conflicts;
+ for(pos=files_list;pos;++pos)
+ {
+ const GUTF8String save_name=files_list[pos]->check_save_name(save_as_bundled).downcase();
+ if(save_map.contains(save_name))
+ {
+ conflicts[save_name].append(files_list[pos]);
+ }else
+ {
+ save_map[save_name]=0;
+ }
+ }
+ for(pos=conflicts;pos;++pos)
+ {
+ const GUTF8String &save_name=conflicts.key(pos);
+ const int dot=save_name.rsearch('.',0);
+ GPList<DjVmDir::File> &cfiles=conflicts[pos];
+ int count=1;
+ for(GPosition qpos=cfiles;qpos;++qpos)
+ {
+ GUTF8String new_name=cfiles[qpos]->get_load_name();
+ if((new_name != GUTF8String(GNativeString(new_name)))
+ ||conflicts.contains(new_name))
+ {
+ do
+ {
+ new_name=(dot<0)
+ ?(save_name+"-"+GUTF8String(count++))
+ :(save_name.substr(0,dot)+"-"+GUTF8String(count++)+
+ save_name.substr(dot,(unsigned int)(-1)));
+ } while(save_map.contains(new_name.downcase()));
+ }
+ cfiles[qpos]->set_save_name(new_name);
+ save_map[new_name]=0;
+ }
+ }
+ return files_list;
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVmDir.h b/kviewshell/plugins/djvu/libdjvu/DjVmDir.h
new file mode 100644
index 00000000..86b661e3
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVmDir.h
@@ -0,0 +1,451 @@
+//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: DjVmDir.h,v 1.10 2003/11/07 22:08:20 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _DJVMDIR_H
+#define _DJVMDIR_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+/** @name DjVmDir.h
+ Files #"DjVmDir.h"# and #"DjVmDir.cpp"# implement class \Ref{DjVmDir} for
+ representing the directory of a DjVu multipage document.
+
+ {\bf Bundled vs. Indirect format} --- There are currently two multipage
+ DjVu formats supported: {\em bundled} and {\em indirect}. In the first
+ format all component files composing a given document are packaged (or
+ bundled) into one file, in the second one every page and component is
+ stored in a separate file and there is one more file, which contains the
+ list of all others.
+
+ {\bf Multipage DjVu format} --- Multipage DjVu documents follow the EA
+ IFF85 format (cf. \Ref{IFFByteStream.h}.) A document is composed of a
+ #"FORM:DJVM"# whose first chunk is a #"DIRM"# chunk containing the {\em
+ document directory}. This directory lists all component files composing
+ the given document, helps to access every component file and identify the
+ pages of the document.
+ \begin{itemize}
+ \item In a {\em bundled} multipage file, the component files
+ are stored immediately after the #"DIRM"# chunk,
+ within the #"FORM:DJVU"# composite chunk.
+ \item In an {\em indirect} multipage file, the component files are
+ stored in different files whose URLs are composed using information
+ stored in the #"DIRM"# chunk.
+ \end{itemize}
+ Most of the component files represent pages of a document. Some files
+ however represent data shared by several pages. The pages refer to these
+ supporting files by means of an inclusion chunk (#"INCL"# chunks)
+ identifying the supporting file.
+
+ {\bf Document Directory} --- Every directory record describes a component
+ file. Each component file is identified by a small string named the
+ identifier (ID). Each component file also contains a file name and a
+ title. The format of the #"DIRM"# chunk is described in section
+ \Ref{Format of the DIRM chunk.}.
+
+ Theoretically, IDs are used to uniquely identify each component file in
+ #"INCL"# chunks, names are used to compose the the URLs of the component
+ files in an indirect multipage DjVu file, and titles are cosmetic names
+ possibly displayed when viewing a page of a document. There are however
+ many problems with this scheme, and we {\em strongly suggest}, with the
+ current implementation to always make the file ID, the file name and the
+ file title identical.
+
+ @memo Implements DjVu multipage document directory
+ @author Andrei Erofeev <eaf@geocities.com>
+ @version
+ #$Id: DjVmDir.h,v 1.10 2003/11/07 22:08:20 leonb Exp $# */
+//@{
+
+
+
+#include "GString.h"
+#include "GThreads.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+class ByteStream;
+
+/** Implements DjVu multipage document directory. There are currently two
+ multipage DjVu formats supported: {\em bundled} and {\em indirect}. In
+ the first format all component files composing a given document are
+ packaged (or bundled) into one file, in the second one every page and
+ component is stored in a separate file and there is one more file, which
+ contains the list of all others.
+
+ The multipage document directory lists all component files composing the
+ given document, helps to access every file, identify pages and maintain
+ user-specified shortcuts. Every directory record describes a file
+ composing the document. Each file is identified by a small string named
+ the identifier (ID). Each file may also contain a file name and a title.
+
+ The #DjVmDir# class represents a multipage document directory. Its main
+ purpose is to encode and decode the document directory when writing or
+ reading the #DIRM# chunk. Normally you don't have to create this class
+ yourself. It's done automatically when \Ref{DjVmDoc} class initializes
+ itself. It may be useful though to be able to access records in the
+ directory because some classes (like \Ref{DjVuDocument} and \Ref{DjVmDoc})
+ return a pointer to #DjVmDir# in some cases. */
+
+class DjVmDir : public GPEnabled
+{
+protected:
+ /** Class \Ref{DjVmDir::File} represents the directory records
+ managed by class \Ref{DjVmDir}. */
+ DjVmDir(void) { } ;
+public:
+ class File;
+
+ static const int version;
+
+ /** Class \Ref{DjVmDir::File} represents the directory records
+ managed by class \Ref{DjVmDir}. */
+ static GP<DjVmDir> create(void) {return new DjVmDir; } ;
+
+ /** Decodes the directory from the specified stream. */
+ void decode(const GP<ByteStream> &stream);
+ /** Encodes the directory into the specified stream. */
+ void encode(const GP<ByteStream> &stream, const bool do_rename=false) const;
+ /** Encodes the directory into the specified stream, explicitely as bundled or indirect. */
+ void encode(const GP<ByteStream> &stream, const bool bundled, const bool do_rename) const;
+ /** Tests if directory defines an {\em indirect} document. */
+ bool is_indirect(void) const;
+ /** Tests if the directory defines a {\em bundled} document. */
+ bool is_bundled(void) const;
+ /** Translates page numbers to file records. */
+ GP<File> page_to_file(int page_num) const;
+ /** Translates file names to file records. */
+ GP<File> name_to_file(const GUTF8String & name) const;
+ /** Translates file IDs to file records. */
+ GP<File> id_to_file(const GUTF8String &id) const;
+ /** Translates file shortcuts to file records. */
+ GP<File> title_to_file(const GUTF8String &title) const;
+ /** Returns position of the file in the directory. */
+ int get_file_pos(const File * f) const;
+ /** Returns position of the given page in the directory. */
+ int get_page_pos(int page_num) const;
+ /** Check for duplicate names, and resolve them. */
+ GPList<File> resolve_duplicates(const bool save_as_bundled);
+ /** Returns a copy of the list of file records. */
+ GPList<File> get_files_list(void) const;
+ /** Returns the number of file records. */
+ int get_files_num(void) const;
+ /** Returns the number of file records representing pages. */
+ int get_pages_num(void) const;
+ /** Returns back pointer to the file with #SHARED_ANNO# flag.
+ Note that there may be only one file with shared annotations
+ in any multipage DjVu document. */
+ GP<File> get_shared_anno_file(void) const;
+ /** Changes the title of the file with ID #id#. */
+ void set_file_title(const GUTF8String &id, const GUTF8String &title);
+ /** Changes the name of the file with ID #id#. */
+ void set_file_name(const GUTF8String &id, const GUTF8String &name);
+ /** Inserts the specified file record at the specified position.
+ Specifying #pos# equal to #-1# means to append. The actual position
+ inserted is returned. */
+ int insert_file(const GP<File> & file, int pos=-1);
+ /** Removes a file record with ID #id#. */
+ void delete_file(const GUTF8String &id);
+private:
+ GCriticalSection class_lock;
+ GPList<File> files_list;
+ GPArray<File> page2file;
+ GPMap<GUTF8String, File> name2file;
+ GPMap<GUTF8String, File> id2file;
+ GPMap<GUTF8String, File> title2file;
+private: //dummy stuff
+ static void decode(ByteStream *);
+ static void encode(ByteStream *);
+};
+
+class DjVmDir::File : public GPEnabled
+{
+public:
+ // Out of the record: INCLUDE below must be zero and PAGE must be one.
+ // This is to avoid problems with the File constructor, which now takes
+ // 'int file_type' as the last argument instead of 'bool is_page'
+
+ /** File type. Possible file types are:
+ \begin{description}
+ \item[PAGE] This is a top level page file. It may include other
+ #INCLUDE#d files, which may in turn be shared between
+ different pages.
+ \item[INCLUDE] This file is included into some other file inside
+ this document.
+ \item[THUMBNAILS] This file contains thumbnails for the document
+ pages.
+ \item[SHARED_ANNO] This file contains annotations shared by
+ all the pages. It's supposed to be included into every page
+ for the annotations to take effect. There may be only one
+ file with shared annotations in a document.
+ \end{description} */
+ enum FILE_TYPE { INCLUDE=0, PAGE=1, THUMBNAILS=2, SHARED_ANNO=3 };
+protected:
+ /** Default constructor. */
+ File(void);
+
+public:
+ static GP<File> create(void) { return new File(); }
+ static GP<File> create(const GUTF8String &load_name,
+ const GUTF8String &save_name, const GUTF8String &title,
+ const FILE_TYPE file_type);
+
+ /** Check for filenames that are not valid for the native encoding,
+ and change them. */
+ const GUTF8String &check_save_name(const bool as_bundled);
+
+ /** File name. The optional file name must be unique and is the name
+ that will be used when the document is saved to an indirect file.
+ If not assigned, the value of #id# will be used for this purpose.
+ By keeping the name in {\em bundled} document we guarantee, that it
+ can be expanded later into {\em indirect} document and files will
+ still have the same names, if the name is legal on a given filesystem.
+ */
+ const GUTF8String &get_save_name(void) const;
+
+ /** File identifier. The encoder assigns a unique identifier to each file
+ in a multipage document. This is the name used when loading files.
+ Indirection chunks in other files (#"INCL"# chunks) may refer to another
+ file using its identifier. */
+ const GUTF8String &get_load_name(void) const;
+ void set_load_name(const GUTF8String &id);
+
+ /** File title. The file title is assigned by the user and may be used as
+ a shortcut for viewing a particular page. Names like #"chapter1"# or
+ #"appendix"# are appropriate. */
+ const GUTF8String &get_title() const;
+ void set_title(const GUTF8String &id);
+
+ /** Reports an ascii string indicating file type. */
+ GUTF8String get_str_type(void) const;
+
+ /** Offset of the file data in a bundled DJVM file. This number is
+ relevant in the {\em bundled} case only when everything is packed into
+ one single file. */
+ int offset;
+
+ /** Size of the file data in a bundled DJVM file. This number is
+ relevant in the {\em bundled} case only when everything is
+ packed into one single file. */
+ int size;
+
+ /** Have we checked the saved file name, to see if it is valid on the
+ local disk? */
+ bool valid_name;
+
+ /** Tests if this file represents a page of the document. */
+ bool is_page(void) const
+ {
+ return (flags & TYPE_MASK)==PAGE;
+ }
+
+ /** Returns #TRUE# if this file is included into some other files of
+ this document. */
+ bool is_include(void) const
+ {
+ return (flags & TYPE_MASK)==INCLUDE;
+ }
+
+ /** Returns #TRUE# if this file contains thumbnails for the document pages. */
+ bool is_thumbnails(void) const
+ {
+ return (flags & TYPE_MASK)==THUMBNAILS;
+ }
+
+ /** Returns the page number of this file. This function returns
+ #-1# if this file does not represent a page of the document. */
+ bool is_shared_anno(void) const
+ { return (flags & TYPE_MASK)==SHARED_ANNO; }
+
+ int get_page_num(void) const
+ { return page_num; }
+protected:
+ GUTF8String name;
+ GUTF8String oldname;
+ GUTF8String id;
+ GUTF8String title;
+ void set_save_name(const GUTF8String &name);
+private:
+ friend class DjVmDir;
+ enum FLAGS_0 { IS_PAGE_0=1, HAS_NAME_0=2, HAS_TITLE_0=4 };
+ enum FLAGS_1 { HAS_NAME=0x80, HAS_TITLE=0x40, TYPE_MASK=0x3f };
+ unsigned char flags;
+ int page_num;
+};
+
+inline const GUTF8String &
+DjVmDir::File::get_load_name(void) const
+{ return id; }
+
+inline const GUTF8String &
+DjVmDir::File::get_title() const
+{ return *(title.length()?&title:&id); }
+
+inline void
+DjVmDir::File::set_title(const GUTF8String &xtitle) { title=xtitle; }
+
+/** @name Format of the DIRM chunk.
+
+ {\bf Variants} --- There are two versions of the #"DIRM"# chunk format.
+ The version number is identified by the seven low bits of the first byte
+ of the chunk. Version {\bf 0} is obsolete and should never be used. This
+ section describes version {\bf 1}. There are two major multipage DjVu
+ formats supported: {\em bundled} and {\em indirect}. The #"DIRM"# chunk
+ indicates which format is used in the most significant bit of the first
+ byte of the chunk. The document is bundled when this bit is set.
+ Otherwise the document is indirect.
+
+ {\bf Unencoded data} --- The #"DIRM"# chunk is composed some unencoded
+ data followed by \Ref{bzz} encoded data. The unencoded data starts with
+ the version byte and a 16 bit integer representing the number of component
+ files. All integers are encoded with the most significant byte first.
+ \begin{verbatim}
+ BYTE: Flags/Version: 0x<bundled>0000011
+ INT16: Number of component files.
+ \end{verbatim}
+ When the document is a bundled document (i.e. the flag #bundled# is set),
+ this header is followed by the offsets of each of the component files within
+ the #"FORM:DJVM"#. These offsets allow for random component file access.
+ \begin{verbatim}
+ INT32: Offset of first component file.
+ INT32: Offset of second component file.
+ ...
+ INT32: Offset of last component file.
+ \end{verbatim}
+
+ {\bf BZZ encoded data} --- The rest of the chunk is entirely compressed
+ with the BZZ general purpose compressor. We describe now the data fed
+ into (or retrieved from) the BZZ codec (cf. \Ref{BSByteStream}.) First
+ come the sizes and the flags associated with each component file.
+ \begin{verbatim}
+ INT24: Size of the first component file.
+ INT24: Size of the second component file.
+ ...
+ INT24: Size of the last component file.
+ BYTE: Flag byte for the first component file.
+ BYTE: Flag byte for the second component file.
+ ...
+ BYTE: Flag byte for the last component file.
+ \end{verbatim}
+ The flag bytes have the following format:
+ \begin{verbatim}
+ 0b<hasname><hastitle>000000 for a file included by other files.
+ 0b<hasname><hastitle>000001 for a file representing a page.
+ 0b<hasname><hastitle>000010 for a file containing thumbnails.
+ \end{verbatim}
+ Flag #hasname# is set when the name of the file is different from the file
+ ID. Flag #hastitle# is set when the title of the file is different from
+ the file ID. These flags are used to avoid encoding the same string three
+ times. Then come a sequence of zero terminated strings. There are one to
+ three such strings per component file. The first string contains the ID
+ of the component file. The second string contains the name of the
+ component file. It is only present when the flag #hasname# is set. The third
+ one contains the title of the component file. It is only present when the
+ flag #hastitle# is set. The \Ref{bzz} encoding system makes sure that
+ all these strings will be encoded efficiently despite their possible
+ redundancies.
+ \begin{verbatim}
+ ZSTR: ID of the first component file.
+ ZSTR: Name of the first component file (only if #hasname# is set.)
+ ZSTR: Title of the first component file (only if #hastitle# is set.)
+ ...
+ ZSTR: ID of the last component file.
+ ZSTR: Name of the last component file (only if #hasname# is set.)
+ ZSTR: Title of the last component file (only if #hastitle# is set.)
+ \end{verbatim}
+
+ @memo Description of the format of the DIRM chunk. */
+//@}
+
+
+
+// -------------- IMPLEMENTATION
+
+
+inline bool
+DjVmDir::is_bundled(void) const
+{
+ return ! is_indirect();
+}
+
+inline bool
+DjVmDir::is_indirect(void) const
+{
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+ return ( files_list.size() && files_list[files_list] != 0 &&
+ files_list[files_list]->offset==0 );
+}
+
+
+
+// ----- THE END
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVmDir0.cpp b/kviewshell/plugins/djvu/libdjvu/DjVmDir0.cpp
new file mode 100644
index 00000000..62694098
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVmDir0.cpp
@@ -0,0 +1,169 @@
+//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: DjVmDir0.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 "DjVmDir0.h"
+#include "ByteStream.h"
+#include "debug.h"
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+int
+DjVmDir0::get_size(void) const
+ // WARNING! make sure, that get_size(), encode() and decode() are in sync
+{
+ int size=0;
+
+ size+=2; // number of files
+ for(int i=0;i<num2file.size();i++)
+ {
+ FileRec & file=*num2file[i];
+ size+=file.name.length()+1; // file name
+ size+=1; // is IFF file
+ size+=4; // file offset
+ size+=4; // file size
+ };
+
+ return size;
+}
+
+#ifndef NEED_DECODER_ONLY
+void
+DjVmDir0::encode(ByteStream & bs)
+ // WARNING! make sure, that get_size(), encode() and decode() are in sync
+{
+ bs.write16(num2file.size());
+ for(int i=0;i<num2file.size();i++)
+ {
+ FileRec & file=*num2file[i];
+ bs.writestring(file.name);
+ bs.write8(0);
+ bs.write8(file.iff_file);
+ bs.write32(file.offset);
+ bs.write32(file.size);
+ }
+}
+#endif
+
+void
+DjVmDir0::decode(ByteStream & bs)
+ // WARNING! make sure, that get_size(), encode() and decode() are in sync
+{
+ name2file.empty();
+ num2file.empty();
+
+ for(int i=bs.read16();i>0;i--)
+ {
+ GUTF8String name;
+ char ch;
+ while(bs.read(&ch, 1) && ch) name+=ch;
+ bool iff_file=bs.read8()?true:false;
+ int offset=bs.read32();
+ int size=bs.read32();
+ add_file(name, iff_file, offset, size);
+ };
+}
+
+GP<DjVmDir0::FileRec>
+DjVmDir0::get_file(const GUTF8String &name)
+{
+ if (name2file.contains(name))
+ return name2file[name];
+ return 0;
+}
+
+GP<DjVmDir0::FileRec>
+DjVmDir0::get_file(int file_num)
+{
+ if (file_num<num2file.size()) return num2file[file_num];
+ return 0;
+}
+
+void
+DjVmDir0::add_file(
+ const GUTF8String &name, bool iff_file, int offset, int size)
+{
+ DEBUG_MSG("DjVmDir0::add_file(): name='" << name << "', iff=" << iff_file <<
+ ", offset=" << offset << "\n");
+
+ if (name.search('/') >= 0)
+ G_THROW( ERR_MSG("DjVmDir0.no_slash") );
+
+ GP<FileRec> file=new FileRec(name, iff_file, offset, size);
+ name2file[name]=file;
+ num2file.resize(num2file.size());
+ num2file[num2file.size()-1]=file;
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVmDir0.h b/kviewshell/plugins/djvu/libdjvu/DjVmDir0.h
new file mode 100644
index 00000000..c17c795e
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVmDir0.h
@@ -0,0 +1,217 @@
+//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: DjVmDir0.h,v 1.8 2003/11/07 22:08:20 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _DJVMDIR0_H
+#define _DJVMDIR0_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+#include "GString.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+class ByteStream;
+
+/** @name DjVmDir0.h
+
+ Files #"DjVmDir0.h"# and #"DjVmDir0.cpp"# contain implementation of
+ \Ref{DjVmDir0} class responsible for reading and writing the directory
+ of a multipage all-in-one-file DjVu document (usually referred to as
+ {\bf DjVm} document.
+
+ This is {\bf not} a navigation directory, which lists all the pages
+ in a multipage document. The navigation directory is supported by class
+ \Ref{DjVuNavDir}. This is the directory of a DjVm archive.
+
+
+ @memo Directory of DjVu all-in-one-file DjVu documents.
+ @author Andrei Erofeev <eaf@geocities.com>
+ @version #$Id: DjVmDir0.h,v 1.8 2003/11/07 22:08:20 leonb Exp $# */
+
+//@{
+
+/** Directory of all-in-one-file DjVu documents (also known as DjVm documents).
+ This class can read and write the directory (table of contents, in other
+ words) of a DjVm document. This table of contents lists all {\bf files}
+ included into the document, not {\bf pages} like \Ref{DjVuNavDir} does.
+ It is normally stored in the document inside {\bf DIR0} chunk where
+ {\bf "0"} refers to the version number.
+
+ An object of this class can be created either as a result of the decoding
+ of an existing DjVm file, or manually by calling the default constructor
+ and adding later directory entries by means of \Ref{add_file}() function.
+
+ You normally will not want to create or decode this directory manually.
+ \Ref{DjVmFile} class will do it for you. */
+class DjVmDir0 : public GPEnabled
+{
+public:
+ /** Describes a file record inside a DjVm document (archive) */
+ class FileRec;
+private:
+ GMap<GUTF8String, GP<FileRec> > name2file;
+ GPArray<FileRec> num2file;
+protected:
+ /// Default constructor
+ DjVmDir0(void) {};
+public:
+ /// Copy constructor
+ DjVmDir0(const DjVmDir0 & d);
+
+ static GP<DjVmDir0> create(void) {return new DjVmDir0;}
+
+ virtual ~DjVmDir0(void) {};
+
+ /// Returns the number of files in the DjVm archive
+ int get_files_num(void) const;
+
+ /// Returns the file record with name #name#
+ GP<FileRec> get_file(const GUTF8String &name);
+
+ /// Returns the file record number #file_num#
+ GP<FileRec> get_file(int file_num);
+
+ /** Creates a new file record with name #name# at offset
+ #offset# and size #size#, which is in IFF format if
+ #iff_file# is #TRUE#. */
+ void add_file(const GUTF8String &name, bool iff_file,
+ int offset=-1, int size=-1);
+
+ /// Returns the size of the directory if it were encoded in #DIR0# chunk
+ int get_size(void) const;
+
+ /** Encodes the directory in #DIR0# chunk into the specified
+ \Ref{ByteStream} */
+ void encode(ByteStream & bs);
+
+ /** Decodes the directory from #DIR0# chunk from the specified
+ \Ref{ByteStream} */
+ void decode(ByteStream & bs);
+
+};
+
+ /** Describes a file record inside a DjVm document (archive) */
+class DjVmDir0::FileRec : public GPEnabled
+{
+public:
+ /// Name of the file.
+ GUTF8String name;
+ /// 1 if the file is in IFF format.
+ bool iff_file;
+ /// Offset of the file in the archive.
+ int offset;
+ /// Size of the file
+ int size;
+
+ friend int operator==(const FileRec & f1, const FileRec & f2);
+
+ /// Constructs the #FileRec# object
+ FileRec(const GUTF8String &name, bool iff_file,
+ int offset=-1, int size=-1);
+ /// Default constructor
+ FileRec(void);
+ virtual ~FileRec(void);
+};
+
+inline
+DjVmDir0::FileRec::FileRec(
+ const GUTF8String &name_in, bool iff_file_in, int offset_in, int size_in)
+: name(name_in), iff_file(iff_file_in), offset(offset_in), size(size_in)
+{
+}
+
+inline
+DjVmDir0::FileRec::FileRec(void) : iff_file(0), offset(-1), size(-1)
+{
+}
+
+inline
+DjVmDir0::FileRec::~FileRec(void)
+{
+}
+
+inline int
+DjVmDir0::get_files_num(void) const
+{
+ return num2file.size();
+}
+
+inline
+DjVmDir0::DjVmDir0(const DjVmDir0 & d) :
+ name2file(d.name2file), num2file(d.num2file)
+{
+}
+
+//@}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVmDoc.cpp b/kviewshell/plugins/djvu/libdjvu/DjVmDoc.cpp
new file mode 100644
index 00000000..5b851d6e
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVmDoc.cpp
@@ -0,0 +1,663 @@
+//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: DjVmDoc.cpp,v 1.10 2005/05/25 20:24:52 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "DjVmDoc.h"
+#include "DjVmNav.h"
+#include "DataPool.h"
+#include "IFFByteStream.h"
+#include "GOS.h"
+#include "debug.h"
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+static const char octets[4]={0x41,0x54,0x26,0x54};
+
+// Save the file to disk, remapping INCL chunks while saving.
+static void
+save_file(
+ IFFByteStream &iff_in, IFFByteStream &iff_out, const DjVmDir &dir,
+ GMap<GUTF8String,GUTF8String> &incl)
+{
+ GUTF8String chkid;
+ if (iff_in.get_chunk(chkid))
+ {
+ iff_out.put_chunk(chkid,true);
+ if(!chkid.cmp("FORM:",5))
+ {
+ for(;iff_in.get_chunk(chkid);iff_in.close_chunk())
+ {
+ iff_out.put_chunk(chkid);
+ if(chkid == "INCL")
+ {
+ GUTF8String incl_str;
+ char buffer[1024];
+ int length;
+ while((length=iff_in.read(buffer, 1024)))
+ incl_str+=GUTF8String(buffer, length);
+ // Eat '\n' in the beginning and at the end
+ while(incl_str.length() && incl_str[0]=='\n')
+ {
+ incl_str=incl_str.substr(1,(unsigned int)(-1));
+ }
+ while(incl_str.length()>0 && incl_str[(int)incl_str.length()-1]=='\n')
+ {
+ incl_str.setat(incl_str.length()-1, 0);
+ }
+ GPosition pos=incl.contains(incl_str);
+ if(pos)
+ {
+ iff_out.get_bytestream()->writestring(incl[pos]);
+ }else
+ {
+ GP<DjVmDir::File> incl_file=dir.id_to_file(incl_str);
+ if(incl_file)
+ {
+ DEBUG_MSG("INCL '"<<(const char *)incl_file->get_save_name()<<"'\n");
+ const GUTF8String incl_name=incl_file->get_save_name();
+ incl[incl_str]=incl_name;
+ iff_out.get_bytestream()->writestring(incl_name);
+ }else
+ {
+ DEBUG_MSG("BOGUS INCL '"<<(const char *)incl_str<<"'\n");
+ iff_out.copy(*iff_in.get_bytestream());
+ }
+ }
+ }else
+ {
+ iff_out.copy(*iff_in.get_bytestream());
+ }
+ iff_out.close_chunk();
+ }
+ }else
+ {
+ iff_out.copy(*iff_in.get_bytestream());
+ }
+ iff_out.close_chunk();
+ iff_in.close_chunk();
+ }
+}
+
+DjVmDoc::DjVmDoc(void)
+{
+ DEBUG_MSG("DjVmDoc::DjVmDoc(): Constructing empty DjVm document.\n");
+ DEBUG_MAKE_INDENT(3);
+}
+
+void
+DjVmDoc::init(void)
+{
+ dir=DjVmDir::create();
+}
+
+GP<DjVmDoc>
+DjVmDoc::create(void)
+{
+ DjVmDoc *doc=new DjVmDoc();
+ GP<DjVmDoc> retval=doc;
+ doc->init();
+ return retval;
+}
+
+void
+DjVmDoc::insert_file(const GP<DjVmDir::File> & f,
+ GP<DataPool> data_pool, int pos)
+{
+ DEBUG_MSG("DjVmDoc::insert_file(): inserting file '" << f->get_load_name() <<
+ "' at pos " << pos << "\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (!f)
+ G_THROW( ERR_MSG("DjVmDoc.no_zero_file") );
+ if (data.contains(f->get_load_name()))
+ G_THROW( ERR_MSG("DjVmDoc.no_duplicate") );
+
+ char buffer[4];
+ if (data_pool->get_data(buffer, 0, 4)==4 && !memcmp(buffer, octets, 4))
+ {
+ data_pool=DataPool::create(data_pool, 4, -1);
+ }
+ data[f->get_load_name()]=data_pool;
+ dir->insert_file(f, pos);
+}
+
+void
+DjVmDoc::insert_file(
+ ByteStream &data, DjVmDir::File::FILE_TYPE file_type,
+ const GUTF8String &name, const GUTF8String &id, const GUTF8String &title,
+ int pos)
+{
+ const GP<DjVmDir::File> file(
+ DjVmDir::File::create(name, id, title, file_type));
+ const GP<DataPool> pool(DataPool::create());
+ // Cannot connect to a bytestream.
+ // Must copy data into the datapool.
+ int nbytes;
+ char buffer[1024];
+ while ((nbytes = data.read(buffer, sizeof(buffer))))
+ pool->add_data(buffer, nbytes);
+ pool->set_eof();
+ // Call low level insert
+ insert_file(file, pool, pos);
+}
+
+void
+DjVmDoc::insert_file(
+ const GP<DataPool> &pool, DjVmDir::File::FILE_TYPE file_type,
+ const GUTF8String &name, const GUTF8String &id, const GUTF8String &title,
+ int pos)
+{
+ const GP<DjVmDir::File> file(
+ DjVmDir::File::create(name, id, title, file_type));
+ // Call low level insert
+ insert_file(file, pool, pos);
+}
+
+void
+DjVmDoc::delete_file(const GUTF8String &id)
+{
+ DEBUG_MSG("DjVmDoc::delete_file(): deleting file '" << id << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (!data.contains(id))
+ G_THROW(GUTF8String( ERR_MSG("DjVmDoc.cant_delete") "\t") + id);
+
+ data.del(id);
+ dir->delete_file(id);
+}
+
+void
+DjVmDoc::set_djvm_nav(GP<DjVmNav> n)
+{
+ if (n && ! n->isValidBookmark())
+ G_THROW("Invalid bookmark data");
+ nav = n;
+}
+
+GP<DataPool>
+DjVmDoc::get_data(const GUTF8String &id) const
+{
+ GPosition pos;
+ if (!data.contains(id, pos))
+ G_THROW(GUTF8String( ERR_MSG("DjVmDoc.cant_find") "\t") + id);
+ const GP<DataPool> pool(data[pos]);
+ // First check that the file is in IFF format
+ G_TRY
+ {
+ const GP<ByteStream> str_in(pool->get_stream());
+ const GP<IFFByteStream> giff_in=IFFByteStream::create(str_in);
+ IFFByteStream &iff_in=*giff_in;
+ GUTF8String chkid;
+ int size=iff_in.get_chunk(chkid);
+ if (size<0 || size>0x7fffffff)
+ G_THROW( ERR_MSG("DjVmDoc.not_IFF") "\t" + id);
+ }
+ G_CATCH_ALL
+ {
+ G_THROW( ERR_MSG("DjVmDoc.not_IFF") "\t" + id);
+ }
+ G_ENDCATCH;
+ return pool;
+}
+
+void
+DjVmDoc::write(const GP<ByteStream> &gstr)
+{
+ const GMap<GUTF8String,void *> reserved;
+ write(gstr,reserved);
+}
+
+static inline GUTF8String
+get_name(const DjVmDir::File &file)
+{
+ const GUTF8String save_name(file.get_save_name());
+ return save_name.length()?save_name:(file.get_load_name());
+}
+
+void
+DjVmDoc::write(const GP<ByteStream> &gstr,
+ const GMap<GUTF8String,void *> &reserved)
+{
+ DEBUG_MSG("DjVmDoc::write(): Storing document into the byte stream.\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GPList<DjVmDir::File> files_list=dir->resolve_duplicates(true);
+ bool do_rename=false;
+ GPosition pos(reserved);
+
+ GMap<GUTF8String,GUTF8String> incl;
+ DEBUG_MSG("pass 1: looking for reserved names.");
+ if(pos)
+ {
+ // Check if there are any conflicting file names.
+ for(pos=files_list;pos;++pos)
+ {
+ GP<DjVmDir::File> file=files_list[pos];
+ if((do_rename=(reserved.contains(file->get_load_name())?true:false))
+ ||(do_rename=(reserved.contains(file->get_save_name())?true:false)))
+ {
+ break;
+ }
+ }
+ // If there are conflicting file names, check if the save names
+ // are OK. If not, generate new save names.
+ if(do_rename)
+ {
+ DEBUG_MSG("pass 1: renaming reserved names.");
+ for(;;files_list=dir->resolve_duplicates(true))
+ {
+ GMap<GUTF8String,void *> this_doc;
+ for(pos=files_list;pos;++pos)
+ {
+ GP<DjVmDir::File> file=files_list[pos];
+ this_doc[::get_name(*file)]=0;
+ }
+ bool need_new_list=false;
+ for(pos=files_list;pos;++pos)
+ {
+ GP<DjVmDir::File> file=files_list[pos];
+ const GUTF8String name(::get_name(*file));
+ if(reserved.contains(name))
+ {
+ GUTF8String new_name;
+ int series=0;
+ do
+ {
+ int dot=name.rsearch('.');
+ if(dot>0)
+ {
+ new_name=name.substr(0,dot)+
+ "_"+GUTF8String(++series)+name.substr(dot,-1);
+ }else
+ {
+ new_name=name+"_"+GUTF8String(++series);
+ }
+ } while(reserved.contains(new_name)||this_doc.contains(new_name));
+ dir->set_file_name(file->get_load_name(),new_name);
+ need_new_list=true;
+ }
+ }
+ if(!need_new_list)
+ break;
+ }
+ }
+ }
+
+ DEBUG_MSG("pass 2: create dummy DIRM chunk and calculate offsets...\n");
+ for(pos=files_list;pos;++pos)
+ {
+ GP<DjVmDir::File> file=files_list[pos];
+ file->offset=0xffffffff;
+ GPosition data_pos=data.contains(file->get_load_name());
+ if (!data_pos)
+ G_THROW( ERR_MSG("DjVmDoc.no_data") "\t" + file->get_load_name());
+ if(do_rename)
+ {
+ GP<ByteStream> gout(ByteStream::create());
+ {
+ const GP<IFFByteStream> giff_in(
+ IFFByteStream::create(data[data_pos]->get_stream()));
+ const GP<IFFByteStream> giff_out(IFFByteStream::create(gout));
+ ::save_file(*giff_in,*giff_out,*dir,incl);
+ }
+ gout->seek(0L);
+ data[data_pos]=DataPool::create(gout);
+ }
+ file->size=data[data_pos]->get_length();
+ if (!file->size)
+ G_THROW( ERR_MSG("DjVmDoc.zero_file") );
+ }
+
+ const GP<ByteStream> tmp_str(ByteStream::create());
+ const GP<IFFByteStream> gtmp_iff(IFFByteStream::create(tmp_str));
+ IFFByteStream &tmp_iff=*gtmp_iff;
+ tmp_iff.put_chunk("FORM:DJVM", 1);
+ tmp_iff.put_chunk("DIRM");
+ dir->encode(tmp_iff.get_bytestream(),do_rename);
+ tmp_iff.close_chunk();
+ if (nav)
+ {
+ tmp_iff.put_chunk("NAVM");
+ nav->encode(tmp_iff.get_bytestream());
+ tmp_iff.close_chunk();
+ }
+ tmp_iff.close_chunk();
+ int offset=tmp_iff.tell();
+
+ for(pos=files_list;pos;++pos)
+ {
+ if ((offset & 1)!=0)
+ offset++;
+
+ GP<DjVmDir::File> & file=files_list[pos];
+ file->offset=offset;
+ offset+=file->size; // file->size has been set in the first pass
+ }
+
+ DEBUG_MSG("pass 3: store the file contents.\n");
+
+ GP<IFFByteStream> giff=IFFByteStream::create(gstr);
+ IFFByteStream &iff=*giff;
+ iff.put_chunk("FORM:DJVM", 1);
+ iff.put_chunk("DIRM");
+ dir->encode(iff.get_bytestream(),do_rename);
+ iff.close_chunk();
+ if (nav)
+ {
+ iff.put_chunk("NAVM");
+ nav->encode(iff.get_bytestream());
+ iff.close_chunk();
+ }
+
+ for(pos=files_list;pos;++pos)
+ {
+ GP<DjVmDir::File> & file=files_list[pos];
+
+ const GP<DataPool> pool=get_data(file->get_load_name());
+ const GP<ByteStream> str_in(pool->get_stream());
+ if ((iff.tell() & 1)!=0)
+ {
+ iff.get_bytestream()->write8(0);
+ }
+ iff.copy(*str_in);
+ }
+
+ iff.close_chunk();
+ iff.flush();
+
+ DEBUG_MSG("done storing DjVm file.\n");
+}
+
+void
+DjVmDoc::read(const GP<DataPool> & pool)
+{
+ DEBUG_MSG("DjVmDoc::read(): reading the BUNDLED doc contents from the pool\n");
+ DEBUG_MAKE_INDENT(3);
+
+ const GP<ByteStream> str(pool->get_stream());
+
+ GP<IFFByteStream> giff=IFFByteStream::create(str);
+ IFFByteStream &iff=*giff;
+ GUTF8String chkid;
+ iff.get_chunk(chkid);
+ if (chkid!="FORM:DJVM")
+ G_THROW( ERR_MSG("DjVmDoc.no_form_djvm") );
+
+ iff.get_chunk(chkid);
+ if (chkid!="DIRM")
+ G_THROW( ERR_MSG("DjVmDoc.no_dirm_chunk") );
+ dir->decode(iff.get_bytestream());
+ iff.close_chunk();
+
+ data.empty();
+
+ if (dir->is_indirect())
+ G_THROW( ERR_MSG("DjVmDoc.cant_read_indr") );
+
+ GPList<DjVmDir::File> files_list=dir->get_files_list();
+ for(GPosition pos=files_list;pos;++pos)
+ {
+ DjVmDir::File * f=files_list[pos];
+
+ DEBUG_MSG("reading contents of file '" << f->get_load_name() << "'\n");
+ data[f->get_load_name()]=DataPool::create(pool, f->offset, f->size);
+ }
+}
+
+void
+DjVmDoc::read(ByteStream & str_in)
+{
+ DEBUG_MSG("DjVmDoc::read(): reading the BUNDLED doc contents from the stream\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GP<DataPool> pool=DataPool::create();
+ char buffer[1024];
+ int length;
+ while((length=str_in.read(buffer, 1024)))
+ pool->add_data(buffer, length);
+ pool->set_eof();
+
+ read(pool);
+}
+
+void
+DjVmDoc::read(const GURL &url)
+{
+ DEBUG_MSG("DjVmDoc::read(): reading the doc contents from the HDD\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GP<DataPool> pool=DataPool::create(url);
+ const GP<ByteStream> str(pool->get_stream());
+ GP<IFFByteStream> giff=IFFByteStream::create(str);
+ IFFByteStream &iff=*giff;
+ GUTF8String chkid;
+ iff.get_chunk(chkid);
+ if (chkid!="FORM:DJVM")
+ G_THROW( ERR_MSG("DjVmDoc.no_form_djvm2") );
+
+ iff.get_chunk(chkid);
+ if (chkid!="DIRM")
+ G_THROW( ERR_MSG("DjVmDoc.no_dirm_chunk") );
+ dir->decode(iff.get_bytestream());
+ iff.close_chunk();
+
+ if (dir->is_bundled())
+ read(pool);
+ else
+ {
+// GUTF8String full_name=GOS::expand_name(name);
+// GUTF8String dir_name=GOS::dirname(GOS::url_to_filename(url.base()));
+ GURL dirbase=url.base();
+
+ data.empty();
+
+ GPList<DjVmDir::File> files_list=dir->get_files_list();
+ for(GPosition pos=files_list;pos;++pos)
+ {
+ DjVmDir::File * f=files_list[pos];
+
+ DEBUG_MSG("reading contents of file '" << f->get_load_name() << "'\n");
+
+ const GURL::UTF8 url(f->get_load_name(),dirbase);
+ data[f->get_load_name()]=DataPool::create(url);
+ }
+ }
+}
+
+void
+DjVmDoc::write_index(const GP<ByteStream> &str)
+{
+ DEBUG_MSG("DjVmDoc::write_index(): Storing DjVm index file\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GPList<DjVmDir::File> files_list=dir->get_files_list();
+ for(GPosition pos=files_list;pos;++pos)
+ {
+ GP<DjVmDir::File> file=files_list[pos];
+ file->offset=0;
+
+ GPosition data_pos=data.contains(file->get_load_name());
+ if (!data_pos)
+ G_THROW( ERR_MSG("DjVmDoc.no_data") "\t" + file->get_load_name());
+ file->size=data[data_pos]->get_length();
+ if (!file->size)
+ G_THROW( ERR_MSG("DjVmDoc.zero_file") );
+ }
+
+ GP<IFFByteStream> giff=IFFByteStream::create(str);
+ IFFByteStream &iff=*giff;
+ iff.put_chunk("FORM:DJVM", 1);
+ iff.put_chunk("DIRM");
+ dir->encode(iff.get_bytestream());
+ iff.close_chunk();
+ if (nav)
+ {
+ iff.put_chunk("NAVM");
+ nav->encode(iff.get_bytestream());
+ iff.close_chunk();
+ }
+ iff.close_chunk();
+ iff.flush();
+}
+
+void
+DjVmDoc::save_page(
+ const GURL &codebase, const DjVmDir::File &file) const
+{
+ GMap<GUTF8String,GUTF8String> incl;
+ save_file(codebase,file,&incl);
+}
+
+void
+DjVmDoc::save_page(
+ const GURL &codebase, const DjVmDir::File &file,
+ GMap<GUTF8String,GUTF8String> &incl ) const
+{
+ save_file(codebase,file,&incl);
+}
+
+void
+DjVmDoc::save_file(
+ const GURL &codebase, const DjVmDir::File &file) const
+{
+ save_file(codebase,file,0);
+}
+
+GUTF8String
+DjVmDoc::save_file(const GURL &codebase, const DjVmDir::File &file,
+ GMap<GUTF8String,GUTF8String> &incl, const GP<DataPool> &pool) const
+{
+ const GUTF8String save_name(file.get_save_name());
+ const GURL::UTF8 new_url(save_name,codebase);
+ DEBUG_MSG("storing file '"<<new_url<<"'\n");
+ DataPool::load_file(new_url);
+ const GP<ByteStream> str_in(pool->get_stream());
+ const GP<ByteStream> str_out(ByteStream::create(new_url, "wb"));
+ ::save_file( *IFFByteStream::create(str_in),
+ *IFFByteStream::create(str_out), *dir, incl);
+ return save_name;
+}
+
+void
+DjVmDoc::save_file(
+ const GURL &codebase, const DjVmDir::File &file,
+ GMap<GUTF8String,GUTF8String> *incl) const
+{
+ const GUTF8String load_name=file.get_load_name();
+ if(!incl || !incl->contains(load_name))
+ {
+ GMap<GUTF8String,GUTF8String> new_incl;
+ const GUTF8String save_name(
+ save_file(codebase,file,new_incl,get_data(load_name)));
+
+ if(incl)
+ {
+ (*incl)[load_name]=save_name;
+ for(GPosition pos=new_incl;pos;++pos)
+ {
+ save_file(codebase,file,incl);
+ }
+ }
+ }
+}
+
+void
+DjVmDoc::expand(const GURL &codebase, const GUTF8String &idx_name)
+{
+ DEBUG_MSG("DjVmDoc::expand(): Expanding into '" << codebase << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ // Resolve any name conflicts
+ // Find the list of all files.
+ GPList<DjVmDir::File> files_list=dir->resolve_duplicates(false);
+
+ // store each file
+ for(GPosition pos=files_list;pos;++pos)
+ {
+ save_file(codebase,*files_list[pos]);
+ }
+
+ if (idx_name.length())
+ {
+ const GURL::UTF8 idx_url(idx_name, codebase);
+
+ DEBUG_MSG("storing index file '" << idx_url << "'\n");
+
+ DataPool::load_file(idx_url);
+ GP<ByteStream> str=ByteStream::create(idx_url, "wb");
+ write_index(str);
+ }
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVmDoc.h b/kviewshell/plugins/djvu/libdjvu/DjVmDoc.h
new file mode 100644
index 00000000..637d0b78
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVmDoc.h
@@ -0,0 +1,274 @@
+//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: DjVmDoc.h,v 1.10 2005/05/25 20:24:52 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _DJVMDOC_H
+#define _DJVMDOC_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+#include "DjVmDir.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+class ByteStream;
+class DataPool;
+class GURL;
+class GUTF8String;
+class DjVmNav;
+
+/** @name DjVmDoc.h
+ Files #"DjVmDoc.h"# and #"DjVmDoc.cpp"# contain implementation of the
+ \Ref{DjVmDoc} class used to read and write new DjVu multipage documents.
+
+ @memo DjVu multipage documents reader/writer.
+ @author Andrei Erofeev <eaf@geocities.com>
+ @version #$Id: DjVmDoc.h,v 1.10 2005/05/25 20:24:52 leonb Exp $#
+*/
+
+//@{
+
+/** Read/Write DjVu multipage documents.
+
+ The "new" DjVu multipage documents can be of two types: {\em bundled} and
+ {\em indirect}. In the first case all pages are packed into one file,
+ which is very like an archive internally. In the second case every page
+ is stored in a separate file. Plus there can be other components,
+ included into one or more pages, which also go into separate files. In
+ addition to pages and components, in the case of the {\em indirect} format
+ there is one more top-level file with the document directory (see
+ \Ref{DjVmDir}), which is basically an index file containing the
+ list of all files composing the document.
+
+ This class can read documents of both formats and can save them under any
+ format. It is therefore ideal for converting between {\em bundled} and
+ {\em indirect} formats. It cannot be used however for reading obsolete
+ formats. The best way to convert obsolete formats consists in reading
+ them with class \Ref{DjVuDocument} class and saving them using
+ \Ref{DjVuDocument::write} or \Ref{DjVuDocument::expand}.
+
+ This class can also be used to create and modify multipage documents at
+ the low level without decoding every page or component (See
+ \Ref{insert_file}() and \Ref{delete_file}()).
+*/
+
+class DjVmDoc : public GPEnabled
+{
+ // Internal function.
+protected:
+ DjVmDoc(void);
+ void init(void);
+public:
+ /// Creator
+ static GP<DjVmDoc> create(void);
+ /** Inserts a file into the document.
+ @param data ByteStream containing the file data.
+ @param file_type Describes the type of the file to be inserted.
+ See \Ref{DjVmDir::File} for details.
+ @param name Name of the file in the document (e.g. an URL).
+ @param id Identifier of the file (as used in INCL chunks).
+ @param title Optional title of the file (shown in browsers).
+ @param pos Position of the file in the document (default is append).
+ */
+ void insert_file(
+ ByteStream &data, DjVmDir::File::FILE_TYPE file_type,
+ const GUTF8String &name, const GUTF8String &id,
+ const GUTF8String &title=GUTF8String(), int pos=-1 );
+ /** Inserts a file into the document.
+ @param pool Data pool containing file data.
+ @param file_type Describes the type of the file to be inserted.
+ See \Ref{DjVmDir::File} for details.
+ @param name Name of the file in the document (e.g. an URL).
+ @param id Identifier of the file (as used in INCL chunks).
+ @param title Optional title of the file (shown in browsers).
+ @param pos Position of the file in the document (default is append).
+ */
+ void insert_file(
+ const GP<DataPool> &pool, DjVmDir::File::FILE_TYPE file_type,
+ const GUTF8String &name, const GUTF8String &id,
+ const GUTF8String &title=GUTF8String(), int pos=-1 );
+
+ /** Inserts a file described by \Ref{DjVmDir::File} structure with
+ data #data# at position #pos#. If #pos# is negative, the file
+ will be appended to the document. Otherwise it will be inserted
+ at position #pos#. */
+ void insert_file(const GP<DjVmDir::File> & f,
+ GP<DataPool> data, int pos=-1);
+
+ /** Removes file with the specified #id# from the document. Every
+ file inside a new DjVu multipage document has its unique ID
+ (refer to \Ref{DjVmDir} for details), which is passed to this
+ function. */
+ void delete_file(const GUTF8String &id);
+
+ /** Set the bookmarks */
+ void set_djvm_nav(GP<DjVmNav> n);
+
+ /** Returns the directory of the DjVm document (the one which will
+ be encoded into #DJVM# chunk of the top-level file or the bundle). */
+ GP<DjVmDir> get_djvm_dir(void);
+
+ /** Returns contents of file with ID #id# from the document.
+ Please refer to \Ref{DjVmDir} for the explanation of what
+ IDs mean. */
+ GP<DataPool> get_data(const GUTF8String &id) const;
+
+ /** Reading routines */
+ //@{
+ /** Reads contents of a {\em bundled} multipage DjVu document from
+ the stream. */
+ void read(ByteStream & str);
+ /** Reads contents of a {\em bundled} multipage DjVu document from
+ the \Ref{DataPool}. */
+ void read(const GP<DataPool> & data_pool);
+ /** Reads the DjVu multipage document in either {\em bundled} or
+ {\em indirect} format.
+
+ {\bf Note:} For {\em bundled} documents the file is not
+ read into memory. We just open it and access data directly there.
+ Thus you should not modify the file contents.
+
+ @param name For {\em bundled} documents this is the name
+ of the document. For {\em indirect} documents this is
+ the name of the top-level file of the document (containing
+ the \Ref{DjVmDir} with the list of all files).
+ The rest of the files are expected to be in the
+ same directory and will be read by this function as well. */
+ void read(const GURL &url);
+ //@}
+
+ /** Writing routines */
+ //@{
+ /** Writes the multipage DjVu document in the {\em bundled} format into
+ the stream. */
+ void write(const GP<ByteStream> &str);
+ /** Writes the multipage DjVu document in the {\em bundled} format into
+ the stream, reserving any of the specified names. */
+ void write(const GP<ByteStream> &str,
+ const GMap<GUTF8String,void *>& reserved);
+ /** Stored index (top-level) file of the DjVu document in the {\em
+ indirect} format into the specified stream. */
+ void write_index(const GP<ByteStream> &str);
+ /** Writes the multipage DjVu document in the {\em indirect} format
+ into the given directory. Every page and included file will be
+ stored as a separate file. Besides, one top-level file with
+ the document directory (named #idx_name#) will be created unless
+ #idx_name# is empty.
+
+ @param dir_name Name of the directory where files should be
+ created
+ @param idx_name Name of the top-level file with the \Ref{DjVmDir}
+ with the list of files composing the given document.
+ If empty, the file will not be created. */
+ void expand(const GURL &codebase, const GUTF8String &idx_name);
+
+ /** Writes an individual file, and all included files.
+ INCL chunks will be remapped as appropriate. */
+ void save_page(const GURL &codebase, const DjVmDir::File &file) const;
+
+ /** Writes an individual file if not mapped, and all included files.
+ INCL chunks will be remapped as appropriate. All pages saved
+ are added to the #incl# map. */
+ void save_page(const GURL &codebase, const DjVmDir::File &file,
+ GMap<GUTF8String,GUTF8String> &incl) const;
+
+ /** Writes an individual file specified, remapping INCL chunks as
+ appropriate. Included files will not be saved. */
+ void save_file(const GURL &codebase, const DjVmDir::File &file) const;
+
+ /** Writes the specified file from the given #pool#. */
+ GUTF8String save_file(const GURL &codebase, const DjVmDir::File &file,
+ GMap<GUTF8String,GUTF8String> &incl,
+ const GP<DataPool> &pool) const;
+ //@}
+private:
+ void save_file(const GURL &codebase, const DjVmDir::File &file,
+ GMap<GUTF8String,GUTF8String> *incl) const;
+ GP<DjVmDir> dir;
+ GP<DjVmNav> nav;
+ GPMap<GUTF8String, DataPool > data;
+private: // dummy stuff
+ static void write(ByteStream *);
+ static void write_index(ByteStream *);
+};
+
+inline GP<DjVmDir>
+DjVmDoc::get_djvm_dir(void)
+{
+ return dir;
+}
+
+
+//@}
+
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVmNav.cpp b/kviewshell/plugins/djvu/libdjvu/DjVmNav.cpp
new file mode 100644
index 00000000..9e8b5fd7
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVmNav.cpp
@@ -0,0 +1,338 @@
+//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: DjVmNav.cpp,v 1.1 2005/05/25 17:36:53 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include <ctype.h>
+
+#include "DjVuDocument.h"
+#include "DjVmNav.h"
+#include "BSByteStream.h"
+#include "GURL.h"
+#include "debug.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+GP<DjVmNav::DjVuBookMark>
+DjVmNav::DjVuBookMark::create(void)
+{
+ return new DjVuBookMark();
+}
+
+GP<DjVmNav::DjVuBookMark>
+DjVmNav::DjVuBookMark::create(const unsigned short count,
+ const GUTF8String &displayname,
+ const GUTF8String &url)
+{
+ DjVuBookMark *pvm=new DjVuBookMark();
+ GP<DjVuBookMark> bookmark=pvm;
+ pvm->count=count;
+ pvm->displayname=displayname;
+ pvm->url=url;
+ return bookmark;
+}
+
+DjVmNav::DjVuBookMark::DjVuBookMark(void)
+ : count(0), displayname(), url()
+{
+}
+
+GP<DjVmNav>
+DjVmNav::create(void)
+{
+ return new DjVmNav;
+}
+
+// Decode the input bytestream and populate this object
+void
+DjVmNav::DjVuBookMark::decode(const GP<ByteStream> &gstr)
+{
+ int textsize=0, readsize=0;
+ char *buffer=0;
+ ByteStream &bs=*gstr;
+ count = bs.read8();
+ displayname.empty();
+#ifdef DJVMNAV_WITH_256LIMIT
+ textsize = bs.read24();
+#else
+ int counthi = bs.read8();
+ count = (counthi<<8)+ count;
+ textsize = bs.read16();
+#endif
+ if (textsize)
+ {
+ buffer = displayname.getbuf(textsize);
+ readsize = bs.read(buffer,textsize);
+ buffer[readsize] = 0;
+ }
+ url.empty();
+ textsize = bs.read24();
+ if (textsize)
+ {
+ buffer = url.getbuf(textsize);
+ readsize = bs.read(buffer,textsize);
+ buffer[readsize] = 0;
+ }
+}
+
+// Serialize this object to the output bytestream
+void
+DjVmNav::DjVuBookMark::encode(const GP<ByteStream> &gstr)
+{
+ int textsize=0;
+ ByteStream &bs=*gstr;
+#ifdef DJVMNAV_WITH_256LIMIT
+ if (count>255)
+ G_THROW("Excessive number of children in bookmark tree");
+ bs.write8(count);
+ textsize = displayname.length();
+ bs.write24( textsize );
+#else
+ if (count>65535)
+ G_THROW("Excessive number of children in bookmark tree");
+ bs.write8( count & 0xff );
+ bs.write8( (count>>8) & 0xff );
+ textsize = displayname.length();
+ bs.write16( textsize );
+#endif
+ bs.writestring(displayname);
+ textsize = url.length();
+ bs.write24( textsize );
+ bs.writestring(url);
+}
+
+// Text dump of this object to the output bytestream
+void
+DjVmNav::DjVuBookMark::dump(const GP<ByteStream> &gstr)
+{
+ int textsize=0;
+ ByteStream &bs=*gstr;
+ bs.format("\n count=%d\n",count);
+ textsize = displayname.length();
+ bs.format(" (%d) %s\n",textsize, displayname.getbuf());
+ textsize = url.length();
+ bs.format(" (%d) %s\n",textsize, url.getbuf());
+}
+
+// Decode the input bytestream and populate this object
+void
+DjVmNav::decode(const GP<ByteStream> &gstr)
+{
+ //ByteStream &str=*gstr;
+ GP<ByteStream> gpBSByteStream = BSByteStream::create(gstr);
+ GCriticalSectionLock lock(&class_lock);
+ bookmark_list.empty();
+ int nbookmarks=gpBSByteStream->read16();
+ if (nbookmarks)
+ {
+ for(int bookmark=0;bookmark<nbookmarks;bookmark++)
+ {
+ GP<DjVuBookMark> pBookMark=DjVuBookMark::create();
+ pBookMark->decode(gpBSByteStream);
+ bookmark_list.append(pBookMark);
+ }
+ }
+}
+
+// Serialize this object to the output stream
+void
+DjVmNav::encode(const GP<ByteStream> &gstr)
+{
+ //ByteStream &str=*gstr;
+ GP<ByteStream> gpBSByteStream = BSByteStream::create(gstr, 1024);
+ GCriticalSectionLock lock(&class_lock);
+ int nbookmarks=bookmark_list.size();
+ gpBSByteStream->write16(nbookmarks);
+ if (nbookmarks)
+ {
+ GPosition pos;
+ int cnt=0;
+ for (pos = bookmark_list; pos; ++pos)
+ {
+ bookmark_list[pos]->encode(gpBSByteStream);
+ cnt++;
+ }
+ if (nbookmarks != cnt)
+ {
+ GUTF8String msg;
+ msg.format("Corrupt bookmarks found during encode: %d of %d \n",
+ cnt, nbookmarks);
+ G_THROW (msg);
+ }
+ }
+}
+
+int
+DjVmNav::getBookMarkCount()
+{
+ return(bookmark_list.size());
+}
+
+void
+DjVmNav::append (const GP<DjVuBookMark> &gpBookMark)
+{
+ bookmark_list.append(gpBookMark);
+}
+
+bool
+DjVmNav::getBookMark(GP<DjVuBookMark> &gpBookMark, int iPos)
+{
+ GPosition pos = bookmark_list.nth(iPos);
+ if (pos)
+ gpBookMark = bookmark_list[pos];
+ else
+ gpBookMark = 0;
+ return (gpBookMark?true:false);
+}
+
+
+// A text dump of this object
+void
+DjVmNav::dump(const GP<ByteStream> &gstr)
+{
+ ByteStream &str=*gstr;
+ GCriticalSectionLock lock(&class_lock);
+ int nbookmarks=bookmark_list.size();
+ str.format("%d bookmarks:\n",nbookmarks);
+ if (nbookmarks)
+ {
+ GPosition pos;
+ int cnt=0;
+ for (pos = bookmark_list; pos; ++pos)
+ {
+ bookmark_list[pos]->dump(&str);
+ cnt++;
+ }
+ if (nbookmarks != cnt)
+ {
+ GUTF8String msg;
+ msg.format("Corrupt bookmarks found during encode: %d of %d \n",
+ cnt,nbookmarks);
+ G_THROW (msg);
+ }
+ }
+}
+
+bool
+DjVmNav::isValidBookmark()
+{
+ //test if the bookmark is properly given
+ //for example: (4, "A", urla)
+ // (0, "B", urlb)
+ // (0, "C", urlc)
+ //is not a bookmark since A suppose to have 4 decendents, it only get one.
+ int bookmark_totalnum=getBookMarkCount();
+ GP<DjVuBookMark> gpBookMark;
+ int* count_array=(int*)malloc(sizeof(int)*bookmark_totalnum);
+ for(int i=0;i<bookmark_totalnum;i++)
+ {
+ getBookMark(gpBookMark, i);
+ count_array[i]=gpBookMark->count;
+ }
+ int index=0;
+ int trees=0;
+ int* treeSizes=(int*)malloc(sizeof(int)*bookmark_totalnum);
+ while(index<bookmark_totalnum)
+ {
+ int treeSize=get_tree(index,count_array,bookmark_totalnum);
+ if(treeSize>0) //is a tree
+ {
+ index+=treeSize;
+ treeSizes[trees++]=treeSize;
+ }
+ else //not a tree
+ break;
+ }
+ free(count_array);
+ free(treeSizes);
+ return true;
+}
+
+int
+DjVmNav::get_tree(int index, int* count_array, int count_array_size)
+{
+ int i=index;
+ int accumulate_count=0;
+ while(i<count_array_size)
+ {
+ accumulate_count+=count_array[i];
+ if(accumulate_count==0)
+ return 1;
+ else if(accumulate_count == i-index) //get a tree
+ return accumulate_count;
+ i++;
+ }
+ return 0;
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVmNav.h b/kviewshell/plugins/djvu/libdjvu/DjVmNav.h
new file mode 100644
index 00000000..46c5d57f
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVmNav.h
@@ -0,0 +1,146 @@
+//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: DjVmNav.h,v 1.1 2005/05/25 17:36:53 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _DJVMNAV_H
+#define _DJVMNAV_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+#include "DjVuGlobal.h"
+#include "GString.h"
+#include "GThreads.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+class ByteStream;
+
+/** The NAVM chunk.
+ The optional #"NAVM"# chunk which follows the DIRM chunk describes
+ how the user can navigate the document.
+ This is a list of DjVuBookMarks.
+**/
+
+class DjVmNav : public GPEnabled
+{
+public:
+ /** Class \Ref{DjVmNav::DjVuBookMark} represents a entry in the
+ hierarchy of contents. */
+ class DjVuBookMark;
+
+ static GP<DjVmNav> create(void);
+ /** Decodes the directory from the specified stream. */
+ void decode(const GP<ByteStream> &stream);
+ /** Encodes the directory into the specified stream. */
+ void encode(const GP<ByteStream> &stream) ;
+ void dump(const GP<ByteStream> &stream) ;
+ /** Return bookmark at zero-based position i */
+ bool getBookMark(GP<DjVuBookMark> &gpBookMark, int i) ;
+ int getBookMarkCount();
+ /** Append the BookMark to the end of the list */
+ void append (const GP<DjVuBookMark> &gpBookMark) ;
+ /** This function will check the given bookmark is valid or not */
+ bool isValidBookmark();
+ /** This function determines if the given count_array is a tree
+ sequence, that is if it fits a tree. */
+ int get_tree(int index, int* count_array, int count_array_size);
+protected:
+ DjVmNav(void) { } ;
+private:
+ GCriticalSection class_lock;
+ GPList<DjVuBookMark> bookmark_list;
+};
+
+/** The DjVuBookMark.
+ Each entry in the Navigation chunk (NAVM) is a bookmark. A bookmark
+ contains a count of immediate children, a display string and a url.
+**/
+
+class DjVmNav::DjVuBookMark : public GPEnabled
+{
+protected:
+ /** Default constructor. */
+ DjVuBookMark(void);
+public:
+ static GP<DjVuBookMark> create(void);
+ static GP<DjVuBookMark> create(const unsigned short count,
+ const GUTF8String &displayname,
+ const GUTF8String &url);
+ void encode(const GP<ByteStream> &stream);
+ void dump(const GP<ByteStream> &stream);
+ void decode(const GP<ByteStream> &stream);
+ int count; // count of immediate children.
+ GUTF8String displayname; // example: "Section 3.5 - Encryption"
+ GUTF8String url; // url, may be blank or relative.
+};
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuAnno.cpp b/kviewshell/plugins/djvu/libdjvu/DjVuAnno.cpp
new file mode 100644
index 00000000..a6772e61
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuAnno.cpp
@@ -0,0 +1,1514 @@
+//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: DjVuAnno.cpp,v 1.12 2004/04/17 23:56:11 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "DjVuAnno.h"
+#include "GContainer.h"
+#include "GException.h"
+#include "IFFByteStream.h"
+#include "BSByteStream.h"
+#include "GMapAreas.h"
+
+#include "debug.h"
+
+#include <ctype.h>
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+// GLParser.h and GLParser.cpp used to be separate files capable to decode
+// that weird ANTa chunk format into C++ structures and lists. But since
+// its implementation is temporary and is used only in this file (DjVuAnno.cpp)
+// it appears reasonable to build it in here.
+
+//***************************************************************************
+//****************************** GLParser.h *********************************
+//***************************************************************************
+
+
+class GLObject : public GPEnabled
+{
+public:
+ enum GLObjectType { INVALID=0, NUMBER=1, STRING=2, SYMBOL=3, LIST=4 };
+ static const char * const GLObjectString[LIST+1];
+
+ GLObject(int _number=0);
+ GLObject(GLObjectType type, const char * str);
+ GLObject(const char * name, const GPList<GLObject> & list);
+ virtual ~GLObject(void);
+
+ int get_number(void) const;
+ GUTF8String get_string(void) const;
+ GUTF8String get_symbol(void) const;
+ GPList<GLObject> & get_list(void);
+ GP<GLObject> operator[](int n) const;
+
+ GLObjectType get_type(void) const;
+ GUTF8String get_name(void) const;
+ void print(ByteStream & str, int compact=1, int indent=0, int * cur_pos=0) const;
+private:
+ GLObjectType type;
+ GUTF8String name;
+
+ int number;
+ GUTF8String string;
+ GUTF8String symbol;
+ GPList<GLObject> list;
+ void throw_can_not_convert_to(const GLObjectType to) const;
+};
+
+const char * const GLObject::GLObjectString[]=
+ {"invalid", "number", "string", "symbol", "list"};
+
+inline GLObject::GLObjectType
+GLObject::get_type(void) const { return type; }
+
+inline
+GLObject::~GLObject(void) {}
+
+class GLToken
+{
+public:
+ enum GLTokenType { OPEN_PAR, CLOSE_PAR, OBJECT };
+ GLTokenType type;
+ GP<GLObject> object;
+
+ GLToken(GLTokenType type, const GP<GLObject> & object);
+};
+
+inline
+GLToken::GLToken(GLTokenType xtype, const GP<GLObject> & xobject) :
+ type(xtype), object(xobject) {}
+
+class GLParser
+{
+public:
+ void parse(const char * str);
+ GPList<GLObject> & get_list(void);
+ GP<GLObject> get_object(const char * name, bool last=true);
+ void print(ByteStream & str, int compact=1);
+
+ GLParser(void);
+ GLParser(const char * str);
+ ~GLParser(void);
+private:
+ GPList<GLObject> list;
+
+ bool compat;
+ void skip_white_space(const char * & start);
+ void check_compat(const char *str);
+ GLToken get_token(const char * & start);
+ void parse(const char * cur_name, GPList<GLObject> & list,
+ const char * & start);
+};
+
+GLParser::GLParser(void)
+ : compat(false)
+{
+}
+
+GLParser::~GLParser(void)
+{
+}
+
+GPList<GLObject> &
+GLParser::get_list(void)
+{
+ return list;
+}
+
+GLParser::GLParser(const char * str)
+ : compat(false)
+{
+ parse(str);
+}
+
+
+//***************************************************************************
+//***************************** GLParser.cpp ********************************
+//***************************************************************************
+
+
+GLObject::GLObject(int xnumber) : type(NUMBER), number(xnumber) {}
+
+GLObject::GLObject(GLObjectType xtype, const char * str) : type(xtype)
+{
+ if (type!=STRING && type!=SYMBOL)
+ G_THROW( ERR_MSG("DjVuAnno.bad_type") );
+ if (type==STRING)
+ string=str;
+ else symbol=str;
+}
+
+GLObject::GLObject(const char * xname, const GPList<GLObject> & xlist) :
+ type(LIST), name(xname), list(xlist) {}
+
+void
+GLObject::print(ByteStream & str, int compact, int indent, int * cur_pos) const
+{
+ int local_cur_pos = 0;
+ if (!cur_pos) { cur_pos = &local_cur_pos; }
+
+ GUTF8String buffer;
+ const char * to_print=0;
+ switch(type)
+ {
+ case NUMBER:
+ to_print=buffer.format("%d",number);
+ break;
+ case STRING:
+ {
+ int length = string.length();
+ const char *data = (const char*)string;
+ buffer = GUTF8String("\"");
+ while (*data && length>0)
+ {
+ int span = 0;
+ while (span<length && (unsigned char)(data[span])>=0x20 &&
+ data[span]!=0x7f && data[span]!='"' && data[span]!='\\' )
+ span++;
+ if (span > 0)
+ {
+ buffer = buffer + GUTF8String(data, span);
+ data += span;
+ length -= span;
+ }
+ else
+ {
+ char buf[8];
+ static char *tr1 = "\"\\tnrbf";
+ static char *tr2 = "\"\\\t\n\r\b\f";
+ sprintf(buf,"\\%03o", (int)(((unsigned char*)data)[span]));
+ for (int i=0; tr2[i]; i++)
+ if (data[span] == tr2[i])
+ buf[1] = tr1[i];
+ if (buf[1]<'0' || buf[1]>'3')
+ buf[2] = 0;
+ buffer = buffer + GUTF8String(buf);
+ data += 1;
+ length -= 1;
+ }
+ }
+ buffer = buffer + GUTF8String("\"");
+ to_print = buffer;
+ }
+ break;
+ case SYMBOL:
+ to_print=buffer.format("%s",(const char *)symbol);
+ break;
+ case LIST:
+ to_print=buffer.format("(%s",(const char *)name);
+ break;
+ case INVALID:
+ break;
+ }
+ if (!compact && *cur_pos+strlen(to_print)>70)
+ {
+ char ch='\n';
+ str.write(&ch, 1);
+ ch=' ';
+ for(int i=0;i<indent;i++) str.write(&ch, 1);
+ *cur_pos=indent;
+ }
+ str.write(to_print, strlen(to_print));
+ char ch=' ';
+ str.write(&ch, 1);
+ *cur_pos+=strlen(to_print)+1;
+ if (type==LIST)
+ {
+ int indent=*cur_pos-strlen(to_print);
+ for(GPosition pos=list;pos;++pos)
+ list[pos]->print(str, compact, indent, cur_pos);
+ str.write(") ", 2);
+ *cur_pos+=2;
+ }
+}
+
+// This function constructs message names for external lookup.
+// The message names are constructed to avoid the problems of concatenating
+// phrases (which does not translate well into other languages). The
+// message names that can be generated are (listed here to appease the
+// auditing program which reads comments):
+// ERR_MSG("DjVuAnno.invalid2number"), ERR_MSG("DjVuAnno.string2number"),
+// ERR_MSG("DjVuAnno.symbol2number"), ERR_MSG("DjVuAnno.list2number")
+// ERR_MSG("DjVuAnno.invalid2string"), ERR_MSG("DjVuAnno.number2string"),
+// ERR_MSG("DjVuAnno.symbol2string"), ERR_MSG("DjVuAnno.list2string")
+// ERR_MSG("DjVuAnno.invalid2symbol"), ERR_MSG("DjVuAnno.number2symbol"),
+// ERR_MSG("DjVuAnno.string2symbol"), ERR_MSG("DjVuAnno.list2symbol")
+// ERR_MSG("DjVuAnno.invalid2list"), ERR_MSG("DjVuAnno.number2list"),
+// ERR_MSG("DjVuAnno.string2list"), ERR_MSG("DjVuAnno.symbol2list")
+void
+GLObject::throw_can_not_convert_to(const GLObjectType to) const
+{
+ static const GUTF8String two('2');
+ static const GUTF8String tab('\t');
+ GUTF8String mesg("DjVuAnno.");
+ switch(type)
+ {
+ case NUMBER:
+ mesg+=GLObjectString[NUMBER]+two+GLObjectString[to]+tab+GUTF8String(number);
+ break;
+ case STRING:
+ mesg+=GLObjectString[STRING]+two+GLObjectString[to]+tab+string;
+ break;
+ case SYMBOL:
+ mesg+=GLObjectString[SYMBOL]+two+GLObjectString[to]+tab+symbol;
+ break;
+ case LIST:
+ mesg+=GLObjectString[LIST]+two+GLObjectString[to]+tab+name;
+ break;
+ default:
+ mesg+=GLObjectString[INVALID]+two+GLObjectString[to];
+ break;
+ }
+ G_THROW(mesg);
+}
+
+GUTF8String
+GLObject::get_string(void) const
+{
+ if (type!=STRING)
+ {
+ throw_can_not_convert_to(STRING);
+ }
+ return string;
+}
+
+GUTF8String
+GLObject::get_symbol(void) const
+{
+ if (type!=SYMBOL)
+ {
+ throw_can_not_convert_to(SYMBOL);
+ }
+ return symbol;
+}
+
+int
+GLObject::get_number(void) const
+{
+ if (type!=NUMBER)
+ {
+ throw_can_not_convert_to(NUMBER);
+ }
+ return number;
+}
+
+GUTF8String
+GLObject::get_name(void) const
+{
+ if (type!=LIST)
+ {
+ throw_can_not_convert_to(LIST);
+ }
+ return name;
+}
+
+GP<GLObject>
+GLObject::operator[](int n) const
+{
+ if (type!=LIST)
+ {
+ throw_can_not_convert_to(LIST);
+ }
+ if (n>=list.size()) G_THROW( ERR_MSG("DjVuAnno.too_few") "\t"+name);
+ int i;
+ GPosition pos;
+ for(i=0, pos=list;i<n && pos;i++, ++pos)
+ continue;
+ return list[pos];
+}
+
+GPList<GLObject> &
+GLObject::get_list(void)
+{
+ if (type!=LIST)
+ {
+ throw_can_not_convert_to(LIST);
+ }
+ return list;
+}
+
+//********************************** GLParser *********************************
+
+void
+GLParser::skip_white_space(const char * & start)
+{
+ while(*start && isspace(*start)) start++;
+ if (!*start)
+ G_THROW( ByteStream::EndOfFile );
+}
+
+GLToken
+GLParser::get_token(const char * & start)
+{
+ skip_white_space(start);
+ char c = *start;
+ if (c == '(')
+ {
+ start++;
+ return GLToken(GLToken::OPEN_PAR, 0);
+ }
+ else if (c == ')')
+ {
+ start++;
+ return GLToken(GLToken::CLOSE_PAR, 0);
+ }
+ else if (c=='-' || (c>='0' && c<='9'))
+ {
+ return GLToken(GLToken::OBJECT,
+ new GLObject(strtol(start, (char **) &start, 10)));
+ }
+ else if (c=='"')
+ {
+ GUTF8String str;
+ start++;
+ while(1)
+ {
+ int span = 0;
+ while (start[span] && start[span]!='\\' && start[span]!='\"')
+ span++;
+ if (span > 0)
+ {
+ str = str + GUTF8String(start,span);
+ start += span;
+ }
+ else if (start[0]=='\"')
+ {
+ start += 1;
+ break;
+ }
+ else if (start[0]=='\\' && compat)
+ {
+ char c = start[1];
+ if (c == '\"')
+ {
+ start += 2;
+ str += '\"';
+ }
+ else
+ {
+ start += 1;
+ str += '\\';
+ }
+ }
+ else if (start[0]=='\\' && start[1])
+ {
+ char c = *++start;
+ if (c>='0' && c<='7')
+ {
+ int x = 0;
+ for (int i=0; i<3 && c>='0' && c<='7'; i++)
+ {
+ x = x * 8 + c - '0';
+ c = *++start;
+ }
+ str += (char)(x & 0xff);
+ }
+ else
+ {
+ static char *tr1 = "tnrbfva";
+ static char *tr2 = "\t\n\r\b\f\013\007";
+ for (int i=0; tr1[i]; i++)
+ if (c == tr1[i])
+ c = tr2[i];
+ start += 1;
+ str += c;
+ }
+ }
+ else
+ {
+ G_THROW( ByteStream::EndOfFile );
+ }
+ }
+ return GLToken(GLToken::OBJECT,
+ new GLObject(GLObject::STRING, str));
+ }
+ else
+ {
+ GUTF8String str;
+ while(1)
+ {
+ char ch=*start++;
+ if (!ch)
+ G_THROW( ByteStream::EndOfFile );
+ if (ch==')') { start--; break; }
+ if (isspace(ch)) break;
+ str+=ch;
+ }
+ return GLToken(GLToken::OBJECT, new GLObject(GLObject::SYMBOL, str));
+ }
+}
+
+void
+GLParser::parse(const char * cur_name, GPList<GLObject> & list,
+ const char * & start)
+{
+ DEBUG_MSG("GLParse::parse(): Parsing contents of object '" << cur_name << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ while(1)
+ {
+ GLToken token=get_token(start);
+ if (token.type==GLToken::OPEN_PAR)
+ {
+ if (isspace(*start))
+ {
+ GUTF8String mesg=GUTF8String( ERR_MSG("DjVuAnno.paren") "\t")+cur_name;
+ G_THROW(mesg);
+ }
+
+ GLToken tok=get_token(start);
+ GP<GLObject> object=tok.object; // This object should be SYMBOL
+ // We will convert it to LIST later
+ if (tok.type!=GLToken::OBJECT || object->get_type()!=GLObject::SYMBOL)
+ {
+ if (tok.type==GLToken::OPEN_PAR ||
+ tok.type==GLToken::CLOSE_PAR)
+ {
+ GUTF8String mesg=GUTF8String( ERR_MSG("DjVuAnno.no_paren") "\t")+cur_name;
+ G_THROW(mesg);
+ }
+ if (tok.type==GLToken::OBJECT)
+ {
+ GLObject::GLObjectType type=object->get_type();
+ if (type==GLObject::NUMBER)
+ {
+ GUTF8String mesg( ERR_MSG("DjVuAnno.no_number") "\t");
+ mesg += cur_name;
+ G_THROW(mesg);
+ }
+ else if (type==GLObject::STRING)
+ {
+ GUTF8String mesg( ERR_MSG("DjVuAnno.no_string") "\t");
+ mesg += cur_name;
+ G_THROW(mesg);
+ }
+ }
+ }
+
+ // OK. Get the object contents
+ GPList<GLObject> new_list;
+ G_TRY
+ {
+ parse(object->get_symbol(), new_list, start);
+ }
+ G_CATCH(exc)
+ {
+ if (exc.cmp_cause(ByteStream::EndOfFile))
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+ list.append(new GLObject(object->get_symbol(), new_list));
+ continue;
+ }
+ if (token.type==GLToken::CLOSE_PAR)
+ return;
+ list.append(token.object);
+ }
+}
+
+void
+GLParser::check_compat(const char *s)
+{
+ int state = 0;
+ while (s && *s && !compat)
+ {
+ switch(state)
+ {
+ case 0:
+ if (*s == '\"')
+ state = '\"';
+ break;
+ case '\"':
+ if (*s == '\"')
+ state = 0;
+ else if (*s == '\\')
+ state = '\\';
+ else if ((unsigned char)(*s)<0x20 || *s==0x7f)
+ compat = true;
+ break;
+ case '\\':
+ if (!strchr("01234567tnrbfva\"\\",*s))
+ compat = true;
+ state = '\"';
+ break;
+ }
+ s += 1;
+ }
+}
+
+void
+GLParser::parse(const char * str)
+{
+ DEBUG_MSG("GLParser::parse(): parsing string contents\n");
+ DEBUG_MAKE_INDENT(3);
+
+ G_TRY
+ {
+ check_compat(str);
+ parse("toplevel", list, str);
+ } G_CATCH(exc)
+ {
+ if (exc.cmp_cause(ByteStream::EndOfFile))
+ G_RETHROW;
+ } G_ENDCATCH;
+}
+
+void
+GLParser::print(ByteStream & str, int compact)
+{
+ for(GPosition pos=list;pos;++pos)
+ list[pos]->print(str, compact);
+}
+
+GP<GLObject>
+GLParser::get_object(const char * name, bool last)
+{
+ GP<GLObject> object;
+ for(GPosition pos=list;pos;++pos)
+ {
+ GP<GLObject> obj=list[pos];
+ if (obj->get_type()==GLObject::LIST &&
+ obj->get_name()==name)
+ {
+ object=obj;
+ if (!last) break;
+ }
+ }
+ return object;
+}
+
+//***************************************************************************
+//********************************** ANT ************************************
+//***************************************************************************
+
+static const char *zoom_strings[]={
+ "default","page","width","one2one","stretch"};
+static const int zoom_strings_size=sizeof(zoom_strings)/sizeof(const char *);
+
+static const char *mode_strings[]={
+ "default","color","fore","back","bw"};
+static const int mode_strings_size=sizeof(mode_strings)/sizeof(const char *);
+
+static const char *align_strings[]={
+ "default","left","center","right","top","bottom"};
+static const int align_strings_size=sizeof(align_strings)/sizeof(const char *);
+
+#define PNOTE_TAG "pnote"
+#define BACKGROUND_TAG "background"
+#define ZOOM_TAG "zoom"
+#define MODE_TAG "mode"
+#define ALIGN_TAG "align"
+#define HALIGN_TAG "halign"
+#define VALIGN_TAG "valign"
+#define METADATA_TAG "metadata"
+
+static const unsigned long default_bg_color=0xffffffff;
+
+DjVuANT::DjVuANT(void)
+{
+ bg_color=default_bg_color;
+ zoom=0;
+ mode=MODE_UNSPEC;
+ hor_align=ver_align=ALIGN_UNSPEC;
+}
+
+DjVuANT::~DjVuANT()
+{
+}
+
+GUTF8String
+DjVuANT::get_paramtags(void) const
+{
+ GUTF8String retval;
+ if(zoom > 0)
+ {
+ retval+="<PARAM name=\"" ZOOM_TAG "\" value=\""+GUTF8String(zoom)+="\" />\n";
+ }else if(zoom && ((-zoom)<zoom_strings_size))
+ {
+ retval+="<PARAM name=\"" ZOOM_TAG "\" value=\""+GUTF8String(zoom_strings[-zoom])+"\" />\n";
+ }
+ if((mode>0)&&(mode<mode_strings_size))
+ {
+ retval+="<PARAM name=\"" MODE_TAG "\" value=\""+GUTF8String(mode_strings[mode])+"\" />\n";
+ }
+ if((hor_align>ALIGN_UNSPEC)&&(hor_align<align_strings_size))
+ {
+ retval+="<PARAM name=\"" HALIGN_TAG "\" value=\""+GUTF8String(align_strings[hor_align])+"\" />\n";
+ }
+ if((ver_align>ALIGN_UNSPEC)&&(ver_align<align_strings_size))
+ {
+ retval+="<PARAM name=\"" VALIGN_TAG "\" value=\""+GUTF8String(align_strings[ver_align])+"\" />\n";
+ }
+ if((bg_color&0xffffff) == bg_color)
+ {
+ retval+="<PARAM name=\"" BACKGROUND_TAG "\" value=\""+GUTF8String().format("#%06lX",bg_color)+"\" />\n";
+ }
+ return retval;
+}
+
+void
+DjVuANT::writeParam(ByteStream &str_out) const
+{
+ str_out.writestring(get_paramtags());
+}
+
+GUTF8String
+DjVuANT::get_xmlmap(const GUTF8String &name,const int height) const
+{
+ GUTF8String retval("<MAP name=\""+name.toEscaped()+"\" >\n");
+ for(GPosition pos(map_areas);pos;++pos)
+ {
+ retval+=map_areas[pos]->get_xmltag(height);
+ }
+ return retval+"</MAP>\n";
+}
+
+void
+DjVuANT::writeMap(
+ ByteStream &str_out,const GUTF8String &name,const int height) const
+{
+ str_out.writestring("<MAP name=\""+name.toEscaped()+"\" >\n");
+ for(GPosition pos(map_areas);pos;++pos)
+ {
+ str_out.writestring(GUTF8String(map_areas[pos]->get_xmltag(height)));
+ }
+ str_out.writestring(GUTF8String("</MAP>\n"));
+}
+
+GUTF8String
+DjVuANT::read_raw(ByteStream & str)
+{
+ GUTF8String raw;
+ char buffer[1024];
+ int length;
+ while((length=str.read(buffer, 1024)))
+ raw+=GUTF8String(buffer, length);
+ return raw;
+}
+
+void
+DjVuANT::decode(class GLParser & parser)
+{
+ bg_color=get_bg_color(parser);
+ zoom=get_zoom(parser);
+ mode=get_mode(parser);
+ hor_align=get_hor_align(parser);
+ ver_align=get_ver_align(parser);
+ map_areas=get_map_areas(parser);
+#ifndef NO_METADATA_IN_ANT_CHUNK
+ metadata=get_metadata(parser);
+#endif
+}
+
+
+void
+DjVuANT::decode(ByteStream & str)
+{
+ GLParser parser(read_raw(str));
+ decode(parser);
+}
+
+void
+DjVuANT::merge(ByteStream & str)
+{
+ GLParser parser(encode_raw());
+ GUTF8String add_raw=read_raw(str);
+ parser.parse(add_raw);
+ decode(parser);
+}
+
+void
+DjVuANT::encode(ByteStream &bs)
+{
+ GUTF8String raw=encode_raw();
+ bs.writall((const char*) raw, raw.length());
+}
+
+unsigned int
+DjVuANT::get_memory_usage() const
+{
+ return sizeof(DjVuANT);
+}
+
+unsigned char
+DjVuANT::decode_comp(char ch1, char ch2)
+{
+ unsigned char dig1=0;
+ if (ch1)
+ {
+ ch1=toupper(ch1);
+ if (ch1>='0' && ch1<='9') dig1=ch1-'0';
+ if (ch1>='A' && ch1<='F') dig1=10+ch1-'A';
+
+ unsigned char dig2=0;
+ if (ch2)
+ {
+ ch2=toupper(ch2);
+ if (ch2>='0' && ch2<='9') dig2=ch2-'0';
+ if (ch2>='A' && ch2<='F') dig2=10+ch2-'A';
+ return (dig1 << 4) | dig2;
+ }
+ return dig1;
+ }
+ return 0;
+}
+
+unsigned long int
+DjVuANT::cvt_color(const char * color, unsigned long int def)
+{
+ if (color[0]!='#') return def;
+
+ unsigned long int color_rgb=0;
+ color++;
+ const char * start, * end;
+
+ // Do blue
+ end=color+strlen(color); start=end-2;
+ if (start<color) start=color;
+ if (end>start)
+ color_rgb|=decode_comp(start[0], start+1<end ? start[1] : 0);
+
+ // Do green
+ end=color+strlen(color)-2; start=end-2;
+ if (start<color) start=color;
+ if (end>start)
+ color_rgb|=decode_comp(start[0], start+1<end ? start[1] : 0) << 8;
+
+ // Do red
+ end=color+strlen(color)-4; start=end-2;
+ if (start<color) start=color;
+ if (end>start)
+ color_rgb|=decode_comp(start[0], start+1<end ? start[1] : 0) << 16;
+
+ // Do the fourth byte
+ end=color+strlen(color)-6; start=end-2;
+ if (start<color) start=color;
+ if (end>start)
+ color_rgb|=decode_comp(start[0], start+1<end ? start[1] : 0) << 24;
+
+ return color_rgb;
+}
+
+unsigned long int
+DjVuANT::get_bg_color(GLParser & parser)
+{
+ unsigned long retval=default_bg_color;
+ DEBUG_MSG("DjVuANT::get_bg_color(): getting background color ...\n");
+ DEBUG_MAKE_INDENT(3);
+ G_TRY
+ {
+ GP<GLObject> obj=parser.get_object(BACKGROUND_TAG);
+ if (obj && obj->get_list().size()==1)
+ {
+ GUTF8String color=(*obj)[0]->get_symbol();
+ DEBUG_MSG("color='" << color << "'\n");
+ retval=cvt_color(color, 0xffffff);
+ }
+#ifndef NDEBUG
+ if(retval == default_bg_color)
+ {
+ DEBUG_MSG("can't find any.\n");
+ }
+#endif // NDEBUG
+ } G_CATCH_ALL {} G_ENDCATCH;
+#ifndef NDEBUG
+ if(retval == default_bg_color)
+ {
+ DEBUG_MSG("resetting color to 0xffffffff (UNSPEC)\n");
+ }
+#endif // NDEBUG
+ return retval;
+}
+
+int
+DjVuANT::get_zoom(GLParser & parser)
+ // Returns:
+ // <0 - special zoom (like ZOOM_STRETCH)
+ // =0 - not set
+ // >0 - numeric zoom (%%)
+{
+ int retval=ZOOM_UNSPEC;
+ DEBUG_MSG("DjVuANT::get_zoom(): getting zoom factor ...\n");
+ DEBUG_MAKE_INDENT(3);
+ G_TRY
+ {
+ GP<GLObject> obj=parser.get_object(ZOOM_TAG);
+ if (obj && obj->get_list().size()==1)
+ {
+ const GUTF8String zoom((*obj)[0]->get_symbol());
+ DEBUG_MSG("zoom='" << zoom << "'\n");
+
+ for(int i=0;(i<zoom_strings_size);++i)
+ {
+ if(zoom == zoom_strings[i])
+ {
+ retval=(-i);
+ break;
+ }
+ }
+ if(retval == ZOOM_UNSPEC)
+ {
+ if (zoom[0]!='d')
+ {
+ G_THROW( ERR_MSG("DjVuAnno.bad_zoom") );
+ }else
+ {
+ retval=zoom.substr(1, zoom.length()).toInt(); //atoi((const char *) zoom+1);
+ }
+ }
+ }
+#ifndef NDEBUG
+ if(retval == ZOOM_UNSPEC)
+ {
+ DEBUG_MSG("can't find any.\n");
+ }
+#endif // NDEBUG
+ } G_CATCH_ALL {} G_ENDCATCH;
+#ifndef NDEBUG
+ if(retval == ZOOM_UNSPEC)
+ {
+ DEBUG_MSG("resetting zoom to 0 (UNSPEC)\n");
+ }
+#endif // NDEBUG
+ return retval;
+}
+
+int
+DjVuANT::get_mode(GLParser & parser)
+{
+ int retval=MODE_UNSPEC;
+ DEBUG_MSG("DjVuAnt::get_mode(): getting default mode ...\n");
+ DEBUG_MAKE_INDENT(3);
+ G_TRY
+ {
+ GP<GLObject> obj=parser.get_object(MODE_TAG);
+ if (obj && obj->get_list().size()==1)
+ {
+ const GUTF8String mode((*obj)[0]->get_symbol());
+ DEBUG_MSG("mode='" << mode << "'\n");
+ for(int i=0;(i<mode_strings_size);++i)
+ {
+ if(mode == mode_strings[i])
+ {
+ retval=i;
+ break;
+ }
+ }
+ }
+#ifndef NDEBUG
+ if(retval == MODE_UNSPEC)
+ {
+ DEBUG_MSG("can't find any.\n");
+ }
+#endif // NDEBUG
+ } G_CATCH_ALL {} G_ENDCATCH;
+#ifndef NDEBUG
+ if(retval == MODE_UNSPEC)
+ {
+ DEBUG_MSG("resetting mode to MODE_UNSPEC\n");
+ }
+#endif // NDEBUG
+ return retval;
+}
+
+static inline DjVuANT::alignment
+legal_halign(const int i)
+{
+ DjVuANT::alignment retval;
+ switch((DjVuANT::alignment)i)
+ {
+ case DjVuANT::ALIGN_LEFT:
+ case DjVuANT::ALIGN_CENTER:
+ case DjVuANT::ALIGN_RIGHT:
+ retval=(DjVuANT::alignment)i;
+ break;
+ default:
+ retval=DjVuANT::ALIGN_UNSPEC;
+ break;
+ }
+ return retval;
+}
+
+static inline DjVuANT::alignment
+legal_valign(const int i)
+{
+ DjVuANT::alignment retval;
+ switch((DjVuANT::alignment)i)
+ {
+ case DjVuANT::ALIGN_CENTER:
+ case DjVuANT::ALIGN_TOP:
+ case DjVuANT::ALIGN_BOTTOM:
+ retval=(DjVuANT::alignment)i;
+ break;
+ default:
+ retval=DjVuANT::ALIGN_UNSPEC;
+ break;
+ }
+ return retval;
+}
+
+DjVuANT::alignment
+DjVuANT::get_hor_align(GLParser & parser)
+{
+ DEBUG_MSG("DjVuAnt::get_hor_align(): getting hor page alignemnt ...\n");
+ DEBUG_MAKE_INDENT(3);
+ alignment retval=ALIGN_UNSPEC;
+ G_TRY
+ {
+ GP<GLObject> obj=parser.get_object(ALIGN_TAG);
+ if (obj && obj->get_list().size()==2)
+ {
+ const GUTF8String align((*obj)[0]->get_symbol());
+ DEBUG_MSG("hor_align='" << align << "'\n");
+
+ for(int i=(int)ALIGN_UNSPEC;(i<align_strings_size);++i)
+ {
+ const alignment j=legal_halign(i);
+ if((i == (int)j)&&(align == align_strings[i]))
+ {
+ retval=j;
+ break;
+ }
+ }
+ }
+#ifndef NDEBUG
+ if(retval == ALIGN_UNSPEC)
+ {
+ DEBUG_MSG("can't find any.\n");
+ }
+#endif // NDEBUG
+ } G_CATCH_ALL {} G_ENDCATCH;
+#ifndef NDEBUG
+ if(retval == ALIGN_UNSPEC)
+ {
+ DEBUG_MSG("resetting alignment to ALIGN_UNSPEC\n");
+ }
+#endif // NDEBUG
+ return retval;
+}
+
+DjVuANT::alignment
+DjVuANT::get_ver_align(GLParser & parser)
+{
+ DEBUG_MSG("DjVuAnt::get_ver_align(): getting vert page alignemnt ...\n");
+ DEBUG_MAKE_INDENT(3);
+ alignment retval=ALIGN_UNSPEC;
+ G_TRY
+ {
+ GP<GLObject> obj=parser.get_object(ALIGN_TAG);
+ if (obj && obj->get_list().size()==2)
+ {
+ const GUTF8String align((*obj)[1]->get_symbol());
+ DEBUG_MSG("ver_align='" << align << "'\n");
+ for(int i=(int)ALIGN_UNSPEC;(i<align_strings_size);++i)
+ {
+ const alignment j=legal_valign(i);
+ if((i == (int)j)&&(align == align_strings[i]))
+ {
+ retval=j;
+ break;
+ }
+ }
+ }
+#ifndef NDEBUG
+ if(retval == ALIGN_UNSPEC)
+ {
+ DEBUG_MSG("can't find any.\n");
+ }
+#endif // NDEBUG
+ } G_CATCH_ALL {} G_ENDCATCH;
+#ifndef NDEBUG
+ if(retval == ALIGN_UNSPEC)
+ {
+ DEBUG_MSG("resetting alignment to ALIGN_UNSPEC\n");
+ }
+#endif // NDEBUG
+ return retval;
+}
+
+#ifndef NO_METADATA_IN_ANT_CHUNK
+GMap<GUTF8String, GUTF8String>
+DjVuANT::get_metadata(GLParser & parser)
+{
+ DEBUG_MSG("DjVuANT::get_map_areas(): forming and returning back list of map areas\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GMap<GUTF8String, GUTF8String> mdata;
+
+ GPList<GLObject> list=parser.get_list();
+ for(GPosition pos=list;pos;++pos)
+ {
+ GLObject & obj=*list[pos];
+ if (obj.get_type()==GLObject::LIST && obj.get_name()==METADATA_TAG)
+ {
+ G_TRY
+ {
+ for(int obj_num=0;obj_num<obj.get_list().size();obj_num++)
+ {
+ GLObject & el=*obj[obj_num];
+ const int type = el.get_type();
+ if (type == GLObject::LIST)
+ {
+ const GUTF8String & name=el.get_name();
+ mdata[name]=(el[0])->get_string();
+ }
+ }
+ }
+ G_CATCH_ALL { } G_ENDCATCH;
+ }
+ }
+ return mdata;
+}
+#endif
+
+GPList<GMapArea>
+DjVuANT::get_map_areas(GLParser & parser)
+{
+ DEBUG_MSG("DjVuANT::get_map_areas(): forming and returning back list of map areas\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GPList<GMapArea> map_areas;
+
+ GPList<GLObject> list=parser.get_list();
+
+ for(GPosition pos=list;pos;++pos)
+ {
+ GLObject & obj=*list[pos];
+ const int type=obj.get_type();
+ if (type == GLObject::LIST)
+ {
+ const GUTF8String name=obj.get_name();
+ if(name == GMapArea::MAPAREA_TAG)
+ {
+ G_TRY {
+ // Getting the url
+ GUTF8String url;
+ GUTF8String target=GMapArea::TARGET_SELF;
+ GLObject & url_obj=*(obj[0]);
+ if (url_obj.get_type()==GLObject::LIST)
+ {
+ if (url_obj.get_name()!=GMapArea::URL_TAG)
+ G_THROW( ERR_MSG("DjVuAnno.bad_url") );
+ url=(url_obj[0])->get_string();
+ target=(url_obj[1])->get_string();
+ } else url=url_obj.get_string();
+
+ // Getting the comment
+ GUTF8String comment=(obj[1])->get_string();
+
+ DEBUG_MSG("found maparea '" << comment << "' (" <<
+ url << ":" << target << ")\n");
+
+ GLObject * shape=obj[2];
+ GP<GMapArea> map_area;
+ if (shape->get_type()==GLObject::LIST)
+ {
+ if (shape->get_name()==GMapArea::RECT_TAG)
+ {
+ DEBUG_MSG("it's a rectangle.\n");
+ GRect grect((*shape)[0]->get_number(),
+ (*shape)[1]->get_number(),
+ (*shape)[2]->get_number(),
+ (*shape)[3]->get_number());
+ GP<GMapRect> map_rect=GMapRect::create(grect);
+ map_area=(GMapRect *)map_rect;
+ } else if (shape->get_name()==GMapArea::POLY_TAG)
+ {
+ DEBUG_MSG("it's a polygon.\n");
+ int points=shape->get_list().size()/2;
+ GTArray<int> xx(points-1), yy(points-1);
+ for(int i=0;i<points;i++)
+ {
+ xx[i]=(*shape)[2*i]->get_number();
+ yy[i]=(*shape)[2*i+1]->get_number();
+ }
+ GP<GMapPoly> map_poly=GMapPoly::create(xx,yy,points);
+ map_area=(GMapPoly *)map_poly;
+ } else if (shape->get_name()==GMapArea::OVAL_TAG)
+ {
+ DEBUG_MSG("it's an ellipse.\n");
+ GRect grect((*shape)[0]->get_number(),
+ (*shape)[1]->get_number(),
+ (*shape)[2]->get_number(),
+ (*shape)[3]->get_number());
+ GP<GMapOval> map_oval=GMapOval::create(grect);
+ map_area=(GMapOval *)map_oval;
+ }
+ }
+
+ if (map_area)
+ {
+ map_area->url=url;
+ map_area->target=target;
+ map_area->comment=comment;
+ for(int obj_num=3;obj_num<obj.get_list().size();obj_num++)
+ {
+ GLObject * el=obj[obj_num];
+ if (el->get_type()==GLObject::LIST)
+ {
+ const GUTF8String & name=el->get_name();
+ if (name==GMapArea::BORDER_AVIS_TAG)
+ map_area->border_always_visible=true;
+ else if (name==GMapArea::HILITE_TAG)
+ {
+ GLObject * obj=el->get_list()[el->get_list().firstpos()];
+ if (obj->get_type()==GLObject::SYMBOL)
+ map_area->hilite_color=cvt_color(obj->get_symbol(), 0xff);
+ } else
+ {
+ int border_type=
+ name==GMapArea::NO_BORDER_TAG ? GMapArea::NO_BORDER :
+ name==GMapArea::XOR_BORDER_TAG ? GMapArea::XOR_BORDER :
+ name==GMapArea::SOLID_BORDER_TAG ? GMapArea::SOLID_BORDER :
+ name==GMapArea::SHADOW_IN_BORDER_TAG ? GMapArea::SHADOW_IN_BORDER :
+ name==GMapArea::SHADOW_OUT_BORDER_TAG ? GMapArea::SHADOW_OUT_BORDER :
+ name==GMapArea::SHADOW_EIN_BORDER_TAG ? GMapArea::SHADOW_EIN_BORDER :
+ name==GMapArea::SHADOW_EOUT_BORDER_TAG ? GMapArea::SHADOW_EOUT_BORDER : -1;
+ if (border_type>=0)
+ {
+ map_area->border_type=(GMapArea::BorderType) border_type;
+ for(GPosition pos=el->get_list();pos;++pos)
+ {
+ GLObject * obj=el->get_list()[pos];
+ if (obj->get_type()==GLObject::SYMBOL)
+ map_area->border_color=cvt_color(obj->get_symbol(), 0xff);
+ if (obj->get_type()==GLObject::NUMBER)
+ map_area->border_width=obj->get_number();
+ }
+ }
+ }
+ } // if (el->get_type()==...)
+ } // for(int obj_num=...)
+ map_areas.append(map_area);
+ } // if (map_area) ...
+ } G_CATCH_ALL {} G_ENDCATCH;
+ }
+ }
+ } // while(item==...)
+
+ DEBUG_MSG("map area list size = " << list.size() << "\n");
+
+ return map_areas;
+}
+
+void
+DjVuANT::del_all_items(const char * name, GLParser & parser)
+{
+ GPList<GLObject> & list=parser.get_list();
+ GPosition pos=list;
+ while(pos)
+ {
+ GLObject & obj=*list[pos];
+ if (obj.get_type()==GLObject::LIST &&
+ obj.get_name()==name)
+ {
+ GPosition this_pos=pos;
+ ++pos;
+ list.del(this_pos);
+ } else ++pos;
+ }
+}
+
+GUTF8String
+DjVuANT::encode_raw(void) const
+{
+ GUTF8String buffer;
+ GLParser parser;
+
+ //*** Background color
+ del_all_items(BACKGROUND_TAG, parser);
+ if (bg_color!=default_bg_color)
+ {
+ buffer.format("(" BACKGROUND_TAG " #%02X%02X%02X)",
+ (unsigned int)((bg_color & 0xff0000) >> 16),
+ (unsigned int)((bg_color & 0xff00) >> 8),
+ (unsigned int)(bg_color & 0xff));
+ parser.parse(buffer);
+ }
+
+ //*** Zoom
+ del_all_items(ZOOM_TAG, parser);
+ if (zoom!=ZOOM_UNSPEC)
+ {
+ buffer="(" ZOOM_TAG " ";
+ const int i=1-zoom;
+ if((i>=0)&& (i<zoom_strings_size))
+ {
+ buffer+=zoom_strings[i];
+ }else
+ {
+ buffer+="d"+GUTF8String(zoom);
+ }
+ buffer+=")";
+ parser.parse(buffer);
+ }
+
+ //*** Mode
+ del_all_items(MODE_TAG, parser);
+ if (mode!=MODE_UNSPEC)
+ {
+ const int i=mode-1;
+ if((i>=0)&& (i<mode_strings_size))
+ {
+ buffer="(" MODE_TAG " " + GUTF8String(mode_strings[mode]) + ")";
+ }
+ parser.parse(buffer);
+ }
+
+ //*** Alignment
+ del_all_items(ALIGN_TAG, parser);
+ if (hor_align!=ALIGN_UNSPEC || ver_align!=ALIGN_UNSPEC)
+ {
+ buffer= GUTF8String("(" ALIGN_TAG " ")
+ +align_strings[((hor_align<ALIGN_UNSPEC)||
+ (hor_align>=align_strings_size))?ALIGN_UNSPEC:hor_align]
+ +" "+align_strings[((ver_align<ALIGN_UNSPEC)||
+ (ver_align>=align_strings_size))?ALIGN_UNSPEC:ver_align]+")";
+ parser.parse(buffer);
+ }
+ //*** Metadata
+#ifndef NO_METADATA_IN_ANT_CHUNK
+ del_all_items(METADATA_TAG, parser);
+ if (!metadata.isempty())
+ {
+ GUTF8String mdatabuffer("(");
+ mdatabuffer += METADATA_TAG ;
+ for (GPosition pos=metadata; pos; ++pos)
+ mdatabuffer +=" (" + metadata.key(pos)+" \""+metadata[pos]+"\")";
+ mdatabuffer += " )";
+ parser.parse(mdatabuffer);
+ }
+#endif
+ //*** Mapareas
+ del_all_items(GMapArea::MAPAREA_TAG, parser);
+ for(GPosition pos=map_areas;pos;++pos)
+ parser.parse(map_areas[pos]->print());
+
+ GP<ByteStream> gstr=ByteStream::create();
+ ByteStream &str=*gstr;
+ parser.print(str, 1);
+ GUTF8String ans;
+ int size = str.size();
+ str.seek(0);
+ str.read(ans.getbuf(size), size);
+ return ans;
+}
+
+bool
+DjVuANT::is_empty(void) const
+{
+ GUTF8String raw=encode_raw();
+ for(int i=raw.length()-1;i>=0;i--)
+ if (isspace(raw[i])) raw.setat(i, 0);
+ else break;
+ return raw.length()==0;
+}
+
+GP<DjVuANT>
+DjVuANT::copy(void) const
+{
+ GP<DjVuANT> ant=new DjVuANT(*this);
+
+
+ // Now process the list of hyperlinks.
+ ant->map_areas.empty();
+ for(GPosition pos=map_areas;pos;++pos)
+ ant->map_areas.append(map_areas[pos]->get_copy());
+
+ return ant;
+}
+
+//***************************************************************************
+//******************************** DjVuAnno *********************************
+//***************************************************************************
+
+GUTF8String
+DjVuAnno::get_xmlmap(const GUTF8String &name,const int height) const
+{
+ return ant
+ ?(ant->get_xmlmap(name,height))
+ :("<MAP name=\""+name.toEscaped()+"\"/>\n");
+}
+
+void
+DjVuAnno::writeMap(ByteStream &str_out,const GUTF8String &name,const int height) const
+{
+ if(ant)
+ {
+ ant->writeMap(str_out,name,height);
+ }else
+ {
+ str_out.writestring(get_xmlmap(name,height));
+ }
+}
+
+GUTF8String
+DjVuAnno::get_paramtags(void) const
+{
+ return ant
+ ?(ant->get_paramtags())
+ :GUTF8String();
+}
+
+void
+DjVuAnno::writeParam(ByteStream &str_out) const
+{
+ str_out.writestring(get_paramtags());
+}
+
+
+void
+DjVuAnno::decode(const GP<ByteStream> &gbs)
+{
+ GUTF8String chkid;
+ GP<IFFByteStream> giff=IFFByteStream::create(gbs);
+ IFFByteStream &iff=*giff;
+ while( iff.get_chunk(chkid) )
+ {
+ if (chkid == "ANTa")
+ {
+ if (ant) {
+ ant->merge(*iff.get_bytestream());
+ } else {
+ ant=DjVuANT::create();
+ ant->decode(*iff.get_bytestream());
+ }
+ }
+ else if (chkid == "ANTz")
+ {
+ GP<ByteStream> gbsiff=BSByteStream::create(giff->get_bytestream());
+ if (ant) {
+ ant->merge(*gbsiff);
+ } else {
+ ant=DjVuANT::create();
+ ant->decode(*gbsiff);
+ }
+ }
+ // Add decoding of other chunks here
+ iff.close_chunk();
+ }
+}
+
+void
+DjVuAnno::encode(const GP<ByteStream> &gbs)
+{
+ GP<IFFByteStream> giff=IFFByteStream::create(gbs);
+ IFFByteStream &iff=*giff;
+ if (ant)
+ {
+#if 0
+ iff.put_chunk("ANTa");
+ ant->encode(iff);
+ iff.close_chunk();
+#else
+ iff.put_chunk("ANTz");
+ {
+// GP<ByteStream> bsbinput = giff.get_bytestream();
+ GP<ByteStream> bsb = BSByteStream::create(giff->get_bytestream(), 50);
+ ant->encode(*bsb);
+ }
+ iff.close_chunk();
+#endif
+ }
+ // Add encoding of other chunks here
+}
+
+
+GP<DjVuAnno>
+DjVuAnno::copy(void) const
+{
+ GP<DjVuAnno> anno= new DjVuAnno;
+ // Copy any primitives (if any)
+ *anno=*this;
+ // Copy each substructure
+ if (ant) anno->ant = ant->copy();
+ return anno;
+}
+
+void
+DjVuAnno::merge(const GP<DjVuAnno> & anno)
+{
+ if (anno)
+ {
+ GP<ByteStream> gstr=ByteStream::create();
+ encode(gstr);
+ anno->encode(gstr);
+ gstr->seek(0);
+ decode(gstr);
+ }
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuAnno.h b/kviewshell/plugins/djvu/libdjvu/DjVuAnno.h
new file mode 100644
index 00000000..964c6c44
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuAnno.h
@@ -0,0 +1,295 @@
+//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: DjVuAnno.h,v 1.8 2003/11/07 22:08:20 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _DJVUANNO_H
+#define _DJVUANNO_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+
+/** @name DjVuAnno.h
+
+ Files #"DjVuAnno.h"# and #"DjVuAnno.cpp"# implement the mechanism for
+ annotating DjVuImages. Annotations are additional instructions for the
+ plugin about how the image should be displayed. The exact format of
+ annotations is not strictly defined. The only requirement is that they
+ have to be stored as a sequence of chunks inside a #FORM:ANNO#.
+
+ This file implements annotations understood by the DjVu plugins
+ and encoders.
+
+
+ using: contents of #ANT*# chunks.
+
+ Contents of the #FORM:ANNO# should be passed to \Ref{DjVuAnno::decode}()
+ for parsing, which initializes \Ref{DjVuAnno::ANT}
+ and fills them with decoded data.
+ @memo Implements support for DjVuImage annotations
+ @author Andrei Erofeev <eaf@geocities.com>
+ @version
+ #$Id: DjVuAnno.h,v 1.8 2003/11/07 22:08:20 leonb Exp $# */
+//@{
+
+
+#include "GString.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+class GMapArea;
+class ByteStream;
+
+// -------- DJVUANT --------
+
+/** This class contains some trivial annotations of the page or of the
+ document such as page border color, page alignment, initial zoom and
+ display mode, hyperlinks and highlighted areas. All this information is
+ put inside a textual chunk #ANTa# in pseudo-lisp format. Decoding and
+ encoding are normally done by \Ref{DjVuANT::decode}() and
+ \Ref{DjVuANT::encode}() functions. */
+
+class DjVuANT : public GPEnabled
+{
+protected:
+ /// Constructs an empty annotation object.
+ DjVuANT(void);
+
+public:
+ enum { MODE_UNSPEC=0, MODE_COLOR, MODE_FORE, MODE_BACK, MODE_BW };
+ enum { ZOOM_STRETCH=-4, ZOOM_ONE2ONE=-3, ZOOM_WIDTH=-2,
+ ZOOM_PAGE=-1, ZOOM_UNSPEC=0 };
+ enum alignment { ALIGN_UNSPEC=0, ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT,
+ ALIGN_TOP, ALIGN_BOTTOM };
+
+ /// Creates an empty annotation object.
+ static GP<DjVuANT> create(void) { return new DjVuANT; }
+ virtual ~DjVuANT();
+
+ /** Background color. Is in #0x00RRBBGG# format. #0xffffffff# if
+ there were no background color records in the annotation chunk. */
+ unsigned long int bg_color;
+ /** Initial zoom. Possible values are:
+ \begin{description}
+ \item[ZOOM_STRETCH] the image is stretched to the viewport.
+ \item[ZOOM_ONE2ONE] the image is displayed pixel-to-pixel.
+ \item[ZOOM_WIDTH] "Fit width" mode.
+ \item[ZOOM_PAGE] "Fit page" mode.
+ \item[ZOOM_UNSPEC] Annotation does not specify a zoom factor.
+ \end{description} */
+ int zoom;
+ /** Initial mode. Possible values are:
+ \begin{description}
+ \item[MODE_COLOR] color mode.
+ \item[MODE_FORE] foreground mode.
+ \item[MODE_BACK] background mode.
+ \item[MODE_BW] black and white mode.
+ \item[MODE_UNSPEC] Annotation does not specify a display mode.
+ \item[Any positive number] Zoom in \%. Please note that
+ all constants above are either negative or ZERO. Thus
+ it's possible to distinguish numerical zoom from those
+ special cases.
+ \end{description} */
+ int mode;
+ /** Horizontal page alignment. Possible values are #ALIGN_LEFT#,
+ #ALIGN_CENTER#, #ALIGN_RIGHT# and #ALIGN_UNSPEC#. */
+ alignment hor_align;
+ /** Vertical page alignment. Possible values are #ALIGN_TOP#,
+ #ALIGN_CENTER#, #ALIGN_BOTTOM# and #ALIGN_UNSPEC#. */
+ alignment ver_align;
+ /** List of defined map areas. They may be just areas of highlighting
+ or hyperlink. Please refer to \Ref{GMapArea}, \Ref{GMapRect},
+ \Ref{GMapPoly} and \Ref{GMapOval} for details. */
+ GPList<GMapArea> map_areas;
+#ifndef NO_METADATA_IN_ANT_CHUNK
+ /** Metainformations like title, author ... */
+ GMap<GUTF8String,GUTF8String> metadata;
+#endif
+ /** Returns TRUE if no features are specified or specified features
+ are not different from default ones */
+ bool is_empty(void) const;
+
+ /** Decodes contents of annotation chunk #ANTa#. The chunk data is
+ read from ByteStream #bs# until reaching an end-of-stream marker.
+ This function is normally called after a call to
+ \Ref{IFFByteStream::get_chunk}(). */
+ void decode(ByteStream &bs);
+
+ /** Same as \Ref{decode}() but adds the new data to what has
+ been decoded before. */
+ void merge(ByteStream & bs);
+
+ /** Encodes the #ANTa# chunk. The annotation data is simply written
+ into ByteStream #bs# with no IFF header. This function is normally
+ called after a call to \Ref{IFFByteStream::put_chunk}(). */
+ void encode(ByteStream &bs);
+
+ /// Encodes data back into raw annotation data.
+ GUTF8String encode_raw(void) const;
+
+ /// Returns a copy of this object
+ GP<DjVuANT> copy(void) const;
+
+ /** Returns the number of bytes needed by this data structure. It's
+ used by caching routines to estimate the size of a \Ref{DjVuImage}. */
+ unsigned int get_memory_usage() const;
+
+ /// Converts color from string in \#RRGGBB notation to an unsigned integer
+ static unsigned long int cvt_color(const char * color, unsigned long int def);
+ /// Obtain the <MAP></MAP> tag for these annotations.
+ GUTF8String get_xmlmap(const GUTF8String &name, const int height) const;
+ /// Write the <MAP></MAP> tag for these annotations.
+ void writeMap(
+ ByteStream &bs,const GUTF8String &name, const int height) const;
+ /// Obtain the XML flags for the default specifications.
+ GUTF8String get_paramtags(void) const;
+ /// Write the XML flags for the default specifications.
+ void writeParam(ByteStream &out_str) const;
+private:
+ void decode(class GLParser & parser);
+ static GUTF8String read_raw(ByteStream & str);
+ static unsigned char decode_comp(char ch1, char ch2);
+ static unsigned long int get_bg_color(class GLParser & parser);
+ static int get_zoom(class GLParser & parser);
+ static int get_mode(class GLParser & parser);
+ static alignment get_hor_align(class GLParser & parser);
+ static alignment get_ver_align(class GLParser & parser);
+ static GPList<GMapArea> get_map_areas(class GLParser & parser);
+#ifndef NO_METADATA_IN_ANT_CHUNK
+ static GMap<GUTF8String, GUTF8String>get_metadata(GLParser & parser);
+#endif
+ static void del_all_items(const char * name, class GLParser & parser);
+};
+
+// -------- DJVUANNO --------
+
+
+/** This is a top-level class containing annotations of a DjVu document (or
+ just a page). It has only two functions: \Ref{encode}() and
+ \Ref{decode}(). Both of them work with a sequence of annotation chunks
+ from #FORM:ANNO# form. Basing on the name of the chunks they call
+ #encode()# and #decode()# functions of the proper annotation structure
+ (like \Ref{ANT}). The real work of encoding and decoding is done by
+ lower-level classes. */
+class DjVuAnno : public GPEnabled
+{
+protected:
+ DjVuAnno(void) {}
+public:
+ /// Creation method.
+ static GP<DjVuAnno> create(void) { return new DjVuAnno; }
+
+ GP<DjVuANT> ant;
+
+ /** Decodes a sequence of annotation chunks and merges contents of every
+ chunk with previously decoded information. This function
+ should be called right after applying \Ref{IFFByteStream::get_chunk}()
+ to data from #FORM:ANNO#. */
+ void decode(const GP<ByteStream> &bs);
+
+ /** Encodes all annotations back into a sequence of chunks to be put
+ inside a #FORM:ANNO#. */
+ void encode(const GP<ByteStream> &bs);
+
+ /// Returns a copy of this object
+ GP<DjVuAnno> copy(void) const;
+
+ /** Merged the contents of this class and of annotations
+ pointed by #anno# pointer */
+ void merge(const GP<DjVuAnno> & anno);
+
+ /** Returns the number of bytes needed by this data structure. It's
+ used by caching routines to estimate the size of a \Ref{DjVuImage}. */
+ inline unsigned int get_memory_usage() const;
+ /// Obtain the <MAP></MAP> tag for these annotations.
+ GUTF8String get_xmlmap(const GUTF8String &name, const int height) const;
+ /// Write the <MAP></MAP> tag for these annotations.
+ void writeMap(
+ ByteStream &bs,const GUTF8String &name, const int height) const;
+ /// Obtain the XML flags for the default specifications.
+ GUTF8String get_paramtags(void) const;
+ /// Write the XML flags for the default specifications.
+ void writeParam(ByteStream &out_str) const;
+private: // dummy stuff
+ static void decode(ByteStream *);
+ static void encode(ByteStream *);
+};
+
+//@}
+
+inline unsigned int
+DjVuAnno::get_memory_usage() const
+{
+ return (ant)?(ant->get_memory_usage()):0;
+}
+
+// ----- THE END
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuDocEditor.cpp b/kviewshell/plugins/djvu/libdjvu/DjVuDocEditor.cpp
new file mode 100644
index 00000000..542faa7a
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuDocEditor.cpp
@@ -0,0 +1,2193 @@
+//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: DjVuDocEditor.cpp,v 1.13 2005/05/25 20:24:52 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "DjVuDocEditor.h"
+#include "DjVuImage.h"
+#include "IFFByteStream.h"
+#include "DataPool.h"
+#include "IW44Image.h"
+#include "GOS.h"
+#include "GURL.h"
+#include "DjVuAnno.h"
+#include "GRect.h"
+#include "DjVmNav.h"
+
+#include "debug.h"
+
+#include <ctype.h>
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+static const char octets[4]={0x41,0x54,0x26,0x54};
+
+int DjVuDocEditor::thumbnails_per_file=10;
+
+// This is a structure for active files and DataPools. It may contain
+// a DjVuFile, which is currently being used by someone (I check the list
+// and get rid of hanging files from time to time) or a DataPool,
+// which is "custom" with respect to the document (was modified or
+// inserted), or both.
+//
+// DjVuFile is set to smth!=0 when it's created using url_to_file().
+// It's reset back to ZERO in clean_files_map() when
+// it sees, that a given file is not used by anyone.
+// DataPool is updated when a file is inserted
+class DjVuDocEditor::File : public GPEnabled
+{
+public:
+ // 'pool' below may be non-zero only if it cannot be retrieved
+ // by the DjVuDocument, that is it either corresponds to a
+ // modified DjVuFile or it has been inserted. Otherwise it's ZERO
+ // Once someone assigns a non-zero DataPool, it remains non-ZERO
+ // (may be updated if the file gets modified) and may be reset
+ // only by save() or save_as() functions.
+ GP<DataPool> pool;
+
+ // If 'file' is non-zero, it means, that it's being used by someone
+ // We check for unused files from time to time and ZERO them.
+ // But before we do it, we may save the DataPool in the case if
+ // file has been modified.
+ GP<DjVuFile> file;
+};
+
+void
+DjVuDocEditor::check(void)
+{
+ if (!initialized) G_THROW( ERR_MSG("DjVuDocEditor.not_init") );
+}
+
+DjVuDocEditor::DjVuDocEditor(void)
+{
+ initialized=false;
+ refresh_cb=0;
+ refresh_cl_data=0;
+}
+
+DjVuDocEditor::~DjVuDocEditor(void)
+{
+ if (!tmp_doc_url.is_empty())
+ {
+ tmp_doc_url.deletefile();
+ }
+
+ GCriticalSectionLock lock(&thumb_lock);
+ thumb_map.empty();
+ DataPool::close_all();
+}
+
+void
+DjVuDocEditor::init(void)
+{
+ DEBUG_MSG("DjVuDocEditor::init() called\n");
+ DEBUG_MAKE_INDENT(3);
+
+ // If you remove this check be sure to delete thumb_map
+ if (initialized) G_THROW( ERR_MSG("DjVuDocEditor.init") );
+
+ doc_url=GURL::Filename::UTF8("noname.djvu");
+
+ const GP<DjVmDoc> doc(DjVmDoc::create());
+ const GP<ByteStream> gstr(ByteStream::create());
+ doc->write(gstr);
+ gstr->seek(0, SEEK_SET);
+ doc_pool=DataPool::create(gstr);
+
+ orig_doc_type=UNKNOWN_TYPE;
+ orig_doc_pages=0;
+
+ initialized=true;
+
+ DjVuDocument::init(doc_url, this);
+}
+
+void
+DjVuDocEditor::init(const GURL &url)
+{
+ DEBUG_MSG("DjVuDocEditor::init() called: url='" << url << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ // If you remove this check be sure to delete thumb_map
+ if (initialized)
+ G_THROW( ERR_MSG("DjVuDocEditor.init") );
+
+ // First - create a temporary DjVuDocument and check its type
+ doc_pool=DataPool::create(url);
+ doc_url=url;
+ const GP<DjVuDocument> tmp_doc(DjVuDocument::create_wait(doc_url,this));
+ if (!tmp_doc->is_init_ok())
+ G_THROW( ERR_MSG("DjVuDocEditor.open_fail") "\t" +url.get_string());
+
+ orig_doc_type=tmp_doc->get_doc_type();
+ orig_doc_pages=tmp_doc->get_pages_num();
+ if (orig_doc_type==OLD_BUNDLED ||
+ orig_doc_type==OLD_INDEXED ||
+ orig_doc_type==SINGLE_PAGE)
+ {
+ // Suxx. I need to convert it NOW.
+ // We will unlink this file in the destructor
+ tmp_doc_url=GURL::Filename::Native(tmpnam(0));
+ const GP<ByteStream> gstr(ByteStream::create(tmp_doc_url, "wb"));
+ tmp_doc->write(gstr, true); // Force DJVM format
+ gstr->flush();
+ doc_pool=DataPool::create(tmp_doc_url);
+ }
+
+ // OK. Now doc_pool contains data of the document in one of the
+ // new formats. It will be a lot easier to insert/delete pages now.
+
+ // 'doc_url' below of course doesn't refer to the file with the converted
+ // data, but we will take care of it by redirecting the request_data().
+ initialized=true;
+ DjVuDocument::init(doc_url, this);
+
+ // Cool. Now extract the thumbnails...
+ GCriticalSectionLock lock(&thumb_lock);
+ int pages_num=get_pages_num();
+ for(int page_num=0;page_num<pages_num;page_num++)
+ {
+ // Call DjVuDocument::get_thumbnail() here to bypass logic
+ // of DjVuDocEditor::get_thumbnail(). init() is the only safe
+ // place where we can still call DjVuDocument::get_thumbnail();
+ const GP<DataPool> pool(DjVuDocument::get_thumbnail(page_num, true));
+ if (pool)
+ {
+ thumb_map[page_to_id(page_num)]=pool;
+ }
+ }
+ // And remove then from DjVmDir so that DjVuDocument
+ // does not try to use them
+ unfile_thumbnails();
+}
+
+GP<DataPool>
+DjVuDocEditor::request_data(const DjVuPort * source, const GURL & url)
+{
+ DEBUG_MSG("DjVuDocEditor::request_data(): url='" << url << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ // Check if we have either original data or converted (to new format),
+ // if all the story is about the DjVuDocument's data
+ if (url==doc_url)
+ return doc_pool;
+
+ // Now see if we have any file matching the url
+ const GP<DjVmDir::File> frec(djvm_dir->name_to_file(url.fname()));
+ if (frec)
+ {
+ GCriticalSectionLock lock(&files_lock);
+ GPosition pos;
+ if (files_map.contains(frec->get_load_name(), pos))
+ {
+ const GP<File> f(files_map[pos]);
+ if (f->file && f->file->get_init_data_pool())
+ return f->file->get_init_data_pool();// Favor DjVuFile's knowledge
+ else if (f->pool) return f->pool;
+ }
+ }
+
+ // Finally let DjVuDocument cope with it. It may be a connected DataPool
+ // for a BUNDLED format. Or it may be a file. Anyway, it was not
+ // manually included, so it should be in the document.
+ const GP<DataPool> pool(DjVuDocument::request_data(source, url));
+
+ // We do NOT update the 'File' structure, because our rule is that
+ // we keep a separate copy of DataPool in 'File' only if it cannot
+ // be retrieved from DjVuDocument (like it has been "inserted" or
+ // corresponds to a modified file).
+ return pool;
+}
+
+void
+DjVuDocEditor::clean_files_map(void)
+ // Will go thru the map of files looking for unreferenced
+ // files or records w/o DjVuFile and DataPool.
+ // These will be modified and/or removed.
+{
+ DEBUG_MSG("DjVuDocEditor::clean_files_map() called\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GCriticalSectionLock lock(&files_lock);
+
+ // See if there are too old items in the "cache", which are
+ // not referenced by anyone. If the corresponding DjVuFile has been
+ // modified, obtain the new data and replace the 'pool'. Clear the
+ // DjVuFile anyway. If both DataPool and DjVuFile are zero, remove
+ // the entry.
+ for(GPosition pos=files_map;pos;)
+ {
+ const GP<File> f(files_map[pos]);
+ if (f->file && f->file->get_count()==1)
+ {
+ DEBUG_MSG("ZEROing file '" << f->file->get_url() << "'\n");
+ if (f->file->is_modified())
+ f->pool=f->file->get_djvu_data(false);
+ f->file=0;
+ }
+ if (!f->file && !f->pool)
+ {
+ DEBUG_MSG("Removing record '" << files_map.key(pos) << "'\n");
+ GPosition this_pos=pos;
+ ++pos;
+ files_map.del(this_pos);
+ } else ++pos;
+ }
+}
+
+GP<DjVuFile>
+DjVuDocEditor::url_to_file(const GURL & url, bool dont_create) const
+{
+ DEBUG_MSG("DjVuDocEditor::url_to_file(): url='" << url << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ // Check if have a DjVuFile with this url cached (created before
+ // and either still active or left because it has been modified)
+ GP<DjVmDir::File> frec;
+ if((const DjVmDir *)djvm_dir)
+ frec=djvm_dir->name_to_file(url.fname());
+ if (frec)
+ {
+ GCriticalSectionLock lock(&(const_cast<DjVuDocEditor *>(this)->files_lock));
+ GPosition pos;
+ if (files_map.contains(frec->get_load_name(), pos))
+ {
+ const GP<File> f(files_map[pos]);
+ if (f->file)
+ return f->file;
+ }
+ }
+
+ const_cast<DjVuDocEditor *>(this)->clean_files_map();
+
+ // We don't have the file cached. Let DjVuDocument create the file.
+ const GP<DjVuFile> file(DjVuDocument::url_to_file(url, dont_create));
+
+ // And add it to our private "cache"
+ if (file && frec)
+ {
+ GCriticalSectionLock lock(&(const_cast<DjVuDocEditor *>(this)->files_lock));
+ GPosition pos;
+ if (files_map.contains(frec->get_load_name(), pos))
+ {
+ files_map[frec->get_load_name()]->file=file;
+ }else
+ {
+ const GP<File> f(new File());
+ f->file=file;
+ const_cast<DjVuDocEditor *>(this)->files_map[frec->get_load_name()]=f;
+ }
+ }
+
+ return file;
+}
+
+GUTF8String
+DjVuDocEditor::page_to_id(int page_num) const
+{
+ if (page_num<0 || page_num>=get_pages_num())
+ G_THROW( ERR_MSG("DjVuDocEditor.page_num") "\t"+GUTF8String(page_num));
+ const GP<DjVmDir::File> f(djvm_dir->page_to_file(page_num));
+ if (! f)
+ G_THROW( ERR_MSG("DjVuDocEditor.page_num") "\t"+GUTF8String(page_num));
+
+ return f->get_load_name();
+}
+
+GUTF8String
+DjVuDocEditor::find_unique_id(GUTF8String id)
+{
+ const GP<DjVmDir> dir(get_djvm_dir());
+
+ GUTF8String base, ext;
+ const int dot=id.rsearch('.');
+ if(dot >= 0)
+ {
+ base=id.substr(0,dot);
+ ext=id.substr(dot+1,(unsigned int)-1);
+ }else
+ {
+ base=id;
+ }
+
+ int cnt=0;
+ while (!(!dir->id_to_file(id) &&
+ !dir->name_to_file(id) &&
+ !dir->title_to_file(id)))
+ {
+ cnt++;
+ id=base+"_"+GUTF8String(cnt);
+ if (ext.length())
+ id+="."+ext;
+ }
+ return id;
+}
+
+GP<DataPool>
+DjVuDocEditor::strip_incl_chunks(const GP<DataPool> & pool_in)
+{
+ DEBUG_MSG("DjVuDocEditor::strip_incl_chunks() called\n");
+ DEBUG_MAKE_INDENT(3);
+
+ const GP<IFFByteStream> giff_in(
+ IFFByteStream::create(pool_in->get_stream()));
+
+ const GP<ByteStream> gbs_out(ByteStream::create());
+ const GP<IFFByteStream> giff_out(IFFByteStream::create(gbs_out));
+
+ IFFByteStream &iff_in=*giff_in;
+ IFFByteStream &iff_out=*giff_out;
+
+ bool have_incl=false;
+ int chksize;
+ GUTF8String chkid;
+ if (iff_in.get_chunk(chkid))
+ {
+ iff_out.put_chunk(chkid);
+ while((chksize=iff_in.get_chunk(chkid)))
+ {
+ if (chkid!="INCL")
+ {
+ iff_out.put_chunk(chkid);
+ iff_out.copy(*iff_in.get_bytestream());
+ iff_out.close_chunk();
+ } else
+ {
+ have_incl=true;
+ }
+ iff_in.close_chunk();
+ }
+ iff_out.close_chunk();
+ }
+
+ if (have_incl)
+ {
+ gbs_out->seek(0,SEEK_SET);
+ return DataPool::create(gbs_out);
+ } else return pool_in;
+}
+
+GUTF8String
+DjVuDocEditor::insert_file(const GURL &file_url, const GUTF8String &parent_id,
+ int chunk_num, DjVuPort *source)
+ // Will open the 'file_name' and insert it into an existing DjVuFile
+ // with ID 'parent_id'. Will insert the INCL chunk at position chunk_num
+ // Will NOT process ANY files included into the file being inserted.
+ // Moreover it will strip out any INCL chunks in that file...
+{
+ DEBUG_MSG("DjVuDocEditor::insert_file(): fname='" << file_url <<
+ "', parent_id='" << parent_id << "'\n");
+ DEBUG_MAKE_INDENT(3);
+ const GP<DjVmDir> dir(get_djvm_dir());
+
+ if(!source)
+ source=this;
+ // Create DataPool and see if the file exists
+ GP<DataPool> file_pool;
+ if(file_url.is_empty()||file_url.is_local_file_url())
+ {
+ file_pool=DataPool::create(file_url);
+ }else
+ {
+ file_pool=source->request_data(source, file_url);
+ if(source != this)
+ {
+ file_pool=DataPool::create(file_pool->get_stream()->duplicate());
+ }
+ }
+ if(file_pool && file_url && DjVuDocument::djvu_import_codec)
+ {
+ (*DjVuDocument::djvu_import_codec)(file_pool,file_url,needs_compression_flag,can_compress_flag);
+ }
+
+ // Strip any INCL chunks
+ file_pool=strip_incl_chunks(file_pool);
+
+ // Check if parent ID is valid
+ GP<DjVmDir::File> parent_frec(dir->id_to_file(parent_id));
+ if (!parent_frec)
+ parent_frec=dir->name_to_file(parent_id);
+ if (!parent_frec)
+ parent_frec=dir->title_to_file(parent_id);
+ if (!parent_frec)
+ G_THROW( ERR_MSG("DjVuDocEditor.no_file") "\t" +parent_id);
+ const GP<DjVuFile> parent_file(get_djvu_file(parent_id));
+ if (!parent_file)
+ G_THROW( ERR_MSG("DjVuDocEditor.create_fail") "\t"+parent_id);
+
+ // Now obtain ID for the new file
+ const GUTF8String id(find_unique_id(file_url.fname()));
+
+ // Add it into the directory
+ const GP<DjVmDir::File> frec(
+ DjVmDir::File::create(id, id, id, DjVmDir::File::INCLUDE));
+ int pos=dir->get_file_pos(parent_frec);
+ if (pos>=0)
+ ++pos;
+ dir->insert_file(frec, pos);
+
+ // Add it to our "cache"
+ {
+ const GP<File> f(new File);
+ f->pool=file_pool;
+ GCriticalSectionLock lock(&files_lock);
+ files_map[id]=f;
+ }
+
+ // And insert it into the parent DjVuFile
+ parent_file->insert_file(id, chunk_num);
+
+ return id;
+}
+
+ // First it will insert the 'file_url' at position 'file_pos'.
+ //
+ // Then it will process all the INCL chunks in the file and try to do
+ // the same thing with the included files. If insertion of an included
+ // file fails, it will proceed with other INCL chunks until it does
+ // them all. In the very end we will throw exception to let the caller
+ // know about problems with included files.
+ //
+ // If the name of a file being inserted conflicts with some other
+ // name, which has been in DjVmDir prior to call to this function,
+ // it will be modified. name2id is the translation table to
+ // keep track of these modifications.
+ //
+ // Also, if a name is in name2id, we will not insert that file again.
+ //
+ // Will return TRUE if the file has been successfully inserted.
+ // FALSE, if the file contains NDIR chunk and has been skipped.
+bool
+DjVuDocEditor::insert_file(const GURL &file_url, bool is_page,
+ int & file_pos, GMap<GUTF8String, GUTF8String> & name2id,
+ DjVuPort *source)
+{
+
+ DEBUG_MSG("DjVuDocEditor::insert_file(): file_url='" << file_url <<
+ "', is_page='" << is_page << "'\n");
+ DEBUG_MAKE_INDENT(3);
+ if (refresh_cb)
+ refresh_cb(refresh_cl_data);
+
+
+ // We do not want to insert the same file twice (important when
+ // we insert a group of files at the same time using insert_group())
+ // So we check if we already did that and return if so.
+ if (name2id.contains(file_url.fname()))
+ return true;
+
+ if(!source)
+ source=this;
+
+ GP<DataPool> file_pool;
+ if(file_url.is_empty()||file_url.is_local_file_url())
+ {
+ file_pool=DataPool::create(file_url);
+ }
+ else
+ {
+ file_pool=source->request_data(source, file_url);
+ if(source != this)
+ {
+ file_pool=DataPool::create(file_pool->get_stream());
+ }
+ }
+ // Create DataPool and see if the file exists
+ if(file_pool && !file_url.is_empty() && DjVuDocument::djvu_import_codec)
+ {
+ (*DjVuDocument::djvu_import_codec)(file_pool,file_url,
+ needs_compression_flag,
+ can_compress_flag);
+ }
+
+ // Oh. It does exist... Check that it has IFF structure
+ {
+ const GP<IFFByteStream> giff(
+ IFFByteStream::create(file_pool->get_stream()));
+ IFFByteStream &iff=*giff;
+ GUTF8String chkid;
+
+ int length;
+ length=iff.get_chunk(chkid);
+ if (chkid!="FORM:DJVI" && chkid!="FORM:DJVU" &&
+ chkid!="FORM:BM44" && chkid!="FORM:PM44")
+ G_THROW( ERR_MSG("DjVuDocEditor.not_1_page") "\t"+file_url.get_string());
+
+ // Wonderful. It's even a DjVu file. Scan for NDIR chunks.
+ // If NDIR chunk is found, ignore the file
+ while(iff.get_chunk(chkid))
+ {
+ if (chkid=="NDIR")
+ return false;
+ iff.close_chunk();
+ }
+ }
+ return insert_file(file_pool,file_url,is_page,file_pos,name2id,source);
+}
+
+bool
+DjVuDocEditor::insert_file(const GP<DataPool> &file_pool,
+ const GURL &file_url, bool is_page,
+ int & file_pos, GMap<GUTF8String, GUTF8String> & name2id,
+ DjVuPort *source)
+{
+ GUTF8String errors;
+ if(file_pool)
+ {
+ const GP<DjVmDir> dir(get_djvm_dir());
+ G_TRY
+ {
+ // Now get a unique name for this file.
+ // Check the name2id first...
+ const GUTF8String name=file_url.fname();
+ GUTF8String id;
+ if (name2id.contains(name))
+ {
+ id=name2id[name];
+ }else
+ {
+ // Check to see if this page exists with a different name.
+ if(!is_page)
+ {
+ GPList<DjVmDir::File> list(dir->get_files_list());
+ for(GPosition pos=list;pos;++pos)
+ {
+ DEBUG_MSG("include " << list[pos]->is_include()
+ << " size=" << list[pos]->size << " length="
+ << file_pool->get_length() << "\n");
+ if(list[pos]->is_include()
+ && (!list[pos]->size
+ || (list[pos]->size == file_pool->get_length())))
+ {
+ id=list[pos]->get_load_name();
+ GP<DjVuFile> file(get_djvu_file(id,false));
+ const GP<DataPool> pool(file->get_djvu_data(false));
+ if(file_pool->simple_compare(*pool))
+ {
+ // The files are the same, so just store the alias.
+ name2id[name]=id;
+ }
+ const GP<IFFByteStream> giff_old(IFFByteStream::create(pool->get_stream()));
+ const GP<IFFByteStream> giff_new(IFFByteStream::create(file_pool->get_stream()));
+ file=0;
+ if(giff_old->compare(*giff_new))
+ {
+ // The files are the same, so just store the alias.
+ name2id[name]=id;
+ return true;
+ }
+ }
+ }
+ }
+ // Otherwise create a new unique ID and remember the translation
+ id=find_unique_id(name);
+ name2id[name]=id;
+ }
+
+ // Good. Before we continue with the included files we want to
+ // complete insertion of this one. Notice, that insertion of
+ // children may fail, in which case we will have to modify
+ // data for this file to get rid of invalid INCL
+
+ // Create a file record with the chosen ID
+ const GP<DjVmDir::File> file(DjVmDir::File::create(id, id, id,
+ is_page ? DjVmDir::File::PAGE : DjVmDir::File::INCLUDE ));
+
+ // And insert it into the directory
+ file_pos=dir->insert_file(file, file_pos);
+
+ // And add the File record (containing the file URL and DataPool)
+ {
+ const GP<File> f(new File);
+ f->pool=file_pool;
+ GCriticalSectionLock lock(&files_lock);
+ files_map[id]=f;
+ }
+
+ // The file has been added. If it doesn't include anything else,
+ // that will be enough. Otherwise repeat what we just did for every
+ // included child. Don't forget to modify the contents of INCL
+ // chunks due to name2id translation.
+ // We also want to include here our file with shared annotations,
+ // if it exists.
+ GUTF8String chkid;
+ const GP<IFFByteStream> giff_in(
+ IFFByteStream::create(file_pool->get_stream()));
+ IFFByteStream &iff_in=*giff_in;
+ const GP<ByteStream> gstr_out(ByteStream::create());
+ const GP<IFFByteStream> giff_out(IFFByteStream::create(gstr_out));
+ IFFByteStream &iff_out=*giff_out;
+
+ const GP<DjVmDir::File> shared_frec(djvm_dir->get_shared_anno_file());
+
+ iff_in.get_chunk(chkid);
+ iff_out.put_chunk(chkid);
+ while(iff_in.get_chunk(chkid))
+ {
+ if (chkid!="INCL")
+ {
+ iff_out.put_chunk(chkid);
+ iff_out.copy(*iff_in.get_bytestream());
+ iff_in.close_chunk();
+ iff_out.close_chunk();
+ if (shared_frec && chkid=="INFO")
+ {
+ iff_out.put_chunk("INCL");
+ iff_out.get_bytestream()->writestring(shared_frec->get_load_name());
+ iff_out.close_chunk();
+ }
+ } else
+ {
+ GUTF8String name;
+ char buffer[1024];
+ int length;
+ while((length=iff_in.read(buffer, 1024)))
+ name+=GUTF8String(buffer, length);
+ while(isspace(name[0]))
+ {
+ name=name.substr(1,(unsigned int)-1);
+ }
+ while(isspace(name[(int)name.length()-1]))
+ {
+ name.setat(name.length()-1, 0);
+ }
+ const GURL::UTF8 full_url(name,file_url.base());
+ iff_in.close_chunk();
+
+ G_TRY {
+ if (insert_file(full_url, false, file_pos, name2id, source))
+ {
+ // If the child file has been inserted (doesn't
+ // contain NDIR chunk), add INCL chunk.
+ GUTF8String id=name2id[name];
+ iff_out.put_chunk("INCL");
+ iff_out.get_bytestream()->writestring(id);
+ iff_out.close_chunk();
+ }
+ } G_CATCH(exc) {
+ // Should an error occur, we move on. INCL chunk will
+ // not be copied.
+ if (errors.length())
+ errors+="\n\n";
+ errors+=exc.get_cause();
+ } G_ENDCATCH;
+ }
+ } // while(iff_in.get_chunk(chkid))
+ iff_out.close_chunk();
+
+ // Increment the file_pos past the page inserted.
+ if (file_pos>=0) file_pos++;
+
+ // We have just inserted every included file. We may have modified
+ // contents of the INCL chunks. So we need to update the DataPool...
+ gstr_out->seek(0);
+ const GP<DataPool> new_file_pool(DataPool::create(gstr_out));
+ {
+ // It's important that we replace the pool here anyway.
+ // By doing this we load the file into memory. And this is
+ // exactly what insert_group() wants us to do because
+ // it creates temporary files.
+ GCriticalSectionLock lock(&files_lock);
+ files_map[id]->pool=new_file_pool;
+ }
+ } G_CATCH(exc) {
+ if (errors.length())
+ errors+="\n\n";
+ errors+=exc.get_cause();
+ G_THROW(errors);
+ } G_ENDCATCH;
+
+ // The only place where we intercept exceptions is when we process
+ // included files. We want to process all of them even if we failed to
+ // process one. But here we need to let the exception propagate...
+ if (errors.length())
+ G_THROW(errors);
+
+ return true;
+ }
+ return false;
+}
+
+void
+DjVuDocEditor::insert_group(const GList<GURL> & file_urls, int page_num,
+ void (* _refresh_cb)(void *), void * _cl_data)
+ // The function will insert every file from the list at position
+ // corresponding to page_num. If page_num is negative, concatenation
+ // will occur. Included files will be processed as well
+{
+ refresh_cb=_refresh_cb;
+ refresh_cl_data=_cl_data;
+
+ G_TRY
+ {
+
+ // First translate the page_num to file_pos.
+ const GP<DjVmDir> dir(get_djvm_dir());
+ int file_pos;
+ if (page_num<0 || page_num>=dir->get_pages_num())
+ {
+ file_pos=-1;
+ }
+ else
+ {
+ file_pos=dir->get_page_pos(page_num);
+ }
+
+ // Now call the insert_file() for every page. We will remember the
+ // name2id translation table. Thus insert_file() will remember IDs
+ // it assigned to shared files
+ GMap<GUTF8String, GUTF8String> name2id;
+
+ GUTF8String errors;
+ for(GPosition pos=file_urls;pos;++pos)
+ {
+ const GURL &furl=file_urls[pos];
+ DEBUG_MSG( "Inserting file '" << furl << "'\n" );
+ G_TRY
+ {
+ // Check if it's a multipage document...
+ GP<DataPool> xdata_pool(DataPool::create(furl));
+ if(xdata_pool && furl.is_valid()
+ && furl.is_local_file_url() && DjVuDocument::djvu_import_codec)
+ {
+ (*DjVuDocument::djvu_import_codec)(xdata_pool,furl,
+ needs_compression_flag,
+ can_compress_flag);
+ }
+ GUTF8String chkid;
+ IFFByteStream::create(xdata_pool->get_stream())->get_chunk(chkid);
+ if (name2id.contains(furl.fname())||(chkid=="FORM:DJVM"))
+ {
+ GMap<GUTF8String,void *> map;
+ map_ids(map);
+ DEBUG_MSG("Read DjVuDocument furl='" << furl << "'\n");
+ GP<ByteStream> gbs(ByteStream::create());
+ GP<DjVuDocument> doca(DjVuDocument::create_noinit());
+ doca->set_verbose_eof(verbose_eof);
+ doca->set_recover_errors(recover_errors);
+ doca->init(furl /* ,this */ );
+ doca->wait_for_complete_init();
+ get_portcaster()->add_route(doca,this);
+ DEBUG_MSG("Saving DjVuDocument url='" << furl << "' with unique names\n");
+ doca->write(gbs,map);
+ gbs->seek(0L);
+ DEBUG_MSG("Loading unique names\n");
+ GP<DjVuDocument> doc(DjVuDocument::create(gbs));
+ doc->set_verbose_eof(verbose_eof);
+ doc->set_recover_errors(recover_errors);
+ doc->wait_for_complete_init();
+ get_portcaster()->add_route(doc,this);
+ gbs=0;
+ DEBUG_MSG("Inserting pages\n");
+ int pages_num=doc->get_pages_num();
+ for(int page_num=0;page_num<pages_num;page_num++)
+ {
+ const GURL url(doc->page_to_url(page_num));
+ insert_file(url, true, file_pos, name2id, doc);
+ }
+ }
+ else
+ {
+ insert_file(furl, true, file_pos, name2id, this);
+ }
+ } G_CATCH(exc)
+ {
+ if (errors.length())
+ {
+ errors+="\n\n";
+ }
+ errors+=exc.get_cause();
+ }
+ G_ENDCATCH;
+ }
+ if (errors.length())
+ {
+ G_THROW(errors);
+ }
+ } G_CATCH_ALL
+ {
+ refresh_cb=0;
+ refresh_cl_data=0;
+ G_RETHROW;
+ } G_ENDCATCH;
+ refresh_cb=0;
+ refresh_cl_data=0;
+}
+
+void
+DjVuDocEditor::insert_page(const GURL &file_url, int page_num)
+{
+ DEBUG_MSG("DjVuDocEditor::insert_page(): furl='" << file_url << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GList<GURL> list;
+ list.append(file_url);
+
+ insert_group(list, page_num);
+}
+
+void
+DjVuDocEditor::insert_page(GP<DataPool> & _file_pool,
+ const GURL & file_url, int page_num)
+ // Use _file_pool as source of data, create a new DjVuFile
+ // with name file_name, and insert it as page number page_num
+{
+ DEBUG_MSG("DjVuDocEditor::insert_page(): pool size='" <<
+ _file_pool->get_size() << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ const GP<DjVmDir> dir(get_djvm_dir());
+
+ // Strip any INCL chunks (we do not allow to insert hierarchies
+ // using this function)
+ const GP<DataPool> file_pool(strip_incl_chunks(_file_pool));
+
+ // Now obtain ID for the new file
+ const GUTF8String id(find_unique_id(file_url.fname()));
+
+ // Add it into the directory
+ const GP<DjVmDir::File> frec(DjVmDir::File::create(
+ id, id, id, DjVmDir::File::PAGE));
+ int pos=dir->get_page_pos(page_num);
+ dir->insert_file(frec, pos);
+
+ // Add it to our "cache"
+ {
+ GP<File> f=new File;
+ f->pool=file_pool;
+ GCriticalSectionLock lock(&files_lock);
+ files_map[id]=f;
+ }
+}
+
+void
+DjVuDocEditor::generate_ref_map(const GP<DjVuFile> & file,
+ GMap<GUTF8String, void *> & ref_map,
+ GMap<GURL, void *> & visit_map)
+ // This private function is used to generate a list (implemented as map)
+ // of files referencing the given file. To get list of all parents
+ // for file with ID 'id' iterate map obtained as
+ // *((GMap<GUTF8String, void *> *) ref_map[id])
+{
+ const GURL url=file->get_url();
+ const GUTF8String id(djvm_dir->name_to_file(url.fname())->get_load_name());
+ if (!visit_map.contains(url))
+ {
+ visit_map[url]=0;
+
+ GPList<DjVuFile> files_list=file->get_included_files(false);
+ for(GPosition pos=files_list;pos;++pos)
+ {
+ GP<DjVuFile> child_file=files_list[pos];
+ // First: add the current file to the list of parents for
+ // the child being processed
+ GURL child_url=child_file->get_url();
+ const GUTF8String child_id(
+ djvm_dir->name_to_file(child_url.fname())->get_load_name());
+ GMap<GUTF8String, void *> * parents=0;
+ if (ref_map.contains(child_id))
+ parents=(GMap<GUTF8String, void *> *) ref_map[child_id];
+ else
+ ref_map[child_id]=parents=new GMap<GUTF8String, void *>();
+ (*parents)[id]=0;
+ // Second: go recursively
+ generate_ref_map(child_file, ref_map, visit_map);
+ }
+ }
+}
+
+void
+DjVuDocEditor::remove_file(const GUTF8String &id, bool remove_unref,
+ GMap<GUTF8String, void *> & ref_map)
+ // Private function, which will remove file with ID id.
+ //
+ // If will also remove all INCL chunks in parent files pointing
+ // to this one
+ //
+ // Finally, if remove_unref is TRUE, we will go down the files
+ // hierarchy removing every file, which becomes unreferenced.
+ //
+ // ref_map will be used to find out list of parents referencing
+ // this file (required when removing INCL chunks)
+{
+ // First get rid of INCL chunks in parents
+ GMap<GUTF8String, void *> * parents=(GMap<GUTF8String, void *> *) ref_map[id];
+ if (parents)
+ {
+ for(GPosition pos=*parents;pos;++pos)
+ {
+ const GUTF8String parent_id((*parents).key(pos));
+ const GP<DjVuFile> parent(get_djvu_file(parent_id));
+ if (parent)
+ parent->unlink_file(id);
+ }
+ delete parents;
+ parents=0;
+ ref_map.del(id);
+ }
+
+ // We will accumulate errors here.
+ GUTF8String errors;
+
+ // Now modify the ref_map and process children if necessary
+ GP<DjVuFile> file=get_djvu_file(id);
+ if (file)
+ {
+ G_TRY {
+ GPList<DjVuFile> files_list=file->get_included_files(false);
+ for(GPosition pos=files_list;pos;++pos)
+ {
+ GP<DjVuFile> child_file=files_list[pos];
+ GURL child_url=child_file->get_url();
+ const GUTF8String child_id(
+ djvm_dir->name_to_file(child_url.fname())->get_load_name());
+ GMap<GUTF8String, void *> * parents=(GMap<GUTF8String, void *> *) ref_map[child_id];
+ if (parents) parents->del(id);
+
+ if (remove_unref && (!parents || !parents->size()))
+ remove_file(child_id, remove_unref, ref_map);
+ }
+ } G_CATCH(exc) {
+ if (errors.length()) errors+="\n\n";
+ errors+=exc.get_cause();
+ } G_ENDCATCH;
+ }
+
+ // Finally remove this file from the directory.
+ djvm_dir->delete_file(id);
+
+ // And get rid of its thumbnail, if any
+ GCriticalSectionLock lock(&thumb_lock);
+ GPosition pos(thumb_map.contains(id));
+ if (pos)
+ {
+ thumb_map.del(pos);
+ }
+ if (errors.length())
+ G_THROW(errors);
+}
+
+void
+DjVuDocEditor::remove_file(const GUTF8String &id, bool remove_unref)
+{
+ DEBUG_MSG("DjVuDocEditor::remove_file(): id='" << id << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (!djvm_dir->id_to_file(id))
+ G_THROW( ERR_MSG("DjVuDocEditor.no_file") "\t"+id);
+
+ // First generate a map of references (containing the list of parents
+ // including this particular file. This will speed things up
+ // significatly.
+ GMap<GUTF8String, void *> ref_map; // GMap<GUTF8String, GMap<GUTF8String, void *> *> in fact
+ GMap<GURL, void *> visit_map; // To avoid loops
+
+ int pages_num=djvm_dir->get_pages_num();
+ for(int page_num=0;page_num<pages_num;page_num++)
+ generate_ref_map(get_djvu_file(page_num), ref_map, visit_map);
+
+ // Now call the function, which will do the removal recursively
+ remove_file(id, remove_unref, ref_map);
+
+ // And clear the ref_map
+ GPosition pos;
+ while((pos=ref_map))
+ {
+ GMap<GUTF8String, void *> * parents=(GMap<GUTF8String, void *> *) ref_map[pos];
+ delete parents;
+ ref_map.del(pos);
+ }
+}
+
+void
+DjVuDocEditor::remove_page(int page_num, bool remove_unref)
+{
+ DEBUG_MSG("DjVuDocEditor::remove_page(): page_num=" << page_num << "\n");
+ DEBUG_MAKE_INDENT(3);
+
+ // Translate the page_num to ID
+ GP<DjVmDir> djvm_dir=get_djvm_dir();
+ if (page_num<0 || page_num>=djvm_dir->get_pages_num())
+ G_THROW( ERR_MSG("DjVuDocEditor.bad_page") "\t"+GUTF8String(page_num));
+
+ // And call general remove_file()
+ remove_file(djvm_dir->page_to_file(page_num)->get_load_name(), remove_unref);
+}
+
+void
+DjVuDocEditor::remove_pages(const GList<int> & page_list, bool remove_unref)
+{
+ DEBUG_MSG("DjVuDocEditor::remove_pages() called\n");
+ DEBUG_MAKE_INDENT(3);
+
+ // First we need to translate page numbers to IDs (they will
+ // obviously be changing while we're removing pages one after another)
+ GP<DjVmDir> djvm_dir=get_djvm_dir();
+ GPosition pos ;
+ if (djvm_dir)
+ {
+ GList<GUTF8String> id_list;
+ for(pos=page_list;pos;++pos)
+ {
+ GP<DjVmDir::File> frec=djvm_dir->page_to_file(page_list[pos]);
+ if (frec)
+ id_list.append(frec->get_load_name());
+ }
+
+ for(pos=id_list;pos;++pos)
+ {
+ GP<DjVmDir::File> frec=djvm_dir->id_to_file(id_list[pos]);
+ if (frec)
+ remove_page(frec->get_page_num(), remove_unref);
+ }
+ }
+}
+
+void
+DjVuDocEditor::move_file(const GUTF8String &id, int & file_pos,
+ GMap<GUTF8String, void *> & map)
+ // NOTE! file_pos here is the desired position in DjVmDir *after*
+ // the record with ID 'id' is removed.
+{
+ if (!map.contains(id))
+ {
+ map[id]=0;
+
+ GP<DjVmDir::File> file_rec=djvm_dir->id_to_file(id);
+ if (file_rec)
+ {
+ file_rec=new DjVmDir::File(*file_rec);
+ djvm_dir->delete_file(id);
+ djvm_dir->insert_file(file_rec, file_pos);
+
+ if (file_pos>=0)
+ {
+ file_pos++;
+
+ // We care to move included files only if we do not append
+ // This is because the only reason why we move included
+ // files is to made them available sooner than they would
+ // be available if we didn't move them. By appending files
+ // we delay the moment when the data for the file becomes
+ // available, of course.
+ GP<DjVuFile> djvu_file=get_djvu_file(id);
+ if (djvu_file)
+ {
+ GPList<DjVuFile> files_list=djvu_file->get_included_files(false);
+ for(GPosition pos=files_list;pos;++pos)
+ {
+ const GUTF8String name(files_list[pos]->get_url().fname());
+ GP<DjVmDir::File> child_frec=djvm_dir->name_to_file(name);
+
+ // If the child is positioned in DjVmDir AFTER the
+ // file being processed (position is file_pos or greater),
+ // move it to file_pos position
+ if (child_frec)
+ if (djvm_dir->get_file_pos(child_frec)>file_pos)
+ move_file(child_frec->get_load_name(), file_pos, map);
+ }
+ }
+ }
+ }
+ }
+}
+
+void
+DjVuDocEditor::move_page(int page_num, int new_page_num)
+{
+ DEBUG_MSG("DjVuDocEditor::move_page(): page_num=" << page_num <<
+ ", new_page_num=" << new_page_num << "\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (page_num==new_page_num) return;
+
+ int pages_num=get_pages_num();
+ if (page_num<0 || page_num>=pages_num)
+ G_THROW( ERR_MSG("DjVuDocEditor.bad_page") "\t"+GUTF8String(page_num));
+
+ const GUTF8String id(page_to_id(page_num));
+ int file_pos=-1;
+ if (new_page_num>=0 && new_page_num<pages_num)
+ if (new_page_num>page_num) // Moving toward the end
+ {
+ if (new_page_num<pages_num-1)
+ file_pos=djvm_dir->get_page_pos(new_page_num+1)-1;
+ } else
+ file_pos=djvm_dir->get_page_pos(new_page_num);
+
+ GMap<GUTF8String, void *> map;
+ move_file(id, file_pos, map);
+}
+#ifdef _WIN32_WCE_EMULATION // Work around odd behavior under WCE Emulation
+#define CALLINGCONVENTION __cdecl
+#else
+#define CALLINGCONVENTION /* */
+#endif
+
+static int
+CALLINGCONVENTION
+cmp(const void * ptr1, const void * ptr2)
+{
+ int num1=*(int *) ptr1;
+ int num2=*(int *) ptr2;
+ return num1<num2 ? -1 : num1>num2 ? 1 : 0;
+}
+
+static GList<int>
+sortList(const GList<int> & list)
+{
+ GArray<int> a(list.size()-1);
+ int cnt;
+ GPosition pos;
+ for(pos=list, cnt=0;pos;++pos, cnt++)
+ a[cnt]=list[pos];
+
+ qsort((int *) a, a.size(), sizeof(int), cmp);
+
+ GList<int> l;
+ for(int i=0;i<a.size();i++)
+ l.append(a[i]);
+
+ return l;
+}
+
+void
+DjVuDocEditor::move_pages(const GList<int> & _page_list, int shift)
+{
+ if (!shift) return;
+
+ GList<int> page_list=sortList(_page_list);
+
+ GList<GUTF8String> id_list;
+ for(GPosition pos=page_list;pos;++pos)
+ {
+ GP<DjVmDir::File> frec=djvm_dir->page_to_file(page_list[pos]);
+ if (frec)
+ id_list.append(frec->get_load_name());
+ }
+
+ if (shift<0)
+ {
+ // We have to start here from the smallest page number
+ // We will move it according to the 'shift', and all
+ // further moves are guaranteed not to affect its page number.
+
+ // We will be changing the 'min_page' to make sure that
+ // pages moved beyond the document will still be in correct order
+ int min_page=0;
+ for(GPosition pos=id_list;pos;++pos)
+ {
+ GP<DjVmDir::File> frec=djvm_dir->id_to_file(id_list[pos]);
+ if (frec)
+ {
+ int page_num=frec->get_page_num();
+ int new_page_num=page_num+shift;
+ if (new_page_num<min_page)
+ new_page_num=min_page++;
+ move_page(page_num, new_page_num);
+ }
+ }
+ } else
+ {
+ // We have to start here from the biggest page number
+ // We will move it according to the 'shift', and all
+ // further moves will not affect its page number.
+
+ // We will be changing the 'max_page' to make sure that
+ // pages moved beyond the document will still be in correct order
+ int max_page=djvm_dir->get_pages_num()-1;
+ for(GPosition pos=id_list.lastpos();pos;--pos)
+ {
+ GP<DjVmDir::File> frec=djvm_dir->id_to_file(id_list[pos]);
+ if (frec)
+ {
+ int page_num=frec->get_page_num();
+ int new_page_num=page_num+shift;
+ if (new_page_num>max_page)
+ new_page_num=max_page--;
+ move_page(page_num, new_page_num);
+ }
+ }
+ }
+}
+
+void
+DjVuDocEditor::set_file_name(const GUTF8String &id, const GUTF8String &name)
+{
+ DEBUG_MSG("DjVuDocEditor::set_file_name(), id='" << id << "', name='" << name << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ // It's important to get the URL now, because later (after we
+ // change DjVmDir) id_to_url() will be returning a modified value
+ GURL url=id_to_url(id);
+
+ // Change DjVmDir. It will check if the name is unique
+ djvm_dir->set_file_name(id, name);
+
+ // Now find DjVuFile (if any) and rename it
+ GPosition pos;
+ if (files_map.contains(id, pos))
+ {
+ GP<File> file=files_map[pos];
+ GP<DataPool> pool=file->pool;
+ if (pool) pool->load_file();
+ GP<DjVuFile> djvu_file=file->file;
+ if (djvu_file) djvu_file->set_name(name);
+ }
+}
+
+void
+DjVuDocEditor::set_page_name(int page_num, const GUTF8String &name)
+{
+ DEBUG_MSG("DjVuDocEditor::set_page_name(), page_num='" << page_num << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (page_num<0 || page_num>=get_pages_num())
+ G_THROW( ERR_MSG("DjVuDocEditor.bad_page") "\t"+GUTF8String(page_num));
+
+ set_file_name(page_to_id(page_num), name);
+}
+
+void
+DjVuDocEditor::set_file_title(const GUTF8String &id, const GUTF8String &title)
+{
+ DEBUG_MSG("DjVuDocEditor::set_file_title(), id='" << id << "', title='" << title << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ // Just change DjVmDir. It will check if the title is unique
+ djvm_dir->set_file_title(id, title);
+}
+
+void
+DjVuDocEditor::set_page_title(int page_num, const GUTF8String &title)
+{
+ DEBUG_MSG("DjVuDocEditor::set_page_title(), page_num='" << page_num << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (page_num<0 || page_num>=get_pages_num())
+ G_THROW( ERR_MSG("DjVuDocEditor.bad_page") "\t"+GUTF8String(page_num));
+
+ set_file_title(page_to_id(page_num), title);
+}
+
+//****************************************************************************
+//************************** Shared annotations ******************************
+//****************************************************************************
+
+void
+DjVuDocEditor::simplify_anno(void (* progress_cb)(float progress, void *),
+ void * cl_data)
+ // It's important that no decoding is done while this function
+ // is running. Otherwise the DjVuFile's decoding routines and
+ // this function may attempt to decode/modify a file's
+ // annotations at the same time.
+{
+ // Get the name of the SHARED_ANNO file. We will not
+ // touch that file (will not move annotations from it)
+ GP<DjVmDir::File> shared_file=djvm_dir->get_shared_anno_file();
+ GUTF8String shared_id;
+ if (shared_file)
+ shared_id=shared_file->get_load_name();
+
+ GList<GURL> ignore_list;
+ if (shared_id.length())
+ ignore_list.append(id_to_url(shared_id));
+
+ // First, for every page get merged (or "flatten" or "projected")
+ // annotations and store them inside the top-level page file
+ int pages_num=djvm_dir->get_pages_num();
+ for(int page_num=0;page_num<pages_num;page_num++)
+ {
+ GP<DjVuFile> djvu_file=get_djvu_file(page_num);
+ if (!djvu_file)
+ G_THROW( ERR_MSG("DjVuDocEditor.page_fail") "\t"+page_num);
+ int max_level=0;
+ GP<ByteStream> anno;
+ anno=djvu_file->get_merged_anno(ignore_list, &max_level);
+ if (anno && max_level>0)
+ {
+ // This is the moment when we try to modify DjVuFile's annotations
+ // Make sure, that it's not being decoded
+ GSafeFlags & file_flags=djvu_file->get_safe_flags();
+ GMonitorLock lock(&file_flags);
+ while(file_flags & DjVuFile::DECODING)
+ file_flags.wait();
+
+ // Merge all chunks in one by decoding and encoding DjVuAnno
+ const GP<DjVuAnno> dec_anno(DjVuAnno::create());
+ dec_anno->decode(anno);
+ const GP<ByteStream> new_anno(ByteStream::create());
+ dec_anno->encode(new_anno);
+ new_anno->seek(0);
+
+ // And store it in the file
+ djvu_file->anno=new_anno;
+ djvu_file->rebuild_data_pool();
+ if ((file_flags & (DjVuFile::DECODE_OK |
+ DjVuFile::DECODE_FAILED |
+ DjVuFile::DECODE_STOPPED))==0)
+ djvu_file->anno=0;
+ }
+ if (progress_cb)
+ progress_cb((float)(page_num/2.0/pages_num), cl_data);
+ }
+
+ // Now remove annotations from every file except for
+ // the top-level page files and SHARED_ANNO file.
+ // Unlink empty files too.
+ GPList<DjVmDir::File> files_list=djvm_dir->get_files_list();
+ int cnt;
+ GPosition pos;
+ for(pos=files_list, cnt=0;pos;++pos, cnt++)
+ {
+ GP<DjVmDir::File> frec=files_list[pos];
+ if (!frec->is_page() && frec->get_load_name()!=shared_id)
+ {
+ GP<DjVuFile> djvu_file=get_djvu_file(frec->get_load_name());
+ if (djvu_file)
+ {
+ djvu_file->remove_anno();
+ if (djvu_file->get_chunks_number()==0)
+ remove_file(frec->get_load_name(), true);
+ }
+ }
+ if (progress_cb)
+ progress_cb((float)(0.5+cnt/2.0/files_list.size()), cl_data);
+ }
+}
+
+void
+DjVuDocEditor::create_shared_anno_file(void (* progress_cb)(float progress, void *),
+ void * cl_data)
+{
+ if (djvm_dir->get_shared_anno_file())
+ G_THROW( ERR_MSG("DjVuDocEditor.share_fail") );
+
+ // Prepare file with ANTa chunk inside
+ const GP<ByteStream> gstr(ByteStream::create());
+ const GP<IFFByteStream> giff(IFFByteStream::create(gstr));
+ IFFByteStream &iff=*giff;
+ iff.put_chunk("FORM:DJVI");
+ iff.put_chunk("ANTa");
+ iff.close_chunk();
+ iff.close_chunk();
+ ByteStream &str=*gstr;
+ str.flush();
+ str.seek(0);
+ const GP<DataPool> file_pool(DataPool::create(gstr));
+
+ // Get a unique ID for the new file
+ const GUTF8String id(find_unique_id("shared_anno.iff"));
+
+ // Add it into the directory
+ GP<DjVmDir::File> frec(DjVmDir::File::create(id, id, id,
+ DjVmDir::File::SHARED_ANNO));
+ djvm_dir->insert_file(frec, 1);
+
+ // Add it to our "cache"
+ {
+ GP<File> f=new File;
+ f->pool=file_pool;
+ GCriticalSectionLock lock(&files_lock);
+ files_map[id]=f;
+ }
+
+ // Now include this shared file into every top-level page file
+ int pages_num=djvm_dir->get_pages_num();
+ for(int page_num=0;page_num<pages_num;page_num++)
+ {
+ GP<DjVuFile> djvu_file=get_djvu_file(page_num);
+ djvu_file->insert_file(id, 1);
+
+ if (progress_cb)
+ progress_cb((float) page_num/pages_num, cl_data);
+ }
+}
+
+void
+DjVuDocEditor::set_djvm_nav(GP<DjVmNav> n)
+{
+ if (n && ! n->isValidBookmark())
+ G_THROW("Invalid bookmark data");
+ djvm_nav = n;
+}
+
+GP<DjVuFile>
+DjVuDocEditor::get_shared_anno_file(void)
+{
+ GP<DjVuFile> djvu_file;
+
+ GP<DjVmDir::File> frec=djvm_dir->get_shared_anno_file();
+ if (frec)
+ djvu_file=get_djvu_file(frec->get_load_name());
+
+ return djvu_file;
+}
+
+GP<DataPool>
+DjVuDocEditor::get_thumbnail(int page_num, bool dont_decode)
+ // We override DjVuDocument::get_thumbnail() here because
+ // pages may have been shuffled and those "thumbnail file records"
+ // from the DjVmDir do not describe things correctly.
+ //
+ // So, first we will check the thumb_map[] if we have a predecoded
+ // thumbnail for the given page. If this is the case, we will
+ // return it. Otherwise we will ask DjVuDocument to generate
+ // this thumbnail for us.
+{
+ const GUTF8String id(page_to_id(page_num));
+
+ GCriticalSectionLock lock(&thumb_lock);
+ const GPosition pos(thumb_map.contains(id));
+ if (pos)
+ {
+ // Get the image from the map
+ return thumb_map[pos];
+ } else
+ {
+ unfile_thumbnails();
+ return DjVuDocument::get_thumbnail(page_num, dont_decode);
+ }
+}
+
+int
+DjVuDocEditor::get_thumbnails_num(void) const
+{
+ GCriticalSectionLock lock((GCriticalSection *) &thumb_lock);
+
+ int cnt=0;
+ int pages_num=get_pages_num();
+ for(int page_num=0;page_num<pages_num;page_num++)
+ {
+ if (thumb_map.contains(page_to_id(page_num)))
+ cnt++;
+ }
+ return cnt;
+}
+
+int
+DjVuDocEditor::get_thumbnails_size(void) const
+{
+ DEBUG_MSG("DjVuDocEditor::remove_thumbnails(): doing it\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GCriticalSectionLock lock((GCriticalSection *) &thumb_lock);
+
+ int pages_num=get_pages_num();
+ for(int page_num=0;page_num<pages_num;page_num++)
+ {
+ const GPosition pos(thumb_map.contains(page_to_id(page_num)));
+ if (pos)
+ {
+ const GP<ByteStream> gstr(thumb_map[pos]->get_stream());
+ GP<IW44Image> iwpix=IW44Image::create_decode(IW44Image::COLOR);
+ iwpix->decode_chunk(gstr);
+
+ int width=iwpix->get_width();
+ int height=iwpix->get_height();
+ return width<height ? width : height;
+ }
+ }
+ return -1;
+}
+
+void
+DjVuDocEditor::remove_thumbnails(void)
+{
+ DEBUG_MSG("DjVuDocEditor::remove_thumbnails(): doing it\n");
+ DEBUG_MAKE_INDENT(3);
+
+ unfile_thumbnails();
+
+ DEBUG_MSG("clearing thumb_map\n");
+ GCriticalSectionLock lock(&thumb_lock);
+ thumb_map.empty();
+}
+
+void
+DjVuDocEditor::unfile_thumbnails(void)
+ // Will erase all "THUMBNAILS" files from DjVmDir.
+ // This function is useful when filing thumbnails (to get rid of
+ // those files, which currently exist: they need to be replaced
+ // anyway) and when calling DjVuDocument::get_thumbnail() to
+ // be sure, that it will not use wrong information from DjVmDir
+{
+ DEBUG_MSG("DjVuDocEditor::unfile_thumbnails(): updating DjVmDir\n");
+ DEBUG_MAKE_INDENT(3);
+
+ {
+ GCriticalSectionLock lock(&threqs_lock);
+ threqs_list.empty();
+ }
+ if((const DjVmDir *)djvm_dir)
+ {
+ GPList<DjVmDir::File> xfiles_list=djvm_dir->get_files_list();
+ for(GPosition pos=xfiles_list;pos;++pos)
+ {
+ GP<DjVmDir::File> f=xfiles_list[pos];
+ if (f->is_thumbnails())
+ djvm_dir->delete_file(f->get_load_name());
+ }
+ }
+}
+
+void
+DjVuDocEditor::file_thumbnails(void)
+ // The purpose of this function is to create files containing
+ // thumbnail images and register them in DjVmDir.
+ // If some of the thumbnail images are missing, they'll
+ // be generated with generate_thumbnails()
+{
+ DEBUG_MSG("DjVuDocEditor::file_thumbnails(): updating DjVmDir\n");
+ DEBUG_MAKE_INDENT(3);
+ unfile_thumbnails();
+
+ // Generate thumbnails if they're missing due to some reason.
+ int thumb_num=get_thumbnails_num();
+ int size=thumb_num>0 ? get_thumbnails_size() : 128;
+ if (thumb_num!=get_pages_num())
+ {
+ generate_thumbnails(size);
+ }
+
+ DEBUG_MSG("filing thumbnails\n");
+
+ GCriticalSectionLock lock(&thumb_lock);
+
+ // The first thumbnail file always contains only one thumbnail
+ int ipf=1;
+ int image_num=0;
+ int page_num=0, pages_num=djvm_dir->get_pages_num();
+ GP<ByteStream> str(ByteStream::create());
+ GP<IFFByteStream> iff(IFFByteStream::create(str));
+ iff->put_chunk("FORM:THUM");
+ for(;;)
+ {
+ GUTF8String id(page_to_id(page_num));
+ const GPosition pos(thumb_map.contains(id));
+ if (! pos)
+ {
+ G_THROW( ERR_MSG("DjVuDocEditor.no_thumb") "\t"+GUTF8String(page_num));
+ }
+ iff->put_chunk("TH44");
+ iff->copy(*(thumb_map[pos]->get_stream()));
+ iff->close_chunk();
+ image_num++;
+ page_num++;
+ if (image_num>=ipf || page_num>=pages_num)
+ {
+ int i=id.rsearch('.');
+ if(i<=0)
+ {
+ i=id.length();
+ }
+ id=id.substr(0,i)+".thumb";
+ // Get unique ID for this file
+ id=find_unique_id(id);
+
+ // Create a file record with the chosen ID
+ GP<DjVmDir::File> file(DjVmDir::File::create(id, id, id,
+ DjVmDir::File::THUMBNAILS));
+
+ // Set correct file position (so that it will cover the next
+ // ipf pages)
+ int file_pos=djvm_dir->get_page_pos(page_num-image_num);
+ djvm_dir->insert_file(file, file_pos);
+
+ // Now add the File record (containing the file URL and DataPool)
+ // After we do it a simple save_as() will save the document
+ // with the thumbnails. This is because DjVuDocument will see
+ // the file in DjVmDir and will ask for data. We will intercept
+ // the request for data and will provide this DataPool
+ iff->close_chunk();
+ str->seek(0);
+ const GP<DataPool> file_pool(DataPool::create(str));
+ GP<File> f=new File;
+ f->pool=file_pool;
+ GCriticalSectionLock lock(&files_lock);
+ files_map[id]=f;
+
+ // And create new streams
+ str=ByteStream::create();
+ iff=IFFByteStream::create(str);
+ iff->put_chunk("FORM:THUM");
+ image_num=0;
+
+ // Reset ipf to correct value (after we stored first
+ // "exceptional" file with thumbnail for the first page)
+ if (page_num==1) ipf=thumbnails_per_file;
+ if (page_num>=pages_num) break;
+ }
+ }
+}
+
+int
+DjVuDocEditor::generate_thumbnails(int thumb_size, int page_num)
+{
+ DEBUG_MSG("DjVuDocEditor::generate_thumbnails(): doing it\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if(page_num<(djvm_dir->get_pages_num()))
+ {
+ const GUTF8String id(page_to_id(page_num));
+ if (!thumb_map.contains(id))
+ {
+ const GP<DjVuImage> dimg(get_page(page_num, true));
+
+ GRect rect(0, 0, thumb_size, dimg->get_height()*thumb_size/dimg->get_width());
+ GP<GPixmap> pm=dimg->get_pixmap(rect, rect, get_thumbnails_gamma());
+ if (!pm)
+ {
+ const GP<GBitmap> bm(dimg->get_bitmap(rect, rect, sizeof(int)));
+ if (bm)
+ pm = GPixmap::create(*bm);
+ else
+ pm = GPixmap::create(rect.height(), rect.width(), &GPixel::WHITE);
+ }
+ // Store and compress the pixmap
+ const GP<IW44Image> iwpix(IW44Image::create_encode(*pm));
+ const GP<ByteStream> gstr(ByteStream::create());
+ IWEncoderParms parms;
+ parms.slices=97;
+ parms.bytes=0;
+ parms.decibels=0;
+ iwpix->encode_chunk(gstr, parms);
+ gstr->seek(0L);
+ thumb_map[id]=DataPool::create(gstr);
+ }
+ ++page_num;
+ }
+ else
+ {
+ page_num = -1;
+ }
+ return page_num;
+}
+
+void
+DjVuDocEditor::generate_thumbnails(int thumb_size,
+ bool (* cb)(int page_num, void *),
+ void * cl_data)
+{
+ int page_num=0;
+ do
+ {
+ page_num=generate_thumbnails(thumb_size,page_num);
+ if (cb) if (cb(page_num, cl_data)) return;
+ } while(page_num>=0);
+}
+
+static void
+store_file(const GP<DjVmDir> & src_djvm_dir, const GP<DjVmDoc> & djvm_doc,
+ GP<DjVuFile> & djvu_file, GMap<GURL, void *> & map)
+{
+ GURL url=djvu_file->get_url();
+ if (!map.contains(url))
+ {
+ map[url]=0;
+
+ // Store included files first
+ GPList<DjVuFile> djvu_files_list=djvu_file->get_included_files(false);
+ for(GPosition pos=djvu_files_list;pos;++pos)
+ store_file(src_djvm_dir, djvm_doc, djvu_files_list[pos], map);
+
+ // Now store contents of this file
+ GP<DataPool> file_data=djvu_file->get_djvu_data(false);
+ GP<DjVmDir::File> frec=src_djvm_dir->name_to_file(url.name());
+ if (frec)
+ {
+ frec=new DjVmDir::File(*frec);
+ djvm_doc->insert_file(frec, file_data, -1);
+ }
+ }
+}
+
+void
+DjVuDocEditor::save_pages_as(
+ const GP<ByteStream> &str, const GList<int> & _page_list)
+{
+ GList<int> page_list=sortList(_page_list);
+
+ GP<DjVmDoc> djvm_doc=DjVmDoc::create();
+ GMap<GURL, void *> map;
+ for(GPosition pos=page_list;pos;++pos)
+ {
+ GP<DjVmDir::File> frec=djvm_dir->page_to_file(page_list[pos]);
+ if (frec)
+ {
+ GP<DjVuFile> djvu_file=get_djvu_file(frec->get_load_name());
+ if (djvu_file)
+ store_file(djvm_dir, djvm_doc, djvu_file, map);
+ }
+ }
+ djvm_doc->write(str);
+}
+
+void
+DjVuDocEditor::save_file(const GUTF8String &file_id, const GURL &codebase,
+ const bool only_modified, GMap<GUTF8String,GUTF8String> & map)
+{
+ if(only_modified)
+ {
+ for(GPosition pos=files_map;pos;++pos)
+ {
+ const GP<File> file_rec(files_map[pos]);
+ const bool file_modified=file_rec->pool ||
+ (file_rec->file && file_rec->file->is_modified());
+ if(!file_modified)
+ {
+ const GUTF8String id=files_map.key(pos);
+ const GUTF8String save_name(djvm_dir->id_to_file(id)->get_save_name());
+ if(id == save_name)
+ {
+ map[id]=id;
+ }
+ }
+ }
+ }
+ save_file(file_id,codebase,map);
+}
+
+void
+DjVuDocEditor::save_file(
+ const GUTF8String &file_id, const GURL &codebase,
+ GMap<GUTF8String,GUTF8String> & map)
+{
+ DEBUG_MSG("DjVuDocEditor::save_file(): ID='" << file_id << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (!map.contains(file_id))
+ {
+ const GP<DjVmDir::File> file(djvm_dir->id_to_file(file_id));
+
+ GP<DataPool> file_pool;
+ const GPosition pos(files_map.contains(file_id));
+ if (pos)
+ {
+ const GP<File> file_rec(files_map[pos]);
+ if (file_rec->file)
+ file_pool=file_rec->file->get_djvu_data(false);
+ else
+ file_pool=file_rec->pool;
+ }
+
+ if (!file_pool)
+ {
+ DjVuPortcaster * pcaster=DjVuPort::get_portcaster();
+ file_pool=pcaster->request_data(this, id_to_url(file_id));
+ }
+
+ if (file_pool)
+ {
+ GMap<GUTF8String,GUTF8String> incl;
+ map[file_id]=get_djvm_doc()->save_file(codebase,*file,incl,file_pool);
+ for(GPosition pos=incl;pos;++pos)
+ {
+ save_file(incl.key(pos),codebase ,map);
+ }
+ }else
+ {
+ map[file_id]=file->get_save_name();
+ }
+ }
+}
+
+void
+DjVuDocEditor::save(void)
+{
+ DEBUG_MSG("DjVuDocEditor::save(): saving the file\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (!can_be_saved())
+ G_THROW( ERR_MSG("DjVuDocEditor.cant_save") );
+ save_as(GURL(), orig_doc_type!=INDIRECT);
+}
+
+void
+DjVuDocEditor::write(const GP<ByteStream> &gbs, bool force_djvm)
+{
+ DEBUG_MSG("DjVuDocEditor::write()\n");
+ DEBUG_MAKE_INDENT(3);
+ if (get_thumbnails_num()==get_pages_num())
+ {
+ file_thumbnails();
+ }else
+ {
+ remove_thumbnails();
+ }
+ clean_files_map();
+ DjVuDocument::write(gbs,force_djvm);
+}
+
+void
+DjVuDocEditor::write(
+ const GP<ByteStream> &gbs,const GMap<GUTF8String,void *> &reserved)
+{
+ DEBUG_MSG("DjVuDocEditor::write()\n");
+ DEBUG_MAKE_INDENT(3);
+ if (get_thumbnails_num()==get_pages_num())
+ {
+ file_thumbnails();
+ }else
+ {
+ remove_thumbnails();
+ }
+ clean_files_map();
+ DjVuDocument::write(gbs,reserved);
+}
+
+void
+DjVuDocEditor::save_as(const GURL &where, bool bundled)
+{
+ DEBUG_MSG("DjVuDocEditor::save_as(): where='" << where << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ // First see if we need to generate (or just reshuffle) thumbnails...
+ // If we have an icon for every page, we will just call
+ // file_thumbnails(), which will update DjVmDir and will create
+ // the actual bundles with thumbnails (very fast)
+ // Otherwise we will remove the thumbnails completely because
+ // we really don't want to deal with documents, which have only
+ // some of their pages thumbnailed.
+ if (get_thumbnails_num()==get_pages_num())
+ {
+ file_thumbnails();
+ }else
+ {
+ remove_thumbnails();
+ }
+
+ GURL save_doc_url;
+
+ if (where.is_empty())
+ {
+ // Assume, that we just want to 'save'. Check, that it's possible
+ // and proceed.
+ bool can_be_saved_bundled=orig_doc_type==BUNDLED ||
+ orig_doc_type==OLD_BUNDLED ||
+ orig_doc_type==SINGLE_PAGE ||
+ orig_doc_type==OLD_INDEXED && orig_doc_pages==1;
+ if ((bundled ^ can_be_saved_bundled)!=0)
+ G_THROW( ERR_MSG("DjVuDocEditor.cant_save2") );
+ save_doc_url=doc_url;
+ } else
+ {
+ save_doc_url=where;
+ }
+
+ int save_doc_type=bundled ? BUNDLED : INDIRECT;
+
+ clean_files_map();
+
+ GCriticalSectionLock lock(&files_lock);
+
+ DjVuPortcaster * pcaster=DjVuPort::get_portcaster();
+
+ // First consider saving in SINGLE_FILE format (one file)
+ if(needs_compression())
+ {
+ DEBUG_MSG("Compressing on output\n");
+ remove_thumbnails();
+ if(! djvu_compress_codec)
+ {
+ G_THROW( ERR_MSG("DjVuDocEditor.no_codec") );
+ }
+ const GP<DjVmDoc> doc(get_djvm_doc());
+ GP<ByteStream> mbs(ByteStream::create());
+ doc->write(mbs);
+ mbs->flush();
+ mbs->seek(0,SEEK_SET);
+ djvu_compress_codec(mbs,save_doc_url,(!(const DjVmDir *)djvm_dir)||(djvm_dir->get_files_num()==1)||(save_doc_type!=INDIRECT));
+ files_map.empty();
+ doc_url=GURL();
+ }else
+ {
+ if (djvm_dir->get_files_num()==1)
+ {
+ // Here 'bundled' has no effect: we will save it as one page.
+ DEBUG_MSG("saving one file...\n");
+ GURL file_url=page_to_url(0);
+ const GUTF8String file_id(djvm_dir->page_to_file(0)->get_load_name());
+ GP<DataPool> file_pool;
+ GPosition pos=files_map.contains(file_id);
+ if (pos)
+ {
+ const GP<File> file_rec(files_map[pos]);
+ if (file_rec->pool && (!file_rec->file ||
+ !file_rec->file->is_modified()))
+ {
+ file_pool=file_rec->pool;
+ }else if (file_rec->file)
+ {
+ file_pool=file_rec->file->get_djvu_data(false);
+ }
+ }
+ // Even if file has not been modified (pool==0) we still want
+ // to save it.
+ if (!file_pool)
+ file_pool=pcaster->request_data(this, file_url);
+ if (file_pool)
+ {
+ DEBUG_MSG("Saving '" << file_url << "' to '" << save_doc_url << "'\n");
+ DataPool::load_file(save_doc_url);
+ const GP<ByteStream> gstr_out(ByteStream::create(save_doc_url, "wb"));
+ ByteStream &str_out=*gstr_out;
+ str_out.writall(octets, 4);
+ const GP<ByteStream> str_in(file_pool->get_stream());
+ str_out.copy(*str_in);
+ }
+
+ // Update the document's DataPool (to save memory)
+ const GP<DjVmDoc> doc(get_djvm_doc());
+ const GP<ByteStream> gstr=ByteStream::create();// One page: we can do it in the memory
+ doc->write(gstr);
+ gstr->seek(0, SEEK_SET);
+ const GP<DataPool> pool(DataPool::create(gstr));
+ doc_pool=pool;
+ init_data_pool=pool;
+
+ // Also update DjVmDir (to reflect changes in offsets)
+ djvm_dir=doc->get_djvm_dir();
+ } else if (save_doc_type==INDIRECT)
+ {
+ DEBUG_MSG("Saving in INDIRECT format to '" << save_doc_url << "'\n");
+ bool save_only_modified=!(save_doc_url!=doc_url || save_doc_type!=orig_doc_type);
+ GPList<DjVmDir::File> xfiles_list=djvm_dir->resolve_duplicates(false);
+ const GURL codebase=save_doc_url.base();
+ int pages_num=djvm_dir->get_pages_num();
+ GMap<GUTF8String, GUTF8String> map;
+ // First go thru the pages
+ for(int page_num=0;page_num<pages_num;page_num++)
+ {
+ const GUTF8String id(djvm_dir->page_to_file(page_num)->get_load_name());
+ save_file(id, codebase, save_only_modified, map);
+ }
+ // Next go thru thumbnails and similar stuff
+ GPosition pos;
+ for(pos=xfiles_list;pos;++pos)
+ save_file(xfiles_list[pos]->get_load_name(), codebase, save_only_modified, map);
+
+ // Finally - save the top-level index file
+ for(pos=xfiles_list;pos;++pos)
+ {
+ const GP<DjVmDir::File> file(xfiles_list[pos]);
+ file->offset=0;
+ file->size=0;
+ }
+ DataPool::load_file(save_doc_url);
+ const GP<ByteStream> gstr(ByteStream::create(save_doc_url, "wb"));
+ const GP<IFFByteStream> giff(IFFByteStream::create(gstr));
+ IFFByteStream &iff=*giff;
+
+ iff.put_chunk("FORM:DJVM", 1);
+ iff.put_chunk("DIRM");
+ djvm_dir->encode(giff->get_bytestream());
+ iff.close_chunk();
+ iff.close_chunk();
+ iff.flush();
+
+ // Update the document data pool (not required, but will save memory)
+ doc_pool=DataPool::create(save_doc_url);
+ init_data_pool=doc_pool;
+
+ // No reason to update DjVmDir as for this format it doesn't
+ // contain DJVM offsets
+ } else if (save_doc_type==BUNDLED || save_doc_type==OLD_BUNDLED)
+ {
+ DEBUG_MSG("Saving in BUNDLED format to '" << save_doc_url << "'\n");
+
+ // Can't be very smart here. Simply overwrite the file.
+ const GP<DjVmDoc> doc(get_djvm_doc());
+ DataPool::load_file(save_doc_url);
+ const GP<ByteStream> gstr(ByteStream::create(save_doc_url, "wb"));
+ doc->write(gstr);
+ gstr->flush();
+
+ // Update the document data pool (not required, but will save memory)
+ doc_pool=DataPool::create(save_doc_url);
+ init_data_pool=doc_pool;
+
+ // Also update DjVmDir (to reflect changes in offsets)
+ djvm_dir=doc->get_djvm_dir();
+ } else
+ {
+ G_THROW( ERR_MSG("DjVuDocEditor.cant_save") );
+ }
+
+ // Now, after we have saved the document w/o any error, detach DataPools,
+ // which are in the 'File's list to save memory. Detach everything.
+ // Even in the case when File->file is non-zero. If File->file is zero,
+ // remove the item from the list at all. If it's non-zero, it has
+ // to stay there because by definition files_map[] contains the list
+ // of all active files and customized DataPools
+ //
+ // In addition to it, look thru all active files and change their URLs
+ // to reflect changes in the document's URL (if there was a change)
+ // Another reason why file's URLs must be changed is that we may have
+ // saved the document in a different format, which changes the rules
+ // of file url composition.
+ for(GPosition pos=files_map;pos;)
+ {
+ const GP<File> file_rec(files_map[pos]);
+ file_rec->pool=0;
+ if (file_rec->file==0)
+ {
+ GPosition this_pos=pos;
+ ++pos;
+ files_map.del(this_pos);
+ } else
+ {
+ // Change the file's url;
+ if (doc_url!=save_doc_url ||
+ orig_doc_type!=save_doc_type)
+ if (save_doc_type==BUNDLED)
+ file_rec->file->move(save_doc_url);
+ else file_rec->file->move(save_doc_url.base());
+ ++pos;
+ }
+ }
+
+ }
+ orig_doc_type=save_doc_type;
+ doc_type=save_doc_type;
+
+ if (doc_url!=save_doc_url)
+ {
+ // Also update document's URL (we moved, didn't we?)
+ doc_url=save_doc_url;
+ init_url=save_doc_url;
+ }
+}
+
+GP<DjVuDocEditor>
+DjVuDocEditor::create_wait(void)
+{
+ DjVuDocEditor *doc=new DjVuDocEditor();
+ const GP<DjVuDocEditor> retval(doc);
+ doc->init();
+ return retval;
+}
+
+GP<DjVuDocEditor>
+DjVuDocEditor::create_wait(const GURL &url)
+{
+ DjVuDocEditor *doc=new DjVuDocEditor();
+ const GP<DjVuDocEditor> retval(doc);
+ doc->init(url);
+ return retval;
+}
+
+bool
+DjVuDocEditor::inherits(const GUTF8String &class_name) const
+{
+ return (class_name == "DjVuDocEditor")||DjVuDocument::inherits(class_name);
+}
+
+int
+DjVuDocEditor::get_orig_doc_type(void) const
+{
+ return orig_doc_type;
+}
+
+bool
+DjVuDocEditor::can_be_saved(void) const
+{
+ return !(needs_rename()||needs_compression()||orig_doc_type==UNKNOWN_TYPE ||
+ orig_doc_type==OLD_INDEXED);
+}
+
+int
+DjVuDocEditor::get_save_doc_type(void) const
+{
+ if (orig_doc_type==SINGLE_PAGE)
+ if (djvm_dir->get_files_num()==1)
+ return SINGLE_PAGE;
+ else
+ return BUNDLED;
+ else if (orig_doc_type==INDIRECT)
+ return INDIRECT;
+ else if (orig_doc_type==OLD_BUNDLED || orig_doc_type==BUNDLED)
+ return BUNDLED;
+ else
+ return UNKNOWN_TYPE;
+}
+
+GURL
+DjVuDocEditor::get_doc_url(void) const
+{
+ return doc_url.is_empty() ? init_url : doc_url;
+}
+
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuDocEditor.h b/kviewshell/plugins/djvu/libdjvu/DjVuDocEditor.h
new file mode 100644
index 00000000..7bf6124a
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuDocEditor.h
@@ -0,0 +1,460 @@
+//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: DjVuDocEditor.h,v 1.9 2005/05/25 20:24:52 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _DJVUDOCEDITOR_H
+#define _DJVUDOCEDITOR_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+#include "DjVuDocument.h"
+#include "DjVmDoc.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+/** @name DjVuDocEditor.h
+ Files #"DjVuDocEditor.h"# and #"DjVuDocEditor.cpp"# contain extension
+ of \Ref{DjVuDocument} class, which can create and modify existing
+ DjVu document, generate thumbnails, etc. It does {\bf not} do
+ compression though.
+
+ @memo DjVu document editor class.
+ @author Andrei Erofeev <eaf@geocities.com>
+ @version #$Id: DjVuDocEditor.h,v 1.9 2005/05/25 20:24:52 leonb Exp $#
+*/
+
+//@{
+
+/** #DjVuDocEditor# is an extension of \Ref{DjVuDocument} class with
+ additional capabilities for editing the document contents.
+
+ It can be used to:
+ \begin{enumerate}
+ \item Create (compose) new multipage DjVu documents using single
+ page DjVu documents. The class does {\bf not} do compression.
+ \item Insert and remove different pages of multipage DjVu documents.
+ \item Change attributes ({\em names}, {\em IDs} and {\em titles})
+ of files composing the DjVu document.
+ \item Generate thumbnail images and integrate them into the document.
+ \end{enumerate}
+*/
+
+class DjVuDocEditor : public DjVuDocument
+{
+public:
+ static int thumbnails_per_file;
+
+protected:
+ /// Default constructor
+ DjVuDocEditor(void);
+
+ /** Initialization function. Initializes an empty document.
+
+ {\bf Note}: You must call either of the two
+ available \Ref{init}() function before you start doing
+ anything else with the #DjVuDocEditor#. */
+ void init(void);
+
+ /** Initialization function. Opens document with name #filename#.
+
+ {\bf Note}: You must call either of the two
+ available \Ref{init}() function before you start doing
+ anything else with the #DjVuDocEditor#. */
+ void init(const GURL &url);
+
+public:
+ /** Creates a DjVuDocEditor class and initializes with #fname#. */
+ static GP<DjVuDocEditor> create_wait(const GURL &url);
+
+ /** Creates a DjVuDocEditor class and initializes an empty document. */
+ static GP<DjVuDocEditor> create_wait(void);
+
+
+ /// Destructor
+ virtual ~DjVuDocEditor(void);
+
+ /** Returns type of open document. #DjVuDocEditor# silently
+ converts any open DjVu document to #BUNDLED# format (see
+ \Ref{DjVuDocument}. Thus, \Ref{DjVuDocument::get_doc_type}()
+ will always be returning #BUNDLED#. Use this function to
+ learn the original format of the document being edited. */
+ int get_orig_doc_type(void) const;
+
+ /** Returns #TRUE# if the document can be "saved" (sometimes
+ the only possibility is to do a "save as"). The reason why
+ we have this function is that #DjVuDocEditor# can save
+ documents in new formats only (#BUNDLED# and #INDIRECT#).
+ At the same time it recognizes all DjVu formats (#OLD_BUNDLED#,
+ #OLD_INDEXED#, #BUNDLED#, and #INDIRECT#).
+
+ #OLD_BUNDLED# and #BUNDLED# documents occupy only one file,
+ so in this case "saving" involves the automatic conversion
+ to #BUNDLED# format and storing data into the same file.
+
+ #OLD_INDEXED# documents, on the other hand, occupy more
+ than one file. They could be converted to #INDIRECT# format
+ if these two formats had the same set of files. Unfortunately,
+ these formats are too different, and the best thing to do
+ is to use "save as" capability. */
+ bool can_be_saved(void) const;
+
+ /** Returns type of the document, which can be created by
+ \Ref{save}() function. Can be #INDIRECT#, #BUNDLED#,
+ #SINGLE_PAGE#, or #UNKNOWN_TYPE#. The latter indicates,
+ that \Ref{save}() will fail, and that \Ref{save_as}()
+ should be used instead */
+ int get_save_doc_type(void) const;
+
+ /** Saves the document. May generate exception if the document
+ can not be saved, and \Ref{save_as}() should be used.
+ See \Ref{can_be_saved}() for details. */
+ void save(void);
+
+ /** Saves the document. */
+ virtual void save_as(const GURL &where, bool bundled);
+
+ /** Saves the document in the {\em new bundled} format. All the data
+ is "bundled" into one file and this file is written into the
+ passed stream.
+
+ If #force_djvm# is #TRUE# then even one page documents will be
+ saved in the #DJVM BUNDLED# format (inside a #FORM:DJVM#);
+
+ {\bf Plugin Warning}. This function will read contents of the whole
+ document. Thus, if you call it from the main thread (the thread,
+ which transfers data from Netscape), the plugin will block. */
+ virtual void write(const GP<ByteStream> &str, bool force_djvm=false);
+ /** Always save as bundled, renaming any files conflicting with the
+ the names in the supplied GMap. */
+ virtual void write(const GP<ByteStream> &str,
+ const GMap<GUTF8String,void *> &reserved);
+
+ /** Saves the specified pages in DjVu #BUNDLED# multipage document. */
+ void save_pages_as(
+ const GP<ByteStream> &str, const GList<int> & page_list);
+
+ /** Translates page number #page_num# to ID. If #page_num# is invalid,
+ an exception is thrown. */
+ GUTF8String page_to_id(int page_num) const;
+
+ GUTF8String insert_file(const GURL &url, const GUTF8String &parent_id,
+ int chunk_num=1, DjVuPort *source=0);
+ /** Inserts the referenced file into this DjVu document.
+
+ @param fname Name of the top-level file containing the image of
+ the page to be inserted. This file must be a DjVu file and
+ may include one or more other DjVu files.
+
+ If it include other DjVu files, the function will try to
+ insert them into the document too. Should this attempt fail,
+ the corresponding #INCL# chunk will be removed from the
+ referencing file and an exception will be thrown.
+
+ When inserting a file, the function may modify its name
+ to be unique in the DjVu document.
+ @param page_num Position where the new page should be inserted at.
+ Negative value means "append" */
+ void insert_page(const GURL &fname, int page_num=-1);
+ /** Inserts a new page with data inside the #data_pool# as page
+ number #page_num.
+
+ @param data_pool \Ref{DataPool} with data for this page.
+ @param file_name Name, which will be assigned to this page.
+ If you try to save the document in #INDIRECT# format,
+ a file with this name will be created to hold the
+ page's data. If there is already a file in the document
+ with the same name, the function will derive a new
+ unique name from file_name, which will be assigned
+ to the page.
+ @param page_num Describes where the page should be inserted.
+ Negative number means "append". */
+ void insert_page(GP<DataPool> & file_pool,
+ const GURL &fname, int page_num=-1);
+ /** Inserts a group of pages into this DjVu document.
+
+ Like \Ref{insert_page}() it will insert every page into the document.
+ The main advantage of calling this function once for the whole
+ group instead of calling \Ref{insert_page}() for every page is
+ the processing of included files:
+
+ The group of files may include one or more files, which are thus
+ shared by them. If you call \Ref{insert_page}() for every page,
+ this shared file will be inserted into the document more than once
+ though under different names. This is how \Ref{insert_page}() works:
+ whenever it inserts something, it checks for duplicate names with
+ only one purpose: invent a new name if a given one is already in
+ use.
+
+ On the other hand, if you call #insert_group#(), it will insert
+ shared included files only once. This is because it can analyze
+ the group of files before inserting them and figure out what files
+ are shared and thus should be inserted only once.
+
+ @param fname_list List of top-level files for the pages to be inserted
+ @param page_num Position where the new pages should be inserted at.
+ Negative value means "append" */
+ void insert_group(const GList<GURL> & furl_list, int page_num=-1,
+ void (* refresh_cb)(void *)=0, void * cl_data=0);
+ /** Removes the specified page from the document. If #remove_unref#
+ is #TRUE#, the function will also remove from the document any file,
+ which became unreferenced due to the page's removal */
+ void remove_page(int page_num, bool remove_unref=true);
+ /** Removes the specified pages from the document. If #remove_unref#
+ is #TRUE#, the function will also remove from the document any file,
+ which became unreferenced due to the pages' removal */
+ void remove_pages(const GList<int> & page_list, bool remove_unref=true);
+ /** Removes a DjVu file with the specified #id#.
+
+ If some other files include this file, the corresponding #INCL#
+ chunks will be removed to avoid dead links.
+
+ If #remove_unref# is #TRUE#, the function will also remove every
+ file, which will become unreferenced after the removal of this file. */
+ void remove_file(const GUTF8String &id, bool remove_unref=true);
+ /** Makes page number #page_num# to be #new_page_num#. If #new_page_num#
+ is negative or too big, the function will move page #page_num# to
+ the end of the document. */
+ void move_page(int page_num, int new_page_num);
+ /** Shifts all pags from the #page_list# according to the #shift#.
+ The #shift# can be positive (shift toward the end of the document)
+ or negative (shift toward the beginning of the document).
+
+ It is OK to make #shift# too big in value. Pages will just be
+ moved to the end (or to the beginning, depending on the #shift#
+ sign) of the document. */
+ void move_pages(const GList<int> & page_list, int shift);
+
+ /** Changes the name of the file with ID #id# to #name#.
+ Refer to \Ref{DjVmDir} for the explanation of {\em IDs},
+ {\em names} and {\em titles}. */
+ void set_file_name(const GUTF8String &id, const GUTF8String &name);
+ /** Changes the name of the page #page_num# to #name#.
+ Refer to \Ref{DjVmDir} for the explanation of {\em IDs},
+ {\em names} and {\em titles}. */
+ void set_page_name(int page_num, const GUTF8String &name);
+ /** Changes the title of the file with ID #id# to #title#.
+ Refer to \Ref{DjVmDir} for the explanation of {\em IDs},
+ {\em names} and {\em titles}. */
+ void set_file_title(const GUTF8String &id, const GUTF8String &title);
+ /** Changes the title of the page #page_num# to #title#.
+ Refer to \Ref{DjVmDir} for the explanation of {\em IDs},
+ {\em names} and {\em titles}. */
+ void set_page_title(int page_num, const GUTF8String &title);
+
+ /** @name Thumbnails */
+ //@{
+ /** Returns the number of thumbnails stored inside this document.
+
+ It may be #ZERO#, which means, that there are no thumbnails at all.
+
+ It may be equal to the number of pages, which is what should
+ normally be.
+
+ Finally, it may be greater than #ZERO# and less than the number
+ of pages, in which case thumbnails should be regenerated before
+ the document can be saved. */
+ int get_thumbnails_num(void) const;
+
+ /** Returns the size of the first encountered thumbnail image. Since
+ thumbnails can currently be generated by \Ref{generate_thumbnails}()
+ only, all thumbnail images should be of the same size. Thus,
+ the number returned is actually the size of {\em all}
+ document thumbnails.
+
+ The function will return #-1# if there are no thumbnails. */
+ int get_thumbnails_size(void) const;
+
+ /** Removes all thumbnails from the document */
+ void remove_thumbnails(void);
+
+ /** Generates thumbnails for the specified page, if and only if
+ it does not have a thumbnail yet. If you want to regenerate
+ thumbnails for all pages, call \Ref{remove_thumbnails}() prior
+ to calling this function.
+
+ @param thumb_size The size of the thumbnails in pixels. DjVu viewer
+ is able to rescale the thumbnail images if necessary, so this
+ parameter affects thumbnails quality only. 128 is a good number.
+ @param page_num The page number to genate the thumbnail for. */
+ int generate_thumbnails(int thumb_size, int page_num);
+
+ /** Generates thumbnails for those pages, which do not have them yet.
+ If you want to regenerate thumbnails for all pages, call
+ \Ref{remove_thumbnails}() prior to calling this function.
+
+ @param thumb_size The size of the thumbnails in pixels. DjVu viewer
+ is able to rescale the thumbnail images if necessary, so this
+ parameter affects thumbnails quality only. 128 is a good number.
+ @param cb The callback, which will be called after thumbnail image
+ for the next page has been generated. Regardless of if
+ the document already has thumbnail images for some of its
+ pages, the callback will be called #pages_num# times, where
+ #pages_num# is the total number of pages in the document.
+ The callback should return #FALSE# if thumbnails generating
+ should proceed. #TRUE# will stop it. */
+ void generate_thumbnails(int thumb_size,
+ bool (* cb)(int page_num, void *)=0,
+ void * cl_data=0);
+ //@}
+ /** Use this function to simplify annotations in the document.
+ The "simplified" format is when annotations are only allowed
+ either in top-level page files or in a special file with
+ #SHARED_ANNO# flag on. This file is supposed to be included into
+ every page. */
+ void simplify_anno(void (* progress_cb)(float progress, void *)=0,
+ void * cl_data=0);
+
+ /** Will create a file that will be included into every page and
+ marked with the #SHARED_ANNO# flag. This file can be used
+ to store global annotations (annotations applicable to every page).
+
+ {\bf Note:} There may be only one #SHARED_ANNO# file in any
+ DjVu multipage document. */
+ void create_shared_anno_file(void (* progress_cb)(float progress, void *)=0,
+ void * cl_data=0);
+
+ /** Sets bookmark data */
+ void set_djvm_nav(GP<DjVmNav> nav);
+
+ /** Returns a pointer to the file with #SHARED_ANNO# flag on.
+ This file should be used for storing document-wide annotations.
+
+ {\bf Note:} There may be only one #SHARED_ANNO# file in any
+ DjVu multipage document. */
+ GP<DjVuFile> get_shared_anno_file(void);
+
+ GURL get_doc_url(void) const;
+
+ /** Returns TRUE if #class_name# is #"DjVuDocEditor"#,
+ #"DjVuDocument"# or #"DjVuPort"# */
+ virtual bool inherits(const GUTF8String &class_name) const;
+ virtual GP<DataPool> request_data(const DjVuPort * source, const GURL & url);
+protected:
+ virtual GP<DjVuFile> url_to_file(const GURL & url, bool dont_create) const;
+ virtual GP<DataPool> get_thumbnail(int page_num, bool dont_decode);
+ friend class CThumbNails;
+public:
+ class File;
+private:
+ bool initialized;
+ GURL doc_url;
+ GP<DataPool> doc_pool;
+ GURL tmp_doc_url;
+ int orig_doc_type;
+ int orig_doc_pages;
+
+ GPMap<GUTF8String, File> files_map; // files_map[id]=GP<File>
+ GCriticalSection files_lock;
+
+ GPMap<GUTF8String,DataPool> thumb_map;
+ GCriticalSection thumb_lock;
+
+ void (* refresh_cb)(void *);
+ void * refresh_cl_data;
+
+ void check(void);
+ GUTF8String find_unique_id(GUTF8String id);
+ GP<DataPool> strip_incl_chunks(const GP<DataPool> & pool);
+ void clean_files_map(void);
+ bool insert_file_type(const GURL &file_url,
+ DjVmDir::File::FILE_TYPE page_type,
+ int & file_pos,
+ GMap<GUTF8String, GUTF8String> & name2id);
+ bool insert_file( const GP<DataPool> &pool,
+ const GURL &file_url, bool is_page,
+ int & file_pos,
+ GMap<GUTF8String,GUTF8String> & name2id,
+ DjVuPort *source=0 );
+ bool insert_file(
+ const GURL &file_url, bool is_page,
+ int & file_pos,
+ GMap<GUTF8String,GUTF8String> & name2id,
+ DjVuPort *source=0 );
+ void remove_file(const GUTF8String &id, bool remove_unref,
+ GMap<GUTF8String, void *> & ref_map);
+ void generate_ref_map(const GP<DjVuFile> & file,
+ GMap<GUTF8String, void *> & ref_map,
+ GMap<GURL, void *> & visit_map);
+ void move_file(const GUTF8String &id, int & file_pos,
+ GMap<GUTF8String, void *> & map);
+ void unfile_thumbnails(void);
+ void file_thumbnails(void);
+ void save_file(const GUTF8String &id, const GURL &codebase,
+ const bool only_modified, GMap<GUTF8String, GUTF8String> & map);
+ void save_file(const GUTF8String &id, const GURL &codebase,
+ GMap<GUTF8String, GUTF8String> & map);
+};
+
+//@}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
+
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuDocument.cpp b/kviewshell/plugins/djvu/libdjvu/DjVuDocument.cpp
new file mode 100644
index 00000000..3b33d943
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuDocument.cpp
@@ -0,0 +1,1845 @@
+//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: DjVuDocument.cpp,v 1.13 2005/05/25 20:24:52 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "DjVuDocument.h"
+#include "DjVmDoc.h"
+#include "DjVmDir0.h"
+#include "DjVmNav.h"
+#include "DjVuNavDir.h"
+#include "DjVuImage.h"
+#include "DjVuFileCache.h"
+#include "IFFByteStream.h"
+#include "GOS.h"
+#include "DataPool.h"
+#include "IW44Image.h"
+#include "GRect.h"
+
+#include "debug.h"
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+static const char octets[4]={0x41,0x54,0x26,0x54};
+const float DjVuDocument::thumb_gamma=(float)2.20;
+
+void (* DjVuDocument::djvu_import_codec)(
+ GP<DataPool> &pool, const GURL &url, bool &needs_compression,
+ bool &needs_rename )=0;
+
+void (* DjVuDocument::djvu_compress_codec)(
+ GP<ByteStream> &doc,const GURL &where,bool bundled)=0;
+
+void
+DjVuDocument::set_import_codec(
+ void (*codec)(
+ GP<DataPool> &pool, const GURL &url, bool &needs_compression, bool &needs_rename ))
+{
+ djvu_import_codec=codec;
+}
+
+void
+DjVuDocument::set_compress_codec(
+ void (* codec)(
+ GP<ByteStream> &doc,const GURL &where,bool bundled))
+{
+ djvu_compress_codec=codec;
+}
+
+DjVuDocument::DjVuDocument(void)
+ : doc_type(UNKNOWN_TYPE),
+ needs_compression_flag(false),
+ can_compress_flag(false),
+ needs_rename_flag(false),
+ has_url_names(false),
+ recover_errors(ABORT),
+ verbose_eof(false),
+ init_started(false),
+ cache(0)
+{
+}
+
+GP<DjVuDocument>
+DjVuDocument::create(
+ GP<DataPool> pool, GP<DjVuPort> xport, DjVuFileCache * const xcache)
+{
+ DjVuDocument *doc=new DjVuDocument;
+ GP<DjVuDocument> retval=doc;
+ doc->init_data_pool=pool;
+ doc->start_init(GURL(),xport,xcache);
+ return retval;
+}
+
+GP<DjVuDocument>
+DjVuDocument::create(
+ const GP<ByteStream> &bs, GP<DjVuPort> xport, DjVuFileCache * const xcache)
+{
+ return create(DataPool::create(bs),xport,xcache);
+}
+
+GP<DjVuDocument>
+DjVuDocument::create_wait(
+ const GURL &url, GP<DjVuPort> xport, DjVuFileCache * const xcache)
+{
+ GP<DjVuDocument> retval=create(url,xport,xcache);
+ retval->wait_for_complete_init();
+ return retval;
+}
+
+void
+DjVuDocument::start_init(
+ const GURL & url, GP<DjVuPort> xport, DjVuFileCache * xcache)
+{
+ DEBUG_MSG("DjVuDocument::start_init(): initializing class...\n");
+ DEBUG_MAKE_INDENT(3);
+ if (init_started)
+ G_THROW( ERR_MSG("DjVuDocument.2nd_init") );
+ if (!get_count())
+ G_THROW( ERR_MSG("DjVuDocument.not_secure") );
+ if(url.is_empty())
+ {
+ if (!init_data_pool)
+ G_THROW( ERR_MSG("DjVuDocument.empty_url") );
+ if(init_url.is_empty())
+ {
+ init_url=invent_url("document.djvu");
+ }
+ }else
+ {
+ init_url=url;
+ }
+
+ // Initialize
+ cache=xcache;
+ doc_type=UNKNOWN_TYPE;
+ DjVuPortcaster * pcaster=get_portcaster();
+ if (!xport)
+ xport=simple_port=new DjVuSimplePort();
+ pcaster->add_route(this, xport);
+ pcaster->add_route(this, this);
+
+ if(!url.is_empty())
+ {
+ init_data_pool=pcaster->request_data(this, init_url);
+ if(init_data_pool)
+ {
+ if(!init_url.is_empty() && init_url.is_local_file_url() && djvu_import_codec)
+ {
+ djvu_import_codec(init_data_pool,init_url,needs_compression_flag,needs_rename_flag);
+ }
+ if(needs_rename_flag)
+ can_compress_flag=true;
+ }
+ if (!init_data_pool)
+ {
+ G_THROW( ERR_MSG("DjVuDocument.fail_URL") "\t"+init_url.get_string());
+ }
+ }
+ // Now we say it is ready
+ init_started=true;
+
+ init_thread_flags=STARTED;
+ init_life_saver=this;
+ init_thr.create(static_init_thread, this);
+}
+
+DjVuDocument::~DjVuDocument(void)
+{
+ // No more messages, please. We're being destroyed.
+ get_portcaster()->del_port(this);
+
+ // We want to stop any DjVuFile which has been created by us
+ // and is still being decoded. We have to stop them manually because
+ // they keep the "life saver" in the decoding thread and won't stop
+ // when we clear the last reference to them
+ {
+ GCriticalSectionLock lock(&ufiles_lock);
+ for(GPosition pos=ufiles_list;pos;++pos)
+ {
+ GP<DjVuFile> file=ufiles_list[pos]->file;
+ file->stop_decode(false);
+ file->stop(false); // Disable any access to data
+ }
+ ufiles_list.empty();
+ }
+
+ GPList<DjVuPort> ports=get_portcaster()->prefix_to_ports(get_int_prefix());
+ for(GPosition pos=ports;pos;++pos)
+ {
+ GP<DjVuPort> port=ports[pos];
+ if (port->inherits("DjVuFile"))
+ {
+ DjVuFile * file=(DjVuFile *) (DjVuPort *) port;
+ file->stop_decode(false);
+ file->stop(false); // Disable any access to data
+ }
+ }
+ DataPool::close_all();
+}
+
+void
+DjVuDocument::stop_init(void)
+{
+ DEBUG_MSG("DjVuDocument::stop_init(): making sure that the init thread dies.\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GMonitorLock lock(&init_thread_flags);
+ while((init_thread_flags & STARTED) &&
+ !(init_thread_flags & FINISHED))
+ {
+ if (init_data_pool) init_data_pool->stop(true); // blocking operation
+
+ if (ndir_file) ndir_file->stop(false);
+
+ {
+ GCriticalSectionLock lock(&ufiles_lock);
+ for(GPosition pos=ufiles_list;pos;++pos)
+ ufiles_list[pos]->file->stop(false); // Disable any access to data
+ ufiles_list.empty();
+ }
+
+ init_thread_flags.wait(50);
+ }
+}
+
+void
+DjVuDocument::check() const
+{
+ if (!init_started)
+ G_THROW( ERR_MSG("DjVuDocument.not_init") );
+}
+
+void
+DjVuDocument::static_init_thread(void * cl_data)
+{
+ DjVuDocument * th=(DjVuDocument *) cl_data;
+ GP<DjVuDocument> life_saver=th;
+ th->init_life_saver=0;
+ G_TRY {
+ th->init_thread();
+ } G_CATCH(exc) {
+ th->flags|=DjVuDocument::DOC_INIT_FAILED;
+ G_TRY {
+ th->check_unnamed_files();
+ if (!exc.cmp_cause(ByteStream::EndOfFile) && th->verbose_eof)
+ get_portcaster()->notify_error(th, ERR_MSG("DjVuDocument.init_eof") );
+ else if (!exc.cmp_cause(DataPool::Stop))
+ get_portcaster()->notify_status(th, ERR_MSG("DjVuDocument.stopped") );
+ else
+ get_portcaster()->notify_error(th, exc.get_cause());
+ } G_CATCH_ALL {} G_ENDCATCH;
+ th->init_thread_flags|=FINISHED;
+ } G_ENDCATCH;
+}
+
+void
+DjVuDocument::init_thread(void)
+ // This function is run in a separate thread.
+ // The goal is to detect the document type (BUNDLED, OLD_INDEXED, etc.)
+ // and decode navigation directory.
+{
+ DEBUG_MSG("DjVuDocument::init_thread(): guessing what we're dealing with\n");
+ DEBUG_MAKE_INDENT(3);
+
+ DjVuPortcaster * pcaster=get_portcaster();
+
+ GP<ByteStream> stream=init_data_pool->get_stream();
+
+ GP<IFFByteStream> giff=IFFByteStream::create(stream);
+ IFFByteStream &iff=*giff;
+ GUTF8String chkid;
+ int size=iff.get_chunk(chkid);
+ if (!size)
+ G_THROW( ByteStream::EndOfFile );
+ if (size < 0)
+ G_THROW( ERR_MSG("DjVuDocument.no_file") );
+ if (size<8)
+ {
+ G_THROW( ERR_MSG("DjVuDocument.not_DjVu") );
+ }
+ if (chkid=="FORM:DJVM")
+ {
+ DEBUG_MSG("Got DJVM document here\n");
+ DEBUG_MAKE_INDENT(3);
+
+ size=iff.get_chunk(chkid);
+ if (chkid=="DIRM")
+ {
+ djvm_dir=DjVmDir::create();
+ djvm_dir->decode(iff.get_bytestream());
+ iff.close_chunk();
+ if (djvm_dir->is_bundled())
+ {
+ DEBUG_MSG("Got BUNDLED file.\n");
+ doc_type=BUNDLED;
+ }
+ else
+ {
+ DEBUG_MSG("Got INDIRECT file.\n");
+ doc_type=INDIRECT;
+ }
+ flags|=DOC_TYPE_KNOWN | DOC_DIR_KNOWN;
+ pcaster->notify_doc_flags_changed(this, DOC_TYPE_KNOWN | DOC_DIR_KNOWN, 0);
+ check_unnamed_files();
+
+ /* Check for NAVM */
+ size=iff.get_chunk(chkid);
+ if (size && chkid=="NAVM")
+ {
+ djvm_nav=DjVmNav::create();
+ djvm_nav->decode(iff.get_bytestream());
+ iff.close_chunk();
+ }
+ }
+ else if (chkid=="DIR0")
+ {
+ DEBUG_MSG("Got OLD_BUNDLED file.\n");
+ doc_type=OLD_BUNDLED;
+ flags|=DOC_TYPE_KNOWN;
+ pcaster->notify_doc_flags_changed(this, DOC_TYPE_KNOWN, 0);
+ check_unnamed_files();
+ }
+ else
+ G_THROW( ERR_MSG("DjVuDocument.bad_format") );
+
+ if (doc_type==OLD_BUNDLED)
+ {
+ // Read the DjVmDir0 directory. We are unable to tell what
+ // files are pages and what are included at this point.
+ // We only know that the first file with DJVU (BM44 or PM44)
+ // form *is* the first page. The rest will become known
+ // after we decode DjVuNavDir
+ djvm_dir0=DjVmDir0::create();
+ djvm_dir0->decode(*iff.get_bytestream());
+ iff.close_chunk();
+ // Get offset to the first DJVU, PM44 or BM44 chunk
+ int first_page_offset=0;
+ while(!first_page_offset)
+ {
+ int offset;
+ size=iff.get_chunk(chkid, &offset);
+ if (size==0) G_THROW( ERR_MSG("DjVuDocument.no_page") );
+ if (chkid=="FORM:DJVU" || chkid=="FORM:PM44" || chkid=="FORM:BM44")
+ {
+ DEBUG_MSG("Got 1st page offset=" << offset << "\n");
+ first_page_offset=offset;
+ }
+ iff.close_chunk();
+ }
+
+ // Now get the name of this file
+ int file_num;
+ for(file_num=0;file_num<djvm_dir0->get_files_num();file_num++)
+ {
+ DjVmDir0::FileRec & file=*djvm_dir0->get_file(file_num);
+ if (file.offset==first_page_offset)
+ {
+ first_page_name=file.name;
+ break;
+ }
+ }
+ if (!first_page_name.length())
+ G_THROW( ERR_MSG("DjVuDocument.no_page") );
+ flags|=DOC_DIR_KNOWN;
+ pcaster->notify_doc_flags_changed(this, DOC_DIR_KNOWN, 0);
+ check_unnamed_files();
+ }
+ }
+ else // chkid!="FORM:DJVM"
+ {
+ // DJVU format
+ DEBUG_MSG("Got DJVU OLD_INDEXED or SINGLE_PAGE document here.\n");
+ doc_type=SINGLE_PAGE;
+ flags|=DOC_TYPE_KNOWN;
+ pcaster->notify_doc_flags_changed(this, DOC_TYPE_KNOWN, 0);
+ check_unnamed_files();
+ }
+ if (doc_type==OLD_BUNDLED || doc_type==SINGLE_PAGE)
+ {
+ DEBUG_MSG("Searching for NDIR chunks...\n");
+ ndir_file=get_djvu_file(-1);
+ if (ndir_file) ndir=ndir_file->decode_ndir();
+ ndir_file=0; // Otherwise ~DjVuDocument() will stop (=kill) it
+ if (!ndir)
+ {
+ // Seems to be 1-page old-style document. Create dummy NDIR
+ if (doc_type==OLD_BUNDLED)
+ {
+ ndir=DjVuNavDir::create(GURL::UTF8("directory",init_url));
+ ndir->insert_page(-1, first_page_name);
+ }
+ else
+ {
+ ndir=DjVuNavDir::create(GURL::UTF8("directory",init_url.base()));
+ ndir->insert_page(-1, init_url.fname());
+ }
+ }
+ else
+ {
+ if (doc_type==SINGLE_PAGE)
+ doc_type=OLD_INDEXED;
+ }
+ flags|=DOC_NDIR_KNOWN;
+ pcaster->notify_doc_flags_changed(this, DOC_NDIR_KNOWN, 0);
+ check_unnamed_files();
+ }
+
+ flags|=DOC_INIT_OK;
+ pcaster->notify_doc_flags_changed(this, DOC_INIT_OK, 0);
+ check_unnamed_files();
+ init_thread_flags|=FINISHED;
+ DEBUG_MSG("DOCUMENT IS FULLY INITIALIZED now: doc_type='" <<
+ (doc_type==BUNDLED ? "BUNDLED" :
+ doc_type==OLD_BUNDLED ? "OLD_BUNDLED" :
+ doc_type==INDIRECT ? "INDIRECT" :
+ doc_type==OLD_INDEXED ? "OLD_INDEXED" :
+ doc_type==SINGLE_PAGE ? "SINGLE_PAGE" :
+ "UNKNOWN") << "'\n");
+}
+
+bool
+DjVuDocument::wait_for_complete_init(void)
+{
+ flags.enter();
+ while(!(flags & DOC_INIT_FAILED) &&
+ !(flags & DOC_INIT_OK)) flags.wait();
+ flags.leave();
+ init_thread_flags.enter();
+ while (!(init_thread_flags & FINISHED))
+ init_thread_flags.wait();
+ init_thread_flags.leave();
+ return (flags & (DOC_INIT_OK | DOC_INIT_FAILED))!=0;
+}
+
+int
+DjVuDocument::wait_get_pages_num(void) const
+{
+ GSafeFlags &f=const_cast<GSafeFlags &>(flags);
+ f.enter();
+ while(!(f & DOC_TYPE_KNOWN) &&
+ !(f & DOC_INIT_FAILED) &&
+ !(f & DOC_INIT_OK)) f.wait();
+ f.leave();
+ return get_pages_num();
+}
+
+GUTF8String
+DjVuDocument::get_int_prefix(void) const
+{
+ // These NAMEs are used to enable DjVuFile sharing inside the same
+ // DjVuDocument using DjVuPortcaster. Since URLs are unique to the
+ // document, other DjVuDocuments cannot retrieve files until they're
+ // assigned some permanent name. After '?' there should be the real
+ // file's URL. Please note, that output of this function is used only
+ // as name for DjVuPortcaster. Not as a URL.
+ GUTF8String retval;
+ return retval.format("document_%p%d?", this, hash(init_url));
+}
+
+void
+DjVuDocument::set_file_aliases(const DjVuFile * file)
+{
+ DEBUG_MSG("DjVuDocument::set_file_aliases(): setting global aliases for file '"
+ << file->get_url() << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ DjVuPortcaster * pcaster=DjVuPort::get_portcaster();
+
+ GMonitorLock lock(&((DjVuFile *) file)->get_safe_flags());
+ pcaster->clear_aliases(file);
+ if (file->is_decode_ok() && cache)
+ {
+ // If file is successfully decoded and caching is enabled,
+ // assign a global alias to this file, so that any other
+ // DjVuDocument will be able to use it.
+
+ pcaster->add_alias(file, file->get_url().get_string());
+ if (flags & (DOC_NDIR_KNOWN | DOC_DIR_KNOWN))
+ {
+ int page_num=url_to_page(file->get_url());
+ if (page_num>=0)
+ {
+ if (page_num==0) pcaster->add_alias(file, init_url.get_string()+"#-1");
+ pcaster->add_alias(file, init_url.get_string()+"#"+GUTF8String(page_num));
+ }
+ }
+ // The following line MUST stay here. For OLD_INDEXED documents
+ // a page may finish decoding before DIR or NDIR becomes known
+ // (multithreading, remember), so the code above would not execute
+ pcaster->add_alias(file, file->get_url().get_string()+"#-1");
+ } else pcaster->add_alias(file, get_int_prefix()+file->get_url());
+}
+
+void
+DjVuDocument::check_unnamed_files(void)
+{
+ DEBUG_MSG("DjVuDocument::check_unnamed_files(): Seeing if we can fix some...\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (flags & DOC_INIT_FAILED)
+ {
+ // Init failed. All unnamed files should be terminated
+ GCriticalSectionLock lock(&ufiles_lock);
+ for(GPosition pos=ufiles_list;pos;++pos)
+ {
+ GP<DjVuFile> file=ufiles_list[pos]->file;
+ file->stop_decode(true);
+ file->stop(false); // Disable any access to data
+ }
+ ufiles_list.empty();
+ return;
+ }
+
+ if ((flags & DOC_TYPE_KNOWN)==0)
+ return;
+
+ // See the list of unnamed files (created when there was insufficient
+ // information about DjVuDocument structure) and try to fix those,
+ // which can be fixed at this time
+ while(true)
+ {
+ DjVuPortcaster * pcaster=get_portcaster();
+
+ GP<UnnamedFile> ufile;
+ GURL new_url;
+ GPosition pos ;
+ GCriticalSectionLock lock(&ufiles_lock);
+ for(pos=ufiles_list;pos;)
+ {
+ G_TRY
+ {
+ GP<UnnamedFile> f=ufiles_list[pos];
+ if (f->id_type==UnnamedFile::ID)
+ new_url=id_to_url(f->id);
+ else
+ new_url=page_to_url(f->page_num);
+ if (!new_url.is_empty())
+ {
+ ufile=f;
+ // Don't take it off the list. We want to be
+ // able to stop the init from ~DjVuDocument();
+ //
+ // ufiles_list.del(pos);
+ break;
+ } else if (is_init_complete())
+ {
+ // No empty URLs are allowed at this point.
+ // We now know all information about the document
+ // and can determine if a page is inside it or not
+ f->data_pool->set_eof();
+ GUTF8String msg;
+ if (f->id_type==UnnamedFile::ID)
+ msg= ERR_MSG("DjVuDocument.miss_page_name") "\t"+f->id;
+ else
+ msg= ERR_MSG("DjVuDocument.miss_page_num") "\t"+GUTF8String(f->page_num);
+ G_THROW(msg);
+ }
+ ++pos;
+ }
+ G_CATCH(exc)
+ {
+ pcaster->notify_error(this, exc.get_cause());
+ GP<DataPool> pool=ufiles_list[pos]->data_pool;
+ if (pool)
+ pool->stop();
+ GPosition this_pos=pos;
+ ++pos;
+ ufiles_list.del(this_pos);
+ }
+ G_ENDCATCH;
+ }
+
+ if (ufile && !new_url.is_empty())
+ {
+ DEBUG_MSG("Fixing file: '" << ufile->url << "'=>'" << new_url << "'\n");
+ // Now, once we know its real URL we can request a real DataPool and
+ // can connect the DataPool owned by DjVuFile to that real one
+ // Note, that now request_data() will not play fool because
+ // we have enough information
+
+ G_TRY
+ {
+ if (ufile->data_pool)
+ {
+ GP<DataPool> new_pool=pcaster->request_data(ufile->file, new_url);
+ if(!new_pool)
+ G_THROW( ERR_MSG("DjVuDocument.fail_URL") "\t"+new_url.get_string());
+ ufile->data_pool->connect(new_pool);
+ }
+ ufile->file->set_name(new_url.fname());
+ ufile->file->move(new_url.base());
+ set_file_aliases(ufile->file);
+ }
+ G_CATCH(exc)
+ {
+ pcaster->notify_error(this, exc.get_cause());
+ }
+ G_ENDCATCH;
+ }
+ else
+ break;
+
+ // Remove the 'ufile' from the list
+ for(pos=ufiles_list;pos;++pos)
+ if (ufiles_list[pos]==ufile)
+ {
+ ufiles_list.del(pos);
+ break;
+ }
+ } // while(1)
+}
+
+int
+DjVuDocument::get_pages_num(void) const
+{
+ check();
+ if (flags & DOC_TYPE_KNOWN)
+ if (doc_type==BUNDLED || doc_type==INDIRECT)
+ return djvm_dir->get_pages_num();
+ else if (flags & DOC_NDIR_KNOWN)
+ return ndir->get_pages_num();
+ return 1;
+}
+
+GURL
+DjVuDocument::page_to_url(int page_num) const
+{
+ check();
+ DEBUG_MSG("DjVuDocument::page_to_url(): page_num=" << page_num << "\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GURL url;
+ if (flags & DOC_TYPE_KNOWN)
+ switch(doc_type)
+ {
+ case SINGLE_PAGE:
+ case OLD_INDEXED:
+ {
+ if (page_num<0) url=init_url;
+ else if (flags & DOC_NDIR_KNOWN) url=ndir->page_to_url(page_num);
+ break;
+ }
+ case OLD_BUNDLED:
+ {
+ if (page_num<0) page_num=0;
+ if (page_num==0 && (flags & DOC_DIR_KNOWN))
+ url=GURL::UTF8(first_page_name,init_url);
+ else if (flags & DOC_NDIR_KNOWN)
+ url=ndir->page_to_url(page_num);
+ break;
+ }
+ case BUNDLED:
+ {
+ if (page_num<0)
+ page_num=0;
+ if (flags & DOC_DIR_KNOWN)
+ {
+ GP<DjVmDir::File> file=djvm_dir->page_to_file(page_num);
+ if (!file) G_THROW( ERR_MSG("DjVuDocument.big_num") );
+ url=GURL::UTF8(file->get_load_name(),init_url);
+ }
+ break;
+ }
+ case INDIRECT:
+ {
+ if (page_num<0) page_num=0;
+ if (flags & DOC_DIR_KNOWN)
+ {
+ GP<DjVmDir::File> file=djvm_dir->page_to_file(page_num);
+ if (!file)
+ G_THROW( ERR_MSG("DjVuDocument.big_num") );
+ url=GURL::UTF8(file->get_load_name(),init_url.base());
+ }
+ break;
+ }
+ default:
+ G_THROW( ERR_MSG("DjVuDocument.unk_type") );
+ }
+ return url;
+}
+
+int
+DjVuDocument::url_to_page(const GURL & url) const
+{
+ check();
+ DEBUG_MSG("DjVuDocument::url_to_page(): url='" << url << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ int page_num=-1;
+ if (flags & DOC_TYPE_KNOWN)
+ switch(doc_type)
+ {
+ case SINGLE_PAGE:
+ case OLD_BUNDLED:
+ case OLD_INDEXED:
+ {
+ if (flags & DOC_NDIR_KNOWN) page_num=ndir->url_to_page(url);
+ break;
+ }
+ case BUNDLED:
+ {
+ if (flags & DOC_DIR_KNOWN)
+ {
+ GP<DjVmDir::File> file;
+ if (url.base()==init_url)
+ file=djvm_dir->id_to_file(url.fname());
+ if (file)
+ page_num=file->get_page_num();
+ }
+ break;
+ }
+ case INDIRECT:
+ {
+ if (flags & DOC_DIR_KNOWN)
+ {
+ GP<DjVmDir::File> file;
+ if (url.base()==init_url.base())
+ file=djvm_dir->id_to_file(url.fname());
+ if (file)
+ page_num=file->get_page_num();
+ }
+ break;
+ }
+ default:
+ G_THROW( ERR_MSG("DjVuDocument.unk_type") );
+ }
+ return page_num;
+}
+
+GURL
+DjVuDocument::id_to_url(const GUTF8String & id) const
+{
+ check();
+ DEBUG_MSG("DjVuDocument::id_to_url(): translating ID='" << id << "' to URL\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (flags & DOC_TYPE_KNOWN)
+ switch(doc_type)
+ {
+ case BUNDLED:
+ if (flags & DOC_DIR_KNOWN)
+ {
+ GP<DjVmDir::File> file=djvm_dir->id_to_file(id);
+ if (!file)
+ {
+ file=djvm_dir->name_to_file(id);
+ if (!file)
+ file=djvm_dir->title_to_file(id);
+ }
+ if (file)
+ return GURL::UTF8(file->get_load_name(),init_url);
+ }
+ break;
+ case INDIRECT:
+ if (flags & DOC_DIR_KNOWN)
+ {
+ GP<DjVmDir::File> file=djvm_dir->id_to_file(id);
+ if (!file)
+ {
+ file=djvm_dir->name_to_file(id);
+ if (!file)
+ file=djvm_dir->title_to_file(id);
+ }
+ if (file)
+ return GURL::UTF8(file->get_load_name(),init_url.base());
+ }
+ break;
+ case OLD_BUNDLED:
+ if (flags & DOC_DIR_KNOWN)
+ {
+ GP<DjVmDir0::FileRec> frec=djvm_dir0->get_file(id);
+ if (frec)
+ return GURL::UTF8(id,init_url);
+ }
+ break;
+ case OLD_INDEXED:
+ case SINGLE_PAGE:
+ return GURL::UTF8(id,init_url.base());
+ break;
+ }
+ return GURL();
+}
+
+GURL
+DjVuDocument::id_to_url(const DjVuPort * source, const GUTF8String &id)
+{
+ return id_to_url(id);
+}
+
+GP<DjVuFile>
+DjVuDocument::url_to_file(const GURL & url, bool dont_create) const
+ // This function is private and is called from two places:
+ // id_to_file() and get_djvu_file() ONLY when the structure is known
+{
+ check();
+ DEBUG_MSG("DjVuDocument::url_to_file(): url='" << url << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ // Try DjVuPortcaster to find existing files.
+ DjVuPortcaster * pcaster=DjVuPort::get_portcaster();
+ GP<DjVuPort> port;
+
+ if (cache)
+ {
+ // First - fully decoded files
+ port=pcaster->alias_to_port(url.get_string());
+ if (port && port->inherits("DjVuFile"))
+ {
+ DEBUG_MSG("found fully decoded file using DjVuPortcaster\n");
+ return (DjVuFile *) (DjVuPort *) port;
+ }
+ }
+
+ // Second - internal files
+ port=pcaster->alias_to_port(get_int_prefix()+url);
+ if (port && port->inherits("DjVuFile"))
+ {
+ DEBUG_MSG("found internal file using DjVuPortcaster\n");
+ return (DjVuFile *) (DjVuPort *) port;
+ }
+
+ GP<DjVuFile> file;
+
+ if (!dont_create)
+ {
+ DEBUG_MSG("creating a new file\n");
+ file=DjVuFile::create(url,const_cast<DjVuDocument *>(this),recover_errors,verbose_eof);
+ const_cast<DjVuDocument *>(this)->set_file_aliases(file);
+ }
+
+ return file;
+}
+
+GP<DjVuFile>
+DjVuDocument::get_djvu_file(int page_num, bool dont_create) const
+{
+ check();
+ DEBUG_MSG("DjVuDocument::get_djvu_file(): request for page " << page_num << "\n");
+ DEBUG_MAKE_INDENT(3);
+
+ DjVuPortcaster * pcaster=DjVuPort::get_portcaster();
+
+ GURL url;
+ {
+ // I'm locking the flags because depending on what page_to_url()
+ // returns me, I'll be creating DjVuFile in different ways.
+ // And I don't want the situation to change between the moment I call
+ // id_to_url() and I actually create DjVuFile
+ GMonitorLock lock(&(const_cast<DjVuDocument *>(this)->flags));
+ url=page_to_url(page_num);
+ if (url.is_empty())
+ {
+ // If init is complete and url is empty, we know for sure, that
+ // smth is wrong with the page_num. So we can return ZERO.
+ // Otherwise we create a temporary file and wait for init to finish
+ if (is_init_complete()) return 0;
+
+ DEBUG_MSG("Structure is not known => check <doc_url>#<page_num> alias...\n");
+ GP<DjVuPort> port;
+ if (cache)
+ port=pcaster->alias_to_port(init_url.get_string()+"#"+GUTF8String(page_num));
+ if (!port || !port->inherits("DjVuFile"))
+ {
+ DEBUG_MSG("failed => invent dummy URL and proceed\n");
+
+ // Invent some dummy temporary URL. I don't care what it will
+ // be. I'll remember the page_num and will generate the correct URL
+ // after I learn what the document is
+ GUTF8String name("page");
+ name+=GUTF8String(page_num);
+ name+=".djvu";
+ url=invent_url(name);
+
+ GCriticalSectionLock(&(const_cast<DjVuDocument *>(this)->ufiles_lock));
+ for(GPosition pos=ufiles_list;pos;++pos)
+ {
+ GP<UnnamedFile> f=ufiles_list[pos];
+ if (f->url==url) return f->file;
+ }
+ GP<UnnamedFile> ufile=new UnnamedFile(UnnamedFile::PAGE_NUM, 0,
+ page_num, url, 0);
+
+ // We're adding the record to the list before creating the DjVuFile
+ // because DjVuFile::init() will call request_data(), and the
+ // latter should be able to find the record.
+ //
+ // We also want to keep ufiles_lock to make sure that when
+ // request_data() is called, the record is still there
+ const_cast<DjVuDocument *>(this)->ufiles_list.append(ufile);
+
+ GP<DjVuFile> file=
+ DjVuFile::create(url,const_cast<DjVuDocument *>(this),recover_errors,verbose_eof);
+ ufile->file=file;
+ return file;
+ } else url=((DjVuFile *) (DjVuPort *) port)->get_url();
+ }
+ }
+
+ GP<DjVuFile> file=url_to_file(url, dont_create);
+ if (file)
+ pcaster->add_route(file, const_cast<DjVuDocument *>(this));
+ return file;
+}
+
+GURL
+DjVuDocument::invent_url(const GUTF8String &name) const
+{
+ GUTF8String buffer;
+ buffer.format("djvufileurl://%p/%s", this, (const char *)name);
+ return GURL::UTF8(buffer);
+}
+
+GP<DjVuFile>
+DjVuDocument::get_djvu_file(const GUTF8String& id, bool dont_create)
+{
+ check();
+ DEBUG_MSG("DjVuDocument::get_djvu_file(): ID='" << id << "'\n");
+ DEBUG_MAKE_INDENT(3);
+ if (!id.length())
+ return get_djvu_file(-1);
+
+// Integers are not supported, only ID's
+// if (id.is_int())
+// return get_djvu_file(id.toInt(),dont_create);
+
+ GURL url;
+ // I'm locking the flags because depending on what id_to_url()
+ // returns me, I'll be creating DjVuFile in different ways.
+ // And I don't want the situation to change between the moment I call
+ // id_to_url() and I actually create DjVuFile
+ {
+ GMonitorLock lock(&flags);
+ url=id_to_url(id);
+ if(url.is_empty() && !id.is_int())
+ {
+ // If init is complete, we know for sure, that there is no such
+ // file with ID 'id' in the document. Otherwise we have to
+ // create a temporary file and wait for the init to finish
+ if (is_init_complete())
+ return 0;
+ // Invent some dummy temporary URL. I don't care what it will
+ // be. I'll remember the ID and will generate the correct URL
+ // after I learn what the document is
+ url=invent_url(id);
+ DEBUG_MSG("Invented url='" << url << "'\n");
+
+ GCriticalSectionLock lock(&ufiles_lock);
+ for(GPosition pos=ufiles_list;pos;++pos)
+ {
+ GP<UnnamedFile> f=ufiles_list[pos];
+ if (f->url==url)
+ return f->file;
+ }
+ GP<UnnamedFile> ufile=new UnnamedFile(UnnamedFile::ID, id, 0, url, 0);
+
+ // We're adding the record to the list before creating the DjVuFile
+ // because DjVuFile::init() will call request_data(), and the
+ // latter should be able to find the record.
+ //
+ // We also want to keep ufiles_lock to make sure that when
+ // request_data() is called, the record is still there
+ ufiles_list.append(ufile);
+
+ GP<DjVuFile> file=DjVuFile::create(url,this,recover_errors,verbose_eof);
+ ufile->file=file;
+ return file;
+ }
+ }
+
+ return get_djvu_file(url,dont_create);
+}
+
+GP<DjVuFile>
+DjVuDocument::get_djvu_file(const GURL& url, bool dont_create)
+{
+ check();
+ DEBUG_MSG("DjVuDocument::get_djvu_file(): URL='" << url << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (url.is_empty())
+ return 0;
+
+ const GP<DjVuFile> file(url_to_file(url, dont_create));
+
+ if (file)
+ get_portcaster()->add_route(file, this);
+
+ return file;
+}
+
+GP<DjVuImage>
+DjVuDocument::get_page(int page_num, bool sync, DjVuPort * port) const
+{
+ check();
+ DEBUG_MSG("DjVuDocument::get_page(): request for page " << page_num << "\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GP<DjVuImage> dimg;
+ const GP<DjVuFile> file(get_djvu_file(page_num));
+ if (file)
+ {
+ dimg=DjVuImage::create(file);
+ if (port)
+ DjVuPort::get_portcaster()->add_route(dimg, port);
+
+ file->resume_decode();
+ if (dimg && sync)
+ dimg->wait_for_complete_decode();
+ }
+ return dimg;
+}
+
+GP<DjVuImage>
+DjVuDocument::get_page(const GUTF8String &id, bool sync, DjVuPort * port)
+{
+ check();
+ DEBUG_MSG("DjVuDocument::get_page(): ID='" << id << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GP<DjVuImage> dimg;
+ const GP<DjVuFile> file(get_djvu_file(id));
+ if(file)
+ {
+ dimg=DjVuImage::create(file);
+ if (port)
+ DjVuPort::get_portcaster()->add_route(dimg, port);
+
+ file->resume_decode();
+ if (dimg && sync)
+ dimg->wait_for_complete_decode();
+ }
+ return dimg;
+}
+
+void
+DjVuDocument::process_threqs(void)
+ // Will look thru threqs_list and try to fulfil every request
+{
+ GCriticalSectionLock lock(&threqs_lock);
+ for(GPosition pos=threqs_list;pos;)
+ {
+ GP<ThumbReq> req=threqs_list[pos];
+ bool remove=false;
+ if (req->thumb_file)
+ {
+ G_TRY {
+ // There is supposed to be a file with thumbnails
+ if (req->thumb_file->is_data_present())
+ {
+ // Cool, we can extract the thumbnail now
+ GP<ByteStream> str=req->thumb_file->get_init_data_pool()->get_stream();
+ GP<IFFByteStream> giff=IFFByteStream::create(str);
+ IFFByteStream &iff=*giff;
+ GUTF8String chkid;
+ if (!iff.get_chunk(chkid) || chkid!="FORM:THUM")
+ G_THROW( ERR_MSG("DjVuDocument.bad_thumb") );
+
+ for(int i=0;i<req->thumb_chunk;i++)
+ {
+ if (!iff.get_chunk(chkid))
+ G_THROW( ERR_MSG("DjVuDocument.bad_thumb") );
+ iff.close_chunk();
+ }
+ if (!iff.get_chunk(chkid) || chkid!="TH44")
+ G_THROW( ERR_MSG("DjVuDocument.bad_thumb") );
+
+ // Copy the data
+ char buffer[1024];
+ int length;
+ while((length=iff.read(buffer, 1024)))
+ req->data_pool->add_data(buffer, length);
+ req->data_pool->set_eof();
+
+ // Also add this file to cache so that we won't have
+ // to download it next time
+ add_to_cache(req->thumb_file);
+
+ req->thumb_file=0;
+ req->image_file=0;
+ remove=true;
+ }
+ } G_CATCH(exc) {
+ GUTF8String msg= ERR_MSG("DjVuDocument.cant_extract") "\n";
+ msg+=exc.get_cause();
+ get_portcaster()->notify_error(this, msg);
+ // Switch this request to the "decoding" mode
+ req->image_file=get_djvu_file(req->page_num);
+ req->thumb_file=0;
+ req->data_pool->set_eof();
+ remove=true;
+ } G_ENDCATCH;
+ } // if (req->thumb_file)
+
+ if (req->image_file)
+ {
+ G_TRY {
+ // Decode the file if necessary. Or just used predecoded image.
+ GSafeFlags & file_flags=req->image_file->get_safe_flags();
+ {
+ GMonitorLock lock(&file_flags);
+ if (!req->image_file->is_decoding())
+ {
+ if (req->image_file->is_decode_ok())
+ {
+ // We can generate it now
+ const GP<DjVuImage> dimg(DjVuImage::create(req->image_file));
+
+ dimg->wait_for_complete_decode();
+
+ int width = 160;
+ int height = 160;
+
+ if( dimg->get_width() )
+ width = dimg->get_width();
+ if( dimg->get_height() )
+ height = dimg->get_height();
+
+ GRect rect(0, 0, 160, height*160/width);
+ GP<GPixmap> pm=dimg->get_pixmap(rect, rect, thumb_gamma);
+ if (!pm)
+ {
+ GP<GBitmap> bm=dimg->get_bitmap(rect, rect, sizeof(int));
+ if(bm)
+ pm=GPixmap::create(*bm);
+ else
+ pm = GPixmap::create(rect.height(), rect.width(),
+ &GPixel::WHITE);
+ }
+
+ // Store and compress the pixmap
+ GP<IW44Image> iwpix=IW44Image::create_encode(*pm);
+ GP<ByteStream> gstr=ByteStream::create();
+ IWEncoderParms parms;
+ parms.slices=97;
+ parms.bytes=0;
+ parms.decibels=0;
+ iwpix->encode_chunk(gstr, parms);
+ TArray<char> data=gstr->get_data();
+
+ req->data_pool->add_data((const char *) data, data.size());
+ req->data_pool->set_eof();
+
+ req->thumb_file=0;
+ req->image_file=0;
+ remove=true;
+ } else if (req->image_file->is_decode_failed())
+ {
+ // Unfortunately we cannot decode it
+ req->thumb_file=0;
+ req->image_file=0;
+ req->data_pool->set_eof();
+ remove=true;
+ } else
+ {
+ req->image_file->start_decode();
+ }
+ }
+ }
+ } G_CATCH(exc) {
+ GUTF8String msg="Failed to decode thumbnails:\n";
+ msg+=exc.get_cause();
+ get_portcaster()->notify_error(this, msg);
+
+ // Get rid of this request
+ req->image_file=0;
+ req->thumb_file=0;
+ req->data_pool->set_eof();
+ remove=true;
+ } G_ENDCATCH;
+ }
+
+ if (remove)
+ {
+ GPosition this_pos=pos;
+ ++pos;
+ threqs_list.del(this_pos);
+ } else ++pos;
+ }
+}
+
+GP<DjVuDocument::ThumbReq>
+DjVuDocument::add_thumb_req(const GP<ThumbReq> & thumb_req)
+ // Will look through the list of pending requests for thumbnails
+ // and try to add the specified request. If a duplicate is found,
+ // it will be returned and the list will not be modified
+{
+ GCriticalSectionLock lock(&threqs_lock);
+ for(GPosition pos=threqs_list;pos;++pos)
+ {
+ GP<ThumbReq> req=threqs_list[pos];
+ if (req->page_num==thumb_req->page_num)
+ return req;
+ }
+ threqs_list.append(thumb_req);
+ return thumb_req;
+}
+
+GList<GUTF8String>
+DjVuDocument::get_id_list(void)
+{
+ GList<GUTF8String> ids;
+ if (is_init_complete())
+ {
+ if(djvm_dir)
+ {
+ GPList<DjVmDir::File> files_list=djvm_dir->get_files_list();
+ for(GPosition pos=files_list;pos;++pos)
+ {
+ ids.append(files_list[pos]->get_load_name());
+ }
+ }else
+ {
+ const int page_num=get_pages_num();
+ for(int page=0;page<page_num;page++)
+ {
+ ids.append(page_to_url(page).fname());
+ }
+ }
+ }
+ return ids;
+}
+
+void
+DjVuDocument::map_ids(GMap<GUTF8String,void *> &map)
+{
+ GList<GUTF8String> ids=get_id_list();
+ for(GPosition pos=ids;pos;++pos)
+ {
+ map[ids[pos]]=0;
+ }
+}
+
+GP<DataPool>
+DjVuDocument::get_thumbnail(int page_num, bool dont_decode)
+{
+ DEBUG_MSG("DjVuDocument::get_thumbnail(): page_num=" << page_num << "\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (!is_init_complete()) return 0;
+
+ {
+ // See if we already have request for this thumbnail pending
+ GCriticalSectionLock lock(&threqs_lock);
+ for(GPosition pos=threqs_list;pos;++pos)
+ {
+ GP<ThumbReq> req=threqs_list[pos];
+ if (req->page_num==page_num)
+ return req->data_pool; // That's it. Just return it.
+ }
+ }
+
+ // No pending request for this page... Create one
+ GP<ThumbReq> thumb_req=new ThumbReq(page_num, DataPool::create());
+
+ // First try to find predecoded thumbnail
+ if (get_doc_type()==INDIRECT || get_doc_type()==BUNDLED)
+ {
+ // Predecoded thumbnails exist for new formats only
+ GPList<DjVmDir::File> files_list=djvm_dir->get_files_list();
+ GP<DjVmDir::File> thumb_file;
+ int thumb_start=0;
+ int page_cnt=-1;
+ for(GPosition pos=files_list;pos;++pos)
+ {
+ GP<DjVmDir::File> f=files_list[pos];
+ if (f->is_thumbnails())
+ {
+ thumb_file=f;
+ thumb_start=page_cnt+1;
+ } else if (f->is_page())
+ {
+ page_cnt++;
+ }
+ if (page_cnt==page_num) break;
+ }
+ if (thumb_file)
+ {
+ // That's the file with the desired thumbnail image
+ thumb_req->thumb_file=get_djvu_file(thumb_file->get_load_name());
+ thumb_req->thumb_chunk=page_num-thumb_start;
+ thumb_req=add_thumb_req(thumb_req);
+ process_threqs();
+ return thumb_req->data_pool;
+ }
+ }
+
+ // Apparently we're out of luck and need to decode the requested
+ // page (unless it's already done and if it's allowed) and render
+ // it into the thumbnail. If dont_decode is true, do not attempt
+ // to create this file (because this will result in a request for data)
+ GP<DjVuFile> file=get_djvu_file(page_num, dont_decode);
+ if (file)
+ {
+ thumb_req->image_file=file;
+
+ // I'm locking the flags here to make sure, that DjVuFile will not
+ // change its state in between of the checks.
+ GSafeFlags & file_flags=file->get_safe_flags();
+ {
+ GMonitorLock lock(&file_flags);
+ if (thumb_req->image_file->is_decode_ok() || !dont_decode)
+ {
+ // Just add it to the list and call process_threqs(). It
+ // will start decoding if necessary
+ thumb_req=add_thumb_req(thumb_req);
+ process_threqs();
+ } else
+ {
+ // Nothing can be done return ZERO
+ thumb_req=0;
+ }
+ }
+ } else thumb_req=0;
+
+ if (thumb_req) return thumb_req->data_pool;
+ else return 0;
+}
+
+static void
+add_to_cache(const GP<DjVuFile> & f, GMap<GURL, void *> & map,
+ DjVuFileCache * cache)
+{
+ GURL url=f->get_url();
+ DEBUG_MSG("DjVuDocument::add_to_cache(): url='" << url << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (!map.contains(url))
+ {
+ map[url]=0;
+ cache->add_file(f);
+
+ GPList<DjVuFile> list;
+ for(GPosition pos=list;pos;++pos)
+ add_to_cache(list[pos], map, cache);
+ }
+}
+
+void
+DjVuDocument::add_to_cache(const GP<DjVuFile> & f)
+{
+ if (cache)
+ {
+ GMap<GURL, void *> map;
+ ::add_to_cache(f, map, cache);
+ }
+}
+
+void
+DjVuDocument::notify_file_flags_changed(const DjVuFile * source,
+ long set_mask, long clr_mask)
+{
+ // Don't check here if the document is initialized or not.
+ // This function may be called when it's not.
+ // check();
+ if (set_mask & DjVuFile::DECODE_OK)
+ {
+ set_file_aliases(source);
+ if (cache) add_to_cache((DjVuFile *) source);
+ if(!needs_compression_flag)
+ {
+ if(source->needs_compression())
+ {
+ can_compress_flag=true;
+ needs_compression_flag=true;
+ }else if(source->can_compress())
+ {
+ can_compress_flag=true;
+ }
+ }
+ process_threqs();
+ }
+
+ if (set_mask & DjVuFile::DATA_PRESENT)
+ process_threqs(); // May be we can extract thumbnails now
+}
+
+GP<DjVuFile>
+DjVuDocument::id_to_file(const DjVuPort * source, const GUTF8String &id)
+{
+ return (DjVuFile *) get_djvu_file(id);
+}
+
+GP<DataPool>
+DjVuDocument::request_data(const DjVuPort * source, const GURL & url)
+{
+ DEBUG_MSG("DjVuDocument::request_data(): seeing if we can do it\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (url==init_url)
+ return init_data_pool;
+
+ check(); // Don't put it before 'init_data_pool'
+
+ {
+ // See if there is a file in the "UnnamedFiles" list.
+ // If it's there, then create an empty DataPool and store its
+ // pointer in the list. The "init thread" will eventually
+ // do smth with it.
+ GCriticalSectionLock lock(&ufiles_lock);
+ for(GPosition pos=ufiles_list;pos;++pos)
+ {
+ GP<UnnamedFile> f=ufiles_list[pos];
+ if (f->url==url)
+ {
+ DEBUG_MSG("Found tmp unnamed DjVuFile. Return empty DataPool\n");
+ // Remember the DataPool. We will connect it to the
+ // actual data after the document structure becomes known
+ f->data_pool=DataPool::create();
+ return f->data_pool;
+ }
+ }
+ }
+
+ // Well, the url is not in the "UnnamedFiles" list, but it doesn't
+ // mean, that it's not "artificial". Stay alert!
+ GP<DataPool> data_pool;
+ if (flags & DOC_TYPE_KNOWN)
+ switch(doc_type)
+ {
+ case OLD_BUNDLED:
+ {
+ if (flags & DOC_DIR_KNOWN)
+ {
+ DEBUG_MSG("The document is in OLD_BUNDLED format\n");
+ if (url.base()!=init_url)
+ G_THROW( ERR_MSG("DjVuDocument.URL_outside") "\t"+url.get_string());
+
+ GP<DjVmDir0::FileRec> file=djvm_dir0->get_file(url.fname());
+ if (!file)
+ {
+ G_THROW( ERR_MSG("DjVuDocument.file_outside") "\t"+url.fname());
+ }
+ data_pool=DataPool::create(init_data_pool, file->offset, file->size);
+ }
+ break;
+ }
+ case BUNDLED:
+ {
+ if (flags & DOC_DIR_KNOWN)
+ {
+ DEBUG_MSG("The document is in new BUNDLED format\n");
+ if (url.base()!=init_url)
+ {
+ G_THROW( ERR_MSG("DjVuDocument.URL_outside") "\t"
+ +url.get_string());
+ }
+
+ GP<DjVmDir::File> file=djvm_dir->id_to_file(url.fname());
+ if (!file)
+ {
+ G_THROW( ERR_MSG("DjVuDocument.file_outside") "\t"+url.fname());
+ }
+ data_pool=DataPool::create(init_data_pool, file->offset, file->size);
+ }
+ break;
+ }
+ case SINGLE_PAGE:
+ case OLD_INDEXED:
+ case INDIRECT:
+ {
+ DEBUG_MSG("The document is in SINGLE_PAGE or OLD_INDEXED or INDIRECT format\n");
+ if (flags & DOC_DIR_KNOWN)
+ if (doc_type==INDIRECT && !djvm_dir->id_to_file(url.fname()))
+ G_THROW( ERR_MSG("DjVuDocument.URL_outside2") "\t"+url.get_string());
+
+ if (url.is_local_file_url())
+ {
+// GUTF8String fname=GOS::url_to_filename(url);
+// if (GOS::basename(fname)=="-") fname="-";
+ DEBUG_MSG("url=" << url << "\n");
+
+ data_pool=DataPool::create(url);
+ }
+ }
+ }
+ return data_pool;
+}
+
+
+static void
+add_file_to_djvm(const GP<DjVuFile> & file, bool page,
+ DjVmDoc & doc, GMap<GURL, void *> & map)
+ // This function is used only for obsolete formats.
+ // For new formats there is no need to process files recursively.
+ // All information is already available from the DJVM chunk
+{
+ GURL url=file->get_url();
+
+ if (!map.contains(url))
+ {
+ map[url]=0;
+
+ if (file->get_chunks_number()>0 && !file->contains_chunk("NDIR"))
+ {
+ // Get the data and unlink any file containing NDIR chunk.
+ // Yes. We're lazy. We don't check if those files contain
+ // anything else.
+ GPosition pos;
+ GPList<DjVuFile> files_list=file->get_included_files(false);
+ GP<DataPool> data=file->get_djvu_data(false);
+ for(pos=files_list;pos;++pos)
+ {
+ GP<DjVuFile> f=files_list[pos];
+ if (f->contains_chunk("NDIR"))
+ data=DjVuFile::unlink_file(data, f->get_url().fname());
+ }
+
+ // Finally add it to the document
+ GUTF8String name=file->get_url().fname();
+ GP<DjVmDir::File> file_rec=DjVmDir::File::create(
+ name, name, name,
+ page ? DjVmDir::File::PAGE : DjVmDir::File::INCLUDE );
+ doc.insert_file(file_rec, data, -1);
+
+ // And repeat for all included files
+ for(pos=files_list;pos;++pos)
+ add_file_to_djvm(files_list[pos], false, doc, map);
+ }
+ }
+}
+
+static void
+add_file_to_djvm(const GP<DjVuFile> & file, bool page,
+ DjVmDoc & doc, GMap<GURL, void *> & map,
+ bool &needs_compression_flag, bool &can_compress_flag )
+{
+ if(!needs_compression_flag)
+ {
+ if(file->needs_compression())
+ {
+ can_compress_flag=true;
+ needs_compression_flag=true;
+ }else if(file->can_compress())
+ {
+ can_compress_flag=true;
+ }
+ }
+ add_file_to_djvm(file,page,doc,map);
+}
+
+static void
+local_get_url_names(DjVuFile * f,const GMap<GURL, void *> & map,GMap<GURL,void *> &tmpmap)
+{
+ GURL url=f->get_url();
+ if (!map.contains(url) && !tmpmap.contains(url))
+ {
+ tmpmap[url]=0;
+ f->process_incl_chunks();
+ GPList<DjVuFile> files_list=f->get_included_files(false);
+ for(GPosition pos=files_list;pos;++pos)
+ local_get_url_names(files_list[pos], map, tmpmap);
+ }
+}
+
+static void
+local_get_url_names(DjVuFile * f, GMap<GURL, void *> & map)
+{
+ GMap<GURL,void *> tmpmap;
+ local_get_url_names(f,map,tmpmap);
+ for(GPosition pos=tmpmap;pos;++pos)
+ map[tmpmap.key(pos)]=0;
+}
+
+GList<GURL>
+DjVuDocument::get_url_names(void)
+{
+ check();
+
+ GCriticalSectionLock lock(&url_names_lock);
+ if(has_url_names)
+ return url_names;
+
+ GMap<GURL, void *> map;
+ int i;
+ if (doc_type==BUNDLED || doc_type==INDIRECT)
+ {
+ GPList<DjVmDir::File> files_list=djvm_dir->get_files_list();
+ for(GPosition pos=files_list;pos;++pos)
+ {
+ GURL url=id_to_url(files_list[pos]->get_load_name());
+ map[url]=0;
+ }
+ }else
+ {
+ int pages_num=get_pages_num();
+ for(i=0;i<pages_num;i++)
+ {
+ G_TRY
+ {
+ local_get_url_names(get_djvu_file(i), map);
+ }
+ G_CATCH(ex)
+ {
+ // Why is this try/catch block here?
+ G_TRY {
+ get_portcaster()->notify_error(this, ex.get_cause());
+ GUTF8String emsg = ERR_MSG("DjVuDocument.exclude_page") "\t" + (i+1);
+ get_portcaster()->notify_error(this, emsg);
+ }
+ G_CATCH_ALL
+ {
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+ }
+ G_ENDCATCH;
+ }
+ }
+ for(GPosition j=map;j;++j)
+ {
+ if (map.key(j).is_local_file_url())
+ {
+ url_names.append(map.key(j));
+ }
+ }
+ has_url_names=true;
+ return url_names;
+}
+
+GP<DjVmDoc>
+DjVuDocument::get_djvm_doc()
+ // This function may block for data
+{
+ check();
+ DEBUG_MSG("DjVuDocument::get_djvm_doc(): creating the DjVmDoc\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (!is_init_complete())
+ G_THROW( ERR_MSG("DjVuDocument.init_not_done") );
+
+ GP<DjVmDoc> doc=DjVmDoc::create();
+
+ if (doc_type==BUNDLED || doc_type==INDIRECT)
+ {
+ GPList<DjVmDir::File> files_list=djvm_dir->get_files_list();
+ for(GPosition pos=files_list;pos;++pos)
+ {
+ GP<DjVmDir::File> f=new DjVmDir::File(*files_list[pos]);
+ GP<DjVuFile> file=url_to_file(id_to_url(f->get_load_name()));
+ GP<DataPool> data;
+ if (file->is_modified())
+ data=file->get_djvu_data(false);
+ else
+ data=file->get_init_data_pool();
+ doc->insert_file(f, data);
+ }
+ if (djvm_nav)
+ doc->set_djvm_nav(djvm_nav);
+ }
+ else if (doc_type==SINGLE_PAGE)
+ {
+ DEBUG_MSG("Creating: djvm for a single page document.\n");
+ GMap<GURL, void *> map_add;
+ GP<DjVuFile> file=get_djvu_file(0);
+ add_file_to_djvm(file, true, *doc, map_add,
+ needs_compression_flag,can_compress_flag);
+ }
+ else
+ {
+ DEBUG_MSG("Converting: the document is in an old format.\n");
+ GMap<GURL, void *> map_add;
+ if(recover_errors == ABORT)
+ {
+ for(int page_num=0;page_num<ndir->get_pages_num();page_num++)
+ {
+ GP<DjVuFile> file=url_to_file(ndir->page_to_url(page_num));
+ add_file_to_djvm(file, true, *doc, map_add,
+ needs_compression_flag,can_compress_flag);
+ }
+ }
+ else
+ {
+ for(int page_num=0;page_num<ndir->get_pages_num();page_num++)
+ {
+ G_TRY
+ {
+ GP<DjVuFile> file=url_to_file(ndir->page_to_url(page_num));
+ add_file_to_djvm(file, true, *doc, map_add,
+ needs_compression_flag,can_compress_flag);
+ }
+ G_CATCH(ex)
+ {
+ G_TRY {
+ get_portcaster()->notify_error(this, ex.get_cause());
+ GUTF8String emsg = ERR_MSG("DjVuDocument.skip_page") "\t"
+ + (page_num+1);
+ get_portcaster()->notify_error(this, emsg);
+ }
+ G_CATCH_ALL
+ {
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+ }
+ G_ENDCATCH;
+ }
+ }
+ }
+ return doc;
+}
+
+void
+DjVuDocument::write( const GP<ByteStream> &gstr,
+ const GMap<GUTF8String,void *> &reserved)
+{
+ DEBUG_MSG("DjVuDocument::write(): storing DjVmDoc into ByteStream\n");
+ DEBUG_MAKE_INDENT(3);
+ get_djvm_doc()->write(gstr,reserved);
+}
+
+void
+DjVuDocument::write(const GP<ByteStream> &gstr, bool force_djvm)
+{
+ DEBUG_MSG("DjVuDocument::write(): storing DjVmDoc into ByteStream\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GP<DjVmDoc> doc=get_djvm_doc();
+ GP<DjVmDir> dir=doc->get_djvm_dir();
+ if (force_djvm || dir->get_files_num()>1)
+ {
+ doc->write(gstr);
+ }else
+ {
+ GPList<DjVmDir::File> files_list=dir->resolve_duplicates(false);
+ GP<DataPool> pool=doc->get_data(files_list[files_list]->get_load_name());
+ GP<ByteStream> pool_str=pool->get_stream();
+ ByteStream &str=*gstr;
+ str.writall(octets,4);
+ str.copy(*pool_str);
+ }
+}
+
+void
+DjVuDocument::expand(const GURL &codebase, const GUTF8String &idx_name)
+{
+ DEBUG_MSG("DjVuDocument::expand(): codebase='" << codebase << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GP<DjVmDoc> doc=get_djvm_doc();
+ doc->expand(codebase, idx_name);
+}
+
+void
+DjVuDocument::save_as(const GURL &where, const bool bundled)
+{
+ DEBUG_MSG("DjVuDocument::save_as(): where='" << where <<
+ "', bundled=" << bundled << "\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (needs_compression())
+ {
+ if(!djvu_compress_codec)
+ {
+ G_THROW( ERR_MSG("DjVuDocument.comp_codec") );
+ }
+ GP<ByteStream> gmbs=ByteStream::create();
+ write(gmbs);
+ ByteStream &mbs=*gmbs;
+ mbs.flush();
+ mbs.seek(0,SEEK_SET);
+ (*djvu_compress_codec)(gmbs,where,bundled);
+ }else if (bundled)
+ {
+ DataPool::load_file(where);
+ write(ByteStream::create(where, "wb"));
+ } else
+ {
+ expand(where.base(), where.fname());
+ }
+}
+
+static const char prolog[]="<?xml version=\"1.0\" ?>\n<!DOCTYPE DjVuXML PUBLIC \"-//W3C//DTD DjVuXML 1.1//EN\" \"pubtext/DjVuXML-s.dtd\">\n<DjVuXML>\n<HEAD>";
+static const char start_xml[]="</HEAD>\n<BODY>\n";
+static const char end_xml[]="</BODY>\n</DjVuXML>\n";
+
+void
+DjVuDocument::writeDjVuXML(const GP<ByteStream> &gstr_out,int flags) const
+{
+ ByteStream &str_out=*gstr_out;
+ str_out.writestring(
+ prolog+get_init_url().get_string().toEscaped()+start_xml);
+ const int pages=wait_get_pages_num();
+ for(int page_num=0;page_num<pages;++page_num)
+ {
+ const GP<DjVuImage> dimg(get_page(page_num,true));
+ if(!dimg)
+ {
+ G_THROW( ERR_MSG("DjVuToText.decode_failed") );
+ }
+ dimg->writeXML(str_out,get_init_url(),flags);
+ }
+ str_out.writestring(GUTF8String(end_xml));
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuDocument.h b/kviewshell/plugins/djvu/libdjvu/DjVuDocument.h
new file mode 100644
index 00000000..418d0814
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuDocument.h
@@ -0,0 +1,1071 @@
+//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: DjVuDocument.h,v 1.10 2005/05/25 20:24:52 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _DJVUDOCUMENT_H
+#define _DJVUDOCUMENT_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+#include "DjVuPort.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+class DjVmDoc;
+class DjVmDir;
+class DjVmDir0;
+class DjVmNav;
+class DjVuImage;
+class DjVuFile;
+class DjVuFileCache;
+class DjVuNavDir;
+class ByteStream;
+
+/** @name DjVuDocument.h
+ Files #"DjVuDocument.h"# and #"DjVuDocument.cpp"# contain implementation
+ of the \Ref{DjVuDocument} class - the ideal tool for opening, decoding
+ and saving DjVu single page and multi page documents.
+
+ @memo DjVu document class.
+ @author Andrei Erofeev <eaf@geocities.com>
+ @version #$Id: DjVuDocument.h,v 1.10 2005/05/25 20:24:52 leonb Exp $#
+*/
+
+//@{
+
+/** #DjVuDocument# provides convenient interface for opening, decoding
+ and saving back DjVu documents in single page and multi page formats.
+
+ {\bf Input formats}
+ It can read multi page DjVu documents in either of the 4 formats: 2
+ obsolete ({\em old bundled} and {\em old indexed}) and two new
+ ({\em new bundled} and {\em new indirect}).
+
+ {\bf Output formats}
+ To encourage users to switch to the new formats, the #DjVuDocument# can
+ save documents back only in the new formats: {\em bundled} and
+ {\em indirect}.
+
+ {\bf Conversion.} Since #DjVuDocument# can open DjVu documents in
+ an obsolete format and save it in any of the two new formats
+ ({\em new bundled} and {\em new indirect}), this class can be used for
+ conversion from obsolete formats to the new ones. Although it can also
+ do conversion between the new two formats, it's not the best way to
+ do it. Please refer to \Ref{DjVmDoc} for details.
+
+ {\bf Decoding.} #DjVuDocument# provides convenient interface for obtaining
+ \Ref{DjVuImage} corresponding to any page of the document. It uses
+ \Ref{DjVuFileCache} to do caching thus avoiding unnecessary multiple decoding of
+ the same page. The real decoding though is accomplished by \Ref{DjVuFile}.
+
+ {\bf Messenging.} Being derived from \Ref{DjVuPort}, #DjVuDocument#
+ takes an active part in exchanging messages (requests and notifications)
+ between different parties involved in decoding. It reports (relays)
+ errors, progress information and even handles some requests for data (when
+ these requests deal with local files).
+
+ Typical usage of #DjVuDocument# class in a threadless command line
+ program would be the following:
+ \begin{verbatim}
+ static const char file_name[]="/tmp/document.djvu";
+ GP<DjVuDocument> doc=DjVuDocument::create_wait(file_name);
+ const int pages=doc->get_pages_num();
+ for(int page=0;page<pages;page++)
+ {
+ GP<DjVuImage> dimg=doc->get_page(page);
+ // Do something
+ };
+ \end{verbatim}
+
+ {\bf Comments for the code above}
+ \begin{enumerate}
+ \item Since the document is assumed to be stored on the hard drive,
+ we don't have to cope with \Ref{DjVuPort}s and can pass
+ #ZERO# pointer to the \Ref{init}() function. #DjVuDocument#
+ can access local data itself. In the case of a plugin though,
+ one would have to implement his own \Ref{DjVuPort}, which
+ would handle requests for data arising when the document
+ is being decoded.
+ \item In a threaded program instead of calling the \Ref{init}()
+ function one can call \Ref{start_init}() and \Ref{stop_init}()
+ to initiate and interrupt initialization carried out in
+ another thread. This possibility of initializing the document
+ in another thread has been added specially for the plugin
+ because the initialization itself requires data, which is
+ not immediately available in the plugin. Thus, to prevent the
+ main thread from blocking, we perform initialization in a
+ separate thread. To check if the class is completely and
+ successfully initialized, use \Ref{is_init_ok}(). To see if
+ there was an error, use \Ref{is_init_failed}(). To
+ know when initialization is over (whether successfully or not),
+ use \Ref{is_init_complete}(). To wait for this to happen use
+ \Ref{wait_for_complete_init}(). Once again, all these things are
+ not required for single-threaded program.
+
+ Another difference between single-threaded and multi-threaded
+ environments is that in a single-threaded program, the image is
+ fully decoded before it's returned. In a multi-threaded
+ application decoding starts in a separate thread, and the pointer
+ to the \Ref{DjVuImage} being decoded is returned immediately.
+ This has been done to enable progressive redisplay
+ in the DjVu plugin. Use communication mechanism provided by
+ \Ref{DjVuPort} and \Ref{DjVuPortcaster} to learn about progress
+ of decoding. Or try #dimg->wait_for_complete_decode()# to wait
+ until the decoding ends.
+ \item See Also: \Ref{DjVuFile}, \Ref{DjVuImage}, \Ref{GOS}.
+ \end{enumerate}
+
+ {\bf Initialization}
+ As mentioned above, the #DjVuDocument# can go through several stages
+ of initialization. The functionality is gradually added while it passes
+ one stage after another:
+ \begin{enumerate}
+ \item First of all, immediately after the object is created \Ref{init}()
+ or \Ref{start_init}() functions must be called. {\bf Nothing}
+ will work until this is done. \Ref{init}() function will not
+ return until the initialization is complete. You need to make
+ sure, that enough data is available. {\bf Do not call \Ref{init}()
+ in the plugin}. \Ref{start_init}() will start initialization
+ in another thread. Use \Ref{stop_init}() to interrupt it.
+ Use \Ref{is_init_complete}() to check the initialization progress.
+ Use \Ref{wait_for_complete_init}() to wait for init to finish.
+ \item The first thing the initializing code learns about the document
+ is its type (#BUNDLED#, #INDIRECT#, #OLD_BUNDLED# or #OLD_INDEXED#).
+ As soon as it happens, document flags are changed and
+ #notify_doc_flags_changed()# request is sent through the
+ communication mechanism provided by \Ref{DjVuPortcaster}.
+ \item After the document type becomes known, the initializing code
+ proceeds with learning the document structure. Gradually the
+ flags are updated with values:
+ \begin{itemize}
+ \item #DOC_DIR_KNOWN#: Contents of the document became known.
+ This is meaningful for #BUNDLED#, #OLD_BUNDLED# and
+ #INDIRECT# documents only.
+ \item #DOC_NDIR_KNOWN#: Contents of the document navigation
+ directory became known. This is meaningful for old-style
+ documents (#OLD_BUNDLED# and #OLD_INDEXED#) only
+ \item #DOC_INIT_OK# or #DOC_INIT_FAILED#:
+ The initializating code finished.
+ \end{itemize}
+ \end{enumerate} */
+
+class DjVuDocument : public DjVuPort
+{
+public:
+ /** Flags describing the document initialization state.
+ \begin{itemize}
+ \item #DOC_TYPE_KNOWN#: The type of the document has been learnt.
+ \item #DOC_DIR_KNOWN#: Contents of the document became known.
+ This is meaningful for #BUNDLED#, #OLD_BUNDLED# and
+ #INDIRECT# documents only.
+ \item #DOC_NDIR_KNOWN#: Contents of the document navigation
+ directory became known. This is meaningful for old-style
+ documents (#OLD_BUNDLED# and #OLD_INDEXED#) only
+ \item #DOC_INIT_OK#: The initialization has completed successfully.
+ \item #DOC_INIT_FAILED#: The initialization failed.
+ \end{itemize} */
+ enum DOC_FLAGS { DOC_TYPE_KNOWN=1, DOC_DIR_KNOWN=2,
+ DOC_NDIR_KNOWN=4, DOC_INIT_OK=8,
+ DOC_INIT_FAILED=16 };
+ /** Specifies the format of #DjVuDocument#. There are currently 4 DjVu
+ multipage formats recognized by the library. Two of them are obsolete
+ and should not be used.
+ \begin{enumerate}
+ \item #OLD_BUNDLED# - Obsolete bundled format
+ \item #OLD_INDEXED# - Obsolete multipage format where every page
+ is stored in a separate file and "includes" (by means
+ of an #INCL# chunk) the file with the document directory.
+ \item #SINGLE_PAGE# - Single page document. Basically a file
+ with either #FORM:DJVU# or #FORM:IW44# and no multipage
+ information. For example, #OLD_INDEXED# documents with
+ document directory do not qualify even if they contain only
+ one page.
+ \item #BUNDLED# - Currently supported bundled format
+ \item #INDIRECT# - Currently supported "expanded" format, where
+ every page and component is stored in a separate file. There
+ is also a {\em top-level} file with the document directory.
+ \end{enumerate} */
+ enum DOC_TYPE { OLD_BUNDLED=1, OLD_INDEXED, BUNDLED, INDIRECT,
+ SINGLE_PAGE, UNKNOWN_TYPE };
+ enum THREAD_FLAGS { STARTED=1, FINISHED=2 };
+
+protected:
+ /** Default creator. Please call functions \Ref{init}() or
+ \Ref{start_init}() before you start working with the #DjVuDocument#.
+ */
+ DjVuDocument(void);
+public:
+
+ /// Virtual Destructor
+ virtual ~DjVuDocument(void);
+
+ /** Initializes the #DjVuDocument# object using an existing document.
+ This function should be called once after creating the object.
+ The #url# should point to the real data, and the creator of the
+ document should be ready to return this data to the document
+ if it's not stored locally (in which case #DjVuDocument# can
+ access it itself).
+
+ {\bf Initializing thread}
+ In a single-threaded application, the #start_init()# function performs
+ the complete initialization of the #DjVuDocument# before it returns.
+ In a multi-threaded application, though, it initializes some internal
+ variables, requests data for the document and starts a new
+ {\em initializing} thread, which is responsible for determining the
+ document type and structure and completing the initialization
+ process. This additional complication is justified in the case of
+ the DjVu plugin because performing initialization requires data and
+ in the plugin the data can be supplied by the main thread only.
+ Thus, if the initialization was completed by the main thread, the
+ plugin would run out of data and block.
+
+ {\bf Stages of initialization}
+ Immediately after the #start_init()# function terminates, the
+ #DjVuDocument# object is ready for use. Its functionality will
+ not be complete (until the initializing thread finishes), but
+ the object is still very useful. Such functions as \Ref{get_page}()
+ or \Ref{get_djvu_file}() or \Ref{id_to_url}() may be called
+ before the initializing thread completes. This allows the DjVu
+ plugin start decoding as soon as possible without waiting for
+ all data to arrive.
+
+ To query the current stage of initialization you can use
+ \Ref{get_doc_flags}() function or listen to the
+ #notify_doc_flags_changed()# notifications distributed with the help
+ of \Ref{DjVuPortcaster}. To wait for the initialization to
+ complete use \Ref{wait_for_complete_init}(). To stop initialization
+ call \Ref{stop_init}().
+
+ {\bf Querying data}
+ The query for data is done using the communication mechanism
+ provided by \Ref{DjVuPort} and \Ref{DjVuPortcaster}. If #port#
+ is not #ZERO#, then the request for data will be forwarded to it.
+ If it {\bf is} #ZERO# then #DjVuDocument# will create an internal
+ instance of \Ref{DjVuSimplePort} and will use it to access local
+ files and report errors to #stderr#. In short, if the document
+ file is stored on the local hard disk, and you're OK about reporting
+ errors to #stderr#, you may pass #ZERO# pointer to \Ref{DjVuPort}
+ as #DjVuDocument# can take care of this situation by itself.
+
+ {\bf The URL}
+ Depending on the document type the #url# should point to:
+ \begin{itemize}
+ \item {\bf Old bundled} and {\bf New bundled} formats: to the
+ document itself.
+ \item {\bf Old indexed} format: to any page of the document.
+ \item {\bf New indirect} format: to the top-level file of the
+ document. If (like in the {\em old indexed} format) you
+ point the #url# to a page, the page {\em will} be decoded,
+ but it will {\em not} be recognized to be part of the
+ document.
+ \end{itemize}
+
+ @param url The URL pointing to the document. If the document is
+ in a {\em bundled} format then the URL should point to it.
+ If the document is in the {\em old indexed} format then
+ URL may point to any page of this document. For {\em new
+ indirect} format the URL should point to the top-level
+ file of the document.
+ @param port If not #ZERO#, all requests and notifications will
+ be sent to it. Otherwise #DjVuDocument# will create an internal
+ instance of \Ref{DjVuSimplePort} for these purposes.
+ It's OK to make it #ZERO# if you're writing a command line
+ tool, which should work with files on the hard disk only
+ because #DjVuDocument# can access such files itself.
+ @param cache It's used to cache decoded \Ref{DjVuFile}s and
+ is actually useful in the plugin only. */
+ void start_init(const GURL & url, GP<DjVuPort> port=0,
+ DjVuFileCache * cache=0);
+
+ /** This creates a DjVuDocument without initializing it. */
+ static GP<DjVuDocument> create_noinit(void) {return new DjVuDocument;}
+
+ /** Create a version of DjVuDocument which has finished initializing. */
+ static GP<DjVuDocument> create_wait(
+ const GURL &url, GP<DjVuPort> xport=0, DjVuFileCache * const xcache=0);
+
+ /** Create a version of DjVuDocument which has begun initializing. */
+ static GP<DjVuDocument> create(
+ const GURL &url, GP<DjVuPort> xport=0, DjVuFileCache * const xcache=0);
+
+ /** Create a version of DjVuDocument which has begun initializing. */
+ static GP<DjVuDocument> create(
+ GP<DataPool> pool, GP<DjVuPort> xport=0, DjVuFileCache * const xcache=0);
+
+ /** Create a version of DjVuDocument which has begun initializing. */
+ static GP<DjVuDocument> create(
+ const GP<ByteStream> &bs, GP<DjVuPort> xport=0,
+ DjVuFileCache * const xcache=0);
+
+ /** Call this function when you don't need the #DjVuDocument# any more.
+ In a multi-threaded environment it will stop initialization
+ thread, if it is currently running. {\bf You will not be able
+ to start the initialization again. Thus, after calling this
+ function the document should not be used any more}. */
+ void stop_init(void);
+
+ /** Initializes the document.
+
+ Contrary to \Ref{start_init}(), which just starts the initialization
+ thread in a multi-threaded environment, this function does not
+ return until the initialization completes (either successfully or
+ not). Basically, it calls \Ref{start_init}() and then
+ \Ref{wait_for_complete_init}().
+ */
+ void init(const GURL & url, GP<DjVuPort> port=0,
+ DjVuFileCache * cache=0);
+
+ /** Returns #TRUE# if the initialization thread finished (does not
+ matter successfully or not). As soon as it happens, the document
+ becomes completely initialized and its every function should work
+ properly. Please refer to the description of \Ref{init}() function
+ and of the #DjVuDocument# class to learn about the initializing
+ stages.
+
+ To wait for the initialization to complete use
+ \Ref{wait_for_complete_init}() function.
+
+ To query the initialization stage use \Ref{get_flags}() function.
+
+ To learn whether initialization was successful or not,
+ use \Ref{is_init_ok}() and \Ref{is_init_failed}().
+
+ {\bf Note:} In a single threaded application the initialization
+ completes before the \Ref{init}() function returns. */
+ bool is_init_complete(void) const;
+
+ /** Returns #TRUE# is the initialization thread finished successfully.
+
+ See \Ref{is_init_complete}() and \Ref{wait_for_complete_init}()
+ for more details. */
+ bool is_init_ok(void) const;
+ /** Forces compression with the next save_as function. */
+ void set_needs_compression(void);
+ /** Returns #TRUE# if there are uncompressed pages in this document. */
+ bool needs_compression(void) const;
+ /** Returns #TRUE# if this file must be renamed before saving. */
+ bool needs_rename(void) const;
+ /** Returns #TRUE# if this file must be renamed before saving. */
+ bool can_compress(void) const;
+
+ /** Returns #TRUE# is the initialization thread failed.
+
+ See \Ref{is_init_complete}() and \Ref{wait_for_complete_init}()
+ for more details. */
+ bool is_init_failed(void) const;
+
+ /** If the document has already learnt its type, the function will
+ returns it: #DjVuDocument::OLD_BUNDLED# or
+ #DjVuDocument::OLD_INDEXED# or #DjVuDocument::SINGLE_PAGE# or
+ #DjVuDocument:BUNDLED# or #DjVuDocument::INDIRECT#. The first
+ two formats are obsolete. Otherwise (if the type is unknown yet),
+ #UNKNOWN_TYPE# will be returned.
+
+ {\bf Note:} To check the stage of the document initialization
+ use \Ref{get_flags}() or \Ref{is_init_complete}() functions. To
+ wait for the initialization to complete use \Ref{wait_for_complete_init}().
+ For single threaded applications the initialization completes
+ before the \Ref{init}() function returns. */
+ int get_doc_type(void) const;
+
+ /** Returns the document flags. The flags describe the degree in which
+ the #DjVuDocument# object is initialized. Every time the flags
+ are changed, a #notify_doc_flags_changed()# notification is
+ distributed using the \Ref{DjVuPortcaster} communication
+ mechanism.
+
+ {\bf Note:} To wait for the initialization to complete use
+ \Ref{wait_for_complete_init}(). For single threaded applications
+ the initialization completes before the \Ref{init}() function
+ returns. */
+ long get_doc_flags(void) const;
+
+ /** Returns #TRUE# if the document is in bundled format (either in
+ #DjVuDocument::OLD_BUNDLED# or #DjVuDocument::BUNDLED# formats). */
+ bool is_bundled(void) const;
+
+ /// Returns the URL passed to the \Ref{init}() function
+ GURL get_init_url(void) const;
+
+ /// Returns a listing of id's used by this document.
+ GList<GUTF8String> get_id_list(void);
+
+ /// Fill the id's into a GMap.
+ void map_ids( GMap<GUTF8String,void *> &map);
+
+ /** Returns data corresponding to the URL passed to the \Ref{init}()
+ function.
+
+ {\bf Note:} The pointer returned is guaranteed to be non-#ZERO#
+ only after the #DjVuDocument# learns its type (passes through
+ the first stage of initialization process). Please refer to
+ \Ref{init}() for details. */
+ GP<DataPool> get_init_data_pool(void) const;
+
+ /** @name Accessing pages */
+ //@{
+ /** Returns the number of pages in the document. If there is still
+ insufficient information about the document structure (initialization
+ has not finished yet), #1# will be returned. Please refer to
+ \Ref{init}() for details. */
+ int get_pages_num(void) const;
+
+ /** Translates the page number to the full URL of the page. This URL
+ is "artificial" for the {\em bundled} formats and is obtained
+ by appending the page name to the document's URL honoring possible
+ #;# and #?# in it. Negative page number has a special meaning for
+ #OLD_INDEXED# documents: it points to the URL, which the
+ #DjVuDocument# has been initialized with. For other formats this
+ is the same as page #0#.
+
+ The function tries it best to map the page number to the URL.
+ Although, if the document structure has not been fully discovered
+ yet, an empty URL will be returned. Use \Ref{wait_for_complete_init}()
+ to wait until the document initialization completes. Refer to
+ \Ref{init}() for details.
+
+ Depending on the document format, the function assumes, that there
+ is enough information to complete the request when:
+ \begin{itemize}
+ \item #OLD_INDEXED#: If #page_num<0#, #DOC_TYPE_KNOWN# flag must
+ be set. Otherwise #DOC_NDIR_KNOWN# must be set.
+ \item #OLD_BUNDLED#: If #page_num=0#, #DOC_DIR_KNOWN# flag must
+ be set. Otherwise #DOC_NDIR_KNOWN# flag must be set.
+ \item #INDIRECT# and #BUNDLED#: #DOC_DIR_KNOWN# flag must be set.
+ \end{itemize} */
+ GURL page_to_url(int page_num) const;
+ /// Tranlate the page number to id...
+ GUTF8String page_to_id(int page_num) const
+ { return url_to_id(page_to_url(page_num)); }
+ /** Translates the page URL back to page number. Returns #-1# if the
+ page is not in the document or the document's structure
+ has not been learnt yet.
+
+ Depending on the document format, the function starts working
+ properly as soon as:
+ \begin{itemize}
+ \item #OLD_INDEXED# and #OLD_BUNDLED# and #SINGLE_PAGE#:
+ #DOC_NDIR_KNOWN# is set
+ \item #INDIRECT# and #BUNDLED#: #DOC_DIR_KNOWN# is set.
+ \end{itemize} */
+ int url_to_page(const GURL & url) const;
+ /// Map the specified url to it's id.
+ GUTF8String url_to_id(const GURL &url) const
+ { return url.fname(); }
+
+ /** Translates the textual ID to the complete URL if possible.
+
+ Depending on the document format the translation is done in the
+ following way:
+ \begin{itemize}
+ \item For #BUNDLED# and #INDIRECT# documents the function
+ scans the \Ref{DjVmDir} (the document directory) and
+ matches the ID against:
+ \begin{enumerate}
+ \item File ID from the \Ref{DjVmDir}
+ \item File name from the \Ref{DjVmDir}
+ \item File title from the \Ref{DjVmDir}
+ \end{enumerate}
+ Then for #BUNDLED# document the URL is obtained by
+ appending the #name# of the found file to the document's
+ URL.
+
+ For #INDIRECT# documents the URL is obtained by
+ appending the #name# of the found file to the URL of
+ the directory containing the document.
+ \item For #OLD_BUNDLED# documents the function compares the ID
+ with internal name of every file inside the bundle and
+ composes an artificial URL by appending the file name to
+ the document's URL.
+ \item For #OLD_INDEXED# or #SINGLE_PAGE# documents the function
+ composes the URL by appending the ID to the URL of the
+ directory containing the document.
+ \end{itemize}
+
+ If information obtained by the initialization thread is not
+ sufficient yet, the #id_to_url()# may return an empty URL.
+ Depending on the document type, the information is sufficient when
+ \begin{itemize}
+ \item #BUNDLED# and #INDIRECT#: #DOC_DIR_KNOWN# flag is set.
+ \item #OLD_BUNDLED# and #OLD_INDEXED# and #SINGLE_PAGE#:
+ #DOC_TYPE_KNOWN# flag is set.
+ \end{itemize} */
+ GURL id_to_url(const GUTF8String &id) const;
+ /// Find out which page this id is...
+ int id_to_page(const GUTF8String &id) const
+ { return url_to_page(id_to_url(id)); }
+
+ /** Returns \Ref{GP} pointer to \Ref{DjVuImage} corresponding to page
+ #page_num#. If caching is enabled, and there is a {\em fully decoded}
+ \Ref{DjVuFile} in the cache, the image will be reused and will
+ be returned fully decoded. Otherwise, if multi-threaded behavior
+ is allowed, and #sync# is set to #FALSE#, the decoding will be
+ started in a separate thread, which enables to do progressive
+ redisplay. Thus, in this case the image returned may be partially
+ decoded.
+
+ Negative #page_num# has a special meaning for the {\em old indexed}
+ multipage documents: the #DjVuDocument# will start decoding of the
+ URL with which it has been initialized. For other formats page
+ #-1# is the same as page #0#.
+
+ #DjVuDocument# can also connect the created page to the specified
+ #port# {\em before starting decoding}. This option will allow
+ the future owner of \Ref{DjVuImage} to receive all messages and
+ requests generated during its decoding.
+
+ If this function is called before the document's structure becomes
+ known (the initialization process completes), the \Ref{DjVuFile},
+ which the returned image will be attached to, will be assigned a
+ temporary artificial URL, which will be corrected as soon as enough
+ information becomes available. The trick prevents the main thread
+ from blocking and in some cases helps to start decoding earlier.
+ The URL is corrected and decoding will start as soon as
+ #DjVuDocument# passes some given stages of initialization and
+ \Ref{page_to_url}(), \Ref{id_to_url}() functions start working
+ properly. Please look through their description for details.
+
+ {\bf Note:} To wait for the initialization to complete use
+ \Ref{wait_for_complete_init}(). For single threaded applications
+ the initialization completes before the \Ref{init}() function
+ returns.
+
+ @param page_num Number of the page to be decoded
+ @param sync When set to #TRUE# the function will not return
+ until the page is completely decoded. Otherwise,
+ in a multi-threaded program, this function will
+ start decoding in a new thread and will return
+ a partially decoded image. Refer to
+ \Ref{DjVuImage::wait_for_complete_decode}() and
+ \Ref{DjVuFile::is_decode_ok}().
+ @param port A pointer to \Ref{DjVuPort}, that the created image
+ will be connected to. */
+ GP<DjVuImage> get_page(int page_num, bool sync=true, DjVuPort * port=0) const;
+ GP<DjVuImage> get_page(int page_num, bool sync=true, DjVuPort * port=0)
+ { return const_cast<const DjVuDocument *>(this)->get_page(page_num,sync,port); }
+
+ /** Returns \Ref{GP} pointer to \Ref{DjVuImage} corresponding to the
+ specified ID. This function behaves exactly as the #get_page()#
+ function above. The only thing worth mentioning here is how the #ID#
+ parameter is treated.
+
+ First of all the function checks, if the ID contains a number.
+ If so, it just calls the #get_page()# function above. If ID is
+ #ZERO# or just empty, page number #-1# is assumed. Otherwise
+ the ID is translated to the URL using \Ref{id_to_url}(). */
+ GP<DjVuImage> get_page(const GUTF8String &id, bool sync=true, DjVuPort * port=0);
+
+ /** Returns \Ref{DjVuFile} corresponding to the specified page.
+ Normally it translates the page number to the URL using
+ \Ref{page_to_url}() and then creates \Ref{DjVuFile} initializing
+ it with data from the URL.
+
+ The behavior becomes different, though in the case when the
+ document structure is unknown at the moment this function is called.
+ In this situations it invents a temporary URL, creates a
+ \Ref{DjVuFile}, initializes it with this URL and returns
+ immediately. The caller may start decoding the file right away
+ (if necessary). The decoding will block but will automatically
+ continue as soon as enough information is collected about the
+ document. This trick should be quite transparent to the user and
+ helps to prevent the main thread from blocking. The decoding will
+ unblock and this function will stop using this "trick" as soon
+ as #DjVuDocument# passes some given stages of initialization and
+ \Ref{page_to_url}(), \Ref{id_to_url}() functions start working
+ properly.
+
+ If #dont_create# is #FALSE# the function will return the file
+ only if it already exists.
+
+ {\bf Note:} To wait for the initialization to complete use
+ \Ref{wait_for_complete_init}(). For single threaded applications
+ the initialization completes before the \Ref{init}() function
+ returns. */
+ GP<DjVuFile> get_djvu_file(int page_num, bool dont_create=false) const;
+ GP<DjVuFile> get_djvu_file(int page_num, bool dont_create=false)
+ { return const_cast<const DjVuDocument *>(this)->get_djvu_file(page_num,dont_create); }
+
+
+ /** Returns \Ref{DjVuFile} corresponding to the specified ID.
+ This function behaves exactly as the #get_djvu_file()# function
+ above. The only thing worth mentioning here is how the #ID#
+ parameter is treated.
+
+ First off, \Ref{id_to_url}() is called. If not successfull,
+ the function checks, if the ID contains a number.
+ If so, it just calls the #get_djvu_file()# function above. If ID is
+ #ZERO# or just empty, page number #-1# is assumed.
+
+ If #dont_create# is #FALSE# the function will return the file
+ only if it already exists. */
+ GP<DjVuFile> get_djvu_file(const GUTF8String &id, bool dont_create=false);
+ GP<DjVuFile> get_djvu_file(const GURL &url, bool dont_create=false);
+ /** Returns a \Ref{DataPool} containing one chunk #TH44# with
+ the encoded thumbnail for the specified page. The function
+ first looks for thumbnails enclosed into the document and if
+ it fails to find one, it decodes the required page and creates
+ the thumbnail on the fly (unless #dont_decode# is true).
+
+ {\bf Note:} It may happen that the returned \Ref{DataPool} will
+ not contain all the data you need. In this case you will need
+ to install a trigger into the \Ref{DataPool} to learn when the
+ data actually arrives. */
+ virtual GP<DataPool> get_thumbnail(int page_num, bool dont_decode);
+ /* Will return gamma correction, which was used when creating
+ thumbnail images. If you need other gamma correction, you will
+ need to correct the thumbnails again. */
+ float get_thumbnails_gamma(void) const;
+ //@}
+
+ /** Waits until the document initialization process finishes.
+ It can finish either successfully or not. Use \Ref{is_init_ok}()
+ and \Ref{is_init_failed}() to learn the result code.
+
+ As described in \Ref{start_init}(), for multi-threaded applications the
+ initialization is carried out in parallel with the main thread.
+ This function blocks the calling thread until the initializing
+ thread reads enough data, receives information about the document
+ format and exits. This function returns #true# if the
+ initialization is successful. You can use \Ref{get_flags}() or
+ \Ref{is_init_complete}() to check more precisely the degree of
+ initialization. Use \Ref{stop_init}() to interrupt initialization. */
+ bool wait_for_complete_init(void);
+
+ /** Wait until we known the number of pages and return. */
+ int wait_get_pages_num(void) const;
+
+ /// Returns cache being used.
+ DjVuFileCache * get_cache(void) const;
+
+ /** @name Saving document to disk */
+ //@{
+ /** Returns pointer to the \Ref{DjVmDoc} class, which can save the
+ document contents on the hard disk in one of the two new formats:
+ {\em bundled} and {\em indirect}. You may also want to look
+ at \Ref{write}() and \Ref{expand}() if you are interested in
+ how to save the document.
+
+ {\bf Plugin Warning}. This function will read contents of the whole
+ document. Thus, if you call it from the main thread (the thread,
+ which transfers data from Netscape), the plugin will block. */
+ GP<DjVmDoc> get_djvm_doc(void);
+ /** Saves the document in the {\em new bundled} format. All the data
+ is "bundled" into one file and this file is written into the
+ passed stream.
+
+ If #force_djvm# is #TRUE# then even one page documents will be
+ saved in the #DJVM BUNDLED# format (inside a #FORM:DJVM#);
+
+ {\bf Plugin Warning}. This function will read contents of the whole
+ document. Thus, if you call it from the main thread (the thread,
+ which transfers data from Netscape), the plugin will block. */
+ virtual void write(const GP<ByteStream> &str, bool force_djvm=false);
+ /** Always save as bundled, renaming any files conflicting with the
+ the names in the supplied GMap. */
+ virtual void write(const GP<ByteStream> &str,
+ const GMap<GUTF8String,void *> &reserved);
+ /** Saves the document in the {\em new indirect} format when every
+ page and component are stored in separate files. This format
+ is ideal for web publishing because it allows direct access to
+ any page and component. In addition to it, a top-level file
+ containing the list of all components will be created. To view
+ the document later in the plugin or in the viewer one should
+ load the top-level file.
+
+ {\bf Plugin Warning}. This function will read contents of the whole
+ document. Thus, if you call it from the main thread (the thread,
+ which transfers data from Netscape), the plugin will block.
+
+ @param codebase - Name of the directory which the document should
+ be expanded into.
+ @param idx_name - Name of the top-level file containing the document
+ directory (basically, list of all files composing the document).
+ */
+ void expand(const GURL &codebase, const GUTF8String &idx_name);
+ /** This function can be used instead of \Ref{write}() and \Ref{expand}().
+ It allows to save the document either in the new #BUNDLED# format
+ or in the new #INDIRECT# format depending on the value of parameter
+ #bundled#.
+
+ Depending on the document's type, the meaning of #where# is:
+ \begin{itemize}
+ \item For #BUNDLED# documents this is the name of the file
+ \item For #INDIRECT# documents this is the name of top-level
+ index file. All document files will be saved into the
+ save directory where the index file will resize. */
+ virtual void save_as(const GURL &where, const bool bundled=0);
+ //@}
+ /** Returns pointer to the internal directory of the document, if it
+ is in one of the new formats: #BUNDLED# or #INDIRECT#.
+ Otherwise (if the format of the input document is obsolete),
+ #ZERO# is returned.
+
+ #ZERO# will also be returned if the initializing thread has not
+ learnt enough information about the document (#DOC_DIR_KNOWN# has
+ not been set yet). Check \Ref{is_init_complete}() and \Ref{init}()
+ for details. */
+ GP<DjVmDir> get_djvm_dir(void) const;
+ /** Returns pointer to the document bookmarks.
+ This applies to #BUNDLED# and #INDIRECT# documents.
+
+ #ZERO# will also be returned if the initializing thread has not
+ learnt enough information about the document (#DOC_DIR_KNOWN# has
+ not been set yet). Check \Ref{is_init_complete}() and \Ref{init}()
+ for details. */
+ GP<DjVmNav> get_djvm_nav(void) const;
+ /** Returns pointer to the internal directory of the document, if it
+ is in obsolete #OLD_BUNDLED# format.
+
+ #ZERO# will also be returned if the initializing thread has not
+ learnt enough information about the document (#DOC_DIR_KNOWN# has
+ not been set yet). Check \Ref{is_init_complete}() and \Ref{init}()
+ for details. */
+ GP<DjVmDir0> get_djvm_dir0(void) const;
+ /** Returns pointer to {\em navigation directory} of the document.
+ The navigation directory is a DjVu file containing only one
+ chunk #NDIR# inside a #FORM:DJVI# with the list of all
+ document pages. */
+ GP<DjVuNavDir> get_nav_dir(void) const;
+
+ /// Create a complete DjVuXML file.
+ void writeDjVuXML(const GP<ByteStream> &gstr_out,int flags) const;
+
+ /// Returns TRUE if #class_name# is #"DjVuDocument"# or #"DjVuPort"#
+ virtual bool inherits(const GUTF8String &class_name) const;
+
+ /// Converts the specified id to a URL.
+ virtual GURL id_to_url(const DjVuPort * source, const GUTF8String &id);
+ virtual GP<DjVuFile> id_to_file(const DjVuPort * source, const GUTF8String &id);
+ virtual GP<DataPool> request_data(const DjVuPort * source, const GURL & url);
+ virtual void notify_file_flags_changed(const DjVuFile * source,
+ long set_mask, long clr_mask);
+
+ virtual GList<GURL> get_url_names(void);
+ virtual void set_recover_errors(ErrorRecoveryAction=ABORT);
+ virtual void set_verbose_eof(bool=true);
+
+ static void set_compress_codec(
+ void (*codec)(GP<ByteStream> &, const GURL &where, bool bundled));
+
+ static void set_import_codec(
+ void (*codec)(GP<DataPool> &,const GURL &url,bool &, bool &));
+
+protected:
+ static void (*djvu_import_codec) (
+ GP<DataPool> &pool, const GURL &url,bool &needs_compression, bool &needs_rename );
+ static void (*djvu_compress_codec) (
+ GP<ByteStream> &bs, const GURL &where, bool bundled);
+ virtual GP<DjVuFile> url_to_file(const GURL & url, bool dont_create=false) const;
+ GURL init_url;
+ GP<DataPool> init_data_pool;
+ GP<DjVmDir> djvm_dir; // New-style DjVm directory
+ GP<DjVmNav> djvm_nav;
+ int doc_type;
+ bool needs_compression_flag;
+ bool can_compress_flag;
+ bool needs_rename_flag;
+
+
+
+ bool has_url_names;
+ GCriticalSection url_names_lock;
+ GList<GURL> url_names;
+ ErrorRecoveryAction recover_errors;
+ bool verbose_eof;
+public:
+ class UnnamedFile; // This really should be protected ...
+ class ThumbReq; // This really should be protected ...
+protected:
+ bool init_started;
+ GSafeFlags flags;
+ GSafeFlags init_thread_flags;
+ DjVuFileCache * cache;
+ GP<DjVuSimplePort> simple_port;
+
+ GP<DjVmDir0> djvm_dir0; // Old-style DjVm directory
+ GP<DjVuNavDir> ndir; // Old-style navigation directory
+ GUTF8String first_page_name;// For OLD_BUNDLED docs only
+
+ // The following is used in init() and destructor to query NDIR
+ // DO NOT USE FOR ANYTHING ELSE. THE FILE IS ZEROED IMMEDIATELY
+ // AFTER IT'S NO LONGER NEEDED. If you don't zero it, ~DjVuDocument()
+ // will kill it, which is a BAD thing if the file's already in cache.
+ GP<DjVuFile> ndir_file;
+
+ GPList<UnnamedFile> ufiles_list;
+ GCriticalSection ufiles_lock;
+
+ GPList<ThumbReq> threqs_list;
+ GCriticalSection threqs_lock;
+
+ GP<DjVuDocument> init_life_saver;
+
+ static const float thumb_gamma;
+
+ // Reads document contents in another thread trying to determine
+ // its type and structure
+ GThread init_thr;
+ static void static_init_thread(void *);
+ void init_thread(void);
+
+ void check() const;
+
+ void process_threqs(void);
+ GP<ThumbReq> add_thumb_req(const GP<ThumbReq> & thumb_req);
+
+ void add_to_cache(const GP<DjVuFile> & f);
+ void check_unnamed_files(void);
+ GUTF8String get_int_prefix(void) const;
+ void set_file_aliases(const DjVuFile * file);
+ GURL invent_url(const GUTF8String &name) const;
+};
+
+class DjVuDocument::UnnamedFile : public GPEnabled
+{
+public:
+ enum { ID, PAGE_NUM };
+ int id_type;
+ GUTF8String id;
+ int page_num;
+ GURL url;
+ GP<DjVuFile> file;
+ GP<DataPool> data_pool;
+protected:
+ UnnamedFile(int xid_type, const GUTF8String &xid, int xpage_num, const GURL & xurl,
+ const GP<DjVuFile> & xfile) :
+ id_type(xid_type), id(xid), page_num(xpage_num), url(xurl), file(xfile) {}
+ friend class DjVuDocument;
+};
+
+class DjVuDocument::ThumbReq : public GPEnabled
+{
+public:
+ int page_num;
+ GP<DataPool> data_pool;
+
+ // Either of the next two blocks should present
+ GP<DjVuFile> image_file;
+
+ int thumb_chunk;
+ GP<DjVuFile> thumb_file;
+protected:
+ ThumbReq(int xpage_num, const GP<DataPool> & xdata_pool) :
+ page_num(xpage_num), data_pool(xdata_pool) {}
+ friend class DjVuDocument;
+};
+
+inline void
+DjVuDocument::init(const GURL &url, GP<DjVuPort> port, DjVuFileCache *cache)
+{
+ start_init(url,port,cache);
+ wait_for_complete_init();
+}
+
+inline GP<DjVuDocument>
+DjVuDocument::create(
+ const GURL &url, GP<DjVuPort> xport, DjVuFileCache * const xcache)
+{
+ DjVuDocument *doc=new DjVuDocument;
+ GP<DjVuDocument> retval=doc;
+ doc->start_init(url,xport,xcache);
+ return retval;
+}
+
+inline bool
+DjVuDocument::is_init_complete(void) const
+{
+ return (flags & (DOC_INIT_OK | DOC_INIT_FAILED))!=0;
+}
+
+inline bool
+DjVuDocument::is_init_ok(void) const
+{
+ return (flags & DOC_INIT_OK)!=0;
+}
+
+inline void
+DjVuDocument::set_needs_compression(void)
+{
+ needs_compression_flag=true;
+}
+
+inline bool
+DjVuDocument::needs_compression(void) const
+{
+ return needs_compression_flag;
+}
+
+inline bool
+DjVuDocument::needs_rename(void) const
+{
+ return needs_rename_flag;
+}
+
+inline bool
+DjVuDocument::can_compress(void) const
+{
+ return can_compress_flag;
+}
+
+inline bool
+DjVuDocument::is_init_failed(void) const
+{
+ return (flags & DOC_INIT_FAILED)!=0;
+}
+
+inline int
+DjVuDocument::get_doc_type(void) const { return doc_type; }
+
+inline long
+DjVuDocument::get_doc_flags(void) const { return flags; }
+
+inline bool
+DjVuDocument::is_bundled(void) const
+{
+ return doc_type==BUNDLED || doc_type==OLD_BUNDLED;
+}
+
+inline GURL
+DjVuDocument::get_init_url(void) const { return init_url; }
+
+inline GP<DataPool>
+DjVuDocument::get_init_data_pool(void) const { return init_data_pool; }
+
+inline bool
+DjVuDocument::inherits(const GUTF8String &class_name) const
+{
+ return
+ (GUTF8String("DjVuDocument") == class_name) ||
+ DjVuPort::inherits(class_name);
+// !strcmp("DjVuDocument", class_name) ||
+// DjVuPort::inherits(class_name);
+}
+
+inline float
+DjVuDocument::get_thumbnails_gamma(void) const
+{
+ return thumb_gamma;
+}
+
+inline DjVuFileCache *
+DjVuDocument::get_cache(void) const
+{
+ return cache;
+}
+
+inline GP<DjVmDir>
+DjVuDocument::get_djvm_dir(void) const
+{
+ if (doc_type==SINGLE_PAGE)
+ G_THROW( ERR_MSG("DjVuDocument.no_dir") );
+ if (doc_type!=BUNDLED && doc_type!=INDIRECT)
+ G_THROW( ERR_MSG("DjVuDocument.obsolete") );
+ return djvm_dir;
+}
+
+inline GP<DjVmNav>
+DjVuDocument::get_djvm_nav(void) const
+{
+ if (doc_type==BUNDLED || doc_type==INDIRECT)
+ return djvm_nav;
+ return 0;
+}
+
+inline GP<DjVmDir0>
+DjVuDocument::get_djvm_dir0(void) const
+{
+ if (doc_type!=OLD_BUNDLED)
+ G_THROW( ERR_MSG("DjVuDocument.old_bundle") );
+ return djvm_dir0;
+}
+
+inline GP<DjVuNavDir>
+DjVuDocument::get_nav_dir(void) const
+{
+ return ndir;
+}
+
+inline void
+DjVuDocument::set_recover_errors(ErrorRecoveryAction recover)
+{
+ recover_errors=recover;
+}
+
+inline void
+DjVuDocument::set_verbose_eof(bool verbose)
+{
+ verbose_eof=verbose;
+}
+
+//@}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuDumpHelper.cpp b/kviewshell/plugins/djvu/libdjvu/DjVuDumpHelper.cpp
new file mode 100644
index 00000000..2d977be1
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuDumpHelper.cpp
@@ -0,0 +1,353 @@
+//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: DjVuDumpHelper.cpp,v 1.9 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 "DjVuDumpHelper.h"
+#include "DataPool.h"
+#include "DjVmDir.h"
+#include "DjVuInfo.h"
+#include "IFFByteStream.h"
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+#ifdef putchar
+#undef putchar
+#endif
+
+struct DjVmInfo
+{
+ GP<DjVmDir> dir;
+ GPMap<int,DjVmDir::File> map;
+};
+
+inline static void
+putchar(ByteStream & str, char ch)
+{
+ str.write(&ch, 1);
+}
+
+// ---------- ROUTINES FOR SUMMARIZING CHUNK DATA
+
+static void
+display_djvu_info(ByteStream & out_str, IFFByteStream &iff,
+ GUTF8String, size_t size, DjVmInfo&, int)
+{
+ GP<DjVuInfo> ginfo=DjVuInfo::create();
+ DjVuInfo &info=*ginfo;
+ info.decode(*iff.get_bytestream());
+ if (size >= 4)
+ out_str.format( "DjVu %dx%d", info.width, info.height);
+ if (size >= 5)
+ out_str.format( ", v%d", info.version);
+ if (size >= 8)
+ out_str.format( ", %d dpi", info.dpi);
+ if (size >= 8)
+ out_str.format( ", gamma=%3.1f", info.gamma);
+}
+
+static void
+display_djbz(ByteStream & out_str, IFFByteStream &iff,
+ GUTF8String, size_t, DjVmInfo&, int)
+{
+ out_str.format( "JB2 shared dictionary");
+}
+
+static void
+display_fgbz(ByteStream & out_str, IFFByteStream &iff,
+ GUTF8String, size_t, DjVmInfo&, int)
+{
+ out_str.format( "JB2 colors data");
+}
+
+static void
+display_sjbz(ByteStream & out_str, IFFByteStream &iff,
+ GUTF8String, size_t, DjVmInfo&, int)
+{
+ out_str.format( "JB2 bilevel data");
+}
+
+static void
+display_smmr(ByteStream & out_str, IFFByteStream &iff,
+ GUTF8String, size_t, DjVmInfo&, int)
+{
+ out_str.format( "G4/MMR stencil data");
+}
+
+static void
+display_iw4(ByteStream & out_str, IFFByteStream &iff,
+ GUTF8String, size_t, DjVmInfo&, int)
+{
+ GP<ByteStream> gbs = iff.get_bytestream();
+ unsigned char serial = gbs->read8();
+ unsigned char slices = gbs->read8();
+ out_str.format( "IW4 data #%d, %d slices", serial+1, slices);
+ if (serial == 0)
+ {
+ unsigned char major = gbs->read8();
+ unsigned char minor = gbs->read8();
+ unsigned char xhi = gbs->read8();
+ unsigned char xlo = gbs->read8();
+ unsigned char yhi = gbs->read8();
+ unsigned char ylo = gbs->read8();
+ out_str.format( ", v%d.%d (%s), %dx%d", major & 0x7f, minor,
+ (major & 0x80 ? "b&w" : "color"), (xhi<<8)+xlo, (yhi<<8)+ylo );
+ }
+}
+
+static void
+display_djvm_dirm(ByteStream & out_str, IFFByteStream & iff,
+ GUTF8String head, size_t, DjVmInfo& djvminfo, int)
+{
+ GP<DjVmDir> dir = DjVmDir::create();
+ dir->decode(iff.get_bytestream());
+ GPList<DjVmDir::File> list = dir->get_files_list();
+ if (dir->is_indirect())
+ {
+ out_str.format( "Document directory (indirect, %d files %d pages)",
+ dir->get_files_num(), dir->get_pages_num());
+ for (GPosition p=list; p; ++p)
+ out_str.format( "\n%s%s -> %s", (const char*)head,
+ (const char*)list[p]->get_load_name(), (const char*)list[p]->get_save_name() );
+ }
+ else
+ {
+ out_str.format( "Document directory (bundled, %d files %d pages)",
+ dir->get_files_num(), dir->get_pages_num());
+ djvminfo.dir = dir;
+ djvminfo.map.empty();
+ for (GPosition p=list; p; ++p)
+ djvminfo.map[list[p]->offset] = list[p];
+ }
+}
+
+static void
+display_th44(ByteStream & out_str, IFFByteStream & iff,
+ GUTF8String, size_t, DjVmInfo & djvminfo, int counter)
+{
+ int start_page=-1;
+ if (djvminfo.dir)
+ {
+ GPList<DjVmDir::File> files_list=djvminfo.dir->get_files_list();
+ for(GPosition pos=files_list;pos;++pos)
+ {
+ GP<DjVmDir::File> frec=files_list[pos];
+ if (iff.tell()>=frec->offset &&
+ iff.tell()<frec->offset+frec->size)
+ {
+ while(pos && !files_list[pos]->is_page())
+ ++pos;
+ if (pos)
+ start_page=files_list[pos]->get_page_num();
+ break;
+ }
+ }
+ }
+ if (start_page>=0)
+ out_str.format( "Thumbnail icon for page %d", start_page+counter+1);
+ else
+ out_str.format( "Thumbnail icon");
+}
+
+static void
+display_incl(ByteStream & out_str, IFFByteStream & iff,
+ GUTF8String, size_t, DjVmInfo&, int)
+{
+ GUTF8String name;
+ char ch;
+ while(iff.read(&ch, 1) && ch!='\n')
+ name += ch;
+ out_str.format( "Indirection chunk --> {%s}", (const char *) name);
+}
+
+static void
+display_anno(ByteStream & out_str, IFFByteStream &iff,
+ GUTF8String, size_t, DjVmInfo&, int)
+{
+ out_str.format( "Page annotation");
+ GUTF8String id;
+ iff.short_id(id);
+ out_str.format( " (hyperlinks, etc.)");
+}
+
+static void
+display_text(ByteStream & out_str, IFFByteStream &iff,
+ GUTF8String, size_t, DjVmInfo&, int)
+{
+ out_str.format( "Hidden text");
+ GUTF8String id;
+ iff.short_id(id);
+ out_str.format( " (text, etc.)");
+}
+
+struct displaysubr
+{
+ const char *id;
+ void (*subr)(ByteStream &, IFFByteStream &, GUTF8String,
+ size_t, DjVmInfo&, int counter);
+};
+
+static displaysubr disproutines[] =
+{
+ { "DJVU.INFO", display_djvu_info },
+ { "DJVU.Smmr", display_smmr },
+ { "DJVU.Sjbz", display_sjbz },
+ { "DJVU.Djbz", display_djbz },
+ { "DJVU.FG44", display_iw4 },
+ { "DJVU.BG44", display_iw4 },
+ { "DJVU.FGbz", display_fgbz },
+ { "DJVI.Sjbz", display_sjbz },
+ { "DJVI.Djbz", display_djbz },
+ { "DJVI.FGbz", display_fgbz },
+ { "DJVI.FG44", display_iw4 },
+ { "DJVI.BG44", display_iw4 },
+ { "BM44.BM44", display_iw4 },
+ { "PM44.PM44", display_iw4 },
+ { "DJVM.DIRM", display_djvm_dirm },
+ { "THUM.TH44", display_th44 },
+ { "INCL", display_incl },
+ { "ANTa", display_anno },
+ { "ANTz", display_anno },
+ { "TXTa", display_text },
+ { "TXTz", display_text },
+ { 0, 0 },
+};
+
+// ---------- ROUTINES FOR DISPLAYING CHUNK STRUCTURE
+
+static void
+display_chunks(ByteStream & out_str, IFFByteStream &iff,
+ const GUTF8String &head, DjVmInfo djvminfo)
+{
+ size_t size;
+ GUTF8String id, fullid;
+ GUTF8String head2 = head + " ";
+ GPMap<int,DjVmDir::File> djvmmap;
+ int rawoffset;
+ GMap<GUTF8String, int> counters;
+
+ while ((size = iff.get_chunk(id, &rawoffset)))
+ {
+ if (!counters.contains(id)) counters[id]=0;
+ else counters[id]++;
+
+ GUTF8String msg;
+ msg.format("%s%s [%d] ", (const char *)head, (const char *)id, size);
+ out_str.format( "%s", (const char *)msg);
+ // Display DJVM is when adequate
+ if (djvminfo.dir)
+ {
+ GP<DjVmDir::File> rec = djvminfo.map[rawoffset];
+ if (rec)
+ out_str.format( "{%s}", (const char*) rec->get_load_name());
+ }
+ // Test chunk type
+ iff.full_id(fullid);
+ for (int i=0; disproutines[i].id; i++)
+ if (fullid == disproutines[i].id || id == disproutines[i].id)
+ {
+ int n = msg.length();
+ while (n++ < 14+(int) head.length()) putchar(out_str, ' ');
+ if (!iff.composite()) out_str.format( " ");
+ (*disproutines[i].subr)(out_str, iff, head2,
+ size, djvminfo, counters[id]);
+ break;
+ }
+ // Default display of composite chunk
+ out_str.format( "\n");
+ if (iff.composite())
+ display_chunks(out_str, iff, head2, djvminfo);
+ // Terminate
+ iff.close_chunk();
+ }
+}
+
+GP<ByteStream>
+DjVuDumpHelper::dump(const GP<DataPool> & pool)
+{
+ return dump(pool->get_stream());
+}
+
+GP<ByteStream>
+DjVuDumpHelper::dump(GP<ByteStream> gstr)
+{
+ GP<ByteStream> out_str=ByteStream::create();
+ GUTF8String head=" ";
+ GP<IFFByteStream> iff=IFFByteStream::create(gstr);
+ DjVmInfo djvminfo;
+ display_chunks(*out_str, *iff, head, djvminfo);
+ return out_str;
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuDumpHelper.h b/kviewshell/plugins/djvu/libdjvu/DjVuDumpHelper.h
new file mode 100644
index 00000000..33be56c3
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuDumpHelper.h
@@ -0,0 +1,126 @@
+//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: DjVuDumpHelper.h,v 1.9 2003/11/07 22:08:20 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _DJVUDUMPHELPER_H
+#define _DJVUDUMPHELPER_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+/** @name DjVuDupmHelper.h
+ This file contains code capable of generating information on
+ DjVu documents without actually decoding them. The code has
+ been extracted from a command line utility \Ref{djvudump.cpp}
+ for use in the DjVu plugin.
+ @memo
+ DjVu Dump Helper.
+ @author
+ L\'eon Bottou <leonb@research.att.com> -- as a separate program.\\
+ Andrei Erofeev <eaf@geocities.com> -- as a class.
+ @version
+ #$Id: DjVuDumpHelper.h,v 1.9 2003/11/07 22:08:20 leonb Exp $# */
+//@{
+
+
+
+#include "GSmartPointer.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+class DataPool;
+class ByteStream;
+
+/** DjVuDumpHelper.
+ This class can dump information on any DjVu file without decoding it.
+ Based upon old \Ref{djvudump.cpp} code.
+ */
+
+class DjVuDumpHelper
+{
+public:
+ /// Default constructor
+ DjVuDumpHelper(void) {}
+ /// Destructor
+ ~DjVuDumpHelper(void) {}
+ /** Interprets the file passed in the \Ref{DataPool}, and returns
+ the results in \Ref{ByteStream}. */
+ GP<ByteStream> dump(const GP<DataPool> & pool);
+ /** Interprets the file passed in the \Ref{ByteStream}, and returns
+ the results in \Ref{ByteStream}. */
+ GP<ByteStream> dump(GP<ByteStream> str);
+};
+
+
+//@}
+
+// ----- THE END
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuErrorList.cpp b/kviewshell/plugins/djvu/libdjvu/DjVuErrorList.cpp
new file mode 100644
index 00000000..e7c74b84
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuErrorList.cpp
@@ -0,0 +1,174 @@
+//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: DjVuErrorList.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 "DjVuErrorList.h"
+#include "DjVmDoc.h"
+#include "GException.h"
+#include "GContainer.h"
+#include "GOS.h"
+#include "DataPool.h"
+#include <string.h>
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+DjVuErrorList::DjVuErrorList() {}
+
+GURL
+DjVuErrorList::set_stream(GP<ByteStream> xibs)
+{
+ GUTF8String name;
+ static unsigned long serial=0;
+ pool=DataPool::create(xibs);
+ name.format("data://%08lx/%08lx.djvu",
+ ++serial,(unsigned long)(size_t)((const ByteStream *)xibs));
+ pool_url=GURL::UTF8(name);
+ return pool_url;
+}
+
+bool
+DjVuErrorList::notify_error(const DjVuPort * source, const GUTF8String & msg)
+{
+ Errors.append(msg);
+ return 1;
+}
+
+bool
+DjVuErrorList::notify_status(const DjVuPort * source, const GUTF8String &msg)
+{
+ Status.append(msg);
+ return 1;
+}
+
+GUTF8String
+DjVuErrorList::GetError(void)
+{
+ GUTF8String PrevError;
+ GPosition pos;
+ if((pos=Errors))
+ {
+ PrevError=Errors[pos];
+ Errors.del(pos);
+ }
+ return PrevError;
+}
+
+GUTF8String
+DjVuErrorList::GetStatus(void)
+{
+ GUTF8String PrevStatus;
+ GPosition pos;
+ if((pos=Status))
+ {
+ PrevStatus=Status[pos];
+ Status.del(pos);
+ }
+ return PrevStatus;
+}
+
+GP<DataPool>
+DjVuErrorList::request_data(const DjVuPort * source, const GURL & url)
+{
+ GP<DataPool> retval;
+ G_TRY
+ {
+ if (pool && url.protocol().downcase() == "data")
+ {
+ if(url == pool_url)
+ {
+ retval=pool;
+ }else if(url.base() == pool_url)
+ {
+ GUTF8String name=url.fname();
+ GP<DjVmDoc> doc=DjVmDoc::create();
+ GP<ByteStream> bs=pool->get_stream();
+ doc->read(*bs);
+ retval=doc->get_data(name);
+ }
+ }else if (url.is_local_file_url())
+ {
+// GUTF8String fname=GOS::url_to_filename(url);
+// if (GOS::basename(fname)=="-") fname="-";
+ retval=DataPool::create(url);
+ }
+ }
+ G_CATCH_ALL
+ {
+ retval=0;
+ } G_ENDCATCH;
+ return retval;
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuErrorList.h b/kviewshell/plugins/djvu/libdjvu/DjVuErrorList.h
new file mode 100644
index 00000000..885e76aa
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuErrorList.h
@@ -0,0 +1,194 @@
+//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: DjVuErrorList.h,v 1.9 2003/11/07 22:08:20 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _DJVUERRORLIST_H
+#define _DJVUERRORLIST_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+#include "DjVuPort.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+class ByteStream;
+
+/** @name DjVuErrorList.h
+ This file implements a very simple class for redirecting port caster
+ messages that would normally end up on stderr to a double linked list.
+
+ @memo DjVuErrorList class.
+ @author Bill C Riemers <docbill@sourceforge.net>
+ @version #$Id: DjVuErrorList.h,v 1.9 2003/11/07 22:08:20 leonb Exp $#
+*/
+
+//@{
+
+/** #DjVuErrorList# provides a convenient way to redirect error messages
+ from classes derived from DjVuPort to a list that can be accessed at
+ any time. */
+
+class DjVuErrorList : public DjVuSimplePort
+{
+protected:
+ /// The normal port caster constructor.
+ DjVuErrorList(void);
+public:
+ static GP<DjVuErrorList> create(void) {return new DjVuErrorList();}
+
+ /// This constructor allows the user to specify the ByteStream.
+ GURL set_stream(GP<ByteStream>);
+
+ /// Append all error messages to the list
+ virtual bool notify_error(const DjVuPort * source, const GUTF8String & msg);
+
+ /// Append all status messages to the list
+ virtual bool notify_status(const DjVuPort * source, const GUTF8String & msg);
+
+ /// Add a new class to have its messages redirected here.
+ inline void connect( const DjVuPort &port);
+
+ /// Get the listing of errors, and clear the list.
+ inline GList<GUTF8String> GetErrorList(void);
+
+ /// Just clear the list.
+ inline void ClearError(void);
+
+ /// Get one error message and clear that message from the list.
+ GUTF8String GetError(void);
+
+ /// Check if there are anymore error messages.
+ inline bool HasError(void) const;
+
+ /// Get the listing of status messages, and clear the list.
+ inline GList<GUTF8String> GetStatusList(void);
+
+ /// Just clear the list.
+ inline void ClearStatus(void);
+
+ /// Get one status message and clear that message from the list.
+ GUTF8String GetStatus(void);
+
+ /// Check if there are any more status messages.
+ inline bool HasStatus(void) const;
+
+ /** This gets the data. We can't use the simple port's request
+ data since we want to allow the user to specify the ByteStream. */
+ virtual GP<DataPool> request_data (
+ const DjVuPort * source, const GURL & url );
+
+private:
+ GURL pool_url;
+ GP<DataPool> pool;
+ GList<GUTF8String> Errors;
+ GList<GUTF8String> Status;
+private: //dummy stuff
+ static GURL set_stream(ByteStream *);
+};
+
+inline void
+DjVuErrorList::connect( const DjVuPort &port )
+{ get_portcaster()->add_route(&port, this); }
+
+inline GList<GUTF8String>
+DjVuErrorList::GetErrorList(void)
+{
+ GList<GUTF8String> retval=(const GList<GUTF8String>)Errors;
+ Errors.empty();
+ return retval;
+}
+
+inline void
+DjVuErrorList::ClearError(void)
+{ Errors.empty(); }
+
+inline GList<GUTF8String>
+DjVuErrorList::GetStatusList(void)
+{
+ GList<GUTF8String> retval=(const GList<GUTF8String>)Status;
+ Status.empty();
+ return retval;
+}
+
+inline void
+DjVuErrorList::ClearStatus(void)
+{ Status.empty(); }
+
+inline bool
+DjVuErrorList::HasError(void) const
+{ return !Errors.isempty(); }
+
+inline bool
+DjVuErrorList::HasStatus(void) const
+{ return !Status.isempty(); }
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuFile.cpp b/kviewshell/plugins/djvu/libdjvu/DjVuFile.cpp
new file mode 100644
index 00000000..73e3a9c2
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuFile.cpp
@@ -0,0 +1,2831 @@
+//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: DjVuFile.cpp,v 1.11 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 "DjVuFile.h"
+#include "IFFByteStream.h"
+#include "GOS.h"
+#include "MMRDecoder.h"
+#ifdef NEED_JPEG_DECODER
+#include "JPEGDecoder.h"
+#endif
+#include "DjVuAnno.h"
+#include "DjVuText.h"
+#include "DataPool.h"
+#include "JB2Image.h"
+#include "IW44Image.h"
+#include "DjVuNavDir.h"
+#ifndef NEED_DECODER_ONLY
+#include "BSByteStream.h"
+#endif // NEED_DECODER_ONLY
+
+#include "debug.h"
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+#define STRINGIFY(x) STRINGIFY_(x)
+#define STRINGIFY_(x) #x
+
+
+#define REPORT_EOF(x) \
+ {G_TRY{G_THROW( ByteStream::EndOfFile );}G_CATCH(ex){report_error(ex,(x));}G_ENDCATCH;}
+
+static GP<GPixmap> (*djvu_decode_codec)(ByteStream &bs)=0;
+
+class ProgressByteStream : public ByteStream
+{
+public:
+ ProgressByteStream(const GP<ByteStream> & xstr) : str(xstr),
+ last_call_pos(0) {}
+ virtual ~ProgressByteStream() {}
+
+ virtual size_t read(void *buffer, size_t size)
+ {
+ int rc=0;
+ // G_TRY {} CATCH; block here is merely to avoid egcs internal error
+ G_TRY {
+ int cur_pos=str->tell();
+ if (progress_cb && (last_call_pos/256!=cur_pos/256))
+ {
+ progress_cb(cur_pos, progress_cl_data);
+ last_call_pos=cur_pos;
+ }
+ rc=str->read(buffer, size);
+ } G_CATCH_ALL {
+ G_RETHROW;
+ } G_ENDCATCH;
+ return rc;
+ }
+ virtual size_t write(const void *buffer, size_t size)
+ {
+ return str->write(buffer, size);
+ }
+ virtual int seek(long offset, int whence = SEEK_SET, bool nothrow=false)
+ {
+ return str->seek(offset, whence);
+ }
+ virtual long tell(void ) const { return str->tell(); }
+
+ void set_progress_cb(void (* xprogress_cb)(int, void *),
+ void * xprogress_cl_data)
+ {
+ progress_cb=xprogress_cb;
+ progress_cl_data=xprogress_cl_data;
+ }
+private:
+ GP<ByteStream> str;
+ void * progress_cl_data;
+ void (* progress_cb)(int pos, void *);
+ int last_call_pos;
+
+ // Cancel C++ default stuff
+ ProgressByteStream & operator=(const ProgressByteStream &);
+};
+
+
+DjVuFile::DjVuFile()
+: file_size(0), recover_errors(ABORT), verbose_eof(false), chunks_number(-1),
+initialized(false)
+{
+}
+
+void
+DjVuFile::check() const
+{
+ if (!initialized)
+ G_THROW( ERR_MSG("DjVuFile.not_init") );
+}
+
+GP<DjVuFile>
+DjVuFile::create(
+ const GP<ByteStream> & str, const ErrorRecoveryAction recover_errors,
+ const bool verbose_eof )
+{
+ DjVuFile *file=new DjVuFile();
+ GP<DjVuFile> retval=file;
+ file->set_recover_errors(recover_errors);
+ file->set_verbose_eof(verbose_eof);
+ file->init(str);
+ return retval;
+}
+
+void
+DjVuFile::init(const GP<ByteStream> & str)
+{
+ DEBUG_MSG("DjVuFile::DjVuFile(): ByteStream constructor\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (initialized)
+ G_THROW( ERR_MSG("DjVuFile.2nd_init") );
+ if (!get_count())
+ G_THROW( ERR_MSG("DjVuFile.not_secured") );
+
+ file_size=0;
+ decode_thread=0;
+
+ // Read the data from the stream
+ data_pool=DataPool::create(str);
+
+ // Construct some dummy URL
+ GUTF8String buffer;
+ buffer.format("djvufile:/%p.djvu", this);
+ DEBUG_MSG("DjVuFile::DjVuFile(): url is "<<(const char *)buffer<<"\n");
+ url=GURL::UTF8(buffer);
+
+ // Set it here because trigger will call other DjVuFile's functions
+ initialized=true;
+
+ // Add (basically - call) the trigger
+ data_pool->add_trigger(-1, static_trigger_cb, this);
+}
+
+GP<DjVuFile>
+DjVuFile::create(
+ const GURL & xurl, GP<DjVuPort> port,
+ const ErrorRecoveryAction recover_errors, const bool verbose_eof )
+{
+ DjVuFile *file=new DjVuFile();
+ GP<DjVuFile> retval=file;
+ file->set_recover_errors(recover_errors);
+ file->set_verbose_eof(verbose_eof);
+ file->init(xurl,port);
+ return retval;
+}
+
+void
+DjVuFile::init(const GURL & xurl, GP<DjVuPort> port)
+{
+ DEBUG_MSG("DjVuFile::init(): url='" << xurl << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (initialized)
+ G_THROW( ERR_MSG("DjVuFile.2nd_init") );
+ if (!get_count())
+ G_THROW( ERR_MSG("DjVuFile.not_secured") );
+ if (xurl.is_empty())
+ G_THROW( ERR_MSG("DjVuFile.empty_URL") );
+
+ url = xurl;
+ DEBUG_MSG("DjVuFile::DjVuFile(): url is "<<(const char *)url<<"\n");
+ file_size=0;
+ decode_thread=0;
+
+ DjVuPortcaster * pcaster=get_portcaster();
+
+ // We need it 'cause we're waiting for our own termination in stop_decode()
+ pcaster->add_route(this, this);
+ if (!port)
+ port = simple_port = new DjVuSimplePort();
+ pcaster->add_route(this, port);
+
+ // Set it here because trigger will call other DjVuFile's functions
+ initialized=true;
+
+ if (!(data_pool=DataPool::create(pcaster->request_data(this, url))))
+ G_THROW( ERR_MSG("DjVuFile.no_data") "\t"+url.get_string());
+ data_pool->add_trigger(-1, static_trigger_cb, this);
+}
+
+DjVuFile::~DjVuFile(void)
+{
+ DEBUG_MSG("DjVuFile::~DjVuFile(): destroying...\n");
+ DEBUG_MAKE_INDENT(3);
+
+ // No more messages. They may result in adding this file to a cache
+ // which will be very-very bad as we're being destroyed
+ get_portcaster()->del_port(this);
+
+ // Unregister the trigger (we don't want it to be called and attempt
+ // to access the destroyed object)
+ if (data_pool)
+ data_pool->del_trigger(static_trigger_cb, this);
+
+ // We don't have to wait for decoding to finish here. It's already
+ // finished (we know it because there is a "life saver" in the
+ // thread function) -- but we need to delete it
+ delete decode_thread; decode_thread=0;
+}
+
+void
+DjVuFile::reset(void)
+{
+ flags.enter();
+ info = 0;
+ anno = 0;
+ text = 0;
+ meta = 0;
+ bg44 = 0;
+ fgbc = 0;
+ fgjb = 0;
+ fgjd = 0;
+ fgpm = 0;
+ dir = 0;
+ description = "";
+ mimetype = "";
+ flags=(flags&(ALL_DATA_PRESENT|DECODE_STOPPED|DECODE_FAILED));
+ flags.leave();
+}
+
+unsigned int
+DjVuFile::get_memory_usage(void) const
+{
+ unsigned int size=sizeof(*this);
+ if (info) size+=info->get_memory_usage();
+ if (bg44) size+=bg44->get_memory_usage();
+ if (fgjb) size+=fgjb->get_memory_usage();
+ if (fgpm) size+=fgpm->get_memory_usage();
+ if (fgbc) size+=fgbc->size()*sizeof(int);
+ if (anno) size+=anno->size();
+ if (meta) size+=meta->size();
+ if (dir) size+=dir->get_memory_usage();
+ return size;
+}
+
+GPList<DjVuFile>
+DjVuFile::get_included_files(bool only_created)
+{
+ check();
+ if (!only_created && !are_incl_files_created())
+ process_incl_chunks();
+
+ GCriticalSectionLock lock(&inc_files_lock);
+ GPList<DjVuFile> list=inc_files_list; // Get a copy when locked
+ return list;
+}
+
+void
+DjVuFile::wait_for_chunk(void)
+// Will return after a chunk has been decoded
+{
+ check();
+ DEBUG_MSG("DjVuFile::wait_for_chunk() called\n");
+ DEBUG_MAKE_INDENT(3);
+ chunk_mon.enter();
+ chunk_mon.wait();
+ chunk_mon.leave();
+}
+
+bool
+DjVuFile::wait_for_finish(bool self)
+// if self==TRUE, will block until decoding of this file is over
+// if self==FALSE, will block until decoding of a child (direct
+// or indirect) is over.
+// Will return FALSE if there is nothing to wait for. TRUE otherwise
+{
+ DEBUG_MSG("DjVuFile::wait_for_finish(): self=" << self <<"\n");
+ DEBUG_MAKE_INDENT(3);
+
+ check();
+
+ if (self)
+ {
+ // It's best to check for self termination using flags. The reason
+ // is that finish_mon is updated in a DjVuPort function, which
+ // will not be called if the object is being destroyed
+ GMonitorLock lock(&flags);
+ if (is_decoding())
+ {
+ while(is_decoding()) flags.wait();
+ DEBUG_MSG("got it\n");
+ return 1;
+ }
+ } else
+ {
+ // By locking the monitor, we guarantee that situation doesn't change
+ // between the moments when we check for pending finish events
+ // and when we actually run wait(). If we don't lock, the last child
+ // may terminate in between, and we'll wait forever.
+ //
+ // Locking is required by GMonitor interface too, btw.
+ GMonitorLock lock(&finish_mon);
+ GP<DjVuFile> file;
+ {
+ GCriticalSectionLock lock(&inc_files_lock);
+ for(GPosition pos=inc_files_list;pos;++pos)
+ {
+ GP<DjVuFile> & f=inc_files_list[pos];
+ if (f->is_decoding())
+ {
+ file=f; break;
+ }
+ }
+ }
+ if (file)
+ {
+ finish_mon.wait();
+ DEBUG_MSG("got it\n");
+ return 1;
+ }
+ }
+ DEBUG_MSG("nothing to wait for\n");
+ return 0;
+}
+
+void
+DjVuFile::notify_chunk_done(const DjVuPort *, const GUTF8String &)
+{
+ check();
+ chunk_mon.enter();
+ chunk_mon.broadcast();
+ chunk_mon.leave();
+}
+
+void
+DjVuFile::notify_file_flags_changed(const DjVuFile * src,
+ long set_mask, long clr_mask)
+{
+ check();
+ if (set_mask & (DECODE_OK | DECODE_FAILED | DECODE_STOPPED))
+ {
+ // Signal threads waiting for file termination
+ finish_mon.enter();
+ finish_mon.broadcast();
+ finish_mon.leave();
+
+ // In case a thread is still waiting for a chunk
+ chunk_mon.enter();
+ chunk_mon.broadcast();
+ chunk_mon.leave();
+ }
+
+ if ((set_mask & ALL_DATA_PRESENT) && src!=this &&
+ are_incl_files_created() && is_data_present())
+ {
+ if (src!=this && are_incl_files_created() && is_data_present())
+ {
+ // Check if all children have data
+ bool all=true;
+ {
+ GCriticalSectionLock lock(&inc_files_lock);
+ for(GPosition pos=inc_files_list;pos;++pos)
+ if (!inc_files_list[pos]->is_all_data_present())
+ {
+ all=false;
+ break;
+ }
+ }
+ if (all)
+ {
+ DEBUG_MSG("Just got ALL data for '" << url << "'\n");
+ flags|=ALL_DATA_PRESENT;
+ get_portcaster()->notify_file_flags_changed(this, ALL_DATA_PRESENT, 0);
+ }
+ }
+ }
+}
+
+void
+DjVuFile::static_decode_func(void * cl_data)
+{
+ DjVuFile * th=(DjVuFile *) cl_data;
+
+ /* Please do not undo this life saver. If you do then try to resolve the
+ following conflict first:
+ 1. Decoding starts and there is only one external reference
+ to the DjVuFile.
+ 2. Decoding proceeds and calls DjVuPortcaster::notify_error(),
+ which creates inside a temporary GP<DjVuFile>.
+ 3. While notify_error() is running, the only external reference
+ is lost, but the DjVuFile is still alive (remember the
+ temporary GP<>?)
+ 4. The notify_error() returns, the temporary GP<> gets destroyed
+ and the DjVuFile is attempting to destroy right in the middle
+ of the decoding thread. This is either a dead block (waiting
+ for the termination of the decoding from the ~DjVuFile() called
+ from the decoding thread) or coredump. */
+ GP<DjVuFile> life_saver=th;
+ th->decode_life_saver=0;
+ G_TRY {
+ th->decode_func();
+ } G_CATCH_ALL {
+ } G_ENDCATCH;
+}
+
+void
+DjVuFile::decode_func(void)
+{
+ check();
+ DEBUG_MSG("DjVuFile::decode_func() called, url='" << url << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ DjVuPortcaster * pcaster=get_portcaster();
+
+ G_TRY {
+ const GP<ByteStream> decode_stream(decode_data_pool->get_stream());
+ ProgressByteStream *pstr=new ProgressByteStream(decode_stream);
+ const GP<ByteStream> gpstr(pstr);
+ pstr->set_progress_cb(progress_cb, this);
+
+ decode(gpstr);
+
+ // Wait for all child files to finish
+ while(wait_for_finish(0))
+ continue;
+
+ DEBUG_MSG("waiting for children termination\n");
+ // Check for termination status
+ GCriticalSectionLock lock(&inc_files_lock);
+ for(GPosition pos=inc_files_list;pos;++pos)
+ {
+ GP<DjVuFile> & f=inc_files_list[pos];
+ if (f->is_decode_failed())
+ G_THROW( ERR_MSG("DjVuFile.decode_fail") );
+ if (f->is_decode_stopped())
+ G_THROW( DataPool::Stop );
+ if (!f->is_decode_ok())
+ {
+ DEBUG_MSG("this_url='" << url << "'\n");
+ DEBUG_MSG("incl_url='" << f->get_url() << "'\n");
+ DEBUG_MSG("decoding=" << f->is_decoding() << "\n");
+ DEBUG_MSG("status='" << f->get_flags() << "\n");
+ G_THROW( ERR_MSG("DjVuFile.not_finished") );
+ }
+ }
+ } G_CATCH(exc) {
+ G_TRY {
+ if (!exc.cmp_cause(DataPool::Stop))
+ {
+ flags.enter();
+ flags=flags & ~DECODING | DECODE_STOPPED;
+ flags.leave();
+ pcaster->notify_status(this, GUTF8String(ERR_MSG("DjVuFile.stopped"))
+ + GUTF8String("\t") + GUTF8String(url));
+ pcaster->notify_file_flags_changed(this, DECODE_STOPPED, DECODING);
+ } else
+ {
+ flags.enter();
+ flags=flags & ~DECODING | DECODE_FAILED;
+ flags.leave();
+ pcaster->notify_status(this, GUTF8String(ERR_MSG("DjVuFile.failed"))
+ + GUTF8String("\t") + GUTF8String(url));
+ pcaster->notify_error(this, exc.get_cause());
+ pcaster->notify_file_flags_changed(this, DECODE_FAILED, DECODING);
+ }
+ } G_CATCH_ALL
+ {
+ DEBUG_MSG("******* Oops. Almost missed an exception\n");
+ } G_ENDCATCH;
+ } G_ENDCATCH;
+
+ decode_data_pool->clear_stream();
+ G_TRY {
+ if (flags.test_and_modify(DECODING, 0, DECODE_OK | INCL_FILES_CREATED, DECODING))
+ pcaster->notify_file_flags_changed(this, DECODE_OK | INCL_FILES_CREATED,
+ DECODING);
+ } G_CATCH_ALL {} G_ENDCATCH;
+ DEBUG_MSG("decoding thread for url='" << url << "' ended\n");
+}
+
+GP<DjVuFile>
+DjVuFile::process_incl_chunk(ByteStream & str, int file_num)
+{
+ check();
+ DEBUG_MSG("DjVuFile::process_incl_chunk(): processing INCL chunk...\n");
+ DEBUG_MAKE_INDENT(3);
+
+ DjVuPortcaster * pcaster=get_portcaster();
+
+ GUTF8String incl_str;
+ char buffer[1024];
+ int length;
+ while((length=str.read(buffer, 1024)))
+ incl_str+=GUTF8String(buffer, length);
+
+ // Eat '\n' in the beginning and at the end
+ while(incl_str.length() && incl_str[0]=='\n')
+ {
+ incl_str=incl_str.substr(1,(unsigned int)(-1));
+ }
+ while(incl_str.length()>0 && incl_str[(int)incl_str.length()-1]=='\n')
+ {
+ incl_str.setat(incl_str.length()-1, 0);
+ }
+
+ if (incl_str.length()>0)
+ {
+ if (strchr(incl_str, '/'))
+ G_THROW( ERR_MSG("DjVuFile.malformed") );
+
+ DEBUG_MSG("incl_str='" << incl_str << "'\n");
+
+ GURL incl_url=pcaster->id_to_url(this, incl_str);
+ if (incl_url.is_empty()) // Fallback. Should never be used.
+ incl_url=GURL::UTF8(incl_str,url.base());
+
+ // Now see if there is already a file with this *name* created
+ {
+ GCriticalSectionLock lock(&inc_files_lock);
+ GPosition pos;
+ for(pos=inc_files_list;pos;++pos)
+ {
+ if (inc_files_list[pos]->url.fname()==incl_url.fname())
+ break;
+ }
+ if (pos)
+ return inc_files_list[pos];
+ }
+
+ // No. We have to request a new file
+ GP<DjVuFile> file;
+ G_TRY
+ {
+ file=pcaster->id_to_file(this, incl_str);
+ }
+ G_CATCH(ex)
+ {
+ unlink_file(incl_str);
+ // In order to keep compatibility with the previous
+ // release of the DjVu plugin, we will not interrupt
+ // decoding here. We will just report the error.
+ // NOTE, that it's now the responsibility of the
+ // decoder to resolve all chunk dependencies, and
+ // abort decoding if necessary.
+
+ // G_EXTHROW(ex); /* commented out */
+
+ get_portcaster()->notify_error(this,ex.get_cause());
+ return 0;
+ }
+ G_ENDCATCH;
+ if (!file)
+ {
+ G_THROW( ERR_MSG("DjVuFile.no_create") "\t"+incl_str);
+ }
+ if (recover_errors!=ABORT)
+ file->set_recover_errors(recover_errors);
+ if (verbose_eof)
+ file->set_verbose_eof(verbose_eof);
+ pcaster->add_route(file, this);
+
+ // We may have been stopped. Make sure the child will be stopped too.
+ if (flags & STOPPED)
+ file->stop(false);
+ if (flags & BLOCKED_STOPPED)
+ file->stop(true);
+
+ // Lock the list again and check if the file has already been
+ // added by someone else
+ {
+ GCriticalSectionLock lock(&inc_files_lock);
+ GPosition pos;
+ for(pos=inc_files_list;pos;++pos)
+ {
+ if (inc_files_list[pos]->url.fname()==incl_url.fname())
+ break;
+ }
+ if (pos)
+ {
+ file=inc_files_list[pos];
+ } else if (file_num<0 || !(pos=inc_files_list.nth(file_num)))
+ {
+ inc_files_list.append(file);
+ } else
+ {
+ inc_files_list.insert_before(pos, file);
+ }
+ }
+ return file;
+ }
+ return 0;
+}
+
+
+void
+DjVuFile::report_error(const GException &ex,bool throw_errors)
+{
+ data_pool->clear_stream();
+ if((!verbose_eof)|| (ex.cmp_cause(ByteStream::EndOfFile)))
+ {
+ if(throw_errors)
+ {
+ G_EXTHROW(ex);
+ }else
+ {
+ get_portcaster()->notify_error(this,ex.get_cause());
+ }
+ }else
+ {
+ GURL url=get_url();
+ GUTF8String url_str=url.get_string();
+// if (url.is_local_file_url())
+// url_str=url.filename();
+
+ GUTF8String msg = GUTF8String( ERR_MSG("DjVuFile.EOF") "\t") + url;
+ if(throw_errors)
+ {
+ G_EXTHROW(ex, msg);
+ }else
+ {
+ get_portcaster()->notify_error(this,msg);
+ }
+ }
+}
+
+void
+DjVuFile::process_incl_chunks(void)
+// This function may block for data
+// NOTE: It may be called again when INCL_FILES_CREATED is set.
+// It happens in insert_file() when it has modified the data
+// and wants to create the actual file
+{
+ DEBUG_MSG("DjVuFile::process_incl_chunks(void)\n");
+ DEBUG_MAKE_INDENT(3);
+ check();
+
+ int incl_cnt=0;
+
+ const GP<ByteStream> str(data_pool->get_stream());
+ GUTF8String chkid;
+ const GP<IFFByteStream> giff(IFFByteStream::create(str));
+ IFFByteStream &iff=*giff;
+ if (iff.get_chunk(chkid))
+ {
+ int chunks=0;
+ int last_chunk=0;
+ G_TRY
+ {
+ int chunks_left=(recover_errors>SKIP_PAGES)?chunks_number:(-1);
+ int chksize;
+ for(;(chunks_left--)&&(chksize=iff.get_chunk(chkid));last_chunk=chunks)
+ {
+ chunks++;
+ if (chkid=="INCL")
+ {
+ G_TRY
+ {
+ process_incl_chunk(*iff.get_bytestream(), incl_cnt++);
+ }
+ G_CATCH(ex);
+ {
+ report_error(ex,(recover_errors <= SKIP_PAGES));
+ }
+ G_ENDCATCH;
+ }else if(chkid=="FAKE")
+ {
+ set_needs_compression(true);
+ set_can_compress(true);
+ }else if(chkid=="BGjp")
+ {
+ set_can_compress(true);
+ }else if(chkid=="Smmr")
+ {
+ set_can_compress(true);
+ }
+ iff.seek_close_chunk();
+ }
+ if (chunks_number < 0) chunks_number=last_chunk;
+ }
+ G_CATCH(ex)
+ {
+ if (chunks_number < 0)
+ chunks_number=(recover_errors>SKIP_CHUNKS)?chunks:last_chunk;
+ report_error(ex,(recover_errors <= SKIP_PAGES));
+ }
+ G_ENDCATCH;
+ }
+ flags|=INCL_FILES_CREATED;
+ data_pool->clear_stream();
+}
+
+GP<JB2Dict>
+DjVuFile::static_get_fgjd(void *arg)
+{
+ DjVuFile *file = (DjVuFile*)arg;
+ return file->get_fgjd(1);
+}
+
+GP<JB2Dict>
+DjVuFile::get_fgjd(int block)
+{
+ check();
+
+ // Simplest case
+ if (fgjd)
+ return fgjd;
+ // Check wether included files
+ chunk_mon.enter();
+ G_TRY {
+ for(;;)
+ {
+ int active = 0;
+ GPList<DjVuFile> incs = get_included_files();
+ for (GPosition pos=incs.firstpos(); pos; ++pos)
+ {
+ GP<DjVuFile> file = incs[pos];
+ if (file->is_decoding())
+ active = 1;
+ GP<JB2Dict> fgjd = file->get_fgjd();
+ if (fgjd)
+ {
+ chunk_mon.leave();
+ return fgjd;
+ }
+ }
+ // Exit if non-blocking mode
+ if (! block)
+ break;
+ // Exit if there is no decoding activity
+ if (! active)
+ break;
+ // Wait until a new chunk gets decoded
+ wait_for_chunk();
+ }
+ } G_CATCH_ALL {
+ chunk_mon.leave();
+ G_RETHROW;
+ } G_ENDCATCH;
+ chunk_mon.leave();
+ if (is_decode_stopped()) G_THROW( DataPool::Stop );
+ return 0;
+}
+
+int
+DjVuFile::get_dpi(int w, int h)
+{
+ int dpi=0, red=1;
+ if (info)
+ {
+ for(red=1; red<=12; red++)
+ if ((info->width+red-1)/red==w)
+ if ((info->height+red-1)/red==h)
+ break;
+ if (red>12)
+ G_THROW( ERR_MSG("DjVuFile.corrupt_BG44") );
+ dpi=info->dpi;
+ }
+ return (dpi ? dpi : 300)/red;
+}
+
+static inline bool
+is_info(const GUTF8String &chkid)
+{
+ return (chkid=="INFO");
+}
+
+static inline bool
+is_annotation(const GUTF8String &chkid)
+{
+ return (chkid=="ANTa" ||
+ chkid=="ANTz" ||
+ chkid=="FORM:ANNO" );
+}
+
+static inline bool
+is_text(const GUTF8String &chkid)
+{
+ return (chkid=="TXTa" || chkid=="TXTz");
+}
+
+static inline bool
+is_meta(const GUTF8String &chkid)
+{
+ return (chkid=="METa" || chkid=="METz");
+}
+
+
+GUTF8String
+DjVuFile::decode_chunk( const GUTF8String &id, const GP<ByteStream> &gbs,
+ bool djvi, bool djvu, bool iw44)
+{
+ DEBUG_MSG("DjVuFile::decode_chunk()\n");
+ ByteStream &bs=*gbs;
+ check();
+
+ // If this object is referenced by only one GP<> pointer, this
+ // pointer should be the "life_saver" created by the decoding thread.
+ // If it is the only GP<> pointer, then nobody is interested in the
+ // results of the decoding and we can abort now with #DataPool::Stop#
+ if (get_count()==1)
+ G_THROW( DataPool::Stop );
+
+ GUTF8String desc = ERR_MSG("DjVuFile.unrecog_chunk");
+ GUTF8String chkid = id;
+ DEBUG_MSG("DjVuFile::decode_chunk() : decoding " << id << "\n");
+
+ // INFO (information chunk for djvu page)
+ if (is_info(chkid) && (djvu || djvi))
+ {
+ if (info)
+ G_THROW( ERR_MSG("DjVuFile.corrupt_dupl") );
+ if (djvi)
+ G_THROW( ERR_MSG("DjVuFile.corrupt_INFO") );
+ // DjVuInfo::decode no longer throws version exceptions
+ GP<DjVuInfo> xinfo=DjVuInfo::create();
+ xinfo->decode(bs);
+ info = xinfo;
+ desc.format( ERR_MSG("DjVuFile.page_info") );
+ // Consistency checks (previously in DjVuInfo::decode)
+ if (info->width<0 || info->height<0)
+ G_THROW( ERR_MSG("DjVuFile.corrupt_zero") );
+ if (info->version >= DJVUVERSION_TOO_NEW)
+ G_THROW( ERR_MSG("DjVuFile.new_version") "\t" STRINGIFY(DJVUVERSION_TOO_NEW) );
+ if(info->compressable)
+ set_can_compress(true);
+ }
+
+ // INCL (inclusion chunk)
+ else if (chkid == "INCL" && (djvi || djvu || iw44))
+ {
+ GP<DjVuFile> file=process_incl_chunk(bs);
+ if (file)
+ {
+ int decode_was_already_started = 1;
+ {
+ GMonitorLock lock(&file->flags);
+ // Start decoding
+ if(file->resume_decode())
+ {
+ decode_was_already_started = 0;
+ }
+ }
+ // Send file notifications if previously started
+ if (decode_was_already_started)
+ {
+ // May send duplicate notifications...
+ if (file->is_decode_ok())
+ get_portcaster()->notify_file_flags_changed(file, DECODE_OK, 0);
+ else if (file->is_decode_failed())
+ get_portcaster()->notify_file_flags_changed(file, DECODE_FAILED, 0);
+ }
+ desc.format( ERR_MSG("DjVuFile.indir_chunk1") "\t" + file->get_url().fname() );
+ } else
+ desc.format( ERR_MSG("DjVuFile.indir_chunk2") );
+ }
+
+ // Djbz (JB2 Dictionary)
+ else if (chkid == "Djbz" && (djvu || djvi))
+ {
+ if (this->fgjd)
+ G_THROW( ERR_MSG("DjVuFile.dupl_Dxxx") );
+ if (this->fgjd)
+ G_THROW( ERR_MSG("DjVuFile.Dxxx_after_Sxxx") );
+ GP<JB2Dict> fgjd = JB2Dict::create();
+ fgjd->decode(gbs);
+ this->fgjd = fgjd;
+ desc.format( ERR_MSG("DjVuFile.shape_dict") "\t%d", fgjd->get_shape_count() );
+ }
+
+ // Sjbz (JB2 encoded mask)
+ else if (chkid=="Sjbz" && (djvu || djvi))
+ {
+ if (this->fgjb)
+ G_THROW( ERR_MSG("DjVuFile.dupl_Sxxx") );
+ GP<JB2Image> fgjb=JB2Image::create();
+ // ---- begin hack
+ if (info && info->version <=18)
+ fgjb->reproduce_old_bug = true;
+ // ---- end hack
+ fgjb->decode(gbs, static_get_fgjd, (void*)this);
+ this->fgjb = fgjb;
+ desc.format( ERR_MSG("DjVuFile.fg_mask") "\t%d\t%d\t%d",
+ fgjb->get_width(), fgjb->get_height(),
+ get_dpi(fgjb->get_width(), fgjb->get_height()));
+ }
+
+ // Smmr (MMR-G4 encoded mask)
+ else if (chkid=="Smmr" && (djvu || djvi))
+ {
+ if (this->fgjb)
+ G_THROW( ERR_MSG("DjVuFile.dupl_Sxxx") );
+ set_can_compress(true);
+ this->fgjb = MMRDecoder::decode(gbs);
+ desc.format( ERR_MSG("DjVuFile.G4_mask") "\t%d\t%d\t%d",
+ fgjb->get_width(), fgjb->get_height(),
+ get_dpi(fgjb->get_width(), fgjb->get_height()));
+ }
+
+ // BG44 (background wavelets)
+ else if (chkid == "BG44" && (djvu || djvi))
+ {
+ if (!bg44)
+ {
+ if (bgpm)
+ G_THROW( ERR_MSG("DjVuFile.dupl_backgrnd") );
+ // First chunk
+ GP<IW44Image> bg44=IW44Image::create_decode(IW44Image::COLOR);
+ bg44->decode_chunk(gbs);
+ this->bg44 = bg44;
+ desc.format( ERR_MSG("DjVuFile.IW44_bg1") "\t%d\t%d\t%d",
+ bg44->get_width(), bg44->get_height(),
+ get_dpi(bg44->get_width(), bg44->get_height()));
+ }
+ else
+ {
+ // Refinement chunks
+ GP<IW44Image> bg44 = this->bg44;
+ bg44->decode_chunk(gbs);
+ desc.format( ERR_MSG("DjVuFile.IW44_bg2") "\t%d\t%d",
+ bg44->get_serial(), get_dpi(bg44->get_width(), bg44->get_height()));
+ }
+ }
+
+ // FG44 (foreground wavelets)
+ else if (chkid == "FG44" && (djvu || djvu))
+ {
+ if (fgpm || fgbc)
+ G_THROW( ERR_MSG("DjVuFile.dupl_foregrnd") );
+ GP<IW44Image> gfg44=IW44Image::create_decode(IW44Image::COLOR);
+ IW44Image &fg44=*gfg44;
+ fg44.decode_chunk(gbs);
+ fgpm=fg44.get_pixmap();
+ desc.format( ERR_MSG("DjVuFile.IW44_fg") "\t%d\t%d\t%d",
+ fg44.get_width(), fg44.get_height(),
+ get_dpi(fg44.get_width(), fg44.get_height()));
+ }
+
+ // LINK (background LINK)
+ else if (chkid == "LINK" && (djvu || djvi))
+ {
+ if (bg44 || bgpm)
+ G_THROW( ERR_MSG("DjVuFile.dupl_backgrnd") );
+ if(djvu_decode_codec)
+ {
+ set_modified(true);
+ set_can_compress(true);
+ set_needs_compression(true);
+ this->bgpm = djvu_decode_codec(bs);
+ desc.format( ERR_MSG("DjVuFile.color_import1") "\t%d\t%d\t%d",
+ bgpm->columns(), bgpm->rows(),
+ get_dpi(bgpm->columns(), bgpm->rows()));
+ }else
+ {
+ desc.format( ERR_MSG("DjVuFile.color_import2") );
+ }
+ }
+
+ // BGjp (background JPEG)
+ else if (chkid == "BGjp" && (djvu || djvi))
+ {
+ if (bg44 || bgpm)
+ G_THROW( ERR_MSG("DjVuFile.dupl_backgrnd") );
+ set_can_compress(true);
+#ifdef NEED_JPEG_DECODER
+ this->bgpm = JPEGDecoder::decode(bs);
+ desc.format( ERR_MSG("DjVuFile.JPEG_bg1") "\t%d\t%d\t%d",
+ bgpm->columns(), bgpm->rows(),
+ get_dpi(bgpm->columns(), bgpm->rows()));
+#else
+ desc.format( ERR_MSG("DjVuFile.JPEG_bg2") );
+#endif
+ }
+
+ // FGjp (foreground JPEG)
+ else if (chkid == "FGjp" && (djvu || djvi))
+ {
+ if (fgpm || fgbc)
+ G_THROW( ERR_MSG("DjVuFile.dupl_foregrnd") );
+#ifdef NEED_JPEG_DECODER
+ this->fgpm = JPEGDecoder::decode(bs);
+ desc.format( ERR_MSG("DjVuFile.JPEG_fg1") "\t%d\t%d\t%d",
+ fgpm->columns(), fgpm->rows(),
+ get_dpi(fgpm->columns(), fgpm->rows()));
+#else
+ desc.format( ERR_MSG("DjVuFile.JPEG_fg2") );
+#endif
+ }
+
+ // BG2k (background JPEG-2000) Note: JPEG2K bitstream not finalized.
+ else if (chkid == "BG2k" && (djvu || djvi))
+ {
+ if (bg44)
+ G_THROW( ERR_MSG("DjVuFile.dupl_backgrnd") );
+ desc.format( ERR_MSG("DjVuFile.JPEG2K_bg") );
+ }
+
+ // FG2k (foreground JPEG-2000) Note: JPEG2K bitstream not finalized.
+ else if (chkid == "FG2k" && (djvu || djvi))
+ {
+ if (fgpm || fgbc)
+ G_THROW( ERR_MSG("DjVuFile.dupl_foregrnd") );
+ desc.format( ERR_MSG("DjVuFile.JPEG2K_fg") );
+ }
+
+ // FGbz (foreground color vector)
+ else if (chkid == "FGbz" && (djvu || djvi))
+ {
+ if (fgpm || fgbc)
+ G_THROW( ERR_MSG("DjVuFile.dupl_foregrnd") );
+ GP<DjVuPalette> fgbc = DjVuPalette::create();
+ fgbc->decode(gbs);
+ this->fgbc = fgbc;
+ desc.format( ERR_MSG("DjVuFile.JB2_fg") "\t%d\t%d",
+ fgbc->size(), fgbc->colordata.size());
+ }
+
+ // BM44/PM44 (IW44 data)
+ else if ((chkid == "PM44" || chkid=="BM44") && iw44)
+ {
+ if (!bg44)
+ {
+ // First chunk
+ GP<IW44Image> bg44 = IW44Image::create_decode(IW44Image::COLOR);
+ bg44->decode_chunk(gbs);
+ GP<DjVuInfo> info = DjVuInfo::create();
+ info->width = bg44->get_width();
+ info->height = bg44->get_height();
+ info->dpi = 100;
+ this->bg44 = bg44;
+ this->info = info;
+ desc.format( ERR_MSG("DjVuFile.IW44_data1") "\t%d\t%d\t%d",
+ bg44->get_width(), bg44->get_height(),
+ get_dpi(bg44->get_width(), bg44->get_height()));
+ }
+ else
+ {
+ // Refinement chunks
+ GP<IW44Image> bg44 = this->bg44;
+ bg44->decode_chunk(gbs);
+ desc.format( ERR_MSG("DjVuFile.IW44_data2") "\t%d\t%d",
+ bg44->get_serial(),
+ get_dpi(bg44->get_width(), bg44->get_height()));
+ }
+ }
+
+ // NDIR (obsolete navigation chunk)
+ else if (chkid == "NDIR")
+ {
+ GP<DjVuNavDir> dir=DjVuNavDir::create(url);
+ dir->decode(bs);
+ this->dir=dir;
+ desc.format( ERR_MSG("DjVuFile.nav_dir") );
+ }
+
+ // FORM:ANNO (obsolete) (must be before other annotations)
+ else if (chkid == "FORM:ANNO")
+ {
+ const GP<ByteStream> gachunk(ByteStream::create());
+ ByteStream &achunk=*gachunk;
+ achunk.copy(bs);
+ achunk.seek(0);
+ GCriticalSectionLock lock(&anno_lock);
+ if (! anno)
+ {
+ anno=ByteStream::create();
+ }
+ anno->seek(0,SEEK_END);
+ if (anno->tell())
+ {
+ anno->write((void*)"", 1);
+ }
+ // Copy data
+ anno->copy(achunk);
+ desc.format( ERR_MSG("DjVuFile.anno1") );
+ }
+
+ // ANTa/ANTx/TXTa/TXTz annotations
+ else if (is_annotation(chkid)) // but not FORM:ANNO
+ {
+ const GP<ByteStream> gachunk(ByteStream::create());
+ ByteStream &achunk=*gachunk;
+ achunk.copy(bs);
+ achunk.seek(0);
+ GCriticalSectionLock lock(&anno_lock);
+ if (! anno)
+ {
+ anno = ByteStream::create();
+ }
+ anno->seek(0,SEEK_END);
+ if (anno->tell() & 1)
+ {
+ anno->write((const void*)"", 1);
+ }
+ // Recreate chunk header
+ const GP<IFFByteStream> giffout(IFFByteStream::create(anno));
+ IFFByteStream &iffout=*giffout;
+ iffout.put_chunk(id);
+ iffout.copy(achunk);
+ iffout.close_chunk();
+ desc.format( ERR_MSG("DjVuFile.anno2") );
+ }
+ else if (is_text(chkid))
+ {
+ const GP<ByteStream> gachunk(ByteStream::create());
+ ByteStream &achunk=*gachunk;
+ achunk.copy(bs);
+ achunk.seek(0);
+ GCriticalSectionLock lock(&text_lock);
+ if (! text)
+ {
+ text = ByteStream::create();
+ }
+ text->seek(0,SEEK_END);
+ if (text->tell())
+ {
+ text->write((const void*)"", 1);
+ }
+ // Recreate chunk header
+ const GP<IFFByteStream> giffout(IFFByteStream::create(text));
+ IFFByteStream &iffout=*giffout;
+ iffout.put_chunk(id);
+ iffout.copy(achunk);
+ iffout.close_chunk();
+ desc.format( ERR_MSG("DjVuFile.text") );
+ }
+ else if (is_meta(chkid))
+ {
+ const GP<ByteStream> gachunk(ByteStream::create());
+ ByteStream &achunk=*gachunk;
+ achunk.copy(bs);
+ achunk.seek(0);
+ GCriticalSectionLock lock(&text_lock);
+ if (! meta)
+ {
+ meta = ByteStream::create();
+ }
+ meta->seek(0,SEEK_END);
+ if (meta->tell())
+ {
+ meta->write((const void*)"", 1);
+ }
+ // Recreate chunk header
+ const GP<IFFByteStream> giffout(IFFByteStream::create(meta));
+ IFFByteStream &iffout=*giffout;
+ iffout.put_chunk(id);
+ iffout.copy(achunk);
+ iffout.close_chunk();
+// desc.format( ERR_MSG("DjVuFile.text") );
+ }
+
+ // Return description
+ return desc;
+}
+
+void
+DjVuFile::set_decode_codec(GP<GPixmap> (*codec)(ByteStream &bs))
+{
+ djvu_decode_codec=codec;
+}
+
+void
+DjVuFile::decode(const GP<ByteStream> &gbs)
+{
+ check();
+ DEBUG_MSG("DjVuFile::decode(), url='" << url << "'\n");
+ DEBUG_MAKE_INDENT(3);
+ DjVuPortcaster * pcaster=get_portcaster();
+
+ // Get form chunk
+ GUTF8String chkid;
+ const GP<IFFByteStream> giff(IFFByteStream::create(gbs));
+ IFFByteStream &iff=*giff;
+ if (!iff.get_chunk(chkid))
+ REPORT_EOF(true)
+
+ // Check file format
+ bool djvi = (chkid=="FORM:DJVI")?true:false;
+ bool djvu = (chkid=="FORM:DJVU")?true:false;
+ bool iw44 = ((chkid=="FORM:PM44") || (chkid=="FORM:BM44"));
+ if (djvi || djvu)
+ mimetype = "image/x.djvu";
+ else if (iw44)
+ mimetype = "image/x-iw44";
+ else
+ G_THROW( ERR_MSG("DjVuFile.unexp_image") );
+
+ // Process chunks
+ int size_so_far=iff.tell();
+ int chunks=0;
+ int last_chunk=0;
+ G_TRY
+ {
+ int chunks_left=(recover_errors>SKIP_PAGES)?chunks_number:(-1);
+ int chksize;
+ for(;(chunks_left--)&&(chksize = iff.get_chunk(chkid));last_chunk=chunks)
+ {
+ chunks++;
+
+ // Decode and get chunk description
+ GUTF8String str = decode_chunk(chkid, iff.get_bytestream(), djvi, djvu, iw44);
+ // Add parameters to the chunk description to give the size and chunk id
+ GUTF8String desc;
+ desc.format("\t%5.1f\t%s", chksize/1024.0, (const char*)chkid);
+ // Append the whole thing to the growing file description
+ description = description + str + desc + "\n";
+
+ pcaster->notify_chunk_done(this, chkid);
+ // Close chunk
+ iff.seek_close_chunk();
+ // Record file size
+ size_so_far=iff.tell();
+ }
+ if (chunks_number < 0) chunks_number=last_chunk;
+ }
+ G_CATCH(ex)
+ {
+ if(!ex.cmp_cause(ByteStream::EndOfFile))
+ {
+ if (chunks_number < 0)
+ chunks_number=(recover_errors>SKIP_CHUNKS)?chunks:last_chunk;
+ report_error(ex,(recover_errors <= SKIP_PAGES));
+ }else
+ {
+ report_error(ex,true);
+ }
+ }
+ G_ENDCATCH;
+
+ // Record file size
+ file_size=size_so_far;
+ // Close form chunk
+ iff.close_chunk();
+ // Close BG44 codec
+ if (bg44)
+ bg44->close_codec();
+
+ // Complete description
+ if (djvu && !info)
+ G_THROW( ERR_MSG("DjVuFile.corrupt_missing_info") );
+ if (iw44 && !info)
+ G_THROW( ERR_MSG("DjVuFile.corrupt_missing_IW44") );
+ if (info)
+ {
+ GUTF8String desc;
+ if (djvu || djvi)
+ desc.format( ERR_MSG("DjVuFile.djvu_header") "\t%d\t%d\t%d\t%d",
+ info->width, info->height,
+ info->dpi, info->version);
+ else if (iw44)
+ desc.format( ERR_MSG("DjVuFile.IW44_header") "\t%d\t%d\t%d",
+ info->width, info->height, info->dpi);
+ description=desc + "\n" + description;
+ int rawsize=info->width*info->height*3;
+ desc.format( ERR_MSG("DjVuFile.ratio") "\t%0.1f\t%0.1f",
+ (double)rawsize/file_size, file_size/1024.0 );
+ description=description+desc;
+ }
+}
+
+void
+DjVuFile::start_decode(void)
+{
+ check();
+ DEBUG_MSG("DjVuFile::start_decode(), url='" << url << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GThread * thread_to_delete=0;
+ flags.enter();
+ G_TRY {
+ if (!(flags & DONT_START_DECODE) && !is_decoding())
+ {
+ if (flags & DECODE_STOPPED) reset();
+ flags&=~(DECODE_OK | DECODE_STOPPED | DECODE_FAILED);
+ flags|=DECODING;
+
+ // Don't delete the thread while you're owning the flags lock
+ // Beware of deadlock!
+ thread_to_delete=decode_thread; decode_thread=0;
+
+ // We want to create it right here to be able to stop the
+ // decoding thread even before its function is called (it starts)
+ decode_data_pool=DataPool::create(data_pool);
+ decode_life_saver=this;
+
+ decode_thread=new GThread();
+ decode_thread->create(static_decode_func, this);
+ }
+ }
+ G_CATCH_ALL
+ {
+ flags&=~DECODING;
+ flags|=DECODE_FAILED;
+ flags.leave();
+ get_portcaster()->notify_file_flags_changed(this, DECODE_FAILED, DECODING);
+ delete thread_to_delete;
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+ flags.leave();
+ delete thread_to_delete;
+}
+
+bool
+DjVuFile::resume_decode(const bool sync)
+{
+ bool retval=false;
+ {
+ GMonitorLock lock(&flags);
+ if( !is_decoding() && !is_decode_ok() && !is_decode_failed() )
+ {
+ start_decode();
+ retval=true;
+ }
+ }
+ if(sync)
+ {
+ wait_for_finish();
+ }
+ return retval;
+}
+
+void
+DjVuFile::stop_decode(bool sync)
+{
+ check();
+
+ DEBUG_MSG("DjVuFile::stop_decode(), url='" << url <<
+ "', sync=" << (int) sync << "\n");
+ DEBUG_MAKE_INDENT(3);
+
+ G_TRY
+ {
+ flags|=DONT_START_DECODE;
+
+ // Don't stop SYNCHRONOUSLY from the thread where the decoding is going!!!
+ {
+ // First - ask every included child to stop in async mode
+ GCriticalSectionLock lock(&inc_files_lock);
+ for(GPosition pos=inc_files_list;pos;++pos)
+ inc_files_list[pos]->stop_decode(0);
+
+// if (decode_data_pool) decode_data_pool->stop();
+ }
+
+ if (sync)
+ {
+ while(1)
+ {
+ GP<DjVuFile> file;
+ {
+ GCriticalSectionLock lock(&inc_files_lock);
+ for(GPosition pos=inc_files_list;pos;++pos)
+ {
+ GP<DjVuFile> & f=inc_files_list[pos];
+ if (f->is_decoding())
+ {
+ file=f; break;
+ }
+ }
+ }
+ if (!file) break;
+
+ file->stop_decode(1);
+ }
+
+ wait_for_finish(1); // Wait for self termination
+
+ // Don't delete the thread here. Until GPBase::preserve() is
+ // reimplemented somehow at the GThread level.
+ // delete decode_thread; decode_thread=0;
+ }
+ flags&=~(DONT_START_DECODE);
+ } G_CATCH_ALL {
+ flags&=~(DONT_START_DECODE);
+ G_RETHROW;
+ } G_ENDCATCH;
+}
+
+void
+DjVuFile::stop(bool only_blocked)
+// This is a one-way function. There is no way to undo the stop()
+// command.
+{
+ DEBUG_MSG("DjVuFile::stop(): Stopping everything\n");
+ DEBUG_MAKE_INDENT(3);
+
+ flags|=only_blocked ? BLOCKED_STOPPED : STOPPED;
+ if (data_pool) data_pool->stop(only_blocked);
+ GCriticalSectionLock lock(&inc_files_lock);
+ for(GPosition pos=inc_files_list;pos;++pos)
+ inc_files_list[pos]->stop(only_blocked);
+}
+
+GP<DjVuNavDir>
+DjVuFile::find_ndir(GMap<GURL, void *> & map)
+{
+ check();
+
+ DEBUG_MSG("DjVuFile::find_ndir(): looking for NDIR in '" << url << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (dir) return dir;
+
+ if (!map.contains(url))
+ {
+ map[url]=0;
+
+ GPList<DjVuFile> list=get_included_files(false);
+ for(GPosition pos=list;pos;++pos)
+ {
+ GP<DjVuNavDir> d=list[pos]->find_ndir(map);
+ if (d) return d;
+ }
+ }
+ return 0;
+}
+
+GP<DjVuNavDir>
+DjVuFile::find_ndir(void)
+{
+ GMap<GURL, void *> map;
+ return find_ndir(map);
+}
+
+GP<DjVuNavDir>
+DjVuFile::decode_ndir(GMap<GURL, void *> & map)
+{
+ check();
+
+ DEBUG_MSG("DjVuFile::decode_ndir(): decoding for NDIR in '" << url << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (dir) return dir;
+
+ if (!map.contains(url))
+ {
+ map[url]=0;
+
+ const GP<ByteStream> str(data_pool->get_stream());
+
+ GUTF8String chkid;
+ const GP<IFFByteStream> giff(IFFByteStream::create(str));
+ IFFByteStream &iff=*giff;
+ if (!iff.get_chunk(chkid))
+ REPORT_EOF(true)
+
+ int chunks=0;
+ int last_chunk=0;
+ G_TRY
+ {
+ int chunks_left=(recover_errors>SKIP_PAGES)?chunks_number:(-1);
+ int chksize;
+ for(;(chunks_left--)&&(chksize=iff.get_chunk(chkid));last_chunk=chunks)
+ {
+ chunks++;
+ if (chkid=="NDIR")
+ {
+ GP<DjVuNavDir> d=DjVuNavDir::create(url);
+ d->decode(*iff.get_bytestream());
+ dir=d;
+ break;
+ }
+ iff.seek_close_chunk();
+ }
+ if ((!dir)&&(chunks_number < 0)) chunks_number=last_chunk;
+ }
+ G_CATCH(ex)
+ {
+ if(!ex.cmp_cause(ByteStream::EndOfFile))
+ {
+ if (chunks_number < 0)
+ chunks_number=(recover_errors>SKIP_CHUNKS)?chunks:last_chunk;
+ report_error(ex,(recover_errors<=SKIP_PAGES));
+ }else
+ {
+ report_error(ex,true);
+ }
+ }
+ G_ENDCATCH;
+
+ data_pool->clear_stream();
+ if (dir) return dir;
+
+ GPList<DjVuFile> list=get_included_files(false);
+ for(GPosition pos=list;pos;++pos)
+ {
+ GP<DjVuNavDir> d=list[pos]->decode_ndir(map);
+ if (d) return d;
+ }
+ data_pool->clear_stream();
+ }
+ return 0;
+}
+
+GP<DjVuNavDir>
+DjVuFile::decode_ndir(void)
+{
+ GMap<GURL, void *> map;
+ return decode_ndir(map);
+}
+
+void
+DjVuFile::get_merged_anno(const GP<DjVuFile> & file,
+ const GP<ByteStream> &gstr_out, const GList<GURL> & ignore_list,
+ int level, int & max_level, GMap<GURL, void *> & map)
+{
+ DEBUG_MSG("DjVuFile::get_merged_anno()\n");
+ GURL url=file->get_url();
+ if (!map.contains(url))
+ {
+ ByteStream &str_out=*gstr_out;
+ map[url]=0;
+
+ // Do the included files first (To make sure that they have
+ // less precedence)
+ // Depending on if we have all data present, we will
+ // either create all included files or will use only
+ // those that have already been created
+ GPList<DjVuFile> list=file->get_included_files(!file->is_data_present());
+ for(GPosition pos=list;pos;++pos)
+ get_merged_anno(list[pos], gstr_out, ignore_list, level+1, max_level, map);
+
+ // Now process the DjVuFile's own annotations
+ if (!ignore_list.contains(file->get_url()))
+ {
+ if (!file->is_data_present() ||
+ file->is_modified() && file->anno)
+ {
+ // Process the decoded (?) anno
+ GCriticalSectionLock lock(&file->anno_lock);
+ if (file->anno && file->anno->size())
+ {
+ if (str_out.tell())
+ {
+ str_out.write((void *) "", 1);
+ }
+ file->anno->seek(0);
+ str_out.copy(*file->anno);
+ }
+ } else if (file->is_data_present())
+ {
+ // Copy all annotations chunks, but do NOT modify
+ // this->anno (to avoid correlation with DjVuFile::decode())
+ const GP<ByteStream> str(file->data_pool->get_stream());
+ const GP<IFFByteStream> giff(IFFByteStream::create(str));
+ IFFByteStream &iff=*giff;
+ GUTF8String chkid;
+ if (iff.get_chunk(chkid))
+ while(iff.get_chunk(chkid))
+ {
+ if (chkid=="FORM:ANNO")
+ {
+ if (max_level<level)
+ max_level=level;
+ if (str_out.tell())
+ {
+ str_out.write((void *) "", 1);
+ }
+ str_out.copy(*iff.get_bytestream());
+ }
+ else if (is_annotation(chkid)) // but not FORM:ANNO
+ {
+ if (max_level<level)
+ max_level=level;
+ if (str_out.tell()&&chkid != "ANTz")
+ {
+ str_out.write((void *) "", 1);
+ }
+ const GP<IFFByteStream> giff_out(IFFByteStream::create(gstr_out));
+ IFFByteStream &iff_out=*giff_out;
+ iff_out.put_chunk(chkid);
+ iff_out.copy(*iff.get_bytestream());
+ iff_out.close_chunk();
+ }
+ iff.close_chunk();
+ }
+ file->data_pool->clear_stream();
+ }
+ }
+ }
+}
+
+GP<ByteStream>
+DjVuFile::get_merged_anno(const GList<GURL> & ignore_list,
+ int * max_level_ptr)
+ // Will do the same thing as get_merged_anno(int *), but will
+ // ignore DjVuFiles with URLs from the ignore_list
+{
+ DEBUG_MSG("DjVuFile::get_merged_anno()\n");
+ GP<ByteStream> gstr(ByteStream::create());
+ GMap<GURL, void *> map;
+ int max_level=0;
+ get_merged_anno(this, gstr, ignore_list, 0, max_level, map);
+ if (max_level_ptr)
+ *max_level_ptr=max_level;
+ ByteStream &str=*gstr;
+ if (!str.tell())
+ {
+ gstr=0;
+ }else
+ {
+ str.seek(0);
+ }
+ return gstr;
+}
+
+GP<ByteStream>
+DjVuFile::get_merged_anno(int * max_level_ptr)
+// Will go down the DjVuFile's hierarchy and decode all DjVuAnno even
+// when the DjVuFile is not fully decoded yet. To avoid correlations
+// with DjVuFile::decode(), we do not modify DjVuFile::anno data.
+//
+// Files deeper in the hierarchy have less influence on the
+// results. It means, for example, that the if annotations are
+// specified in the top level page file and in a shared file,
+// the top level page file settings will take precedence.
+//
+// NOTE! This function guarantees correct results only if the
+// DjVuFile has all data
+{
+ GList<GURL> ignore_list;
+ return get_merged_anno(ignore_list, max_level_ptr);
+}
+
+
+// [LB->BCR] The following six functions get_anno, get_text, get_meta
+// contain the same code in triplicate!!!
+
+void
+DjVuFile::get_anno(
+ const GP<DjVuFile> & file, const GP<ByteStream> &gstr_out)
+{
+ DEBUG_MSG("DjVuFile::get_anno()\n");
+ ByteStream &str_out=*gstr_out;
+ if (!file->is_data_present() ||
+ file->is_modified() && file->anno)
+ {
+ // Process the decoded (?) anno
+ GCriticalSectionLock lock(&file->anno_lock);
+ if (file->anno && file->anno->size())
+ {
+ if (str_out.tell())
+ {
+ str_out.write((void *) "", 1);
+ }
+ file->anno->seek(0);
+ str_out.copy(*file->anno);
+ }
+ } else if (file->is_data_present())
+ {
+ // Copy all anno chunks, but do NOT modify
+ // DjVuFile::anno (to avoid correlation with DjVuFile::decode())
+ const GP<ByteStream> str=file->data_pool->get_stream();
+ const GP<IFFByteStream> giff=IFFByteStream::create(str);
+ IFFByteStream &iff=*giff;
+ GUTF8String chkid;
+ if (iff.get_chunk(chkid))
+ {
+ while(iff.get_chunk(chkid))
+ {
+ if (is_annotation(chkid))
+ {
+ if (str_out.tell())
+ {
+ str_out.write((void *) "", 1);
+ }
+ const GP<IFFByteStream> giff_out(IFFByteStream::create(gstr_out));
+ IFFByteStream &iff_out=*giff_out;
+ iff_out.put_chunk(chkid);
+ iff_out.copy(*iff.get_bytestream());
+ iff_out.close_chunk();
+ }
+ iff.close_chunk();
+ }
+ }
+ file->data_pool->clear_stream();
+ }
+}
+
+void
+DjVuFile::get_text(
+ const GP<DjVuFile> & file, const GP<ByteStream> &gstr_out)
+{
+ DEBUG_MSG("DjVuFile::get_text()\n");
+ ByteStream &str_out=*gstr_out;
+ if (!file->is_data_present() ||
+ file->is_modified() && file->text)
+ {
+ // Process the decoded (?) text
+ GCriticalSectionLock lock(&file->text_lock);
+ if (file->text && file->text->size())
+ {
+ if (str_out.tell())
+ {
+ str_out.write((void *) "", 1);
+ }
+ file->text->seek(0);
+ str_out.copy(*file->text);
+ }
+ } else if (file->is_data_present())
+ {
+ // Copy all text chunks, but do NOT modify
+ // DjVuFile::text (to avoid correlation with DjVuFile::decode())
+ const GP<ByteStream> str=file->data_pool->get_stream();
+ const GP<IFFByteStream> giff=IFFByteStream::create(str);
+ IFFByteStream &iff=*giff;
+ GUTF8String chkid;
+ if (iff.get_chunk(chkid))
+ {
+ while(iff.get_chunk(chkid))
+ {
+ if (is_text(chkid))
+ {
+ if (str_out.tell())
+ {
+ str_out.write((void *) "", 1);
+ }
+ const GP<IFFByteStream> giff_out(IFFByteStream::create(gstr_out));
+ IFFByteStream &iff_out=*giff_out;
+ iff_out.put_chunk(chkid);
+ iff_out.copy(*iff.get_bytestream());
+ iff_out.close_chunk();
+ }
+ iff.close_chunk();
+ }
+ }
+ file->data_pool->clear_stream();
+ }
+}
+
+void
+DjVuFile::get_meta(
+ const GP<DjVuFile> & file, const GP<ByteStream> &gstr_out)
+{
+ DEBUG_MSG("DjVuFile::get_meta()\n");
+ ByteStream &str_out=*gstr_out;
+ if (!file->is_data_present() ||
+ file->is_modified() && file->meta)
+ {
+ // Process the decoded (?) meta
+ GCriticalSectionLock lock(&file->meta_lock);
+ if (file->meta && file->meta->size())
+ {
+ if (str_out.tell())
+ {
+ str_out.write((void *) "", 1);
+ }
+ file->meta->seek(0);
+ str_out.copy(*file->meta);
+ }
+ } else if (file->is_data_present())
+ {
+ // Copy all meta chunks, but do NOT modify
+ // DjVuFile::meta (to avoid correlation with DjVuFile::decode())
+ const GP<ByteStream> str=file->data_pool->get_stream();
+ const GP<IFFByteStream> giff=IFFByteStream::create(str);
+ IFFByteStream &iff=*giff;
+ GUTF8String chkid;
+ if (iff.get_chunk(chkid))
+ {
+ while(iff.get_chunk(chkid))
+ {
+ if (is_meta(chkid))
+ {
+ if (str_out.tell())
+ {
+ str_out.write((void *) "", 1);
+ }
+ const GP<IFFByteStream> giff_out(IFFByteStream::create(gstr_out));
+ IFFByteStream &iff_out=*giff_out;
+ iff_out.put_chunk(chkid);
+ iff_out.copy(*iff.get_bytestream());
+ iff_out.close_chunk();
+ }
+ iff.close_chunk();
+ }
+ }
+ file->data_pool->clear_stream();
+ }
+}
+
+GP<ByteStream>
+DjVuFile::get_anno(void)
+{
+ DEBUG_MSG("DjVuFile::get_text(void)\n");
+ GP<ByteStream> gstr(ByteStream::create());
+ get_anno(this, gstr);
+ ByteStream &str=*gstr;
+ if (!str.tell())
+ {
+ gstr=0;
+ }else
+ {
+ str.seek(0);
+ }
+ return gstr;
+}
+
+GP<ByteStream>
+DjVuFile::get_text(void)
+{
+ DEBUG_MSG("DjVuFile::get_text(void)\n");
+ GP<ByteStream> gstr(ByteStream::create());
+ get_text(this, gstr);
+ ByteStream &str=*gstr;
+ if (!str.tell())
+ {
+ gstr=0;
+ }else
+ {
+ str.seek(0);
+ }
+ return gstr;
+}
+
+GP<ByteStream>
+DjVuFile::get_meta(void)
+{
+ DEBUG_MSG("DjVuFile::get_meta(void)\n");
+ GP<ByteStream> gstr(ByteStream::create());
+ get_meta(this, gstr);
+ ByteStream &str=*gstr;
+ if (!str.tell())
+ {
+ gstr=0;
+ }else
+ {
+ str.seek(0);
+ }
+ return gstr;
+}
+
+void
+DjVuFile::static_trigger_cb(void * cl_data)
+{
+ DjVuFile * th=(DjVuFile *) cl_data;
+ G_TRY {
+ GP<DjVuPort> port=DjVuPort::get_portcaster()->is_port_alive(th);
+ if (port && port->inherits("DjVuFile"))
+ ((DjVuFile *) (DjVuPort *) port)->trigger_cb();
+ } G_CATCH(exc) {
+ G_TRY {
+ get_portcaster()->notify_error(th, exc.get_cause());
+ } G_CATCH_ALL {} G_ENDCATCH;
+ } G_ENDCATCH;
+}
+
+void
+DjVuFile::trigger_cb(void)
+{
+ GP<DjVuFile> life_saver=this;
+
+ DEBUG_MSG("DjVuFile::trigger_cb(): got data for '" << url << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ file_size=data_pool->get_length();
+ flags|=DATA_PRESENT;
+ get_portcaster()->notify_file_flags_changed(this, DATA_PRESENT, 0);
+
+ if (!are_incl_files_created())
+ process_incl_chunks();
+
+ bool all=true;
+ inc_files_lock.lock();
+ GPList<DjVuFile> files_list=inc_files_list;
+ inc_files_lock.unlock();
+ for(GPosition pos=files_list;pos&&(all=files_list[pos]->is_all_data_present());++pos)
+ EMPTY_LOOP;
+ if (all)
+ {
+ DEBUG_MSG("DjVuFile::trigger_cb(): We have ALL data for '" << url << "'\n");
+ flags|=ALL_DATA_PRESENT;
+ get_portcaster()->notify_file_flags_changed(this, ALL_DATA_PRESENT, 0);
+ }
+}
+
+void
+DjVuFile::progress_cb(int pos, void * cl_data)
+{
+ DEBUG_MSG("DjVuFile::progress_cb() called\n");
+ DEBUG_MAKE_INDENT(3);
+
+ DjVuFile * th=(DjVuFile *) cl_data;
+
+ int length=th->decode_data_pool->get_length();
+ if (length>0)
+ {
+ float progress=(float) pos/length;
+ DEBUG_MSG("progress=" << progress << "\n");
+ get_portcaster()->notify_decode_progress(th, progress);
+ } else
+ {
+ DEBUG_MSG("DataPool size is still unknown => ignoring\n");
+ }
+}
+
+//*****************************************************************************
+//******************************** Utilities **********************************
+//*****************************************************************************
+
+void
+DjVuFile::move(GMap<GURL, void *> & map, const GURL & dir_url)
+// This function may block for data.
+{
+ if (!map.contains(url))
+ {
+ map[url]=0;
+
+ url=GURL::UTF8(url.name(),dir_url);
+
+
+ // Leave the lock here!
+ GCriticalSectionLock lock(&inc_files_lock);
+ for(GPosition pos=inc_files_list;pos;++pos)
+ inc_files_list[pos]->move(map, dir_url);
+ }
+}
+
+void
+DjVuFile::move(const GURL & dir_url)
+// This function may block for data.
+{
+ check();
+ DEBUG_MSG("DjVuFile::move(): dir_url='" << dir_url << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GMap<GURL, void *> map;
+ move(map, dir_url);
+}
+
+void
+DjVuFile::set_name(const GUTF8String &name)
+{
+ DEBUG_MSG("DjVuFile::set_name(): name='" << name << "'\n");
+ DEBUG_MAKE_INDENT(3);
+ url=GURL::UTF8(name,url.base());
+}
+
+//*****************************************************************************
+//****************************** Data routines ********************************
+//*****************************************************************************
+
+int
+DjVuFile::get_chunks_number(void)
+{
+ if(chunks_number < 0)
+ {
+ const GP<ByteStream> str(data_pool->get_stream());
+ GUTF8String chkid;
+ const GP<IFFByteStream> giff(IFFByteStream::create(str));
+ IFFByteStream &iff=*giff;
+ if (!iff.get_chunk(chkid))
+ REPORT_EOF(true)
+
+ int chunks=0;
+ int last_chunk=0;
+ G_TRY
+ {
+ int chksize;
+ for(;(chksize=iff.get_chunk(chkid));last_chunk=chunks)
+ {
+ chunks++;
+ iff.seek_close_chunk();
+ }
+ chunks_number=last_chunk;
+ }
+ G_CATCH(ex)
+ {
+ chunks_number=(recover_errors>SKIP_CHUNKS)?chunks:last_chunk;
+ report_error(ex,(recover_errors<=SKIP_PAGES));
+ }
+ G_ENDCATCH;
+ data_pool->clear_stream();
+ }
+ return chunks_number;
+}
+
+GUTF8String
+DjVuFile::get_chunk_name(int chunk_num)
+{
+ if(chunk_num < 0)
+ {
+ G_THROW( ERR_MSG("DjVuFile.illegal_chunk") );
+ }
+ if((chunks_number >= 0)&&(chunk_num > chunks_number))
+ {
+ G_THROW( ERR_MSG("DjVuFile.missing_chunk") );
+ }
+ check();
+
+ GUTF8String name;
+ const GP<ByteStream> str(data_pool->get_stream());
+ GUTF8String chkid;
+ const GP<IFFByteStream> giff(IFFByteStream::create(str));
+ IFFByteStream &iff=*giff;
+ if (!iff.get_chunk(chkid))
+ REPORT_EOF(true)
+
+ int chunks=0;
+ int last_chunk=0;
+ G_TRY
+ {
+ int chunks_left=(recover_errors>SKIP_PAGES)?chunks_number:(-1);
+ int chksize;
+ for(;(chunks_left--)&&(chksize=iff.get_chunk(chkid));last_chunk=chunks)
+ {
+ if (chunks++==chunk_num) { name=chkid; break; }
+ iff.seek_close_chunk();
+ }
+ }
+ G_CATCH(ex)
+ {
+ if (chunks_number < 0)
+ chunks_number=(recover_errors>SKIP_CHUNKS)?chunks:last_chunk;
+ report_error(ex,(recover_errors <= SKIP_PAGES));
+ }
+ G_ENDCATCH;
+ if (!name.length())
+ {
+ if (chunks_number < 0) chunks_number=chunks;
+ G_THROW( ERR_MSG("DjVuFile.missing_chunk") );
+ }
+ return name;
+}
+
+bool
+DjVuFile::contains_chunk(const GUTF8String &chunk_name)
+{
+ check();
+ DEBUG_MSG("DjVuFile::contains_chunk(): url='" << url << "', chunk_name='" <<
+ chunk_name << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ bool contains=0;
+ const GP<ByteStream> str(data_pool->get_stream());
+ GUTF8String chkid;
+ const GP<IFFByteStream> giff(IFFByteStream::create(str));
+ IFFByteStream &iff=*giff;
+ if (!iff.get_chunk(chkid))
+ REPORT_EOF((recover_errors<=SKIP_PAGES))
+
+ int chunks=0;
+ int last_chunk=0;
+ G_TRY
+ {
+ int chunks_left=(recover_errors>SKIP_PAGES)?chunks_number:(-1);
+ int chksize;
+ for(;(chunks_left--)&&(chksize=iff.get_chunk(chkid));last_chunk=chunks)
+ {
+ chunks++;
+ if (chkid==chunk_name) { contains=1; break; }
+ iff.seek_close_chunk();
+ }
+ if (!contains &&(chunks_number < 0)) chunks_number=last_chunk;
+ }
+ G_CATCH(ex)
+ {
+ if (chunks_number < 0)
+ chunks_number=(recover_errors>SKIP_CHUNKS)?chunks:last_chunk;
+ report_error(ex,(recover_errors <= SKIP_PAGES));
+ }
+ G_ENDCATCH;
+ data_pool->clear_stream();
+ return contains;
+}
+
+bool
+DjVuFile::contains_anno(void)
+{
+ const GP<ByteStream> str(data_pool->get_stream());
+
+ GUTF8String chkid;
+ const GP<IFFByteStream> giff(IFFByteStream::create(str));
+ IFFByteStream &iff=*giff;
+ if (!iff.get_chunk(chkid))
+ G_THROW( ByteStream::EndOfFile );
+
+ while(iff.get_chunk(chkid))
+ {
+ if (is_annotation(chkid))
+ return true;
+ iff.close_chunk();
+ }
+
+ data_pool->clear_stream();
+ return false;
+}
+
+bool
+DjVuFile::contains_text(void)
+{
+ const GP<ByteStream> str(data_pool->get_stream());
+
+ GUTF8String chkid;
+ const GP<IFFByteStream> giff(IFFByteStream::create(str));
+ IFFByteStream &iff=*giff;
+ if (!iff.get_chunk(chkid))
+ G_THROW( ByteStream::EndOfFile );
+
+ while(iff.get_chunk(chkid))
+ {
+ if (is_text(chkid))
+ return true;
+ iff.close_chunk();
+ }
+
+ data_pool->clear_stream();
+ return false;
+}
+
+bool
+DjVuFile::contains_meta(void)
+{
+ const GP<ByteStream> str(data_pool->get_stream());
+
+ GUTF8String chkid;
+ const GP<IFFByteStream> giff(IFFByteStream::create(str));
+ IFFByteStream &iff=*giff;
+ if (!iff.get_chunk(chkid))
+ G_THROW( ByteStream::EndOfFile );
+
+ while(iff.get_chunk(chkid))
+ {
+ if (is_meta(chkid))
+ return true;
+ iff.close_chunk();
+ }
+
+ data_pool->clear_stream();
+ return false;
+}
+
+//*****************************************************************************
+//****************************** Save routines ********************************
+//*****************************************************************************
+
+static void
+copy_chunks(const GP<ByteStream> &from, IFFByteStream &ostr)
+{
+ from->seek(0);
+ const GP<IFFByteStream> giff(IFFByteStream::create(from));
+ IFFByteStream &iff=*giff;
+ GUTF8String chkid;
+ int chksize;
+ while ((chksize=iff.get_chunk(chkid)))
+ {
+ ostr.put_chunk(chkid);
+ int ochksize=ostr.copy(*iff.get_bytestream());
+ ostr.close_chunk();
+ iff.seek_close_chunk();
+ if(ochksize != chksize)
+ {
+ G_THROW( ByteStream::EndOfFile );
+ }
+ }
+}
+
+
+void
+DjVuFile::add_djvu_data(IFFByteStream & ostr, GMap<GURL, void *> & map,
+ const bool included_too, const bool no_ndir)
+{
+ check();
+ if (map.contains(url)) return;
+ bool top_level = !map.size();
+ map[url]=0;
+ bool processed_annotation = false;
+ bool processed_text = false;
+ bool processed_meta = false;
+
+ const GP<ByteStream> str(data_pool->get_stream());
+ GUTF8String chkid;
+ const GP<IFFByteStream> giff(IFFByteStream::create(str));
+ IFFByteStream &iff=*giff;
+ if (!iff.get_chunk(chkid))
+ REPORT_EOF(true)
+
+ // Open toplevel form
+ if (top_level)
+ ostr.put_chunk(chkid);
+ // Process chunks
+ int chunks=0;
+ int last_chunk=0;
+ G_TRY
+ {
+ int chunks_left=(recover_errors>SKIP_PAGES)?chunks_number:(-1);
+ int chksize;
+ for(;(chunks_left--)&&(chksize = iff.get_chunk(chkid));last_chunk=chunks)
+ {
+ chunks++;
+ if (is_info(chkid) && info)
+ {
+ ostr.put_chunk(chkid);
+ info->encode(*ostr.get_bytestream());
+ ostr.close_chunk();
+ }
+ else if (chkid=="INCL" && included_too)
+ {
+ GP<DjVuFile> file = process_incl_chunk(*iff.get_bytestream());
+ if (file)
+ {
+ if(recover_errors!=ABORT)
+ file->set_recover_errors(recover_errors);
+ if(verbose_eof)
+ file->set_verbose_eof(verbose_eof);
+ file->add_djvu_data(ostr, map, included_too, no_ndir);
+ }
+ }
+ else if (is_annotation(chkid) && anno && anno->size())
+ {
+ if (!processed_annotation)
+ {
+ processed_annotation = true;
+ GCriticalSectionLock lock(&anno_lock);
+ copy_chunks(anno, ostr);
+ }
+ }
+ else if (is_text(chkid) && text && text->size())
+ {
+ if (!processed_text)
+ {
+ processed_text = true;
+ GCriticalSectionLock lock(&text_lock);
+ copy_chunks(text, ostr);
+ }
+ }
+ else if (is_meta(chkid) && meta && meta->size())
+ {
+ if (!processed_meta)
+ {
+ processed_meta = true;
+ GCriticalSectionLock lock(&meta_lock);
+ copy_chunks(meta, ostr);
+ }
+ }
+ else if (chkid!="NDIR"||!(no_ndir || dir))
+ { // Copy NDIR chunks, but never generate new ones.
+ ostr.put_chunk(chkid);
+ ostr.copy(*iff.get_bytestream());
+ ostr.close_chunk();
+ }
+ iff.seek_close_chunk();
+ }
+ if (chunks_number < 0) chunks_number=last_chunk;
+ }
+ G_CATCH(ex)
+ {
+ if(!ex.cmp_cause(ByteStream::EndOfFile))
+ {
+ if (chunks_number < 0)
+ chunks_number=(recover_errors>SKIP_CHUNKS)?chunks:last_chunk;
+ report_error(ex,(recover_errors<=SKIP_PAGES));
+ }else
+ {
+ report_error(ex,true);
+ }
+ }
+ G_ENDCATCH;
+
+ // Otherwise, writes annotation at the end (annotations could be big)
+ if (!processed_annotation && anno && anno->size())
+ {
+ processed_annotation = true;
+ GCriticalSectionLock lock(&anno_lock);
+ copy_chunks(anno, ostr);
+ }
+ if (!processed_text && text && text->size())
+ {
+ processed_text = true;
+ GCriticalSectionLock lock(&text_lock);
+ copy_chunks(text, ostr);
+ }
+ if (!processed_meta && meta && meta->size())
+ {
+ processed_meta = true;
+ GCriticalSectionLock lock(&meta_lock);
+ copy_chunks(meta, ostr);
+ }
+ // Close iff
+ if (top_level)
+ ostr.close_chunk();
+
+ data_pool->clear_stream();
+}
+
+GP<ByteStream>
+DjVuFile::get_djvu_bytestream(const bool included_too, const bool no_ndir)
+{
+ check();
+ DEBUG_MSG("DjVuFile::get_djvu_bytestream(): creating DjVu raw file\n");
+ DEBUG_MAKE_INDENT(3);
+ const GP<ByteStream> pbs(ByteStream::create());
+ const GP<IFFByteStream> giff=IFFByteStream::create(pbs);
+ IFFByteStream &iff=*giff;
+ GMap<GURL, void *> map;
+ add_djvu_data(iff, map, included_too, no_ndir);
+ iff.flush();
+ pbs->seek(0, SEEK_SET);
+ return pbs;
+}
+
+GP<DataPool>
+DjVuFile::get_djvu_data(const bool included_too, const bool no_ndir)
+{
+ const GP<ByteStream> pbs = get_djvu_bytestream(included_too, no_ndir);
+ return DataPool::create(pbs);
+}
+
+void
+DjVuFile::merge_anno(ByteStream &out)
+{
+ // Reuse get_merged_anno(), which is better than the previous
+ // implementation due to three things:
+ // 1. It works even before the file is completely decoded
+ // 2. It merges annotations taking into account where a child DjVuFile
+ // is included.
+ // 3. It handles loops in DjVuFile's hierarchy
+
+ const GP<ByteStream> str(get_merged_anno());
+ if (str)
+ {
+ str->seek(0);
+ if (out.tell())
+ {
+ out.write((void *) "", 1);
+ }
+ out.copy(*str);
+ }
+}
+
+void
+DjVuFile::get_text(ByteStream &out)
+{
+ const GP<ByteStream> str(get_text());
+ if (str)
+ {
+ str->seek(0);
+ if (out.tell())
+ {
+ out.write((void *) "", 1);
+ }
+ out.copy(*str);
+ }
+}
+
+void
+DjVuFile::get_meta(ByteStream &out)
+{
+ const GP<ByteStream> str(get_meta());
+ if (str)
+ {
+ str->seek(0);
+ if (out.tell())
+ {
+ out.write((void *) "", 1);
+ }
+ out.copy(*str);
+ }
+}
+
+
+
+//****************************************************************************
+//******************************* Modifying **********************************
+//****************************************************************************
+
+void
+DjVuFile::remove_anno(void)
+{
+ DEBUG_MSG("DjVuFile::remove_anno()\n");
+ const GP<ByteStream> str_in(data_pool->get_stream());
+ const GP<ByteStream> gstr_out(ByteStream::create());
+
+ GUTF8String chkid;
+ const GP<IFFByteStream> giff_in(IFFByteStream::create(str_in));
+ IFFByteStream &iff_in=*giff_in;
+ if (!iff_in.get_chunk(chkid))
+ G_THROW( ByteStream::EndOfFile );
+
+ const GP<IFFByteStream> giff_out(IFFByteStream::create(gstr_out));
+ IFFByteStream &iff_out=*giff_out;
+ iff_out.put_chunk(chkid);
+
+ while(iff_in.get_chunk(chkid))
+ {
+ if (!is_annotation(chkid))
+ {
+ iff_out.put_chunk(chkid);
+ iff_out.copy(*iff_in.get_bytestream());
+ iff_out.close_chunk();
+ }
+ iff_in.close_chunk();
+ }
+
+ iff_out.close_chunk();
+
+ gstr_out->seek(0, SEEK_SET);
+ data_pool=DataPool::create(gstr_out);
+ chunks_number=-1;
+
+ anno=0;
+
+ flags|=MODIFIED;
+ data_pool->clear_stream();
+}
+
+void
+DjVuFile::remove_text(void)
+{
+ DEBUG_MSG("DjVuFile::remove_text()\n");
+ const GP<ByteStream> str_in(data_pool->get_stream());
+ const GP<ByteStream> gstr_out(ByteStream::create());
+
+ GUTF8String chkid;
+ const GP<IFFByteStream> giff_in(IFFByteStream::create(str_in));
+ IFFByteStream &iff_in=*giff_in;
+ if (!iff_in.get_chunk(chkid))
+ G_THROW( ByteStream::EndOfFile );
+
+ const GP<IFFByteStream> giff_out(IFFByteStream::create(gstr_out));
+ IFFByteStream &iff_out=*giff_out;
+ iff_out.put_chunk(chkid);
+
+ while(iff_in.get_chunk(chkid))
+ {
+ if (!is_text(chkid))
+ {
+ iff_out.put_chunk(chkid);
+ iff_out.copy(*iff_in.get_bytestream());
+ iff_out.close_chunk();
+ }
+ iff_in.close_chunk();
+ }
+
+ iff_out.close_chunk();
+
+ gstr_out->seek(0, SEEK_SET);
+ data_pool=DataPool::create(gstr_out);
+ chunks_number=-1;
+
+ text=0;
+
+ flags|=MODIFIED;
+ data_pool->clear_stream();
+}
+
+void
+DjVuFile::remove_meta(void)
+{
+ DEBUG_MSG("DjVuFile::remove_meta()\n");
+ const GP<ByteStream> str_in(data_pool->get_stream());
+ const GP<ByteStream> gstr_out(ByteStream::create());
+
+ GUTF8String chkid;
+ const GP<IFFByteStream> giff_in(IFFByteStream::create(str_in));
+ IFFByteStream &iff_in=*giff_in;
+ if (!iff_in.get_chunk(chkid))
+ G_THROW( ByteStream::EndOfFile );
+
+ const GP<IFFByteStream> giff_out(IFFByteStream::create(gstr_out));
+ IFFByteStream &iff_out=*giff_out;
+ iff_out.put_chunk(chkid);
+
+ while(iff_in.get_chunk(chkid))
+ {
+ if (!is_meta(chkid))
+ {
+ iff_out.put_chunk(chkid);
+ iff_out.copy(*iff_in.get_bytestream());
+ iff_out.close_chunk();
+ }
+ iff_in.close_chunk();
+ }
+
+ iff_out.close_chunk();
+
+ gstr_out->seek(0, SEEK_SET);
+ data_pool=DataPool::create(gstr_out);
+ chunks_number=-1;
+
+ meta=0;
+
+ flags|=MODIFIED;
+ data_pool->clear_stream();
+}
+
+void
+DjVuFile::rebuild_data_pool(void)
+{
+ data_pool=get_djvu_data(false,false);
+ chunks_number=1;
+ flags|=MODIFIED;
+}
+
+// Do NOT comment this function out. It's used by DjVuDocEditor to convert
+// old-style DjVu documents to BUNDLED format.
+
+GP<DataPool>
+DjVuFile::unlink_file(const GP<DataPool> & data, const GUTF8String &name)
+// Will process contents of data[] and remove any INCL chunk
+// containing 'name'
+{
+ DEBUG_MSG("DjVuFile::unlink_file()\n");
+ const GP<ByteStream> gstr_out(ByteStream::create());
+ const GP<IFFByteStream> giff_out(IFFByteStream::create(gstr_out));
+ IFFByteStream &iff_out=*giff_out;
+
+ const GP<ByteStream> str_in(data->get_stream());
+ const GP<IFFByteStream> giff_in(IFFByteStream::create(str_in));
+ IFFByteStream &iff_in=*giff_in;
+
+ int chksize;
+ GUTF8String chkid;
+ if (!iff_in.get_chunk(chkid)) return data;
+
+ iff_out.put_chunk(chkid);
+
+ while((chksize=iff_in.get_chunk(chkid)))
+ {
+ if (chkid=="INCL")
+ {
+ GUTF8String incl_str;
+ char buffer[1024];
+ int length;
+ while((length=iff_in.read(buffer, 1024)))
+ incl_str+=GUTF8String(buffer, length);
+
+ // Eat '\n' in the beginning and at the end
+ while(incl_str.length() && incl_str[0]=='\n')
+ {
+ incl_str=incl_str.substr(1,(unsigned int)(-1));
+ }
+ while(incl_str.length()>0 && incl_str[(int)incl_str.length()-1]=='\n')
+ {
+ incl_str.setat(incl_str.length()-1, 0);
+ }
+ if (incl_str!=name)
+ {
+ iff_out.put_chunk(chkid);
+ iff_out.get_bytestream()->writestring(incl_str);
+ iff_out.close_chunk();
+ }
+ } else
+ {
+ iff_out.put_chunk(chkid);
+ char buffer[1024];
+ int length;
+ for(const GP<ByteStream> gbs(iff_out.get_bytestream());
+ (length=iff_in.read(buffer, 1024));)
+ {
+ gbs->writall(buffer, length);
+ }
+ iff_out.close_chunk();
+ }
+ iff_in.close_chunk();
+ }
+ iff_out.close_chunk();
+ iff_out.flush();
+ gstr_out->seek(0, SEEK_SET);
+ data->clear_stream();
+ return DataPool::create(gstr_out);
+}
+
+#ifndef NEED_DECODER_ONLY
+void
+DjVuFile::insert_file(const GUTF8String &id, int chunk_num)
+{
+ DEBUG_MSG("DjVuFile::insert_file(): id='" << id << "', chunk_num="
+ << chunk_num << "\n");
+ DEBUG_MAKE_INDENT(3);
+
+ // First: create new data
+ const GP<ByteStream> str_in(data_pool->get_stream());
+ const GP<IFFByteStream> giff_in(IFFByteStream::create(str_in));
+ IFFByteStream &iff_in=*giff_in;
+
+ const GP<ByteStream> gstr_out(ByteStream::create());
+ const GP<IFFByteStream> giff_out(IFFByteStream::create(gstr_out));
+ IFFByteStream &iff_out=*giff_out;
+
+ int chunk_cnt=0;
+ bool done=false;
+ GUTF8String chkid;
+ if (iff_in.get_chunk(chkid))
+ {
+ iff_out.put_chunk(chkid);
+ int chksize;
+ while((chksize=iff_in.get_chunk(chkid)))
+ {
+ if (chunk_cnt++==chunk_num)
+ {
+ iff_out.put_chunk("INCL");
+ iff_out.get_bytestream()->writestring(id);
+ iff_out.close_chunk();
+ done=true;
+ }
+ iff_out.put_chunk(chkid);
+ iff_out.copy(*iff_in.get_bytestream());
+ iff_out.close_chunk();
+ iff_in.close_chunk();
+ }
+ if (!done)
+ {
+ iff_out.put_chunk("INCL");
+ iff_out.get_bytestream()->writestring(id);
+ iff_out.close_chunk();
+ }
+ iff_out.close_chunk();
+ }
+ gstr_out->seek(0, SEEK_SET);
+ data_pool=DataPool::create(gstr_out);
+ chunks_number=-1;
+
+ // Second: create missing DjVuFiles
+ process_incl_chunks();
+
+ flags|=MODIFIED;
+ data_pool->clear_stream();
+}
+#endif
+
+void
+DjVuFile::unlink_file(const GUTF8String &id)
+{
+ DEBUG_MSG("DjVuFile::insert_file(): id='" << id << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ // Remove the file from the list of included files
+ {
+ GURL url=DjVuPort::get_portcaster()->id_to_url(this, id);
+ if (url.is_empty()) url=GURL::UTF8(id,this->url.base());
+ GCriticalSectionLock lock(&inc_files_lock);
+ for(GPosition pos=inc_files_list;pos;)
+ if (inc_files_list[pos]->get_url()==url)
+ {
+ GPosition this_pos=pos;
+ ++pos;
+ inc_files_list.del(this_pos);
+ } else ++pos;
+ }
+
+ // And update the data.
+ const GP<ByteStream> str_in(data_pool->get_stream());
+ const GP<IFFByteStream> giff_in(IFFByteStream::create(str_in));
+ IFFByteStream &iff_in=*giff_in;
+
+ const GP<ByteStream> gstr_out(ByteStream::create());
+ const GP<IFFByteStream> giff_out(IFFByteStream::create(gstr_out));
+ IFFByteStream &iff_out=*giff_out;
+
+ GUTF8String chkid;
+ if (iff_in.get_chunk(chkid))
+ {
+ iff_out.put_chunk(chkid);
+ int chksize;
+ while((chksize=iff_in.get_chunk(chkid)))
+ {
+ if (chkid!="INCL")
+ {
+ iff_out.put_chunk(chkid);
+ iff_out.copy(*iff_in.get_bytestream());
+ iff_out.close_chunk();
+ } else
+ {
+ GUTF8String incl_str;
+ char buffer[1024];
+ int length;
+ while((length=iff_in.read(buffer, 1024)))
+ incl_str+=GUTF8String(buffer, length);
+
+ // Eat '\n' in the beginning and at the end
+ while(incl_str.length() && incl_str[0]=='\n')
+ {
+ incl_str=incl_str.substr(1,(unsigned int)(-1));
+ }
+ while(incl_str.length()>0 && incl_str[(int)incl_str.length()-1]=='\n')
+ incl_str.setat(incl_str.length()-1, 0);
+ if (incl_str!=id)
+ {
+ iff_out.put_chunk("INCL");
+ iff_out.get_bytestream()->writestring(incl_str);
+ iff_out.close_chunk();
+ }
+ }
+ iff_in.close_chunk();
+ }
+ iff_out.close_chunk();
+ }
+
+ gstr_out->seek(0, SEEK_SET);
+ data_pool=DataPool::create(gstr_out);
+ chunks_number=-1;
+
+ flags|=MODIFIED;
+}
+
+void
+DjVuFile::change_info(GP<DjVuInfo> xinfo,const bool do_reset)
+{
+ DEBUG_MSG("DjVuFile::change_text()\n");
+ // Mark this as modified
+ set_modified(true);
+ if(do_reset)
+ reset();
+ info=xinfo;
+}
+
+#ifndef NEED_DECODER_ONLY
+void
+DjVuFile::change_text(GP<DjVuTXT> txt,const bool do_reset)
+{
+ DEBUG_MSG("DjVuFile::change_text()\n");
+ GP<DjVuText> gtext_c=DjVuText::create();
+ DjVuText &text_c=*gtext_c;
+ if(contains_text())
+ {
+ const GP<ByteStream> file_text(get_text());
+ if(file_text)
+ {
+ text_c.decode(file_text);
+ }
+ }
+ GCriticalSectionLock lock(&text_lock);
+ // Mark this as modified
+ set_modified(true);
+ if(do_reset)
+ reset();
+ text_c.txt = txt;
+ text=ByteStream::create();
+ text_c.encode(text);
+}
+
+void
+DjVuFile::change_meta(const GUTF8String &xmeta,const bool do_reset)
+{
+ DEBUG_MSG("DjVuFile::change_meta()\n");
+ // Mark this as modified
+ set_modified(true);
+ if(contains_meta())
+ {
+ (void)get_meta();
+ }
+ if(do_reset)
+ reset();
+ GCriticalSectionLock lock(&meta_lock);
+ meta=ByteStream::create();
+ if(xmeta.length())
+ {
+ const GP<IFFByteStream> giff=IFFByteStream::create(meta);
+ IFFByteStream &iff=*giff;
+ iff.put_chunk("METz");
+ {
+ GP<ByteStream> gbsiff=BSByteStream::create(iff.get_bytestream(),50);
+ gbsiff->writestring(xmeta);
+ }
+ iff.close_chunk();
+ }
+}
+#endif
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuFile.h b/kviewshell/plugins/djvu/libdjvu/DjVuFile.h
new file mode 100644
index 00000000..ea0e6db3
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuFile.h
@@ -0,0 +1,848 @@
+//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: DjVuFile.h,v 1.9 2003/11/07 22:08:20 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _DJVUFILE_H
+#define _DJVUFILE_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+#include "DjVuInfo.h"
+#include "DjVuPalette.h"
+#include "DjVuPort.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+class DjVuTXT;
+class ByteStream;
+class DataPool;
+class JB2Image;
+class JB2Dict;
+class IW44Image;
+class IFFByteStream;
+class GPixmap;
+class DjVuNavDir;
+
+
+/** @name DjVuFile.h
+ Files #"DjVuFile.h"# and #"DjVuFile.cpp"# contain implementation of the
+ \Ref{DjVuFile} class, which takes the leading role in decoding of
+ \Ref{DjVuImage}s.
+
+ In the previous releases of the library the work of decoding has been
+ entirely done in \Ref{DjVuImage}. Now, due to the introduction of multipage
+ documents, the decoding procedure became significantly more complex and
+ has been moved out from \Ref{DjVuImage} into \Ref{DjVuFile}.
+
+ There is not much point though in creating just \Ref{DjVuFile} alone.
+ The maximum power of the decoder is achieved when you create the
+ \Ref{DjVuDocument} and work with {\bf it} when decoding the image.
+
+ @memo Classes representing DjVu files.
+ @author Andrei Erofeev <eaf@geocities.com>
+ @version #$Id: DjVuFile.h,v 1.9 2003/11/07 22:08:20 leonb Exp $#
+*/
+
+//@{
+
+/** #DjVuFile# plays the central role in decoding \Ref{DjVuImage}s.
+ First of all, it represents a DjVu file whether it's part of a
+ multipage all-in-one-file DjVu document, or part of a multipage
+ DjVu document where every page is in a separate file, or the whole
+ single page document. #DjVuFile# can read its contents from a file
+ and store it back when necessary.
+
+ Second, #DjVuFile# does the greatest part of decoding work. In the
+ past this was the responsibility of \Ref{DjVuImage}. Now, with the
+ introduction of the multipage DjVu formats, the decoding routines
+ have been extracted from the \Ref{DjVuImage} and put into this separate
+ class #DjVuFile#.
+
+ As \Ref{DjVuImage} before, #DjVuFile# now contains public class
+ variables corresponding to every component, that can ever be decoded
+ from a DjVu file (such as #INFO# chunk, #BG44# chunk, #SJBZ# chunk, etc.).
+
+ As before, the decoding is initiated by a single function
+ (\Ref{start_decode}() in this case, and \Ref{DjVuImage::decode}() before).
+ The difference is that #DjVuFile# now handles threads creation itself.
+ When you call the \Ref{start_decode}() function, it creates the decoding
+ thread, which starts decoding, and which can create additional threads:
+ one per each file included into this one.
+
+ {\bf Inclusion} is also a new feature specifically designed for a
+ multipage document. Indeed, inside a given document there can be a lot
+ of things shared between its pages. Examples can be the document
+ annotation (\Ref{DjVuAnno}) and other things like shared shapes and
+ dictionary (to be implemented). To avoid putting these chunks into
+ every page, we have invented new chunk called #INCL# which purpose is
+ to make the decoder open the specified file and decode it.
+
+ {\bf Source of data.} The #DjVuFile# can be initialized in two ways:
+ \begin{itemize}
+ \item With #URL# and \Ref{DjVuPort}. In this case #DjVuFile# will
+ request its data thru the communication mechanism provided by
+ \Ref{DjVuPort} in the constructor. If this file references
+ (includes) any other file, data for them will also be requested
+ in the same way.
+ \item With \Ref{ByteStream}. In this case the #DjVuFile# will read
+ its data directly from the passed stream. This constructor
+ has been added to simplify creation of #DjVuFile#s, which do
+ no include anything else. In this case the \Ref{ByteStream}
+ is enough for the #DjVuFile# to initialize.
+ \end{itemize}
+
+ {\bf Progress information.} #DjVuFile# does not do decoding silently.
+ Instead, it sends a whole set of notifications through the mechanism
+ provided by \Ref{DjVuPort} and \Ref{DjVuPortcaster}. It tells the user
+ of the class about the progress of the decoding, about possible errors,
+ chunk being decoded, etc. The data is requested using this mechanism too.
+
+ {\bf Creating.} Depending on where you have data of the DjVu file, the
+ #DjVuFile# can be initialized in two ways:
+ \begin{itemize}
+ \item By providing #URL# and pointer to \Ref{DjVuPort}. In this case
+ #DjVuFile# will request data using communication mechanism
+ provided by \Ref{DjVuPort}. This is useful when the data is on
+ the web or when this file includes other files.
+ \item By providing a \Ref{ByteStream} with the data for the file. Use
+ it only when the file doesn't include other files.
+ \end{itemize}
+ There is also a bunch of functions provided for composing
+ the desired \Ref{DjVuDocument} and modifying #DjVuFile# structure. The
+ examples are \Ref{delete_chunks}(), \Ref{insert_chunk}(),
+ \Ref{include_file}() and \Ref{unlink_file}().
+
+ {\bf Caching.} In the case of plugin it's important to do the caching
+ of decoded images or files. #DjVuFile# appears to be the best candidate
+ for caching, and that's why it supports this procedure. Whenever a
+ #DjVuFile# is successfully decoded, it's added to the cache by
+ \Ref{DjVuDocument}. Next time somebody needs it, it will be extracted
+ from the cache directly by \Ref{DjVuDocument} and won't be decoded again.
+
+ {\bf URLs.} Historically the biggest strain is put on making the decoder
+ available for Netscape and IE plugins where the original files reside
+ somewhere in the net. That is why #DjVuFile# uses {\bf URLs} to
+ identify itself and other files. If you're working with files on the
+ hard disk, you have to use the local URLs instead of file names.
+ A good way to do two way conversion is the \Ref{GOS} class. Sometimes it
+ happens that a given file does not reside anywhere but the memory. No
+ problem in this case either. There is a special port \Ref{DjVuMemoryPort},
+ which can associate any URL with the corresponding data in the memory.
+ All you need to do is to invent your own URL prefix for this case.
+ "#memory:#" will do. The usage of absolute URLs has many advantages among
+ which is the capability to cache files with their URL being the cache key.
+
+ Please note, that the #DjVuFile# class has been designed to work closely
+ with \Ref{DjVuDocument}. So please review the documentation on this class
+ too. */
+
+class DjVuFile : public DjVuPort
+{
+public:
+ enum { DECODING=1, DECODE_OK=2, DECODE_FAILED=4, DECODE_STOPPED=8,
+ DATA_PRESENT=16, ALL_DATA_PRESENT=32, INCL_FILES_CREATED=64,
+ MODIFIED=128, DONT_START_DECODE=256, STOPPED=512,
+ BLOCKED_STOPPED=1024, CAN_COMPRESS=2048, NEEDS_COMPRESSION=4096 };
+ enum { STARTED=1, FINISHED=2 };
+
+ /** @name Decoded file contents */
+ //@{
+ /// Pointer to the DjVu file information component.
+ GP<DjVuInfo> info;
+ /// Pointer to the background component of DjVu image (IW44 encoded).
+ GP<IW44Image> bg44;
+ /// Pointer to the background component of DjVu image (Raw).
+ GP<GPixmap> bgpm;
+ /// Pointer to the mask of foreground component of DjVu image (JB2 encoded).
+ GP<JB2Image> fgjb;
+ /// Pointer to the optional shape dictionary for the mask (JB2 encoded).
+ GP<JB2Dict> fgjd;
+ /// Pointer to a colors layer for the foreground component of DjVu image.
+ GP<GPixmap> fgpm;
+ /// Pointer to a colors vector for the foreground component of DjVu image.
+ GP<DjVuPalette> fgbc;
+ /// Pointer to collected annotation chunks.
+ GP<ByteStream> anno;
+ /// Pointer to collected hiddentext chunks.
+ GP<ByteStream> text;
+ /// Pointer to meta data chunks.
+ GP<ByteStream> meta;
+ /// Pointer to the *old* navigation directory contained in this file
+ GP<DjVuNavDir> dir;
+ /// Description of the file formed during decoding
+ GUTF8String description;
+ /// MIME type string describing the DjVu data.
+ GUTF8String mimetype;
+ /// Size of the file.
+ int file_size;
+ //@}
+
+protected:
+ /** Default constructor. Must follow with an init() */
+ DjVuFile(void);
+public:
+ virtual ~DjVuFile(void);
+
+ /** Initializes a #DjVuFile# object. This is a simplified initializer,
+ which is not supposed to be used for decoding or creating
+ #DjVuFile#s, which include other files.
+
+ If the file is stored on the hard drive, you may also use the
+ other constructor and pass it the file's URL and #ZERO# #port#.
+ The #DjVuFile# will read the data itself.
+
+ If you want to receive error messages and notifications, you
+ may connect the #DjVuFile# to your own \Ref{DjVuPort} after
+ it has been constructed.
+
+ @param str The stream containing data for the file. */
+ void init(const GP<ByteStream> & str);
+
+ /** Creator, does the init(ByteStream &str) */
+ static GP<DjVuFile> create( const GP<ByteStream> & str,
+ const ErrorRecoveryAction recover_action=ABORT,
+ const bool verbose_eof=true);
+
+ /** Initializes a #DjVuFile# object. As you can notice, the data is not
+ directly passed to this function. The #DjVuFile# will ask for it
+ through the \Ref{DjVuPort} mechanism before the constructor
+ finishes. If the data is stored locally on the hard disk then the
+ pointer to \Ref{DjVuPort} may be set to #ZERO#, which will make
+ #DjVuFile# read all data from the hard disk and report all errors
+ to #stderr#.
+
+ {\bf Note}. If the file includes (by means of #INCL# chunks) other
+ files then you should be ready to
+ \begin{enumerate}
+ \item Reply to requests \Ref{DjVuPort::id_to_url}() issued to
+ translate IDs (used in #INCL# chunks) to absolute URLs.
+ Usually, when the file is created by \Ref{DjVuDocument}
+ this job is done by it. If you construct such a file
+ manually, be prepared to do the ID to URL translation
+ \item Provide data for all included files.
+ \end{enumerate}
+
+ @param url The URL assigned to this file. It will be used when
+ the #DjVuFile# asks for data.
+ @param port All communication between #DjVuFile#s and \Ref{DjVuDocument}s
+ is done through the \Ref{DjVuPort} mechanism. If the {\em url}
+ is not local or the data does not reside on the hard disk,
+ the {\em port} parameter must not be #ZERO#. If the {\em port}
+ is #ZERO# then #DjVuFile# will create an internal instance
+ of \Ref{DjVuSimplePort} for accessing local files and
+ reporting errors. It can later be disabled by means
+ of \Ref{disable_standard_port}() function. */
+ void init(const GURL & url, GP<DjVuPort> port=0);
+
+ /** Creator, does the init(const GURL &url, GP<DjVuPort> port=0) */
+ static GP<DjVuFile> create(
+ const GURL & url, GP<DjVuPort> port=0,
+ const ErrorRecoveryAction recover_action=ABORT,
+ const bool verbose_eof=true);
+
+ /** Disables the built-in port for accessing local files, which may
+ have been created in the case when the #port# argument to
+ the \Ref{DjVuFile::DjVuFile}() constructor is #ZERO# */
+ void disable_standard_port(void);
+
+ /** Looks for #decoded# navigation directory (\Ref{DjVuNavDir}) in this
+ or included files. Returns #ZERO# if nothing could be found.
+
+ {\bf Note.} This function does {\bf not} attempt to decode #NDIR#
+ chunks. It is looking for predecoded components. #NDIR# can be
+ decoded either during regular decoding (initiated by
+ \Ref{start_decode}() function) or by \Ref{decode_ndir}() function,
+ which processes this and included files recursively in search
+ of #NDIR# chunks and decodes them. */
+ GP<DjVuNavDir> find_ndir(void);
+
+ /** @name #DjVuFile# flags query functions */
+ //@{
+ /** Returns the #DjVuFile# flags. The value returned is the
+ result of ORing one or more of the following constants:
+ \begin{itemize}
+ \item #DECODING# The decoding is in progress
+ \item #DECODE_OK# The decoding has finished successfully
+ \item #DECODE_FAILED# The decoding has failed
+ \item #DECODE_STOPPED# The decoding has been stopped by
+ \Ref{stop_decode}() function
+ \item #DATA_PRESENT# All data for this file has been received.
+ It's especially important in the case of Netscape or IE
+ plugins when the data is being received while the
+ decoding is done.
+ \item #ALL_DATA_PRESENT# Not only data for this file, but also
+ for all included file has been received.
+ \item #INCL_FILES_CREATED# All #INCL# and #INCF# chunks have been
+ processed and the corresponding #DjVuFile#s created. This
+ is important to know to be sure that the list returned by
+ \Ref{get_included_files}() is OK.
+ \end{itemize} */
+ long get_flags(void) const;
+ /// Returns #TRUE# if the file is being decoded.
+ bool is_decoding(void) const;
+ /// Returns #TRUE# if decoding of the file has finished successfully.
+ bool is_decode_ok(void) const;
+ /// Returns #TRUE# if decoding of the file has failed.
+ bool is_decode_failed(void) const;
+ /** Returns #TRUE# if decoding of the file has been stopped by
+ \Ref{stop_decode}() function. */
+ bool is_decode_stopped(void) const;
+ /// Returns #TRUE# if this file has received all data.
+ bool is_data_present(void) const;
+ /** Returns #TRUE# if this file {\bf and} all included files have
+ received all data. */
+ bool is_all_data_present(void) const;
+ /** Returns #TRUE# if all included files have been created. Only when
+ this function returns 1, the \Ref{get_included_files}() returns
+ the correct information. */
+ bool are_incl_files_created(void) const;
+ bool is_modified(void) const;
+ bool needs_compression(void) const;
+ bool can_compress(void) const;
+ void set_modified(bool m);
+ void set_needs_compression(bool m);
+ void set_can_compress(bool m);
+ //@}
+
+ /// Returns the URL assigned to this file
+ GURL get_url(void) const;
+
+ /** @name Decode control routines */
+ //@{
+ /** Starts decode. If threads are enabled, the decoding will be
+ done in another thread. Be sure to use \Ref{wait_for_finish}()
+ or listen for notifications sent through the \Ref{DjVuPortcaster}
+ to remain in sync. */
+ void start_decode(void);
+ /** Start the decode iff not already decoded. If sync is true, wait
+ wait for decode to complete. Returns true of start_decode is called.
+ */
+ bool resume_decode(const bool sync=false);
+ /** Stops decode. If #sync# is 1 then the function will not return
+ until the decoding thread actually dies. Otherwise it will
+ just signal the thread to stop and will return immediately.
+ Decoding of all included files will be stopped too. */
+ void stop_decode(bool sync);
+ /** Recursively stops all data-related operations.
+
+ Depending on the value of #only_blocked# flag this works as follows:
+ \begin{itemize}
+ \item If #only_blocked# is #TRUE#, the function will make sure,
+ that any further access to the file's data will result
+ in a #STOP# exception if the desired data is not available
+ (and the thread would normally block).
+ \item If #only_blocked# is #FALSE#, then {\bf any} further
+ access to the file's data will result in immediate
+ #STOP# exception.
+ \end{itemize}
+
+ The action of this function is recursive, meaning that any #DjVuFile#
+ included into this one will also be stopped.
+
+ Use this function when you don't need the #DjVuFile# anymore. The
+ results cannot be undone, and the whole idea is to make all threads
+ working with this file exit with the #STOP# exception. */
+ void stop(bool only_blocked);
+ /** Wait for the decoding to finish. This will wait for the
+ termination of included files too. */
+ void wait_for_finish(void);
+ /** Looks for #NDIR# chunk (navigation directory), and decodes its
+ contents. If the #NDIR# chunk has not been found in {\em this} file,
+ but this file includes others, the procedure will continue
+ recursively. This function is useful to obtain the document
+ navigation directory before any page has been decoded. After it
+ returns the directory can be obtained by calling \Ref{find_ndir}()
+ function.
+
+ {\bf Warning.} Contrary to \Ref{start_decode}(), this function
+ does not return before it completely decodes the directory.
+ Make sure, that this file and all included files have enough data. */
+ GP<DjVuNavDir> decode_ndir(void);
+ /// Clears all decoded components.
+ void reset(void);
+ /** Processes #INCL# chunks and creates included files.
+ Normally you won't need to call this function because included
+ files are created automatically when the file is being decoded.
+ But if due to some reason you'd like to obtain the list of included
+ files without decoding this file, this is an ideal function to call.
+
+ {\bf Warning.} This function does not return before it reads the
+ whole file, which may block your application under some circumstances
+ if not all data is available. */
+ void process_incl_chunks(void);
+ //@}
+
+ // Function needed by the cache
+ unsigned int get_memory_usage(void) const;
+
+ /** Returns the list of included DjVuFiles.
+
+ {\bf Warning.} Included files are normally created during decoding.
+ Before that they do not exist. If you call this function at
+ that time and set #only_created# to #FALSE# then it will have to
+ read all the data from this file in order to find #INCL# chunks,
+ which may block your application, if not all data is available.
+
+ @param only_created If #TRUE#, the file will not try to process
+ #INCL# chunks and load referenced files. It will return
+ just those files, which have already been created during
+ the decoding procedure. */
+ GPList<DjVuFile> get_included_files(bool only_created=true);
+
+ /** Includes a #DjVuFile# with the specified #id# into this one.
+ This function will also insert an #INCL# chunk at position
+ #chunk_num#. The function will request data for the included
+ file and will create it before returning. */
+ void insert_file(const GUTF8String &id, int chunk_num=1);
+ /// Will get rid of included file with the given #id#
+ void unlink_file(const GUTF8String &id);
+ /** Will find an #INCL# chunk containing #name# in input #data# and
+ will remove it */
+ static GP<DataPool> unlink_file(const GP<DataPool> & data, const GUTF8String &name);
+
+ /// Returns the number of chunks in the IFF file data
+ int get_chunks_number(void);
+ /// Returns the name of chunk number #chunk_num#
+ GUTF8String get_chunk_name(int chunk_num);
+ /// Returns 1 if this file contains chunk with name #chunk_name#
+ bool contains_chunk(const GUTF8String &chunk_name);
+
+ /** Processes the included files hierarchy and returns merged
+ annotations. This function may be used even when the #DjVuFile#
+ has not been decoded yet. If all data has been received for
+ this #DjVuFile# and all included #DjVuFile#s, it will will
+ gather annotations from them and will return the result.
+ If no annotations have been found, #ZERO# will be returned.
+ If either this #DjVuFile# or any of the included files do not
+ have all the data, the function will use the results of
+ decoding, which may have been started with the \Ref{start_decode}()
+ function. Otherwise #ZERO# will be returned as well.
+
+ If #max_level_ptr# pointer is not zero, the function will use
+ it to store the maximum level number from which annotations
+ have been obtained. #ZERO# level corresponds to the top-level
+ page file.
+
+ {\bf Summary:} This function will return complete annotations only
+ when the \Ref{is_all_data_present}() returns #TRUE#. */
+ GP<ByteStream> get_merged_anno(int * max_level_ptr=0);
+
+ /** Returns the annotation chunks (#"ANTa"# and #"ANTz"#). This
+ function may be used even when the #DjVuFile# has not been decoded
+ yet. If all data has been received for this #DjVuFile#, it will
+ gather hidden text and return the result. If no hidden text has
+ been found, #ZERO# will be returned.
+
+ {\bf Summary:} This function will return complete annotations
+ only when the \Ref{is_all_data_present}() returns #TRUE#. */
+ GP<ByteStream> get_anno(void);
+
+ /** Returns the text chunks (#"TXTa"# and #"TXTz"#). This function may
+ be used even when the #DjVuFile# has not been decoded yet. If all
+ data has been received for this #DjVuFile#, it will gather hidden
+ text and return the result. If no hidden text has been found,
+ #ZERO# will be returned.
+
+ {\bf Summary:} This function will return complete hidden text layers
+ only when the \Ref{is_all_data_present}() returns #TRUE#. */
+ GP<ByteStream> get_text(void);
+
+ /** Returns the meta chunks (#"METa"# and #"METz"#). This function may
+ be used even when the #DjVuFile# has not been decoded yet. If all
+ data has been received for this #DjVuFile#, it will gather metadata
+ and return the result. If no hidden text has been found, #ZERO#
+ will be returned.
+
+ {\bf Summary:} This function will return complete meta data only
+ when the \Ref{is_all_data_present}() returns #TRUE#. */
+ GP<ByteStream> get_meta(void);
+
+ /** Goes down the hierarchy of #DjVuFile#s and merges their annotations.
+ (shouldn't this one be private?).
+ @param max_level_ptr If this pointer is not ZERO, the function
+ will use it to store the maximum level at which annotations
+ were found. Top-level page files have ZERO #level#.
+ @param ignore_list The function will not process included #DjVuFile#s
+ with URLs matching those mentioned in this #ignore_list#. */
+ GP<ByteStream> get_merged_anno(const GList<GURL> & ignore_list,
+ int * max_level_ptr);
+
+ /** Clears this file of all annotations. */
+ void remove_anno(void);
+
+ /** Clears the hidden text. */
+ void remove_text(void);
+
+ /// Clears the meta data.
+ void remove_meta(void);
+
+ /** Returns #TRUE# if the file contains annotation chunks.
+ Known annotation chunks at the time of writing this help are:
+ {\bf ANTa}, {\bf ANTz}, {\bf FORM:ANNO}. */
+ bool contains_anno(void);
+
+ /** Returns #TRUE# if the file contains hiddentext chunks.
+ Known hiddentext chunks at the time of writing this help are:
+ {\bf TXTa}, and {\bf TXTz}. */
+ bool contains_text(void);
+
+ /** Returns #TRUE# if the file contains metadata chunks.
+ Known metadata chunks at the time of writing this help are:
+ {\bf METa}, and {\bf METz}. */
+ bool contains_meta(void);
+
+ /** Changes the value of the hiddentext. */
+ void change_info(GP<DjVuInfo> info, const bool do_reset=false);
+
+ /** Changes the value of the hiddentext. */
+ void change_text(GP<DjVuTXT> txt, const bool do_reset=false);
+
+ /** Changes the value of the metadata. */
+ void change_meta(const GUTF8String &meta, const bool do_reset=false);
+
+ /** @name Encoding routines */
+ //@{
+ /** The main function that encodes data back into binary stream.
+ The data returned will reflect possible changes made into the
+ chunk structure, annotation chunks and navigation directory
+ chunk #NDIR#.
+
+ {\bf Note:} The file stream will not have the magic
+ #0x41,0x54,0x26,0x54#
+ at the beginning.
+
+ @param included_too Process included files too. */
+ GP<ByteStream> get_djvu_bytestream(const bool included_too, const bool no_ndir=true);
+
+ /** Same as \Ref{get_djvu_bytestream}(), returning a DataPool.
+ @param included_too Process included files too. */
+ GP<DataPool> get_djvu_data(const bool included_too, const bool no_ndir=true );
+ //@}
+
+ // Internal. Used by DjVuDocument
+ GP<DataPool> get_init_data_pool(void) const { return data_pool; };
+
+ // Internal. Used by DjVuDocument. May block for data.
+ void move(const GURL & dir_url);
+
+ /** Internal. Used by DjVuDocument. The #name# should {\bf not}
+ be encoded with \Ref{GOS::encode_reserved}(). */
+ void set_name(const GUTF8String &name);
+
+ // Internal. Used by DjVuDocument
+ GSafeFlags & get_safe_flags(void);
+
+ // Internal. Used by DjVuImage
+ void merge_anno(ByteStream &out);
+
+ // Internal. Used by DjVuImage
+ void get_text(ByteStream &out);
+
+ // Internal. Used by DjVuImage
+ void get_meta(ByteStream &out);
+
+ // Internal. Used by DjVuDocEditor
+ void rebuild_data_pool(void);
+
+ // Functions inherited from DjVuPort
+ virtual bool inherits(const GUTF8String &class_name) const;
+ virtual void notify_chunk_done(const DjVuPort * source, const GUTF8String &name);
+ virtual void notify_file_flags_changed(const DjVuFile * source,
+ long set_mask, long clr_mask);
+ virtual void set_recover_errors(const ErrorRecoveryAction=ABORT);
+ virtual void set_verbose_eof(const bool verbose_eof=true);
+ virtual void report_error(const GException &ex,const bool=true);
+ static void set_decode_codec(GP<GPixmap> (*codec)(ByteStream &bs));
+
+protected:
+ GURL url;
+ GP<DataPool> data_pool;
+
+ GPList<DjVuFile> inc_files_list;
+ GCriticalSection inc_files_lock;
+ GCriticalSection anno_lock;
+ GCriticalSection text_lock;
+ GCriticalSection meta_lock;
+ ErrorRecoveryAction recover_errors;
+ bool verbose_eof;
+ int chunks_number;
+private:
+ bool initialized;
+ GSafeFlags flags;
+
+ GThread * decode_thread;
+ GP<DataPool> decode_data_pool;
+ GP<DjVuFile> decode_life_saver;
+
+ GP<DjVuPort> simple_port;
+
+ GMonitor chunk_mon, finish_mon;
+
+ // Functions called when the decoding thread starts
+ static void static_decode_func(void *);
+ void decode_func(void);
+ void decode(const GP<ByteStream> &str);
+ GUTF8String decode_chunk(const GUTF8String &chkid,
+ const GP<ByteStream> &str, bool djvi, bool djvu, bool iw44);
+ int get_dpi(int w, int h);
+
+ // Functions dealing with the shape directory (fgjd)
+ static GP<JB2Dict> static_get_fgjd(void *);
+ GP<JB2Dict> get_fgjd(int block=0);
+
+ // Functions used to wait for smth
+ void wait_for_chunk(void);
+ bool wait_for_finish(bool self);
+
+ // INCL chunk processor
+ GP<DjVuFile> process_incl_chunk(ByteStream & str, int file_num=-1);
+
+ // Trigger: called when DataPool has all data
+ static void static_trigger_cb(void *);
+ void trigger_cb(void);
+
+ // Progress callback: called from time to time
+ static void progress_cb(int pos, void *);
+ static void get_merged_anno(const GP<DjVuFile> & file,
+ const GP<ByteStream> &str_out, const GList<GURL> & ignore_list,
+ int level, int & max_level, GMap<GURL, void *> & map);
+ static void get_anno(const GP<DjVuFile> & file,
+ const GP<ByteStream> &str_out);
+ static void get_text(const GP<DjVuFile> & file,
+ const GP<ByteStream> &str_out);
+ static void get_meta(const GP<DjVuFile> & file,
+ const GP<ByteStream> &str_out);
+
+ void check() const;
+ GP<DjVuNavDir>find_ndir(GMap<GURL, void *> & map);
+ GP<DjVuNavDir>decode_ndir(GMap<GURL, void *> & map);
+ void add_djvu_data(IFFByteStream & str,
+ GMap<GURL, void *> & map,
+ const bool included_too, const bool no_ndir=true);
+ void move(GMap<GURL, void *> & map, const GURL & dir_url);
+private: // dummy stuff
+ static void decode(ByteStream *);
+ static GUTF8String decode_chunk(const GUTF8String &, ByteStream *,bool,bool,bool);
+ static void get_merged_anno(const GP<DjVuFile> &,ByteStream *,
+ const GList<GURL> &, int, int &, GMap<GURL, void *> &);
+ static void get_text(const GP<DjVuFile> &,ByteStream *);
+ static void get_meta(const GP<DjVuFile> &,ByteStream *);
+
+};
+
+inline long
+DjVuFile::get_flags(void) const
+{
+ return flags;
+}
+
+inline GSafeFlags &
+DjVuFile::get_safe_flags(void)
+{
+ return flags;
+}
+
+inline bool
+DjVuFile::is_decoding(void) const
+{
+ return (flags & DECODING)!=0;
+}
+
+inline bool
+DjVuFile::is_decode_ok(void) const
+{
+ return (flags & DECODE_OK)!=0;
+}
+
+inline bool
+DjVuFile::is_decode_failed(void) const
+{
+ return (flags & DECODE_FAILED)!=0;
+}
+
+inline bool
+DjVuFile::is_decode_stopped(void) const
+{
+ return (flags & DECODE_STOPPED)!=0;
+}
+
+inline bool
+DjVuFile::is_data_present(void) const
+{
+ return (flags & DATA_PRESENT)!=0;
+}
+
+inline bool
+DjVuFile::is_all_data_present(void) const
+{
+ return (flags & ALL_DATA_PRESENT)!=0;
+}
+
+inline bool
+DjVuFile::are_incl_files_created(void) const
+{
+ return (flags & INCL_FILES_CREATED)!=0;
+}
+
+inline bool
+DjVuFile::is_modified(void) const
+{
+ return (flags & MODIFIED)!=0;
+}
+
+inline void
+DjVuFile::set_modified(bool m)
+{
+ flags=m ? (flags | MODIFIED) : (flags & ~MODIFIED);
+}
+
+inline bool
+DjVuFile::needs_compression(void) const
+{
+ return (flags & NEEDS_COMPRESSION)!=0;
+}
+
+inline void
+DjVuFile::set_needs_compression(bool m)
+{
+ if (m) flags=flags | NEEDS_COMPRESSION;
+ else flags=flags & ~NEEDS_COMPRESSION;
+}
+
+inline bool
+DjVuFile::can_compress(void) const
+{
+ return (flags & CAN_COMPRESS)!=0;
+}
+
+inline void
+DjVuFile::set_can_compress(bool m)
+{
+ if(info)
+ {
+ info->compressable=m;
+ }
+ if (m)
+ {
+ flags=flags | CAN_COMPRESS;
+ } else
+ {
+ flags=flags & ~CAN_COMPRESS;
+ }
+}
+
+inline void
+DjVuFile::disable_standard_port(void)
+{
+ simple_port=0;
+}
+
+inline bool
+DjVuFile::inherits(const GUTF8String &class_name) const
+{
+ return
+ (GUTF8String("DjVuFile") == class_name) ||
+ DjVuPort::inherits(class_name);
+// !strcmp("DjVuFile", class_name) ||
+// DjVuPort::inherits(class_name);
+}
+
+inline void
+DjVuFile::wait_for_finish(void)
+{
+ while(wait_for_finish(1))
+ EMPTY_LOOP;
+}
+
+inline GURL
+DjVuFile::get_url(void) const
+{
+ return url;
+}
+
+inline void
+DjVuFile::set_verbose_eof
+(const bool verbose)
+{
+ verbose_eof=verbose;
+}
+
+inline void
+DjVuFile::set_recover_errors
+(const ErrorRecoveryAction action)
+{
+ recover_errors=action;
+}
+
+//@}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuFileCache.cpp b/kviewshell/plugins/djvu/libdjvu/DjVuFileCache.cpp
new file mode 100644
index 00000000..13220a96
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuFileCache.cpp
@@ -0,0 +1,272 @@
+//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: DjVuFileCache.cpp,v 1.9 2004/08/06 15:11:29 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "DjVuFileCache.h"
+#include "debug.h"
+
+#include <stdlib.h>
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+DjVuFileCache::~DjVuFileCache(void) {}
+
+int
+DjVuFileCache::Item::qsort_func(const void * el1, const void * el2)
+{
+ const Item * item1=*(Item **) el1;
+ const Item * item2=*(Item **) el2;
+ time_t time1=item1->get_time();
+ time_t time2=item2->get_time();
+ return time1<time2 ? -1 : time1>time2 ? 1 : 0;
+}
+
+void
+DjVuFileCache::set_max_size(int xmax_size)
+{
+ DEBUG_MSG("DjVuFileCache::set_max_size(): resizing to " << xmax_size << "\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GCriticalSectionLock lock(&class_lock);
+
+ max_size=xmax_size;
+ cur_size=calculate_size();
+
+ if (max_size>=0) clear_to_size(enabled ? max_size : 0);
+}
+
+void
+DjVuFileCache::enable(bool en)
+{
+ enabled=en;
+ set_max_size(max_size);
+}
+
+void
+DjVuFileCache::add_file(const GP<DjVuFile> & file)
+{
+ DEBUG_MSG("DjVuFileCache::add_file(): trying to add a new item\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GCriticalSectionLock lock(&class_lock);
+
+ // See if the file is already cached
+ GPosition pos;
+ for(pos=list;pos;++pos)
+ if (list[pos]->get_file()==file) break;
+
+ if (pos) list[pos]->refresh(); // Refresh the timestamp
+ else
+ {
+ // Doesn't exist in the list yet
+ int _max_size=enabled ? max_size : 0;
+ if (max_size<0) _max_size=max_size;
+
+ int add_size=file->get_memory_usage();
+
+ if (_max_size>=0 && add_size>_max_size)
+ {
+ DEBUG_MSG("but this item is way too large => doing nothing\n");
+ return;
+ }
+
+ if (_max_size>=0) clear_to_size(_max_size-add_size);
+
+ list.append(new Item(file));
+ cur_size+=add_size;
+ file_added(file);
+ }
+}
+
+void
+DjVuFileCache::clear_to_size(int size)
+{
+ DEBUG_MSG("DjVuFileCache::clear_to_size(): dropping cache size to " << size << "\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GCriticalSectionLock lock(&class_lock);
+
+ if (size==0)
+ {
+ list.empty();
+ cur_size=0;
+ } else
+ if (list.size()>20)
+ {
+ // More than 20 elements in the cache: use qsort to
+ // sort them before picking up the oldest
+ GTArray<void *> item_arr(list.size()-1);
+ GPosition pos;
+ int i;
+ for(pos=list, i=0;pos;++pos, i++)
+ {
+ GP<Item> item=list[pos];
+ item->list_pos=pos;
+ item_arr[i]=item;
+ }
+
+ qsort(&item_arr[0], item_arr.size(), sizeof(item_arr[0]), Item::qsort_func);
+
+ for(i=0;i<item_arr.size() && cur_size>(int) size;i++)
+ {
+ Item * item=(Item *) item_arr[i];
+ cur_size-=item->get_size();
+ GP<DjVuFile> file=item->file;
+ list.del(item->list_pos);
+ file_cleared(file);
+ if (cur_size<=0) cur_size=calculate_size();
+ }
+ } else
+ {
+ // Less than 20 elements: no reason to presort
+ while(cur_size>(int) size)
+ {
+ if (!list.size())
+ {
+ // Oops. Discrepancy due to an item changed its size
+ cur_size=0;
+ break;
+ }
+
+ // Remove the oldest cache item
+ GPosition oldest_pos=list;
+ GPosition pos=list;
+ for(++pos;pos;++pos)
+ if (list[pos]->get_time()<list[oldest_pos]->get_time())
+ oldest_pos=pos;
+ cur_size-=list[oldest_pos]->get_size();
+ GP<DjVuFile> file=list[oldest_pos]->file;
+ list.del(oldest_pos);
+ file_cleared(file);
+
+ // cur_size *may* become negative because items may change their
+ // size after they've been added to the cache
+ if (cur_size<=0) cur_size=calculate_size();
+ }
+ }
+
+ DEBUG_MSG("done: current cache size=" << cur_size << "\n");
+}
+
+int
+DjVuFileCache::calculate_size(void)
+{
+ GCriticalSectionLock lock(&class_lock);
+
+ int size=0;
+ for(GPosition pos=list;pos;++pos)
+ size+=list[pos]->get_size();
+ return size;
+}
+
+void
+DjVuFileCache::del_file(const DjVuFile * file)
+{
+ DEBUG_MSG("DjVuFileCache::del_file(): Removing an item from cache\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GCriticalSectionLock lock(&class_lock);
+
+ for(GPosition pos=list;pos;++pos)
+ if (list[pos]->get_file()==file)
+ {
+ GP<DjVuFile> file=list[pos]->get_file();
+ cur_size-=list[pos]->get_size();
+ list.del(pos);
+ file_deleted(file);
+ break;
+ }
+ if (cur_size<0) cur_size=calculate_size();
+ DEBUG_MSG("current cache size=" << cur_size << "\n");
+}
+
+GPList<DjVuFileCache::Item>
+DjVuFileCache::get_items(void)
+{
+ GCriticalSectionLock lock(&class_lock);
+
+ return list;
+}
+
+void
+DjVuFileCache::file_added(const GP<DjVuFile> &) {}
+
+void
+DjVuFileCache::file_deleted(const GP<DjVuFile> &) {}
+
+void
+DjVuFileCache::file_cleared(const GP<DjVuFile> &) {}
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuFileCache.h b/kviewshell/plugins/djvu/libdjvu/DjVuFileCache.h
new file mode 100644
index 00000000..9898b8f3
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuFileCache.h
@@ -0,0 +1,292 @@
+//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: DjVuFileCache.h,v 1.8 2003/11/07 22:08:20 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _DJVUFILECACHE_H
+#define _DJVUFILECACHE_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+#include "DjVuFile.h"
+
+#ifndef macintosh //MCW can't compile
+# ifndef UNDER_CE
+# include <sys/types.h>
+# include <time.h>
+# endif
+#else
+# include <time.h>
+#endif
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+/** @name DjVuFileCache.h
+ Files #"DjVuFileCache.h"# and #"DjVuFileCache.cpp"# implement a simple
+ caching mechanism for keeping a given number of \Ref{DjVuFile} instances
+ alive. The cache estimates the size of its elements and gets rid of
+ the oldest ones when necessary.
+
+ See \Ref{DjVuFileCache} for details.
+
+ @memo Simple DjVuFile caching class.
+ @author Andrei Erofeev <eaf@geocities.com>
+ @version #$Id: DjVuFileCache.h,v 1.8 2003/11/07 22:08:20 leonb Exp $#
+*/
+
+//@{
+
+/** #DjVuFileCache# is a simple list of \Ref{DjVuFile} instances. It keeps
+ track of the total size of all elements and can get rid of the oldest
+ one once the total size becomes over some threshold. Its main purpose
+ is to keep the added \Ref{DjVuFile} instances alive until their size
+ exceeds some given threshold (set by \Ref{set_maximum_size}() function).
+ The user is supposed to use \Ref{DjVuPortcaster::name_to_port}() to
+ find a file corresponding to a given name. The cache provides no
+ naming services */
+#ifdef UNDER_CE
+class DjVuFileCache : public GPEnabled
+{
+protected:
+ DjVuFileCache(const int) {}
+public:
+ static GP<DjVuFileCache> create(const int);
+ virtual ~DjVuFileCache(void);
+ void del_file(const DjVuFile *) {}
+ void add_file(const GP<DjVuFile> &) {}
+ void clear(void) {}
+ void set_max_size(int) {}
+ int get_max_size(void) const {return 0;}
+ void enable(bool en) {}
+ bool is_enabled(void) const {return false;}
+} ;
+#else
+class DjVuFileCache : public GPEnabled
+{
+protected:
+ DjVuFileCache(const int max_size=5*2*1024*1024);
+public:
+ /** Constructs the #DjVuFileCache#
+ @param max_size Maximum allowed size of the cache in bytes. */
+ static GP<DjVuFileCache> create(const int max_size=5*2*1024*1024);
+
+ virtual ~DjVuFileCache(void);
+
+ /** Removes file #file# from the cache */
+ void del_file(const DjVuFile * file);
+
+ /** Adds the given file to the cache. It it's already there, its
+ timestamp will be refreshed. */
+ void add_file(const GP<DjVuFile> & file);
+
+ /** Clears the cache. All items will be deleted. */
+ void clear(void);
+ /** Sets new maximum size. If the total size of all items in the cache
+ is greater than #max_size#, the cache will be deleting the oldest
+ items until the size is OK. */
+ void set_max_size(int max_size);
+
+ /** Returns the maximum allowed size of the cache. */
+ int get_max_size(void) const;
+
+ /** Enables or disables the cache. See \Ref{is_enabled}() for details
+ @param en - If {\em en} is TRUE, the cache will be enabled.
+ Otherwise it will be disabled.
+ */
+ void enable(bool en);
+
+ /** Returns #TRUE# if the cache is enabled, #FALSE# otherwise.
+ When a cache is disabled, \Ref{add_file}(), and
+ \Ref{del_file}() do nothing. But the {\em maximum size} is preserved
+ inside the class so that next time the cache is enabled, it will
+ be configured the same way. Clearly this "enable/disable" thing is
+ for convenience only. One could easily simulate this behavior by
+ setting the {\em maximum size} of the cache to #ZERO#. */
+ bool is_enabled(void) const;
+
+public:
+ class Item;
+
+ class Item : public GPEnabled
+ {
+ public:
+ virtual ~Item(void);
+ time_t get_time(void) const;
+
+ GP<DjVuFile> get_file(void) const;
+ unsigned int get_size(void) const;
+
+ void refresh(void);
+
+ public:
+ GP<DjVuFile> file;
+ time_t time;
+ GPosition list_pos;
+ static int qsort_func(const void * el1, const void * el2);
+
+ Item(void);
+ Item(const GP<DjVuFile> & xfile);
+ };
+
+protected:
+ GCriticalSection class_lock;
+
+ /** This function is called right after the given file has been added
+ to the cache for management. */
+ virtual void file_added(const GP<DjVuFile> & file);
+ /** This function is called when the given file is no longer
+ managed by the cache. */
+ virtual void file_deleted(const GP<DjVuFile> & file);
+ /** This function is called when after the cache decides to get rid
+ of the file. */
+ virtual void file_cleared(const GP<DjVuFile> & file);
+
+ GPList<Item> get_items(void);
+private:
+ GPList<Item> list;
+ bool enabled;
+ int max_size;
+ int cur_size;
+
+ int calculate_size(void);
+ void clear_to_size(int size);
+};
+
+
+
+//@}
+
+inline
+DjVuFileCache::Item::Item(void) : time(::time(0)) {}
+
+inline
+DjVuFileCache::Item::Item(const GP<DjVuFile> & xfile) :
+ file(xfile), time(::time(0)) {}
+
+inline
+DjVuFileCache::Item::~Item(void) {}
+
+inline GP<DjVuFile>
+DjVuFileCache::Item::get_file(void) const
+{
+ return file;
+}
+
+inline unsigned int
+DjVuFileCache::Item::get_size(void) const
+{
+ return file->get_memory_usage();
+}
+
+inline time_t
+DjVuFileCache::Item::get_time(void) const
+{
+ return time;
+}
+
+inline void
+DjVuFileCache::Item::refresh(void)
+{
+ time=::time(0);
+}
+
+inline
+DjVuFileCache::DjVuFileCache(const int xmax_size) :
+ enabled(true), max_size(xmax_size), cur_size(0) {}
+
+inline void
+DjVuFileCache::clear(void)
+{
+ clear_to_size(0);
+}
+
+inline bool
+DjVuFileCache::is_enabled(void) const
+{
+ return enabled;
+}
+
+inline int
+DjVuFileCache::get_max_size(void) const
+{
+ return max_size;
+}
+
+#endif
+
+inline GP<DjVuFileCache>
+DjVuFileCache::create(const int max_size)
+{
+ return new DjVuFileCache(max_size);
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuGlobal.cpp b/kviewshell/plugins/djvu/libdjvu/DjVuGlobal.cpp
new file mode 100644
index 00000000..b31b04bf
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuGlobal.cpp
@@ -0,0 +1,255 @@
+//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: DjVuGlobal.cpp,v 1.7 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
+
+/** This file impliments the DjVuProgressTask elements. The memory
+ functions are implimented in a separate file, because only the memory
+ functions should be compiled with out overloading of the memory functions.
+ */
+
+
+#ifdef NEED_DJVU_PROGRESS
+#include "DjVuGlobal.h"
+
+
+// ----------------------------------------
+
+#include "GOS.h"
+#include "GThreads.h"
+#include "GException.h"
+#include "GContainer.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define INITIAL 500
+#define INTERVAL 250
+
+class DjVuProgressTask::Data : public GPEnabled
+{
+public:
+ djvu_progress_callback *callback;
+ DjVuProgressTask *head;
+ const char *gtask;
+ unsigned long lastsigdate;
+ Data(djvu_progress_callback *_callback):
+ callback(_callback), head(0), gtask(0), lastsigdate(0) {}
+};
+
+
+static GPMap<void *,DjVuProgressTask::Data> &
+get_map(void)
+{
+ static GPMap<void *,DjVuProgressTask::Data> xmap;
+ return xmap;
+}
+
+djvu_progress_callback *
+DjVuProgressTask::set_callback(djvu_progress_callback *_callback)
+{
+ djvu_progress_callback *retval=0;
+ if(_callback)
+ {
+ GMap<void *,GP<DjVuProgressTask::Data> > &map=get_map();
+ void *threadID=GThread::current();
+ if(map.contains(threadID))
+ {
+ DjVuProgressTask::Data &data=*(map[threadID]);
+ retval=data.callback;
+ data.callback=_callback;
+ data.head=0;
+ data.gtask=0;
+ data.lastsigdate=0;
+ }else
+ {
+ map[threadID]=new Data(_callback);
+ }
+ }else
+ {
+ GMap<void *,GP<DjVuProgressTask::Data> > &map=get_map();
+ void *threadID=GThread::current();
+ if(map.contains(threadID))
+ {
+ DjVuProgressTask::Data &data=*(map[threadID]);
+ retval=data.callback;
+ data.callback=0;
+ data.head=0;
+ data.gtask=0;
+ data.lastsigdate=0;
+ map.del(threadID);
+ }
+ }
+ return retval;
+}
+
+DjVuProgressTask::DjVuProgressTask(const char *xtask,int nsteps)
+ : task(xtask),parent(0), nsteps(nsteps), runtostep(0), gdata(0), data(0)
+{
+ // gtask=task;
+ {
+ GMap<void *,GP<DjVuProgressTask::Data> > &map=get_map();
+ void *threadID=GThread::current();
+ if(map.contains(threadID))
+ {
+ gdata=new GP<Data>;
+ Data &d=*(data=((*(GP<Data> *)gdata)=map[threadID]));
+ if(d.callback)
+ {
+ unsigned long curdate = GOS::ticks();
+ startdate = curdate;
+ if (!d.head)
+ d.lastsigdate = curdate + INITIAL;
+ parent = d.head;
+ d.head = this;
+ }
+ }
+ }
+}
+
+DjVuProgressTask::~DjVuProgressTask()
+{
+ if (data && data->callback)
+ {
+ if (data->head != this)
+ G_THROW( ERR_MSG("DjVuGlobal.not_compatible") );
+ data->head = parent;
+ if (!parent)
+ {
+ unsigned long curdate = GOS::ticks();
+ if((*(data->callback))(data->gtask?data->gtask:"",curdate-startdate, curdate-startdate))
+ {
+ G_THROW("INTERRUPT");
+ }
+ }
+ }
+ delete (GP<Data> *)gdata;
+}
+
+void
+DjVuProgressTask::run(int tostep)
+{
+ if(data)
+ {
+ data->gtask=task;
+ if ((data->callback)&&(tostep>runtostep))
+ {
+ unsigned long curdate = GOS::ticks();
+ if (curdate > data->lastsigdate + INTERVAL)
+ signal(curdate, curdate);
+ runtostep = tostep;
+ }
+ }
+}
+
+void
+DjVuProgressTask::signal(unsigned long curdate, unsigned long estdate)
+{
+ int inprogress = runtostep;
+ if (inprogress > nsteps)
+ inprogress = nsteps;
+ if (inprogress > 0)
+ {
+ const unsigned long enddate = startdate+
+ (unsigned long)(((float)(estdate-startdate) * (float)nsteps) / (float)inprogress);
+ if (parent)
+ {
+ parent->signal(curdate, enddate);
+ }
+ else if (data && data->callback && curdate<enddate)
+ {
+ if((*(data->callback))(data->gtask?data->gtask:"",curdate-startdate, enddate-startdate))
+ {
+ G_THROW("INTERRUPT");
+ }
+ data->lastsigdate = curdate;
+ }
+ }
+}
+
+// Progress callback
+//
+djvu_progress_callback *
+djvu_set_progress_callback( djvu_progress_callback *callback )
+{
+ return DjVuProgressTask::set_callback(callback);
+}
+
+int djvu_supports_progress_callback(void) {return 1;}
+
+#else
+
+#ifndef HAS_DJVU_PROGRESS_TYPEDEF
+extern "C"
+{
+ void *djvu_set_progress_callback(void *);
+ int djvu_supports_progress_callback(void);
+}
+void *djvu_set_progress_callback(void *) { return 0; }
+int djvu_supports_progress_callback(void) {return 0;}
+#else
+int djvu_supports_progress_callback(void) {return 0;}
+djvu_progress_callback *
+djvu_set_progress_callback( djvu_progress_callback *) { return 0; }
+#endif
+
+#endif
+
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuGlobal.h b/kviewshell/plugins/djvu/libdjvu/DjVuGlobal.h
new file mode 100644
index 00000000..bfdd4dd1
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuGlobal.h
@@ -0,0 +1,398 @@
+//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: DjVuGlobal.h,v 1.10 2004/08/04 02:36:59 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _DJVUGLOBAL_H
+#define _DJVUGLOBAL_H
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+#if defined(UNDER_CE)
+# ifndef __WCEALT_H__
+inline void * operator new(size_t, void * ptr) { return ptr; }
+# endif
+#elif defined(HAVE_STDINCLUDES)
+# include <new>
+#else
+# include <new.h>
+#endif
+
+#ifdef WIN32
+# ifdef DLL_EXPORT
+# define DJVUAPI __declspec(dllexport)
+# else
+# ifdef LIBDJVU_DLL_IMPORT
+# define DJVUAPI __declspec(dllimport)
+# endif
+# endif
+#endif
+#ifndef DJVUAPI
+# define DJVUAPI
+#endif
+
+
+/** @name DjVuGlobal.h
+
+ This file is included by all include files in the DjVu reference library.
+
+ If compilation symbols #NEED_DJVU_MEMORY#, #NEED_DJVU_PROGRESS#
+ or #NEED_DJVU_NAMES# are defined, this file enables
+ features which are useful for certain applications of the
+ DjVu Reference Library. These features are still experimental and
+ therefore poorly documented.
+
+ @memo
+ Global definitions.
+ @version
+ #$Id: DjVuGlobal.h,v 1.10 2004/08/04 02:36:59 leonb Exp $#
+ @author
+ L\'eon Bottou <leonb@research.att.com> -- empty file.\\
+ Bill Riemers <docbill@sourceforge.net> -- real work. */
+//@{
+
+
+/** @name DjVu Memory
+
+ This section is enabled when compilation symbol #NEED_DJVU_MEMORY# is
+ defined. Function #_djvu_memory_callback# can be used to redefine the C++
+ memory allocation operators. Some operating systems (e.g. Macintoshes)
+ require very peculiar memory allocation in shared objects. We redefine
+ the operators #new# and #delete# as #STATIC_INLINE# because we do not
+ want to export these redefined versions to other libraries. */
+//@{
+//@}
+
+#ifdef NEED_DJVU_MEMORY
+
+# include "DjVu.h"
+
+// These define the two callbacks needed for C++
+typedef void djvu_delete_callback(void *);
+typedef void *djvu_new_callback(size_t);
+
+// These functions allow users to set the callbacks.
+int djvu_memoryObject_callback ( djvu_delete_callback*, djvu_new_callback*);
+int djvu_memoryArray_callback ( djvu_delete_callback*, djvu_new_callback*);
+
+// We need to use this inline function in all modules, but we never want it to
+// appear in the symbol table. It seems different compilers need different
+// directives to do this...
+# ifndef STATIC_INLINE
+# ifdef __GNUC__
+# define STATIC_INLINE extern inline
+# else /* !__GNUC__ */
+# define STATIC_INLINE static inline
+# endif /* __GNUC__ */
+# endif /* STATIC_INLINE */
+
+// This clause is used when overriding operator new
+// because the standard has slightly changed.
+# if defined( __GNUC__ ) && ( __GNUC__*1000 + __GNUC_MINOR__ >= 2091 )
+# ifndef new_throw_spec
+# define new_throw_spec throw(std::bad_alloc)
+# endif /* new_throw_spec */
+# ifndef delete_throw_spec
+# define delete_throw_spec throw()
+# endif /* delete_throw_spec */
+# endif /* __GNUC__ ... */
+// Old style
+# ifndef new_throw_spec
+# define new_throw_spec
+# endif /* new_throw_spec */
+# ifndef delete_throw_spec
+# define delete_throw_spec
+# endif /* delete_throw_spec */
+
+# ifdef UNIX
+extern djvu_new_callback *_djvu_new_ptr;
+extern djvu_new_callback *_djvu_newArray_ptr;
+extern djvu_delete_callback *_djvu_delete_ptr;
+extern djvu_delete_callback *_djvu_deleteArray_ptr;
+
+# ifndef NEED_DJVU_MEMORY_IMPLEMENTATION
+void *operator new (size_t) new_throw_spec;
+void *operator new[] (size_t) new_throw_spec;
+void operator delete (void *) delete_throw_spec;
+void operator delete[] (void *) delete_throw_spec;
+
+STATIC_INLINE void *
+operator new(size_t sz) new_throw_spec
+{ return (*_djvu_new_ptr)(sz); }
+STATIC_INLINE void
+operator delete(void *addr) delete_throw_spec
+{ return (*_djvu_delete_ptr)(addr); }
+STATIC_INLINE void *
+operator new [] (size_t sz) new_throw_spec
+{ return (*_djvu_newArray_ptr)(sz); }
+STATIC_INLINE void
+operator delete [] (void *addr) delete_throw_spec
+{ return (*_djvu_deleteArray_ptr)(addr); }
+# endif /* NEED_DJVU_MEMORY_IMPLEMENTATION */
+
+# else /* UNIX */
+
+# ifndef NEED_DJVU_MEMORY_IMPLEMENTATION
+STATIC_INLINE void *
+operator new(size_t sz) new_throw_spec
+{ return _djvu_new(sz); }
+inline_as_macro void
+operator delete(void *addr) delete_throw_spec
+{ return _djvu_delete(addr); }
+inline_as_macro void *
+operator new [] (size_t sz) new_throw_spec
+{ return _djvu_new(sz); }
+inline_as_macro void
+operator delete [] (void *addr) delete_throw_spec
+{ _djvu_deleteArray(addr); }
+# endif /* !NEED_DJVU_MEMORY_IMPLEMENTATION */
+
+# endif /* UNIX */
+
+#else
+
+# define _djvu_free(ptr) free((ptr))
+# define _djvu_malloc(siz) malloc((siz))
+# define _djvu_realloc(ptr,siz) realloc((ptr),(siz))
+# define _djvu_calloc(siz,items) calloc((siz),(items))
+
+#endif /* NEED_DJVU_MEMORY */
+
+/** @name DjVu Progress
+
+ This section is enabled when compilation symbol #NEED_DJVU_PROGRESS# is
+ defined. This macro setups callback function that may be used to
+ implement a progress indicator for the encoding routines. The decoding
+ routines do not need such a facility because it is sufficient to monitor
+ the calls to function \Ref{ByteStream::read} in class \Ref{ByteStream}.
+
+ {\bf Code tracing macros} ---
+ Monitoring the progress of such complex algorithms requires significant
+ code support. This is achieved by inserting {\em code tracing macros}
+ in strategic regions of the code.
+ \begin{description}
+ \item[DJVU_PROGRESS_TASK(name,task,nsteps)] indicates that the current
+ scope performs a task roughly divided in #nsteps# equal steps, with
+ the specified #task# string used in the callback.
+ \item[DJVU_PROGRESS_RUN(name,tostep)] indicates that we are starting
+ an operation which will take us to step #tostep#. The operation
+ will be considered finished when #DJVU_PROGRESS_RUN# will be called
+ again with an argument greater than #tostep#. The execution of
+ this operation of course can be described by one subtask and so on.
+ \end{description}
+
+ {\bf Progress callback} --- Before defining the outermost task, you can
+ store a callback function pointer into the static member variable
+ #DjVuProgressTask::callback#. This callback function is called
+ periodically with two unsigned long arguments. The first argument is the
+ elapsed time. The second argument is the estimated total execution time.
+ Both times are given in milliseconds.
+
+ {\bf Important Note} --- This monitoring mechanism should not be used by
+ multithreaded programs. */
+//@{
+
+#ifndef HAS_DJVU_PROGRESS_CALLBACKS
+# define HAS_DJVU_PROGRESS_CALLBACKS
+
+# ifdef NEED_DJVU_PROGRESS
+# include "DjVu.h"
+
+extern djvu_progress_callback *_djvu_progress_ptr;
+
+# define DJVU_PROGRESS_TASK(name,task,nsteps) DjVuProgressTask task_##name(task,nsteps)
+# define DJVU_PROGRESS_RUN(name,tostep) { task_##name.run(tostep); }
+
+class DjVuProgressTask
+{
+public:
+ class Data;
+ ~DjVuProgressTask();
+ DjVuProgressTask(const char *task,int nsteps);
+ void run(int tostep);
+ const char *task;
+ static djvu_progress_callback *set_callback(djvu_progress_callback *ptr=0);
+private:
+ DjVuProgressTask *parent;
+ int nsteps;
+ int runtostep;
+ unsigned long startdate;
+ // Statics
+ void *gdata;
+ Data *data;
+ // Helpers
+ void signal(unsigned long curdate, unsigned long estdate);
+};
+
+# else // ! NEED_DJVU_PROGRESS
+
+# define DJVU_PROGRESS_TASK(name,task,nsteps)
+# define DJVU_PROGRESS_RUN(name,step)
+
+# endif // ! NEED_DJVU_PROGRESS
+#endif // HAS_DJVU_PROGRESS_CALLBACKS
+//@}
+
+
+/** @name General functions.
+
+ This section contains functions that replace some of the standard
+ system calls without any other header file dependancies.
+ */
+
+#ifdef __cplusplus
+# define DJVUEXTERNCAPI(x) extern "C" DJVUAPI x;
+#else
+# define DJVUEXTERNCAPI(x) extern DJVUAPI x
+#endif
+
+/** This replaces fprintf(stderr,...), but with UTF8 encoded strings. */
+DJVUEXTERNCAPI(void DjVuPrintErrorUTF8(const char *fmt, ...))
+
+/** This replaces fprintf(stderr,...), but with UTF8 encoded strings. */
+DJVUEXTERNCAPI(void DjVuPrintErrorNative(const char *fmt, ...))
+
+/** This replaces printf(...), but requires UTF8 encoded strings. */
+DJVUEXTERNCAPI(void DjVuPrintMessageUTF8(const char *fmt, ...))
+
+/** This replaces printf(...), but requires UTF8 encoded strings. */
+DJVUEXTERNCAPI(void DjVuPrintMessageNative(const char *fmt, ...))
+
+/** The format (fmt) and arguments define a MessageList to be looked
+ up in the external messages and printed to stderr. */
+DJVUEXTERNCAPI(void DjVuFormatErrorUTF8(const char *fmt, ...))
+
+/** The format (fmt) and arguments define a MessageList to be looked
+ up in the external messages and printed to stderr. */
+DJVUEXTERNCAPI(void DjVuFormatErrorNative(const char *fmt, ...))
+
+/** Prints the translation of message to stderr. */
+DJVUEXTERNCAPI(void DjVuWriteError( const char *message ))
+
+/** Prints the translation of message to stdout. */
+DJVUEXTERNCAPI(void DjVuWriteMessage( const char *message ))
+
+/** A C function to perform a message lookup. Arguments are a buffer to
+ received the translated message, a buffer size (bytes), and a
+ message_list. The translated result is returned in msg_buffer encoded
+ in UTF-8. In case of error, msg_buffer is empty
+ (i.e., msg_buffer[0] == '\0').
+*/
+DJVUEXTERNCAPI(void DjVuMessageLookUpUTF8(
+ char *msg_buffer, const unsigned int buffer_size,
+ const char *message ))
+DJVUEXTERNCAPI(void DjVuMessageLookUpNative(
+ char *msg_buffer, const unsigned int buffer_size,
+ const char *message ))
+
+/** This function sets the program name used when
+ searching for language files.
+*/
+DJVUEXTERNCAPI(const char *djvu_programname(const char *programname))
+
+
+/** @name DjVu Names
+
+ This section is enabled when compilation symbol #NEED_DJVU_NAMES# is
+ defined. This section redefines class names in order to unclutter the
+ name space of shared objects. This is useful on systems which
+ automatically export all global symbols when building a shared object.
+ @args */
+//@{
+//@}
+
+#ifdef NEED_DJVU_NAMES
+/* The contents of this section may be generated by this shell command :
+ * % egrep -h '^(class|struct) +[A-Z_][A-Za-z0-9_]*' *.h *.cpp |\
+ * sed -e 's:[a-z]* *\([A-Za-z_][A-Za-z0-9_]*\).*:#define \1 DJVU_\1:g' |\
+ * sort
+ */
+#endif // NEED_DJVU_NAMES
+
+//@}
+
+#if defined(macintosh)
+# define EMPTY_LOOP continue
+#else
+# define EMPTY_LOOP /* nop */
+#endif
+
+// The ERR_MSG(x) macro is intended to permit automated checking of the
+// externalized error message names against the source code. It has no
+// effect on the executed program. It should be used to surround each
+// message name that will need to be looked up in the external message
+// files. In particular, it should use on all strings passed to G_THROW.
+#ifndef HAS_CTRL_C_IN_ERR_MSG
+# define HAS_CTRL_C_IN_ERR_MSG 1
+#endif
+#ifndef ERR_MSG
+# if HAS_CTRL_C_IN_ERR_MSG
+// This hack allows for the coexistence of internationalized
+// and non-internationalized code. All internationalized error
+// message names are prefixed with a ctrl-c. Only these will
+// be looked for in the message files. Messages that do no
+// start with a ctrl-c will remain untranslated.
+# define ERR_MSG(x) "\003" x
+# else
+# define ERR_MSG(x) x
+# endif
+#endif
+
+#endif /* _DJVUGLOBAL_H_ */
+
+
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuGlobalMemory.cpp b/kviewshell/plugins/djvu/libdjvu/DjVuGlobalMemory.cpp
new file mode 100644
index 00000000..1c684336
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuGlobalMemory.cpp
@@ -0,0 +1,306 @@
+//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: DjVuGlobalMemory.cpp,v 1.6 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
+
+#ifdef NEED_DJVU_MEMORY
+#ifndef NEED_DJVU_MEMORY_IMPLEMENTATION
+#define NEED_DJVU_MEMORY_IMPLEMENTATION
+#endif /* NEED_DJVU_MEMORY_IMPLEMENTATION */
+
+#include "DjVuGlobal.h"
+#include "GException.h"
+#include <stdlib.h>
+#include <string.h>
+#include "debug.h"
+
+#ifdef UNIX
+djvu_delete_callback *
+_djvu_delete_ptr=(djvu_delete_callback *)&(operator delete);
+djvu_delete_callback *
+_djvu_deleteArray_ptr=(djvu_delete_callback *)&(operator delete []);
+djvu_new_callback *
+_djvu_new_ptr=(djvu_new_callback *)&(operator new);
+djvu_new_callback *
+_djvu_newArray_ptr=(djvu_new_callback *)&(operator new []);
+#endif
+
+static djvu_delete_callback *_djvu_delete_handler = 0;
+static djvu_new_callback *_djvu_new_handler = 0;
+static djvu_delete_callback *deleteArray_handler = 0;
+static djvu_new_callback *newArray_handler = 0;
+
+static djvu_free_callback *_djvu_free_handler = 0;
+static djvu_realloc_callback *_djvu_realloc_handler = 0;
+static djvu_calloc_callback *_djvu_calloc_handler = 0;
+static djvu_malloc_callback *_djvu_malloc_handler = 0;
+
+int
+djvu_memoryObject_callback (
+ djvu_delete_callback* delete_handler,
+ djvu_new_callback* new_handler
+) {
+ if(delete_handler && new_handler)
+ {
+#ifdef UNIX
+ _djvu_new_ptr=&_djvu_new;
+ _djvu_delete_ptr=&_djvu_delete;
+#endif
+ _djvu_delete_handler=delete_handler;
+ _djvu_new_handler=new_handler;
+ return 1;
+ }else
+ {
+#ifdef UNIX
+ _djvu_new_ptr=(djvu_new_callback *)&(operator new);
+ _djvu_delete_ptr=(djvu_delete_callback *)&(operator delete);
+#endif
+ _djvu_delete_handler=0;
+ _djvu_new_handler=0;
+ return (delete_handler||new_handler)?0:1;
+ }
+ return 0;
+}
+
+int
+djvu_set_memory_callbacks
+(
+ djvu_free_callback *free_handler,
+ djvu_realloc_callback *realloc_handler,
+ djvu_malloc_callback *malloc_handler,
+ djvu_calloc_callback *calloc_handler
+)
+{
+ if(free_handler && realloc_handler && malloc_handler)
+ {
+#ifdef UNIX
+ _djvu_new_ptr=(djvu_new_callback *)&_djvu_new;
+ _djvu_delete_ptr=(djvu_delete_callback *)&_djvu_delete;
+#endif
+ _djvu_new_handler=(djvu_new_callback *)malloc_handler;
+ _djvu_delete_handler=(djvu_delete_callback *)free_handler;
+ _djvu_malloc_handler=(djvu_malloc_callback *)malloc_handler;
+ _djvu_free_handler=(djvu_free_callback *)free_handler;
+ _djvu_realloc_handler=(djvu_realloc_callback *)realloc_handler;
+ if(calloc_handler)
+ {
+ _djvu_calloc_handler=(djvu_calloc_callback *)&calloc_handler;
+ }else
+ {
+ _djvu_calloc_handler=0;
+ }
+ return 1;
+ }else
+ {
+#ifdef UNIX
+ _djvu_new_ptr=(djvu_new_callback *)&(operator new);
+ _djvu_delete_ptr=(djvu_delete_callback *)&(operator delete);
+#endif
+ _djvu_delete_handler=0;
+ _djvu_new_handler=0;
+ _djvu_malloc_handler=0;
+ _djvu_free_handler=0;
+ _djvu_realloc_handler=0;
+ _djvu_calloc_handler=0;
+ return !(_djvu_malloc_handler
+ ||_djvu_free_handler
+ ||_djvu_realloc_handler
+ ||_djvu_calloc_handler);
+ }
+}
+
+DJVUAPI void *
+_djvu_new(size_t siz)
+{
+ void *ptr;
+#ifndef UNIX
+ if(_djvu_new_handler)
+ {
+#endif
+ if(!(ptr=(*_djvu_new_handler)(siz?siz:1)))
+ {
+ G_THROW( ERR_MSG("DjVuGlobalMemory.exhausted") );
+ }
+#ifndef UNIX
+ }else
+ {
+ ptr=::operator new(siz?siz:1);
+ }
+#endif
+ return ptr;
+}
+
+void
+_djvu_delete(void *addr)
+{
+ if(addr)
+ {
+ if(_djvu_delete_handler)
+ {
+ (*_djvu_delete_handler)(addr);
+ }else
+ {
+ operator delete(addr);
+ }
+ }
+}
+
+void *
+_djvu_newArray(size_t siz)
+{
+ void *ptr;
+#ifndef UNIX
+ if(newArray_handler)
+ {
+#endif
+ if(!(ptr=(*newArray_handler)(siz?siz:1)))
+ {
+ G_THROW( ERR_MSG("DjVuGlobalMemory.exhausted") );
+ }
+#ifndef UNIX
+ }else
+ {
+ ptr=::new unsigned char[siz?siz:1];
+ }
+#endif
+ return ptr;
+}
+
+void
+_djvu_deleteArray(void *addr)
+{
+ if(addr)
+ {
+ if(deleteArray_handler)
+ {
+ (*deleteArray_handler)(addr);
+ }else
+ {
+#ifdef WIN32
+ delete [] (addr) ;
+#else
+ operator delete [] (addr);
+#endif
+ }
+ }
+}
+
+void *
+_djvu_malloc(size_t siz)
+{
+ DEBUG_MSG("_djvu_malloc: siz="<<siz<<"\n");
+ return _djvu_malloc_handler?(*_djvu_malloc_handler)(siz?siz:1):malloc(siz?siz:1);
+}
+
+void *
+_djvu_calloc(size_t siz, size_t items)
+{
+ DEBUG_MSG("_djvu_calloc: siz="<<siz<<" items="<<items<<"\n");
+ void *ptr;
+ if( _djvu_calloc_handler )
+ {
+ ptr = (*_djvu_calloc_handler)(siz?siz:1, items?items:1);
+ }else if( _djvu_malloc_handler )
+ {
+ if((ptr = (*_djvu_malloc_handler)((siz?siz:1)*(items?items:1)))&&siz&&items)
+ {
+ memset(ptr,0,siz*items);
+ }
+ }else
+ {
+ ptr = calloc(siz?siz:1, items?items:1);
+ }
+ return ptr;
+}
+
+void *
+_djvu_realloc(void* ptr, size_t siz)
+{
+ DEBUG_MSG("_djvu_realloc: ptr="<<ptr<<" siz="<<siz<<"\n");
+ void *newptr;
+ if( _djvu_realloc_handler )
+ {
+ newptr = (*_djvu_realloc_handler)(ptr, siz);
+ }else
+ {
+ newptr = realloc(ptr, siz?siz:1);
+ }
+ return newptr;
+}
+
+void
+_djvu_free(void *ptr)
+{
+ DEBUG_MSG("_djvu_free: ptr="<<ptr<<"\n");
+ if(ptr)
+ {
+ if( _djvu_free_handler )
+ {
+ (*_djvu_free_handler)(ptr);
+ }else
+ {
+ free(ptr);
+ }
+ }
+}
+
+#endif
+
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuImage.cpp b/kviewshell/plugins/djvu/libdjvu/DjVuImage.cpp
new file mode 100644
index 00000000..f384ce97
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuImage.cpp
@@ -0,0 +1,1486 @@
+//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: DjVuImage.cpp,v 1.10 2005/04/27 16:34:13 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "DjVuImage.h"
+#include "GScaler.h"
+#include "DjVuDocument.h"
+#include "DjVuPalette.h"
+#include "GContainer.h"
+#include "GSmartPointer.h"
+#include "JB2Image.h"
+#include "IW44Image.h"
+#include "DataPool.h"
+#include "ByteStream.h"
+#include "GMapAreas.h"
+#include "DjVuText.h"
+#include "IFFByteStream.h"
+#include "BSByteStream.h"
+#include "debug.h"
+#include <stdarg.h>
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+
+//// DJVUIMAGE: CONSTRUCTION
+
+DjVuImage::DjVuImage(void)
+: rotate_count(-1),relayout_sent(false)
+{
+}
+
+void
+DjVuImage::connect(const GP<DjVuFile> & xfile)
+{
+ file=xfile;
+ DjVuPort::get_portcaster()->add_route(file, this);
+}
+
+
+
+
+//// DJVUIMAGE: DATA COLLECTORS
+
+GP<DjVuInfo>
+DjVuImage::get_info(const GP<DjVuFile> & file) const
+{
+ if (file->info)
+ {
+ if(rotate_count<0)
+ {
+ const_cast<DjVuImage *>(this)->init_rotate(*(file->info));
+ }
+ return file->info;
+ }
+ GPList<DjVuFile> list=file->get_included_files();
+ for(GPosition pos=list;pos;++pos)
+ {
+ GP<DjVuInfo> info=get_info(list[pos]);
+ if (info)
+ {
+ if(rotate_count<0)
+ {
+ const_cast<DjVuImage *>(this)->init_rotate(*(file->info));
+ }
+ return info;
+ }
+ }
+ return 0;
+}
+
+GP<IW44Image>
+DjVuImage::get_bg44(const GP<DjVuFile> & file) const
+{
+ if (file->bg44)
+ return file->bg44;
+ GPList<DjVuFile> list=file->get_included_files();
+ for(GPosition pos=list;pos;++pos)
+ {
+ GP<IW44Image> bg44=get_bg44(list[pos]);
+ if (bg44)
+ return bg44;
+ }
+ return 0;
+}
+
+GP<GPixmap>
+DjVuImage::get_bgpm(const GP<DjVuFile> & file) const
+{
+ if (file->bgpm)
+ return file->bgpm;
+ GPList<DjVuFile> list=file->get_included_files();
+ for(GPosition pos=list;pos;++pos)
+ {
+ GP<GPixmap> bgpm=get_bgpm(list[pos]);
+ if (bgpm) return bgpm;
+ }
+ return 0;
+}
+
+GP<JB2Image>
+DjVuImage::get_fgjb(const GP<DjVuFile> & file) const
+{
+ if (file->fgjb)
+ return file->fgjb;
+ GPList<DjVuFile> list=file->get_included_files();
+ for(GPosition pos=list;pos;++pos)
+ {
+ GP<JB2Image> fgjb=get_fgjb(list[pos]);
+ if (fgjb)
+ return fgjb;
+ }
+ return 0;
+}
+
+GP<GPixmap>
+DjVuImage::get_fgpm(const GP<DjVuFile> & file) const
+{
+ if (file->fgpm)
+ return file->fgpm;
+ GPList<DjVuFile> list=file->get_included_files();
+ for(GPosition pos=list;pos;++pos)
+ {
+ GP<GPixmap> fgpm=get_fgpm(list[pos]);
+ if (fgpm)
+ return fgpm;
+ }
+ return 0;
+}
+
+GP<DjVuPalette>
+DjVuImage::get_fgbc(const GP<DjVuFile> & file) const
+{
+ if (file->fgbc)
+ return file->fgbc;
+ GPList<DjVuFile> list=file->get_included_files();
+ for(GPosition pos=list;pos;++pos)
+ {
+ GP<DjVuPalette> fgbc=get_fgbc(list[pos]);
+ if (fgbc) return fgbc;
+ }
+ return 0;
+}
+
+GP<DjVuInfo>
+DjVuImage::get_info() const
+{
+ if (file)
+ {
+ return get_info(file);
+ }else
+ {
+ return 0;
+ }
+}
+
+GP<ByteStream>
+DjVuImage::get_anno() const
+{
+ GP<ByteStream> out = ByteStream::create();
+ ByteStream &mbs = *out;
+ if (file)
+ {
+ file->merge_anno(mbs);
+ }
+ mbs.seek(0);
+ if(!mbs.size())
+ {
+ out=0;
+ }
+ return out;
+}
+
+GP<ByteStream>
+DjVuImage::get_text() const
+{
+ GP<ByteStream> out = ByteStream::create();
+ ByteStream &mbs = *out;
+ if (file)
+ {
+ file->get_text(mbs);
+ }
+ mbs.seek(0);
+ if(!mbs.size())
+ {
+ out=0;
+ }
+ return out;
+}
+
+GP<ByteStream>
+DjVuImage::get_meta() const
+{
+ GP<ByteStream> out = ByteStream::create();
+ ByteStream &mbs = *out;
+ if (file)
+ {
+ file->get_meta(mbs);
+ }
+ mbs.seek(0);
+ if(!mbs.size())
+ {
+ out=0;
+ }
+ return out;
+}
+
+GP<IW44Image>
+DjVuImage::get_bg44() const
+{
+ if (file)
+ return get_bg44(file);
+ else
+ return 0;
+}
+
+GP<GPixmap>
+DjVuImage::get_bgpm() const
+{
+ if (file)
+ return get_bgpm(file);
+ else
+ return 0;
+}
+
+GP<JB2Image>
+DjVuImage::get_fgjb() const
+{
+ if (file)
+ return get_fgjb(file);
+ else
+ return 0;
+}
+
+GP<GPixmap>
+DjVuImage::get_fgpm() const
+{
+ if (file)
+ return get_fgpm(file);
+ else
+ return 0;
+}
+
+GP<DjVuPalette>
+DjVuImage::get_fgbc() const
+{
+ if (file)
+ return get_fgbc(file);
+ else
+ return 0;
+}
+
+int
+DjVuImage::get_width() const
+{
+ GP<DjVuInfo> info=get_info();
+ return info?((rotate_count&1)?(info->height):(info->width)):0;
+}
+
+int
+DjVuImage::get_height() const
+{
+ GP<DjVuInfo> info=get_info();
+ return info?((rotate_count&1)?(info->width):(info->height)):0;
+}
+
+int
+DjVuImage::get_real_width() const
+{
+ GP<DjVuInfo> info=get_info();
+ return info ? info->width : 0;
+}
+
+int
+DjVuImage::get_real_height() const
+{
+ GP<DjVuInfo> info=get_info();
+ return info ? info->height : 0;
+}
+
+int
+DjVuImage::get_version() const
+{
+ GP<DjVuInfo> info=get_info();
+ return info ? info->version : DJVUVERSION;
+}
+
+int
+DjVuImage::get_dpi() const
+{
+ GP<DjVuInfo> info=get_info();
+ return info ? info->dpi : 300;
+}
+
+int
+DjVuImage::get_rounded_dpi() const
+{
+ return (get_dpi()+5)/10*10;
+#if 0
+ /* This code used to round the reported dpi to 25, 50, 75, 100, 150,
+ 300, and 600. Now we just round the dpi to 10ths and return it */
+ int dpi=get_dpi();
+ if (dpi>700) return dpi;
+
+ const int std_dpi[]={ 25, 50, 75, 100, 150, 300, 600 };
+ const int std_dpis=sizeof(std_dpi)/sizeof(std_dpi[0]);
+ int min_dist=abs(dpi-std_dpi[0]);
+ int min_idx=0;
+ for(int i=1;i<std_dpis;i++)
+ if (abs(std_dpi[i]-dpi)<min_dist)
+ {
+ min_dist=abs(std_dpi[i]-dpi);
+ min_idx=i;
+ };
+ return std_dpi[min_idx];
+#endif
+}
+
+double
+DjVuImage::get_gamma() const
+{
+ GP<DjVuInfo> info=get_info();
+ return info ? info->gamma : 2.2;
+}
+
+GUTF8String
+DjVuImage::get_mimetype() const
+{
+ return file ? file->mimetype : GUTF8String();
+}
+
+
+//// DJVUIMAGE: UTILITIES
+
+GUTF8String
+DjVuImage::get_short_description() const
+{
+ GUTF8String msg = "Empty";
+ int width = get_width();
+ int height = get_height();
+ if (width && height)
+ if (file && file->file_size>100)
+ //msg.format("%dx%d in %0.1f Kb", width, height, file->file_size/1024.0);
+ msg.format( ERR_MSG("DjVuImage.short1") "\t%d\t%d\t%0.1f", width, height, file->file_size/1024.0 );
+ else
+ //msg.format("%dx%d", width, height);
+ msg.format( ERR_MSG("DjVuImage.short2") "\t%d\t%d", width, height );
+ return msg;
+}
+
+GUTF8String
+DjVuImage::get_long_description() const
+{
+ return file?(file->description):GUTF8String();
+}
+
+
+void
+DjVuImage::notify_chunk_done(const DjVuPort *, const GUTF8String & name)
+{
+ if (!relayout_sent &&
+ ( !name.cmp("INFO", 4) ||
+ !name.cmp("PMxx", 2) ||
+ !name.cmp("BMxx", 2) ) )
+ {
+ DjVuPort::get_portcaster()->notify_relayout(this);
+ relayout_sent=true;
+ }
+ else if (!name.cmp("Sxxx", 1) ||
+ !name.cmp("BGxx", 2) ||
+ !name.cmp("FGxx", 2) ||
+ !name.cmp("BMxx", 2) ||
+ !name.cmp("PMxx", 2) )
+ DjVuPort::get_portcaster()->notify_redisplay(this);
+}
+
+
+
+
+
+
+//// DJVUIMAGE: OLD-STYLE DECODING
+
+DjVuInterface::~DjVuInterface()
+{
+}
+
+class DjVuImageNotifier : public DjVuPort
+{
+ friend class DjVuImage;
+ DjVuInterface *notifier;
+ GP<DataPool> stream_pool;
+ GURL stream_url;
+public:
+ DjVuImageNotifier(DjVuInterface *notifier);
+ GP<DataPool> request_data(const DjVuPort *src, const GURL & url);
+ void notify_chunk_done(const DjVuPort *, const GUTF8String &name);
+ void notify_redisplay(const class DjVuImage * source);
+ void notify_relayout(const class DjVuImage * source);
+};
+
+DjVuImageNotifier::DjVuImageNotifier(DjVuInterface *notifier)
+ : notifier(notifier)
+{
+}
+
+GP<DataPool>
+DjVuImageNotifier::request_data(const DjVuPort *src, const GURL & url)
+{
+ if (url!=stream_url)
+ G_THROW( ERR_MSG("DjVuImage.not_decode") );
+ return stream_pool;
+}
+
+void
+DjVuImageNotifier::notify_redisplay(const class DjVuImage * source)
+{
+ if (notifier)
+ notifier->notify_redisplay();
+}
+
+void
+DjVuImageNotifier::notify_relayout(const class DjVuImage * source)
+{
+ if (notifier)
+ notifier->notify_relayout();
+}
+
+void
+DjVuImageNotifier::notify_chunk_done(const DjVuPort *, const GUTF8String &name)
+{
+ if (notifier)
+ notifier->notify_chunk(name, "" );
+}
+
+void
+DjVuImage::decode(ByteStream & str, DjVuInterface *notifier)
+{
+ DEBUG_MSG("DjVuImage::decode(): decoding old way...\n");
+ DEBUG_MAKE_INDENT(3);
+ if (file)
+ G_THROW( ERR_MSG("DjVuImage.bad_call") );
+ GP<DjVuImageNotifier> pport = new DjVuImageNotifier(notifier);
+ pport->stream_url=GURL::UTF8("internal://fake/fake.djvu");
+ pport->stream_pool=DataPool::create();
+ // Get all the data first
+ int length;
+ char buffer[1024];
+ while((length=str.read(buffer, 1024)))
+ pport->stream_pool->add_data(buffer, length);
+ pport->stream_pool->set_eof();
+ GP<DjVuDocument> doc = DjVuDocument::create_wait(pport->stream_url, (DjVuImageNotifier*)pport);
+ GP<DjVuImage> dimg=doc->get_page(-1, true, (DjVuImageNotifier*)pport);
+ file=dimg->get_djvu_file();
+ if (file->is_decode_stopped())
+ G_THROW( DataPool::Stop );
+ if (file->is_decode_failed())
+ G_THROW( ByteStream::EndOfFile ); // guess
+ if (!file->is_decode_ok())
+ G_THROW( ERR_MSG("DjVuImage.mult_error") );
+ DEBUG_MSG("decode DONE\n");
+}
+
+
+//// DJVUIMAGE: CHECKING
+
+static int
+compute_red(int w, int h, int rw, int rh)
+{
+ for (int red=1; red<16; red++)
+ if (((w+red-1)/red==rw) && ((h+red-1)/red==rh))
+ return red;
+ return 16;
+}
+
+
+int
+DjVuImage::is_legal_bilevel() const
+{
+ // Components
+ GP<DjVuInfo> info = get_info();
+ GP<JB2Image> fgjb = get_fgjb();
+ GP<IW44Image> bg44 = get_bg44();
+ GP<GPixmap> bgpm = get_bgpm();
+ GP<GPixmap> fgpm = get_fgpm();
+ // Check info
+ if (! info)
+ return 0;
+ int width = info->width;
+ int height = info->height;
+ if (! (width>0 && height>0))
+ return 0;
+ // Check fgjb
+ if (!fgjb)
+ return 0;
+ if (fgjb->get_width()!=width || fgjb->get_height()!=height)
+ return 0;
+ // Check that color information is not present.
+ if (bg44 || bgpm || fgpm)
+ return 0;
+ // Ok.
+ return 1;
+}
+
+int
+DjVuImage::is_legal_photo() const
+{
+ // Components
+ GP<DjVuInfo> info = get_info();
+ GP<JB2Image> fgjb = get_fgjb();
+ GP<IW44Image> bg44 = get_bg44();
+ GP<GPixmap> bgpm = get_bgpm();
+ GP<GPixmap> fgpm = get_fgpm();
+ // Check info
+ if (! info)
+ return 0;
+ int width = info->width;
+ int height = info->height;
+ if (! (width>0 && height>0))
+ return 0;
+ // Check that extra information is not present.
+ if (fgjb || fgpm)
+ return 0;
+ // Check bg44
+ if (bg44 && bg44->get_width()==width && bg44->get_height()==height)
+ return 1;
+ // Check bgpm
+ if (bgpm && (int)bgpm->columns()==width && (int)bgpm->rows()==height)
+ return 1;
+ // Ok.
+ return 0;
+}
+
+int
+DjVuImage::is_legal_compound() const
+{
+ // Components
+ GP<DjVuInfo> info = get_info();
+ GP<JB2Image> fgjb = get_fgjb();
+ GP<IW44Image> bg44 = get_bg44();
+ GP<GPixmap> bgpm = get_bgpm();
+ GP<GPixmap> fgpm = get_fgpm();
+ GP<DjVuPalette> fgbc = get_fgbc();
+ // Check size
+ if (! info)
+ return 0;
+ int width = info->width;
+ int height = info->height;
+ if (! (width>0 && height>0))
+ return 0;
+ // Check fgjb
+ if (!fgjb)
+ return 0;
+ if (fgjb->get_width()!=width || fgjb->get_height()!=height)
+ return 0;
+ // Check background
+ int bgred = 0;
+ if (bg44)
+ bgred = compute_red(width, height, bg44->get_width(), bg44->get_height());
+ else if (bgpm)
+ bgred = compute_red(width, height, bgpm->columns(), bgpm->rows());
+ if (bgred<1 || bgred>12)
+ return 0;
+ // Check foreground colors
+ int fgred = 0;
+ if (fgbc)
+ fgred = 1;
+ else if (fgpm)
+ fgred = compute_red(width, height, fgpm->columns(), fgpm->rows());
+ if (fgred<1 || fgred>12)
+ return 0;
+ // Check that all components are present
+ if (fgjb && bgred && fgred)
+ return 1;
+ // Unrecognized
+ return 0;
+}
+
+
+//// DJVUIMAGE: LOW LEVEL RENDERING
+
+GP<GBitmap>
+DjVuImage::get_bitmap(const GRect &rect,
+ int subsample, int align) const
+{
+ // Access image size
+ int width = get_real_width();
+ int height = get_real_height();
+ GP<JB2Image> fgjb = get_fgjb();
+ if ( width && height && fgjb &&
+ (fgjb->get_width() == width) &&
+ (fgjb->get_height() == height) )
+ {
+ return fgjb->get_bitmap(rect, subsample, align);
+ }
+ return 0;
+}
+
+GP<GPixmap>
+DjVuImage::get_bg_pixmap(const GRect &rect,
+ int subsample, double gamma) const
+{
+ GP<GPixmap> pm = 0;
+ // Access image size
+
+ GP<DjVuInfo> info = get_info();
+ int width = get_real_width();
+ int height = get_real_height();
+
+
+ if (width<=0 || height<=0 || !info) return 0;
+ // Compute gamma_correction
+ double gamma_correction = 1.0;
+ if (gamma > 0)
+ gamma_correction = gamma / info->gamma;
+ if (gamma_correction < 0.1)
+ gamma_correction = 0.1;
+ else if (gamma_correction > 10)
+ gamma_correction = 10;
+
+ // CASE1: Incremental BG IW44Image
+ GP<IW44Image> bg44 = get_bg44();
+ if (bg44)
+ {
+ int w = bg44->get_width();
+ int h = bg44->get_height();
+ // Avoid silly cases
+ if (w==0 || h==0 || width==0 || height==0)
+ return 0;
+ // Determine how much bg44 is reduced
+ int red = compute_red(width,height,w,h);
+ if (red<1 || red>12)
+ return 0;
+ // Handle pure downsampling cases
+ if (subsample == red)
+ pm = bg44->get_pixmap(1,rect);
+ else if (subsample == 2*red)
+ pm = bg44->get_pixmap(2,rect);
+ else if (subsample == 4*red)
+ pm = bg44->get_pixmap(4,rect);
+ else if (subsample == 8*red)
+ pm = bg44->get_pixmap(8,rect);
+ // Handle fractional downsampling case
+ else if (red*4 == subsample*3)
+ {
+ GRect nrect = rect;
+ GRect xrect = rect;
+ xrect.xmin = (xrect.xmin/3)*4;
+ xrect.ymin = (xrect.ymin/3)*4;
+ xrect.xmax = ((xrect.xmax+2)/3)*4;
+ xrect.ymax = ((xrect.ymax+2)/3)*4;
+ nrect.translate(-xrect.xmin*3/4, -xrect.ymin*3/4);
+ if (xrect.xmax > w)
+ xrect.xmax = w;
+ if (xrect.ymax > h)
+ xrect.ymax = h;
+ GP<GPixmap> ipm = bg44->get_pixmap(1,xrect);
+ pm = GPixmap::create();
+ pm->downsample43(ipm, &nrect);
+ }
+ // Handle all other cases with pixmapscaler
+ else
+ {
+ // find suitable power of two
+ int po2 = 16;
+ while (po2>1 && subsample<po2*red)
+ po2 >>= 1;
+ // setup pixmap scaler
+ int inw = (w+po2-1)/po2;
+ int inh = (h+po2-1)/po2;
+ int outw = (width+subsample-1)/subsample;
+ int outh = (height+subsample-1)/subsample;
+ GP<GPixmapScaler> gps=GPixmapScaler::create(inw, inh, outw, outh);
+ GPixmapScaler &ps=*gps;
+ ps.set_horz_ratio(red*po2, subsample);
+ ps.set_vert_ratio(red*po2, subsample);
+ // run pixmap scaler
+ GRect xrect;
+ ps.get_input_rect(rect,xrect);
+ GP<GPixmap> ipm = bg44->get_pixmap(po2,xrect);
+ pm = GPixmap::create();
+ ps.scale(xrect, *ipm, rect, *pm);
+ }
+ // Apply gamma correction
+ if (pm && gamma_correction!=1.0)
+ pm->color_correct(gamma_correction);
+ return pm;
+ }
+
+ // CASE 2: Raw background pixmap
+ GP<GPixmap> bgpm = get_bgpm();
+ if (bgpm)
+ {
+ int w = bgpm->columns();
+ int h = bgpm->rows();
+ // Avoid silly cases
+ if (w==0 || h==0 || width==0 || height==0)
+ return 0;
+ // Determine how much bgpm is reduced
+ int red = compute_red(width,height,w,h);
+ if (red<1 || red>12)
+ return 0;
+ // Handle pure downsampling cases
+ int ratio = subsample/red;
+ if (subsample==ratio*red && ratio>=1)
+ {
+ pm = GPixmap::create();
+ if (ratio == 1)
+ pm->init(*bgpm, rect);
+ else if (ratio > 1)
+ pm->downsample(bgpm, ratio, &rect);
+ }
+ // Handle all other cases with pixmapscaler
+ else
+ {
+ // setup pixmap scaler
+ int outw = (width+subsample-1)/subsample;
+ int outh = (height+subsample-1)/subsample;
+ GP<GPixmapScaler> gps=GPixmapScaler::create(w, h, outw, outh);
+ GPixmapScaler &ps=*gps;
+ ps.set_horz_ratio(red, subsample);
+ ps.set_vert_ratio(red, subsample);
+ // run pixmap scaler
+ pm = GPixmap::create();
+ GRect xrect(0,0,w,h);
+ ps.scale(xrect, *bgpm, rect, *pm);
+ }
+ // Apply gamma correction
+ if (pm && gamma_correction!=1.0)
+ pm->color_correct(gamma_correction);
+ return pm;
+ }
+
+ // FAILURE
+ return 0;
+}
+
+
+
+int
+DjVuImage::stencil(GPixmap *pm, const GRect &rect,
+ int subsample, double gamma) const
+{
+ // Warping and blending.
+ if (!pm)
+ return 0;
+ // Access components
+
+ GP<DjVuInfo> info = get_info();
+ int width = get_real_width();
+ int height = get_real_height();
+
+
+ if (width<=0 || height<=0 || !info) return 0;
+ GP<JB2Image> fgjb = get_fgjb();
+ GP<GPixmap> fgpm = get_fgpm();
+ GP<DjVuPalette> fgbc = get_fgbc();
+
+ // Compute gamma_correction
+ double gamma_correction = 1.0;
+ if (gamma > 0)
+ gamma_correction = gamma / info->gamma;
+ if (gamma_correction < 0.1)
+ gamma_correction = 0.1;
+ else if (gamma_correction > 10)
+ gamma_correction = 10;
+
+ // Compute alpha map and relevant JB2Image components
+ GList<int> components;
+ GP<GBitmap> bm;
+ if (fgjb)
+ {
+ JB2Image *jimg = fgjb;
+ if (! (width && height &&
+ jimg->get_width() == width &&
+ jimg->get_height() == height ) )
+ return 0;
+ // Decode bitmap
+ bm = GBitmap::create(rect.height(), rect.width());
+ bm->set_grays(1+subsample*subsample);
+ int rxmin = rect.xmin * subsample;
+ int rymin = rect.ymin * subsample;
+ for (int blitno = 0; blitno < jimg->get_blit_count(); blitno++)
+ {
+ const JB2Blit *pblit = jimg->get_blit(blitno);
+ const JB2Shape &pshape = jimg->get_shape(pblit->shapeno);
+ if (pshape.bits &&
+ pblit->left <= rect.xmax * subsample &&
+ pblit->bottom <= rect.ymax * subsample &&
+ pblit->left + (int)pshape.bits->columns() >= rect.xmin * subsample &&
+ pblit->bottom + (int)pshape.bits->rows() >= rect.ymin * subsample )
+ {
+ // Record component list
+ if (fgbc) components.append(blitno);
+ // Blit
+ bm->blit(pshape.bits,
+ pblit->left - rxmin, pblit->bottom - rymin,
+ subsample);
+ }
+ }
+ }
+
+
+ // TWO LAYER MODEL
+ if (bm && fgbc)
+ {
+ // Perform attenuation from scratch
+ pm->attenuate(bm, 0, 0);
+ // Check that fgbc has the correct size
+ JB2Image *jimg = fgjb;
+ DjVuPalette *fg = fgbc;
+ if (jimg->get_blit_count() != fg->colordata.size())
+ return 0;
+ // Copy and color correct palette
+ int palettesize = fg->size();
+ GTArray<GPixel> colors(0,palettesize-1);
+ for (int i=0; i<palettesize; i++)
+ fg->index_to_color(i, colors[i]);
+ GPixmap::color_correct(gamma_correction, colors, palettesize);
+ // Blit all components (one color at a time)
+ while (components.size() > 0)
+ {
+ GPosition nullpos;
+ GPosition pos = components;
+ int lastx = 0;
+ int colorindex = fg->colordata[components[pos]];
+ if (colorindex >= palettesize)
+ G_THROW( ERR_MSG("DjVuImage.corrupted") );
+ // Gather relevant components and relevant rectangle
+ GList<int> compset;
+ GRect comprect;
+ while (pos)
+ {
+ int blitno = components[pos];
+ const JB2Blit *pblit = jimg->get_blit(blitno);
+ if (pblit->left < lastx) break;
+ lastx = pblit->left;
+ if (fg->colordata[blitno] == colorindex)
+ {
+ const JB2Shape &pshape = jimg->get_shape(pblit->shapeno);
+ GRect rect(pblit->left, pblit->bottom,
+ pshape.bits->columns(), pshape.bits->rows());
+ comprect.recthull(comprect, rect);
+ compset.insert_before(nullpos, components, pos);
+ continue;
+ }
+ ++pos;
+ }
+ // Round alpha map rectangle
+ comprect.xmin = comprect.xmin / subsample;
+ comprect.ymin = comprect.ymin / subsample;
+ comprect.xmax = (comprect.xmax+subsample-1) / subsample;
+ comprect.ymax = (comprect.ymax+subsample-1) / subsample;
+ comprect.intersect(comprect, rect);
+ // Compute alpha map for that color
+ bm = 0;
+ bm = GBitmap::create(comprect.height(), comprect.width());
+ bm->set_grays(1+subsample*subsample);
+ int rxmin = comprect.xmin * subsample;
+ int rymin = comprect.ymin * subsample;
+ for (pos=compset; pos; ++pos)
+ {
+ int blitno = compset[pos];
+ const JB2Blit *pblit = jimg->get_blit(blitno);
+ const JB2Shape &pshape = jimg->get_shape(pblit->shapeno);
+ bm->blit(pshape.bits,
+ pblit->left - rxmin, pblit->bottom - rymin,
+ subsample);
+ }
+ // Blend color into background pixmap
+ pm->blit(bm, comprect.xmin-rect.xmin, comprect.ymin-rect.ymin, &colors[colorindex]);
+ }
+ return 1;
+ }
+
+
+ // THREE LAYER MODEL
+ if (bm && fgpm)
+ {
+ // This follows fig. 4 in Adelson "Layered representations for image
+ // coding" (1991) http://www-bcs.mit.edu/people/adelson/papers.html.
+ // The properly warped background is already in PM. The properly warped
+ // alpha map is already in BM. We just have to warp the foreground and
+ // perform alpha blending.
+#ifdef SIMPLE_THREE_LAYER_RENDERING
+ int w = fgpm->columns();
+ int h = fgpm->rows();
+ // Determine foreground reduction
+ int red = compute_red(width,height, w, h);
+ if (red<1 || red>12)
+ return 0;
+ // Warp foreground pixmap
+ GPixmapScaler ps(w,h,width/subsample+1,height/subsample+1);
+ ps.set_horz_ratio(red,subsample);
+ ps.set_vert_ratio(red,subsample);
+ GP<GPixmap> nfg = new GPixmap;
+ GRect provided(0,0,w,h);
+ ps.scale(provided, *fgpm, rect, *nfg);
+ // Attenuate background and blit
+ nfg->color_correct(gamma_correction);
+ pm->blend(bm, 0, 0, nfg); // blend == attenuate + blit
+ return 1;
+#else
+ // Things are now a little bit more complex because the convenient
+ // function GPixmap::stencil() simultaneously upsamples the foreground
+ // by an integer factor and performs the alpha blending. We have
+ // to determine how and when this facility can be used.
+ int w = fgpm->columns();
+ int h = fgpm->rows();
+ // Determine foreground reduction
+ int red = compute_red(width,height,w,h);
+ if (red<1 || red>12)
+ return 0;
+ // Try supersampling foreground pixmap by an integer factor
+ int supersample = ( red>subsample ? red/subsample : 1);
+ int wantedred = supersample*subsample;
+ // Try simple foreground upsampling
+ if (red == wantedred)
+ {
+ // Simple foreground upsampling is enough.
+ pm->stencil(bm, fgpm, supersample, &rect, gamma_correction);
+ return 1;
+ }
+ else
+ {
+ // Must pre-warp foreground pixmap
+ GP<GPixmap> nfg;
+ int desw = (w*red+wantedred-1)/wantedred;
+ int desh = (h*red+wantedred-1)/wantedred;
+ // Cache rescaled fgpm for speed
+ static const DjVuImage *tagimage = 0;
+ static const GPixmap *tagfgpm = 0;
+ static GP<GPixmap> cachednfg = 0;
+ // Check whether cached fgpm applies.
+ if ( cachednfg && this==tagimage && fgpm==tagfgpm
+ && desw==(int)cachednfg->columns()
+ && desh==(int)cachednfg->rows() )
+ {
+ nfg = cachednfg;
+ }
+ else
+ {
+ GP<GPixmapScaler> gps=GPixmapScaler::create(w,h,desw,desh);
+ GPixmapScaler &ps=*gps;
+ ps.set_horz_ratio(red, wantedred);
+ ps.set_vert_ratio(red, wantedred);
+ nfg = GPixmap::create();
+ GRect provided(0,0,w,h);
+ GRect desired(0,0,desw,desh);
+ ps.scale(provided, *fgpm, desired, *nfg);
+ }
+ // Use combined warp+blend function
+ pm->stencil(bm, nfg, supersample, &rect, gamma_correction);
+ // Cache
+ tagimage = this;
+ tagfgpm = fgpm;
+ cachednfg = nfg;
+ return 1;
+ }
+#endif
+ }
+
+ // FAILURE
+ return 0;
+}
+
+
+GP<GPixmap>
+DjVuImage::get_fg_pixmap(const GRect &rect,
+ int subsample, double gamma) const
+{
+ // Obtain white background pixmap
+ GP<GPixmap> pm;
+ // Access components
+ const int width = get_real_width();
+ const int height = get_real_height();
+ if (width && height)
+ {
+ pm = GPixmap::create(rect.height(),rect.width(), &GPixel::WHITE);
+ if (!stencil(pm, rect, subsample, gamma))
+ pm=0;
+ }
+ return pm;
+}
+
+
+GP<GPixmap>
+DjVuImage::get_pixmap(const GRect &rect, int subsample, double gamma) const
+{
+ // Get background
+ GP<GPixmap> pm = get_bg_pixmap(rect, subsample, gamma);
+ // Superpose foreground
+ if (! stencil(pm, rect, subsample, gamma))
+ // Avoid ugly progressive display (hack)
+ if (get_fgjb()) return 0;
+ // Return
+ return pm;
+}
+
+
+//// DJVUIMAGE: RENDERING (ARBITRARY SCALE)
+
+typedef GP<GBitmap>(DjVuImage::*BImager)(const GRect &, int, int) const;
+typedef GP<GPixmap>(DjVuImage::*PImager)(const GRect &, int, double) const;
+
+static GP<GBitmap>
+do_bitmap(const DjVuImage &dimg, BImager get,
+ const GRect &inrect, const GRect &inall, int align )
+{
+ GRect rect=inrect;
+ GRect all=inall;
+///* rotate code
+ if( dimg.get_rotate()%4 )
+ {
+ GRectMapper mapper;
+ mapper.rotate((4-dimg.get_rotate())%4);
+ mapper.map(rect);
+ mapper.map(all);
+ }
+///* rotate code ends
+
+ // Sanity
+ if (! ( all.contains(rect.xmin, rect.ymin) &&
+ all.contains(rect.xmax-1, rect.ymax-1) ))
+ G_THROW( ERR_MSG("DjVuImage.bad_rect") );
+ // Check for integral reduction
+ int red;
+ int w = dimg.get_real_width();
+ int h = dimg.get_real_height();
+
+ int rw = all.width();
+ int rh = all.height();
+ GRect zrect = rect;
+ zrect.translate(-all.xmin, -all.ymin);
+ for (red=1; red<=15; red++)
+ if (rw*red>w-red && rw*red<w+red && rh*red>h-red && rh*red<h+red)
+ {
+ GP<GBitmap> bm=(dimg.*get)(zrect, red, align);
+ if(bm)
+ return bm->rotate((4-dimg.get_rotate())%4);
+ else
+ return NULL;
+ }
+ // Find best reduction
+ for (red=15; red>1; red--)
+ if ( (rw*red < w && rh*red < h) ||
+ (rw*red*3 < w || rh*red*3 < h) )
+ break;
+ // Setup bitmap scaler
+ if (! (w && h)) return 0;
+ GP<GBitmapScaler> gbs=GBitmapScaler::create();
+ GBitmapScaler &bs=*gbs;
+ bs.set_input_size( (w+red-1)/red, (h+red-1)/red );
+ bs.set_output_size( rw, rh );
+ bs.set_horz_ratio( rw*red, w );
+ bs.set_vert_ratio( rh*red, h );
+ // Scale
+ GRect srect;
+ bs.get_input_rect(zrect, srect);
+ GP<GBitmap> sbm = (dimg.*get)(srect, red, 1);
+ if (!sbm) return 0;
+ int border = ((zrect.width() + align - 1) & ~(align - 1)) - zrect.width();
+ GP<GBitmap> bm = GBitmap::create(zrect.height(), zrect.width(), border);
+ bs.scale(srect, *sbm, zrect, *bm);
+ if( bm )
+ return bm->rotate((4-dimg.get_rotate())%4);
+ else
+ return NULL;
+}
+
+static GP<GPixmap>
+do_pixmap(const DjVuImage &dimg, PImager get,
+ const GRect &inrect, const GRect &inall, double gamma )
+{
+
+ GRect rect=inrect;
+ GRect all=inall;
+///* rotate code
+ if( dimg.get_rotate()%4 )
+ {
+ GRectMapper mapper;
+ mapper.rotate((4-dimg.get_rotate())%4);
+ mapper.map(rect);
+ mapper.map(all);
+ }
+///* rotate code ends
+
+ // Sanity
+ if (! ( all.contains(rect.xmin, rect.ymin) &&
+ all.contains(rect.xmax-1, rect.ymax-1) ))
+ G_THROW( ERR_MSG("DjVuImage.bad_rect2") );
+ // Check for integral reduction
+ int red, w=0, h=0, rw=0, rh=0;
+ w = dimg.get_real_width();
+ h = dimg.get_real_height();
+
+
+ rw = all.width();
+ rh = all.height();
+ GRect zrect = rect;
+ zrect.translate(-all.xmin, -all.ymin);
+ for (red=1; red<=15; red++)
+ if (rw*red>w-red && rw*red<w+red && rh*red>h-red && rh*red<h+red)
+ {
+ GP<GPixmap> pm = (dimg.*get)(zrect, red, gamma);
+ if( pm )
+ return pm->rotate((4-dimg.get_rotate())%4);
+ else
+ return NULL;
+ }
+ // These reductions usually go faster (improve!)
+ static int fastred[] = { 12,6,4,3,2,1 };
+ // Find best reduction
+ for (int i=0; (red=fastred[i])>1; i++)
+ if ( (rw*red < w && rh*red < h) ||
+ (rw*red*3 < w || rh*red*3 < h) )
+ break;
+ // Setup pixmap scaler
+ if (w<0 || h<0) return 0;
+ GP<GPixmapScaler> gps=GPixmapScaler::create();
+ GPixmapScaler &ps=*gps;
+ ps.set_input_size( (w+red-1)/red, (h+red-1)/red );
+ ps.set_output_size( rw, rh );
+ ps.set_horz_ratio( rw*red, w );
+ ps.set_vert_ratio( rh*red, h );
+ // Scale
+ GRect srect;
+ ps.get_input_rect(zrect, srect);
+ GP<GPixmap> spm = (dimg.*get)(srect, red, gamma);
+ if (!spm) return 0;
+ GP<GPixmap> pm = GPixmap::create();
+ ps.scale(srect, *spm, zrect, *pm);
+ if(pm)
+ return pm->rotate((4-dimg.get_rotate())%4);
+ else
+ return NULL;
+}
+
+GP<GPixmap>
+DjVuImage::get_pixmap(const GRect &rect, const GRect &all, double gamma) const
+{
+ return do_pixmap(*this, & DjVuImage::get_pixmap, rect, all, gamma);
+}
+
+GP<GBitmap>
+DjVuImage::get_bitmap(const GRect &rect, const GRect &all, int align) const
+{
+ return do_bitmap(*this, & DjVuImage::get_bitmap, rect, all, align);
+}
+
+GP<GPixmap>
+DjVuImage::get_bg_pixmap(const GRect &rect, const GRect &all, double gamma) const
+{
+ return do_pixmap(*this, & DjVuImage::get_bg_pixmap, rect, all, gamma);
+}
+
+GP<GPixmap>
+DjVuImage::get_fg_pixmap(const GRect &rect, const GRect &all, double gamma) const
+{
+ return do_pixmap(*this, & DjVuImage::get_fg_pixmap, rect, all, gamma);
+}
+
+int
+DjVuImage::get_rotate() const
+{
+ return (rotate_count<0)?0:rotate_count;
+}
+
+void
+DjVuImage::init_rotate(const DjVuInfo &info)
+{
+ rotate_count=((360-GRect::findangle(info.orientation))/90)%4;
+}
+
+void DjVuImage::set_rotate(int count)
+{
+ rotate_count=((count%4)+4)%4;
+}
+
+GP<DjVuAnno>
+DjVuImage::get_decoded_anno()
+{
+ GP<DjVuAnno> djvuanno = DjVuAnno::create();
+ GP<ByteStream> bs=get_anno();
+ if( bs )
+ {
+ djvuanno->decode(bs);
+
+ const int rotate_count=get_rotate();
+ if( rotate_count % 4 )
+ {
+ ///map hyperlinks correctly for rotation
+ GRect input, output;
+ input = GRect(0,0,get_width(), get_height());
+ output = GRect(0,0, get_real_width(), get_real_height());
+
+ GRectMapper mapper;
+ mapper.clear();
+ mapper.set_input(input);
+ mapper.set_output(output);
+ mapper.rotate((4-rotate_count)%4);
+
+ GPList<GMapArea> &list=djvuanno->ant->map_areas;
+ for(GPosition pos=list;pos;++pos)
+ {
+ list[pos]->unmap(mapper);
+ }
+ }
+ return djvuanno;
+ }
+ else
+ return NULL;
+}
+
+
+void
+DjVuImage::map(GRect &rect) const
+{
+ GRect input, output;
+ const int rotate_count=get_rotate();
+ if(rotate_count%4)
+ {
+ input = GRect(0,0,get_width(), get_height());
+ output = GRect(0,0, get_real_width(), get_real_height());
+
+ GRectMapper mapper;
+ mapper.clear();
+ mapper.set_input(input);
+ mapper.set_output(output);
+ mapper.rotate((4-rotate_count)%4);
+ mapper.map(rect);
+ }
+}
+
+void
+DjVuImage::unmap(GRect &rect) const
+{
+ GRect input, output;
+ const int rotate_count=get_rotate();
+ if(rotate_count%4)
+ {
+ input = GRect(0,0,get_width(), get_height());
+ output = GRect(0,0, get_real_width(), get_real_height());
+
+ GRectMapper mapper;
+ mapper.clear();
+ mapper.set_input(input);
+ mapper.set_output(output);
+ mapper.rotate((4-rotate_count)%4);
+ mapper.unmap(rect);
+ }
+}
+
+void
+DjVuImage::map(int &x, int &y) const
+{
+ GRect input, output;
+ const int rotate_count=get_rotate();
+ if(rotate_count%4)
+ {
+ input = GRect(0,0,get_width(), get_height());
+ output = GRect(0,0, get_real_width(), get_real_height());
+
+ GRectMapper mapper;
+ mapper.clear();
+ mapper.set_input(input);
+ mapper.set_output(output);
+ mapper.rotate((4-rotate_count)%4);
+ mapper.map(x, y);
+ }
+}
+
+void
+DjVuImage::unmap(int &x, int &y) const
+{
+ GRect input, output;
+ const int rotate_count=get_rotate();
+ if(rotate_count%4)
+ {
+ input = GRect(0,0,get_width(), get_height());
+ output = GRect(0,0, get_real_width(), get_real_height());
+
+ GRectMapper mapper;
+ mapper.clear();
+ mapper.set_input(input);
+ mapper.set_output(output);
+ mapper.rotate((4-rotate_count)%4);
+ mapper.unmap(x, y);
+ }
+}
+
+bool
+DjVuImage::wait_for_complete_decode(void)
+{
+ if (file)
+ {
+ file->resume_decode(true);
+ return file->is_decode_ok();
+ }
+ return 0;
+}
+
+// Write out a DjVuXML object tag and map tag.
+void
+DjVuImage::writeXML(ByteStream &str_out,const GURL &doc_url,const int flags) const
+{
+ const int height=get_height();
+
+ static const char *Object="<OBJECT data=\"";
+ const GURL url(get_djvu_file()->get_url());
+ const GUTF8String pagename(url.fname());
+ GUTF8String page_param;
+ if(doc_url.is_valid() && !doc_url.is_empty() && (doc_url != url))
+ {
+ str_out.writestring(Object+doc_url.get_string());
+ page_param="<PARAM name=\"PAGE\" value=\""+pagename+"\" />\n";
+ }else
+ {
+ str_out.writestring(Object+doc_url.get_string());
+ }
+ str_out.writestring("\" type=\""+get_mimetype()+"\" height=\""
+ +GUTF8String(height)+"\" width=\""+GUTF8String(get_width())
+ +"\" usemap=\""+pagename.toEscaped()+"\" >\n");
+ if(!(flags & NOINFO))
+ {
+ const GP<DjVuInfo> info(get_info());
+ if(info)
+ {
+ info->writeParam(str_out);
+ }
+ }
+ str_out.writestring(page_param);
+ const GP<DjVuAnno> anno(DjVuAnno::create());
+ if(!(flags & NOINFO)||!(flags&NOMAP))
+ {
+ const GP<ByteStream> anno_str(get_anno());
+ if(anno_str)
+ {
+ anno->decode(anno_str);
+ }
+ if(!(flags & NOINFO))
+ {
+ anno->writeParam(str_out);
+ }
+ }
+ if(!(flags & NOTEXT))
+ {
+ const GP<DjVuText> text(DjVuText::create());
+ {
+ const GP<ByteStream> text_str(get_text());
+ if(text_str)
+ {
+ text->decode(text_str);
+ }
+ text->writeText(str_out,height);
+ }
+ }
+ if(!(flags & NOMETA))
+ {
+ const GP<ByteStream> meta_str(get_meta());
+ if(meta_str)
+ {
+ GP<IFFByteStream> giff=IFFByteStream::create(meta_str);
+ IFFByteStream &iff=*giff;
+ GUTF8String chkid;
+ while( iff.get_chunk(chkid))
+ {
+ GP<ByteStream> gbs(iff.get_bytestream());
+ if(chkid == "METa")
+ {
+ str_out.copy(*gbs);
+ //str_out.writestring(gbs->getAsUTF8());
+ }else if(chkid == "METz")
+ {
+ gbs=BSByteStream::create(gbs);
+ str_out.copy(*gbs);
+ //str_out.writestring(gbs->getAsUTF8());
+ }
+ iff.close_chunk();
+ }
+ }
+ }
+ str_out.writestring(GUTF8String("</OBJECT>\n"));
+ if(!(flags & NOMAP))
+ {
+ anno->writeMap(str_out,pagename,height);
+ }
+}
+
+// Write out a DjVuXML object tag and map tag.
+void
+DjVuImage::writeXML(ByteStream &str_out) const
+{
+ writeXML(str_out,GURL());
+}
+
+// Write out a DjVuXML object tag and map tag.
+GUTF8String
+DjVuImage::get_XML(const GURL &doc_url,const int flags) const
+{
+ GP<ByteStream> gbs(ByteStream::create());
+ ByteStream &bs=*gbs;
+ writeXML(bs,doc_url);
+ bs.seek(0L);
+ return bs.getAsUTF8();
+}
+
+// Write out a DjVuXML object tag and map tag.
+GUTF8String
+DjVuImage::get_XML(void) const
+{
+ return get_XML(GURL());
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuImage.h b/kviewshell/plugins/djvu/libdjvu/DjVuImage.h
new file mode 100644
index 00000000..57b40938
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuImage.h
@@ -0,0 +1,449 @@
+//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: DjVuImage.h,v 1.9 2005/04/27 16:34:13 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _DJVUIMAGE_H
+#define _DJVUIMAGE_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+/** @name DjVuImage.h
+
+ Files #"DjVuImage.h"# and #"DjVuImage.cpp"# implement \Ref{DjVuImage}
+ class produced as a result of decoding of DjVu files. In the previous
+ version of the library both the rendering {\bf and} decoding have been
+ handled by \Ref{DjVuImage}. This is no longer true. Now the
+ \Ref{DjVuDocument} and \Ref{DjVuFile} classes handle decoding of both
+ single page and multi page documents.
+
+ For compatibility reasons though, we still support old-style decoding
+ interface through the \Ref{DjVuImage} class for single page documents
+ {\em only}. As before, the display programs can call the decoding
+ function from a separate thread. The user interface thread may call
+ the rendering functions at any time. Rendering will be performed using
+ the most recent data generated by the decoding thread. This multithreaded
+ capability enables progressive display of remote images.
+
+ {\bf Creating DjVu images} --- Class \Ref{DjVuImage} does not provide a
+ direct way to create a DjVu image. The recommended procedure consists of
+ directly writing the required chunks into an \Ref{IFFByteStream} as
+ demonstrated in program \Ref{djvumake}. Dealing with too many encoding
+ issues (such as chunk ordering and encoding quality) would indeed make the
+ decoder unnecessarily complex.
+
+ {\bf ToDo: Layered structure} --- Class #DjVuImage# currently contains an
+ unstructured collection of smart pointers to various data structures.
+ Although it simplifies the rendering routines, this choice does not
+ reflect the layered structure of DjVu images and does not leave much room
+ for evolution. We should be able to do better.
+
+ @memo
+ Decoding DjVu and IW44 images.
+ @author
+ L\'eon Bottou <leonb@research.att.com> - initial implementation
+ Andrei Erofeev <eaf@geocities.com> - multipage support
+ @version
+ #$Id: DjVuImage.h,v 1.9 2005/04/27 16:34:13 leonb Exp $# */
+//@{
+
+
+
+#include "DjVuFile.h"
+#include "DjVuAnno.h"
+#include "GRect.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+/* Obsolete class included for backward compatibility. */
+
+class DjVuInterface
+{
+public:
+ virtual ~DjVuInterface();
+ virtual void notify_chunk(const char *chkid, const char *msg) = 0;
+ virtual void notify_relayout(void) = 0;
+ virtual void notify_redisplay(void) = 0;
+};
+
+
+/** Main DjVu Image data structure. This class defines the internal
+ representation of a DjVu image. This representation consists of a few
+ pointers referencing the various components of the DjVu image. These
+ components are created and populated by the decoding function. The
+ rendering functions then can use the available components to compute a
+ pixel representation of the desired segment of the DjVu image. */
+
+class DjVuImage : public DjVuPort
+{
+protected:
+ DjVuImage(void);
+public:
+ enum { NOINFO, NOTEXT=1, NOMAP=4, NOMETA=8 };
+ // CONSTRUCTION
+ /** @name Construction. */
+ //@{
+ /** Creates an empty DjVu image. After the image has been constructed,
+ it may be connected to an existing \Ref{DjVuFile} or left as is.
+
+ In the former case #DjVuImage# will look for its decoded components
+ (like #Sjbz# or #BG44#) by decending the hierarchy of \Ref{DjVuFile}s
+ starting from the one passed to \Ref{connect}().
+
+ In the latter case you can use \Ref{decode}() function to decode
+ {\bf single-page} DjVu documents in the old-style way. */
+ static GP<DjVuImage> create(void) {return new DjVuImage();}
+
+ /** Connects this #DjVuImage# to the passed \Ref{DjVuFile}. The #DjVuImage#
+ will use this \Ref{DjVuFile} to retrieve components necessary for
+ decoding. It will also connect itself to \Ref{DjVuFile} using the
+ communication mechanism provided by \Ref{DjVuPort} and \Ref{DjVuPortcaster}.
+ This will allow it to receive and relay messages and requests generated
+ by the passed \Ref{DjVuFile} and any file included into it. */
+ void connect(const GP<DjVuFile> & file);
+
+ /** This combines the above two steps for simplier code operations. */
+ static GP<DjVuImage> create(const GP<DjVuFile> &file)
+ { const GP<DjVuImage> retval=create(); retval->connect(file); return retval; }
+
+ //@}
+
+ // COMPONENTS
+ /** @name Components. */
+ //@{
+ /** Returns a pointer to a DjVu information component.
+ This function returns a null pointer until the decoder
+ actually processes an #"INFO"# chunk. */
+ GP<DjVuInfo> get_info() const;
+ /** Returns a pointer to the IW44 encoded background component of a DjVu
+ image. This function returns a null pointer until the decoder actually
+ processes an #"BG44"# chunk. */
+ GP<IW44Image> get_bg44() const;
+ /** Returns a pointer to the raw background component of a DjVu image. The
+ background component is used for JPEG encoded backgrounds. This
+ function returns a null pointer until the decoder actually processes an
+ #"BGjp"# chunk. */
+ GP<GPixmap> get_bgpm() const;
+ /** Returns a pointer to the mask of the foreground component of a DjVu
+ image. The mask of the foreground component is always a JB2 image in
+ this implementation. This function returns a null pointer until the
+ decoder actually processes an #"Sjbz"# chunk. */
+ GP<JB2Image> get_fgjb() const;
+ /** Returns a pointer to the colors of the foreground component of a DjVu
+ image. The mask of the foreground component is always a small pixmap in
+ this implementation. This function returns a null pointer until the
+ decoder actually processes an #"FG44"# chunk. */
+ GP<GPixmap> get_fgpm() const;
+ /** Returns a pointer to a palette object containing colors for the
+ foreground components of a DjVu image. These colors are only
+ pertinent with respect to the JB2Image. */
+ GP<DjVuPalette> get_fgbc() const;
+ /** Returns a pointer to a ByteStream containing all the annotation
+ chunks collected so far for this image. Individual chunks can be
+ retrieved using \Ref{IFFByteStream}. Returns NULL if no chunks have been
+ collected yet. */
+ GP<ByteStream> get_anno() const;
+ /** Returns a pointer to a ByteStream containing all the hidden text.
+ Returns NULL if no chunks have been collected yet. */
+ GP<ByteStream> get_text() const;
+ /** Returns a pointer to a ByteStream containing all the metadata.
+ Returns NULL if no chunks have been collected yet. */
+ GP<ByteStream> get_meta() const;
+ //@}
+
+ // NEW STYLE DECODING
+ /** @name New style decoding. */
+ //@{
+ /** The decoder is now started when the image is created
+ by function \Ref{DjVuDocument::get_page} in \Ref{DjVuDocument}.
+ This function waits until the decoding thread terminates
+ and returns TRUE if the image has been successfully decoded. */
+ bool wait_for_complete_decode(void);
+ //@}
+
+ // OLD STYLE DECODING
+ /** @name Old style decoding (backward compatibility). */
+ //@{
+ /** This function is here for backward compatibility. Now, with the
+ introduction of multipage DjVu documents, the decoding is handled
+ by \Ref{DjVuFile} and \Ref{DjVuDocument} classes. For single page
+ documents though, we still have this wrapper. */
+ void decode(ByteStream & str, DjVuInterface *notifier=0);
+ //@}
+
+ // UTILITIES
+ /** @name Utilities */
+ //@{
+ /** Returns the width of the DjVu image. This function just extracts this
+ information from the DjVu information component. It returns zero if such
+ a component is not yet available. This gives rotated width if there is any
+ rotation of image. If you need real width, use #get_real_width()#.*/
+ int get_width() const;
+ /** Returns the height of the DjVu image. This function just extracts this
+ information from the DjVu information component. It returns zero if such
+ a component is not yet available. This gives rotated height if there is any
+ rotation of image. If you need real width, use #get_real_height()#.*/
+ int get_height() const;
+ /** Returns the width of the DjVu image. This function just extracts this
+ information from the DjVu information component. It returns zero if such
+ a component is not yet available.*/
+ int get_real_width() const;
+ /** Returns the height of the DjVu image. This function just extracts this
+ information from the DjVu information component. It returns zero if such
+ a component is not yet available.*/
+ int get_real_height() const;
+ /** Returns the format version the DjVu data. This function just extracts
+ this information from the DjVu information component. It returns zero if
+ such a component is not yet available. This version number should
+ be compared with the \Ref{DjVu version constants}. */
+ int get_version() const;
+ /** Returns the resolution of the DjVu image. This information is given in
+ pixels per 2.54 cm. Display programs can use this information to
+ determine the natural magnification to use for rendering a DjVu
+ image. */
+ int get_dpi() const;
+ /** Same as \Ref{get_dpi}() but instead of precise value returns the closest
+ "standard" one: 25, 50, 75, 100, 150, 300, 600. If dpi is greater than
+ 700, it's returned as is. */
+ int get_rounded_dpi() const;
+ /** Returns the gamma coefficient of the display for which the image was
+ designed. The rendering functions can use this information in order to
+ perform color correction for the intended display device. */
+ double get_gamma() const;
+ /** Returns a MIME type string describing the DjVu data. This information
+ is auto-sensed by the decoder. The MIME type can be #"image/djvu"# or
+ #"image/iw44"# depending on the data stream. */
+ GUTF8String get_mimetype() const;
+ /** Returns a short string describing the DjVu image.
+ Example: #"2500x3223 in 23.1 Kb"#. */
+ GUTF8String get_short_description() const;
+ /** Returns a verbose description of the DjVu image. This description lists
+ all the chunks with their size and a brief comment, as shown in the
+ following example.
+ \begin{verbatim}
+ DJVU Image (2325x3156) version 17:
+ 0.0 Kb 'INFO' Page information.
+ 17.3 Kb 'Sjbz' JB2 foreground mask (2325x3156)
+ 2.5 Kb 'BG44' IW44 background (775x1052)
+ 1.0 Kb 'FG44' IW44 foreground colors (194x263)
+ 3.0 Kb 'BG44' IW44 background (part 2).
+ 0.9 Kb 'BG44' IW44 background (part 3).
+ 7.1 Kb 'BG44' IW44 background (part 4).
+ Compression ratio: 676 (31.8 Kb)
+ \end{verbatim} */
+ GUTF8String get_long_description() const;
+ /** Returns pointer to \Ref{DjVuFile} which contains this image in
+ compressed form. */
+ GP<DjVuFile> get_djvu_file(void) const;
+ /// Write out a DjVuXML object tag and map tag.
+ void writeXML(ByteStream &str_out,const GURL &doc_url, const int flags=0) const;
+ /// Write out a DjVuXML object tag and map tag.
+ void writeXML(ByteStream &str_out) const;
+ /// Get a DjVuXML object tag and map tag.
+ GUTF8String get_XML(const GURL &doc_url, const int flags=0) const;
+ /// Get a DjVuXML object tag and map tag.
+ GUTF8String get_XML(void) const;
+ //@}
+
+ // CHECKING
+ /** @name Checking for legal DjVu files. */
+ //@{
+ /** This function returns true if this object contains a well formed {\em
+ Photo DjVu Image}. Calling function #get_pixmap# on a well formed photo
+ image should always return a non zero value. Note that function
+ #get_pixmap# works as soon as sufficient information is present,
+ regardless of the fact that the image follows the rules or not. */
+ int is_legal_photo() const;
+ /** This function returns true if this object contains a well formed {\em
+ Bilevel DjVu Image}. Calling function #get_bitmap# on a well formed
+ bilevel image should always return a non zero value. Note that function
+ #get_bitmap# works as soon as a foreground mask component is present,
+ regardless of the fact that the image follows the rules or not. */
+ int is_legal_bilevel() const;
+ /** This function returns true if this object contains a well formed {\em
+ Compound DjVu Image}. Calling function #get_bitmap# or #get_pixmap# on
+ a well formed compound DjVu image should always return a non zero value.
+ Note that functions #get_bitmap# or #get_pixmap# works as soon as
+ sufficient information is present, regardless of the fact that the image
+ follows the rules or not. */
+ int is_legal_compound() const;
+ //@}
+
+ // RENDERING
+ /** @name Rendering.
+ All these functions take two rectangles as argument. Conceptually,
+ these function first render the whole image into a rectangular area
+ defined by rectangle #all#. The relation between this rectangle and the
+ image size define the appropriate scaling. The rendering function then
+ extract the subrectangle #rect# and return the corresponding pixels as a
+ #GPixmap# or #GBitmap# object. The #all# and #rect# should take the any
+ rotation in to effect, The actual implementation performs these
+ two operation simultaneously for obvious efficiency reasons. The best
+ rendering speed is achieved by making sure that the size of rectangle
+ #all# and the size of the DjVu image are related by an integer ratio. */
+ //@{
+ /** Renders the image and returns a color pixel image. Rectangles #rect#
+ and #all# are used as explained above. Color correction is performed
+ according to argument #gamma#, which represents the gamma coefficient of
+ the display device on which the pixmap will be rendered. The default
+ value, zero, means that no color correction should be performed.
+ This function returns a null pointer if there is not enough information
+ in the DjVu image to properly render the desired image. */
+ GP<GPixmap> get_pixmap(const GRect &rect, const GRect &all, double gamma=0) const;
+ /** Renders the mask of the foreground layer of the DjVu image. This
+ functions is a wrapper for \Ref{JB2Image::get_bitmap}. Argument #align#
+ specified the alignment of the rows of the returned images. Setting
+ #align# to #4#, for instance, will adjust the bitmap border in order to
+ make sure that each row of the returned image starts on a word (four
+ byte) boundary. This function returns a null pointer if there is not
+ enough information in the DjVu image to properly render the desired
+ image. */
+ GP<GBitmap> get_bitmap(const GRect &rect, const GRect &all, int align = 1) const;
+ /** Renders the background layer of the DjVu image. Rectangles #rect# and
+ #all# are used as explained above. Color correction is performed
+ according to argument #gamma#, which represents the gamma coefficient of
+ the display device on which the pixmap will be rendered. The default
+ value, zero, means that no color correction should be performed. This
+ function returns a null pointer if there is not enough information in
+ the DjVu image to properly render the desired image. */
+ GP<GPixmap> get_bg_pixmap(const GRect &rect, const GRect &all, double gamma=0) const;
+ /** Renders the foreground layer of the DjVu image. Rectangles #rect# and
+ #all# are used as explained above. Color correction is performed
+ according to argument #gamma#, which represents the gamma coefficient of
+ the display device on which the pixmap will be rendered. The default
+ value, zero, means that no color correction should be performed. This
+ function returns a null pointer if there is not enough information in
+ the DjVu image to properly render the desired image. */
+ GP<GPixmap> get_fg_pixmap(const GRect &rect, const GRect &all, double gamma=0) const;
+
+
+ /** set the rotation count(angle) in counter clock wise for the image
+ values (0,1,2,3) correspond to (0,90,180,270) degree rotation*/
+ void set_rotate(int count=0);
+ /** returns the rotation count*/
+ int get_rotate() const;
+ /** returns decoded annotations in DjVuAnno object in which all hyperlinks
+ and hilighted areas are rotated as per rotation setting*/
+ GP<DjVuAnno> get_decoded_anno();
+ /** maps the given #rect# from rotated co-ordinates to unrotated document
+ co-ordinates*/
+ void map(GRect &rect) const;
+ /** unmaps the given #rect# from unrotated document co-ordinates to rotated
+ co-ordinates*/
+ void unmap(GRect &rect) const;
+ /** maps the given #x#, #y# from rotated co-ordinates to unrotated document
+ co-ordinates*/
+ void map(int &x, int &y) const;
+ /** unmaps the given #x#, #y# from unrotated document co-ordinates to rotated
+ co-ordinates*/
+ void unmap(int &x, int &y) const;
+
+
+
+ //@}
+
+ // Inherited from DjVuPort.
+ virtual void notify_chunk_done(const DjVuPort *, const GUTF8String &name);
+
+ // SUPERSEDED
+ GP<GPixmap> get_pixmap(const GRect &rect, int subs=1, double gamma=0) const;
+ GP<GBitmap> get_bitmap(const GRect &rect, int subs=1, int align = 1) const;
+ GP<GPixmap> get_bg_pixmap(const GRect &rect, int subs=1, double gamma=0) const;
+ GP<GPixmap> get_fg_pixmap(const GRect &rect, int subs=1, double gamma=0) const;
+private:
+ GP<DjVuFile> file;
+ int rotate_count;
+ bool relayout_sent;
+
+ // HELPERS
+ int stencil(GPixmap *pm, const GRect &rect, int subs, double gcorr) const;
+ GP<DjVuInfo> get_info(const GP<DjVuFile> & file) const;
+ GP<IW44Image> get_bg44(const GP<DjVuFile> & file) const;
+ GP<GPixmap> get_bgpm(const GP<DjVuFile> & file) const;
+ GP<JB2Image> get_fgjb(const GP<DjVuFile> & file) const;
+ GP<GPixmap> get_fgpm(const GP<DjVuFile> & file) const;
+ GP<DjVuPalette> get_fgbc(const GP<DjVuFile> & file) const;
+ void init_rotate(const DjVuInfo &info);
+};
+
+
+inline GP<DjVuFile>
+DjVuImage::get_djvu_file(void) const
+{
+ return file;
+}
+
+//@}
+
+
+
+// ----- THE END
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuInfo.cpp b/kviewshell/plugins/djvu/libdjvu/DjVuInfo.cpp
new file mode 100644
index 00000000..13ae6480
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuInfo.cpp
@@ -0,0 +1,205 @@
+//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: DjVuInfo.cpp,v 1.9 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "DjVuInfo.h"
+#include "GException.h"
+#include "ByteStream.h"
+#include "GString.h"
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+// ----------------------------------------
+// CLASS DJVUINFO
+
+
+#define STRINGIFY(x) STRINGIFY_(x)
+#define STRINGIFY_(x) #x
+
+
+DjVuInfo::DjVuInfo()
+ : width(0), height(0),
+#ifdef DJVUVERSION_FOR_OUTPUT
+ version(DJVUVERSION_FOR_OUTPUT),
+#else
+ version(DJVUVERSION),
+#endif
+ dpi(300), gamma(2.2), compressable(false), orientation(GRect::BULRNR)
+{
+}
+
+void
+DjVuInfo::decode(ByteStream &bs)
+{
+ // Set to default values
+ width = 0;
+ height = 0;
+ version = DJVUVERSION;
+ dpi = 300;
+ gamma = 2.2;
+ compressable=false;
+ orientation=GRect::BULRNR;
+ // Read data
+ unsigned char buffer[10];
+ int size = bs.readall((void*)buffer, sizeof(buffer));
+ if (size == 0)
+ G_THROW( ByteStream::EndOfFile );
+ if (size < 5)
+ G_THROW( ERR_MSG("DjVuInfo.corrupt_file") );
+ // Analyze data with backward compatibility in mind!
+ if (size>=2)
+ width = (buffer[0]<<8) + buffer[1];
+ if (size>=4)
+ height = (buffer[2]<<8) + buffer[3];
+ if (size>=5)
+ version = buffer[4];
+ if (size>=6 && buffer[5]!=0xff)
+ version = (buffer[5]<<8) + buffer[4];
+ if (size>=8 && buffer[7]!=0xff)
+ dpi = (buffer[7]<<8) + buffer[6];
+ if (size>=9)
+ gamma = 0.1 * buffer[8];
+ int flags=0;
+ if (size>=10)
+ flags = buffer[9];
+ // Fixup
+ if (gamma<0.3)
+ gamma=0.3;
+ if (gamma>5.0)
+ gamma=5.0;
+ if (dpi < 25 || dpi > 6000)
+ dpi = 300;
+ if(flags&COMPRESSABLE_FLAG)
+ compressable=true;
+ if(version>=DJVUVERSION_ORIENTATION)
+ {
+ orientation=(GRect::Orientations)(flags&((int)GRect::BOTTOM_UP|(int)GRect::MIRROR|(int)GRect::ROTATE90_CW));
+ }
+}
+
+void
+DjVuInfo::encode(ByteStream &bs)
+{
+ bs.write16(width);
+ bs.write16(height);
+ bs.write8(version & 0xff);
+ bs.write8(version >> 8);
+ bs.write8(dpi & 0xff);
+ bs.write8(dpi >> 8);
+ bs.write8((int)(10.0*gamma+0.5) );
+ unsigned char flags=orientation;
+ if(compressable)
+ {
+ flags|=COMPRESSABLE_FLAG;
+ }
+ bs.write8(flags);
+}
+
+unsigned int
+DjVuInfo::get_memory_usage() const
+{
+ return sizeof(DjVuInfo);
+}
+
+GUTF8String
+DjVuInfo::get_paramtags(void) const
+{
+ const int angle=GRect::findangle(orientation);
+ GUTF8String retval;
+ if(angle)
+ {
+ retval+="<PARAM name=\"ROTATE\" value=\""+GUTF8String(angle)+"\" />\n";
+ }
+ if(orientation == GRect::rotate(angle,GRect::TDLRNR))
+ {
+ retval+="<PARAM name=\"VFLIP\" value=\"true\" />\n";
+ }
+ if(dpi)
+ {
+ retval+="<PARAM name=\"DPI\" value=\""+GUTF8String(dpi)+"\" />\n";
+ }
+ if(gamma)
+ {
+ retval+="<PARAM name=\"GAMMA\" value=\""+GUTF8String(gamma)+"\" />\n";
+ }
+ return retval;
+}
+
+void
+DjVuInfo::writeParam(ByteStream &str_out) const
+{
+ str_out.writestring(get_paramtags());
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuInfo.h b/kviewshell/plugins/djvu/libdjvu/DjVuInfo.h
new file mode 100644
index 00000000..67a83be9
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuInfo.h
@@ -0,0 +1,193 @@
+//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: DjVuInfo.h,v 1.12 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _DJVUINFO_H
+#define _DJVUINFO_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+/** @name DjVuInfo.h
+ Each instance of class #DjVuInfo# represents the information
+ contained in the information chunk of a DjVu file. This #"INFO"#
+ chunk is always the first chunk of a DjVu file.
+ @memo
+ DjVu information chunk.
+ @author
+ L\'eon Bottou <leonb@research.att.com>
+ @version
+ #$Id: DjVuInfo.h,v 1.12 2003/11/07 22:08:21 leonb Exp $# */
+//@{
+
+
+
+#include "GSmartPointer.h"
+#include "GRect.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+class ByteStream;
+
+/** @name DjVu version constants
+ @memo DjVu file format version. */
+//@{
+/** Current DjVu format version. The value of this macro represents the
+ version of the DjVu file format implemented by this release of the DjVu
+ Reference Library. */
+#define DJVUVERSION 25
+/** DjVu format version. This is the value used in files produced
+ with DjVuLibre. This is smaller than DJVUVERSION because version
+ number inflation causes problems with older software.
+ */
+#define DJVUVERSION_FOR_OUTPUT 24
+/** This is the version which introduced orientations. */
+#define DJVUVERSION_ORIENTATION 22
+/** Oldest DjVu format version supported by this library. This release of the
+ library cannot completely decode DjVu files whose version field is less
+ than or equal to this number. */
+#define DJVUVERSION_TOO_OLD 15
+/** Newest DjVu format partially supported by this library. This release of
+ the library will attempt to decode files whose version field is smaller
+ than this macro. If the version field is greater than or equal to this
+ number, the decoder will just throw a \Ref{GException}. */
+#define DJVUVERSION_TOO_NEW 50
+//@}
+
+
+class GUTF8String;
+
+/** Information component.
+ Each instance of class #DjVuInfo# represents the information
+ contained in the information chunk of a DjVu file. This #"INFO"#
+ chunk is always the first chunk of a DjVu file.
+ */
+
+class DjVuInfo : public GPEnabled
+{
+protected:
+ DjVuInfo(void);
+public:
+ /** Creates an empty DjVuInfo object.
+ The #width# and #height# fields are set to zero.
+ All other fields are initialized with suitable default values. */
+ static GP<DjVuInfo> create(void) {return new DjVuInfo();}
+
+ /** Decodes the DjVu #"INFO"# chunk. This function reads binary data from
+ ByteStream #bs# and populates the fields of this DjVuInfo object. It is
+ normally called after detecting an #"INFO"# chunk header with function
+ \Ref{IFFByteStream::get_chunk}. */
+ void decode(ByteStream &bs);
+ /** Encodes the DjVu #"INFO"# chunk. This function writes the fields of this
+ DjVuInfo object into ByteStream #bs#. It is normally called after
+ creating an #"INFO"# chunk header with function
+ \Ref{IFFByteStream::put_chunk}. */
+ void encode(ByteStream &bs);
+ /** Returns the number of bytes used by this object. */
+ unsigned int get_memory_usage() const;
+ /** Width of the DjVu image (in pixels). */
+ int width;
+ /** Height of the DjVu image (in pixels). */
+ int height;
+ /** DjVu file version number. This number characterizes the file format
+ version used by the encoder to generate this DjVu image. A decoder
+ should compare this version number with the constants described in
+ section "\Ref{DjVu version constants}". */
+ int version;
+ /** Resolution of the DjVu image. The resolution is given in ``pixels per
+ 2.54 centimeters'' (this unit is sometimes called ``pixels per
+ inch''). Display programs can use this information to determine the
+ natural magnification to use for rendering a DjVu image. */
+ int dpi;
+ /** Gamma coefficient of the display for which the image was designed. The
+ rendering functions can use this information in order to perform color
+ correction for the intended display device. */
+ double gamma;
+ /** The following boolian values are stored in the last character of the
+ info structure. Unused bits are reserved for possible future extensions
+ and backwards compatability. */
+ bool compressable;
+ enum {COMPRESSABLE_FLAG=0x80,RESERVED_FLAGS1=0x7f};
+
+ /** We also store the current image orientation as three bits. */
+ GRect::Orientations orientation;
+
+ /// Obtain the flags for the default specifications.
+ GUTF8String get_paramtags(void) const;
+ /// Obtain the flags for the default specifications.
+ void writeParam(ByteStream &out_str) const;
+};
+
+
+//@}
+
+// ----- THE END
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuMessage.cpp b/kviewshell/plugins/djvu/libdjvu/DjVuMessage.cpp
new file mode 100644
index 00000000..e92b7570
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuMessage.cpp
@@ -0,0 +1,647 @@
+//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: DjVuMessage.cpp,v 1.16 2005/04/27 16:34:13 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+// From: Leon Bottou, 1/31/2002
+// All these XML messages are Lizardtech innovations.
+
+#include "DjVuMessage.h"
+#include "GOS.h"
+#include "XMLTags.h"
+#include "ByteStream.h"
+#include "GURL.h"
+#include "debug.h"
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#ifdef WIN32
+# include <tchar.h>
+# include <atlbase.h>
+# include <windows.h>
+# include <winreg.h>
+#endif
+#ifdef UNIX
+# include <unistd.h>
+# include <pwd.h>
+# include <sys/types.h>
+#endif
+#include <locale.h>
+#ifndef LC_MESSAGES
+# define LC_MESSAGES LC_ALL
+#endif
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+GUTF8String &
+DjVuMessage::programname(void)
+{
+ static GUTF8String xprogramname;
+ use_language();
+ return xprogramname;
+}
+
+static const char namestring[]="name";
+static const char srcstring[]="src";
+
+static const char *failed_to_parse_XML=ERR_MSG("DjVuMessage.failed_to_parse_XML");
+static const char bodystring[]="BODY";
+static const char languagestring[]="LANGUAGE";
+static const char headstring[]="HEAD";
+static const char includestring[]="INCLUDE";
+static const char messagestring[]="MESSAGE";
+static const char localestring[]="locale";
+
+
+// directory names for searching messages
+static const char opensourcedir[]="osi";
+#ifdef AUTOCONF
+static const char DjVuDataDir[] = DIR_DATADIR "/djvu";
+static const char ModuleDjVuDir[] ="share/djvu";
+#else /* !AUTOCONF */
+static const char ModuleDjVuDir[] ="profiles";
+#endif /* !AUTOCONF */
+static const char LocalDjVuDir[] =".DjVu"; // relative to ${HOME}
+#ifdef LT_DEFAULT_PREFIX
+static const char DjVuPrefixDir[] = LT_DEFAULT_PREFIX "/profiles";
+#endif
+#ifndef NDEBUG
+static const char DebugModuleDjVuDir[] ="../TOPDIR/SRCDIR/profiles";
+#endif
+#ifdef WIN32
+static const char RootDjVuDir[] ="C:/Program Files/LizardTech/Profiles";
+static const TCHAR registrypath[]= TEXT("Software\\LizardTech\\DjVu\\Profile Path");
+#else
+static const char RootDjVuDir[] ="/etc/DjVu/"; // global last resort
+#endif
+
+static const char DjVuEnv[] = "DJVU_CONFIG_DIR";
+
+// The name of the message file
+static const char MessageFile[]="messages.xml";
+static const char LanguageFile[]="languages.xml";
+
+#ifdef WIN32
+static GURL
+RegOpenReadConfig ( HKEY hParentKey )
+{
+ GURL retval;
+ // To do: This needs to be shared with SetProfile.cpp
+ LPCTSTR path = registrypath;
+
+ HKEY hKey = 0;
+ // MultiByteToWideChar(CP_ACP,MB_PRECOMPOSED,argv[1],strlen(argv[1])+1,wszSrcFile,sizeof(wszSrcFile));
+ if (RegOpenKeyEx(hParentKey, path, 0,
+ KEY_READ, &hKey) == ERROR_SUCCESS )
+ {
+ TCHAR path[1024];
+ // Success
+ TCHAR *szPathValue = path;
+ LPCTSTR lpszEntry = (LPCTSTR &)TEXT("");
+ DWORD dwCount = (sizeof(path)/sizeof(TCHAR))-1;
+ DWORD dwType;
+
+ LONG lResult = RegQueryValueEx(hKey, lpszEntry, NULL,
+ &dwType, (LPBYTE) szPathValue, &dwCount);
+
+ RegCloseKey(hKey);
+
+ if ((lResult == ERROR_SUCCESS))
+ {
+ szPathValue[dwCount] = 0;
+ USES_CONVERSION;
+ retval=GURL::Filename::Native(T2CA(path));
+ }
+ }
+// if (hKey) RegCloseKey(hKey);
+ return retval;
+}
+
+static GURL
+GetModulePath( void )
+{
+ const GUTF8String cwd(GOS::cwd());
+ TCHAR path[1024];
+ DWORD dwCount = (sizeof(path)/sizeof(TCHAR))-1;
+ GetModuleFileName(0, path, dwCount);
+ USES_CONVERSION;
+ GURL retval=GURL::Filename::Native(T2CA(path)).base();
+ GOS::cwd(cwd);
+ return retval;
+}
+#elif defined(UNIX)
+
+static GList<GURL>
+parsePATH(void)
+{
+ GList<GURL> retval;
+ const char *path=getenv("PATH");
+ if(path)
+ {
+ GNativeString p(path);
+ int from=0;
+ for(int to;(to=p.search(':',from))>0;from=to+1)
+ {
+ if(to > from)
+ {
+ retval.append(GURL::Filename::Native(p.substr(from,to-from)));
+ }
+ }
+ if((from+1)<(int)p.length())
+ {
+ retval.append(GURL::Filename::Native(p.substr(from,-1)));
+ }
+ }
+ return retval;
+}
+
+static GURL
+GetModulePath( void )
+{
+ GURL retval;
+ GUTF8String &xprogramname=DjVuMessage::programname();
+ if(xprogramname.length())
+ {
+ if(xprogramname[1]=='/'
+ ||!xprogramname.cmp("../",3)
+ ||!xprogramname.cmp("./",2))
+ {
+ retval=GURL::Filename::UTF8(xprogramname);
+ }
+ if(retval.is_empty() || !retval.is_file())
+ {
+ GList<GURL> paths(parsePATH());
+ GMap<GUTF8String,void *> pathMAP;
+ for(GPosition pos=paths;pos;++pos)
+ {
+ retval=GURL::UTF8(xprogramname,paths[pos]);
+ const GUTF8String path(retval.get_string());
+ if(!pathMAP.contains(path))
+ {
+ if(retval.is_file())
+ break;
+ pathMAP[path]=0;
+ }
+ }
+ }
+ if (! retval.is_empty() )
+ retval = retval.follow_symlinks();
+ if (! retval.is_empty() )
+ retval = retval.base();
+ }
+ return retval;
+}
+#endif
+
+static void
+appendPath(const GURL &url,
+ GMap<GUTF8String,void *> &map,
+ GList<GURL> &list)
+{
+ if( !url.is_empty()
+ && !map.contains(url.get_string()) && url.is_dir() )
+ {
+ map[url.get_string()]=0;
+ list.append(url);
+ }
+}
+
+GList<GURL>
+DjVuMessage::GetProfilePaths(void)
+{
+ static bool first=true;
+ static GList<GURL> realpaths;
+ if(first)
+ {
+ first=false;
+ GMap<GUTF8String,void *> pathsmap;
+ GList<GURL> paths;
+ GURL path;
+ const GUTF8String envp(GOS::getenv(DjVuEnv));
+ if(envp.length())
+ appendPath(GURL::Filename::UTF8(envp),pathsmap,paths);
+#if defined(WIN32) || defined(UNIX)
+ GURL mpath(GetModulePath());
+ if(!mpath.is_empty() && mpath.is_dir())
+ {
+#if defined(UNIX) && !defined(AUTOCONF) && !defined(NDEBUG)
+ appendPath(GURL::UTF8(DebugModuleDjVuDir,mpath),pathsmap,paths);
+#endif
+ appendPath(mpath,pathsmap,paths);
+ mpath=mpath.base();
+ appendPath(GURL::UTF8(ModuleDjVuDir,mpath),pathsmap,paths);
+ mpath=mpath.base();
+ appendPath(GURL::UTF8(ModuleDjVuDir,mpath),pathsmap,paths);
+ }
+#endif
+#if defined(AUTOCONF)
+ GURL dpath = GURL::Filename::UTF8(DjVuDataDir);
+ appendPath(dpath,pathsmap,paths);
+#endif
+#ifdef WIN32
+ appendPath(RegOpenReadConfig(HKEY_CURRENT_USER),pathsmap,paths);
+ appendPath(RegOpenReadConfig(HKEY_LOCAL_MACHINE),pathsmap,paths);
+#else
+ GUTF8String home=GOS::getenv("HOME");
+# if HAVE_GETPWUID
+ if (! home.length()) {
+ struct passwd *pw=0;
+ if ((pw = getpwuid(getuid())))
+ home=GNativeString(pw->pw_dir);
+ }
+# endif
+ if (home.length()) {
+ GURL hpath = GURL::UTF8(LocalDjVuDir,GURL::Filename::UTF8(home));
+ appendPath(hpath,pathsmap,paths);
+ }
+#endif
+#ifdef LT_DEFAULT_PREFIX
+ appendPath(GURL::Filename::UTF8(DjVuPrefixDir),pathsmap,paths);
+#endif
+ appendPath(GURL::Filename::UTF8(RootDjVuDir),pathsmap,paths);
+ pathsmap.empty();
+
+ GPosition pos;
+ GList< GMap<GUTF8String,GP<lt_XMLTags> > > localemaps;
+ for(pos=paths;pos;++pos)
+ {
+ path=GURL::UTF8(LanguageFile,paths[pos]);
+ if(path.is_file())
+ {
+ const GP<lt_XMLTags> xml(lt_XMLTags::create(ByteStream::create(path,"rb")));
+ const GPList<lt_XMLTags> Body(xml->get_Tags(bodystring));
+ GPosition pos=Body;
+ if(!pos || (pos != Body.lastpos()))
+ {
+ G_THROW( ERR_MSG("XMLAnno.extra_body") );
+ }
+ const GP<lt_XMLTags> GBody(Body[pos]);
+ if(!GBody)
+ {
+ G_THROW( ERR_MSG("XMLAnno.no_body") );
+ }
+ GMap<GUTF8String,GP<lt_XMLTags> > localemap;
+ lt_XMLTags::get_Maps(languagestring,localestring,Body,localemap);
+ localemaps.append(localemap);
+ }
+ }
+ GList<GURL> localepaths;
+ GList<GURL> osilocalepaths;
+
+ // Need to do it the right way!
+ GUTF8String defaultlocale = getenv("LANGUAGE");
+ if (! defaultlocale)
+ {
+ const GUTF8String oldlocale(setlocale(LC_MESSAGES,0));
+ defaultlocale = setlocale(LC_MESSAGES,"");
+ setlocale(LC_MESSAGES,(const char *)oldlocale);
+ }
+ // Unfathomable search.
+ for(int loop=0; loop<2; loop++)
+ {
+ static const char sepchars[]=" _.@";
+ const char *p=sepchars+sizeof(sepchars)-1;
+ do
+ {
+ int sepcharpos=p[0]?defaultlocale.search(p[0]):defaultlocale.length();
+ if(sepcharpos > 0)
+ {
+ const GUTF8String sublocale(defaultlocale,sepcharpos);
+ const GUTF8String downcasesublocale("downcase^"+sublocale.downcase());
+ for(pos=localemaps;pos;++pos)
+ {
+ const GMap<GUTF8String,GP<lt_XMLTags> > &localemap=localemaps[pos];
+ GPosition pos=localemap.contains(sublocale);
+ if(!pos)
+ pos=localemap.contains(downcasesublocale);
+ if(pos)
+ {
+ const GMap<GUTF8String,GUTF8String>&args
+ = localemap[pos]->get_args();
+ pos = args.contains(srcstring);
+ if (pos)
+ {
+ const GUTF8String src(args[pos]);
+ for(pos=paths;pos;++pos)
+ {
+ path=GURL::UTF8(src,paths[pos]);
+ if(path.is_dir())
+ localepaths.append(path);
+ path=GURL::UTF8(GUTF8String(opensourcedir)+"/"+src,paths[pos]);
+ if(path.is_dir())
+ osilocalepaths.append(path);
+ }
+ }
+ // We don't need to check anymore language files.
+ p=sepchars;
+ break;
+ }
+ }
+ if(!pos)
+ {
+ for(pos=paths;pos;++pos)
+ {
+ path=GURL::UTF8(sublocale,paths[pos]);
+ if(path.is_dir())
+ {
+ localepaths.append(path);
+ }
+ path=GURL::UTF8(GUTF8String(opensourcedir)+"/"+sublocale,paths[pos]);
+ if(path.is_dir())
+ {
+ osilocalepaths.append(path);
+ }
+ }
+ }
+ }
+ } while(p-- != sepchars);
+ if((GPosition) localepaths)
+ break;
+ defaultlocale="C";
+ }
+ for(pos=localepaths;pos;++pos)
+ appendPath(localepaths[pos],pathsmap,realpaths);
+ for(pos=paths;pos;++pos)
+ appendPath(paths[pos],pathsmap,realpaths);
+ for(pos=osilocalepaths;pos;++pos)
+ appendPath(osilocalepaths[pos],pathsmap,realpaths);
+ for(pos=paths;pos;++pos)
+ {
+ path=GURL::UTF8(opensourcedir,paths[pos]);
+ appendPath(path,pathsmap,realpaths);
+ }
+ }
+ return realpaths;
+}
+
+static GUTF8String
+getbodies(
+ GList<GURL> &paths,
+ const GUTF8String &MessageFileName,
+ GPList<lt_XMLTags> &body,
+ GMap<GUTF8String, void *> & map )
+{
+ GUTF8String errors;
+ bool isdone=false;
+ GPosition firstpathpos=paths;
+ for(GPosition pathpos=firstpathpos;!isdone && pathpos;++pathpos)
+ {
+ const GURL::UTF8 url(MessageFileName,paths[pathpos]);
+ if(url.is_file())
+ {
+ map[MessageFileName]=0;
+ GP<lt_XMLTags> gtags;
+ {
+ GP<ByteStream> bs=ByteStream::create(url,"rb");
+ G_TRY
+ {
+ gtags=lt_XMLTags::create(bs);
+ }
+ G_CATCH(ex)
+ {
+ GUTF8String mesg(failed_to_parse_XML+("\t"+url.get_string()));
+ if(errors.length())
+ {
+ errors+="\n"+mesg;
+ }else
+ {
+ errors=mesg;
+ }
+ errors+="\n"+GUTF8String(ex.get_cause());
+ }
+ G_ENDCATCH;
+ }
+ if(gtags)
+ {
+ lt_XMLTags &tags=*gtags;
+ GPList<lt_XMLTags> Bodies=tags.get_Tags(bodystring);
+ if(! Bodies.isempty())
+ {
+ isdone=true;
+ for(GPosition pos=Bodies;pos;++pos)
+ {
+ body.append(Bodies[pos]);
+ }
+ }
+ GPList<lt_XMLTags> Head=tags.get_Tags(headstring);
+ if(! Head.isempty())
+ {
+ isdone=true;
+ GMap<GUTF8String, GP<lt_XMLTags> > includes;
+ lt_XMLTags::get_Maps(includestring,namestring,Head,includes);
+ for(GPosition pos=includes;pos;++pos)
+ {
+ const GUTF8String file=includes.key(pos);
+ if(! map.contains(file))
+ {
+ GList<GURL> xpaths;
+ xpaths.append(url.base());
+ const GUTF8String err2(getbodies(xpaths,file,body,map));
+ if(err2.length())
+ {
+ if(errors.length())
+ {
+ errors+="\n"+err2;
+ }else
+ {
+ errors=err2;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return errors;
+}
+
+static GUTF8String
+parse(GMap<GUTF8String,GP<lt_XMLTags> > &retval)
+{
+ GUTF8String errors;
+ GPList<lt_XMLTags> body;
+ {
+ GList<GURL> paths=DjVuMessage::GetProfilePaths();
+ GMap<GUTF8String, void *> map;
+ GUTF8String m(MessageFile);
+ errors=getbodies(paths,m,body,map);
+ }
+ if(! body.isempty())
+ {
+ lt_XMLTags::get_Maps(messagestring,namestring,body,retval);
+ }
+ return errors;
+}
+
+
+const DjVuMessageLite &
+DjVuMessage::create_full(void)
+{
+ GP<DjVuMessageLite> &static_message=getDjVuMessageLite();
+ if(!static_message)
+ {
+ DjVuMessage *mesg=new DjVuMessage;
+ static_message=mesg;
+ mesg->init();
+ }
+ return DjVuMessageLite::create_lite();
+}
+
+void
+DjVuMessage::set_programname(const GUTF8String &xprogramname)
+{
+ programname()=xprogramname;
+ DjVuMessageLite::create=create_full;
+}
+
+void
+DjVuMessage::use_language(void)
+{
+ DjVuMessageLite::create=create_full;
+}
+
+
+// Constructor
+DjVuMessage::DjVuMessage( void ) {}
+
+void
+DjVuMessage::init(void)
+{
+ errors=parse(Map);
+}
+
+// Destructor
+DjVuMessage::~DjVuMessage( )
+{
+}
+
+
+// A C function to perform a message lookup. Arguments are a buffer to receiv
+// translated message, a buffer size (bytes), and a message_list. The transla
+// result is returned in msg_buffer encoded in Native MBS encoding. In case
+// of error, msg_b empty (i.e., msg_buffer[0] == '\0').
+void
+DjVuMessageLookUpNative(
+ char *msg_buffer, const unsigned int buffer_size, const char *message)
+{
+ const GNativeString converted(DjVuMessage::LookUpNative( message ));
+ if( converted.length() >= buffer_size )
+ msg_buffer[0] = '\0';
+ else
+ strcpy( msg_buffer, converted );
+}
+
+// A C function to perform a message lookup. Arguments are a buffer to receiv
+// translated message, a buffer size (bytes), and a message_list. The transla
+// result is returned in msg_buffer encoded in UTF8 encoding. In case
+// of error, msg_b empty (i.e., msg_buffer[0] == '\0').
+void
+DjVuMessageLookUpUTF8(
+ char *msg_buffer, const unsigned int buffer_size, const char *message)
+{
+ const GUTF8String converted(DjVuMessage::LookUpUTF8( message ));
+ if( converted.length() >= buffer_size )
+ msg_buffer[0] = '\0';
+ else
+ strcpy( msg_buffer, converted );
+}
+
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+
+void
+DjVuFormatErrorUTF8( const char *fmt, ... )
+{
+ va_list args;
+ va_start(args, fmt);
+ const GUTF8String message(fmt,args);
+ DjVuWriteError( message );
+}
+
+void
+DjVuFormatErrorNative( const char *fmt, ... )
+{
+ va_list args;
+ va_start(args, fmt);
+ const GNativeString message(fmt,args);
+ DjVuWriteError( message );
+}
+
+const char *
+djvu_programname(const char *xprogramname)
+{
+ if(xprogramname)
+ DjVuMessage::programname()=GNativeString(xprogramname);
+ return DjVuMessage::programname();
+}
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuMessage.h b/kviewshell/plugins/djvu/libdjvu/DjVuMessage.h
new file mode 100644
index 00000000..2302be37
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuMessage.h
@@ -0,0 +1,135 @@
+//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: DjVuMessage.h,v 1.9 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+
+#ifndef __DJVU_MESSAGE_H__
+#define __DJVU_MESSAGE_H__
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+// From: Leon Bottou, 1/31/2002
+// All these I18N XML messages are Lizardtech innovations.
+// For DjvuLibre, I changed the path extraction logic
+// and added support for non I18N messages.
+
+
+#include "DjVuMessageLite.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+class GURL;
+
+class DjVuMessage : public DjVuMessageLite
+{
+protected:
+ void init(void);
+ DjVuMessage(void);
+
+public:
+ /// Use the locale info and find the XML files on disk.
+ static void use_language(void);
+
+ /// Set the program name used when searching for XML files on disk.
+ static void set_programname(const GUTF8String &programname);
+ static GUTF8String &programname(void);
+
+ /// creates this class specifically.
+ static const DjVuMessageLite &create_full(void);
+
+ /** Adds a byte stream to be parsed whenever the next DjVuMessage::create()
+ call is made. */
+ static void AddByteStreamLater(const GP<ByteStream> &bs)
+ { use_language(); DjVuMessageLite::AddByteStreamLater(bs); }
+
+ /** Destructor: Does any necessary cleanup. Actions depend on how the message
+ file is implemented. */
+ ~DjVuMessage();
+
+ //// Same as LookUp, but this is a static method.
+ static GUTF8String LookUpUTF8( const GUTF8String & MessageList )
+ { use_language();return DjVuMessageLite::LookUpUTF8(MessageList); }
+
+ /** Same as Lookup, but returns a multibyte character string in the
+ current locale. */
+ static GNativeString LookUpNative( const GUTF8String & MessageList )
+ { use_language();return DjVuMessageLite::LookUpNative(MessageList); }
+
+ /// This is a simple alias to the above class, but does an fprintf to stderr.
+ static void perror( const GUTF8String & MessageList )
+ { use_language();DjVuMessageLite::perror(MessageList); }
+
+ static GList<GURL> GetProfilePaths(void);
+};
+
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif /* __DJVU_MESSAGE_H__ */
+
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuMessageLite.cpp b/kviewshell/plugins/djvu/libdjvu/DjVuMessageLite.cpp
new file mode 100644
index 00000000..258b0649
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuMessageLite.cpp
@@ -0,0 +1,478 @@
+//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: DjVuMessageLite.cpp,v 1.13 2005/04/27 16:34:13 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+// From: Leon Bottou, 1/31/2002
+// All these I18N XML messages are Lizardtech innovations.
+// For DjvuLibre, I changed the path extraction logic
+// and added support for non I18N messages.
+
+#include "DjVuMessageLite.h"
+#include "GOS.h"
+#include "XMLTags.h"
+#include "ByteStream.h"
+#include "GURL.h"
+#include "debug.h"
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+// #include <stdio.h>
+#ifdef WIN32
+#include <tchar.h>
+#include <atlbase.h>
+#include <windows.h>
+#include <winreg.h>
+#endif
+#ifdef UNIX
+#include <unistd.h>
+#include <pwd.h>
+#include <sys/types.h>
+#endif
+#include <locale.h>
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+const DjVuMessageLite& (*DjVuMessageLite::create)(void) =
+ DjVuMessageLite::create_lite;
+
+static const char *failed_to_parse_XML=
+ ERR_MSG("DjVuMessage.failed_to_parse_XML");
+static const char *unrecognized=
+ ERR_MSG("DjVuMessage.Unrecognized");
+static const char *uparameter=
+ ERR_MSG("DjVuMessage.Parameter");
+#ifdef LIZARDTECH_1_800_NUMBER
+static const char unrecognized_default[] =
+ "** Unrecognized DjVu Message: [Contact LizardTech at "
+ LIZARDTECH_1_800_NUMBER " \n"
+ "\t** Message name: %1!s!";
+#else
+static const char unrecognized_default[] =
+ "** Unrecognized DjVu Message:\n"
+ "\t** Message name: %1!s!";
+#endif
+static const char uparameter_default[] =
+ "\t Parameter: %1!s!";
+static const char failed_to_parse_XML_default[]=
+ "Failed to parse XML message file:&#10;&#09;&apos;%1!s!&apos;.";
+
+static const char namestring[]="name";
+static const char valuestring[]="value";
+static const char numberstring[]="number";
+static const char bodystring[]="BODY";
+static const char messagestring[]="MESSAGE";
+
+GPList<ByteStream> &
+DjVuMessageLite::getByteStream(void)
+{
+ static GPList<ByteStream> gbs;
+ return gbs;
+}
+
+GP<DjVuMessageLite> &
+DjVuMessageLite::getDjVuMessageLite(void)
+{
+ static GP<DjVuMessageLite> message;
+ return message;
+}
+
+void
+DjVuMessageLite::AddByteStreamLater(const GP<ByteStream> &bs)
+{
+ getByteStream().append(bs);
+}
+
+// There is only object of class DjVuMessage in a program, and here it is:
+//DjVuMessage DjVuMsg;
+const DjVuMessageLite &
+DjVuMessageLite::create_lite(void)
+{
+ GP<DjVuMessageLite> &static_message=getDjVuMessageLite();
+ if(!static_message)
+ {
+ static_message=new DjVuMessageLite;
+ }
+ DjVuMessageLite &m=*static_message;
+ GPList<ByteStream> &bs = getByteStream();
+ for(GPosition pos;(pos=bs);bs.del(pos))
+ {
+ m.AddByteStream(bs[pos]);
+ }
+ return m;
+}
+
+// Constructor
+DjVuMessageLite::DjVuMessageLite( void ) {}
+
+// Destructor
+DjVuMessageLite::~DjVuMessageLite( ) {}
+
+
+void
+DjVuMessageLite::perror( const GUTF8String & MessageList )
+{
+ DjVuPrintErrorUTF8("%s\n",(const char *)DjVuMessageLite::LookUpUTF8(MessageList));
+}
+
+
+// Expands message lists by looking up the message IDs and inserting
+// arguments into the retrieved messages.
+// N.B. The resulting string may be encoded in UTF-8 format (ISO 10646-1 Annex R)
+// and SHOULD NOT BE ASSUMED TO BE ASCII.
+GUTF8String
+DjVuMessageLite::LookUp( const GUTF8String & MessageList ) const
+{
+// DEBUG_MSG( "========== DjVuMessageLite::LookUp ==========\n" <<
+// MessageList <<
+// "\n========== DjVuMessageLite::LookUp ==========\n" );
+ GUTF8String result; // Result string; begins empty
+ if(errors.length())
+ {
+ const GUTF8String err1(errors);
+ (const_cast<GUTF8String &>(errors)).empty();
+ result=LookUp(err1)+"\n";
+ }
+
+ int start = 0; // Beginning of next message
+ int end = MessageList.length(); // End of the message string
+
+ // Isolate single messages and process them
+ while( start < end )
+ {
+ if( MessageList[start] == '\n' )
+ {
+ result += MessageList[start++]; // move the newline to the result
+ // and advance to the next message
+ }
+ else
+ {
+ // Find the end of the next message and process it
+ int next_ending = MessageList.search((unsigned long)'\n', start);
+ if( next_ending < 0 )
+ next_ending = end;
+ result += LookUpSingle( MessageList.substr(start, next_ending-start) );
+ // Advance to the next message
+ start = next_ending;
+ }
+ }
+
+ // All done
+ return result;
+}
+
+
+// Expands a single message and inserts the arguments. Single_Message
+// contains no separators (newlines), but includes all the parameters
+// separated by tabs.
+GUTF8String
+DjVuMessageLite::LookUpSingle( const GUTF8String &Single_Message ) const
+{
+#if HAS_CTRL_C_IN_ERR_MSG
+ if (Single_Message[0] != '\003')
+ return Single_Message;
+#endif
+ // Isolate the message ID and get the corresponding message text
+ int ending_posn = Single_Message.contains("\t\v");
+ if( ending_posn < 0 )
+ ending_posn = Single_Message.length();
+ GUTF8String msg_text;
+ GUTF8String msg_number;
+ const GUTF8String message=Single_Message.substr(0,ending_posn);
+ LookUpID( message, msg_text, msg_number );
+
+ // Check whether we found anything
+ if( !msg_text.length())
+ {
+ if(message == unrecognized)
+ {
+ msg_text = unrecognized_default;
+ }else if(message == uparameter)
+ {
+ msg_text = uparameter_default;
+ }else if(message == failed_to_parse_XML)
+ {
+ msg_text = failed_to_parse_XML_default;
+ }else
+ {
+ return LookUpSingle(unrecognized + ("\t" + Single_Message));
+ }
+ }
+
+ // Insert the parameters (if any)
+ unsigned int param_num = 0;
+ while( (unsigned int)ending_posn < Single_Message.length() )
+ {
+ GUTF8String arg;
+ const int start_posn = ending_posn+1;
+ if(Single_Message[ending_posn] == '\v')
+ {
+ ending_posn=Single_Message.length();
+ arg=LookUpSingle(Single_Message.substr(start_posn,ending_posn));
+ }else
+ {
+ ending_posn = Single_Message.contains("\v\t",start_posn);
+ if( ending_posn < 0 )
+ ending_posn = Single_Message.length();
+ arg=Single_Message.substr(start_posn, ending_posn-start_posn);
+ }
+ InsertArg( msg_text, ++param_num, arg);
+ }
+ // Insert the message number
+ InsertArg( msg_text, 0, msg_number );
+
+ return msg_text;
+}
+
+
+// Looks up the msgID in the file of messages and returns a pointer to
+// the beginning of the translated message, if found; and an empty string
+// otherwise.
+void
+DjVuMessageLite::LookUpID( const GUTF8String &xmsgID,
+ GUTF8String &message_text,
+ GUTF8String &message_number ) const
+{
+ if(!Map.isempty())
+ {
+ GUTF8String msgID = xmsgID;
+#if HAS_CTRL_C_IN_ERR_MSG
+ int start = 0;
+ while (msgID[start] == '\003')
+ start ++;
+ if (start > 0)
+ msgID = msgID.substr(start, msgID.length() - start);
+#endif
+ GPosition pos=Map.contains(msgID);
+ if(pos)
+ {
+ const GP<lt_XMLTags> tag=Map[pos];
+ GPosition valuepos=tag->get_args().contains(valuestring);
+ if(valuepos)
+ {
+ message_text=tag->get_args()[valuepos];
+ }else
+ {
+ const GUTF8String raw(tag->get_raw());
+ const int start_line=raw.search((unsigned long)'\n',0);
+
+ const int start_text=raw.nextNonSpace(0);
+ const int end_text=raw.firstEndSpace(0);
+ if(start_line<0 || start_text<0 || start_text < start_line)
+ {
+ message_text=raw.substr(0,end_text).fromEscaped();
+ }else
+ {
+ message_text=raw.substr(start_line+1,end_text-start_line-1).fromEscaped();
+ }
+ }
+ GPosition numberpos=tag->get_args().contains(numberstring);
+ if(numberpos)
+ {
+ message_number=tag->get_args()[numberpos];
+ }
+ }
+ }
+}
+
+
+// Insert a string into the message text. Will insert into any field
+// description. Except for an ArgId of zero (message number), if the ArgId
+// is not found, the routine adds a line with the parameter so information
+// will not be lost.
+void
+DjVuMessageLite::InsertArg( GUTF8String &message,
+ const int ArgId, const GUTF8String &arg ) const
+{
+ // argument target string
+ const GUTF8String target= "%"+GUTF8String(ArgId)+"!";
+ // location of target string
+ int format_start = message.search( (const char *)target );
+ if( format_start >= 0 )
+ {
+ do
+ {
+ const int n=format_start+target.length()+1;
+ const int format_end=message.search((unsigned long)'!',n);
+ if(format_end > format_start)
+ {
+ const int len=1+format_end-n;
+ if(len && isascii(message[n-1]))
+ {
+ GUTF8String narg;
+ GUTF8String format="%"+message.substr(n-1,len);
+ switch(format[len])
+ {
+ case 'd':
+ case 'i':
+ narg.format((const char *)format,arg.toInt());
+ break;
+ case 'u':
+ case 'o':
+ case 'x':
+ case 'X':
+ narg.format((const char *)format,(unsigned int)arg.toInt());
+ break;
+ case 'f':
+ {
+ int endpos;
+ narg.format((const char *)format, arg.toDouble(0,endpos));
+ if( endpos < 0 )
+ narg = arg;
+ }
+ break;
+ default:
+ narg.format((const char *)format,(const char *)arg);
+ break;
+ }
+ message = message.substr( 0, format_start )+narg
+ +message.substr( format_end+1, -1 );
+ }else
+ {
+ message = message.substr( 0, format_start )+arg
+ +message.substr( format_end+1, -1 );
+ }
+ }
+ format_start=message.search((const char*)target, format_start+arg.length());
+ } while(format_start >= 0);
+ }
+ else
+ {
+ // Not found, fake it
+ if( ArgId != 0 )
+ {
+ message += "\n"+LookUpSingle(uparameter+("\t"+arg));
+ }
+ }
+}
+
+
+// A C function to perform a message lookup. Arguments are a buffer to received the
+// translated message, a buffer size (bytes), and a message_list. The translated
+// result is returned in msg_buffer encoded in UTF-8. In case of error, msg_buffer is
+// empty (i.e., msg_buffer[0] == '\0').
+void
+DjVuMessageLite_LookUp( char *msg_buffer, const unsigned int buffer_size, const char *message )
+{
+ GUTF8String converted = DjVuMessageLite::LookUpUTF8( message );
+ if( converted.length() >= buffer_size )
+ msg_buffer[0] = '\0';
+ else
+ strcpy( msg_buffer, converted );
+}
+
+void
+DjVuMessageLite::AddByteStream(const GP<ByteStream> &bs)
+{
+ const GP<lt_XMLTags> gtags(lt_XMLTags::create(bs));
+ lt_XMLTags &tags=*gtags;
+ GPList<lt_XMLTags> Bodies=tags.get_Tags(bodystring);
+ if(! Bodies.isempty())
+ {
+ lt_XMLTags::get_Maps(messagestring,namestring,Bodies,Map);
+ }
+}
+
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+
+void
+DjVuWriteError( const char *message )
+{
+ G_TRY {
+ GP<ByteStream> errout = ByteStream::get_stderr();
+ if (errout)
+ {
+ const GUTF8String external = DjVuMessageLite::LookUpUTF8( message );
+ errout->writestring(external+"\n");
+ }
+ // Need to catch all exceptions because these might be
+ // called from an outer exception handler (with prejudice)
+ } G_CATCH_ALL { } G_ENDCATCH;
+}
+
+void
+DjVuWriteMessage( const char *message )
+{
+ G_TRY {
+ GP<ByteStream> strout = ByteStream::get_stdout();
+ if (strout)
+ {
+ const GUTF8String external = DjVuMessageLite::LookUpUTF8( message );
+ strout->writestring(external+"\n");
+ }
+ // Need to catch all exceptions because these might be
+ // called from an outer exception handler (with prejudice)
+ } G_CATCH_ALL { } G_ENDCATCH;
+}
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuMessageLite.h b/kviewshell/plugins/djvu/libdjvu/DjVuMessageLite.h
new file mode 100644
index 00000000..f2e941cf
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuMessageLite.h
@@ -0,0 +1,227 @@
+//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: DjVuMessageLite.h,v 1.9 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef __DJVU_MESSAGE_LITE_H__
+#define __DJVU_MESSAGE_LITE_H__
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+// From: Leon Bottou, 1/31/2002
+// All these I18N XML messages are Lizardtech innovations.
+// For DjvuLibre, I changed the path extraction logic
+// and added support for non I18N messages.
+
+
+#include "GString.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+class lt_XMLTags;
+class ByteStream;
+
+/** Exception causes and external messages are passed as message lists which
+ have the following syntax:
+
+ message_list ::= single_message |
+ single_message separator message_list
+
+ separator ::= newline |
+ newline | separator
+
+ single_message ::= message_ID |
+ message_ID parameters
+
+ parameters ::= tab string |
+ tab string parameters
+
+ Message_IDs are looked up an external file and replaced by the message
+ text strings they are mapped to. The message text may contain the
+ following:
+
+ Parameter specifications: These are modelled after printf format
+ specifications and have one of the following forms:
+
+ %n!s! %n!d! %n!i! %n!u! %n!x! %n!X!
+
+ where n is the parameter number. The parameter number is indicated
+ explicitly to allow for the possibility that the parameter order may
+ change when the message text is translated into another language.
+ The final letter ('s', 'd', 'i', 'u', 'x', or 'X') indicates the form
+ of the parameter (string, integer, integer, unsigned integer, lowercase
+ hexadecimal, or uppercase hexadecimal, respectively). In addition
+ formating options such as precision available in sprintf, may be used.
+ So, to print the third argument as 5 digit unsigned number, with leading
+ zero's one could use:
+ %3!05u!
+
+ All of the arguments are actually strings. For forms that don't take
+ string input ('d', 'i', 'u', 'x', or 'X'), and atoi() conversion is done
+ on the string before formatting. In addition the form indicates to the
+ translater whether to expect a word or a number.
+
+ The strings are read in from XML. To to format the strings, use the
+ relavent XML escape sequences, such as follows:
+
+ &#10; [line feed]
+ &#09; [horizontal tab]
+ &apos; [single quote]
+ &#34; [double quote]
+ &lt; [less than sign]
+ &gt; [greater than sign]
+
+ After parameters have been inserted in the message text, the formatting
+ strings are replaced by their usual equivalents (newline and tab
+ respectively).
+
+ If a message_id cannot be found in the external file, a message text
+ is fabricated giving the message_id and the parameters (if any).
+
+ Separators (newlines) are preserved in the translated message list.
+
+ Expands message lists by looking up the message IDs and inserting
+ arguments into the retrieved messages.
+
+ N.B. The resulting string may be encoded in UTF-8 format (ISO 10646-1
+ Annex R) and SHOULD NOT BE ASSUMED TO BE ASCII.
+ */
+
+class DjVuMessageLite : public GPEnabled
+{
+protected:
+ // Constructor:
+ DjVuMessageLite( void );
+ GMap<GUTF8String,GP<lt_XMLTags> > Map;
+ GUTF8String errors;
+ /// Creates a DjVuMessage class.
+ static const DjVuMessageLite &real_create(void);
+
+public:
+ /// Creates a DjVuMessage class.
+ static const DjVuMessageLite& (*create)(void);
+
+ /// Creates this class specifically.
+ static const DjVuMessageLite &create_lite(void);
+
+ /** Adds a byte stream to be parsed whenever the next DjVuMessage::create()
+ call is made. */
+ static void AddByteStreamLater(const GP<ByteStream> &bs);
+
+ /** Destructor: Does any necessary cleanup. Actions depend on how the message
+ file is implemented. */
+ ~DjVuMessageLite();
+
+ /// Lookup the relavent string and parse the message.
+ GUTF8String LookUp( const GUTF8String & MessageList ) const;
+
+ //// Same as LookUp, but this is a static method.
+ static GUTF8String LookUpUTF8( const GUTF8String & MessageList )
+ { return create().LookUp(MessageList); }
+
+ /** Same as Lookup, but returns the a multibyte character string in the
+ current locale. */
+ static GNativeString LookUpNative( const GUTF8String & MessageList )
+ { return create().LookUp(MessageList).getUTF82Native(); }
+
+ /// This is a simple alias to the above class, but does an fprintf to stderr.
+ static void perror( const GUTF8String & MessageList );
+
+protected:
+
+ /* Looks up the msgID in the file of messages. The strings message_text
+ and message_number are returned if found. If not found, these strings
+ are empty. */
+ void LookUpID( const GUTF8String & msgID,
+ GUTF8String &message_text, GUTF8String &message_number ) const;
+
+ /* Expands a single message and inserts the arguments. Single_Message
+ contains no separators (newlines), but includes all the parameters
+ separated by tabs. */
+ GUTF8String LookUpSingle( const GUTF8String & Single_Message ) const;
+
+ /* Insert a string into the message text. Will insert into any field
+ description. Except for an ArgId of zero (message number), if the
+ #ArgId# is not found, the routine adds a line with the parameter
+ so information will not be lost. */
+ void InsertArg(
+ GUTF8String &message, const int ArgId, const GUTF8String &arg ) const;
+
+ void AddByteStream(const GP<ByteStream> &bs);
+
+protected:
+ /* Static storage of the DjVuMessage class. */
+ static GP<DjVuMessageLite> &getDjVuMessageLite(void);
+ /* Static storage of the ByteStream list. */
+ static GPList<ByteStream> &getByteStream(void);
+};
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif /* __DJVU_MESSAGE_LITE_H__ */
+
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuNavDir.cpp b/kviewshell/plugins/djvu/libdjvu/DjVuNavDir.cpp
new file mode 100644
index 00000000..615041b0
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuNavDir.cpp
@@ -0,0 +1,237 @@
+//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: DjVuNavDir.cpp,v 1.8 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "DjVuNavDir.h"
+#include "debug.h"
+#include "GException.h"
+#include "GOS.h"
+#include "ByteStream.h"
+#include "GURL.h"
+#include <ctype.h>
+
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+
+DjVuNavDir::DjVuNavDir(const GURL &dirURL)
+{
+ if (!dirURL) G_THROW( ERR_MSG("DjVuNavDir.zero_dir") );
+ baseURL=dirURL.base();
+}
+
+DjVuNavDir::DjVuNavDir(ByteStream & str, const GURL &dirURL)
+{
+ if (!dirURL) G_THROW( ERR_MSG("DjVuNavDir.zero_dir") );
+
+ baseURL=GURL(dirURL).base();
+
+ decode(str);
+}
+
+void
+DjVuNavDir::decode(ByteStream & str)
+{
+ GCriticalSectionLock lk(&lock);
+
+ GList<GUTF8String> tmp_page2name;
+ int eof=0;
+ while(!eof)
+ {
+ char buffer[1024];
+ char * ptr;
+ for(ptr=buffer;ptr-buffer<1024;ptr++)
+ if ((eof=!str.read(ptr, 1)) || *ptr=='\n') break;
+ if (ptr-buffer==1024) G_THROW( ERR_MSG("DjVuNavDir.long_line") );
+ *ptr=0;
+ if (!strlen(buffer)) continue;
+
+ if (!tmp_page2name.contains(buffer))
+ tmp_page2name.append(buffer);
+ };
+
+ // Now copying lists to arrays for faster access later
+ int pages=tmp_page2name.size();
+ page2name.resize(pages-1);
+
+ int cnt;
+ GPosition pos;
+ for(pos=tmp_page2name, cnt=0;pos;++pos, cnt++)
+ page2name[cnt]=tmp_page2name[pos];
+
+ // Now creating reverse mapping (strings => numbers)
+ for(cnt=0;cnt<pages;cnt++)
+ {
+ name2page[page2name[cnt]]=cnt;
+ url2page[GURL::UTF8(page2name[cnt],baseURL)]=cnt;
+ }
+}
+
+#ifndef NEED_DECODER_ONLY
+void
+DjVuNavDir::encode(ByteStream & str)
+{
+ GCriticalSectionLock lk(&lock);
+
+ for(int i=0;i<page2name.size();i++)
+ {
+ GUTF8String & name=page2name[i];
+ str.writall((const char*)name, name.length());
+ str.writall("\n", 1);
+ };
+}
+#endif //NEED_DECODER_ONLY
+
+int
+DjVuNavDir::get_pages_num(void) const
+{
+ GCriticalSectionLock lk((GCriticalSection *)&lock);
+
+ return page2name.size();
+}
+
+int
+DjVuNavDir::name_to_page(const char * name) const
+{
+ GCriticalSectionLock lk((GCriticalSection *)&lock);
+
+ if (!name2page.contains(name)) return -1;
+ return name2page[name];
+}
+
+int
+DjVuNavDir::url_to_page(const GURL & url) const
+{
+ GCriticalSectionLock lk((GCriticalSection *)&lock);
+
+ if (!url2page.contains(url)) return -1;
+ return url2page[url];
+}
+
+GUTF8String
+DjVuNavDir::page_to_name(int page) const
+{
+ GCriticalSectionLock lk((GCriticalSection *)&lock);
+
+ if (page<0)
+ G_THROW( ERR_MSG("DjVuNavDir.neg_page") );
+ if (page>=page2name.size())
+ G_THROW( ERR_MSG("DjVuNavDir.large_page") );
+ return page2name[page];
+}
+
+GURL
+DjVuNavDir::page_to_url(int page) const
+{
+ GCriticalSectionLock lk((GCriticalSection *)&lock);
+
+ return GURL::UTF8(page_to_name(page),baseURL);
+}
+
+void
+DjVuNavDir::insert_page(int where, const char * name)
+{
+ GCriticalSectionLock lk((GCriticalSection *)&lock);
+
+ int pages=page2name.size();
+ if (where<0) where=pages;
+
+ page2name.resize(pages);
+ for(int i=pages;i>where;i--)
+ page2name[i]=page2name[i-1];
+ page2name[where]=name;
+ name2page[name]=where;
+ url2page[GURL::UTF8(name,baseURL)]=where;
+}
+
+#ifndef NEED_DECODER_ONLY
+void
+DjVuNavDir::delete_page(int page_num)
+{
+ GCriticalSectionLock lk((GCriticalSection *)&lock);
+
+ int pages=page2name.size();
+
+ if (page_num<0 || page_num>=pages)
+ G_THROW( ERR_MSG("DjVuNavDir.bad_page") );
+
+ for(int i=page_num;i<pages-1;i++)
+ page2name[i]=page2name[i+1];
+ page2name.resize(--pages-1);
+}
+#endif
+
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuNavDir.h b/kviewshell/plugins/djvu/libdjvu/DjVuNavDir.h
new file mode 100644
index 00000000..90b2b8db
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuNavDir.h
@@ -0,0 +1,192 @@
+//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: DjVuNavDir.h,v 1.8 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _DJVUNAVDIR_H
+#define _DJVUNAVDIR_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+#include "GString.h"
+#include "GThreads.h"
+#include "GURL.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+class ByteStream;
+
+/** @name DjVuNavDir.h
+ Files #"DjVuNavDir.h"# and #"DjVuNavDir.cpp"# contain implementation of the
+ multipage DjVu navigation directory. This directory lists all the pages,
+ that a given document is composed of. The navigation (switching from page
+ to page in the plugin) is not possible before this directory is decoded.
+
+ Refer to the \Ref{DjVuNavDir} class description for greater details.
+
+ @memo DjVu Navigation Directory
+ @author Andrei Erofeev <eaf@geocities.com>
+ @version #$Id: DjVuNavDir.h,v 1.8 2003/11/07 22:08:21 leonb Exp $#
+*/
+
+//@{
+
+//*****************************************************************************
+//********************* Note: this class is thread-safe ***********************
+//*****************************************************************************
+
+/** DjVu Navigation Directory.
+
+ This class implements the {\em navigation directory} of a multipage
+ DjVu document - basically a list of pages that this document is composed
+ of. We would like to emphasize, that this is the list of namely
+ {\bf pages}, not {\bf files}. Any page may include any
+ number of additional files. When you've got an all-in-one-file multipage
+ DjVu document (DjVm archive) you may get the files list from \Ref{DjVmDir0}
+ class.
+
+ The \Ref{DjVuNavDir} class can decode and encode the navigation directory
+ from {\bf NDIR} IFF chunk. It's normally created by the library during
+ decoding procedure and can be accessed like any other component of
+ the \Ref{DjVuImage} being decoded.
+
+ In a typical multipage DjVu document the navigation directory is stored
+ in a separate IFF file containing only one chunk: {\bf NDIR} chunk.
+ This file should be included (by means of the {\bf INCL} chunk) into
+ every page of the document to enable the navigation. */
+class DjVuNavDir : public GPEnabled
+{
+private:
+ GCriticalSection lock;
+ GURL baseURL;
+ GArray<GUTF8String> page2name;
+ GMap<GUTF8String, int> name2page;
+ GMap<GURL, int> url2page;
+protected:
+ DjVuNavDir(const GURL &dir_url);
+ DjVuNavDir(ByteStream & str, const GURL &dir_url);
+
+public:
+ int get_memory_usage(void) const { return 1024; };
+
+ /** Creates a #DjVuNavDir# object. #dir_url# is the URL of the file
+ containing the directory source data. It will be used later
+ in translation by functions like \Ref{url_to_page}() and
+ \Ref{page_to_url}() */
+ static GP<DjVuNavDir> create(const GURL &dir_url)
+ {return new DjVuNavDir(dir_url);}
+
+ /** Creates #DjVuNavDir# object by decoding its contents from
+ the stream. #dir_url# is the URL of the file containing the
+ directory source data. */
+ static GP<DjVuNavDir> create(ByteStream & str, const GURL &dir_url)
+ { return new DjVuNavDir(str,dir_url); }
+
+ virtual ~DjVuNavDir(void) {};
+
+ /// Decodes the directory contents from the given \Ref{ByteStream}
+ void decode(ByteStream & str);
+
+ /// Encodes the directory contents into the given \Ref{ByteStream}
+ void encode(ByteStream & str);
+
+ /** Inserts a new page at position #where# pointing to a file
+ with name #name#.
+
+ @param where The position where the page should be inserted.
+ #-1# means to append.
+ @param name The name of the file corresponding to this page.
+ The name may not contain slashes. The file may include
+ other files. */
+ void insert_page(int where, const char * name);
+
+ /// Deletes page with number #page_num# from the directory.
+ void delete_page(int page_num);
+
+ /// Returns the number of pages in the directory.
+ int get_pages_num(void) const;
+ /** Converts the #url# to page number. Returns #-1# if the #url#
+ does not correspond to anything in the directory. */
+ int url_to_page(const GURL & url) const;
+ /** Converts file name #name# to page number. Returns #-1# if file
+ with given name cannot be found. */
+ int name_to_page(const char * name) const;
+ /** Converts given #page# to URL. Throws an exception if page number
+ is invalid. */
+ GURL page_to_url(int page) const;
+ /** Converts given #page# to URL. Throws an exception if page number
+ is invalid. */
+ GUTF8String page_to_name(int page) const;
+};
+
+//@}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuPalette.cpp b/kviewshell/plugins/djvu/libdjvu/DjVuPalette.cpp
new file mode 100644
index 00000000..4e49fe12
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuPalette.cpp
@@ -0,0 +1,590 @@
+//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: DjVuPalette.cpp,v 1.11 2004/03/18 15:03:50 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "GException.h"
+#include "ByteStream.h"
+#include "BSByteStream.h"
+#include "DjVuPalette.h"
+#include <stdlib.h>
+#include <math.h>
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+#define CUBEBITS 4
+#define CUBESIDE (1<<CUBEBITS)
+#define CUBESIZE (CUBESIDE*CUBESIDE*CUBESIDE)
+
+#define RMUL 5
+#define GMUL 9
+#define BMUL 2
+#define SMUL (RMUL+GMUL+BMUL)
+
+#define MAXPALETTESIZE 65535 // Limit for a 16 bit unsigned read.
+
+
+inline unsigned char
+umax(unsigned char a, unsigned char b)
+{ return (a>b) ? a : b; }
+
+inline unsigned char
+umin(unsigned char a, unsigned char b)
+{ return (a>b) ? b : a; }
+
+inline float
+fmin(float a, float b)
+{ return (a>b) ? b : a; }
+
+
+
+// ------- DJVUPALETTE
+
+
+DjVuPalette::DjVuPalette()
+ : mask(0), hist(0), pmap(0)
+{
+}
+
+DjVuPalette::~DjVuPalette()
+{
+ delete hist;
+ delete pmap;
+}
+
+DjVuPalette&
+DjVuPalette::operator=(const DjVuPalette &ref)
+{
+ if (this != &ref)
+ {
+ delete hist;
+ delete pmap;
+ mask = 0;
+ palette = ref.palette;
+ colordata = ref.colordata;
+ }
+ return *this;
+}
+
+DjVuPalette::DjVuPalette(const DjVuPalette &ref)
+ : mask(0), hist(0), pmap(0)
+{
+ this->operator=(ref);
+}
+
+
+
+// -------- HISTOGRAM ALLOCATION
+
+void
+DjVuPalette::allocate_hist()
+{
+ if (! hist)
+ {
+ hist = new GMap<int,int>;
+ mask = 0;
+ }
+ else
+ {
+ GMap<int,int> *old = hist;
+ hist = new GMap<int,int>;
+ mask = (mask<<1)|(0x010101);
+ for (GPosition p = *old; p; ++p)
+ {
+ int k = old->key(p);
+ int w = (*old)[p];
+ (*hist)[k | mask] += w;
+ }
+ delete old;
+ }
+}
+
+
+// -------- PALETTE COMPUTATION
+
+
+#ifndef NEED_DECODER_ONLY
+
+struct PData
+{
+ unsigned char p[3];
+ int w;
+};
+
+struct PBox
+{
+ PData *data;
+ int colors;
+ int boxsize;
+ int sum;
+};
+int
+DjVuPalette::bcomp (const void *a, const void *b)
+{
+ return ((PData*)a)->p[0] - ((PData*)b)->p[0];
+}
+
+int
+
+DjVuPalette::gcomp (const void *a, const void *b)
+{
+ return ((PData*)a)->p[1] - ((PData*)b)->p[1];
+}
+
+int
+DjVuPalette::rcomp (const void *a, const void *b)
+{
+ return ((PData*)a)->p[2] - ((PData*)b)->p[2];
+}
+
+int
+DjVuPalette::lcomp (const void *a, const void *b)
+{
+ unsigned char *aa = ((PColor*)a)->p;
+ unsigned char *bb = ((PColor*)b)->p;
+ if (aa[3] != bb[3])
+ return aa[3]-bb[3];
+ else if (aa[2] != bb[2])
+ return aa[2]-bb[2];
+ else if (aa[1] != bb[1])
+ return aa[1]=bb[1];
+ else
+ return aa[0]-bb[0];
+}
+
+int
+DjVuPalette::compute_palette(int maxcolors, int minboxsize)
+{
+ if (!hist)
+ G_THROW( ERR_MSG("DjVuPalette.no_color") );
+ if (maxcolors<1 || maxcolors>MAXPALETTESIZE)
+ G_THROW( ERR_MSG("DjVuPalette.many_colors") );
+
+ // Paul Heckbert: "Color Image Quantization for Frame Buffer Display",
+ // SIGGRAPH '82 Proceedings, page 297. (also in ppmquant)
+
+ // Collect histogram colors
+ int sum = 0;
+ int ncolors = 0;
+ GTArray<PData> pdata;
+ for (GPosition p = *hist; p; ++p)
+ {
+ pdata.touch(ncolors);
+ PData &data = pdata[ncolors++];
+ int k = hist->key(p);
+ data.p[0] = (k>>16) & 0xff;
+ data.p[1] = (k>>8) & 0xff;
+ data.p[2] = (k) & 0xff;
+ data.w = (*hist)[p];
+ sum += data.w;
+ }
+ // Create first box
+ GList<PBox> boxes;
+ PBox newbox;
+ newbox.data = pdata;
+ newbox.colors = ncolors;
+ newbox.boxsize = 256;
+ newbox.sum = sum;
+ boxes.append(newbox);
+ // Repeat spliting boxes
+ while (boxes.size() < maxcolors)
+ {
+ // Find suitable box
+ GPosition p;
+ for (p=boxes; p; ++p)
+ if (boxes[p].colors>=2 && boxes[p].boxsize>minboxsize)
+ break;
+ if (! p)
+ break;
+ // Find box boundaries
+ PBox &splitbox = boxes[p];
+ unsigned char pmax[3];
+ unsigned char pmin[3];
+ pmax[0] = pmin[0] = splitbox.data->p[0];
+ pmax[1] = pmin[1] = splitbox.data->p[1];
+ pmax[2] = pmin[2] = splitbox.data->p[2];
+ for (int j=1; j<splitbox.colors; j++)
+ {
+ pmax[0] = umax(pmax[0], splitbox.data[j].p[0]);
+ pmax[1] = umax(pmax[1], splitbox.data[j].p[1]);
+ pmax[2] = umax(pmax[2], splitbox.data[j].p[2]);
+ pmin[0] = umin(pmin[0], splitbox.data[j].p[0]);
+ pmin[1] = umin(pmin[1], splitbox.data[j].p[1]);
+ pmin[2] = umin(pmin[2], splitbox.data[j].p[2]);
+ }
+ // Determine split direction and sort
+ int bl = pmax[0]-pmin[0];
+ int gl = pmax[1]-pmin[1];
+ int rl = pmax[2]-pmin[2];
+ splitbox.boxsize = (bl>gl ? (rl>bl ? rl : bl) : (rl>gl ? rl : gl));
+ if (splitbox.boxsize <= minboxsize)
+ continue;
+ if (gl == splitbox.boxsize)
+ qsort(splitbox.data, splitbox.colors, sizeof(PData), gcomp);
+ else if (rl == splitbox.boxsize)
+ qsort(splitbox.data, splitbox.colors, sizeof(PData), rcomp);
+ else
+ qsort(splitbox.data, splitbox.colors, sizeof(PData), bcomp);
+ // Find median
+ int lowercolors = 0;
+ int lowersum = 0;
+ while (lowercolors<splitbox.colors-1 && lowersum+lowersum<splitbox.sum)
+ lowersum += splitbox.data[lowercolors++].w;
+ // Compute new boxes
+ newbox.data = splitbox.data + lowercolors;
+ newbox.colors = splitbox.colors - lowercolors;
+ newbox.sum = splitbox.sum - lowersum;
+ splitbox.colors = lowercolors;
+ splitbox.sum = lowersum;
+ // Insert boxes at proper location
+ GPosition q;
+ for (q=p; q; ++q)
+ if (boxes[q].sum < newbox.sum)
+ break;
+ boxes.insert_before(q, newbox);
+ for (q=p; q; ++q)
+ if (boxes[q].sum < splitbox.sum)
+ break;
+ boxes.insert_before(q, boxes, p);
+ }
+ // Fill palette array
+ ncolors = 0;
+ palette.empty();
+ palette.resize(0,boxes.size()-1);
+ for (GPosition p=boxes; p; ++p)
+ {
+ PBox &box = boxes[p];
+ // Compute box representative color
+ float bsum = 0;
+ float gsum = 0;
+ float rsum = 0;
+ for (int j=0; j<box.colors; j++)
+ {
+ float w = (float)box.data[j].w;
+ bsum += box.data[j].p[0] * w;
+ gsum += box.data[j].p[1] * w;
+ rsum += box.data[j].p[2] * w;
+ }
+ PColor &color = palette[ncolors++];
+ color.p[0] = (unsigned char) fmin(255, bsum/box.sum);
+ color.p[1] = (unsigned char) fmin(255, gsum/box.sum);
+ color.p[2] = (unsigned char) fmin(255, rsum/box.sum);
+ color.p[3] = ( color.p[0]*BMUL + color.p[1]*GMUL + color.p[2]*RMUL) / SMUL;
+ }
+ // Save dominant color
+ PColor dcolor = palette[0];
+ // Sort palette colors in luminance order
+ qsort((PColor*)palette, ncolors, sizeof(PColor), lcomp);
+ // Clear invalid data
+ colordata.empty();
+ delete pmap;
+ pmap = 0;
+ // Return dominant color
+ return color_to_index_slow(dcolor.p);
+}
+
+
+
+int
+DjVuPalette::compute_pixmap_palette(const GPixmap &pm, int ncolors, int minboxsize)
+{
+ // Prepare histogram
+ histogram_clear();
+ for (int j=0; j<(int)pm.rows(); j++)
+ {
+ const GPixel *p = pm[j];
+ for (int i=0; i<(int)pm.columns(); i++)
+ histogram_add(p[i], 1);
+ }
+ // Compute palette
+ return compute_palette(ncolors, minboxsize);
+}
+
+
+#endif
+
+
+
+
+// -------- QUANTIZATION
+
+
+void
+DjVuPalette::allocate_pmap()
+{
+ if (! pmap)
+ pmap = new GMap<int,int>;
+}
+
+int
+DjVuPalette::color_to_index_slow(const unsigned char *bgr)
+{
+ PColor *pal = palette;
+ const int ncolors = palette.size();
+ if (! ncolors)
+ G_THROW( ERR_MSG("DjVuPalette.not_init") );
+ // Should be able to do better
+ int found = 0;
+ int founddist = 3*256*256;
+ for (int i=0; i<ncolors; i++)
+ {
+ int bd = bgr[0] - pal[i].p[0];
+ int gd = bgr[1] - pal[i].p[1];
+ int rd = bgr[2] - pal[i].p[2];
+ int dist = (bd*bd)+(gd*gd)+(rd*rd);
+ if (dist < founddist)
+ {
+ found = i;
+ founddist = dist;
+ }
+ }
+ // Store in pmap
+ if (pmap && pmap->size()<0x8000)
+ {
+ int key = (bgr[0]<<16)|(bgr[1]<<8)|(bgr[2]);
+ (*pmap)[key] = found;
+ }
+ // Return
+ return found;
+}
+
+
+#ifndef NEED_DECODER_ONLY
+
+void
+DjVuPalette::quantize(GPixmap &pm)
+{
+ for (int j=0; j<(int)pm.rows(); j++)
+ {
+ GPixel *p = pm[j];
+ for (int i=0; i<(int)pm.columns(); i++)
+ index_to_color(color_to_index(p[i]), p[i]);
+ }
+}
+
+int
+DjVuPalette::compute_palette_and_quantize(GPixmap &pm, int maxcolors, int minboxsize)
+{
+ int result = compute_pixmap_palette(pm, maxcolors, minboxsize);
+ quantize(pm);
+ return result;
+}
+
+void
+DjVuPalette::color_correct(double corr)
+{
+ const int palettesize = palette.size();
+ if (palettesize > 0)
+ {
+ // Copy colors
+ int i;
+ GTArray<GPixel> pix(0,palettesize-1);
+ GPixel *r = pix;
+ PColor *q = palette;
+ for (i=0; i<palettesize; i++)
+ {
+ r[i].b = q[i].p[0];
+ r[i].g = q[i].p[1];
+ r[i].r = q[i].p[2];
+ }
+ // Apply color correction
+ GPixmap::color_correct(corr, r, palettesize);
+ // Restore colors
+ for (i=0; i<palettesize; i++)
+ {
+ q[i].p[0] = r[i].b;
+ q[i].p[1] = r[i].g;
+ q[i].p[2] = r[i].r;
+ }
+ }
+}
+
+#endif
+
+
+// -------- ENCODE AND DECODE
+
+#define DJVUPALETTEVERSION 0
+
+void
+DjVuPalette::encode_rgb_entries(ByteStream &bs) const
+{
+ const int palettesize = palette.size();
+ for (int c=0; c<palettesize; c++)
+ {
+ unsigned char p[3];
+ p[2] = palette[c].p[0];
+ p[1] = palette[c].p[1];
+ p[0] = palette[c].p[2];
+ bs.writall((const void*)p, 3);
+ }
+}
+
+void
+DjVuPalette::encode(GP<ByteStream> gbs) const
+{
+ ByteStream &bs=*gbs;
+ const int palettesize = palette.size();
+ const int datasize = colordata.size();
+ // Code version number
+ int version = DJVUPALETTEVERSION;
+ if (datasize>0) version |= 0x80;
+ bs.write8(version);
+ // Code palette
+ bs.write16(palettesize);
+ for (int c=0; c<palettesize; c++)
+ {
+ unsigned char p[3];
+ p[0] = palette[c].p[0];
+ p[1] = palette[c].p[1];
+ p[2] = palette[c].p[2];
+ bs.writall((const void*)p, 3);
+ }
+ // Code colordata
+ if (datasize > 0)
+ {
+ bs.write24(datasize);
+ GP<ByteStream> gbsb=BSByteStream::create(gbs, 50);
+ ByteStream &bsb=*gbsb;
+ for (int d=0; d<datasize; d++)
+ bsb.write16(colordata[d]);
+ }
+}
+
+void
+DjVuPalette::decode_rgb_entries(ByteStream &bs, const int palettesize)
+{
+ palette.resize(0,palettesize-1);
+ for (int c=0; c<palettesize; c++)
+ {
+ unsigned char p[3];
+ bs.readall((void*)p, 3);
+ palette[c].p[0] = p[2];
+ palette[c].p[1] = p[1];
+ palette[c].p[2] = p[0];
+ palette[c].p[3] = (p[0]*BMUL+p[1]*GMUL+p[2]*RMUL)/SMUL;
+ }
+}
+
+void
+DjVuPalette::decode(GP<ByteStream> gbs)
+{
+ ByteStream &bs=*gbs;
+ // Make sure that everything is clear
+ delete hist;
+ delete pmap;
+ hist = 0;
+ pmap = 0;
+ mask = 0;
+ // Code version
+ int version = bs.read8();
+ if ( (version & 0x7f) != DJVUPALETTEVERSION)
+ G_THROW( ERR_MSG("DjVuPalette.bad_version") );
+ // Code palette
+ const int palettesize = bs.read16();
+ if (palettesize<0 || palettesize>MAXPALETTESIZE)
+ G_THROW( ERR_MSG("DjVuPalette.bad_palette") );
+ palette.resize(0,palettesize-1);
+ for (int c=0; c<palettesize; c++)
+ {
+ unsigned char p[3];
+ bs.readall((void*)p, 3);
+ palette[c].p[0] = p[0];
+ palette[c].p[1] = p[1];
+ palette[c].p[2] = p[2];
+ palette[c].p[3] = (p[0]*BMUL+p[1]*GMUL+p[2]*RMUL)/SMUL;
+ }
+ // Code data
+ if (version & 0x80)
+ {
+ int datasize = bs.read24();
+ if (datasize<0)
+ G_THROW( ERR_MSG("DjVuPalette.bad_palette") );
+ colordata.resize(0,datasize-1);
+ GP<ByteStream> gbsb=BSByteStream::create(gbs);
+ ByteStream &bsb=*gbsb;
+ for (int d=0; d<datasize; d++)
+ {
+ short s = bsb.read16();
+ if (s<0 || s>=palettesize)
+ G_THROW( ERR_MSG("DjVuPalette.bad_palette") );
+ colordata[d] = s;
+ }
+ }
+}
+
+
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuPalette.h b/kviewshell/plugins/djvu/libdjvu/DjVuPalette.h
new file mode 100644
index 00000000..7f9884f1
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuPalette.h
@@ -0,0 +1,339 @@
+//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: DjVuPalette.h,v 1.9 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _DJVUPALETTE_H_
+#define _DJVUPALETTE_H_
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+#include "GContainer.h"
+#include "GPixmap.h"
+#include <string.h>
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+/** @name DjVuPalette.h
+ Files #"DjVuPalette.h"# and #"DjVuPalette.cpp"# implement a single class
+ \Ref{DjVuPalette} which provides facilities for computing optimal color
+ palettes, coding color palettes, and coding sequences of color indices.
+ @memo
+ DjVuPalette header file
+ @version
+ #$Id: DjVuPalette.h,v 1.9 2003/11/07 22:08:21 leonb Exp $#
+ @author:
+ L\'eon Bottou <leonb@research.att.com> */
+//@{
+
+
+/** Computing and coding color palettes and index arrays.
+ This class provides facilities for computing optimal color palettes,
+ coding color palettes, and coding sequences of color indices.
+
+ {\bf Creating a color palette} -- The recipe for creating a color palette
+ consists in (a) creating a DjVuPalette object, (b) constructing a color
+ histogram using \Ref{histogram_add}, and (c) calling function
+ \Ref{compute_palette}.
+
+ {\bf Accessing the color palette} -- Conversion between colors and color
+ palette indices is easily achieved with \Ref{color_to_index} and
+ \Ref{index_to_color}. There are also functions for computing a palette
+ and quantizing a complete pixmap.
+
+ {\bf Sequences of color indices} -- The DjVuPalette object also contains
+ an array \Ref{colordata} optionally containing a sequence of color
+ indices. This array will be encoded and decoded by functions \Ref{encode}
+ and \Ref{decode}. This feature simplifies the implementation of the ``one
+ color per symbol'' model in DjVu.
+
+ {\bf Coding color palettes and color indices} -- Two functions
+ \Ref{encode} and \Ref{decode} are provided for coding the color palette
+ and the array of color indices when appropriate. */
+#ifdef _WIN32_WCE_EMULATION // Work around odd behavior under WCE Emulation
+#define CALLINGCONVENTION __cdecl
+#else
+#define CALLINGCONVENTION /* */
+#endif
+
+class DjVuPalette : public GPEnabled
+{
+protected:
+ DjVuPalette(void);
+public:
+ /// Generic creator
+ static GP<DjVuPalette> create(void) {return new DjVuPalette();}
+
+ /// Non-virtual destructor
+ ~DjVuPalette();
+ // COPY
+ DjVuPalette(const DjVuPalette &ref);
+ DjVuPalette& operator=(const DjVuPalette &ref);
+ // PALETTE COMPUTATION
+ /** Resets the color histogram to zero. */
+ void histogram_clear();
+ /** Adds the color specified by #p# to the histogram.
+ Argument #weight# represent the number of pixels with this color. */
+ void histogram_add(const GPixel &p, int weight);
+ /** Adds the color specified by the triple #bgr# to the histogram.
+ Argument #weight# represent the number of pixels with this color. */
+ void histogram_add(const unsigned char *bgr, int weight);
+ /** Adds the color specified by the weighted triple #bgr# to the histogram.
+ Argument #weight# represent the number of pixels with this color. This
+ function will compute the actual color by dividing the elements of the
+ #bgr# array by #weight# and then use the unnormalized values to compute
+ the average color per bucket. This is all a way to avoid excessive loss
+ of accuracy. */
+ void histogram_norm_and_add(const int *bgr, int weight);
+ /** Computes an optimal palette for representing an image where colors
+ appear according to the histogram. Argument #maxcolors# is the maximum
+ number of colors allowed in the palette (up to 1024). Argument
+ #minboxsize# controls the minimal size of the color cube area affected
+ to a color palette entry. Returns the index of the dominant color. */
+ int compute_palette(int maxcolors, int minboxsize=0);
+ /** Computes the optimal palette for pixmap #pm#. This function builds the
+ histogram for pixmap #pm# and computes the optimal palette using
+ \Ref{compute_palette}. */
+ int compute_pixmap_palette(const GPixmap &pm, int ncolors, int minboxsize=0);
+ // CONVERSION
+ /** Returns the number of colors in the palette. */
+ int size() const;
+ /** Returns the best palette index for representing color #p#. */
+ int color_to_index(const GPixel &p);
+ /** Returns the best palette index for representing color #bgr#. */
+ int color_to_index(const unsigned char *bgr);
+ /** Overwrites #p# with the color located at position #index# in the palette. */
+ void index_to_color(int index, GPixel &p) const;
+ /** Overwrites #rgb[0..3]# with the color located at
+ position #index# in the palette. */
+ void index_to_color(int index, unsigned char *bgr) const;
+ /** Quantizes pixmap #pm#. All pixels are replaced by their closest
+ approximation available in the palette. */
+ void quantize(GPixmap &pm);
+ /** Calls \Ref{compute_pixmap_palette} and \Ref{quantize}. */
+ int compute_palette_and_quantize(GPixmap &pm, int maxcolors, int minboxsize=0);
+ // COLOR CORRECTION
+ /** Applies a luminance gamma correction factor of #corr# to the palette
+ entries. Values greater than #1.0# make the image brighter. Values
+ smaller than #1.0# make the image darker. The documentation of program
+ \Ref{ppmcoco} explains how to properly use this function. */
+ void color_correct(double corr);
+ // COLOR INDEX DATA
+ /** Contains an optional sequence of color indices.
+ Function \Ref{encode} and \Ref{decode} also encode and decode this
+ sequence when such a sequence is provided. */
+ GTArray<short> colordata;
+ /** Returns colors from the color index sequence. Pixel #out# is
+ overwritten with the color corresponding to the #nth# element of the
+ color sequence \Ref{colordata}. */
+ void get_color(int nth, GPixel &out) const;
+ // CODING
+ /** Writes the palette colors. This function writes each palette color as a
+ RGB triple into bytestream #bs#. */
+ void encode_rgb_entries(ByteStream &bs) const;
+ /** Reads palette colors. This function initializes the palette colors by
+ reading #palettesize# RGB triples from bytestream #bs#. */
+ void decode_rgb_entries(ByteStream &bs, const int palettesize);
+ /** Encodes the palette and the color index sequence. This function encodes
+ the a version byte, the palette size, the palette colors and the color
+ index sequence into bytestream #bs#. Note that the color histogram is
+ never saved. */
+ void encode(GP<ByteStream> bs) const;
+ /** Initializes the object by reading data from bytestream #bs#. This
+ function reads a version byte, the palette size, the palette and the
+ color index sequence from bytestream #bs#. Note that the color
+ histogram is never saved. */
+ void decode(GP<ByteStream> bs);
+
+private:
+ // Histogram
+ int mask;
+ GMap<int,int> *hist;
+ // Quantization data
+ struct PColor { unsigned char p[4]; };
+ GTArray<PColor> palette;
+ GMap<int,int> *pmap;
+ // Helpers
+ void allocate_hist();
+ void allocate_pmap();
+ static int CALLINGCONVENTION bcomp (const void*, const void*);
+ static int CALLINGCONVENTION gcomp (const void*, const void*);
+ static int CALLINGCONVENTION rcomp (const void*, const void*);
+ static int CALLINGCONVENTION lcomp (const void*, const void*);
+ int color_to_index_slow(const unsigned char *bgr);
+private: // dummy functions
+ static void encode(ByteStream *);
+ static void decode(ByteStream *);
+};
+
+
+//@}
+
+// ------------ INLINES
+
+
+inline void
+DjVuPalette::histogram_clear()
+{
+ delete hist;
+ hist = 0;
+ mask = 0;
+}
+
+inline void
+DjVuPalette::histogram_add(const unsigned char *bgr, int weight)
+{
+ if (weight > 0)
+ {
+ if (!hist || hist->size()>=0x4000)
+ allocate_hist();
+ int key = (bgr[0]<<16)|(bgr[1]<<8)|(bgr[2])|(mask);
+ (*hist)[key] += weight;
+ }
+}
+
+inline void
+DjVuPalette::histogram_add(const GPixel &p, int weight)
+{
+ histogram_add(&p.b, weight);
+}
+
+inline void
+DjVuPalette::histogram_norm_and_add(const int *bgr, int weight)
+{
+ if (weight > 0)
+ {
+ int p0 = bgr[0]/weight; if (p0>255) p0=255;
+ int p1 = bgr[1]/weight; if (p1>255) p1=255;
+ int p2 = bgr[2]/weight; if (p2>255) p2=255;
+ if (!hist || hist->size()>=0x4000)
+ allocate_hist();
+ int key = (p0<<16)|(p1<<8)|(p2)|(mask);
+ (*hist)[key] += weight;
+ }
+}
+
+inline int
+DjVuPalette::size() const
+{
+ return palette.size();
+}
+
+inline int
+DjVuPalette::color_to_index(const unsigned char *bgr)
+{
+ if (! pmap)
+ allocate_pmap();
+ int key = (bgr[0]<<16)|(bgr[1]<<8)|(bgr[2]);
+ GPosition p = pmap->contains(key);
+ if ( p)
+ return (*pmap)[p];
+ return color_to_index_slow(bgr);
+}
+
+inline int
+DjVuPalette::color_to_index(const GPixel &p)
+{
+ return color_to_index(&p.b);
+}
+
+inline void
+DjVuPalette::index_to_color(int index, unsigned char *bgr) const
+{
+ const PColor &color = palette[index];
+ bgr[0] = color.p[0];
+ bgr[1] = color.p[1];
+ bgr[2] = color.p[2];
+}
+
+inline void
+DjVuPalette::index_to_color(int index, GPixel &p) const
+{
+ index_to_color(index, &p.b);
+}
+
+inline void
+DjVuPalette::get_color(int nth, GPixel &p) const
+{
+ index_to_color(colordata[nth], p);
+}
+
+
+
+// ------------ THE END
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
+
+
+
+
+
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuPort.cpp b/kviewshell/plugins/djvu/libdjvu/DjVuPort.cpp
new file mode 100644
index 00000000..5e8a25c9
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuPort.cpp
@@ -0,0 +1,710 @@
+//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: DjVuPort.cpp,v 1.10 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "DjVuPort.h"
+#include "GOS.h"
+#include "DjVuImage.h"
+#include "DjVuDocument.h"
+#include "DjVuFile.h"
+#include "DjVuMessageLite.h"
+#include "DataPool.h"
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+//****************************************************************************
+//******************************* Globals ************************************
+//****************************************************************************
+
+static DjVuPortcaster *pcaster;
+
+DjVuPortcaster *
+DjVuPort::get_portcaster(void)
+{
+ if (!pcaster) pcaster = new DjVuPortcaster();
+ return pcaster;
+}
+
+class DjVuPort::DjVuPortCorpse
+{
+public:
+ DjVuPort * port;
+ DjVuPortCorpse * next;
+
+ DjVuPortCorpse(DjVuPort * _port) : port(_port), next(0) {}
+};
+
+//****************************************************************************
+//******************************* DjVuPort ***********************************
+//****************************************************************************
+
+#define MAX_CORPSE_NUM 128
+
+// Last MAX_CORPSE_NUM addresses of dead DjVuPorts. We want to maintain this
+// list because of the way DjVuPort::is_port_alive() works: it accepts an
+// address and runs it thru its internal maps. The problem will occur if
+// a new DjVuPort is created exactly on place of another one, which just
+// died. Here we attempt to remember the last MAX_CORPSE_NUM addresses
+// of dead DjVuPorts, and take them into account in DjVuPort::operator new();
+GCriticalSection * DjVuPort::corpse_lock;
+DjVuPort::DjVuPortCorpse * DjVuPort::corpse_head;
+DjVuPort::DjVuPortCorpse * DjVuPort::corpse_tail;
+int DjVuPort::corpse_num;
+
+void *
+DjVuPort::operator new (size_t sz)
+{
+ if (!corpse_lock) corpse_lock=new GCriticalSection();
+
+ // Loop until we manage to allocate smth, which is not mentioned in
+ // the 'corpse' list. Thus we will avoid allocating a new DjVuPort
+ // on place of a dead one. Not *absolutely* secure (only 64 items
+ // in the list) but is still better than nothing.
+ void * addr=0;
+ {
+ GCriticalSectionLock lock(corpse_lock);
+
+ // Store here addresses, which were found in 'corpse' list.
+ // We will free then in the end
+ int addr_num=0;
+ static void * addr_arr[MAX_CORPSE_NUM];
+
+ // Make at most MAX_CORPSE_NUM attempts. During each attempt
+ // we try to allocate a block of memory for DjVuPort. If
+ // the address of this block is not in the corpse list, we break
+ // All addresses will be recorder, so that we can delete them
+ // after we're done.
+ for(int attempt=0;attempt<MAX_CORPSE_NUM;attempt++)
+ {
+ void * test_addr=::operator new (sz);
+ addr_arr[addr_num++]=test_addr;
+
+ // See if 'test_addr' is in the 'corpse' list (was recently used)
+ DjVuPortCorpse * corpse;
+ for(corpse=corpse_head;corpse;corpse=corpse->next)
+ if (test_addr==corpse->port) break;
+ if (!corpse)
+ {
+ addr=test_addr;
+ addr_num--;
+ break;
+ }
+ }
+ // If all attempts failed (all addresses generated are already
+ // in the list of corpses, allocate a new one and proceed
+ // w/o additional checks
+ if (!addr) addr=::operator new(sz);
+
+ // Here 'addr_arr[0<=i<addr_num]' contains addresses, that we
+ // tried to allocate, and which need to be freed now
+ // 'addr' contains address we want to use.
+ addr_num--;
+ while(addr_num>=0) ::operator delete(addr_arr[addr_num--]);
+ }
+
+ DjVuPortcaster * pcaster=get_portcaster();
+ GCriticalSectionLock lock(&pcaster->map_lock);
+ pcaster->cont_map[addr]=0;
+ return addr;
+}
+
+void
+DjVuPort::operator delete(void * addr)
+{
+ if (corpse_lock)
+ {
+ GCriticalSectionLock lock(corpse_lock);
+
+ // Add 'addr' to the list of corpses
+ if (corpse_tail)
+ {
+ corpse_tail->next=new DjVuPortCorpse((DjVuPort *) addr);
+ corpse_tail=corpse_tail->next;
+ corpse_tail->next=0;
+ } else
+ {
+ corpse_head=corpse_tail=new DjVuPortCorpse((DjVuPort *) addr);
+ corpse_tail->next=0;
+ }
+ corpse_num++;
+ if (corpse_num>=MAX_CORPSE_NUM)
+ {
+ DjVuPortCorpse * corpse=corpse_head;
+ corpse_head=corpse_head->next;
+ delete corpse;
+ corpse_num--;
+ }
+ }
+ ::operator delete(addr);
+}
+
+DjVuPort::DjVuPort()
+{
+ DjVuPortcaster *pcaster = get_portcaster();
+ GCriticalSectionLock lock(& pcaster->map_lock );
+ GPosition p = pcaster->cont_map.contains(this);
+ if (!p) G_THROW( ERR_MSG("DjVuPort.not_alloc") );
+ pcaster->cont_map[p] = (void*)this;
+}
+
+DjVuPort::DjVuPort(const DjVuPort & port)
+{
+ DjVuPortcaster *pcaster = get_portcaster();
+ GCriticalSectionLock lock(& pcaster->map_lock );
+ GPosition p = pcaster->cont_map.contains(this);
+ if (!p) G_THROW( ERR_MSG("DjVuPort.not_alloc") );
+ pcaster->cont_map[p] = (void*)this;
+ pcaster->copy_routes(this, &port);
+}
+
+DjVuPort &
+DjVuPort::operator=(const DjVuPort & port)
+{
+ if (this != &port)
+ get_portcaster()->copy_routes(this, &port);
+ return *this;
+}
+
+DjVuPort::~DjVuPort(void)
+{
+ get_portcaster()->del_port(this);
+}
+
+
+//****************************************************************************
+//**************************** DjVuPortcaster ********************************
+//****************************************************************************
+
+
+
+DjVuPortcaster::DjVuPortcaster(void)
+{
+}
+
+DjVuPortcaster::~DjVuPortcaster(void)
+{
+ GCriticalSectionLock lock(&map_lock);
+ for(GPosition pos=route_map;pos;++pos)
+ delete (GList<void *> *) route_map[pos];
+}
+
+GP<DjVuPort>
+DjVuPortcaster::is_port_alive(DjVuPort *port)
+{
+ GP<DjVuPort> gp_port;
+ GCriticalSectionLock lock(&map_lock);
+ GPosition pos=cont_map.contains(port);
+ if (pos && cont_map[pos] && ((DjVuPort *) port)->get_count()>0)
+ gp_port=port;
+ return gp_port;
+}
+
+void
+DjVuPortcaster::add_alias(const DjVuPort * port, const GUTF8String &alias)
+{
+ GCriticalSectionLock lock(&map_lock);
+ a2p_map[alias]=port;
+}
+
+void
+DjVuPortcaster::clear_all_aliases(void)
+{
+ DjVuPortcaster *p=get_portcaster();
+ GCriticalSectionLock lock(&(p->map_lock));
+ GPosition pos;
+ while((pos=p->a2p_map))
+ {
+ p->a2p_map.del(pos);
+ }
+}
+
+void
+DjVuPortcaster::clear_aliases(const DjVuPort * port)
+{
+ GCriticalSectionLock lock(&map_lock);
+ for(GPosition pos=a2p_map;pos;)
+ if (a2p_map[pos]==port)
+ {
+ GPosition this_pos=pos;
+ ++pos;
+ a2p_map.del(this_pos);
+ } else ++pos;
+}
+
+GP<DjVuPort>
+DjVuPortcaster::alias_to_port(const GUTF8String &alias)
+{
+ GCriticalSectionLock lock(&map_lock);
+ GPosition pos;
+ if (a2p_map.contains(alias, pos))
+ {
+ DjVuPort * port=(DjVuPort *) a2p_map[pos];
+ GP<DjVuPort> gp_port=is_port_alive(port);
+ if (gp_port) return gp_port;
+ else a2p_map.del(pos);
+ }
+ return 0;
+}
+
+GPList<DjVuPort>
+DjVuPortcaster::prefix_to_ports(const GUTF8String &prefix)
+{
+ GPList<DjVuPort> list;
+ {
+ int length=prefix.length();
+ if (length)
+ {
+ GCriticalSectionLock lock(&map_lock);
+ for(GPosition pos=a2p_map;pos;++pos)
+ if (!prefix.cmp(a2p_map.key(pos), length))
+ {
+ DjVuPort * port=(DjVuPort *) a2p_map[pos];
+ GP<DjVuPort> gp_port=is_port_alive(port);
+ if (gp_port) list.append(gp_port);
+ }
+ }
+ }
+ return list;
+}
+
+void
+DjVuPortcaster::del_port(const DjVuPort * port)
+{
+ GCriticalSectionLock lock(&map_lock);
+
+ GPosition pos;
+
+ // Update the "aliases map"
+ clear_aliases(port);
+
+ // Update "contents map"
+ if (cont_map.contains(port, pos)) cont_map.del(pos);
+
+ // Update "route map"
+ if (route_map.contains(port, pos))
+ {
+ delete (GList<void *> *) route_map[pos];
+ route_map.del(pos);
+ }
+ for(pos=route_map;pos;)
+ {
+ GList<void *> & list=*(GList<void *> *) route_map[pos];
+ GPosition list_pos;
+ if (list.search((void *) port, list_pos)) list.del(list_pos);
+ if (!list.size())
+ {
+ delete &list;
+ GPosition tmp_pos=pos;
+ ++pos;
+ route_map.del(tmp_pos);
+ } else ++pos;
+ }
+}
+
+void
+DjVuPortcaster::add_route(const DjVuPort * src, DjVuPort * dst)
+ // Adds route src->dst
+{
+ GCriticalSectionLock lock(&map_lock);
+ if (cont_map.contains(src) && src->get_count()>0 &&
+ cont_map.contains(dst) && dst->get_count()>0)
+ {
+ if (!route_map.contains(src)) route_map[src]=new GList<void *>();
+ GList<void *> & list=*(GList<void *> *) route_map[src];
+ if (!list.contains(dst)) list.append(dst);
+ }
+}
+
+void
+DjVuPortcaster::del_route(const DjVuPort * src, DjVuPort * dst)
+// Deletes route src->dst
+{
+ GCriticalSectionLock lock(&map_lock);
+
+ if (route_map.contains(src))
+ {
+ GList<void *> & list=*(GList<void *> *) route_map[src];
+ GPosition pos;
+ if (list.search(dst, pos)) list.del(pos);
+ if (!list.size())
+ {
+ delete &list;
+ route_map.del(src);
+ }
+ }
+}
+
+void
+DjVuPortcaster::copy_routes(DjVuPort * dst, const DjVuPort * src)
+ // For every route src->x or x->src, it creates a new one:
+ // dst->x or x->dst respectively. It's useful when you create a copy
+ // of a port and you want the copy to stay connected.
+{
+ GCriticalSectionLock lock(&map_lock);
+
+ if (!cont_map.contains(src) || src->get_count()<=0 ||
+ !cont_map.contains(dst) || dst->get_count()<=0) return;
+
+ for(GPosition pos=route_map;pos;++pos)
+ {
+ GList<void *> & list=*(GList<void *> *) route_map[pos];
+ if (route_map.key(pos) == src)
+ for(GPosition pos=list;pos;++pos)
+ add_route(dst, (DjVuPort *) list[pos]);
+ for(GPosition pos=list;pos;++pos)
+ if ((DjVuPort*)(list[pos]) == src)
+ add_route((DjVuPort *) route_map.key(pos), dst);
+ }
+}
+
+void
+DjVuPortcaster::add_to_closure(GMap<const void *, void *> & set,
+ const DjVuPort * dst, int distance)
+{
+ // Assuming that the map's already locked
+ // GCriticalSectionLock lock(&map_lock);
+ set[dst]= (void*) (unsigned long) distance;
+ if (route_map.contains(dst))
+ {
+ GList<void *> & list=*(GList<void *> *) route_map[dst];
+ for(GPosition pos=list;pos;++pos)
+ {
+ DjVuPort * new_dst=(DjVuPort *) list[pos];
+ if (!set.contains(new_dst))
+ add_to_closure(set, new_dst, distance+1);
+ }
+ }
+}
+
+void
+DjVuPortcaster::compute_closure(const DjVuPort * src, GPList<DjVuPort> &list, bool sorted)
+{
+ GCriticalSectionLock lock(&map_lock);
+ GMap<const void*, void*> set;
+ if (route_map.contains(src))
+ {
+ GList<void *> & list=*(GList<void *> *) route_map[src];
+ for(GPosition pos=list;pos;++pos)
+ {
+ DjVuPort * dst=(DjVuPort *) list[pos];
+ if (dst==src) add_to_closure(set, src, 0);
+ else add_to_closure(set, dst, 1);
+ }
+ }
+
+ // Compute list
+ GPosition pos;
+ if (sorted)
+ {
+ // Sort in depth order
+ int max_dist=0;
+ for(pos=set;pos;++pos)
+ if (max_dist < (int)(long)set[pos])
+ max_dist = (int)(long)set[pos];
+ GArray<GList<const void*> > lists(0,max_dist);
+ for(pos=set;pos;++pos)
+ lists[(int)(long)set[pos]].append(set.key(pos));
+ for(int dist=0;dist<=max_dist;dist++)
+ for(pos=lists[dist];pos;++pos)
+ {
+ GP<DjVuPort> p = is_port_alive((DjVuPort*) lists[dist][pos]);
+ if (p) list.append(p);
+ }
+ }
+ else
+ {
+ // Gather ports without order
+ for(pos=set;pos;++pos)
+ {
+ GP<DjVuPort> p = is_port_alive((DjVuPort*) set.key(pos));
+ if (p) list.append(p);
+ }
+ }
+}
+
+GURL
+DjVuPortcaster::id_to_url(const DjVuPort * source, const GUTF8String &id)
+{
+ GPList<DjVuPort> list;
+ compute_closure(source, list, true);
+ GURL url;
+ for(GPosition pos=list;pos;++pos)
+ {
+ url=list[pos]->id_to_url(source, id);
+ if (!url.is_empty()) break;
+ }
+ return url;
+}
+
+GP<DjVuFile>
+DjVuPortcaster::id_to_file(const DjVuPort * source, const GUTF8String &id)
+{
+ GPList<DjVuPort> list;
+ compute_closure(source, list, true);
+ GP<DjVuFile> file;
+ for(GPosition pos=list;pos;++pos)
+ if ((file=list[pos]->id_to_file(source, id))) break;
+ return file;
+}
+
+GP<DataPool>
+DjVuPortcaster::request_data(const DjVuPort * source, const GURL & url)
+{
+ GPList<DjVuPort> list;
+ compute_closure(source, list, true);
+ GP<DataPool> data;
+ for(GPosition pos=list;pos;++pos)
+ if ((data = list[pos]->request_data(source, url)))
+ break;
+ return data;
+}
+
+bool
+DjVuPortcaster::notify_error(const DjVuPort * source, const GUTF8String &msg)
+{
+ GPList<DjVuPort> list;
+ compute_closure(source, list, true);
+ for(GPosition pos=list;pos;++pos)
+ if (list[pos]->notify_error(source, msg))
+ return 1;
+ return 0;
+}
+
+bool
+DjVuPortcaster::notify_status(const DjVuPort * source, const GUTF8String &msg)
+{
+ GPList<DjVuPort> list;
+ compute_closure(source, list, true);
+ for(GPosition pos=list;pos;++pos)
+ if (list[pos]->notify_status(source, msg))
+ return 1;
+ return 0;
+}
+
+void
+DjVuPortcaster::notify_redisplay(const DjVuImage * source)
+{
+ GPList<DjVuPort> list;
+ compute_closure(source, list);
+ for(GPosition pos=list; pos; ++pos)
+ list[pos]->notify_redisplay(source);
+}
+
+void
+DjVuPortcaster::notify_relayout(const DjVuImage * source)
+{
+ GPList<DjVuPort> list;
+ compute_closure(source, list);
+ for(GPosition pos=list; pos; ++pos)
+ list[pos]->notify_relayout(source);
+}
+
+void
+DjVuPortcaster::notify_chunk_done(const DjVuPort * source, const GUTF8String &name)
+{
+ GPList<DjVuPort> list;
+ compute_closure(source, list);
+ for(GPosition pos=list; pos; ++pos)
+ list[pos]->notify_chunk_done(source, name);
+}
+
+void
+DjVuPortcaster::notify_file_flags_changed(const DjVuFile * source,
+ long set_mask, long clr_mask)
+{
+ GPList<DjVuPort> list;
+ compute_closure(source, list);
+ for(GPosition pos=list; pos; ++pos)
+ list[pos]->notify_file_flags_changed(source, set_mask, clr_mask);
+}
+
+void
+DjVuPortcaster::notify_doc_flags_changed(const DjVuDocument * source,
+ long set_mask, long clr_mask)
+{
+ GPList<DjVuPort> list;
+ compute_closure(source, list);
+ for(GPosition pos=list; pos; ++pos)
+ list[pos]->notify_doc_flags_changed(source, set_mask, clr_mask);
+}
+
+void
+DjVuPortcaster::notify_decode_progress(const DjVuPort * source, float done)
+{
+ GPList<DjVuPort> list;
+ compute_closure(source, list);
+ for(GPosition pos=list; pos; ++pos)
+ list[pos]->notify_decode_progress(source, done);
+}
+
+//****************************************************************************
+//******************************* DjVuPort ***********************************
+//****************************************************************************
+
+GURL
+DjVuPort::id_to_url(const DjVuPort *, const GUTF8String &) { return GURL(); }
+
+GP<DjVuFile>
+DjVuPort::id_to_file(const DjVuPort *, const GUTF8String &) { return 0; }
+
+GP<DataPool>
+DjVuPort::request_data(const DjVuPort *, const GURL &) { return 0; }
+
+bool
+DjVuPort::notify_error(const DjVuPort *, const GUTF8String &) { return 0; }
+
+bool
+DjVuPort::notify_status(const DjVuPort *, const GUTF8String &) { return 0; }
+
+void
+DjVuPort::notify_redisplay(const DjVuImage *) {}
+
+void
+DjVuPort::notify_relayout(const DjVuImage *) {}
+
+void
+DjVuPort::notify_chunk_done(const DjVuPort *, const GUTF8String &) {}
+
+void
+DjVuPort::notify_file_flags_changed(const DjVuFile *, long, long) {}
+
+void
+DjVuPort::notify_doc_flags_changed(const DjVuDocument *, long, long) {}
+
+void
+DjVuPort::notify_decode_progress(const DjVuPort *, float) {}
+
+//****************************************************************************
+//*************************** DjVuSimplePort *********************************
+//****************************************************************************
+
+GP<DataPool>
+DjVuSimplePort::request_data(const DjVuPort * source, const GURL & url)
+{
+ G_TRY {
+ if (url.is_local_file_url())
+ {
+// GUTF8String fname=GOS::url_to_filename(url);
+// if (GOS::basename(fname)=="-") fname="-";
+ return DataPool::create(url);
+ }
+ } G_CATCH_ALL {} G_ENDCATCH;
+ return 0;
+}
+
+bool
+DjVuSimplePort::notify_error(const DjVuPort * source, const GUTF8String &msg)
+{
+ DjVuMessageLite::perror(msg);
+ return 1;
+}
+
+bool
+DjVuSimplePort::notify_status(const DjVuPort * source, const GUTF8String &msg)
+{
+ DjVuMessageLite::perror(msg);
+ return 1;
+}
+
+
+
+
+
+//****************************************************************************
+//*************************** DjVuMemoryPort *********************************
+//****************************************************************************
+
+
+
+GP<DataPool>
+DjVuMemoryPort::request_data(const DjVuPort * source, const GURL & url)
+{
+ GCriticalSectionLock lk(&lock);
+ GP<DataPool> pool;
+ GPosition pos;
+ if (map.contains(url, pos))
+ pool=map[pos];
+ return pool;
+}
+
+void
+DjVuMemoryPort::add_data(const GURL & url, const GP<DataPool> & pool)
+{
+ GCriticalSectionLock lk(&lock);
+ map[url]=pool;
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuPort.h b/kviewshell/plugins/djvu/libdjvu/DjVuPort.h
new file mode 100644
index 00000000..99c165fb
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuPort.h
@@ -0,0 +1,518 @@
+//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: DjVuPort.h,v 1.8 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _DJVUPORT_H
+#define _DJVUPORT_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+#include "GThreads.h"
+#include "GURL.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+class DataPool;
+
+/** @name DjVuPort.h
+ Files #"DjVuPort.h"# and #"DjVuPort.cpp"# implement a communication
+ mechanism between different parties involved in decoding DjVu files.
+ It should be pretty clear that the creator of \Ref{DjVuDocument} and
+ \Ref{DjVuFile} would like to receive some information about the progress
+ of decoding, errors occurred, etc. It may also want to provide source data
+ for decoders (like it's done in the plugin where the real data is downloaded
+ from the net and is fed into DjVu decoders).
+
+ Normally this functionality is implemented by means of callbacks which are
+ run when a given condition comes true. Unfortunately it's not quite easy
+ to implement this strategy in our case. The reason is that there may be
+ more than one "client" working with the same document, and the document
+ should send the information to each of the clients. This could be done by
+ means of callback {\em lists}, of course, but we want to achieve more
+ bulletproof results: we want to be sure that the client that we're about
+ to contact is still alive, and is not being destroyed by another thread.
+ Besides, we are going to call these "callbacks" from many places, from
+ many different classes. Maintaining multi-thread safe callback lists is
+ very difficult.
+
+ Finally, we want to provide some default implementation of these
+ "callbacks" in the library, which should attempt to process the requests
+ themselves if they can, and contact the client only if they're unable to
+ do it (like in the case of \Ref{DjVuPort::request_data}() with local URL
+ where \Ref{DjVuDocument} can get the data from the hard drive itself not
+ disturbing the document's creator.
+
+ Two classes implement a general communication mechanism: \Ref{DjVuPort} and
+ \Ref{DjVuPortcaster}. Any sender and recipient of requests should be a
+ subclass of \Ref{DjVuPort}. \Ref{DjVuPortcaster} maintains a map of
+ routes between \Ref{DjVuPort}s, which should be configured by somebody
+ else. Whenever a port wants to send a request, it calls the corresponding
+ function of \Ref{DjVuPortcaster}, and the portcaster relays the request to
+ all the destinations that it sees in the internal map.
+
+ The \Ref{DjVuPortcaster} is responsible for keeping the map up to date by
+ getting rid of destinations that have been destroyed. Map updates are
+ performed from a single place and are serialized by a global monitor.
+
+ @memo DjVu decoder communication mechanism.
+ @author Andrei Erofeev <eaf@geocities.com>\\
+ L\'eon Bottou <leonb@research.att.com>
+ @version #$Id: DjVuPort.h,v 1.8 2003/11/07 22:08:21 leonb Exp $# */
+//@{
+
+class DjVuPort;
+class DjVuPortcaster;
+class DjVuFile;
+
+/** Base class for notification targets.
+ #DjVuPort# provides base functionality for classes willing to take part in
+ sending and receiving messages generated during decoding process. You
+ need to derive your class from #DjVuPort# if you want it to be able to
+ send or receive requests. In addition, for receiving requests you should
+ override one or more virtual function.
+
+ {\bf Important remark} --- All ports should be allocated on the heap using
+ #operator new# and immediately secured using a \Ref{GP} smart pointer.
+ Ports which are not secured by a smart-pointer are not considered
+ ``alive'' and never receive notifications! */
+
+class DjVuPort : public GPEnabled
+{
+public:
+ DjVuPort();
+ virtual ~DjVuPort();
+ static void *operator new (size_t sz);
+ static void operator delete(void *addr);
+
+ /** Use this function to get a copy of the global \Ref{DjVuPortcaster}. */
+ static DjVuPortcaster *get_portcaster(void);
+
+ /** Copy constructor. When #DjVuPort#s are copied, the portcaster
+ copies all incoming and outgoing routes of the original. */
+ DjVuPort(const DjVuPort & port);
+
+ /** Copy operator. Similarly to the copy constructor, the portcaster
+ copies all incoming and outgoing coming routes of the original. */
+ DjVuPort & operator=(const DjVuPort & port);
+
+ /** Should return 1 if the called class inherits class #class_name#.
+ When a destination receives a request, it can retrieve the pointer
+ to the source #DjVuPort#. This virtual function should be able
+ to help to identify the source of the request. For example,
+ \Ref{DjVuFile} is also derived from #DjVuPort#. In order for
+ the receiver to recognize the sender, the \Ref{DjVuFile} should
+ override this function to return #TRUE# when the #class_name#
+ is either #DjVuPort# or #DjVuFile# */
+ virtual bool inherits(const GUTF8String &class_name) const;
+
+ /** @name Notifications.
+ These virtual functions may be overridden by the subclasses
+ of #DjVuPort#. They are called by the \Ref{DjVuPortcaster}
+ when the port is alive and when there is a route between the
+ source of the notification and this port. */
+ //@{
+
+ /** This request is issued to request translation of the ID, used
+ in an DjVu INCL chunk to a URL, which may be used to request
+ data associated with included file. \Ref{DjVuDocument} usually
+ intercepts all such requests, and the user doesn't have to
+ worry about the translation */
+ virtual GURL id_to_url(const DjVuPort * source, const GUTF8String &id);
+
+ /** This request is used to get a file corresponding to the
+ given ID. \Ref{DjVuDocument} is supposed to intercept it
+ and either create a new instance of \Ref{DjVuFile} or reuse
+ an existing one from the cache. */
+ virtual GP<DjVuFile> id_to_file(const DjVuPort * source, const GUTF8String &id);
+
+ /** This request is issued when decoder needs additional data
+ for decoding. Both \Ref{DjVuFile} and \Ref{DjVuDocument} are
+ initialized with a URL, not the document data. As soon as
+ they need the data, they call this function, whose responsibility
+ is to locate the source of the data basing on the #URL# passed
+ and return it back in the form of the \Ref{DataPool}. If this
+ particular receiver is unable to fullfil the request, it should
+ return #0#. */
+ virtual GP<DataPool> request_data(const DjVuPort * source, const GURL & url);
+
+ /** This notification is sent when an error occurs and the error message
+ should be shown to the user. The receiver should return #0# if it is
+ unable to process the request. Otherwise the receiver should return 1. */
+ virtual bool notify_error(const DjVuPort * source, const GUTF8String &msg);
+
+ /** This notification is sent to update the decoding status. The
+ receiver should return #0# if it is unable to process the
+ request. Otherwise the receiver should return 1. */
+ virtual bool notify_status(const DjVuPort * source, const GUTF8String &msg);
+
+ /** This notification is sent by \Ref{DjVuImage} when it should be
+ redrawn. It may be used to implement progressive redisplay.
+
+ @param source The sender of the request */
+ virtual void notify_redisplay(const class DjVuImage * source);
+
+ /** This notification is sent by \ref{DjVuImage} when its geometry
+ has been changed as a result of decoding. It may be used to
+ implement progressive redisplay. */
+ virtual void notify_relayout(const class DjVuImage * source);
+
+ /** This notification is sent when a new chunk has been decoded. */
+ virtual void notify_chunk_done(const DjVuPort * source, const GUTF8String &name);
+
+ /** This notification is sent after the \Ref{DjVuFile} flags have
+ been changed. This happens, for example, when:
+ \begin{itemize}
+ \item Decoding succeeded, failed or just stopped
+ \item All data has been received
+ \item All included files have been created
+ \end{itemize}
+
+ @param source \Ref{DjVuFile}, which flags have been changed
+ @param set_mask bits, which have been set
+ @param clr_mask bits, which have been cleared */
+ virtual void notify_file_flags_changed(const class DjVuFile * source,
+ long set_mask, long clr_mask);
+
+ /** This notification is sent after the \Ref{DjVuDocument} flags have
+ been changed. This happens, for example, after it receives enough
+ data and can determine its structure (#BUNDLED#, #OLD_INDEXED#, etc.).
+
+ @param source \Ref{DjVuDocument}, which flags have been changed
+ @param set_mask bits, which have been set
+ @param clr_mask bits, which have been cleared */
+ virtual void notify_doc_flags_changed(const class DjVuDocument * source,
+ long set_mask, long clr_mask);
+
+ /** This notification is sent from time to time while decoding is in
+ progress. The purpose is obvious: to provide a way to know how much
+ is done and how long the decoding will continue. Argument #done# is
+ a number from 0 to 1 reflecting the progress. */
+ virtual void notify_decode_progress(const DjVuPort * source, float done);
+
+ /** This is the standard types for defining what to do in case of errors.
+ This is only used by some of the subclasses, but it needs to be
+ defined here to guarantee all subclasses use the same enum types.
+ In general, many errors are non recoverable. Using a setting
+ other than ABORT may just result in even more errors. */
+ enum ErrorRecoveryAction {ABORT=0,SKIP_PAGES=1,SKIP_CHUNKS=2,KEEP_ALL=3 };
+ //@}
+public:
+ class DjVuPortCorpse;
+private:
+ static GCriticalSection * corpse_lock;
+ static DjVuPortCorpse * corpse_head, * corpse_tail;
+ static int corpse_num;
+};
+
+/** Simple port.
+ An instance of #DjVuSimplePort# is automatically created when you create a
+ \Ref{DjVuFile} or a \Ref{DjVuDocument} without specifying a port. This
+ simple port can retrieve data for local urls (i.e. urls referring to local
+ files) and display error messages on #stderr#. All other notifications
+ are ignored. */
+
+class DjVuSimplePort : public DjVuPort
+{
+public:
+ /// Returns 1 if #class_name# is #"DjVuPort"# or #"DjVuSimplePort"#.
+ virtual bool inherits(const GUTF8String &class_name) const;
+
+ /** If #url# is local, it created a \Ref{DataPool}, connects it to the
+ file with the given name and returns. Otherwise returns #0#. */
+ virtual GP<DataPool> request_data(const DjVuPort * source, const GURL & url);
+
+ /// Displays error on #stderr#. Always returns 1.
+ virtual bool notify_error(const DjVuPort * source, const GUTF8String &msg);
+
+ /// Displays status on #stderr#. Always returns 1.
+ virtual bool notify_status(const DjVuPort * source, const GUTF8String &msg);
+};
+
+
+/** Memory based port.
+ This \Ref{DjVuPort} maintains a map associating pseudo urls with data
+ segments. It processes the #request_data# notifications according to this
+ map. After initializing the port, you should add as many pairs #<url,
+ pool># as needed need and add a route from a \Ref{DjVuDocument} or
+ \Ref{DjVuFile} to this port. */
+
+class DjVuMemoryPort : public DjVuPort
+{
+public:
+ /// Returns 1 if #class_name# is #"DjVuPort"# or #"DjVuMemoryPort"#
+ virtual bool inherits(const GUTF8String &class_name) const;
+
+ /** If #url# is one of those, that have been added before by means
+ of \Ref{add_data}() function, it will return the associated
+ \Ref{DataPool}. #ZERO# otherwize. */
+ virtual GP<DataPool> request_data(const DjVuPort * source, const GURL & url);
+
+ /** Adds #<url, pool># pair to the internal map. From now on, if
+ somebody asks for data corresponding to the #url#, it will
+ be returning the #pool# */
+ void add_data(const GURL & url, const GP<DataPool> & pool);
+private:
+ GCriticalSection lock;
+ GPMap<GURL, DataPool>map;
+};
+
+
+
+/** Maintains associations between ports.
+ It monitors the status of all ports (have they been destructed yet?),
+ accepts requests and notifications from them and forwards them to
+ destinations according to internally maintained map of routes.
+
+ The caller can modify the route map any way he likes (see
+ \Ref{add_route}(), \Ref{del_route}(), \Ref{copy_routes}(),
+ etc. functions). Any port can be either a sender of a message, an
+ intermediary receiver or a final destination.
+
+ When a request is sent, the #DjVuPortcaster# computes the list of
+ destinations by consulting with the route map. Notifications are only
+ sent to ``alive'' ports. A port is alive if it is referenced by a valid
+ \Ref{GP} smartpointer. As a consequence, a port usually becomes alive
+ after running the constructor (since the returned pointer is then assigned
+ to a smartpointer) and is no longer alive when the port is destroyed
+ (because it would not be destroyed if a smartpointer was referencing it).
+
+ Destination ports are sorted according to their distance from the source.
+ For example, if port {\bf A} is connected to ports {\bf B} and {\bf C}
+ directly, and port {\bf B} is connected to {\bf D}, then {\bf B} and {\bf
+ C} are assumed to be one hop away from {\bf A}, while {\bf D} is two hops
+ away from {\bf A}.
+
+ In some cases the requests and notifications are sent to every possible
+ destination, and the order is not significant (like it is for
+ \Ref{notify_file_flags_changed}() request). Others should be sent to the closest
+ destinations first, and only then to the farthest, in case if they have
+ not been processed by the closest. The examples are \Ref{request_data}(),
+ \Ref{notify_error}() and \Ref{notify_status}().
+
+ The user is not expected to create the #DjVuPortcaster# itself. He should
+ use \Ref{get_portcaster}() global function instead. */
+class DjVuPortcaster
+{
+public:
+ /** Use this function to get a copy of the global \Ref{DjVuPortcaster}. */
+ static DjVuPortcaster *get_portcaster(void)
+ { return DjVuPort::get_portcaster(); } ;
+
+ /** The default constructor. */
+ DjVuPortcaster(void);
+
+ virtual ~DjVuPortcaster(void);
+
+ /** Removes the specified port from all routes. It will no longer
+ be able to receive or generate messages and will be considered
+ {\bf "dead"} by \Ref{is_port_alive}() function. */
+ void del_port(const DjVuPort * port);
+
+ /** Adds route from #src# to #dst#. Whenever a request is
+ sent or received by #src#, it will be forwarded to #dst# as well.
+ @param src The source
+ @param dst The destination */
+ void add_route(const DjVuPort *src, DjVuPort *dst);
+
+ /** The opposite of \Ref{add_route}(). Removes the association
+ between #src# and #dst# */
+ void del_route(const DjVuPort *src, DjVuPort *dst);
+
+ /** Copies all incoming and outgoing routes from #src# to
+ #dst#. This function should be called when a \Ref{DjVuPort} is
+ copied, if you want to preserve the connectivity. */
+ void copy_routes(DjVuPort *dst, const DjVuPort *src);
+
+ /** Returns a smart pointer to the port if #port# is a valid pointer
+ to an existing #DjVuPort#. Returns a null pointer otherwise. */
+ GP<DjVuPort> is_port_alive(DjVuPort *port);
+
+ /** Assigns one more {\em alias} for the specified \Ref{DjVuPort}.
+ {\em Aliases} are names, which can be used later to retrieve this
+ \Ref{DjVuPort}, if it still exists. Any \Ref{DjVuPort} may have
+ more than one {\em alias}. But every {\em alias} must correspond
+ to only one \Ref{DjVuPort}. Thus, if the specified alias is
+ already associated with another port, this association will be
+ removed. */
+ void add_alias(const DjVuPort * port, const GUTF8String &alias);
+
+ /** Removes all the aliases */
+ static void clear_all_aliases(void);
+
+ /** Removes all aliases associated with the given \Ref{DjVuPort}. */
+ void clear_aliases(const DjVuPort * port);
+
+ /** Returns \Ref{DjVuPort} associated with the given #alias#. If nothing
+ is known about name #alias#, or the port associated with it has
+ already been destroyed #ZERO# pointer will be returned. */
+ GP<DjVuPort> alias_to_port(const GUTF8String &name);
+
+ /** Returns a list of \Ref{DjVuPort}s with aliases starting with
+ #prefix#. If no \Ref{DjVuPort}s have been found, empty
+ list is returned. */
+ GPList<DjVuPort> prefix_to_ports(const GUTF8String &prefix);
+
+ /** Computes destination list for #source# and calls the corresponding
+ function in each of the ports from the destination list starting from
+ the closest until one of them returns non-empty \Ref{GURL}. */
+ virtual GURL id_to_url(const DjVuPort * source, const GUTF8String &id);
+
+ /** Computes destination list for #source# and calls the corresponding
+ function in each of the ports from the destination list starting from
+ the closest until one of them returns non-zero pointer to
+ \Ref{DjVuFile}. */
+ virtual GP<DjVuFile> id_to_file(const DjVuPort * source, const GUTF8String &id);
+
+ /** Computes destination list for #source# and calls the corresponding
+ function in each of the ports from the destination list starting from
+ the closest until one of them returns non-zero \Ref{DataPool}. */
+ virtual GP<DataPool> request_data(const DjVuPort * source, const GURL & url);
+
+ /** Computes destination list for #source# and calls the corresponding.
+ function in each of the ports from the destination starting from
+ the closest until one of them returns 1. */
+ virtual bool notify_error(const DjVuPort * source, const GUTF8String &msg);
+
+ /** Computes destination list for #source# and calls the corresponding
+ function in each of the ports from the destination list starting from
+ the closest until one of them returns 1. */
+ virtual bool notify_status(const DjVuPort * source, const GUTF8String &msg);
+
+ /** Computes destination list for #source# and calls the corresponding
+ function in each of the ports from the destination list starting from
+ the closest. */
+ virtual void notify_redisplay(const class DjVuImage * source);
+
+ /** Computes destination list for #source# and calls the corresponding
+ function in each of the ports from the destination list starting from
+ the closest. */
+ virtual void notify_relayout(const class DjVuImage * source);
+
+ /** Computes destination list for #source# and calls the corresponding
+ function in each of the ports from the destination list starting from
+ the closest. */
+ virtual void notify_chunk_done(const DjVuPort * source, const GUTF8String &name);
+
+ /** Computes destination list for #source# and calls the corresponding
+ function in each of the ports from the destination list starting from
+ the closest. */
+ virtual void notify_file_flags_changed(const class DjVuFile * source,
+ long set_mask, long clr_mask);
+
+ /** Computes destination list for #source# and calls the corresponding
+ function in each of the ports from the destination list starting from
+ the closest. */
+ virtual void notify_doc_flags_changed(const class DjVuDocument * source,
+ long set_mask, long clr_mask);
+
+ /** Computes destination list for #source# and calls the corresponding
+ function in each of the ports from the destination list starting from
+ the closest. */
+ virtual void notify_decode_progress(const DjVuPort * source, float done);
+
+private:
+ // We use these 'void *' to minimize template instantiations.
+ friend class DjVuPort;
+ GCriticalSection map_lock;
+ GMap<const void *, void *> route_map; // GMap<DjVuPort *, GList<DjVuPort *> *>
+ GMap<const void *, void *> cont_map; // GMap<DjVuPort *, DjVuPort *>
+ GMap<GUTF8String, const void *> a2p_map; // GMap<GUTF8String, DjVuPort *>
+ void add_to_closure(GMap<const void*, void*> & set,
+ const DjVuPort *dst, int distance);
+ void compute_closure(const DjVuPort *src, GPList<DjVuPort> &list,
+ bool sorted=false);
+};
+
+
+inline bool
+DjVuPort::inherits(const GUTF8String &class_name) const
+{
+ return (class_name == "DjVuPort");
+}
+
+inline bool
+DjVuSimplePort::inherits(const GUTF8String &class_name) const
+{
+ return
+ (class_name == "DjVuSimplePort") || DjVuPort::inherits(class_name);
+}
+
+inline bool
+DjVuMemoryPort::inherits(const GUTF8String &class_name) const
+{
+ return
+ (class_name == "DjVuMemoryPort") || DjVuPort::inherits(class_name);
+}
+
+//@}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuText.cpp b/kviewshell/plugins/djvu/libdjvu/DjVuText.cpp
new file mode 100644
index 00000000..b359df41
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuText.cpp
@@ -0,0 +1,971 @@
+//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: DjVuText.cpp,v 1.10 2004/07/07 19:23:36 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "DjVuText.h"
+#include "IFFByteStream.h"
+#include "BSByteStream.h"
+#include "debug.h"
+#include <ctype.h>
+
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+
+#ifdef min
+#undef min
+#endif
+template<class TYPE>
+static inline TYPE min(TYPE a,TYPE b) { return (a<b)?a:b; }
+
+//***************************************************************************
+//******************************** DjVuTXT **********************************
+//***************************************************************************
+
+const char DjVuTXT::end_of_column = 013; // VT: Vertical Tab
+const char DjVuTXT::end_of_region = 035; // GS: Group Separator
+const char DjVuTXT::end_of_paragraph = 037; // US: Unit Separator
+const char DjVuTXT::end_of_line = 012; // LF: Line Feed
+
+const int DjVuTXT::Zone::version = 1;
+
+DjVuTXT::Zone::Zone()
+ : ztype(DjVuTXT::PAGE), text_start(0), text_length(0), zone_parent(0)
+{
+}
+
+DjVuTXT::Zone *
+DjVuTXT::Zone::append_child()
+{
+ Zone empty;
+ empty.ztype = ztype;
+ empty.text_start = 0;
+ empty.text_length = 0;
+ empty.zone_parent=this;
+ children.append(empty);
+ return & children[children.lastpos()];
+}
+
+void
+DjVuTXT::Zone::cleartext()
+{
+ text_start = 0;
+ text_length = 0;
+ for (GPosition i=children; i; ++i)
+ children[i].cleartext();
+}
+
+void
+DjVuTXT::Zone::normtext(const char *instr, GUTF8String &outstr)
+{
+ if (text_length == 0)
+ {
+ // Descend collecting text below
+ text_start = outstr.length();
+ for (GPosition i=children; i; ++i)
+ children[i].normtext(instr, outstr);
+ text_length = outstr.length() - text_start;
+ // Ignore empty zones
+ if (text_length == 0)
+ return;
+ }
+ else
+ {
+ // Collect text at this level
+ int new_start = outstr.length();
+ outstr = outstr + GUTF8String(instr+text_start, text_length);
+ text_start = new_start;
+ // Clear textual information on lower level nodes
+ for (GPosition i=children; i; ++i)
+ children[i].cleartext();
+ }
+ // Determine standard separator
+ char sep;
+ switch (ztype)
+ {
+ case COLUMN:
+ sep = end_of_column; break;
+ case REGION:
+ sep = end_of_region; break;
+ case PARAGRAPH:
+ sep = end_of_paragraph; break;
+ case LINE:
+ sep = end_of_line; break;
+ case WORD:
+ sep = ' '; break;
+ default:
+ return;
+ }
+ // Add separator if not present yet.
+ if (outstr[text_start+text_length-1] != sep)
+ {
+ outstr = outstr + GUTF8String(&sep, 1);
+ text_length += 1;
+ }
+}
+
+unsigned int
+DjVuTXT::Zone::memuse() const
+{
+ int memuse = sizeof(*this);
+ for (GPosition i=children; i; ++i)
+ memuse += children[i].memuse();
+ return memuse;
+}
+
+
+#ifndef NEED_DECODER_ONLY
+void
+DjVuTXT::Zone::encode(
+ const GP<ByteStream> &gbs, const Zone * parent, const Zone * prev) const
+{
+ ByteStream &bs=*gbs;
+ // Encode type
+ bs.write8(ztype);
+
+ // Modify text_start and bounding rectangle based on the context
+ // (whether there is a previous non-zero same-level-child or parent)
+ int start=text_start;
+ int x=rect.xmin, y=rect.ymin;
+ int width=rect.width(), height=rect.height();
+ if (prev)
+ {
+ if (ztype==PAGE || ztype==PARAGRAPH || ztype==LINE)
+ {
+ // Encode offset from the lower left corner of the previous
+ // child in the coord system in that corner with x to the
+ // right and y down
+ x=x-prev->rect.xmin;
+ y=prev->rect.ymin-(y+height);
+ } else // Either COLUMN or WORD or CHARACTER
+ {
+ // Encode offset from the lower right corner of the previous
+ // child in the coord system in that corner with x to the
+ // right and y up
+ x=x-prev->rect.xmax;
+ y=y-prev->rect.ymin;
+ }
+ start-=prev->text_start+prev->text_length;
+ } else if (parent)
+ {
+ // Encode offset from the upper left corner of the parent
+ // in the coord system in that corner with x to the right and y down
+ x=x-parent->rect.xmin;
+ y=parent->rect.ymax-(y+height);
+ start-=parent->text_start;
+ }
+ // Encode rectangle
+ bs.write16(0x8000+x);
+ bs.write16(0x8000+y);
+ bs.write16(0x8000+width);
+ bs.write16(0x8000+height);
+ // Encode text info
+ bs.write16(0x8000+start);
+ bs.write24(text_length);
+ // Encode number of children
+ bs.write24(children.size());
+
+ const Zone * prev_child=0;
+ // Encode all children
+ for (GPosition i=children; i; ++i)
+ {
+ children[i].encode(gbs, this, prev_child);
+ prev_child=&children[i];
+ }
+}
+#endif
+
+void
+DjVuTXT::Zone::decode(const GP<ByteStream> &gbs, int maxtext,
+ const Zone * parent, const Zone * prev)
+{
+ ByteStream &bs=*gbs;
+ // Decode type
+ ztype = (ZoneType) bs.read8();
+ if ( ztype<PAGE || ztype>CHARACTER )
+ G_THROW( ERR_MSG("DjVuText.corrupt_text") );
+
+ // Decode coordinates
+ int x=(int) bs.read16()-0x8000;
+ int y=(int) bs.read16()-0x8000;
+ int width=(int) bs.read16()-0x8000;
+ int height=(int) bs.read16()-0x8000;
+
+ // Decode text info
+ text_start = (int) bs.read16()-0x8000;
+// int start=text_start;
+ text_length = bs.read24();
+ if (prev)
+ {
+ if (ztype==PAGE || ztype==PARAGRAPH || ztype==LINE)
+ {
+ x=x+prev->rect.xmin;
+ y=prev->rect.ymin-(y+height);
+ } else // Either COLUMN or WORD or CHARACTER
+ {
+ x=x+prev->rect.xmax;
+ y=y+prev->rect.ymin;
+ }
+ text_start+=prev->text_start+prev->text_length;
+ } else if (parent)
+ {
+ x=x+parent->rect.xmin;
+ y=parent->rect.ymax-(y+height);
+ text_start+=parent->text_start;
+ }
+ rect=GRect(x, y, width, height);
+ // Get children size
+ int size = bs.read24();
+
+ // Checks
+ if (rect.isempty() || text_start<0 || text_start+text_length>maxtext )
+ G_THROW( ERR_MSG("DjVuText.corrupt_text") );
+
+ // Process children
+ const Zone * prev_child=0;
+ children.empty();
+ while (size-- > 0)
+ {
+ Zone *z = append_child();
+ z->decode(gbs, maxtext, this, prev_child);
+ prev_child=z;
+ }
+}
+
+void
+DjVuTXT::normalize_text()
+{
+ GUTF8String newtextUTF8;
+ page_zone.normtext( (const char*)textUTF8, newtextUTF8 );
+ textUTF8 = newtextUTF8;
+}
+
+int
+DjVuTXT::has_valid_zones() const
+{
+ if (!textUTF8)
+ return false;
+ if (page_zone.children.isempty() || page_zone.rect.isempty())
+ return false;
+ return true;
+}
+
+
+#ifndef NEED_DECODER_ONLY
+void
+DjVuTXT::encode(const GP<ByteStream> &gbs) const
+{
+ ByteStream &bs=*gbs;
+ if (! textUTF8 )
+ G_THROW( ERR_MSG("DjVuText.no_text") );
+ // Encode text
+ int textsize = textUTF8.length();
+ bs.write24( textsize );
+ bs.writall( (void*)(const char*)textUTF8, textsize );
+ // Encode zones
+ if (has_valid_zones())
+ {
+ bs.write8(Zone::version);
+ page_zone.encode(gbs);
+ }
+}
+#endif
+
+void
+DjVuTXT::decode(const GP<ByteStream> &gbs)
+{
+ ByteStream &bs=*gbs;
+ // Read text
+ textUTF8.empty();
+ int textsize = bs.read24();
+ char *buffer = textUTF8.getbuf(textsize);
+ int readsize = bs.read(buffer,textsize);
+ buffer[readsize] = 0;
+ if (readsize < textsize)
+ G_THROW( ERR_MSG("DjVuText.corrupt_chunk") );
+ // Try reading zones
+ unsigned char version;
+ if ( bs.read( (void*) &version, 1 ) == 1)
+ {
+ if (version != Zone::version)
+ G_THROW( ERR_MSG("DjVuText.bad_version") "\t" + GUTF8String(version) );
+ page_zone.decode(gbs, textsize);
+ }
+}
+
+GP<DjVuTXT>
+DjVuTXT::copy(void) const
+{
+ return new DjVuTXT(*this);
+}
+
+
+static inline bool
+intersects_zone(GRect box, const GRect &zone)
+{
+ return
+ ((box.xmin < zone.xmin)
+ ?(box.xmax >= zone.xmin)
+ :(box.xmin <= zone.xmax))
+ &&((box.ymin < zone.ymin)
+ ?(box.ymax >= zone.ymin)
+ :(box.ymin <= zone.ymax));
+}
+
+void
+DjVuTXT::Zone::get_text_with_rect(const GRect &box,
+ int &string_start, int &string_end) const
+{
+ GPosition pos=children;
+ if(pos?box.contains(rect):intersects_zone(box,rect))
+ {
+ const int text_end=text_start+text_length;
+ if(string_start == string_end)
+ {
+ string_start=text_start;
+ string_end=text_end;
+ }else
+ {
+ if (string_end < text_end)
+ string_end=text_end;
+ if(text_start < string_start)
+ string_start=text_start;
+ }
+ }else if(pos&&intersects_zone(box,rect))
+ {
+ do
+ {
+ children[pos].get_text_with_rect(box,string_start,string_end);
+ } while(++pos);
+ }
+}
+
+void
+DjVuTXT::Zone::find_zones(GList<Zone *> &list,
+ const int string_start, const int string_end) const
+{
+ const int text_end=text_start+text_length;
+ if(text_start >= string_start)
+ {
+ if(text_end <= string_end)
+ {
+ list.append(const_cast<Zone *>(this));
+ }
+ else if(text_start < string_end)
+ {
+ if (children.size())
+ for (GPosition pos=children; pos; ++pos)
+ children[pos].find_zones(list,string_start,string_end);
+ else
+ list.append(const_cast<Zone *>(this));
+ }
+ }
+ else if( text_end > string_start)
+ {
+ if (children.size())
+ for (GPosition pos=children; pos; ++pos)
+ children[pos].find_zones(list,string_start,string_end);
+ else
+ list.append(const_cast<Zone *>(this));
+ }
+}
+
+void
+DjVuTXT::Zone::get_smallest(GList<GRect> &list) const
+{
+ GPosition pos=children;
+ if(pos)
+ {
+ do {
+ children[pos].get_smallest(list);
+ } while (++pos);
+ }
+ else
+ {
+ list.append(rect);
+ }
+}
+
+void
+DjVuTXT::Zone::get_smallest(GList<GRect> &list, const int padding) const
+{
+ GPosition pos=children;
+ if(pos)
+ {
+ do {
+ children[pos].get_smallest(list,padding);
+ } while (++pos);
+ }
+ else if(zone_parent && zone_parent->ztype >= PARAGRAPH)
+ {
+ const GRect &xrect=zone_parent->rect;
+ if(xrect.height() < xrect.width())
+ {
+ list.append(GRect(rect.xmin-padding,xrect.ymin-padding,rect.width()
+ +2*padding,xrect.height()+2*padding));
+ }
+ else
+ {
+ list.append(GRect(xrect.xmin-padding,rect.ymin-padding,xrect.width()
+ +2*padding,rect.height()+2*padding));
+ }
+ }
+ else
+ {
+ list.append(GRect(rect.xmin-padding,rect.ymin-padding,rect.width()
+ +2*padding,rect.height()+2*padding));
+ }
+}
+
+void
+DjVuTXT::get_zones(int zone_type, const Zone *parent,
+ GList<Zone *> & zone_list) const
+ // get all the zones of type zone_type under zone node parent
+{
+ // search all branches under parent
+ const Zone *zone=parent;
+ for( int cur_ztype=zone->ztype; cur_ztype<zone_type; ++cur_ztype )
+ {
+ GPosition pos;
+ for(pos=zone->children; pos; ++pos)
+ {
+ Zone *zcur=(Zone *)&zone->children[pos];
+ if ( zcur->ztype == zone_type )
+ {
+ GPosition zpos=zone_list;
+ if ( !zone_list.search(zcur,zpos) )
+ zone_list.append(zcur);
+ }
+ else if ( zone->children[pos].ztype < zone_type )
+ get_zones(zone_type, &zone->children[pos], zone_list);
+ }
+ }
+}
+
+GList<GRect>
+DjVuTXT::find_text_with_rect(const GRect &box, GUTF8String &text,
+ const int padding) const
+{
+ GList<GRect> retval;
+ int text_start=0;
+ int text_end=0;
+ page_zone.get_text_with_rect(box,text_start,text_end);
+ if(text_start != text_end)
+ {
+ GList<Zone *> zones;
+ page_zone.find_zones(zones,text_start,text_end);
+ GPosition pos=zones;
+ if(pos)
+ {
+ do
+ {
+ if(padding >= 0)
+ {
+ zones[pos]->get_smallest(retval,padding);
+ }else
+ {
+ zones[pos]->get_smallest(retval);
+ }
+ } while(++pos);
+ }
+ }
+ text=textUTF8.substr(text_start,text_end-text_start);
+ return retval;
+}
+
+
+GList<DjVuTXT::Zone *>
+DjVuTXT::find_text_in_rect(GRect target_rect, GUTF8String &text) const
+ // returns a list of zones of type WORD in the nearest/selected paragraph
+{
+ GList<Zone *> zone_list;
+ GList<Zone *> lines;
+
+ get_zones((int)PARAGRAPH, &page_zone, zone_list);
+ // it's possible that no paragraph structure exists for reasons that
+ // 1) ocr engine is not capable 2) file was modified by user. In such case,
+ // we can only make a rough guess, i.e., select all the lines intersected with
+ // target_rect
+ if (zone_list.isempty())
+ {
+ get_zones((int)LINE, &page_zone, zone_list);
+ GPosition pos;
+ for(pos=zone_list; pos; ++pos)
+ {
+ GRect rect=zone_list[pos]->rect;
+ int h0=rect.height()/2;
+ if(rect.intersect(rect,target_rect) && rect.height()>h0)
+ lines.append(zone_list[pos]);
+ }
+ } else
+ {
+ GPosition pos, pos_sel=zone_list;
+ float ar=0;
+ for(pos=zone_list; pos; ++pos)
+ {
+ GRect rect=zone_list[pos]->rect;
+ int area=rect.area();
+ if (rect.intersect(rect, target_rect))
+ {
+ float ftmp=rect.area()/(float)area;
+ if ( !ar || ar<ftmp )
+ {
+ ar=ftmp;
+ pos_sel=pos;
+ }
+ }
+ }
+ Zone *parag = 0;
+ if ( ar>0 ) parag=zone_list[pos_sel];
+ zone_list.empty();
+ if ( ar>0 )
+ {
+ get_zones((int)LINE, parag, zone_list);
+ if ( !zone_list.isempty() )
+ {
+ for(GPosition pos=zone_list; pos; ++pos)
+ {
+ GRect rect=zone_list[pos]->rect;
+ int h0=rect.height()/2;
+ if(rect.intersect(rect,target_rect) && rect.height()>h0)
+ lines.append(zone_list[pos]);
+ }
+ }
+ }
+ }
+
+ zone_list.empty();
+ if (!lines.isempty())
+ {
+ int i=1, lsize=lines.size();
+
+ GList<Zone *> words;
+ for (GPosition pos=lines; pos; ++pos, ++i)
+ {
+ words.empty();
+ get_zones((int)WORD, lines[pos], words);
+
+ if ( lsize==1 )
+ {
+ for(GPosition p=words;p;++p)
+ {
+ GRect rect=words[p]->rect;
+ if(rect.intersect(rect,target_rect))
+ //if (target_rect.contains(words[p]->rect))
+ zone_list.append(words[p]);
+ }
+ } else
+ {
+ if (i==1)
+ {
+ bool start=true;
+ for(GPosition p=words; p; ++p)
+ {
+ if ( start )
+ {
+ GRect rect=words[p]->rect;
+ if(rect.intersect(rect,target_rect))
+ //if (target_rect.contains(words[p]->rect))
+ {
+ start=false;
+ zone_list.append(words[p]);
+ }
+ } else
+ zone_list.append(words[p]);
+ }
+ } else if (i==lsize)
+ {
+ bool end=true;
+ for(GPosition p=words.lastpos();p;--p)
+ {
+ if ( end )
+ {
+ GRect rect=words[p]->rect;
+ if(rect.intersect(rect,target_rect))
+ //if(target_rect.contains(words[p]->rect) )
+ {
+ end=false;
+ zone_list.append(words[p]);
+ }
+ } else
+ zone_list.append(words[p]);
+ }
+ }
+
+ if (i!=1 && i!=lsize )
+ {
+ for(GPosition p=words;p;++p)
+ zone_list.append(words[p]);
+ }
+ }
+ }
+ }
+
+ return zone_list;
+}
+
+unsigned int
+DjVuTXT::get_memory_usage() const
+{
+ return sizeof(*this) + textUTF8.length() + page_zone.memuse() - sizeof(page_zone);
+}
+
+
+
+//***************************************************************************
+//******************************** DjVuText *********************************
+//***************************************************************************
+
+void
+DjVuText::decode(const GP<ByteStream> &gbs)
+{
+ GUTF8String chkid;
+ GP<IFFByteStream> giff=IFFByteStream::create(gbs);
+ IFFByteStream &iff=*giff;
+ while( iff.get_chunk(chkid) )
+ {
+ if (chkid == "TXTa")
+ {
+ if (txt)
+ G_THROW( ERR_MSG("DjVuText.dupl_text") );
+ txt = DjVuTXT::create();
+ txt->decode(iff.get_bytestream());
+ }
+ else if (chkid == "TXTz")
+ {
+ if (txt)
+ G_THROW( ERR_MSG("DjVuText.dupl_text") );
+ txt = DjVuTXT::create();
+ const GP<ByteStream> gbsiff=BSByteStream::create(iff.get_bytestream());
+ txt->decode(gbsiff);
+ }
+ // Add decoding of other chunks here
+ iff.close_chunk();
+ }
+}
+
+void
+DjVuText::encode(const GP<ByteStream> &gbs)
+{
+ if (txt)
+ {
+ const GP<IFFByteStream> giff=IFFByteStream::create(gbs);
+ IFFByteStream &iff=*giff;
+ iff.put_chunk("TXTz");
+ {
+ GP<ByteStream> gbsiff=BSByteStream::create(iff.get_bytestream(),50);
+ txt->encode(gbsiff);
+ }
+ iff.close_chunk();
+ }
+ // Add encoding of other chunks here
+}
+
+
+GP<DjVuText>
+DjVuText::copy(void) const
+{
+ GP<DjVuText> text= new DjVuText;
+ // Copy any primitives (if any)
+ *text=*this;
+ // Copy each substructure
+ if (txt)
+ text->txt = txt->copy();
+ return text;
+}
+
+static GUTF8String
+indent ( int spaces)
+{
+ GUTF8String ret;
+ for( int i = 0 ; i < spaces ; i++ )
+ ret += ' ';
+ return ret;
+}
+
+static const char *tags[8]=
+{ 0,
+ "HIDDENTEXT",
+ "PAGECOLUMN",
+ "REGION",
+ "PARAGRAPH",
+ "LINE",
+ "WORD",
+ "CHARACTER" };
+static const int tags_size=sizeof(tags)/sizeof(const char *);
+
+static GUTF8String
+start_tag(const DjVuTXT::ZoneType zone)
+{
+ GUTF8String retval;
+ if((tags_size > (int)zone)&&((int)zone > 0))
+ {
+ switch (zone)
+ {
+ case DjVuTXT::CHARACTER:
+ retval="<"+GUTF8String(tags[zone])+">";
+ break;
+ case DjVuTXT::WORD:
+ retval=indent(2*(int)zone+2)+"<"+tags[zone]+">";
+ break;
+ default:
+ retval=indent(2*(int)zone+2)+"<"+tags[zone]+">\n";
+ break;
+ }
+ }
+ return retval;
+}
+
+static GUTF8String
+start_tag(const DjVuTXT::ZoneType zone, const GUTF8String &attributes)
+{
+ GUTF8String retval;
+ if((tags_size > (int)zone)&&((int)zone > 0))
+ {
+ switch (zone)
+ {
+ case DjVuTXT::CHARACTER:
+ retval="<"+GUTF8String(tags[zone])+" "+attributes+">";
+ break;
+ case DjVuTXT::WORD:
+ retval=indent(2*(int)zone+2)+"<"+tags[zone]+" "+attributes+">";
+ break;
+ default:
+ retval=indent(2*(int)zone+2)+"<"+tags[zone]+" "+attributes+">\n";
+ break;
+ }
+ }
+ return retval;
+}
+
+static inline GUTF8String
+start_tag(const int layer)
+{
+ return start_tag((const DjVuTXT::ZoneType)layer);
+}
+
+
+static GUTF8String
+end_tag(const DjVuTXT::ZoneType zone)
+{
+ GUTF8String retval;
+ if((tags_size > (int)zone)&&((int)zone >= 0))
+ {
+ switch (zone)
+ {
+ case DjVuTXT::CHARACTER:
+ retval="</"+GUTF8String(tags[zone])+">";
+ break;
+ case DjVuTXT::WORD:
+ retval="</"+GUTF8String(tags[zone])+">\n";
+ break;
+ default:
+ retval=indent(2*(int)zone+2)+"</"+tags[zone]+">\n";
+ break;
+ }
+ }
+ return retval;
+}
+
+static inline GUTF8String
+end_tag(const int layer)
+{
+ return end_tag((const DjVuTXT::ZoneType)layer);
+}
+
+static GUTF8String
+tolayer(int &layer, const DjVuTXT::ZoneType next_layer)
+{
+ GUTF8String retval;
+ for( ;layer < (int)next_layer;layer++ )
+ {
+ retval+=start_tag(layer);
+ }
+ while (layer > (int)next_layer )
+ {
+ retval+=end_tag(--layer);
+ }
+ return retval;
+}
+
+static void
+writeText( ByteStream & str_out,
+ const GUTF8String &textUTF8,
+ const DjVuTXT::Zone &zone,
+ const int WindowHeight );
+
+static void
+writeText( ByteStream & str_out,
+ const GUTF8String &textUTF8,
+ const DjVuTXT::ZoneType zlayer,
+ const GList<DjVuTXT::Zone> &children,
+ const int WindowHeight )
+{
+// assert( txt->has_valid_zones() );
+// DEBUG_MSG( "--zonetype=" << txt->page_zone.ztype << "\n" );
+
+ // Beginning tags for missing layers
+ int layer=(int)zlayer;
+ // Output the next layer
+ for(GPosition pos=children ; pos ; ++pos )
+ {
+ str_out.writestring(tolayer(layer,children[pos].ztype));
+ writeText( str_out,
+ textUTF8,
+ children[pos],
+ WindowHeight );
+ }
+ str_out.writestring(tolayer(layer,zlayer));
+}
+
+static void
+writeText( ByteStream & str_out,
+ const GUTF8String &textUTF8,
+ const DjVuTXT::Zone &zone,
+ const int WindowHeight )
+{
+// DEBUG_MSG( "--zonetype=" << zone.ztype << "\n" );
+
+ const GUTF8String xindent(indent( 2 * zone.ztype + 2 ));
+ GPosition pos=zone.children;
+ // Build attribute string
+ if( ! pos )
+ {
+ GUTF8String coords;
+ coords.format("coords=\"%d,%d,%d,%d\"",
+ zone.rect.xmin, WindowHeight - 1 - zone.rect.ymin,
+ zone.rect.xmax, WindowHeight - 1 - zone.rect.ymax);
+ const int start=zone.text_start;
+ const int end=textUTF8.firstEndSpace(start,zone.text_length);
+ str_out.writestring(start_tag(zone.ztype,coords));
+ str_out.writestring(textUTF8.substr(start,end-start).toEscaped());
+ str_out.writestring(end_tag(zone.ztype));
+ } else
+ {
+ writeText(str_out,textUTF8,zone.ztype,zone.children,WindowHeight);
+ }
+}
+
+void
+DjVuTXT::writeText(ByteStream &str_out,const int height) const
+{
+ if(has_valid_zones())
+ {
+ ::writeText(str_out,textUTF8,DjVuTXT::PAGE,page_zone.children,height);
+ }else
+ {
+ str_out.writestring(start_tag(DjVuTXT::PAGE));
+ str_out.writestring(end_tag(DjVuTXT::PAGE));
+ }
+}
+
+void
+DjVuText::writeText(ByteStream &str_out,const int height) const
+{
+ if(txt)
+ {
+ txt->writeText(str_out,height);
+ }else
+ {
+ str_out.writestring("<"+GUTF8String(tags[DjVuTXT::PAGE])+"/>\n");
+ }
+
+}
+GUTF8String
+DjVuTXT::get_xmlText(const int height) const
+{
+ GP<ByteStream> gbs(ByteStream::create());
+ ByteStream &bs=*gbs;
+ writeText(bs,height);
+ bs.seek(0L);
+ return bs.getAsUTF8();
+}
+
+GUTF8String
+DjVuText::get_xmlText(const int height) const
+{
+ GUTF8String retval;
+ if(txt)
+ {
+ retval=txt->get_xmlText(height);
+ }else
+ {
+ retval="<"+GUTF8String(tags[DjVuTXT::PAGE])+"/>\n";
+ }
+ return retval;
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuText.h b/kviewshell/plugins/djvu/libdjvu/DjVuText.h
new file mode 100644
index 00000000..61ee3667
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuText.h
@@ -0,0 +1,281 @@
+//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: DjVuText.h,v 1.10 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _DJVUTEXT_H
+#define _DJVUTEXT_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+
+/** @name DjVuText.h
+
+ Files #"DjVuText.h"# and #"DjVuText.cpp"# implement the mechanism for
+ text in DjVuImages.
+
+ This file implements annotations understood by the DjVu plugins
+ and encoders.
+
+
+ using: contents of #TXT*# chunks.
+
+ Contents of the #FORM:TEXT# should be passed to \Ref{DjVuText::decode}()
+ for parsing, which initializes \Ref{DjVuText::TXT}
+ and fills them with decoded data.
+ @memo Implements support for DjVuImage hidden text.
+ @author Andrei Erofeev <eaf@geocities.com>
+ @version
+ #$Id: DjVuText.h,v 1.10 2003/11/07 22:08:21 leonb Exp $# */
+//@{
+
+
+#include "GMapAreas.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+class ByteStream;
+
+// -------- DJVUTXT --------
+
+/** Description of the text contained in a DjVu page. This class contains the
+ textual data for the page. It describes the text as a hierarchy of zones
+ corresponding to page, column, region, paragraph, lines, words, etc...
+ The piece of text associated with each zone is represented by an offset
+ and a length describing a segment of a global UTF8 encoded string. */
+
+class DjVuTXT : public GPEnabled
+{
+protected:
+ DjVuTXT(void) {}
+public:
+ /// Default creator
+ static GP<DjVuTXT> create(void) {return new DjVuTXT();}
+
+ /** These constants are used to tell what a zone describes.
+ This can be useful for a copy/paste application.
+ The deeper we go into the hierarchy, the higher the constant. */
+ enum ZoneType { PAGE=1, COLUMN=2, REGION=3, PARAGRAPH=4,
+ LINE=5, WORD=6, CHARACTER=7 };
+ /** Data structure representing document textual components.
+ The text structure is represented by a hierarchy of rectangular zones. */
+ class Zone
+ {
+ public:
+ Zone();
+ /** Type of the zone. */
+ enum ZoneType ztype;
+ /** Rectangle spanned by the zone */
+ GRect rect;
+ /** Position of the zone text in string #textUTF8#. */
+ int text_start;
+ /** Length of the zone text in string #textUTF8#. */
+ int text_length;
+ /** List of children zone. */
+ GList<Zone> children;
+ /** Appends another subzone inside this zone. The new zone is initialized
+ with an empty rectangle, empty text, and has the same type as this
+ zone. */
+ Zone *append_child();
+ /** Find the text_start and text_end indicated by the given box. */
+ void get_text_with_rect(const GRect &box,
+ int &string_start,int &string_end ) const;
+ /** Find the zones used by the specified string and append them to the list. */
+ void find_zones(GList<Zone *> &list,
+ const int string_start, const int string_end) const;
+ /** Finds the smallest rectangles and appends them to the list. */
+ void get_smallest(GList<GRect> &list) const;
+ /** Finds the smallest rectangles and appends them to the list after
+ padding the smallest unit to fit width or height for the parent rectangle
+ and adding the number of specified pixels. */
+ void get_smallest(GList<GRect> &list,const int padding) const;
+ /// Find out this Zone's parent.
+ const Zone *get_parent(void) const;
+ private:
+ friend class DjVuTXT;
+ const Zone *zone_parent;
+ void cleartext();
+ void normtext(const char *instr, GUTF8String &outstr);
+ unsigned int memuse() const;
+ static const int version;
+ void encode(const GP<ByteStream> &bs,
+ const Zone * parent=0, const Zone * prev=0) const;
+ void decode(const GP<ByteStream> &bs, int maxtext,
+ const Zone * parent=0, const Zone * prev=0);
+ };
+ /** Textual data for this page.
+ The content of this string is encoded using the UTF8 code.
+ This code corresponds to ASCII for the first 127 characters.
+ Columns, regions, paragraph and lines are delimited by the following
+ control character:
+ \begin{tabular}{lll}
+ {\bf Name} & {\bf Octal} & {\bf Ascii name} \\\hline\\
+ {\tt DjVuText::end_of_column} & 013 & VT, Vertical Tab \\
+ {\tt DjVuText::end_of_region} & 035 & GS, Group Separator \\
+ {\tt DjVuText::end_of_paragraph} & 037 & US, Unit Separator \\
+ {\tt DjVuText::end_of_line} & 012 & LF: Line Feed
+ \end{tabular} */
+ GUTF8String textUTF8;
+ static const char end_of_column ; // VT: Vertical Tab
+ static const char end_of_region ; // GS: Group Separator
+ static const char end_of_paragraph ; // US: Unit Separator
+ static const char end_of_line ; // LF: Line Feed
+ /** Main zone in the document.
+ This zone represent the page. */
+ Zone page_zone;
+ /** Tests whether there is a meaningful zone hierarchy. */
+ int has_valid_zones() const;
+ /** Normalize textual data. Assuming that a zone hierarchy has been built
+ and represents the reading order. This function reorganizes the string
+ #textUTF8# by gathering the highest level text available in the zone
+ hierarchy. The text offsets and lengths are recomputed for all the
+ zones in the hierarchy. Separators are inserted where appropriate. */
+ void normalize_text();
+ /** Encode data for a TXT chunk. */
+ void encode(const GP<ByteStream> &bs) const;
+ /** Decode data from a TXT chunk. */
+ void decode(const GP<ByteStream> &bs);
+ /** Returns a copy of this object. */
+ GP<DjVuTXT> copy(void) const;
+ /// Write XML formated text.
+ void writeText(ByteStream &bs,const int height) const;
+ /// Get XML formatted text.
+ GUTF8String get_xmlText(const int height) const;
+ /** Find the text specified by the rectangle. */
+ GList<Zone*> find_text_in_rect(GRect target_rect, GUTF8String &text) const;
+ /** Find the text specified by the rectangle. */
+ GList<GRect> find_text_with_rect(const GRect &box, GUTF8String &text, const int padding=0) const;
+ /** Get all zones of zone type zone_type under node parent.
+ zone_list contains the return value. */
+ void get_zones(int zone_type, const Zone *parent, GList<Zone *> & zone_list) const;
+ /** Returns the number of bytes needed by this data structure. It's
+ used by caching routines to estimate the size of a \Ref{DjVuImage}. */
+ unsigned int get_memory_usage() const;
+};
+
+inline const DjVuTXT::Zone *
+DjVuTXT::Zone::get_parent(void) const
+{
+ return zone_parent;
+}
+
+
+class DjVuText : public GPEnabled
+{
+protected:
+ DjVuText(void) {}
+public:
+ /// Default creator.
+ static GP<DjVuText> create(void) {return new DjVuText();}
+
+ /** Decodes a sequence of annotation chunks and merges contents of every
+ chunk with previously decoded information. This function
+ should be called right after applying \Ref{IFFByteStream::get_chunk}()
+ to data from #FORM:TEXT#. */
+ void decode(const GP<ByteStream> &bs);
+
+ /** Encodes all annotations back into a sequence of chunks to be put
+ inside a #FORM:TEXT#. */
+ void encode(const GP<ByteStream> &bs);
+
+ /// Returns a copy of this object
+ GP<DjVuText> copy(void) const;
+
+ /** Returns the number of bytes needed by this data structure. It's
+ used by caching routines to estimate the size of a \Ref{DjVuImage}. */
+ inline unsigned int get_memory_usage() const;
+
+ /// Write XML formated text.
+ void writeText(ByteStream &bs,const int height) const;
+
+ /// Get XML formatted text.
+ GUTF8String get_xmlText(const int height) const;
+
+ GP<DjVuTXT> txt;
+private: // dummy stuff
+ static void decode(ByteStream *);
+ static void encode(ByteStream *);
+};
+
+//@}
+
+inline unsigned int
+DjVuText::get_memory_usage() const
+{
+ return (txt)?(txt->get_memory_usage()):0;
+}
+
+
+// ----- THE END
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
+
+
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuToPS.cpp b/kviewshell/plugins/djvu/libdjvu/DjVuToPS.cpp
new file mode 100644
index 00000000..beaa01bc
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuToPS.cpp
@@ -0,0 +1,2582 @@
+//C- -*- C++ -*-
+//C- -------------------------------------------------------------------
+//C- DjVuLibre-3.5
+//C- Copyright (c) 2002-2003 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: DjVuToPS.cpp,v 1.23 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "DjVuToPS.h"
+#include "IFFByteStream.h"
+#include "BSByteStream.h"
+#include "DjVuImage.h"
+#include "DjVuText.h"
+#include "DataPool.h"
+#include "IW44Image.h"
+#include "JB2Image.h"
+#include "GBitmap.h"
+#include "GPixmap.h"
+#include "debug.h"
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <math.h>
+#ifdef UNIX
+#include <pwd.h>
+#include <grp.h>
+#include <unistd.h>
+#endif
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+static const size_t ps_string_size=15000;
+
+// ***************************************************************************
+// ****************************** Options ************************************
+// ***************************************************************************
+
+DjVuToPS::Options::
+Options(void)
+: format(PS),
+ level(2),
+ orientation(AUTO),
+ mode(COLOR),
+ zoom(0),
+ color(true),
+ calibrate(true),
+ text(false),
+ gamma((double)2.2),
+ copies(1),
+ frame(false),
+ cropmarks(false),
+ bookletmode(OFF),
+ bookletmax(0),
+ bookletalign(0),
+ bookletfold(18),
+ bookletxfold(200)
+{}
+
+void
+DjVuToPS::Options::
+set_format(Format xformat)
+{
+ if (xformat != EPS && xformat != PS)
+ G_THROW(ERR_MSG("DjVuToPS.bad_format"));
+ format=xformat;
+}
+
+void
+DjVuToPS::Options::
+set_level(int xlevel)
+{
+ if (xlevel<1 || xlevel>3)
+ G_THROW(ERR_MSG("DjVuToPS.bad_level")
+ + GUTF8String("\t") + GUTF8String(xlevel));
+ level=xlevel;
+}
+
+void
+DjVuToPS::Options::
+set_orientation(Orientation xorientation)
+{
+ if (xorientation!=PORTRAIT &&
+ xorientation!=LANDSCAPE &&
+ xorientation!=AUTO )
+ G_THROW(ERR_MSG("DjVuToPS.bad_orient"));
+ orientation=xorientation;
+}
+
+void
+DjVuToPS::Options::
+set_mode(Mode xmode)
+{
+ if (xmode!=COLOR && xmode!=FORE && xmode!=BACK && xmode!=BW)
+ G_THROW(ERR_MSG("DjVuToPS.bad_mode"));
+ mode=xmode;
+}
+
+void
+DjVuToPS::Options::
+set_zoom(int xzoom)
+{
+ if (xzoom!=0 && !(xzoom>=5 && xzoom<=999))
+ G_THROW(ERR_MSG("DjVuToPS.bad_zoom"));
+ zoom=xzoom;
+}
+
+void
+DjVuToPS::Options::
+set_color(bool xcolor)
+{
+ color=xcolor;
+}
+
+void
+DjVuToPS::Options::
+set_sRGB(bool xcalibrate)
+{
+ calibrate=xcalibrate;
+}
+
+void
+DjVuToPS::Options::
+set_gamma(double xgamma)
+{
+ if (xgamma<(double)(0.3-0.0001) || xgamma>(double)(5.0+0.0001))
+ G_THROW(ERR_MSG("DjVuToPS.bad_gamma"));
+ gamma=xgamma;
+}
+
+void
+DjVuToPS::Options::
+set_copies(int xcopies)
+{
+ if (xcopies<=0)
+ G_THROW(ERR_MSG("DjVuToPS.bad_number"));
+ copies=xcopies;
+}
+
+void
+DjVuToPS::Options::
+set_frame(bool xframe)
+{
+ frame=xframe;
+}
+
+void
+DjVuToPS::Options::
+set_cropmarks(bool xmarks)
+{
+ cropmarks=xmarks;
+}
+
+void
+DjVuToPS::Options::
+set_text(bool xtext)
+{
+ text=xtext;
+}
+
+void
+DjVuToPS::Options::
+set_bookletmode(BookletMode m)
+{
+ bookletmode = m;
+}
+
+void
+DjVuToPS::Options::
+set_bookletmax(int m)
+{
+ bookletmax = 0;
+ if (m > 0)
+ bookletmax = (m+3)/4;
+ bookletmax *= 4;
+}
+
+void
+DjVuToPS::Options::
+set_bookletalign(int m)
+{
+ bookletalign = m;
+}
+
+void
+DjVuToPS::Options::
+set_bookletfold(int fold, int xfold)
+{
+ if (fold >= 0)
+ bookletfold = fold;
+ if (xfold >= 0)
+ bookletxfold = xfold;
+}
+
+
+// ***************************************************************************
+// ******************************* DjVuToPS **********************************
+// ***************************************************************************
+
+static char bin2hex[256][2];
+
+DjVuToPS::DjVuToPS(void)
+{
+ DEBUG_MSG("DjVuToPS::DjVuToPS(): initializing...\n");
+ DEBUG_MAKE_INDENT(3);
+ DEBUG_MSG("Initializing dig2hex[]\n");
+ // Creating tables for bin=>text translation
+ static char * dig2hex="0123456789ABCDEF";
+ int i;
+ for(i=0;i<256;i++)
+ {
+ bin2hex[i][0]=dig2hex[i/16];
+ bin2hex[i][1]=dig2hex[i%16];
+ }
+ refresh_cb=0;
+ refresh_cl_data=0;
+ prn_progress_cb=0;
+ prn_progress_cl_data=0;
+ dec_progress_cb=0;
+ dec_progress_cl_data=0;
+ info_cb=0;
+ info_cl_data=0;
+}
+
+#ifdef __GNUC__
+static void
+write(ByteStream &str, const char *format, ...)
+__attribute__((format (printf, 2, 3)));
+#endif
+
+static void
+write(ByteStream &str, const char *format, ...)
+{
+ /* Will output the formated string to the specified \Ref{ByteStream}
+ like #fprintf# would do it for a #FILE#. */
+ va_list args;
+ va_start(args, format);
+ GUTF8String tmp;
+ tmp.vformat(format, args);
+ str.writall((const char *) tmp, tmp.length());
+}
+
+// ************************* DOCUMENT LEVEL *********************************
+
+void
+DjVuToPS::
+store_doc_prolog(ByteStream &str, int pages, int dpi, GRect *grect)
+{
+ /* Will store the {\em document prolog}, which is basically a
+ block of document-level comments in PS DSC 3.0 format.
+ @param str Stream where PostScript data should be written
+ @param pages Total number of pages
+ @param dpi (EPS mode only)
+ @param grect (EPS mode only) */
+ DEBUG_MSG("storing the document prolog\n");
+ DEBUG_MAKE_INDENT(3);
+ if (options.get_format()==Options::EPS)
+ write(str,
+ "%%!PS-Adobe-3.0 EPSF 3.0\n"
+ "%%%%BoundingBox: 0 0 %d %d\n",
+ (grect->width()*100+dpi-1)/dpi,
+ (grect->height()*100+dpi-1)/dpi );
+ else
+ write(str, "%%!PS-Adobe-3.0\n");
+ write(str,
+ "%%%%Title: DjVu PostScript document\n"
+ "%%%%Copyright: Copyright (c) 1998-1999 AT&T\n"
+ "%%%%Creator: DjVu (code by Andrei Erofeev)\n"
+ "%%%%DocumentData: Clean7Bit\n");
+ // Date
+ time_t tm=time(0);
+ write(str, "%%%%CreationDate: %s", ctime(&tm));
+ // For
+#ifdef UNIX
+ passwd *pswd = getpwuid(getuid());
+ if (pswd)
+ {
+ char *s = strchr(pswd->pw_gecos, ',');
+ if (s)
+ *s = 0;
+ s = 0;
+ if (pswd->pw_gecos && strlen(pswd->pw_gecos))
+ s = pswd->pw_gecos;
+ else if (pswd->pw_name && strlen(pswd->pw_name))
+ s = pswd->pw_name;
+ if (s)
+ write(str, "%%%%For: %s\n", s);
+ }
+#endif
+ // Language
+ write(str, "%%%%LanguageLevel: %d\n", options.get_level());
+ if (options.get_level()<2 && options.get_color())
+ write(str, "%%%%Extensions: CMYK\n");
+ // Pages
+ write(str, "%%%%Pages: %d\n",pages );
+ write(str, "%%%%PageOrder: Ascend\n");
+ // Orientation
+ if (options.get_orientation() != Options::AUTO)
+ write(str, "%%%%Orientation: %s\n",
+ options.get_orientation()==Options::PORTRAIT ?
+ "Portrait" : "Landscape" );
+ // Requirements
+ if (options.get_format() == Options::PS)
+ {
+ write(str, "%%%%Requirements:");
+ if (options.get_color())
+ write(str, " color");
+ if (options.get_copies()>1)
+ write(str, " numcopies(%d)", options.get_copies());
+ if (options.get_level()>=2)
+ {
+ if (options.get_copies()>1)
+ write(str, " collate");
+ if (options.get_bookletmode() == Options::RECTOVERSO)
+ write(str, " duplex(tumble)");
+ }
+ write(str, "\n");
+ }
+ // End
+ write(str,
+ "%%%%EndComments\n"
+ "%%%%EndProlog\n"
+ "\n");
+}
+
+void
+DjVuToPS::
+store_doc_setup(ByteStream &str)
+{
+ /* Will store the {\em document setup}, which is a set of
+ PostScript commands and functions used to inspect and prepare
+ the PostScript interpreter environment before displaying images. */
+ write(str,
+ "%%%%BeginSetup\n"
+ "/doc-origstate save def\n");
+ if (options.get_level()>=2)
+ {
+ if (options.get_format() == Options::PS)
+ {
+ if (options.get_copies()>1)
+ write(str,
+ "[{\n"
+ "%%%%BeginFeature: NumCopies %d\n"
+ "<< /NumCopies %d >> setpagedevice\n"
+ "%%%%EndFeature\n"
+ "} stopped cleartomark\n"
+ "[{\n"
+ "%%%%BeginFeature: Collate\n"
+ "<< /Collate true >> setpagedevice\n"
+ "%%%%EndFeature\n"
+ "} stopped cleartomark\n",
+ options.get_copies(),
+ options.get_copies() );
+ if (options.get_bookletmode()==Options::RECTOVERSO)
+ write(str,
+ "[{\n"
+ "%%%%BeginFeature: Duplex DuplexTumble\n"
+ "<< /Duplex true /Tumble true >> setpagedevice\n"
+ "%%%%EndFeature\n"
+ "} stopped cleartomark\n");
+ }
+ if (options.get_color())
+ write(str,
+ "%% -- procs for reading color image\n"
+ "/readR () def\n"
+ "/readG () def\n"
+ "/readB () def\n"
+ "/ReadData {\n"
+ " currentfile /ASCII85Decode filter dup\n"
+ " /RunLengthDecode filter\n"
+ " bufferR readstring pop /readR exch def\n"
+ " dup status { flushfile } { pop } ifelse\n"
+ " currentfile /ASCII85Decode filter dup\n"
+ " /RunLengthDecode filter\n"
+ " bufferG readstring pop /readG exch def\n"
+ " dup status { flushfile } { pop } ifelse\n"
+ " currentfile /ASCII85Decode filter dup\n"
+ " /RunLengthDecode filter\n"
+ " bufferB readstring pop /readB exch def\n"
+ " dup status { flushfile } { pop } ifelse\n"
+ "} bind def\n"
+ "/ReadR {\n"
+ " readR length 0 eq { ReadData } if\n"
+ " readR /readR () def\n"
+ "} bind def\n"
+ "/ReadG {\n"
+ " readG length 0 eq { ReadData } if\n"
+ " readG /readG () def\n"
+ "} bind def\n"
+ "/ReadB {\n"
+ " readB length 0 eq { ReadData } if\n"
+ " readB /readB () def\n"
+ "} bind def\n");
+ write(str,
+ "%% -- procs for foreground layer\n"
+ "/g {gsave 0 0 0 0 5 index 5 index setcachedevice\n"
+ " true [1 0 0 1 0 0] 5 4 roll imagemask grestore\n"
+ "} bind def\n"
+ "/gn {gsave 0 0 0 0 6 index 6 index setcachedevice\n"
+ " true [1 0 0 1 0 0] 3 2 roll 5 1 roll \n"
+ " { 1 sub 0 index 2 add 1 index 1 add roll\n"
+ " } imagemask grestore pop \n"
+ "} bind def\n"
+ "/c {setcolor rmoveto glyphshow} bind def\n"
+ "/s {rmoveto glyphshow} bind def\n"
+ "/S {rmoveto gsave show grestore} bind def\n"
+ "/F {(Helvetica) findfont exch scalefont setfont} bind def\n"
+ "%% -- emulations\n"
+ "systemdict /rectstroke known not {\n"
+ " /rectstroke %% stack : x y width height \n"
+ " { newpath 4 2 roll moveto 1 index 0 rlineto\n"
+ " 0 exch rlineto neg 0 rlineto closepath stroke\n"
+ " } bind def } if\n"
+ "systemdict /rectclip known not {\n"
+ " /rectclip %% stack : x y width height \n"
+ " { newpath 4 2 roll moveto 1 index 0 rlineto\n"
+ " 0 exch rlineto neg 0 rlineto closepath clip\n"
+ " } bind def } if\n"
+ "%% -- color space\n" );
+ if (options.get_sRGB())
+ write(str,
+ "/DjVuColorSpace [ %s\n"
+ "<< /DecodeLMN [ { dup 0.03928 le {\n"
+ " 12.92321 div\n"
+ " } {\n"
+ " 0.055 add 1.055 div 2.4 exp\n"
+ " } ifelse } bind dup dup ]\n"
+ " /MatrixLMN [\n"
+ " 0.412457 0.212673 0.019334\n"
+ " 0.357576 0.715152 0.119192\n"
+ " 0.180437 0.072175 0.950301 ]\n"
+ " /WhitePoint [ 0.9505 1 1.0890 ] %% D65 \n"
+ " /BlackPoint[0 0 0] >> ] def\n",
+ (options.get_color()) ? "/CIEBasedABC" : "/CIEBasedA" );
+ else if (options.get_color())
+ write(str,"/DjVuColorSpace /DeviceRGB def\n");
+ else
+ write(str,"/DjVuColorSpace /DeviceGray def\n");
+ }
+ else
+ {
+ // level<2
+ if (options.get_format() == Options::PS)
+ if (options.get_copies() > 1)
+ write(str,"/#copies %d def\n", options.get_copies());
+ if (options.get_color())
+ write(str,
+ "%% -- buffers for reading image\n"
+ "/buffer8 () def\n"
+ "/buffer24 () def\n"
+ "%% -- colorimage emulation\n"
+ "systemdict /colorimage known {\n"
+ " /ColorProc {\n"
+ " currentfile buffer24 readhexstring pop\n"
+ " } bind def\n"
+ " /ColorImage {\n"
+ " colorimage\n"
+ " } bind def\n"
+ "} {\n"
+ " /ColorProc {\n"
+ " currentfile buffer24 readhexstring pop\n"
+ " /data exch def /datalen data length def\n"
+ " /cnt 0 def\n"
+ " 0 1 datalen 3 idiv 1 sub {\n"
+ " buffer8 exch\n"
+ " data cnt get 20 mul /cnt cnt 1 add def\n"
+ " data cnt get 32 mul /cnt cnt 1 add def\n"
+ " data cnt get 12 mul /cnt cnt 1 add def\n"
+ " add add 64 idiv put\n"
+ " } for\n"
+ " buffer8 0 datalen 3 idiv getinterval\n"
+ " } bind def\n"
+ " /ColorImage {\n"
+ " pop pop image\n"
+ " } bind def\n"
+ "} ifelse\n");
+ } // level<2
+ write(str, "%%%%EndSetup\n\n");
+}
+
+void
+DjVuToPS::
+store_doc_trailer(ByteStream &str)
+{
+ /* Will store the {\em document trailer}, which is a clean-up code
+ used to return the PostScript interpeter back to the state, in which
+ it was before displaying this document. */
+ write(str,
+ "%%%%Trailer\n"
+ "doc-origstate restore\n"
+ "%%%%EOF\n");
+}
+
+// ***********************************************************************
+// ***************************** PAGE LEVEL ******************************
+// ***********************************************************************
+
+static unsigned char *
+ASCII85_encode(unsigned char * dst,
+ const unsigned char * src_start,
+ const unsigned char * src_end)
+{
+ /* Will read data between #src_start# and #src_end# pointers (excluding byte
+ pointed by #src_end#), encode it using {\bf ASCII85} algorithm, and
+ output the result into the destination buffer pointed by #dst#. The
+ function returns pointer to the first unused byte in the destination
+ buffer. */
+ int symbols=0;
+ const unsigned char * ptr;
+ for(ptr=src_start;ptr<src_end;ptr+=4)
+ {
+ unsigned int num=0;
+ if (ptr+3<src_end)
+ {
+ num |= ptr[0] << 24;
+ num |= ptr[1] << 16;
+ num |= ptr[2] << 8;
+ num |= ptr[3];
+ }
+ else
+ {
+ num |= ptr[0] << 24;
+ if (ptr+1<src_end)
+ num |= ptr[1] << 16;
+ if (ptr+2<src_end)
+ num |= ptr[2] << 8;
+ }
+ int a1, a2, a3, a4, a5;
+ a5=num % 85; num/=85;
+ a4=num % 85; num/=85;
+ a3=num % 85; num/=85;
+ a2=num % 85;
+ a1=num / 85;
+ *dst++ = a1+33;
+ *dst++ = a2+33;
+ if (ptr+1<src_end)
+ *dst++ = a3+33;
+ if (ptr+2<src_end)
+ *dst++ = a4+33;
+ if (ptr+3<src_end)
+ *dst++ = a5+33;
+ symbols += 5;
+ if (symbols > 70 && ptr+4<src_end)
+ {
+ *dst++='\n';
+ symbols=0;
+ }
+ }
+ return dst;
+}
+
+static unsigned char *
+RLE_encode(unsigned char * dst,
+ const unsigned char * src_start,
+ const unsigned char * src_end)
+{
+ /* Will read data between #src_start# and #src_end# pointers (excluding byte
+ pointed by #src_end#), RLE encode it, and output the result into the
+ destination buffer pointed by #dst#. #counter# is used to count the
+ number of output bytes. The function returns pointer to the first unused
+ byte in the destination buffer. */
+ const unsigned char * ptr;
+ for(ptr=src_start;ptr<src_end;ptr++)
+ {
+ if (ptr==src_end-1)
+ {
+ *dst++=0; *dst++=*ptr;
+ }
+ else if (ptr[0]!=ptr[1])
+ {
+ // Guess how many non repeating bytes we have
+ const unsigned char * ptr1;
+ for(ptr1=ptr+1;ptr1<src_end-1;ptr1++)
+ if (ptr1[0]==ptr1[1] || ptr1-ptr>=128) break;
+ int pixels=ptr1-ptr;
+ *dst++=pixels-1;
+ for(int cnt=0;cnt<pixels;cnt++)
+ *dst++=*ptr++;
+ ptr--;
+ }
+ else
+ {
+ // Get the number of repeating bytes
+ const unsigned char * ptr1;
+ for(ptr1=ptr+1;ptr1<src_end-1;ptr1++)
+ if (ptr1[0]!=ptr1[1] || ptr1-ptr+1>=128) break;
+ int pixels=ptr1-ptr+1;
+ *dst++=257-pixels;
+ *dst++=*ptr;
+ ptr=ptr1;
+ }
+ }
+ return dst;
+}
+
+#define GRAY(r,g,b) (((r)*20+(g)*32+(b)*12)/64)
+
+void
+DjVuToPS::
+store_page_setup(ByteStream &str,
+ int dpi,
+ const GRect &grect,
+ int align )
+{
+ /* Will store PostScript code necessary to prepare page for
+ the coming \Ref{DjVuImage}. This is basically a scaling
+ code plus initialization of some buffers. */
+ if (options.get_format() == Options::EPS)
+ write(str,
+ "/page-origstate save def\n"
+ "%% -- coordinate system\n"
+ "/image-dpi %d def\n"
+ "/image-x 0 def\n"
+ "/image-y 0 def\n"
+ "/image-width %d def\n"
+ "/image-height %d def\n"
+ "/coeff 100 image-dpi div def\n"
+ "/a11 coeff def\n"
+ "/a12 0 def\n"
+ "/a13 0 def\n"
+ "/a21 0 def\n"
+ "/a22 coeff def\n"
+ "/a23 0 def\n"
+ "[a11 a21 a12 a22 a13 a23] concat\n"
+ "gsave 0 0 image-width image-height rectclip\n"
+ "%% -- begin printing\n",
+ dpi, grect.width(), grect.height() );
+ else
+ {
+ int margin = 0;
+ const char *xauto = "false";
+ const char *xportrait = "false";
+ const char *xfit = "false";
+ if (options.get_orientation()==Options::AUTO)
+ xauto = "true";
+ if (options.get_orientation()==Options::PORTRAIT)
+ xportrait = "true";
+ if (options.get_zoom()<=0)
+ xfit = "true";
+ if (options.get_cropmarks())
+ margin = 36;
+ else if (options.get_frame())
+ margin = 6;
+ write(str,
+ "/page-origstate save def\n"
+ "%% -- coordinate system\n"
+ "/auto-orient %s def\n"
+ "/portrait %s def\n"
+ "/fit-page %s def\n"
+ "/zoom %d def\n"
+ "/image-dpi %d def\n"
+ "clippath pathbbox newpath\n"
+ "2 index sub exch 3 index sub\n"
+ "/page-width exch def\n"
+ "/page-height exch def\n"
+ "/page-y exch def\n"
+ "/page-x exch def\n"
+ "/image-x 0 def\n"
+ "/image-y 0 def\n"
+ "/image-width %d def\n"
+ "/image-height %d def\n"
+ "/margin %d def\n"
+ "/halign %d def\n"
+ "/valign 0 def\n",
+ xauto, xportrait, xfit, options.get_zoom(),
+ dpi, grect.width(), grect.height(),
+ margin, align );
+ write(str,
+ "%% -- position page\n"
+ "auto-orient {\n"
+ " image-height image-width sub\n"
+ " page-height page-width sub\n"
+ " mul 0 ge /portrait exch def\n"
+ "} if\n"
+ "fit-page {\n"
+ " /page-width page-width margin sub\n"
+ " halign 0 eq { margin sub } if def\n"
+ " /page-height page-height margin sub\n"
+ " valign 0 eq { margin sub } if def\n"
+ " /page-x page-x halign 0 ge { margin add } if def\n"
+ " /page-y page-y valign 0 ge { margin add } if def\n"
+ "} if\n"
+ "portrait {\n"
+ " fit-page {\n"
+ " image-height page-height div\n"
+ " image-width page-width div\n"
+ " gt {\n"
+ " page-height image-height div /coeff exch def\n"
+ " } {\n"
+ " page-width image-width div /coeff exch def\n"
+ " } ifelse\n"
+ " } {\n"
+ " /coeff 72 image-dpi div zoom mul 100 div def\n"
+ " } ifelse\n"
+ " /start-x page-x page-width image-width\n"
+ " coeff mul sub 2 div halign 1 add mul add def\n"
+ " /start-y page-y page-height image-height\n"
+ " coeff mul sub 2 div valign 1 add mul add def\n"
+ " /a11 coeff def\n"
+ " /a12 0 def\n"
+ " /a13 start-x def\n"
+ " /a21 0 def\n"
+ " /a22 coeff def\n"
+ " /a23 start-y def\n"
+ "} { %% landscape\n"
+ " fit-page {\n"
+ " image-height page-width div\n"
+ " image-width page-height div\n"
+ " gt {\n"
+ " page-width image-height div /coeff exch def\n"
+ " } {\n"
+ " page-height image-width div /coeff exch def\n"
+ " } ifelse\n"
+ " } {\n"
+ " /coeff 72 image-dpi div zoom mul 100 div def\n"
+ " } ifelse\n"
+ " /start-x page-x page-width add page-width image-height\n"
+ " coeff mul sub 2 div valign 1 add mul sub def\n"
+ " /start-y page-y page-height image-width\n"
+ " coeff mul sub 2 div halign 1 add mul add def\n"
+ " /a11 0 def\n"
+ " /a12 coeff neg def\n"
+ " /a13 start-x image-y coeff neg mul sub def\n"
+ " /a21 coeff def\n"
+ " /a22 0 def\n"
+ " /a23 start-y image-x coeff mul add def \n"
+ "} ifelse\n"
+ "[a11 a21 a12 a22 a13 a23] concat\n"
+ "gsave 0 0 image-width image-height rectclip\n"
+ "%% -- begin print\n");
+ }
+}
+
+void
+DjVuToPS::
+store_page_trailer(ByteStream &str)
+{
+ write(str,
+ "%% -- end print\n"
+ "grestore\n");
+ if (options.get_frame())
+ write(str,
+ "%% Drawing frame\n"
+ "gsave 0.7 setgray 0.5 coeff div setlinewidth 0 0\n"
+ "image-width image-height rectstroke\n"
+ "grestore\n");
+ if (options.get_cropmarks() &&
+ options.get_format() != Options::EPS )
+ write(str,
+ "%% Drawing crop marks\n"
+ "/cm { gsave translate rotate 1 coeff div dup scale\n"
+ " 0 setgray 0.5 setlinewidth -36 0 moveto 0 0 lineto\n"
+ " 0 -36 lineto stroke grestore } bind def\n"
+ "0 0 0 cm 180 image-width image-height cm\n"
+ "90 image-width 0 cm 270 0 image-height cm\n");
+ write(str,
+ "page-origstate restore\n");
+}
+
+static int
+compute_red(int w, int h, int rw, int rh)
+{
+ for (int red=1; red<16; red++)
+ if (((w+red-1)/red==rw) && ((h+red-1)/red==rh))
+ return red;
+ return 16;
+}
+
+static int
+get_bg_red(GP<DjVuImage> dimg)
+{
+ GP<GPixmap> pm = 0;
+ // Access image size
+ int width = dimg->get_width();
+ int height = dimg->get_height();
+ if (width<=0 || height<=0) return 0;
+ // CASE1: Incremental BG IW44Image
+ GP<IW44Image> bg44 = dimg->get_bg44();
+ if (bg44)
+ {
+ int w = bg44->get_width();
+ int h = bg44->get_height();
+ // Avoid silly cases
+ if (w==0 || h==0 || width==0 || height==0)
+ return 0;
+ return compute_red(width,height,w,h);
+ }
+ // CASE 2: Raw background pixmap
+ GP<GPixmap> bgpm = dimg->get_bgpm();
+ if (bgpm)
+ {
+ int w = bgpm->columns();
+ int h = bgpm->rows();
+ // Avoid silly cases
+ if (w==0 || h==0 || width==0 || height==0)
+ return 0;
+ return compute_red(width,height,w,h);
+ }
+ return 0;
+}
+
+static GP<GPixmap>
+get_bg_pixmap(GP<DjVuImage> dimg, const GRect &rect)
+{
+ GP<GPixmap> pm = 0;
+ // Access image size
+ int width = dimg->get_width();
+ int height = dimg->get_height();
+ GP<DjVuInfo> info = dimg->get_info();
+ if (width<=0 || height<=0 || !info) return 0;
+ // CASE1: Incremental BG IW44Image
+ GP<IW44Image> bg44 = dimg->get_bg44();
+ if (bg44)
+ {
+ int w = bg44->get_width();
+ int h = bg44->get_height();
+ // Avoid silly cases
+ if (w==0 || h==0 || width==0 || height==0)
+ return 0;
+ pm = bg44->get_pixmap(1,rect);
+ return pm;
+ }
+ // CASE 2: Raw background pixmap
+ GP<GPixmap> bgpm = dimg->get_bgpm();
+ if (bgpm)
+ {
+ int w = bgpm->columns();
+ int h = bgpm->rows();
+ // Avoid silly cases
+ if (w==0 || h==0 || width==0 || height==0)
+ return 0;
+ pm->init(*bgpm, rect);
+ return pm;
+ }
+ // FAILURE
+ return 0;
+}
+
+void
+DjVuToPS::
+make_gamma_ramp(GP<DjVuImage> dimg)
+{
+ double targetgamma = options.get_gamma();
+ double whitepoint = (options.get_sRGB() ? 255 : 280);
+ for (int i=0; i<256; i++)
+ ramp[i] = i;
+ if (! dimg->get_info())
+ return;
+ if (targetgamma < 0.1)
+ return;
+ double filegamma = dimg->get_info()->gamma;
+ double correction = filegamma / targetgamma;
+ if (correction<0.1 || correction>10)
+ return;
+ {
+ for (int i=0; i<256; i++)
+ {
+ double x = (double)(i)/255.0;
+ if (correction != 1.0)
+ x = pow(x, correction);
+ int j = (int) floor(whitepoint * x + 0.5);
+ ramp[i] = (j>255) ? 255 : (j<0) ? 0 : j;
+ }
+ }
+}
+
+void
+DjVuToPS::
+print_fg_2layer(ByteStream &str,
+ GP<DjVuImage> dimg,
+ const GRect &prn_rect,
+ unsigned char *blit_list)
+{
+ // Pure-jb2 or color-jb2 case.
+ GPixel p;
+ int currentx=0;
+ int currenty=0;
+ GP<DjVuPalette> pal = dimg->get_fgbc();
+ GP<JB2Image> jb2 = dimg->get_fgjb();
+ if (! jb2) return;
+ int num_blits = jb2->get_blit_count();
+ int current_blit;
+ for(current_blit=0; current_blit<num_blits; current_blit++)
+ {
+ if (blit_list[current_blit])
+ {
+ JB2Blit *blit = jb2->get_blit(current_blit);
+ if ((pal) && !(options.get_mode()==Options::BW))
+ {
+ pal->index_to_color(pal->colordata[current_blit], p);
+ if (options.get_color())
+ {
+ write(str,"/%d %d %d %f %f %f c\n",
+ blit->shapeno,
+ blit->left-currentx, blit->bottom-currenty,
+ ramp[p.r]/255.0, ramp[p.g]/255.0, ramp[p.b]/255.0);
+ }
+ else
+ {
+ write(str,"/%d %d %d %f c\n",
+ blit->shapeno,
+ blit->left-currentx, blit->bottom-currenty,
+ ramp[GRAY(p.r, p.g, p.b)]/255.0);
+ }
+ }
+ else
+ {
+ write(str,"/%d %d %d s\n",
+ blit->shapeno,
+ blit->left-currentx, blit->bottom-currenty);
+ }
+ currentx = blit->left;
+ currenty = blit->bottom;
+ }
+ }
+}
+
+void
+DjVuToPS::
+print_fg_3layer(ByteStream &str,
+ GP<DjVuImage> dimg,
+ const GRect &cprn_rect,
+ unsigned char *blit_list )
+{
+ GRect prn_rect;
+ GP<GPixmap> brush = dimg->get_fgpm();
+ if (! brush) return;
+ int br = brush->rows();
+ int bc = brush->columns();
+ int red = compute_red(dimg->get_width(),dimg->get_height(),bc,br);
+ prn_rect.ymin = (cprn_rect.ymin)/red;
+ prn_rect.xmin = (cprn_rect.xmin)/red;
+ prn_rect.ymax = (cprn_rect.ymax+red-1)/red;
+ prn_rect.xmax = (cprn_rect.xmax+red-1)/red;
+ int color_nb = ((options.get_color()) ? 3 : 1);
+ GP<JB2Image> jb2 = dimg->get_fgjb();
+ if (! jb2) return;
+ int pw = bc;
+ int ph = 2;
+
+ write(str,
+ "/P {\n"
+ " 11 dict dup begin 4 1 roll\n"
+ " /PatternType 1 def\n"
+ " /PaintType 1 def\n"
+ " /TilingType 1 def\n"
+ " /H exch def\n"
+ " /W exch def\n"
+ " /Red %d def\n"
+ " /PatternString exch def\n"
+ " /XStep W Red mul def\n"
+ " /YStep H Red mul def\n"
+ " /BBox [0 0 XStep YStep] def\n"
+ " /PaintProc { begin\n"
+ " Red dup scale\n"
+ " << /ImageType 1 /Width W /Height H\n"
+ " /BitsPerComponent 8 /Interpolate false\n"
+ " /Decode [%s] /ImageMatrix [1 0 0 1 0 0]\n"
+ " /DataSource PatternString >> image\n"
+ " end } bind def\n"
+ " 0 0 XStep YStep rectclip\n"
+ " end matrix makepattern\n"
+ " /Pattern setcolorspace setpattern\n"
+ " 0 0 moveto\n"
+ "} def\n", red, (color_nb == 1) ? "0 1" : "0 1 0 1 0 1" );
+
+ unsigned char *s;
+ GPBuffer<unsigned char> gs(s,pw*ph*color_nb);
+ unsigned char *s_ascii_encoded;
+ GPBuffer<unsigned char> gs_ascii_encoded(s_ascii_encoded,pw*ph*2*color_nb);
+ {
+ for (int y=prn_rect.ymin; y<prn_rect.ymax; y+=ph)
+ for (int x=prn_rect.xmin; x<prn_rect.xmax; x+=pw)
+ {
+ int w = ((x+pw > prn_rect.xmax) ? prn_rect.xmax-x : pw);
+ int h = ((y+ph > prn_rect.ymax) ? prn_rect.ymax-y : ph);
+ int currentx = x * red;
+ int currenty = y * red;
+ // Find first intersecting blit
+ int current_blit;
+ int num_blits = jb2->get_blit_count();
+ GRect rect1(currentx,currenty, w*red, h*red);
+ for(current_blit=0; current_blit<num_blits; current_blit++)
+ if (blit_list[current_blit])
+ {
+ JB2Blit *blit = jb2->get_blit(current_blit);
+ GRect rect2(blit->left, blit->bottom,
+ jb2->get_shape(blit->shapeno).bits->columns(),
+ jb2->get_shape(blit->shapeno).bits->rows());
+ if (rect2.intersect(rect1,rect2))
+ break;
+ }
+ if (current_blit >= num_blits)
+ continue;
+ // Setup pattern
+ write(str,"gsave %d %d translate\n", currentx, currenty);
+ write(str,"<~");
+ unsigned char *q = s;
+ for(int current_row = y; current_row<y+h; current_row++)
+ {
+ GPixel *row_pix = (*brush)[current_row];
+ for(int current_col = x; current_col<x+w; current_col++)
+ {
+ GPixel &p = row_pix[current_col];
+ if (color_nb>1)
+ {
+ *q++ = ramp[p.r];
+ *q++ = ramp[p.g];
+ *q++ = ramp[p.b];
+ }
+ else
+ {
+ *q++ = ramp[GRAY(p.r,p.g,p.b)];
+ }
+ }
+ }
+ unsigned char *stop_ascii =
+ ASCII85_encode(s_ascii_encoded,s,s+w*h*color_nb);
+ *stop_ascii++='\0';
+ write(str,"%s",s_ascii_encoded);
+ write(str,"~> %d %d P\n", w, h);
+ // Keep performing blits
+ for(; current_blit<num_blits; current_blit++)
+ if (blit_list[current_blit])
+ {
+ JB2Blit *blit = jb2->get_blit(current_blit);
+ GRect rect2(blit->left, blit->bottom,
+ jb2->get_shape(blit->shapeno).bits->columns(),
+ jb2->get_shape(blit->shapeno).bits->rows());
+ if (rect2.intersect(rect1,rect2))
+ {
+ write(str,"/%d %d %d s\n",
+ blit->shapeno,
+ blit->left-currentx, blit->bottom-currenty);
+ currentx = blit->left;
+ currenty = blit->bottom;
+ }
+ }
+ write(str,"grestore\n");
+ }
+ // Cleanup
+ }
+}
+
+void
+DjVuToPS::
+print_fg(ByteStream &str,
+ GP<DjVuImage> dimg,
+ const GRect &prn_rect )
+{
+ GP<JB2Image> jb2=dimg->get_fgjb();
+ if (! jb2) return;
+ int num_blits = jb2->get_blit_count();
+ int num_shapes = jb2->get_shape_count();
+ unsigned char *dict_shapes = 0;
+ unsigned char *blit_list = 0;
+ GPBuffer<unsigned char> gdict_shapes(dict_shapes,num_shapes);
+ GPBuffer<unsigned char> gblit_list(blit_list,num_blits);
+ for(int i=0; i<num_shapes; i++)
+ {
+ dict_shapes[i]=0;
+ }
+ for(int current_blit=0; current_blit<num_blits; current_blit++)
+ {
+ JB2Blit *blit = jb2->get_blit(current_blit);
+ JB2Shape *shape = & jb2->get_shape(blit->shapeno);
+ blit_list[current_blit] = 0;
+ if (! shape->bits)
+ continue;
+ GRect rect2(blit->left, blit->bottom,
+ shape->bits->columns(), shape->bits->rows());
+ if (rect2.intersect(rect2, prn_rect))
+ {
+ dict_shapes[blit->shapeno] = 1;
+ blit_list[current_blit] = 1;
+ }
+ }
+ write(str,
+ "%% --- now doing the foreground\n"
+ "gsave DjVuColorSpace setcolorspace\n" );
+ // Define font
+ write(str,
+ "/$DjVuLocalFont 7 dict def\n"
+ "$DjVuLocalFont begin\n"
+ "/FontType 3 def \n"
+ "/FontMatrix [1 0 0 1 0 0] def\n"
+ "/FontBBox [0 0 1 .5] def\n"
+ "/CharStrings %d dict def\n"
+ "/Encoding 2 array def\n"
+ "0 1 1 {Encoding exch /.notdef put} for \n"
+ "CharStrings begin\n"
+ "/.notdef {} def\n",
+ num_shapes+1);
+ for(int current_shape=0; current_shape<num_shapes; current_shape++)
+ {
+ if (dict_shapes[current_shape])
+ {
+ JB2Shape *shape = & jb2->get_shape(current_shape);
+ GP<GBitmap> bitmap = shape->bits;
+ int rows = bitmap->rows();
+ int columns = bitmap->columns();
+ int nbytes = (columns+7)/8*rows+1;
+ int nrows = rows;
+ int nstrings=0;
+ if (nbytes>(int)ps_string_size) //max string length
+ {
+ nrows=ps_string_size/((columns+7)/8);
+ nbytes=(columns+7)/8*nrows+1;
+ }
+ unsigned char *s_start;
+ GPBuffer<unsigned char> gs_start(s_start,nbytes);
+ unsigned char *s_ascii;
+ GPBuffer<unsigned char> gs_ascii(s_ascii,nbytes*2);
+ write(str,"/%d {",current_shape);
+
+ unsigned char *s = s_start;
+ for(int current_row=0; current_row<rows; current_row++)
+ {
+ unsigned char * row_bits = (*bitmap)[current_row];
+ unsigned char acc = 0;
+ unsigned char mask = 0;
+ for(int current_col=0; current_col<columns; current_col++)
+ {
+ if (mask == 0)
+ mask = 0x80;
+ if (row_bits[current_col])
+ acc |= mask;
+ mask >>= 1;
+ if (mask == 0)
+ {
+ *s=acc;
+ s++;
+ acc = mask = 0;
+ }
+ }
+ if (mask != 0)
+ {
+ *s=acc;
+ s++;
+ }
+ if (!((current_row+1)%nrows))
+ {
+ unsigned char *stop_ascii = ASCII85_encode(s_ascii,s_start,s);
+ *stop_ascii++='\0';
+ write(str,"<~%s~> ",s_ascii);
+ s=s_start;
+ nstrings++;
+ }
+ }
+ if (s!=s_start)
+ {
+ unsigned char *stop_ascii = ASCII85_encode(s_ascii,s_start,s);
+ *stop_ascii++='\0';
+ write(str,"<~%s~> ",s_ascii);
+ nstrings++;
+ }
+ if (nstrings==1)
+ write(str," %d %d g} def\n", columns, rows);
+ else
+ write(str," %d %d %d gn} def\n", columns, rows,nstrings);
+ }
+ }
+ write(str,
+ "end\n"
+ "/BuildGlyph {\n"
+ " exch /CharStrings get exch\n"
+ " 2 copy known not\n"
+ " {pop /.notdef} if\n"
+ " get exec \n"
+ "} bind def\n"
+ "end\n"
+ "/LocalDjVuFont $DjVuLocalFont definefont pop\n"
+ "/LocalDjVuFont findfont setfont\n" );
+ write(str,
+ "-%d -%d translate\n"
+ "0 0 moveto\n",
+ prn_rect.xmin, prn_rect.ymin);
+ // Print the foreground layer
+ if (dimg->get_fgpm() && !(options.get_mode()==Options::BW))
+ print_fg_3layer(str, dimg, prn_rect, blit_list);
+ else
+ print_fg_2layer(str, dimg, prn_rect, blit_list);
+ write(str, "/LocalDjVuFont undefinefont grestore\n");
+}
+
+
+void
+DjVuToPS::
+print_bg(ByteStream &str,
+ GP<DjVuImage> dimg,
+ const GRect &cprn_rect)
+{
+ GP<GPixmap> pm;
+ GRect prn_rect;
+ double print_done = 0;
+ int red = 0;
+ write(str, "%% --- now doing the background\n");
+ if (! (red = get_bg_red(dimg)))
+ return;
+ write(str,
+ "gsave -%d -%d translate\n"
+ "/bgred %d def bgred bgred scale\n",
+ cprn_rect.xmin % red,
+ cprn_rect.ymin % red,
+ red);
+ prn_rect.ymin = (cprn_rect.ymin)/red;
+ prn_rect.ymax = (cprn_rect.ymax+red-1)/red;
+ prn_rect.xmin = (cprn_rect.xmin)/red;
+ prn_rect.xmax = (cprn_rect.xmax+red-1)/red;
+ // Display image
+ int band_bytes = 125000;
+ int band_height = band_bytes/prn_rect.width();
+ int buffer_size = band_height*prn_rect.width();
+ int ps_chunk_height = 30960/prn_rect.width()+1;
+ buffer_size = buffer_size*23/10;
+ bool do_color = options.get_color();
+ if (!dimg->is_legal_photo() &&
+ !dimg->is_legal_compound() ||
+ options.get_mode()==Options::BW)
+ do_color = false;
+ if (do_color)
+ buffer_size *= 3;
+ if (do_color)
+ write(str,
+ "/bufferR %d string def\n"
+ "/bufferG %d string def\n"
+ "/bufferB %d string def\n"
+ "DjVuColorSpace setcolorspace\n"
+ "<< /ImageType 1\n"
+ " /Width %d\n"
+ " /Height %d\n"
+ " /BitsPerComponent 8\n"
+ " /Decode [0 1 0 1 0 1]\n"
+ " /ImageMatrix [1 0 0 1 0 0]\n"
+ " /MultipleDataSources true\n"
+ " /DataSource [ { ReadR } { ReadG } { ReadB } ]\n"
+ " /Interpolate false >> image\n",
+ ps_chunk_height*prn_rect.width(),
+ ps_chunk_height*prn_rect.width(),
+ ps_chunk_height*prn_rect.width(),
+ prn_rect.width(), prn_rect.height());
+ else
+ write(str,
+ "DjVuColorSpace setcolorspace\n"
+ "<< /ImageType 1\n"
+ " /Width %d\n"
+ " /Height %d\n"
+ " /BitsPerComponent 8\n"
+ " /Decode [0 1]\n"
+ " /ImageMatrix [1 0 0 1 0 0]\n"
+ " /DataSource currentfile /ASCII85Decode\n"
+ " filter /RunLengthDecode filter\n"
+ " /Interpolate false >> image\n",
+ prn_rect.width(), prn_rect.height());
+
+ unsigned char *buffer;
+ GPBuffer<unsigned char> gbuffer(buffer,buffer_size);
+ unsigned char *rle_in;
+ GPBuffer<unsigned char> grle_in(rle_in,ps_chunk_height*prn_rect.width());
+ unsigned char *rle_out;
+ GPBuffer<unsigned char> grle_out(rle_out,2*ps_chunk_height*prn_rect.width());
+ {
+ // Start storing image in bands
+ unsigned char * rle_out_end = rle_out;
+ GRect grectBand = prn_rect;
+ grectBand.ymax = grectBand.ymin;
+ while(grectBand.ymax < prn_rect.ymax)
+ {
+ GP<GPixmap> pm = 0;
+ // Compute next band
+ grectBand.ymin=grectBand.ymax;
+ grectBand.ymax=grectBand.ymin+band_bytes/grectBand.width();
+ if (grectBand.ymax>prn_rect.ymax)
+ grectBand.ymax=prn_rect.ymax;
+ pm = get_bg_pixmap(dimg, grectBand);
+ unsigned char *buf_ptr = buffer;
+ if (pm)
+ {
+ if (do_color)
+ {
+ int y=0;
+ while(y<grectBand.height())
+ {
+ int row, y1;
+ unsigned char *ptr, *ptr1;
+ // Doing R component of current chunk
+ for (row=0,ptr=rle_in,y1=y;
+ row<ps_chunk_height && y1<grectBand.height();
+ row++,y1++)
+ {
+ GPixel *pix = (*pm)[y1];
+ for (int x=grectBand.width(); x>0; x--,pix++)
+ *ptr++ = ramp[pix->r];
+ }
+ ptr1 = RLE_encode(rle_out, rle_in, ptr);
+ *ptr1++ = 0x80;
+ buf_ptr = ASCII85_encode(buf_ptr, rle_out, ptr1);
+ *buf_ptr++ = '~'; *buf_ptr++ = '>'; *buf_ptr++ = '\n';
+ // Doing G component of current chunk
+ for (row=0,ptr=rle_in,y1=y;
+ row<ps_chunk_height && y1<grectBand.height();
+ row++,y1++)
+ {
+ GPixel *pix = (*pm)[y1];
+ for (int x=grectBand.width(); x>0; x--,pix++)
+ *ptr++ = ramp[pix->g];
+ }
+ ptr1 = RLE_encode(rle_out, rle_in, ptr);
+ *ptr1++ = 0x80;
+ buf_ptr = ASCII85_encode(buf_ptr, rle_out, ptr1);
+ *buf_ptr++ = '~';
+ *buf_ptr++ = '>';
+ *buf_ptr++ = '\n';
+ // Doing B component of current chunk
+ for (row=0, ptr=rle_in, y1=y;
+ row<ps_chunk_height && y1<grectBand.height();
+ row++,y1++)
+ {
+ GPixel *pix = (*pm)[y1];
+ for (int x=grectBand.width(); x>0; x--,pix++)
+ *ptr++ = ramp[pix->b];
+ }
+ ptr1 = RLE_encode(rle_out, rle_in, ptr);
+ *ptr1++ = 0x80;
+ buf_ptr = ASCII85_encode(buf_ptr, rle_out, ptr1);
+ *buf_ptr++ = '~';
+ *buf_ptr++ = '>';
+ *buf_ptr++ = '\n';
+ y=y1;
+ if (refresh_cb)
+ refresh_cb(refresh_cl_data);
+ } //while (y>=0)
+ }
+ else
+ {
+ // Don't use color
+ int y=0;
+ while(y<grectBand.height())
+ {
+ unsigned char *ptr = rle_in;
+ for(int row=0;
+ row<ps_chunk_height && y<grectBand.height();
+ row++,y++)
+ {
+ GPixel *pix = (*pm)[y];
+ for (int x=grectBand.width(); x>0; x--,pix++)
+ *ptr++ = ramp[GRAY(pix->r,pix->g,pix->b)];
+ }
+ rle_out_end = RLE_encode(rle_out_end, rle_in, ptr);
+ unsigned char *encode_to
+ = rle_out+(rle_out_end-rle_out)/4*4;
+ int bytes_left = rle_out_end-encode_to;
+ buf_ptr = ASCII85_encode(buf_ptr, rle_out, encode_to);
+ *buf_ptr++ = '\n';
+ memcpy(rle_out, encode_to, bytes_left);
+ rle_out_end = rle_out+bytes_left;
+ if (refresh_cb)
+ refresh_cb(refresh_cl_data);
+ }
+ }
+ } // if (pm)
+ str.writall(buffer, buf_ptr-buffer);
+ if (prn_progress_cb)
+ {
+ double done=(double)(grectBand.ymax
+ - prn_rect.ymin)/prn_rect.height();
+ if ((int) (20*print_done)!=(int) (20*done))
+ {
+ print_done=done;
+ prn_progress_cb(done, prn_progress_cl_data);
+ }
+ }
+ } // while(grectBand.yax<grect.ymax)
+ if (! do_color)
+ {
+ unsigned char * buf_ptr = buffer;
+ *rle_out_end++ = 0x80;
+ buf_ptr = ASCII85_encode(buf_ptr, rle_out, rle_out_end);
+ *buf_ptr++='~';
+ *buf_ptr++='>';
+ *buf_ptr++='\n';
+ str.writall(buffer, buf_ptr-buffer);
+ }
+ }
+ //restore the scaling
+ write(str, "grestore\n");
+}
+
+void
+DjVuToPS::
+print_image_lev1(ByteStream &str,
+ GP<DjVuImage> dimg,
+ const GRect &prn_rect)
+{
+ double print_done=0;
+ GRect all(0,0, dimg->get_width(),dimg->get_height());
+ GP<GPixmap> pm;
+ GP<GBitmap> bm;
+ GRect test(0,0,1,1);
+ if (options.get_mode() == Options::FORE)
+ pm = dimg->get_fg_pixmap(test, all);
+ else if (options.get_mode() == Options::BACK)
+ pm = dimg->get_bg_pixmap(test, all);
+ else if (options.get_mode() != Options::BW)
+ pm = dimg->get_pixmap(test, all);
+ if (! pm)
+ bm = dimg->get_bitmap(test,all);
+ if (! pm && ! bm)
+ return;
+ write(str,
+ "%% --- now doing a level 1 image\n"
+ "gsave\n");
+ // Display image
+ int band_bytes=125000;
+ int band_height = band_bytes/prn_rect.width();
+ int buffer_size = band_height*prn_rect.width();
+ buffer_size = buffer_size*21/10;
+ bool do_color = false;
+ bool do_color_or_gray = false;
+ if (pm && (options.get_mode() != Options::BW))
+ do_color_or_gray = true;
+ if (do_color_or_gray && options.get_color())
+ do_color = true;
+ if (do_color)
+ buffer_size *= 3;
+ if (do_color)
+ write(str, "/buffer24 %d string def\n", 3*prn_rect.width());
+ if (do_color_or_gray)
+ write(str, "/buffer8 %d string def\n", prn_rect.width());
+ else
+ write(str, "/buffer8 %d string def\n", (prn_rect.width()+7)/8);
+ if (do_color)
+ {
+ write(str,
+ "%d %d 8 [ 1 0 0 1 0 0 ]\n"
+ "{ ColorProc } false 3 ColorImage\n",
+ prn_rect.width(), prn_rect.height());
+ }
+ else if (do_color_or_gray)
+ {
+ write(str,
+ "%d %d 8 [ 1 0 0 1 0 0 ]\n"
+ "{ currentfile buffer8 readhexstring pop } image\n",
+ prn_rect.width(), prn_rect.height());
+ }
+ else
+ {
+ write(str,
+ "%d %d 1 [ 1 0 0 1 0 0 ]\n"
+ "{ currentfile buffer8 readhexstring pop } image\n",
+ prn_rect.width(), prn_rect.height());
+ }
+ unsigned char * buffer;
+ GPBuffer<unsigned char> gbuffer(buffer,buffer_size);
+ {
+ // Start storing image in bands
+ GRect grectBand = prn_rect;
+ grectBand.ymax = grectBand.ymin;
+ while(grectBand.ymax < prn_rect.ymax)
+ {
+ // Compute next band
+ grectBand.ymin = grectBand.ymax;
+ grectBand.ymax = grectBand.ymin+band_bytes/grectBand.width();
+ if (grectBand.ymax > prn_rect.ymax)
+ grectBand.ymax = prn_rect.ymax;
+ GRect all(0,0, dimg->get_width(),dimg->get_height());
+ pm = 0;
+ bm = 0;
+ if (do_color_or_gray)
+ {
+ if (options.get_mode() == Options::FORE)
+ pm = dimg->get_fg_pixmap(grectBand, all);
+ else if (options.get_mode() == Options::BACK)
+ pm = dimg->get_bg_pixmap(grectBand, all);
+ else
+ pm = dimg->get_pixmap(grectBand, all);
+ }
+ else
+ {
+ bm = dimg->get_bitmap(grectBand, all);
+ }
+ // Store next band
+ unsigned char *buf_ptr = buffer;
+ int symbols=0;
+ for (int y=0; y<grectBand.height(); y++)
+ {
+ if (pm && do_color_or_gray)
+ {
+ GPixel *pix = (*pm)[y];
+ for (int x=grectBand.width(); x>0; x--, pix++)
+ {
+ if (do_color)
+ {
+ char *data;
+ data = bin2hex[ramp[pix->r]];
+ *buf_ptr++ = data[0];
+ *buf_ptr++ = data[1];
+ data = bin2hex[ramp[pix->g]];
+ *buf_ptr++ = data[0];
+ *buf_ptr++ = data[1];
+ data = bin2hex[ramp[pix->b]];
+ *buf_ptr++ = data[0];
+ *buf_ptr++ = data[1];
+ symbols += 6;
+ }
+ else
+ {
+ char *data;
+ data = bin2hex[ramp[GRAY(pix->r,pix->g,pix->b)]];
+ *buf_ptr++ = data[0];
+ *buf_ptr++ = data[1];
+ symbols += 2;
+ }
+ if (symbols>70)
+ {
+ *buf_ptr++ = '\n';
+ symbols=0;
+ }
+ }
+ }
+ else if (bm)
+ {
+ unsigned char *pix = (*bm)[y];
+ unsigned char acc = 0;
+ unsigned char mask = 0;
+ char *data;
+ for (int x=grectBand.width(); x>0; x--, pix++)
+ {
+ if (mask == 0)
+ mask = 0x80;
+ if (! *pix)
+ acc |= mask;
+ mask >>= 1;
+ if (mask == 0)
+ {
+ data = bin2hex[acc];
+ acc = 0;
+ *buf_ptr++ = data[0];
+ *buf_ptr++ = data[1];
+ symbols += 2;
+ if (symbols>70)
+ {
+ *buf_ptr++ = '\n';
+ symbols = 0;
+ }
+ }
+ }
+ if (mask != 0)
+ {
+ data = bin2hex[acc];
+ *buf_ptr++ = data[0];
+ *buf_ptr++ = data[1];
+ symbols += 2;
+ }
+ }
+ if (refresh_cb)
+ refresh_cb(refresh_cl_data);
+ }
+ str.writall(buffer, buf_ptr-buffer);
+ if (prn_progress_cb)
+ {
+ double done=(double) (grectBand.ymax
+ - prn_rect.ymin)/prn_rect.height();
+ if ((int) (20*print_done)!=(int) (20*done))
+ {
+ print_done=done;
+ prn_progress_cb(done, prn_progress_cl_data);
+ }
+ }
+ }
+ write(str, "\n");
+ }
+ write(str, "grestore\n");
+}
+
+void
+DjVuToPS::
+print_image_lev2(ByteStream &str,
+ GP<DjVuImage> dimg,
+ const GRect &prn_rect)
+{
+ double print_done=0;
+ GRect all(0,0, dimg->get_width(),dimg->get_height());
+ GP<GPixmap> pm;
+ GRect test(0,0,1,1);
+ if (options.get_mode() == Options::FORE)
+ pm = dimg->get_fg_pixmap(test, all);
+ else if (options.get_mode() == Options::BACK)
+ pm = dimg->get_bg_pixmap(test, all);
+ else if (options.get_mode() != Options::BW)
+ pm = dimg->get_pixmap(test, all);
+ if (! pm)
+ return;
+ write(str,
+ "%% --- now doing a level 2 image\n"
+ "gsave\n");
+ // Display image
+ int band_bytes=125000;
+ int band_height = band_bytes/prn_rect.width();
+ int buffer_size = band_height*prn_rect.width();
+ int ps_chunk_height = 30960/prn_rect.width()+1;
+ buffer_size = buffer_size*21/10 + 32;
+ bool do_color = options.get_color();
+ if (do_color)
+ {
+ buffer_size *= 3;
+ write(str,
+ "/bufferR %d string def\n"
+ "/bufferG %d string def\n"
+ "/bufferB %d string def\n"
+ "DjVuColorSpace setcolorspace\n"
+ "<< /ImageType 1\n"
+ " /Width %d\n"
+ " /Height %d\n"
+ " /BitsPerComponent 8\n"
+ " /Decode [0 1 0 1 0 1]\n"
+ " /ImageMatrix [1 0 0 1 0 0]\n"
+ " /MultipleDataSources true\n"
+ " /DataSource [ { ReadR } { ReadG } { ReadB } ]\n"
+ " /Interpolate false >> image\n",
+ ps_chunk_height*prn_rect.width(),
+ ps_chunk_height*prn_rect.width(),
+ ps_chunk_height*prn_rect.width(),
+ prn_rect.width(), prn_rect.height());
+ }
+ else
+ {
+ write(str,
+ "DjVuColorSpace setcolorspace\n"
+ "<< /ImageType 1\n"
+ " /Width %d\n"
+ " /Height %d\n"
+ " /BitsPerComponent 8\n"
+ " /Decode [0 1]\n"
+ " /ImageMatrix [1 0 0 1 0 0]\n"
+ " /DataSource currentfile /ASCII85Decode\n"
+ " filter /RunLengthDecode filter\n"
+ " /Interpolate false >> image\n",
+ prn_rect.width(), prn_rect.height());
+ }
+ unsigned char *buffer;
+ GPBuffer<unsigned char> gbuffer(buffer,buffer_size);
+ unsigned char *rle_in;
+ GPBuffer<unsigned char> grle_in(rle_in,ps_chunk_height*prn_rect.width());
+ unsigned char *rle_out;
+ GPBuffer<unsigned char> grle_out(rle_out,2*ps_chunk_height*prn_rect.width());
+ {
+ // Start storing image in bands
+ unsigned char * rle_out_end = rle_out;
+ GRect grectBand = prn_rect;
+ grectBand.ymax = grectBand.ymin;
+ while(grectBand.ymax < prn_rect.ymax)
+ {
+ // Compute next band
+ grectBand.ymin = grectBand.ymax;
+ grectBand.ymax = grectBand.ymin+band_bytes/grectBand.width();
+ if (grectBand.ymax > prn_rect.ymax)
+ grectBand.ymax = prn_rect.ymax;
+ GRect all(0,0, dimg->get_width(),dimg->get_height());
+ pm = 0;
+ if (options.get_mode() == Options::FORE)
+ pm = dimg->get_fg_pixmap(grectBand, all);
+ else if (options.get_mode() == Options::BACK)
+ pm = dimg->get_bg_pixmap(grectBand, all);
+ else
+ pm = dimg->get_pixmap(grectBand, all);
+ // Store next band
+ unsigned char *buf_ptr = buffer;
+ if (do_color && pm)
+ {
+ int y=0;
+ while(y<grectBand.height())
+ {
+ int row, y1;
+ unsigned char *ptr, *ptr1;
+ // Doing R component of current chunk
+ for (row=0,ptr=rle_in,y1=y;
+ row<ps_chunk_height && y1<grectBand.height();
+ row++,y1++)
+ {
+ GPixel *pix = (*pm)[y1];
+ for (int x=grectBand.width(); x>0; x--,pix++)
+ *ptr++ = ramp[pix->r];
+ }
+ ptr1 = RLE_encode(rle_out, rle_in, ptr);
+ *ptr1++ = 0x80;
+ buf_ptr = ASCII85_encode(buf_ptr, rle_out, ptr1);
+ *buf_ptr++ = '~'; *buf_ptr++ = '>'; *buf_ptr++ = '\n';
+ // Doing G component of current chunk
+ for (row=0,ptr=rle_in,y1=y;
+ row<ps_chunk_height && y1<grectBand.height();
+ row++,y1++)
+ {
+ GPixel *pix = (*pm)[y1];
+ for (int x=grectBand.width(); x>0; x--,pix++)
+ *ptr++ = ramp[pix->g];
+ }
+ ptr1 = RLE_encode(rle_out, rle_in, ptr);
+ *ptr1++ = 0x80;
+ buf_ptr = ASCII85_encode(buf_ptr, rle_out, ptr1);
+ *buf_ptr++ = '~';
+ *buf_ptr++ = '>';
+ *buf_ptr++ = '\n';
+ // Doing B component of current chunk
+ for (row=0, ptr=rle_in, y1=y;
+ row<ps_chunk_height && y1<grectBand.height();
+ row++,y1++)
+ {
+ GPixel *pix = (*pm)[y1];
+ for (int x=grectBand.width(); x>0; x--,pix++)
+ *ptr++ = ramp[pix->b];
+ }
+ ptr1 = RLE_encode(rle_out, rle_in, ptr);
+ *ptr1++ = 0x80;
+ buf_ptr = ASCII85_encode(buf_ptr, rle_out, ptr1);
+ *buf_ptr++ = '~';
+ *buf_ptr++ = '>';
+ *buf_ptr++ = '\n';
+ y=y1;
+ if (refresh_cb)
+ refresh_cb(refresh_cl_data);
+ } //while (y>=0)
+ }
+ else if (pm)
+ {
+ // Don't use color
+ int y=0;
+ while(y<grectBand.height())
+ {
+ unsigned char *ptr = rle_in;
+ for(int row=0;
+ row<ps_chunk_height && y<grectBand.height();
+ row++,y++)
+ {
+ GPixel *pix = (*pm)[y];
+ for (int x=grectBand.width(); x>0; x--,pix++)
+ *ptr++ = ramp[GRAY(pix->r,pix->g,pix->b)];
+ }
+ rle_out_end = RLE_encode(rle_out_end, rle_in, ptr);
+ unsigned char *encode_to = rle_out
+ + (rle_out_end-rle_out)/4*4;
+ int bytes_left = rle_out_end-encode_to;
+ buf_ptr = ASCII85_encode(buf_ptr, rle_out, encode_to);
+ *buf_ptr++ = '\n';
+ memcpy(rle_out, encode_to, bytes_left);
+ rle_out_end = rle_out+bytes_left;
+ if (refresh_cb)
+ refresh_cb(refresh_cl_data);
+ }
+ if (grectBand.ymax >= prn_rect.ymax)
+ {
+ *rle_out_end++ = 0x80; // Add EOF marker
+ buf_ptr = ASCII85_encode(buf_ptr, rle_out, rle_out_end);
+ *buf_ptr++ = '~';
+ *buf_ptr++ = '>';
+ *buf_ptr++ = '\n';
+ }
+ }
+ str.writall(buffer, buf_ptr-buffer);
+ if (prn_progress_cb)
+ {
+ double done=(double) (grectBand.ymax
+ - prn_rect.ymin)/prn_rect.height();
+ if ((int) (20*print_done)!=(int) (20*done))
+ {
+ print_done=done;
+ prn_progress_cb(done, prn_progress_cl_data);
+ }
+ }
+ }
+ write(str, "\n");
+ }
+ write(str, "grestore\n");
+}
+
+static void
+get_anno_sub(IFFByteStream &iff, IFFByteStream &out)
+{
+ GUTF8String chkid;
+ while (iff.get_chunk(chkid))
+ {
+ if (iff.composite())
+ get_anno_sub(iff, out);
+ else if (chkid == "ANTa" || chkid == "ANTz" ||
+ chkid == "TXTa" || chkid == "TXTz" )
+ {
+ out.put_chunk(chkid);
+ out.copy(*iff.get_bytestream());
+ out.close_chunk();
+ }
+ iff.close_chunk();
+ }
+}
+
+static GP<ByteStream>
+get_anno(GP<DjVuFile> f)
+{
+ if (! f->anno)
+ {
+ GP<ByteStream> bs = f->get_init_data_pool()->get_stream();
+ GP<ByteStream> anno = ByteStream::create();
+ GP<IFFByteStream> in = IFFByteStream::create(bs);
+ GP<IFFByteStream> out = IFFByteStream::create(anno);
+ get_anno_sub(*in, *out);
+ f->anno = anno;
+ }
+ f->anno->seek(0);
+ return f->anno;
+}
+
+static GP<DjVuTXT>
+get_text(GP<DjVuFile> file)
+{
+ GUTF8String chkid;
+ GP<IFFByteStream> iff = IFFByteStream::create(get_anno(file));
+ while (iff->get_chunk(chkid))
+ {
+ if (chkid == "TXTa")
+ {
+ GP<DjVuTXT> txt = DjVuTXT::create();
+ txt->decode(iff->get_bytestream());
+ return txt;
+ }
+ else if (chkid == "TXTz")
+ {
+ GP<DjVuTXT> txt = DjVuTXT::create();
+ GP<ByteStream> bsiff = BSByteStream::create(iff->get_bytestream());
+ txt->decode(bsiff);
+ return txt;
+ }
+ iff->close_chunk();
+ }
+ return 0;
+}
+
+static void
+print_ps_string(const char *data, int length, ByteStream &out)
+{
+ while (*data && length>0)
+ {
+ int span = 0;
+ while (span<length && data[span]>=0x20 && data[span]<0x7f
+ && data[span]!='(' && data[span]!=')' && data[span]!='\\' )
+ span++;
+ if (span > 0)
+ {
+ out.write(data, span);
+ data += span;
+ length -= span;
+ }
+ else
+ {
+ char buffer[5];
+ sprintf(buffer,"\\%03o", *data);
+ out.write(buffer,4);
+ data += 1;
+ length -= 1;
+ }
+ }
+}
+
+static void
+print_txt_sub(DjVuTXT &txt, DjVuTXT::Zone &zone,
+ ByteStream &out,int &lastx,int &lasty)
+{
+ // Get separator
+ char separator = 0;
+ switch(zone.ztype)
+ {
+ case DjVuTXT::COLUMN:
+ separator = DjVuTXT::end_of_column; break;
+ case DjVuTXT::REGION:
+ separator = DjVuTXT::end_of_region; break;
+ case DjVuTXT::PARAGRAPH:
+ separator = DjVuTXT::end_of_paragraph; break;
+ case DjVuTXT::LINE:
+ separator = DjVuTXT::end_of_line; break;
+ case DjVuTXT::WORD:
+ separator = ' '; break;
+ default:
+ separator = 0; break;
+ }
+ // Zone children
+ if (zone.children.isempty())
+ {
+ const char *data = (const char*)txt.textUTF8 + zone.text_start;
+ int length = zone.text_length;
+ if (data[length-1] == separator)
+ length -= 1;
+ out.write("( ",2);
+ print_ps_string(data,length,out);
+ out.write(")",1);
+ GUTF8String message;
+ int tmpx= zone.rect.xmin-lastx;
+ int tmpy= zone.rect.ymin-lasty;
+ message.format(" %d %d S \n", tmpx, tmpy);
+ lastx=zone.rect.xmin;
+ lasty=zone.rect.ymin;
+ out.write((const char*)message, message.length());
+ }
+ else
+ {
+ if (zone.ztype==DjVuTXT::LINE)
+ {
+ GUTF8String message;
+ message.format("%d F\n",zone.rect.ymax-zone.rect.ymin);
+ out.write((const char*)message,message.length());
+ }
+ for (GPosition pos=zone.children; pos; ++pos)
+ print_txt_sub(txt, zone.children[pos], out,lastx,lasty);
+ }
+}
+
+static void
+print_txt(GP<DjVuTXT> txt,
+ ByteStream &out )
+{
+ if (txt)
+ {
+ int lastx=0;
+ int lasty=0;
+ GUTF8String message =
+ "%% -- now doing hidden text\n"
+ "gsave -1 -1 0 0 clip 0 0 moveto\n";
+ out.write((const char*)message,message.length());
+ print_txt_sub(*txt, txt->page_zone, out,lastx,lasty);
+ message =
+ "grestore \n";
+ out.write((const char*)message,message.length());
+ }
+}
+
+void
+DjVuToPS::
+print_image(ByteStream &str,
+ GP<DjVuImage> dimg,
+ const GRect &prn_rect,
+ GP<DjVuTXT> txt)
+{
+ /* Just outputs the specified image. The function assumes, that
+ all add-ons (like {\em document setup}, {\em page setup}) are
+ already there. It will just output the image. Since
+ output of this function will generate PostScript errors when
+ used without output of auxiliary functions, it should be
+ used carefully. */
+ DEBUG_MSG("DjVuToPS::print_image(): Printing DjVuImage to a stream\n");
+ DEBUG_MAKE_INDENT(3);
+ if (!dimg)
+ G_THROW(ERR_MSG("DjVuToPS.empty_image"));
+ if (prn_rect.isempty())
+ G_THROW(ERR_MSG("DjVuToPS.empty_rect"));
+ if (prn_progress_cb)
+ prn_progress_cb(0, prn_progress_cl_data);
+ // Compute information for chosen display mode
+ print_txt(txt, str);
+ make_gamma_ramp(dimg);
+ if (options.get_level() < 2)
+ {
+ print_image_lev1(str, dimg, prn_rect);
+ }
+ else if (options.get_level() < 3 && dimg->get_fgpm())
+ {
+ switch(options.get_mode())
+ {
+ case Options::COLOR:
+ case Options::FORE:
+ print_image_lev2(str, dimg, prn_rect);
+ break;
+ case Options::BW:
+ print_fg(str, dimg, prn_rect);
+ break;
+ case Options::BACK:
+ print_bg(str, dimg, prn_rect);
+ break;
+ }
+ }
+ else
+ {
+ switch(options.get_mode())
+ {
+ case Options::COLOR:
+ print_bg(str, dimg, prn_rect);
+ print_fg(str, dimg, prn_rect);
+ break;
+ case Options::FORE:
+ case Options::BW:
+ print_fg(str, dimg, prn_rect);
+ break;
+ case Options::BACK:
+ print_bg(str, dimg, prn_rect);
+ break;
+ }
+ }
+ if (prn_progress_cb)
+ prn_progress_cb(1, prn_progress_cl_data);
+}
+
+
+
+
+// ***********************************************************************
+// ******* PUBLIC FUNCTION FOR PRINTING A SINGLE PAGE ********************
+// ***********************************************************************
+
+
+
+
+void
+DjVuToPS::
+print(ByteStream &str,
+ GP<DjVuImage> dimg,
+ const GRect &prn_rect_in,
+ const GRect &img_rect,
+ int override_dpi)
+{
+ DEBUG_MSG("DjVuToPS::print(): Printing DjVu page to a stream\n");
+ DEBUG_MAKE_INDENT(3);
+ GRect prn_rect;
+ prn_rect.intersect(prn_rect_in, img_rect);
+ DEBUG_MSG("prn_rect=(" << prn_rect.xmin << ", " << prn_rect.ymin << ", " <<
+ prn_rect.width() << ", " << prn_rect.height() << ")\n");
+ DEBUG_MSG("img_rect=(" << img_rect.xmin << ", " << img_rect.ymin << ", " <<
+ img_rect.width() << ", " << img_rect.height() << ")\n");
+ if (!dimg)
+ G_THROW(ERR_MSG("DjVuToPS.empty_image"));
+ if (prn_rect.isempty())
+ G_THROW(ERR_MSG("DjVuToPS.empty_rect"));
+ if (img_rect.isempty())
+ G_THROW(ERR_MSG("DjVuToPS.bad_scale"));
+ GRectMapper mapper;
+ mapper.set_input(img_rect);
+ GRect full_rect(0, 0, dimg->get_width(), dimg->get_height());
+ mapper.set_output(full_rect);
+ mapper.map(prn_rect);
+ int image_dpi = dimg->get_dpi();
+ if (override_dpi>0)
+ image_dpi = override_dpi;
+ if (image_dpi <= 0)
+ image_dpi = 300;
+ store_doc_prolog(str, 1, (int)(image_dpi), &prn_rect);
+ store_doc_setup(str);
+ write(str,"%%%%Page: 1 1\n");
+ store_page_setup(str, (int)(image_dpi), prn_rect);
+ print_image(str, dimg, prn_rect, 0);
+ store_page_trailer(str);
+ write(str,"showpage\n");
+ store_doc_trailer(str);
+}
+
+
+
+
+// ***********************************************************************
+// *************************** DOCUMENT LEVEL ****************************
+// ***********************************************************************
+
+
+void
+DjVuToPS::
+parse_range(GP<DjVuDocument> doc,
+ GUTF8String page_range,
+ GList<int> &pages_todo)
+{
+ int doc_pages = doc->get_pages_num();
+ if (!page_range.length())
+ page_range.format("1-%d", doc_pages);
+ DEBUG_MSG("page_range='" << (const char *)page_range << "'\n");
+ int spec = 0;
+ int both = 1;
+ int start_page = 1;
+ int end_page = doc_pages;
+ const char *q = (const char*)page_range;
+ char *p = (char*)q;
+ while (*p)
+ {
+ while (*p==' ')
+ p += 1;
+ if (! *p)
+ break;
+ if (*p>='0' && *p<='9')
+ {
+ end_page = strtol(p, &p, 10);
+ spec = 1;
+ }
+ else if (*p=='$')
+ {
+ spec = 1;
+ end_page = doc_pages;
+ p += 1;
+ }
+ else if (both)
+ {
+ end_page = 1;
+ }
+ else
+ {
+ end_page = doc_pages;
+ }
+ while (*p==' ')
+ p += 1;
+ if (both)
+ {
+ start_page = end_page;
+ if (*p == '-')
+ {
+ p += 1;
+ both = 0;
+ continue;
+ }
+ }
+ both = 1;
+ while (*p==' ')
+ p += 1;
+ if (*p && *p != ',')
+ G_THROW(ERR_MSG("DjVuToPS.bad_range")
+ + GUTF8String("\t") + GUTF8String(p) );
+ if (*p == ',')
+ p += 1;
+ if (! spec)
+ G_THROW(ERR_MSG("DjVuToPS.bad_range")
+ + GUTF8String("\t") + page_range );
+ spec = 0;
+ if (end_page < 0)
+ end_page = 0;
+ if (start_page < 0)
+ start_page = 0;
+ if (end_page > doc_pages)
+ end_page = doc_pages;
+ if (start_page > doc_pages)
+ start_page = doc_pages;
+ if (start_page <= end_page)
+ for(int page_num=start_page; page_num<=end_page; page_num++)
+ pages_todo.append(page_num-1);
+ else
+ for(int page_num=start_page; page_num>=end_page; page_num--)
+ pages_todo.append(page_num-1);
+ }
+}
+
+class DjVuToPS::DecodePort : public DjVuPort
+{
+protected:
+ DecodePort(void);
+public:
+ static GP<DecodePort> create(void);
+ GEvent decode_event;
+ bool decode_event_received;
+ double decode_done;
+ GURL decode_page_url;
+ virtual void notify_file_flags_changed(const DjVuFile*,long,long);
+ virtual void notify_decode_progress(const DjVuPort*,double);
+};
+
+DjVuToPS::DecodePort::
+DecodePort(void)
+ : decode_event_received(false),
+ decode_done((double)0)
+{
+}
+
+GP<DjVuToPS::DecodePort>
+DjVuToPS::DecodePort::
+create(void)
+{
+ return new DecodePort;
+}
+
+void
+DjVuToPS::DecodePort::
+notify_file_flags_changed(const DjVuFile *source,
+ long set_mask, long clr_mask)
+{
+ // WARNING! This function is called from another thread
+ if (set_mask & (DjVuFile::DECODE_OK |
+ DjVuFile::DECODE_FAILED |
+ DjVuFile::DECODE_STOPPED ))
+ {
+ if (source->get_url() == decode_page_url)
+ {
+ decode_event_received=true;
+ decode_event.set();
+ }
+ }
+}
+
+void
+DjVuToPS::DecodePort::
+notify_decode_progress(const DjVuPort *source, double done)
+{
+ // WARNING! This function is called from another thread
+ if (source->inherits("DjVuFile"))
+ {
+ DjVuFile * file=(DjVuFile *) source;
+ if (file->get_url()==decode_page_url)
+ if ((int) (decode_done*20)!=(int) (done*20))
+ {
+ decode_done=done;
+ decode_event_received=true;
+ decode_event.set();
+ }
+ }
+}
+
+void
+DjVuToPS::
+set_refresh_cb(void (*_refresh_cb)(void*), void *_refresh_cl_data)
+{
+ refresh_cb = _refresh_cb;
+ refresh_cl_data = _refresh_cl_data;
+}
+
+void
+DjVuToPS::
+set_prn_progress_cb(void (*_prn_progress_cb)(double, void *),
+ void *_prn_progress_cl_data)
+{
+ prn_progress_cb=_prn_progress_cb;
+ prn_progress_cl_data=_prn_progress_cl_data;
+}
+
+void
+DjVuToPS::
+set_dec_progress_cb(void (*_dec_progress_cb)(double, void *),
+ void *_dec_progress_cl_data)
+{
+ dec_progress_cb=_dec_progress_cb;
+ dec_progress_cl_data=_dec_progress_cl_data;
+}
+
+void
+DjVuToPS::
+set_info_cb(void (*_info_cb)(int, int, int, Stage, void*),
+ void *_info_cl_data)
+{
+ info_cb=_info_cb;
+ info_cl_data=_info_cl_data;
+}
+
+GP<DjVuImage>
+DjVuToPS::
+decode_page(GP<DjVuDocument> doc,
+ int page_num, int cnt, int todo)
+{
+ DEBUG_MSG("processing page #" << page_num << "\n");
+ if (! port)
+ {
+ port = DecodePort::create();
+ DjVuPort::get_portcaster()->add_route((DjVuDocument*)doc, port);
+ }
+ port->decode_event_received = false;
+ port->decode_done = 0;
+ GP<DjVuFile> djvu_file;
+ GP<DjVuImage> dimg;
+ if (page_num >= 0 && page_num < doc->get_pages_num())
+ djvu_file = doc->get_djvu_file(page_num);
+ if (! djvu_file )
+ return 0;
+ if (djvu_file->is_decode_ok())
+ return doc->get_page(page_num, false);
+ // This is the best place to call info_cb(). Note, that
+ // get_page() will start decoding if necessary, and will not
+ // return until the decoding is over in a single threaded
+ // environment. That's why we call get_djvu_file() first.
+ if (info_cb)
+ info_cb(page_num, cnt, todo, DECODING, info_cl_data);
+ // Do NOT decode the page synchronously here!!!
+ // The plugin will deadlock otherwise.
+ dimg = doc->get_page(page_num, false);
+ djvu_file = dimg->get_djvu_file();
+ port->decode_page_url = djvu_file->get_url();
+ if (djvu_file->is_decode_ok())
+ return dimg;
+ DEBUG_MSG("decoding\n");
+ if (dec_progress_cb)
+ dec_progress_cb(0, dec_progress_cl_data);
+ while(! djvu_file->is_decode_ok())
+ {
+ while(!port->decode_event_received &&
+ !djvu_file->is_decode_ok())
+ {
+ port->decode_event.wait(250);
+ if (refresh_cb)
+ refresh_cb(refresh_cl_data);
+ }
+ port->decode_event_received = false;
+ if (djvu_file->is_decode_failed() ||
+ djvu_file->is_decode_stopped())
+ G_THROW(ERR_MSG("DjVuToPS.no_image")
+ + GUTF8String("\t")
+ + GUTF8String(page_num));
+ if (dec_progress_cb)
+ dec_progress_cb(port->decode_done, dec_progress_cl_data);
+ }
+ if (dec_progress_cb)
+ dec_progress_cb(1, dec_progress_cl_data);
+ return dimg;
+}
+
+void
+DjVuToPS::
+process_single_page(ByteStream &str,
+ GP<DjVuDocument> doc,
+ int page_num, int cnt, int todo,
+ int magic)
+{
+ GP<DjVuTXT> txt;
+ GP<DjVuImage> dimg;
+ dimg = decode_page(doc, page_num, cnt, todo);
+ if (options.get_text())
+ txt = get_text(dimg->get_djvu_file());
+ if (info_cb)
+ info_cb(page_num, cnt, todo, PRINTING, info_cl_data);
+ if (!magic)
+ write(str, "%%%%Page: %d %d\n", page_num+1, cnt+1);
+ if (dimg)
+ {
+ int dpi = dimg->get_dpi();
+ dpi = ((dpi <= 0) ? 300 : dpi);
+ GRect img_rect(0, 0, dimg->get_width(), dimg->get_height());
+ store_page_setup(str, dpi, img_rect, magic);
+ print_image(str, dimg, img_rect,txt);
+ store_page_trailer(str);
+ }
+ if (!magic)
+ write(str,"showpage\n");
+}
+
+
+struct pdata {
+ int page1, page2;
+ int smax, spos;
+ int offset;
+};
+
+void
+DjVuToPS::
+process_double_page(ByteStream &str,
+ GP<DjVuDocument> doc,
+ void *v, int cnt, int todo)
+{
+ const pdata *inf = (const pdata*)v;
+ int off = abs(inf->offset);
+ write(str,
+ "%%%%Page: (%d,%d) %d\n"
+ "gsave\n"
+ "/fold-dict 8 dict dup 3 1 roll def begin\n"
+ " clippath pathbbox newpath pop pop translate\n"
+ " clippath pathbbox newpath 4 2 roll pop pop\n"
+ " /ph exch def\n"
+ " /pw exch def\n"
+ " /w ph %d sub 2 div def\n"
+ " /m1 %d def\n"
+ " /m2 %d def\n"
+ "end\n",
+ inf->page1 + 1, inf->page2 + 1, cnt,
+ 2 * (off + options.get_bookletfold(inf->smax-1)),
+ inf->offset + options.get_bookletfold(inf->spos),
+ inf->offset - options.get_bookletfold(inf->spos));
+ if (options.get_cropmarks())
+ write(str,
+ "%% -- folding marks\n"
+ "fold-dict begin\n"
+ " 0 setgray 0.5 setlinewidth\n"
+ " ph m1 m2 add add 2 div dup\n"
+ " 0 exch moveto 36 0 rlineto stroke\n"
+ " pw exch moveto -36 0 rlineto stroke\n"
+ "end\n");
+ write(str,
+ "%% -- first page\n"
+ "gsave fold-dict begin\n"
+ " 0 ph 2 div w add m1 add translate 270 rotate\n"
+ " 0 0 w pw rectclip end\n");
+ if (inf->page1 >= 0)
+ process_single_page(str, doc, inf->page1, cnt*2, todo*2, +1);
+ write(str,
+ "grestore\n"
+ "%% -- second page\n"
+ "gsave fold-dict begin\n"
+ " 0 ph 2 div m2 add translate 270 rotate\n"
+ " 0 0 w pw rectclip end\n");
+ if (inf->page2 >= 0)
+ process_single_page(str, doc, inf->page2, cnt*2+1, todo*2, -1);
+ write(str,
+ "grestore\n"
+ "grestore\n"
+ "showpage\n");
+}
+
+static void
+booklet_order(GList<int>& pages, int smax)
+{
+ // -- make a multiple of four
+ while (pages.size() & 0x3)
+ pages.append(-1);
+ // -- copy to array
+ int i = 0;
+ int n = pages.size();
+ GTArray<int> p(0,n-1);
+ for (GPosition pos=pages; pos; ++pos)
+ p[i++] = pages[pos];
+ // -- rebuild
+ pages.empty();
+ for (i=0; i<n; i+=smax)
+ {
+ int lo = i;
+ int hi = i+smax-1;
+ if (hi >= n)
+ hi = n-1;
+ while (lo < hi)
+ {
+ pages.append(p[hi--]);
+ pages.append(p[lo++]);
+ pages.append(p[lo++]);
+ pages.append(p[hi--]);
+ }
+ }
+}
+
+
+// ***********************************************************************
+// ******* PUBLIC FUNCTIONS FOR PRINTING MULTIPLE PAGES ******************
+// ***********************************************************************
+
+
+
+void
+DjVuToPS::
+print(ByteStream &str,
+ GP<DjVuDocument> doc,
+ GUTF8String page_range)
+{
+ DEBUG_MSG("DjVuToPS::print(): Printing DjVu document\n");
+ DEBUG_MAKE_INDENT(3);
+ // Get page range
+ GList<int> pages_todo;
+ parse_range(doc, page_range, pages_todo);
+ int todo = pages_todo.size();
+ if (options.get_format()==Options::EPS)
+ {
+ /* Encapsulated Postscript mode */
+ if (todo != 1)
+ G_THROW(ERR_MSG("DjVuToPS.only_one_page"));
+ GPosition pos = pages_todo;
+ int page_num = pages_todo[pos];
+ GP<DjVuImage> dimg = decode_page(doc,page_num,0,todo);
+ if (! dimg)
+ G_THROW(ERR_MSG("DjVuToPS.no_image") + GUTF8String("\t1"));
+ GRect bbox(0, 0, dimg->get_width(), dimg->get_height());
+ store_doc_prolog(str, 1, dimg->get_dpi(), &bbox);
+ store_doc_setup(str);
+ process_single_page(str, doc, page_num, 0, todo, 0);
+ }
+ else if (options.get_bookletmode()==Options::OFF)
+ {
+ /* Normal mode */
+ int cnt = 0;
+ store_doc_prolog(str, todo, 0, 0);
+ store_doc_setup(str);
+ for(GPosition pos = pages_todo; pos; ++pos)
+ process_single_page(str,doc,pages_todo[pos],cnt++,todo,0);
+ store_doc_trailer(str);
+ }
+ else
+ {
+ /* Booklet mode */
+ int sheets_left = (todo+3)/4;
+ int sides_todo = sheets_left;
+ if (options.get_bookletmode() == Options::RECTOVERSO)
+ sides_todo *= 2;
+ int sheets_max = (options.get_bookletmax()+3)/4;
+ if (! sheets_max)
+ sheets_max = sheets_left;
+ // -- reorder pages
+ booklet_order(pages_todo, sheets_max*4);
+ // -- print
+ int sides = 0;
+ int sheetpos = sheets_max;
+ store_doc_prolog(str, sides_todo, 0, 0);
+ store_doc_setup(str);
+ for (GPosition p=pages_todo; p; ++p)
+ {
+ struct pdata inf;
+ inf.page1 = pages_todo[p];
+ inf.page2 = pages_todo[++p];
+ inf.smax = sheets_max;
+ inf.spos = --sheetpos;
+ inf.offset = options.get_bookletalign();
+ if (options.get_bookletmode() != Options::VERSO)
+ process_double_page(str,doc,(void*)&inf,sides++,sides_todo);
+ inf.page1 = pages_todo[++p];
+ inf.page2 = pages_todo[++p];
+ inf.offset = -inf.offset;
+ if (options.get_bookletmode() != Options::RECTO)
+ process_double_page(str,doc,(void*)&inf,sides++,sides_todo);
+ sheets_left -= 1;
+ if (sheetpos <= 0)
+ sheetpos = ((sheets_max<sheets_left) ? sheets_max : sheets_left);
+ }
+ store_doc_trailer(str);
+ }
+}
+
+
+void
+DjVuToPS::
+print(ByteStream &str, GP<DjVuDocument> doc)
+{
+ GUTF8String dummy;
+ print(str,doc,dummy);
+}
+
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuToPS.h b/kviewshell/plugins/djvu/libdjvu/DjVuToPS.h
new file mode 100644
index 00000000..95d547bb
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/DjVuToPS.h
@@ -0,0 +1,425 @@
+//C- -*- C++ -*-
+//C- -------------------------------------------------------------------
+//C- DjVuLibre-3.5
+//C- Copyright (c) 2002-2003 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: DjVuToPS.h,v 1.14 2004/03/05 16:48:53 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _DJVU_TO_PS_H_
+#define _DJVU_TO_PS_H_
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+/** @name DjVuToPS.h
+ Files #"DjVuToPS.h"# and #"DjVuToPS.cpp"# implement code that can be
+ used to convert a \Ref{DjVuImage} or \Ref{DjVuDocument} to PostScript
+ format. The conversion is carried out by the \Ref{DjVuToPS} class.
+
+ @memo PostScript file generator
+ @author Andrei Erofeev <eaf@geocities.com> \\
+ Florin Nicsa <Florin.Nicsa@insa-lyon.fr>
+ @version
+ #$Id: DjVuToPS.h,v 1.14 2004/03/05 16:48:53 leonb Exp $#
+*/
+//@{
+
+#include "DjVuGlobal.h"
+#include "GRect.h"
+#include "DjVuDocument.h"
+#include "DjVuText.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+/** DjVuImage to PostScript converter.
+ Use this class to print \Ref{DjVuImage}s and \Ref{DjVuDocument}s.
+ The behavior is customizable. See \Ref{DjVuToPS::Options} for the
+ description of available options.*/
+class DjVuToPS
+{
+public:
+ class DecodePort;
+
+ /** DjVuToPS options. Use this class to customize the way
+ in which DjVu to PS conversion will be done. You can adjust
+ the following things:
+ \begin{description}
+ \item[Format] ({\em EPS} or {\em PS}). Use the {\em EPS}
+ format if you plan to embed the output image into another
+ document. Print {\em PS} otherwise.
+ \item[Language level] ({\em 1} or {\em 2}). Any PostScript
+ printer or interpreter should understand PostScript Level 1
+ files. Unfortunately we cannot efficiently compress and encode
+ data when generating Level 1 files. PostScript Level 2 allows
+ to employ an RLE compression and ASCII85 encoding scheme,
+ which makes output files significantly smaller. Most of
+ the printers and word processors nowadays support PostScript
+ Level 2.
+ \item[Orientation] ({\em PORTRAIT} or {\em LANDSCAPE})
+ \item[Zoom factor] ({\em FIT_PAGE} or {\em ONE_TO_ONE}).
+ {\em ONE_TO_ONE} mode is useful, if you want the output to
+ be of the same size as the original image (before compression).
+ This requires that the #dpi# setting inside the \Ref{DjVuImage}
+ is correct. In most of the cases the {\em FIT_PAGE} zoom is
+ would be your best choice.
+ \item[Mode] ({\em COLOR}, {\em FORE}, {\em BACK}, or {\em BW})
+ Specifies how the \Ref{DjVuImage}s will be rendered (all layers,
+ foreground layer, background layer, and the mask respectively)
+ \item[Color] ({\em TRUE} or {\em FALSE}). Choosing {\em FALSE}
+ converts color images to gray scale.
+ \item[Gamma] Printer color correction.
+ This parameter ranges from #0.3# to #5.0#.
+ \item[sRGB] ({\em TRUE} or {\em FALSE}). Choosing {\em TRUE}
+ enables accurate sRGB color calibration. This option
+ only works with language level 2. When this is set,
+ gamma correction is clamped to #2.2#.
+ \item[Number of copies] Specifies how many copies should be
+ printed. This does {\bf not} affect the size of the output file.
+ \end{description}
+ */
+ class Options
+ {
+ public:
+ /** Specifies the rendering mode */
+ enum Mode { COLOR, FORE, BACK, BW };
+ /** Selects the output format */
+ enum Format { PS, EPS };
+ /** Specifies the orientation of the output image */
+ enum Orientation { PORTRAIT, LANDSCAPE, AUTO };
+ /** Specifies the booklet mode */
+ enum BookletMode { OFF, RECTO, VERSO, RECTOVERSO };
+ private:
+ Format format;
+ int level;
+ Orientation orientation;
+ Mode mode;
+ int zoom;
+ bool color;
+ bool calibrate;
+ bool text;
+ double gamma;
+ int copies;
+ bool frame;
+ bool cropmarks;
+ BookletMode bookletmode;
+ int bookletmax;
+ int bookletalign;
+ int bookletfold;
+ int bookletxfold;
+ public:
+ /** Sets output image format to #PS# or #EPS# */
+ void set_format(Format format);
+ /** Sets PostScript level (#1#, #2#, or #3#) */
+ void set_level(int level);
+ /** Sets orientation (#LANDSCAPE# or #PORTRAIT#) */
+ void set_orientation(Orientation orientation);
+ /** Sets \Ref{DjVuImage} rendering mode (#COLOR#, #BW#, #FORE#, #BACK#) */
+ void set_mode(Mode mode);
+ /** Sets zoom factor. Zoom 0 means fit page. */
+ void set_zoom(int zoom);
+ /** Affects automatic conversion to GreyScale mode. */
+ void set_color(bool color);
+ /** Sets gamma correction factor. Ranges from #0.3# to #5.0#. */
+ void set_gamma(double gamma);
+ /** Sets sRGB color calibration flag. */
+ void set_sRGB(bool calibrate);
+ /** Specifies the number of copies to be printed. */
+ void set_copies(int copies);
+ /** Specifies if a gray frame around the image should be printed. */
+ void set_frame(bool on);
+ /** Specifies if crop marks should be printed. */
+ void set_cropmarks(bool on);
+ /** Specifies if a shadow text should be printed. */
+ void set_text(bool on);
+ /** Specifies the bookletmode */
+ void set_bookletmode(BookletMode m);
+ /** Specifies the maximal number of pages in a booklet */
+ void set_bookletmax(int m);
+ /** Specifies an offset (points) between
+ booklet recto(s) and verso(s). */
+ void set_bookletalign(int m);
+ /** Specifies the margin (points) required to fold
+ the booklet (#fold# in points) and the margin
+ increase required for each sheet (#xfold# in millipoints). */
+ void set_bookletfold(int fold, int xfold=0);
+
+ /** Returns output image format (#PS# or #EPS#) */
+ Format get_format(void) const {
+ return format; }
+ /** Returns PostScript level (#1# or #2#) */
+ int get_level(void) const {
+ return level; }
+ /** Returns output image orientation (#PORTRAIT# or #LANDSCAPE#) */
+ Orientation get_orientation(void) const {
+ return orientation; }
+ /** Returns \Ref{DjVuImage} rendering mode
+ (#COLOR#, #FORE#, #BACK#, #BW#) */
+ Mode get_mode(void) const {
+ return mode; }
+ /** Returns output zoom factor (#FIT_PAGE# or #ONE_TO_ONE#) */
+ int get_zoom(void) const {
+ return zoom; }
+ /** Returns color printing flag. */
+ bool get_color(void) const {
+ return color; }
+ /** Returns sRGB color calibration flag. */
+ bool get_sRGB(void) const {
+ return calibrate; }
+ /** Returns printer gamma correction factor */
+ double get_gamma(void) const {
+ return ((calibrate) ? ((double)2.2) : gamma); }
+ /** Returns the number of copies, which will be printed by printer
+ This parameter does {\bf not} affect the size of output file */
+ int get_copies(void) const {
+ return copies; }
+ /** Returns #TRUE# if there will be a gray frame */
+ bool get_frame(void) const {
+ return frame; }
+ /** Returns #TRUE# if there will be a gray frame */
+ bool get_cropmarks(void) const {
+ return cropmarks; }
+ /** Returns #TRUE# if there will be a shadow text printed */
+ bool get_text(void) const {
+ return text; }
+ /** Returns the booklet mode */
+ BookletMode get_bookletmode(void) const {
+ return bookletmode; }
+ /** Returns the booklet max size */
+ int get_bookletmax(void) {
+ return bookletmax; }
+ /** Returns the booklet recto/verso offset */
+ int get_bookletalign(void) {
+ return bookletalign; }
+ /** Returns the folding margin for sheet number #n#. */
+ int get_bookletfold(int n=0) {
+ return bookletfold + (n*bookletxfold+500)/1000; }
+ /* Constructor */
+ Options(void);
+ };
+
+ /** Describes current page processing stage. This is passed to
+ the #info_cb()# callback. See \Ref{set_info_cb}() for details. */
+ enum Stage { DECODING, PRINTING };
+
+private:
+ void (*refresh_cb)(void*);
+ void *refresh_cl_data;
+ void (*prn_progress_cb)(double, void*);
+ void *prn_progress_cl_data;
+ void (*dec_progress_cb)(double, void*);
+ void *dec_progress_cl_data;
+ void (*info_cb)(int,int,int,Stage,void*);
+ void *info_cl_data;
+ unsigned char ramp[256];
+ GP<DecodePort> port;
+protected:
+ void store_doc_prolog(ByteStream&,int,int,GRect*);
+ void store_doc_setup(ByteStream&);
+ void store_doc_trailer(ByteStream&);
+ void store_page_setup(ByteStream&,int,const GRect&,int align=0);
+ void store_page_trailer(ByteStream&);
+ void make_gamma_ramp(GP<DjVuImage>);
+ void print_image_lev1(ByteStream&,GP<DjVuImage>,const GRect&);
+ void print_image_lev2(ByteStream&,GP<DjVuImage>,const GRect&);
+ void print_bg(ByteStream&,GP<DjVuImage>,const GRect&);
+ void print_fg_3layer(ByteStream&,GP<DjVuImage>,const GRect&,unsigned char*);
+ void print_fg_2layer(ByteStream&,GP<DjVuImage>,const GRect&,unsigned char*);
+ void print_fg(ByteStream&,GP<DjVuImage>,const GRect&);
+ void print_image(ByteStream&,GP<DjVuImage>,const GRect&,GP<DjVuTXT>);
+ void parse_range(GP<DjVuDocument>,GUTF8String,GList<int>&);
+ GP<DjVuImage> decode_page(GP<DjVuDocument>,int,int,int);
+ void process_single_page(ByteStream&,GP<DjVuDocument>,int,int,int,int);
+ void process_double_page(ByteStream&,GP<DjVuDocument>,void*,int,int);
+
+public:
+ /** Options affecting the print result. Please refer to
+ \Ref{DjVuToPS::Options} for details. */
+ Options options;
+
+ /** @name Callbacks */
+ //@{
+ /** Refresh callback is a function, which will be called fairly
+ often while the image (document) is being printed. It can
+ be used to refresh a GUI, if necessary.
+
+ @param refresh_cb Callback function to be called periodically
+ @param refresh_cl_data Pointer passed to #refresh_cb()# */
+ void set_refresh_cb(void (*refresh_cb)(void*), void *refresh_cl_data);
+ /** Callback used to report the progress of printing. The progress is a
+ double number from 0 to 1. If an existing \Ref{DjVuImage} is printed,
+ this callback will be called at least twice: in the beginning and at the
+ end of printing. If a \Ref{DjVuDocument} is being printed, this
+ callback will be used to report printing progress of every page. To
+ learn the number of the page being printed you can use
+ \Ref{set_info_cb}() function. See \Ref{set_dec_progress_cb}() to find
+ out how to learn the decoding progress.
+
+ @param cb Callback function to be called
+ @param data Pointer passed to #cb()#. */
+ void set_prn_progress_cb(void (*cb)(double, void*), void *data);
+ /** Callback used to report the progress of decoding. The progress is a
+ double number from 0 to 1. This callback is only used when printing a
+ \Ref{DjVuDocument} in a multithreaded environment. In all other cases it
+ will not be called. Whenever you \Ref{print}() a page range from a
+ \Ref{DjVuDocument}, the #DjVuToPS# has to decode the mentioned pages
+ before writing them to the output \Ref{ByteStream}. This callback can be
+ helpful to find out the status of the decoding. See
+ \Ref{set_prn_progress_cb}() to find out how to learn the printing
+ progress. See \Ref{set_info_cb}() to learn how to find out the number
+ of the page being processed, the total number of pages and the number of
+ processed pages.
+
+ @param cb Callback function to be called
+ @param data Pointer passed to #cb()#. */
+ void set_dec_progress_cb(void (*cb)(double, void*), void *data);
+ /** Callback used to report the current printing stage of a
+ \Ref{DjVuDocument}. When printing a \Ref{DjVuDocument} ({\bf not} a
+ \Ref{DjVuImage}), the #DjVuToPS# class will decode and output every page
+ mentioned in the {\em page range}. Before decoding and outputing, it
+ will call this #info_cb()# callback in order to let you know about what
+ is going on. This can be quite useful in a GUI program to keep the user
+ informed. This function is not called when you print a \Ref{DjVuImage}.
+
+ Description of the arguments passed to #info_cb#:
+ \begin{description}
+ \item[page_num] The number of the page being processed
+ \item[page_cnt] Counts how many pages have already been processed.
+ \item[tot_pages] Counts how many pages will be output enventually.
+ \item[stage] Describes the current processing stage
+ (#DECODING# or #PRINTING#).
+ \end{description}
+ @param cb Callback function to be called
+ @param data Pointer, which will be passed to #cb()#. */
+ void set_info_cb(void (*cb)(int,int,int,Stage,void*), void *data);
+ //@}
+
+ /** Prints the specified \Ref{DjVuImage} #dimg# into the
+ \Ref{ByteStream} #str#. The function will first scale
+ the image to fit the #img_rect#, then extract #prn_rect#
+ from the obtained bitmap and will output it in the
+ PostScript format. The function generates a legal PostScript
+ (or Encapsulated PostScript) file taking care of all comments
+ conforming to Document Structure Conventions v. 3.0.
+
+ {\bf Warning:} The zoom factor specified in \Ref{Options} does
+ not affect the amount of data stored into the PostScript file.
+ It will be used by the PostScript code to additionally scale
+ the image. We cannot pre-scale it here, because we do not know
+ the future resolution of the printer. The #img_rect# and
+ #prn_rect# alone define how much data will be sent to printer.
+
+ Using #img_rect# one can upsample or downsample the image prior
+ to sending it to the printer.
+
+ @param str \Ref{ByteStream} where PostScript output will be sent
+ @param dimg \Ref{DjVuImage} to print
+ @param img_rect Rectangle to which the \Ref{DjVuImage} will be scaled.
+ Note that this parameters defines the amount of data
+ that will actually be sent to the printer. The PostScript
+ code can futher resize the image according to the
+ #zoom# parameter from the \Ref{Options} structure.
+ @param prn_rect Part of img_rect to send to printer.
+ @param override_dpi Optional parameter allowing you to override
+ dpi setting that would otherwise be extracted from #dimg# */
+ void print(ByteStream&, GP<DjVuImage> dimg,
+ const GRect &prn_rect, const GRect &img_rect,
+ int override_dpi=-1 );
+
+ /** Outputs the specifies pages from the \Ref{DjVuDocument} into the
+ \Ref{ByteStream} in PostScript format. The function will generate a
+ multipage PostScript document conforming to PS DSC 3.0 by storing into
+ it every page mentioned in the #page_range#.
+
+ If #page_range# is empty, all pages from the \Ref{DjVuDocument} #doc#
+ will be printed. The #page_range# is a set of ranges separated by
+ commas. Every range has this form: {\em start_page}[-{\em
+ end_page}]. {\em end_page} is optional and can be less than the {\em
+ start_page}, in which case the pages will be printed in the reverse
+ order.
+
+ Examples:
+ \begin{itemize}
+ \item {\bf 1-10} - Will print pages 1 to 10.
+ \item {\bf 10-1} - Will print pages 1 to 10 in reverse order.
+ \item {\bf 1-10,12-20} - Will print pages 1 to 20 with page 11 skipped.
+ \end{itemize} */
+ void print(ByteStream&, GP<DjVuDocument> doc, GUTF8String page_range);
+ void print(ByteStream&, GP<DjVuDocument> doc);
+
+
+ /** Default constructor. Initializes the class. */
+ DjVuToPS(void);
+};
+
+
+//****************************************************************************
+//******************************** DjVuToPS **********************************
+//****************************************************************************
+
+//@}
+// ------------
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/GBitmap.cpp b/kviewshell/plugins/djvu/libdjvu/GBitmap.cpp
new file mode 100644
index 00000000..696367e7
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GBitmap.cpp
@@ -0,0 +1,1658 @@
+//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: GBitmap.cpp,v 1.10 2004/04/17 23:56:11 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "GBitmap.h"
+#include "ByteStream.h"
+#include "GRect.h"
+#include "GString.h"
+#include "GThreads.h"
+#include "GException.h"
+#include <string.h>
+
+// File "$Id: GBitmap.cpp,v 1.10 2004/04/17 23:56:11 leonb Exp $"
+// - Author: Leon Bottou, 05/1997
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+// ----- constructor and destructor
+
+GBitmap::~GBitmap()
+{
+}
+
+void
+GBitmap::destroy(void)
+{
+ gbytes_data.resize(0);
+ bytes = 0;
+ grle.resize(0);
+ grlerows.resize(0);
+ rlelength = 0;
+}
+
+GBitmap::GBitmap()
+ : nrows(0), ncolumns(0), border(0),
+ bytes_per_row(0), grays(0), bytes(0), gbytes_data(bytes_data),
+ grle(rle), grlerows(rlerows), rlelength(0),
+ monitorptr(0)
+{
+}
+
+GBitmap::GBitmap(int nrows, int ncolumns, int border)
+ : nrows(0), ncolumns(0), border(0),
+ bytes_per_row(0), grays(0), bytes(0), gbytes_data(bytes_data),
+ grle(rle), grlerows(rlerows), rlelength(0),
+ monitorptr(0)
+{
+ G_TRY
+ {
+ init(nrows, ncolumns, border);
+ }
+ G_CATCH_ALL
+ {
+ destroy();
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+}
+
+GBitmap::GBitmap(ByteStream &ref, int border)
+ : nrows(0), ncolumns(0), border(0),
+ bytes_per_row(0), grays(0), bytes(0), gbytes_data(bytes_data),
+ grle(rle), grlerows(rlerows), rlelength(0),
+ monitorptr(0)
+{
+ G_TRY
+ {
+ init(ref, border);
+ }
+ G_CATCH_ALL
+ {
+ destroy();
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+}
+
+GBitmap::GBitmap(const GBitmap &ref)
+ : nrows(0), ncolumns(0), border(0),
+ bytes_per_row(0), grays(0), bytes(0), gbytes_data(bytes_data),
+ grle(rle), grlerows(rlerows), rlelength(0),
+ monitorptr(0)
+{
+ G_TRY
+ {
+ init(ref, ref.border);
+ }
+ G_CATCH_ALL
+ {
+ destroy();
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+}
+
+GBitmap::GBitmap(const GBitmap &ref, int border)
+ : nrows(0), ncolumns(0), border(0),
+ bytes_per_row(0), grays(0), bytes(0), gbytes_data(bytes_data),
+ grle(rle), grlerows(rlerows), rlelength(0),
+ monitorptr(0)
+{
+ G_TRY
+ {
+ init(ref, border);
+ }
+ G_CATCH_ALL
+ {
+ destroy();
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+}
+
+
+GBitmap::GBitmap(const GBitmap &ref, const GRect &rect, int border)
+ : nrows(0), ncolumns(0), border(0),
+ bytes_per_row(0), grays(0), bytes(0), gbytes_data(bytes_data),
+ grle(rle), grlerows(rlerows), rlelength(0),
+ monitorptr(0)
+{
+ G_TRY
+ {
+ init(ref, rect, border);
+ }
+ G_CATCH_ALL
+ {
+ destroy();
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+}
+
+
+
+
+
+
+// ----- initialization
+
+void
+GBitmap::init(int arows, int acolumns, int aborder)
+{
+ GMonitorLock lock(monitor());
+ destroy();
+ grays = 2;
+ nrows = arows;
+ ncolumns = acolumns;
+ border = aborder;
+ bytes_per_row = ncolumns + border;
+ int npixels = nrows * bytes_per_row + border;
+ gzerobuffer=zeroes(bytes_per_row + border);
+ if (npixels > 0)
+ {
+ gbytes_data.resize(npixels);
+ gbytes_data.clear();
+ bytes = bytes_data;
+ }
+}
+
+
+void
+GBitmap::init(const GBitmap &ref, int aborder)
+{
+ GMonitorLock lock(monitor());
+ if (this != &ref)
+ {
+ GMonitorLock lock(ref.monitor());
+ init(ref.nrows, ref.ncolumns, aborder);
+ grays = ref.grays;
+ unsigned char *row = bytes_data+border;
+ for (int n=0; n<nrows; n++, row+=bytes_per_row)
+ memcpy( (void*)row, (void*)ref[n], ncolumns );
+ }
+ else if (aborder > border)
+ {
+ minborder(aborder);
+ }
+}
+
+
+void
+GBitmap::init(const GBitmap &ref, const GRect &rect, int border)
+{
+ GMonitorLock lock(monitor());
+ // test bitmap physical equality
+ if (this == &ref)
+ {
+ GBitmap tmp;
+ tmp.grays = grays;
+ tmp.border = border;
+ tmp.bytes_per_row = bytes_per_row;
+ tmp.ncolumns = ncolumns;
+ tmp.nrows = nrows;
+ tmp.bytes = bytes;
+ tmp.gbytes_data.swap(gbytes_data);
+ tmp.grle.swap(grle);
+ bytes = 0 ;
+ init(tmp, rect, border);
+ }
+ else
+ {
+ GMonitorLock lock(ref.monitor());
+ // create empty bitmap
+ init(rect.height(), rect.width(), border);
+ grays = ref.grays;
+ // compute destination rectangle
+ GRect rect2(0, 0, ref.columns(), ref.rows() );
+ rect2.intersect(rect2, rect);
+ rect2.translate(-rect.xmin, -rect.ymin);
+ // copy bits
+ if (! rect2.isempty())
+ {
+ for (int y=rect2.ymin; y<rect2.ymax; y++)
+ {
+ unsigned char *dst = (*this)[y];
+ const unsigned char *src = ref[y+rect.ymin] + rect.xmin;
+ for (int x=rect2.xmin; x<rect2.xmax; x++)
+ dst[x] = src[x];
+ }
+ }
+ }
+}
+
+
+void
+GBitmap::init(ByteStream &ref, int aborder)
+{
+ GMonitorLock lock(monitor());
+ // Get magic number
+ char magic[2];
+ magic[0] = magic[1] = 0;
+ ref.readall((void*)magic, sizeof(magic));
+ char lookahead = '\n';
+ int acolumns = read_integer(lookahead, ref);
+ int arows = read_integer(lookahead, ref);
+ init(arows, acolumns, aborder);
+ // go reading file
+ if (magic[0]=='P')
+ {
+ switch(magic[1])
+ {
+ case '1':
+ grays = 2;
+ read_pbm_text(ref);
+ return;
+ case '2':
+ grays = 1 + read_integer(lookahead, ref);
+ if (grays > 256)
+ G_THROW("Cannot read PGM with depth greater than 8 bits.");
+ read_pgm_text(ref);
+ return;
+ case '4':
+ grays = 2;
+ read_pbm_raw(ref);
+ return;
+ case '5':
+ grays = 1 + read_integer(lookahead, ref);
+ if (grays > 256)
+ grays = 256;
+ read_pgm_raw(ref);
+ return;
+ }
+ }
+ else if (magic[0]=='R')
+ {
+ switch(magic[1])
+ {
+ case '4':
+ grays = 2;
+ read_rle_raw(ref);
+ return;
+ }
+ }
+ G_THROW( ERR_MSG("GBitmap.bad_format") );
+}
+
+void
+GBitmap::donate_data(unsigned char *data, int w, int h)
+{
+ destroy();
+ grays = 2;
+ nrows = h;
+ ncolumns = w;
+ border = 0;
+ bytes_per_row = w;
+ gbytes_data.replace(data,w*h);
+ bytes = bytes_data;
+ rlelength = 0;
+}
+
+void
+GBitmap::donate_rle(unsigned char *rledata, unsigned int rledatalen, int w, int h)
+{
+ destroy();
+ grays = 2;
+ nrows = h;
+ ncolumns = w;
+ border = 0;
+ bytes_per_row = w;
+// rle = rledata;
+ grle.replace(rledata,rledatalen);
+ rlelength = rledatalen;
+}
+
+
+unsigned char *
+GBitmap::take_data(size_t &offset)
+{
+ GMonitorLock lock(monitor());
+ unsigned char *ret = bytes_data;
+ if (ret) offset = (size_t)border;
+ bytes_data=0;
+ return ret;
+}
+
+const unsigned char *
+GBitmap::get_rle(unsigned int &rle_length)
+{
+ if(!rle)
+ compress();
+ rle_length=rlelength;
+ return rle;
+}
+
+// ----- compression
+
+
+void
+GBitmap::compress()
+{
+ if (grays > 2)
+ G_THROW( ERR_MSG("GBitmap.cant_compress") );
+ GMonitorLock lock(monitor());
+ if (bytes)
+ {
+ grle.resize(0);
+ grlerows.resize(0);
+ rlelength = encode(rle,grle);
+ if (rlelength)
+ {
+ gbytes_data.resize(0);
+ bytes = 0;
+ }
+ }
+}
+
+void
+GBitmap::uncompress()
+{
+ GMonitorLock lock(monitor());
+ if (!bytes && rle)
+ decode(rle);
+}
+
+
+
+unsigned int
+GBitmap::get_memory_usage() const
+{
+ unsigned long usage = sizeof(GBitmap);
+ if (bytes)
+ usage += nrows * bytes_per_row + border;
+ if (rle)
+ usage += rlelength;
+ return usage;
+}
+
+
+void
+GBitmap::minborder(int minimum)
+{
+ if (border < minimum)
+ {
+ GMonitorLock lock(monitor());
+ if (border < minimum)
+ {
+ if (bytes)
+ {
+ GBitmap tmp(*this, minimum);
+ bytes_per_row = tmp.bytes_per_row;
+ tmp.gbytes_data.swap(gbytes_data);
+ bytes = bytes_data;
+ tmp.bytes = 0;
+ }
+ border = minimum;
+ gzerobuffer=zeroes(border + ncolumns + border);
+ }
+ }
+}
+
+
+#define NMONITORS 8
+static GMonitor monitors[NMONITORS];
+
+void
+GBitmap::share()
+{
+ if (!monitorptr)
+ {
+ unsigned long x = (unsigned long)this;
+ monitorptr = &monitors[(x^(x>>5)) % NMONITORS];
+ }
+}
+
+
+// ----- gray levels
+
+void
+GBitmap::set_grays(int ngrays)
+{
+ if (ngrays<2 || ngrays>256)
+ G_THROW( ERR_MSG("GBitmap.bad_levels") );
+ // set gray levels
+ GMonitorLock lock(monitor());
+ grays = ngrays;
+ if (ngrays>2 && !bytes)
+ uncompress();
+}
+
+void
+GBitmap::change_grays(int ngrays)
+{
+ GMonitorLock lock(monitor());
+ // set number of grays
+ int ng = ngrays - 1;
+ int og = grays - 1;
+ set_grays(ngrays);
+ // setup conversion table
+ unsigned char conv[256];
+ for (int i=0; i<256; i++)
+ {
+ if (i > og)
+ conv[i] = ng;
+ else
+ conv[i] = (i*ng+og/2)/og;
+ }
+ // perform conversion
+ for (int row=0; row<nrows; row++)
+ {
+ unsigned char *p = (*this)[row];
+ for (int n=0; n<ncolumns; n++)
+ p[n] = conv[ p[n] ];
+ }
+}
+
+void
+GBitmap::binarize_grays(int threshold)
+{
+ GMonitorLock lock(monitor());
+ if (bytes)
+ for (int row=0; row<nrows; row++)
+ {
+ unsigned char *p = (*this)[row];
+ for(unsigned char const * const pend=p+ncolumns;p<pend;++p)
+ {
+ *p = (*p>threshold) ? 1 : 0;
+ }
+ }
+ grays = 2;
+}
+
+
+// ----- additive blitting
+
+#undef min
+#undef max
+
+static inline int
+min(int x, int y)
+{
+ return (x < y ? x : y);
+}
+
+static inline int
+max(int x, int y)
+{
+ return (x > y ? x : y);
+}
+
+void
+GBitmap::blit(const GBitmap *bm, int x, int y)
+{
+ // Check boundaries
+ if ((x >= ncolumns) ||
+ (y >= nrows) ||
+ (x + (int)bm->columns() < 0) ||
+ (y + (int)bm->rows() < 0) )
+ return;
+
+ // Perform blit
+ GMonitorLock lock1(monitor());
+ GMonitorLock lock2(bm->monitor());
+ if (bm->bytes)
+ {
+ if (!bytes_data)
+ uncompress();
+ // Blit from bitmap
+ const unsigned char *srow = bm->bytes + bm->border;
+ unsigned char *drow = bytes_data + border + y*bytes_per_row + x;
+ for (int sr = 0; sr < bm->nrows; sr++)
+ {
+ if (sr+y>=0 && sr+y<nrows)
+ {
+ int sc = max(0, -x);
+ int sc1 = min(bm->ncolumns, ncolumns-x);
+ while (sc < sc1)
+ {
+ drow[sc] += srow[sc];
+ sc += 1;
+ }
+ }
+ srow += bm->bytes_per_row;
+ drow += bytes_per_row;
+ }
+ }
+ else if (bm->rle)
+ {
+ if (!bytes_data)
+ uncompress();
+ // Blit from rle
+ const unsigned char *runs = bm->rle;
+ unsigned char *drow = bytes_data + border + y*bytes_per_row + x;
+ int sr = bm->nrows - 1;
+ drow += sr * bytes_per_row;
+ int sc = 0;
+ char p = 0;
+ while (sr >= 0)
+ {
+ const int z = read_run(runs);
+ if (sc+z > bm->ncolumns)
+ G_THROW( ERR_MSG("GBitmap.lost_sync") );
+ int nc = sc + z;
+ if (p && sr+y>=0 && sr+y<nrows)
+ {
+ if (sc + x < 0)
+ sc = min(-x, nc);
+ while (sc < nc && sc + x<ncolumns)
+ drow[sc++] += 1;
+ }
+ sc = nc;
+ p = 1 - p;
+ if (sc >= bm->ncolumns)
+ {
+ p = 0;
+ sc = 0;
+ drow -= bytes_per_row;
+ sr -= 1;
+ }
+ }
+ }
+}
+
+
+
+void
+GBitmap::blit(const GBitmap *bm, int xh, int yh, int subsample)
+{
+ // Use code when no subsampling is necessary
+ if (subsample == 1)
+ {
+ blit(bm, xh, yh);
+ return;
+ }
+
+ // Check boundaries
+ if ((xh >= ncolumns * subsample) ||
+ (yh >= nrows * subsample) ||
+ (xh + (int)bm->columns() < 0) ||
+ (yh + (int)bm->rows() < 0) )
+ return;
+
+ // Perform subsampling blit
+ GMonitorLock lock1(monitor());
+ GMonitorLock lock2(bm->monitor());
+ if (bm->bytes)
+ {
+ if (!bytes_data)
+ uncompress();
+ // Blit from bitmap
+ int dr, dr1, zdc, zdc1;
+ euclidian_ratio(yh, subsample, dr, dr1);
+ euclidian_ratio(xh, subsample, zdc, zdc1);
+ const unsigned char *srow = bm->bytes + bm->border;
+ unsigned char *drow = bytes_data + border + dr*bytes_per_row;
+ for (int sr = 0; sr < bm->nrows; sr++)
+ {
+ if (dr>=0 && dr<nrows)
+ {
+ int dc = zdc;
+ int dc1 = zdc1;
+ for (int sc=0; sc < bm->ncolumns; sc++)
+ {
+ if (dc>=0 && dc<ncolumns)
+ drow[dc] += srow[sc];
+ if (++dc1 >= subsample)
+ {
+ dc1 = 0;
+ dc += 1;
+ }
+ }
+ }
+ // next line in source
+ srow += bm->bytes_per_row;
+ // next line fraction in destination
+ if (++dr1 >= subsample)
+ {
+ dr1 = 0;
+ dr += 1;
+ drow += bytes_per_row;
+ }
+ }
+ }
+ else if (bm->rle)
+ {
+ if (!bytes_data)
+ uncompress();
+ // Blit from rle
+ int dr, dr1, zdc, zdc1;
+ euclidian_ratio(yh+bm->nrows-1, subsample, dr, dr1);
+ euclidian_ratio(xh, subsample, zdc, zdc1);
+ const unsigned char *runs = bm->rle;
+ unsigned char *drow = bytes_data + border + dr*bytes_per_row;
+ int sr = bm->nrows -1;
+ int sc = 0;
+ char p = 0;
+ int dc = zdc;
+ int dc1 = zdc1;
+ while (sr >= 0)
+ {
+ int z = read_run(runs);
+ if (sc+z > bm->ncolumns)
+ G_THROW( ERR_MSG("GBitmap.lost_sync") );
+ int nc = sc + z;
+
+ if (dr>=0 && dr<nrows)
+ while (z>0 && dc<ncolumns)
+ {
+ int zd = subsample - dc1;
+ if (zd > z)
+ zd = z;
+ if (p && dc>=0)
+ drow[dc] += zd;
+ z -= zd;
+ dc1 += zd;
+ if (dc1 >= subsample)
+ {
+ dc1 = 0;
+ dc += 1;
+ }
+ }
+ // next fractional row
+ sc = nc;
+ p = 1 - p;
+ if (sc >= bm->ncolumns)
+ {
+ sc = 0;
+ dc = zdc;
+ dc1 = zdc1;
+ p = 0;
+ sr -= 1;
+ if (--dr1 < 0)
+ {
+ dr1 = subsample - 1;
+ dr -= 1;
+ drow -= bytes_per_row;
+ }
+ }
+ }
+ }
+}
+
+
+
+// ------ load bitmaps
+
+
+unsigned int
+GBitmap::read_integer(char &c, ByteStream &bs)
+{
+ unsigned int x = 0;
+ // eat blank before integer
+ while (c==' ' || c=='\t' || c=='\r' || c=='\n' || c=='#')
+ {
+ if (c=='#')
+ do { } while (bs.read(&c,1) && c!='\n' && c!='\r');
+ c = 0;
+ bs.read(&c, 1);
+ }
+ // check integer
+ if (c<'0' || c>'9')
+ G_THROW( ERR_MSG("GBitmap.not_int") );
+ // eat integer
+ while (c>='0' && c<='9')
+ {
+ x = x*10 + c - '0';
+ c = 0;
+ bs.read(&c, 1);
+ }
+ return x;
+}
+
+
+void
+GBitmap::read_pbm_text(ByteStream &bs)
+{
+ unsigned char *row = bytes_data + border;
+ row += (nrows-1) * bytes_per_row;
+ for (int n = nrows-1; n>=0; n--)
+ {
+ for (int c = 0; c<ncolumns; c++)
+ {
+ char bit = 0;
+ bs.read(&bit,1);
+ while (bit==' ' || bit=='\t' || bit=='\r' || bit=='\n')
+ {
+ bit=0;
+ bs.read(&bit,1);
+ }
+ if (bit=='1')
+ row[c] = 1;
+ else if (bit=='0')
+ row[c] = 0;
+ else
+ G_THROW( ERR_MSG("GBitmap.bad_PBM") );
+ }
+ row -= bytes_per_row;
+ }
+}
+
+void
+GBitmap::read_pgm_text(ByteStream &bs)
+{
+ unsigned char *row = bytes_data + border;
+ row += (nrows-1) * bytes_per_row;
+ char lookahead = '\n';
+ for (int n = nrows-1; n>=0; n--)
+ {
+ for (int c = 0; c<ncolumns; c++)
+ row[c] = grays - 1 - read_integer(lookahead, bs);
+ row -= bytes_per_row;
+ }
+}
+
+void
+GBitmap::read_pbm_raw(ByteStream &bs)
+{
+ unsigned char *row = bytes_data + border;
+ row += (nrows-1) * bytes_per_row;
+ for (int n = nrows-1; n>=0; n--)
+ {
+ unsigned char acc = 0;
+ unsigned char mask = 0;
+ for (int c = 0; c<ncolumns; c++)
+ {
+ if (!mask)
+ {
+ bs.read(&acc, 1);
+ mask = (unsigned char)0x80;
+ }
+ if (acc & mask)
+ row[c] = 1;
+ else
+ row[c] = 0;
+ mask >>= 1;
+ }
+ row -= bytes_per_row;
+ }
+}
+
+void
+GBitmap::read_pgm_raw(ByteStream &bs)
+{
+ unsigned char *row = bytes_data + border;
+ row += (nrows-1) * bytes_per_row;
+ for (int n = nrows-1; n>=0; n--)
+ {
+ for (int c = 0; c<ncolumns; c++)
+ {
+ unsigned char x;
+ bs.read((void*)&x, 1);
+ row[c] = grays - 1 - x;
+ }
+ row -= bytes_per_row;
+ }
+}
+
+void
+GBitmap::read_rle_raw(ByteStream &bs)
+{
+ // interpret runs data
+ unsigned char h;
+ unsigned char p = 0;
+ unsigned char *row = bytes_data + border;
+ int n = nrows - 1;
+ row += n * bytes_per_row;
+ int c = 0;
+ while (n >= 0)
+ {
+ bs.read(&h, 1);
+ int x = h;
+ if (x >= (int)RUNOVERFLOWVALUE)
+ {
+ bs.read(&h, 1);
+ x = h + ((x - (int)RUNOVERFLOWVALUE) << 8);
+ }
+ if (c+x > ncolumns)
+ G_THROW( ERR_MSG("GBitmap.lost_sync") );
+ while (x-- > 0)
+ row[c++] = p;
+ p = 1 - p;
+ if (c >= ncolumns)
+ {
+ c = 0;
+ p = 0;
+ row -= bytes_per_row;
+ n -= 1;
+ }
+ }
+}
+
+
+// ------ save bitmaps
+
+void
+GBitmap::save_pbm(ByteStream &bs, int raw)
+{
+ // check arguments
+ if (grays > 2)
+ G_THROW( ERR_MSG("GBitmap.cant_make_PBM") );
+ GMonitorLock lock(monitor());
+ // header
+ {
+ GUTF8String head;
+ head.format("P%c\n%d %d\n", (raw ? '4' : '1'), ncolumns, nrows);
+ bs.writall((void*)(const char *)head, head.length());
+ }
+ // body
+ if(raw)
+ {
+ if(!rle)
+ compress();
+ const unsigned char *runs=rle;
+ const unsigned char * const runs_end=rle+rlelength;
+ const int count=(ncolumns+7)>>3;
+ unsigned char *buf;
+ GPBuffer<unsigned char> gbuf(buf,count);
+ while(runs<runs_end)
+ {
+ rle_get_bitmap(ncolumns,runs,buf,false);
+ bs.writall(buf,count);
+ }
+ }else
+ {
+ if (!bytes)
+ uncompress();
+ const unsigned char *row = bytes + border;
+ int n = nrows - 1;
+ row += n * bytes_per_row;
+ while (n >= 0)
+ {
+ unsigned char eol='\n';
+ for (int c=0; c<ncolumns;)
+ {
+ unsigned char bit= (row[c] ? '1' : '0');
+ bs.write((void*)&bit, 1);
+ c += 1;
+ if (c==ncolumns || (c&(int)RUNMSBMASK)==0)
+ bs.write((void*)&eol, 1);
+ }
+ // next row
+ row -= bytes_per_row;
+ n -= 1;
+ }
+ }
+}
+
+void
+GBitmap::save_pgm(ByteStream &bs, int raw)
+{
+ // checks
+ GMonitorLock lock(monitor());
+ if (!bytes)
+ uncompress();
+ // header
+ GUTF8String head;
+ head.format("P%c\n%d %d\n%d\n", (raw ? '5' : '2'), ncolumns, nrows, grays-1);
+ bs.writall((void*)(const char *)head, head.length());
+ // body
+ const unsigned char *row = bytes + border;
+ int n = nrows - 1;
+ row += n * bytes_per_row;
+ while (n >= 0)
+ {
+ if (raw)
+ {
+ for (int c=0; c<ncolumns; c++)
+ {
+ char x = grays - 1 - row[c];
+ bs.write((void*)&x, 1);
+ }
+ }
+ else
+ {
+ unsigned char eol='\n';
+ for (int c=0; c<ncolumns; )
+ {
+ head.format("%d ", grays - 1 - row[c]);
+ bs.writall((void*)(const char *)head, head.length());
+ c += 1;
+ if (c==ncolumns || (c&0x1f)==0)
+ bs.write((void*)&eol, 1);
+ }
+ }
+ row -= bytes_per_row;
+ n -= 1;
+ }
+}
+
+void
+GBitmap::save_rle(ByteStream &bs)
+{
+ // checks
+ if (ncolumns==0 || nrows==0)
+ G_THROW( ERR_MSG("GBitmap.not_init") );
+ GMonitorLock lock(monitor());
+ if (grays > 2)
+ G_THROW( ERR_MSG("GBitmap.cant_make_PBM") );
+ // header
+ GUTF8String head;
+ head.format("R4\n%d %d\n", ncolumns, nrows);
+ bs.writall((void*)(const char *)head, head.length());
+ // body
+ if (rle)
+ {
+ bs.writall((void*)rle, rlelength);
+ }
+ else
+ {
+ unsigned char *runs = 0;
+ GPBuffer<unsigned char> gruns(runs);
+ int size = encode(runs,gruns);
+ bs.writall((void*)runs, size);
+ }
+}
+
+
+// ------ runs
+
+
+void
+GBitmap::makerows(
+ int nrows, const int ncolumns, unsigned char *runs, unsigned char *rlerows[])
+{
+ while (nrows-- > 0)
+ {
+ rlerows[nrows] = runs;
+ int c;
+ for(c=0;c<ncolumns;c+=GBitmap::read_run(runs))
+ EMPTY_LOOP;
+ if (c > ncolumns)
+ G_THROW( ERR_MSG("GBitmap.lost_sync2") );
+ }
+}
+
+
+void
+GBitmap::rle_get_bitmap (
+ const int ncolumns,
+ const unsigned char *&runs,
+ unsigned char *bitmap,
+ const bool invert )
+{
+ const int obyte_def=invert?0xff:0;
+ const int obyte_ndef=invert?0:0xff;
+ int mask=0x80,obyte=0;
+ for(int c=ncolumns;c > 0 ;)
+ {
+ int x=read_run(runs);
+ c-=x;
+ while((x--)>0)
+ {
+ if(!(mask>>=1))
+ {
+ *(bitmap++) = obyte^obyte_def;
+ obyte=0;
+ mask=0x80;
+ for(;x>=8;x-=8)
+ {
+ *(bitmap++)=obyte_def;
+ }
+ }
+ }
+ if(c>0)
+ {
+ int x=read_run(runs);
+ c-=x;
+ while((x--)>0)
+ {
+ obyte|=mask;
+ if(!(mask>>=1))
+ {
+ *(bitmap++)=obyte^obyte_def;
+ obyte=0;
+ mask=0x80;
+ for(;(x>8);x-=8)
+ *(bitmap++)=obyte_ndef;
+ }
+ }
+ }
+ }
+ if(mask != 0x80)
+ {
+ *(bitmap++)=obyte^obyte_def;
+ }
+}
+
+int
+GBitmap::rle_get_bits(int rowno, unsigned char *bits) const
+{
+ GMonitorLock lock(monitor());
+ if (!rle)
+ return 0;
+ if (rowno<0 || rowno>=nrows)
+ return 0;
+ if (!rlerows)
+ {
+ const_cast<GPBuffer<unsigned char *> &>(grlerows).resize(nrows);
+ makerows(nrows,ncolumns,rle,const_cast<unsigned char **>(rlerows));
+ }
+ int n = 0;
+ int p = 0;
+ int c = 0;
+ unsigned char *runs = rlerows[rowno];
+ while (c < ncolumns)
+ {
+ const int x=read_run(runs);
+ if ((c+=x)>ncolumns)
+ c = ncolumns;
+ while (n<c)
+ bits[n++] = p;
+ p = 1-p;
+ }
+ return n;
+}
+
+
+int
+GBitmap::rle_get_runs(int rowno, int *rlens) const
+{
+ GMonitorLock lock(monitor());
+ if (!rle)
+ return 0;
+ if (rowno<0 || rowno>=nrows)
+ return 0;
+ if (!rlerows)
+ {
+ const_cast<GPBuffer<unsigned char *> &>(grlerows).resize(nrows);
+ makerows(nrows,ncolumns,rle,const_cast<unsigned char **>(rlerows));
+ }
+ int n = 0;
+ int d = 0;
+ int c = 0;
+ unsigned char *runs = rlerows[rowno];
+ while (c < ncolumns)
+ {
+ const int x=read_run(runs);
+ if (n>0 && !x)
+ {
+ n--;
+ d = d-rlens[n];
+ }
+ else
+ {
+ rlens[n++] = (c+=x)-d;
+ d = c;
+ }
+ }
+ return n;
+}
+
+
+int
+GBitmap::rle_get_rect(GRect &rect) const
+{
+ GMonitorLock lock(monitor());
+ if (!rle)
+ return 0;
+ int area = 0;
+ unsigned char *runs = rle;
+ rect.xmin = ncolumns;
+ rect.ymin = nrows;
+ rect.xmax = 0;
+ rect.ymax = 0;
+ int r = nrows;
+ while (--r >= 0)
+ {
+ int p = 0;
+ int c = 0;
+ int n = 0;
+ while (c < ncolumns)
+ {
+ const int x=read_run(runs);
+ if(x)
+ {
+ if (p)
+ {
+ if (c < rect.xmin)
+ rect.xmin = c;
+ if ((c += x) > rect.xmax)
+ rect.xmax = c-1;
+ n += x;
+ }
+ else
+ {
+ c += x;
+ }
+ }
+ p = 1-p;
+ }
+ area += n;
+ if (n)
+ {
+ rect.ymin = r;
+ if (r > rect.ymax)
+ rect.ymax = r;
+ }
+ }
+ if (area==0)
+ rect.clear();
+ return area;
+}
+
+
+
+// ------ helpers
+
+int
+GBitmap::encode(unsigned char *&pruns,GPBuffer<unsigned char> &gpruns) const
+{
+ // uncompress rle information
+ if (nrows==0 || ncolumns==0)
+ {
+ gpruns.resize(0);
+ return 0;
+ }
+ if (!bytes)
+ {
+ unsigned char *runs;
+ GPBuffer<unsigned char> gruns(runs,rlelength);
+ memcpy((void*)runs, rle, rlelength);
+ gruns.swap(gpruns);
+ return rlelength;
+ }
+ gpruns.resize(0);
+ // create run array
+ int pos = 0;
+ int maxpos = 1024 + ncolumns + ncolumns;
+ unsigned char *runs;
+ GPBuffer<unsigned char> gruns(runs,maxpos);
+ // encode bitmap as rle
+ const unsigned char *row = bytes + border;
+ int n = nrows - 1;
+ row += n * bytes_per_row;
+ while (n >= 0)
+ {
+ if (maxpos < pos+ncolumns+ncolumns+2)
+ {
+ maxpos += 1024 + ncolumns + ncolumns;
+ gruns.resize(maxpos);
+ }
+
+ unsigned char *runs_pos=runs+pos;
+ const unsigned char * const runs_pos_start=runs_pos;
+ append_line(runs_pos,row,ncolumns);
+ pos+=(size_t)runs_pos-(size_t)runs_pos_start;
+ row -= bytes_per_row;
+ n -= 1;
+ }
+ // return result
+ gruns.resize(pos);
+ gpruns.swap(gruns);
+ return pos;
+}
+
+void
+GBitmap::decode(unsigned char *runs)
+{
+ // initialize pixel array
+ if (nrows==0 || ncolumns==0)
+ G_THROW( ERR_MSG("GBitmap.not_init") );
+ bytes_per_row = ncolumns + border;
+ if (runs==0)
+ G_THROW( ERR_MSG("GBitmap.null_arg") );
+ int npixels = nrows * bytes_per_row + border;
+ if (!bytes_data)
+ {
+ gbytes_data.resize(npixels);
+ bytes = bytes_data;
+ }
+ gbytes_data.clear();
+ gzerobuffer=zeroes(bytes_per_row + border);
+ // interpret runs data
+ int c, n;
+ unsigned char p = 0;
+ unsigned char *row = bytes_data + border;
+ n = nrows - 1;
+ row += n * bytes_per_row;
+ c = 0;
+ while (n >= 0)
+ {
+ int x = read_run(runs);
+ if (c+x > ncolumns)
+ G_THROW( ERR_MSG("GBitmap.lost_sync2") );
+ while (x-- > 0)
+ row[c++] = p;
+ p = 1 - p;
+ if (c >= ncolumns)
+ {
+ c = 0;
+ p = 0;
+ row -= bytes_per_row;
+ n -= 1;
+ }
+ }
+ // Free rle data possibly attached to this bitmap
+ grle.resize(0);
+ grlerows.resize(0);
+ rlelength = 0;
+#ifndef NDEBUG
+ check_border();
+#endif
+}
+
+class GBitmap::ZeroBuffer : public GPEnabled
+{
+public:
+ ZeroBuffer(const unsigned int zerosize);
+ unsigned char *zerobuffer;
+ GPBuffer<unsigned char> gzerobuffer;
+};
+
+GBitmap::ZeroBuffer::ZeroBuffer(const unsigned int zerosize)
+: gzerobuffer(zerobuffer,zerosize)
+{
+ gzerobuffer.clear();
+ GBitmap::zerobuffer=zerobuffer;
+ GBitmap::zerosize=zerosize;
+}
+
+static const unsigned char static_zerobuffer[]=
+{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 32
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 64
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 96
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 128
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 160
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 192
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 234
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 256
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 288
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 320
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 352
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 384
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 416
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 448
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 480
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 512
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 544
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 576
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 608
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 640
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 672
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 704
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 736
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 768
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 800
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 832
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 864
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 896
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 928
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 960
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 992
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+32
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+64
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+96
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+128
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+160
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+192
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+234
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+256
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+288
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+320
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+352
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+384
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+416
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+448
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+480
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+512
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+544
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+576
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+608
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+640
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+672
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+704
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+736
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+768
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+800
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+832
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+864
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+896
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+928
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+960
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 1024+992
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+32
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+64
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+96
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+128
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+160
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+192
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+234
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+256
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+288
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+320
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+352
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+384
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+416
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+448
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+480
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+512
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+544
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+576
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+608
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+640
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+672
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+704
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+736
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+768
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+800
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+832
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+864
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+896
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+928
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+960
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 2048+992
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+32
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+64
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+96
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+128
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+160
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+192
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+234
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+256
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+288
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+320
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+352
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+384
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+416
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+448
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+480
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+512
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+544
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+576
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+608
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+640
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+672
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+704
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+736
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+768
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+800
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+832
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+864
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+896
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+928
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+960
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 3072+992
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // 4096
+
+int GBitmap::zerosize = sizeof(static_zerobuffer);
+unsigned char *GBitmap::zerobuffer=const_cast<unsigned char *>(static_zerobuffer);
+
+GP<GBitmap::ZeroBuffer>
+GBitmap::zeroes(int required)
+{
+ GMonitorLock lock(&monitors[0]); // any monitor would do
+ static GP<GBitmap::ZeroBuffer> gzerobuffer;
+ if (zerosize < required)
+ {
+ int z;
+ for(z=zerosize;z<required;z <<= 1)
+ EMPTY_LOOP;
+ z=(z+0xfff)&(~0xfff);
+ gzerobuffer=new GBitmap::ZeroBuffer((unsigned int)z);
+ }
+ return gzerobuffer;
+}
+
+
+// Fills a bitmap with the given value
+void
+GBitmap::fill(unsigned char value)
+{
+ GMonitorLock lock(monitor());
+ for(unsigned int y=0; y<rows(); y++)
+ {
+ unsigned char* bm_y = (*this)[y];
+ for(unsigned int x=0; x<columns(); x++)
+ bm_y[x] = value;
+ }
+}
+
+
+void
+GBitmap::append_long_run(unsigned char *&data, int count)
+{
+ while (count > MAXRUNSIZE)
+ {
+ data[0] = data[1] = 0xff;
+ data[2] = 0;
+ data += 3;
+ count -= MAXRUNSIZE;
+ }
+ if (count < RUNOVERFLOWVALUE)
+ {
+ data[0] = count;
+ data += 1;
+ }
+ else
+ {
+ data[0] = (count>>8) + GBitmap::RUNOVERFLOWVALUE;
+ data[1] = (count & 0xff);
+ data += 2;
+ }
+}
+
+
+void
+GBitmap::append_line(unsigned char *&data,const unsigned char *row,
+ const int rowlen,bool invert)
+{
+ const unsigned char *rowend=row+rowlen;
+ bool p=!invert;
+ while(row<rowend)
+ {
+ int count=0;
+ if ((p=!p))
+ {
+ if(*row)
+ for(++count,++row;(row<rowend)&&*row;++count,++row)
+ EMPTY_LOOP;
+ }
+ else if(!*row)
+ {
+ for(++count,++row;(row<rowend)&&!*row;++count,++row)
+ EMPTY_LOOP;
+ }
+ append_run(data,count);
+ }
+}
+
+#if 0
+static inline int
+GetRowTDLRNR(
+ GBitmap &bit,const int row, const unsigned char *&startptr,
+ const unsigned char *&stopptr)
+{
+ stopptr=(startptr=bit[row])+bit.columns();
+ return 1;
+}
+
+static inline int
+GetRowTDLRNR(
+ GBitmap &bit,const int row, const unsigned char *&startptr,
+ const unsigned char *&stopptr)
+{
+ stopptr=(startptr=bit[row])+bit.columns();
+ return 1;
+}
+
+static inline int
+GetRowTDRLNR(
+ GBitmap &bit,const int row, const unsigned char *&startptr,
+ const unsigned char *&stopptr)
+{
+ startptr=(stopptr=bit[row]-1)+bit.columns();
+ return -1;
+}
+#endif // 0
+
+GP<GBitmap>
+GBitmap::rotate(int count)
+{
+ GP<GBitmap> newbitmap=this;
+ if((count%=4))
+ {
+ if( count & 0x01 )
+ {
+ newbitmap = new GBitmap(ncolumns, nrows);
+ }else
+ {
+ newbitmap = new GBitmap(nrows, ncolumns);
+ }
+ GMonitorLock lock(monitor());
+ if (!bytes_data)
+ uncompress();
+ GBitmap &dbitmap = *newbitmap;
+ dbitmap.set_grays(grays);
+ switch(count)
+ {
+ case 1: // rotate 90 counter clockwise
+ {
+ const int lastrow = dbitmap.rows()-1;
+ for(int y=0; y<nrows; y++)
+ {
+ const unsigned char *r=operator[] (y);
+ for(int x=0,xnew=lastrow;xnew>=0; x++,xnew--)
+ {
+ dbitmap[xnew][y] = r[x];
+ }
+ }
+ }
+ break;
+ case 2: // rotate 180 counter clockwise
+ {
+ const int lastrow = dbitmap.rows()-1;
+ const int lastcolumn = dbitmap.columns()-1;
+ for(int y=0,ynew=lastrow;ynew>=0; y++,ynew--)
+ {
+ const unsigned char *r=operator[] (y);
+ unsigned char *d=dbitmap[ynew];
+ for(int xnew=lastcolumn;xnew>=0; r++,--xnew)
+ {
+ d[xnew] = *r;
+ }
+ }
+ }
+ break;
+ case 3: // rotate 270 counter clockwise
+ {
+ const int lastcolumn = dbitmap.columns()-1;
+ for(int y=0,ynew=lastcolumn;ynew>=0;y++,ynew--)
+ {
+ const unsigned char *r=operator[] (y);
+ for(int x=0; x<ncolumns; x++)
+ {
+ dbitmap[x][ynew] = r[x];
+ }
+ }
+ }
+ break;
+ }
+ if(grays == 2)
+ {
+ compress();
+ dbitmap.compress();
+ }
+ }
+ return newbitmap;
+}
+
+#ifndef NDEBUG
+void
+GBitmap::check_border() const
+{int col ;
+ if (bytes)
+ {
+ const unsigned char *p = (*this)[-1];
+ for (col=-border; col<ncolumns+border; col++)
+ if (p[col])
+ G_THROW( ERR_MSG("GBitmap.zero_damaged") );
+ for (int row=0; row<nrows; row++)
+ {
+ p = (*this)[row];
+ for (col=-border; col<0; col++)
+ if (p[col])
+ G_THROW( ERR_MSG("GBitmap.left_damaged") );
+ for (col=ncolumns; col<ncolumns+border; col++)
+ if (p[col])
+ G_THROW( ERR_MSG("GBitmap.right_damaged") );
+ }
+ }
+}
+#endif
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+
diff --git a/kviewshell/plugins/djvu/libdjvu/GBitmap.h b/kviewshell/plugins/djvu/libdjvu/GBitmap.h
new file mode 100644
index 00000000..74669c05
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GBitmap.h
@@ -0,0 +1,673 @@
+//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: GBitmap.h,v 1.9 2004/04/17 23:56:11 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _GBITMAP_H_
+#define _GBITMAP_H_
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+#include "GSmartPointer.h"
+#ifndef NDEBUG
+#include "GException.h"
+#endif
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+class GRect;
+class GMonitor;
+class ByteStream;
+
+/** @name GBitmap.h
+
+ Files #"GBitmap.h"# and #"GBitmap.cpp"# implement class \Ref{GBitmap}.
+ Instances of this class represent bilevel or gray-level images. The
+ ``bottom left'' coordinate system is used consistently in the DjVu library.
+ Line zero of a bitmap is the bottom line in the bitmap. Pixels are
+ organized from left to right within each line. As suggested by its name,
+ class #GBitmap# was initially a class for bilevel images only. It was
+ extended to handle gray-level images when arose the need to render
+ anti-aliased images. This class has been a misnomer since then.
+
+ {\bf ToDo} --- Class #GBitmap# can internally represent bilevel images
+ using a run-length encoded representation. Some algorithms may benefit
+ from a direct access to this run information.
+
+ @memo
+ Generic support for bilevel and gray-level images.
+ @author
+ L\'eon Bottou <leonb@research.att.com>
+ @version
+ #$Id: GBitmap.h,v 1.9 2004/04/17 23:56:11 leonb Exp $#
+
+ */
+//@{
+
+
+/** Bilevel and gray-level images. Instances of class #GBitmap# represent
+ bilevel or gray-level images. Images are usually represented using one
+ byte per pixel. Value zero represents a white pixel. A value equal to
+ the number of gray levels minus one represents a black pixel. The number
+ of gray levels is returned by the function \Ref{get_grays} and can be
+ manipulated by the functions \Ref{set_grays} and \Ref{change_grays}.
+
+ The bracket operator returns a pointer to the bytes composing one line of
+ the image. This pointer can be used to read or write the image pixels.
+ Line zero represents the bottom line of the image.
+
+ The memory organization is setup in such a way that you can safely read a
+ few pixels located in a small border surrounding all four sides of the
+ image. The width of this border can be modified using the function
+ \Ref{minborder}. The border pixels are initialized to zero and therefore
+ represent white pixels. You should never write anything into border
+ pixels because they are shared between images and between lines. */
+
+class GBitmap : public GPEnabled
+{
+protected:
+ GBitmap(void);
+ GBitmap(int nrows, int ncolumns, int border=0);
+ GBitmap(const GBitmap &ref);
+ GBitmap(const GBitmap &ref, int border);
+ GBitmap(const GBitmap &ref, const GRect &rect, int border=0);
+ GBitmap(ByteStream &ref, int border=0);
+public:
+ virtual ~GBitmap();
+ void destroy(void);
+ /** @name Construction. */
+ //@{
+ /** Constructs an empty GBitmap object. The returned GBitmap has zero rows
+ and zero columns. Use function \Ref{init} to change the size of the
+ image. */
+ static GP<GBitmap> create(void) {return new GBitmap;}
+
+ /** Constructs a GBitmap with #nrows# rows and #ncolumns# columns. All
+ pixels are initialized to white. The optional argument #border#
+ specifies the size of the optional border of white pixels surrounding
+ the image. The number of gray levels is initially set to #2#. */
+ static GP<GBitmap> create(const int nrows, const int ncolumns, const int border=0)
+ {return new GBitmap(nrows,ncolumns, border); }
+
+ /** Copy constructor. Constructs a GBitmap by replicating the size, the
+ border and the contents of GBitmap #ref#. */
+ static GP<GBitmap> create(const GBitmap &ref)
+ {return new GBitmap(ref);}
+
+ /** Constructs a GBitmap by copying the contents of GBitmap #ref#.
+ Argument #border# specifies the width of the optional border. */
+ static GP<GBitmap> create(const GBitmap &ref, const int border)
+ { return new GBitmap(ref,border); }
+
+ /** Constructs a GBitmap by copying a rectangular segment #rect# of GBitmap
+ #ref#. The optional argument #border# specifies the size of the
+ optional border of white pixels surrounding the image. */
+ static GP<GBitmap> create(const GBitmap &ref, const GRect &rect, const int border=0)
+ { return new GBitmap(ref,rect,border); }
+
+ /** Constructs a GBitmap by reading PBM, PGM or RLE data from ByteStream
+ #ref# into this GBitmap. The optional argument #border# specifies the
+ size of the optional border of white pixels surrounding the image. See
+ \Ref{PNM and RLE file formats} for more information. */
+ static GP<GBitmap> create(ByteStream &ref, const int border=0)
+ { return new GBitmap(ref,border); }
+
+ //@}
+
+ /** @name Initialization. */
+ //@{
+ /** Resets this GBitmap size to #nrows# rows and #ncolumns# columns and sets
+ all pixels to white. The optional argument #border# specifies the size
+ of the optional border of white pixels surrounding the image. The
+ number of gray levels is initialized to #2#. */
+ void init(int nrows, int ncolumns, int border=0);
+ /** Initializes this GBitmap with the contents of the GBitmap #ref#. The
+ optional argument #border# specifies the size of the optional border of
+ white pixels surrounding the image. */
+ void init(const GBitmap &ref, int border=0);
+ /** Initializes this GBitmap with a rectangular segment #rect# of GBitmap
+ #ref#. The optional argument #border# specifies the size of the
+ optional border of white pixels surrounding the image. */
+ void init(const GBitmap &ref, const GRect &rect, int border=0);
+ /** Reads PBM, PGM or RLE data from ByteStream #ref# into this GBitmap. The
+ previous content of the GBitmap object is lost. The optional argument
+ #border# specifies the size of the optional border of white pixels
+ surrounding the image. See \Ref{PNM and RLE file formats} for more
+ information. */
+ void init(ByteStream &ref, int border=0);
+ /** Assignment operator. Initializes this GBitmap by copying the size, the
+ border and the contents of GBitmap #ref#. */
+ GBitmap& operator=(const GBitmap &ref);
+ /** Initializes all the GBitmap pixels to value #value#. */
+ void fill(unsigned char value);
+ //@}
+
+ /** @name Accessing the pixels. */
+ //@{
+ /** Returns the number of rows (the image height). */
+ unsigned int rows() const;
+ /** Returns the number of columns (the image width). */
+ unsigned int columns() const;
+ /** Returns a constant pointer to the first byte of row #row#.
+ This pointer can be used as an array to read the row elements. */
+ const unsigned char *operator[] (int row) const;
+ /** Returns a pointer to the first byte of row #row#.
+ This pointer can be used as an array to read or write the row elements. */
+ unsigned char *operator[] (int row);
+ /** Returns the size of a row in memory (in pixels). This number is equal
+ to the difference between pointers to pixels located in the same column
+ in consecutive rows. This difference can be larger than the number of
+ columns in the image. */
+ unsigned int rowsize() const;
+ /** Makes sure that the border is at least #minimum# pixels large. This
+ function does nothing it the border width is already larger than
+ #minimum#. Otherwise it reorganizes the data in order to provide a
+ border of #minimum# pixels. */
+ void minborder(int minimum);
+ //@}
+
+ /** @name Managing gray levels. */
+ //@{
+ /** Returns the number of gray levels.
+ Value #2# denotes a bilevel image. */
+ int get_grays() const;
+ /** Sets the number of gray levels without changing the pixels.
+ Argument #grays# must be in range #2# to #256#. */
+ void set_grays(int grays);
+ /** Changes the number of gray levels. The argument #grays# must be in the
+ range #2# to #256#. All the pixel values are then rescaled and clipped
+ in range #0# to #grays-1#. */
+ void change_grays(int grays);
+ /** Binarizes a gray level image using a threshold. The number of gray
+ levels is reduced to #2# as in a bilevel image. All pixels whose value
+ was strictly greater than #threshold# are set to black. All other pixels
+ are set to white. */
+ void binarize_grays(int threshold=0);
+ //@}
+
+ /** @name Optimizing the memory usage.
+ The amount of memory used by bilevel images can be reduced using
+ function \Ref{compress}, which encodes the image using a run-length
+ encoding scheme. The bracket operator decompresses the image on demand.
+ A few highly optimized functions (e.g. \Ref{blit}) can use a run-length
+ encoded bitmap without decompressing it. There are unfortunate locking
+ issues associated with this capability (c.f. \Ref{share} and
+ \Ref{monitor}). */
+ //@{
+ /** Reduces the memory required for a bilevel image by using a run-length
+ encoded representation. Functions that need to access the pixel array
+ will decompress the image on demand. */
+ void compress();
+ /** Decodes run-length encoded bitmaps and recreate the pixel array.
+ This function is usually called by #operator[]# when needed. */
+ void uncompress();
+ /** Returns the number of bytes allocated for this image. */
+ unsigned int get_memory_usage() const;
+ /** Returns a possibly null pointer to a \Ref{GMonitor} for this bitmap.
+ You should use this monitor to ensure that the data representation of the
+ bitmap will not change while you are using it. We suggest using
+ class \Ref{GMonitorLock} which properly handles null monitor pointers. */
+ GMonitor *monitor() const;
+ /** Associates a \Ref{GMonitor} with this bitmap. This function should be
+ called on all bitmaps susceptible of being simultaneously used by
+ several threads. It will make sure that function \Ref{monitor} returns
+ a pointer to a suitable monitor for this bitmap. */
+ void share();
+ //@}
+
+ /** @name Accessing RLE data.
+ The next functions are useful for processing bilevel images
+ encoded using the run length encoding scheme. These functions always return
+ zero if the bitmap is not RLE encoded. Function \Ref{compress} must
+ be used to ensure that the bitmap is RLE encoded. */
+ //@{
+ /** Gets the pixels for line #rowno#. One line of pixel is stored as
+ #unsigned char# values into array #bits#. Each pixel is either 1 or 0.
+ The array must be large enough to hold the whole line. The number of
+ pixels is returned. */
+
+ int rle_get_bits(int rowno, unsigned char *bits) const;
+
+ /** Gets the bitmap line rle data passed. One line of pixel is stored one
+ with 8 bits per #unsigned char# in an array. The array must be large
+ enough to hold the whole line. */
+
+ static void rle_get_bitmap(const int ncolumns,const unsigned char *&runs,
+ unsigned char *bitmap, const bool invert );
+
+ /** Gets the lengths of all runs in line #rowno#. The array #rlens# must be
+ large enough to accomodate #w+2# integers where #w# is the number of
+ columns in the image. These integers represent the lengths of
+ consecutive runs of alternatively white or black pixels. Lengths can be
+ zero in order to allow for lines starting with black pixels. This
+ function returns the total number of runs in the line. */
+ int rle_get_runs(int rowno, int *rlens) const;
+ /** Gets the smallest rectangle enclosing black pixels.
+ Rectangle rect gives the coordinates of the smallest rectangle
+ containing all black pixels. Returns the number of black pixels. */
+ int rle_get_rect(GRect &rect) const;
+ //@}
+
+ /** @name Additive Blit.
+ The blit functions are designed to efficiently construct an anti-aliased
+ image by copying smaller images at predefined locations. The image of a
+ page, for instance, is composed by copying the images of characters at
+ predefined locations. These functions are fairly optimized. They can
+ directly use compressed GBitmaps (see \Ref{compress}). We consider in
+ this section that each GBitmap comes with a coordinate system defined as
+ follows. Position (#0#,#0#) corresponds to the bottom left corner of
+ the bottom left pixel. Position (#1#,#1#) corresponds to the top right
+ corner of the bottom left pixel, which is also the bottom left corner of
+ the second pixel of the second row. Position (#w#,#h#), where #w# and
+ #h# denote the size of the GBitmap, corresponds to the top right corner
+ of the top right pixel. */
+
+ //@{
+ /** Performs an additive blit of the GBitmap #bm#. The GBitmap #bm# is
+ first positioned above the current GBitmap in such a way that position
+ (#u#,#v#) in GBitmap #bm# corresponds to position (#u#+#x#,#v#+#y#) in
+ the current GBitmap. The value of each pixel in GBitmap #bm# is then
+ added to the value of the corresponding pixel in the current GBitmap.
+
+ {\bf Example}: Assume for instance that the current GBitmap is initially
+ white (all pixels have value zero). This operation copies the pixel
+ values of GBitmap #bm# at position (#x#,#y#) into the current GBitmap.
+ Note that function #blit# does not change the number of gray levels in
+ the current GBitmap. You may have to call \Ref{set_grays} to specify
+ how the pixel values should be interpreted. */
+ void blit(const GBitmap *bm, int x, int y);
+ /** Performs an additive blit of the GBitmap #bm# with anti-aliasing. The
+ GBitmap #bm# is first positioned above the current GBitmap in such a
+ way that position (#u#,#v#) in GBitmap #bm# corresponds to position
+ (#u#+#x#/#subsample#,#v#+#y#/#subsample#) in the current GBitmap. This
+ mapping results in a contraction of GBitmap #bm# by a factor
+ #subsample#. Each pixel of the current GBitmap can be covered by a
+ maximum of #subsample^2# pixels of GBitmap #bm#. The value of
+ each pixel in GBitmap #bm# is then added to the value of the
+ corresponding pixel in the current GBitmap.
+
+ {\bf Example}: Assume for instance that the current GBitmap is initially
+ white (all pixels have value zero). Each pixel of the current GBitmap
+ then contains the sum of the gray levels of the corresponding pixels in
+ GBitmap #bm#. There are up to #subsample*subsample# such pixels. If
+ for instance GBitmap #bm# is a bilevel image (pixels can be #0# or #1#),
+ the pixels of the current GBitmap can take values in range #0# to
+ #subsample*subsample#. Note that function #blit# does not change the
+ number of gray levels in the current GBitmap. You must call
+ \Ref{set_grays} to indicate that there are #subsample^2+1# gray
+ levels. Since there is at most 256 gray levels, this also means that
+ #subsample# should never be greater than #15#.
+
+ {\bf Remark}: Arguments #x# and #y# do not represent a position in the
+ coordinate system of the current GBitmap. According to the above
+ discussion, the position is (#x/subsample#,#y/subsample#). In other
+ words, you can position the blit with a sub-pixel resolution. The
+ resulting anti-aliasing changes are paramount to the image quality. */
+ void blit(const GBitmap *shape, int x, int y, int subsample);
+ //@}
+
+ /** @name Saving images.
+ The following functions write PBM, PGM and RLE files. PBM and PGM are
+ well known formats for bilevel and gray-level images. The RLE is a
+ simple run-length encoding scheme for bilevel images. These files can be
+ read using the ByteStream based constructor or initialization function.
+ See \Ref{PNM and RLE file formats} for more information. */
+ //@{
+ /** Saves the image into ByteStream #bs# using the PBM format. Argument
+ #raw# selects the ``Raw PBM'' (1) or the ``Ascii PBM'' (0) format. The
+ image is saved as a bilevel image. All non zero pixels are considered
+ black pixels. See section \Ref{PNM and RLE file formats}. */
+ void save_pbm(ByteStream &bs, int raw=1);
+ /** Saves the image into ByteStream #bs# using the PGM format. Argument
+ #raw# selects the ``Raw PGM'' (1) or the ``Ascii PGM'' (0) format. The
+ image is saved as a gray level image. See section
+ \Ref{PNM and RLE file formats}. */
+ void save_pgm(ByteStream &bs, int raw=1);
+ /** Saves the image into ByteStream #bs# using the RLE file format.
+ The image is saved as a bilevel image. All non zero pixels are
+ considered black pixels. See section \Ref{PNM and RLE file formats}. */
+ void save_rle(ByteStream &bs);
+ //@}
+
+ /** @name Stealing or borrowing the memory buffer (advanced). */
+ //@{
+ /** Steals the memory buffer of a GBitmap. This function returns the
+ address of the memory buffer allocated by this GBitmap object. The
+ offset of the first pixel in the bottom line is written into variable
+ #offset#. Other lines can be accessed using pointer arithmetic (see
+ \Ref{rowsize}). The GBitmap object no longer ``owns'' the buffer: you
+ must explicitly de-allocate the buffer using #operator delete []#. This
+ de-allocation should take place after the destruction or the
+ re-initialization of the GBitmap object. This function will return a
+ null pointer if the GBitmap object does not ``own'' the buffer in the
+ first place. */
+ unsigned char *take_data(size_t &offset);
+ /** Initializes this GBitmap by borrowing a memory segment. The GBitmap
+ then directly addresses the memory buffer #data# provided by the user.
+ This buffer must be large enough to hold #w*h# bytes representing each
+ one pixel. The GBitmap object does not ``own'' the buffer: you must
+ explicitly de-allocate the buffer using #operator delete []#. This
+ de-allocation should take place after the destruction or the
+ re-initialization of the GBitmap object. */
+ inline void borrow_data(unsigned char &data, int w, int h);
+ /** Same as borrow_data, except GBitmap will call #delete[]#. */
+ void donate_data(unsigned char *data, int w, int h);
+ /** Return a pointer to the rle data. */
+ const unsigned char *get_rle(unsigned int &rle_length);
+ /** Initializes this GBitmap by setting the size to #h# rows and #w#
+ columns, and directly addressing the memory buffer #rledata# provided by
+ the user. This buffer contains #rledatalen# bytes representing the
+ bitmap in run length encoded form. The GBitmap object then ``owns'' the
+ buffer (unlike #borrow_data#, but like #donate_data#) and will
+ deallocate this buffer when appropriate: you should not deallocate this
+ buffer yourself. The encoding of buffer #rledata# is similar to the
+ data segment of the RLE file format (without the header) documented in
+ \Ref{PNM and RLE file formats}. */
+ void donate_rle(unsigned char *rledata, unsigned int rledatalen, int w, int h);
+ /** Static function for parsing run data.
+ This function returns one run length encoded at position #data#
+ and increments the pointer #data# accordingly. */
+ static inline int read_run(const unsigned char *&data);
+ static inline int read_run(unsigned char *&data);
+ /** Static function for generating run data.
+ This function encoded run length #count# at position #data#
+ and increments the pointer accordingly. The pointer must
+ initially point to a large enough data buffer. */
+ static inline void append_run(unsigned char *&data, int count);
+ /** Rotates bitmap by 90, 180 or 270 degrees anticlockwise
+ and returns a new pixmap, input bitmap is not changed.
+ count can be 1, 2, or 3 for 90, 180, 270 degree rotation.
+ It returns the same bitmap if not rotated.
+ The input bitmap will be uncompressed for rotation*/
+ GP<GBitmap> rotate(int count=0);
+ //@}
+
+// These are constants, but we use enum because that works on older compilers.
+ enum {MAXRUNSIZE=0x3fff};
+ enum {RUNOVERFLOWVALUE=0xc0};
+ enum {RUNMSBMASK=0x3f};
+ enum {RUNLSBMASK=0xff};
+
+
+protected:
+ // bitmap components
+ unsigned short nrows;
+ unsigned short ncolumns;
+ unsigned short border;
+ unsigned short bytes_per_row;
+ unsigned short grays;
+ unsigned char *bytes;
+ unsigned char *bytes_data;
+ GPBuffer<unsigned char> gbytes_data;
+ unsigned char *rle;
+ GPBuffer<unsigned char> grle;
+ unsigned char **rlerows;
+ GPBuffer<unsigned char *> grlerows;
+ unsigned int rlelength;
+private:
+ GMonitor *monitorptr;
+public:
+ class ZeroBuffer;
+ friend class ZeroBuffer;
+ GP<ZeroBuffer> gzerobuffer;
+private:
+ static int zerosize;
+ static unsigned char *zerobuffer;
+ static GP<ZeroBuffer> zeroes(int ncolumns);
+ static unsigned int read_integer(char &lookahead, ByteStream &ref);
+ static void euclidian_ratio(int a, int b, int &q, int &r);
+ int encode(unsigned char *&pruns,GPBuffer<unsigned char> &gpruns) const;
+ void decode(unsigned char *runs);
+ void read_pbm_text(ByteStream &ref);
+ void read_pgm_text(ByteStream &ref);
+ void read_pbm_raw(ByteStream &ref);
+ void read_pgm_raw(ByteStream &ref);
+ void read_rle_raw(ByteStream &ref);
+ static void append_long_run(unsigned char *&data, int count);
+ static void append_line(unsigned char *&data,const unsigned char *row,
+ const int rowlen,bool invert=false);
+ static void makerows(int,const int, unsigned char *, unsigned char *[]);
+ friend class DjVu_Stream;
+ friend class DjVu_PixImage;
+public:
+#ifndef NDEBUG
+ void check_border() const;
+#endif
+};
+
+
+/** @name PNM and RLE file formats
+
+ {\bf PNM} --- There are actually three PNM file formats: PBM for bilevel
+ images, PGM for gray level images, and PPM for color images. These
+ formats are widely used by popular image manipulation packages such as
+ NetPBM \URL{http://www.arc.umn.edu/GVL/Software/netpbm.html} or
+ ImageMagick \URL{http://www.wizards.dupont.com/cristy/}.
+
+ {\bf RLE} --- The binary RLE file format is a simple run-length encoding
+ scheme for storing bilevel images. Encoding or decoding a RLE encoded
+ file is extremely simple. Yet RLE encoded files are usually much smaller
+ than the corresponding PBM encoded files. RLE files always begin with a
+ header line composed of:\\
+ - the two characters #"R4"#,\\
+ - one or more blank characters,\\
+ - the number of columns, encoded using characters #"0"# to #"9"#,\\
+ - one or more blank characters,\\
+ - the number of lines, encoded using characters #"0"# to #"9"#,\\
+ - exactly one blank character (usually a line-feed character).
+
+ The rest of the file encodes a sequence of numbers representing the
+ lengths of alternating runs of white and black pixels. Lines are encoded
+ starting with the top line and progressing towards the bottom line. Each
+ line starts with a white run. The decoder knows that a line is finished
+ when the sum of the run lengths for that line is equal to the number of
+ columns in the image. Numbers in range #0# to #191# are represented by a
+ single byte in range #0x00# to #0xbf#. Numbers in range #192# to #16383#
+ are represented by a two byte sequence: the first byte, in range #0xc0# to
+ #0xff#, encodes the six most significant bits of the number, the second
+ byte encodes the remaining eight bits of the number. This scheme allows
+ for runs of length zero, which are useful when a line starts with a black
+ pixel, and when a very long run (whose length exceeds #16383#) must be
+ split into smaller runs.
+
+ @memo
+ Simple image file formats. */
+
+//@}
+
+
+// ---------------- IMPLEMENTATION
+
+inline unsigned int
+GBitmap::rows() const
+{
+ return nrows;
+}
+
+inline unsigned int
+GBitmap::columns() const
+{
+ return ncolumns;
+}
+
+inline unsigned int
+GBitmap::rowsize() const
+{
+ return bytes_per_row;
+}
+
+inline int
+GBitmap::get_grays() const
+{
+ return grays;
+}
+
+inline unsigned char *
+GBitmap::operator[](int row)
+{
+ if (!bytes) uncompress();
+ if (row<0 || row>=nrows) {
+#ifndef NDEBUG
+ if (zerosize < bytes_per_row + border)
+ G_THROW( ERR_MSG("GBitmap.zero_small") );
+#endif
+ return zerobuffer + border;
+ }
+ return &bytes[row * bytes_per_row + border];
+}
+
+inline const unsigned char *
+GBitmap::operator[](int row) const
+{
+ if (!bytes) ((GBitmap*)this)->uncompress();
+ if (row<0 || row>=nrows) {
+#ifndef NDEBUG
+ if (zerosize < bytes_per_row + border)
+ G_THROW( ERR_MSG("GBitmap.zero_small") );
+#endif
+ return zerobuffer + border;
+ }
+ return &bytes[row * bytes_per_row + border];
+}
+
+inline GBitmap&
+GBitmap::operator=(const GBitmap &ref)
+{
+ init(ref, ref.border);
+ return *this;
+}
+
+inline GMonitor *
+GBitmap::monitor() const
+{
+ return monitorptr;
+}
+
+inline void
+GBitmap::euclidian_ratio(int a, int b, int &q, int &r)
+{
+ q = a / b;
+ r = a - b*q;
+ if (r < 0)
+ {
+ q -= 1;
+ r += b;
+ }
+}
+
+
+inline int
+GBitmap::read_run(unsigned char *&data)
+{
+ register int z=*data++;
+ return (z>=RUNOVERFLOWVALUE)?
+ ((z&~RUNOVERFLOWVALUE)<<8)|(*data++):z;
+}
+
+inline int
+GBitmap::read_run(const unsigned char *&data)
+{
+ register int z=*data++;
+ return (z>=RUNOVERFLOWVALUE)?
+ ((z&~RUNOVERFLOWVALUE)<<8)|(*data++):z;
+}
+
+inline void
+GBitmap::append_run(unsigned char *&data, int count)
+{
+ if (count < RUNOVERFLOWVALUE)
+ {
+ data[0] = count;
+ data += 1;
+ }
+ else if (count <= MAXRUNSIZE)
+ {
+ data[0] = (count>>8) + GBitmap::RUNOVERFLOWVALUE;
+ data[1] = (count & 0xff);
+ data += 2;
+ }
+ else
+ {
+ append_long_run(data, count);
+ }
+}
+
+
+inline void
+GBitmap::borrow_data(unsigned char &data,int w,int h)
+{
+ donate_data(&data,w,h);
+ bytes_data=0;
+}
+
+// ---------------- THE END
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/GContainer.cpp b/kviewshell/plugins/djvu/libdjvu/GContainer.cpp
new file mode 100644
index 00000000..2019439c
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GContainer.cpp
@@ -0,0 +1,802 @@
+//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: GContainer.cpp,v 1.12 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "GContainer.h"
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+// ------------------------------------------------------------
+// DYNAMIC ARRAYS
+// ------------------------------------------------------------
+
+
+GArrayBase::GArrayBase(const GArrayBase &ref)
+ : traits(ref.traits),
+ gdata(data,0,1),
+ minlo(ref.minlo), maxhi(ref.maxhi),
+ lobound(ref.lobound), hibound(ref.hibound)
+{
+ if (maxhi >= minlo)
+ gdata.resize(traits.size * (maxhi - minlo + 1),1);
+ if (hibound >= lobound)
+ traits.copy(traits.lea(data, lobound-minlo),
+ traits.lea(ref.data, lobound-minlo),
+ hibound - lobound + 1, 0);
+}
+
+
+GArrayBase::GArrayBase(const GCONT Traits &traits)
+ : traits(traits),
+ gdata(data,0,1),
+ minlo(0), maxhi(-1),
+ lobound(0), hibound(-1)
+{
+}
+
+
+GArrayBase::GArrayBase(const GCONT Traits &traits, int lobound, int hibound)
+ : traits(traits),
+ gdata(data,0,1),
+ minlo(0), maxhi(-1),
+ lobound(0), hibound(-1)
+{
+ resize(lobound, hibound);
+}
+
+
+GArrayBase::~GArrayBase()
+{
+ G_TRY { empty(); } G_CATCH_ALL { } G_ENDCATCH;
+}
+
+
+GArrayBase &
+GArrayBase::operator= (const GArrayBase &ga)
+{
+ if (this == &ga)
+ return *this;
+ empty();
+ if (ga.hibound >= ga.lobound)
+ {
+ resize(ga.lobound, ga.hibound);
+ traits.copy( traits.lea(data, lobound-minlo),
+ traits.lea(ga.data, ga.lobound-ga.minlo),
+ hibound - lobound + 1, 0 );
+ }
+ return *this;
+}
+
+
+void
+GArrayBase::steal(GArrayBase &ga)
+{
+ if (this != &ga)
+ {
+ empty();
+ lobound = ga.lobound;
+ hibound = ga.hibound;
+ minlo = ga.minlo;
+ maxhi = ga.maxhi;
+ data = ga.data;
+ ga.data = 0;
+ ga.lobound = ga.minlo = 0;
+ ga.hibound = ga.maxhi = -1;
+ }
+}
+
+
+void
+GArrayBase::empty()
+{
+ resize(0, -1);
+}
+
+
+void
+GArrayBase::touch(int n)
+{
+ int nlo = (n<lobound ? n : lobound);
+ int nhi = (n>hibound ? n : hibound);
+ if (hibound < lobound)
+ nlo = nhi = n;
+ resize(nlo, nhi);
+}
+
+
+void
+GArrayBase::resize(int lo, int hi)
+{
+ // Validation
+ int nsize = hi - lo + 1;
+ if (nsize < 0)
+ G_THROW( ERR_MSG("GContainer.bad_args") );
+ // Destruction
+ if (nsize == 0)
+ {
+ if (hibound >= lobound)
+ traits.fini( traits.lea(data, lobound-minlo), hibound-lobound+1 );
+ if (data)
+ gdata.resize(0,1);
+ lobound = minlo = 0;
+ hibound = maxhi = -1;
+ return;
+ }
+ // Simple extension
+ if (lo >= minlo && hi <= maxhi)
+ {
+ if (lobound > lo)
+ traits.init( traits.lea(data,lo-minlo), lobound-lo );
+ else if (lo > lobound)
+ traits.fini( traits.lea(data,lobound-minlo), lo-lobound );
+ if (hi > hibound)
+ traits.init( traits.lea(data,hibound-minlo+1), hi-hibound );
+ else if (hibound > hi)
+ traits.fini( traits.lea(data,hi-minlo+1), hibound-hi );
+ 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 and move
+ int beg = lo;
+ int end = hi;
+ int bytesize = traits.size * (nmaxhi-nminlo+1);
+ void *ndata;
+ GPBufferBase gndata(ndata,bytesize,1);
+#if GCONTAINER_ZERO_FILL
+ memset(ndata, 0, bytesize); // slower but cleaner
+#endif
+ if (lo < lobound)
+ { traits.init( traits.lea(ndata,lo-nminlo), lobound-lo ); beg=lobound; }
+ else if (lobound < lo)
+ { traits.fini( traits.lea(data,lobound-minlo), lo-lobound); }
+ if (hibound < hi)
+ { traits.init( traits.lea(ndata,hibound-nminlo+1), hi-hibound ); end=hibound; }
+ else if (hi < hibound)
+ { traits.fini( traits.lea(data, hi-minlo+1), hibound-hi ); }
+ if (end >= beg)
+ { traits.copy( traits.lea(ndata, beg-nminlo),
+ traits.lea(data, beg-minlo),
+ end-beg+1, 1 ); }
+ // free and replace
+ void *tmp=data;
+ data=ndata;
+ ndata=tmp;
+ minlo = nminlo;
+ maxhi = nmaxhi;
+ lobound = lo;
+ hibound = hi;
+}
+
+
+void
+GArrayBase::shift(int disp)
+{
+ lobound += disp;
+ hibound += disp;
+ minlo += disp;
+ maxhi += disp;
+}
+
+
+void
+GArrayBase::del(int n, int howmany)
+{
+ if (howmany < 0)
+ G_THROW( ERR_MSG("GContainer.bad_howmany") );
+ if (howmany == 0)
+ return;
+ if ( n < lobound || n+(int)howmany-1 > hibound)
+ G_THROW( ERR_MSG("GContainer.bad_sub2") );
+ traits.fini( traits.lea(data, n-minlo), howmany );
+ if ( n+howmany-1 < hibound)
+ traits.copy( traits.lea(data, n-minlo),
+ traits.lea(data, n-minlo+howmany),
+ hibound - (n+howmany-1), 1 );
+ hibound = hibound - howmany;
+}
+
+
+static inline void *
+nextptr(void *p, int elsize)
+{
+ return (void*)(((char*)p) + elsize);
+}
+
+
+static inline void *
+prevptr(void *p, int elsize)
+{
+ return (void*)(((char*)p) - elsize);
+}
+
+
+void
+GArrayBase::ins(int n, const void *src, int howmany)
+{
+ if (howmany < 0)
+ G_THROW( ERR_MSG("GContainer.bad_howmany") );
+ if (howmany == 0)
+ return;
+ // Make enough room
+ if (hibound+howmany > maxhi)
+ {
+ int nmaxhi = maxhi;
+ while (nmaxhi < hibound+howmany)
+ nmaxhi += (nmaxhi < 8 ? 8 : (nmaxhi > 32768 ? 32768 : nmaxhi));
+ int bytesize = traits.size * (nmaxhi-minlo+1);
+ void *ndata; // = operator new (bytesize);
+ GPBufferBase gndata(ndata,bytesize,1);
+ memset(ndata, 0, bytesize); // slower but cleaner
+ if (hibound >= lobound)
+ traits.copy( traits.lea(ndata, lobound-minlo),
+ traits.lea(data, lobound-minlo),
+ hibound-lobound+1, 1 );
+ maxhi = nmaxhi;
+ void *tmp=data;
+ data = ndata;
+ ndata=tmp;
+ }
+ // Shift data
+ int elsize = traits.size;
+ void *pdst = traits.lea(data, hibound+howmany-minlo);
+ void *psrc = traits.lea(data, hibound-minlo);
+ void *pend = traits.lea(data, n-minlo);
+ while ((char*)psrc >= (char*)pend)
+ {
+ traits.copy( pdst, psrc, 1, 1 );
+ pdst = prevptr(pdst, elsize);
+ psrc = prevptr(psrc, elsize);
+ }
+ hibound += howmany;
+ // Initialize new data
+ if (! src)
+ {
+ traits.init( traits.lea(data, n-minlo), howmany );
+ hibound += howmany;
+ return;
+ }
+ // Initialize new data with copy constructor
+ pdst = traits.lea(data, n-minlo);
+ pend = traits.lea(data, n+howmany-minlo);
+ while ((char*)pdst < (char*)pend)
+ {
+ traits.copy( pdst, src, 1, 0);
+ pdst = nextptr(pdst, elsize);
+ }
+}
+
+
+
+// ------------------------------------------------------------
+// GPOSITION
+// ------------------------------------------------------------
+
+
+
+void
+GPosition::throw_invalid(void *c) const
+{
+ if (c != cont)
+ G_THROW( ERR_MSG("GContainer.bad_pos_cont") );
+ else if (! ptr)
+ G_THROW( ERR_MSG("GContainer.bad_pos_null") );
+ else
+ G_THROW( ERR_MSG("GContainer.bad_pos") );
+}
+
+
+
+// ------------------------------------------------------------
+// DOUBLY LINKED LISTS
+// ------------------------------------------------------------
+
+
+GListBase::GListBase(const Traits& traits)
+ : traits(traits)
+{
+ nelem = 0;
+ head.next = head.prev = 0;
+}
+
+
+GListBase::GListBase(const GListBase &ref)
+ : traits(ref.traits)
+{
+ nelem = 0;
+ head.next = head.prev = 0;
+ GListBase::operator= (ref);
+}
+
+#include <stdio.h>
+GListBase::~GListBase()
+{
+ G_TRY
+ {
+ empty();
+ }
+ G_CATCH_ALL
+ {
+ }
+ G_ENDCATCH;
+}
+
+
+void
+GListBase::append(Node *n)
+{
+ // Link
+ n->next = 0;
+ n->prev = head.prev;
+ head.prev = n;
+ if (n->prev)
+ n->prev->next = n;
+ else
+ head.next = n;
+ // Finish
+ nelem += 1;
+}
+
+
+void
+GListBase::prepend(Node *n)
+{
+ // Link
+ n->next = head.next;
+ n->prev = 0;
+ head.next = n;
+ if (n->next)
+ n->next->prev = n;
+ else
+ head.prev = n;
+ // Finish
+ nelem += 1;
+}
+
+
+void
+GListBase::insert_after(GPosition pos, Node *n)
+{
+ // Prepare
+ if (pos.ptr)
+ {
+ if (pos.cont != (void*)this)
+ pos.throw_invalid((void*)this);
+ Node *p = pos.ptr;
+ n->prev = p;
+ n->next = p->next;
+ }
+ else
+ {
+ n->prev = 0;
+ n->next = head.next;
+ }
+ // Link
+ if (n->prev)
+ n->prev->next = n;
+ else
+ head.next = n;
+ if (n->next)
+ n->next->prev = n;
+ else
+ head.prev = n;
+ // Finish
+ nelem += 1;
+}
+
+
+void
+GListBase::insert_before(GPosition pos, Node *n)
+{
+ // Prepare
+ if (pos.ptr)
+ {
+ if (pos.cont != (void*)this)
+ pos.throw_invalid((void*)this);
+ Node *p = pos.ptr;
+ n->prev = p->prev;
+ n->next = p;
+ }
+ else
+ {
+ n->prev = head.prev;
+ n->next = 0;
+ }
+ // Link
+ if (n->prev)
+ n->prev->next = n;
+ else
+ head.next = n;
+ if (n->next)
+ n->next->prev = n;
+ else
+ head.prev = n;
+ // Finish
+ nelem += 1;
+}
+
+
+void
+GListBase::insert_before(GPosition pos, GListBase &fromlist, GPosition &frompos)
+{
+ // Check
+ if (!frompos.ptr || frompos.cont != (void*)&fromlist)
+ frompos.throw_invalid((void*)&fromlist);
+ if (pos.ptr && pos.cont != (void*)this)
+ pos.throw_invalid((void*)this);
+ // Update frompos
+ Node *n = frompos.ptr;
+ frompos.ptr = n->next;
+ if (pos.ptr == n) return;
+ // Unlink
+ if (n->next)
+ n->next->prev = n->prev;
+ else
+ fromlist.head.prev = n->prev;
+ if (n->prev)
+ n->prev->next = n->next;
+ else
+ fromlist.head.next = n->next;
+ fromlist.nelem -= 1;
+ // Prepare insertion
+ if (pos.ptr)
+ {
+ Node *p = pos.ptr;
+ n->prev = p->prev;
+ n->next = p;
+ }
+ else
+ {
+ n->prev = head.prev;
+ n->next = 0;
+ }
+ // Link
+ if (n->prev)
+ n->prev->next = n;
+ else
+ head.next = n;
+ if (n->next)
+ n->next->prev = n;
+ else
+ head.prev = n;
+ nelem += 1;
+}
+
+
+void
+GListBase::del(GPosition &pos)
+{
+ // Check
+ if (!pos.ptr || pos.cont != (void*)this) return;
+ // Unlink
+ Node *n = pos.ptr;
+ if (n->next)
+ n->next->prev = n->prev;
+ else
+ head.prev = n->prev;
+ if (n->prev)
+ n->prev->next = n->next;
+ else
+ head.next = n->next;
+ // Finish
+ nelem -= 1;
+ traits.fini( (void*)n, 1);
+ operator delete ( (void*)n );
+ pos.ptr = 0;
+}
+
+
+GPosition
+GListBase::nth(unsigned int n) const
+{
+ Node *p = 0;
+ if ((int)n < nelem)
+ for (p=head.next; p; p=p->next)
+ if ( n-- == 0)
+ break;
+ return GPosition(p, (void*)this);
+}
+
+
+void
+GListBase::empty()
+{
+ Node *n=head.next;
+ while (n)
+ {
+ Node *p = n->next;
+ traits.fini( (void*)n, 1 );
+ operator delete ( (void*)n );
+ n = p;
+ }
+ head.next = head.prev = 0;
+ nelem = 0;
+}
+
+
+GListBase &
+GListBase::operator= (const GListBase & ref)
+{
+ if (this == &ref)
+ return *this;
+ empty();
+ for(Node *n = ref.head.next; n; n=n->next)
+ {
+ Node *m = (Node*) operator new (traits.size);
+ traits.copy( (void*)m, (void*)n, 1, 0);
+ append(m);
+ }
+ return *this;
+}
+
+
+
+
+
+// ------------------------------------------------------------
+// ASSOCIATIVE MAPS
+// ------------------------------------------------------------
+
+
+
+
+GSetBase::GSetBase(const Traits &traits)
+ : traits(traits), nelems(0), nbuckets(0),
+ gtable(table), first(0)
+{
+ rehash(17);
+}
+
+
+GSetBase::GSetBase(const GSetBase &ref)
+ : traits(ref.traits),
+ nelems(0), nbuckets(0), gtable(table), first(0)
+{
+ GSetBase::operator= (ref);
+}
+
+
+GSetBase::~GSetBase()
+{
+ G_TRY { empty(); } G_CATCH_ALL { } G_ENDCATCH;
+// delete [] table;
+}
+
+
+GCONT HNode *
+GSetBase::hashnode(unsigned int hashcode) const
+{
+ int bucket = hashcode % nbuckets;
+ return table[bucket];
+}
+
+GCONT HNode *
+GSetBase::installnode(HNode *n)
+{
+ // Rehash if table is more than 60% full
+ if (nelems*3 > nbuckets*2)
+ rehash( 2*nbuckets - 1 );
+ // Create and insert
+ insertnode(n);
+ return n;
+}
+
+void
+GSetBase::insertnode(HNode *n)
+{
+ int bucket = n->hashcode % nbuckets;
+ n->prev = n->hprev = table[bucket];
+ if (n->prev)
+ {
+ // bucket was not empty
+ n->next = n->prev->next;
+ n->prev->next = n;
+ if (n->next)
+ n->next->prev = n;
+ }
+ else
+ {
+ // bucket was empty.
+ n->next = first;
+ first = n;
+ if (n->next)
+ n->next->prev = n;
+ }
+ // finish
+ table[bucket] = n;
+ nelems += 1;
+}
+
+
+void
+GSetBase::deletenode(GCONT HNode *n)
+{
+ if (n == 0)
+ return;
+ int bucket = n->hashcode % nbuckets;
+ // Regular links
+ if (n->next)
+ n->next->prev = n->prev;
+ if (n->prev)
+ n->prev->next = n->next;
+ else
+ first = (HNode*)(n->next);
+ // HPrev links
+ if (table[bucket] == n)
+ table[bucket] = n->hprev;
+ else
+ ((HNode*)(n->next))->hprev = n->hprev;
+ // Delete entry
+ traits.fini( (void*)n, 1 );
+ operator delete ( (void*)n );
+ nelems -= 1;
+}
+
+
+void
+GSetBase::rehash(int newbuckets)
+{
+ // Save chain of nodes
+ Node *n = first;
+ // Simulate an empty map
+ nelems = 0;
+ first = 0;
+ // Allocate a new empty bucket table
+// delete [] table;
+ gtable.resize(0);
+ nbuckets = newbuckets;
+ typedef HNode *HNodePtr;
+// table = new HNodePtr[nbuckets];
+ gtable.resize(nbuckets);
+ gtable.clear();
+// for (int i=0; i<nbuckets; i++)
+// table[i] = 0;
+ // Insert saved nodes
+ while (n)
+ {
+ Node *p = n->next;
+ insertnode((HNode*)n);
+ n = p;
+ }
+}
+
+
+GSetBase&
+GSetBase::operator=(const GSetBase &ref)
+{
+ if (this == &ref)
+ return *this;
+ empty();
+ rehash(ref.nbuckets);
+ for (Node *n = ref.first; n; n=n->next)
+ {
+ HNode *m = (HNode*) operator new (traits.size);
+ traits.copy( (void*)m, (void*)n, 1, 0);
+ insertnode(m);
+ }
+ return *this;
+}
+
+
+GPosition
+GSetBase::firstpos() const
+{
+ return GPosition(first, (void*)this);
+}
+
+
+void
+GSetBase::del(GPosition &pos)
+{
+ if (pos.ptr && pos.cont==(void*)this)
+ {
+ deletenode((HNode*)pos.ptr);
+ pos.ptr = 0;
+ }
+}
+
+void
+GSetBase::empty()
+{
+ HNode *n = first;
+ while (n)
+ {
+ HNode *p = (HNode*)(n->next);
+ traits.fini( (void*)n, 1 );
+ operator delete ( (void*)n );
+ n = p;
+ }
+ first = 0;
+ nelems = 0;
+ gtable.clear();
+// for (int i=0; i<nbuckets; i++)
+// table[i] = 0;
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+
diff --git a/kviewshell/plugins/djvu/libdjvu/GContainer.h b/kviewshell/plugins/djvu/libdjvu/GContainer.h
new file mode 100644
index 00000000..d21838dc
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GContainer.h
@@ -0,0 +1,1366 @@
+//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: GContainer.h,v 1.15 2004/05/13 15:16:34 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _GCONTAINER_H_
+#define _GCONTAINER_H_
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+#include "GException.h"
+#include "GSmartPointer.h"
+#include <string.h>
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+// Supports old iterators (first/last/next/prev) on lists and maps?
+#ifndef GCONTAINER_OLD_ITERATORS
+#define GCONTAINER_OLD_ITERATORS 1
+#endif
+
+// Check array bounds at runtime ?
+#ifndef GCONTAINER_BOUNDS_CHECK
+#define GCONTAINER_BOUNDS_CHECK 1
+#endif
+
+// Clears allocated memory prior to running constructors ?
+#ifndef GCONTAINER_ZERO_FILL
+#define GCONTAINER_ZERO_FILL 1
+#endif
+
+// Avoid member templates (needed by old compilers)
+#ifndef GCONTAINER_NO_MEMBER_TEMPLATES
+#if defined(__GNUC__) && (__GNUC__==2) && (__GNUC_MINOR__<91)
+#define GCONTAINER_NO_MEMBER_TEMPLATES 1
+#elif defined(_MSC_VER) && !defined(__ICL)
+#define GCONTAINER_NO_MEMBER_TEMPLATES 1
+#elif defined(__MWERKS__)
+#define GCONTAINER_NO_MEMBER_TEMPLATES 1
+#else
+#define GCONTAINER_NO_MEMBER_TEMPLATES 0
+#endif
+#endif
+
+// Define typename when needed
+#ifndef GCONTAINER_NO_TYPENAME
+#define GCONTAINER_NO_TYPENAME 0
+#endif
+#if GCONTAINER_NO_TYPENAME
+#define typename /**/
+#endif
+
+
+/** @name GContainer.h
+
+ Files #"GContainer.h"# and #"GContainer.cpp"# implement three main
+ template class for generic containers.
+ Class #GArray# (see \Ref{Dynamic Arrays}) implements an array of objects
+ with variable bounds. Class #GList# (see \Ref{Doubly Linked Lists})
+ implements a doubly linked list of objects. Class #GMap# (see
+ \Ref{Associative Maps}) implements a hashed associative map. The
+ container templates are not thread-safe. Thread safety can be implemented
+ using the facilities provided in \Ref{GThreads.h}.
+
+ @memo
+ Template class for generic containers.
+ @author
+ L\'eon Bottou <leonb@research.att.com> -- initial implementation.\\
+ Andrei Erofeev <eaf@geocities.com> -- bug fixes.
+ @version
+ #$Id: GContainer.h,v 1.15 2004/05/13 15:16:34 leonb Exp $# */
+//@{
+
+
+
+// ------------------------------------------------------------
+// HELPER CLASSES
+// ------------------------------------------------------------
+
+
+
+/* Namespace for containers support classes. This class is used as a
+ namespace for global identifiers related to the implementation of
+ containers. It is inherited by all container objects. This is disabled by
+ defining compilation symbol #GCONTAINER_NO_MEMBER_TEMPATES# to 1. */
+
+
+#ifdef _MSC_VER
+// Language lawyer say MS is wrong on that one.
+// Cf section 5.4.7 in november 1997 draft.
+#pragma warning( disable : 4243 )
+#endif
+
+
+// GPEnabled inhertenced removed again so the code works on more machines.
+class GCont
+#if GCONTAINER_NO_MEMBER_TEMPLATES
+{
+};
+#else
+{
+public:
+#endif
+ // --- Pointers to type management functions
+ struct Traits
+ {
+ int size;
+ void *(*lea) (void *base, int n);
+ void (*init) (void *dst, int n);
+ void (*copy) (void *dst, const void* src, int n, int zap);
+ void (*fini) (void *dst, int n);
+ };
+#if !GCONTAINER_NO_MEMBER_TEMPLATES
+protected:
+#endif
+ // --- Management of simple types
+ template <int SZ> class TrivTraits
+ {
+ public:
+ // The unique object
+ static const Traits & traits();
+ // Offset in an array of T
+ static void * lea(void* base, int n)
+ { return (void*)( ((char*)base) + SZ*n ); }
+ // Trivial default constructor
+ static void init(void* dst, int n) {}
+ // Trivial copy constructor
+ static void copy(void* dst, const void* src, int n, int )
+ { memcpy(dst, src, SZ*n); }
+ // Trivial destructor
+ static void fini(void* dst, int n) {}
+ };
+ // --- Management of regular types
+ template <class T> class NormTraits
+ {
+ public:
+ // The unique object
+ static const Traits & traits();
+ // Offset in an array of T
+ static void * lea(void* base, int n)
+ { return (void*)( ((T*)base) + n ); }
+ // Template based default constructor
+ static void init(void* dst, int n)
+ { T* d = (T*)dst; while (--n>=0) { new ((void*)d) T; d++; } }
+ // Template based copy constructor
+ static void copy(void* dst, const void* src, int n, int zap)
+ { T* d = (T*)dst; const T *s = (const T*)src;
+ while (--n>=0) { new ((void*)d) T(*s); if (zap) { s->T::~T(); }; d++; s++; } }
+ // Template based destructor
+ static void fini(void* dst, int n)
+ { T* d = (T*)dst; while (--n>=0) { d->T::~T(); d++; } }
+ };
+ // --- Base class for list nodes
+ struct Node
+ {
+ Node *next;
+ Node *prev;
+ };
+ // -- Class for list nodes
+ template <class T> struct ListNode : public Node
+ {
+ T val;
+ };
+ // -- Class for map nodes showing the hash
+ struct HNode : public Node
+ {
+ HNode *hprev;
+ unsigned int hashcode;
+ };
+ // -- Class for map nodes showing the hash and the key
+ template <class K> struct SetNode : public HNode
+ {
+ K key;
+ };
+ // -- Class for map nodes with everything
+ template <class K, class T> struct MapNode : public SetNode<K>
+ {
+ T val;
+ };
+#if !GCONTAINER_NO_MEMBER_TEMPLATES
+};
+#endif
+
+
+#if !GCONTAINER_NO_MEMBER_TEMPLATES
+#define GCONT GCont::
+#else
+#define GCONT
+#endif
+
+template <int SZ> const GCONT Traits &
+GCONT TrivTraits<SZ>::traits()
+{
+ static const Traits theTraits = {
+ SZ,
+ TrivTraits<SZ>::lea,
+ TrivTraits<SZ>::init,
+ TrivTraits<SZ>::copy,
+ TrivTraits<SZ>::fini
+ };
+ return theTraits;
+}
+
+template <class T> const GCONT Traits &
+GCONT NormTraits<T>::traits()
+{
+ static const Traits theTraits = {
+ sizeof(T),
+ NormTraits<T>::lea,
+ NormTraits<T>::init,
+ NormTraits<T>::copy,
+ NormTraits<T>::fini
+ };
+ return theTraits;
+}
+
+
+// ------------------------------------------------------------
+// DYNAMIC ARRAYS
+// ------------------------------------------------------------
+
+
+/** @name Dynamic Arrays
+
+ These class implement arrays of objects of any 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.
+
+ Class \Ref{GArrayTemplate} implements all methods for manipulating arrays
+ of type #TYPE#. You should not however create instances of this class.
+ You should instead use one of the following classes:
+ \begin{itemize}
+ \item Class \Ref{GArray<TYPE>} is the most general class,
+ \item Class \Ref{GTArray<TYPE>} is more efficient, but only works for
+ types that do not require sophisticated constructors or destructors,
+ such as the plain old C types (e.g. #int# or #char# ...).
+ \item Class \Ref{GPArray<TYPE>} implements an array of smart-pointers
+ \Ref{GP<TYPE>} to objects of type #TYPE#. Using this class
+ reduces the size of the code generated by the template instanciation.
+ \end{itemize}
+
+ Another variant of dynamic arrays is implemented in file \Ref{Arrays.h}.
+ The main difference is that class \Ref{TArray}, \Ref{DArray} and
+ \Ref{DPArray} implement a copy-on-demand scheme.
+
+ @memo Dynamic arrays. */
+//@{
+
+class GArrayBase : public GCont
+{
+public:
+ // -- CONSTRUCTORS
+ GArrayBase(const GArrayBase &ref);
+ GArrayBase(const Traits &traits);
+ GArrayBase(const Traits &traits, int lobound, int hibound);
+ // -- DESTRUCTOR
+ ~GArrayBase();
+ // -- ASSIGNMENT
+ GArrayBase& operator= (const GArrayBase &ga);
+ // -- ALTERATION
+ void empty();
+ void touch(int n);
+ void resize(int lobound, int hibound);
+ void shift(int disp);
+ void del(int n, int howmany=1);
+ void ins(int n, const void *src, int howmany=1);
+ void steal(GArrayBase &ga);
+protected:
+ const Traits &traits;
+ void *data;
+ GPBufferBase gdata;
+ int minlo;
+ int maxhi;
+ int lobound;
+ int hibound;
+};
+
+
+/** Common base class for all dynamic arrays.
+ Class \Ref{GArrayTemplate} implements all methods for manipulating arrays
+ of type #TYPE#. You should not however create instances of this class.
+ You should instead use class \Ref{GArray}, \Ref{GTArray} or
+ \Ref{GPArray}. */
+
+template<class TYPE>
+class GArrayTemplate : protected GArrayBase
+{
+public:
+ // -- CONSTRUCTORS
+ GArrayTemplate(const Traits &traits) : GArrayBase(traits) {}
+ GArrayTemplate(const Traits &traits, int lobound, int hibound)
+ : GArrayBase(traits, lobound, hibound) {}
+ // -- ACCESS
+ /** Returns the number of elements in the array. */
+ int size() const
+ { return hibound-lobound+1; }
+ /** Returns the lower bound of the valid subscript range. */
+ int lbound() const
+ { return lobound; }
+ /** Returns the upper bound of the valid subscript range. */
+ int hbound() const
+ { return hibound; }
+ /** 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. */
+ inline TYPE& operator[](int const 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 GArray<TYPE>#. */
+ inline const TYPE& operator[](int n) const;
+ // -- CONVERSION
+ /** 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* ()
+ { return ((TYPE*)data)-minlo; }
+ /** 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
+ { return ((const TYPE*)data)-minlo; }
+ operator const TYPE* () // suppress warning with gcc-2.95
+ { return ((const TYPE*)data)-minlo; }
+ // -- ALTERATION
+ /** Erases the array contents. All elements in the array are destroyed.
+ The valid subscript range is set to the empty range. */
+ void empty()
+ { GArrayBase::empty(); }
+ /** Extends the subscript range so that it 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;
+ GArray<GString> a;
+ while (! end_of_file()) {
+ a.touch(lineno);
+ a[lineno++] = read_a_line();
+ }
+ \end{verbatim} */
+ void touch(int n)
+ { if (n<lobound || n>hibound) GArrayBase::touch(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. */
+ void resize(int hibound)
+ { GArrayBase::resize(0, 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. */
+ void resize(int lobound, int hibound)
+ { GArrayBase::resize(lobound, 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)
+ { GArrayBase::shift(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. */
+ void del(int n, int howmany=1)
+ { GArrayBase::del(n, howmany); }
+ /** Insert new elements into an array. This function inserts
+ #howmany# elements at position #n# into the array. These
+ elements are constructed using the default constructor for type
+ #TYPE#. 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. */
+ void ins(int n, int howmany=1)
+ { GArrayBase::ins(n, 0, howmany); }
+ /** Insert new elements into an array. The new elements are
+ constructed by copying element #val# using the copy constructor
+ for type #TYPE#. See \Ref{ins(int n, unsigned int howmany=1)}. */
+ void ins(int n, const TYPE &val, int howmany=1)
+ { GArrayBase::ins(n, (const void*)&val, howmany); }
+ /** Steals contents from array #ga#. After this call, array #ga# is empty,
+ and this array contains everything previously contained in #ga#. */
+ void steal(GArrayTemplate &ga)
+ { GArrayBase::steal(ga); }
+ // -- SORTING
+ /** Sort array elements. Sort all array elements in ascending
+ order according to the less-or-equal comparison
+ operator for type #TYPE#. */
+ void sort()
+ { sort(lbound(), hbound()); }
+ /** Sort array elements in subscript range #lo# to #hi#. Sort all array
+ elements whose subscripts are in range #lo# to #hi# in ascending order
+ according to the less-or-equal comparison operator for type #TYPE#. 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. */
+ void sort(int lo, int hi);
+};
+
+
+
+/* That one must be implemented as a regular template function. */
+template <class TYPE> void
+GArrayTemplate<TYPE>::sort(int lo, int hi)
+{
+ if (hi <= lo)
+ return;
+ if (hi > hibound || lo<lobound)
+ G_THROW( ERR_MSG("GContainer.illegal_subscript") );
+ TYPE *data = (TYPE*)(*this);
+ // Test for insertion sort
+ if (hi <= lo + 50)
+ {
+ for (int i=lo+1; i<=hi; i++)
+ {
+ int j = i;
+ TYPE tmp = data[i];
+ while ((--j>=lo) && !(data[j]<=tmp))
+ data[j+1] = data[j];
+ data[j+1] = tmp;
+ }
+ return;
+ }
+ // -- determine suitable quick-sort pivot
+ TYPE tmp = data[lo];
+ TYPE pivot = data[(lo+hi)/2];
+ if (pivot <= tmp)
+ { tmp = pivot; pivot=data[lo]; }
+ if (data[hi] <= tmp)
+ { pivot = tmp; }
+ else if (data[hi] <= pivot)
+ { pivot = data[hi]; }
+ // -- partition set
+ int h = hi;
+ int l = lo;
+ while (l < h)
+ {
+ while (! (pivot <= data[l])) l++;
+ while (! (data[h] <= pivot)) h--;
+ if (l < h)
+ {
+ tmp = data[l];
+ data[l] = data[h];
+ data[h] = tmp;
+ l = l+1;
+ h = h-1;
+ }
+ }
+ // -- recursively restart
+ sort(lo, h);
+ sort(l, hi);
+}
+
+template<class TYPE> inline TYPE&
+GArrayTemplate<TYPE>::operator[](int const n)
+{
+#if GCONTAINER_BOUNDS_CHECK
+ if (n<lobound || n>hibound)
+ {
+ G_THROW( ERR_MSG("GContainer.illegal_subscript") );
+ }
+#endif
+ return ((TYPE*)data)[n-minlo];
+}
+
+
+template<class TYPE> inline const TYPE &
+GArrayTemplate<TYPE>::operator[](int const n) const
+{
+#if GCONTAINER_BOUNDS_CHECK
+ if (n<lobound || n>hibound)
+ {
+ G_THROW( ERR_MSG("GContainer.illegal_subscript") );
+ }
+#endif
+ return ((const TYPE*)data)[n-minlo];
+}
+
+
+
+/** Dynamic array for general types.
+ Template class #GArray<TYPE># implements an array of elements of type
+ #TYPE#. This template class must be able to access the following
+ functions.
+ \begin{itemize}
+ \item a default constructor #TYPE::TYPE()#,
+ \item a copy constructor #TYPE::TYPE(const TYPE &)#,
+ \item and optionally a destructor #TYPE::~TYPE()#.
+ \end{itemize}
+ This class only implement constructors. See class \Ref{GArrayTemplate}
+ for a description of all access methods. */
+
+template<class TYPE>
+class GArray : public GArrayTemplate<TYPE>
+{
+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. */
+ GArray()
+ : GArrayTemplate<TYPE>(GCONT NormTraits<TYPE>::traits() ) {}
+ /** Constructs an array with subscripts in range 0 to #hibound#.
+ The subscript range can be subsequently modified with member functions
+ #touch# and #resize#. */
+ GArray(int hi)
+ : GArrayTemplate<TYPE>(GCONT NormTraits<TYPE>::traits(), 0, hi ) {}
+ /** Constructs an array with subscripts in range #lobound# to #hibound#.
+ The subscript range can be subsequently modified with member functions
+ #touch# and #resize#. */
+ GArray(int lo, int hi)
+ : GArrayTemplate<TYPE>(GCONT NormTraits<TYPE>::traits(), lo, hi ) {}
+ // Copy operator
+ GArray& operator=(const GArray &r)
+ { GArrayBase::operator=(r); return *this; }
+};
+
+
+/** Dynamic array for smart pointers.
+ Template class #GPArray<TYPE># implements an array of elements of type
+ #GP<TYPE># (see \Ref{GSmartPointer.h}). Significantly smaller code sizes
+ can be achieved by using this class instead of the more general
+ #GArray<GP<TYPE>>#.
+ This class only implement constructors. See class \Ref{GArrayTemplate}
+ for a description of all access methods. */
+
+template<class TYPE>
+class GPArray : public GArrayTemplate<GP<TYPE> >
+{
+public:
+ GPArray()
+ : GArrayTemplate<GP<TYPE> >(GCONT NormTraits<GPBase>::traits() ) {}
+ GPArray(int hi)
+ : GArrayTemplate<GP<TYPE> >(GCONT NormTraits<GPBase>::traits(), 0, hi ) {}
+ GPArray(int lo, int hi)
+ : GArrayTemplate<GP<TYPE> >(GCONT NormTraits<GPBase>::traits(), lo, hi ) {}
+ // Copy operator
+ GPArray& operator=(const GPArray &r)
+ { GArrayBase::operator=(r); return *this; }
+};
+
+/** Dynamic array for simple types.
+ Template class #GTArray<TYPE># implements an array of elements of {\em
+ simple} type #TYPE#. {\em Simple} means that objects of type #TYPE# can
+ be created, copied, moved or destroyed without using specific constructors
+ or destructor functions. Class #GTArray<TYPE># will move or copy objects
+ using simple bitwise copies. Otherwise you must use class #GArray<TYPE>#.
+ This class only implement constructors. See class \Ref{GArrayTemplate}
+ for a description of all access methods. */
+template<class TYPE>
+class GTArray : public GArrayTemplate<TYPE>
+{
+public:
+ GTArray()
+ : GArrayTemplate<TYPE>(GCONT TrivTraits<sizeof(TYPE)>::traits() ) {}
+ GTArray(int hi)
+ : GArrayTemplate<TYPE>(GCONT TrivTraits<sizeof(TYPE)>::traits(), 0, hi ) {}
+ GTArray(int lo, int hi)
+ : GArrayTemplate<TYPE>(GCONT TrivTraits<sizeof(TYPE)>::traits(), lo, hi ) {}
+ // Copy operator
+ GTArray& operator=(const GTArray &r)
+ { GArrayBase::operator=(r); return *this; }
+};
+
+
+//@}
+
+
+
+// ------------------------------------------------------------
+// DOUBLY LINKED LISTS
+// ------------------------------------------------------------
+
+
+/** @name Doubly Linked Lists
+
+ The template classes \Ref{GList} and \Ref{GPList} implement a doubly
+ linked list of objects of arbitrary types. Member functions are provided
+ to search the list for an element, to insert or delete elements at
+ specified positions. Theses template class must be able to access
+ \begin{itemize}
+ \item a default constructor #TYPE::TYPE()#,
+ \item a copy constructor #TYPE::TYPE(const TYPE &)#,
+ \item optionally a destructor #TYPE::~TYPE()#,
+ \item and optionally a comparison operator #TYPE::operator==(const TYPE &)#.
+ \end{itemize}
+ @memo Doubly linked lists.
+*/
+//@{
+
+/** Generic iterator class.
+ This class represents a position in a list (see \Ref{GList}) or a map
+ (see \Ref{GMap}). As demonstrated by the following examples,
+ this class should be used to iterate over the objects contained
+ in a list or a map:
+ \begin{verbatim}
+ void print_list(GList<GString> a)
+ {
+ for (GPosition i = a ; i; ++i)
+ DjVuPrintMessage("%s\n", (const char*) a[i] );
+ }
+
+ void print_list_backwards(GList<GString> a)
+ {
+ for (GPosition i = a.lastpos() ; i; --i)
+ DjVuPrintMessage("%s\n", (const char*) a[i] );
+ }
+ \end{verbatim}
+ GPosition objects should only be used with the list or map for which they
+ have been created (using the member functions #firstpos# or #lastpos# of
+ the container). Furthermore, you should never use a GPosition object
+ which designates a list element which has been removed from the list
+ (using member function #del# or by other means.)
+*/
+
+class GPosition : protected GCont
+{
+public:
+ /** Creates a null GPosition object. */
+ GPosition() : ptr(0), cont(0) {}
+ /** Creates a copy of a GPosition object. */
+ GPosition(const GPosition &ref) : ptr(ref.ptr), cont(ref.cont) {}
+ /** Tests whether this GPosition object is non null. */
+ operator int() const
+ { return !!ptr; }
+ /** Tests whether this GPosition object is null. */
+ int operator !() const
+ { return !ptr; }
+ /** Moves this GPosition object to the next object in the container. */
+ GPosition& operator ++()
+ { if (ptr) ptr = ptr->next; return *this; }
+ /** Moves this GPosition object to the previous object in the container. */
+ GPosition& operator --()
+ { if (ptr) ptr = ptr->prev; return *this; }
+ // Internal. Do not use.
+ GPosition(Node *p, void *c) : ptr(p), cont(c) {}
+#if GCONTAINER_BOUNDS_CHECK
+ Node *check(void *c)
+ { if (!ptr || c!=cont) throw_invalid(c); return ptr; }
+ const Node *check(void *c) const
+ { if (!ptr || c!=cont) throw_invalid(c); return ptr; }
+#else
+ Node *check(void *c)
+ { return ptr; }
+ const Node *check(void *c) const
+ { return ptr; }
+#endif
+protected:
+ Node *ptr;
+ void *cont;
+ friend class GListBase;
+ friend class GSetBase;
+ void throw_invalid(void *c) const no_return;
+};
+
+
+class GListBase : public GCont
+{
+protected:
+ GListBase(const Traits& traits);
+ GListBase(const GListBase &ref);
+ void append(Node *n);
+ void prepend(Node *n);
+ void insert_after(GPosition pos, Node *n);
+ void insert_before(GPosition pos, Node *n);
+ void insert_before(GPosition pos, GListBase &fromlist, GPosition &frompos);
+ void del(GPosition &pos);
+protected:
+ const Traits &traits;
+ int nelem;
+ Node head;
+public:
+ ~GListBase();
+ GListBase & operator= (const GListBase & gl);
+ GPosition firstpos() const { return GPosition(head.next, (void*)this); }
+ GPosition lastpos() const { return GPosition(head.prev, (void*)this); }
+ int isempty() const { return nelem==0; };
+ GPosition nth(unsigned int n) const;
+ void empty();
+};
+
+
+template<class TI>
+class GListImpl : public GListBase
+{
+protected:
+ GListImpl();
+ typedef GCONT ListNode<TI> LNode;
+ static Node * newnode(const TI &elt);
+ int operator==(const GListImpl<TI> &l2) const;
+ int search(const TI &elt, GPosition &pos) const;
+};
+
+template<class TI>
+GListImpl<TI>::GListImpl()
+ : GListBase( GCONT NormTraits<LNode>::traits() )
+{
+}
+
+template<class TI> GCONT Node *
+GListImpl<TI>::newnode(const TI &elt)
+{
+ LNode *n = (LNode *) operator new (sizeof(LNode ));
+#if GCONTAINER_ZERO_FILL
+ memset(n, 0, sizeof(LNode ));
+#endif
+ new ((void*)&(n->val)) TI(elt);
+ return (Node*) n;
+}
+
+template<class TI> int
+GListImpl<TI>::operator==(const GListImpl<TI> &l2) const
+{
+ Node *p, *q;
+ for (p=head.next, q=l2.head.next; p && q; p=p->next, q=q->next )
+ if (((LNode*)p)->val != ((LNode*)q)->val)
+ return 0;
+ return p==0 && q==0;
+}
+
+template<class TI> int
+GListImpl<TI>::search(const TI &elt, GPosition &pos) const
+{
+ Node *n = (pos ? pos.check((void*)this) : head.next);
+ for (; n; n=n->next)
+ if ( ((LNode *)n)->val == elt )
+ break;
+ if (n) pos = GPosition(n, (void*)this);
+ return (n != 0);
+}
+
+
+/** Common base class for all doubly linked lists.
+ Class \Ref{GListTemplate} implements all methods for manipulating lists
+ of of objects of type #TYPE#. You should not however create instances of
+ this class. You should instead use class \Ref{GList} or \Ref{GPList}. */
+
+template <class TYPE, class TI>
+class GListTemplate : protected GListImpl<TI>
+{
+public:
+ // -- ACCESS
+ /** Returns the number of elements in the list. */
+ int size() const
+ { return this->nelem; }
+ /** Returns the first position in the list. See \Ref{GPosition}. */
+ GPosition firstpos() const
+ { return GListImpl<TI>::firstpos(); }
+ /** Returns the last position in the list. See \Ref{GPosition}. */
+ GPosition lastpos() const
+ { return GListImpl<TI>::lastpos(); }
+ /** Implicit notation for GList::firstpos(). */
+ operator GPosition() const
+ { return firstpos(); }
+ /** Returns a reference to the list element at position #pos#. This
+ reference can be used for both reading (as "#a[n]#") and modifying (as
+ "#a[n]=v#") a list element. Using an invalid position will cause a
+ segmentation violation. See \Ref{GPosition} for efficient operations on
+ positions. */
+ TYPE& operator[](GPosition pos)
+ { return (TYPE&) (((typename GListImpl<TI>::LNode *)pos.check((void*)this))->val); }
+ /** Returns a constant reference to the list element at position #pos#.
+ This reference only be used for reading a list element. An exception
+ \Ref{GException} is thrown if #pos# is not a valid position. This
+ variant of #operator[]# is necessary when dealing with a #const
+ GList<TYPE>#. See \Ref{GPosition} for efficient operations on
+ positions. */
+ const TYPE& operator[](GPosition pos) const
+ { return (const TYPE&) (((const typename GListImpl<TI>::LNode *)pos.check((void*)this))->val); }
+ // -- TEST
+ /** Tests whether a list is empty.
+ Returns a non zero value if the list contains no elements. */
+ int isempty() const
+ { return this->nelem==0; }
+ /** Compares two lists. Returns a non zero value if and only if both lists
+ contain the same elements (as tested by #TYPE::operator==(const TYPE&)#
+ in the same order. */
+ int operator==(const GListTemplate<TYPE,TI> &l2) const
+ { return GListImpl<TI>::operator==(l2); }
+ // -- SEARCHING
+ /** Returns the position #pos# of the #n#-th list element. An invalid
+ position is returned if the list contains less than #n# elements. The
+ operation works by sequentially scanning the list until reaching the
+ #n#-th element. */
+ GPosition nth(unsigned int n) const
+ { return GListImpl<TI>::nth(n); }
+ /* Compatibility */
+ int nth(unsigned int n, GPosition &pos) const
+ { GPosition npos=nth(n); if (npos) pos=npos; return !!pos; }
+ /** Tests whether the list contains a given element. If the list contains
+ #elt#, the position of the the first list element equal to #elt# as
+ checked by #TYPE::operator==(const TYPE&)# is returned. Otherwise an
+ invalid position is returned. */
+ GPosition contains(const TYPE &elt) const
+ { GPosition pos; GListImpl<TI>::search((const TI&)elt, pos); return pos; }
+ /** Searches the list for a given element. If position #pos# is a valid
+ position for this list, the search starts at the specified position. If
+ position #pos# is not a valid position, the search starts at the
+ beginning of the list. The list elements are sequentially compared with
+ #elt# using #TYPE::operator==(const TYPE&)#. As soon as a list element
+ is equal to #elt#, function #search# sets argument #pos# with the
+ position of this list element and returns 1. If however the search
+ reaches the end of the list, function #search# returns 0 and leaves
+ #pos# unchanged. */
+ int search(const TYPE &elt, GPosition &pos) const
+ { return GListImpl<TI>::search((const TI&)elt, pos); }
+ // -- ALTERATION
+ /** Erases the list contents. All list elements are destroyed and
+ unlinked. The list is left with zero elements. */
+ void empty()
+ { GListImpl<TI>::empty(); }
+ /** Inserts an element after the last element of the list.
+ The new element is initialized with a copy of argument #elt#. */
+ void append(const TYPE &elt)
+ { GListImpl<TI>::append(newnode((const TI&)elt)); }
+ /** Inserts an element before the first element of the list.
+ The new element is initialized with a copy of argument #elt#. */
+ void prepend(const TYPE &elt)
+ { GListImpl<TI>::prepend(newnode((const TI&)elt)); }
+ /** Inserts a new element after the list element at position #pos#. When
+ position #pos# is null the element is inserted at the beginning of the
+ list. The new element is initialized with a copy of #elt#. */
+ void insert_after(GPosition pos, const TYPE &elt)
+ { GListImpl<TI>::insert_after(pos, newnode((const TI&)elt)); }
+ /** Inserts a new element before the list element at position #pos#. When
+ position #pos# is null the element is inserted at the end of the
+ list. The new element is initialized with a copy of #elt#. */
+ void insert_before(GPosition pos, const TYPE &elt)
+ { GListImpl<TI>::insert_before(pos, newnode((const TI&)elt)); }
+ /** Inserts an element of another list into this list. This function
+ removes the element at position #frompos# in list #frompos#, inserts it
+ in the current list before the element at position #pos#, and advances
+ #frompos# to the next element in list #fromlist#. When position #pos# is
+ null the element is inserted at the end of the list. */
+ void insert_before(GPosition pos, GListTemplate<TYPE,TI> &fromlist, GPosition &frompos)
+ { GListImpl<TI>::insert_before(pos, fromlist, frompos); }
+ /** Destroys the list element at position #pos#. This function does
+ nothing unless position #pos# is a valid position. */
+ void del(GPosition &pos)
+ { GListImpl<TI>::del(pos); }
+ /* Old iterators. Do not use. */
+#if GCONTAINER_OLD_ITERATORS
+ void first(GPosition &pos) const { pos = firstpos(); }
+ void last(GPosition &pos) const { pos = lastpos(); }
+ const TYPE *next(GPosition &pos) const
+ { if (!pos) return 0; const TYPE *x=&((*this)[pos]); ++pos; return x; }
+ const TYPE *prev(GPosition &pos) const
+ { if (!pos) return 0; const TYPE *x=&((*this)[pos]); --pos; return x; }
+ TYPE *next(GPosition &pos)
+ { if (!pos) return 0; TYPE *x=&((*this)[pos]); ++pos; return x; }
+ TYPE *prev(GPosition &pos)
+ { if (!pos) return 0; TYPE *x=&((*this)[pos]); --pos; return x; }
+#endif
+};
+
+
+/** Doubly linked lists. Template class #GList<TYPE># implements a doubly
+ linked list of elements of type #TYPE#. This class only implement
+ constructors. See class \Ref{GListTemplate} and \Ref{GPosition} for a
+ description of all access methods. */
+
+template <class TYPE>
+class GList : public GListTemplate<TYPE,TYPE>
+{
+public:
+ /** Null Constructor. Constructs a list with zero elements. */
+ GList() : GListTemplate<TYPE,TYPE>() {}
+ GList& operator=(const GList &r)
+ { GListBase::operator=(r); return *this; }
+};
+
+
+/** Doubly linked lists for smart pointers.
+ Template class #GList<TYPE># implements a doubly linked list of elements
+ of type #GP<TYPE># (see \Ref{GSmartPointer.h}). Significantly smaller
+ code sizes can be achieved by using this class instead of the more general
+ #GArray<GP<TYPE>>#.
+ This class only implement constructors. See class \Ref{GListTemplate} and
+ \Ref{GPosition} for a description of all access methods. */
+
+template <class TYPE>
+class GPList : public GListTemplate<GP<TYPE>,GPBase>
+{
+public:
+ /** Null Constructor. Constructs a list with zero elements. */
+ GPList() : GListTemplate<GP<TYPE>,GPBase>() {}
+ GPList& operator=(const GPList &r)
+ { GListBase::operator=(r); return *this; }
+};
+
+
+//@}
+
+
+
+// ------------------------------------------------------------
+// ASSOCIATIVE MAPS
+// ------------------------------------------------------------
+
+/** @name Associative Maps
+
+ These template classes implements a associative maps. The associative map
+ contains an arbitrary number of entries. Each entry is a pair containing
+ one element of type #KTYPE# (named the "key") and one element of type
+ #VTYPE# (named the "value"). All entries have distinct keys.
+ These template class must be able to access the following functions:
+ \begin{itemize}
+ \item a #VTYPE# default constructor #VTYPE::VTYPE()#,
+ \item a #VTYPE# copy constructor #VTYPE::VTYPE(const VTYPE &)#,
+ \item optionally a #VTYPE# destructor #VTYPE::~VTYPE()#,
+ \item a #KTYPE# default constructor #KTYPE::KTYPE()#,
+ \item a #KTYPE# copy constructor #KTYPE::KTYPE(const KTYPE &)#,
+ \item optionally a #KTYPE# destructor #KTYPE::~KTYPE()#,
+ \item a #KTYPE# comparison operator #KTYPE::operator==(const KTYPE &)#,
+ \item and a #KTYPE# hashing function #hash(const KTYPE&)#.
+ \end{itemize}
+ The hashing function must return an #unsigned int# number. Multiple
+ invocations of the hashing function with equal arguments (in the sense of
+ #KTYPE::operator==#) must always return the same number.
+ Position objects (see \Ref{GPosition}) may be used to iterate over the
+ entries contained by an associative map.
+ @memo Associative maps.
+*/
+//@{
+
+class GSetBase : public GCont
+{
+protected:
+ GSetBase(const Traits &traits);
+ GSetBase(const GSetBase &ref);
+ static GCONT HNode *newnode(const void *key);
+ HNode *hashnode(unsigned int hashcode) const;
+ HNode *installnode(HNode *n);
+ void deletenode(HNode *n);
+protected:
+ const Traits &traits;
+ int nelems;
+ int nbuckets;
+ HNode **table;
+ GPBuffer<HNode *> gtable;
+ HNode *first;
+private:
+ void insertnode(HNode *n);
+ void rehash(int newbuckets);
+public:
+ ~GSetBase();
+ GSetBase& operator=(const GSetBase &ref);
+ GPosition firstpos() const;
+ void del(GPosition &pos);
+ void empty();
+};
+
+template <class K>
+class GSetImpl : public GSetBase
+{
+protected:
+ GSetImpl();
+ GSetImpl(const Traits &traits);
+ typedef GCONT SetNode<K> SNode;
+ HNode *get(const K &key) const;
+ HNode *get_or_throw(const K &key) const;
+ HNode *get_or_create(const K &key);
+public:
+ GPosition contains(const K &key) const
+ { return GPosition( get(key), (void*)this); }
+ void del(const K &key)
+ { deletenode(get(key)); }
+};
+
+template<class K>
+GSetImpl<K>::GSetImpl()
+ : GSetBase( GCONT NormTraits<GCONT SetNode<K> >::traits() )
+{
+}
+
+template<class K>
+GSetImpl<K>::GSetImpl(const Traits &traits)
+ : GSetBase(traits)
+{
+}
+
+template<class K> GCONT HNode *
+GSetImpl<K>::get(const K &key) const
+{
+ unsigned int hashcode = hash(key);
+ for (SNode *s=(SNode*)hashnode(hashcode); s; s=(SNode*)(s->hprev))
+ if (s->hashcode == hashcode && s->key == key) return s;
+ return 0;
+}
+
+#if GCONTAINER_BOUNDS_CHECK
+template<class K> GCONT HNode *
+GSetImpl<K>::get_or_throw(const K &key) const
+{
+ HNode *m = get(key);
+ if (!m)
+ {
+ G_THROW( ERR_MSG("GContainer.cannot_add") );
+ }
+ return m;
+}
+#else
+template<class K> inline GCONT HNode *
+GSetImpl<K>::get_or_throw(const K &key) const
+{
+ return get(key);
+}
+#endif
+
+template<class K> GCONT HNode *
+GSetImpl<K>::get_or_create(const K &key)
+{
+ HNode *m = get(key);
+ if (m) return m;
+ SNode *n = (SNode*) operator new (sizeof(SNode));
+#if GCONTAINER_ZERO_FILL
+ memset(n, 0, sizeof(SNode));
+#endif
+ new ((void*)&(n->key)) K ( key );
+ n->hashcode = hash((const K&)(n->key));
+ installnode(n);
+ return n;
+}
+
+template <class K, class TI>
+class GMapImpl : public GSetImpl<K>
+{
+protected:
+ GMapImpl();
+ GMapImpl(const GCONT Traits &traits);
+ typedef GCONT MapNode<K,TI> MNode;
+ GCONT HNode* get_or_create(const K &key);
+};
+
+template<class K, class TI>
+GMapImpl<K,TI>::GMapImpl()
+ : GSetImpl<K> ( GCONT NormTraits<GCONT MapNode<K,TI> >::traits() )
+{
+}
+
+template<class K, class TI>
+GMapImpl<K,TI>::GMapImpl(const GCONT Traits &traits)
+ : GSetImpl<K>(traits)
+{
+}
+
+template<class K, class TI> GCONT HNode *
+GMapImpl<K,TI>::get_or_create(const K &key)
+{
+ GCONT HNode *m = get(key);
+ if (m) return m;
+ MNode *n = (MNode*) operator new (sizeof(MNode));
+#if GCONTAINER_ZERO_FILL
+ memset(n, 0, sizeof(MNode));
+#endif
+ new ((void*)&(n->key)) K (key);
+ new ((void*)&(n->val)) TI ();
+ n->hashcode = hash((const K&)(n->key));
+ installnode(n);
+ return n;
+}
+
+
+
+/** Common base class for all associative maps.
+ Class \Ref{GArrayTemplate} implements all methods for manipulating
+ associative maps with key type #KTYPE# and value type #VTYPE#.
+ You should not however create instances of this class.
+ You should instead use class \Ref{GMap} or \Ref{GPMap}. */
+
+template <class KTYPE, class VTYPE, class TI>
+class GMapTemplate : protected GMapImpl<KTYPE,TI>
+{
+public:
+ /** Returns the number of elements in the map. */
+ int size() const
+ { return this->nelems; }
+ /** Returns the first position in the map. */
+ GPosition firstpos() const
+ { return GMapImpl<KTYPE,TI>::firstpos(); }
+ /** Implicit notation for GMap::firstpos(). */
+ operator GPosition() const
+ { return firstpos(); }
+ /** Tests whether the associative map is empty.
+ Returns a non zero value if and only if the map contains zero entries. */
+ int isempty() const
+ { return this->nelems==0; }
+ /** Searches an entry for key #key#. If the map contains an entry whose key
+ is equal to #key# according to #KTYPE::operator==(const KTYPE&)#, this
+ function returns its position. Otherwise it returns an invalid
+ position. */
+ GPosition contains(const KTYPE &key) const
+ { return GMapImpl<KTYPE,TI>::contains(key); }
+ /* Compatibility */
+ GPosition contains(const KTYPE &key, GPosition &pos) const
+ { return pos = GMapImpl<KTYPE,TI>::contains(key); }
+ // -- ALTERATION
+ /** Erases the associative map contents. All entries are destroyed and
+ removed. The map is left with zero entries. */
+ void empty()
+ { GMapImpl<KTYPE,TI>::empty(); }
+ /** Returns a constant reference to the key of the map entry at position
+ #pos#. An exception \Ref{GException} is thrown if position #pos# is not
+ valid. There is no direct way to change the key of a map entry. */
+ const KTYPE &key(const GPosition &pos) const
+ { return (const KTYPE&)(((typename GMapImpl<KTYPE,TI>::MNode*)(pos.check((void*)this)))->key); }
+ /** Returns a reference to the value of the map entry at position #pos#.
+ This reference can be used for both reading (as "#a[n]#") and modifying
+ (as "#a[n]=v#"). An exception \Ref{GException} is thrown if position
+ #pos# is not valid. */
+ VTYPE& operator[](const GPosition &pos)
+ { return (VTYPE&)(((typename GMapImpl<KTYPE,TI>::MNode*)(pos.check((void*)this)))->val); }
+ /** Returns a constant reference to the value of the map entry at position
+ #pos#. This reference can only be used for reading (as "#a[n]#") the
+ entry value. An exception \Ref{GException} is thrown if position #pos#
+ is not valid. */
+ const VTYPE& operator[](const GPosition &pos) const
+ { return (const VTYPE&)(((typename GMapImpl<KTYPE,TI>::MNode*)(pos.check((void*)this)))->val); }
+ /** Returns a constant reference to the value of the map entry for key
+ #key#. This reference can only be used for reading (as "#a[n]#") the
+ entry value. An exception \Ref{GException} is thrown if no entry
+ contains key #key#. This variant of #operator[]# is necessary when
+ dealing with a #const GMAP<KTYPE,VTYPE>#. */
+ const VTYPE& operator[](const KTYPE &key) const
+ { return (const VTYPE&)(((const typename GMapImpl<KTYPE,TI>::MNode*)(get_or_throw(key)))->val); }
+ /** Returns a reference to the value of the map entry for key #key#. This
+ reference can be used for both reading (as "#a[n]#") and modifying (as
+ "#a[n]=v#"). If there is no entry for key #key#, a new entry is created
+ for that key with the null constructor #VTYPE::VTYPE()#. */
+ VTYPE& operator[](const KTYPE &key)
+ { return (VTYPE&)(((typename GMapImpl<KTYPE,TI>::MNode*)(get_or_create(key)))->val); }
+ /** Destroys the map entry for position #pos#.
+ Nothing is done if position #pos# is not a valid position. */
+ void del(GPosition &pos)
+ { GSetBase::del(pos); }
+ /** Destroys the map entry for key #key#.
+ Nothing is done if there is no entry for key #key#. */
+ void del(const KTYPE &key)
+ { GMapImpl<KTYPE,TI>::del(key); }
+ /* Old iterators. Do not use. */
+#if GCONTAINER_OLD_ITERATORS
+ void first(GPosition &pos) const { pos = firstpos(); }
+ const VTYPE *next(GPosition &pos) const
+ { if (!pos) return 0; const VTYPE *x=&((*this)[pos]); ++pos; return x; }
+ VTYPE *next(GPosition &pos)
+ { if (!pos) return 0; VTYPE *x=&((*this)[pos]); ++pos; return x; }
+#endif
+};
+
+
+
+/** Associative maps.
+ Template class #GMap<KTYPE,VTYPE># implements an associative map.
+ The map contains an arbitrary number of entries. Each entry is a
+ pair containing one element of type #KTYPE# (named the "key") and one
+ element of type #VTYPE# (named the "value").
+ The entry associated to a particular value of the key can retrieved
+ very efficiently.
+ This class only implement constructors. See class \Ref{GMapTemplate} and
+ \Ref{GPosition} for a description of all access methods.*/
+
+template <class KTYPE, class VTYPE>
+class GMap : public GMapTemplate<KTYPE,VTYPE,VTYPE>
+{
+public:
+ // -- ACCESS
+ GMap() : GMapTemplate<KTYPE,VTYPE,VTYPE>() {}
+ GMap& operator=(const GMap &r)
+ { GSetBase::operator=(r); return *this; }
+};
+
+/** Associative maps for smart-pointers.
+ Template class #GMap<KTYPE,VTYPE># implements an associative map for key
+ type #KTYPE# and value type #GP<VTYPE># (see \Ref{GSmartPointer.h}). The
+ map contains an arbitrary number of entries. Each entry is a pair
+ containing one element of type #KTYPE# (named the "key") and one aelement
+ of type #VTYPE# (named the "value"). The entry associated to a particular
+ value of the key can retrieved very efficiently.
+ Significantly smaller code sizes can be achieved by using this class
+ instead of the more general #GMap<KTYPE,GP<VTYPE>># (see \Ref{GMap}).
+ This class only implement constructors. See class \Ref{GMapTemplate} and
+ \Ref{GPosition} for a description of all access methods.*/
+
+template <class KTYPE, class VTYPE>
+class GPMap : public GMapTemplate<KTYPE,GP<VTYPE>,GPBase>
+{
+public:
+ GPMap() : GMapTemplate<KTYPE,GP<VTYPE>,GPBase>() {}
+ GPMap& operator=(const GPMap &r)
+ { GSetBase::operator=(r); return *this; }
+};
+
+
+// ------------------------------------------------------------
+// HASH FUNCTIONS
+// ------------------------------------------------------------
+
+
+/** @name Hash functions
+ These functions let you use template class \Ref{GMap} with the
+ corresponding elementary types. The returned hash code may be reduced to
+ an arbitrary range by computing its remainder modulo the upper bound of
+ the range.
+ @memo Hash functions for elementary types. */
+//@{
+
+/** Hashing function (unsigned int). */
+static inline unsigned int
+hash(const unsigned int & x)
+{
+ return x;
+}
+
+/** Hashing function (int). */
+static inline unsigned int
+hash(const int & x)
+{
+ return (unsigned int)x;
+}
+
+/** Hashing function (long). */
+static inline unsigned int
+hash(const long & x)
+{
+ return (unsigned int)x;
+}
+
+/** Hashing function (unsigned long). */
+static inline unsigned int
+hash(const unsigned long & x)
+{
+ return (unsigned int)x;
+}
+
+/** Hashing function (void *). */
+static inline unsigned int
+hash(void * const & x)
+{
+ return (unsigned long) x;
+}
+
+/** Hashing function (const void *). */
+static inline unsigned int
+hash(const void * const & x)
+{
+ return (unsigned long) x;
+}
+
+/** Hashing function (float). */
+static inline unsigned int
+hash(const float & x)
+{
+ // optimizer will get rid of unnecessary code
+ unsigned int *addr = (unsigned int*)&x;
+ if (sizeof(float)<2*sizeof(unsigned int))
+ return addr[0];
+ else
+ return addr[0]^addr[1];
+}
+
+/** Hashing function (double). */
+static inline unsigned int
+hash(const double & x)
+{
+ // optimizer will get rid of unnecessary code
+ unsigned int *addr = (unsigned int*)&x;
+ if (sizeof(double)<2*sizeof(unsigned int))
+ return addr[0];
+ else if (sizeof(double)<4*sizeof(unsigned int))
+ return addr[0]^addr[1];
+ else
+ return addr[0]^addr[1]^addr[2]^addr[3];
+}
+
+
+//@}
+//@}
+//@}
+
+// ------------ THE END
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
+
+
diff --git a/kviewshell/plugins/djvu/libdjvu/GException.cpp b/kviewshell/plugins/djvu/libdjvu/GException.cpp
new file mode 100644
index 00000000..f3f84dda
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GException.cpp
@@ -0,0 +1,284 @@
+//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: GException.cpp,v 1.14 2004/08/06 15:11:29 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "GException.h"
+#include "DjVuMessageLite.h"
+#include "debug.h"
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+// - Author: Leon Bottou, 05/1997
+
+GException::GException()
+ : cause(0), file(0), func(0), line(0), source(GException::GINTERNAL)
+{
+}
+
+const char * const
+GException::outofmemory = ERR_MSG("GException.outofmemory");
+
+GException::GException(const GException & exc)
+ : file(exc.file), func(exc.func), line(exc.line), source(exc.source)
+{
+ if (exc.cause && exc.cause!=outofmemory)
+ {
+ char *s = new char[strlen(exc.cause)+1];
+ strcpy(s, exc.cause);
+ cause = s;
+ }
+ else
+ {
+ cause = exc.cause;
+ }
+}
+
+GException::GException (const char *xcause, const char *file, int line,
+ const char *func, const source_type xsource)
+ : file(file), func(func), line(line), source(xsource)
+{
+ // good place to set a breakpoint and DEBUG message too.
+ // It'd hard to track exceptions which seem to go from nowhere
+#ifdef DEBUG_MSG
+ DEBUG_MSG("GException::GException(): cause=" << (xcause ? xcause : "unknown") << "\n");
+#endif
+ if (xcause && xcause!=outofmemory)
+ {
+ char *s = new char[strlen(xcause)+1];
+ strcpy(s, xcause);
+ cause = s;
+ }
+ else
+ {
+ cause = xcause;
+ }
+}
+
+GException::~GException(void)
+{
+ if (cause && cause!=outofmemory )
+ delete [] const_cast<char*>(cause);
+ cause=file=func=0;
+}
+
+GException &
+GException::operator=(const GException & exc)
+{
+ if (cause && cause!=outofmemory)
+ delete [] const_cast<char*>(cause);
+ cause = 0;
+ file = exc.file;
+ func = exc.func;
+ line = exc.line;
+ source=exc.source;
+ if (exc.cause && exc.cause!=outofmemory)
+ {
+ char *s = new char[strlen(exc.cause)+1];
+ strcpy(s, exc.cause);
+ cause = s;
+ }
+ else
+ {
+ cause = exc.cause;
+ }
+ return *this;
+}
+
+void
+GException::perror(void) const
+{
+ fflush(0);
+ DjVuPrintErrorUTF8("*** ");
+ DjVuMessageLite::perror(get_cause());
+ if (file && line>0)
+ DjVuPrintErrorUTF8("*** (%s:%d)\n", file, line);
+ else if (file)
+ DjVuPrintErrorUTF8("*** (%s)\n", file);
+ if (func)
+ DjVuPrintErrorUTF8("*** '%s'\n", func);
+ DjVuPrintErrorUTF8("\n");
+}
+
+const char*
+GException::get_cause(void) const
+{
+ if (! cause)
+ return "Invalid exception";
+ return cause;
+}
+
+int
+GException::cmp_cause(const char s1[] , const char s2[])
+{
+ int retval;
+ if(! s2 || !s2[0])
+ {
+ retval=(s1&&s1[0])?1:(-1);
+ }else if(! s1 || !s1[0])
+ {
+ retval=(-1);
+ }else
+ {
+ const char *end_s1=strpbrk(s1,"\t\n");
+ const int n1=end_s1?(int)((size_t)end_s1-(size_t)s1):strlen(s1);
+ const char *end_s2=strpbrk(s1,"\t\n");
+ const int n2=end_s2?(int)((size_t)end_s2-(size_t)s2):strlen(s2);
+ retval=(n1==n2)?strncmp(s1,s2,n1):strcmp(s1,s2);
+ }
+ return retval;
+}
+
+int
+GException::cmp_cause(const char s2[]) const
+{
+ return cmp_cause(cause,s2);
+}
+
+#ifdef USE_EXCEPTION_EMULATION
+
+GExceptionHandler *GExceptionHandler::head = 0;
+
+void
+GExceptionHandler::emthrow(const GException &gex)
+{
+ if (head)
+ {
+ head->current = gex;
+ longjmp(head->jump, -1);
+ }
+ else
+ {
+ DjVuPrintErrorUTF8("\n*** Unhandled exception");
+ gex.perror();
+ abort();
+ }
+}
+
+#else // ! USE_EXCEPTION_EMULATION
+
+static int abort_on_exception = 0;
+
+void
+#ifndef NO_LIBGCC_HOOKS
+GExceptionHandler::exthrow(const GException &ex)
+#else
+GExceptionHandler::exthrow(const GException ex)
+#endif /* NO_LIBGCC_HOOKS */
+{
+ if (abort_on_exception)
+ abort();
+ throw ex;
+}
+
+void
+GExceptionHandler::rethrow(void)
+{
+ if (abort_on_exception)
+ abort();
+ throw;
+}
+
+#endif
+
+
+
+// ------ MEMORY MANAGEMENT HANDLER
+
+#ifndef NEED_DJVU_MEMORY
+// This is not activated when C++ memory management
+// is overidden. The overriding functions handle
+// memory exceptions by themselves.
+# if defined(_MSC_VER)
+// Microsoft is different!
+static int throw_memory_error(size_t) { G_THROW(GException::outofmemory); return 0; }
+static int (*old_handler)(size_t) = _set_new_handler(throw_memory_error);
+# else // !_MSC_VER
+// Standard C++
+static void throw_memory_error() { G_THROW(GException::outofmemory); }
+# if !defined(WIN32) && !defined(__CYGWIN32__) && !defined(OS2)
+# ifdef HAVE_STDINCLUDES
+static void (*old_handler)() = std::set_new_handler(throw_memory_error);
+# else
+static void (*old_handler)() = set_new_handler(throw_memory_error);
+# endif // HAVE_STDINCLUDES
+# endif // ! WIN32
+# endif // !_MSC_VER
+#endif // !NEED_DJVU_MEMORY
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+
diff --git a/kviewshell/plugins/djvu/libdjvu/GException.h b/kviewshell/plugins/djvu/libdjvu/GException.h
new file mode 100644
index 00000000..97286987
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GException.h
@@ -0,0 +1,356 @@
+//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: GException.h,v 1.10 2005/06/07 23:42:22 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _GEXCEPTION_H_
+#define _GEXCEPTION_H_
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+#ifndef no_return
+#ifdef __GNUC__
+#define no_return __attribute__ ((noreturn))
+#else
+#define no_return
+#endif
+#endif
+
+/** @name GException.h
+
+ Files #"GException.h"# and #"GException.cpp"# define a portable exception
+ scheme used through the DjVu Reference Library. This scheme can use native
+ C++ exceptions or an exception emulation based on #longjmp#/#setjmp#. A
+ particular model can be forced a compile time by defining option
+ #CPP_SUPPORTS_EXCEPTIONS# or #USE_EXCEPTION_EMULATION#.
+
+ This emulation code was motivated because many compilers did not properly
+ support exceptions as mandated by the C++ standard documents. This
+ emulation is now considered obsolete because (a) it is not able to call
+ the proper destructors when an exception occurs, and (b) it is not thread
+ safe. Although all modern C++ compiler handle exception decently, the
+ exception handling intrinsics are not always thread safe. Therefore we
+ urge programmers to {\em only} use exceptions to signal error conditions
+ that force the library to discontinue execution.
+
+ There are four macros for handling exceptions. Macros #G_TRY#, #G_CATCH# and
+ #G_ENDCATCH# are used to define an exception catching block. Exceptions can
+ be thrown at all times using macro #G_THROW(cause)#. An exception can be
+ re-thrown from a catch block using macro #G_RETHROW#.
+
+ Example:
+ \begin{verbatim}
+ G_TRY
+ {
+ // program lines which may result in a call to THROW()
+ G_THROW("message");
+ }
+ G_CATCH(ex)
+ {
+ // Variable ex refers to a GException object.
+ ex.perror();
+ // You can rethrow the exception to an outer exception handler.
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+ \end{verbatim}
+
+ @memo
+ Portable exceptions.
+ @author
+ L\'eon Bottou <leonb@research.att.com> -- initial implementation.\\
+ Andrei Erofeev <eaf@geocities.com> -- fixed message memory allocation.
+ @version
+ #$Id: GException.h,v 1.10 2005/06/07 23:42:22 leonb Exp $# */
+//@{
+
+#include "DjVuGlobal.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+
+/** Exception class.
+ The library always uses macros #G_TRY#, #G_THROW#, #G_CATCH# and #G_ENDCATCH# for
+ throwing and catching exceptions (see \Ref{GException.h}). These macros
+ only deal with exceptions of type #GException#. */
+
+class GException {
+public:
+ enum source_type { GINTERNAL=0, GEXTERNAL, GAPPLICATION, GOTHER };
+ /** Constructs a GException. This constructor is usually called by macro
+ #G_THROW#. Argument #cause# is a plain text error message. As a
+ convention, string #ByteStream::EndOfFile# is used when reaching an unexpected
+ end-of-file condition and string #DataPool::Stop# is used when the user
+ interrupts the execution. The remaining arguments are usually provided
+ by the predefined macros #__FILE__#, #__LINE__#, and (G++ and EGCS only)
+ #__PRETTY_FUNCTION__#. */
+ GException (const char *cause, const char *file=0, int line=0,
+ const char *func=0, const source_type source=GINTERNAL);
+
+ /** Copy Constructor. */
+ GException (const GException & exc);
+
+ /** Null Constructor. */
+ GException ();
+
+ /** Destructor. */
+ virtual ~GException(void);
+
+ /** Copy Operator. */
+ GException & operator=(const GException & exc);
+
+ /** Prints an error message on stderr.
+ This function no longer takes a message parameter because
+ some instances used a i18n message id and other instances
+ used a literal string. */
+ void perror(void) const;
+
+ /** Returns the string describing the cause of the exception. The returned
+ pointer is never null. Exception handlers should not rely on the value
+ of the string #cause#. As a convention however, string
+ #ByteStream::EndOfFile# is used
+ when reaching an unexpected end-of-file condition and string
+ #DataPool::Stop# is used when the user interrupts the execution. These
+ strings can be tested by the exception handlers, with
+ #cmp_cause#. Similar conventional strings may be defined
+ in the future. They all will be small strings with only uppercase
+ characters. */
+ const char* get_cause(void) const;
+
+ /** Compares the cause with the specified string, ignoring anything after
+ the first tab. */
+ int cmp_cause(const char s2[]) const;
+
+ /** Compares the cause with the specified string, ignoring anything after
+ the first tab. */
+ static int cmp_cause(const char s1[],const char s2[]);
+
+ /** Returns the function name from which the exception was thrown.
+ A null pointer is returned if no function name is available. */
+ const char* get_function(void) const { return func; }
+
+ /** Returns the file name from which the exception was thrown.
+ A null pointer is returned if no file name is available. */
+ const char* get_file(void) const { return file; }
+
+ /** Returns the exception source */
+ source_type get_source(void) const { return source; }
+
+ /** Returns the line number from which the exception was thrown.
+ A zero is returned if no line number is available. */
+ int get_line(void) const { return line; };
+
+ // Magic cause string
+ static const char * const outofmemory;
+
+private:
+ const char *cause;
+ const char *file;
+ const char *func;
+ int line;
+ source_type source;
+};
+
+//@}
+
+#undef G_TRY
+#undef G_CATCH
+#undef G_CATCH_ALL
+#undef G_ENDCATCH
+#undef G_RETHROW
+#undef G_THROW
+#undef G_THROW_TYPE
+#undef G_THROW_INTERNAL
+#undef G_THROW_EXTERNAL
+#undef G_THROW_APPLICATION
+#undef G_THROW_OTHER
+
+// Check if compiler supports native exceptions
+#if defined(_MSC_VER)
+#define CPP_SUPPORTS_EXCEPTIONS
+#endif
+#if defined(__MWERKS__)
+#define CPP_SUPPORTS_EXCEPTIONS
+#endif
+#if defined(__EXCEPTIONS)
+#define CPP_SUPPORTS_EXCEPTIONS
+#endif
+// Decide which exception model to use
+#ifndef CPP_SUPPORTS_EXCEPTIONS
+#ifndef USE_EXCEPTION_EMULATION
+#define USE_EXCEPTION_EMULATION
+#endif
+#endif
+
+
+#ifndef USE_EXCEPTION_EMULATION
+
+// Compiler supports ANSI C++ exceptions.
+// Defined exception macros accordingly.
+
+class GExceptionHandler {
+public:
+#ifndef NO_LIBGCC_HOOKS
+ static void exthrow(const GException &) no_return;
+#else
+ static void exthrow(const GException ) no_return;
+#endif /* NO_LIBGCC_HOOKS */
+ static void rethrow(void) no_return;
+};
+
+#define G_TRY try
+#define G_CATCH(n) catch(const GException &n) {
+#define G_CATCH_ALL catch(...) {
+#define G_ENDCATCH }
+#define G_RETHROW GExceptionHandler::rethrow()
+#define G_EMTHROW(ex) GExceptionHandler::exthrow(ex)
+#ifdef __GNUG__
+#define G_THROW_TYPE(msg,xtype) GExceptionHandler::exthrow \
+ (GException(msg, __FILE__, __LINE__, __PRETTY_FUNCTION__, xtype))
+#else
+#define G_THROW_TYPE(msg,xtype) GExceptionHandler::exthrow \
+ (GException(msg, __FILE__, __LINE__,0, xtype))
+#endif
+
+#else // USE_EXCEPTION_EMULATION
+
+// Compiler does not support ANSI C++ exceptions.
+// Emulate with setjmp/longjmp.
+
+#include <setjmp.h>
+
+class GExceptionHandler {
+public:
+ jmp_buf jump;
+ GExceptionHandler *next;
+ GException current;
+public:
+ static GExceptionHandler *head;
+ static void emthrow(const GException &) no_return;
+public:
+ GExceptionHandler() { next = head; };
+ ~GExceptionHandler() { head = next; };
+};
+
+#define G_TRY do { GExceptionHandler __exh; \
+ if (!setjmp(__exh.jump)) \
+ { GExceptionHandler::head = &__exh;
+
+#define G_CATCH_ALL } else { GExceptionHandler::head = __exh.next;
+#define G_CATCH(n) G_CATCH_ALL const GException& n = __exh.current;
+
+#define G_ENDCATCH } } while(0)
+
+#define G_RETHROW GExceptionHandler::emthrow(__exh.current)
+
+#ifdef __GNUG__
+#define G_THROW_TYPE(msg,xtype) GExceptionHandler::emthrow \
+ (GException(msg, __FILE__, __LINE__, __PRETTY_FUNCTION__, xtype))
+#define G_EMTHROW(ex) GExceptionHandler::emthrow(ex)
+#else
+#define G_THROW_TYPE(m,xtype) GExceptionHandler::emthrow \
+ (GException(m, __FILE__, __LINE__,0, xtype))
+#define G_EMTHROW(ex) GExceptionHandler::emthrow(ex)
+#endif
+
+#endif // !CPP_SUPPORTS_EXCEPTIONS
+
+
+inline void
+G_EXTHROW
+(const GException &ex,const char *msg=0,const char *file=0,int line=0,
+ const char *func=0, const GException::source_type source=GException::GINTERNAL)
+{
+ G_EMTHROW( (msg||file||line||func)?
+ GException(msg?msg:ex.get_cause(),
+ file?file:ex.get_file(),
+ line?line:ex.get_line(),
+ func?func:ex.get_function(),
+ source)
+ :ex);
+}
+
+inline void
+G_EXTHROW
+(const char msg[],const char *file=0,int line=0,const char *func=0,
+ const GException::source_type source=GException::GINTERNAL )
+{
+ G_EMTHROW(GException(msg,file,line,func,source));
+}
+
+#define G_THROW(msg) G_THROW_TYPE(msg,GException::GINTERNAL)
+#define G_THROW_INTERNAL(msg) G_THROW_TYPE(msg,GException::GINTERNAL)
+#define G_THROW_EXTERNAL(msg) G_THROW_TYPE(msg,GException::GEXTERNAL)
+#define G_THROW_APPLICATION(msg) G_THROW_TYPE(msg,GException::GAPPLICATION)
+#define G_THROW_OTHER(msg) G_THROW_TYPE(msg,GException::GOTHER)
+
+// -------------- THE END
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/GIFFManager.cpp b/kviewshell/plugins/djvu/libdjvu/GIFFManager.cpp
new file mode 100644
index 00000000..973c6cec
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GIFFManager.cpp
@@ -0,0 +1,663 @@
+//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: GIFFManager.cpp,v 1.8 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "GIFFManager.h"
+#include "GException.h"
+#include "debug.h"
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+GIFFChunk::~GIFFChunk(void) {}
+
+GIFFManager::~GIFFManager(void) {}
+
+GP<GIFFManager>
+GIFFManager::create(void)
+{
+ GIFFManager *iff=new GIFFManager();
+ GP<GIFFManager> retval=iff;
+ iff->init();
+ return retval;
+}
+
+GP<GIFFManager>
+GIFFManager::create(const GUTF8String &name)
+{
+ GIFFManager *iff=new GIFFManager();
+ GP<GIFFManager> retval=iff;
+ iff->init(name);
+ return retval;
+}
+
+void
+GIFFChunk::set_name(GUTF8String name)
+{
+ DEBUG_MSG("GIFFChunk::set_name(): name='" << name << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ const int colon=name.search(':');
+ if(colon>=0)
+ {
+ type=name.substr(0,colon);
+ name=name.substr(colon+1,(unsigned int)-1);
+ if(name.search(':')>=0)
+ G_THROW( ERR_MSG("GIFFManager.one_colon") );
+ }
+
+ DEBUG_MSG("auto-setting type to '" << type << "'\n");
+
+ if (name.contains(".[]")>=0)
+ G_THROW( ERR_MSG("GIFFManager.bad_char") );
+
+ strncpy(GIFFChunk::name, (const char *)name, 4);
+ GIFFChunk::name[4]=0;
+ for(int i=strlen(GIFFChunk::name);i<4;i++)
+ GIFFChunk::name[i]=' ';
+}
+
+bool
+GIFFChunk::check_name(GUTF8String name)
+{
+ GUTF8String type;
+ const int colon=name.search(':');
+ if(colon>=0)
+ {
+ type=name.substr(0,colon);
+ name=name.substr(colon+1,(unsigned int)-1);
+ }
+
+ const GUTF8String sname=(name.substr(0,4)+" ").substr(0,4);
+
+ DEBUG_MSG("GIFFChunk::check_name(): type='" << type << "' name='" << sname << "'\n");
+ return (type==GIFFChunk::type || !type.length() && GIFFChunk::type=="FORM")
+ && sname==GIFFChunk::name;
+}
+
+void
+GIFFChunk::save(IFFByteStream & istr, bool use_trick)
+{
+ DEBUG_MSG("GIFFChunk::save(): saving chunk '" << get_full_name() << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (is_container())
+ {
+ istr.put_chunk(get_full_name(), use_trick);
+ if (chunks.size())
+ {
+ GPosition pos;
+ for(pos=chunks;pos;++pos)
+ if (chunks[pos]->get_type()=="PROP")
+ chunks[pos]->save(istr);
+ for(pos=chunks;pos;++pos)
+ if (chunks[pos]->get_type()!="PROP")
+ chunks[pos]->save(istr);
+ } else
+ {
+ DEBUG_MSG("but it's empty => saving empty container.\n");
+ }
+ istr.close_chunk();
+ } else
+ {
+ istr.put_chunk(get_name(), use_trick);
+ istr.get_bytestream()->writall((const char *) data, data.size());
+ istr.close_chunk();
+ }
+}
+
+void
+GIFFChunk::add_chunk(const GP<GIFFChunk> & chunk, int position)
+{
+ DEBUG_MSG("GIFFChunk::add_chunk(): Adding chunk to '" << get_name() <<
+ "' @ position=" << position << "\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (!type.length())
+ {
+ DEBUG_MSG("Converting the parent to FORM\n");
+ type="FORM";
+ }
+
+ if (chunk->get_type()=="PROP")
+ {
+ DEBUG_MSG("Converting the parent to LIST\n");
+ type="LIST";
+ }
+
+ GPosition pos;
+ if (position>=0 && chunks.nth(position, pos))
+ {
+ chunks.insert_before(pos, chunk);
+ }else
+ {
+ chunks.append(chunk);
+ }
+}
+
+GUTF8String
+GIFFChunk::decode_name(const GUTF8String &name, int &number)
+{
+ DEBUG_MSG("GIFFChunk::decode_name(): Checking brackets in name '" << name << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (name.search('.')>=0)
+ G_THROW( ERR_MSG("GIFFManager.no_dots") );
+
+ number=0;
+ const int obracket=name.search('[');
+ GUTF8String short_name;
+ if (obracket >= 0)
+ {
+ const int cbracket=name.search(']',obracket+1);
+ if (cbracket < 0)
+ G_THROW( ERR_MSG("GIFFManager.unmatched") );
+ if (name.length() > (unsigned int)(cbracket+1))
+ G_THROW( ERR_MSG("GIFFManager.garbage") );
+// number =atoi((const char *)name.substr(obracket+1,cbracket-obracket-1));
+ number= name.substr(obracket+1,cbracket-obracket-1).toInt();
+ short_name=name.substr(0,obracket);
+ }else
+ {
+ short_name=name;
+ }
+
+ const int colon=short_name.search(':');
+ if (colon>=0)
+ short_name=short_name.substr(colon+1,(unsigned int)-1);
+
+ for(int i=short_name.length();i<4;i++)
+ short_name.setat(i, ' ');
+
+ DEBUG_MSG("short_name='" << short_name << "'\n");
+ DEBUG_MSG("number=" << number << "\n");
+
+ return short_name;
+}
+
+void
+GIFFChunk::del_chunk(const GUTF8String &name)
+ // The name may contain brackets to specify the chunk number
+{
+ DEBUG_MSG("GIFFChunk::del_chunk(): Deleting chunk '" << name <<
+ "' from '" << get_name() << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ int number;
+ const GUTF8String short_name=decode_name(name,number);
+
+ GPosition pos=chunks;
+ for(int num=0;pos;++pos)
+ {
+ if ((chunks[pos]->get_name()==short_name)&&(num++ == number))
+ {
+ chunks.del(pos);
+ break;
+ }
+ }
+ if(! pos)
+ {
+ G_THROW( ERR_MSG("GIFFManager.no_chunk") "\t"+short_name+"\t"+GUTF8String(number)+"\t"+get_name());
+ }
+}
+
+GP<GIFFChunk>
+GIFFChunk::get_chunk(const GUTF8String &name, int * pos_ptr)
+ // The name may contain brackets to specify the chunk number
+{
+ DEBUG_MSG("GIFFChunk::get_chunk(): Returning chunk '" << name <<
+ "' from '" << get_name() << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ int number;
+ const GUTF8String short_name=decode_name(name,number);
+
+ int num=0;
+ int pos_num;
+ GP<GIFFChunk> retval;
+ GPosition pos;
+ for(pos=chunks, pos_num=0;pos;++pos, pos_num++)
+ {
+ if (chunks[pos]->get_name()==short_name && num++==number)
+ {
+ if (pos_ptr)
+ *pos_ptr=pos_num;
+ retval=chunks[pos];
+ break;
+ }
+ }
+ return retval;
+}
+
+int
+GIFFChunk::get_chunks_number(void)
+{
+ DEBUG_MSG("GIFFChunk::get_chunks_number(): Returning number of chunks '" << name <<
+ "' in '" << get_name() << "'\n");
+ DEBUG_MAKE_INDENT(3);
+ return chunks.size();
+}
+
+int
+GIFFChunk::get_chunks_number(const GUTF8String &name)
+{
+ DEBUG_MSG("GIFFChunk::get_chunks_number(): Returning number of chunks '" << name <<
+ "' in '" << get_name() << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (name.contains("[]")>=0)
+ G_THROW( ERR_MSG("GIFFManager.no_brackets") );
+
+ int number;
+ GUTF8String short_name=decode_name(name,number);
+
+ int num=0;
+ for(GPosition pos=chunks;pos;++pos)
+ num+=(chunks[pos]->get_name()==short_name);
+ return num;
+}
+
+//************************************************************************
+
+void
+GIFFManager::add_chunk(GUTF8String parent_name, const GP<GIFFChunk> & chunk,
+ int pos)
+ // parent_name is the fully qualified name of the PARENT
+ // IT MAY BE EMPTY
+ // All the required chunks will be created
+ // pos=-1 means to append the chunk
+{
+ DEBUG_MSG("GIFFManager::add_chunk(): Adding chunk to name='" << parent_name << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (!top_level->get_name().length())
+ {
+ if ((!parent_name.length())||(parent_name[0]!='.'))
+ G_THROW( ERR_MSG("GIFFManager.no_top_name") );
+ if (parent_name.length() < 2)
+ {
+ // 'chunk' is actually the new top-level chunk
+ DEBUG_MSG("since parent_name=='.', making the chunk top-level\n");
+ if (!chunk->is_container())
+ G_THROW( ERR_MSG("GIFFManager.no_top_cont") );
+ top_level=chunk;
+ return;
+ }
+
+ DEBUG_MSG("Setting the name of the top-level chunk\n");
+ const int next_dot=parent_name.search('.',1);
+ if(next_dot>=0)
+ {
+ top_level->set_name(parent_name.substr(1,next_dot-1));
+ }else
+ {
+ top_level->set_name(parent_name.substr(1,(unsigned int)-1));
+ }
+ }
+
+ DEBUG_MSG("top level chunk name='" << top_level->get_name() << "'\n");
+
+ if (parent_name.length() && parent_name[0] == '.')
+ {
+ int next_dot=parent_name.search('.',1);
+ if(next_dot<0)
+ {
+ next_dot=parent_name.length();
+ }
+ GUTF8String top_name=parent_name.substr(1,next_dot-1);
+ if (!top_level->check_name(top_name))
+ G_THROW( ERR_MSG("GIFFManager.wrong_name") "\t"+top_name);
+ parent_name=parent_name.substr(next_dot,(unsigned int)-1);
+ }
+
+ GP<GIFFChunk> cur_sec=top_level;
+ const char * start, * end=(const char *)parent_name-1;
+ do
+ {
+ for(start=++end;*end&&(*end!='.');end++)
+ EMPTY_LOOP;
+ if (end>start)
+ {
+ GUTF8String name(start,end-start);
+ GUTF8String short_name;
+ int number=0;
+ const int obracket=name.search('[');
+ if (obracket >= 0)
+ {
+ const int cbracket=name.search(']',obracket+1);
+ if (cbracket < 0)
+ G_THROW( ERR_MSG("GIFFManager.unmatched") );
+// number=atoi((const char *)name.substr(obracket+1,cbracket-obracket-1));
+ number = name.substr(obracket+1,cbracket-obracket-1).toInt();
+ short_name=name.substr(0,obracket);
+ }else
+ {
+ short_name=name;
+ }
+
+ for(int i=cur_sec->get_chunks_number(short_name);i<number+1;i++)
+ cur_sec->add_chunk(GIFFChunk::create(short_name));
+ cur_sec=cur_sec->get_chunk(name);
+ if (!cur_sec)
+ G_THROW( ERR_MSG("GIFFManager.unknown") "\t"+name);
+ }
+ } while(*end);
+ cur_sec->add_chunk(chunk, pos);
+}
+
+void
+GIFFManager::add_chunk(GUTF8String name, const TArray<char> & data)
+ // name is fully qualified name of the chunk TO BE INSERTED.
+ // it may contain brackets at the end to set the position
+ // All the required chunks will be created
+{
+ DEBUG_MSG("GIFFManager::add_chunk(): adding plain chunk with name='" << name << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GUTF8String chunk_name;
+ const int lastdot=name.rsearch('.');
+ if(lastdot < 0)
+ {
+ chunk_name=name;
+ name=name.substr(0,lastdot);
+ }else
+ {
+ chunk_name=name.substr(lastdot+1,(unsigned int)-1);
+ }
+
+ int pos=-1;
+ const int obracket=chunk_name.search('[');
+ if (obracket >= 0)
+ {
+ const int cbracket=chunk_name.search(']',obracket+1);
+ if (cbracket < 0)
+ G_THROW( ERR_MSG("GIFFManager.unmatched") );
+ if (name.length() > (unsigned int)(cbracket+1))
+ G_THROW( ERR_MSG("GIFFManager.garbage") );
+// pos=atoi((const char *)chunk_name.substr(obracket+1,cbracket-obracket-1));
+ pos = chunk_name.substr(obracket+1,cbracket-obracket-1).toInt();
+ chunk_name=chunk_name.substr(0,obracket);
+ }
+ DEBUG_MSG("Creating new chunk with name " << chunk_name << "\n");
+ GP<GIFFChunk> chunk;
+ chunk=GIFFChunk::create(chunk_name, data);
+ add_chunk(name, chunk, pos);
+}
+
+void
+GIFFManager::del_chunk(void)
+{
+ DEBUG_MSG("GIFFManager::del_chunk(): Deleting chunk\n");
+ DEBUG_MAKE_INDENT(3);
+
+ G_THROW( ERR_MSG("GIFFManager.del_empty") );
+}
+
+void
+GIFFManager::del_chunk(GUTF8String name)
+ // "name" should be fully qualified, that is contain dots.
+ // It may also end with [] to set the chunk order number
+{
+ DEBUG_MSG("GIFFManager::del_chunk(): Deleting chunk '" << name << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (!name.length())
+ G_THROW( ERR_MSG("GIFFManager.del_empty") );
+
+ if (name[0]=='.')
+ {
+ const int next_dot=name.search('.',1);
+ if (next_dot < 0)
+ {
+ if (top_level->check_name(name.substr(1,(unsigned int)-1)))
+ {
+ DEBUG_MSG("Removing top level chunk..\n");
+ top_level=GIFFChunk::create();
+ return;
+ }
+ G_THROW( ERR_MSG("GIFFManager.wrong_name2") "\t"+name.substr(1,(unsigned int)-1));
+ }
+ const GUTF8String top_name=name.substr(1,next_dot-1);
+ if (!top_level->check_name(top_name))
+ G_THROW( ERR_MSG("GIFFManager.wrong_name2") "\t"+top_name);
+ name=name.substr(next_dot+1,(unsigned int)-1);
+ }
+
+ GP<GIFFChunk> cur_sec=top_level;
+ const char * start, * end=(const char *)name-1;
+ do
+ {
+ for(start=++end;*end&&(*end!='.');end++)
+ EMPTY_LOOP;
+ if (end>start && *end=='.')
+ cur_sec=cur_sec->get_chunk(GUTF8String(start, end-start));
+ if (!cur_sec)
+ G_THROW( ERR_MSG("GIFFManager.cant_find") "\t"+GUTF8String(name));
+ } while(*end);
+
+ if (!start[0])
+ {
+ G_THROW(GUTF8String( ERR_MSG("GIFFManager.malformed") "\t")+name);
+ }
+
+ cur_sec->del_chunk(start);
+}
+
+GP<GIFFChunk>
+GIFFManager::get_chunk(GUTF8String name, int * pos_num)
+ // "name" should be fully qualified, that is contain dots.
+ // It may also end with [] to set the chunk order number
+{
+ DEBUG_MSG("GIFFManager::get_chunk(): Returning chunk '" << name << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ if (!name.length())
+ G_THROW( ERR_MSG("GIFFManager.get_empty") );
+
+ if (name[0]=='.')
+ {
+ const int next_dot=name.search('.',1);
+ if (next_dot < 0)
+ {
+ if (top_level->check_name(name.substr(1,(unsigned int)-1)))
+ {
+ DEBUG_MSG("Removing top level chunk..\n");
+ return top_level;
+ }
+ G_THROW( ERR_MSG("GIFFManager.wrong_name2") "\t"+name.substr(1,(unsigned int)-1));
+ }
+ const GUTF8String top_name=name.substr(1,next_dot-1);
+ if (!top_level->check_name(top_name))
+ G_THROW( ERR_MSG("GIFFManager.wrong_name2") "\t"+top_name);
+ name=name.substr(next_dot+1,(unsigned int)-1);
+ }
+
+ GP<GIFFChunk> cur_sec=top_level;
+ const char * start, * end=(const char *) name-1;
+ do
+ {
+ for(start=++end;*end&&(*end!='.');end++)
+ EMPTY_LOOP;
+ if (end>start)
+ cur_sec=cur_sec->get_chunk(GUTF8String(start, end-start), pos_num);
+ if (!cur_sec)
+ break;
+ } while(*end);
+
+ return cur_sec;
+}
+
+int
+GIFFManager::get_chunks_number(void)
+{
+ DEBUG_MSG("GIFFManager::get_chunks_number()\n");
+ DEBUG_MAKE_INDENT(3);
+ return top_level->get_chunks_number();
+}
+
+int
+GIFFManager::get_chunks_number(const GUTF8String &name)
+ // Returns the number of chunks with given fully qualified name
+{
+ DEBUG_MSG("GIFFManager::get_chunks_number(): name='" << name << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ int retval;
+ const int last_dot=name.rsearch('.');
+ if (last_dot<0)
+ {
+ retval=top_level->get_chunks_number(name);
+ }else if(!last_dot)
+ {
+ retval=(top_level->get_name()==name.substr(1,(unsigned int)-1))?1:0;
+ }else
+ {
+ GP<GIFFChunk> chunk=get_chunk(name.substr(0,last_dot));
+ retval=( chunk
+ ?(chunk->get_chunks_number(name.substr(last_dot+1,(unsigned int)-1)))
+ :0 );
+ }
+ return retval;
+}
+
+void
+GIFFManager::load_chunk(IFFByteStream & istr, GP<GIFFChunk> chunk)
+{
+ DEBUG_MSG("GIFFManager::load_chunk(): loading contents of chunk '" <<
+ chunk->get_name() << "'\n");
+ DEBUG_MAKE_INDENT(3);
+
+ int chunk_size;
+ GUTF8String chunk_id;
+ while ((chunk_size=istr.get_chunk(chunk_id)))
+ {
+ if (istr.check_id(chunk_id))
+ {
+ GP<GIFFChunk> ch=GIFFChunk::create(chunk_id);
+ load_chunk(istr, ch);
+ chunk->add_chunk(ch);
+ } else
+ {
+ TArray<char> data(chunk_size-1);
+ istr.get_bytestream()->readall( (char*)data, data.size());
+ GP<GIFFChunk> ch=GIFFChunk::create(chunk_id, data);
+ chunk->add_chunk(ch);
+ }
+ istr.close_chunk();
+ }
+}
+
+void
+GIFFManager::load_file(const TArray<char> & data)
+{
+ GP<ByteStream> str=ByteStream::create((const char *)data, data.size());
+ load_file(str);
+}
+
+void
+GIFFManager::load_file(GP<ByteStream> str)
+{
+ DEBUG_MSG("GIFFManager::load_file(): Loading IFF file.\n");
+ DEBUG_MAKE_INDENT(3);
+
+ GP<IFFByteStream> gistr=IFFByteStream::create(str);
+ IFFByteStream &istr=*gistr;
+ GUTF8String chunk_id;
+ if (istr.get_chunk(chunk_id))
+ {
+ if (chunk_id.substr(0,5) != "FORM:")
+ G_THROW( ERR_MSG("GIFFManager.cant_find2") );
+ set_name(chunk_id);
+ load_chunk(istr, top_level);
+ istr.close_chunk();
+ }
+}
+
+void
+GIFFManager::save_file(TArray<char> & data)
+{
+ GP<ByteStream> gstr=ByteStream::create();
+ save_file(gstr);
+ data=gstr->get_data();
+}
+
+void
+GIFFManager::save_file(GP<ByteStream> str)
+{
+ GP<IFFByteStream> istr=IFFByteStream::create(str);
+ top_level->save(*istr, 1);
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+
diff --git a/kviewshell/plugins/djvu/libdjvu/GIFFManager.h b/kviewshell/plugins/djvu/libdjvu/GIFFManager.h
new file mode 100644
index 00000000..722f592f
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GIFFManager.h
@@ -0,0 +1,394 @@
+//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: GIFFManager.h,v 1.8 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _GIFFMANAGER_H
+#define _GIFFMANAGER_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+#include "IFFByteStream.h"
+#include "GContainer.h"
+#include "Arrays.h"
+#include "GSmartPointer.h"
+#include "GString.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+/** @name GIFFManager.h
+
+ Files #"GIFFManager.h"# and #"GIFFManager.cpp"# define more convenient
+ interface to IFF files. You may want to use the {\Ref GIFFManager} class
+ instead of coping with {\Ref IFFByteStream} especially when you have to
+ insert or move chunks, which is a kind of tricky with sequential access
+ provided by {\Ref IFFByteStream}.
+
+ You will mostly deal with {\Ref GIFFManager} class, but sometimes you may
+ want to use {\Ref GIFFChunk}s as well thus bypassing {\Ref GIFFManager}'s
+ interface and working with the chunks hierarchy yourself.
+
+ Interface to IFF files.
+ @author
+ Andrei Erofeev <eaf@geocities.com> -- Initial implementation.
+ @version
+ #$Id: GIFFManager.h,v 1.8 2003/11/07 22:08:21 leonb Exp $# */
+
+/** #GIFFChunk# is the base class for other IFF chunks understood by
+ {\Ref GIFFManager}. It provides some basic interface, and is not supposed
+ to be used on its own. */
+
+class GIFFChunk : public GPEnabled
+{
+protected:
+ GIFFChunk(void);
+ GIFFChunk(const GUTF8String &name);
+ GIFFChunk(const GUTF8String &name, const TArray<char> & data);
+public:
+ /// Default creator.
+ static GP<GIFFChunk> create(void) {return new GIFFChunk();}
+
+ /** Creates the chunk with the given name. The {\em name} may not
+ contain dots colons or brackets */
+ static GP<GIFFChunk> create(const GUTF8String &name)
+ {return new GIFFChunk(name);}
+
+ /** Creates the {\em plain chunk} containing raw data */
+ static GP<GIFFChunk> create(const GUTF8String &name, const TArray<char> & data)
+ { return new GIFFChunk(name,data); }
+
+ /// Destructor
+ virtual ~GIFFChunk(void);
+
+ /// Returns the name of the chunk (without possible #FORM:# or similar prefixes)
+ GUTF8String get_name(void) const;
+ /// Returns full chunk name, with possible container specification
+ GUTF8String get_full_name(void) const;
+ /// Returns the chunk type, like #CAT# for chunk #CAT:DJVU#
+ GUTF8String get_type(void) const;
+ /// Returns TRUE if the chunk may contain other chunks or FALSE otherwise
+ bool is_container(void) const;
+ /** Sets the chunk name. The {\em name} may not contain dots or brackets,
+ but {\bf may} contain colons. */
+ void set_name(GUTF8String name);
+ /** Parses the {\em name} probably containing colon and compares it
+ with its own name returning TRUE if they are the same */
+ bool check_name(GUTF8String name);
+
+ /** Adds the {\em chunk} to the chunks list at position {\em order}.
+ Set {\em order} to #-1# to append the chunk to the list.
+ {\bf Note!} By adding chunk #PROP# you will convert this chunk
+ to type #LIST# {\em automatically}. */
+ void add_chunk(const GP<GIFFChunk> & chunk, int order=-1);
+ /** Removes the chunk with given {\em name}. The {\em name} may not
+ contain dots, but MAY contain colons and brackets (the latter -
+ for specifying the chunk number) */
+ void del_chunk(const GUTF8String &name);
+ /** Returns the chunk with given {\em name}. The {\em name} may not
+ contain dots, but MAY contain colons and brackets (the latter -
+ for specifying the chunk number). If {\em position} is not zero
+ then the chunk position in its parent will be put into #*position# */
+ GP<GIFFChunk>get_chunk(const GUTF8String &name, int * position=0);
+ /** Returns the number of chunks with given {\em name}. The {\em name}
+ may not contain dots and brackets. If {\em name} is ZERO, the
+ total number of chunks will be returned. */
+ int get_chunks_number(const GUTF8String &name);
+ int get_chunks_number(void);
+ /** Returns the data array for plain chunks */
+ TArray<char> get_data(void) const;
+
+ /** Saves the chunk into the {\Ref IFFByteStream}.
+ Set {\em use_trick} to #1# if this is a top-level chunk */
+ void save(IFFByteStream & istr, bool use_trick=0);
+private:
+ char name[5];
+ GUTF8String type;
+ GPList<GIFFChunk> chunks;
+ TArray<char> data;
+ static GUTF8String decode_name(const GUTF8String &name, int &number);
+};
+
+inline GUTF8String
+GIFFChunk::get_name(void) const { return GUTF8String(name, 4); }
+
+inline GUTF8String
+GIFFChunk::get_type(void) const { return type; }
+
+inline GUTF8String
+GIFFChunk::get_full_name(void) const { return get_type()+":"+get_name(); }
+
+inline bool
+GIFFChunk::is_container(void) const { return type.length()!=0; }
+
+inline TArray<char>
+GIFFChunk::get_data(void) const { return data; }
+
+inline
+GIFFChunk::GIFFChunk(void) { name[0]=0; }
+
+inline
+GIFFChunk::GIFFChunk(const GUTF8String &name) { set_name(name); }
+
+inline
+GIFFChunk::GIFFChunk(const GUTF8String &name, const TArray<char> & data_in) :
+ data(data_in)
+{
+ set_name(name);
+}
+
+//************************************************************************
+
+/** Intuitive interface to IFF files.
+
+ It's too terrible to keep reading/writing IFF files chunk after chunk
+ using {\Ref IFFByteStream}s. This class allows you to operate with chunks
+ as with structures or arrays without even caring about the byte streams.
+
+ Some of the examples are below:
+ \begin{verbatim}
+ GP<GIFFChunk> chunk;
+ chunk=manager1.get_chunk("BG44[2]");
+ manager2.add_chunk(".FORM:DJVU.BG44[-1]", chunk);
+ \end{verbatim}
+
+ {\bf Chunk name}
+ \begin{itemize}
+ \item Every chunk name may contain optional prefix #FORM:#, #LIST:#,
+ #PROP:# or #CAT:#. If the prefix is omitted and the chunk happens
+ to contain other chunks, #FORM:# will be assumed.
+ \item Every chunk name may be {\em short} or {\em complete}.
+ {\em short} chunk names may not contain dots as they're a
+ subchunks names with respect to a given chunk.
+ {\em complete} chunk names may contain dots. But there may be
+ or may not be the {\em leading dot} in the name. If the
+ {\em leading dot} is present, then the name is assumed to contain
+ the name of the top-level chunk as well. Otherwise it's treated
+ {\em with respect} to the top-level chunk. You may want to use
+ the leading dot only when you add a chunk to an empty document,
+ since a command like #manager.addChunk(".FORM:DJVU.BG44", chunk)#
+ will create the top level chunk of the requested type (#FORM:DJVU#)
+ and will add chunk #BG44# to it {\em automatically}.
+ \item You may use {\em brackets} in the name to specify the chunk's
+ position. The meaning of the number inside the brackets depends
+ on the function you call. In most of the cases this is the number
+ of the chunk with the given name in the parent chunk. But sometimes
+ (as in #addChunk(name, buffer, length)#) the brackets at the
+ end of the #name# actually specify the {\em position} of the
+ chunk in the parent. For example, to insert #INCL# chunk into
+ #DJVU# form at position #1# (make it the second) you may want to
+ use #manager.addChunk(".DJVU.INCL[1]", data, size)#. At the same
+ time, to get 2-nd chunk with name #BG44# from form #DJVU# you
+ should do smth like #chunk=manager.getChunk("BG44[1]")#. Note, that
+ here the manager will search for chunk #BG44# in form #DJVU# and
+ will take the second {\em found} one.
+ \end{itemize} */
+
+class GIFFManager : public GPEnabled
+{
+protected:
+ GIFFManager(void);
+ void init(void);
+ void init(const GUTF8String &name);
+public:
+ /// Default creator.
+ static GP<GIFFManager> create(void);
+
+ /** Creates the {\Ref GIFFManager} and assigns name {\em name} to
+ the top-level chunk. you may use chunk type names (before colon)
+ to set the top-level chunk type, or omit it to work with #FORM# */
+ static GP<GIFFManager> create(const GUTF8String &name);
+
+ /// Virtual destructor.
+ virtual ~GIFFManager(void);
+
+ /// Sets the name of the top level chunk to {\em name}
+ void set_name(const GUTF8String &name);
+ /** Adds the chunk {\em chunk} to chunk with name {\em parent_name} at
+ position {\em pos}. {\em parent_name} may contain dots, brackets
+ and colons. All missing chunks in the chain will be created.
+
+ {\bf Examples:}
+ \begin{verbatim}
+ ;; To set the top-level chunk to 'ch'
+ m.addChunk(".", ch);
+ ;; To add 'ch' to the top-level chunk "DJVU" creating it if necessary
+ m.addChunk(".DJVU", ch);
+ ;; Same as above regardless of top-level chunk name
+ m.addChunk("", ch);
+ ;; To add 'ch' to 2nd FORM DJVU in top-level form DJVM
+ m.addChunk(".FORM:DJVM.FORM:DJVU[1]", ch);
+ ;; Same thing regardless of the top-level chunk name
+ m.addChunk("FORM:DJVU[1]", ch);
+ \end{verbatim} */
+ void add_chunk(GUTF8String parent_name, const GP<GIFFChunk> & chunk, int pos=-1);
+ /** If {\em name}={\em name1}.{\em name2} where {\em name2} doesn't
+ contain dots, then #addChunk()# will create plain chunk with
+ name {\em name2} with data {\em buffer} of size {\em length} and
+ will add it to chunk {\em name1} in the same way as
+ #addChunk(name, chunk, pos)# function would do it. The #pos# in
+ this case is either #-1# (append) or is extracted from between
+ brackets if the {\em name} ends with them.
+
+ {\bf Examples:}
+ \begin{verbatim}
+ ;; To insert INCL chunk at position 2 (make it 3rd)
+ m.addChunk("INCL[2]", data, length);
+ ;; To append chunk BG44 to 2nd DjVu file inside DjVm archive:
+ m.addChunk(".DJVM.DJVU[1].BG44", data, length);
+ \end{verbatim} */
+ void add_chunk(GUTF8String name, const TArray<char> & data);
+ /** Will remove chunk with name {\em name}. You may use dots, colons
+ and brackets to specify the chunk uniquely.
+
+ {\bf Examples:}
+ \begin{verbatim}
+ ;; To remove 2nd DjVu document from DjVm archive use
+ m.delChunk(".DJVM.DJVU[1]");
+ ;; Same thing without top-level chunk name specification
+ m.delChunk("DJVU[1]");
+ ;; Same thing for the first DJVU chunk
+ m.delChunk("DJVU");
+ \end{verbatim}
+ */
+ void del_chunk(GUTF8String name);
+ void del_chunk(void);
+ /** Will return the number of chunks with given name. The {\em name} may
+ not end with brackets, but may contain them inside. It may also
+ contain dots and colons. If {\em name} is ZERO, the total number
+ of chunks will be returned.
+
+ {\bf Examples:}
+ \begin{verbatim}
+ ;; To get the number of DJVU forms inside DjVm document
+ m.getChunksNumber(".DJVM.DJVU");
+ ;; Same thing without top-level chunk name specification
+ m.getChunksNumber("DJVU");
+ \end{verbatim}
+ */
+ int get_chunks_number(const GUTF8String &name);
+ int get_chunks_number(void);
+
+ /** Returns the chunk with name {\em name}. The {\em name} may contain dots
+ colons and slashes. If {\em position} is not zero, #*position# will
+ be assigned the position of the found chunk in the parent chunk.
+
+ {\bf Examples:}
+ \begin{verbatim}
+ ;; To get the directory chunk of DjVm document
+ m.getChunk(".DJVM.DIR0");
+ ;; To get chunk corresponding to 2nd DJVU form
+ m.getChunk(".DJVU[1]");
+ \end{verbatim} */
+ GP<GIFFChunk>get_chunk(GUTF8String name, int * position=0);
+
+ /** Loads the composite {\em chunk}'s contents from stream {\em istr}. */
+ void load_chunk(IFFByteStream & istr, GP<GIFFChunk> chunk);
+ /** Loads the file contents from stream {\em str} */
+ void load_file(GP<ByteStream> str);
+ /** Loads the file contents from the data array {\em data} */
+ void load_file(const TArray<char> & data);
+ /** Saves all the chunks into stream {\em str} */
+ void save_file(GP<ByteStream> str);
+ /** Saves all the chunks into the data array {\em data} */
+ void save_file(TArray<char> & data);
+
+private:
+ GP<GIFFChunk> top_level;
+
+ static const char * check_leading_dot(const GUTF8String &name);
+private: //dummy methods
+ static void save_file(ByteStream *);
+ static void load_file(ByteStream *);
+};
+
+inline void
+GIFFManager::set_name(const GUTF8String &name)
+{
+ top_level->set_name(name);
+}
+
+inline
+GIFFManager::GIFFManager(void) {}
+
+inline void
+GIFFManager::init(void)
+{
+ top_level=GIFFChunk::create();
+}
+
+inline void
+GIFFManager::init(const GUTF8String &name)
+{
+ top_level=GIFFChunk::create(name);
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/GMapAreas.cpp b/kviewshell/plugins/djvu/libdjvu/GMapAreas.cpp
new file mode 100644
index 00000000..5a85e1fc
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GMapAreas.cpp
@@ -0,0 +1,1066 @@
+//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: GMapAreas.cpp,v 1.9 2004/05/05 15:12:42 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "GMapAreas.h"
+#include "GException.h"
+#include "debug.h"
+
+#include <math.h>
+#include <stdio.h>
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+/****************************************************************************
+***************************** GMapArea definition ***************************
+****************************************************************************/
+
+const char GMapArea::MAPAREA_TAG[] = "maparea";
+const char GMapArea::RECT_TAG[] = "rect";
+const char GMapArea::POLY_TAG[] = "poly";
+const char GMapArea::OVAL_TAG[] = "oval";
+const char GMapArea::NO_BORDER_TAG[] = "none";
+const char GMapArea::XOR_BORDER_TAG[] = "xor";
+const char GMapArea::SOLID_BORDER_TAG[] = "border";
+const char GMapArea::SHADOW_IN_BORDER_TAG[] = "shadow_in";
+const char GMapArea::SHADOW_OUT_BORDER_TAG[] = "shadow_out";
+const char GMapArea::SHADOW_EIN_BORDER_TAG[] = "shadow_ein";
+const char GMapArea::SHADOW_EOUT_BORDER_TAG[] = "shadow_eout";
+const char GMapArea::BORDER_AVIS_TAG[] = "border_avis";
+const char GMapArea::HILITE_TAG[] = "hilite";
+const char GMapArea::URL_TAG[] = "url";
+const char GMapArea::TARGET_SELF[] = "_self";
+static const char zero_width[] = ERR_MSG("GMapAreas.zero_width");
+static const char zero_height[] = ERR_MSG("GMapAreas.zero_height");
+static const char width_1[] = ERR_MSG("GMapAreas.width_1");
+static const char width_3_32 [] = ERR_MSG("GMapAreas.width_3-32");
+static const char error_poly_border [] = ERR_MSG("GMapAreas.poly_border");
+static const char error_poly_hilite [] = ERR_MSG("GMapAreas.poly_hilite");
+static const char error_oval_border [] = ERR_MSG("GMapAreas.oval_border");
+static const char error_oval_hilite [] = ERR_MSG("GMapAreas.oval_hilite");
+static const char error_too_few_points [] = ERR_MSG("GMapAreas.too_few_points");
+static const char error_intersect [] = ERR_MSG("GMapAreas.intersect");
+
+GMapArea::~GMapArea() {}
+
+GMapRect::~GMapRect() {}
+
+GMapPoly::~GMapPoly() {}
+
+GMapOval::~GMapOval() {}
+
+void
+GMapArea::initialize_bounds(void)
+{
+ xmin=gma_get_xmin();
+ xmax=gma_get_xmax();
+ ymin=gma_get_ymin();
+ ymax=gma_get_ymax();
+ bounds_initialized=true;
+}
+
+int
+GMapArea::get_xmin(void) const
+{
+ if (!bounds_initialized)
+ const_cast<GMapArea *>(this)->initialize_bounds();
+ return xmin;
+}
+
+int
+GMapArea::get_ymin(void) const
+{
+ if (!bounds_initialized)
+ const_cast<GMapArea *>(this)->initialize_bounds();
+ return ymin;
+}
+
+int
+GMapArea::get_xmax(void) const
+{
+ if (!bounds_initialized)
+ const_cast<GMapArea *>(this)->initialize_bounds();
+ return xmax;
+}
+
+int
+GMapArea::get_ymax(void) const
+{
+ if (!bounds_initialized)
+ const_cast<GMapArea *>(this)->initialize_bounds();
+ return ymax;
+}
+
+GRect
+GMapArea::get_bound_rect(void) const
+{
+ return GRect(get_xmin(), get_ymin(), get_xmax()-get_xmin(),
+ get_ymax()-get_ymin());
+}
+
+void
+GMapArea::move(int dx, int dy)
+{
+ if (dx || dy)
+ {
+ if (bounds_initialized)
+ {
+ xmin+=dx;
+ ymin+=dy;
+ xmax+=dx;
+ ymax+=dy;
+ }
+ gma_move(dx, dy);
+ }
+}
+
+void
+GMapArea::resize(int new_width, int new_height)
+{
+ if (get_xmax()-get_xmin()!=new_width ||
+ get_ymax()-get_ymin()!=new_height)
+ {
+ gma_resize(new_width, new_height);
+ bounds_initialized=false;
+ }
+}
+
+void
+GMapArea::transform(const GRect & grect)
+{
+ if (grect.xmin!=get_xmin() || grect.ymin!=get_ymin() ||
+ grect.xmax!=get_xmax() || grect.ymax!=get_ymax())
+ {
+ gma_transform(grect);
+ bounds_initialized=false;
+ }
+}
+
+char const * const
+GMapArea::check_object(void)
+{
+ char const *retval;
+ if (get_xmax()==get_xmin())
+ {
+ retval=zero_width;
+ }
+ else if (get_ymax()==get_ymin())
+ {
+ retval=zero_height;
+ }
+ else if ((border_type==XOR_BORDER ||
+ border_type==SOLID_BORDER) && border_width!=1)
+ {
+ retval=width_1;
+ }
+ else if ((border_type==SHADOW_IN_BORDER ||
+ border_type==SHADOW_OUT_BORDER ||
+ border_type==SHADOW_EIN_BORDER ||
+ border_type==SHADOW_EOUT_BORDER)&&
+ (border_width<3 || border_width>32))
+ {
+ retval=width_3_32;
+ }else
+ {
+ retval=gma_check_object();
+ }
+ return retval;
+}
+
+bool
+GMapArea::is_point_inside(int x, int y) const
+{
+ if (!bounds_initialized)
+ const_cast<GMapArea *>(this)->initialize_bounds();
+ return (x>=xmin && x<xmax && y>=ymin && y<ymax) ?
+ gma_is_point_inside(x, y) : false;
+}
+
+GUTF8String
+GMapArea::print(void)
+{
+ // Make this hard check to make sure, that *no* illegal GMapArea
+ // can be stored into a file.
+ const char * const errors=check_object();
+ if (errors[0])
+ {
+ G_THROW(errors);
+ }
+
+ int i;
+ GUTF8String tmp;
+ GUTF8String url1, target1, comment1;
+ const GUTF8String url_str=url;
+ for(i=0;i<(int) url_str.length();i++)
+ {
+ char ch=url_str[i];
+ if (ch=='"')
+ url1+='\\';
+ url1+=ch;
+ }
+ for(i=0;i<(int) target.length();i++)
+ {
+ char ch=target[i];
+ if (ch=='"')
+ target1+='\\';
+ target1+=ch;
+ }
+ for(i=0;i<(int) comment.length();i++)
+ {
+ char ch=comment[i];
+ if (ch=='"')
+ comment1+='\\';
+ comment1+=ch;
+ }
+
+ GUTF8String border_color_str;
+ border_color_str.format("#%02X%02X%02X",
+ (border_color & 0xff0000) >> 16,
+ (border_color & 0xff00) >> 8,
+ (border_color & 0xff));
+
+ static const GUTF8String left('(');
+ static const GUTF8String right(')');
+ static const GUTF8String space(' ');
+ static const GUTF8String quote('"');
+ GUTF8String border_type_str;
+ switch(border_type)
+ {
+ case NO_BORDER:
+ border_type_str=left+NO_BORDER_TAG+right;
+ break;
+ case XOR_BORDER:
+ border_type_str=left+XOR_BORDER_TAG+right;
+ break;
+ case SOLID_BORDER:
+ border_type_str=left+SOLID_BORDER_TAG+space+border_color_str+right;
+ break;
+ case SHADOW_IN_BORDER:
+ border_type_str=left+SHADOW_IN_BORDER_TAG+space+GUTF8String(border_width)+right;
+ break;
+ case SHADOW_OUT_BORDER:
+ border_type_str=left+SHADOW_OUT_BORDER_TAG+space+GUTF8String(border_width)+right;
+ break;
+ case SHADOW_EIN_BORDER:
+ border_type_str=left+SHADOW_EIN_BORDER_TAG+space+GUTF8String(border_width)+right;
+ break;
+ case SHADOW_EOUT_BORDER:
+ border_type_str=left+SHADOW_EOUT_BORDER_TAG+space+GUTF8String(border_width)+right;
+ break;
+ default:
+ border_type_str=left+XOR_BORDER_TAG+right;
+ break;
+ }
+
+ GUTF8String hilite_str;
+ if (hilite_color!=0xffffffff)
+ {
+ hilite_str.format("(%s #%02X%02X%02X)",
+ HILITE_TAG, (hilite_color & 0xff0000) >> 16,
+ (hilite_color & 0xff00) >> 8,
+ (hilite_color & 0xff));
+ }
+
+ GUTF8String URL;
+ if (target1==TARGET_SELF)
+ {
+ URL=quote+url1+quote;
+ }else
+ {
+ URL=left+URL_TAG+space+quote+url1+quote+space+quote+target1+quote+right;
+ }
+
+ GUTF8String total=left+MAPAREA_TAG+space+URL+space+quote+comment1+quote+space+gma_print()+border_type_str;
+ if (border_always_visible)
+ total+=space+left+BORDER_AVIS_TAG+right;
+ if ( hilite_str.length() > 0 )
+ total+=space+hilite_str;
+ total+=right;
+ return total;
+}
+
+/*
+void
+GMapArea::map(GRectMapper &mapper)
+{
+ get_bound_rect();
+ GRect rect = GRect(xmin, ymin, xmax, ymax);
+ mapper.map(rect);
+ xmin = rect.xmin;
+ ymin = rect.ymin;
+ xmax = rect.xmax;
+ ymax = rect.ymax;
+ clear_bounds();
+}
+void
+GMapArea::unmap(GRectMapper &mapper)
+{
+ get_bound_rect();
+ GRect rect = GRect(xmin, ymin, xmax, ymax);
+ mapper.unmap(rect);
+ xmin = rect.xmin;
+ ymin = rect.ymin;
+ xmax = rect.xmax;
+ ymax = rect.ymax;
+ clear_bounds();
+}
+*/
+
+
+/// Virtual function generating a list of defining coordinates
+/// (default are the opposite corners of the enclosing rectangle)
+void GMapArea::get_coords( GList<int> & CoordList ) const
+{
+ CoordList.append( get_xmin() );
+ CoordList.append( get_ymin() );
+ CoordList.append( get_xmax() );
+ CoordList.append( get_ymax() );
+}
+
+
+/****************************************************************************
+**************************** GMapRect definition ****************************
+****************************************************************************/
+
+void
+GMapRect::gma_resize(int new_width, int new_height)
+{
+ xmax=xmin+new_width;
+ ymax=ymin+new_height;
+}
+
+void
+GMapRect::gma_transform(const GRect & grect)
+{
+ xmin=grect.xmin; ymin=grect.ymin;
+ xmax=grect.xmax; ymax=grect.ymax;
+}
+
+GUTF8String
+GMapRect::gma_print(void)
+{
+ GUTF8String buffer;
+ return buffer.format("(%s %d %d %d %d) ",
+ RECT_TAG, xmin, ymin, xmax-xmin, ymax-ymin);
+}
+
+void
+GMapRect::map(GRectMapper &mapper)
+{
+ get_bound_rect();
+ GRect rect;
+ rect.xmin = xmin;
+ rect.xmax = xmax;
+ rect.ymin = ymin;
+ rect.ymax = ymax;
+ mapper.map(rect);
+ xmin = rect.xmin;
+ ymin = rect.ymin;
+ xmax = rect.xmax;
+ ymax = rect.ymax;
+ clear_bounds();
+}
+void
+GMapRect::unmap(GRectMapper &mapper)
+{
+ get_bound_rect();
+ GRect rect;
+ rect.xmin = xmin;
+ rect.xmax = xmax;
+ rect.ymin = ymin;
+ rect.ymax = ymax;
+ mapper.unmap(rect);
+ xmin = rect.xmin;
+ ymin = rect.ymin;
+ xmax = rect.xmax;
+ ymax = rect.ymax;
+ clear_bounds();
+}
+
+/****************************************************************************
+**************************** GMapPoly definition ****************************
+****************************************************************************/
+
+inline int
+GMapPoly::sign(int x) { return x<0 ? -1 : x>0 ? 1 : 0; }
+
+bool
+GMapPoly::does_side_cross_rect(const GRect & grect, int side)
+{
+ int x1=xx[side], x2=xx[(side+1)%points];
+ int y1=yy[side], y2=yy[(side+1)%points];
+ int xmin=x1<x2 ? x1 : x2;
+ int ymin=y1<y2 ? y1 : y2;
+ int xmax=x1+x2-xmin;
+ int ymax=y1+y2-ymin;
+
+ if (xmax<grect.xmin || xmin>grect.xmax ||
+ ymax<grect.ymin || ymin>grect.ymax) return false;
+
+ return
+ x1>=grect.xmin && x1<=grect.xmax && y1>=grect.ymin && y1<=grect.ymax ||
+ x2>=grect.xmin && x2<=grect.xmax && y2>=grect.ymin && y2<=grect.ymax ||
+ do_segments_intersect(grect.xmin, grect.ymin, grect.xmax, grect.ymax,
+ x1, y1, x2, y2) ||
+ do_segments_intersect(grect.xmax, grect.ymin, grect.xmin, grect.ymax,
+ x1, y1, x2, y2);
+}
+
+bool
+GMapPoly::is_projection_on_segment(int x, int y, int x1, int y1, int x2, int y2)
+{
+ int res1=(x-x1)*(x2-x1)+(y-y1)*(y2-y1);
+ int res2=(x-x2)*(x2-x1)+(y-y2)*(y2-y1);
+ return sign(res1)*sign(res2)<=0;
+}
+
+bool
+GMapPoly::do_segments_intersect(int x11, int y11, int x12, int y12,
+ int x21, int y21, int x22, int y22)
+{
+ int res11=(x11-x21)*(y22-y21)-(y11-y21)*(x22-x21);
+ int res12=(x12-x21)*(y22-y21)-(y12-y21)*(x22-x21);
+ int res21=(x21-x11)*(y12-y11)-(y21-y11)*(x12-x11);
+ int res22=(x22-x11)*(y12-y11)-(y22-y11)*(x12-x11);
+ if (!res11 && !res12)
+ {
+ // Segments are on the same line
+ return
+ is_projection_on_segment(x11, y11, x21, y21, x22, y22) ||
+ is_projection_on_segment(x12, y12, x21, y21, x22, y22) ||
+ is_projection_on_segment(x21, y21, x11, y11, x12, y12) ||
+ is_projection_on_segment(x22, y22, x11, y11, x12, y12);
+ }
+ int sign1=sign(res11)*sign(res12);
+ int sign2=sign(res21)*sign(res22);
+ return sign1<=0 && sign2<=0;
+}
+
+bool
+GMapPoly::are_segments_parallel(int x11, int y11, int x12, int y12,
+ int x21, int y21, int x22, int y22)
+{
+ return (x12-x11)*(y22-y21)-(y12-y11)*(x22-x21)==0;
+}
+
+char const * const
+GMapPoly::check_data(void)
+{
+ if (open && points<2 || !open && points<3)
+ return error_too_few_points;
+ for(int i=0;i<sides;i++)
+ {
+ for(int j=i+2;j<sides;j++)
+ {
+ if (i != (j+1)%points )
+ {
+ if (do_segments_intersect(xx[i], yy[i], xx[i+1], yy[i+1],
+ xx[j], yy[j], xx[(j+1)%points], yy[(j+1)%points]))
+ {
+ return error_intersect;
+ }
+ }
+ }
+ }
+ return "";
+}
+
+void
+GMapPoly::optimize_data(void)
+{
+ // Removing segments of length zero
+ int i;
+ for(i=0;i<sides;i++)
+ {
+ while(xx[i]==xx[(i+1)%points] && yy[i]==yy[(i+1)%points])
+ {
+ for(int k=(i+1)%points;k<points-1;k++)
+ {
+ xx[k]=xx[k+1]; yy[k]=yy[k+1];
+ }
+ points--; sides--;
+ if (!points) return;
+ }
+ }
+ // Concatenating consequitive parallel segments
+ for(i=0;i<sides;i++)
+ {
+ while((open && i+1<sides || !open) &&
+ are_segments_parallel(xx[i], yy[i],
+ xx[(i+1)%points], yy[(i+1)%points],
+ xx[(i+1)%points], yy[(i+1)%points],
+ xx[(i+2)%points], yy[(i+2)%points]))
+ {
+ for(int k=(i+1)%points;k<points-1;k++)
+ {
+ xx[k]=xx[k+1]; yy[k]=yy[k+1];
+ }
+ points--; sides--;
+ if (!points) return;
+ }
+ }
+}
+
+bool
+GMapPoly::gma_is_point_inside(const int xin, const int yin) const
+{
+ if (open)
+ return false;
+
+ int xfar=get_xmax()+(get_xmax()-get_xmin());
+
+ int intersections=0;
+ for(int i=0;i<points;i++)
+ {
+ int res1=yy[i]-yin;
+ if (!res1) continue;
+ int res2, isaved=i;
+ while(!(res2=yy[(i+1)%points]-yin)) i++;
+ if (isaved!=i)
+ {
+ // Some points fell exactly on the line
+ if ((xx[(isaved+1)%points]-xin)*
+ (xx[i%points]-xin)<=0)
+ {
+ // Test point is exactly on the boundary
+ return true;
+ }
+ }
+ if (res1<0 && res2>0 || res1>0 && res2<0)
+ {
+ int x1=xx[i%points], y1=yy[i%points];
+ int x2=xx[(i+1)%points], y2=yy[(i+1)%points];
+ int _res1=(xin-x1)*(y2-y1)-(yin-y1)*(x2-x1);
+ int _res2=(xfar-x1)*(y2-y1)-(yin-y1)*(x2-x1);
+ if (!_res1 || !_res2)
+ {
+ // The point is on this boundary
+ return true;
+ }
+ if (sign(_res1)*sign(_res2)<0) intersections++;
+ }
+ }
+ return (intersections % 2)!=0;
+}
+
+int
+GMapPoly::gma_get_xmin(void) const
+{
+ int x=xx[0];
+ for(int i=1;i<points;i++)
+ if (x>xx[i]) x=xx[i];
+ return x;
+}
+
+int
+GMapPoly::gma_get_xmax(void) const
+{
+ int x=xx[0];
+ for(int i=1;i<points;i++)
+ if (x<xx[i]) x=xx[i];
+ return x+1;
+}
+
+int
+GMapPoly::gma_get_ymin(void) const
+{
+ int y=yy[0];
+ for(int i=1;i<points;i++)
+ if (y>yy[i]) y=yy[i];
+ return y;
+}
+
+int
+GMapPoly::gma_get_ymax(void) const
+{
+ int y=yy[0];
+ for(int i=1;i<points;i++)
+ if (y<yy[i]) y=yy[i];
+ return y+1;
+}
+
+void
+GMapPoly::gma_move(int dx, int dy)
+{
+ for(int i=0;i<points;i++)
+ {
+ xx[i]+=dx; yy[i]+=dy;
+ }
+}
+
+void
+GMapPoly::gma_resize(int new_width, int new_height)
+{
+ int width=get_xmax()-get_xmin();
+ int height=get_ymax()-get_ymin();
+ int xmin=get_xmin(), ymin=get_ymin();
+ for(int i=0;i<points;i++)
+ {
+ xx[i]=xmin+(xx[i]-xmin)*new_width/width;
+ yy[i]=ymin+(yy[i]-ymin)*new_height/height;
+ }
+}
+
+void
+GMapPoly::gma_transform(const GRect & grect)
+{
+ int width=get_xmax()-get_xmin();
+ int height=get_ymax()-get_ymin();
+ int xmin=get_xmin(), ymin=get_ymin();
+ for(int i=0;i<points;i++)
+ {
+ xx[i]=grect.xmin+(xx[i]-xmin)*grect.width()/width;
+ yy[i]=grect.ymin+(yy[i]-ymin)*grect.height()/height;
+ }
+}
+
+char const * const
+GMapPoly::gma_check_object(void) const
+{
+ const char * str;
+ str=(border_type!=NO_BORDER &&
+ border_type!=SOLID_BORDER &&
+ border_type!=XOR_BORDER) ? error_poly_border:
+ ((hilite_color!=0xffffffff) ? error_poly_hilite:"");
+ return str;
+}
+
+GMapPoly::GMapPoly(const int * _xx, const int * _yy, int _points, bool _open) :
+ open(_open), points(_points)
+{
+ sides=points-(open!=0);
+
+ xx.resize(points-1); yy.resize(points-1);
+ for(int i=0;i<points;i++)
+ {
+ xx[i]=_xx[i]; yy[i]=_yy[i];
+ }
+ optimize_data();
+ char const * const res=check_data();
+ if (res[0])
+ G_THROW(res);
+}
+
+int
+GMapPoly::add_vertex(int x, int y)
+{
+ points++;
+ sides=points-(open!=0);
+
+ xx.resize(points-1); yy.resize(points-1);
+ xx[points-1] = x;
+ yy[points-1] = y;
+
+ return points;
+}
+
+void
+GMapPoly::close_poly()
+{
+ open = false;
+ sides=points;
+}
+
+GUTF8String
+GMapPoly::gma_print(void)
+{
+ static const GUTF8String space(' ');
+ GUTF8String res=GUTF8String('(')+POLY_TAG+space;
+ for(int i=0;i<points;i++)
+ {
+ GUTF8String buffer;
+ res+=buffer.format("%d %d ", xx[i], yy[i]);
+ }
+ res.setat(res.length()-1, ')');
+ res+=space;
+ return res;
+}
+
+/// Virtual function generating a list of defining coordinates
+void GMapPoly::get_coords( GList<int> & CoordList ) const
+{
+ for(int i = 0 ; i < points ; i++)
+ {
+ CoordList.append( xx[i] );
+ CoordList.append( yy[i] );
+ }
+}
+
+void
+GMapPoly::map(GRectMapper &mapper)
+{
+ get_bound_rect();
+ for(int i=0; i<points; i++)
+ {
+ mapper.map(xx[i], yy[i]);
+ }
+ clear_bounds();
+}
+
+void
+GMapPoly::unmap(GRectMapper &mapper)
+{
+ get_bound_rect();
+ for(int i=0; i<points; i++)
+ {
+ mapper.unmap(xx[i], yy[i]);
+ }
+ clear_bounds();
+}
+
+
+
+/****************************************************************************
+**************************** GMapOval definition ****************************
+****************************************************************************/
+
+void
+GMapOval::gma_resize(int new_width, int new_height)
+{
+ xmax=xmin+new_width;
+ ymax=ymin+new_height;
+ initialize();
+}
+
+void
+GMapOval::gma_transform(const GRect & grect)
+{
+ xmin=grect.xmin; ymin=grect.ymin;
+ xmax=grect.xmax; ymax=grect.ymax;
+ initialize();
+}
+
+bool
+GMapOval::gma_is_point_inside(const int x, const int y) const
+{
+ return
+ sqrt((double)((x-xf1)*(x-xf1)+(y-yf1)*(y-yf1))) +
+ sqrt((double)((x-xf2)*(x-xf2)+(y-yf2)*(y-yf2))) <= 2*rmax;
+}
+
+char const * const
+GMapOval::gma_check_object(void) const
+{
+ return (border_type!=NO_BORDER &&
+ border_type!=SOLID_BORDER &&
+ border_type!=XOR_BORDER)?error_oval_border:
+ ((hilite_color!=0xffffffff) ? error_oval_hilite:"");
+}
+
+void
+GMapOval::initialize(void)
+{
+ int xc=(xmax+xmin)/2;
+ int yc=(ymax+ymin)/2;
+ int f;
+
+ a=(xmax-xmin)/2;
+ b=(ymax-ymin)/2;
+ if (a>b)
+ {
+ rmin=b; rmax=a;
+ f=(int) sqrt((double)(rmax*rmax-rmin*rmin));
+ xf1=xc+f; xf2=xc-f; yf1=yf2=yc;
+ } else
+ {
+ rmin=a; rmax=b;
+ f=(int) sqrt((double)(rmax*rmax-rmin*rmin));
+ yf1=yc+f; yf2=yc-f; xf1=xf2=xc;
+ }
+}
+
+GMapOval::GMapOval(const GRect & rect) : xmin(rect.xmin), ymin(rect.ymin),
+ xmax(rect.xmax), ymax(rect.ymax)
+{
+ initialize();
+}
+
+GUTF8String
+GMapOval::gma_print(void)
+{
+ GUTF8String buffer;
+ return buffer.format("(%s %d %d %d %d) ",
+ OVAL_TAG, xmin, ymin, xmax-xmin, ymax-ymin);
+}
+
+void
+GMapOval::map(GRectMapper &mapper)
+{
+ get_bound_rect();
+ GRect rect;
+ rect.xmin = xmin;
+ rect.xmax = xmax;
+ rect.ymin = ymin;
+ rect.ymax = ymax;
+ mapper.map(rect);
+ xmin = rect.xmin;
+ ymin = rect.ymin;
+ xmax = rect.xmax;
+ ymax = rect.ymax;
+ clear_bounds();
+ initialize();
+}
+
+void
+GMapOval::unmap(GRectMapper &mapper)
+{
+ get_bound_rect();
+ GRect rect;
+ rect.xmin = xmin;
+ rect.xmax = xmax;
+ rect.ymin = ymin;
+ rect.ymax = ymax;
+ mapper.unmap(rect);
+ xmin = rect.xmin;
+ ymin = rect.ymin;
+ xmax = rect.xmax;
+ ymax = rect.ymax;
+ clear_bounds();
+ initialize();
+}
+
+GMapArea::GMapArea(void) : target("_self"), border_type(NO_BORDER),
+ border_always_visible(false), border_color(0xff), border_width(1),
+ hilite_color(0xffffffff), bounds_initialized(0) {}
+
+GMapRect::GMapRect(void) : xmin(0), ymin(0), xmax(0), ymax(0) {}
+
+GMapRect::GMapRect(const GRect & rect) : xmin(rect.xmin), ymin(rect.ymin),
+ xmax(rect.xmax), ymax(rect.ymax) {}
+
+GMapRect &
+GMapRect::operator=(const GRect & rect)
+{
+ xmin=rect.xmin;
+ xmax=rect.xmax;
+ ymin=rect.ymin;
+ ymax=rect.ymax;
+ return *this;
+}
+
+void
+GMapRect::gma_move(int dx, int dy)
+{
+ xmin+=dx;
+ xmax+=dx;
+ ymin+=dy;
+ ymax+=dy;
+}
+
+bool
+GMapRect::gma_is_point_inside(const int x, const int y) const
+{
+ return (x>=xmin)&&(x<xmax)&&(y>=ymin)&&(y<ymax);
+}
+
+GP<GMapArea>
+GMapRect::get_copy(void) const { return new GMapRect(*this); }
+
+GMapPoly::GMapPoly(void) : points(0), sides(0) {}
+
+void
+GMapPoly::move_vertex(int i, int x, int y)
+{
+ xx[i]=x; yy[i]=y;
+ clear_bounds();
+}
+
+GP<GMapArea>
+GMapPoly::get_copy(void) const { return new GMapPoly(*this); }
+
+GMapOval::GMapOval(void) : xmin(0), ymin(0), xmax(0), ymax(0) {}
+
+void
+GMapOval::gma_move(int dx, int dy)
+{
+ xmin+=dx; xmax+=dx; ymin+=dy; ymax+=dy;
+ xf1+=dx; yf1+=dy; xf2+=dx; yf2+=dy;
+}
+
+GP<GMapArea>
+GMapOval::get_copy(void) const
+{
+ return new GMapOval(*this);
+}
+
+static GUTF8String
+GMapArea2xmltag(const GMapArea &area,const GUTF8String &coords)
+{
+ GUTF8String retval("<AREA coords=\""
+ +coords+"\" shape=\""+area.get_shape_name()+"\" "
+ +"alt=\""+area.comment.toEscaped()+"\" ");
+ if(area.url.length())
+ {
+ retval+="href=\""+area.url+"\" ";
+ }else
+ {
+ retval+="nohref=\"nohref\" ";
+ }
+ if(area.target.length())
+ {
+ retval+="target=\""+area.target.toEscaped()+"\" ";
+ }
+ // highlight
+ if( area.hilite_color != GMapArea::NO_HILITE &&
+ area.hilite_color != GMapArea::XOR_HILITE )
+ {
+ retval+=GUTF8String().format( "highlight=\"#%06X\" ", area.hilite_color );
+ }
+ const char *b_type="none";
+ switch( area.border_type )
+ {
+ case GMapArea::NO_BORDER:
+ b_type = "none";
+ break;
+ case GMapArea::XOR_BORDER:
+ b_type = "xor";
+ break;
+ case GMapArea::SOLID_BORDER:
+ b_type = "solid";
+ break;
+ case GMapArea::SHADOW_IN_BORDER:
+ b_type = "shadowin";
+ break;
+ case GMapArea::SHADOW_OUT_BORDER:
+ b_type = "shadowout";
+ break;
+ case GMapArea::SHADOW_EIN_BORDER:
+ b_type = "etchedin";
+ break;
+ case GMapArea::SHADOW_EOUT_BORDER:
+ b_type = "etchedout";
+ break;
+ }
+ retval=retval+"bordertype=\""+b_type+"\" ";
+ if( area.border_type != GMapArea::NO_BORDER)
+ {
+ retval+="bordercolor=\""+GUTF8String().format("#%06X",area.border_color)
+ +"\" border=\""+GUTF8String(area.border_width)+"\" ";
+ }
+ if(area.border_always_visible )
+ retval=retval+"visible=\"visible\" ";
+ return retval+"/>\n";
+}
+
+GUTF8String
+GMapRect::get_xmltag(const int height) const
+{
+ return GMapArea2xmltag( *this, GUTF8String(get_xmin())
+ +","+GUTF8String(height-1-get_ymax())
+ +","+GUTF8String(get_xmax())
+ +","+GUTF8String(height-1-get_ymin()));
+#if 0
+ GUTF8String retval;
+ return retval;
+#endif
+}
+
+GUTF8String
+GMapOval::get_xmltag(const int height) const
+{
+ return GMapArea2xmltag( *this, GUTF8String(get_xmin())
+ +","+GUTF8String(height-1-get_ymax())
+ +","+GUTF8String(get_xmax())
+ +","+GUTF8String(height-1-get_ymin()));
+#if 0
+ GUTF8String retval;
+ return retval;
+#endif
+}
+
+GUTF8String
+GMapPoly::get_xmltag(const int height) const
+{
+ GList<int> CoordList;
+ get_coords(CoordList);
+ GPosition pos=CoordList;
+ GUTF8String retval;
+ if(pos)
+ {
+ GUTF8String coords(CoordList[pos]);
+ while(++pos)
+ {
+ coords+=","+GUTF8String(height-1-CoordList[pos]);
+ if(! ++pos)
+ break;
+ coords+=","+GUTF8String(CoordList[pos]);
+ }
+ retval=GMapArea2xmltag( *this, coords);
+ }
+ return retval;
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+
diff --git a/kviewshell/plugins/djvu/libdjvu/GMapAreas.h b/kviewshell/plugins/djvu/libdjvu/GMapAreas.h
new file mode 100644
index 00000000..251427ed
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GMapAreas.h
@@ -0,0 +1,565 @@
+//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: GMapAreas.h,v 1.8 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _GMAPAREAS_H
+#define _GMAPAREAS_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+#include "GSmartPointer.h"
+#include "GContainer.h"
+#include "GString.h"
+#include "GRect.h"
+#include "GURL.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+/** @name GMapAreas.h
+
+ Files #"GMapAreas.h"# and #"GMapAreas.cpp"# implement base objects
+ used by the plugin to display and manage hyperlinks and highlighted
+ areas inside a \Ref{DjVuImage} page.
+
+ The currently supported areas can be rectangular (\Ref{GMapRect}),
+ elliptical (\Ref{GMapOval}) and polygonal (\Ref{GMapPoly}). Every
+ map area besides the definition of its shape contains information
+ about display style and optional {\bf URL}, which it may refer to.
+ If this {\bf URL} is not empty then the map area will work like a
+ hyperlink.
+
+ The classes also implement some useful functions to ease geometry
+ manipulations
+
+ @memo Definition of base map area classes
+ @author Andrei Erofeev <eaf@geocities.com>
+ @version
+ #$Id: GMapAreas.h,v 1.8 2003/11/07 22:08:21 leonb Exp $# */
+//@{
+
+
+// ---------- GMAPAREA ---------
+
+/** This is the base object for all map areas. It defines some standard
+ interface to access the geometrical properties of the areas and
+ describes the area itsef:
+ \begin{itemize}
+ \item #url# If the optional #URL# is specified, the map area will
+ also work as a hyperlink meaning that if you click it with
+ your mouse pointer, the browser will be advised to load
+ the page referenced by the #URL#.
+ \item #target# Defines where the specified #URL# should be loaded
+ \item #comment# This is a string displayed in a status line or in
+ a popup window when the mouse pointer moves over the hyperlink
+ area
+ \item #border_type#, #border_color# and #border_width# describes
+ how the area border should be drawn
+ \item #area_color# describes how the area should be highlighted.
+ \end{itemize}
+
+ The map areas can be displayed using two different techniques, which
+ can be combined together:
+ \begin{itemize}
+ \item Visible border. The border of a map area can be drawn in several
+ different ways (like #XOR_BORDER# or #SHADOW_IN_BORDER#).
+ It can be made always visible, or appearing only when the
+ mouse pointer moves over the map area.
+ \item Highlighted contents. Contents of rectangular map areas can
+ also be highlighted with some given color.
+ \end{itemize}
+*/
+
+class GMapArea : public GPEnabled
+{
+protected:
+ GMapArea(void);
+public:
+// // Default creator.
+// static GP<GMapArea> create(void) {return new GMapArea();}
+
+ /// Virtual destructor.
+ virtual ~GMapArea();
+
+ static const char MAPAREA_TAG [];
+ static const char RECT_TAG [];
+ static const char POLY_TAG [];
+ static const char OVAL_TAG [];
+ static const char NO_BORDER_TAG [];
+ static const char XOR_BORDER_TAG [];
+ static const char SOLID_BORDER_TAG [];
+ static const char SHADOW_IN_BORDER_TAG [];
+ static const char SHADOW_OUT_BORDER_TAG [];
+ static const char SHADOW_EIN_BORDER_TAG [];
+ static const char SHADOW_EOUT_BORDER_TAG [];
+ static const char BORDER_AVIS_TAG [];
+ static const char HILITE_TAG [];
+ static const char URL_TAG [];
+ static const char TARGET_SELF [];
+
+ enum BorderType { NO_BORDER=0, XOR_BORDER=1, SOLID_BORDER=2,
+ SHADOW_IN_BORDER=3, SHADOW_OUT_BORDER=4,
+ SHADOW_EIN_BORDER=5, SHADOW_EOUT_BORDER=6 };
+
+ enum Special_Hilite_Color{ NO_HILITE=0xFFFFFFFF, XOR_HILITE=0xFF000000};
+
+ // Enumeration for reporting the type of map area. "MapUnknown" is reported
+ // for objects of type GMapArea (there shouldn't be any).
+ enum MapAreaType { UNKNOWN, RECT, OVAL, POLY };
+
+ /** Optional URL which this map area can be associated with.
+ If it's not empty then clicking this map area with the mouse
+ will make the browser load the HTML page referenced by
+ this #url#. Note: This may also be a relative URL, so the
+ GURL class is not used. */
+ GUTF8String url;
+ /** The target for the #URL#. Standard targets are:
+ \begin{itemize}
+ \item #_blank# - Load the link in a new blank window
+ \item #_self# - Load the link into the plugin window
+ \item #_top# - Load the link into the top-level frame
+ \end{itemize} */
+ GUTF8String target;
+ /** Comment (displayed in a status line or as a popup hint when
+ the mouse pointer moves over the map area */
+ GUTF8String comment;
+ /** Border type. Defines how the map area border should be drawn
+ \begin{itemize}
+ \item #NO_BORDER# - No border drawn
+ \item #XOR_BORDER# - The border is drawn using XOR method.
+ \item #SOLID_BORDER# - The border is drawn as a solid line
+ of a given color.
+ \item #SHADOW_IN_BORDER# - Supported for \Ref{GMapRect} only.
+ The map area area looks as if it was "pushed-in".
+ \item #SHADOW_OUT_BORDER# - The opposite of #SHADOW_OUT_BORDER#
+ \item #SHADOW_EIN_BORDER# - Also for \Ref{GMapRect} only.
+ Is translated as "shadow etched in"
+ \item #SHADOW_EOUT_BORDER# - The opposite of #SHADOW_EIN_BORDER#.
+ \end{itemize} */
+ BorderType border_type;
+ /** If #TRUE#, the border will be made always visible. Otherwise
+ it will be drawn when the mouse moves over the map area. */
+ bool border_always_visible;
+ /// Border color (when relevant) in #0x00RRGGBB# format
+ unsigned long int border_color;
+ /// Border width in pixels
+ int border_width;
+ /** Specified a color for highlighting the internal area of the map
+ area. Will work with rectangular map areas only. The color is
+ specified in \#00RRGGBB format. A special value of \#FFFFFFFF disables
+ highlighting and \#FF000000 is for XOR highlighting. */
+ unsigned long int hilite_color;
+
+ /// Returns 1 if the given point is inside the hyperlink area
+ bool is_point_inside(int x, int y) const;
+
+ /// Returns xmin of the bounding rectangle
+ int get_xmin(void) const;
+ /// Returns ymin of the bounding rectangle
+ int get_ymin(void) const;
+ /** Returns xmax of the bounding rectangle. In other words, if #X# is
+ a coordinate of the last point in the right direction, the
+ function will return #X+1# */
+ int get_xmax(void) const;
+ /** Returns xmax of the bounding rectangle. In other words, if #Y# is
+ a coordinate of the last point in the top direction, the
+ function will return #Y+1# */
+ int get_ymax(void) const;
+ /// Returns the hyperlink bounding rectangle
+ GRect get_bound_rect(void) const;
+ /** Moves the hyperlink along the given vector. Is used by the
+ hyperlinks editor. */
+ void move(int dx, int dy);
+ /** Resizes the hyperlink to fit new bounding rectangle while
+ keeping the (xmin, ymin) points at rest. */
+ void resize(int new_width, int new_height);
+ /** Transforms the hyperlink to be within the specified rectangle */
+ void transform(const GRect & grect);
+ /** Checks if the object is OK. Especially useful with \Ref{GMapPoly}
+ where edges may intersect. If there is a problem it returns a
+ string describing it. */
+ char const * const check_object(void);
+ /** Stores the contents of the hyperlink object in a lisp-like format
+ for saving into #ANTa# chunk (see \Ref{DjVuAnno}) */
+ GUTF8String print(void);
+
+ virtual GUTF8String get_xmltag(const int height) const=0;
+
+ /// Virtual function returning the shape type.
+ virtual MapAreaType const get_shape_type( void ) const { return UNKNOWN; };
+ /// Virtual function returning the shape name.
+ virtual char const * const get_shape_name(void) const=0;
+ /// Virtual function generating a copy of this object
+ virtual GP<GMapArea> get_copy(void) const=0;
+ /// Virtual function generating a list of defining coordinates
+ /// (default are the opposite corners of the enclosing rectangle)
+ virtual void get_coords( GList<int> & CoordList ) const;
+ /// Virtual function maps maparea from one area to another using mapper
+ virtual void map(GRectMapper &mapper)=0;
+ /// Virtual function unmaps maparea from one area to another using mapper
+ virtual void unmap(GRectMapper &mapper)=0;
+
+protected:
+ virtual int gma_get_xmin(void) const=0;
+ virtual int gma_get_ymin(void) const=0;
+ virtual int gma_get_xmax(void) const=0;
+ virtual int gma_get_ymax(void) const=0;
+ virtual void gma_move(int dx, int dy)=0;
+ virtual void gma_resize(int new_width, int new_height)=0;
+ virtual void gma_transform(const GRect & grect)=0;
+ virtual bool gma_is_point_inside(const int x, const int y) const=0;
+ virtual char const * const gma_check_object(void) const=0;
+ virtual GUTF8String gma_print(void)=0;
+
+ void clear_bounds(void) { bounds_initialized=0; }
+private:
+ int xmin, xmax, ymin, ymax;
+ bool bounds_initialized;
+
+ void initialize_bounds(void);
+};
+
+// ---------- GMAPRECT ---------
+
+/** Implements rectangular map areas. This is the only kind of map areas
+ supporting #SHADOW_IN_BORDER#, #SHADOW_OUT_BORDER#, #SHADOW_EIN_BORDER#
+ and #SHADOW_EOUT_BORDER# types of border and area highlighting. */
+
+class GMapRect: public GMapArea
+{
+protected:
+ GMapRect(void);
+ GMapRect(const GRect & rect);
+public:
+ /// Default creator.
+ static GP<GMapRect> create(void) {return new GMapRect();}
+ /// Create with the specified GRect.
+ static GP<GMapRect> create(const GRect &rect) {return new GMapRect(rect);}
+
+ virtual ~GMapRect();
+
+ /// Returns the width of the rectangle
+ int get_width(void) const { return xmax-xmin; }
+ /// Returns the height of the rectangle
+ int get_height(void) const { return ymax-ymin; }
+
+ /// Changes the #GMapRect#'s geometry
+ GMapRect & operator=(const GRect & rect);
+
+ /// Returns \Ref{GRect} describing the map area's rectangle
+ operator GRect(void);
+
+ virtual GUTF8String get_xmltag(const int height) const;
+ /// Returns MapRect
+ virtual MapAreaType const get_shape_type( void ) const { return RECT; };
+ /// Returns #"rect"#
+ virtual char const * const get_shape_name(void) const;
+ /// Returns a copy of the rectangle
+ virtual GP<GMapArea> get_copy(void) const;
+ /// Virtual function maps rectangle from one area to another using mapper
+ virtual void map(GRectMapper &mapper);
+ /// Virtual function unmaps rectangle from one area to another using mapper
+ virtual void unmap(GRectMapper &mapper);
+protected:
+ int xmin, ymin, xmax, ymax;
+ virtual int gma_get_xmin(void) const;
+ virtual int gma_get_ymin(void) const;
+ virtual int gma_get_xmax(void) const;
+ virtual int gma_get_ymax(void) const;
+ virtual void gma_move(int dx, int dy);
+ virtual void gma_resize(int new_width, int new_height);
+ virtual void gma_transform(const GRect & grect);
+ virtual bool gma_is_point_inside(const int x, const int y) const;
+ virtual char const * const gma_check_object(void) const;
+ virtual GUTF8String gma_print(void);
+};
+
+// ---------- GMAPPOLY ---------
+
+/** Implements polygonal map areas. The only supported types of border
+ are #NO_BORDER#, #XOR_BORDER# and #SOLID_BORDER#. Its contents can not
+ be highlighted either. It's worth mentioning here that despite its
+ name the polygon may be open, which basically makes it a broken line.
+ This very specific mode is used by the hyperlink editor when creating
+ the polygonal hyperlink. */
+
+class GMapPoly : public GMapArea
+{
+protected:
+ GMapPoly(void);
+ GMapPoly(const int * xx, const int * yy, int points, bool open=false);
+public:
+ /// Default creator
+ static GP<GMapPoly> create(void) {return new GMapPoly();}
+
+ /// Create from specified coordinates.
+ static GP<GMapPoly> create(
+ const int xx[], const int yy[], const int points, const bool open=false)
+ {return new GMapPoly(xx,yy,points,open);}
+
+ /// Virtual destructor.
+ virtual ~GMapPoly();
+
+ /// Returns 1 if side #side# crosses the specified rectangle #rect#.
+ bool does_side_cross_rect(const GRect & grect, int side);
+
+ /// Returns the number of vertices in the polygon
+ int get_points_num(void) const;
+
+ /// Returns the number sides in the polygon
+ int get_sides_num(void) const;
+
+ /// Returns x coordinate of vertex number #i#
+ int get_x(int i) const;
+
+ /// Returns y coordinate of vertex number #i#
+ int get_y(int i) const;
+
+ /// Moves vertex #i# to position (#x#, #y#)
+ void move_vertex(int i, int x, int y);
+
+ /// Adds a new vertex and returns number of vertices in the polygon
+ int add_vertex(int x, int y);
+
+ /// Closes the polygon if it is not closed
+ void close_poly();
+ /// Optimizes the polygon
+ void optimize_data(void);
+ /// Checks validity of the polygon
+ char const * const check_data(void);
+
+ virtual GUTF8String get_xmltag(const int height) const;
+ /// Returns MapPoly
+ virtual MapAreaType const get_shape_type( void ) const { return POLY; };
+ /// Returns #"poly"# all the time
+ virtual char const * const get_shape_name(void) const;
+ /// Returns a copy of the polygon
+ virtual GP<GMapArea> get_copy(void) const;
+ /// Virtual function generating a list of defining coordinates
+ void get_coords( GList<int> & CoordList ) const;
+ /// Virtual function maps polygon from one area to another using mapper
+ virtual void map(GRectMapper &mapper);
+ /// Virtual function unmaps polygon from one area to another using mapper
+ virtual void unmap(GRectMapper &mapper);
+protected:
+ virtual int gma_get_xmin(void) const;
+ virtual int gma_get_ymin(void) const;
+ virtual int gma_get_xmax(void) const;
+ virtual int gma_get_ymax(void) const;
+ virtual void gma_move(int dx, int dy);
+ virtual void gma_resize(int new_width, int new_height);
+ virtual void gma_transform(const GRect & grect);
+ virtual bool gma_is_point_inside(const int x, const int y) const;
+ virtual char const * const gma_check_object(void) const;
+ virtual GUTF8String gma_print(void);
+private:
+ bool open;
+ int points, sides;
+ GTArray<int> xx, yy;
+ static int sign(int x);
+ static bool is_projection_on_segment(int x, int y, int x1, int y1, int x2, int y2);
+ static bool do_segments_intersect(int x11, int y11, int x12, int y12,
+ int x21, int y21, int x22, int y22);
+ static bool are_segments_parallel(int x11, int y11, int x12, int y12,
+ int x21, int y21, int x22, int y22);
+};
+
+// ---------- GMAPOVAL ---------
+
+/** Implements elliptical map areas. The only supported types of border
+ are #NO_BORDER#, #XOR_BORDER# and #SOLID_BORDER#. Its contents can not
+ be highlighted either. */
+
+class GMapOval: public GMapArea
+{
+protected:
+ GMapOval(void);
+ GMapOval(const GRect & rect);
+public:
+ /// Default creator.
+ static GP<GMapOval> create(void) {return new GMapOval();}
+
+ /// Create from the specified GRect.
+ static GP<GMapOval> create(const GRect &rect) {return new GMapOval(rect);}
+
+ /// Virtual destructor.
+ virtual ~GMapOval();
+
+ /// Returns (xmax-xmin)/2
+ int get_a(void) const;
+ /// Returns (ymax-ymin)/2
+ int get_b(void) const;
+ /// Returns the lesser of \Ref{get_a}() and \Ref{get_b}()
+ int get_rmin(void) const;
+ /// Returns the greater of \Ref{get_a}() and \Ref{get_b}()
+ int get_rmax(void) const;
+
+ virtual GUTF8String get_xmltag(const int height) const;
+ /// Returns MapOval
+ virtual MapAreaType const get_shape_type( void ) const { return OVAL; };
+ /// Returns #"oval"#
+ virtual char const * const get_shape_name(void) const;
+ /// Returns a copy of the oval
+ virtual GP<GMapArea> get_copy(void) const;
+ /// Virtual function maps oval from one area to another using mapper
+ virtual void map(GRectMapper &mapper);
+ /// Virtual function unmaps oval from one area to another using mapper
+ virtual void unmap(GRectMapper &mapper);
+protected:
+ virtual int gma_get_xmin(void) const;
+ virtual int gma_get_ymin(void) const;
+ virtual int gma_get_xmax(void) const;
+ virtual int gma_get_ymax(void) const;
+ virtual void gma_move(int dx, int dy);
+ virtual void gma_resize(int new_width, int new_height);
+ virtual void gma_transform(const GRect & grect);
+ virtual bool gma_is_point_inside(const int x, const int y) const;
+ virtual char const * const gma_check_object(void) const;
+ virtual GUTF8String gma_print(void);
+private:
+ int rmax, rmin;
+ int a, b;
+ int xf1, yf1, xf2, yf2;
+ int xmin, ymin, xmax, ymax;
+
+ void initialize(void);
+};
+
+inline
+GMapRect::operator GRect(void)
+{
+ return GRect(xmin, ymin, xmax-xmin, ymax-ymin);
+}
+
+inline int
+GMapRect::gma_get_xmin(void) const { return xmin; }
+
+inline int
+GMapRect::gma_get_ymin(void) const { return ymin; }
+
+inline int
+GMapRect::gma_get_xmax(void) const { return xmax; }
+
+inline int
+GMapRect::gma_get_ymax(void) const { return ymax; }
+
+inline char const * const
+GMapRect::gma_check_object(void) const{ return ""; }
+
+inline char const * const
+GMapRect::get_shape_name(void) const { return RECT_TAG; }
+
+inline int
+GMapPoly::get_points_num(void) const { return points; }
+
+inline int
+GMapPoly::get_sides_num(void) const { return sides; }
+
+inline int
+GMapPoly::get_x(int i) const { return xx[i]; }
+
+inline int
+GMapPoly::get_y(int i) const { return yy[i]; }
+
+inline char const * const
+GMapPoly::get_shape_name(void) const { return POLY_TAG; }
+
+inline int
+GMapOval::get_a(void) const { return a; }
+
+inline int
+GMapOval::get_b(void) const { return b; }
+
+inline int
+GMapOval::get_rmin(void) const { return rmin; }
+
+inline int
+GMapOval::get_rmax(void) const { return rmax; }
+
+inline int
+GMapOval::gma_get_xmin(void) const { return xmin; }
+
+inline int
+GMapOval::gma_get_ymin(void) const { return ymin; }
+
+inline int
+GMapOval::gma_get_xmax(void) const { return xmax; }
+
+inline int
+GMapOval::gma_get_ymax(void) const { return ymax; }
+
+inline char const * const
+GMapOval::get_shape_name(void) const { return OVAL_TAG; }
+
+//@}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/GOS.cpp b/kviewshell/plugins/djvu/libdjvu/GOS.cpp
new file mode 100644
index 00000000..35aa8997
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GOS.cpp
@@ -0,0 +1,370 @@
+//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: GOS.cpp,v 1.12 2005/04/27 16:34:13 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "GException.h"
+#include "GThreads.h"
+#include "GOS.h"
+#include "GURL.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>
+#include <string.h>
+
+#ifdef WIN32
+# include <atlbase.h>
+# include <windows.h>
+# include <direct.h>
+#endif
+
+#ifdef OS2
+# define INCL_DOS
+# include <os2.h>
+#endif
+
+#if defined(UNIX) || defined(OS2)
+# include <errno.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <sys/time.h>
+# include <fcntl.h>
+# include <pwd.h>
+# include <stdio.h>
+# include <unistd.h>
+#endif
+
+#ifdef macintosh
+# include <unix.h>
+# include <errno.h>
+# include <unistd.h>
+#endif
+
+// -- TRUE FALSE
+#undef TRUE
+#undef FALSE
+#define TRUE 1
+#define FALSE 0
+
+// -- MAXPATHLEN
+#ifndef MAXPATHLEN
+# ifdef _MAX_PATH
+# define MAXPATHLEN _MAX_PATH
+# else
+# define MAXPATHLEN 1024
+# endif
+#else
+# if ( MAXPATHLEN < 1024 )
+# undef MAXPATHLEN
+# define MAXPATHLEN 1024
+# endif
+#endif
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+#if defined(AUTOCONF) && !defined(HAVE_STRERROR)
+# define NEED_STRERROR
+#elif defined(sun) && !defined(__svr4__)
+# define NEED_STRERROR
+#elif defined(REIMPLEMENT_STRERROR)
+# define NEED_STRERROR
+#endif
+#ifdef NEED_STRERROR
+char *
+strerror(int errno)
+{
+ extern int sys_nerr;
+ extern char *sys_errlist[];
+ if (errno>0 && errno<sys_nerr)
+ return sys_errlist[errno];
+ return "unknown stdio error";
+}
+#endif
+
+
+static const char slash='/';
+static const char percent='%';
+static const char backslash='\\';
+static const char colon=':';
+static const char dot='.';
+static const char nillchar=0;
+
+
+// -----------------------------------------
+// Functions for dealing with filenames
+// -----------------------------------------
+
+static inline int
+finddirsep(const GUTF8String &fname)
+{
+#if defined(UNIX)
+ return fname.rsearch('/',0);
+#elif defined(WIN32) || defined(OS2)
+ return fname.rcontains("\\/",0);
+#elif defined(macintosh)
+ return fname.rcontains(":/",0);
+#else
+#error "Define something here for your operating system"
+#endif
+}
+
+
+// basename(filename[, suffix])
+// -- returns the last component of filename and removes suffix
+// when present. works like /bin/basename.
+GUTF8String
+GOS::basename(const GUTF8String &gfname, const char *suffix)
+{
+ if(!gfname.length())
+ return gfname;
+
+ const char *fname=gfname;
+#if defined(WIN32) || defined(OS2)
+ // Special cases
+ if (fname[1] == colon)
+ {
+ if(!fname[2])
+ {
+ return gfname;
+ }
+ if (!fname[3] && (fname[2]== slash || fname[2]== backslash))
+ {
+ char string_buffer[4];
+ string_buffer[0] = fname[0];
+ string_buffer[1] = colon;
+ string_buffer[2] = backslash;
+ string_buffer[3] = 0;
+ return string_buffer;
+ }
+ }
+#endif
+
+
+ // Allocate buffer
+ GUTF8String retval(gfname,finddirsep(gfname)+1,(unsigned int)(-1));
+ fname=retval;
+
+ // Process suffix
+ if (suffix)
+ {
+ if (suffix[0]== dot )
+ suffix ++;
+ if (suffix[0])
+ {
+ const GUTF8String gsuffix(suffix);
+ const int sl = gsuffix.length();
+ const char *s = fname + strlen(fname);
+ if (s > fname + sl)
+ {
+ s = s - (sl + 1);
+ if(*s == dot && (GUTF8String(s+1).downcase() == gsuffix.downcase()))
+ {
+ retval.setat((int)((size_t)s-(size_t)fname),0);
+ }
+ }
+ }
+ }
+ return retval;
+}
+
+
+
+// errmsg --
+// -- A small helper function returning a
+// stdio error message in a static buffer.
+
+static GNativeString
+errmsg()
+{
+ GNativeString buffer;
+ const char *errname = strerror(errno);
+ buffer.format("%s (errno = %d)", errname, errno);
+ return buffer;
+}
+
+
+
+// -----------------------------------------
+// Functions for measuring time
+// -----------------------------------------
+
+// ticks() --
+// -- returns the number of milliseconds elapsed since
+// a system dependent date.
+unsigned long
+GOS::ticks()
+{
+#if defined(UNIX)
+ struct timeval tv;
+ if (gettimeofday(&tv, NULL) < 0)
+ G_THROW(errmsg());
+ return (unsigned long)( ((tv.tv_sec & 0xfffff)*1000)
+ + (tv.tv_usec/1000) );
+#elif defined(WIN32)
+ DWORD clk = GetTickCount();
+ return (unsigned long)clk;
+#elif defined(OS2)
+ ULONG clk = 0;
+ DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, (PVOID)&clk, sizeof(ULONG));
+ return clk;
+#elif defined(macintosh)
+ return (unsigned long)((double)TickCount()*16.66);
+#else
+# error "Define something here for your operating system"
+#endif
+}
+
+// sleep(int milliseconds) --
+// -- sleeps during the specified time (in milliseconds)
+void
+GOS::sleep(int milliseconds)
+{
+#if defined(UNIX)
+ struct timeval tv;
+ tv.tv_sec = milliseconds / 1000;
+ tv.tv_usec = (milliseconds - (tv.tv_sec * 1000)) * 1000;
+# if defined(THREADMODEL) && (THREADMODEL==COTHREADS)
+ GThread::select(0, NULL, NULL, NULL, &tv);
+# else
+ select(0, NULL, NULL, NULL, &tv);
+# endif
+#elif defined(WIN32)
+ Sleep(milliseconds);
+#elif defined(OS2)
+ DosSleep(milliseconds);
+#elif defined(macintosh)
+ unsigned long tick = ticks(), now;
+ while (1) {
+ now = ticks();
+ if ((tick+milliseconds) < now)
+ break;
+ GThread::yield();
+ }
+#endif
+}
+
+
+// -----------------------------------------
+// Testing
+// -----------------------------------------
+
+// cwd([dirname])
+// -- changes directory to dirname (when specified).
+// returns the full path name of the current directory.
+GUTF8String
+GOS::cwd(const GUTF8String &dirname)
+{
+#if defined(UNIX) || defined(macintosh) || defined(OS2)
+ if (dirname.length() && chdir(dirname.getUTF82Native())==-1)//MBCS cvt
+ G_THROW(errmsg());
+ char *string_buffer;
+ GPBuffer<char> gstring_buffer(string_buffer,MAXPATHLEN+1);
+ char *result = getcwd(string_buffer,MAXPATHLEN);
+ if (!result)
+ G_THROW(errmsg());
+ return GNativeString(result).getNative2UTF8();//MBCS cvt
+#elif defined (WIN32)
+ char drv[2];
+ if (dirname.length() && _chdir(dirname.getUTF82Native())==-1)//MBCS cvt
+ G_THROW(errmsg());
+ drv[0]= dot ; drv[1]=0;
+ char *string_buffer;
+ GPBuffer<char> gstring_buffer(string_buffer,MAXPATHLEN+1);
+ char *result = getcwd(string_buffer,MAXPATHLEN);
+ GetFullPathName(drv, MAXPATHLEN, string_buffer, &result);
+ return GNativeString(string_buffer).getNative2UTF8();//MBCS cvt
+#else
+#error "Define something here for your operating system"
+#endif
+}
+
+GUTF8String
+GOS::getenv(const GUTF8String &name)
+{
+ GUTF8String retval;
+ if(name.length())
+ {
+ const char *env=::getenv(name.getUTF82Native());
+ if(env)
+ {
+ retval=GNativeString(env);
+ }
+ }
+ return retval;
+}
+
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+
diff --git a/kviewshell/plugins/djvu/libdjvu/GOS.h b/kviewshell/plugins/djvu/libdjvu/GOS.h
new file mode 100644
index 00000000..3e57fb40
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GOS.h
@@ -0,0 +1,161 @@
+//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: GOS.h,v 1.8 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _GOS_H_
+#define _GOS_H_
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+/** @name GOS.h
+ Files #"GOS.h"# and #"GOS.cpp"# implement operating system
+ dependent functions with a unified interface. All these functions
+ are implemented as static member of class \Ref{GOS}.
+ Functions are provided for testing the presence of a file or a directory
+ (\Ref{GOS::is_file}, \Ref{GOS::is_dir}), for manipulating file and directory names
+ (\Ref{GOS::dirname}, \Ref{GOS::basename}, \Ref{GOS::expand_name},
+ for obtaining and changing the current directory (\Ref{GOS::cwd}),
+ for converting between file names and urls (\Ref{GOS::filename_to_url},
+ \Ref{GOS::url_to_filename}), and for counting time (\Ref{GOS::ticks},
+ \Ref{GOS::sleep}).
+
+ @memo
+ Operating System dependent functions.
+ @author
+ L\'eon Bottou <leonb@research.att.com> -- Initial implementation
+ @version
+ #$Id: GOS.h,v 1.8 2003/11/07 22:08:21 leonb Exp $#
+*/
+//@{
+
+#include "DjVuGlobal.h"
+#include "GString.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+class GURL;
+
+/** Operating System dependent functions. */
+class GOS
+{
+ public:
+ // -----------------------------------------
+ // Functions for dealing with filenames
+ // -----------------------------------------
+
+ /** Returns the last component of file name #filename#. If the filename
+ suffix matches argument #suffix#, the filename suffix is removed. This
+ function works like the unix command #/bin/basename#, but also supports
+ the naming conventions of other operating systems. */
+ static GUTF8String basename(const GUTF8String &filename, const char *suffix=0);
+
+ /** Sets and returns the current working directory.
+ When argument #dirname# is specified, the current directory is changed
+ to #dirname#. This function always returns the fully qualified name
+ of the current directory. */
+ static GUTF8String cwd(const GUTF8String &dirname=GUTF8String());
+
+ // -----------------------------------------
+ // Functions for measuring time
+ // -----------------------------------------
+
+ /** Returns a number of elapsed milliseconds. This number counts elapsed
+ milliseconds since a operating system dependent date. This function is
+ useful for timing code. */
+ static unsigned long ticks();
+
+ /** Sleeps during the specified time expressed in milliseconds.
+ Other threads can run while the calling thread sleeps. */
+ static void sleep(int milliseconds);
+
+ /// Read the named variable from the environment, and converts it to UTF8.
+ static GUTF8String getenv(const GUTF8String &name);
+
+#if 0
+ // -------------------------------------------
+ // Functions for converting filenames and urls
+ // -------------------------------------------
+ /** Encodes all reserved characters, so that the #filename# can be
+ used inside a URL. Every reserved character is encoded using escape
+ sequence in the form of #%XX#. The legal characters are alphanumeric and
+ #$-_.+!*'(),:#.
+ Use \Ref{decode_reserved}() to convert the URL back to the filename. */
+// static GString encode_reserved(const char * filename);
+ static GString encode_mbcs_reserved(const char * filename);/*MBCS*/
+#endif
+
+};
+
+
+//@}
+// ------------
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/GPixmap.cpp b/kviewshell/plugins/djvu/libdjvu/GPixmap.cpp
new file mode 100644
index 00000000..81c1dd71
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GPixmap.cpp
@@ -0,0 +1,1676 @@
+//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: GPixmap.cpp,v 1.12 2004/08/06 15:11:29 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+// -- Implements class PIXMAP
+// Author: Leon Bottou 07/1997
+
+
+
+#include "GPixmap.h"
+
+#include "GString.h"
+#include "GException.h"
+#include "ByteStream.h"
+#include "GRect.h"
+#include "GBitmap.h"
+#include "GThreads.h"
+#include "Arrays.h"
+#include "JPEGDecoder.h"
+#include <stdlib.h>
+#include <math.h>
+#include <assert.h>
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+
+//////////////////////////////////////////////////
+// ------- predefined colors
+//////////////////////////////////////////////////
+
+
+const GPixel GPixel::WHITE = { 255, 255, 255 };
+const GPixel GPixel::BLACK = { 0, 0, 0 };
+const GPixel GPixel::BLUE = { 255, 0, 0 };
+const GPixel GPixel::GREEN = { 0, 255, 0 };
+const GPixel GPixel::RED = { 0, 0, 255 };
+
+
+//////////////////////////////////////////////////
+// ----- utilities
+//////////////////////////////////////////////////
+
+
+static const GPixel *
+new_gray_ramp(int grays,GPixel *ramp)
+{
+ int color = 0xff0000;
+ int decrement = color / (grays-1);
+ for (int i=0; i<grays; i++)
+ {
+ int level = color >> 16;
+ ramp[i].b = level;
+ ramp[i].g = level;
+ ramp[i].r = level;
+ color -= decrement;
+ }
+ return ramp;
+}
+
+
+static inline int
+mini(int x, int y)
+{
+ return (x < y ? x : y);
+}
+
+
+static inline int
+maxi(int x, int y)
+{
+ return (x > y ? x : y);
+}
+
+
+static inline void
+euclidian_ratio(int a, int b, int &q, int &r)
+{
+ q = a / b;
+ r = a - b*q;
+ if (r < 0)
+ {
+ q -= 1;
+ r += b;
+ }
+}
+
+
+//////////////////////////////////////////////////
+// global lock used by some rare operations
+//////////////////////////////////////////////////
+
+static GMonitor &pixmap_monitor() {
+ static GMonitor xpixmap_monitor;
+ return xpixmap_monitor;
+}
+
+
+//////////////////////////////////////////////////
+// constructors and destructors
+//////////////////////////////////////////////////
+
+
+GPixmap::~GPixmap()
+{
+ delete [] pixels_data;
+}
+
+void
+GPixmap::destroy(void)
+{
+ delete [] pixels_data;
+ pixels = pixels_data = 0;
+}
+
+GPixmap::GPixmap()
+: nrows(0), ncolumns(0), pixels(0), pixels_data(0)
+{
+}
+
+GPixmap::GPixmap(int nrows, int ncolumns, const GPixel *filler)
+: nrows(0), ncolumns(0), pixels(0), pixels_data(0)
+{
+ G_TRY
+ {
+ init(nrows, ncolumns, filler);
+ }
+ G_CATCH_ALL
+ {
+ destroy();
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+}
+
+GPixmap::GPixmap(ByteStream &bs)
+: nrows(0), ncolumns(0), pixels(0), pixels_data(0)
+{
+ G_TRY
+ {
+ init(bs);
+ }
+ G_CATCH_ALL
+ {
+ destroy();
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+}
+
+GPixmap::GPixmap(const GBitmap &ref)
+: nrows(0), ncolumns(0), pixels(0), pixels_data(0)
+{
+ G_TRY
+ {
+ init(ref, 0);
+ }
+ G_CATCH_ALL
+ {
+ destroy();
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+}
+
+GPixmap::GPixmap(const GBitmap &ref, const GRect &rect)
+: nrows(0), ncolumns(0), pixels(0), pixels_data(0)
+{
+ G_TRY
+ {
+ init(ref, rect, 0);
+ }
+ G_CATCH_ALL
+ {
+ destroy();
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+}
+
+GPixmap::GPixmap(const GPixmap &ref)
+: nrows(0), ncolumns(0), pixels(0), pixels_data(0)
+{
+ G_TRY
+ {
+ init(ref);
+ }
+ G_CATCH_ALL
+ {
+ destroy();
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+}
+
+GPixmap::GPixmap(const GPixmap &ref, const GRect &rect)
+: nrows(0), ncolumns(0), pixels(0), pixels_data(0)
+{
+ G_TRY
+ {
+ init(ref, rect);
+ }
+ G_CATCH_ALL
+ {
+ destroy();
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+}
+
+
+
+//////////////////////////////////////////////////
+// Initialization
+//////////////////////////////////////////////////
+
+
+void
+GPixmap::init(int arows, int acolumns, const GPixel *filler)
+{
+ destroy();
+ nrows = arows;
+ ncolumns = acolumns;
+ nrowsize = acolumns;
+ int npix = nrows * nrowsize;
+ if (npix > 0)
+ {
+ pixels = pixels_data = new GPixel[npix];
+ if (filler)
+ {
+ while (--npix>=0)
+ pixels_data[npix] = *filler;
+ }
+ }
+}
+
+
+void
+GPixmap::init(const GBitmap &ref, const GPixel *userramp)
+{
+ init(ref.rows(), ref.columns(), 0);
+ GPixel *xramp;
+ GPBuffer<GPixel> gxramp(xramp);
+ if (nrows>0 && ncolumns>0)
+ {
+ // Create pixel ramp
+ const GPixel *ramp = userramp;
+ if (!userramp)
+ {
+ gxramp.resize(256);
+ gxramp.clear();
+ ramp = new_gray_ramp(ref.get_grays(),xramp);
+ }
+ // Copy pixels
+ for (int y=0; y<nrows; y++)
+ {
+ GPixel *dst = (*this)[y];
+ const unsigned char *src = ref[y];
+ for (int x=0; x<ncolumns; x++)
+ dst[x] = ramp[ src[x] ];
+ }
+ // Free ramp
+// if (!userramp)
+// delete [] (GPixel*)ramp;
+ }
+}
+
+
+void
+GPixmap::init(const GBitmap &ref, const GRect &rect, const GPixel *userramp)
+{
+ init(rect.height(), rect.width(), 0);
+ // compute destination rectangle
+ GRect rect2(0, 0, ref.columns(), ref.rows() );
+ rect2.intersect(rect2, rect);
+ rect2.translate(-rect.xmin, -rect.ymin);
+ // copy bits
+ if (! rect2.isempty())
+ {
+ GPixel *xramp;
+ GPBuffer<GPixel> gxramp(xramp);
+ // allocate ramp
+ const GPixel *ramp = userramp;
+ if (!userramp)
+ {
+ gxramp.resize(256);
+ gxramp.clear();
+ ramp = new_gray_ramp(ref.get_grays(),xramp);
+ }
+ // copy pixels
+ for (int y=rect2.ymin; y<rect2.ymax; y++)
+ {
+ GPixel *dst = (*this)[y];
+ const unsigned char *src = ref[y+rect.ymin] + rect.xmin;
+ for (int x=rect2.xmin; x<rect2.xmax; x++)
+ dst[x] = ramp[ src[x] ];
+ }
+ // free ramp
+// if (!userramp)
+// delete [] (GPixel*) ramp;
+ }
+}
+
+
+void
+GPixmap::init(const GPixmap &ref)
+{
+ init(ref.rows(), ref.columns(), 0);
+ if (nrows>0 && ncolumns>0)
+ {
+ for (int y=0; y<nrows; y++)
+ {
+ GPixel *dst = (*this)[y];
+ const GPixel *src = ref[y];
+ for (int x=0; x<ncolumns; x++)
+ dst[x] = src[x];
+ }
+ }
+}
+
+
+void
+GPixmap::init(const GPixmap &ref, const GRect &rect)
+{
+ init(rect.height(), rect.width(), 0);
+ // compute destination rectangle
+ GRect rect2(0, 0, ref.columns(), ref.rows() );
+ rect2.intersect(rect2, rect);
+ rect2.translate(-rect.xmin, -rect.ymin);
+ // copy bits
+ if (! rect2.isempty())
+ {
+ for (int y=rect2.ymin; y<rect2.ymax; y++)
+ {
+ GPixel *dst = (*this)[y];
+ const GPixel *src = ref[y+rect.ymin] + rect.xmin;
+ for (int x=rect2.xmin; x<rect2.xmax; x++)
+ dst[x] = src[x];
+ }
+ }
+}
+
+
+void
+GPixmap::donate_data(GPixel *data, int w, int h)
+{
+ destroy();
+ nrows = h;
+ ncolumns = w;
+ nrowsize = w;
+ pixels_data=pixels=data;
+}
+
+
+GPixel *
+GPixmap::take_data(size_t &offset)
+{
+ GPixel *ret = pixels_data;
+ pixels_data = 0;
+ offset = 0;
+ return ret;
+}
+
+
+
+//////////////////////////////////////////////////
+// Save and load ppm files
+//////////////////////////////////////////////////
+
+
+static unsigned int
+read_integer(char &c, ByteStream &bs)
+{
+ unsigned int x = 0;
+ // eat blank before integer
+ while (c==' ' || c=='\t' || c=='\r' || c=='\n' || c=='#')
+ {
+ if (c=='#')
+ do { } while (bs.read(&c,1) && c!='\n' && c!='\r');
+ c = 0;
+ bs.read(&c, 1);
+ }
+ // check integer
+ if (c<'0' || c>'9')
+ G_THROW( ERR_MSG("GPixmap.no_int") );
+ // eat integer
+ while (c>='0' && c<='9')
+ {
+ x = x*10 + c - '0';
+ c = 0;
+ bs.read(&c, 1);
+ }
+ return x;
+}
+
+
+void
+GPixmap::init(ByteStream &bs)
+{
+ // Read header
+ int raw = 0;
+ char magic[2];
+ magic[0] = magic[1] = 0;
+ bs.readall((void*)magic, sizeof(magic));
+ if (magic[0]=='P' && magic[1]=='3')
+ {
+ raw = 0;
+ }else if (magic[0]=='P' && magic[1]=='6')
+ {
+ raw = 1;
+ }else
+ {
+#ifdef NEED_JPEG_DECODER
+ bs.seek(0L);
+ JPEGDecoder::decode(bs,*this);
+ return;
+#else // NEED_JPEG_DECODER
+
+ G_THROW( ERR_MSG("GPixmap.unk_PPM") );
+#endif // NEED_JPEG_DECODER
+ }
+ // Read image size
+ char lookahead = '\n';
+ int acolumns = read_integer(lookahead, bs);
+ int arows = read_integer(lookahead, bs);
+ int maxval = read_integer(lookahead, bs);
+ if (maxval > 255)
+ G_THROW("Cannot read PPM with depth greater than 24 bits.");
+ init(arows, acolumns, 0);
+ // Read image data
+ if (raw)
+ {
+ GTArray<unsigned char> line(ncolumns*3);
+ for (int y=nrows-1; y>=0; y--)
+ {
+ GPixel *p = (*this)[y];
+ unsigned char *rgb = &line[0];
+ if ( bs.readall((void*)rgb, ncolumns*3) < (size_t)(ncolumns*3))
+ G_THROW( ByteStream::EndOfFile );
+ for (int x=0; x<ncolumns; x+=1, rgb+=3)
+ {
+ p[x].r = rgb[0];
+ p[x].g = rgb[1];
+ p[x].b = rgb[2];
+ }
+ }
+ }
+ else
+ {
+ for (int y=nrows-1; y>=0; y--)
+ {
+ GPixel *p = (*this)[y];
+ for (int x=0; x<ncolumns; x++)
+ {
+ p[x].r = read_integer(lookahead, bs);
+ p[x].g = read_integer(lookahead, bs);
+ p[x].b = read_integer(lookahead, bs);
+ }
+ }
+ }
+ // Process small values of maxval
+ if (maxval>0 && maxval<255)
+ {
+ char table[256];
+ for (int i=0; i<256; i++)
+ table[i] = (i<maxval ? (255*i + maxval/2) / maxval : 255);
+ for (int y=0; y<nrows; y++)
+ {
+ GPixel *p = (*this)[y];
+ for (int x=0; x<ncolumns; x++)
+ {
+ p[x].r = table[p[x].r];
+ p[x].g = table[p[x].g];
+ p[x].b = table[p[x].b];
+ }
+ }
+ }
+}
+
+
+void
+GPixmap::save_ppm(ByteStream &bs, int raw) const
+{
+ GUTF8String head;
+ head.format("P%c\n%d %d\n255\n", (raw ? '6' : '3'), ncolumns, nrows);
+ bs.writall((void*)(const char *)head, head.length());
+ if (raw)
+ {
+ int rowsize = ncolumns+ncolumns+ncolumns;
+ GTArray<unsigned char> xrgb(rowsize);
+ for (int y=nrows-1; y>=0; y--)
+ {
+ const GPixel *p = (*this)[y];
+ unsigned char *d = xrgb;
+ for (int x=0; x<ncolumns; x++)
+ {
+ *d++ = p[x].r;
+ *d++ = p[x].g;
+ *d++ = p[x].b;
+ }
+ bs.writall((void*)(unsigned char*)xrgb, ncolumns * 3);
+ }
+ }
+ else
+ {
+ for (int y=nrows-1; y>=0; y--)
+ {
+ const GPixel *p = (*this)[y];
+ unsigned char eol='\n';
+ for (int x=0; x<ncolumns; )
+ {
+ head.format("%d %d %d ", p[x].r, p[x].g, p[x].b);
+ bs.writall((void*)(const char *)head, head.length());
+ x += 1;
+ if (x==ncolumns || (x&0x7)==0)
+ bs.write((void*)&eol, 1);
+ }
+ }
+ }
+}
+
+
+
+
+//////////////////////////////////////////////////
+// Color correction
+//////////////////////////////////////////////////
+
+
+static void
+color_correction_table(double gamma, unsigned char gtable[256] )
+{
+ // Check argument
+ if (gamma<0.1 || gamma>10.0)
+ G_THROW( ERR_MSG("GPixmap.bad_param") );
+ if (gamma<1.001 && gamma>0.999)
+ {
+ // Trivial correction
+ for (int i=0; i<256; i++)
+ gtable[i] = i;
+ }
+ else
+ {
+ // Must compute the correction
+ for (int i=0; i<256; i++)
+ {
+ double x = (double)(i)/255.0;
+#ifdef BEZIERGAMMA
+ double t = ( sqrt(1.0+(gamma*gamma-1.0)*x) - 1.0 ) / (gamma - 1.0);
+ x = ( (1.0 - gamma)*t + 2.0 * gamma ) * t / (gamma + 1.0);
+#else
+ x = pow(x, 1.0/gamma);
+#endif
+ gtable[i] = (int) floor(255.0 * x + 0.5);
+ }
+ // Make sure that min and max values are exactly black or white
+ gtable[0] = 0;
+ gtable[255] = 255;
+ }
+}
+
+static void
+color_correction_table_cache(double gamma, unsigned char gtable[256] )
+{
+ // Compute color correction table
+ if (gamma<1.001 && gamma>0.999)
+ {
+ color_correction_table(gamma, gtable);
+ }
+ else
+ {
+ static double lgamma = -1.0;
+ static unsigned char ctable[256];
+ GMonitorLock lock(&pixmap_monitor());
+ if (gamma != lgamma)
+ {
+ color_correction_table(gamma, ctable);
+ lgamma = gamma;
+ }
+ memcpy(gtable, ctable, 256*sizeof(unsigned char));
+ }
+}
+
+void
+GPixmap::color_correct(double gamma_correction)
+{
+ // Trivial corrections
+ if (gamma_correction>0.999 && gamma_correction<1.001)
+ return;
+ // Compute correction table
+ unsigned char gtable[256];
+ color_correction_table_cache(gamma_correction, gtable);
+ // Perform correction
+ for (int y=0; y<nrows; y++)
+ {
+ GPixel *pix = (*this)[y];
+ for (int x=0; x<ncolumns; x++, pix++)
+ {
+ pix->r = gtable[ pix->r ];
+ pix->g = gtable[ pix->g ];
+ pix->b = gtable[ pix->b ];
+ }
+ }
+}
+
+
+void
+GPixmap::color_correct(double gamma_correction, GPixel *pix, int npixels)
+{
+ // Trivial corrections
+ if (gamma_correction>0.999 && gamma_correction<1.001)
+ return;
+ // Compute correction table
+ unsigned char gtable[256];
+ color_correction_table_cache(gamma_correction, gtable);
+ // Perform correction
+ while (--npixels>=0)
+ {
+ pix->r = gtable[pix->r];
+ pix->g = gtable[pix->g];
+ pix->b = gtable[pix->b];
+ pix++;
+ }
+}
+
+
+
+//////////////////////////////////////////////////
+// Dithering
+//////////////////////////////////////////////////
+
+
+void
+GPixmap::ordered_666_dither(int xmin, int ymin)
+{
+ static unsigned char quantize[256+0x33+0x33];
+ static unsigned char *quant = quantize + 0x33;
+ static char dither_ok = 0;
+ static short dither[16][16] =
+ {
+ { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 },
+ { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
+ { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
+ { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
+ { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 },
+ { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
+ { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
+ { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
+ { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 },
+ { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
+ { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
+ { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
+ { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 },
+ { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
+ { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
+ { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
+ };
+ // Prepare tables
+ if (!dither_ok)
+ {
+ int i, j;
+ for (i=0; i<16; i++)
+ for (j=0; j<16; j++)
+ dither[i][j] = ((255 - 2*dither[i][j]) * 0x33) / 512;
+ j = -0x33;
+ for (i=0x19; i<256; i+=0x33)
+ while (j <= i)
+ quant[j++] = i-0x19;
+ assert(i-0x19 == 0xff);
+ while (j< 256+0x33)
+ quant[j++] = i-0x19;
+ dither_ok = 1;
+ }
+ // Go dithering
+ for (int y=0; y<nrows; y++)
+ {
+ GPixel *pix = (*this)[y];
+ for (int x=0; x<ncolumns; x++, pix++)
+ {
+ pix->r = quant[ pix->r + dither[(x+xmin+0)&0xf][(y+ymin+0)&0xf] ];
+ pix->g = quant[ pix->g + dither[(x+xmin+5)&0xf][(y+ymin+11)&0xf] ];
+ pix->b = quant[ pix->b + dither[(x+xmin+11)&0xf][(y+ymin+5)&0xf] ];
+ }
+ }
+}
+
+void
+GPixmap::ordered_32k_dither(int xmin, int ymin)
+{
+ static unsigned char quantize[256+8+8];
+ static unsigned char *quant = quantize + 8;
+ static char dither_ok = 0;
+ static short dither[16][16] =
+ {
+ { 0,192, 48,240, 12,204, 60,252, 3,195, 51,243, 15,207, 63,255 },
+ { 128, 64,176,112,140, 76,188,124,131, 67,179,115,143, 79,191,127 },
+ { 32,224, 16,208, 44,236, 28,220, 35,227, 19,211, 47,239, 31,223 },
+ { 160, 96,144, 80,172,108,156, 92,163, 99,147, 83,175,111,159, 95 },
+ { 8,200, 56,248, 4,196, 52,244, 11,203, 59,251, 7,199, 55,247 },
+ { 136, 72,184,120,132, 68,180,116,139, 75,187,123,135, 71,183,119 },
+ { 40,232, 24,216, 36,228, 20,212, 43,235, 27,219, 39,231, 23,215 },
+ { 168,104,152, 88,164,100,148, 84,171,107,155, 91,167,103,151, 87 },
+ { 2,194, 50,242, 14,206, 62,254, 1,193, 49,241, 13,205, 61,253 },
+ { 130, 66,178,114,142, 78,190,126,129, 65,177,113,141, 77,189,125 },
+ { 34,226, 18,210, 46,238, 30,222, 33,225, 17,209, 45,237, 29,221 },
+ { 162, 98,146, 82,174,110,158, 94,161, 97,145, 81,173,109,157, 93 },
+ { 10,202, 58,250, 6,198, 54,246, 9,201, 57,249, 5,197, 53,245 },
+ { 138, 74,186,122,134, 70,182,118,137, 73,185,121,133, 69,181,117 },
+ { 42,234, 26,218, 38,230, 22,214, 41,233, 25,217, 37,229, 21,213 },
+ { 170,106,154, 90,166,102,150, 86,169,105,153, 89,165,101,149, 85 }
+ };
+ // Prepare tables
+ if (!dither_ok)
+ {
+ int i, j;
+ for (i=0; i<16; i++)
+ for (j=0; j<16; j++)
+ dither[i][j] = ((255 - 2*dither[i][j]) * 8) / 512;
+ j = -8;
+ for (i=3; i<256; i+=8)
+ while (j <= i)
+ quant[j++] = i;
+ while (j<256+8)
+ quant[j++] = 0xff;
+ dither_ok = 1;
+ }
+ // Go dithering
+ for (int y=0; y<nrows; y++)
+ {
+ GPixel *pix = (*this)[y];
+ for (int x=0; x<ncolumns; x++, pix++)
+ {
+ pix->r = quant[ pix->r + dither[(x+xmin+0)&0xf][(y+ymin+0)&0xf] ];
+ pix->g = quant[ pix->g + dither[(x+xmin+5)&0xf][(y+ymin+11)&0xf] ];
+ pix->b = quant[ pix->b + dither[(x+xmin+11)&0xf][(y+ymin+5)&0xf] ];
+ }
+ }
+}
+
+
+//////////////////////////////////////////////////
+// Upsample Downsample
+//////////////////////////////////////////////////
+
+
+void
+GPixmap::downsample(const GPixmap *src, int factor, const GRect *pdr)
+{
+ // check arguments
+ GRect rect(0, 0, (src->columns()+factor-1)/factor, (src->rows()+factor-1)/factor);
+ if (pdr != 0)
+ {
+ if (pdr->xmin < rect.xmin ||
+ pdr->ymin < rect.ymin ||
+ pdr->xmax > rect.xmax ||
+ pdr->ymax > rect.ymax )
+ G_THROW( ERR_MSG("GPixmap.overflow1") );
+ rect = *pdr;
+ }
+
+ // precompute inverse map
+ static int invmap[256];
+ static int invmapok = 0;
+ if (! invmapok)
+ {
+ invmapok = 1;
+ for (int i=1; i<(int)(sizeof(invmap)/sizeof(int)); i++)
+ invmap[i] = 0x10000 / i;
+ }
+
+ // initialise pixmap
+ init(rect.height(), rect.width(), 0);
+
+ // determine starting and ending points in source rectangle
+ int sy = rect.ymin * factor;
+ int sxz = rect.xmin * factor;
+
+
+ // loop over source rows
+ const GPixel *sptr = (*src)[sy];
+ GPixel *dptr = (*this)[0];
+ for (int y=0; y<nrows; y++)
+ {
+ int sx = sxz;
+ // loop over source columns
+ for (int x=0; x<ncolumns; x++)
+ {
+ int r=0, g=0, b=0, s=0;
+ // compute average bounds
+ const GPixel *ksptr = sptr;
+ int lsy = sy + factor;
+ if (lsy > (int)src->rows())
+ lsy = (int)src->rows();
+ int lsx = sx + factor;
+ if (lsx > (int)src->columns())
+ lsx = (int)src->columns();
+ // compute average
+ for (int rsy=sy; rsy<lsy; rsy++)
+ {
+ for (int rsx = sx; rsx<lsx; rsx++)
+ {
+ r += ksptr[rsx].r;
+ g += ksptr[rsx].g;
+ b += ksptr[rsx].b;
+ s += 1;
+ }
+ ksptr += src->rowsize();
+ }
+ // set pixel color
+ if (s >= (int)(sizeof(invmap)/sizeof(int)))
+ {
+ dptr[x].r = r / s;
+ dptr[x].g = g / s;
+ dptr[x].b = b / s;
+ }
+ else
+ {
+ dptr[x].r = (r*invmap[s] + 0x8000) >> 16;
+ dptr[x].g = (g*invmap[s] + 0x8000) >> 16;
+ dptr[x].b = (b*invmap[s] + 0x8000) >> 16;
+ }
+ // next column
+ sx = sx + factor;
+ }
+ // next row
+ sy = sy + factor;
+ sptr = sptr + factor * src->rowsize();
+ dptr = dptr + rowsize();
+ }
+}
+
+void
+GPixmap::upsample(const GPixmap *src, int factor, const GRect *pdr)
+{
+ // check arguments
+ GRect rect(0, 0, src->columns()*factor, src->rows()*factor);
+ if (pdr != 0)
+ {
+ if (pdr->xmin < rect.xmin ||
+ pdr->ymin < rect.ymin ||
+ pdr->xmax > rect.xmax ||
+ pdr->ymax > rect.ymax )
+ G_THROW( ERR_MSG("GPixmap.overflow2") );
+ rect = *pdr;
+ }
+ // initialise pixmap
+ init(rect.height(), rect.width(), 0);
+ // compute starting point in source rectangle
+ int sy, sy1, sxz, sx1z;
+ euclidian_ratio(rect.ymin, factor, sy, sy1);
+ euclidian_ratio(rect.xmin, factor, sxz, sx1z);
+ // loop over rows
+ const GPixel *sptr = (*src)[sy];
+ GPixel *dptr = (*this)[0];
+ for (int y=0; y<nrows; y++)
+ {
+ // loop over columns
+ int sx = sxz;
+ int sx1 = sx1z;
+ for (int x=0; x<ncolumns; x++)
+ {
+ dptr[x] = sptr[sx];
+ // next column
+ if (++sx1 >= factor)
+ {
+ sx1 = 0;
+ sx += 1;
+ }
+ }
+ // next row
+ dptr += rowsize();
+ if (++sy1 >= factor)
+ {
+ sy1 = 0;
+ sptr += src->rowsize();
+ }
+ }
+}
+
+
+static inline void
+downsample_4x4_to_3x3 (const GPixel *s, int sadd, GPixel *d, int dadd)
+{
+ const GPixel *x = s;
+ const GPixel *y = x + sadd;
+ d[0].b = ( 11*x[0].b + 2*(x[1].b + y[0].b ) + y[1].b + 8) >> 4;
+ d[0].g = ( 11*x[0].g + 2*(x[1].g + y[0].g ) + y[1].g + 8) >> 4;
+ d[0].r = ( 11*x[0].r + 2*(x[1].r + y[0].r ) + y[1].r + 8) >> 4;
+ d[1].b = ( 7*(x[1].b + x[2].b) + y[1].b + y[2].b + 8 ) >> 4;
+ d[1].g = ( 7*(x[1].g + x[2].g) + y[1].g + y[2].g + 8 ) >> 4;
+ d[1].r = ( 7*(x[1].r + x[2].r) + y[1].r + y[2].r + 8 ) >> 4;
+ d[2].b = ( 11*x[3].b + 2*(x[2].b + y[3].b ) + y[2].b + 8) >> 4;
+ d[2].g = ( 11*x[3].g + 2*(x[2].g + y[3].g ) + y[2].g + 8) >> 4;
+ d[2].r = ( 11*x[3].r + 2*(x[2].r + y[3].r ) + y[2].r + 8) >> 4;
+ d = d + dadd;
+ x = x + sadd + sadd;
+ d[0].b = ( 7*(x[0].b + y[0].b) + x[1].b + y[1].b + 8 ) >> 4;
+ d[0].g = ( 7*(x[0].g + y[0].g) + x[1].g + y[1].g + 8 ) >> 4;
+ d[0].r = ( 7*(x[0].r + y[0].r) + x[1].r + y[1].r + 8 ) >> 4;
+ d[1].b = ( x[2].b + y[2].b + x[1].b + y[1].b + 2 ) >> 2;
+ d[1].g = ( x[2].g + y[2].g + x[1].g + y[1].g + 2 ) >> 2;
+ d[1].r = ( x[2].r + y[2].r + x[1].r + y[1].r + 2 ) >> 2;
+ d[2].b = ( 7*(x[3].b + y[3].b) + x[2].b + y[2].b + 8 ) >> 4;
+ d[2].g = ( 7*(x[3].g + y[3].g) + x[2].g + y[2].g + 8 ) >> 4;
+ d[2].r = ( 7*(x[3].r + y[3].r) + x[2].r + y[2].r + 8 ) >> 4;
+ d = d + dadd;
+ y = y + sadd + sadd;
+ d[0].b = ( 11*y[0].b + 2*(y[1].b + x[0].b ) + x[1].b + 8) >> 4;
+ d[0].g = ( 11*y[0].g + 2*(y[1].g + x[0].g ) + x[1].g + 8) >> 4;
+ d[0].r = ( 11*y[0].r + 2*(y[1].r + x[0].r ) + x[1].r + 8) >> 4;
+ d[1].b = ( 7*(y[1].b + y[2].b) + x[1].b + x[2].b + 8 ) >> 4;
+ d[1].g = ( 7*(y[1].g + y[2].g) + x[1].g + x[2].g + 8 ) >> 4;
+ d[1].r = ( 7*(y[1].r + y[2].r) + x[1].r + x[2].r + 8 ) >> 4;
+ d[2].b = ( 11*y[3].b + 2*(y[2].b + x[3].b ) + x[2].b + 8) >> 4;
+ d[2].g = ( 11*y[3].g + 2*(y[2].g + x[3].g ) + x[2].g + 8) >> 4;
+ d[2].r = ( 11*y[3].r + 2*(y[2].r + x[3].r ) + x[2].r + 8) >> 4;
+}
+
+
+static inline void
+upsample_2x2_to_3x3 (const GPixel *s, int sadd, GPixel *d, int dadd)
+{
+ const GPixel *x = s;
+ const GPixel *y = x + sadd;
+ d[0] = x[0];
+ d[1].b = (x[0].b + x[1].b + 1) >> 1;
+ d[1].g = (x[0].g + x[1].g + 1) >> 1;
+ d[1].r = (x[0].r + x[1].r + 1) >> 1;
+ d[2] = x[1];
+ d = d + dadd;
+ d[0].b = (x[0].b + y[0].b + 1) >> 1;
+ d[0].g = (x[0].g + y[0].g + 1) >> 1;
+ d[0].r = (x[0].r + y[0].r + 1) >> 1;
+ d[1].b = (x[0].b + y[0].b + x[1].b + y[1].b + 2) >> 2;
+ d[1].g = (x[0].g + y[0].g + x[1].g + y[1].g + 2) >> 2;
+ d[1].r = (x[0].r + y[0].r + x[1].r + y[1].r + 2) >> 2;
+ d[2].b = (x[1].b + y[1].b + 1) >> 1;
+ d[2].g = (x[1].g + y[1].g + 1) >> 1;
+ d[2].r = (x[1].r + y[1].r + 1) >> 1;
+ d = d + dadd;
+ d[0] = y[0];
+ d[1].b = (y[0].b + y[1].b + 1) >> 1;
+ d[1].g = (y[0].g + y[1].g + 1) >> 1;
+ d[1].r = (y[0].r + y[1].r + 1) >> 1;
+ d[2] = y[1];
+}
+
+
+static inline void
+copy_to_partial(int w, int h,
+ const GPixel *s, int sadd,
+ GPixel *d, int dadd, int xmin, int xmax, int ymin, int ymax)
+{
+ int y = 0;
+ while (y<ymin && y<h)
+ {
+ y += 1;
+ s += sadd;
+ d += dadd;
+ }
+ while (y<ymax && y<h)
+ {
+ int x = (xmin>0 ? xmin : 0);
+ while (x<w && x<xmax)
+ {
+ d[x] = s[x];
+ x++;
+ }
+ y += 1;
+ s += sadd;
+ d += dadd;
+ }
+}
+
+
+static inline void
+copy_line(const GPixel *s, int smin, int smax,
+ GPixel *d, int dmin, int dmax)
+{
+ int x = dmin;
+ while (x < smin)
+ {
+ d[x] = s[smin];
+ x++;
+ }
+ while (x < dmax && x < smax)
+ {
+ d[x] = s[x];
+ x++;
+ }
+ while (x < dmax)
+ {
+ d[x] = s[smax];
+ x++;
+ }
+}
+
+
+static inline void
+copy_from_partial(int w, int h,
+ const GPixel *s, int sadd, int xmin, int xmax, int ymin, int ymax,
+ GPixel *d, int dadd)
+{
+ int y = 0;
+ s += (ymin>0 ? sadd * ymin : 0);
+ while (y<ymin && y<h)
+ {
+ copy_line(s, xmin, xmax, d, 0, w);
+ y += 1;
+ d += dadd;
+ }
+ while (y<ymax && y<h)
+ {
+ copy_line(s, xmin, xmax, d, 0, w);
+ y += 1;
+ s += sadd;
+ d += dadd;
+ }
+ s -= sadd;
+ while (y < h)
+ {
+ copy_line(s, xmin, xmax, d, 0, w);
+ y += 1;
+ d += dadd;
+ }
+}
+
+
+
+
+
+void
+GPixmap::downsample43(const GPixmap *src, const GRect *pdr)
+{
+ // check arguments
+ int srcwidth = src->columns();
+ int srcheight = src->rows();
+ int destwidth = (srcwidth * 3 + 3 ) / 4;
+ int destheight = (srcheight * 3 + 3) / 4;
+ GRect rect(0, 0, destwidth, destheight);
+ if (pdr != 0)
+ {
+ if (pdr->xmin < rect.xmin ||
+ pdr->ymin < rect.ymin ||
+ pdr->xmax > rect.xmax ||
+ pdr->ymax > rect.ymax )
+ G_THROW( ERR_MSG("GPixmap.overflow3") );
+ rect = *pdr;
+ destwidth = rect.width();
+ destheight = rect.height();
+ }
+ // initialize pixmap
+ init(destheight, destwidth, 0);
+
+ // compute bounds
+ int dxz, dy; // location of bottomleft block in destination image
+ int sxz, sy; // location of bottomleft block in source image
+ euclidian_ratio(rect.ymin, 3, sy, dy);
+ euclidian_ratio(rect.xmin, 3, sxz, dxz);
+ sxz = 4 * sxz;
+ sy = 4 * sy;
+ dxz = - dxz;
+ dy = - dy;
+
+ // prepare variables
+ int sadd = src->rowsize();
+ int dadd = this->rowsize();
+ const GPixel *sptr = (*src)[0] + sy * sadd;
+ GPixel *dptr = (*this)[0] + dy * dadd;
+ int s4add = 4 * sadd;
+ int d3add = 3 * dadd;
+
+ // iterate over row blocks
+ while (dy < destheight)
+ {
+ int sx = sxz;
+ int dx = dxz;
+ // iterate over column blocks
+ while (dx < destwidth)
+ {
+ GPixel xin[16], xout[9];
+
+ if (dx>=0 && dy>=0 && dx+3<=destwidth && dy+3<=destheight)
+ {
+ if (sx+4<=srcwidth && sy+4<=srcheight)
+ {
+ downsample_4x4_to_3x3(sptr+sx, sadd, dptr+dx, dadd);
+ }
+ else
+ {
+ copy_from_partial(4,4, sptr+sx,sadd,-sx,srcwidth-sx,-sy,srcheight-sy, xin,4);
+ downsample_4x4_to_3x3(xin, 4, dptr+dx, dadd);
+ }
+ }
+ else
+ {
+ if (sx+4<=srcwidth && sy+4<=srcheight)
+ {
+ downsample_4x4_to_3x3(sptr+sx, sadd, xout, 3);
+ copy_to_partial(3,3, xout, 3, dptr+dx, dadd,-dx,destwidth-dx,-dy,destheight-dy);
+ }
+ else
+ {
+ copy_from_partial(4,4, sptr+sx,sadd,-sx,srcwidth-sx,-sy,srcheight-sy, xin,4);
+ downsample_4x4_to_3x3(xin, 4, xout, 3);
+ copy_to_partial(3,3, xout,3, dptr+dx,dadd,-dx,destwidth-dx,-dy,destheight-dy);
+ }
+ }
+ // next column
+ dx += 3;
+ sx += 4;
+ }
+ // next row
+ dy += 3;
+ dptr += d3add;
+ sy += 4;
+ sptr += s4add;
+ }
+}
+
+
+void
+GPixmap::upsample23(const GPixmap *src, const GRect *pdr)
+{
+ // check arguments
+ int srcwidth = src->columns();
+ int srcheight = src->rows();
+ int destwidth = (srcwidth * 3 + 1 ) / 2;
+ int destheight = (srcheight * 3 + 1) / 2;
+ GRect rect(0, 0, destwidth, destheight);
+ if (pdr != 0)
+ {
+ if (pdr->xmin < rect.xmin ||
+ pdr->ymin < rect.ymin ||
+ pdr->xmax > rect.xmax ||
+ pdr->ymax > rect.ymax )
+ G_THROW( ERR_MSG("GPixmap.overflow4") );
+ rect = *pdr;
+ destwidth = rect.width();
+ destheight = rect.height();
+ }
+ // initialize pixmap
+ init(destheight, destwidth, 0);
+
+ // compute bounds
+ int dxz, dy; // location of bottomleft block in destination image
+ int sxz, sy; // location of bottomleft block in source image
+ euclidian_ratio(rect.ymin, 3, sy, dy);
+ euclidian_ratio(rect.xmin, 3, sxz, dxz);
+ sxz = 2 * sxz;
+ sy = 2 * sy;
+ dxz = - dxz;
+ dy = - dy;
+
+ // prepare variables
+ int sadd = src->rowsize();
+ int dadd = this->rowsize();
+ const GPixel *sptr = (*src)[0] + sy * sadd;
+ GPixel *dptr = (*this)[0] + dy * dadd;
+ int s2add = 2 * sadd;
+ int d3add = 3 * dadd;
+
+ // iterate over row blocks
+ while (dy < destheight)
+ {
+ int sx = sxz;
+ int dx = dxz;
+ // iterate over column blocks
+ while (dx < destwidth)
+ {
+ GPixel xin[4], xout[9];
+
+ if (dx>=0 && dy>=0 && dx+3<=destwidth && dy+3<=destheight)
+ {
+ if (sx+2<=srcwidth && sy+2<=srcheight)
+ {
+ upsample_2x2_to_3x3( sptr+sx, sadd, dptr+dx, dadd);
+ }
+ else
+ {
+ copy_from_partial(2, 2, sptr+sx, sadd, -sx, srcwidth-sx, -sy, srcheight-sy, xin, 2);
+ upsample_2x2_to_3x3(xin, 2, dptr+dx, dadd);
+ }
+ }
+ else
+ {
+ if (sx+2<=srcwidth && sy+2<=srcheight)
+ {
+ upsample_2x2_to_3x3( sptr+sx, sadd, xout, 3);
+ copy_to_partial(3,3, xout, 3, dptr+dx, dadd, -dx, destwidth-dx, -dy, destheight-dy);
+ }
+ else
+ {
+ copy_from_partial(2, 2, sptr+sx, sadd, -sx, srcwidth-sx, -sy, srcheight-sy, xin, 2);
+ upsample_2x2_to_3x3(xin, 2, xout, 3);
+ copy_to_partial(3,3, xout, 3, dptr+dx, dadd, -dx, destwidth-dx, -dy, destheight-dy);
+ }
+ }
+ // next column
+ dx += 3;
+ sx += 2;
+ }
+ // next row
+ dy += 3;
+ dptr += d3add;
+ sy += 2;
+ sptr += s2add;
+ }
+}
+
+
+//////////////////////////////////////////////////
+// Blitting and attenuating
+//////////////////////////////////////////////////
+
+
+static unsigned char clip[512];
+static bool clipok = false;
+
+static void
+compute_clip()
+{
+ clipok = true;
+ for (unsigned int i=0; i<sizeof(clip); i++)
+ clip[i] = (i<256 ? i : 255);
+}
+
+
+void
+GPixmap::attenuate(const GBitmap *bm, int xpos, int ypos)
+{
+ // Check
+ if (!bm) G_THROW( ERR_MSG("GPixmap.null_alpha") );
+ // Compute number of rows and columns
+ int xrows = mini(ypos + (int)bm->rows(), nrows) - maxi(0, ypos),
+ xcolumns = mini(xpos + (int) bm->columns(), ncolumns) - maxi(0, xpos);
+ if(xrows <= 0 || xcolumns <= 0)
+ return;
+ // Precompute multiplier map
+ unsigned int multiplier[256];
+ unsigned int maxgray = bm->get_grays() - 1;
+ for (unsigned int i=0; i<maxgray ; i++)
+ multiplier[i] = 0x10000 * i / maxgray;
+ // Compute starting point
+ const unsigned char *src = (*bm)[0] - mini(0,ypos)*bm->rowsize()-mini(0,xpos);
+ GPixel *dst = (*this)[0] + maxi(0, ypos)*rowsize()+maxi(0, xpos);
+ // Loop over rows
+ for (int y=0; y<xrows; y++)
+ {
+ // Loop over columns
+ for (int x=0; x<xcolumns; x++)
+ {
+ unsigned char srcpix = src[x];
+ // Perform pixel operation
+ if (srcpix > 0)
+ {
+ if (srcpix >= maxgray)
+ {
+ dst[x].b = 0;
+ dst[x].g = 0;
+ dst[x].r = 0;
+ }
+ else
+ {
+ unsigned int level = multiplier[srcpix];
+ dst[x].b -= (dst[x].b * level) >> 16;
+ dst[x].g -= (dst[x].g * level) >> 16;
+ dst[x].r -= (dst[x].r * level) >> 16;
+ }
+ }
+ }
+ // Next line
+ dst += rowsize();
+ src += bm->rowsize();
+ }
+}
+
+
+void
+GPixmap::blit(const GBitmap *bm, int xpos, int ypos, const GPixel *color)
+{
+ // Check
+ if (!bm) G_THROW( ERR_MSG("GPixmap.null_alpha") );
+ if (!clipok) compute_clip();
+ if (!color) return;
+ // Compute number of rows and columns
+ int xrows = mini(ypos + (int)bm->rows(), nrows) - maxi(0, ypos),
+ xcolumns = mini(xpos + (int) bm->columns(), ncolumns) - maxi(0, xpos);
+ if(xrows <= 0 || xcolumns <= 0)
+ return;
+ // Precompute multiplier map
+ unsigned int multiplier[256];
+ unsigned int maxgray = bm->get_grays() - 1;
+ for (unsigned int i=1; i<maxgray ; i++)
+ multiplier[i] = 0x10000 * i / maxgray;
+ // Cache target color
+ unsigned char gr = color->r;
+ unsigned char gg = color->g;
+ unsigned char gb = color->b;
+ // Compute starting point
+ const unsigned char *src = (*bm)[0] - mini(0,ypos)*bm->rowsize()-mini(0,xpos);
+ GPixel *dst = (*this)[0] + maxi(0, ypos)*rowsize()+maxi(0, xpos);
+ // Loop over rows
+ for (int y=0; y<xrows; y++)
+ {
+ // Loop over columns
+ for (int x=0; x<xcolumns; x++)
+ {
+ unsigned char srcpix = src[x];
+ // Perform pixel operation
+ if (srcpix > 0)
+ {
+ if (srcpix >= maxgray)
+ {
+ dst[x].b = clip[dst[x].b + gb];
+ dst[x].g = clip[dst[x].g + gg];
+ dst[x].r = clip[dst[x].r + gr];
+ }
+ else
+ {
+ unsigned int level = multiplier[srcpix];
+ dst[x].b = clip[dst[x].b + ((gb * level) >> 16)];
+ dst[x].g = clip[dst[x].g + ((gg * level) >> 16)];
+ dst[x].r = clip[dst[x].r + ((gr * level) >> 16)];
+ }
+ }
+ }
+ // Next line
+ dst += rowsize();
+ src += bm->rowsize();
+ }
+}
+
+
+void
+GPixmap::blit(const GBitmap *bm, int xpos, int ypos, const GPixmap *color)
+{
+ // Check
+ if (!bm) G_THROW( ERR_MSG("GPixmap.null_alpha") );
+ if (!color) G_THROW( ERR_MSG("GPixmap.null_color") );
+ if (!clipok) compute_clip();
+ if (bm->rows()!=color->rows() || bm->columns()!=color->columns())
+ G_THROW( ERR_MSG("GPixmap.diff_size") );
+ // Compute number of rows and columns
+ int xrows = mini(ypos + (int)bm->rows(), nrows) - maxi(0, ypos),
+ xcolumns = mini(xpos + (int) bm->columns(), ncolumns) - maxi(0, xpos);
+ if(xrows <= 0 || xcolumns <= 0)
+ return;
+ // Precompute multiplier map
+ unsigned int multiplier[256];
+ unsigned int maxgray = bm->get_grays() - 1;
+ for (unsigned int i=1; i<maxgray ; i++)
+ multiplier[i] = 0x10000 * i / maxgray;
+ // Cache target color
+ // Compute starting point
+ const unsigned char *src = (*bm)[0] - mini(0,ypos)*bm->rowsize()-mini(0,xpos);
+ const GPixel *src2 = (*color)[0] + maxi(0, ypos)*color->rowsize()+maxi(0, xpos);
+ GPixel *dst = (*this)[0] + maxi(0, ypos)*rowsize()+maxi(0, xpos);
+ // Loop over rows
+ for (int y=0; y<xrows; y++)
+ {
+ // Loop over columns
+ for (int x=0; x<xcolumns; x++)
+ {
+ unsigned char srcpix = src[x];
+ // Perform pixel operation
+ if (srcpix > 0)
+ {
+ if (srcpix >= maxgray)
+ {
+ dst[x].b = clip[dst[x].b + src2[x].b];
+ dst[x].g = clip[dst[x].g + src2[x].g];
+ dst[x].r = clip[dst[x].r + src2[x].r];
+ }
+ else
+ {
+ unsigned int level = multiplier[srcpix];
+ dst[x].b = clip[dst[x].b + ((src2[x].b * level) >> 16)];
+ dst[x].g = clip[dst[x].g + ((src2[x].g * level) >> 16)];
+ dst[x].r = clip[dst[x].r + ((src2[x].r * level) >> 16)];
+ }
+ }
+ }
+ // Next line
+ dst += rowsize();
+ src += bm->rowsize();
+ src2 += color->rowsize();
+ }
+}
+
+
+
+void
+GPixmap::blend(const GBitmap *bm, int xpos, int ypos, const GPixmap *color)
+{
+ // Check
+ if (!bm) G_THROW( ERR_MSG("GPixmap.null_alpha") );
+ if (!color) G_THROW( ERR_MSG("GPixmap.null_color") );
+ if (!clipok) compute_clip();
+ if (bm->rows()!=color->rows() || bm->columns()!=color->columns())
+ G_THROW( ERR_MSG("GPixmap.diff_size") );
+ // Compute number of rows and columns
+ int xrows = mini(ypos + (int)bm->rows(), nrows) - maxi(0, ypos),
+ xcolumns = mini(xpos + (int) bm->columns(), ncolumns) - maxi(0, xpos);
+ if(xrows <= 0 || xcolumns <= 0)
+ return;
+ // Precompute multiplier map
+ unsigned int multiplier[256];
+ unsigned int maxgray = bm->get_grays() - 1;
+ for (unsigned int i=1; i<maxgray ; i++)
+ multiplier[i] = 0x10000 * i / maxgray;
+ // Cache target color
+ // Compute starting point
+ const unsigned char *src = (*bm)[0] - mini(0,ypos)*bm->rowsize()-mini(0,xpos);
+ const GPixel *src2 = (*color)[0] + maxi(0, ypos)*color->rowsize()+maxi(0, xpos);
+ GPixel *dst = (*this)[0] + maxi(0, ypos)*rowsize()+maxi(0, xpos);
+ // Loop over rows
+ for (int y=0; y<xrows; y++)
+ {
+ // Loop over columns
+ for (int x=0; x<xcolumns; x++)
+ {
+ unsigned char srcpix = src[x];
+ // Perform pixel operation
+ if (srcpix > 0)
+ {
+ if (srcpix >= maxgray)
+ {
+ dst[x].b = src2[x].b;
+ dst[x].g = src2[x].g;
+ dst[x].r = src2[x].r;
+ }
+ else
+ {
+ unsigned int level = multiplier[srcpix];
+ dst[x].b -= (((int)dst[x].b - (int)src2[x].b) * level) >> 16;
+ dst[x].g -= (((int)dst[x].g - (int)src2[x].g) * level) >> 16;
+ dst[x].r -= (((int)dst[x].r - (int)src2[x].r) * level) >> 16;
+ }
+ }
+ }
+ // Next line
+ dst += rowsize();
+ src += bm->rowsize();
+ src2 += color->rowsize();
+ }
+}
+
+
+
+
+void
+GPixmap::stencil(const GBitmap *bm,
+ const GPixmap *pm, int pms, const GRect *pmr,
+ double corr)
+{
+ // Check arguments
+ GRect rect(0, 0, pm->columns()*pms, pm->rows()*pms);
+ if (pmr != 0)
+ {
+ if (pmr->xmin < rect.xmin ||
+ pmr->ymin < rect.ymin ||
+ pmr->xmax > rect.xmax ||
+ pmr->ymax > rect.ymax )
+ G_THROW( ERR_MSG("GPixmap.overflow5") );
+ rect = *pmr;
+ }
+ // Compute number of rows
+ int xrows = nrows;
+ if ((int)bm->rows() < xrows)
+ xrows = bm->rows();
+ if (rect.height() < xrows)
+ xrows = rect.height();
+ // Compute number of columns
+ int xcolumns = ncolumns;
+ if ((int)bm->columns() < xcolumns)
+ xcolumns = bm->columns();
+ if (rect.width() < xcolumns)
+ xcolumns = rect.width();
+ // Precompute multiplier map
+ unsigned int multiplier[256];
+ unsigned int maxgray = bm->get_grays() - 1;
+ for (unsigned int i=1; i<maxgray ; i++)
+ multiplier[i] = 0x10000 * i / maxgray;
+ // Prepare color correction table
+ unsigned char gtable[256];
+ color_correction_table_cache(corr, gtable);
+ // Compute starting point in blown up foreground pixmap
+ int fgy, fgy1, fgxz, fgx1z;
+ euclidian_ratio(rect.ymin, pms, fgy, fgy1);
+ euclidian_ratio(rect.xmin, pms, fgxz, fgx1z);
+ const GPixel *fg = (*pm)[fgy];
+ const unsigned char *src = (*bm)[0];
+ GPixel *dst = (*this)[0];
+ // Loop over rows
+ for (int y=0; y<xrows; y++)
+ {
+ // Loop over columns
+ int fgx = fgxz;
+ int fgx1 = fgx1z;
+ for (int x=0; x<xcolumns; x++)
+ {
+ unsigned char srcpix = src[x];
+ // Perform pixel operation
+ if (srcpix > 0)
+ {
+ if (srcpix >= maxgray)
+ {
+ dst[x].b = gtable[fg[fgx].b];
+ dst[x].g = gtable[fg[fgx].g];
+ dst[x].r = gtable[fg[fgx].r];
+ }
+ else
+ {
+ unsigned int level = multiplier[srcpix];
+ dst[x].b -= (((int)dst[x].b - (int)gtable[fg[fgx].b]) * level) >> 16;
+ dst[x].g -= (((int)dst[x].g - (int)gtable[fg[fgx].g]) * level) >> 16;
+ dst[x].r -= (((int)dst[x].r - (int)gtable[fg[fgx].r]) * level) >> 16;
+ }
+ }
+ // Next column
+ if (++fgx1 >= pms)
+ {
+ fgx1 = 0;
+ fgx += 1;
+ }
+ }
+ // Next line
+ dst += rowsize();
+ src += bm->rowsize();
+ if (++fgy1 >= pms)
+ {
+ fgy1 = 0;
+ fg += pm->rowsize();
+ }
+ }
+}
+
+GP<GPixmap> GPixmap::rotate(int count)
+{
+ GP<GPixmap> newpixmap(this);
+ if((count %= 4))
+ {
+ if( count&0x01)
+ newpixmap = new GPixmap(ncolumns, nrows);
+ else
+ newpixmap = new GPixmap(nrows, ncolumns);
+
+ GPixmap &dpixmap = *newpixmap;
+
+ GMonitorLock lock(&pixmap_monitor());
+ switch(count)
+ {
+ case 1: //// rotate 90 counter clockwise
+ {
+ int lastrow = dpixmap.rows()-1;
+
+ for(int y=0; y<nrows; y++)
+ {
+ const GPixel *r=operator [] (y);
+ for(int x=0,xnew=lastrow; xnew>=0; x++,xnew--)
+ {
+ dpixmap[xnew][y] = r[x];
+ }
+ }
+ }
+ break;
+ case 2: //// rotate 180 counter clockwise
+ {
+ int lastrow = dpixmap.rows()-1;
+ int lastcolumn = dpixmap.columns()-1;
+
+ for(int y=0,ynew=lastrow; ynew>=0; y++,ynew--)
+ {
+ const GPixel *r=operator [] (y);
+ GPixel *d=dpixmap[ynew];
+ for(int xnew=lastcolumn; xnew>=0; r++,xnew--)
+ {
+ d[xnew] = *r;
+ }
+ }
+ }
+ break;
+ case 3: //// rotate 270 counter clockwise
+ {
+ int lastcolumn = dpixmap.columns()-1;
+
+ for(int y=0,ynew=lastcolumn; ynew>=0; y++,ynew--)
+ {
+ const GPixel *r=operator [] (y);
+ for(int x=0; x<ncolumns; x++)
+ {
+ dpixmap[x][ynew] = r[x];
+ }
+ }
+ }
+ break;
+ }
+ }
+ return newpixmap;
+}
+
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+
diff --git a/kviewshell/plugins/djvu/libdjvu/GPixmap.h b/kviewshell/plugins/djvu/libdjvu/GPixmap.h
new file mode 100644
index 00000000..32d51c7e
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GPixmap.h
@@ -0,0 +1,531 @@
+//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: GPixmap.h,v 1.8 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _GPIXMAP_H_
+#define _GPIXMAP_H_
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+/** @name GPixmap.h
+
+ Files #"GPixmap.h"# and #"GPixmap.cpp"# implement class \Ref{GPixmap}.
+ Instances of this class represent color images. Each RGB pixel is
+ represented by structure \Ref{GPixel}. The ``bottom left'' coordinate system
+ is used consistently in the DjVu library. Line zero of a GPixmap is the
+ bottom line in the color image. Pixels are organized from left to right
+ within each line.
+
+ {\bf ToDo} --- More sophisticated color correction schemes.
+
+ @memo
+ Generic support for color images.
+ @author
+ L\'eon Bottou <leonb@research.att.com>
+ @version
+ #$Id: GPixmap.h,v 1.8 2003/11/07 22:08:21 leonb Exp $# */
+//@{
+
+
+#include "GSmartPointer.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+class GBitmap;
+class GRect;
+class ByteStream;
+
+
+/** Color pixel as a RGB triple.
+ The colors are represented using three bytes named #r#, #g# and #b#. The
+ value of these bytes represent additive amounts of light. Color white is
+ represented by setting all three bytes to #255#. Color black is
+ represented by setting all three bytes to #0#. This convention should not
+ be confused with the convention adopted for class \Ref{GBitmap} where the
+ pixel values represent an ink level. */
+
+struct GPixel
+{
+ /** Blue component. */
+ unsigned char b;
+ /** Green component. */
+ unsigned char g;
+ /** Red component. */
+ unsigned char r;
+ /** Returns true iff colors are identical. */
+ friend int operator==(const GPixel & p1, const GPixel & p2);
+ /** Returns true iff colors are different. */
+ friend int operator!=(const GPixel & p1, const GPixel & p2);
+ /** Returns a hash code for the color. */
+ friend unsigned int hash(const GPixel &p);
+ /** @name Predefined colors. */
+ //@{
+ /// GPixel::WHITE is initialized to #rgb:255/255/255#.
+ static const GPixel WHITE;
+ /// GPixel::BLACK is initialized to #rgb:0/0/0#.
+ static const GPixel BLACK;
+ /// GPixel::BLUE is initialized to #rgb:0/0/255#.
+ static const GPixel BLUE;
+ /// GPixel::GREEN is initialized to #rgb:0/255/0#.
+ static const GPixel GREEN;
+ /// GPixel::RED is initialized to #rgb:255/0/0#.
+ static const GPixel RED;
+ //@}
+};
+
+
+/** RGB Color images.
+ Instances of class #GPixmap# represent color images as a two dimensional
+ array of pixels \Ref{GPixel}. The bracket operator returns a pointer to
+ the pixels composing one line of the image. This pointer can be used as
+ an array to read or write the pixels of this particular line. Following
+ the general convention of the DjVu Reference Library, line zero is always
+ the bottom line of the image.
+ */
+
+class GPixmap : public GPEnabled
+{
+protected:
+ GPixmap(void);
+ GPixmap(int nrows, int ncolumns, const GPixel *filler=0);
+ GPixmap(const GBitmap &ref);
+ GPixmap(const GBitmap &ref, const GRect &rect);
+ GPixmap(const GPixmap &ref);
+ GPixmap(const GPixmap &ref, const GRect &rect);
+ GPixmap(ByteStream &ref);
+
+public:
+ /// Virtual destructor.
+ virtual ~GPixmap();
+
+ void destroy(void);
+ /** @name Construction. */
+ //@{
+ /** Creates an empty GBitmap object. The returned GPixmap has zero rows
+ and zero columns. Use function \Ref{init} to change the size of the
+ image. */
+ static GP<GPixmap> create(void) {return new GPixmap();}
+
+ /** Creates a GPixmap with #nrows# rows and #ncolumns# columns. When the
+ optional argument #filler# is specified, all pixels are initialized
+ with the corresponding color. */
+ static GP<GPixmap> create(
+ const int nrows, const int ncolumns, const GPixel *filler=0)
+ { return new GPixmap(nrows,ncolumns,filler); }
+
+ /** Creates a GPixmap by copying the gray level image #ref#.
+ The constructed GPixmap has the same size as #ref#. The pixels
+ are initialized with shades of grays copied from #ref#. */
+ static GP<GPixmap> create(const GBitmap &ref)
+ { return new GPixmap(ref); }
+
+ /** Creates a GPixmap by copying the rectangle #rect# of the gray level
+ image #ref#. The constructed GPixmap has the same size as rectangle
+ #rect#. The pixels are initialized with shades of grays converted from
+ the ink levels represented in #ref#. This conversion depends on the
+ number of gray levels in #ref#. */
+ static GP<GPixmap> create(const GBitmap &ref, const GRect &rect)
+ { return new GPixmap(ref,rect); }
+
+ /** Copy constructors. Creates a GPixmap by replicating the size and the
+ contents of GPixmap #ref#. */
+ static GP<GPixmap> create(const GPixmap &ref)
+ { return new GPixmap(ref); }
+
+ /** Creates a GPixmap by copying the rectangle #rect# of the color image #ref#.
+ The constructed GPixmap has the same size as rectangle #rect#.
+ The pixels are initialized with colors copied from #ref#. */
+ static GP<GPixmap> create(const GPixmap &ref, const GRect &rect)
+ { return new GPixmap(ref,rect); }
+
+ /** Creates a GPixmap by reading PPM data from ByteStream #ref#.
+ See \Ref{PNM and RLE file formats} for more information. */
+ static GP<GPixmap> create(ByteStream &ref)
+ { return new GPixmap(ref); }
+
+ //@}
+
+ /** @name Initialization. */
+ //@{
+ /** Resets the GPixmap to #nrows# rows and #ncolumns# columns. When the
+ optional argument #filler# is specified, all pixels are initialized with
+ the corresponding color. The previous content of the GPixmap is discarded. */
+ void init(int nrows, int ncolumns, const GPixel *filler=0);
+ /** Resets the GPixmap by copying the size and the contents of the color
+ image #ref#. The previous content of the GPixmap is discarded. */
+ void init(const GPixmap &ref);
+ /** Resets the GPixmap by copying the rectangle #rect# of the color image #ref#.
+ The previous content of the GPixmap is discarded. */
+ void init(const GPixmap &ref, const GRect &rect);
+ /** Resets the GPixmap by copying the size and the contents of the gray
+ level image #ref#. The optional argument #ramp# is an array of 256
+ pixel values used for mapping the gray levels to color values.
+ Setting #ramp# to zero selects a linear ramp of shades of gray. */
+ void init(const GBitmap &ref, const GPixel *ramp=0);
+ /** Resets the GPixmap by copying the rectangle #rect# of the gray level
+ image #ref#. The optional argument #ramp# is an array of 256 pixel
+ values used for mapping the gray levels to color values. Setting #ramp#
+ to zero selects a linear ramp computed according to the maximal number
+ of gray levels in #ref#. */
+ void init(const GBitmap &ref, const GRect &rect, const GPixel *ramp=0);
+ /** Resets the GPixmap by reading PPM data from ByteStream #ref#. See
+ \Ref{PNM and RLE file formats} for more information. */
+ void init(ByteStream &ref);
+ /** Resets the GPixmap by copying the gray level image #ref#. The pixels
+ are initialized with shades of grays copied from #ref#. */
+ GPixmap& operator=(const GBitmap &ref);
+ /** Copy operator. Resets the GPixmap by copying the size and the contents
+ of the color image #ref#. The previous content of the GPixmap is
+ discarded. */
+ GPixmap& operator=(const GPixmap &ref);
+ //@}
+
+ /** @name Accessing pixels. */
+ //@{
+ /** Returns the number of rows (the image height). */
+ unsigned int rows() const;
+ /** Returns the number of columns (the image width). */
+ unsigned int columns() const;
+ /** Returns a constant pointer to the first GPixel in row #row#. This
+ pointer can be used as an array to read the row elements. */
+ const GPixel * operator[] (int row) const;
+ /** Returns a pointer to the first GPixel in row #row#. This pointer can be
+ used as an array to read or write the row elements. */
+ GPixel * operator[] (int row);
+ /** Returns the length (in pixels) of a row in memory. This number is equal
+ to the difference between pointers to pixels located in the same column
+ in consecutive rows. This difference may be larger than the number of
+ columns in the image. */
+ unsigned int rowsize() const;
+ //@}
+
+ /** @name Resampling images. */
+ //@{
+ /** Resets this GPixmap with a subsampled segment of color image #src#.
+ This function conceptually rescales image #src# by a factor #1:factor#,
+ and copies rectangle #rect# of the subsampled image into the current GPixmap.
+ The full subsampled image is copied if #rect# is a null pointer.
+ Both operations are however performed together for efficiency reasons.
+ Subsampling works by averaging the colors of the source pixels located
+ in small squares of size #factor# times #factor#. */
+ void downsample(const GPixmap *src, int factor, const GRect *rect=0);
+ /** Resets this GPixmap with a oversampled segment of color image #src#.
+ This function conceptually rescales image #src# by a factor #factor:1#,
+ and copies rectangle #rect# of the oversampled image into the current
+ GPixmap. The full oversampled image is copied if #rect# is a null
+ pointer. Both operations are however performed together for efficiency
+ reasons. Oversampling works by replicating the color of the source
+ pixels into squares of size #factor# times #factor#. */
+ void upsample(const GPixmap *src, int factor, const GRect *rect=0);
+ /** Resets this GPixmap with a rescaled segment of #src# (zoom 75%). This
+ function conceptually rescales image #src# by a factor #3:4#, and copies
+ rectangle #rect# of the rescaled image into the current GPixmap. The
+ full rescaled image is copied if #rect# is a null pointer. Both
+ operations are however performed together for efficiency reasons. This
+ function has been superseded by class \Ref{GPixmapScaler}. */
+ void downsample43(const GPixmap *src, const GRect *rect=0);
+ /** Resets this GPixmap with a rescaled segment of #src# (zoom 150%). This
+ function conceptually rescales image #src# by a factor #3:2# and copies
+ rectangle #rect# of the rescaled image into the current GPixmap. The
+ full rescaled image is copied if #rect# is a null pointer. Both
+ operations are however performed together for efficiency reasons. This
+ function has been superseded by class \Ref{GPixmapScaler}. */
+ void upsample23(const GPixmap *src, const GRect *rect=0);
+ //@}
+
+ /** @name Blitting and applying stencils.
+ These function is essential for rendering DjVu images. The elementary
+ functions are \Ref{attenuate} and \Ref{blit}. The combined functions
+ \Ref{blend} and \Ref{stencil} should be viewed as optimizations. */
+ //@{
+ /** Attenuates the color image in preparation for a blit.
+ Bitmap #bm# is positionned at location #x#,#y# over this color image.
+ The matching color image pixels are then multiplied by #1.0-Alpha# where
+ #Alpha# denotes the gray value, in range #[0,1]#, represented by the
+ corresponding pixel of bitmap #bm#. */
+ void attenuate(const GBitmap *bm, int x, int y);
+ /** Blits solid color #color# through transparency mask #bm#.
+ Bitmap #bm# is positionned at location #x#,#y# over this color image.
+ The matching color image pixels are then modified by adding color
+ #color# multiplied by #Alpha#, where #Alpha# denotes the gray value, in
+ range #[0,1]#, represented by the corresponding pixel of bitmap #bm#. */
+ void blit(const GBitmap *bm, int x, int y, const GPixel *color);
+ /** Blits pixmap #color# through transparency mask #bm#.
+ Bitmap #bm# is positionned at location #x#,#y# over this color image.
+ The matching color image pixels are then modified by adding the
+ corresponding pixel color in pixmap #color#, multiplied by #Alpha#,
+ where #Alpha# denotes the gray value, in range #[0,1]#, represented by
+ the corresponding pixel of bitmap #bm#. */
+ void blit(const GBitmap *bm, int x, int y, const GPixmap *color);
+ /** Performs alpha blending. This function is similar to first calling
+ \Ref{attenuate} with alpha map #bm# and then calling \Ref{blit} with
+ alpha map #bm# and color map #color#. Both operations are performed
+ together for efficiency reasons. */
+ void blend(const GBitmap *bm, int x, int y, const GPixmap *color);
+ /** Resample color pixmap and performs color corrected alpha blending. This
+ function conceptually computes an intermediate color image by first
+ upsampling the GPixmap #pm# by a factor #pms:1# (see \Ref{upsample}),
+ extracting the sub-image designated by rectangle #pmr# and applying
+ color correction #corr# (see \Ref{color_correct}). This intermediate
+ color image is then blended into this pixel map according to the alpha
+ map #bm# (see \Ref{blend}). */
+ void stencil(const GBitmap *bm,
+ const GPixmap *pm, int pms,
+ const GRect *pmr, double corr=1.0);
+ //@}
+
+ /** @name Manipulating colors. */
+ //@{
+ /** Dithers the image to 216 colors. This function applies an ordered
+ dithering algorithm to reduce the image to 216 predefined colors. These
+ predefined colors are located on a color cube of 6x6x6 colors: the color
+ RGB coordinates can only take the following values: #0#, #51#, #102#,
+ #163#, #214# or #255#. This is useful for displaying images on a device
+ supporting a maximum of 256 colors. Arguments #xmin# and #ymin# control
+ the position of the dithering grids. This is useful for dithering tiled
+ images. Arguments #xmin# and #ymin# must be the position of the bottom
+ left corner of the tile contained in this GPixmap. Properly setting
+ these arguments eliminates dithering artifacts on the tile
+ boundaries. */
+ void ordered_666_dither(int xmin=0, int ymin=0);
+ /** Dithers the image to 32768 colors. This function applies an ordered
+ dithering algorithm to reduce the image to 32768 predefined colors.
+ These predefined colors are located on a color cube of 32x32x32 colors:
+ the color RGB coordinates can only take values in which the three least
+ significant bits are set to #1#. This is useful for displaying images
+ with less than 24 bits per pixel. Arguments #xmin# and #ymin# control
+ the position of the dithering grids. This is useful for dithering tiled
+ images. Arguments #xmin# and #ymin# must be the position of the bottom
+ left corner of the tile contained in this GPixmap. Properly setting
+ these arguments eliminates dithering artifacts on the tile
+ boundaries. */
+ void ordered_32k_dither(int xmin=0, int ymin=0);
+ /** Applies a luminance gamma correction factor of #corr#. Values greater than
+ #1.0# make the image brighter. Values smaller than #1.0# make the image
+ darker. The documentation of program \Ref{ppmcoco} explains how to
+ properly use this function. */
+ void color_correct(double corr);
+ /** Applies a luminance gamma correction to an array of pixels.
+ This function is {\em static} and does not modify this pixmap. */
+ static void color_correct(double corr, GPixel *pixels, int npixels);
+
+ //@}
+
+ /** @name Miscellaneous. */
+ //@{
+ /** Returns the number of bytes allocated for this image. */
+ inline unsigned int get_memory_usage() const;
+ /** Saves the image into ByteStream #bs# using the PPM format.
+ Argument #raw# selects the ``Raw PPM'' (1) or the ``Ascii PPM'' (0) format.
+ See \Ref{PNM and RLE file formats} for more information. */
+ void save_ppm(ByteStream &bs, int raw=1) const;
+ //@}
+
+ /** @name Stealing or borrowing the memory buffer (advanced). */
+ //@{
+ /** Steals the memory buffer of a GPixmap. This function returns the
+ address of the memory buffer allocated by this GPixmap object. The
+ offset of the first pixel in the bottom line is written into variable
+ #offset#. Other lines can be accessed using pointer arithmetic (see
+ \Ref{rowsize}). The GPixmap object no longer ``owns'' the buffer: you
+ must explicitly de-allocate the buffer using #operator delete []#. This
+ de-allocation should take place after the destruction or the
+ re-initialization of the GPixmap object. This function will return a
+ null pointer if the GPixmap object does not ``own'' the buffer in the
+ first place. */
+ GPixel *take_data(size_t &offset);
+ /** Initializes this GPixmap by borrowing a memory segment. The GPixmap
+ then directly addresses the memory buffer #data# provided by the user.
+ This buffer must be large enough to hold #w*h# GPixels. The GPixmap
+ object does not ``own'' the buffer: you must explicitly de-allocate the
+ buffer using #operator delete []#. This de-allocation should take place
+ after the destruction or the re-initialization of the GPixmap object. */
+ inline void borrow_data(GPixel &data, int w, int h);
+ /// Identical to the above, but GPixmap will do the delete [].
+ void donate_data(GPixel *data, int w, int h);
+
+ /** Rotates pixmap by 90, 180 or 270 degrees anticlockwise
+ and returns a new pixmap, input pixmap is not changed.
+ count can be 1, 2, or 3 for 90, 180, 270 degree rotation.
+ It returns the same pixmap if not rotated. */
+ GP<GPixmap> rotate(int count=0);
+
+ //@}
+
+ // Please ignore these two functions. Their only purpose is to allow
+ // DjVu viewer compile w/o errors. eaf.
+ // Is this still useful ?. lyb.
+ int get_grays(void) const { return 256; };
+ void set_grays(int) {};\
+
+protected:
+ // data
+ unsigned short nrows;
+ unsigned short ncolumns;
+ unsigned short nrowsize;
+ GPixel *pixels;
+ GPixel *pixels_data;
+ friend class DjVu_PixImage;
+};
+
+//@}
+
+// INLINE --------------------------
+
+
+inline int
+operator==(const GPixel & p1, const GPixel & p2)
+{
+ return p1.r==p2.r && p1.g==p2.g && p1.b==p2.b;
+}
+
+inline int
+operator!=(const GPixel & p1, const GPixel & p2)
+{
+ return p1.r!=p2.r || p1.g!=p2.g || p1.b!=p2.b;
+}
+
+inline unsigned int
+hash(const GPixel &p)
+{
+ unsigned int x = (p.b<<16)|(p.g<<8)|(p.r);
+ return x ^ (p.b<<4) ^ (p.r<<12);
+}
+
+inline unsigned int
+GPixmap::rows() const
+{
+ return nrows;
+}
+
+inline unsigned int
+GPixmap::columns() const
+{
+ return ncolumns;
+}
+
+inline unsigned int
+GPixmap::rowsize() const
+{
+ return nrowsize;
+}
+
+inline GPixel *
+GPixmap::operator[](int row)
+{
+ if (row<0 || row>=nrows || !pixels) return 0;
+ return &pixels[row * nrowsize];
+}
+
+inline const GPixel *
+GPixmap::operator[](int row) const
+{
+ if (row<0 || row>=nrows) return 0;
+ return &pixels[row * nrowsize];
+}
+
+inline GPixmap &
+GPixmap::operator=(const GBitmap &ref)
+{
+ init(ref);
+ return *this;
+}
+
+inline GPixmap &
+GPixmap::operator=(const GPixmap &ref)
+{
+ init(ref);
+ return *this;
+}
+
+inline void
+GPixmap::borrow_data(GPixel &data, int w, int h)
+{
+ donate_data(&data,w,h);
+ pixels_data=0;
+}
+
+//////////////////////////////////////////////////
+// Memory usage
+//////////////////////////////////////////////////
+
+
+inline unsigned int
+GPixmap::get_memory_usage() const
+{
+ return sizeof(GPixmap)+(nrows * ncolumns * sizeof(GPixel));
+}
+
+// ---------------------------------
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
+
+
diff --git a/kviewshell/plugins/djvu/libdjvu/GRect.cpp b/kviewshell/plugins/djvu/libdjvu/GRect.cpp
new file mode 100644
index 00000000..1ac0a87c
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GRect.cpp
@@ -0,0 +1,458 @@
+//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: GRect.cpp,v 1.10 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+// -- Implementation of class GRect and GRectMapper
+// - Author: Leon Bottou, 05/1997
+
+
+#include "GRect.h"
+#include "GException.h"
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+// -- Local utilities
+
+static inline int
+imin(int x, int y)
+{
+ if (x < y)
+ return x;
+ else
+ return y;
+}
+
+static inline int
+imax(int x, int y)
+{
+ if (x > y)
+ return x;
+ else
+ return y;
+}
+
+static inline void
+iswap(int &x, int &y)
+{
+ int tmp = x; x = y; y = tmp;
+}
+
+// -- Class GRect
+
+int
+operator==(const GRect & r1, const GRect & r2)
+{
+ int isempty1 = r1.isempty();
+ int isempty2 = r2.isempty();
+ if (isempty1 || isempty2)
+ if (isempty1 && isempty2)
+ return 1;
+ if ( r1.xmin==r2.xmin && r1.xmax==r2.xmax
+ && r1.ymin==r2.ymin && r1.ymax==r2.ymax )
+ return 1;
+ return 0;
+}
+
+int
+GRect::inflate(int dx, int dy)
+{
+ xmin -= dx;
+ xmax += dx;
+ ymin -= dy;
+ ymax += dy;
+ if (! isempty())
+ return 1;
+ xmin = ymin = xmax = ymax = 0;
+ return 0;
+}
+
+int
+GRect::translate(int dx, int dy)
+{
+ xmin += dx;
+ xmax += dx;
+ ymin += dy;
+ ymax += dy;
+ if (! isempty())
+ return 1;
+ xmin = ymin = xmax = ymax = 0;
+ return 0;
+}
+
+int
+GRect::intersect(const GRect &rect1, const GRect &rect2)
+{
+ xmin = imax(rect1.xmin, rect2.xmin);
+ xmax = imin(rect1.xmax, rect2.xmax);
+ ymin = imax(rect1.ymin, rect2.ymin);
+ ymax = imin(rect1.ymax, rect2.ymax);
+ if (! isempty())
+ return 1;
+ xmin = ymin = xmax = ymax = 0;
+ return 0;
+}
+
+int
+GRect::recthull(const GRect &rect1, const GRect &rect2)
+{
+ if (rect1.isempty())
+ {
+ xmin = rect2.xmin;
+ xmax = rect2.xmax;
+ ymin = rect2.ymin;
+ ymax = rect2.ymax;
+ return !isempty();
+ }
+ if (rect2.isempty())
+ {
+ xmin = rect1.xmin;
+ xmax = rect1.xmax;
+ ymin = rect1.ymin;
+ ymax = rect1.ymax;
+ return !isempty();
+ }
+ xmin = imin(rect1.xmin, rect2.xmin);
+ xmax = imax(rect1.xmax, rect2.xmax);
+ ymin = imin(rect1.ymin, rect2.ymin);
+ ymax = imax(rect1.ymax, rect2.ymax);
+ return 1;
+}
+
+int
+GRect::contains(const GRect & rect) const
+{
+ GRect tmp_rect;
+ tmp_rect.intersect(*this, rect);
+ return tmp_rect==rect;
+}
+
+void
+GRect::scale(float factor)
+{
+ xmin = (int)(((float)xmin) * factor);
+ ymin = (int)(((float)ymin) * factor);
+ xmax = (int)(((float)xmax) * factor);
+ ymax = (int)(((float)ymax) * factor);
+}
+
+void
+GRect::scale(float xfactor, float yfactor)
+{
+ xmin = (int)(((float)xmin) * xfactor);
+ ymin = (int)(((float)ymin) * yfactor);
+ xmax = (int)(((float)xmax) * xfactor);
+ ymax = (int)(((float)ymax) * yfactor);
+}
+// -- Class GRatio
+
+
+inline
+GRectMapper::GRatio::GRatio()
+ : p(0), q(1)
+{
+}
+
+inline
+GRectMapper::GRatio::GRatio(int p, int q)
+ : p(p), q(q)
+{
+ if (q == 0)
+ G_THROW( ERR_MSG("GRect.div_zero") );
+ if (p == 0)
+ q = 1;
+ if (q < 0)
+ {
+ p = -p;
+ q = -q;
+ }
+ int gcd = 1;
+ int g1 = p;
+ int g2 = q;
+ if (g1 > g2)
+ {
+ gcd = g1;
+ g1 = g2;
+ g2 = gcd;
+ }
+ while (g1 > 0)
+ {
+ gcd = g1;
+ g1 = g2 % g1;
+ g2 = gcd;
+ }
+ p /= gcd;
+ q /= gcd;
+}
+
+
+#ifdef HAVE_LONG_LONG_INT
+#define llint_t long long int
+#else
+#define llint_t long int
+#endif
+
+inline int
+operator*(int n, GRectMapper::GRatio r )
+{
+ /* [LB] -- This computation is carried out with integers and
+ rational numbers because it must be exact. Some lizard changed
+ it to double and this is wrong. I suspect they did so because
+ they encountered overflow issues. Let's use long long ints. */
+ llint_t x = (llint_t) n * (llint_t) r.p;
+ if (x >= 0)
+ return ((r.q/2 + x) / r.q);
+ else
+ return - ((r.q/2 - x) / r.q);
+}
+
+inline int
+operator/(int n, GRectMapper::GRatio r )
+{
+ /* [LB] -- See comment in operator*() above. */
+ llint_t x = (llint_t) n * (llint_t) r.q;
+ if (x >= 0)
+ return ((r.p/2 + x) / r.p);
+ else
+ return - ((r.p/2 - x) / r.p);
+}
+
+
+// -- Class GRectMapper
+
+#define MIRRORX 1
+#define MIRRORY 2
+#define SWAPXY 4
+
+
+GRectMapper::GRectMapper()
+: rectFrom(0,0,1,1),
+ rectTo(0,0,1,1),
+ code(0)
+{
+
+}
+
+void
+GRectMapper::clear()
+{
+ rectFrom = GRect(0,0,1,1);
+ rectTo = GRect(0,0,1,1);
+ code = 0;
+}
+
+void
+GRectMapper::set_input(const GRect &rect)
+{
+ if (rect.isempty())
+ G_THROW( ERR_MSG("GRect.empty_rect1") );
+ rectFrom = rect;
+ if (code & SWAPXY)
+ {
+ iswap(rectFrom.xmin, rectFrom.ymin);
+ iswap(rectFrom.xmax, rectFrom.ymax);
+ }
+ rw = rh = GRatio();
+}
+
+void
+GRectMapper::set_output(const GRect &rect)
+{
+ if (rect.isempty())
+ G_THROW( ERR_MSG("GRect.empty_rect2") );
+ rectTo = rect;
+ rw = rh = GRatio();
+}
+
+void
+GRectMapper::rotate(int count)
+{
+ int oldcode = code;
+ switch (count & 0x3)
+ {
+ case 1:
+ code ^= (code & SWAPXY) ? MIRRORY : MIRRORX;
+ code ^= SWAPXY;
+ break;
+ case 2:
+ code ^= (MIRRORX|MIRRORY);
+ break;
+ case 3:
+ code ^= (code & SWAPXY) ? MIRRORX : MIRRORY;
+ code ^= SWAPXY;
+ break;
+ }
+ if ((oldcode ^ code) & SWAPXY)
+ {
+ iswap(rectFrom.xmin, rectFrom.ymin);
+ iswap(rectFrom.xmax, rectFrom.ymax);
+ rw = rh = GRatio();
+ }
+}
+
+void
+GRectMapper::mirrorx()
+{
+ code ^= MIRRORX;
+}
+
+void
+GRectMapper::mirrory()
+{
+ code ^= MIRRORY;
+}
+
+void
+GRectMapper::precalc()
+{
+ if (rectTo.isempty() || rectFrom.isempty())
+ G_THROW( ERR_MSG("GRect.empty_rect3") );
+ rw = GRatio(rectTo.width(), rectFrom.width());
+ rh = GRatio(rectTo.height(), rectFrom.height());
+}
+
+void
+GRectMapper::map(int &x, int &y)
+{
+ int mx = x;
+ int my = y;
+ // precalc
+ if (! (rw.p && rh.p))
+ precalc();
+ // swap and mirror
+ if (code & SWAPXY)
+ iswap(mx,my);
+ if (code & MIRRORX)
+ mx = rectFrom.xmin + rectFrom.xmax - mx;
+ if (code & MIRRORY)
+ my = rectFrom.ymin + rectFrom.ymax - my;
+ // scale and translate
+ x = rectTo.xmin + (mx - rectFrom.xmin) * rw;
+ y = rectTo.ymin + (my - rectFrom.ymin) * rh;
+}
+
+void
+GRectMapper::unmap(int &x, int &y)
+{
+ // precalc
+ if (! (rw.p && rh.p))
+ precalc();
+ // scale and translate
+ int mx = rectFrom.xmin + (x - rectTo.xmin) / rw;
+ int my = rectFrom.ymin + (y - rectTo.ymin) / rh;
+ // mirror and swap
+ if (code & MIRRORX)
+ mx = rectFrom.xmin + rectFrom.xmax - mx;
+ if (code & MIRRORY)
+ my = rectFrom.ymin + rectFrom.ymax - my;
+ if (code & SWAPXY)
+ iswap(mx,my);
+ x = mx;
+ y = my;
+}
+
+void
+GRectMapper::map(GRect &rect)
+{
+ map(rect.xmin, rect.ymin);
+ map(rect.xmax, rect.ymax);
+ if (rect.xmin >= rect.xmax)
+ iswap(rect.xmin, rect.xmax);
+ if (rect.ymin >= rect.ymax)
+ iswap(rect.ymin, rect.ymax);
+}
+
+void
+GRectMapper::unmap(GRect &rect)
+{
+ unmap(rect.xmin, rect.ymin);
+ unmap(rect.xmax, rect.ymax);
+ if (rect.xmin >= rect.xmax)
+ iswap(rect.xmin, rect.xmax);
+ if (rect.ymin >= rect.ymax)
+ iswap(rect.ymin, rect.ymax);
+}
+
+GRect
+GRectMapper::get_input()
+{
+ return rectFrom;
+}
+
+GRect
+GRectMapper::get_output()
+{
+ return rectTo;
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/GRect.h b/kviewshell/plugins/djvu/libdjvu/GRect.h
new file mode 100644
index 00000000..1a86f80d
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GRect.h
@@ -0,0 +1,407 @@
+//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: GRect.h,v 1.9 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _GRECT_H_
+#define _GRECT_H_
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+/** @name GRect.h
+ Files #"GRect.h"# and #"GRect.cpp"# implement basic operations on
+ rectangles. Class \Ref{GRect} is used to represent rectangles. Class
+ \Ref{GRectMapper} represent the correspondence between points relative to
+ given rectangles. Class \Ref{GRatio} is used to represent scaling factors
+ as rational numbers.
+ @memo
+ Rectangle manipulation class.
+ @author
+ L\'eon Bottou <leonb@research.att.com> -- initial implementation.
+ @version
+ #$Id: GRect.h,v 1.9 2003/11/07 22:08:21 leonb Exp $# */
+//@{
+
+#include "DjVuGlobal.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+
+/** @name Point Coordinates vs. Pixel Coordinates
+
+ The DjVu technology relies on the accurate superposition of images at
+ different resolutions. Such an accuracy cannot be reached with the usual
+ assumption that pixels are small enough to be considered infinitesimally
+ small. We must distinguish very precisely ``points'' and ``pixels''.
+ This distinction is essential for performing scaling operations.
+
+ The pixels of an image are identified by ``pixel coordinates''. The
+ bottom-left corner pixel has coordinates #(0,0)# and the top-right corner
+ pixel has coordinates #(w-1,h-1)# where #w# and #h# are the image size.
+ Pixel coordinates are necessarily integers since pixels never overlap.
+
+ An infinitesimally small point is identified by its ``point coordinates''.
+ There may be fractional point coordinates, although this library does not
+ make use of them. Points with integer coordinates are located {\em on the
+ corners of each pixel}. They are not located on the pixel centers. The
+ center of the pixel with pixel coordinates #(i,j)# is located at point
+ coordinates #(i+1/2,j+1/2)#. In other words, the pixel #(i,j)# extends
+ from point #(i,j)# to point #(i+1,j+1)#.
+
+ Therefore, the point located on the bottom left corner of an image has
+ coordinates #(0,0)#. This point is in fact the bottom left corner of the
+ bottom left pixel of the image. The point located on the top right corner
+ of an image has coordinates #(w,h)# where #w# and #h# are the image size.
+ This is in fact the top right corner of pixel #(w-1,h-1)# which is the
+ image pixel with the highest coordinates.
+*/
+//@{
+//@}
+
+
+
+/** Rectangle class. Each instance of this class represents a rectangle whose
+ sides are parallel to the axis. Such a rectangle represents all the points
+ whose coordinates lies between well defined minimal and maximal values.
+ Member functions can combine several rectangles by computing the
+ intersection of rectangles (\Ref{intersect}) or the smallest rectangle
+ enclosing two rectangles (\Ref{recthull}). */
+
+class GRect
+{
+public:
+ /** #OrientationBits# defines 3 mutually exclusive
+ bits to indicate the image orientation.
+
+ There are four possible rotation values for an image
+ which are 0 degrees, 90 degrees, 180 degrees, and 270 degrees.
+ In addition the image can be mirrored backwards in any of these
+ orientations, giving a possible of 8 orientations. To sanely deal
+ with these orientations, we have defined 3 mutually exclusive
+ bits. These are BOTTOM_UP, MIRROR, and ROTATE90_CW.
+ */
+ enum OrientationBits
+ {
+ BOTTOM_UP=0x1, /* Upside down */
+ MIRROR=0x2, /* Written backwards. (right to left) */
+ ROTATE90_CW=0x4 /* rotated 90 degrees */
+ };
+
+ /** #Orientations# defines all 8 possible orientations, using
+ the three \Ref{OrientationBits}.
+ \begin{itemize}
+ \item {\em TDLRNR} for Top Down, Left to Right, No Rotation.
+ \item {\em BULRNR} for Bottom Up, Left to Right, No Rotation.
+ \item {\em TDRLNR} for Top Down, Right to Left, No Rotation.
+ \item {\em BURLNR} for Bottom Up, Right to Left, No Rotation.
+ \item {\em TDLRCW} for Top Down, Left to Right, 90 degree CW rotation.
+ \item {\em BULRCW} for Bottom Up, Left to Right, 90 degree CW rotation.
+ \item {\em TDRLCW} for Top Down, Right to Left, 90 degree CW rotation.
+ \item {\em BURLCW} for Bottom Up, Right to Left, 90 degree CW rotation.
+ \end{itemize}
+ */
+ enum Orientations
+ {
+ TDLRNR=0, /* normal orientation */
+ BULRNR=BOTTOM_UP, /* upside down */
+ TDRLNR=MIRROR, /* backwards (right to left) */
+ BURLNR=MIRROR|BOTTOM_UP, /* rotate 180 */
+ TDLRCW=ROTATE90_CW, /* rotated 90 */
+ BULRCW=ROTATE90_CW|BOTTOM_UP, /* backwards and rotate 180 */
+ TDRLCW=ROTATE90_CW|MIRROR, /* backwards and rotate 90 */
+ BURLCW=ROTATE90_CW|MIRROR|BOTTOM_UP /* rotate 270 */
+ };
+
+ static Orientations
+ rotate(const int angle,Orientations orientation)
+ {
+ for(int a=(((angle)%360)+405)%360;a>90;a-=90)
+ orientation=(Orientations)((int)orientation^(int)(orientation&ROTATE90_CW)?BURLCW:TDLRCW);
+ return orientation;
+ }
+
+ static int
+ findangle(const Orientations orientation)
+ {
+ int a=270;
+ while(a&&(rotate(a,BURLNR)!=orientation)&&(rotate(a,TDRLNR)!=orientation))
+ a-=90;
+ return a;
+ }
+
+ /** Constructs an empty rectangle */
+ GRect();
+ /** Constructs a rectangle given its minimal coordinates #xmin# and #ymin#,
+ and its measurements #width# and #height#. Setting #width# or #height# to zero
+ produces an empty rectangle. */
+ GRect(int xmin, int ymin, unsigned int width=0, unsigned int height=0);
+ /** Returns the rectangle width. */
+ int width() const;
+ /** Returns the rectangle height. */
+ int height() const;
+ /** Returns the area of the rectangle. */
+ int area() const;
+ /** Returns true if the rectangle is empty. */
+ int isempty() const;
+ /** Returns true if the rectangle contains pixel (#x#,#y#). A rectangle
+ contains all pixels with horizontal pixel coordinates in range #xmin#
+ (inclusive) to #xmax# (exclusive) and vertical coordinates #ymin#
+ (inclusive) to #ymax# (exclusive). */
+ int contains(int x, int y) const;
+ /** Returns true if this rectangle contains the passed rectangle #rect#.
+ The function basically checks, that the intersection of this rectangle
+ with #rect# is #rect#. */
+ int contains(const GRect & rect) const;
+ /** Returns true if rectangles #r1# and #r2# are equal. */
+ friend int operator==(const GRect & r1, const GRect & r2);
+ /** Returns true if rectangles #r1# and #r2# are not equal. */
+ friend int operator!=(const GRect & r1, const GRect & r2);
+ /** Resets the rectangle to the empty rectangle */
+ void clear();
+ /** Fatten the rectangle. Both vertical sides of the rectangle are pushed
+ apart by #dx# units. Both horizontal sides of the rectangle are pushed
+ apart by #dy# units. Setting arguments #dx# (resp. #dy#) to a negative
+ value reduces the rectangle horizontal (resp. vertical) size. */
+ int inflate(int dx, int dy);
+ /** Translate the rectangle. The new rectangle is composed of all the points
+ of the old rectangle translated by #dx# units horizontally and #dy#
+ units vertically. */
+ int translate(int dx, int dy);
+ /** Sets the rectangle to the intersection of rectangles #rect1# and #rect2#.
+ This function returns true if the intersection rectangle is not empty. */
+ int intersect(const GRect &rect1, const GRect &rect2);
+ /** Sets the rectangle to the smallest rectangle containing the points of
+ both rectangles #rect1# and #rect2#. This function returns true if the
+ created rectangle is not empty. */
+ int recthull(const GRect &rect1, const GRect &rect2);
+ /** Multiplies xmin, ymin, xmax, ymax by factor and scales the rectangle*/
+ void scale(float factor);
+ /** Multiplies xmin, xmax by xfactor and ymin, ymax by yfactor and scales the rectangle*/
+ void scale(float xfactor, float yfactor);
+ /** Minimal horizontal point coordinate of the rectangle. */
+ int xmin;
+ /** Minimal vertical point coordinate of the rectangle. */
+ int ymin;
+ /** Maximal horizontal point coordinate of the rectangle. */
+ int xmax;
+ /** Maximal vertical point coordinate of the rectangle. */
+ int ymax;
+};
+
+
+/** Maps points from one rectangle to another rectangle. This class
+ represents a relation between the points of two rectangles. Given the
+ coordinates of a point in the first rectangle (input rectangle), function
+ \Ref{map} computes the coordinates of the corresponding point in the
+ second rectangle (the output rectangle). This function actually implements
+ an affine transform which maps the corners of the first rectangle onto the
+ matching corners of the second rectangle. The scaling operation is
+ performed using integer fraction arithmetic in order to maximize
+ accuracy. */
+class GRectMapper
+{
+public:
+ /** Constructs a rectangle mapper. */
+ GRectMapper();
+ /** Resets the rectangle mapper state. Both the input rectangle
+ and the output rectangle are marked as undefined. */
+ void clear();
+ /** Sets the input rectangle. */
+ void set_input(const GRect &rect);
+ /** Returns the input rectangle. */
+ GRect get_input();
+ /** Sets the output rectangle. */
+ void set_output(const GRect &rect);
+ /** Returns the output rectangle. */
+ GRect get_output();
+ /** Composes the affine transform with a rotation of #count# quarter turns
+ counter-clockwise. This operation essentially is a modification of the
+ match between the corners of the input rectangle and the corners of the
+ output rectangle. */
+ void rotate(int count=1);
+ /** Composes the affine transform with a symmetry with respect to the
+ vertical line crossing the center of the output rectangle. This
+ operation essentially is a modification of the match between the corners
+ of the input rectangle and the corners of the output rectangle. */
+ void mirrorx();
+ /** Composes the affine transform with a symmetry with respect to the
+ horizontal line crossing the center of the output rectangle. This
+ operation essentially is a modification of the match between the corners
+ of the input rectangle and the corners of the output rectangle. */
+ void mirrory();
+ /** Maps a point according to the affine transform. Variables #x# and #y#
+ initially contain the coordinates of a point. This operation overwrites
+ these variables with the coordinates of a second point located in the
+ same position relative to the corners of the output rectangle as the
+ first point relative to the matching corners of the input rectangle.
+ Coordinates are rounded to the nearest integer. */
+ void map(int &x, int &y);
+ /** Maps a rectangle according to the affine transform. This operation
+ consists in mapping the rectangle corners and reordering the corners in
+ the canonical rectangle representation. Variable #rect# is overwritten
+ with the new rectangle coordinates. */
+ void map(GRect &rect);
+ /** Maps a point according to the inverse of the affine transform.
+ Variables #x# and #y# initially contain the coordinates of a point. This
+ operation overwrites these variables with the coordinates of a second
+ point located in the same position relative to the corners of input
+ rectangle as the first point relative to the matching corners of the
+ input rectangle. Coordinates are rounded to the nearest integer. */
+ void unmap(int &x, int &y);
+ /** Maps a rectangle according to the inverse of the affine transform. This
+ operation consists in mapping the rectangle corners and reordering the
+ corners in the canonical rectangle representation. Variable #rect# is
+ overwritten with the new rectangle coordinates. */
+ void unmap(GRect &rect);
+private:
+ // GRatio
+ struct GRatio {
+ GRatio ();
+ GRatio (int p, int q);
+ int p;
+ int q;
+ };
+ // Data
+ GRect rectFrom;
+ GRect rectTo;
+ int code;
+ // Helper
+ void precalc();
+ friend int operator*(int n, GRatio r );
+ friend int operator/(int n, GRatio r );
+ GRatio rw;
+ GRatio rh;
+};
+
+
+//@}
+
+
+
+// ---- INLINES
+
+inline
+GRect::GRect()
+: xmin(0), ymin(0), xmax(0), ymax(0)
+{
+}
+
+inline
+GRect::GRect(int xmin, int ymin, unsigned int width, unsigned int height)
+: xmin(xmin), ymin(ymin), xmax(xmin+width), ymax(ymin+height)
+{
+}
+
+inline int
+GRect::width() const
+{
+ return xmax - xmin;
+}
+
+inline int
+GRect::height() const
+{
+ return ymax - ymin;
+}
+
+inline int
+GRect::isempty() const
+{
+ return (xmin>=xmax || ymin>=ymax);
+}
+
+inline int
+GRect::area() const
+{
+ return isempty() ? 0 : (xmax-xmin)*(ymax-ymin);
+}
+
+inline int
+GRect::contains(int x, int y) const
+{
+ return (x>=xmin && x<xmax && y>=ymin && y<ymax);
+}
+
+inline void
+GRect::clear()
+{
+ xmin = xmax = ymin = ymax = 0;
+}
+
+inline int
+operator!=(const GRect & r1, const GRect & r2)
+{
+ return !(r1==r2);
+}
+
+// ---- THE END
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/GScaler.cpp b/kviewshell/plugins/djvu/libdjvu/GScaler.cpp
new file mode 100644
index 00000000..0eeb9ebf
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GScaler.cpp
@@ -0,0 +1,706 @@
+//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: GScaler.cpp,v 1.11 2004/06/03 14:15:18 leonb Exp $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+// Rescale images with fast bilinear interpolation
+// From: Leon Bottou, 1/31/2002
+// Almost equal to my initial code.
+
+#include "GScaler.h"
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+////////////////////////////////////////
+// CONSTANTS
+
+
+#define FRACBITS 4
+#define FRACSIZE (1<<FRACBITS)
+#define FRACSIZE2 (FRACSIZE>>1)
+#define FRACMASK (FRACSIZE-1)
+
+
+
+
+
+
+////////////////////////////////////////
+// UTILITIES
+
+
+static int interp_ok = 0;
+static short interp[FRACSIZE][512];
+
+static void
+prepare_interp()
+{
+ if (! interp_ok)
+ {
+ interp_ok = 1;
+ for (int i=0; i<FRACSIZE; i++)
+ {
+ short *deltas = & interp[i][256];
+ for (int j = -255; j <= 255; j++)
+ deltas[j] = ( j*i + FRACSIZE2 ) >> FRACBITS;
+ }
+ }
+}
+
+
+static inline int
+mini(int x, int y)
+{
+ return (x < y ? x : y);
+}
+
+
+static inline int
+maxi(int x, int y)
+{
+ return (x > y ? x : y);
+}
+
+
+
+
+
+
+////////////////////////////////////////
+// GSCALER
+
+
+GScaler::GScaler()
+ : inw(0), inh(0),
+ xshift(0), yshift(0), redw(0), redh(0),
+ outw(0), outh(0),
+ gvcoord(vcoord,0), ghcoord(hcoord,0)
+{
+}
+
+
+GScaler::~GScaler()
+{
+}
+
+
+void
+GScaler::set_input_size(int w, int h)
+{
+ inw = w;
+ inh = h;
+ if (vcoord)
+ {
+ gvcoord.resize(0);
+ }
+ if (hcoord)
+ {
+ ghcoord.resize(0);
+ }
+}
+
+
+void
+GScaler::set_output_size(int w, int h)
+{
+ outw = w;
+ outh = h;
+ if (vcoord)
+ {
+ gvcoord.resize(0);
+ }
+ if (hcoord)
+ {
+ ghcoord.resize(0);
+ }
+}
+
+
+static void
+prepare_coord(int *coord, int inmax, int outmax, int in, int out)
+{
+ int len = (in*FRACSIZE);
+ int beg = (len+out)/(2*out) - FRACSIZE2;
+ // Bresenham algorithm
+ int y = beg;
+ int z = out/2;
+ int inmaxlim = (inmax-1)*FRACSIZE;
+ for (int x=0; x<outmax; x++)
+ {
+ coord[x] = mini(y,inmaxlim);
+ z = z + len;
+ y = y + z / out;
+ z = z % out;
+ }
+ // Result must fit exactly
+ if (out==outmax && y!=beg+len)
+ G_THROW( ERR_MSG("GScaler.assertion") );
+}
+
+
+void
+GScaler::set_horz_ratio(int numer, int denom)
+{
+ if (! (inw>0 && inh>0 && outw>0 && outh>0))
+ G_THROW( ERR_MSG("GScaler.undef_size") );
+ // Implicit ratio (determined by the input/output sizes)
+ if (numer==0 && denom==0) {
+ numer = outw;
+ denom = inw;
+ } else if (numer<=0 || denom<=0)
+ G_THROW( ERR_MSG("GScaler.ratios") );
+ // Compute horz reduction
+ xshift = 0;
+ redw = inw;
+ while (numer+numer < denom) {
+ xshift += 1;
+ redw = (redw + 1) >> 1;
+ numer = numer << 1;
+ }
+ // Compute coordinate table
+ if (! hcoord)
+ ghcoord.resize(outw);
+ prepare_coord(hcoord, redw, outw, denom, numer);
+}
+
+
+void
+GScaler::set_vert_ratio(int numer, int denom)
+{
+ if (! (inw>0 && inh>0 && outw>0 && outh>0))
+ G_THROW( ERR_MSG("GScaler.undef_size") );
+ // Implicit ratio (determined by the input/output sizes)
+ if (numer==0 && denom==0) {
+ numer = outh;
+ denom = inh;
+ } else if (numer<=0 || denom<=0)
+ G_THROW( ERR_MSG("GScaler.ratios") );
+ // Compute horz reduction
+ yshift = 0;
+ redh = inh;
+ while (numer+numer < denom) {
+ yshift += 1;
+ redh = (redh + 1) >> 1;
+ numer = numer << 1;
+ }
+ // Compute coordinate table
+ if (! vcoord)
+ {
+ gvcoord.resize(outh);
+ }
+ prepare_coord(vcoord, redh, outh, denom, numer);
+}
+
+
+void
+GScaler::make_rectangles(const GRect &desired, GRect &red, GRect &inp)
+{
+ // Parameter validation
+ if (desired.xmin<0 || desired.ymin<0 ||
+ desired.xmax>outw || desired.ymax>outh )
+ G_THROW( ERR_MSG("GScaler.too_big") );
+ // Compute ratio (if not done yet)
+ if (!vcoord)
+ set_vert_ratio(0,0);
+ if (!hcoord)
+ set_horz_ratio(0,0);
+ // Compute reduced bounds
+ red.xmin = (hcoord[desired.xmin]) >> FRACBITS;
+ red.ymin = (vcoord[desired.ymin]) >> FRACBITS;
+ red.xmax = (hcoord[desired.xmax-1]+FRACSIZE-1) >> FRACBITS;
+ red.ymax = (vcoord[desired.ymax-1]+FRACSIZE-1) >> FRACBITS;
+ // Borders
+ red.xmin = maxi(red.xmin, 0);
+ red.xmax = mini(red.xmax+1, redw);
+ red.ymin = maxi(red.ymin, 0);
+ red.ymax = mini(red.ymax+1, redh);
+ // Input
+ inp.xmin = maxi(red.xmin<<xshift, 0);
+ inp.xmax = mini(red.xmax<<xshift, inw);
+ inp.ymin = maxi(red.ymin<<yshift, 0);
+ inp.ymax = mini(red.ymax<<yshift, inh);
+}
+
+
+void
+GScaler::get_input_rect( const GRect &desired_output, GRect &required_input )
+{
+ GRect red;
+ make_rectangles(desired_output, red, required_input);
+}
+
+
+
+
+
+
+////////////////////////////////////////
+// GBITMAPSCALER
+
+
+GBitmapScaler::GBitmapScaler()
+ : glbuffer(lbuffer,0), gconv(conv,0), gp1(p1,0), gp2(p2,0)
+{
+}
+
+
+GBitmapScaler::GBitmapScaler(int inw, int inh, int outw, int outh)
+ : glbuffer(lbuffer,0), gconv(conv,0), gp1(p1,0), gp2(p2,0)
+{
+ set_input_size(inw, inh);
+ set_output_size(outw, outh);
+}
+
+
+GBitmapScaler::~GBitmapScaler()
+{
+}
+
+
+unsigned char *
+GBitmapScaler::get_line(int fy,
+ const GRect &required_red,
+ const GRect &provided_input,
+ const GBitmap &input )
+{
+ if (fy < required_red.ymin)
+ fy = required_red.ymin;
+ else if (fy >= required_red.ymax)
+ fy = required_red.ymax - 1;
+ // Cached line
+ if (fy == l2)
+ return p2;
+ if (fy == l1)
+ return p1;
+ // Shift
+ unsigned char *p = p1;
+ p1 = p2;
+ l1 = l2;
+ p2 = p;
+ l2 = fy;
+ if (xshift==0 && yshift==0)
+ {
+ // Fast mode
+ int dx = required_red.xmin-provided_input.xmin;
+ int dx1 = required_red.xmax-provided_input.xmin;
+ const unsigned char *inp1 = input[fy-provided_input.ymin] + dx;
+ while (dx++ < dx1)
+ *p++ = conv[*inp1++];
+ return p2;
+ }
+ else
+ {
+ // Compute location of line
+ GRect line;
+ line.xmin = required_red.xmin << xshift;
+ line.xmax = required_red.xmax << xshift;
+ line.ymin = fy << yshift;
+ line.ymax = (fy+1) << yshift;
+ line.intersect(line, provided_input);
+ line.translate(-provided_input.xmin, -provided_input.ymin);
+ // Prepare variables
+ const unsigned char *botline = input[line.ymin];
+ int rowsize = input.rowsize();
+ int sw = 1<<xshift;
+ int div = xshift+yshift;
+ int rnd = 1<<(div-1);
+ // Compute averages
+ for (int x=line.xmin; x<line.xmax; x+=sw,p++)
+ {
+ int g=0, s=0;
+ const unsigned char *inp0 = botline + x;
+ int sy1 = mini(line.height(), (1<<yshift));
+ for (int sy=0; sy<sy1; sy++,inp0+=rowsize)
+ {
+ const unsigned char *inp1;
+ const unsigned char *inp2 = inp0 + mini(x+sw, line.xmax) - x;
+ for (inp1=inp0; inp1<inp2; inp1++)
+ {
+ g += conv[*inp1];
+ s += 1;
+ }
+ }
+ if (s == rnd+rnd)
+ *p = (g+rnd)>>div;
+ else
+ *p = (g+s/2)/s;
+ }
+ // Return
+ return p2;
+ }
+}
+
+
+void
+GBitmapScaler::scale( const GRect &provided_input, const GBitmap &input,
+ const GRect &desired_output, GBitmap &output )
+{
+ // Compute rectangles
+ GRect required_input;
+ GRect required_red;
+ make_rectangles(desired_output, required_red, required_input);
+ // Parameter validation
+ if (provided_input.width() != (int)input.columns() ||
+ provided_input.height() != (int)input.rows() )
+ G_THROW( ERR_MSG("GScaler.no_match") );
+ if (provided_input.xmin > required_input.xmin ||
+ provided_input.ymin > required_input.ymin ||
+ provided_input.xmax < required_input.xmax ||
+ provided_input.ymax < required_input.ymax )
+ G_THROW( ERR_MSG("GScaler.too_small") );
+ // Adjust output pixmap
+ if (desired_output.width() != (int)output.columns() ||
+ desired_output.height() != (int)output.rows() )
+ output.init(desired_output.height(), desired_output.width());
+ output.set_grays(256);
+ // Prepare temp stuff
+ gp1.resize(0);
+ gp2.resize(0);
+ glbuffer.resize(0);
+ prepare_interp();
+ const int bufw = required_red.width();
+ glbuffer.resize(bufw+2);
+ gp1.resize(bufw);
+ gp2.resize(bufw);
+ l1 = l2 = -1;
+ // Prepare gray conversion array (conv)
+ gconv.resize(0);
+ gconv.resize(256);
+ int maxgray = input.get_grays()-1;
+ for (int i=0; i<256; i++)
+ {
+ conv[i]=(i<= maxgray)
+ ?(((i*255) + (maxgray>>1)) / maxgray)
+ :255;
+ }
+ // Loop on output lines
+ for (int y=desired_output.ymin; y<desired_output.ymax; y++)
+ {
+ // Perform vertical interpolation
+ {
+ int fy = vcoord[y];
+ int fy1 = fy>>FRACBITS;
+ int fy2 = fy1+1;
+ const unsigned char *lower, *upper;
+ // Obtain upper and lower line in reduced image
+ lower = get_line(fy1, required_red, provided_input, input);
+ upper = get_line(fy2, required_red, provided_input, input);
+ // Compute line
+ unsigned char *dest = lbuffer+1;
+ const short *deltas = & interp[fy&FRACMASK][256];
+ for(unsigned char const * const edest=(unsigned char const *)dest+bufw;
+ dest<edest;upper++,lower++,dest++)
+ {
+ const int l = *lower;
+ const int u = *upper;
+ *dest = l + deltas[u-l];
+ }
+ }
+ // Perform horizontal interpolation
+ {
+ // Prepare for side effects
+ lbuffer[0] = lbuffer[1];
+ lbuffer[bufw] = lbuffer[bufw];
+ unsigned char *line = lbuffer+1-required_red.xmin;
+ unsigned char *dest = output[y-desired_output.ymin];
+ // Loop horizontally
+ for (int x=desired_output.xmin; x<desired_output.xmax; x++)
+ {
+ int n = hcoord[x];
+ const unsigned char *lower = line + (n>>FRACBITS);
+ const short *deltas = &interp[n&FRACMASK][256];
+ int l = lower[0];
+ int u = lower[1];
+ *dest = l + deltas[u-l];
+ dest++;
+ }
+ }
+ }
+ // Free temporaries
+ gp1.resize(0);
+ gp2.resize(0);
+ glbuffer.resize(0);
+ gconv.resize(0);
+}
+
+
+
+
+
+
+////////////////////////////////////////
+// GPIXMAPSCALER
+
+
+GPixmapScaler::GPixmapScaler()
+ : glbuffer((void *&)lbuffer,0,sizeof(GPixel)),
+ gp1((void *&)p1,0,sizeof(GPixel)),
+ gp2((void *&)p2,0,sizeof(GPixel))
+{
+}
+
+
+GPixmapScaler::GPixmapScaler(int inw, int inh, int outw, int outh)
+ : glbuffer((void *&)lbuffer,0,sizeof(GPixel)),
+ gp1((void *&)p1,0,sizeof(GPixel)),
+ gp2((void *&)p2,0,sizeof(GPixel))
+{
+ set_input_size(inw, inh);
+ set_output_size(outw, outh);
+}
+
+
+GPixmapScaler::~GPixmapScaler()
+{
+}
+
+
+GPixel *
+GPixmapScaler::get_line(int fy,
+ const GRect &required_red,
+ const GRect &provided_input,
+ const GPixmap &input )
+{
+ if (fy < required_red.ymin)
+ fy = required_red.ymin;
+ else if (fy >= required_red.ymax)
+ fy = required_red.ymax - 1;
+ // Cached line
+ if (fy == l2)
+ return p2;
+ if (fy == l1)
+ return p1;
+ // Shift
+ GPixel *p=p1;
+ p1 = p2;
+ l1 = l2;
+ p2 = p;
+ l2 = fy;
+ // Compute location of line
+ GRect line;
+ line.xmin = required_red.xmin << xshift;
+ line.xmax = required_red.xmax << xshift;
+ line.ymin = fy << yshift;
+ line.ymax = (fy+1) << yshift;
+ line.intersect(line, provided_input);
+ line.translate(-provided_input.xmin, -provided_input.ymin);
+ // Prepare variables
+ const GPixel *botline = input[line.ymin];
+ int rowsize = input.rowsize();
+ int sw = 1<<xshift;
+ int div = xshift+yshift;
+ int rnd = 1<<(div-1);
+ // Compute averages
+ for (int x=line.xmin; x<line.xmax; x+=sw,p++)
+ {
+ int r=0, g=0, b=0, s=0;
+ const GPixel *inp0 = botline + x;
+ int sy1 = mini(line.height(), (1<<yshift));
+ for (int sy=0; sy<sy1; sy++,inp0+=rowsize)
+ {
+ const GPixel *inp1;
+ const GPixel *inp2 = inp0 + mini(x+sw, line.xmax) - x;
+ for (inp1 = inp0; inp1<inp2; inp1++)
+ {
+ r += inp1->r;
+ g += inp1->g;
+ b += inp1->b;
+ s += 1;
+ }
+ }
+ if (s == rnd+rnd)
+ {
+ p->r = (r+rnd) >> div;
+ p->g = (g+rnd) >> div;
+ p->b = (b+rnd) >> div;
+ }
+ else
+ {
+ p->r = (r+s/2)/s;
+ p->g = (g+s/2)/s;
+ p->b = (b+s/2)/s;
+ }
+ }
+ // Return
+ return (GPixel *)p2;
+}
+
+
+void
+GPixmapScaler::scale( const GRect &provided_input, const GPixmap &input,
+ const GRect &desired_output, GPixmap &output )
+{
+ // Compute rectangles
+ GRect required_input;
+ GRect required_red;
+ make_rectangles(desired_output, required_red, required_input);
+ // Parameter validation
+ if (provided_input.width() != (int)input.columns() ||
+ provided_input.height() != (int)input.rows() )
+ G_THROW( ERR_MSG("GScaler.no_match") );
+ if (provided_input.xmin > required_input.xmin ||
+ provided_input.ymin > required_input.ymin ||
+ provided_input.xmax < required_input.xmax ||
+ provided_input.ymax < required_input.ymax )
+ G_THROW( ERR_MSG("GScaler.too_small") );
+ // Adjust output pixmap
+ if (desired_output.width() != (int)output.columns() ||
+ desired_output.height() != (int)output.rows() )
+ output.init(desired_output.height(), desired_output.width());
+ // Prepare temp stuff
+ gp1.resize(0,sizeof(GPixel));
+ gp2.resize(0,sizeof(GPixel));
+ glbuffer.resize(0,sizeof(GPixel));
+ prepare_interp();
+ const int bufw = required_red.width();
+ glbuffer.resize(bufw+2,sizeof(GPixel));
+ if (xshift>0 || yshift>0)
+ {
+ gp1.resize(bufw,sizeof(GPixel));
+ gp2.resize(bufw,sizeof(GPixel));
+ l1 = l2 = -1;
+ }
+ // Loop on output lines
+ for (int y=desired_output.ymin; y<desired_output.ymax; y++)
+ {
+ // Perform vertical interpolation
+ {
+ int fy = vcoord[y];
+ int fy1 = fy>>FRACBITS;
+ int fy2 = fy1+1;
+ const GPixel *lower, *upper;
+ // Obtain upper and lower line in reduced image
+ if (xshift>0 || yshift>0)
+ {
+ lower = get_line(fy1, required_red, provided_input, input);
+ upper = get_line(fy2, required_red, provided_input, input);
+ }
+ else
+ {
+ int dx = required_red.xmin-provided_input.xmin;
+ fy1 = maxi(fy1, required_red.ymin);
+ fy2 = mini(fy2, required_red.ymax-1);
+ lower = input[fy1-provided_input.ymin] + dx;
+ upper = input[fy2-provided_input.ymin] + dx;
+ }
+ // Compute line
+ GPixel *dest = lbuffer+1;
+ const short *deltas = & interp[fy&FRACMASK][256];
+ for(GPixel const * const edest = (GPixel const *)dest+bufw;
+ dest<edest;upper++,lower++,dest++)
+ {
+ const int lower_r = lower->r;
+ const int delta_r = deltas[(int)upper->r - lower_r];
+ dest->r = lower_r + delta_r;
+ const int lower_g = lower->g;
+ const int delta_g = deltas[(int)upper->g - lower_g];
+ dest->g = lower_g + delta_g;
+ const int lower_b = lower->b;
+ const int delta_b = deltas[(int)upper->b - lower_b];
+ dest->b = lower_b + delta_b;
+ }
+ }
+ // Perform horizontal interpolation
+ {
+ // Prepare for side effects
+ lbuffer[0] = lbuffer[1];
+ lbuffer[bufw] = lbuffer[bufw];
+ GPixel *line = lbuffer+1-required_red.xmin;
+ GPixel *dest = output[y-desired_output.ymin];
+ // Loop horizontally
+ for (int x=desired_output.xmin; x<desired_output.xmax; x++,dest++)
+ {
+ const int n = hcoord[x];
+ const GPixel *lower = line + (n>>FRACBITS);
+ const short *deltas = &interp[n&FRACMASK][256];
+ const int lower_r = lower[0].r;
+ const int delta_r = deltas[(int)lower[1].r - lower_r];
+ dest->r = lower_r + delta_r;
+ const int lower_g = lower[0].g;
+ const int delta_g = deltas[(int)lower[1].g - lower_g];
+ dest->g = lower_g + delta_g;
+ const int lower_b = lower[0].b;
+ const int delta_b = deltas[(int)lower[1].b - lower_b];
+ dest->b = lower_b + delta_b;
+ }
+ }
+ }
+ // Free temporaries
+ gp1.resize(0,sizeof(GPixel));
+ gp2.resize(0,sizeof(GPixel));
+ glbuffer.resize(0,sizeof(GPixel));
+}
+
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+
diff --git a/kviewshell/plugins/djvu/libdjvu/GScaler.h b/kviewshell/plugins/djvu/libdjvu/GScaler.h
new file mode 100644
index 00000000..4843f6d0
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GScaler.h
@@ -0,0 +1,321 @@
+//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: GScaler.h,v 1.9 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _GSCALER_H_
+#define _GSCALER_H_
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+// From: Leon Bottou, 1/31/2002
+// Almost equal to my initial code.
+
+#include "GException.h"
+#include "GRect.h"
+#include "GBitmap.h"
+#include "GPixmap.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+/** @name GScaler.h
+
+ Files #"GScaler.h"# and #"GScaler.cpp"# implement a fast bilinear
+ interpolation scheme to rescale a \Ref{GBitmap} or a \Ref{GPixmap}.
+ Common setup functions are implemented by the base class \Ref{GScaler}.
+ The actual function for rescaling a gray level image is implemented by
+ class \Ref{GBitmapScaler}. The actual function for rescaling a color
+ image is implemented by class \Ref{GPixmapScaler}.
+
+ {\bf Remark} --- The bilinear interpolation code relies on fixed precision
+ tables. It becomes suboptimal when upsampling (i.e. zooming into) an
+ image by a factor greater than eight. High contrast images displayed at
+ high magnification may contain visible jaggies.
+
+ @memo
+ Rescaling images with bilinear interpolation.
+ @author
+ L\'eon Bottou <leonb@research.att.com>
+ @version
+ #$Id: GScaler.h,v 1.9 2003/11/07 22:08:21 leonb Exp $# */
+//@{
+
+
+/** Base class for GBitmapScaler and GPixmapScaler. This base class
+ implements the common elements of class \Ref{GBitmapScaler} and
+ \Ref{GPixmapScaler}. Functions \Ref{set_input_size} and
+ \Ref{set_output_size} are used to specify the size of the input image and
+ the size of the output image. Functions \Ref{set_horz_ratio} and
+ \Ref{set_vert_ratio} may be used to override the scaling ratios computed
+ from the image sizes. You can then call function \Ref{get_input_rect} to
+ know which pixels of the input image are necessary to compute a specified
+ rectangular zone of the output image. The actual computation is then
+ performed by calling function #scale# in class \Ref{GBitmapScaler} and
+ \Ref{GPixmapScaler}.
+*/
+class GScaler : public GPEnabled
+{
+protected:
+ GScaler();
+public:
+ virtual ~GScaler();
+ /** Sets the size of the input image. Argument #w# (resp. #h#) contains the
+ horizontal (resp. vertical) size of the input image. This size is used
+ to initialize the internal data structures of the scaler object. */
+ void set_input_size(int w, int h);
+ /** Sets the size of the output image. Argument #w# (resp. #h#) contains the
+ horizontal (resp. vertical) size of the output image. This size is used
+ to initialize the internal data structures of the scaler object. */
+ void set_output_size(int w, int h);
+ /** Sets the horizontal scaling ratio #numer/denom#. This function may be
+ used to force an exact scaling ratio. The scaling ratios are otherwise
+ derived from the sizes of the input and output images. */
+ void set_horz_ratio(int numer, int denom);
+ /** Sets the vertical scaling ratio to #numer/denom#. This function may be
+ used to force an exact scaling ratio. The scaling ratios are otherwise
+ derived from the sizes of the input and output images. */
+ void set_vert_ratio(int numer, int denom);
+ /** Computes which input pixels are required to compute specified output
+ pixels. Let us assume that we only need a part of the output
+ image. This part is defined by rectangle #desired_output#. Only a part
+ of the input image is necessary to compute the output pixels. Function
+ #get_input_rect# computes the coordinates of that part of the input
+ image, and stores them into rectangle #required_input#. */
+ void get_input_rect( const GRect &desired_output, GRect &required_input );
+protected:
+ // The sizes
+ int inw, inh;
+ int xshift, yshift;
+ int redw, redh;
+ int outw, outh;
+ // Fixed point coordinates
+ int *vcoord;
+ GPBuffer<int> gvcoord;
+ int *hcoord;
+ GPBuffer<int> ghcoord;
+ // Helper
+ void make_rectangles(const GRect &desired, GRect &red, GRect &inp);
+};
+
+
+
+/** Fast rescaling code for gray level images. This class augments the base
+ class \Ref{GScaler} with a function for rescaling gray level
+ images. Function \Ref{GBitmapScaler::scale} computes an arbitrary segment
+ of the output image given the corresponding pixels in the input image.
+
+ {\bf Example} --- The following functions returns an gray level image
+ (sixteen gray levels, size #nw# by #nh#) containing a rescaled version of
+ the input image #in#.
+ \begin{verbatim}
+ GBitmap *rescale_bitmap(const GBitmap &in, int nw, int nh)
+ {
+ int w = in.columns(); // Get input width
+ int h = in.raws(); // Get output width
+ GBitmapScaler scaler(w,h,nw,nh); // Creates bitmap scaler
+ GRect desired(0,0,nw,nh); // Desired output = complete bitmap
+ GRect provided(0,0,w,h); // Provided input = complete bitmap
+ GBitmap *out = new GBitmap;
+ scaler.scale(provided, in, desired, *out); // Rescale
+ out->change_grays(16); // Reduce to 16 gray levels
+ return out;
+ }
+ \end{verbatim} */
+class GBitmapScaler : public GScaler
+{
+protected:
+ GBitmapScaler(void);
+ GBitmapScaler(int inw, int inh, int outw, int outh);
+public:
+ /// Virtual destructor.
+ virtual ~GBitmapScaler();
+
+ /** Creates an empty GBitmapScaler. You must call functions
+ \Ref{GScaler::set_input_size} and \Ref{GScaler::set_output_size} before
+ calling any of the scaling functions. */
+ static GP<GBitmapScaler> create(void) {return new GBitmapScaler(); }
+
+ /** Creates a GBitmapScaler. The size of the input image is given by
+ #inw# and #inh#. This function internally calls
+ \Ref{GScaler::set_input_size} and \Ref{GScaler::set_output_size}. The
+ size of the output image is given by #outw# and #outh#. . */
+ static GP<GBitmapScaler> create(
+ const int inw, const int inh, const int outw, const int outh)
+ { return new GBitmapScaler(inw,inh,outw,outh); }
+
+ /** Computes a segment of the rescaled output image. The GBitmap object
+ #output# is overwritten with the segment of the output image specified
+ by the rectangle #desired_output#. The rectangle #provided_input#
+ specifies which segment of the input image is provided by the GBitmap
+ object #input#. An exception \Ref{GException} is thrown if the
+ rectangle #provided_input# is smaller then the rectangle
+ #required_input# returned by function \Ref{GScaler::get_input_rect}.
+ Note that the output image always contain 256 gray levels. You may want
+ to use function \Ref{GBitmap::change_grays} to reduce the number of gray
+ levels. */
+ void scale( const GRect &provided_input, const GBitmap &input,
+ const GRect &desired_output, GBitmap &output );
+protected:
+ // Helpers
+ unsigned char *get_line(int, const GRect &, const GRect &, const GBitmap &);
+ // Temporaries
+ unsigned char *lbuffer;
+ GPBuffer<unsigned char> glbuffer;
+ unsigned char *conv;
+ GPBuffer<unsigned char> gconv;
+ unsigned char *p1;
+ GPBuffer<unsigned char> gp1;
+ unsigned char *p2;
+ GPBuffer<unsigned char> gp2;
+ int l1;
+ int l2;
+};
+
+
+/** Fast rescaling code for color images. This class augments the base class
+ \Ref{GScaler} with a function for rescaling color images. Function
+ \Ref{GPixmapScaler::scale} computes an arbitrary segment of the output
+ image given the corresponding pixels in the input image.
+
+ {\bf Example} --- The following functions returns a color image
+ of size #nw# by #nh# containing a rescaled version of
+ the input image #in#.
+ \begin{verbatim}
+ GPixmap *rescale_pixmap(const GPixmap &in, int nw, int nh)
+ {
+ int w = in.columns(); // Get input width
+ int h = in.raws(); // Get output width
+ GPixmapScaler scaler(w,h,nw,nh); // Creates bitmap scaler
+ GRect desired(0,0,nw,nh); // Desired output = complete image
+ GRect provided(0,0,w,h); // Provided input = complete image
+ GPixmap *out = new GPixmap;
+ scaler.scale(provided, in, desired, *out); // Rescale
+ return out;
+ }
+ \end{verbatim}
+
+ */
+class GPixmapScaler : public GScaler
+{
+protected:
+ GPixmapScaler(void);
+ GPixmapScaler(int inw, int inh, int outw, int outh);
+public:
+ /// Virtual destructor.
+ virtual ~GPixmapScaler();
+
+ /** Creates an empty GPixmapScaler. You must call functions
+ \Ref{GScaler::set_input_size} and \Ref{GScaler::set_output_size} before
+ calling any of the scaling functions. */
+ static GP<GPixmapScaler> create(void) {return new GPixmapScaler(); }
+
+ /** Creates a GPixmapScaler. The size of the input image is given by
+ #inw# and #inh#. This function internally calls
+ \Ref{GScaler::set_input_size} and \Ref{GScaler::set_output_size}. The
+ size of the output image is given by #outw# and #outh#. . */
+ static GP<GPixmapScaler> create(
+ const int inw, const int inh, const int outw, const int outh)
+ { return new GPixmapScaler(inw,inh,outw,outh); }
+
+ /** Computes a segment of the rescaled output image. The pixmap #output# is
+ overwritten with the segment of the output image specified by the
+ rectangle #desired_output#. The rectangle #provided_input# specifies
+ which segment of the input image is provided in the pixmap #input#. An
+ exception \Ref{GException} is thrown if the rectangle #provided_input#
+ is smaller then the rectangle #required_input# returned by function
+ \Ref{GScaler::get_input_rect}. */
+ void scale( const GRect &provided_input, const GPixmap &input,
+ const GRect &desired_output, GPixmap &output );
+protected:
+ // Helpers
+ GPixel *get_line(int, const GRect &, const GRect &, const GPixmap &);
+ // Temporaries
+ GPixel *lbuffer;
+ GPBufferBase glbuffer;
+ GPixel *p1;
+ GPBufferBase gp1;
+ GPixel *p2;
+ GPBufferBase gp2;
+ int l1;
+ int l2;
+};
+
+
+
+
+
+//@}
+
+
+
+
+// -------- END
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/GSmartPointer.cpp b/kviewshell/plugins/djvu/libdjvu/GSmartPointer.cpp
new file mode 100644
index 00000000..8c17755d
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GSmartPointer.cpp
@@ -0,0 +1,256 @@
+//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: GSmartPointer.cpp,v 1.11 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+// - Author: Leon Bottou, 05/1997
+
+// From: Leon Bottou, 1/31/2002
+// Class GPBuffer has been added (but not documented) by Lizardtech.
+// Our original implementation consisted of multiple classes.
+// <http://prdownloads.sourceforge.net/djvu/DjVu2_2b-src.tgz>.
+
+#include <string.h>
+#include "GThreads.h"
+#include "GSmartPointer.h"
+#include "GException.h"
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+// ------ STATIC CRITICAL SECTION
+
+static GCriticalSection gcsCounter;
+
+
+// ------ GPENABLED
+
+
+GPEnabled::~GPEnabled()
+{
+ if (count > 0)
+ G_THROW( ERR_MSG("GSmartPointer.suspicious") );
+}
+
+void
+GPEnabled::destroy()
+{
+ if (count >= 0)
+ G_THROW( ERR_MSG("GSmartPointer.suspicious") );
+ delete this;
+}
+
+void
+GPEnabled::ref()
+{
+ gcsCounter.lock();
+ count++;
+ gcsCounter.unlock();
+}
+
+void
+GPEnabled::unref()
+{
+ gcsCounter.lock();
+ if (! --count)
+ count = -1;
+ gcsCounter.unlock();
+ if (count < 0)
+ destroy();
+}
+
+
+// ------ GPBASE
+
+
+GPBase&
+GPBase::assign (GPEnabled *nptr)
+{
+ gcsCounter.lock();
+ if (nptr)
+ {
+ if (nptr->count >= 0)
+ nptr->count++;
+ else
+ nptr = 0;
+ }
+ if (ptr)
+ {
+ GPEnabled *old = ptr;
+ ptr = nptr;
+ if (! --old->count)
+ old->count = -1;
+ gcsCounter.unlock();
+ if (old->count < 0)
+ old->destroy();
+ }
+ else
+ {
+ ptr = nptr;
+ gcsCounter.unlock();
+ }
+ return *this;
+}
+
+GPBase&
+GPBase::assign (const GPBase &sptr)
+{
+ gcsCounter.lock();
+ if (sptr.ptr)
+ {
+ sptr.ptr->count++;
+ }
+ if (ptr)
+ {
+ GPEnabled *old = ptr;
+ ptr = sptr.ptr;
+ if (! --old->count)
+ old->count = -1;
+ gcsCounter.unlock();
+ if (old->count < 0)
+ old->destroy();
+ }
+ else
+ {
+ ptr = sptr.ptr;
+ gcsCounter.unlock();
+ }
+ return *this;
+}
+
+
+// ------ GPBUFFERBASE
+
+
+void
+GPBufferBase::replace(void *nptr,const size_t n)
+{
+ resize(0,0);
+ ptr=nptr;
+ num=n;
+}
+
+GPBufferBase::GPBufferBase(void *&xptr,const size_t n,const size_t t)
+ : ptr(xptr), num(n)
+{
+ if (n)
+ xptr = ::operator new(n*t);
+ else
+ xptr = 0;
+}
+
+GPBufferBase::~GPBufferBase()
+{
+ ::operator delete(ptr);
+}
+
+void
+GPBufferBase::swap(GPBufferBase &other)
+{
+ void * const temp_ptr=ptr;
+ ptr=other.ptr;
+ other.ptr=temp_ptr;
+ const size_t temp_num=num;
+ num=other.num;
+ other.num=temp_num;
+}
+
+void
+GPBufferBase::resize(const size_t n, const size_t t)
+{
+ if(!n && !ptr)
+ {
+ num=0;
+ }
+ else
+ {
+ const size_t s=ptr?(((num<n)?num:n)*t):0;
+ void *nptr;
+ GPBufferBase gnptr(nptr, n, t);
+ if(s)
+ {
+ memcpy(nptr, ptr, s);
+ }
+ swap(gnptr);
+ }
+}
+
+void
+GPBufferBase::set(const size_t t,const char c)
+{
+ if(num)
+ memset(ptr,c,num*t);
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+
diff --git a/kviewshell/plugins/djvu/libdjvu/GSmartPointer.h b/kviewshell/plugins/djvu/libdjvu/GSmartPointer.h
new file mode 100644
index 00000000..04b79ecf
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GSmartPointer.h
@@ -0,0 +1,489 @@
+//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: GSmartPointer.h,v 1.11 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _GSMARTPOINTER_H_
+#define _GSMARTPOINTER_H_
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+/** @name GSmartPointer.h
+
+ Files #"GSmartPointer.h"# and #"GSmartPointer.cpp"# define a smart-pointer
+ class which automatically performs thread-safe reference counting. Class
+ \Ref{GP} implements smart-pointers by overloading the usual pointer
+ assignment and dereferencing operators. The overloaded operators maintain
+ the reference counters and destroy the pointed objects as soon as their
+ reference counter reaches zero. Transparent type conversions are provided
+ between smart-pointers and regular pointers. Objects referenced by
+ smart-pointers must be derived from class \Ref{GPEnabled}.
+
+ @memo
+ Thread-Safe reference counting smart-pointers.
+ @author
+ L\'eon Bottou <leonb@research.att.com> -- initial implementation\\
+ Andrei Erofeev <eaf@geocities.com> -- bug fix.
+
+// From: Leon Bottou, 1/31/2002
+// Class GPBuffer has been added (but not documented) by Lizardtech.
+// Our original implementation consisted of multiple classes.
+// <http://prdownloads.sourceforge.net/djvu/DjVu2_2b-src.tgz>.
+
+ @version
+ #$Id: GSmartPointer.h,v 1.11 2003/11/07 22:08:21 leonb Exp $#
+ @args
+*/
+//@{
+
+#if defined(_MSC_VER)
+// Language lawyer say MSVC6 is wrong on that one.
+// Cf section 5.4.7 in november 1997 draft.
+#pragma warning( disable : 4243 )
+#endif
+
+#include "DjVuGlobal.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+
+/* What is this innovation ?
+ What does it do that a GArray does not do ? */
+
+class GPBufferBase
+{
+public:
+ GPBufferBase(void *&,const size_t n,const size_t t);
+ void swap(GPBufferBase &p);
+ void resize(const size_t n,const size_t t);
+ void replace(void *nptr,const size_t n);
+ void set(const size_t t,const char c);
+ ~GPBufferBase();
+ operator int(void) const { return ptr ? num : 0; }
+private:
+ void *&ptr;
+ size_t num;
+};
+
+template<class TYPE>
+class GPBuffer : public GPBufferBase
+{
+public:
+ GPBuffer(TYPE *&xptr,const size_t n=0) : GPBufferBase((void *&)xptr,n,sizeof(TYPE)) {}
+ inline void resize(const size_t n) {GPBufferBase::resize(n,sizeof(TYPE));}
+ inline void clear(void) {GPBufferBase::set(sizeof(TYPE),0);}
+ inline void set(const char c) {GPBufferBase::set(sizeof(TYPE),c);}
+ inline operator int(void) const {return GPBufferBase::operator int();}
+};
+
+/** Base class for reference counted objects.
+ This is the base class for all reference counted objects.
+ Any instance of a subclass of #GPEnabled# can be used with
+ smart-pointers (see \Ref{GP}).
+ */
+class GPEnabled
+{
+public:
+ /// Null constructor.
+ GPEnabled();
+ /// Copy construcotr
+ GPEnabled(const GPEnabled & obj);
+ /// Virtual destructor.
+ virtual ~GPEnabled();
+ /// Copy operator
+ GPEnabled & operator=(const GPEnabled & obj);
+ /** Returns the number of references to this object. This should be only
+ used for debugging purposes. Other uses are not thread-safe. */
+ int get_count(void) const;
+protected:
+ /// The reference counter
+ volatile int count;
+private:
+ friend class GPBase;
+ void unref();
+ void ref();
+ void destroy();
+};
+
+
+
+/** Base class for all smart-pointers.
+ This class implements common mechanisms for all
+ smart-pointers (see \Ref{GP}). There should be no need
+ to use this class directly. Its sole purpose consists
+ in reducing the template expansion overhead.
+*/
+
+class GPBase
+{
+public:
+ /** Null Constructor. */
+ GPBase();
+ /** Copy Constructor.
+ Increments the reference count.
+ @param sptr reference to a #GPBase# object. */
+ GPBase(const GPBase &sptr);
+ /** Construct a GPBase from a pointer.
+ Increments the reference count.
+ @param nptr pointer to a #GPEnabled# object. */
+ GPBase(GPEnabled *nptr);
+ /** Destructor. Decrements the reference count. */
+ ~GPBase();
+ /** Accesses the actual pointer. */
+ GPEnabled* get() const;
+ /** Assignment from smartpointer.
+ Increments the counter of the new value of the pointer.
+ Decrements the counter of the previous value of the pointer. */
+ GPBase& assign(const GPBase &sptr);
+ /** Assignment from pointer.
+ Checks that the object is not being destroyed.
+ Increments the counter of the new value of the pointer.
+ Decrements the counter of the previous value of the pointer. */
+ GPBase& assign(GPEnabled *nptr);
+ /** Assignment operator. */
+ GPBase & operator=(const GPBase & obj);
+ /** Comparison operator. */
+ int operator==(const GPBase & g2) const;
+protected:
+ /** Actual pointer */
+ GPEnabled *ptr;
+};
+
+
+/** Reference counting pointer.
+ Class #GP<TYPE># represents a smart-pointer to an object of type #TYPE#.
+ Type #TYPE# must be a subclass of #GPEnabled#. This class overloads the
+ usual pointer assignment and dereferencing operators. The overloaded
+ operators maintain the reference counters and destroy the pointed object
+ as soon as their reference counter reaches zero. Transparent type
+ conversions are provided between smart-pointers and regular pointers.
+
+ Using a smart-pointer is a convenience and not an obligation. There is no
+ need to use a smart-pointer to access a #GPEnabled# object. As long as
+ you never use a smart-pointer to access a #GPEnabled# object, its
+ reference counter remains zero. Since the reference counter is never
+ decremented from one to zero, the object is never destroyed by the
+ reference counting code. You can therefore choose to only use regular
+ pointers to access objects allocated on the stack (automatic variables) or
+ objects allocated dynamically. In the latter case you must explicitly
+ destroy the dynamically allocated object with operator #delete#.
+
+ The first time you use a smart-pointer to access #GPEnabled# object, the
+ reference counter is incremented to one. Object destruction will then
+ happen automatically when the reference counter is decremented back to
+ zero (i.e. when the last smart-pointer referencing this object stops doing so).
+ This will happen regardless of how many regular pointers reference this object.
+ In other words, if you start using smart-pointers with a #GPEnabled#
+ object, you engage automatic mode for this object. You should only do
+ this with objects dynamically allocated with operator #new#. You should
+ never destroy the object yourself, but let the smart-pointers control the
+ life of the object.
+
+ {\bf Performance considerations} --- Thread safe reference counting incurs
+ a significant overhead. Smart-pointer are best used with sizeable objects
+ for which the cost of maintaining the counters represent a small fraction
+ of the processing time. It is always possible to cache a smart-pointer
+ into a regular pointer. The cached pointer will remain valid until the
+ smart-pointer object is destroyed or the smart-pointer value is changed.
+
+ {\bf Safety considerations} --- As explained above, a #GPEnabled# object
+ switches to automatic mode as soon as it becomes referenced by a
+ smart-pointer. There is no way to switch the object back to manual mode.
+ Suppose that you have decided to only use regular pointers with a
+ particular #GPEnabled# object. You therefore plan to destroy the object
+ explicitly when you no longer need it. When you pass a regular pointer to
+ this object as argument to a function, you really need to be certain that
+ the function implementation will not assign this pointer to a
+ smart-pointer. Doing so would indeed destroy the object as soon as the
+ function returns. The bad news is that the fact that a function assigns a
+ pointer argument to a smart-pointer does not necessarily appear in the
+ function prototype. Such a behavior must be {\em documented} with the
+ function public interface. As a convention, we usually write such
+ functions with smart-pointer arguments instead of a regular pointer
+ arguments. This is not enough to catch the error at compile time, but
+ this is a simple way to document such a behavior. We still believe that
+ this is a small problem in regard to the benefits of the smart-pointer.
+ But one has to be aware of its existence. */
+
+template <class TYPE>
+class GP : protected GPBase
+{
+public:
+ /** Constructs a null smart-pointer. */
+ GP();
+ /** Constructs a copy of a smart-pointer.
+ @param sptr smart-pointer to copy. */
+ GP(const GP<TYPE> &sptr);
+ /** Constructs a smart-pointer from a regular pointer.
+ The pointed object must be dynamically allocated (with operator #new#).
+ You should no longer explicitly destroy the object referenced by #sptr#
+ since the object life is now controlled by smart-pointers.
+ @param nptr regular pointer to a {\em dynamically allocated object}. */
+ GP(TYPE *nptr);
+ /** Converts a smart-pointer into a regular pointer.
+ This is useful for caching the value of a smart-pointer for performances
+ purposes. The cached pointer will remain valid until the smart-pointer
+ is destroyed or until the smart-pointer value is changed. */
+ operator TYPE* () const;
+ /** Assigns a regular pointer to a smart-pointer lvalue.
+ The pointed object must be dynamically allocated (with operator #new#).
+ You should no longer explicitly destroy the object referenced by #sptr#
+ since the object life is now controlled by smart-pointers.
+ @param nptr regular pointer to a {\em dynamically allocated object}. */
+ GP<TYPE>& operator= (TYPE *nptr);
+ /** Assigns a smart-pointer to a smart-pointer lvalue.
+ @param sptr smart-pointer copied into this smart-pointer. */
+ GP<TYPE>& operator= (const GP<TYPE> &sptr);
+ /** Indirection operator.
+ This operator provides a convenient access to the members
+ of a smart-pointed object. Operator #-># works with smart-pointers
+ exactly as with regular pointers. */
+ TYPE* operator->() const;
+ /** Dereferencement operator.
+ This operator provides a convenient access to the smart-pointed object.
+ Operator #*# works with smart-pointers exactly as with regular pointers. */
+ TYPE& operator*() const;
+ /** Comparison operator.
+ Returns true if both this smart-pointer and pointer #nptr# point to the
+ same object. The automatic conversion from smart-pointers to regular
+ pointers allows you to compare two smart-pointers as well.
+ @param nptr pointer to compare with. */
+ int operator== (TYPE *nptr) const;
+ /** Comparison operator.
+ Returns true if this smart-pointer and pointer #nptr# point to different
+ objects. The automatic conversion from smart-pointers to regular
+ pointers allows you to compare two smart-pointers as well.
+ @param nptr pointer to compare with. */
+ int operator!= (TYPE *nptr) const;
+ /** Test operator.
+ Returns true if the smart-pointer is null. The automatic conversion
+ from smart-pointers to regular pointers allows you to test whether
+ a smart-pointer is non-null. You can use both following constructs:
+ \begin{verbatim}
+ if (gp) { ... }
+ while (! gp) { ... }
+ \end{verbatim} */
+ int operator! () const;
+};
+
+//@}
+
+// INLINE FOR GPENABLED
+
+inline
+GPEnabled::GPEnabled()
+ : count(0)
+{
+}
+
+inline
+GPEnabled::GPEnabled(const GPEnabled & obj)
+ : count(0)
+{
+
+}
+
+inline int
+GPEnabled::get_count(void) const
+{
+ return count;
+}
+
+inline GPEnabled &
+GPEnabled::operator=(const GPEnabled & obj)
+{
+ /* The copy operator should do nothing because the count should not be
+ changed. Subclasses of GPEnabled will call this version of the copy
+ operator as part of the default 'memberwise copy' strategy. */
+ return *this;
+}
+
+// INLINE FOR GPBASE
+
+inline
+GPBase::GPBase()
+ : ptr(0)
+{
+}
+
+inline
+GPBase::GPBase(GPEnabled *nptr)
+ : ptr(0)
+{
+ assign(nptr);
+}
+
+inline
+GPBase::GPBase(const GPBase &sptr)
+{
+ if (sptr.ptr)
+ sptr.ptr->ref();
+ ptr = sptr.ptr;
+}
+
+inline
+GPBase::~GPBase()
+{
+ GPEnabled *old = ptr;
+ ptr = 0;
+ if (old)
+ old->unref();
+}
+
+inline GPEnabled*
+GPBase::get() const
+{
+ return ptr;
+}
+
+inline GPBase &
+GPBase::operator=(const GPBase & obj)
+{
+ return assign(obj);
+}
+
+inline int
+GPBase::operator==(const GPBase & g2) const
+{
+ return ptr == g2.ptr;
+}
+
+
+
+
+// INLINE FOR GP<TYPE>
+
+template <class TYPE> inline
+GP<TYPE>::GP()
+{
+}
+
+template <class TYPE> inline
+GP<TYPE>::GP(TYPE *nptr)
+: GPBase((GPEnabled*)nptr)
+{
+}
+
+template <class TYPE> inline
+GP<TYPE>::GP(const GP<TYPE> &sptr)
+: GPBase((const GPBase&) sptr)
+{
+}
+
+template <class TYPE> inline
+GP<TYPE>::operator TYPE* () const
+{
+ return (TYPE*) ptr;
+}
+
+template <class TYPE> inline TYPE*
+GP<TYPE>::operator->() const
+{
+ return (TYPE*) ptr;
+}
+
+template <class TYPE> inline TYPE&
+GP<TYPE>::operator*() const
+{
+ return *(TYPE*) ptr;
+}
+
+template <class TYPE> inline GP<TYPE>&
+GP<TYPE>::operator= (TYPE *nptr)
+{
+ return (GP<TYPE>&)( assign(nptr) );
+}
+
+template <class TYPE> inline GP<TYPE>&
+GP<TYPE>::operator= (const GP<TYPE> &sptr)
+{
+ return (GP<TYPE>&)( assign((const GPBase&)sptr) );
+}
+
+template <class TYPE> inline int
+GP<TYPE>::operator== (TYPE *nptr) const
+{
+ return ( (TYPE*)ptr == nptr );
+}
+
+template <class TYPE> inline int
+GP<TYPE>::operator!= (TYPE *nptr) const
+{
+ return ( (TYPE*)ptr != nptr );
+}
+
+template <class TYPE> inline int
+GP<TYPE>::operator! () const
+{
+ return !ptr;
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/GString.cpp b/kviewshell/plugins/djvu/libdjvu/GString.cpp
new file mode 100644
index 00000000..a618055e
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GString.cpp
@@ -0,0 +1,2811 @@
+//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: GString.cpp,v 1.22 2005/04/27 16:34:13 leonb Exp $
+// $Name: release_3_5_15 $
+
+// From: Leon Bottou, 1/31/2002
+// This file has very little to do with my initial implementation.
+// It has been practically rewritten by Lizardtech for i18n changes.
+// My original implementation was very small in comparison
+// <http://prdownloads.sourceforge.net/djvu/DjVu2_2b-src.tgz>.
+// In my opinion, the duplication of the string classes is a failed
+// attempt to use the type system to enforce coding policies.
+// This could be fixed. But there are better things to do in djvulibre.
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "GString.h"
+#include "GThreads.h"
+#include "debug.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#if HAS_WCHAR
+# include <locale.h>
+# if !defined(AUTOCONF) || HAVE_WCHAR_H
+# include <wchar.h>
+# endif
+# if HAS_WCTYPE
+# include <wctype.h>
+# endif
+#endif
+#include <ctype.h>
+
+#ifndef DO_CHANGELOCALE
+#define DO_CHANGELOCALE 1
+#ifdef UNIX
+#if THREADMODEL != COTHREADS
+#if THREADMODEL != NOTHREADS
+#undef DO_CHANGELOCALE
+#define DO_CHANGELOCALE 0
+#endif
+#endif
+#endif
+#endif
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+GBaseString::~GBaseString() {}
+GNativeString::~GNativeString() {}
+GUTF8String::~GUTF8String() {}
+
+#if !HAS_MBSTATE && HAS_WCHAR
+// Under some systems, wctomb() and mbtowc() are not thread
+// safe. In those cases, wcrtomb and mbrtowc are preferred.
+// For Solaris, wctomb() and mbtowc() are thread safe, and
+// wcrtomb() and mbrtowc() don't exist.
+
+#define wcrtomb MYwcrtomb
+#define mbrtowc MYmbrtowc
+#define mbrlen MYmbrlen
+
+static inline int
+wcrtomb(char *bytes,wchar_t w,mbstate_t *)
+{
+ return wctomb(bytes,w);
+}
+
+static inline int
+mbrtowc(wchar_t *w,const char *source, size_t n, mbstate_t *)
+{
+ return mbtowc(w,source,n);
+}
+
+static inline size_t
+mbrlen(const char *s, size_t n, mbstate_t *)
+{
+ return mblen(s,n);
+}
+#endif // !HAS_MBSTATE || HAS_WCHAR
+
+
+GP<GStringRep>
+GStringRep::upcase(void) const
+{ return tocase(giswupper,gtowupper); }
+
+GP<GStringRep>
+GStringRep::downcase(void) const
+{ return tocase(giswlower,gtowlower); }
+
+GP<GStringRep>
+GStringRep::UTF8::create(const unsigned int sz)
+{
+ return GStringRep::create(sz,(GStringRep::UTF8 *)0);
+}
+
+GP<GStringRep>
+GStringRep::UTF8::create(const char *s)
+{
+ GStringRep::UTF8 dummy;
+ return dummy.strdup(s);
+}
+
+GP<GStringRep>
+GStringRep::UTF8::create(const GP<GStringRep> &s1,const GP<GStringRep> &s2)
+{
+ GStringRep::UTF8 dummy;
+ return dummy.concat(s1,s2);
+}
+
+GP<GStringRep>
+GStringRep::UTF8::create( const GP<GStringRep> &s1,const char *s2)
+{
+ GStringRep::UTF8 dummy;
+ return dummy.concat(s1,s2);
+}
+
+GP<GStringRep>
+GStringRep::UTF8::create( const char *s1, const GP<GStringRep> &s2)
+{
+ GStringRep::UTF8 dummy;
+ return dummy.concat(s1,s2);
+}
+
+GP<GStringRep>
+GStringRep::UTF8::create( const char *s1,const char *s2)
+{
+ GStringRep::UTF8 dummy;
+ return dummy.concat(s1,s2);
+}
+
+GP<GStringRep>
+GStringRep::UTF8::create(const char *s,const int start,const int length)
+{
+ GStringRep::UTF8 dummy;
+ return dummy.substr(s,start,length);
+}
+
+GP<GStringRep>
+GStringRep::UTF8::create(
+ const unsigned short *s,const int start,const int length)
+{
+ GStringRep::UTF8 dummy;
+ return dummy.substr(s,start,length);
+}
+
+GP<GStringRep>
+GStringRep::UTF8::create(
+ const unsigned long *s,const int start,const int length)
+{
+ GStringRep::UTF8 dummy;
+ return dummy.substr(s,start,length);
+}
+
+GP<GStringRep>
+GStringRep::UTF8::blank(const unsigned int sz) const
+{
+ return GStringRep::create(sz,(GStringRep::UTF8 *)0);
+}
+
+bool
+GStringRep::UTF8::isUTF8(void) const
+{
+ return true;
+}
+
+GP<GStringRep>
+GStringRep::UTF8::toThis(
+ const GP<GStringRep> &rep,const GP<GStringRep> &) const
+{
+ return rep?(rep->toUTF8(true)):rep;
+}
+
+GP<GStringRep>
+GStringRep::UTF8::create(const char fmt[],va_list& args)
+{
+ const GP<GStringRep> s(create(fmt));
+ return (s?(s->vformat(args)):s);
+}
+
+#if !HAS_WCHAR
+
+#define NATIVE_CREATE(x) UTF8::create( x );
+
+#ifdef LC_ALL
+#undef LC_ALL
+#endif
+#define LC_ALL 0
+
+class GStringRep::ChangeLocale
+{
+public:
+ ChangeLocale(const int,const char *) {}
+ ~ChangeLocale() {};
+};
+
+GP<GStringRep>
+GStringRep::NativeToUTF8( const char *s )
+{
+ return GStringRep::UTF8::create(s);
+}
+
+#else
+
+#define NATIVE_CREATE(x) Native::create( x );
+
+// The declaration and implementation of GStringRep::ChangeLocale
+// Not used in WinCE
+
+class GStringRep::ChangeLocale
+{
+public:
+ ChangeLocale(const int category,const char locale[]);
+ ~ChangeLocale();
+private:
+ GUTF8String locale;
+ int category;
+};
+
+class GStringRep::Native : public GStringRep
+{
+public:
+ // default constructor
+ Native(void);
+ // virtual destructor
+ virtual ~Native();
+
+ // Other virtual methods.
+ // Create an empty string.
+ virtual GP<GStringRep> blank(const unsigned int sz = 0) const;
+ // Append a string.
+ virtual GP<GStringRep> append(const GP<GStringRep> &s2) const;
+ // Test if Native.
+ virtual bool isNative(void) const;
+ // Convert to Native.
+ virtual GP<GStringRep> toNative(
+ const EscapeMode escape=UNKNOWN_ESCAPED) const;
+ // Convert to UTF8.
+ virtual GP<GStringRep> toUTF8(const bool nothrow=false) const;
+ // Convert to UTF8.
+ virtual GP<GStringRep> toThis(
+ const GP<GStringRep> &rep,const GP<GStringRep> &) const;
+ // Compare with #s2#.
+ virtual int cmp(const GP<GStringRep> &s2, const int len=(-1)) const;
+
+ // Convert strings to numbers.
+ virtual int toInt(void) const;
+ virtual long toLong(
+ const int pos, int &endpos, const int base=10) const;
+ virtual unsigned long toULong(
+ const int pos, int &endpos, const int base=10) const;
+ virtual double toDouble(
+ const int pos, int &endpos) const;
+
+ // Create an empty string
+ static GP<GStringRep> create(const unsigned int sz = 0);
+
+ // Create a strdup string.
+ static GP<GStringRep> create(const char *s);
+
+ // Creates by appending to the current string
+
+ // Creates with a concat operation.
+ static GP<GStringRep> create(
+ const GP<GStringRep> &s1,const GP<GStringRep> &s2);
+ static GP<GStringRep> create( const GP<GStringRep> &s1,const char *s2);
+ static GP<GStringRep> create( const char *s1, const GP<GStringRep> &s2);
+ static GP<GStringRep> create(const char *s1,const char *s2);
+
+ // Create with a strdup and substr operation.
+ static GP<GStringRep> create(
+ const char *s,const int start,const int length=(-1));
+ static GP<GStringRep> create(
+ const unsigned short *s,const int start,const int length=(-1));
+ static GP<GStringRep> create(
+ const unsigned long *s,const int start,const int length=(-1));
+
+ // Create with an sprintf()
+ static GP<GStringRep> create_format(const char fmt[],...);
+ static GP<GStringRep> create(const char fmt[],va_list &args);
+
+ virtual unsigned char *UCS4toString(
+ const unsigned long w,unsigned char *ptr, mbstate_t *ps=0) const;
+
+ // Tests if a string is legally encoded in the current character set.
+ virtual bool is_valid(void) const;
+
+ virtual int ncopy(wchar_t * const buf, const int buflen) const;
+
+ friend class GBaseString;
+protected:
+ // Return the next character and increment the source pointer.
+ virtual unsigned long getValidUCS4(const char *&source) const;
+};
+
+GP<GStringRep>
+GStringRep::Native::create(const unsigned int sz)
+{
+ return GStringRep::create(sz,(GStringRep::Native *)0);
+}
+
+ // Create a strdup string.
+GP<GStringRep>
+GStringRep::Native::create(const char *s)
+{
+ GStringRep::Native dummy;
+ return dummy.strdup(s);
+}
+
+GP<GStringRep>
+GStringRep::Native::create(const GP<GStringRep> &s1,const GP<GStringRep> &s2)
+{
+ GStringRep::Native dummy;
+ return dummy.concat(s1,s2);
+}
+
+GP<GStringRep>
+GStringRep::Native::create( const GP<GStringRep> &s1,const char *s2)
+{
+ GStringRep::Native dummy;
+ return dummy.concat(s1,s2);
+}
+
+GP<GStringRep>
+GStringRep::Native::create( const char *s1, const GP<GStringRep> &s2)
+{
+ GStringRep::Native dummy;
+ return dummy.concat(s1,s2);
+}
+
+GP<GStringRep>
+GStringRep::Native::create(const char *s1,const char *s2)
+{
+ GStringRep::Native dummy;
+ return dummy.concat(s1,s2);
+}
+
+GP<GStringRep>
+GStringRep::Native::create(
+ const char *s,const int start,const int length)
+{
+ GStringRep::Native dummy;
+ return dummy.substr(s,start,length);
+}
+
+GP<GStringRep>
+GStringRep::Native::create(
+ const unsigned short *s,const int start,const int length)
+{
+ GStringRep::Native dummy;
+ return dummy.substr(s,start,length);
+}
+
+GP<GStringRep>
+GStringRep::Native::create(
+ const unsigned long *s,const int start,const int length)
+{
+ GStringRep::Native dummy;
+ return dummy.substr(s,start,length);
+}
+
+GP<GStringRep>
+GStringRep::Native::blank(const unsigned int sz) const
+{
+ return GStringRep::create(sz,(GStringRep::Native *)0);
+}
+
+bool
+GStringRep::Native::isNative(void) const
+{
+ return true;
+}
+
+GP<GStringRep>
+GStringRep::Native::toThis(
+ const GP<GStringRep> &rep,const GP<GStringRep> &) const
+{
+ return rep?(rep->toNative(NOT_ESCAPED)):rep;
+}
+
+GP<GStringRep>
+GStringRep::Native::create(const char fmt[],va_list &args)
+{
+ const GP<GStringRep> s(create(fmt));
+ return (s?(s->vformat(args)):s);
+}
+
+int
+GStringRep::Native::ncopy(
+ wchar_t * const buf, const int buflen ) const
+{
+ return toUTF8()->ncopy(buf,buflen);
+}
+
+GStringRep::ChangeLocale::ChangeLocale(const int xcategory, const char xlocale[] )
+ : category(xcategory)
+{
+#if DO_CHANGELOCALE
+ // This is disabled under UNIX because
+ // it does not play nice with MT.
+ if(xlocale)
+ {
+ locale=setlocale(xcategory,0);
+ if(locale.length() &&(locale!=xlocale))
+ {
+ if(locale == setlocale(category,xlocale))
+ {
+ locale.empty();
+ }
+ }
+ else
+ {
+ locale.empty();
+ }
+ }
+#endif
+}
+
+GStringRep::ChangeLocale::~ChangeLocale()
+{
+#if DO_CHANGELOCALE
+ if(locale.length())
+ {
+ setlocale(category,(const char *)locale);
+ }
+#endif
+}
+
+GNativeString &
+GNativeString::format(const char fmt[], ... )
+{
+ va_list args;
+ va_start(args, fmt);
+ return init(GStringRep::Native::create(fmt,args));
+}
+
+// Gather the native implementations here. Not used in WinCE.
+
+GStringRep::Native::Native(void) {}
+GStringRep::Native::~Native() {}
+
+GP<GStringRep>
+GStringRep::Native::append(const GP<GStringRep> &s2) const
+{
+ GP<GStringRep> retval;
+ if(s2)
+ {
+ if(s2->isUTF8())
+ {
+ G_THROW( ERR_MSG("GStringRep.appendUTF8toNative") );
+ }
+ retval=concat(data,s2->data);
+ }else
+ {
+ retval=const_cast<GStringRep::Native *>(this);
+ }
+ return retval;
+}
+
+GP<GStringRep>
+GStringRep::Native::create_format(const char fmt[],...)
+{
+ va_list args;
+ va_start(args, fmt);
+ return create(fmt,args);
+}
+
+unsigned char *
+GStringRep::Native::UCS4toString(
+ const unsigned long w0,unsigned char *ptr, mbstate_t *ps) const
+{
+ return UCS4toNative(w0,ptr,ps);
+}
+
+// Convert a UCS4 to a multibyte string in the value bytes.
+// The data pointed to by ptr should be long enough to contain
+// the results with a nill termination. (Normally 7 characters
+// is enough.)
+unsigned char *
+GStringRep::UCS4toNative(
+ const unsigned long w0,unsigned char *ptr, mbstate_t *ps)
+{
+ unsigned short w1;
+ unsigned short w2=1;
+ for(int count=(sizeof(wchar_t)==sizeof(w1)) ? UCS4toUTF16(w0,w1,w2) : 1;
+ count;
+ --count,w1=w2)
+ {
+ // wchar_t can be either UCS4 or UCS2
+ const wchar_t w=(sizeof(wchar_t) == sizeof(w1))?(wchar_t)w1:(wchar_t)w0;
+ int i=wcrtomb((char *)ptr,w,ps);
+ if(i<0)
+ {
+ break;
+ }
+ ptr[i]=0;
+ ptr += i;
+ }
+ ptr[0]=0;
+ return ptr;
+}
+
+GP<GStringRep>
+GStringRep::Native::toNative(const EscapeMode escape) const
+{
+ if(escape == UNKNOWN_ESCAPED)
+ G_THROW( ERR_MSG("GStringRep.NativeToNative") );
+ return const_cast<GStringRep::Native *>(this);
+}
+
+GP<GStringRep>
+GStringRep::Native::toUTF8(const bool) const
+{
+ unsigned char *buf;
+ GPBuffer<unsigned char> gbuf(buf,size*6+1);
+ buf[0]=0;
+ if(data && size)
+ {
+ size_t n=size;
+ const char *source=data;
+ mbstate_t ps;
+ unsigned char *ptr=buf;
+ //(void)mbrlen(source, n, &ps);
+ memset(&ps,0,sizeof(mbstate_t));
+ int i=0;
+ if(sizeof(wchar_t) == sizeof(unsigned long))
+ {
+ wchar_t w = 0;
+ for(;(n>0)&&((i=mbrtowc(&w,source,n,&ps))>=0); n-=i,source+=i)
+ {
+ ptr=UCS4toUTF8(w,ptr);
+ }
+ }
+ else
+ {
+ wchar_t w = 0;
+ for(;(n>0)&&((i=mbrtowc(&w,source,n,&ps))>=0);n-=i,source+=i)
+ {
+ unsigned short s[2];
+ s[0]=w;
+ unsigned long w0;
+ if(UTF16toUCS4(w0,s,s+1)<=0)
+ {
+ source+=i;
+ n-=i;
+ if((n>0)&&((i=mbrtowc(&w,source,n,&ps))>=0))
+ {
+ s[1]=w;
+ if(UTF16toUCS4(w0,s,s+2)<=0)
+ {
+ i=(-1);
+ break;
+ }
+ }
+ else
+ {
+ i=(-1);
+ break;
+ }
+ }
+ ptr=UCS4toUTF8(w0,ptr);
+ }
+ }
+ if(i<0)
+ {
+ gbuf.resize(0);
+ }
+ else
+ {
+ ptr[0]=0;
+ }
+ }
+ return GStringRep::UTF8::create((const char *)buf);
+}
+
+GNativeString
+GBaseString::UTF8ToNative(
+ const bool currentlocale,const EscapeMode escape) const
+{
+ const char *source=(*this);
+ GP<GStringRep> retval;
+ if(source && source[0])
+ {
+#if DO_CHANGELOCALE
+ GUTF8String lc_ctype(setlocale(LC_CTYPE,0));
+#endif
+ bool repeat;
+ for(repeat=!currentlocale;;repeat=false)
+ {
+ retval=(*this)->toNative((GStringRep::EscapeMode)escape);
+#if DO_CHANGELOCALE
+ if (!repeat || retval || (lc_ctype == setlocale(LC_CTYPE,"")))
+#endif
+ break;
+ }
+#if DO_CHANGELOCALE
+ if(!repeat)
+ {
+ setlocale(LC_CTYPE,(const char *)lc_ctype);
+ }
+#endif
+ }
+ return GNativeString(retval);
+}
+
+/*MBCS*/
+GNativeString
+GBaseString::getUTF82Native( const EscapeMode escape ) const
+{ //MBCS cvt
+ GNativeString retval;
+
+ // We don't want to convert this if it
+ // already is known to be native...
+// if (isNative()) return *this;
+
+ const size_t slen=length()+1;
+ if(slen>1)
+ {
+ retval=UTF8ToNative(false,escape) ;
+ if(!retval.length())
+ {
+ retval=(const char*)*this;
+ }
+ }
+ return retval;
+}
+
+GUTF8String
+GBaseString::NativeToUTF8(void) const
+{
+ GP<GStringRep> retval;
+ if(length())
+ {
+ const char *source=(*this);
+#if DO_CHANGELOCALE
+ GUTF8String lc_ctype=setlocale(LC_CTYPE,0);
+#endif
+ bool repeat;
+ for(repeat=true;;repeat=false)
+ {
+ if( (retval=GStringRep::NativeToUTF8(source)) )
+ {
+ if(GStringRep::cmp(retval->toNative(),source))
+ {
+ retval=GStringRep::UTF8::create((unsigned int)0);
+ }
+ }
+#if DO_CHANGELOCALE
+ if(!repeat || retval || (lc_ctype == setlocale(LC_CTYPE,"")))
+#endif
+ break;
+ }
+#if DO_CHANGELOCALE
+ if(!repeat)
+ {
+ setlocale(LC_CTYPE,(const char *)lc_ctype);
+ }
+#endif
+ }
+ return GUTF8String(retval);
+}
+
+GUTF8String
+GBaseString::getNative2UTF8(void) const
+{ //MBCS cvt
+
+ // We don't want to do a transform this
+ // if we already are in the given type.
+// if (isUTF8()) return *this;
+
+ const size_t slen=length()+1;
+ GUTF8String retval;
+ if(slen > 1)
+ {
+ retval=NativeToUTF8();
+ if(!retval.length())
+ {
+ retval=(const char *)(*this);
+ }
+ }
+ return retval;
+} /*MBCS*/
+
+int
+GStringRep::Native::cmp(const GP<GStringRep> &s2,const int len) const
+{
+ int retval;
+ if(s2)
+ {
+ if(s2->isUTF8())
+ {
+ const GP<GStringRep> r(toUTF8(true));
+ if(r)
+ {
+ retval=GStringRep::cmp(r->data,s2->data,len);
+ }else
+ {
+ retval=cmp(s2->toNative(NOT_ESCAPED),len);
+ }
+ }else
+ {
+ retval=GStringRep::cmp(data,s2->data,len);
+ }
+ }else
+ {
+ retval=GStringRep::cmp(data,0,len);
+ }
+ return retval;
+}
+
+int
+GStringRep::Native::toInt() const
+{
+ return atoi(data);
+}
+
+long
+GStringRep::Native::toLong(
+ const int pos, int &endpos, const int base) const
+{
+ char *edata=0;
+ const long retval=strtol(data+pos, &edata, base);
+ if(edata)
+ {
+ endpos=(int)((size_t)edata-(size_t)data);
+ }else
+ {
+ endpos=(-1);
+ }
+ return retval;
+}
+
+unsigned long
+GStringRep::Native::toULong(
+ const int pos, int &endpos, const int base) const
+{
+ char *edata=0;
+ const unsigned long retval=strtoul(data+pos, &edata, base);
+ if(edata)
+ {
+ endpos=(int)((size_t)edata-(size_t)data);
+ }else
+ {
+ endpos=(-1);
+ }
+ return retval;
+}
+
+double
+GStringRep::Native::toDouble(
+ const int pos, int &endpos) const
+{
+ char *edata=0;
+ const double retval=strtod(data+pos, &edata);
+ if(edata)
+ {
+ endpos=(int)((size_t)edata-(size_t)data);
+ }else
+ {
+ endpos=(-1);
+ }
+ return retval;
+}
+
+unsigned long
+GStringRep::Native::getValidUCS4(const char *&source) const
+{
+ unsigned long retval=0;
+ int n=(int)((size_t)size+(size_t)data-(size_t)source);
+ if(source && (n > 0))
+ {
+ mbstate_t ps;
+ //(void)mbrlen(source, n, &ps);
+ memset(&ps,0,sizeof(mbstate_t));
+ wchar_t wt;
+ const int len=mbrtowc(&wt,source,n,&ps);
+ if(len>=0)
+ {
+ if(sizeof(wchar_t) == sizeof(unsigned short))
+ {
+ source+=len;
+ unsigned short s[2];
+ s[0]=(unsigned short)wt;
+ if(UTF16toUCS4(retval,s,s+1)<=0)
+ {
+ if((n-=len)>0)
+ {
+ const int len=mbrtowc(&wt,source,n,&ps);
+ if(len>=0)
+ {
+ s[1]=(unsigned short)wt;
+ unsigned long w;
+ if(UTF16toUCS4(w,s,s+2)>0)
+ {
+ source+=len;
+ retval=w;
+ }
+ }
+ }
+ }
+ }else
+ {
+ retval=(unsigned long)wt;
+ source++;
+ }
+ }else
+ {
+ source++;
+ }
+ }
+ return retval;
+}
+
+// Tests if a string is legally encoded in the current character set.
+bool
+GStringRep::Native::is_valid(void) const
+{
+ bool retval=true;
+ if(data && size)
+ {
+ size_t n=size;
+ const char *s=data;
+ mbstate_t ps;
+ //(void)mbrlen(s, n, &ps);
+ memset(&ps,0,sizeof(mbstate_t));
+ do
+ {
+ size_t m=mbrlen(s,n,&ps);
+ if(m > n)
+ {
+ retval=false;
+ break;
+ }else if(m)
+ {
+ s+=m;
+ n-=m;
+ }else
+ {
+ break;
+ }
+ } while(n);
+ }
+ return retval;
+}
+
+// These are dummy functions.
+void
+GStringRep::set_remainder(void const * const, const unsigned int,
+ const EncodeType) {}
+void
+GStringRep::set_remainder(void const * const, const unsigned int,
+ const GP<GStringRep> &encoding) {}
+void
+GStringRep::set_remainder( const GP<GStringRep::Unicode> &) {}
+
+GP<GStringRep::Unicode>
+GStringRep::get_remainder( void ) const
+{
+ return 0;
+}
+
+GNativeString::GNativeString(const char dat)
+{
+ init(GStringRep::Native::create(&dat,0,1));
+}
+
+GNativeString::GNativeString(const char *str)
+{
+ init(GStringRep::Native::create(str));
+}
+
+GNativeString::GNativeString(const unsigned char *str)
+{
+ init(GStringRep::Native::create((const char *)str));
+}
+
+GNativeString::GNativeString(const unsigned short *str)
+{
+ init(GStringRep::Native::create(str,0,-1));
+}
+
+GNativeString::GNativeString(const unsigned long *str)
+{
+ init(GStringRep::Native::create(str,0,-1));
+}
+
+GNativeString::GNativeString(const char *dat, unsigned int len)
+{
+ init(
+ GStringRep::Native::create(dat,0,((int)len<0)?(-1):(int)len));
+}
+
+GNativeString::GNativeString(const unsigned short *dat, unsigned int len)
+{
+ init(
+ GStringRep::Native::create(dat,0,((int)len<0)?(-1):(int)len));
+}
+
+GNativeString::GNativeString(const unsigned long *dat, unsigned int len)
+{
+ init(
+ GStringRep::Native::create(dat,0,((int)len<0)?(-1):(int)len));
+}
+
+GNativeString::GNativeString(const GNativeString &str)
+{
+ init(str);
+}
+
+GNativeString::GNativeString(const GBaseString &gs, int from, int len)
+{
+ init(
+ GStringRep::Native::create(gs,from,((int)len<0)?(-1):(int)len));
+}
+
+GNativeString::GNativeString(const int number)
+{
+ init(GStringRep::Native::create_format("%d",number));
+}
+
+GNativeString::GNativeString(const double number)
+{
+ init(GStringRep::Native::create_format("%f",number));
+}
+
+GNativeString&
+GNativeString::operator= (const char str)
+{ return init(GStringRep::Native::create(&str,0,1)); }
+
+GNativeString&
+GNativeString::operator= (const char *str)
+{ return init(GStringRep::Native::create(str)); }
+
+GNativeString
+GBaseString::operator+(const GNativeString &s2) const
+{
+ return GStringRep::Native::create(*this,s2);
+}
+
+GP<GStringRep>
+GStringRep::NativeToUTF8( const char *s )
+{
+ return GStringRep::Native::create(s)->toUTF8();
+}
+
+#endif // HAS_WCHAR
+
+template <class TYPE>
+GP<GStringRep>
+GStringRep::create(const unsigned int sz, TYPE *)
+{
+ GP<GStringRep> gaddr;
+ if (sz > 0)
+ {
+ GStringRep *addr;
+ gaddr=(addr=new TYPE);
+ addr->data=(char *)(::operator new(sz+1));
+ addr->size = sz;
+ addr->data[sz] = 0;
+ }
+ return gaddr;
+}
+
+GP<GStringRep>
+GStringRep::strdup(const char *s) const
+{
+ GP<GStringRep> retval;
+ const int length=s?strlen(s):0;
+ if(length>0)
+ {
+ retval=blank(length);
+ char const * const end=s+length;
+ char *ptr=retval->data;
+ for(;*s&&(s!=end);ptr++)
+ {
+ ptr[0]=s++[0];
+ }
+ ptr[0]=0;
+ }
+ return retval;
+}
+
+GP<GStringRep>
+GStringRep::substr(const char *s,const int start,const int len) const
+{
+ GP<GStringRep> retval;
+ if(s && s[0])
+ {
+ const unsigned int length=(start<0 || len<0)?(unsigned int)strlen(s):(unsigned int)(-1);
+ const char *startptr, *endptr;
+ if(start<0)
+ {
+ startptr=s+length+start;
+ if(startptr<s)
+ startptr=s;
+ }else
+ {
+ startptr=s;
+ for(const char * const ptr=s+start;(startptr<ptr)&&*startptr;++startptr)
+ EMPTY_LOOP;
+ }
+ if(len<0)
+ {
+ if(s+length+1 < startptr+len)
+ {
+ endptr=startptr;
+ }else
+ {
+ endptr=s+length+1+len;
+ }
+ }else
+ {
+ endptr=startptr;
+ for(const char * const ptr=startptr+len;(endptr<ptr)&&*endptr;++endptr)
+ EMPTY_LOOP;
+ }
+ if(endptr>startptr)
+ {
+ retval=blank((size_t)(endptr-startptr));
+ char *data=retval->data;
+ for(; (startptr<endptr) && *startptr; ++startptr,++data)
+ {
+ data[0]=startptr[0];
+ }
+ data[0]=0;
+ }
+ }
+ return retval;
+}
+
+GP<GStringRep>
+GStringRep::substr(const unsigned short *s,const int start,const int len) const
+{
+ GP<GStringRep> retval;
+ if(s && s[0])
+ {
+ unsigned short const *eptr;
+ if(len<0)
+ {
+ for(eptr=s;eptr[0];++eptr)
+ EMPTY_LOOP;
+ }else
+ {
+ eptr=&(s[len]);
+ }
+ s=&s[start];
+ if((size_t)s<(size_t)eptr)
+ {
+ mbstate_t ps;
+ memset(&ps,0,sizeof(mbstate_t));
+ unsigned char *buf,*ptr;
+ GPBuffer<unsigned char> gbuf(buf,(((size_t)eptr-(size_t)s)/2)*3+7);
+ for(ptr=buf;s[0];)
+ {
+ unsigned long w;
+ int i=UTF16toUCS4(w,s,eptr);
+ if(i<=0)
+ break;
+ s+=i;
+ ptr=UCS4toString(w,ptr,&ps);
+ }
+ ptr[0]=0;
+ retval = strdup( (const char *)buf );
+ }
+ }
+ return retval;
+}
+
+GP<GStringRep>
+GStringRep::substr(const unsigned long *s,const int start,const int len) const
+{
+ GP<GStringRep> retval;
+ if(s && s[0])
+ {
+ unsigned long const *eptr;
+ if(len<0)
+ {
+ for(eptr=s;eptr[0];++eptr)
+ EMPTY_LOOP;
+ }else
+ {
+ eptr=&(s[len]);
+ }
+ s=&s[start];
+ if((size_t)s<(size_t)eptr)
+ {
+ mbstate_t ps;
+ memset(&ps,0,sizeof(mbstate_t));
+ unsigned char *buf,*ptr;
+ GPBuffer<unsigned char> gbuf(buf,((((size_t)eptr-(size_t)s))/4)*6+7);
+ for(ptr=buf;s[0];++s)
+ {
+ ptr=UCS4toString(s[0],ptr,&ps);
+ }
+ ptr[0]=0;
+ retval = strdup( (const char *)buf );
+ }
+ }
+ return retval;
+}
+
+GP<GStringRep>
+GStringRep::append(const char *s2) const
+{
+ GP<GStringRep> retval;
+ if(s2)
+ {
+ retval=concat(data,s2);
+ }else
+ {
+ retval=const_cast<GStringRep *>(this);
+ }
+ return retval;
+}
+
+GP<GStringRep>
+GStringRep::UTF8::append(const GP<GStringRep> &s2) const
+{
+ GP<GStringRep> retval;
+ if(s2)
+ {
+ if(s2->isNative())
+ {
+ G_THROW( ERR_MSG("GStringRep.appendNativeToUTF8") );
+ }
+ retval=concat(data,s2->data);
+ }else
+ {
+ retval=const_cast<GStringRep::UTF8 *>(this);
+ }
+ return retval;
+}
+
+GP<GStringRep>
+GStringRep::concat(const char *s1,const char *s2) const
+{
+ const int length1=(s1?strlen(s1):0);
+ const int length2=(s2?strlen(s2):0);
+ const int length=length1+length2;
+ GP<GStringRep> retval;
+ if(length>0)
+ {
+ retval=blank(length);
+ GStringRep &r=*retval;
+ if(length1)
+ {
+ strcpy(r.data,s1);
+ if(length2)
+ strcat(r.data,s2);
+ }else
+ {
+ strcpy(r.data,s2);
+ }
+ }
+ return retval;
+}
+
+const char *GBaseString::nullstr = "";
+
+void
+GBaseString::empty( void )
+{
+ init(0);
+}
+
+GP<GStringRep>
+GStringRep::getbuf(int n) const
+{
+ GP<GStringRep> retval;
+ if(n< 0)
+ n=strlen(data);
+ if(n>0)
+ {
+ retval=blank(n);
+ char *ndata=retval->data;
+ strncpy(ndata,data,n);
+ ndata[n]=0;
+ }
+ return retval;
+}
+
+const char *
+GStringRep::isCharType(
+ bool (*xiswtest)(const unsigned long wc), const char *ptr, const bool reverse) const
+{
+ char const * xptr=ptr;
+ const unsigned long w=getValidUCS4(xptr);
+ if((ptr != xptr)
+ &&(((sizeof(wchar_t) == 2)&&(w&~0xffff))
+ ||(reverse?(!xiswtest(w)):xiswtest(w))))
+ {
+ ptr=xptr;
+ }
+ return ptr;
+}
+
+int
+GStringRep::nextCharType(
+ bool (*xiswtest)(const unsigned long wc), const int from, const int len,
+ const bool reverse) const
+{
+ // We want to return the position of the next
+ // non white space starting from the #from#
+ // location. isspace should work in any locale
+ // so we should only need to do this for the non-
+ // native locales (UTF8)
+ int retval;
+ if(from<size)
+ {
+ retval=from;
+ const char * ptr = data+from;
+ for( const char * const eptr=ptr+((len<0)?(size-from):len);
+ (ptr<eptr) && *ptr;)
+ {
+ // Skip characters that fail the isCharType test
+ char const * const xptr=isCharType(xiswtest,ptr,!reverse);
+ if(xptr == ptr)
+ break;
+ ptr=xptr;
+ }
+ retval=(int)((size_t)ptr-(size_t)data);
+ }else
+ {
+ retval=size;
+ }
+ return retval;
+}
+
+bool
+GStringRep::giswspace(const unsigned long w)
+{
+#if HAS_WCTYPE
+ return
+ ((sizeof(wchar_t) == 2)&&(w&~0xffff))
+ ||((unsigned long)iswspace((wchar_t)w))
+ ||((w == '\r')||(w == '\n'));
+#else
+ return
+ (w&~0xff)?(true):(((unsigned long)isspace((char)w))||((w == '\r')||(w == '\n')));
+#endif
+}
+
+bool
+GStringRep::giswupper(const unsigned long w)
+{
+#if HAS_WCTYPE
+ return ((sizeof(wchar_t) == 2)&&(w&~0xffff))
+ ?(true):((unsigned long)iswupper((wchar_t)w)?true:false);
+#else
+ return (w&~0xff)?(true):((unsigned long)isupper((char)w)?true:false);
+#endif
+}
+
+bool
+GStringRep::giswlower(const unsigned long w)
+{
+#if HAS_WCTYPE
+ return ((sizeof(wchar_t) == 2)&&(w&~0xffff))
+ ?(true):((unsigned long)iswlower((wchar_t)w)?true:false);
+#else
+ return (w&~0xff)?(true):((unsigned long)islower((char)w)?true:false);
+#endif
+}
+
+unsigned long
+GStringRep::gtowupper(const unsigned long w)
+{
+#if HAS_WCTYPE
+ return ((sizeof(wchar_t) == 2)&&(w&~0xffff))
+ ?w:((unsigned long)towupper((wchar_t)w));
+#else
+ return (w&~0xff)?w:((unsigned long)toupper((char)w));
+#endif
+}
+
+unsigned long
+GStringRep::gtowlower(const unsigned long w)
+{
+#if HAS_WCTYPE
+ return ((sizeof(wchar_t) == 2)&&(w&~0xffff))
+ ?w:((unsigned long)towlower((wchar_t)w));
+#else
+ return (w&~0xff)?w:((unsigned long)tolower((char)w));
+#endif
+}
+
+GP<GStringRep>
+GStringRep::tocase(
+ bool (*xiswcase)(const unsigned long wc),
+ unsigned long (*xtowcase)(const unsigned long wc)) const
+{
+ GP<GStringRep> retval;
+ char const * const eptr=data+size;
+ char const *ptr=data;
+ while(ptr<eptr)
+ {
+ char const * const xptr=isCharType(xiswcase,ptr,false);
+ if(ptr == xptr)
+ break;
+ ptr=xptr;
+ }
+ if(ptr<eptr)
+ {
+ const int n=(int)((size_t)ptr-(size_t)data);
+ unsigned char *buf;
+ GPBuffer<unsigned char> gbuf(buf,n+(1+size-n)*6);
+ if(n>0)
+ {
+ strncpy((char *)buf,data,n);
+ }
+ unsigned char *buf_ptr=buf+n;
+ for(char const *ptr=data+n;ptr<eptr;)
+ {
+ char const * const xptr=ptr;
+ const unsigned long w=getValidUCS4(ptr);
+ if(ptr == xptr)
+ break;
+ if(xiswcase(w))
+ {
+ const int len=(int)((size_t)ptr-(size_t)xptr);
+ strncpy((char *)buf_ptr,xptr,len);
+ buf_ptr+=len;
+ }else
+ {
+ mbstate_t ps;
+ memset(&ps,0,sizeof(mbstate_t));
+ buf_ptr=UCS4toString(xtowcase(w),buf_ptr,&ps);
+ }
+ }
+ buf_ptr[0]=0;
+ retval=substr((const char *)buf,0,(int)((size_t)buf_ptr-(size_t)buf));
+ }else
+ {
+ retval=const_cast<GStringRep *>(this);
+ }
+ return retval;
+}
+
+// Returns a copy of this string with characters used in XML escaped as follows:
+// '<' --> "&lt;"
+// '>' --> "&gt;"
+// '&' --> "&amp;"
+// '\'' --> "&apos;"
+// '\"' --> "&quot;"
+// Also escapes characters 0x00 through 0x1f and 0x7e through 0x7f.
+GP<GStringRep>
+GStringRep::toEscaped( const bool tosevenbit ) const
+{
+ bool modified=false;
+ char *ret;
+ GPBuffer<char> gret(ret,size*7);
+ ret[0]=0;
+ char *retptr=ret;
+ char const *start=data;
+ char const *s=start;
+ char const *last=s;
+ GP<GStringRep> special;
+ for(unsigned long w;(w=getValidUCS4(s));last=s)
+ {
+ char const *ss=0;
+ switch(w)
+ {
+ case '<':
+ ss="&lt;";
+ break;
+ case '>':
+ ss="&gt;";
+ break;
+ case '&':
+ ss="&amp;";
+ break;
+ case '\47':
+ ss="&apos;";
+ break;
+ case '\42':
+ ss="&quot;";
+ break;
+ default:
+ if((w<' ')||(w>=0x7e && (tosevenbit || (w < 0x80))))
+ {
+ special=toThis(UTF8::create_format("&#%lu;",w));
+ ss=special->data;
+ }
+ break;
+ }
+ if(ss)
+ {
+ modified=true;
+ if(s!=start)
+ {
+ size_t len=(size_t)last-(size_t)start;
+ strncpy(retptr,start,len);
+ retptr+=len;
+ start=s;
+ }
+ if(ss[0])
+ {
+ size_t len=strlen(ss);
+ strcpy(retptr,ss);
+ retptr+=len;
+ }
+ }
+ }
+ GP<GStringRep> retval;
+ if(modified)
+ {
+ strcpy(retptr,start);
+ retval=strdup( ret );
+ }else
+ {
+ retval=const_cast<GStringRep *>(this);
+ }
+// DEBUG_MSG( "Escaped string is '" << ret << "'\n" );
+ return retval;
+}
+
+
+static const GMap<GUTF8String,GUTF8String> &
+BasicMap( void )
+{
+ static GMap<GUTF8String,GUTF8String> Basic;
+ if (! Basic.size())
+ {
+ Basic["lt"] = GUTF8String('<');
+ Basic["gt"] = GUTF8String('>');
+ Basic["amp"] = GUTF8String('&');
+ Basic["apos"] = GUTF8String('\47');
+ Basic["quot"] = GUTF8String('\42');
+ }
+ return Basic;
+}
+
+GUTF8String
+GUTF8String::fromEscaped( const GMap<GUTF8String,GUTF8String> ConvMap ) const
+{
+ GUTF8String ret; // Build output string here
+ int start_locn = 0; // Beginning of substring to skip
+ int amp_locn; // Location of a found ampersand
+
+ while( (amp_locn = search( '&', start_locn )) > -1 )
+ {
+ // Found the next apostrophe
+ // Locate the closing semicolon
+ const int semi_locn = search( ';', amp_locn );
+ // No closing semicolon, exit and copy
+ // the rest of the string.
+ if( semi_locn < 0 )
+ break;
+ ret += substr( start_locn, amp_locn - start_locn );
+ int const len = semi_locn - amp_locn - 1;
+ if(len)
+ {
+ GUTF8String key = substr( amp_locn+1, len);
+ //DEBUG_MSG( "key = '" << key << "'\n" );
+ char const * s=key;
+ if( s[0] == '#')
+ {
+ unsigned long value;
+ char *ptr=0;
+ if(s[1] == 'x' || s[1] == 'X')
+ {
+ value=strtoul((char const *)(s+2),&ptr,16);
+ }else
+ {
+ value=strtoul((char const *)(s+1),&ptr,10);
+ }
+ if(ptr)
+ {
+ unsigned char utf8char[7];
+ unsigned char const * const end=GStringRep::UCS4toUTF8(value,utf8char);
+ ret+=GUTF8String((char const *)utf8char,(size_t)end-(size_t)utf8char);
+ }else
+ {
+ ret += substr( amp_locn, semi_locn - amp_locn + 1 );
+ }
+ }else
+ {
+ GPosition map_entry = ConvMap.contains( key );
+ if( map_entry )
+ { // Found in the conversion map, substitute
+ ret += ConvMap[map_entry];
+ } else
+ {
+ static const GMap<GUTF8String,GUTF8String> &Basic = BasicMap();
+ GPosition map_entry = Basic.contains( key );
+ if ( map_entry )
+ {
+ ret += Basic[map_entry];
+ }else
+ {
+ ret += substr( amp_locn, len+2 );
+ }
+ }
+ }
+ }else
+ {
+ ret += substr( amp_locn, len+2 );
+ }
+ start_locn = semi_locn + 1;
+// DEBUG_MSG( "ret = '" << ret << "'\n" );
+ }
+
+ // Copy the end of the string to the output
+ ret += substr( start_locn, length()-start_locn );
+
+// DEBUG_MSG( "Unescaped string is '" << ret << "'\n" );
+ return (ret == *this)?(*this):ret;
+}
+
+GUTF8String
+GUTF8String::fromEscaped(void) const
+{
+ const GMap<GUTF8String,GUTF8String> nill;
+ return fromEscaped(nill);
+}
+
+GP<GStringRep>
+GStringRep::setat(int n, char ch) const
+{
+ GP<GStringRep> retval;
+ if(n<0)
+ n+=size;
+ if (n < 0 || n>size)
+ GBaseString::throw_illegal_subscript();
+ if(ch == data[n])
+ {
+ retval=const_cast<GStringRep *>(this);
+ }else if(!ch)
+ {
+ retval=getbuf(n);
+ }else
+ {
+ retval=getbuf((n<size)?size:n);
+ retval->data[n]=ch;
+ if(n == size)
+ retval->data[n+1]=0;
+ }
+ return retval;
+}
+
+#ifdef WIN32
+#define USE_VSNPRINTF _vsnprintf
+#endif
+
+#ifdef AUTOCONF
+# ifdef HAVE_VSNPRINTF
+# define USE_VSNPRINTF vsnprintf
+# endif
+#else
+# ifdef linux
+# define USE_VSNPRINTF vsnprintf
+# endif
+#endif
+
+GUTF8String &
+GUTF8String::format(const char fmt[], ... )
+{
+ va_list args;
+ va_start(args, fmt);
+ return init(GStringRep::UTF8::create(fmt,args));
+}
+
+GP<GStringRep>
+GStringRep::UTF8::create_format(const char fmt[],...)
+{
+ va_list args;
+ va_start(args, fmt);
+ return create(fmt,args);
+}
+
+GP<GStringRep>
+GStringRep::vformat(va_list args) const
+{
+ GP<GStringRep> retval;
+ if(size)
+ {
+#ifndef WIN32
+ char *nfmt;
+ GPBuffer<char> gnfmt(nfmt,size+1);
+ nfmt[0]=0;
+ int start=0;
+#endif
+ int from=0;
+ while((from=search('%',from)) >= 0)
+ {
+ if(data[++from] != '%')
+ {
+ int m,n=0;
+ sscanf(data+from,"%d!%n",&m,&n);
+ if(n)
+ {
+#ifdef WIN32
+ char *lpszFormat=data;
+ LPTSTR lpszTemp;
+ if((!::FormatMessage(
+ FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ lpszFormat, 0, 0, (LPTSTR)&lpszTemp,0,&args))
+ || !lpszTemp)
+ {
+ G_THROW(GException::outofmemory);
+ }
+ va_end(args);
+ retval=strdup((const char *)lpszTemp);
+ LocalFree(lpszTemp);
+ break;
+#else
+ from+=n;
+ const int end=search('!',from);
+ if(end>=0)
+ {
+ strncat(nfmt,data+start,(int)(end-start));
+ strncat(nfmt,"$",1);
+ start=from=end+1;
+ }else
+ {
+ gnfmt.resize(0);
+ from=(-1);
+ break;
+ }
+#endif
+ }else
+ {
+#ifndef WIN32
+ gnfmt.resize(0);
+#endif
+ from=(-1);
+ break;
+ }
+ }
+ }
+ if(from < 0)
+ {
+#ifndef WIN32
+ char const * const fmt=(nfmt&&nfmt[0])?nfmt:data;
+#else
+ char const * const fmt=data;
+#endif
+ int buflen=32768;
+ char *buffer;
+ GPBuffer<char> gbuffer(buffer,buflen);
+
+ ChangeLocale locale(LC_NUMERIC,(isNative()?0:"C"));
+
+ // Format string
+#ifdef USE_VSNPRINTF
+ while(USE_VSNPRINTF(buffer, buflen, fmt, args)<0)
+ {
+ gbuffer.resize(0);
+ gbuffer.resize(buflen+32768);
+ }
+ va_end(args);
+#else
+ buffer[buflen-1] = 0;
+ vsprintf(buffer, fmt, args);
+ va_end(args);
+ if (buffer[buflen-1])
+ {
+ // This isn't as fatal since it is on the stack, but we
+ // definitely should stop the current operation.
+ G_THROW( ERR_MSG("GString.overwrite") );
+ }
+#endif
+ retval=strdup((const char *)buffer);
+ }
+ }
+ // Go altering the string
+ return retval;
+}
+
+int
+GStringRep::search(char c, int from) const
+{
+ if (from<0)
+ from += size;
+ int retval=(-1);
+ if (from>=0 && from<size)
+ {
+ char const *const s = strchr(data+from,c);
+ if(s)
+ retval=(int)((size_t)s-(size_t)data);
+ }
+ return retval;
+}
+
+int
+GStringRep::search(char const *ptr, int from) const
+{
+ if(from<0)
+ {
+ from+=size;
+ if(from<0)
+ G_THROW( ERR_MSG("GString.bad_subscript") );
+ }
+ int retval=(-1);
+ if (from>=0 && from<size)
+ {
+ char const *const s = strstr(data+from,ptr);
+ if(s)
+ retval=(int)((size_t)s-(size_t)data);
+ }
+ return retval;
+}
+
+int
+GStringRep::rsearch(char c, int from) const
+{
+ if(from<0)
+ {
+ from+=size;
+ if(from<0)
+ G_THROW( ERR_MSG("GString.bad_subscript") );
+ }
+ int retval=(-1);
+ if ((from>=0) && (from<size))
+ {
+ char const *const s = strrchr(data+from,c);
+ if(s)
+ retval=(int)((size_t)s-(size_t)data);
+ }
+ return retval;
+}
+
+int
+GStringRep::rsearch(char const *ptr, int from) const
+{
+ if(from<0)
+ {
+ from+=size;
+ if(from<0)
+ G_THROW( ERR_MSG("GString.bad_subscript") );
+ }
+ int retval=(-1);
+ for(int loc=from;(loc=search(ptr,loc)) >= 0;++loc)
+ retval=loc;
+ return retval;
+}
+
+int
+GStringRep::contains(const char accept[],int from) const
+{
+ if(from<0)
+ {
+ from+=size;
+ if(from<0)
+ G_THROW( ERR_MSG("GString.bad_subscript") );
+ }
+ int retval=(-1);
+ if (accept && accept[0] && from>=0 && from<size)
+ {
+ char const * const src = data+from;
+ char const *ptr=strpbrk(src,accept);
+ if(ptr)
+ {
+ retval=(int)(ptr-src)+from;
+ }
+ }
+ return retval;
+}
+
+int
+GStringRep::rcontains(const char accept[],int from) const
+{
+ int retval=(-1);
+ while((from=contains(accept,from)) >= 0)
+ {
+ retval=from++;
+ }
+ return retval;
+}
+
+bool
+GBaseString::is_int(void) const
+{
+ bool isLong=!!ptr;
+ if(isLong)
+ {
+ int endpos;
+ (*this)->toLong(0,endpos);
+ if(endpos>=0)
+ {
+ isLong=((*this)->nextNonSpace(endpos) == (int)length());
+ }
+ }
+ return isLong;
+}
+
+bool
+GBaseString::is_float(void) const
+{
+ bool isDouble=!!ptr;
+ if(isDouble)
+ {
+ int endpos;
+ (*this)->toDouble(0,endpos);
+ if(endpos>=0)
+ {
+ isDouble=((*this)->nextNonSpace(endpos) == (int)length());
+ }
+ }
+ return isDouble;
+}
+
+unsigned int
+hash(const GBaseString &str)
+{
+ unsigned int x = 0;
+ const char *s = (const char*)str;
+ while (*s)
+ x = x ^ (x<<6) ^ (unsigned char)(*s++);
+ return x;
+}
+
+void
+GBaseString::throw_illegal_subscript()
+{
+ G_THROW( ERR_MSG("GString.bad_subscript") );
+}
+
+unsigned char *
+GStringRep::UTF8::UCS4toString(
+ const unsigned long w0,unsigned char *ptr, mbstate_t *) const
+{
+ return UCS4toUTF8(w0,ptr);
+}
+
+int
+GStringRep::UTF8::ncopy(
+ wchar_t * const buf, const int buflen ) const
+{
+ int retval=(-1);
+ if(buf && buflen)
+ {
+ buf[0]=0;
+ if(data[0])
+ {
+ const size_t length=strlen(data);
+ const unsigned char * const eptr=(const unsigned char *)(data+length);
+ wchar_t *r=buf;
+ wchar_t const * const rend=buf+buflen;
+ for(const unsigned char *s=(const unsigned char *)data;(r<rend)&&(s<eptr)&&*s;)
+ {
+ const unsigned long w0=UTF8toUCS4(s,eptr);
+ unsigned short w1;
+ unsigned short w2=1;
+ for(int count=(sizeof(wchar_t) == sizeof(w1))?UCS4toUTF16(w0,w1,w2):1;
+ count&&(r<rend);
+ --count,w1=w2,++r)
+ {
+ r[0]=(sizeof(wchar_t) == sizeof(w1))?(wchar_t)w1:(wchar_t)w0;
+ }
+ }
+ if(r<rend)
+ {
+ r[0]=0;
+ retval=((size_t)r-(size_t)buf)/sizeof(wchar_t);
+ }
+ }else
+ {
+ retval=0;
+ }
+ }
+ return retval;
+}
+
+GP<GStringRep>
+GStringRep::UTF8::toNative(const EscapeMode escape) const
+{
+ GP<GStringRep> retval;
+ if(data[0])
+ {
+ const size_t length=strlen(data);
+ const unsigned char * const eptr=(const unsigned char *)(data+length);
+ unsigned char *buf;
+ GPBuffer<unsigned char> gbuf(buf,12*length+12);
+ unsigned char *r=buf;
+ mbstate_t ps;
+ memset(&ps,0,sizeof(mbstate_t));
+ for(const unsigned char *s=(const unsigned char *)data;(s<eptr)&& *s;)
+ {
+ const unsigned long w0=UTF8toUCS4(s,eptr);
+ const unsigned char * const r0=r;
+ r=UCS4toNative(w0,r,&ps);
+ if(r == r0)
+ {
+ if(escape == IS_ESCAPED)
+ {
+ sprintf((char *)r,"&#%lu;",w0);
+ r+=strlen((char *)r);
+ }else
+ {
+ r=buf;
+ break;
+ }
+ }
+ }
+ r[0]=0;
+ retval = NATIVE_CREATE( (const char *)buf );
+ } else
+ {
+ retval = NATIVE_CREATE( (unsigned int)0 );
+ }
+ return retval;
+}
+
+GP<GStringRep>
+GStringRep::UTF8::toUTF8(const bool nothrow) const
+{
+ if(!nothrow)
+ G_THROW( ERR_MSG("GStringRep.UTF8ToUTF8") );
+ return const_cast<GStringRep::UTF8 *>(this);
+}
+
+// Tests if a string is legally encoded in the current character set.
+bool
+GStringRep::UTF8::is_valid(void) const
+{
+ bool retval=true;
+ if(data && size)
+ {
+ const unsigned char * const eptr=(const unsigned char *)(data+size);
+ for(const unsigned char *s=(const unsigned char *)data;(s<eptr)&& *s;)
+ {
+ const unsigned char * const r=s;
+ (void)UTF8toUCS4(s,eptr);
+ if(r == s)
+ {
+ retval=false;
+ break;
+ }
+ }
+ }
+ return retval;
+}
+
+static inline unsigned long
+add_char(unsigned long const U, unsigned char const * const r)
+{
+ unsigned long const C=r[0];
+ return ((C|0x3f) == 0xbf)?((U<<6)|(C&0x3f)):0;
+}
+
+unsigned long
+GStringRep::UTF8toUCS4(
+ unsigned char const *&s,void const * const eptr)
+{
+ unsigned long U=0;
+ unsigned char const *r=s;
+ if(r < eptr)
+ {
+ unsigned long const C1=r++[0];
+ if(C1&0x80)
+ {
+ if(r < eptr)
+ {
+ U=C1;
+ if((U=((C1&0x40)?add_char(U,r++):0)))
+ {
+ if(C1&0x20)
+ {
+ if(r < eptr)
+ {
+ if((U=add_char(U,r++)))
+ {
+ if(C1&0x10)
+ {
+ if(r < eptr)
+ {
+ if((U=add_char(U,r++)))
+ {
+ if(C1&0x8)
+ {
+ if(r < eptr)
+ {
+ if((U=add_char(U,r++)))
+ {
+ if(C1&0x4)
+ {
+ if(r < eptr)
+ {
+ if((U=((!(C1&0x2))?(add_char(U,r++)&0x7fffffff):0)))
+ {
+ s=r;
+ }else
+ {
+ U=(unsigned int)(-1)-s++[0];
+ }
+ }else
+ {
+ U=0;
+ }
+ }else if((U=((U&0x4000000)?0:(U&0x3ffffff))))
+ {
+ s=r;
+ }
+ }else
+ {
+ U=(unsigned int)(-1)-s++[0];
+ }
+ }else
+ {
+ U=0;
+ }
+ }else if((U=((U&0x200000)?0:(U&0x1fffff))))
+ {
+ s=r;
+ }
+ }else
+ {
+ U=(unsigned int)(-1)-s++[0];
+ }
+ }else
+ {
+ U=0;
+ }
+ }else if((U=((U&0x10000)?0:(U&0xffff))))
+ {
+ s=r;
+ }
+ }else
+ {
+ U=(unsigned int)(-1)-s++[0];
+ }
+ }else
+ {
+ U=0;
+ }
+ }else if((U=((U&0x800)?0:(U&0x7ff))))
+ {
+ s=r;
+ }
+ }else
+ {
+ U=(unsigned int)(-1)-s++[0];
+ }
+ }else
+ {
+ U=0;
+ }
+ }else if((U=C1))
+ {
+ s=r;
+ }
+ }
+ return U;
+}
+
+unsigned char *
+GStringRep::UCS4toUTF8(const unsigned long w,unsigned char *ptr)
+{
+ if(w <= 0x7f)
+ {
+ *ptr++ = (unsigned char)w;
+ }
+ else if(w <= 0x7ff)
+ {
+ *ptr++ = (unsigned char)((w>>6)|0xC0);
+ *ptr++ = (unsigned char)((w|0x80)&0xBF);
+ }
+ else if(w <= 0xFFFF)
+ {
+ *ptr++ = (unsigned char)((w>>12)|0xE0);
+ *ptr++ = (unsigned char)(((w>>6)|0x80)&0xBF);
+ *ptr++ = (unsigned char)((w|0x80)&0xBF);
+ }
+ else if(w <= 0x1FFFFF)
+ {
+ *ptr++ = (unsigned char)((w>>18)|0xF0);
+ *ptr++ = (unsigned char)(((w>>12)|0x80)&0xBF);
+ *ptr++ = (unsigned char)(((w>>6)|0x80)&0xBF);
+ *ptr++ = (unsigned char)((w|0x80)&0xBF);
+ }
+ else if(w <= 0x3FFFFFF)
+ {
+ *ptr++ = (unsigned char)((w>>24)|0xF8);
+ *ptr++ = (unsigned char)(((w>>18)|0x80)&0xBF);
+ *ptr++ = (unsigned char)(((w>>12)|0x80)&0xBF);
+ *ptr++ = (unsigned char)(((w>>6)|0x80)&0xBF);
+ *ptr++ = (unsigned char)((w|0x80)&0xBF);
+ }
+ else if(w <= 0x7FFFFFFF)
+ {
+ *ptr++ = (unsigned char)((w>>30)|0xFC);
+ *ptr++ = (unsigned char)(((w>>24)|0x80)&0xBF);
+ *ptr++ = (unsigned char)(((w>>18)|0x80)&0xBF);
+ *ptr++ = (unsigned char)(((w>>12)|0x80)&0xBF);
+ *ptr++ = (unsigned char)(((w>>6)|0x80)&0xBF);
+ *ptr++ = (unsigned char)((w|0x80)&0xBF);
+ }
+ else
+ {
+ *ptr++ = '?';
+ }
+ return ptr;
+}
+
+ // Creates with a concat operation.
+GP<GStringRep>
+GStringRep::concat( const char *s1, const GP<GStringRep> &s2) const
+{
+ GP<GStringRep> retval;
+ if(s2)
+ {
+ retval=toThis(s2);
+ if(s1 && s1[0])
+ {
+ if(retval)
+ {
+ retval=concat(s1,retval->data);
+ }else
+ {
+ retval=strdup(s1);
+ }
+ }
+ }else if(s1 && s1[0])
+ {
+ retval=strdup(s1);
+ }
+ return retval;
+}
+
+ // Creates with a concat operation.
+
+GP<GStringRep>
+GStringRep::concat( const GP<GStringRep> &s1,const char *s2) const
+{
+ GP<GStringRep> retval;
+ if(s1)
+ {
+ retval=toThis(s1);
+ if(s2 && s2[0])
+ {
+ if(retval)
+ {
+ retval=retval->append(s2);
+ }else
+ {
+ retval=strdup(s2);
+ }
+ }
+ }else if(s2 && s2[0])
+ {
+ retval=strdup(s2);
+ }
+ return retval;
+}
+
+GP<GStringRep>
+GStringRep::concat(const GP<GStringRep> &s1,const GP<GStringRep> &s2) const
+{
+ GP<GStringRep> retval;
+ if(s1)
+ {
+ retval=toThis(s1,s2);
+ if(retval && s2)
+ {
+ retval=retval->append(toThis(s2));
+ }
+ }else if(s2)
+ {
+ retval=toThis(s2);
+ }
+ return retval;
+}
+
+#ifdef WIN32
+static const char *setlocale_win32(void)
+{
+ static const char *locale=setlocale(LC_ALL,0);
+ if(! locale || (locale[0] == 'C' && !locale[1]))
+ {
+ locale=setlocale(LC_ALL,"");
+ }
+ return locale;
+}
+#endif
+
+GStringRep::GStringRep(void)
+{
+#ifdef WIN32
+ static const char *locale=setlocale_win32();
+#endif
+ size=0;
+ data=0;
+}
+
+GStringRep::~GStringRep()
+{
+ if(data)
+ {
+ data[0]=0;
+ ::operator delete(data);
+ }
+ data=0;
+}
+
+GStringRep::UTF8::UTF8(void) {}
+
+GStringRep::UTF8::~UTF8() {}
+
+int
+GStringRep::cmp(const char *s1,const int len) const
+{
+ return cmp(data,s1,len);
+}
+
+int
+GStringRep::cmp(const char *s1, const char *s2,const int len)
+{
+ return (len
+ ?((s1&&s1[0])
+ ?((s2&&s2[0])
+ ?((len>0)
+ ?strncmp(s1,s2,len)
+ :strcmp(s1,s2))
+ :1)
+ :((s2&&s2[0])?(-1):0))
+ :0);
+}
+
+int
+GStringRep::cmp(const GP<GStringRep> &s1, const GP<GStringRep> &s2,
+ const int len )
+{
+ return (s1?(s1->cmp(s2,len)):cmp(0,(s2?(s2->data):0),len));
+}
+
+int
+GStringRep::cmp(const GP<GStringRep> &s1, const char *s2,
+ const int len )
+{
+ return cmp((s1?s1->data:0),s2,len);
+}
+
+int
+GStringRep::cmp(const char *s1, const GP<GStringRep> &s2,
+ const int len )
+{
+ return cmp(s1,(s2?(s2->data):0),len);
+}
+
+int
+GStringRep::UTF8::cmp(const GP<GStringRep> &s2,const int len) const
+{
+ int retval;
+ if(s2)
+ {
+ if(s2->isNative())
+ {
+ GP<GStringRep> r(s2->toUTF8(true));
+ if(r)
+ {
+ retval=GStringRep::cmp(data,r->data,len);
+ }else
+ {
+ retval=-(s2->cmp(toNative(NOT_ESCAPED),len));
+ }
+ }else
+ {
+ retval=GStringRep::cmp(data,s2->data,len);
+ }
+ }else
+ {
+ retval=GStringRep::cmp(data,0,len);
+ }
+ return retval;
+}
+
+int
+GStringRep::UTF8::toInt() const
+{
+ int endpos;
+ return (int)toLong(0,endpos);
+}
+
+static inline long
+Cstrtol(char *data,char **edata, const int base)
+{
+ GStringRep::ChangeLocale locale(LC_NUMERIC,"C");
+ while (data && *data==' ') data++;
+ return strtol(data,edata,base);
+}
+
+long
+GStringRep::UTF8::toLong(
+ const int pos, int &endpos, const int base) const
+{
+ char *edata=0;
+ long retval=Cstrtol(data+pos,&edata, base);
+ if(edata)
+ {
+ endpos=edata-data;
+ }else
+ {
+ endpos=(-1);
+ GP<GStringRep> ptr=ptr->strdup(data+pos);
+ if(ptr)
+ ptr=ptr->toNative(NOT_ESCAPED);
+ if(ptr)
+ {
+ int xendpos;
+ retval=ptr->toLong(0,xendpos,base);
+ if(xendpos> 0)
+ {
+ endpos=(int)size;
+ ptr=ptr->strdup(data+xendpos);
+ if(ptr)
+ {
+ ptr=ptr->toUTF8(true);
+ if(ptr)
+ {
+ endpos-=(int)(ptr->size);
+ }
+ }
+ }
+ }
+ }
+ return retval;
+}
+
+static inline unsigned long
+Cstrtoul(char *data,char **edata, const int base)
+{
+ GStringRep::ChangeLocale locale(LC_NUMERIC,"C");
+ while (data && *data==' ') data++;
+ return strtoul(data,edata,base);
+}
+
+unsigned long
+GStringRep::UTF8::toULong(
+ const int pos, int &endpos, const int base) const
+{
+ char *edata=0;
+ unsigned long retval=Cstrtoul(data+pos,&edata, base);
+ if(edata)
+ {
+ endpos=edata-data;
+ }else
+ {
+ endpos=(-1);
+ GP<GStringRep> ptr=ptr->strdup(data+pos);
+ if(ptr)
+ ptr=ptr->toNative(NOT_ESCAPED);
+ if(ptr)
+ {
+ int xendpos;
+ retval=ptr->toULong(0,xendpos,base);
+ if(xendpos> 0)
+ {
+ endpos=(int)size;
+ ptr=ptr->strdup(data+xendpos);
+ if(ptr)
+ {
+ ptr=ptr->toUTF8(true);
+ if(ptr)
+ {
+ endpos-=(int)(ptr->size);
+ }
+ }
+ }
+ }
+ }
+ return retval;
+}
+
+static inline double
+Cstrtod(char *data,char **edata)
+{
+ GStringRep::ChangeLocale locale(LC_NUMERIC,"C");
+ while (data && *data==' ') data++;
+ return strtod(data,edata);
+}
+
+double
+GStringRep::UTF8::toDouble(const int pos, int &endpos) const
+{
+ char *edata=0;
+ double retval=Cstrtod(data+pos,&edata);
+ if(edata)
+ {
+ endpos=edata-data;
+ }else
+ {
+ endpos=(-1);
+ GP<GStringRep> ptr=ptr->strdup(data+pos);
+ if(ptr)
+ ptr=ptr->toNative(NOT_ESCAPED);
+ if(ptr)
+ {
+ int xendpos;
+ retval=ptr->toDouble(0,xendpos);
+ if(xendpos >= 0)
+ {
+ endpos=(int)size;
+ ptr=ptr->strdup(data+xendpos);
+ if(ptr)
+ {
+ ptr=ptr->toUTF8(true);
+ if(ptr)
+ {
+ endpos-=(int)(ptr->size);
+ }
+ }
+ }
+ }
+ }
+ return retval;
+}
+
+int
+GStringRep::getUCS4(unsigned long &w, const int from) const
+{
+ int retval;
+ if(from>=size)
+ {
+ w=0;
+ retval=size;
+ }else if(from<0)
+ {
+ w=(unsigned int)(-1);
+ retval=(-1);
+ }else
+ {
+ const char *source=data+from;
+ w=getValidUCS4(source);
+ retval=(int)((size_t)source-(size_t)data);
+ }
+ return retval;
+}
+
+
+unsigned long
+GStringRep::UTF8::getValidUCS4(const char *&source) const
+{
+ return GStringRep::UTF8toUCS4((const unsigned char *&)source,data+size);
+}
+
+int
+GStringRep::nextNonSpace(const int from,const int len) const
+{
+ return nextCharType(giswspace,from,len,true);
+}
+
+int
+GStringRep::nextSpace(const int from,const int len) const
+{
+ return nextCharType(giswspace,from,len,false);
+}
+
+int
+GStringRep::nextChar(const int from) const
+{
+ char const * xptr=data+from;
+ (void)getValidUCS4(xptr);
+ return (int)((size_t)xptr-(size_t)data);
+}
+
+int
+GStringRep::firstEndSpace(int from,const int len) const
+{
+ const int xsize=(len<0)?size:(from+len);
+ const int ysize=(size<xsize)?size:xsize;
+ int retval=ysize;
+ while(from<ysize)
+ {
+ from=nextNonSpace(from,ysize-from);
+ if(from < size)
+ {
+ const int r=nextSpace(from,ysize-from);
+ // If a character isn't legal, then it will return
+ // tru for both nextSpace and nextNonSpace.
+ if(r == from)
+ {
+ from++;
+ }else
+ {
+ from=retval=r;
+ }
+ }
+ }
+ return retval;
+}
+
+int
+GStringRep::UCS4toUTF16(
+ const unsigned long w,unsigned short &w1, unsigned short &w2)
+{
+ int retval;
+ if(w<0x10000)
+ {
+ w1=(unsigned short)w;
+ w2=0;
+ retval=1;
+ }else
+ {
+ w1=(unsigned short)((((w-0x10000)>>10)&0x3ff)+0xD800);
+ w2=(unsigned short)((w&0x3ff)+0xDC00);
+ retval=2;
+ }
+ return retval;
+}
+
+int
+GStringRep::UTF16toUCS4(
+ unsigned long &U,unsigned short const * const s,void const * const eptr)
+{
+ int retval=0;
+ U=0;
+ unsigned short const * const r=s+1;
+ if(r <= eptr)
+ {
+ unsigned long const W1=s[0];
+ if((W1<0xD800)||(W1>0xDFFF))
+ {
+ if((U=W1))
+ {
+ retval=1;
+ }
+ }else if(W1<=0xDBFF)
+ {
+ unsigned short const * const rr=r+1;
+ if(rr <= eptr)
+ {
+ unsigned long const W2=s[1];
+ if(((W2>=0xDC00)||(W2<=0xDFFF))&&((U=(0x10000+((W1&0x3ff)<<10))|(W2&0x3ff))))
+ {
+ retval=2;
+ }else
+ {
+ retval=(-1);
+ }
+ }
+ }
+ }
+ return retval;
+}
+
+
+//bcr
+
+GUTF8String&
+GUTF8String::operator+= (char ch)
+{
+ return init(
+ GStringRep::UTF8::create((const char*)*this,
+ GStringRep::UTF8::create(&ch,0,1)));
+}
+
+GUTF8String&
+GUTF8String::operator+= (const char *str)
+{
+ return init(GStringRep::UTF8::create(*this,str));
+}
+
+GUTF8String&
+GUTF8String::operator+= (const GBaseString &str)
+{
+ return init(GStringRep::UTF8::create(*this,str));
+}
+
+GUTF8String
+GUTF8String::substr(int from, int len) const
+{ return GUTF8String(*this, from, len); }
+
+GUTF8String
+GUTF8String::operator+(const GBaseString &s2) const
+{ return GStringRep::UTF8::create(*this,s2); }
+
+GUTF8String
+GUTF8String::operator+(const GUTF8String &s2) const
+{ return GStringRep::UTF8::create(*this,s2); }
+
+GUTF8String
+GUTF8String::operator+(const char *s2) const
+{ return GStringRep::UTF8::create(*this,s2); }
+
+char *
+GUTF8String::getbuf(int n)
+{
+ if(ptr)
+ init((*this)->getbuf(n));
+ else if(n>0)
+ init(GStringRep::UTF8::create(n));
+ else
+ init(0);
+ return ptr?((*this)->data):0;
+}
+
+void
+GUTF8String::setat(const int n, const char ch)
+{
+ if((!n)&&(!ptr))
+ {
+ init(GStringRep::UTF8::create(&ch,0,1));
+ }else
+ {
+ init((*this)->setat(CheckSubscript(n),ch));
+ }
+}
+
+GP<GStringRep>
+GStringRep::UTF8ToNative( const char *s, const EscapeMode escape )
+{
+ return GStringRep::UTF8::create(s)->toNative(escape);
+}
+
+GUTF8String::GUTF8String(const char dat)
+{ init(GStringRep::UTF8::create(&dat,0,1)); }
+
+GUTF8String::GUTF8String(const GUTF8String &fmt, va_list &args)
+{
+ if (fmt.ptr)
+ init(fmt->vformat(args));
+ else
+ init(fmt);
+}
+
+GUTF8String::GUTF8String(const char *str)
+{ init(GStringRep::UTF8::create(str)); }
+
+GUTF8String::GUTF8String(const unsigned char *str)
+{ init(GStringRep::UTF8::create((const char *)str)); }
+
+GUTF8String::GUTF8String(const unsigned short *str)
+{ init(GStringRep::UTF8::create(str,0,-1)); }
+
+GUTF8String::GUTF8String(const unsigned long *str)
+{ init(GStringRep::UTF8::create(str,0,-1)); }
+
+GUTF8String::GUTF8String(const char *dat, unsigned int len)
+{ init(GStringRep::UTF8::create(dat,0,((int)len<0)?(-1):(int)len)); }
+
+GUTF8String::GUTF8String(const unsigned short *dat, unsigned int len)
+{ init(GStringRep::UTF8::create(dat,0,((int)len<0)?(-1):(int)len)); }
+
+GUTF8String::GUTF8String(const unsigned long *dat, unsigned int len)
+{ init(GStringRep::UTF8::create(dat,0,((int)len<0)?(-1):(int)len)); }
+
+GUTF8String::GUTF8String(const GBaseString &gs, int from, int len)
+{ init(GStringRep::UTF8::create(gs,from,((int)len<0)?(-1):(int)len)); }
+
+GUTF8String::GUTF8String(const int number)
+{ init(GStringRep::UTF8::create_format("%d",number)); }
+
+GUTF8String::GUTF8String(const double number)
+{ init(GStringRep::UTF8::create_format("%f",number)); }
+
+GUTF8String& GUTF8String::operator= (const char str)
+{ return init(GStringRep::UTF8::create(&str,0,1)); }
+
+GUTF8String& GUTF8String::operator= (const char *str)
+{ return init(GStringRep::UTF8::create(str)); }
+
+GUTF8String GBaseString::operator+(const GUTF8String &s2) const
+{ return GStringRep::UTF8::create(*this,s2); }
+
+#if HAS_WCHAR
+GUTF8String
+GNativeString::operator+(const GUTF8String &s2) const
+{
+ if (ptr)
+ return GStringRep::UTF8::create((*this)->toUTF8(true),s2);
+ else
+ return GStringRep::UTF8::create((*this),s2);
+}
+#endif
+
+GUTF8String
+GUTF8String::operator+(const GNativeString &s2) const
+{
+ GP<GStringRep> g = s2;
+ if (s2.ptr)
+ g = s2->toUTF8(true);
+ return GStringRep::UTF8::create(*this,g);
+}
+
+GUTF8String
+operator+(const char *s1, const GUTF8String &s2)
+{ return GStringRep::UTF8::create(s1,s2); }
+
+#if HAS_WCHAR
+GNativeString
+operator+(const char *s1, const GNativeString &s2)
+{ return GStringRep::Native::create(s1,s2); }
+
+GNativeString&
+GNativeString::operator+= (char ch)
+{
+ char s[2]; s[0]=ch; s[1]=0;
+ return init(GStringRep::Native::create((const char*)*this, s));
+}
+
+GNativeString&
+GNativeString::operator+= (const char *str)
+{
+ return init(GStringRep::Native::create(*this,str));
+}
+
+GNativeString&
+GNativeString::operator+= (const GBaseString &str)
+{
+ return init(GStringRep::Native::create(*this,str));
+}
+
+GNativeString
+GNativeString::operator+(const GBaseString &s2) const
+{ return GStringRep::Native::create(*this,s2); }
+
+GNativeString
+GNativeString::operator+(const GNativeString &s2) const
+{ return GStringRep::Native::create(*this,s2); }
+
+GNativeString
+GNativeString::operator+(const char *s2) const
+{ return GStringRep::Native::create(*this,s2); }
+
+char *
+GNativeString::getbuf(int n)
+{
+ if(ptr)
+ init((*this)->getbuf(n));
+ else if(n>0)
+ init(GStringRep::Native::create(n));
+ else
+ init(0);
+ return ptr?((*this)->data):0;
+}
+
+void
+GNativeString::setat(const int n, const char ch)
+{
+ if((!n)&&(!ptr))
+ {
+ init(GStringRep::Native::create(&ch,0,1));
+ }else
+ {
+ init((*this)->setat(CheckSubscript(n),ch));
+ }
+}
+
+#endif
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/GString.h b/kviewshell/plugins/djvu/libdjvu/GString.h
new file mode 100644
index 00000000..601db983
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GString.h
@@ -0,0 +1,1676 @@
+//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: GString.h,v 1.19 2004/08/06 15:11:29 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _GSTRING_H_
+#define _GSTRING_H_
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+/** @name GString.h
+
+ Files #"GString.h"# and #"GString.cpp"# implement a general
+ purpose string class \Ref{GBaseString}, with dirived types
+ \Ref{GUTF8String} and \Ref{GNativeString} for UTF8 MBS encoding
+ and the current Native MBS encoding respectively. This
+ implementation relies on smart pointers (see
+ \Ref{GSmartPointer.h}).
+
+ {\bf Historical Comments} --- At some point during the DjVu
+ research era, it became clear that C++ compilers rarely provided
+ portable libraries. We then decided to avoid fancy classes (like
+ #iostream# or #string#) and to rely only on the good old C
+ library. A good string class however is very useful. We had
+ already randomly picked letter 'G' to prefix class names and we
+ logically derived the new class name. Native English speakers
+ kept laughing in hiding. This is ironic because we completely
+ forgot this letter 'G' when creating more challenging things
+ like the ZP Coder or the IW44 wavelets.
+
+ {\bf Later Changes}
+ When converting to I18N, we (Lizardtech) decided that two string classes
+ where needing, replacing the original GString with \Ref{GUTF8String} and
+ \Ref{GNativeString}.
+
+ @memo
+ General purpose string class.
+ @author
+ L\'eon Bottou <leonb@research.att.com> -- initial implementation.\\
+
+// From: Leon Bottou, 1/31/2002
+// This file has very little to do with my initial implementation.
+// It has been practically rewritten by Lizardtech for i18n changes.
+// My original implementation was very small in comparison
+// <http://prdownloads.sourceforge.net/djvu/DjVu2_2b-src.tgz>.
+// In my opinion, the duplication of the string classes is a failed
+// attempt to use the type system to enforce coding policies.
+// This could be fixed. But there are better things to do in djvulibre.
+
+ @version
+ #$Id: GString.h,v 1.19 2004/08/06 15:11:29 leonb Exp $# */
+//@{
+
+
+#include "DjVuGlobal.h"
+#include "GContainer.h"
+
+#include <stdlib.h>
+#include <stdarg.h>
+#ifdef WIN32
+# include <windows.h>
+# define HAS_WCHAR 1
+# define HAS_MBSTATE 1
+#endif
+
+#if HAS_WCHAR
+# if !defined(AUTOCONF) || HAVE_WCHAR_H
+# include <wchar.h>
+# endif
+#endif
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+#if !HAS_MBSTATE
+# ifndef HAVE_MBSTATE_T
+typedef int mbstate_t;
+# endif
+#endif
+
+class GBaseString;
+
+// Internal string representation.
+class GStringRep : public GPEnabled
+{
+public:
+ enum EncodeType { XUCS4, XUCS4BE, XUCS4LE, XUCS4_2143, XUCS4_3412,
+ XUTF16, XUTF16BE, XUTF16LE, XUTF8, XEBCDIC, XOTHER } ;
+
+ enum EscapeMode { UNKNOWN_ESCAPED=0, IS_ESCAPED=1, NOT_ESCAPED=2 };
+
+ class UTF8;
+ friend class UTF8;
+ class Unicode;
+ friend class Unicode;
+
+ class ChangeLocale;
+#if HAS_WCHAR
+ class Native;
+ friend class Native;
+#endif // HAS_WCHAR
+ friend class GBaseString;
+ friend class GUTF8String;
+ friend class GNativeString;
+ friend unsigned int hash(const GBaseString &ref);
+
+public:
+ // default constructor
+ GStringRep(void);
+ // virtual destructor
+ virtual ~GStringRep();
+
+ // Other virtual methods.
+ // Create an empty string.
+ virtual GP<GStringRep> blank(const unsigned int sz) const = 0;
+ // Create a duplicate at the given size.
+ GP<GStringRep> getbuf(int n) const;
+ // Change the value of one of the bytes.
+ GP<GStringRep> setat(int n, char ch) const;
+ // Append a string.
+ virtual GP<GStringRep> append(const GP<GStringRep> &s2) const = 0;
+ // Test if isUTF8.
+ virtual bool isUTF8(void) const { return false; }
+ // Test if Native.
+ virtual bool isNative(void) const { return false; }
+ // Convert to Native.
+ virtual GP<GStringRep> toNative(
+ const EscapeMode escape=UNKNOWN_ESCAPED ) const = 0;
+ // Convert to UTF8.
+ virtual GP<GStringRep> toUTF8(const bool nothrow=false) const = 0;
+ // Convert to same as current class.
+ virtual GP<GStringRep> toThis(
+ const GP<GStringRep> &rep,const GP<GStringRep> &locale=0) const = 0;
+ // Compare with #s2#.
+ virtual int cmp(const GP<GStringRep> &s2,const int len=(-1)) const = 0;
+
+ // Convert strings to numbers.
+ virtual int toInt(void) const = 0;
+ virtual long int toLong(
+ const int pos, int &endpos, const int base=10) const = 0;
+ virtual unsigned long toULong(
+ const int pos, int &endpos, const int base=10) const = 0;
+ virtual double toDouble(const int pos, int &endpos) const = 0;
+
+ // return the position of the next character
+ int nextChar( const int from=0 ) const;
+
+ // return next non space position
+ int nextNonSpace( const int from=0, const int len=(-1) ) const;
+
+ // return next white space position
+ int nextSpace( const int from=0, const int len=(-1) ) const;
+
+ // return the position after the last non-whitespace character.
+ int firstEndSpace( int from=0, const int len=(-1) ) const;
+
+ // Create an empty string.
+ template <class TYPE> static GP<GStringRep> create(
+ const unsigned int sz,TYPE *);
+ // Creates with a strdup string.
+ GP<GStringRep> strdup(const char *s) const;
+
+ // Creates by appending to the current string
+ GP<GStringRep> append(const char *s2) const;
+
+ // Creates with a concat operation.
+ GP<GStringRep> concat(const GP<GStringRep> &s1,const GP<GStringRep> &s2) const;
+ GP<GStringRep> concat(const char *s1,const GP<GStringRep> &s2) const;
+ GP<GStringRep> concat(const GP<GStringRep> &s1,const char *s2) const;
+ GP<GStringRep> concat(const char *s1,const char *s2) const;
+
+ /* Creates with a strdup and substr. Negative values have strlen(s)+1
+ added to them.
+ */
+ GP<GStringRep> substr(
+ const char *s,const int start,const int length=(-1)) const;
+
+ GP<GStringRep> substr(
+ const unsigned short *s,const int start,const int length=(-1)) const;
+
+ GP<GStringRep> substr(
+ const unsigned long *s,const int start,const int length=(-1)) const;
+
+ /** Initializes a string with a formatted string (as in #vprintf#). The
+ string is re-initialized with the characters generated according to the
+ specified format #fmt# and using the optional arguments. See the ANSI-C
+ function #vprintf()# for more information. The current implementation
+ will cause a segmentation violation if the resulting string is longer
+ than 32768 characters. */
+ GP<GStringRep> vformat(va_list args) const;
+ // -- SEARCHING
+
+ static GP<GStringRep> UTF8ToNative( const char *s,
+ const EscapeMode escape=UNKNOWN_ESCAPED );
+ static GP<GStringRep> NativeToUTF8( const char *s );
+
+ // Creates an uppercase version of the current string.
+ GP<GStringRep> upcase(void) const;
+ // Creates a lowercase version of the current string.
+ GP<GStringRep> downcase(void) const;
+
+ /** Returns the next UCS4 character, and updates the pointer s. */
+ static unsigned long UTF8toUCS4(
+ unsigned char const *&s, void const * const endptr );
+
+ /** Returns the number of bytes in next UCS4 character,
+ and sets #w# to the next UCS4 chacter. */
+ static int UTF8toUCS4(
+ unsigned long &w, unsigned char const s[], void const * const endptr )
+ { unsigned char const *r=s;w=UTF8toUCS4(r,endptr);return (int)((size_t)r-(size_t)s); }
+
+ /** Returns the next UCS4 word from the UTF16 string. */
+ static int UTF16toUCS4(
+ unsigned long &w, unsigned short const * const s,void const * const eptr);
+
+ static int UCS4toUTF16(
+ unsigned long w, unsigned short &w1, unsigned short &w2);
+
+ int cmp(const char *s2, const int len=(-1)) const;
+ static int cmp(
+ const GP<GStringRep> &s1, const GP<GStringRep> &s2, const int len=(-1)) ;
+ static int cmp(
+ const GP<GStringRep> &s1, const char *s2, const int len=(-1));
+ static int cmp(
+ const char *s1, const GP<GStringRep> &s2, const int len=(-1));
+ static int cmp(
+ const char *s1, const char *s2, const int len=(-1));
+
+ // Lookup the next character, and return the position of the next character.
+ int getUCS4(unsigned long &w, const int from) const;
+
+ virtual unsigned char *UCS4toString(
+ const unsigned long w, unsigned char *ptr, mbstate_t *ps=0) const = 0;
+
+ static unsigned char *UCS4toUTF8(
+ const unsigned long w,unsigned char *ptr);
+
+ static unsigned char *UCS4toNative(
+ const unsigned long w,unsigned char *ptr, mbstate_t *ps);
+
+ int search(char c, int from=0) const;
+
+ int search(char const *str, int from=0) const;
+
+ int rsearch(char c, int from=0) const;
+
+ int rsearch(char const *str, int from=0) const;
+
+ int contains(char const accept[], int from=0) const;
+
+ int rcontains(char const accept[], int from=0) const;
+
+protected:
+ // Return the next character and increment the source pointer.
+ virtual unsigned long getValidUCS4(const char *&source) const = 0;
+
+ GP<GStringRep> tocase(
+ bool (*xiswcase)(const unsigned long wc),
+ unsigned long (*xtowcase)(const unsigned long wc)) const;
+
+ // Tests if the specified character passes the xiswtest. If so, the
+ // return pointer is incremented to the next character, otherwise the
+ // specified #ptr# is returned.
+ const char * isCharType( bool (*xiswtest)(const unsigned long wc), const char *ptr,
+ const bool reverse=false) const;
+
+ // Find the next character position that passes the isCharType test.
+ int nextCharType(
+ bool (*xiswtest)(const unsigned long wc),const int from,const int len,
+ const bool reverse=false) const;
+
+ static bool giswspace(const unsigned long w);
+ static bool giswupper(const unsigned long w);
+ static bool giswlower(const unsigned long w);
+ static unsigned long gtowupper(const unsigned long w);
+ static unsigned long gtowlower(const unsigned long w);
+
+ virtual void set_remainder( void const * const buf, const unsigned int size,
+ const EncodeType encodetype);
+ virtual void set_remainder( void const * const buf, const unsigned int size,
+ const GP<GStringRep> &encoding );
+ virtual void set_remainder ( const GP<Unicode> &remainder );
+
+ virtual GP<Unicode> get_remainder( void ) const;
+
+public:
+ /* Returns a copy of this string with characters used in XML with
+ '<' to "&lt;", '>' to "&gt;", '&' to "&amp;" '\'' to
+ "&apos;", and '\"' to "&quot;". Characters 0x01 through
+ 0x1f are also escaped. */
+ GP<GStringRep> toEscaped( const bool tosevenbit ) const;
+
+ // Tests if a string is legally encoded in the current character set.
+ virtual bool is_valid(void) const = 0;
+
+ virtual int ncopy(wchar_t * const buf, const int buflen) const = 0;
+
+protected:
+
+// Actual string data.
+ int size;
+ char *data;
+};
+
+class GStringRep::UTF8 : public GStringRep
+{
+public:
+ // default constructor
+ UTF8(void);
+ // virtual destructor
+ virtual ~UTF8();
+
+ // Other virtual methods.
+ virtual GP<GStringRep> blank(const unsigned int sz = 0) const;
+ virtual GP<GStringRep> append(const GP<GStringRep> &s2) const;
+ // Test if Native.
+ virtual bool isUTF8(void) const;
+ // Convert to Native.
+ virtual GP<GStringRep> toNative(
+ const EscapeMode escape=UNKNOWN_ESCAPED) const;
+ // Convert to UTF8.
+ virtual GP<GStringRep> toUTF8(const bool nothrow=false) const;
+ // Convert to same as current class.
+ virtual GP<GStringRep> toThis(
+ const GP<GStringRep> &rep,const GP<GStringRep> &) const;
+ // Compare with #s2#.
+ virtual int cmp(const GP<GStringRep> &s2,const int len=(-1)) const;
+
+ static GP<GStringRep> create(const unsigned int sz = 0);
+
+ // Convert strings to numbers.
+ virtual int toInt(void) const;
+ virtual long int toLong(
+ const int pos, int &endpos, const int base=10) const;
+ virtual unsigned long toULong(
+ const int pos, int &endpos, const int base=10) const;
+ virtual double toDouble(
+ const int pos, int &endpos) const;
+
+ // Create a strdup string.
+ static GP<GStringRep> create(const char *s);
+
+ // Creates with a concat operation.
+ static GP<GStringRep> create(
+ const GP<GStringRep> &s1,const GP<GStringRep> &s2);
+ static GP<GStringRep> create( const GP<GStringRep> &s1,const char *s2);
+ static GP<GStringRep> create( const char *s1, const GP<GStringRep> &s2);
+ static GP<GStringRep> create( const char *s1,const char *s2);
+
+ // Create with a strdup and substr operation.
+ static GP<GStringRep> create(
+ const char *s,const int start,const int length=(-1));
+
+ static GP<GStringRep> create(
+ const unsigned short *s,const int start,const int length=(-1));
+
+ static GP<GStringRep> create(
+ const unsigned long *s,const int start,const int length=(-1));
+
+ static GP<GStringRep> create_format(const char fmt[],...);
+ static GP<GStringRep> create(const char fmt[],va_list& args);
+
+ virtual unsigned char *UCS4toString(
+ const unsigned long w,unsigned char *ptr, mbstate_t *ps=0) const;
+
+ // Tests if a string is legally encoded in the current character set.
+ virtual bool is_valid(void) const;
+
+ virtual int ncopy(wchar_t * const buf, const int buflen) const;
+
+ friend class GBaseString;
+
+protected:
+ // Return the next character and increment the source pointer.
+ virtual unsigned long getValidUCS4(const char *&source) const;
+};
+
+class GUTF8String;
+class GNativeString;
+
+/** General purpose character string.
+ Each dirivied instance of class #GBaseString# represents a
+ character string. Overloaded operators provide a value semantic
+ to #GBaseString# objects. Conversion operators and constructors
+ transparently convert between #GBaseString# objects and
+ #const char*# pointers. The #GBaseString# class has no public
+ constructors, since a dirived type should always be used
+ to specify the desired multibyte character encoding.
+
+ Functions taking strings as arguments should declare their
+ arguments as "#const char*#". Such functions will work equally
+ well with dirived #GBaseString# objects since there is a fast
+ conversion operator from the dirivied #GBaseString# objects
+ to "#const char*#". Functions returning strings should return
+ #GUTF8String# or #GNativeString# objects because the class will
+ automatically manage the necessary memory.
+
+ Characters in the string can be identified by their position. The
+ first character of a string is numbered zero. Negative positions
+ represent characters relative to the end of the string (i.e.
+ position #-1# accesses the last character of the string,
+ position #-2# represents the second last character, etc.) */
+
+class GBaseString : protected GP<GStringRep>
+{
+public:
+ enum EscapeMode {
+ UNKNOWN_ESCAPED=GStringRep::UNKNOWN_ESCAPED,
+ IS_ESCAPED=GStringRep::IS_ESCAPED,
+ NOT_ESCAPED=GStringRep::NOT_ESCAPED };
+
+ friend class GUTF8String;
+ friend class GNativeString;
+protected:
+ // Sets the gstr pointer;
+ void init(void);
+
+ ~GBaseString();
+ GBaseString &init(const GP<GStringRep> &rep);
+
+ // -- CONSTRUCTORS
+ /** Null constructor. Constructs an empty string. */
+ GBaseString( void );
+
+public:
+ // -- ACCESS
+ /** Converts a string into a constant null terminated character
+ array. This conversion operator is very efficient because
+ it simply returns a pointer to the internal string data. The
+ returned pointer remains valid as long as the string is
+ unmodified. */
+ operator const char* ( void ) const ;
+ /// Returns the string length.
+ unsigned int length( void ) const;
+ /** Returns true if and only if the string contains zero characters.
+ This operator is useful for conditional expression in control
+ structures.
+ \begin{verbatim}
+ if (! str) { ... }
+ while (!! str) { ... } -- Note the double operator!
+ \end{verbatim}
+ Class #GBaseString# does not to support syntax
+ "#if# #(str)# #{}#" because the required conversion operator
+ introduces dangerous ambiguities with certain compilers. */
+ bool operator! ( void ) const;
+
+ // -- INDEXING
+ /** Returns the character at position #n#. An exception
+ \Ref{GException} is thrown if number #n# is not in range #-len#
+ to #len-1#, where #len# is the length of the string. The first
+ character of a string is numbered zero. Negative positions
+ represent characters relative to the end of the string. */
+ char operator[] (int n) const;
+ /// Returns #TRUE# if the string contains an integer number.
+ bool is_int(void) const;
+ /// Returns #TRUE# if the string contains a float number.
+ bool is_float(void) const;
+
+ /** Converts strings between native & UTF8 **/
+ GNativeString getUTF82Native( EscapeMode escape=UNKNOWN_ESCAPED ) const;
+ GUTF8String getNative2UTF8( void ) const;
+
+ // -- ALTERING
+ /// Reinitializes a string with the null string.
+ void empty( void );
+ // -- SEARCHING
+ /** Searches character #c# in the string, starting at position
+ #from# and scanning forward until reaching the end of the
+ string. This function returns the position of the matching
+ character. It returns #-1# if character #c# cannot be found. */
+ int search(char c, int from=0) const;
+
+ /** Searches sub-string #str# in the string, starting at position
+ #from# and scanning forward until reaching the end of the
+ string. This function returns the position of the first
+ matching character of the sub-string. It returns #-1# if
+ string #str# cannot be found. */
+ int search(const char *str, int from=0) const;
+
+ /** Searches character #c# in the string, starting at position
+ #from# and scanning backwards until reaching the beginning of
+ the string. This function returns the position of the matching
+ character. It returns #-1# if character #c# cannot be found. */
+ int rsearch(char c, const int from=0) const;
+ /** Searches sub-string #str# in the string, starting at position
+ #from# and scanning backwards until reaching the beginning of
+ the string. This function returns the position of the first
+ matching character of the sub-string. It returns #-1# if
+ string #str# cannot be found. */
+ int rsearch(const char *str, const int from=0) const;
+ /** Searches for any of the specified characters in the accept
+ string. It returns #-1# if the none of the characters and
+ be found, otherwise the position of the first match. */
+ int contains(const char accept[], const int from=0) const;
+ /** Searches for any of the specified characters in the accept
+ string. It returns #-1# if the none of the characters and be
+ found, otherwise the position of the last match. */
+ int rcontains(const char accept[], const int from=0) const;
+
+ /** Concatenates strings. Returns a string composed by concatenating
+ the characters of strings #s1# and #s2#. */
+ GUTF8String operator+(const GUTF8String &s2) const;
+ GNativeString operator+(const GNativeString &s2) const;
+
+ /** Returns an integer. Implements i18n atoi. */
+ int toInt(void) const;
+
+ /** Returns a long intenger. Implments i18n strtol. */
+ long toLong(const int pos, int &endpos, const int base=10) const;
+
+ /** Returns a unsigned long integer. Implements i18n strtoul. */
+ unsigned long toULong(
+ const int pos, int &endpos, const int base=10) const;
+
+ /** Returns a double. Implements the i18n strtod. */
+ double toDouble(
+ const int pos, int &endpos ) const;
+
+ /** Returns a long intenger. Implments i18n strtol. */
+ static long toLong(
+ const GUTF8String& src, const int pos, int &endpos, const int base=10);
+
+ static unsigned long toULong(
+ const GUTF8String& src, const int pos, int &endpos, const int base=10);
+
+ static double toDouble(
+ const GUTF8String& src, const int pos, int &endpos);
+
+ /** Returns a long intenger. Implments i18n strtol. */
+ static long toLong(
+ const GNativeString& src, const int pos, int &endpos, const int base=10);
+
+ static unsigned long toULong(
+ const GNativeString& src, const int pos, int &endpos, const int base=10);
+
+ static double toDouble(
+ const GNativeString& src, const int pos, int &endpos);
+
+ // -- HASHING
+
+ // -- COMPARISONS
+ /** Returns an #int#. Compares string with #s2# and returns
+ sorting order. */
+ int cmp(const GBaseString &s2, const int len=(-1)) const;
+ /** Returns an #int#. Compares string with #s2# and returns
+ sorting order. */
+ int cmp(const char *s2, const int len=(-1)) const;
+ /** Returns an #int#. Compares string with #s2# and returns
+ sorting order. */
+ int cmp(const char s2) const;
+ /** Returns an #int#. Compares #s2# with #s2# and returns
+ sorting order. */
+ static int cmp(const char *s1, const char *s2, const int len=(-1));
+ /** Returns a boolean. The Standard C strncmp takes two string and
+ compares the first N characters. static bool GBaseString::ncmp
+ will compare #s1# with #s2# with the #len# characters starting
+ from the beginning of the string. */
+ /** String comparison. Returns true if and only if character
+ strings #s1# and #s2# are equal (as with #strcmp#.)
+ */
+ bool operator==(const GBaseString &s2) const;
+ bool operator==(const char *s2) const;
+ friend bool operator==(const char *s1, const GBaseString &s2);
+
+ /** String comparison. Returns true if and only if character
+ strings #s1# and #s2# are not equal (as with #strcmp#.)
+ */
+ bool operator!=(const GBaseString &s2) const;
+ bool operator!=(const char *s2) const;
+ friend bool operator!=(const char *s1, const GBaseString &s2);
+
+ /** String comparison. Returns true if and only if character
+ strings #s1# is lexicographically greater than or equal to
+ string #s2# (as with #strcmp#.) */
+ bool operator>=(const GBaseString &s2) const;
+ bool operator>=(const char *s2) const;
+ bool operator>=(const char s2) const;
+ friend bool operator>=(const char *s1, const GBaseString &s2);
+ friend bool operator>=(const char s1, const GBaseString &s2);
+
+ /** String comparison. Returns true if and only if character
+ strings #s1# is lexicographically less than string #s2#
+ (as with #strcmp#.)
+ */
+ bool operator<(const GBaseString &s2) const;
+ bool operator<(const char *s2) const;
+ bool operator<(const char s2) const;
+ friend bool operator<(const char *s1, const GBaseString &s2);
+ friend bool operator<(const char s1, const GBaseString &s2);
+
+ /** String comparison. Returns true if and only if character
+ strings #s1# is lexicographically greater than string #s2#
+ (as with #strcmp#.)
+ */
+ bool operator> (const GBaseString &s2) const;
+ bool operator> (const char *s2) const;
+ bool operator> (const char s2) const;
+ friend bool operator> (const char *s1, const GBaseString &s2);
+ friend bool operator> (const char s1, const GBaseString &s2);
+
+ /** String comparison. Returns true if and only if character
+ strings #s1# is lexicographically less than or equal to string
+ #s2# (as with #strcmp#.)
+ */
+ bool operator<=(const GBaseString &s2) const;
+ bool operator<=(const char *s2) const;
+ bool operator<=(const char s2) const;
+ friend bool operator<=(const char *s1, const GBaseString &s2);
+ friend bool operator<=(const char s1, const GBaseString &s2);
+
+ /** Returns an integer. Implements a functional i18n atoi. Note
+ that if you pass a GBaseString that is not in Native format
+ the results may be disparaging. */
+
+ /** Returns a hash code for the string. This hashing function
+ helps when creating associative maps with string keys (see
+ \Ref{GMap}). This hash code may be reduced to an arbitrary
+ range by computing its remainder modulo the upper bound of
+ the range. */
+ friend unsigned int hash(const GBaseString &ref);
+ // -- HELPERS
+ friend class GStringRep;
+
+ /// Returns next non space position.
+ int nextNonSpace( const int from=0, const int len=(-1) ) const;
+
+ /// Returns next character position.
+ int nextChar( const int from=0 ) const;
+
+ /// Returns next non space position.
+ int nextSpace( const int from=0, const int len=(-1) ) const;
+
+ /// return the position after the last non-whitespace character.
+ int firstEndSpace( const int from=0,const int len=(-1) ) const;
+
+ /// Tests if the string is legally encoded in the current codepage.
+ bool is_valid(void) const;
+
+ /// copy to a wchar_t buffer
+ int ncopy(wchar_t * const buf, const int buflen) const;
+
+protected:
+ const char *gstr;
+ static void throw_illegal_subscript() no_return;
+ static const char *nullstr;
+public:
+ GNativeString UTF8ToNative(
+ const bool currentlocale=false,
+ const EscapeMode escape=UNKNOWN_ESCAPED) const;
+ GUTF8String NativeToUTF8(void) const;
+protected:
+ int CheckSubscript(int n) const;
+};
+
+/** General purpose character string.
+ Each instance of class #GUTF8String# represents a character
+ string. Overloaded operators provide a value semantic to
+ #GUTF8String# objects. Conversion operators and constructors
+ transparently convert between #GUTF8String# objects and
+ #const char*# pointers.
+
+ Functions taking strings as arguments should declare their
+ arguments as "#const char*#". Such functions will work equally
+ well with #GUTF8String# objects since there is a fast conversion
+ operator from #GUTF8String# to "#const char*#". Functions
+ returning strings should return #GUTF8String# or #GNativeString#
+ objects because the class will automatically manage the necessary
+ memory.
+
+ Characters in the string can be identified by their position. The
+ first character of a string is numbered zero. Negative positions
+ represent characters relative to the end of the string (i.e.
+ position #-1# accesses the last character of the string,
+ position #-2# represents the second last character, etc.) */
+
+class GUTF8String : public GBaseString
+{
+public:
+ ~GUTF8String();
+ void init(void);
+
+ GUTF8String &init(const GP<GStringRep> &rep);
+
+ // -- CONSTRUCTORS
+ /** Null constructor. Constructs an empty string. */
+ GUTF8String(void);
+ /// Constructs a string from a character.
+ GUTF8String(const char dat);
+ /// Constructs a string from a null terminated character array.
+ GUTF8String(const char *str);
+ /// Constructs a string from a null terminated character array.
+ GUTF8String(const unsigned char *str);
+ GUTF8String(const unsigned short *dat);
+ GUTF8String(const unsigned long *dat);
+ /** Constructs a string from a character array. Elements of the
+ character array #dat# are added into the string until the
+ string length reaches #len# or until encountering a null
+ character (whichever comes first). */
+ GUTF8String(const char *dat, unsigned int len);
+ GUTF8String(const unsigned short *dat, unsigned int len);
+ GUTF8String(const unsigned long *dat, unsigned int len);
+
+ /// Construct from base class.
+ GUTF8String(const GP<GStringRep> &str);
+ GUTF8String(const GBaseString &str);
+ GUTF8String(const GUTF8String &str);
+ GUTF8String(const GNativeString &str);
+ /** Constructs a string from a character array. Elements of the
+ character array #dat# are added into the string until the
+ string length reaches #len# or until encountering a null
+ character (whichever comes first). */
+ GUTF8String(const GBaseString &gs, int from, int len);
+
+ /** Copy a null terminated character array. Resets this string
+ with the character string contained in the null terminated
+ character array #str#. */
+ GUTF8String& operator= (const char str);
+ GUTF8String& operator= (const char *str);
+ GUTF8String& operator= (const GP<GStringRep> &str);
+ GUTF8String& operator= (const GBaseString &str);
+ GUTF8String& operator= (const GUTF8String &str);
+ GUTF8String& operator= (const GNativeString &str);
+
+ /** Constructs a string with a formatted string (as in #vprintf#).
+ The string is re-initialized with the characters generated
+ according to the specified format #fmt# and using the optional
+ arguments. See the ANSI-C function #vprintf()# for more
+ information. The current implementation will cause a
+ segmentation violation if the resulting string is longer
+ than 32768 characters. */
+ GUTF8String(const GUTF8String &fmt, va_list &args);
+
+ /// Constructs a string from a character.
+ /** Constructs a string with a human-readable representation of
+ integer #number#. The format is similar to format #"%d"# in
+ function #printf#. */
+ GUTF8String(const int number);
+
+ /** Constructs a string with a human-readable representation of
+ floating point number #number#. The format is similar to
+ format #"%f"# in function #printf#. */
+ GUTF8String(const double number);
+
+
+ /** Initializes a string with a formatted string (as in #printf#).
+ The string is re-initialized with the characters generated
+ according to the specified format #fmt# and using the optional
+ arguments. See the ANSI-C function #printf()# for more
+ information. The current implementation will cause a
+ segmentation violation if the resulting string is longer
+ than 32768 characters. */
+ GUTF8String &format(const char *fmt, ... );
+ /** Initializes a string with a formatted string (as in #vprintf#).
+ The string is re-initialized with the characters generated
+ according to the specified format #fmt# and using the optional
+ arguments. See the ANSI-C function #vprintf()# for more
+ information. The current implementation will cause a
+ segmentation violation if the resulting string is longer
+ than 32768 characters. */
+ GUTF8String &vformat(const GUTF8String &fmt, va_list &args);
+
+ /** Returns a copy of this string with characters used in XML with
+ '<' to "&lt;", '>' to "&gt;", '&' to "&amp;" '\'' to
+ "&apos;", and '\"' to "&quot;". Characters 0x01 through
+ 0x1f are also escaped. */
+ GUTF8String toEscaped( const bool tosevenbit=false ) const;
+
+ /** Converts strings containing HTML/XML escaped characters into
+ their unescaped forms. Numeric representations of characters
+ (e.g., "&#38;" or "&#x26;" for "*") are the only forms
+ converted by this function. */
+ GUTF8String fromEscaped( void ) const;
+
+ /** Converts strings containing HTML/XML escaped characters
+ (e.g., "&lt;" for "<") into their unescaped forms. The
+ conversion is partially defined by the ConvMap argument which
+ specifies the conversion strings to be recognized. Numeric
+ representations of characters (e.g., "&#38;" or "&#x26;"
+ for "*") are always converted. */
+ GUTF8String fromEscaped(
+ const GMap<GUTF8String,GUTF8String> ConvMap ) const;
+
+
+ // -- CONCATENATION
+ /// Appends character #ch# to the string.
+ GUTF8String& operator+= (char ch);
+
+ /// Appends the null terminated character array #str# to the string.
+ GUTF8String& operator+= (const char *str);
+ /// Appends the specified GBaseString to the string.
+ GUTF8String& operator+= (const GBaseString &str);
+
+ /** Returns a sub-string. The sub-string is composed by copying
+ #len# characters starting at position #from# in this string.
+ The length of the resulting string may be smaller than #len#
+ if the specified range is too large. */
+ GUTF8String substr(int from, int len/*=(-1)*/) const;
+
+ /** Returns an upper case copy of this string. The returned string
+ contains a copy of the current string with all letters turned
+ into upper case letters. */
+ GUTF8String upcase( void ) const;
+ /** Returns an lower case copy of this string. The returned string
+ contains a copy of the current string with all letters turned
+ into lower case letters. */
+ GUTF8String downcase( void ) const;
+
+ /** Concatenates strings. Returns a string composed by concatenating
+ the characters of strings #s1# and #s2#.
+ */
+ GUTF8String operator+(const GBaseString &s2) const;
+ GUTF8String operator+(const GUTF8String &s2) const;
+ GUTF8String operator+(const GNativeString &s2) const;
+ GUTF8String operator+(const char *s2) const;
+ friend GUTF8String operator+(const char *s1, const GUTF8String &s2);
+
+ /** Provides a direct access to the string buffer. Returns a
+ pointer for directly accessing the string buffer. This pointer
+ valid remains valid as long as the string is not modified by
+ other means. Positive values for argument #n# represent the
+ length of the returned buffer. The returned string buffer will
+ be large enough to hold at least #n# characters plus a null
+ character. If #n# is positive but smaller than the string
+ length, the string will be truncated to #n# characters. */
+ char *getbuf(int n = -1);
+ /** Set the character at position #n# to value #ch#. An exception
+ \Ref{GException} is thrown if number #n# is not in range #-len#
+ to #len#, where #len# is the length of the string. If character
+ #ch# is zero, the string is truncated at position #n#. The
+ first character of a string is numbered zero. Negative
+ positions represent characters relative to the end of the
+ string. If position #n# is equal to the length of the string,
+ this function appends character #ch# to the end of the string. */
+ void setat(const int n, const char ch);
+public:
+ typedef enum GStringRep::EncodeType EncodeType;
+ static GUTF8String create(void const * const buf,
+ const unsigned int size,
+ const EncodeType encodetype, const GUTF8String &encoding);
+ static GUTF8String create( void const * const buf,
+ unsigned int size, const EncodeType encodetype );
+ static GUTF8String create( void const * const buf,
+ const unsigned int size, const GUTF8String &encoding );
+ static GUTF8String create( void const * const buf,
+ const unsigned int size, const GP<GStringRep::Unicode> &remainder);
+ GP<GStringRep::Unicode> get_remainder(void) const;
+ static GUTF8String create( const char *buf, const unsigned int bufsize );
+ static GUTF8String create( const unsigned short *buf, const unsigned int bufsize );
+ static GUTF8String create( const unsigned long *buf, const unsigned int bufsize );
+};
+
+
+#if !HAS_WCHAR
+#define GBaseString GUTF8String
+#endif
+
+/** General purpose character string.
+ Each instance of class #GNativeString# represents a character
+ string. Overloaded operators provide a value semantic to
+ #GNativeString# objects. Conversion operators and constructors
+ transparently convert between #GNativeString# objects and
+ #const char*# pointers.
+
+ Functions taking strings as arguments should declare their
+ arguments as "#const char*#". Such functions will work equally
+ well with #GNativeString# objects since there is a fast conversion
+ operator from #GNativeString# to "#const char*#". Functions
+ returning strings should return #GUTF8String# or #GNativeString#
+ objects because the class will automatically manage the necessary
+ memory.
+
+ Characters in the string can be identified by their position. The
+ first character of a string is numbered zero. Negative positions
+ represent characters relative to the end of the string (i.e.
+ position #-1# accesses the last character of the string,
+ position #-2# represents the second last character, etc.) */
+
+class GNativeString : public GBaseString
+{
+public:
+ ~GNativeString();
+ // -- CONSTRUCTORS
+ /** Null constructor. Constructs an empty string. */
+ GNativeString(void);
+ /// Constructs a string from a character.
+ GNativeString(const char dat);
+ /// Constructs a string from a null terminated character array.
+ GNativeString(const char *str);
+ /// Constructs a string from a null terminated character array.
+ GNativeString(const unsigned char *str);
+ GNativeString(const unsigned short *str);
+ GNativeString(const unsigned long *str);
+ /** Constructs a string from a character array. Elements of the
+ character array #dat# are added into the string until the
+ string length reaches #len# or until encountering a null
+ character (whichever comes first). */
+ GNativeString(const char *dat, unsigned int len);
+ GNativeString(const unsigned short *dat, unsigned int len);
+ GNativeString(const unsigned long *dat, unsigned int len);
+ /// Construct from base class.
+ GNativeString(const GP<GStringRep> &str);
+ GNativeString(const GBaseString &str);
+#if HAS_WCHAR
+ GNativeString(const GUTF8String &str);
+#endif
+ GNativeString(const GNativeString &str);
+ /** Constructs a string from a character array. Elements of the
+ character array #dat# are added into the string until the
+ string length reaches #len# or until encountering a null
+ character (whichever comes first). */
+ GNativeString(const GBaseString &gs, int from, int len);
+
+ /** Constructs a string with a formatted string (as in #vprintf#).
+ The string is re-initialized with the characters generated
+ according to the specified format #fmt# and using the optional
+ arguments. See the ANSI-C function #vprintf()# for more
+ information. The current implementation will cause a
+ segmentation violation if the resulting string is longer than
+ 32768 characters. */
+ GNativeString(const GNativeString &fmt, va_list &args);
+
+ /** Constructs a string with a human-readable representation of
+ integer #number#. The format is similar to format #"%d"# in
+ function #printf#. */
+ GNativeString(const int number);
+
+ /** Constructs a string with a human-readable representation of
+ floating point number #number#. The format is similar to
+ format #"%f"# in function #printf#. */
+ GNativeString(const double number);
+
+#if !HAS_WCHAR
+#undef GBaseString
+#else
+ /// Initialize this string class
+ void init(void);
+
+ /// Initialize this string class
+ GNativeString &init(const GP<GStringRep> &rep);
+
+ /** Copy a null terminated character array. Resets this string with
+ the character string contained in the null terminated character
+ array #str#. */
+ GNativeString& operator= (const char str);
+ GNativeString& operator= (const char *str);
+ GNativeString& operator= (const GP<GStringRep> &str);
+ GNativeString& operator= (const GBaseString &str);
+ GNativeString& operator= (const GUTF8String &str);
+ GNativeString& operator= (const GNativeString &str);
+ // -- CONCATENATION
+ /// Appends character #ch# to the string.
+ GNativeString& operator+= (char ch);
+ /// Appends the null terminated character array #str# to the string.
+ GNativeString& operator+= (const char *str);
+ /// Appends the specified GBaseString to the string.
+ GNativeString& operator+= (const GBaseString &str);
+
+ /** Returns a sub-string. The sub-string is composed by copying
+ #len# characters starting at position #from# in this string.
+ The length of the resulting string may be smaller than #len#
+ if the specified range is too large. */
+ GNativeString substr(int from, int len/*=(-1)*/) const;
+
+ /** Returns an upper case copy of this string. The returned
+ string contains a copy of the current string with all letters
+ turned into upper case letters. */
+ GNativeString upcase( void ) const;
+ /** Returns an lower case copy of this string. The returned
+ string contains a copy of the current string with all letters
+ turned into lower case letters. */
+ GNativeString downcase( void ) const;
+
+
+ GNativeString operator+(const GBaseString &s2) const;
+ GNativeString operator+(const GNativeString &s2) const;
+ GUTF8String operator+(const GUTF8String &s2) const;
+ GNativeString operator+(const char *s2) const;
+ friend GNativeString operator+(const char *s1, const GNativeString &s2);
+
+ /** Initializes a string with a formatted string (as in #printf#).
+ The string is re-initialized with the characters generated
+ according to the specified format #fmt# and using the optional
+ arguments. See the ANSI-C function #printf()# for more
+ information. The current implementation will cause a
+ segmentation violation if the resulting string is longer than
+ 32768 characters. */
+ GNativeString &format(const char *fmt, ... );
+ /** Initializes a string with a formatted string (as in #vprintf#).
+ The string is re-initialized with the characters generated
+ according to the specified format #fmt# and using the optional
+ arguments. See the ANSI-C function #vprintf()# for more
+ information. The current implementation will cause a
+ segmentation violation if the resulting string is longer than
+ 32768 characters. */
+ GNativeString &vformat(const GNativeString &fmt, va_list &args);
+
+ /** Returns a copy of this string with characters used in XML with
+ '<' to "&lt;", '>' to "&gt;", '&' to "&amp;" '\'' to
+ "&apos;", and '\"' to "&quot;". Characters 0x01 through
+ 0x1f are also escaped. */
+ GNativeString toEscaped( const bool tosevenbit=false ) const;
+
+
+ /** Provides a direct access to the string buffer. Returns a
+ pointer for directly accessing the string buffer. This
+ pointer valid remains valid as long as the string is not
+ modified by other means. Positive values for argument #n#
+ represent the length of the returned buffer. The returned
+ string buffer will be large enough to hold at least #n#
+ characters plus a null character. If #n# is positive but
+ smaller than the string length, the string will be truncated
+ to #n# characters. */
+ char *getbuf(int n = -1);
+ /** Set the character at position #n# to value #ch#. An exception
+ \Ref{GException} is thrown if number #n# is not in range #-len#
+ to #len#, where #len# is the length of the string. If
+ character #ch# is zero, the string is truncated at position
+ #n#. The first character of a string is numbered zero.
+ Negative positions represent characters relative to the end of
+ the string. If position #n# is equal to the length of the
+ string, this function appends character #ch# to the end of the
+ string. */
+ void setat(const int n, const char ch);
+
+ static GNativeString create( const char *buf, const unsigned int bufsize );
+ static GNativeString create( const unsigned short *buf, const unsigned int bufsize );
+ static GNativeString create( const unsigned long *buf, const unsigned int bufsize );
+#endif // WinCE
+};
+
+//@}
+
+inline
+GBaseString::operator const char* ( void ) const
+{
+ return ptr?(*this)->data:nullstr;
+}
+
+inline unsigned int
+GBaseString::length( void ) const
+{
+ return ptr ? (*this)->size : 0;
+}
+
+inline bool
+GBaseString::operator! ( void ) const
+{
+ return !ptr;
+}
+
+inline GUTF8String
+GUTF8String::upcase( void ) const
+{
+ if (ptr) return (*this)->upcase();
+ return *this;
+}
+
+inline GUTF8String
+GUTF8String::downcase( void ) const
+{
+ if (ptr) return (*this)->downcase();
+ return *this;
+}
+
+inline void
+GUTF8String::init(void)
+{ GBaseString::init(); }
+
+inline GUTF8String &
+GUTF8String::init(const GP<GStringRep> &rep)
+{ GP<GStringRep>::operator=(rep?rep->toUTF8(true):rep); init(); return *this; }
+
+inline GUTF8String &
+GUTF8String::vformat(const GUTF8String &fmt, va_list &args)
+{ return (*this = (fmt.ptr?GUTF8String(fmt,args):fmt)); }
+
+inline GUTF8String
+GUTF8String::toEscaped( const bool tosevenbit ) const
+{ return ptr?GUTF8String((*this)->toEscaped(tosevenbit)):(*this); }
+
+inline GP<GStringRep::Unicode>
+GUTF8String::get_remainder(void) const
+{
+ GP<GStringRep::Unicode> retval;
+ if(ptr)
+ retval=((*this)->get_remainder());
+ return retval;
+}
+
+inline
+GUTF8String::GUTF8String(const GNativeString &str)
+{ init(str.length()?(str->toUTF8(true)):(GP<GStringRep>)str); }
+
+inline
+GUTF8String::GUTF8String(const GP<GStringRep> &str)
+{ init(str?(str->toUTF8(true)):str); }
+
+inline
+GUTF8String::GUTF8String(const GBaseString &str)
+{ init(str.length()?(str->toUTF8(true)):(GP<GStringRep>)str); }
+
+inline void
+GBaseString::init(void)
+{
+ gstr=ptr?((*this)->data):nullstr;
+}
+/** Returns an integer. Implements i18n atoi. */
+inline int
+GBaseString::toInt(void) const
+{ return ptr?(*this)->toInt():0; }
+
+/** Returns a long intenger. Implments i18n strtol. */
+inline long
+GBaseString::toLong(const int pos, int &endpos, const int base) const
+{
+ long int retval=0;
+ if(ptr)
+ {
+ retval=(*this)->toLong(pos, endpos, base);
+ }else
+ {
+ endpos=(-1);
+ }
+ return retval;
+}
+
+inline long
+GBaseString::toLong(
+ const GUTF8String& src, const int pos, int &endpos, const int base)
+{
+ return src.toLong(pos,endpos,base);
+}
+
+inline long
+GBaseString::toLong(
+ const GNativeString& src, const int pos, int &endpos, const int base)
+{
+ return src.toLong(pos,endpos,base);
+}
+
+/** Returns a unsigned long integer. Implements i18n strtoul. */
+inline unsigned long
+GBaseString::toULong(const int pos, int &endpos, const int base) const
+{
+ unsigned long retval=0;
+ if(ptr)
+ {
+ retval=(*this)->toULong(pos, endpos, base);
+ }else
+ {
+ endpos=(-1);
+ }
+ return retval;
+}
+
+inline unsigned long
+GBaseString::toULong(
+ const GUTF8String& src, const int pos, int &endpos, const int base)
+{
+ return src.toULong(pos,endpos,base);
+}
+
+inline unsigned long
+GBaseString::toULong(
+ const GNativeString& src, const int pos, int &endpos, const int base)
+{
+ return src.toULong(pos,endpos,base);
+}
+
+/** Returns a double. Implements the i18n strtod. */
+inline double
+GBaseString::toDouble(
+ const int pos, int &endpos ) const
+{
+ double retval=(double)0;
+ if(ptr)
+ {
+ retval=(*this)->toDouble(pos, endpos);
+ }else
+ {
+ endpos=(-1);
+ }
+ return retval;
+}
+
+inline double
+GBaseString::toDouble(
+ const GUTF8String& src, const int pos, int &endpos)
+{
+ return src.toDouble(pos,endpos);
+}
+
+inline double
+GBaseString::toDouble(
+ const GNativeString& src, const int pos, int &endpos)
+{
+ return src.toDouble(pos,endpos);
+}
+
+inline GBaseString &
+GBaseString::init(const GP<GStringRep> &rep)
+{ GP<GStringRep>::operator=(rep); init(); return *this;}
+
+inline char
+GBaseString::operator[] (int n) const
+{ return ((n||ptr)?((*this)->data[CheckSubscript(n)]):0); }
+
+inline int
+GBaseString::search(char c, int from) const
+{ return ptr?((*this)->search(c,from)):(-1); }
+
+inline int
+GBaseString::search(const char *str, int from) const
+{ return ptr?((*this)->search(str,from)):(-1); }
+
+inline int
+GBaseString::rsearch(char c, const int from) const
+{ return ptr?((*this)->rsearch(c,from)):(-1); }
+
+inline int
+GBaseString::rsearch(const char *str, const int from) const
+{ return ptr?((*this)->rsearch(str,from)):(-1); }
+
+inline int
+GBaseString::contains(const char accept[], const int from) const
+{ return ptr?((*this)->contains(accept,from)):(-1); }
+
+inline int
+GBaseString::rcontains(const char accept[], const int from) const
+{ return ptr?((*this)->rcontains(accept,from)):(-1); }
+
+inline int
+GBaseString::cmp(const GBaseString &s2, const int len) const
+{ return GStringRep::cmp(*this,s2,len); }
+
+inline int
+GBaseString::cmp(const char *s2, const int len) const
+{ return GStringRep::cmp(*this,s2,len); }
+
+inline int
+GBaseString::cmp(const char s2) const
+{ return GStringRep::cmp(*this,&s2,1); }
+
+inline int
+GBaseString::cmp(const char *s1, const char *s2, const int len)
+{ return GStringRep::cmp(s1,s2,len); }
+
+inline bool
+GBaseString::operator==(const GBaseString &s2) const
+{ return !cmp(s2); }
+
+inline bool
+GBaseString::operator==(const char *s2) const
+{ return !cmp(s2); }
+
+inline bool
+GBaseString::operator!=(const GBaseString &s2) const
+{ return !!cmp(s2); }
+
+inline bool
+GBaseString::operator!=(const char *s2) const
+{ return !!cmp(s2); }
+
+inline bool
+GBaseString::operator>=(const GBaseString &s2) const
+{ return (cmp(s2)>=0); }
+
+inline bool
+GBaseString::operator>=(const char *s2) const
+{ return (cmp(s2)>=0); }
+
+inline bool
+GBaseString::operator>=(const char s2) const
+{ return (cmp(s2)>=0); }
+
+inline bool
+GBaseString::operator<(const GBaseString &s2) const
+{ return (cmp(s2)<0); }
+
+inline bool
+GBaseString::operator<(const char *s2) const
+{ return (cmp(s2)<0); }
+
+inline bool
+GBaseString::operator<(const char s2) const
+{ return (cmp(s2)<0); }
+
+inline bool
+GBaseString::operator> (const GBaseString &s2) const
+{ return (cmp(s2)>0); }
+
+inline bool
+GBaseString::operator> (const char *s2) const
+{ return (cmp(s2)>0); }
+
+inline bool
+GBaseString::operator> (const char s2) const
+{ return (cmp(s2)>0); }
+
+inline bool
+GBaseString::operator<=(const GBaseString &s2) const
+{ return (cmp(s2)<=0); }
+
+inline bool
+GBaseString::operator<=(const char *s2) const
+{ return (cmp(s2)<=0); }
+
+inline bool
+GBaseString::operator<=(const char s2) const
+{ return (cmp(s2)<=0); }
+
+inline int
+GBaseString::nextNonSpace( const int from, const int len ) const
+{ return ptr?(*this)->nextNonSpace(from,len):0; }
+
+inline int
+GBaseString::nextChar( const int from ) const
+{ return ptr?(*this)->nextChar(from):0; }
+
+inline int
+GBaseString::nextSpace( const int from, const int len ) const
+{ return ptr?(*this)->nextSpace(from,len):0; }
+
+inline int
+GBaseString::firstEndSpace( const int from,const int len ) const
+{ return ptr?(*this)->firstEndSpace(from,len):0; }
+
+inline bool
+GBaseString::is_valid(void) const
+{ return ptr?((*this)->is_valid()):true; }
+
+inline int
+GBaseString::ncopy(wchar_t * const buf, const int buflen) const
+{if(buf&&buflen)buf[0]=0;return ptr?((*this)->ncopy(buf,buflen)):0;}
+
+inline int
+GBaseString::CheckSubscript(int n) const
+{
+ if(n)
+ {
+ if (n<0 && ptr)
+ n += (*this)->size;
+ if (n<0 || !ptr || n > (int)(*this)->size)
+ throw_illegal_subscript();
+ }
+ return n;
+}
+
+inline GBaseString::GBaseString(void) { init(); }
+
+inline GUTF8String::GUTF8String(void) { }
+
+inline GUTF8String::GUTF8String(const GUTF8String &str) : GBaseString(str)
+{ init(str); }
+
+inline GUTF8String& GUTF8String::operator= (const GP<GStringRep> &str)
+{ return init(str); }
+
+inline GUTF8String& GUTF8String::operator= (const GBaseString &str)
+{ return init(str); }
+
+inline GUTF8String& GUTF8String::operator= (const GUTF8String &str)
+{ return init(str); }
+
+inline GUTF8String& GUTF8String::operator= (const GNativeString &str)
+{ return init(str); }
+
+inline GUTF8String
+GUTF8String::create( const char *buf, const unsigned int bufsize )
+{
+#if HAS_WCHAR
+ return GNativeString(buf,bufsize);
+#else
+ return GUTF8String(buf,bufsize);
+#endif
+}
+
+inline GUTF8String
+GUTF8String::create( const unsigned short *buf, const unsigned int bufsize )
+{
+ return GUTF8String(buf,bufsize);
+}
+
+inline GUTF8String
+GUTF8String::create( const unsigned long *buf, const unsigned int bufsize )
+{
+ return GUTF8String(buf,bufsize);
+}
+
+inline GNativeString::GNativeString(void) {}
+
+#if !HAS_WCHAR
+// For Windows CE, GNativeString is essentially GUTF8String
+
+inline
+GNativeString::GNativeString(const GUTF8String &str)
+: GUTF8String(str) {}
+
+inline
+GNativeString::GNativeString(const GP<GStringRep> &str)
+: GUTF8String(str) {}
+
+inline
+GNativeString::GNativeString(const char dat)
+: GUTF8String(dat) {}
+
+inline
+GNativeString::GNativeString(const char *str)
+: GUTF8String(str) {}
+
+inline
+GNativeString::GNativeString(const unsigned char *str)
+: GUTF8String(str) {}
+
+inline
+GNativeString::GNativeString(const unsigned short *str)
+: GUTF8String(str) {}
+
+inline
+GNativeString::GNativeString(const unsigned long *str)
+: GUTF8String(str) {}
+
+inline
+GNativeString::GNativeString(const char *dat, unsigned int len)
+: GUTF8String(dat,len) {}
+
+inline
+GNativeString::GNativeString(const unsigned short *dat, unsigned int len)
+: GUTF8String(dat,len) {}
+
+inline
+GNativeString::GNativeString(const unsigned long *dat, unsigned int len)
+: GUTF8String(dat,len) {}
+
+inline
+GNativeString::GNativeString(const GNativeString &str)
+: GUTF8String(str) {}
+
+inline
+GNativeString::GNativeString(const int number)
+: GUTF8String(number) {}
+
+inline
+GNativeString::GNativeString(const double number)
+: GUTF8String(number) {}
+
+inline
+GNativeString::GNativeString(const GNativeString &fmt, va_list &args)
+: GUTF8String(fmt,args) {}
+
+#else // HAS_WCHAR
+
+/// Initialize this string class
+inline void
+GNativeString::init(void)
+{ GBaseString::init(); }
+
+/// Initialize this string class
+inline GNativeString &
+GNativeString::init(const GP<GStringRep> &rep)
+{
+ GP<GStringRep>::operator=(rep?rep->toNative(GStringRep::NOT_ESCAPED):rep);
+ init();
+ return *this;
+}
+
+inline GNativeString
+GNativeString::substr(int from, int len) const
+{ return GNativeString(*this, from, len); }
+
+inline GNativeString &
+GNativeString::vformat(const GNativeString &fmt, va_list &args)
+{ return (*this = (fmt.ptr?GNativeString(fmt,args):fmt)); }
+
+inline GNativeString
+GNativeString::toEscaped( const bool tosevenbit ) const
+{ return ptr?GNativeString((*this)->toEscaped(tosevenbit)):(*this); }
+
+inline
+GNativeString::GNativeString(const GUTF8String &str)
+{
+ if (str.length())
+ init(str->toNative(GStringRep::NOT_ESCAPED));
+ else
+ init((GP<GStringRep>)str);
+}
+
+inline
+GNativeString::GNativeString(const GP<GStringRep> &str)
+{
+ if (str)
+ init(str->toNative(GStringRep::NOT_ESCAPED));
+ else
+ init(str);
+}
+
+inline
+GNativeString::GNativeString(const GBaseString &str)
+{
+ if (str.length())
+ init(str->toNative(GStringRep::NOT_ESCAPED));
+ else
+ init((GP<GStringRep>)str);
+}
+
+
+inline
+GNativeString::GNativeString(const GNativeString &fmt, va_list &args)
+{
+ if (fmt.ptr)
+ init(fmt->vformat(args));
+ else
+ init(fmt);
+}
+
+inline GNativeString
+GNativeString::create( const char *buf, const unsigned int bufsize )
+{
+ return GNativeString(buf,bufsize);
+}
+
+inline GNativeString
+GNativeString::create( const unsigned short *buf, const unsigned int bufsize )
+{
+ return GNativeString(buf,bufsize);
+}
+
+inline GNativeString
+GNativeString::create( const unsigned long *buf, const unsigned int bufsize )
+{
+ return GNativeString(buf,bufsize);
+}
+
+inline GNativeString&
+GNativeString::operator= (const GP<GStringRep> &str)
+{ return init(str); }
+
+inline GNativeString&
+GNativeString::operator= (const GBaseString &str)
+{ return init(str); }
+
+inline GNativeString&
+GNativeString::operator= (const GUTF8String &str)
+{ return init(str); }
+
+inline GNativeString&
+GNativeString::operator= (const GNativeString &str)
+{ return init(str); }
+
+inline GNativeString
+GNativeString::upcase( void ) const
+{
+ if (ptr) return (*this)->upcase();
+ return *this;
+}
+
+inline GNativeString
+GNativeString::downcase( void ) const
+{
+ if (ptr) return (*this)->downcase();
+ return *this;
+}
+
+#endif // HAS_WCHAR
+
+inline bool
+operator==(const char *s1, const GBaseString &s2)
+{ return !s2.cmp(s1); }
+
+inline bool
+operator!=(const char *s1, const GBaseString &s2)
+{ return !!s2.cmp(s1); }
+
+inline bool
+operator>=(const char *s1, const GBaseString &s2)
+{ return (s2.cmp(s1)<=0); }
+
+inline bool
+operator>=(const char s1, const GBaseString &s2)
+{ return (s2.cmp(s1)<=0); }
+
+inline bool
+operator<(const char *s1, const GBaseString &s2)
+{ return (s2.cmp(s1)>0); }
+
+inline bool
+operator<(const char s1, const GBaseString &s2)
+{ return (s2.cmp(s1)>0); }
+
+inline bool
+operator> (const char *s1, const GBaseString &s2)
+{ return (s2.cmp(s1)<0); }
+
+inline bool
+operator> (const char s1, const GBaseString &s2)
+{ return (s2.cmp(s1)<0); }
+
+inline bool
+operator<=(const char *s1, const GBaseString &s2)
+{ return !(s1>s2); }
+
+inline bool
+operator<=(const char s1, const GBaseString &s2)
+{ return !(s1>s2); }
+
+// ------------------- The end
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
+
diff --git a/kviewshell/plugins/djvu/libdjvu/GThreads.cpp b/kviewshell/plugins/djvu/libdjvu/GThreads.cpp
new file mode 100644
index 00000000..ce88361e
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GThreads.cpp
@@ -0,0 +1,1887 @@
+//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: GThreads.cpp,v 1.15 2004/04/21 14:54:43 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+// This file defines machine independent classes
+// for running and synchronizing threads.
+// - Author: Leon Bottou, 01/1998
+
+// From: Leon Bottou, 1/31/2002
+// Almost unchanged by Lizardtech.
+// GSafeFlags should go because it not as safe as it claims.
+
+#include "GThreads.h"
+#include "GException.h"
+#include "DjVuMessageLite.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+// ----------------------------------------
+// Consistency check
+
+#if THREADMODEL!=NOTHREADS
+#ifdef USE_EXCEPTION_EMULATION
+#warning "Compiler must support thread safe exceptions"
+#endif //USE_EXCEPTION_EMULATION
+#if defined(__GNUC__)
+#if (__GNUC__<2) || ((__GNUC__==2) && (__GNUC_MINOR__<=8))
+#warning "GCC 2.8 exceptions are not thread safe."
+#warning "Use properly configured EGCS-1.1 or greater."
+#endif // (__GNUC__<2 ...
+#endif // defined(__GNUC__)
+#endif // THREADMODEL!=NOTHREADS
+
+#ifndef _DEBUG
+#if defined(DEBUG)
+#define _DEBUG /* */
+#elif DEBUGLVL >= 1
+#define _DEBUG /* */
+#endif
+#endif
+
+#if THREADMODEL==WINTHREADS
+# include <process.h>
+#endif
+#if THREADMODEL==COTHREADS
+# include <setjmp.h>
+# include <string.h>
+# include <unistd.h>
+# include <sys/types.h>
+# include <sys/time.h>
+#endif
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+// ----------------------------------------
+// NOTHREADS
+// ----------------------------------------
+
+#if THREADMODEL==NOTHREADS
+int
+GThread::create( void (*entry)(void*), void *arg)
+{
+ (*entry)(arg);
+ return 0;
+}
+#endif
+
+
+// ----------------------------------------
+// WIN32 IMPLEMENTATION
+// ----------------------------------------
+
+#if THREADMODEL==WINTHREADS
+
+static unsigned __stdcall
+start(void *arg)
+{
+ GThread *gt = (GThread*)arg;
+ try
+ {
+ G_TRY
+ {
+ gt->xentry( gt->xarg );
+ }
+ G_CATCH(ex)
+ {
+ ex.perror();
+ DjVuMessageLite::perror( ERR_MSG("GThreads.uncaught") );
+#ifdef _DEBUG
+ abort();
+#endif
+ }
+ G_ENDCATCH;
+ }
+ catch(...)
+ {
+ DjVuMessageLite::perror( ERR_MSG("GThreads.unrecognized") );
+#ifdef _DEBUG
+ abort();
+#endif
+ }
+ return 0;
+}
+
+GThread::GThread(int stacksize)
+ : hthr(0), thrid(0), xentry(0), xarg(0)
+{
+}
+
+GThread::~GThread()
+{
+ if (hthr)
+ CloseHandle(hthr);
+ hthr = 0;
+ thrid = 0;
+}
+
+int
+GThread::create(void (*entry)(void*), void *arg)
+{
+ if (hthr)
+ return -1;
+ xentry = entry;
+ xarg = arg;
+ unsigned uthread = 0;
+ hthr = (HANDLE)_beginthreadex(NULL, 0, start, (void*)this, 0, &uthread);
+ thrid = (DWORD) uthread;
+ if (hthr)
+ return 0;
+ return -1;
+}
+
+void
+GThread::terminate()
+{
+ OutputDebugString("Terminating thread.\n");
+ if (hthr)
+ TerminateThread(hthr,0);
+}
+
+int
+GThread::yield()
+{
+ Sleep(0);
+ return 0;
+}
+
+void *
+GThread::current()
+{
+ return (void*) GetCurrentThreadId();
+}
+
+struct thr_waiting {
+ struct thr_waiting *next;
+ struct thr_waiting *prev;
+ BOOL waiting;
+ HANDLE gwait;
+};
+
+GMonitor::GMonitor()
+ : ok(0), count(1), head(0), tail(0)
+{
+ InitializeCriticalSection(&cs);
+ locker = GetCurrentThreadId();
+ ok = 1;
+}
+
+GMonitor::~GMonitor()
+{
+ ok = 0;
+ EnterCriticalSection(&cs);
+ for (struct thr_waiting *w=head; w; w=w->next)
+ SetEvent(w->gwait);
+ LeaveCriticalSection(&cs);
+ DeleteCriticalSection(&cs);
+}
+
+void
+GMonitor::enter()
+{
+ DWORD self = GetCurrentThreadId();
+ if (count>0 || self!=locker)
+ {
+ if (ok)
+ EnterCriticalSection(&cs);
+ locker = self;
+ count = 1;
+ }
+ count -= 1;
+}
+
+void
+GMonitor::leave()
+{
+ DWORD self = GetCurrentThreadId();
+ if (ok && (count>0 || self!=locker))
+ G_THROW( ERR_MSG("GThreads.not_acq_broad") );
+ count += 1;
+ if (count > 0)
+ {
+ count = 1;
+ if (ok)
+ LeaveCriticalSection(&cs);
+ }
+}
+
+void
+GMonitor::signal()
+{
+ if (ok)
+ {
+ DWORD self = GetCurrentThreadId();
+ if (count>0 || self!=locker)
+ G_THROW( ERR_MSG("GThreads.not_acq_signal") );
+ for (struct thr_waiting *w=head; w; w=w->next)
+ if (w->waiting)
+ {
+ SetEvent(w->gwait);
+ w->waiting = FALSE;
+ break; // Only one thread is allowed to run!
+ }
+ }
+}
+
+void
+GMonitor::broadcast()
+{
+ if (ok)
+ {
+ DWORD self = GetCurrentThreadId();
+ if (count>0 || self!=locker)
+ G_THROW( ERR_MSG("GThreads.not_acq_broad") );
+ for (struct thr_waiting *w=head; w; w=w->next)
+ if (w->waiting)
+ {
+ SetEvent(w->gwait);
+ w->waiting = FALSE;
+ }
+ }
+}
+
+void
+GMonitor::wait()
+{
+ // Check state
+ DWORD self = GetCurrentThreadId();
+ if (count>0 || self!=locker)
+ G_THROW( ERR_MSG("GThreads.not_acq_wait") );
+ // Wait
+ if (ok)
+ {
+ // Prepare wait record
+ struct thr_waiting waitrec;
+ waitrec.waiting = TRUE;
+ waitrec.gwait = CreateEvent(NULL,FALSE,FALSE,NULL);
+ waitrec.next = 0;
+ waitrec.prev = tail;
+ // Link wait record (protected by critical section)
+ *(waitrec.next ? &waitrec.next->prev : &tail) = &waitrec;
+ *(waitrec.prev ? &waitrec.prev->next : &head) = &waitrec;
+ // Start wait
+ int sav_count = count;
+ count = 1;
+ LeaveCriticalSection(&cs);
+ WaitForSingleObject(waitrec.gwait,INFINITE);
+ // Re-acquire
+ EnterCriticalSection(&cs);
+ count = sav_count;
+ locker = self;
+ // Unlink wait record
+ *(waitrec.next ? &waitrec.next->prev : &tail) = waitrec.prev;
+ *(waitrec.prev ? &waitrec.prev->next : &head) = waitrec.next;
+ CloseHandle(waitrec.gwait);
+ }
+}
+
+void
+GMonitor::wait(unsigned long timeout)
+{
+ // Check state
+ DWORD self = GetCurrentThreadId();
+ if (count>0 || self!=locker)
+ G_THROW( ERR_MSG("GThreads.not_acq_wait") );
+ // Wait
+ if (ok)
+ {
+ // Prepare wait record
+ struct thr_waiting waitrec;
+ waitrec.waiting = TRUE;
+ waitrec.gwait = CreateEvent(NULL,FALSE,FALSE,NULL);
+ waitrec.next = 0;
+ waitrec.prev = tail;
+ // Link wait record (protected by critical section)
+ *(waitrec.prev ? &waitrec.prev->next : &head) = &waitrec;
+ *(waitrec.next ? &waitrec.next->prev : &tail) = &waitrec;
+ // Start wait
+ int sav_count = count;
+ count = 1;
+ LeaveCriticalSection(&cs);
+ WaitForSingleObject(waitrec.gwait,timeout);
+ // Re-acquire
+ EnterCriticalSection(&cs);
+ count = sav_count;
+ locker = self;
+ // Unlink wait record
+ *(waitrec.next ? &waitrec.next->prev : &tail) = waitrec.prev;
+ *(waitrec.prev ? &waitrec.prev->next : &head) = waitrec.next;
+ CloseHandle(waitrec.gwait);
+ }
+}
+
+#endif
+
+
+
+// ----------------------------------------
+// MACTHREADS IMPLEMENTATION (from Praveen)
+// ----------------------------------------
+
+#if THREADMODEL==MACTHREADS
+
+// Doubly linked list of waiting threads
+struct thr_waiting {
+ struct thr_waiting *next; // ptr to next waiting thread record
+ struct thr_waiting *prev; // ptr to ptr to this waiting thread
+ unsigned long thid; // id of waiting thread
+ int *wchan; // cause of the wait
+};
+static struct thr_waiting *first_waiting_thr = 0;
+static struct thr_waiting *last_waiting_thr = 0;
+
+
+// Stops current thread.
+// Argument ``self'' must be current thread id.
+// Assumes ``ThreadBeginCritical'' has been called before.
+static void
+macthread_wait(ThreadID self, int *wchan)
+{
+ // Prepare and link wait record
+ struct thr_waiting wait; // no need to malloc :-)
+ wait.thid = self;
+ wait.wchan = wchan;
+ wait.next = 0;
+ wait.prev = last_waiting_thr;
+ *(wait.prev ? &wait.prev->next : &first_waiting_thr ) = &wait;
+ *(wait.next ? &wait.next->prev : &last_waiting_thr ) = &wait;
+ // Leave critical section and start waiting.
+ (*wchan)++;
+ SetThreadStateEndCritical(self, kStoppedThreadState, kNoThreadID);
+ // The Apple documentation says that the above call reschedules a new
+ // thread. Therefore it will only return when the thread wakes up.
+ ThreadBeginCritical();
+ (*wchan)--;
+ // Unlink wait record
+ *(wait.prev ? &wait.prev->next : &first_waiting_thr ) = wait.next;
+ *(wait.next ? &wait.next->prev : &last_waiting_thr ) = wait.prev;
+ // Returns from the wait.
+}
+
+// Wakeup one thread or all threads waiting on cause wchan
+static void
+macthread_wakeup(int *wchan, int onlyone)
+{
+ if (*wchan == 0)
+ return;
+ for (struct thr_waiting *q=first_waiting_thr; q; q=q->next)
+ if (q->wchan == wchan) {
+ // Found a waiting thread
+ q->wchan = 0;
+ SetThreadState(q->thid, kReadyThreadState, kNoThreadID);
+ if (onlyone)
+ return;
+ }
+}
+
+GThread::GThread(int stacksize)
+ : thid(kNoThreadID), xentry(0), xarg(0)
+{
+}
+
+GThread::~GThread(void)
+{
+ thid = kNoThreadID;
+}
+
+pascal void *
+GThread::start(void *arg)
+{
+ GThread *gt = (GThread*)arg;
+ try
+ {
+ G_TRY
+ {
+ (gt->xentry)(gt->xarg);
+ }
+ G_CATCH(ex)
+ {
+ ex.perror();
+ DjVuMessageLite::perror( ERR_MSG("GThreads.uncaught") );
+#ifdef _DEBUG
+ abort();
+#endif
+ }
+ G_ENDCATCH;
+ }
+ catch(...)
+ {
+ DjVuMessageLite::perror( ERR_MSG("GThreads.unrecognized") );
+#ifdef _DEBUG
+ abort();
+#endif
+ }
+ return 0;
+}
+
+int
+GThread::create(void (*entry)(void*), void *arg)
+{
+ if (xentry || thid!=kNoThreadID)
+ return -1;
+ xentry = entry;
+ xarg = arg;
+ int err = NewThread( kCooperativeThread, GThread::start , this, 0,
+ kCreateIfNeeded, (void**)nil, &thid );
+ if( err != noErr )
+ return err;
+ return 0;
+}
+
+void
+GThread::terminate()
+{
+ if (thid != kNoThreadID) {
+ DisposeThread( thid, NULL, false );
+ thid = kNoThreadID;
+ }
+}
+
+int
+GThread::yield()
+{
+ YieldToAnyThread();
+ return 0;
+}
+
+void*
+GThread::current()
+{
+ unsigned long thid = kNoThreadID;
+ GetCurrentThread(&thid);
+ return (void*) thid;
+}
+
+
+// GMonitor implementation
+GMonitor::GMonitor()
+ : ok(0), count(1), locker(0), wlock(0), wsig(0)
+{
+ locker = kNoThreadID;
+ ok = 1;
+}
+
+GMonitor::~GMonitor()
+{
+ ok = 0;
+ ThreadBeginCritical();
+ macthread_wakeup(&wsig, 0);
+ macthread_wakeup(&wlock, 0);
+ ThreadEndCritical();
+ YieldToAnyThread();
+}
+
+void
+GMonitor::enter()
+{
+ ThreadID self;
+ GetCurrentThread(&self);
+ ThreadBeginCritical();
+ if (count>0 || self!=locker)
+ {
+ while (ok && count<=0)
+ macthread_wait(self, &wlock);
+ count = 1;
+ locker = self;
+ }
+ count -= 1;
+ ThreadEndCritical();
+}
+
+void
+GMonitor::leave()
+{
+ ThreadID self;
+ GetCurrentThread(&self);
+ if (ok && (count>0 || self!=locker))
+ G_THROW( ERR_MSG("GThreads.not_acq_leave") );
+ ThreadBeginCritical();
+ if (++count > 0)
+ macthread_wakeup(&wlock, 1);
+ ThreadEndCritical();
+}
+
+void
+GMonitor::signal()
+{
+ ThreadID self;
+ GetCurrentThread(&self);
+ if (count>0 || self!=locker)
+ G_THROW( ERR_MSG("GThreads.not_acq_signal") );
+ ThreadBeginCritical();
+ macthread_wakeup(&wsig, 1);
+ ThreadEndCritical();
+}
+
+void
+GMonitor::broadcast()
+{
+ ThreadID self;
+ GetCurrentThread(&self);
+ if (count>0 || self!=locker)
+ G_THROW( ERR_MSG("GThreads.not_acq_broad") );
+ ThreadBeginCritical();
+ macthread_wakeup(&wsig, 0);
+ ThreadEndCritical();
+}
+
+void
+GMonitor::wait()
+{
+ // Check state
+ ThreadID self;
+ GetCurrentThread(&self);
+ if (count>0 || locker!=self)
+ G_THROW( ERR_MSG("GThreads.not_acq_wait") );
+ // Wait
+ if (ok)
+ {
+ // Atomically release monitor and wait
+ ThreadBeginCritical();
+ int sav_count = count;
+ count = 1;
+ macthread_wakeup(&wlock, 1);
+ macthread_wait(self, &wsig);
+ // Re-acquire
+ while (ok && count<=0)
+ macthread_wait(self, &wlock);
+ count = sav_count;
+ locker = self;
+ ThreadEndCritical();
+ }
+}
+
+void
+GMonitor::wait(unsigned long timeout)
+{
+ // Timeouts are not used for anything important.
+ // Just ignore the timeout and wait the regular way.
+ wait();
+}
+
+#endif
+
+
+
+// ----------------------------------------
+// POSIXTHREADS IMPLEMENTATION
+// ----------------------------------------
+
+#if THREADMODEL==POSIXTHREADS
+
+#if defined(CMA_INCLUDE)
+#define DCETHREADS
+#define pthread_key_create pthread_keycreate
+#else
+#define pthread_mutexattr_default NULL
+#define pthread_condattr_default NULL
+#endif
+
+
+void *
+GThread::start(void *arg)
+{
+ GThread *gt = (GThread*)arg;
+#ifdef DCETHREADS
+#ifdef CANCEL_ON
+ pthread_setcancel(CANCEL_ON);
+ pthread_setasynccancel(CANCEL_ON);
+#endif
+#else // !DCETHREADS
+#ifdef PTHREAD_CANCEL_ENABLE
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, 0);
+#endif
+#ifdef PTHREAD_CANCEL_ASYNCHRONOUS
+ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
+#endif
+#endif
+ // Catch exceptions
+#ifdef __EXCEPTIONS
+ try
+ {
+#endif
+ G_TRY
+ {
+ (gt->xentry)(gt->xarg);
+ }
+ G_CATCH(ex)
+ {
+ ex.perror();
+ DjVuMessageLite::perror( ERR_MSG("GThreads.uncaught") );
+#ifdef _DEBUG
+ abort();
+#endif
+ }
+ G_ENDCATCH;
+#ifdef __EXCEPTIONS
+ }
+ catch(...)
+ {
+ DjVuMessageLite::perror( ERR_MSG("GThreads.unrecognized") );
+#ifdef _DEBUG
+ abort();
+#endif
+ }
+#endif
+ return 0;
+}
+
+
+// GThread
+
+GThread::GThread(int stacksize) :
+ hthr(0), xentry(0), xarg(0)
+{
+}
+
+GThread::~GThread()
+{
+ hthr = 0;
+}
+
+int
+GThread::create(void (*entry)(void*), void *arg)
+{
+ if (xentry || xarg)
+ return -1;
+ xentry = entry;
+ xarg = arg;
+#ifdef DCETHREADS
+ int ret = pthread_create(&hthr, pthread_attr_default, GThread::start, (void*)this);
+ if (ret >= 0)
+ pthread_detach(hthr);
+#else
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ int ret = pthread_create(&hthr, &attr, start, (void*)this);
+ pthread_attr_destroy(&attr);
+#endif
+ return ret;
+}
+
+void
+GThread::terminate()
+{
+ if (xentry || xarg)
+ pthread_cancel(hthr);
+}
+
+int
+GThread::yield()
+{
+#ifdef DCETHREADS
+ pthread_yield();
+#else
+ // should use sched_yield() when available.
+ static struct timeval timeout = { 0, 0 };
+ ::select(0, 0,0,0, &timeout);
+#endif
+ return 0;
+}
+
+void*
+GThread::current()
+{
+ pthread_t self = pthread_self();
+#if defined(pthread_getunique_np)
+ return (void*) pthread_getunique_np( & self );
+#elif defined(cma_thread_get_unique)
+ return (void*) cma_thread_get_unique( & self );
+#else
+ return (void*) self;
+#endif
+}
+
+// -- GMonitor
+
+GMonitor::GMonitor()
+ : ok(0), count(1), locker(0)
+{
+ // none of this should be necessary ... in theory.
+#ifdef PTHREAD_MUTEX_INITIALIZER
+ static pthread_mutex_t tmutex=PTHREAD_MUTEX_INITIALIZER;
+ memcpy(&mutex,&tmutex,sizeof(mutex));
+#endif
+#ifdef PTHREAD_COND_INITIALIZER
+ static pthread_cond_t tcond=PTHREAD_COND_INITIALIZER;
+ memcpy(&cond,&tcond,sizeof(cond));
+#endif
+ // standard
+ pthread_mutex_init(&mutex, pthread_mutexattr_default);
+ pthread_cond_init(&cond, pthread_condattr_default);
+ locker = pthread_self();
+ ok = 1;
+}
+
+GMonitor::~GMonitor()
+{
+ ok = 0;
+ pthread_cond_destroy(&cond);
+ pthread_mutex_destroy(&mutex);
+}
+
+
+void
+GMonitor::enter()
+{
+ pthread_t self = pthread_self();
+ if (count>0 || !pthread_equal(locker, self))
+ {
+ if (ok)
+ pthread_mutex_lock(&mutex);
+ locker = self;
+ count = 1;
+ }
+ count -= 1;
+}
+
+void
+GMonitor::leave()
+{
+ pthread_t self = pthread_self();
+ if (ok && (count>0 || !pthread_equal(locker, self)))
+ G_THROW( ERR_MSG("GThreads.not_acq_broad") );
+ count += 1;
+ if (count > 0)
+ {
+ count = 1;
+ if (ok)
+ pthread_mutex_unlock(&mutex);
+ }
+}
+
+void
+GMonitor::signal()
+{
+ if (ok)
+ {
+ pthread_t self = pthread_self();
+ if (count>0 || !pthread_equal(locker, self))
+ G_THROW( ERR_MSG("GThreads.not_acq_signal") );
+ pthread_cond_signal(&cond);
+ }
+}
+
+void
+GMonitor::broadcast()
+{
+ if (ok)
+ {
+ pthread_t self = pthread_self();
+ if (count>0 || !pthread_equal(locker, self))
+ G_THROW( ERR_MSG("GThreads.not_acq_broad") );
+ pthread_cond_broadcast(&cond);
+ }
+}
+
+void
+GMonitor::wait()
+{
+ // Check
+ pthread_t self = pthread_self();
+ if (count>0 || !pthread_equal(locker, self))
+ G_THROW( ERR_MSG("GThreads.not_acq_wait") );
+ // Wait
+ if (ok)
+ {
+ // Release
+ int sav_count = count;
+ count = 1;
+ // Wait
+ pthread_cond_wait(&cond, &mutex);
+ // Re-acquire
+ count = sav_count;
+ locker = self;
+ }
+}
+
+void
+GMonitor::wait(unsigned long timeout)
+{
+ // Check
+ pthread_t self = pthread_self();
+ if (count>0 || !pthread_equal(locker, self))
+ G_THROW( ERR_MSG("GThreads.not_acq_wait") );
+ // Wait
+ if (ok)
+ {
+ // Release
+ int sav_count = count;
+ count = 1;
+ // Wait
+ struct timeval abstv;
+ struct timespec absts;
+ gettimeofday(&abstv, NULL); // grrr
+ absts.tv_sec = abstv.tv_sec + timeout/1000;
+ absts.tv_nsec = abstv.tv_usec*1000 + (timeout%1000)*1000000;
+ if (absts.tv_nsec > 1000000000) {
+ absts.tv_nsec -= 1000000000;
+ absts.tv_sec += 1;
+ }
+ pthread_cond_timedwait(&cond, &mutex, &absts);
+ // Re-acquire
+ count = sav_count;
+ locker = self;
+ }
+}
+
+#endif
+
+
+
+// ----------------------------------------
+// CUSTOM COOPERATIVE THREADS
+// ----------------------------------------
+
+#if THREADMODEL==COTHREADS
+
+#ifndef __GNUG__
+#error "COTHREADS require G++"
+#endif
+#if (__GNUC__<2) || ((__GNUC__==2) && (__GNUC_MINOR__<=90))
+#warning "COTHREADS require EGCS-1.1.1 with Leon's libgcc patch."
+#warning "You may have trouble with thread-unsafe exceptions..."
+#define NO_LIBGCC_HOOKS
+#endif
+
+// -------------------------------------- constants
+
+// Minimal stack size
+#define MINSTACK (32*1024)
+// Default stack size
+#define DEFSTACK (127*1024)
+// Maxtime between checking fdesc (ms)
+#define MAXFDWAIT (200)
+// Maximum time to wait in any case
+#define MAXWAIT (60*60*1000)
+// Maximum penalty for hog task (ms)
+#define MAXPENALTY (1000)
+// Trace task switches
+#undef COTHREAD_TRACE
+#undef COTHREAD_TRACE_VERBOSE
+
+// -------------------------------------- context switch code
+
+struct mach_state {
+ jmp_buf buf;
+};
+
+static void
+mach_switch(mach_state *st1, mach_state *st2)
+{
+#if #cpu(sparc)
+ asm("ta 3"); // save register windows
+#endif
+ if (! setjmp(st1->buf))
+ longjmp(st2->buf, 1);
+}
+
+static void
+mach_start(mach_state *st1, void *pc, char *stacklo, char *stackhi)
+{
+#if #cpu(sparc)
+ asm("ta 3"); // save register windows
+#endif
+ if (! setjmp(st1->buf))
+ {
+ // The following code must perform two tasks:
+ // -- set stack pointer to a proper value between #stacklo# and #stackhi#.
+ // -- branch to or call the function at address #pc#.
+ // This function never returns ... so there is no need to save anything
+#if #cpu(mips)
+ char *sp = (char*)(((unsigned long)stackhi-16) & ~0xff);
+ asm volatile ("move $sp,%0\n\t" // set new stack pointer
+ "move $25,%1\n\t" // call subroutine via $25
+ "jal $25\n\t" // call subroutine via $25
+ "nop" // delay slot
+ : : "r" (sp), "r" (pc) );
+#elif #cpu(i386)
+ char *sp = (char*)(((unsigned long)stackhi-16) & ~0xff);
+ asm volatile ("movl %0,%%esp\n\t" // set new stack pointer
+ "call *%1" // call function
+ : : "r" (sp), "r" (pc) );
+#elif #cpu(sparc)
+ char *sp = (char*)(((unsigned long)stackhi-16) & ~0xff);
+ asm volatile ("ta 3\n\t" // saving the register windows will not hurt.
+ "mov %0,%%sp\n\t" // set new stack pointer
+ "call %1,0\n\t" // call function
+ "nop" // delay slot
+ : : "r" (sp), "r" (pc) );
+#elif #cpu(hppa)
+ char *sp = (char*)(((unsigned long)stacklo+128+255) & ~0xff);
+ asm volatile("copy %0,%%sp\n\t" // set stack pointer
+ "copy %1,%%r22\n\t" // set call address
+ ".CALL\n\t" // call pseudo instr (why?)
+ "bl $$dyncall,%%r31\n\t" // call
+ "copy %%r31,%%r2" // delay slot ???
+ : : "r" (sp), "r" (pc) );
+#elif #cpu(alpha)
+ char *sp = (char*)(((unsigned long)stackhi-16) & ~0xff);
+ asm volatile ("bis $31,%0,$30\n\t" // set new stack pointer
+ "bis $31,%1,$27\n\t" // load function pointer
+ "jsr $26,($27),0" // call function
+ : : "r" (sp), "r" (pc) );
+#elif #cpu(powerpc)
+ char *sp = (char*)(((unsigned long)stackhi-16) & ~0xff);
+ asm volatile ("mr 1,%0\n\t" // set new stack pointer
+ "mr 0,%1\n\t" // load func pointer into r0
+ "mtlr 0\n\t" // load link register with r0
+ "blrl" // branch
+ : : "r" (sp), "r" (pc) );
+#elif #cpu(m68k) && defined(COTHREAD_UNTESTED)
+ char *sp = (char*)(((unsigned long)stackhi-16) & ~0xff);
+ asm volatile ("move%.l %0,%Rsp\n\t" // set new stack pointer
+ "jmp %a1" // branch to address %1
+ : : "r" (sp), "a" (pc) );
+#elif #cpu(arm) && defined(COTHREAD_UNTESTED)
+ char *sp = (char*)(((unsigned long)stackhi-16) & ~0xff);
+ asm volatile ("mov%?\t%|sp, %0\n\t" // set new stack pointer
+ "mov%?\t%|pc, %1" // branch to address %1
+ : : "r" (sp), "r" (pc) );
+#else
+#error "COTHREADS not supported on this machine."
+#error "Try -DTHREADMODEL=NOTHREADS."
+#endif
+ // We should never reach this point
+ abort();
+ // Note that this call to abort() makes sure
+ // that function mach_start() is compiled as a non-leaf
+ // function. It is indeed a non-leaf function since the
+ // piece of assembly code calls a function, but the compiler
+ // would not know without the call to abort() ...
+ }
+}
+
+#ifdef CHECK
+// This code can be used to verify that task switching works.
+char stack[16384];
+mach_state st1, st2;
+void th2() {
+ puts("2b"); mach_switch(&st2, &st1);
+ puts("4b"); mach_switch(&st2, &st1);
+ puts("6b"); mach_switch(&st2, &st1);
+}
+void th2relay() {
+ th2(); puts("ooops\n");
+}
+void th1() {
+ mach_start(&st1, (void*)th2relay, stack, stack+sizeof(stack));
+ puts("3a"); mach_switch(&st1, &st2);
+ puts("5a"); mach_switch(&st1, &st2);
+}
+int main() {
+ puts("1a"); th1(); puts("6a");
+}
+#endif
+
+
+
+// -------------------------------------- select
+
+struct coselect {
+ int nfds;
+ fd_set rset;
+ fd_set wset;
+ fd_set eset;
+};
+
+static void
+coselect_merge(coselect *dest, coselect *from)
+{
+ int i;
+ int nfds = from->nfds;
+ if (nfds > dest->nfds)
+ dest->nfds = nfds;
+ for (i=0; i<nfds; i++) if (FD_ISSET(i, &from->rset)) FD_SET(i, &dest->rset);
+ for (i=0; i<nfds; i++) if (FD_ISSET(i, &from->wset)) FD_SET(i, &dest->wset);
+ for (i=0; i<nfds; i++) if (FD_ISSET(i, &from->eset)) FD_SET(i, &dest->eset);
+}
+
+static int
+coselect_test(coselect *c)
+{
+ static timeval tmzero = {0,0};
+ fd_set copyr = c->rset;
+ fd_set copyw = c->wset;
+ fd_set copye = c->eset;
+ return select(c->nfds, &copyr, &copyw, &copye, &tmzero);
+}
+
+
+// -------------------------------------- cotask
+
+class GThread::cotask {
+public:
+#ifndef NO_LIBGCC_HOOKS
+ cotask(const int xstacksize,void *);
+#else
+ cotask(const int xstacksize);
+#endif
+ ~cotask();
+ class GThread::cotask *next;
+ class GThread::cotask *prev;
+ // context
+ mach_state regs;
+ // stack information
+ char *stack;
+ GPBuffer<char> gstack;
+ int stacksize;
+ // timing information
+ unsigned long over;
+ // waiting information
+ void *wchan;
+ coselect *wselect;
+ unsigned long *maxwait;
+ // delete after termination
+ bool autodelete;
+ // egcs exception support
+#ifndef NO_LIBGCC_HOOKS
+ void *ehctx;
+#endif
+};
+
+#ifndef NO_LIBGCC_HOOKS
+GThread::cotask::cotask(const int xstacksize, void *xehctx)
+#else
+GThread::cotask::cotask(const int xstacksize)
+#endif
+: next(0), prev(0), gstack(stack,xstacksize), stacksize(xstacksize),
+ over(0), wchan(0), wselect(0), maxwait(0), autodelete(false)
+#ifndef NO_LIBGCC_HOOKS
+ ,ehctx(xehctx)
+#endif
+{
+ memset(&regs,0,sizeof(regs));
+}
+
+static GThread::cotask *maintask = 0;
+static GThread::cotask *curtask = 0;
+static GThread::cotask *autodeletetask = 0;
+static unsigned long globalmaxwait = 0;
+static void (*scheduling_callback)(int) = 0;
+static timeval time_base;
+
+
+GThread::cotask::~cotask()
+{
+ gstack.resize(0);
+#ifndef NO_LIBGCC_HOOKS
+ if (ehctx)
+ free(ehctx);
+ ehctx = 0;
+#endif
+}
+
+static void
+cotask_free(GThread::cotask *task)
+{
+#ifdef COTHREAD_TRACE
+ DjVuPrintErrorUTF8("cothreads: freeing task %p with autodelete=%d\n",
+ task,task->autodelete);
+#endif
+ if (task!=maintask)
+ {
+ delete task;
+ }
+}
+
+
+// -------------------------------------- time
+
+static unsigned long
+time_elapsed(int reset=1)
+{
+ timeval tm;
+ gettimeofday(&tm, NULL);
+ long msec = (tm.tv_usec-time_base.tv_usec)/1000;
+ unsigned long elapsed = (long)(tm.tv_sec-time_base.tv_sec)*1000 + msec;
+ if (reset && elapsed>0)
+ {
+#ifdef COTHREAD_TRACE
+#ifdef COTHREAD_TRACE_VERBOSE
+ DjVuPrintErrorUTF8("cothreads: %4ld ms in task %p\n", elapsed, curtask);
+#endif
+#endif
+ time_base.tv_sec = tm.tv_sec;
+ time_base.tv_usec += msec*1000;
+ }
+ return elapsed;
+}
+
+
+// -------------------------------------- scheduler
+
+static int
+cotask_yield()
+{
+ // ok
+ if (! maintask)
+ return 0;
+ // get elapsed time and return immediately when it is too small
+ unsigned long elapsed = time_elapsed();
+ if (elapsed==0 && curtask->wchan==0 && curtask->prev && curtask->next)
+ return 0;
+ // adjust task running time
+ curtask->over += elapsed;
+ if (curtask->over > MAXPENALTY)
+ curtask->over = MAXPENALTY;
+ // start scheduling
+ reschedule:
+ // try unblocking tasks
+ GThread::cotask *n = curtask->next;
+ GThread::cotask *q = n;
+ do
+ {
+ if (q->wchan)
+ {
+ if (q->maxwait && *q->maxwait<=elapsed)
+ {
+ *q->maxwait = 0;
+ q->wchan=0;
+ q->maxwait=0;
+ q->wselect=0;
+ }
+ else if (q->wselect && globalmaxwait<=elapsed && coselect_test(q->wselect))
+ {
+ q->wchan=0;
+ if (q->maxwait)
+ *q->maxwait -= elapsed;
+ q->maxwait = 0;
+ q->wselect=0;
+ }
+ if (q->maxwait)
+ *q->maxwait -= elapsed;
+ }
+ q = q->next;
+ }
+ while (q!=n);
+ // adjust globalmaxwait
+ if (globalmaxwait < elapsed)
+ globalmaxwait = MAXFDWAIT;
+ else
+ globalmaxwait -= elapsed;
+ // find best candidate
+ static int count;
+ unsigned long best = MAXPENALTY + 1;
+ GThread::cotask *r = 0;
+ count = 0;
+ q = n;
+ do
+ {
+ if (! q->wchan)
+ {
+ count += 1;
+ if (best > q->over)
+ {
+ r = q;
+ best = r->over;
+ }
+ }
+ q = q->next;
+ }
+ while (q != n);
+ // found
+ if (count > 0)
+ {
+ // adjust over
+ q = n;
+ do
+ {
+ q->over = (q->over>best ? q->over-best : 0);
+ q = q->next;
+ }
+ while (q != n);
+ // Switch
+ if (r != curtask)
+ {
+#ifdef COTHREAD_TRACE
+ DjVuPrintErrorUTF8("cothreads: ----- switch to %p [%ld]\n", r, best);
+#endif
+ GThread::cotask *old = curtask;
+ curtask = r;
+ mach_switch(&old->regs, &curtask->regs);
+ }
+ // handle autodelete
+ if (autodeletetask && autodeletetask->autodelete)
+ cotask_free(autodeletetask);
+ autodeletetask = 0;
+ // return
+ if (count == 1)
+ return 1;
+ return 0;
+ }
+ // No task ready
+ count = 0;
+ unsigned long minwait = MAXWAIT;
+ coselect allfds;
+ allfds.nfds = 1;
+ FD_ZERO(&allfds.rset);
+ FD_ZERO(&allfds.wset);
+ FD_ZERO(&allfds.eset);
+ q = n;
+ do
+ {
+ if (q->maxwait || q->wselect)
+ count += 1;
+ if (q->maxwait && *q->maxwait<minwait)
+ minwait = *q->maxwait;
+ if (q->wselect)
+ coselect_merge(&allfds, q->wselect);
+ q = q->next;
+ }
+ while (q != n);
+ // abort on deadlock
+ if (count == 0) {
+ DjVuMessageLite::perror( ERR_MSG("GThreads.panic") );
+ abort();
+ }
+ // select
+ timeval tm;
+ tm.tv_sec = minwait/1000;
+ tm.tv_usec = 1000*(minwait-1000*tm.tv_sec);
+ select(allfds.nfds,&allfds.rset, &allfds.wset, &allfds.eset, &tm);
+ // reschedule
+ globalmaxwait = 0;
+ elapsed = time_elapsed();
+ goto reschedule;
+}
+
+
+static void
+cotask_terminate(GThread::cotask *task)
+{
+#ifdef COTHREAD_TRACE
+ DjVuPrintErrorUTF8("cothreads: terminating task %p\n", task);
+#endif
+ if (task && task!=maintask)
+ {
+ if (task->prev && task->next)
+ {
+ if (scheduling_callback)
+ (*scheduling_callback)(GThread::CallbackTerminate);
+ task->prev->next = task->next;
+ task->next->prev = task->prev;
+ // mark task as terminated
+ task->prev = 0;
+ // self termination
+ if (task == curtask)
+ {
+ if (task->autodelete)
+ autodeletetask = task;
+ cotask_yield();
+ }
+ }
+ }
+}
+
+
+static void
+cotask_wakeup(void *wchan, int onlyone)
+{
+ if (maintask && curtask)
+ {
+ GThread::cotask *n = curtask->next;
+ GThread::cotask *q = n;
+ do
+ {
+ if (q->wchan == wchan)
+ {
+ q->wchan=0;
+ q->maxwait=0;
+ q->wselect=0;
+ q->over = 0;
+ if (onlyone)
+ return;
+ }
+ q = q->next;
+ }
+ while (q!=n);
+ }
+}
+
+
+// -------------------------------------- select / get_select
+
+static int
+cotask_select(int nfds,
+ fd_set *rfds, fd_set *wfds, fd_set *efds,
+ struct timeval *tm)
+{
+ // bypass
+ if (maintask==0 || (tm && tm->tv_sec==0 && tm->tv_usec<1000))
+ return select(nfds, rfds, wfds, efds, tm);
+ // copy parameters
+ unsigned long maxwait = 0;
+ coselect parm;
+ // set waiting info
+ curtask->wchan = (void*)&parm;
+ if (rfds || wfds || efds)
+ {
+ parm.nfds = nfds;
+ if (rfds) { parm.rset=*rfds; } else { FD_ZERO(&parm.rset); }
+ if (wfds) { parm.wset=*wfds; } else { FD_ZERO(&parm.wset); }
+ if (efds) { parm.eset=*efds; } else { FD_ZERO(&parm.eset); }
+ curtask->wselect = &parm;
+ }
+ if (tm)
+ {
+ maxwait = time_elapsed(0) + tm->tv_sec*1000 + tm->tv_usec/1000;
+ curtask->maxwait = &maxwait;
+ }
+ // reschedule
+ cotask_yield();
+ // call select to update masks
+ if (tm)
+ {
+ tm->tv_sec = maxwait/1000;
+ tm->tv_usec = 1000*(maxwait-1000*tm->tv_sec);
+ }
+ static timeval tmzero = {0,0};
+ return select(nfds, rfds, wfds, efds, &tmzero);
+}
+
+
+static void
+cotask_get_select(int &nfds, fd_set *rfds, fd_set *wfds, fd_set *efds,
+ unsigned long &timeout)
+{
+ int ready = 1;
+ unsigned long minwait = MAXWAIT;
+ unsigned long elapsed = time_elapsed(0);
+ coselect allfds;
+ allfds.nfds=0;
+ FD_ZERO(&allfds.rset);
+ FD_ZERO(&allfds.wset);
+ FD_ZERO(&allfds.eset);
+ if (curtask)
+ {
+ GThread::cotask *q=curtask->next;
+ while (q != curtask)
+ {
+ ready++;
+ if (q->wchan)
+ {
+ if (q->wselect)
+ coselect_merge(&allfds, q->wselect);
+ if (q->maxwait && *q->maxwait<minwait)
+ minwait = *q->maxwait;
+ ready--;
+ }
+ q = q->next;
+ }
+ }
+ timeout = 0;
+ nfds=allfds.nfds;
+ *rfds=allfds.rset;
+ *wfds=allfds.wset;
+ *efds=allfds.eset;
+ if (ready==1 && minwait>elapsed)
+ timeout = minwait-elapsed;
+}
+
+
+
+// -------------------------------------- libgcc hook
+
+#ifndef NO_LIBGCC_HOOKS
+// These are exported by Leon's patched version of libgcc.a
+// Let's hope that the egcs people will include the patch in
+// the distributions.
+extern "C"
+{
+ extern void* (*__get_eh_context_ptr)(void);
+ extern void* __new_eh_context(void);
+}
+
+// This function is called via the pointer __get_eh_context_ptr
+// by the internal mechanisms of egcs. It must return the
+// per-thread event handler context. This is necessary to
+// implement thread safe exceptions on some machine and/or
+// when flag -fsjlj-exception is set.
+static void *
+cotask_get_eh_context()
+{
+ if (curtask)
+ return curtask->ehctx;
+ else if (maintask)
+ return maintask->ehctx;
+ DjVuMessageLite::perror( ERR_MSG("GThreads.co_panic") );
+ abort();
+}
+#endif
+
+
+
+// -------------------------------------- GThread
+
+void
+GThread::set_scheduling_callback(void (*call)(int))
+{
+ if (scheduling_callback)
+ G_THROW( ERR_MSG("GThreads.dupl_callback") );
+ scheduling_callback = call;
+}
+
+
+GThread::GThread(int stacksize)
+ : task(0), xentry(0), xarg(0)
+{
+ // check argument
+ if (stacksize < 0)
+ stacksize = DEFSTACK;
+ if (stacksize < MINSTACK)
+ stacksize = MINSTACK;
+ // initialization
+ if (! maintask)
+ {
+#ifndef NO_LIBGCC_HOOKS
+ static GThread::cotask comaintask(0,(*__get_eh_context_ptr)());
+ __get_eh_context_ptr = cotask_get_eh_context;
+#else
+ static GThread::cotask comaintask(0);
+#endif
+ maintask = &comaintask;
+// memset(maintask, 0, sizeof(GThread::cotask));
+ maintask->next = maintask;
+ maintask->prev = maintask;
+ gettimeofday(&time_base,NULL);
+ curtask = maintask;
+ }
+ // allocation
+#ifndef NO_LIBGCC_HOOKS
+ task = new GThread::cotask(stacksize,__new_eh_context());
+#else
+ task = new GThread::cotask(stacksize);
+#endif
+}
+
+
+GThread::~GThread()
+{
+ if (task && task!=maintask)
+ {
+ if (task->prev) // running
+ task->autodelete = true;
+ else
+ cotask_free(task);
+ task = 0;
+ }
+}
+
+#if __GNUC__ >= 3
+# if __GNUC_MINOR__ >= 4
+# define noinline __attribute__((noinline,used))
+# elif __GNUC_MINOR >= 2
+# define noinline __attribute__((noinline))
+# endif
+#endif
+#ifndef noinline
+# define noinline /**/
+#endif
+
+static noinline void startone(void);
+static noinline void starttwo(GThread *thr);
+static GThread * volatile starter;
+
+static void
+startone(void)
+{
+ GThread *thr = starter;
+ mach_switch(&thr->task->regs, &curtask->regs);
+ // Registers may still contain an improper pointer
+ // to the exception context. We should neither
+ // register cleanups nor register handlers.
+ starttwo(thr);
+ abort();
+}
+
+static void
+starttwo(GThread *thr)
+{
+ // Hopefully this function reacquires
+ // an exception context pointer. Therefore
+ // we can register the exception handlers.
+ // It is placed after ``startone'' to avoid inlining.
+#ifdef __EXCEPTIONS
+ try
+ {
+#endif
+ G_TRY
+ {
+ thr->xentry( thr->xarg );
+ }
+ G_CATCH(ex)
+ {
+ ex.perror();
+ DjVuMessageLite::perror( ERR_MSG("GThreads.uncaught") );
+#ifdef _DEBUG
+ abort();
+#endif
+ }
+ G_ENDCATCH;
+#ifdef __EXCEPTIONS
+ }
+ catch(...)
+ {
+ DjVuMessageLite::perror( ERR_MSG("GThreads.unrecognized") );
+#ifdef _DEBUG
+ abort();
+#endif
+ }
+#endif
+ cotask_terminate(curtask);
+ GThread::yield();
+ // Do not add anything below this line!
+ // Nothing should reach it anyway.
+ abort();
+}
+
+int
+GThread::create(void (*entry)(void*), void *arg)
+{
+ if (task->next || task->prev)
+ return -1;
+ xentry = entry;
+ xarg = arg;
+ task->wchan = 0;
+ task->next = curtask;
+ task->prev = curtask->prev;
+ task->next->prev = task;
+ task->prev->next = task;
+ GThread::cotask *old = curtask;
+ starter = this;
+ mach_start(&old->regs, (void*)startone,
+ task->stack, task->stack+task->stacksize);
+ if (scheduling_callback)
+ (*scheduling_callback)(CallbackCreate);
+ return 0;
+}
+
+
+void
+GThread::terminate()
+{
+ if (task && task!=maintask)
+ cotask_terminate(task);
+}
+
+int
+GThread::yield()
+{
+ return cotask_yield();
+}
+
+int
+GThread::select(int nfds,
+ fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
+ struct timeval *timeout)
+{
+ return cotask_select(nfds, readfds, writefds, exceptfds, timeout);
+}
+
+void
+GThread::get_select(int &nfds, fd_set *rfds, fd_set *wfds, fd_set *efds,
+ unsigned long &timeout)
+{
+ cotask_get_select(nfds, rfds, wfds, efds, timeout);
+}
+
+inline void *
+GThread::current()
+{
+ if (curtask && curtask!=maintask)
+ return (void*)curtask;
+ return (void*)0;
+}
+
+
+// -------------------------------------- GMonitor
+
+GMonitor::GMonitor()
+ : count(1), locker(0), wlock(0), wsig(0)
+{
+ locker = 0;
+ ok = 1;
+}
+
+GMonitor::~GMonitor()
+{
+ ok = 0;
+ cotask_wakeup((void*)&wsig, 0);
+ cotask_wakeup((void*)&wlock, 0);
+ cotask_yield();
+ // Because we know how the scheduler works, we know that this single call to
+ // yield will run all unblocked tasks and given them the chance to leave the
+ // scope of the monitor object.
+}
+
+void
+GMonitor::enter()
+{
+ void *self = GThread::current();
+ if (count>0 || self!=locker)
+ {
+ while (ok && count<=0)
+ {
+ curtask->wchan = (void*)&wlock;
+ wlock++;
+ cotask_yield();
+ wlock--;
+ }
+ count = 1;
+ locker = self;
+ }
+ count -= 1;
+}
+
+void
+GMonitor::leave()
+{
+ void *self = GThread::current();
+ if (ok && (count>0 || self!=locker))
+ G_THROW( ERR_MSG("GThreads.not_acq_leave") );
+ if (++count > 0 && wlock > 0)
+ cotask_wakeup((void*)&wlock, 1);
+}
+
+void
+GMonitor::signal()
+{
+ void *self = GThread::current();
+ if (count>0 || self!=locker)
+ G_THROW( ERR_MSG("GThreads.not_acq_signal") );
+ if (wsig > 0)
+ {
+ cotask_wakeup((void*)&wsig, 1);
+ if (scheduling_callback)
+ (*scheduling_callback)(GThread::CallbackUnblock);
+ }
+}
+
+void
+GMonitor::broadcast()
+{
+ void *self = GThread::current();
+ if (count>0 || self!=locker)
+ G_THROW( ERR_MSG("GThreads.not_acq_broad") );
+ if (wsig > 0)
+ {
+ cotask_wakeup((void*)&wsig, 0);
+ if (scheduling_callback)
+ (*scheduling_callback)(GThread::CallbackUnblock);
+ }
+}
+
+void
+GMonitor::wait()
+{
+ // Check state
+ void *self = GThread::current();
+ if (count>0 || locker!=self)
+ G_THROW( ERR_MSG("GThreads.not_acq_wait") );
+ // Wait
+ if (ok)
+ {
+ // Atomically release monitor and wait
+ int sav_count = count;
+ count = 1;
+ curtask->wchan = (void*)&wsig;
+ cotask_wakeup((void*)&wlock, 1);
+ wsig++;
+ cotask_yield();
+ wsig--;
+ // Re-acquire
+ while (ok && count <= 0)
+ {
+ curtask->wchan = (void*)&wlock;
+ wlock++;
+ cotask_yield();
+ wlock--;
+ }
+ count = sav_count;
+ locker = self;
+ }
+}
+
+void
+GMonitor::wait(unsigned long timeout)
+{
+ // Check state
+ void *self = GThread::current();
+ if (count>0 || locker!=self)
+ G_THROW( ERR_MSG("GThreads.not_acq_wait") );
+ // Wait
+ if (ok)
+ {
+ // Atomically release monitor and wait
+ int sav_count = count;
+ count = 1;
+ unsigned long maxwait = time_elapsed(0) + timeout;
+ curtask->maxwait = &maxwait;
+ curtask->wchan = (void*)&wsig;
+ cotask_wakeup((void*)&wlock, 1);
+ wsig++;
+ cotask_yield();
+ wsig--;
+ // Re-acquire
+ while (ok && count<=0)
+ {
+ curtask->wchan = (void*)&wlock;
+ wlock++;
+ cotask_yield();
+ wlock--;
+ }
+ count = sav_count;
+ locker = self;
+ }
+}
+
+#endif
+
+
+
+
+// ----------------------------------------
+// GSAFEFLAGS
+// ----------------------------------------
+
+
+
+GSafeFlags &
+GSafeFlags::operator=(long xflags)
+{
+ enter();
+ if (flags!=xflags)
+ {
+ flags=xflags;
+ broadcast();
+ }
+ leave();
+ return *this;
+}
+
+GSafeFlags::operator long(void) const
+{
+ long f;
+ ((GSafeFlags *) this)->enter();
+ f=flags;
+ ((GSafeFlags *) this)->leave();
+ return f;
+}
+
+bool
+GSafeFlags::test_and_modify(long set_mask, long clr_mask,
+ long set_mask1, long clr_mask1)
+{
+ enter();
+ if ((flags & set_mask)==set_mask &&
+ (~flags & clr_mask)==clr_mask)
+ {
+ long new_flags=flags;
+ new_flags|=set_mask1;
+ new_flags&=~clr_mask1;
+ if (new_flags!=flags)
+ {
+ flags=new_flags;
+ broadcast();
+ }
+ leave();
+ return true;
+ }
+ leave();
+ return false;
+}
+
+void
+GSafeFlags::wait_and_modify(long set_mask, long clr_mask,
+ long set_mask1, long clr_mask1)
+{
+ enter();
+ while((flags & set_mask)!=set_mask ||
+ (~flags & clr_mask)!=clr_mask) wait();
+ long new_flags=flags;
+ new_flags|=set_mask1;
+ new_flags&=~clr_mask1;
+ if (flags!=new_flags)
+ {
+ flags=new_flags;
+ broadcast();
+ }
+ leave();
+}
+
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/GThreads.h b/kviewshell/plugins/djvu/libdjvu/GThreads.h
new file mode 100644
index 00000000..92691db4
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GThreads.h
@@ -0,0 +1,639 @@
+//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: GThreads.h,v 1.10 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _GTHREADS_H_
+#define _GTHREADS_H_
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+/** @name GThreads.h
+
+ Files #"GThreads.h"# and #"GThreads.cpp"# implement common entry points
+ for multithreading on multiple platforms. Each execution thread is
+ represented by an instance of class \Ref{GThread}. Synchronization is
+ provided by class \Ref{GMonitor} which implements a monitor (C.A.R Hoare,
+ Communications of the ACM, 17(10), 1974).
+
+ The value of compiler symbol #THREADMODEL# selects an appropriate
+ implementation for these classes. The current implementation supports
+ the following values:
+ \begin{description}
+ \item[-DTHREADMODEL=NOTHREADS] Dummy implementation. This is a
+ good choice when the multithreading features are not required,
+ because it minimizes the portability problems. This is currently
+ the default when compiling under Unix.
+ \item[-DTHREADMODEL=WINTHREADS] Windows implementation.
+ This is the default when compiling under Windows.
+ \item[-DTHREADMODEL=MACTHREADS] Macintosh implementation,
+ which is based on the MacOS cooperative model. The current
+ implementation does not yet fully support synchronization.
+ This is the default when compiling under MacOS.
+ \item[-DTHREADMODEL=POSIXTHREADS] Posix implementation.
+ This implementation also supports DCE threads. The behavior of
+ the code is subject to the quality of the system implementation of
+ Posix threads.
+ \item[-DTHREADMODEL=COTHREADS] Custom cooperative threads.
+ These custom threads do not redefine system calls. Before executing
+ a potentially blocking system function, each thread must explicitly
+ check whether it is going to block and yield control explicitly if
+ this is the case. This code must be compiled with a patched version
+ of egcs-1.1.1 \URL{http://egcs.cygnus.com}. The patch addresses
+ exception thread-safety and is provided in #"@Tools/libgcc2.c.diff"#.
+ Once you get the right compiler, this implementation is remarkably
+ compact and portable. A variety of processors are supported,
+ including mips, intel, sparc, hppa, and alpha.
+ \item[-DTHREADMODEL=JRITHREADS] Java implementation hooks.
+ Multi-threading within a Netscape plugin can be tricky. A simple
+ idea however consists of implementing the threading primitives in
+ Java and to access them using JRI. The classes just contain a
+ JRIGlobalRef. This is not a real implementation since everything
+ (Java code, native functions, stubs, exception thread safety) must
+ be addressed by the plugin source code. Performance may be a serious
+ issue.
+ \end{description}
+
+ {\bf Portability}: The simultaneous use of threads and exceptions caused a
+ lot of portability headaches under Unix. We eventually decided to
+ implement the COTHREADS cooperative threads (because preemptive threads
+ have more problems) and to patch EGCS in order to make exception handling
+ COTHREAD-safe.
+
+ @memo
+ Portable threads
+ @author
+ L\'eon Bottou <leonb@research.att.com> -- initial implementation.\\
+ Praveen Guduru <praveen@sanskrit.lz.att.com> -- mac implementation.
+
+// From: Leon Bottou, 1/31/2002
+// Almost unchanged by Lizardtech.
+// GSafeFlags should go because it not as safe as it claims.
+
+ @version
+ #$Id: GThreads.h,v 1.10 2003/11/07 22:08:21 leonb Exp $# */
+//@{
+
+
+#include "DjVuGlobal.h"
+#include "GException.h"
+
+#define NOTHREADS 0
+#define COTHREADS 1
+#define JRITHREADS 2
+#define POSIXTHREADS 10
+#define WINTHREADS 11
+#define MACTHREADS 12
+
+// Known platforms
+#ifndef THREADMODEL
+#if defined(WIN32)
+#define THREADMODEL WINTHREADS
+#endif
+#if defined(macintosh)
+#define THREADMODEL MACTHREADS
+#endif
+#endif
+
+// Exception emulation is not thread safe
+#ifdef USE_EXCEPTION_EMULATION
+#undef THREADMODEL
+#define THREADMODEL NOTHREADS
+#endif
+// Default is nothreads
+#ifndef THREADMODEL
+#define THREADMODEL NOTHREADS
+#endif
+
+// ----------------------------------------
+// INCLUDES
+
+#if THREADMODEL==WINTHREADS
+#ifndef _WINDOWS_
+#define WIN32_LEAN_AND_MEAN
+#include "windows.h"
+#endif
+#endif
+
+#if THREADMODEL==MACTHREADS
+#include <threads.h>
+#endif
+
+#if THREADMODEL==POSIXTHREADS
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#undef TRY
+#undef CATCH
+#define _CMA_NOWRAPPERS_
+#include <pthread.h>
+#endif
+
+#if THREADMODEL==JRITHREADS
+#include "jri.h"
+#endif
+
+#if THREADMODEL==COTHREADS
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#endif
+
+
+// ----------------------------------------
+// PORTABLE CLASSES
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+
+/** Thread class. A multithreaded process is composed of a main execution
+ thread and of several secondary threads. Each secondary thread is
+ represented by a #GThread# object. The amount of memory required for the
+ stack of a secondary thread is defined when the #GThread# object is
+ constructed. The execution thread is started when function
+ \Ref{GThread::create} is called. The destructor of class GThread waits
+ until the thread terminanes. Note that the execution can be terminated at
+ any time (with possible prejudice) by calling \Ref{GThread::terminate}.
+
+ Several static member functions control the thread scheduler. Function
+ \Ref{GThread::yield} relinquishes the processor to another thread.
+ Function \Ref{GThread::select} (#COTHREADS# only) provides a thread-aware
+ replacement for the well-known unix system call #select#.
+
+ {\bf Note} --- Both the copy constructor and the copy operator are declared
+ as private members. It is therefore not possible to make multiple copies
+ of instances of this class, as implied by the class semantic. */
+
+class GThread {
+public:
+ /** Constructs a new thread object. Memory is allocated for the
+ thread, but the thread is not started.
+ Argument #stacksize# is used by the #COTHREADS# model only for
+ specifying the amount of memory needed for the processor stack. A
+ negative value will be replaced by a suitable default value of 128Kb.
+ A minimum value of 32Kb is silently enforced. */
+ GThread(int stacksize = -1);
+ /** Destructor. Destroying the thread object while the thread is running is
+ perfectly ok since it only destroys the thread identifier. Execution
+ will continue without interference. */
+ ~GThread();
+ /** Starts the thread. The new thread executes function #entry# with
+ argument #arg#. The thread terminates when the function returns. A
+ thread cannot be restarted after its termination. You must create a new
+ #GThread# object. */
+ int create(void (*entry)(void*), void *arg);
+ /** Terminates a thread with extreme prejudice. The thread is removed from
+ the scheduling list. Execution terminates regardless of the execution
+ status of the thread function. Automatic variables may or may not be
+ destroyed. This function must be considered as a last resort since
+ memory may be lost. */
+ void terminate();
+ /** Causes the current thread to relinquish the processor. The scheduler
+ selects a thread ready to run and transfers control to that thread. The
+ actual effect of #yield# heavily depends on the selected implementation.
+ Function #yield# usually returns zero when the execution of the current
+ thread is resumed. It may return a positive number when it can
+ determine that the current thread will remain the only runnable thread
+ for some time. You may then call function \Ref{get_select} to
+ obtain more information. */
+ static int yield();
+ /** Returns a value which uniquely identifies the current thread. */
+ static void *current();
+
+#if THREADMODEL==WINTHREADS
+private:
+ HANDLE hthr;
+ DWORD thrid;
+#elif THREADMODEL==MACTHREADS
+private:
+ unsigned long thid;
+ static pascal void *start(void *arg);
+#elif THREADMODEL==POSIXTHREADS
+private:
+ pthread_t hthr;
+ static void *start(void *arg);
+#elif THREADMODEL==JRITHREADS
+private:
+ JRIGlobalRef obj;
+#elif THREADMODEL==COTHREADS
+ friend class GMonitor;
+public:
+ class cotask;
+ class cotask *task;
+ /** Replaces system call #select# (COTHREADS only). The #COTHREADS# model
+ does not redefine system function. System functions therefore can
+ potentially block the whole process (instead of blocking the current
+ thread only) because the system is not aware of the #COTHREADS#
+ scheduler. The function #GThread::select# is a #COTHREADS#-aware
+ replacement for the well known system function #select#. You can also
+ use #GThread::select# for making sure that calls to system functions
+ will not block the entire process, as demonstrated below:
+ \begin{verbatim}
+ int
+ gthread_read(int fd, void *buffer, size_t len)
+ {
+ fd_set rdset;
+ FD_ZERO(&rdset);
+ FD_SET(fd, &rdset);
+ GThread::select(fd+1, &rdset, 0, 0, 0);
+ return read(fd, buffer, len);
+ }
+ \end{verbatim} */
+ static int select(int nfds, fd_set*, fd_set*, fd_set*, struct timeval*);
+ /** Provide arguments for system call #select# (COTHREADS only). It may be
+ appropriate to call the real system call #select# if the current thread
+ is the only thread ready to run. Other threads however may wake up when
+ certain file descriptors are ready or when a certain delay expires.
+ Function #get_select# returns this information by filling the three
+ usual file descriptor sets (similar to the arguments of system call
+ #select#). It also returns a timeout #timeout# expressed in
+ milliseconds. Note that this timeout is zero is the current thread is
+ not the sole thread ready to run. */
+ static void get_select(int &nfds, fd_set*, fd_set*, fd_set*, unsigned long &timeout);
+ /** Install hooks in the scheduler (COTHREADS only). The hook function
+ #call# is called when a new thread is created (argument is
+ #GThread::CallbackCreate#), when a thread terminates (argument is
+ #GThread::CallbackTerminate#), or when thread is unblocked (argument is
+ #GThread::CallbackUnblock#). This callback can be useful in certain GUI
+ toolkits where the most convenient method for scheduling the threads
+ consists in setting a timer event that calls \Ref{GThread::yield}. */
+ static void set_scheduling_callback(void (*call)(int));
+ enum { CallbackCreate, CallbackTerminate, CallbackUnblock };
+
+#endif
+public:
+ // Should be considered as private
+ void (*xentry)(void*);
+ void *xarg;
+private:
+ // Disable default members
+ GThread(const GThread&);
+ GThread& operator=(const GThread&);
+};
+
+
+/** Monitor class. Monitors have been first described in (C.A.R Hoare,
+ Communications of the ACM, 17(10), 1974). This mechanism provides the
+ basic mutual exclusion (mutex) and thread notification facilities
+ (condition variables).
+
+ Only one thread can own the monitor at a given time. Functions
+ \Ref{enter} and \Ref{leave} can be used to acquire and release the
+ monitor. This mutual exclusion provides an efficient way to protect
+ segment of codes ({\em critical sections}) which should not be
+ simultaneously executed by two threads. Class \Ref{GMonitorLock} provides
+ a convenient way to do this effectively.
+
+ When the thread owning the monitor calls function \Ref{wait}, the monitor
+ is released and the thread starts waiting until another thread calls
+ function \Ref{signal} or \Ref{broadcast}. When the thread wakes-up, it
+ re-acquires the monitor and function #wait# returns. Since the signaling
+ thread must acquire the monitor before calling functions #signal# and
+ #broadcast#, the signaled thread will not be able to re-acquire the
+ monitor until the signaling thread(s) releases the monitor.
+
+ {\bf Note} --- Both the copy constructor and the copy operator are declared
+ as private members. It is therefore not possible to make multiple copies
+ of instances of this class, as implied by the class semantic. */
+
+class GMonitor
+{
+public:
+ GMonitor();
+ ~GMonitor();
+ /** Enters the monitor. If the monitor is acquired by another thread this
+ function waits until the monitor is released. The current thread then
+ acquires the monitor. Calls to #enter# and #leave# may be nested. */
+ void enter();
+ /** Leaves the monitor. The monitor counts how many times the current
+ thread has entered the monitor. Function #leave# decrement this count.
+ The monitor is released when this count reaches zero. An exception is
+ thrown if this function is called by a thread which does not own the
+ monitor. */
+ void leave();
+ /** Waits until the monitor is signaled. The current thread atomically
+ releases the monitor and waits until another thread calls function
+ #signal# or #broadcast#. Function #wait# then re-acquires the monitor
+ and returns. An exception is thrown if this function is called by a
+ thread which does not own the monitor. */
+ void wait();
+ /** Waits until the monitor is signaled or a timeout is reached. The
+ current thread atomically releases the monitor and waits until another
+ thread calls function #signal# or #broadcast# or a maximum of #timeout#
+ milliseconds. Function #wait# then re-acquires the monitor and returns.
+ An exception is thrown if this function is called by a thread which does
+ not own the monitor. */
+ void wait(unsigned long timeout);
+ /** Signals one waiting thread. Function #signal# wakes up at most one of
+ the waiting threads for this monitor. An exception is thrown if this
+ function is called by a thread which does not own the monitor. */
+ void signal();
+ /** Signals all waiting threads. Function #broadcast# wakes up all the
+ waiting threads for this monitor. An exception is thrown if this
+ function is called by a thread which does not own the monitor. */
+ void broadcast();
+private:
+#if THREADMODEL==WINTHREADS
+ int ok;
+ int count;
+ DWORD locker;
+ CRITICAL_SECTION cs;
+ struct thr_waiting *head;
+ struct thr_waiting *tail;
+#elif THREADMODEL==MACTHREADS
+ int ok;
+ int count;
+ unsigned long locker;
+ int wlock;
+ int wsig;
+#elif THREADMODEL==POSIXTHREADS
+ int ok;
+ int count;
+ pthread_t locker;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+#elif THREADMODEL==COTHREADS
+ int ok;
+ int count;
+ void *locker;
+ int wlock;
+ int wsig;
+#elif THREADMODEL==JRITHREADS
+ JRIGlobalRef obj;
+#endif
+private:
+ // Disable default members
+ GMonitor(const GMonitor&);
+ GMonitor& operator=(const GMonitor&);
+};
+
+
+
+
+// ----------------------------------------
+// NOTHREADS INLINES
+
+#if THREADMODEL==NOTHREADS
+inline GThread::GThread(int) {}
+inline GThread::~GThread(void) {}
+inline void GThread::terminate() {}
+inline int GThread::yield() { return 0; }
+inline void* GThread::current() { return 0; }
+inline GMonitor::GMonitor() {}
+inline GMonitor::~GMonitor() {}
+inline void GMonitor::enter() {}
+inline void GMonitor::leave() {}
+inline void GMonitor::wait() {}
+inline void GMonitor::wait(unsigned long) {}
+inline void GMonitor::signal() {}
+inline void GMonitor::broadcast() {}
+#endif // NOTHREADS
+
+
+// ----------------------------------------
+// SCOPE LOCK
+
+
+/** Wrapper for mutually exclusive code.
+ This class locks a specified critical section (see \Ref{GCriticalSection})
+ at construction time and unlocks it at destruction time. It provides a
+ convenient way to take advantage of the C++ implicit destruction of
+ automatic variables in order to make sure that the monitor is
+ released when exiting the protected code. The following code will release
+ the monitor when the execution thread leaves the protected scope, either
+ because the protected code has executed successfully, or because an
+ exception was thrown.
+ \begin{verbatim}
+ { -- protected scope
+ static GMonitor theMonitor;
+ GMonitorLock lock(&theMonitor)
+ ... -- protected code
+ }
+ \end{verbatim}
+ This construct will do nothing when passed a null pointer.
+*/
+class GMonitorLock
+{
+private:
+ GMonitor *gsec;
+public:
+ /** Constructor. Enters the monitor #gsec#. */
+ GMonitorLock(GMonitor *gsec) : gsec(gsec)
+ { if (gsec) gsec->enter(); };
+ /** Destructor. Leaves the associated monitor. */
+ ~GMonitorLock()
+ { if (gsec) gsec->leave(); };
+};
+
+
+
+// ----------------------------------------
+// GSAFEFLAGS (not so safe)
+
+
+/** A thread safe class representing a set of flags. The flags are protected
+ by \Ref{GMonitor}, which is attempted to be locked whenever somebody
+ accesses the flags. One can modify the class contents using one of
+ two functions: \Ref{test_and_modify}() and \Ref{wait_and_modify}().
+ Both of them provide atomic operation of testing (first) and modification
+ (second). The flags remain locked between the moment of testing and
+ modification, which guarantees, that their state cannot be changed in
+ between of these operations. */
+class GSafeFlags : public GMonitor
+{
+private:
+ volatile long flags;
+public:
+ /// Constructs #GSafeFlags# object.
+ GSafeFlags(long flags=0);
+
+ /** Assignment operator. Will also wake up threads waiting for the
+ flags to change. */
+ GSafeFlags & operator=(long flags);
+
+ /** Returns the value of the flags */
+ operator long(void) const;
+ /** Modifies the flags by ORing them with the provided mask. A broadcast
+ will be sent after the modification is done. */
+ GSafeFlags & operator|=(long mask);
+ /** Modifies the flags by ANDing them with the provided mask. A broadcast
+ will be sent after the modification is done. */
+ GSafeFlags & operator&=(long mask);
+
+ /** If all bits mentioned in #set_mask# are set in the flags and all
+ bits mentioned in #clr_mask# are cleared in the flags, it sets all
+ bits from #set_mask1# in the flags, clears all flags from
+ #clr_mask1# in the flags and returns #TRUE#. Otherwise returns
+ #FALSE#. */
+ bool test_and_modify(long set_mask, long clr_mask,
+ long set_mask1, long clr_mask1);
+
+ /** Waits until all bits mentioned in #set_mask# are set in the flags
+ and all bits mentioned in #clr_flags# are cleared in the flags.
+ After that it sets bits from #set_mask1# and clears bits from
+ #clr_mask1# in the flags. */
+ void wait_and_modify(long set_mask, long clr_mask,
+ long set_mask1, long clr_mask1);
+
+ /** Waits until all bits set in #set_mask# are set in the flags and
+ all bits mentioned in #clr_mask# are cleared in the flags. */
+ void wait_for_flags(long set_mask, long clr_mask=0) const;
+
+ /** Modifies the flags by setting all bits mentioned in #set_mask#
+ and clearing all bits mentioned in #clr_mask#. If the flags have
+ actually been modified, a broadcast will be sent. */
+ void modify(long set_mask, long clr_mask);
+};
+
+inline
+GSafeFlags::GSafeFlags(long xflags)
+ : flags(xflags)
+{
+}
+
+inline void
+GSafeFlags::wait_for_flags(long set_mask, long clr_mask) const
+{
+ ((GSafeFlags *) this)->wait_and_modify(set_mask, clr_mask, 0, 0);
+}
+
+inline void
+GSafeFlags::modify(long set_mask, long clr_mask)
+{
+ test_and_modify(0, 0, set_mask, clr_mask);
+}
+
+inline GSafeFlags &
+GSafeFlags::operator|=(long mask)
+{
+ test_and_modify(0, 0, mask, 0);
+ return *this;
+}
+
+inline GSafeFlags &
+GSafeFlags::operator&=(long mask)
+{
+ test_and_modify(0, 0, 0, ~mask);
+ return *this;
+}
+
+//@}
+
+
+
+
+// ----------------------------------------
+// COMPATIBILITY CLASSES
+
+
+// -- these classes are no longer documented.
+
+class GCriticalSection : protected GMonitor
+{
+public:
+ void lock()
+ { GMonitor::enter(); };
+ void unlock()
+ { GMonitor::leave(); };
+};
+
+class GEvent : protected GMonitor
+{
+private:
+ int status;
+public:
+ GEvent()
+ : status(0) { };
+ void set()
+ { if (!status) { enter(); status=1; signal(); leave(); } };
+ void wait()
+ { enter(); if (!status) GMonitor::wait(); status=0; leave(); };
+ void wait(int timeout)
+ { enter(); if (!status) GMonitor::wait(timeout); status=0; leave(); };
+};
+
+class GCriticalSectionLock
+{
+private:
+ GCriticalSection *gsec;
+public:
+ GCriticalSectionLock(GCriticalSection *gsec) : gsec(gsec)
+ { if (gsec) gsec->lock(); };
+ ~GCriticalSectionLock()
+ { if (gsec) gsec->unlock(); };
+};
+
+
+// ----------------------------------------
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif //_GTHREADS_H_
+
diff --git a/kviewshell/plugins/djvu/libdjvu/GURL.cpp b/kviewshell/plugins/djvu/libdjvu/GURL.cpp
new file mode 100644
index 00000000..54b082ff
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GURL.cpp
@@ -0,0 +1,1965 @@
+//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: GURL.cpp,v 1.19 2005/04/27 16:34:13 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+// From: Leon Bottou, 1/31/2002
+// This has been heavily changed by Lizardtech.
+// They decided to use URLs for everyting, including
+// the most basic file access. The URL class now is a unholy
+// mixture of code for syntactically parsing the urls (which it was)
+// and file status code (only for local file: urls).
+
+#include "GException.h"
+#include "GOS.h"
+#include "GURL.h"
+#include "debug.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <math.h>
+#include <string.h>
+
+#ifdef WIN32
+# include <atlbase.h>
+# include <windows.h>
+# include <direct.h>
+#endif /* WIN32 */
+
+// -- MAXPATHLEN
+#ifndef MAXPATHLEN
+# ifdef _MAX_PATH
+# define MAXPATHLEN _MAX_PATH
+# else
+# define MAXPATHLEN 1024
+# endif
+#else
+# if ( MAXPATHLEN < 1024 )
+# undef MAXPATHLEN
+# define MAXPATHLEN 1024
+# endif
+#endif
+
+#if defined(UNIX) || defined(OS2)
+# include <unistd.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <errno.h>
+# include <fcntl.h>
+# include <pwd.h>
+# include <stdio.h>
+# ifdef AUTOCONF
+# ifdef TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+# else
+# ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+# endif
+# ifdef HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+# else
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# ifdef HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# endif
+# endif
+# else /* !AUTOCONF */
+# include <sys/time.h>
+# if defined(XENIX)
+# define USE_DIRECT
+# include <sys/ndir.h>
+# elif defined(OLDBSD)
+# define USE_DIRECT
+# include <sys/dir.h>
+# endif
+# ifdef USE_DIRECT
+# define dirent direct
+# define NAMLEN(dirent) (dirent)->d_namlen
+# else
+# include <dirent.h>
+# define NAMLEN(dirent) strlen((dirent)->d_name)
+# endif
+# endif /* !AUTOCONF */
+#endif /* UNIX */
+
+#ifdef macintosh
+#include <unix.h>
+#include <errno.h>
+#include <unistd.h>
+#endif
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+static const char djvuopts[]="DJVUOPTS";
+static const char localhost[]="file://localhost/";
+static const char backslash='\\';
+static const char colon=':';
+static const char dot='.';
+static const char filespecslashes[] = "file://";
+static const char filespec[] = "file:";
+static const char slash='/';
+static const char percent='%';
+static const char localhostspec1[] = "//localhost/";
+static const char localhostspec2[] = "///";
+static const char nillchar=0;
+#if defined(UNIX)
+ static const char tilde='~';
+ static const char root[] = "/";
+#elif defined(WIN32) || defined(OS2)
+ static const char root[] = "\\";
+#elif defined(macintosh)
+ static char const * const root = &nillchar;
+#else
+#error "Define something here for your operating system"
+#endif
+
+
+static const int
+pathname_start(const GUTF8String &url, const int protolength);
+
+// hexval --
+// -- Returns the hexvalue of a character.
+// Returns -1 if illegal;
+
+static int
+hexval(char c)
+{
+ return ((c>='0' && c<='9')
+ ?(c-'0')
+ :((c>='A' && c<='F')
+ ?(c-'A'+10)
+ :((c>='a' && c<='f')
+ ?(c-'a'+10):(-1))));
+}
+
+
+static bool
+is_argument(const char * start)
+ // Returns TRUE if 'start' points to the beginning of an argument
+ // (either hash or CGI)
+{
+ // return (*start=='#' || *start=='?' || *start=='&' || *start==';');
+ return (*start=='#' || *start=='?' );
+}
+
+static bool
+is_argument_sep(const char * start)
+ // Returns TRUE if 'start' points to the beginning of an argument
+ // (either hash or CGI)
+{
+ return (*start=='&')||(*start == ';');
+}
+
+void
+GURL::convert_slashes(void)
+{
+ GUTF8String xurl(get_string());
+#if defined(WIN32)
+ const int protocol_length=protocol(xurl).length();
+ for(char *ptr=(xurl.getbuf()+protocol_length);*ptr;ptr++)
+ if(*ptr == backslash)
+ *ptr=slash;
+ url=xurl;
+#endif
+}
+
+static void
+collapse(char * ptr, const int chars)
+ // Will remove the first 'chars' chars from the string and
+ // move the rest toward the beginning. Will take into account
+ // string length
+{
+ const int length=strlen(ptr);
+ const char *srcptr=ptr+((chars>length)?length:chars);
+ while((*(ptr++) = *(srcptr++)))
+ EMPTY_LOOP;
+}
+
+GUTF8String
+GURL::beautify_path(GUTF8String xurl)
+{
+
+ const int protocol_length=GURL::protocol(xurl).length();
+
+ // Eats parts like ./ or ../ or ///
+ char * buffer;
+ GPBuffer<char> gbuffer(buffer,xurl.length()+1);
+ strcpy(buffer, (const char *)xurl);
+
+ // Find start point
+ char * start=buffer+pathname_start(xurl,protocol_length);
+
+ // Find end of the url (don't touch arguments)
+ char * ptr;
+ GUTF8String args;
+ for(ptr=start;*ptr;ptr++)
+ {
+ if (is_argument(ptr))
+ {
+ args=ptr;
+ *ptr=0;
+ break;
+ }
+ }
+
+ // Eat multiple slashes
+ for(;(ptr=strstr(start, "////"));collapse(ptr, 3))
+ EMPTY_LOOP;
+ for(;(ptr=strstr(start, "//"));collapse(ptr, 1))
+ EMPTY_LOOP;
+ // Convert /./ stuff into plain /
+ for(;(ptr=strstr(start, "/./"));collapse(ptr, 2))
+ EMPTY_LOOP;
+#if defined(WIN32) || defined(OS2)
+ if(!xurl.cmp(filespec,sizeof(filespec)-1))
+ {
+ int offset=1;
+ if(start&&(start[0] == '/')&&
+ !xurl.cmp("file:////",sizeof("file:////")-1))
+ {
+ collapse(start, 1);
+ offset=0;
+ }
+ for(ptr=start+offset;(ptr=strchr(ptr, '/'));)
+ {
+ if(isalpha((++ptr)[0]))
+ {
+ if((ptr[1] == ':')&&(ptr[2]=='/'))
+ {
+ char *buffer2;
+ GPBuffer<char> gbuffer2(buffer2,strlen(ptr)+1);
+ strcpy(buffer2,ptr);
+ gbuffer.resize(strlen(ptr)+sizeof(localhost));
+ strcpy(buffer,localhost);
+ strcat(buffer,buffer2);
+ ptr=(start=buffer+sizeof(localhost))+1;
+ }
+ }
+ }
+ }
+#endif
+ // Process /../
+ while((ptr=strstr(start, "/../")))
+ {
+ for(char * ptr1=ptr-1;(ptr1>=start);ptr1--)
+ {
+ if (*ptr1==slash)
+ {
+ collapse(ptr1, ptr-ptr1+3);
+ break;
+ }
+ }
+ }
+
+ // Remove trailing /.
+ ptr=start+strlen(start)-2;
+ if((ptr>=start)&& (ptr == GUTF8String("/.")))
+ {
+ ptr[1]=0;
+ }
+ // Eat trailing /..
+ ptr=start+strlen(start)-3;
+ if((ptr >= start) && (ptr == GUTF8String("/..")))
+ {
+ for(char * ptr1=ptr-1;(ptr1>=start);ptr1--)
+ {
+ if (*ptr1==slash)
+ {
+ ptr1[1]=0;
+ break;
+ }
+ }
+ }
+
+ // Done. Copy the buffer back into the URL and add arguments.
+ xurl=buffer;
+ return (xurl+args);
+}
+
+
+void
+GURL::beautify_path(void)
+{
+ url=beautify_path(get_string());
+}
+
+void
+GURL::init(const bool nothrow)
+{
+ GCriticalSectionLock lock(&class_lock);
+ validurl=true;
+
+ if (url.length())
+ {
+ GUTF8String proto=protocol();
+ if (proto.length()<2)
+ {
+ validurl=false;
+ if(!nothrow)
+ G_THROW( ERR_MSG("GURL.no_protocol") "\t"+url);
+ return;
+ }
+
+ // Below we have to make this complex test to detect URLs really
+ // referring to *local* files. Surprisingly, file://hostname/dir/file
+ // is also valid, but shouldn't be treated thru local FS.
+ if (proto=="file" && url[5]==slash &&
+ (url[6]!=slash || !url.cmp(localhost, sizeof(localhost))))
+ {
+ // Separate the arguments
+ GUTF8String arg;
+ {
+ const char * const url_ptr=url;
+ const char * ptr;
+ for(ptr=url_ptr;*ptr&&!is_argument(ptr);ptr++)
+ EMPTY_LOOP;
+ arg=ptr;
+ url=url.substr(0,(size_t)ptr-(size_t)url_ptr);
+ }
+
+ // Do double conversion
+ GUTF8String tmp=UTF8Filename();
+ if (!tmp.length())
+ {
+ validurl=false;
+ if(!nothrow)
+ G_THROW( ERR_MSG("GURL.fail_to_file") );
+ return;
+ }
+ url=GURL::Filename::UTF8(tmp).get_string();
+ if (!url.length())
+ {
+ validurl=false;
+ if(!nothrow)
+ G_THROW( ERR_MSG("GURL.fail_to_URL") );
+ return;
+ }
+ // Return the argument back
+ url+=arg;
+ }
+ convert_slashes();
+ beautify_path();
+ parse_cgi_args();
+ }
+}
+
+GURL::GURL(void)
+ : validurl(false)
+{
+}
+
+GURL::GURL(const char * url_in)
+ : url(url_in ? url_in : ""), validurl(false)
+{
+}
+
+GURL::GURL(const GUTF8String & url_in)
+ : url(url_in), validurl(false)
+{
+}
+
+GURL::GURL(const GNativeString & url_in)
+ : url(url_in.getNative2UTF8()), validurl(false)
+{
+#if defined(WIN32) || defined(OS2)
+ if(is_valid() && is_local_file_url())
+ {
+ GURL::Filename::UTF8 xurl(UTF8Filename());
+ url=xurl.get_string(true);
+ validurl=false;
+ }
+#endif
+}
+
+GURL::GURL(const GURL & url_in)
+ : validurl(false)
+{
+ if(url_in.is_valid())
+ {
+ url=url_in.get_string();
+ init();
+ }else
+ {
+ url=url_in.url;
+ }
+}
+
+GURL &
+GURL::operator=(const GURL & url_in)
+{
+ GCriticalSectionLock lock(&class_lock);
+ if(url_in.is_valid())
+ {
+ url=url_in.get_string();
+ init(true);
+ }else
+ {
+ url=url_in.url;
+ validurl=false;
+ }
+ return *this;
+}
+
+GUTF8String
+GURL::protocol(const GUTF8String& url)
+{
+ const char * const url_ptr=url;
+ const char * ptr=url_ptr;
+ for(char c=*ptr;
+ c && (isalnum(c) || c == '+' || c == '-' || c == '.');
+ c=*(++ptr)) EMPTY_LOOP;
+ return(*ptr==colon)?GUTF8String(url_ptr, ptr-url_ptr):GUTF8String();
+}
+
+GUTF8String
+GURL::hash_argument(void) const
+ // Returns the HASH argument (anything after '#' and before '?')
+{
+ const GUTF8String xurl(get_string());
+
+ bool found=false;
+ GUTF8String arg;
+
+ // Break if CGI argument is found
+ for(const char * start=xurl;*start&&(*start!='?');start++)
+ {
+ if (found)
+ {
+ arg+=*start;
+ }else
+ {
+ found=(*start=='#');
+ }
+ }
+ return decode_reserved(arg);
+}
+
+void
+GURL::set_hash_argument(const GUTF8String &arg)
+{
+ const GUTF8String xurl(get_string());
+
+ GUTF8String new_url;
+ bool found=false;
+ const char * ptr;
+ for(ptr=xurl;*ptr;ptr++)
+ {
+ if (is_argument(ptr))
+ {
+ if (*ptr!='#')
+ {
+ break;
+ }
+ found=true;
+ } else if (!found)
+ {
+ new_url+=*ptr;
+ }
+ }
+
+ url=new_url+"#"+GURL::encode_reserved(arg)+ptr;
+}
+
+void
+GURL::parse_cgi_args(void)
+ // Will read CGI arguments from the URL into
+ // cgi_name_arr and cgi_value_arr
+{
+ if(!validurl)
+ init();
+ GCriticalSectionLock lock1(&class_lock);
+ cgi_name_arr.empty();
+ cgi_value_arr.empty();
+
+ // Search for the beginning of CGI arguments
+ const char * start=url;
+ while(*start)
+ {
+ if(*(start++)=='?')
+ {
+ break;
+ }
+ }
+
+ // Now loop until we see all of them
+ while(*start)
+ {
+ GUTF8String arg; // Storage for another argument
+ while(*start) // Seek for the end of it
+ {
+ if (is_argument_sep(start))
+ {
+ start++;
+ break;
+ } else
+ {
+ arg+=*start++;
+ }
+ }
+ if (arg.length())
+ {
+ // Got argument in 'arg'. Split it into 'name' and 'value'
+ const char * ptr;
+ const char * const arg_ptr=arg;
+ for(ptr=arg_ptr;*ptr&&(*ptr != '=');ptr++)
+ EMPTY_LOOP;
+
+ GUTF8String name, value;
+ if (*ptr)
+ {
+ name=GUTF8String(arg_ptr, (int)((ptr++)-arg_ptr));
+ value=GUTF8String(ptr, arg.length()-name.length()-1);
+ } else
+ {
+ name=arg;
+ }
+
+ int args=cgi_name_arr.size();
+ cgi_name_arr.resize(args);
+ cgi_value_arr.resize(args);
+ cgi_name_arr[args]=decode_reserved(name);
+ cgi_value_arr[args]=decode_reserved(value);
+ }
+ }
+}
+
+void
+GURL::store_cgi_args(void)
+ // Will store CGI arguments from the cgi_name_arr and cgi_value_arr
+ // back into the URL
+{
+ if(!validurl)
+ init();
+ GCriticalSectionLock lock1(&class_lock);
+
+ const char * const url_ptr=url;
+ const char * ptr;
+ for(ptr=url_ptr;*ptr&&(*ptr!='?');ptr++)
+ EMPTY_LOOP;
+
+ GUTF8String new_url(url_ptr, ptr-url_ptr);
+
+ for(int i=0;i<cgi_name_arr.size();i++)
+ {
+ GUTF8String name=GURL::encode_reserved(cgi_name_arr[i]);
+ GUTF8String value=GURL::encode_reserved(cgi_value_arr[i]);
+ new_url+=(i?"&":"?")+name;
+ if (value.length())
+ new_url+="="+value;
+ }
+
+ url=new_url;
+}
+
+int
+GURL::cgi_arguments(void) const
+{
+ if(!validurl)
+ const_cast<GURL *>(this)->init();
+ return cgi_name_arr.size();
+}
+
+int
+GURL::djvu_cgi_arguments(void) const
+{
+ if(!validurl)
+ const_cast<GURL *>(this)->init();
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+
+ int args=0;
+ for(int i=0;i<cgi_name_arr.size();i++)
+ {
+ if (cgi_name_arr[i].upcase()==djvuopts)
+ {
+ args=cgi_name_arr.size()-(i+1);
+ break;
+ }
+ }
+ return args;
+}
+
+GUTF8String
+GURL::cgi_name(int num) const
+{
+ if(!validurl) const_cast<GURL *>(this)->init();
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+ return (num<cgi_name_arr.size())?cgi_name_arr[num]:GUTF8String();
+}
+
+GUTF8String
+GURL::djvu_cgi_name(int num) const
+{
+ if(!validurl) const_cast<GURL *>(this)->init();
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+
+ GUTF8String arg;
+ for(int i=0;i<cgi_name_arr.size();i++)
+ if (cgi_name_arr[i].upcase()==djvuopts)
+ {
+ for(i++;i<cgi_name_arr.size();i++)
+ if (! num--)
+ {
+ arg=cgi_name_arr[i];
+ break;
+ }
+ break;
+ }
+ return arg;
+}
+
+GUTF8String
+GURL::cgi_value(int num) const
+{
+ if(!validurl) const_cast<GURL *>(this)->init();
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+ return (num<cgi_value_arr.size())?cgi_value_arr[num]:GUTF8String();
+}
+
+GUTF8String
+GURL::djvu_cgi_value(int num) const
+{
+ if(!validurl) const_cast<GURL *>(this)->init();
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+
+ GUTF8String arg;
+ for(int i=0;i<cgi_name_arr.size();i++)
+ {
+ if (cgi_name_arr[i].upcase()==djvuopts)
+ {
+ for(i++;i<cgi_name_arr.size();i++)
+ {
+ if (! num--)
+ {
+ arg=cgi_value_arr[i];
+ break;
+ }
+ }
+ break;
+ }
+ }
+ return arg;
+}
+
+DArray<GUTF8String>
+GURL::cgi_names(void) const
+{
+ if(!validurl) const_cast<GURL *>(this)->init();
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+ return cgi_name_arr;
+}
+
+DArray<GUTF8String>
+GURL::cgi_values(void) const
+{
+ if(!validurl) const_cast<GURL *>(this)->init();
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+ return cgi_value_arr;
+}
+
+DArray<GUTF8String>
+GURL::djvu_cgi_names(void) const
+{
+ if(!validurl) const_cast<GURL *>(this)->init();
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+
+ int i;
+ DArray<GUTF8String> arr;
+ for(i=0;(i<cgi_name_arr.size())&&
+ (cgi_name_arr[i].upcase()!=djvuopts)
+ ;i++)
+ EMPTY_LOOP;
+
+ int size=cgi_name_arr.size()-(i+1);
+ if (size>0)
+ {
+ arr.resize(size-1);
+ for(i=0;i<arr.size();i++)
+ arr[i]=cgi_name_arr[cgi_name_arr.size()-arr.size()+i];
+ }
+
+ return arr;
+}
+
+DArray<GUTF8String>
+GURL::djvu_cgi_values(void) const
+{
+ if(!validurl) const_cast<GURL *>(this)->init();
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+
+ int i;
+ DArray<GUTF8String> arr;
+ for(i=0;i<cgi_name_arr.size()&&(cgi_name_arr[i].upcase()!=djvuopts);i++)
+ EMPTY_LOOP;
+
+ int size=cgi_name_arr.size()-(i+1);
+ if (size>0)
+ {
+ arr.resize(size-1);
+ for(i=0;i<arr.size();i++)
+ arr[i]=cgi_value_arr[cgi_value_arr.size()-arr.size()+i];
+ }
+
+ return arr;
+}
+
+void
+GURL::clear_all_arguments(void)
+{
+ clear_hash_argument();
+ clear_cgi_arguments();
+}
+
+void
+GURL::clear_hash_argument(void)
+ // Clear anything after first '#' and before the following '?'
+{
+ if(!validurl) init();
+ GCriticalSectionLock lock(&class_lock);
+ bool found=false;
+ GUTF8String new_url;
+ for(const char * start=url;*start;start++)
+ {
+ // Break on first CGI arg.
+ if (*start=='?')
+ {
+ new_url+=start;
+ break;
+ }
+
+ if (!found)
+ {
+ if (*start=='#')
+ found=true;
+ else
+ new_url+=*start;
+ }
+ }
+ url=new_url;
+}
+
+void
+GURL::clear_cgi_arguments(void)
+{
+ if(!validurl)
+ init();
+ GCriticalSectionLock lock1(&class_lock);
+
+ // Clear the arrays
+ cgi_name_arr.empty();
+ cgi_value_arr.empty();
+
+ // And clear everything past the '?' sign in the URL
+ for(const char * ptr=url;*ptr;ptr++)
+ if (*ptr=='?')
+ {
+ url.setat(ptr-url, 0);
+ break;
+ }
+}
+
+void
+GURL::clear_djvu_cgi_arguments(void)
+{
+ if(!validurl) init();
+ // First - modify the arrays
+ GCriticalSectionLock lock(&class_lock);
+ for(int i=0;i<cgi_name_arr.size();i++)
+ {
+ if (cgi_name_arr[i].upcase()==djvuopts)
+ {
+ cgi_name_arr.resize(i-1);
+ cgi_value_arr.resize(i-1);
+ break;
+ }
+ }
+
+ // And store them back into the URL
+ store_cgi_args();
+}
+
+void
+GURL::add_djvu_cgi_argument(const GUTF8String &name, const char * value)
+{
+ if(!validurl)
+ init();
+ GCriticalSectionLock lock1(&class_lock);
+
+ // Check if we already have the "DJVUOPTS" argument
+ bool have_djvuopts=false;
+ for(int i=0;i<cgi_name_arr.size();i++)
+ {
+ if (cgi_name_arr[i].upcase()==djvuopts)
+ {
+ have_djvuopts=true;
+ break;
+ }
+ }
+
+ // If there is no DJVUOPTS, insert it
+ if (!have_djvuopts)
+ {
+ int pos=cgi_name_arr.size();
+ cgi_name_arr.resize(pos);
+ cgi_value_arr.resize(pos);
+ cgi_name_arr[pos]=djvuopts;
+ }
+
+ // Add new argument to the array
+ int pos=cgi_name_arr.size();
+ cgi_name_arr.resize(pos);
+ cgi_value_arr.resize(pos);
+ cgi_name_arr[pos]=name;
+ cgi_value_arr[pos]=value;
+
+ // And update the URL
+ store_cgi_args();
+}
+
+bool
+GURL::is_local_file_url(void) const
+{
+ if(!validurl) const_cast<GURL *>(this)->init();
+ GCriticalSectionLock lock((GCriticalSection *) &class_lock);
+ return (protocol()=="file" && url[5]==slash);
+}
+
+static const int
+pathname_start(const GUTF8String &url, const int protolength)
+{
+ const int length=url.length();
+ int retval=0;
+ if(protolength+1<length)
+ {
+ retval=url.search(slash,((url[protolength+1] == '/')
+ ?((url[protolength+2] == '/')?(protolength+3):(protolength+2))
+ :(protolength+1)));
+ }
+ return (retval>0)?retval:length;
+}
+
+GUTF8String
+GURL::pathname(void) const
+{
+ return (is_local_file_url())
+ ?GURL::encode_reserved(UTF8Filename())
+ :url.substr(pathname_start(url,protocol().length()),(unsigned int)(-1));
+}
+
+GURL
+GURL::base(void) const
+{
+ const GUTF8String xurl(get_string());
+ const int protocol_length=protocol(xurl).length();
+ const int xurl_length=xurl.length();
+ const char * const url_ptr=xurl;
+ const char * ptr, * xslash;
+ ptr=xslash=url_ptr+protocol_length+1;
+ if(xslash[0] == '/')
+ {
+ xslash++;
+ if(xslash[0] == '/')
+ xslash++;
+ for(ptr=xslash;ptr[0] && !is_argument(ptr);ptr++)
+ {
+ if ((ptr[0]==slash)&&ptr[1]&&!is_argument(ptr+1))
+ xslash=ptr;
+ }
+ if(xslash[0] != '/')
+ {
+ xslash=url_ptr+xurl_length;
+ }
+ }
+ return GURL::UTF8(
+// ifdef WIN32
+// (*(xslash-1) == colon)?
+// (GUTF8String(xurl,(int)(xslash-url_ptr))+"/" ):
+// endif
+ (GUTF8String(xurl,(int)(xslash-url_ptr))+"/"));
+}
+
+bool
+GURL::operator==(const GURL & gurl2) const
+{
+ bool retval=false;
+ const GUTF8String g1(get_string());
+ const int g1_length=g1.length();
+ const GUTF8String g2(gurl2.get_string());
+ const int g2_length=g2.length();
+ if(g1_length == g2_length) // exactly equal
+ {
+ retval=(g1==g2);
+ }else if(g1_length+1 == g2_length) // g1 is g2 with a slash at the end
+ {
+ retval=(g2[g1_length] == '/')&&!g1.cmp(g2,g1_length);
+ }else if(g2_length+1 == g1_length) // g2 is g1 with a slash at the end
+ {
+ retval=(g1[g2_length] == '/')&&!g1.cmp(g2,g2_length);
+ }
+ return retval;
+}
+
+GUTF8String
+GURL::name(void) const
+{
+ if(!validurl)
+ const_cast<GURL *>(this)->init();
+ GUTF8String retval;
+ if(!is_empty())
+ {
+ const GUTF8String xurl(url);
+ const int protocol_length=protocol(xurl).length();
+ const char * ptr, * xslash=(const char *)xurl+protocol_length-1;
+ for(ptr=(const char *)xurl+protocol_length;
+ *ptr && !is_argument(ptr);ptr++)
+ {
+ if (*ptr==slash)
+ xslash=ptr;
+ }
+ retval=GUTF8String(xslash+1, ptr-xslash-1);
+ }
+ return retval;
+}
+
+GUTF8String
+GURL::fname(void) const
+{
+ if(!validurl)
+ const_cast<GURL *>(this)->init();
+ return decode_reserved(name());
+}
+
+GUTF8String
+GURL::extension(void) const
+{
+ if(!validurl)
+ const_cast<GURL *>(this)->init();
+ GUTF8String xfilename=name();
+ GUTF8String retval;
+
+ for(int i=xfilename.length()-1;i>=0;i--)
+ {
+ if (xfilename[i]=='.')
+ {
+ retval=(const char*)xfilename+i+1;
+ break;
+ }
+ }
+ return retval;
+}
+
+GUTF8String
+GURL::decode_reserved(const GUTF8String &gurl)
+{
+ const char *url=gurl;
+ char *res;
+ GPBuffer<char> gres(res,gurl.length()+1);
+ char *r=res;
+ for(const char * ptr=url;*ptr;++ptr,++r)
+ {
+ if (*ptr!=percent)
+ {
+ r[0]=*ptr;
+ }else
+ {
+ int c1,c2;
+ if ( ((c1=hexval(ptr[1]))>=0)
+ && ((c2=hexval(ptr[2]))>=0) )
+ {
+ r[0]=(c1<<4)|c2;
+ ptr+=2;
+ } else
+ {
+ r[0]=*ptr;
+ }
+ }
+ }
+ r[0]=0;
+ GUTF8String retval(res);
+ if(!retval.is_valid())
+ {
+ retval=GNativeString(res);
+ }
+ return retval;
+}
+
+GUTF8String
+GURL::encode_reserved(const GUTF8String &gs)
+{
+ const char *s=(const char *)gs;
+ // Potentially unsafe characters (cf. RFC1738 and RFC1808)
+ static const char hex[] = "0123456789ABCDEF";
+
+ unsigned char *retval;
+ GPBuffer<unsigned char> gd(retval,strlen(s)*3+1);
+ unsigned char *d=retval;
+ for (; *s; s++,d++)
+ {
+ // Convert directory separator to slashes
+#if defined(WIN32) || defined(OS2)
+ if (*s == backslash || *s== slash)
+#else
+#ifdef macintosh
+ if (*s == colon )
+#else
+#ifdef UNIX
+ if (*s == slash )
+#else
+#error "Define something here for your operating system"
+#endif
+#endif
+#endif
+ {
+ *d = slash;
+ continue;
+ }
+ unsigned char const ss=(unsigned char const)(*s);
+ // WARNING: Whenever you modify this conversion code,
+ // make sure, that the following functions are in sync:
+ // encode_reserved()
+ // decode_reserved()
+ // url_to_filename()
+ // filename_to_url()
+ // unreserved characters
+ if ( (ss>='a' && ss<='z') ||
+ (ss>='A' && ss<='Z') ||
+ (ss>='0' && ss<='9') ||
+ (strchr("$-_.+!*'(),:~=", ss)) )
+ {
+ *d = ss;
+ continue;
+ }
+ // escape sequence
+ d[0] = percent;
+ d[1] = hex[ (ss >> 4) & 0xf ];
+ d[2] = hex[ (ss) & 0xf ];
+ d+=2;
+ }
+ *d = 0;
+ return retval;
+}
+
+// -------------------------------------------
+// Functions for converting filenames and urls
+// -------------------------------------------
+
+static GUTF8String
+url_from_UTF8filename(const GUTF8String &gfilename)
+{
+ if(GURL::UTF8(gfilename).is_valid())
+ {
+ DEBUG_MSG("Debug: URL as Filename: " << gfilename << "\n");
+ }
+ const char *filename=gfilename;
+ if(filename && (unsigned char)filename[0] == (unsigned char)0xEF
+ && (unsigned char)filename[1] == (unsigned char)0xBB
+ && (unsigned char)filename[2] == (unsigned char)0xBF)
+ {
+ filename+=3;
+ }
+
+ // Special case for blank pages
+ if(!filename || !filename[0])
+ {
+ return GUTF8String();
+ }
+
+ // Normalize file name to url slash-and-escape syntax
+ GUTF8String oname=GURL::expand_name(filename);
+ GUTF8String nname=GURL::encode_reserved(oname);
+
+ // Preprend "file://" to file name. If file is on the local
+ // machine, include "localhost".
+ GUTF8String url=filespecslashes;
+ const char *cnname=nname;
+ if (cnname[0] == slash)
+ {
+ if (cnname[1] == slash)
+ {
+ url += cnname+2;
+ }else
+ {
+ url = localhost + nname;
+ }
+ }else
+ {
+ url += (localhostspec1+2) + nname;
+ }
+ return url;
+}
+
+GUTF8String
+GURL::get_string(const bool nothrow) const
+{
+ if(!validurl)
+ const_cast<GURL *>(this)->init(nothrow);
+ return url;
+}
+
+// -- Returns a url for accessing a given file.
+// If useragent is not provided, standard url will be created,
+// but will not be understood by some versions if IE.
+GUTF8String
+GURL::get_string(const GUTF8String &useragent) const
+{
+ if(!validurl)
+ const_cast<GURL *>(this)->init();
+ GUTF8String retval(url);
+ if(is_local_file_url()&&useragent.length())
+ {
+ if(useragent.search("MSIE") >= 0 || useragent.search("Microsoft")>=0)
+ {
+ retval=filespecslashes + expand_name(UTF8Filename());
+ }
+ }
+ return retval;
+}
+
+GURL::UTF8::UTF8(const GUTF8String &xurl)
+: GURL(xurl) {}
+
+GURL::UTF8::UTF8(const GUTF8String &xurl,const GURL &codebase)
+: GURL(xurl,codebase) {}
+
+GURL::GURL(const GUTF8String &xurl,const GURL &codebase)
+ : validurl(false)
+{
+ if(GURL::UTF8(xurl).is_valid())
+ {
+ url=xurl;
+ }else
+ {
+ const char *c=xurl;
+ if(c[0] == slash)
+ {
+ GURL base(codebase);
+ for(GURL newbase=base.base();newbase!=base;newbase=base.base())
+ {
+ base=newbase;
+ }
+ url=base.get_string(true)+GURL::encode_reserved(xurl);
+ }else
+ {
+ url=beautify_path(codebase.get_string(true)+GUTF8String(slash)+GURL::encode_reserved(xurl));
+ }
+ }
+}
+
+GURL::Native::Native(const GNativeString &xurl)
+: GURL(xurl) {}
+
+GURL::Native::Native(const GNativeString &xurl,const GURL &codebase)
+: GURL(xurl,codebase) {}
+
+GURL::GURL(const GNativeString &xurl,const GURL &codebase)
+ : validurl(false)
+{
+ GURL retval(xurl.getNative2UTF8(),codebase);
+ if(retval.is_valid())
+ {
+#if defined(WIN32)
+ // Hack for IE to change \\ to /
+ if(retval.is_local_file_url())
+ {
+ GURL::Filename::UTF8 retval2(retval.UTF8Filename());
+ url=retval2.get_string(true);
+ validurl=false;
+ }else
+#endif // WIN32
+ {
+ url=retval.get_string(true);
+ validurl=false;
+ }
+ }
+}
+
+GURL::Filename::Filename(const GNativeString &gfilename)
+{
+ url=url_from_UTF8filename(gfilename.getNative2UTF8());
+}
+
+GURL::Filename::Native::Native(const GNativeString &gfilename)
+: GURL::Filename(gfilename) {}
+
+GURL::Filename::Filename(const GUTF8String &gfilename)
+{
+ url=url_from_UTF8filename(gfilename);
+}
+
+GURL::Filename::UTF8::UTF8(const GUTF8String &gfilename)
+: GURL::Filename(gfilename) {}
+
+// filename --
+// -- Applies heuristic rules to convert a url into a valid file name.
+// Returns a simple basename in case of failure.
+GUTF8String
+GURL::UTF8Filename(void) const
+{
+ GUTF8String retval;
+ if(! is_empty())
+ {
+ const char *url_ptr=url;
+
+ // WARNING: Whenever you modify this conversion code,
+ // make sure, that the following functions are in sync:
+ // encode_reserved()
+ // decode_reserved()
+ // url_to_filename()
+ // filename_to_url()
+
+ GUTF8String urlcopy=decode_reserved(url);
+ url_ptr = urlcopy;
+
+ // All file urls are expected to start with filespec which is "file:"
+ if (GStringRep::cmp(filespec, url_ptr, sizeof(filespec)-1)) //if not
+ return GOS::basename(url_ptr);
+ url_ptr += sizeof(filespec)-1;
+
+#if defined(macintosh)
+ //remove all leading slashes
+ for(;*url_ptr==slash;url_ptr++)
+ EMPTY_LOOP;
+ // Remove possible localhost spec
+ if ( !GStringRep::cmp(localhost, url_ptr, sizeof(localhost)-1) )
+ url_ptr += sizeof(localhost)-1;
+ //remove all leading slashes
+ while(*url_ptr==slash)
+ url_ptr++;
+#else
+ // Remove possible localhost spec
+ if ( !GStringRep::cmp(localhostspec1, url_ptr, sizeof(localhostspec1)-1) )
+ // RFC 1738 local host form
+ url_ptr += sizeof(localhostspec1)-1;
+ else if ( !GStringRep::cmp(localhostspec2, url_ptr, sizeof(localhostspec2)-1 ) )
+ // RFC 1738 local host form
+ url_ptr += sizeof(localhostspec2)-1;
+ else if ( (strlen(url_ptr) > 4) // "file://<letter>:/<path>"
+ && (url_ptr[0] == slash) // "file://<letter>|/<path>"
+ && (url_ptr[1] == slash)
+ && isalpha(url_ptr[2])
+ && ( url_ptr[3] == colon || url_ptr[3] == '|' )
+ && (url_ptr[4] == slash) )
+ url_ptr += 2;
+ else if ( (strlen(url_ptr)) > 2 // "file:/<path>"
+ && (url_ptr[0] == slash)
+ && (url_ptr[1] != slash) )
+ url_ptr++;
+#endif
+
+ // Check if we are finished
+#if defined(macintosh)
+ {
+ char *l_url;
+ GPBuffer<char> gl_url(l_url,strlen(url_ptr)+1);
+ const char *s;
+ char *r;
+ for ( s=url_ptr,r=l_url; *s; s++,r++)
+ {
+ *r=(*s == slash)?colon:*s;
+ }
+ *r=0;
+ retval = expand_name(l_url,root);
+ }
+#else
+ retval = expand_name(url_ptr,root);
+#endif
+
+#if defined(WIN32) || defined(OS2)
+ if (url_ptr[0] && url_ptr[1]=='|' && url_ptr[2]== slash)
+ {
+ if ((url_ptr[0]>='a' && url_ptr[0]<='z')
+ || (url_ptr[0]>='A' && url_ptr[0]<='Z'))
+ {
+ GUTF8String drive;
+ drive.format("%c%c%c", url_ptr[0],colon,backslash);
+ retval = expand_name(url_ptr+3, drive);
+ }
+ }
+#endif
+ }
+ // Return what we have
+ return retval;
+}
+
+GNativeString
+GURL::NativeFilename(void) const
+{
+ return UTF8Filename().getUTF82Native();
+}
+
+#if defined(UNIX) || defined(macintosh) || defined(OS2)
+static int
+urlstat(const GURL &url,struct stat &buf)
+{
+ return ::stat(url.NativeFilename(),&buf);
+}
+#endif
+
+// is_file(url) --
+// -- returns true if filename denotes a regular file.
+bool
+GURL::is_file(void) const
+{
+ bool retval=false;
+ if(is_local_file_url())
+ {
+#if defined(UNIX) || defined(macintosh) || defined(OS2)
+ struct stat buf;
+ if (!urlstat(*this,buf))
+ {
+ retval=!(buf.st_mode & S_IFDIR);
+ }
+#elif defined(WIN32)
+ GUTF8String filename(UTF8Filename());
+ if(filename.length() >= MAX_PATH)
+ {
+ if(!filename.cmp("\\\\",2))
+ filename="\\\\?\\UNC"+filename.substr(1,-1);
+ else
+ filename="\\\\?\\"+filename;
+ }
+ wchar_t *wfilename;
+ const size_t wfilename_size=filename.length()+1;
+ GPBuffer<wchar_t> gwfilename(wfilename,wfilename_size);
+ filename.ncopy(wfilename,wfilename_size);
+ DWORD dwAttrib;
+ dwAttrib = GetFileAttributesW(wfilename);
+ if((dwAttrib|1) == 0xFFFFFFFF)
+ {
+ USES_CONVERSION ;
+ dwAttrib = GetFileAttributes(A2CT(NativeFilename())) ;//MBCS cvt
+ }
+ retval=!( dwAttrib & FILE_ATTRIBUTE_DIRECTORY );
+#else
+# error "Define something here for your operating system"
+#endif
+ }
+ return retval;
+}
+
+bool
+GURL::is_local_path(void) const
+{
+ bool retval=false;
+ if(is_local_file_url())
+ {
+#if defined(UNIX) || defined(macintosh) || defined(OS2)
+ struct stat buf;
+ retval=!urlstat(*this,buf);
+#else
+ GUTF8String filename(UTF8Filename());
+ if(filename.length() >= MAX_PATH)
+ {
+ if(!filename.cmp("\\\\",2))
+ filename="\\\\?\\UNC"+filename.substr(1,-1);
+ else
+ filename="\\\\?\\"+filename;
+ }
+ wchar_t *wfilename;
+ const size_t wfilename_size=filename.length()+1;
+ GPBuffer<wchar_t> gwfilename(wfilename,wfilename_size);
+ filename.ncopy(wfilename,wfilename_size);
+ DWORD dwAttrib;
+ dwAttrib = GetFileAttributesW(wfilename);
+ if((dwAttrib|1) == 0xFFFFFFFF)
+ {
+ USES_CONVERSION ;
+ dwAttrib = GetFileAttributes(A2CT(NativeFilename())) ;//MBCS cvt
+ }
+ retval=( (dwAttrib|1) != 0xFFFFFFFF);
+#endif
+ }
+ return retval;
+}
+
+// is_dir(url) --
+// -- returns true if url denotes a directory.
+bool
+GURL::is_dir(void) const
+{
+ bool retval=false;
+ if(is_local_file_url())
+ {
+ // UNIX implementation
+#if defined(UNIX) || defined(macintosh) || defined(OS2)
+ struct stat buf;
+ if (!urlstat(*this,buf))
+ {
+ retval=(buf.st_mode & S_IFDIR);
+ }
+#elif defined(WIN32) // (either Windows or WCE)
+ GUTF8String filename(UTF8Filename());
+ if(filename.length() >= MAX_PATH)
+ {
+ if(!filename.cmp("\\\\",2))
+ filename="\\\\?\\UNC"+filename.substr(1,-1);
+ else
+ filename="\\\\?\\"+filename;
+ }
+ wchar_t *wfilename;
+ const size_t wfilename_size=filename.length()+1;
+ GPBuffer<wchar_t> gwfilename(wfilename,wfilename_size);
+ filename.ncopy(wfilename,wfilename_size);
+ DWORD dwAttrib;
+ dwAttrib = GetFileAttributesW(wfilename);
+ if((dwAttrib|1) == 0xFFFFFFFF)
+ {
+ USES_CONVERSION ;
+ dwAttrib = GetFileAttributes(A2CT(NativeFilename())) ;//MBCS cvt
+ }
+ retval=((dwAttrib != 0xFFFFFFFF)&&( dwAttrib & FILE_ATTRIBUTE_DIRECTORY ));
+#else
+# error "Define something here for your operating system"
+#endif
+ }
+ return retval;
+}
+
+// Follows symbolic links.
+GURL
+GURL::follow_symlinks(void) const
+{
+ GURL ret = *this;
+#if defined(S_IFLNK)
+#if defined(UNIX) || defined(macintosh)
+ int lnklen;
+ char lnkbuf[MAXPATHLEN+1];
+ struct stat buf;
+ while ( (urlstat(ret, buf) >= 0) &&
+ (buf.st_mode & S_IFLNK) &&
+ ((lnklen = readlink(ret.NativeFilename(),lnkbuf,sizeof(lnkbuf))) > 0) )
+ {
+ lnkbuf[lnklen] = 0;
+ GNativeString lnk(lnkbuf);
+ ret = GURL(lnk, ret.base());
+ }
+#endif
+#endif
+ return ret;
+}
+
+int
+GURL::mkdir() const
+{
+ if(! is_local_file_url())
+ return -1;
+ int retval=0;
+ const GURL baseURL=base();
+ if (baseURL.get_string() != url && !baseURL.is_dir())
+ retval = baseURL.mkdir();
+ if(!retval)
+ {
+#if defined(UNIX)
+ if (is_dir())
+ retval = 0;
+ else
+ retval = ::mkdir(NativeFilename(), 0755);
+#elif defined(WIN32)
+ USES_CONVERSION;
+ if (is_dir())
+ retval = 0;
+ else
+ retval = CreateDirectory(A2CT(NativeFilename()), NULL);
+#else
+# error "Define something here for your operating system"
+#endif
+ }
+ return retval;
+}
+
+// deletefile
+// -- deletes a file or directory
+
+int
+GURL::deletefile(void) const
+{
+ int retval = -1;
+ if(is_local_file_url())
+ {
+#if defined(UNIX)
+ if (is_dir())
+ retval = ::rmdir(NativeFilename());
+ else
+ retval = ::unlink(NativeFilename());
+#elif defined(WIN32)
+ USES_CONVERSION;
+ if (is_dir())
+ retval = ::RemoveDirectory(A2CT(NativeFilename()));
+ else
+ retval = ::DeleteFile(A2CT(NativeFilename()));
+#else
+# error "Define something here for your operating system"
+#endif
+ }
+ return retval;
+}
+
+GList<GURL>
+GURL::listdir(void) const
+{
+ GList<GURL> retval;
+ if(is_dir())
+ {
+#if defined(UNIX) || defined(OS2)
+ DIR * dir=opendir(NativeFilename());//MBCS cvt
+ for(dirent *de=readdir(dir);de;de=readdir(dir))
+ {
+ const int len = NAMLEN(de);
+ if (de->d_name[0]== dot && len==1)
+ continue;
+ if (de->d_name[0]== dot && de->d_name[1]== dot && len==2)
+ continue;
+ retval.append(GURL::Native(de->d_name,*this));
+ }
+ closedir(dir);
+#elif defined (WIN32)
+ GURL::UTF8 wildcard("*.*",*this);
+ WIN32_FIND_DATA finddata;
+ HANDLE handle = FindFirstFile(wildcard.NativeFilename(), &finddata);//MBCS cvt
+ const GUTF8String gpathname=pathname();
+ const GUTF8String gbase=base().pathname();
+ if( handle != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ GURL::UTF8 Entry(finddata.cFileName,*this);
+ const GUTF8String gentry=Entry.pathname();
+ if((gentry != gpathname) && (gentry != gbase))
+ retval.append(Entry);
+ } while( FindNextFile(handle, &finddata) );
+
+ FindClose(handle);
+ }
+#else
+# error "Define something here for your operating system"
+#endif
+ }
+ return retval;
+}
+
+int
+GURL::cleardir(const int timeout) const
+{
+ int retval=(-1);
+ if(is_dir())
+ {
+ GList<GURL> dirlist=listdir();
+ retval=0;
+ for(GPosition pos=dirlist;pos&&!retval;++pos)
+ {
+ const GURL &Entry=dirlist[pos];
+ if(Entry.is_dir())
+ {
+ if((retval=Entry.cleardir(timeout)) < 0)
+ {
+ break;
+ }
+ }
+ if(((retval=Entry.deletefile())<0) && (timeout>0))
+ {
+ GOS::sleep(timeout);
+ retval=Entry.deletefile();
+ }
+ }
+ }
+ return retval;
+}
+
+int
+GURL::renameto(const GURL &newurl) const
+{
+ if (is_local_file_url() && newurl.is_local_file_url())
+ return rename(NativeFilename(),newurl.NativeFilename());
+ return -1;
+}
+
+// expand_name(filename[, fromdirname])
+// -- returns the full path name of filename interpreted
+// relative to fromdirname. Use current working dir when
+// fromdirname is null.
+GUTF8String
+GURL::expand_name(const GUTF8String &xfname, const char *from)
+{
+ const char *fname=xfname;
+ GUTF8String retval;
+ const size_t maxlen=xfname.length()*9+MAXPATHLEN+10;
+ char * const string_buffer = retval.getbuf(maxlen);
+ // UNIX implementation
+#if defined(UNIX)
+ // Perform tilde expansion
+ GUTF8String senv;
+ if (fname && fname[0]==tilde)
+ {
+ int n;
+ for(n=1;fname[n] && fname[n]!= slash;n++)
+ EMPTY_LOOP;
+ struct passwd *pw=0;
+ if (n!=1)
+ {
+ GUTF8String user(fname+1, n-1);
+ pw=getpwnam(user);
+ }else if ((senv=GOS::getenv("HOME")).length())
+ {
+ from=(const char *)senv;
+ fname = fname + n;
+ }else if ((senv=GOS::getenv("LOGNAME")).length())
+ {
+ pw = getpwnam((const char *)senv.getUTF82Native());
+ }else
+ {
+ pw=getpwuid(getuid());
+ }
+ if (pw)
+ {
+ senv=GNativeString(pw->pw_dir).getNative2UTF8();
+ from = (const char *)senv;
+ fname = fname + n;
+ }
+ for(;fname[0] == slash; fname++)
+ EMPTY_LOOP;
+ }
+ // Process absolute vs. relative path
+ if (fname && fname[0]== slash)
+ {
+ string_buffer[0]=slash;
+ string_buffer[1]=0;
+ }else if (from)
+ {
+ strcpy(string_buffer, expand_name(from));
+ }else
+ {
+ strcpy(string_buffer, GOS::cwd());
+ }
+ char *s = string_buffer + strlen(string_buffer);
+ if(fname)
+ {
+ for(;fname[0]== slash;fname++)
+ EMPTY_LOOP;
+ // Process path components
+ while(fname[0])
+ {
+ if (fname[0] == dot )
+ {
+ if (!fname[1] || fname[1]== slash)
+ {
+ fname++;
+ continue;
+ }else if (fname[1]== dot && (fname[2]== slash || !fname[2]))
+ {
+ fname +=2;
+ for(;s>string_buffer+1 && *(s-1)== slash; s--)
+ EMPTY_LOOP;
+ for(;s>string_buffer+1 && *(s-1)!= slash; s--)
+ EMPTY_LOOP;
+ continue;
+ }
+ }
+ if ((s==string_buffer)||(*(s-1)!= slash))
+ {
+ *s = slash;
+ s++;
+ }
+ while (*fname &&(*fname!= slash))
+ {
+ *s = *fname++;
+ if ((size_t)((++s)-string_buffer) > maxlen)
+ {
+ G_THROW( ERR_MSG("GURL.big_name") );
+ }
+ }
+ *s = 0;
+ for(;fname[0]== slash;fname++)
+ EMPTY_LOOP;
+ }
+ }
+ if (!fname || !fname[0])
+ {
+ for(;s>string_buffer+1 && *(s-1) == slash; s--)
+ EMPTY_LOOP;
+ *s = 0;
+ }
+#elif defined (WIN32) // WIN32 implementation
+ // Handle base
+ strcpy(string_buffer, (char const *)(from ? expand_name(from) : GOS::cwd()));
+ // GNativeString native;
+ if (fname)
+ {
+ char *s = string_buffer;
+ char drv[4];
+ // Handle absolute part of fname
+ // Put absolute part of the file name in string_buffer, and
+ // the relative part pointed to by fname.
+ if (fname[0]== slash || fname[0]== backslash)
+ {
+ if (fname[1]== slash || fname[1]== backslash)
+ { // Case "//abcd"
+ s[0]=s[1]= backslash; s[2]=0;
+ }
+ else
+ { // Case "/abcd" or "/"
+ // File is at the root of the current drive. Delete the
+ // slash at the beginning of the filename and leave
+ // an explicit identification of the root of the drive in
+ // string_buffer.
+ fname++;
+ s[3] = '\0';
+ }
+ }
+ else if (fname[0] && fname[1]==colon)
+ {
+ if (fname[2]!= slash && fname[2]!= backslash)
+ { // Case "x:abcd"
+ if ( toupper((unsigned char)s[0]) != toupper((unsigned char)fname[0])
+ || s[1]!=colon)
+ {
+ drv[0]=fname[0];
+ drv[1]=colon;
+ drv[2]= dot ;
+ drv[3]=0;
+ GetFullPathName(drv, maxlen, string_buffer, &s);
+ strcpy(string_buffer,(const char *)GUTF8String(string_buffer).getNative2UTF8());
+ s = string_buffer;
+ }
+ fname += 2;
+ }
+ else if (fname[3]!= slash && fname[3]!= backslash)
+ { // Case "x:/abcd"
+ s[0]=toupper((unsigned char)fname[0]);
+ s[1]=colon;
+ s[2]=backslash;
+ s[3]=0;
+ fname += 3;
+ }
+ else
+ { // Case "x://abcd"
+ s[0]=s[1]=backslash;
+ s[2]=0;
+ fname += 4;
+ }
+ }
+ // Process path components
+ for(;*fname== slash || *fname==backslash;fname++)
+ EMPTY_LOOP;
+ while(*fname)
+ {
+ if (fname[0]== dot )
+ {
+ if (fname[1]== slash || fname[1]==backslash || !fname[1])
+ {
+ fname++;
+ continue;
+ }else if ((fname[1] == dot)
+ && (fname[2]== slash || fname[2]==backslash || !fname[2]))
+ {
+ fname += 2;
+ char *back=_tcsrchr(string_buffer,backslash);
+ char *forward=_tcsrchr(string_buffer,slash);
+ if(back>forward)
+ {
+ *back=0;
+ }else if(forward)
+ {
+ *forward=0;
+ }
+ s = string_buffer;
+ continue;
+ }
+ char* s2=s;//MBCS DBCS
+ for(;*s;s++)
+ EMPTY_LOOP;
+ char* back = _tcsrchr(s2,backslash);//MBCS DBCS
+ if ((s>string_buffer)&&(*(s-1)!= slash)&&
+ (back == NULL || (back!=NULL && s-1 != back) ))//MBCS DBCS
+ {
+ *s = backslash;
+ s++;
+ }
+ while (*fname && *fname!= slash && *fname!=backslash)
+ {
+ *s = *fname++;
+ if ((size_t)((++s)-string_buffer) > maxlen)
+ G_THROW( ERR_MSG("GURL.big_name") );
+ }
+ *s = 0;
+ }
+ char* s2=s;//MBCS DBCS
+ for(;*s;s++)
+ EMPTY_LOOP;
+ char* back = _tcsrchr(s2,backslash);//MBCS DBCS
+ if ((s>string_buffer)&&(*(s-1)!= slash)
+ &&(back == NULL || (back!=NULL && s-1 != back) ))//MBCS DBCS
+ {
+ *s = backslash;
+ s++;
+ }
+ while (*fname && (*fname!= slash) && (*fname!=backslash))
+ {
+ *s = *fname++;
+ if ((size_t)((++s)-string_buffer) > maxlen)
+ G_THROW( ERR_MSG("GURL.big_name") );
+ }
+ *s = 0;
+ for(;(*fname== slash)||(*fname==backslash);fname++)
+ EMPTY_LOOP;
+ }
+ }
+#elif defined(macintosh) // MACINTOSH implementation
+ strcpy(string_buffer, (const char *)(from?from:GOS::cwd()));
+
+ if (!GStringRep::cmp(fname, string_buffer,strlen(string_buffer)) || is_file(fname))
+ {
+ strcpy(string_buffer, "");//please don't expand, the logic of filename is chaos.
+ }
+
+ // Process path components
+ char *s = string_buffer + strlen(string_buffer);
+ if(fname)
+ {
+ for(;fname[0]==colon;fname++)
+ EMPTY_LOOP;
+ while(fname[0])
+ {
+ if (fname[0]== dot )
+ {
+ if (fname[1]==colon || !fname[1])
+ {
+ fname++;
+ continue;
+ }
+ if ((fname[1]== dot )
+ &&(fname[2]==colon || fname[2]==0))
+ {
+ fname +=2;
+ for(;(s>string_buffer+1)&&(*(s-1)==colon);s--)
+ EMPTY_LOOP;
+ for(;(s>string_buffer+1)&&(*(s-1)!=colon);s--)
+ EMPTY_LOOP;
+ continue;
+ }
+ }
+ if ((s==string_buffer)||(*(s-1)!=colon))
+ {
+ *s = colon;
+ s++;
+ }
+ while (*fname!=0 && *fname!=colon)
+ {
+ *s = *fname++;
+ if ((++s)-string_buffer > maxlen)
+ G_THROW( ERR_MSG("GURL.big_name") );
+ }
+ *s = 0;
+ for(;fname[0]==colon;fname++)
+ EMPTY_LOOP;
+ }
+ }
+ for(;(s>string_buffer+1) && (*(s-1)==colon);s--)
+ EMPTY_LOOP;
+ *s = 0;
+ return ((string_buffer[0]==colon)?(string_buffer+1):string_buffer);
+#else
+# error "Define something here for your operating system"
+#endif
+ return retval;
+}
+
+unsigned int
+hash(const GURL & gurl)
+{
+ unsigned int retval;
+ const GUTF8String s(gurl.get_string());
+ const int len=s.length();
+ if(len && (s[len-1] == '/')) // Don't include the trailing slash as part of the hash.
+ {
+ retval=hash(s.substr(0,len-1));
+ }else
+ {
+ retval=hash(s);
+ }
+ return retval;
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/GURL.h b/kviewshell/plugins/djvu/libdjvu/GURL.h
new file mode 100644
index 00000000..eb3ed4bc
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GURL.h
@@ -0,0 +1,446 @@
+//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: GURL.h,v 1.9 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _GURL_H_
+#define _GURL_H_
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+#include "GString.h"
+#include "Arrays.h"
+#include "GThreads.h"
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+/** @name GURL.h
+ Files #"GURL.h"# and #"GURL.cpp"# contain the implementation of the
+ \Ref{GURL} class used to store URLs in a system independent format.
+ @memo System independent URL representation.
+ @author Andrei Erofeev <eaf@geocities.com>
+
+// From: Leon Bottou, 1/31/2002
+// This has been heavily changed by Lizardtech.
+// They decided to use URLs for everyting, including
+// the most basic file access. The URL class now is a unholy
+// mixture of code for syntactically parsing the urls (which is was)
+// and file status code (only for local file: urls).
+
+ @version #$Id: GURL.h,v 1.9 2003/11/07 22:08:21 leonb Exp $#
+*/
+
+//@{
+
+/** System independent URL representation.
+
+ This class is used in the library to store URLs in a system independent
+ format. The idea to use a general class to hold URL arose after we
+ realized, that DjVu had to be able to access files both from the WEB
+ and from the local disk. While it is strange to talk about system
+ independence of HTTP URLs, file names formats obviously differ from
+ platform to platform. They may contain forward slashes, backward slashes,
+ colons as separators, etc. There maybe more than one URL corresponding
+ to the same file name. Compare #file:/dir/file.djvu# and
+ #file://localhost/dir/file.djvu#.
+
+ To simplify a developer's life we have created this class, which contains
+ inside a canonical representation of URLs.
+
+ File URLs are converted to internal format with the help of \Ref{GOS} class.
+
+ All other URLs are modified to contain only forward slashes.
+*/
+
+class GURL
+{
+public:
+ class Filename;
+ class UTF8;
+ class Native;
+protected:
+ /** @name Constructors
+ Accept the string URL, check that it starts from #file:/#
+ or #http:/# and convert to internal system independent
+ representation.
+ */
+ //@{
+ ///
+ GURL(const char * url_string);
+ //@}
+
+public:
+ GURL(void);
+
+ GURL(const GUTF8String & url_string);
+
+ GURL(const GNativeString & url_string);
+
+ GURL(const GUTF8String &xurl, const GURL &codebase);
+
+ GURL(const GNativeString &xurl, const GURL &codebase);
+
+ /// Copy constructor
+ GURL(const GURL & gurl);
+
+ /// The destructor
+ virtual ~GURL(void) {}
+
+private:
+ // The 'class_lock' should be locked whenever you're accessing
+ // url, or cgi_name_arr, or cgi_value_arr.
+ GCriticalSection class_lock;
+protected:
+ GUTF8String url;
+ DArray<GUTF8String> cgi_name_arr, cgi_value_arr;
+ bool validurl;
+
+ void init(const bool nothrow=false);
+ void convert_slashes(void);
+ void beautify_path(void);
+ static GUTF8String beautify_path(GUTF8String url);
+
+ static GUTF8String protocol(const GUTF8String& url);
+ void parse_cgi_args(void);
+ void store_cgi_args(void);
+public:
+ /// Test if the URL is valid. If invalid, reinitialize.
+ bool is_valid(void) const; // const lies to the compiler because of dependency problems
+
+ /// Extracts the {\em protocol} part from the URL and returns it
+ GUTF8String protocol(void) const;
+
+ /** Returns string after the first '\#' with decoded
+ escape sequences. */
+ GUTF8String hash_argument(void) const;
+
+ /** Inserts the #arg# after a separating hash into the URL.
+ The function encodes any illegal character in #arg# using
+ \Ref{GOS::encode_reserved}(). */
+ void set_hash_argument(const GUTF8String &arg);
+
+ /** Returns the total number of CGI arguments in the URL.
+ CGI arguments follow '#?#' sign and are separated by '#&#' signs */
+ int cgi_arguments(void) const;
+
+ /** Returns the total number of DjVu-related CGI arguments (arguments
+ following #DJVUOPTS# in the URL). */
+ int djvu_cgi_arguments(void) const;
+
+ /** Returns that part of CGI argument number #num#, which is
+ before the equal sign. */
+ GUTF8String cgi_name(int num) const;
+
+ /** Returns that part of DjVu-related CGI argument number #num#,
+ which is before the equal sign. */
+ GUTF8String djvu_cgi_name(int num) const;
+
+ /** Returns that part of CGI argument number #num#, which is
+ after the equal sign. */
+ GUTF8String cgi_value(int num) const;
+
+ /** Returns that part of DjVu-related CGI argument number #num#,
+ which is after the equal sign. */
+ GUTF8String djvu_cgi_value(int num) const;
+
+ /** Returns array of all known CGI names (part of CGI argument before
+ the equal sign) */
+ DArray<GUTF8String>cgi_names(void) const;
+
+ /** Returns array of names of DjVu-related CGI arguments (arguments
+ following #DJVUOPTS# option. */
+ DArray<GUTF8String>djvu_cgi_names(void) const;
+
+ /** Returns array of all known CGI names (part of CGI argument before
+ the equal sign) */
+ DArray<GUTF8String>cgi_values(void) const;
+
+ /** Returns array of values of DjVu-related CGI arguments (arguments
+ following #DJVUOPTS# option. */
+ DArray<GUTF8String>djvu_cgi_values(void) const;
+
+ /// Erases everything after the first '\#' or '?'
+ void clear_all_arguments(void);
+
+ /// Erases everything after the first '\#'
+ void clear_hash_argument(void);
+
+ /// Erases DjVu CGI arguments (following "#DJVUOPTS#")
+ void clear_djvu_cgi_arguments(void);
+
+ /// Erases all CGI arguments (following the first '?')
+ void clear_cgi_arguments(void);
+
+ /** Appends the specified CGI argument. Will insert "#DJVUOPTS#" if
+ necessary */
+ void add_djvu_cgi_argument(const GUTF8String &name, const char * value=0);
+
+ /** Returns the URL corresponding to the directory containing
+ the document with this URL. The function basically takes the
+ URL and clears everything after the last slash. */
+ GURL base(void) const;
+
+ /// Returns the aboslute URL without the host part.
+ GUTF8String pathname(void) const;
+
+ /** Returns the name part of this URL.
+ For example, if the URL is #http://www.lizardtech.com/file%201.djvu# then
+ this function will return #file%201.djvu#. \Ref{fname}() will
+ return #file 1.djvu# at the same time. */
+ GUTF8String name(void) const;
+
+ /** Returns the name part of this URL with escape sequences expanded.
+ For example, if the URL is #http://www.lizardtech.com/file%201.djvu# then
+ this function will return #file 1.djvu#. \Ref{name}() will
+ return #file%201.djvu# at the same time. */
+ GUTF8String fname(void) const;
+
+ /// Returns the extention part of name of document in this URL.
+ GUTF8String extension(void) const;
+
+ /// Checks if this is an empty URL
+ bool is_empty(void) const;
+
+ /// Checks if the URL is local (starts from #file:/#) or not
+ bool is_local_file_url(void) const;
+
+ /** @name Concatenation operators
+ Concatenate the GURL with the passed {\em name}. If the {\em name}
+ is absolute (has non empty protocol prefix), we just return
+ #GURL(name)#. Otherwise the #name# is appended to the GURL after a
+ separating slash.
+ */
+ //@{
+ ///
+// GURL operator+(const GUTF8String &name) const;
+ //@}
+
+ /// Returns TRUE if #gurl1# and #gurl2# are the same
+ bool operator==(const GURL & gurl2) const;
+
+ /// Returns TRUE if #gurl1# and #gurl2# are different
+ bool operator!=(const GURL & gurl2) const;
+
+ /// Assignment operator
+ GURL & operator=(const GURL & url);
+
+ /// Returns Internal URL representation
+ operator const char*(void) const { return url; };
+
+ /** Returns a string representing the URL. This function normally
+ returns a standard file URL as described in RFC 1738.
+ Some versions of MSIE do not support this standard syntax.
+ A brain damaged MSIE compatible syntax is generated
+ when the optional argument #useragent# contains string #"MSIE"# or
+ #"Microsoft"#. */
+ GUTF8String get_string(const GUTF8String &useragent) const;
+
+ GUTF8String get_string(const bool nothrow=false) const;
+
+ /// Escape special characters
+ static GUTF8String encode_reserved(const GUTF8String &gs);
+
+ /** Decodes reserved characters from the URL.
+ See also: \Ref{encode_reserved}(). */
+ static GUTF8String decode_reserved(const GUTF8String &url);
+
+ /// Test if this url is an existing file, directory, or device.
+ bool is_local_path(void) const;
+
+ /// Test if this url is an existing file.
+ bool is_file(void) const;
+
+ /// Test if this url is an existing directory.
+ bool is_dir(void) const;
+
+ /// Follows symbolic links.
+ GURL follow_symlinks(void) const;
+
+ /// Creates the specified directory.
+ int mkdir(void) const;
+
+ /** Deletes file or directory.
+ Directories are not deleted unless the directory is empty.
+ Returns a negative number if an error occurs. */
+ int deletefile(void) const;
+
+ /** Recursively erases contents of directory. The directory
+ itself will not be removed. */
+ int cleardir(const int timeout=0) const;
+
+ /// Rename a file or directory.
+ int renameto(const GURL &newurl) const;
+
+ /// List the contents of a directory.
+ GList<GURL> listdir(void) const;
+
+ /** Returns a filename for a URL. Argument #url# must be a legal file URL.
+ This function applies heuristic rules to convert the URL into a valid
+ file name. It is guaranteed that this function can properly parse all
+ URLs generated by #filename_to_url#. The heuristics also work better when
+ the file actually exists. The empty string is returned when this
+ function cannot parse the URL or when the URL is not a file URL.
+ URL formats are as described in RFC 1738 plus the following alternative
+ formats for files on the local host:
+
+ file://<letter>:/<path>
+ file://<letter>|/<path>
+ file:/<path>
+
+ which are accepted because various browsers recognize them.*/
+ GUTF8String UTF8Filename(void) const;
+ /// Same but returns a native string.
+ GNativeString NativeFilename(void) const;
+
+ /** Hashing function.
+ @return hash suitable for usage in \Ref{GMap} */
+ friend unsigned int hash(const GURL & gurl);
+
+ /** Returns fully qualified file names. This functions constructs the fully
+ qualified name of file or directory #filename#. When provided, the
+ optional argument #fromdirname# is used as the current directory when
+ interpreting relative specifications in #filename#. Function
+ #expand_name# is very useful for logically concatenating file names. It
+ knows which separators should be used for each operating system and it
+ knows which syntactical rules apply. */
+ static GUTF8String expand_name(const GUTF8String &filename, const char *fromdirname=0);
+};
+
+class GURL::UTF8 : public GURL
+{
+public:
+ UTF8(const GUTF8String &xurl);
+ UTF8(const GUTF8String &xurl, const GURL &codebase);
+};
+
+class GURL::Native : public GURL
+{
+public:
+ Native(const GNativeString &xurl);
+ Native(const GNativeString &xurl, const GURL &codebase);
+};
+
+class GURL::Filename : public GURL
+{
+public:
+ Filename(const GUTF8String &filename);
+ Filename(const GNativeString &filename);
+ class UTF8;
+ class Native;
+};
+
+class GURL::Filename::UTF8 : public GURL::Filename
+{
+public:
+ UTF8(const GUTF8String &filename);
+};
+
+class GURL::Filename::Native : public GURL::Filename
+{
+public:
+ Native(const GNativeString &filename);
+};
+
+
+inline bool
+GURL::operator!=(const GURL & gurl2) const
+{
+ return !(*this == gurl2);
+}
+
+inline GUTF8String
+GURL::protocol(void) const
+{
+ return protocol(get_string());
+}
+
+inline bool
+GURL::is_empty(void) const
+{
+ return !url.length()||!get_string().length();
+}
+
+// Test if the URL is valid.
+// If invalid, reinitialize and return the result.
+inline bool
+GURL::is_valid(void) const
+{
+ if(!validurl)
+ const_cast<GURL *>(this)->init(true);
+ return validurl;
+}
+
+
+
+//@}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/GUnicode.cpp b/kviewshell/plugins/djvu/libdjvu/GUnicode.cpp
new file mode 100644
index 00000000..dbbefc5c
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/GUnicode.cpp
@@ -0,0 +1,790 @@
+//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: GUnicode.cpp,v 1.11 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "GString.h"
+#if HAS_ICONV
+#include <iconv.h>
+#endif
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+static unsigned char nill=0;
+
+static void const *
+checkmarks(void const * const xbuf,
+ unsigned int &bufsize,
+ GStringRep::EncodeType &rep)
+{
+ unsigned char const *buf=(unsigned char const *)xbuf;
+ if(bufsize >= 2 || (xbuf && !bufsize && rep != GStringRep::XOTHER))
+ {
+ const unsigned int s=(((unsigned int)buf[0])<<8)+(unsigned int)buf[1];
+ switch(s)
+ {
+ case 0:
+ if((bufsize>=4)||(!bufsize && rep == GStringRep::XUCS4BE)
+ ||(!bufsize && rep == GStringRep::XUCS4_2143))
+ {
+ const unsigned int s=(((unsigned int)buf[2])<<8)+(unsigned int)buf[3];
+ if(s == 0xfeff)
+ {
+ rep=GStringRep::XUCS4BE;
+ buf+=4;
+ }else if(s == 0xfffe)
+ {
+ rep=GStringRep::XUCS4_2143;
+ buf+=4;
+ }
+ }
+ break;
+ case 0xfffe:
+ if(((bufsize>=4)||(!bufsize && rep == GStringRep::XUCS4LE))
+ && !((unsigned char *)buf)[2] && !((unsigned char *)buf)[3])
+ {
+ rep=GStringRep::XUCS4LE;
+ buf+=4;
+ }else
+ {
+ rep=GStringRep::XUTF16LE;
+ buf+=2;
+ }
+ break;
+ case 0xfeff:
+ if(((bufsize>=4)||(!bufsize && rep == GStringRep::XUCS4_3412))
+ && !((unsigned char *)buf)[2] && !((unsigned char *)buf)[3])
+ {
+ rep=GStringRep::XUCS4_3412;
+ buf+=4;
+ }else
+ {
+ rep=GStringRep::XUTF16LE;
+ buf+=2;
+ }
+ break;
+ case 0xefbb:
+ if(((bufsize>=3)||(!bufsize && GStringRep::XUTF8 == rep))&&(buf[2] == 0xbf))
+ {
+ rep=GStringRep::XUTF8;
+ buf+=3;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if(buf != xbuf)
+ {
+ if(bufsize)
+ {
+ const size_t s=(size_t)xbuf-(size_t)buf;
+ if(bufsize> s)
+ {
+ bufsize-=s;
+ }else
+ {
+ bufsize=0;
+ buf=(const unsigned char *)&nill;
+ }
+ }
+ }
+ return buf;
+}
+
+class GStringRep::Unicode : public GStringRep::UTF8
+{
+public:
+ GP<GStringRep> encoding;
+ EncodeType encodetype;
+ void *remainder;
+ GPBufferBase gremainder;
+public:
+ Unicode(void);
+ /// virtual destructor.
+ virtual ~Unicode();
+
+ static GP<GStringRep> create(const unsigned int sz);
+ static GP<GStringRep> create(void const * const buf, unsigned int bufsize,
+ const EncodeType, const GP<GStringRep> &encoding);
+ static GP<GStringRep> create( void const * const buf,
+ unsigned int size, const EncodeType encodetype );
+ static GP<GStringRep> create( void const * const buf,
+ const unsigned int size, GP<GStringRep> encoding );
+ static GP<GStringRep> create( void const * const buf,
+ const unsigned int size, const GP<Unicode> &remainder );
+
+protected:
+ virtual void set_remainder( void const * const buf, const unsigned int size,
+ const EncodeType encodetype );
+ virtual void set_remainder( void const * const buf, const unsigned int size,
+ const GP<GStringRep> &encoding );
+ virtual void set_remainder( const GP<Unicode> &remainder );
+ virtual GP<Unicode> get_remainder(void) const;
+};
+// static unsigned long UTF8toUCS4(unsigned char const *&,void const * const);
+static unsigned long xUTF16toUCS4(unsigned short const *&s,void const * const);
+static unsigned long UTF16BEtoUCS4(unsigned char const *&s,void const * const);
+static unsigned long UTF16LEtoUCS4(unsigned char const *&s,void const * const);
+static unsigned long UCS4BEtoUCS4(unsigned char const *&s,void const * const);
+static unsigned long UCS4LEtoUCS4(unsigned char const *&s,void const * const);
+static unsigned long UCS4_3412toUCS4(unsigned char const *&s,void const * const);
+static unsigned long UCS4_2143toUCS4(unsigned char const *&s,void const * const);
+
+GP<GStringRep>
+GStringRep::Unicode::create(const unsigned int sz)
+{
+ GP<GStringRep> gaddr;
+ if (sz > 0)
+ {
+ GStringRep *addr;
+ gaddr=(addr=new GStringRep::Unicode);
+ addr->data=(char *)(::operator new(sz+1));
+ addr->size = sz;
+ addr->data[sz] = 0;
+ }
+ return gaddr;
+}
+
+GStringRep::Unicode::Unicode(void)
+: encodetype(XUTF8), gremainder(remainder,0,1) {}
+
+GStringRep::Unicode::~Unicode() {}
+
+GP<GStringRep>
+GStringRep::Unicode::create(
+ void const * const xbuf,
+ unsigned int bufsize,
+ const EncodeType t,
+ const GP<GStringRep> &encoding)
+{
+ return (encoding->size)
+ ?create(xbuf,bufsize,encoding)
+ :create(xbuf,bufsize,t);
+}
+
+GP<GStringRep>
+GStringRep::Unicode::create(
+ void const * const xbuf,
+ const unsigned int bufsize,
+ const GP<Unicode> &xremainder )
+{
+ Unicode *r=xremainder;
+ GP<GStringRep> retval;
+ if(r)
+ {
+ const int s=r->gremainder;
+ if(xbuf && bufsize)
+ {
+ if(s)
+ {
+ void *buf;
+ GPBufferBase gbuf(buf,s+bufsize,1);
+ memcpy(buf,r->remainder,s);
+ memcpy((void *)((size_t)buf+s),xbuf,bufsize);
+ retval=((r->encoding)
+ ?create(buf,s+bufsize,r->encoding)
+ :create(buf,s+bufsize,r->encodetype));
+ }else
+ {
+ retval=((r->encoding)
+ ?create(xbuf,bufsize,r->encoding)
+ :create(xbuf,bufsize,r->encodetype));
+ }
+ }else if(s)
+ {
+ void *buf;
+ GPBufferBase gbuf(buf,s,1);
+ memcpy(buf,r->remainder,s);
+ retval=((r->encoding)
+ ?create(buf,s,r->encoding)
+ :create(buf,s,r->encodetype));
+ }else
+ {
+ retval=((r->encoding)
+ ?create(0,0,r->encoding)
+ :create(0,0,r->encodetype));
+ }
+ }else
+ {
+ retval=create(xbuf,bufsize,XUTF8);
+ }
+ return retval;
+}
+
+#if HAS_ICONV
+/* This template works around incompatible iconv protoypes */
+template<typename _T> inline size_t
+iconv_adaptor(size_t(*iconv_func)(iconv_t, _T, size_t *, char**, size_t*),
+ iconv_t cd, char **inbuf, size_t *inbytesleft,
+ char **outbuf, size_t *outbytesleft)
+{
+ return iconv_func (cd, (_T)inbuf, inbytesleft, outbuf, outbytesleft);
+}
+#endif
+
+GP<GStringRep>
+GStringRep::Unicode::create(
+ void const * const xbuf,
+ unsigned int bufsize,
+ GP<GStringRep> encoding)
+{
+ GP<GStringRep> retval;
+ GStringRep *e=encoding;
+ if(e)
+ {
+ e=(encoding=e->upcase());
+ }
+ if(!e || !e->size)
+ {
+ retval=create(xbuf,bufsize,XOTHER);
+ }else if(!e->cmp("UTF8") || !e->cmp("UTF-8"))
+ {
+ retval=create(xbuf,bufsize,XUTF8);
+ }else if(!e->cmp("UTF16")|| !e->cmp("UTF-16")
+ || !e->cmp("UCS2") || !e->cmp("UCS2"))
+ {
+ retval=create(xbuf,bufsize,XUTF16);
+ }else if(!e->cmp("UCS4") || !e->cmp("UCS-4"))
+ {
+ retval=create(xbuf,bufsize,XUCS4);
+ }else
+ {
+#if HAS_ICONV
+ EncodeType t=XOTHER;
+ void const * const buf=checkmarks(xbuf,bufsize,t);
+ if(t != XOTHER)
+ {
+ retval=create(xbuf,bufsize,t);
+ }else if(buf && bufsize)
+ {
+ unsigned char const *eptr=(unsigned char *)buf;
+ unsigned int j=0;
+ for(j=0;(j<bufsize)&&*eptr;j++,eptr++)
+ EMPTY_LOOP;
+ if (j)
+ {
+ unsigned char const *ptr=(unsigned char *)buf;
+ if(e)
+ {
+ iconv_t cv=iconv_open("UTF-8",(const char *)e);
+ if(cv == (iconv_t)(-1))
+ {
+ const int i=e->search('-');
+ if(i>=0)
+ {
+ cv=iconv_open("UTF-8",e->data+i+1);
+ }
+ }
+ if(cv == (iconv_t)(-1))
+ {
+ retval=create(0,0,XOTHER);
+ }else
+ {
+ size_t ptrleft=(eptr-ptr);
+ char *utf8buf;
+ size_t pleft=6*ptrleft+1;
+ GPBuffer<char> gutf8buf(utf8buf,pleft);
+ char *p=utf8buf;
+ unsigned char const *last=ptr;
+ for(;iconv_adaptor(iconv, cv, (char**)&ptr, &ptrleft, &p, &pleft);last=ptr)
+ EMPTY_LOOP;
+ iconv_close(cv);
+ retval=create(utf8buf,(size_t)last-(size_t)buf,t);
+ retval->set_remainder(last,(size_t)eptr-(size_t)last,e);
+ }
+ }
+ }else
+ {
+ retval=create(0,0,XOTHER);
+ retval->set_remainder(0,0,e);
+ }
+ }
+#else
+ retval=create(xbuf,bufsize,XOTHER);
+#endif
+ }
+ return retval;
+}
+
+GP<GStringRep>
+GStringRep::Unicode::create(
+ void const * const xbuf,
+ unsigned int bufsize,
+ EncodeType t)
+{
+ GP<GStringRep> gretval;
+ GStringRep *retval=0;
+ void const * const buf=checkmarks(xbuf,bufsize,t);
+ if(buf && bufsize)
+ {
+ unsigned char const *eptr=(unsigned char *)buf;
+ unsigned int maxutf8size=0;
+ void const* const xeptr=(void const *)((size_t)eptr+bufsize);
+ switch(t)
+ {
+ case XUCS4:
+ case XUCS4BE:
+ case XUCS4LE:
+ case XUCS4_2143:
+ case XUCS4_3412:
+ {
+ for(unsigned long w;
+ (eptr<xeptr)&&(w=*(unsigned long const *)eptr);
+ eptr+=sizeof(unsigned long))
+ {
+ maxutf8size+=(w>0x7f)?6:1;
+ }
+ break;
+ }
+ case XUTF16:
+ case XUTF16BE:
+ case XUTF16LE:
+ {
+ for(unsigned short w;
+ (eptr<xeptr)&&(w=*(unsigned short const *)eptr);
+ eptr+=sizeof(unsigned short))
+ {
+ maxutf8size+=3;
+ }
+ break;
+ }
+ case XUTF8:
+ for(;(eptr<xeptr)&&*eptr;maxutf8size++,eptr++)
+ EMPTY_LOOP;
+ break;
+ case XEBCDIC:
+ for(;(eptr<xeptr)&&*eptr;eptr++)
+ {
+ maxutf8size+=(*eptr>0x7f)?2:1;
+ }
+ break;
+ default:
+ break;
+ }
+ unsigned char *utf8buf=0;
+ GPBuffer<unsigned char> gutf8buf(utf8buf,maxutf8size+1);
+ utf8buf[0]=0;
+ if (maxutf8size)
+ {
+ unsigned char *optr=utf8buf;
+ int len=0;
+ unsigned char const *iptr=(unsigned char *)buf;
+ unsigned long w;
+ switch(t)
+ {
+ case XUCS4:
+ for(;
+ (iptr<eptr)&&(w=*(unsigned long const *)iptr);
+ len++,iptr+=sizeof(unsigned long const))
+ {
+ optr=UCS4toUTF8(w,optr);
+ }
+ break;
+ case XUCS4BE:
+ for(;(w=UCS4BEtoUCS4(iptr,eptr));len++)
+ {
+ optr=UCS4toUTF8(w,optr);
+ }
+ break;
+ case XUCS4LE:
+ for(;(w=UCS4LEtoUCS4(iptr,eptr));len++)
+ {
+ optr=UCS4toUTF8(w,optr);
+ }
+ break;
+ case XUCS4_2143:
+ for(;(w=UCS4_2143toUCS4(iptr,eptr));len++)
+ {
+ optr=UCS4toUTF8(w,optr);
+ }
+ break;
+ case XUCS4_3412:
+ for(;(w=UCS4_3412toUCS4(iptr,eptr));len++)
+ {
+ optr=UCS4toUTF8(w,optr);
+ }
+ break;
+ case XUTF16:
+ for(;
+ (w=xUTF16toUCS4((unsigned short const*&)iptr,eptr));
+ len++)
+ {
+ optr=UCS4toUTF8(w,optr);
+ }
+ break;
+ case XUTF16BE:
+ for(;(w=UTF16BEtoUCS4(iptr,eptr));len++)
+ {
+ optr=UCS4toUTF8(w,optr);
+ }
+ break;
+ case XUTF16LE:
+ for(;(w=UTF16LEtoUCS4(iptr,eptr));len++)
+ {
+ optr=UCS4toUTF8(w,optr);
+ }
+ break;
+ case XUTF8:
+ for(;(w=UTF8toUCS4(iptr,eptr));len++)
+ {
+ optr=UCS4toUTF8(w,optr);
+ }
+ break;
+ case XEBCDIC:
+ for(;(iptr<eptr)&&(w=*iptr++);len++)
+ {
+ optr=UCS4toUTF8(w,optr);
+ }
+ break;
+ default:
+ break;
+ }
+ const unsigned int size=(size_t)optr-(size_t)utf8buf;
+ if(size)
+ {
+ retval=(gretval=GStringRep::Unicode::create(size));
+ memcpy(retval->data,utf8buf,size);
+ }else
+ {
+ retval=(gretval=GStringRep::Unicode::create(1));
+ retval->size=size;
+ }
+ retval->data[size]=0;
+ gutf8buf.resize(0);
+ const size_t s=(size_t)eptr-(size_t)iptr;
+ retval->set_remainder(iptr,s,t);
+ }
+ }
+ if(!retval)
+ {
+ retval=(gretval=GStringRep::Unicode::create(1));
+ retval->data[0]=0;
+ retval->size=0;
+ retval->set_remainder(0,0,t);
+ }
+ return gretval;
+}
+
+static unsigned long
+xUTF16toUCS4(unsigned short const *&s,void const * const eptr)
+{
+ unsigned long U=0;
+ unsigned short const * const r=s+1;
+ if(r <= eptr)
+ {
+ unsigned long const W1=s[0];
+ if((W1<0xD800)||(W1>0xDFFF))
+ {
+ if((U=W1))
+ {
+ s=r;
+ }
+ }else if(W1<=0xDBFF)
+ {
+ unsigned short const * const rr=r+1;
+ if(rr <= eptr)
+ {
+ unsigned long const W2=s[1];
+ if(((W2>=0xDC00)||(W2<=0xDFFF))&&((U=(0x1000+((W1&0x3ff)<<10))|(W2&0x3ff))))
+ {
+ s=rr;
+ }else
+ {
+ U=(unsigned int)(-1)-W1;
+ s=r;
+ }
+ }
+ }
+ }
+ return U;
+}
+
+static unsigned long
+UTF16BEtoUCS4(unsigned char const *&s,void const * const eptr)
+{
+ unsigned long U=0;
+ unsigned char const * const r=s+2;
+ if(r <= eptr)
+ {
+ unsigned long const C1MSB=s[0];
+ if((C1MSB<0xD8)||(C1MSB>0xDF))
+ {
+ if((U=((C1MSB<<8)|((unsigned long)s[1]))))
+ {
+ s=r;
+ }
+ }else if(C1MSB<=0xDB)
+ {
+ unsigned char const * const rr=r+2;
+ if(rr <= eptr)
+ {
+ unsigned long const C2MSB=s[2];
+ if((C2MSB>=0xDC)||(C2MSB<=0xDF))
+ {
+ U=0x10000+((unsigned long)s[1]<<10)+(unsigned long)s[3]
+ +(((C1MSB<<18)|(C2MSB<<8))&0xc0300);
+ s=rr;
+ }else
+ {
+ U=(unsigned int)(-1)-((C1MSB<<8)|((unsigned long)s[1]));
+ s=r;
+ }
+ }
+ }
+ }
+ return U;
+}
+
+static unsigned long
+UTF16LEtoUCS4(unsigned char const *&s,void const * const eptr)
+{
+ unsigned long U=0;
+ unsigned char const * const r=s+2;
+ if(r <= eptr)
+ {
+ unsigned long const C1MSB=s[1];
+ if((C1MSB<0xD8)||(C1MSB>0xDF))
+ {
+ if((U=((C1MSB<<8)|((unsigned long)s[0]))))
+ {
+ s=r;
+ }
+ }else if(C1MSB<=0xDB)
+ {
+ unsigned char const * const rr=r+2;
+ if(rr <= eptr)
+ {
+ unsigned long const C2MSB=s[3];
+ if((C2MSB>=0xDC)||(C2MSB<=0xDF))
+ {
+ U=0x10000+((unsigned long)s[0]<<10)+(unsigned long)s[2]
+ +(((C1MSB<<18)|(C2MSB<<8))&0xc0300);
+ s=rr;
+ }else
+ {
+ U=(unsigned int)(-1)-((C1MSB<<8)|((unsigned long)s[1]));
+ s=r;
+ }
+ }
+ }
+ }
+ return U;
+}
+
+static unsigned long
+UCS4BEtoUCS4(unsigned char const *&s,void const * const eptr)
+{
+ unsigned long U=0;
+ unsigned char const * const r=s+4;
+ if(r<=eptr)
+ {
+ U=(((((((unsigned long)s[0]<<8)|(unsigned long)s[1])<<8)|(unsigned long)s[2])<<8)|(unsigned long)s[3]);
+ if(U)
+ {
+ s=r;
+ }
+ }
+ return U;
+}
+
+static unsigned long
+UCS4LEtoUCS4(unsigned char const *&s,void const * const eptr)
+{
+ unsigned long U=0;
+ unsigned char const * const r=s+4;
+ if(r<=eptr)
+ {
+ U=(((((((unsigned long)s[3]<<8)|(unsigned long)s[2])<<8)|(unsigned long)s[1])<<8)|(unsigned long)s[0]);
+ if(U)
+ {
+ s=r;
+ }
+ }
+ return U;
+}
+
+static unsigned long
+UCS4_2143toUCS4(unsigned char const *&s,void const * const eptr)
+{
+ unsigned long U=0;
+ unsigned char const * const r=s+4;
+ if(r<=eptr)
+ {
+ U=(((((((unsigned long)s[1]<<8)|(unsigned long)s[0])<<8)|(unsigned long)s[3])<<8)|(unsigned long)s[2]);
+ if(U)
+ {
+ s=r;
+ }
+ }
+ return U;
+}
+
+static unsigned long
+UCS4_3412toUCS4(unsigned char const *&s,void const * const eptr)
+{
+ unsigned long U=0;
+ unsigned char const * const r=s+4;
+ if(r<=eptr)
+ {
+ U=(((((((unsigned long)s[2]<<8)|(unsigned long)s[3])<<8)|(unsigned long)s[0])<<8)|(unsigned long)s[1]);
+ if(U)
+ {
+ s=r;
+ }
+ }
+ return U;
+}
+
+void
+GStringRep::Unicode::set_remainder( void const * const buf,
+ const unsigned int size, const EncodeType xencodetype )
+{
+ gremainder.resize(size,1);
+ if(size)
+ memcpy(remainder,buf,size);
+ encodetype=xencodetype;
+ encoding=0;
+}
+
+void
+GStringRep::Unicode::set_remainder( void const * const buf,
+ const unsigned int size, const GP<GStringRep> &xencoding )
+{
+ gremainder.resize(size,1);
+ if(size)
+ memcpy(remainder,buf,size);
+ encoding=xencoding;
+ encodetype=XOTHER;
+}
+
+void
+GStringRep::Unicode::set_remainder( const GP<GStringRep::Unicode> &xremainder )
+{
+ if(xremainder)
+ {
+ const int size=xremainder->gremainder;
+ gremainder.resize(size,1);
+ if(size)
+ memcpy(remainder,xremainder->remainder,size);
+ encodetype=xremainder->encodetype;
+ }else
+ {
+ gremainder.resize(0,1);
+ encodetype=XUTF8;
+ }
+}
+
+GP<GStringRep::Unicode>
+GStringRep::Unicode::get_remainder( void ) const
+{
+ return const_cast<GStringRep::Unicode *>(this);
+}
+
+GUTF8String
+GUTF8String::create(void const * const buf,const unsigned int size,
+ const EncodeType encodetype, const GUTF8String &encoding)
+{
+ return encoding.length()
+ ?create(buf,size,encodetype)
+ :create(buf,size,encoding);
+}
+
+GUTF8String
+GUTF8String::create( void const * const buf,
+ unsigned int size, const EncodeType encodetype )
+{
+ GUTF8String retval;
+ retval.init(GStringRep::Unicode::create(buf,size,encodetype));
+ return retval;
+}
+
+GUTF8String
+GUTF8String::create( void const * const buf,
+ const unsigned int size, const GP<GStringRep::Unicode> &remainder)
+{
+ GUTF8String retval;
+ retval.init(GStringRep::Unicode::create(buf,size,remainder));
+ return retval;
+}
+
+GUTF8String
+GUTF8String::create( void const * const buf,
+ const unsigned int size, const GUTF8String &encoding )
+{
+ GUTF8String retval;
+ retval.init(GStringRep::Unicode::create(buf,size,encoding ));
+ return retval;
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/IFFByteStream.cpp b/kviewshell/plugins/djvu/libdjvu/IFFByteStream.cpp
new file mode 100644
index 00000000..9bf184bd
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/IFFByteStream.cpp
@@ -0,0 +1,558 @@
+//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: IFFByteStream.cpp,v 1.10 2004/08/06 15:11:29 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+// -- Implementation of IFFByteStream
+// - Author: Leon Bottou, 06/1998
+
+// From: Leon Bottou, 1/31/2002
+// This has been changed by Lizardtech to fit better
+// with their re-implementation of ByteStreams.
+
+#include <assert.h>
+#include "IFFByteStream.h"
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+// Constructor
+IFFByteStream::IFFByteStream(const GP<ByteStream> &xbs,const int xpos)
+: ByteStream::Wrapper(xbs), has_magic(false), ctx(0), dir(0)
+{
+ offset = seekto = xpos;
+}
+
+// Destructor
+IFFByteStream::~IFFByteStream()
+{
+ while (ctx)
+ close_chunk();
+}
+
+GP<IFFByteStream>
+IFFByteStream::create(const GP<ByteStream> &bs)
+{
+ const int pos=bs->tell();
+ return new IFFByteStream(bs,pos);
+}
+
+
+// IFFByteStream::ready
+// -- indicates if bytestream is ready for reading
+// returns number of bytes available
+
+int
+IFFByteStream::ready()
+{
+ if (ctx && dir < 0)
+ return ctx->offEnd - offset;
+ else if (ctx)
+ return 1;
+ else
+ return 0;
+}
+
+
+// IFFByteStream::composite
+// -- indicates if bytestream is ready for putting or getting chunks
+
+int
+IFFByteStream::composite()
+{
+ if (ctx && !ctx->bComposite)
+ return 0;
+ else
+ return 1;
+}
+
+
+
+
+// IFFByteStream::check_id
+// -- checks if an id is legal
+
+int
+IFFByteStream::check_id(const char *id)
+{
+ int i;
+ // check absence of null bytes
+ for (i=0; i<4; i++)
+ if (id[i]<0x20 || id[i]>0x7e)
+ return -1;
+ // check composite chunks
+ static char *szComposite[] = { "FORM", "LIST", "PROP", "CAT ", 0 };
+ for (i=0; szComposite[i]; i++)
+ if (!memcmp(id, szComposite[i], 4))
+ return 1;
+ // check reserved chunks
+ static char *szReserved[] = { "FOR", "LIS", "CAT", 0 };
+ for (i=0; szReserved[i]; i++)
+ if (!memcmp(id, szReserved[i], 3) && id[3]>='1' && id[3]<='9')
+ return -1;
+ // regular chunk
+ return 0;
+}
+
+
+
+// IFFByteStream::get_chunk
+// -- get next chunk header
+
+int
+IFFByteStream::get_chunk(GUTF8String &chkid, int *rawoffsetptr, int *rawsizeptr)
+{
+ int bytes;
+ char buffer[8];
+
+ // Check that we are allowed to read a chunk
+ if (dir > 0)
+ G_THROW( ERR_MSG("IFFByteStream.read_write") );
+ if (ctx && !ctx->bComposite)
+ G_THROW( ERR_MSG("IFFByteStream.not_ready") );
+ dir = -1;
+
+ // Seek to end of previous chunk if necessary
+ if (seekto > offset)
+ {
+ bs->seek(seekto);
+ offset = seekto;
+ }
+
+ // Skip padding byte
+ if (ctx && offset == ctx->offEnd)
+ return 0;
+ if (offset & 1)
+ {
+ bytes = bs->read( (void*)buffer, 1);
+ if (bytes==0 && !ctx)
+ return 0;
+ offset += bytes;
+ }
+
+ // Record raw offset
+ int rawoffset = offset;
+
+ // Read chunk id (skipping magic sequences inserted here to make
+ // DjVu files recognizable.)
+ for(;;)
+ {
+ if (ctx && offset == ctx->offEnd)
+ return 0;
+ if (ctx && offset+4 > ctx->offEnd)
+ G_THROW( ERR_MSG("IFFByteStream.corrupt_end") );
+ bytes = bs->readall( (void*)&buffer[0], 4);
+ offset = seekto = offset + bytes;
+ if (bytes==0 && !ctx)
+ return 0;
+ if (bytes != 4)
+ G_THROW( ByteStream::EndOfFile );
+ if(buffer[0] != 0x41 || buffer[1] != 0x54 ||
+ buffer[2] != 0x26 || buffer[3] != 0x54 )
+ break;
+ has_magic=true;
+ }
+
+ // Read chunk size
+ if (ctx && offset+4 > ctx->offEnd)
+ G_THROW( ERR_MSG("IFFByteStream.corrupt_end2") );
+ bytes = bs->readall( (void*)&buffer[4], 4);
+ offset = seekto = offset + bytes;
+ if (bytes != 4)
+ G_THROW( ByteStream::EndOfFile );
+ long size = ((unsigned char)buffer[4]<<24) |
+ ((unsigned char)buffer[5]<<16) |
+ ((unsigned char)buffer[6]<<8) |
+ ((unsigned char)buffer[7]);
+ if (ctx && offset+size > ctx->offEnd)
+ G_THROW( ERR_MSG("IFFByteStream.corrupt_mangled") );
+
+ // Check if composite
+ int composite = check_id(buffer);
+ if (composite < 0)
+ G_THROW( ERR_MSG("IFFByteStream.corrupt_id") );
+
+ // Read secondary id of composite chunk
+ if (composite)
+ {
+ if (ctx && ctx->offEnd<offset+4)
+ G_THROW( ERR_MSG("IFFByteStream.corrupt_header") );
+ bytes = bs->readall( (void*)&buffer[4], 4);
+ offset += bytes;
+ if (bytes != 4)
+ G_THROW( ByteStream::EndOfFile );
+ if (check_id(&buffer[4]))
+ G_THROW( ERR_MSG("IFFByteStream.corrupt_2nd_id") );
+ }
+
+ // Create context record
+ IFFContext *nctx = new IFFContext;
+ G_TRY
+ {
+ nctx->next = ctx;
+ nctx->offStart = seekto;
+ nctx->offEnd = seekto + size;
+ if (composite)
+ {
+ memcpy( (void*)(nctx->idOne), (void*)&buffer[0], 4);
+ memcpy( (void*)(nctx->idTwo), (void*)&buffer[4], 4);
+ nctx->bComposite = 1;
+ }
+ else
+ {
+ memcpy( (void*)(nctx->idOne), (void*)&buffer[0], 4);
+ memset( (void*)(nctx->idTwo), 0, 4);
+ nctx->bComposite = 0;
+ }
+ }
+ G_CATCH_ALL
+ {
+ delete nctx;
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+
+ // Install context record
+ ctx = nctx;
+ chkid = GUTF8String(ctx->idOne, 4);
+ if (composite)
+ chkid = chkid + ":" + GUTF8String(ctx->idTwo, 4);
+
+ // Return
+ if (rawoffsetptr)
+ *rawoffsetptr = rawoffset;
+ if (rawsizeptr)
+ *rawsizeptr = ( ctx->offEnd - rawoffset + 1) & ~0x1;
+ return size;
+}
+
+
+
+// IFFByteStream::put_chunk
+// -- write new chunk header
+
+void
+IFFByteStream::put_chunk(const char *chkid, int insert_magic)
+{
+ int bytes;
+ char buffer[8];
+
+ // Check that we are allowed to write a chunk
+ if (dir < 0)
+ G_THROW( ERR_MSG("IFFByteStream.read_write") );
+ if (ctx && !ctx->bComposite)
+ G_THROW( ERR_MSG("IFFByteStream.not_ready2") );
+ dir = +1;
+
+ // Check primary id
+ int composite = check_id(chkid);
+ if ((composite<0) || (composite==0 && chkid[4])
+ || (composite && (chkid[4]!=':' || check_id(&chkid[5]) || chkid[9])) )
+ G_THROW( ERR_MSG("IFFByteStream.bad_chunk") );
+
+ // Write padding byte
+ assert(seekto <= offset);
+ memset((void*)buffer, 0, 8);
+ if (offset & 1)
+ offset += bs->write((void*)&buffer[4], 1);
+
+ // Insert magic to make this file recognizable as DjVu
+ if (insert_magic)
+ {
+ // Don't change the way you do the file magic!
+ // I rely on these bytes letters in some places
+ // (like DjVmFile.cpp and djvm.cpp) -- eaf
+ buffer[0]=0x41;
+ buffer[1]=0x54;
+ buffer[2]=0x26;
+ buffer[3]=0x54;
+ offset += bs->writall((void*)&buffer[0], 4);
+ }
+
+ // Write chunk header
+ memcpy((void*)&buffer[0], (void*)&chkid[0], 4);
+ bytes = bs->writall((void*)&buffer[0], 8);
+ offset = seekto = offset + bytes;
+ if (composite)
+ {
+ memcpy((void*)&buffer[4], (void*)&chkid[5], 4);
+ bytes = bs->writall((void*)&buffer[4], 4);
+ offset = offset + bytes;
+ }
+
+ // Create new context record
+ IFFContext *nctx = new IFFContext;
+ G_TRY
+ {
+ nctx->next = ctx;
+ nctx->offStart = seekto;
+ nctx->offEnd = 0;
+ if (composite)
+ {
+ memcpy( (void*)(nctx->idOne), (void*)&buffer[0], 4);
+ memcpy( (void*)(nctx->idTwo), (void*)&buffer[4], 4);
+ nctx->bComposite = 1;
+ }
+ else
+ {
+ memcpy( (void*)(nctx->idOne), (void*)&buffer[0], 4);
+ memset( (void*)(nctx->idTwo), 0, 4);
+ nctx->bComposite = 0;
+ }
+ }
+ G_CATCH_ALL
+ {
+ delete nctx;
+ G_RETHROW;
+ }
+ G_ENDCATCH;
+ // Install context record and leave
+ ctx = nctx;
+}
+
+
+
+void
+IFFByteStream::close_chunk()
+{
+ // Check that this is ok
+ if (!ctx)
+ G_THROW( ERR_MSG("IFFByteStream.cant_close") );
+ // Patch size field in new chunk
+ if (dir > 0)
+ {
+ ctx->offEnd = offset;
+ long size = ctx->offEnd - ctx->offStart;
+ char buffer[4];
+ buffer[0] = (unsigned char)(size>>24);
+ buffer[1] = (unsigned char)(size>>16);
+ buffer[2] = (unsigned char)(size>>8);
+ buffer[3] = (unsigned char)(size);
+ bs->seek(ctx->offStart - 4);
+ bs->writall((void*)buffer, 4);
+ bs->seek(offset);
+ }
+ // Arrange for reader to seek at next chunk
+ seekto = ctx->offEnd;
+ // Remove ctx record
+ IFFContext *octx = ctx;
+ ctx = octx->next;
+ assert(ctx==0 || ctx->bComposite);
+ delete octx;
+}
+
+// This is the same as above, but adds a seek to the close
+// Otherwise an EOF in this chunk won't be reported until we
+// try to open the next chunk, which makes error recovery
+// very difficult.
+void
+IFFByteStream::seek_close_chunk(void)
+{
+ close_chunk();
+ if ((dir <= 0)&&((!ctx)||(ctx->bComposite))&&(seekto > offset))
+ {
+ bs->seek(seekto);
+ offset = seekto;
+ }
+}
+
+// IFFByteStream::short_id
+// Returns the id of the current chunk
+
+void
+IFFByteStream::short_id(GUTF8String &chkid)
+{
+ if (!ctx)
+ G_THROW( ERR_MSG("IFFByteStream.no_chunk_id") );
+ if (ctx->bComposite)
+ chkid = GUTF8String(ctx->idOne, 4) + ":" + GUTF8String(ctx->idTwo, 4);
+ else
+ chkid = GUTF8String(ctx->idOne, 4);
+}
+
+
+// IFFByteStream::full_id
+// Returns the full chunk id of the current chunk
+
+void
+IFFByteStream::full_id(GUTF8String &chkid)
+{
+ short_id(chkid);
+ if (ctx->bComposite)
+ return;
+ // Search parent FORM or PROP chunk.
+ for (IFFContext *ct = ctx->next; ct; ct=ct->next)
+ if (memcmp(ct->idOne, "FOR", 3)==0 ||
+ memcmp(ct->idOne, "PRO", 3)==0 )
+ {
+ chkid = GUTF8String(ct->idTwo, 4) + "." + chkid;
+ break;
+ }
+}
+
+
+
+// IFFByteStream::read
+// -- read bytes from IFF file chunk
+
+size_t
+IFFByteStream::read(void *buffer, size_t size)
+{
+ if (! (ctx && dir < 0))
+ G_THROW( ERR_MSG("IFFByteStream.not_ready3") );
+ // Seek if necessary
+ if (seekto > offset) {
+ bs->seek(seekto);
+ offset = seekto;
+ }
+ // Ensure that read does not extend beyond chunk
+ if (offset > ctx->offEnd)
+ G_THROW( ERR_MSG("IFFByteStream.bad_offset") );
+ if (offset + (long)size > ctx->offEnd)
+ size = (size_t) (ctx->offEnd - offset);
+ // Read bytes
+ size_t bytes = bs->read(buffer, size);
+ offset += bytes;
+ return bytes;
+}
+
+
+// IFFByteStream::write
+// -- write bytes to IFF file chunk
+
+size_t
+IFFByteStream::write(const void *buffer, size_t size)
+{
+ if (! (ctx && dir > 0))
+ G_THROW( ERR_MSG("IFFByteStream.not_ready4") );
+ if (seekto > offset)
+ G_THROW( ERR_MSG("IFFByteStream.cant_write") );
+ size_t bytes = bs->write(buffer, size);
+ offset += bytes;
+ return bytes;
+}
+
+// IFFByteStream::tell
+// -- tell position
+
+long
+IFFByteStream::tell() const
+{
+ return (seekto>offset)?seekto:offset;
+}
+
+bool
+IFFByteStream::compare(IFFByteStream &iff)
+{
+ bool retval=(&iff == this);
+ if(!retval)
+ {
+ GUTF8String chkid1, chkid2;
+ int size;
+ while((size=get_chunk(chkid1)) == iff.get_chunk(chkid2))
+ {
+ if(chkid1 != chkid2)
+ {
+ break;
+ }
+ if(!size)
+ {
+ retval=true;
+ break;
+ }
+ char buf[4096];
+ int len;
+ while((len=read(buf,sizeof(buf))))
+ {
+ int s=0;
+ char buf2[sizeof(buf)];
+ while(s<len)
+ {
+ const int i=iff.read(buf2+s,len-s);
+ if(!i)
+ break;
+ s+=i;
+ }
+ if((s != len)||memcmp(buf,buf2,len))
+ break;
+ }
+ if(len)
+ break;
+ iff.close_chunk();
+ close_chunk();
+ }
+ }
+ return retval;
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/IFFByteStream.h b/kviewshell/plugins/djvu/libdjvu/IFFByteStream.h
new file mode 100644
index 00000000..cb1fb616
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/IFFByteStream.h
@@ -0,0 +1,312 @@
+//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: IFFByteStream.h,v 1.10 2003/11/07 22:08:21 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _IFFBYTESTREAM_H_
+#define _IFFBYTESTREAM_H_
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+/** @name IFFByteStream.h
+
+ Files #"IFFByteStream.h"# and #"IFFByteStream.cpp"# implement a parser for
+ files structured according the Electronic Arts ``EA IFF 85 Interchange
+ File Format''. IFF files are composed of a sequence of data {\em chunks}.
+ Each chunk is identified by a four character {\em chunk identifier}
+ describing the type of the data stored in the chunk. A few special chunk
+ identifiers, for instance #"FORM"#, are reserved for {\em composite
+ chunks} which themselves contain a sequence of data chunks. This
+ conventions effectively provides IFF files with a convenient hierarchical
+ structure. Composite chunks are further identified by a secondary chunk
+ identifier.
+
+ We found convenient to define a {\em extended chunk identifier}. In the
+ case of a regular chunk, the extended chunk identifier is simply the
+ chunk identifier, as in #"PM44"#. In the case of a composite chunk, the
+ extended chunk identifier is composed by concatenating the main chunk
+ identifier, a colon, and the secondary chunk identifier, as in
+ #"FORM:DJVU"#.
+
+ Class \Ref{IFFByteStream} provides a way to read or write IFF structured
+ files. Member functions provide an easy mean to position the underlying
+ \Ref{ByteStream} at the beginning of each chunk and to read or write the
+ data until reaching the end of the chunk. The utility program
+ \Ref{djvuinfo} demonstrates how to use class #IFFByteStream#.
+
+ {\bf IFF Files and ZP-Coder} ---
+ Class #IFFByteStream# repositions the underlying ByteStream whenever a new
+ chunk is accessed. It is possible to code chunk data with the ZP-Coder
+ without worrying about the final file position. See class \Ref{ZPCodec}
+ for more details.
+
+ {\bf DjVu IFF Files} --- We had initially planned to exactly follow the
+ IFF specifications. Then we realized that certain versions of MSIE
+ recognize any IFF file as a Microsoft AIFF sound file and pop a message
+ box "Cannot play that sound". It appears that the structure of AIFF files
+ is entirely modeled after the IFF standard, with small variations
+ regarding the endianness of numbers and the padding rules. We eliminate
+ this problem by casting the octet protection spell. Our IFF files always
+ start with the four octets #0x41,0x54,0x26,0x54# followed by the fully
+ conformant IFF byte stream. Class #IFFByteStream# silently skips these
+ four octets when it encounters them.
+
+ {\bf References} --- EA IFF 85 Interchange File Format specification:\\
+ \URL{http://www.cica.indiana.edu/graphics/image_specs/ilbm.format.txt} or
+ \URL{http://www.tnt.uni-hannover.de/soft/compgraph/fileformats/docs/iff.pre}
+
+ @memo
+ IFF file parser.
+ @author
+ L\'eon Bottou <leonb@research.att.com>
+
+// From: Leon Bottou, 1/31/2002
+// This has been changed by Lizardtech to fit better
+// with their re-implementation of ByteStreams.
+
+ @version
+ #$Id: IFFByteStream.h,v 1.10 2003/11/07 22:08:21 leonb Exp $# */
+//@{
+
+
+#include "DjVuGlobal.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "GException.h"
+#include "GString.h"
+#include "ByteStream.h"
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+/** ByteStream interface for an IFF file.
+
+ Class #IFFByteStream# augments the #ByteStream# interface with
+ functions for navigating from chunk to chunk. It works in relation
+ with a ByteStream specified at construction time.
+
+ {\bf Reading an IFF file} --- You can read an IFF file by constructing an
+ #IFFByteStream# object attached to the ByteStream containing the IFF file.
+ Calling function \Ref{get_chunk} positions the file pointer at the
+ beginning of the first chunk. You can then use \Ref{ByteStream::read} to
+ access the chunk data. Function #read# will return #0# if you attempt to
+ read past the end of the chunk, just as if you were trying to read past
+ the end of a file. You can at any time call function \Ref{close_chunk} to
+ terminate reading data in this chunk. The following chunks can be
+ accessed by calling #get_chunk# and #close_chunk# repeatedly until you
+ reach the end of the file. Function #read# is not very useful when
+ accessing a composite chunk. You can instead make nested calls to
+ functions #get_chunk# and #close_chunk# in order to access the chunks
+ located inside the composite chunk.
+
+ {\bf Writing an IFF file} --- You can write an IFF file by constructing an
+ #IFFByteStream# object attached to the seekable ByteStream object that
+ will contain the IFF file. Calling function \Ref{put_chunk} creates a
+ first chunk header and positions the file pointer at the beginning of the
+ chunk. You can then use \Ref{ByteStream::write} to store the chunk data.
+ Calling function \Ref{close_chunk} terminates the current chunk. You can
+ append more chunks by calling #put_chunk# and #close_chunk# repeatedly.
+ Function #write# is not very useful for writing a composite chunk. You
+ can instead make nested calls to function #put_chunk# and #close_chunk# in
+ order to create chunks located inside the composite chunk.
+
+ Writing an IFF file requires a seekable ByteStream (see
+ \Ref{ByteStream::is_seekable}). This is not much of a problem because you
+ can always create the IFF file into a \Ref{MemoryByteStream} and then use
+ \Ref{ByteStream::copy} to transfer the IFF file into a non seekable
+ ByteStream. */
+
+class IFFByteStream : protected ByteStream::Wrapper
+{
+protected:
+ IFFByteStream(const GP<ByteStream> &bs, const int pos);
+public:
+ /** Constructs an IFFByteStream object attached to ByteStream #bs#.
+ Any ByteStream can be used when reading an IFF file. Writing
+ an IFF file however requires a seekable ByteStream. */
+ static GP<IFFByteStream> create(const GP<ByteStream> &bs);
+ // --- BYTESTREAM INTERFACE
+ ~IFFByteStream();
+ virtual size_t read(void *buffer, size_t size);
+ virtual size_t write(const void *buffer, size_t size);
+ virtual long tell(void) const;
+ // -- NAVIGATING CHUNKS
+ /** Enters a chunk for reading. Function #get_chunk# returns zero when the
+ last chunk has already been accessed. Otherwise it parses a chunk
+ header, positions the IFFByteStream at the beginning of the chunk data,
+ stores the extended chunk identifier into string #chkid#, and returns
+ the non zero chunk size. The file offset of the chunk data may be
+ retrieved using function #tell#. The chunk data can then be read using
+ function #read# until reaching the end of the chunk. Advanced users may
+ supply two pointers to integer variables using arguments #rawoffsetptr#
+ and #rawsizeptr#. These variables will be overwritten with the offset
+ and the length of the file segment containing both the chunk header and
+ the chunk data. */
+ int get_chunk(GUTF8String &chkid, int *rawoffsetptr=0, int *rawsizeptr=0);
+ /** Enters a chunk for writing. Function #put_chunk# prepares a chunk
+ header and positions the IFFByteStream at the beginning of the chunk
+ data. Argument #chkid# defines a extended chunk identifier for this
+ chunk. The chunk data can then be written using function #write#. The
+ chunk is terminated by a matching call to function #close_chunk#. When
+ #insertmagic# is non zero, function #put_chunk# inserts the bytes:
+ 0x41, 0x54, 0x26, 0x54 before the chunk header, as discussed in
+ \Ref{IFFByteStream.h}. */
+ void put_chunk(const char *chkid, int insertmagic=0);
+ /** Leaves the current chunk. This function leaves the chunk previously
+ entered by a matching call to #get_chunk# and #put_chunk#. The
+ IFFByteStream is then ready to process the next chunk at the same
+ hierarchical level. */
+ void close_chunk();
+ /** This is identical to the above, plus it adds a seek to the start of
+ the next chunk. This way we catch EOF errors with the current chunk.*/
+ void seek_close_chunk();
+ /** Returns true when it is legal to call #read# or #write#. */
+ int ready();
+ /** Returns true when the current chunk is a composite chunk. */
+ int composite();
+ /** Returns the current chunk identifier of the current chunk. String
+ #chkid# is overwritten with the {\em extended chunk identifier} of the
+ current chunk. The extended chunk identifier of a regular chunk is
+ simply the chunk identifier, as in #"PM44"#. The extended chunk
+ identifier of a composite chunk is the concatenation of the chunk
+ identifier, of a semicolon #":"#, and of the secondary chunk identifier,
+ as in #"FORM:DJVU"#. */
+ void short_id(GUTF8String &chkid);
+ /** Returns the qualified chunk identifier of the current chunk. String
+ #chkid# is overwritten with the {\em qualified chunk identifier} of the
+ current chunk. The qualified chunk identifier of a composite chunk is
+ equal to the extended chunk identifier. The qualified chunk identifier
+ of a regular chunk is composed by concatenating the secondary chunk
+ identifier of the closest #"FORM"# or #"PROP"# composite chunk
+ containing the current chunk, a dot #"."#, and the current chunk
+ identifier, as in #"DJVU.INFO"#. According to the EA IFF 85 identifier
+ scoping rules, the qualified chunk identifier uniquely defines how the
+ chunk data should be interpreted. */
+ void full_id(GUTF8String &chkid);
+ /** Checks a potential chunk identifier. This function categorizes the
+ chunk identifier formed by the first four characters of string #chkid#.
+ It returns #0# if this is a legal identifier for a regular chunk. It
+ returns #+1# if this is a reserved composite chunk identifier. It
+ returns #-1# if this is an illegal or otherwise reserved identifier
+ which should not be used. */
+ static int check_id(const char *id);
+ GP<ByteStream> get_bytestream(void) {return this;}
+ /** Copy data from another ByteStream. A maximum of #size# bytes are read
+ from the ByteStream #bsfrom# and are written to the ByteStream #*this#
+ at the current position. Less than #size# bytes may be written if an
+ end-of-file mark is reached on #bsfrom#. This function returns the
+ total number of bytes copied. Setting argument #size# to zero (the
+ default value) has a special meaning: the copying process will continue
+ until reaching the end-of-file mark on ByteStream #bsfrom#, regardless
+ of the number of bytes transferred. */
+ size_t copy(ByteStream &bsfrom, size_t size=0)
+ { return get_bytestream()->copy(bsfrom,size); }
+ /** Flushes all buffers in the ByteStream. Calling this function
+ guarantees that pending data have been actually written (i.e. passed to
+ the operating system). Class #ByteStream# provides a default
+ implementation which does nothing. */
+ virtual void flush(void)
+ { ByteStream::Wrapper::flush(); }
+ /** This is a simple compare method. The IFFByteStream may be read for
+ the sake of the comparison. Since IFFByteStreams are non-seekable,
+ the stream is not valid for use after comparing, regardless of the
+ result. */
+ bool compare(IFFByteStream &iff);
+ /** #has_magic# is true if the stream has the DjVu file magic.
+ */
+ bool has_magic;
+private:
+ // private datatype
+ struct IFFContext
+ {
+ IFFContext *next;
+ long offStart;
+ long offEnd;
+ char idOne[4];
+ char idTwo[4];
+ char bComposite;
+ };
+ // Implementation
+ IFFContext *ctx;
+ long offset;
+ long seekto;
+ int dir;
+ // Cancel C++ default stuff
+ IFFByteStream(const IFFByteStream &);
+ IFFByteStream & operator=(const IFFByteStream &);
+ static GP<IFFByteStream> create(ByteStream *bs);
+};
+
+//@}
+
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/IW44EncodeCodec.cpp b/kviewshell/plugins/djvu/libdjvu/IW44EncodeCodec.cpp
new file mode 100644
index 00000000..c63eda7d
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/IW44EncodeCodec.cpp
@@ -0,0 +1,1797 @@
+//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: IW44EncodeCodec.cpp,v 1.11 2004/08/06 15:11:29 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+// - Author: Leon Bottou, 08/1998
+// From: Leon Bottou, 1/31/2002
+// Lizardtech has split this file into a decoder and an encoder.
+// Only superficial changes. The meat is mine.
+
+#define IW44IMAGE_IMPLIMENTATION /* */
+
+
+
+#include "IW44Image.h"
+#include "ZPCodec.h"
+#include "GBitmap.h"
+#include "GPixmap.h"
+#include "IFFByteStream.h"
+#include "GRect.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "MMX.h"
+#undef IWTRANSFORM_TIMER
+#ifdef IWTRANSFORM_TIMER
+#include "GOS.h"
+#endif
+
+#include <assert.h>
+#include <string.h>
+#include <math.h>
+
+#ifndef NEED_DECODER_ONLY
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+#define IWALLOCSIZE 4080
+#define IWCODEC_MAJOR 1
+#define IWCODEC_MINOR 2
+#define DECIBEL_PRUNE 5.0
+
+
+//////////////////////////////////////////////////////
+// WAVELET DECOMPOSITION CONSTANTS
+//////////////////////////////////////////////////////
+
+// Parameters for IW44 wavelet.
+// - iw_norm: norm of all wavelets (for db estimation)
+// - iw_shift: scale applied before decomposition
+
+
+static const float iw_norm[16] = {
+ 2.627989e+03F,
+ 1.832893e+02F, 1.832959e+02F, 5.114690e+01F,
+ 4.583344e+01F, 4.583462e+01F, 1.279225e+01F,
+ 1.149671e+01F, 1.149712e+01F, 3.218888e+00F,
+ 2.999281e+00F, 2.999476e+00F, 8.733161e-01F,
+ 1.074451e+00F, 1.074511e+00F, 4.289318e-01F
+};
+
+static const int iw_shift = 6;
+static const int iw_round = (1<<(iw_shift-1));
+
+static const struct { int start; int size; }
+bandbuckets[] =
+{
+ // Code first bucket and number of buckets in each band
+ { 0, 1 }, // -- band zero contains all lores info
+ { 1, 1 }, { 2, 1 }, { 3, 1 },
+ { 4, 4 }, { 8, 4 }, { 12,4 },
+ { 16,16 }, { 32,16 }, { 48,16 },
+};
+
+
+/** IW44 encoded gray-level image. This class provided functions for managing
+ a gray level image represented as a collection of IW44 wavelet
+ coefficients. The coefficients are stored in a memory efficient data
+ structure. Member function \Ref{get_bitmap} renders an arbitrary segment
+ of the image into a \Ref{GBitmap}. Member functions \Ref{decode_iff} and
+ \Ref{encode_iff} read and write DjVu IW44 files (see \Ref{IW44Image.h}).
+ Both the copy constructor and the copy operator are declared as private
+ members. It is therefore not possible to make multiple copies of instances
+ of this class. */
+
+class IWBitmap::Encode : public IWBitmap
+{
+public:
+ /// Destructor
+ virtual ~Encode(void);
+ /** Null constructor. Constructs an empty IWBitmap object. This object does
+ not contain anything meaningful. You must call function \Ref{init},
+ \Ref{decode_iff} or \Ref{decode_chunk} to populate the wavelet
+ coefficient data structure. */
+ Encode(void);
+ /** Initializes an IWBitmap with image #bm#. This constructor
+ performs the wavelet decomposition of image #bm# and records the
+ corresponding wavelet coefficient. Argument #mask# is an optional
+ bilevel image specifying the masked pixels (see \Ref{IW44Image.h}). */
+ void init(const GBitmap &bm, const GP<GBitmap> mask=0);
+ // CODER
+ /** Encodes one data chunk into ByteStream #bs#. Parameter #parms# controls
+ how much data is generated. The chunk data is written to ByteStream
+ #bs# with no IFF header. Successive calls to #encode_chunk# encode
+ successive chunks. You must call #close_codec# after encoding the last
+ chunk of a file. */
+ virtual int encode_chunk(GP<ByteStream> gbs, const IWEncoderParms &parms);
+ /** Writes a gray level image into DjVu IW44 file. This function creates a
+ composite chunk (identifier #FORM:BM44#) composed of #nchunks# chunks
+ (identifier #BM44#). Data for each chunk is generated with
+ #encode_chunk# using the corresponding parameters in array #parms#. */
+ virtual void encode_iff(IFFByteStream &iff, int nchunks, const IWEncoderParms *parms);
+ /** Resets the encoder/decoder state. The first call to #decode_chunk# or
+ #encode_chunk# initializes the coder for encoding or decoding. Function
+ #close_codec# must be called after processing the last chunk in order to
+ reset the coder and release the associated memory. */
+ virtual void close_codec(void);
+protected:
+ Codec::Encode *ycodec_enc;
+};
+
+/** IW44 encoded color image. This class provided functions for managing a
+ color image represented as a collection of IW44 wavelet coefficients. The
+ coefficients are stored in a memory efficient data structure. Member
+ function \Ref{get_pixmap} renders an arbitrary segment of the image into a
+ \Ref{GPixmap}. Member functions \Ref{decode_iff} and \Ref{encode_iff}
+ read and write DjVu IW44 files (see \Ref{IW44Image.h}). Both the copy
+ constructor and the copy operator are declared as private members. It is
+ therefore not possible to make multiple copies of instances of this
+ class. */
+
+class IWPixmap::Encode : public IWPixmap
+{
+public:
+ enum CRCBMode {
+ CRCBnone=IW44Image::CRCBnone,
+ CRCBhalf=IW44Image::CRCBhalf,
+ CRCBnormal=IW44Image::CRCBnormal,
+ CRCBfull=IW44Image::CRCBfull };
+ /// Destructor
+ virtual ~Encode(void);
+ /** Null constructor. Constructs an empty IWPixmap object. This object does
+ not contain anything meaningful. You must call function \Ref{init},
+ \Ref{decode_iff} or \Ref{decode_chunk} to populate the wavelet
+ coefficient data structure. */
+ Encode(void);
+ /** Initializes an IWPixmap with color image #bm#. This constructor
+ performs the wavelet decomposition of image #bm# and records the
+ corresponding wavelet coefficient. Argument #mask# is an optional
+ bilevel image specifying the masked pixels (see \Ref{IW44Image.h}).
+ Argument #crcbmode# specifies how the chrominance information should be
+ encoded (see \Ref{CRCBMode}). */
+ void init(const GPixmap &bm, const GP<GBitmap> mask=0, CRCBMode crcbmode=CRCBnormal);
+ // CODER
+ /** Encodes one data chunk into ByteStream #bs#. Parameter #parms# controls
+ how much data is generated. The chunk data is written to ByteStream
+ #bs# with no IFF header. Successive calls to #encode_chunk# encode
+ successive chunks. You must call #close_codec# after encoding the last
+ chunk of a file. */
+ virtual int encode_chunk(GP<ByteStream> gbs, const IWEncoderParms &parms);
+ /** Writes a color image into a DjVu IW44 file. This function creates a
+ composite chunk (identifier #FORM:PM44#) composed of #nchunks# chunks
+ (identifier #PM44#). Data for each chunk is generated with
+ #encode_chunk# using the corresponding parameters in array #parms#. */
+ virtual void encode_iff(IFFByteStream &iff, int nchunks, const IWEncoderParms *parms);
+ /** Resets the encoder/decoder state. The first call to #decode_chunk# or
+ #encode_chunk# initializes the coder for encoding or decoding. Function
+ #close_codec# must be called after processing the last chunk in order to
+ reset the coder and release the associated memory. */
+ virtual void close_codec(void);
+protected:
+ Codec::Encode *ycodec_enc, *cbcodec_enc, *crcodec_enc;
+};
+
+class IW44Image::Map::Encode : public IW44Image::Map // DJVU_CLASS
+{
+public:
+ Encode(const int w, const int h) : Map(w,h) {}
+ // creation (from image)
+ void create(const signed char *img8, int imgrowsize,
+ const signed char *msk8=0, int mskrowsize=0);
+ // slash resolution
+ void slashres(int res);
+};
+
+class IW44Image::Codec::Encode : public IW44Image::Codec
+{
+public:
+ Encode(IW44Image::Map &map);
+ // Coding
+ virtual int code_slice(ZPCodec &zp);
+ float estimate_decibel(float frac);
+ // Data
+ void encode_buckets(ZPCodec &zp, int bit, int band,
+ IW44Image::Block &blk, IW44Image::Block &eblk, int fbucket, int nbucket);
+ int encode_prepare(int band, int fbucket, int nbucket, IW44Image::Block &blk, IW44Image::Block &eblk);
+ IW44Image::Map emap;
+};
+
+IW44Image::Codec::Encode::Encode(IW44Image::Map &map)
+: Codec(map), emap(map.iw,map.ih) {}
+
+//////////////////////////////////////////////////////
+/** IW44Image::Transform::Encode
+*/
+
+class IW44Image::Transform::Encode : IW44Image::Transform
+{
+ public:
+ // WAVELET TRANSFORM
+ /** Forward transform. */
+ static void forward(short *p, int w, int h, int rowsize, int begin, int end);
+
+ // COLOR TRANSFORM
+ /** Extracts Y */
+ static void RGB_to_Y(const GPixel *p, int w, int h, int rowsize,
+ signed char *out, int outrowsize);
+ /** Extracts Cb */
+ static void RGB_to_Cb(const GPixel *p, int w, int h, int rowsize,
+ signed char *out, int outrowsize);
+ /** Extracts Cr */
+ static void RGB_to_Cr(const GPixel *p, int w, int h, int rowsize,
+ signed char *out, int outrowsize);
+};
+
+
+//////////////////////////////////////////////////////
+// MMX IMPLEMENTATION HELPERS
+//////////////////////////////////////////////////////
+
+
+// Note:
+// MMX implementation for vertical transforms only.
+// Speedup is basically related to faster memory transfer
+// The IW44 transform is not CPU bound, it is memory bound.
+
+#ifdef MMX
+
+static const short w9[] = {9,9,9,9};
+static const short w1[] = {1,1,1,1};
+static const int d8[] = {8,8};
+static const int d16[] = {16,16};
+
+
+static inline void
+mmx_fv_1 ( short* &q, short* e, int s, int s3 )
+{
+ while (q<e && (((long)q)&0x7))
+ {
+ int a = (int)q[-s] + (int)q[s];
+ int b = (int)q[-s3] + (int)q[s3];
+ *q -= (((a<<3)+a-b+8)>>4);
+ q++;
+ }
+ while (q+3<e)
+ {
+ MMXar( movq, q-s,mm0); // MM0=[ b3, b2, b1, b0 ]
+ MMXar( movq, q+s,mm2); // MM2=[ c3, c2, c1, c0 ]
+ MMXrr( movq, mm0,mm1);
+ MMXrr( punpcklwd, mm2,mm0); // MM0=[ c1, b1, c0, b0 ]
+ MMXrr( punpckhwd, mm2,mm1); // MM1=[ c3, b3, c2, b2 ]
+ MMXar( pmaddwd, w9,mm0); // MM0=[ (c1+b1)*9, (c0+b0)*9 ]
+ MMXar( pmaddwd, w9,mm1); // MM1=[ (c3+b3)*9, (c2+b2)*9 ]
+ MMXar( movq, q-s3,mm2);
+ MMXar( movq, q+s3,mm4);
+ MMXrr( movq, mm2,mm3);
+ MMXrr( punpcklwd, mm4,mm2); // MM2=[ d1, a1, d0, a0 ]
+ MMXrr( punpckhwd, mm4,mm3); // MM3=[ d3, a3, d2, a2 ]
+ MMXar( pmaddwd, w1,mm2); // MM2=[ (a1+d1)*1, (a0+d0)*1 ]
+ MMXar( pmaddwd, w1,mm3); // MM3=[ (a3+d3)*1, (a2+d2)*1 ]
+ MMXar( paddd, d8,mm0);
+ MMXar( paddd, d8,mm1);
+ MMXrr( psubd, mm2,mm0); // MM0=[ (c1+b1)*9-a1-d1+8, ...
+ MMXrr( psubd, mm3,mm1); // MM1=[ (c3+b3)*9-a3-d3+8, ...
+ MMXir( psrad, 4,mm0);
+ MMXar( movq, q,mm7); // MM7=[ p3,p2,p1,p0 ]
+ MMXir( psrad, 4,mm1);
+ MMXrr( packssdw, mm1,mm0); // MM0=[ x3,x2,x1,x0 ]
+ MMXrr( psubw, mm0,mm7); // MM7=[ p3-x3, p2-x2, ... ]
+ MMXra( movq, mm7,q);
+#if defined(_MSC_VER) && defined(_DEBUG)
+ MMXemms;
+#endif
+ q += 4;
+ }
+}
+
+static inline void
+mmx_fv_2 ( short* &q, short* e, int s, int s3 )
+{
+ while (q<e && (((long)q)&0x7))
+ {
+ int a = (int)q[-s] + (int)q[s];
+ int b = (int)q[-s3] + (int)q[s3];
+ *q += (((a<<3)+a-b+16)>>5);
+ q ++;
+ }
+ while (q+3<e)
+ {
+ MMXar( movq, q-s,mm0); // MM0=[ b3, b2, b1, b0 ]
+ MMXar( movq, q+s,mm2); // MM2=[ c3, c2, c1, c0 ]
+ MMXrr( movq, mm0,mm1);
+ MMXrr( punpcklwd, mm2,mm0); // MM0=[ c1, b1, c0, b0 ]
+ MMXrr( punpckhwd, mm2,mm1); // MM1=[ c3, b3, c2, b2 ]
+ MMXar( pmaddwd, w9,mm0); // MM0=[ (c1+b1)*9, (c0+b0)*9 ]
+ MMXar( pmaddwd, w9,mm1); // MM1=[ (c3+b3)*9, (c2+b2)*9 ]
+ MMXar( movq, q-s3,mm2);
+ MMXar( movq, q+s3,mm4);
+ MMXrr( movq, mm2,mm3);
+ MMXrr( punpcklwd, mm4,mm2); // MM2=[ d1, a1, d0, a0 ]
+ MMXrr( punpckhwd, mm4,mm3); // MM3=[ d3, a3, d2, a2 ]
+ MMXar( pmaddwd, w1,mm2); // MM2=[ (a1+d1)*1, (a0+d0)*1 ]
+ MMXar( pmaddwd, w1,mm3); // MM3=[ (a3+d3)*1, (a2+d2)*1 ]
+ MMXar( paddd, d16,mm0);
+ MMXar( paddd, d16,mm1);
+ MMXrr( psubd, mm2,mm0); // MM0=[ (c1+b1)*9-a1-d1+8, ...
+ MMXrr( psubd, mm3,mm1); // MM1=[ (c3+b3)*9-a3-d3+8, ...
+ MMXir( psrad, 5,mm0);
+ MMXar( movq, q,mm7); // MM7=[ p3,p2,p1,p0 ]
+ MMXir( psrad, 5,mm1);
+ MMXrr( packssdw, mm1,mm0); // MM0=[ x3,x2,x1,x0 ]
+ MMXrr( paddw, mm0,mm7); // MM7=[ p3+x3, p2+x2, ... ]
+ MMXra( movq, mm7,q);
+#if defined(_MSC_VER) && defined(_DEBUG)
+ MMXemms;
+#endif
+ q += 4;
+ }
+}
+
+#endif /* MMX */
+
+//////////////////////////////////////////////////////
+// NEW FILTERS
+//////////////////////////////////////////////////////
+
+static void
+filter_fv(short *p, int w, int h, int rowsize, int scale)
+{
+ int y = 0;
+ int s = scale*rowsize;
+ int s3 = s+s+s;
+ h = ((h-1)/scale)+1;
+ y += 1;
+ p += s;
+ while (y-3 < h)
+ {
+ // 1-Delta
+ {
+ short *q = p;
+ short *e = q+w;
+ if (y>=3 && y+3<h)
+ {
+ // Generic case
+#ifdef MMX
+ if (scale==1 && MMXControl::mmxflag>0)
+ mmx_fv_1(q, e, s, s3);
+#endif
+ while (q<e)
+ {
+ int a = (int)q[-s] + (int)q[s];
+ int b = (int)q[-s3] + (int)q[s3];
+ *q -= (((a<<3)+a-b+8)>>4);
+ q += scale;
+ }
+ }
+ else if (y<h)
+ {
+ // Special cases
+ short *q1 = (y+1<h ? q+s : q-s);
+ while (q<e)
+ {
+ int a = (int)q[-s] + (int)(*q1);
+ *q -= ((a+1)>>1);
+ q += scale;
+ q1 += scale;
+ }
+ }
+ }
+ // 2-Update
+ {
+ short *q = p-s3;
+ short *e = q+w;
+ if (y>=6 && y<h)
+ {
+ // Generic case
+#ifdef MMX
+ if (scale==1 && MMXControl::mmxflag>0)
+ mmx_fv_2(q, e, s, s3);
+#endif
+ while (q<e)
+ {
+ int a = (int)q[-s] + (int)q[s];
+ int b = (int)q[-s3] + (int)q[s3];
+ *q += (((a<<3)+a-b+16)>>5);
+ q += scale;
+ }
+ }
+ else if (y>=3)
+ {
+ // Special cases
+ short *q1 = (y-2<h ? q+s : 0);
+ short *q3 = (y<h ? q+s3 : 0);
+ if (y>=6)
+ {
+ while (q<e)
+ {
+ int a = (int)q[-s] + (q1 ? (int)(*q1) : 0);
+ int b = (int)q[-s3] + (q3 ? (int)(*q3) : 0);
+ *q += (((a<<3)+a-b+16)>>5);
+ q += scale;
+ if (q1) q1 += scale;
+ if (q3) q3 += scale;
+ }
+ }
+ else if (y>=4)
+ {
+ while (q<e)
+ {
+ int a = (int)q[-s] + (q1 ? (int)(*q1) : 0);
+ int b = (q3 ? (int)(*q3) : 0);
+ *q += (((a<<3)+a-b+16)>>5);
+ q += scale;
+ if (q1) q1 += scale;
+ if (q3) q3 += scale;
+ }
+ }
+ else
+ {
+ while (q<e)
+ {
+ int a = (q1 ? (int)(*q1) : 0);
+ int b = (q3 ? (int)(*q3) : 0);
+ *q += (((a<<3)+a-b+16)>>5);
+ q += scale;
+ if (q1) q1 += scale;
+ if (q3) q3 += scale;
+ }
+ }
+ }
+ }
+ y += 2;
+ p += s+s;
+ }
+}
+
+static void
+filter_fh(short *p, int w, int h, int rowsize, int scale)
+{
+ int y = 0;
+ int s = scale;
+ int s3 = s+s+s;
+ rowsize *= scale;
+ while (y<h)
+ {
+ short *q = p+s;
+ short *e = p+w;
+ int a0=0, a1=0, a2=0, a3=0;
+ int b0=0, b1=0, b2=0, b3=0;
+ if (q < e)
+ {
+ // Special case: x=1
+ a1 = a2 = a3 = q[-s];
+ if (q+s<e)
+ a2 = q[s];
+ if (q+s3<e)
+ a3 = q[s3];
+ b3 = q[0] - ((a1+a2+1)>>1);
+ q[0] = b3;
+ q += s+s;
+ }
+ while (q+s3 < e)
+ {
+ // Generic case
+ a0=a1;
+ a1=a2;
+ a2=a3;
+ a3=q[s3];
+ b0=b1;
+ b1=b2;
+ b2=b3;
+ b3 = q[0] - ((((a1+a2)<<3)+(a1+a2)-a0-a3+8) >> 4);
+ q[0] = b3;
+ q[-s3] = q[-s3] + ((((b1+b2)<<3)+(b1+b2)-b0-b3+16) >> 5);
+ q += s+s;
+ }
+ while (q < e)
+ {
+ // Special case: w-3 <= x < w
+ a1=a2;
+ a2=a3;
+ b0=b1;
+ b1=b2;
+ b2=b3;
+ b3 = q[0] - ((a1+a2+1)>>1);
+ q[0] = b3;
+ q[-s3] = q[-s3] + ((((b1+b2)<<3)+(b1+b2)-b0-b3+16) >> 5);
+ q += s+s;
+ }
+ while (q-s3 < e)
+ {
+ // Special case w <= x < w+3
+ b0=b1;
+ b1=b2;
+ b2=b3;
+ b3=0;
+ if (q-s3 >= p)
+ q[-s3] = q[-s3] + ((((b1+b2)<<3)+(b1+b2)-b0-b3+16) >> 5);
+ q += s+s;
+ }
+ y += scale;
+ p += rowsize;
+ }
+}
+
+
+//////////////////////////////////////////////////////
+// WAVELET TRANSFORM
+//////////////////////////////////////////////////////
+
+
+//----------------------------------------------------
+// Function for applying bidimensional IW44 between
+// scale intervals begin(inclusive) and end(exclusive)
+
+void
+IW44Image::Transform::Encode::forward(short *p, int w, int h, int rowsize, int begin, int end)
+{
+
+ // PREPARATION
+ filter_begin(w,h);
+ // LOOP ON SCALES
+ for (int scale=begin; scale<end; scale<<=1)
+ {
+#ifdef IWTRANSFORM_TIMER
+ int tv,th;
+ th = tv = GOS::ticks();
+#endif
+ filter_fh(p, w, h, rowsize, scale);
+#ifdef IWTRANSFORM_TIMER
+ th = GOS::ticks();
+ tv = th - tv;
+#endif
+ filter_fv(p, w, h, rowsize, scale);
+#ifdef IWTRANSFORM_TIMER
+ th = GOS::ticks()-th;
+ DjVuPrintErrorUTF8("forw%d\tv=%dms h=%dms\n", scale,th,tv);
+#endif
+ }
+ // TERMINATE
+ filter_end();
+}
+
+//////////////////////////////////////////////////////
+// COLOR TRANSFORM
+//////////////////////////////////////////////////////
+
+static const float
+rgb_to_ycc[3][3] =
+{ { 0.304348F, 0.608696F, 0.086956F },
+ { 0.463768F, -0.405797F, -0.057971F },
+ {-0.173913F, -0.347826F, 0.521739F } };
+
+
+/* Extracts Y */
+void
+IW44Image::Transform::Encode::RGB_to_Y(const GPixel *p, int w, int h, int rowsize,
+ signed char *out, int outrowsize)
+{
+ int rmul[256], gmul[256], bmul[256];
+ for (int k=0; k<256; k++)
+ {
+ rmul[k] = (int)(k*0x10000*rgb_to_ycc[0][0]);
+ gmul[k] = (int)(k*0x10000*rgb_to_ycc[0][1]);
+ bmul[k] = (int)(k*0x10000*rgb_to_ycc[0][2]);
+ }
+ for (int i=0; i<h; i++, p+=rowsize, out+=outrowsize)
+ {
+ const GPixel *p2 = p;
+ signed char *out2 = out;
+ for (int j=0; j<w; j++,p2++,out2++)
+ {
+ int y = rmul[p2->r] + gmul[p2->g] + bmul[p2->b] + 32768;
+ *out2 = (y>>16) - 128;
+ }
+ }
+}
+
+#ifdef min
+#undef min
+#endif
+static inline int min(const int x,const int y) {return (x<y)?x:y;}
+#ifdef max
+#undef max
+#endif
+static inline int max(const int x,const int y) {return (x>y)?x:y;}
+
+/* Extracts Cb */
+void
+IW44Image::Transform::Encode::RGB_to_Cb(const GPixel *p, int w, int h, int rowsize,
+ signed char *out, int outrowsize)
+{
+ int rmul[256], gmul[256], bmul[256];
+ for (int k=0; k<256; k++)
+ {
+ rmul[k] = (int)(k*0x10000*rgb_to_ycc[2][0]);
+ gmul[k] = (int)(k*0x10000*rgb_to_ycc[2][1]);
+ bmul[k] = (int)(k*0x10000*rgb_to_ycc[2][2]);
+ }
+ for (int i=0; i<h; i++, p+=rowsize, out+=outrowsize)
+ {
+ const GPixel *p2 = p;
+ signed char *out2 = out;
+ for (int j=0; j<w; j++,p2++,out2++)
+ {
+ int c = rmul[p2->r] + gmul[p2->g] + bmul[p2->b] + 32768;
+ *out2 = max(-128, min(127, c>>16));
+ }
+ }
+}
+
+/* Extracts Cr */
+void
+IW44Image::Transform::Encode::RGB_to_Cr(const GPixel *p, int w, int h, int rowsize,
+ signed char *out, int outrowsize)
+{
+ int rmul[256], gmul[256], bmul[256];
+ for (int k=0; k<256; k++)
+ {
+ rmul[k] = (int)((k*0x10000)*rgb_to_ycc[1][0]);
+ gmul[k] = (int)((k*0x10000)*rgb_to_ycc[1][1]);
+ bmul[k] = (int)((k*0x10000)*rgb_to_ycc[1][2]);
+ }
+ for (int i=0; i<h; i++, p+=rowsize, out+=outrowsize)
+ {
+ const GPixel *p2 = p;
+ signed char *out2 = out;
+ for (int j=0; j<w; j++,p2++,out2++)
+ {
+ int c = rmul[p2->r] + gmul[p2->g] + bmul[p2->b] + 32768;
+ *out2 = max(-128, min(127, c>>16));
+ }
+ }
+}
+
+
+//////////////////////////////////////////////////////
+// MASKING DECOMPOSITION
+//////////////////////////////////////////////////////
+
+//----------------------------------------------------
+// Function for applying bidimensional IW44 between
+// scale intervals begin(inclusive) and end(exclusive)
+// with a MASK bitmap
+
+
+static void
+interpolate_mask(short *data16, int w, int h, int rowsize,
+ const signed char *mask8, int mskrowsize)
+{
+ int i,j;
+ // count masked bits
+ short *count;
+ GPBuffer<short> gcount(count,w*h);
+ short *cp = count;
+ for (i=0; i<h; i++, cp+=w, mask8+=mskrowsize)
+ for (j=0; j<w; j++)
+ cp[j] = (mask8[j] ? 0 : 0x1000);
+ // copy image
+ short *sdata;
+ GPBuffer<short> gsdata(sdata,w*h);
+ short *p = sdata;
+ short *q = data16;
+ for (i=0; i<h; i++, p+=w, q+=rowsize)
+ for (j=0; j<w; j++)
+ p[j] = q[j];
+ // iterate over resolutions
+ int split = 1;
+ int scale = 2;
+ int again = 1;
+ while (again && scale<w && scale<h)
+ {
+ again = 0;
+ p = data16;
+ q = sdata;
+ cp = count;
+ // iterate over block
+ for (i=0; i<h; i+=scale, cp+=w*scale, q+=w*scale, p+=rowsize*scale)
+ for (j=0; j<w; j+=scale)
+ {
+ int ii, jj;
+ int gotz = 0;
+ int gray = 0;
+ int npix = 0;
+ short *cpp = cp;
+ short *qq = q;
+ // look around when square goes beyond border
+ int istart = i;
+ if (istart+split>h)
+ {
+ istart -= scale;
+ cpp -= w*scale;
+ qq -= w*scale;
+ }
+ int jstart = j;
+ if (jstart+split>w)
+ jstart -= scale;
+ // compute gray level
+ for (ii=istart; ii<i+scale && ii<h; ii+=split, cpp+=w*split, qq+=w*split)
+ for (jj=jstart; jj<j+scale && jj<w; jj+=split)
+ {
+ if (cpp[jj]>0)
+ {
+ npix += cpp[jj];
+ gray += cpp[jj] * qq[jj];
+ }
+ else if (ii>=i && jj>=j)
+ {
+ gotz = 1;
+ }
+ }
+ // process result
+ if (npix == 0)
+ {
+ // continue to next resolution
+ again = 1;
+ cp[j] = 0;
+ }
+ else
+ {
+ gray = gray / npix;
+ // check whether initial image require fix
+ if (gotz)
+ {
+ cpp = cp;
+ qq = p;
+ for (ii=i; ii<i+scale && ii<h; ii+=1, cpp+=w, qq+=rowsize)
+ for (jj=j; jj<j+scale && jj<w; jj+=1)
+ if (cpp[jj] == 0)
+ {
+ qq[jj] = gray;
+ cpp[jj] = 1;
+ }
+ }
+ // store average for next iteration
+ cp[j] = npix>>2;
+ q[j] = gray;
+ }
+ }
+ // double resolution
+ split = scale;
+ scale = scale+scale;
+ }
+}
+
+
+static void
+forward_mask(short *data16, int w, int h, int rowsize, int begin, int end,
+ const signed char *mask8, int mskrowsize )
+{
+ int i,j;
+ signed char *m;
+ short *p;
+ short *d;
+ // Allocate buffers
+ short *sdata;
+ GPBuffer<short> gsdata(sdata,w*h);
+ signed char *smask;
+ GPBuffer<signed char> gsmask(smask,w*h);
+ // Copy mask
+ m = smask;
+ for (i=0; i<h; i+=1, m+=w, mask8+=mskrowsize)
+ memcpy((void*)m, (void*)mask8, w);
+ // Loop over scale
+ for (int scale=begin; scale<end; scale<<=1)
+ {
+ // Copy data into sdata buffer
+ p = data16;
+ d = sdata;
+ for (i=0; i<h; i+=scale)
+ {
+ for (j=0; j<w; j+=scale)
+ d[j] = p[j];
+ p += rowsize * scale;
+ d += w * scale;
+ }
+ // Decompose
+ IW44Image::Transform::Encode::forward(sdata, w, h, w, scale, scale+scale);
+ // Cancel masked coefficients
+ d = sdata;
+ m = smask;
+ for (i=0; i<h; i+=scale+scale)
+ {
+ for (j=scale; j<w; j+=scale+scale)
+ if (m[j])
+ d[j] = 0;
+ d += w * scale;
+ m += w * scale;
+ if (i+scale < h)
+ {
+ for (j=0; j<w; j+=scale)
+ if (m[j])
+ d[j] = 0;
+ d += w * scale;
+ m += w * scale;
+ }
+ }
+ // Reconstruct
+ IW44Image::Transform::Decode::backward(sdata, w, h, w, scale+scale, scale);
+ // Correct visible pixels
+ p = data16;
+ d = sdata;
+ m = smask;
+ for (i=0; i<h; i+=scale)
+ {
+ for (j=0; j<w; j+=scale)
+ if (! m[j])
+ d[j] = p[j];
+ p += rowsize*scale;
+ m += w*scale;
+ d += w*scale;
+ }
+ // Decompose again (no need to iterate actually!)
+ IW44Image::Transform::Encode::forward(sdata, w, h, w, scale, scale+scale);
+ // Copy coefficients from sdata buffer
+ p = data16;
+ d = sdata;
+ for (i=0; i<h; i+=scale)
+ {
+ for (j=0; j<w; j+=scale)
+ p[j] = d[j];
+ p += rowsize * scale;
+ d += w * scale;
+ }
+ // Compute new mask for next scale
+ m = smask;
+ signed char *m0 = m;
+ signed char *m1 = m;
+ for (i=0; i<h; i+=scale+scale)
+ {
+ m0 = m1;
+ if (i+scale < h)
+ m1 = m + w*scale;
+ for (j=0; j<w; j+=scale+scale)
+ if (m[j] && m0[j] && m1[j] && (j<=0 || m[j-scale]) && (j+scale>=w || m[j+scale]))
+ m[j] = 1;
+ else
+ m[j] = 0;
+ m = m1 + w*scale;
+ }
+ }
+ // Free buffers
+}
+
+void
+IW44Image::Map::Encode::create(const signed char *img8, int imgrowsize,
+ const signed char *msk8, int mskrowsize )
+{
+ int i, j;
+ // Progress
+ DJVU_PROGRESS_TASK(transf,"create iw44 map",3);
+ // Allocate decomposition buffer
+ short *data16;
+ GPBuffer<short> gdata16(data16,bw*bh);
+ // Copy pixels
+ short *p = data16;
+ const signed char *row = img8;
+ for (i=0; i<ih; i++)
+ {
+ for (j=0; j<iw; j++)
+ *p++ = (int)(row[j]) << iw_shift;
+ row += imgrowsize;
+ for (j=iw; j<bw; j++)
+ *p++ = 0;
+ }
+ for (i=ih; i<bh; i++)
+ for (j=0; j<bw; j++)
+ *p++ = 0;
+ // Handle bitmask
+ if (msk8)
+ {
+ // Interpolate pixels below mask
+ DJVU_PROGRESS_RUN(transf, 1);
+ interpolate_mask(data16, iw, ih, bw, msk8, mskrowsize);
+ // Multiscale iterative masked decomposition
+ DJVU_PROGRESS_RUN(transf, 3);
+ forward_mask(data16, iw, ih, bw, 1, 32, msk8, mskrowsize);
+ }
+ else
+ {
+ // Perform traditional decomposition
+ DJVU_PROGRESS_RUN(transf, 3);
+ IW44Image::Transform::Encode::forward(data16, iw, ih, bw, 1, 32);
+ }
+ // Copy coefficient into blocks
+ p = data16;
+ IW44Image::Block *block = blocks;
+ for (i=0; i<bh; i+=32)
+ {
+ for (j=0; j<bw; j+=32)
+ {
+ short liftblock[1024];
+ // transfer coefficients at (p+j) into aligned block
+ short *pp = p + j;
+ short *pl = liftblock;
+ for (int ii=0; ii<32; ii++, pp+=bw)
+ for (int jj=0; jj<32; jj++)
+ *pl++ = pp[jj];
+ // transfer into IW44Image::Block (apply zigzag and scaling)
+ block->read_liftblock(liftblock, this);
+ block++;
+ }
+ // next row of blocks
+ p += 32*bw;
+ }
+}
+
+void
+IW44Image::Map::Encode::slashres(int res)
+{
+ int minbucket = 1;
+ if (res < 2)
+ return;
+ else if (res < 4)
+ minbucket=16;
+ else if (res < 8)
+ minbucket=4;
+ for (int blockno=0; blockno<nb; blockno++)
+ for (int buckno=minbucket; buckno<64; buckno++)
+ blocks[blockno].zero(buckno);
+}
+
+// encode_prepare
+// -- compute the states prior to encoding the buckets
+int
+IW44Image::Codec::Encode::encode_prepare(int band, int fbucket, int nbucket, IW44Image::Block &blk, IW44Image::Block &eblk)
+{
+ int bbstate = 0;
+ // compute state of all coefficients in all buckets
+ if (band)
+ {
+ // Band other than zero
+ int thres = quant_hi[band];
+ char *cstate = coeffstate;
+ for (int buckno=0; buckno<nbucket; buckno++, cstate+=16)
+ {
+ const short *pcoeff = blk.data(fbucket+buckno);
+ const short *epcoeff = eblk.data(fbucket+buckno);
+ int bstatetmp = 0;
+ if (! pcoeff)
+ {
+ bstatetmp = UNK;
+ // cstate[i] is not used and does not need initialization
+ }
+ else if (! epcoeff)
+ {
+ for (int i=0; i<16; i++)
+ {
+ int cstatetmp = UNK;
+ if ((int)(pcoeff[i])>=thres || (int)(pcoeff[i])<=-thres)
+ cstatetmp = NEW|UNK;
+ cstate[i] = cstatetmp;
+ bstatetmp |= cstatetmp;
+ }
+ }
+ else
+ {
+ for (int i=0; i<16; i++)
+ {
+ int cstatetmp = UNK;
+ if (epcoeff[i])
+ cstatetmp = ACTIVE;
+ else if ((int)(pcoeff[i])>=thres || (int)(pcoeff[i])<=-thres)
+ cstatetmp = NEW|UNK;
+ cstate[i] = cstatetmp;
+ bstatetmp |= cstatetmp;
+ }
+ }
+ bucketstate[buckno] = bstatetmp;
+ bbstate |= bstatetmp;
+ }
+ }
+ else
+ {
+ // Band zero ( fbucket==0 implies band==zero and nbucket==1 )
+ const short *pcoeff = blk.data(0, &map);
+ const short *epcoeff = eblk.data(0, &emap);
+ char *cstate = coeffstate;
+ for (int i=0; i<16; i++)
+ {
+ int thres = quant_lo[i];
+ int cstatetmp = cstate[i];
+ if (cstatetmp != ZERO)
+ {
+ cstatetmp = UNK;
+ if (epcoeff[i])
+ cstatetmp = ACTIVE;
+ else if ((int)(pcoeff[i])>=thres || (int)(pcoeff[i])<=-thres)
+ cstatetmp = NEW|UNK;
+ }
+ cstate[i] = cstatetmp;
+ bbstate |= cstatetmp;
+ }
+ bucketstate[0] = bbstate;
+ }
+ return bbstate;
+}
+
+// encode_buckets
+// -- code a sequence of buckets in a given block
+void
+IW44Image::Codec::Encode::encode_buckets(ZPCodec &zp, int bit, int band,
+ IW44Image::Block &blk, IW44Image::Block &eblk,
+ int fbucket, int nbucket)
+{
+ // compute state of all coefficients in all buckets
+ int bbstate = encode_prepare(band, fbucket, nbucket, blk, eblk);
+
+ // code root bit
+ if ((nbucket<16) || (bbstate&ACTIVE))
+ {
+ bbstate |= NEW;
+ }
+ else if (bbstate & UNK)
+ {
+ zp.encoder( (bbstate&NEW) ? 1 : 0 , ctxRoot);
+#ifdef TRACE
+ DjVuPrintMessage("bbstate[bit=%d,band=%d] = %d\n", bit, band, bbstate);
+#endif
+ }
+
+ // code bucket bits
+ if (bbstate & NEW)
+ for (int buckno=0; buckno<nbucket; buckno++)
+ {
+ // Code bucket bit
+ if (bucketstate[buckno] & UNK)
+ {
+ // Context
+ int ctx = 0;
+#ifndef NOCTX_BUCKET_UPPER
+ if (band>0)
+ {
+ int k = (fbucket+buckno)<<2;
+ const short *b = eblk.data(k>>4);
+ if (b)
+ {
+ k = k & 0xf;
+ if (b[k])
+ ctx += 1;
+ if (b[k+1])
+ ctx += 1;
+ if (b[k+2])
+ ctx += 1;
+ if (ctx<3 && b[k+3])
+ ctx += 1;
+ }
+ }
+#endif
+#ifndef NOCTX_BUCKET_ACTIVE
+ if (bbstate & ACTIVE)
+ ctx |= 4;
+#endif
+ // Code
+ zp.encoder( (bucketstate[buckno]&NEW) ? 1 : 0, ctxBucket[band][ctx] );
+#ifdef TRACE
+ DjVuPrintMessage(" bucketstate[bit=%d,band=%d,buck=%d] = %d\n",
+ bit, band, buckno, bucketstate[buckno] & ~ZERO);
+#endif
+ }
+ }
+
+ // code new active coefficient (with their sign)
+ if (bbstate & NEW)
+ {
+ int thres = quant_hi[band];
+ char *cstate = coeffstate;
+ for (int buckno=0; buckno<nbucket; buckno++, cstate+=16)
+ if (bucketstate[buckno] & NEW)
+ {
+ int i;
+#ifndef NOCTX_EXPECT
+ int gotcha = 0;
+ const int maxgotcha = 7;
+ for (i=0; i<16; i++)
+ if (cstate[i] & UNK)
+ gotcha += 1;
+#endif
+ const short *pcoeff = blk.data(fbucket+buckno);
+ short *epcoeff = eblk.data(fbucket+buckno, &emap);
+ // iterate within bucket
+ for (i=0; i<16; i++)
+ {
+ if (cstate[i] & UNK)
+ {
+ // Prepare context
+ int ctx = 0;
+#ifndef NOCTX_EXPECT
+ if (gotcha>=maxgotcha)
+ ctx = maxgotcha;
+ else
+ ctx = gotcha;
+#endif
+#ifndef NOCTX_ACTIVE
+ if (bucketstate[buckno] & ACTIVE)
+ ctx |= 8;
+#endif
+ // Code
+ zp.encoder( (cstate[i]&NEW) ? 1 : 0, ctxStart[ctx] );
+ if (cstate[i] & NEW)
+ {
+ // Code sign
+ zp.IWencoder( (pcoeff[i]<0) ? 1 : 0 );
+ // Set encoder state
+ if (band==0)
+ thres = quant_lo[i];
+ epcoeff[i] = thres + (thres>>1);
+ }
+#ifndef NOCTX_EXPECT
+ if (cstate[i] & NEW)
+ gotcha = 0;
+ else if (gotcha > 0)
+ gotcha -= 1;
+#endif
+#ifdef TRACE
+ DjVuPrintMessage(" coeffstate[bit=%d,band=%d,buck=%d,c=%d] = %d\n",
+ bit, band, buckno, i, cstate[i]);
+#endif
+ }
+ }
+ }
+ }
+
+ // code mantissa bits
+ if (bbstate & ACTIVE)
+ {
+ int thres = quant_hi[band];
+ char *cstate = coeffstate;
+ for (int buckno=0; buckno<nbucket; buckno++, cstate+=16)
+ if (bucketstate[buckno] & ACTIVE)
+ {
+ const short *pcoeff = blk.data(fbucket+buckno);
+ short *epcoeff = eblk.data(fbucket+buckno, &emap);
+ for (int i=0; i<16; i++)
+ if (cstate[i] & ACTIVE)
+ {
+ // get coefficient
+ int coeff = pcoeff[i];
+ int ecoeff = epcoeff[i];
+ if (coeff < 0)
+ coeff = -coeff;
+ // get band zero thresholds
+ if (band == 0)
+ thres = quant_lo[i];
+ // compute mantissa bit
+ int pix = 0;
+ if (coeff >= ecoeff)
+ pix = 1;
+ // encode second or lesser mantissa bit
+ if (ecoeff <= 3*thres)
+ zp.encoder(pix, ctxMant);
+ else
+ zp.IWencoder(!!pix);
+ // adjust epcoeff
+ epcoeff[i] = ecoeff - (pix ? 0 : thres) + (thres>>1);
+ }
+ }
+ }
+}
+
+// IW44Image::Codec::estimate_decibel
+// -- estimate encoding error (after code_slice) in decibels.
+float
+IW44Image::Codec::Encode::estimate_decibel(float frac)
+{
+ int i,j;
+ const float *q;
+ // Fill norm arrays
+ float norm_lo[16];
+ float norm_hi[10];
+ // -- lo coefficients
+ q = iw_norm;
+ for (i=j=0; i<4; j++)
+ norm_lo[i++] = *q++;
+ for (j=0; j<4; j++)
+ norm_lo[i++] = *q;
+ q += 1;
+ for (j=0; j<4; j++)
+ norm_lo[i++] = *q;
+ q += 1;
+ for (j=0; j<4; j++)
+ norm_lo[i++] = *q;
+ q += 1;
+ // -- hi coefficients
+ norm_hi[0] = 0;
+ for (j=1; j<10; j++)
+ norm_hi[j] = *q++;
+ // Initialize mse array
+ float *xmse;
+ GPBuffer<float> gxmse(xmse,map.nb);
+ // Compute mse in each block
+ for (int blockno=0; blockno<map.nb; blockno++)
+ {
+ float mse = 0;
+ // Iterate over bands
+ for (int bandno=0; bandno<10; bandno++)
+ {
+ int fbucket = bandbuckets[bandno].start;
+ int nbucket = bandbuckets[bandno].size;
+ IW44Image::Block &blk = map.blocks[blockno];
+ IW44Image::Block &eblk = emap.blocks[blockno];
+ float norm = norm_hi[bandno];
+ for (int buckno=0; buckno<nbucket; buckno++)
+ {
+ const short *pcoeff = blk.data(fbucket+buckno);
+ const short *epcoeff = eblk.data(fbucket+buckno);
+ if (pcoeff)
+ {
+ if (epcoeff)
+ {
+ for (i=0; i<16; i++)
+ {
+ if (bandno == 0)
+ norm = norm_lo[i];
+ float delta = (float)(pcoeff[i]<0 ? -pcoeff[i] : pcoeff[i]);
+ delta = delta - epcoeff[i];
+ mse = mse + norm * delta * delta;
+ }
+ }
+ else
+ {
+ for (i=0; i<16; i++)
+ {
+ if (bandno == 0)
+ norm = norm_lo[i];
+ float delta = (float)(pcoeff[i]);
+ mse = mse + norm * delta * delta;
+ }
+ }
+ }
+ }
+ }
+ xmse[blockno] = mse / 1024;
+ }
+ // Compute partition point
+ int n = 0;
+ int m = map.nb - 1;
+ int p = (int)floor(m*(1.0-frac)+0.5);
+ p = (p>m ? m : (p<0 ? 0 : p));
+ float pivot = 0;
+ // Partition array
+ while (n < p)
+ {
+ int l = n;
+ int h = m;
+ if (xmse[l] > xmse[h]) { float tmp=xmse[l]; xmse[l]=xmse[h]; xmse[h]=tmp; }
+ pivot = xmse[(l+h)/2];
+ if (pivot < xmse[l]) { float tmp=pivot; pivot=xmse[l]; xmse[l]=tmp; }
+ if (pivot > xmse[h]) { float tmp=pivot; pivot=xmse[h]; xmse[h]=tmp; }
+ while (l < h)
+ {
+ if (xmse[l] > xmse[h]) { float tmp=xmse[l]; xmse[l]=xmse[h]; xmse[h]=tmp; }
+ while (xmse[l]<pivot || (xmse[l]==pivot && l<h)) l++;
+ while (xmse[h]>pivot) h--;
+ }
+ if (p>=l)
+ n = l;
+ else
+ m = l-1;
+ }
+ // Compute average mse
+ float mse = 0;
+ for (i=p; i<map.nb; i++)
+ mse = mse + xmse[i];
+ mse = mse / (map.nb - p);
+ // Return
+ float factor = 255 << iw_shift;
+ float decibel = (float)(10.0 * log ( factor * factor / mse ) / 2.302585125);
+ return decibel;
+}
+
+
+
+
+//////////////////////////////////////////////////////
+// IW44IMAGE ENCODING ROUTINES
+//////////////////////////////////////////////////////
+
+
+void
+IW44Image::PrimaryHeader::encode(GP<ByteStream> gbs)
+{
+ gbs->write8(serial);
+ gbs->write8(slices);
+}
+
+void
+IW44Image::SecondaryHeader::encode(GP<ByteStream> gbs)
+{
+ gbs->write8(major);
+ gbs->write8(minor);
+}
+
+void
+IW44Image::TertiaryHeader::encode(GP<ByteStream> gbs)
+{
+ gbs->write8(xhi);
+ gbs->write8(xlo);
+ gbs->write8(yhi);
+ gbs->write8(ylo);
+ gbs->write8(crcbdelay);
+}
+
+
+
+GP<IW44Image>
+IW44Image::create_encode(const ImageType itype)
+{
+ switch(itype)
+ {
+ case COLOR:
+ return new IWPixmap::Encode();
+ case GRAY:
+ return new IWBitmap::Encode();
+ default:
+ return 0;
+ }
+}
+
+GP<IW44Image>
+IW44Image::create_encode(const GBitmap &bm, const GP<GBitmap> mask)
+{
+ IWBitmap::Encode *bit=new IWBitmap::Encode();
+ GP<IW44Image> retval=bit;
+ bit->init(bm, mask);
+ return retval;
+}
+
+
+IWBitmap::Encode::Encode(void)
+: IWBitmap(), ycodec_enc(0)
+{}
+
+IWBitmap::Encode::~Encode()
+{
+ close_codec();
+}
+
+void
+IWBitmap::Encode::init(const GBitmap &bm, const GP<GBitmap> gmask)
+{
+ // Free
+ close_codec();
+ delete ymap;
+ ymap = 0;
+ // Init
+ int i, j;
+ int w = bm.columns();
+ int h = bm.rows();
+ int g = bm.get_grays()-1;
+ signed char *buffer;
+ GPBuffer<signed char> gbuffer(buffer,w*h);
+ // Prepare gray level conversion table
+ signed char bconv[256];
+ for (i=0; i<256; i++)
+ bconv[i] = max(0,min(255,i*255/g)) - 128;
+ // Perform decomposition
+ // Prepare mask information
+ const signed char *msk8 = 0;
+ int mskrowsize = 0;
+ GBitmap *mask=gmask;
+ if (gmask)
+ {
+ msk8 = (const signed char*)((*mask)[0]);
+ mskrowsize = mask->rowsize();
+ }
+ // Prepare a buffer of signed bytes
+ for (i=0; i<h; i++)
+ {
+ signed char *bufrow = buffer + i*w;
+ const unsigned char *bmrow = bm[i];
+ for (j=0; j<w; j++)
+ bufrow[j] = bconv[bmrow[j]];
+ }
+ // Create map
+ Map::Encode *eymap=new Map::Encode(w,h);
+ ymap = eymap;
+ eymap->create(buffer, w, msk8, mskrowsize);
+}
+
+void
+IWBitmap::Encode::close_codec(void)
+{
+ delete ycodec_enc;
+ ycodec_enc = 0;
+ IWBitmap::close_codec();
+}
+
+int
+IWBitmap::Encode::encode_chunk(GP<ByteStream> gbs, const IWEncoderParms &parm)
+{
+ // Check
+ if (parm.slices==0 && parm.bytes==0 && parm.decibels==0)
+ G_THROW( ERR_MSG("IW44Image.need_stop") );
+ if (! ymap)
+ G_THROW( ERR_MSG("IW44Image.empty_object") );
+ // Open codec
+ if (!ycodec_enc)
+ {
+ cslice = cserial = cbytes = 0;
+ ycodec_enc = new Codec::Encode(*ymap);
+ }
+ // Adjust cbytes
+ cbytes += sizeof(struct IW44Image::PrimaryHeader);
+ if (cserial == 0)
+ cbytes += sizeof(struct IW44Image::SecondaryHeader) + sizeof(struct IW44Image::TertiaryHeader);
+ // Prepare zcoded slices
+ int flag = 1;
+ int nslices = 0;
+ GP<ByteStream> gmbs=ByteStream::create();
+ ByteStream &mbs=*gmbs;
+ DJVU_PROGRESS_TASK(chunk,"encode chunk",parm.slices-cslice);
+ {
+ float estdb = -1.0;
+ GP<ZPCodec> gzp=ZPCodec::create(gmbs, true, true);
+ ZPCodec &zp=*gzp;
+ while (flag)
+ {
+ if (parm.decibels>0 && estdb>=parm.decibels)
+ break;
+ if (parm.bytes>0 && mbs.tell()+cbytes>=parm.bytes)
+ break;
+ if (parm.slices>0 && nslices+cslice>=parm.slices)
+ break;
+ DJVU_PROGRESS_RUN(chunk, (1+nslices-cslice)|0xf);
+ flag = ycodec_enc->code_slice(zp);
+ if (flag && parm.decibels>0.0)
+ if (ycodec_enc->curband==0 || estdb>=parm.decibels-DECIBEL_PRUNE)
+ estdb = ycodec_enc->estimate_decibel(db_frac);
+ nslices++;
+ }
+ }
+ // Write primary header
+ struct IW44Image::PrimaryHeader primary;
+ primary.serial = cserial;
+ primary.slices = nslices;
+ primary.encode(gbs);
+ // Write auxilliary headers
+ if (cserial == 0)
+ {
+ struct IW44Image::SecondaryHeader secondary;
+ secondary.major = IWCODEC_MAJOR + 0x80;
+ secondary.minor = IWCODEC_MINOR;
+ secondary.encode(gbs);
+ struct IW44Image::TertiaryHeader tertiary;
+ tertiary.xhi = (ymap->iw >> 8) & 0xff;
+ tertiary.xlo = (ymap->iw >> 0) & 0xff;
+ tertiary.yhi = (ymap->ih >> 8) & 0xff;
+ tertiary.ylo = (ymap->ih >> 0) & 0xff;
+ tertiary.crcbdelay = 0;
+ tertiary.encode(gbs);
+ }
+ // Write slices
+ mbs.seek(0);
+ gbs->copy(mbs);
+ // Return
+ cbytes += mbs.tell();
+ cslice += nslices;
+ cserial += 1;
+ return flag;
+}
+
+void
+IWBitmap::Encode::encode_iff(IFFByteStream &iff, int nchunks, const IWEncoderParms *parms)
+{
+ if (ycodec_enc)
+ G_THROW( ERR_MSG("IW44Image.left_open1") );
+ int flag = 1;
+ iff.put_chunk("FORM:BM44", 1);
+ DJVU_PROGRESS_TASK(iff,"encode iff chunk",nchunks);
+ for (int i=0; flag && i<nchunks; i++)
+ {
+ DJVU_PROGRESS_RUN(iff,i+1);
+ iff.put_chunk("BM44");
+ flag = encode_chunk(iff.get_bytestream(),parms[i]);
+ iff.close_chunk();
+ }
+ iff.close_chunk();
+ close_codec();
+}
+
+GP<IW44Image>
+IW44Image::create_encode(
+ const GPixmap &pm, const GP<GBitmap> gmask, CRCBMode crcbmode)
+{
+ IWPixmap::Encode *pix=new IWPixmap::Encode();
+ GP<IW44Image> retval=pix;
+ pix->init(pm, gmask,(IWPixmap::Encode::CRCBMode)crcbmode);
+ return retval;
+}
+
+IWPixmap::Encode::Encode(void)
+: IWPixmap(), ycodec_enc(0), cbcodec_enc(0), crcodec_enc(0)
+{}
+
+IWPixmap::Encode::~Encode()
+{
+ close_codec();
+}
+
+void
+IWPixmap::Encode::init(const GPixmap &pm, const GP<GBitmap> gmask, CRCBMode crcbmode)
+{
+ /* Free */
+ close_codec();
+ delete ymap;
+ delete cbmap;
+ delete crmap;
+ ymap = cbmap = crmap = 0;
+ /* Create */
+ int w = pm.columns();
+ int h = pm.rows();
+ signed char *buffer;
+ GPBuffer<signed char> gbuffer(buffer,w*h);
+ // Create maps
+ Map::Encode *eymap = new Map::Encode(w,h);
+ ymap = eymap;
+ // Handle CRCB mode
+ switch (crcbmode)
+ {
+ case CRCBnone: crcb_half=1; crcb_delay=-1; break;
+ case CRCBhalf: crcb_half=1; crcb_delay=10; break;
+ case CRCBnormal: crcb_half=0; crcb_delay=10; break;
+ case CRCBfull: crcb_half=0; crcb_delay= 0; break;
+ }
+ // Prepare mask information
+ const signed char *msk8 = 0;
+ int mskrowsize = 0;
+ GBitmap *mask=gmask;
+ if (mask)
+ {
+ msk8 = (signed char const *)((*mask)[0]);
+ mskrowsize = mask->rowsize();
+ }
+ // Fill buffer with luminance information
+ DJVU_PROGRESS_TASK(create,"initialize pixmap",3);
+ DJVU_PROGRESS_RUN(create,(crcb_delay>=0 ? 1 : 3));
+ Transform::Encode::RGB_to_Y(pm[0], w, h, pm.rowsize(), buffer, w);
+ if (crcb_delay < 0)
+ {
+ // Stupid inversion for gray images
+ signed char *e = buffer + w*h;
+ for (signed char *b=buffer; b<e; b++)
+ *b = 255 - *b;
+ }
+ // Create YMAP
+ eymap->create(buffer, w, msk8, mskrowsize);
+ // Create chrominance maps
+ if (crcb_delay >= 0)
+ {
+ Map::Encode *ecbmap = new Map::Encode(w,h);
+ cbmap = ecbmap;
+ Map::Encode *ecrmap = new Map::Encode(w,h);
+ crmap = ecrmap;
+ // Process CB information
+ DJVU_PROGRESS_RUN(create,2);
+ Transform::Encode::RGB_to_Cb(pm[0], w, h, pm.rowsize(), buffer, w);
+ ecbmap->create(buffer, w, msk8, mskrowsize);
+ // Process CR information
+ DJVU_PROGRESS_RUN(create,3);
+ Transform::Encode::RGB_to_Cr(pm[0], w, h, pm.rowsize(), buffer, w);
+ ecrmap->create(buffer, w, msk8, mskrowsize);
+ // Perform chrominance reduction (CRCBhalf)
+ if (crcb_half)
+ {
+ ecbmap->slashres(2);
+ ecrmap->slashres(2);
+ }
+ }
+}
+
+void
+IWPixmap::Encode::encode_iff(IFFByteStream &iff, int nchunks, const IWEncoderParms *parms)
+{
+ if (ycodec_enc)
+ G_THROW( ERR_MSG("IW44Image.left_open3") );
+ int flag = 1;
+ iff.put_chunk("FORM:PM44", 1);
+ DJVU_PROGRESS_TASK(iff,"encode pixmap chunk", nchunks);
+ for (int i=0; flag && i<nchunks; i++)
+ {
+ DJVU_PROGRESS_RUN(iff,i+1);
+ iff.put_chunk("PM44");
+ flag = encode_chunk(iff.get_bytestream(), parms[i]);
+ iff.close_chunk();
+ }
+ iff.close_chunk();
+ close_codec();
+}
+
+void
+IWPixmap::Encode::close_codec(void)
+{
+ delete ycodec_enc;
+ delete cbcodec_enc;
+ delete crcodec_enc;
+ ycodec_enc = crcodec_enc = cbcodec_enc = 0;
+ IWPixmap::close_codec();
+}
+
+int
+IWPixmap::Encode::encode_chunk(GP<ByteStream> gbs, const IWEncoderParms &parm)
+{
+ // Check
+ if (parm.slices==0 && parm.bytes==0 && parm.decibels==0)
+ G_THROW( ERR_MSG("IW44Image.need_stop2") );
+ if (!ymap)
+ G_THROW( ERR_MSG("IW44Image.empty_object2") );
+ // Open
+ if (!ycodec_enc)
+ {
+ cslice = cserial = cbytes = 0;
+ ycodec_enc = new Codec::Encode(*ymap);
+ if (crmap && cbmap)
+ {
+ cbcodec_enc = new Codec::Encode(*cbmap);
+ crcodec_enc = new Codec::Encode(*crmap);
+ }
+ }
+
+ // Adjust cbytes
+ cbytes += sizeof(struct IW44Image::PrimaryHeader);
+ if (cserial == 0)
+ cbytes += sizeof(struct IW44Image::SecondaryHeader) + sizeof(struct IW44Image::TertiaryHeader);
+ // Prepare zcodec slices
+ int flag = 1;
+ int nslices = 0;
+ GP<ByteStream> gmbs=ByteStream::create();
+ ByteStream &mbs=*gmbs;
+ DJVU_PROGRESS_TASK(chunk, "encode pixmap chunk", parm.slices-cslice);
+ {
+ float estdb = -1.0;
+ GP<ZPCodec> gzp=ZPCodec::create(gmbs, true, true);
+ ZPCodec &zp=*gzp;
+ while (flag)
+ {
+ if (parm.decibels>0 && estdb>=parm.decibels)
+ break;
+ if (parm.bytes>0 && mbs.tell()+cbytes>=parm.bytes)
+ break;
+ if (parm.slices>0 && nslices+cslice>=parm.slices)
+ break;
+ DJVU_PROGRESS_RUN(chunk,(1+nslices-cslice)|0xf);
+ flag = ycodec_enc->code_slice(zp);
+ if (flag && parm.decibels>0)
+ if (ycodec_enc->curband==0 || estdb>=parm.decibels-DECIBEL_PRUNE)
+ estdb = ycodec_enc->estimate_decibel(db_frac);
+ if (crcodec_enc && cbcodec_enc && cslice+nslices>=crcb_delay)
+ {
+ flag |= cbcodec_enc->code_slice(zp);
+ flag |= crcodec_enc->code_slice(zp);
+ }
+ nslices++;
+ }
+ }
+ // Write primary header
+ struct IW44Image::PrimaryHeader primary;
+ primary.serial = cserial;
+ primary.slices = nslices;
+ primary.encode(gbs);
+ // Write secondary header
+ if (cserial == 0)
+ {
+ struct IW44Image::SecondaryHeader secondary;
+ secondary.major = IWCODEC_MAJOR;
+ secondary.minor = IWCODEC_MINOR;
+ if (! (crmap && cbmap))
+ secondary.major |= 0x80;
+ secondary.encode(gbs);
+ struct IW44Image::TertiaryHeader tertiary;
+ tertiary.xhi = (ymap->iw >> 8) & 0xff;
+ tertiary.xlo = (ymap->iw >> 0) & 0xff;
+ tertiary.yhi = (ymap->ih >> 8) & 0xff;
+ tertiary.ylo = (ymap->ih >> 0) & 0xff;
+ tertiary.crcbdelay = (crcb_half ? 0x00 : 0x80);
+ tertiary.crcbdelay |= (crcb_delay>=0 ? crcb_delay : 0x00);
+ tertiary.encode(gbs);
+ }
+ // Write slices
+ mbs.seek(0);
+ gbs->copy(mbs);
+ // Return
+ cbytes += mbs.tell();
+ cslice += nslices;
+ cserial += 1;
+ return flag;
+}
+
+// code_slice
+// -- read/write a slice of datafile
+
+int
+IW44Image::Codec::Encode::code_slice(ZPCodec &zp)
+{
+ // Check that code_slice can still run
+ if (curbit < 0)
+ return 0;
+ // Perform coding
+ if (! is_null_slice(curbit, curband))
+ {
+ for (int blockno=0; blockno<map.nb; blockno++)
+ {
+ const int fbucket = bandbuckets[curband].start;
+ const int nbucket = bandbuckets[curband].size;
+ encode_buckets(zp, curbit, curband,
+ map.blocks[blockno], emap.blocks[blockno],
+ fbucket, nbucket);
+ }
+ }
+ return finish_code_slice(zp);
+}
+
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif // NEED_DECODER_ONLY
+
diff --git a/kviewshell/plugins/djvu/libdjvu/IW44Image.cpp b/kviewshell/plugins/djvu/libdjvu/IW44Image.cpp
new file mode 100644
index 00000000..2cadf4f9
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/IW44Image.cpp
@@ -0,0 +1,1935 @@
+//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: IW44Image.cpp,v 1.11 2004/08/06 15:11:29 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+// - Author: Leon Bottou, 08/1998
+
+// From: Leon Bottou, 1/31/2002
+// Lizardtech has split this file into a decoder and an encoder.
+// Only superficial changes. The meat is mine.
+
+#define IW44IMAGE_IMPLIMENTATION /* */
+// -------------------^ not my spelling mistake (Leon Bottou)
+
+#include "IW44Image.h"
+#include "ZPCodec.h"
+#include "GBitmap.h"
+#include "GPixmap.h"
+#include "IFFByteStream.h"
+#include "GRect.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "MMX.h"
+#undef IWTRANSFORM_TIMER
+#ifdef IWTRANSFORM_TIMER
+#include "GOS.h"
+#endif
+
+#include <assert.h>
+#include <string.h>
+#include <math.h>
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+#define IWALLOCSIZE 4080
+#define IWCODEC_MAJOR 1
+#define IWCODEC_MINOR 2
+#define DECIBEL_PRUNE 5.0
+
+
+//////////////////////////////////////////////////////
+// WAVELET DECOMPOSITION CONSTANTS
+//////////////////////////////////////////////////////
+
+// Parameters for IW44 wavelet.
+// - iw_quant: quantization for all 16 sub-bands
+// - iw_norm: norm of all wavelets (for db estimation)
+// - iw_border: pixel border required to run filters
+// - iw_shift: scale applied before decomposition
+
+
+static const int iw_quant[16] = {
+ 0x004000,
+ 0x008000, 0x008000, 0x010000,
+ 0x010000, 0x010000, 0x020000,
+ 0x020000, 0x020000, 0x040000,
+ 0x040000, 0x040000, 0x080000,
+ 0x040000, 0x040000, 0x080000
+};
+
+static const float iw_norm[16] = {
+ 2.627989e+03F,
+ 1.832893e+02F, 1.832959e+02F, 5.114690e+01F,
+ 4.583344e+01F, 4.583462e+01F, 1.279225e+01F,
+ 1.149671e+01F, 1.149712e+01F, 3.218888e+00F,
+ 2.999281e+00F, 2.999476e+00F, 8.733161e-01F,
+ 1.074451e+00F, 1.074511e+00F, 4.289318e-01F
+};
+
+static const int iw_border = 3;
+static const int iw_shift = 6;
+static const int iw_round = (1<<(iw_shift-1));
+
+class IW44Image::Codec::Decode : public IW44Image::Codec
+{
+public:
+ // Construction
+ Decode(IW44Image::Map &map) : Codec(map) {}
+ // Coding
+ virtual int code_slice(ZPCodec &zp);
+};
+
+//////////////////////////////////////////////////////
+// MMX IMPLEMENTATION HELPERS
+//////////////////////////////////////////////////////
+
+
+// Note:
+// MMX implementation for vertical transforms only.
+// Speedup is basically related to faster memory transfer
+// The IW44 transform is not CPU bound, it is memory bound.
+
+#ifdef MMX
+
+static const short w9[] = {9,9,9,9};
+static const short w1[] = {1,1,1,1};
+static const int d8[] = {8,8};
+static const int d16[] = {16,16};
+
+static void
+mmx_bv_1 ( short* &q, short* e, int s, int s3 )
+{
+ while (q<e && (((long)q)&0x7))
+ {
+ int a = (int)q[-s] + (int)q[s];
+ int b = (int)q[-s3] + (int)q[s3];
+ *q -= (((a<<3)+a-b+16)>>5);
+ q ++;
+ }
+ while (q+3 < e)
+ {
+ MMXar( movq, q-s,mm0); // MM0=[ b3, b2, b1, b0 ]
+ MMXar( movq, q+s,mm2); // MM2=[ c3, c2, c1, c0 ]
+ MMXrr( movq, mm0,mm1);
+ MMXrr( punpcklwd, mm2,mm0); // MM0=[ c1, b1, c0, b0 ]
+ MMXrr( punpckhwd, mm2,mm1); // MM1=[ c3, b3, c2, b2 ]
+ MMXar( pmaddwd, w9,mm0); // MM0=[ (c1+b1)*9, (c0+b0)*9 ]
+ MMXar( pmaddwd, w9,mm1); // MM1=[ (c3+b3)*9, (c2+b2)*9 ]
+ MMXar( movq, q-s3,mm2);
+ MMXar( movq, q+s3,mm4);
+ MMXrr( movq, mm2,mm3);
+ MMXrr( punpcklwd, mm4,mm2); // MM2=[ d1, a1, d0, a0 ]
+ MMXrr( punpckhwd, mm4,mm3); // MM3=[ d3, a3, d2, a2 ]
+ MMXar( pmaddwd, w1,mm2); // MM2=[ (a1+d1)*1, (a0+d0)*1 ]
+ MMXar( pmaddwd, w1,mm3); // MM3=[ (a3+d3)*1, (a2+d2)*1 ]
+ MMXar( paddd, d16,mm0);
+ MMXar( paddd, d16,mm1);
+ MMXrr( psubd, mm2,mm0); // MM0=[ (c1+b1)*9-a1-d1+8, ...
+ MMXrr( psubd, mm3,mm1); // MM1=[ (c3+b3)*9-a3-d3+8, ...
+ MMXir( psrad, 5,mm0);
+ MMXar( movq, q,mm7); // MM7=[ p3,p2,p1,p0 ]
+ MMXir( psrad, 5,mm1);
+ MMXrr( packssdw, mm1,mm0); // MM0=[ x3,x2,x1,x0 ]
+ MMXrr( psubw, mm0,mm7); // MM7=[ p3-x3, p2-x2, ... ]
+ MMXra( movq, mm7,q);
+#if defined(_MSC_VER) && defined(_DEBUG)
+ MMXemms;
+#endif
+ q += 4;
+ }
+}
+
+
+static void
+mmx_bv_2 ( short* &q, short* e, int s, int s3 )
+{
+ while (q<e && (((long)q)&0x7))
+ {
+ int a = (int)q[-s] + (int)q[s];
+ int b = (int)q[-s3] + (int)q[s3];
+ *q += (((a<<3)+a-b+8)>>4);
+ q ++;
+ }
+ while (q+3 < e)
+ {
+ MMXar( movq, q-s,mm0); // MM0=[ b3, b2, b1, b0 ]
+ MMXar( movq, q+s,mm2); // MM2=[ c3, c2, c1, c0 ]
+ MMXrr( movq, mm0,mm1);
+ MMXrr( punpcklwd, mm2,mm0); // MM0=[ c1, b1, c0, b0 ]
+ MMXrr( punpckhwd, mm2,mm1); // MM1=[ c3, b3, c2, b2 ]
+ MMXar( pmaddwd, w9,mm0); // MM0=[ (c1+b1)*9, (c0+b0)*9 ]
+ MMXar( pmaddwd, w9,mm1); // MM1=[ (c3+b3)*9, (c2+b2)*9 ]
+ MMXar( movq, q-s3,mm2);
+ MMXar( movq, q+s3,mm4);
+ MMXrr( movq, mm2,mm3);
+ MMXrr( punpcklwd, mm4,mm2); // MM2=[ d1, a1, d0, a0 ]
+ MMXrr( punpckhwd, mm4,mm3); // MM3=[ d3, a3, d2, a2 ]
+ MMXar( pmaddwd, w1,mm2); // MM2=[ (a1+d1)*1, (a0+d0)*1 ]
+ MMXar( pmaddwd, w1,mm3); // MM3=[ (a3+d3)*1, (a2+d2)*1 ]
+ MMXar( paddd, d8,mm0);
+ MMXar( paddd, d8,mm1);
+ MMXrr( psubd, mm2,mm0); // MM0=[ (c1+b1)*9-a1-d1+8, ...
+ MMXrr( psubd, mm3,mm1); // MM1=[ (c3+b3)*9-a3-d3+8, ...
+ MMXir( psrad, 4,mm0);
+ MMXar( movq, q,mm7); // MM7=[ p3,p2,p1,p0 ]
+ MMXir( psrad, 4,mm1);
+ MMXrr( packssdw, mm1,mm0); // MM0=[ x3,x2,x1,x0 ]
+ MMXrr( paddw, mm0,mm7); // MM7=[ p3+x3, p2+x2, ... ]
+ MMXra( movq, mm7,q);
+#if defined(_MSC_VER) && defined(_DEBUG)
+ MMXemms;
+#endif
+ q += 4;
+ }
+}
+#endif /* MMX */
+
+static void
+filter_bv(short *p, int w, int h, int rowsize, int scale)
+{
+ int y = 0;
+ int s = scale*rowsize;
+ int s3 = s+s+s;
+ h = ((h-1)/scale)+1;
+ while (y-3 < h)
+ {
+ // 1-Lifting
+ {
+ short *q = p;
+ short *e = q+w;
+ if (y>=3 && y+3<h)
+ {
+ // Generic case
+#ifdef MMX
+ if (scale==1 && MMXControl::mmxflag>0)
+ mmx_bv_1(q, e, s, s3);
+#endif
+ while (q<e)
+ {
+ int a = (int)q[-s] + (int)q[s];
+ int b = (int)q[-s3] + (int)q[s3];
+ *q -= (((a<<3)+a-b+16)>>5);
+ q += scale;
+ }
+ }
+ else if (y<h)
+ {
+ // Special cases
+ short *q1 = (y+1<h ? q+s : 0);
+ short *q3 = (y+3<h ? q+s3 : 0);
+ if (y>=3)
+ {
+ while (q<e)
+ {
+ int a = (int)q[-s] + (q1 ? (int)(*q1) : 0);
+ int b = (int)q[-s3] + (q3 ? (int)(*q3) : 0);
+ *q -= (((a<<3)+a-b+16)>>5);
+ q += scale;
+ if (q1) q1 += scale;
+ if (q3) q3 += scale;
+ }
+ }
+ else if (y>=1)
+ {
+ while (q<e)
+ {
+ int a = (int)q[-s] + (q1 ? (int)(*q1) : 0);
+ int b = (q3 ? (int)(*q3) : 0);
+ *q -= (((a<<3)+a-b+16)>>5);
+ q += scale;
+ if (q1) q1 += scale;
+ if (q3) q3 += scale;
+ }
+ }
+ else
+ {
+ while (q<e)
+ {
+ int a = (q1 ? (int)(*q1) : 0);
+ int b = (q3 ? (int)(*q3) : 0);
+ *q -= (((a<<3)+a-b+16)>>5);
+ q += scale;
+ if (q1) q1 += scale;
+ if (q3) q3 += scale;
+ }
+ }
+ }
+ }
+ // 2-Interpolation
+ {
+ short *q = p-s3;
+ short *e = q+w;
+ if (y>=6 && y<h)
+ {
+ // Generic case
+#ifdef MMX
+ if (scale==1 && MMXControl::mmxflag>0)
+ mmx_bv_2(q, e, s, s3);
+#endif
+ while (q<e)
+ {
+ int a = (int)q[-s] + (int)q[s];
+ int b = (int)q[-s3] + (int)q[s3];
+ *q += (((a<<3)+a-b+8)>>4);
+ q += scale;
+ }
+ }
+ else if (y>=3)
+ {
+ // Special cases
+ short *q1 = (y-2<h ? q+s : q-s);
+ while (q<e)
+ {
+ int a = (int)q[-s] + (int)(*q1);
+ *q += ((a+1)>>1);
+ q += scale;
+ q1 += scale;
+ }
+ }
+ }
+ y += 2;
+ p += s+s;
+ }
+}
+
+static void
+filter_bh(short *p, int w, int h, int rowsize, int scale)
+{
+ int y = 0;
+ int s = scale;
+ int s3 = s+s+s;
+ rowsize *= scale;
+ while (y<h)
+ {
+ short *q = p;
+ short *e = p+w;
+ int a0=0, a1=0, a2=0, a3=0;
+ int b0=0, b1=0, b2=0, b3=0;
+ if (q<e)
+ {
+ // Special case: x=0
+ if (q+s < e)
+ a2 = q[s];
+ if (q+s3 < e)
+ a3 = q[s3];
+ b2 = b3 = q[0] - ((((a1+a2)<<3)+(a1+a2)-a0-a3+16) >> 5);
+ q[0] = b3;
+ q += s+s;
+ }
+ if (q<e)
+ {
+ // Special case: x=2
+ a0 = a1;
+ a1 = a2;
+ a2 = a3;
+ if (q+s3 < e)
+ a3 = q[s3];
+ b3 = q[0] - ((((a1+a2)<<3)+(a1+a2)-a0-a3+16) >> 5);
+ q[0] = b3;
+ q += s+s;
+ }
+ if (q<e)
+ {
+ // Special case: x=4
+ b1 = b2;
+ b2 = b3;
+ a0 = a1;
+ a1 = a2;
+ a2 = a3;
+ if (q+s3 < e)
+ a3 = q[s3];
+ b3 = q[0] - ((((a1+a2)<<3)+(a1+a2)-a0-a3+16) >> 5);
+ q[0] = b3;
+ q[-s3] = q[-s3] + ((b1+b2+1)>>1);
+ q += s+s;
+ }
+ while (q+s3 < e)
+ {
+ // Generic case
+ a0=a1;
+ a1=a2;
+ a2=a3;
+ a3=q[s3];
+ b0=b1;
+ b1=b2;
+ b2=b3;
+ b3 = q[0] - ((((a1+a2)<<3)+(a1+a2)-a0-a3+16) >> 5);
+ q[0] = b3;
+ q[-s3] = q[-s3] + ((((b1+b2)<<3)+(b1+b2)-b0-b3+8) >> 4);
+ q += s+s;
+ }
+ while (q < e)
+ {
+ // Special case: w-3 <= x < w
+ a0=a1;
+ a1=a2;
+ a2=a3;
+ a3=0;
+ b0=b1;
+ b1=b2;
+ b2=b3;
+ b3 = q[0] - ((((a1+a2)<<3)+(a1+a2)-a0-a3+16) >> 5);
+ q[0] = b3;
+ q[-s3] = q[-s3] + ((((b1+b2)<<3)+(b1+b2)-b0-b3+8) >> 4);
+ q += s+s;
+ }
+ while (q-s3 < e)
+ {
+ // Special case w <= x < w+3
+ b0=b1;
+ b1=b2;
+ b2=b3;
+ if (q-s3 >= p)
+ q[-s3] = q[-s3] + ((b1+b2+1)>>1);
+ q += s+s;
+ }
+ y += scale;
+ p += rowsize;
+ }
+}
+
+
+//////////////////////////////////////////////////////
+// REPRESENTATION OF WAVELET DECOMPOSED IMAGES
+//////////////////////////////////////////////////////
+
+
+
+//---------------------------------------------------------------
+// Zig zag location in a 1024 liftblock.
+// These numbers have been generated with the following program:
+//
+// int x=0, y=0;
+// for (int i=0; i<5; i++) {
+// x = (x<<1) | (n&1); n >>= 1;
+// y = (y<<1) | (n&1); n >>= 1;
+// }
+
+
+static int zigzagloc[1024] = {
+ 0, 16, 512, 528, 8, 24, 520, 536, 256, 272, 768, 784, 264, 280, 776, 792,
+ 4, 20, 516, 532, 12, 28, 524, 540, 260, 276, 772, 788, 268, 284, 780, 796,
+ 128, 144, 640, 656, 136, 152, 648, 664, 384, 400, 896, 912, 392, 408, 904, 920,
+ 132, 148, 644, 660, 140, 156, 652, 668, 388, 404, 900, 916, 396, 412, 908, 924,
+ 2, 18, 514, 530, 10, 26, 522, 538, 258, 274, 770, 786, 266, 282, 778, 794,
+ 6, 22, 518, 534, 14, 30, 526, 542, 262, 278, 774, 790, 270, 286, 782, 798,
+ 130, 146, 642, 658, 138, 154, 650, 666, 386, 402, 898, 914, 394, 410, 906, 922,
+ 134, 150, 646, 662, 142, 158, 654, 670, 390, 406, 902, 918, 398, 414, 910, 926,
+ 64, 80, 576, 592, 72, 88, 584, 600, 320, 336, 832, 848, 328, 344, 840, 856,
+ 68, 84, 580, 596, 76, 92, 588, 604, 324, 340, 836, 852, 332, 348, 844, 860,
+ 192, 208, 704, 720, 200, 216, 712, 728, 448, 464, 960, 976, 456, 472, 968, 984,
+ 196, 212, 708, 724, 204, 220, 716, 732, 452, 468, 964, 980, 460, 476, 972, 988,
+ 66, 82, 578, 594, 74, 90, 586, 602, 322, 338, 834, 850, 330, 346, 842, 858,
+ 70, 86, 582, 598, 78, 94, 590, 606, 326, 342, 838, 854, 334, 350, 846, 862,
+ 194, 210, 706, 722, 202, 218, 714, 730, 450, 466, 962, 978, 458, 474, 970, 986,
+ 198, 214, 710, 726, 206, 222, 718, 734, 454, 470, 966, 982, 462, 478, 974, 990, // 255
+ 1, 17, 513, 529, 9, 25, 521, 537, 257, 273, 769, 785, 265, 281, 777, 793,
+ 5, 21, 517, 533, 13, 29, 525, 541, 261, 277, 773, 789, 269, 285, 781, 797,
+ 129, 145, 641, 657, 137, 153, 649, 665, 385, 401, 897, 913, 393, 409, 905, 921,
+ 133, 149, 645, 661, 141, 157, 653, 669, 389, 405, 901, 917, 397, 413, 909, 925,
+ 3, 19, 515, 531, 11, 27, 523, 539, 259, 275, 771, 787, 267, 283, 779, 795,
+ 7, 23, 519, 535, 15, 31, 527, 543, 263, 279, 775, 791, 271, 287, 783, 799,
+ 131, 147, 643, 659, 139, 155, 651, 667, 387, 403, 899, 915, 395, 411, 907, 923,
+ 135, 151, 647, 663, 143, 159, 655, 671, 391, 407, 903, 919, 399, 415, 911, 927,
+ 65, 81, 577, 593, 73, 89, 585, 601, 321, 337, 833, 849, 329, 345, 841, 857,
+ 69, 85, 581, 597, 77, 93, 589, 605, 325, 341, 837, 853, 333, 349, 845, 861,
+ 193, 209, 705, 721, 201, 217, 713, 729, 449, 465, 961, 977, 457, 473, 969, 985,
+ 197, 213, 709, 725, 205, 221, 717, 733, 453, 469, 965, 981, 461, 477, 973, 989,
+ 67, 83, 579, 595, 75, 91, 587, 603, 323, 339, 835, 851, 331, 347, 843, 859,
+ 71, 87, 583, 599, 79, 95, 591, 607, 327, 343, 839, 855, 335, 351, 847, 863,
+ 195, 211, 707, 723, 203, 219, 715, 731, 451, 467, 963, 979, 459, 475, 971, 987,
+ 199, 215, 711, 727, 207, 223, 719, 735, 455, 471, 967, 983, 463, 479, 975, 991, // 511
+ 32, 48, 544, 560, 40, 56, 552, 568, 288, 304, 800, 816, 296, 312, 808, 824,
+ 36, 52, 548, 564, 44, 60, 556, 572, 292, 308, 804, 820, 300, 316, 812, 828,
+ 160, 176, 672, 688, 168, 184, 680, 696, 416, 432, 928, 944, 424, 440, 936, 952,
+ 164, 180, 676, 692, 172, 188, 684, 700, 420, 436, 932, 948, 428, 444, 940, 956,
+ 34, 50, 546, 562, 42, 58, 554, 570, 290, 306, 802, 818, 298, 314, 810, 826,
+ 38, 54, 550, 566, 46, 62, 558, 574, 294, 310, 806, 822, 302, 318, 814, 830,
+ 162, 178, 674, 690, 170, 186, 682, 698, 418, 434, 930, 946, 426, 442, 938, 954,
+ 166, 182, 678, 694, 174, 190, 686, 702, 422, 438, 934, 950, 430, 446, 942, 958,
+ 96, 112, 608, 624, 104, 120, 616, 632, 352, 368, 864, 880, 360, 376, 872, 888,
+ 100, 116, 612, 628, 108, 124, 620, 636, 356, 372, 868, 884, 364, 380, 876, 892,
+ 224, 240, 736, 752, 232, 248, 744, 760, 480, 496, 992,1008, 488, 504,1000,1016,
+ 228, 244, 740, 756, 236, 252, 748, 764, 484, 500, 996,1012, 492, 508,1004,1020,
+ 98, 114, 610, 626, 106, 122, 618, 634, 354, 370, 866, 882, 362, 378, 874, 890,
+ 102, 118, 614, 630, 110, 126, 622, 638, 358, 374, 870, 886, 366, 382, 878, 894,
+ 226, 242, 738, 754, 234, 250, 746, 762, 482, 498, 994,1010, 490, 506,1002,1018,
+ 230, 246, 742, 758, 238, 254, 750, 766, 486, 502, 998,1014, 494, 510,1006,1022, // 767
+ 33, 49, 545, 561, 41, 57, 553, 569, 289, 305, 801, 817, 297, 313, 809, 825,
+ 37, 53, 549, 565, 45, 61, 557, 573, 293, 309, 805, 821, 301, 317, 813, 829,
+ 161, 177, 673, 689, 169, 185, 681, 697, 417, 433, 929, 945, 425, 441, 937, 953,
+ 165, 181, 677, 693, 173, 189, 685, 701, 421, 437, 933, 949, 429, 445, 941, 957,
+ 35, 51, 547, 563, 43, 59, 555, 571, 291, 307, 803, 819, 299, 315, 811, 827,
+ 39, 55, 551, 567, 47, 63, 559, 575, 295, 311, 807, 823, 303, 319, 815, 831,
+ 163, 179, 675, 691, 171, 187, 683, 699, 419, 435, 931, 947, 427, 443, 939, 955,
+ 167, 183, 679, 695, 175, 191, 687, 703, 423, 439, 935, 951, 431, 447, 943, 959,
+ 97, 113, 609, 625, 105, 121, 617, 633, 353, 369, 865, 881, 361, 377, 873, 889,
+ 101, 117, 613, 629, 109, 125, 621, 637, 357, 373, 869, 885, 365, 381, 877, 893,
+ 225, 241, 737, 753, 233, 249, 745, 761, 481, 497, 993,1009, 489, 505,1001,1017,
+ 229, 245, 741, 757, 237, 253, 749, 765, 485, 501, 997,1013, 493, 509,1005,1021,
+ 99, 115, 611, 627, 107, 123, 619, 635, 355, 371, 867, 883, 363, 379, 875, 891,
+ 103, 119, 615, 631, 111, 127, 623, 639, 359, 375, 871, 887, 367, 383, 879, 895,
+ 227, 243, 739, 755, 235, 251, 747, 763, 483, 499, 995,1011, 491, 507,1003,1019,
+ 231, 247, 743, 759, 239, 255, 751, 767, 487, 503, 999,1015, 495, 511,1007,1023, // 1023
+};
+
+//---------------------------------------------------------------
+// *** Class IW44Image::Alloc [declaration]
+
+struct IW44Image::Alloc // DJVU_CLASS
+{
+ Alloc *next;
+ short data[IWALLOCSIZE];
+};
+
+//---------------------------------------------------------------
+// *** Class IW44Image::Block [implementation]
+
+
+IW44Image::Block::Block(void)
+{
+ pdata[0] = pdata[1] = pdata[2] = pdata[3] = 0;
+}
+
+void
+IW44Image::Block::zero(int n)
+{
+ if (pdata[n>>4])
+ pdata[n>>4][n&15] = 0;
+}
+
+void
+IW44Image::Block::read_liftblock(const short *coeff, IW44Image::Map *map)
+{
+ int n=0;
+ for (int n1=0; n1<64; n1++)
+ {
+ short *d = data(n1,map);
+ for (int n2=0; n2<16; n2++,n++)
+ d[n2] = coeff[zigzagloc[n]];
+ }
+}
+
+void
+IW44Image::Block::write_liftblock(short *coeff, int bmin, int bmax) const
+{
+ int n = bmin<<4;
+ memset(coeff, 0, 1024*sizeof(short));
+ for (int n1=bmin; n1<bmax; n1++)
+ {
+ const short *d = data(n1);
+ if (d == 0)
+ n += 16;
+ else
+ for (int n2=0; n2<16; n2++,n++)
+ coeff[zigzagloc[n]] = d[n2];
+ }
+}
+
+//---------------------------------------------------------------
+// *** Class IW44Image::Map [implementation]
+
+
+IW44Image::Map::Map(int w, int h)
+ : blocks(0), iw(w), ih(h), chain(0)
+{
+ bw = (w+0x20-1) & ~0x1f;
+ bh = (h+0x20-1) & ~0x1f;
+ nb = (bw * bh) / (32 * 32);
+ blocks = new IW44Image::Block[nb];
+ top = IWALLOCSIZE;
+}
+
+IW44Image::Map::~Map()
+{
+ while (chain)
+ {
+ IW44Image::Alloc *next = chain->next;
+ delete chain;
+ chain = next;
+ }
+ delete [] blocks;
+}
+
+short *
+IW44Image::Map::alloc(int n)
+{
+ if (top+n > IWALLOCSIZE)
+ {
+ IW44Image::Alloc *n = new IW44Image::Alloc;
+ n->next = chain;
+ chain = n;
+ top = 0;
+ }
+ short *ans = chain->data + top;
+ top += n;
+ memset((void*)ans, 0, sizeof(short)*n);
+ return ans;
+}
+
+short **
+IW44Image::Map::allocp(int n)
+{
+ // Allocate enough room for pointers plus alignment
+ short *p = alloc( (n+1) * sizeof(short*) / sizeof(short) );
+ // Align on pointer size
+ while ( ((long)p) & (sizeof(short*)-1) )
+ p += 1;
+ // Cast and return
+ return (short**)p;
+}
+
+int
+IW44Image::Map::get_bucket_count(void) const
+{
+ int buckets = 0;
+ for (int blockno=0; blockno<nb; blockno++)
+ for (int buckno=0; buckno<64; buckno++)
+ if (blocks[blockno].data(buckno))
+ buckets += 1;
+ return buckets;
+}
+
+unsigned int
+IW44Image::Map::get_memory_usage(void) const
+{
+ unsigned int usage = sizeof(Map);
+ usage += sizeof(IW44Image::Block) * nb;
+ for (IW44Image::Alloc *n = chain; n; n=n->next)
+ usage += sizeof(IW44Image::Alloc);
+ return usage;
+}
+
+
+
+
+void
+IW44Image::Map::image(signed char *img8, int rowsize, int pixsep, int fast)
+{
+ // Allocate reconstruction buffer
+ short *data16;
+ GPBuffer<short> gdata16(data16,bw*bh);
+ // Copy coefficients
+ int i;
+ short *p = data16;
+ const IW44Image::Block *block = blocks;
+ for (i=0; i<bh; i+=32)
+ {
+ for (int j=0; j<bw; j+=32)
+ {
+ short liftblock[1024];
+ // transfer into IW44Image::Block (apply zigzag and scaling)
+ block->write_liftblock(liftblock);
+ block++;
+ // transfer into coefficient matrix at (p+j)
+ short *pp = p + j;
+ short *pl = liftblock;
+ for (int ii=0; ii<32; ii++, pp+=bw,pl+=32)
+ memcpy((void*)pp, (void*)pl, 32*sizeof(short));
+ }
+ // next row of blocks
+ p += 32*bw;
+ }
+ // Reconstruction
+ if (fast)
+ {
+ IW44Image::Transform::Decode::backward(data16, iw, ih, bw, 32, 2);
+ p = data16;
+ for (i=0; i<bh; i+=2,p+=bw)
+ for (int jj=0; jj<bw; jj+=2,p+=2)
+ p[bw] = p[bw+1] = p[1] = p[0];
+ }
+ else
+ {
+ IW44Image::Transform::Decode::backward(data16, iw, ih, bw, 32, 1);
+ }
+ // Copy result into image
+ p = data16;
+ signed char *row = img8;
+ for (i=0; i<ih; i++)
+ {
+ signed char *pix = row;
+ for (int j=0; j<iw; j+=1,pix+=pixsep)
+ {
+ int x = (p[j] + iw_round) >> iw_shift;
+ if (x < -128)
+ x = -128;
+ else if (x > 127)
+ x = 127;
+ *pix = x;
+ }
+ row += rowsize;
+ p += bw;
+ }
+}
+
+void
+IW44Image::Map::image(int subsample, const GRect &rect,
+ signed char *img8, int rowsize, int pixsep, int fast)
+{
+ int i;
+ // Compute number of decomposition levels
+ int nlevel = 0;
+ while (nlevel<5 && (32>>nlevel)>subsample)
+ nlevel += 1;
+ int boxsize = 1<<nlevel;
+ // Parameter check
+ if (subsample!=(32>>nlevel))
+ G_THROW( ERR_MSG("IW44Image.sample_factor") );
+ if (rect.isempty())
+ G_THROW( ERR_MSG("IW44Image.empty_rect") );
+ GRect irect(0,0,(iw+subsample-1)/subsample,(ih+subsample-1)/subsample);
+ if (rect.xmin<0 || rect.ymin<0 || rect.xmax>irect.xmax || rect.ymax>irect.ymax)
+ G_THROW( ERR_MSG("IW44Image.bad_rect") );
+ // Multiresolution rectangles
+ // -- needed[i] tells which coeffs are required for the next step
+ // -- recomp[i] tells which coeffs need to be computed at this level
+ GRect needed[8];
+ GRect recomp[8];
+ int r = 1;
+ needed[nlevel] = rect;
+ recomp[nlevel] = rect;
+ for (i=nlevel-1; i>=0; i--)
+ {
+ needed[i] = recomp[i+1];
+ needed[i].inflate(iw_border*r, iw_border*r);
+ needed[i].intersect(needed[i], irect);
+ r += r;
+ recomp[i].xmin = (needed[i].xmin + r-1) & ~(r-1);
+ recomp[i].xmax = (needed[i].xmax) & ~(r-1);
+ recomp[i].ymin = (needed[i].ymin + r-1) & ~(r-1);
+ recomp[i].ymax = (needed[i].ymax) & ~(r-1);
+ }
+ // Working rectangle
+ // -- a rectangle large enough to hold all the data
+ GRect work;
+ work.xmin = (needed[0].xmin) & ~(boxsize-1);
+ work.ymin = (needed[0].ymin) & ~(boxsize-1);
+ work.xmax = ((needed[0].xmax-1) & ~(boxsize-1) ) + boxsize;
+ work.ymax = ((needed[0].ymax-1) & ~(boxsize-1) ) + boxsize;
+ // -- allocate work buffer
+ int dataw = work.xmax - work.xmin; // Note: cannot use inline width() or height()
+ int datah = work.ymax - work.ymin; // because Intel C++ compiler optimizes it wrong !
+ short *data;
+ GPBuffer<short> gdata(data,dataw*datah);
+ // Fill working rectangle
+ // -- loop over liftblocks rows
+ short *ldata = data;
+ int blkw = (bw>>5);
+ const IW44Image::Block *lblock = blocks + (work.ymin>>nlevel)*blkw + (work.xmin>>nlevel);
+ for (int by=work.ymin; by<work.ymax; by+=boxsize)
+ {
+ // -- loop over liftblocks in row
+ const IW44Image::Block *block = lblock;
+ short *rdata = ldata;
+ for (int bx=work.xmin; bx<work.xmax; bx+=boxsize)
+ {
+ // -- decide how much to load
+ int mlevel = nlevel;
+ if (nlevel>2)
+ if (bx+31<needed[2].xmin || bx>needed[2].xmax ||
+ by+31<needed[2].ymin || by>needed[2].ymax )
+ mlevel = 2;
+ int bmax = ((1<<(mlevel+mlevel))+15)>>4;
+ int ppinc = (1<<(nlevel-mlevel));
+ int ppmod1 = (dataw<<(nlevel-mlevel));
+ int ttmod0 = (32 >> mlevel);
+ int ttmod1 = (ttmod0 << 5);
+ // -- get current block
+ short liftblock[1024];
+ block->write_liftblock(liftblock, 0, bmax );
+ // -- copy liftblock into image
+ short *tt = liftblock;
+ short *pp = rdata;
+ for (int ii=0; ii<boxsize; ii+=ppinc,pp+=ppmod1,tt+=ttmod1-32)
+ for (int jj=0; jj<boxsize; jj+=ppinc,tt+=ttmod0)
+ pp[jj] = *tt;
+ // -- next block in row
+ rdata += boxsize;
+ block += 1;
+ }
+ // -- next row of blocks
+ ldata += dataw << nlevel;
+ lblock += blkw;
+ }
+ // Perform reconstruction
+ r = boxsize;
+ for (i=0; i<nlevel; i++)
+ {
+ GRect comp = needed[i];
+ comp.xmin = comp.xmin & ~(r-1);
+ comp.ymin = comp.ymin & ~(r-1);
+ comp.translate(-work.xmin, -work.ymin);
+ // Fast mode shortcuts finer resolution
+ if (fast && i>=4)
+ {
+ short *pp = data + comp.ymin*dataw;
+ for (int ii=comp.ymin; ii<comp.ymax; ii+=2, pp+=dataw+dataw)
+ for (int jj=comp.xmin; jj<comp.xmax; jj+=2)
+ pp[jj+dataw] = pp[jj+dataw+1] = pp[jj+1] = pp[jj];
+ break;
+ }
+ else
+ {
+ short *pp = data + comp.ymin*dataw + comp.xmin;
+ IW44Image::Transform::Decode::backward(pp, comp.width(), comp.height(), dataw, r, r>>1);
+ }
+ r = r>>1;
+ }
+ // Copy result into image
+ GRect nrect = rect;
+ nrect.translate(-work.xmin, -work.ymin);
+ short *p = data + nrect.ymin*dataw;
+ signed char *row = img8;
+ for (i=nrect.ymin; i<nrect.ymax; i++)
+ {
+ int j;
+ signed char *pix = row;
+ for (j=nrect.xmin; j<nrect.xmax; j+=1,pix+=pixsep)
+ {
+ int x = (p[j] + iw_round) >> iw_shift;
+ if (x < -128)
+ x = -128;
+ else if (x > 127)
+ x = 127;
+ *pix = x;
+ }
+ row += rowsize;
+ p += dataw;
+ }
+}
+
+
+
+
+//////////////////////////////////////////////////////
+// ENCODING/DECODING WAVELET COEFFICIENTS
+// USING HIERARCHICAL SET DIFFERENCE
+//////////////////////////////////////////////////////
+
+
+//-----------------------------------------------
+// Class IW44Image::Codec [implementation]
+// Maintains information shared while encoding or decoding
+
+
+// Constant
+
+static const struct { int start; int size; }
+bandbuckets[] =
+{
+ // Code first bucket and number of buckets in each band
+ { 0, 1 }, // -- band zero contains all lores info
+ { 1, 1 }, { 2, 1 }, { 3, 1 },
+ { 4, 4 }, { 8, 4 }, { 12,4 },
+ { 16,16 }, { 32,16 }, { 48,16 },
+};
+
+
+// IW44Image::Codec constructor
+
+IW44Image::Codec::Codec(IW44Image::Map &xmap)
+ : map(xmap),
+ curband(0),
+ curbit(1)
+{
+ // Initialize quantification
+ int j;
+ int i = 0;
+ const int *q = iw_quant;
+ // -- lo coefficients
+ for (j=0; i<4; j++)
+ quant_lo[i++] = *q++;
+ for (j=0; j<4; j++)
+ quant_lo[i++] = *q;
+ q += 1;
+ for (j=0; j<4; j++)
+ quant_lo[i++] = *q;
+ q += 1;
+ for (j=0; j<4; j++)
+ quant_lo[i++] = *q;
+ q += 1;
+ // -- hi coefficients
+ quant_hi[0] = 0;
+ for (j=1; j<10; j++)
+ quant_hi[j] = *q++;
+ // Initialize coding contexts
+ memset((void*)ctxStart, 0, sizeof(ctxStart));
+ memset((void*)ctxBucket, 0, sizeof(ctxBucket));
+ ctxMant = 0;
+ ctxRoot = 0;
+}
+
+
+// IW44Image::Codec destructor
+
+IW44Image::Codec::~Codec() {}
+
+// is_null_slice
+// -- check if data can be produced for this band/mask
+// -- also fills the sure_zero array
+
+int
+IW44Image::Codec::is_null_slice(int bit, int band)
+{
+ if (band == 0)
+ {
+ int is_null = 1;
+ for (int i=0; i<16; i++)
+ {
+ int threshold = quant_lo[i];
+ coeffstate[i] = ZERO;
+ if (threshold>0 && threshold<0x8000)
+ {
+ coeffstate[i] = UNK;
+ is_null = 0;
+ }
+ }
+ return is_null;
+ }
+ else
+ {
+ int threshold = quant_hi[band];
+ return (! (threshold>0 && threshold<0x8000));
+ }
+}
+
+
+// code_slice
+// -- read/write a slice of datafile
+
+int
+IW44Image::Codec::Decode::code_slice(ZPCodec &zp)
+{
+ // Check that code_slice can still run
+ if (curbit < 0)
+ return 0;
+ // Perform coding
+ if (! is_null_slice(curbit, curband))
+ {
+ for (int blockno=0; blockno<map.nb; blockno++)
+ {
+ int fbucket = bandbuckets[curband].start;
+ int nbucket = bandbuckets[curband].size;
+ decode_buckets(zp, curbit, curband,
+ map.blocks[blockno],
+ fbucket, nbucket);
+ }
+ }
+ return finish_code_slice(zp);
+}
+
+// code_slice
+// -- read/write a slice of datafile
+
+int
+IW44Image::Codec::finish_code_slice(ZPCodec &zp)
+{
+ // Reduce quantization threshold
+ quant_hi[curband] = quant_hi[curband] >> 1;
+ if (curband == 0)
+ for (int i=0; i<16; i++)
+ quant_lo[i] = quant_lo[i] >> 1;
+ // Proceed to the next slice
+ if (++curband >= (int)(sizeof(bandbuckets)/sizeof(bandbuckets[0])))
+ {
+ curband = 0;
+ curbit += 1;
+ if (quant_hi[(sizeof(bandbuckets)/sizeof(bandbuckets[0]))-1] == 0)
+ {
+ // All quantization thresholds are null
+ curbit = -1;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+// decode_prepare
+// -- prepare the states before decoding buckets
+
+int
+IW44Image::Codec::decode_prepare(int fbucket, int nbucket, IW44Image::Block &blk)
+{
+ int bbstate = 0;
+ char *cstate = coeffstate;
+ if (fbucket)
+ {
+ // Band other than zero
+ for (int buckno=0; buckno<nbucket; buckno++, cstate+=16)
+ {
+ int bstatetmp = 0;
+ const short *pcoeff = blk.data(fbucket+buckno);
+ if (! pcoeff)
+ {
+ // cstate[0..15] will be filled later
+ bstatetmp = UNK;
+ }
+ else
+ {
+ for (int i=0; i<16; i++)
+ {
+ int cstatetmp = UNK;
+ if (pcoeff[i])
+ cstatetmp = ACTIVE;
+ cstate[i] = cstatetmp;
+ bstatetmp |= cstatetmp;
+ }
+ }
+ bucketstate[buckno] = bstatetmp;
+ bbstate |= bstatetmp;
+ }
+ }
+ else
+ {
+ // Band zero ( fbucket==0 implies band==zero and nbucket==1 )
+ const short *pcoeff = blk.data(0);
+ if (! pcoeff)
+ {
+ // cstate[0..15] will be filled later
+ bbstate = UNK;
+ }
+ else
+ {
+ for (int i=0; i<16; i++)
+ {
+ int cstatetmp = cstate[i];
+ if (cstatetmp != ZERO)
+ {
+ cstatetmp = UNK;
+ if (pcoeff[i])
+ cstatetmp = ACTIVE;
+ }
+ cstate[i] = cstatetmp;
+ bbstate |= cstatetmp;
+ }
+ }
+ bucketstate[0] = bbstate;
+ }
+ return bbstate;
+}
+
+
+// decode_buckets
+// -- code a sequence of buckets in a given block
+
+void
+IW44Image::Codec::decode_buckets(ZPCodec &zp, int bit, int band,
+ IW44Image::Block &blk,
+ int fbucket, int nbucket)
+{
+ // compute state of all coefficients in all buckets
+ int bbstate = decode_prepare(fbucket, nbucket, blk);
+ // code root bit
+ if ((nbucket<16) || (bbstate&ACTIVE))
+ {
+ bbstate |= NEW;
+ }
+ else if (bbstate & UNK)
+ {
+ if (zp.decoder(ctxRoot))
+ bbstate |= NEW;
+#ifdef TRACE
+ DjVuPrintMessage("bbstate[bit=%d,band=%d] = %d\n", bit, band, bbstate);
+#endif
+ }
+
+ // code bucket bits
+ if (bbstate & NEW)
+ for (int buckno=0; buckno<nbucket; buckno++)
+ {
+ // Code bucket bit
+ if (bucketstate[buckno] & UNK)
+ {
+ // Context
+ int ctx = 0;
+#ifndef NOCTX_BUCKET_UPPER
+ if (band>0)
+ {
+ int k = (fbucket+buckno)<<2;
+ const short *b = blk.data(k>>4);
+ if (b)
+ {
+ k = k & 0xf;
+ if (b[k])
+ ctx += 1;
+ if (b[k+1])
+ ctx += 1;
+ if (b[k+2])
+ ctx += 1;
+ if (ctx<3 && b[k+3])
+ ctx += 1;
+ }
+ }
+#endif // NOCTX_BUCKET_UPPER
+#ifndef NOCTX_BUCKET_ACTIVE
+ if (bbstate & ACTIVE)
+ ctx |= 4;
+#endif
+ // Code
+ if (zp.decoder( ctxBucket[band][ctx] ))
+ bucketstate[buckno] |= NEW;
+#ifdef TRACE
+ DjVuPrintMessage(" bucketstate[bit=%d,band=%d,buck=%d] = %d\n",
+ bit, band, buckno, bucketstate[buckno]);
+#endif
+ }
+ }
+
+ // code new active coefficient (with their sign)
+ if (bbstate & NEW)
+ {
+ int thres = quant_hi[band];
+ char *cstate = coeffstate;
+ for (int buckno=0; buckno<nbucket; buckno++, cstate+=16)
+ if (bucketstate[buckno] & NEW)
+ {
+ int i;
+ short *pcoeff = (short*)blk.data(fbucket+buckno);
+ if (!pcoeff)
+ {
+ pcoeff = blk.data(fbucket+buckno, &map);
+ // time to fill cstate[0..15]
+ if (fbucket == 0) // band zero
+ {
+ for (i=0; i<16; i++)
+ if (cstate[i] != ZERO)
+ cstate[i] = UNK;
+ }
+ else
+ {
+ for (i=0; i<16; i++)
+ cstate[i] = UNK;
+ }
+ }
+#ifndef NOCTX_EXPECT
+ int gotcha = 0;
+ const int maxgotcha = 7;
+ for (i=0; i<16; i++)
+ if (cstate[i] & UNK)
+ gotcha += 1;
+#endif
+ for (i=0; i<16; i++)
+ {
+ if (cstate[i] & UNK)
+ {
+ // find lores threshold
+ if (band == 0)
+ thres = quant_lo[i];
+ // prepare context
+ int ctx = 0;
+#ifndef NOCTX_EXPECT
+ if (gotcha>=maxgotcha)
+ ctx = maxgotcha;
+ else
+ ctx = gotcha;
+#endif
+#ifndef NOCTX_ACTIVE
+ if (bucketstate[buckno] & ACTIVE)
+ ctx |= 8;
+#endif
+ // code difference bit
+ if (zp.decoder( ctxStart[ctx] ))
+ {
+ cstate[i] |= NEW;
+ int halfthres = thres>>1;
+ int coeff = thres+halfthres-(halfthres>>2);
+ if (zp.IWdecoder())
+ pcoeff[i] = -coeff;
+ else
+ pcoeff[i] = coeff;
+ }
+#ifndef NOCTX_EXPECT
+ if (cstate[i] & NEW)
+ gotcha = 0;
+ else if (gotcha > 0)
+ gotcha -= 1;
+#endif
+#ifdef TRACE
+ DjVuPrintMessage(" coeffstate[bit=%d,band=%d,buck=%d,c=%d] = %d\n",
+ bit, band, buckno, i, cstate[i]);
+#endif
+ }
+ }
+ }
+ }
+
+ // code mantissa bits
+ if (bbstate & ACTIVE)
+ {
+ int thres = quant_hi[band];
+ char *cstate = coeffstate;
+ for (int buckno=0; buckno<nbucket; buckno++, cstate+=16)
+ if (bucketstate[buckno] & ACTIVE)
+ {
+ short *pcoeff = (short*)blk.data(fbucket+buckno);
+ for (int i=0; i<16; i++)
+ if (cstate[i] & ACTIVE)
+ {
+ int coeff = pcoeff[i];
+ if (coeff < 0)
+ coeff = -coeff;
+ // find lores threshold
+ if (band == 0)
+ thres = quant_lo[i];
+ // adjust coefficient
+ if (coeff <= 3*thres)
+ {
+ // second mantissa bit
+ coeff = coeff + (thres>>2);
+ if (zp.decoder(ctxMant))
+ coeff = coeff + (thres>>1);
+ else
+ coeff = coeff - thres + (thres>>1);
+ }
+ else
+ {
+ if (zp.IWdecoder())
+ coeff = coeff + (thres>>1);
+ else
+ coeff = coeff - thres + (thres>>1);
+ }
+ // store coefficient
+ if (pcoeff[i] > 0)
+ pcoeff[i] = coeff;
+ else
+ pcoeff[i] = -coeff;
+ }
+ }
+ }
+}
+
+
+//////////////////////////////////////////////////////
+// UTILITIES
+//////////////////////////////////////////////////////
+
+
+#ifdef min
+#undef min
+#endif
+static inline int
+min(const int x, const int y)
+{
+ return (x <= y) ? x : y;
+}
+
+#ifdef max
+#undef max
+#endif
+static inline int
+max(const int x, const int y)
+{
+ return (y <= x) ? x : y;
+}
+
+
+void
+IW44Image::PrimaryHeader::decode(GP<ByteStream> gbs)
+{
+ serial = gbs->read8();
+ slices = gbs->read8();
+}
+
+void
+IW44Image::SecondaryHeader::decode(GP<ByteStream> gbs)
+{
+ major = gbs->read8();
+ minor = gbs->read8();
+}
+
+void
+IW44Image::TertiaryHeader::decode(GP<ByteStream> gbs, int major, int minor)
+{
+ xhi = gbs->read8();
+ xlo = gbs->read8();
+ yhi = gbs->read8();
+ ylo = gbs->read8();
+ crcbdelay = 0;
+ if (major== 1 && minor>=2)
+ crcbdelay = gbs->read8();
+}
+
+
+
+//////////////////////////////////////////////////////
+// CLASS IW44Image
+//////////////////////////////////////////////////////
+
+IW44Image::IW44Image(void)
+ : db_frac(1.0),
+ ymap(0), cbmap(0), crmap(0),
+ cslice(0), cserial(0), cbytes(0)
+{}
+
+IW44Image::~IW44Image()
+{
+ delete ymap;
+ delete cbmap;
+ delete crmap;
+}
+
+GP<IW44Image>
+IW44Image::create_decode(const ImageType itype)
+{
+ switch(itype)
+ {
+ case COLOR:
+ return new IWPixmap();
+ case GRAY:
+ return new IWBitmap();
+ default:
+ return 0;
+ }
+}
+
+int
+IW44Image::encode_chunk(GP<ByteStream>, const IWEncoderParms &)
+{
+ G_THROW( ERR_MSG("IW44Image.codec_open2") );
+ return 0;
+}
+
+void
+IW44Image::encode_iff(IFFByteStream &, int nchunks, const IWEncoderParms *)
+{
+ G_THROW( ERR_MSG("IW44Image.codec_open2") );
+}
+
+
+void
+IWBitmap::close_codec(void)
+{
+ delete ycodec;
+ ycodec = 0;
+ cslice = cbytes = cserial = 0;
+}
+
+void
+IWPixmap::close_codec(void)
+{
+ delete ycodec;
+ delete cbcodec;
+ delete crcodec;
+ ycodec = crcodec = cbcodec = 0;
+ cslice = cbytes = cserial = 0;
+}
+
+int
+IW44Image::get_width(void) const
+{
+ return (ymap)?(ymap->iw):0;
+}
+
+int
+IW44Image::get_height(void) const
+{
+ return (ymap)?(ymap->ih):0;
+}
+
+
+//////////////////////////////////////////////////////
+// CLASS IWBITMAP
+//////////////////////////////////////////////////////
+
+IWBitmap::IWBitmap(void )
+: IW44Image(), ycodec(0)
+{}
+
+IWBitmap::~IWBitmap()
+{
+ close_codec();
+}
+
+int
+IWBitmap::get_percent_memory(void) const
+{
+ int buckets = 0;
+ int maximum = 0;
+ if (ymap)
+ {
+ buckets += ymap->get_bucket_count();
+ maximum += 64 * ymap->nb;
+ }
+ return 100*buckets/ (maximum ? maximum : 1);
+}
+
+unsigned int
+IWBitmap::get_memory_usage(void) const
+{
+ unsigned int usage = sizeof(GBitmap);
+ if (ymap)
+ usage += ymap->get_memory_usage();
+ return usage;
+}
+
+
+GP<GBitmap>
+IWBitmap::get_bitmap(void)
+{
+ // Check presence of data
+ if (ymap == 0)
+ return 0;
+ // Perform wavelet reconstruction
+ int w = ymap->iw;
+ int h = ymap->ih;
+ GP<GBitmap> pbm = GBitmap::create(h, w);
+ ymap->image((signed char*)(*pbm)[0],pbm->rowsize());
+ // Shift image data
+ for (int i=0; i<h; i++)
+ {
+ unsigned char *urow = (*pbm)[i];
+ signed char *srow = (signed char*)urow;
+ for (int j=0; j<w; j++)
+ urow[j] = (int)(srow[j]) + 128;
+ }
+ pbm->set_grays(256);
+ return pbm;
+}
+
+
+GP<GBitmap>
+IWBitmap::get_bitmap(int subsample, const GRect &rect)
+{
+ if (ymap == 0)
+ return 0;
+ // Allocate bitmap
+ int w = rect.width();
+ int h = rect.height();
+ GP<GBitmap> pbm = GBitmap::create(h,w);
+ ymap->image(subsample, rect, (signed char*)(*pbm)[0],pbm->rowsize());
+ // Shift image data
+ for (int i=0; i<h; i++)
+ {
+ unsigned char *urow = (*pbm)[i];
+ signed char *srow = (signed char*)urow;
+ for (int j=0; j<w; j++)
+ urow[j] = (int)(srow[j]) + 128;
+ }
+ pbm->set_grays(256);
+ return pbm;
+}
+
+
+int
+IWBitmap::decode_chunk(GP<ByteStream> gbs)
+{
+ // Open
+ if (! ycodec)
+ {
+ cslice = cserial = 0;
+ delete ymap;
+ ymap = 0;
+ }
+ // Read primary header
+ struct IW44Image::PrimaryHeader primary;
+ primary.decode(gbs);
+ if (primary.serial != cserial)
+ G_THROW( ERR_MSG("IW44Image.wrong_serial") );
+ int nslices = cslice + primary.slices;
+ // Read auxilliary headers
+ if (cserial == 0)
+ {
+ struct IW44Image::SecondaryHeader secondary;
+ secondary.decode(gbs);
+ if ((secondary.major & 0x7f) != IWCODEC_MAJOR)
+ G_THROW( ERR_MSG("IW44Image.incompat_codec") );
+ if (secondary.minor > IWCODEC_MINOR)
+ G_THROW( ERR_MSG("IW44Image.recent_codec") );
+ // Read tertiary header
+ struct IW44Image::TertiaryHeader tertiary;
+ tertiary.decode(gbs, secondary.major & 0x7f, secondary.minor);
+ if (! (secondary.major & 0x80))
+ G_THROW( ERR_MSG("IW44Image.has_color") );
+ // Create ymap and ycodec
+ int w = (tertiary.xhi << 8) | tertiary.xlo;
+ int h = (tertiary.yhi << 8) | tertiary.ylo;
+ assert(! ymap);
+ ymap = new Map(w, h);
+ assert(! ycodec);
+ ycodec = new Codec::Decode(*ymap);
+ }
+ // Read data
+ assert(ymap);
+ assert(ycodec);
+ GP<ZPCodec> gzp=ZPCodec::create(gbs, false, true);
+ ZPCodec &zp=*gzp;
+ int flag = 1;
+ while (flag && cslice<nslices)
+ {
+ flag = ycodec->code_slice(zp);
+ cslice++;
+ }
+ // Return
+ cserial += 1;
+ return nslices;
+}
+
+void
+IWBitmap::parm_dbfrac(float frac)
+{
+ if (frac>0 && frac<=1)
+ db_frac = frac;
+ else
+ G_THROW( ERR_MSG("IW44Image.param_range") );
+}
+
+
+int
+IWBitmap::get_serial(void)
+{
+ return cserial;
+}
+
+void
+IWBitmap::decode_iff(IFFByteStream &iff, int maxchunks)
+{
+ if (ycodec)
+ G_THROW( ERR_MSG("IW44Image.left_open2") );
+ GUTF8String chkid;
+ iff.get_chunk(chkid);
+ if (chkid != "FORM:BM44")
+ G_THROW( ERR_MSG("IW44Image.corrupt_BM44") );
+ while (--maxchunks>=0 && iff.get_chunk(chkid))
+ {
+ if (chkid == "BM44")
+ decode_chunk(iff.get_bytestream());
+ iff.close_chunk();
+ }
+ iff.close_chunk();
+ close_codec();
+}
+
+
+
+
+//////////////////////////////////////////////////////
+// CLASS IWENCODERPARMS
+//////////////////////////////////////////////////////
+
+
+IWEncoderParms::IWEncoderParms(void)
+{
+ // Zero represent default values
+ memset((void*)this, 0, sizeof(IWEncoderParms));
+}
+
+
+
+
+
+//////////////////////////////////////////////////////
+// CLASS IWPIXMAP
+//////////////////////////////////////////////////////
+
+
+IWPixmap::IWPixmap(void)
+: IW44Image(), crcb_delay(10), crcb_half(0), ycodec(0), cbcodec(0), crcodec(0)
+{}
+
+IWPixmap::~IWPixmap()
+{
+ close_codec();
+}
+
+int
+IWPixmap::get_percent_memory(void) const
+{
+ int buckets = 0;
+ int maximum = 0;
+ if (ymap)
+ {
+ buckets += ymap->get_bucket_count();
+ maximum += 64*ymap->nb;
+ }
+ if (cbmap)
+ {
+ buckets += cbmap->get_bucket_count();
+ maximum += 64*cbmap->nb;
+ }
+ if (crmap)
+ {
+ buckets += crmap->get_bucket_count();
+ maximum += 64*crmap->nb;
+ }
+ return 100*buckets/ (maximum ? maximum : 1);
+}
+
+unsigned int
+IWPixmap::get_memory_usage(void) const
+{
+ unsigned int usage = sizeof(GPixmap);
+ if (ymap)
+ usage += ymap->get_memory_usage();
+ if (cbmap)
+ usage += cbmap->get_memory_usage();
+ if (crmap)
+ usage += crmap->get_memory_usage();
+ return usage;
+}
+
+
+GP<GPixmap>
+IWPixmap::get_pixmap(void)
+{
+ // Check presence of data
+ if (ymap == 0)
+ return 0;
+ // Allocate pixmap
+ int w = ymap->iw;
+ int h = ymap->ih;
+ GP<GPixmap> ppm = GPixmap::create(h, w);
+ // Perform wavelet reconstruction
+ signed char *ptr = (signed char*) (*ppm)[0];
+ int rowsep = ppm->rowsize() * sizeof(GPixel);
+ int pixsep = sizeof(GPixel);
+ ymap->image(ptr, rowsep, pixsep);
+ if (crmap && cbmap && crcb_delay >= 0)
+ {
+ cbmap->image(ptr+1, rowsep, pixsep, crcb_half);
+ crmap->image(ptr+2, rowsep, pixsep, crcb_half);
+ }
+ // Convert image data to RGB
+ if (crmap && cbmap && crcb_delay >= 0)
+ {
+ Transform::Decode::YCbCr_to_RGB((*ppm)[0], w, h, ppm->rowsize());
+ }
+ else
+ {
+ for (int i=0; i<h; i++)
+ {
+ GPixel *pixrow = (*ppm)[i];
+ for (int j=0; j<w; j++, pixrow++)
+ pixrow->b = pixrow->g = pixrow->r
+ = 127 - (int)(((signed char*)pixrow)[0]);
+ }
+ }
+ // Return
+ return ppm;
+}
+
+
+
+GP<GPixmap>
+IWPixmap::get_pixmap(int subsample, const GRect &rect)
+{
+ if (ymap == 0)
+ return 0;
+ // Allocate
+ int w = rect.width();
+ int h = rect.height();
+ GP<GPixmap> ppm = GPixmap::create(h,w);
+ // Perform wavelet reconstruction
+ signed char *ptr = (signed char*) (*ppm)[0];
+ int rowsep = ppm->rowsize() * sizeof(GPixel);
+ int pixsep = sizeof(GPixel);
+ ymap->image(subsample, rect, ptr, rowsep, pixsep);
+ if (crmap && cbmap && crcb_delay >= 0)
+ {
+ cbmap->image(subsample, rect, ptr+1, rowsep, pixsep, crcb_half);
+ crmap->image(subsample, rect, ptr+2, rowsep, pixsep, crcb_half);
+ }
+ // Convert image data to RGB
+ if (crmap && cbmap && crcb_delay >= 0)
+ {
+ Transform::Decode::YCbCr_to_RGB((*ppm)[0], w, h, ppm->rowsize());
+ }
+ else
+ {
+ for (int i=0; i<h; i++)
+ {
+ GPixel *pixrow = (*ppm)[i];
+ for (int j=0; j<w; j++, pixrow++)
+ pixrow->b = pixrow->g = pixrow->r
+ = 127 - (int)(((signed char*)pixrow)[0]);
+ }
+ }
+ // Return
+ return ppm;
+}
+
+
+int
+IWPixmap::decode_chunk(GP<ByteStream> gbs)
+{
+ // Open
+ if (! ycodec)
+ {
+ cslice = cserial = 0;
+ delete ymap;
+ ymap = 0;
+ }
+
+ // Read primary header
+ struct IW44Image::PrimaryHeader primary;
+ primary.decode(gbs);
+ if (primary.serial != cserial)
+ G_THROW( ERR_MSG("IW44Image.wrong_serial2") );
+ int nslices = cslice + primary.slices;
+ // Read secondary header
+ if (cserial == 0)
+ {
+ struct IW44Image::SecondaryHeader secondary;
+ secondary.decode(gbs);
+ if ((secondary.major & 0x7f) != IWCODEC_MAJOR)
+ G_THROW( ERR_MSG("IW44Image.incompat_codec2") );
+ if (secondary.minor > IWCODEC_MINOR)
+ G_THROW( ERR_MSG("IW44Image.recent_codec2") );
+ // Read tertiary header
+ struct IW44Image::TertiaryHeader tertiary;
+ tertiary.decode(gbs, secondary.major & 0x7f, secondary.minor);
+ // Handle header information
+ int w = (tertiary.xhi << 8) | tertiary.xlo;
+ int h = (tertiary.yhi << 8) | tertiary.ylo;
+ crcb_delay = 0;
+ crcb_half = 0;
+ if (secondary.minor>=2)
+ crcb_delay = tertiary.crcbdelay & 0x7f;
+ if (secondary.minor>=2)
+ crcb_half = (tertiary.crcbdelay & 0x80 ? 0 : 1);
+ if (secondary.major & 0x80)
+ crcb_delay = -1;
+ // Create ymap and ycodec
+ assert(! ymap);
+ assert(! ycodec);
+ ymap = new Map(w, h);
+ ycodec = new Codec::Decode(*ymap);
+ if (crcb_delay >= 0)
+ {
+ cbmap = new Map(w, h);
+ crmap = new Map(w, h);
+ cbcodec = new Codec::Decode(*cbmap);
+ crcodec = new Codec::Decode(*crmap);
+ }
+ }
+ // Read data
+ assert(ymap);
+ assert(ycodec);
+ GP<ZPCodec> gzp=ZPCodec::create(gbs, false, true);
+ ZPCodec &zp=*gzp;
+ int flag = 1;
+ while (flag && cslice<nslices)
+ {
+ flag = ycodec->code_slice(zp);
+ if (crcodec && cbcodec && crcb_delay<=cslice)
+ {
+ flag |= cbcodec->code_slice(zp);
+ flag |= crcodec->code_slice(zp);
+ }
+ cslice++;
+ }
+ // Return
+ cserial += 1;
+ return nslices;
+}
+
+
+int
+IWPixmap::parm_crcbdelay(const int parm)
+{
+ if (parm >= 0)
+ crcb_delay = parm;
+ return crcb_delay;
+}
+
+void
+IWPixmap::parm_dbfrac(float frac)
+{
+ if (frac>0 && frac<=1)
+ db_frac = frac;
+ else
+ G_THROW( ERR_MSG("IW44Image.param_range2") );
+}
+
+int
+IWPixmap::get_serial(void)
+{
+ return cserial;
+}
+
+
+void
+IWPixmap::decode_iff(IFFByteStream &iff, int maxchunks)
+{
+ if (ycodec)
+ G_THROW( ERR_MSG("IW44Image.left_open4") );
+ GUTF8String chkid;
+ iff.get_chunk(chkid);
+ if (chkid!="FORM:PM44" && chkid!="FORM:BM44")
+ G_THROW( ERR_MSG("IW44Image.corrupt_BM44_2") );
+ while (--maxchunks>=0 && iff.get_chunk(chkid))
+ {
+ if (chkid=="PM44" || chkid=="BM44")
+ decode_chunk(iff.get_bytestream());
+ iff.close_chunk();
+ }
+ iff.close_chunk();
+ close_codec();
+}
+
+//////////////////////////////////////////////////////
+// NEW FILTERS
+//////////////////////////////////////////////////////
+
+void
+IW44Image::Transform::filter_begin(int w, int h)
+{
+ if (MMXControl::mmxflag < 0)
+ MMXControl::enable_mmx();
+}
+
+
+void
+IW44Image::Transform::filter_end(void)
+{
+#ifdef MMX
+ if (MMXControl::mmxflag > 0)
+ MMXemms;
+#endif
+}
+
+
+//////////////////////////////////////////////////////
+// WAVELET TRANSFORM
+//////////////////////////////////////////////////////
+
+
+//----------------------------------------------------
+// Function for applying bidimensional IW44 between
+// scale intervals begin(inclusive) and end(exclusive)
+
+void
+IW44Image::Transform::Decode::backward(short *p, int w, int h, int rowsize, int begin, int end)
+{
+ // PREPARATION
+ filter_begin(w,h);
+ // LOOP ON SCALES
+ for (int scale=begin>>1; scale>=end; scale>>=1)
+ {
+#ifdef IWTRANSFORM_TIMER
+ int tv,th;
+ th = tv = GOS::ticks();
+#endif
+ filter_bv(p, w, h, rowsize, scale);
+#ifdef IWTRANSFORM_TIMER
+ th = GOS::ticks();
+ tv = th - tv;
+#endif
+ filter_bh(p, w, h, rowsize, scale);
+#ifdef IWTRANSFORM_TIMER
+ th = GOS::ticks()-th;
+ DjVuPrintErrorUTF8("back%d\tv=%dms h=%dms\n", scale,tv,th);
+#endif
+ }
+ // TERMINATE
+ filter_end();
+}
+
+
+
+
+//////////////////////////////////////////////////////
+// COLOR TRANSFORM
+//////////////////////////////////////////////////////
+
+/* Converts YCbCr to RGB. */
+void
+IW44Image::Transform::Decode::YCbCr_to_RGB(GPixel *p, int w, int h, int rowsize)
+{
+ for (int i=0; i<h; i++,p+=rowsize)
+ {
+ GPixel *q = p;
+ for (int j=0; j<w; j++,q++)
+ {
+ signed char y = ((signed char*)q)[0];
+ signed char b = ((signed char*)q)[1];
+ signed char r = ((signed char*)q)[2];
+ // This is the Pigeon transform
+ int t1 = b >> 2 ;
+ int t2 = r + (r >> 1);
+ int t3 = y + 128 - t1;
+ int tr = y + 128 + t2;
+ int tg = t3 - (t2 >> 1);
+ int tb = t3 + (b << 1);
+ q->r = max(0,min(255,tr));
+ q->g = max(0,min(255,tg));
+ q->b = max(0,min(255,tb));
+ }
+ }
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/IW44Image.h b/kviewshell/plugins/djvu/libdjvu/IW44Image.h
new file mode 100644
index 00000000..56cf00fa
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/IW44Image.h
@@ -0,0 +1,761 @@
+//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: IW44Image.h,v 1.11 2003/11/07 22:08:22 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef IW44IMAGE_H_
+#define IW44IMAGE_H_
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+/** @name IW44Image.h
+
+ Files #"IW44Image.h"# and #"IW44Image.cpp"# implement the DjVu IW44 wavelet
+ scheme for the compression of gray-level images (see class \Ref{IWBitmap})
+ and color images (see class \Ref{IWPixmap}). Programs \Ref{c44} and
+ \Ref{d44} demonstrate how to encode and decode IW44 files.
+
+ {\bf IW44 File Structure} --- The IW44 files are structured according to
+ the EA IFF85 specifications (see \Ref{IFFByteStream.h}). Gray level IW44
+ Images consist of a single #"FORM:BM44"# chunk composed of an arbitrary
+ number of #"BM44"# data chunks. Color IW44 Images consist of a single
+ #"FORM:PM44"# chunk composed of an arbitrary number of #"PM44"# data
+ chunks. The successive #"PM44"# or #"BM44"# data chunks contain
+ successive refinements of the encoded image. Each chunk contains a
+ certain number of ``data slices''. The first chunk also contains a small
+ image header. You can use program \Ref{djvuinfo} to display all this
+ structural information:
+ \begin{verbatim}
+ % djvuinfo lag.iw4
+ lag.iw4:
+ FORM:PM44 [62598]
+ PM44 [10807] #1 - 74 slices - v1.2 (color) - 684x510
+ PM44 [23583] #2 - 13 slices
+ PM44 [28178] #3 - 10 slices
+ \end{verbatim}
+
+ {\bf Embedded IW44 Images} --- These IW44 data chunks can also appear within
+ other contexts. Files representing a DjVu page, for instance, consist of
+ a single #"FORM:DJVU"# composite chunk. This composite chunk may contain
+ #"BG44"# chunks encoding the background layer and #"FG44"# chunks encoding
+ the foreground color layer. These #"BG44"# and #"FG44"# chunks are
+ actually regular IW44 data chunks with a different chunk identifier. This
+ information too can be displayed using program \Ref{djvuinfo}.
+ \begin{verbatim}
+ % djvuinfo graham1.djvu
+ graham1.djvu:
+ FORM:DJVU [32553]
+ INFO [5] 3156x2325, version 17
+ Sjbz [17692]
+ BG44 [2570] #1 - 74 slices - v1.2 (color) - 1052x775
+ FG44 [1035] #1 - 100 slices - v1.2 (color) - 263x194
+ BG44 [3048] #2 - 10 slices
+ BG44 [894] #3 - 4 slices
+ BG44 [7247] #4 - 9 slices
+ \end{verbatim}
+
+ {\bf Performance} --- The main design objective for the DjVu wavelets
+ consisted of allowing progressive rendering and smooth scrolling of large
+ images with limited memory requirements. Decoding functions process the
+ compressed data and update a memory efficient representation of the
+ wavelet coefficients. Imaging function then can quickly render an
+ arbitrary segment of the image using the available data. Both process can
+ be carried out in two threads of execution. This design plays an
+ important role in the DjVu system. We have investigated various
+ state-of-the-art wavelet compression schemes: although these schemes may
+ achieve slightly smaller file sizes, the decoding functions did not even
+ approach our requirements.
+
+ The IW44 wavelets satisfy these requirements today. It performs very well
+ for quality settings resulting in high compression ratios. It should not
+ be used for quasi-lossless compression because certain design choices
+ deliberately sacrifice the IW44 quasi-lossless performance in order to
+ improve the image quality at high compression ratios.
+
+ Little care however has been taken to make the IW44 encoder memory
+ efficient. This code uses two copies of the wavelet coefficient data
+ structure (one for the raw coefficients, one for the quantized
+ coefficients). A more sophisticated implementation should considerably
+ reduce the memory requirements.
+
+ {\bf Masking} --- When we create a DjVu image, we often know that certain
+ pixels of the background image are going to be covered by foreground
+ objects like text or drawings. The DjVu IW44 wavelet decomposition
+ routine can use an optional bilevel image named the mask. Every non zero
+ pixel in the mask means the value of the corresponding pixel in the
+ background image is irrelevant. The wavelet decomposition code will
+ replace these masked pixels by a color value whose coding cost is minimal
+ (see \URL{http://www.research.att.com/~leonb/DJVU/mask}).
+
+ {\bf ToDo} --- There are many improvements to be made. Besides better
+ quantization algorithms (such as trellis quantization and bitrate
+ allocation), we should allow for more wavelet transforms. These
+ improvements may be implemented in future version, if (and only if) they
+ can meet our decoding constraints. Future versions will probably split
+ file #"IW44Image.cpp"# which currently contains everything.
+
+ @memo
+ Wavelet encoded images.
+ @author
+ L\'eon Bottou <leonb@research.att.com>
+
+// From: Leon Bottou, 1/31/2002
+// Lizardtech has split the corresponding cpp file into a decoder and an encoder.
+// Only superficial changes. The meat is mine.
+
+ @version
+ #$Id: IW44Image.h,v 1.11 2003/11/07 22:08:22 leonb Exp $# */
+//@{
+
+
+#include "GSmartPointer.h"
+#include "ZPCodec.h"
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+class GRect;
+class IFFByteStream;
+class ByteStream;
+class GBitmap;
+class GPixmap;
+
+
+
+/** IW44 encoding parameters.
+ This data structure gathers the quality specification parameters needed
+ for encoding each chunk of an IW44 file. Chunk data is generated until
+ meeting either the slice target, the size target or the decibel target. */
+
+struct IWEncoderParms
+{
+ /** Slice target. Data generation for the current chunk stops if the total
+ number of slices (in this chunk and all the previous chunks) reaches
+ value #slice#. The default value #0# has a special meaning: data will
+ be generated regardless of the number of slices in the file. */
+ int slices;
+ /** Size target. Data generation for the current chunk stops if the total
+ data size (in this chunk and all the previous chunks), expressed in
+ bytes, reaches value #size#. The default value #0# has a special
+ meaning: data will be generated regardless of the file size. */
+ int bytes;
+ /** Decibel target. Data generation for the current chunk stops if the
+ estimated luminance error, expressed in decibels, reaches value
+ #decibel#. The default value #0# has a special meaning: data will be
+ generated regardless of the estimated luminance error. Specifying value
+ #0# in fact shortcuts the computation of the estimated luminance error
+ and sensibly speeds up the encoding process. */
+ float decibels;
+ /** Constructor. Initializes the structure with the default values. */
+ IWEncoderParms(void);
+};
+
+
+
+/** IW44 encoded gray-level and color images. This class acts as a base for
+ images represented as a collection of IW44 wavelet coefficients. The
+ coefficients are stored in a memory efficient data structure. Member
+ function \Ref{get_bitmap} renders an arbitrary segment of the image into
+ a \Ref{GBitmap}. Member functions \Ref{decode_iff} and \Ref{encode_iff}
+ read and write DjVu IW44 files (see \Ref{IW44Image.h}). Both the copy
+ constructor and the copy operator are declared as private members. It is
+ therefore not possible to make multiple copies of instances of this
+ class. */
+
+class IW44Image : public GPEnabled
+{
+public:
+ /** Chrominance processing selector. The following constants may be used as
+ argument to the following \Ref{IWPixmap} constructor to indicate how the
+ chrominance information should be processed. There are four possible values:
+ \begin{description}
+ \item[CRCBnone:] The wavelet transform will discard the chrominance
+ information and only keep the luminance. The image will show in shades of gray.
+ \item[CRCBhalf:] The wavelet transform will process the chrominance at only
+ half the image resolution. This option creates smaller files but may create
+ artifacts in highly colored images.
+ \item[CRCBnormal:] The wavelet transform will process the chrominance at full
+ resolution. This is the default.
+ \item[CRCBfull:] The wavelet transform will process the chrominance at full
+ resolution. This option also disables the chrominance encoding delay
+ (see \Ref{parm_crcbdelay}) which usually reduces the bitrate associated with the
+ chrominance information.
+ \end{description} */
+ enum CRCBMode {
+ CRCBnone,
+ CRCBhalf,
+ CRCBnormal,
+ CRCBfull };
+ class Transform;
+ class Map;
+ class Block;
+ class Codec;
+ struct Alloc;
+ struct PrimaryHeader;
+ struct SecondaryHeader;
+ struct TertiaryHeader;
+ enum ImageType {
+ GRAY=false,
+ COLOR=true };
+protected:
+ IW44Image(void);
+public:
+ /** Null constructor. Constructs an empty IW44Image object. This object does
+ not contain anything meaningful. You must call function \Ref{init},
+ \Ref{decode_iff} or \Ref{decode_chunk} to populate the wavelet
+ coefficient data structure. You may not use \Ref{encode_iff} or
+ \Ref{encode_chunk}. */
+ static GP<IW44Image> create_decode(const ImageType itype=COLOR);
+ /** Null constructor. Constructs an empty IW44Image object. This object does
+ not contain anything meaningful. You must call function \Ref{init},
+ \Ref{decode_iff} or \Ref{decode_chunk} to populate the wavelet
+ coefficient data structure. You may then use \Ref{encode_iff}
+ and \Ref{encode_chunk}. */
+ static GP<IW44Image> create_encode(const ImageType itype=COLOR);
+ // virtual destructor
+ virtual ~IW44Image();
+ /** Initializes an IWBitmap with image #bm#. This constructor
+ performs the wavelet decomposition of image #bm# and records the
+ corresponding wavelet coefficient. Argument #mask# is an optional
+ bilevel image specifying the masked pixels (see \Ref{IW44Image.h}). */
+ static GP<IW44Image> create_encode(const GBitmap &bm, const GP<GBitmap> mask=0);
+ /** Initializes an IWPixmap with color image #bm#. This constructor
+ performs the wavelet decomposition of image #bm# and records the
+ corresponding wavelet coefficient. Argument #mask# is an optional
+ bilevel image specifying the masked pixels (see \Ref{IW44Image.h}).
+ Argument #crcbmode# specifies how the chrominance information should be
+ encoded (see \Ref{CRCBMode}). */
+ static GP<IW44Image> create_encode(const GPixmap &bm, const GP<GBitmap> mask=0, CRCBMode crcbmode=CRCBnormal);
+ // ACCESS
+ /** Returns the width of the IWBitmap image. */
+ int get_width(void) const;
+ /** Returns the height of the IWBitmap image. */
+ int get_height(void) const;
+ /** Reconstructs the complete image. The reconstructed image
+ is then returned as a GBitmap object. */
+ virtual GP<GBitmap> get_bitmap(void) {return 0;}
+ /** Reconstructs a segment of the image at a given scale. The subsampling
+ ratio #subsample# must be a power of two between #1# and #32#. Argument
+ #rect# specifies which segment of the subsampled image should be
+ reconstructed. The reconstructed image is returned as a GBitmap object
+ whose size is equal to the size of the rectangle #rect#. */
+ virtual GP<GBitmap> get_bitmap(int subsample, const GRect &rect) {return 0;}
+ /** Reconstructs the complete image. The reconstructed image
+ is then returned as a GPixmap object. */
+ virtual GP<GPixmap> get_pixmap(void) {return 0;}
+ /** Reconstructs a segment of the image at a given scale. The subsampling
+ ratio #subsample# must be a power of two between #1# and #32#. Argument
+ #rect# specifies which segment of the subsampled image should be
+ reconstructed. The reconstructed image is returned as a GPixmap object
+ whose size is equal to the size of the rectangle #rect#. */
+ virtual GP<GPixmap> get_pixmap(int subsample, const GRect &rect) {return 0;}
+ /** Returns the amount of memory used by the wavelet coefficients. This
+ amount of memory is expressed in bytes. */
+ virtual unsigned int get_memory_usage(void) const = 0;
+ /** Returns the filling ratio of the internal data structure. Wavelet
+ coefficients are stored in a sparse array. This function tells what
+ percentage of bins have been effectively allocated. */
+ virtual int get_percent_memory(void) const = 0;
+ // CODER
+ /** Encodes one data chunk into ByteStream #bs#. Parameter #parms# controls
+ how much data is generated. The chunk data is written to ByteStream
+ #bs# with no IFF header. Successive calls to #encode_chunk# encode
+ successive chunks. You must call #close_codec# after encoding the last
+ chunk of a file. */
+ virtual int encode_chunk(GP<ByteStream> gbs, const IWEncoderParms &parms);
+ /** Writes a gray level image into DjVu IW44 file. This function creates a
+ composite chunk (identifier #FORM:BM44# or #FORM:PM44#) composed of
+ #nchunks# chunks (identifier #BM44# or #PM44#). Data for each chunk is
+ generated with #encode_chunk# using the corresponding parameters in
+ array #parms#. */
+ virtual void encode_iff(IFFByteStream &iff, int nchunks, const IWEncoderParms *parms);
+ // DECODER
+ /** Decodes one data chunk from ByteStream #bs#. Successive calls to
+ #decode_chunk# decode successive chunks. You must call #close_codec#
+ after decoding the last chunk of a file. Note that function
+ #get_bitmap# and #decode_chunk# may be called simultaneously from two
+ execution threads. */
+ virtual int decode_chunk(GP<ByteStream> gbs) = 0;
+ /** This function enters a composite chunk (identifier #FORM:BM44#, or
+ #FORM:PM44#), and decodes a maximum of #maxchunks# data chunks
+ (identifier #BM44#). Data for each chunk is processed using the
+ function #decode_chunk#. */
+ virtual void decode_iff(IFFByteStream &iff, int maxchunks=999) = 0;
+ // MISCELLANEOUS
+ /** Resets the encoder/decoder state. The first call to #decode_chunk# or
+ #encode_chunk# initializes the coder for encoding or decoding. Function
+ #close_codec# must be called after processing the last chunk in order to
+ reset the coder and release the associated memory. */
+ virtual void close_codec(void) = 0;
+ /** Returns the chunk serial number. This function returns the serial
+ number of the last chunk encoded with #encode_chunk# or decoded with
+ #decode_chunk#. The first chunk always has serial number #1#. Successive
+ chunks have increasing serial numbers. Value #0# is returned if this
+ function is called before calling #encode_chunk# or #decode_chunk# or
+ after calling #close_codec#. */
+ virtual int get_serial(void) = 0;
+ /** Sets the chrominance delay parameter. This function can be called
+ before encoding the first color IW44 data chunk. Parameter #parm# is an
+ encoding delay which reduces the bitrate associated with the
+ chrominance information. The default chrominance encoding delay is 10. */
+ virtual int parm_crcbdelay(const int parm) {return parm;}
+ /** Sets the #dbfrac# parameter. This function can be called before
+ encoding the first IW44 data chunk. Parameter #frac# modifies the
+ decibel estimation algorithm in such a way that the decibel target only
+ pertains to the average error of the fraction #frac# of the most
+ misrepresented 32x32 pixel blocks. Setting arguments #frac# to #1.0#
+ restores the normal behavior. */
+ virtual void parm_dbfrac(float frac) = 0;
+protected:
+ // Parameter
+ float db_frac;
+ // Data
+ Map *ymap, *cbmap, *crmap;
+ int cslice;
+ int cserial;
+ int cbytes;
+private:
+ // Disable assignment semantic
+ IW44Image(const IW44Image &ref);
+ IW44Image& operator=(const IW44Image &ref);
+};
+
+#ifdef IW44IMAGE_IMPLIMENTATION
+
+/*x IW44 encoded gray-level image. This class provided functions for managing
+ a gray level image represented as a collection of IW44 wavelet
+ coefficients. The coefficients are stored in a memory efficient data
+ structure. Member function \Ref{get_bitmap} renders an arbitrary segment
+ of the image into a \Ref{GBitmap}. Member functions \Ref{decode_iff} and
+ \Ref{encode_iff} read and write DjVu IW44 files (see \Ref{IW44Image.h}).
+ Both the copy constructor and the copy operator are declared as private
+ members. It is therefore not possible to make multiple copies of instances
+ of this class. */
+
+class IWBitmap : public IW44Image
+{
+public:
+ friend class IW44Image;
+ class Encode;
+protected:
+ /*x Null constructor. Constructs an empty IWBitmap object. This object does
+ not contain anything meaningful. You must call function \Ref{init},
+ \Ref{decode_iff} or \Ref{decode_chunk} to populate the wavelet
+ coefficient data structure. */
+ IWBitmap(void);
+public:
+ //x virtual destructor
+ virtual ~IWBitmap();
+ //x ACCESS
+ /*x Reconstructs the complete image. The reconstructed image
+ is then returned as a GBitmap object. */
+ virtual GP<GBitmap> get_bitmap(void);
+ /*x Reconstructs a segment of the image at a given scale. The subsampling
+ ratio #subsample# must be a power of two between #1# and #32#. Argument
+ #rect# specifies which segment of the subsampled image should be
+ reconstructed. The reconstructed image is returned as a GBitmap object
+ whose size is equal to the size of the rectangle #rect#. */
+ virtual GP<GBitmap> get_bitmap(int subsample, const GRect &rect);
+ /*x Returns the amount of memory used by the wavelet coefficients. This
+ amount of memory is expressed in bytes. */
+ virtual unsigned int get_memory_usage(void) const;
+ /*x Returns the filling ratio of the internal data structure. Wavelet
+ coefficients are stored in a sparse array. This function tells what
+ percentage of bins have been effectively allocated. */
+ virtual int get_percent_memory(void) const;
+ // DECODER
+ /*x Decodes one data chunk from ByteStream #bs#. Successive calls to
+ #decode_chunk# decode successive chunks. You must call #close_codec#
+ after decoding the last chunk of a file. Note that function
+ #get_bitmap# and #decode_chunk# may be called simultaneously from two
+ execution threads. */
+ virtual int decode_chunk(GP<ByteStream> gbs);
+ /*x Reads a DjVu IW44 file as a gray level image. This function enters a
+ composite chunk (identifier #FORM:BM44#), and decodes a maximum of
+ #maxchunks# data chunks (identifier #BM44#). Data for each chunk is
+ processed using the function #decode_chunk#. */
+ virtual void decode_iff(IFFByteStream &iff, int maxchunks=999);
+ // MISCELLANEOUS
+ /*x Resets the encoder/decoder state. The first call to #decode_chunk# or
+ #encode_chunk# initializes the coder for encoding or decoding. Function
+ #close_codec# must be called after processing the last chunk in order to
+ reset the coder and release the associated memory. */
+ virtual void close_codec(void);
+ /*x Returns the chunk serial number. This function returns the serial
+ number of the last chunk encoded with #encode_chunk# or decoded with
+ #decode_chunk#. The first chunk always has serial number #1#. Successive
+ chunks have increasing serial numbers. Value #0# is returned if this
+ function is called before calling #encode_chunk# or #decode_chunk# or
+ after calling #close_codec#. */
+ virtual int get_serial(void);
+ /*x Sets the #dbfrac# parameter. This function can be called before
+ encoding the first IW44 data chunk. Parameter #frac# modifies the
+ decibel estimation algorithm in such a way that the decibel target only
+ pertains to the average error of the fraction #frac# of the most
+ misrepresented 32x32 pixel blocks. Setting arguments #frac# to #1.0#
+ restores the normal behavior. */
+ virtual void parm_dbfrac(float frac);
+private:
+ Codec *ycodec;
+};
+
+
+/*x IW44 encoded color image. This class provided functions for managing a
+ color image represented as a collection of IW44 wavelet coefficients. The
+ coefficients are stored in a memory efficient data structure. Member
+ function \Ref{get_pixmap} renders an arbitrary segment of the image into a
+ \Ref{GPixmap}. Member functions \Ref{decode_iff} and \Ref{encode_iff}
+ read and write DjVu IW44 files (see \Ref{IW44Image.h}). Both the copy
+ constructor and the copy operator are declared as private members. It is
+ therefore not possible to make multiple copies of instances of this
+ class. */
+
+class IWPixmap : public IW44Image
+{
+public:
+ friend class IW44Image;
+protected:
+ class Encode;
+ /*x Null constructor. Constructs an empty IWPixmap object. This object does
+ not contain anything meaningful. You must call function \Ref{init},
+ \Ref{decode_iff} or \Ref{decode_chunk} to populate the wavelet
+ coefficient data structure. */
+ IWPixmap(void);
+public:
+ // virtual destructor
+ virtual ~IWPixmap();
+ // ACCESS
+ /*x Reconstructs the complete image. The reconstructed image
+ is then returned as a GPixmap object. */
+ virtual GP<GPixmap> get_pixmap(void);
+ /*x Reconstructs a segment of the image at a given scale. The subsampling
+ ratio #subsample# must be a power of two between #1# and #32#. Argument
+ #rect# specifies which segment of the subsampled image should be
+ reconstructed. The reconstructed image is returned as a GPixmap object
+ whose size is equal to the size of the rectangle #rect#. */
+ virtual GP<GPixmap> get_pixmap(int subsample, const GRect &rect);
+ /*x Returns the amount of memory used by the wavelet coefficients. This
+ amount of memory is expressed in bytes. */
+ virtual unsigned int get_memory_usage(void) const;
+ /*x Returns the filling ratio of the internal data structure. Wavelet
+ coefficients are stored in a sparse array. This function tells what
+ percentage of bins have been effectively allocated. */
+ virtual int get_percent_memory(void) const;
+ // DECODER
+ /*x Decodes one data chunk from ByteStream #bs#. Successive calls to
+ #decode_chunk# decode successive chunks. You must call #close_codec#
+ after decoding the last chunk of a file. Note that function
+ #get_bitmap# and #decode_chunk# may be called simultaneously from two
+ execution threads. */
+ virtual int decode_chunk(GP<ByteStream> gbs);
+ /*x Reads a DjVu IW44 file as a color image. This function enters a
+ composite chunk (identifier #FORM:PM44# or #FORM:BM44#), and decodes a
+ maximum of #maxchunks# data chunks (identifier #PM44# or #BM44#). Data
+ for each chunk is processed using the function #decode_chunk#. */
+ virtual void decode_iff(IFFByteStream &iff, int maxchunks=999);
+ // MISCELLANEOUS
+ /*x Resets the encoder/decoder state. The first call to #decode_chunk# or
+ #encode_chunk# initializes the coder for encoding or decoding. Function
+ #close_codec# must be called after processing the last chunk in order to
+ reset the coder and release the associated memory. */
+ virtual void close_codec(void);
+ /*x Returns the chunk serial number. This function returns the serial
+ number of the last chunk encoded with #encode_chunk# or decoded with
+ #decode_chunk#. The first chunk always has serial number #1#. Successive
+ chunks have increasing serial numbers. Value #0# is returned if this
+ function is called before calling #encode_chunk# or #decode_chunk# or
+ after calling #close_codec#. */
+ virtual int get_serial(void);
+ /*x Sets the chrominance delay parameter. This function can be called
+ before encoding the first IW44 data chunk. Parameter #parm# is an
+ encoding delay which reduces the bitrate associated with the
+ chrominance information. The default chrominance encoding delay is 10. */
+ virtual int parm_crcbdelay(const int parm);
+ /*x Sets the #dbfrac# parameter. This function can be called before
+ encoding the first IW44 data chunk. Parameter #frac# modifies the
+ decibel estimation algorithm in such a way that the decibel target only
+ pertains to the average error of the fraction #frac# of the most
+ misrepresented 32x32 pixel blocks. Setting arguments #frac# to #1.0#
+ restores the normal behavior. */
+ virtual void parm_dbfrac(float frac);
+protected:
+ // Parameter
+ int crcb_delay;
+ int crcb_half;
+ // Data
+private:
+ Codec *ycodec, *cbcodec, *crcodec;
+};
+
+/*x IW44Transform.
+*/
+class IW44Image::Transform
+{
+public:
+ class Decode;
+ class Encode;
+protected:
+ static void filter_begin(int w, int h);
+ static void filter_end(void);
+};
+
+struct GPixel;
+class IW44Image::Transform::Decode : public IW44Image::Transform
+{
+public:
+ // WAVELET TRANSFORM
+ /*x Forward transform. */
+ static void backward(short *p, int w, int h, int rowsize, int begin, int end);
+
+ // COLOR TRANSFORM
+ /*x Converts YCbCr to RGB. */
+ static void YCbCr_to_RGB(GPixel *p, int w, int h, int rowsize);
+};
+
+//---------------------------------------------------------------
+// *** Class IW44Image::Block [declaration]
+// Represents a block of 32x32 coefficients after zigzagging and scaling
+
+
+class IW44Image::Block // DJVU_CLASS
+{
+public:
+ // creating
+ Block(void);
+ // accessing scaled coefficients
+ short get(int n) const;
+ void set(int n, int val, IW44Image::Map *map);
+ // converting from liftblock
+ void read_liftblock(const short *coeff, IW44Image::Map *map);
+ void write_liftblock(short *coeff, int bmin=0, int bmax=64) const;
+ // sparse array access
+ const short* data(int n) const;
+ short* data(int n, IW44Image::Map *map);
+ void zero(int n);
+ // sparse representation
+private:
+ short **(pdata[4]);
+};
+
+//---------------------------------------------------------------
+// *** Class IW44Image::Map [declaration]
+// Represents all the blocks of an image
+
+class IW44Image::Map // DJVU_CLASS
+{
+public:
+ class Encode;
+
+ // construction
+ Map(int w, int h);
+ ~Map();
+ // image access
+ void image(signed char *img8, int rowsize,
+ int pixsep=1, int fast=0);
+ void image(int subsample, const GRect &rect,
+ signed char *img8, int rowsize,
+ int pixsep=1, int fast=0);
+ // array of blocks
+ IW44Image::Block *blocks;
+ // geometry
+ int iw, ih;
+ int bw, bh;
+ int nb;
+ // coefficient allocation stuff
+ short *alloc(int n);
+ short **allocp(int n);
+ IW44Image::Alloc *chain;
+ int top;
+ // statistics
+ int get_bucket_count(void) const;
+ unsigned int get_memory_usage(void) const;
+};
+
+//////////////////////////////////////////////////////
+// ENCODING/DECODING WAVELET COEFFICIENTS
+// USING HIERARCHICAL SET DIFFERENCE
+//////////////////////////////////////////////////////
+
+
+//-----------------------------------------------
+// Class IW44Image::Codec [declaration+implementation]
+// Maintains information shared while encoding or decoding
+
+class IW44Image::Codec
+{
+public:
+ class Decode;
+ class Encode;
+
+protected:
+ // Construction
+ Codec(IW44Image::Map &map);
+public:
+ virtual ~Codec();
+ // Coding
+ int finish_code_slice(ZPCodec &zp);
+ virtual int code_slice(ZPCodec &zp) = 0;
+ // Data
+ IW44Image::Map &map; // working map
+ // status
+ int curband; // current band
+ int curbit; // current bitplane
+ // quantization tables
+ int quant_hi[10]; // quantization for bands 1 to 9
+ int quant_lo[16]; // quantization for band 0.
+ // bucket state
+ char coeffstate[256];
+ char bucketstate[16];
+ enum { ZERO = 1, // this coeff never hits this bit
+ ACTIVE = 2, // this coeff is already active
+ NEW = 4, // this coeff is becoming active
+ UNK = 8 }; // this coeff may become active
+ // coding context
+ BitContext ctxStart [32];
+ BitContext ctxBucket[10][8];
+ BitContext ctxMant;
+ BitContext ctxRoot;
+ // helper
+ int is_null_slice(int bit, int band);
+ int decode_prepare(int fbucket, int nbucket, IW44Image::Block &blk);
+ void decode_buckets(ZPCodec &zp, int bit, int band,
+ IW44Image::Block &blk, int fbucket, int nbucket);
+};
+
+//////////////////////////////////////////////////////
+// DEFINITION OF CHUNK HEADERS
+//////////////////////////////////////////////////////
+
+
+struct IW44Image::PrimaryHeader {
+ unsigned char serial;
+ unsigned char slices;
+ void encode(GP<ByteStream> gbs);
+ void decode(GP<ByteStream> gbs);
+};
+
+struct IW44Image::SecondaryHeader {
+ unsigned char major;
+ unsigned char minor;
+ void encode(GP<ByteStream> gbs);
+ void decode(GP<ByteStream> gbs);
+};
+
+struct IW44Image::TertiaryHeader {
+ unsigned char xhi, xlo;
+ unsigned char yhi, ylo;
+ unsigned char crcbdelay;
+ void encode(GP<ByteStream> gbs);
+ void decode(GP<ByteStream> gbs, int major=1, int minor=2);
+};
+
+inline const short*
+IW44Image::Block::data(int n) const
+{
+ if (! pdata[n>>4])
+ return 0;
+ return pdata[n>>4][n&15];
+}
+
+inline short*
+IW44Image::Block::data(int n, IW44Image::Map *map)
+{
+ if (! pdata[n>>4])
+ pdata[n>>4] = map->allocp(16);
+ if (! pdata[n>>4][n &15])
+ pdata[n>>4][n &15] = map->alloc(16);
+ return pdata[n>>4][n&15];
+}
+
+inline short
+IW44Image::Block::get(int n) const
+{
+ int n1 = (n>>4);
+ const short *d = data(n1);
+ if (! d)
+ return 0;
+ return d[n&15];
+}
+
+inline void
+IW44Image::Block::set(int n, int val, IW44Image::Map *map)
+{
+ int n1 = (n>>4);
+ short* d = data(n1, map);
+ d[n&15] = val;
+}
+
+#endif /* IW44IMAGE_IMPLIMENTATION */
+
+//@}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
+
diff --git a/kviewshell/plugins/djvu/libdjvu/JB2EncodeCodec.cpp b/kviewshell/plugins/djvu/libdjvu/JB2EncodeCodec.cpp
new file mode 100644
index 00000000..5a8092a0
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/JB2EncodeCodec.cpp
@@ -0,0 +1,564 @@
+//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: JB2EncodeCodec.cpp,v 1.9 2003/11/07 22:08:22 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+// From: Leon Bottou, 1/31/2002
+// Lizardtech has split the corresponding cpp file into a decoder and an encoder.
+// Only superficial changes. The meat is mine.
+
+#ifndef NEED_DECODER_ONLY
+
+#include "JB2Image.h"
+#include "GBitmap.h"
+#include <string.h>
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+////////////////////////////////////////
+//// CLASS JB2Codec::Encode: DECLARATION
+////////////////////////////////////////
+
+// This class is accessed via the encode
+// functions of class JB2Image
+
+
+//**** Class JB2Codec
+// This class implements the JB2 coder.
+// Contains all contextual information for encoding a JB2Image.
+
+class JB2Dict::JB2Codec::Encode : public JB2Dict::JB2Codec
+{
+public:
+ Encode(void);
+ void init(const GP<ByteStream> &gbs);
+//virtual
+ void code(const GP<JB2Image> &jim);
+ void code(JB2Image *jim) { const GP<JB2Image> gjim(jim);code(gjim); }
+ void code(const GP<JB2Dict> &jim);
+ void code(JB2Dict *jim) { const GP<JB2Dict> gjim(jim);code(gjim); }
+
+protected:
+ void CodeNum(const int num, const int lo, const int hi, NumContext &ctx);
+ void encode_libonly_shape(const GP<JB2Image> &jim, int shapeno);
+// virtual
+ bool CodeBit(const bool bit, BitContext &ctx);
+ void code_comment(GUTF8String &comment);
+ void code_record_type(int &rectype);
+ int code_match_index(int &index, JB2Dict &jim);
+ void code_inherited_shape_count(JB2Dict &jim);
+ void code_image_size(JB2Dict &jim);
+ void code_image_size(JB2Image &jim);
+ void code_absolute_location(JB2Blit *jblt, int rows, int columns);
+ void code_absolute_mark_size(GBitmap &bm, int border=0);
+ void code_relative_mark_size(GBitmap &bm, int cw, int ch, int border=0);
+ void code_bitmap_directly(GBitmap &bm,const int dw, int dy,
+ unsigned char *up2, unsigned char *up1, unsigned char *up0 );
+ int get_diff(const int x_diff,NumContext &rel_loc);
+ void code_bitmap_by_cross_coding (GBitmap &bm, GBitmap &cbm,
+ const int xd2c, const int dw, int dy, int cy,
+ unsigned char *up1, unsigned char *up0, unsigned char *xup1,
+ unsigned char *xup0, unsigned char *xdn1 );
+
+private:
+ GP<ZPCodec> gzp;
+};
+
+
+////////////////////////////////////////
+//// CLASS JB2DICT: IMPLEMENTATION
+////////////////////////////////////////
+
+void
+JB2Dict::encode(const GP<ByteStream> &gbs) const
+{
+ JB2Codec::Encode codec;
+ codec.init(gbs);
+ codec.code(const_cast<JB2Dict *>(this));
+}
+
+////////////////////////////////////////
+//// CLASS JB2IMAGE: IMPLEMENTATION
+////////////////////////////////////////
+
+void
+JB2Image::encode(const GP<ByteStream> &gbs) const
+{
+ JB2Codec::Encode codec;
+ codec.init(gbs);
+ codec.code(const_cast<JB2Image *>(this));
+}
+
+////////////////////////////////////////
+//// CLASS JB2CODEC : IMPLEMENTATION
+////////////////////////////////////////
+
+#define START_OF_DATA (0)
+#define NEW_MARK (1)
+#define NEW_MARK_LIBRARY_ONLY (2)
+#define NEW_MARK_IMAGE_ONLY (3)
+#define MATCHED_REFINE (4)
+#define MATCHED_REFINE_LIBRARY_ONLY (5)
+#define MATCHED_REFINE_IMAGE_ONLY (6)
+#define MATCHED_COPY (7)
+#define NON_MARK_DATA (8)
+#define REQUIRED_DICT_OR_RESET (9)
+#define PRESERVED_COMMENT (10)
+#define END_OF_DATA (11)
+
+// STATIC DATA MEMBERS
+
+static const int BIGPOSITIVE = 262142;
+static const int BIGNEGATIVE = -262143;
+static const int CELLCHUNK = 20000;
+static const int CELLEXTRA = 500;
+
+// CONSTRUCTOR
+
+JB2Dict::JB2Codec::Encode::Encode(void)
+: JB2Dict::JB2Codec(1) {}
+
+void
+JB2Dict::JB2Codec::Encode::init(const GP<ByteStream> &gbs)
+{
+ gzp=ZPCodec::create(gbs,true,true);
+}
+
+inline bool
+JB2Dict::JB2Codec::Encode::CodeBit(const bool bit, BitContext &ctx)
+{
+ gzp->encoder(bit?1:0, ctx);
+ return bit;
+}
+
+void
+JB2Dict::JB2Codec::Encode::CodeNum(int num, int low, int high, NumContext &ctx)
+{
+ if (num < low || num > high)
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ JB2Codec::CodeNum(low,high,&ctx,num);
+}
+
+// CODE COMMENTS
+
+void
+JB2Dict::JB2Codec::Encode::code_comment(GUTF8String &comment)
+{
+ // Encode size
+ int size=comment.length();
+ CodeNum(size, 0, BIGPOSITIVE, dist_comment_length);
+ for (int i=0; i<size; i++)
+ {
+ CodeNum(comment[i], 0, 255, dist_comment_byte);
+ }
+}
+
+// CODE SIMPLE VALUES
+
+inline void
+JB2Dict::JB2Codec::Encode::code_record_type(int &rectype)
+{
+ CodeNum(rectype, START_OF_DATA, END_OF_DATA, dist_record_type);
+}
+
+int
+JB2Dict::JB2Codec::Encode::code_match_index(int &index, JB2Dict &jim)
+{
+ int match=shape2lib[index];
+ CodeNum(match, 0, lib2shape.hbound(), dist_match_index);
+ return match;
+}
+
+// CODE PAIRS
+
+void
+JB2Dict::JB2Codec::Encode::code_inherited_shape_count(JB2Dict &jim)
+{
+ CodeNum(jim.get_inherited_shape_count(),
+ 0, BIGPOSITIVE, inherited_shape_count_dist);
+}
+
+void
+JB2Dict::JB2Codec::Encode::code_image_size(JB2Dict &jim)
+{
+ CodeNum(0, 0, BIGPOSITIVE, image_size_dist);
+ CodeNum(0, 0, BIGPOSITIVE, image_size_dist);
+ JB2Codec::code_image_size(jim);
+}
+
+void
+JB2Dict::JB2Codec::Encode::code_image_size(JB2Image &jim)
+{
+ image_columns = jim.get_width();
+ CodeNum(image_columns, 0, BIGPOSITIVE, image_size_dist);
+ image_rows = jim.get_height();
+ CodeNum(image_rows, 0, BIGPOSITIVE, image_size_dist);
+ JB2Codec::code_image_size(jim);
+}
+
+inline int
+JB2Dict::JB2Codec::Encode::get_diff(int x_diff,NumContext &rel_loc)
+{
+ CodeNum(x_diff, BIGNEGATIVE, BIGPOSITIVE, rel_loc);
+ return x_diff;
+}
+
+void
+JB2Dict::JB2Codec::Encode::code_absolute_location(JB2Blit *jblt, int rows, int columns)
+{
+ // Check start record
+ if (!gotstartrecordp)
+ G_THROW( ERR_MSG("JB2Image.no_start") );
+ // Code TOP and LEFT
+ CodeNum(jblt->left+1, 1, image_columns, abs_loc_x);
+ CodeNum(jblt->bottom+rows-1+1, 1, image_rows, abs_loc_y);
+}
+
+void
+JB2Dict::JB2Codec::Encode::code_absolute_mark_size(GBitmap &bm, int border)
+{
+ CodeNum(bm.columns(), 0, BIGPOSITIVE, abs_size_x);
+ CodeNum(bm.rows(), 0, BIGPOSITIVE, abs_size_y);
+}
+
+void
+JB2Dict::JB2Codec::Encode::code_relative_mark_size(GBitmap &bm, int cw, int ch, int border)
+{
+ CodeNum(bm.columns()-cw, BIGNEGATIVE, BIGPOSITIVE, rel_size_x);
+ CodeNum(bm.rows()-ch, BIGNEGATIVE, BIGPOSITIVE, rel_size_y);
+}
+
+// CODE BITMAP DIRECTLY
+
+void
+JB2Dict::JB2Codec::Encode::code_bitmap_directly(
+ GBitmap &bm,const int dw, int dy,
+ unsigned char *up2, unsigned char *up1, unsigned char *up0 )
+{
+ ZPCodec &zp=*gzp;
+ // iterate on rows (encoding)
+ while (dy >= 0)
+ {
+ int context=get_direct_context(up2, up1, up0, 0);
+ for (int dx=0;dx < dw;)
+ {
+ int n = up0[dx++];
+ zp.encoder(n, bitdist[context]);
+ context=shift_direct_context(context, n, up2, up1, up0, dx);
+ }
+ // next row
+ dy -= 1;
+ up2 = up1;
+ up1 = up0;
+ up0 = bm[dy];
+ }
+}
+
+// CODE BITMAP BY CROSS CODING
+
+void
+JB2Dict::JB2Codec::Encode::code_bitmap_by_cross_coding (GBitmap &bm, GBitmap &cbm,
+ const int xd2c, const int dw, int dy, int cy,
+ unsigned char *up1, unsigned char *up0, unsigned char *xup1,
+ unsigned char *xup0, unsigned char *xdn1 )
+{
+ ZPCodec &zp=*gzp;
+ // iterate on rows (encoding)
+ while (dy >= 0)
+ {
+ int context=get_cross_context(up1, up0, xup1, xup0, xdn1, 0);
+ for(int dx=0;dx < dw;)
+ {
+ const int n = up0[dx++];
+ zp.encoder(n, cbitdist[context]);
+ context=shift_cross_context(context, n,
+ up1, up0, xup1, xup0, xdn1, dx);
+ }
+ // next row
+ up1 = up0;
+ up0 = bm[--dy];
+ xup1 = xup0;
+ xup0 = xdn1;
+ xdn1 = cbm[(--cy)-1] + xd2c;
+ }
+}
+
+// CODE JB2DICT
+
+void
+JB2Dict::JB2Codec::Encode::code(const GP<JB2Dict> &gjim)
+{
+ if(!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Dict &jim=*gjim;
+ // -------------------------
+ // THIS IS THE ENCODING PART
+ // -------------------------
+ int firstshape = jim.get_inherited_shape_count();
+ int nshape = jim.get_shape_count();
+ init_library(jim);
+ // Code headers.
+ int rectype = REQUIRED_DICT_OR_RESET;
+ if (jim.get_inherited_shape_count() > 0)
+ code_record(rectype, gjim, 0);
+ rectype = START_OF_DATA;
+ code_record(rectype, gjim, 0);
+ // Code Comment.
+ rectype = PRESERVED_COMMENT;
+ if (!! jim.comment)
+ code_record(rectype, gjim, 0);
+ // Encode every shape
+ int shapeno;
+ DJVU_PROGRESS_TASK(jb2code,"jb2 encode", nshape-firstshape);
+ for (shapeno=firstshape; shapeno<nshape; shapeno++)
+ {
+ DJVU_PROGRESS_RUN(jb2code, (shapeno-firstshape)|0xff);
+ // Code shape
+ JB2Shape &jshp = jim.get_shape(shapeno);
+ rectype=(jshp.parent >= 0)
+ ?MATCHED_REFINE_LIBRARY_ONLY:NEW_MARK_LIBRARY_ONLY;
+ code_record(rectype, gjim, &jshp);
+ add_library(shapeno, jshp);
+ // Check numcoder status
+ if (cur_ncell > CELLCHUNK)
+ {
+ rectype = REQUIRED_DICT_OR_RESET;
+ code_record(rectype, 0, 0);
+ }
+ }
+ // Code end of data record
+ rectype = END_OF_DATA;
+ code_record(rectype, gjim, 0);
+ gzp=0;
+}
+
+// CODE JB2IMAGE
+
+void
+JB2Dict::JB2Codec::Encode::code(const GP<JB2Image> &gjim)
+{
+ if(!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Image &jim=*gjim;
+ // -------------------------
+ // THIS IS THE ENCODING PART
+ // -------------------------
+ int i;
+ init_library(jim);
+ int firstshape = jim.get_inherited_shape_count();
+ int nshape = jim.get_shape_count();
+ int nblit = jim.get_blit_count();
+ // Initialize shape2lib
+ shape2lib.resize(0,nshape-1);
+ for (i=firstshape; i<nshape; i++)
+ shape2lib[i] = -1;
+ // Determine shapes that go into library (shapeno>=firstshape)
+ // shape2lib is -2 if used by one blit
+ // shape2lib is -3 if used by more than one blit
+ // shape2lib is -4 if used as a parent
+ for (i=0; i<nblit; i++)
+ {
+ JB2Blit *jblt = jim.get_blit(i);
+ int shapeno = jblt->shapeno;
+ if (shapeno < firstshape)
+ continue;
+ if (shape2lib[shapeno] >= -2)
+ shape2lib[shapeno] -= 1;
+ shapeno = jim.get_shape(shapeno).parent;
+ while (shapeno>=firstshape && shape2lib[shapeno]>=-3)
+ {
+ shape2lib[shapeno] = -4;
+ shapeno = jim.get_shape(shapeno).parent;
+ }
+ }
+ // Code headers.
+ int rectype = REQUIRED_DICT_OR_RESET;
+ if (jim.get_inherited_shape_count() > 0)
+ code_record(rectype, gjim, 0, 0);
+ rectype = START_OF_DATA;
+ code_record(rectype, gjim, 0, 0);
+ // Code Comment.
+ rectype = PRESERVED_COMMENT;
+ if (!! jim.comment)
+ code_record(rectype, gjim, 0, 0);
+ // Encode every blit
+ int blitno;
+ DJVU_PROGRESS_TASK(jb2code,"jb2 encode", nblit);
+ for (blitno=0; blitno<nblit; blitno++)
+ {
+ DJVU_PROGRESS_RUN(jb2code, blitno|0xff);
+ JB2Blit *jblt = jim.get_blit(blitno);
+ int shapeno = jblt->shapeno;
+ JB2Shape &jshp = jim.get_shape(shapeno);
+ // Tests if shape exists in library
+ if (shape2lib[shapeno] >= 0)
+ {
+ int rectype = MATCHED_COPY;
+ code_record(rectype, gjim, 0, jblt);
+ }
+ // Avoid coding null shapes/blits
+ else if (jshp.bits)
+ {
+ // Make sure all parents have been coded
+ if (jshp.parent>=0 && shape2lib[jshp.parent]<0)
+ encode_libonly_shape(gjim, jshp.parent);
+ // Allocate library entry when needed
+#define LIBRARY_CONTAINS_ALL
+ int libraryp = 0;
+#ifdef LIBRARY_CONTAINS_MARKS // baseline
+ if (jshp.parent >= -1)
+ libraryp = 1;
+#endif
+#ifdef LIBRARY_CONTAINS_SHARED // worse
+ if (shape2lib[shapeno] <= -3)
+ libraryp = 1;
+#endif
+#ifdef LIBRARY_CONTAINS_ALL // better
+ libraryp = 1;
+#endif
+ // Test all blit cases
+ if (jshp.parent<-1 && !libraryp)
+ {
+ int rectype = NON_MARK_DATA;
+ code_record(rectype, gjim, &jshp, jblt);
+ }
+ else if (jshp.parent < 0)
+ {
+ int rectype = (libraryp ? NEW_MARK : NEW_MARK_IMAGE_ONLY);
+ code_record(rectype, gjim, &jshp, jblt);
+ }
+ else
+ {
+ int rectype = (libraryp ? MATCHED_REFINE : MATCHED_REFINE_IMAGE_ONLY);
+ code_record(rectype, gjim, &jshp, jblt);
+ }
+ // Add shape to library
+ if (libraryp)
+ add_library(shapeno, jshp);
+ }
+ // Check numcoder status
+ if (cur_ncell > CELLCHUNK)
+ {
+ rectype = REQUIRED_DICT_OR_RESET;
+ code_record(rectype, 0, 0);
+ }
+ }
+ // Code end of data record
+ rectype = END_OF_DATA;
+ code_record(rectype, gjim, 0, 0);
+ gzp=0;
+}
+
+////////////////////////////////////////
+//// HELPERS
+////////////////////////////////////////
+
+void
+JB2Dict::JB2Codec::Encode::encode_libonly_shape(
+ const GP<JB2Image> &gjim, int shapeno )
+{
+ if(!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Image &jim=*gjim;
+ // Recursively encode parent shape
+ JB2Shape &jshp = jim.get_shape(shapeno);
+ if (jshp.parent>=0 && shape2lib[jshp.parent]<0)
+ encode_libonly_shape(gjim, jshp.parent);
+ // Test that library shape must be encoded
+ if (shape2lib[shapeno] < 0)
+ {
+ // Code library entry
+ int rectype=(jshp.parent >= 0)
+ ?NEW_MARK_LIBRARY_ONLY:MATCHED_REFINE_LIBRARY_ONLY;
+ code_record(rectype, gjim, &jshp, 0);
+ // Add shape to library
+ add_library(shapeno, jshp);
+ // Check numcoder status
+ if (cur_ncell > CELLCHUNK)
+ {
+ rectype = REQUIRED_DICT_OR_RESET;
+ code_record(rectype, 0, 0);
+ }
+ }
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+
+#endif /* NEED_DECODER_ONLY */
+
diff --git a/kviewshell/plugins/djvu/libdjvu/JB2Image.cpp b/kviewshell/plugins/djvu/libdjvu/JB2Image.cpp
new file mode 100644
index 00000000..7aad9261
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/JB2Image.cpp
@@ -0,0 +1,1427 @@
+//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: JB2Image.cpp,v 1.10 2004/04/17 23:56:11 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+// From: Leon Bottou, 1/31/2002
+// Lizardtech has split the corresponding cpp file into a decoder and an encoder.
+// Only superficial changes. The meat is mine.
+
+#include "JB2Image.h"
+#include "GThreads.h"
+#include "GRect.h"
+#include "GBitmap.h"
+#include <string.h>
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+////////////////////////////////////////
+//// CLASS JB2Codec::Decode: DECLARATION
+////////////////////////////////////////
+
+// This class is accessed via the decode
+// functions of class JB2Image
+
+
+//**** Class JB2Codec
+// This class implements the JB2 decoder.
+// Contains all contextual information for decoding a JB2Image.
+
+class JB2Dict::JB2Codec::Decode : public JB2Dict::JB2Codec
+{
+public:
+ Decode(void);
+ void init(const GP<ByteStream> &gbs);
+// virtual
+ void code(const GP<JB2Image> &jim);
+ void code(JB2Image *jim) {const GP<JB2Image> gjim(jim);code(gjim);}
+ void code(const GP<JB2Dict> &jim);
+ void code(JB2Dict *jim) {const GP<JB2Dict> gjim(jim);code(gjim);}
+ void set_dict_callback(JB2DecoderCallback *cb, void *arg);
+protected:
+ int CodeNum(const int lo, const int hi, NumContext &ctx);
+
+// virtual
+ bool CodeBit(const bool bit, BitContext &ctx);
+ void code_comment(GUTF8String &comment);
+ void code_record_type(int &rectype);
+ int code_match_index(int &index, JB2Dict &jim);
+ void code_inherited_shape_count(JB2Dict &jim);
+ void code_image_size(JB2Dict &jim);
+ void code_image_size(JB2Image &jim);
+ void code_absolute_location(JB2Blit *jblt, int rows, int columns);
+ void code_absolute_mark_size(GBitmap &bm, int border=0);
+ void code_relative_mark_size(GBitmap &bm, int cw, int ch, int border=0);
+ void code_bitmap_directly(GBitmap &bm,const int dw, int dy,
+ unsigned char *up2, unsigned char *up1, unsigned char *up0 );
+ void code_bitmap_by_cross_coding (GBitmap &bm, GBitmap &cbm,
+ const int xd2c, const int dw, int dy, int cy,
+ unsigned char *up1, unsigned char *up0, unsigned char *xup1,
+ unsigned char *xup0, unsigned char *xdn1 );
+ int get_diff(const int x_diff,NumContext &rel_loc);
+
+private:
+ GP<ZPCodec> gzp;
+ JB2DecoderCallback *cbfunc;
+ void *cbarg;
+};
+
+////////////////////////////////////////
+//// CLASS JB2DICT: IMPLEMENTATION
+////////////////////////////////////////
+
+
+JB2Dict::JB2Dict()
+ : inherited_shapes(0)
+{
+}
+
+void
+JB2Dict::init()
+{
+ inherited_shapes = 0;
+ inherited_dict = 0;
+ shapes.empty();
+}
+
+JB2Shape &
+JB2Dict::get_shape(const int shapeno)
+{
+ JB2Shape *retval;
+ if(shapeno >= inherited_shapes)
+ {
+ retval=&shapes[shapeno - inherited_shapes];
+ }else if(inherited_dict)
+ {
+ retval=&(inherited_dict->get_shape(shapeno));
+ }else
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ return *retval;
+}
+
+const JB2Shape &
+JB2Dict::get_shape(const int shapeno) const
+{
+ const JB2Shape *retval;
+ if(shapeno >= inherited_shapes)
+ {
+ retval=&shapes[shapeno - inherited_shapes];
+ }else if(inherited_dict)
+ {
+ retval=&(inherited_dict->get_shape(shapeno));
+ }else
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ return *retval;
+}
+
+void
+JB2Dict::set_inherited_dict(const GP<JB2Dict> &dict)
+{
+ if (shapes.size() > 0)
+ G_THROW( ERR_MSG("JB2Image.cant_set") );
+ if (inherited_dict)
+ G_THROW( ERR_MSG("JB2Image.cant_change") );
+ inherited_dict = dict;
+ inherited_shapes = dict->get_shape_count();
+ // Make sure that inherited bitmaps are marked as shared
+ for (int i=0; i<inherited_shapes; i++)
+ {
+ JB2Shape &jshp = dict->get_shape(i);
+ if (jshp.bits) jshp.bits->share();
+ }
+}
+
+void
+JB2Dict::compress()
+{
+ for (int i=shapes.lbound(); i<=shapes.hbound(); i++)
+ shapes[i].bits->compress();
+}
+
+unsigned int
+JB2Dict::get_memory_usage() const
+{
+ unsigned int usage = sizeof(JB2Dict);
+ usage += sizeof(JB2Shape) * shapes.size();
+ for (int i=shapes.lbound(); i<=shapes.hbound(); i++)
+ if (shapes[i].bits)
+ usage += shapes[i].bits->get_memory_usage();
+ return usage;
+}
+
+int
+JB2Dict::add_shape(const JB2Shape &shape)
+{
+ if (shape.parent >= get_shape_count())
+ G_THROW( ERR_MSG("JB2Image.bad_parent_shape") );
+ int index = shapes.size();
+ shapes.touch(index);
+ shapes[index] = shape;
+ return index + inherited_shapes;
+}
+
+void
+JB2Dict::decode(const GP<ByteStream> &gbs, JB2DecoderCallback *cb, void *arg)
+{
+ init();
+ JB2Codec::Decode codec;
+ codec.init(gbs);
+ codec.set_dict_callback(cb,arg);
+ codec.code(this);
+}
+
+
+
+////////////////////////////////////////
+//// CLASS JB2IMAGE: IMPLEMENTATION
+////////////////////////////////////////
+
+
+JB2Image::JB2Image(void)
+ : width(0), height(0), reproduce_old_bug(false)
+{
+}
+
+void
+JB2Image::init(void)
+{
+ width = height = 0;
+ blits.empty();
+ JB2Dict::init();
+}
+
+unsigned int
+JB2Image::get_memory_usage() const
+{
+ unsigned int usage = JB2Dict::get_memory_usage();
+ usage += sizeof(JB2Image) - sizeof(JB2Dict);
+ usage += sizeof(JB2Blit) * blits.size();
+ return usage;
+}
+
+void
+JB2Image::set_dimension(int awidth, int aheight)
+{
+ width = awidth;
+ height = aheight;
+}
+
+int
+JB2Image::add_blit(const JB2Blit &blit)
+{
+ if (blit.shapeno >= (unsigned int)get_shape_count())
+ G_THROW( ERR_MSG("JB2Image.bad_shape") );
+ int index = blits.size();
+ blits.touch(index);
+ blits[index] = blit;
+ return index;
+}
+
+GP<GBitmap>
+JB2Image::get_bitmap(int subsample, int align) const
+{
+ if (width==0 || height==0)
+ G_THROW( ERR_MSG("JB2Image.cant_create") );
+ int swidth = (width + subsample - 1) / subsample;
+ int sheight = (height + subsample - 1) / subsample;
+ int border = ((swidth + align - 1) & ~(align - 1)) - swidth;
+ GP<GBitmap> bm = GBitmap::create(sheight, swidth, border);
+ bm->set_grays(1+subsample*subsample);
+ for (int blitno = 0; blitno < get_blit_count(); blitno++)
+ {
+ const JB2Blit *pblit = get_blit(blitno);
+ const JB2Shape &pshape = get_shape(pblit->shapeno);
+ if (pshape.bits)
+ bm->blit(pshape.bits, pblit->left, pblit->bottom, subsample);
+ }
+ return bm;
+}
+
+GP<GBitmap>
+JB2Image::get_bitmap(const GRect &rect, int subsample, int align, int dispy) const
+{
+ if (width==0 || height==0)
+ G_THROW( ERR_MSG("JB2Image.cant_create") );
+ int rxmin = rect.xmin * subsample;
+ int rymin = rect.ymin * subsample;
+ int swidth = rect.width();
+ int sheight = rect.height();
+ int border = ((swidth + align - 1) & ~(align - 1)) - swidth;
+ GP<GBitmap> bm = GBitmap::create(sheight, swidth, border);
+ bm->set_grays(1+subsample*subsample);
+ for (int blitno = 0; blitno < get_blit_count(); blitno++)
+ {
+ const JB2Blit *pblit = get_blit(blitno);
+ const JB2Shape &pshape = get_shape(pblit->shapeno);
+ if (pshape.bits)
+ bm->blit(pshape.bits, pblit->left-rxmin, pblit->bottom-rymin+dispy, subsample);
+ }
+ return bm;
+}
+
+void
+JB2Image::decode(const GP<ByteStream> &gbs, JB2DecoderCallback *cb, void *arg)
+{
+ init();
+ JB2Codec::Decode codec;
+ codec.init(gbs);
+ codec.set_dict_callback(cb,arg);
+ codec.code(this);
+}
+
+
+
+////////////////////////////////////////
+//// CLASS JB2CODEC : IMPLEMENTATION
+////////////////////////////////////////
+
+
+
+#define START_OF_DATA (0)
+#define NEW_MARK (1)
+#define NEW_MARK_LIBRARY_ONLY (2)
+#define NEW_MARK_IMAGE_ONLY (3)
+#define MATCHED_REFINE (4)
+#define MATCHED_REFINE_LIBRARY_ONLY (5)
+#define MATCHED_REFINE_IMAGE_ONLY (6)
+#define MATCHED_COPY (7)
+#define NON_MARK_DATA (8)
+#define REQUIRED_DICT_OR_RESET (9)
+#define PRESERVED_COMMENT (10)
+#define END_OF_DATA (11)
+
+
+
+// STATIC DATA MEMBERS
+
+static const int BIGPOSITIVE = 262142;
+static const int BIGNEGATIVE = -262143;
+static const int CELLCHUNK = 20000;
+static const int CELLEXTRA = 500;
+
+
+// CONSTRUCTOR
+
+JB2Dict::JB2Codec::Decode::Decode(void)
+: JB2Dict::JB2Codec(0), cbfunc(0), cbarg(0) {}
+
+void
+JB2Dict::JB2Codec::Decode::init(const GP<ByteStream> &gbs)
+{
+ gzp=ZPCodec::create(gbs,false,true);
+}
+
+JB2Dict::JB2Codec::JB2Codec(const bool xencoding)
+ : encoding(xencoding),
+ cur_ncell(0),
+ gbitcells(bitcells,CELLCHUNK+CELLEXTRA),
+ gleftcell(leftcell,CELLCHUNK+CELLEXTRA),
+ grightcell(rightcell,CELLCHUNK+CELLEXTRA),
+ refinementp(false),
+ gotstartrecordp(0),
+ dist_comment_byte(0),
+ dist_comment_length(0),
+ dist_record_type(0),
+ dist_match_index(0),
+ dist_refinement_flag(0),
+ abs_loc_x(0),
+ abs_loc_y(0),
+ abs_size_x(0),
+ abs_size_y(0),
+ image_size_dist(0),
+ inherited_shape_count_dist(0),
+ offset_type_dist(0),
+ rel_loc_x_current(0),
+ rel_loc_x_last(0),
+ rel_loc_y_current(0),
+ rel_loc_y_last(0),
+ rel_size_x(0),
+ rel_size_y(0)
+{
+ memset(bitdist, 0, sizeof(bitdist));
+ memset(cbitdist, 0, sizeof(cbitdist));
+ // Initialize numcoder
+ bitcells[0] = 0; // dummy cell
+ leftcell[0] = rightcell[0] = 0;
+ cur_ncell = 1;
+}
+
+JB2Dict::JB2Codec::~JB2Codec() {}
+
+void
+JB2Dict::JB2Codec::reset_numcoder()
+{
+ dist_comment_byte = 0;
+ dist_comment_length = 0;
+ dist_record_type = 0;
+ dist_match_index = 0;
+ abs_loc_x = 0;
+ abs_loc_y = 0;
+ abs_size_x = 0;
+ abs_size_y = 0;
+ image_size_dist = 0;
+ inherited_shape_count_dist = 0;
+ rel_loc_x_current = 0;
+ rel_loc_x_last = 0;
+ rel_loc_y_current = 0;
+ rel_loc_y_last = 0;
+ rel_size_x = 0;
+ rel_size_y = 0;
+ gbitcells.clear();
+ gleftcell.clear();
+ grightcell.clear();
+ cur_ncell = 1;
+}
+
+
+void
+JB2Dict::JB2Codec::Decode::set_dict_callback(JB2DecoderCallback *cb, void *arg)
+{
+ cbfunc = cb;
+ cbarg = arg;
+}
+
+
+// CODE NUMBERS
+
+inline bool
+JB2Dict::JB2Codec::Decode::CodeBit(const bool, BitContext &ctx)
+{
+ return gzp->decoder(ctx)?true:false;
+}
+
+int
+JB2Dict::JB2Codec::Decode::CodeNum(int low, int high, NumContext &ctx)
+{
+ return JB2Codec::CodeNum(low,high,&ctx,0);
+}
+
+int
+JB2Dict::JB2Codec::CodeNum(int low, int high, NumContext *pctx, int v)
+{
+ bool negative=false;
+ int cutoff;
+ // Check
+ if (!pctx || ((int)*pctx >= cur_ncell))
+ G_THROW( ERR_MSG("JB2Image.bad_numcontext") );
+ // Start all phases
+ cutoff = 0;
+ for(int phase=1,range=0xffffffff;range != 1;)
+ {
+ if (! *pctx)
+ {
+ const int max_ncell=gbitcells;
+ if (cur_ncell >= max_ncell)
+ {
+ const int nmax_ncell = max_ncell+CELLCHUNK;
+ gbitcells.resize(nmax_ncell);
+ gleftcell.resize(nmax_ncell);
+ grightcell.resize(nmax_ncell);
+ }
+ *pctx = cur_ncell ++;
+ bitcells[*pctx] = 0;
+ leftcell[*pctx] = rightcell[*pctx] = 0;
+ }
+ // encode
+ const bool decision = encoding
+ ? ((low < cutoff && high >= cutoff)
+ ? CodeBit((v>=cutoff),bitcells[*pctx])
+ : (v >= cutoff))
+ : ((low>=cutoff)||((high>=cutoff)&&CodeBit(false,bitcells[*pctx])));
+ // context for new bit
+ pctx = decision?(&rightcell[*pctx]):(&leftcell[*pctx]);
+ // phase dependent part
+ switch (phase)
+ {
+ case 1:
+ negative = !decision;
+ if (negative)
+ {
+ if (encoding)
+ v = - v - 1;
+ const int temp = - low - 1;
+ low = - high - 1;
+ high = temp;
+ }
+ phase = 2; cutoff = 1;
+ break;
+
+ case 2:
+ if (!decision)
+ {
+ phase = 3;
+ range = (cutoff + 1) / 2;
+ if (range == 1)
+ cutoff = 0;
+ else
+ cutoff -= range / 2;
+ }
+ else
+ {
+ cutoff += cutoff + 1;
+ }
+ break;
+
+ case 3:
+ range /= 2;
+ if (range != 1)
+ {
+ if (!decision)
+ cutoff -= range / 2;
+ else
+ cutoff += range / 2;
+ }
+ else if (!decision)
+ {
+ cutoff --;
+ }
+ break;
+ }
+ }
+ return (negative)?(- cutoff - 1):cutoff;
+}
+
+
+
+// CODE COMMENTS
+
+void
+JB2Dict::JB2Codec::Decode::code_comment(GUTF8String &comment)
+{
+ int size=CodeNum(0, BIGPOSITIVE, dist_comment_length);
+ comment.empty();
+ char *combuf = comment.getbuf(size);
+ for (int i=0; i<size; i++)
+ {
+ combuf[i]=CodeNum(0, 255, dist_comment_byte);
+ }
+ comment.getbuf();
+}
+
+
+// LIBRARY
+
+
+void
+JB2Dict::JB2Codec::init_library(JB2Dict &jim)
+{
+ int nshape = jim.get_inherited_shape_count();
+ shape2lib.resize(0,nshape-1);
+ lib2shape.resize(0,nshape-1);
+ libinfo.resize(0,nshape-1);
+ for (int i=0; i<nshape; i++)
+ {
+ shape2lib[i] = i;
+ lib2shape[i] = i;
+ JB2Shape &jshp = jim.get_shape(i);
+ libinfo[i].compute_bounding_box(*(jshp.bits));
+ }
+}
+
+int
+JB2Dict::JB2Codec::add_library(const int shapeno, JB2Shape &jshp)
+{
+ const int libno = lib2shape.hbound() + 1;
+ lib2shape.touch(libno);
+ lib2shape[libno] = shapeno;
+ shape2lib.touch(shapeno);
+ shape2lib[shapeno] = libno;
+ libinfo.touch(libno);
+ libinfo[libno].compute_bounding_box(*(jshp.bits));
+ return libno;
+}
+
+
+// CODE SIMPLE VALUES
+
+inline void
+JB2Dict::JB2Codec::Decode::code_record_type(int &rectype)
+{
+ rectype=CodeNum( START_OF_DATA, END_OF_DATA, dist_record_type);
+}
+
+int
+JB2Dict::JB2Codec::Decode::code_match_index(int &index, JB2Dict &)
+{
+ int match=CodeNum(0, lib2shape.hbound(), dist_match_index);
+ index = lib2shape[match];
+ return match;
+}
+
+
+// HANDLE SHORT LIST
+
+int
+JB2Dict::JB2Codec::update_short_list(const int v)
+{
+ if (++ short_list_pos == 3)
+ short_list_pos = 0;
+ int * const s = short_list;
+ s[short_list_pos] = v;
+
+ return (s[0] >= s[1])
+ ?((s[0] > s[2])?((s[1] >= s[2])?s[1]:s[2]):s[0])
+ :((s[0] < s[2])?((s[1] >= s[2])?s[2]:s[1]):s[0]);
+}
+
+
+
+// CODE PAIRS
+
+
+void
+JB2Dict::JB2Codec::Decode::code_inherited_shape_count(JB2Dict &jim)
+{
+ int size=CodeNum(0, BIGPOSITIVE, inherited_shape_count_dist);
+ {
+ GP<JB2Dict> dict = jim.get_inherited_dict();
+ if (!dict && size>0)
+ {
+ // Call callback function to obtain dictionary
+ if (cbfunc)
+ dict = (*cbfunc)(cbarg);
+ if (dict)
+ jim.set_inherited_dict(dict);
+ }
+ if (!dict && size>0)
+ G_THROW( ERR_MSG("JB2Image.need_dict") );
+ if (dict && size!=dict->get_shape_count())
+ G_THROW( ERR_MSG("JB2Image.bad_dict") );
+ }
+}
+
+void
+JB2Dict::JB2Codec::Decode::code_image_size(JB2Dict &jim)
+{
+ int w=CodeNum(0, BIGPOSITIVE, image_size_dist);
+ int h=CodeNum(0, BIGPOSITIVE, image_size_dist);
+ if (w || h)
+ G_THROW( ERR_MSG("JB2Image.bad_dict2") );
+ JB2Codec::code_image_size(jim);
+}
+
+void
+JB2Dict::JB2Codec::code_image_size(JB2Dict &)
+{
+ last_left = 1;
+ last_row_left = 0;
+ last_row_bottom = 0;
+ last_right = 0;
+ fill_short_list(last_row_bottom);
+ gotstartrecordp = 1;
+}
+
+void
+JB2Dict::JB2Codec::Decode::code_image_size(JB2Image &jim)
+{
+ image_columns=CodeNum(0, BIGPOSITIVE, image_size_dist);
+ image_rows=CodeNum(0, BIGPOSITIVE, image_size_dist);
+ if (!image_columns || !image_rows)
+ G_THROW( ERR_MSG("JB2Image.zero_dim") );
+ jim.set_dimension(image_columns, image_rows);
+ JB2Codec::code_image_size(jim);
+}
+
+void
+JB2Dict::JB2Codec::code_image_size(JB2Image &)
+{
+ last_left = 1 + image_columns;
+ last_row_left = 0;
+ last_row_bottom = image_rows;
+ last_right = 0;
+ fill_short_list(last_row_bottom);
+ gotstartrecordp = 1;
+}
+
+inline int
+JB2Dict::JB2Codec::Decode::get_diff(int,NumContext &rel_loc)
+{
+ return CodeNum(BIGNEGATIVE, BIGPOSITIVE, rel_loc);
+}
+
+void
+JB2Dict::JB2Codec::code_relative_location(JB2Blit *jblt, int rows, int columns)
+{
+ // Check start record
+ if (!gotstartrecordp)
+ G_THROW( ERR_MSG("JB2Image.no_start") );
+ // Find location
+ int bottom=0, left=0, top=0, right=0;
+ int x_diff, y_diff;
+ if (encoding)
+ {
+ left = jblt->left + 1;
+ bottom = jblt->bottom + 1;
+ right = left + columns - 1;
+ top = bottom + rows - 1;
+ }
+ // Code offset type
+ int new_row=CodeBit((left<last_left), offset_type_dist);
+ if (new_row)
+ {
+ // Begin a new row
+ x_diff=get_diff(left-last_row_left,rel_loc_x_last);
+ y_diff=get_diff(top-last_row_bottom,rel_loc_y_last);
+ if (!encoding)
+ {
+ left = last_row_left + x_diff;
+ top = last_row_bottom + y_diff;
+ right = left + columns - 1;
+ bottom = top - rows + 1;
+ }
+ last_left = last_row_left = left;
+ last_right = right;
+ last_bottom = last_row_bottom = bottom;
+ fill_short_list(bottom);
+ }
+ else
+ {
+ // Same row
+ x_diff=get_diff(left-last_right,rel_loc_x_current);
+ y_diff=get_diff(bottom-last_bottom,rel_loc_y_current);
+ if (!encoding)
+ {
+ left = last_right + x_diff;
+ bottom = last_bottom + y_diff;
+ right = left + columns - 1;
+ top = bottom + rows - 1;
+ }
+ last_left = left;
+ last_right = right;
+ last_bottom = update_short_list(bottom);
+ }
+ // Store in blit record
+ if (!encoding)
+ {
+ jblt->bottom = bottom - 1;
+ jblt->left = left - 1;
+ }
+}
+
+void
+JB2Dict::JB2Codec::Decode::code_absolute_location(JB2Blit *jblt, int rows, int columns)
+{
+ // Check start record
+ if (!gotstartrecordp)
+ G_THROW( ERR_MSG("JB2Image.no_start") );
+ int left=CodeNum(1, image_columns, abs_loc_x);
+ int top=CodeNum(1, image_rows, abs_loc_y);
+ jblt->bottom = top - rows + 1 - 1;
+ jblt->left = left - 1;
+}
+
+void
+JB2Dict::JB2Codec::Decode::code_absolute_mark_size(GBitmap &bm, int border)
+{
+ int xsize=CodeNum(0, BIGPOSITIVE, abs_size_x);
+ int ysize=CodeNum(0, BIGPOSITIVE, abs_size_y);
+ if ((xsize!=(unsigned short)xsize) || (ysize!=(unsigned short)ysize))
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ bm.init(ysize, xsize, border);
+}
+
+void
+JB2Dict::JB2Codec::Decode::code_relative_mark_size(GBitmap &bm, int cw, int ch, int border)
+{
+ int xdiff=CodeNum(BIGNEGATIVE, BIGPOSITIVE, rel_size_x);
+ int ydiff=CodeNum(BIGNEGATIVE, BIGPOSITIVE, rel_size_y);
+ int xsize = cw + xdiff;
+ int ysize = ch + ydiff;
+ if ((xsize!=(unsigned short)xsize) || (ysize!=(unsigned short)ysize))
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ bm.init(ysize, xsize, border);
+}
+
+
+
+
+// CODE BITMAP DIRECTLY
+
+void
+JB2Dict::JB2Codec::code_bitmap_directly (GBitmap &bm)
+{
+ // Make sure bitmap will not be disturbed
+ GMonitorLock lock(bm.monitor());
+ // ensure borders are adequate
+ bm.minborder(3);
+ // initialize row pointers
+ int dy = bm.rows() - 1;
+ code_bitmap_directly(bm,bm.columns(),dy,bm[dy+2],bm[dy+1],bm[dy]);
+}
+
+void
+JB2Dict::JB2Codec::Decode::code_bitmap_directly(
+ GBitmap &bm,const int dw, int dy,
+ unsigned char *up2, unsigned char *up1, unsigned char *up0 )
+{
+ ZPCodec &zp=*gzp;
+ // iterate on rows (decoding)
+ while (dy >= 0)
+ {
+ int context=get_direct_context(up2, up1, up0, 0);
+ for(int dx=0;dx < dw;)
+ {
+ int n = zp.decoder(bitdist[context]);
+ up0[dx++] = n;
+ context=shift_direct_context(context, n, up2, up1, up0, dx);
+ }
+ // next row
+ dy -= 1;
+ up2 = up1;
+ up1 = up0;
+ up0 = bm[dy];
+ }
+#ifndef NDEBUG
+ bm.check_border();
+#endif
+}
+
+
+
+
+
+// CODE BITMAP BY CROSS CODING
+
+void
+JB2Dict::JB2Codec::code_bitmap_by_cross_coding (GBitmap &bm, GP<GBitmap> &cbm, const int libno)
+{
+ // Make sure bitmaps will not be disturbed
+ GP<GBitmap> copycbm=GBitmap::create();
+ if (cbm->monitor())
+ {
+ // Perform a copy when the bitmap is explicitely shared
+ GMonitorLock lock2(cbm->monitor());
+ copycbm->init(*cbm);
+ cbm = copycbm;
+ }
+ GMonitorLock lock1(bm.monitor());
+ // Center bitmaps
+ const int cw = cbm->columns();
+ const int dw = bm.columns();
+ const int dh = bm.rows();
+ const LibRect &l = libinfo[libno];
+ const int xd2c = (dw/2 - dw + 1) - ((l.right - l.left + 1)/2 - l.right);
+ const int yd2c = (dh/2 - dh + 1) - ((l.top - l.bottom + 1)/2 - l.top);
+ // Ensure borders are adequate
+ bm.minborder(2);
+ cbm->minborder(2-xd2c);
+ cbm->minborder(2+dw+xd2c-cw);
+ // Initialize row pointers
+ const int dy = dh - 1;
+ const int cy = dy + yd2c;
+#ifndef NDEBUG
+ bm.check_border();
+ cbm->check_border();
+#endif
+ code_bitmap_by_cross_coding (bm,*cbm, xd2c, dw, dy, cy, bm[dy+1], bm[dy],
+ (*cbm)[cy+1] + xd2c, (*cbm)[cy ] + xd2c, (*cbm)[cy-1] + xd2c);
+}
+
+void
+JB2Dict::JB2Codec::Decode::code_bitmap_by_cross_coding (GBitmap &bm, GBitmap &cbm,
+ const int xd2c, const int dw, int dy, int cy,
+ unsigned char *up1, unsigned char *up0, unsigned char *xup1,
+ unsigned char *xup0, unsigned char *xdn1 )
+{
+ ZPCodec &zp=*gzp;
+ // iterate on rows (decoding)
+ while (dy >= 0)
+ {
+ int context=get_cross_context(
+ up1, up0, xup1, xup0, xdn1, 0);
+ for(int dx=0;dx < dw;)
+ {
+ const int n = zp.decoder(cbitdist[context]);
+ up0[dx++] = n;
+ context=shift_cross_context(context, n,
+ up1, up0, xup1, xup0, xdn1, dx);
+ }
+ // next row
+ up1 = up0;
+ up0 = bm[--dy];
+ xup1 = xup0;
+ xup0 = xdn1;
+ xdn1 = cbm[(--cy)-1] + xd2c;
+#ifndef NDEBUG
+ bm.check_border();
+#endif
+ }
+}
+
+
+
+
+// CODE JB2DICT RECORD
+
+void
+JB2Dict::JB2Codec::code_record(
+ int &rectype, const GP<JB2Dict> &gjim, JB2Shape *xjshp)
+{
+ GP<GBitmap> cbm;
+ GP<GBitmap> bm;
+ int shapeno = -1;
+
+ // Code record type
+ code_record_type(rectype);
+
+ // Pre-coding actions
+ switch(rectype)
+ {
+ case NEW_MARK_LIBRARY_ONLY:
+ case MATCHED_REFINE_LIBRARY_ONLY:
+ {
+ if(!xjshp)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Shape &jshp=*xjshp;
+ if (!encoding)
+ {
+ jshp.bits = GBitmap::create();
+ jshp.parent = -1;
+ }
+ bm = jshp.bits;
+ break;
+ }
+ }
+ // Coding actions
+ switch (rectype)
+ {
+ case START_OF_DATA:
+ {
+ if(!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Dict &jim=*gjim;
+ code_image_size (jim);
+ code_eventual_lossless_refinement ();
+ if (! encoding)
+ init_library(jim);
+ break;
+ }
+ case NEW_MARK_LIBRARY_ONLY:
+ {
+ code_absolute_mark_size (*bm, 4);
+ code_bitmap_directly (*bm);
+ break;
+ }
+ case MATCHED_REFINE_LIBRARY_ONLY:
+ {
+ if(!xjshp||!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Dict &jim=*gjim;
+ JB2Shape &jshp=*xjshp;
+ int match = code_match_index (jshp.parent, jim);
+ cbm = jim.get_shape(jshp.parent).bits;
+ LibRect &l = libinfo[match];
+ code_relative_mark_size (*bm, l.right-l.left+1, l.top-l.bottom+1, 4);
+ code_bitmap_by_cross_coding (*bm, cbm, jshp.parent);
+ break;
+ }
+ case PRESERVED_COMMENT:
+ {
+ if(!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Dict &jim=*gjim;
+ code_comment(jim.comment);
+ break;
+ }
+ case REQUIRED_DICT_OR_RESET:
+ {
+ if (! gotstartrecordp)
+ {
+ // Indicates need for a shape dictionary
+ if(!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ code_inherited_shape_count(*gjim);
+ }else
+ // Reset all numerical contexts to zero
+ reset_numcoder();
+ break;
+ }
+ case END_OF_DATA:
+ {
+ break;
+ }
+ default:
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_type") );
+ }
+ }
+ // Post-coding action
+ if (!encoding)
+ {
+ // add shape to dictionary
+ switch(rectype)
+ {
+ case NEW_MARK_LIBRARY_ONLY:
+ case MATCHED_REFINE_LIBRARY_ONLY:
+ {
+ if(!xjshp||!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Shape &jshp=*xjshp;
+ shapeno = gjim->add_shape(jshp);
+ add_library(shapeno, jshp);
+ break;
+ }
+ }
+ // make sure everything is compacted
+ // decompaction will occur automatically when needed
+ if (bm)
+ bm->compress();
+ }
+}
+
+
+// CODE JB2DICT
+
+void
+JB2Dict::JB2Codec::Decode::code(const GP<JB2Dict> &gjim)
+{
+ if(!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Dict &jim=*gjim;
+ // -------------------------
+ // THIS IS THE DECODING PART
+ // -------------------------
+ int rectype;
+ JB2Shape tmpshape;
+ do
+ {
+ code_record(rectype, gjim, &tmpshape);
+ }
+ while(rectype != END_OF_DATA);
+ if (!gotstartrecordp)
+ G_THROW( ERR_MSG("JB2Image.no_start") );
+ jim.compress();
+}
+
+
+
+// CODE JB2IMAGE RECORD
+
+void
+JB2Dict::JB2Codec::code_record(
+ int &rectype, const GP<JB2Image> &gjim, JB2Shape *xjshp, JB2Blit *jblt)
+{
+ GP<GBitmap> bm;
+ GP<GBitmap> cbm;
+ int shapeno = -1;
+ int match;
+
+ // Code record type
+ code_record_type(rectype);
+
+ // Pre-coding actions
+ switch(rectype)
+ {
+ case NEW_MARK:
+ case NEW_MARK_LIBRARY_ONLY:
+ case NEW_MARK_IMAGE_ONLY:
+ case MATCHED_REFINE:
+ case MATCHED_REFINE_LIBRARY_ONLY:
+ case MATCHED_REFINE_IMAGE_ONLY:
+ case NON_MARK_DATA:
+ {
+ if(!xjshp)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Shape &jshp=*xjshp;
+ if (!encoding)
+ {
+ jshp.bits = GBitmap::create();
+ jshp.parent = -1;
+ if (rectype == NON_MARK_DATA)
+ jshp.parent = -2;
+ }
+ bm = jshp.bits;
+ break;
+ }
+ }
+ // Coding actions
+ switch (rectype)
+ {
+ case START_OF_DATA:
+ {
+ if(!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Image &jim=*gjim;
+ code_image_size (jim);
+ code_eventual_lossless_refinement ();
+ if (! encoding)
+ init_library(jim);
+ break;
+ }
+ case NEW_MARK:
+ {
+ code_absolute_mark_size (*bm, 4);
+ code_bitmap_directly (*bm);
+ code_relative_location (jblt, bm->rows(), bm->columns() );
+ break;
+ }
+ case NEW_MARK_LIBRARY_ONLY:
+ {
+ code_absolute_mark_size (*bm, 4);
+ code_bitmap_directly (*bm);
+ break;
+ }
+ case NEW_MARK_IMAGE_ONLY:
+ {
+ code_absolute_mark_size (*bm, 3);
+ code_bitmap_directly (*bm);
+ code_relative_location (jblt, bm->rows(), bm->columns() );
+ break;
+ }
+ case MATCHED_REFINE:
+ {
+ if(!xjshp || !gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Shape &jshp=*xjshp;
+ JB2Image &jim=*gjim;
+ match = code_match_index (jshp.parent, jim);
+ cbm = jim.get_shape(jshp.parent).bits;
+ LibRect &l = libinfo[match];
+ code_relative_mark_size (*bm, l.right-l.left+1, l.top-l.bottom+1, 4);
+ code_bitmap_by_cross_coding (*bm, cbm, match);
+ code_relative_location (jblt, bm->rows(), bm->columns() );
+ break;
+ }
+ case MATCHED_REFINE_LIBRARY_ONLY:
+ {
+ if(!xjshp||!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Image &jim=*gjim;
+ JB2Shape &jshp=*xjshp;
+ match = code_match_index (jshp.parent, jim);
+ cbm = jim.get_shape(jshp.parent).bits;
+ LibRect &l = libinfo[match];
+ code_relative_mark_size (*bm, l.right-l.left+1, l.top-l.bottom+1, 4);
+ break;
+ }
+ case MATCHED_REFINE_IMAGE_ONLY:
+ {
+ if(!xjshp||!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Image &jim=*gjim;
+ JB2Shape &jshp=*xjshp;
+ match = code_match_index (jshp.parent, jim);
+ cbm = jim.get_shape(jshp.parent).bits;
+ LibRect &l = libinfo[match];
+ code_relative_mark_size (*bm, l.right-l.left+1, l.top-l.bottom+1, 4);
+ code_bitmap_by_cross_coding (*bm, cbm, match);
+ code_relative_location (jblt, bm->rows(), bm->columns() );
+ break;
+ }
+ case MATCHED_COPY:
+ {
+ int temp;
+ if (encoding) temp = jblt->shapeno;
+ if(!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Image &jim=*gjim;
+ match = code_match_index (temp, jim);
+ if (!encoding) jblt->shapeno = temp;
+ bm = jim.get_shape(jblt->shapeno).bits;
+ LibRect &l = libinfo[match];
+ jblt->left += l.left;
+ jblt->bottom += l.bottom;
+ if (jim.reproduce_old_bug)
+ code_relative_location (jblt, bm->rows(), bm->columns() );
+ else
+ code_relative_location (jblt, l.top-l.bottom+1, l.right-l.left+1 );
+ jblt->left -= l.left;
+ jblt->bottom -= l.bottom;
+ break;
+ }
+ case NON_MARK_DATA:
+ {
+ code_absolute_mark_size (*bm, 3);
+ code_bitmap_directly (*bm);
+ code_absolute_location (jblt, bm->rows(), bm->columns() );
+ break;
+ }
+ case PRESERVED_COMMENT:
+ {
+ if(!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Image &jim=*gjim;
+ code_comment(jim.comment);
+ break;
+ }
+ case REQUIRED_DICT_OR_RESET:
+ {
+ if(!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Image &jim=*gjim;
+ if (! gotstartrecordp)
+ // Indicates need for a shape dictionary
+ code_inherited_shape_count(jim);
+ else
+ // Reset all numerical contexts to zero
+ reset_numcoder();
+ break;
+ }
+ case END_OF_DATA:
+ {
+ break;
+ }
+ default:
+ {
+ G_THROW( ERR_MSG("JB2Image.unknown_type") );
+ }
+ }
+
+ // Post-coding action
+ if (!encoding)
+ {
+ // add shape to image
+ switch(rectype)
+ {
+ case NEW_MARK:
+ case NEW_MARK_LIBRARY_ONLY:
+ case NEW_MARK_IMAGE_ONLY:
+ case MATCHED_REFINE:
+ case MATCHED_REFINE_LIBRARY_ONLY:
+ case MATCHED_REFINE_IMAGE_ONLY:
+ case NON_MARK_DATA:
+ {
+ if(!xjshp||!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Shape &jshp=*xjshp;
+ shapeno = gjim->add_shape(jshp);
+ shape2lib.touch(shapeno);
+ shape2lib[shapeno] = -1;
+ break;
+ }
+ }
+ // add shape to library
+ switch(rectype)
+ {
+ case NEW_MARK:
+ case NEW_MARK_LIBRARY_ONLY:
+ case MATCHED_REFINE:
+ case MATCHED_REFINE_LIBRARY_ONLY:
+ if(!xjshp)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ add_library(shapeno, *xjshp);
+ break;
+ }
+ // make sure everything is compacted
+ // decompaction will occur automatically on cross-coding bitmaps
+ if (bm)
+ bm->compress();
+ // add blit to image
+ switch (rectype)
+ {
+ case NEW_MARK:
+ case NEW_MARK_IMAGE_ONLY:
+ case MATCHED_REFINE:
+ case MATCHED_REFINE_IMAGE_ONLY:
+ case NON_MARK_DATA:
+ jblt->shapeno = shapeno;
+ case MATCHED_COPY:
+ if(!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ gjim->add_blit(* jblt);
+ break;
+ }
+ }
+}
+
+
+// CODE JB2IMAGE
+
+void
+JB2Dict::JB2Codec::Decode::code(const GP<JB2Image> &gjim)
+{
+ if(!gjim)
+ {
+ G_THROW( ERR_MSG("JB2Image.bad_number") );
+ }
+ JB2Image &jim=*gjim;
+ // -------------------------
+ // THIS IS THE DECODING PART
+ // -------------------------
+ int rectype;
+ JB2Blit tmpblit;
+ JB2Shape tmpshape;
+ do
+ {
+ code_record(rectype, gjim, &tmpshape, &tmpblit);
+ }
+ while(rectype!=END_OF_DATA);
+ if (!gotstartrecordp)
+ G_THROW( ERR_MSG("JB2Image.no_start") );
+ jim.compress();
+}
+
+
+
+////////////////////////////////////////
+//// HELPERS
+////////////////////////////////////////
+
+void
+JB2Dict::JB2Codec::LibRect::compute_bounding_box(const GBitmap &bm)
+{
+ // First lock the stuff.
+ GMonitorLock lock(bm.monitor());
+ // Get size
+ const int w = bm.columns();
+ const int h = bm.rows();
+ const int s = bm.rowsize();
+ // Right border
+ for(right=w-1;right >= 0;--right)
+ {
+ unsigned char const *p = bm[0] + right;
+ unsigned char const * const pe = p+(s*h);
+ for (;(p<pe)&&(!*p);p+=s)
+ continue;
+ if (p<pe)
+ break;
+ }
+ // Top border
+ for(top=h-1;top >= 0;--top)
+ {
+ unsigned char const *p = bm[top];
+ unsigned char const * const pe = p+w;
+ for (;(p<pe)&&(!*p); ++p)
+ continue;
+ if (p<pe)
+ break;
+ }
+ // Left border
+ for (left=0;left <= right;++left)
+ {
+ unsigned char const *p = bm[0] + left;
+ unsigned char const * const pe=p+(s*h);
+ for (;(p<pe)&&(!*p);p+=s)
+ continue;
+ if (p<pe)
+ break;
+ }
+ // Bottom border
+ for(bottom=0;bottom <= top;++bottom)
+ {
+ unsigned char const *p = bm[bottom];
+ unsigned char const * const pe = p+w;
+ for (;(p<pe)&&(!*p); ++p)
+ continue;
+ if (p<pe)
+ break;
+ }
+}
+
+GP<JB2Dict>
+JB2Dict::create(void)
+{
+ return new JB2Dict();
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/JB2Image.h b/kviewshell/plugins/djvu/libdjvu/JB2Image.h
new file mode 100644
index 00000000..f55ae451
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/JB2Image.h
@@ -0,0 +1,805 @@
+//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: JB2Image.h,v 1.9 2003/11/07 22:08:22 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _JB2IMAGE_H
+#define _JB2IMAGE_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+/** @name JB2Image.h
+
+ Files #"JB2Image.h"# and #"JB2Image.cpp"# address the compression of
+ bilevel images using the JB2 soft pattern matching scheme. These files
+ provide the complete decoder and the decoder back-end. The JB2 scheme is
+ optimized for images containing a large number of self-similar small
+ components such as characters. Typical text images can be compressed into
+ files 3 to 5 times smaller than with G4/MMR and 2 to 4 times smaller than
+ with JBIG1.
+
+ {\bf JB2 and JBIG2} --- JB2 has strong similarities with the forthcoming
+ JBIG2 standard developed by the "ISO/IEC JTC1 SC29 Working Group 1" which
+ is responsible for both the JPEG and JBIG standards. This is hardly
+ surprising since JB2 was our own proposal for the JBIG2 standard
+ and remained the only proposal for years. The full JBIG2 standard however
+ is significantly more complex and slighlty less efficient than JB2 because
+ it addresses a broader range of applications. Full JBIG2 compliance may
+ be implemented in the future.
+
+ {\bf JB2 Images} --- Class \Ref{JB2Image} is the central data structure
+ implemented here. A #JB2Image# is composed of an array of shapes
+ and an array of blits. Each shape contains a small bitmap representing an
+ elementary blob of ink, such as a character or a segment of line art.
+ Each blit instructs the decoder to render a particular shape at a
+ specified position in the image. Some compression is already achieved
+ because several blits can refer to the same shape. A shape can also
+ contain a pointer to a parent shape. Additional compression is achieved
+ when both shapes are similar because each shape is encoded using the
+ parent shape as a model. A #"O"# shape for instance could be a parent for
+ both a #"C"# shape and a #"Q"# shape.
+
+ {\bf JB2 Dictionary} --- Class \Ref{JB2Dict} is a peculiar kind of
+ JB2Image which only contains an array of shapes. These shapes can be
+ referenced from another JB2Dict/JB2Image. This is arranged by setting the
+ ``inherited dictionary'' of a JB2Dict/JB2Image using function
+ \Ref{JB2Dict::set_inherited_dict}. Several JB2Images can use shapes from a
+ same JB2Dict encoded separately. This is how several pages of a same
+ document can share information.
+
+ {\bf Decoding JB2 data} --- The first step for decoding JB2 data consists of
+ creating an empty #JB2Image# object. Function \Ref{JB2Image::decode} then
+ reads the data and populates the #JB2Image# with the shapes and the blits.
+ Function \Ref{JB2Image::get_bitmap} finally produces an anti-aliased image.
+
+ {\bf Encoding JB2 data} --- The first step for decoding JB2 data also
+ consists of creating an empty #JB2Image# object. You must then use
+ functions \Ref{JB2Image::add_shape} and \Ref{JB2Image::add_blit} to
+ populate the #JB2Image# object. Function \Ref{JB2Image::encode} finally
+ produces the JB2 data. Function #encode# sequentially encodes the blits
+ and the necessary shapes. The compression ratio depends on several
+ factors:
+ \begin{itemize}
+ \item Blits should reuse shapes as often as possible.
+ \item Blits should be sorted in reading order because this facilitates
+ the prediction of the blit coordinates.
+ \item Shapes should be sorted according to the order of first appearance
+ in the sequence of blits because this facilitates the prediction of the
+ shape indices.
+ \item Shapes should be compared to all previous shapes in the shape array.
+ The shape parent pointer should be set to a suitable parent shape if
+ such a parent shape exists. The parent shape should have almost the
+ same size and the same pixels.
+ \end{itemize}
+ All this is quite easy to achieve in the case of an electronically
+ produced document such as a DVI file or a PS file: we know what the
+ characters are and where they are located. If you only have a scanned
+ image however you must first locate the characters (connected component
+ analysis) and cut the remaining pieces of ink into smaller blobs.
+ Ordering the blits and matching the shapes is then an essentially
+ heuristic process. Although the quality of the heuristics substantially
+ effects the file size, misordering blits or mismatching shapes never
+ effects the quality of the image. The last refinement consists in
+ smoothing the shapes in order to reduce the noise and maximize the
+ similarities between shapes.
+
+ {\bf JB2 extensions} --- Two extensions of the JB2
+ encoding format have been introduced with DjVu files version 21. The first
+ extension addresses the shared shape dictionaries. The second extension
+ bounds the number of probability contexts used for coding numbers.
+ Both extensions maintain backward compatibility with JB2 as
+ described in the ICFDD proposal. A more complete discussion
+ can be found in section \Ref{JB2 extensions for version 21.}.
+
+ {\bf References}
+ \begin{itemize}
+ \item Paul G. Howard : {\em Text image compression using soft
+ pattern matching}, Computer Journal, volume 40:2/3, 1997.
+ \item JBIG1 : \URL{http://www.jpeg.org/public/jbighomepage.htm}.
+ \item JBIG2 draft : \URL{http://www.jpeg.org/public/jbigpt2.htm}.
+ \item ICFDD Draft Proposed American National Standard, 1999-08-26.
+ \end{itemize}
+
+ @version
+ #$Id: JB2Image.h,v 1.9 2003/11/07 22:08:22 leonb Exp $#
+ @memo
+ Coding bilevel images with JB2.
+ @author
+ Paul Howard <pgh@research.att.com> -- JB2 design\\
+ L\'eon Bottou <leonb@research.att.com> -- this implementation
+
+// From: Leon Bottou, 1/31/2002
+// Lizardtech has split the corresponding cpp file into a decoder and an encoder.
+// Only superficial changes. The meat is mine.
+
+*/
+//@{
+
+
+#include "GString.h"
+#include "ZPCodec.h"
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+class JB2Dict;
+class JB2Image;
+class GRect;
+class GBitmap;
+class ByteStream;
+
+/** Blit data structure. A #JB2Image# contains an array of #JB2Blit# data
+ structures. Each array entry instructs the decoder to render a particular
+ shape at a particular location. Members #left# and #bottom# specify the
+ coordinates of the bottom left corner of the shape bitmap. All
+ coordinates are relative to the bottom left corner of the image. Member
+ #shapeno# is the subscript of the shape to be rendered. */
+
+class JB2Blit {
+public:
+ /** Horizontal coordinate of the blit. */
+ unsigned short left;
+ /** Vertical coordinate of the blit. */
+ unsigned short bottom;
+ /** Index of the shape to blit. */
+ unsigned int shapeno;
+};
+
+
+/** Shape data structure. A #JB2Image# contains an array of #JB2Shape# data
+ structures. Each array entry represents an elementary blob of ink such as
+ a character or a segment of line art. Member #bits# points to a bilevel
+ image representing the shape pixels. Member #parent# is the subscript of
+ the parent shape. */
+
+class JB2Shape
+{
+public:
+ /** Subscript of the parent shape. The parent shape must always be located
+ before the current shape in the shape array. A negative value indicates
+ that this shape has no parent. Any negative values smaller than #-1#
+ further indicates that this shape does not look like a character. This
+ is used to enable a few internal optimizations. This information is
+ saved into the JB2 file, but the actual value of the #parent# variable
+ is not. */
+ int parent;
+ /** Bilevel image of the shape pixels. This must be a pointer to a bilevel
+ #GBitmap# image. This pointer can also be null. The encoder will just
+ silently discard all blits referring to a shape containing a null
+ bitmap. */
+ GP<GBitmap> bits;
+ /** Private user data. This long word is provided as a convenience for users
+ of the JB2Image data structures. Neither the rendering functions nor
+ the coding functions ever access this value. */
+ long userdata;
+};
+
+
+
+/** JB2 Dictionary callback.
+ The decoding function call this callback function when they discover that
+ the current JB2Image or JB2Dict needs a pre-existing shape dictionary.
+ The callback function must return a pointer to the dictionary or NULL
+ if none is found. */
+
+typedef GP<JB2Dict> JB2DecoderCallback ( void* );
+
+
+/** Dictionary of JB2 shapes. */
+
+class JB2Dict : public GPEnabled
+{
+protected:
+ JB2Dict(void);
+public:
+ class JB2Codec;
+
+ // CONSTRUCTION
+ /** Default creator. Constructs an empty #JB2Dict# object. You can then
+ call the decoding function #decode#. You can also manually set the
+ image size using #add_shape#. */
+ static GP<JB2Dict> create(void);
+
+ // INITIALIZATION
+ /** Resets the #JB2Image# object. This function reinitializes both the shape
+ and the blit arrays. All allocated memory is freed. */
+ void init(void);
+
+ // INHERITED
+ /** Returns the inherited dictionary. */
+ GP<JB2Dict> get_inherited_dict(void) const;
+ /** Returns the number of inherited shapes. */
+ int get_inherited_shape_count(void) const;
+ /** Sets the inherited dictionary. */
+ void set_inherited_dict(const GP<JB2Dict> &dict);
+
+ // ACCESSING THE SHAPE LIBRARY
+ /** Returns the total number of shapes.
+ Shape indices range from #0# to #get_shape_count()-1#. */
+ int get_shape_count(void) const;
+ /** Returns a pointer to shape #shapeno#.
+ The returned pointer directly points into the shape array.
+ This pointer can be used for reading or writing the shape data. */
+ JB2Shape &get_shape(const int shapeno);
+ /** Returns a constant pointer to shape #shapeno#.
+ The returned pointer directly points into the shape array.
+ This pointer can only be used for reading the shape data. */
+ const JB2Shape &get_shape(const int shapeno) const;
+ /** Appends a shape to the shape array. This function appends a copy of
+ shape #shape# to the shape array and returns the subscript of the new
+ shape. The subscript of the parent shape #shape.parent# must
+ actually designate an already existing shape. */
+ int add_shape(const JB2Shape &shape);
+
+ // MEMORY OPTIMIZATION
+ /** Compresses all shape bitmaps. This function reduces the memory required
+ by the #JB2Image# by calling \Ref{GBitmap::compress} on all shapes
+ bitmaps. This function is best called after decoding a #JB2Image#,
+ because function \Ref{get_bitmap} can directly use the compressed
+ bitmaps. */
+ void compress(void);
+ /** Returns the total memory used by the JB2Image.
+ The returned value is expressed in bytes. */
+ unsigned int get_memory_usage(void) const;
+
+ // CODING
+ /** Encodes the JB2Dict into ByteStream #bs#.
+ This function generates the JB2 data stream without any header. */
+ void encode(const GP<ByteStream> &gbs) const;
+ /** Decodes JB2 data from ByteStream #bs#. This function decodes the image
+ size and populates the shape and blit arrays. The callback function
+ #cb# is called when the decoder determines that the ByteStream data
+ requires a shape dictionary which has not been set with
+ \Ref{JB2Dict::set_inherited_dict}. The callback receives argument #arg#
+ and must return a suitable dictionary which will be installed as the
+ inherited dictionary. The callback should return null if no such
+ dictionary is found. */
+ void decode(const GP<ByteStream> &gbs, JB2DecoderCallback *cb=0, void *arg=0);
+
+
+public:
+ /** Comment string coded by JB2 file. */
+ GUTF8String comment;
+
+private:
+ int inherited_shapes;
+ GP<JB2Dict> inherited_dict;
+ GArray<JB2Shape> shapes;
+
+};
+
+/** Main JB2 data structure. Each #JB2Image# consists of an array of shapes
+ and an array of blits. These arrays can be populated by hand using
+ functions \Ref{add_shape} and \Ref{add_blit}, or by decoding JB2 data
+ using function \Ref{decode}. You can then use function \Ref{get_bitmap}
+ to render anti-aliased images, or use function \Ref{encode} to generate
+ JB2 data. */
+
+class JB2Image : public JB2Dict
+{
+protected:
+ JB2Image(void);
+public:
+
+ /** Creates an empty #JB2Image# object. You can then
+ call the decoding function #decode#. You can also manually set the
+ image size using #set_dimension# and populate the shape and blit arrays
+ using #add_shape# and #add_blit#. */
+ static GP<JB2Image> create(void) { return new JB2Image(); }
+
+ // INITIALIZATION
+ /** Resets the #JB2Image# object. This function reinitializes both the shape
+ and the blit arrays. All allocated memory is freed. */
+ void init(void);
+
+ // DIMENSION
+ /** Returns the width of the image.
+ This is the width value previously set with #set_dimension#. */
+ int get_width(void) const;
+ /** Returns the height of the image.
+ This is the height value previously set with #set_dimension#. */
+ int get_height(void) const;
+ /** Sets the size of the JB2Image.
+ This function can be called at any time.
+ The corresponding #width# and the #height# are stored
+ in the JB2 file. */
+ void set_dimension(int width, int height);
+
+ // RENDERING
+ /** Renders an anti-aliased gray level image. This function renders the
+ JB2Image as a bilevel or gray level image. Argument #subsample#
+ specifies the desired subsampling ratio in range #1# to #15#. The
+ returned image uses #1+subsample^2# gray levels for representing
+ anti-aliased edges. Argument #align# specified the alignment of the
+ rows of the returned images. Setting #align# to #4#, for instance, will
+ adjust the bitmap border in order to make sure that each row of the
+ returned image starts on a word (four byte) boundary. */
+ GP<GBitmap> get_bitmap(int subsample = 1, int align = 1) const;
+ /** Renders an anti-aliased gray level sub-image. This function renders a
+ segment of the JB2Image as a bilevel or gray level image. Conceptually,
+ this function first renders the full JB2Image with subsampling ratio
+ #subsample# and then extracts rectangle #rect# in the subsampled image.
+ Both operations of course are efficiently performed simultaneously.
+ Argument #align# specified the alignment of the rows of the returned
+ images, as explained above. Argument #dispy# should remain null. */
+ GP<GBitmap> get_bitmap(const GRect &rect, int subsample=1, int align=1, int dispy=0) const;
+
+ // ACCESSING THE BLIT LIBRARY
+ /** Returns the total number of blits.
+ Blit indices range from #0# to #get_blit_count(void)-1#. */
+ int get_blit_count(void) const;
+ /** Returns a pointer to blit #blitno#.
+ The returned pointer directly points into the blit array.
+ This pointer can be used for reading or writing the blit data. */
+ JB2Blit *get_blit(int blitno);
+ /** Returns a constant pointer to blit #blitno#.
+ The returned pointer directly points into the shape array.
+ This pointer can only be used for reading the shape data. */
+ const JB2Blit *get_blit(int blitno) const;
+ /** Appends a blit to the blit array. This function appends a copy of blit
+ #blit# to the blit array and returns the subscript of the new blit. The
+ shape subscript #blit.shapeno# must actually designate an already
+ existing shape. */
+ int add_blit(const JB2Blit &blit);
+
+ // MEMORY OPTIMIZATION
+ /** Returns the total memory used by the JB2Image.
+ The returned value is expressed in bytes. */
+ unsigned int get_memory_usage(void) const;
+
+ // CODING
+ /** Encodes the JB2Image into ByteStream #bs#.
+ This function generates the JB2 data stream without any header. */
+ void encode(const GP<ByteStream> &gbs) const;
+ /** Decodes JB2 data from ByteStream #bs#. This function decodes the image
+ size and populates the shape and blit arrays. The callback function
+ #cb# is called when the decoder determines that the ByteStream data
+ requires a shape dictionary which has not been set with
+ \Ref{JB2Dict::set_inherited_dict}. The callback receives argument #arg#
+ and must return a suitable dictionary which will be installed as the
+ inherited dictionary. The callback should return null if no such
+ dictionary is found. */
+ void decode(const GP<ByteStream> &gbs, JB2DecoderCallback *cb=0, void *arg=0);
+
+private:
+ // Implementation
+ int width;
+ int height;
+ GTArray<JB2Blit> blits;
+public:
+ /** Reproduces a old bug. Setting this flag may be necessary for accurately
+ decoding DjVu files with version smaller than #18#. The default value
+ is of couse #false#. */
+ bool reproduce_old_bug;
+};
+
+
+
+// JB2DICT INLINE FUNCTIONS
+
+inline int
+JB2Dict::get_shape_count(void) const
+{
+ return inherited_shapes + shapes.size();
+}
+
+inline int
+JB2Dict::get_inherited_shape_count(void) const
+{
+ return inherited_shapes;
+}
+
+inline GP<JB2Dict>
+JB2Dict::get_inherited_dict(void) const
+{
+ return inherited_dict;
+}
+
+// JB2IMAGE INLINE FUNCTIONS
+
+inline int
+JB2Image::get_width(void) const
+{
+ return width;
+}
+
+inline int
+JB2Image::get_height(void) const
+{
+ return height;
+}
+
+
+inline int
+JB2Image::get_blit_count(void) const
+{
+ return blits.size();
+}
+
+
+inline JB2Blit *
+JB2Image::get_blit(int blitno)
+{
+ return & blits[blitno];
+}
+
+inline const JB2Blit *
+JB2Image::get_blit(int blitno) const
+{
+ return & blits[blitno];
+}
+
+
+
+
+
+/** @name JB2 extensions for version 21.
+
+ Two extensions of the JB2 encoding format have been introduced
+ with DjVu files version 21. Both extensions maintain significant
+ backward compatibility with previous version of the JB2 format.
+ These extensions are described below by reference to the ICFDD
+ proposal dated August 1999. Both extension make use of the unused
+ record type value #9# (cf. ICFDD page 24) which has been renamed
+ #REQUIRED_DICT_OR_RESET#.
+
+ {\bf Shared Shape Dictionaries} --- This extension provides
+ support for sharing symbol definitions between the pages of a
+ document. To achieve this objective, the JB2 image data chunk
+ must be able to address symbols defined elsewhere by a JB2
+ dictionary data chunk shared by all the pages of a document.
+
+ The arithmetically encoded JB2 image data logically consist of a
+ sequence of records. The decoder processes these records in
+ sequence and maintains a library of symbols which can be addressed
+ by the following records. The first record usually is a ``Start
+ Of Image'' record describing the size of the image.
+
+ Starting with version 21, a #REQUIRED_DICT_OR_RESET# (9) record
+ type can appear {\em before} the #START_OF_DATA# (0) record. The
+ record type field is followed by a single number arithmetically
+ encoded (cf. ICFDD page 26) using a sixteenth context (cf. ICFDD
+ page 25). This record appears when the JB2 data chunk requires
+ symbols encoded in a separate JB2 dictionary data chunk. The
+ number (the {\bf dictionary size}) indicates how many symbols
+ should have been defined by the JB2 dictionary data chunk. The
+ decoder should simply load these symbols in the symbol library and
+ proceed as usual. New symbols potentially defined by the
+ subsequent JB2 image data records will therefore be numbered with
+ integers greater or equal than the dictionary size.
+
+ The JB2 dictionary data format is a pure subset of the JB2 image
+ data format. The #START_OF_DATA# (0) record always specifies an
+ image width of zero and an image height of zero. The only allowed
+ record types are those defining library symbols only
+ (#NEW_SYMBOL_LIBRARY_ONLY# (2) and #MATCHED_REFINE_LIBRARY_ONLY#
+ (5) cf. ICFDD page 24) followed by a final #END_OF_DATA# (11)
+ record.
+
+ The JB2 dictionary data is usually located in an {\bf Djbz} chunk.
+ Each page {\bf FORM:DJVU} may directly contain a {\bf Djbz} chunk,
+ or may indirectly point to such a chunk using an {\bf INCL} chunk
+ (cf. \Ref{Multipage DjVu documents.}).
+
+
+ {\bf Numcoder Reset} --- This extension addresses a problem for
+ hardware implementations. The encoding of numbers (cf. ICFDD page
+ 26) potentially uses an unbounded number of binary coding
+ contexts. These contexts are normally allocated when they are used
+ for the first time (cf. ICFDD informative note, page 27).
+
+ Starting with version 21, a #REQUIRED_DICT_OR_RESET# (9) record
+ type can appear {\em after} the #START_OF_DATA# (0) record. The
+ decoder should proceed with the next record after {\em clearing
+ all binary contexts used for coding numbers}. This operation
+ implies that all binary contexts previously allocated for coding
+ numbers can be deallocated.
+
+ Starting with version 21, the JB2 encoder should insert a
+ #REQUIRED_DICT_OR_RESET# record type whenever the number of these
+ allocated binary contexts exceeds #20000#. Only very large
+ documents ever reach such a large number of allocated binary
+ contexts (e.g large maps). Hardware implementation however can
+ benefit greatly from a hard bound on the total number of binary
+ coding contexts. Old JB2 decoders will treat this record type as
+ an #END_OF_DATA# record and cleanly stop decoding (cf. ICFDD page
+ 30, Image refinement data).
+
+
+ {\bf References} ---
+ \begin{itemize}
+ \item ICFDD Draft Proposed American National Standard, 1999-08-26.
+ \item DjVu Specification, \URL{http://www.lizardtech.com/djvu/sci/djvuspec}.
+ \end{itemize}
+
+ @memo Extensions to the JB2 format introduced in version 21. */
+
+//@}
+
+////////////////////////////////////////
+//// CLASS JB2CODEC: DECLARATION
+////////////////////////////////////////
+
+// This class is accessed via the encode and decode
+// functions of class JB2Image
+
+
+//**** Class JB2Codec
+// This class implements the base class for both the JB2 coder and decoder.
+// The JB2Codec's Contains all contextual information for encoding/decoding
+// a JB2Image.
+
+class JB2Dict::JB2Codec
+{
+public:
+ class Decode;
+ class Encode;
+ typedef unsigned int NumContext;
+ struct LibRect
+ {
+ int top,left,right,bottom;
+ void compute_bounding_box(const GBitmap &cbm);
+ };
+ virtual ~JB2Codec();
+protected:
+ // Constructors
+ JB2Codec(const bool xencoding=false);
+ // Forbidden assignment
+ JB2Codec(const JB2Codec &ref);
+ JB2Codec& operator=(const JB2Codec &ref);
+
+ int CodeNum(int lo, int hi, NumContext *pctx,int v);
+ void reset_numcoder(void);
+ inline void code_eventual_lossless_refinement(void);
+ void init_library(JB2Dict &jim);
+ int add_library(const int shapeno, JB2Shape &jshp);
+ void code_relative_location(JB2Blit *jblt, int rows, int columns);
+ void code_bitmap_directly (GBitmap &bm);
+ void code_bitmap_by_cross_coding (GBitmap &bm, GP<GBitmap> &cbm, const int libno);
+ void code_record(int &rectype, const GP<JB2Dict> &jim, JB2Shape *jshp);
+ void code_record(int &rectype, const GP<JB2Image> &jim, JB2Shape *jshp, JB2Blit *jblt);
+ static void compute_bounding_box(GBitmap &cbm, LibRect &lrect);
+ static int get_direct_context( unsigned char const * const up2,
+ unsigned char const * const up1, unsigned char const * const up0,
+ const int column);
+ static int shift_direct_context ( const int context,
+ const int next, unsigned char const * const up2,
+ unsigned char const * const up1, unsigned char const * const up0,
+ const int column);
+ static int get_cross_context( unsigned char const * const up1,
+ unsigned char const * const up0, unsigned char const * const xup1,
+ unsigned char const * const xup0, unsigned char const * const xdn1,
+ const int column );
+ static int shift_cross_context( const int context,
+ const int n, unsigned char const * const up1,
+ unsigned char const * const up0, unsigned char const * const xup1,
+ unsigned char const * const xup0, unsigned char const * const xdn1,
+ const int column );
+
+ virtual bool CodeBit(const bool bit, BitContext &ctx) = 0;
+ virtual void code_comment(GUTF8String &comment) = 0;
+ virtual void code_record_type(int &rectype) = 0;
+ virtual int code_match_index(int &index, JB2Dict &jim)=0;
+ virtual void code_inherited_shape_count(JB2Dict &jim)=0;
+ virtual void code_image_size(JB2Dict &jim);
+ virtual void code_image_size(JB2Image &jim);
+ virtual void code_absolute_location(JB2Blit *jblt, int rows, int columns)=0;
+ virtual void code_absolute_mark_size(GBitmap &bm, int border=0) = 0;
+ virtual void code_relative_mark_size(GBitmap &bm, int cw, int ch, int border=0) = 0;
+ virtual void code_bitmap_directly(GBitmap &bm,const int dw, int dy,
+ unsigned char *up2, unsigned char *up1, unsigned char *up0 )=0;
+ virtual void code_bitmap_by_cross_coding (GBitmap &bm, GBitmap &cbm,
+ const int xd2c, const int dw, int dy, int cy,
+ unsigned char *up1, unsigned char *up0, unsigned char *xup1,
+ unsigned char *xup0, unsigned char *xdn1 )=0;
+ // Code records
+ virtual int get_diff(const int x_diff,NumContext &rel_loc) = 0;
+
+private:
+ bool encoding;
+
+protected:
+ // NumCoder
+ int cur_ncell;
+ BitContext *bitcells;
+ GPBuffer<BitContext> gbitcells;
+ NumContext *leftcell;
+ GPBuffer<NumContext> gleftcell;
+ NumContext *rightcell;
+ GPBuffer<NumContext> grightcell;
+ // Info
+ bool refinementp;
+ char gotstartrecordp;
+ // Code comment
+ NumContext dist_comment_byte;
+ NumContext dist_comment_length;
+ // Code values
+ NumContext dist_record_type;
+ NumContext dist_match_index;
+ BitContext dist_refinement_flag;
+ // Library
+ GTArray<int> shape2lib;
+ GTArray<int> lib2shape;
+ GTArray<LibRect> libinfo;
+ // Code pairs
+ NumContext abs_loc_x;
+ NumContext abs_loc_y;
+ NumContext abs_size_x;
+ NumContext abs_size_y;
+ NumContext image_size_dist;
+ NumContext inherited_shape_count_dist;
+ BitContext offset_type_dist;
+ NumContext rel_loc_x_current;
+ NumContext rel_loc_x_last;
+ NumContext rel_loc_y_current;
+ NumContext rel_loc_y_last;
+ NumContext rel_size_x;
+ NumContext rel_size_y;
+ int last_bottom;
+ int last_left;
+ int last_right;
+ int last_row_bottom;
+ int last_row_left;
+ int image_columns;
+ int image_rows;
+ int short_list[3];
+ int short_list_pos;
+ inline void fill_short_list(const int v);
+ int update_short_list(const int v);
+ // Code bitmaps
+ BitContext bitdist[1024];
+ BitContext cbitdist[2048];
+};
+
+inline void
+JB2Dict::JB2Codec::code_eventual_lossless_refinement(void)
+{
+ refinementp=CodeBit(refinementp, dist_refinement_flag);
+}
+
+inline void
+JB2Dict::JB2Codec::fill_short_list(const int v)
+{
+ short_list[0] = short_list[1] = short_list[2] = v;
+ short_list_pos = 0;
+}
+
+inline int
+JB2Dict::JB2Codec::get_direct_context( unsigned char const * const up2,
+ unsigned char const * const up1,
+ unsigned char const * const up0,
+ const int column)
+{
+ return ( (up2[column - 1] << 9) |
+ (up2[column ] << 8) |
+ (up2[column + 1] << 7) |
+ (up1[column - 2] << 6) |
+ (up1[column - 1] << 5) |
+ (up1[column ] << 4) |
+ (up1[column + 1] << 3) |
+ (up1[column + 2] << 2) |
+ (up0[column - 2] << 1) |
+ (up0[column - 1] << 0) );
+}
+
+inline int
+JB2Dict::JB2Codec::shift_direct_context(const int context, const int next,
+ unsigned char const * const up2,
+ unsigned char const * const up1,
+ unsigned char const * const up0,
+ const int column)
+{
+ return ( ((context << 1) & 0x37a) |
+ (up1[column + 2] << 2) |
+ (up2[column + 1] << 7) |
+ (next << 0) );
+}
+
+inline int
+JB2Dict::JB2Codec::get_cross_context( unsigned char const * const up1,
+ unsigned char const * const up0,
+ unsigned char const * const xup1,
+ unsigned char const * const xup0,
+ unsigned char const * const xdn1,
+ const int column )
+{
+ return ( ( up1[column - 1] << 10) |
+ ( up1[column ] << 9) |
+ ( up1[column + 1] << 8) |
+ ( up0[column - 1] << 7) |
+ (xup1[column ] << 6) |
+ (xup0[column - 1] << 5) |
+ (xup0[column ] << 4) |
+ (xup0[column + 1] << 3) |
+ (xdn1[column - 1] << 2) |
+ (xdn1[column ] << 1) |
+ (xdn1[column + 1] << 0) );
+}
+
+inline int
+JB2Dict::JB2Codec::shift_cross_context( const int context, const int n,
+ unsigned char const * const up1,
+ unsigned char const * const up0,
+ unsigned char const * const xup1,
+ unsigned char const * const xup0,
+ unsigned char const * const xdn1,
+ const int column )
+{
+ return ( ((context<<1) & 0x636) |
+ ( up1[column + 1] << 8) |
+ (xup1[column ] << 6) |
+ (xup0[column + 1] << 3) |
+ (xdn1[column + 1] << 0) |
+ (n << 7) );
+}
+
+// ---------- THE END
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
+
diff --git a/kviewshell/plugins/djvu/libdjvu/JPEGDecoder.cpp b/kviewshell/plugins/djvu/libdjvu/JPEGDecoder.cpp
new file mode 100644
index 00000000..3f611965
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/JPEGDecoder.cpp
@@ -0,0 +1,413 @@
+//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: JPEGDecoder.cpp,v 1.8 2003/11/07 22:08:22 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#ifdef NEED_JPEG_DECODER
+
+#include "JPEGDecoder.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef HAVE_STDLIB_H
+#undef HAVE_STDDEF_H
+#include <stdio.h>
+#include <jconfig.h>
+#include <jpeglib.h>
+#include <jerror.h>
+#ifdef __cplusplus
+}
+#endif
+
+#include "ByteStream.h"
+#include "GPixmap.h"
+#ifdef LIBJPEGNAME
+#include "DjVuDynamic.h"
+#include "GString.h"
+#endif // LIBJPEGNAME
+
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+class JPEGDecoder::Impl : public JPEGDecoder
+{
+public:
+ static void jpeg_byte_stream_src(j_decompress_ptr, ByteStream &);
+};
+
+extern "C"
+{
+
+struct djvu_error_mgr
+{
+ struct jpeg_error_mgr pub; /* "public" fields */
+
+ jmp_buf setjmp_buffer; /* for return to caller */
+};
+
+typedef struct djvu_error_mgr * djvu_error_ptr;
+
+METHODDEF(void)
+djvu_error_exit (j_common_ptr cinfo)
+{
+ /* cinfo->err really points to a djvu_error_mgr struct, so coerce pointer */
+ djvu_error_ptr djvuerr = (djvu_error_ptr) cinfo->err;
+
+ /* Always display the message. */
+ /* We could postpone this until after returning, if we chose. */
+ (*cinfo->err->output_message) (cinfo);
+
+ /* Return control to the setjmp point */
+ longjmp(djvuerr->setjmp_buffer, 1);
+}
+
+}
+
+GP<GPixmap>
+JPEGDecoder::decode(ByteStream & bs )
+{
+ GP<GPixmap> retval=GPixmap::create();
+ G_TRY
+ {
+ decode(bs,*retval);
+ } G_CATCH_ALL
+ {
+ retval=0;
+ }
+ G_ENDCATCH;
+ return retval;
+}
+
+void
+JPEGDecoder::decode(ByteStream & bs,GPixmap &pix)
+{
+ struct jpeg_decompress_struct cinfo;
+
+ /* We use our private extension JPEG error handler. */
+ struct djvu_error_mgr jerr;
+
+ JSAMPARRAY buffer; /* Output row buffer */
+ int row_stride; /* physical row width in output buffer */
+ int full_buf_size;
+ int isGrey,i;
+
+ cinfo.err = jpeg_std_error(&jerr.pub);
+
+ jerr.pub.error_exit = djvu_error_exit;
+
+ if (setjmp(jerr.setjmp_buffer))
+ {
+
+ jpeg_destroy_decompress(&cinfo);
+ G_THROW( ERR_MSG("GPixmap.unk_PPM") );
+ }
+
+ jpeg_create_decompress(&cinfo);
+
+ Impl::jpeg_byte_stream_src(&cinfo, bs);
+
+ (void) jpeg_read_header(&cinfo, TRUE);
+
+ jpeg_start_decompress(&cinfo);
+
+ /* We may need to do some setup of our own at this point before reading
+ * the data. After jpeg_start_decompress() we have the correct scaled
+ * output image dimensions available, as well as the output colormap
+ * if we asked for color quantization.
+ * In this example, we need to make an output work buffer of the right size.
+ */
+
+ /* JSAMPLEs per row in output buffer */
+ row_stride = cinfo.output_width * cinfo.output_components;
+ full_buf_size = row_stride * cinfo.output_height;
+
+ /* Make a one-row-high sample array that will go away when done with image */
+ buffer = (*cinfo.mem->alloc_sarray)
+ ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
+
+ GP<ByteStream> goutputBlock=ByteStream::create();
+ ByteStream &outputBlock=*goutputBlock;
+ outputBlock.format("P6\n%d %d\n%d\n",cinfo.output_width,
+ cinfo.output_height,255);
+
+ isGrey = ( cinfo.out_color_space == JCS_GRAYSCALE) ? 1 : 0;
+
+ while (cinfo.output_scanline < cinfo.output_height)
+ {
+ (void) jpeg_read_scanlines(&cinfo, buffer, 1);
+
+ if ( isGrey == 1 )
+ {
+ for (i=0; i<row_stride; i++)
+ {
+ outputBlock.write8((char)buffer[0][i]);
+ outputBlock.write8((char)buffer[0][i]);
+ outputBlock.write8((char)buffer[0][i]);
+ }
+ }else
+ {
+ for (i=0; i<row_stride; i++)
+ outputBlock.write8((char)buffer[0][i]);
+ }
+ }
+
+ (void) jpeg_finish_decompress(&cinfo);
+
+ jpeg_destroy_decompress(&cinfo);
+
+ outputBlock.seek(0,SEEK_SET);
+
+ pix.init(outputBlock);
+}
+
+/*** From here onwards code is to make ByteStream as the data
+ source for the JPEG library */
+
+extern "C"
+{
+
+typedef struct
+{
+ struct jpeg_source_mgr pub; /* public fields */
+
+ ByteStream * byteStream; /* source stream */
+ JOCTET * buffer; /* start of buffer */
+ boolean start_of_stream;
+} byte_stream_src_mgr;
+
+
+typedef byte_stream_src_mgr * byte_stream_src_ptr;
+
+#define INPUT_BUF_SIZE 4096
+
+METHODDEF(void)
+init_source (j_decompress_ptr cinfo)
+{
+ byte_stream_src_ptr src = (byte_stream_src_ptr) cinfo->src;
+
+ src->start_of_stream = TRUE;
+}
+
+METHODDEF(boolean)
+fill_input_buffer (j_decompress_ptr cinfo)
+{
+ byte_stream_src_ptr src = (byte_stream_src_ptr) cinfo->src;
+ size_t nbytes;
+
+ nbytes = src->byteStream->readall(src->buffer, INPUT_BUF_SIZE);
+
+ if (nbytes <= 0)
+ {
+ if (src->start_of_stream) /* Treat empty input as fatal error */
+ ERREXIT(cinfo, JERR_INPUT_EMPTY);
+ WARNMS(cinfo, JWRN_JPEG_EOF);
+ /* Insert a fake EOI marker */
+ src->buffer[0] = (JOCTET) 0xFF;
+ src->buffer[1] = (JOCTET) JPEG_EOI;
+ nbytes = 2;
+ }
+
+ src->pub.next_input_byte = src->buffer;
+ src->pub.bytes_in_buffer = nbytes;
+ src->start_of_stream = FALSE;
+
+ return TRUE;
+}
+
+
+METHODDEF(void)
+skip_input_data (j_decompress_ptr cinfo, long num_bytes)
+{
+ byte_stream_src_ptr src = (byte_stream_src_ptr) cinfo->src;
+
+ if (num_bytes > (long) src->pub.bytes_in_buffer)
+ {
+ src->byteStream->seek((num_bytes - src->pub.bytes_in_buffer), SEEK_CUR);
+ (void) fill_input_buffer(cinfo);
+ }else
+ {
+ src->pub.bytes_in_buffer -= num_bytes;
+ src->pub.next_input_byte += num_bytes;
+ }
+}
+
+METHODDEF(void)
+term_source (j_decompress_ptr cinfo)
+{
+ /* no work necessary here */
+}
+
+}
+
+void
+JPEGDecoder::Impl::jpeg_byte_stream_src(j_decompress_ptr cinfo,ByteStream &bs)
+{
+ byte_stream_src_ptr src;
+
+ if (cinfo->src == NULL)
+ { /* first time for this JPEG object? */
+ cinfo->src = (struct jpeg_source_mgr *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ sizeof(byte_stream_src_mgr));
+ src = (byte_stream_src_ptr) cinfo->src;
+ src->buffer = (JOCTET *)
+ (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
+ INPUT_BUF_SIZE * sizeof(JOCTET));
+ }
+
+ src = (byte_stream_src_ptr) cinfo->src;
+ src->pub.init_source = init_source;
+ src->pub.fill_input_buffer = fill_input_buffer;
+ src->pub.skip_input_data = skip_input_data;
+ src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
+ src->pub.term_source = term_source;
+ src->byteStream = &bs;
+ src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
+ src->pub.next_input_byte = NULL; /* until buffer loaded */
+}
+
+#ifdef LIBJPEGNAME
+void *
+JPEGDecoder::jpeg_lookup(const GUTF8String &name)
+{
+ static DjVuDynamic lib(GUTF8String(LIBJPEGNAME));
+ void *sym=lib.lookup(name);
+ if(!sym)
+ G_THROW(ERR_MSG("DjVuFile.JPEG_bg2"));
+ return sym;
+}
+
+jpeg_error_mgr *
+JPEGDecoder::jpeg_std_error(jpeg_error_mgr *x)
+{
+ static void *sym=jpeg_lookup("jpeg_std_error");
+ return ((jpeg_error_mgr *(*)(jpeg_error_mgr *))sym)(x);
+}
+
+void
+JPEGDecoder::jpeg_CreateDecompress(jpeg_decompress_struct *x,int v, size_t s)
+{
+ static void *sym=jpeg_lookup("jpeg_CreateDecompress");
+ ((void (*)(jpeg_decompress_struct *,int,size_t))sym)(x,v,s);
+}
+
+void
+JPEGDecoder::jpeg_destroy_decompress(j_decompress_ptr x)
+{
+ static void *sym=jpeg_lookup("jpeg_destroy_decompress");
+ ((void (*)(j_decompress_ptr))sym)(x);
+}
+
+int
+JPEGDecoder::jpeg_read_header(j_decompress_ptr x,boolean y)
+{
+ static void *sym=jpeg_lookup("jpeg_read_header");
+ return ((int (*)(j_decompress_ptr,boolean))sym)(x,y);
+}
+
+JDIMENSION
+JPEGDecoder::jpeg_read_scanlines(j_decompress_ptr x,JSAMPARRAY y,JDIMENSION z)
+{
+ static void *sym=jpeg_lookup("jpeg_read_scanlines");
+ return ((JDIMENSION (*)(j_decompress_ptr,JSAMPARRAY,JDIMENSION))sym)(x,y,z);
+}
+
+boolean
+JPEGDecoder::jpeg_finish_decompress(j_decompress_ptr x)
+{
+ static void *sym=jpeg_lookup("jpeg_finish_decompress");
+ return ((boolean (*)(j_decompress_ptr))sym)(x);
+}
+
+boolean
+JPEGDecoder::jpeg_resync_to_restart(jpeg_decompress_struct *x,int d)
+{
+ static void *sym=jpeg_lookup("jpeg_resync_to_restart");
+ return ((boolean (*)(jpeg_decompress_struct *,int))sym)(x,d);
+}
+
+boolean
+JPEGDecoder::jpeg_start_decompress(j_decompress_ptr x)
+{
+ static void *sym=jpeg_lookup("jpeg_start_decompress");
+ return ((boolean (*)(j_decompress_ptr))sym)(x);
+}
+
+#endif // LIBJPEGNAME
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+
+#endif
+
diff --git a/kviewshell/plugins/djvu/libdjvu/JPEGDecoder.h b/kviewshell/plugins/djvu/libdjvu/JPEGDecoder.h
new file mode 100644
index 00000000..8a0ace5d
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/JPEGDecoder.h
@@ -0,0 +1,133 @@
+//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: JPEGDecoder.h,v 1.8 2003/11/07 22:08:22 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _JPEGDECODER_H_
+#define _JPEGDECODER_H_
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+#ifdef NEED_JPEG_DECODER
+
+#include <string.h>
+#include <setjmp.h>
+
+#include "GSmartPointer.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+class ByteStream;
+class GPixmap;
+
+
+/** @name JPEGDecoder.h
+ Files #"JPEGDecoder.h"# and #"JPEGDecoder.cpp"# implement an
+ interface to the decoding subset of the IJG JPEG library.
+ @memo
+ Decoding interface to the IJG JPEG library.
+ @version
+ #$Id: JPEGDecoder.h,v 1.8 2003/11/07 22:08:22 leonb Exp $#
+ @author
+ Parag Deshmukh <parag@sanskrit.lz.att.com>
+*/
+//@{
+
+class GUTF8String;
+
+/** This class ensures namespace isolation. */
+class JPEGDecoder
+{
+public:
+ class Impl;
+
+ /** Decodes the JPEG formated ByteStream */
+ static GP<GPixmap> decode(ByteStream & bs);
+ static void decode(ByteStream & bs,GPixmap &pix);
+#ifdef LIBJPEGNAME
+ static void *jpeg_lookup(const GUTF8String &name);
+ static jpeg_error_mgr *jpeg_std_error(jpeg_error_mgr *x);
+ static void jpeg_CreateDecompress(jpeg_decompress_struct *x,int v, size_t s);
+ static void jpeg_destroy_decompress(j_decompress_ptr x);
+ static int jpeg_read_header(j_decompress_ptr x,boolean y);
+ static JDIMENSION jpeg_read_scanlines(j_decompress_ptr x,JSAMPARRAY y,JDIMENSION z);
+ static boolean jpeg_finish_decompress(j_decompress_ptr x);
+ static boolean jpeg_resync_to_restart(jpeg_decompress_struct *x,int d);
+ static boolean jpeg_start_decompress(j_decompress_ptr x);
+#endif // LIBJPEGNAME
+};
+
+
+//@}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+
+#endif // NEED_JPEG_DECODER
+#endif // _JPEGDECODER_H_
+
diff --git a/kviewshell/plugins/djvu/libdjvu/MMRDecoder.cpp b/kviewshell/plugins/djvu/libdjvu/MMRDecoder.cpp
new file mode 100644
index 00000000..b14220d1
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/MMRDecoder.cpp
@@ -0,0 +1,961 @@
+//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: MMRDecoder.cpp,v 1.8 2003/11/07 22:08:22 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "MMRDecoder.h"
+#include "JB2Image.h"
+#include "ByteStream.h"
+#include "GBitmap.h"
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+// ----------------------------------------
+// MMR CODEBOOKS
+
+static const char invalid_mmr_data[]= ERR_MSG("MMRDecoder.bad_data");
+
+struct VLCode
+{
+ unsigned short code;
+ short codelen;
+ short value;
+};
+
+enum MMRMode
+{
+ P=0, H=1, V0=2, VR1=3, VR2=4, VR3=5, VL1=6, VL2=7, VL3=8
+};
+
+static const VLCode mrcodes[] =
+{ // Codes on 7 bits
+ // 7 bit codes
+ { 0x08, 4, P }, // 0001
+ { 0x10, 3, H }, // 001
+ { 0x40, 1, V0 }, // 1
+ { 0x30, 3, VR1 }, // 011
+ { 0x06, 6, VR2 }, // 000011
+ { 0x03, 7, VR3 }, // 0000011
+ { 0x20, 3, VL1 }, // 010
+ { 0x04, 6, VL2 }, // 000010
+ { 0x02, 7, VL3 }, // 0000010
+ { 0x00, 0, -1 } // Illegal entry
+};
+
+
+static const VLCode wcodes[] = {
+ // 13 bit codes
+ { 0x06a0, 8, 0 }, // 00110101
+ { 0x0380, 6, 1 }, // 000111
+ { 0x0e00, 4, 2 }, // 0111
+ { 0x1000, 4, 3 }, // 1000
+ { 0x1600, 4, 4 }, // 1011
+ { 0x1800, 4, 5 }, // 1100
+ { 0x1c00, 4, 6 }, // 1110
+ { 0x1e00, 4, 7 }, // 1111
+ { 0x1300, 5, 8 }, // 10011
+ { 0x1400, 5, 9 }, // 10100
+ { 0x0700, 5, 10 }, // 00111
+ { 0x0800, 5, 11 }, // 01000
+ { 0x0400, 6, 12 }, // 001000
+ { 0x0180, 6, 13 }, // 000011
+ { 0x1a00, 6, 14 }, // 110100
+ { 0x1a80, 6, 15 }, // 110101
+ { 0x1500, 6, 16 }, // 101010
+ { 0x1580, 6, 17 }, // 101011
+ { 0x09c0, 7, 18 }, // 0100111
+ { 0x0300, 7, 19 }, // 0001100
+ { 0x0200, 7, 20 }, // 0001000
+ { 0x05c0, 7, 21 }, // 0010111
+ { 0x00c0, 7, 22 }, // 0000011
+ { 0x0100, 7, 23 }, // 0000100
+ { 0x0a00, 7, 24 }, // 0101000
+ { 0x0ac0, 7, 25 }, // 0101011
+ { 0x04c0, 7, 26 }, // 0010011
+ { 0x0900, 7, 27 }, // 0100100
+ { 0x0600, 7, 28 }, // 0011000
+ { 0x0040, 8, 29 }, // 00000010
+ { 0x0060, 8, 30 }, // 00000011
+ { 0x0340, 8, 31 }, // 00011010
+ { 0x0360, 8, 32 }, // 00011011
+ { 0x0240, 8, 33 }, // 00010010
+ { 0x0260, 8, 34 }, // 00010011
+ { 0x0280, 8, 35 }, // 00010100
+ { 0x02a0, 8, 36 }, // 00010101
+ { 0x02c0, 8, 37 }, // 00010110
+ { 0x02e0, 8, 38 }, // 00010111
+ { 0x0500, 8, 39 }, // 00101000
+ { 0x0520, 8, 40 }, // 00101001
+ { 0x0540, 8, 41 }, // 00101010
+ { 0x0560, 8, 42 }, // 00101011
+ { 0x0580, 8, 43 }, // 00101100
+ { 0x05a0, 8, 44 }, // 00101101
+ { 0x0080, 8, 45 }, // 00000100
+ { 0x00a0, 8, 46 }, // 00000101
+ { 0x0140, 8, 47 }, // 00001010
+ { 0x0160, 8, 48 }, // 00001011
+ { 0x0a40, 8, 49 }, // 01010010
+ { 0x0a60, 8, 50 }, // 01010011
+ { 0x0a80, 8, 51 }, // 01010100
+ { 0x0aa0, 8, 52 }, // 01010101
+ { 0x0480, 8, 53 }, // 00100100
+ { 0x04a0, 8, 54 }, // 00100101
+ { 0x0b00, 8, 55 }, // 01011000
+ { 0x0b20, 8, 56 }, // 01011001
+ { 0x0b40, 8, 57 }, // 01011010
+ { 0x0b60, 8, 58 }, // 01011011
+ { 0x0940, 8, 59 }, // 01001010
+ { 0x0960, 8, 60 }, // 01001011
+ { 0x0640, 8, 61 }, // 00110010
+ { 0x0660, 8, 62 }, // 00110011
+ { 0x0680, 8, 63 }, // 00110100
+ { 0x1b00, 5, 64 }, // 11011
+ { 0x1200, 5, 128 }, // 10010
+ { 0x0b80, 6, 192 }, // 010111
+ { 0x0dc0, 7, 256 }, // 0110111
+ { 0x06c0, 8, 320 }, // 00110110
+ { 0x06e0, 8, 384 }, // 00110111
+ { 0x0c80, 8, 448 }, // 01100100
+ { 0x0ca0, 8, 512 }, // 01100101
+ { 0x0d00, 8, 576 }, // 01101000
+ { 0x0ce0, 8, 640 }, // 01100111
+ { 0x0cc0, 9, 704 }, // 011001100
+ { 0x0cd0, 9, 768 }, // 011001101
+ { 0x0d20, 9, 832 }, // 011010010
+ { 0x0d30, 9, 896 }, // 011010011
+ { 0x0d40, 9, 960 }, // 011010100
+ { 0x0d50, 9, 1024 }, // 011010101
+ { 0x0d60, 9, 1088 }, // 011010110
+ { 0x0d70, 9, 1152 }, // 011010111
+ { 0x0d80, 9, 1216 }, // 011011000
+ { 0x0d90, 9, 1280 }, // 011011001
+ { 0x0da0, 9, 1344 }, // 011011010
+ { 0x0db0, 9, 1408 }, // 011011011
+ { 0x0980, 9, 1472 }, // 010011000
+ { 0x0990, 9, 1536 }, // 010011001
+ { 0x09a0, 9, 1600 }, // 010011010
+ { 0x0c00, 6, 1664 }, // 011000 (what did they think?)
+ { 0x09b0, 9, 1728 }, // 010011011
+ { 0x0020, 11, 1792 }, // 00000001000
+ { 0x0030, 11, 1856 }, // 00000001100
+ { 0x0034, 11, 1920 }, // 00000001101
+ { 0x0024, 12, 1984 }, // 000000010010
+ { 0x0026, 12, 2048 }, // 000000010011
+ { 0x0028, 12, 2112 }, // 000000010100
+ { 0x002a, 12, 2176 }, // 000000010101
+ { 0x002c, 12, 2240 }, // 000000010110
+ { 0x002e, 12, 2304 }, // 000000010111
+ { 0x0038, 12, 2368 }, // 000000011100
+ { 0x003a, 12, 2432 }, // 000000011101
+ { 0x003c, 12, 2496 }, // 000000011110
+ { 0x003e, 12, 2560 }, // 000000011111
+ { 0x0000, 0, -1 } // Illegal entry
+};
+
+
+static const VLCode bcodes[] = {
+ // 13 bit codes
+ { 0x01b8, 10, 0 }, // 0000110111
+ { 0x0800, 3, 1 }, // 010
+ { 0x1800, 2, 2 }, // 11
+ { 0x1000, 2, 3 }, // 10
+ { 0x0c00, 3, 4 }, // 011
+ { 0x0600, 4, 5 }, // 0011
+ { 0x0400, 4, 6 }, // 0010
+ { 0x0300, 5, 7 }, // 00011
+ { 0x0280, 6, 8 }, // 000101
+ { 0x0200, 6, 9 }, // 000100
+ { 0x0100, 7, 10 }, // 0000100
+ { 0x0140, 7, 11 }, // 0000101
+ { 0x01c0, 7, 12 }, // 0000111
+ { 0x0080, 8, 13 }, // 00000100
+ { 0x00e0, 8, 14 }, // 00000111
+ { 0x0180, 9, 15 }, // 000011000
+ { 0x00b8, 10, 16 }, // 0000010111
+ { 0x00c0, 10, 17 }, // 0000011000
+ { 0x0040, 10, 18 }, // 0000001000
+ { 0x019c, 11, 19 }, // 00001100111
+ { 0x01a0, 11, 20 }, // 00001101000
+ { 0x01b0, 11, 21 }, // 00001101100
+ { 0x00dc, 11, 22 }, // 00000110111
+ { 0x00a0, 11, 23 }, // 00000101000
+ { 0x005c, 11, 24 }, // 00000010111
+ { 0x0060, 11, 25 }, // 00000011000
+ { 0x0194, 12, 26 }, // 000011001010
+ { 0x0196, 12, 27 }, // 000011001011
+ { 0x0198, 12, 28 }, // 000011001100
+ { 0x019a, 12, 29 }, // 000011001101
+ { 0x00d0, 12, 30 }, // 000001101000
+ { 0x00d2, 12, 31 }, // 000001101001
+ { 0x00d4, 12, 32 }, // 000001101010
+ { 0x00d6, 12, 33 }, // 000001101011
+ { 0x01a4, 12, 34 }, // 000011010010
+ { 0x01a6, 12, 35 }, // 000011010011
+ { 0x01a8, 12, 36 }, // 000011010100
+ { 0x01aa, 12, 37 }, // 000011010101
+ { 0x01ac, 12, 38 }, // 000011010110
+ { 0x01ae, 12, 39 }, // 000011010111
+ { 0x00d8, 12, 40 }, // 000001101100
+ { 0x00da, 12, 41 }, // 000001101101
+ { 0x01b4, 12, 42 }, // 000011011010
+ { 0x01b6, 12, 43 }, // 000011011011
+ { 0x00a8, 12, 44 }, // 000001010100
+ { 0x00aa, 12, 45 }, // 000001010101
+ { 0x00ac, 12, 46 }, // 000001010110
+ { 0x00ae, 12, 47 }, // 000001010111
+ { 0x00c8, 12, 48 }, // 000001100100
+ { 0x00ca, 12, 49 }, // 000001100101
+ { 0x00a4, 12, 50 }, // 000001010010
+ { 0x00a6, 12, 51 }, // 000001010011
+ { 0x0048, 12, 52 }, // 000000100100
+ { 0x006e, 12, 53 }, // 000000110111
+ { 0x0070, 12, 54 }, // 000000111000
+ { 0x004e, 12, 55 }, // 000000100111
+ { 0x0050, 12, 56 }, // 000000101000
+ { 0x00b0, 12, 57 }, // 000001011000
+ { 0x00b2, 12, 58 }, // 000001011001
+ { 0x0056, 12, 59 }, // 000000101011
+ { 0x0058, 12, 60 }, // 000000101100
+ { 0x00b4, 12, 61 }, // 000001011010
+ { 0x00cc, 12, 62 }, // 000001100110
+ { 0x00ce, 12, 63 }, // 000001100111
+ { 0x0078, 10, 64 }, // 0000001111
+ { 0x0190, 12, 128 }, // 000011001000
+ { 0x0192, 12, 192 }, // 000011001001
+ { 0x00b6, 12, 256 }, // 000001011011
+ { 0x0066, 12, 320 }, // 000000110011
+ { 0x0068, 12, 384 }, // 000000110100
+ { 0x006a, 12, 448 }, // 000000110101
+ { 0x006c, 13, 512 }, // 0000001101100
+ { 0x006d, 13, 576 }, // 0000001101101
+ { 0x004a, 13, 640 }, // 0000001001010
+ { 0x004b, 13, 704 }, // 0000001001011
+ { 0x004c, 13, 768 }, // 0000001001100
+ { 0x004d, 13, 832 }, // 0000001001101
+ { 0x0072, 13, 896 }, // 0000001110010
+ { 0x0073, 13, 960 }, // 0000001110011
+ { 0x0074, 13, 1024 }, // 0000001110100
+ { 0x0075, 13, 1088 }, // 0000001110101
+ { 0x0076, 13, 1152 }, // 0000001110110
+ { 0x0077, 13, 1216 }, // 0000001110111
+ { 0x0052, 13, 1280 }, // 0000001010010
+ { 0x0053, 13, 1344 }, // 0000001010011
+ { 0x0054, 13, 1408 }, // 0000001010100
+ { 0x0055, 13, 1472 }, // 0000001010101
+ { 0x005a, 13, 1536 }, // 0000001011010
+ { 0x005b, 13, 1600 }, // 0000001011011
+ { 0x0064, 13, 1664 }, // 0000001100100
+ { 0x0065, 13, 1728 }, // 0000001100101
+ { 0x0020, 11, 1792 }, // 00000001000
+ { 0x0030, 11, 1856 }, // 00000001100
+ { 0x0034, 11, 1920 }, // 00000001101
+ { 0x0024, 12, 1984 }, // 000000010010
+ { 0x0026, 12, 2048 }, // 000000010011
+ { 0x0028, 12, 2112 }, // 000000010100
+ { 0x002a, 12, 2176 }, // 000000010101
+ { 0x002c, 12, 2240 }, // 000000010110
+ { 0x002e, 12, 2304 }, // 000000010111
+ { 0x0038, 12, 2368 }, // 000000011100
+ { 0x003a, 12, 2432 }, // 000000011101
+ { 0x003c, 12, 2496 }, // 000000011110
+ { 0x003e, 12, 2560 }, // 000000011111
+ { 0x0000, 0, -1 } // Illegal entry
+};
+
+
+
+
+// ----------------------------------------
+// SOURCE OF BITS
+
+#define VLSBUFSIZE 64
+
+class MMRDecoder::VLSource : public GPEnabled
+{
+protected:
+ VLSource(GP<ByteStream> &inp);
+ void init(const bool striped);
+public:
+ // Initializes a bit source on a bytestream
+ static GP<VLSource> create(GP<ByteStream> &inp, const bool striped);
+
+ // Synchronize on the next stripe
+ void nextstripe(void);
+ // Returns a 32 bits integer with at least the
+ // next sixteen code bits in the high order bits.
+ inline unsigned int peek(void);
+ // Ensures that next #peek()# contains at least
+ // the next 24 code bits.
+ void preload(void);
+ // Consumes #n# bits.
+ void shift(const int n);
+private:
+ GP<ByteStream> ginp;
+ ByteStream &inp;
+ unsigned char buffer[ VLSBUFSIZE ];
+ unsigned int codeword;
+ int lowbits;
+ int bufpos;
+ int bufmax;
+ int readmax;
+};
+
+MMRDecoder::VLSource::VLSource(GP<ByteStream> &xinp)
+: ginp(xinp), inp(*ginp), codeword(0),
+ lowbits(0), bufpos(0), bufmax(0),
+ readmax(-1)
+{}
+
+void
+MMRDecoder::VLSource::init(const bool striped)
+{
+ if (striped)
+ readmax = inp.read32();
+ lowbits = 32;
+ preload();
+}
+
+GP<MMRDecoder::VLSource>
+MMRDecoder::VLSource::create(GP<ByteStream> &inp, const bool striped)
+{
+ VLSource *src=new VLSource(inp);
+ GP<VLSource> retval=src;
+ src->init(striped);
+ return retval;
+}
+
+void
+MMRDecoder::VLSource::shift(const int n)
+{
+ codeword<<=n;
+ lowbits+=n;
+ if (lowbits>=16)
+ preload();
+}
+
+inline unsigned int
+MMRDecoder::VLSource::peek(void)
+{
+ return codeword;
+}
+
+
+void
+MMRDecoder::VLSource::nextstripe(void)
+{
+ while (readmax>0)
+ {
+ int size = sizeof(buffer);
+ if (readmax < size)
+ size = readmax;
+ inp.readall(buffer, size);
+ readmax -= size;
+ }
+ bufpos = bufmax = 0;
+ memset(buffer,0,sizeof(buffer));
+ readmax = inp.read32();
+ codeword = 0;
+ lowbits = 32;
+ preload();
+}
+
+void
+MMRDecoder::VLSource::preload(void)
+{
+ while (lowbits>=8)
+ {
+ if (bufpos >= bufmax)
+ {
+ // Refill buffer
+ bufpos = bufmax = 0;
+ int size = sizeof(buffer);
+ if (readmax>=0 && readmax<size)
+ size = readmax;
+ if (size>0)
+ bufmax = inp.read((void*)buffer, size);
+ readmax -= bufmax;
+ if (bufmax <= 0)
+ return;
+ }
+ lowbits -= 8;
+ codeword |= buffer[bufpos++] << lowbits;
+ }
+}
+
+
+
+// ----------------------------------------
+// VARIABLE LENGTH CODES
+
+
+
+class MMRDecoder::VLTable : public GPEnabled
+{
+protected:
+ VLTable(const VLCode *codes);
+ void init(const int nbits);
+public:
+ // Construct a VLTable given a codebook with #nbits# long codes.
+ static GP<VLTable> create(VLCode const * const codes, const int nbits);
+
+ // Reads one symbol from a VLSource
+ int decode(MMRDecoder::VLSource *src);
+
+ const VLCode *code;
+ int codewordshift;
+ unsigned char *index;
+ GPBuffer<unsigned char> gindex;
+};
+
+GP<MMRDecoder::VLTable>
+MMRDecoder::VLTable::create(VLCode const * const codes, const int nbits)
+{
+ VLTable *table=new VLTable(codes);
+ GP<VLTable> retval=table;
+ table->init(nbits);
+ return retval;
+}
+
+inline int
+MMRDecoder::VLTable::decode(MMRDecoder::VLSource *src)
+{
+ const VLCode &c = code[ index[ src->peek() >> codewordshift ] ];
+ src->shift(c.codelen);
+ return c.value;
+}
+
+MMRDecoder::VLTable::VLTable(const VLCode *codes)
+: code(codes), codewordshift(0), gindex(index,0)
+{}
+
+void
+MMRDecoder::VLTable::init(const int nbits)
+{
+ // count entries
+ int ncodes = 0;
+ while (code[ncodes].codelen)
+ ncodes++;
+ // check arguments
+ if (nbits<=1 || nbits>16)
+ G_THROW(invalid_mmr_data);
+ if (ncodes>=256)
+ G_THROW(invalid_mmr_data);
+ codewordshift = 32 - nbits;
+ // allocate table
+ int size = (1<<nbits);
+ gindex.resize(size);
+ gindex.set(ncodes);
+ // process codes
+ for (int i=0; i<ncodes; i++) {
+ const int c = code[i].code;
+ const int b = code[i].codelen;
+ if(b<=0 || b>nbits)
+ {
+ G_THROW(invalid_mmr_data);
+ }
+ // fill table entries whose index high bits are code.
+ int n = c + (1<<(nbits-b));
+ while ( --n >= c ) {
+ if(index[n] != ncodes)
+ G_THROW( ERR_MSG("MMRDecoder.bad_codebook") );
+ index[n] = i;
+ }
+ }
+}
+
+// ----------------------------------------
+// MMR DECODER
+
+
+
+MMRDecoder::~MMRDecoder() {}
+
+MMRDecoder::MMRDecoder( const int xwidth, const int xheight )
+: width(xwidth), height(xheight), lineno(0),
+ striplineno(0), rowsperstrip(0), gline(line,width+8),
+ glineruns(lineruns,width+4), gprevruns(prevruns,width+4)
+{
+ gline.clear();
+ glineruns.clear();
+ gprevruns.clear();
+ lineruns[0] = width;
+ prevruns[0] = width;
+}
+
+void
+MMRDecoder::init(GP<ByteStream> gbs, const bool striped)
+{
+ rowsperstrip = (striped ? gbs->read16() : height);
+ src = VLSource::create(gbs, striped);
+ mrtable = VLTable::create(mrcodes, 7);
+ btable = VLTable::create(bcodes, 13);
+ wtable = VLTable::create(wcodes, 13);
+}
+
+GP<MMRDecoder>
+MMRDecoder::create( GP<ByteStream> gbs, const int width,
+ const int height, const bool striped )
+{
+ MMRDecoder *mmr=new MMRDecoder(width,height);
+ GP<MMRDecoder> retval=mmr;
+ mmr->init(gbs,striped);
+ return retval;
+}
+
+const unsigned short *
+MMRDecoder::scanruns(const unsigned short **endptr)
+{
+ // Check if all lines have been returned
+ if (lineno >= height)
+ return 0;
+ // Check end of stripe
+ if ( striplineno == rowsperstrip )
+ {
+ striplineno=0;
+ lineruns[0] = prevruns[0] = width;
+ src->nextstripe();
+ }
+ // Swap run buffers
+ unsigned short *pr = lineruns;
+ unsigned short *xr = prevruns;
+ prevruns = pr;
+ lineruns = xr;
+ // Loop until scanline is complete
+ bool a0color = false;
+ int a0,rle,b1;
+ for(a0=0,rle=0,b1=*pr++;a0 < width;)
+ {
+ // Process MMR codes
+ const int c=mrtable->decode(src);
+ switch ( c )
+ {
+ /* Pass Mode */
+ case P:
+ {
+ b1 += *pr++;
+ rle += b1 - a0;
+ a0 = b1;
+ b1 += *pr++;
+ break;
+ }
+ /* Horizontal Mode */
+ case H:
+ {
+ // First run
+ VLTable &table1 = *(a0color ? btable : wtable);
+ int inc;
+ do { inc=table1.decode(src); a0+=inc; rle+=inc; } while (inc>=64);
+ *xr = rle; xr++; rle = 0;
+ // Second run
+ VLTable &table2 = *(!a0color ? btable : wtable);
+ do { inc=table2.decode(src); a0+=inc; rle+=inc; } while (inc>=64);
+ *xr = rle; xr++; rle = 0;
+ break;
+ }
+ /* Vertical Modes */
+ case V0:
+ case VR3:
+ case VR2:
+ case VR1:
+ case VL3:
+ case VL2:
+ case VL1:
+ {
+ int inc=b1;
+ switch ( c )
+ {
+ case V0:
+ inc = b1;
+ b1 += *pr++;
+ break;
+ case VR3:
+ inc = b1+3;
+ b1 += *pr++;
+ break;
+ case VR2:
+ inc = b1+2;
+ b1 += *pr++;
+ break;
+ case VR1:
+ inc = b1+1;
+ b1 += *pr++;
+ break;
+ case VL3:
+ inc = b1-3;
+ b1 -= *--pr;
+ break;
+ case VL2:
+ inc = b1-2;
+ b1 -= *--pr;
+ break;
+ case VL1:
+ inc = b1-1;
+ b1 -= *--pr;
+ break;
+ }
+ *xr = inc+rle-a0;
+ xr++;
+ a0 = inc;
+ rle = 0;
+ a0color = !a0color;
+ break;
+ }
+ /* Uncommon modes */
+ default:
+ {
+ src->preload();
+ unsigned int m = src->peek();
+ // -- Could be EOFB ``000000000001000000000001''
+ // TIFF6 says that all remaining lines are white
+ if ((m & 0xffffff00) == 0x00100100)
+ {
+ lineno = height;
+ return 0;
+ }
+ // -- Could be UNCOMPRESSED ``0000001111''
+ // TIFF6 says people should not do this.
+ // RFC1314 says people should do this.
+ else if ((m & 0xffc00000) == 0x03c00000)
+ {
+#ifdef MMRDECODER_REFUSES_UNCOMPRESSED
+ G_THROW( ERR_MSG("MMRDecoder.cant_process") );
+#else
+ // ---THE-FOLLOWING-CODE-IS-POORLY-TESTED---
+ src->shift(10);
+ while ((m = (src->peek() & 0xfc000000)))
+ {
+ if (m == 0x04000000) // 000001
+ {
+ src->shift(6);
+ if (a0color)
+ {
+ *xr = rle;
+ xr++;
+ rle = 0;
+ a0color = !a0color;
+ }
+ rle += 5;
+ a0 += 5;
+ }
+ else // 000010 to 111111
+ {
+ src->shift(1);
+ if (a0color == !(m & 0x80000000))
+ {
+ *xr = rle;
+ xr++;
+ rle = 0;
+ a0color = !a0color;
+ }
+ rle++;
+ a0++;
+ }
+ if (a0 > width)
+ G_THROW(invalid_mmr_data);
+ }
+ // Analyze uncompressed termination code.
+ m = src->peek() & 0xff000000;
+ src->shift(8);
+ if ( (m & 0xfe000000) != 0x02000000 )
+ G_THROW(invalid_mmr_data);
+ if (rle)
+ {
+ *xr = rle;
+ xr++;
+ rle = 0;
+ a0color = !a0color;
+ }
+ if (a0color == !(m & 0x01000000))
+ {
+ *xr = rle;
+ xr++;
+ rle = 0;
+ a0color = !a0color;
+ }
+ // Cross fingers and proceed ...
+ break;
+#endif
+ }
+ // -- Unknown MMR code.
+ G_THROW(invalid_mmr_data);
+ }
+ }
+ // Next reference run
+ for(;b1<=a0 && b1<width;pr+=2)
+ {
+ b1 += pr[0]+pr[1];
+ }
+ }
+ // Final P must be followed by V0 (they say!)
+ if (rle > 0)
+ {
+ if (mrtable->decode(src) != V0)
+ {
+ G_THROW(invalid_mmr_data);
+ }
+ }
+ if (rle > 0)
+ {
+ *xr = rle;
+ xr++;
+ }
+ // At this point we should have A0 equal to WIDTH
+ // But there are buggy files around (Kofax!)
+ // and we are not the CCITT police.
+ if (a0 > width)
+ {
+ while (a0 > width && xr > lineruns)
+ a0 -= *--xr;
+ if (a0 < width)
+ {
+ *xr = width-a0;
+ xr++;
+ }
+ }
+ /* Increment and return */
+ if (endptr)
+ *endptr = xr;
+ xr[0] = 0;
+ xr[1] = 0;
+ lineno ++;
+ striplineno ++;
+ return lineruns;
+}
+
+
+
+const unsigned char *
+MMRDecoder::scanrle(const bool invert, const unsigned char **endptr)
+{
+ // Obtain run lengths
+ const unsigned short *xr = scanruns();
+ if (!xr) return 0;
+ unsigned char *p=line;
+ // Process inversion
+ if (invert)
+ {
+ if (! *xr)
+ {
+ xr++;
+ }else
+ {
+ *p = 0; p++;
+ }
+ }
+ // Encode lenghts using the RLE format
+ for(int a0=0;a0 < width;)
+ {
+ int count = *xr++;
+ a0 += count;
+ GBitmap::append_run(p, count);
+ }
+ if (endptr)
+ *endptr = p;
+ p[0] = 0;
+ p[1] = 0;
+ return line;
+}
+
+
+#if 0
+const unsigned char *
+MMRDecoder::scanline(void)
+{
+ // Obtain run lengths
+ const unsigned short *xr = scanruns();
+ if (!xr) return 0;
+ // Allocate data buffer if needed
+ unsigned char *p = line;
+ // Decode run lengths
+ int a0 = 0;
+ int a0color = 0;
+ while (a0 < width)
+ {
+ int a1 = a0 + *xr++;
+ while (a0<a1 && a0<width)
+ line[a0++] = a0color;
+ a0color = !a0color;
+ }
+ return line;
+}
+#endif
+
+
+
+
+// ----------------------------------------
+// MAIN DECODING ROUTINE
+
+bool
+MMRDecoder::decode_header(
+ ByteStream &inp, int &width, int &height, int &invert)
+{
+ unsigned long int magic = inp.read32();
+ if((magic&0xfffffffc) != 0x4d4d5200)
+ G_THROW( ERR_MSG("MMRDecoder.unrecog_header") );
+ invert = ((magic & 0x1) ? 1 : 0);
+ const bool strip = ((magic & 0x2) ? 1 : 0);
+ width = inp.read16();
+ height = inp.read16();
+ if (width<=0 || height<=0)
+ G_THROW( ERR_MSG("MMRDecoder.bad_header") );
+ return strip;
+}
+
+static inline int MAX(int a, int b) { return a>b ? a : b; }
+static inline int MIN(int a, int b) { return a<b ? a : b; }
+
+GP<JB2Image>
+MMRDecoder::decode(GP<ByteStream> gbs)
+{
+ ByteStream &inp=*gbs;
+ // Read header
+ int width, height, invert;
+ const bool striped=decode_header(inp, width, height, invert);
+ // Prepare image
+ GP<JB2Image> jimg = JB2Image::create();
+ jimg->set_dimension(width, height);
+ // Choose pertinent blocksize
+ int blocksize = MIN(500,MAX(64,MAX(width/17,height/22)));
+ int blocksperline = (width+blocksize-1)/blocksize;
+ // Prepare decoder
+ GP<MMRDecoder> gdcd=MMRDecoder::create(gbs, width, height, striped);
+ MMRDecoder &dcd=*gdcd;
+ // Loop on JB2 bands
+ int line = height-1;
+ while (line >= 0)
+ {
+ int bandline = MIN(blocksize-1,line);
+ GPArray<GBitmap> blocks(0,blocksperline-1);
+ // Loop on scanlines
+ for(; bandline >= 0; bandline--,line--)
+ {
+ // Decode one scanline
+ const unsigned short *s = dcd.scanruns();
+ if (s)
+ {
+ // Loop on blocks
+ int x = 0;
+ int b = 0;
+ int firstx = 0;
+ bool c = !!invert;
+ while (x < width)
+ {
+ int xend = x + *s++;
+ while (b<blocksperline)
+ {
+ int lastx = MIN(firstx+blocksize,width);
+ if (c)
+ {
+ if (!blocks[b])
+ blocks[b] = GBitmap::create(bandline+1, lastx-firstx);
+ unsigned char *bptr = (*blocks[b])[bandline] - firstx;
+ int x1 = MAX(x,firstx);
+ int x2 = MIN(xend,lastx);
+ while (x1 < x2)
+ bptr[x1++] = 1;
+ }
+ if (xend < lastx)
+ break;
+ firstx = lastx;
+ b ++;
+ }
+ x = xend;
+ c = !c;
+ }
+ }
+ }
+ // Insert blocks into JB2Image
+ for (int b=0; b<blocksperline; b++)
+ {
+ JB2Shape shape;
+ shape.bits = blocks[b];
+ if (shape.bits)
+ {
+ shape.parent = -1;
+ shape.bits->compress();
+ JB2Blit blit;
+ blit.left = b*blocksize;
+ blit.bottom = line+1;
+ blit.shapeno = jimg->add_shape(shape);
+ jimg->add_blit(blit);
+ }
+ }
+ }
+ // Return
+ return jimg;
+}
+
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/MMRDecoder.h b/kviewshell/plugins/djvu/libdjvu/MMRDecoder.h
new file mode 100644
index 00000000..6516b4cd
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/MMRDecoder.h
@@ -0,0 +1,238 @@
+//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: MMRDecoder.h,v 1.9 2003/11/07 22:08:22 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _MMRDECODER_H_
+#define _MMRDECODER_H_
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+#include "GSmartPointer.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+class ByteStream;
+class JB2Image;
+
+/** @name MMRDecoder.h
+ Files #"MMRDecoder.h"# and #"MMRDecoder.cpp"# implement a
+ CCITT-G4/MMR decoder suitable for use in DjVu. The main
+ entry point is function \Ref{MMRDecoder::decode}.
+
+ The foreground mask layer of a DjVu file is usually encoded with a
+ #"Sjbz"# chunk containing JB2 encoded data (cf. \Ref{JB2Image.h}).
+ Alternatively, the qmask layer may be encoded with a #"Smmr"#
+ chunk containing a small header followed by MMR encoded data.
+ This encoding scheme produces significantly larger files. On the
+ other hand, many scanners a printers talk MMR using very efficient
+ hardware components. This is the reason behind the introduction
+ of #"Smmr"# chunks.
+
+ The #Smmr# chunk starts by a header containing the following data:
+ \begin{verbatim}
+ BYTE*3 : 'M' 'M' 'R'
+ BYTE : 0xb000000<s><i>
+ INT16 : <width> (MSB first)
+ INT16 : <height> (MSB first)
+ \end{verbatim}
+
+ The header is followed by the encoded data. Bit 0 of the fourth header
+ byte (#<i>#) is similar to TIFF's ``min-is-black'' tag. This bit is set
+ for a reverse video image. The encoded data can be in either ``regular''
+ MMR form or ``striped'' MMR form. This is indicated by bit 1 of the
+ fourth header byte (#<s>#). This bit is set to indicate ``striped''
+ data. The ``regular'' data format consists of ordinary MMR encoded data.
+ The ``striped'' data format consists of one sixteen bit integer (msb
+ first) containing the number of rows per stripe, followed by data for each
+ stripe as follows.
+ \begin{verbatim}
+ INT16 : <rowsperstripe> (MSB first)
+ INT32 : <nbytes1>
+ BYTE*<nbytes1> : <mmrdata1>
+ INT32 : <nbytes2>
+ BYTE*<nbytes2> : <mmrdata2>
+ ...
+ \end{verbatim}
+ Static function \Ref{MMRDecoder::decode_header} decodes the header. You
+ can then create a \Ref{MMRDecoder} object with the flags #inverted# and
+ #striped# as obtained when decoding the header. One can also decode raw
+ MMR data by simply initialising a \Ref{MMRDecoder} object with flag
+ #striped# unset. Each call to \Ref{MMRDecoder::scanruns},
+ \Ref{MMRDecoder::scanrle} or \Ref{MMRDecoder::scanline} will then decode a
+ row of the MMR encoded image.
+
+ Function \Ref{MMRDecoder::decode} is a convenience function for decoding
+ the contents of a #"Smmr"# chunk. It returns a \Ref{JB2Image} divided
+ into manageable blocks in order to provide the zooming and panning
+ features implemented by class \Ref{JB2Image}.
+
+ @memo
+ CCITT-G4/MMR decoder.
+ @version
+ #$Id: MMRDecoder.h,v 1.9 2003/11/07 22:08:22 leonb Exp $#
+ @author
+ Parag Deshmukh <parag@sanskrit.lz.att.com> \\
+ Leon Bottou <leonb@research.att.com> */
+//@{
+
+
+
+#define MMRDECODER_HAS_SCANRUNS 1
+#define MMRDECODER_HAS_SCANRLE 1
+
+
+
+/** Class for G4/MMR decoding. The simplest way to use this class is
+ the static member function \Ref{MMRDecoder::decode}. This
+ function internally creates an instance of #MMRDecoder# which
+ processes the MMR data scanline by scanline. */
+class MMRDecoder : public GPEnabled
+{
+protected:
+ MMRDecoder(const int width, const int height);
+ void init(GP<ByteStream> gbs, const bool striped=false);
+public:
+ /** Main decoding routine that (a) decodes the header using
+ #decode_header#, (b) decodes the MMR data using an instance of
+ #MMRDecoder#, and returns a new \Ref{JB2Image} composed of tiles
+ whose maximal width and height is derived from the size of the
+ image. */
+ static GP<JB2Image> decode(GP<ByteStream> gbs);
+
+ /// Only decode the header.
+ static bool decode_header(ByteStream &inp,
+ int &width, int &height, int &invert);
+
+public:
+ /// Non-virtual destructor.
+ ~MMRDecoder();
+ /** Create a MMRDecoder object for decoding an image
+ of size #width# by #height#. Flag $striped# must be set
+ if the image is composed of multiple stripes. */
+ static GP<MMRDecoder> create(GP<ByteStream> gbs,
+ const int width, const int height,
+ const bool striped=false );
+
+ /** Decodes a scanline and returns a pointer to an array of run lengths.
+ The returned buffer contains the length of alternative white and black
+ runs. These run lengths sum to the image width. They are followed by
+ two zeroes. The position of these two zeroes is stored in the pointer
+ specified by the optional argument #endptr#. The buffer data should be
+ processed before calling this function again. */
+ const unsigned short *scanruns(const unsigned short **endptr=0);
+ /** Decodes a scanline and returns a pointer to RLE encoded data. The
+ buffer contains the length of the runs for the current line encoded as
+ described in \Ref{PNM and RLE file formats}.) The flag #invert# can be
+ used to indicate that the MMR data is encoded in reverse video. The RLE
+ data is followed by two zero bytes. The position of these two zeroes is
+ stored in the pointer specified by the optional argument #endptr#. The
+ buffer data should be processed before calling this function again. This
+ is implemented by calling \Ref{MMRDecoder::scanruns}. */
+ const unsigned char *scanrle(const bool invert,
+ const unsigned char **endptr=0);
+#if 0
+ /** Decodes a scanline and returns a pointer to an array of #0# or #1# bytes.
+ Returns a pointer to the scanline buffer containing one byte per pixel.
+ The buffer data should be processed before calling this function again.
+ This is implemented by calling \Ref{MMRDecoder::scanruns}. */
+ const unsigned char *scanline();
+#endif
+ private:
+ int width;
+ int height;
+ int lineno;
+ int striplineno;
+ int rowsperstrip;
+ unsigned char *line;
+ GPBuffer<unsigned char> gline;
+ unsigned short *lineruns;
+ GPBuffer<unsigned short> glineruns;
+ unsigned short *prevruns;
+ GPBuffer<unsigned short> gprevruns;
+public:
+ class VLSource;
+ class VLTable;
+private:
+ GP<VLSource> src;
+ GP<VLTable> mrtable;
+ GP<VLTable> wtable;
+ GP<VLTable> btable;
+ friend class VLSource;
+ friend class VLTable;
+};
+
+
+//@}
+
+
+// -----------
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/MMX.cpp b/kviewshell/plugins/djvu/libdjvu/MMX.cpp
new file mode 100644
index 00000000..58b74177
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/MMX.cpp
@@ -0,0 +1,209 @@
+//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: MMX.cpp,v 1.10 2004/05/13 16:50:10 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "MMX.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+// ----------------------------------------
+// PRINTING MMX REGISTERS (Debug)
+
+
+#if defined(MMX) && defined(DEBUG)
+extern "C" void
+mmx_show()
+{
+ /* This function can be called from a debugger
+ in order to visualize the contents of the MMX registers. */
+ int mmregs[16];
+ MMXra( movq, mm0, &mmregs[0]);
+ MMXra( movq, mm1, &mmregs[2]);
+ MMXra( movq, mm2, &mmregs[4]);
+ MMXra( movq, mm3, &mmregs[6]);
+ MMXra( movq, mm4, &mmregs[8]);
+ MMXra( movq, mm5, &mmregs[10]);
+ MMXra( movq, mm6, &mmregs[12]);
+ MMXra( movq, mm7, &mmregs[14]);
+ MMXemms;
+ for (int i=0; i<8; i++)
+ DjVuPrintMessageUTF8("mm%d: %08x%08x\n", i,
+ mmregs[i+i+1], mmregs[i+i]);
+ MMXar( movq, &mmregs[0], mm0);
+ MMXar( movq, &mmregs[2], mm1);
+ MMXar( movq, &mmregs[4], mm2);
+ MMXar( movq, &mmregs[6], mm3);
+ MMXar( movq, &mmregs[8], mm4);
+ MMXar( movq, &mmregs[10], mm5);
+ MMXar( movq, &mmregs[12], mm6);
+ MMXar( movq, &mmregs[14], mm7);
+}
+#endif
+
+
+
+// ----------------------------------------
+// MMX ENABLE/DISABLE
+
+// Default settings autodetect MMX.
+// Use macro DISABLE_MMX to disable MMX by default.
+
+#if defined(MMX) && !defined(DISABLE_MMX)
+int MMXControl::mmxflag = -1;
+#else
+int MMXControl::mmxflag = 0;
+#endif
+
+int
+MMXControl::disable_mmx()
+{
+ mmxflag = 0;
+ return mmxflag;
+}
+
+int
+MMXControl::enable_mmx()
+{
+ int cpuflags = 0;
+#if defined(MMX) && defined(__GNUC__) && defined(__i386__)
+ // Detection of MMX for GCC
+ __asm__ volatile ("pushl %%ebx\n\t"
+ "pushfl\n\t"
+ "popl %%ecx\n\t"
+ "xorl %%edx,%%edx\n\t"
+ // Check that CPUID exists
+ "movl %%ecx,%%eax\n\t"
+ "xorl $0x200000,%%eax\n\t"
+ "pushl %%eax\n\t"
+ "popfl\n\t"
+ "pushfl\n\t"
+ "popl %%eax\n\t"
+ "xorl %%ecx,%%eax\n\t"
+ "jz 1f\n\t"
+ "pushl %%ecx\n\t"
+ "popfl\n\t"
+ // Check that CR0:EM is clear
+ "smsw %%ax\n\t"
+ "andl $4,%%eax\n\t"
+ "jnz 1f\n\t"
+ // Execute CPUID
+ "movl $1,%%eax\n\t"
+ "cpuid\n"
+ // EBX contains magic when -fPIC is on.
+ "1:\tpopl %%ebx\n\t"
+ "movl %%edx, %0"
+ : "=m" (cpuflags) :
+ : "eax","ecx","edx");
+#endif
+#if defined(MMX) && defined(_MSC_VER) && defined(_M_IX86)
+ // Detection of MMX for MSVC
+ __asm { pushfd
+ pop ecx
+ xor edx,edx
+ ;// Check that CPUID exists
+ mov eax,ecx
+ xor eax,0x200000
+ push eax
+ popfd
+ pushfd
+ pop eax
+ xor eax,ecx
+ jz fini
+ push ecx
+ popfd
+ ;// Check that CR0:EM is zero
+ smsw ax
+ and eax,4
+ jnz fini
+ ;// Execute CPUID
+ mov eax,1
+ _emit 0xf
+ _emit 0xa2
+ fini:
+ mov cpuflags,edx
+ ;// MSVC determines clobbered registers by scanning the assembly code.
+ ;// Since it does not know CPUID, it would not know that EBX is clobbered
+ ;// without the dummy instruction below...
+ xor ebx,ebx
+ }
+#endif
+ mmxflag = !!(cpuflags & 0x800000);
+ return mmxflag;
+}
+
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/MMX.h b/kviewshell/plugins/djvu/libdjvu/MMX.h
new file mode 100644
index 00000000..41ec002f
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/MMX.h
@@ -0,0 +1,194 @@
+//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: MMX.h,v 1.9 2003/12/01 22:57:40 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _MMX_H_
+#define _MMX_H_
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+#include "DjVuGlobal.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+/** @name MMX.h
+ Files #"MMX.h"# and #"MMX.cpp"# implement basic routines for
+ supporting the MMX instructions on x86. Future instruction sets
+ for other processors may be supported in this file as well.
+
+ Macro #MMX# is defined if the compiler supports the X86-MMX instructions.
+ It does not mean however that the processor supports the instruction set.
+ Variable #MMXControl::mmxflag# must be used to decide whether MMX.
+ instructions can be executed. MMX instructions are entered in the middle
+ of C++ code using the following macros. Examples can be found in
+ #"IWTransform.cpp"#.
+
+ \begin{description}
+ \item[MMXrr( insn, srcreg, dstreg)]
+ Encode a register to register MMX instruction
+ (e.g. #paddw# or #punpcklwd#).
+ \item[MMXar( insn, addr, dstreg )]
+ Encode a memory to register MMX instruction
+ (e.g. #moveq# from memory).
+ \item[MMXra( insn, srcreg, addr )]
+ Encode a register to memory MMX instruction
+ (e.g. #moveq# to memory).
+ \item[MMXir( insn, imm, dstreg )]
+ Encode a immediate to register MMX instruction
+ (e.g #psraw#).
+ \item[MMXemms]
+ Execute the #EMMS# instruction to reset the FPU state.
+ \end{description}
+
+ @memo
+ Essential support for MMX.
+ @version
+ #$Id: MMX.h,v 1.9 2003/12/01 22:57:40 leonb Exp $#
+ @author:
+ L\'eon Bottou <leonb@research.att.com> -- initial implementation */
+//@{
+
+
+/** MMX Control.
+ Class #MMXControl# encapsulates a few static functions for
+ globally enabling or disabling MMX support. */
+
+class MMXControl
+{
+ public:
+ // MMX DETECTION
+ /** Detects and enable MMX or similar technologies. This function checks
+ whether the CPU supports a vectorial instruction set (such as Intel's
+ MMX) and enables them. Returns a boolean indicating whether such an
+ instruction set is available. Speedups factors may vary. */
+ static int enable_mmx();
+ /** Disables MMX or similar technologies. The transforms will then be
+ performed using the baseline code. */
+ static int disable_mmx();
+ /** Contains a value greater than zero if the CPU supports vectorial
+ instructions. A negative value means that you must call \Ref{enable_mmx}
+ and test the value again. Direct access to this member should only be
+ used to transfer the instruction flow to the vectorial branch of the
+ code. Never modify the value of this variable. Use #enable_mmx# or
+ #disable_mmx# instead. */
+ static int mmxflag; // readonly
+};
+
+//@}
+
+
+
+
+// ----------------------------------------
+// GCC MMX MACROS
+
+#ifndef NO_MMX
+
+#if defined(__GNUC__) && defined(__i386__)
+#define MMXemms \
+ __asm__ volatile("emms" : : : "memory" )
+#define MMXrr(op,src,dst) \
+ __asm__ volatile( #op " %%" #src ",%%" #dst : : : "memory")
+#define MMXir(op,imm,dst) \
+ __asm__ volatile( #op " %0,%%" #dst : : "i" (imm) : "memory")
+#define MMXar(op,addr,dst) \
+ __asm__ volatile( #op " %0,%%" #dst : : "m" (*(int*)(addr)) : "memory")
+#define MMXra(op,src,addr) \
+ __asm__ volatile( #op " %%" #src ",%0" : : "m" (*(int*)(addr)) : "memory")
+#define MMX 1
+#endif
+
+
+// ----------------------------------------
+// MSVC MMX MACROS
+
+#if defined(_MSC_VER) && defined(_M_IX86)
+// Compiler option /GM is required
+#pragma warning( disable : 4799 )
+#define MMXemms \
+ __asm { emms }
+#define MMXrr(op,src,dst) \
+ __asm { op dst,src }
+#define MMXir(op,imm,dst) \
+ __asm { op dst,imm }
+#define MMXar(op,addr,dst) \
+ { register __int64 var=*(__int64*)(addr); __asm { op dst,var } }
+#define MMXra(op,src,addr) \
+ { register __int64 var; __asm { op [var],src }; *(__int64*)addr = var; }
+// Probably not as efficient as GCC macros
+#define MMX 1
+#endif
+
+#endif
+
+// -----------
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/Makefile.am b/kviewshell/plugins/djvu/libdjvu/Makefile.am
new file mode 100644
index 00000000..4795da0d
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/Makefile.am
@@ -0,0 +1,18 @@
+INCLUDES = -I$(top_srcdir) $(all_includes)
+
+kde_module_LTLIBRARIES = libdjvu.la
+libdjvu_la_LDFLAGS = -avoid-version $(all_libraries)
+libdjvu_la_LIBADD = $(LIBJPEG)
+libdjvu_la_SOURCES = Arrays.cpp DjVuDocEditor.cpp DjVuMessageLite.cpp GOS.cpp IW44Image.cpp \
+ BSByteStream.cpp DjVuDocument.cpp DjVuNavDir.cpp GPixmap.cpp JB2EncodeCodec.cpp \
+ BSEncodeByteStream.cpp DjVuDumpHelper.cpp DjVuPalette.cpp GRect.cpp JB2Image.cpp \
+ ByteStream.cpp DjVuErrorList.cpp DjVuPort.cpp GScaler.cpp JPEGDecoder.cpp \
+ DataPool.cpp DjVuFileCache.cpp DjVuText.cpp GSmartPointer.cpp MMRDecoder.cpp \
+ DjVuFile.cpp DjVuToPS.cpp GString.cpp MMX.cpp DjVmNav.cpp \
+ debug.cpp DjVuGlobal.cpp GBitmap.cpp GThreads.cpp UnicodeByteStream.cpp \
+ DjVmDir0.cpp DjVuGlobalMemory.cpp GContainer.cpp GUnicode.cpp XMLParser.cpp \
+ DjVmDir.cpp DjVuImage.cpp GException.cpp GURL.cpp XMLTags.cpp \
+ DjVmDoc.cpp DjVuInfo.cpp GIFFManager.cpp IFFByteStream.cpp ZPCodec.cpp \
+ DjVuAnno.cpp DjVuMessage.cpp GMapAreas.cpp IW44EncodeCodec.cpp
+
+KDE_OPTIONS = nofinal
diff --git a/kviewshell/plugins/djvu/libdjvu/README.djvulibre b/kviewshell/plugins/djvu/libdjvu/README.djvulibre
new file mode 100644
index 00000000..fb37c8d7
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/README.djvulibre
@@ -0,0 +1,85 @@
+
+
+1- WHAT IS DJVU.
+================
+
+DjVu (pronounced "dj vu") a set of compression technologies, a file format,
+and a software platform for the delivery over the Web of digital documents,
+scanned documents, and high resolution images.
+
+DjVu documents download and display extremely quickly, and look exactly the
+same on all platforms. DjVu can be seen as superior alternative to PDF and
+Postscript for digital documents, to TIFF (and PDF) for scanned documents, to
+JPEG for photographs and pictures, and to GIF for large palettized
+images. DjVu is the only Web format that is practical for distributing
+high-resolution scanned documents in color. No other format comes close.
+
+Typical DjVu file sizes are as follows:
+
+- Bitonal scanned documents:
+ 5 to 30KB per page at 300dpi,
+ 3 to 10 times smaller than PDF or TIFF.
+
+- Color scanned documents:
+ 30 to 100KB per page at 300dpi,
+ 5 to 10 times smaller than JPEG.
+
+- Photos:
+ 2 times smaller than JPEG,
+ about the same as JPEG-2000.
+
+- Palettized images:
+ 2 times smaller than GIF,
+ up to 10 times if there is text.
+
+DjVu is used by hundreds of commercial, governmental, and non-commercial web
+sites around the world to distribute scanned documents, digital documents, and
+high-resolution photos.
+
+Demos, and general information about DjVu can be found at
+http://www.djvuzone.org, or at http://www.lizardtech.com.
+
+DjVu was originally developed at AT&T Labs-Research. AT&T sold DjVu to
+LizardTech Inc. in March 2000.
+
+
+
+2- WHAT IS DJVULIBRE?
+=====================
+
+In an effort to promote DjVu as a Web standard, LizardTech's management was
+enlightened enough to release the reference implementation of DjVu under the
+GNU GPL in October 2000. DjVuLibre (pronounced like the French "dj vu
+libre"), is an enhanced version of that code maintained by the original
+inventors of DjVu. It is compatible with LizardTech's DjVu software v3.5.
+
+DjVuLibre includes:
+
+- A standalone DjVu viewer for Unix under X11 (based on the Qt library).
+
+- A browser plugin that works with most Unix browsers, including:
+ Netscape-4.x, Netscape-6.x, Mozilla, Galeon, Konqueror, and Opera.
+
+- A full-fledged wavelet-based compressor for pictures.
+
+- A simple compressor for bitonal (black and white) scanned pages.
+
+- A compressor for palettized images (a la GIF).
+
+- A full set of utilities to manipulate and assemble DjVu images and documents.
+
+- A set of decoders to convert DjVu to a number of other formats.
+
+- An up-to-date version of the C++ DjVu Reference Library
+
+Windows and Mac versions of the viewer/plug-in, as well as commercial versions
+of the compressors and OCR engines are available from LizardTech Inc.. The
+compressors provided here are slower, produce larger files, and sometimes
+lower quality images than the commercial compressors, but they do the job.
+
+A variety of free web-based conversion services are also available, including
+any2djvu.djvuzone.org, bib2web.djvuzone.org, and openlib.djvuzone.org.
+
+
+
+
diff --git a/kviewshell/plugins/djvu/libdjvu/Template.h b/kviewshell/plugins/djvu/libdjvu/Template.h
new file mode 100644
index 00000000..c37935ce
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/Template.h
@@ -0,0 +1,258 @@
+//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: Template.h,v 1.8 2003/11/07 22:08:22 leonb Exp $
+// $Name: release_3_5_15 $
+
+//T// This is a template for the header files in the
+//T// DjVu reference library. It describes the general
+//T// conventions as well as the documentation.
+//T// Comments prefixed with '//T//' explain the template
+//T// features and should be removed.
+
+#ifndef _TEMPLATE_H_
+#define _TEMPLATE_H_
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+//T// Always include "DjVuGlobal.h"
+#include "DjVuGlobal.h"
+
+//T// Other include files
+#include <string.h>
+#include "GException.h"
+
+//T// Begin name space
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+/** @name Template.h
+
+ Files #"Template.h"# and #"Template.cpp"# are not used for anything but
+ the current programming and documentation standards in the DjVu reference
+ library. This doc++ comment briefly describes the abstractions defined in
+ this files. It must mention all the files involved in implementing this
+ features, as well as references to the main classes \Ref{classname}.
+
+ This comment may contain additional sections as follows:
+
+ {\bf Algorithmic Remarks} --- Comments about the algorithms, their
+ performance and their limitations.
+
+ {\bf Historical Remarks} --- Comments about the successive revisions of
+ this file and other anecdotical details. This is where we can amuse the
+ reader with funny details.
+
+ {\bf ToDo} --- Things that we have been thinking to do but did not
+ fully implement yet. It should explain how we plan to modify the current
+ code could be modified to implement these things. People who change this
+ code thus should avoid jeopardizing these plans.
+
+ {\bf Example} --- It would be cool to demonstrate how these functions
+ can be used by providing a small segment of C/C++ code.
+ \begin{verbatim}
+ ExampleClass toto(3,4);
+ toto.draw(mywin);
+ \end{verbatim}
+
+ This main doc++ comment is followed by a few doc++ entries.
+ \begin{itemize}
+ \item the "memo" field contains a single line description of the file.
+ \item the "version" field contains a cvs magic expression.
+ \item the author fields contains a list of authors and email addresses.
+ (the #\\# termination breaks the line.)
+ \end{itemize}
+
+ @memo
+ Template header file
+ @version
+ #$Id: Template.h,v 1.8 2003/11/07 22:08:22 leonb Exp $#
+ @author:
+ L\'eon Bottou <leonb@research.att.com> -- initial implementation \\
+ Andrew Erofeev <eaf@geocities.com> -- implemented EXTERNAL_TEMPLATES */
+//@{
+//T// The magic doc++ comment above opens a doc++ context.
+
+
+
+//T// Now comes the 'interface part' of the file.
+//T// The c++ classes and public functions are defined there.
+//T// Doc++ comments must be inserted for all functions
+//T// intended to be used by other people.
+//T//
+//T// Quite often c++ sucks and it is necessary to have public or external symbols
+//T// that actually are only there for implementation purposes.
+//T// It is good to give a comment but this should not be a doc++ comment
+//T// (see class GPool in GContainer.h). All other 'public' and 'protected'
+//T// members should have a doc++ comment. There is no need to comment 'private'
+//T// members, although a regular comment can be useful (not a doc++ comment).
+
+
+
+/** One-line class description.
+ Long description. There is no need to repeat the class name in the
+ one-line description. The long description should describe the abstraction
+ and point the user to the main member functions. An example could be
+ inserted when this is informative and not redundant with the file
+ description. Templates should document which member functions are
+ required for their type argument. The availability of non availabilty of a
+ copy constructor/copy operator can be specified when appropriate.
+ See the doc++ documentation for available LaTeX constructs.
+*/
+
+class ExampleClass
+{
+public:
+ /** Virtual Destructor. */
+ ~ExampleClass();
+ /** Null Constructor. */
+ ExampleClass();
+ /** Copy Constructor. */
+ ExampleClass(ExampleClass &ref);
+ /** Copy operator. */
+ ExampleClass& operator=(ExampleClass &ref);
+ /** Example of member function. The first sentence of the member
+ function description must be a short single line description.
+ The rest can be more verbose. Excerpts of C or C++ text should
+ be surrounded by dieze characters (as in #win#). The doc++ #@param#
+ construct should be used when there is a need for additional details
+ about the arguments. In that case all the arguments must be documented
+ with a #@param# directive.
+ @param win drawing window.
+ This window must be created with #CreateWindow# and must be visible when
+ function #draw# is called.
+ */
+ void draw(Window win);
+protected:
+ /** Minimal x-coordinate. */
+ int xmin;
+ /** Maximal x-coordinate. */
+ int xmax;
+private:
+ int whatever;
+ float encode;
+};
+
+
+/** One-line function description.
+ Long description. Public external functions should be documented
+ as classes. Note that a family of public external function can be
+ introduced by a generic entry (see below) */
+
+ExampleClass combine_example_classes(const ExampleClass&,
+ const ExampleClass &b);
+
+
+/** @name Generic entry.
+ Long description. there is sometimes a need to add documentation
+ entries for grouping things which are not connected by the C++
+ syntax (a family of functions, a family of defines, etc...).
+ The description starts with a very short name (introduced with #@name#)
+ followed by a long description. Because of doc++ limitations,
+ the one-line description must appear after the long description
+ in a #@memo# entry.
+ @memo One-line description
+*/
+
+//T// The following comments should be used when
+//T// the preceding generic entry contains sub-entries
+//@{
+//T// Sub-entries (both DOC++ and C++) should be declared there.
+//@}
+
+
+
+
+
+
+//@}
+//T// The magic doc++ comment above closes the doc++ file context.
+//T// The rest of the file only contains implementation stuff.
+
+// ------------ CLASSEXAMPLE INLINES
+//T// This is where all the inline/template functions should be written
+//T// This part of the file is segmented with comments.
+
+inline void
+ClassExample::width()
+{
+ return xmax-xmin;
+}
+
+
+
+// ------------ THE END
+//T// End name space
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
+//T// Terminates the multiple inclusion #ifndef
+
+
+
+
+
diff --git a/kviewshell/plugins/djvu/libdjvu/UnicodeByteStream.cpp b/kviewshell/plugins/djvu/libdjvu/UnicodeByteStream.cpp
new file mode 100644
index 00000000..8d4f0188
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/UnicodeByteStream.cpp
@@ -0,0 +1,368 @@
+//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: UnicodeByteStream.cpp,v 1.8 2003/11/07 22:08:22 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "UnicodeByteStream.h"
+#include "ByteStream.h"
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+UnicodeByteStream::UnicodeByteStream(const UnicodeByteStream &uni)
+: bs(uni.bs), buffer(uni.buffer), bufferpos(uni.bufferpos), linesread(0)
+{
+ startpos=bs->tell();
+}
+
+UnicodeByteStream::UnicodeByteStream(
+ GP<ByteStream> ibs,const GStringRep::EncodeType et)
+: bs(ibs), bufferpos(0), linesread(0)
+{
+ buffer=GUTF8String::create(0,0,et);
+ startpos=bs->tell();
+}
+
+UnicodeByteStream::~UnicodeByteStream()
+{}
+
+static int
+CountLines(const GUTF8String &str)
+{
+ int retval=0;
+ static const unsigned long lf='\n';
+ for(int pos=0;(pos=str.search(lf,pos)+1)>0;++retval)
+ EMPTY_LOOP;
+ return retval;
+}
+
+void
+UnicodeByteStream::set_encodetype(const GStringRep::EncodeType et)
+{
+ seek(startpos,SEEK_SET);
+ bufferpos=0;
+ buffer=GUTF8String::create(0,0,et);
+}
+
+void
+UnicodeByteStream::set_encoding(const GUTF8String &xencoding)
+{
+ seek(startpos,SEEK_SET);
+ bufferpos=0;
+ buffer=GUTF8String::create(0,0,xencoding);
+}
+
+size_t
+UnicodeByteStream::read(void *buf, size_t size)
+{
+ bufferpos=0;
+ const int retval=bs->read(buf,size);
+ if(retval)
+ {
+ buffer=GUTF8String::create(
+ (unsigned char const *)buf,retval,buffer.get_remainder());
+ }else
+ {
+ buffer=GUTF8String::create(0,0,buffer.get_remainder());
+ }
+ return retval;
+}
+
+size_t
+UnicodeByteStream::write(const void *buf, size_t size)
+{
+ bufferpos=0;
+ buffer=GUTF8String::create(0,0,buffer.get_remainder());
+ return bs->write(buf,size);
+}
+
+long
+UnicodeByteStream::tell(void) const
+{
+ return bs->tell();
+}
+
+UnicodeByteStream &
+UnicodeByteStream::operator=(UnicodeByteStream &uni)
+{
+ bs=uni.bs;
+ bufferpos=uni.bufferpos;
+ buffer=uni.buffer;
+ return *this;
+}
+
+int
+UnicodeByteStream::seek
+(long offset, int whence, bool nothrow)
+{
+ int retval=bs->seek(offset,whence,nothrow);
+ bufferpos=0;
+ buffer=GUTF8String::create(0,0,buffer.get_remainder());
+ return retval;
+}
+
+void
+UnicodeByteStream::flush(void)
+{
+ bs->flush();
+ bufferpos=0;
+ buffer=GUTF8String::create(0,0,buffer.get_remainder());
+}
+
+
+
+GUTF8String
+UnicodeByteStream::gets(
+ size_t const t,unsigned long const stopat,bool const inclusive)
+{
+ GUTF8String retval;
+ unsigned int len=buffer.length()-bufferpos;
+ if(!len)
+ {
+ int i;
+ char *buf;
+ static const size_t bufsize=327680;
+ GPBuffer<char> gbuf(buf,bufsize);
+ while((i=read(buf,bufsize)>0))
+ {
+ if((len=buffer.length()-bufferpos))
+ break;
+ }
+ }
+ if(len)
+ {
+ int i=buffer.search((char)stopat,bufferpos);
+ if(i>=0)
+ {
+ if(inclusive)
+ {
+ ++i;
+ }
+ if(t&&(i>(int)t+bufferpos))
+ {
+ i=t+bufferpos;
+ }
+ if(i>bufferpos)
+ {
+ retval=buffer.substr(bufferpos,i-bufferpos);
+ }
+ bufferpos=i;
+ linesread+=CountLines(retval);
+ }else
+ {
+ retval=buffer.substr(bufferpos,len);
+ bufferpos=buffer.length();
+ linesread+=CountLines(retval);
+ retval+=gets(t?(t-(i-bufferpos)):0,stopat,inclusive);
+ }
+ }
+ return retval;
+}
+
+XMLByteStream::XMLByteStream(UnicodeByteStream &uni)
+: UnicodeByteStream(uni) {}
+
+XMLByteStream::XMLByteStream(GP<ByteStream> &ibs)
+: UnicodeByteStream(ibs,GStringRep::XOTHER)
+{}
+
+GP<XMLByteStream>
+XMLByteStream::create(GP<ByteStream> ibs)
+{
+ XMLByteStream *xml=new XMLByteStream(ibs);
+ GP<XMLByteStream> retval=xml;
+ xml->init();
+ return retval;
+}
+
+void
+XMLByteStream::init(void)
+{
+ unsigned char buf[4];
+ GP<ByteStream> ibs=bs;
+ bufferpos=0;
+ bs->readall(buf,sizeof(buf));
+ const unsigned int i=(buf[0]<<8)+buf[1];
+ switch(i)
+ {
+ case 0x0000:
+ {
+ const unsigned int j=(buf[2]<<8)+buf[3];
+ switch(j)
+ {
+ case 0x003C:
+ {
+ buffer=GUTF8String::create(buf,sizeof(buf),GStringRep::XUCS4BE);
+ break;
+ }
+ case 0x3C00:
+ {
+ buffer=GUTF8String::create(buf,sizeof(buf),GStringRep::XUCS4_2143);
+ break;
+ }
+ case 0xFEFF:
+ {
+ buffer=GUTF8String::create(0,0,GStringRep::XUCS4BE);
+ startpos+=sizeof(buf);
+ break;
+ }
+ case 0xFFFE:
+ {
+ buffer=GUTF8String::create(0,0,GStringRep::XUCS4_2143);
+ startpos+=sizeof(buf);
+ break;
+ }
+ default:
+ {
+ buffer=GUTF8String::create(buf,sizeof(buf),GStringRep::XUTF8);
+ break;
+ }
+ }
+ }
+ case 0x003C:
+ {
+ const unsigned int j=(buf[2]<<8)+buf[3];
+ switch(j)
+ {
+ case 0x0000:
+ buffer=GUTF8String::create(buf,sizeof(buf),GStringRep::XUCS4_3412);
+ break;
+ case 0x003F:
+ buffer=GUTF8String::create(buf,sizeof(buf),GStringRep::XUTF16BE);
+ break;
+ default:
+ buffer=GUTF8String::create(buf,sizeof(buf),GStringRep::XUTF8);
+ break;
+ }
+ break;
+ }
+ case 0x3C00:
+ {
+ const unsigned int j=(buf[2]<<8)+buf[3];
+ switch(j)
+ {
+ case 0x0000:
+ buffer=GUTF8String::create(buf,sizeof(buf),GStringRep::XUCS4LE);
+ break;
+ case 0x3F00:
+ buffer=GUTF8String::create(buf,sizeof(buf),GStringRep::XUTF16LE);
+ break;
+ default:
+ buffer=GUTF8String::create(buf,sizeof(buf),GStringRep::XUTF8);
+ break;
+ }
+ break;
+ }
+ case 0x4C6F:
+ {
+ const unsigned int j=(buf[2]<<8)+buf[3];
+ buffer=GUTF8String::create(buf,sizeof(buf),
+ (j == 0xA794)?(GStringRep::XEBCDIC):(GStringRep::XUTF8));
+ break;
+ }
+ case 0xFFFE:
+ {
+ buffer=GUTF8String::create(buf+2,sizeof(buf)-2,GStringRep::XUTF16LE);
+ startpos+=2;
+ break;
+ }
+ case 0xFEFF:
+ {
+ buffer=GUTF8String::create(buf+2,sizeof(buf)-2,GStringRep::XUTF16BE);
+ startpos+=2;
+ break;
+ }
+ case 0xEFBB:
+ {
+ if(buf[2] == 0xBF)
+ {
+ buffer=GUTF8String::create(buf+3,sizeof(buf)-3,GStringRep::XUTF8);
+ startpos+=3;
+ }else
+ {
+ buffer=GUTF8String::create(buf,sizeof(buf),GStringRep::XUTF8);
+ }
+ break;
+ }
+ case 0x3C3F:
+ default:
+ {
+ buffer=GUTF8String::create(buf,sizeof(buf),GStringRep::XUTF8);
+ }
+ }
+ bs=ibs;
+}
+
+XMLByteStream::~XMLByteStream()
+{}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/UnicodeByteStream.h b/kviewshell/plugins/djvu/libdjvu/UnicodeByteStream.h
new file mode 100644
index 00000000..df678ffe
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/UnicodeByteStream.h
@@ -0,0 +1,199 @@
+//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: UnicodeByteStream.h,v 1.9 2003/11/07 22:08:22 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _UNICODEBYTESTREAM_H_
+#define _UNICODEBYTESTREAM_H_
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+
+/** @name UnicodeByteStream.h
+
+ Files #"UnicodeByteStream.h"# and #"UnicodeByteStream.cpp"# implement a parser for
+ files structured W3C Extensible Markup Language (XML) 1.0 (Second Edition).
+
+ Class \Ref{UnicodeByteStream} provides a way to read or write XML files.
+ files. Member functions provide an easy mean to position the underlying
+ \Ref{ByteStream}.
+
+ {\bf References} --- W3C Extensible Markup Language (XML) 1.0
+ (Second Edition)
+ \URL{http://www.w3.org/TR/2000/REC-xml-20001006.html}
+
+ @memo
+ XML file parser.
+ @author
+ Bill C Riemers <docbill@sourceforge.net>
+ @version
+ #$Id: UnicodeByteStream.h,v 1.9 2003/11/07 22:08:22 leonb Exp $# */
+//@{
+
+#include "DjVuGlobal.h"
+#include "GString.h"
+#include "ByteStream.h"
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+
+/** ByteStream interface for an Unicode file.
+
+ Class #UnicodeByteStream# augments the #ByteStream# interface with
+ functions for navigating Unicode documents. It works in relation
+ with a ByteStream specified at construction time.
+
+ {\bf Reading an Unicode file} --- You can read an Unicode file by
+ constructing an #UnicodeByteStream# object attached to the ByteStream
+ containing the Unicode file.
+
+ {\bf Writing an Unicode file} --- You can write an Unicode file by
+ constructing an #UnicodeByteStream# object attached to the seekable
+ ByteStream object that will contain the XML file.
+
+ Writing an XML file requires a seekable ByteStream (see
+ \Ref{ByteStream::is_seekable}). This is not much of a problem because you
+ can always create the XML file into a \Ref{MemoryByteStream} and then use
+ \Ref{ByteStream::copy} to transfer the XML file into a non seekable
+ ByteStream. */
+
+class UnicodeByteStream : public ByteStream
+{
+protected:
+ UnicodeByteStream(const UnicodeByteStream &bs);
+ UnicodeByteStream(GP<ByteStream> bs,
+ const GStringRep::EncodeType encodetype=GStringRep::XUTF8);
+public:
+ /** Constructs an UnicodeByteStream object attached to ByteStream #bs#.
+ Any ByteStream can be used when reading an XML file. Writing
+ an XML file however requires a seekable ByteStream. */
+ static GP<UnicodeByteStream> create(GP<ByteStream> bs,
+ const GStringRep::EncodeType encodetype=GStringRep::XUTF8)
+ { return new UnicodeByteStream(bs,encodetype); }
+
+ // --- BYTESTREAM INTERFACE
+ ~UnicodeByteStream();
+ /// Sets the encoding type and seek's to position 0.
+ void set_encodetype(const GStringRep::EncodeType et=GStringRep::XUTF8);
+ void set_encoding(const GUTF8String &encoding);
+ /// Simmular to fgets(), except read aheads effect the tell() position.
+ virtual GUTF8String gets(size_t const t=0,unsigned long const stopat='\n',bool const inclusive=true);
+ /// Resets the gets buffering as well as physically seeking.
+ virtual int seek(long offset, int whence = SEEK_SET, bool nothrow=false);
+ /** Physically reads the specified bytes, and truncate the read ahead buffer.
+ */
+ virtual size_t read(void *buffer, size_t size);
+ /// Not correctly implimented...
+ virtual size_t write(const void *buffer, size_t size);
+ /// tell will tell you the read position, including read ahead for gets()...
+ virtual long tell(void) const;
+ /// Does a flush, and clears the read ahead buffer.
+ virtual void flush(void);
+
+ /// Find out how many lines have been read with gets.
+ int get_lines_read(void) const { return linesread; }
+protected:
+ /// The real byte stream.
+ GP<ByteStream> bs;
+ GUTF8String buffer;
+ int bufferpos;
+ int linesread;
+ long startpos;
+private:
+ // Cancel C++ default stuff
+ UnicodeByteStream & operator=(UnicodeByteStream &);
+};
+
+
+class XMLByteStream : public UnicodeByteStream
+{
+protected:
+ XMLByteStream(GP<ByteStream> &bs);
+ XMLByteStream(UnicodeByteStream &bs);
+ void init(void);
+public:
+ static GP<XMLByteStream> create(GP<ByteStream> bs);
+ static GP<XMLByteStream> create(UnicodeByteStream &bs);
+ // --- BYTESTREAM INTERFACE
+ ~XMLByteStream();
+};
+
+inline GP<XMLByteStream>
+XMLByteStream::create(UnicodeByteStream &bs)
+{
+ return new XMLByteStream(bs);
+}
+
+//@}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
+
diff --git a/kviewshell/plugins/djvu/libdjvu/XMLParser.cpp b/kviewshell/plugins/djvu/libdjvu/XMLParser.cpp
new file mode 100644
index 00000000..b1d9f469
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/XMLParser.cpp
@@ -0,0 +1,1128 @@
+//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: XMLParser.cpp,v 1.10 2003/11/07 22:08:22 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+// From: Leon Bottou, 1/31/2002
+// This is purely Lizardtech stuff.
+
+#include "XMLParser.h"
+#include "XMLTags.h"
+#include "ByteStream.h"
+#include "GOS.h"
+#include "DjVuDocument.h"
+#include "DjVuText.h"
+#include "DjVuAnno.h"
+#include "DjVuFile.h"
+#include "DjVuImage.h"
+#include "debug.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+static const char mimetype[]="image/x.djvu";
+static const char bodytag[]="BODY";
+static const char areatag[]="AREA";
+static const char maptag[]="MAP";
+static const char objecttag[]="OBJECT";
+static const char paramtag[]="PARAM";
+static const char wordtag[]="WORD";
+static const char linetag[]="LINE";
+static const char paragraphtag[]="PARAGRAPH";
+static const char regiontag[]="REGION";
+static const char pagecolumntag[]="PAGECOLUMN";
+static const char hiddentexttag[]="HIDDENTEXT";
+static const char metadatatag[]="METADATA";
+
+class lt_XMLParser::Impl : public lt_XMLParser
+{
+public:
+ Impl(void);
+ virtual ~Impl();
+ /// Parse the specified bytestream.
+ virtual void parse(const GP<ByteStream> &bs);
+ /// Parse the specified tags - this one does all the work
+ virtual void parse(const lt_XMLTags &tags);
+ /// write to disk.
+ virtual void save(void);
+ /// erase.
+ virtual void empty(void);
+protected:
+ GP<DjVuFile> get_file(const GURL &url,GUTF8String page);
+
+ void parse_anno(const int width, const int height,
+ const lt_XMLTags &GObject,
+ GMap<GUTF8String,GP<lt_XMLTags> > &Maps, DjVuFile &dfile);
+
+ void parse_text(const int width, const int height,
+ const lt_XMLTags &GObject, DjVuFile &dfile);
+
+ void parse_meta(const lt_XMLTags &GObject, DjVuFile &dfile);
+
+ void ChangeAnno( const int width, const int height,
+ DjVuFile &dfile, const lt_XMLTags &map);
+
+ void ChangeInfo(DjVuFile &dfile,const int dpi,const double gamma);
+
+ void ChangeText( const int width, const int height,
+ DjVuFile &dfile, const lt_XMLTags &map);
+
+ void ChangeMeta( DjVuFile &dfile, const lt_XMLTags &map);
+
+ void ChangeTextOCR( const GUTF8String &value,
+ const int width, const int height,
+ const GP<DjVuFile> &dfile);
+
+ // we may want to make these list of modified file static so
+ // they only needed to be loaded and saved once.
+
+ GMap<GUTF8String,GP<DjVuFile> > m_files;
+ GMap<GUTF8String,GP<DjVuDocument> > m_docs;
+
+ GURL m_codebase;
+ GCriticalSection xmlparser_lock;
+};
+
+static GP<ByteStream>
+OCRcallback(
+ void * const xarg,
+ lt_XMLParser::mapOCRcallback * const xcallback,
+ const GUTF8String &value=GUTF8String(),
+ const GP<DjVuImage> &image=0 );
+
+static inline GP<ByteStream>
+OCRcallback(const GUTF8String &value, const GP<DjVuImage> &image)
+{
+ return OCRcallback(0,0,value,image);
+}
+
+lt_XMLParser::lt_XMLParser() {}
+lt_XMLParser::~lt_XMLParser() {}
+lt_XMLParser::Impl::Impl() {}
+lt_XMLParser::Impl::~Impl() {}
+
+GP<lt_XMLParser>
+lt_XMLParser::create(void)
+{
+ return new lt_XMLParser::Impl;
+}
+
+// helper function for args
+static void
+intList(GUTF8String coords, GList<int> &retval)
+{
+ int pos=0;
+ while(coords.length())
+ {
+ int epos;
+ unsigned long i=coords.toLong(pos,epos,10);
+ if(epos>=0)
+ {
+ retval.append(i);
+ const int n=coords.nextNonSpace(epos);
+ if(coords[n] != ',')
+ break;
+ pos=n+1;
+ }
+ }
+}
+
+void
+lt_XMLParser::Impl::empty(void)
+{
+ GCriticalSectionLock lock(&xmlparser_lock);
+ m_files.empty();
+ m_docs.empty();
+}
+
+void
+lt_XMLParser::Impl::save(void)
+{
+ GCriticalSectionLock lock(&xmlparser_lock);
+ for(GPosition pos=m_docs;pos;++pos)
+ {
+ const GP<DjVuDocument> doc(m_docs[pos]);
+ const GURL url=doc->get_init_url();
+
+ DEBUG_MSG("Saving "<<(const char *)url<<" with new text and annotations\n");
+ const bool bundle=doc->is_bundled()||(doc->get_doc_type()==DjVuDocument::SINGLE_PAGE);
+ doc->save_as(url,bundle);
+ }
+ empty();
+}
+
+void
+lt_XMLParser::Impl::parse(const GP<ByteStream> &bs)
+{
+ const GP<lt_XMLTags> tags(lt_XMLTags::create(bs));
+ parse(*tags);
+}
+
+static const GMap<GUTF8String,GMapArea::BorderType> &
+BorderTypeMap(void)
+{
+ static GMap<GUTF8String,GMapArea::BorderType> typeMap;
+ if (! typeMap.size())
+ {
+ typeMap["none"]=GMapArea::NO_BORDER;
+ typeMap["xor"]=GMapArea::XOR_BORDER;
+ typeMap["solid"]=GMapArea::SOLID_BORDER;
+ typeMap["default"]=GMapArea::SOLID_BORDER;
+ typeMap["shadowout"]=GMapArea::SHADOW_OUT_BORDER;
+ typeMap["shadowin"]=GMapArea::SHADOW_IN_BORDER;
+ typeMap["etchedin"]=GMapArea::SHADOW_EIN_BORDER;
+ typeMap["etchedout"]=GMapArea::SHADOW_EOUT_BORDER;
+ }
+ return typeMap;
+}
+
+static unsigned long
+convertToColor(const GUTF8String &s)
+{
+ unsigned long retval=0;
+ if(s.length())
+ {
+ int endpos;
+ if(s[0] == '#')
+ {
+ retval=s.substr(1,-1).toULong(0,endpos,16);
+ }
+ if(endpos < 0)
+ {
+ G_THROW( (ERR_MSG("XMLAnno.bad_color") "\t")+s );
+ }
+ }
+ return retval;
+}
+
+void
+lt_XMLParser::Impl::ChangeInfo(DjVuFile &dfile,const int dpi,const double gamma)
+{
+ GP<DjVuInfo> info;
+ if(dpi >= 5 && dpi <= 4800)
+ {
+ dfile.resume_decode(true);
+ if(dfile.info && (dpi != dfile.info->dpi) )
+ {
+ info=new DjVuInfo(*dfile.info);
+ info->dpi=dpi;
+ }
+ }
+ if(gamma >= 0.1 && gamma <= 5.0)
+ {
+ dfile.resume_decode(true);
+ if(dfile.info && (gamma != dfile.info->gamma) )
+ {
+ if(!info)
+ info=new DjVuInfo(*dfile.info);
+ info->gamma=gamma;
+ }
+ }
+ if(info)
+ {
+ dfile.change_info(info);
+ }
+}
+
+void
+lt_XMLParser::Impl::ChangeAnno(
+ const int width, const int height,
+ DjVuFile &dfile,
+ const lt_XMLTags &map )
+{
+ dfile.resume_decode(true);
+ const GP<DjVuInfo> info(dfile.info);
+ const GP<DjVuAnno> ganno(DjVuAnno::create());
+ DjVuAnno &anno=*ganno;
+ GPosition map_pos;
+ map_pos=map.contains(areatag);
+ if(dfile.contains_anno())
+ {
+ GP<ByteStream> annobs=dfile.get_merged_anno();
+ if(annobs)
+ {
+ anno.decode(annobs);
+ if(anno.ant && info)
+ {
+ anno.ant->map_areas.empty();
+ }
+ }
+// dfile.remove_anno();
+ }
+ if(info && map_pos)
+ {
+ const int h=info->height;
+ const int w=info->width;
+ double ws=1.0;
+ double hs=1.0;
+ if(width && width != w)
+ {
+ ws=((double)w)/((double)width);
+ }
+ if(height && height != h)
+ {
+ hs=((double)h)/((double)height);
+ }
+ if(!anno.ant)
+ {
+ anno.ant=DjVuANT::create();
+ }
+ GPList<GMapArea> &map_areas=anno.ant->map_areas;
+ map_areas.empty();
+ GPList<lt_XMLTags> gareas=map[map_pos];
+ for(GPosition pos=gareas;pos;++pos)
+ {
+ if(gareas[pos])
+ {
+ lt_XMLTags &areas=*(gareas[pos]);
+ GMap<GUTF8String,GUTF8String> args(areas.get_args());
+ GList<int> coords;
+ // ******************************************************
+ // Parse the coords attribute: first read the raw data into
+ // a list, then scale the x, y data into another list. For
+ // circles, you also get a radius element with (looks like an x
+ // with no matching y).
+ // ******************************************************
+ {
+ GPosition coords_pos=args.contains("coords");
+ if(coords_pos)
+ {
+ GList<int> raw_coords;
+ intList(args[coords_pos],raw_coords);
+ for(GPosition raw_pos=raw_coords;raw_pos;++raw_pos)
+ {
+ const int r=raw_coords[raw_pos];
+ const int x=(int)(ws*(double)r+0.5);
+ coords.append(x);
+ int y=h-1;
+ if(! ++raw_pos)
+ {
+ y-=(int)(hs*(double)r+0.5);
+ }else
+ {
+ y-=(int)(hs*(double)raw_coords[raw_pos]+0.5);
+ }
+ coords.append(y);
+// DjVuPrintMessage("Coords (%d,%d)\n",x,y);
+ }
+ }
+ }
+ GUTF8String shape;
+ {
+ GPosition shape_pos=args.contains("shape");
+ if(shape_pos)
+ {
+ shape=args[shape_pos];
+ }
+ }
+ GP<GMapArea> a;
+ if(shape == "default")
+ {
+ GRect rect(0,0,w,h);
+ a=GMapRect::create(rect);
+ }else if(!shape.length() || shape == "rect")
+ {
+ int xx[4];
+ int i=0;
+ for(GPosition rect_pos=coords;(rect_pos)&&(i<4);++rect_pos,++i)
+ {
+ xx[i]=coords[rect_pos];
+ }
+ if(i!=4)
+ {
+ G_THROW( ERR_MSG("XMLAnno.bad_rect") );
+ }
+ int xmin,xmax;
+ if(xx[0]>xx[2])
+ {
+ xmax=xx[0];
+ xmin=xx[2];
+ }else
+ {
+ xmin=xx[0];
+ xmax=xx[2];
+ }
+ int ymin,ymax;
+ if(xx[1]>xx[3])
+ {
+ ymax=xx[1];
+ ymin=xx[3];
+ }else
+ {
+ ymin=xx[1];
+ ymax=xx[3];
+ }
+ GRect rect(xmin,ymin,xmax-xmin,ymax-ymin);
+ a=GMapRect::create(rect);
+ }else if(shape == "circle")
+ {
+ int xx[4];
+ int i=0;
+ GPosition rect_pos=coords.lastpos();
+ if(rect_pos)
+ {
+ coords.append(coords[rect_pos]);
+ for(rect_pos=coords;(rect_pos)&&(i<4);++rect_pos)
+ {
+ xx[i++]=coords[rect_pos];
+ }
+ }
+ if(i!=4)
+ {
+ G_THROW( ERR_MSG("XMLAnno.bad_circle") );
+ }
+ int x=xx[0],y=xx[1],rx=xx[2],ry=(h-xx[3])-1;
+ GRect rect(x-rx,y-ry,2*rx,2*ry);
+ a=GMapOval::create(rect);
+ }else if(shape == "oval")
+ {
+ int xx[4];
+ int i=0;
+ for(GPosition rect_pos=coords;(rect_pos)&&(i<4);++rect_pos,++i)
+ {
+ xx[i]=coords[rect_pos];
+ }
+ if(i!=4)
+ {
+ G_THROW( ERR_MSG("XMLAnno.bad_oval") );
+ }
+ int xmin,xmax;
+ if(xx[0]>xx[2])
+ {
+ xmax=xx[0];
+ xmin=xx[2];
+ }else
+ {
+ xmin=xx[0];
+ xmax=xx[2];
+ }
+ int ymin,ymax;
+ if(xx[1]>xx[3])
+ {
+ ymax=xx[1];
+ ymin=xx[3];
+ }else
+ {
+ ymin=xx[1];
+ ymax=xx[3];
+ }
+ GRect rect(xmin,ymin,xmax-xmin,ymax-ymin);
+ a=GMapOval::create(rect);
+ }else if(shape == "poly")
+ {
+ GP<GMapPoly> p=GMapPoly::create();
+ for(GPosition poly_pos=coords;poly_pos;++poly_pos)
+ {
+ int x=coords[poly_pos];
+ if(! ++poly_pos)
+ break;
+ int y=coords[poly_pos];
+ p->add_vertex(x,y);
+ }
+ p->close_poly();
+ a=p;
+ }else
+ {
+ G_THROW( ( ERR_MSG("XMLAnno.unknown_shape") "\t")+shape );
+ }
+ if(a)
+ {
+ GPosition pos;
+ if((pos=args.contains("href")))
+ {
+ a->url=args[pos];
+ }
+ if((pos=args.contains("target")))
+ {
+ a->target=args[pos];
+ }
+ if((pos=args.contains("alt")))
+ {
+ a->comment=args[pos];
+ }
+ if((pos=args.contains("bordertype")))
+ {
+ GUTF8String b=args[pos];
+ static const GMap<GUTF8String,GMapArea::BorderType> typeMap=BorderTypeMap();
+ if((pos=typeMap.contains(b)))
+ {
+ a->border_type=typeMap[pos];
+ }else
+ {
+ G_THROW( (ERR_MSG("XMLAnno.unknown_border") "\t")+b );
+ }
+ }
+ a->border_always_visible=!!args.contains("visible");
+ if((pos=args.contains("bordercolor")))
+ {
+ a->border_color=convertToColor(args[pos]);
+ }
+ if((pos=args.contains("highlight")))
+ {
+ a->hilite_color=convertToColor(args[pos]);
+ }
+ if((pos=args.contains("border")))
+ {
+ a->border_width=args[pos].toInt(); //atoi(args[pos]);
+ }
+ map_areas.append(a);
+ }
+ }
+ }
+ }
+ dfile.set_modified(true);
+ dfile.anno=ByteStream::create();
+ anno.encode(dfile.anno);
+}
+
+GP<DjVuFile>
+lt_XMLParser::Impl::get_file(const GURL &url,GUTF8String id)
+{
+ GP<DjVuFile> dfile;
+ GP<DjVuDocument> doc;
+ GCriticalSectionLock lock(&xmlparser_lock);
+ {
+ GPosition pos=m_docs.contains(url.get_string());
+ if(pos)
+ {
+ doc=m_docs[pos];
+ }else
+ {
+ doc=DjVuDocument::create_wait(url);
+ if(! doc->wait_for_complete_init())
+ {
+ G_THROW(( ERR_MSG("XMLAnno.fail_init") "\t")+url.get_string() );
+ }
+ m_docs[url.get_string()]=doc;
+ }
+ if(id.is_int())
+ {
+ const int xpage=id.toInt(); //atoi((char const *)page);
+ if(xpage>0)
+ id=doc->page_to_id(xpage-1);
+ }else if(!id.length())
+ {
+ id=doc->page_to_id(0);
+ }
+ }
+ const GURL fileurl(doc->id_to_url(id));
+ GPosition dpos(m_files.contains(fileurl.get_string()));
+ if(!dpos)
+ {
+ if(!doc->get_id_list().contains(id))
+ {
+ G_THROW( ERR_MSG("XMLAnno.bad_page") );
+ }
+ dfile=doc->get_djvu_file(id,false);
+ if(!dfile)
+ {
+ G_THROW( ERR_MSG("XMLAnno.bad_page") );
+ }
+ m_files[fileurl.get_string()]=dfile;
+ }else
+ {
+ dfile=m_files[dpos];
+ }
+ return dfile;
+}
+
+void
+lt_XMLParser::Impl::parse(const lt_XMLTags &tags)
+{
+ const GPList<lt_XMLTags> Body(tags.get_Tags(bodytag));
+ GPosition pos=Body;
+
+ if(!pos || (pos != Body.lastpos()))
+ {
+ G_THROW( ERR_MSG("XMLAnno.extra_body") );
+ }
+ const GP<lt_XMLTags> GBody(Body[pos]);
+ if(!GBody)
+ {
+ G_THROW( ERR_MSG("XMLAnno.no_body") );
+ }
+
+ GMap<GUTF8String,GP<lt_XMLTags> > Maps;
+ lt_XMLTags::get_Maps(maptag,"name",Body,Maps);
+
+ const GPList<lt_XMLTags> Objects(GBody->get_Tags(objecttag));
+ lt_XMLTags::get_Maps(maptag,"name",Objects,Maps);
+
+ for(GPosition Objpos=Objects;Objpos;++Objpos)
+ {
+ lt_XMLTags &GObject=*Objects[Objpos];
+ // Map of attributes to value (e.g. "width" --> "500")
+ const GMap<GUTF8String,GUTF8String> &args=GObject.get_args();
+ GURL codebase;
+ {
+ DEBUG_MSG("Setting up codebase... m_codebase = " << m_codebase << "\n");
+ GPosition codebasePos=args.contains("codebase");
+ // If user specified a codebase attribute, assume it is correct (absolute URL):
+ // the GURL constructor will throw an exception if it isn't
+ if(codebasePos)
+ {
+ codebase=GURL::UTF8(args[codebasePos]);
+ }else if (m_codebase.is_dir())
+ {
+ codebase=m_codebase;
+ }else
+ {
+ codebase=GURL::Filename::UTF8(GOS::cwd());
+ }
+ DEBUG_MSG("codebase = " << codebase << "\n");
+ }
+ // the data attribute specifies the input file. This can be
+ // either an absolute URL (starts with file:/) or a relative
+ // URL (for now, just a path and file name). If it's absolute,
+ // our GURL will adequately wrap it. If it's relative, we need
+ // to use the codebase attribute to form an absolute URL first.
+ GPosition datapos=args.contains("data");
+ if(datapos)
+ {
+ bool isDjVuType=false;
+ GPosition typePos(args.contains("type"));
+ if(typePos)
+ {
+ if(args[typePos] != mimetype)
+ {
+// DjVuPrintErrorUTF8("Ignoring %s Object tag\n",mimetype);
+ continue;
+ }
+ isDjVuType=true;
+ }
+ const GURL url=GURL::UTF8(args[datapos],(args[datapos][0] == '/')?codebase.base():codebase);
+ int width;
+ {
+ GPosition widthPos=args.contains("width");
+ width=(widthPos)?args[widthPos].toInt():0;
+ }
+ int height;
+ {
+ GPosition heightPos=args.contains("height");
+ height=(heightPos)?args[heightPos].toInt():0;
+ }
+ GUTF8String gamma;
+ GUTF8String dpi;
+ GUTF8String page;
+ GUTF8String do_ocr;
+ {
+ GPosition paramPos(GObject.contains(paramtag));
+ if(paramPos)
+ {
+ const GPList<lt_XMLTags> Params(GObject[paramPos]);
+ for(GPosition loc=Params;loc;++loc)
+ {
+ const GMap<GUTF8String,GUTF8String> &pargs=Params[loc]->get_args();
+ GPosition namepos=pargs.contains("name");
+ if(namepos)
+ {
+ GPosition valuepos=pargs.contains("value");
+ if(valuepos)
+ {
+ const GUTF8String name=pargs[namepos].downcase();
+ const GUTF8String &value=pargs[valuepos];
+ if(name == "flags")
+ {
+ GMap<GUTF8String,GUTF8String> args;
+ lt_XMLTags::ParseValues(value,args,true);
+ if(args.contains("page"))
+ {
+ page=args["page"];
+ }
+ if(args.contains("dpi"))
+ {
+ dpi=args["dpi"];
+ }
+ if(args.contains("gamma"))
+ {
+ gamma=args["gamma"];
+ }
+ if(args.contains("ocr"))
+ {
+ do_ocr=args["ocr"];
+ }
+ }else if(name == "page")
+ {
+ page=value;
+ }else if(name == "dpi")
+ {
+ dpi=value;
+ }else if(name == "gamma")
+ {
+ gamma=value;
+ }else if(name == "ocr")
+ {
+ do_ocr=value;
+ }
+ }
+ }
+ }
+ }
+ }
+ const GP<DjVuFile> dfile(get_file(url,page));
+ if(dpi.is_int() || gamma.is_float())
+ {
+ int pos=0;
+ ChangeInfo(*dfile,dpi.toInt(),gamma.toDouble(pos,pos));
+ }
+ parse_anno(width,height,GObject,Maps,*dfile);
+ parse_meta(GObject,*dfile);
+ parse_text(width,height,GObject,*dfile);
+ ChangeTextOCR(do_ocr,width,height,dfile);
+ }
+ }
+}
+
+void
+lt_XMLParser::Impl::parse_anno(
+ const int width,
+ const int height,
+ const lt_XMLTags &GObject,
+ GMap<GUTF8String,GP<lt_XMLTags> > &Maps,
+ DjVuFile &dfile )
+{
+ GP<lt_XMLTags> map;
+ {
+ GPosition usemappos=GObject.get_args().contains("usemap");
+ if(usemappos)
+ {
+ const GUTF8String mapname(GObject.get_args()[usemappos]);
+ GPosition mappos=Maps.contains(mapname);
+ if(!mappos)
+ {
+ G_THROW((ERR_MSG("XMLAnno.map_find") "\t")+mapname );
+ }else
+ {
+ map=Maps[mappos];
+ }
+ }
+ }
+ if(map)
+ {
+ ChangeAnno(width,height,dfile,*map);
+ }
+}
+
+#ifdef max
+#undef max
+#endif
+template<class TYPE>
+static inline TYPE max(TYPE a,TYPE b) { return (a>b)?a:b; }
+#ifdef min
+#undef min
+#endif
+template<class TYPE>
+static inline TYPE min(TYPE a,TYPE b) { return (a<b)?a:b; }
+
+// used to build the zone tree
+// true is returned if the GRect is known for this object,
+// and false, if the rectangle's size is just the parent size.
+static bool
+make_child_layer(
+ DjVuTXT::Zone &parent,
+ const lt_XMLTags &tag, ByteStream &bs,
+ const int height, const double ws, const double hs)
+{
+ bool retval=true;
+ // the plugin thinks there are only Pages, Lines and Words
+ // so we don't make Paragraphs, Regions and Columns zones
+ // if we did the plugin is not able to search the text but
+ // DjVuToText writes out all the text anyway
+ DjVuTXT::Zone *self_ptr;
+ char sepchar;
+ const GUTF8String name(tag.get_name());
+ if(name == wordtag)
+ {
+ self_ptr=parent.append_child();
+ self_ptr->ztype = DjVuTXT::WORD;
+ sepchar=' ';
+ }else if(name == linetag)
+ {
+ self_ptr=parent.append_child();
+ self_ptr->ztype = DjVuTXT::LINE;
+ sepchar=DjVuTXT::end_of_line;
+ }else if(name == paragraphtag)
+ {
+ self_ptr=parent.append_child();
+ self_ptr->ztype = DjVuTXT::PARAGRAPH;
+ sepchar=DjVuTXT::end_of_paragraph;
+ }else if(name == regiontag)
+ {
+ self_ptr=parent.append_child();
+ self_ptr->ztype = DjVuTXT::REGION;
+ sepchar=DjVuTXT::end_of_region;
+ }else if(name == pagecolumntag)
+ {
+ self_ptr=parent.append_child();
+ self_ptr->ztype = DjVuTXT::COLUMN;
+ sepchar=DjVuTXT::end_of_column;
+ }else
+ {
+ self_ptr = &parent;
+ self_ptr->ztype = DjVuTXT::PAGE;
+ sepchar=0;
+ }
+ DjVuTXT::Zone &self = *self_ptr;
+ self.text_start = bs.tell();
+ int &xmin=self.rect.xmin, &ymin=self.rect.ymin,
+ &xmax=self.rect.xmax, &ymax=self.rect.ymax;
+ GRect default_rect;
+ default_rect.xmin=max(parent.rect.xmax,parent.rect.xmin);
+ default_rect.xmax=min(parent.rect.xmax,parent.rect.xmin);
+ default_rect.ymin=max(parent.rect.ymax,parent.rect.ymin);
+ default_rect.ymax=min(parent.rect.ymax,parent.rect.ymin);
+ // Now if there are coordinates, use those.
+ GPosition pos(tag.get_args().contains("coords"));
+ if(pos)
+ {
+ GList<int> rectArgs;
+ intList(tag.get_args()[pos], rectArgs);
+ if((pos=rectArgs))
+ {
+ xmin=(int)(ws*(double)rectArgs[pos]);
+ if(++pos)
+ {
+ ymin=(height-1)-(int)(hs*(double)rectArgs[pos]);
+ if(++pos)
+ {
+ xmax=(int)(ws*(double)rectArgs[pos]);
+ if(++pos)
+ {
+ ymax=(height-1)-(int)(hs*(double)rectArgs[pos]);
+ if(xmin>xmax) // Make sure xmin is really minimum
+ {
+ const int t=xmin;
+ xmin=xmax;
+ xmax=t;
+ }
+ if(ymin>ymax) // Make sure ymin is really minimum
+ {
+ const int t=ymin;
+ ymin=ymax;
+ ymax=t;
+ }
+ }
+ }
+ }
+ }
+ }
+ if(self.ztype == DjVuTXT::WORD)
+ {
+ if(! pos)
+ {
+ self.rect=default_rect;
+ retval=false;
+ }
+ const GUTF8String raw(tag.get_raw().fromEscaped());
+ const int i=raw.nextNonSpace(0);
+ bs.writestring(raw.substr(i,raw.firstEndSpace(i)-i));
+ if(sepchar)
+ bs.write8(sepchar);
+ self.text_length = bs.tell() - self.text_start;
+ }else if(pos)
+ {
+ pos=tag.get_content();
+ if(pos)
+ {
+ for(pos=tag.get_content(); pos; ++pos)
+ {
+ const GP<lt_XMLTags> t(tag.get_content()[pos].tag);
+ make_child_layer(self, *t, bs, height,ws,hs);
+ }
+ if(sepchar)
+ bs.write8(sepchar);
+ self.text_length = bs.tell() - self.text_start;
+ }else
+ {
+ const GUTF8String raw(tag.get_raw().fromEscaped());
+ const int i=raw.nextNonSpace(0);
+ bs.writestring(raw.substr(i,raw.firstEndSpace(i)-i));
+ if(sepchar)
+ bs.write8(sepchar);
+ self.text_length = bs.tell() - self.text_start;
+ }
+ }else
+ {
+ self.rect=default_rect;
+ if((pos=tag.get_content()))
+ {
+ do
+ {
+ const GP<lt_XMLTags> t(tag.get_content()[pos].tag);
+ const GRect save_rect(self.rect);
+ self.rect=default_rect;
+ if(retval=make_child_layer(self, *t, bs, height,ws,hs))
+ {
+ xmin=min(save_rect.xmin,xmin);
+ xmax=max(save_rect.xmax,xmax);
+ ymin=min(save_rect.ymin,ymin);
+ ymax=max(save_rect.ymax,ymax);
+ }else
+ {
+ // If the child doesn't have coordinates, we need to use a box
+ // at least as big as the parent's coordinates.
+ xmin=min(save_rect.xmin,default_rect.xmax);
+ xmax=max(save_rect.xmax,default_rect.xmin);
+ ymin=min(save_rect.ymin,default_rect.ymax);
+ ymax=max(save_rect.ymax,default_rect.ymin);
+ for(; pos; ++pos)
+ {
+ const GP<lt_XMLTags> t(tag.get_content()[pos].tag);
+ make_child_layer(self, *t, bs, height,ws,hs);
+ }
+ break;
+ }
+ } while(++pos);
+ if(sepchar)
+ bs.write8(sepchar);
+ self.text_length = bs.tell() - self.text_start;
+ }else
+ {
+ const GUTF8String raw(tag.get_raw().fromEscaped());
+ const int i=raw.nextNonSpace(0);
+ bs.writestring(raw.substr(i,raw.firstEndSpace(i)-i));
+ if(sepchar)
+ bs.write8(sepchar);
+ self.text_length = bs.tell() - self.text_start;
+ }
+ }
+ parent.rect.xmin=min(xmin,parent.rect.xmin);
+ parent.rect.ymin=min(ymin,parent.rect.ymin);
+ parent.rect.xmax=max(xmax,parent.rect.xmax);
+ parent.rect.ymax=max(ymax,parent.rect.ymax);
+ if(xmin>xmax)
+ {
+ const int t=xmin;
+ xmin=xmax;
+ xmax=t;
+ }
+ if(ymin>ymax)
+ {
+ const int t=ymin;
+ ymin=ymax;
+ ymax=t;
+ }
+// DjVuPrintMessage("(%d,%d)(%d,%d)<<<\\%o>>>\n",
+// xmin,ymin,xmax,ymax, sepchar);
+ return retval;
+}
+
+void
+lt_XMLParser::Impl::ChangeTextOCR(
+ const GUTF8String &value,
+ const int width,
+ const int height,
+ const GP<DjVuFile> &dfile)
+{
+ if(value.length() && value.downcase() != "false")
+ {
+ const GP<ByteStream> bs=OCRcallback(value,DjVuImage::create(dfile));
+ if( bs && bs->size() )
+ {
+ const GP<lt_XMLTags> tags(lt_XMLTags::create(bs));
+ ChangeText(width,height,*dfile,*tags);
+ }
+ }
+}
+
+void
+lt_XMLParser::Impl::ChangeMeta(
+ DjVuFile &dfile, const lt_XMLTags &tags )
+{
+ dfile.resume_decode(true);
+ GP<ByteStream> gbs(ByteStream::create());
+ tags.write(*gbs,false);
+ gbs->seek(0L);
+ GUTF8String raw(gbs->getAsUTF8());
+ if(raw.length())
+ {
+ //GUTF8String gs="<"+(metadatatag+(">"+raw))+"</"+metadatatag+">\n");
+ dfile.change_meta(raw+"\n");
+ }else
+ {
+ dfile.change_meta(GUTF8String());
+ }
+}
+
+void
+lt_XMLParser::Impl::ChangeText(
+ const int width, const int height,
+ DjVuFile &dfile, const lt_XMLTags &tags )
+{
+ dfile.resume_decode(true);
+
+ GP<DjVuText> text = DjVuText::create();
+ GP<DjVuTXT> txt = text->txt = DjVuTXT::create();
+
+ // to store the new text
+ GP<ByteStream> textbs = ByteStream::create();
+
+ GP<DjVuInfo> info=(dfile.info);
+ if(info)
+ {
+ const int h=info->height;
+ const int w=info->width;
+ txt->page_zone.text_start = 0;
+ DjVuTXT::Zone &parent=txt->page_zone;
+ parent.rect.xmin=0;
+ parent.rect.ymin=0;
+ parent.rect.ymax=h;
+ parent.rect.xmax=w;
+ double ws=1.0;
+ if(width && width != w)
+ {
+ ws=((double)w)/((double)width);
+ }
+ double hs=1.0;
+ if(height && height != h)
+ {
+ hs=((double)h)/((double)height);
+ }
+ make_child_layer(parent, tags, *textbs, h, ws,hs);
+ textbs->write8(0);
+ long len = textbs->tell();
+ txt->page_zone.text_length = len;
+ textbs->seek(0,SEEK_SET);
+ textbs->read(txt->textUTF8.getbuf(len), len);
+
+ dfile.change_text(txt,false);
+ }
+}
+
+void
+lt_XMLParser::Impl::parse_text(
+ const int width,
+ const int height,
+ const lt_XMLTags &GObject,
+ DjVuFile &dfile )
+{
+ GPosition textPos = GObject.contains(hiddentexttag);
+ if(textPos)
+ {
+ // loop through the hidden text - there should only be one
+ // if there are more ??only the last one will be saved??
+ GPList<lt_XMLTags> textTags = GObject[textPos];
+ GPosition pos = textTags;
+ ChangeText(width,height,dfile,*textTags[pos]);
+ }
+}
+
+void
+lt_XMLParser::Impl::parse_meta(
+ const lt_XMLTags &GObject,
+ DjVuFile &dfile )
+{
+ GPosition metaPos = GObject.contains(metadatatag);
+ if(metaPos)
+ {
+ // loop through the hidden text - there should only be one
+ // if there are more ??only the last one will be saved??
+ GPList<lt_XMLTags> metaTags = GObject[metaPos];
+ GPosition pos = metaTags;
+ ChangeMeta(dfile,*metaTags[pos]);
+ }
+}
+
+static GP<ByteStream>
+OCRcallback(
+ void * const xarg,
+ lt_XMLParser::mapOCRcallback * const xcallback,
+ const GUTF8String &value,
+ const GP<DjVuImage> &image )
+{
+ GP<ByteStream> retval;
+ static void *arg=0;
+ static lt_XMLParser::mapOCRcallback *callback=0;
+ if(image)
+ {
+ if(callback)
+ retval=callback(arg,value,image);
+ }else
+ {
+ arg=xarg;
+ callback=xcallback;
+ }
+ return retval;
+}
+
+void
+lt_XMLParser::setOCRcallback(
+ void * const arg,
+ mapOCRcallback * const callback)
+{
+ ::OCRcallback(arg,callback);
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/XMLParser.h b/kviewshell/plugins/djvu/libdjvu/XMLParser.h
new file mode 100644
index 00000000..08b6d508
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/XMLParser.h
@@ -0,0 +1,123 @@
+//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: XMLParser.h,v 1.9 2003/11/07 22:08:22 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _LT_XMLPARSER__
+#define _LT_XMLPARSER__
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+// From: Leon Bottou, 1/31/2002
+// This is purely Lizardtech stuff.
+
+#include "GContainer.h"
+#include "GURL.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+class ByteStream;
+class lt_XMLTags;
+class lt_XMLContents;
+class DjVuFile;
+class DjVuDocument;
+class DjVuImage;
+class GBitmap;
+
+// this is the base class for using XML to change DjVu Docs.
+
+class lt_XMLParser : public GPEnabled
+{
+public:
+ class Impl;
+ typedef GP<ByteStream> mapOCRcallback(
+ void *,const GUTF8String &value,const GP<DjVuImage> &);
+protected:
+ lt_XMLParser(void);
+ virtual ~lt_XMLParser();
+public:
+ static GP<lt_XMLParser> create(void);
+ /// Parse the specified bytestream.
+ virtual void parse(const GP<ByteStream> &bs) = 0;
+ /// Parse the specified tags - this one does all the work
+ virtual void parse(const lt_XMLTags &tags) = 0;
+ /// write to disk.
+ virtual void save(void) = 0;
+ /// erase.
+ virtual void empty(void) = 0;
+
+ // helper function for args
+ static void setOCRcallback(
+ void * const arg,mapOCRcallback * const );
+};
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif /* _LT_XMLPARSER__ */
+
+
diff --git a/kviewshell/plugins/djvu/libdjvu/XMLTags.cpp b/kviewshell/plugins/djvu/libdjvu/XMLTags.cpp
new file mode 100644
index 00000000..2511a585
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/XMLTags.cpp
@@ -0,0 +1,417 @@
+//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: XMLTags.cpp,v 1.12 2003/11/07 22:08:22 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+// From: Leon Bottou, 1/31/2002
+// This is purely Lizardtech stuff.
+
+#include "XMLTags.h"
+#include "UnicodeByteStream.h"
+#include <ctype.h>
+#if HAS_WCTYPE
+#include <wctype.h>
+#endif
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+lt_XMLContents::lt_XMLContents(void) {}
+
+lt_XMLContents::lt_XMLContents(GP<lt_XMLTags> t)
+{
+ tag=t;
+}
+
+static GUTF8String
+getargn(char const tag[], char const *&t)
+{
+ char const *s;
+ for(s=tag;isspace(*s);s++);
+ for(t=s;(*t)&&((*t)!='/')&&((*t)!='>')&&((*t)!='=')&&!isspace(*t);++t);
+ return GUTF8String(s,t-s);
+}
+
+static GUTF8String
+getargv(char const tag[], char const *&t)
+{
+ GUTF8String retval;
+ if(tag && tag[0] == '=')
+ {
+ char const *s=t=tag+1;
+ if((*t == '"')||(*t == '\47'))
+ {
+ char const q=*(t++);
+ for(s++;(*t)&&((*t)!=q)&&((*t)!='>');++t);
+ retval=GUTF8String(s,t-s);
+ if (t[0] == q)
+ {
+ ++t;
+ }
+ }else
+ {
+ for(t=s;(*t)&&((*t)!='/')&&((*t)!='>')&&!isspace(*t);++t);
+ retval=GUTF8String(s,t-s);
+ }
+ }else
+ {
+ t=tag;
+ }
+ return retval;
+}
+
+static GUTF8String
+tagtoname(char const tag[],char const *&t)
+{
+ char const *s;
+ for(s=tag;isspace(*s);s++);
+ for(t=s;(*t)&&((*t)!='>')&&((*t)!='/')&&!isspace(*t);++t);
+ return GUTF8String(s,t-s);
+}
+
+static inline GUTF8String
+tagtoname(char const tag[])
+{
+ char const *t;
+ return tagtoname(tag,t);
+}
+
+static inline bool
+isspaces(const GUTF8String &raw)
+{
+ return (raw.nextNonSpace() == (int)raw.length());
+}
+
+void
+lt_XMLTags::ParseValues(char const *t, GMap<GUTF8String,GUTF8String> &args,bool downcase)
+{
+ GUTF8String argn;
+ char const *tt;
+ while((argn=getargn(t,tt)).length())
+ {
+ if(downcase)
+ argn=argn.downcase();
+ args[argn]=getargv(tt,t).fromEscaped();
+ }
+}
+
+lt_XMLTags::~lt_XMLTags() {}
+
+lt_XMLTags::lt_XMLTags(void) : startline(0) {}
+
+lt_XMLTags::lt_XMLTags(const char n[]) : startline(0)
+{
+ char const *t;
+ name=tagtoname(n,t);
+ ParseValues(t,args);
+}
+
+void
+lt_XMLTags::init(const GP<ByteStream> &bs)
+{
+ GP<XMLByteStream> gxmlbs=XMLByteStream::create(bs);
+ init(*gxmlbs);
+}
+
+void
+lt_XMLTags::init(const GURL &url)
+{
+ const GP<ByteStream> bs=ByteStream::create(url,"rb");
+ init(bs);
+}
+
+void
+lt_XMLTags::init(XMLByteStream &xmlbs)
+{
+ if(!get_count())
+ {
+ G_THROW( ERR_MSG("XMLTags.no_GP") );
+ }
+ GPList<lt_XMLTags> level;
+ GUTF8String tag,raw(xmlbs.gets(0,'<',false));
+ int linesread=xmlbs.get_lines_read();
+ if(!isspaces(raw))
+ {
+ G_THROW( (ERR_MSG("XMLTags.raw_string") "\t")+raw);
+ }
+ GUTF8String encoding;
+ for(int len;(len=(tag=xmlbs.gets(0,'>',true)).length());)
+ {
+ if(tag[len-1] != '>')
+ {
+ G_THROW((ERR_MSG("XMLTags.bad_tag") "\t")+tag);
+ }
+ switch(tag[1])
+ {
+ case '?':
+ {
+ while(len < 4 || tag.substr(len-2,len) != "?>")
+ {
+ GUTF8String cont(xmlbs.gets(0,'>',true));
+ if(!cont.length())
+ {
+ G_THROW( (ERR_MSG("XMLTags.bad_PI") "\t")+tag);
+ }
+ len=((tag+=cont).length());
+ }
+ char const *n;
+ GUTF8String xtag = tag.substr(2,-1);
+ GUTF8String xname = tagtoname(xtag,n);
+ if(xname.downcase() == "xml")
+ {
+ ParseValues(n,args);
+ for(GPosition pos=args;pos;++pos)
+ {
+ if(args.key(pos) == "encoding")
+ {
+ const GUTF8String e=args[pos].upcase();
+ if(e != encoding)
+ {
+ xmlbs.set_encoding((encoding=e));
+ }
+ }
+ }
+ }
+ break;
+ }
+ case '!':
+ {
+ if(tag[2] == '-' && tag[3] == '-')
+ {
+ while((len < 7) ||
+ (tag.substr(len-3,-1) != "-->"))
+ {
+ GUTF8String cont(xmlbs.gets(0,'>',true));
+ if(!cont.length())
+ {
+ GUTF8String mesg;
+ mesg.format( ERR_MSG("XMLTags.bad_comment") "\t%s",(const char *)tag);
+ G_THROW(mesg);
+ }
+ len=((tag+=cont).length());
+ }
+ }
+ break;
+ }
+ case '/':
+ {
+ GUTF8String xname=tagtoname(tag.substr(2,-1));
+ GPosition last=level.lastpos();
+ if(last)
+ {
+ if(level[last]->name != xname)
+ {
+ G_THROW( (ERR_MSG("XMLTags.unmatched_end") "\t")
+ +level[last]->name+("\t"+GUTF8String(level[last]->get_Line()))
+ +("\t"+xname)+("\t"+GUTF8String(linesread+1)));
+ }
+ level.del(last);
+ }else
+ {
+ G_THROW( ERR_MSG("XMLTags.bad_form") );
+ }
+ break;
+ }
+ default:
+ {
+ GPosition last=level.lastpos();
+ GP<lt_XMLTags> t;
+ if(last)
+ {
+ t=new lt_XMLTags(tag.substr(1,len-1));
+ level[last]->addtag(t);
+ if(tag[len-2] != '/')
+ {
+ level.append(t);
+ }
+ }else if(tag[len-2] != '/')
+ {
+ char const *n;
+ GUTF8String xtag = tag.substr(1,-1);
+ name=tagtoname(xtag, n);
+ ParseValues(n,args);
+ t=this;
+ level.append(t);
+ }else
+ {
+ G_THROW( ERR_MSG("XMLTags.no_body") );
+ }
+ t->set_Line(linesread+1);
+ break;
+ }
+ }
+ if((raw=xmlbs.gets(0,'<',false))[0])
+ {
+ linesread=xmlbs.get_lines_read();
+ GPosition last=level.lastpos();
+ if(last)
+ {
+ level[last]->addraw(raw);
+ }else if(!isspaces(raw))
+ {
+ G_THROW(( ERR_MSG("XMLTags.raw_string") "\t")+raw);
+ }
+ }
+ }
+}
+
+GPList<lt_XMLTags>
+lt_XMLTags::get_Tags(char const tagname[]) const
+{
+ GPosition pos=allTags.contains(tagname);
+ GPList<lt_XMLTags> retval;
+ return (pos?allTags[pos]:retval);
+}
+
+void
+lt_XMLTags::get_Maps(char const tagname[],
+ char const argn[],
+ GPList<lt_XMLTags> list,
+ GMap<GUTF8String, GP<lt_XMLTags> > &map)
+{
+ for(GPosition pos=list;pos;++pos)
+ {
+ GP<lt_XMLTags> &tag=list[pos];
+ if(tag)
+ {
+ GPosition loc;
+ if((loc=tag->contains(tagname)))
+ {
+ GPList<lt_XMLTags> maps=(GPList<lt_XMLTags> &)((*tag)[loc]);
+ for(GPosition mloc=maps;mloc;++mloc)
+ {
+ GP<lt_XMLTags> gtag=maps[mloc];
+ if(gtag)
+ {
+ GMap<GUTF8String,GUTF8String> &args=gtag->args;
+ GPosition gpos;
+ if((gpos=args.contains(argn)))
+ {
+ map[args[gpos]]=gtag;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+void
+lt_XMLTags::write(ByteStream &bs,bool const top) const
+{
+ if(name.length())
+ {
+ GUTF8String tag="<"+name;
+ for(GPosition pos=args;pos;++pos)
+ {
+ tag+=GUTF8String(' ')+args.key(pos)+GUTF8String("=\42")+args[pos].toEscaped()+GUTF8String("\42");
+ }
+ GPosition tags=content;
+ if(tags||raw.length())
+ {
+ tag+=">";
+ bs.writall((const char *)tag,tag.length());
+ tag="</"+name+">";
+ if(raw.length())
+ {
+ bs.writestring(raw);
+ }
+ for(;tags;++tags)
+ {
+ content[tags].write(bs);
+ }
+ }else if(!raw.length())
+ {
+ tag+="/>";
+ }
+ bs.writall((const char *)tag,tag.length());
+ }
+ if(top)
+ {
+ bs.writall("\n",1);
+ }
+}
+
+void
+lt_XMLContents::write(ByteStream &bs) const
+{
+ if(tag)
+ {
+ tag->write(bs,false);
+ }
+ if(raw.length())
+ {
+ bs.writestring(raw);
+ }
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/XMLTags.h b/kviewshell/plugins/djvu/libdjvu/XMLTags.h
new file mode 100644
index 00000000..027e629b
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/XMLTags.h
@@ -0,0 +1,242 @@
+//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: XMLTags.h,v 1.9 2003/11/07 22:08:22 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _LT_XMLTAGS__
+#define _LT_XMLTAGS__
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+// From: Leon Bottou, 1/31/2002
+// This is purely Lizardtech stuff.
+
+#include "GContainer.h"
+#include "GString.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+class lt_XMLContents;
+class DjVuFile;
+class DjVuDocument;
+class ByteStream;
+class XMLByteStream;
+class GURL;
+
+class lt_XMLTags : public GPEnabled
+{
+protected:
+ lt_XMLTags();
+ lt_XMLTags(const char n[]);
+
+public:
+ /// Empty creator.
+ static GP<lt_XMLTags> create(void) { return new lt_XMLTags; }
+ /// Default the specified tag.
+ static GP<lt_XMLTags> create(const char n[]) { return new lt_XMLTags(n); }
+ /// Initialize from the specified URL.
+ void init(const GURL & url);
+ /// Create from the specified URL.
+ static GP<lt_XMLTags> create(const GURL &url);
+ /// Initialize from the specified bytestream.
+ void init(const GP<ByteStream> &bs);
+ /// Create from the specified bytestream.
+ static GP<lt_XMLTags> create(const GP<ByteStream> &bs);
+ /// Initialize from an XMLByteStream.
+ void init(XMLByteStream &xmlbs);
+ /// Create from an XML bytestream.
+ static GP<lt_XMLTags> create(XMLByteStream &xmlbs);
+ /// Non-virtual destructor.
+ ~lt_XMLTags();
+
+ inline int get_Line(void) const;
+ inline const GUTF8String& get_raw(void) const;
+ inline const GUTF8String& get_name(void) const;
+ inline const GList<lt_XMLContents>& get_content(void) const;
+ inline const GMap<GUTF8String,GUTF8String>& get_args(void) const;
+ inline const GMap<GUTF8String,GPList<lt_XMLTags> >& get_allTags(void) const;
+
+ GPList<lt_XMLTags> get_Tags(char const tagname[]) const;
+ inline void set_Line(const int xstartline) { startline=xstartline; }
+
+ inline void addtag(GP<lt_XMLTags> x);
+ inline void addraw(GUTF8String raw);
+ inline GPosition contains(GUTF8String name) const;
+ inline const GPList<lt_XMLTags> & operator [] (const GUTF8String name) const;
+ inline const GPList<lt_XMLTags> & operator [] (const GPosition &pos) const;
+ static void ParseValues(char const *t, GMap<GUTF8String,GUTF8String> &args,bool downcase=true);
+ static void get_Maps(char const tagname[],char const argn[],
+ GPList<lt_XMLTags> list, GMap<GUTF8String, GP<lt_XMLTags> > &map);
+ void write(ByteStream &bs,bool const top=true) const;
+
+protected:
+ GUTF8String name;
+ GMap<GUTF8String,GUTF8String> args;
+ GList<lt_XMLContents> content;
+ GUTF8String raw;
+ GMap<GUTF8String,GPList<lt_XMLTags> > allTags;
+ int startline;
+};
+
+class lt_XMLContents
+{
+public:
+ lt_XMLContents(void);
+ lt_XMLContents(GP<lt_XMLTags> tag);
+ GP<lt_XMLTags> tag;
+ GUTF8String raw;
+ void write(ByteStream &bs) const;
+};
+
+inline GP<lt_XMLTags>
+lt_XMLTags::create(const GURL &url)
+{
+ const GP<lt_XMLTags> retval(new lt_XMLTags);
+ retval->init(url);
+ return retval;
+}
+
+inline GP<lt_XMLTags>
+lt_XMLTags::create(const GP<ByteStream> &bs)
+{
+ const GP<lt_XMLTags> retval(new lt_XMLTags);
+ retval->init(bs);
+ return retval;
+}
+
+inline GP<lt_XMLTags>
+lt_XMLTags::create(XMLByteStream &xmlbs)
+{
+ const GP<lt_XMLTags> retval(new lt_XMLTags);
+ retval->init(xmlbs);
+ return retval;
+}
+
+/// Non-virtual destructor.
+inline void
+lt_XMLTags::addtag (GP<lt_XMLTags> x)
+{
+ content.append(lt_XMLContents(x));
+ allTags[x->name].append(x);
+}
+
+inline void
+lt_XMLTags::addraw (GUTF8String r)
+{
+ GPosition pos=content;
+ if(pos)
+ {
+ content[pos].raw+=r;
+ }else
+ {
+ raw+=r;
+ }
+}
+
+inline int
+lt_XMLTags::get_Line(void) const
+{ return startline; }
+
+inline const GUTF8String &
+lt_XMLTags::get_name(void) const { return name; }
+
+inline const GUTF8String &
+lt_XMLTags::get_raw(void) const { return raw; }
+
+inline const GList<lt_XMLContents> &
+lt_XMLTags::get_content(void) const { return content; }
+
+inline const GMap<GUTF8String,GUTF8String> &
+lt_XMLTags::get_args(void) const { return args; }
+
+inline const GMap<GUTF8String,GPList<lt_XMLTags> > &
+lt_XMLTags::get_allTags(void) const { return allTags; }
+
+inline GPosition
+lt_XMLTags::contains(GUTF8String name) const
+{
+ return allTags.contains(name);
+}
+
+inline const GPList<lt_XMLTags> &
+lt_XMLTags::operator [] (const GUTF8String name) const
+{
+ return allTags[name];
+}
+
+inline const GPList<lt_XMLTags> &
+lt_XMLTags::operator [] (const GPosition &pos) const
+{
+ return allTags[pos];
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif /* _LT_XMLTAGS__ */
+
+
diff --git a/kviewshell/plugins/djvu/libdjvu/ZPCodec.cpp b/kviewshell/plugins/djvu/libdjvu/ZPCodec.cpp
new file mode 100644
index 00000000..89461872
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/ZPCodec.cpp
@@ -0,0 +1,1292 @@
+//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: ZPCodec.cpp,v 1.10 2004/08/06 14:49:34 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+// From: Leon Bottou, 1/31/2002
+// Almost equal to my initial code.
+
+#include "ZPCodec.h"
+#include "ByteStream.h"
+#include "GException.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+////////////////////////////////////////////////////////////////
+// CODER SPECIFICATION
+////////////////////////////////////////////////////////////////
+
+
+#ifndef ZPCODER
+#ifndef ZCODER
+#define ZPCODER
+#endif
+#endif
+#ifdef ZCODER
+
+// The ZCODER option is provided for documentation purposes only. The ZCODER
+// might come dangerously close to U.S. patent 5059976 (Mitsubishi). This is
+// why we always use the ZPCODER, although it usually produces 1% larger files.
+#warning "The ZCODER may infringe non-LizardTech patent(s)."
+#warning "You should use the ZPCODER instead."
+#endif
+
+
+////////////////////////////////////////////////////////////////
+// ZP CODER DEFAULT ADAPTATION TABLE
+////////////////////////////////////////////////////////////////
+
+
+// See ZPCodec::ZPCodec to see how this
+// default table is modified when not
+// using the DjVu compatibility mode.
+
+
+static ZPCodec::Table default_ztable[256] =
+{
+#ifdef ZPCODER
+ /* This table has been designed for the ZPCoder
+ * by running the following command in file 'zptable.sn':
+ * (fast-crude (steady-mat 0.0035 0.0002) 260)))
+ */
+ { 0x8000, 0x0000, 84, 145 }, /* 000: p=0.500000 ( 0, 0) */
+ { 0x8000, 0x0000, 3, 4 }, /* 001: p=0.500000 ( 0, 0) */
+ { 0x8000, 0x0000, 4, 3 }, /* 002: p=0.500000 ( 0, 0) */
+ { 0x6bbd, 0x10a5, 5, 1 }, /* 003: p=0.465226 ( 0, 0) */
+ { 0x6bbd, 0x10a5, 6, 2 }, /* 004: p=0.465226 ( 0, 0) */
+ { 0x5d45, 0x1f28, 7, 3 }, /* 005: p=0.430708 ( 0, 0) */
+ { 0x5d45, 0x1f28, 8, 4 }, /* 006: p=0.430708 ( 0, 0) */
+ { 0x51b9, 0x2bd3, 9, 5 }, /* 007: p=0.396718 ( 0, 0) */
+ { 0x51b9, 0x2bd3, 10, 6 }, /* 008: p=0.396718 ( 0, 0) */
+ { 0x4813, 0x36e3, 11, 7 }, /* 009: p=0.363535 ( 0, 0) */
+ { 0x4813, 0x36e3, 12, 8 }, /* 010: p=0.363535 ( 0, 0) */
+ { 0x3fd5, 0x408c, 13, 9 }, /* 011: p=0.331418 ( 0, 0) */
+ { 0x3fd5, 0x408c, 14, 10 }, /* 012: p=0.331418 ( 0, 0) */
+ { 0x38b1, 0x48fd, 15, 11 }, /* 013: p=0.300585 ( 0, 0) */
+ { 0x38b1, 0x48fd, 16, 12 }, /* 014: p=0.300585 ( 0, 0) */
+ { 0x3275, 0x505d, 17, 13 }, /* 015: p=0.271213 ( 0, 0) */
+ { 0x3275, 0x505d, 18, 14 }, /* 016: p=0.271213 ( 0, 0) */
+ { 0x2cfd, 0x56d0, 19, 15 }, /* 017: p=0.243438 ( 0, 0) */
+ { 0x2cfd, 0x56d0, 20, 16 }, /* 018: p=0.243438 ( 0, 0) */
+ { 0x2825, 0x5c71, 21, 17 }, /* 019: p=0.217391 ( 0, 0) */
+ { 0x2825, 0x5c71, 22, 18 }, /* 020: p=0.217391 ( 0, 0) */
+ { 0x23ab, 0x615b, 23, 19 }, /* 021: p=0.193150 ( 0, 0) */
+ { 0x23ab, 0x615b, 24, 20 }, /* 022: p=0.193150 ( 0, 0) */
+ { 0x1f87, 0x65a5, 25, 21 }, /* 023: p=0.170728 ( 0, 0) */
+ { 0x1f87, 0x65a5, 26, 22 }, /* 024: p=0.170728 ( 0, 0) */
+ { 0x1bbb, 0x6962, 27, 23 }, /* 025: p=0.150158 ( 0, 0) */
+ { 0x1bbb, 0x6962, 28, 24 }, /* 026: p=0.150158 ( 0, 0) */
+ { 0x1845, 0x6ca2, 29, 25 }, /* 027: p=0.131418 ( 0, 0) */
+ { 0x1845, 0x6ca2, 30, 26 }, /* 028: p=0.131418 ( 0, 0) */
+ { 0x1523, 0x6f74, 31, 27 }, /* 029: p=0.114460 ( 0, 0) */
+ { 0x1523, 0x6f74, 32, 28 }, /* 030: p=0.114460 ( 0, 0) */
+ { 0x1253, 0x71e6, 33, 29 }, /* 031: p=0.099230 ( 0, 0) */
+ { 0x1253, 0x71e6, 34, 30 }, /* 032: p=0.099230 ( 0, 0) */
+ { 0x0fcf, 0x7404, 35, 31 }, /* 033: p=0.085611 ( 0, 0) */
+ { 0x0fcf, 0x7404, 36, 32 }, /* 034: p=0.085611 ( 0, 0) */
+ { 0x0d95, 0x75d6, 37, 33 }, /* 035: p=0.073550 ( 0, 0) */
+ { 0x0d95, 0x75d6, 38, 34 }, /* 036: p=0.073550 ( 0, 0) */
+ { 0x0b9d, 0x7768, 39, 35 }, /* 037: p=0.062888 ( 0, 0) */
+ { 0x0b9d, 0x7768, 40, 36 }, /* 038: p=0.062888 ( 0, 0) */
+ { 0x09e3, 0x78c2, 41, 37 }, /* 039: p=0.053539 ( 0, 0) */
+ { 0x09e3, 0x78c2, 42, 38 }, /* 040: p=0.053539 ( 0, 0) */
+ { 0x0861, 0x79ea, 43, 39 }, /* 041: p=0.045365 ( 0, 0) */
+ { 0x0861, 0x79ea, 44, 40 }, /* 042: p=0.045365 ( 0, 0) */
+ { 0x0711, 0x7ae7, 45, 41 }, /* 043: p=0.038272 ( 0, 0) */
+ { 0x0711, 0x7ae7, 46, 42 }, /* 044: p=0.038272 ( 0, 0) */
+ { 0x05f1, 0x7bbe, 47, 43 }, /* 045: p=0.032174 ( 0, 0) */
+ { 0x05f1, 0x7bbe, 48, 44 }, /* 046: p=0.032174 ( 0, 0) */
+ { 0x04f9, 0x7c75, 49, 45 }, /* 047: p=0.026928 ( 0, 0) */
+ { 0x04f9, 0x7c75, 50, 46 }, /* 048: p=0.026928 ( 0, 0) */
+ { 0x0425, 0x7d0f, 51, 47 }, /* 049: p=0.022444 ( 0, 0) */
+ { 0x0425, 0x7d0f, 52, 48 }, /* 050: p=0.022444 ( 0, 0) */
+ { 0x0371, 0x7d91, 53, 49 }, /* 051: p=0.018636 ( 0, 0) */
+ { 0x0371, 0x7d91, 54, 50 }, /* 052: p=0.018636 ( 0, 0) */
+ { 0x02d9, 0x7dfe, 55, 51 }, /* 053: p=0.015421 ( 0, 0) */
+ { 0x02d9, 0x7dfe, 56, 52 }, /* 054: p=0.015421 ( 0, 0) */
+ { 0x0259, 0x7e5a, 57, 53 }, /* 055: p=0.012713 ( 0, 0) */
+ { 0x0259, 0x7e5a, 58, 54 }, /* 056: p=0.012713 ( 0, 0) */
+ { 0x01ed, 0x7ea6, 59, 55 }, /* 057: p=0.010419 ( 0, 0) */
+ { 0x01ed, 0x7ea6, 60, 56 }, /* 058: p=0.010419 ( 0, 0) */
+ { 0x0193, 0x7ee6, 61, 57 }, /* 059: p=0.008525 ( 0, 0) */
+ { 0x0193, 0x7ee6, 62, 58 }, /* 060: p=0.008525 ( 0, 0) */
+ { 0x0149, 0x7f1a, 63, 59 }, /* 061: p=0.006959 ( 0, 0) */
+ { 0x0149, 0x7f1a, 64, 60 }, /* 062: p=0.006959 ( 0, 0) */
+ { 0x010b, 0x7f45, 65, 61 }, /* 063: p=0.005648 ( 0, 0) */
+ { 0x010b, 0x7f45, 66, 62 }, /* 064: p=0.005648 ( 0, 0) */
+ { 0x00d5, 0x7f6b, 67, 63 }, /* 065: p=0.004506 ( 0, 0) */
+ { 0x00d5, 0x7f6b, 68, 64 }, /* 066: p=0.004506 ( 0, 0) */
+ { 0x00a5, 0x7f8d, 69, 65 }, /* 067: p=0.003480 ( 0, 0) */
+ { 0x00a5, 0x7f8d, 70, 66 }, /* 068: p=0.003480 ( 0, 0) */
+ { 0x007b, 0x7faa, 71, 67 }, /* 069: p=0.002602 ( 0, 0) */
+ { 0x007b, 0x7faa, 72, 68 }, /* 070: p=0.002602 ( 0, 0) */
+ { 0x0057, 0x7fc3, 73, 69 }, /* 071: p=0.001843 ( 0, 0) */
+ { 0x0057, 0x7fc3, 74, 70 }, /* 072: p=0.001843 ( 0, 0) */
+ { 0x003b, 0x7fd7, 75, 71 }, /* 073: p=0.001248 ( 0, 0) */
+ { 0x003b, 0x7fd7, 76, 72 }, /* 074: p=0.001248 ( 0, 0) */
+ { 0x0023, 0x7fe7, 77, 73 }, /* 075: p=0.000749 ( 0, 0) */
+ { 0x0023, 0x7fe7, 78, 74 }, /* 076: p=0.000749 ( 0, 0) */
+ { 0x0013, 0x7ff2, 79, 75 }, /* 077: p=0.000402 ( 0, 0) */
+ { 0x0013, 0x7ff2, 80, 76 }, /* 078: p=0.000402 ( 0, 0) */
+ { 0x0007, 0x7ffa, 81, 77 }, /* 079: p=0.000153 ( 0, 0) */
+ { 0x0007, 0x7ffa, 82, 78 }, /* 080: p=0.000153 ( 0, 0) */
+ { 0x0001, 0x7fff, 81, 79 }, /* 081: p=0.000027 ( 0, 0) */
+ { 0x0001, 0x7fff, 82, 80 }, /* 082: p=0.000027 ( 0, 0) */
+ { 0x5695, 0x0000, 9, 85 }, /* 083: p=0.411764 ( 2, 3) */
+ { 0x24ee, 0x0000, 86, 226 }, /* 084: p=0.199988 ( 1, 0) */
+ { 0x8000, 0x0000, 5, 6 }, /* 085: p=0.500000 ( 3, 3) */
+ { 0x0d30, 0x0000, 88, 176 }, /* 086: p=0.071422 ( 4, 0) */
+ { 0x481a, 0x0000, 89, 143 }, /* 087: p=0.363634 ( 1, 2) */
+ { 0x0481, 0x0000, 90, 138 }, /* 088: p=0.024388 ( 13, 0) */
+ { 0x3579, 0x0000, 91, 141 }, /* 089: p=0.285711 ( 1, 3) */
+ { 0x017a, 0x0000, 92, 112 }, /* 090: p=0.007999 ( 41, 0) */
+ { 0x24ef, 0x0000, 93, 135 }, /* 091: p=0.199997 ( 1, 5) */
+ { 0x007b, 0x0000, 94, 104 }, /* 092: p=0.002611 ( 127, 0) */
+ { 0x1978, 0x0000, 95, 133 }, /* 093: p=0.137929 ( 1, 8) */
+ { 0x0028, 0x0000, 96, 100 }, /* 094: p=0.000849 ( 392, 0) */
+ { 0x10ca, 0x0000, 97, 129 }, /* 095: p=0.090907 ( 1, 13) */
+ { 0x000d, 0x0000, 82, 98 }, /* 096: p=0.000276 ( 1208, 0) */
+ { 0x0b5d, 0x0000, 99, 127 }, /* 097: p=0.061537 ( 1, 20) */
+ { 0x0034, 0x0000, 76, 72 }, /* 098: p=0.001102 ( 1208, 1) */
+ { 0x078a, 0x0000, 101, 125 }, /* 099: p=0.040815 ( 1, 31) */
+ { 0x00a0, 0x0000, 70, 102 }, /* 100: p=0.003387 ( 392, 1) */
+ { 0x050f, 0x0000, 103, 123 }, /* 101: p=0.027397 ( 1, 47) */
+ { 0x0117, 0x0000, 66, 60 }, /* 102: p=0.005912 ( 392, 2) */
+ { 0x0358, 0x0000, 105, 121 }, /* 103: p=0.018099 ( 1, 72) */
+ { 0x01ea, 0x0000, 106, 110 }, /* 104: p=0.010362 ( 127, 1) */
+ { 0x0234, 0x0000, 107, 119 }, /* 105: p=0.011940 ( 1, 110) */
+ { 0x0144, 0x0000, 66, 108 }, /* 106: p=0.006849 ( 193, 1) */
+ { 0x0173, 0x0000, 109, 117 }, /* 107: p=0.007858 ( 1, 168) */
+ { 0x0234, 0x0000, 60, 54 }, /* 108: p=0.011925 ( 193, 2) */
+ { 0x00f5, 0x0000, 111, 115 }, /* 109: p=0.005175 ( 1, 256) */
+ { 0x0353, 0x0000, 56, 48 }, /* 110: p=0.017995 ( 127, 2) */
+ { 0x00a1, 0x0000, 69, 113 }, /* 111: p=0.003413 ( 1, 389) */
+ { 0x05c5, 0x0000, 114, 134 }, /* 112: p=0.031249 ( 41, 1) */
+ { 0x011a, 0x0000, 65, 59 }, /* 113: p=0.005957 ( 2, 389) */
+ { 0x03cf, 0x0000, 116, 132 }, /* 114: p=0.020618 ( 63, 1) */
+ { 0x01aa, 0x0000, 61, 55 }, /* 115: p=0.009020 ( 2, 256) */
+ { 0x0285, 0x0000, 118, 130 }, /* 116: p=0.013652 ( 96, 1) */
+ { 0x0286, 0x0000, 57, 51 }, /* 117: p=0.013672 ( 2, 168) */
+ { 0x01ab, 0x0000, 120, 128 }, /* 118: p=0.009029 ( 146, 1) */
+ { 0x03d3, 0x0000, 53, 47 }, /* 119: p=0.020710 ( 2, 110) */
+ { 0x011a, 0x0000, 122, 126 }, /* 120: p=0.005961 ( 222, 1) */
+ { 0x05c5, 0x0000, 49, 41 }, /* 121: p=0.031250 ( 2, 72) */
+ { 0x00ba, 0x0000, 124, 62 }, /* 122: p=0.003925 ( 338, 1) */
+ { 0x08ad, 0x0000, 43, 37 }, /* 123: p=0.046979 ( 2, 47) */
+ { 0x007a, 0x0000, 72, 66 }, /* 124: p=0.002586 ( 514, 1) */
+ { 0x0ccc, 0x0000, 39, 31 }, /* 125: p=0.069306 ( 2, 31) */
+ { 0x01eb, 0x0000, 60, 54 }, /* 126: p=0.010386 ( 222, 2) */
+ { 0x1302, 0x0000, 33, 25 }, /* 127: p=0.102940 ( 2, 20) */
+ { 0x02e6, 0x0000, 56, 50 }, /* 128: p=0.015695 ( 146, 2) */
+ { 0x1b81, 0x0000, 29, 131 }, /* 129: p=0.148935 ( 2, 13) */
+ { 0x045e, 0x0000, 52, 46 }, /* 130: p=0.023648 ( 96, 2) */
+ { 0x24ef, 0x0000, 23, 17 }, /* 131: p=0.199999 ( 3, 13) */
+ { 0x0690, 0x0000, 48, 40 }, /* 132: p=0.035533 ( 63, 2) */
+ { 0x2865, 0x0000, 23, 15 }, /* 133: p=0.218748 ( 2, 8) */
+ { 0x09de, 0x0000, 42, 136 }, /* 134: p=0.053434 ( 41, 2) */
+ { 0x3987, 0x0000, 137, 7 }, /* 135: p=0.304346 ( 2, 5) */
+ { 0x0dc8, 0x0000, 38, 32 }, /* 136: p=0.074626 ( 41, 3) */
+ { 0x2c99, 0x0000, 21, 139 }, /* 137: p=0.241378 ( 2, 7) */
+ { 0x10ca, 0x0000, 140, 172 }, /* 138: p=0.090907 ( 13, 1) */
+ { 0x3b5f, 0x0000, 15, 9 }, /* 139: p=0.312499 ( 3, 7) */
+ { 0x0b5d, 0x0000, 142, 170 }, /* 140: p=0.061537 ( 20, 1) */
+ { 0x5695, 0x0000, 9, 85 }, /* 141: p=0.411764 ( 2, 3) */
+ { 0x078a, 0x0000, 144, 168 }, /* 142: p=0.040815 ( 31, 1) */
+ { 0x8000, 0x0000, 141, 248 }, /* 143: p=0.500000 ( 2, 2) */
+ { 0x050f, 0x0000, 146, 166 }, /* 144: p=0.027397 ( 47, 1) */
+ { 0x24ee, 0x0000, 147, 247 }, /* 145: p=0.199988 ( 0, 1) */
+ { 0x0358, 0x0000, 148, 164 }, /* 146: p=0.018099 ( 72, 1) */
+ { 0x0d30, 0x0000, 149, 197 }, /* 147: p=0.071422 ( 0, 4) */
+ { 0x0234, 0x0000, 150, 162 }, /* 148: p=0.011940 ( 110, 1) */
+ { 0x0481, 0x0000, 151, 95 }, /* 149: p=0.024388 ( 0, 13) */
+ { 0x0173, 0x0000, 152, 160 }, /* 150: p=0.007858 ( 168, 1) */
+ { 0x017a, 0x0000, 153, 173 }, /* 151: p=0.007999 ( 0, 41) */
+ { 0x00f5, 0x0000, 154, 158 }, /* 152: p=0.005175 ( 256, 1) */
+ { 0x007b, 0x0000, 155, 165 }, /* 153: p=0.002611 ( 0, 127) */
+ { 0x00a1, 0x0000, 70, 156 }, /* 154: p=0.003413 ( 389, 1) */
+ { 0x0028, 0x0000, 157, 161 }, /* 155: p=0.000849 ( 0, 392) */
+ { 0x011a, 0x0000, 66, 60 }, /* 156: p=0.005957 ( 389, 2) */
+ { 0x000d, 0x0000, 81, 159 }, /* 157: p=0.000276 ( 0, 1208) */
+ { 0x01aa, 0x0000, 62, 56 }, /* 158: p=0.009020 ( 256, 2) */
+ { 0x0034, 0x0000, 75, 71 }, /* 159: p=0.001102 ( 1, 1208) */
+ { 0x0286, 0x0000, 58, 52 }, /* 160: p=0.013672 ( 168, 2) */
+ { 0x00a0, 0x0000, 69, 163 }, /* 161: p=0.003387 ( 1, 392) */
+ { 0x03d3, 0x0000, 54, 48 }, /* 162: p=0.020710 ( 110, 2) */
+ { 0x0117, 0x0000, 65, 59 }, /* 163: p=0.005912 ( 2, 392) */
+ { 0x05c5, 0x0000, 50, 42 }, /* 164: p=0.031250 ( 72, 2) */
+ { 0x01ea, 0x0000, 167, 171 }, /* 165: p=0.010362 ( 1, 127) */
+ { 0x08ad, 0x0000, 44, 38 }, /* 166: p=0.046979 ( 47, 2) */
+ { 0x0144, 0x0000, 65, 169 }, /* 167: p=0.006849 ( 1, 193) */
+ { 0x0ccc, 0x0000, 40, 32 }, /* 168: p=0.069306 ( 31, 2) */
+ { 0x0234, 0x0000, 59, 53 }, /* 169: p=0.011925 ( 2, 193) */
+ { 0x1302, 0x0000, 34, 26 }, /* 170: p=0.102940 ( 20, 2) */
+ { 0x0353, 0x0000, 55, 47 }, /* 171: p=0.017995 ( 2, 127) */
+ { 0x1b81, 0x0000, 30, 174 }, /* 172: p=0.148935 ( 13, 2) */
+ { 0x05c5, 0x0000, 175, 193 }, /* 173: p=0.031249 ( 1, 41) */
+ { 0x24ef, 0x0000, 24, 18 }, /* 174: p=0.199999 ( 13, 3) */
+ { 0x03cf, 0x0000, 177, 191 }, /* 175: p=0.020618 ( 1, 63) */
+ { 0x2b74, 0x0000, 178, 222 }, /* 176: p=0.235291 ( 4, 1) */
+ { 0x0285, 0x0000, 179, 189 }, /* 177: p=0.013652 ( 1, 96) */
+ { 0x201d, 0x0000, 180, 218 }, /* 178: p=0.173910 ( 6, 1) */
+ { 0x01ab, 0x0000, 181, 187 }, /* 179: p=0.009029 ( 1, 146) */
+ { 0x1715, 0x0000, 182, 216 }, /* 180: p=0.124998 ( 9, 1) */
+ { 0x011a, 0x0000, 183, 185 }, /* 181: p=0.005961 ( 1, 222) */
+ { 0x0fb7, 0x0000, 184, 214 }, /* 182: p=0.085105 ( 14, 1) */
+ { 0x00ba, 0x0000, 69, 61 }, /* 183: p=0.003925 ( 1, 338) */
+ { 0x0a67, 0x0000, 186, 212 }, /* 184: p=0.056337 ( 22, 1) */
+ { 0x01eb, 0x0000, 59, 53 }, /* 185: p=0.010386 ( 2, 222) */
+ { 0x06e7, 0x0000, 188, 210 }, /* 186: p=0.037382 ( 34, 1) */
+ { 0x02e6, 0x0000, 55, 49 }, /* 187: p=0.015695 ( 2, 146) */
+ { 0x0496, 0x0000, 190, 208 }, /* 188: p=0.024844 ( 52, 1) */
+ { 0x045e, 0x0000, 51, 45 }, /* 189: p=0.023648 ( 2, 96) */
+ { 0x030d, 0x0000, 192, 206 }, /* 190: p=0.016529 ( 79, 1) */
+ { 0x0690, 0x0000, 47, 39 }, /* 191: p=0.035533 ( 2, 63) */
+ { 0x0206, 0x0000, 194, 204 }, /* 192: p=0.010959 ( 120, 1) */
+ { 0x09de, 0x0000, 41, 195 }, /* 193: p=0.053434 ( 2, 41) */
+ { 0x0155, 0x0000, 196, 202 }, /* 194: p=0.007220 ( 183, 1) */
+ { 0x0dc8, 0x0000, 37, 31 }, /* 195: p=0.074626 ( 3, 41) */
+ { 0x00e1, 0x0000, 198, 200 }, /* 196: p=0.004750 ( 279, 1) */
+ { 0x2b74, 0x0000, 199, 243 }, /* 197: p=0.235291 ( 1, 4) */
+ { 0x0094, 0x0000, 72, 64 }, /* 198: p=0.003132 ( 424, 1) */
+ { 0x201d, 0x0000, 201, 239 }, /* 199: p=0.173910 ( 1, 6) */
+ { 0x0188, 0x0000, 62, 56 }, /* 200: p=0.008284 ( 279, 2) */
+ { 0x1715, 0x0000, 203, 237 }, /* 201: p=0.124998 ( 1, 9) */
+ { 0x0252, 0x0000, 58, 52 }, /* 202: p=0.012567 ( 183, 2) */
+ { 0x0fb7, 0x0000, 205, 235 }, /* 203: p=0.085105 ( 1, 14) */
+ { 0x0383, 0x0000, 54, 48 }, /* 204: p=0.019021 ( 120, 2) */
+ { 0x0a67, 0x0000, 207, 233 }, /* 205: p=0.056337 ( 1, 22) */
+ { 0x0547, 0x0000, 50, 44 }, /* 206: p=0.028571 ( 79, 2) */
+ { 0x06e7, 0x0000, 209, 231 }, /* 207: p=0.037382 ( 1, 34) */
+ { 0x07e2, 0x0000, 46, 38 }, /* 208: p=0.042682 ( 52, 2) */
+ { 0x0496, 0x0000, 211, 229 }, /* 209: p=0.024844 ( 1, 52) */
+ { 0x0bc0, 0x0000, 40, 34 }, /* 210: p=0.063636 ( 34, 2) */
+ { 0x030d, 0x0000, 213, 227 }, /* 211: p=0.016529 ( 1, 79) */
+ { 0x1178, 0x0000, 36, 28 }, /* 212: p=0.094593 ( 22, 2) */
+ { 0x0206, 0x0000, 215, 225 }, /* 213: p=0.010959 ( 1, 120) */
+ { 0x19da, 0x0000, 30, 22 }, /* 214: p=0.139999 ( 14, 2) */
+ { 0x0155, 0x0000, 217, 223 }, /* 215: p=0.007220 ( 1, 183) */
+ { 0x24ef, 0x0000, 26, 16 }, /* 216: p=0.199998 ( 9, 2) */
+ { 0x00e1, 0x0000, 219, 221 }, /* 217: p=0.004750 ( 1, 279) */
+ { 0x320e, 0x0000, 20, 220 }, /* 218: p=0.269229 ( 6, 2) */
+ { 0x0094, 0x0000, 71, 63 }, /* 219: p=0.003132 ( 1, 424) */
+ { 0x432a, 0x0000, 14, 8 }, /* 220: p=0.344827 ( 6, 3) */
+ { 0x0188, 0x0000, 61, 55 }, /* 221: p=0.008284 ( 2, 279) */
+ { 0x447d, 0x0000, 14, 224 }, /* 222: p=0.349998 ( 4, 2) */
+ { 0x0252, 0x0000, 57, 51 }, /* 223: p=0.012567 ( 2, 183) */
+ { 0x5ece, 0x0000, 8, 2 }, /* 224: p=0.434782 ( 4, 3) */
+ { 0x0383, 0x0000, 53, 47 }, /* 225: p=0.019021 ( 2, 120) */
+ { 0x8000, 0x0000, 228, 87 }, /* 226: p=0.500000 ( 1, 1) */
+ { 0x0547, 0x0000, 49, 43 }, /* 227: p=0.028571 ( 2, 79) */
+ { 0x481a, 0x0000, 230, 246 }, /* 228: p=0.363634 ( 2, 1) */
+ { 0x07e2, 0x0000, 45, 37 }, /* 229: p=0.042682 ( 2, 52) */
+ { 0x3579, 0x0000, 232, 244 }, /* 230: p=0.285711 ( 3, 1) */
+ { 0x0bc0, 0x0000, 39, 33 }, /* 231: p=0.063636 ( 2, 34) */
+ { 0x24ef, 0x0000, 234, 238 }, /* 232: p=0.199997 ( 5, 1) */
+ { 0x1178, 0x0000, 35, 27 }, /* 233: p=0.094593 ( 2, 22) */
+ { 0x1978, 0x0000, 138, 236 }, /* 234: p=0.137929 ( 8, 1) */
+ { 0x19da, 0x0000, 29, 21 }, /* 235: p=0.139999 ( 2, 14) */
+ { 0x2865, 0x0000, 24, 16 }, /* 236: p=0.218748 ( 8, 2) */
+ { 0x24ef, 0x0000, 25, 15 }, /* 237: p=0.199998 ( 2, 9) */
+ { 0x3987, 0x0000, 240, 8 }, /* 238: p=0.304346 ( 5, 2) */
+ { 0x320e, 0x0000, 19, 241 }, /* 239: p=0.269229 ( 2, 6) */
+ { 0x2c99, 0x0000, 22, 242 }, /* 240: p=0.241378 ( 7, 2) */
+ { 0x432a, 0x0000, 13, 7 }, /* 241: p=0.344827 ( 3, 6) */
+ { 0x3b5f, 0x0000, 16, 10 }, /* 242: p=0.312499 ( 7, 3) */
+ { 0x447d, 0x0000, 13, 245 }, /* 243: p=0.349998 ( 2, 4) */
+ { 0x5695, 0x0000, 10, 2 }, /* 244: p=0.411764 ( 3, 2) */
+ { 0x5ece, 0x0000, 7, 1 }, /* 245: p=0.434782 ( 3, 4) */
+ { 0x8000, 0x0000, 244, 83 }, /* 246: p=0.500000 ( 2, 2) */
+ { 0x8000, 0x0000, 249, 250 }, /* 247: p=0.500000 ( 1, 1) */
+ { 0x5695, 0x0000, 10, 2 }, /* 248: p=0.411764 ( 3, 2) */
+ { 0x481a, 0x0000, 89, 143 }, /* 249: p=0.363634 ( 1, 2) */
+ { 0x481a, 0x0000, 230, 246 }, /* 250: p=0.363634 ( 2, 1) */
+#endif
+#ifdef ZCODER
+ /* This table has been designed for the ZCoder
+ * by running the following command in file 'ztable2.sn':
+ * (fast-crude (steady-mat 0.0035 0.0002) 260)))
+ */
+ { 0x8000, 0x0000, 84, 139 }, /* 000: p=0.500000 ( 0, 0) */
+ { 0x8000, 0x0000, 3, 4 }, /* 001: p=0.500000 ( 0, 0) */
+ { 0x8000, 0x0000, 4, 3 }, /* 002: p=0.500000 ( 0, 0) */
+ { 0x7399, 0x10a5, 5, 1 }, /* 003: p=0.465226 ( 0, 0) */
+ { 0x7399, 0x10a5, 6, 2 }, /* 004: p=0.465226 ( 0, 0) */
+ { 0x6813, 0x1f28, 7, 3 }, /* 005: p=0.430708 ( 0, 0) */
+ { 0x6813, 0x1f28, 8, 4 }, /* 006: p=0.430708 ( 0, 0) */
+ { 0x5d65, 0x2bd3, 9, 5 }, /* 007: p=0.396718 ( 0, 0) */
+ { 0x5d65, 0x2bd3, 10, 6 }, /* 008: p=0.396718 ( 0, 0) */
+ { 0x5387, 0x36e3, 11, 7 }, /* 009: p=0.363535 ( 0, 0) */
+ { 0x5387, 0x36e3, 12, 8 }, /* 010: p=0.363535 ( 0, 0) */
+ { 0x4a73, 0x408c, 13, 9 }, /* 011: p=0.331418 ( 0, 0) */
+ { 0x4a73, 0x408c, 14, 10 }, /* 012: p=0.331418 ( 0, 0) */
+ { 0x421f, 0x48fe, 15, 11 }, /* 013: p=0.300562 ( 0, 0) */
+ { 0x421f, 0x48fe, 16, 12 }, /* 014: p=0.300562 ( 0, 0) */
+ { 0x3a85, 0x5060, 17, 13 }, /* 015: p=0.271166 ( 0, 0) */
+ { 0x3a85, 0x5060, 18, 14 }, /* 016: p=0.271166 ( 0, 0) */
+ { 0x339b, 0x56d3, 19, 15 }, /* 017: p=0.243389 ( 0, 0) */
+ { 0x339b, 0x56d3, 20, 16 }, /* 018: p=0.243389 ( 0, 0) */
+ { 0x2d59, 0x5c73, 21, 17 }, /* 019: p=0.217351 ( 0, 0) */
+ { 0x2d59, 0x5c73, 22, 18 }, /* 020: p=0.217351 ( 0, 0) */
+ { 0x27b3, 0x615e, 23, 19 }, /* 021: p=0.193091 ( 0, 0) */
+ { 0x27b3, 0x615e, 24, 20 }, /* 022: p=0.193091 ( 0, 0) */
+ { 0x22a1, 0x65a7, 25, 21 }, /* 023: p=0.170683 ( 0, 0) */
+ { 0x22a1, 0x65a7, 26, 22 }, /* 024: p=0.170683 ( 0, 0) */
+ { 0x1e19, 0x6963, 27, 23 }, /* 025: p=0.150134 ( 0, 0) */
+ { 0x1e19, 0x6963, 28, 24 }, /* 026: p=0.150134 ( 0, 0) */
+ { 0x1a0f, 0x6ca3, 29, 25 }, /* 027: p=0.131397 ( 0, 0) */
+ { 0x1a0f, 0x6ca3, 30, 26 }, /* 028: p=0.131397 ( 0, 0) */
+ { 0x167b, 0x6f75, 31, 27 }, /* 029: p=0.114441 ( 0, 0) */
+ { 0x167b, 0x6f75, 32, 28 }, /* 030: p=0.114441 ( 0, 0) */
+ { 0x1353, 0x71e6, 33, 29 }, /* 031: p=0.099214 ( 0, 0) */
+ { 0x1353, 0x71e6, 34, 30 }, /* 032: p=0.099214 ( 0, 0) */
+ { 0x108d, 0x7403, 35, 31 }, /* 033: p=0.085616 ( 0, 0) */
+ { 0x108d, 0x7403, 36, 32 }, /* 034: p=0.085616 ( 0, 0) */
+ { 0x0e1f, 0x75d7, 37, 33 }, /* 035: p=0.073525 ( 0, 0) */
+ { 0x0e1f, 0x75d7, 38, 34 }, /* 036: p=0.073525 ( 0, 0) */
+ { 0x0c01, 0x7769, 39, 35 }, /* 037: p=0.062871 ( 0, 0) */
+ { 0x0c01, 0x7769, 40, 36 }, /* 038: p=0.062871 ( 0, 0) */
+ { 0x0a2b, 0x78c2, 41, 37 }, /* 039: p=0.053524 ( 0, 0) */
+ { 0x0a2b, 0x78c2, 42, 38 }, /* 040: p=0.053524 ( 0, 0) */
+ { 0x0895, 0x79ea, 43, 39 }, /* 041: p=0.045374 ( 0, 0) */
+ { 0x0895, 0x79ea, 44, 40 }, /* 042: p=0.045374 ( 0, 0) */
+ { 0x0737, 0x7ae7, 45, 41 }, /* 043: p=0.038280 ( 0, 0) */
+ { 0x0737, 0x7ae7, 46, 42 }, /* 044: p=0.038280 ( 0, 0) */
+ { 0x060b, 0x7bbe, 47, 43 }, /* 045: p=0.032175 ( 0, 0) */
+ { 0x060b, 0x7bbe, 48, 44 }, /* 046: p=0.032175 ( 0, 0) */
+ { 0x050b, 0x7c75, 49, 45 }, /* 047: p=0.026926 ( 0, 0) */
+ { 0x050b, 0x7c75, 50, 46 }, /* 048: p=0.026926 ( 0, 0) */
+ { 0x0431, 0x7d10, 51, 47 }, /* 049: p=0.022430 ( 0, 0) */
+ { 0x0431, 0x7d10, 52, 48 }, /* 050: p=0.022430 ( 0, 0) */
+ { 0x0379, 0x7d92, 53, 49 }, /* 051: p=0.018623 ( 0, 0) */
+ { 0x0379, 0x7d92, 54, 50 }, /* 052: p=0.018623 ( 0, 0) */
+ { 0x02dd, 0x7dff, 55, 51 }, /* 053: p=0.015386 ( 0, 0) */
+ { 0x02dd, 0x7dff, 56, 52 }, /* 054: p=0.015386 ( 0, 0) */
+ { 0x025b, 0x7e5b, 57, 53 }, /* 055: p=0.012671 ( 0, 0) */
+ { 0x025b, 0x7e5b, 58, 54 }, /* 056: p=0.012671 ( 0, 0) */
+ { 0x01ef, 0x7ea7, 59, 55 }, /* 057: p=0.010414 ( 0, 0) */
+ { 0x01ef, 0x7ea7, 60, 56 }, /* 058: p=0.010414 ( 0, 0) */
+ { 0x0195, 0x7ee6, 61, 57 }, /* 059: p=0.008529 ( 0, 0) */
+ { 0x0195, 0x7ee6, 62, 58 }, /* 060: p=0.008529 ( 0, 0) */
+ { 0x0149, 0x7f1b, 63, 59 }, /* 061: p=0.006935 ( 0, 0) */
+ { 0x0149, 0x7f1b, 64, 60 }, /* 062: p=0.006935 ( 0, 0) */
+ { 0x010b, 0x7f46, 65, 61 }, /* 063: p=0.005631 ( 0, 0) */
+ { 0x010b, 0x7f46, 66, 62 }, /* 064: p=0.005631 ( 0, 0) */
+ { 0x00d5, 0x7f6c, 67, 63 }, /* 065: p=0.004495 ( 0, 0) */
+ { 0x00d5, 0x7f6c, 68, 64 }, /* 066: p=0.004495 ( 0, 0) */
+ { 0x00a5, 0x7f8d, 69, 65 }, /* 067: p=0.003484 ( 0, 0) */
+ { 0x00a5, 0x7f8d, 70, 66 }, /* 068: p=0.003484 ( 0, 0) */
+ { 0x007b, 0x7faa, 71, 67 }, /* 069: p=0.002592 ( 0, 0) */
+ { 0x007b, 0x7faa, 72, 68 }, /* 070: p=0.002592 ( 0, 0) */
+ { 0x0057, 0x7fc3, 73, 69 }, /* 071: p=0.001835 ( 0, 0) */
+ { 0x0057, 0x7fc3, 74, 70 }, /* 072: p=0.001835 ( 0, 0) */
+ { 0x0039, 0x7fd8, 75, 71 }, /* 073: p=0.001211 ( 0, 0) */
+ { 0x0039, 0x7fd8, 76, 72 }, /* 074: p=0.001211 ( 0, 0) */
+ { 0x0023, 0x7fe7, 77, 73 }, /* 075: p=0.000740 ( 0, 0) */
+ { 0x0023, 0x7fe7, 78, 74 }, /* 076: p=0.000740 ( 0, 0) */
+ { 0x0013, 0x7ff2, 79, 75 }, /* 077: p=0.000402 ( 0, 0) */
+ { 0x0013, 0x7ff2, 80, 76 }, /* 078: p=0.000402 ( 0, 0) */
+ { 0x0007, 0x7ffa, 81, 77 }, /* 079: p=0.000153 ( 0, 0) */
+ { 0x0007, 0x7ffa, 82, 78 }, /* 080: p=0.000153 ( 0, 0) */
+ { 0x0001, 0x7fff, 81, 79 }, /* 081: p=0.000027 ( 0, 0) */
+ { 0x0001, 0x7fff, 82, 80 }, /* 082: p=0.000027 ( 0, 0) */
+ { 0x620b, 0x0000, 9, 85 }, /* 083: p=0.411764 ( 2, 3) */
+ { 0x294a, 0x0000, 86, 216 }, /* 084: p=0.199988 ( 1, 0) */
+ { 0x8000, 0x0000, 5, 6 }, /* 085: p=0.500000 ( 3, 3) */
+ { 0x0db3, 0x0000, 88, 168 }, /* 086: p=0.071422 ( 4, 0) */
+ { 0x538e, 0x0000, 89, 137 }, /* 087: p=0.363634 ( 1, 2) */
+ { 0x0490, 0x0000, 90, 134 }, /* 088: p=0.024388 ( 13, 0) */
+ { 0x3e3e, 0x0000, 91, 135 }, /* 089: p=0.285711 ( 1, 3) */
+ { 0x017c, 0x0000, 92, 112 }, /* 090: p=0.007999 ( 41, 0) */
+ { 0x294a, 0x0000, 93, 133 }, /* 091: p=0.199997 ( 1, 5) */
+ { 0x007c, 0x0000, 94, 104 }, /* 092: p=0.002611 ( 127, 0) */
+ { 0x1b75, 0x0000, 95, 131 }, /* 093: p=0.137929 ( 1, 8) */
+ { 0x0028, 0x0000, 96, 100 }, /* 094: p=0.000849 ( 392, 0) */
+ { 0x12fc, 0x0000, 97, 129 }, /* 095: p=0.097559 ( 1, 12) */
+ { 0x000d, 0x0000, 82, 98 }, /* 096: p=0.000276 ( 1208, 0) */
+ { 0x0cfb, 0x0000, 99, 125 }, /* 097: p=0.067795 ( 1, 18) */
+ { 0x0034, 0x0000, 76, 72 }, /* 098: p=0.001102 ( 1208, 1) */
+ { 0x08cd, 0x0000, 101, 123 }, /* 099: p=0.046511 ( 1, 27) */
+ { 0x00a0, 0x0000, 70, 102 }, /* 100: p=0.003387 ( 392, 1) */
+ { 0x05de, 0x0000, 103, 119 }, /* 101: p=0.031249 ( 1, 41) */
+ { 0x0118, 0x0000, 66, 60 }, /* 102: p=0.005912 ( 392, 2) */
+ { 0x03e9, 0x0000, 105, 117 }, /* 103: p=0.020942 ( 1, 62) */
+ { 0x01ed, 0x0000, 106, 110 }, /* 104: p=0.010362 ( 127, 1) */
+ { 0x0298, 0x0000, 107, 115 }, /* 105: p=0.013937 ( 1, 94) */
+ { 0x0145, 0x0000, 66, 108 }, /* 106: p=0.006849 ( 193, 1) */
+ { 0x01b6, 0x0000, 109, 113 }, /* 107: p=0.009216 ( 1, 143) */
+ { 0x0237, 0x0000, 60, 54 }, /* 108: p=0.011925 ( 193, 2) */
+ { 0x0121, 0x0000, 65, 111 }, /* 109: p=0.006097 ( 1, 217) */
+ { 0x035b, 0x0000, 56, 48 }, /* 110: p=0.017995 ( 127, 2) */
+ { 0x01f9, 0x0000, 59, 53 }, /* 111: p=0.010622 ( 2, 217) */
+ { 0x05de, 0x0000, 114, 130 }, /* 112: p=0.031249 ( 41, 1) */
+ { 0x02fc, 0x0000, 55, 49 }, /* 113: p=0.016018 ( 2, 143) */
+ { 0x03e9, 0x0000, 116, 128 }, /* 114: p=0.020942 ( 62, 1) */
+ { 0x0484, 0x0000, 51, 45 }, /* 115: p=0.024138 ( 2, 94) */
+ { 0x0298, 0x0000, 118, 126 }, /* 116: p=0.013937 ( 94, 1) */
+ { 0x06ca, 0x0000, 47, 39 }, /* 117: p=0.036082 ( 2, 62) */
+ { 0x01b6, 0x0000, 120, 124 }, /* 118: p=0.009216 ( 143, 1) */
+ { 0x0a27, 0x0000, 41, 121 }, /* 119: p=0.053434 ( 2, 41) */
+ { 0x0121, 0x0000, 66, 122 }, /* 120: p=0.006097 ( 217, 1) */
+ { 0x0e57, 0x0000, 37, 31 }, /* 121: p=0.074626 ( 3, 41) */
+ { 0x01f9, 0x0000, 60, 54 }, /* 122: p=0.010622 ( 217, 2) */
+ { 0x0f25, 0x0000, 37, 29 }, /* 123: p=0.078651 ( 2, 27) */
+ { 0x02fc, 0x0000, 56, 50 }, /* 124: p=0.016018 ( 143, 2) */
+ { 0x1629, 0x0000, 33, 127 }, /* 125: p=0.112902 ( 2, 18) */
+ { 0x0484, 0x0000, 52, 46 }, /* 126: p=0.024138 ( 94, 2) */
+ { 0x1ee8, 0x0000, 27, 21 }, /* 127: p=0.153845 ( 3, 18) */
+ { 0x06ca, 0x0000, 48, 40 }, /* 128: p=0.036082 ( 62, 2) */
+ { 0x200f, 0x0000, 27, 19 }, /* 129: p=0.159089 ( 2, 12) */
+ { 0x0a27, 0x0000, 42, 132 }, /* 130: p=0.053434 ( 41, 2) */
+ { 0x2dae, 0x0000, 21, 15 }, /* 131: p=0.218748 ( 2, 8) */
+ { 0x0e57, 0x0000, 38, 32 }, /* 132: p=0.074626 ( 41, 3) */
+ { 0x4320, 0x0000, 15, 7 }, /* 133: p=0.304346 ( 2, 5) */
+ { 0x11a0, 0x0000, 136, 164 }, /* 134: p=0.090907 ( 13, 1) */
+ { 0x620b, 0x0000, 9, 85 }, /* 135: p=0.411764 ( 2, 3) */
+ { 0x0bbe, 0x0000, 138, 162 }, /* 136: p=0.061537 ( 20, 1) */
+ { 0x8000, 0x0000, 135, 248 }, /* 137: p=0.500000 ( 2, 2) */
+ { 0x07f3, 0x0000, 140, 160 }, /* 138: p=0.042104 ( 30, 1) */
+ { 0x294a, 0x0000, 141, 247 }, /* 139: p=0.199988 ( 0, 1) */
+ { 0x053e, 0x0000, 142, 158 }, /* 140: p=0.027971 ( 46, 1) */
+ { 0x0db3, 0x0000, 143, 199 }, /* 141: p=0.071422 ( 0, 4) */
+ { 0x0378, 0x0000, 144, 156 }, /* 142: p=0.018604 ( 70, 1) */
+ { 0x0490, 0x0000, 145, 167 }, /* 143: p=0.024388 ( 0, 13) */
+ { 0x024d, 0x0000, 146, 154 }, /* 144: p=0.012384 ( 106, 1) */
+ { 0x017c, 0x0000, 147, 101 }, /* 145: p=0.007999 ( 0, 41) */
+ { 0x0185, 0x0000, 148, 152 }, /* 146: p=0.008197 ( 161, 1) */
+ { 0x007c, 0x0000, 149, 159 }, /* 147: p=0.002611 ( 0, 127) */
+ { 0x0100, 0x0000, 68, 150 }, /* 148: p=0.005405 ( 245, 1) */
+ { 0x0028, 0x0000, 151, 155 }, /* 149: p=0.000849 ( 0, 392) */
+ { 0x01c0, 0x0000, 62, 56 }, /* 150: p=0.009421 ( 245, 2) */
+ { 0x000d, 0x0000, 81, 153 }, /* 151: p=0.000276 ( 0, 1208) */
+ { 0x02a7, 0x0000, 58, 52 }, /* 152: p=0.014256 ( 161, 2) */
+ { 0x0034, 0x0000, 75, 71 }, /* 153: p=0.001102 ( 1, 1208) */
+ { 0x0403, 0x0000, 54, 46 }, /* 154: p=0.021472 ( 106, 2) */
+ { 0x00a0, 0x0000, 69, 157 }, /* 155: p=0.003387 ( 1, 392) */
+ { 0x0608, 0x0000, 48, 42 }, /* 156: p=0.032110 ( 70, 2) */
+ { 0x0118, 0x0000, 65, 59 }, /* 157: p=0.005912 ( 2, 392) */
+ { 0x0915, 0x0000, 44, 38 }, /* 158: p=0.047945 ( 46, 2) */
+ { 0x01ed, 0x0000, 161, 165 }, /* 159: p=0.010362 ( 1, 127) */
+ { 0x0db4, 0x0000, 40, 32 }, /* 160: p=0.071428 ( 30, 2) */
+ { 0x0145, 0x0000, 65, 163 }, /* 161: p=0.006849 ( 1, 193) */
+ { 0x1417, 0x0000, 34, 26 }, /* 162: p=0.102940 ( 20, 2) */
+ { 0x0237, 0x0000, 59, 53 }, /* 163: p=0.011925 ( 2, 193) */
+ { 0x1dd6, 0x0000, 30, 166 }, /* 164: p=0.148935 ( 13, 2) */
+ { 0x035b, 0x0000, 55, 47 }, /* 165: p=0.017995 ( 2, 127) */
+ { 0x294a, 0x0000, 24, 18 }, /* 166: p=0.199999 ( 13, 3) */
+ { 0x11a0, 0x0000, 169, 195 }, /* 167: p=0.090907 ( 1, 13) */
+ { 0x31a3, 0x0000, 170, 212 }, /* 168: p=0.235291 ( 4, 1) */
+ { 0x0bbe, 0x0000, 171, 193 }, /* 169: p=0.061537 ( 1, 20) */
+ { 0x235a, 0x0000, 172, 208 }, /* 170: p=0.173910 ( 6, 1) */
+ { 0x07f3, 0x0000, 173, 191 }, /* 171: p=0.042104 ( 1, 30) */
+ { 0x18b3, 0x0000, 174, 206 }, /* 172: p=0.124998 ( 9, 1) */
+ { 0x053e, 0x0000, 175, 189 }, /* 173: p=0.027971 ( 1, 46) */
+ { 0x1073, 0x0000, 176, 204 }, /* 174: p=0.085105 ( 14, 1) */
+ { 0x0378, 0x0000, 177, 187 }, /* 175: p=0.018604 ( 1, 70) */
+ { 0x0b35, 0x0000, 178, 200 }, /* 176: p=0.058822 ( 21, 1) */
+ { 0x024d, 0x0000, 179, 185 }, /* 177: p=0.012384 ( 1, 106) */
+ { 0x0778, 0x0000, 180, 198 }, /* 178: p=0.039603 ( 32, 1) */
+ { 0x0185, 0x0000, 181, 183 }, /* 179: p=0.008197 ( 1, 161) */
+ { 0x04ed, 0x0000, 182, 194 }, /* 180: p=0.026315 ( 49, 1) */
+ { 0x0100, 0x0000, 67, 59 }, /* 181: p=0.005405 ( 1, 245) */
+ { 0x0349, 0x0000, 184, 192 }, /* 182: p=0.017621 ( 74, 1) */
+ { 0x02a7, 0x0000, 57, 51 }, /* 183: p=0.014256 ( 2, 161) */
+ { 0x022e, 0x0000, 186, 190 }, /* 184: p=0.011730 ( 112, 1) */
+ { 0x0403, 0x0000, 53, 45 }, /* 185: p=0.021472 ( 2, 106) */
+ { 0x0171, 0x0000, 64, 188 }, /* 186: p=0.007767 ( 170, 1) */
+ { 0x0608, 0x0000, 47, 41 }, /* 187: p=0.032110 ( 2, 70) */
+ { 0x0283, 0x0000, 58, 52 }, /* 188: p=0.013513 ( 170, 2) */
+ { 0x0915, 0x0000, 43, 37 }, /* 189: p=0.047945 ( 2, 46) */
+ { 0x03cc, 0x0000, 54, 48 }, /* 190: p=0.020349 ( 112, 2) */
+ { 0x0db4, 0x0000, 39, 31 }, /* 191: p=0.071428 ( 2, 30) */
+ { 0x05b6, 0x0000, 50, 42 }, /* 192: p=0.030434 ( 74, 2) */
+ { 0x1417, 0x0000, 33, 25 }, /* 193: p=0.102940 ( 2, 20) */
+ { 0x088a, 0x0000, 44, 196 }, /* 194: p=0.045161 ( 49, 2) */
+ { 0x1dd6, 0x0000, 29, 197 }, /* 195: p=0.148935 ( 2, 13) */
+ { 0x0c16, 0x0000, 40, 34 }, /* 196: p=0.063291 ( 49, 3) */
+ { 0x294a, 0x0000, 23, 17 }, /* 197: p=0.199999 ( 3, 13) */
+ { 0x0ce2, 0x0000, 40, 32 }, /* 198: p=0.067307 ( 32, 2) */
+ { 0x31a3, 0x0000, 201, 243 }, /* 199: p=0.235291 ( 1, 4) */
+ { 0x1332, 0x0000, 36, 202 }, /* 200: p=0.098590 ( 21, 2) */
+ { 0x235a, 0x0000, 203, 239 }, /* 201: p=0.173910 ( 1, 6) */
+ { 0x1adc, 0x0000, 30, 24 }, /* 202: p=0.135134 ( 21, 3) */
+ { 0x18b3, 0x0000, 205, 237 }, /* 203: p=0.124998 ( 1, 9) */
+ { 0x1be7, 0x0000, 30, 22 }, /* 204: p=0.139999 ( 14, 2) */
+ { 0x1073, 0x0000, 207, 235 }, /* 205: p=0.085105 ( 1, 14) */
+ { 0x294a, 0x0000, 26, 16 }, /* 206: p=0.199998 ( 9, 2) */
+ { 0x0b35, 0x0000, 209, 231 }, /* 207: p=0.058822 ( 1, 21) */
+ { 0x3a07, 0x0000, 20, 210 }, /* 208: p=0.269229 ( 6, 2) */
+ { 0x0778, 0x0000, 211, 229 }, /* 209: p=0.039603 ( 1, 32) */
+ { 0x4e30, 0x0000, 14, 8 }, /* 210: p=0.344827 ( 6, 3) */
+ { 0x04ed, 0x0000, 213, 225 }, /* 211: p=0.026315 ( 1, 49) */
+ { 0x4fa6, 0x0000, 14, 214 }, /* 212: p=0.349998 ( 4, 2) */
+ { 0x0349, 0x0000, 215, 223 }, /* 213: p=0.017621 ( 1, 74) */
+ { 0x6966, 0x0000, 8, 2 }, /* 214: p=0.434782 ( 4, 3) */
+ { 0x022e, 0x0000, 217, 221 }, /* 215: p=0.011730 ( 1, 112) */
+ { 0x8000, 0x0000, 218, 87 }, /* 216: p=0.500000 ( 1, 1) */
+ { 0x0171, 0x0000, 63, 219 }, /* 217: p=0.007767 ( 1, 170) */
+ { 0x538e, 0x0000, 220, 246 }, /* 218: p=0.363634 ( 2, 1) */
+ { 0x0283, 0x0000, 57, 51 }, /* 219: p=0.013513 ( 2, 170) */
+ { 0x3e3e, 0x0000, 222, 244 }, /* 220: p=0.285711 ( 3, 1) */
+ { 0x03cc, 0x0000, 53, 47 }, /* 221: p=0.020349 ( 2, 112) */
+ { 0x294a, 0x0000, 224, 242 }, /* 222: p=0.199997 ( 5, 1) */
+ { 0x05b6, 0x0000, 49, 41 }, /* 223: p=0.030434 ( 2, 74) */
+ { 0x1b75, 0x0000, 226, 240 }, /* 224: p=0.137929 ( 8, 1) */
+ { 0x088a, 0x0000, 43, 227 }, /* 225: p=0.045161 ( 2, 49) */
+ { 0x12fc, 0x0000, 228, 238 }, /* 226: p=0.097559 ( 12, 1) */
+ { 0x0c16, 0x0000, 39, 33 }, /* 227: p=0.063291 ( 3, 49) */
+ { 0x0cfb, 0x0000, 230, 234 }, /* 228: p=0.067795 ( 18, 1) */
+ { 0x0ce2, 0x0000, 39, 31 }, /* 229: p=0.067307 ( 2, 32) */
+ { 0x08cd, 0x0000, 112, 232 }, /* 230: p=0.046511 ( 27, 1) */
+ { 0x1332, 0x0000, 35, 233 }, /* 231: p=0.098590 ( 2, 21) */
+ { 0x0f25, 0x0000, 38, 30 }, /* 232: p=0.078651 ( 27, 2) */
+ { 0x1adc, 0x0000, 29, 23 }, /* 233: p=0.135134 ( 3, 21) */
+ { 0x1629, 0x0000, 34, 236 }, /* 234: p=0.112902 ( 18, 2) */
+ { 0x1be7, 0x0000, 29, 21 }, /* 235: p=0.139999 ( 2, 14) */
+ { 0x1ee8, 0x0000, 28, 22 }, /* 236: p=0.153845 ( 18, 3) */
+ { 0x294a, 0x0000, 25, 15 }, /* 237: p=0.199998 ( 2, 9) */
+ { 0x200f, 0x0000, 28, 20 }, /* 238: p=0.159089 ( 12, 2) */
+ { 0x3a07, 0x0000, 19, 241 }, /* 239: p=0.269229 ( 2, 6) */
+ { 0x2dae, 0x0000, 22, 16 }, /* 240: p=0.218748 ( 8, 2) */
+ { 0x4e30, 0x0000, 13, 7 }, /* 241: p=0.344827 ( 3, 6) */
+ { 0x4320, 0x0000, 16, 8 }, /* 242: p=0.304346 ( 5, 2) */
+ { 0x4fa6, 0x0000, 13, 245 }, /* 243: p=0.349998 ( 2, 4) */
+ { 0x620b, 0x0000, 10, 2 }, /* 244: p=0.411764 ( 3, 2) */
+ { 0x6966, 0x0000, 7, 1 }, /* 245: p=0.434782 ( 3, 4) */
+ { 0x8000, 0x0000, 244, 83 }, /* 246: p=0.500000 ( 2, 2) */
+ { 0x8000, 0x0000, 249, 250 }, /* 247: p=0.500000 ( 1, 1) */
+ { 0x620b, 0x0000, 10, 2 }, /* 248: p=0.411764 ( 3, 2) */
+ { 0x538e, 0x0000, 89, 137 }, /* 249: p=0.363634 ( 1, 2) */
+ { 0x538e, 0x0000, 220, 246 }, /* 250: p=0.363634 ( 2, 1) */
+#endif
+};
+
+
+
+////////////////////////////////////////////////////////////////
+// CONSTRUCTOR/DESTRUCTOR
+////////////////////////////////////////////////////////////////
+
+class ZPCodec::Encode : public ZPCodec
+{
+public:
+ Encode(GP<ByteStream> gbs, const bool djvucompat);
+ virtual ~Encode();
+private:
+ void init(void);
+};
+
+ZPCodec::Encode::Encode(GP<ByteStream> gbs, const bool djvucompat)
+: ZPCodec(gbs,true,djvucompat)
+{
+ init();
+ // Codebit counter
+#ifdef ZPCODEC_BITCOUNT
+ bitcount = 0;
+#endif
+}
+
+ZPCodec::Encode::~Encode()
+{
+ eflush();
+}
+
+class ZPCodec::Decode : public ZPCodec
+{
+public:
+ Decode(GP<ByteStream> gbs, const bool djvucompat);
+ virtual ~Decode();
+private:
+ void init(void);
+};
+
+ZPCodec::Decode::Decode(GP<ByteStream> gbs, const bool djvucompat)
+: ZPCodec(gbs,false,djvucompat)
+{
+ init();
+ // Codebit counter
+#ifdef ZPCODEC_BITCOUNT
+ bitcount = 0;
+#endif
+}
+
+ZPCodec::Decode::~Decode() {}
+
+ZPCodec::ZPCodec(GP<ByteStream> xgbs, const bool xencoding, const bool djvucompat)
+: gbs(xgbs), bs(xgbs), encoding(xencoding), fence(0), subend(0), buffer(0), nrun(0)
+{
+ // Create machine independent ffz table
+ for (int i=0; i<256; i++)
+ {
+ ffzt[i]=0;
+ for (int j=i; j&0x80; j<<=1)
+ ffzt[i] += 1;
+ }
+ // Initialize table
+ newtable(default_ztable);
+ // Patch table table (and lose DjVu compatibility).
+ if (!djvucompat)
+ {
+ for (int j=0; j<256; j++)
+ {
+ unsigned short a = 0x10000-p[j];
+ while (a>=0x8000) a=(unsigned short)(a<<1);
+ if (m[j]>0 && a+p[j]>=0x8000 && a>=m[j])
+ {
+ BitContext x = default_ztable[j].dn;
+ BitContext y = default_ztable[x].dn;
+ dn[j] = y;
+ }
+ }
+ }
+}
+
+ZPCodec::~ZPCodec() {}
+
+GP<ZPCodec>
+ZPCodec::create(GP<ByteStream> gbs, const bool encoding, const bool djvucompat)
+{
+ GP<ZPCodec> retval;
+ if(encoding)
+ {
+ retval=new ZPCodec::Encode(gbs,djvucompat);
+ }else
+ {
+ retval=new ZPCodec::Decode(gbs,djvucompat);
+ }
+ return retval;
+}
+
+////////////////////////////////////////////////////////////////
+// Z CODER DECODE ALGORITHM
+////////////////////////////////////////////////////////////////
+
+
+
+void
+ZPCodec::Decode::init(void)
+{
+ assert(sizeof(unsigned int)==4);
+ assert(sizeof(unsigned short)==2);
+ a = 0;
+ /* Read first 16 bits of code */
+ if (! bs->read((void*)&byte, 1))
+ byte = 0xff;
+ code = (byte<<8);
+ if (! bs->read((void*)&byte, 1))
+ byte = 0xff;
+ code = code | byte;
+ /* Preload buffer */
+ delay = 25;
+ scount = 0;
+ preload();
+ /* Compute initial fence */
+ fence = code;
+ if (code >= 0x8000)
+ fence = 0x7fff;
+}
+
+
+void
+ZPCodec::preload(void)
+{
+ while (scount<=24)
+ {
+ if (bs->read((void*)&byte, 1) < 1)
+ {
+ byte = 0xff;
+ if (--delay < 1)
+ G_THROW( ByteStream::EndOfFile );
+ }
+ buffer = (buffer<<8) | byte;
+ scount += 8;
+ }
+}
+
+
+inline int
+ZPCodec::ffz(unsigned int x)
+{
+ // DO NOT DEFINE FASTBSR :
+ // Test shows that it hardly helps on a PPro,
+ // and rumors are that BSR is very slow on PPlain.
+#if defined(FASTBSR) && defined(_MSC_VER) && defined(_M_IX86)
+ int r;
+ __asm {
+ mov ebx, x
+ xor ebx, 0xffff
+ mov eax, -1
+ bsr eax, ebx
+ mov r, eax
+ }
+ return 15 - r;
+#elif defined(FASTBSR) && defined(__GNUC__) && defined(__i386__)
+ int r, dummy;
+ __asm__ const ( "movl %2,%1\n\t"
+ "xorl $0xffff, %1\n\t"
+ "movl $-1, %0\n\t"
+ "bsrl %1, %0"
+ : "=&q" (r), "=q" (dummy) : "rm" (x) );
+ return 15 - r;
+#else
+ return (x>=0xff00) ? (ffzt[x&0xff]+8) : (ffzt[(x>>8)&0xff]);
+#endif
+}
+
+
+int
+ZPCodec::decode_sub(BitContext &ctx, unsigned int z)
+{
+ /* Save bit */
+ int bit = (ctx & 1);
+ /* Avoid interval reversion */
+#ifdef ZPCODER
+ unsigned int d = 0x6000 + ((z+a)>>2);
+ if (z > d)
+ z = d;
+#endif
+#ifdef ZCODER
+ if (z >= 0x8000)
+ z = 0x4000 + (z>>1);
+#endif
+ /* Test MPS/LPS */
+ if (z > code)
+ {
+ /* LPS branch */
+ z = 0x10000 - z;
+ a = a + z;
+ code = code + z;
+ /* LPS adaptation */
+ ctx = dn[ctx];
+ /* LPS renormalization */
+ int shift = ffz(a);
+ scount -= shift;
+ a = (unsigned short)(a<<shift);
+ code = (unsigned short)(code<<shift) | ((buffer>>scount) & ((1<<shift)-1));
+#ifdef ZPCODEC_BITCOUNT
+ bitcount += shift;
+#endif
+ if (scount<16) preload();
+ /* Adjust fence */
+ fence = code;
+ if (code >= 0x8000)
+ fence = 0x7fff;
+ return bit ^ 1;
+ }
+ else
+ {
+ /* MPS adaptation */
+ if (a >= m[ctx])
+ ctx = up[ctx];
+ /* MPS renormalization */
+ scount -= 1;
+ a = (unsigned short)(z<<1);
+ code = (unsigned short)(code<<1) | ((buffer>>scount) & 1);
+#ifdef ZPCODEC_BITCOUNT
+ bitcount += 1;
+#endif
+ if (scount<16) preload();
+ /* Adjust fence */
+ fence = code;
+ if (code >= 0x8000)
+ fence = 0x7fff;
+ return bit;
+ }
+}
+
+
+int
+ZPCodec::decode_sub_simple(int mps, unsigned int z)
+{
+ /* Test MPS/LPS */
+ if (z > code)
+ {
+ /* LPS branch */
+ z = 0x10000 - z;
+ a = a + z;
+ code = code + z;
+ /* LPS renormalization */
+ int shift = ffz(a);
+ scount -= shift;
+ a = (unsigned short)(a<<shift);
+ code = (unsigned short)(code<<shift) | ((buffer>>scount) & ((1<<shift)-1));
+#ifdef ZPCODEC_BITCOUNT
+ bitcount += shift;
+#endif
+ if (scount<16) preload();
+ /* Adjust fence */
+ fence = code;
+ if (code >= 0x8000)
+ fence = 0x7fff;
+ return mps ^ 1;
+ }
+ else
+ {
+ /* MPS renormalization */
+ scount -= 1;
+ a = (unsigned short)(z<<1);
+ code = (unsigned short)(code<<1) | ((buffer>>scount) & 1);
+#ifdef ZPCODEC_BITCOUNT
+ bitcount += 1;
+#endif
+ if (scount<16) preload();
+ /* Adjust fence */
+ fence = code;
+ if (code >= 0x8000)
+ fence = 0x7fff;
+ return mps;
+ }
+}
+
+
+int
+ZPCodec::decode_sub_nolearn(int mps, unsigned int z)
+{
+#ifdef ZPCODER
+ unsigned int d = 0x6000 + ((z+a)>>2);
+ if (z > d)
+ z = d;
+#endif
+#ifdef ZCODER
+ if (z >= 0x8000)
+ z = 0x4000 + (z>>1);
+#endif
+ /* Test MPS/LPS */
+ if (z > code)
+ {
+ /* LPS branch */
+ z = 0x10000 - z;
+ a = a + z;
+ code = code + z;
+ /* LPS renormalization */
+ int shift = ffz(a);
+ scount -= shift;
+ a = (unsigned short)(a<<shift);
+ code = (unsigned short)(code<<shift) | ((buffer>>scount) & ((1<<shift)-1));
+#ifdef ZPCODEC_BITCOUNT
+ bitcount += shift;
+#endif
+ if (scount<16) preload();
+ /* Adjust fence */
+ fence = code;
+ if (code >= 0x8000)
+ fence = 0x7fff;
+ return mps ^ 1;
+ }
+ else
+ {
+ /* MPS renormalization */
+ scount -= 1;
+ a = (unsigned short)(z<<1);
+ code = (unsigned short)(code<<1) | ((buffer>>scount) & 1);
+#ifdef ZPCODEC_BITCOUNT
+ bitcount += 1;
+#endif
+ if (scount<16) preload();
+ /* Adjust fence */
+ fence = code;
+ if (code >= 0x8000)
+ fence = 0x7fff;
+ return mps;
+ }
+}
+
+
+
+
+
+////////////////////////////////////////////////////////////////
+// Z CODER ENCODE ALGORITHM
+////////////////////////////////////////////////////////////////
+
+
+
+
+void
+ZPCodec::Encode::init(void)
+{
+ assert(sizeof(unsigned int)==4);
+ assert(sizeof(unsigned short)==2);
+ a = 0;
+ scount = 0;
+ byte = 0;
+ delay = 25;
+ subend = 0;
+ buffer = 0xffffff;
+ nrun = 0;
+}
+
+void
+ZPCodec::outbit(int bit)
+{
+ if (delay > 0)
+ {
+ if (delay < 0xff) // delay=0xff suspends emission forever
+ delay -= 1;
+ }
+ else
+ {
+ /* Insert a bit */
+ byte = (byte<<1) | bit;
+ /* Output a byte */
+ if (++scount == 8)
+ {
+ if (!encoding)
+ G_THROW( ERR_MSG("ZPCodec.no_encoding") );
+ if (bs->write((void*)&byte, 1) != 1)
+ G_THROW( ERR_MSG("ZPCodec.write_error") );
+ scount = 0;
+ byte = 0;
+ }
+ }
+}
+
+void
+ZPCodec::zemit(int b)
+{
+ /* Shift new bit into 3bytes buffer */
+ buffer = (buffer<<1) + b;
+ /* Examine bit going out of the 3bytes buffer */
+ b = (buffer >> 24);
+ buffer = (buffer & 0xffffff);
+ /* The following lines have been changed in order to emphazise the
+ * similarity between this bit counting and the scheme of Witten, Neal & Cleary
+ * (WN&C). Corresponding changes have been made in outbit and eflush.
+ * Variable 'nrun' is similar to the 'bits_to_follow' in the W&N code.
+ */
+ switch(b)
+ {
+ /* Similar to WN&C upper renormalization */
+ case 1:
+ outbit(1);
+ while (nrun-- > 0)
+ outbit(0);
+ nrun = 0;
+ break;
+ /* Similar to WN&C lower renormalization */
+ case 0xff:
+ outbit(0);
+ while (nrun-- > 0)
+ outbit(1);
+ nrun = 0;
+ break;
+ /* Similar to WN&C central renormalization */
+ case 0:
+ nrun += 1;
+ break;
+ default:
+ assert(0);
+ }
+ /* Code bit counter */
+#ifdef ZPCODEC_BITCOUNT
+ bitcount += 1;
+#endif
+}
+
+void
+ZPCodec::eflush()
+{
+ /* adjust subend */
+ if (subend > 0x8000)
+ subend = 0x10000;
+ else if (subend > 0)
+ subend = 0x8000;
+ /* zemit many mps bits */
+ while (buffer != 0xffffff || subend )
+ {
+ zemit(1 - (subend>>15) );
+ subend = (unsigned short)(subend<<1);
+ }
+ /* zemit pending run */
+ outbit(1);
+ while (nrun-- > 0)
+ outbit(0);
+ nrun = 0;
+ /* zemit 1 until full byte */
+ while (scount > 0)
+ outbit(1);
+ /* prevent further emission */
+ delay = 0xff;
+}
+
+void
+ZPCodec::encode_mps(BitContext &ctx, unsigned int z)
+{
+ /* Avoid interval reversion */
+#ifdef ZPCODER
+ unsigned int d = 0x6000 + ((z+a)>>2);
+ if (z > d)
+ z = d;
+#endif
+#ifdef ZCODER
+ if (z >= 0x8000)
+ z = 0x4000 + (z>>1);
+#endif
+ /* Adaptation */
+ if (a >= m[ctx])
+ ctx = up[ctx];
+ /* Code MPS */
+ a = z;
+ /* Export bits */
+ if (a >= 0x8000)
+ {
+ zemit(1 - (subend>>15) );
+ subend = (unsigned short)(subend<<1);
+ a = (unsigned short)(a<<1);
+ }
+}
+
+
+void
+ZPCodec::encode_lps(BitContext &ctx, unsigned int z)
+{
+ /* Avoid interval reversion */
+#ifdef ZPCODER
+ unsigned int d = 0x6000 + ((z+a)>>2);
+ if (z > d)
+ z = d;
+#endif
+#ifdef ZCODER
+ if (z >= 0x8000)
+ z = 0x4000 + (z>>1);
+#endif
+ /* Adaptation */
+ ctx = dn[ctx];
+ /* Code LPS */
+ z = 0x10000 - z;
+ subend += z;
+ a += z;
+ /* Export bits */
+ while (a >= 0x8000)
+ {
+ zemit(1 - (subend>>15) );
+ subend = (unsigned short)(subend<<1);
+ a = (unsigned short)(a<<1);
+ }
+}
+
+
+void
+ZPCodec::encode_mps_simple(unsigned int z)
+{
+ /* Code MPS */
+ a = z;
+ /* Export bits */
+ if (a >= 0x8000)
+ {
+ zemit(1 - (subend>>15) );
+ subend = (unsigned short)(subend<<1);
+ a = (unsigned short)(a<<1);
+ }
+}
+
+void
+ZPCodec::encode_lps_simple(unsigned int z)
+{
+ /* Code LPS */
+ z = 0x10000 - z;
+ subend += z;
+ a += z;
+ /* Export bits */
+ while (a >= 0x8000)
+ {
+ zemit(1 - (subend>>15) );
+ subend = (unsigned short)(subend<<1);
+ a = (unsigned short)(a<<1);
+ }
+}
+
+
+void
+ZPCodec::encode_mps_nolearn(unsigned int z)
+{
+#ifdef ZPCODER
+ unsigned int d = 0x6000 + ((z+a)>>2);
+ if (z > d)
+ z = d;
+#endif
+#ifdef ZCODER
+ if (z >= 0x8000)
+ z = 0x4000 + (z>>1);
+#endif
+ /* Code MPS */
+ a = z;
+ /* Export bits */
+ if (a >= 0x8000)
+ {
+ zemit(1 - (subend>>15) );
+ subend = (unsigned short)(subend<<1);
+ a = (unsigned short)(a<<1);
+ }
+}
+
+
+void
+ZPCodec::encode_lps_nolearn(unsigned int z)
+{
+#ifdef ZPCODER
+ unsigned int d = 0x6000 + ((z+a)>>2);
+ if (z > d)
+ z = d;
+#endif
+#ifdef ZCODER
+ if (z >= 0x8000)
+ z = 0x4000 + (z>>1);
+#endif
+ /* Code LPS */
+ z = 0x10000 - z;
+ subend += z;
+ a += z;
+ /* Export bits */
+ while (a >= 0x8000)
+ {
+ zemit(1 - (subend>>15) );
+ subend = (unsigned short)(subend<<1);
+ a = (unsigned short)(a<<1);
+ }
+}
+
+
+
+
+
+
+////////////////////////////////////////////////////////////////
+// TABLE AND PARAMETER MANAGEMENT
+////////////////////////////////////////////////////////////////
+
+
+
+
+void
+ZPCodec::newtable(ZPCodec::Table *table)
+{
+ for (int i=0; i<256; i++)
+ {
+ p[i] = table[i].p;
+ m[i] = table[i].m;
+ up[i] = table[i].up;
+ dn[i] = table[i].dn;
+ }
+}
+
+static float
+p_to_plps(unsigned short p)
+{
+ float fplps;
+ float fp = (float)(p) / (float)(0x10000);
+ const float log2 = (float)0.69314718055994530942;
+#ifdef ZCODER
+ fplps = fp - (fp+0.5) * log(fp+0.5) + (fp-0.5)*log2;
+#endif
+#ifdef ZPCODER
+ if (fp <= (1.0/6.0) )
+ fplps = fp * 2 * log2;
+ else
+ fplps = (float)((1.5*fp-0.25) - (1.5*fp+0.25)*log(1.5*fp+0.25) + (0.5*fp-0.25)*log2);
+#endif
+ return fplps;
+}
+
+
+BitContext
+ZPCodec::state(float prob1)
+{
+ // Return a state representing 'prob1' in the steady chain
+ // FixMe: This is quite slow!
+ int mps = (prob1 <= 0.5 ? 0 : 1);
+ float plps = (float)(mps ? 1.0 - prob1 : prob1);
+ // Locate steady chain (ordered, decreasing)
+ int sz = 0;
+ int lo = (mps ? 1 : 2);
+ while (p[lo+sz+sz+2] < p[lo+sz+sz]) sz+=1;
+ // Bisection
+ while (sz > 1)
+ {
+ int nsz = sz >> 1;
+ float nplps = p_to_plps( p[lo+nsz+nsz] );
+ if (nplps < plps)
+ { sz=nsz; }
+ else
+ { lo=lo+nsz+nsz; sz=sz-nsz; }
+ }
+ // Choose closest one
+ float f1 = p_to_plps(p[lo])-plps;
+ float f2 = plps-p_to_plps(p[lo+2]);
+ return (f1<f2) ? lo : lo+2;
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/ZPCodec.h b/kviewshell/plugins/djvu/libdjvu/ZPCodec.h
new file mode 100644
index 00000000..4eba6901
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/ZPCodec.h
@@ -0,0 +1,747 @@
+//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: ZPCodec.h,v 1.9 2003/11/07 22:08:22 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _ZPCODEC_H
+#define _ZPCODEC_H
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+// From: Leon Bottou, 1/31/2002
+// Almost equal to my initial code.
+
+#include "GContainer.h"
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+class ByteStream;
+
+
+
+/** @name ZPCodec.h
+
+ Files #"ZPCodec.h"# and #"ZPCodec.cpp"# implement a fast binary adaptive
+ quasi-arithmetic coder named ZP-Coder. Because of its speed and
+ convenience, the ZP-Coder is used in several parts of the DjVu reference
+ library (See \Ref{BSByteStream.h}, \Ref{JB2Image.h}, \Ref{IW44Image.h}).
+ The following comments avoid the theory (see the historical remarks for
+ useful pointers) and concentrate on the user perspective on the ZP-Coder.
+
+ {\bf Introduction} ---
+ Encoding consists of transforming a sequence of {\em message bits} into a
+ sequence of {\em code bits}. Decoding consists of retrieving the message
+ bits using only the code bits. We can make the code smaller than the
+ message as soon as we can predict a message bit on the basis of a {\em
+ coding context} composed of previously encoded or decoded bits. If the
+ prediction is always correct, we do not even need to encode the message
+ bit. If the prediction is totally unreliable, we need to generate one code
+ bit in order to unambiguously specify the message bit. In other words,
+ the more reliable the prediction, the more compression we get.
+
+ The ZP-Coder handles prediction by means of {\em context variables} (see
+ \Ref{BitContext}). There must be a context variable for each possible
+ combination of context bits. Both the encoder and the decoder use same
+ context variable for coding each message bit. For instance, we can code a
+ binary image by successively coding all the pixels (the message bits) in
+ row and column order. It is reasonable to assume that each pixel can be
+ reasonably well predicted by looking at a few (say 10) neighboring pixels
+ located above and to the left of the current pixel. Since these 10 pixels
+ make 1024 combinations, we need 1024 context variables. Each pixel is
+ encoded using the context variable corresponding to the values of the 10
+ neighboring pixels. Each pixel will be decoded by specifying the same
+ context variable corresponding to the values of these 10 pixels. This is
+ possible because these 10 pixels (located above and to the left) have
+ already been decoded and therefore are known by the decoder program.
+
+ The context variables are initially set to zero, which mean that we do not
+ know yet how to predict the current message bit on the basis of the
+ context bits. While coding the message bits, the ZP-Coder automatically
+ estimates the frequencies of #0#s and #1#s coded using each context
+ variable. These frequencies actually provide a prediction (the most
+ probable bit value) and an estimation of the prediction reliability (how
+ often the prediction was correct in the past). All this statistical
+ information is stored into the context variable after coding each bit. In
+ other words, the more we code bits within a particular context, the better
+ the ZP-Coder adapts its prediction model, and the more compression we can
+ obtain.
+
+ All this adaptation works indeed because both the encoder program and the
+ decoder program are always synchronized. Both the encoder and the decoder
+ see the same message bits encoded (or decoded) with the same context
+ variables. Both the encoder and the decoder apply the same rules to
+ update the context variables and improve the predictors. Both the encoder
+ and the decoder programs use the same predictors for any given message
+ bit. The decoder could not work if this was not the case.
+
+ Just before encoding a message bit, all the context variables in the
+ encoder program contain certain values. Just before decoding this message
+ bit, all the context variables in the decoder program must contain the same
+ values as for the encoder program. This is guaranteed as long as
+ each prediction only depends on already coded bits: {\em the coding context,
+ on which the each prediction is based, must be composed of message bits which
+ have already been coded. }
+
+ {\bf Usage} ---
+ Once you know how to organize the predictions (i.e. which coding context
+ to use, how many context variables to initialize, etc.), using the
+ ZP-Coder is straightforward (see \Ref{ZPCodec Examples}):
+ \begin{itemize}
+ \item The {\em encoder program} allocates context variables and
+ initializes them to zero. It then constructs a \Ref{ZPCodec} object for
+ encoding. For each message bit, the encoder program retrieves the context
+ bits, selects a context variable on the basis of the context bits and
+ calls member function \Ref{ZPCodec::encoder} with the message bit and a
+ reference to the context variable.
+ \item The {\em decoder program} allocates context variables and
+ initializes them to zero. It then constructs a \Ref{ZPCodec} object for
+ decoding. For each message bit, the decoder program retrieves the context
+ bits, selects a context variable on the basis of the context bits and
+ calls member function \Ref{ZPCodec::decoder} with a reference to the
+ context variable. This function returns the message bit.
+ \end{itemize}
+ Functions #encoder# and #decoder# only require a few machine cycles to
+ perform two essential tasks, namely {\em coding} and {\em context
+ adaptation}. Function #decoder# often returns after two arithmetic
+ operations only. To make your program fast, you just need to feed message
+ bits and context variables fast enough.
+
+ {\bf History} --- The ZP-Coder is similar in function and performance to
+ the seminal Q-Coder (Pennebaker, Mitchell, Langdon, Arps, IBM J. Res
+ Dev. 32, 1988). An improved version of the Q-Coder, named QM-Coder, has
+ been described in certain parts of the JPEG standard. Unfortunate patent
+ policies have made these coders very difficult to use in general purpose
+ applications. The Z-Coder is constructed using a new approach based on an
+ extension of the Golomb codes (Bottou, Howard, Bengio, IEEE DCC 98, 1998
+ \URL[DjVu]{http://www.research.att.com/~leonb/DJVU/bottou-howard-bengio/}
+ \URL[PostScript]{http://www.research.att.com/~leonb/PS/bottou-howard-bengio.ps.gz})
+ This new approach does not infringe the QM-Coder patents. Unfortunately
+ the Z-Coder is dangerously close to the patented Arithmetic MEL Coder.
+ Therefore we wrote the ZP-Coder (pronounce Zee-Prime Coder) which we
+ believe is clear of legal problems. Needless to say, AT&T has patents
+ pending for both the Z-Coder and the ZP-Coder, licenced to LizardTech.
+ The good news however is that we can grant a license to use the ZP-Coder
+ in ``free software'' without further complication. See the Copyright
+ for more information.
+
+ @memo
+ Binary adaptive quasi-arithmetic coder.
+ @version
+ #$Id: ZPCodec.h,v 1.9 2003/11/07 22:08:22 leonb Exp $#
+ @author
+ L\'eon Bottou <leonb@research.att.com> */
+//@{
+
+
+/** Context variable.
+ Variables of type #BitContext# hold a single byte describing how to encode
+ or decode message bits with similar statistical properties. This single
+ byte simultaneously represents the current estimate of the bit probability
+ distribution (which is determined by the frequencies of #1#s and #0#s
+ already coded with this context) and the confidence in this estimate
+ (which determines how fast the estimate can change.)
+
+ A coding program typically allocates hundreds of context variables. Each
+ coding context is initialized to zero before encoding or decoding. Value
+ zero represents equal probabilities for #1#s and #0#s with a minimal
+ confidence and therefore a maximum adaptation speed. Each message bit is
+ encoded using a coding context determined as a function of previously
+ encoded message bits. The decoder therefore can examine the previously
+ decoded message bits and decode the current bit using the same context as
+ the encoder. This is critical for proper decoding.
+*/
+typedef unsigned char BitContext;
+
+
+/** Performs ZP-Coder encoding and decoding. A ZPCodec object must either
+ constructed for encoding or for decoding. The ZPCodec object is connected
+ with a \Ref{ByteStream} object specified at construction time. A ZPCodec
+ object constructed for decoding reads code bits from the ByteStream and
+ returns a message bit whenever function \Ref{decoder} is called. A
+ ZPCodec constructed for encoding processes the message bits provided by
+ function \Ref{encoder} and writes the corresponding code bits to
+ ByteStream #bs#.
+
+ You should never directly access a ByteStream object connected to a valid
+ ZPCodec object. The most direct way to access the ByteStream object
+ consists of using the "pass-thru" versions of functions \Ref{encoder} and
+ \Ref{decoder}.
+
+ The ByteStream object can be accessed again after the destruction of the
+ ZPCodec object. Note that the encoder always flushes its internal buffers
+ and writes a few final code bytes when the ZPCodec object is destroyed.
+ Note also that the decoder often reads a few bytes beyond the last code byte
+ written by the encoder. This lag means that you must reposition the
+ ByteStream after the destruction of the ZPCodec object and before re-using
+ the ByteStream object (see \Ref{IFFByteStream}.)
+
+ Please note also that the decoder has no way to reliably indicate the end
+ of the message bit sequence. The content of the message must be designed
+ in a way which indicates when to stop decoding. Simple ways to achieve
+ this consists of announcing the message length at the beginning (like a
+ pascal style string), or of defining a termination code (like a null
+ terminated string). */
+
+class ZPCodec : public GPEnabled {
+protected:
+ ZPCodec (GP<ByteStream> gbs, const bool encoding, const bool djvucompat=false);
+public:
+ class Encode;
+ class Decode;
+
+ /// Non-virtual destructor.
+ ~ZPCodec();
+ /** Constructs a ZP-Coder. If argument #encoding# is zero, the ZP-Coder
+ object will read code bits from the ByteStream #bs# and return a message
+ bit whenever function #decoder# is called. If flag #encoding# is set
+ the ZP-Coder object will process the message bits provided by function
+ #encoder# and write code bits to ByteStream #bs#. Optional flag
+ #djvucompat# selects a slightly less efficient adaptation table which is
+ used by the DjVu project. This is required in order to ensure the
+ bitstream compatibility. You should not use this flag unless you want
+ to decode JB2, IW44 or BZZ encoded data. */
+ static GP<ZPCodec> create(
+ GP<ByteStream> gbs, const bool encoding, const bool djvucompat=false);
+
+ /** Encodes bit #bit# using context variable #ctx#. Argument #bit# must be
+ #0# or #1#. This function should only be used with ZP-Coder objects
+ created for encoding. It may modify the contents of variable #ctx# in
+ order to perform context adaptation. */
+ void encoder(int bit, BitContext &ctx);
+
+ /** Decodes a bit using context variable #ctx#. This function should only be
+ used with ZP-Coder objects created for decoding. It may modify the
+ contents of variable #ctx# in order to perform context adaptation. */
+ int decoder(BitContext &ctx);
+
+ /** Encodes bit #bit# without compression (pass-thru encoder). Argument
+ #bit# must be #0# or #1#. No compression will be applied. Calling this
+ function always increases the length of the code bit sequence by one
+ bit. */
+ void encoder(int bit);
+
+ /** Decodes a bit without compression (pass-thru decoder). This function
+ retrieves bits encoded with the pass-thru encoder. */
+ int decoder(void);
+#ifdef ZPCODEC_BITCOUNT
+ /** Counter for code bits (requires #-DZPCODEC_BITCOUNT#). This member
+ variable is available when the ZP-Coder is compiled with option
+ #-DZPCODEC_BITCOUNT#. Variable #bitcount# counts the number of code
+ bits processed by the coder since the construction of the object. This
+ variable can be used to evaluate how many code bits are spent on various
+ components of the message. */
+ int bitcount;
+#endif
+ // Table management (advanced stuff)
+ struct Table {
+ unsigned short p;
+ unsigned short m;
+ BitContext up;
+ BitContext dn;
+ };
+ void newtable(ZPCodec::Table *table);
+ BitContext state(float prob1);
+ // Non-adaptive encoder/decoder
+ void encoder_nolearn(int pix, BitContext &ctx);
+ int decoder_nolearn(BitContext &ctx);
+ inline int IWdecoder(void);
+ inline void IWencoder(const bool bit);
+protected:
+ // coder status
+ GP<ByteStream> gbs; // Where the data goes/comes from
+ ByteStream *bs; // Where the data goes/comes from
+ const bool encoding; // Direction (0=decoding, 1=encoding)
+ unsigned char byte;
+ unsigned char scount;
+ unsigned char delay;
+ unsigned int a;
+ unsigned int code;
+ unsigned int fence;
+ unsigned int subend;
+ unsigned int buffer;
+ unsigned int nrun;
+ // table
+ unsigned int p[256];
+ unsigned int m[256];
+ BitContext up[256];
+ BitContext dn[256];
+ // machine independent ffz
+ char ffzt[256];
+ // encoder private
+ void einit (void);
+ void eflush (void);
+ void outbit(int bit);
+ void zemit(int b);
+ void encode_mps(BitContext &ctx, unsigned int z);
+ void encode_lps(BitContext &ctx, unsigned int z);
+ void encode_mps_simple(unsigned int z);
+ void encode_lps_simple(unsigned int z);
+ void encode_mps_nolearn(unsigned int z);
+ void encode_lps_nolearn(unsigned int z);
+ // decoder private
+ void dinit(void);
+ void preload(void);
+ int ffz(unsigned int x);
+ int decode_sub(BitContext &ctx, unsigned int z);
+ int decode_sub_simple(int mps, unsigned int z);
+ int decode_sub_nolearn(int mps, unsigned int z);
+private:
+ // no copy allowed (hate c++)
+ ZPCodec(const ZPCodec&);
+ ZPCodec& operator=(const ZPCodec&);
+#ifdef ZPCODEC_FRIEND
+ friend ZPCODEC_FRIEND;
+#endif
+};
+
+
+
+
+
+
+// INLINE CODE
+
+inline void
+ZPCodec::encoder(int bit, BitContext &ctx)
+{
+ unsigned int z = a + p[ctx];
+ if (bit != (ctx & 1))
+ {
+ encode_lps(ctx, z);
+ }else if (z >= 0x8000)
+ {
+ encode_mps(ctx, z);
+ }else
+ {
+ a = z;
+ }
+}
+
+inline int
+ZPCodec::IWdecoder(void)
+{
+ return decode_sub_simple(0,0x8000 + ((a+a+a) >> 3));
+}
+
+inline int
+ZPCodec::decoder(BitContext &ctx)
+{
+ unsigned int z = a + p[ctx];
+ if (z <= fence)
+ { a = z; return (ctx&1); }
+ return decode_sub(ctx, z);
+}
+
+inline void
+ZPCodec::encoder_nolearn(int bit, BitContext &ctx)
+{
+ unsigned int z = a + p[ctx];
+ if (bit != (ctx & 1))
+ encode_lps_nolearn(z);
+ else if (z >= 0x8000)
+ encode_mps_nolearn(z);
+ else
+ a = z;
+}
+
+inline int
+ZPCodec::decoder_nolearn(BitContext &ctx)
+{
+ unsigned int z = a + p[ctx];
+ if (z <= fence)
+ { a = z; return (ctx&1); }
+ return decode_sub_nolearn( (ctx&1), z);
+}
+
+inline void
+ZPCodec::encoder(int bit)
+{
+ if (bit)
+ encode_lps_simple(0x8000 + (a>>1));
+ else
+ encode_mps_simple(0x8000 + (a>>1));
+}
+
+inline int
+ZPCodec::decoder(void)
+{
+ return decode_sub_simple(0, 0x8000 + (a>>1));
+}
+
+inline void
+ZPCodec::IWencoder(const bool bit)
+{
+ const int z = 0x8000 + ((a+a+a) >> 3);
+ if (bit)
+ {
+ encode_lps_simple(z);
+ }else
+ {
+ encode_mps_simple(z);
+ }
+}
+
+// ------------ ADDITIONAL DOCUMENTATION
+
+/** @name ZPCodec Examples
+
+ Binary adaptive coders are efficient and very flexible. Unfortunate
+ intellectual property issues however have limited their popularity. As a
+ consequence, few programmers have a direct experience of using such a
+ coding device. The few examples provided in this section demonstrate how
+ we think the ZP-Coder should be used.
+
+ {\bf Encoding Multivalued Symbols} ---
+ Since the ZP-Coder is a strictly binary coder, every message must be
+ reduced to a sequence of bits (#0#s or #1#s). It is often convenient to
+ consider that a message is a sequence of symbols taking more than two
+ values. For instance, a character string may be a sequence of bytes, and
+ each byte can take 256 values. Each byte of course is composed of eight
+ bits that we can encode in sequence. The real issue however consists of
+ deciding how we will use context variables in order to let the ZP-Coder
+ learn the probability distribution of the byte values.
+
+ The most significant bit #b0# decides whether the byte is in range 0..127
+ or in range 128..255. We let the ZP-Coder learn how to predict this bit
+ by allocating one context variable for it. The second most significant
+ byte #b1# has two distinct meanings depending of bit #b0#. If bit #b0# is
+ #0#, bit #b1# decides whether the byte is in range 0..63 or 64..127. If
+ bit #b0# is #1#, bit #b1# decides whether the byte is in range 128..191 or
+ 192..255. The prediction for bit #b1# must therefore depend on the value
+ of #b0#. This is why we will allocate two context variables for this bit.
+ If bit #b0# is #0#, we will use the first variable; if bit #b0# is #1#, we
+ will use the second variable. The next bit #b2# has four meanings and
+ therefore we will use four context variables, etc. This analysis leads to
+ a total of #1+2+4+...+128# = #255# context variables for encoding one
+ byte. This encoding procedure can be understood as a binary decision
+ tree with a dedicated context variable for predicting each decision.
+ \begin{verbatim}
+ [>=128]----n---[>=64?]----n----[>31?] ...
+ \ `---y----[>95?] ...
+ \
+ `--y---[>=192?]----n---[>=160?] ...
+ `---y---[>=224?] ...
+ \end{verbatim}
+ The following decoding function illustrates a very compact way to
+ implement such a decision tree. Argument #ctx# points to an array of 255
+ #BitContext# variables. Macro #REPEAT8# is a shorthand notation for eight
+ repetitions of its argument.
+ \begin{verbatim}
+ int decode_8_bits(ZPCodec &zp, BitContext *ctx )
+ {
+ int n = 1;
+ REPEAT8( { n = (n<<1) | (zp.decoder(ctx[n-1])); } );
+ return n & 0xff;
+ }
+ \end{verbatim}
+ The binary representation of variable #n# is always composed of a #1#
+ followed by whichever bits have been decoded so far. This extra bit #1# in
+ fact is a nice trick to flatten out the tree structure and directly
+ address the array of context variables. Bit #b0# is decoded using the
+ first context variable since #n# is initially #1#. Bit #b1# is decoded
+ using one of the next two variables in the array, since #n# is either #2#
+ (#10# in binary) or #3# (#11# in binary). Bit #b2# will be decoded using
+ one of the next four variables, since #n# ranges from #4# (#100# in
+ binary) to #7# (#111# in binary). The final result is given by removing
+ the extra #1# in variable #n#.
+
+ The corresponding encoding function is almost as compact. Argument #ctx#
+ again is an array of 255 #BitContext# variables. Each bit of byte #x# is
+ encoded and shifted into variable #n# as in the decoding function.
+ Variable #x# in fact contains the bits to be encoded. Variable #n#
+ contains a #1# followed by the already encoded bits.
+ \begin{verbatim}
+ void encode_8_bits(ZPCodec &zp, int x, BitContext *ctx )
+ {
+ int n = 1;
+ REPEAT8( { int b=((x&0x80)?1:0); x=(x<<1);
+ zp.encoder(b,ctx[n-1]); n=(n<<1)|(b); } );
+ }
+ \end{verbatim}
+ The ZP-Coder automatically adjusts the content of the context variables
+ while coding (recall the context variable argument is passed to functions
+ #encoder# and #decoder# by reference). The whole array of 255 context
+ variables can be understood as a "byte context variable". The estimated
+ probability of each byte value is indeed the product of the estimated
+ probabilities of the eight binary decisions that lead to that value in the
+ decision tree. All these probabilities are adapted by the underlying
+ adaptation algorithm of the ZP-Coder.
+
+ {\bf Application} ---
+ We consider now a simple applications consisting of encoding the
+ horizontal and vertical coordinates of a cloud of points. Each coordinate
+ requires one byte. The following function illustrates a possible
+ implementation:
+ \begin{verbatim}
+ void encode_points(const char *filename, int n, int *x, int *y)
+ {
+ StdioByteStream bs(filename, "wb");
+ bs.write32(n); // Write number of points.
+ ZPCodec zp(bs, 1); // Construct encoder and context vars.
+ BitContext ctxX[255], ctxY[255];
+ memset(ctxX, 0, sizeof(ctxX));
+ memset(ctxY, 0, sizeof(ctxY));
+ for (int i=0; i<n; i++) { // Encode coordinates.
+ encode_8_bits(zp, x[i], ctxX);
+ encode_8_bits(zp, y[i], ctxY);
+ }
+ }
+ \end{verbatim}
+ The decoding function is very similar to the encoding function:
+ \begin{verbatim}
+ int decode_points(const char *filename, int *x, int *y)
+ {
+ StdioByteStream bs(filename,"rb");
+ int n = bs.read32(); // Read number of points.
+ ZPCodec zp(bs, 0); // Construct decoder and context vars.
+ BitContext ctxX[255], ctxY[255];
+ memset(ctxX, 0, sizeof(ctxX));
+ memset(ctxY, 0, sizeof(ctxY));
+ for (int i=0; i<n; i++) { // Decode coordinates.
+ x[i] = decode_8_bits(zp, ctxX);
+ y[i] = decode_8_bits(zp, ctxY);
+ }
+ return n; // Return number of points.
+ }
+ \end{verbatim}
+ The ZP-Coder automatically estimates the probability distributions of both
+ the horizontal and vertical coordinates. These estimates are used to
+ efficiently encode the point coordinates. This particular implementation
+ is a good option if we assume that the order of the points is significant
+ and that successive points are independent. It would be much smarter
+ otherwise to sort the points and encode relative displacements between
+ successive points.
+
+
+ {\bf Huffman Coding Tricks} ---
+ Programmers with experience in Huffman codes can see the similarity in the
+ ZP-Coder. Huffman codes also organize the symbol values as a decision
+ tree. The tree is balanced in such a way that each decision is as
+ unpredictable as possible (i.e. both branches must be equally probable).
+ This is very close to the ZP-Coder technique described above. Since we
+ allocate one context variable for each decision, our tree need not be
+ balanced: the context variable will track the decision statistics and the
+ ZP-Coder will compensate optimally.
+
+ There are good reasons however to avoid unbalanced trees with the ZP-Coder.
+ Frequent symbol values may be located quite deep in a poorly balanced
+ tree. This increases the average number of message bits (the number of
+ decisions) required to code a symbol. The ZP-Coder will be called more
+ often, making the coding program slower. Furthermore, each message
+ bit is encoded using an estimated distribution. All these useless message
+ bits mean that the ZP-Coder has more distributions to adapt. This
+ extra adaptation work will probably increase the file size.
+
+ Huffman codes are very fast when the tree structure is fixed beforehand.
+ Such {\em static Huffman codes} are unfortunately not very efficient
+ because the tree never matches the actual data distribution. This is why
+ such programs almost always define a data dependent tree structure. This
+ structure must then be encoded in the file since the decoder must know it
+ before decoding the symbols. Static Huffman codes however become very
+ efficient when decisions are encoded with the ZP-Coder. The tree
+ structure represents a priori knowledge about the distribution of the
+ symbol values. Small data discrepancies will be addressed transparently
+ by the ZP-Coder.
+
+
+ {\bf Encoding Numbers} ---
+ This technique is illustrated with the following number encoding example.
+ The multivalued technique described above is not practical with large
+ numbers because the decision tree has too many nodes and requires too many
+ context variables. This problem can be solved by using a priori knowledge
+ about the probability distribution of our numbers.
+
+ Assume for instance that the distribution is symmetrical and that small
+ numbers are much more probable than large numbers. We will first group
+ our numbers into several sets. Each number is coded by first coding which
+ set contains the number and then coding a position within the set. Each
+ set contains #2^n# numbers that we consider roughly equiprobable. Since
+ the most probable values occur much more often, we want to model their
+ probability more precisely. Therefore we use small sets for the most
+ probable values and large sets for the least probable values, as
+ demonstrated below.
+ \begin{verbatim}
+ A---------------- {0} (size=1)
+ `------B---C---- {1} or {-1} (size=1)
+ \ `--- {2,3} or {-2,-3} (size=2)
+ D------ {4...131} or {-4...-131} (size=128)
+ `----- {132...32899} or {-132...-32899} (size=32768)
+ \end{verbatim}
+ We then organize a decision tree for coding the set identifier. This
+ decision tree is balanced using whatever a priori knowledge we have about
+ the probability distribution of the number values, just like a static
+ Huffman tree. Each decision (except the sign decision) is then coded
+ using a dedicated context variable.
+ \begin{verbatim}
+ if (! zp.decoder(ctx_A)) { // decision A
+ return 0;
+ } else {
+ if (! zp.decoder(ctx_B)) { // + decision B
+ if (! zp.decoder(ctx_C)) { // ++ decision C
+ if (! zp.decoder()) // +++ sign decision
+ return +1;
+ else
+ return -1;
+ } else {
+ if (! zp.decoder()) // +++ sign decision
+ return + 2 + zp.decoder();
+ else
+ return - 2 - zp.decoder();
+ }
+ } else {
+ if (! zp.decoder(ctx_D)) { // ++ decision D
+ if (! zp.decoder()) // +++ sign decision
+ return + 4 + decode_7_bits(zp);
+ else
+ return - 4 - decode_7_bits(zp);
+ } else {
+ if (! zp.decoder()) // +++ sign decision
+ return + 132 + decode_15_bits(zp);
+ else
+ return - 132 - decode_15_bits(zp);
+ }
+ }
+ }
+ \end{verbatim}
+ Note that the call #zp.decoder()# for coding the sign decision does not use
+ a context variable. This is a "pass-thru" variant of \Ref{decoder} which
+ bypasses the ZP-Coder and just reads a bit from the code sequence. There
+ is a corresponding "pass-thru" version of \Ref{encoder} for encoding such
+ bits. Similarly, functions #decode_7_bits# and #decode_15_bits# do not
+ take an array of context variables because, unlike function #decode_8_bits#
+ listed above, they are based on the pass-thru decoder instead of the
+ regular decoder.
+
+ The ZP-Coder will not learn the probabilities of the numbers within a set
+ since no context variables have been allocated for that purpose. This
+ could be improved by allocating additional context variables for encoding
+ the position within the smaller sets and using the regular decoding
+ functions instead of the pass-thru variants. Only experimentation can tell
+ what works best for your particular encoding problem.
+
+
+ {\bf Understanding Adaptation} ---
+ We have so far explained that the ZP-Coder adaptation algorithm is able to
+ quickly estimate of the probability distribution of the message bits coded
+ using a particular context variable. It is also able to track slow
+ variations when the actual probabilities change while coding.
+
+ Let us consider the ``cloud of points'' application presented above.
+ Suppose that we first code points located towards the left side and then
+ slowly move towards points located on the right side. The ZP-Coder will
+ first estimate that the X coordinates are rather on the left side. This
+ estimation will be progressively revised after seeing more points on the
+ right side. Such an ordering of the points obviously violates the point
+ independence assumption on which our code is based. Despite our inexact
+ assumptions, the tracking mechanism allows for better prediction of the X
+ coordinates and therefore better compression.
+
+ However, this is not a perfect solution. The ZP-Coder tracks the changes
+ because every point seems to be a little bit more on the right side than
+ suggested by the previous points. The ZP-Coder coding algorithm is always
+ slightly misadjusted and we always lose a little on possible compression
+ ratio. This is not much of a problem when the probabilities drift slowly.
+ On the other hand, this can be very significant if the probabilities change
+ drastically.
+
+ Adaptation is always associated with a small loss of efficiency. The
+ ZP-Coder updates the probability model whenever it suspects, {\em after
+ coding}, that the current settings were not optimal. The model will be
+ better next time, but a slight loss in compression has occurred. The
+ design of ZP-Coder of course minimizes this effect as much as possible.
+ Yet you will pay a price if you ask too much to the adaptation algorithm.
+ If you have millions of context variables, it will be difficult to train
+ them all. If the probability distributions change drastically while
+ coding, it will be difficult to track the changes fast enough.
+
+ Adaptation on the other hand is a great simplification. A good data
+ compression program must (a) represent the data in order to make its
+ predictability apparent, and (b) perform the predictions and generate the
+ code bits. The ZP-Coder is an efficient and effortless solution for
+ implementing task (b).
+
+
+ {\bf Practical Debugging Tricks} ---
+ Sometimes you write an encoding program and a decoding program.
+ Unfortunately there is a bug: the decoding program decodes half the file
+ and then just outputs garbage. There is a simple way to locate the
+ problem. In the encoding program, after each call to #encoder#, print the
+ encoded bit and the value of the context variable. In the decoding
+ program, after each call to #decoder#, print the decoded bit and the value
+ of the context variable. Both program should print exactly the same thing.
+ When you find the difference, you find the bug.
+
+ @memo Suggestions for efficiently using the ZP-Coder. */
+//@}
+
+// ------------ THE END
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
+
+
diff --git a/kviewshell/plugins/djvu/libdjvu/configure.in.in b/kviewshell/plugins/djvu/libdjvu/configure.in.in
new file mode 100644
index 00000000..c2a1d2b6
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/configure.in.in
@@ -0,0 +1,674 @@
+dnl Copyright (c) 2002 Leon Bottou and Yann Le Cun.
+dnl Copyright (c) 2001 AT&T
+dnl
+dnl Most of these macros are derived from macros listed
+dnl at the GNU Autoconf Macro Archive
+dnl http://www.gnu.org/software/ac-archive/
+dnl
+dnl This program is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; if not, write to the Free Software
+dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA02111 USA
+dnl
+
+dnl -------------------------------------------------------
+dnl @synopsis AC_CHECK_CXX_OPT(OPTION,
+dnl ACTION-IF-OKAY,ACTION-IF-NOT-OKAY)
+dnl Check if compiler accepts option OPTION.
+dnl -------------------------------------------------------
+AC_DEFUN([AC_CHECK_CXX_OPT],[
+ opt="$1"
+ AC_MSG_CHECKING([if $CXX accepts $opt])
+ echo 'void f(){}' > conftest.cc
+ if test -z "`${CXX} ${CXXFLAGS} ${OPTS} $opt -c conftest.cc 2>&1`"; then
+ AC_MSG_RESULT(yes)
+ rm conftest.*
+ $2
+ else
+ AC_MSG_RESULT(no)
+ rm conftest.*
+ $3
+ fi
+])
+
+dnl -------------------------------------------------------
+dnl @synopsis AC_CXX_MEMBER_TEMPLATES
+dnl If the compiler supports member templates,
+dnl define HAVE_MEMBER_TEMPLATES.
+dnl -------------------------------------------------------
+AC_DEFUN([AC_CXX_MEMBER_TEMPLATES],
+[AC_CACHE_CHECK(whether the compiler supports member templates,
+ac_cv_cxx_member_templates,
+[AC_LANG_SAVE
+ AC_LANG_CPLUSPLUS
+ AC_TRY_COMPILE([
+template<class T, int N> class A
+{ public:
+ template<int N2> A<T,N> operator=(const A<T,N2>& z) { return A<T,N>(); }
+};],[A<double,4> x; A<double,7> y; x = y; return 0;],
+ ac_cv_cxx_member_templates=yes, ac_cv_cxx_member_templates=no)
+ AC_LANG_RESTORE
+])
+if test "$ac_cv_cxx_member_templates" = yes; then
+ AC_DEFINE(HAVE_MEMBER_TEMPLATES,1,
+ [define if the compiler supports member templates])
+fi
+])
+
+
+dnl -------------------------------------------------------
+dnl @synopsis AC_CXX_NAMESPACES
+dnl Define HAVE_NAMESPACES if the compiler supports
+dnl namespaces.
+dnl -------------------------------------------------------
+AC_DEFUN([AC_CXX_NAMESPACES],
+[AC_CACHE_CHECK(whether the compiler implements namespaces,
+ac_cv_cxx_namespaces,
+[ AC_LANG_SAVE
+ AC_LANG_CPLUSPLUS
+ AC_TRY_COMPILE([namespace Outer { namespace Inner { int i = 0; }}],
+ [using namespace Outer::Inner; return i;],
+ ac_cv_cxx_namespaces=yes, ac_cv_cxx_namespaces=no)
+ AC_LANG_RESTORE
+])
+if test "$ac_cv_cxx_namespaces" = yes && test "$ac_debug" = no; then
+ AC_DEFINE(HAVE_NAMESPACES,1,
+ [define if the compiler implements namespaces])
+fi
+])
+
+
+
+dnl -------------------------------------------------------
+dnl @synopsis AC_CXX_TYPENAME
+dnl Define HAVE_TYPENAME if the compiler recognizes
+dnl keyword typename.
+dnl -------------------------------------------------------
+AC_DEFUN([AC_CXX_TYPENAME],
+[AC_CACHE_CHECK(whether the compiler recognizes typename,
+ac_cv_cxx_typename,
+[AC_LANG_SAVE
+ AC_LANG_CPLUSPLUS
+ AC_TRY_COMPILE([template<typename T>class X {public:X(){}};],
+[X<float> z; return 0;],
+ ac_cv_cxx_typename=yes, ac_cv_cxx_typename=no)
+ AC_LANG_RESTORE
+])
+if test "$ac_cv_cxx_typename" = yes; then
+ AC_DEFINE(HAVE_TYPENAME,1,[define if the compiler recognizes typename])
+fi
+])
+
+
+dnl -------------------------------------------------------
+dnl @synopsis AC_CXX_STDINCLUDES
+dnl Define HAVE_STDINCLUDES if the compiler has the
+dnl new style include files (without the .h)
+dnl -------------------------------------------------------
+AC_DEFUN([AC_CXX_STDINCLUDES],
+[AC_CACHE_CHECK(whether the compiler comes with standard includes,
+ac_cv_cxx_stdincludes,
+[AC_LANG_SAVE
+ AC_LANG_CPLUSPLUS
+ AC_TRY_COMPILE([#include <new>
+struct X { int a; X(int a):a(a){}; };
+X* foo(void *x) { return new(x) X(2); } ],[],
+ ac_cv_cxx_stdincludes=yes, ac_cv_cxx_stdincludes=no)
+ AC_LANG_RESTORE
+])
+if test "$ac_cv_cxx_stdincludes" = yes; then
+ AC_DEFINE(HAVE_STDINCLUDES,1,
+ [define if the compiler comes with standard includes])
+fi
+])
+
+
+dnl -------------------------------------------------------
+dnl @synopsis AC_CXX_BOOL
+dnl If the compiler recognizes bool as a separate built-in type,
+dnl define HAVE_BOOL. Note that a typedef is not a separate
+dnl type since you cannot overload a function such that it
+dnl accepts either the basic type or the typedef.
+dnl -------------------------------------------------------
+AC_DEFUN([AC_CXX_BOOL],
+[AC_CACHE_CHECK(whether the compiler recognizes bool as a built-in type,
+ac_cv_cxx_bool,
+[AC_LANG_SAVE
+ AC_LANG_CPLUSPLUS
+ AC_TRY_COMPILE([
+int f(int x){return 1;}
+int f(char x){return 1;}
+int f(bool x){return 1;}
+],[bool b = true; return f(b);],
+ ac_cv_cxx_bool=yes, ac_cv_cxx_bool=no)
+ AC_LANG_RESTORE
+])
+if test "$ac_cv_cxx_bool" = yes; then
+ AC_DEFINE(HAVE_BOOL,1,[define if bool is a built-in type])
+fi
+])
+
+dnl -------------------------------------------------------
+dnl @synopsis AC_CXX_EXCEPTIONS
+dnl If the C++ compiler supports exceptions handling (try,
+dnl throw and catch), define HAVE_EXCEPTIONS.
+dnl -------------------------------------------------------
+AC_DEFUN([AC_CXX_EXCEPTIONS],
+[AC_CACHE_CHECK(whether the compiler supports exceptions,
+ac_cv_cxx_exceptions,
+[AC_LANG_SAVE
+ AC_LANG_CPLUSPLUS
+ AC_TRY_COMPILE(,[try { throw 1; } catch (int i) { return i; }],
+ ac_cv_cxx_exceptions=yes, ac_cv_cxx_exceptions=no)
+ AC_LANG_RESTORE
+])
+if test "$ac_cv_cxx_exceptions" = yes; then
+ AC_DEFINE(HAVE_EXCEPTIONS,1,[define if the compiler supports exceptions])
+fi
+])
+
+
+dnl -------------------------------------------------------
+dnl @synopsis AC_CXX_RPO
+dnl Defines option --enable-rpo and searches program RPO.
+dnl Set output variables CXXRPOFLAGS and RPO.
+dnl -------------------------------------------------------
+AC_DEFUN([AC_CXX_RPO],
+[ CXXRPOFLAGS=
+ RPO_YES='#'
+ RPO_NO=''
+ if test x$GXX = xyes ; then
+ AC_ARG_ENABLE([rpo],
+ AC_HELP_STRING([--enable-rpo],
+ [Enable compilation with option -frepo]),
+ [ac_rpo=$enableval], [ac_rpo=no] )
+ if test x$ac_rpo != xno ; then
+ CXXRPOFLAGS='-frepo -fno-rtti'
+ RPO_YES=''
+ RPO_NO='#'
+ fi
+ fi
+ AC_SUBST(CXXRPOFLAGS)
+ AC_SUBST(RPO_YES)
+ AC_SUBST(RPO_NO)
+])
+
+
+dnl ------------------------------------------------------------------
+dnl @synopsis AC_PATH_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+dnl This macro figures out how to build C programs using POSIX
+dnl threads. It sets the PTHREAD_LIBS output variable to the threads
+dnl library and linker flags, and the PTHREAD_CFLAGS output variable
+dnl to any special C compiler flags that are needed. (The user can also
+dnl force certain compiler flags/libs to be tested by setting these
+dnl environment variables.).
+dnl ------------------------------------------------------------------
+AC_DEFUN([AC_PATH_PTHREAD], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+acx_pthread_ok=no
+# First, check if the POSIX threads header, pthread.h, is available.
+# If it isn't, don't bother looking for the threads libraries.
+AC_CHECK_HEADER(pthread.h, , acx_pthread_ok=noheader)
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works.
+if test x${PTHREAD_LIBS+set} = xset ||
+ test x${PTHREAD_CFLAGS+set} = xset ; then
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ save_CXXFLAGS="$CXXFLAGS"
+ CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS"
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ AC_MSG_CHECKING([provided PTHREAD_LIBS/PTHREAD_CFLAGS.])
+ AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes)
+ AC_MSG_RESULT($acx_pthread_ok)
+ if test x"$acx_pthread_ok" = xno; then
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+ fi
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+ CXXFLAGS="$save_CXXFLAGS"
+fi
+# Create a list of thread flags to try. Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all.
+acx_pthread_flags="pthreads none -Kthread -kthread lthread
+ -pthread -pthreads -mthreads pthread
+ --thread-safe -mt"
+# The ordering *is* (sometimes) important.
+# Some notes on the individual items follow:
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+# other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
+# -pthreads: Solaris/gcc
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+# doesn't hurt to check since this sometimes defines pthreads too;
+# also defines -D_REENTRANT)
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+case "${host_cpu}-${host_os}" in
+ *solaris*)
+ # On Solaris (at least, for some versions), libc contains stubbed
+ # (non-functional) versions of the pthreads routines, so link-based
+ # tests will erroneously succeed. (We need to link with -pthread or
+ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
+ # a function called by this macro, so we could check for that, but
+ # who knows whether they'll stub that too in a future libc.) So,
+ # we'll just look for -pthreads and -lpthread first:
+ acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags"
+ ;;
+esac
+if test x"$acx_pthread_ok" = xno; then
+for flag in $acx_pthread_flags; do
+ case $flag in
+ none)
+ AC_MSG_CHECKING([whether pthreads work without any flags])
+ ;;
+ -*)
+ AC_MSG_CHECKING([whether pthreads work with $flag])
+ PTHREAD_CFLAGS="$flag"
+ ;;
+ *)
+ AC_MSG_CHECKING([for the pthreads library -l$flag])
+ PTHREAD_LIBS="-l$flag"
+ ;;
+ esac
+ save_LIBS="$LIBS"
+ save_CFLAGS="$CFLAGS"
+ save_CXXFLAGS="$CXXFLAGS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS"
+ # Check for various functions. We must include pthread.h,
+ # since some functions may be macros. (On the Sequent, we
+ # need a special flag -Kthread to make this header compile.)
+ # We check for pthread_join because it is in -lpthread on IRIX
+ # while pthread_create is in libc. We check for pthread_attr_init
+ # due to DEC craziness with -lpthreads. We check for
+ # pthread_cleanup_push because it is one of the few pthread
+ # functions on Solaris that doesn't have a non-functional libc stub.
+ # We try pthread_create on general principles.
+ AC_TRY_LINK([#include <pthread.h>],
+ [pthread_t th; pthread_join(th, 0);
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0); ],
+ [acx_pthread_ok=yes])
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+ CXXFLAGS="$save_CXXFLAGS"
+ AC_MSG_RESULT($acx_pthread_ok)
+ if test "x$acx_pthread_ok" = xyes; then
+ break;
+ fi
+ PTHREAD_LIBS=""
+ PTHREAD_CFLAGS=""
+done
+fi
+# Various other checks:
+if test "x$acx_pthread_ok" = xyes; then
+ save_LIBS="$LIBS"
+ LIBS="$PTHREAD_LIBS $LIBS"
+ save_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+ save_CXXFLAGS="$CXXFLAGS"
+ CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS"
+ AC_MSG_CHECKING([if more special flags are required for pthreads])
+ flag=no
+ case "${host_cpu}-${host_os}" in
+ *-aix* | *-freebsd*) flag="-D_THREAD_SAFE";;
+ *solaris* | alpha*-osf*) flag="-D_REENTRANT";;
+ esac
+ AC_MSG_RESULT(${flag})
+ if test "x$flag" != xno; then
+ PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
+ fi
+ LIBS="$save_LIBS"
+ CFLAGS="$save_CFLAGS"
+ CXXFLAGS="$save_CXXFLAGS"
+fi
+AC_ARG_VAR(PTHREAD_LIBS, [Flags for linking pthread programs.])
+AC_ARG_VAR(PTHREAD_CFLAGS, [Flags for compiling pthread programs.])
+# execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test x"$acx_pthread_ok" = xyes; then
+ AC_DEFINE(HAVE_PTHREAD,1,[Define if pthreads are available])
+ ifelse([$1],,:,[$1])
+else
+ ifelse([$2],,:,[$2])
+fi
+])
+
+
+dnl ------------------------------------------------------------------
+dnl @synopsis AC_PATH_COTHREADS([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+dnl Define HAVE_COTHREAD if cothreads can be used.
+dnl Define HAVE_COTHREAD_PATCH if cothread libgcc patch is available
+dnl ------------------------------------------------------------------
+
+AC_DEFUN([AC_PATH_COTHREAD], [
+AC_REQUIRE([AC_CANONICAL_HOST])
+acx_cothread=no
+if test x$GXX = xyes ; then
+ AC_MSG_CHECKING([whether cothreads work with ${host_cpu}])
+ case ${host_cpu} in
+ i?86|powerpc*|mips*|alpha*|hppa*)
+ acx_cothread=yes
+ ;;
+ esac
+ AC_MSG_RESULT($acx_cothread)
+fi
+if test x$acx_cothread != xno ; then
+ AC_MSG_CHECKING([whether libgcc contains the cothread patch])
+ AC_LANG_PUSH([C++])
+ AC_TRY_LINK([extern "C" { void *(*__get_eh_context_ptr)();
+ void *__new_eh_context(void); }],
+ [ __get_eh_context_ptr = &__new_eh_context;],
+ [acx_cothread_patch=yes], [acx_cothread_patch=no])
+ AC_LANG_POP([C++])
+ AC_MSG_RESULT($acx_cothread_patch)
+ if test x$acx_cothread_patch = xno ; then
+ AC_MSG_CHECKING([if the cothread patch is critical])
+ echo 'void foo() { throw "Hello"; }' > conftest.cc
+ compile="$CXX $CXXFLAGS -c conftest.cc"
+ check="nm conftest.o | grep sjthrow | cat > conftest.out"
+ acx_cothread_patch=yes
+ if AC_TRY_EVAL(compile) && AC_TRY_EVAL(check) ; then
+ if test -z "`cat conftest.out`" ; then
+ acx_cothread_patch=no
+ fi
+ fi
+ AC_MSG_RESULT($acx_cothread_patch)
+ rm conftest.*
+ if test x$acx_cothread_patch = xyes ; then
+ acx_cothread=no
+ AC_MSG_WARN([Cothread cannot work without the patch])
+ else
+ AC_MSG_WARN([Applying the patch is recommended anyway])
+ fi
+ AC_MSG_WARN([See the INSTALL file for more information])
+ fi
+fi
+# Must do.
+if test x$acx_cothread = xyes ; then
+ AC_DEFINE(HAVE_COTHREAD,1,
+ [Define if cothreads are available.])
+ if test x$acx_cothread_patch = xyes ; then
+ AC_DEFINE(HAVE_COTHREAD_PATCH,1,
+ [Define if libgcc contains the cothread patch.])
+ fi
+ ifelse([$1],,:,[$1])
+else
+ ifelse([$2],,:,[$2])
+fi
+])
+
+dnl ------------------------------------------------------------------
+dnl @synopsis AC_PATH_THREADS([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+dnl Process optional option --enable-threads
+dnl Check availability of pthreads or cothreads
+dnl using AC_PATH_PTHREAD and AC_PATH_COTHREAD.
+dnl Set output variable THREADS_LIBS and THREADS_CFLAGS
+dnl ------------------------------------------------------------------
+
+AC_DEFUN([AC_PATH_THREADS], [
+AC_ARG_ENABLE(threads,
+ AC_HELP_STRING([--enable-threads],
+ [select threading model (default is auto)]),
+ ac_use_threads=$enableval, ac_use_threads=auto)
+ac_threads=no
+if test x$ac_use_threads != xno ; then
+ case x$ac_use_threads in
+ x|xyes|xauto|xposix|xpthread)
+ AC_PATH_PTHREAD(
+ [ ac_threads=pthread
+ ac_use_threads=pthread
+ THREAD_LIBS="$PTHREAD_LIBS"
+ THREAD_CFLAGS="$PTHREAD_CFLAGS -DTHREADMODEL=POSIXTHREADS"
+ ] )
+ ;;
+ esac
+ case x$ac_use_threads in
+ xposix|xpthread)
+ ;;
+ x|xyes|xauto|xcothread)
+ AC_PATH_COTHREAD(
+ [ ac_threads=cothread
+ THREAD_CFLAGS="-DTHREADMODEL=COTHREADS"
+ ] )
+ ;;
+ *)
+ AC_MSG_ERROR(
+[Invalid argument for --enable-threads
+Valid arguments are: yes, no, posix, pthread, cothread, auto.])
+ ;;
+ esac
+fi
+AC_SUBST(THREAD_LIBS)
+AC_SUBST(THREAD_CFLAGS)
+AC_MSG_CHECKING([threading model])
+AC_MSG_RESULT($ac_threads)
+if test $ac_threads != no ; then
+ AC_MSG_RESULT([setting THREAD_CFLAGS=$THREAD_CFLAGS])
+ AC_MSG_RESULT([setting THREAD_LIBS=$THREAD_LIBS])
+ ifelse([$1],,:,[$1])
+else
+ ifelse([$2],,:,[$2])
+fi
+])
+
+
+dnl ------------------------------------------------------------------
+dnl @synopsis AC_PATH_TIFF([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+dnl Process option --with-tiff
+dnl Search LIBTIFF. Define HAVE_TIFF.
+dnl Set output variable TIFF_CFLAGS and TIFF_LIBS
+dnl ------------------------------------------------------------------
+
+AC_DEFUN([AC_PATH_TIFF],
+[
+ AC_ARG_VAR(TIFF_LIBS)
+ AC_ARG_VAR(TIFF_CFLAGS)
+ ac_tiff=no
+ AC_ARG_WITH(tiff,
+ AC_HELP_STRING([--with-tiff=DIR],
+ [where libtiff is located]),
+ [ac_tiff=$withval], [ac_tiff=yes] )
+ # Process specification
+ if test x$ac_tiff = xyes ; then
+ test x${TIFF_LIBS+set} != xset && TIFF_LIBS="-ltiff"
+ elif test x$ac_tiff != xno ; then
+ test x${TIFF_LIBS+set} != xset && TIFF_LIBS="-L$ac_tiff -ltiff"
+ test x${TIFF_CFLAGS+set} != xset && TIFF_CFLAGS="-I$ac_tiff"
+ fi
+ # Try linking
+ if test x$ac_tiff != xno ; then
+ AC_MSG_CHECKING([for the libtiff library])
+ save_CFLAGS="$CFLAGS"
+ save_CXXFLAGS="$CXXFLAGS"
+ save_LIBS="$LIBS"
+ CFLAGS="$CFLAGS $TIFF_CFLAGS"
+ CXXFLAGS="$CXXFLAGS $TIFF_CFLAGS"
+ LIBS="$LIBS $TIFF_LIBS"
+ AC_TRY_LINK([
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <stdio.h>
+#include <tiffio.h>
+#ifdef __cplusplus
+}
+#endif ],[
+TIFFOpen(0,0);],
+ [ac_tiff=yes], [ac_tiff=no] )
+ CFLAGS="$save_CFLAGS"
+ CXXFLAGS="$save_CXXFLAGS"
+ LIBS="$save_LIBS"
+ AC_MSG_RESULT($ac_tiff)
+ fi
+ # Finish
+ if test x$ac_tiff = xno; then
+ TIFF_CFLAGS= ; TIFF_LIBS=
+ ifelse([$2],,:,[$2])
+ else
+ AC_DEFINE(HAVE_TIFF,1,[Define if you have libtiff.])
+ AC_MSG_RESULT([setting TIFF_CFLAGS=$TIFF_CFLAGS])
+ AC_MSG_RESULT([setting TIFF_LIBS=$TIFF_LIBS])
+ ifelse([$1],,:,[$1])
+ fi
+])
+
+# C++
+AC_LANG(C++)
+AC_CXX_BOOL
+AC_CXX_EXCEPTIONS
+AC_CXX_TYPENAME
+AC_CXX_STDINCLUDES
+AC_CXX_NAMESPACES
+AC_CXX_MEMBER_TEMPLATES
+AC_CXX_RPO
+
+# ----------------------------------------
+# Libraries
+# ----------------------------------------
+
+AC_CHECK_LIB(m,sqrt)
+AC_CHECK_LIB(iconv,libiconv)
+
+# ----------------------------------------
+# Header Files
+# ----------------------------------------
+
+AC_HEADER_STDC
+AC_HEADER_DIRENT
+AC_HEADER_TIME
+AC_HEADER_SYS_WAIT
+AC_CHECK_HEADERS(wchar.h wctype.h sys/mman.h iconv.h)
+AC_CHECK_HEADERS(stdint.h sys/ipc.h sys/shm.h)
+
+# ----------------------------------------
+# Types
+# ----------------------------------------
+
+AC_CHECK_TYPES(wchar_t)
+AC_CHECK_TYPES(long long int)
+AC_CHECK_TYPES(mbstate_t,,,[#include "wchar.h"])
+
+# ----------------------------------------
+# Functions
+# ----------------------------------------
+
+AC_FUNC_MMAP
+AC_FUNC_FORK
+AC_CHECK_FUNCS(wcrtomb iswspace)
+AC_CHECK_FUNCS(putc_unlocked strerror vsnprintf)
+AC_CHECK_FUNCS(gethostname iconv strftime getpwuid)
+
+# ----------------------------------------
+# Test auxilliary packages
+# ----------------------------------------
+
+# Search TIFF library
+AC_PATH_TIFF(,
+[ no_tiff=yes
+ AC_MSG_WARN([Tiff support is disabled]) ])
+
+# Search MULTITHREADING library
+AC_PATH_THREADS(,
+[ no_threads=yes
+ AC_MSG_WARN([Thread support is disabled]) ])
+
+# ----------------------------------------
+# Stuff added to config.h
+# ----------------------------------------
+
+# Fence
+AH_TOP([
+#ifndef DJVU_CONFIG_H
+#define DJVU_CONFIG_H
+/* config.h: begin */
+])
+
+# L18N Macros
+AH_BOTTOM([
+/* - Miscellaneous */
+#define UNIX 1
+#define NEED_GNUG_PRAGMAS 0
+
+/* - BOOL */
+#if !defined(HAVE_BOOL) && !defined(bool)
+#define bool char
+#define true 1
+#define false 0
+#endif
+
+/* - WCHAR etc.*/
+#if ! defined(HAVE_WCHAR_T)
+#define HAS_WCHAR 0
+#define HAS_WCTYPE 0
+#define HAS_MBSTATE 0
+#else
+#define HAS_WCHAR 1
+#if defined(HAVE_WCTYPE_H) && defined(HAVE_ISWSPACE)
+#define HAS_WCTYPE 1
+#endif
+#if defined(HAVE_MBSTATE_T) && defined(HAVE_WCRTOMB)
+#define HAS_MBSTATE 1
+#endif
+#endif
+#if defined(HAVE_ICONV_H) && defined(HAVE_ICONV)
+#define HAS_ICONV 1
+#else
+#define HAS_ICONV 0
+#endif
+
+/* - I18N MESSAGES HELL */
+#define HAS_CTRL_C_IN_ERR_MSG 1
+
+/* - CONTAINERS */
+#ifndef HAVE_MEMBER_TEMPLATES
+#define GCONTAINER_NO_MEMBER_TEMPLATES
+#endif
+#ifndef HAVE_TYPENAME
+#define GCONTAINER_NO_TYPENAME
+#endif
+
+/* - COTHREAD */
+#ifdef HAVE_COTHREAD
+#ifndef HAVE_COTHREAD_PATCH
+#define NO_LIBGCC_HOOKS
+#endif
+#endif
+
+/* - JPEG */
+#ifdef HAVE_LIBJPEG
+#define NEED_JPEG_DECODER
+#endif
+
+/* - MMAP */
+#if defined(HAVE_MMAP) && defined(HAVE_SYS_MMAN_H)
+#define HAS_MEMMAP 1
+#else
+#define HAS_MEMMAP 0
+#endif
+
+/* config.h: end */
+#endif
+])
diff --git a/kviewshell/plugins/djvu/libdjvu/debug.cpp b/kviewshell/plugins/djvu/libdjvu/debug.cpp
new file mode 100644
index 00000000..20c93e50
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/debug.cpp
@@ -0,0 +1,299 @@
+//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: debug.cpp,v 1.14 2005/05/27 14:26:00 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma implementation
+#endif
+
+#include "debug.h"
+
+#if ( DEBUGLVL > 0 )
+
+#include "GThreads.h"
+#include "GContainer.h"
+#include "GString.h"
+#include "GString.h"
+#include "ByteStream.h"
+#include "GURL.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <errno.h>
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+#endif
+#endif
+
+
+#ifndef UNIX
+#ifndef WIN32
+#ifndef macintosh
+#define UNIX
+#endif
+#endif
+#endif
+
+static GCriticalSection debug_lock;
+#ifdef RUNTIME_DEBUG_ONLY
+static int debug_level = 0;
+#else
+static int debug_level = DEBUGLVL;
+#endif
+static int debug_id;
+static FILE *debug_file;
+static int debug_file_count;
+
+#if THREADMODEL==NOTHREADS
+static DjVuDebug debug_obj;
+#else
+static GMap<long, DjVuDebug> &
+debug_map(void)
+{
+ static GMap<long, DjVuDebug> xmap;
+ return xmap;
+}
+#endif
+
+DjVuDebug::DjVuDebug()
+ : block(0), indent(0)
+{
+ id = debug_id++;
+#ifdef UNIX
+ if (debug_file_count++ == 0 && !debug_file)
+ set_debug_file(stderr);
+#endif
+}
+
+DjVuDebug::~DjVuDebug()
+{
+#ifdef UNIX
+ if (--debug_file_count == 0)
+ {
+ if (debug_file && (debug_file != stderr))
+ fclose(debug_file);
+ debug_file = 0;
+ }
+#endif
+}
+
+void
+DjVuDebug::format(const char *fmt, ... )
+{
+ if (! block)
+ {
+ va_list ap;
+ va_start(ap, fmt);
+ GUTF8String buffer(fmt,ap);
+ va_end(ap);
+ GCriticalSectionLock glock(&debug_lock);
+ if (debug_file)
+ {
+ fprintf(debug_file,"%s", (const char*)buffer);
+ fflush(debug_file);
+ }
+#ifdef WIN32
+ else
+ {
+ USES_CONVERSION;
+ OutputDebugString(A2CT((const char *)buffer));
+ }
+#endif
+ }
+}
+
+void
+DjVuDebug::set_debug_level(int lvl)
+{
+ debug_level = lvl;
+}
+
+void
+DjVuDebug::set_debug_file(FILE * file)
+{
+ GCriticalSectionLock glock(&debug_lock);
+ if (debug_file && (debug_file != stderr))
+ fclose(debug_file);
+ debug_file = file;
+}
+
+void
+DjVuDebug::modify_indent(int rindent)
+{
+ indent += rindent;
+}
+
+DjVuDebug&
+DjVuDebug::lock(int lvl, int noindent)
+{
+ int threads_num=1;
+ debug_lock.lock();
+ // Find Debug object
+#if THREADMODEL==NOTHREADS
+ // Get no-threads debug object
+ DjVuDebug &dbg = debug_obj;
+#else
+ // Get per-thread debug object
+ long threadid = (long) GThread::current();
+ DjVuDebug &dbg = debug_map()[threadid];
+ threads_num=debug_map().size();
+#endif
+ // Check level
+ dbg.block = (lvl > debug_level);
+ // Output thread id and indentation
+ if (! noindent)
+ {
+ if (threads_num>1)
+ dbg.format("[T%d] ", dbg.id);
+ int ind = dbg.indent;
+ char buffer[257];
+ memset(buffer,' ', sizeof(buffer)-1);
+ buffer[sizeof(buffer)-1] = 0;
+ while (ind > (int)sizeof(buffer)-1)
+ {
+ dbg.format("%s", buffer);
+ ind -= sizeof(buffer)-1;
+ }
+ if (ind > 0)
+ {
+ buffer[ind] = 0;
+ dbg.format("%s", buffer);
+ }
+ }
+ // Return
+ return dbg;
+}
+
+void
+DjVuDebug::unlock()
+{
+ debug_lock.unlock();
+}
+
+#define OP(type, fmt) \
+DjVuDebug& DjVuDebug::operator<<(type arg)\
+{ format(fmt, arg); return *this; }
+
+DjVuDebug& DjVuDebug::operator<<(bool arg)
+{
+ format("%s", arg ? "TRUE" : "FALSE"); return *this;
+}
+
+OP(char, "%c")
+OP(unsigned char, "%c")
+OP(int, "%d")
+OP(unsigned int, "%u")
+OP(short int, "%hd")
+OP(unsigned short int, "%hu")
+OP(long, "%ld")
+OP(unsigned long, "%lu")
+OP(float, "%g")
+OP(double, "%g")
+OP(const void * const, "0x%08x")
+
+DjVuDebug& DjVuDebug::operator<<(const char * const ptr)
+{
+ GUTF8String buffer(ptr?ptr:"(null)");
+ if(buffer.length() > 255)
+ {
+ buffer=buffer.substr(0,252)+"...";
+ }
+ format("%s", (const char *)buffer);
+ return *this;
+}
+
+DjVuDebug& DjVuDebug::operator<<(const unsigned char * const ptr)
+{
+ return operator<<( (const char *) ptr );
+}
+
+DjVuDebug& DjVuDebug::operator<<(const GUTF8String &ptr)
+{
+ GUTF8String buffer(ptr);
+ if(buffer.length() > 255)
+ buffer=buffer.substr(0,252)+"...";
+ format("%s", (const char *)buffer);
+ return *this;
+}
+
+DjVuDebugIndent::DjVuDebugIndent(int inc)
+ : inc(inc)
+{
+ DjVuDebug &dbg = DjVuDebug::lock(0,1);
+ dbg.modify_indent(inc);
+ dbg.unlock();
+}
+
+DjVuDebugIndent::~DjVuDebugIndent()
+{
+ DjVuDebug &dbg = DjVuDebug::lock(0,1);
+ dbg.modify_indent(-inc);
+ dbg.unlock();
+}
+
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+#endif
diff --git a/kviewshell/plugins/djvu/libdjvu/debug.h b/kviewshell/plugins/djvu/libdjvu/debug.h
new file mode 100644
index 00000000..c39390a2
--- /dev/null
+++ b/kviewshell/plugins/djvu/libdjvu/debug.h
@@ -0,0 +1,304 @@
+//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: debug.h,v 1.12 2005/05/27 14:26:01 leonb Exp $
+// $Name: release_3_5_15 $
+
+#ifndef _DEBUG_H_
+#define _DEBUG_H_
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#if NEED_GNUG_PRAGMAS
+# pragma interface
+#endif
+
+#include <stdio.h>
+#ifdef WIN32
+# include <atlbase.h> // USES_CONVERSION, A2CT macro
+# include <windows.h> // OutputDebugString
+#endif
+
+
+#ifdef HAVE_NAMESPACES
+namespace DJVU {
+# ifdef NOT_DEFINED // Just to fool emacs c++ mode
+}
+# endif
+#endif
+
+/** @name debug.h
+
+ Files #"debug.h"# and #"debug.cpp"# implement means to print debug
+ messages in a multithread safe way. Message are also marked with a thread
+ identifier. Under Windows, debug messages are directly sent to the
+ debugger using the Win32 function #OutputDebugString#. Under Unix, debug
+ messages are printed on the controlling terminal, preferably using device
+ #/dev/tty#.
+
+ The preprocessor variable #DEBUGLVL# defines which debug code is going to
+ be compiled. Selecting #-DDEBUGLVL=0# (the default) disables all
+ debugging code. Selecting a positive values (e.g. #-DDEBUGLVL=4#) enables
+ more and more debugging code.
+
+ Message output is controlled by the current debugging level (an integer
+ between #0# and #DEBUGLVL#). Greater values enable more messages. The
+ initial debugging level is set to the maximum value. The debugging level
+ can be changed using macro \Ref{DEBUG_SET_LEVEL}.
+
+ Message indentation can be modified using macro \Ref{DEBUG_MAKE_INDENT}.
+ Messages are generated by macro \Ref{DEBUG_MSG} or its variants. The
+ argument of the macro can contain several components separated by operator
+ #<<#, as demonstrated in the example below:
+ \begin{verbatim}
+ DEBUG_MSG("The value of a[" << n << "] is " << a[n] << '\n');
+ \end{verbatim}
+
+ One more preprocessor variable #RUNTIME_DEBUG_ONLY# enables compilation
+ of debug code, but does not enable the debug messages automatically.
+ In order to see them the program should use \Ref{DEBUG_SET_LEVEL} to
+ change the level to anything greater than 0. Normally this happens when
+ user specifies option #-debug# in the command line. Usage of
+ #RUNTIME_DEBUG_ONLY# implies #DEBUGLVL=1# if not specified otherwise.
+
+ Finally, #-DNO_DEBUG# or #-DNDEBUG# can be used instead of #-DDEBUGLVL=0#,
+ and #-D_DEBUG# can be used instead of #-DDEBUGLVL=0#.
+
+ {\bf Historical Comment} --- Debug macros are rarely used in the reference
+ DjVu library because Leon thinks that debugging messages unnecessarily
+ clutter the code. Debug macros are used everywhere in the plugin code
+ because Andrew thinks that code without debugging messages is close to
+ useless. No agreement could be reached. Neither could they agree on
+ if cluttering header files with huge documentation chunks helps to
+ improve code readability.
+
+ @memo
+ Macros for printing debug messages.
+ @version
+ #$Id: debug.h,v 1.12 2005/05/27 14:26:01 leonb Exp $#
+ @author
+ Andrew Erofeev <eaf@geocities.com> -- initial implementation \\
+ Leon Bottou <leonb@research.att.com> -- cleanups */
+//@{
+
+#ifndef DEBUGLVL
+# ifdef NDEBUG
+# define DEBUGLVL 0
+# endif
+#endif
+#ifndef DEBUGLVL
+# ifdef NO_DEBUG
+# define DEBUGLVL 0
+# endif
+#endif
+#ifndef DEBUGLVL
+# ifdef RUNTIME_DEBUG_ONLY
+# define DEBUGLVL 1
+# endif
+#endif
+#ifndef DEBUGLVL
+# ifdef _DEBUG
+# define DEBUGLVL 1
+# endif
+#endif
+#ifndef DEBUGLVL
+# define DEBUGLVL 0
+#endif
+
+#if DEBUGLVL <= 0
+
+# ifndef NO_DEBUG
+# define NO_DEBUG
+# endif
+# ifndef NDEBUG
+# define NDEBUG
+# endif
+# ifdef _DEBUG
+# undef _DEBUG
+# endif
+
+# define DEBUG_MAKE_INDENT(x)
+# define DEBUG_SET_LEVEL(level)
+# define DEBUG_MSG_LVL(level,x)
+# define DEBUG_MSGN_LVL(level,x)
+
+#else
+
+# ifdef NO_DEBUG
+# undef NO_DEBUG
+# endif
+# ifdef NDEBUG
+# undef NDEBUG
+# endif
+# ifndef _DEBUG
+# define _DEBUG
+# endif
+
+class GUTF8String;
+
+// ------------ SUPPORT
+
+class DjVuDebug // DJVU_CLASS
+{
+private:
+ int id;
+ int block;
+ int indent;
+ void format(const char *fmt, ... );
+public:
+ // construction
+ DjVuDebug();
+ ~DjVuDebug();
+ // access
+ static void set_debug_level(int lvl);
+ static void set_debug_file(FILE * file);
+ void modify_indent(int rindent);
+ static DjVuDebug& lock(int lvl, int noindent);
+ void unlock();
+ // printing
+ DjVuDebug & operator<<(bool b);
+ DjVuDebug & operator<<(char c);
+ DjVuDebug & operator<<(unsigned char c);
+ DjVuDebug & operator<<(int i);
+ DjVuDebug & operator<<(unsigned int i);
+ DjVuDebug & operator<<(short int i);
+ DjVuDebug & operator<<(unsigned short int i);
+ DjVuDebug & operator<<(long i);
+ DjVuDebug & operator<<(unsigned long i);
+ DjVuDebug & operator<<(const char * const ptr);
+ DjVuDebug & operator<<(const unsigned char * const ptr);
+ DjVuDebug& operator<<(const GUTF8String &ptr);
+ DjVuDebug & operator<<(float f);
+ DjVuDebug & operator<<(double d);
+ DjVuDebug & operator<<(const void * const p);
+};
+
+class DjVuDebugIndent // DJVU_CLASS
+{
+private:
+ int inc;
+public:
+ DjVuDebugIndent(int inc=2);
+ ~DjVuDebugIndent();
+//#define DEBUG_MAKE_INDENT_2(x, y) DjVuDebugIndent debug_indent ## y (x)
+//#define DEBUG_MAKE_INDENT_1(x, y) DEBUG_MAKE_INDENT_2(x, y)
+#define DEBUG_MAKE_INDENT_1(x, y) DjVuDebugIndent debug_indent ## y (x)
+};
+
+// ------------ MAIN MACROS
+
+# define DEBUG_MAKE_INDENT(x) DEBUG_MAKE_INDENT_1(x, __LINE__)
+# define DEBUG_SET_LEVEL(level) DjVuDebug::set_debug_level(level)
+# define DEBUG_MSG_LVL(level,x) { ( DjVuDebug::lock(level,0) << x ).unlock(); }
+# define DEBUG_MSGN_LVL(level,x) { ( DjVuDebug::lock(level,1) << x ).unlock(); }
+# define DEBUG_MSGF_LVL(level,x) { ( DjVuDebug::lock(level,1) << x ).unlock(); }
+
+#endif
+
+
+// ------------ EAF MACROS
+
+#if ( DEBUGLVL >= 1 )
+/** Generates a level 1 message */
+# define DEBUG1_MSG(x) DEBUG_MSG_LVL(1,x)
+# define DEBUG1_MSGF(x) DEBUG_MSGF_LVL(1,x)
+#else
+# define DEBUG1_MSG(x)
+# define DEBUG1_MSGF(x)
+#endif
+#if ( DEBUGLVL >= 2 )
+/** Generates a level 2 message */
+# define DEBUG2_MSG(x) DEBUG_MSG_LVL(2,x)
+# define DEBUG2_MSGF(x) DEBUG_MSGF_LVL(2,x)
+#else
+# define DEBUG2_MSG(x)
+# define DEBUG2_MSGF(x)
+#endif
+#if ( DEBUGLVL >= 3 )
+/** Generates a level 3 message */
+# define DEBUG3_MSG(x) DEBUG_MSG_LVL(3,x)
+# define DEBUG3_MSGF(x) DEBUG_MSGF_LVL(3,x)
+#else
+# define DEBUG3_MSG(x)
+# define DEBUG3_MSGF(x)
+#endif
+#if ( DEBUGLVL >= 4 )
+/** Generates a level 4 message */
+# define DEBUG4_MSG(x) DEBUG_MSG_LVL(4,x)
+# define DEBUG4_MSGF(x) DEBUG_MSGF_LVL(4,x)
+#else
+# define DEBUG4_MSG(x)
+# define DEBUG4_MSGF(x)
+#endif
+
+#define DEBUG_RUNTIME_SET_LEVEL(level) DEBUG_SET_LEVEL(level)
+/** Generates a level 1 message. */
+#define DEBUG_MSG(x) DEBUG1_MSG(x)
+/** Generates a level 1 message without indentation. */
+#define DEBUG_MSGF(x) DEBUG1_MSGF(x)
+/** Generates a level 1 message terminated with a newline. */
+#define DEBUG_MSGN(x) DEBUG_MSG(x<<'\n')
+
+//@}
+
+// ------------ THE END
+
+#ifdef HAVE_NAMESPACES
+}
+# ifndef NOT_USING_DJVU_NAMESPACE
+using namespace DJVU;
+# endif
+#endif
+
+#endif // DEBUG_H
diff --git a/kviewshell/plugins/djvu/pageRangeWidget.cpp b/kviewshell/plugins/djvu/pageRangeWidget.cpp
new file mode 100644
index 00000000..338624b8
--- /dev/null
+++ b/kviewshell/plugins/djvu/pageRangeWidget.cpp
@@ -0,0 +1,68 @@
+/***************************************************************************
+ * 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 <kdebug.h>
+
+#include "pageRangeWidget.h"
+
+
+PageRangeWidget::PageRangeWidget( Q_UINT16 _from, Q_UINT16 _to, Q_UINT16 _current, QWidget *parent, const char *name) : PageRangeWidget_base(parent, name)
+{
+ // Paranoid security checks
+ if ((from == 0) || (to == 0))
+ return;
+ if (_from > _to) {
+ kdError() << "PageRangeWidget::PageRangeWidget(..): from > to" << endl;
+ _to = _from;
+ }
+ if (_current < _from) {
+ kdError() << "PageRangeWidget::PageRangeWidget(..): _current < _from" << endl;
+ _current = _from;
+ }
+ if (_current > _to) {
+ kdError() << "PageRangeWidget::PageRangeWidget(..): _current > _to" << endl;
+ _current = _to;
+ }
+
+ connect(from, SIGNAL(valueChanged(int)), this, SLOT(fromValueChanged(int)));
+ connect(to, SIGNAL(valueChanged(int)), this, SLOT(toValueChanged(int)));
+
+ from->setRange(_from, _to);
+ from->setValue(_current);
+ to->setRange(_from, _to);
+ to->setValue(_current);
+}
+
+
+void PageRangeWidget::toValueChanged(int val)
+{
+ if (val < from->value())
+ from->setValue(val);
+}
+
+
+void PageRangeWidget::fromValueChanged(int val)
+{
+ if (val > to->value())
+ to->setValue(val);
+}
+
+#include "pageRangeWidget.moc"
+
diff --git a/kviewshell/plugins/djvu/pageRangeWidget.h b/kviewshell/plugins/djvu/pageRangeWidget.h
new file mode 100644
index 00000000..ca9b4a00
--- /dev/null
+++ b/kviewshell/plugins/djvu/pageRangeWidget.h
@@ -0,0 +1,45 @@
+/***************************************************************************
+ * 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 PAGERANGEWIDGET_H
+#define PAGERANGEWIDGET_H
+
+#include <knuminput.h>
+
+#include "pageRangeWidget_base.h"
+
+
+class PageRangeWidget : public PageRangeWidget_base
+{
+Q_OBJECT
+
+public:
+ PageRangeWidget( Q_UINT16 _from, Q_UINT16 _to, Q_UINT16 _current, QWidget *parent = 0, const char *name = 0 );
+
+ Q_UINT16 getFrom() const {return (from == 0) ? 0 : from->value(); }
+ Q_UINT16 getTo() const {return (to == 0) ? 0 : to->value(); }
+
+private slots:
+ void toValueChanged(int val);
+ void fromValueChanged(int val);
+};
+
+
+#endif // PAGERANGETOWIDGET_H
diff --git a/kviewshell/plugins/djvu/pageRangeWidget_base.ui b/kviewshell/plugins/djvu/pageRangeWidget_base.ui
new file mode 100644
index 00000000..29784c3a
--- /dev/null
+++ b/kviewshell/plugins/djvu/pageRangeWidget_base.ui
@@ -0,0 +1,75 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>PageRangeWidget_base</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>PageRangeWidget_base</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>641</width>
+ <height>49</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>fromToWidget_base</string>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>From page:</string>
+ </property>
+ </widget>
+ <widget class="KIntNumInput">
+ <property name="name">
+ <cstring>from</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>4</hsizetype>
+ <vsizetype>5</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>To page:</string>
+ </property>
+ </widget>
+ <widget class="KIntNumInput">
+ <property name="name">
+ <cstring>to</cstring>
+ </property>
+ </widget>
+ </hbox>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+</includehints>
+</UI>
diff --git a/kviewshell/plugins/djvu/prefs.kcfgc b/kviewshell/plugins/djvu/prefs.kcfgc
new file mode 100644
index 00000000..93a7650b
--- /dev/null
+++ b/kviewshell/plugins/djvu/prefs.kcfgc
@@ -0,0 +1,5 @@
+# Code generation options for kconfig_compiler
+File=djvumultipage.kcfg
+ClassName=Prefs
+Singleton=true
+Mutators=true \ No newline at end of file
diff --git a/kviewshell/renderedDocumentPage.cpp b/kviewshell/renderedDocumentPage.cpp
new file mode 100644
index 00000000..c5f0d361
--- /dev/null
+++ b/kviewshell/renderedDocumentPage.cpp
@@ -0,0 +1,375 @@
+//
+// Class: RenderedDocumentPage
+//
+// Widget for displaying TeX DVI files.
+// Part of KDVI- A previewer for TeX DVI files.
+//
+// (C) 2004 Stefan Kebekus. Distributed under the GPL.
+
+#include <config.h>
+
+#include <kdebug.h>
+
+#include "renderedDocumentPage.h"
+#include "hyperlink.h"
+#include "selection.h"
+#include "textBox.h"
+
+
+RenderedDocumentPage::RenderedDocumentPage()
+{
+ textBoxList.reserve(250);
+ pageNr = 0;
+ isEmpty = true;
+ pageText = QString::null;
+}
+
+
+RenderedDocumentPage::~RenderedDocumentPage()
+{
+ ;
+}
+
+
+void RenderedDocumentPage::setPageNumber(const PageNumber& pnr)
+{
+ pageNr = pnr;
+ clear();
+}
+
+
+void RenderedDocumentPage::clear()
+{
+#ifdef DEBUG_DOCUMENTPAGE
+ kdDebug(1223) << "RenderedDocumentPage::clear() called for page #" << pageNumber << endl;
+#endif
+
+ textBoxList.clear();
+ hyperLinkList.clear();
+ pageText = QString::null;
+
+ isEmpty = true;
+}
+
+
+QRegion RenderedDocumentPage::selectedRegion(const TextSelection& selection)
+{
+ if (selection.isEmpty() || selection.getPageNumber() != pageNr)
+ return QRegion();
+
+ int startIndex = selection.getSelectedTextStart();
+ int endIndex = selection.getSelectedTextEnd();
+
+ QValueVector<QRect> wordBox;
+
+ QRect currentWordBox;
+ //unsigned int currentBaseline = 0;
+
+ // Merge character boxes into boxes containing complete words.
+ // Note: A word in this context is defined as a string of boxes
+ // with the same baseline.
+ for (int i = startIndex; i <= endIndex; i++)
+ {
+ if (i == 0)
+ {
+ // start first word
+ currentWordBox = textBoxList[i].box;
+ //currentBaseline = textBoxList[i].baseline;
+ continue;
+ }
+
+ /*if (currentBaseline == textBoxList[i].baseline)
+ {
+ currentWordBox = currentWordBox.unite(textBoxList[i].box);
+ }
+ else*/
+ {
+ // start next word
+ wordBox.push_back(currentWordBox);
+ currentWordBox = textBoxList[i].box;
+ //currentBaseline = textBoxList[i].baseline;
+ }
+ }
+ // we still need to store the last word
+ wordBox.push_back(currentWordBox);
+
+ QValueVector<QRect> lineBox;
+
+ // Merge word boxes into boxes containing whole lines.
+ // We start a new line if we encounter a wordbox which does not
+ // vertically overlap which the current lineBox.
+ QRect currentLineBox;
+
+ for (unsigned int i = 0; i < wordBox.size(); i++)
+ {
+ if (!currentLineBox.isValid())
+ {
+ // start first line
+ currentLineBox = wordBox[i];
+ continue;
+ }
+
+ // check if there is vertical overlap
+ if (wordBox[i].top() <= currentLineBox.bottom() && wordBox[i].bottom() >= currentLineBox.top())
+ {
+ // the word belongs to the current line
+ currentLineBox = currentLineBox.unite(wordBox[i]);
+ }
+ else
+ {
+ // start next line
+ //kdDebug() << "push line (" << currentLineBox.top() << ", " << currentLineBox.bottom() << ")" << endl;
+ lineBox.push_back(currentLineBox);
+ currentLineBox = wordBox[i];
+ }
+ }
+ // we still need to store the last line
+ //kdDebug() << "push line (" << currentLineBox.top() << ", " << currentLineBox.bottom() << ")" << endl;
+ lineBox.push_back(currentLineBox);
+
+ //kdDebug() << "Number of lineboxes = " << lineBox.size() << endl;
+
+ // Now we increase the height of the lines if necessary to obtain a connected region
+ // for our selection.
+ for (unsigned int i = 0; i < lineBox.size() - 1; i++)
+ {
+ if (lineBox[i+1].top() >= lineBox[i].bottom())
+ {
+ int midPoint = (lineBox[i].bottom() + lineBox[i+1].top()) / 2;
+
+ lineBox[i].setBottom(midPoint);
+ lineBox[i+1].setTop(midPoint+1);
+ }
+ }
+
+ // Add the lineboxes to a Region
+ QRegion selectedRegion;
+ for (unsigned int i = 0; i < lineBox.size(); i++)
+ {
+ selectedRegion += QRegion(lineBox[i]);
+ }
+
+ return selectedRegion;
+}
+
+
+TextSelection RenderedDocumentPage::select(const QRect& selectedRectangle)
+{
+ int selectedTextStart = -1;
+ int selectedTextEnd = -1;
+
+ // Find the smallest and biggest index for which the corresponding
+ // textBoxList entry intersects the selected rectangle.
+ for (unsigned int i=0; i<textBoxList.size(); i++)
+ {
+ if (selectedRectangle.intersects(textBoxList[i].box))
+ {
+ if (selectedTextStart == -1)
+ selectedTextStart = i;
+ selectedTextEnd = i;
+ }
+ }
+
+ TextSelection selection;
+
+ QString selectedText;
+
+ if (selectedTextStart != -1)
+ {
+ for (int i = selectedTextStart; (i <= selectedTextEnd) && (i < (int)textBoxList.size()); i++)
+ {
+ selectedText += textBoxList[i].text;
+ }
+ selection.set(pageNr, selectedTextStart, selectedTextEnd, selectedText);
+ return selection;
+ }
+ // return empty selection
+ return selection;
+}
+
+TextSelection RenderedDocumentPage::select(const QPoint& point)
+{
+ int selectedTextStart = -1;
+ int selectedTextEnd = -1;
+
+ for (unsigned int i=0; i<textBoxList.size(); i++)
+ {
+ if (textBoxList[i].box.contains(point))
+ {
+ selectedTextStart = i;
+ selectedTextEnd = i;
+ break;
+ }
+ }
+
+ TextSelection selection;
+
+ QString selectedText;
+
+ if (selectedTextStart != -1)
+ {
+ selectedText = textBoxList[selectedTextStart].text;
+ selection.set(pageNr, selectedTextStart, selectedTextEnd, selectedText);
+ return selection;
+ }
+ // return empty selection
+ return selection;
+}
+
+TextSelection RenderedDocumentPage::find(const QString& str, int index, bool caseSensitive)
+{
+ if (pageText.isNull())
+ {
+ // Create the pageText by joining all entries of textBoxList.
+ for (QValueVector<TextBox>::Iterator i = textBoxList.begin(); i != textBoxList.end(); i++)
+ {
+ pageText = pageText + i->text;
+ }
+ }
+
+ // Create empty selection;
+ TextSelection selection;
+
+ // If the page contains no searchable text
+ if (pageText.isNull())
+ return selection;
+
+ // Compute the corresponding pageText index
+ unsigned int subIndex = 0;
+ for (int i = 0; i < index; i++)
+ {
+ subIndex += textBoxList[i].text.length();
+ }
+
+ int textIndex = pageText.find(str, subIndex, caseSensitive);
+
+ if (textIndex == -1)
+ return selection;
+
+ // Because a single Hyperlink structure can possible store more then
+ // one character we now have to search for the Indices in the
+ // textBoxList Vector which corresponds to the found index in the
+ // String pageText. FIXME: It would be faster to search directly in
+ // the textBoxList.
+ int counter = 0;
+ int startIndex = 0;
+ while (counter < textIndex)
+ {
+ counter += textBoxList[startIndex].text.length();
+ // If the string we searched for starts in the middle of some text element we better return a
+ // selection that it somewhat bigger.
+ if (counter > textIndex)
+ break;
+
+ startIndex++;
+
+ // safety check
+ if (startIndex >= (int)textBoxList.size())
+ return selection;
+ }
+
+ // Search for the end index.
+ // TODO: This algorithm is not entirely correct if str does not start exactly at the beginning of some text element.
+ counter = 0;
+ int endIndex = startIndex;
+ while (counter < (int)str.length())
+ {
+ counter += textBoxList[endIndex].text.length();
+ if (counter >= (int)str.length())
+ break;
+
+ endIndex++;
+
+ // safety check
+ if (endIndex >= (int)textBoxList.size())
+ return selection;
+ }
+
+ // Set the selection
+ selection.set(pageNr, startIndex, endIndex, str);
+ return selection;
+}
+
+
+TextSelection RenderedDocumentPage::findRev(const QString& str, int index, bool caseSensitive)
+{
+ // Negative index means we start the search at the end of the text.
+ if (index < 0)
+ {
+ index = textBoxList.size();
+ }
+
+ if (pageText.isNull())
+ {
+ // Create the pageText by joining all entries of textBoxList.
+ for (QValueVector<TextBox>::Iterator i = textBoxList.begin(); i != textBoxList.end(); i++)
+ {
+ pageText = pageText + i->text;
+ }
+ }
+
+ // Create empty selection;
+ TextSelection selection;
+
+ // If the page contains no searchable text
+ if (pageText.isNull())
+ return selection;
+
+ // Compute the corresponding pageText index
+ unsigned int subIndex = 0;
+ for (int i = 0; i < index; i++)
+ {
+ subIndex += textBoxList[i].text.length();
+ }
+
+ int textIndex = pageText.findRev(str, subIndex, caseSensitive);
+
+ if (textIndex == -1)
+ return selection;
+
+ // Because a single Hyperlink structure can possible store more then
+ // one character we now have to search for the Indices in the
+ // textBoxList Vector which corresponds to the found index in the
+ // String pageText. FIXME: It would be faster to search directly in
+ // the textBoxList.
+ int counter = 0;
+ int startIndex = 0;
+ while (counter < textIndex)
+ {
+ counter += textBoxList[startIndex].text.length();
+ // If the string we searched for starts in the middle of some text element we better return a
+ // selection that it somewhat bigger.
+ if (counter > textIndex)
+ break;
+
+ startIndex++;
+
+ // safety check
+ if (startIndex >= (int)textBoxList.size())
+ return selection;
+ }
+
+ // Search for the end index.
+ // TODO: This algorithm is not entirely correct if str does not start exactly at the beginning of some text element.
+ counter = 0;
+ int endIndex = startIndex;
+ while (counter < (int)str.length())
+ {
+ counter += textBoxList[endIndex].text.length();
+ if (counter >= (int)str.length())
+ break;
+
+ endIndex++;
+
+ // safety check
+ if (endIndex >= (int)textBoxList.size())
+ return selection;
+ }
+
+ // Set the selection
+ selection.set(pageNr, startIndex, endIndex, str);
+ return selection;
+}
+
+#include "renderedDocumentPage.moc"
+
diff --git a/kviewshell/renderedDocumentPage.h b/kviewshell/renderedDocumentPage.h
new file mode 100644
index 00000000..f91144cc
--- /dev/null
+++ b/kviewshell/renderedDocumentPage.h
@@ -0,0 +1,241 @@
+// -*- C++ -*-
+//
+// Class: documentPage
+//
+// Widget for displaying TeX DVI files.
+// Part of KDVI- A previewer for TeX DVI files.
+//
+// (C) 2004-2005 Stefan Kebekus. Distributed under the GPL.
+
+
+#ifndef _rendereddocumentpage_h_
+#define _rendereddocumentpage_h_
+
+#include "pageNumber.h"
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qvaluevector.h>
+
+class Hyperlink;
+class QPainter;
+class QRect;
+class QRegion;
+class TextBox;
+class TextSelection;
+
+/** @short Represents a page in a document, contains the page's graphical
+ representation and resolution-dependent information.
+
+ This abstract class represents a page in a document. Its
+ implementations contain graphical representations of document pages,
+ and resolution-dependent information. The most important members are
+
+ - the page number
+
+ - a vector that contains hyperlinks
+
+ - a vector for source hyperlinks; this vector is currently used by
+ KDVI only, and is therefore not documented much here.
+
+ - a vector that contains the document text together with
+ information about the position of the text on the page. This
+ information is used in kviewshell e.g. for selecting text with the
+ mouse or for the "export as text..." functionality
+
+ - the implementations of the documentPage will also contain a
+ QPaintDevice, onto which the graphical representation of the page
+ is rendered. This could for instance be a QPixmap, if the page is
+ to be displayed on a computer screen, or a QPrinter for printing.
+
+ The kviewshell program uses the documentPage class in the
+ following manner: first, it is constructed, the page number is
+ invalid. The page number is then set to a reasonable value using
+ the setPageNumber() method. After this, the
+ documentRenderer.drawPage() method of an implementation of the
+ documentRenderer is used to render a graphical representation into
+ the QPaintDevice at a given resolution, and to fill the
+ (source-)hyperlink and text vectors, which are also
+ resolution-dependent. After the data has been used, the
+ documentPage is clear()ed, perhaps a new page number set, and
+ documentRenderer.drawPage() is used again.
+
+ @author Stefan Kebekus <kebekus@kde.org>
+ @version 1.0.0
+*/
+
+class RenderedDocumentPage : public QObject
+{
+ Q_OBJECT
+
+ public:
+ /** \brief Default constructor
+
+ The default constructor constructs a RenderedDocumentPage whose pageNumber
+ is invalid. It sets the member 'isEmpty' to 'true'.
+ */
+ RenderedDocumentPage();
+
+ virtual ~RenderedDocumentPage();
+
+ /** \brief Set page number
+
+ This method sets the number of the page that this instance
+ represents. A value of '0' means that this class does not represent
+ any page ('invalid page'). This method also calls clear().
+ */
+ void setPageNumber(const PageNumber& pagenr);
+
+ /** \brief Get page number
+
+ @returns The number of the page that this instance represents.
+ */
+ PageNumber getPageNumber() const {return pageNr;}
+
+ /** \brief Get paint device
+
+ This method is used for instance by the documentRenderer.drawPage()
+ method to draw on the page. It returns a pointer to a QPainter (in
+ most implementation a painter on either a QPixmap, or a
+ QPrinter). The pointer returned points to an active QPainter and is
+ valid as long as *this RenderedDocumentPage exists. The pointer
+ returned must not be deleted nor should QPainter::end() be
+ called. Instead, the method returnPainter() must be called as soon
+ as drawing is finished.
+
+ In short, to draw on a renderedDocumentPage, you do the following:
+ @code
+ RenderedDocumentPage rdp;
+
+ QPainter *paint = rdp.getPainter()
+ if (paint != 0) {
+
+ <Do some painting, don't call paint->end() >
+
+ rdp.returnPainter(paint);
+ }
+ @endcode
+
+ @warning Before the pointer has been returned by the returnPainter()
+ method, all subsequent calls to getPainter() will return undefined
+ results. Do not delete a renderedDocumentPage when you still hold a
+ pointer. Call returnPainter() first.
+
+ @returns A pointer to a QPainter (in most implementation a painter
+ on either a QPixmap, or a QPrinter), or NULL, if painting is not
+ possible. The QPainter object is owned by the RenderedDocumentPage.
+ */
+ virtual QPainter *getPainter() = 0;
+
+
+ /** \brief Returns a pointer to the paint device.
+
+ See the documentation to the getPainter() method for an explanation
+
+ @see getPainter
+
+ @warning Returning a pointer twice, or returning arbitrary pointers
+ will lead to a segfault.
+
+ @param pt a pointer to a QPainter, as returned by the getPainter()
+ method
+ */
+ virtual void returnPainter(QPainter *pt) = 0;
+
+ /** \brief Returns the size of the page in pixel. */
+ virtual QSize size() = 0;
+
+ /** \brief Returns the width of the page in pixel.
+
+ @warning If you are implementing DocumentRenderer::drawPage(), it
+ may be tempting to compute the image size in pixel, using
+ page->height() and page->width(). DON'T DO THAT. KViewShell uses
+ transformations e.g. to rotate the page, and sets the argument
+ 'resolution' accordingly; these changes are not reflected in
+ page->height() and page->width(). Similar problems occur if
+ KViewShell required a shrunken version of the page, e.g. to print
+ multiple pages on one sheet of paper. See the documentation of
+ DocumentRenderer::drawPage() to learn how to compute the sizes
+ properly.
+ */
+ virtual int width() {return size().width(); }
+
+ /** \brief Returns the height of the page in pixel.
+
+ @warning If you are implementing DocumentRenderer::drawPage(), it
+ may be tempting to compute the image size in pixel, using
+ page->height() and page->width(). DON'T DO THAT. KViewShell uses
+ transformations e.g. to rotate the page, and sets the argument
+ 'resolution' accordingly; these changes are not reflected in
+ page->height() and page->width(). Similar problems occur if
+ KViewShell required a shrunken version of the page, e.g. to print
+ multiple pages on one sheet of paper. See the documentation of
+ DocumentRenderer::drawPage() to learn how to compute the sizes
+ properly.
+ */
+ virtual int height() {return size().height(); }
+
+ /** \brief Text contained in the document page
+
+ This vector contains the document text together with information
+ about the position of the text on the page. This information is
+ generated by the documentRenderer.drawPage() method. It is used in
+ kviewshell e.g. for selecting text with the mouse or for the "export
+ as text..." functionality.
+ */
+ QValueVector<TextBox> textBoxList;
+
+ /** \brief Calculates the text selected by the given rectangle. */
+ TextSelection select(const QRect&);
+
+ /** \brief Selects the character which lies at the given point. */
+ TextSelection select(const QPoint&);
+
+ QRegion selectedRegion(const TextSelection& selection);
+
+ /** Finds the first occurence of str starting by the current index.
+ If the text is found a corresponding TextSelection is returned.
+ If the text is not found a empty selection is returned. */
+ TextSelection find(const QString& str, int index = 0, bool caseSensitive = true);
+
+ /** Finds the first occurence of str starting by the current index searching backwards.
+ If the text is found a corresponding TextSelection is returned.
+ If the text is not found a empty selection is returned.
+ If index < 0 start the search at the end of the page. */
+ TextSelection findRev(const QString& str, int index = 0, bool cs = true);
+
+ /** \brief Hyperlinks on the document page
+
+ This vector contains the hyperlinks that appear on the page. This
+ information is generated by the documentRenderer.drawPage()
+ method. It is used in kviewshell so users can use the mouse to
+ navigate in the document through hyperlinks.
+ */
+ QValueVector<Hyperlink> hyperLinkList;
+
+ // set to 'false' in the constructor, set to 'true' by the renderer,
+ // if something really has been rendered
+ bool isEmpty;
+
+ /** \brief Clears the data structures
+
+ Clears the contents of the class, but leaves pageNumber intact. For
+ performance reasons, it does not free the memory for the
+ QValueVectors so that lengthy re-allocations won't be necessary
+ later.
+ */
+ virtual void clear();
+
+ private:
+ /** \brief Page number
+
+ Number of the page that this instance represents a value of '0'
+ means that this class does not represent any page.
+ */
+ PageNumber pageNr;
+
+ QString pageText;
+};
+
+
+#endif
diff --git a/kviewshell/renderedDocumentPagePixmap.cpp b/kviewshell/renderedDocumentPagePixmap.cpp
new file mode 100644
index 00000000..aaa06878
--- /dev/null
+++ b/kviewshell/renderedDocumentPagePixmap.cpp
@@ -0,0 +1,122 @@
+
+/* This file is part of the KDE project
+ Copyright (C) 2005 Wilfried Huss <Wilfried.Huss@gmx.at>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <config.h>
+
+#include <kimageeffect.h>
+#include <kdebug.h>
+#include <qimage.h>
+
+#include "kvsprefs.h"
+#include "renderedDocumentPagePixmap.h"
+
+RenderedDocumentPagePixmap::RenderedDocumentPagePixmap()
+ : _accessiblePixmap(0), dirty(true)
+{
+}
+
+RenderedDocumentPagePixmap::~RenderedDocumentPagePixmap()
+{
+ delete _accessiblePixmap;
+}
+
+
+QPainter* RenderedDocumentPagePixmap::getPainter()
+{
+ if (paintingActive()) {
+ kdError(1223) << "RenderedDocumentPagePixmap::getPainter() called when painting was active" << endl;
+ return 0;
+ } else
+ return new QPainter(this);
+}
+
+
+void RenderedDocumentPagePixmap::resize(int width, int height)
+{
+ QPixmap::resize(width, height);
+ if(_accessiblePixmap)
+ _accessiblePixmap->resize(width, height);
+
+ dirty = true;
+}
+
+void RenderedDocumentPagePixmap::resize(const QSize& size)
+{
+ resize(size.width(), size.height());
+}
+
+QPixmap RenderedDocumentPagePixmap::accessiblePixmap()
+{
+ if (!_accessiblePixmap || dirty)
+ {
+ QImage backImage = this->convertToImage();
+ switch (KVSPrefs::renderMode())
+ {
+ case KVSPrefs::EnumRenderMode::Inverted:
+ // Invert image pixels using QImage internal function
+ backImage.invertPixels(false);
+ break;
+ case KVSPrefs::EnumRenderMode::Recolor:
+ // Recolor image using KImageEffect::flatten with dither:0
+ KImageEffect::flatten(backImage, KVSPrefs::recolorForeground(), KVSPrefs::recolorBackground());
+ break;
+ case KVSPrefs::EnumRenderMode::BlackWhite:
+ // Manual Gray and Contrast
+ unsigned int* data = (unsigned int*)backImage.bits();
+ int val;
+ int pixels = backImage.width() * backImage.height();
+ int con = KVSPrefs::bWContrast();
+ int thr = 255 - KVSPrefs::bWThreshold();
+
+ for( int i = 0; i < pixels; ++i )
+ {
+ val = qGray(data[i]);
+ if (val > thr)
+ val = 128 + (127 * (val - thr)) / (255 - thr);
+ else if ( val < thr )
+ val = (128 * val) / thr;
+ if (con > 2)
+ {
+ val = con * (val - thr) / 2 + thr;
+ if (val > 255)
+ val = 255;
+ else if (val < 0)
+ val = 0;
+ }
+ data[i] = qRgba(val, val, val, 255);
+ }
+ break;
+ }
+ if (!_accessiblePixmap)
+ _accessiblePixmap = new QPixmap(width(), height());
+
+ _accessiblePixmap->convertFromImage(backImage);
+ dirty = false;
+ }
+
+ return *_accessiblePixmap;
+}
+
+unsigned int RenderedDocumentPagePixmap::memory()
+{
+ return size().height() * size().width() * depth() / 8;
+}
+
+#include "renderedDocumentPagePixmap.moc"
diff --git a/kviewshell/renderedDocumentPagePixmap.h b/kviewshell/renderedDocumentPagePixmap.h
new file mode 100644
index 00000000..112650ba
--- /dev/null
+++ b/kviewshell/renderedDocumentPagePixmap.h
@@ -0,0 +1,59 @@
+// -*- C++ -*-
+//
+// Class: RenderedDocumentPagePixmap
+//
+// Widget for displaying TeX DVI files.
+// Part of KDVI- A previewer for TeX DVI files.
+//
+// (C) 2004-2005 Stefan Kebekus. Distributed under the GPL.
+
+
+#ifndef _rendereddocumentpagepixmap_h_
+#define _rendereddocumentpagepixmap_h_
+
+#include "renderedDocumentPage.h"
+
+#include <qpainter.h>
+#include <qpixmap.h>
+
+
+// This class contains everything documentRenderer needs to know
+// about a certain page.
+class RenderedDocumentPagePixmap: public RenderedDocumentPage, public QPixmap
+{
+ Q_OBJECT
+
+public:
+ RenderedDocumentPagePixmap();
+
+ virtual ~RenderedDocumentPagePixmap();
+
+ /** Returns a pointer to the paintDevice (in most implementation
+ either a QPixmap, or a QPrinter). The pointer returned is valid
+ as long as *this RenderedDocumentPage exists. This method is
+ used by the renderer to draw on the page. */
+ virtual QPainter *getPainter();
+
+ /** This implementation delete the QPainter *pt (and thereby initiates the drawing) */
+ virtual void returnPainter(QPainter *pt) {delete pt;}
+
+ QPixmap accessiblePixmap();
+
+ void resize(const QSize& size);
+ void resize(int width, int height);
+
+ virtual QSize size() { return QPixmap::size(); }
+ virtual int width() { return QPixmap::width(); }
+ virtual int height() { return QPixmap::height(); }
+
+ /** Returns the amount of memory used by this pixmap */
+ unsigned int memory();
+
+private:
+ QPixmap* _accessiblePixmap;
+ /** true if _accessiblePixmap needs updateing */
+ bool dirty;
+};
+
+
+#endif
diff --git a/kviewshell/renderedDocumentPagePrinter.cpp b/kviewshell/renderedDocumentPagePrinter.cpp
new file mode 100644
index 00000000..6e0ba57a
--- /dev/null
+++ b/kviewshell/renderedDocumentPagePrinter.cpp
@@ -0,0 +1,53 @@
+
+/* This file is part of the KDE project
+ Copyright (C) 2005 Stefan Kebekus <kebekus@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <config.h>
+
+#include <kdebug.h>
+#include <qguardedptr.h>
+#include <qpaintdevicemetrics.h>
+#include <kprinter.h>
+
+#include "renderedDocumentPagePrinter.h"
+
+RenderedDocumentPagePrinter::RenderedDocumentPagePrinter(KPrinter *kp)
+{
+ printer = kp;
+ printerPainter = 0;
+
+ if (printer == 0) {
+ kdError(1223) << "RenderedDocumentPagePrinter::RenderedDocumentPagePixmap() called with printer == 0" << endl;
+ return;
+ }
+
+ printerPainter = new QPainter(printer);
+}
+
+
+QSize RenderedDocumentPagePrinter::size()
+{
+ if (printer == 0) {
+ kdError(1223) << "RenderedDocumentPagePrinter::size() called with printer == 0" << endl;
+ return QSize(0,0);
+ }
+
+ QPaintDeviceMetrics pdm( printer );
+ return QSize(pdm.width(), pdm.height());
+}
diff --git a/kviewshell/renderedDocumentPagePrinter.h b/kviewshell/renderedDocumentPagePrinter.h
new file mode 100644
index 00000000..44bdc6d2
--- /dev/null
+++ b/kviewshell/renderedDocumentPagePrinter.h
@@ -0,0 +1,46 @@
+// -*- C++ -*-
+//
+// Class: RenderedDocumentPagePrinter
+//
+// Widget for displaying TeX DVI files.
+// Part of KDVI- A previewer for TeX DVI files.
+//
+// (C) 2005 Stefan Kebekus. Distributed under the GPL.
+
+
+#ifndef _rendereddocumentpageprinter_h_
+#define _rendereddocumentpageprinter_h_
+
+#include "renderedDocumentPage.h"
+#include <qpainter.h>
+
+class KPrinter;
+
+
+class RenderedDocumentPagePrinter: public RenderedDocumentPage
+{
+public:
+ RenderedDocumentPagePrinter(KPrinter *kp);
+
+ virtual ~RenderedDocumentPagePrinter() { delete printerPainter; }
+
+ /** Returns a pointer to the paintDevice, in this implementation
+ either a QPrinter. The pointer returned is valid as long as
+ *this RenderedDocumentPage exists. This method is used by the
+ renderer to draw on the page. */
+ virtual QPainter *getPainter() { return printerPainter; }
+
+ virtual QSize size();
+
+ /** This method does nothing. In particular, it does NOT delete the
+ QPainter. The QPainter is deleted automatically when this
+ RenderedDocumentPagePrinter is destructed. */
+ virtual void returnPainter(QPainter *) {;}
+
+private:
+ KPrinter *printer;
+ QPainter *printerPainter;
+};
+
+
+#endif
diff --git a/kviewshell/searchWidget.cpp b/kviewshell/searchWidget.cpp
new file mode 100644
index 00000000..7c4422e6
--- /dev/null
+++ b/kviewshell/searchWidget.cpp
@@ -0,0 +1,141 @@
+/***************************************************************************
+ * 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 <config.h>
+
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qcheckbox.h>
+#include <qlayout.h>
+#include <qtooltip.h>
+#include <qwhatsthis.h>
+
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include <klineedit.h>
+
+
+#include "searchWidget.h"
+
+SearchWidget::SearchWidget(QWidget* parent, const char* name, WFlags fl)
+ : QWidget(parent, name, fl)
+{
+ setName("SearchWidget");
+
+ setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);
+
+ layout = new QHBoxLayout(this, 4, 6, "SearchWidgetLayout");
+
+ stopButton = new QPushButton(this, "stopButton");
+ stopButton->setPixmap(KGlobal::iconLoader()->loadIcon("stop", KIcon::Small, KIcon::SizeSmall));
+ layout->addWidget(stopButton);
+
+ searchLabel = new QLabel(this, "searchLabel");
+ searchLabel->setText(i18n("Search:"));
+ layout->addWidget(searchLabel);
+
+ searchText = new KLineEdit(this, "searchText");
+ layout->addWidget(searchText);
+
+ searchLabel->setBuddy(searchText);
+
+ findPrevButton = new QPushButton(this, "findPrevButton");
+ findPrevButton->setPixmap(KGlobal::iconLoader()->loadIcon("back", KIcon::NoGroup, KIcon::SizeSmall));
+ QToolTip::add(findPrevButton, i18n("Find previous"));
+ layout->addWidget(findPrevButton);
+
+ findNextButton = new QPushButton(this, "findNextButton");
+ findNextButton->setPixmap(KGlobal::iconLoader()->loadIcon("forward", KIcon::NoGroup, KIcon::SizeSmall));
+ QToolTip::add(findNextButton, i18n("Find next"));
+ layout->addWidget(findNextButton);
+
+ caseSensitiveCheckBox = new QCheckBox(this, "caseSensitiveCheckBox");
+ caseSensitiveCheckBox->setText(i18n("Case sensitive"));
+ layout->addWidget(caseSensitiveCheckBox);
+
+ connect(stopButton, SIGNAL(clicked()), this, SIGNAL(stopSearch()));
+
+ connect(findNextButton, SIGNAL(clicked()), this, SIGNAL(findNextText()));
+ connect(findPrevButton, SIGNAL(clicked()), this, SIGNAL(findPrevText()));
+
+ connect(searchText, SIGNAL(textChanged(const QString&)), this, SLOT(textChanged()));
+
+ textChanged();
+}
+
+SearchWidget::~SearchWidget()
+{
+}
+
+QString SearchWidget::getText() const
+{
+ return searchText->text();
+}
+
+bool SearchWidget::caseSensitive() const
+{
+ return caseSensitiveCheckBox->isChecked();
+}
+
+void SearchWidget::textChanged()
+{
+ bool empty = searchText->text().isEmpty();
+
+ findNextButton->setDisabled(empty);
+ findPrevButton->setDisabled(empty);
+ emit searchEnabled(!empty);
+}
+
+void SearchWidget::show()
+{
+ searchText->setEnabled(true);
+ searchText->selectAll();
+ QWidget::show();
+ emit searchEnabled(!searchText->text().isEmpty());
+}
+
+void SearchWidget::hide()
+{
+ searchText->setEnabled(false);
+ QWidget::hide();
+}
+
+void SearchWidget::setFocus()
+{
+ searchText->setFocus();
+}
+
+void SearchWidget::keyPressEvent(QKeyEvent* e)
+{
+ if (e->key() == Qt::Key_Escape)
+ emit stopSearch();
+
+ if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter)
+ {
+ if (e->state() == Qt::ShiftButton)
+ emit findPrevText();
+ else
+ emit findNextText();
+ }
+}
+
+#include "searchWidget.moc"
diff --git a/kviewshell/searchWidget.h b/kviewshell/searchWidget.h
new file mode 100644
index 00000000..49b2c5cb
--- /dev/null
+++ b/kviewshell/searchWidget.h
@@ -0,0 +1,73 @@
+// -*- C++ -*-
+/***************************************************************************
+ * 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 SEARCHWIDGET_H
+#define SEARCHWIDGET_H
+
+#include <qwidget.h>
+
+class QHBoxLayout;
+class QLabel;
+class KLineEdit;
+class QPushButton;
+class QCheckBox;
+class QString;
+
+class SearchWidget : public QWidget
+{
+ Q_OBJECT
+
+public:
+ SearchWidget(QWidget* parent = 0, const char* name = 0, WFlags fl = 0);
+ ~SearchWidget();
+
+ QString getText() const;
+ bool caseSensitive() const;
+
+public slots:
+ virtual void setFocus();
+ virtual void show();
+ virtual void hide();
+
+signals:
+ void findNextText();
+ void findPrevText();
+ void searchEnabled(bool);
+ void stopSearch();
+
+protected:
+ virtual void keyPressEvent(QKeyEvent*);
+
+private slots:
+ void textChanged();
+
+private:
+ QPushButton* stopButton;
+ QLabel* searchLabel;
+ KLineEdit* searchText;
+ QPushButton* findNextButton;
+ QPushButton* findPrevButton;
+ QCheckBox* caseSensitiveCheckBox;
+
+ QHBoxLayout* layout;
+};
+
+#endif
diff --git a/kviewshell/selection.cpp b/kviewshell/selection.cpp
new file mode 100644
index 00000000..be288fe0
--- /dev/null
+++ b/kviewshell/selection.cpp
@@ -0,0 +1,66 @@
+//
+// selection.cpp
+//
+// Part of KDVI - A previewer for TeX DVI files.
+//
+// (C) 2001--2004 Stefan Kebekus
+// Distributed under the GPL
+
+#include <config.h>
+
+#include <qapplication.h>
+#include <qclipboard.h>
+
+#include "selection.h"
+
+TextSelection::TextSelection()
+ : page(PageNumber::invalidPage),
+ selectedText(QString::null)
+{}
+
+
+void TextSelection::set(const PageNumber& pageNr, Q_INT32 start, Q_INT32 end, const QString& text)
+{
+ page = pageNr;
+ selectedTextStart = start;
+ selectedTextEnd = end;
+ if (page != 0)
+ selectedText = text;
+ else
+ selectedText = QString::null;
+
+ if (page != 0) {
+ QApplication::clipboard()->setSelectionMode(true);
+ QApplication::clipboard()->setText(selectedText);
+ }
+}
+
+
+bool TextSelection::operator== (const TextSelection& s) const
+{
+ // We don't check if the strings are equal because for corretly constructed selection objects this is always
+ // the case if the following condition holds.
+ return (page == s.page && selectedTextStart == s.selectedTextStart && selectedTextEnd == s.selectedTextEnd);
+}
+
+
+bool TextSelection::operator!= (const TextSelection& s) const
+{
+ return !(*this == s);
+}
+
+
+void TextSelection::copyText() const
+{
+ if (!isEmpty()) {
+ QApplication::clipboard()->setSelectionMode(false);
+ QApplication::clipboard()->setText(selectedText);
+ }
+}
+
+
+void TextSelection::clear()
+{
+ set(0, -1, -1, QString::null);
+}
+
diff --git a/kviewshell/selection.h b/kviewshell/selection.h
new file mode 100644
index 00000000..23261d49
--- /dev/null
+++ b/kviewshell/selection.h
@@ -0,0 +1,86 @@
+// -*- C++ -*-
+//
+// selection.h
+//
+// (C) 2001-20004 Stefan Kebekus
+// Distributed under the GPL
+
+#ifndef selection_h
+#define selection_h
+
+#include "pageNumber.h"
+
+#include <qstring.h>
+
+
+/* The --very simple-- class TextSelection represents text that the
+ user has selected on a certain page of a document. The class stores
+
+ the page number,
+
+ two Q_INT32 numbers, 'selectedTextStart' and 'selectedTextEnd' that
+ should hold indiced referring to the start and the end of the
+ selected text in the appropriate documentPage's textLinkList
+
+ a QString, 'selectedText' that holds the text that is selected
+
+ these values can be stored, retrieved, it can be checked if the
+ selection is empty, and signals are emitted when the values change
+ */
+
+class TextSelection
+{
+
+public:
+ // Constructs an empty selection with an invalid page number, and an
+ // empty text string. The values 'selectedTextStart' and
+ // 'selectedTextEnd' are set to 0. None of the signals pageChanged()
+ // or selectionIsNotEmpty() is emitted at construction time
+ TextSelection();
+
+ void clear();
+
+ // Use this method to set the data that is described above. Note
+ // that the consistency of 'pageNr' 'selectedTextStart' and
+ // 'selectedTextEnd' are not checked; it is entirely of the program
+ // that calls this method to make sure that it sets reasonable
+ // values; it is not even checked if selectedTextStart <=
+ // selectedTextEnd! The signals pageChanged() and
+ // selectionIsNotEmpty() are emitted if appropriate.
+ void set(const PageNumber& pageNr, Q_INT32 selectedTextStart, Q_INT32 selectedTextEnd, const QString& text);
+
+ // This method can be used to find out if the selection is empty,
+ // i.e. if the page number is invalid or the selected text is empty.
+ bool isEmpty() const {return (!page.isValid() || selectedText.isEmpty());}
+
+ // Method used to retrieve the data described above
+ Q_INT32 getSelectedTextStart() const {return selectedTextStart;}
+
+ // Method used to retrieve the data described above
+ Q_INT32 getSelectedTextEnd() const {return selectedTextEnd;}
+
+ // Method used to retrieve the data described above
+ const QString &getSelectedText() const {return selectedText;}
+
+ // Method used to retrieve the data described above
+ PageNumber getPageNumber() const {return page;}
+
+ // If the selection is not empty, this method copies the text to the
+ // system clipboard. If the selection is empty, nothing is done.
+ void copyText() const;
+
+ bool operator== (const TextSelection&) const;
+ bool operator!= (const TextSelection&) const;
+
+ private:
+ // Described above
+ PageNumber page;
+
+ // Described above
+ Q_INT32 selectedTextStart, selectedTextEnd;
+
+ // Described above
+ QString selectedText;
+};
+
+#endif
diff --git a/kviewshell/simplePageSize.cpp b/kviewshell/simplePageSize.cpp
new file mode 100644
index 00000000..cc235ef8
--- /dev/null
+++ b/kviewshell/simplePageSize.cpp
@@ -0,0 +1,49 @@
+// SimplePageSize.cpp
+//
+// Part of KVIEWSHELL - A framework for multipage text/gfx viewers
+//
+// (C) 2002-2005 Stefan Kebekus
+// Distributed under the GPL
+
+// Add header files alphabetically
+
+#include <config.h>
+
+#include <kdebug.h>
+#include <qpaintdevice.h>
+
+#include "simplePageSize.h"
+
+
+double SimplePageSize::zoomForHeight(Q_UINT32 height) const
+{
+ if (!isValid()) {
+ kdError(1223) << "SimplePageSize::zoomForHeight() called when paper height was invalid" << endl;
+ return 0.1;
+ }
+ return (double)(height)/(QPaintDevice::x11AppDpiY()*(pageHeight.getLength_in_inch()));
+}
+
+
+double SimplePageSize::zoomForWidth(Q_UINT32 width) const
+{
+ if (!isValid()) {
+ kdError(1223) << "SimplePageSize::zoomForWidth() called when paper width was invalid" << endl;
+ return 0.1;
+ }
+ return (double)(width)/(QPaintDevice::x11AppDpiX()*(pageWidth.getLength_in_inch()));
+}
+
+
+double SimplePageSize::zoomToFitInto(const SimplePageSize &target) const
+{
+ if (!isValid() || isSmall() || !target.isValid()) {
+ kdWarning(1223) << "SimplePageSize::zoomToFitInto(...) with unsuitable source of target" << endl;
+ return 1.0;
+ }
+
+ double z1 = target.width() / pageWidth;
+ double z2 = target.height() / pageHeight;
+
+ return QMIN(z1,z2);
+}
diff --git a/kviewshell/simplePageSize.h b/kviewshell/simplePageSize.h
new file mode 100644
index 00000000..bd5f9ca8
--- /dev/null
+++ b/kviewshell/simplePageSize.h
@@ -0,0 +1,164 @@
+// -*- C++ -*-
+//
+// simplePageSize.h
+//
+// Part of KVIEWSHELL - A framework for multipage text/gfx viewers
+//
+// (C) 2002-2004 Stefan Kebekus
+// Distributed under the GPL
+
+
+#ifndef SIMPLEPAGESIZE_H
+#define SIMPLEPAGESIZE_H
+
+#include "length.h"
+
+#include <qsize.h>
+
+class QString;
+class QStringList;
+
+
+/** \brief This class represents phyiscal page sizes.
+
+This class represents page sizes. It contains nothing but two numbers,
+the page width, and page height, and a few utility functions that
+convert page sizes to pixel sizes and to compute the aspect ratio. A
+page with width<=1mm or height<=1mm is considered invalid. pageSize is
+a more elaborate class that is derived from SimplePageSize and knows
+about standard paper sizes.
+
+@author Stefan Kebekus <kebekus@kde.org>
+@version 1.0 0
+*/
+
+class SimplePageSize
+{
+ public:
+ /** Constructs an invalid SimplePageSize, with size 0x0mm */
+ SimplePageSize() { pageWidth.setLength_in_mm(0.0); pageHeight.setLength_in_mm(0.0); }
+
+ /** Constructs a SimplePagesize with given page width and height in
+ mm. Recall that if width or height is less or equal than 1mm,
+ the page size is considered 'invalid' by the isValid()
+ method.
+
+ @param width
+ @param height
+ */
+ SimplePageSize(const Length& width, const Length& height) { pageWidth = width; pageHeight = height; }
+
+ /** \brief Sets the page width and height
+
+ If width or height is less or equal than 1mm, the page size is
+ considered 'invalid' by the isValid() method.
+
+ @param width
+ @param height
+ */
+ virtual void setPageSize(const Length& width, const Length& height) { pageWidth = width; pageHeight = height; }
+
+ /** \brief Returns the page width. */
+ Length width() const { return pageWidth; }
+
+ /** \brief Returns the page height. */
+ Length height() const { return pageHeight; }
+
+ /** \brief Aspect ratio
+
+ @returns if the paper size is valid, this method returns the ratio
+ width/height. Returns 1.0 otherwise. */
+ double aspectRatio() const { return isValid() ? (pageWidth/pageHeight) : 1.0; }
+
+ /** \brief Converts the physical page size to a pixel size
+
+ @param resolution in dots per inch
+
+ @returns the pixel size, represented by a QSize. If the page size is
+ invalid, the result is undefined. */
+ QSize sizeInPixel(double resolution) const {return QSize( (int)(resolution*pageWidth.getLength_in_inch() + 0.5),
+ (int)(resolution*pageHeight.getLength_in_inch() + 0.5)); }
+
+ /** \brief Zoom value required to scale to a certain height
+
+ If the pageSize is valid, this method returns the zoom value
+ required to scale the page size down to 'height' pixels on the
+ currently used display. The method uses QPaintDevice::x11AppDpiY()
+ to find the resolution of the display. If the pageSize is invalid,
+ an error message is printed, and an undefined value is returned.
+
+ @param height target height in pixels
+
+ @returns the zoom value required to scale the page size down to
+ 'height' pixels. If the pageSize is invalid, an undefined value is
+ returned.
+ */
+ double zoomForHeight(Q_UINT32 height) const;
+
+ /** \brief Zoom value required to scale to a certain height
+
+ If the pageSize is valid, this method returns the zoom value
+ required to scale the page size down to 'width' pixels on the
+ currently used display. The method uses QPaintDevice::x11AppDpiX()
+ to find the resolution of the display. If the pageSize is invalid,
+ an error message is printed, and an undefined value is returned.
+
+ @param width target width in pixels
+
+ @returns the zoom value required to scale the page size down to
+ 'width' pixels. If the pageSize is invalid, an undefined value is
+ returned.
+ */
+ double zoomForWidth(Q_UINT32 width) const;
+
+ /** \brief Returns a zoom to fit into a certain page size
+
+ This method computes the larget zoom value such that *this, zoomed
+ by the computed values fits into the page size 'target'. If *this or
+ if target are invalid, or is this->isSmall() is true, an undefined
+ value is returned. If height or width of this is nearly 0.0, a
+ floating point exception may occur.
+ */
+ double zoomToFitInto(const SimplePageSize &target) const;
+
+ /** \brief Validity check
+
+ @returns 'True' if the page width and height are both larger than
+ 1mm */
+ bool isValid() const { return ( (pageWidth.getLength_in_mm() > 1.0) && (pageHeight.getLength_in_mm() > 1.0) ); }
+
+ /** \brief Validity check:
+
+ @returns 'True' if the page ares is less than 1.0 square mm
+ */
+ bool isSmall() const { return (pageWidth.getLength_in_mm()*pageHeight.getLength_in_mm() < 1.0); }
+
+ /** \brief Approximate equality
+
+ @param size pageSize object to compare this object with
+
+ @returns 'True' if height and width of the two obejcts differ by at
+ most 2mm, 'false' otherwise
+ */
+ bool isNearlyEqual(const SimplePageSize &size) const {return (pageWidth.isNearlyEqual(size.pageWidth) && pageHeight.isNearlyEqual(size.pageHeight)); }
+
+ /** Test if paper size is higher than wide
+
+ @returns 'True' if the paper size is higher than wide
+ */
+ bool isPortrait() const { return (pageHeight >= pageWidth);}
+
+ /** Rotates by 90 degrees
+
+ @returns a SimplePageSize with height and width swapped. The
+ original instance is unchanged.
+ */
+ SimplePageSize rotate90() const { return SimplePageSize(pageHeight, pageWidth);}
+
+ protected:
+ Length pageWidth;
+ Length pageHeight;
+};
+
+
+#endif
diff --git a/kviewshell/sizePreview.cpp b/kviewshell/sizePreview.cpp
new file mode 100644
index 00000000..e6d56715
--- /dev/null
+++ b/kviewshell/sizePreview.cpp
@@ -0,0 +1,134 @@
+// SizePreview.cpp
+//
+// Part of KVIEWSHELL - A framework for multipage text/gfx viewers
+//
+// (C) 2002 Stefan Kebekus
+// Distributed under the GPL
+
+// Add header files alphabetically
+
+#include <config.h>
+
+#include <kdebug.h>
+#include <krandomsequence.h>
+#include <qevent.h>
+#include <qpainter.h>
+
+#include "sizePreview.h"
+
+#include "simplePageSize.h"
+
+SizePreview::SizePreview( QWidget *parent, const char *name, WFlags)
+ : QWidget( parent, name, WStaticContents | WNoAutoErase )
+{
+ // Set a sane default
+ _width = _height = 50.0;
+ orientation = 0; // Portrait
+}
+
+void SizePreview::setSize(const SimplePageSize& size)
+{
+ _width = size.width().getLength_in_mm();
+ _height = size.height().getLength_in_mm();
+
+ if (_width < 50.0)
+ _width = 50.0;
+ if (_width > 1200.0)
+ _width = 1200.0;
+
+ if (_height < 50.0)
+ _height = 50.0;
+ if (_height > 1200.0)
+ _height = 1200.0;
+
+ update();
+}
+
+void SizePreview::resizeEvent(QResizeEvent*)
+{
+ update();
+}
+
+void SizePreview::paintEvent( QPaintEvent * )
+{
+ int displayedWidth, displayedHeight;
+
+ // Figure the width and height of the displayed page. Tricky.
+ if (orientation == 0) {
+ displayedWidth = (int)(height() * (_width/_height) + 0.5);
+ displayedHeight = (int)(width() * (_height/_width) + 0.5);
+ } else {
+ displayedHeight = (int)(height() * (_width/_height) + 0.5);
+ displayedWidth = (int)(width() * (_height/_width) + 0.5);
+ }
+ if (displayedWidth <= width())
+ displayedHeight = height();
+ else
+ displayedWidth = width();
+
+ int hOffset = (width()-displayedWidth)/2;
+ int vOffset = (height()-displayedHeight)/2;
+
+
+ // Now draw the graphics
+ pixmap.resize(width(), height());
+
+ QPainter p(&pixmap);
+ p.fillRect(rect(), colorGroup().background());
+ p.setPen(Qt::black);
+ p.setBrush(Qt::white);
+ p.drawRect(hOffset, vOffset, displayedWidth, displayedHeight);
+
+ // mark the textbox; we assume 25mm margin
+ int margin = (int)(25.0*displayedWidth/_width + 0.5);
+ QRect textBox(hOffset+margin, vOffset+margin, displayedWidth-2*margin, displayedHeight-2*margin);
+ p.setPen(Qt::lightGray);
+ p.drawRect(textBox);
+
+ // Draw some dummy "text", represented by black lines
+ int lineSpacing = (int)(7.0*displayedWidth/_width + 0.5); // equiv. 7 mm
+ if (lineSpacing <= 3)
+ lineSpacing = 3;
+ int interWordSpace = (int)(4.0*displayedWidth/_width + 0.5); // equiv. 4 mm
+ if (interWordSpace <= 1)
+ interWordSpace = 2;
+
+ KRandomSequence rnd(1); // to generate word widths
+
+ p.setClipRect(textBox);
+ p.setPen(Qt::black);
+ int count = 1; // Counts lines
+ for (int y = vOffset+margin+lineSpacing; y <= vOffset+displayedHeight-margin; y += lineSpacing) {
+ // We start each line with its own seed.
+ // This means that the random sequence for each line is always the same, and this
+ // results in a more steady picture when the widget is resized.
+ rnd.setSeed(count);
+
+ // Every 10th line the end of a paragraph
+ int endParagraph;
+ if (count++ % 10 == 0)
+ endParagraph = (int)(50.0*displayedWidth/_width + 0.5);
+ else
+ endParagraph = 0;
+ for(int x = hOffset+margin; x <= hOffset+displayedWidth-margin-endParagraph; ) {
+ double wordWidthMM = rnd.getDouble()*30.0+10.0;
+ int wordWidth = (int)(wordWidthMM*displayedWidth/_width + 0.5);
+ p.drawLine(x, y, x+wordWidth, y);
+ x += wordWidth+interWordSpace+1;
+ }
+ }
+
+ p.end();
+
+ // Copy the pixmap onto the widget
+ bitBlt(this, rect().topLeft(), &pixmap, rect(), CopyROP);
+ return;
+}
+
+void SizePreview::setOrientation(int ori)
+{
+ orientation = ori;
+ update();
+}
+
+#include "sizePreview.moc"
diff --git a/kviewshell/sizePreview.h b/kviewshell/sizePreview.h
new file mode 100644
index 00000000..4d5a5b3b
--- /dev/null
+++ b/kviewshell/sizePreview.h
@@ -0,0 +1,47 @@
+// -*- C++ -*-
+// SizePreview.h
+//
+// Part of KVIEWSHELL - A framework for multipage text/gfx viewers
+//
+// (C) 2002 Stefan Kebekus
+// Distributed under the GPL
+
+// Add header files alphabetically
+
+#ifndef SIZEPREVIEW_H
+#define SIZEPREVIEW_H
+
+#include <qpixmap.h>
+#include <qwidget.h>
+
+class SimplePageSize;
+
+class SizePreview : public QWidget
+{
+ Q_OBJECT
+
+public:
+ SizePreview( QWidget *parent, const char* name=0, WFlags f=0 );
+
+public slots:
+ // Sets the size.
+ void setSize(const SimplePageSize&);
+
+ // or = 0 means "Portrait", anything else means "Landscape"
+ void setOrientation(int ori);
+
+protected:
+ void paintEvent(QPaintEvent*);
+ void resizeEvent(QResizeEvent*);
+
+private:
+ int orientation; // 0 = portrait, other = landscape
+
+ // Both must be positive at all times!
+ float _width; // in mm
+ float _height; // in mm
+
+ QPixmap pixmap;
+};
+
+#endif
diff --git a/kviewshell/tableOfContents.cpp b/kviewshell/tableOfContents.cpp
new file mode 100644
index 00000000..e7c5db28
--- /dev/null
+++ b/kviewshell/tableOfContents.cpp
@@ -0,0 +1,119 @@
+/***************************************************************************
+ * 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 <config.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "tableOfContents.h"
+#include "bookmark.h"
+#include "kvsprefs.h"
+
+
+TocItem::TocItem(TocItem* parent)
+ : KListViewItem(parent)
+{
+}
+
+TocItem::TocItem(QListView* parent)
+ : KListViewItem(parent)
+{
+}
+
+
+TableOfContents::TableOfContents(QWidget* parent)
+ : KListView(parent)
+{
+ addColumn(i18n("Topic"));
+ addColumn(i18n("Page"));
+
+ setSorting(-1);
+ setRootIsDecorated(true);
+ setSelectionMode(QListView::NoSelection);
+ setResizeMode(AllColumns);
+ setColumnWidthMode(0, Manual);
+ setColumnWidthMode(1, Manual);
+ setFullWidth(true);
+
+ readSettings();
+
+ connect(this, SIGNAL(executed(QListViewItem*)), this, SLOT(itemClicked(QListViewItem*)));
+}
+
+TableOfContents::~TableOfContents()
+{
+ writeSettings();
+}
+
+void TableOfContents::writeSettings()
+{
+ saveLayout(KVSPrefs::self()->config(), "tocLayout");
+}
+
+void TableOfContents::readSettings()
+{
+ restoreLayout(KVSPrefs::self()->config(), "tocLayout");
+}
+
+void TableOfContents::setContents(const QPtrList<Bookmark>& bookmarks)
+{
+ clear();
+ addItems(bookmarks);
+}
+
+void TableOfContents::addItems(const QPtrList<Bookmark>& _bookmarks, TocItem* parent)
+{
+ kdDebug(1223) << "TableOfContents::setContents()" << endl;
+ if (_bookmarks.isEmpty())
+ return;
+ kdDebug(1223) << "Bookmarks are not empty" << endl;
+
+ // Why isn't QPtrList const-correct?
+ QPtrList<Bookmark> bookmarks = _bookmarks;
+ for (Bookmark* current = bookmarks.last(); current; current = bookmarks.prev() ) {
+ TocItem* item;
+ if (!parent)
+ item = new TocItem(this);
+ else
+ item = new TocItem(parent);
+
+ item->setText(0, current->bookmarkText);
+ if (current->position.page != 0)
+ item->setText(1, QString().setNum(current->position.page));
+ else
+ item->setText(1, "--");
+ item->setAnchor(current->position);
+
+ if (!current->subordinateBookmarks.isEmpty())
+ addItems(current->subordinateBookmarks, item);
+ }
+ }
+
+void TableOfContents::itemClicked(QListViewItem* _item)
+{
+ TocItem* item = static_cast<TocItem*>(_item);
+
+ Anchor destination = item->getAnchor();
+
+ emit gotoPage(destination);
+}
+
+#include "tableOfContents.moc"
diff --git a/kviewshell/tableOfContents.h b/kviewshell/tableOfContents.h
new file mode 100644
index 00000000..4f653d25
--- /dev/null
+++ b/kviewshell/tableOfContents.h
@@ -0,0 +1,69 @@
+// -*- C++ -*-
+/***************************************************************************
+ * 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 TABLEOFCONTENTS_H
+#define TABLEOFCONTENTS_H
+
+#include "anchor.h"
+
+#include <klistview.h>
+
+class Bookmark;
+
+
+class TocItem : public KListViewItem
+{
+public:
+ TocItem(TocItem* parent);
+ TocItem(QListView* parent);
+
+ void setAnchor(const Anchor & _anchor) { anchor = _anchor; }
+ Anchor getAnchor() { return anchor; }
+
+private:
+ Anchor anchor;
+};
+
+
+class TableOfContents : public KListView
+{
+Q_OBJECT
+
+public:
+ TableOfContents(QWidget* parent);
+ virtual ~TableOfContents();
+
+ void setContents(const QPtrList<Bookmark>& bookmarks);
+
+ void writeSettings();
+ void readSettings();
+
+signals:
+ void gotoPage(const Anchor&);
+
+private:
+ void addItems(const QPtrList<Bookmark>& bookmarks, TocItem* parent = 0);
+
+private slots:
+ void itemClicked(QListViewItem*);
+};
+
+#endif
diff --git a/kviewshell/textBox.h b/kviewshell/textBox.h
new file mode 100644
index 00000000..281de465
--- /dev/null
+++ b/kviewshell/textBox.h
@@ -0,0 +1,65 @@
+// -*- C++ -*-
+//
+// Class: textBox
+//
+// Part of KDVI- A previewer for TeX DVI files.
+//
+// (C) 2004-2005 Stefan Kebekus. Distributed under the GPL.
+
+
+#ifndef _textbox_h_
+#define _textbox_h_
+
+#include <qrect.h>
+#include <qstring.h>
+
+/** Represents a rectangular region in a RenderedDocumentPage that contains text
+
+ This trivial class is used in the RenderedDocumentPage class to
+ give a non-graphical representation of text in a rendered document
+ page. This is used, e.g. by text search and the text selection
+ functions that need to know the contents and the position of text
+ on a page
+
+ @author Stefan Kebekus <kebekus@kde.org>
+ @version 1.0.0
+*/
+
+class TextBox
+{
+public:
+ /** \brief Default Constructor
+
+ The default constructor leaves all fields uninitialized.
+ */
+ TextBox() {}
+
+ /** \brief Constructor
+
+ Trivial constructor leaves that initialized all members.
+
+ @param re value for the box
+ @param lT valus for the text field
+ */
+ TextBox(const QRect& re, const QString& lT): box(re), text(lT) {}
+
+ /** \brief Bounding box of the text or hyperlink
+
+ This rectangle specifies where on the page the text or hyperlink is
+ found. It uses the same coordinates that were used when the
+ associated documentPage was rendered by the
+ documentRenderer.drawPage() method. The contents of the box is
+ graphically inverted to indicate marked text.
+ */
+ QRect box;
+
+ /** \brief Name of the region
+
+ The text associated with the box is stored here.
+ */
+ QString text;
+};
+
+
+
+#endif
diff --git a/kviewshell/units.cpp b/kviewshell/units.cpp
new file mode 100644
index 00000000..e675f916
--- /dev/null
+++ b/kviewshell/units.cpp
@@ -0,0 +1,83 @@
+// units.cpp
+//
+// Part of KVIEWSHELL - A framework for multipage text/gfx viewers
+//
+// (C) 2003 Stefan Kebekus
+// Distributed under the GPL
+
+// Add header files alphabetically
+
+#include <config.h>
+
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <math.h>
+#include <qstringlist.h>
+
+#include "units.h"
+
+class unitOfDistance
+{
+ public:
+ float mmPerUnit;
+ const char* name;
+};
+
+unitOfDistance distanceUnitTable[] = {
+ // Metric units
+ {1.0, "mm"},
+ {1.0, "millimeter"},
+ {10.0, "cm"},
+ {10.0, "centimeter"},
+ {100.0*10.0, "m"},
+ {100.0*10.0, "meter"},
+
+ // Imperial units
+ {25.4, "in"},
+ {25.4, "inch"},
+
+ // Typographical units
+ {2540.0/7227.0, "pt"}, // TeX points. 7227points = 254cm
+ {25.4/72.0, "bp"}, // big points, 1/72 inch as used in Postscript
+ {25.4/6.0, "pc"}, // pica = 1/6 inch
+ {25.4/6.0, "pica"},
+ {25.4*0.0148, "dd"}, // didot points = 0.0148 inches
+ {25.4*0.0148, "didot"},
+ {25.4*0.178, "cc"}, // cicero points = 0.178 inches
+ {25.4*0.178, "cicero"},
+
+ {0.0, 0},
+};
+
+
+
+
+float distance::convertToMM(const QString &distance, bool *ok)
+{
+ // kdDebug() << "convertToMM( " << distance << " )" << endl;
+
+ float MMperUnit = 0.0;
+ int unitPos = 0; // position of the unit in the string
+
+ // Check for various known units, and store the beginning position
+ // of the unit in 'unitPos', so that distance[0..unitPos] will hold
+ // the value. Store the number of mm per unit in 'MMperUnit'.
+ for(int i=0; MMperUnit==0.0 && distanceUnitTable[i].name != 0; i++) {
+ unitPos = distance.findRev(distanceUnitTable[i].name);
+ if (unitPos != -1)
+ MMperUnit = distanceUnitTable[i].mmPerUnit;
+ }
+
+ // If no unit has been found -> error message, set *ok to false and
+ // return 0.0.
+ if (MMperUnit == 0.0) {
+ kdError() << "distance::convertToMM: no known unit found in the string '" << distance << "'." << endl;
+ if (ok)
+ *ok = false;
+ return 0.0;
+ }
+
+ QString val = distance.left(unitPos).simplifyWhiteSpace();
+ return MMperUnit*val.toFloat(ok);
+}
diff --git a/kviewshell/units.h b/kviewshell/units.h
new file mode 100644
index 00000000..48708c01
--- /dev/null
+++ b/kviewshell/units.h
@@ -0,0 +1,34 @@
+// units.h
+//
+// Part of KVIEWSHELL - A framework for multipage text/gfx viewers
+//
+// (C) 2003 Stefan Kebekus
+// Distributed under the GPL
+
+// Add header files alphabetically
+
+#ifndef UNITS_H
+#define UNITS_H
+
+class QString;
+
+class distance {
+ public:
+ // This method converts a string that gives a distance in one of the
+ // commonly used units, such as "12.3mm", "12 inch" or "15 didot" to
+ // millimeters. For a complete list of supported units, see the
+ // static lists that are hardcoded in "units.cpp".
+ //
+ // If the conversion is not possible *ok is set to "false" and an
+ // undefined value is returned. If the unit could not be recognized,
+ // an error message is printed via kdError(). Otherwise, *ok is set
+ // to true.
+ //
+ // It is possible in rare circumstances that ok is set to true
+ // although the string is malformed.
+ //
+ // It is fine to set ok to 0.
+ static float convertToMM(const QString &distance, bool *ok=0);
+};
+
+#endif
diff --git a/kviewshell/zoom.cpp b/kviewshell/zoom.cpp
new file mode 100644
index 00000000..3c3e56df
--- /dev/null
+++ b/kviewshell/zoom.cpp
@@ -0,0 +1,156 @@
+// zoom.cpp
+//
+// Part of KVIEWSHELL - A framework for multipage text/gfx viewers
+//
+// (C) 2002 Stefan Kebekus
+// Distributed under the GPL
+
+// Add header files alphabetically
+
+#include <config.h>
+
+#include <math.h>
+#include <qstringlist.h>
+
+#include <klocale.h>
+
+#include "zoom.h"
+#include "zoomlimits.h"
+
+float zoomVals[] = {0.20, 0.33, 0.50, 0.75, 1.00, 1.25, 1.50, 2.00, 2.50, 0};
+
+Zoom::Zoom()
+{
+ valueNames << i18n("Fit to Page Width");
+ valueNames << i18n("Fit to Page Height");
+ valueNames << i18n("Fit to Page");
+
+ _zoomValue = 1.0;
+ valNo = 6; // 1.0 is 6rd entry in the list
+ for(int i=0; zoomVals[i] != 0; i++)
+ valueNames << QString("%1%").arg(zoomVals[i]);
+}
+
+
+void Zoom::setZoomValue(const QString &cval)
+{
+ float fval;
+
+ // Remove a trailing '%', if any
+ QString val = cval.stripWhiteSpace();
+ if (val.right(1) == "%")
+ val = val.left(val.length()-1).stripWhiteSpace();
+
+ bool ok;
+ fval = val.toFloat(&ok)/100.0;
+
+ if (ok == true)
+ setZoomValue(fval);
+ else {
+ emit(zoomNamesChanged(valueNames));
+ emit(valNoChanged(valNo));
+ emit(zoomNameChanged(QString("%1%").arg((int)(_zoomValue*100.0+0.5))));
+ }
+}
+
+void Zoom::setZoomFitWidth(float zoom)
+{
+ // Make sure _zoomValue is in the permissible range!
+ if (zoom < ZoomLimits::MinZoom/1000.0)
+ zoom = ZoomLimits::MinZoom/1000.0;
+ if (zoom > ZoomLimits::MaxZoom/1000.0)
+ zoom = ZoomLimits::MaxZoom/1000.0;
+ _zoomValue = zoom;
+
+ valNo = 0;
+ emit(valNoChanged(valNo));
+ emit(zoomNameChanged(QString("%1%").arg((int)(_zoomValue*100.0+0.5))));
+}
+
+void Zoom::setZoomFitHeight(float zoom)
+{
+ // Make sure _zoomValue is in the permissible range!
+ if (zoom < ZoomLimits::MinZoom/1000.0)
+ zoom = ZoomLimits::MinZoom/1000.0;
+ if (zoom > ZoomLimits::MaxZoom/1000.0)
+ zoom = ZoomLimits::MaxZoom/1000.0;
+ _zoomValue = zoom;
+
+ valNo = 1;
+ emit(valNoChanged(valNo));
+ emit(zoomNameChanged(QString("%1%").arg((int)(_zoomValue*100.0+0.5))));
+}
+
+void Zoom::setZoomFitPage(float zoom)
+{
+ // Make sure _zoomValue is in the permissible range!
+ if (zoom < ZoomLimits::MinZoom/1000.0)
+ zoom = ZoomLimits::MinZoom/1000.0;
+ if (zoom > ZoomLimits::MaxZoom/1000.0)
+ zoom = ZoomLimits::MaxZoom/1000.0;
+ _zoomValue = zoom;
+
+ valNo = 2;
+ emit(valNoChanged(valNo));
+ emit(zoomNameChanged(QString("%1%").arg((int)(_zoomValue*100.0+0.5))));
+}
+
+void Zoom::setZoomValue(float f)
+{
+ // Make sure _zoomValue is in the permissible range!
+ if (f < ZoomLimits::MinZoom/1000.0)
+ f = ZoomLimits::MinZoom/1000.0;
+ if (f > ZoomLimits::MaxZoom/1000.0)
+ f = ZoomLimits::MaxZoom/1000.0;
+ _zoomValue = f;
+
+
+ valueNames.clear();
+
+ valueNames << i18n("Fit to Page Width");
+ valueNames << i18n("Fit to Page Height");
+ valueNames << i18n("Fit to Page");
+
+ bool flag = false;
+ for(int i = 0; zoomVals[i] != 0; i++) {
+ if ((_zoomValue <= zoomVals[i]) && (flag == false)) {
+ flag = true;
+ valNo = i + 3;
+ if (fabs(_zoomValue-zoomVals[i]) > 0.01)
+ valueNames << QString("%1%").arg((int)(_zoomValue*100.0+0.5));
+ }
+ valueNames << QString("%1%").arg((int)(zoomVals[i]*100.0+0.5));
+ }
+
+ if (flag == false) {
+ valNo = valueNames.size();
+ valueNames << QString("%1%").arg((int)(_zoomValue*100.0+0.5));
+ }
+
+ emit(zoomNamesChanged(valueNames));
+ emit(valNoChanged(valNo));
+ emit(zoomNameChanged(QString("%1%").arg((int)(_zoomValue*100.0+0.5))));
+}
+
+float Zoom::zoomIn()
+{
+ int i;
+ for(i=0; zoomVals[i] != 0; i++)
+ if (zoomVals[i] > _zoomValue)
+ return zoomVals[i];
+
+ return zoomVals[i-1];
+}
+
+float Zoom::zoomOut()
+{
+ float result = zoomVals[0];
+
+ for(int i=0; zoomVals[i] != 0; i++)
+ if (_zoomValue > zoomVals[i])
+ result = zoomVals[i];
+
+ return result;
+}
+
+#include "zoom.moc"
diff --git a/kviewshell/zoom.h b/kviewshell/zoom.h
new file mode 100644
index 00000000..985e18a9
--- /dev/null
+++ b/kviewshell/zoom.h
@@ -0,0 +1,55 @@
+// -*- C++ -*-
+// zoom.h
+//
+// Part of KVIEWSHELL - A framework for multipage text/gfx viewers
+//
+// (C) 2002 Stefan Kebekus
+// Distributed under the GPL
+
+// Add header files alphabetically
+
+#ifndef ZOOM_H
+#define ZOOM_H
+
+#include <qobject.h>
+#include <qstringlist.h>
+
+
+class Zoom : public QObject
+{
+Q_OBJECT
+
+public:
+ /** Initializs the zoom with a default of 100% */
+ Zoom();
+
+ /** Returns a list like "33%", "100%", etc. If you call
+ zoomNames() more than once, it is guaranteed that the same
+ list of strings will be returned. */
+ QStringList zoomNames() const { return valueNames; }
+
+ float zoomIn();
+ float zoomOut();
+ float value() const { return _zoomValue; }
+
+public slots:
+ void setZoomValue(float);
+ void setZoomValue(const QString &);
+
+ void setZoomFitWidth(float zoom);
+ void setZoomFitHeight(float zoom);
+ void setZoomFitPage(float zoom);
+
+signals:
+ void zoomNamesChanged(const QStringList &);
+ void zoomNameChanged(const QString &);
+ void valNoChanged(int);
+
+private:
+ float _zoomValue;
+ QStringList valueNames;
+ // This will be the number of the current value in the generated QStringList.
+ int valNo;
+};
+
+#endif
diff --git a/kviewshell/zoomlimits.h b/kviewshell/zoomlimits.h
new file mode 100644
index 00000000..2458c488
--- /dev/null
+++ b/kviewshell/zoomlimits.h
@@ -0,0 +1,19 @@
+// -*- C++ -*-
+#ifndef ZOOMLIMITS_H
+#define ZOOMLIMITS_H
+
+// Define the maximal and minimal zoom factor which is accepted by
+// the kviewshell. If the user or a configuration file asks for
+// smaller or bigger values, the kviewshell uses either MinZoom or
+// MaxZoom. Implementations of the parts should also use these
+// limits if they whish to implement limits on the allowed zoom
+// factors.
+
+// We use integers which need to be divided by 1000 before use.
+// In this case, this means MinZoom = 0.05 and MaxZoom = 3.
+
+namespace ZoomLimits {
+ enum { MinZoom = 50, MaxZoom = 3000 };
+}
+
+#endif
diff --git a/libkscan/AUTHORS b/libkscan/AUTHORS
new file mode 100644
index 00000000..9d4c1dab
--- /dev/null
+++ b/libkscan/AUTHORS
@@ -0,0 +1,2 @@
+Ivan Shvedunov <ivan_iv@rf-hp.npi.msu.su>
+Klaas Freitag <freitag@suse.de>
diff --git a/libkscan/COPYING.LIB b/libkscan/COPYING.LIB
new file mode 100644
index 00000000..01148ab6
--- /dev/null
+++ b/libkscan/COPYING.LIB
@@ -0,0 +1,486 @@
+NOTE! The LGPL below is copyrighted by the Free Software Foundation, but
+the instance of code that it refers to (the kde libraries) are copyrighted
+by the authors who actually wrote it.
+
+---------------------------------------------------------------------------
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor
+ Boston, MA 02110-1301, USA.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the library GPL. It is
+ numbered 2 because it goes with version 2 of the ordinary GPL.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Library General Public License, applies to some
+specially designated Free Software Foundation software, and to any
+other libraries whose authors decide to use it. You can use it for
+your libraries, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if
+you distribute copies of the library, or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link a program with the library, you must provide
+complete object files to the recipients so that they can relink them
+with the library, after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ Our method of protecting your rights has two steps: (1) copyright
+the library, and (2) offer you this license which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ Also, for each distributor's protection, we want to make certain
+that everyone understands that there is no warranty for this free
+library. If the library is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original
+version, so that any problems introduced by others will not reflect on
+the original authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that companies distributing free
+software will individually obtain patent licenses, thus in effect
+transforming the program into proprietary software. To prevent this,
+we have made it clear that any patent must be licensed for everyone's
+free use or not licensed at all.
+
+ Most GNU software, including some libraries, is covered by the ordinary
+GNU General Public License, which was designed for utility programs. This
+license, the GNU Library General Public License, applies to certain
+designated libraries. This license is quite different from the ordinary
+one; be sure to read it in full, and don't assume that anything in it is
+the same as in the ordinary license.
+
+ The reason we have a separate public license for some libraries is that
+they blur the distinction we usually make between modifying or adding to a
+program and simply using it. Linking a program with a library, without
+changing the library, is in some sense simply using the library, and is
+analogous to running a utility program or application program. However, in
+a textual and legal sense, the linked executable is a combined work, a
+derivative of the original library, and the ordinary General Public License
+treats it as such.
+
+ Because of this blurred distinction, using the ordinary General
+Public License for libraries did not effectively promote software
+sharing, because most developers did not use the libraries. We
+concluded that weaker conditions might promote sharing better.
+
+ However, unrestricted linking of non-free programs would deprive the
+users of those programs of all benefit from the free status of the
+libraries themselves. This Library General Public License is intended to
+permit developers of non-free programs to use free libraries, while
+preserving your freedom as a user of such programs to change the free
+libraries that are incorporated in them. (We have not seen how to achieve
+this as regards changes in header files, but we have achieved it as regards
+changes in the actual functions of the Library.) The hope is that this
+will lead to faster development of free libraries.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, while the latter only
+works together with the library.
+
+ Note that it is possible for a library to be covered by the ordinary
+General Public License rather than by this special one.
+
+ GNU LIBRARY GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library which
+contains a notice placed by the copyright holder or other authorized
+party saying it may be distributed under the terms of this Library
+General Public License (also called "this License"). Each licensee is
+addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also compile or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ c) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ d) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the source code distributed need not include anything that is normally
+distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Library General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/libkscan/INSTALL b/libkscan/INSTALL
new file mode 100644
index 00000000..02a4a074
--- /dev/null
+++ b/libkscan/INSTALL
@@ -0,0 +1,167 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes a while. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 4. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made.
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
+
diff --git a/libkscan/Makefile.am b/libkscan/Makefile.am
new file mode 100644
index 00000000..b0c3be45
--- /dev/null
+++ b/libkscan/Makefile.am
@@ -0,0 +1,32 @@
+INCLUDES = -I$(top_srcdir)/libkscan $(all_includes) $(LIBSANE_INCLUDES)
+
+lib_LTLIBRARIES = libkscan.la
+
+noinst_HEADERS = kscandevice.h kscanslider.h kgammatable.h \
+ kscanoption.h kscanoptset.h \
+ gammadialog.h dispgamma.h \
+ scansourcedialog.h scanparams.h massscandialog.h devselector.h \
+ img_canvas.h previewer.h imgscaledialog.h sizeindicator.h \
+ imgscaninfo.h
+
+libkscan_la_SOURCES = kscandevice.cpp kscanslider.cpp kgammatable.cpp\
+ kscanoption.cpp kscanoptset.cpp \
+ gammadialog.cpp dispgamma.cpp \
+ scansourcedialog.cpp scanparams.cpp massscandialog.cpp \
+ devselector.cpp scandialog.cpp \
+ img_canvas.cpp previewer.cpp imgscaledialog.cpp sizeindicator.cpp \
+ imgscaninfo.cpp
+
+
+libkscan_la_LDFLAGS = $(all_libraries) $(LIBSANE_LDFLAGS) -no-undefined -version-info 1:0
+libkscan_la_LIBADD = $(LIBSANE_LIBS) $(LIB_KFILE)
+
+kde_services_DATA = scanservice.desktop
+
+METASOURCES = AUTO
+
+SUBDIRS = pics
+
+messages:
+ $(XGETTEXT) *.cpp -o $(podir)/libkscan.pot
+
diff --git a/libkscan/README b/libkscan/README
new file mode 100644
index 00000000..d947ac58
--- /dev/null
+++ b/libkscan/README
@@ -0,0 +1,12 @@
+KScan is KDE's Scanner Library.
+It's used by kooka and by koffice.
+It provides an easy-to-use library, which
+allows you to acces your scanner (camera - as long as it's
+sane compatible).
+
+It's based on SANE.
+You can find SANE under http://www.sane-project.org/
+
+
+Nikolas Zimmermann
+<wildfox@kde.org>
diff --git a/libkscan/TODO b/libkscan/TODO
new file mode 100644
index 00000000..5dd0a652
--- /dev/null
+++ b/libkscan/TODO
@@ -0,0 +1,59 @@
+
+Our TODO List:
+2. Tue Oct 31 18:12:25 CET 2000 - Klaas Freitag <freitag@suse.de>
+
+ OK, trying to find smaller portions of work to do ;)
+ Trying to write down the status of the classes here.
+
+ Probably all classes need:
+ - a cleanup of the code. Lots of unused stuff may be deleted.
+ - a debug concept. By now, the function debug() is used, but probably that not state of the art?
+ - a rewrite/cleaning to adept to Qt 2.x
+ - the gui functionality KDE 2.x - features.
+ - KDE-features at all ! The whole stuff does not use any KDE-funcitonality, only Qt.
+ What about having a Version which compiles without KDE ? .o0( Good idea to think about ? )
+ - attention to drop QString where possible, and I think, its possible where SANE-stuff is
+ used.
+ - I18N-functions. In resource.h, I defined a macro I18N which does not much by now. I tried
+ to place it around strings to prepare for real I18N treatment. How is that done ?
+ - C++ - cleanup. Nearly no class has proper default and copy constructor and stuff...
+
+ KGammaTable: an abstrct data type
+ - seems to work more or less for 255-color images. Does not work for palettes with more entries.
+
+ - needs documentation
+
+ KScanDevice: logic scanner device.
+ - has mixed code for the widget-factory (getGuiElement) and the logic scanner. Dont know if
+ that is cool, or if we should participate that.
+ - Has the sane scanner handle as a modul global variable. Thus, only one scanner handle can
+ be used in one application.
+ - No net device yet. I never had a look for it, and if it works or not. I only disabled it to
+ cut down complexity.
+ - ... much more
+ - should be able to load and apply option sets (see there).
+
+ - needs documentation
+
+ KScanOption:
+ - has no possibility to be applied immediatly after being set. That might be a real problem
+ in some cases. Good ideas are welcome.
+ By now, the Option can be set and needs to be applied (means sent to the scanner device)
+ by a call to the apply method in KScanDevice. After that, it could be checked, if other
+ options changed thereby. Thats fine under the aspect of a good OO design, but might cause
+ problems in case a option is changed and there is no possibility to call apply.
+
+ - needs documentation
+
+ KScanOptSet:
+ - needs possibility to be stored and loaded in/from KDE-configuration files. Example:
+ Option set (including resolution, gammatables etc.) for photos, for ocr, bla...
+
+
+ KScanSlider:
+ - needs a neutral button in the widget !
+
+ KScanEntry :
+ KScanCombo :
+
+ ... much more.
diff --git a/libkscan/configure.in.bot b/libkscan/configure.in.bot
new file mode 100644
index 00000000..64c4c234
--- /dev/null
+++ b/libkscan/configure.in.bot
@@ -0,0 +1,9 @@
+if test -z "$SANE_CONFIG"; then
+ echo ""
+ echo "You're missing development files for libsane - "
+ echo "libkscan/kooka won't be compiled without libsane."
+ echo "You can download it from"
+ echo "http://www.sane-project.org/"
+ echo ""
+ all_tests=bad
+fi
diff --git a/libkscan/configure.in.in b/libkscan/configure.in.in
new file mode 100644
index 00000000..09929e92
--- /dev/null
+++ b/libkscan/configure.in.in
@@ -0,0 +1,22 @@
+
+KDE_FIND_PATH( sane-config, SANE_CONFIG, [ ${prefix}/bin, ${exec_prefix}/bin,
+ /usr/local/bin, /opt/local/bin,
+ /usr/bin ] )
+if test -n "$SANE_CONFIG"; then
+ dnl ### version check. Klaas, which version is minimum?
+
+ LIBSANE_LIBS="`$SANE_CONFIG --libs`"
+ LIBSANE_LDFLAGS="`$SANE_CONFIG --ldflags`"
+ dnl Bah, --cflags is -I lines only (according to the sane-config.in source
+ dnl and _INCLUDES looks nicer :)
+ LIBSANE_INCLUDES="`$SANE_CONFIG --cflags`"
+
+ AC_DEFINE_UNQUOTED(HAVE_SANE, 1, [Defines if your system has the sane libraries])
+else
+ DO_NOT_COMPILE="$DO_NOT_COMPILE libkscan kooka"
+fi
+
+AM_CONDITIONAL(include_kooka, test -n "$SANE_CONFIG")
+AC_SUBST(LIBSANE_LIBS)
+AC_SUBST(LIBSANE_LDFLAGS)
+AC_SUBST(LIBSANE_INCLUDES)
diff --git a/libkscan/devselector.cpp b/libkscan/devselector.cpp
new file mode 100644
index 00000000..8d1a90ad
--- /dev/null
+++ b/libkscan/devselector.cpp
@@ -0,0 +1,183 @@
+/* This file is part of the KDE Project
+ Copyright (C) 2000 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <stdlib.h>
+
+#include <qbuttongroup.h>
+#include <qcheckbox.h>
+#include <qcstring.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qfile.h>
+#include <qpushbutton.h>
+#include <qradiobutton.h>
+#include <qstrlist.h>
+#include <qstringlist.h>
+
+#include <kapplication.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <ksimpleconfig.h>
+
+#include "devselector.h"
+
+
+DeviceSelector::DeviceSelector( QWidget *parent, QStrList& devList,
+ const QStringList& hrdevList )
+ : KDialogBase( parent, "DeviceSel", true, i18n("Welcome to Kooka"),
+ Ok|Cancel, Ok, true )
+{
+ kdDebug(29000) << "Starting DevSelector!" << endl;
+ // Layout-Boxes
+ QWidget *page = new QWidget( this );
+ Q_CHECK_PTR( page );
+ setMainWidget( page );
+
+ QVBoxLayout *topLayout = new QVBoxLayout( page, marginHint(), spacingHint() );
+ QLabel *label = new QLabel( page, "captionImage" );
+ Q_CHECK_PTR( label );
+ label->setPixmap( QPixmap( "kookalogo.png" ));
+ label->resize( 100, 350 );
+ topLayout->addWidget( label );
+
+ selectBox = new QButtonGroup( 1, Horizontal, i18n( "Select Scan Device" ),
+ page, "ButtonBox");
+ Q_CHECK_PTR( selectBox );
+ selectBox->setExclusive( true );
+ topLayout->addWidget( selectBox );
+ setScanSources( devList, hrdevList );
+
+ cbSkipDialog = new QCheckBox( i18n("&Do not ask on startup again, always use this device"),
+ page, "CBOX_SKIP_ON_START" );
+
+ KConfig *gcfg = KGlobal::config();
+ gcfg->setGroup(QString::fromLatin1(GROUP_STARTUP));
+ bool skipDialog = gcfg->readBoolEntry( STARTUP_SKIP_ASK, false );
+ cbSkipDialog->setChecked( skipDialog );
+
+ topLayout->addWidget(cbSkipDialog);
+
+}
+
+QCString DeviceSelector::getDeviceFromConfig( void ) const
+{
+ KConfig *gcfg = KGlobal::config();
+ gcfg->setGroup(QString::fromLatin1(GROUP_STARTUP));
+ bool skipDialog = gcfg->readBoolEntry( STARTUP_SKIP_ASK, false );
+
+ QCString result;
+
+ /* in this case, the user has checked 'Do not ask me again' and does not
+ * want to be bothered any more.
+ */
+ result = QFile::encodeName(gcfg->readEntry( STARTUP_SCANDEV, "" ));
+ kdDebug(29000) << "Got scanner from config file to use: " << result << endl;
+
+ /* Now check if the scanner read from the config file is available !
+ * if not, ask the user !
+ */
+ if( skipDialog && devices.find( result ) > -1 )
+ {
+ kdDebug(29000) << "Scanner from Config file is available - fine." << endl;
+ }
+ else
+ {
+ kdDebug(29000) << "Scanner from Config file is _not_ available" << endl;
+ result = QCString();
+ }
+
+ return( result );
+}
+
+bool DeviceSelector::getShouldSkip( void ) const
+{
+ return( cbSkipDialog->isChecked());
+}
+
+QCString DeviceSelector::getSelectedDevice( void ) const
+{
+ unsigned int selID = selectBox->id( selectBox->selected() );
+
+ int dcount = devices.count();
+ kdDebug(29000) << "The Selected ID is <" << selID << ">/" << dcount << endl;
+
+ const char * dev = devices.at( selID );
+
+ kdDebug(29000) << "The selected device: <" << dev << ">" << endl;
+
+ /* Store scanner selection settings */
+ KConfig *c = KGlobal::config();
+ c->setGroup(QString::fromLatin1(GROUP_STARTUP));
+ /* Write both the scan device and the skip-start-dialog flag global. */
+ c->writeEntry( STARTUP_SCANDEV, dev, true, true );
+ c->writeEntry( STARTUP_SKIP_ASK, getShouldSkip(), true, true );
+ c->sync();
+
+ return dev;
+}
+
+
+void DeviceSelector::setScanSources( const QStrList& sources,
+ const QStringList& hrSources )
+{
+ bool default_ok = false;
+ KConfig *gcfg = KGlobal::config();
+ gcfg->setGroup(QString::fromLatin1(GROUP_STARTUP));
+ QCString defstr = gcfg->readEntry( STARTUP_SCANDEV, "" ).local8Bit();
+
+ /* Selector-Stuff*/
+ uint nr = 0;
+ int checkDefNo = 0;
+
+ QStrListIterator it( sources );
+ QStringList::ConstIterator it2 = hrSources.begin();
+ for ( ; it.current(); ++it, ++it2 )
+ {
+ QString text = QString::fromLatin1("&%1. %2\n%3").arg(1+nr).arg( QString::fromLocal8Bit(*it) ).arg( *it2 );
+ QRadioButton *rb = new QRadioButton( text, selectBox );
+ selectBox->insert( rb );
+
+ devices.append( *it );
+
+ if( *it == defstr )
+ checkDefNo = nr;
+
+ nr++;
+ }
+
+ /* Default still needs to be set */
+ if( ! default_ok )
+ {
+ /* if no default found, set the first */
+ QRadioButton *rb = (QRadioButton*) selectBox->find( checkDefNo );
+ if ( rb )
+ rb->setChecked( true );
+ }
+}
+
+DeviceSelector::~DeviceSelector()
+{
+
+}
+
+/* The End ;) */
+#include "devselector.moc"
diff --git a/libkscan/devselector.h b/libkscan/devselector.h
new file mode 100644
index 00000000..9fa80469
--- /dev/null
+++ b/libkscan/devselector.h
@@ -0,0 +1,104 @@
+/* This file is part of the KDE Project
+ Copyright (C) 2000 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef DEVSELECTOR_H
+#define DEVSELECTOR_H
+
+
+#include <kdialogbase.h>
+
+class QButtonGroup;
+class QStrList;
+class QStringList;
+class QCheckBox;
+
+/**
+ *@author Klaas Freitag
+ */
+
+/* Configuration-file definitions */
+#define GROUP_STARTUP "Scan Settings"
+#define STARTUP_SCANDEV "ScanDevice"
+#define STARTUP_SKIP_ASK "SkipStartupAsk"
+#define STARTUP_ONLY_LOCAL "QueryLocalOnly"
+
+
+/**
+ * A utitlity class that lets the user select a scan device.
+ *
+ * This class provides functions to get the scan device to use for an
+ * application with scan support.
+ *
+ * Its main purpose is to display a selection dialog, but it also reads
+ * and writes config entries to store the users selection and handles
+ * a field 'do not ask me again'.
+ *
+ */
+
+class DeviceSelector: public KDialogBase
+{
+ Q_OBJECT
+public:
+ /**
+ * constructs the dialog class
+ * @param QWidget *parent - the parent
+ * @param QStrList backends - a list of device names retrieved from the scan device
+ * @param QStrList scannerNames - a list of corresponding human readable sanner names.
+ */
+ DeviceSelector( QWidget *parent, QStrList&, const QStringList& );
+ ~DeviceSelector();
+
+ /**
+ * returns the device the user selected.
+ * @return a CString containing the technical name of the selected device (taken from
+ * the backends-list from the constructor)
+ */
+ QCString getSelectedDevice( void ) const;
+
+ /**
+ * returns the users selection if the dialog should be skipped in future.
+ * @return true for should be skipped.
+ */
+ bool getShouldSkip( void ) const;
+
+ /**
+ * retrieval to get the device from the config file. The function reads the applications
+ * config file, cares for the 'do not ask me again'-settings and checks if the scandevice
+ * specified in the config file is present at the current configuration.
+ * If this function returns null, the DeviceSelector should be opened for a user selection.
+ * @return a string containing the device to open or null if no device is specified or the
+ * one specified is not valid.
+ */
+ QCString getDeviceFromConfig( void ) const;
+
+public slots:
+ void setScanSources( const QStrList&, const QStringList& );
+
+private:
+ QButtonGroup *selectBox;
+ mutable QStrList devices;
+ QCheckBox *cbSkipDialog;
+ bool configDevValid;
+
+ class DeviceSelectorPrivate;
+ DeviceSelectorPrivate *d;
+
+};
+
+#endif
diff --git a/libkscan/dispgamma.cpp b/libkscan/dispgamma.cpp
new file mode 100644
index 00000000..2892d563
--- /dev/null
+++ b/libkscan/dispgamma.cpp
@@ -0,0 +1,85 @@
+/* This file is part of the KDE Project
+ Copyright (C) 2000 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qpainter.h>
+#include <qpixmap.h>
+
+#include "dispgamma.h"
+
+DispGamma::DispGamma( QWidget *parent ) : QWidget( parent )
+{
+ vals = 0;
+ margin = 10;
+}
+
+DispGamma::~DispGamma()
+{
+
+}
+
+void DispGamma::resizeEvent (QResizeEvent* )
+{
+ repaint();
+}
+
+void DispGamma::paintEvent( QPaintEvent *ev )
+{
+ QPainter p(this);
+ int w = vals->size() +1;
+
+ // Viewport auf margin setzen.
+ p.setViewport( margin, margin, width() - margin, height() - margin );
+ p.setWindow( 0, 255, w, -256 );
+
+ p.setClipRect( ev->rect());
+
+ p.setPen( colorGroup().highlight() );
+ p.setBrush( colorGroup().base() );
+ // Backgrond
+ p.drawRect( 0,0, w, 256 );
+ p.setPen( QPen(colorGroup().midlight(), 1, DotLine));
+ // horizontal Grid
+ for( int l = 1; l < 5; l++ )
+ p.drawLine( 1, l*51, 255, l*51 );
+
+ // vertical Grid
+ for( int l = 1; l < 5; l++ )
+ p.drawLine( l*51, 2, l*51, 255 );
+
+ // draw gamma-Line
+ p.setPen( colorGroup().highlight() );
+ p.moveTo( 1, vals->at(1) );
+ for( int i = 2; i < w-1; i++ )
+ {
+ p.lineTo( i, vals->at(i) );
+ }
+ p.flush();
+}
+
+
+QSize DispGamma::sizeHint( void )
+{
+ return QSize( 256 + 2*margin,256 + 2 * margin );
+}
+
+QSizePolicy DispGamma::sizePolicy( void )
+{
+ return QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding );
+}
+#include "dispgamma.moc"
diff --git a/libkscan/dispgamma.h b/libkscan/dispgamma.h
new file mode 100644
index 00000000..86c8c1b4
--- /dev/null
+++ b/libkscan/dispgamma.h
@@ -0,0 +1,62 @@
+/* This file is part of the KDE Project
+ Copyright (C) 2000 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef DISPGAMMA_H
+#define DISPGAMMA_H
+
+#include <qwidget.h>
+#include <qsizepolicy.h>
+#include <qsize.h>
+#include <qmemarray.h>
+
+extern "C"{
+#include <sane/sane.h>
+#include <sane/saneopts.h>
+}
+/**
+ *@author Klaas Freitag
+ */
+
+class DispGamma : public QWidget {
+ Q_OBJECT
+public:
+ DispGamma( QWidget *parent );
+ ~DispGamma();
+
+ QSize sizeHint( void );
+ QSizePolicy sizePolicy( void );
+
+ void setValueRef( QMemArray<SANE_Word> *newVals )
+ {
+ vals = newVals;
+ }
+protected:
+ void paintEvent (QPaintEvent *ev );
+ void resizeEvent( QResizeEvent* );
+
+private:
+
+ QMemArray<SANE_Word> *vals;
+ int margin;
+
+ class DispGammaPrivate;
+ DispGammaPrivate *d;
+};
+
+#endif
diff --git a/libkscan/gammadialog.cpp b/libkscan/gammadialog.cpp
new file mode 100644
index 00000000..4a8b3302
--- /dev/null
+++ b/libkscan/gammadialog.cpp
@@ -0,0 +1,114 @@
+/* This file is part of the KDE Project
+ Copyright (C) 2000 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qslider.h>
+#include <qlineedit.h>
+#include <qcombobox.h>
+
+#include <kscanslider.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "gammadialog.h"
+
+GammaDialog::GammaDialog( QWidget *parent ) :
+ KDialogBase( parent, "GammaDialog", true, i18n("Custom Gamma Tables"),
+ Ok|Cancel|Apply, Ok, true )
+{
+ gt = new KGammaTable();
+ QWidget *page = new QWidget( this );
+
+ Q_CHECK_PTR( page );
+ setMainWidget( page );
+
+ /* This connect is for recalculating the table every time a new
+ * Bright., Contrast or Gamma-Value is set */
+ connect( gt, SIGNAL(tableChanged()), gt, SLOT(getTable()));
+
+ gtDisp = new DispGamma( page );
+ gtDisp->setValueRef( gt->getArrayPtr() );
+ gtDisp->resize( 280, 280 );
+
+ connect( gt, SIGNAL(tableChanged()), gtDisp, SLOT( repaint()));
+
+ // setCaption( i18n( "Gamma Table" ));
+
+ // Layout-Boxes
+ QVBoxLayout *bigdad = new QVBoxLayout( page, 10 );
+ QHBoxLayout *lhMiddle = new QHBoxLayout( 5 );
+ QVBoxLayout *lvSliders = new QVBoxLayout( 10 );
+
+ QLabel *l_top = new QLabel( i18n( "<B>Edit the custom gamma table</B><BR>This gamma table is passed to the scanner hardware." ), page );
+ bigdad->addWidget( l_top, 1 );
+ bigdad->addLayout( lhMiddle, 6 );
+
+ lhMiddle->addLayout( lvSliders, 3);
+ lhMiddle->addWidget( gtDisp, 2 );
+
+ /* Slider Widgets for gamma, brightness, contrast */
+ wBright = new KScanSlider ( page, i18n("Brightness"), -50.0, 50.0 );
+ Q_CHECK_PTR(wBright);
+ wBright->slSetSlider( 0 );
+ connect( wBright, SIGNAL(valueChanged(int)), gt, SLOT(setBrightness(int)));
+
+ wContrast = new KScanSlider ( page, i18n("Contrast") , -50.0, 50.0 );
+ Q_CHECK_PTR(wContrast);
+ wContrast->slSetSlider( 0 );
+ connect( wContrast, SIGNAL(valueChanged(int)), gt, SLOT(setContrast(int)));
+
+ wGamma = new KScanSlider ( page, i18n("Gamma"), 30.0, 300.0 );
+ Q_CHECK_PTR(wGamma);
+ wGamma->slSetSlider(100);
+ connect( wGamma, SIGNAL(valueChanged(int)), gt, SLOT(setGamma(int)));
+
+ /* and add the Sliders */
+ lvSliders->addWidget( wBright, 1 );
+ lvSliders->addWidget( wContrast, 1 );
+ lvSliders->addWidget( wGamma, 1 );
+
+ // Finished and Activate !
+ bigdad->activate();
+ resize( 480, 300 );
+}
+
+
+void GammaDialog::setGt(KGammaTable& ngt)
+{
+ *gt = ngt;
+
+ if( wBright ) wBright->slSetSlider( gt->getBrightness() );
+ if( wContrast ) wContrast->slSetSlider( gt->getContrast() );
+ if( wGamma ) wGamma->slSetSlider( gt->getGamma() );
+
+}
+
+void GammaDialog::slotApply()
+{
+ /* and call a signal */
+ KGammaTable *myTable = getGt();
+ emit( gammaToApply( myTable ));
+}
+
+GammaDialog::~GammaDialog()
+{
+
+}
+#include "gammadialog.moc"
diff --git a/libkscan/gammadialog.h b/libkscan/gammadialog.h
new file mode 100644
index 00000000..8ba648a3
--- /dev/null
+++ b/libkscan/gammadialog.h
@@ -0,0 +1,75 @@
+/* This file is part of the KDE Project
+ Copyright (C) 2000 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef GAMMADIALOG_H
+#define GAMMADIALOG_H
+
+#include <qwidget.h>
+#include <qlayout.h>
+
+#include <kgammatable.h>
+#include <kdialogbase.h>
+
+
+
+#include "dispgamma.h"
+
+
+/**
+ *@author Klaas Freitag
+ */
+
+class KScanSlider;
+class KGammaTable;
+
+class GammaDialog : public KDialogBase
+{
+ Q_OBJECT
+// FIXME: Doesn't compile with Qt 3 (malte)
+// Q_PROPERTY( KGammaTable *gt READ getGt WRITE setGt )
+
+public:
+ GammaDialog ( QWidget *parent );
+ ~GammaDialog( );
+
+ KGammaTable *getGt( ) const { return gt; }
+ void setGt( KGammaTable& ngt);
+
+public slots:
+ virtual void slotApply();
+
+signals:
+void gammaToApply( KGammaTable* );
+
+private:
+ KGammaTable *gt;
+ DispGamma *gtDisp;
+
+ QHBoxLayout *lhMiddle;
+ QVBoxLayout *lvSliders;
+
+ KScanSlider *wGamma;
+ KScanSlider *wBright;
+ KScanSlider *wContrast;
+
+ class GammaDialogPrivate;
+ GammaDialogPrivate *d;
+};
+
+#endif
diff --git a/libkscan/img_canvas.cpp b/libkscan/img_canvas.cpp
new file mode 100644
index 00000000..eccaa412
--- /dev/null
+++ b/libkscan/img_canvas.cpp
@@ -0,0 +1,1115 @@
+/* This file is part of the KDE Project
+ Copyright (C) 1999 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qapplication.h>
+#include <qfiledialog.h>
+#include <qstring.h>
+#include <qmessagebox.h>
+#include <qscrollview.h>
+#include <kpopupmenu.h>
+#include <qlabel.h>
+#include <qdict.h>
+#include <qimage.h>
+#include <qpainter.h>
+
+#include <klocale.h>
+#include <kstyle.h>
+#include <kapplication.h>
+
+#include <kpixmapio.h>
+#include <kdebug.h>
+#include <kiconloader.h>
+#include <kcmenumngr.h>
+#include <qpixmap.h>
+
+#define __IMG_CANVAS_CPP__
+
+#include "imgscaledialog.h"
+#include "img_canvas.h"
+
+
+
+#define MIN(x,y) (x<y?x:y)
+
+
+inline void debug_rect( const char *name, QRect *r )
+{
+ kdDebug(29000) << (name ? name: "NONAME") << ": " << r->x() << ", " << r->y() << ", " << r->width() << ", " << r->height() << endl;
+}
+
+
+class ImageCanvas::ImageCanvasPrivate
+{
+public:
+ ImageCanvasPrivate()
+ : keepZoom(false),
+ readOnly(false),
+ scaleKind( UNSPEC ),
+ defaultScaleKind( FIT_ORIG )
+ {}
+
+ bool keepZoom; /* keep the zoom settings if images change */
+ bool readOnly;
+ ScaleKinds scaleKind;
+ ScaleKinds defaultScaleKind;
+
+ QValueList<QRect> highlightRects;
+};
+
+ImageCanvas::ImageCanvas(QWidget *parent,
+ const QImage *start_image,
+ const char *name ):
+ QScrollView( parent, name ),
+ m_contextMenu(0)
+{
+ d = new ImageCanvasPrivate();
+
+ scale_factor = 100; // means original size
+ maintain_aspect = true;
+ selected = new QRect;
+ selected->setWidth(0);
+ selected->setHeight(0);
+
+ timer_id = 0;
+ pmScaled = 0;
+
+ image = start_image;
+ moving = MOVE_NONE;
+
+ QSize img_size;
+
+ if( image && ! image->isNull() )
+ {
+ img_size = image->size();
+ pmScaled = new QPixmap( img_size );
+
+#ifdef USE_KPIXMAPIO
+ *pmScaled = pixIO.convertToPixmap(*image);
+#else
+ pmScaled->convertFromImage( *image );
+#endif
+
+ acquired = true;
+ } else {
+ img_size = size();
+ }
+
+
+ update_scaled_pixmap();
+
+ // timer-Start and stop
+ connect( this, SIGNAL( newRect()), SLOT( newRectSlot()));
+ connect( this, SIGNAL( noRect()), SLOT( noRectSlot()));
+
+ //zoomOut();scrollview/scrollview
+ viewport()->setCursor( crossCursor );
+ cr1 = 0;
+ cr2 = 0;
+ viewport()->setMouseTracking(TRUE);
+ viewport()->setBackgroundMode(PaletteBackground);
+ show();
+
+}
+
+ImageCanvas::~ImageCanvas()
+{
+ kdDebug(29000) << "Destructor of ImageCanvas" << endl;
+ noRectSlot();
+ if( selected ) delete selected;
+ selected = 0;
+ if( pmScaled ) delete pmScaled;
+ pmScaled = 0;
+ delete d;
+}
+
+void ImageCanvas::deleteView( QImage *delimage )
+{
+ const QImage *img = rootImage();
+
+ if( delimage == img )
+ {
+ kdDebug(29000) << "ImageCanvas -> emiting newImage(0L)" << endl;
+ newImage( 0L );
+ noRectSlot();
+ }
+
+}
+
+void ImageCanvas::newImageHoldZoom( QImage *new_image )
+{
+ bool holdZ = d->keepZoom;
+
+ d->keepZoom = true;
+ newImage( new_image );
+ d->keepZoom = holdZ;
+}
+
+void ImageCanvas::newImage( QImage *new_image )
+{
+
+ /** do cleanups **/
+ // dont free old image -> not yours
+ image = new_image;
+
+ if( ! image || image->isNull())
+ {
+ kdDebug(29000) << "newImage: Got Empty image !" << endl;
+ }
+
+ if( pmScaled )
+ {
+ delete pmScaled;
+ pmScaled = 0L;
+ }
+
+ if( selected )
+ {
+ noRectSlot();
+ }
+
+ /* throw away all highlights */
+ d->highlightRects.clear();
+
+ /** handle the new image **/
+ if( image )
+ {
+ if( image->depth() == 1 ) {
+ pmScaled = new QPixmap( image->size(), 1 );
+ } else {
+ int i = QPixmap::defaultDepth();
+ pmScaled = new QPixmap( image->size(), i);
+ }
+
+ // image->convertDepth(32);
+#ifdef USE_KPIXMAPIO
+
+ *pmScaled = pixIO.convertToPixmap(*image);
+#else
+ pmScaled->convertFromImage( *image );
+ // *pmScaled = image->convertToPixmap( );
+#endif
+
+ acquired = true;
+
+ if( d->keepZoom )
+ {
+ kdDebug(29000) << "Preserving Zoom settings!" << endl;
+ }
+ else
+ {
+ kdDebug(29000) << "Resetting Zoom to original size!" << endl;
+ setScaleKind( defaultScaleKind() );
+ }
+
+ update_scaled_pixmap();
+ setContentsPos(0,0);
+ } else {
+ kdDebug(29000) << "New image called without image => deleting!" << endl;
+ acquired = false;
+ resizeContents( 0,0 );
+ }
+
+
+ kdDebug(29000) << "going to repaint!" << endl;
+ repaint( true );
+ kdDebug(29000) << "repaint ok" << endl;
+}
+
+QSize ImageCanvas::sizeHint() const
+{
+ return( QSize( 2, 2 ));
+}
+
+void ImageCanvas::enableContextMenu( bool wantContextMenu )
+{
+ if( wantContextMenu )
+ {
+ if( ! m_contextMenu )
+ {
+ m_contextMenu = new KPopupMenu(this, "IMG_CANVAS");
+
+ KContextMenuManager::insert( viewport(), m_contextMenu );
+ }
+ }
+ else
+ {
+ /* remove all items */
+ if( m_contextMenu ) m_contextMenu->clear();
+ /* contextMenu is not deleted because there is no way to remove
+ * it from the contextMenuManager
+ */
+ }
+
+}
+
+void ImageCanvas::handle_popup( int item )
+{
+ if( item < ID_POP_ZOOM || item > ID_ORIG_SIZE ) return;
+
+ if( ! image ) return;
+ ImgScaleDialog *zoomDia = 0;
+
+ switch( item )
+ {
+ case ID_POP_ZOOM:
+
+ zoomDia = new ImgScaleDialog( this, getScaleFactor() );
+ if( zoomDia->exec() )
+ {
+ int sf = zoomDia->getSelected();
+ setScaleKind(ZOOM);
+ setScaleFactor( sf );
+ }
+ delete zoomDia;
+ zoomDia = 0;
+ break;
+ case ID_ORIG_SIZE:
+ setScaleKind( FIT_ORIG );
+ break;
+ case ID_FIT_WIDTH:
+ setScaleKind( FIT_WIDTH );
+ break;
+ case ID_FIT_HEIGHT:
+ setScaleKind( FIT_HEIGHT );
+ break;
+ case ID_POP_CLOSE:
+ emit( closingRequested());
+ break;
+
+ default: break;
+ }
+ update_scaled_pixmap();
+ repaint();
+}
+
+
+/**
+ * Returns the selected rect in tenth of percent, not in absolute
+ * sizes, eg. 500 means 50.0 % of original width/height.
+ * That makes it easier to work with different scales and units
+ */
+QRect ImageCanvas::sel( void )
+{
+ QRect retval;
+ retval.setCoords(0, 0, 0, 0);
+
+ if( selected && image && selected->width()>MIN_AREA_WIDTH
+ && selected->height()>MIN_AREA_HEIGHT )
+ {
+ /* Get the size in real image pixels */
+
+ // debug_rect( "PRE map", selected );
+ QRect mapped = inv_scale_matrix.map( (const QRect) *selected );
+ // debug_rect( "Postmap", &mapped );
+ if( mapped.x() > 0 )
+ retval.setLeft((int) (1000.0/( (double)image->width() / (double)mapped.x())));
+
+ if( mapped.y() > 0 )
+ retval.setTop((int) (1000.0/( (double)image->height() / (double)mapped.y())));
+
+ if( mapped.width() > 0 )
+ retval.setWidth((int) (1000.0/( (double)image->width() / (double)mapped.width())));
+
+ if( mapped.height() > 0 )
+ retval.setHeight((int)(1000.0/( (double)image->height() / (double)mapped.height())));
+
+ }
+ // debug_rect( "sel() return", &retval );
+ return( retval );
+
+}
+
+bool ImageCanvas::selectedImage( QImage *retImg )
+{
+ QRect r = sel();
+ bool result = false;
+
+ const QImage* entireImg = this->rootImage();
+
+ if( entireImg )
+ {
+ QSize s = entireImg->size();
+
+ int x = (s.width() * r.x())/1000;
+ int y = (s.height() * r.y())/1000;
+ int w = (s.width() * r.width())/1000;
+ int h = (s.height() * r.height())/1000;
+
+ if( w > 0 && h > 0 ) {
+ *retImg = entireImg->copy( x, y, w, h );
+ result = true;
+ }
+ }
+ return(result);
+
+}
+
+
+void ImageCanvas::drawContents( QPainter * p, int clipx, int clipy, int clipw, int cliph )
+{
+ if( !pmScaled ) return;
+ int x1 = 0;
+ int y1 = 0;
+
+ int x2 = pmScaled->width();
+ int y2 = pmScaled->height();
+
+ if (x1 < clipx) x1=clipx;
+ if (y1 < clipy) y1=clipy;
+ if (x2 > clipx+clipw-1) x2=clipx+clipw-1;
+ if (y2 > clipy+cliph-1) y2=clipy+cliph-1;
+
+ // Paint using the small coordinates...
+ // p->scale( used_xscaler, used_yscaler );
+ // p->scale( used_xscaler, used_yscaler );
+ if ( x2 >= x1 && y2 >= y1 ) {
+ p->drawPixmap( x1, y1, *pmScaled, x1, y1 ); //, clipw, cliph);
+ // p->setBrush( red );
+ // p->drawRect( x1, y1, clipw, cliph );
+ }
+
+ // p->fillRect(x1, y1, x2-x1+1, y2-y1+1, red);
+
+}
+
+void ImageCanvas::timerEvent(QTimerEvent *)
+{
+ if(moving!=MOVE_NONE || !acquired ) return;
+ cr1++;
+ QPainter p(viewport());
+ // p.setWindow( contentsX(), contentsY(), contentsWidth(), contentsHeight());
+ drawAreaBorder(&p);
+}
+
+void ImageCanvas::newRectSlot( QRect newSel )
+{
+ QRect to_map;
+ QPainter p(viewport());
+ drawAreaBorder(&p,TRUE);
+ selected->setWidth(0);
+ selected->setHeight(0);
+
+ emit( noRect() );
+
+ if ( image )
+ {
+ int rx, ry, rw, rh;
+ int w = image->width();
+ int h = image->height();
+
+ kdDebug(29000) << "ImageCanvas: Image size is " << w << "x" << h << endl;
+ kdDebug(29000) << "ImageCanvas got selection Rect: W=" << newSel.width() << ", H=" << newSel.height() << endl;
+ // to_map.setWidth(static_cast<int>(w * newSel.width() / 1000.0));
+ rw = static_cast<int>(w * newSel.width() / 1000.0);
+ rx = static_cast<int>(w * newSel.x() / 1000.0);
+ ry = static_cast<int>(h * newSel.y() / 1000.0);
+ rh = static_cast<int>(h * newSel.height() / 1000.0);
+ kdDebug(29000) << "ImageCanvas: scaled Height is " << rh << endl;
+
+ to_map.setRect( rx, ry, rw, rh );
+
+ kdDebug(29000) << "ImageCanvas Selection: W=" << to_map.width() << " H=" << to_map.height() << endl;
+ *selected = scale_matrix.map( to_map );
+ kdDebug(29000) << "ImageCanvas Selection: W=" << selected->width() << " H=" << selected->height() << endl;
+ emit( newRect( sel() ));
+ newRectSlot();
+ }
+}
+
+
+
+void ImageCanvas::newRectSlot( )
+{
+ // printf( "Timer switched on !\n" );
+ if( timer_id == 0 )
+ timer_id = startTimer( 100 );
+}
+
+void ImageCanvas::noRectSlot( void )
+{
+ // printf( "Timer switched off !\n" );
+ if( timer_id ) {
+ killTimer( timer_id );
+ timer_id = 0;
+ }
+
+ if( selected )
+ selected->setCoords( 0,0,0,0 );
+}
+
+void ImageCanvas::viewportMousePressEvent(QMouseEvent *ev)
+{
+ if( ! acquired || ! image ) return;
+
+ if(ev->button()==LeftButton )
+ {
+
+ int cx = contentsX(), cy = contentsY();
+ int x = lx = ev->x(),y = ly = ev->y();
+
+ int ix, iy;
+ scale_matrix.map( image->width(), image->height(), &ix, &iy );
+ if( x > ix-cx || y > iy-cy ) return;
+
+ if( moving == MOVE_NONE )
+ {
+ QPainter p( viewport());
+ drawAreaBorder(&p,TRUE);
+ moving = classifyPoint( x+cx ,y+cy);
+
+ if(moving == MOVE_NONE)
+ { //Create new area
+ selected->setCoords( x+cx, y+cy, x+cx, y+cy );
+ moving = MOVE_BOTTOM_RIGHT;
+ }
+ drawAreaBorder(&p);
+ }
+ }
+}
+
+
+void ImageCanvas::viewportMouseReleaseEvent(QMouseEvent *ev)
+{
+ if(ev->button()!=LeftButton || !acquired ) return;
+
+ //// debug( "Mouse Release at %d/%d", ev->x(), ev->y());
+ if(moving!=MOVE_NONE) {
+ QPainter p(viewport());
+ drawAreaBorder(&p,TRUE);
+ moving = MOVE_NONE;
+ *selected = selected->normalize();
+
+ if(selected->width () < MIN_AREA_WIDTH ||
+ selected->height() < MIN_AREA_HEIGHT)
+ {
+ selected->setWidth(0);
+ selected->setHeight(0);
+ emit noRect();
+ return;
+ }
+
+ drawAreaBorder(&p);
+ emit newRect( sel() );
+ emit newRect( );
+ }
+}
+
+
+void ImageCanvas::viewportMouseMoveEvent(QMouseEvent *ev)
+{
+ if( ! acquired || !image) return;
+
+ static cursor_type ps = HREN;
+ int x = ev->x(), y = ev->y();
+ int cx = contentsX(), cy = contentsY();
+
+ // debug("Mouse Coord x: %d, y: %d | cx: %d, cy: %d", x,y, cx, cy );
+ // dont draw out of the scaled Pixmap
+ if( x < 0 ) x = 0;
+ int ix, iy;
+ scale_matrix.map( image->width(), image->height(), &ix, &iy );
+ if( x >= ix ) return;
+
+ if( y < 0 ) y = 0;
+ if( y >= iy ) return;
+
+ // debug( "cx, cy: %dx%d, x,y: %d, %d",
+ // cx, cy, x, y );
+
+#if 0
+ if( moving == MOVE_NONE )
+ moving = classifyPoint(x, y);
+#endif
+ switch( moving!=MOVE_NONE ? moving:classifyPoint(x+cx,y+cy) ) {
+ case MOVE_NONE:
+ if(ps!=CROSS) {
+ viewport()->setCursor(crossCursor);
+ ps = CROSS;
+ }
+ break;
+ case MOVE_LEFT:
+ case MOVE_RIGHT:
+ if(ps!=HSIZE) {
+ viewport()->setCursor(sizeHorCursor);
+ ps = HSIZE;
+ }
+ break;
+ case MOVE_TOP:
+ case MOVE_BOTTOM:
+ if(ps!=VSIZE) {
+ viewport()->setCursor(sizeVerCursor);
+ ps = VSIZE;
+ }
+ break;
+ case MOVE_TOP_LEFT:
+ case MOVE_BOTTOM_RIGHT:
+ if(ps!=FDIAG) {
+ viewport()->setCursor(sizeFDiagCursor);
+ ps = FDIAG;
+ }
+ break;
+ case MOVE_TOP_RIGHT:
+ case MOVE_BOTTOM_LEFT:
+ if(ps!=BDIAG) {
+ viewport()->setCursor(sizeBDiagCursor);
+ ps = BDIAG;
+ }
+ break;
+ case MOVE_WHOLE:
+ if(ps!=ALL) {
+ viewport()->setCursor(sizeAllCursor);
+ ps = ALL;
+ }
+ }
+ //At ButtonRelease : normalize + clip
+ if( moving!=MOVE_NONE ) {
+ int mx, my;
+ QPainter p(viewport());
+ drawAreaBorder(&p,TRUE);
+ switch(moving) {
+ case MOVE_NONE: //Just to make compiler happy
+ break;
+ case MOVE_TOP_LEFT:
+ selected->setLeft( x + cx );
+ case MOVE_TOP: // fall through
+ selected->setTop( y + cy );
+ break;
+ case MOVE_TOP_RIGHT:
+ selected->setTop( y + cy );
+ case MOVE_RIGHT: // fall through
+ selected->setRight( x + cx );
+ break;
+ case MOVE_BOTTOM_LEFT:
+ selected->setBottom( y + cy );
+ case MOVE_LEFT: // fall through
+ selected->setLeft( x + cx );
+ break;
+ case MOVE_BOTTOM_RIGHT:
+ selected->setRight( x + cx );
+ case MOVE_BOTTOM: // fall through
+ selected->setBottom( y + cy );
+ break;
+ case MOVE_WHOLE:
+ if( selected )
+ {
+ // lx is the Last x-Koord from the run before (global)
+ mx = x-lx; my = y-ly;
+ /* Check if rectangle would run out of the image on right and bottom */
+ if( selected->x()+ selected->width()+mx >= ix-cx )
+ {
+ mx = ix -cx - selected->width() - selected->x();
+ kdDebug(29000) << "runs out !" << endl;
+ }
+ if( selected->y()+ selected->height()+my >= iy-cy )
+ {
+ my = iy -cy - selected->height() - selected->y();
+ kdDebug(29000) << "runs out !" << endl;
+ }
+
+ /* Check if rectangle would run out of the image on left and top */
+ if( selected->x() +mx < 0 )
+ mx = -selected->x();
+ if( selected->y()+ +my < 0 )
+ my = -selected->y();
+
+ x = mx+lx; y = my+ly;
+
+ selected->moveBy( mx, my );
+
+ }
+ }
+ drawAreaBorder(&p);
+ lx = x;
+ ly = y;
+ }
+}
+
+
+void ImageCanvas::setScaleFactor( int i )
+{
+ kdDebug(29000) << "Setting Scalefactor to " << i << endl;
+ scale_factor = i;
+ if( i == 0 ){
+ kdDebug(29000) << "Setting Dynamic Scaling!" << endl;
+ setScaleKind(DYNAMIC);
+ }
+ update_scaled_pixmap();
+}
+
+
+void ImageCanvas::resizeEvent( QResizeEvent * event )
+{
+ QScrollView::resizeEvent( event );
+ update_scaled_pixmap();
+
+}
+
+void ImageCanvas::update_scaled_pixmap( void )
+{
+ resizeContents( 0,0 );
+ updateScrollBars();
+ if( !pmScaled || !image)
+ { // debug( "Pixmap px is null in Update_scaled" );
+ return;
+ }
+
+ QApplication::setOverrideCursor(waitCursor);
+
+ kdDebug(28000) << "Updating scaled_pixmap" << endl;
+ if( scaleKind() == DYNAMIC )
+ kdDebug(28000) << "Scaling DYNAMIC" << endl;
+ QSize noSBSize( visibleWidth(), visibleHeight());
+ const int sbWidth = kapp->style().pixelMetric( QStyle::PM_ScrollBarExtent );
+
+ // if( verticalScrollBar()->visible() ) noSBSize.width()+=sbWidth;
+ // if( horizontalScrollBar()->visible() ) noSBSize.height()+=sbWidth;
+
+ switch( scaleKind() )
+ {
+ case DYNAMIC:
+ // do scaling to window-size
+ used_yscaler = ((double)viewport()-> height()) / ((double)image->height());
+ used_xscaler = ((double)viewport()-> width()) / ((double)image->width());
+ scale_factor = 0;
+ break;
+ case FIT_ORIG:
+ used_yscaler = used_xscaler = 1.0;
+ scale_factor = 100;
+ break;
+ case FIT_WIDTH:
+ used_xscaler = used_yscaler = double(noSBSize.width()) / double(image->width());
+ if( used_xscaler * image->height() >= noSBSize.height() )
+ {
+ /* substract for scrollbar */
+ used_xscaler = used_yscaler = double(noSBSize.width() - sbWidth) /
+ double(image->width());
+ kdDebug(29000) << "FIT WIDTH scrollbar to substract: " << sbWidth << endl;
+ }
+ scale_factor = 100*used_xscaler;
+ break;
+ case FIT_HEIGHT:
+ used_yscaler = used_xscaler = double(noSBSize.height())/double(image->height());
+
+ // scale = int(100.0 * noSBSize.height() / image->height());
+ if( used_xscaler * image->width() >= noSBSize.width() )
+ {
+ /* substract for scrollbar */
+ used_xscaler = used_yscaler = double(noSBSize.height() - sbWidth) /
+ double(image->height());
+
+ kdDebug(29000) << "FIT HEIGHT scrollbar to substract: " << sbWidth << endl;
+ // scale = int(100.0*(noSBSize.height() -sbWidth) / image->height());
+ }
+ scale_factor = 100*used_xscaler;
+
+ break;
+ case ZOOM:
+ used_xscaler = used_yscaler = double(getScaleFactor())/100.0;
+ scale_factor = 100*used_xscaler;
+ break;
+ default:
+ break;
+ }
+
+ // reconvert the selection to orig size
+ if( selected ) {
+ *selected = inv_scale_matrix.map( (const QRect) *selected );
+ }
+
+ scale_matrix.reset(); // transformation matrix
+ inv_scale_matrix.reset();
+
+
+ if( scaleKind() == DYNAMIC && maintain_aspect ) {
+ // printf( "Skaler: x: %f, y: %f\n", x_scaler, y_scaler );
+ used_xscaler = used_yscaler < used_xscaler ?
+ used_yscaler : used_xscaler;
+ used_yscaler = used_xscaler;
+ }
+
+ scale_matrix.scale( used_xscaler, used_yscaler ); // define scale factors
+ inv_scale_matrix = scale_matrix.invert(); // for redraw of selection
+
+ if( selected ) {
+ *selected = scale_matrix.map( (const QRect )*selected );
+ }
+
+#ifdef USE_KPIXMAPIO
+ *pmScaled = pixIO.convertToPixmap(*image);
+#else
+ pmScaled->convertFromImage( *image );
+#endif
+
+ *pmScaled = pmScaled->xForm( scale_matrix ); // create scaled pixmap
+
+ /* Resizing to 0,0 never may be dropped, otherwise there are problems
+ * with redrawing of new images.
+ */
+ resizeContents( static_cast<int>(image->width() * used_xscaler),
+ static_cast<int>(image->height() * used_yscaler ) );
+
+ QApplication::restoreOverrideCursor();
+}
+
+
+void ImageCanvas::drawHAreaBorder(QPainter &p,int x1,int x2,int y,int r)
+{
+ if( ! acquired || !image ) return;
+
+ if(moving!=MOVE_NONE) cr2 = 0;
+ int inc = 1;
+ int cx = contentsX(), cy = contentsY();
+ if(x2 < x1) inc = -1;
+
+ if(!r) {
+ if(cr2 & 4) p.setPen(black);
+ else p.setPen(white);
+ } else if(!acquired) p.setPen(QPen(QColor(150,150,150)));
+
+ for(;;) {
+ if(rect().contains(QPoint(x1,y))) {
+ if( r && acquired ) {
+ int re_x1, re_y;
+ inv_scale_matrix.map( x1+cx, y+cy, &re_x1, &re_y );
+ re_x1 = MIN( image->width()-1, re_x1 );
+ re_y = MIN( image->height()-1, re_y );
+
+ p.setPen( QPen( QColor( image->pixel(re_x1, re_y))));
+ }
+ p.drawPoint(x1,y);
+ }
+ if(!r) {
+ cr2++;
+ cr2 &= 7;
+ if(!(cr2&3)) {
+ if(cr2&4) p.setPen(black);
+ else p.setPen(white);
+ }
+ }
+ if(x1==x2) break;
+ x1 += inc;
+ }
+
+}
+
+void ImageCanvas::drawVAreaBorder(QPainter &p, int x, int y1, int y2, int r )
+{
+ if( ! acquired || !image ) return;
+ if( moving!=MOVE_NONE ) cr2 = 0;
+ int inc = 1;
+ if( y2 < y1 ) inc = -1;
+
+ int cx = contentsX(), cy = contentsY();
+
+
+ if( !r ) {
+ if( cr2 & 4 ) p.setPen(black);
+ else
+ p.setPen(white);
+ } else
+ if( !acquired ) p.setPen( QPen( QColor(150,150,150) ) );
+
+ for(;;) {
+ if(rect().contains( QPoint(x,y1) )) {
+ if( r && acquired ) {
+ int re_y1, re_x;
+ inv_scale_matrix.map( x+cx, y1+cy, &re_x, &re_y1 );
+ re_x = MIN( image->width()-1, re_x );
+ re_y1 = MIN( image->height()-1, re_y1 );
+
+ p.setPen( QPen( QColor( image->pixel( re_x, re_y1) )));
+ }
+ p.drawPoint(x,y1);
+ }
+
+ if(!r) {
+ cr2++;
+ cr2 &= 7;
+ if(!(cr2&3)) {
+ if(cr2&4) p.setPen(black);
+ else p.setPen(white);
+ }
+ }
+ if(y1==y2) break;
+ y1 += inc;
+ }
+
+}
+
+void ImageCanvas::drawAreaBorder(QPainter *p,int r )
+{
+ if(selected->isNull()) return;
+
+ cr2 = cr1;
+ int xinc = 1;
+ if( selected->right() < selected->left()) xinc = -1;
+ int yinc = 1;
+ if( selected->bottom() < selected->top()) yinc = -1;
+
+ if( selected->width() )
+ drawHAreaBorder(*p,
+ selected->left() - contentsX(),
+ selected->right()- contentsX(),
+ selected->top() - contentsY(), r );
+ if( selected->height() ) {
+ drawVAreaBorder(*p,
+ selected->right() - contentsX(),
+ selected->top()- contentsY()+yinc,
+ selected->bottom()- contentsY(),r);
+ if(selected->width()) {
+ drawHAreaBorder(*p,
+ selected->right()-xinc- contentsX(),
+ selected->left()- contentsX(),
+ selected->bottom()- contentsY(),r);
+ drawVAreaBorder(*p,
+ selected->left()- contentsX(),
+ selected->bottom()-yinc- contentsY(),
+ selected->top()- contentsY()+yinc,r);
+ }
+ }
+}
+
+// x and y come as real pixmap-coords, not contents-coords
+preview_state ImageCanvas::classifyPoint(int x,int y)
+{
+ if(selected->isEmpty()) return MOVE_NONE;
+
+ QRect a = selected->normalize();
+
+ int top = 0,left = 0,right = 0,bottom = 0;
+ int lx = a.left()-x, rx = x-a.right();
+ int ty = a.top()-y, by = y-a.bottom();
+
+ if( a.width() > delta*2+2 )
+ lx = abs(lx), rx = abs(rx);
+
+ if(a.height()>delta*2+2)
+ ty = abs(ty), by = abs(by);
+
+ if( lx>=0 && lx<=delta ) left++;
+ if( rx>=0 && rx<=delta ) right++;
+ if( ty>=0 && ty<=delta ) top++;
+ if( by>=0 && by<=delta ) bottom++;
+ if( y>=a.top() &&y<=a.bottom() ) {
+ if(left) {
+ if(top) return MOVE_TOP_LEFT;
+ if(bottom) return MOVE_BOTTOM_LEFT;
+ return MOVE_LEFT;
+ }
+ if(right) {
+ if(top) return MOVE_TOP_RIGHT;
+ if(bottom) return MOVE_BOTTOM_RIGHT;
+ return MOVE_RIGHT;
+ }
+ }
+ if(x>=a.left()&&x<=a.right()) {
+ if(top) return MOVE_TOP;
+ if(bottom) return MOVE_BOTTOM;
+ if(selected->contains(QPoint(x,y))) return MOVE_WHOLE;
+ }
+ return MOVE_NONE;
+}
+
+
+int ImageCanvas::getBrightness() const
+{
+ return brightness;
+}
+
+int ImageCanvas::getContrast() const
+{
+ return contrast;
+}
+
+int ImageCanvas::getGamma() const
+{
+ return gamma;
+}
+
+int ImageCanvas::getScaleFactor() const
+{
+ return( scale_factor );
+}
+
+const QImage *ImageCanvas::rootImage( )
+{
+ return( image );
+}
+
+void ImageCanvas::setReadOnly( bool ro )
+{
+ d->readOnly = ro;
+ emit( imageReadOnly(ro) );
+}
+
+bool ImageCanvas::readOnly()
+{
+ return d->readOnly;
+}
+
+void ImageCanvas::setBrightness(int b)
+{
+ brightness = b;
+}
+
+void ImageCanvas::setContrast(int c)
+{
+ contrast = c;
+}
+
+void ImageCanvas::setGamma(int c)
+{
+ gamma = c;
+}
+
+void ImageCanvas::setKeepZoom( bool k )
+{
+ d->keepZoom = k;
+}
+
+ImageCanvas::ScaleKinds ImageCanvas::scaleKind()
+{
+ if( d->scaleKind == UNSPEC )
+ return defaultScaleKind();
+ else
+ return d->scaleKind;
+}
+
+ImageCanvas::ScaleKinds ImageCanvas::defaultScaleKind()
+{
+ return d->defaultScaleKind;
+}
+
+void ImageCanvas::setScaleKind( ScaleKinds k )
+{
+ if( k == d->scaleKind ) return; // no change, return
+ d->scaleKind = k;
+
+ emit scalingChanged(scaleKindString());
+}
+
+void ImageCanvas::setDefaultScaleKind( ScaleKinds k )
+{
+ d->defaultScaleKind = k;
+}
+
+const QString ImageCanvas::imageInfoString( int w, int h, int d )
+{
+ if( w == 0 && h == 0 && d == 0 )
+ {
+ if( image )
+ {
+ w = image->width();
+ h = image->height();
+ d = image->depth();
+ }
+ else
+ return QString("-");
+ }
+ return i18n("%1x%2 pixel, %3 bit").arg(w).arg(h).arg(d);
+}
+
+
+const QString ImageCanvas::scaleKindString()
+{
+ switch( scaleKind() )
+ {
+ case DYNAMIC:
+ return i18n("Fit window best");
+ break;
+ case FIT_ORIG:
+ return i18n("Original size");
+ break;
+ case FIT_WIDTH:
+ return i18n("Fit Width");
+ break;
+ case FIT_HEIGHT:
+ return i18n("Fit Height");
+ break;
+ case ZOOM:
+ return i18n("Zoom to %1 %%").arg( QString::number(getScaleFactor()));
+ break;
+ default:
+ return i18n("Unknown scaling!");
+ break;
+ }
+}
+
+
+int ImageCanvas::highlight( const QRect& rect, const QPen& pen, const QBrush&, bool ensureVis )
+{
+ QRect saveRect;
+ saveRect.setRect( rect.x()-2, rect.y()-2, rect.width()+4, rect.height()+4 );
+ d->highlightRects.append( saveRect );
+
+ int idx = d->highlightRects.findIndex(saveRect);
+
+ QRect targetRect = scale_matrix.map( rect );
+
+ QPainter p( pmScaled );
+
+ p.setPen(pen);
+ p.drawLine( targetRect.x(), targetRect.y()+targetRect.height(),
+ targetRect.x()+targetRect.width(), targetRect.y()+targetRect.height() );
+
+ p.flush();
+ updateContents(targetRect.x()-1, targetRect.y()-1,
+ targetRect.width()+2, targetRect.height()+2 );
+
+ if( ensureVis )
+ {
+ QPoint p = targetRect.center();
+ ensureVisible( p.x(), p.y(), 10+targetRect.width()/2, 10+targetRect.height()/2 );
+ }
+
+ return idx;
+}
+
+void ImageCanvas::removeHighlight( int idx )
+{
+ if( (unsigned) idx >= d->highlightRects.count() )
+ {
+ kdDebug(28000) << "removeHighlight: Not a valid index" << endl;
+ return;
+ }
+
+ /* take the rectangle from the stored highlight rects and map it to the viewer scaling */
+ QRect r = d->highlightRects[idx];
+ d->highlightRects.remove(r);
+ QRect targetRect = scale_matrix.map( r );
+
+ /* create a small pixmap with a copy of the region in question of the original image */
+ QPixmap origPix;
+ origPix.convertFromImage( image->copy(r) );
+ /* and scale it */
+ QPixmap scaledPix = origPix.xForm( scale_matrix );
+ /* and finally draw it */
+ QPainter p( pmScaled );
+ p.drawPixmap( targetRect, scaledPix );
+ p.flush();
+
+ /* update the viewers contents */
+ updateContents(targetRect.x()-1, targetRect.y()-1,
+ targetRect.width()+2, targetRect.height()+2 );
+
+
+}
+
+
+#include "img_canvas.moc"
diff --git a/libkscan/img_canvas.h b/libkscan/img_canvas.h
new file mode 100644
index 00000000..5abf267c
--- /dev/null
+++ b/libkscan/img_canvas.h
@@ -0,0 +1,221 @@
+/* This file is part of the KDE Project
+ Copyright (C) 1999 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __IMG_CANVAS_H__
+#define __IMG_CANVAS_H__
+
+#include <qwidget.h>
+#include <qrect.h>
+#include <stdlib.h>
+#include <qsize.h>
+#include <qwmatrix.h>
+#include <qscrollview.h>
+#include <qstrlist.h>
+
+#ifdef USE_KPIXMAPIO
+#include <kpixmapio.h>
+#endif
+
+class QPopupMenu;
+class QPixmap;
+class QImage;
+class QPainter;
+
+enum preview_state {
+ MOVE_NONE,
+ MOVE_TOP_LEFT,
+ MOVE_TOP_RIGHT,
+ MOVE_BOTTOM_LEFT,
+ MOVE_BOTTOM_RIGHT,
+ MOVE_LEFT,
+ MOVE_RIGHT,
+ MOVE_TOP,
+ MOVE_BOTTOM,
+ MOVE_WHOLE
+};
+
+enum cursor_type {
+ CROSS,
+ VSIZE,
+ HSIZE,
+ BDIAG,
+ FDIAG,
+ ALL,
+ HREN
+};
+
+const int MIN_AREA_WIDTH = 3;
+const int MIN_AREA_HEIGHT = 3;
+const int delta = 3;
+#ifdef __PREVIEW_CPP__
+int max_dpi = 600;
+#else
+extern int max_dpi;
+#endif
+
+
+
+class ImageCanvas: public QScrollView
+{
+ Q_OBJECT
+ Q_ENUMS( PopupIDs )
+ Q_PROPERTY( int brightness READ getBrightness WRITE setBrightness )
+ Q_PROPERTY( int contrast READ getContrast WRITE setContrast )
+ Q_PROPERTY( int gamma READ getGamma WRITE setGamma )
+ Q_PROPERTY( int scale_factor READ getScaleFactor WRITE setScaleFactor )
+
+public:
+ ImageCanvas( QWidget *parent = 0,
+ const QImage *start_image = 0,
+ const char *name = 0);
+ ~ImageCanvas( );
+
+ int getBrightness() const;
+ int getContrast() const;
+ int getGamma() const;
+
+ int getScaleFactor() const;
+
+ const QImage *rootImage();
+
+ bool hasImage( void ) { return acquired; }
+ QPopupMenu* contextMenu() { return m_contextMenu; }
+ QRect sel( void );
+
+ enum ScaleKinds { UNSPEC, DYNAMIC, FIT_ORIG, FIT_WIDTH, FIT_HEIGHT, ZOOM };
+
+ enum PopupIDs { ID_POP_ZOOM, ID_POP_CLOSE, ID_FIT_WIDTH,
+ ID_FIT_HEIGHT, ID_ORIG_SIZE };
+
+ bool selectedImage( QImage* );
+
+ ScaleKinds scaleKind();
+ const QString scaleKindString();
+
+ ScaleKinds defaultScaleKind();
+
+ const QString imageInfoString( int w=0, int h=0, int d=0 );
+
+public slots:
+ void setBrightness(int);
+ void setContrast(int );
+ void setGamma(int );
+
+ void toggleAspect( int aspect_in_mind )
+ {
+ maintain_aspect = aspect_in_mind;
+ repaint();
+ }
+ virtual QSize sizeHint() const;
+ void newImage( QImage* );
+ void newImageHoldZoom( QImage* );
+ void deleteView( QImage *);
+ void newRectSlot();
+ void newRectSlot( QRect newSel );
+ void noRectSlot( void );
+ void setScaleFactor( int i );
+ void handle_popup(int item );
+ void enableContextMenu( bool wantContextMenu );
+ void setKeepZoom( bool k );
+ void setScaleKind( ScaleKinds k );
+ void setDefaultScaleKind( ScaleKinds k );
+
+ /**
+ * Highlight a rectangular area on the current image using the given brush
+ * and pen.
+ * The function returns a id that needs to be given to the remove method.
+ */
+ int highlight( const QRect&, const QPen&, const QBrush&, bool ensureVis=false );
+
+ /**
+ * reverts the highlighted region back to normal view.
+ */
+ void removeHighlight( int idx = -1 );
+
+ /**
+ * permit to do changes to the image that are saved back to the file
+ */
+ void setReadOnly( bool );
+
+ bool readOnly();
+
+signals:
+ void noRect( void );
+ void newRect( void );
+ void newRect( QRect );
+ void scalingRequested();
+ void closingRequested();
+ void scalingChanged( const QString& );
+ /**
+ * signal emitted if the permission of the currently displayed image changed,
+ * ie. if it goes from writeable to readable.
+ * @param shows if the image is now read only (true) or not.
+ */
+ void imageReadOnly( bool isRO );
+
+protected:
+ void drawContents( QPainter * p, int clipx, int clipy, int clipw, int cliph );
+
+ void timerEvent(QTimerEvent *);
+ void viewportMousePressEvent(QMouseEvent *);
+ void viewportMouseReleaseEvent(QMouseEvent *);
+ void viewportMouseMoveEvent(QMouseEvent *);
+
+ void resizeEvent( QResizeEvent * event );
+
+private:
+ QStrList urls;
+
+ int scale_factor;
+ const QImage *image;
+ int brightness, contrast, gamma;
+
+
+#ifdef USE_KPIXMAPIO
+ KPixmapIO pixIO;
+#endif
+
+ QWMatrix scale_matrix;
+ QWMatrix inv_scale_matrix;
+ QPixmap *pmScaled;
+ float used_yscaler;
+ float used_xscaler;
+ QPopupMenu *m_contextMenu;
+ bool maintain_aspect;
+
+ int timer_id;
+ QRect *selected;
+ preview_state moving;
+ int cr1,cr2;
+ int lx,ly;
+ bool acquired;
+
+ /* private functions for the running ant */
+ void drawHAreaBorder(QPainter &p,int x1,int x2,int y,int r = FALSE);
+ void drawVAreaBorder(QPainter &p,int x,int y1,int y2,int r = FALSE);
+ void drawAreaBorder(QPainter *p,int r = FALSE);
+ void update_scaled_pixmap( void );
+
+ preview_state classifyPoint(int x,int y);
+
+ class ImageCanvasPrivate;
+ ImageCanvasPrivate *d;
+};
+
+#endif
diff --git a/libkscan/imgscaledialog.cpp b/libkscan/imgscaledialog.cpp
new file mode 100644
index 00000000..535d3ffd
--- /dev/null
+++ b/libkscan/imgscaledialog.cpp
@@ -0,0 +1,178 @@
+/* This file is part of the KDE Project
+ Copyright (C) 1999 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <qbuttongroup.h>
+#include <qradiobutton.h>
+#include <knumvalidator.h>
+#include "imgscaledialog.h"
+
+/* ############################################################################## */
+
+
+ImgScaleDialog::ImgScaleDialog( QWidget *parent, int curr_sel,
+ const char *name )
+ :KDialogBase( parent, name , true, i18n("Zoom"),
+ Ok|Cancel, Ok, true )
+{
+ // setCaption (i18n ("Image Zoom"));
+ selected = curr_sel;
+ int one_is_selected = false;
+ enableButtonSeparator( false );
+
+ // (void) new QLabel( , main, "Page");
+ //
+ // makeMainWidget();
+ QButtonGroup *radios = new QButtonGroup ( 2, Qt::Horizontal, this );
+ setMainWidget(radios);
+ Q_CHECK_PTR(radios);
+ radios->setTitle( i18n("Select Image Zoom") );
+
+ connect( radios, SIGNAL( clicked( int )),
+ this, SLOT( setSelValue( int )));
+
+ // left gap: smaller Image
+ QRadioButton *rb25 = new QRadioButton (i18n ("25 %"), radios);
+ if( curr_sel == 25 ){
+ rb25->setChecked( true );
+ one_is_selected = true;
+ }
+
+ QRadioButton *rb50 = new QRadioButton (i18n ("50 %"), radios );
+ if( curr_sel == 50 ){
+ rb50->setChecked( true );
+ one_is_selected = true;
+ }
+
+ QRadioButton *rb75 = new QRadioButton (i18n ("75 %"), radios );
+ if( curr_sel == 75 ) {
+ rb75->setChecked( true );
+ one_is_selected = true;
+ }
+
+ QRadioButton *rb100 = new QRadioButton (i18n ("100 %"), radios);
+ if( curr_sel == 100 ) {
+ rb100->setChecked( true );
+ one_is_selected = true;
+ }
+
+ QRadioButton *rb150 = new QRadioButton (i18n ("150 %"), radios);
+ if( curr_sel == 150 ) {
+ rb150->setChecked( true );
+ one_is_selected = true;
+ }
+
+ QRadioButton *rb200 = new QRadioButton (i18n ("200 %"), radios );
+ if( curr_sel == 200 ) {
+ rb200->setChecked( true );
+ one_is_selected = true;
+ }
+
+ QRadioButton *rb300 = new QRadioButton (i18n ("300 %"), radios );
+ if( curr_sel == 300 ) {
+ rb300->setChecked( true );
+ one_is_selected = true;
+ }
+
+ QRadioButton *rb400 = new QRadioButton (i18n ("400 %"), radios);
+ if( curr_sel == 400 ) {
+ rb400->setChecked( true );
+ one_is_selected = true;
+ }
+
+ // Custom Scaler at the bottom
+ QRadioButton *rbCust = new QRadioButton (i18n ("Custom scale factor:"),
+ radios);
+ if( ! one_is_selected )
+ rbCust->setChecked( true );
+
+
+ leCust = new QLineEdit( radios );
+ QString sn;
+ sn.setNum(curr_sel );
+ leCust->setValidator( new KIntValidator( leCust ) );
+ leCust->setText(sn );
+ connect( leCust, SIGNAL( textChanged( const QString& )),
+ this, SLOT( customChanged( const QString& )));
+ connect( rbCust, SIGNAL( toggled( bool )),
+ this, SLOT(enableAndFocus(bool)));
+ leCust->setEnabled( rbCust->isChecked());
+
+
+}
+
+void ImgScaleDialog::customChanged( const QString& s )
+{
+ bool ok;
+ int okval = s.toInt( &ok );
+ if( ok && okval > 5 && okval < 1000 ) {
+ selected = okval;
+ emit( customScaleChange( okval ));
+ } else {
+ kdDebug(29000) << "ERR: To large, to smale, or whatever shitty !" << endl;
+ }
+}
+
+// This slot is called, when the user changes the Scale-Selection
+// in the button group. The value val is the index of the active
+// button which is translated to the Scale-Size in percent.
+// If custom size is selected, the ScaleSize is read from the
+// QLineedit.
+//
+void ImgScaleDialog::setSelValue( int val )
+{
+ const int translator[]={ 25, 50, 75, 100, 150,200,300, 400, -1 };
+ const size_t translator_size = sizeof( translator ) / sizeof(int);
+ int old_sel = selected;
+
+ // Check if value is in Range
+ if( val >= 0 && val < (int) translator_size ) {
+ selected = translator[val];
+
+ // Custom size selected
+ if( selected == -1 ) {
+ QString s = leCust->text();
+
+ bool ok;
+ int okval = s.toInt( &ok );
+ if( ok ) {
+ selected = okval;
+ emit( customScaleChange( okval ));
+ } else {
+ selected = old_sel;
+ }
+ } // Selection is not custom
+ } else {
+ kdDebug(29000) << "ERR: Invalid size selected !" << endl;
+ }
+ // debug( "SetValue: Selected Scale is %d", selected );
+}
+
+
+int ImgScaleDialog::getSelected() const
+{
+ return( selected );
+}
+
+
+/* ############################################################################## */
+
+
+#include "imgscaledialog.moc"
diff --git a/libkscan/imgscaledialog.h b/libkscan/imgscaledialog.h
new file mode 100644
index 00000000..8bbe1963
--- /dev/null
+++ b/libkscan/imgscaledialog.h
@@ -0,0 +1,62 @@
+/* This file is part of the KDE Project
+ Copyright (C) 1999 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __IMGSCALEDIALOG_H__
+#define __IMGSCALEDIALOG_H__
+
+#include <qlineedit.h>
+#include <kdialogbase.h>
+
+
+/* ----------------------------------------------------------------------
+ * The ImgScaleDialg is a small dialog to be used by the image canvas. It
+ * allows the user to select a zoom factor in percent, either in steps
+ * or as a custom value.
+ */
+class ImgScaleDialog : public KDialogBase
+{
+ Q_OBJECT
+ Q_PROPERTY( int selected READ getSelected WRITE setSelValue )
+
+public:
+ ImgScaleDialog( QWidget *parent, int curr_sel = 100,
+ const char *name = 0 );
+
+public slots:
+ void enableAndFocus( bool b )
+ {
+ leCust->setEnabled( b ); leCust->setFocus();
+ }
+
+ void setSelValue( int val );
+ int getSelected() const;
+
+signals:
+ void customScaleChange( int );
+public slots:
+ void customChanged( const QString& );
+private:
+ QLineEdit *leCust;
+ int selected;
+
+ class ImgScaleDialogPrivate;
+ ImgScaleDialogPrivate *d;
+};
+
+#endif
diff --git a/libkscan/imgscaninfo.cpp b/libkscan/imgscaninfo.cpp
new file mode 100644
index 00000000..a3287a5b
--- /dev/null
+++ b/libkscan/imgscaninfo.cpp
@@ -0,0 +1,75 @@
+/* This file is part of the KDE Project
+ Copyright (C) 2004 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "imgscaninfo.h"
+
+#include <klocale.h>
+#include <kdebug.h>
+
+
+/* ############################################################################## */
+
+ImgScanInfo::ImgScanInfo()
+ :m_xRes(0),
+ m_yRes(0),
+ d(0)
+{
+
+
+}
+
+void ImgScanInfo::setXResolution( int xres )
+{
+ m_xRes = xres;
+}
+
+int ImgScanInfo::getXResolution()
+{
+ return m_xRes;
+}
+
+void ImgScanInfo::setYResolution( int yres )
+{
+ m_yRes = yres;
+}
+
+int ImgScanInfo::getYResolution()
+{
+ return m_yRes;
+}
+
+void ImgScanInfo::setMode( const QString& smode )
+{
+ m_mode = smode;
+}
+
+QString ImgScanInfo::getMode()
+{
+ return m_mode;
+}
+
+void ImgScanInfo::setScannerName( const QString& name )
+{
+ m_scanner = name;
+}
+
+QString ImgScanInfo::getScannerName()
+{
+ return m_scanner;
+}
diff --git a/libkscan/imgscaninfo.h b/libkscan/imgscaninfo.h
new file mode 100644
index 00000000..05ff63e2
--- /dev/null
+++ b/libkscan/imgscaninfo.h
@@ -0,0 +1,52 @@
+/* This file is part of the KDE Project
+ Copyright (C) 1999 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef __IMGSCANINFO_H__
+#define __IMGSCANINFO_H__
+
+#include <qstring.h>
+
+/* ----------------------------------------------------------------------
+ *
+ */
+class ImgScanInfo
+{
+public:
+ ImgScanInfo();
+
+ int getXResolution();
+ int getYResolution();
+ QString getMode();
+ QString getScannerName();
+
+ void setXResolution( int );
+ void setYResolution( int );
+ void setMode( const QString& );
+ void setScannerName( const QString& );
+private:
+ int m_xRes;
+ int m_yRes;
+ QString m_mode;
+ QString m_scanner;
+
+ class ImgScanInfoPrivate;
+ ImgScanInfoPrivate *d;
+};
+
+#endif
diff --git a/libkscan/kgammatable.cpp b/libkscan/kgammatable.cpp
new file mode 100644
index 00000000..4f1ef64f
--- /dev/null
+++ b/libkscan/kgammatable.cpp
@@ -0,0 +1,93 @@
+/* This file is part of the KDE Project
+ Copyright (C) 2002 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <math.h>
+
+#include <kdebug.h>
+#include "kgammatable.h"
+
+KGammaTable::KGammaTable( int gamma, int brightness, int contrast )
+ : QObject()
+{
+ g = gamma < 1 ? 1 : gamma;
+ b = brightness;
+ c = contrast;
+ gt.resize(256);
+ calcTable();
+}
+
+const KGammaTable& KGammaTable::operator=(const KGammaTable& gt)
+{
+ if( this != &gt )
+ {
+ g = gt.g;
+ b = gt.b;
+ c = gt.c;
+
+ calcTable();
+ }
+
+ return( *this );
+}
+
+inline SANE_Word adjust( SANE_Word x, int gl,int bl,int cl)
+{
+ //printf("x : %d, x/256 : %lg, g : %d, 100/g : %lg",
+ // x,(double)x/256.0,g,100.0/(double)g);
+ x = ( SANE_Int )(256*pow((double)x/256.0,100.0/(double)gl));
+ x = ((65536/(128-cl)-256)*(x-128)>>8)+128+bl;
+ if(x<0) x = 0; else if(x>255) x = 255;
+ //printf(" -> %d\n",x);
+ return x;
+}
+
+void KGammaTable::calcTable( )
+{
+ int br = (b<<8)/(128-c);
+ int gr = g;
+ int cr = c;
+
+ if( gr == 0 )
+ {
+ kdDebug(29000) << "Cant calc table -> would raise div. by zero !" << endl;
+ return;
+ }
+
+ for( SANE_Word i = 0; i<256; i++)
+ gt[i] = adjust(i, gr, br, cr );
+
+ dirty = false;
+}
+
+void KGammaTable::setAll( int gamma, int brightness, int contrast )
+{
+ g = gamma < 1 ? 1 : gamma;
+ b = brightness;
+ c = contrast;
+
+ dirty = true;
+}
+
+
+SANE_Word* KGammaTable::getTable()
+{
+ if( dirty ) calcTable();
+ return( gt.data());
+}
+#include "kgammatable.moc"
diff --git a/libkscan/kgammatable.h b/libkscan/kgammatable.h
new file mode 100644
index 00000000..05e71ddd
--- /dev/null
+++ b/libkscan/kgammatable.h
@@ -0,0 +1,71 @@
+/* This file is part of the KDE Project
+ Copyright (C) 2002 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KGAMMATABLE_H
+#define KGAMMATABLE_H
+
+#include <qmemarray.h>
+#include <qobject.h>
+
+extern "C" {
+#include <sane/sane.h>
+}
+
+class KGammaTable: public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY( int g READ getGamma WRITE setGamma )
+ Q_PROPERTY( int c READ getContrast WRITE setContrast )
+ Q_PROPERTY( int b READ getBrightness WRITE setBrightness )
+
+public:
+ KGammaTable ( int gamma = 100, int brightness = 0,
+ int contrast = 0 );
+ void setAll ( int gamma, int brightness, int contrast );
+ QMemArray<SANE_Word> *getArrayPtr( void ) { return &gt; }
+
+ int getGamma( ) const { return g; }
+ int getBrightness( ) const { return b; }
+ int getContrast( ) const { return c; }
+
+ const KGammaTable& operator=(const KGammaTable&);
+
+public slots:
+ void setContrast ( int con ) { c = con; dirty = true; emit( tableChanged() );}
+ void setBrightness ( int bri ) { b = bri; dirty = true; emit( tableChanged() );}
+ void setGamma ( int gam ) { g = gam; dirty = true; emit( tableChanged() );}
+
+ int tableSize() { return gt.size(); }
+ SANE_Word *getTable();
+
+signals:
+ void tableChanged(void);
+
+private:
+ void calcTable( );
+ int g, b, c;
+ bool dirty;
+ QMemArray<SANE_Word> gt;
+
+ class KGammaTablePrivate;
+ KGammaTablePrivate *d;
+};
+
+#endif // KGAMMATABLE_H
diff --git a/libkscan/kscandevice.cpp b/libkscan/kscandevice.cpp
new file mode 100644
index 00000000..ca678eac
--- /dev/null
+++ b/libkscan/kscandevice.cpp
@@ -0,0 +1,1541 @@
+/* This file is part of the KDE Project
+ Copyright (C) 1999 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <stdlib.h>
+#include <qwidget.h>
+#include <qobject.h>
+#include <qasciidict.h>
+#include <qcombobox.h>
+#include <qslider.h>
+#include <qcheckbox.h>
+#include <qlineedit.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qtooltip.h>
+#include <qimage.h>
+#include <qfileinfo.h>
+#include <qapplication.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kconfig.h>
+#include <kstandarddirs.h>
+
+#include <unistd.h>
+#include "kgammatable.h"
+#include "kscandevice.h"
+#include "kscanslider.h"
+#include "kscanoption.h"
+#include "kscanoptset.h"
+#include "devselector.h"
+#include "imgscaninfo.h"
+
+#include <ksimpleconfig.h>
+
+#define MIN_PREVIEW_DPI 75
+#define UNDEF_SCANNERNAME I18N_NOOP( "undefined" )
+#define MAX_PROGRESS 100
+
+/* ---------------------------------------------------------------------------
+ Private class for KScanDevice
+ ------------------------------------------------------------------------- */
+class KScanDevice::KScanDevicePrivate
+
+{
+public:
+ KScanDevicePrivate()
+ : currScanResolutionX(0),
+ currScanResolutionY(0)
+ {
+
+ }
+
+ int currScanResolutionX, currScanResolutionY;
+
+};
+
+
+/* ---------------------------------------------------------------------------
+
+ ------------------------------------------------------------------------- */
+void KScanDevice::guiSetEnabled( const QCString& name, bool state )
+{
+ KScanOption *so = getExistingGuiElement( name );
+
+ if( so )
+ {
+ QWidget *w = so->widget();
+
+ if( w )
+ w->setEnabled( state );
+ }
+}
+
+
+/* ---------------------------------------------------------------------------
+
+ ------------------------------------------------------------------------- */
+KScanOption *KScanDevice::getExistingGuiElement( const QCString& name )
+{
+ KScanOption *ret = 0L;
+
+ QCString alias = aliasName( name );
+
+ /* gui_elements is a QList<KScanOption> */
+ for( ret = gui_elements.first(); ret != 0; ret = gui_elements.next())
+ {
+ if( ret->getName() == alias ) break;
+ }
+
+ return( ret );
+}
+/* ---------------------------------------------------------------------------
+
+ ------------------------------------------------------------------------- */
+
+KScanOption *KScanDevice::getGuiElement( const QCString& name, QWidget *parent,
+ const QString& desc,
+ const QString& tooltip )
+{
+ if( name.isEmpty() ) return(0);
+ QWidget *w = 0;
+ KScanOption *so = 0;
+
+ QCString alias = aliasName( name );
+
+ /* Check if already exists */
+ so = getExistingGuiElement( name );
+
+ if( so ) return( so );
+
+ /* ...else create a new one */
+ so = new KScanOption( alias );
+
+ if( so->valid() && so->softwareSetable())
+ {
+ /** store new gui-elem in list of all gui-elements */
+ gui_elements.append( so );
+
+ w = so->createWidget( parent, desc, tooltip );
+ if( w )
+ {
+ connect( so, SIGNAL( optionChanged( KScanOption* ) ),
+ this, SLOT( slOptChanged( KScanOption* )));
+ w->setEnabled( so->active() );
+ }
+ else
+ {
+ kdDebug(29000) << "ERROR: No widget created for " << name << endl;
+ }
+ }
+ else
+ {
+ if( !so->valid())
+ kdDebug(29000) << "getGuiElem: no option <" << alias << ">" << endl;
+ else
+ if( !so->softwareSetable())
+ kdDebug(29000) << "getGuiElem: option <" << alias << "> is not software Setable" << endl;
+
+ delete so;
+ so = 0;
+ }
+
+ return( so );
+}
+// ---------------------------------------------------------------------------
+
+// ---------------------------------------------------------------------------
+
+
+KScanDevice::KScanDevice( QObject *parent )
+ : QObject( parent )
+{
+ SANE_Status sane_stat = sane_init(NULL, NULL );
+
+ d = new KScanDevicePrivate();
+
+ option_dic = new QAsciiDict<int>;
+ option_dic->setAutoDelete( true );
+ gui_elements.setAutoDelete( true );
+
+ scanner_initialised = false; /* stays false until openDevice. */
+ scanStatus = SSTAT_SILENT;
+
+ data = 0; /* temporary image data buffer while scanning */
+ sn = 0; /* socket notifier for async scanning */
+ img = 0; /* temporary image to scan in */
+ storeOptions = 0; /* list of options to store during preview */
+ overall_bytes = 0;
+ rest_bytes = 0;
+ pixel_x = 0;
+ pixel_y = 0;
+ scanner_name = 0L;
+
+ KConfig *konf = KGlobal::config ();
+ konf->setGroup( GROUP_STARTUP );
+ bool netaccess = konf->readBoolEntry( STARTUP_ONLY_LOCAL, false );
+ kdDebug(29000) << "Query for network scanners " << (netaccess ? "Not enabled" : "Enabled") << endl;
+ if( sane_stat == SANE_STATUS_GOOD )
+ {
+ sane_stat = sane_get_devices( &dev_list, netaccess ? SANE_TRUE : SANE_FALSE );
+
+ // NO network devices yet
+
+ // Store all available Scanner to Stringlist
+ for( int devno = 0; sane_stat == SANE_STATUS_GOOD &&
+ dev_list[ devno ]; ++devno )
+ {
+ if( dev_list[devno] )
+ {
+ scanner_avail.append( dev_list[devno]->name );
+ scannerDevices.insert( dev_list[devno]->name, dev_list[devno] );
+ kdDebug(29000) << "Found Scanner: " << dev_list[devno]->name << endl;
+ }
+ }
+#if 0
+ connect( this, SIGNAL(sigOptionsChanged()), SLOT(slReloadAll()));
+#endif
+ gammaTables = new KScanOptSet( "GammaTables" );
+ }
+ else
+ {
+ kdDebug(29000) << "ERROR: sane_init failed -> SANE installed ?" << endl;
+ }
+
+ connect( this, SIGNAL( sigScanFinished( KScanStat )), SLOT( slScanFinished( KScanStat )));
+
+}
+
+
+KScanDevice::~KScanDevice()
+{
+ if( storeOptions ) delete (storeOptions );
+ kdDebug(29000) << "Calling sane_exit to finish sane!" << endl;
+ sane_exit();
+ delete d;
+}
+
+
+KScanStat KScanDevice::openDevice( const QCString& backend )
+{
+ KScanStat stat = KSCAN_OK;
+ SANE_Status sane_stat = SANE_STATUS_GOOD;
+
+ if( backend.isEmpty() ) return KSCAN_ERR_PARAM;
+
+ // search for scanner
+ int indx = scanner_avail.find( backend );
+
+ if( indx < 0 ) {
+ stat = KSCAN_ERR_NO_DEVICE;
+ }
+
+ // if available, build lists of properties
+ if( stat == KSCAN_OK )
+ {
+ sane_stat = sane_open( backend, &scanner_handle );
+
+
+ if( sane_stat == SANE_STATUS_GOOD )
+ {
+ // fill description dic with names and numbers
+ stat = find_options();
+ scanner_name = backend;
+
+ } else {
+ stat = KSCAN_ERR_OPEN_DEV;
+ scanner_name = UNDEF_SCANNERNAME;
+ }
+ }
+
+ if( stat == KSCAN_OK )
+ scanner_initialised = true;
+
+ return( stat );
+}
+
+void KScanDevice::slCloseDevice( )
+{
+ /* First of all, send a signal to close down the scanner dev. */
+ emit( sigCloseDevice( ));
+
+ kdDebug(29000) << "Saving scan settings" << endl;
+ slSaveScanConfigSet( DEFAULT_OPTIONSET, i18n("the default startup setup"));
+
+ /* After return, delete all related stuff */
+ scanner_name = UNDEF_SCANNERNAME;
+ if( scanner_handle )
+ {
+ if( scanStatus != SSTAT_SILENT )
+ {
+ kdDebug(29000) << "Scanner is still active, calling cancel !" << endl;
+ sane_cancel( scanner_handle );
+ }
+ sane_close( scanner_handle );
+ scanner_handle = 0;
+ }
+
+ gui_elements.clear();
+
+ option_dic->clear();
+ scanner_initialised = false;
+
+}
+
+
+QString KScanDevice::getScannerName(const QCString& name) const
+{
+ QString ret = i18n("No scanner selected");
+ SANE_Device *scanner = 0L;
+
+ if( scanner_name && scanner_initialised && name.isEmpty())
+ {
+ scanner = scannerDevices[ scanner_name ];
+ }
+ else if ( ! name.isEmpty() )
+ {
+ scanner = scannerDevices[ name ];
+ ret = QString::null;
+ }
+
+ if( scanner ) {
+ // ret.sprintf( "%s %s %s", scanner->vendor, scanner->model, scanner->type );
+ ret.sprintf( "%s %s", scanner->vendor, scanner->model );
+ }
+
+ kdDebug(29000) << "getScannerName returns <" << ret << ">" << endl;
+ return ( ret );
+}
+
+
+QSize KScanDevice::getMaxScanSize( void ) const
+{
+ QSize s;
+ double min, max, q;
+
+ KScanOption so_w( SANE_NAME_SCAN_BR_X );
+ so_w.getRange( &min, &max, &q );
+
+ s.setWidth( (int) max );
+
+ KScanOption so_h( SANE_NAME_SCAN_BR_Y );
+ so_h.getRange( &min, &max, &q );
+
+ s.setHeight( (int) max );
+
+ return( s );
+}
+
+
+KScanStat KScanDevice::find_options()
+{
+ KScanStat stat = KSCAN_OK;
+ SANE_Int n;
+ SANE_Int opt;
+ int *new_opt;
+
+ SANE_Option_Descriptor *d;
+
+ if( sane_control_option(scanner_handle, 0,SANE_ACTION_GET_VALUE, &n, &opt)
+ != SANE_STATUS_GOOD )
+ stat = KSCAN_ERR_CONTROL;
+
+ // printf("find_options(): Found %d options\n", n );
+
+ // resize the Array which hold the descriptions
+ if( stat == KSCAN_OK )
+ {
+
+ option_dic->clear();
+
+ for(int i = 1; i<n; i++)
+ {
+ d = (SANE_Option_Descriptor*)
+ sane_get_option_descriptor( scanner_handle, i);
+
+ if( d )
+ {
+ // logOptions( d );
+ if(d->name )
+ {
+ // Die Option anhand des Namen in den Dict
+
+ if( strlen( d->name ) > 0 )
+ {
+ new_opt = new int;
+ *new_opt = i;
+ kdDebug(29000) << "Inserting <" << d->name << "> as " << *new_opt << endl;
+ /* create a new option in the set. */
+ option_dic->insert ( (const char*)d->name, new_opt );
+ option_list.append( (const char*) d->name );
+#if 0
+ KScanOption *newOpt = new KScanOption( d->name );
+ const QString qq = newOpt->get();
+ qDebug( "INIT: <%s> = <%s>", d->name, qq );
+ allOptionSet->insert( d->name, newOpt );
+#endif
+ }
+ else if( d->type == SANE_TYPE_GROUP )
+ {
+ // qDebug( "######### Group found: %s ########", d->title );
+ }
+ else
+ kdDebug(29000) << "Unable to detect option " << endl;
+ }
+ }
+ }
+ }
+ return stat;
+}
+
+
+QStrList KScanDevice::getAllOptions()
+{
+ return( option_list );
+}
+
+QStrList KScanDevice::getCommonOptions()
+{
+ QStrList com_opt;
+
+ QCString s = option_list.first();
+
+ while( !s.isEmpty() )
+ {
+ KScanOption opt( s );
+ if( opt.commonOption() )
+ com_opt.append( s );
+ s = option_list.next();
+ }
+ return( com_opt );
+}
+
+QStrList KScanDevice::getAdvancedOptions()
+{
+ QStrList com_opt;
+
+ QCString s = option_list.first();
+
+ while( !s.isEmpty() )
+ {
+ KScanOption opt( s );
+ if( !opt.commonOption() )
+ com_opt.append( s );
+ s = option_list.next();
+ }
+ return( com_opt );
+}
+
+KScanStat KScanDevice::apply( KScanOption *opt, bool isGammaTable )
+{
+ KScanStat stat = KSCAN_OK;
+ if( !opt ) return( KSCAN_ERR_PARAM );
+ int sane_result = 0;
+
+ int *num = (*option_dic)[ opt->getName() ];
+ SANE_Status sane_stat = SANE_STATUS_GOOD;
+ const QCString& oname = opt->getName();
+
+ if ( oname == "preview" || oname == "mode" ) {
+ sane_stat = sane_control_option( scanner_handle, *num,
+ SANE_ACTION_SET_AUTO, 0,
+ &sane_result );
+ /* No return here, please ! Carsten, does it still work than for you ? */
+ }
+
+
+ if( ! opt->initialised() || opt->getBuffer() == 0 )
+ {
+ kdDebug(29000) << "Attempt to set Zero buffer of " << oname << " -> skipping !" << endl;
+
+ if( opt->autoSetable() )
+ {
+ kdDebug(29000) << "Setting option automatic !" << endl;
+ sane_stat = sane_control_option( scanner_handle, *num,
+ SANE_ACTION_SET_AUTO, 0,
+ &sane_result );
+ }
+ else
+ {
+ sane_stat = SANE_STATUS_INVAL;
+ }
+ stat = KSCAN_ERR_PARAM;
+ }
+ else
+ {
+ if( ! opt->active() )
+ {
+ kdDebug(29000) << "Option " << oname << " is not active now!" << endl;
+ stat = KSCAN_OPT_NOT_ACTIVE;
+ }
+ else if( ! opt->softwareSetable() )
+ {
+ kdDebug(29000) << "Option " << oname << " is not software Setable!" << endl;
+ stat = KSCAN_OPT_NOT_ACTIVE;
+ }
+ else
+ {
+
+ sane_stat = sane_control_option( scanner_handle, *num,
+ SANE_ACTION_SET_VALUE,
+ opt->getBuffer(),
+ &sane_result );
+ }
+ }
+
+ if( stat == KSCAN_OK )
+ {
+ if( sane_stat == SANE_STATUS_GOOD )
+ {
+ kdDebug(29000) << "Applied <" << oname << "> successfully" << endl;
+
+ if( sane_result & SANE_INFO_RELOAD_OPTIONS )
+ {
+ kdDebug(29000) << "* Setting status to reload options" << endl;
+ stat = KSCAN_RELOAD;
+#if 0
+ qDebug( "Emitting sigOptionChanged()" );
+ emit( sigOptionsChanged() );
+#endif
+ }
+
+#if 0
+ if( sane_result & SANE_INFO_RELOAD_PARAMS )
+ emit( sigScanParamsChanged() );
+#endif
+ if( sane_result & SANE_INFO_INEXACT )
+ {
+ kdDebug(29000) << "Option <" << oname << "> was set inexact !" << endl;
+ }
+
+ /* if it is a gamma table, the gamma values must be stored */
+ if( isGammaTable )
+ {
+ gammaTables->backupOption( *opt );
+ kdDebug(29000) << "GammaTable stored: " << opt->getName() << endl;
+ }
+ }
+ else
+ {
+ kdDebug(29000) << "Status of sane is bad: " << sane_strstatus( sane_stat )
+ << " for option " << oname << endl;
+
+ }
+ }
+ else
+ {
+ kdDebug(29000) << "Setting of <" << oname << "> failed -> kscanerror." << endl;
+ }
+
+ if( stat == KSCAN_OK )
+ {
+ slSetDirty( oname );
+ }
+
+ return( stat );
+}
+
+bool KScanDevice::optionExists( const QCString& name )
+{
+ if( name.isEmpty() ) return false;
+ int *i = 0L;
+
+ QCString altname = aliasName( name );
+
+ if( ! altname.isNull() )
+ i = (*option_dic)[ altname ];
+
+ if( !i )
+ return( false );
+ return( *i > -1 );
+}
+
+void KScanDevice::slSetDirty( const QCString& name )
+{
+ if( optionExists( name ) )
+ {
+ if( dirtyList.find( name ) == -1 )
+ {
+ kdDebug(29000)<< "Setting dirty <" << name << ">" << endl;
+ /* item not found */
+ dirtyList.append( name );
+ }
+ }
+}
+
+
+/* This function tries to find name aliases which appear from backend to backend.
+ * Example: Custom-Gamma is for epson backends 'gamma-correction' - not a really
+ * cool thing :-|
+ * Maybe this helps us out ?
+ */
+QCString KScanDevice::aliasName( const QCString& name )
+{
+ int *i = (*option_dic)[ name ];
+ QCString ret;
+
+ if( i ) return( name );
+ ret = name;
+
+ if( name == SANE_NAME_CUSTOM_GAMMA )
+ {
+ if((*option_dic)["gamma-correction"])
+ ret = "gamma-correction";
+
+ }
+
+ if( ret != name )
+ kdDebug( 29000) << "Found alias for <" << name << "> which is <" << ret << ">" << endl;
+
+ return( ret );
+}
+
+
+
+/* Nothing to do yet. This Slot may get active to do same user Widget changes */
+void KScanDevice::slOptChanged( KScanOption *opt )
+{
+ kdDebug(29000) << "Slot Option Changed for Option " << opt->getName() << endl;
+ apply( opt );
+}
+
+/* This might result in a endless recursion ! */
+void KScanDevice::slReloadAllBut( KScanOption *not_opt )
+{
+ if( ! not_opt )
+ {
+ kdDebug(29000) << "ReloadAllBut called with invalid argument" << endl;
+ return;
+ }
+
+ /* Make sure its applied */
+ apply( not_opt );
+
+ kdDebug(29000) << "*** Reload of all except <" << not_opt->getName() << "> forced ! ***" << endl;
+
+ for( KScanOption *so = gui_elements.first(); so; so = gui_elements.next())
+ {
+ if( so != not_opt )
+ {
+ kdDebug(29000) << "Reloading <" << so->getName() << ">" << endl;
+ so->slReload();
+ so->slRedrawWidget(so);
+ }
+ }
+ kdDebug(29000) << "*** Reload of all finished ! ***" << endl;
+
+}
+
+
+/* This might result in a endless recursion ! */
+void KScanDevice::slReloadAll( )
+{
+ kdDebug(29000) << "*** Reload of all forced ! ***" << endl;
+
+ for( KScanOption *so = gui_elements.first(); so; so = gui_elements.next())
+ {
+ so->slReload();
+ so->slRedrawWidget(so);
+ }
+}
+
+
+void KScanDevice::slStopScanning( void )
+{
+ kdDebug(29000) << "Attempt to stop scanning" << endl;
+ if( scanStatus == SSTAT_IN_PROGRESS )
+ {
+ emit( sigScanFinished( KSCAN_CANCELLED ));
+ }
+ scanStatus = SSTAT_STOP_NOW;
+}
+
+
+const QString KScanDevice::previewFile()
+{
+ QString dir = (KGlobal::dirs())->saveLocation( "data", "ScanImages", true );
+ if( !dir.endsWith("/") )
+ dir += "/";
+
+ QString fname = dir + QString::fromLatin1(".previews/");
+ QString sname( getScannerName(shortScannerName()) );
+ sname.replace( '/', "_");
+
+ return fname+sname;
+}
+
+QImage KScanDevice::loadPreviewImage()
+{
+ const QString prevFile = previewFile();
+ kdDebug(29000) << "Loading preview from file " << prevFile << endl;
+
+ QImage image;
+ image.load( prevFile );
+
+ return image;
+}
+
+bool KScanDevice::savePreviewImage( const QImage &image )
+{
+ if( image.isNull() )
+ return false;
+
+ const QString prevFile = previewFile();
+ kdDebug(29000) << "Saving preview to file " << prevFile << endl;
+
+ return image.save( prevFile, "BMP" );
+}
+
+
+KScanStat KScanDevice::acquirePreview( bool forceGray, int dpi )
+{
+ if( ! scanner_handle )
+ return KSCAN_ERR_NO_DEVICE;
+
+ double min, max, q;
+
+ (void) forceGray;
+
+ if( storeOptions )
+ storeOptions->clear();
+ else
+ storeOptions = new KScanOptSet( "TempStore" );
+
+
+ /* set Preview = ON if exists */
+ if( optionExists( SANE_NAME_PREVIEW ) )
+ {
+ KScanOption prev( aliasName(SANE_NAME_PREVIEW) );
+
+ prev.set( true );
+ apply( &prev );
+
+ /* after having applied, save set to false to switch preview mode off after
+ scanning */
+ prev.set( false );
+ storeOptions->backupOption( prev );
+ }
+
+ /* Gray-Preview only done by widget ? */
+ if( optionExists( SANE_NAME_GRAY_PREVIEW ))
+ {
+ KScanOption *so = getExistingGuiElement( SANE_NAME_GRAY_PREVIEW );
+ if( so )
+ {
+ if( so->get() == "true" )
+ {
+ /* Gray preview on */
+ so->set( true );
+ kdDebug(29000) << "Setting GrayPreview ON" << endl;
+ }
+ else
+ {
+ so->set(false );
+ kdDebug(29000) << "Setting GrayPreview OFF" << endl;
+ }
+ }
+ apply( so );
+ }
+
+
+ if( optionExists( SANE_NAME_SCAN_MODE ) )
+ {
+ KScanOption mode( SANE_NAME_SCAN_MODE );
+ const QString kk = mode.get();
+ kdDebug(29000) << "Mode is <" << kk << ">" << endl;
+ storeOptions->backupOption( mode );
+ /* apply if it has a widget, or apply always ? */
+ if( mode.widget() ) apply( &mode );
+ }
+
+ /** Scan Resolution should always exist. **/
+ KScanOption res ( SANE_NAME_SCAN_RESOLUTION );
+ const QString p = res.get();
+
+ kdDebug(29000) << "Scan Resolution pre Preview is " << p << endl;
+ storeOptions->backupOption( res );
+
+ int set_dpi = dpi;
+
+ if( dpi == 0 )
+ {
+ /* No resolution argument */
+ if( ! res.getRange( &min, &max, &q ) )
+ {
+ if( ! res.getRangeFromList ( &min, &max, &q ) )
+ {
+ kdDebug(29000) << "Could not retrieve resolution range!" << endl;
+ min = 75.0; // Hope that every scanner can 75
+ }
+ }
+ kdDebug(29000) << "Minimum Range: " << min << ", Maximum Range: " << max << endl;
+
+ if( min > MIN_PREVIEW_DPI )
+ set_dpi = (int) min;
+ else
+ set_dpi = MIN_PREVIEW_DPI;
+ }
+
+ /* Set scan resolution for preview. */
+ if( !optionExists( SANE_NAME_SCAN_Y_RESOLUTION ) )
+ d->currScanResolutionY = 0;
+ else
+ {
+ KScanOption yres ( SANE_NAME_SCAN_Y_RESOLUTION );
+ /* if active ? */
+ storeOptions->backupOption( yres );
+ yres.set( set_dpi );
+ apply( &yres );
+ yres.get( &d->currScanResolutionY );
+
+ /* Resolution bind switch ? */
+ if( optionExists( SANE_NAME_RESOLUTION_BIND ) )
+ {
+ KScanOption bind_so( SANE_NAME_RESOLUTION_BIND );
+ /* Switch binding on if available */
+ storeOptions->backupOption( bind_so );
+ bind_so.set( true );
+ apply( &bind_so );
+ }
+ }
+
+ res.set( set_dpi );
+ apply( &res );
+
+ /* Store the resulting preview for additional image information */
+ res.get( &d->currScanResolutionX );
+
+ if ( d->currScanResolutionY == 0 )
+ d->currScanResolutionY = d->currScanResolutionX;
+
+ /* Start scanning */
+ KScanStat stat = acquire_data( true );
+
+ /* Restauration of the previous values must take place in the scanfinished slot,
+ * because scanning works asynchron now.
+ */
+
+ return( stat );
+}
+
+
+
+/**
+ * prepareScan tries to set as much as parameters as possible.
+ *
+ **/
+#define NOTIFIER(X) optionNotifyString(X)
+
+QString KScanDevice::optionNotifyString( int i ) const
+{
+ const QString sOff = " |";
+ const QString sOn = " X |";
+ if( i > 0 )
+ {
+ return sOn;
+ }
+ return sOff;
+}
+
+
+void KScanDevice::prepareScan( void )
+{
+ QAsciiDictIterator<int> it( *option_dic ); // iterator for dict
+
+ kdDebug(29000) << "########################################################################################################" << endl;
+ kdDebug(29000) << "Scanner: " << scanner_name << endl;
+ kdDebug(29000) << " " << getScannerName() << endl;
+ kdDebug(29000) << "----------------------------------+--------+--------+--------+--------+--------+--------+--------+" << endl;
+ kdDebug(29000) << " Option-Name |SOFT_SEL|HARD_SEL|SOFT_DET|EMULATED|AUTOMATI|INACTIVE|ADVANCED|" << endl;
+ kdDebug(29000) << "----------------------------------+--------+--------+--------+--------+--------+--------+--------+" << endl;
+
+ while ( it.current() )
+ {
+ // qDebug( "%s -> %d", it.currentKey().latin1(), *it.current() );
+ int descriptor = *it.current();
+
+ const SANE_Option_Descriptor *d = sane_get_option_descriptor( scanner_handle, descriptor );
+
+ if( d )
+ {
+ int cap = d->cap;
+
+ QString s = QString(it.currentKey()).leftJustify(32, ' ');
+ kdDebug(29000) << " " << s << " |" <<
+ NOTIFIER( ((cap) & SANE_CAP_SOFT_SELECT)) <<
+ NOTIFIER( ((cap) & SANE_CAP_HARD_SELECT)) <<
+ NOTIFIER( ((cap) & SANE_CAP_SOFT_DETECT)) <<
+ NOTIFIER( ((cap) & SANE_CAP_EMULATED) ) <<
+ NOTIFIER( ((cap) & SANE_CAP_AUTOMATIC) ) <<
+ NOTIFIER( ((cap) & SANE_CAP_INACTIVE) ) <<
+ NOTIFIER( ((cap) & SANE_CAP_ADVANCED ) ) << endl;
+
+ }
+ ++it;
+ }
+ kdDebug(29000) << "----------------------------------+--------+--------+--------+--------+--------+--------+--------+" << endl;
+
+ KScanOption pso( SANE_NAME_PREVIEW );
+ const QString q = pso.get();
+
+ kdDebug(29000) << "Preview-Switch is at the moment: " << q << endl;
+
+
+}
+
+/** Starts scanning
+ * depending on if a filename is given or not, the function tries to open
+ * the file using the Qt-Image-IO or really scans the image.
+ **/
+KScanStat KScanDevice::acquire( const QString& filename )
+{
+ if( ! scanner_handle )
+ return KSCAN_ERR_NO_DEVICE;
+
+ KScanOption *so = 0;
+
+ if( filename.isEmpty() )
+ {
+ /* *real* scanning - apply all Options and go for it */
+ prepareScan();
+
+ for( so = gui_elements.first(); so; so = gui_elements.next() )
+ {
+ if( so->active() )
+ {
+ kdDebug(29000) << "apply <" << so->getName() << ">" << endl;
+ apply( so );
+ }
+ else
+ {
+ kdDebug(29000) << "Option <" << so->getName() << "> is not active !" << endl;
+ }
+ }
+
+ /** Scan Resolution should always exist. **/
+ KScanOption res( SANE_NAME_SCAN_RESOLUTION );
+ res.get( &d->currScanResolutionX );
+ if ( !optionExists( SANE_NAME_SCAN_Y_RESOLUTION ) )
+ d->currScanResolutionY = d->currScanResolutionX;
+ else
+ {
+ KScanOption yres( SANE_NAME_SCAN_Y_RESOLUTION );
+ yres.get( &d->currScanResolutionY );
+ }
+
+ return( acquire_data( false ));
+ }
+ else
+ {
+ /* a filename is in the parameter */
+ QFileInfo file( filename );
+ if( file.exists() )
+ {
+ QImage i;
+ ImgScanInfo info;
+ if( i.load( filename ))
+ {
+ info.setXResolution(i.dotsPerMeterX()); // TODO: *2.54/100
+ info.setYResolution(i.dotsPerMeterY()); // TODO: *2.54/100
+ info.setScannerName(filename);
+ emit( sigNewImage( &i, &info ));
+ }
+ }
+ }
+
+ return KSCAN_OK;
+}
+
+
+/**
+ * Creates a new QImage from the retrieved Image Options
+ **/
+KScanStat KScanDevice::createNewImage( SANE_Parameters *p )
+{
+ if( !p ) return( KSCAN_ERR_PARAM );
+ KScanStat stat = KSCAN_OK;
+
+ if( img ) {
+ delete( img );
+ img = 0;
+ }
+
+ if( p->depth == 1 ) // Lineart !!
+ {
+ img = new QImage( p->pixels_per_line, p->lines, 8 );
+ if( img )
+ {
+ img->setNumColors( 2 );
+ img->setColor( 0, qRgb( 0,0,0));
+ img->setColor( 1, qRgb( 255,255,255) );
+ }
+ }
+ else if( p->depth == 8 )
+ {
+ // 8 bit rgb-Picture
+ if( p->format == SANE_FRAME_GRAY )
+ {
+ /* Grayscale */
+ img = new QImage( p->pixels_per_line, p->lines, 8 );
+ if( img )
+ {
+ img->setNumColors( 256 );
+
+ for(int i = 0; i<256; i++)
+ img->setColor(i, qRgb(i,i,i));
+ }
+ }
+ else
+ {
+ /* true color image */
+ img = new QImage( p->pixels_per_line, p->lines, 32 );
+ if( img )
+ img->setAlphaBuffer( false );
+ }
+ }
+ else
+ {
+ /* ERROR: NO OTHER DEPTHS supported */
+ kdDebug(29000) << "KScan supports only bit dephts 1 and 8 yet!" << endl;
+ }
+
+ if( ! img ) stat = KSCAN_ERR_MEMORY;
+ return( stat );
+}
+
+
+KScanStat KScanDevice::acquire_data( bool isPreview )
+{
+ SANE_Status sane_stat = SANE_STATUS_GOOD;
+ KScanStat stat = KSCAN_OK;
+
+ scanningPreview = isPreview;
+
+ emit sigScanStart();
+
+ sane_stat = sane_start( scanner_handle );
+ if( sane_stat == SANE_STATUS_GOOD )
+ {
+ sane_stat = sane_get_parameters( scanner_handle, &sane_scan_param );
+
+ if( sane_stat == SANE_STATUS_GOOD )
+ {
+ kdDebug(29000) << "--Pre-Loop" << endl;
+ kdDebug(29000) << "format : " << sane_scan_param.format << endl;
+ kdDebug(29000) << "last_frame : " << sane_scan_param.last_frame << endl;
+ kdDebug(29000) << "lines : " << sane_scan_param.lines << endl;
+ kdDebug(29000) << "depth : " << sane_scan_param.depth << endl;
+ kdDebug(29000) << "pixels_per_line : " << sane_scan_param.pixels_per_line << endl;
+ kdDebug(29000) << "bytes_per_line : " << sane_scan_param.bytes_per_line << endl;
+ }
+ else
+ {
+ stat = KSCAN_ERR_OPEN_DEV;
+ kdDebug(29000) << "sane-get-parameters-Error: " << sane_strstatus( sane_stat ) << endl;
+ }
+ }
+ else
+ {
+ stat = KSCAN_ERR_OPEN_DEV;
+ kdDebug(29000) << "sane-start-Error: " << sane_strstatus( sane_stat ) << endl;
+ }
+
+
+ if( sane_scan_param.pixels_per_line == 0 || sane_scan_param.lines < 1 )
+ {
+ kdDebug(29000) << "ERROR: Acquiring empty picture !" << endl;
+ stat = KSCAN_ERR_EMPTY_PIC;
+ }
+
+ /* Create new Image from SANE-Parameters */
+ if( stat == KSCAN_OK )
+ {
+ stat = createNewImage( &sane_scan_param );
+ }
+
+ if( stat == KSCAN_OK )
+ {
+ /* new buffer for scanning one line */
+ if(data) delete [] data;
+ data = new SANE_Byte[ sane_scan_param.bytes_per_line +4 ];
+ if( ! data ) stat = KSCAN_ERR_MEMORY;
+ }
+
+ /* Signal for a progress dialog */
+ emit( sigScanProgress( 0 ) );
+ emit( sigAcquireStart() );
+
+ if( stat == KSCAN_OK )
+ {
+ /* initiates Redraw of the Progress-Window */
+ qApp->processEvents();
+ }
+
+ if( stat == KSCAN_OK )
+ {
+ overall_bytes = 0;
+ scanStatus = SSTAT_IN_PROGRESS;
+ pixel_x = 0;
+ pixel_y = 0;
+ overall_bytes = 0;
+ rest_bytes = 0;
+
+ /* internal status to indicate Scanning in progress
+ * this status might be changed by pressing Stop on a GUI-Dialog displayed during scan */
+ if( sane_set_io_mode( scanner_handle, SANE_TRUE ) == SANE_STATUS_GOOD )
+ {
+
+ int fd = 0;
+ if( sane_get_select_fd( scanner_handle, &fd ) == SANE_STATUS_GOOD )
+ {
+ sn = new QSocketNotifier( fd, QSocketNotifier::Read, this );
+ QObject::connect( sn, SIGNAL(activated(int)),
+ this, SLOT( doProcessABlock() ) );
+
+ }
+ }
+ else
+ {
+ do
+ {
+ doProcessABlock();
+ if( scanStatus != SSTAT_SILENT )
+ {
+ sane_stat = sane_get_parameters( scanner_handle, &sane_scan_param );
+ kdDebug(29000) << "--ProcessABlock-Loop" << endl;
+ kdDebug(29000) << "format : " << sane_scan_param.format << endl;
+ kdDebug(29000) << "last_frame : " << sane_scan_param.last_frame << endl;
+ kdDebug(29000) << "lines : " << sane_scan_param.lines << endl;
+ kdDebug(29000) << "depth : " << sane_scan_param.depth << endl;
+ kdDebug(29000) << "pixels_per_line : " << sane_scan_param.pixels_per_line << endl;
+ kdDebug(29000) << "bytes_per_line : " << sane_scan_param.bytes_per_line << endl;
+ }
+ } while ( scanStatus != SSTAT_SILENT );
+ }
+ }
+
+ if( stat != KSCAN_OK )
+ {
+ /* Scanning was disturbed in any way - end it */
+ kdDebug(29000) << "Scanning was disturbed - clean up" << endl;
+ emit( sigScanFinished( stat ));
+ }
+ return( stat );
+}
+
+void KScanDevice::loadOptionSet( KScanOptSet *optSet )
+{
+ if( !optSet )
+ {
+ return;
+ }
+
+ // kdDebug(29000) << "Loading Option set: " << optSet->optSetName() << endl;
+ QAsciiDictIterator<KScanOption> it(*optSet);
+
+ kdDebug(29000) << "Postinstalling " << optSet->count() << " options" << endl;
+ while( it.current() )
+ {
+ KScanOption *so = it.current();
+ if( ! so->initialised() )
+ kdDebug(29000) << so->getName() << " is not initialised" << endl;
+
+ if( ! so->active() )
+ kdDebug(29000) << so->getName() << " is not active" << endl;
+
+ if( so && so->active() && so->initialised())
+ {
+ const QString qq = so->get();
+
+ kdDebug(29000) << "Post-Scan-apply <" << it.currentKey() << ">: " << qq << endl;
+ apply( so );
+ }
+ ++it;
+ }
+
+}
+
+
+void KScanDevice::slScanFinished( KScanStat status )
+{
+ // clean up
+ if( sn ) {
+ sn->setEnabled( false );
+ delete sn;
+ sn = 0;
+ }
+
+ emit( sigScanProgress( MAX_PROGRESS ));
+
+ kdDebug(29000) << "Slot ScanFinished hit with status " << status << endl;
+
+ if( data )
+ {
+ delete[] data;
+ data = 0;
+ }
+
+ if( status == KSCAN_OK && img )
+ {
+ ImgScanInfo info;
+ info.setXResolution(d->currScanResolutionX);
+ info.setYResolution(d->currScanResolutionY);
+ info.setScannerName(shortScannerName());
+
+ // put the resolution also into the image itself
+ img->setDotsPerMeterX(static_cast<int>(d->currScanResolutionX / 0.0254 + 0.5));
+ img->setDotsPerMeterY(static_cast<int>(d->currScanResolutionY / 0.0254 + 0.5));
+ kdDebug(29000) << "resolutionX:" << d->currScanResolutionX << " resolutionY:" << d->currScanResolutionY << endl;
+
+ if( scanningPreview )
+ {
+ kdDebug(29000) << "Scanning a preview !" << endl;
+ savePreviewImage(*img);
+ emit( sigNewPreview( img, &info ));
+
+ /* The old settings need to be redefined */
+ loadOptionSet( storeOptions );
+ }
+ else
+ {
+ emit( sigNewImage( img, &info ));
+ }
+ }
+
+
+ sane_cancel(scanner_handle);
+
+ /* This follows after sending the signal */
+ if( img )
+ {
+ delete img;
+ img = 0;
+ }
+
+ /* delete the socket notifier */
+ if( sn ) {
+ delete( sn );
+ sn = 0;
+ }
+
+}
+
+
+/* This function calls at least sane_read and converts the read data from the scanner
+ * to the qimage.
+ * The function needs:
+ * QImage img valid
+ * the data-buffer set to a appropriate size
+ **/
+
+void KScanDevice::doProcessABlock( void )
+{
+ int val,i;
+ QRgb col, newCol;
+
+ SANE_Byte *rptr = 0;
+ SANE_Int bytes_written = 0;
+ int chan = 0;
+ SANE_Status sane_stat = SANE_STATUS_GOOD;
+ uchar eight_pix = 0;
+ bool goOn = true;
+
+ // int rest_bytes = 0;
+ while( goOn && data )
+ {
+ sane_stat =
+ sane_read( scanner_handle, data + rest_bytes, sane_scan_param.bytes_per_line, &bytes_written);
+ int red = 0;
+ int green = 0;
+ int blue = 0;
+
+ if( sane_stat != SANE_STATUS_GOOD )
+ {
+ /** any other error **/
+ kdDebug(29000) << "sane_read returned with error <" << sane_strstatus( sane_stat ) << ">: " << bytes_written << " bytes left" << endl;
+ goOn = false;
+ }
+
+ if( goOn && bytes_written < 1 )
+ {
+ // qDebug( "No bytes written -> leaving out !" );
+ goOn = false; /** No more data -> leave ! **/
+ }
+
+ if( goOn )
+ {
+ overall_bytes += bytes_written;
+ // qDebug( "Bytes read: %d, bytes written: %d", bytes_written, rest_bytes );
+
+ rptr = data; // + rest_bytes;
+
+ switch( sane_scan_param.format )
+ {
+ case SANE_FRAME_RGB:
+ if( sane_scan_param.lines < 1 ) break;
+ bytes_written += rest_bytes; // die bergebliebenen Bytes dazu
+ rest_bytes = bytes_written % 3;
+
+ for( val = 0; val < ((bytes_written-rest_bytes) / 3); val++ )
+ {
+ red = *rptr++;
+ green = *rptr++;
+ blue = *rptr++;
+
+ // kdDebug(29000) << "RGB: %d, %d, %d\n", red, green, blue" << endl;
+ if( pixel_x == sane_scan_param.pixels_per_line )
+ { pixel_x = 0; pixel_y++; }
+ if( pixel_y < img->height())
+ img->setPixel( pixel_x, pixel_y, qRgb( red, green,blue ));
+
+ pixel_x++;
+ }
+ /* copy the remaining bytes to the beginning of the block :-/ */
+ for( val = 0; val < rest_bytes; val++ )
+ {
+ *(data+val) = *rptr++;
+ }
+
+ break;
+ case SANE_FRAME_GRAY:
+ for( val = 0; val < bytes_written ; val++ )
+ {
+ if( pixel_y >= sane_scan_param.lines ) break;
+ if( sane_scan_param.depth == 8 )
+ {
+ if( pixel_x == sane_scan_param.pixels_per_line ) { pixel_x = 0; pixel_y++; }
+ img->setPixel( pixel_x, pixel_y, *rptr++ );
+ pixel_x++;
+ }
+ else
+ { // Lineart
+ /* Lineart needs to be converted to byte */
+ eight_pix = *rptr++;
+ for( i = 0; i < 8; i++ )
+ {
+ if( pixel_y < sane_scan_param.lines )
+ {
+ chan = (eight_pix & 0x80)> 0 ? 0:1;
+ eight_pix = eight_pix << 1;
+ //qDebug( "Setting on %d, %d: %d", pixel_x, pixel_y, chan );
+ img->setPixel( pixel_x, pixel_y, chan );
+ pixel_x++;
+ if( pixel_x >= sane_scan_param.pixels_per_line )
+ {
+ pixel_x = 0; pixel_y++;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ break;
+ case SANE_FRAME_RED:
+ case SANE_FRAME_GREEN:
+ case SANE_FRAME_BLUE:
+ kdDebug(29000) << "Scanning Single color Frame: " << bytes_written << " Bytes!" << endl;
+ for( val = 0; val < bytes_written ; val++ )
+ {
+ if( pixel_x >= sane_scan_param.pixels_per_line )
+ {
+ pixel_y++; pixel_x = 0;
+ }
+
+ if( pixel_y < sane_scan_param.lines )
+ {
+
+ col = img->pixel( pixel_x, pixel_y );
+
+ red = qRed( col );
+ green = qGreen( col );
+ blue = qBlue( col );
+ chan = *rptr++;
+
+ switch( sane_scan_param.format )
+ {
+ case SANE_FRAME_RED :
+ newCol = qRgba( chan, green, blue, 0xFF );
+ break;
+ case SANE_FRAME_GREEN :
+ newCol = qRgba( red, chan, blue, 0xFF );
+ break;
+ case SANE_FRAME_BLUE :
+ newCol = qRgba( red , green, chan, 0xFF );
+ break;
+ default:
+ kdDebug(29000) << "Undefined format !" << endl;
+ newCol = qRgba( 0xFF, 0xFF, 0xFF, 0xFF );
+ break;
+ }
+ img->setPixel( pixel_x, pixel_y, newCol );
+ pixel_x++;
+ }
+ }
+ break;
+ default:
+ kdDebug(29000) << "Unexpected ERROR: No Format type" << endl;
+ break;
+ } /* switch */
+
+
+ if( (sane_scan_param.lines > 0) && (sane_scan_param.lines * pixel_y> 0) )
+ {
+ int progress = (int)(((double)MAX_PROGRESS) / sane_scan_param.lines *
+ pixel_y);
+ if( progress < MAX_PROGRESS)
+ emit( sigScanProgress( progress));
+ }
+
+ if( bytes_written == 0 || sane_stat == SANE_STATUS_EOF )
+ {
+ kdDebug(29000) << "Down under sane_stat not OK" << endl;
+ goOn = false;
+ }
+ }
+
+ if( goOn && scanStatus == SSTAT_STOP_NOW )
+ {
+ /* scanStatus is set to SSTAT_STOP_NOW due to hitting slStopScanning */
+ /* Mostly that one is fired by the STOP-Button in the progress dialog. */
+
+ /* This is also hit after the normal finish of the scan. Most probably,
+ * the QSocketnotifier fires for a few times after the scan has been
+ * cancelled. Does it matter ? To see it, just uncomment the qDebug msg.
+ */
+ kdDebug(29000) << "Stopping the scan progress !" << endl;
+ goOn = false;
+ scanStatus = SSTAT_SILENT;
+ emit( sigScanFinished( KSCAN_OK ));
+ }
+
+ } /* while( 1 ) */
+
+
+ /** Comes here if scanning is finished or has an error **/
+ if( sane_stat == SANE_STATUS_EOF)
+ {
+ if ( sane_scan_param.last_frame)
+ {
+ /** Everythings okay, the picture is ready **/
+ kdDebug(29000) << "last frame reached - scan successful" << endl;
+ scanStatus = SSTAT_SILENT;
+ emit( sigScanFinished( KSCAN_OK ));
+ }
+ else
+ {
+ /** EOF und nicht letzter Frame -> Parameter neu belegen und neu starten **/
+ scanStatus = SSTAT_NEXT_FRAME;
+ kdDebug(29000) << "EOF, but another frame to scan" << endl;
+
+ }
+ }
+
+ if( sane_stat == SANE_STATUS_CANCELLED )
+ {
+ scanStatus = SSTAT_STOP_NOW;
+ kdDebug(29000) << "Scan was cancelled" << endl;
+
+ // stat = KSCAN_CANCELLED;
+ // emit( sigScanFinished( stat ));
+
+ /* hmmm - how could this happen ? */
+ }
+} /* end of fkt */
+
+
+void KScanDevice::slSaveScanConfigSet( const QString& setName, const QString& descr )
+{
+ if( setName.isEmpty() || setName.isNull()) return;
+
+ kdDebug(29000) << "Saving Scan Configuration" << setName << endl;
+
+ KScanOptSet optSet( DEFAULT_OPTIONSET );
+ getCurrentOptions( &optSet );
+
+ optSet.saveConfig( scanner_name , setName, descr );
+
+}
+
+
+void KScanDevice::getCurrentOptions( KScanOptSet *optSet )
+{
+ if( ! optSet ) return;
+
+ for( KScanOption *so = gui_elements.first(); so; so = gui_elements.next())
+ {
+ kdDebug(29000) << "Storing <" << so->getName() << ">" << endl;
+ if( so && so->active())
+ {
+ apply(so);
+ optSet->backupOption( *so );
+ }
+
+ /* drop the thing from the dirty-list */
+ dirtyList.removeRef( so->getName());
+ }
+
+ QStrListIterator it( dirtyList );
+ while( it.current())
+ {
+ KScanOption so( it.current() );
+ optSet->backupOption( so );
+ ++it;
+ }
+}
+
+QString KScanDevice::getConfig( const QString& key, const QString& def ) const
+{
+ QString confFile = SCANNER_DB_FILE;
+
+ KSimpleConfig scanConfig( confFile, true );
+ scanConfig.setGroup( shortScannerName() );
+
+ return scanConfig.readEntry( key, def );
+}
+
+void KScanDevice::slStoreConfig( const QString& key, const QString& val )
+{
+ QString confFile = SCANNER_DB_FILE;
+ QString scannerName = shortScannerName();
+
+ if( scannerName.isEmpty() || scannerName == UNDEF_SCANNERNAME )
+ {
+ kdDebug(29000) << "Skipping config write, scanner name is empty!" << endl;
+ }
+ else
+ {
+ kdDebug(29000) << "Storing config " << key << " in Group " << scannerName << endl;
+
+ KSimpleConfig scanConfig( confFile );
+ scanConfig.setGroup( scannerName );
+ scanConfig.writeEntry( key, val );
+ scanConfig.sync();
+ }
+}
+
+
+bool KScanDevice::scanner_initialised = false;
+SANE_Handle KScanDevice::scanner_handle = 0L;
+SANE_Device const **KScanDevice::dev_list = 0L;
+QAsciiDict<int> *KScanDevice::option_dic = 0L;
+KScanOptSet *KScanDevice::gammaTables = 0L;
+
+
+#include "kscandevice.moc"
diff --git a/libkscan/kscandevice.h b/libkscan/kscandevice.h
new file mode 100644
index 00000000..dd849566
--- /dev/null
+++ b/libkscan/kscandevice.h
@@ -0,0 +1,459 @@
+/* This file is part of the KDE Project
+ Copyright (C) 1999 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KSCANDEV_H_
+#define _KSCANDEV_H_
+
+#include <qwidget.h>
+#include <qasciidict.h>
+#include <qsize.h>
+#include <qobject.h>
+#include <qstrlist.h>
+#include <qsocketnotifier.h>
+
+
+#include "kscanoption.h"
+#include "kscanoptset.h"
+
+#define DEFAULT_OPTIONSET "saveSet"
+#define SCANNER_DB_FILE "scannerrc"
+
+class ImgScanInfo;
+
+extern "C" {
+#include <sane/sane.h>
+#include <sane/saneopts.h>
+}
+
+/**
+ * This is KScanDevice, a class for accessing the SANE scanning functions under KDE
+ *
+ * @short KScanDevice
+ * @author Klaas Freitag
+ * @version 0.1alpha
+ *
+ */
+
+typedef enum {
+ SSTAT_SILENT, SSTAT_IN_PROGRESS, SSTAT_NEXT_FRAME, SSTAT_STOP_NOW, STTAT_STOP_ADF_FINISHED
+} SCANSTATUS;
+
+
+/**
+ * KScanStat
+ * shows the status of a KScan operation
+ **/
+
+
+class KScanDevice : public QObject
+{
+ Q_OBJECT
+
+ /* Hmmm - No Q_PROPS ? */
+public:
+ /**
+ * KScanDevice - the KDE Scanner Device
+ * constructor. Does not much.
+ *
+ * @see openDevice
+ *
+ */
+
+ KScanDevice( QObject *parent = 0 );
+
+ /**
+ * Destructor
+ *
+ * releases internal allocated memory.
+ */
+ ~KScanDevice( );
+
+ /**
+ * opens the device named backend.
+ * @return the state of the operation
+ * @param backend: the name of the backend to open
+ */
+ KScanStat openDevice( const QCString& backend );
+
+ /**
+ * returns the names of all existing Scan Devices in the system.
+ * @param enable_net: allow net devices.
+ * @return a QStrList of available Scanners in the system
+ * @see KScanDevice
+ */
+ QStrList getDevices( ) const
+ { return( scanner_avail ); }
+
+ /**
+ * returns the short, technical name of the currently attached backend.
+ * It is in the form 'umax:/dev/sg1'.
+ */
+ QCString shortScannerName() const { return scanner_name; }
+
+ /**
+ * returns a long, human readable name of the scanner, like
+ * 'Mustek SP1200 Flatbed scanner'. The parameter name takes
+ * the name of a backend, what means something like "/dev/scanner".
+ * If the name of the backend is skipped, the selected backend is
+ * returned.
+ *
+ * @param a QString with a backend string
+ * @return a QString containing a human readable scanner name
+ **/
+ QString getScannerName( const QCString& name = 0 ) const;
+
+ /*
+ * ========= Preview Functions ==========
+ */
+
+ /**
+ * QImage * acquirePreview( bool forceGray = 0, int dpi = 0 )
+ *
+ * acquires a preview on the selected device. KScanDevice allocs
+ * memory for the qimage returned. This qimage remains valid
+ * until the next call to acquirePreview or until KScanDevice is
+ * destructed.
+ *
+ * @return a pointer to a qimage or null on error
+ * @param bool forceGray if true, acquire a preview in gray
+
+ * @param int dpi dpi setting. If 0, the dpi setting is
+ * elected by the object, e.g. is the smallest possible
+ * resolution.
+
+ */
+ KScanStat acquirePreview( bool forceGray = 0, int dpi = 0 );
+
+ /** acquires a qimage on the given settings.
+ * the Parameter image needs to point to a object qimage,
+ * which is filled by the SANE-Dev. After the function returns,
+ * the qimage is valid, if the returnvalue is OK.
+ * @param QImage *image - Pointer to a reserved image
+ * @return the state of the operation in KScanStat
+ */
+ KScanStat acquire( const QString& filename = QString::null );
+
+ /**
+ * returns the default filename of the preview image of this scanner.
+ * @return default filename
+ **/
+ const QString previewFile();
+
+ /**
+ * loads the last saved previewed image on this device from the default file
+ * @return a bitmap as QImage
+ **/
+ QImage loadPreviewImage();
+
+ /**
+ * saves current previewed image from this device to the default file
+ * @param image current preview image which should be saved
+ * @return true if the saving was sucessful
+ **/
+ bool savePreviewImage( const QImage& image );
+
+
+ /*
+ * ========= List Functions ==========
+ */
+
+ /**
+ * returns all existing options of the selected device.
+ * @see openDevice
+ * @return a QStrList with the names of all options
+ **/
+ QStrList getAllOptions();
+
+ /**
+ * returns the common options of the device. A frontend should
+ * display the returned options in a convinient way and easy to
+ * use.
+ * @see getAllOptions
+ * @see getAdvancedOptions
+ * @return a QStrList with with names of the common options.
+ */
+ QStrList getCommonOptions();
+
+ /**
+ * returns a list of advanced scan options. A frontend should
+ * display these options in a special dialog.
+ * @see getAllOptions
+ * @see getCommonOptions
+ * @return a QStrList with names of advanced scan options.
+ */
+ QStrList getAdvancedOptions();
+
+ /**
+ * retrieves a set of the current scan options and writes them
+ * to the object pointed to by parameter optSet
+ * @see KScanOptSet
+ * @param optSet, a pointer to the option set object
+ */
+ void getCurrentOptions( KScanOptSet *optSet );
+
+ /**
+ * load scanner parameter sets. All options stored in @param optSet
+ * are loaded into the scan device.
+ */
+ void loadOptionSet( KScanOptSet *optSet );
+
+ /**
+ * applys the values in an scan-option object. The value to
+ * set must be set in the KScanOption object prior. However,
+ * it takes effect after being applied with this function.
+ * @see KScanOption
+ * @return the status of the operation
+ * @param a scan-option object with the scanner option to set and
+ * an optional boolean parameter if it is a gamma table.
+ **/
+
+ KScanStat apply( KScanOption *opt, bool=false );
+
+ /**
+ * returns true if the option exists in that device.
+ * @param name: the name of a option from a returned option-List
+ * @return true, if the option exists
+ */
+ bool optionExists( const QCString& name );
+
+ /**
+ * checks if the backend knows the option with the required name under
+ * a different name, like some backends do. If it does, the known name
+ * is returned, otherwise a null QCString.
+ */
+
+ QCString aliasName( const QCString& name );
+
+ /**
+ * returns a Widget suitable for the selected Option and creates the
+ * KScanOption. It is internally connected to the scan device, every
+ * change to the widget is automaticly considered by the scan device.
+ * @param name: Name of the SANE Option
+ * @param parent: pointer to the parent widget
+ * @param desc: pointer to the text appearing as widget text
+ * @param tooltip: tooltip text. If zero, the SANE text will be used.
+ **/
+ KScanOption *getGuiElement( const QCString& name, QWidget *parent,
+ const QString& desc = QString::null,
+ const QString& tooltip = QString::null );
+
+ /**
+ * returns the pointer to an already created Scanoption from the
+ * gui element list. Cares for option name aliases.
+ */
+ KScanOption *getExistingGuiElement( const QCString& name );
+
+ /**
+ * sets an widget of the named option enabled/disabled
+ **/
+ void guiSetEnabled( const QCString& name, bool state );
+
+ /**
+ * returns the maximum scan size. This is interesting e.g. for the
+ * preview widget etc.
+ * The unit of the return value is millimeter, if the sane backend
+ * returns millimeter. (TODO)
+ **/
+ QSize getMaxScanSize( void ) const;
+
+ /**
+ * returns the information bit stored for the currently attached scanner
+ * identified by the key.
+ */
+ QString getConfig( const QString& key, const QString& def = QString() ) const;
+
+ static bool scanner_initialised;
+ static SANE_Handle scanner_handle;
+ static QAsciiDict<int>* option_dic;
+ static SANE_Device const **dev_list;
+ static KScanOptSet *gammaTables;
+
+public slots:
+ void slOptChanged( KScanOption* );
+
+ /**
+ * The setting of some options require a complete reload of all
+ * options, because they might have changed. In that case, slot
+ * slReloadAll() is called.
+ **/
+ void slReloadAll( );
+
+ /**
+ * This slot does the same as ReloadAll, but it does not reload
+ * the scanner option given as parameter. This is useful to make
+ * sure that no recursion takes places during reload of options.
+ **/
+ void slReloadAllBut( KScanOption*);
+
+ /**
+ * Notifies the scan device to stop the current scanning.
+ * This slot only makes sense, if a scan is in progress.
+ * Note that if the slot is called, it can take a few moments
+ * to stop the scanning
+ */
+ void slStopScanning( void );
+
+ /**
+ * Image ready-slot in asynchronous scanning
+ */
+ void slScanFinished( KScanStat );
+
+ /**
+ * Save the current configuration parameter set. Only changed options are saved.
+ **/
+ void slSaveScanConfigSet( const QString&, const QString& );
+
+
+ void slSetDirty( const QCString& name );
+
+ /**
+ * Closes the scan device and frees all related data, makes
+ * the system ready to open a new, other scanner.
+ */
+ void slCloseDevice( );
+
+ /**
+ * stores the info bit in a config file for the currently connected
+ * scanner. For this, the config file $KDEHOME/.kde/share/config/scannerrc
+ * is opened, a group is created that identifies the scanner and the
+ * device where it is connected. The information is stored into that group.
+ */
+ void slStoreConfig( const QString&, const QString& );
+
+signals:
+ /**
+ * emitted, if an option change was applied, which made other
+ * options changed. The application may connect a slot to this
+ * signal to see, if other options became active/inactive.
+ **/
+ void sigOptionsChanged();
+
+ /**
+ * emitted, if an option change was applied, which made the
+ * scan parameters change. The parameters need to be reread
+ * by sane_get_parameters().
+ **/
+ void sigScanParamsChanged();
+
+ /**
+ * emitted if a new image was acquired. The image has to be
+ * copied in the signal handler.
+ */
+ void sigNewImage( QImage*, ImgScanInfo* );
+
+ /**
+ * emitted if a new preview was acquired. The image has to be
+ * copied in the signal handler.
+ */
+ void sigNewPreview( QImage*, ImgScanInfo* );
+
+ /**
+ * emitted to tell the application the start of scanning. That is
+ * before the enquiry of the scanner starts. Between this signal
+ * and @see sigScanProgress(0) can be some time consumed by a scanner
+ * warming up etc.
+ */
+ void sigScanStart();
+
+ /**
+ * signal to indicate the start of acquireing data. It is equal
+ * to @see sigScanProgress emitted with value 0 and thus it is sent
+ * after sigScanStart.
+ * The time between sigScanStart and sigAcquireStart differs very much
+ * from scanner to scanner.
+ */
+ void sigAcquireStart();
+
+ /**
+ * emitted to tell the application the progress of the scanning
+ * of one page. The final value is always 1000. The signal is
+ * emitted for zero to give the change to initialize the progress
+ * dialog.
+ **/
+ void sigScanProgress( int );
+
+ /**
+ * emitted to show that a scan finished and provides a status how
+ * the scan finished.
+ */
+ void sigScanFinished( KScanStat );
+
+
+ /**
+ * emitted to give all objects using this device to free all dependencies
+ * on the scan device, because this signal means, that the scan device is
+ * going to be closed. The can not be stopped. All receiving objects have
+ * to free their stuff using the device and pray. While handling the signal,
+ * the device is still open and valid.
+ */
+ void sigCloseDevice( );
+
+private slots:
+ /**
+ * Slot to acquire a whole image */
+ void doProcessABlock( void );
+
+
+private:
+ /**
+ * Function which applies all Options which need to be applied.
+ * See SANE-Documentation Table 4.5, description for SANE_CAP_SOFT_DETECT.
+ * The function sets the options which have SANE_CAP_AUTOMATIC set,
+ * to autmatic adjust.
+ **/
+ void prepareScan( void );
+
+ KScanStat createNewImage( SANE_Parameters *p );
+
+// not implemented
+// QWidget *entryField( QWidget *parent, const QString& text,
+// const QString& tooltip );
+ KScanStat find_options(); // help fct. to process options
+ KScanStat acquire_data( bool isPreview = false );
+ QStrList scanner_avail; // list of names of all scan dev.
+ QStrList option_list; // list of names of all options
+ QStrList dirtyList; // option changes
+
+ inline QString optionNotifyString(int) const;
+
+ QPtrList<KScanOption> gui_elements;
+ QAsciiDict<SANE_Device> scannerDevices;
+
+ QSocketNotifier *sn;
+
+ SCANSTATUS scanStatus;
+
+ /* Data for the scan process */
+ /* This could/should go to a small help object */
+ QCString scanner_name;
+ SANE_Byte *data;
+ QImage *img;
+ SANE_Parameters sane_scan_param;
+ long overall_bytes;
+ int rest_bytes;
+ int pixel_x, pixel_y;
+ bool scanningPreview;
+
+ KScanOptSet *storeOptions;
+
+ class KScanDevicePrivate;
+ KScanDevicePrivate *d;
+};
+
+#endif
diff --git a/libkscan/kscandoc.h b/libkscan/kscandoc.h
new file mode 100644
index 00000000..14f1f2c8
--- /dev/null
+++ b/libkscan/kscandoc.h
@@ -0,0 +1,116 @@
+/* This file is part of the KDE Project
+ Copyright (C) 2002 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+/**
+\mainpage The KScan Library.
+
+ The KScan Library provides an interface for the SANE-lib (see http://www.sane-project.org for more information) for KDE2 applications.
+
+\section intro Introduction
+
+The KScan Library furnishes each KDE2 application with an object which can connect to a scanner set up by SANE, as well as read out and manage the scanner's parameters. The difficulty with this is that SANE scanners do not have a uniform set of options. The scanners support various scan options. An interface for establishing contact to the scanners has to be set up dynamically after the decision is made as to which available device in the system should be used (dynamic GUI).
+
+\section usage How to use libkscan
+
+Libkscan provides a dialog for you to include scan functionality to your application. This includes on the main page of the dialog
+ - The scanner setting parts with dynamically generated controls of scan parameters and the buttons to start scanning
+ - A preview window to select the scan area
+ - An option tab to edit basically scan options.
+The scan dialog works completely as KPart and allows the user to scan a preview, select the interesting part on the preview scan, and than start the final scan. Your application will be notified by a signal finalImage that informs you that a new image is available from the scanner.
+
+
+
+
+
+\section objectOverview Abstract KScan Objects
+
+The KScan Library defines the following classes which are responsible for managing the scanner's parameters:
+
+- KGammaTable\n
+This is a base class which implements a gamma table and carries out the calculations etc. internally.
+
+- KScanOption\n
+The object KScanOption implements exactly one scanning option, such as the scanning resolution. A scanner supports several options which are, in part, independent of one another. This means that if option A is modified, option B could be modified along with it. The KScanLib supports the handling of these dependencies.
+
+- KScanDevice\n
+The object KScanDevice maps the scanners available in the system. This object assists the detection of reachable devices and the options they support.
+\n
+Once a device is decided upon and this has been opened, the KScanDevice will represent the scanning device. By way of this class, the hardware will actually utilize the options (KScanOption). Furthermore, scanned image data is supplied by KScanDevice.
+
+- KScanOptSet\n
+The object KScanOptSet represents a container for the KScanOption options, apart from a specific device. Up until now, this was made possible by saving several options during the course of the program, e.g. previously configured scanning parameters if a preview scan were to be carried out so that this can be restored following the preview scan.\n
+Furthermore, option sets can be saved to disk.
+
+\section helpers Helper Classes
+
+There are some helper widgets which simplify the dynamic setup of the scanning interface. These objects provide simple combinations of base widgets to make their usage easier.
+
+Itemized, these are:
+
+- KScanEntry\n(defined in kscanslider.h)\n
+Provides an entry field preceded by text.
+
+- KScanSlider \n(defined in kscanslider.h)\n
+Slider preceded by text. Range values are transferred with the data type double.
+
+- KScanCombo \n(defined in kscanslider.h)\n
+Combobox widget which precedes description text and can represent icons.
+
+- DispGamma \n(defined in dispgamma.h)\n
+Widget for displaying gamma tables.
+
+\section guiElements Interface Objects
+
+The KScan Library offers some ready-made objects which can be used as a sort of pre-fabricated dialog in order to integrate the scanning functionality into an application. This results in the availability of scanning functionality in all applications over the same interface.
+
+Currently, there are the following interface elements:
+
+- DeviceSelector\n
+is a class which represents a dialog for scanner selection.
+
+- GammaDialog\n
+is a dialog where a gamma table can be edited. To represent the gamma tables, the gamma dialog uses KGammaTable internally. This class is returned in such as way that it can set the relevant scanner options directly, once the dialog has been completed.
+
+- MassScanDialog\n
+is a mass scanning dialog which informs the user about how the scanning is progressing when the automatic document feeder is used. \e very \e beta \e !
+
+- ScanSourceDialog\n
+Small dialog which enables scanning source selection, e.g. Flatbed, automatic document feeder...
+
+- ScanParams\n
+The ScanParams class is the actual core of the
+ KScan Library in terms of interface layout. The ScanParams class provides a ready-to-use interface for the selected scanner.\n
+\n
+ The scanner device is analyzed in this class and dynamically generates an interface, according to the device's properties, containing the most important operational elements. These are currently
+
+ <ul>
+ <li> Setting options for scanning resolution
+ <li> Scanning source selection
+ <li> Scanning mode
+ <li> Brightness and contrast settings
+ <li> Gamma table
+ <li> Preview scanning
+ </ul>
+
+
+
+\author Klaas Freitag <freitag@suse.de>
+
+*/
+
diff --git a/libkscan/kscanoption.cpp b/libkscan/kscanoption.cpp
new file mode 100644
index 00000000..1aae1602
--- /dev/null
+++ b/libkscan/kscanoption.cpp
@@ -0,0 +1,1221 @@
+/* This file is part of the KDE Project
+ Copyright (C) 2000 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <stdlib.h>
+#include <qwidget.h>
+#include <qobject.h>
+#include <qasciidict.h>
+#include <qcombobox.h>
+#include <qslider.h>
+#include <qcheckbox.h>
+#include <qlineedit.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qtooltip.h>
+#include <qimage.h>
+#include <qregexp.h>
+
+#include <kdebug.h>
+
+#include <unistd.h>
+#include "kgammatable.h"
+#include "kscandevice.h"
+#include "kscanslider.h"
+#include "kscanoptset.h"
+
+
+// #define MIN_PREVIEW_DPI 20
+// this is nowhere used!? Additionally, it's defined to 75 in kscandevice.cpp
+
+/* switch to show some from time to time useful alloc-messages */
+#undef MEM_DEBUG
+
+#undef APPLY_IN_SITU
+
+
+
+/** inline-access to the option descriptor, object to changes with global vars. **/
+inline const SANE_Option_Descriptor *getOptionDesc( const QCString& name )
+{
+ int *idx = (*KScanDevice::option_dic)[ name ];
+
+ const SANE_Option_Descriptor *d = 0;
+ // debug( "<< for option %s >>", name );
+ if ( idx && *idx > 0 )
+ {
+ d = sane_get_option_descriptor( KScanDevice::scanner_handle, *idx );
+ // debug( "retrieving Option %s", d->name );
+ }
+ else
+ {
+ kdDebug(29000) << "no option descriptor for <" << name << ">" << endl;
+ // debug( "Name survived !" );
+ }
+ // debug( "<< leaving option %s >>", name );
+
+ return( d );
+}
+
+
+
+/* ************************************************************************ */
+/* KScan Option */
+/* ************************************************************************ */
+KScanOption::KScanOption( const QCString& new_name ) :
+ QObject()
+{
+ if( initOption( new_name ) )
+ {
+ int *num = (*KScanDevice::option_dic)[ getName() ];
+ if( !num || !buffer )
+ return;
+
+ SANE_Status sane_stat = sane_control_option( KScanDevice::scanner_handle, *num,
+ SANE_ACTION_GET_VALUE,
+ buffer, 0 );
+
+ if( sane_stat == SANE_STATUS_GOOD )
+ {
+ buffer_untouched = false;
+ }
+ }
+ else
+ {
+ kdDebug(29000) << "Had problems to create KScanOption - initOption failed !" << endl;
+ }
+}
+
+
+bool KScanOption::initOption( const QCString& new_name )
+{
+ desc = 0;
+ if( new_name.isEmpty() ) return( false );
+
+ name = new_name;
+ desc = getOptionDesc( name );
+ buffer = 0;
+ internal_widget = 0;
+ buffer_untouched = true;
+ buffer_size = 0;
+
+ if( desc )
+ {
+
+ /* Gamma-Table - initial values */
+ gamma = 0; /* marks as unvalid */
+ brightness = 0;
+ contrast = 0;
+ gamma = 100;
+
+ // allocate memory
+ switch( desc->type )
+ {
+ case SANE_TYPE_INT:
+ case SANE_TYPE_FIXED:
+ case SANE_TYPE_STRING:
+ buffer = allocBuffer( desc->size );
+ break;
+ case SANE_TYPE_BOOL:
+ buffer = allocBuffer( sizeof( SANE_Word ) );
+ break;
+ default:
+ buffer_size = 0;
+ buffer = 0;
+ }
+
+ KScanOption *gtOption = (*KScanDevice::gammaTables)[ new_name ];
+ if( gtOption )
+ {
+ kdDebug(29000) << "Is older GammaTable!" << endl;
+ KGammaTable gt;
+ gtOption->get( &gt );
+
+ gamma = gt.getGamma();
+ contrast = gt.getContrast();
+ brightness = gt.getBrightness();
+ }
+ else
+ {
+ // kdDebug(29000) << "Is NOT older GammaTable!" << endl;
+ }
+ }
+
+ return desc;
+}
+
+KScanOption::KScanOption( const KScanOption &so ) :
+ QObject()
+{
+ /* desc is stored by sane-lib and may be copied */
+ desc = so.desc;
+ name = so.name;
+ buffer_untouched = so.buffer_untouched;
+ gamma = so.gamma;
+ brightness = so.brightness;
+ contrast = so.contrast;
+
+ /* intialise */
+ buffer = 0;
+ buffer_size = 0;
+
+ /* the widget is not copied ! */
+ internal_widget = 0;
+
+ if( ! ( desc && name ) )
+ {
+ kdWarning( 29000) << "Trying to copy a not healthy option (no name nor desc)" << endl;
+ return;
+ }
+
+ if( so.buffer_untouched )
+ kdDebug(29000) << "Buffer of source is untouched!" << endl;
+
+ switch( desc->type )
+ {
+ case SANE_TYPE_INT:
+ case SANE_TYPE_FIXED:
+ case SANE_TYPE_STRING:
+ buffer = allocBuffer( desc->size );
+ // desc->size / sizeof( SANE_Word )
+ memcpy( buffer, so.buffer, buffer_size );
+ break;
+ case SANE_TYPE_BOOL:
+ buffer = allocBuffer( sizeof( SANE_Word ) );
+ memcpy( buffer, so.buffer, buffer_size );
+ break;
+ default:
+ kdWarning( 29000 ) << "unknown option type in copy constructor" << endl;
+ break;
+ }
+}
+
+
+const QString KScanOption::configLine( void )
+{
+ QCString strval = this->get();
+ kdDebug(29000) << "configLine returns <" << strval << ">" << endl;
+ return( strval );
+}
+
+
+const KScanOption& KScanOption::operator= (const KScanOption& so )
+{
+ /* desc is stored by sane-lib and may be copied */
+ if( this == &so ) return( *this );
+
+ desc = so.desc;
+ name = so.name;
+ buffer_untouched = so.buffer_untouched;
+ gamma = so.gamma;
+ brightness = so.brightness;
+ contrast = so.contrast;
+
+ delete internal_widget;
+ internal_widget = so.internal_widget;
+
+ if( buffer ) {
+ delete [] buffer;
+ buffer = 0;
+ }
+
+ switch( desc->type )
+ {
+ case SANE_TYPE_INT:
+ case SANE_TYPE_FIXED:
+ case SANE_TYPE_STRING:
+ buffer = allocBuffer( desc->size );
+ memcpy( buffer, so.buffer, buffer_size );
+ break;
+ case SANE_TYPE_BOOL:
+ buffer = allocBuffer( sizeof( SANE_Word ) );
+ memcpy( buffer, so.buffer, buffer_size );
+ break;
+ default:
+ buffer = 0;
+ buffer_size = 0;
+ }
+ return( *this );
+}
+
+void KScanOption::slWidgetChange( const QCString& t )
+{
+ kdDebug(29000) << "Received WidgetChange for " << getName() << " (const QCString&)" << endl;
+ set( t );
+ emit( guiChange( this ) );
+ // emit( optionChanged( this ));
+}
+
+void KScanOption::slWidgetChange( void )
+{
+ kdDebug(29000) << "Received WidgetChange for " << getName() << " (void)" << endl;
+ /* If Type is bool, the widget is a checkbox. */
+ if( type() == BOOL )
+ {
+ bool b = ((QCheckBox*) internal_widget)->isChecked();
+ kdDebug(29000) << "Setting bool: " << b << endl;
+ set( b );
+ }
+ emit( guiChange( this ) );
+ // emit( optionChanged( this ));
+
+}
+
+void KScanOption::slWidgetChange( int i )
+{
+ kdDebug(29000) << "Received WidgetChange for " << getName() << " (int)" << endl;
+ set( i );
+ emit( guiChange( this ) );
+ // emit( optionChanged( this ));
+}
+
+/* this slot is called on a widget change, if a widget was created.
+ * In normal case, it is internally connected, so the param so and
+ * this are equal !
+ */
+void KScanOption::slRedrawWidget( KScanOption *so )
+{
+ // qDebug( "Checking widget %s", (const char*) so->getName());
+ int help = 0;
+ QString string;
+
+ QWidget *w = so->widget();
+
+ if( so->valid() && w && so->getBuffer() )
+ {
+ switch( so->type( ) )
+ {
+ case BOOL:
+ if( so->get( &help ))
+ ((QCheckBox*) w)->setChecked( (bool) help );
+ /* Widget Type is ToggleButton */
+ break;
+ case SINGLE_VAL:
+ /* Widget Type is Entry-Field - not implemented yet */
+
+ break;
+ case RANGE:
+ /* Widget Type is Slider */
+ if( so->get( &help ))
+ ((KScanSlider*)w)->slSetSlider( help );
+
+ break;
+ case GAMMA_TABLE:
+ /* Widget Type is GammaTable */
+ // w = new QSlider( parent, "AUTO_GAMMA" );
+ break;
+ case STR_LIST:
+ // w = comboBox( parent, text );
+ ((KScanCombo*)w)->slSetEntry( so->get() );
+ /* Widget Type is Selection Box */
+ break;
+ case STRING:
+ // w = entryField( parent, text );
+ ((KScanEntry*)w)->slSetEntry( so->get() );
+ /* Widget Type is Selection Box */
+ break;
+ default:
+ // w = 0;
+ break;
+ }
+ }
+}
+
+/* In this slot, the option queries the scanner for current values. */
+
+void KScanOption::slReload( void )
+{
+ int *num = (*KScanDevice::option_dic)[ getName() ];
+ desc = getOptionDesc( getName() );
+
+ if( !desc || !num )
+ return;
+
+ if( widget() )
+ {
+ kdDebug(29000) << "constraint is " << desc->cap << endl;
+ if( !active() )
+ kdDebug(29000) << desc->name << " is not active now" << endl;
+
+ if( !softwareSetable() )
+ kdDebug(29000) << desc->name << " is not software setable" << endl;
+
+ if( !active() || !softwareSetable() )
+ {
+ kdDebug(29000) << "Disabling widget " << getName() << " !" << endl;
+ widget()->setEnabled( false );
+ }
+ else
+ widget()->setEnabled( true );
+ }
+
+ /* first get mem if nothing is approbiate */
+ if( !buffer )
+ {
+ kdDebug(29000) << " *********** getting without space **********" << endl;
+ // allocate memory
+ switch( desc->type )
+ {
+ case SANE_TYPE_INT:
+ case SANE_TYPE_FIXED:
+ case SANE_TYPE_STRING:
+ buffer = allocBuffer( desc->size );
+ break;
+ case SANE_TYPE_BOOL:
+ buffer = allocBuffer( sizeof( SANE_Word ) );
+ break;
+ default:
+ if( desc->size > 0 )
+ {
+ buffer = allocBuffer( desc->size );
+ }
+ }
+ }
+
+ if( active())
+ {
+ if( (size_t) desc->size > buffer_size )
+ {
+ kdDebug(29000) << "ERROR: Buffer to small" << endl;
+ }
+ else
+ {
+ SANE_Status sane_stat = sane_control_option( KScanDevice::scanner_handle, *num,
+ SANE_ACTION_GET_VALUE, buffer, 0 );
+
+ if( sane_stat != SANE_STATUS_GOOD )
+ {
+ kdDebug(29000) << "ERROR: Cant get value for " << getName() << ": " << sane_strstatus( sane_stat ) << endl;
+ } else {
+ buffer_untouched = false;
+ kdDebug(29000) << "Setting buffer untouched to FALSE" << endl;
+ }
+ }
+ }
+}
+
+
+KScanOption::~KScanOption()
+{
+#ifdef MEM_DEBUG
+ qDebug( "M: FREEing %d byte of option <%s>", buffer_size, (const char*) getName());
+#endif
+}
+
+bool KScanOption::valid( void ) const
+{
+ return( desc && 1 );
+}
+
+bool KScanOption::autoSetable( void )
+{
+ /* Refresh description */
+ desc = getOptionDesc( name );
+
+ return( desc && ((desc->cap & SANE_CAP_AUTOMATIC) > 0 ) );
+}
+
+bool KScanOption::commonOption( void )
+{
+ /* Refresh description */
+ desc = getOptionDesc( name );
+
+ return( desc && ((desc->cap & SANE_CAP_ADVANCED) == 0) );
+}
+
+
+bool KScanOption::active( void )
+{
+ bool ret = false;
+ /* Refresh description */
+ desc = getOptionDesc( name );
+ if( desc )
+ ret = SANE_OPTION_IS_ACTIVE( desc->cap );
+
+ return( ret );
+}
+
+bool KScanOption::softwareSetable( void )
+{
+ /* Refresh description */
+ desc = getOptionDesc( name );
+ if( desc )
+ {
+ if( SANE_OPTION_IS_SETTABLE(desc->cap) == SANE_TRUE )
+ return( true );
+ }
+ return( false );
+}
+
+
+KSANE_Type KScanOption::type( void ) const
+{
+ KSANE_Type ret = INVALID_TYPE;
+
+ if( valid() )
+ {
+ switch( desc->type )
+ {
+ case SANE_TYPE_BOOL:
+ ret = BOOL;
+ break;
+ case SANE_TYPE_INT:
+ case SANE_TYPE_FIXED:
+ if( desc->constraint_type == SANE_CONSTRAINT_RANGE )
+ {
+ /* FIXME ! Dies scheint nicht wirklich so zu sein */
+ if( desc->size == sizeof( SANE_Word ))
+ ret = RANGE;
+ else
+ ret = GAMMA_TABLE;
+ }
+ else if( desc->constraint_type == SANE_CONSTRAINT_NONE )
+ {
+ ret = SINGLE_VAL;
+ }
+ else if( desc->constraint_type == SANE_CONSTRAINT_WORD_LIST )
+ {
+ ret = STR_LIST;
+ // ret = GAMMA_TABLE;
+ }
+ else
+ {
+ ret = INVALID_TYPE;
+ }
+ break;
+ case SANE_TYPE_STRING:
+ if( desc->constraint_type == SANE_CONSTRAINT_STRING_LIST )
+ ret = STR_LIST;
+ else
+ ret = STRING;
+ break;
+ default:
+ ret = INVALID_TYPE;
+ break;
+ }
+ }
+ return( ret );
+}
+
+
+bool KScanOption::set( int val )
+{
+ if( ! desc ) return( false );
+ bool ret = false;
+
+ int word_size = 0;
+ QMemArray<SANE_Word> qa;
+ SANE_Word sw = SANE_TRUE;
+ const SANE_Word sw1 = val;
+ const SANE_Word sw2 = SANE_FIX( (double) val );
+
+ switch( desc->type )
+ {
+ case SANE_TYPE_BOOL:
+
+ if( ! val )
+ sw = SANE_FALSE;
+ if( buffer ) {
+ memcpy( buffer, &sw, sizeof( SANE_Word ));
+ ret = true;
+ }
+ break;
+ // Type int: Fill the whole buffer with that value
+ case SANE_TYPE_INT:
+ word_size = desc->size / sizeof( SANE_Word );
+
+ qa.resize( word_size );
+ qa.fill( sw1 );
+
+ if( buffer ) {
+ memcpy( buffer, qa.data(), desc->size );
+ ret = true;
+ }
+ break;
+
+ // Type fixed: Fill the whole buffer with that value
+ case SANE_TYPE_FIXED:
+ word_size = desc->size / sizeof( SANE_Word );
+
+ qa.resize( word_size );
+ qa.fill( sw2 );
+
+ if( buffer ) {
+ memcpy( buffer, qa.data(), desc->size );
+ ret = true;
+ }
+ break;
+ default:
+ kdDebug(29000) << "Cant set " << name << " with type int" << endl;
+ }
+ if( ret )
+ {
+ buffer_untouched = false;
+#ifdef APPLY_IN_SITU
+ applyVal();
+#endif
+
+#if 0
+ emit( optionChanged( this ));
+#endif
+ }
+
+ return( ret );
+}
+
+
+
+bool KScanOption::set( double val )
+{
+ if( ! desc ) return( false );
+ bool ret = false;
+ int word_size = 0;
+ QMemArray<SANE_Word> qa;
+ SANE_Word sw = SANE_FALSE;
+
+ switch( desc->type )
+ {
+ case SANE_TYPE_BOOL:
+
+ if( val > 0 )
+ sw = SANE_TRUE;
+ if( buffer ) {
+ memcpy( buffer, &sw, sizeof( SANE_Word ));
+ ret = true;
+ }
+ break;
+ // Type int: Fill the whole buffer with that value
+ case SANE_TYPE_INT:
+ sw = (SANE_Word) val;
+ word_size = desc->size / sizeof( SANE_Word );
+
+ qa.resize( word_size );
+ qa.fill( sw );
+
+ if( buffer ) {
+ memcpy( buffer, qa.data(), desc->size );
+ ret = true;
+ }
+ break;
+
+ // Type fixed: Fill the whole buffer with that value
+ case SANE_TYPE_FIXED:
+ sw = SANE_FIX( val );
+ word_size = desc->size / sizeof( SANE_Word );
+
+ qa.resize( word_size );
+ qa.fill( sw );
+
+ if( buffer ) {
+ memcpy( buffer, qa.data(), desc->size );
+ ret = true;
+ }
+ break;
+ default:
+ kdDebug(29000) << "Cant set " << name << " with type double" << endl;
+ }
+
+ if( ret )
+ {
+ buffer_untouched = false;
+#ifdef APPLY_IN_SITU
+ applyVal();
+#endif
+#if 0
+ emit( optionChanged( this ));
+#endif
+ }
+
+ return( ret );
+}
+
+
+
+bool KScanOption::set( int *val, int size )
+{
+ if( ! desc || ! val ) return( false );
+ bool ret = false;
+ int offset = 0;
+
+ int word_size = desc->size / sizeof( SANE_Word ); /* add 1 in case offset is needed */
+ QMemArray<SANE_Word> qa( 1+word_size );
+#if 0
+ if( desc->constraint_type == SANE_CONSTRAINT_WORD_LIST )
+ {
+ /* That means that the first entry must contain the size */
+ kdDebug(29000) << "Size: " << size << ", word_size: " << word_size << ", descr-size: "<< desc->size << endl;
+ qa[0] = (SANE_Word) 1+size;
+ kdDebug(29000) << "set length field to " << qa[0] <<endl;
+ offset = 1;
+ }
+#endif
+
+ switch( desc->type )
+ {
+ case SANE_TYPE_INT:
+ for( int i = 0; i < word_size; i++ )
+ {
+ if( i < size )
+ qa[offset+i] = (SANE_Word) *(val++);
+ else
+ qa[offset+i] = (SANE_Word) *val;
+ }
+ ret = true;
+ break;
+
+ // Type fixed: Fill the whole buffer with that value
+ case SANE_TYPE_FIXED:
+ for( int i = 0; i < word_size; i++ )
+ {
+ if( i < size )
+ qa[offset+i] = SANE_FIX((double)*(val++));
+ else
+ qa[offset+i] = SANE_FIX((double) *val );
+ }
+ ret = true;
+ break;
+ default:
+ kdDebug(29000) << "Cant set " << name << " with type int*" << endl;
+
+ }
+
+ if( ret && buffer ) {
+ int copybyte = desc->size;
+
+ if( offset )
+ copybyte += sizeof( SANE_Word );
+
+ kdDebug(29000) << "Copying " << copybyte << " byte to options buffer" << endl;
+
+ memcpy( buffer, qa.data(), copybyte );
+ }
+
+ if( ret )
+ {
+ buffer_untouched = false;
+#ifdef APPLY_IN_SITU
+ applyVal();
+#endif
+#if 0
+ emit( optionChanged( this ));
+#endif
+ }
+
+ return( ret );
+}
+
+bool KScanOption::set( const QCString& c_string )
+{
+ bool ret = false;
+ int val = 0;
+
+ if( ! desc ) return( false );
+
+ /* Check if it is a gammatable. If it is, convert to KGammaTable and call
+ * the approbiate set method.
+ */
+ QRegExp re( "\\d+, \\d+, \\d+" );
+ re.setMinimal(true);
+
+ if( QString(c_string).contains( re ))
+ {
+ QStringList relist = QStringList::split( ", ", QString(c_string) );
+
+ int brig = (relist[0]).toInt();
+ int contr = (relist[1]).toInt();
+ int gamm = (relist[2]).toInt();
+
+ KGammaTable gt( brig, contr, gamm );
+ ret = set( &gt );
+ kdDebug(29000) << "Setting GammaTable with int vals " << brig << "|" << contr << "|" << gamm << endl;
+
+ return( ret );
+ }
+
+
+ /* On String-type the buffer gets malloced in Constructor */
+ switch( desc->type )
+ {
+ case SANE_TYPE_STRING:
+ kdDebug(29000) << "Setting " << c_string << " as String" << endl;
+
+ if( buffer_size >= c_string.length() )
+ {
+ memset( buffer, 0, buffer_size );
+ qstrncpy( (char*) buffer, (const char*) c_string, buffer_size );
+ ret = true;
+ }
+ else
+ {
+ kdDebug(29000) << "ERROR: Buffer for String " << c_string << " too small: " << buffer_size << " < " << c_string.length() << endl;
+ }
+ break;
+ case SANE_TYPE_INT:
+ case SANE_TYPE_FIXED:
+ kdDebug(29000) << "Type is INT or FIXED, try to set value <" << c_string << ">" << endl;
+ val = c_string.toInt( &ret );
+ if( ret )
+ set( &val, 1 );
+ else
+ kdDebug(29000) << "Conversion of string value failed!" << endl;
+
+ break;
+ case SANE_TYPE_BOOL:
+ kdDebug(29000) << "Type is BOOL, setting value <" << c_string << ">" << endl;
+ val = 0;
+ if( c_string == "true" ) val = 1;
+ set( val );
+ break;
+ default:
+ kdDebug(29000) << "Type of " << name << " is " << desc->type << endl;
+ kdDebug(29000) << "Cant set " << name << " with type string" << endl;
+ break;
+ }
+
+ if( ret )
+ {
+ buffer_untouched = false;
+#ifdef APPLY_IN_SITU
+ applyVal();
+#endif
+#if 0
+ emit( optionChanged( this ));
+#endif
+ }
+ kdDebug(29000) << "Returning " << ret << endl;
+ return( ret );
+}
+
+
+bool KScanOption::set( KGammaTable *gt )
+{
+ if( ! desc ) return( false );
+ bool ret = true;
+ int size = gt->tableSize();
+ SANE_Word *run = gt->getTable();
+
+ int word_size = desc->size / sizeof( SANE_Word );
+ QMemArray<SANE_Word> qa( word_size );
+ kdDebug(29000) << "KScanOption::set for Gammatable !" << endl;
+ switch( desc->type )
+ {
+ case SANE_TYPE_INT:
+ for( int i = 0; i < word_size; i++ ){
+ if( i < size )
+ qa[i] = *run++;
+ else
+ qa[i] = *run;
+ }
+ break;
+
+ // Type fixed: Fill the whole buffer with that value
+ case SANE_TYPE_FIXED:
+ for( int i = 0; i < word_size; i++ ){
+ if( i < size )
+ qa[i] = SANE_FIX((double)*(run++));
+ else
+ qa[i] = SANE_FIX((double) *run );
+ }
+ break;
+ default:
+ kdDebug(29000) << "Cant set " << name << " with type GammaTable" << endl;
+ ret = false;
+
+ }
+
+ if( ret && buffer )
+ {
+ /* remember raw vals */
+ gamma = gt->getGamma();
+ brightness = gt->getBrightness();
+ contrast = gt->getContrast();
+
+ memcpy( buffer, qa.data(), desc->size );
+ buffer_untouched = false;
+#ifdef APPLY_IN_SITU
+ applyVal();
+#endif
+#if 0
+ emit( optionChanged( this ));
+#endif
+ }
+
+ return( ret );
+}
+
+bool KScanOption::get( int *val ) const
+{
+ SANE_Word sane_word;
+ double d;
+ if( !valid() || !getBuffer())
+ return( false );
+
+ switch( desc->type )
+ {
+ case SANE_TYPE_BOOL:
+ /* Buffer has a SANE_Word */
+ sane_word = *((SANE_Word*)buffer);
+ if( sane_word == SANE_TRUE )
+ *val = 1;
+ else
+ *val = 0;
+ break;
+ /* Type int: Fill the whole buffer with that value */
+ /* reading the first is OK */
+ case SANE_TYPE_INT:
+ sane_word = *((SANE_Word*)buffer);
+ *val = sane_word;
+ break;
+
+ // Type fixed: whole buffer filled with the same value
+ case SANE_TYPE_FIXED:
+ d = SANE_UNFIX(*(SANE_Word*)buffer);
+ *val = (int)d;
+ break;
+ default:
+ kdDebug(29000) << "Cant get " << name << " to type int" << endl;
+ return( false );
+ }
+
+ // qDebug( "option::get returns %d", *val );
+ return( true );
+}
+
+
+
+QCString KScanOption::get( void ) const
+{
+ QCString retstr;
+
+ SANE_Word sane_word;
+
+
+ if( !valid() || !getBuffer())
+ return( "parametererror" );
+
+ switch( desc->type )
+ {
+ case SANE_TYPE_BOOL:
+ sane_word = *((SANE_Word*)buffer);
+ if( sane_word == SANE_TRUE )
+ retstr = "true";
+ else
+ retstr = "false";
+ break;
+ case SANE_TYPE_STRING:
+ retstr = (const char*) getBuffer();
+ // retstr.sprintf( "%s", cc );
+ break;
+ case SANE_TYPE_INT:
+ sane_word = *((SANE_Word*)buffer);
+ retstr.setNum( sane_word );
+ break;
+ case SANE_TYPE_FIXED:
+ sane_word = (SANE_Word) SANE_UNFIX(*(SANE_Word*)buffer);
+ retstr.setNum( sane_word );
+ break;
+
+ default:
+ kdDebug(29000) << "Cant get " << getName() << " to type String !" << endl;
+ retstr = "unknown";
+ }
+
+ /* Handle gamma-table correctly */
+ ;
+ if( type() == GAMMA_TABLE )
+ {
+ retstr.sprintf( "%d, %d, %d", gamma, brightness, contrast );
+ }
+
+ kdDebug(29000) << "option::get returns " << retstr << endl;
+ return( retstr );
+}
+
+
+/* Caller needs to have the space ;) */
+bool KScanOption::get( KGammaTable *gt ) const
+{
+ if( gt )
+ {
+ gt->setAll( gamma, brightness, contrast );
+ // gt->calcTable();
+ return( true );
+ }
+ return( false );
+}
+
+
+QStrList KScanOption::getList( ) const
+{
+ if( ! desc ) return( false );
+ const char **sstring = 0;
+ QStrList strList;
+
+ if( desc->constraint_type == SANE_CONSTRAINT_STRING_LIST ) {
+ sstring = (const char**) desc->constraint.string_list;
+
+ while( *sstring )
+ {
+ // qDebug( "This is in the stringlist: %s", *sstring );
+ strList.append( *sstring );
+ sstring++;
+ }
+ }
+ if( desc->constraint_type == SANE_CONSTRAINT_WORD_LIST ) {
+ const SANE_Int *sint = desc->constraint.word_list;
+ int amount_vals = *sint; sint ++;
+ QString s;
+
+ for( int i=0; i < amount_vals; i++ ) {
+ if( desc->type == SANE_TYPE_FIXED )
+ s.sprintf( "%f", SANE_UNFIX(*sint) );
+ else
+ s.sprintf( "%d", *sint );
+ sint++;
+ strList.append( s.local8Bit() );
+ }
+ }
+ return( strList );
+}
+
+
+
+bool KScanOption::getRangeFromList( double *min, double *max, double *q ) const
+{
+ if( !desc ) return( false );
+ bool ret = true;
+
+ if ( desc->constraint_type == SANE_CONSTRAINT_WORD_LIST ) {
+ // Try to read resolutions from word list
+ kdDebug(29000) << "Resolutions are in a word list" << endl;
+ const SANE_Int *sint = desc->constraint.word_list;
+ int amount_vals = *sint; sint ++;
+ double value;
+ *min = 0;
+ *max = 0;
+ *q = -1; // What is q?
+
+ for( int i=0; i < amount_vals; i++ ) {
+ if( desc->type == SANE_TYPE_FIXED ) {
+ value = (double) SANE_UNFIX( *sint );
+ } else {
+ value = *sint;
+ }
+ if ((*min > value) || (*min == 0)) *min = value;
+ if ((*max < value) || (*max == 0)) *max = value;
+
+ if( min != 0 && max != 0 && max > min ) {
+ double newq = max - min;
+ *q = newq;
+ }
+ sint++;
+ }
+ } else {
+ kdDebug(29000) << "getRangeFromList: No list type " << desc->name << endl;
+ ret = false;
+ }
+ return( ret );
+}
+
+
+
+bool KScanOption::getRange( double *min, double *max, double *q ) const
+{
+ if( !desc ) return( false );
+ bool ret = true;
+
+ if( desc->constraint_type == SANE_CONSTRAINT_RANGE ||
+ desc->constraint_type == SANE_CONSTRAINT_WORD_LIST ) {
+ const SANE_Range *r = desc->constraint.range;
+
+ if( desc->type == SANE_TYPE_FIXED ) {
+ *min = (double) SANE_UNFIX( r->min );
+ *max = (double) SANE_UNFIX( r->max );
+ *q = (double) SANE_UNFIX( r->quant );
+ } else {
+ *min = r->min ;
+ *max = r->max ;
+ *q = r->quant ;
+ }
+ } else {
+ kdDebug(29000) << "getRange: No range type " << desc->name << endl;
+ ret = false;
+ }
+ return( ret );
+}
+
+QWidget *KScanOption::createWidget( QWidget *parent, const QString& w_desc,
+ const QString& tooltip )
+{
+ QStrList list;
+ if( ! valid() )
+ {
+ kdDebug(29000) << "The option is not valid!" << endl;
+ return( 0 );
+ }
+ QWidget *w = 0;
+ /* free the old widget */
+ delete internal_widget;
+ internal_widget = 0;
+
+ /* check for text */
+ QString text = w_desc;
+ if( text.isEmpty() && desc ) {
+ text = QString::fromLocal8Bit( desc->title );
+ }
+
+
+ switch( type( ) )
+ {
+ case BOOL:
+ /* Widget Type is ToggleButton */
+ w = new QCheckBox( text, parent, "AUTO_TOGGLE_BUTTON" );
+ connect( w, SIGNAL(clicked()), this,
+ SLOT(slWidgetChange()));
+ break;
+ case SINGLE_VAL:
+ /* Widget Type is Entry-Field */
+ w = 0; // new QEntryField(
+ kdDebug(29000) << "can not create widget for SINGLE_VAL!" << endl;
+ break;
+ case RANGE:
+ /* Widget Type is Slider */
+ w = KSaneSlider( parent, text );
+ break;
+ case GAMMA_TABLE:
+ /* Widget Type is Slider */
+ // w = KSaneSlider( parent, text );
+ kdDebug(29000) << "can not create widget for GAMMA_TABLE!" << endl;
+ w = 0; // No widget, needs to be a set !
+ break;
+ case STR_LIST:
+ w = comboBox( parent, text );
+ /* Widget Type is Selection Box */
+ break;
+ case STRING:
+ w = entryField( parent, text );
+ /* Widget Type is Selection Box */
+ break;
+ default:
+ kdDebug(29000) << "returning zero for default widget creation!" << endl;
+ w = 0;
+ break;
+ }
+
+ if( w )
+ {
+ internal_widget = w;
+ connect( this, SIGNAL( optionChanged( KScanOption*)),
+ SLOT( slRedrawWidget( KScanOption* )));
+ QString tt = tooltip;
+ if( tt.isEmpty() && desc )
+ tt = QString::fromLocal8Bit( desc->desc );
+
+ if( !tt.isEmpty() )
+ QToolTip::add( internal_widget, tt );
+ }
+
+ /* Check if option is active, setEnabled etc. */
+ slReload();
+ if( w ) slRedrawWidget( this );
+ return( w );
+}
+
+
+QWidget *KScanOption::comboBox( QWidget *parent, const QString& text )
+{
+ QStrList list = getList();
+
+ KScanCombo *cb = new KScanCombo( parent, text, list);
+
+ connect( cb, SIGNAL( valueChanged( const QCString& )), this,
+ SLOT( slWidgetChange( const QCString& )));
+
+ return( cb );
+}
+
+
+QWidget *KScanOption::entryField( QWidget *parent, const QString& text )
+{
+ KScanEntry *ent = new KScanEntry( parent, text );
+ connect( ent, SIGNAL( valueChanged( QCString )), this,
+ SLOT( slWidgetChange( QCString )));
+
+ return( ent );
+}
+
+
+QWidget *KScanOption::KSaneSlider( QWidget *parent, const QString& text )
+{
+ double min, max, quant;
+ getRange( &min, &max, &quant );
+
+ KScanSlider *slider = new KScanSlider( parent, text, min, max );
+ /* Connect to the options change Slot */
+ connect( slider, SIGNAL( valueChanged(int)), this,
+ SLOT( slWidgetChange(int)));
+
+ return( slider );
+}
+
+
+
+
+void *KScanOption::allocBuffer( long size )
+{
+ if( size < 1 ) return( 0 );
+
+#ifdef MEM_DEBUG
+ qDebug( "M: Reserving %ld bytes of mem for <%s>", size, (const char*) getName() );
+#endif
+
+ void *r = new char[ size ];
+ buffer_size = size;
+
+ if( r ) memset( r, 0, size );
+
+ return( r );
+
+}
+
+
+
+bool KScanOption::applyVal( void )
+{
+ bool res = true;
+ int *idx = (*KScanDevice::option_dic)[ name ];
+
+ if( *idx == 0 ) return( false );
+ if( ! buffer ) return( false );
+
+ SANE_Status stat = sane_control_option ( KScanDevice::scanner_handle, *idx,
+ SANE_ACTION_SET_VALUE, buffer,
+ 0 );
+ if( stat != SANE_STATUS_GOOD )
+ {
+ kdDebug(29000) << "Error in in situ appliance " << getName() << ": " << sane_strstatus( stat ) << endl;
+ res = false;
+ }
+ else
+ {
+ kdDebug(29000) << "IN SITU appliance " << getName() << ": OK" << endl;
+
+ }
+ return( res );
+}
+#include "kscanoption.moc"
diff --git a/libkscan/kscanoption.h b/libkscan/kscanoption.h
new file mode 100644
index 00000000..616ece23
--- /dev/null
+++ b/libkscan/kscanoption.h
@@ -0,0 +1,260 @@
+/* This file is part of the KDE Project
+ Copyright (C) 2000 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef _KSCANOPTION_H_
+#define _KSCANOPTION_H_
+
+#include <qwidget.h>
+#include <qdict.h>
+#include <qobject.h>
+#include <qstrlist.h>
+#include <qsocketnotifier.h>
+#include <qdatastream.h>
+
+extern "C" {
+#include <sane/sane.h>
+#include <sane/saneopts.h>
+}
+
+
+typedef enum { KSCAN_OK, KSCAN_ERROR, KSCAN_ERR_NO_DEVICE,
+ KSCAN_ERR_BLOCKED, KSCAN_ERR_NO_DOC, KSCAN_ERR_PARAM,
+ KSCAN_ERR_OPEN_DEV, KSCAN_ERR_CONTROL, KSCAN_ERR_EMPTY_PIC,
+ KSCAN_ERR_MEMORY, KSCAN_ERR_SCAN, KSCAN_UNSUPPORTED,
+ KSCAN_RELOAD, KSCAN_CANCELLED, KSCAN_OPT_NOT_ACTIVE }
+KScanStat;
+
+typedef enum { INVALID_TYPE, BOOL, SINGLE_VAL, RANGE, GAMMA_TABLE, STR_LIST, STRING }
+KSANE_Type;
+
+class KGammaTable;
+
+
+/**
+ * This is KScanOption, a class which holds a single scanner option.
+ *
+ * @short KScanOption
+ * @author Klaas Freitag
+ * @version 0.1alpha
+ *
+ * is a help class for accessing the scanner options.
+ **/
+
+
+class KScanOption : public QObject
+{
+ Q_OBJECT
+
+public:
+ /**
+ * creates a new option object for the named option. After that, the
+ * option is valid and contains the correct value retrieved from the
+ * scanner.
+ **/
+ KScanOption( const QCString& new_name );
+
+ /**
+ * creates a KScanOption from another
+ **/
+ KScanOption( const KScanOption& so );
+ ~KScanOption();
+
+ /**
+ * tests if the option is initialised. It is initialised, if the value
+ * for the option was once read from the scanner
+ **/
+ bool initialised( void ){ return( ! buffer_untouched );}
+
+ /**
+ * checks if the option is valid, means that the option is known by the scanner
+ **/
+ bool valid( void ) const;
+
+ /**
+ * checks if the option is auto setable, what means, the scanner can cope
+ * with the option automatically.
+ **/
+ bool autoSetable( void );
+
+ /**
+ * checks if the option is a so called common option. All frontends should
+ * provide gui elements to change them.
+ **/
+ bool commonOption( void );
+
+ /**
+ * checks if the option is active at the moment. Note that this changes
+ * on runtime due to the settings of mode, resolutions etc.
+ **/
+ bool active( void );
+
+ /**
+ * checks if the option is setable by software. Some scanner options can not
+ * be set by software.
+ **/
+ bool softwareSetable();
+
+ /**
+ * returns the type the option is. Type is one of
+ * INVALID_TYPE, BOOL, SINGLE_VAL, RANGE, GAMMA_TABLE, STR_LIST, STRING
+ **/
+ KSANE_Type type( void ) const;
+
+ /**
+ * set the option depending on the type
+ **/
+ bool set( int val );
+ bool set( double val );
+ bool set( int *p_val, int size );
+ bool set( const QCString& );
+ bool set( bool b ){ if( b ) return(set( (int)(1==1) )); else return( set( (int) (1==0) )); }
+ bool set( KGammaTable *gt );
+
+ /**
+ * retrieves the option value, depending on the type.
+ **/
+ bool get( int* ) const;
+ bool get( KGammaTable* ) const;
+ QCString get( void ) const;
+
+ /**
+ * This function creates a widget for the scanner option depending
+ * on the type of the option.
+ *
+ * For boolean options, a checkbox is generated. For ranges, a KSaneSlider
+ * is generated.
+ *
+ * For a String list such as mode etc., a KScanCombo is generated.
+ *
+ * For option type string and gamma table, no widget is generated yet.
+ *
+ * The widget is maintained completely by the kscanoption object.
+ *
+ **/
+
+ QWidget *createWidget( QWidget *parent,
+ const QString& w_desc = QString::null,
+ const QString& tooltip = QString::null );
+
+ /* Operators */
+ const KScanOption& operator= (const KScanOption& so );
+
+ const QString configLine( void );
+
+
+ // Possible Values
+ QStrList getList() const;
+ bool getRangeFromList( double*, double*, double* ) const;
+ bool getRange( double*, double*, double* ) const;
+
+ QCString getName() const { return( name ); }
+ void * getBuffer() const { return( buffer ); }
+ QWidget *widget( ) const { return( internal_widget ); }
+ /**
+ * returns the type of the selected option.
+ * This might be SINGLE_VAL, VAL_LIST, STR_LIST, GAMMA_TABLE,
+ * RANGE or BOOL
+ *
+ * You may use the information returned to decide, in which way
+ * the option is to set.
+ *
+ * A SINGLE_VAL is returned in case the value is represented by a
+ * single number, e.g. the resoltion.
+ *
+ * A VAL_LIST is returned in case the value needs to be set by
+ * a list of numbers. You need to check the size to find out,
+ * how many numbers you have to
+ * @param name: the name of a option from a returned option-List
+ * return a option type.
+
+ ### not implemented at all?
+ **/
+ KSANE_Type typeToSet( const QCString& name );
+
+ /**
+ * returns a string describing the unit of given the option.
+ * @return the unit description, e.g. mm
+ * @param name: the name of a option from a returned option-List
+
+ ### not implemented at all?
+ **/
+ QString unitOf( const QCString& name );
+
+public slots:
+ void slRedrawWidget( KScanOption *so );
+ /**
+ * that slot makes the option to reload the buffer from the scanner.
+ */
+ void slReload( void );
+
+protected slots:
+ /**
+ * this slot is called if an option has a gui element (not all have)
+ * and if the value of the widget is changed.
+ * This is an internal slot.
+ **/
+ void slWidgetChange( void );
+ void slWidgetChange( const QCString& );
+ void slWidgetChange( int );
+
+ signals:
+ /**
+ * Signal emitted if a option changed for different reasons.
+ * The signal should be connected by outside objects.
+ **/
+ void optionChanged( KScanOption*);
+ /**
+ * Signal emitted if the option is set by a call to the set()
+ * member of the option. In the slot needs to be checked, if
+ * a widget exists, it needs to be set to the new value.
+ * This is a more internal signal
+ **/
+ void optionSet( void );
+
+ /**
+ * Signal called when user changes a gui - element
+ */
+ void guiChange( KScanOption* );
+
+private:
+ bool applyVal( void );
+ bool initOption( const QCString& new_name );
+ void *allocBuffer( long );
+
+ QWidget *entryField ( QWidget *parent, const QString& text );
+ QWidget *KSaneSlider( QWidget *parent, const QString& text );
+ QWidget *comboBox ( QWidget *parent, const QString& text );
+
+ const SANE_Option_Descriptor *desc;
+ QCString name;
+ void *buffer;
+ QWidget *internal_widget;
+ bool buffer_untouched;
+ size_t buffer_size;
+
+ /* For gamma-Tables remember gamma, brightness, contrast */
+ int gamma, brightness, contrast;
+
+ class KScanOptionPrivate;
+ KScanOptionPrivate *d;
+};
+
+
+
+#endif
diff --git a/libkscan/kscanoptset.cpp b/libkscan/kscanoptset.cpp
new file mode 100644
index 00000000..ac30ae40
--- /dev/null
+++ b/libkscan/kscanoptset.cpp
@@ -0,0 +1,221 @@
+/* This file is part of the KDE Project
+ Copyright (C) 2000 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qstring.h>
+#include <qasciidict.h>
+#include <qmap.h>
+#include <qdict.h>
+#include <kdebug.h>
+#include <kconfig.h>
+
+#include "kscandevice.h"
+#include "kscanoption.h"
+#include "kscanoptset.h"
+
+KScanOptSet::KScanOptSet( const QCString& setName )
+{
+ name = setName;
+
+ setAutoDelete( false );
+
+ description = "";
+
+ strayCatsList.setAutoDelete( true );
+}
+
+
+
+KScanOptSet::~KScanOptSet()
+{
+ /* removes all deep copies from backupOption */
+ strayCatsList.clear();
+}
+
+
+
+KScanOption *KScanOptSet::get( const QCString name ) const
+{
+ KScanOption *ret = 0;
+
+ ret = (*this) [name];
+
+ return( ret );
+}
+
+QCString KScanOptSet::getValue( const QCString name ) const
+{
+ KScanOption *re = get( name );
+ QCString retStr = "";
+
+ if( re )
+ {
+ retStr = re->get();
+ }
+ else
+ {
+ kdDebug(29000) << "option " << name << " from OptionSet is not available" << endl;
+ }
+ return( retStr );
+}
+
+
+bool KScanOptSet::backupOption( const KScanOption& opt )
+{
+ bool retval = true;
+
+ /** Allocate a new option and store it **/
+ const QCString& optName = opt.getName();
+ if( !optName )
+ retval = false;
+
+ if( retval )
+ {
+ KScanOption *newopt = find( optName );
+
+ if( newopt )
+ {
+ /** The option already exists **/
+ /* Copy the new one into the old one. TODO: checken Zuweisungoperatoren OK ? */
+ *newopt = opt;
+ }
+ else
+ {
+ const QCString& qq = opt.get();
+ kdDebug(29000) << "Value is now: <" << qq << ">" << endl;
+ const KScanOption *newopt = new KScanOption( opt );
+
+ strayCatsList.append( newopt );
+
+ if( newopt )
+ {
+ insert( optName, newopt );
+ } else {
+ retval = false;
+ }
+ }
+ }
+
+ return( retval );
+
+}
+
+QString KScanOptSet::getDescription() const
+{
+ return description;
+}
+
+void KScanOptSet::slSetDescription( const QString& str )
+{
+ description = str;
+}
+
+void KScanOptSet::backupOptionDict( const QAsciiDict<KScanOption>& optDict )
+{
+ QAsciiDictIterator<KScanOption> it( optDict );
+
+ while ( it.current() )
+ {
+ kdDebug(29000) << "Dict-Backup of Option <" << it.currentKey() << ">" << endl;
+ backupOption( *(it.current()));
+ ++it;
+ }
+
+
+}
+
+/* */
+void KScanOptSet::saveConfig( const QString& scannerName, const QString& configName,
+ const QString& descr )
+{
+ QString confFile = SCANNER_DB_FILE;
+ kdDebug( 29000) << "Creating scan configuration file <" << confFile << ">" << endl;
+
+ KConfig *scanConfig = new KConfig( confFile );
+ QString cfgName = configName;
+
+ if( configName.isNull() || configName.isEmpty() )
+ cfgName = "default";
+
+ scanConfig->setGroup( cfgName );
+
+ scanConfig->writeEntry( "description", descr );
+ scanConfig->writeEntry( "scannerName", scannerName );
+ QAsciiDictIterator<KScanOption> it( *this);
+
+ while ( it.current() )
+ {
+ const QString line = it.current() -> configLine();
+ const QString name = it.current()->getName();
+
+ kdDebug(29000) << "writing " << name << " = <" << line << ">" << endl;
+
+ scanConfig->writeEntry( name, line );
+
+ ++it;
+ }
+
+ scanConfig->sync();
+ delete( scanConfig );
+}
+
+bool KScanOptSet::load( const QString& /*scannerName*/ )
+{
+ QString confFile = SCANNER_DB_FILE;
+ kdDebug( 29000) << "** Reading from scan configuration file <" << confFile << ">" << endl;
+ bool ret = true;
+
+ KConfig *scanConfig = new KConfig( confFile, true );
+ QString cfgName = name; /* of the KScanOptSet, given in constructor */
+
+ if( cfgName.isNull() || cfgName.isEmpty() )
+ cfgName = "default";
+
+ if( ! scanConfig->hasGroup( name ) )
+ {
+ kdDebug(29000) << "Group " << name << " does not exist in configuration !" << endl;
+ ret = false;
+ }
+ else
+ {
+ scanConfig->setGroup( name );
+
+ typedef QMap<QString, QString> StringMap;
+
+ StringMap strMap = scanConfig->entryMap( name );
+
+ StringMap::Iterator it;
+ for( it = strMap.begin(); it != strMap.end(); ++it )
+ {
+ QCString optName = it.key().latin1();
+ KScanOption optset( optName );
+
+ QCString val = it.data().latin1();
+ kdDebug(29000) << "Reading for " << optName << " value " << val << endl;
+
+ optset.set( val );
+
+ backupOption( optset );
+ }
+ }
+ delete( scanConfig );
+
+ return( ret );
+}
+
+/* END */
diff --git a/libkscan/kscanoptset.h b/libkscan/kscanoptset.h
new file mode 100644
index 00000000..042dbe86
--- /dev/null
+++ b/libkscan/kscanoptset.h
@@ -0,0 +1,113 @@
+/* This file is part of the KDE Project
+ Copyright (C) 2000 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSCANOPTSET_H
+#define KSCANOPTSET_H
+
+#include <qobject.h>
+#include <qstring.h>
+#include <qptrlist.h>
+#include <qasciidict.h>
+
+
+#include "kscanoption.h"
+
+/**
+ * This is a container class for KScanOption-objects, which contain information
+ * about single scanner dependant options. It allows you to store a bunch
+ * of options and accessing them via a iterator.
+ *
+ * The class which is inherited from QAsciiDict does no deep copy of the options
+ * to store by with the standard method insert.
+ * @see backupOption to get a deep copy.
+ *
+ * Note that the destructor of the KScanOptSet only clears the options created
+ * by backupOption.
+ *
+ * @author Klaas Freitag@SuSE.de
+ * @version 0.1
+ */
+
+
+
+class KScanOptSet: public QAsciiDict<KScanOption>
+{
+
+public:
+ /**
+ * Constructor to create a new Container. Takes a string as a name, which
+ * has no special meaning yet ;)
+ */
+ KScanOptSet( const QCString& );
+ ~KScanOptSet();
+
+ /**
+ * function to store a deep copy of an option. Note that this class is inherited
+ * from QAsciiDict and thus does no deep copies. This method does.
+ * @see insert
+ */
+ bool backupOption( const KScanOption& );
+
+ /**
+ * returns a pointer to a stored option given by name.
+ */
+ KScanOption *get( const QCString name ) const;
+ QCString getValue( const QCString name ) const;
+
+ void backupOptionDict( const QAsciiDict<KScanOption>& );
+
+ /**
+ * saves a configuration set to the configuration file 'ScanSettings'
+ * in the default dir config (@see KDir). It uses the group given
+ * in configName and stores the entire option set in that group.
+ * additionally, a description is also saved.
+ *
+ * @param scannerName : the name of the scanner
+ * @param configName: The name of the config, e.g. Black and White
+ * @param descr : A description for the config.
+ */
+ void saveConfig( const QString&, const QString&, const QString&);
+
+ /**
+ * allows to load a configuration. Simple create a optionSet with the
+ * approbiate name the config was called ( @see saveConfig ) and call
+ * load for the scanner you want.
+ * @param scannerName: A scanner's name
+ */
+ bool load( const QString& scannerName );
+
+ QString getDescription() const;
+
+public slots:
+
+ void slSetDescription( const QString& );
+
+private:
+ QCString name;
+
+ /* List to collect objects for which memory was allocated and must be freed */
+ QPtrList<KScanOption> strayCatsList;
+
+ class KScanOptSetPrivate;
+ KScanOptSetPrivate *d;
+
+ QString description;
+};
+
+#endif // KScanOptSet
diff --git a/libkscan/kscanslider.cpp b/libkscan/kscanslider.cpp
new file mode 100644
index 00000000..3bf50395
--- /dev/null
+++ b/libkscan/kscanslider.cpp
@@ -0,0 +1,319 @@
+/* This file is part of the KDE Project
+ Copyright (C) 2000 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qlayout.h>
+#include <qpushbutton.h>
+#include <qspinbox.h>
+#include <qtooltip.h>
+#include <qcombobox.h>
+#include <qlabel.h>
+#include <qslider.h>
+#include <qlineedit.h>
+
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include "kscanslider.h"
+
+KScanSlider::KScanSlider( QWidget *parent, const QString& text,
+ double min, double max, bool haveStdButt,
+ int stdValue )
+ : QFrame( parent ),
+ m_stdValue( stdValue ),
+ m_stdButt(0)
+{
+ QHBoxLayout *hb = new QHBoxLayout( this );
+ l1 = new QLabel( text, this, "AUTO_SLIDER_LABEL" );
+ hb->addWidget( l1,20 );
+
+ if( haveStdButt )
+ {
+ KIconLoader *loader = KGlobal::iconLoader();
+ m_stdButt = new QPushButton( this );
+ m_stdButt->setPixmap( loader->loadIcon( "undo",KIcon::Small ));
+
+ /* connect the button click to setting the value */
+ connect( m_stdButt, SIGNAL(clicked()),
+ this, SLOT(slRevertValue()));
+
+ QToolTip::add( m_stdButt,
+ i18n( "Revert value back to its standard value %1" ).arg( stdValue ));
+ hb->addWidget( m_stdButt, 0 );
+ hb->addSpacing( 4 );
+ }
+
+ slider = new QSlider( (int) min, (int)max, 1, (int)min, QSlider::Horizontal, this, "AUTO_SLIDER_" );
+ slider->setTickmarks( QSlider::Below );
+ slider->setTickInterval( int(QMAX( (max-min)/10, 1 )) );
+ slider->setSteps( int(QMAX( (max-min)/20, 1) ), int(QMAX( (max-min)/10, 1) ) );
+ slider->setMinimumWidth( 140 );
+ /* set a buddy */
+ l1->setBuddy( slider );
+
+ /* create a spinbox for displaying the values */
+ m_spin = new QSpinBox( (int) min, (int) max,
+ 1, // step
+ this );
+
+
+ /* make spin box changes change the slider */
+ connect( m_spin, SIGNAL(valueChanged(int)), this, SLOT(slSliderChange(int)));
+
+ /* Handle internal number display */
+ // connect(slider, SIGNAL(valueChanged(int)), numdisp, SLOT( setNum(int) ));
+ connect(slider, SIGNAL(valueChanged(int)), this, SLOT( slSliderChange(int) ));
+
+ /* set Value 0 to the widget */
+ slider->setValue( (int) min -1 );
+
+ /* Add to layout widget and activate */
+ hb->addWidget( slider, 36 );
+ hb->addSpacing( 4 );
+ hb->addWidget( m_spin, 0 );
+
+ hb->activate();
+
+}
+
+void KScanSlider::setEnabled( bool b )
+{
+ if( slider )
+ slider->setEnabled( b );
+ if( l1 )
+ l1->setEnabled( b );
+ if( m_spin )
+ m_spin->setEnabled( b );
+ if( m_stdButt )
+ m_stdButt->setEnabled( b );
+}
+
+void KScanSlider::slSetSlider( int value )
+{
+ /* Important to check value to avoid recursive signals ;) */
+ // debug( "Slider val: %d -> %d", value, slider_val );
+ kdDebug(29000) << "Setting Slider with " << value << endl;
+
+ if( value == slider->value() )
+ {
+ kdDebug(29000) << "Returning because slider value is already == " << value << endl;
+ return;
+ }
+ slider->setValue( value );
+ slSliderChange( value );
+
+}
+
+void KScanSlider::slSliderChange( int v )
+{
+ // kdDebug(29000) << "Got slider val: " << v << endl;
+ // slider_val = v;
+ int spin = m_spin->value();
+ if( v != spin )
+ m_spin->setValue(v);
+ int slid = slider->value();
+ if( v != slid )
+ slider->setValue(v);
+
+ emit( valueChanged( v ));
+}
+
+void KScanSlider::slRevertValue()
+{
+ if( m_stdButt )
+ {
+ /* Only if stdButt is non-zero, the default value is valid */
+ slSetSlider( m_stdValue );
+ }
+}
+
+
+KScanSlider::~KScanSlider()
+{
+}
+
+/* ====================================================================== */
+
+KScanEntry::KScanEntry( QWidget *parent, const QString& text )
+ : QFrame( parent )
+{
+ QHBoxLayout *hb = new QHBoxLayout( this );
+
+ QLabel *l1 = new QLabel( text, this, "AUTO_ENTRYFIELD" );
+ hb->addWidget( l1,1 );
+
+ entry = new QLineEdit( this, "AUTO_ENTRYFIELD_E" );
+ l1->setBuddy( entry );
+ connect( entry, SIGNAL( textChanged(const QString& )),
+ this, SLOT( slEntryChange(const QString&)));
+ connect( entry, SIGNAL( returnPressed()),
+ this, SLOT( slReturnPressed()));
+
+ hb->addWidget( entry,3 );
+ hb->activate();
+}
+
+QString KScanEntry::text( void ) const
+{
+ QString str = QString::null;
+ // kdDebug(29000) << "entry is "<< entry << endl;
+ if(entry)
+ {
+ str = entry->text();
+ if( ! str.isNull() && ! str.isEmpty())
+ {
+ kdDebug(29000) << "KScanEntry returns <" << str << ">" << endl;
+ }
+ else
+ {
+ kdDebug(29000) << "KScanEntry: nothing entered !" << endl;
+ }
+ }
+ else
+ {
+ kdDebug(29000) << "KScanEntry ERR: member var entry not defined!" << endl;
+ }
+ return ( str );
+}
+
+void KScanEntry::slSetEntry( const QString& t )
+{
+ if( t == entry->text() )
+ return;
+ /* Important to check value to avoid recursive signals ;) */
+
+ entry->setText( t );
+}
+
+void KScanEntry::slEntryChange( const QString& t )
+{
+ emit valueChanged( QCString( t.latin1() ) );
+}
+
+void KScanEntry::slReturnPressed( void )
+{
+ QString t = text();
+ emit returnPressed( QCString( t.latin1()));
+}
+
+
+
+KScanCombo::KScanCombo( QWidget *parent, const QString& text,
+ const QStrList& list )
+ : QHBox( parent ),
+ combo(0)
+{
+ createCombo( text );
+ if( combo )
+ combo->insertStrList( list);
+ combolist = list;
+}
+
+KScanCombo::KScanCombo( QWidget *parent, const QString& text,
+ const QStringList& list )
+ : QHBox( parent ),
+ combo(0)
+{
+ createCombo( text );
+ if( combo )
+ combo->insertStringList( list );
+
+ for ( QStringList::ConstIterator it = list.begin(); it != list.end(); ++it ) {
+ combolist.append( (*it).local8Bit() );
+ }
+}
+
+
+void KScanCombo::createCombo( const QString& text )
+{
+ setSpacing( 12 );
+ setMargin( 2 );
+
+
+ (void) new QLabel( text, this, "AUTO_COMBOLABEL" );
+
+ combo = new QComboBox( this, "AUTO_COMBO" );
+
+ connect( combo, SIGNAL(activated( const QString &)), this,
+ SLOT( slComboChange( const QString &)));
+ connect( combo, SIGNAL(activated( int )),
+ this, SLOT(slFireActivated(int)));
+
+}
+
+
+void KScanCombo::slSetEntry( const QString &t )
+{
+ if( t.isNull() ) return;
+ int i = combolist.find( t.local8Bit() );
+
+ /* Important to check value to avoid recursive signals ;) */
+ if( i == combo->currentItem() )
+ return;
+
+ if( i > -1 )
+ combo->setCurrentItem( i );
+ else
+ kdDebug(29000) << "Combo item not in list !" << endl;
+}
+
+void KScanCombo::slComboChange( const QString &t )
+{
+ emit valueChanged( QCString( t.latin1() ) );
+ kdDebug(29000) << "Combo: valueChanged emitted!" << endl;
+}
+
+void KScanCombo::slSetIcon( const QPixmap& pix, const QString& str)
+{
+ for( int i=0; i < combo->count(); i++ )
+ {
+ if( combo->text(i) == str )
+ {
+ combo->changeItem( pix, str, i );
+ break;
+ }
+ }
+}
+
+QString KScanCombo::currentText( void ) const
+{
+ return( combo->currentText() );
+}
+
+
+QString KScanCombo::text( int i ) const
+{
+ return( combo->text(i) );
+}
+
+void KScanCombo::setCurrentItem( int i )
+{
+ combo->setCurrentItem( i );
+}
+
+int KScanCombo::count( void ) const
+{
+ return( combo->count() );
+}
+
+void KScanCombo::slFireActivated( int i )
+{
+ emit( activated( i ));
+}
+
+#include "kscanslider.moc"
diff --git a/libkscan/kscanslider.h b/libkscan/kscanslider.h
new file mode 100644
index 00000000..7502ecad
--- /dev/null
+++ b/libkscan/kscanslider.h
@@ -0,0 +1,244 @@
+/* This file is part of the KDE Project
+ Copyright (C) 2000 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KSCANSLIDER_H
+#define KSCANSLIDER_H
+
+#include <qframe.h>
+#include <qstrlist.h>
+#include <qhbox.h>
+#include <qcombobox.h>
+#include <qslider.h>
+#include <qlineedit.h>
+/**
+ *@author Klaas Freitag
+ */
+
+class QPushButton;
+class QSpinBox;
+class QLabel;
+
+/**
+ * a kind of extended slider which has a spinbox beside the slider offering
+ * the possibility to enter an exact numeric value to the slider. If
+ * desired, the slider has a neutral button by the side. A descriptional
+ * text is handled automatically.
+ *
+ * @author Klaas Freitag <freitag@suse.de>
+ */
+class KScanSlider : public QFrame
+{
+ Q_OBJECT
+ Q_PROPERTY( int slider_val READ value WRITE slSetSlider )
+
+public:
+ /**
+ * Create the slider.
+ *
+ * @param parent parent widget
+ * @param text is the text describing the the slider value. If the text
+ * contains a '&', a buddy for the slider will be created.
+ * @param min minimum slider value
+ * @param max maximum slider value
+ * @param haveStdButt make a 'set to standard'-button visible. The button
+ * appears on the left of the slider.
+ * @param stdValue the value to which the standard button resets the slider.
+ */
+ KScanSlider( QWidget *parent, const QString& text,
+ double min, double max, bool haveStdButt=false,
+ int stdValue=0);
+ /**
+ * Destructor
+ */
+ ~KScanSlider();
+
+ /**
+ * @return the current slider value
+ */
+ int value( ) const
+ { return( slider->value()); }
+
+public slots:
+ /**
+ * sets the slider value
+ */
+ void slSetSlider( int );
+
+ /**
+ * enables the complete slider.
+ */
+ void setEnabled( bool b );
+
+protected slots:
+ /**
+ * reverts the slider back to the standard value given in the constructor
+ */
+ void slRevertValue();
+
+ signals:
+ /**
+ * emitted if the slider value changes
+ */
+ void valueChanged( int );
+
+private slots:
+ void slSliderChange( int );
+
+private:
+ QSlider *slider;
+ QLabel *l1, *numdisp;
+ QSpinBox *m_spin;
+ int m_stdValue;
+ QPushButton *m_stdButt;
+ class KScanSliderPrivate;
+ KScanSliderPrivate *d;
+
+};
+
+/**
+ * a entry field with a prefix text for description.
+ */
+class KScanEntry : public QFrame
+{
+ Q_OBJECT
+ Q_PROPERTY( QString text READ text WRITE slSetEntry )
+
+public:
+ /**
+ * create a new entry field prepended by text.
+ * @param parent the parent widget
+ * @text the prefix text
+ */
+ KScanEntry( QWidget *parent, const QString& text );
+ // ~KScanEntry();
+
+ /**
+ * @return the current entry field contents.
+ */
+ QString text( ) const;
+
+public slots:
+ /**
+ * set the current text
+ * @param t the new string
+ */
+ void slSetEntry( const QString& t );
+ /**
+ * enable or disable the text entry.
+ * @param b set enabled if true, else disabled.
+ */
+ void setEnabled( bool b ){ if( entry) entry->setEnabled( b ); }
+
+protected slots:
+ void slReturnPressed( void );
+
+signals:
+ void valueChanged( const QCString& );
+ void returnPressed( const QCString& );
+
+private slots:
+ void slEntryChange( const QString& );
+
+private:
+ QLineEdit *entry;
+
+ class KScanEntryPrivate;
+ KScanEntryPrivate *d;
+
+};
+
+
+/**
+ * a combobox filled with a decriptional text.
+ */
+class KScanCombo : public QHBox
+{
+ Q_OBJECT
+ Q_PROPERTY( QString cbEntry READ currentText WRITE slSetEntry )
+
+public:
+ /**
+ * create a combobox with prepended text.
+ *
+ * @param parent parent widget
+ * @param text the text the combobox is prepended by
+ * @param list a stringlist with values the list should contain.
+ */
+ KScanCombo( QWidget *parent, const QString& text, const QStrList& list );
+ KScanCombo( QWidget *parent, const QString& text, const QStringList& list );
+ // ~KScanCombo();
+
+ /**
+ * @return the current selected text
+ */
+ QString currentText( ) const;
+
+ /**
+ * @return the text a position i
+ */
+ QString text( int i ) const;
+
+ /**
+ * @return the amount of list entries.
+ */
+ int count( ) const;
+
+public slots:
+ /**
+ * set the current entry to the given string if it is member of the list.
+ * if not, the entry is not changed.
+ */
+ void slSetEntry( const QString &);
+
+ /**
+ * enable or disable the combobox.
+ * @param b enables the combobox if true.
+ */
+ void setEnabled( bool b){ if(combo) combo->setEnabled( b ); };
+
+ /**
+ * set an icon for a string in the combobox
+ * @param pix the pixmap to set.
+ * @param str the string for which the pixmap should be set.
+ */
+ void slSetIcon( const QPixmap& pix, const QString& str);
+
+ /**
+ * set the current item of the combobox.
+ */
+ void setCurrentItem( int i );
+
+private slots:
+ void slFireActivated( int);
+ void slComboChange( const QString & );
+
+signals:
+ void valueChanged( const QCString& );
+ void activated(int);
+
+private:
+ void createCombo( const QString& text );
+ QComboBox *combo;
+ QStrList combolist;
+
+ class KScanComboPrivate;
+ KScanComboPrivate *d;
+};
+
+#endif
diff --git a/libkscan/massscandialog.cpp b/libkscan/massscandialog.cpp
new file mode 100644
index 00000000..c86cd4e5
--- /dev/null
+++ b/libkscan/massscandialog.cpp
@@ -0,0 +1,123 @@
+/* This file is part of the KDE Project
+ Copyright (C) 2000 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qprogressbar.h>
+#include <qgroupbox.h>
+#include <qframe.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <kpushbutton.h>
+#include <kstdguiitem.h>
+
+#include "massscandialog.h"
+
+MassScanDialog::MassScanDialog( QWidget *parent )
+ :QDialog( parent, "MASS_SCAN", true )
+{
+ setCaption( i18n( "ADF Scanning" ));
+ kdDebug(29000) << "Starting MassScanDialog!" << endl;
+ // Layout-Boxes
+ QVBoxLayout *bigdad = new QVBoxLayout( this, 5 );
+ // QHBoxLayout *hl1= new QHBoxLayout( ); // Caption
+ QHBoxLayout *l_but = new QHBoxLayout( 10 ); // Buttons
+
+ /* Caption */
+ QLabel *l1 = new QLabel( i18n( "<B>Mass Scanning</B>" ), this);
+ bigdad->addWidget( l1, 1);
+
+ /* Scan parameter information */
+ QGroupBox *f1 = new QGroupBox( i18n("Scan Parameter"), this );
+ f1->setFrameStyle( QFrame::Box | QFrame::Sunken );
+ f1->setMargin(5);
+ f1->setLineWidth( 1 );
+ QVBoxLayout *l_main = new QVBoxLayout( f1, f1->frameWidth()+3, 3 );
+ bigdad->addWidget( f1, 6 );
+
+ scanopts = i18n("Scanning <B>%s</B> with <B>%d</B> dpi");
+ l_scanopts = new QLabel( scanopts, f1 );
+ l_main->addWidget( l_scanopts );
+
+ tofolder = i18n("Storing new images in folder <B>%s</B>");
+ l_tofolder = new QLabel( tofolder, f1 );
+ l_main->addWidget( l_tofolder );
+
+ /* Scan Progress information */
+ QGroupBox *f2 = new QGroupBox( i18n("Scan Progress"), this );
+ f2->setFrameStyle( QFrame::Box | QFrame::Sunken );
+ f2->setMargin(15);
+ f2->setLineWidth( 1 );
+ QVBoxLayout *l_pro = new QVBoxLayout( f2, f2->frameWidth()+3, 3 );
+ bigdad->addWidget( f2, 6 );
+
+ QHBoxLayout *l_scanp = new QHBoxLayout( );
+ l_pro->addLayout( l_scanp, 5 );
+ progress = i18n("Scanning page %1");
+ l_progress = new QLabel( progress, f2 );
+ l_scanp->addWidget( l_progress, 3 );
+ l_scanp->addStretch( 1 );
+ QPushButton *pb_cancel_scan = new QPushButton( i18n("Cancel Scan"), f2);
+ l_scanp->addWidget( pb_cancel_scan,3 );
+
+ progressbar = new QProgressBar( 1000, f2 );
+ l_pro->addWidget( progressbar, 3 );
+
+ /* Buttons to start scanning and close the Window */
+ bigdad->addLayout( l_but );
+
+ QPushButton *b_start = new QPushButton( i18n("Start Scan"), this, "ButtOK" );
+ connect( b_start, SIGNAL(clicked()), this, SLOT( slStartScan()) );
+
+ QPushButton *b_cancel = new QPushButton( i18n("Stop"), this, "ButtCancel" );
+ connect( b_cancel, SIGNAL(clicked()), this, SLOT(slStopScan()) );
+
+ QPushButton *b_finish = new KPushButton( KStdGuiItem::close(), this, "ButtFinish" );
+ connect( b_finish, SIGNAL(clicked()), this, SLOT(slFinished()) );
+
+ l_but->addWidget( b_start );
+ l_but->addWidget( b_cancel );
+ l_but->addWidget( b_finish );
+
+ bigdad->activate();
+ show();
+}
+
+MassScanDialog::~MassScanDialog()
+{
+
+}
+
+void MassScanDialog::slStartScan( void )
+{
+
+}
+
+void MassScanDialog::slStopScan( void )
+{
+
+}
+
+void MassScanDialog::slFinished( void )
+{
+ delete this;
+}
+
+#include "massscandialog.moc"
diff --git a/libkscan/massscandialog.h b/libkscan/massscandialog.h
new file mode 100644
index 00000000..6e57b098
--- /dev/null
+++ b/libkscan/massscandialog.h
@@ -0,0 +1,67 @@
+/* This file is part of the KDE Project
+ Copyright (C) 2000 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef MASSSCANDIALOG_H
+#define MASSSCANDIALOG_H
+
+#include <qstring.h>
+#include <qdialog.h>
+
+class QProgressBar;
+class QLabel;
+
+/**
+ *@author Klaas Freitag
+ */
+
+class MassScanDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ MassScanDialog( QWidget *parent);
+ ~MassScanDialog();
+
+public slots:
+
+ void slStartScan( void );
+ void slStopScan( void );
+ void slFinished( void );
+
+ void setPageProgress( int p )
+ {
+ progressbar->setProgress( p );
+ }
+
+private:
+ QString scanopts;
+ QLabel *l_scanopts;
+
+ QString tofolder;
+ QLabel *l_tofolder;
+
+ QString progress;
+ QLabel *l_progress;
+
+ QProgressBar *progressbar;
+
+ class MassScanDialogPrivate;
+ MassScanDialogPrivate *d;
+};
+
+#endif
diff --git a/libkscan/pics/Makefile.am b/libkscan/pics/Makefile.am
new file mode 100644
index 00000000..56681824
--- /dev/null
+++ b/libkscan/pics/Makefile.am
@@ -0,0 +1 @@
+KDE_ICON=AUTO \ No newline at end of file
diff --git a/libkscan/pics/cr16-action-palette_color.png b/libkscan/pics/cr16-action-palette_color.png
new file mode 100644
index 00000000..f41ed604
--- /dev/null
+++ b/libkscan/pics/cr16-action-palette_color.png
Binary files differ
diff --git a/libkscan/pics/cr16-action-palette_gray.png b/libkscan/pics/cr16-action-palette_gray.png
new file mode 100644
index 00000000..fe2a423c
--- /dev/null
+++ b/libkscan/pics/cr16-action-palette_gray.png
Binary files differ
diff --git a/libkscan/pics/cr16-action-palette_halftone.png b/libkscan/pics/cr16-action-palette_halftone.png
new file mode 100644
index 00000000..3d410fc9
--- /dev/null
+++ b/libkscan/pics/cr16-action-palette_halftone.png
Binary files differ
diff --git a/libkscan/pics/cr16-action-palette_lineart.png b/libkscan/pics/cr16-action-palette_lineart.png
new file mode 100644
index 00000000..3d410fc9
--- /dev/null
+++ b/libkscan/pics/cr16-action-palette_lineart.png
Binary files differ
diff --git a/libkscan/previewer.cpp b/libkscan/previewer.cpp
new file mode 100644
index 00000000..f4133ee9
--- /dev/null
+++ b/libkscan/previewer.cpp
@@ -0,0 +1,871 @@
+
+/* This file is part of the KDE Project
+ Copyright (C) 2000 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qlabel.h>
+#include <qfontmetrics.h>
+#include <qhbox.h>
+#include <qtooltip.h>
+#include <qpopupmenu.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qcombobox.h>
+#include <qradiobutton.h>
+#include <qgroupbox.h>
+#include <qlayout.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kcombobox.h>
+#include <kaction.h>
+#include <kstandarddirs.h>
+
+#include "previewer.h"
+#include "img_canvas.h"
+#include "sizeindicator.h"
+#include "devselector.h" /* for definition of config key :( */
+#include "kscandevice.h"
+#include <qslider.h>
+#include <qcheckbox.h>
+#include <kconfig.h>
+#include <qbuttongroup.h>
+#include <qvbuttongroup.h>
+#include <kmessagebox.h>
+#include <qvaluevector.h>
+
+#define ID_CUSTOM 0
+#define ID_A4 1
+#define ID_A5 2
+#define ID_A6 3
+#define ID_9_13 4
+#define ID_10_15 5
+#define ID_LETTER 6
+
+/** Config tags for autoselection **/
+#define CFG_AUTOSEL_DO "doAutoselection" /* do it or not */
+#define CFG_AUTOSEL_THRESH "autoselThreshold" /* threshold */
+#define CFG_AUTOSEL_DUSTSIZE "autoselDustsize" /* dust size */
+/* tag if a scan of the empty scanner results in black or white image */
+#define CFG_SCANNER_EMPTY_BG "scannerBackgroundWhite"
+
+/* Defaultvalues for the threshold for the autodetection */
+#define DEF_THRESH_BLACK "45"
+#define DEF_THRESH_WHITE "240"
+
+/* Items for the combobox to set the color of an empty scan */
+#define BG_ITEM_BLACK 0
+#define BG_ITEM_WHITE 1
+
+
+class Previewer::PreviewerPrivate
+{
+public:
+ PreviewerPrivate():
+ m_doAutoSelection(false),
+ m_autoSelThresh(0),
+ m_dustsize(5),
+ m_bgIsWhite(false),
+ m_sliderThresh(0),
+ m_sliderDust(0),
+ m_cbAutoSel(0),
+ m_cbBackground(0),
+ m_autoSelGroup(0),
+ m_scanner(0)
+ {
+ }
+ bool m_doAutoSelection; /* switch auto-selection on and off */
+ int m_autoSelThresh; /* threshold for auto selection */
+ int m_dustsize; /* dustsize for auto selection */
+
+ bool m_bgIsWhite; /* indicates if a scan without paper
+ * results in black or white */
+ QSlider *m_sliderThresh;
+ QSlider *m_sliderDust;
+ QCheckBox *m_cbAutoSel;
+ QComboBox *m_cbBackground;
+ QGroupBox *m_autoSelGroup;
+ KScanDevice *m_scanner;
+
+ QMemArray<long> m_heightSum;
+ QMemArray<long> m_widthSum;
+};
+
+Previewer::Previewer(QWidget *parent, const char *name )
+ : QWidget(parent,name)
+{
+ d = new PreviewerPrivate();
+
+ // beautification to look like the left scanparams widget in the dialog
+ QHBoxLayout *htop = new QHBoxLayout( this );
+ QFrame *frame = new QFrame( this );
+ frame->setFrameStyle( QFrame::Panel | QFrame::Raised );
+ frame->setLineWidth( 1 );
+ htop->addWidget( frame );
+
+ QVBoxLayout *top = new QVBoxLayout( frame, KDialog::marginHint(), KDialog::spacingHint() );
+ layout = new QHBoxLayout( KDialog::spacingHint() );
+ top->addLayout( layout, 9 );
+ QVBoxLayout *left = new QVBoxLayout( KDialog::spacingHint() );
+ layout->addLayout( left, 2 );
+
+ /* Load autoselection values from Config file */
+ KConfig *cfg = KGlobal::config();
+ cfg->setGroup( GROUP_STARTUP );
+
+ /* Units etc. TODO: get from Config */
+ sizeUnit = KRuler::Millimetres;
+ displayUnit = sizeUnit;
+ d->m_autoSelThresh = 240;
+
+ overallHeight = 295; /* Default DIN A4 */
+ overallWidth = 210;
+ kdDebug(29000) << "Previewer: got Overallsize: " <<
+ overallWidth << " x " << overallHeight << endl;
+ img_canvas = new ImageCanvas( frame );
+
+ img_canvas->setDefaultScaleKind( ImageCanvas::DYNAMIC );
+ img_canvas->enableContextMenu(true);
+ img_canvas->repaint();
+ layout->addWidget( img_canvas, 6 );
+
+ /* Actions for the previewer zoom */
+ KAction *act;
+ act = new KAction(i18n("Scale to W&idth"), "scaletowidth", CTRL+Key_I,
+ this, SLOT( slScaleToWidth()), this, "preview_scaletowidth" );
+ act->plug( img_canvas->contextMenu());
+
+ act = new KAction(i18n("Scale to &Height"), "scaletoheight", CTRL+Key_H,
+ this, SLOT( slScaleToHeight()), this, "preview_scaletoheight" );
+ act->plug( img_canvas->contextMenu());
+
+ /*Signals: Control the custom-field and show size of selection */
+ connect( img_canvas, SIGNAL(newRect()), this, SLOT(slCustomChange()));
+ connect( img_canvas, SIGNAL(newRect(QRect)), this, SLOT(slNewDimen(QRect)));
+
+ /* Stuff for the preview-Notification */
+ left->addWidget( new QLabel( i18n("<B>Preview</B>"), frame ), 1);
+
+ // Create a button group to contain buttons for Portrait/Landscape
+ bgroup = new QVButtonGroup( i18n("Scan Size"), frame );
+
+ // -----
+ pre_format_combo = new QComboBox( frame, "PREVIEWFORMATCOMBO" );
+ pre_format_combo->insertItem( i18n( "Custom" ), ID_CUSTOM);
+ pre_format_combo->insertItem( i18n( "DIN A4" ), ID_A4);
+ pre_format_combo->insertItem( i18n( "DIN A5" ), ID_A5);
+ pre_format_combo->insertItem( i18n( "DIN A6" ), ID_A6);
+ pre_format_combo->insertItem( i18n( "9x13 cm" ), ID_9_13 );
+ pre_format_combo->insertItem( i18n( "10x15 cm" ), ID_10_15 );
+ pre_format_combo->insertItem( i18n( "Letter" ), ID_LETTER);
+
+ connect( pre_format_combo, SIGNAL(activated (int)),
+ this, SLOT( slFormatChange(int)));
+
+ left->addWidget( pre_format_combo, 1 );
+
+ /** Potrait- and Landscape Selector **/
+ QFontMetrics fm = bgroup->fontMetrics();
+ int w = fm.width( (const QString)i18n(" Landscape " ) );
+ int h = fm.height( );
+
+ rb1 = new QRadioButton( i18n("&Landscape"), bgroup );
+ landscape_id = bgroup->id( rb1 );
+ rb2 = new QRadioButton( i18n("P&ortrait"), bgroup );
+ portrait_id = bgroup->id( rb2 );
+ bgroup->setButton( portrait_id );
+
+ connect(bgroup, SIGNAL(clicked(int)), this, SLOT(slOrientChange(int)));
+
+ int rblen = 5+w+12; // 12 for the button?
+ rb1->setGeometry( 5, 6, rblen, h );
+ rb2->setGeometry( 5, 1+h/2+h, rblen, h );
+
+ left->addWidget( bgroup, 2 );
+
+
+ /** Autoselection Box **/
+ d->m_autoSelGroup = new QGroupBox( 1, Horizontal, i18n("Auto-Selection"), frame);
+
+ QHBox *hbox = new QHBox(d->m_autoSelGroup);
+ d->m_cbAutoSel = new QCheckBox( i18n("Active on"), hbox );
+ QToolTip::add( d->m_cbAutoSel, i18n("Check here if you want autodetection\n"
+ "of the document on the preview."));
+
+ /* combobox to select if black or white background */
+ d->m_cbBackground = new QComboBox( hbox );
+ d->m_cbBackground->insertItem(i18n("Black"), BG_ITEM_BLACK );
+ d->m_cbBackground->insertItem(i18n("White"), BG_ITEM_WHITE );
+ connect( d->m_cbBackground, SIGNAL(activated(int) ),
+ this, SLOT( slScanBackgroundChanged( int )));
+
+
+ QToolTip::add( d->m_cbBackground,
+ i18n("Select whether a scan of the empty\n"
+ "scanner glass results in a\n"
+ "black or a white image."));
+ connect( d->m_cbAutoSel, SIGNAL(toggled(bool) ), SLOT(slAutoSelToggled(bool)));
+
+ (void) new QLabel( i18n("scanner background"), d->m_autoSelGroup );
+
+ QLabel *l1= new QLabel( i18n("Thresh&old:"), d->m_autoSelGroup );
+ d->m_sliderThresh = new QSlider( 0, 254, 10, d->m_autoSelThresh, Qt::Horizontal,
+ d->m_autoSelGroup );
+ connect( d->m_sliderThresh, SIGNAL(valueChanged(int)), SLOT(slSetAutoSelThresh(int)));
+ QToolTip::add( d->m_sliderThresh,
+ i18n("Threshold for autodetection.\n"
+ "All pixels higher (on black background)\n"
+ "or smaller (on white background)\n"
+ "than this are considered to be part of the image."));
+ l1->setBuddy(d->m_sliderThresh);
+
+#if 0 /** Dustsize-Slider: No deep impact on result **/
+ (void) new QLabel( i18n("Dust size:"), grBox );
+ d->m_sliderDust = new QSlider( 0, 50, 5, d->m_dustsize, Qt::Horizontal, grBox );
+ connect( d->m_sliderDust, SIGNAL(valueChanged(int)), SLOT(slSetAutoSelDustsize(int)));
+#endif
+
+ /* disable Autoselbox as long as no scanner is connected */
+ d->m_autoSelGroup->setEnabled(false);
+
+ left->addWidget(d->m_autoSelGroup);
+
+ /* Labels for the dimension */
+ QGroupBox *gbox = new QGroupBox( 1, Horizontal, i18n("Selection"), frame, "GROUPBOX" );
+
+ QLabel *l2 = new QLabel( i18n("width - mm" ), gbox );
+ QLabel *l3 = new QLabel( i18n("height - mm" ), gbox );
+
+ connect( this, SIGNAL(setScanWidth(const QString&)),
+ l2, SLOT(setText(const QString&)));
+ connect( this, SIGNAL(setScanHeight(const QString&)),
+ l3, SLOT(setText(const QString&)));
+
+ /* size indicator */
+ QHBox *hb = new QHBox( gbox );
+ (void) new QLabel( i18n( "Size:"), hb );
+ SizeIndicator *indi = new SizeIndicator( hb );
+ QToolTip::add( indi, i18n( "This size field shows how large the uncompressed image will be.\n"
+ "It tries to warn you, if you try to produce huge images by \n"
+ "changing its background color." ));
+ indi->setText( i18n("-") );
+
+ connect( this, SIGNAL( setSelectionSize(long)),
+ indi, SLOT( setSizeInByte (long)) );
+
+ left->addWidget( gbox, 1 );
+
+ left->addStretch( 6 );
+
+ top->activate();
+
+ /* Preset custom Cutting */
+ pre_format_combo->setCurrentItem( ID_CUSTOM );
+ slFormatChange( ID_CUSTOM);
+
+ scanResX = -1;
+ scanResY = -1;
+ pix_per_byte = 1;
+
+ selectionWidthMm = 0.0;
+ selectionHeightMm = 0.0;
+ recalcFileSize();
+}
+
+Previewer::~Previewer()
+{
+ delete d;
+}
+
+bool Previewer::setPreviewImage( const QImage &image )
+{
+ if ( image.isNull() )
+ return false;
+
+ m_previewImage = image;
+ img_canvas->newImage( &m_previewImage );
+
+ return true;
+}
+
+QString Previewer::galleryRoot()
+{
+ QString dir = (KGlobal::dirs())->saveLocation( "data", "ScanImages", true );
+
+ if( !dir.endsWith("/") )
+ dir += "/";
+
+ return( dir );
+
+}
+
+void Previewer::newImage( QImage *ni )
+{
+ /* image canvas does not copy the image, so we hold a copy here */
+ m_previewImage = *ni;
+
+ /* clear the auto detection arrays */
+ d->m_heightSum.resize( 0 );
+ d->m_widthSum.resize( 0 );
+
+ img_canvas->newImage( &m_previewImage );
+ findSelection( );
+}
+
+void Previewer::setScanSize( int w, int h, KRuler::MetricStyle unit )
+{
+ overallWidth = w;
+ overallHeight = h;
+ sizeUnit = unit;
+}
+
+
+void Previewer::slSetDisplayUnit( KRuler::MetricStyle unit )
+{
+ displayUnit = unit;
+}
+
+
+void Previewer::slOrientChange( int id )
+{
+ (void) id;
+ /* Gets either portrait or landscape-id */
+ /* Just read the format-selection and call slFormatChange */
+ slFormatChange( pre_format_combo->currentItem() );
+}
+
+/** Slot called whenever the format selection combo changes. **/
+void Previewer::slFormatChange( int id )
+{
+ QPoint p(0,0);
+ bool lands_allowed;
+ bool portr_allowed;
+ bool setSelection = true;
+ int s_long = 0;
+ int s_short= 0;
+
+ isCustom = false;
+
+ switch( id )
+ {
+ case ID_LETTER:
+ s_long = 294;
+ s_short = 210;
+ lands_allowed = false;
+ portr_allowed = true;
+ break;
+ case ID_CUSTOM:
+ lands_allowed = false;
+ portr_allowed = false;
+ setSelection = false;
+ isCustom = true;
+ break;
+ case ID_A4:
+ s_long = 297;
+ s_short = 210;
+ lands_allowed = false;
+ portr_allowed = true;
+ break;
+ case ID_A5:
+ s_long = 210;
+ s_short = 148;
+ lands_allowed = true;
+ portr_allowed = true;
+ break;
+ case ID_A6:
+ s_long = 148;
+ s_short = 105;
+ lands_allowed = true;
+ portr_allowed = true;
+ break;
+ case ID_9_13:
+ s_long = 130;
+ s_short = 90;
+ lands_allowed = true;
+ portr_allowed = true;
+ break;
+ case ID_10_15:
+ s_long = 150;
+ s_short = 100;
+ lands_allowed = true;
+ portr_allowed = true;
+ break;
+ default:
+ lands_allowed = true;
+ portr_allowed = true;
+ setSelection = false;
+ break;
+ }
+
+ rb1->setEnabled( lands_allowed );
+ rb2->setEnabled( portr_allowed );
+
+ int format_id = bgroup->id( bgroup->selected() );
+ if( !lands_allowed && format_id == landscape_id )
+ {
+ bgroup->setButton( portrait_id );
+ format_id = portrait_id;
+ }
+ /* Convert the new dimension to a new QRect and call slot in canvas */
+ if( setSelection )
+ {
+ QRect newrect;
+ newrect.setRect( 0,0, p.y(), p.x() );
+
+ if( format_id == portrait_id )
+ { /* Portrait Mode */
+ p = calcPercent( s_short, s_long );
+ kdDebug(29000) << "Now is portrait-mode" << endl;
+ }
+ else
+ { /* Landscape-Mode */
+ p = calcPercent( s_long, s_short );
+ }
+
+ newrect.setWidth( p.x() );
+ newrect.setHeight( p.y() );
+
+ img_canvas->newRectSlot( newrect );
+ }
+}
+
+/* This is called when the user fiddles around in the image.
+ * This makes the selection custom-sized immediately.
+ */
+void Previewer::slCustomChange( void )
+{
+ if( isCustom )return;
+ pre_format_combo->setCurrentItem(ID_CUSTOM);
+ slFormatChange( ID_CUSTOM );
+}
+
+
+void Previewer::slNewScanResolutions( int x, int y )
+{
+ kdDebug(29000) << "got new Scan Resolutions: " << x << "|" << y << endl;
+ scanResX = x;
+ scanResY = y;
+
+ recalcFileSize();
+}
+
+
+/* This slot is called with the new dimension for the selection
+ * in values between 0..1000. It emits signals, that redraw the
+ * size labels.
+ */
+void Previewer::slNewDimen(QRect r)
+{
+ if( r.height() > 0)
+ selectionWidthMm = (overallWidth / 1000 * r.width());
+ if( r.width() > 0)
+ selectionHeightMm = (overallHeight / 1000 * r.height());
+
+ QString s;
+ s = i18n("width %1 mm").arg( int(selectionWidthMm));
+ emit(setScanWidth(s));
+
+ kdDebug(29000) << "Setting new Dimension " << s << endl;
+ s = i18n("height %1 mm").arg(int(selectionHeightMm));
+ emit(setScanHeight(s));
+
+ recalcFileSize( );
+
+}
+
+void Previewer::recalcFileSize( void )
+{
+ /* Calculate file size */
+ long size_in_byte = 0;
+ if( scanResY > -1 && scanResX > -1 )
+ {
+ double w_inch = ((double) selectionWidthMm) / 25.4;
+ double h_inch = ((double) selectionHeightMm) / 25.4;
+
+ int pix_w = int( w_inch * double( scanResX ));
+ int pix_h = int( h_inch * double( scanResY ));
+
+ size_in_byte = pix_w * pix_h / pix_per_byte;
+ }
+
+ emit( setSelectionSize( size_in_byte ));
+}
+
+
+QPoint Previewer::calcPercent( int w_mm, int h_mm )
+{
+ QPoint p(0,0);
+ if( overallWidth < 1.0 || overallHeight < 1.0 ) return( p );
+
+ if( sizeUnit == KRuler::Millimetres ) {
+ p.setX( static_cast<int>(1000.0*w_mm / overallWidth) );
+ p.setY( static_cast<int>(1000.0*h_mm / overallHeight) );
+ } else {
+ kdDebug(29000) << "ERROR: Only mm supported yet !" << endl;
+ }
+ return( p );
+
+}
+
+void Previewer::slScaleToWidth()
+{
+ if( img_canvas )
+ {
+ img_canvas->handle_popup( ImageCanvas::ID_FIT_WIDTH );
+ }
+}
+
+void Previewer::slScaleToHeight()
+{
+ if( img_canvas )
+ {
+ img_canvas->handle_popup( ImageCanvas::ID_FIT_HEIGHT);
+ }
+}
+
+void Previewer::slConnectScanner( KScanDevice *scan )
+{
+ kdDebug(29000) << "Connecting scan device!" << endl;
+ d->m_scanner = scan;
+
+ if( scan )
+ {
+ /* Enable the by-default disabled autoselection group */
+ d->m_autoSelGroup->setEnabled(true);
+ QString h;
+
+ h = scan->getConfig( CFG_AUTOSEL_DO, QString("unknown") );
+ if( h == QString("on") )
+ d->m_cbAutoSel->setChecked(true);
+ else
+ d->m_cbAutoSel->setChecked(false);
+
+ QString isWhite = d->m_scanner->getConfig( CFG_SCANNER_EMPTY_BG, "unknown" );
+
+ h = scan->getConfig( CFG_AUTOSEL_DUSTSIZE, QString("5") );
+ d->m_dustsize = h.toInt();
+
+ QString thresh = DEF_THRESH_BLACK; /* for black */
+ if( isWhite.lower() == "yes" )
+ thresh = DEF_THRESH_WHITE;
+
+ h = scan->getConfig( CFG_AUTOSEL_THRESH, thresh );
+ d->m_sliderThresh->setValue( h.toInt() );
+ }
+}
+
+void Previewer::slSetScannerBgIsWhite( bool b )
+{
+ d->m_bgIsWhite = b;
+
+ if( d->m_scanner )
+ {
+ if( b ) // The background _is_ white
+ {
+ d->m_cbBackground->setCurrentItem( BG_ITEM_WHITE );
+ }
+ else
+ {
+ d->m_cbBackground->setCurrentItem( BG_ITEM_BLACK );
+ }
+
+ d->m_scanner->slStoreConfig( CFG_SCANNER_EMPTY_BG, b ? QString("Yes") : QString("No"));
+ }
+}
+
+/**
+ * reads the scanner dependant config file through the m_scanner pointer.
+ * If a value for the scanner is not yet known, the function starts up a
+ * popup and asks the user. The result is stored.
+ */
+void Previewer::checkForScannerBg()
+{
+ if( d->m_scanner ) /* Is the scan device already known? */
+ {
+ QString isWhite = d->m_scanner->getConfig( CFG_SCANNER_EMPTY_BG, "unknown" );
+ bool goWhite = false;
+ if( isWhite == "unknown" )
+ {
+ /* not yet known, should ask the user. */
+ kdDebug(29000) << "Dont know the scanner background yet!" << endl;
+
+ goWhite = ( KMessageBox::questionYesNo( this,
+ i18n("The autodetection of images on the preview depends on the background color of the preview image (Think of a preview of an empty scanner).\nPlease select whether the background of the preview image is black or white"),
+ i18n("Image Autodetection"),
+ i18n("White"), i18n("Black") ) == KMessageBox::Yes );
+ kdDebug(29000) << "User said " << isWhite << endl;
+
+ }
+ else
+ {
+ if( isWhite.lower() == "yes" )
+ goWhite = true;
+ }
+
+ /* remember value */
+ slSetScannerBgIsWhite( goWhite );
+ }
+}
+
+void Previewer::slScanBackgroundChanged( int indx )
+{
+ slSetScannerBgIsWhite( indx == BG_ITEM_WHITE );
+}
+
+void Previewer::slAutoSelToggled(bool isOn )
+{
+ if( isOn )
+ checkForScannerBg();
+
+ if( d->m_cbAutoSel )
+ {
+ QRect r = img_canvas->sel();
+
+ kdDebug(29000) << "The rect is " << r.width() << " x " << r.height() << endl;
+ d->m_doAutoSelection = isOn;
+
+ /* Store configuration */
+ if( d->m_scanner )
+ {
+ d->m_scanner->slStoreConfig( CFG_AUTOSEL_DO,
+ isOn ? "on" : "off" );
+ }
+
+ if( isOn && r.width() < 2 && r.height() < 2) /* There is no selection yet */
+ {
+ /* if there is already an image, check, if the bg-color is set already */
+ if( img_canvas->rootImage() )
+ {
+ kdDebug(29000) << "No selection -> try to find one!" << endl;
+
+ findSelection();
+ }
+
+ }
+ }
+ if( d->m_sliderThresh )
+ d->m_sliderThresh->setEnabled(isOn);
+ if( d->m_sliderDust )
+ d->m_sliderDust->setEnabled(isOn);
+ if( d->m_cbBackground )
+ d->m_cbBackground->setEnabled(isOn);
+
+}
+
+
+void Previewer::slSetAutoSelThresh(int t)
+{
+ d->m_autoSelThresh = t;
+ kdDebug(29000) << "Setting threshold to " << t << endl;
+ if( d->m_scanner )
+ d->m_scanner->slStoreConfig( CFG_AUTOSEL_THRESH, QString::number(t) );
+ findSelection();
+}
+
+void Previewer::slSetAutoSelDustsize(int dSize)
+{
+ d->m_dustsize = dSize;
+ kdDebug(29000) << "Setting dustsize to " << dSize << endl;
+ findSelection();
+}
+
+/**
+ * This method tries to find a selection on the preview image automatically.
+ * It uses the image of the preview image canvas, the previewer global
+ * threshold setting and a dustsize.
+ **/
+void Previewer::findSelection( )
+{
+ kdDebug(29000) << "Searching Selection" << endl;
+
+ kdDebug(29000) << "Threshold: " << d->m_autoSelThresh << endl;
+ kdDebug(29000) << "dustsize: " << d->m_dustsize << endl;
+ kdDebug(29000) << "isWhite: " << d->m_bgIsWhite << endl;
+
+
+ if( ! d->m_doAutoSelection ) return;
+ int line;
+ int x;
+ const QImage *img = img_canvas->rootImage();
+ if( ! img ) return;
+
+ long iWidth = img->width();
+ long iHeight = img->height();
+
+ QMemArray<long> heightSum;
+ QMemArray<long> widthSum;
+
+ kdDebug(29000)<< "Preview size is " << iWidth << "x" << iHeight << endl;
+
+ if( (d->m_heightSum).size() == 0 && (iHeight>0) )
+ {
+ kdDebug(29000) << "Starting to fill Array " << endl;
+ QMemArray<long> heightSum(iHeight);
+ QMemArray<long> widthSum(iWidth);
+ heightSum.fill(0);
+ widthSum.fill(0);
+
+ kdDebug(29000) << "filled Array with zero " << endl;
+
+ for( line = 0; line < iHeight; line++ )
+ {
+
+ for( x = 0; x < iWidth; x++ )
+ {
+ int gray = qGray( img->pixel( x, line ));
+ // kdDebug(29000) << "Gray-Value at line " << gray << endl;
+ Q_ASSERT( line < iHeight );
+ Q_ASSERT( x < iWidth );
+ int hsum = heightSum.at(line);
+ int wsum = widthSum.at(x);
+
+ heightSum[line] = hsum+gray;
+ widthSum [x] = wsum+gray;
+ }
+ heightSum[line] = heightSum[line]/iWidth;
+ }
+ /* Divide by amount of pixels */
+ kdDebug(29000) << "Resizing now" << endl;
+ for( x = 0; x < iWidth; x++ )
+ widthSum[x] = widthSum[x]/iHeight;
+
+ kdDebug(29000) << "Filled Arrays successfully" << endl;
+ d->m_widthSum = widthSum;
+ d->m_heightSum = heightSum;
+ }
+ /* Now try to find values in arrays that have grayAdds higher or lower
+ * than threshold */
+#if 0
+ /* debug output */
+ {
+ QFile fi( "/tmp/thheight.dat");
+ if( fi.open( IO_ReadWrite ) ) {
+ QTextStream str( &fi );
+
+ str << "# height ##################" << endl;
+ for( x = 0; x < iHeight; x++ )
+ str << x << '\t' << d->m_heightSum[x] << endl;
+ fi.close();
+ }
+ }
+ QFile fi1( "/tmp/thwidth.dat");
+ if( fi1.open( IO_ReadWrite ))
+ {
+ QTextStream str( &fi1 );
+ str << "# width ##################" << endl;
+ str << "# " << iWidth << " points" << endl;
+ for( x = 0; x < iWidth; x++ )
+ str << x << '\t' << d->m_widthSum[x] << endl;
+
+ fi1.close();
+ }
+#endif
+ int start = 0;
+ int end = 0;
+ QRect r;
+
+ /** scale to 0..1000 range **/
+ start = 0;
+ end = 0;
+ imagePiece( d->m_heightSum, start, end ); // , d->m_threshold, d->m_dustsize, false );
+
+ r.setTop( 1000*start/iHeight );
+ r.setBottom( 1000*end/iHeight);
+ // r.setTop( start );
+ // r.setBottom( end );
+
+ start = 0;
+ end = 0;
+ imagePiece( d->m_widthSum, start, end ); // , d->m_threshold, d->m_dustsize, false );
+ r.setLeft( 1000*start/iWidth );
+ r.setRight( 1000*end/iWidth );
+ // r.setLeft( start );
+ // r.setRight( end );
+
+ kdDebug(29000) << " -- Autodetection -- " << endl;
+ kdDebug(29000) << "Area top " << r.top() << endl;
+ kdDebug(29000) << "Area left" << r.left() << endl;
+ kdDebug(29000) << "Area bottom " << r.bottom() << endl;
+ kdDebug(29000) << "Area right " << r.right() << endl;
+ kdDebug(29000) << "Area width " << r.width() << endl;
+ kdDebug(29000) << "Area height " << r.height() << endl;
+
+ img_canvas->newRectSlot( r );
+ slCustomChange();
+}
+
+
+/*
+ * returns an Array containing the
+ */
+bool Previewer::imagePiece( QMemArray<long> src, int& start, int& end )
+{
+ for( uint x = 0; x < src.size(); x++ )
+ {
+ if( !d->m_bgIsWhite )
+ {
+ /* pixelvalue needs to be higher than threshold, white background */
+ if( src[x] > d->m_autoSelThresh )
+ {
+ /* Ok this pixel could be the start */
+ int iStart = x;
+ int iEnd = x;
+ x++;
+ while( x < src.size() && src[x] > d->m_autoSelThresh )
+ {
+ x++;
+ }
+ iEnd = x;
+
+ int delta = iEnd-iStart;
+
+ if( delta > d->m_dustsize && end-start < delta )
+ {
+ start = iStart;
+ end = iEnd;
+ }
+ }
+ }
+ else
+ {
+ /* pixelvalue needs to be lower than threshold, black background */
+ if( src[x] < d->m_autoSelThresh )
+ {
+ int iStart = x;
+ int iEnd = x;
+ x++;
+ while( x < src.size() && src[x] < d->m_autoSelThresh )
+ {
+ x++;
+ }
+ iEnd = x;
+
+ int delta = iEnd-iStart;
+
+ if( delta > d->m_dustsize && end-start < delta )
+ {
+ start = iStart;
+ end = iEnd;
+ }
+ }
+ }
+ }
+ return (end-start)>0;
+}
+
+#include "previewer.moc"
diff --git a/libkscan/previewer.h b/libkscan/previewer.h
new file mode 100644
index 00000000..b2f993a0
--- /dev/null
+++ b/libkscan/previewer.h
@@ -0,0 +1,120 @@
+/* This file is part of the KDE Project
+ Copyright (C) 2000 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef PREVIEWER_H
+#define PREVIEWER_H
+
+#include <qwidget.h>
+#include <qimage.h>
+#include <qrect.h>
+#include <qbuttongroup.h>
+#include <qpoint.h>
+
+#include <kruler.h>
+#include <qmemarray.h>
+
+/**
+ *@author Klaas Freitag
+ */
+class ImageCanvas;
+class QCheckBox;
+class QSlider;
+class KScanDevice;
+class QComboBox;
+class QRadioButton;
+class QHBoxLayout;
+
+class Previewer : public QWidget
+{
+ Q_OBJECT
+public:
+ Previewer(QWidget *parent=0, const char *name=0);
+ ~Previewer();
+
+ ImageCanvas *getImageCanvas( void ){ return( img_canvas ); }
+
+ /**
+ * Static function that returns the image gallery base dir.
+ */
+ static QString galleryRoot();
+ bool setPreviewImage( const QImage &image );
+ void findSelection();
+
+public slots:
+ void newImage( QImage* );
+ void slFormatChange( int id );
+ void slOrientChange(int);
+ void slSetDisplayUnit( KRuler::MetricStyle unit );
+ void setScanSize( int w, int h, KRuler::MetricStyle unit );
+ void slCustomChange( void );
+ void slNewDimen(QRect r);
+ void slNewScanResolutions( int, int );
+ void recalcFileSize( void );
+ void slSetAutoSelThresh(int);
+ void slSetAutoSelDustsize(int);
+ void slSetScannerBgIsWhite(bool b);
+ void slConnectScanner( KScanDevice *scan );
+protected slots:
+ void slScaleToWidth();
+ void slScaleToHeight();
+ void slAutoSelToggled(bool);
+ void slScanBackgroundChanged(int);
+
+signals:
+ void newRect( QRect );
+ void noRect( void );
+ void setScanWidth(const QString&);
+ void setScanHeight(const QString&);
+ void setSelectionSize( long );
+
+private:
+ void checkForScannerBg();
+
+ QPoint calcPercent( int, int );
+
+ QHBoxLayout *layout;
+ ImageCanvas *img_canvas;
+ QComboBox *pre_format_combo;
+ QMemArray<QCString> format_ids;
+ QButtonGroup * bgroup;
+ QRadioButton * rb1;
+ QRadioButton * rb2;
+ QImage m_previewImage;
+
+ bool imagePiece( QMemArray<long> src,
+ int& start,
+ int& end );
+
+ int landscape_id, portrait_id;
+
+ double overallWidth, overallHeight;
+ KRuler::MetricStyle sizeUnit;
+ KRuler::MetricStyle displayUnit;
+ bool isCustom;
+
+ int scanResX, scanResY;
+ int pix_per_byte;
+ double selectionWidthMm;
+ double selectionHeightMm;
+
+ class PreviewerPrivate;
+ PreviewerPrivate *d;
+};
+
+#endif
diff --git a/libkscan/scandialog.cpp b/libkscan/scandialog.cpp
new file mode 100644
index 00000000..8a6689fa
--- /dev/null
+++ b/libkscan/scandialog.cpp
@@ -0,0 +1,380 @@
+/* This file is part of the KDE Project
+ Copyright (C) 2001 Nikolas Zimmermann <wildfox@kde.org>
+ Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qstringlist.h>
+#include <qstrlist.h>
+#include <qtooltip.h>
+#include <qsizepolicy.h>
+#include <qapplication.h>
+#include <qcheckbox.h>
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kconfig.h>
+#include <ksimpleconfig.h>
+#include <kled.h>
+#include <kglobalsettings.h>
+#include <kscandevice.h>
+
+// libkscan stuff
+#include "scanparams.h"
+#include "devselector.h"
+#include "img_canvas.h"
+#include "previewer.h"
+#include "scandialog.h"
+
+#define SCANDIA_SPLITTER_SIZES "ScanDialogSplitter %1"
+
+extern "C" {
+ void * init_libkscan() {
+ return new ScanDialogFactory;
+ }
+}
+
+ScanDialogFactory::ScanDialogFactory( QObject *parent, const char *name )
+ : KScanDialogFactory( parent, name )
+{
+ setName( "ScanDialogFactory" );
+ KGlobal::locale()->insertCatalogue( QString::fromLatin1("libkscan") );
+}
+
+KScanDialog * ScanDialogFactory::createDialog( QWidget *parent,
+ const char *name, bool modal)
+{
+ return new ScanDialog( parent, name, modal );
+}
+
+
+///////////////////////////////////////////////////////////////////
+
+
+ScanDialog::ScanDialog( QWidget *parent, const char *name, bool modal )
+ : KScanDialog( Tabbed, Close|Help, parent, name, modal ),
+ good_scan_connect(false)
+{
+ QVBox *page = addVBoxPage( i18n("&Scanning") );
+
+ splitter = new QSplitter( Horizontal, page, "splitter" );
+ Q_CHECK_PTR( splitter );
+
+ m_scanParams = 0;
+ m_device = new KScanDevice( this );
+ connect(m_device, SIGNAL(sigNewImage(QImage *, ImgScanInfo*)),
+ this, SLOT(slotFinalImage(QImage *, ImgScanInfo *)));
+
+ connect( m_device, SIGNAL(sigScanStart()), this, SLOT(slotScanStart()));
+ connect( m_device, SIGNAL(sigScanFinished(KScanStat)),
+ this, SLOT(slotScanFinished(KScanStat)));
+ connect( m_device, SIGNAL(sigAcquireStart()), this, SLOT(slotAcquireStart()));
+ /* Create a preview widget to the right side of the splitter */
+ m_previewer = new Previewer( splitter );
+ Q_CHECK_PTR(m_previewer );
+
+ /* ... and connect to the selector-slots. They communicate user's
+ * selection to the scanner parameter engine */
+ /* a new preview signal */
+ connect( m_device, SIGNAL( sigNewPreview( QImage*, ImgScanInfo* )),
+ this, SLOT( slotNewPreview( QImage* )));
+
+ m_previewer->setEnabled( false ); // will be enabled in setup()
+
+ /* Options-page */
+ createOptionsTab( );
+
+}
+
+
+void ScanDialog::createOptionsTab( void )
+{
+
+ QVBox *page = addVBoxPage( i18n("&Options"));
+ setMainWidget(page);
+
+ QGroupBox *gb = new QGroupBox( 1, Qt::Horizontal, i18n("Startup Options"), page, "GB_STARTUP" );
+ QLabel *label = new QLabel( i18n( "Note: changing these options will affect the scan plugin on next start." ),
+ gb );
+ label->setSizePolicy( QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed ) );
+
+ /* Checkbox for asking for scanner on startup */
+ cb_askOnStart = new QCheckBox( i18n( "&Ask for the scan device on plugin startup"), gb );
+ QToolTip::add( cb_askOnStart,
+ i18n("You can uncheck this if you do not want to be asked which scanner to use on startup."));
+ Q_CHECK_PTR( cb_askOnStart );
+
+ /* Checkbox for network access */
+ cb_network = new QCheckBox( i18n( "&Query the network for scan devices"), gb );
+ QToolTip::add( cb_network,
+ i18n("Check this if you want to query for configured network scan stations."));
+ Q_CHECK_PTR( cb_network );
+
+
+ /* Read settings for startup behavior */
+ KConfig *gcfg = KGlobal::config();
+ gcfg->setGroup(QString::fromLatin1(GROUP_STARTUP));
+ bool skipDialog = gcfg->readBoolEntry( STARTUP_SKIP_ASK, false );
+ bool onlyLocal = gcfg->readBoolEntry( STARTUP_ONLY_LOCAL, false );
+
+ /* Note: flag must be inverted because of question is 'the other way round' */
+ cb_askOnStart->setChecked( !skipDialog );
+ connect( cb_askOnStart, SIGNAL(toggled(bool)), this, SLOT(slotAskOnStartToggle(bool)));
+
+ cb_network->setChecked( !onlyLocal );
+ connect( cb_network, SIGNAL(toggled(bool)), this, SLOT(slotNetworkToggle(bool)));
+
+
+ QWidget *spaceEater = new QWidget( page );
+ Q_CHECK_PTR( spaceEater );
+ spaceEater->setSizePolicy( QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding) );
+
+}
+
+void ScanDialog::slotNetworkToggle( bool state)
+{
+ bool writestate = !state;
+
+ kdDebug(29000) << "slotNetworkToggle: Writing state " << writestate << endl;
+ KConfig *c = KGlobal::config();
+ c->setGroup(QString::fromLatin1(GROUP_STARTUP));
+ c->writeEntry( STARTUP_ONLY_LOCAL, writestate, true, true );
+}
+
+void ScanDialog::slotAskOnStartToggle(bool state)
+{
+ bool writestate = !state;
+
+ kdDebug(29000) << "slotAskOnStartToggle: Writing state " << writestate << endl;
+ KConfig *c = KGlobal::config();
+ c->setGroup(QString::fromLatin1(GROUP_STARTUP));
+ c->writeEntry( STARTUP_SKIP_ASK, writestate, true, true );
+}
+
+void ScanDialog::slotScanStart( )
+{
+ if( m_scanParams )
+ {
+ m_scanParams->setEnabled( false );
+ KLed *led = m_scanParams->operationLED();
+ if( led )
+ {
+ led->setColor( Qt::red );
+ led->setState( KLed::On );
+ }
+
+ }
+}
+
+void ScanDialog::slotAcquireStart( )
+{
+ if( m_scanParams )
+ {
+ KLed *led = m_scanParams->operationLED();
+ if( led )
+ {
+ led->setColor( Qt::green );
+ }
+
+ }
+}
+
+void ScanDialog::slotScanFinished( KScanStat status )
+{
+ kdDebug(29000) << "Scan finished with status " << status << endl;
+ if( m_scanParams )
+ {
+ m_scanParams->setEnabled( true );
+ KLed *led = m_scanParams->operationLED();
+ if( led )
+ {
+ led->setColor( Qt::green );
+ led->setState( KLed::Off );
+ }
+
+ }
+}
+
+bool ScanDialog::setup()
+{
+ if( ! m_device )
+ {
+ good_scan_connect = false;
+ return(false);
+ }
+ // The scan device is now closed on closing the scan dialog. That means
+ // that more work to open it needs to be done in the setup slot like opening
+ // the selector if necessary etc.
+
+ if( m_scanParams )
+ {
+ /* if m_scanParams exist it means, that the dialog is already open */
+ return true;
+ }
+
+ m_scanParams = new ScanParams( splitter );
+ connect( m_previewer->getImageCanvas(), SIGNAL( newRect(QRect)),
+ m_scanParams, SLOT(slCustomScanSize(QRect)));
+ connect( m_previewer->getImageCanvas(), SIGNAL( noRect()),
+ m_scanParams, SLOT(slMaximalScanSize()));
+
+ connect( m_scanParams, SIGNAL( scanResolutionChanged( int, int )),
+ m_previewer, SLOT( slNewScanResolutions( int, int )));
+
+
+ /* continue to attach a real scanner */
+ /* first, get the list of available devices from libkscan */
+ QStringList scannerNames;
+ QStrList backends = m_device->getDevices();;
+ QStrListIterator it( backends );
+
+ while ( it.current() ) {
+ scannerNames.append( m_device->getScannerName( it.current() ));
+ ++it;
+ }
+
+ /* ..if there are devices.. */
+ QCString configDevice;
+ good_scan_connect = true;
+ if( scannerNames.count() > 0 )
+ {
+ /* allow the user to select one */
+ DeviceSelector ds( this, backends, scannerNames );
+ configDevice = ds.getDeviceFromConfig( );
+
+ if( configDevice.isEmpty() || configDevice.isNull() )
+ {
+ kdDebug(29000) << "configDevice is not valid - starting selector!" << configDevice << endl;
+ if ( ds.exec() == QDialog::Accepted )
+ {
+ configDevice = ds.getSelectedDevice();
+ }
+ }
+
+ /* If a device was selected, */
+ if( ! configDevice.isNull() )
+ {
+ /* ..open it (init sane with that) */
+ m_device->openDevice( configDevice );
+
+ /* ..and connect to the gui (create the gui) */
+ if ( !m_scanParams->connectDevice( m_device ) )
+ {
+ kdDebug(29000) << "ERR: Could not connect scan device" << endl;
+ good_scan_connect = false;
+ }
+ }
+ }
+
+ if( configDevice.isNull() || configDevice.isEmpty() )
+ {
+ /* No scanner found, open with information */
+ m_scanParams->connectDevice( 0L );
+ good_scan_connect = false;
+ /* Making the previewer gray */
+ /* disabling is much better than hiding for 'advertising' ;) */
+ }
+
+ /* Move the scan params to the left, for backward compatibility.
+ * However, having it on the right looks a bit better IMHO */
+ if( splitter && m_scanParams )
+ splitter->moveToFirst( m_scanParams );
+
+ if( good_scan_connect )
+ {
+ m_previewer->setEnabled( true );
+ m_previewer->setPreviewImage( m_device->loadPreviewImage() );
+ m_previewer->slConnectScanner( m_device );
+ }
+
+ /* set initial sizes */
+ setInitialSize( configDialogSize( GROUP_STARTUP ));
+
+ KConfig *kfg = KGlobal::config();
+ if( kfg )
+ {
+ QRect r = KGlobalSettings::desktopGeometry(this);
+
+ kfg->setGroup( GROUP_STARTUP );
+ /* Since this is a vertical splitter, only the width is important */
+ QString key = QString::fromLatin1( SCANDIA_SPLITTER_SIZES ).arg( r.width());
+ kdDebug(29000) << "Read Splitter-Sizes " << key << endl;
+ splitter->setSizes( kfg->readIntListEntry( key ));
+ }
+
+ return true;
+}
+
+void ScanDialog::slotClose()
+{
+ /* Save the dialog start size to global configuration */
+ saveDialogSize( GROUP_STARTUP, true );
+
+ if( splitter )
+ {
+ KConfig *kfg = KGlobal::config();
+ if( kfg )
+ {
+ QRect r = KGlobalSettings::desktopGeometry(this);
+
+ kfg->setGroup( GROUP_STARTUP );
+ /* Since this is a vertical splitter, only the width is important */
+ QString key = QString::fromLatin1( SCANDIA_SPLITTER_SIZES ).arg( r.width());
+ kfg->writeEntry( key, splitter->sizes(), true, true);
+ }
+ }
+
+ if( m_scanParams )
+ {
+ delete m_scanParams;
+ m_scanParams =0;
+ }
+ if( m_device )
+ m_device->slCloseDevice();
+ else
+ kdDebug(29000) << "ERR: no device exists :(" << endl;
+ // bullshit happend
+ accept();
+}
+
+void ScanDialog::slotNewPreview( QImage *image )
+{
+ if( image )
+ {
+ m_previewImage = *image;
+ // hmmm - dont know, if conversion of the bit-depth is necessary.
+ // m_previewImage.convertDepth(32);
+
+ /* The previewer does not copy the image data ! */
+ m_previewer->newImage( &m_previewImage );
+ }
+
+}
+
+ScanDialog::~ScanDialog()
+{
+}
+
+void ScanDialog::slotFinalImage(QImage *image, ImgScanInfo *)
+{
+ emit finalImage(*image, nextId());
+}
+
+#include "scandialog.moc"
diff --git a/libkscan/scandialog.h b/libkscan/scandialog.h
new file mode 100644
index 00000000..02aa48b1
--- /dev/null
+++ b/libkscan/scandialog.h
@@ -0,0 +1,83 @@
+/* This file is part of the KDE Project
+ Copyright (C)2001 Nikolas Zimmermann <wildfox@kde.org>
+ Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SCAN_H
+#define SCAN_H
+
+#include <qimage.h>
+#include <kscan.h>
+
+class ScanParams;
+class KScanDevice;
+class Previewer;
+class QSplitter;
+
+class ScanDialog : public KScanDialog
+{
+ Q_OBJECT
+
+public:
+ ScanDialog( QWidget *parent=0, const char *name=0, bool modal=false );
+ ~ScanDialog();
+
+ virtual bool setup();
+
+private:
+ void createOptionsTab( void );
+
+protected slots:
+ void slotFinalImage( QImage *, ImgScanInfo * );
+ void slotNewPreview( QImage * );
+ void slotScanStart( );
+ void slotScanFinished( KScanStat status );
+ void slotAcquireStart();
+
+private slots:
+ void slotAskOnStartToggle(bool state);
+ void slotNetworkToggle( bool state);
+
+
+ void slotClose();
+private:
+ ScanParams *m_scanParams;
+ KScanDevice *m_device;
+ Previewer *m_previewer;
+ QImage m_previewImage;
+ bool good_scan_connect;
+ QCheckBox *cb_askOnStart;
+ QCheckBox *cb_network;
+ QSplitter *splitter;
+ class ScanDialogPrivate;
+ ScanDialogPrivate *d;
+};
+
+class ScanDialogFactory : public KScanDialogFactory
+{
+public:
+ ScanDialogFactory( QObject *parent=0, const char *name=0 );
+
+protected:
+ virtual KScanDialog * createDialog( QWidget *parent=0, const char *name=0,
+ bool modal=false );
+
+
+};
+
+#endif // SCAN_H
diff --git a/libkscan/scanparams.cpp b/libkscan/scanparams.cpp
new file mode 100644
index 00000000..d886d113
--- /dev/null
+++ b/libkscan/scanparams.cpp
@@ -0,0 +1,1140 @@
+/* This file is part of the KDE Project
+ Copyright (C) 1999 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <sane/saneopts.h>
+#include <qcstring.h>
+#include <qfile.h>
+#include <qframe.h>
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qcombobox.h>
+#include <qimage.h>
+#include <qtooltip.h>
+#include <qmessagebox.h>
+#include <qlayout.h>
+#include <qdict.h>
+#include <qprogressdialog.h>
+#include <qscrollview.h>
+#include <qsizepolicy.h>
+#include <qcheckbox.h>
+#include <qbuttongroup.h>
+
+
+#include <kfiledialog.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kbuttonbox.h>
+#include <kiconloader.h>
+#include <kled.h>
+#include <kseparator.h>
+
+#include "scanparams.h"
+#include <scansourcedialog.h>
+#include "massscandialog.h"
+#include <gammadialog.h>
+#include "kscanslider.h"
+
+
+
+
+ScanParams::ScanParams( QWidget *parent, const char *name )
+ : QVBox( parent, name ),
+ m_firstGTEdit( true )
+{
+ /* first some initialisation and debug messages */
+ sane_device = 0; virt_filename = 0;
+ pb_edit_gtable = 0;
+ cb_gray_preview = 0;
+ pb_source_sel = 0;
+ bg_virt_scan_mode = 0;
+ xy_resolution_bind = 0;
+ progressDialog = 0;
+
+ /* Preload icons */
+ pixMiniFloppy = SmallIcon( "3floppy_unmount" );
+
+ pixColor = SmallIcon( "palette_color" );
+ pixGray = SmallIcon( "palette_gray" );
+ pixLineArt = SmallIcon( "palette_lineart" );
+ pixHalftone = SmallIcon( "palette_halftone" );
+
+ /* intialise the default last save warnings */
+ startupOptset = 0;
+
+}
+
+bool ScanParams::connectDevice( KScanDevice *newScanDevice )
+{
+ setMargin( KDialog::marginHint() );
+ setSpacing( KDialog::spacingHint() );
+ /* Debug: dump common Options */
+
+ if( ! newScanDevice )
+ {
+ kdDebug(29000) << "No scan device found !" << endl;
+ sane_device = 0L;
+ createNoScannerMsg();
+ return( true );
+ }
+ sane_device = newScanDevice;
+
+ QStrList strl = sane_device->getCommonOptions();
+ QString emp;
+ for ( emp=strl.first(); strl.current(); emp=strl.next() )
+ kdDebug(29000) << "Common: " << strl.current() << endl;
+
+ /* Start path for virual scanner */
+ last_virt_scan_path = QDir::home();
+ adf = ADF_OFF;
+
+ /* Frame stuff for toplevel of scanparams - beautification */
+ setFrameStyle( QFrame::Panel | QFrame::Raised );
+ setLineWidth( 1 );
+
+
+ /* initialise own widgets */
+ cb_gray_preview = 0;
+
+ /* A top layout box */
+ // QVBoxLayout *top = new QVBoxLayout(this, 6);
+ QHBox *hb = new QHBox( this );
+ hb->setSpacing( KDialog::spacingHint() );
+ QString cap = i18n("<B>Scanner Settings</B>") + " : ";
+ cap += sane_device->getScannerName();
+ (void ) new QLabel( cap, hb );
+ m_led = new KLed( hb );
+ m_led->setState( KLed::Off );
+ m_led->setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ));
+
+
+ (void) new KSeparator( KSeparator::HLine, this);
+
+ /* Now create Widgets for the important scan settings */
+ QScrollView *sv = 0;
+
+ if( sane_device->optionExists( SANE_NAME_FILE ) )
+ {
+ /* Its a virtual scanner */
+ scan_mode = ID_SANE_DEBUG;
+ virtualScannerParams( );
+
+ } else {
+ scan_mode = ID_SCAN;
+
+ /* load the startup scanoptions */
+ startupOptset = new KScanOptSet( DEFAULT_OPTIONSET );
+ Q_CHECK_PTR( startupOptset );
+
+ if( !startupOptset->load( "Startup" ) )
+ {
+ kdDebug(29000) << "Could not load Startup-Options" << endl;
+ delete startupOptset;
+ startupOptset = 0;
+ }
+ sv = scannerParams( );
+ }
+
+ /* Reload all options to care for inactive options */
+ sane_device->slReloadAll();
+
+ /* Create a Start-Scan-Button */
+ (void) new KSeparator( KSeparator::HLine, this);
+ KButtonBox *kbb = new KButtonBox( this );
+ QPushButton* pb = kbb->addButton( KGuiItem( i18n( "Final S&can" ), "scanner" ) );
+ connect( pb, SIGNAL(clicked()), this, SLOT(slStartScan()) );
+ pb = kbb->addButton( i18n( "&Preview Scan" ));
+ connect( pb, SIGNAL(clicked()), this, SLOT(slAcquirePreview()) );
+ kbb->layout();
+
+ /* Initialise the progress dialog */
+ progressDialog = new QProgressDialog( i18n("Scanning in progress"),
+ i18n("Stop"), 100, 0L,
+ "SCAN_PROGRESS", true, 0 );
+ progressDialog->setAutoClose( true );
+ progressDialog->setAutoReset( true );
+
+ connect( sane_device, SIGNAL(sigScanProgress(int)),
+ progressDialog, SLOT(setProgress(int)));
+
+ /* Connect the Progress Dialogs cancel-Button */
+ connect( progressDialog, SIGNAL( cancelled() ), sane_device,
+ SLOT( slStopScanning() ) );
+
+ return( true );
+}
+
+
+ScanParams::~ScanParams()
+{
+ if( startupOptset )
+ {
+ delete startupOptset;
+ startupOptset = 0;
+ }
+
+ if( progressDialog )
+ {
+ delete( progressDialog );
+ progressDialog = 0;
+ }
+}
+
+void ScanParams::initialise( KScanOption *so )
+{
+ if( ! so ) return;
+ bool initialised = false;
+
+ if( startupOptset )
+ {
+ QCString name = so->getName();
+ if( ! name.isEmpty() ){
+ QCString val = startupOptset->getValue( name );
+ kdDebug( 29000) << "Initialising <" << name << "> with value <" << val << ">" << endl;
+ so->set( val );
+ sane_device->apply(so);
+ initialised = true;
+ }
+ }
+
+ if( ! initialised )
+ {
+
+ }
+}
+
+QScrollView *ScanParams::scannerParams( )
+{
+ KScanOption *so = 0;
+
+ /* Its a real scanner */
+ QScrollView *sv = new QScrollView( this );
+ sv->setHScrollBarMode( QScrollView::AlwaysOff );
+ sv->setResizePolicy( QScrollView::AutoOneFit );
+ QVBox *pbox = new QVBox( sv->viewport());
+ pbox->setSpacing( KDialog::spacingHint() );
+ sv->setFrameStyle( QFrame::NoFrame );
+
+ QHBox *hb = new QHBox(pbox);
+
+ /* Mode setting */
+ so = sane_device->getGuiElement( SANE_NAME_SCAN_MODE, hb,
+ SANE_TITLE_SCAN_MODE,
+ SANE_DESC_SCAN_MODE );
+ if ( so )
+ {
+ /* Pretty-Pixmap */
+
+ KScanCombo *cb = (KScanCombo*) so->widget();
+ Q_CHECK_PTR(cb);
+ // the following strings are not translatable since the sane library does not translate them.
+ // so, if we want icons, we have to keep them non-translated for now.
+ cb->slSetIcon( pixLineArt, "Line art" );
+ cb->slSetIcon( pixLineArt, "Lineart" );
+ cb->slSetIcon( pixLineArt, "Binary" );
+ cb->slSetIcon( pixGray, "Gray" );
+ cb->slSetIcon( pixGray, "Gray" );
+ cb->slSetIcon( pixColor, "Color" );
+ cb->slSetIcon( pixHalftone, "Halftone" );
+
+ // hb->setMargin( KDialog::marginHint() );
+ // hb->setSpacing( KDialog::spacingHint());
+ hb->setMargin( 0 ); /// KDialog::marginHint() );
+ hb->setSpacing( KDialog::spacingHint());
+
+ hb->setStretchFactor( cb, 5 );
+
+ initialise( so );
+ connect( so, SIGNAL(guiChange(KScanOption*)),
+ this, SLOT(slReloadAllGui( KScanOption* )));
+ }
+
+ /* Add a button for Source-Selection */
+ if( sane_device->optionExists( SANE_NAME_SCAN_SOURCE ))
+ {
+ KScanOption source( SANE_NAME_SCAN_SOURCE );
+ QStrList l = source.getList();
+
+ QWidget *spacer = new QWidget(hb);
+ hb->setStretchFactor( spacer, 1 );
+ kdDebug(29000) << "Source list size: " << l.count() << endl;
+
+ if( l.count() > 1 )
+ {
+ pb_source_sel = new QPushButton( i18n("Source..."), hb );
+ connect( pb_source_sel, SIGNAL(clicked()), this, SLOT(slSourceSelect()));
+ initialise( &source );
+ hb->setStretchFactor( pb_source_sel, 3 );
+
+#if 0 /* Testing !! TODO: remove */
+ if( ! source.active() ) {
+ pb_source_sel->setEnabled( false );
+ }
+#endif
+ }
+ else
+ {
+ kdDebug(29000) << "only one scan-source, do not show button." << endl;
+ }
+ }
+
+ /* Halftoning */
+ if( sane_device->optionExists( SANE_NAME_HALFTONE ) )
+ {
+ so = sane_device->getGuiElement( SANE_NAME_HALFTONE, pbox,
+ SANE_TITLE_HALFTONE,
+ SANE_DESC_HALFTONE );
+ if( so )
+ {
+ initialise(so);
+ connect( so, SIGNAL(guiChange(KScanOption*)),
+ this, SLOT(slReloadAllGui( KScanOption* )));
+ }
+ }
+
+ if( sane_device->optionExists( SANE_NAME_HALFTONE_DIMENSION) )
+ {
+ kdDebug(29000) << "Halftone-Dimen exists" << endl;
+ so = sane_device->getGuiElement( SANE_NAME_HALFTONE_DIMENSION, pbox,
+ SANE_TITLE_HALFTONE_DIMENSION,
+ SANE_DESC_HALFTONE_DIMENSION );
+ if( so )
+ {
+ initialise(so);
+ connect( so, SIGNAL(guiChange(KScanOption*)),
+ this, SLOT(slReloadAllGui( KScanOption* )));
+ }
+ }
+
+ if( sane_device->optionExists( SANE_NAME_HALFTONE_PATTERN) )
+ {
+ kdDebug(29000) << "Halftone-Pattern exists" << endl;
+ so = sane_device->getGuiElement( SANE_NAME_HALFTONE_PATTERN, pbox,
+ SANE_TITLE_HALFTONE_PATTERN,
+ SANE_DESC_HALFTONE_PATTERN );
+ if( so )
+ {
+ initialise(so);
+ connect( so, SIGNAL(guiChange(KScanOption*)),
+ this, SLOT(slReloadAllGui( KScanOption* )));
+ }
+ }
+
+
+ /* Resolution Setting -> X-Resolution Setting */
+ so = sane_device->getGuiElement( SANE_NAME_SCAN_X_RESOLUTION, pbox /* this */,
+ i18n("Resolution"),
+ SANE_DESC_SCAN_X_RESOLUTION );
+
+ if ( so )
+ {
+ initialise( so );
+ int x_y_res;
+ so->get( &x_y_res );
+ so->slRedrawWidget( so );
+
+ /* connect to slot that passes the resolution to the previewer */
+ connect( so, SIGNAL(guiChange(KScanOption*)),
+ this, SLOT( slNewXResolution(KScanOption*)));
+
+ connect( so, SIGNAL(guiChange(KScanOption*)),
+ this, SLOT(slReloadAllGui( KScanOption* )));
+
+ xy_resolution_bind =
+ sane_device->getGuiElement(SANE_NAME_RESOLUTION_BIND, pbox,
+ SANE_TITLE_RESOLUTION_BIND,
+ SANE_DESC_RESOLUTION_BIND );
+ if( xy_resolution_bind )
+ {
+ initialise( xy_resolution_bind );
+ xy_resolution_bind->slRedrawWidget( xy_resolution_bind );
+ /* Connect to Gui-change-Slot */
+ connect( xy_resolution_bind, SIGNAL(guiChange(KScanOption*)),
+ this, SLOT(slReloadAllGui( KScanOption* )));
+ }
+
+ /* Resolution Setting -> Y-Resolution Setting */
+ so = sane_device->getGuiElement( SANE_NAME_SCAN_Y_RESOLUTION, pbox,
+ SANE_TITLE_SCAN_Y_RESOLUTION,
+ SANE_DESC_SCAN_Y_RESOLUTION );
+ int y_res = x_y_res;
+ if ( so )
+ {
+ initialise( so );
+ if( so->active() )
+ so->get( &y_res );
+ so->slRedrawWidget( so );
+ }
+
+ emit( scanResolutionChanged( x_y_res, y_res ));
+ }
+ else
+ {
+ /* If the SCAN_X_RES does not exists, perhaps just SCAN_RES does */
+ so = sane_device->getGuiElement( SANE_NAME_SCAN_RESOLUTION, pbox,
+ SANE_TITLE_SCAN_Y_RESOLUTION,
+ SANE_DESC_SCAN_X_RESOLUTION );
+ if( so )
+ {
+ initialise( so );
+ }
+ else
+ {
+ kdDebug(29000) << "SERIOUS: No Resolution setting possible !" << endl;
+ }
+ }
+
+ /* Insert another beautification line */
+ (void) new KSeparator( KSeparator::HLine, pbox );
+
+ /* Speed-Setting - show only if active */
+ if( sane_device->optionExists( SANE_NAME_SCAN_SPEED ))
+ {
+ KScanOption kso_speed( SANE_NAME_SCAN_SPEED );
+ if( kso_speed.valid() && kso_speed.softwareSetable() && kso_speed.active())
+ {
+ so = sane_device->getGuiElement( SANE_NAME_SCAN_SPEED, pbox,
+ SANE_TITLE_SCAN_SPEED,
+ SANE_DESC_SCAN_SPEED );
+ initialise( so );
+ }
+ }
+
+ /* Threshold-Setting */
+ so = sane_device->getGuiElement( SANE_NAME_THRESHOLD, pbox,
+ SANE_TITLE_THRESHOLD,
+ SANE_DESC_THRESHOLD);
+ if( so )
+ {
+ initialise( so );
+ }
+
+ /* Brightness-Setting */
+ so = sane_device->getGuiElement( SANE_NAME_BRIGHTNESS, pbox,
+ SANE_TITLE_BRIGHTNESS,
+ SANE_DESC_BRIGHTNESS);
+ if( so ) initialise( so );
+
+ /* Contrast-Setting */
+ so = sane_device->getGuiElement( SANE_NAME_CONTRAST, pbox,
+ SANE_TITLE_CONTRAST,
+ SANE_DESC_CONTRAST );
+ if( so ) initialise( so );
+ /* Custom Gamma */
+
+ /* Sharpness */
+ so = sane_device->getGuiElement( "sharpness", pbox );
+ if( so ) initialise( so );
+
+
+ /* The gamma table can be used - add a button for editing */
+ QHBox *hb1 = new QHBox(pbox);
+
+ if( sane_device->optionExists( SANE_NAME_CUSTOM_GAMMA ) )
+ {
+ so = sane_device->getGuiElement( SANE_NAME_CUSTOM_GAMMA, hb1,
+ SANE_TITLE_CUSTOM_GAMMA,
+ SANE_DESC_CUSTOM_GAMMA );
+ initialise( so );
+ connect( so, SIGNAL(guiChange(KScanOption*)),
+ this, SLOT(slReloadAllGui( KScanOption* )));
+ }
+ else
+ {
+ (void) new QLabel( i18n("Custom Gamma Table"), hb1 );
+ }
+
+ /* Connect a signal to refresh activity of the gamma tables */
+ (void) new QWidget( hb1 ); /* dummy widget to eat space */
+
+ pb_edit_gtable = new QPushButton( i18n("Edit..."), hb1 );
+ Q_CHECK_PTR(pb_edit_gtable);
+
+ connect( pb_edit_gtable, SIGNAL( clicked () ),
+ this, SLOT( slEditCustGamma () ) );
+ setEditCustomGammaTableState();
+
+ /* This connection cares for enabling/disabling the edit-Button */
+ if(so )
+ connect( so, SIGNAL(guiChange(KScanOption*)),
+ this, SLOT(slOptionNotify(KScanOption*)));
+
+ /* my Epson Perfection backends offer a list of user defined gamma values */
+
+ /* Insert another beautification line */
+ if( sane_device->optionExists( SANE_NAME_GRAY_PREVIEW ) ||
+ sane_device->optionExists( SANE_NAME_NEGATIVE ) )
+ {
+ (void) new KSeparator( KSeparator::HLine, pbox );
+ }
+
+ so = sane_device->getGuiElement( SANE_NAME_NEGATIVE, pbox,
+ SANE_TITLE_NEGATIVE,
+ SANE_DESC_NEGATIVE );
+ initialise( so );
+
+ /* PREVIEW-Switch */
+ kdDebug(29000) << "Try to get Gray-Preview" << endl;
+ if( sane_device->optionExists( SANE_NAME_GRAY_PREVIEW ))
+ {
+ so = sane_device->getGuiElement( SANE_NAME_GRAY_PREVIEW, pbox,
+ SANE_TITLE_GRAY_PREVIEW,
+ SANE_DESC_GRAY_PREVIEW );
+ initialise( so );
+ cb_gray_preview = (QCheckBox*) so->widget();
+ QToolTip::add( cb_gray_preview, i18n("Acquire a gray preview even in color mode (faster)") );
+ }
+
+ QWidget *spacer = new QWidget( pbox );
+ spacer->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Expanding);
+
+ pbox->setMinimumWidth( pbox->sizeHint().width() );
+ sv->setMinimumWidth( pbox->minimumWidth() );
+ sv->addChild( pbox );
+
+ return( sv );
+}
+
+
+void ScanParams::createNoScannerMsg( void )
+{
+ /* Mode setting */
+ QString cap;
+ cap = i18n( "<B>Problem: No Scanner was found</B><P>Your system does not provide a SANE <I>(Scanner Access Now Easy)</I> installation, which is required by the KDE scan support.<P>Please install and configure SANE correctly on your system.<P>Visit the SANE homepage under http://www.sane-project.org to find out more about SANE installation and configuration. " );
+
+ (void) new QLabel( cap, this );
+
+}
+
+/* This slot will be called if something changes with the option given as a param.
+ * This is useful if the parameter - Gui has widgets in his own space, which depend
+ * on widget controlled by the KScanOption.
+ */
+void ScanParams::slOptionNotify( KScanOption *kso )
+{
+ if( !kso || !kso->valid()) return;
+ setEditCustomGammaTableState ();
+}
+
+
+void ScanParams::slSourceSelect( void )
+{
+ kdDebug(29000) << "Open Window for source selection !" << endl;
+ KScanOption so( SANE_NAME_SCAN_SOURCE );
+ ADF_BEHAVE adf = ADF_OFF;
+
+ const QCString& currSource = so.get();
+ kdDebug(29000) << "Current Source is <" << currSource << ">" << endl;
+ QStrList sources;
+
+ if( so.valid() )
+ {
+ sources = so.getList();
+#undef CHEAT_FOR_DEBUGGING
+#ifdef CHEAT_FOR_DEBUGGING
+ if( sources.find( "Automatic Document Feeder" ) == -1)
+ sources.append( "Automatic Document Feeder" );
+#endif
+
+ ScanSourceDialog d( this, sources, adf );
+ d.slSetSource( currSource );
+
+ if( d.exec() == QDialog::Accepted )
+ {
+ QString sel_source = d.getText();
+ adf = d.getAdfBehave();
+
+ /* set the selected Document source, the behavior is stored in a membervar */
+ so.set( QCString(sel_source.latin1()) ); // FIX in ScanSourceDialog, then here
+ sane_device->apply( &so );
+
+ kdDebug(29000) << "Dialog finished OK: " << sel_source << ", " << adf << endl;
+
+ }
+ }
+}
+
+/** slFileSelect
+ * this slot allows to select a file or directory for virtuell Scanning.
+ * If a dir is selected, the virt. Scanner crawls for all readable
+ * images, if a single file is selected, the virt Scanner just reads
+ * one file.
+ * If SANE Debug Mode is selected, only pnm can be loaded.
+ * on Qt mode, all available Qt-Formats are ok.
+ */
+void ScanParams::slFileSelect( void )
+{
+ kdDebug(29000) << "File Selector" << endl;
+ QString filter;
+ QCString prefix = "\n*.";
+
+ if( scan_mode == ID_QT_IMGIO )
+ {
+ QStrList filterList = QImage::inputFormats();
+ filter = i18n( "*|All Files (*)");
+ for( QCString fi_item = filterList.first(); !fi_item.isEmpty();
+ fi_item = filterList.next() )
+ {
+
+ filter.append( QString::fromLatin1( prefix + fi_item.lower()) );
+ }
+ }
+ else
+ {
+ filter.append( i18n( "*.pnm|PNM Image Files (*.pnm)") );
+ }
+
+
+
+ KFileDialog fd(last_virt_scan_path.path(), filter, this, "FileDialog",true);
+ fd.setCaption( i18n("Select Input File") );
+ /* Read the filename and remind it */
+ QString fileName;
+ if ( fd.exec() == QDialog::Accepted ) {
+ fileName = fd.selectedFile();
+ QFileInfo ppath( fileName );
+ last_virt_scan_path = QDir(ppath.dirPath(true));
+ } else {
+ return;
+ }
+
+ if ( !fileName.isNull() && virt_filename ) { // got a file name
+ kdDebug(29000) << "Got fileName: " << fileName << endl;
+ // write Value to SANEOption, it updates itself.
+ virt_filename->set( QFile::encodeName( fileName ) );
+ }
+}
+
+/** Slot which is called if the user switches in the gui between
+ * the SANE-Debug-Mode and the qt image reading
+ */
+void ScanParams::slVirtScanModeSelect( int id )
+{
+ if( id == 0 ) {
+ scan_mode = ID_SANE_DEBUG; /* , ID_QT_IMGIO */
+ sane_device->guiSetEnabled( "three-pass", true );
+ sane_device->guiSetEnabled( "grayify", true );
+ sane_device->guiSetEnabled( SANE_NAME_CONTRAST, true );
+ sane_device->guiSetEnabled( SANE_NAME_BRIGHTNESS, true );
+
+ /* Check if the entered filename to delete */
+ if( virt_filename ) {
+ QString vf = virt_filename->get();
+ kdDebug(29000) << "Found File in Filename-Option: " << vf << endl;
+
+ QFileInfo fi( vf );
+ if( fi.extension() != QString::fromLatin1("pnm") )
+ virt_filename->set(QCString(""));
+ }
+ } else {
+ scan_mode = ID_QT_IMGIO;
+ sane_device->guiSetEnabled( "three-pass", false );
+ sane_device->guiSetEnabled( "grayify", false );
+ sane_device->guiSetEnabled( SANE_NAME_CONTRAST, false );
+ sane_device->guiSetEnabled( SANE_NAME_BRIGHTNESS, false );
+ }
+}
+
+
+/**
+ * virtualScannerParams builds the GUI for the virtual scanner,
+ * which allows the user to read images from the harddisk.
+ */
+void ScanParams::virtualScannerParams( void )
+{
+#if 0
+ KScanOption *so = 0;
+ QWidget *w = 0;
+
+ /* Selection if virt. Scanner or SANE Debug */
+ bg_virt_scan_mode = new QButtonGroup( 2, Qt::Horizontal,
+ this, "GroupBoxVirtScanner" );
+ connect( bg_virt_scan_mode, SIGNAL(clicked(int)),
+ this, SLOT( slVirtScanModeSelect(int)));
+
+ QRadioButton *rb1 = new QRadioButton( i18n("SANE debug (pnm only)"),
+ bg_virt_scan_mode, "VirtScanSANEDebug" );
+
+
+
+ QRadioButton *rb2 = new QRadioButton( i18n("virt. Scan (all Qt modes)"),
+ bg_virt_scan_mode, "VirtScanQtModes" );
+
+ rb1->setChecked( true );
+ rb2->setChecked( false );
+
+ if( scan_mode == ID_QT_IMGIO )
+ {
+ rb2->setChecked( true );
+ rb1->setChecked( false );
+ }
+
+ top->addWidget( bg_virt_scan_mode, 1 );
+
+ /* GUI-Element Filename */
+ virt_filename = sane_device->getGuiElement( SANE_NAME_FILE, this,
+ SANE_TITLE_FILE,
+ SANE_DESC_FILE );
+ if( virt_filename )
+ {
+ QHBoxLayout *hb = new QHBoxLayout();
+ top->addLayout( hb );
+ w = virt_filename->widget();
+ w->setMinimumHeight( (w->sizeHint()).height());
+ connect( w, SIGNAL(returnPressed()), this,
+ SLOT( slCheckGlob()));
+
+ hb->addWidget( w, 12 );
+
+ QPushButton *pb_file_sel = new QPushButton( this );
+ pb_file_sel->setPixmap(miniFloppyPixmap);
+ //hb->addStretch( 1 );
+ hb->addWidget( pb_file_sel, 1 );
+ connect( pb_file_sel, SIGNAL(clicked()), this, SLOT(slFileSelect()));
+
+ }
+
+ /* GUI-Element Brightness */
+ so = sane_device->getGuiElement( SANE_NAME_BRIGHTNESS, this,
+ SANE_TITLE_BRIGHTNESS,
+ SANE_DESC_BRIGHTNESS );
+ if( so )
+ {
+ top->addWidget( so->widget(), 1 );
+ so->set( 0 );
+ sane_device->apply( so );
+ }
+
+ /* GUI-Element Contrast */
+ so = sane_device->getGuiElement( SANE_NAME_CONTRAST, this,
+ SANE_TITLE_CONTRAST,
+ SANE_DESC_CONTRAST );
+ if ( so )
+ {
+ top->addWidget( so->widget(), 1 );
+ so->set( 0 );
+ sane_device->apply( so );
+ }
+
+
+ /* GUI-Element grayify on startup */
+ so = sane_device->getGuiElement( "grayify", this, i18n("convert the image to gray on loading"), 0 );
+ if ( so )
+ {
+ top->addWidget( so->widget(), 1 );
+ so->set( true );
+ sane_device->apply( so );
+ }
+
+ /* GUI-Element three pass simulation */
+ so = sane_device->getGuiElement( "three-pass", this, i18n("Simulate three-pass acquiring"), 0 );
+ if ( so )
+ {
+ top->addWidget( so->widget(), 1 );
+ so->set( false );
+ sane_device->apply( so );
+ }
+#endif
+}
+
+/* This slot is called if the user changes the
+void ScanParams::slCheckGlob( void )
+{
+
+}
+*/
+/* Slot called to start scanning */
+void ScanParams::slStartScan( void )
+{
+ KScanStat stat = KSCAN_OK;
+
+ kdDebug(29000) << "Called start-scan-Slot!" << endl;
+ QString q;
+
+ if( scan_mode == ID_SANE_DEBUG || scan_mode == ID_QT_IMGIO )
+ {
+ if( virt_filename )
+ q = virt_filename->get();
+ if( q.isEmpty() )
+ {
+ QMessageBox::information( this, i18n("KSANE"),
+ i18n("The filename for virtual scanning is not set.\n"
+ "Please set the filename first.") );
+ stat = KSCAN_ERR_PARAM;
+ }
+ }
+ /* if it is a virt Scanner in SANE Debug or real scanning is on */
+ if( stat == KSCAN_OK )
+ {
+ if( (scan_mode == ID_SANE_DEBUG || scan_mode == ID_SCAN) )
+ {
+ if( adf == ADF_OFF )
+ {
+ /* Progress-Dialog */
+ progressDialog->setProgress(0);
+ if( progressDialog->isHidden())
+ progressDialog->show();
+ kdDebug(29000) << "* slStartScan: Start to acquire an image!" << endl;
+ stat = sane_device->acquire( );
+
+ } else {
+ kdDebug(29000) << "Not yet implemented :-/" << endl;
+
+ // stat = performADFScan();
+ }
+ } else {
+ kdDebug(29000) << "Reading dir by Qt-internal imagereading file " << q << endl;
+ sane_device->acquire( q );
+ }
+ }
+}
+
+/* Slot called to start the Custom Gamma Table Edit dialog */
+
+void ScanParams::slEditCustGamma( void )
+{
+ kdDebug(29000) << "Called EditCustGamma ;)" << endl;
+ KGammaTable old_gt;
+
+
+ /* Since gammatable options are not set in the default gui, it must be
+ * checked if it is the first edit. If it is, take from loaded default
+ * set if available there */
+ if( m_firstGTEdit && startupOptset )
+ {
+ m_firstGTEdit = false;
+ KScanOption *gt = startupOptset->get(SANE_NAME_GAMMA_VECTOR);
+ if( !gt )
+ {
+ /* If it not gray, it should be one color. */
+ gt = startupOptset->get( SANE_NAME_GAMMA_VECTOR_R );
+ }
+
+ if( gt )
+ gt->get( &old_gt );
+ }
+ else
+ {
+ /* it is not the first edit, use older values */
+ if( sane_device->optionExists( SANE_NAME_GAMMA_VECTOR ) )
+ {
+ KScanOption grayGt( SANE_NAME_GAMMA_VECTOR );
+ /* This will be fine for all color gt's. */
+ grayGt.get( &old_gt );
+ kdDebug(29000) << "Gray Gamma Table is active " << endl;
+ }
+ else
+ {
+ /* Gray is not active, but at the current implementation without
+ * red/green/blue gammatables, but one for all, all gammatables
+ * are equally. So taking the red one should be fine. TODO
+ */
+ if( sane_device->optionExists( SANE_NAME_GAMMA_VECTOR_R ))
+ {
+ KScanOption redGt( SANE_NAME_GAMMA_VECTOR_R );
+ redGt.get( &old_gt );
+ kdDebug(29000) << "Getting old gamma table from Red channel" << endl;
+ }
+ else
+ {
+ /* uh ! No current gammatable could be retrieved. Use the 100/0/0 gt
+ * created by KGammaTable's constructor. Nothing to do for that.
+ */
+ kdDebug(29000) << "WRN: Could not retrieve a gamma table" << endl;
+ }
+ }
+ }
+
+ kdDebug(29000) << "Old gamma table: " << old_gt.getGamma() << ", " << old_gt.getBrightness() << ", " << old_gt.getContrast() << endl;
+
+ GammaDialog gdiag( this );
+ connect( &gdiag, SIGNAL( gammaToApply(KGammaTable*) ),
+ this, SLOT( slApplyGamma(KGammaTable*) ) );
+
+ gdiag.setGt( old_gt );
+
+ if( gdiag.exec() == QDialog::Accepted )
+ {
+ slApplyGamma( gdiag.getGt() );
+ kdDebug(29000) << "Fine, applied new Gamma Table !" << endl;
+ }
+ else
+ {
+ /* reset to old values */
+ slApplyGamma( &old_gt );
+ kdDebug(29000) << "Cancel, reverted to old Gamma Table !" << endl;
+ }
+
+}
+
+
+void ScanParams::slApplyGamma( KGammaTable* gt )
+{
+ if( ! gt ) return;
+
+ kdDebug(29000) << "Applying gamma table: " << gt->getGamma() <<
+ ", " << gt->getBrightness() << ", " << gt->getContrast() << endl;
+
+
+ if( sane_device->optionExists( SANE_NAME_GAMMA_VECTOR ) )
+ {
+ KScanOption grayGt( SANE_NAME_GAMMA_VECTOR );
+
+ /* Now find out, which gamma-Tables are active. */
+ if( grayGt.active() )
+ {
+ grayGt.set( gt );
+ sane_device->apply( &grayGt, true );
+ }
+ }
+
+ if( sane_device->optionExists( SANE_NAME_GAMMA_VECTOR_R )) {
+ KScanOption rGt( SANE_NAME_GAMMA_VECTOR_R );
+ if( rGt.active() )
+ {
+ rGt.set( gt );
+ sane_device->apply( &rGt, true );
+ }
+ }
+
+ if( sane_device->optionExists( SANE_NAME_GAMMA_VECTOR_G )) {
+ KScanOption gGt( SANE_NAME_GAMMA_VECTOR_G );
+ if( gGt.active() )
+ {
+ gGt.set( gt );
+ sane_device->apply( &gGt, true );
+ }
+ }
+
+ if( sane_device->optionExists( SANE_NAME_GAMMA_VECTOR_B )) {
+ KScanOption bGt( SANE_NAME_GAMMA_VECTOR_B );
+ if( bGt.active() )
+ {
+ bGt.set( gt );
+ sane_device->apply( &bGt, true );
+ }
+ }
+}
+
+/* Slot calls if a widget changes. Things to do:
+ * - Apply the option and reload all if the option affects all
+ */
+
+void ScanParams::slReloadAllGui( KScanOption* t)
+{
+ if( !t || ! sane_device ) return;
+ kdDebug(29000) << "This is slReloadAllGui for widget <" << t->getName() << ">" << endl;
+ /* Need to reload all _except_ the one which was actually changed */
+
+ sane_device->slReloadAllBut( t );
+
+ /* Custom Gamma <- What happens if that does not exist for some scanner ? TODO */
+ setEditCustomGammaTableState();
+}
+
+/*
+ * enable editing of the gamma tables if one of the gamma tables
+ * exists and is active at the moment
+ */
+void ScanParams::setEditCustomGammaTableState()
+{
+ if( !(sane_device && pb_edit_gtable) )
+ return;
+
+ bool butState = false;
+ kdDebug(29000) << "Checking state of edit custom gamma button !" << endl;
+
+ if( sane_device->optionExists( SANE_NAME_CUSTOM_GAMMA ) )
+ {
+ KScanOption kso( SANE_NAME_CUSTOM_GAMMA );
+ butState = kso.active();
+ // kdDebug(29000) << "CustomGamma is active: " << butState << endl;
+ }
+
+ if( !butState && sane_device->optionExists( SANE_NAME_GAMMA_VECTOR_R ) )
+ {
+ KScanOption kso( SANE_NAME_GAMMA_VECTOR_R );
+ butState = kso.active();
+ // kdDebug(29000) << "CustomGamma Red is active: " << butState << endl;
+ }
+
+ if( !butState && sane_device->optionExists( SANE_NAME_GAMMA_VECTOR_G ) )
+ {
+ KScanOption kso( SANE_NAME_GAMMA_VECTOR_G );
+ butState = kso.active();
+ // kdDebug(29000) << "CustomGamma Green is active: " << butState << endl;
+ }
+
+ if( !butState && sane_device->optionExists( SANE_NAME_GAMMA_VECTOR_B ) )
+ {
+ KScanOption kso( SANE_NAME_GAMMA_VECTOR_B );
+ butState = kso.active();
+ // kdDebug(29000) << "CustomGamma blue is active: " << butState << endl;
+ }
+ pb_edit_gtable->setEnabled( butState );
+}
+
+
+/* Slot called to start acquirering a preview */
+void ScanParams::slAcquirePreview( void )
+{
+ kdDebug(29000) << "Called acquirePreview-Slot!" << endl;
+ bool gray_preview = false;
+ if( cb_gray_preview )
+ gray_preview = cb_gray_preview->isChecked();
+
+
+ /* Maximal preview size */
+ slMaximalScanSize();
+
+ if( ! sane_device ) kdDebug(29000) << "Aeetsch: sane_device is 0 !" << endl;
+ Q_CHECK_PTR( sane_device );
+ KScanStat stat = sane_device->acquirePreview( gray_preview );
+
+ if( stat != KSCAN_OK )
+ {
+ kdDebug(29000) << "Error in scanning !" << endl;
+ }
+}
+
+/* Custom Scan size setting.
+ * The custom scan size is given in the QRect parameter. It must contain values
+ * from 0..1000 which are interpreted as tenth of percent of the overall dimension.
+ */
+void ScanParams::slCustomScanSize( QRect sel)
+{
+ kdDebug(29000) << "Custom-Size: " << sel.x() << ", " << sel.y() << " - " << sel.width() << "x" << sel.height() << endl;
+
+ KScanOption tl_x( SANE_NAME_SCAN_TL_X );
+ KScanOption tl_y( SANE_NAME_SCAN_TL_Y );
+ KScanOption br_x( SANE_NAME_SCAN_BR_X );
+ KScanOption br_y( SANE_NAME_SCAN_BR_Y );
+
+ double min1=0.0, max1=0.0, min2=0.0, max2=0.0, dummy1=0.0, dummy2=0.0;
+ tl_x.getRange( &min1, &max1, &dummy1 );
+ br_x.getRange( &min2, &max2, &dummy2 );
+
+ /* overall width */
+ double range = max2-min1;
+ double w = min1 + double(range * (double(sel.x()) / 1000.0) );
+ tl_x.set( w );
+ w = min1 + double(range * double(sel.x() + sel.width())/1000.0);
+ br_x.set( w );
+
+
+ kdDebug(29000) << "set tl_x: " << min1 + double(range * (double(sel.x()) / 1000.0) ) << endl;
+ kdDebug(29000) << "set br_x: " << min1 + double(range * (double(sel.x() + sel.width())/1000.0)) << endl;
+
+ /** Y-Value setting */
+ tl_y.getRange( &min1, &max1, &dummy1 );
+ br_y.getRange(&min2, &max2, &dummy2 );
+
+ /* overall width */
+ range = max2-min1;
+ w = min1 + range * double(sel.y()) / 1000.0;
+ tl_y.set( w );
+ w = min1 + range * double(sel.y() + sel.height())/1000.0;
+ br_y.set( w );
+
+
+ kdDebug(29000) << "set tl_y: " << min1 + double(range * (double(sel.y()) / 1000.0) ) << endl;
+ kdDebug(29000) << "set br_y: " << min1 + double(range * (double(sel.y() + sel.height())/1000.0)) << endl;
+
+
+ sane_device->apply( &tl_x );
+ sane_device->apply( &tl_y );
+ sane_device->apply( &br_x );
+ sane_device->apply( &br_y );
+}
+
+
+/**
+ * sets the scan area to the default, which is the whole area.
+ */
+void ScanParams::slMaximalScanSize( void )
+{
+ kdDebug(29000) << "Setting to default" << endl;
+ slCustomScanSize(QRect( 0,0,1000,1000));
+}
+
+
+void ScanParams::slNewXResolution(KScanOption *opt)
+{
+ if(! opt ) return;
+
+ kdDebug(29000) << "Got new X-Resolution !" << endl;
+
+ int x_res = 0;
+ opt->get( &x_res );
+
+ int y_res = x_res;
+
+ if( xy_resolution_bind && xy_resolution_bind->active() )
+ {
+ /* That means, that x and y may be different */
+ KScanOption opt_y( SANE_NAME_SCAN_Y_RESOLUTION );
+ if( opt_y.valid () )
+ {
+ opt_y.get( &y_res );
+ }
+ }
+
+ emit( scanResolutionChanged( x_res, y_res ) );
+}
+
+void ScanParams::slNewYResolution(KScanOption *opt)
+{
+ if( ! opt ) return;
+
+ int y_res = 0;
+ opt->get( &y_res );
+
+ int x_res = y_res;
+
+ if( xy_resolution_bind && xy_resolution_bind->active())
+ {
+ /* That means, that x and y may be different */
+ KScanOption opt_x( SANE_NAME_SCAN_X_RESOLUTION );
+ if( opt_x.valid () )
+ {
+ opt_x.get( &x_res );
+ }
+ }
+
+ emit( scanResolutionChanged( x_res, y_res ) );
+
+}
+
+
+KScanStat ScanParams::performADFScan( void )
+{
+ KScanStat stat = KSCAN_OK;
+ bool scan_on = true;
+
+ MassScanDialog *msd = new MassScanDialog( this );
+ msd->show();
+
+ /* The scan source should be set to ADF by the SourceSelect-Dialog */
+
+ while( scan_on )
+ {
+ scan_on = false;
+ }
+ return( stat );
+}
+#include "scanparams.moc"
diff --git a/libkscan/scanparams.h b/libkscan/scanparams.h
new file mode 100644
index 00000000..c80e1ce6
--- /dev/null
+++ b/libkscan/scanparams.h
@@ -0,0 +1,182 @@
+/* This file is part of the KDE Project
+ Copyright (C) 1999 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SCANPARAMS_H
+#define SCANPARAMS_H
+
+#include "kscandevice.h"
+#include "scansourcedialog.h"
+
+#include <qvbox.h>
+#include <qhbox.h>
+
+#include <qdir.h>
+#include <qpixmap.h>
+
+/**
+ *@author Klaas Freitag
+ */
+
+class GammaDialog;
+class KScanOptSet;
+class QScrollView;
+class KLed;
+class QProgressDialog;
+class QPushButton;
+class QCheckBox;
+class QButtonGroup;
+
+typedef enum { ID_SANE_DEBUG, ID_QT_IMGIO, ID_SCAN } ScanMode;
+
+class ScanParams : public QVBox
+{
+ Q_OBJECT
+public:
+ ScanParams( QWidget *parent, const char *name = 0);
+ ~ScanParams();
+#if 0
+ QSize sizeHint( );
+#endif
+ bool connectDevice( KScanDevice* );
+
+ KLed *operationLED() { return m_led; }
+
+public slots:
+/**
+ * In this slot, a custom scan window can be set, e.g. through a preview
+ * image with a area selector. The QRect-param needs to contain values
+ * between 0 and 1000, which are interpreted as tenth of percent of the
+ * whole image dimensions.
+ **/
+void slCustomScanSize( QRect );
+
+ /**
+ * sets the scan area to the default, which is the whole area.
+ */
+ void slMaximalScanSize( void );
+
+ /**
+ * starts acquireing a preview image.
+ * This ends up in a preview-signal of the scan-device object
+ */
+ void slAcquirePreview( void );
+ void slStartScan( void );
+
+ /**
+ * connect this slot to KScanOptions Signal optionChanged to be informed
+ * on a options change.
+ */
+ void slOptionNotify( KScanOption *kso );
+
+protected slots:
+/**
+ * connected to the button which opens the source selection dialog
+ */
+void slSourceSelect( void );
+ /**
+ * allows to select a file or directory for the virtuell scanner
+ */
+ void slFileSelect ( void );
+
+ /**
+ * Slot to call if the virtual scanner mode is changed
+ */
+ void slVirtScanModeSelect( int id );
+
+ /**
+ * Slot for result on an edit-Custom Gamma Table request.
+ * Starts a dialog.
+ */
+ void slEditCustGamma( void );
+
+ /**
+ * Slot called if a Gui-Option changed due to user action, eg. the
+ * user selects another entry in a List.
+ * Action to do is to apply the new value and check, if it affects others.
+ */
+ void slReloadAllGui( KScanOption* );
+
+ /**
+ * Slot called when the Edit Custom Gamma-Dialog has a new gamma table
+ * to apply. This is an internal slot.
+ */
+ void slApplyGamma( KGammaTable* );
+
+ /**
+ * internal slot called when the slider for x resolution changes.
+ * In the slot, the signal scanResolutionChanged will be emitted, which
+ * is visible outside the scanparam-object to notify that the resolutions
+ * changed.
+ *
+ * That is e.g. useful for size calculations
+ */
+ void slNewXResolution( KScanOption* );
+
+ /**
+ * the same slot as @see slNewXResolution but for y resolution changes.
+ */
+ void slNewYResolution( KScanOption* );
+
+
+ signals:
+
+ /**
+ * emitted if the resolution to scan changes. This signal may be connected
+ * to slots calculating the size of the image size etc.
+ *
+ * As parameters the resolutions in x- and y-direction are coming.
+ */
+ void scanResolutionChanged( int, int );
+
+private:
+
+
+ QScrollView* scannerParams( );
+ void virtualScannerParams( void );
+ void createNoScannerMsg( void );
+ void initialise( KScanOption* );
+ void setEditCustomGammaTableState();
+
+ KScanStat performADFScan( void );
+
+ KScanDevice *sane_device;
+ KScanOption *virt_filename;
+ QCheckBox *cb_gray_preview;
+ QPushButton *pb_edit_gtable;
+ QPushButton *pb_source_sel;
+ ADF_BEHAVE adf;
+ QButtonGroup *bg_virt_scan_mode;
+ ScanMode scan_mode;
+ QDir last_virt_scan_path;
+
+ KScanOption *xy_resolution_bind;
+
+ KScanOptSet *startupOptset;
+
+ QProgressDialog *progressDialog;
+
+ QPixmap pixLineArt, pixGray, pixColor, pixHalftone, pixMiniFloppy;
+ KLed *m_led;
+ bool m_firstGTEdit;
+
+ class ScanParamsPrivate;
+ ScanParamsPrivate *d;
+};
+
+#endif
diff --git a/libkscan/scanservice.desktop b/libkscan/scanservice.desktop
new file mode 100644
index 00000000..8330e0ae
--- /dev/null
+++ b/libkscan/scanservice.desktop
@@ -0,0 +1,70 @@
+[Desktop Entry]
+Type=Service
+Name=KDE Scan Service
+Name[af]=Kde Skandeer Diens
+Name[ar]=خدمة KDE للمسح الضوئي
+Name[az]=KDE Darama Servisi
+Name[bg]=Услуга за сканиране
+Name[br]=Damanterien skramm
+Name[ca]=Servei d'escaneig del KDE
+Name[cs]=Skenovací služba pro KDE
+Name[cy]=Gwasanaeth Sganio KDE
+Name[da]=KDE Skanneservice
+Name[de]=Scan-Dienst von KDE
+Name[el]=Υπηρεσία σάρωσης του KDE
+Name[eo]=Bildcifereciga servo (skano)
+Name[es]=Servicio de digitalización de KDE
+Name[et]=KDE skaneerimisteenus
+Name[eu]=KDE eskaneatze zerbitzua
+Name[fa]=خدمت پویش KDE
+Name[fi]=KDE :n skannauspalvelu
+Name[fr]=Service de numérisation pour KDE
+Name[gl]=Servicio de escáner de KDE
+Name[he]=שירות הסריקה של KDE
+Name[hi]=केडीई स्कैन सर्विस
+Name[hr]=KDE skan servis
+Name[hu]=KDE lapolvasó szolgáltatás
+Name[is]=KDE myndlesaraþjónusta
+Name[it]=Servizio di scansione di KDE
+Name[ja]=KDE スキャンサービス
+Name[kk]=KDE сканер қызметі
+Name[km]=សេវា​ស្កេន​របស់ KDE
+Name[ko]=KDE 스캔 서비스
+Name[lt]=KDE skanavimo tarnyba
+Name[lv]=KDE Skanēšanas Serviss
+Name[ms]=Perkhidmatan Imbas KDE
+Name[mt]=Servizz KDE tal-iskannjar
+Name[nb]=KDE skannetjeneste
+Name[nds]=Bildinleesdeenst för KDE
+Name[ne]=केडीई स्क्यान सेवा
+Name[nl]=KDE Scannerdiensten
+Name[nn]=KDE Skanningsteneste
+Name[nso]=Tirelo ya Tebelelo ya KDE
+Name[pl]=Usługa skanowania KDE
+Name[pt]=Serviço de 'Scanner' do KDE
+Name[pt_BR]=Serviço de Digitalização do KDE
+Name[ro]=Serviciu de scanare KDE
+Name[ru]=Служба сканирования KDE
+Name[se]=KDE skánnenbálválus
+Name[sk]=KDE skenovacia služba
+Name[sl]=Storitev skeniranja za KDE
+Name[sr]=KDE-ов сервис за скенирање
+Name[sr@Latn]=KDE-ov servis za skeniranje
+Name[sv]=KDE:s bildläsartjänst
+Name[ta]=கேடிஇ வருடு சேவை
+Name[tg]=Сканеронӣ дар KDE
+Name[th]=บริการสแกนภาพ - K
+Name[tr]=KDE Tarama Servisi
+Name[uk]=Служба пошуку KDE
+Name[uz]=KDE skan qilish xizmati
+Name[uz@cyrillic]=KDE скан қилиш хизмати
+Name[ven]=Tshishumiswa tshau naga tsha KDE
+Name[wa]=Siervice di scanaedje di KDE
+Name[xh]=Inkonzo yemita yovavanyo ye KDE
+Name[zh_CN]=KDE 扫描服务
+Name[zh_HK]=KDE 掃描服務
+Name[zh_TW]=KDE 掃描服務
+Name[zu]=Umsebenzi Lokuhlola lwe-KDE
+X-KDE-Library=libkscan
+InitialPreference=2
+ServiceTypes=KScan/KScanDialog
diff --git a/libkscan/scansourcedialog.cpp b/libkscan/scansourcedialog.cpp
new file mode 100644
index 00000000..01d71dc1
--- /dev/null
+++ b/libkscan/scansourcedialog.cpp
@@ -0,0 +1,211 @@
+/* This file is part of the KDE Project
+ Copyright (C) 2000 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "scansourcedialog.h"
+#include "kscanslider.h"
+
+#include <klocale.h>
+#include <kdebug.h>
+
+#include <qlabel.h>
+#include <qpushbutton.h>
+#include <qlayout.h>
+#include <qvbox.h>
+#include <qhbox.h>
+#include <qradiobutton.h>
+#include <qslider.h>
+#include <qlineedit.h>
+#include <qcombobox.h>
+
+#include <qvbuttongroup.h>
+#include <qbuttongroup.h>
+
+
+extern "C"{
+#include <sane/saneopts.h>
+}
+#ifndef SANE_NAME_DOCUMENT_FEEDER
+#define SANE_NAME_DOCUMENT_FEEDER "Automatic Document Feeder"
+#endif
+
+
+ScanSourceDialog::ScanSourceDialog( QWidget *parent, const QStrList list, ADF_BEHAVE adfBehave )
+ : KDialogBase( parent, "SOURCE_DIALOG", true, i18n("Scan Source Selection"),
+ Ok|Cancel,Ok, true)
+{
+ QVBox *vbox = makeVBoxMainWidget();
+
+ (void) new QLabel( i18n("<B>Source selection</B><P>"
+ "Note that you may see more sources than actually exist"), vbox );
+
+ /* Combo Box for sources */
+ const QStrList xx = list;
+ sources = new KScanCombo( vbox,
+ i18n("Select the Scanner document source:"),
+ xx);
+ connect( sources, SIGNAL( activated(int)), this, SLOT( slChangeSource(int)));
+
+
+ /* Button Group for ADF-Behaviour */
+ bgroup = 0;
+ adf = ADF_OFF;
+
+ if( sourceAdfEntry() > -1 )
+ {
+ bgroup = new QVButtonGroup( i18n("Advanced ADF-Options"), vbox, "ADF_BGROUP" );
+
+ connect( bgroup, SIGNAL(clicked(int)), this, SLOT( slNotifyADF(int)));
+
+ /* Two buttons inside */
+ QRadioButton *rbADFTillEnd = new QRadioButton( i18n("Scan until ADF reports out of paper"),
+ bgroup );
+ bgroup->insert( rbADFTillEnd, ADF_SCAN_ALONG );
+
+ QRadioButton *rbADFOnce = new QRadioButton( i18n("Scan only one sheet of ADF per click"),
+ bgroup );
+ bgroup->insert( rbADFOnce, ADF_SCAN_ONCE );
+
+ switch ( adfBehave )
+ {
+ case ADF_OFF:
+ bgroup->setButton( ADF_SCAN_ONCE );
+ bgroup->setEnabled( false );
+ adf = ADF_OFF;
+ break;
+ case ADF_SCAN_ONCE:
+ bgroup->setButton( ADF_SCAN_ONCE );
+ adf = ADF_SCAN_ONCE;
+ break;
+ case ADF_SCAN_ALONG:
+ bgroup->setButton( ADF_SCAN_ALONG );
+ adf = ADF_SCAN_ALONG;
+ break;
+ default:
+ kdDebug(29000) << "Undefined Source !" << endl;
+ // Hmmm.
+ break;
+ }
+ }
+}
+
+QString ScanSourceDialog::getText( void ) const
+{
+ return( sources->currentText() );
+}
+
+void ScanSourceDialog::slNotifyADF( int )
+{
+ // debug( "reported adf-select %d", adf_group );
+ /* this seems to be broken, adf_text is a visible string?
+ * needs rework if SANE 2 comes up which supports i18n */
+#if 0
+ QString adf_text = getText();
+
+ adf = ADF_OFF;
+
+ if( adf_text == "Automatic Document Feeder" ||
+ adf_text == "ADF" )
+ {
+ if( adf_group == 0 )
+ adf = ADF_SCAN_ALONG;
+ else
+ adf = ADF_SCAN_ONCE;
+ }
+#endif
+}
+
+
+void ScanSourceDialog::slChangeSource( int i )
+{
+ if( ! bgroup ) return;
+
+ if( i == sourceAdfEntry())
+ {
+ /* Adf was switched on */
+ bgroup->setEnabled( true );
+ bgroup->setButton( 0 );
+ adf = ADF_SCAN_ALONG;
+ adf_enabled = true;
+ }
+ else
+ {
+ bgroup->setEnabled( false );
+ // adf = ADF_OFF;
+ adf_enabled = false;
+ }
+}
+
+
+
+int ScanSourceDialog::sourceAdfEntry( void ) const
+{
+ if( ! sources ) return( -1 );
+
+ int cou = sources->count();
+
+ for( int i = 0; i < cou; i++ )
+ {
+ QString q = sources->text( i );
+
+#if 0
+ if( q == "ADF" || q == SANE_NAME_DOCUMENT_FEEDER )
+ return( i );
+#endif
+
+ }
+ return( -1 );
+}
+
+
+
+void ScanSourceDialog::slSetSource( const QString source )
+{
+ if( !sources ) return;
+ kdDebug(29000) << "Setting <" << source << "> as source" << endl;
+
+ if( bgroup )
+ bgroup->setEnabled( false );
+ adf_enabled = false ;
+
+
+ for( int i = 0; i < sources->count(); i++ )
+ {
+ if( sources->text( i ) == source )
+ {
+ sources->setCurrentItem( i );
+ if( source == QString::number(sourceAdfEntry()) )
+ {
+ if( bgroup )
+ bgroup->setEnabled( true );
+ adf_enabled = true;
+ }
+ break;
+ }
+ }
+
+}
+
+
+ScanSourceDialog::~ScanSourceDialog()
+{
+
+}
+
+/* EOF */
+#include "scansourcedialog.moc"
diff --git a/libkscan/scansourcedialog.h b/libkscan/scansourcedialog.h
new file mode 100644
index 00000000..3379843f
--- /dev/null
+++ b/libkscan/scansourcedialog.h
@@ -0,0 +1,69 @@
+/* This file is part of the KDE Project
+ Copyright (C) 2000 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SCANSOURCEDIALOG_H
+#define SCANSOURCEDIALOG_H
+#include <qwidget.h>
+#include <kdialogbase.h>
+#include <qstrlist.h>
+#include <qstring.h>
+
+/**
+ *@author Klaas Freitag
+ */
+
+typedef enum { ADF_OFF, ADF_SCAN_ALONG, ADF_SCAN_ONCE } ADF_BEHAVE;
+
+class KScanCombo;
+class QRadioButton;
+class QButtonGroup;
+
+class ScanSourceDialog : public KDialogBase
+{
+ Q_OBJECT
+public:
+ ScanSourceDialog( QWidget *parent, const QStrList, ADF_BEHAVE );
+ ~ScanSourceDialog();
+
+ // void fillWithSources( QStrList *list );
+ QString getText( void ) const;
+
+ ADF_BEHAVE getAdfBehave( void ) const
+ { return( adf ); }
+
+
+public slots:
+ void slNotifyADF( int );
+ void slChangeSource( int );
+ int sourceAdfEntry( void ) const;
+ void slSetSource( const QString source );
+
+private:
+
+ KScanCombo *sources;
+ QButtonGroup *bgroup;
+ QRadioButton *rb0, *rb1;
+ ADF_BEHAVE adf;
+ bool adf_enabled;
+
+ class ScanSourceDialogPrivate;
+ ScanSourceDialogPrivate *d;
+};
+
+#endif
diff --git a/libkscan/sizeindicator.cpp b/libkscan/sizeindicator.cpp
new file mode 100644
index 00000000..4ad1986d
--- /dev/null
+++ b/libkscan/sizeindicator.cpp
@@ -0,0 +1,113 @@
+/* This file is part of the KDE Project
+ Copyright (C) 2000 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "sizeindicator.h"
+
+#include <qpalette.h>
+#include <qimage.h>
+
+#include <kimageeffect.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <qpainter.h>
+
+
+
+SizeIndicator::SizeIndicator( QWidget *parent, long thres, long crit )
+ :QLabel( parent )
+{
+ sizeInByte = -1;
+ setFrameStyle( QFrame::Box | QFrame::Sunken );
+ setMinimumWidth( fontMetrics().width( QString::fromLatin1("MMM.MM MB") ));
+ setCritical( crit );
+ threshold = thres;
+
+}
+
+
+void SizeIndicator::setCritical( long crit )
+{
+ critical = crit;
+ devider = 255.0 / double( critical );
+}
+
+
+void SizeIndicator::setThreshold( long thres )
+{
+ threshold = thres;
+}
+
+
+SizeIndicator::~SizeIndicator()
+{
+
+}
+
+void SizeIndicator::setSizeInByte( long newSize )
+{
+ sizeInByte = newSize;
+ kdDebug(29000) << "New size in byte: " << newSize << endl ;
+
+ QString t;
+
+ QString unit = i18n( "%1 kB" );
+ double sizer = double(sizeInByte)/1024.0; // produces kiloBytes
+ int precision = 1;
+ int fwidth = 3;
+
+ if( sizer > 999.9999999 )
+ {
+ unit = i18n( "%1 MB" );
+ sizer = sizer / 1024.0;
+ precision = 2;
+ fwidth = 2;
+ }
+
+ t = unit.arg( sizer, fwidth, 'f', precision);
+ setText(t);
+
+}
+
+
+
+void SizeIndicator::drawContents( QPainter *p )
+{
+ QSize s = size();
+
+ QColor warnColor;
+
+ if( sizeInByte >= threshold )
+ {
+ int c = int( double(sizeInByte) * devider );
+ if( c > 255 ) c = 255;
+
+ warnColor.setHsv( 0, c, c );
+
+ p->drawImage( 0,0,
+ KImageEffect::unbalancedGradient( s, colorGroup().background(),
+ warnColor, KImageEffect::CrossDiagonalGradient, 200,200 ));
+ }
+ /* Displaying the text */
+ QString t = text();
+ p->drawText( 0, 0, s.width(), s.height(),
+ AlignHCenter | AlignVCenter, t);
+
+}
+
+#include "sizeindicator.moc"
diff --git a/libkscan/sizeindicator.h b/libkscan/sizeindicator.h
new file mode 100644
index 00000000..213fe931
--- /dev/null
+++ b/libkscan/sizeindicator.h
@@ -0,0 +1,98 @@
+/* This file is part of the KDE Project
+ Copyright (C) 2000 Klaas Freitag <freitag@suse.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#ifndef SIZEINDICATOR_H
+#define SIZEINDICATOR_H
+
+#define DEFAULT_CRITICAL (3*1024*1024)
+#define DEFAULT_THRESHOLD (1*1024*1024)
+
+class QPainter;
+#include <qlabel.h>
+
+/**
+ * @short small size indication widget for file sizes
+ * @author Klaas Freitag
+ *
+ * the size indicator is a small widget that displays a file size in a small
+ * frame. The unit (currently kB and MB) is selected automagically.
+ * If the file size grows bigger than the threshold set in the constructor,
+ * the widget starts to change its background color to visualise to the
+ * user that he is doing something obvious.
+ */
+
+class SizeIndicator: public QLabel
+{
+ Q_OBJECT
+ // Q_PROPERTY( KGammaTable *gt READ getGt WRITE setGt )
+
+public:
+ /**
+ * Creates a size indicator widget.
+ * @param thres: Threshold, value on that the widget starts to become red.
+ * @param crit: Critical value, not yet used.
+
+ */
+ SizeIndicator( QWidget *parent, long thres = DEFAULT_THRESHOLD,
+ long crit = DEFAULT_CRITICAL );
+ /**
+ * destructor does not really do much yet.
+ */
+ ~SizeIndicator();
+
+public slots:
+
+ /**
+ * is the slot that sets the file size to display. The widget gets
+ * updated.
+ * @param sizeInByte: the size to set.
+ */
+ void setSizeInByte( long );
+
+ /**
+ * sets the critical size.
+ * @param crit: the critical value
+ */
+ void setCritical( long );
+
+ /**
+ * sets the threshold value.
+ * @param thres: the threshold bytesize
+ */
+ void setThreshold( long );
+
+
+protected:
+ /**
+ * reimplemented to display the color
+ */
+ virtual void drawContents( QPainter* );
+
+private:
+
+ long sizeInByte;
+ long critical, threshold;
+
+ double devider;
+
+ class sizeIndicatorPrivate;
+ sizeIndicatorPrivate *d;
+};
+
+#endif